summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore2
-rw-r--r--Manifest95
-rw-r--r--README137
-rw-r--r--Read-Manifest-Now0
-rw-r--r--Roadmap45
-rw-r--r--WHATSNEW.txt182
-rw-r--r--docs/OID/allocated-arcs.txt17
-rw-r--r--docs/OID/samba-oid.mail27
-rw-r--r--docs/README.Win2kSP256
-rw-r--r--docs/README.Win32-Viruses58
-rw-r--r--docs/README.ldap1
-rw-r--r--docs/Registry/NT4-Locking.reg24
-rw-r--r--docs/Registry/NT4_PlainPassword.reg11
-rw-r--r--docs/Registry/Win2000_PlainPassword.reg11
-rw-r--r--docs/Registry/Win95_PlainPassword.reg4
-rw-r--r--docs/Registry/Win98_PlainPassword.reg4
-rw-r--r--docs/Registry/Win9X-CacheHandling.reg7
-rw-r--r--docs/Registry/WinME_PlainPassword.reg4
-rw-r--r--docs/Registry/WinXP_SignOrSeal.reg9
-rw-r--r--docs/Registry/WindowsTerminalServer.reg7
-rw-r--r--docs/Samba-HOWTO-Collection.pdf2895
-rw-r--r--docs/THANKS22
-rw-r--r--docs/announce89
-rw-r--r--docs/docbook/.cvsignore4
-rw-r--r--docs/docbook/Makefile.in368
-rwxr-xr-xdocs/docbook/configure1067
-rw-r--r--docs/docbook/configure.in49
-rw-r--r--docs/docbook/dbsgml/40chg.txt45
-rw-r--r--docs/docbook/dbsgml/41chg.txt7
-rw-r--r--docs/docbook/dbsgml/50issues.txt39
-rw-r--r--docs/docbook/dbsgml/ChangeLog85
-rw-r--r--docs/docbook/dbsgml/cals-tbl.dtd330
-rw-r--r--docs/docbook/dbsgml/catalog63
-rwxr-xr-xdocs/docbook/dbsgml/dbcent.mod181
-rw-r--r--docs/docbook/dbsgml/dbgenent.mod39
-rwxr-xr-xdocs/docbook/dbsgml/dbhier.mod2100
-rwxr-xr-xdocs/docbook/dbsgml/dbnotn.mod97
-rwxr-xr-xdocs/docbook/dbsgml/dbpool.mod7396
-rw-r--r--docs/docbook/dbsgml/docbook.cat63
-rw-r--r--docs/docbook/dbsgml/docbook.dcl106
-rwxr-xr-xdocs/docbook/dbsgml/docbook.dtd117
-rw-r--r--docs/docbook/dbsgml/ent/ISOamsa66
-rw-r--r--docs/docbook/dbsgml/ent/ISOamsb52
-rw-r--r--docs/docbook/dbsgml/ent/ISOamsc20
-rw-r--r--docs/docbook/dbsgml/ent/ISOamsn70
-rw-r--r--docs/docbook/dbsgml/ent/ISOamso29
-rw-r--r--docs/docbook/dbsgml/ent/ISOamsr94
-rw-r--r--docs/docbook/dbsgml/ent/ISObox62
-rw-r--r--docs/docbook/dbsgml/ent/ISOcyr177
-rw-r--r--docs/docbook/dbsgml/ent/ISOcyr236
-rw-r--r--docs/docbook/dbsgml/ent/ISOdia24
-rw-r--r--docs/docbook/dbsgml/ent/ISOgrk159
-rw-r--r--docs/docbook/dbsgml/ent/ISOgrk230
-rw-r--r--docs/docbook/dbsgml/ent/ISOgrk353
-rw-r--r--docs/docbook/dbsgml/ent/ISOgrk453
-rw-r--r--docs/docbook/dbsgml/ent/ISOlat172
-rw-r--r--docs/docbook/dbsgml/ent/ISOlat2131
-rw-r--r--docs/docbook/dbsgml/ent/ISOnum91
-rw-r--r--docs/docbook/dbsgml/ent/ISOpub100
-rw-r--r--docs/docbook/dbsgml/ent/ISOtech73
-rw-r--r--docs/docbook/dbsgml/readme.txt12
-rw-r--r--docs/docbook/docbook.txt136
-rw-r--r--docs/docbook/global.ent33
-rw-r--r--docs/docbook/manpages/findsmb.1.sgml131
-rw-r--r--docs/docbook/manpages/lmhosts.5.sgml114
-rw-r--r--docs/docbook/manpages/make_smbcodepage.1.sgml197
-rw-r--r--docs/docbook/manpages/make_unicodemap.1.sgml172
-rw-r--r--docs/docbook/manpages/nmbd.8.sgml341
-rw-r--r--docs/docbook/manpages/nmblookup.1.sgml249
-rw-r--r--docs/docbook/manpages/rpcclient.1.sgml420
-rw-r--r--docs/docbook/manpages/samba.7.sgml213
-rw-r--r--docs/docbook/manpages/smb.conf.5.sgml8486
-rw-r--r--docs/docbook/manpages/smbcacls.1.sgml255
-rw-r--r--docs/docbook/manpages/smbclient.1.sgml1023
-rw-r--r--docs/docbook/manpages/smbcontrol.1.sgml174
-rw-r--r--docs/docbook/manpages/smbd.8.sgml611
-rw-r--r--docs/docbook/manpages/smbmnt.8.sgml113
-rw-r--r--docs/docbook/manpages/smbmount.8.sgml327
-rw-r--r--docs/docbook/manpages/smbpasswd.5.sgml204
-rw-r--r--docs/docbook/manpages/smbpasswd.8.sgml426
-rw-r--r--docs/docbook/manpages/smbsh.1.sgml105
-rw-r--r--docs/docbook/manpages/smbspool.8.sgml131
-rw-r--r--docs/docbook/manpages/smbstatus.1.sgml137
-rw-r--r--docs/docbook/manpages/smbtar.1.sgml226
-rw-r--r--docs/docbook/manpages/smbumount.8.sgml73
-rw-r--r--docs/docbook/manpages/swat.8.sgml209
-rw-r--r--docs/docbook/manpages/testparm.1.sgml168
-rw-r--r--docs/docbook/manpages/testprns.1.sgml143
-rw-r--r--docs/docbook/manpages/wbinfo.1.sgml185
-rw-r--r--docs/docbook/manpages/winbindd.8.sgml500
-rw-r--r--docs/docbook/projdoc/CVS-Access.sgml157
-rw-r--r--docs/docbook/projdoc/DOMAIN_MEMBER.sgml224
-rw-r--r--docs/docbook/projdoc/ENCRYPTION.sgml378
-rw-r--r--docs/docbook/projdoc/Integrating-with-Windows.sgml935
-rw-r--r--docs/docbook/projdoc/NT_Security.sgml358
-rw-r--r--docs/docbook/projdoc/OS2-Client-HOWTO.sgml142
-rw-r--r--docs/docbook/projdoc/PAM-Authentication-And-Samba.sgml215
-rw-r--r--docs/docbook/projdoc/Samba-PDC-HOWTO.sgml1828
-rw-r--r--docs/docbook/projdoc/UNIX_INSTALL.sgml451
-rw-r--r--docs/docbook/projdoc/msdfs_setup.sgml117
-rw-r--r--docs/docbook/projdoc/printer_driver2.sgml687
-rw-r--r--docs/docbook/projdoc/samba-doc.sgml66
-rw-r--r--docs/docbook/projdoc/winbind.sgml919
-rw-r--r--docs/docbook/scripts/README.ldp_print60
-rw-r--r--docs/docbook/scripts/collateindex.pl595
-rw-r--r--docs/docbook/scripts/fix_print_html.lib172
-rwxr-xr-xdocs/docbook/scripts/ldp_print71
-rw-r--r--docs/docbook/scripts/make-article.pl25
-rw-r--r--docs/docbook/scripts/strip-links.pl14
-rw-r--r--docs/docbook/stylesheets/ldp.dsl.in256
-rw-r--r--docs/faq/Samba-Server-FAQ-1.html77
-rw-r--r--docs/faq/Samba-Server-FAQ-2.html500
-rw-r--r--docs/faq/Samba-Server-FAQ.html88
-rw-r--r--docs/faq/Samba-Server-FAQ.sgml492
-rw-r--r--docs/faq/Samba-meta-FAQ-1.html160
-rw-r--r--docs/faq/Samba-meta-FAQ-2.html384
-rw-r--r--docs/faq/Samba-meta-FAQ-3.html101
-rw-r--r--docs/faq/Samba-meta-FAQ-4.html215
-rw-r--r--docs/faq/Samba-meta-FAQ-5.html30
-rw-r--r--docs/faq/Samba-meta-FAQ-6.html30
-rw-r--r--docs/faq/Samba-meta-FAQ.html102
-rw-r--r--docs/faq/Samba-meta-FAQ.sgml771
-rw-r--r--docs/faq/Samba-meta-FAQ.txt924
-rw-r--r--docs/faq/sambafaq-1.html392
-rw-r--r--docs/faq/sambafaq-2.html236
-rw-r--r--docs/faq/sambafaq-3.html322
-rw-r--r--docs/faq/sambafaq-4.html37
-rw-r--r--docs/faq/sambafaq-5.html30
-rw-r--r--docs/faq/sambafaq.html115
-rw-r--r--docs/faq/sambafaq.sgml792
-rw-r--r--docs/faq/sambafaq.txt1122
-rw-r--r--docs/history65
-rw-r--r--docs/htmldocs/CVS-Access.html193
-rw-r--r--docs/htmldocs/DOMAIN_MEMBER.html372
-rw-r--r--docs/htmldocs/ENCRYPTION.html656
-rw-r--r--docs/htmldocs/Integrating-with-Windows.html1072
-rw-r--r--docs/htmldocs/NT_Security.html783
-rw-r--r--docs/htmldocs/OS2-Client-HOWTO.html210
-rw-r--r--docs/htmldocs/PAM-Authentication-And-Samba.html318
-rw-r--r--docs/htmldocs/Samba-HOWTO-Collection.html9612
-rw-r--r--docs/htmldocs/Samba-PDC-HOWTO.html2284
-rw-r--r--docs/htmldocs/UNIX_INSTALL.html820
-rw-r--r--docs/htmldocs/findsmb.1.html267
-rw-r--r--docs/htmldocs/lmhosts.5.html214
-rw-r--r--docs/htmldocs/make_smbcodepage.1.html354
-rw-r--r--docs/htmldocs/make_unicodemap.1.html276
-rw-r--r--docs/htmldocs/msdfs_setup.html210
-rw-r--r--docs/htmldocs/nmbd.8.html676
-rw-r--r--docs/htmldocs/nmblookup.1.html394
-rw-r--r--docs/htmldocs/printer_driver2.html985
-rw-r--r--docs/htmldocs/rpcclient.1.html719
-rw-r--r--docs/htmldocs/samba.7.html365
-rw-r--r--docs/htmldocs/smb.conf.5.html19333
-rw-r--r--docs/htmldocs/smbcacls.1.html387
-rw-r--r--docs/htmldocs/smbclient.1.html1554
-rw-r--r--docs/htmldocs/smbcontrol.1.html333
-rw-r--r--docs/htmldocs/smbd.8.html1098
-rw-r--r--docs/htmldocs/smbmnt.8.html178
-rw-r--r--docs/htmldocs/smbmount.8.html468
-rw-r--r--docs/htmldocs/smbpasswd.5.html316
-rw-r--r--docs/htmldocs/smbpasswd.8.html673
-rw-r--r--docs/htmldocs/smbsh.1.html251
-rw-r--r--docs/htmldocs/smbspool.8.html222
-rw-r--r--docs/htmldocs/smbstatus.1.html209
-rw-r--r--docs/htmldocs/smbtar.1.html351
-rw-r--r--docs/htmldocs/smbumount.8.html140
-rw-r--r--docs/htmldocs/swat.8.html420
-rw-r--r--docs/htmldocs/testparm.1.html298
-rw-r--r--docs/htmldocs/testprns.1.html252
-rw-r--r--docs/htmldocs/using_samba/appa_01.html153
-rw-r--r--docs/htmldocs/using_samba/appa_02.html100
-rw-r--r--docs/htmldocs/using_samba/appa_03.html325
-rw-r--r--docs/htmldocs/using_samba/appa_04.html135
-rw-r--r--docs/htmldocs/using_samba/appa_05.html460
-rw-r--r--docs/htmldocs/using_samba/appb_01.html162
-rw-r--r--docs/htmldocs/using_samba/appb_02.html342
-rw-r--r--docs/htmldocs/using_samba/appb_03.html876
-rw-r--r--docs/htmldocs/using_samba/appc_01.html3497
-rw-r--r--docs/htmldocs/using_samba/appd_01.html1907
-rw-r--r--docs/htmldocs/using_samba/appe_01.html96
-rw-r--r--docs/htmldocs/using_samba/appf_01.html315
-rw-r--r--docs/htmldocs/using_samba/ch01_01.html167
-rw-r--r--docs/htmldocs/using_samba/ch01_02.html212
-rw-r--r--docs/htmldocs/using_samba/ch01_03.html444
-rw-r--r--docs/htmldocs/using_samba/ch01_04.html277
-rw-r--r--docs/htmldocs/using_samba/ch01_05.html130
-rw-r--r--docs/htmldocs/using_samba/ch01_06.html90
-rw-r--r--docs/htmldocs/using_samba/ch01_07.html138
-rw-r--r--docs/htmldocs/using_samba/ch01_08.html89
-rw-r--r--docs/htmldocs/using_samba/ch02_01.html197
-rw-r--r--docs/htmldocs/using_samba/ch02_02.html338
-rw-r--r--docs/htmldocs/using_samba/ch02_03.html235
-rw-r--r--docs/htmldocs/using_samba/ch02_04.html186
-rw-r--r--docs/htmldocs/using_samba/ch02_05.html195
-rw-r--r--docs/htmldocs/using_samba/ch02_06.html108
-rw-r--r--docs/htmldocs/using_samba/ch03_01.html277
-rw-r--r--docs/htmldocs/using_samba/ch03_02.html260
-rw-r--r--docs/htmldocs/using_samba/ch03_03.html579
-rw-r--r--docs/htmldocs/using_samba/ch04_01.html415
-rw-r--r--docs/htmldocs/using_samba/ch04_02.html211
-rw-r--r--docs/htmldocs/using_samba/ch04_03.html190
-rw-r--r--docs/htmldocs/using_samba/ch04_04.html214
-rw-r--r--docs/htmldocs/using_samba/ch04_05.html309
-rw-r--r--docs/htmldocs/using_samba/ch04_06.html414
-rw-r--r--docs/htmldocs/using_samba/ch04_07.html151
-rw-r--r--docs/htmldocs/using_samba/ch04_08.html423
-rw-r--r--docs/htmldocs/using_samba/ch05_01.html786
-rw-r--r--docs/htmldocs/using_samba/ch05_02.html429
-rw-r--r--docs/htmldocs/using_samba/ch05_03.html426
-rw-r--r--docs/htmldocs/using_samba/ch05_04.html433
-rw-r--r--docs/htmldocs/using_samba/ch05_05.html399
-rw-r--r--docs/htmldocs/using_samba/ch06_01.html221
-rw-r--r--docs/htmldocs/using_samba/ch06_02.html423
-rw-r--r--docs/htmldocs/using_samba/ch06_03.html384
-rw-r--r--docs/htmldocs/using_samba/ch06_04.html738
-rw-r--r--docs/htmldocs/using_samba/ch06_05.html333
-rw-r--r--docs/htmldocs/using_samba/ch06_06.html537
-rw-r--r--docs/htmldocs/using_samba/ch07_01.html565
-rw-r--r--docs/htmldocs/using_samba/ch07_02.html757
-rw-r--r--docs/htmldocs/using_samba/ch07_03.html404
-rw-r--r--docs/htmldocs/using_samba/ch08_01.html267
-rw-r--r--docs/htmldocs/using_samba/ch08_02.html156
-rw-r--r--docs/htmldocs/using_samba/ch08_03.html472
-rw-r--r--docs/htmldocs/using_samba/ch08_04.html168
-rw-r--r--docs/htmldocs/using_samba/ch08_05.html396
-rw-r--r--docs/htmldocs/using_samba/ch08_06.html509
-rw-r--r--docs/htmldocs/using_samba/ch08_07.html143
-rw-r--r--docs/htmldocs/using_samba/ch09_01.html397
-rw-r--r--docs/htmldocs/using_samba/ch09_02.html1772
-rw-r--r--docs/htmldocs/using_samba/ch09_03.html136
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0101.gifbin0 -> 9850 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0102.gifbin0 -> 10938 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0103.gifbin0 -> 5823 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0104.gifbin0 -> 20973 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0105.gifbin0 -> 11432 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0106.gifbin0 -> 4658 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0107.gifbin0 -> 10347 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0108.gifbin0 -> 21228 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0109.gifbin0 -> 21762 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0110.gifbin0 -> 6227 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0111.gifbin0 -> 8247 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0112.gifbin0 -> 13955 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0113.gifbin0 -> 12108 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0114.gifbin0 -> 24643 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0201.gifbin0 -> 5401 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0202.gifbin0 -> 21864 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0203.gifbin0 -> 19066 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0204.gifbin0 -> 13719 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0301.gifbin0 -> 11604 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0302.gifbin0 -> 12184 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0303.gifbin0 -> 4121 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0304.gifbin0 -> 4872 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0305.gifbin0 -> 14146 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0306.gifbin0 -> 8055 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0307.gifbin0 -> 12529 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0308.gifbin0 -> 16162 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0309.gifbin0 -> 11689 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0310.gifbin0 -> 12693 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0311.gifbin0 -> 13347 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0312.gifbin0 -> 9694 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0313.gifbin0 -> 10215 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0314.gifbin0 -> 5199 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0315.gifbin0 -> 5979 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0316.gifbin0 -> 9579 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0317.gifbin0 -> 14849 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0318.gifbin0 -> 9998 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0319.gifbin0 -> 10874 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0320.gifbin0 -> 10919 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0321.gifbin0 -> 10805 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0322.gifbin0 -> 15031 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0323.gifbin0 -> 13656 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0324.gifbin0 -> 11731 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0325.gifbin0 -> 14093 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0326.gifbin0 -> 7093 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0327.gifbin0 -> 5959 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0328.gifbin0 -> 7816 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0401.gifbin0 -> 8351 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0402.gifbin0 -> 8591 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0403.gifbin0 -> 9284 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0404.gifbin0 -> 5239 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0405.gifbin0 -> 6754 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0406.gifbin0 -> 5708 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0407.gifbin0 -> 10212 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0501.gifbin0 -> 15642 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0502.gifbin0 -> 7757 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0503.gifbin0 -> 8100 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0504.gifbin0 -> 7238 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0505.gifbin0 -> 7634 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0506.gifbin0 -> 13586 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0507.gifbin0 -> 8965 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0508.gifbin0 -> 15146 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0601.gifbin0 -> 10033 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0602.gifbin0 -> 9024 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0603.gifbin0 -> 6005 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0604.gifbin0 -> 12210 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0605.gifbin0 -> 13525 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0606.gifbin0 -> 16887 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0701.gifbin0 -> 5898 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0702.gifbin0 -> 3723 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0703.gifbin0 -> 13047 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0704.gifbin0 -> 7515 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0705.gifbin0 -> 10366 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0706.gifbin0 -> 25083 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0707.gifbin0 -> 11071 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0708.gifbin0 -> 7773 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0709.gifbin0 -> 14114 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0801.gifbin0 -> 12132 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0802.gifbin0 -> 15299 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0803.gifbin0 -> 9690 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0804.gifbin0 -> 11211 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0805.gifbin0 -> 11927 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0901.gifbin0 -> 16309 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0902.gifbin0 -> 26399 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0903.gifbin0 -> 18573 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0904.gifbin0 -> 8977 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.0905.gifbin0 -> 8062 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.aa01.gifbin0 -> 15078 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.ab01.gifbin0 -> 10028 bytes
-rw-r--r--docs/htmldocs/using_samba/figs/sam.ab02.gifbin0 -> 8422 bytes
-rw-r--r--docs/htmldocs/using_samba/gifs/index.gifbin0 -> 565 bytes
-rw-r--r--docs/htmldocs/using_samba/gifs/samba.s.gifbin0 -> 6284 bytes
-rw-r--r--docs/htmldocs/using_samba/gifs/txthome.gifbin0 -> 320 bytes
-rw-r--r--docs/htmldocs/using_samba/gifs/txtnexta.gifbin0 -> 419 bytes
-rw-r--r--docs/htmldocs/using_samba/gifs/txtpreva.gifbin0 -> 588 bytes
-rw-r--r--docs/htmldocs/using_samba/index.html168
-rw-r--r--docs/htmldocs/using_samba/inx.html1344
-rw-r--r--docs/htmldocs/using_samba/licenseinfo.html181
-rw-r--r--docs/htmldocs/using_samba/this_edition.html48
-rw-r--r--docs/htmldocs/wbinfo.1.html308
-rw-r--r--docs/htmldocs/winbind.html1312
-rw-r--r--docs/htmldocs/winbindd.8.html937
-rw-r--r--docs/manpages/findsmb.190
-rw-r--r--docs/manpages/lmhosts.592
-rw-r--r--docs/manpages/make_smbcodepage.1140
-rw-r--r--docs/manpages/make_unicodemap.199
-rw-r--r--docs/manpages/nmbd.8724
-rw-r--r--docs/manpages/nmblookup.1154
-rw-r--r--docs/manpages/rpcclient.1329
-rw-r--r--docs/manpages/samba.7327
-rw-r--r--docs/manpages/smb.conf.59983
-rw-r--r--docs/manpages/smbcacls.1191
-rw-r--r--docs/manpages/smbclient.11886
-rw-r--r--docs/manpages/smbcontrol.1124
-rw-r--r--docs/manpages/smbd.8884
-rw-r--r--docs/manpages/smbmnt.863
-rw-r--r--docs/manpages/smbmount.8216
-rw-r--r--docs/manpages/smbpasswd.5159
-rw-r--r--docs/manpages/smbpasswd.8313
-rw-r--r--docs/manpages/smbrun.170
-rw-r--r--docs/manpages/smbsh.174
-rw-r--r--docs/manpages/smbspool.8102
-rw-r--r--docs/manpages/smbstatus.1114
-rw-r--r--docs/manpages/smbtar.1279
-rw-r--r--docs/manpages/smbumount.842
-rw-r--r--docs/manpages/swat.8140
-rw-r--r--docs/manpages/testparm.1200
-rw-r--r--docs/manpages/testprns.1185
-rw-r--r--docs/manpages/wbinfo.1110
-rw-r--r--docs/manpages/winbindd.8381
-rw-r--r--docs/samba.lsm26
-rw-r--r--docs/textdocs/ADS-HOWTO.txt142
-rw-r--r--docs/textdocs/Application_Serving.txt56
-rw-r--r--docs/textdocs/BROWSING-Config.txt215
-rw-r--r--docs/textdocs/BROWSING.txt569
-rw-r--r--docs/textdocs/BUGS.txt46
-rw-r--r--docs/textdocs/DHCP-Server-Configuration.txt240
-rw-r--r--docs/textdocs/DIAGNOSIS.txt178
-rw-r--r--docs/textdocs/DOMAIN.txt68
-rw-r--r--docs/textdocs/ENCRYPTION.txt333
-rw-r--r--docs/textdocs/Faxing.txt220
-rw-r--r--docs/textdocs/GOTCHAS.txt68
-rw-r--r--docs/textdocs/GROUP-MAPPING-HOWTO.txt78
-rw-r--r--docs/textdocs/HINTS.txt9
-rw-r--r--docs/textdocs/INSTALL.sambatar6
-rw-r--r--docs/textdocs/Imprints.txt47
-rw-r--r--docs/textdocs/Macintosh_Clients.txt23
-rw-r--r--docs/textdocs/NetBIOS.txt152
-rw-r--r--docs/textdocs/PROFILES.txt385
-rw-r--r--docs/textdocs/Passwords.txt14
-rw-r--r--docs/textdocs/Printing.txt255
-rw-r--r--docs/textdocs/README.DCEDFS9
-rw-r--r--docs/textdocs/README.NOW8
-rw-r--r--docs/textdocs/README.jis31
-rw-r--r--docs/textdocs/README.sambatar8
-rw-r--r--docs/textdocs/Recent-FAQs.txt286
-rw-r--r--docs/textdocs/RoutedNetworks.txt63
-rw-r--r--docs/textdocs/SCO.txt9
-rw-r--r--docs/textdocs/SMBTAR.notes8
-rw-r--r--docs/textdocs/Samba-OpenSSL.txt405
-rw-r--r--docs/textdocs/Speed.txt92
-rw-r--r--docs/textdocs/Speed2.txt57
-rw-r--r--docs/textdocs/Support.txt376
-rw-r--r--docs/textdocs/Tracing.txt93
-rw-r--r--docs/textdocs/UNIX-SMB.txt49
-rw-r--r--docs/textdocs/UNIX_SECURITY.txt54
-rw-r--r--docs/textdocs/Win95.txt74
-rw-r--r--docs/textdocs/WinNT.txt68
-rw-r--r--docs/textdocs/cifsntdomain.txt1498
-rw-r--r--docs/textdocs/kurs.pdfbin0 -> 202185 bytes
-rw-r--r--docs/textdocs/kurs.tex2460
-rw-r--r--docs/textdocs/logo.ps344
-rw-r--r--docs/textdocs/outdated/NTDOMAIN.txt51
-rw-r--r--docs/textdocs/outdated/PRINTER_DRIVER.txt240
-rw-r--r--docs/textdocs/outdated/PROJECTS (renamed from docs/textdocs/PROJECTS)48
-rw-r--r--docs/textdocs/security_level.txt100
-rw-r--r--docs/yodldocs/README-NOW14
-rw-r--r--examples/README13
-rw-r--r--examples/VFS/.cvsignore2
-rw-r--r--examples/VFS/Makefile36
-rw-r--r--examples/VFS/README35
-rw-r--r--examples/VFS/audit.c196
-rw-r--r--examples/VFS/block/Makefile37
-rw-r--r--examples/VFS/block/block.c546
-rw-r--r--examples/VFS/block/samba-block.conf6
-rw-r--r--examples/VFS/block/smb.conf13
-rw-r--r--examples/VFS/skel.c297
-rw-r--r--examples/appliance/Makefile68
-rw-r--r--examples/appliance/README52
-rw-r--r--examples/appliance/appliance.spec389
-rwxr-xr-xexamples/appliance/build.sh4
-rw-r--r--examples/appliance/smb.conf-appliance8
-rw-r--r--examples/autofs/auto.a15
-rw-r--r--examples/libsmbclient/Makefile25
-rw-r--r--examples/libsmbclient/README8
-rw-r--r--examples/libsmbclient/testsmbc.c456
-rw-r--r--examples/libsmbclient/tree.c812
-rw-r--r--examples/misc/extra_smbstatus35
-rw-r--r--examples/misc/swat.pl122
-rw-r--r--examples/misc/wall.perl76
-rw-r--r--examples/printer-accounting/README63
-rw-r--r--examples/printer-accounting/acct-all9
-rw-r--r--examples/printer-accounting/acct-sum29
-rw-r--r--examples/printer-accounting/hp5-redir40
-rw-r--r--examples/printer-accounting/lp-acct35
-rw-r--r--examples/printer-accounting/printcap22
-rwxr-xr-xexamples/printing/smbprint24
-rw-r--r--examples/simple/smb.conf6
-rw-r--r--examples/smb.conf.default252
-rw-r--r--examples/svr4-startup/README24
-rwxr-xr-xexamples/svr4-startup/samba.server38
-rw-r--r--examples/thoralf/smb.conf152
-rw-r--r--examples/validchars/msdos70.out257
-rw-r--r--examples/validchars/nwdos70.out257
-rw-r--r--examples/validchars/readme101
-rw-r--r--examples/validchars/validchr.c123
-rw-r--r--examples/validchars/validchr.com77
-rw-r--r--packaging/Caldera/OpenLinux/.cvsignore6
-rw-r--r--packaging/Caldera/OpenLinux/README.Public9
-rw-r--r--packaging/Caldera/OpenLinux/README.home15
-rw-r--r--packaging/Caldera/OpenLinux/README.profiles10
-rwxr-xr-xpackaging/Caldera/OpenLinux/findsmb141
-rw-r--r--packaging/Caldera/OpenLinux/makerpms.sh.tmpl42
-rw-r--r--packaging/Caldera/OpenLinux/samba-3.0.0.pre-install.patch12
-rw-r--r--packaging/Caldera/OpenLinux/samba.daemon6
-rwxr-xr-xpackaging/Caldera/OpenLinux/samba.init62
-rwxr-xr-xpackaging/Caldera/OpenLinux/samba.init-lsb108
-rw-r--r--packaging/Caldera/OpenLinux/samba.logrotate12
-rw-r--r--packaging/Caldera/OpenLinux/samba.pam11
-rw-r--r--packaging/Caldera/OpenLinux/samba2.spec-lsb.tmpl506
-rw-r--r--packaging/Caldera/OpenLinux/samba2.spec.tmpl484
-rw-r--r--packaging/Caldera/OpenLinux/samba3.spec.tmpl314
-rw-r--r--packaging/Caldera/OpenLinux/smb.conf51
-rw-r--r--packaging/Caldera/OpenLinux/smb.conf.sample315
-rwxr-xr-xpackaging/Caldera/OpenLinux/smbadduser.perl146
-rwxr-xr-xpackaging/Caldera/OpenLinux/smbprint77
-rw-r--r--packaging/Caldera/OpenLinux/smbusers3
-rwxr-xr-xpackaging/Caldera/OpenLinux/updatesmbpasswd.perl10
-rwxr-xr-xpackaging/Caldera/OpenServer/Clean22
-rwxr-xr-xpackaging/Caldera/OpenServer/Compile48
-rwxr-xr-xpackaging/Caldera/OpenServer/Configure73
-rwxr-xr-xpackaging/Caldera/OpenServer/Install156
-rwxr-xr-xpackaging/Caldera/OpenServer/Makevol10
-rwxr-xr-xpackaging/Caldera/OpenServer/Package13
-rw-r--r--packaging/Caldera/OpenServer/README44
-rwxr-xr-xpackaging/Caldera/OpenServer/findsmb141
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/Clean3
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/Install1
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/MakeSSO25
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/Packem15
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/Remove16
-rw-r--r--packaging/Caldera/OpenServer/pkg/cdmt.config34
-rwxr-xr-xpackaging/Caldera/OpenServer/pkg/cntl/ccs108
-rw-r--r--packaging/Caldera/OpenServer/pkg/input/Samba.cmpnt25
-rw-r--r--packaging/Caldera/OpenServer/pkg/input/Samba.pkg1905
-rw-r--r--packaging/Caldera/OpenServer/pkg/input/Samba.prd6
-rw-r--r--packaging/Caldera/OpenServer/samba-2.2-osr5.patch29
-rw-r--r--packaging/Caldera/OpenServer/smb.conf291
-rwxr-xr-xpackaging/Caldera/OpenServer/smb.init76
-rwxr-xr-xpackaging/Caldera/OpenServer/smbadduser73
-rwxr-xr-xpackaging/Caldera/OpenServer/smbprint77
-rw-r--r--packaging/Caldera/OpenServer/smbusers3
-rwxr-xr-xpackaging/Caldera/UnixWare/Clean22
-rwxr-xr-xpackaging/Caldera/UnixWare/Compile52
-rwxr-xr-xpackaging/Caldera/UnixWare/Configure67
-rwxr-xr-xpackaging/Caldera/UnixWare/Install146
-rwxr-xr-xpackaging/Caldera/UnixWare/Makepkg10
-rwxr-xr-xpackaging/Caldera/UnixWare/Package40
-rw-r--r--packaging/Caldera/UnixWare/README54
-rwxr-xr-xpackaging/Caldera/UnixWare/findsmb141
-rw-r--r--packaging/Caldera/UnixWare/pkg/admin1
-rw-r--r--packaging/Caldera/UnixWare/pkg/pkginfo10
-rwxr-xr-xpackaging/Caldera/UnixWare/pkg/postinstall56
-rwxr-xr-xpackaging/Caldera/UnixWare/pkg/postremove30
-rw-r--r--packaging/Caldera/UnixWare/pkg/prototype310
-rw-r--r--packaging/Caldera/UnixWare/samba-2.2-uw7-prototype.patch11
-rw-r--r--packaging/Caldera/UnixWare/samba-2.2-uw7.patch200
-rw-r--r--packaging/Caldera/UnixWare/smb.conf291
-rwxr-xr-xpackaging/Caldera/UnixWare/smb.init76
-rwxr-xr-xpackaging/Caldera/UnixWare/smbadduser73
-rwxr-xr-xpackaging/Caldera/UnixWare/smbprint77
-rw-r--r--packaging/Caldera/UnixWare/smbusers3
-rw-r--r--packaging/Digital/Instructions55
-rw-r--r--packaging/Digital/PackageDate1
-rw-r--r--packaging/Digital/Packager2
-rw-r--r--packaging/Digital/Packaging-instructions14
-rwxr-xr-xpackaging/Digital/package-prep30
-rwxr-xr-xpackaging/Digital/samba.init34
-rwxr-xr-xpackaging/Digital/setup.sh24
-rw-r--r--packaging/Digital/skeleton.tarbin0 -> 30720 bytes
-rw-r--r--packaging/Example/Instructions41
-rw-r--r--packaging/Example/PackageDate1
-rw-r--r--packaging/Example/Packager1
-rw-r--r--packaging/Example/Packaging-instructions16
-rwxr-xr-xpackaging/Example/package-prep51
-rwxr-xr-xpackaging/Example/samba.init34
-rwxr-xr-xpackaging/Example/setup.sh27
-rw-r--r--packaging/Example/skeleton.tarbin0 -> 30720 bytes
-rw-r--r--packaging/LSB/README6
-rw-r--r--packaging/LSB/lsb-samba.spec100
-rwxr-xr-xpackaging/LSB/samba.sh80
-rw-r--r--packaging/LSB/samba.xinetd15
-rw-r--r--packaging/LSB/smb.conf290
-rw-r--r--packaging/Mandrake/.cvsignore2
-rw-r--r--packaging/Mandrake/README11
-rw-r--r--packaging/Mandrake/empty.patch0
-rwxr-xr-xpackaging/Mandrake/findsmb141
-rw-r--r--packaging/Mandrake/makerpms.sh.tmpl16
-rw-r--r--packaging/Mandrake/samba.log15
-rw-r--r--packaging/Mandrake/samba.pamd5
-rw-r--r--packaging/Mandrake/samba.xinetd15
-rw-r--r--packaging/Mandrake/samba2.spec.tmpl300
-rw-r--r--packaging/Mandrake/smb.conf320
-rwxr-xr-xpackaging/Mandrake/smb.init93
-rwxr-xr-xpackaging/Mandrake/smbprint77
-rw-r--r--packaging/Mandrake/smbusers3
-rw-r--r--packaging/PHT/TurboLinux/.cvsignore3
-rw-r--r--packaging/PHT/TurboLinux/README11
-rwxr-xr-xpackaging/PHT/TurboLinux/findsmb141
-rw-r--r--packaging/PHT/TurboLinux/makerpms.sh.tmpl14
-rw-r--r--packaging/PHT/TurboLinux/samba.log11
-rw-r--r--packaging/PHT/TurboLinux/samba.pamd11
-rw-r--r--packaging/PHT/TurboLinux/samba2.spec.tmpl502
-rw-r--r--packaging/PHT/TurboLinux/smb.conf291
-rwxr-xr-xpackaging/PHT/TurboLinux/smb.init49
-rwxr-xr-xpackaging/PHT/TurboLinux/smbadduser73
-rwxr-xr-xpackaging/PHT/TurboLinux/smbprint77
-rw-r--r--packaging/PHT/TurboLinux/smbusers3
-rw-r--r--packaging/PHT/TurboLinux/smbw.patch10
-rw-r--r--packaging/README38
-rw-r--r--packaging/README.UnixWare6
-rw-r--r--packaging/RedHat/.cvsignore6
-rw-r--r--packaging/RedHat/README11
-rwxr-xr-xpackaging/RedHat/findsmb141
-rw-r--r--packaging/RedHat/makerpms.sh.tmpl38
-rw-r--r--packaging/RedHat/samba.log11
-rw-r--r--packaging/RedHat/samba.pamd4
-rw-r--r--packaging/RedHat/samba.pamd.stack6
-rw-r--r--packaging/RedHat/samba.xinetd15
-rw-r--r--packaging/RedHat/samba2.spec.tmpl458
-rw-r--r--packaging/RedHat/smb.conf290
-rwxr-xr-xpackaging/RedHat/smb.init49
-rwxr-xr-xpackaging/RedHat/smbprint77
-rw-r--r--packaging/RedHat/smbusers3
-rw-r--r--packaging/SGI/.cvsignore8
-rw-r--r--packaging/SGI/README44
-rwxr-xr-xpackaging/SGI/findsmb141
-rwxr-xr-xpackaging/SGI/idb.pl374
-rwxr-xr-xpackaging/SGI/inetd.sh37
-rwxr-xr-xpackaging/SGI/inst.msg31
-rw-r--r--packaging/SGI/legal_notice.html53
-rwxr-xr-xpackaging/SGI/mkman18
-rwxr-xr-xpackaging/SGI/mkprintcap.sh15
-rwxr-xr-xpackaging/SGI/mkrelease.sh125
-rw-r--r--packaging/SGI/printcap5
-rw-r--r--packaging/SGI/relnotes.html233
-rwxr-xr-xpackaging/SGI/removeswat.sh25
-rw-r--r--packaging/SGI/samba.config1
-rw-r--r--packaging/SGI/samba.rc43
-rw-r--r--packaging/SGI/sambalp157
-rw-r--r--packaging/SGI/smb.conf124
-rw-r--r--packaging/SGI/smbpasswd1
-rw-r--r--packaging/SGI/smbprint54
-rwxr-xr-xpackaging/SGI/spec.pl91
-rwxr-xr-xpackaging/SGI/startswat.sh29
-rw-r--r--packaging/Solaris/README18
-rw-r--r--packaging/Solaris/copyright1
-rw-r--r--packaging/Solaris/i.swat44
-rw-r--r--packaging/Solaris/inetd.conf.master1
-rwxr-xr-xpackaging/Solaris/makepkg.sh185
-rw-r--r--packaging/Solaris/pkg-specs/pkginfo12
-rw-r--r--packaging/Solaris/pkginfo.master12
-rw-r--r--packaging/Solaris/postinstall21
-rw-r--r--packaging/Solaris/preremove12
-rw-r--r--packaging/Solaris/prototype.master52
-rw-r--r--packaging/Solaris/r.swat16
-rw-r--r--packaging/Solaris/request17
-rwxr-xr-xpackaging/Solaris/samba.server.master48
-rw-r--r--packaging/Solaris/services1
-rw-r--r--packaging/SuSE/5.2/samba-1.9.18p5.dif234
-rw-r--r--packaging/SuSE/5.2/samba.spec119
-rw-r--r--packaging/SuSE/7.1/samba-2.2.0-alpha0.dif224
-rw-r--r--packaging/SuSE/7.1/samba.pamd3
-rw-r--r--packaging/SuSE/7.1/samba.spec381
-rwxr-xr-xpackaging/bin/update-pkginfo20
-rwxr-xr-xpcp/Install64
-rw-r--r--pcp/Makefile69
-rw-r--r--pcp/README94
-rwxr-xr-xpcp/Remove52
-rw-r--r--pcp/domain.h4
-rw-r--r--pcp/help77
-rwxr-xr-xpcp/mkheader.pl63
-rw-r--r--pcp/pmns45
-rw-r--r--pcp/root10
-rw-r--r--pcp/samba.c390
-rw-r--r--source/.cvsignore17
-rw-r--r--source/CodingSuggestions143
-rw-r--r--source/Doxyfile170
-rw-r--r--source/Makefile.in899
-rw-r--r--source/acconfig.h186
-rw-r--r--source/aclocal.m4932
-rw-r--r--source/aparser/Makefile17
-rwxr-xr-xsource/aparser/build13
-rw-r--r--source/aparser/cifs.struct1029
-rw-r--r--source/aparser/dump.awk70
-rw-r--r--source/aparser/harness.awk17
-rw-r--r--source/aparser/header.awk80
-rw-r--r--source/aparser/main.awk25
-rw-r--r--source/aparser/parsefn.awk271
-rw-r--r--source/aparser/parser.c471
-rw-r--r--source/aparser/parser.h103
-rw-r--r--source/aparser/parserel.awk213
-rw-r--r--source/aparser/parsetree.awk224
-rw-r--r--source/aparser/spool.struct90
-rw-r--r--source/aparser/spool_io_printer_driver_info_level_3.prsbin0 -> 5636 bytes
-rw-r--r--source/aparser/spool_io_printer_driver_info_level_6.prsbin0 -> 5636 bytes
-rw-r--r--source/aparser/srvsvc.struct184
-rw-r--r--source/aparser/srvsvc2.struct655
-rw-r--r--source/aparser/template.awk18
-rw-r--r--source/aparser/templates/fn_end.tpl13
-rw-r--r--source/aparser/templates/fn_end0.tpl8
-rw-r--r--source/aparser/templates/fn_i_end.tpl12
-rw-r--r--source/aparser/templates/fn_i_start.tpl15
-rw-r--r--source/aparser/templates/fn_mid.tpl6
-rw-r--r--source/aparser/templates/fn_start.tpl17
-rw-r--r--source/aparser/templates/harness.tpl5
-rw-r--r--source/aparser/templates/harness_end.tpl7
-rw-r--r--source/aparser/templates/harness_start.tpl7
-rw-r--r--source/aparser/templates/ifptr_end.tpl1
-rw-r--r--source/aparser/templates/ifptr_start.tpl2
-rw-r--r--source/aparser/templates/module_end.tpl3
-rw-r--r--source/aparser/templates/module_start.tpl5
-rw-r--r--source/aparser/templates/prs_.align.tpl1
-rw-r--r--source/aparser/templates/prs_align2.tpl1
-rw-r--r--source/aparser/templates/prs_align4.tpl1
-rw-r--r--source/aparser/templates/prs_array.tpl8
-rw-r--r--source/aparser/templates/prs_array_optional.tpl5
-rw-r--r--source/aparser/templates/prs_array_remainder.tpl17
-rw-r--r--source/aparser/templates/prs_break.tpl1
-rw-r--r--source/aparser/templates/prs_case.tpl1
-rw-r--r--source/aparser/templates/prs_case_end.tpl1
-rw-r--r--source/aparser/templates/prs_element.tpl1
-rw-r--r--source/aparser/templates/prs_pointer.tpl2
-rw-r--r--source/aparser/templates/prs_struct.tpl1
-rw-r--r--source/aparser/templates/prs_struct_alloc.tpl1
-rw-r--r--source/aparser/templates/prs_uint16.tpl1
-rw-r--r--source/aparser/templates/prs_uint32.tpl1
-rw-r--r--source/aparser/templates/prs_uint8s.tpl2
-rw-r--r--source/aparser/templates/prs_uint8s_fixed.tpl1
-rw-r--r--source/aparser/templates/prs_wstring.tpl2
-rw-r--r--source/aparser/templates/prs_wstring_fixed.tpl2
-rw-r--r--source/aparser/templates/union_end.tpl5
-rw-r--r--source/aparser/templates/union_start.tpl1
-rw-r--r--source/aparser/token.awk180
-rw-r--r--source/aparser/util.awk39
-rw-r--r--source/aparser/util.c112
-rw-r--r--source/aparser/vluke.c41
-rw-r--r--source/architecture.doc134
-rw-r--r--source/auth/auth.c272
-rw-r--r--source/auth/auth_builtin.c90
-rw-r--r--source/auth/auth_domain.c498
-rw-r--r--source/auth/auth_info.c291
-rw-r--r--source/auth/auth_rhosts.c228
-rw-r--r--source/auth/auth_sam.c447
-rw-r--r--source/auth/auth_server.c365
-rw-r--r--source/auth/auth_unix.c125
-rw-r--r--source/auth/auth_util.c750
-rw-r--r--source/auth/auth_winbind.c111
-rw-r--r--source/auth/pampass.c892
-rw-r--r--source/auth/pass_check.c776
-rw-r--r--source/bin/.cvsignore36
-rw-r--r--source/change-log12
-rw-r--r--source/client/.cvsignore0
-rw-r--r--source/client/client.c5959
-rw-r--r--source/client/clitar.c2032
-rw-r--r--source/client/smbmnt.c306
-rw-r--r--source/client/smbmount.c881
-rw-r--r--source/client/smbspool.c413
-rw-r--r--source/client/smbumount.c185
-rw-r--r--source/client/testsmbc.c456
-rw-r--r--source/client/tree.c812
-rw-r--r--source/codepages/.cvsignore0
-rw-r--r--source/codepages/lowcase.datbin0 -> 131072 bytes
-rw-r--r--source/codepages/upcase.datbin0 -> 131072 bytes
-rw-r--r--source/codepages/valid.datbin0 -> 65536 bytes
-rwxr-xr-xsource/config.guess1308
-rwxr-xr-xsource/config.sub1421
-rwxr-xr-xsource/configure13773
-rwxr-xr-xsource/configure.developer2
-rw-r--r--source/configure.in2583
-rwxr-xr-xsource/configure.nodebug.developer3
-rw-r--r--source/dynconfig.c73
-rw-r--r--source/groupdb/aliasdb.c386
-rw-r--r--source/groupdb/aliasfile.c289
-rw-r--r--source/groupdb/groupdb.c382
-rw-r--r--source/groupdb/groupfile.c284
-rw-r--r--source/groupdb/mapping.c1173
-rw-r--r--source/include/.cvsignore4
-rw-r--r--source/include/MacExtensions.h247
-rw-r--r--source/include/ads.h64
-rw-r--r--source/include/asn1.h54
-rw-r--r--source/include/auth.h135
-rw-r--r--source/include/byteorder.h93
-rw-r--r--source/include/charset.h48
-rw-r--r--source/include/client.h147
-rw-r--r--source/include/clitar.h25
-rw-r--r--source/include/config.h.in1093
-rw-r--r--source/include/debug.h198
-rw-r--r--source/include/dlinklist.h79
-rw-r--r--source/include/doserr.h186
-rw-r--r--source/include/dynconfig.h36
-rw-r--r--source/include/hash.h75
-rw-r--r--source/include/hmacmd5.h33
-rw-r--r--source/include/includes.h1652
-rw-r--r--source/include/interfaces.h12
-rw-r--r--source/include/intl.h25
-rw-r--r--source/include/kanji.h130
-rw-r--r--source/include/libsmbclient.h791
-rw-r--r--source/include/local.h196
-rw-r--r--source/include/mapping.h61
-rw-r--r--source/include/md5.h25
-rw-r--r--source/include/messages.h48
-rw-r--r--source/include/msdfs.h78
-rw-r--r--source/include/nameserv.h515
-rw-r--r--source/include/nt_printing.h335
-rw-r--r--source/include/ntdomain.h288
-rw-r--r--source/include/nterr.h563
-rw-r--r--source/include/passdb.h77
-rw-r--r--source/include/printing.h69
-rwxr-xr-xsource/include/rap.h508
-rw-r--r--source/include/rpc_brs.h81
-rw-r--r--source/include/rpc_client.h29
-rw-r--r--source/include/rpc_creds.h97
-rw-r--r--source/include/rpc_dce.h345
-rw-r--r--source/include/rpc_dfs.h198
-rw-r--r--source/include/rpc_lsa.h675
-rw-r--r--source/include/rpc_misc.h371
-rw-r--r--source/include/rpc_netlogon.h906
-rw-r--r--source/include/rpc_parse.h31
-rw-r--r--source/include/rpc_reg.h549
-rw-r--r--source/include/rpc_samr.h1808
-rw-r--r--source/include/rpc_secdes.h175
-rwxr-xr-xsource/include/rpc_spoolss.h1987
-rw-r--r--source/include/rpc_srvsvc.h812
-rw-r--r--source/include/rpc_wkssvc.h73
-rw-r--r--source/include/safe_string.h55
-rw-r--r--source/include/secrets.h40
-rw-r--r--source/include/session.h41
-rw-r--r--source/include/sids.h40
-rw-r--r--source/include/smb.h1992
-rw-r--r--source/include/smb_acls.h279
-rw-r--r--source/include/smb_macros.h270
-rw-r--r--source/include/smbprofile.h461
-rw-r--r--source/include/stamp-h.in1
-rw-r--r--source/include/talloc.h46
-rw-r--r--source/include/trans2.h75
-rw-r--r--source/include/util_getent.h62
-rw-r--r--source/include/util_list.h59
-rw-r--r--source/include/version.h2
-rw-r--r--source/include/vfs.h112
-rw-r--r--source/include/xfile.h48
-rwxr-xr-xsource/install-sh238
-rw-r--r--source/internals.doc281
-rw-r--r--source/intl/.cvsignore2
-rw-r--r--source/intl/lang_tdb.c223
-rw-r--r--source/intl/linux-msg.sed100
-rw-r--r--source/lib/.cvsignore3
-rw-r--r--source/lib/access.c589
-rw-r--r--source/lib/account_pol.c136
-rw-r--r--source/lib/bitmap.c140
-rw-r--r--source/lib/charcnv.c600
-rw-r--r--source/lib/charset.c111
-rw-r--r--source/lib/crc32.c68
-rw-r--r--source/lib/debug.c769
-rw-r--r--source/lib/dprintf.c111
-rw-r--r--source/lib/error.c75
-rw-r--r--source/lib/fault.c55
-rw-r--r--source/lib/fsusage.c149
-rw-r--r--source/lib/genrand.c267
-rw-r--r--source/lib/getsmbpass.c34
-rw-r--r--source/lib/hash.c316
-rw-r--r--source/lib/hmacmd5.c136
-rw-r--r--source/lib/iconv.c582
-rw-r--r--source/lib/interface.c371
-rw-r--r--source/lib/interfaces.c402
-rw-r--r--source/lib/kanji.c895
-rw-r--r--source/lib/md4.c447
-rw-r--r--source/lib/md5.c245
-rw-r--r--source/lib/messages.c430
-rw-r--r--source/lib/ms_fnmatch.c226
-rw-r--r--source/lib/netatalk.c156
-rw-r--r--source/lib/pidfile.c110
-rw-r--r--source/lib/readline.c119
-rw-r--r--source/lib/replace.c417
-rw-r--r--source/lib/select.c129
-rw-r--r--source/lib/signal.c140
-rw-r--r--source/lib/smbpasswd.c201
-rw-r--r--source/lib/smbrun.c181
-rw-r--r--source/lib/snprintf.c961
-rw-r--r--source/lib/substitute.c327
-rw-r--r--source/lib/sysacls.c3211
-rw-r--r--source/lib/system.c974
-rw-r--r--source/lib/talloc.c313
-rw-r--r--source/lib/talloctort.c63
-rw-r--r--source/lib/time.c725
-rw-r--r--source/lib/ufc.c67
-rw-r--r--source/lib/username.c724
-rw-r--r--source/lib/util.c5301
-rw-r--r--source/lib/util_file.c594
-rw-r--r--source/lib/util_getent.c313
-rw-r--r--source/lib/util_seaccess.c422
-rw-r--r--source/lib/util_sec.c423
-rw-r--r--source/lib/util_sid.c710
-rw-r--r--source/lib/util_sock.c1206
-rw-r--r--source/lib/util_str.c939
-rw-r--r--source/lib/util_unistr.c729
-rw-r--r--source/lib/wins_srv.c340
-rw-r--r--source/lib/xfile.c340
-rw-r--r--source/libads/.cvsignore2
-rw-r--r--source/libads/ads_struct.c162
-rw-r--r--source/libads/kerberos.c239
-rw-r--r--source/libads/krb5_setpw.c469
-rw-r--r--source/libads/ldap.c701
-rw-r--r--source/libads/sasl.c217
-rw-r--r--source/libads/util.c59
-rw-r--r--source/libsmb/.cvsignore3
-rw-r--r--source/libsmb/asn1.c414
-rw-r--r--source/libsmb/cli_dfs.c254
-rw-r--r--source/libsmb/cli_lsarpc.c1140
-rw-r--r--source/libsmb/cli_netlogon.c587
-rw-r--r--source/libsmb/cli_pipe_util.c80
-rw-r--r--source/libsmb/cli_reg.c114
-rw-r--r--source/libsmb/cli_samr.c1257
-rw-r--r--source/libsmb/cli_spoolss.c1134
-rw-r--r--source/libsmb/cli_srvsvc.c80
-rw-r--r--source/libsmb/cliconnect.c1343
-rw-r--r--source/libsmb/clidgram.c272
-rw-r--r--source/libsmb/clientgen.c281
-rw-r--r--source/libsmb/clierror.c268
-rw-r--r--source/libsmb/clifile.c830
-rw-r--r--source/libsmb/clikrb5.c146
-rw-r--r--source/libsmb/clilist.c465
-rw-r--r--source/libsmb/climessage.c121
-rw-r--r--source/libsmb/clioplock.c69
-rw-r--r--source/libsmb/cliprint.c158
-rw-r--r--source/libsmb/clirap.c694
-rw-r--r--source/libsmb/clirap2.c1962
-rw-r--r--source/libsmb/clireadwrite.c364
-rw-r--r--source/libsmb/clisecdesc.c132
-rw-r--r--source/libsmb/clispnego.c615
-rw-r--r--source/libsmb/clistr.c44
-rw-r--r--source/libsmb/clitrans.c469
-rw-r--r--source/libsmb/credentials.c216
-rw-r--r--source/libsmb/errormap.c1438
-rw-r--r--source/libsmb/libsmbclient.c2583
-rw-r--r--source/libsmb/namequery.c1233
-rw-r--r--source/libsmb/nmblib.c1184
-rw-r--r--source/libsmb/nterr.c581
-rw-r--r--source/libsmb/passchange.c102
-rw-r--r--source/libsmb/pwd_cache.c250
-rw-r--r--source/libsmb/smbdes.c416
-rw-r--r--source/libsmb/smbencrypt.c420
-rw-r--r--source/libsmb/smberr.c257
-rw-r--r--source/libsmb/trust_passwd.c116
-rw-r--r--source/libsmb/unexpected.c165
-rw-r--r--source/locking/brlock.c598
-rw-r--r--source/locking/locking.c891
-rw-r--r--source/locking/posix.c1316
-rw-r--r--source/mainpage.dox7
-rw-r--r--source/md4.h58
-rw-r--r--source/msdfs/README32
-rw-r--r--source/msdfs/msdfs.c738
-rw-r--r--source/nameserv.c2318
-rw-r--r--source/nmbd/.cvsignore0
-rw-r--r--source/nmbd/asyncdns.c347
-rw-r--r--source/nmbd/nmbd.c869
-rw-r--r--source/nmbd/nmbd_become_dmb.c400
-rw-r--r--source/nmbd/nmbd_become_lmb.c608
-rw-r--r--source/nmbd/nmbd_browserdb.c183
-rw-r--r--source/nmbd/nmbd_browsesync.c704
-rw-r--r--source/nmbd/nmbd_elections.c407
-rw-r--r--source/nmbd/nmbd_incomingdgrams.c861
-rw-r--r--source/nmbd/nmbd_incomingrequests.c624
-rw-r--r--source/nmbd/nmbd_lmhosts.c99
-rw-r--r--source/nmbd/nmbd_logonnames.c166
-rw-r--r--source/nmbd/nmbd_mynames.c225
-rw-r--r--source/nmbd/nmbd_namelistdb.c626
-rw-r--r--source/nmbd/nmbd_namequery.c296
-rw-r--r--source/nmbd/nmbd_nameregister.c400
-rw-r--r--source/nmbd/nmbd_namerelease.c234
-rw-r--r--source/nmbd/nmbd_nodestatus.c95
-rw-r--r--source/nmbd/nmbd_packets.c1979
-rw-r--r--source/nmbd/nmbd_processlogon.c390
-rw-r--r--source/nmbd/nmbd_responserecordsdb.c265
-rw-r--r--source/nmbd/nmbd_sendannounce.c606
-rw-r--r--source/nmbd/nmbd_serverlistdb.c457
-rw-r--r--source/nmbd/nmbd_subnetdb.c395
-rw-r--r--source/nmbd/nmbd_synclists.c298
-rw-r--r--source/nmbd/nmbd_winsproxy.c222
-rw-r--r--source/nmbd/nmbd_winsserver.c1659
-rw-r--r--source/nmbd/nmbd_workgroupdb.c347
-rw-r--r--source/nmbsync.c303
-rw-r--r--source/nsswitch/.cvsignore3
-rw-r--r--source/nsswitch/README13
-rw-r--r--source/nsswitch/nss.h89
-rw-r--r--source/nsswitch/pam_winbind.c514
-rw-r--r--source/nsswitch/pam_winbind.h81
-rw-r--r--source/nsswitch/wb_client.c472
-rw-r--r--source/nsswitch/wb_common.c374
-rw-r--r--source/nsswitch/wbinfo.c658
-rw-r--r--source/nsswitch/winbind_nss.c846
-rw-r--r--source/nsswitch/winbind_nss_config.h148
-rw-r--r--source/nsswitch/winbind_nss_solaris.c279
-rw-r--r--source/nsswitch/winbindd.c870
-rw-r--r--source/nsswitch/winbindd.h203
-rw-r--r--source/nsswitch/winbindd_ads.c752
-rw-r--r--source/nsswitch/winbindd_cache.c856
-rw-r--r--source/nsswitch/winbindd_cm.c732
-rw-r--r--source/nsswitch/winbindd_group.c841
-rw-r--r--source/nsswitch/winbindd_idmap.c301
-rw-r--r--source/nsswitch/winbindd_misc.c152
-rw-r--r--source/nsswitch/winbindd_nss.h187
-rw-r--r--source/nsswitch/winbindd_pam.c204
-rw-r--r--source/nsswitch/winbindd_proto.h114
-rw-r--r--source/nsswitch/winbindd_rpc.c570
-rw-r--r--source/nsswitch/winbindd_sid.c250
-rw-r--r--source/nsswitch/winbindd_user.c616
-rw-r--r--source/nsswitch/winbindd_util.c324
-rw-r--r--source/nsswitch/wins.c243
-rw-r--r--source/pam_smbpass/CHANGELOG31
-rw-r--r--source/pam_smbpass/README66
-rw-r--r--source/pam_smbpass/TODO7
-rw-r--r--source/pam_smbpass/general.h123
-rw-r--r--source/pam_smbpass/pam_smb_acct.c112
-rw-r--r--source/pam_smbpass/pam_smb_auth.c245
-rw-r--r--source/pam_smbpass/pam_smb_passwd.c313
-rw-r--r--source/pam_smbpass/samples/README3
-rw-r--r--source/pam_smbpass/samples/kdc-pdc15
-rw-r--r--source/pam_smbpass/samples/password-mature14
-rw-r--r--source/pam_smbpass/samples/password-migration18
-rw-r--r--source/pam_smbpass/samples/password-sync15
-rw-r--r--source/pam_smbpass/support.c624
-rw-r--r--source/pam_smbpass/support.h52
-rw-r--r--source/param/.cvsignore3
-rw-r--r--source/param/loadparm.c4802
-rw-r--r--source/param/params.c882
-rw-r--r--source/parsing.doc363
-rw-r--r--source/passdb/.cvsignore2
-rw-r--r--source/passdb/ldap.c1017
-rw-r--r--source/passdb/machine_sid.c255
-rw-r--r--source/passdb/nispass.c1083
-rw-r--r--source/passdb/pampass.c892
-rw-r--r--source/passdb/pass_check.c776
-rw-r--r--source/passdb/passdb.c1827
-rw-r--r--source/passdb/passgrp.c217
-rw-r--r--source/passdb/pdb_ldap.c1045
-rw-r--r--source/passdb/pdb_nisplus.c1409
-rw-r--r--source/passdb/pdb_smbpasswd.c1545
-rw-r--r--source/passdb/pdb_tdb.c808
-rw-r--r--source/passdb/secrets.c288
-rw-r--r--source/passdb/smbpass.c304
-rw-r--r--source/passdb/smbpasschange.c25
-rw-r--r--source/passdb/smbpassgroup.c195
-rw-r--r--source/po/de.msg1707
-rw-r--r--source/po/en.msg1707
-rw-r--r--source/po/fr.msg1709
-rw-r--r--source/po/it.msg1707
-rw-r--r--source/po/ja.msg1821
-rw-r--r--source/po/pl.msg1773
-rw-r--r--source/po/tr.msg1723
-rw-r--r--source/popt/.cvsignore8
-rw-r--r--source/popt/CHANGES43
-rw-r--r--source/popt/COPYING22
-rw-r--r--source/popt/README18
-rw-r--r--source/popt/dummy.in0
-rw-r--r--source/popt/findme.c46
-rw-r--r--source/popt/findme.h10
-rw-r--r--source/popt/popt.c782
-rw-r--r--source/popt/popt.h130
-rw-r--r--source/popt/poptconfig.c142
-rw-r--r--source/popt/popthelp.c301
-rw-r--r--source/popt/poptint.h71
-rw-r--r--source/popt/poptparse.c102
-rw-r--r--source/popt/system.h53
-rw-r--r--source/printing/.cvsignore0
-rw-r--r--source/printing/load.c74
-rw-r--r--source/printing/lpq_parse.c1101
-rw-r--r--source/printing/nt_printing.c3912
-rw-r--r--source/printing/pcap.c124
-rw-r--r--source/printing/print_cups.c1189
-rw-r--r--source/printing/print_generic.c243
-rw-r--r--source/printing/print_svid.c145
-rw-r--r--source/printing/printfsp.c96
-rw-r--r--source/printing/printing.c2151
-rw-r--r--source/profile/profile.c157
-rw-r--r--source/rpc_client/cli_login.c174
-rw-r--r--source/rpc_client/cli_netlogon.c471
-rw-r--r--source/rpc_client/cli_pipe.c1260
-rw-r--r--source/rpc_client/cli_reg.c1072
-rw-r--r--source/rpc_client/cli_samr.c838
-rw-r--r--source/rpc_client/cli_spoolss.c818
-rw-r--r--source/rpc_client/cli_spoolss_notify.c293
-rw-r--r--source/rpc_client/cli_srvsvc.c401
-rw-r--r--source/rpc_client/cli_trust.c152
-rw-r--r--source/rpc_client/cli_wkssvc.c85
-rw-r--r--source/rpc_client/msrpc_spoolss.c810
-rw-r--r--source/rpc_client/ntclienttrust.c158
-rw-r--r--source/rpc_parse/.cvsignore2
-rw-r--r--source/rpc_parse/parse_dfs.c543
-rw-r--r--source/rpc_parse/parse_lsa.c2098
-rw-r--r--source/rpc_parse/parse_misc.c1593
-rw-r--r--source/rpc_parse/parse_net.c2896
-rw-r--r--source/rpc_parse/parse_prs.c1237
-rw-r--r--source/rpc_parse/parse_reg.c1680
-rw-r--r--source/rpc_parse/parse_rpc.c1089
-rw-r--r--source/rpc_parse/parse_samr.c7218
-rw-r--r--source/rpc_parse/parse_sec.c806
-rw-r--r--source/rpc_parse/parse_spoolss.c6579
-rw-r--r--source/rpc_parse/parse_srv.c2795
-rw-r--r--source/rpc_parse/parse_wks.c176
-rw-r--r--source/rpc_server/.cvsignore0
-rw-r--r--source/rpc_server/srv_dfs.c177
-rw-r--r--source/rpc_server/srv_dfs_nt.c367
-rw-r--r--source/rpc_server/srv_lsa.c642
-rw-r--r--source/rpc_server/srv_lsa_hnd.c221
-rw-r--r--source/rpc_server/srv_lsa_nt.c1127
-rw-r--r--source/rpc_server/srv_netlog.c341
-rw-r--r--source/rpc_server/srv_netlog_nt.c682
-rw-r--r--source/rpc_server/srv_pipe.c1217
-rw-r--r--source/rpc_server/srv_pipe_hnd.c968
-rw-r--r--source/rpc_server/srv_reg.c209
-rw-r--r--source/rpc_server/srv_reg_nt.c238
-rw-r--r--source/rpc_server/srv_samr.c1442
-rw-r--r--source/rpc_server/srv_samr_nt.c3787
-rwxr-xr-xsource/rpc_server/srv_spoolss.c1418
-rw-r--r--source/rpc_server/srv_spoolss_nt.c7171
-rw-r--r--source/rpc_server/srv_srvsvc.c523
-rw-r--r--source/rpc_server/srv_srvsvc_nt.c1880
-rw-r--r--source/rpc_server/srv_util.c515
-rw-r--r--source/rpc_server/srv_wkssvc.c71
-rw-r--r--source/rpc_server/srv_wkssvc_nt.c79
-rw-r--r--source/rpcclient/cmd_dfs.c238
-rw-r--r--source/rpcclient/cmd_lsarpc.c510
-rw-r--r--source/rpcclient/cmd_netlogon.c335
-rw-r--r--source/rpcclient/cmd_reg.c1029
-rw-r--r--source/rpcclient/cmd_samr.c1205
-rw-r--r--source/rpcclient/cmd_spoolss.c1154
-rw-r--r--source/rpcclient/cmd_srvsvc.c234
-rw-r--r--source/rpcclient/cmd_wkssvc.c85
-rw-r--r--source/rpcclient/display.c1339
-rw-r--r--source/rpcclient/display_sec.c145
-rw-r--r--source/rpcclient/display_spool.c928
-rw-r--r--source/rpcclient/rpcclient.c733
-rw-r--r--source/rpcclient/rpcclient.h35
-rw-r--r--source/rpcclient/samsync.c620
-rw-r--r--source/rpcclient/spoolss_cmds.c89
-rw-r--r--source/script/.cvsignore0
-rw-r--r--source/script/addtosmbpass8
-rwxr-xr-xsource/script/build_env.sh35
-rwxr-xr-xsource/script/convert_smbpasswd17
-rwxr-xr-xsource/script/extract_allparms.sh2
-rwxr-xr-xsource/script/installbin.sh25
-rwxr-xr-xsource/script/installcp.sh44
-rwxr-xr-xsource/script/installman.sh90
-rwxr-xr-xsource/script/installscripts.sh47
-rwxr-xr-xsource/script/installswat.sh127
-rw-r--r--source/script/makeunicodecasemap.awk59
-rwxr-xr-xsource/script/makeyodldocs.sh92
-rwxr-xr-xsource/script/mkinstalldirs40
-rwxr-xr-xsource/script/mknissmbpasswd.sh31
-rwxr-xr-xsource/script/mknissmbpwdtbl.sh42
-rw-r--r--source/script/mkproto.awk153
-rwxr-xr-xsource/script/mkproto.sh41
-rwxr-xr-xsource/script/mksmbpasswd.sh2
-rwxr-xr-xsource/script/revert.sh13
-rwxr-xr-xsource/script/scancvslog.pl112
-rw-r--r--source/script/smbtar43
-rwxr-xr-xsource/script/uninstallbin.sh42
-rwxr-xr-xsource/script/uninstallcp.sh33
-rwxr-xr-xsource/script/uninstallman.sh37
-rwxr-xr-xsource/script/uninstallscripts.sh36
-rwxr-xr-xsource/smbadduser73
-rw-r--r--source/smbd/.cvsignore2
-rw-r--r--source/smbd/blocking.c630
-rw-r--r--source/smbd/build_options.c537
-rw-r--r--source/smbd/chgpasswd.c1201
-rw-r--r--source/smbd/close.c291
-rw-r--r--source/smbd/conn.c227
-rw-r--r--source/smbd/connection.c190
-rw-r--r--source/smbd/dfree.c165
-rw-r--r--source/smbd/dir.c1228
-rw-r--r--source/smbd/dosmode.c336
-rw-r--r--source/smbd/error.c148
-rw-r--r--source/smbd/fileio.c598
-rw-r--r--source/smbd/filename.c507
-rw-r--r--source/smbd/files.c401
-rw-r--r--source/smbd/groupname.c239
-rw-r--r--source/smbd/ipc.c3008
-rw-r--r--source/smbd/lanman.c3682
-rw-r--r--source/smbd/mangle.c1393
-rw-r--r--source/smbd/message.c153
-rw-r--r--source/smbd/negprot.c505
-rw-r--r--source/smbd/noquotas.c39
-rw-r--r--source/smbd/notify.c221
-rw-r--r--source/smbd/notify_hash.c226
-rw-r--r--source/smbd/notify_kernel.c207
-rw-r--r--source/smbd/nttrans.c1880
-rw-r--r--source/smbd/open.c1312
-rw-r--r--source/smbd/oplock.c1218
-rw-r--r--source/smbd/oplock_irix.c286
-rw-r--r--source/smbd/oplock_linux.c301
-rw-r--r--source/smbd/password.c1690
-rw-r--r--source/smbd/pipes.c263
-rw-r--r--source/smbd/posix_acls.c2295
-rw-r--r--source/smbd/process.c1292
-rw-r--r--source/smbd/quotas.c1098
-rw-r--r--source/smbd/reply.c5274
-rw-r--r--source/smbd/sec_ctx.c425
-rw-r--r--source/smbd/server.c4689
-rw-r--r--source/smbd/service.c742
-rw-r--r--source/smbd/session.c175
-rw-r--r--source/smbd/sesssetup.c799
-rw-r--r--source/smbd/smbrun.c96
-rw-r--r--source/smbd/srvstr.c33
-rw-r--r--source/smbd/ssl.c287
-rw-r--r--source/smbd/statcache.c231
-rw-r--r--source/smbd/trans2.c3184
-rw-r--r--source/smbd/uid.c709
-rw-r--r--source/smbd/utmp.c607
-rw-r--r--source/smbd/vfs-wrap.c650
-rw-r--r--source/smbd/vfs.c789
-rw-r--r--source/smbd/vt_mode.c496
-rw-r--r--source/smbwrapper/.cvsignore8
-rw-r--r--source/smbwrapper/PORTING77
-rw-r--r--source/smbwrapper/README94
-rw-r--r--source/smbwrapper/init.c22
-rw-r--r--source/smbwrapper/realcalls.c49
-rw-r--r--source/smbwrapper/realcalls.h264
-rw-r--r--source/smbwrapper/shared.c222
-rw-r--r--source/smbwrapper/smbsh.c128
-rw-r--r--source/smbwrapper/smbsh.in54
-rw-r--r--source/smbwrapper/smbw.c1555
-rw-r--r--source/smbwrapper/smbw.h72
-rw-r--r--source/smbwrapper/smbw_cache.c208
-rw-r--r--source/smbwrapper/smbw_dir.c689
-rw-r--r--source/smbwrapper/smbw_stat.c251
-rw-r--r--source/smbwrapper/wrapped.c706
-rw-r--r--source/tdb/.cvsignore10
-rw-r--r--source/tdb/Makefile26
-rw-r--r--source/tdb/README167
-rw-r--r--source/tdb/spinlock.c430
-rw-r--r--source/tdb/spinlock.h55
-rw-r--r--source/tdb/tdb.c1742
-rw-r--r--source/tdb/tdb.h141
-rw-r--r--source/tdb/tdb.magic10
-rw-r--r--source/tdb/tdbdump.c89
-rw-r--r--source/tdb/tdbtest.c262
-rw-r--r--source/tdb/tdbtool.c479
-rw-r--r--source/tdb/tdbtorture.c216
-rw-r--r--source/tdb/tdbutil.c401
-rw-r--r--source/tests/.cvsignore1
-rw-r--r--source/tests/README10
-rw-r--r--source/tests/crypttest.c852
-rw-r--r--source/tests/fcntl_lock.c121
-rw-r--r--source/tests/fcntl_lock64.c96
-rw-r--r--source/tests/ftruncate.c27
-rw-r--r--source/tests/getgroups.c66
-rw-r--r--source/tests/shared_mmap.c68
-rw-r--r--source/tests/summary.c30
-rw-r--r--source/tests/trivial.c4
-rw-r--r--source/tests/unixsock.c93
-rw-r--r--source/torture/denytest.c1567
-rw-r--r--source/torture/locktest.c625
-rw-r--r--source/torture/locktest2.c616
-rw-r--r--source/torture/masktest.c513
-rw-r--r--source/torture/msgtest.c92
-rw-r--r--source/torture/nbio.c240
-rw-r--r--source/torture/nsstest.c411
-rw-r--r--source/torture/rpctorture.c546
-rw-r--r--source/torture/scanner.c431
-rw-r--r--source/torture/torture.c3272
-rw-r--r--source/torture/utable.c187
-rw-r--r--source/ubiqx/.cvsignore3
-rw-r--r--source/ubiqx/COPYING.LIB481
-rw-r--r--source/ubiqx/README.UBI18
-rw-r--r--source/ubiqx/debugparse.c308
-rw-r--r--source/ubiqx/debugparse.h127
-rw-r--r--source/ubiqx/sys_include.h52
-rw-r--r--source/ubiqx/ubi_BinTree.c1132
-rw-r--r--source/ubiqx/ubi_BinTree.h864
-rw-r--r--source/ubiqx/ubi_Cache.c505
-rw-r--r--source/ubiqx/ubi_Cache.h412
-rw-r--r--source/ubiqx/ubi_SplayTree.c512
-rw-r--r--source/ubiqx/ubi_SplayTree.h377
-rw-r--r--source/ubiqx/ubi_dLinkList.c171
-rw-r--r--source/ubiqx/ubi_dLinkList.h242
-rw-r--r--source/ubiqx/ubi_sLinkList.c187
-rw-r--r--source/ubiqx/ubi_sLinkList.h254
-rw-r--r--source/utils/debug2html.c253
-rw-r--r--source/utils/make_printerdef.c586
-rw-r--r--source/utils/net.c454
-rw-r--r--source/utils/net.h45
-rw-r--r--source/utils/net_ads.c391
-rw-r--r--source/utils/net_lookup.c62
-rw-r--r--source/utils/net_rap.c1127
-rw-r--r--source/utils/net_rpc.c261
-rw-r--r--source/utils/net_rpc_join.c296
-rw-r--r--source/utils/net_time.c182
-rw-r--r--source/utils/nmblookup.c293
-rw-r--r--source/utils/pdbedit.c675
-rw-r--r--source/utils/rpccheck.c63
-rw-r--r--source/utils/smbcacls.c959
-rw-r--r--source/utils/smbcontrol.c432
-rw-r--r--source/utils/smbfilter.c247
-rw-r--r--source/utils/smbgroupedit.c359
-rw-r--r--source/utils/smbpasswd.c972
-rw-r--r--source/utils/smbtree.c424
-rw-r--r--source/utils/smbw_sample.c94
-rw-r--r--source/utils/status.c846
-rw-r--r--source/utils/testparm.c289
-rw-r--r--source/utils/testprns.c19
-rw-r--r--source/web/.cvsignore0
-rw-r--r--source/web/cgi.c662
-rw-r--r--source/web/diagnose.c67
-rw-r--r--source/web/neg_lang.c67
-rw-r--r--source/web/startstop.c105
-rw-r--r--source/web/statuspage.c374
-rw-r--r--source/web/swat.c1119
-rw-r--r--swat/README77
-rw-r--r--swat/help/welcome.html68
-rw-r--r--swat/images/globals.gifbin0 -> 628 bytes
-rw-r--r--swat/images/home.gifbin0 -> 580 bytes
-rw-r--r--swat/images/passwd.gifbin0 -> 613 bytes
-rw-r--r--swat/images/printers.gifbin0 -> 705 bytes
-rw-r--r--swat/images/samba.gifbin0 -> 3643 bytes
-rw-r--r--swat/images/shares.gifbin0 -> 569 bytes
-rw-r--r--swat/images/status.gifbin0 -> 578 bytes
-rw-r--r--swat/images/viewconfig.gifbin0 -> 820 bytes
-rw-r--r--swat/include/footer.html3
-rw-r--r--swat/include/header.html10
-rw-r--r--swat/lang/ja/help/welcome.html86
-rw-r--r--swat/lang/ja/images/globals.gifbin0 -> 1613 bytes
-rw-r--r--swat/lang/ja/images/home.gifbin0 -> 1881 bytes
-rw-r--r--swat/lang/ja/images/passwd.gifbin0 -> 1427 bytes
-rw-r--r--swat/lang/ja/images/printers.gifbin0 -> 1987 bytes
-rw-r--r--swat/lang/ja/images/samba.gifbin0 -> 3877 bytes
-rw-r--r--swat/lang/ja/images/shares.gifbin0 -> 1590 bytes
-rw-r--r--swat/lang/ja/images/status.gifbin0 -> 2582 bytes
-rw-r--r--swat/lang/ja/images/viewconfig.gifbin0 -> 1485 bytes
-rw-r--r--swat/lang/ja/include/footer.html3
-rw-r--r--swat/lang/ja/include/header.html12
-rw-r--r--swat/lang/ja/include/header.nocss.html11
-rw-r--r--swat/lang/ja/include/header_css.html1
-rw-r--r--swat/lang/tr/help/welcome.html69
-rw-r--r--swat/lang/tr/images/globals.gifbin0 -> 442 bytes
-rw-r--r--swat/lang/tr/images/home.gifbin0 -> 608 bytes
-rw-r--r--swat/lang/tr/images/passwd.gifbin0 -> 326 bytes
-rw-r--r--swat/lang/tr/images/printers.gifbin0 -> 519 bytes
-rw-r--r--swat/lang/tr/images/samba.gifbin0 -> 3643 bytes
-rw-r--r--swat/lang/tr/images/shares.gifbin0 -> 474 bytes
-rw-r--r--swat/lang/tr/images/status.gifbin0 -> 431 bytes
-rw-r--r--swat/lang/tr/images/viewconfig.gifbin0 -> 455 bytes
-rw-r--r--swat/lang/tr/include/header.html10
-rw-r--r--testsuite/README19
-rw-r--r--testsuite/build_farm/basicsmb-domainsec-nt4.test31
-rw-r--r--testsuite/build_farm/basicsmb-domainsec.test30
-rw-r--r--testsuite/build_farm/basicsmb-hostsdeny.test18
-rw-r--r--testsuite/build_farm/basicsmb-hostsequiv.test26
-rw-r--r--testsuite/build_farm/basicsmb-invalidusers.test8
-rw-r--r--testsuite/build_farm/basicsmb-local-pass-change.test10
-rw-r--r--testsuite/build_farm/basicsmb-remote-pass-change.test10
-rw-r--r--testsuite/build_farm/basicsmb-serversec.test9
-rw-r--r--testsuite/build_farm/basicsmb-shareguest.test20
-rw-r--r--testsuite/build_farm/basicsmb-sharelist.test19
-rw-r--r--testsuite/build_farm/basicsmb-sharesec.test9
-rw-r--r--testsuite/build_farm/basicsmb-usersec.test9
-rw-r--r--testsuite/build_farm/basicsmb.fns186
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.domain2
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.hostsdeny1
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.hostsequiv.template3
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.invalidusers.template1
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.server3
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.share1
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.template43
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.user1
-rw-r--r--testsuite/build_farm/runlist3
-rw-r--r--testsuite/build_farm/torture-ATTR.test2
-rw-r--r--testsuite/build_farm/torture-BROWSE.test2
-rw-r--r--testsuite/build_farm/torture-DELETE.test2
-rw-r--r--testsuite/build_farm/torture-DENY1.test2
-rw-r--r--testsuite/build_farm/torture-DENY2.test2
-rw-r--r--testsuite/build_farm/torture-DIR.test2
-rw-r--r--testsuite/build_farm/torture-FDPASS.test2
-rw-r--r--testsuite/build_farm/torture-LOCK1.test2
-rw-r--r--testsuite/build_farm/torture-LOCK2.test2
-rw-r--r--testsuite/build_farm/torture-LOCK3.test2
-rw-r--r--testsuite/build_farm/torture-LOCK4.test2
-rw-r--r--testsuite/build_farm/torture-LOCK5.test2
-rw-r--r--testsuite/build_farm/torture-OPEN.test2
-rw-r--r--testsuite/build_farm/torture-OPLOCK1.test2
-rw-r--r--testsuite/build_farm/torture-OPLOCK3.test2
-rw-r--r--testsuite/build_farm/torture-RANDOMIPC.test2
-rw-r--r--testsuite/build_farm/torture-RW1.test2
-rw-r--r--testsuite/build_farm/torture-RW2.test2
-rw-r--r--testsuite/build_farm/torture-TCON.test2
-rw-r--r--testsuite/build_farm/torture-TORTURE.test2
-rw-r--r--testsuite/build_farm/torture-TRANS2.test2
-rw-r--r--testsuite/build_farm/torture-UNLINK.test2
-rw-r--r--testsuite/build_farm/torture_setup.fns19
-rw-r--r--testsuite/config/unix.exp27
-rw-r--r--testsuite/lib/compile.exp79
-rw-r--r--testsuite/lib/default-nt-names.exp20
-rw-r--r--testsuite/lib/env-single.exp36
-rw-r--r--testsuite/lib/nsswitch-config.exp21
-rw-r--r--testsuite/lib/smbclient.exp54
-rw-r--r--testsuite/libsmbclient/src/Makefile817
-rw-r--r--testsuite/libsmbclient/src/chmod/chmod_1.c59
-rw-r--r--testsuite/libsmbclient/src/chown/chown_1.c59
-rw-r--r--testsuite/libsmbclient/src/close/close_1.c59
-rw-r--r--testsuite/libsmbclient/src/close/close_2.c57
-rw-r--r--testsuite/libsmbclient/src/closedir/closedir_1.c65
-rw-r--r--testsuite/libsmbclient/src/closedir/closedir_2.c61
-rw-r--r--testsuite/libsmbclient/src/closedir/closedir_3.c63
-rw-r--r--testsuite/libsmbclient/src/closedir/closedir_4.c59
-rw-r--r--testsuite/libsmbclient/src/creat/creat_1.c60
-rw-r--r--testsuite/libsmbclient/src/creat/creat_2.c63
-rw-r--r--testsuite/libsmbclient/src/creat/creat_3.c56
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_1.c62
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_2.c58
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_3.c69
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_4.c69
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_5.c77
-rw-r--r--testsuite/libsmbclient/src/fstat/fstat_6.c80
-rw-r--r--testsuite/libsmbclient/src/getdents/getdents_1.c72
-rw-r--r--testsuite/libsmbclient/src/getdents/getdents_2.c67
-rw-r--r--testsuite/libsmbclient/src/getdents/getdents_3.c155
-rw-r--r--testsuite/libsmbclient/src/getdents/getdents_4.c101
-rw-r--r--testsuite/libsmbclient/src/getdents/getdents_5.c106
-rw-r--r--testsuite/libsmbclient/src/init/init_1.c18
-rw-r--r--testsuite/libsmbclient/src/init/init_2.c23
-rw-r--r--testsuite/libsmbclient/src/init/init_3.c58
-rw-r--r--testsuite/libsmbclient/src/init/init_4.c18
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_1.c109
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_2.c105
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_3.c103
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_4.c99
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_5.c101
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_6.c110
-rw-r--r--testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_7.c106
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_1.c61
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_2.c57
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_3.c80
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_4.c80
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_5.c80
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_6.c75
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_7.c80
-rw-r--r--testsuite/libsmbclient/src/lseek/lseek_8.c75
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_1.c102
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_2.c95
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_3.c67
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_4.c61
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_5.c119
-rw-r--r--testsuite/libsmbclient/src/lseekdir/lseekdir_6.c124
-rw-r--r--testsuite/libsmbclient/src/mkdir/mkdir_1.c60
-rw-r--r--testsuite/libsmbclient/src/mkdir/mkdir_2.c56
-rw-r--r--testsuite/libsmbclient/src/mkdir/mkdir_3.c58
-rw-r--r--testsuite/libsmbclient/src/mkdir/mkdir_4.c62
-rw-r--r--testsuite/libsmbclient/src/open/open_1.c60
-rw-r--r--testsuite/libsmbclient/src/open/open_2.c56
-rw-r--r--testsuite/libsmbclient/src/open/open_3.c60
-rw-r--r--testsuite/libsmbclient/src/open/open_4.c63
-rw-r--r--testsuite/libsmbclient/src/open/open_5.c58
-rw-r--r--testsuite/libsmbclient/src/open_print_job/open_print_job_1.c60
-rw-r--r--testsuite/libsmbclient/src/open_print_job/open_print_job_2.c56
-rw-r--r--testsuite/libsmbclient/src/opendir/opendir_1.c62
-rw-r--r--testsuite/libsmbclient/src/opendir/opendir_2.c55
-rw-r--r--testsuite/libsmbclient/src/opendir/opendir_3.c65
-rw-r--r--testsuite/libsmbclient/src/opendir/opendir_4.c61
-rw-r--r--testsuite/libsmbclient/src/print_file/print_file_1.c76
-rw-r--r--testsuite/libsmbclient/src/print_file/print_file_2.c72
-rw-r--r--testsuite/libsmbclient/src/print_file/print_file_3.c59
-rw-r--r--testsuite/libsmbclient/src/print_file/print_file_4.c55
-rw-r--r--testsuite/libsmbclient/src/read/read_1.c83
-rw-r--r--testsuite/libsmbclient/src/read/read_10.c68
-rw-r--r--testsuite/libsmbclient/src/read/read_11.c83
-rw-r--r--testsuite/libsmbclient/src/read/read_12.c87
-rw-r--r--testsuite/libsmbclient/src/read/read_13.c91
-rw-r--r--testsuite/libsmbclient/src/read/read_2.c76
-rw-r--r--testsuite/libsmbclient/src/read/read_3.c83
-rw-r--r--testsuite/libsmbclient/src/read/read_4.c77
-rw-r--r--testsuite/libsmbclient/src/read/read_5.c83
-rw-r--r--testsuite/libsmbclient/src/read/read_6.c77
-rw-r--r--testsuite/libsmbclient/src/read/read_7.c60
-rw-r--r--testsuite/libsmbclient/src/read/read_8.c56
-rw-r--r--testsuite/libsmbclient/src/read/read_9.c70
-rw-r--r--testsuite/libsmbclient/src/readdir/readdir_1.c107
-rw-r--r--testsuite/libsmbclient/src/readdir/readdir_2.c102
-rw-r--r--testsuite/libsmbclient/src/readdir/readdir_3.c71
-rw-r--r--testsuite/libsmbclient/src/readdir/readdir_4.c67
-rw-r--r--testsuite/libsmbclient/src/readdir/readdir_5.c155
-rw-r--r--testsuite/libsmbclient/src/rename/rename_1.c57
-rw-r--r--testsuite/libsmbclient/src/rename/rename_10.c64
-rw-r--r--testsuite/libsmbclient/src/rename/rename_11.c63
-rw-r--r--testsuite/libsmbclient/src/rename/rename_12.c58
-rw-r--r--testsuite/libsmbclient/src/rename/rename_13.c63
-rw-r--r--testsuite/libsmbclient/src/rename/rename_14.c58
-rw-r--r--testsuite/libsmbclient/src/rename/rename_2.c54
-rw-r--r--testsuite/libsmbclient/src/rename/rename_3.c56
-rw-r--r--testsuite/libsmbclient/src/rename/rename_4.c55
-rw-r--r--testsuite/libsmbclient/src/rename/rename_5.c59
-rw-r--r--testsuite/libsmbclient/src/rename/rename_6.c57
-rw-r--r--testsuite/libsmbclient/src/rename/rename_7.c66
-rw-r--r--testsuite/libsmbclient/src/rename/rename_8.c68
-rw-r--r--testsuite/libsmbclient/src/rename/rename_9.c68
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_1.c59
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_2.c55
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_3.c61
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_4.c57
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_5.c63
-rw-r--r--testsuite/libsmbclient/src/rmdir/rmdir_6.c59
-rw-r--r--testsuite/libsmbclient/src/stat/stat_1.c62
-rw-r--r--testsuite/libsmbclient/src/stat/stat_2.c58
-rw-r--r--testsuite/libsmbclient/src/stat/stat_3.c66
-rw-r--r--testsuite/libsmbclient/src/stat/stat_4.c62
-rw-r--r--testsuite/libsmbclient/src/stat/stat_5.c77
-rw-r--r--testsuite/libsmbclient/src/stat/stat_6.c80
-rw-r--r--testsuite/libsmbclient/src/telldir/telldir_1.c102
-rw-r--r--testsuite/libsmbclient/src/telldir/telldir_2.c95
-rw-r--r--testsuite/libsmbclient/src/telldir/telldir_3.c67
-rw-r--r--testsuite/libsmbclient/src/telldir/telldir_4.c61
-rw-r--r--testsuite/libsmbclient/src/telldir/telldir_5.c122
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_1.c61
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_10.c62
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_11.c66
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_12.c65
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_2.c61
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_3.c57
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_4.c64
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_5.c62
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_6.c58
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_7.c62
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_8.c55
-rw-r--r--testsuite/libsmbclient/src/unlink/unlink_9.c57
-rw-r--r--testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_1.c107
-rw-r--r--testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_2.c102
-rw-r--r--testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_3.c106
-rw-r--r--testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_4.c101
-rw-r--r--testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_5.c141
-rw-r--r--testsuite/libsmbclient/src/write/write_1.c77
-rw-r--r--testsuite/libsmbclient/src/write/write_10.c70
-rw-r--r--testsuite/libsmbclient/src/write/write_11.c83
-rw-r--r--testsuite/libsmbclient/src/write/write_12.c83
-rw-r--r--testsuite/libsmbclient/src/write/write_13.c87
-rw-r--r--testsuite/libsmbclient/src/write/write_2.c71
-rw-r--r--testsuite/libsmbclient/src/write/write_3.c79
-rw-r--r--testsuite/libsmbclient/src/write/write_4.c74
-rw-r--r--testsuite/libsmbclient/src/write/write_5.c79
-rw-r--r--testsuite/libsmbclient/src/write/write_6.c74
-rw-r--r--testsuite/libsmbclient/src/write/write_7.c60
-rw-r--r--testsuite/libsmbclient/src/write/write_8.c56
-rw-r--r--testsuite/libsmbclient/src/write/write_9.c72
-rw-r--r--testsuite/nsswitch/.cvsignore12
-rw-r--r--testsuite/nsswitch/Makefile.longarg5
-rw-r--r--testsuite/nsswitch/bigfd.c38
-rw-r--r--testsuite/nsswitch/bigfd.exp28
-rw-r--r--testsuite/nsswitch/domusers.exp38
-rw-r--r--testsuite/nsswitch/envvar.exp282
-rw-r--r--testsuite/nsswitch/finger.exp39
-rw-r--r--testsuite/nsswitch/getent.c151
-rw-r--r--testsuite/nsswitch/getent.exp148
-rw-r--r--testsuite/nsswitch/getent_grent.c101
-rw-r--r--testsuite/nsswitch/getent_pwent.c113
-rwxr-xr-xtestsuite/nsswitch/getent_r.sh35
-rw-r--r--testsuite/nsswitch/getgrent_r.c84
-rw-r--r--testsuite/nsswitch/getgrent_r.exp41
-rw-r--r--testsuite/nsswitch/getgrgid.c57
-rw-r--r--testsuite/nsswitch/getgrgid.exp50
-rw-r--r--testsuite/nsswitch/getgrnam.c51
-rw-r--r--testsuite/nsswitch/getgrnam.exp28
-rw-r--r--testsuite/nsswitch/getpwent_r.c85
-rw-r--r--testsuite/nsswitch/getpwent_r.exp41
-rw-r--r--testsuite/nsswitch/getpwnam.c37
-rw-r--r--testsuite/nsswitch/getpwnam.exp28
-rw-r--r--testsuite/nsswitch/getpwuid.c43
-rw-r--r--testsuite/nsswitch/getpwuid.exp59
-rw-r--r--testsuite/nsswitch/groupmem_dom.exp33
-rw-r--r--testsuite/nsswitch/initgroups.c42
-rw-r--r--testsuite/nsswitch/initgroups.exp37
-rw-r--r--testsuite/nsswitch/login.exp102
-rw-r--r--testsuite/nsswitch/longarg.exp29
-rw-r--r--testsuite/nsswitch/longarg_getgrnam.c42
-rw-r--r--testsuite/nsswitch/longarg_getpwnam.c42
-rw-r--r--testsuite/nsswitch/longarg_utils.h27
-rw-r--r--testsuite/nsswitch/nss_winbind_syms.c63
-rw-r--r--testsuite/nsswitch/nss_winbind_syms.exp42
-rw-r--r--testsuite/nsswitch/pam_winbind_syms.c55
-rw-r--r--testsuite/nsswitch/pam_winbind_syms.exp44
-rw-r--r--testsuite/nsswitch/wbinfo.exp360
-rw-r--r--testsuite/printing/.cvsignore2
-rw-r--r--testsuite/printing/Makefile.psec22
-rw-r--r--testsuite/printing/Makefile.vlp14
-rw-r--r--testsuite/printing/README.vlp35
-rw-r--r--testsuite/printing/psec.c433
-rw-r--r--testsuite/printing/vlp.c426
-rw-r--r--testsuite/server/ipc.exp44
-rw-r--r--testsuite/server/masktest.exp57
-rw-r--r--testsuite/server/rename.exp59
-rw-r--r--testsuite/server/xfer.exp48
-rw-r--r--testsuite/smbd/Makefile.se_access_check24
-rw-r--r--testsuite/smbd/Makefile.sec_ctx57
-rw-r--r--testsuite/smbd/se_access_check.exp54
-rw-r--r--testsuite/smbd/se_access_check_allowall.c87
-rw-r--r--testsuite/smbd/se_access_check_allowsome.c104
-rw-r--r--testsuite/smbd/se_access_check_denyall.c86
-rw-r--r--testsuite/smbd/se_access_check_denysome.c106
-rw-r--r--testsuite/smbd/se_access_check_empty.c109
-rw-r--r--testsuite/smbd/se_access_check_nullsd.c74
-rw-r--r--testsuite/smbd/se_access_check_printer.c212
-rw-r--r--testsuite/smbd/se_access_check_utils.c158
-rw-r--r--testsuite/smbd/se_access_check_utils.h46
-rw-r--r--testsuite/smbd/sec_ctx.exp67
-rw-r--r--testsuite/smbd/sec_ctx1.c40
-rw-r--r--testsuite/smbd/sec_ctx_current_user.c114
-rw-r--r--testsuite/smbd/sec_ctx_flow.c73
-rw-r--r--testsuite/smbd/sec_ctx_groups.c131
-rw-r--r--testsuite/smbd/sec_ctx_nonroot.c42
-rw-r--r--testsuite/smbd/sec_ctx_root.c61
-rw-r--r--testsuite/smbd/sec_ctx_stack.c86
-rw-r--r--testsuite/smbd/sec_ctx_torture.c103
-rw-r--r--testsuite/smbd/sec_ctx_utils.c65
-rw-r--r--testsuite/smbd/sec_ctx_utils.h30
-rw-r--r--testsuite/smbd/sighup.exp107
1561 files changed, 490341 insertions, 39517 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 00000000000..30433041802
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,2 @@
+ID
+testtmp
diff --git a/Manifest b/Manifest
new file mode 100644
index 00000000000..18e2d89c3e9
--- /dev/null
+++ b/Manifest
@@ -0,0 +1,95 @@
+Copyright (C) 1997-1998 - Samba-Team
+
+The Samba package you have just unpacked contains the following:
+
+Directory Notes:
+========= ======
+
+docs (Samba Documentation):
+---- ----------------------
+
+ The Samba documentation for the 2.0 release has had all the man pages
+ converted to YODL source format. Because of this the man pages
+ are now available in both traditional man page format (in
+ the doc/manpages directory) and in HTML format (in the
+ docs/htmldocs directory).
+
+ The text documentation files have been moved into a
+ docs/textdocs directory and are in the (slow) process
+ of being converted to YODL source format to allow them
+ to be easily converted to HTML/SGML.
+
+ Note in particular two files - docs/textdocs/<your OS>_INSTALL.txt
+ and docs/textdocs/DIAGNOSIS.txt.
+
+ There is the potential for there to be many *INSTALL.txt files, one
+ for each OS that Samba supports. However we are moving all this into
+ the new structure. For now, most people will be using UNIX_INSTALL.txt.
+
+ Please pay close attention to all the files with a .txt extension
+ in the docs/textdocs directory. Most problems can be solved by reference
+ to the two files mentioned.
+
+ The FAQ documentation can be accessed starting from Samba-meta-FAQ.html,
+ in the docs/faq directory. This is incomplete, but to quote from the
+ abstract, it:
+
+ "contains overview information for the Samba suite of programs,
+ a quick-start guide, and pointers to all other Samba documentation.
+ Other FAQs exist for specific client and server issues, and HOWTO
+ documents for more extended topics to do with Samba software."
+
+
+examples (Example configuration files):
+-------- ------------------------------
+
+ Please pay close attention to the reference smb.conf file
+ smb.conf.default that has now been included as the master guide.
+
+ Do read the smb.conf manual page in considering what settings are
+ appropriate for your site.
+
+
+packaging (Only for those wishing to build binary distributions):
+--------- -------------------------------------------------------
+
+ Currently support is included for the following Linux Distributions :
+
+ Pacfic HiTech, RedHat and SuSE.
+
+ In addition, packaging support is available for SGI and Solaris systems.
+ We hope that other Unix OS vendors will contribute their binary
+ distribution packaging control files - and we hope to make their binary
+ packages available on the master ftp site under:
+
+ ftp://samba.org/pub/samba/Binary_Packages/"OS_Vendor"
+
+
+source (The official Samba source files - expect more of these!):
+------ ----------------------------------------------------------
+
+ To build your own binary files you will need a suitable ansi C
+ compiler.
+
+ For Samba 2.0 the GNU autoconf system has been adopted. In
+ order to build a default Samba for your platform cd into
+ the source/ directory and then type :
+
+ ./configure
+
+ followed by :
+
+ make
+
+ To install the binaries built by the above type :
+
+ make install
+
+ then set up your configuration files.
+
+ NOTE: OS Vendors who provide Samba binary packages will generally
+ integrate all Samba files into their preferred directory locations.
+ These may differ from the default location ALWAYS used by the Samba
+ sources. Please be careful when upgrading a vendor provided binary
+ distribution from files you have built yourself.
+
diff --git a/README b/README
index b7ef5d55957..93c8cb133e7 100644
--- a/README
+++ b/README
@@ -1,60 +1,126 @@
-This is version 1.9 of Samba, the free SMB client and server for unix.
+This is a development version of Samba, the free SMB and CIFS client and
+server for unix and other operating systems. Samba is maintained by
+the Samba Team, who support the original author, Andrew Tridgell.
>>>> Please read THE WHOLE of this file as it gives important information
>>>> about the configuration and use of Samba.
+NOTE: Installation instructions may be found in
+ docs/htmldocs/UNIX_INSTALL.html
+
This software is freely distributable under the GNU public license, a
copy of which you should have received with this software (in a file
called COPYING).
+
+WHAT IS SMB?
+============
+
+This is a big question.
+
+The very short answer is that it is the protocol by which a lot of
+PC-related machines share files and printers and other informatiuon
+such as lists of available files and printers. Operating systems that
+support this natively include Windows NT, OS/2, and Linux and add on
+packages that achieve the same thing are available for DOS, Windows,
+VMS, Unix of all kinds, MVS, and more. Apple Macs and some Web Browsers
+can speak this protocol as well. Alternatives to SMB include
+Netware, NFS, Appletalk, Banyan Vines, Decnet etc; many of these have
+advantages but none are both public specifications and widely
+implemented in desktop machines by default.
+
+The Common Internet Filesystem (CIFS) is what the new SMB initiative
+is called. For details watch http://samba.org/cifs.
+
+
+WHY DO PEOPLE WANT TO USE SMB?
+==============================
+
+1. Many people want to integrate their Microsoft or IBM style desktop
+ machines with their Unix or VMS (etc) servers.
+
+2. Others want to integrate their Microsoft (etc) servers with Unix
+ or VMS (etc) servers. This is a different problem to integrating
+ desktop clients.
+
+3. Others want to replace protocols like NFS, DecNet and Novell NCP,
+ especially when used with PCs.
+
+
WHAT CAN SAMBA DO?
==================
-Here is a very short list of what samba includes, and what it does
+Here is a very short list of what samba includes, and what it does. For
+many networks this can be simply summarised by "Samba provides a complete
+replacement for Windows NT, Warp, NFS or Netware servers."
-- a SMB server, to provide LanManager style file and print services to PCs
+- a SMB server, to provide Windows NT and LAN Manager-style file and print
+ services to SMB clients such as Windows 95, Warp Server, smbfs and others.
-- a Netbios (rfc1001/1002) nameserver
+- a NetBIOS (rfc1001/1002) nameserver, which amongst other things gives
+ browsing support. Samba can be the master browser on your LAN if you wish.
- a ftp-like SMB client so you can access PC resources (disks and
-printers) from unix
+printers) from unix, Netware and other operating systems
- a tar extension to the client for backing up PCs
+- limited command-line tool that supports some of the NT administrative
+ functionality, which can be used on Samba, NT workstation and NT server.
+
+For a much better overview have a look at the web site at
+http://samba.org/samba, and browse the user survey.
+
Related packages include:
-- ksmbfs, a linux-only filesystem allowing you to mount remote SMB
-filesystems from PCs on your linux box
+- smbfs, a linux-only filesystem allowing you to mount remote SMB
+filesystems from PCs on your linux box. This is included as standard with
+Linux 2.0 and later.
- tcpdump-smb, a extension to tcpdump to allow you to investigate SMB
-networking problems over netbeui and tcp/ip
+networking problems over netbeui and tcp/ip.
+
+- smblib, a library of smb functions which are designed to make it
+easy to smb-ise any particular application. See
+ftp://samba.org/pub/samba/smblib.
CONTRIBUTIONS
=============
If you want to contribute to the development of the software then
-please join the mailing list. I accept patches (preferably in
-"diff -u" format) and am always glad to receive feedback or suggestions.
+please join the mailing list. The Samba team accepts patches
+(preferably in "diff -u" format, see docs/BUGS.txt for more details)
+and are always glad to receive feedback or suggestions to the address
+samba-bugs@samba.org. We have recently put a new bug tracking
+system into place which should help the throughput quite a lot. You
+can also get the Samba sourcecode straight from the CVS tree - see
+http://samba.org/cvs.html.
You could also send hardware/software/money/jewelry or pizza
-vouchers directly to me. The pizza vouchers would be especially
-welcome :-)
+vouchers directly to Andrew. The pizza vouchers would be especially
+welcome, in fact there is a special field in the survey for people who
+have paid up their pizza :-)
-If you like a particular feature then look through the change-log and
-see who added it, then send them an email.
+If you like a particular feature then look through the CVS change-log
+(on the web at http://samba.org/cgi-bin/cvsweb/samba) and see
+who added it, then send them an email.
Remember that free software of this kind lives or dies by the response
we get. If noone tells us they like it then we'll probably move onto
-something else.
+something else. However, as you can see from the user survey quite a lot of
+people do seem to like it at the moment :-)
Andrew Tridgell
-Email: samba-bugs@anu.edu.au
+Email: samba-bugs@samba.org
3 Ballow Crescent
Macgregor, A.C.T.
2615 Australia
+Samba Team
+Email: samba-bugs@samba.org
+
MORE INFO
=========
@@ -64,26 +130,34 @@ DOCUMENTATION
There is quite a bit of documentation included with the package,
including man pages, and lots of .txt files with hints and useful
-info.
+info. This is also available from the web page. There is a growing
+collection of information under docs/faq; by the next release expect
+this to be the default starting point.
-FTP SITE
---------
+A list of Samba documentation in languages other than English is
+available on the web page.
+
+If you would like to help with the documentation (and we _need_ help!)
+then have a look at the mailing list samba-docs, archived at
+http://lists.samba.org/
-The main anonymous ftp distribution site for this software is
-nimbus.anu.edu.au in the directory pub/tridge/samba/.
MAILING LIST
------------
There is a mailing list for discussion of Samba. To subscribe send
-mail to listproc@anu.edu.au with a body of "subscribe samba Your Name"
+mail to listproc@samba.org with a body of "subscribe samba Your Name"
+Please do NOT send this request to the list alias instead.
To send mail to everyone on the list mail to samba@listproc.anu.edu.au
-There is also an announcement mailing list where I announce new
-versions. To subscribe send mail to listproc@anu.edu.au with a body
-of "subscribe samba-announce Your Name". All announcements also go to
-the samba list.
+There is also an announcement mailing list where new versions are
+announced. To subscribe send mail to listproc@samba.org with a
+body of "subscribe samba-announce Your Name". All announcements also
+go to the samba list.
+
+For details of other Samba mailing lists and for access to archives, see
+http://lists.samba.org/
NEWS GROUP
@@ -94,7 +168,7 @@ comp.protocols.smb as it often contains lots of useful info and is
frequented by lots of Samba users. The newsgroup was initially setup
by people on the Samba mailing list. It is not, however, exclusive to
Samba, it is a forum for discussing the SMB protocol (which Samba
-implements).
+implements). The samba list is gatewayed to this newsgroup.
WEB SITE
@@ -102,10 +176,9 @@ WEB SITE
A Samba WWW site has been setup with lots of useful info. Connect to:
-http://lake.canberra.edu.au/pub/samba/
-
-It is maintained by Paul Blackman (thanks Paul!). You can contact him
-at ictinus@lake.canberra.edu.au.
-
+http://samba.org/samba/
+As well as general information and documentation, this also has searchable
+archives of the mailing list and a user survey that shows who else is using
+this package. Have you registered with the survey yet? :-)
diff --git a/Read-Manifest-Now b/Read-Manifest-Now
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Read-Manifest-Now
diff --git a/Roadmap b/Roadmap
new file mode 100644
index 00000000000..83b0bcc0e6b
--- /dev/null
+++ b/Roadmap
@@ -0,0 +1,45 @@
+Copyright (C) 1997-1999 - Samba-Team
+
+The Samba-Team are committed to an aggressive program to deliver quality
+controlled software to a well defined roadmap.
+
+The current Samba release 2.0.4 is called the "NT Security update".
+
+It correctly implements the Windows NT specific SMB calls,
+and will operate correctly as a client in a Windows NT
+Domain environment.
+
+In addition, the first implementation of the Web-based GUI
+management tool ships with 2.0.0, thus fullfilling some of
+the commitments made in the 1.9.18 release Roadmap document.
+
+Some work has been done on ensuring compatibility with
+Windows NT 5.0 (now Windows 2000 :-) although this is
+a somewhat (slowly) moving target.
+
+The following development objectives for future releases
+are in place:
+
+----------------------------------------------------------------------------
+2.0.x - "NT Security update" - Allowing Windows NT Clients to
+ manipulate file security and ownership using native tools.
+
+Note that the "NT Security update" part of the Roadmap has been
+achieved with the Samba 2.0.4 release.
+
+2.0.xx - "Thin Server" mode, allowing a Samba server to be
+ inserted into a network with no UNIX setup required.
+ Some management capabilities for Samba using native NT tools.
+ Provision of command-line equivalents to native NT tools.
+
+2.X - "Domain Controller" - able to serve as a Windows NT PDC.
+
+X.XX - "Full Domain Integration" - allowing both PDC and BDC modes.
+
+Note that it is a given that the Samba Team will continue to track
+Windows (NT/2000) update releases, ensuring that Samba will work
+well with whatever "Beta" releases Redmond throws our way :-).
+
+You may also note that the release numbers get fuzzier the
+further into the future the objectives get. This is intentional
+as we cannot yet commit to exact timeframes.
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
new file mode 100644
index 00000000000..9c4b62a5a1b
--- /dev/null
+++ b/WHATSNEW.txt
@@ -0,0 +1,182 @@
+ WHATS NEW IN Samba 3.0 alphaX
+ =============================
+
+Changes in alpha12
+- doc updates (jerry)
+- store domain sid on ADS join (tridge)
+- allow a winbind username on ADS connection (tridge)
+
+Changes in alpha11
+- fixed fallback to "ads server" option (tridge)
+- fix ACL failure on HP HFS (jra)
+- net ads password and net ads chostpass commands (Remus Koos)
+- fixed valid char array generation (tridge)
+- fixed QFS_INFO for win98 long filenames (tridge)
+- added net lookup command (tridge)
+- fixed map to guest with spnego (tridge)
+- fixed irix warnings (tridge)
+
+
+Changes in alpha10
+- hide unreadable fix using acl fns (jra)
+- lsa_open_policy cleanup (jfm)
+- mangled directories fix (jra)
+- fix error return on bad pipe (jra)
+- fix homes share with no home dir (tpot)
+- fixed handling of dead or empty domains in winbindd (tridge)
+- added talloc torture program (mbp)
+- talloc debug code (mbp)
+- added trusted domains to winbindd/ADS (tridge)
+- fix trusted domains in auth code (tridge)
+- new gss error handling code (a.bokovoy@sam-solutions.net & tridge)
+- support mixed ADS/NT4 domains (tridge)
+
+Changes in alpha9
+- nicer net error messages (tpot)
+- trust account patches (mimir)
+- solaris link option update (davecb)
+- added lsa_query_secobj() server fn (jfm)
+- spoolss changeid fix (jerry)
+- domain auth error fix (jmcd)
+- HPUX acl code (jra)
+- set filetime on close fix (jra)
+- allow select of org unit in ads join (tridge)
+
+Changes in alpha8
+- fixed compile of wb_client.c (tridge)
+- fixed net time to use localtime (tridge)
+- net help cleanups (jmcd)
+- debug level fix (tpot)
+- utmp string length fixes (monyo)
+
+
+Changes in alpha7
+
+- added "net ads info" to probe basic into on your ads server without
+ any authentication
+- improved some error handling
+
+Changes in alpha6
+
+- added "net time zone" command (tridge)
+- pam_smbpass updates (a.bokovoy@sam-solutions.net)
+- irix updates (herb)
+- net rpc join handles existing machine acct (tridge)
+
+Changes in alpha5
+
+- added "net time" command (tridge)
+- allow client tools to specify a hostname of form HOST#xx (tridge)
+- added wbinfo --set-auth-user (tpot)
+- added lsaquerysecobj to rpcclient (tpot)
+
+Changes in alpha4
+
+- fixed nexus/win9x user list (jfm)
+- fixed large user/group lists in winbindd (tridge)
+- fixed gssapi headers in redhat (jmcd)
+- fixed rap error code handling (jra)
+- more usermanager rpc calls (jfm)
+- re-added RAP calls at top level to net command (tridge)
+
+Changes in alpha3
+
+- fixed a silly tdb bug in alpha2 that affected internal databases
+
+Changes in alpha2
+
+- we no longer use cyrus-sasl for LDAP SASL/gssapi. This makes our ADS
+ code much more robust.
+- winbindd cache code rewritten to be much more efficient. It also
+ copes much better with server outages.
+- jfm implemented full group mapping and smb.conf option 'domain admin
+ group' is now gone. Consult the GROUP-MAPPING-HOWTO.txt to know how
+ to gain back administrator rights.
+- docs update started
+- numerous small bugfixes
+
+Changes in alpha1
+
+ - winbindd now uses LDAP and works correctly with an ADS server in
+ native mode
+ - XFS quotas code on Linux
+ - group mapping code from JFM
+ - "net rpc join" command replaces smbpasswd -j
+ - fixed winbind initgroups
+
+--------------
+
+This is a pre-release of Samba 3.0 alpha0. This is NOT a stable
+release. Use at your own risk.
+
+The purpose of this alpha release is to get wider testing of the major
+new pieces of code in the current Samba 3.0 development tree. We are
+planning on ceasing development on the 2.2.x release of Samba very
+shortly and after that we will be concentrating on Samba 3.0. To
+reduce the time before the final Samba 3.0 release we need as many
+poeple as possible to start testing these alpha releases, and
+hopefully giving us some high quality feedback on what needs fixing.
+
+Note that Samba 3.0 is not anywhere near feature complete yet. There
+is a lot more coding we have planned, but unless we get what we have
+done already more widely tested we will have a hard time doing a
+stable release in a reasonable time frame.
+
+This release is also missing major pieces of documentation, and there
+are many parts of the docs that have not been updated to reflect the
+new options and features in 3.0.
+
+Major new features:
+-------------------
+
+- Active Directory support. This release is able to join a ADS realm
+ as a member server and authenticate users using
+ LDAP/kerberos. Please read ADS-HOWTO.txt in the release for a very
+ rough guide on how to set this up.
+
+- Unicode support. Samba will now negotiate unicode on the wire and
+ interally there is now a much better infrastructure for multi-byte
+ and unicode character sets. You may need the "dos charset", "unix
+ charset" and "display charset" options. The unicode support is not
+ yet documented.
+
+- New authentication system. The internal authentication system has
+ been almost completely rewritten. Most of the changes are internal,
+ but the new auth system is also very configurable. Not documented
+ yet.
+
+- new filename mangling system. The filename mangling system has been
+ completely rewritten. An internal database now stores mangling maps
+ persistantly. This needs lots of testing.
+
+- new "net" command. A new "net" command has been added. It is
+ somewhat similar to the "net" command in windows. Eventually we plan
+ to replace a bunch of other utilities (such as smbpasswd) with
+ subcommands in "net", at the moment only a few things are
+ implemented.
+
+- Samba now negotiates NT-style status32 codes on the wire. This
+ improves error handling a lot.
+
+- better w2k printing support. The support for printing from win2000
+ clients has improved greatly.
+
+Plus lots of other changes!
+
+Note that many new features are not documented. Don't let this stop
+you from using Samba 3.0. It is particularly important that the basic
+file/print serving abilities of Samba 3.0 are widely tested to ensure
+that we have not broken any of the basic functionality. As we do more
+alpha releases we will start to document the new features.
+
+
+Reporting bugs & Development Discussion
+---------------------------------------
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.openprojects.net
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored.
+
diff --git a/docs/OID/allocated-arcs.txt b/docs/OID/allocated-arcs.txt
new file mode 100644
index 00000000000..4666be4cd79
--- /dev/null
+++ b/docs/OID/allocated-arcs.txt
@@ -0,0 +1,17 @@
+!===========================================================================================
+!==
+!== Allocated Arcs from the Samba Team Private Enterprise Number
+!== ISO(1) org(3) dod(6) internet(1) experimental(3) private(4) enterprise(1) Samba(7165)
+!==
+!== Arc allocation is maintained by jerry carter <jerry@samba.org>. Please notify
+!== me if you need an OID and update this file.
+!==
+!== File Created : Tue May 8 09:33:31 CDT 2001
+!==
+!===========================================================================================
+
+ARC Owner Contact Purpose
+--- ----- ------- -------
+.1 Plainjoe.org Jerry Carter <jerry@samba.org> Use for Plainjoe.org domain
+ and examples in O'Reilly LDAP book
+.2 Samba 2.2. Release jerry@samba.org schema for representing smbpasswd
diff --git a/docs/OID/samba-oid.mail b/docs/OID/samba-oid.mail
new file mode 100644
index 00000000000..d1ad668f880
--- /dev/null
+++ b/docs/OID/samba-oid.mail
@@ -0,0 +1,27 @@
+From gruiz@icann.org Tue May 8 04:27:07 2001
+Date: Tue, 26 Sep 2000 15:29:02 -0700
+From: GIGI RUIZ <gruiz@icann.org>
+To: jerry@samba.org
+Cc: "Iana-Mib (E-mail)" <iana-mib@iana.org>
+Subject: PEN 7165 RE: Application for Enterprise-number
+
+ [ The following text is in the "iso-8859-1" character set. ]
+ [ Your display is set for the "US-ASCII" character set. ]
+ [ Some characters may be displayed incorrectly. ]
+
+Gerald,
+
+We have assigned Private Enterprise Number 7165 to SAMBA Team, with you as
+the point of contact. Please confirm the information listed below.
+
+7165 SAMBA Team Gerald Carter jerry@samba.org
+
+Sincerely,
+
+Gigi Ruiz
+Internet Assigned Numbers Authority - MIB
+
+Voice: (310) 823-9358
+Fax: (310) 823-8649
+EMAIL: iana-mib@iana.org
+
diff --git a/docs/README.Win2kSP2 b/docs/README.Win2kSP2
new file mode 100644
index 00000000000..49a8fbf4ae1
--- /dev/null
+++ b/docs/README.Win2kSP2
@@ -0,0 +1,56 @@
+!==
+!== README.Win2kSP2
+!==
+
+Author: Gerald (Jerry) Carter <jerry@samba.org>
+
+==================================================================
+
+There are several annoyances with Windows 2000 SP2. One of which
+only appears when using a Samba server to host user profiles
+to Windows 2000 SP2 clients in a Windows domain. This assumes
+that Samba is a member of the domain, but the problem will
+likely occur if it is not.
+
+In order to server profiles successfully to Windows 2000 SP2
+clients (when not operating as a PDC), Samba must have
+
+ nt acl support = no
+
+added to the file share which houses the roaming profiles.
+If this is not done, then the Windows 2000 SP2 client will
+complain about not being able to access the profile (Access
+Denied) and create multiple copies of it on disk (DOMAIN.user.001,
+DOMAIN.user.002, etc...). See the smb.conf(5) man page
+for more details on this option. Also note that the "nt acl support"
+parameter was formally a global parameter in releases prior
+to Samba 2.2.2.
+
+The following is a minimal profile share
+
+ [profile]
+ path = /export/profile
+ create mask = 0600
+ directory mask = 0700
+ nt acl support = no
+ read only = no
+
+The reason for this bug is that the Win2k SP2 client copies
+the security descriptor for the profile which contains
+the Samba server's SID, and not the domain SID. The client
+compares the SID for SAMBA\user and realizes it is
+different that the one assigned to DOMAIN\user. Hence the reason
+for the "access denied" message.
+
+By disabling the "nt acl support" parameter, Samba will send
+the Win2k client a response to the QuerySecurityDescriptor
+trans2 call which causes the client to set a default ACL
+for the profile. This default ACL includes
+
+ DOMAIN\user "Full Control"
+
+
+NOTE : This bug does not occur when using winbind to
+create accounts on the Samba host for Domain users.
+
+
diff --git a/docs/README.Win32-Viruses b/docs/README.Win32-Viruses
new file mode 100644
index 00000000000..07f03360cbc
--- /dev/null
+++ b/docs/README.Win32-Viruses
@@ -0,0 +1,58 @@
+While this article is specific to the recent Nimda worm,
+the information can be applied to preventing the spread
+of many Win32 viruses. Thanks to the Samba Users Group of Japan
+(SUGJ) for this article.
+===============================================================================
+Steps againt Nimba Worm for Samba
+
+Author: HASEGAWA Yosuke
+Translator: TAKAHASHI Motonobu <monyo@samba.gr.jp>
+
+The information in this article applies to
+ Samba 2.0.x
+ Samba 2.2.x
+ Windows 95/98/Me/NT/2000
+
+SYMPTOMS
+ This article has described the measure against Nimba Worm for Samba
+ server.
+
+DESCRIPTION
+ Nimba Worm is infected through the shared disk on a network besides
+ Microsoft IIS, Internet Explorer and mailer of Outlook series.
+
+ At this time, the worm copies itself by the name *.nws and *.eml on
+ the shared disk, moreover, by the name of Riched20.dll in the folder
+ where *.doc file is included.
+
+ To prevent infection through the shared disk offered by Samba, set
+ up as follows:
+
+-----
+[global]
+ ...
+ # This can break Administration installations of Office2k.
+ # in that case, don't veto the riched20.dll
+ veto files = /*.eml/*.nws/riched20.dll/
+-----
+
+ Setting up "veto files" parameter, the matched files on the Samba
+ server are completely hidden from the clients and become impossible
+ to access them at all.
+
+ In addition to it, the following setting are also pointed out by the
+ samba-jp:09448 thread: when the
+ "(Jreadme.txt.{3050F4D8-98B5-11CF-BB82-00AA00BDCE0B}"(B file exists on
+ a Samba server, it is visible only with "readme.txt" and a dangerous
+ code may be performed when this file is double-clicked.
+
+ Setting the following,
+-----
+ veto files = /*.{*}/
+-----
+ no files having CLSID in its file extension can be accessed from any
+ clients.
+
+This technical article is created based on the discussion of
+samba-jp:09448 and samba-jp:10900 threads.
+
diff --git a/docs/README.ldap b/docs/README.ldap
new file mode 100644
index 00000000000..451e27b8bf3
--- /dev/null
+++ b/docs/README.ldap
@@ -0,0 +1 @@
+The schema file is stored in ../examples/LDAP/samba.schema
diff --git a/docs/Registry/NT4-Locking.reg b/docs/Registry/NT4-Locking.reg
new file mode 100644
index 00000000000..6175fd51459
--- /dev/null
+++ b/docs/Registry/NT4-Locking.reg
@@ -0,0 +1,24 @@
+REGEDIT4
+
+;Contributor: John H Terpstra <jht@samba.org>
+;Corrected: Stefan Kanthak <skanthak@nexgo.de>
+;Updated: Jun 25, 2001
+;
+;Subject: Registry Entries That Affect Locking and Caching
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
+"BufFilesDenyWrite"=dword:00000000
+"BufNamedPipes"=dword:00000000
+"UseOpportunisticLocking"=dword:00000000
+"DormantFileLimit"=dword:00000000
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters\Linkage]
+"UtilizeNtCaching"=dword:00000000
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Filesystem]
+"Win95TruncatedExtensions"=dword:00000000
+"NTFSDisable8dot3NameCreation"=dword:00000001
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters]
+"EnableOpLockForceClose"=dword:00000001
+"EnableOpLocks"=dword:00000000
diff --git a/docs/Registry/NT4_PlainPassword.reg b/docs/Registry/NT4_PlainPassword.reg
new file mode 100644
index 00000000000..b30db150c24
--- /dev/null
+++ b/docs/Registry/NT4_PlainPassword.reg
@@ -0,0 +1,11 @@
+REGEDIT4
+
+;Contributor: Tim Small (tim.small@virgin.net)
+;Updated: 20 August 1997
+;Status: Current
+;
+;Subject: Registry file to enable plain text passwords in NT4-SP3 and later
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rdr\Parameters]
+"EnablePlainTextPassword"=dword:00000001
+
diff --git a/docs/Registry/Win2000_PlainPassword.reg b/docs/Registry/Win2000_PlainPassword.reg
new file mode 100644
index 00000000000..e0ae280b1c2
--- /dev/null
+++ b/docs/Registry/Win2000_PlainPassword.reg
@@ -0,0 +1,11 @@
+REGEDIT4
+
+;Contributor: Herb Lewis (herb@sgi.com)
+;Updated: 16 July 1999
+;Status: Current
+;
+;Subject: Registry file to enable plain text passwords in Windows 2000
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkStation\Parameters]
+"EnablePlainTextPassword"=dword:00000001
+
diff --git a/docs/Registry/Win95_PlainPassword.reg b/docs/Registry/Win95_PlainPassword.reg
new file mode 100644
index 00000000000..9dd3103689c
--- /dev/null
+++ b/docs/Registry/Win95_PlainPassword.reg
@@ -0,0 +1,4 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VNETSUP]
+"EnablePlainTextPassword"=dword:00000001
diff --git a/docs/Registry/Win98_PlainPassword.reg b/docs/Registry/Win98_PlainPassword.reg
new file mode 100644
index 00000000000..9dd3103689c
--- /dev/null
+++ b/docs/Registry/Win98_PlainPassword.reg
@@ -0,0 +1,4 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VNETSUP]
+"EnablePlainTextPassword"=dword:00000001
diff --git a/docs/Registry/Win9X-CacheHandling.reg b/docs/Registry/Win9X-CacheHandling.reg
new file mode 100644
index 00000000000..265e335b402
--- /dev/null
+++ b/docs/Registry/Win9X-CacheHandling.reg
@@ -0,0 +1,7 @@
+REGEDIT4
+
+; Contributor: John H Terpstra <jht@samba.org>
+; Date: Feb 15, 1999
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VREDIR]
+"DiscardCacheOnOpen"=string:00000001
diff --git a/docs/Registry/WinME_PlainPassword.reg b/docs/Registry/WinME_PlainPassword.reg
new file mode 100644
index 00000000000..9dd3103689c
--- /dev/null
+++ b/docs/Registry/WinME_PlainPassword.reg
@@ -0,0 +1,4 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VNETSUP]
+"EnablePlainTextPassword"=dword:00000001
diff --git a/docs/Registry/WinXP_SignOrSeal.reg b/docs/Registry/WinXP_SignOrSeal.reg
new file mode 100644
index 00000000000..18690ae6619
--- /dev/null
+++ b/docs/Registry/WinXP_SignOrSeal.reg
@@ -0,0 +1,9 @@
+REGEDIT4
+
+;
+; This registry key (gathered from the Samba-tng lists) is needed
+; for a Windows XP client to join and logon to a Samba domain
+;
+
+HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\netlogon\parameters
+"RequireSignOrSeal"=dword:00000000
diff --git a/docs/Registry/WindowsTerminalServer.reg b/docs/Registry/WindowsTerminalServer.reg
new file mode 100644
index 00000000000..73c3b177d20
--- /dev/null
+++ b/docs/Registry/WindowsTerminalServer.reg
@@ -0,0 +1,7 @@
+REGEDIT4
+
+;Subject: Registry file to force multiple NT terminal server users to have their own connections.
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rdr\Parameters]
+"MultipleUsersOnConnection"=dword:00000000
+
diff --git a/docs/Samba-HOWTO-Collection.pdf b/docs/Samba-HOWTO-Collection.pdf
new file mode 100644
index 00000000000..511edd4ed16
--- /dev/null
+++ b/docs/Samba-HOWTO-Collection.pdf
@@ -0,0 +1,2895 @@
+%PDF-1.2
+%âãÏÓ
+1 0 obj<</Producer(htmldoc 1.8.11 Copyright 1997-2001 Easy Software Products, All Rights Reserved.)/CreationDate(D:20011206071218Z)/Title(SAMBA Project Documentation)/Creator(Modular DocBook HTML Stylesheet Version 1.57)>>endobj
+2 0 obj<</Type/Encoding/Differences[ 32/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle/parenleft/parenright/asterisk/plus/comma/minus/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore/grave/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde 128/Euro 130/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE 145/quoteleft/quoteright/quotedblleft/quotedblright/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe 159/Ydieresis/space/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]>>endobj
+3 0 obj<</Type/Font/Subtype/Type1/BaseFont/Courier/Encoding 2 0 R>>endobj
+4 0 obj<</Type/Font/Subtype/Type1/BaseFont/Courier-Bold/Encoding 2 0 R>>endobj
+5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Courier-Oblique/Encoding 2 0 R>>endobj
+6 0 obj<</Type/Font/Subtype/Type1/BaseFont/Courier-BoldOblique/Encoding 2 0 R>>endobj
+7 0 obj<</Type/Font/Subtype/Type1/BaseFont/Times-Roman/Encoding 2 0 R>>endobj
+8 0 obj<</Type/Font/Subtype/Type1/BaseFont/Times-Bold/Encoding 2 0 R>>endobj
+9 0 obj<</Type/Font/Subtype/Type1/BaseFont/Times-Italic/Encoding 2 0 R>>endobj
+10 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica/Encoding 2 0 R>>endobj
+11 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica-Bold/Encoding 2 0 R>>endobj
+12 0 obj<</Type/Font/Subtype/Type1/BaseFont/Symbol>>endobj
+13 0 obj<</S/URI/URI(http://www.samba.org/)>>endobj
+14 0 obj<</Subtype/Link/Rect[188.4 449.8 289.8 462.8]/Border[0 0 0]/A 13 0 R>>endobj
+15 0 obj<</S/URI/URI(mailto:jerry@samba.org)>>endobj
+16 0 obj<</Subtype/Link/Rect[72.0 436.6 148.4 449.6]/Border[0 0 0]/A 15 0 R>>endobj
+17 0 obj[14 0 R
+16 0 R
+]endobj
+18 0 obj<</S/URI/URI(http://www.samba.org/)>>endobj
+19 0 obj<</Subtype/Link/Rect[369.9 587.8 471.0 600.8]/Border[0 0 0]/A 18 0 R>>endobj
+20 0 obj[19 0 R
+]endobj
+21 0 obj<</S/URI/URI(ENCRYPTION.html)>>endobj
+22 0 obj<</Subtype/Link/Rect[176.8 381.8 270.6 394.8]/Border[0 0 0]/A 21 0 R>>endobj
+23 0 obj<</S/URI/URI(#PASSWORDLEVEL)>>endobj
+24 0 obj<</Subtype/Link/Rect[73.0 118.8 154.0 129.8]/Border[0 0 0]/A 23 0 R>>endobj
+25 0 obj<</S/URI/URI(#USERNAMELEVEL)>>endobj
+26 0 obj<</Subtype/Link/Rect[73.0 108.0 148.6 119.0]/Border[0 0 0]/A 25 0 R>>endobj
+27 0 obj[22 0 R
+24 0 R
+26 0 R
+]endobj
+28 0 obj<</S/URI/URI(winbind.html)>>endobj
+29 0 obj<</Subtype/Link/Rect[508.9 602.2 547.4 615.2]/Border[0 0 0]/A 28 0 R>>endobj
+30 0 obj<</S/URI/URI(winbind.html)>>endobj
+31 0 obj<</Subtype/Link/Rect[72.0 589.0 115.4 602.0]/Border[0 0 0]/A 30 0 R>>endobj
+32 0 obj[29 0 R
+31 0 R
+]endobj
+33 0 obj<</S/URI/URI(http://rsync.samba.org/)>>endobj
+34 0 obj<</Subtype/Link/Rect[120.9 89.0 222.3 102.0]/Border[0 0 0]/A 33 0 R>>endobj
+35 0 obj[34 0 R
+]endobj
+36 0 obj<</S/URI/URI(#OBEYPAMRESTRICTIONS)>>endobj
+37 0 obj<</Subtype/Link/Rect[238.2 649.4 332.9 662.4]/Border[0 0 0]/A 36 0 R>>endobj
+38 0 obj<</S/URI/URI(#ENCRYPTPASSWORDS)>>endobj
+39 0 obj<</Subtype/Link/Rect[344.2 570.2 454.9 583.2]/Border[0 0 0]/A 38 0 R>>endobj
+40 0 obj[37 0 R
+39 0 R
+]endobj
+41 0 obj<</S/URI/URI(http://www.microsoft.com/NTServer/nts/downloads/winfeatures/NTSDistrFile/AdminGuide.asp)>>endobj
+42 0 obj<</Subtype/Link/Rect[72.0 590.2 183.5 603.2]/Border[0 0 0]/A 41 0 R>>endobj
+43 0 obj<</S/URI/URI(#HOSTMSDFS)>>endobj
+44 0 obj<</Subtype/Link/Rect[347.8 511.0 420.4 524.0]/Border[0 0 0]/A 43 0 R>>endobj
+45 0 obj<</S/URI/URI(#MSDFSROOT)>>endobj
+46 0 obj<</Subtype/Link/Rect[383.6 497.8 456.2 510.8]/Border[0 0 0]/A 45 0 R>>endobj
+47 0 obj[42 0 R
+44 0 R
+46 0 R
+]endobj
+48 0 obj<</S/URI/URI(#NTACLSUPPORT)>>endobj
+49 0 obj<</Subtype/Link/Rect[342.7 533.8 441.7 546.8]/Border[0 0 0]/A 48 0 R>>endobj
+50 0 obj[49 0 R
+]endobj
+51 0 obj<</S/URI/URI(#SECURITYMASK)>>endobj
+52 0 obj<</Subtype/Link/Rect[88.2 668.2 180.6 681.2]/Border[0 0 0]/A 51 0 R>>endobj
+53 0 obj<</S/URI/URI(#CREATEMASK)>>endobj
+54 0 obj<</Subtype/Link/Rect[358.9 589.0 438.1 602.0]/Border[0 0 0]/A 53 0 R>>endobj
+55 0 obj<</S/URI/URI(#FORCESECURITYMODE)>>endobj
+56 0 obj<</Subtype/Link/Rect[427.0 536.2 526.0 549.2]/Border[0 0 0]/A 55 0 R>>endobj
+57 0 obj<</S/URI/URI(#FORCESECURITYMODE)>>endobj
+58 0 obj<</Subtype/Link/Rect[72.0 523.0 98.4 536.0]/Border[0 0 0]/A 57 0 R>>endobj
+59 0 obj<</S/URI/URI(#FORCECREATEMODE)>>endobj
+60 0 obj<</Subtype/Link/Rect[358.9 443.8 477.7 456.8]/Border[0 0 0]/A 59 0 R>>endobj
+61 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+62 0 obj<</Subtype/Link/Rect[72.0 166.6 151.2 179.6]/Border[0 0 0]/A 61 0 R>>endobj
+63 0 obj[52 0 R
+54 0 R
+56 0 R
+58 0 R
+60 0 R
+62 0 R
+]endobj
+64 0 obj<</S/URI/URI(http://imprints.sourceforge.net)>>endobj
+65 0 obj<</Subtype/Link/Rect[146.5 548.2 280.3 561.2]/Border[0 0 0]/A 64 0 R>>endobj
+66 0 obj<</S/URI/URI(http://msdn.microsoft.com/)>>endobj
+67 0 obj<</Subtype/Link/Rect[221.4 521.8 341.1 534.8]/Border[0 0 0]/A 66 0 R>>endobj
+68 0 obj<</S/URI/URI(http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP)>>endobj
+69 0 obj<</Subtype/Link/Rect[72.0 297.4 355.9 310.4]/Border[0 0 0]/A 68 0 R>>endobj
+70 0 obj[65 0 R
+67 0 R
+69 0 R
+]endobj
+71 0 obj<</Subtype/Link/Rect[462.9 705.8 540.9 718.8]/Border[0 0 0]/Dest[645 0 R/XYZ null 768 0]>>endobj
+72 0 obj<</S/URI/URI(#WRITELIST)>>endobj
+73 0 obj<</Subtype/Link/Rect[91.9 313.4 157.9 326.4]/Border[0 0 0]/A 72 0 R>>endobj
+74 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+75 0 obj<</Subtype/Link/Rect[192.7 300.2 294.1 313.2]/Border[0 0 0]/A 74 0 R>>endobj
+76 0 obj<</S/URI/URI(#GUESTOK)>>endobj
+77 0 obj<</Subtype/Link/Rect[163.3 273.8 231.3 286.8]/Border[0 0 0]/A 76 0 R>>endobj
+78 0 obj<</S/URI/URI(#MAPTOGUEST)>>endobj
+79 0 obj<</Subtype/Link/Rect[401.4 168.2 492.0 181.2]/Border[0 0 0]/A 78 0 R>>endobj
+80 0 obj<</S/URI/URI(#MAPTOGUEST)>>endobj
+81 0 obj<</Subtype/Link/Rect[108.0 155.0 130.0 168.0]/Border[0 0 0]/A 80 0 R>>endobj
+82 0 obj[71 0 R
+73 0 R
+75 0 R
+77 0 R
+79 0 R
+81 0 R
+]endobj
+83 0 obj<</S/URI/URI(#PRINTERADMIN)>>endobj
+84 0 obj<</Subtype/Link/Rect[433.8 567.8 526.2 580.8]/Border[0 0 0]/A 83 0 R>>endobj
+85 0 obj[84 0 R
+]endobj
+86 0 obj<</S/URI/URI(rpcclient.1.html)>>endobj
+87 0 obj<</Subtype/Link/Rect[239.1 583.4 382.1 596.4]/Border[0 0 0]/A 86 0 R>>endobj
+88 0 obj<</S/URI/URI(#SHOWADDPRINTERWIZARD)>>endobj
+89 0 obj<</Subtype/Link/Rect[108.0 159.0 306.0 172.0]/Border[0 0 0]/A 88 0 R>>endobj
+90 0 obj<</S/URI/URI(#ADDPRINTERCOMMAND)>>endobj
+91 0 obj<</Subtype/Link/Rect[456.6 132.6 535.8 145.6]/Border[0 0 0]/A 90 0 R>>endobj
+92 0 obj<</S/URI/URI(#ADDPRINTERCOMMAND)>>endobj
+93 0 obj<</Subtype/Link/Rect[72.0 119.4 118.2 132.4]/Border[0 0 0]/A 92 0 R>>endobj
+94 0 obj[87 0 R
+89 0 R
+91 0 R
+93 0 R
+]endobj
+95 0 obj<</S/URI/URI(#DELETEPRINTERCOMMAND)>>endobj
+96 0 obj<</Subtype/Link/Rect[189.3 681.4 334.5 694.4]/Border[0 0 0]/A 95 0 R>>endobj
+97 0 obj<</S/URI/URI(#ENUMPORTSCOMMAND)>>endobj
+98 0 obj<</Subtype/Link/Rect[451.4 504.2 510.8 517.2]/Border[0 0 0]/A 97 0 R>>endobj
+99 0 obj<</S/URI/URI(#ENUMPORTSCOMMAND)>>endobj
+100 0 obj<</Subtype/Link/Rect[72.0 491.0 118.2 504.0]/Border[0 0 0]/A 99 0 R>>endobj
+101 0 obj<</S/URI/URI(http://imprints.sourceforge.net/)>>endobj
+102 0 obj<</Subtype/Link/Rect[303.3 406.2 442.9 419.2]/Border[0 0 0]/A 101 0 R>>endobj
+103 0 obj[96 0 R
+98 0 R
+100 0 R
+102 0 R
+]endobj
+104 0 obj<</S/URI/URI(http://imprints.sourceforge.net/)>>endobj
+105 0 obj<</Subtype/Link/Rect[108.0 479.8 244.9 492.8]/Border[0 0 0]/A 104 0 R>>endobj
+106 0 obj[105 0 R
+]endobj
+107 0 obj<</S/URI/URI(smbpasswd.8.html)>>endobj
+108 0 obj<</Subtype/Link/Rect[221.4 455.8 287.7 468.8]/Border[0 0 0]/A 107 0 R>>endobj
+109 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+110 0 obj<</Subtype/Link/Rect[353.1 139.0 425.7 152.0]/Border[0 0 0]/A 109 0 R>>endobj
+111 0 obj<</S/URI/URI(#SECURITY)>>endobj
+112 0 obj<</Subtype/Link/Rect[169.1 99.4 241.7 112.4]/Border[0 0 0]/A 111 0 R>>endobj
+113 0 obj[108 0 R
+110 0 R
+112 0 R
+]endobj
+114 0 obj<</S/URI/URI(#WORKGROUP)>>endobj
+115 0 obj<</Subtype/Link/Rect[146.2 721.0 225.4 734.0]/Border[0 0 0]/A 114 0 R>>endobj
+116 0 obj<</S/URI/URI(#ENCRYPTPASSWORDS)>>endobj
+117 0 obj<</Subtype/Link/Rect[224.7 641.8 343.5 654.8]/Border[0 0 0]/A 116 0 R>>endobj
+118 0 obj<</S/URI/URI(#PASSWORDSERVER)>>endobj
+119 0 obj<</Subtype/Link/Rect[188.7 602.2 307.5 615.2]/Border[0 0 0]/A 118 0 R>>endobj
+120 0 obj[115 0 R
+117 0 R
+119 0 R
+]endobj
+121 0 obj<</S/URI/URI(#SECURITYEQUALSSERVER)>>endobj
+122 0 obj<</Subtype/Link/Rect[277.9 721.0 354.1 734.0]/Border[0 0 0]/A 121 0 R>>endobj
+123 0 obj<</S/URI/URI(winbind.html)>>endobj
+124 0 obj<</Subtype/Link/Rect[153.9 668.2 222.3 681.2]/Border[0 0 0]/A 123 0 R>>endobj
+125 0 obj<</S/URI/URI(http://www.linuxworld.com)>>endobj
+126 0 obj<</Subtype/Link/Rect[443.5 351.4 500.6 364.4]/Border[0 0 0]/A 125 0 R>>endobj
+127 0 obj<</S/URI/URI(http://www.linuxworld.com/linuxworld/lw-1998-10/lw-10-samba.html)>>endobj
+128 0 obj<</Subtype/Link/Rect[72.0 338.2 189.3 351.2]/Border[0 0 0]/A 127 0 R>>endobj
+129 0 obj[122 0 R
+124 0 R
+126 0 R
+128 0 R
+]endobj
+130 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+131 0 obj<</Subtype/Link/Rect[182.3 603.4 254.9 616.4]/Border[0 0 0]/A 130 0 R>>endobj
+132 0 obj<</S/URI/URI(ENCRYPTION.html)>>endobj
+133 0 obj<</Subtype/Link/Rect[334.9 603.4 418.9 616.4]/Border[0 0 0]/A 132 0 R>>endobj
+134 0 obj<</S/URI/URI(UNIX_INSTALL.html)>>endobj
+135 0 obj<</Subtype/Link/Rect[339.0 439.4 443.5 452.4]/Border[0 0 0]/A 134 0 R>>endobj
+136 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+137 0 obj<</Subtype/Link/Rect[445.9 426.2 544.6 439.2]/Border[0 0 0]/A 136 0 R>>endobj
+138 0 obj[131 0 R
+133 0 R
+135 0 R
+137 0 R
+]endobj
+139 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+140 0 obj<</Subtype/Link/Rect[468.3 636.2 549.6 649.2]/Border[0 0 0]/A 139 0 R>>endobj
+141 0 obj<</S/URI/URI(smb.conf.5.html)>>endobj
+142 0 obj<</Subtype/Link/Rect[72.0 623.0 92.8 636.0]/Border[0 0 0]/A 141 0 R>>endobj
+143 0 obj<</S/URI/URI(#NETBIOSNAME)>>endobj
+144 0 obj<</Subtype/Link/Rect[94.6 549.6 159.4 560.6]/Border[0 0 0]/A 143 0 R>>endobj
+145 0 obj<</S/URI/URI(#WORKGROUP)>>endobj
+146 0 obj<</Subtype/Link/Rect[94.6 538.8 143.2 549.8]/Border[0 0 0]/A 145 0 R>>endobj
+147 0 obj<</S/URI/URI(#OSLEVEL)>>endobj
+148 0 obj<</Subtype/Link/Rect[94.6 506.4 137.8 517.4]/Border[0 0 0]/A 147 0 R>>endobj
+149 0 obj<</S/URI/URI(#PERFERREDMASTER)>>endobj
+150 0 obj<</Subtype/Link/Rect[94.6 495.6 181.0 506.6]/Border[0 0 0]/A 149 0 R>>endobj
+151 0 obj<</S/URI/URI(#DOMAINMASTER)>>endobj
+152 0 obj<</Subtype/Link/Rect[94.6 484.8 164.8 495.8]/Border[0 0 0]/A 151 0 R>>endobj
+153 0 obj<</S/URI/URI(#LOCALMASTER)>>endobj
+154 0 obj<</Subtype/Link/Rect[94.6 474.0 159.4 485.0]/Border[0 0 0]/A 153 0 R>>endobj
+155 0 obj<</S/URI/URI(#SECURITYEQUALSUSER)>>endobj
+156 0 obj<</Subtype/Link/Rect[94.6 441.6 137.8 452.6]/Border[0 0 0]/A 155 0 R>>endobj
+157 0 obj<</S/URI/URI(#ENCRYPTPASSWORDS)>>endobj
+158 0 obj<</Subtype/Link/Rect[94.6 409.2 186.4 420.2]/Border[0 0 0]/A 157 0 R>>endobj
+159 0 obj<</S/URI/URI(#DOMAINLOGONS)>>endobj
+160 0 obj<</Subtype/Link/Rect[94.6 376.8 164.8 387.8]/Border[0 0 0]/A 159 0 R>>endobj
+161 0 obj<</S/URI/URI(#LOGONPATH)>>endobj
+162 0 obj<</Subtype/Link/Rect[94.6 344.4 148.6 355.4]/Border[0 0 0]/A 161 0 R>>endobj
+163 0 obj<</S/URI/URI(#LOGONDRIVE)>>endobj
+164 0 obj<</Subtype/Link/Rect[94.6 301.2 154.0 312.2]/Border[0 0 0]/A 163 0 R>>endobj
+165 0 obj<</S/URI/URI(#LOGONHOME)>>endobj
+166 0 obj<</Subtype/Link/Rect[94.6 290.4 148.6 301.4]/Border[0 0 0]/A 165 0 R>>endobj
+167 0 obj<</S/URI/URI(#LOGONSCRIPT)>>endobj
+168 0 obj<</Subtype/Link/Rect[94.6 247.2 159.4 258.2]/Border[0 0 0]/A 167 0 R>>endobj
+169 0 obj<</S/URI/URI(#PATH)>>endobj
+170 0 obj<</Subtype/Link/Rect[94.6 204.0 116.2 215.0]/Border[0 0 0]/A 169 0 R>>endobj
+171 0 obj<</S/URI/URI(#READONLY)>>endobj
+172 0 obj<</Subtype/Link/Rect[94.6 193.2 143.2 204.2]/Border[0 0 0]/A 171 0 R>>endobj
+173 0 obj<</S/URI/URI(#WRITELIST)>>endobj
+174 0 obj<</Subtype/Link/Rect[94.6 182.4 148.6 193.4]/Border[0 0 0]/A 173 0 R>>endobj
+175 0 obj<</S/URI/URI(#PATH)>>endobj
+176 0 obj<</Subtype/Link/Rect[94.6 139.2 116.2 150.2]/Border[0 0 0]/A 175 0 R>>endobj
+177 0 obj<</S/URI/URI(#READONLY)>>endobj
+178 0 obj<</Subtype/Link/Rect[94.6 128.4 143.2 139.4]/Border[0 0 0]/A 177 0 R>>endobj
+179 0 obj<</S/URI/URI(#CREATEMASK)>>endobj
+180 0 obj<</Subtype/Link/Rect[94.6 117.6 154.0 128.6]/Border[0 0 0]/A 179 0 R>>endobj
+181 0 obj<</S/URI/URI(#DIRECTORYMASK)>>endobj
+182 0 obj<</Subtype/Link/Rect[94.6 106.8 170.2 117.8]/Border[0 0 0]/A 181 0 R>>endobj
+183 0 obj[140 0 R
+142 0 R
+144 0 R
+146 0 R
+148 0 R
+150 0 R
+152 0 R
+154 0 R
+156 0 R
+158 0 R
+160 0 R
+162 0 R
+164 0 R
+166 0 R
+168 0 R
+170 0 R
+172 0 R
+174 0 R
+176 0 R
+178 0 R
+180 0 R
+182 0 R
+]endobj
+184 0 obj<</S/URI/URI(ENCRYPTION.html)>>endobj
+185 0 obj<</Subtype/Link/Rect[108.0 707.8 200.6 720.8]/Border[0 0 0]/A 184 0 R>>endobj
+186 0 obj<</S/URI/URI(#DOMAINADMINGROUP)>>endobj
+187 0 obj<</Subtype/Link/Rect[497.0 615.4 530.0 628.4]/Border[0 0 0]/A 186 0 R>>endobj
+188 0 obj<</S/URI/URI(#DOMAINADMINGROUP)>>endobj
+189 0 obj<</Subtype/Link/Rect[72.0 602.2 127.9 615.2]/Border[0 0 0]/A 188 0 R>>endobj
+190 0 obj[185 0 R
+187 0 R
+189 0 R
+]endobj
+191 0 obj<</S/URI/URI(smbpasswd.8.html)>>endobj
+192 0 obj<</Subtype/Link/Rect[72.0 550.6 138.6 563.6]/Border[0 0 0]/A 191 0 R>>endobj
+193 0 obj<</S/URI/URI(#ADDUSERSCRIPT)>>endobj
+194 0 obj<</Subtype/Link/Rect[422.7 229.4 486.9 242.4]/Border[0 0 0]/A 193 0 R>>endobj
+195 0 obj[192 0 R
+194 0 R
+]endobj
+196 0 obj<</S/URI/URI(http://www.microsoft.com/ntserver/management/deployment/planguide/prof_policies.asp)>>endobj
+197 0 obj<</Subtype/Link/Rect[164.2 636.2 409.3 649.2]/Border[0 0 0]/A 196 0 R>>endobj
+198 0 obj[197 0 R
+]endobj
+199 0 obj<</S/URI/URI(ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE)>>endobj
+200 0 obj<</Subtype/Link/Rect[287.9 721.0 540.0 734.0]/Border[0 0 0]/A 199 0 R>>endobj
+201 0 obj<</S/URI/URI(ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE)>>endobj
+202 0 obj<</Subtype/Link/Rect[236.3 681.4 508.6 694.4]/Border[0 0 0]/A 201 0 R>>endobj
+203 0 obj<</S/URI/URI(http://www.tcpdump.org/)>>endobj
+204 0 obj<</Subtype/Link/Rect[352.1 266.6 458.1 279.6]/Border[0 0 0]/A 203 0 R>>endobj
+205 0 obj<</S/URI/URI(http://www.ethereal.com/)>>endobj
+206 0 obj<</Subtype/Link/Rect[430.0 253.4 539.4 266.4]/Border[0 0 0]/A 205 0 R>>endobj
+207 0 obj[200 0 R
+202 0 R
+204 0 R
+206 0 R
+]endobj
+208 0 obj<</S/URI/URI(http://samba.org)>>endobj
+209 0 obj<</Subtype/Link/Rect[236.3 338.2 310.8 351.2]/Border[0 0 0]/A 208 0 R>>endobj
+210 0 obj<</S/URI/URI(http://www.skippy.net/linux/smb-howto.html)>>endobj
+211 0 obj<</Subtype/Link/Rect[144.0 285.4 346.1 298.4]/Border[0 0 0]/A 210 0 R>>endobj
+212 0 obj<</S/URI/URI(http://bioserve.latrobe.edu.au/samba)>>endobj
+213 0 obj<</Subtype/Link/Rect[182.5 259.0 345.0 272.0]/Border[0 0 0]/A 212 0 R>>endobj
+214 0 obj<</S/URI/URI(http://samba.org/cifs/)>>endobj
+215 0 obj<</Subtype/Link/Rect[284.9 245.8 381.4 258.8]/Border[0 0 0]/A 214 0 R>>endobj
+216 0 obj<</S/URI/URI(http://mailhost.cb1.com/~lkcl/ntdom/)>>endobj
+217 0 obj<</Subtype/Link/Rect[244.2 232.6 411.2 245.6]/Border[0 0 0]/A 216 0 R>>endobj
+218 0 obj<</S/URI/URI(ftp://ftp.microsoft.com/developr/drg/CIFS/)>>endobj
+219 0 obj<</Subtype/Link/Rect[280.3 219.4 471.9 232.4]/Border[0 0 0]/A 218 0 R>>endobj
+220 0 obj<</S/URI/URI(http://samba.org)>>endobj
+221 0 obj<</Subtype/Link/Rect[361.0 166.6 432.8 179.6]/Border[0 0 0]/A 220 0 R>>endobj
+222 0 obj<</S/URI/URI(http://www.samba-tng.org/)>>endobj
+223 0 obj<</Subtype/Link/Rect[301.1 127.0 425.6 140.0]/Border[0 0 0]/A 222 0 R>>endobj
+224 0 obj[209 0 R
+211 0 R
+213 0 R
+215 0 R
+217 0 R
+219 0 R
+221 0 R
+223 0 R
+]endobj
+225 0 obj<</S/URI/URI(http://lists.samba.org/)>>endobj
+226 0 obj<</Subtype/Link/Rect[135.5 351.4 227.8 364.4]/Border[0 0 0]/A 225 0 R>>endobj
+227 0 obj<</S/URI/URI(http://lists.samba.org/mailman/roster/samba-ntdom)>>endobj
+228 0 obj<</Subtype/Link/Rect[309.0 338.2 330.7 351.2]/Border[0 0 0]/A 227 0 R>>endobj
+229 0 obj[226 0 R
+228 0 R
+]endobj
+230 0 obj<</S/URI/URI(mailto:jtrostel@snapserver.com)>>endobj
+231 0 obj<</Subtype/Link/Rect[200.6 255.4 310.1 268.4]/Border[0 0 0]/A 230 0 R>>endobj
+232 0 obj[231 0 R
+]endobj
+233 0 obj<</S/URI/URI(http://samba.org/)>>endobj
+234 0 obj<</Subtype/Link/Rect[196.9 385.4 308.1 398.4]/Border[0 0 0]/A 233 0 R>>endobj
+235 0 obj[234 0 R
+]endobj
+236 0 obj<</S/URI/URI(winbindd.8.html)>>endobj
+237 0 obj<</Subtype/Link/Rect[311.8 208.2 366.1 221.2]/Border[0 0 0]/A 236 0 R>>endobj
+238 0 obj<</S/URI/URI(#WINBINDSEPARATOR)>>endobj
+239 0 obj<</Subtype/Link/Rect[100.0 137.2 191.8 148.2]/Border[0 0 0]/A 238 0 R>>endobj
+240 0 obj<</S/URI/URI(#WINBINDUID)>>endobj
+241 0 obj<</Subtype/Link/Rect[100.0 115.6 159.4 126.6]/Border[0 0 0]/A 240 0 R>>endobj
+242 0 obj<</S/URI/URI(#WINBINDGID)>>endobj
+243 0 obj<</Subtype/Link/Rect[100.0 94.0 159.4 105.0]/Border[0 0 0]/A 242 0 R>>endobj
+244 0 obj<</S/URI/URI(#WINBINDENUMUSERS)>>endobj
+245 0 obj<</Subtype/Link/Rect[100.0 72.4 197.2 83.4]/Border[0 0 0]/A 244 0 R>>endobj
+246 0 obj<</S/URI/URI(#WINBINDENUMGROUP)>>endobj
+247 0 obj<</Subtype/Link/Rect[100.0 61.6 202.6 72.6]/Border[0 0 0]/A 246 0 R>>endobj
+248 0 obj[237 0 R
+239 0 R
+241 0 R
+243 0 R
+245 0 R
+247 0 R
+]endobj
+249 0 obj<</S/URI/URI(#TEMPLATEHOMEDIR)>>endobj
+250 0 obj<</Subtype/Link/Rect[100.0 711.2 186.4 722.2]/Border[0 0 0]/A 249 0 R>>endobj
+251 0 obj<</S/URI/URI(#TEMPLATESHELL)>>endobj
+252 0 obj<</Subtype/Link/Rect[100.0 700.4 175.6 711.4]/Border[0 0 0]/A 251 0 R>>endobj
+253 0 obj[250 0 R
+252 0 R
+]endobj
+254 0 obj<</S/URI/URI(http://carol.wins.uva.nl/~leeuw/samba/warp.html)>>endobj
+255 0 obj<</Subtype/Link/Rect[331.1 607.0 550.0 620.0]/Border[0 0 0]/A 254 0 R>>endobj
+256 0 obj<</S/URI/URI(ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/)>>endobj
+257 0 obj<</Subtype/Link/Rect[72.0 241.4 319.2 254.4]/Border[0 0 0]/A 256 0 R>>endobj
+258 0 obj<</S/URI/URI(http://carol.wins.uva.nl/~leeuw/lanman.html)>>endobj
+259 0 obj<</Subtype/Link/Rect[346.1 241.4 544.2 254.4]/Border[0 0 0]/A 258 0 R>>endobj
+260 0 obj<</S/URI/URI(ftp://ftp.cdrom.com/pub/os2/network/ndis/)>>endobj
+261 0 obj<</Subtype/Link/Rect[175.9 117.8 366.2 130.8]/Border[0 0 0]/A 260 0 R>>endobj
+262 0 obj[255 0 R
+257 0 R
+259 0 R
+261 0 R
+]endobj
+263 0 obj<</S/URI/URI(http://carol.wins.uva.nl/~leeuw/samba/fix.html)>>endobj
+264 0 obj<</Subtype/Link/Rect[225.7 661.0 434.8 674.0]/Border[0 0 0]/A 263 0 R>>endobj
+265 0 obj[264 0 R
+]endobj
+266 0 obj<</S/URI/URI(http://samba.org/samba/cvs.html)>>endobj
+267 0 obj<</Subtype/Link/Rect[357.1 577.0 500.7 590.0]/Border[0 0 0]/A 266 0 R>>endobj
+268 0 obj<</S/URI/URI(http://samba.org/cgi-bin/cvsweb)>>endobj
+269 0 obj<</Subtype/Link/Rect[138.6 354.6 283.2 367.6]/Border[0 0 0]/A 268 0 R>>endobj
+270 0 obj<</S/URI/URI(http://www.cyclic.com/)>>endobj
+271 0 obj<</Subtype/Link/Rect[394.3 230.2 498.2 243.2]/Border[0 0 0]/A 270 0 R>>endobj
+272 0 obj[267 0 R
+269 0 R
+271 0 R
+]endobj
+273 0 obj<</S/URI/URI(x1098.htm)>>endobj
+274 0 obj<</Subtype/Link/Rect[201.6 408.2 258.1 421.2]/Border[0 0 0]/A 273 0 R>>endobj
+275 0 obj[274 0 R
+]endobj
+276 0 obj<</Subtype/Link/Rect[72.0 684.0 277.3 697.0]/Border[0 0 0]/Dest[543 0 R/XYZ null 798 0]>>endobj
+277 0 obj<</Subtype/Link/Rect[108.0 670.8 249.2 683.8]/Border[0 0 0]/Dest[543 0 R/XYZ null 730 0]>>endobj
+278 0 obj<</Subtype/Link/Rect[108.0 657.6 255.0 670.6]/Border[0 0 0]/Dest[543 0 R/XYZ null 593 0]>>endobj
+279 0 obj<</Subtype/Link/Rect[108.0 644.4 257.7 657.4]/Border[0 0 0]/Dest[543 0 R/XYZ null 178 0]>>endobj
+280 0 obj<</Subtype/Link/Rect[108.0 631.2 309.0 644.2]/Border[0 0 0]/Dest[546 0 R/XYZ null 739 0]>>endobj
+281 0 obj<</Subtype/Link/Rect[108.0 618.0 316.7 631.0]/Border[0 0 0]/Dest[546 0 R/XYZ null 379 0]>>endobj
+282 0 obj<</Subtype/Link/Rect[108.0 604.8 284.9 617.8]/Border[0 0 0]/Dest[546 0 R/XYZ null 268 0]>>endobj
+283 0 obj<</Subtype/Link/Rect[108.0 591.6 280.0 604.6]/Border[0 0 0]/Dest[549 0 R/XYZ null 768 0]>>endobj
+284 0 obj<</Subtype/Link/Rect[108.0 578.4 328.6 591.4]/Border[0 0 0]/Dest[549 0 R/XYZ null 266 0]>>endobj
+285 0 obj<</Subtype/Link/Rect[108.0 565.2 364.9 578.2]/Border[0 0 0]/Dest[552 0 R/XYZ null 686 0]>>endobj
+286 0 obj<</Subtype/Link/Rect[108.0 552.0 315.8 565.0]/Border[0 0 0]/Dest[552 0 R/XYZ null 509 0]>>endobj
+287 0 obj<</Subtype/Link/Rect[108.0 538.8 514.3 551.8]/Border[0 0 0]/Dest[552 0 R/XYZ null 332 0]>>endobj
+288 0 obj<</Subtype/Link/Rect[108.0 525.6 259.4 538.6]/Border[0 0 0]/Dest[555 0 R/XYZ null 768 0]>>endobj
+289 0 obj<</Subtype/Link/Rect[108.0 512.4 236.0 525.4]/Border[0 0 0]/Dest[555 0 R/XYZ null 577 0]>>endobj
+290 0 obj<</Subtype/Link/Rect[108.0 499.2 186.5 512.2]/Border[0 0 0]/Dest[555 0 R/XYZ null 505 0]>>endobj
+291 0 obj<</Subtype/Link/Rect[108.0 486.0 267.2 499.0]/Border[0 0 0]/Dest[555 0 R/XYZ null 394 0]>>endobj
+292 0 obj<</Subtype/Link/Rect[108.0 472.8 295.6 485.8]/Border[0 0 0]/Dest[558 0 R/XYZ null 739 0]>>endobj
+293 0 obj<</Subtype/Link/Rect[108.0 459.6 177.7 472.6]/Border[0 0 0]/Dest[558 0 R/XYZ null 615 0]>>endobj
+294 0 obj<</Subtype/Link/Rect[108.0 446.4 232.3 459.4]/Border[0 0 0]/Dest[561 0 R/XYZ null 768 0]>>endobj
+295 0 obj<</Subtype/Link/Rect[108.0 433.2 232.6 446.2]/Border[0 0 0]/Dest[561 0 R/XYZ null 683 0]>>endobj
+296 0 obj<</Subtype/Link/Rect[72.0 406.8 348.8 419.8]/Border[0 0 0]/Dest[564 0 R/XYZ null 798 0]>>endobj
+297 0 obj<</Subtype/Link/Rect[108.0 393.6 161.5 406.6]/Border[0 0 0]/Dest[564 0 R/XYZ null 706 0]>>endobj
+298 0 obj<</Subtype/Link/Rect[108.0 380.4 327.7 393.4]/Border[0 0 0]/Dest[564 0 R/XYZ null 463 0]>>endobj
+299 0 obj<</Subtype/Link/Rect[108.0 367.2 177.1 380.2]/Border[0 0 0]/Dest[564 0 R/XYZ null 325 0]>>endobj
+300 0 obj<</Subtype/Link/Rect[108.0 354.0 203.6 367.0]/Border[0 0 0]/Dest[567 0 R/XYZ null 435 0]>>endobj
+301 0 obj<</Subtype/Link/Rect[108.0 340.8 195.1 353.8]/Border[0 0 0]/Dest[567 0 R/XYZ null 285 0]>>endobj
+302 0 obj<</Subtype/Link/Rect[108.0 327.6 215.2 340.6]/Border[0 0 0]/Dest[570 0 R/XYZ null 768 0]>>endobj
+303 0 obj<</Subtype/Link/Rect[108.0 314.4 382.4 327.4]/Border[0 0 0]/Dest[570 0 R/XYZ null 268 0]>>endobj
+304 0 obj<</Subtype/Link/Rect[108.0 301.2 255.6 314.2]/Border[0 0 0]/Dest[573 0 R/XYZ null 210 0]>>endobj
+305 0 obj<</Subtype/Link/Rect[108.0 288.0 224.1 301.0]/Border[0 0 0]/Dest[576 0 R/XYZ null 660 0]>>endobj
+306 0 obj<</Subtype/Link/Rect[108.0 274.8 187.8 287.8]/Border[0 0 0]/Dest[579 0 R/XYZ null 371 0]>>endobj
+307 0 obj<</Subtype/Link/Rect[108.0 261.6 194.5 274.6]/Border[0 0 0]/Dest[579 0 R/XYZ null 260 0]>>endobj
+308 0 obj<</Subtype/Link/Rect[108.0 248.4 200.6 261.4]/Border[0 0 0]/Dest[582 0 R/XYZ null 768 0]>>endobj
+309 0 obj<</Subtype/Link/Rect[108.0 235.2 526.0 248.2]/Border[0 0 0]/Dest[582 0 R/XYZ null 529 0]>>endobj
+310 0 obj<</Subtype/Link/Rect[108.0 222.0 500.6 235.0]/Border[0 0 0]/Dest[585 0 R/XYZ null 633 0]>>endobj
+311 0 obj<</Subtype/Link/Rect[108.0 208.8 353.3 221.8]/Border[0 0 0]/Dest[588 0 R/XYZ null 581 0]>>endobj
+312 0 obj<</Subtype/Link/Rect[108.0 195.6 419.0 208.6]/Border[0 0 0]/Dest[588 0 R/XYZ null 304 0]>>endobj
+313 0 obj<</Subtype/Link/Rect[108.0 182.4 332.5 195.4]/Border[0 0 0]/Dest[591 0 R/XYZ null 594 0]>>endobj
+314 0 obj<</Subtype/Link/Rect[108.0 169.2 181.6 182.2]/Border[0 0 0]/Dest[594 0 R/XYZ null 639 0]>>endobj
+315 0 obj<</Subtype/Link/Rect[72.0 142.8 463.4 155.8]/Border[0 0 0]/Dest[597 0 R/XYZ null 798 0]>>endobj
+316 0 obj<</Subtype/Link/Rect[108.0 129.6 202.4 142.6]/Border[0 0 0]/Dest[597 0 R/XYZ null 706 0]>>endobj
+317 0 obj<</Subtype/Link/Rect[108.0 116.4 244.9 129.4]/Border[0 0 0]/Dest[600 0 R/XYZ null 179 0]>>endobj
+318 0 obj<</Subtype/Link/Rect[108.0 103.2 270.3 116.2]/Border[0 0 0]/Dest[603 0 R/XYZ null 726 0]>>endobj
+319 0 obj<</Subtype/Link/Rect[72.0 76.8 402.3 89.8]/Border[0 0 0]/Dest[606 0 R/XYZ null 798 0]>>endobj
+320 0 obj<</Subtype/Link/Rect[108.0 63.6 179.2 76.6]/Border[0 0 0]/Dest[606 0 R/XYZ null 706 0]>>endobj
+321 0 obj[276 0 R
+277 0 R
+278 0 R
+279 0 R
+280 0 R
+281 0 R
+282 0 R
+283 0 R
+284 0 R
+285 0 R
+286 0 R
+287 0 R
+288 0 R
+289 0 R
+290 0 R
+291 0 R
+292 0 R
+293 0 R
+294 0 R
+295 0 R
+296 0 R
+297 0 R
+298 0 R
+299 0 R
+300 0 R
+301 0 R
+302 0 R
+303 0 R
+304 0 R
+305 0 R
+306 0 R
+307 0 R
+308 0 R
+309 0 R
+310 0 R
+311 0 R
+312 0 R
+313 0 R
+314 0 R
+315 0 R
+316 0 R
+317 0 R
+318 0 R
+319 0 R
+320 0 R
+]endobj
+322 0 obj<</Subtype/Link/Rect[108.0 684.0 161.2 697.0]/Border[0 0 0]/Dest[609 0 R/XYZ null 673 0]>>endobj
+323 0 obj<</Subtype/Link/Rect[72.0 657.6 412.7 670.6]/Border[0 0 0]/Dest[612 0 R/XYZ null 798 0]>>endobj
+324 0 obj<</Subtype/Link/Rect[108.0 644.4 447.4 657.4]/Border[0 0 0]/Dest[612 0 R/XYZ null 706 0]>>endobj
+325 0 obj<</Subtype/Link/Rect[108.0 631.2 319.1 644.2]/Border[0 0 0]/Dest[612 0 R/XYZ null 525 0]>>endobj
+326 0 obj<</Subtype/Link/Rect[108.0 618.0 231.1 631.0]/Border[0 0 0]/Dest[612 0 R/XYZ null 348 0]>>endobj
+327 0 obj<</Subtype/Link/Rect[108.0 604.8 292.2 617.8]/Border[0 0 0]/Dest[615 0 R/XYZ null 686 0]>>endobj
+328 0 obj<</Subtype/Link/Rect[108.0 591.6 208.5 604.6]/Border[0 0 0]/Dest[615 0 R/XYZ null 443 0]>>endobj
+329 0 obj<</Subtype/Link/Rect[108.0 578.4 233.6 591.4]/Border[0 0 0]/Dest[615 0 R/XYZ null 187 0]>>endobj
+330 0 obj<</Subtype/Link/Rect[108.0 565.2 301.4 578.2]/Border[0 0 0]/Dest[618 0 R/XYZ null 673 0]>>endobj
+331 0 obj<</Subtype/Link/Rect[108.0 552.0 394.8 565.0]/Border[0 0 0]/Dest[618 0 R/XYZ null 232 0]>>endobj
+332 0 obj<</Subtype/Link/Rect[108.0 538.8 386.9 551.8]/Border[0 0 0]/Dest[624 0 R/XYZ null 594 0]>>endobj
+333 0 obj<</Subtype/Link/Rect[72.0 512.4 277.1 525.4]/Border[0 0 0]/Dest[627 0 R/XYZ null 798 0]>>endobj
+334 0 obj<</Subtype/Link/Rect[108.0 499.2 181.6 512.2]/Border[0 0 0]/Dest[627 0 R/XYZ null 730 0]>>endobj
+335 0 obj<</Subtype/Link/Rect[108.0 486.0 189.0 499.0]/Border[0 0 0]/Dest[627 0 R/XYZ null 302 0]>>endobj
+336 0 obj<</Subtype/Link/Rect[108.0 472.8 209.7 485.8]/Border[0 0 0]/Dest[630 0 R/XYZ null 693 0]>>endobj
+337 0 obj<</Subtype/Link/Rect[108.0 459.6 294.4 472.6]/Border[0 0 0]/Dest[633 0 R/XYZ null 463 0]>>endobj
+338 0 obj<</Subtype/Link/Rect[108.0 446.4 287.3 459.4]/Border[0 0 0]/Dest[636 0 R/XYZ null 686 0]>>endobj
+339 0 obj<</Subtype/Link/Rect[108.0 433.2 350.9 446.2]/Border[0 0 0]/Dest[636 0 R/XYZ null 302 0]>>endobj
+340 0 obj<</Subtype/Link/Rect[108.0 420.0 242.1 433.0]/Border[0 0 0]/Dest[639 0 R/XYZ null 686 0]>>endobj
+341 0 obj<</Subtype/Link/Rect[108.0 406.8 220.1 419.8]/Border[0 0 0]/Dest[639 0 R/XYZ null 496 0]>>endobj
+342 0 obj<</Subtype/Link/Rect[108.0 393.6 214.3 406.6]/Border[0 0 0]/Dest[639 0 R/XYZ null 385 0]>>endobj
+343 0 obj<</Subtype/Link/Rect[108.0 380.4 281.2 393.4]/Border[0 0 0]/Dest[639 0 R/XYZ null 247 0]>>endobj
+344 0 obj<</Subtype/Link/Rect[108.0 367.2 222.3 380.2]/Border[0 0 0]/Dest[639 0 R/XYZ null 149 0]>>endobj
+345 0 obj<</Subtype/Link/Rect[108.0 354.0 234.5 367.0]/Border[0 0 0]/Dest[642 0 R/XYZ null 713 0]>>endobj
+346 0 obj<</Subtype/Link/Rect[108.0 340.8 300.2 353.8]/Border[0 0 0]/Dest[645 0 R/XYZ null 768 0]>>endobj
+347 0 obj<</Subtype/Link/Rect[72.0 314.4 272.9 327.4]/Border[0 0 0]/Dest[648 0 R/XYZ null 798 0]>>endobj
+348 0 obj<</Subtype/Link/Rect[108.0 301.2 299.9 314.2]/Border[0 0 0]/Dest[648 0 R/XYZ null 730 0]>>endobj
+349 0 obj<</Subtype/Link/Rect[108.0 288.0 288.0 301.0]/Border[0 0 0]/Dest[651 0 R/XYZ null 383 0]>>endobj
+350 0 obj<</Subtype/Link/Rect[108.0 274.8 307.9 287.8]/Border[0 0 0]/Dest[651 0 R/XYZ null 166 0]>>endobj
+351 0 obj<</Subtype/Link/Rect[72.0 248.4 416.3 261.4]/Border[0 0 0]/Dest[657 0 R/XYZ null 798 0]>>endobj
+352 0 obj<</Subtype/Link/Rect[108.0 235.2 219.2 248.2]/Border[0 0 0]/Dest[657 0 R/XYZ null 706 0]>>endobj
+353 0 obj<</Subtype/Link/Rect[108.0 222.0 181.0 235.0]/Border[0 0 0]/Dest[657 0 R/XYZ null 608 0]>>endobj
+354 0 obj<</Subtype/Link/Rect[108.0 208.8 316.1 221.8]/Border[0 0 0]/Dest[660 0 R/XYZ null 726 0]>>endobj
+355 0 obj<</Subtype/Link/Rect[108.0 195.6 430.0 208.6]/Border[0 0 0]/Dest[663 0 R/XYZ null 607 0]>>endobj
+356 0 obj<</Subtype/Link/Rect[108.0 182.4 333.2 195.4]/Border[0 0 0]/Dest[663 0 R/XYZ null 232 0]>>endobj
+357 0 obj<</Subtype/Link/Rect[108.0 169.2 362.5 182.2]/Border[0 0 0]/Dest[666 0 R/XYZ null 359 0]>>endobj
+358 0 obj<</Subtype/Link/Rect[108.0 156.0 279.4 169.0]/Border[0 0 0]/Dest[669 0 R/XYZ null 768 0]>>endobj
+359 0 obj<</Subtype/Link/Rect[108.0 142.8 261.4 155.8]/Border[0 0 0]/Dest[669 0 R/XYZ null 392 0]>>endobj
+360 0 obj<</Subtype/Link/Rect[108.0 129.6 252.8 142.6]/Border[0 0 0]/Dest[675 0 R/XYZ null 739 0]>>endobj
+361 0 obj<</Subtype/Link/Rect[108.0 116.4 243.6 129.4]/Border[0 0 0]/Dest[678 0 R/XYZ null 686 0]>>endobj
+362 0 obj<</Subtype/Link/Rect[108.0 103.2 292.9 116.2]/Border[0 0 0]/Dest[684 0 R/XYZ null 303 0]>>endobj
+363 0 obj<</Subtype/Link/Rect[108.0 90.0 332.0 103.0]/Border[0 0 0]/Dest[687 0 R/XYZ null 277 0]>>endobj
+364 0 obj<</Subtype/Link/Rect[108.0 76.8 406.2 89.8]/Border[0 0 0]/Dest[690 0 R/XYZ null 482 0]>>endobj
+365 0 obj<</Subtype/Link/Rect[108.0 63.6 431.0 76.6]/Border[0 0 0]/Dest[702 0 R/XYZ null 274 0]>>endobj
+366 0 obj[322 0 R
+323 0 R
+324 0 R
+325 0 R
+326 0 R
+327 0 R
+328 0 R
+329 0 R
+330 0 R
+331 0 R
+332 0 R
+333 0 R
+334 0 R
+335 0 R
+336 0 R
+337 0 R
+338 0 R
+339 0 R
+340 0 R
+341 0 R
+342 0 R
+343 0 R
+344 0 R
+345 0 R
+346 0 R
+347 0 R
+348 0 R
+349 0 R
+350 0 R
+351 0 R
+352 0 R
+353 0 R
+354 0 R
+355 0 R
+356 0 R
+357 0 R
+358 0 R
+359 0 R
+360 0 R
+361 0 R
+362 0 R
+363 0 R
+364 0 R
+365 0 R
+]endobj
+367 0 obj<</Subtype/Link/Rect[72.0 684.0 426.2 697.0]/Border[0 0 0]/Dest[711 0 R/XYZ null 798 0]>>endobj
+368 0 obj<</Subtype/Link/Rect[108.0 670.8 164.5 683.8]/Border[0 0 0]/Dest[711 0 R/XYZ null 706 0]>>endobj
+369 0 obj<</Subtype/Link/Rect[108.0 657.6 181.6 670.6]/Border[0 0 0]/Dest[711 0 R/XYZ null 569 0]>>endobj
+370 0 obj<</Subtype/Link/Rect[108.0 644.4 233.6 657.4]/Border[0 0 0]/Dest[711 0 R/XYZ null 246 0]>>endobj
+371 0 obj<</Subtype/Link/Rect[108.0 631.2 188.3 644.2]/Border[0 0 0]/Dest[714 0 R/XYZ null 581 0]>>endobj
+372 0 obj<</Subtype/Link/Rect[108.0 618.0 222.0 631.0]/Border[0 0 0]/Dest[714 0 R/XYZ null 417 0]>>endobj
+373 0 obj<</Subtype/Link/Rect[108.0 604.8 288.6 617.8]/Border[0 0 0]/Dest[714 0 R/XYZ null 292 0]>>endobj
+374 0 obj<</Subtype/Link/Rect[108.0 591.6 230.8 604.6]/Border[0 0 0]/Dest[717 0 R/XYZ null 768 0]>>endobj
+375 0 obj<</Subtype/Link/Rect[108.0 578.4 288.9 591.4]/Border[0 0 0]/Dest[717 0 R/XYZ null 313 0]>>endobj
+376 0 obj<</Subtype/Link/Rect[108.0 565.2 269.3 578.2]/Border[0 0 0]/Dest[720 0 R/XYZ null 673 0]>>endobj
+377 0 obj<</Subtype/Link/Rect[108.0 552.0 203.0 565.0]/Border[0 0 0]/Dest[720 0 R/XYZ null 483 0]>>endobj
+378 0 obj<</Subtype/Link/Rect[108.0 538.8 259.9 551.8]/Border[0 0 0]/Dest[720 0 R/XYZ null 332 0]>>endobj
+379 0 obj<</Subtype/Link/Rect[108.0 525.6 189.9 538.6]/Border[0 0 0]/Dest[720 0 R/XYZ null 221 0]>>endobj
+380 0 obj<</Subtype/Link/Rect[108.0 512.4 196.6 525.4]/Border[0 0 0]/Dest[723 0 R/XYZ null 581 0]>>endobj
+381 0 obj<</Subtype/Link/Rect[108.0 499.2 221.1 512.2]/Border[0 0 0]/Dest[723 0 R/XYZ null 298 0]>>endobj
+382 0 obj<</Subtype/Link/Rect[108.0 486.0 178.0 499.0]/Border[0 0 0]/Dest[738 0 R/XYZ null 355 0]>>endobj
+383 0 obj<</Subtype/Link/Rect[108.0 472.8 177.4 485.8]/Border[0 0 0]/Dest[741 0 R/XYZ null 768 0]>>endobj
+384 0 obj<</Subtype/Link/Rect[72.0 446.4 228.8 459.4]/Border[0 0 0]/Dest[744 0 R/XYZ null 798 0]>>endobj
+385 0 obj<</Subtype/Link/Rect[108.0 433.2 159.0 446.2]/Border[0 0 0]/Dest[744 0 R/XYZ null 730 0]>>endobj
+386 0 obj<</Subtype/Link/Rect[108.0 420.0 499.0 433.0]/Border[0 0 0]/Dest[744 0 R/XYZ null 700 0]>>endobj
+387 0 obj<</Subtype/Link/Rect[108.0 406.8 504.2 419.8]/Border[0 0 0]/Dest[744 0 R/XYZ null 348 0]>>endobj
+388 0 obj<</Subtype/Link/Rect[108.0 393.6 455.7 406.6]/Border[0 0 0]/Dest[747 0 R/XYZ null 768 0]>>endobj
+389 0 obj<</Subtype/Link/Rect[108.0 380.4 425.4 393.4]/Border[0 0 0]/Dest[747 0 R/XYZ null 639 0]>>endobj
+390 0 obj<</Subtype/Link/Rect[72.0 354.0 342.4 367.0]/Border[0 0 0]/Dest[750 0 R/XYZ null 798 0]>>endobj
+391 0 obj<</Subtype/Link/Rect[108.0 340.8 187.1 353.8]/Border[0 0 0]/Dest[750 0 R/XYZ null 706 0]>>endobj
+392 0 obj<</Subtype/Link/Rect[108.0 327.6 247.6 340.6]/Border[0 0 0]/Dest[750 0 R/XYZ null 582 0]>>endobj
+393 0 obj<</Subtype/Link/Rect[108.0 314.4 230.8 327.4]/Border[0 0 0]/Dest[750 0 R/XYZ null 484 0]>>endobj
+394 0 obj<</Subtype/Link/Rect[108.0 301.2 205.8 314.2]/Border[0 0 0]/Dest[750 0 R/XYZ null 359 0]>>endobj
+395 0 obj<</Subtype/Link/Rect[72.0 288.0 97.0 301.0]/Border[0 0 0]/Dest[753 0 R/XYZ null 503 0]>>endobj
+396 0 obj[367 0 R
+368 0 R
+369 0 R
+370 0 R
+371 0 R
+372 0 R
+373 0 R
+374 0 R
+375 0 R
+376 0 R
+377 0 R
+378 0 R
+379 0 R
+380 0 R
+381 0 R
+382 0 R
+383 0 R
+384 0 R
+385 0 R
+386 0 R
+387 0 R
+388 0 R
+389 0 R
+390 0 R
+391 0 R
+392 0 R
+393 0 R
+394 0 R
+395 0 R
+]endobj
+397 0 obj<</Dests 398 0 R>>endobj
+398 0 obj<</Kids[399 0 R]>>endobj
+399 0 obj<</Limits[(aen1054)(winbind)]/Names[(aen1054)400 0 R(aen1059)401 0 R(aen1092)402 0 R(aen1098)403 0 R(aen1137)404 0 R(aen117)405 0 R(aen1180)406 0 R(aen1199)407 0 R(aen1234)408 0 R(aen1243)409 0 R(aen1258)410 0 R(aen1306)411 0 R(aen133)412 0 R(aen1350)413 0 R(aen142)414 0 R(aen1464)415 0 R(aen1490)416 0 R(aen1509)417 0 R(aen1517)418 0 R(aen1525)419 0 R(aen1533)420 0 R(aen1540)421 0 R(aen1576)422 0 R(aen158)423 0 R(aen1589)424 0 R(aen1592)425 0 R(aen1602)426 0 R(aen1652)427 0 R(aen1656)428 0 R(aen1669)429 0 R(aen1676)430 0 R(aen1680)431 0 R(aen1685)432 0 R(aen1689)433 0 R(aen1705)434 0 R(aen1713)435 0 R(aen1717)436 0 R(aen172)437 0 R(aen1720)438 0 R(aen1725)439 0 R(aen1738)440 0 R(aen1752)441 0 R(aen1763)442 0 R(aen177)443 0 R(aen1782)444 0 R(aen18)445 0 R(aen1807)446 0 R(aen181)447 0 R(aen1823)448 0 R(aen1834)449 0 R(aen184)450 0 R(aen1870)451 0 R(aen1892)452 0 R(aen193)453 0 R(aen1939)454 0 R(aen1949)455 0 R(aen1963)456 0 R(aen1965)457 0 R(aen197)458 0 R(aen1980)459 0 R(aen1989)460 0 R(aen1993)461 0 R(aen2009)462 0 R(aen2014)463 0 R(aen2017)464 0 R(aen2022)465 0 R(aen2050)466 0 R(aen207)467 0 R(aen210)468 0 R(aen224)469 0 R(aen246)470 0 R(aen26)471 0 R(aen262)472 0 R(aen278)473 0 R(aen289)474 0 R(aen297)475 0 R(aen309)476 0 R(aen321)477 0 R(aen326)478 0 R(aen334)479 0 R(aen339)480 0 R(aen342)481 0 R(aen354)482 0 R(aen364)483 0 R(aen392)484 0 R(aen4)485 0 R(aen400)486 0 R(aen417)487 0 R(aen424)488 0 R(aen429)489 0 R(aen434)490 0 R(aen455)491 0 R(aen499)492 0 R(aen506)493 0 R(aen526)494 0 R(aen54)495 0 R(aen561)496 0 R(aen58)497 0 R(aen581)498 0 R(aen590)499 0 R(aen601)500 0 R(aen621)501 0 R(aen636)502 0 R(aen650)503 0 R(aen657)504 0 R(aen679)505 0 R(aen72)506 0 R(aen743)507 0 R(aen764)508 0 R(aen78)509 0 R(aen786)510 0 R(aen797)511 0 R(aen8)512 0 R(aen832)513 0 R(aen849)514 0 R(aen860)515 0 R(aen88)516 0 R(aen885)517 0 R(aen893)518 0 R(aen897)519 0 R(aen907)520 0 R(aen910)521 0 R(aen914)522 0 R(aen936)523 0 R(aen990)524 0 R(body.html)525 0 R(cvs-access)526 0 R(domain-security)527 0 R(install)528 0 R(integrate-ms-networks)529 0 R(migration)530 0 R(msdfs)531 0 R(os2)532 0 R(pam)533 0 R(printing)534 0 R(samba-pdc)535 0 R(samba-project-documentation)536 0 R(unix-permissions)537 0 R(winbind)538 0 R]>>endobj
+400 0 obj<</D[648 0 R/XYZ null 383 null]>>endobj
+401 0 obj<</D[648 0 R/XYZ null 166 null]>>endobj
+402 0 obj<</D[654 0 R/XYZ null 706 null]>>endobj
+403 0 obj<</D[654 0 R/XYZ null 608 null]>>endobj
+404 0 obj<</D[657 0 R/XYZ null 726 null]>>endobj
+405 0 obj<</D[546 0 R/XYZ null 266 null]>>endobj
+406 0 obj<</D[660 0 R/XYZ null 607 null]>>endobj
+407 0 obj<</D[660 0 R/XYZ null 232 null]>>endobj
+408 0 obj<</D[663 0 R/XYZ null 359 null]>>endobj
+409 0 obj<</D[666 0 R/XYZ null 768 null]>>endobj
+410 0 obj<</D[666 0 R/XYZ null 392 null]>>endobj
+411 0 obj<</D[672 0 R/XYZ null 739 null]>>endobj
+412 0 obj<</D[549 0 R/XYZ null 686 null]>>endobj
+413 0 obj<</D[675 0 R/XYZ null 686 null]>>endobj
+414 0 obj<</D[549 0 R/XYZ null 509 null]>>endobj
+415 0 obj<</D[681 0 R/XYZ null 303 null]>>endobj
+416 0 obj<</D[684 0 R/XYZ null 277 null]>>endobj
+417 0 obj<</D[687 0 R/XYZ null 482 null]>>endobj
+418 0 obj<</D[687 0 R/XYZ null 225 null]>>endobj
+419 0 obj<</D[690 0 R/XYZ null 684 null]>>endobj
+420 0 obj<</D[690 0 R/XYZ null 446 null]>>endobj
+421 0 obj<</D[690 0 R/XYZ null 289 null]>>endobj
+422 0 obj<</D[696 0 R/XYZ null 605 null]>>endobj
+423 0 obj<</D[549 0 R/XYZ null 332 null]>>endobj
+424 0 obj<</D[699 0 R/XYZ null 698 null]>>endobj
+425 0 obj<</D[699 0 R/XYZ null 603 null]>>endobj
+426 0 obj<</D[699 0 R/XYZ null 274 null]>>endobj
+427 0 obj<</D[708 0 R/XYZ null 706 null]>>endobj
+428 0 obj<</D[708 0 R/XYZ null 569 null]>>endobj
+429 0 obj<</D[708 0 R/XYZ null 246 null]>>endobj
+430 0 obj<</D[711 0 R/XYZ null 581 null]>>endobj
+431 0 obj<</D[711 0 R/XYZ null 417 null]>>endobj
+432 0 obj<</D[711 0 R/XYZ null 292 null]>>endobj
+433 0 obj<</D[714 0 R/XYZ null 768 null]>>endobj
+434 0 obj<</D[714 0 R/XYZ null 313 null]>>endobj
+435 0 obj<</D[717 0 R/XYZ null 673 null]>>endobj
+436 0 obj<</D[717 0 R/XYZ null 483 null]>>endobj
+437 0 obj<</D[552 0 R/XYZ null 768 null]>>endobj
+438 0 obj<</D[717 0 R/XYZ null 332 null]>>endobj
+439 0 obj<</D[717 0 R/XYZ null 221 null]>>endobj
+440 0 obj<</D[720 0 R/XYZ null 581 null]>>endobj
+441 0 obj<</D[720 0 R/XYZ null 298 null]>>endobj
+442 0 obj<</D[720 0 R/XYZ null 132 null]>>endobj
+443 0 obj<</D[552 0 R/XYZ null 577 null]>>endobj
+444 0 obj<</D[723 0 R/XYZ null 619 null]>>endobj
+445 0 obj<</D[540 0 R/XYZ null 730 null]>>endobj
+446 0 obj<</D[723 0 R/XYZ null 279 null]>>endobj
+447 0 obj<</D[552 0 R/XYZ null 505 null]>>endobj
+448 0 obj<</D[726 0 R/XYZ null 691 null]>>endobj
+449 0 obj<</D[726 0 R/XYZ null 530 null]>>endobj
+450 0 obj<</D[552 0 R/XYZ null 394 null]>>endobj
+451 0 obj<</D[729 0 R/XYZ null 467 null]>>endobj
+452 0 obj<</D[732 0 R/XYZ null 511 null]>>endobj
+453 0 obj<</D[555 0 R/XYZ null 739 null]>>endobj
+454 0 obj<</D[735 0 R/XYZ null 355 null]>>endobj
+455 0 obj<</D[738 0 R/XYZ null 768 null]>>endobj
+456 0 obj<</D[741 0 R/XYZ null 730 null]>>endobj
+457 0 obj<</D[741 0 R/XYZ null 700 null]>>endobj
+458 0 obj<</D[555 0 R/XYZ null 615 null]>>endobj
+459 0 obj<</D[741 0 R/XYZ null 348 null]>>endobj
+460 0 obj<</D[744 0 R/XYZ null 768 null]>>endobj
+461 0 obj<</D[744 0 R/XYZ null 639 null]>>endobj
+462 0 obj<</D[747 0 R/XYZ null 706 null]>>endobj
+463 0 obj<</D[747 0 R/XYZ null 582 null]>>endobj
+464 0 obj<</D[747 0 R/XYZ null 484 null]>>endobj
+465 0 obj<</D[747 0 R/XYZ null 359 null]>>endobj
+466 0 obj<</D[750 0 R/XYZ null 503 null]>>endobj
+467 0 obj<</D[558 0 R/XYZ null 768 null]>>endobj
+468 0 obj<</D[558 0 R/XYZ null 683 null]>>endobj
+469 0 obj<</D[561 0 R/XYZ null 706 null]>>endobj
+470 0 obj<</D[561 0 R/XYZ null 463 null]>>endobj
+471 0 obj<</D[540 0 R/XYZ null 593 null]>>endobj
+472 0 obj<</D[561 0 R/XYZ null 325 null]>>endobj
+473 0 obj<</D[564 0 R/XYZ null 435 null]>>endobj
+474 0 obj<</D[564 0 R/XYZ null 285 null]>>endobj
+475 0 obj<</D[567 0 R/XYZ null 768 null]>>endobj
+476 0 obj<</D[567 0 R/XYZ null 268 null]>>endobj
+477 0 obj<</D[570 0 R/XYZ null 210 null]>>endobj
+478 0 obj<</D[573 0 R/XYZ null 660 null]>>endobj
+479 0 obj<</D[576 0 R/XYZ null 371 null]>>endobj
+480 0 obj<</D[576 0 R/XYZ null 260 null]>>endobj
+481 0 obj<</D[579 0 R/XYZ null 768 null]>>endobj
+482 0 obj<</D[579 0 R/XYZ null 529 null]>>endobj
+483 0 obj<</D[582 0 R/XYZ null 633 null]>>endobj
+484 0 obj<</D[585 0 R/XYZ null 581 null]>>endobj
+485 0 obj<</D[537 0 R/XYZ null 647 null]>>endobj
+486 0 obj<</D[585 0 R/XYZ null 304 null]>>endobj
+487 0 obj<</D[588 0 R/XYZ null 594 null]>>endobj
+488 0 obj<</D[588 0 R/XYZ null 271 null]>>endobj
+489 0 obj<</D[591 0 R/XYZ null 753 null]>>endobj
+490 0 obj<</D[591 0 R/XYZ null 639 null]>>endobj
+491 0 obj<</D[594 0 R/XYZ null 706 null]>>endobj
+492 0 obj<</D[597 0 R/XYZ null 179 null]>>endobj
+493 0 obj<</D[600 0 R/XYZ null 726 null]>>endobj
+494 0 obj<</D[603 0 R/XYZ null 706 null]>>endobj
+495 0 obj<</D[540 0 R/XYZ null 178 null]>>endobj
+496 0 obj<</D[606 0 R/XYZ null 673 null]>>endobj
+497 0 obj<</D[543 0 R/XYZ null 739 null]>>endobj
+498 0 obj<</D[609 0 R/XYZ null 706 null]>>endobj
+499 0 obj<</D[609 0 R/XYZ null 525 null]>>endobj
+500 0 obj<</D[609 0 R/XYZ null 348 null]>>endobj
+501 0 obj<</D[612 0 R/XYZ null 686 null]>>endobj
+502 0 obj<</D[612 0 R/XYZ null 443 null]>>endobj
+503 0 obj<</D[612 0 R/XYZ null 187 null]>>endobj
+504 0 obj<</D[615 0 R/XYZ null 673 null]>>endobj
+505 0 obj<</D[615 0 R/XYZ null 232 null]>>endobj
+506 0 obj<</D[543 0 R/XYZ null 379 null]>>endobj
+507 0 obj<</D[621 0 R/XYZ null 594 null]>>endobj
+508 0 obj<</D[624 0 R/XYZ null 730 null]>>endobj
+509 0 obj<</D[543 0 R/XYZ null 268 null]>>endobj
+510 0 obj<</D[624 0 R/XYZ null 302 null]>>endobj
+511 0 obj<</D[627 0 R/XYZ null 693 null]>>endobj
+512 0 obj<</D[537 0 R/XYZ null 616 null]>>endobj
+513 0 obj<</D[630 0 R/XYZ null 463 null]>>endobj
+514 0 obj<</D[633 0 R/XYZ null 686 null]>>endobj
+515 0 obj<</D[633 0 R/XYZ null 302 null]>>endobj
+516 0 obj<</D[546 0 R/XYZ null 768 null]>>endobj
+517 0 obj<</D[636 0 R/XYZ null 686 null]>>endobj
+518 0 obj<</D[636 0 R/XYZ null 496 null]>>endobj
+519 0 obj<</D[636 0 R/XYZ null 385 null]>>endobj
+520 0 obj<</D[636 0 R/XYZ null 247 null]>>endobj
+521 0 obj<</D[636 0 R/XYZ null 149 null]>>endobj
+522 0 obj<</D[639 0 R/XYZ null 713 null]>>endobj
+523 0 obj<</D[642 0 R/XYZ null 768 null]>>endobj
+524 0 obj<</D[645 0 R/XYZ null 730 null]>>endobj
+525 0 obj<</D[543 0 R/XYZ null 698 null]>>endobj
+526 0 obj<</D[747 0 R/XYZ null 798 null]>>endobj
+527 0 obj<</D[645 0 R/XYZ null 798 null]>>endobj
+528 0 obj<</D[540 0 R/XYZ null 798 null]>>endobj
+529 0 obj<</D[561 0 R/XYZ null 798 null]>>endobj
+530 0 obj<</D[642 0 R/XYZ null 768 null]>>endobj
+531 0 obj<</D[603 0 R/XYZ null 798 null]>>endobj
+532 0 obj<</D[741 0 R/XYZ null 798 null]>>endobj
+533 0 obj<</D[594 0 R/XYZ null 798 null]>>endobj
+534 0 obj<</D[624 0 R/XYZ null 798 null]>>endobj
+535 0 obj<</D[654 0 R/XYZ null 798 null]>>endobj
+536 0 obj<</D[537 0 R/XYZ null 753 null]>>endobj
+537 0 obj<</D[609 0 R/XYZ null 798 null]>>endobj
+538 0 obj<</D[708 0 R/XYZ null 798 null]>>endobj
+539 0 obj<</Type/Pages/MediaBox[0 0 595 792]/Count 75/Kids[540 0 R
+756 0 R
+759 0 R
+762 0 R
+543 0 R
+546 0 R
+549 0 R
+552 0 R
+555 0 R
+558 0 R
+561 0 R
+564 0 R
+567 0 R
+570 0 R
+573 0 R
+576 0 R
+579 0 R
+582 0 R
+585 0 R
+588 0 R
+591 0 R
+594 0 R
+597 0 R
+600 0 R
+603 0 R
+606 0 R
+609 0 R
+612 0 R
+615 0 R
+618 0 R
+621 0 R
+624 0 R
+627 0 R
+630 0 R
+633 0 R
+636 0 R
+639 0 R
+642 0 R
+645 0 R
+648 0 R
+651 0 R
+654 0 R
+657 0 R
+660 0 R
+663 0 R
+666 0 R
+669 0 R
+672 0 R
+675 0 R
+678 0 R
+681 0 R
+684 0 R
+687 0 R
+690 0 R
+693 0 R
+696 0 R
+699 0 R
+702 0 R
+705 0 R
+708 0 R
+711 0 R
+714 0 R
+717 0 R
+720 0 R
+723 0 R
+726 0 R
+729 0 R
+732 0 R
+735 0 R
+738 0 R
+741 0 R
+744 0 R
+747 0 R
+750 0 R
+753 0 R
+]>>endobj
+540 0 obj<</Type/Page/Parent 539 0 R/Contents 541 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 17 0 R>>endobj
+541 0 obj<</Length 542 0 R/Filter/FlateDecode>>stream
+xuSÉnÛ0½ë+rrT&%Yv|ª“tE‹¤µŠž)i¼U]’ªá¿ïVêÄE!hÎöޛѯHBð%1Mæ¨Ú趈Æïn+öäi†¢†ˆ…à“j´\|¹]àÑèU÷ºê[êœr[ݽ*v!Ur†O}=ñŒ“‡œ‚TëCÞWÃd"ٛͦüðm«“#ÍãüÒq*»ÉCé3®EiQ•;È!å
+~|\×TÃi,U[*ÔÏU‚þMnC8’26ÆG8sôÁÔÙžUpå šfè+Ó~Å®ª7†Õ¾FÙ;XÝ’Û¶dC±
+endobj
+542 0 obj
+501
+endobj
+543 0 obj<</Type/Page/Parent 539 0 R/Contents 544 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 20 0 R>>endobj
+544 0 obj<</Length 545 0 R/Filter/FlateDecode>>stream
+xV]sÛ6|ׯ¸¦‰:cS¢>,Éov§NóÐfë¥ Š¨H€À(šéïÞ‘´å4êÔeK{»{ þ5JiŠŸ”V3šßPVî·£ÉÆfSÚøæfµ¦mNÓd:Å'Ùø§R5Q{JúÅ):zoCTUEÊæ´Õ!Òãݯ÷w?nÿ”:颫s=O“*Ó[£nhzKµÊ)–šje©Q{º} JÓ~ßlÅ»¶çk(7!z³k£ÎéhbÙI™³QKT¹ÈÔ]´[8œ¢"h©«†ïu¤“k ð=*%Dï þ€!Lé:w€sgßF:Xt[v{Fý„˜ñ[ŠþD\­ciìž*sз]/`÷©—›täã¨û*í¿[®¹f¨wy²¦¿©v^˺Ÿ·#¦_4
+&ê+¡é%.¿§1•16·“ÉñxLïHœßóÚmHCXŽ¿´\ÌñºX¯ð:Ã/N/öYN7¢Æ³a§ÞGé-Ý·¦Ê™wöÒ½±Ê›ËVr”³L¸¢ÂxÖ·Ðïö^Õ½8ËAœdcfßözLfÇ°–ì숄/½Î¢ó§„¶¨O¡tm•“j£cj3Œ \òTM|6ZÇ/d`zröØ„¦Â)D]'½=©TŸ4µ¶ ­ªˆ¬Öy`VÌ\«\J}u>ûŠ½sñû/mxÞéõµÌIW`hc1ë=ÜQ‡S‚Ötäá
+Î ¹†]NGk«v•Æxm¤þ¬³–Ûz´ZôE,2ÖÆ2j‘c×; ¡6Ódâ[hÑf°z@tÔ©ào
+w¢BLøïøØ.k)­‘šÿ¬›…ÜIçÁ:ïƒuvË#K|¹›ºq>*‹)ÇÕýoQå’¾‹(ŒÄ^wiÔ"^ ³’ßú «P‘€EÔ€Äìyʽ±Ù …h궒ìK莂L³çÇ ¶
+endobj
+545 0 obj
+1091
+endobj
+546 0 obj<</Type/Page/Parent 539 0 R/Contents 547 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+547 0 obj<</Length 548 0 R/Filter/FlateDecode>>stream
+xWÛnÛ8}ÏWÌö¥.ÐÈ—ØŽ`Ún[E/Û8Ø šÅ‚’h™Dº$•Ô¿gH*vÕ¤› Žc çræÌæÛјFøÓé„NæT4G/WG¯WG£l± ý‹­ðLj¦Ëy¶ éâïOù­•´†í>î_’í|±Ì¦Évû`
+çÃ7KOiµFØùl–ÍiU†Ó#Zƒq6ÍèÂË-œÑ++…—ä7’\“SaôZU­^MkUËìÙê+Ni<Ž'§p7Xm$ ü8ÑlkùÀQGJÏò{0qD®ÍKeeáÝuOKå¼UyË!3:‡MUIçigZT$JvÑp#:ŸdŽ^ ðº­ë9 ¡ÉIIsBš-»sTò¦’pa9m­(¼*$€5—ÝàäVT@ÙXu}x<°“9pŽE“S\.òk§ð@ÝtgÚº¤\¢^Ó ¶ÒÕê†ã)wÑ’ñÃù,:§ôõ¥ªM.꺒AŽÝ=Æï;co*kÚ-ýNï¯Þ~þxù)OÆ¡Ù‡Æ_6ÈÁýÂV-dnàO›ÇãÂ24Äh
+ê–Ýa˜^Fé“ÑŠå™·‘*ÚZ`ÜY†Ðˆ°ŽWr9ÊØÓ—“X}·pAþÆ–Q²"Gâ¦ã‰Ô|ÚõÂP90 ƒ kLT°ƒÕ±T€sQÞBJø*ɘȕûV1-{@Š÷Ì~fü€¹+Rë¾H㺋*,ÜÖ€®VÕÆã†dþ[«Š›º_ ?•V^‰p…K—öo|丫!Ìs¾RÊxÑ|‰ƒcœ‚e
+endobj
+548 0 obj
+1450
+endobj
+549 0 obj<</Type/Page/Parent 539 0 R/Contents 550 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+550 0 obj<</Length 551 0 R/Filter/FlateDecode>>stream
+x•WaOã8ýί¸×ÕÒ´iK[¸O¬v¹Cºe9èiµÒJ'7qZC÷l‡¶ÿþÞØM[²ôX@
+E±Çã÷Þ¼™þ{S¿1zÔRR}˜}šu£ñ˜v3Ã?]÷¢1 Æ#| ¢I–â¿áîM¿ ÄÂKÄß>§suNñ€&ŽŽñ!õï»4IZq4Œâˆî\Й¸Àaœ*g”]*¥K£D—Ù»ÉÃQçj@qâ´{#ÄiÝ|™|ú&sd¥ó\/yçRå9M%¥*ˤ‘¥#•­uE••ts}OÚðŸ÷ä4YgÔ´r2%+Í“J¤¥B,lÄ'v©ÝâÖ8éO­I8Žc(d}6­ŽtI§Þý<ÓVDôuŽ}ÊR*3\(å( mÅýóŽK]gTj7çä÷–‘›Ë’DŠ ”c#r“UÜzœ6Ù‹pb¼‡Í&g 7UÚ¶­-©>íyz{´ªP¹0ùP¬uªtáa³s]å)ÍÅ“$Q5kŸÌë'—¶Žtðܹr$Sõ?Ð’A é
+á…) ‚³Y®ý2P_J,.×à‹
+뫱kè6‚HlhŒ ¨ÒI“ ¸× é…Sš bMz÷äµv!•­ýúë[®#­m€ÁõÜ aYEÞìv¡#º«jÀÏjóSû³šj‡FiÚP10_öÞT—¿:zD-Ñ’ýÓž-ÒD
+¢a7—@¡`¯8Ä ]rª§‹§L¨Ü a“تü^­L<nxâ¤õ]ˆO;yYßl3:e”àê©÷îpÓšœTã’ê‡Fr||üõòîæúæw|¢ÏLo¨7$óI"HÞhΈFÁ÷ò™3l‰. ŠÔÞ pP{hE$Ô ¼ÆŸgšXWvÁjÚz„e½ë"ÃYU@¹ö”«`·ßod£îÔ¯µÜÔ™ñÆÑa àå^H­où[4ˆnÉXâÈ?±õ”ÒÌÑ×éëÝJàçEBü}ë;0ßÀ·8U"jžs£F³CGT0¾'àÏEµµÖm¢Þ›‰ò]KI]­¼`OÅÐê#)Þ×Q)K™çþv~ëR/b¤
+sWÓ–»0\íR±ŸÍšÃT¯¦¦]æM)œz’ä¡ò2…ºÀ!¥Bº|ž9Ï¡§À0jÖü` övíóÀÀá͈¸áó… m£k
+Ð=1Ð̘€p|íÞ{ùÓá_ÏókmŒáõ^þËqhÍóù-ùpCoôÂâœÞ²×SºÙ»›XwÝÚK÷
+endobj
+551 0 obj
+1365
+endobj
+552 0 obj<</Type/Page/Parent 539 0 R/Contents 553 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F2 5 0 R/F3 6 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+553 0 obj<</Length 554 0 R/Filter/FlateDecode>>stream
+x­V]OëF}çWL¥V q’‡J÷SºÒ½Ð6iQÕôaco’%ö®ïîÈ¿¿gvíKH€>´ ÀÁöÌ™3çÌìדõñ= qJç#ÊÊ“·ó“ÞÇ! 4_áÎh2¦yNý¤ßïÓ<ëÌ mUQòä¤ÎIÄN­µ(ÈòI•5™tN::ß"ÜE®Cº\æñmŠ „9xÎ?–ð#}ꦣdD«ëù‡)}ZÑÎÔT;Ïþü}HÎï
+IJ3Äó²ä[šÂƒ¥ØQ¡¶xÚPaÌ–„ç»1=xhªîΓ”³ÈQV…t=wg‡]ç…õuuX€Ë¬ªÇP)z&Ê¥ Ò+AŽ$Ôða~6it>JF4œŒqâÇJZEò/i€
+ùý4™<¡ŒšyYÑhJsËÅ8¯ô:Tï6‚sq'T!–àÀh.ÚZeï¤=ª2åÞv~lØ´]ûY¡¤öÔýÜÜ;oï…€ã¼eC[ÛɽæüÅYÝÆÔENkéi)2PÀ’YáÎ1Ј4MÚ¾æFÿ¤É™Rú —ªˆÍŒµ2óÅ®‘EÛ0'Ñ „èÊx–Dh/^àwMN™Ð$
+gh)Y39÷ÌII÷ü`ƒŠ€í)‡
+±ôYè/B‹5.#;î õ¢ãêlCÂÑÍêf½8=Tl£Õlc äŠô–
+y' Èj«ü.ê”õÌ2])ø"–eå×Z:S%œ»76G+¸ÐÚ=»’ÕÀQÅÊÀÊ µâö3v‹%E…´ í
+endobj
+554 0 obj
+1189
+endobj
+555 0 obj<</Type/Page/Parent 539 0 R/Contents 556 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+556 0 obj<</Length 557 0 R/Filter/FlateDecode>>stream
+xWÙnã8|ÏW4ò²`+¶ã\ƒ=à\‰'3öÂX /´DÙœP¤G¤âøï·š”r(³‚ŠE²««««é{êãg@§C::¡´Ø»˜ïÞœÓ`DóoNÎðQ?é÷û4O;ƒdÐOh±ž&9Í×ʬ]Y󋧅-ÿ8˜Çþ qoxŠý¬5ÖójÚb™#a2ÚÙŠœ¥'o‰_>Òþvmi[Z/‰?q´QZ’Íɗ­÷ñ™44!W­VÒùpBfqˆÜÐÄJ(CœÍ0úÔ%CÞ<WZ‡M©Ðevk’zåð$áD;sÀÀ
+µZ{*¥È8(åŒãj2þ<ý2›ÌÿìC
+üŠnÆ_fƒ·‰R‡q¾J#`_îÂ!…Pš)Ð
+ØmÙiäÖ­J[m‚¶ö‘ Ÿÿíz|uwM¹-)“G¸‡ƒ„f¢X
+Z GK È $M¥sy¥õ;Á«Ö2#ÔɯmåÀ‰còÒµ£":ÛªLvÉY*Än‰¤œ-¤5’¤v2„Y«ÀwI›Ò.µ,Bþß>É2ÅjR>¡¿ÀAj+ Ó*ìæ$‹E+*#á»TZ
+p¥œ«d@É;'Ø˺]¥ES¥\=‡ãL÷·×ãÙ59 y'AÕ&H:Š ™e6­
+i¼ðʲ\À«³U™J
+Êg†Ѯ耶K6lº·Å= ÐWñfÂÙÇò%t¹¶Qà :ö6µšnå“ÔïųŽ“bŽ…³» ÖY\ÌS(¡eêN­Ê¬ *µ(\µÙØÒ;:î¬ïòË·ënø{ûç¬K·ãéÝx:h³?Æì@O烶Ñ;ƒ?¥œ‡¤-ÛB!žUQ¯Áp €ώɽ´
+™¤Öäïsî„©ÂÚ•/"GÁG=\+øÁ‡–<ü¸ÄLë“À?…ønKåw/ßÎdbÈêL–·v0¾à³qˆ°háúÑAr[Õ–f$ €eÌ”2™±V…ŠÊ”Y÷¶¥æ Á ÑÂ:®X˜V°m™A‘!=c·ØëÆâ£ÄŠpcŠ:ÛxaÞ›¦œŠ5z׊[J [à ²'´®XÁ»0ÿš"¯@Í,†1a—.­àÑèw¶÷E¾X¡ÄÒÉò æ˜NXÀ!áz*kÒ0°Q°F»]FòyNA}£AªŸ†¸„jc‚@Á£
+I[vÜ’Œ(ÃVùu#8˜Ã •«O¯–ÖnÄEíÕÓ9êTþ=?æ{Nps?›ÉxŸh:ꡃU€k*Á¤¡ÊŒ¦`ÆêËR;½).—ŸhþÚ³›RÁÚT²ââ³4TrS„ ÿªÉè¶ÑÖç—÷‡“{By¹ ›1Õ¿U©¨€ «„n€1 ›Š—G-y†O¥_ÊJµÏåkZbO¸WBf?nM+räv¸$ðκéXÙU!–è7µ¾¬VªÃ›³úv089Mønð³ñÝŘ-ü;<7þ7w(Ž×‹‹{§C|MÈþ×ׄÑY?9ÇW ,?æ#p›øº÷7¡‚ñ¡endstream
+endobj
+557 0 obj
+1513
+endobj
+558 0 obj<</Type/Page/Parent 539 0 R/Contents 559 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+559 0 obj<</Length 560 0 R/Filter/FlateDecode>>stream
+x•WßoÓH~ï_1êË©õ%iš–RZtèhË5©mì5Y°½fwÝÿþ¾™]‡`¸“N)µ½óã›ï›™ýz0¦þé|B§3ÊëƒËåÁõò`”hvñ4›Òôâ¿'øï4•üú÷Oi<¥e‰ƒ³³³lFË‚p`4¢e~4ÎÆ£lšÑkgš`šOT:[Ó›Û—S°¤èyetèõó'ËÏ05¥ñ8š:™œÃÐÑÒRç5>lÙ€vÖ*ñ¤•©ÔªÒôhÞûzu²R^D^»G|)žuùFkëmmGSUÔh|÷¹­[ a­ÙýˆNƧلÝÂZ#kýäTÑ{œÆ‡Íî´i|P°†‡äsgÚ@tˆƒéaF÷ZÁ ^ò‡®Ëƒ± ~s¤ò •ÖQmÝÐw¡Ró¥˜&3àÎP¬50çÔ+ÏÐ-Þ/Þ’[$Ü 6…Õžê._SŒLÕœ CŸ#Z$ÞûÏüÖ?fô2
+KaÛâ”-û¯“ݾæ+MÔjìk`±Ú27—‰3d*[àïÐéܺ¢·t8 I  Ú ŠB‰0àljN5Ÿ4G²Ú„„Ò+²-T‚t‰/MÁΘ)‡…n¶àD¡ý!€éœ•ounJ£‹ŸüÖkÄØö›û2@šµ‚sYÐÈŽB/[¢Â”%8=Šv~Ì>xgšùfôV;F{B†ƒÀª^)Zi€¬Ñ+&´V(ŽC
+,;4gÛ¨`ðœÊ¼ ÕÃÑÓ¨UÐ2èZØÊ_›º­tÍAAŠ¨¥¯ÊÀ÷J‡.ßs‰ÑÄê îåùæ
+:¶,èPvUµ… *:g Qœ)$#1¼Änôõ*UþcÕ(ÁÔ“.…'€ÄáEbIײ×É‡Ó ¡+L>̦ÇTh´`å¢q0`‰at·xž¥Ñ%‰àrò]ÛZüž#^<±«qF à+Tg0Zë½a©!’A•|É:‰¼vúk§ý0mµ²(e4
+ ¡îÌ\éŒ_»zäÚÃïà ¨ *^ò79¤ “èeÇßs¡ÏZ:z¥ƒFÜà©àÇÌ?á|µeD,ŠTC,I ÐdͦÚH¹¤®{EH0€þkÕ¢N°¥’çæºÜEýN•cŠ™¬‘Π!sð‚$AOÍÀ{² ò샜ö…]'u€‘žÄ@Ð3åÑÌ$-€¾QÛŸ„þò
+‚—iФ¡².xU
+üÿ‚?­&¼qe3)Œ—½ AFìðĺ•Ä‰À^ûWÏб2IoFu1!Е…«ȱFݘ jØx
+ÛüúN·KDŽ/dì#ч#Ï+3¡ÀꞀIMbŽ½1£”:ˆzuè\ƒŽ‚a¼·N 0f-ˆô ä¯v4“n!ÐâH9Ýý9Tä²Hó?¯¨¾·´à
+=4êQ¢*¨Ö˜Ù[h&¶‡…£WÖØ
+endobj
+560 0 obj
+1764
+endobj
+561 0 obj<</Type/Page/Parent 539 0 R/Contents 562 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+562 0 obj<</Length 563 0 R/Filter/FlateDecode>>stream
+x“_OÛ0Åßû)ŽúT¤ÕKš6i‰4¦fo¼熘&vf»|û]'tƒJC(Še+÷ïïœüš¤HøIQ,åPÝ䢜|¾Ú ]¢¬ùK¾æM…D$I‚RÍR‘&"¸‘}¯Í~zrFväÏÊGN\"MÇÄù¢àÄÙug»G#„J×592ûc¬Ah·—ÒT{£ŸÀrñÌrGh­ÝA†!fz,NöÓØ<Á<ÍÄ"6µ}ÐÖ`K4Dûî^(kj6è塶©[/bö×rÂ3"Ï2^—ë‚׿Ž#O‘¬6›¡Í ”Bà;ßÖᲑNªÀ»-…pé½o©óŒ%"­uKRüÖ¡TŠ‘³QÇÂzÀÖánÖjf~#ÇÓ}ÂV ¬;²U XyÐÌà_-üÝÙúšV¶ëˆ¥ˆ²½!~­®†D?FÆñ"áFeëí ×I÷·ê ¥â8,‡ÚEEÆ‘@O²ë[òì¾K°îùµ>«lõ}Ö/ÎKóBD;³[_Ùv{~sqŽ[g¹&¾XµçƒŒ6‰Yó1í}“/׉ØðŸÁ>+^œócòp›ûendstream
+endobj
+563 0 obj
+452
+endobj
+564 0 obj<</Type/Page/Parent 539 0 R/Contents 565 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+565 0 obj<</Length 566 0 R/Filter/FlateDecode>>stream
+x¥V]sê6}çWì#™)66ÞhÚLïL“¹í¥s_ò"ljlɵdÿ¾gå0é¶sÃLléh÷œÝ³úkÑŸˆ1Í攣7£Ÿ7£i°\Òå_µÇ,[̃%%˾Ç1¾V’v¼/ÓÿÃòðéâ)mv@Ÿ/–´Éü{<IÇQ:YQÐ'íä¾Né==¡¯JgæÝ’–îÝTo–Þ•;ÜmþMi'
+8]|ßX,µQŒ‘‡OÔþÎM*ræ“úoÿÖ4ËÄþÊÚ£<`>Í—˜Q ÎVí·æ
+ùÀ#r©÷ý½¥¿ â8Mw.9/l)Q‹Ø *1Aw¦®èuœ¼ÞaÎ¥ª@æ¤köãE¥Àm ;¶g¨–AŠ×1‚,e¥Lözç‹™|q­Q›w%àd.=
+endobj
+566 0 obj
+1213
+endobj
+567 0 obj<</Type/Page/Parent 539 0 R/Contents 568 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+568 0 obj<</Length 569 0 R/Filter/FlateDecode>>stream
+xWÉrÛ8½û+ºr¥Ê¢Û’œ99[Uª&‰'Qj.¾@$("&
+ñ$Ihúx÷†D–Yé\BwΙT /3:*_‰ásò…„+•8ÑN’Ñø±/·ß/æ4]\%KŸT >Ü·'Jœ¹ ›”£OŸ ‘”Â+£]¡8Ä¥ÔìE¿WÙ¹ÙKeI®N Ω½®¤öndXÀ®°;åb6–2åR+ÙßPš´ðµ•ÑsTä`'œJ©”O² 6ºd¥¦ªj­Òè+yñ(JN^í”ÞŒrˆ‡ }U+ùnŸˆ˜uäm_š: ü¨%¢CÀ{©¥ w­¬„ÒŽrõ r„‚§‘Áƒ°^¥u)lƒ+<» qõ"“2[…0œÔNåÖTÈsKJh±—œY:Hë2õêI&#»^_
+f „sH¬€q“‚øt`yC=ð2V€ÐGZ>-B°Í›Ô”¤ªC’ˆBÈ,86¦fð•ýzÑ¢E%_°/
+¦!¸É×›Mù„HàÊyU 4'4hÂ
+ i¬‚p­’¾0ð‘b¾9úööž&ߘzo…{+*jO~xÉ€£09j+¡
+8‹)
+íbY£.Íc’ø?14]^Ý€–ÿMÐå|FísŠ^ýš¢œÞAÛæ4"A;A,jéú|(ãfB«$‚cÉðÏI~¾çÉk\àfxOyŽaRf }S˸{¦V&Æ”0X ¦™[b›¡‘ö¾Œ«Šm£—¥2CgnûÓéÊ` ¸è¼­S~/€v‡úc±¿e%X E7qj¤æ+Ú ÑåNé¬= ïo\aí²ª.½B?Œ¸·Ùœò«ø’„¤jÚAËÚvÁê««fº/¥À¨neÎC_(âýqé¸Òá®òÚâh¼ûH4ŽÒ…†Ö0k}Ý¿Qž)ߦQŠÅjðë)‹EO­¯w_ßñ˜ò¢\Òš‡‹Ð¶8¼iÜ5Û&VŽ‰À+¯7óä6*Ñ-_í¿/þ0WÈendstream
+endobj
+569 0 obj
+1684
+endobj
+570 0 obj<</Type/Page/Parent 539 0 R/Contents 571 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+571 0 obj<</Length 572 0 R/Filter/FlateDecode>>stream
+xWÛnã6}ÏW ܇zÑD¶¼Þ8»oIÛè^ŠèK€‚’h‹‰TIÊŽÿ¾gHÉV”¸ÛHli8sævføÏEJsü¦´ZÐÛkÊë‹»õÅïë‹yrsC§?v‹/sZ¦i² åÍ
+Ÿé
+Ÿ­¤ Á[è9þüìã{J—´Þ@ýõ >áýœÖùt‘,’eBoÖß/fÓNl:“>ŸiçöÊçe’½‰KJÓ¨çj±‚žéºTŽ6ª’!oMåÈ—’Dî[Q‘µ.gªÖ+£É »•Þ%´†L<æÊEU¨.Êî¤%“}—¹'×È\m ÀÇ Ç0æt•¾…Ã0¿1UeöîCD7§÷ .¥«Å»„ÝœR÷ó½î«BhŸ‰ö&ÆÏé {s/íNåøBÃ^oÔ¶µ`ð(9w¾{¾H“롽F ÌŇ)4Öðç”Ðmå¥Õ0·“$q%c)¨1¶ Ñ"Úw1#aeˆÎkžÆCGÛÑrp‘F^«B4´W:Sº8È•¢0ûÿ‰~kMÛœdŸ»:ŽKiœwa.²«ÐÇ2x‘£sáam/Êñ?cóÜ~´Ë!0Î/T¢®UAEÖùq ×9tZú½±G§8ÄG½gªC"™öx‚‚õpæL>k¼Éц]äŽ6ÎÈÛ&ÄøÇú],ÿ^ýs<³=?\q^ÇýºA€Zëä%I‘—d6LNR-óR
+´Mî ´1òàË„qLFXa1¾0;PD§¡<¸ôc &‘ò&À§LÔ ž0ü`3˜Æ!H·ÜÆ ¸Æ(íIyNê1Ç°1Ω®VŽÐ‡a}Ô  †“ äçS½ cñî%×feø42ÊÒ¿N¾Ò£ppΙŒÃH
+M°/È)3¨~éBGõj8¶ütP¸ý«L²áÐaY‹ëØM¿š¡ûÅl¸†¥/Ö°·I\0ëœiò=ïè ñz^˜òq/
+99îvL­­/#ÚôÚ—#WÂ\(R,l…0Jñ Ô)âä@E Ì,nYÌî¨ZNzŒ*ÏõÓ&w²"¼À[w+tŒàÈøÐNƒØr‘¡ áìqôÑ8–,Bd% p€ûq
+ò6Ò<ÜC"Ì‘eø†Ed§˜'ÁA!»qØÍBìx¯‘‘x- l³Ýçˆ3ó="ØÀâ%¢¿ÌÜt¬Ÿ^¯’׶4^Sîo?ßÝÒ7kÂýè7“‡9bÇȯ¢øÕjÛ]Ñßî^¿ü,WKè r霃¿þ¼ø&wÂendstream
+endobj
+572 0 obj
+1574
+endobj
+573 0 obj<</Type/Page/Parent 539 0 R/Contents 574 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+574 0 obj<</Length 575 0 R/Filter/FlateDecode>>stream
+x¥X]S7}çWÜÉéÔÆëP ´3@œÔS ›Ix‘we[aWÚHZ ÿ¾çJ«µ³™iši°¥ûqî¹çÞåËAF#üÏètLoN(¯.“ÅÁhxvF»»Æ/#úåô ¯Çg§xÍÆüŽ•´â+øvºœ?ú0¢·´XÁö l-Šðñˆù!µÿîµúÒHº–þbz3§kQI÷ëëÅçƒ 28Ç¥îlº3;¿ücz=¹>ŸMÞF¿Óo4—öIÚðMå’”#Ûh­ôšŒ¦½ã?bø þ(µ´*§™È7J#NÄG‡)\_^ÿ€Õq÷Jè™Ð)j‡àÿOÔŸnîþüxwsû.[rÌïM%ÒΓ k¶ðÐÆ8Ά'û~´¦©ÿê;7£¯  X¹VìN´|!Q–TÉj)­#³¢îæw€êνËò½D.öÖ”%[;b¦”f²Æš»ÿn³`›W&e›°!ÙÆT#S-}dÃt¦û‚•£Ç”eLùAFƒñÉpÌhO=¹iJ€#I”üFø€S¢Ræ¶PâˆT–ÌV1Ï G5*Š÷I,Í“Òbªó—¦'”;añ&ºÍ8¼MÞÐâòöhzK8é<Ê#¼2ÚÑvƒ’ŠßÀ/Á¼{A1+E¥4êj…7–¶
+e¥B"y¼.Óáì‘ôùÑÆ8ßÁغǕöÈûë9‹¥p>‘yLˆ¼ çL®ƒ²U~C@BEa¥sÃÄÜ“á1cyÏ«ÆKµQÚ3ÃòRXµRyH«õÏ!L6Ãz«søuÔ»²ÒJ•Js‰$qäVæÆŽ
+õ£Úš'UÈÖ|8•’“#ÿR3D+c«ì!ñÙœ>)] '´’Úî¬%ÜÒ¨S ~z܆¹`É%}àû=¯•x¡À)) Y é\“|U pÑ·ìˆoD 7¡äé}ÑVp8» Rf)é9íÇQI;$p{…„¢³j‚×Ö‘!—@a@Ñ öz P›ÁbÑ€Á<B˜Ÿ” Ñ á¼´F9þðšp•¤n* ®‚ÉÁ«Pêª
+tÝã+>En<¤o Ej‚Þ)ÑSáŽåÒ éÓFù$kÏw›€¶¸he æ´a€9Ž€T“ÁcêìJ„ÁòM -p"dýjkìãšGÀ+~¯b¹_ÁCP‚4`AFVcÓxÁt…´10Ù
+ŒœœZëЂ|Ĭz€!¡;a$°1¢óÆ* ‹ëeÌZîÊ}ŠBm9VV<
+4ΣæÉ‘1ÿãünB³¼$“¯CDuóM; ¢þ~•r‹PâœÇ9ÇÛY+óÛaŠðˆÞK­ƒ Ž § J/dêÐ3:ÚtñðFâALmm\„ éÆ–½ŸOîÂûIè”÷Ø~Iö
+Êêßp7~i”å<ÀX]Î&6ë•€XxÞòÖ”`ìÏž=ñÞ&0.jl?i8v¥J­Û<&
+hÆP²åKÏõ5 ‚ó#ª†b«¿ì1ºl—¸„‰£>(ßäï÷bÁºÏ@-â–Ä?òsXÈ0ºû—&èši¡rüz†–[ì%©0dP#S6a(W’AQ®Â´£y&[\„HF}VeKλv»¶
+endobj
+575 0 obj
+1999
+endobj
+576 0 obj<</Type/Page/Parent 539 0 R/Contents 577 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+577 0 obj<</Length 578 0 R/Filter/FlateDecode>>stream
+x•WïOã8ýÎ_1*Ž•hi»,¿´:©”rW ºÍÞj¥J'7q[‰ ÷×ß;i §À-H¥$¶gæÍ{3ã{=êâ·G§}úxBq¶wí¢½nç쌶Åÿt©ßÇÇñÙ)~:ïô©´àx‰c6X~t}L½E œ~rvJQâßw)Š„Nh‘–v%ñ·0¹•¤XÄ+yÈ_5‘Ð$œ“YîÈ’ÏñJè¥$A™´VàÛ“r+¬Ž2ìSšŸ¤)Í%Ùrþ·Œaã‡èï½.µ{ái”8•É¶)%2kÛ!%/hì~±¤E&IYRz×k`п*¤5ié”k©1eÌÙ2Ž¥LiŽS9ˆÚ™XèWƵq@ËæF'ŠV0†5ì/(­+„SzI SPiea©íÏTŽÝ„ø ;Y(ëTLfá­å…q&6i§²Õ?és <¹Ò7¥ód Ž§Ê­\"Mù™|™Ò0ŠªÓ&Ò]Ž¿L)„ìÓÁÆcì@žZzÅÞKšŠl.^…(”êQ¤R»p$6¿8 ›ìZÞ_O2p£×Ev§˜]5£Ž®Ï©‡h˜?ŸNC`[õ;Èiðäæö÷/ÓhJ •Jvh—xí>xÀ~ÏDDkä1!ç;XM":†Hõ»à´òy<º†D*2oè4¼˜Í¾'“h6›~ŸF£ÛýÙìê~üçè~:›¢áKo@ê„b£PÈ0]Æw4HÐ9ÆË]Jj0ÊAÉ+¨s¡
+˜3¬ÔþP…Çkã>ü\`Xf©Îµ·Âƒ'¢ò$yÎ\4…B*eòš]cP}+æ£h,¥êA^ÔŽœsÒzÔî
+l¤êgŸ†&_j¹r4;ˆg¨w~~F·*.Œ5 ‡×E^+Î8u›Í5
+Ë båÊm4zŒX@攬a³7¶3-„JíÏ‹d´*¾ N­ý]†µP–)a­‰ª‡ÝˆX@ksZ *ÊŒŒÕB…T³—ë ÷.()v–VæéÍ“çf7`Á%05Koü÷¨b`<—+ñˆG×:–úQFsÝáIÁÔ(7ºÍ™dé„7¡&¡n0$§C
+S©–°kz
+h Rž–“„6CákÕ3Ž—²ße|7©‘ðsnú„¹¼vH‰Ô¡]-WlÑÏ÷`K£ÿ<û@MO|…xÉK>ýQIt¡ŸgÊÔ'nÍÅ­µÿßzR‰sº[½¿næ+4ã˨YÒÄsÏó¸ 5<ø¶LÙV-Ÿr/
+ÆBલð È7¤ÅnÚÙ)}ŒÂ¶e ú:¶ç‚uÆ¢:Üè8gsc&·HÕ?ØTuŠ0Y#
+/=¿­yüOqéã‘°5)Ót
+Í¡»NÙ–õFL‘ HF'mu 屑 ]ŸU——ÞÉI§G'ç½Î ÏÖÓÁíå€î
+ãïËW&.¹Xø;!ïk÷NN±¼}ÚÇ¥=9xãÊu|zŒiݯêõy+îvìý Ì£Åîendstream
+endobj
+578 0 obj
+1741
+endobj
+579 0 obj<</Type/Page/Parent 539 0 R/Contents 580 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+580 0 obj<</Length 581 0 R/Filter/FlateDecode>>stream
+x•W]OÛH}çW\%›• $!å£o@Ân$HYânµ’¥jbÉ´öŒ;cù÷{îØqZïBiilïç¹çžü8Ò
+;Í/œ?¾Ð lŸÂVûÇ
+¢Õº´”$–©¤ÂÀ’ˆ©XIJ³•q…£Dá+£H:—”iºîS°RŽ¾Ë5á¿RÇÒþ|;ÐÑ‘ÂÃŽá0ÌD´RZ†¡[»Bfa•ÖJ]DFÖ¤Nx$í“‚ý0L…΄ækiÃ0Vd²O4\;„ Œv+a¥kõ©´ßÊGå
+‹p*ËÓ5‰8¦N^.Su8SŸ$ŽPb_ZÙo³ÚvµÔ½šþ1›%3Ýé|òõò6˜>Ì/ƒ)WéÙØØ‘HSóLY™*GA»³ùõíçÉ´Õ®+Ê…B9Ž z´¦Ì%â4’cíÓ¥^“Súq¯?¤t”–±l5ü¬Ò”"Q:´±{³ì·XÆï¯ÀÒHn}HÚè£Ü*] &ŠÐ$qïàLs2[Ê8FhP&ò§-×­&Ê¢9páþ°MŽw.‹«Ù§i ƒ-ý( *Ũ8äçšJ. l5†ƒ­nõ¢O>—‘J€ZÉzi‰2׿NêýU
+{bž|À$HÓ E«=BÈ$9Z#_
+©=Ø?¶åÑvŸ†ƒQÿø¿g~Ä-&Ðl¦º÷SêN>Ý}Ô²
+
+ÃÉÃìïéÃ" §çÿm0=?ÍÄú.Îîé2Ž!Ä0^•|"Üb͸YÍ™(¢Õv6j×¹À^ïÓ¬™lld²\WØൣ&-y©#‡Ä
+lÈ2*Jn¯ÞÉ÷b™£1~áì
+‹Ç7¸¾?žÝoZY»•úIY£¸Œä’¨G˜Œk9»©0<„ú\Ó³¨B’?JEÀ/Vë™>kõr|«tùBûîË":öºy¿›½Ÿ@3\@,ÿ7h†g§?AfܧÉ|A·~äö@ï@&¹XªT^¦oóån«6.Êœ RlÔª€šyyE‰ˆ¼5´.!©y²btþu™A@†õL%Ðv:éPG‰)&.¥„`€#G
+šG ßcùy¥@+ÊUý\y›5=Õð•ç¹‰Ñúu{›¯ û†Îƒf¦í98P&ñ}ƒ!H´\Z샨£°
+²ôyòMÍ‘ðwŸŽ—ªÇ5uWŠÈ3*Òå,]¹ü&#!¨J†yE›ü>óUõ-¤nN¢?÷*ÏŒ+}¼õœïhÆÅaÍ'<‘·w· ·Pã2úÎXGïÐq–¼;…8¯¥³Ø”à•KàýU9xøV•¾ãÙ¨”´² …—a|Ï,yÁÝël—Ooc=ÜÚìzbAcM™ió:ŠÅeÞ¥ß-ì{^óÞðô¬Ï߬ñ¥wçÛïâòîê’î­ñ]™˜¨dnðXçôª·Žª×z¿dëñÙ3Ìf{Ã~ ᯃ§Ç•Ìendstream
+endobj
+581 0 obj
+1654
+endobj
+582 0 obj<</Type/Page/Parent 539 0 R/Contents 583 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+583 0 obj<</Length 584 0 R/Filter/FlateDecode>>stream
+xWËnÛ8Ýç+.ºrD¶\ÇN t‘ôhÓ ìA1@6´DGlhR©8þû9—¤YMÁ4¨a‹ä}žs.õë$§ þrZLéÍœŠíÉÕêäÓêd’]\ÐóGs:ÏgÙŒf |ŸN³ j$m°+‹9~Æ•|Ša¶°‡~KùŒVø_àKÖ'´*FÓìMvžÑë›%}µö¡­_¯~žŒ?Ï(Ï㉳é'F—qÏÝè‡2¥Ý9º6^6Fzº[IKÙ<Êæî59|Q…$åÈW’ä¯V=
+i<ÙMx@ͦÈ'“|Œ)¹Zj£dI7W7Kv=¡³üM6e—w£鯮¿/]d”baW²!çm#ë±8¦¤ë[e‰‡¾ž*ÔÈ{å7®÷$(%3p\hÅ“Š!¯>ÜŽaÎIßÖT Gk) Ý«G|®–Â!=#c…b%ØÿeôŸ%ëÓ9Z‰´V–
+k6ê¾E@K±] ò69nCJ‹«·±ZÛ2÷T‹©!r2R–œm<R–Hßywì°:7rÛuÆŽâ㮡#Ú(-ßu{ßr“s:›žÇà(ýƒSG®­kÛxzOÿHwlæŒÏÌcŸ^N¨uÿ1#ô …y!eB.]ðÿ+ÚËÁ2’@(.ùqV6ïééé)ëýÿs‚»
+ˆIåvåíd+ǧGþŸaHzMÐäŸÐlñö™ê=>÷Ù;›gs$Ôçï,£/vGë¤d¤lZSxeÑ>¦A…%À£”µ¶{PE¬5Ú‚~$MÉ¿»b±  XKm°zœ*›Dñ£mbmå)}[v”¢­(*e@¾ŽsÜWÕPÇéHUº)ù.´< ^
+ÿýñv0(Jxõ­¸+
+eÉF?¤|ÚBC®Ö˜G§Ô Ù§®<0
+*©!þ!ÖMdÈõÐûald˜q0
+l8åÛ
+$„*†ˆ1:²ÞZ/û C²;Û<€B‘©ŒíWi›0ÆBä«çÉq÷zØß¡›Çc'UëôeøÒN¡›,íèˆf·‰æÀòòL¦8 yÆŠd´ä¢Ö¢xÞQ! —¦±-W ˆ“¯Zñ`ñe#ñò
+zJë–™éÂM×\ÆbâQ(-ÖJ3ðL›R0HõùaŸ˜¤xñxàë~÷¾1î d§»ú_šýáîæ J7ˆ5ãáw‘ÆǨíºÐ0§
+žª\Kù='Ûð;I!8mĵ«ƒ*(Aø…€öÒs×’eWáæ«€MÉP‡ÞðJ‚—º(ªãÏéœÏYNóyß–—ß®.鶱<Ìè£-Ú-Øòä`Îâö³ÅožåÞ<g‹n¡aC>ãS¸ÿuò/9šë©endstream
+endobj
+584 0 obj
+1693
+endobj
+585 0 obj<</Type/Page/Parent 539 0 R/Contents 586 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 27 0 R>>endobj
+586 0 obj<</Length 587 0 R/Filter/FlateDecode>>stream
+x¥XÛnãF}÷WæI,Ú”us€}¯g’Æž$V0»À¼´È¦Ô1ÉVºIy”¯Ï©ê&E3Ùd± ‚l6ëzΩjÿz‘Ò5~RZÍèfIYuq·¹x·¹¸NÖk:¸~¹Æ!|Ì×+|ÎfÉšœ¦‚_À3Xé?púêýœÒ”6Œ/×+Úäòüš6ÙäIU[E¾=¬k<)*´jZØjöª!U–öÅSa]¦sò§:ÛÛÚxÕ[Ù‚¶Ï5•ÆóË™³Þ“³mƒÓµn^¬{öÔzSï`O³ùå⚦éM2C “7NW¶ÑÔaóoè œªt£™š_"_m“ÌÖ¦Ô möÆS¦Z¯=…ੱ„Êy¡´™*©Rž„
+³cˆC¡»ô–ð òz­«’dêFï
+äÌÖú’¿f¥VŽýÐo0""GÞT‡ÁD‚&ôaH§Ui~Óù(Ó +šôôpG ˜Æf–6ð ²?ÔÀÁn~ÖIR$<ÿP*ÖCáë®nÀàìÈûDé”õa” •k¼ Š;µL€›|ò…=[ï t
+HÑá·F-S°\³Í"¼ÊÉ?þüñ#óÀaÀiˆê%ä >X+)ëbI[üíþÝ=ëja»Ò“¹zS©Á¬]‹:ª²Åd•’µ%ôxG)ìqô¢²Üª~Põ.n‡¡¾¾A­â2’òFòÓwéõž™³ŽT(Ñm²Š¿•ôÄûËp[¹™sg†2öoÛvÃÊé‚ùb¥ëœ!ü íÁúí:Y¾¶~^Œ$ lG]@cO?t"ð.-
+ÜÙ€|ƒ 7"7àñûOŸ7Ÿ0i \aèð ª,(”ëF™ÒCÏ%jS×Z”u¢è1È›«Rl\WÚ”Þ. 'z
+’MÆr’=Sz9Tx¸õ"î7É×
+¡Þ¡ q/ª_'PÊY(Àu¬b¯ÝÄÙ«#ÀËA`¹³‡üÓÚ
+ü“9 qâ ΋®™˜^Sejì¶h_?ã¼ ñ&$úÉdõSM£«æ•ëÈOØXž;,Ž¼·Ö#¯ÕTâcÁ<<ºÙ1ª«¯®%'zÙ›, ñ ÄÅÊÀ`µU[,µ{›9 d*ãß3{À>Ô·«ó¸¶’áƒáµË C
+qÆnœÑÁx¹äÐ)®7Îuå‚Š[îA粟q£,ûX‚ŽVZa_‘z½°úrœÞat'ÆfÀE¡ ×ê©®‘ºô†]Fjç
+endobj
+587 0 obj
+2036
+endobj
+588 0 obj<</Type/Page/Parent 539 0 R/Contents 589 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+589 0 obj<</Length 590 0 R/Filter/FlateDecode>>stream
+x½WMoÛ8½çW |r‹F±ÇNÈ¡Ý6ØštÝ´DÙLDQ%©8þ÷û†”äXMŶ-RÙ"çãÍ›7“G)Mð7¥Å”Nç”é£Ë£OË£Ir~Nûv8vzšÌiv¾Àól–ÌÈJ*pŸ¦i2mß„Cá lá%ô?`èäjJiJË~çç Zæáý„–Ù¸qÒVBK*å“,ß,ŽN®fíé1ÕÂâ—–”#+¬,w„sURæ2Oøü„Ž§sD¶Ìǘ-ÞÚw¸çÜÖØœLEwןÿ"·s^jG¦ð¸­Å£$xÆGÒêYæ” |Ê6p—Á›Kˆ–¸ÔRTŽüFxRÁ ")Œmݦ§@
+Ö—.ÑV®@+kŒU¬h&umÍ|£«`ƒí±óåE/;¶F]¬Éð!j´ ²7¢]ŽPZûSÏe&—¯5¦FuìAô‹ÞÐ8äï€ÿÜsH À ÂSl®hV
+g0³â” ÚYËùÎ
+¯è(öÔǵ5M Áq¿@¼ôó•[}÷´ÝwIo!(-s$*‹¤ÑÛ†íºÑíz:Efg‚︰®2câ"cãÉì-æhƒî¬áâ ¬s d¸8ÒvÈšóÞ²U îå®—ÃîùübùŽ<Ço<Ca•ñ ¦#©Z<ø„àôÁÀ8{~IêŸùÅKˆNŠ.DL„H"×ÎÚóv'Nç‹$¥ùü4ÜÛ÷_>¼§¯Öýûh²
+endobj
+590 0 obj
+1525
+endobj
+591 0 obj<</Type/Page/Parent 539 0 R/Contents 592 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 32 0 R>>endobj
+592 0 obj<</Length 593 0 R/Filter/FlateDecode>>stream
+xVïoÛ6ýî¿âÐ|ñ€Z²äŸí–I“t»›C7 ´DÛl%Ñi;þï÷Ž”,ÇHV` àXy¼{÷Þ;~oEÔÅoD£˜zCJòÖõ¼u;ouƒñ˜šr…‡.ûAŸú㾇ø(%-±´KñÉ›¨‡}þbá-8~ Pxק(¢ù’ŽG4OÝ‚.Í“ö´ »–t?£ÏªHõÞÐdN©Î…*(Ñ…-u–É’¶F+rKg²Üá?÷¢+üiJ‚r‘¬U!I$‰Þ––ºäÅ?Í¿¶ºÔ‰zAŒSÛ3‘/ ~Þ%UnŠ¨þGÕû:w~݉‡À&òѾ&ísÿ¨Ší#™ƒ±2'ù(“­•o«Ýƒ*z›L¾Øcö)uJútóîŸÉÕý-u¾ÒÍôþêÃÄ=>“@JÛϤӉǨé˜Ðƒ‘¤—(YÊuêÄV%Â*¤šjiÐ¥ï[….â jZH|ÆŠ"eJ…z<àgôC—)¾X}†*ªR«Q¶*&‰‹~ ²‡H¼oÒ‘)-®™¥Ìµ•ÇÞß¼ ˆæ\DÝÈDØ~vâ"ÓÉ7Aþ›RîP$ez¥ œt Ò\¢cç ­’La[”Š•!³Mք쌴–Ù…õªØ‰ U˜µÌ2.¹âPxÉ8
+Ÿ°)”6 }O}ãjª´ '•‡€ÿë¤U+"bYüñ¾Õï ƒ74ŽÐÂœú£XåŸ2š± »xäþž*å
+fV–Ú¹s½óÀsên £Qkˆ;f˜Ÿ‚È“>—ù¨xî
+' ç%<TÍM¢Ã=:‡l'“ú(Ôa¢Á÷ºüvÚSURB±¼”NpsCHÜ%î¯Yµþê7u¶Õ•âdÂLæaÜ…Á×—/ȆÔÆ–ÛIJ9ÌÝ NO .ÆXxÑàªéw=ÓÏ .
+èMŸÓk`:Qà•+é8WSåâ€9 w
+Akô‡RÜ«Ëf ÞfÔÐ{…ÎyAO,)Äx†ÚMö°Á%ÄÏ©G&2e T¼š¿•c9PxæžË»æã…+†¯~C!æS¸fM”B®"|ŲQé+êäT¯;£6 Ã_Ë~°ŽèÓW7^ 7|K¿lö¿VAk-4ù\÷ÄRx9´¿=.ãgn¬Ž®|¥çÛbÃŒÙÕýõ}*õW´”nt²…È­» rÞ¿«ã·µÿß ìúÈÍÝR£GEÊ¿·þj¥µendstream
+endobj
+593 0 obj
+1424
+endobj
+594 0 obj<</Type/Page/Parent 539 0 R/Contents 595 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+595 0 obj<</Length 596 0 R/Filter/FlateDecode>>stream
+x•Tßo›0~Ï_qêöÐIÃByLÛU{é-H}©49Æ$nÁN±IÖÿ~w’(ê4 $ØwßÝ÷Ýç·Qc¼#˜Å0IAÔ£«|ô-Y–ÁñѬñc ÓyÆH²¾O&,…FBI¸ˆiÜÞÎ!Š /1{šÍ /ºõ1äâ2fS6a1ƒ»%<)]˜½…ûî¸Ø(-a!„iµ³_ò—Qx›ÒqŠèyq™o¤•À¼‘o­jdFWï°ßH K^¯8( ­Åÿ܇ÂÔ\i
+endobj
+596 0 obj
+736
+endobj
+597 0 obj<</Type/Page/Parent 539 0 R/Contents 598 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+598 0 obj<</Length 599 0 R/Filter/FlateDecode>>stream
+xW[oÛ6~ϯ8@6ÌùçÒ{h»õi:Ä{ Ñmq•H—¤â¸¿~ß!EKV4,›
+(5ÅsûÎw¿Íi†sº]ÐÕ åõÙ‡ÕÙ¯«³YvwGÝËnñcF7 ¼–w·xÏ—ó솬¤ öÎh±¼ÊéÓõ"[ÆOP†¯°p|AÓôÓ[ZÌhµá›Û;Zá;VòÉÇRì¼´t•ÑG£7jÛX¥·ôåýgÚK…rÞªuãeAx¿Yýu6£ËÅ:&¹ÔÞŠª:ÕB‹-¶ˆÆ—XU¹ðÊhÞͶçØζ/¯æð’WÙ<£{Q¯ ]°±¸uIóy»uqËß“nê5Ü3úC«grçeíèa"·ïè¾Ñto*a•{xsAÂÑ^Vÿ…DÏx>ÜÿBQ+xɦ~Sºy¾ möÔxU©ï’·¶aÍRXýR5Û­XW’ÞŸÄCôÙM%Ù<|~xÍ9”øyC;kžT! ˆ p¸ °`¬úp žXéLcó¡íÜ
+˜fíÒâÌÌCÙ…(
+LP-óRhåꈊôÐ2÷àHT‚«‹‹6ÖðvI.¤­¨æÝÓ"òÏŽšJo¬@̓a•`<RŽ`7ôÔ¸TÐB–Ö4Û’ŒFKRUàñôSb Š=USË:cò#¼`Z¯~ <_HÊsRºP¨¨FTÁ@KŠU ®(ݦ'™MD­³a††H¯€ÐÆT•ÙS@[“|õUÑ9£È›XÛŒEF´*ZRX
+´FÞì¸l­¥ äè¡ÔèÜÔ5z'‡å8Ÿkt :•GA‡fÄ}Myr^ä_·Ü›f°¢NôëÐ}bH ;Ú‡Û4vqX¡c e ØÀT a±M–ÈèW縉‡ÖÎn÷¬ä€i-ùX`—
+â|µŽ3ŽPV“i<"ÏåÎæPÜ™ST{¡ïDý¸Ûë̵{ŽôIcR½åSaŽƒç:ÖÉùàåå<›¥`prrýœw8›Û%%´ŽöÏîO©ÅU ~syPïiÛB{ÊPzhCààZ^#®Mðè¥ðy87’%J-öÄv<5»—ÜC-õü®…ª^J¾Æå6_ä@mœ¥uq=€ ®ç¹i´oÍØœò8–ÃðyUËó'rãA÷èÒÃÚ½|¦g,Uã’ç C_v ¬
+myzéðùñ<†ÇÌæE[)æ8²èíáç«`éL~…óÔ»Óø’Kä¦bиQyfïÂ@€sØÊ]%òÐJê8Çd(ÃÓˆ>
+endobj
+599 0 obj
+1567
+endobj
+600 0 obj<</Type/Page/Parent 539 0 R/Contents 601 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 35 0 R>>endobj
+601 0 obj<</Length 602 0 R/Filter/FlateDecode>>stream
+xÕXÛnÛF}÷W PQ
+K£v¢’aãÍÞ©ê9sy*¡gD(«¨òäeÒ†9•+ŽWƒøiÍËR±*¶¤ IÊA0T^f2—ˆf¥p.ʃ® ý^¨ÇðgUÔd¶’9ÇKžÙò|*s×™$„¶4z§bws &¥;i,T왳`ÊŽgˆ« è}E‘(h#)Òy©2/–2RÉcŒø-Ž÷Hà¸gœ?ÑL—쮚dA¦.
+å öÊú³mÖ{9èµ­J³‘QeÝÁð BÚÉÜÇ´ ÿ©Ø~ Åù°]’•Ò¹ë¨îRDÀçSi=#-²Éðßced¨H'N~Sbþ&ÅÊVFmjPЪ¹æJžÒx¶æ\Cß}ÿáæ~< &|€µ£¿¸ÏJð éòÁjp…Ì9pqºþÌôV¯àŸÙ©È¹Ò1)ê*¥Þ‘_jx·õ<E7¡BÇ2‡¡(ÒuQµwÐì¾AZ#öŸ i›R+åå–t}eÌ™XúnÆU™è,Ó{†0J#üLÚ¢©TTgÂWx,Qg¨:æáz·âmK?6SŽ~¹7çü_ÂŽk¼ß€“8‡™Ú„VFµQÕÁÕJã5Bù¹EÙTÄzO¢F,ž†Ô e;)­è´¶^(íë@ïÁë…róxá“Ü6É>ÈÞû ÒáL>
+¾=¡»ºÀ`E£FCÍEŒGš‡¸;AÇ×Í[¹ÃA7˜ê*"—Ö6&Í æÊÇdR‘ë!=Ô ÌZ…¨é,&‘¡ì1 œV–Èàâ
+`ôÖˆœDÓÞÆÓÚâ
+†Tv†¶DA9éQ*Š-ºNmÛ©Ó¨huü¿ðÞ8ú¢ŽùB ý·à}î £§ÒCð§Oƒÿ]É·®¥:Ô0OÑgFæç)F)—ŒesðKP´cÏRctl¸`´ƒæ)AØ0—•CžÊÇÛyÃ¥ªÔèz‹AŒóB>Ví3Ï Üigb@2ÉœÙÈl¶¹qÊ&P/ƒpô¯7#<ý£¯ÅXÂîÌBüVÇ4Ù"ÏÍPÒ n¥Ø¨ S\±b7œÊÍ“i‘ÅN]0ÉA™ë\6ƒ‰•™W-*½å’Î}Ÿµ–«yRÅÙ9GmªTT¾ü]8?HgSú-ïs» î
+º!Ž{…H)2õè•Ñ9üj#Î çmd£Š†à'ý蔓ž*]ží+ nŸm<¶üåv·éÕŒ±‡"â§>lÍþ J>¡ß~º˜_×´˜#|9M“àÿ'£þV £’ ô+Z,Œ.–ôqÄ«Ëîvz'‹ý(­ªòm:õÛ6Ûðô´»Ç§?¾ö±<\’èM›LÙ” ۵ж’²àTLÙËn ñÕÀ‹Çª[áA, h›_ï;Ná
+‚×Å–àœ[9÷”GrûÖ7X&öàj8ÚH‚(ˬ!ÍWαNµ0†‰€3Þ­¦©Ø1Ýh95œ(QÃpMÄ;ܱnw…*p®B æFè‰Ýw7Q¥ é¶ÝÎXoxwÕ,µÓå
+{ñòzê÷¯‡›ûw7ôÁèOXå趿 ò½±?>^Íð…K<zAqÌWslpîôÌ-u@Õ¯©®*endstream
+endobj
+602 0 obj
+1701
+endobj
+603 0 obj<</Type/Page/Parent 539 0 R/Contents 604 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 40 0 R>>endobj
+604 0 obj<</Length 605 0 R/Filter/FlateDecode>>stream
+xUÁnã6¼û+Þ­°b$Ù–=8ÍîžRlk{É…–(‹[ŠtI*^ÿý)9¼Z1DÓä̼7óôï,£­sZTu³ÇrvÿiIYFeƒb³¦²¦”¥iJe5ß û*+A/óíÓî厤&g¨á–¸#²¢î+/&ÓÐIÖ‚¸œ´ð'cÿ!ÞûVh/+ã-oY±»òÛìc9ë‚å´Ü¬ñœãß
+jJ”-GJËœáqBjÁŒ¾lŸé£yèípàÖíY…/¯ -”…¿?ϲ"
+÷U8‹X‹†÷ÊÓ^´üU{ƒ
+ÝPÛ»Aj(g¥’ãÅw› £Õ9ÂâɃ6(×øj¤„Ã?bô§ñ(iË}€F¦òu(øj±ÂgG‹,eëq5Ú;Å2$`§¡S\ø™À]lOà|bØ=8¥â…иS$஫EÀ®±[lÞ8ÆÝÉ»›A¸ž}7™·J`­Êž¶p#¨vô;Åd#Ë¡Ñ¡]c%“àÍîaÖt¦î•€•¹º87£ ¹×q
+endobj
+605 0 obj
+822
+endobj
+606 0 obj<</Type/Page/Parent 539 0 R/Contents 607 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 47 0 R>>endobj
+607 0 obj<</Length 608 0 R/Filter/FlateDecode>>stream
+x¥WÛnÛF}÷W Ї*€D‹º;@
+ØIÕä!(Z«ŠªKr%nBrU.)Eß3C.))M‹ à˜ÜÙ¹ž93üë.¤1þ…´œÐtAq~÷´¹ûqs7V+ê•{<Œi2›3š­–øûa…?KM;¾C¨é~Aü~ý@“1mvоX®h“È9Þăש:Tº¤Y@o­«L±'EïM\Zgw½1®*MTW:¡µÉô‹ÍÇ»1&3(<Ÿ]¥sªJ­Éô¬òH±
+ó™(Wqj
+MÛç#uRHTœø
+†gLA׆»šzPôa{¯¯kŠØe¢ç0Šûµ§‹q§çš©Ë4ÍÖ$ü)|2pypøµ¸ àz‚lÁÝù’³&OmžzÝÈØbŠãËœ1uô»­ œcö…ª8i.e)&!^‰–m$•nN)ÓG}‘½ àÎj†^¹r§þËìMÑË­“$©7­]þ5=vÞó506«ïÑså™Y­ÁžÊÉ­ÌŸœ/Ó¡;ç‘ÍLLÍ©pêÁš¢"n¶–×…®!.ýYå‡LÝâxoüJ“@ï~Ý•˜>Ö…Ì’ÑùË–+ÃíVr²²¾®vó¢2}`àvÔLÀ³…ôz}Ó{Šþê‚ZéDU˜ƒ‡ŠƒS1ø¿ÑäµH†¬üLŒ—R7–Á|ƒz’÷C\%¨6·ã)Ñ i‹ŸÛX·/¼·ž09žÍ2Ž„“ˆ‡QCE˜F‘x*,U±ç‰ÒŒ½¦Hxd=ÌÙÏÉx<¾5ñV—ú{©àc© T¿%úÐö…_T‹Ð 3(ãr>ðb«`òÓGÎIÛÀ2¶_z\`b‘?Vúóæ5µ?˜»‘±Ž
+P½¢çÇ÷O_•ÁÑ4AôÜmî6•ìÜ×ìXýÝcÙ²º‡$sÀW,õÝÙÛéÑ9B¦²½køìFi·³œé„äh0Í°nŒú>³tÝ\~ñk;Ö÷ïqíle¯¿kÛ+ô 'ÿØ7ÜÇh.R¼‰åýHs›Ðr>ÿîd\C‘ž(¥‘˜Ä%…íöê æ¿t¥Q ýÔ)6ݽQ¹Ÿbx´¸ÔÖYâk˼pÐeno}ÍÞŠ„b3M *u—%®HL¶÷žÆd¹:æÅ[­-²³‡f»ívà TÔ,½¼Ä¥Æ|bÔe°$‹ebvg1Ø Xˆ“#s–
+ ¡ÆèšO¤ïœKØæÆ2va]2›hv,v™ÉM³‚JðÑõœ“ª#,þ® u´&Ÿ%H°GÏ
+°gå‘ÁD–,áÒ½pE ó¦%›U nd~Ú²Í7~ùoOjâ7[ÎÀMø¨J“ ¿ÀÖñËÝßgc!uendstream
+endobj
+608 0 obj
+1534
+endobj
+609 0 obj<</Type/Page/Parent 539 0 R/Contents 610 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+610 0 obj<</Length 611 0 R/Filter/FlateDecode>>stream
+xuTËnÛ0¼û+æVˆUKvý8&MskÑ¢.zñ…&鈉Eª$eAß¡$'¨‘Z0 ˆ\ÎÎcùg’cÎ'ǺÀbYMîw“Kä9vG®¬6kìæÙ|>ÇNN§S‡ #š±Ô]up'#q2ö% :ÔÎؘ^Ò2¬Ž­ó/¥ð: s Zaã-„UQøˆŸ¢:ˆìf÷<™cV¬²%1§¿‚öÎâáf¢e1äÉh¤°°®ÅÁ»6膛½&+n&ûôgí!"öü…„³ß«cÈp'¥ÁØ' èù"+z"#à|¿xÀ~Ú–F–u­Ï PÆk7ä4RÚÛß
+qáúªÅ˜íåvËD¿—mZÙßFùj¥›*Iùv#ý¼ûz‡ïÞ=sñàdSÑM‘¬K\gCÕl(›^ÏÂr½dzsŠEÚÏn~Lþ©pendstream
+endobj
+611 0 obj
+687
+endobj
+612 0 obj<</Type/Page/Parent 539 0 R/Contents 613 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 50 0 R>>endobj
+613 0 obj<</Length 614 0 R/Filter/FlateDecode>>stream
+x•XMoÛF½ûW rb
+Ñr®eÿªÅ?ÆÇLy½íJ²÷e®ª½Cç4‰X5r[¹–"®i)Ô|g-Çàì)GëÛçÑ´¦,Émônñ‰Û±5¥¦C§`¡Ô\I„§z»¤òÊX Á«UÍ”åBIZ·'Œ:ÍùÓ×'‹õ,]ÓòêºZÑâjÎû«’î»3\^I˘ýh{o¡« Qµqh™ë­êÊ–žUÙé˜>ÕÊ«J3Ð9O„2vUÑÅâ"½9_ãîêj2†uœ‰¢ó»E˜Ó4l²¨SVRÓÕµó­|0#¥3Ì ª¡Ö–„+:§-Z̯ßâ‚ø³àl€ßV•ì
+É*²ÐµVm  .ˆ5§1ÒÁÖÕŒ&ÿp™dx?Rôó»¦)ÝH]¤,ˆ\¬ƒÚ{ׂëF3Å=þ‡ž5§SÓ_cä'É‹GéºË +ø‹YO&!ÞYí›ÂÔ“‡_–üE?â&ÂNËQž@£X{ U¯êIÓ5xô£Ó  G5Àˆâ[”ˆÅ¿ÐeŽÎ…Ñ`&qœ£n¨ºÖÊ“ Ã
+~Þ
+2䧦$àîq‹ÐP
+{¶ílÆÂ¥ÊIúBüHbQ‘@#¼ØšJcþ7Ζ{â(x²ŒŠÿÐöËÈÑëá¼Gíä¶`iñÈ’íõ¥¢c„ÄÆ9ûƒÒ3ÀíXN˜‹«ÿÓÅj9—éÅaÕ
+zö:|ñâ…]àµtß ð
+1p6¦=’™6²é²d»Ìá]áÈíl¨ô$ÓJ󹕀 îh?)ÅÈÌGmúE»ZE¿÷ƒóè¦7÷·_ÿ¸ýúø(PzL~cub;o'±^‚LcP›qˆ'ÁÐ4_F ãQ·ï?~¾˃½D;Ÿµr3˜ãx~bLB•\£šË¶&_£hüÖˆÊC ¹³²¹M#?Êú'>sÝdÞÔa¥myFÉWì¨ü™sì+Fp¼ÅðËû­zÓ‡ÛckXŠú>…­^5ÍÎùœr5ÇæýøöHåcÑbÝ”B8¹ŸÐà¤#ìyèC Tà€AâŽ÷½Ãn–¼ÜÁÆ,†Y¬«ÌÆC\³’×÷ª8Þ$ p.èTè×
+endobj
+614 0 obj
+1797
+endobj
+615 0 obj<</Type/Page/Parent 539 0 R/Contents 616 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+616 0 obj<</Length 617 0 R/Filter/FlateDecode>>stream
+x•XÁrÛ6½û+vx3£Ð’lËN/Û±;î$N«I¾@$h¡& €,«_ß·
+ÚhóŒOnE¢\
+ÂöŒDQè Z[iÂâeVªJYg„Ó†j£^T!Ÿä›ÅßGz;=If¸<NuUÉÔÉŒÈi|?9K&É)᨜&,­¯§+Q=IÄ" ±IcWª&å8Û’®h©— B§¢@·aik,I›ÁíF–ÚI*õºâü~ìj¢È³Lh±$ŒÊ‹P…X’#ª…q|3‡Â‡ßÎ\ã™jÙü¶E;fD­L×F¹-aݳ¥ ~rQoýŽJ”[º,
+e‘§È7tR”ãN8¹Ñ¥_.…ªš=¹«É*'>øfq„"ÓüdžÌéôâŸ0¡ØyàÄ;šž6œ˜Ì’‹+Î’Ó„¾*¹QÕ““Ê”AÕ4R¨¥)•µJW6àÐfŒ"Ϙ_L+D§LF˵sÈXîa;ka‹>ïOŠúGÅÍ7º.TúÌàœiiið“¥u¢gJú xÅØjA`ì`Fð…ˆ;{sHÞßý˜ÕÖ–‰ÕK8!¢¡g’)[b ö
+½¾Òü­NK£3C;ðê0ˆ¼—õî̤MªZ "\s•ÉÊ©|ËŸéÁ
+€C~¶@~»B1ývs 0r%‹¬­¬O¡ÖBÏ2Ê„KaQß1ìïB“£á€ƒ ’©‰´ »®kmÜw²±ÒkWX{õsQXOɽ"ÇœUC"O;–¸ ¹´
+^¡=œ;Ôd_°ÍZ]n []É©â×».éÞó£Û5ÔþZWÎè"²@Ý
+Øö"Sy«œ¯iDÚÐꇒvLVÓÝW…’#
+Np#PPF¡sÉ ¨¶o¿\ëºrwòî-÷s¹;9{IìA–»iB·|uG‘úuezì´Í:P\€C»¦8~2z]ƒX ¸[óÌ
+½ôCš<\áïP¹er¿ñýΦƒ­²ç¬0,ýPî]Ýì,‡ùè:Ñ6zÏ8ìâè¨Yï¬áЉÁ(õ#;ÙΘŒŽÇú»_ veWü7™1¸CßKMNÝ´!kƒrõ"ï ÀHí¨êcòyü’éPmÃÖýY01 J¦«‘cº@nÙ—Á$"?¦ 5LaÃl£•mQãÀöƒBŒ‚Ï;.”p°5Ê¡Qƒ¼´W¬Á5Ì„¸¶k?,…}Vv§€µ‘¹z Å{x:äAÑÊ»A—i*­=ˆ´ñÀ£(ÏÍ!ÄWkXjv*+nbLMf×½à«t/Fo²™ïLfá=¨J×…h˜í硯%;ÏóhJ+¯t[i2 6ÖúF¼ÄSA9nRCÓ"ðX6ö_cÒZ
+)Œwž
+¢!–èÔ0ð{6­É¯½À3èøö¢1ªÓùy2ÅŸ
+ØKáùòpùñê’>ý7ƽ×éš †pà&‡ò6l{>Ã_²øÿ½OÏOñöô_œñix·þqô©B6¦endstream
+endobj
+617 0 obj
+1783
+endobj
+618 0 obj<</Type/Page/Parent 539 0 R/Contents 619 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+619 0 obj<</Length 620 0 R/Filter/FlateDecode>>stream
+x•WÁrÛ6½û+vtRfÙRlÉéÍ©›i&Ý6ê´_ ”“¦õ÷}»€$
+r:ÓñØÖˆÀâí¾·ËïgSºÄÏ”3z7§¬:û°<»øxEÓ)- <™ß,h™Óåäòò’–Ùx¹ÑäufëÿZ²åÆ鬵nKv•ñÞØÚÓFyª-9­Jª´ªM½&25µØÿ×ý§Ž÷Ö•9)ÄtºqÚëºõo–ßÎ.éíôÝd
+SjÊ
+Ò(§* ”±ïf»¾«!Ƭ$ß5umZ9V!ŒáØ‹Xɸ
+¯+mï»8_~|¯Tö$ß¿ryÙ:ƒbxãF¡ß¸q˜Gଙ*97ª"³Uck$™ªèÖ‡'ú£jä¼GntN£~$ý7zÑÊ´x\pCF¸sAd|ØáÀæ}—ÁïÒit§Kø5¢‰íáôƒÇwÏ;ˆ'lGJpG™umžˆÖ@‘È’’㨣n¿4ÿ9\ºewª›Õàbçœã¬ÈË9Óáj8]Ðßñ<‰{Uå†öè-¨TBA® Õ•¸†"h¹ìp3`¾ór—J`Xõ~ÈeˈÄÙ{¶r¦½W0*þPu°å®Î6šÕì©HÿÔ˜>²ôB¦„è¸;FÐœÈZ¢ÃãØöø ôÂÞù4&F8õnPI?mý”˜Ð½¨€ß°Üƒ–¹7Žê.¥èÔœi¯é )ŠÚR´¿YoJüÊ ˜0rØÉŠ¤ðƒr{T%\•çpn'JáÊB"¾rBƒò#ßè ·Å AKÌ6 °‡¾Æ%»1ÍÉ™Þàð‡ÉŽsRøÓÑÊÜ—CçÂCœ±§73¼±ü÷Œ=½º‘ŠÃkÕõd‰fBQ±T0™Ãë‹LƒDûM¬à0Wíçî{äò“é0g\slˆ-¢°¯ý <À‚
+N"“:G–¿]Ìð&›ÿïkÍÕâ
+ÇÈÖÙœãð?Îþ²ãÓcendstream
+endobj
+620 0 obj
+1613
+endobj
+621 0 obj<</Type/Page/Parent 539 0 R/Contents 622 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R>>>>/Annots 63 0 R>>endobj
+622 0 obj<</Length 623 0 R/Filter/FlateDecode>>stream
+x¥XMÛ6½ï¯ä²°«•ü½zHФŠ4mãc.\™^3+‰Ž$¯×ùõ}3¤$Jv¢E€$’Èá|¼yóèoW Åø“ÐbL“9¥ùÕÛÕÕÝû1% ­6ø2_.hµ¦8Šã˜VéhcËTÓÚ”:­my¤J§ûÒÔGÊíZ¿^}Åæi»ùv<¦Ø>úT`“¢}¥KJ3“>UäÖÎüÚÑ«O¿½êoQmIívÙ‘ê­&Úé27UelQÑg•?(ÊÕ®’oæY½¦àÍl0¦ÛdÙ >þî±´ûÝÝÁ–Ùš¨¼;ܽP]š]¦J}CªX³É‚&Ë(ÝêôIŽH·ªxÔëÞ!È‚¢Áfõ¨LQÕ²öÁÔ[#S°ïVWœ>É!%ü¿¿~½Jæði>aÏrZŽÛ‡Œ>s øÉT¼îRÏYðö‚ 9%ñ2š{[Íöþyå#u5õ'­•TÕ“d®5"î‹‘¦¶#Ú©RåºÖeDoŠ#IÌõVÕD]jdÎåK^)¼(l-9A]®“k¤©2Ug†xQ¦75}+N¶…S™-€
+IYká"*Ù×]iŸc¥[g¼ETjóªÍƒÉ˜»¦ÞzNG1(‹[±ChË;>Û´Q©ß‡ðÁ4¥]ïS½ŽhÎáú6TwRd¤ÙyQ[Ð!¨&[À sËË}¿[8¾x±Xø9ó³j>‹!”©ü랺ÊÇL3!™ÿ®_j·0cÓ¦uCgÕõ˜N"¨.ÄAx~NSÁcß›¶Š§8@(dè+¹ÉÓô«0@ÓåRà.ÃÆ=´1O—÷½ˆ›)ÕòE܆ð@n§Ü–Ú²ÔÕÎòÜðLã[å<Í ÏI,gH
+"S¸SŠ7Ìd2]gW[ðS“UC‚¨j¾oŠzä¾å«*Kë–Y)¢8'r«0 \ãòh÷¾ÏNíw|‰awÀØ-çVþÔÍžo¾–um&—.GîžNN¼@€pΔ¢UÁNÅzP‘ÑFËW—ÕUq]{E§p{DçÔ&Ýgªôw*()‘B"nø
+endobj
+623 0 obj
+1658
+endobj
+624 0 obj<</Type/Page/Parent 539 0 R/Contents 625 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+625 0 obj<</Length 626 0 R/Filter/FlateDecode>>stream
+x­•MSÛ0†ïù;œÂ qãHÚôc¦Óii3í‹"+X`K©$“É¿ï»ò®n.1’vß}ö]é÷$¥9þRZ-èü’d5¹Î&o>-)M)Ûbår½¢,§y2ŸÏ)“Ó+O¹òÒéÊÏHºÕFÐ"™'K
+…¢p¢RA9OïN³G[ôÁf‹KìÊò©tJE•ðO¼gNýÊÖ:©¨[·¹­çÚ)¬;¼~x°¥=?,¨Ï´WNQíUŽ*|P"'»Wk/kÏ{
+ìNXËÇlt±\& Z®Wøâ ±¶ »·”¢Ffw‘2”!½‹d•Ðg:Bm íu(bR„É…Ë[ž[]*!€s P(v·Óæ¡úÒÙ‚»3mz€=ž¼­TWȇ›ÛAŒžî§¾– O'hANdMy8¹?ƒ`£»oŸÑN¹J{…žƒ b= e…öm?Òs”Ô•؃Æ€†hÝ$­Ù–Z|…½R¦áÚ¥¨Å«@ÏZ4å+Y;D¹¥} Ð8vh”ClqãˆX ,¡öDç¼£h/øˆöQ°/ìžêáSw•R@ÆRd9 )•÷D°gÌf÷F9Ò ,KêbôX#U0Éåù虾ôÅCÕHèÎ Y¨ ¥lõ¶l 5Šð44PáCf¬Ü,µ<G4bòÐ
+c¹eœ2šz0€?9VO‡ÛËhbðá
+šÚe!̃j² íBð‘(K@ÅÞÊ«ò›† k#óâH›ï,ÐTyFzò±o>]´—È”Nn¾œðÑ—¡žrζ‚Oü›Uöœû)Š„;ƒu3¯ä9–Ë FÂ;½È
+ÿËZO@눾êD2“C ã4„=í™<9îC´|‹æý‹®QpÚL(u3‰@b‹»†0&¡ÿ5×<a1¯4@{ÈÇŠ?ÂxèÞÖ›[ð`8ê2‡'0vž
+ÌÌ8Ù{a¤*ÿiª¨”Ç 9îe|{(¢„GIIàßð<ÙgåœÎse†—ùyúÚe¾nm—^®~$ñÃÛ«¯×WôÝÙG¼IôÁʺRB¾ÙYð¬95kŽMÿÇå¿\-“5žܼ‹5çÀsôcòY.jµendstream
+endobj
+626 0 obj
+853
+endobj
+627 0 obj<</Type/Page/Parent 539 0 R/Contents 628 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 70 0 R>>endobj
+628 0 obj<</Length 629 0 R/Filter/FlateDecode>>stream
+x•WËvÚHÝû+j‘9Ç$0†ìœ‡g2c;N '‹qÔ@g$µ¢–ÀÎ×Ï­~ð2™™ÛÇ GwÕ­[÷V?‹©Ÿ˜.Œ(-Î^ÏÎz×Jú4[àÎèrL³ŒúQ¿+içÍJT¬iÑ}­ÊF•Kš¶U¥ë†TISQÌ%Q=¾œ}³+ÅC·RwG Öꌢ8¢÷eSë¬M¥K÷äâØ?™\òs¯åR•%o°QÍŠš•´ ÷©–¹FžûÝŒÛÞ}¤ZKú¢ÊLo Ýͨ
+q2]‰R™Â*ª\²ldÆ»÷©\tk%ˆn§ÝO÷oè¡£"Ùe§÷>ÜL§TŠBfT©J>¼Œȵҭ¡µ¬ R1¤äãÒeþD>8¼s#Ê[Qn£9Ú6yn"1E
+Ü K‡š-tM
+ w-IvíðЩå» [»ÃUë%uVMS½êõ@8¦¡‰ŒnëTö¥ŒJÎ.û‰ßbr€1ôgHžª.Ãà›ÂÓÚFÂÅ&Ë:p4]‘04mDݼÕé=G*ëszW¶ÅznÏ9É&"pþ¡3•¨ÖõXÆà ø:PL@7šD±ÿ¶ƒn8æRï+Éíôí¨—¶Ü†hZH4ÿba²2*TZk£M”ê¢wû@bbº–h|,Ü؃á€8 ’ŸuâÕý{ðçøÜŸ?˜D#¦ù~k1IÓTCo4+^N7Ê _@Ó77؆‘-8¤çßdŠ{'¶þ_íÃT×kBh~† ,þ½•­$ô§ªÚÜ(jÝ.²¶F²tA líYn2ш9tÖX,M…z¦–ßôœ>ü¿¶›ŒÑPÝ€Ül%Q°¨8—²$£ .äѤº\´,±$æºmh³[ šÈB*¤€öB}p]¢Ä@³¦RÓð‹ðŒï­ª­äs:–5;å (9Õ³z7ÅUilHy[/ë+m¬Õé:sඋp[-j]le*H$çŠæíòhgù>`ƒïì# …ž,D¶ïd‡’R
+:‘ÖR°ºv^h=ÖjÖUÿš]߆rË$tj¸ï”Í0X{»Èш®©·Ø.'¥~Z6
+endobj
+629 0 obj
+1754
+endobj
+630 0 obj<</Type/Page/Parent 539 0 R/Contents 631 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 82 0 R>>endobj
+631 0 obj<</Length 632 0 R/Filter/FlateDecode>>stream
+xXÛŽÛF}Ÿ¯¨##Hê#ÀÚÎÎÂv6™Y,™<´È–D›d+Ýä(úû=UݼH#g7<ÓÓ·ªS§ªN󛈦ø?¢eLÉ‚ÒòæÃÓÍߟn¦“ÕŠúìƒ)%Ód² Ùj‰ß£Õl²"«iË[0‹sº°þþaFQDO[Ši±šÓS&óSzJGO{í4”U¥®µuw”WiÑdyµ£·O_oîâ°wt°y…%”Ùü?¶y¡ýŠöôQÎ)سÑ|L¦V§¹ªuFªÊÈíMSdT™š°‚/[«#6ý×Ü$ëédM‹%\§’fÉr² £‚ÙQ8³Œ09t§q¸$¯¨ÒGüpµ*
+Uç¦r¢c©40+¯¶Æ–òw2ÕûÜQºWÕNßLÓZhõ~Ö+´€;‡vÀªÅª³1XÕ#/Ž
+FÙñ“óx2ÚÌæ` x¼ñÔ¹6ÓB0¿Š”¹YÔýLŒÓ[âÝ?¬)š1Ípcv h¶˜Ä“hB­†ÇàÄoB¦7¿³Ù==§4Ž—ìÛ§ŠŒÍ<ø®9Œ­%Í¡0J¸i¶tÁG!$øË,Wclñojªm¾k`¤’.S³߳Π··Ø"+d ÷ôð›ÀlÎpfæiö¨Êºu`£R…#gH,åó ë‘)'ÊKö@U5=û,zÃSÌ*§íKžJ ®oNDÿΫÌ}yòÞÊzd)“ò`ÍKžáˆ€8ý
+l®±ç·­‡ñL
+tÕ4vP× s µ ÂÁÁ·¼nYˆúdHÿ 7®ž\þêô` -oîøb>õj+Öh\ñr…l*i¾žÌà ´Ìaˆ—kɹ3…Ò6ßÁÖ’VóîÐï¶Þ^½.ïH:Õ$ÝóL:8ˤ03Ø\ßP‘è@“»ø‹&*ô‹.x¥‰æ^aÒ_„?kÇí¢ooÍ!CE
+ÐEñ*'^ÌÑâKŠ– vQF­‹¢—"7{€˜…Ž¼’oµ/ÆíɃ³JŠ§Ñ$œ<c6F³Ìž‰ÊVÕ´¦^ZÓvŽçÑüù-!*4‹Ï…WðŽ¤_em¾¶MÄûåZ³û“•hÃ(Z1¥dÔ㔬/´!7u«ÿhr«Y2ÉÕ-:ƒ€{Â*©?o8ÆìlÆ1ênŽ1 ŽÙnö*v÷ó ªƒ—¦úJy^*_ק͈5¶®2ô
+fð„°éJ0­á()©ýC3<}\³ÉÐ[ÒÚX¨uÉŠ8É“7¿K Ás äxÓ¤ÈíP±¹ð’Vø“D\\@ ñVá 4°c
+˜tAq°îÅ›R¤O8¯­¼_ôŸPý{­µåÐB5l4‹ xg·¼™¥cŠ™C$àÇÜíX‡²¿
+].Z,‘ ´y{>¾ÿüá=ýÓš¯
+Ÿ0äSˆ„Ù//cþ†0ú«O³%ù’eÉ”÷" ~¹ù/)¹¦endstream
+endobj
+632 0 obj
+2102
+endobj
+633 0 obj<</Type/Page/Parent 539 0 R/Contents 634 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 85 0 R>>endobj
+634 0 obj<</Length 635 0 R/Filter/FlateDecode>>stream
+xWÛnÛF}÷WL…Q
+äZdaj;âŠ)/´þhTŠi§Ó[ŠJƒÄêÐßǾ$.-“؇=FcJä× 1ep*yTX.â
+‹ð+Cå™°dQÝsIY²Å®·’\ÊA,µ&„<Õp€RpYVÂ)üÉQâèÚ€X™¢'Ä"’´¦(&Õ ×¢&Mïi6ŸL—7sºžO>àcüa<¹_ÞÝÐíýœ–o&¶¥ñ‘3#_ŒOÓ£;Ð*!ÙØãoE¼±eoX/húþîŽL
+Âmì…0Ô{Ëô\pjpŒ!.y"@å¿DÂPbºluÑîsnÆi*£M"ì=*tÆ*Ûv‰ÞÉ$emâ„‹óýVù[¤ƒÉÉÈ9),RQ³nS¥‚1þÖ’LA ÅÆuÕÖm5(o¯×Ò*ä}5ä‹8FD¿ ”Ù…âIH0-gƒõ—C1;髵ª_à/ïU±I!¡28µB‰…Z‡2©ù\AÀº_³x­­îÚ>
+É3‹mÛ,Qî! ÐPT¾‰/\R,¡¶—Z7±Ìµ*Û4Ùmæ9Os5àJÇ@|§Èîx'ölšÿStTô³Òƒ r‹s£#bp…Goû×4ÑÊÃt»v—ËÚߺåË:ƒ¡‡ê!öÍÅøíå-HæB½Ö~ÆY
+ƒì»“
+endobj
+635 0 obj
+1803
+endobj
+636 0 obj<</Type/Page/Parent 539 0 R/Contents 637 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 94 0 R>>endobj
+637 0 obj<</Length 638 0 R/Filter/FlateDecode>>stream
+xµXïoÛ6ýž¿âl˜ ÄŠ$;¶ œ5m3´I»í
+³gÐÒE!cº{l”=wgÑ"½·à%Þp4ÛçqØðáŽԪ‡´–YÖýZ¨uA ­V¥Ç6-ipÕ½7pMAŽ_ŸRÐoèà‡Þh‡/ôzMVe©th™Ð h•ß&tã¶õ®Í¬nÈÌê\L³bZ€9`¡S# ŠWð¨],ïe¦ÊL¢K$<ù ü°´ãKA°à³i°ÄÑÑ`޺Ȕˆ÷ã›(MïÿféàPâv>XÂpàZTß|b3FårÍ8I¬¿®…®í‰Gç,5ö_&”+þà„¥Tâ&ÏN¶Û7Á`ètÒ!3s
+ƒ‘7lFMljbxŠÉv6@$ÙP›‘’98e>²`š‹mŸ
+ƒ®¸¶È6Úãœz¿ÁãltÁ‚¶âpÒˆƒƒ¿P—Q-ˆ¬‘Us ‘ÊsQÄ–ã›C­ìì(N‡ûtǾ5—)+ëOs ’BE©¨¤=©[cبÄ:­–¨“©D–á„z[“s‰Ê2µfRá*åƒÈËÌ2i©Ö°ï
+ò ²o‰ ]ÊøŒ1¿öé”s  nxbï¤ó ñLgã/•j¡¨û´RÕ¯FFØ»JdC ÄÚ
+\Sj¢3Z¯§(”Ø…Þ åƒ ÚX8‡"`»†ÖªŒVèâPL®KY4N]<Ì;œrØ
+mž¿€Y.8qžð Í+ŽKw·su ⼓zÒ³åÐ|Ô ]`mú“=n/ºó^³<j–w‡à‘ëŽçá`hçÑg ‹Ã]…}|æ48Ý ¸¢·†9zŸpg²=ÆìIŸ Øsxk{ŒFÂG?Кm¹•é£+Ûîm1ÛclÛÙ7ȶÍpqÁ áÉNBØKFœâ k×5)^Ò£¬Û¼ÿm1æfjÓ?Z¼vâÎN\G}”ÛÓ!>rêì¿4R;ßNG¶0o_M—h5yÆÝEC9÷bï3½Ûöù˜MÎB˜|;]^ °¡Éí`Û¾îžoíÖ>b6ï¢Ë\lÞX̽j’Dö÷Æ{ŸFuS´õù›¾|…WÚRÜ#.Ù¹Ù
+™‚׿›ÔB‹*õ•ìbÓ–cFÊ×éÒ¡â¡y4•Ì©N¹:›œ„µ’óXVѱ݉r/ç8EE ë˜GÃI žy9.v_éYQL¶OE[`ÛÉѧ%9õë”3 ­rD¡nŸ aÖ.õ[ªÛ×25èÄì‹ÚŠêQƒÈõæ¬Ò¶CÞÒ²Sk¤66Y;ì­ƒHò7­ð¸˜B67Ý{ûD…–¥à—t÷ÝP?[-˜Ð.¨Dw¯(SG˜1(oάu,À‹Ê^)ÿ
+endobj
+638 0 obj
+1839
+endobj
+639 0 obj<</Type/Page/Parent 539 0 R/Contents 640 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 103 0 R>>endobj
+640 0 obj<</Length 641 0 R/Filter/FlateDecode>>stream
+x¥WMsÛ6½ûWìø¤ÌØ´(Ê”•KÇùpë™ÄueÒC. IHHB@Ûʯï[€ h%v;ÓIb‡Âî¾÷öíêûQJcüIi6¡,§¢>zµ8:»šRšÒb…'ùÅŒ%“ñxL‹bdª*j´£R®T#Ë Ic´!½¢ãË¢ÖÒÙ(Y“²d¤k ^$§Ém$•’Kˆn´“¸#œ¿ýbñ']à‰²¤­Q“†é4Í’ rm^Q‡ÄLGJ>È¢uÕ6¥4!šÆ ŽsóÁuÓÈ¿b¥9ñ…àRFU;d4jE¡[$É1Þ.Ž¸z¥ü¿¿¥é,É(ŸæÉ”jJó,9ï®*úÈ¹é ‡Ø-6ÒHÎSP¡ëm%k
+qâË)ãëêÝí"}yâ1Û‹ôõŸïq“®®ß½Å/é
+@A]îuk!±Êj²íÖ‡í¤YÈ­W*ß$W†´b€½Úqÿ‰¶r'¤›jw]7{Nù0]Ôè‹ã
+lâ€)ãvi{gùöY<WÔ” +(¾Ã¾Ñø”I‚Sè‰DïáïýFr©•^«BT¿*€S÷¨uç\5 VhY/~D8!* Ò¢¤¥¨DSp? 7VBU¤¡1/ûAi×+Úépz@ #ØßÁÙK½•Õµdø­nN<PgW0loÏ#[/“B7+®>•Íæ
+âÒK'08—îÕdüæ­
+½¿Ì(ô7€xˆëÌ/눲íA û,¥sÞŸ—$/¤ùO’œ$ô:âýçM ö¶£ö ….@<ÎC€({–žà……¼”; À<¶Ð[É-æxÇî§/£Þ—"Ó‰{ðÎ;€Íï[½Eì=¢Û0ÎàTk^Õ÷"ÿò†qÝÝøuŠ‡N v 'ß~ À øú‡Únyh ƒ5¡‚CõT›0ž°R•´Xž$D„·¯o®¨»Å¢áo ì=•¿I”lvKl¤€5Jj¨¾¡Íýfð¬åç¿ ûp¬…Íù~{T›ŒF¿;–‰%O’î™ß~¨;žêß[ ·-éNa u(–B,·TËb#eklŠôËùºQ>þ‹[“G¤¶Áð
+endobj
+641 0 obj
+1730
+endobj
+642 0 obj<</Type/Page/Parent 539 0 R/Contents 643 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+643 0 obj<</Length 644 0 R/Filter/FlateDecode>>stream
+xW]s7}÷¯¸“'2 0œ—Žãĉ'qãÖtÒ‡}»/ÒFÒB˜Nÿ{Ï•´|¬=Ó™Ú Öê~œs ¨ïM†t1¦|}önvöavÖïM§tx±K|èÓÅàª7¤Ñt‚÷ƒ>¿·’|§°³Áóç·# h¶€ùñtB³"œ÷i–w”£B-•e¹#§–ZD%裮>Òv¥òåBÓ\Rípè m¤U‹ù•ðT‰üI,%f«K#
+¾›"÷u0éW’Œ–¯gßÏúÔ\ ÐYѱr!­Å³JÃŒ¤»ue•öˆEx1Nöˆî<â‹ç·ã‡´ññOMJ$ž›õZjöbò+\t2¯­ò;ÊW2"Ž¿PNÌKYôØB@xŒ/€`Äqˆw Šç·W4%̆Œï1jãÞEoÔ£‡®ƒ'¼2šnJ%u+@¤=dÌ;÷Æ•^»ŽO[¹¶PzyŠ:¶˜‹ÓP%'P‹8€þDíÝÍn §ûéë·Ù×^åÚÀ-T°•—5C·U~Q ÎÔ6— Å5NfÜ.E'$ß<úRÌ`EºëÖgí‚ h{oC€&OfA̠ЕJKz¶$—[UA1è<eÙôP ì>Ž'é°‘ŸíA€‚gŸ!SAK+*(Y”ÇK»H B鞸®þ§ëîp
+‰ìóbl^‚$ë@ðs Ùkª¬Ù¨8 ZK¡1?jiwÏtÑÔ0³(A6A‚á9*,(+_ñM é²O• 7!qZ›B–¤3#meYòïÆ9cÒT21)‰
+rùm=§£
+\¢Aâ
+endobj
+644 0 obj
+1527
+endobj
+645 0 obj<</Type/Page/Parent 539 0 R/Contents 646 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 106 0 R>>endobj
+646 0 obj<</Length 647 0 R/Filter/FlateDecode>>stream
+x­WMoÛ8½çWÌÞ –-ÙñGo ºéöÐEwc  Z¢-¶’¨%é8ù÷û†mEIEP}‘œyïÍ›ñ¿W)Mñ/¥eF³åõÕÝæjr¿¦tN›=Þ,V¸(hšL§SÚä£E2OèzóýjôUŒpJ7ä4í®éAÔ;AY2MžùY–dÉ3:¹ŸSš†ýÆÙû>«'‰…¥pÔÕ8i¨0xf¨8ÈZ6ŽJa)/EsmG'I¥n%©º5úIÛkR ñ)„[ÃûhCFVRXi?Pãã¦4NgøGûPECòYY§šYéŽm0åxC{]Uú„ØWTÔ
+WÚ„þF’ÀŸ+%µÚZµ«$Ù\6G[¬2t9õ# HÇ ãs¿ìéE©ÐÔhG…´ªÛª‘'zTM¡O–þÜP
+Ë™Œ{¼ñI
+Ú UYRŽè¤@Rat‹ìO¾dŽ–éì-öBè¼PTÕ0a­Îâ) ÈÈêöÑopbHì&&]ƒ“:ÞIÛi]…De5Š¦ˆœ“Ù‰üÇIH,×5„¯vªRî…y à3bb5×#W#gÓÈg‡*þ~)ÆwÅv“AR(‹Ÿ‰m±èj¬$`"ÊY'>jI&‚¡ÌLgF¥¶v¡y@uð³½f)/³žÊTêàk!C/ïÖÈ\²É¡ÐÃyºÒH¨½L>o{á¥#è¨C£70ÕäÕ±ÀwCfýúX(^spUf6úªF£›ü ¶Ù:é7¬±¾ï…ÝÏuÒ©å§e~ß/Áüh Ûµnª²º:rSˆEyË:ÚPª‘D6ŠÛo\j‘aFOCyÙ3Ø ;>ó‚Ç~ìÔÀ×æFµ(Š!¨¡¼BŽç²@‰ç•B°áùŘÔÁ·¦Íßýç?€x”¾ ”xhÐMX+áß\qóô”R¾úû3úB2¥ù|Ž¨)]fɺ»«è;ð`…9psžÏo|É\šqé\ûq2áŽÈQ$ÂÏ%|I#Ý„Ï¿l寰\µé• ê–ý/dþJgQG=EÓõ,™ÑxáË÷6/ݱ9üö&URÅÿ4OSôÞùj‰ëtKt>Ÿç¥Á`üXÝ â/Ém
++?òlï’w‡Uã°,ü¼øõ_ó%[¨/šÙMì_Wÿ ‚Ôendstream
+endobj
+647 0 obj
+1405
+endobj
+648 0 obj<</Type/Page/Parent 539 0 R/Contents 649 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F2 5 0 R/F3 6 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 113 0 R>>endobj
+649 0 obj<</Length 650 0 R/Filter/FlateDecode>>stream
+x•WÑnÛF|÷W,P`
+ škÜuÊ~£ŸhFWqxªå‹¨6è¢HÔ³ÜÓB}WÜýàýN°õØ[Gø
+Ù€¸ý1g ¬xxS$JÕrSŠíï.:Ëë+‚^—l¹ðœëý‚°ÏqÛ²cnpyÓ²1a“%‡”¡=:Àc§×ÉSl-w$ì:µ­8Ù¯bû  Öø/ŠÌÎ4~õŽT¯©ÅD„tÛ°1ñ<ÉÝá6•ìRŒéýú믙¼R­»šiduj3šÜDã‘$–´3¶A&páÁ rc9 v@|…¸>LfáŽ?=›ÂñݧÎñ¡ØÉÙËß«í):Á‡J!%m-–Kr"ö¾¤Vì—$³¢qàmu¯6Àø¦ @ˆ+Ýê18{oì§6pÒà*ûûR9ZŽ˜¬Ázà ß뙸ÀÍœæ3ì¿Š¢ùÔèi˜ŸÙ ÞÁ»
+endobj
+650 0 obj
+1500
+endobj
+651 0 obj<</Type/Page/Parent 539 0 R/Contents 652 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 120 0 R>>endobj
+652 0 obj<</Length 653 0 R/Filter/FlateDecode>>stream
+xW]oÛF|÷¯Øú%jaÓ"eKr€ ðG]¨´VuNäIbBò˜»£eýûÎÞiŠ6š¢HàYÜ]};ˆiŒ1ÍšL)-.¿,Æѯ󗘿üñëÁì4Jh:ŸFc*)>Fóð[A÷üÐÉÍ)Å1-V7Ïh‘¹çÇ´HGwòÉRºÕZ’ÝHúqñ…“ô£ æÙ$:Ý9@¡×tr“„,Ï~"Ú*ýu­USÓ;NòÀýä´0GT䕤¼rþZj)Š¿ÉÈÔæ
+/*ÒRdoØ“›³öØå=N¦ÀºÈF½|týá–sö‰èÞ' ²ä†ðŸ ¨D)I­ÜÏ™*@l% -é‹Ê«¼ZGGgI4£é˜ù.)‰“(¿ÞÁöx†?öùþS5T6Æ’(Œ¢xô´×B#¯•º Þ‡à³8:ß—Á^â€l˜œd•ê]m©Æ€ŸÌ|¿FZ&ÜÓÍ9vÒ„—ž{¦%¬”¦j45Fj°ªøácê8ž@¬hhÀveóTXP ßw úx}ñÛYƒñüžMgx
+Qáe•Ñv“£E[xlÎòÈšTfL·WH£é,
+µmej‘O
+H`Ú {r)yMå¦ÄKÂê„sdJšˆ\SHO2ÇÓš–}J…±ºc¢ ¼àóû»{Ê„KæZ0´Ê¡îWdí¬§Ð»ÐÆ»ÂØa×;CÒÒX¡­wF_&$´4È·FCXk;gŸ”9Ü‘ÍY^c°{ZTØ„Îíî¦Áß4™Lp
+bŒV~ûŸã(ðÛ?9?ø%̵1Fñ¥s+’1N /4·#ö7'oöÑ­¨vTKUÒï1a¾¢¹Z®…Ϋëœe{‡h]ÁoPê2/
+ÝÀü/¥ÝJ鯔4×iS¢ÅU
+}±DAÅ·&ǃ‚]–CœËL¾,˜ !÷»øÙþ6
+Δ
+ÎBf›Ûtœ¨öÐõÁ"¢‹×¢¿P/£Wæ©’2ã\µt¿œ$ì.éåS°Çn
+}`¤½dZ‰¦°ØµÏ5Ñ=€~ Ë«À4u­ô‹Ñ•öòý‡{ÇÆÝâ·ÛÇØM@o¶˜j4³€²Ò]7†{¶·ª9r!Vp
+_¡à1wßÉA•ÎQBJ7hN@m,c_O¯ˆ‚Œ•µñp3§yÑ9[B®,ÏÀNè Ÿ’œòÖÍ' ‹²düÒuº’̶'©ï±|JeíNetÝIÑe<¼÷·&W¬¥>¤•V¥ã l 3Q˺lÒËÝ€2Æ|x 'ë5dZ…mü (1zP2]©²n°±Ì!ÝÞ^áøºÍS­ŒZYò™h¼«2ª¸Çꢱ9Zƒ…ñí’|ÇÂpòyÿ|ñÍ¢IDŸ7;À£`L%Ò¨»‚x£¤wÁ~æª^q³«FkÀãÅúÔ=
+I»Æ†©ÞXÐ&¥Û¤Ž?6?gw8p`à0³BaÓ§*ê.`æ €
+endobj
+653 0 obj
+1709
+endobj
+654 0 obj<</Type/Page/Parent 539 0 R/Contents 655 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R>>>>/Annots 129 0 R>>endobj
+655 0 obj<</Length 656 0 R/Filter/FlateDecode>>stream
+x}WMsÛ6½ûWìQ‘i}KîLNœt<Ó8n¬Œ{è"! 0iÙýõ} @$D7eÁ°oß¾ýà‹)Mð3¥õŒæ+JË‹wÛ‹Û‹I2ÁÿùcÊ_~¿˜M–É5­6«dB%Í«dV=ò©« šNi»Ç}«Íš¶™»`BÛtô,ëW²ªT…¨©1Ôä’L‘ÉšE¹deÚÖªy¥Òd’~Ù~c ± X\.Ï,Æk<ÝÌ’é9ž õN.œcëÿ†¯5 ²ýþ´û†Ó£1Ñ1—µ ˜¦-2ª„µp§6í!g·øì¥7t9ñ6‰t£RÑ(£©–?ZiæAГҙ9Z¢ûm°NJ;~¬(%Å+ í»^’©»S×›2u¶äDäfÊ‘›3š’¦³93åV!rˆ×|á ö{(¤°X÷RˆXˆK|î[N’ùà¾sñ€»€`hÎïà?Å꧴Ó+ÏÒó
+¡˜WÛÈÒqØ6†Ÿ¤¢(^ lYuÐôõþî/jUî`àÀ_ã‚ã°tLøý·¸Ü·A8…¨V6!ÚæÊRÊÒÄ_ñ, ã]…¦L>ËÂT%ÂK»Zè4—–Œ
+ÚñŽg™±#µôœw÷XctNÎVÉ‚µ´Å"{ºɧ2‡ú²` ½”³ÉèaÿìËh I=€ÌÎDa}yxOi.´†e\*_DÚÀsÞىס:’·Ï›ÌjÏ,•RhëÓj`Õ'¤%mŽI(«J4žz®¦n‘KàΉÃ檲 æ¿ÑtIfá"ý=R‰LÆôjZJQdÙÀü©:qUàkÁ7´WKkÚ:•F§°\<#çq²Bñm_›2>|:ýpû>HsÒ „Ѥ©i!++¶¡îdÅEe 95¹Kø«ËP‡G]Y+[_§GÑ 0{/)²NŸ^®RŽÚŸ¿KYzjêÔÕ0SIT)WÈ”EQúpªiœÃ¸«0øßÉÚ ö
+a$™Ï1øÕœ…ŽËÈà‰sÎ.@ù¤ÒÚX³oÖ»
+÷
+¹92cÙq9
+âø ¼qD¯Þ!ø®\Ä1CH`p-­àG´zq™;/¡:fÍT ``º÷@›¼u 8©86¬¼~C'k;ÔÙ *è^i®¯°à,BÔåyÉ%ÀÅ÷,ÑcÌ|„½p6}ºûÊ`]ZsPÞ‚|æTÀŠ°Ý81é –”t¥›Tƽvê¶qç°mšs‡è7?ÞÝú …*böú §ƒký‰ê½>pZŒI6iB7(ãxŒ€Å¦\uc¨[+¼G±—/ÔŠgàoß6-&ŠPYÖÝ0Ä~….Ã5sR ÿPf¹ß‘¨ªB¡ípÉdB( 
+¯qmrØH_µz íÔw:y9 L{ÌnëA"¸\s݃žêŠCŒ}5o'Òï¾êñÆ'NÞ';°…[fc*ÅwV85Ê=|¯ŠO ˪À€Ädzå…Z)õ³ªæ΋¬ ¢Îùå˜á6>0ÜõÙ««n„½<uÜûÏÛ¿ò Œ¤óõ4YÒ|Ê͸¤Ål“¬ÂêÍ<Ÿ&<[»¶ÝÏUô‰5èåN äà¿C=™I[7G`è³È·‚¬Ú„™÷zy’;sÿ(íçä~Nuƒ:Ï©ô‡ÒíË“© ßκi¬›dO)àjáèð3?Í'~JœóPçìY´„ÛטûgѲ¤ ûÛ?‹–˜AF|)ÞÞ¢ŸàôpL¼5,—‚÷wWHʾʾuÎU¯àÎìz< À˜Ð ¿Hµ½WÙ„@OWkŒÃë^S¢÷•Ç›Oïnè¡6ßÐï0úȸ ƒ•péO]úc£u2K‚JY“§‘r6Á›Ó­›RœÔë$Á†FóMÔŸÿ8û|endstream
+endobj
+656 0 obj
+1490
+endobj
+657 0 obj<</Type/Page/Parent 539 0 R/Contents 658 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 138 0 R>>endobj
+658 0 obj<</Length 659 0 R/Filter/FlateDecode>>stream
+xXMsÓH½çWtqY§*Vüm‡[>ÈB-„@̲‡Tm¥±= iÄHŠ×ÿ~_÷H²¬À!+ÒôÇëׯ{øq2¤þ i>¢ñŒÂääjyr~{A£-×x3›/hÑ  ð—°w½UY¡-zkwTXº¶éÚlJ§éA%+E£`D*'uºüv2 þh‚ó½{gåötceR>S8ÇÚñWìoˆÏØ_<ÄyœXÀîvúGirShú¬UdÒ?1¡á°:1šó÷WzmÃÞ–ºIKMΟ x,¶&§ÐFY¬U®)Qß5å:Þ«B+<…6±B­bM;SlÙ¢ä÷´R¹ «ä†cìÚÄ:§\»'âüåÉ*àS¤Òˆ¶)ŠEþ‹Š“šœ‘ÌTžï¬‹ˆtº}V›²A3 Znu›ÅβÓ7Ë®…„†üëóŸ'Ãá Ót¶&”Ðp1
+.ª§˜¸¢<^àe»’…ÍLˆ:I¾OÀ9ò8i’䎸 ß‚'‚y¯Nî±7}<­¢Í^'Á´CcQ‹uë»1¢Bi¦6ZP,¶>4@Ð6g“Ù³„g‚œÕñu]¼9€^Ñã8ý:ØÙµgÑÛ_—AaÐ7äb‡ºÐtºf4Ỹa
+èJ…ß7ΖiÄöÎo§Úh˾§ø-ôk©Îùí¬®ÅeYl­û#'yëÖ°ö@Ð>²a™è´ üVLî•I•ÐŒsºQO&‚÷4µ)̼:tñý͵`Aýšç’ú+©FõÝݲîéÛËO¯@×+‹~©=zzåe¦]®#0lµ÷ÚT l}Én&Ôìý¯€gÎQù(2g¬c‘qÚw,‹ËVEà…Û ‰˜B•©•‰Ma¸G,©°õ¡¯&ì°,i‚B P'­ƒ=ööã)2ùÊß  Îh"¢¢ª‰3`V¦¡FÀk„ƒT3(A>:ôóbëŽãÈËal7œöÚÙ¤sJ ®S(£ßÃØ –¹(Ô&„NÙ²ˆMÊ  M ,YN©†å,»§ã¹­h>GÖlBî0üN¨r8\·ê É„ê;‹ ?‚Ç
+VWÉ$VfÂqT BÇŽfÜ“ÁD$j<BüS#Q“Á´#Qk€Ë<U¨ïžãZ‹DK,©e”ãØî@«CÎ ¢e’ò3!èÑ—»wÿüûîîayùþ}°-’øøæã2'xLð׬Aó1Tg|Áó*¡Éx «§&£ñóµ-ºONæ`ãTÏÎ?ƒžÄ{ZùI–…ZóÄCæ—Hw‹3k#4C3 ÌµFÛ!  é*ãÃã€ÚÏx;A§oyF<CªÎ°›Ä‘ü³Dc†m<µ ˆU› XŽ,Á _<fÊQ™)ßÚ2Ž„iœ œ¿fÄÛBÑi›g½v~Ü(|üü6¬³?.Øe¢Þ#HYÉi­˜ü®‰2‹UÈñ©¦)/þ«Ú#+AŠõ“FÛë°tàheí宜.œÑOÞ[ŒÅ€5 )±.ð\@C‹@¨ªùÐ[¬A­ØÎï–G™ÿ~4V"yì9«°§lO}² ¤ßt~ÑZɼ({I¤|¹J(³14öãýF'Æc5@Ži•Ö?ò˜`,á¬& ã’‡RÕFLójÎ<c\;pL7Yb WæÅ‹Â=b×Ãå¸Ë´ŸÅ²h¶ý@/Ÿ­Ë9(è
+Êù5F i«?¶µæ2ƨú€séãŽ"UÅõ‘ŸñØ4Â5àV%*ÜbY"iaìŒ!Ö8´2§ûÍâbâUkò²Bð
+˜#ØÚåy4=¤,2ø‰ ýD‘.”‰qE,Ã-sZfG-§g] <#]„A€¹;6Œ;ãpa­9V¯f&Þs
+endobj
+659 0 obj
+1781
+endobj
+660 0 obj<</Type/Page/Parent 539 0 R/Contents 661 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 183 0 R>>endobj
+661 0 obj<</Length 662 0 R/Filter/FlateDecode>>stream
+x•XMsÚH½ûWôek‰kI 6•Úr’u’Ã:ÙØ·8‡A  D_ &Þ_¿¯{HÄ@bW µ43ýúuOw¾]øäáߧ8 QDI~ñòîâï» o0™Ðþb–<Šñ„ÂIŒÛ0Ž!M ž—XfwÁðáuH¾Ow ¬Mbº›Ë{î’^® ›–…žSYd43©^àw¥<»ûâôcTº
+8 °ãd<™v©ÔRóÔ}xÊ4÷àƒëÒÀÈâA©.ýÇ4©M3­ ÊÒâ+˜Ø¤v%ƒTb×*Ûù“æºNLZqdK{Ôx  Þ2×Uþ®ò*ÓÂæð;OöHok'ÝGd€Ez˜Oˆ·?Ý`æ;·Œ–Oˬœ©ì³K}Ÿ¹rÂßsz©ê4¡Zø?–—¬y$6{ÀKc?Ä5'ìî°¶”îöõÖeÍ„1&tbOÛYZ"Þøb7qÇ8½h,üÞ‡÷oÞw`x#ÀÎ)樋pó'$8<^(ïó oÕ¥)×ÕÏ‚¹¹úxóîŠGï–î>¬t×™Mõª\gsöM³‰hî² ïÿ¬L¹Bú0Hoå¼· a]#£1;ᨑb[¦9Ðœé-Ùã‰ÈÏQØQyâ^ß›röéŒÎˆ-oû·2z¡ §gÚqZu'¶Âp*Nl¯gt]ðî}Ù°û«ŠGlmÔ¡g‡¨P­RÕöäYsŸŒ•Z'¨Cöq·éè¾—¯Q[Ö
+<lÞ¾ùþYÇg^$>sa"ÂôçÛ6þíúDZ3 ~û$x¤DóXYx¼Ruý4GâºÂòmÍ¥Ü%)NMmð£8”ºå#¯„ä¤ÓèG1W¸6úFý^ùq3šˆ{ÒŠz]U¥±Ûš•Ë²èÄç(ô÷ñé„3PÑvprý!>÷k?½)OÁÜHIFÑ®-—b‰Ê”‹4Óõ_j±‡9} ?Šh$¸¨Ý.Ip‚W»:Né=þ~»¹¿ßb€´æÑOrìÀsà¿×´*sMsÄHsÐb /ºAMêL­¨>,T3îDÖÇœ²³ƒˆûAlfnpÚì ŠÊ™=7éÉõV*ì¶.c.¯ ÙN8£uìªþ>6œVæã4Ù<ÂUè“TוNÒ¥¥.´AYw
+\ûávc–‰$Êшt{»‚ŸÄUFgèkÑá\^¾~{y)Á}#7‹Ÿ
+meåϨvØõ ~ÇŠÏíZ“Xΰâžô…}œ0Hò99ˆ¼ç­ÎZŠíM¥@S×êò[ìÍjäG®R„œµœpÚ ?îVŠÓ{i¸®ÍPŠÉ°æ³È0KgÃ-¿h¨™Xé|ÎàOˆÅYŬŽ³zPŸý›¾&ÆpFi89H(Ô8¹v»ú':¿ÂªyžJW¬ÛzîOÜÊI‘ÛàNZ ÷áýi›ª¤ÞƪÆPNPâZÎXç¢3ÎÅ õeˆ&~XØCÛ©Ó‘£—{Z¹?­Ê³]\~£EÙVˆ)½<gJ¹?­p2:h伋D¬ê¯ÇƒÈ‹<¯­!Ëû”XîO+EK{PBwµâŒÞØéÝŸ“úÒ$óq‹û>¿s"}J‚öÇ­rAU™VŽê8¯púg2w,V3sù( ›#ÜðzÒÐ|”_$Ø‘Ðp{õÏË+ú`Ê/¨nø®¬¹’‰ÌHß ïÇçˆÞ¯~’Ñ:áë O · ÿ{ñ?DŠ†mendstream
+endobj
+662 0 obj
+1576
+endobj
+663 0 obj<</Type/Page/Parent 539 0 R/Contents 664 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F3 6 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 190 0 R>>endobj
+664 0 obj<</Length 665 0 R/Filter/FlateDecode>>stream
+x­WÛnÛF}÷W Ü•‹º[vßd§nSÄIš¨(Šº(VäÊbBî*Ü¥eõë{f/4©(iŠ$ˆx›Ë™3gf?Œhˆ?#širAiyr½<ÜNi4¢åšo]\Îi™Ñ0‡´L{?¨´Úo­Ìh+ŒÙé*3TÖÆÒJ’TbUÈ,!ºÕ•º’”I+òÂV´Ñ;"«)Ód7¹9§J®e…;gË'?,OØ…óC#þõîÇ“ÉE2¤‹ù8¹¤’FãËḫ‚Þs _T.àùïwB~}óî÷·Ë—o^'[ìîùK÷ _öâƒÛ4äÞŸÃÌh’Œa«w?¾˜‡ç~Ü_$S~¾ÜH2²zD> So·º²Èµ¹¢B?heH¨ŒD0ÐÄ=úCIë^øÓôÈl <*ñå˜ḃ1¡@a†Ja,¢]Uz‡À A¢”ø±Få~ËU†ÛDi‘Ke¹h…N…õBžù8(©=¾¸AéßRÙ×ù|U®k|--(ó‘®Ùm®MZ—ð!lŠä*-ê ÜÚåvãXBYnl•¯j÷Á¸ ü:Z¼Xœ#ÅëƒLcêϘZ€raè½(W‚Ƹ›iiHiKzÍü”êr[HdŸóÿÏÑê5=TºÞR)¶[Nf…ì¤T ~¯—þWy,ŸŽg õìrâ”4]6W‘Ôx8r¬znº_UþMÝ÷¸{+)ŠbOŸê±¹ s.RÆõ’OÛ‚™‡¿<b.š­HåýÙ9íuÍ·ê"ëVÉAÛmBn O˜>Ú…fsÀTÒd˜LÂÇÞº,i6K®ZϸYqÉ ·;Sd%t v7]I¦\%©VkÈM%JTÁS4WàBéYƒ:¤ÀÂr N_øŽ[°esJÆî I"Mu­¬IÚYÌæ@yz9GFcüC§­½ú]ÑM½†.ÎÆhN;âËdšÐMôv'ÒM®$-+VÀEðâúüg+èƵášp÷ùð8Œg•BGXd{ 0É´Î`›k-Aã-»–ï×Æ×[Ô°®¬#
+=æYìKìpà3FÚÁó"ÚXºzj `Cíàå'©RyŽ¢DwÍKÌ4XX aUR)Ë•<ÔbWÐÇJ¦¹PÎ30èéVÃÙ~¡êðŒÜìsbƒÚ+}PúüA¶Á!4"Vø€t‹&Ÿ·/n XK I4ZSÒP,™\­Â;ùÀ#h€¡ açœ×Fäü œ·ïì@4QYT©®ÁLÌÃïݨÇÎÕ¬Ña Â¹>‹!:ºÉÌ
+endobj
+665 0 obj
+1878
+endobj
+666 0 obj<</Type/Page/Parent 539 0 R/Contents 667 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F3 6 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 195 0 R>>endobj
+667 0 obj<</Length 668 0 R/Filter/FlateDecode>>stream
+xWkoÛ6ýž_q—vˆ IJå·Óm@Ó.[‡¥Ýð -Ñ6[‰tE)Ž÷ëw.)Ê$0±-‘¼ÏsϽü|S1{ÔQ’Ÿ\ÎN¾Ÿt£É„vÅ]šö£ &cüìóÏBÒ[»4Âc¯^‰{xáV
+‹ß|@Nçj@qL³ÔŽ&cš¥n½K³¤5[Iz1ûxÒ¹‚InO«#ˤ³ÖnR¿N·Hê²ØÒFeeÊ–Tât.’•Ò’´È%a­\‘ Óç§$Ök©S™žÓÆè³’VâNbÉI6¿f9ü–Õt©³G³´%HWX±+‰O¡SÒ†he >U…LJSl#º2É{‘¯3ºoDJg©Y¯·gÐ[ei­Wz¹§î?ýÍÔ' W•½2¦̘ڽa4`‹¾ç÷Ãîÿq½±Gnc«¶îo­’O¦1­‹N*ï:ìòEg®tg!2[o ‘o³®‘Ϋ¹¹“çuÒz!i«ç[”MsDJo)•6)ÔºTH‡KÚ¡äL&™B‚ÏIE2:§KaeŽç×&_W¥,"ouиÀFwãÚN¯˜[“áx¶¥¼b`«z'ËË·ïo¼~³ØSO¥áM 0•òoOM.”Žˆfx
+ÅéB jؤ^ÙZëu„ˆ&f¶ùðƒã¥a<Må4áË?dt÷ã$·ßÓ°!¦aÌö©ÉæsÏB·­Éí çlÃjNÖµâ&Ï™-8uvÅήd!›š Ødª0¦|V×Q°£Õ(¥¶ v^/÷”Ù¨ïA`ÃzŸ,Ð'[.×HS]Ggö <jÔxû†êBÑrö6‰C®–RË‚¡t„‹Earƒß¼÷ûidÖu"FQðžxxÿ„ºôY„JóJ*Ïeª`C¶}
+)‚S¶B}¤,²ð‡©üÀŒ{¤z#
+tš¯\½zV£~<ù©kÊÀwð€©ß6Àݺ:WSŠÁÿ<bõÆCשwCDD½ˆNßë6ÂԾʶ§ôšSÎÖÂ…ëz„šq›¡W¾±¸íêù…G77±Yô*¤û¶ÅIçÆ…ºãQëömÄö
+ÄŽ}ýŒår‰aýY‚*_~!§ n`ð§H4|q×´öZð¥dD#ô{Ã-Áƒ>ÈôGÐ0Ó?+]Ý“ÝbÞÊ
+endobj
+668 0 obj
+1656
+endobj
+669 0 obj<</Type/Page/Parent 539 0 R/Contents 670 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+670 0 obj<</Length 671 0 R/Filter/FlateDecode>>stream
+x¥WÛnÛF}÷WL
+aç|ƾ¯¨?%CŽ§Ü¨’LÀ£æÉäz­³#oÑCBtKô Š¥"•(E(½*Í“>¸XôL¢“ RͱڵØߨÐqë+éÙi `̵>:€_œSQ…’–šPoíÚ‘ƒä¶šCÀs;“ç´R&'³â¬‘¤±Êï‰!ìømAÆk„o‘™p¤G+7¸Û WåÇ@A é
+•nŒÕTz®TƒZ" ßk
+k@ãÏd{Ò_Á¿®[ˆ4:ü0 ÿ¸
+gÃ2
+b„Q
+m«Hã†&\ÃF…u÷±ªÐ´¬J(›,+$ÝèôQê¹t_ét* AdS½‚&è¶ÖYÝî¤%§D3ŽDNU€ÍÆi˧ ÈUþv–xú9N ÖýG:b þèf­ú ‚øŸ1l¥SCHCîxÿ »6xõÌèHEV;•£³(©¥C[d54äq@Ô4Ƚ«b[ Õv›ïŸæQ_íø:ˆ‡§CÝæu¶8èßÏO0.i4&×4¾™àó¿<ðºÓutuƒas<__'̦ô£wË\Ü2zï½óÒ¶/ï† Öxe™¡Æ¦y•aÐÙ«3ü‡ K¸õ´üqÞÒYÛŽ˜^ôÊý‚Þ0¢¶ õ;ý´Ó«8®8ácÐj»Õ6ÓYB÷^ëwwl¹­ÎEq(¸'ÜÆ$؇8ý†(vΞ•u;@î2µe{8
+•AÜh˜ìâÚ¯°0äû„\T7™VŒ†Mrå8CvVÃúº™SOf»‹H7ËU¬38m…£2ÌܸžÁZBú9µÛ¸¼]g‹-í²Þ¬Ü<"%I7ðÒÆ×8.…ð¬ùRiú›7£ÙýTÇÚ°³ìŒÖ2¬1¹Oÿfrl¯,”:k/G[d‚/´Nh÷té-kWTù…d‚Æ/ ^å¢6MDÐ-æW¹IQ^#eÆòÄb€0YÙÅŽu,3„/>K&ŽÑZíßÒN30^Z#GoÐdñŸ6ÂìÐ ‹¥‚Ó£ë%§´Â)™tlÊ sÞ¬²Ž*¶P]ôt²N`ÒÊ(Ãn©¡ö®(lʺèåÙÇé+\?Úý>ÞMë¥låòÜí ýIÊËCÇ«×7\4²ºdD­"‡·fÑbÊôíbñiöáÃ|±ø5òü@}¶'Ôû™.;;ZËÀ}å¡ï ÀËr½± ºX‚·èEJÔºö®Úžiìß,~SàÎ$í +_ˆÌëdÌŠ`›W™Eo©22™VÀ’oÊŠÀ@åP­5PˈXf $„è• ®ÐØ
+endobj
+671 0 obj
+1534
+endobj
+672 0 obj<</Type/Page/Parent 539 0 R/Contents 673 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/Fc 12 0 R>>>>>>endobj
+673 0 obj<</Length 674 0 R/Filter/FlateDecode>>stream
+xW]OÛJ}çWŒªVM¥à|&—+(Л[¸Š¤jmoÛ›î® ù÷÷Ìî:qÝÒJ7­
+Y¢ÒuÅ‘Ú¦÷¶€>ƒŽœ!îbTð($‘¡¼ÿ­ã{fõ̉èpòšPÒNŠ´ç¥WP§þûÜ[½áÄ_.äUD÷°½·àøF«rù—ÓH[\ž&¢2S €7ç2+ñÄ|ð¤Ì
+
+)øêÄ–oÛIðŸ7Šd;r¸
+>†%Õ“ÿ….±S¤Ö˜Mêm ƒQZ ù
+4ÚšÂ1l5W}“1ešÁ‡ îÎ"CJ€Ð8Ž*›å™ÝvÈcûÄ}q\S}D)
+éìßÕ´»’ölv}Gîm lóíë·çt¶Æ¬ àï‘—sÃajKøÊ¿&¶À9²Fxv˜m½FXÅ
+Ñ{Ò&½
+ŸP5hý½Êxq&ÀZê"³‘q àþëaŽø«ÆûFÀ³
+ÂÀZÍöÿÃÛ8ÆM­wö¦ÁÑ àE÷Ø·óîôóÙ)Ýhõ7ós•TØç½™2Eã n?œ Ýûç4EGýƒ…´žÉü
+endobj
+674 0 obj
+1802
+endobj
+675 0 obj<</Type/Page/Parent 539 0 R/Contents 676 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 198 0 R>>endobj
+676 0 obj<</Length 677 0 R/Filter/FlateDecode>>stream
+xXMsÛ6½ûWìMJÇ¢õ-+—Œ“8§ušÆJ3í𑄘T‚´¬ß·
+VÃg¬Ž'Ñ,\ ž±:YœEÅ 0X'ØŠ-Õ°u‘¹kxÁ¹jˆæY×P©>O—£CëÀyƒ>‰'¡2±ÎÀöÂät¯’ÂX³)#>0p ÆsT8ô^¢(~¬aú¤©bΊŒRYŠ}Ég®ÞÍk²£ÂÚ£_˜hbmª2ŒËUÌ‘naȯüé¤>=XD×(9¸Çó…Kü©Žx­µ½2”€,àˆ,a«Þ ú¹¢ëë21z£¶ÑÞdÞIS}:‚¼yeKªÀxG7ÐûAO\UŒfÞemuÖX…1vÉgÙ5
+Æ¢¼Ql¼¡ÒIV¥2¥ƒ*w\Gµ£5`ñ6ìúÚ”¼á‹)mé´¡ã…·ÚqBPÒâ<T‚œF­›"Ø‹lbÄc+UúÜ9‡!3ªÉ[¯ ¨Û·a¼«
+FqI"+!Ûƒ±¡ßrFè¡ií0 BQ×Ì€¨ ^wî~åºä«T–ñeˆ
+wõÜÛϽÐb+‹žËYÏ
+ÔüÒë¿O•h n<L®Ss~ª#¼¼×æpI»0,‡ÙYl®°ü$e{n˜èàÔ ûU7­X õAo;f!%–ßýË$Ï=\i”øaJËçÊ:ç(O7ay¡Â633²îÖv…óå­Y`]·I߆ÂÙþðZÊZÀ1ƒ×SülX¯5UŽ¥öý4LdÖÿ4w‹I§¤ß”<Ô/Wïþ)¢ëz¨ù7ºë™áy¸¹}ÃoX_1kÐ[“Tü6ÞNãƒÑ|ÀÁbìnø¯þ0]L›÷šéŒ9€÷å_/þ“Ë÷endstream
+endobj
+677 0 obj
+1793
+endobj
+678 0 obj<</Type/Page/Parent 539 0 R/Contents 679 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 207 0 R>>endobj
+679 0 obj<</Length 680 0 R/Filter/FlateDecode>>stream
+x•XÛrÛÈ}×Wôé*$Hš’ö%å‹”¸J²“^ïVée ȱ€.f ZµÉ¿çt HHI%å2%âÒ×Ó§Ï苘¦øÓåŒæKJŠ‹÷ë‹›õÅ4šâ:Äüñõ¯³ømtMË«e4¥‚Ë+ü¬¿å´â·&· ŠcZglhyuIëT,Li ?ä&y¤.5G©;ØÜ©”ÂN“*“yÒ)e&×ôfý£ï¼ÜÒ0 û_&|F…IJç]¢Ä“~ÉÍfr¿º»ýtw³š|¾ùíÛ*ºùíæܤCSϖѱ ×ðýÝXÄâéóšÈçI—Þ8K.“Èß¼.é^YµÅÏÌ•D]¡ŒõR6¥ÁJ—x¥}‘žzR&W›\s
+äÐß]Ï÷”(KŸh«Ã_8ú+܆
+·ƒ«‡ÿ…²Ïä]U&Ús+ŒEé ¸3Çêâªôˆo?…¾äÆn)7>ø}½ý0ðÒ¥Ô%U¡mIiÏ£»ÆÆ0 ¥‰&ìĸWÅFQ
+‹¥ÙT@â` ¾Ñ÷gÚ:—’þ¹Ï¾+á"I«K…îÞ¿Ø÷Æ}•ìHùžßM ì!æ¨.ɲŸ#H¥Œ\Ï‘¥Fm­óMçr’ra+_•ÞT[ <˜RíK‡RÖÕ8H™ënd@/$4¬h:”4áŒ/Ñ߶T³å¥Ìh×A¾=ž_Ö(å«ÛéÙhN"næ)J9Î-7 ‘aR
+OÆÓJŠm‚×y†6ýîª.7Œê8%·ç"÷"fƒ
+v@/&§‹]€q Áž©¸FÅ•ÊpX“Û· ,†´Mo{hR–«­d k“ç(I’Wé‹¡°žÕ«鱪4h
+ú' ÿp¤“Û#wCA¥Ã‡ÙÛioRqëHi(U’ °Æw4™üiuØçÉ*„Š€ÂÂûWcá?[‡’˜]M£˜fó ¡ 9ôbûí58›ÏdqtÊç•Å©-k¨ôL’%û´*ö< øo‚ˆvAdãápˆ¿¼\¹ŠŽú¶Õ;CÐÅ
+_Í6mrk÷ó‰ŠoâƒaХߙ=¯$L¿/›Å×°âJÔÍòGr`!Š¼IVb
+ôÈÛDZÛ‰"€
+\¨ËL%, x­Æ'•«<Æ4Õ¼Ÿ™Y;x×ìŒ}ó2ifÉ^ŠÎ‚å$˜“Žpø<©­{4——X‰å05 3w ¤)üðRaj‚Ui‚ErD
+µÕKFˆ2è}«ñ2ÇÚ…íp¹XQ4iáR¯ºH}¤_qFóÅõ¨Q§|ñͤ›Ÿ—#‚÷D¼x¦ïgMg…Ã{ Û3Vg•¦ÀA¶>÷ÖÒñt°Nb˜ð#|XúÝU=²â­FóE¤¿Î0ÜÏ÷| o:p:ð§Ý>¤…Î(òLJ›'ÆßÞ
+Wïîß¿ƒîr?08¾Ÿœ9Òq 2Ç"¼œ 6þ‡£ëâr<½X² ì‡\ü‡,b¯endstream
+endobj
+680 0 obj
+2019
+endobj
+681 0 obj<</Type/Page/Parent 539 0 R/Contents 682 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/Fc 12 0 R>>>>/Annots 224 0 R>>endobj
+682 0 obj<</Length 683 0 R/Filter/FlateDecode>>stream
+xÕXMoã6½çWLEÜ"–-ÙñG/E7Û ›ÝíÚÅ¢€/´DÛj$QKRqréoïRòW’nºè¡E€À²¨!gæ½yOþ|R! #ê (ÎO.g'ë>…!Í–üÕ`4¤YBÝ ÛíÒ,nÝ©ME–=Ò£ªh“fR&d¥…±¸C§ï¤Ý(}G·
+‹•¦™R™!Q$t±’…=%RÙµ¤w3šJ}/u@XD‰Â·©¡ïfœ`ëv4úؼõF!úÔ
+m©¬M‹•ÁÇ+UX­2ú
+™áššy•¾OcÉ«.’ÄEì\ÇuZmd‡d’Ö<:ïÖ÷š”q«ö‚ˆoOe&cëNúåœ8=Š³4¾ãìNßÿr|å¶W.GØÖ©.èAÂ_þ¦0•äúJ‹Dm̮ԺÛ>^Mˆ6kYP©U^Z™ü“ÛÑù®¼[ª´ð;£S9Ê´L3ôȬU•%$Rc±{]6ÀÒ°EßNŸÎ~ºýøþýìÛù|úh¬Ì{Ñ|^¸ óù÷Á÷ ™n[Œ§â/ÛÝ]?MµHR–*b[¿Ÿ0´‘Yvv¼k)4êdæó£Ð(I¯)öïêXH@ÍýH“·oO -z~8­ïs¶hï4¥ˆï¤%Jª¼<sìð;móŽEi+-ŸÁ÷¡‚ܤt"õ> ¿|•­ãÊ-
+nõ'pLµ©*Îv,F/4ÊLfÓ€ÿ¸ž ¿kV/«Ý´‡&ìÿ:±ëd˜ÎžÍÿK:ïõø€ÓRÿ;œ~§6 Aùè:îy¼Àv®3›_Á^pØñš§jÙÏ•Ûf˜U¥Ôyj 0å1äpžH™m#J ·R§ÂJÇZˆš&“ZÐïúF"ÉÓJƒ8÷’tºZ[³Ð3Z¨¦Ÿ®
+pˆéþ„¥P¸F"ëñÇ”Üáñƒ‹Ñ,aâ!RDsB*X>‰¶unæ7½še6oÍçîÌnNº°˜ßñ|\K- CY–X(Ó˜2£ ¤Ý®÷†%iëzbו˜ÒåѾl ÜA²˜ƒ¹›3\§5
+uVKšŠ|!ÎÜ^GéµhmmùC§cxe ôÊ•y{ ÷¯ 蓤µ
+íðþÍq–¯ô=\TÞ®s=h4x"ïe¦Êøów¿ÔBC㊿ߺ:Ÿœ?ŒÁ¡@âà" Ò¨Õ"“y@7K2ê á‚îicóË®…· ‰?4™Ûà„!b=0^ãâ^0y ‚¦õ4§±²–n¥ÖìiMšWxÀô¸œ\ÑB¢Æ)Š+ÜQŽa«ÿ‹
+$ ûAX_ÕHxÚS ":¥Ý!¢nóf³ Ì]Z–HßH«‡ŽÉmͪ`móìE
+›àóW%uG¿á¨ïH×Ñõl£ó#²]Ï>ø¡Ë)¨Œóôö’L)ãZž²¶EK7ˆñ?ÈÓX+£–H )ÔIw½êpO¿"©Ýˆ=xaú ByC+x²æsUÉ,sæG.ã^矕±h4ùÂ^è[?`û«'Uƒ9{ÑQë½Sà™+¨¨òª¶•0-yJ&tpª€ÞàM^½„W*ÛÙîmÚ©Ëš4nüî¿ÔÕ¢ç^  ðÅî)_›óF¦UY*ýD¾Ø1þísµX?›©ßb«…^†x^DcèÁ˜%d;ï¡¢î¢.8Ê<îÐë€ü\!=gXÝ^ÜdÑ«éìÝL°¿)j㜰ghÛbžáP¶è†Ç¼²¡fZºÍùwÈ­ãæîµ™]¢ŠS‹÷whÃî˜b¡*ëØæâ´¨$1
+‚S–"¯ïÀÔqå…úshæ…ß W’ƒ¨Â™$Žå¤2“Âà»…ûn“é[Ui hGãë
+endobj
+683 0 obj
+1869
+endobj
+684 0 obj<</Type/Page/Parent 539 0 R/Contents 685 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 229 0 R>>endobj
+685 0 obj<</Length 686 0 R/Filter/FlateDecode>>stream
+x¥X]sÛº}÷¯Ø>YéH´$ȹ/wœÏúÁŽo¬ÛL§îH‚bÐA+ê¯ïÙiɬÛÉÌLñÀâìÙ³üãhFSü™ÑbN§TÔGï–G'ŸÎh6£eÅw/.´,išM§SZ£+»U»†‚®uë@q­"þÑTê'mýF‡†TÐôämë¢Æå˜ïä&9i£LIÊ•é¶Ã°ðfùýhJ“Ùi6Çb£U«‚âÁ=m‚/ÛB“ÂÀMÑZ¨Ò*¶Xk¿|M­3ºr;â_dÓ)žã\7‘V­nšc^nr°ƒÈÖÆ­¨öð'ŸŠ† И_dgÛÃü|Ú=îQÂÓÉéÛì‚wðÔÚEãml°á _Q£ê\ÑηGÛðŠ¼º¼GŒžŠ|¯Ù5Q×d"níD­+uÈ蘩YûÖ–ŒS®r»Ãž±QÎ’dõ€¤FNÃ!`ñ@Mg…wUÆê1ÃhµJÆàøMJÆÑ?W‹Øaz QU…yéîÃ{jÚÍƇø'€»v¤ÊÒjÈ:Çßá6&#Q“Ï£B>KºŸŒ"zÿ÷{êÁª¨¦v²Åž†û)ÖºxÄ$&’o_¸§áÿHuÏ„e
+êd«B*n¦Ïk?Ÿg—ÿGÎ/DÌY]k³ZGh_aÛRwÂÑõ…‘t$e9ˆ}Ó¡ÊW"¬ p0Øb’ØGÞ‚„Ü'€B5T· þŸOÝË0zé+|h4RÂøskAÂx‘ÌÓη«53lÅIç7PQÿ€¾q¡!µ:ÎQ'¯Áñ“ð0º÷ ºÌúNU½VXU=k9kf^PhÚ#ª8Ëa »q#ã¨äzc6LFù"|x3d ²GI°ºÍÿ5{u'à2f[mÁýÿa³þÉíth ÷°LÐUk¡©ÜªU!ž
+Iâ3’Õ{~Yâà—Ù7XS ßˆ¹ H-(‹æR©o–llÒíßJ(Ÿ÷juŸLZºÛ›×‘ÈïË/Çåd¼@p¸,6>m•Ç
+‚•º"ÓJå  D²?ÃÀÌ"9ì»Zgù‡Xf˜ô‚/*@‡ñ(?î‹k“e4µCû
+·ÙE`´j¸ZbîdòXht²“†“
+endobj
+686 0 obj
+2245
+endobj
+687 0 obj<</Type/Page/Parent 539 0 R/Contents 688 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+688 0 obj<</Length 689 0 R/Filter/FlateDecode>>stream
+xW]oÓH}ﯸ+m‘Ó¤!iØÕJý (…. }™Øãf¨í13ã–üû=÷Ž¤¦íRMÆž{ï¹çÜoC:ÆϦ#:™PZœ/^^i8¤eŽ“Éé”–'ÇÇÇ´LçÞ7Ú“Ó…
+:£`)¬5ySÝzPØ;[Q¥Ã£u÷TÚL¤œ¦Ìø´ñÏ›
+ÏO^§ÁØ*!Z¨r¥È7um]ð”ÙR™êÅòëÁ1 †'ÉÖå^´½9Úñ©3uÀתʨñÚQíln
+¸—[G× úlªÌ>ÆìÒ³Míåù½ÓÙ——×ozÓÂè
+î<®Mº¦GS´Òjn
+Ùüiíë£I2f‡?¯u3´¸>§xG®ÚèpŸ_ÃK€#1VΪ,U>
+M·‡«&îÝMm²Ûrê4Ìí±Ö {+9„—j¥¼æ«*ȯÁ  è‡G­ûĈ°€&Ñ ß±¾é<g~=h`±Í;8Ç"ýþ FBÇ+¥×Å€QŒ ¾OM­ò—1ÞôCÏti=ÁëkûHªÁ}®À"øÖÄš8äpB¹³%1,iaaw#æ3p"¬[~ø¤G§O¯€%zƒÁm(ÇJu¯ùƒk™ær“oãZþ<µ—ÓˆÄñÕŽê®C{É]©
+1-ÛB0û©·8õB­µƒí<ˆ½æs”ÄA§é%Újy+V’·Îoö4¬² )jËÊc³N­Ÿ¦‚`å½ï¤^¶‚O m0æ–yæMkïœÏ?,¨R¥¦Ë×gó÷Ó¿"5ÄwÊy¡6ÛjÑúœ®-ËB, ð°u étª¡@ëý€²ßRp®ü‘Wì,¤k= Tá¤[üY¼ùøÏ› ±ÕºLï0~…o'³dÂUtqDW±t-…3 fµöŽØ:°®ŒÌ²’¥ð"X¯Qw¾
+€m^{þ ˆC&'/à
+´Ýä’ÐÂTil‡¸?
+´3ýÇ„_Ü*«´g°lPÂK.«)Œ»ž›qñ3Óì˶•\Z,Ù“mõÌ„Ù3”Ô ›úÔ¯vè¿%§¿÷–ò;8Ÿã#bjãicHèŒGB‹Dµ²M8ê9ÙuM_ë´m’Ýû¦<WhÉ¢è Ž©`Ðt ¿«².ô‘ԳȇÛÛSÊím²õƒæ9›ì±ÌÚ-Ö<‹z„éqn1|-ú"¤±Ã°cðd‡aë•æ9<“p¹ê$* 5À¯X˜¶úïGÀ}5Ö‚‹ï¯æo“›ï¢Rk[`râBþ‹Q°Áö.ÊØ¥¹"Äò\¬]UÆXß,°xÐh4ÅX=>òïøËÈÅ=eFCÌÛ¼§ g'Ò4v›Êirš ©\<æ{ƒÃkV:‡$QËt·¿ú F¼úHâd;ÅAží4
+ŽÜ\^H8joÆh»a×óþèÂå]Fvº¸éFr]¥nSwó#ËšçH+y>c'20"öò*mW·Á:ÃÊ–ÞŽ&Si·»àøl»]u[ÒþpÄ‹˜Œß<Íó$S*ÈP˜\ƒÝC¥)
+ðÿÉè`tŠunžÂ€ˆº„ ¥ÝLÙµTá-ŒÀäƒO‘•éñåÕ«6âáä8Áô
+endobj
+689 0 obj
+1909
+endobj
+690 0 obj<</Type/Page/Parent 539 0 R/Contents 691 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+691 0 obj<</Length 692 0 R/Filter/FlateDecode>>stream
+x­WïoÛ6ýž¿â–!˜8Ší8N\`’&i,n»ë†z(h‰²ØH¢+Rqýßï)ɶ’}Û¤¶EÞwïî¾ô©‡ÿût1 ³…ÙÁõìàvvÐ ./iû§Xâ ŽõFø;¼¼àÏü)$Å|a¦ùƒã§w8Ò§YL]žÓ,rÏ{4 ;Ÿ¦·Ç³o§wÃêL' š%’tžnÈÈ°,”ÝP¦#I´NT˜à•¦”kKk]<QTJ²š¬ “\…"E$ÂèÜ2äM×î;Ó÷W·-wÞtí(Ø¿Ñ£“þY0@È›W÷“öe‘G/œÜ>þù"©}/¢L‘á·ÒXô,
+%¬Ò9ò¦éÃ5•F”Êg™6 ¸ØÑ` 9¢«Ð–l£K6Ae À‘Maª„}«däऑ\ËÈHi8 ]8 §"[Ê8–Ðä³:*§L+ ÎzŠE¡×^ŒÛÊW†e¡ËÛE+Y —|IÁÐÍ[Tôs¢Rga1Õ¥B|p·Òƨ£Š¡Îcµ,A&Ñr
+‡Ï𠓦 æ#2$›vÉä¢Uä©^2 LÙµ¦H„Z¸ŒTËBæ–â¿
+4sŒŠ
+¡:¦zJcPÅeÊg”îZ+¤ZEZäTÙ*…žAÑ‘˜±blÚ«‡·V+‘‘ÈT°°q¥ÞI{ŸÇºžu{WÓ!-¹çÑð<M1TÇîÕ jÐ{½ÆæS¸ÒŠÁ¬ ؼ H¯Ö‰x–
+²m?RdC›WÀÄœ{ æôêáw^bèñãÛÍnµó˜Æ~†HE¾ñiA„à6Lˈ¨|…ƒKúµI„¸ ­^ Z5©×“- ëyø4¥dÛà'-ºív@ÜkzòÅäp¯ Ø×ÏǯNŽþvÉd{cd¿]w'=š êTDµE½â‹ôe™ê…Hÿb^Ö!B&[ÜføÍ“5†&ê5#;ïp‚ò‡à^™¿ñŽ{„ãíédpî×s·€Bòl‚eŽÿj´Ü"»ýÊ´k¾ññùüèÓ|ÎB_Ýà÷Ó;a?#ÿb2C¡B¢L±Ð"2·´é•“$Ô…=M¼ÍÊ^×i-6a~fxõ÷Í9ŸsùY‡›x¤;89b#­~à‹*t¯!4‘{@”ï–_Åx¿Çº
+endobj
+692 0 obj
+1796
+endobj
+693 0 obj<</Type/Page/Parent 539 0 R/Contents 694 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+694 0 obj<</Length 695 0 R/Filter/FlateDecode>>stream
+x¥WïO9ýÎ_1é•Â’„R?@9¤ê
+åŽTí©©*gãM\víÔö6Ô?þÞØ»ÉfÛJÕY{~¼yófòù O=|÷é|@§#J‹ƒëÉÁ“ƒ^2Óî—]àŸöɘ†ãs¼ðK+)ÃÙõÉ°z‚—½ø¶ð¶¿`èäöŒú}šdìp4>§É<èÑ$=º7^^ҳɧƒ“Ûauìè}þ”æ4‰rq1¢cZKZŠ/’æʥ拴rN‚VÖÌrYÐz‰7è­Òs³v”æJj¿BS!”öø!Áö{tÜ?Mð~”­eê•Ñä ù¥¤÷KSH÷ÜRÀ®Ì¤_K©)7 ¥]B4ùîTQ:O÷¯'lÀÊÌXÉnŽ~f’J‡`9Ž7S¹¤•ðËä °÷h4¼ØÜ@òäö¢gú{°“q2À÷6ï‹wôÂèL-J+8±}DÓ`„z!÷‰!W®VÆz¾‹kb]Ú˜’BNˆ9€ÒAò€ˆ¡é l+
+é¥MèQ3Š8Òf ¤
+O-} rØ<‰†øÎÚØ'G0°–yÞ%¡‘ "¡„Ž¸6€ü'1TÖ뤮7
+y£ÂȾxåGÃtD³ØäæjÂ*š¢ Ó˜hK4,s.­£Î£_wR—n‹éž¼YuºÔAŒ -× îÜK¿4fÞ‰ÃjPKæU%lFû°BéÃ/¤]pYjÎqæRÖr‹¾vèdÔ‡¡èéåt
+uç§ÓC8AIʲéäçÞª=@lõ
+¼0søqfMAR¤Kîjy‘j ¿i¬sævš˜‹ `[aö±¡7qæ9m¤c˜Ü’—=Œ¸…ÓNj§¼Âåç-çÚt8]cQö¿ÝºR±R^䔣¡¹l8\¥%ö3üÃJ[égO]á¶àOΖ&†¼Ù¡nOœ-?ƤFf°N%ïlÕÀ]+‡Ê’J™J’»®§yïe1e[)îûŽÛäîê>®.R<‹xµÊÃ~
+÷|Þ†@c8d„õw»†½Ž ƶ΀[ºTZvi{†•Ö[“ÓƒÐ2§oøë†Ù<RäXBêo:Uý¯b†ÌÃãVŒ“ß°ÈÌQ•/° ÈQðÌm   ‹£×Æù:7ôõ‘ñÆþÆ–RS`€kŽÖÊ™1> ‹ü1–ýzÓîÇ·ðÎÏ}ËSЋ°Ý‡1r§RkœÉ°‚Ç玾q¾Íý94Ø1¡ÃWf¶KC5½1LØCd<XuAÇËAØc9Í«
+a7„[èX”ópD ßïCb³; £ÆÀ„Wèÿ_D²^z°ë³»“Ûqõ¡ ?$}Îã`z¼º»¾b|b^ܘ´, ÛÏÇ}DÎøØ5?Š’¾?Îé¥Æj\†ÏEîŠs¸\ÑßCö˜ÆÑ Ï‡ð,žõù lü ;†Mendstream
+endobj
+695 0 obj
+1681
+endobj
+696 0 obj<</Type/Page/Parent 539 0 R/Contents 697 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F6 9 0 R/F8 10 0 R>>>>>>endobj
+697 0 obj<</Length 698 0 R/Filter/FlateDecode>>stream
+x•W]sÛF|ׯ˜â å*’–d}ú%%Ëv¢:YñÅô¹RA*µäš
+ò-´_»™H
+~eÛªà¦V‹
+0±&¸'"b,\pìY—8:¨°0Yø‘ßèÜ”¥v’Eö6*¬F\>Ç=”©à
++êG‹hœ¼KÑiöCÈ5*ˆi²ª AÇùZâ|n̳€Aíjã½±Cœ&
+‰+ñˆ—y^cžƒñ.†5ï抲ã:Ž ¬ó*_cÁ`”½V“˜×À³ø%ªÑ/P<[S?½º™]rK½Ú7Â¥ücÎ(Ê$èߧtYòÊ5²_?%ž¢eÇûñ²2E‘ߦZ²É^ˆõÌÞÞÎÙC…A‚\÷4‹«mù½ “„•—u
+O¯Î$™ëÙõ æwg›Ò,['Ñ=^»\›óÿv\7ÔõK÷bø™ßxºn“×éó«sD—/Î8Ì»ùÑ¿þ ÍÂK¢endstream
+endobj
+698 0 obj
+1803
+endobj
+699 0 obj<</Type/Page/Parent 539 0 R/Contents 700 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+700 0 obj<</Length 701 0 R/Filter/FlateDecode>>stream
+x¥X]oÛH|÷¯h8œHŒäoûpÞu‚3°ñåÖ:‹Õ‘C‘ÉáÎ ­èß_uÏ’iìÓ%0 ÑätwuUuÓž,hŽÿ º>£ó+Jë“Ÿ–'?_ÐbAËœ/]Ý\Ó2£y2ŸÏi™ž¦…N·ä M©i¼n¼#“Ë÷Öš¼¬4µÊ´:uZÓ¤2ÓÈ• eÚ¥¶\ëŒH­Í«^}˜’j2\¯´×rDç´Mî—dì‡å÷“9ÍçÉâŸÊo¾Ü?‘„ÈîŸÕj[6R´Vé¶k©ÌÉê?»Òê,!>h†rú“®â¥³Kšß&W|úcNªªHWNS®ÊÊM©lR«¾;U¯ÕßÒ\wBATéWÜIÞÐZûÖ K!‹y(è#Ò'Û5H¨EBÚ“·*0Öl¬ªG•¹.-HḴͺºågíkÓ$ú‡VÆl‰kVÍž´µ|¼nõ.‰‡]%±½é¨P¯šTšj'iª†ž–l_µ2p `´Îã’'àeªÀØA'ÕHÈDZˆ&7‚øpN¹‡õ‹Ú"䛂§\‹þÁg‡öòçVr@ÅqÔ×2-v%ˆ3¥3‹v…„…—•y®­nP%)‹Ûøq&&·þUUàfh^€_þ´<“éòzŽÆ_Ü\ãó~ðt˜™{@Ž›7Ô¿In’³ä2¡oe“™ã\¿»u^ùø\$sNñ ð·oÌ7]Ó8b\XÆ4Rq¢ôªï
+¢ ò(1;=ó›–(9vn„PeÒY
+¬55fG®Õi™—€ÛÖt›
+,…$mPÊÇÏ—;
+z2^߉¸õžþ^mÓŠsÕmn¯iF% çPà™g‚qwÄPô
+ÿD[³@ÌÕª0µv«U¬Eú?*(+]
+瀮q”Hˆ`Q^ª€°dØ 4X Ž Ôªl<~ †`\N¥eÈW8ÊìÈl~—Lþ W¯Š
+Í höÒÿBie h¸½HkÑTDAS"«qTÈûâÿöËQå»5² @ΙOoЕ¾ï”[SËoÞ$û‡°|ßµ”³p ‹36=\cF¨W8žZC—l1Œa/įÁÑÝ]oä™-_õD8‡‡]aº*cb± ÐIq7MË KòxÔõð,fŒ#ÆÉ÷® m¤Üè]›{29”ÐûO/0”IP¼ÝK Ô EöÒàj½d
+©7vÿ‚Ú=®ð<‰"Â…®àÀ˜X±rªq&´ÍM
+Wãa €1
+ö®ÐFK*·5Ìw”t+ò¢ƒ‘ÏzåÎ@ð}øíª×I×TüÆ2q-ýžþ)a£— »oÇzi•s;c3‡›÷ÚM¢Ø5!ù§§ŸýíëòñßO‰ÿá1ñ ˆã
+ûøù&¾',ÎÉ9XÈ Ôéóý—Ÿî £à;ûÖƒI1ͱŽ3$Rÿâê·Ï®Ïð†ì4¼e±ÛEó¶“åÛès|€#þ_]ÿËôDî¹ «‹ë D—/Ï9 ^ýþsò?B$“endstream
+endobj
+701 0 obj
+2000
+endobj
+702 0 obj<</Type/Page/Parent 539 0 R/Contents 703 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+703 0 obj<</Length 704 0 R/Filter/FlateDecode>>stream
+x…W]O#G|çW´.á$¼ØÆŸHyàŽ\Bt‚}º‡8BãÝY<ÇîÌffãŸê™õ¾païzº»ºº«öŸ£µñÛ¡a—Δ–GfGgŸzÔéÐ,ç£!Í2j'ív›féÉ_ÅSZP·/êÇñZT+)5e)µwde*Õ³ÌH,Líi2£Êš\Ò]_âFá$™<¼o®¼Ÿ};jS«sžtèä¡ÞKë
+wñ—顬 P8~2«´ÉÕ匌=¥ÜXT
+ oìzôtsßÍåäï„ý:;B%4œãµ7ⵋ?”ÇÊÇMå¸ç¼2Ú•>JFI7$ôUé̬—7•öYZ>z‡ªé’W3[Jœ­iã—J?’7伩hmjr•LU¾æ…FÒÂ/Q²ðáb¡žêbØ
+“
+¯Œfè¸p÷ó¦D˜BÜ*O°ä ©©‹l*Ï'6à3¤ÈÇRœ.ȉr×PÔ)  ‰!uiizóa{A8¤Äi»x"®„ŽG««ÊXCêÔ®+8•pnelæöÒŒ’Áÿ4¤>LF¯¸2Lhº–a¼kȆ²üJJM_Ç}”À|¡¯Æ>9aì%íز~ÓîNwˆø­î(¶íÎxÐYkkÁ*È’Ò©±à¸×@RÜ€¸ÀÇEraž0+ñåþ·@·~›ÉéÖã-81}=i¸<|=h×€Vé'~uÌ $C óX»SZ`´–âY2«(“…äô”Oh~r¯R`‘D*9¿Ë ÚÀ/fn÷¶Y`z”¿?æàNÎE]x´úäôDsü¼›Ìç_Þz¸®’äù-+ÏTO­NàU¦5ŒæMŽù´@ºVdÌ|ÎüÖ¢”ÉÝÕô˜T¾?*
+ û£Èóy3_Ç CÔÐmo˽ÔŠÙp9¥Õf^„ÌÛ\ålë4Eâa¸öÑuÄøiZ ºãÀ EÀH/¬§©k:£+éžxO1E§oãr¼×_`~»½ÛzŽ)JJ§%%ð}‰Î*¬ÌŠÕB¤OÕ° ÚBn‰¥’b
+P°—…–>‘/ß­¿QCGl*C¶Ö”[S†¢Ó‹ù|¥´ö`àÚ³çÝOƒú
+)çj‘–ÎØP?K]‘ñŠ†‚a"š´Ü¡báó…XD&g¦™_UÊ3^ÁP*Ì+žŠë/75P ’¹gÐ(-!Ê€²Y܃æ@‚¶r r,ó€Y®,zé1«<÷=5•Š» î˜Úÿ~SÍŽ, {8dkoêqz“í­à0('kM‚§‡ÌH÷@¸ª]ŽŒÎš¶pí¨ñÊÎt»½·Õ>$g‹7æí¿¿âGÉ8¡«Û›ËëÉÃÇÛÉìþösâ_<]ìû›+S
+äü‘s6ýDSv‘Öt†£V°;fÇsgœSÜÁÛnÞ4RÉ_jüW§ßß&ü¦ vºã Æ;6c)U%u¦^°Æ0‘V=*tZÔ[mZ¬é³Ôô;ͤ­ÐdÒ…ö†äñ±(ƒ+ýH‹:÷B°àhRap!ô~„QØäßa¥´Ç¥ì}°5£þà“ÛÙ¯t±Û8ìvoØa¶¤ã×XÒ‡,QL³•p ‚RZÉü
+ 9"ñþ<€Œ°:g s)e3&a<öL
+Ö »îÝnÑn·Ã"è1äíUﶉK—²~ÁŽsسO£} P|T;™^Þ|¸d+üê•Ik~6 Æ—¿Õê„›[Ã.žç²“è¡yÀsõXC]ø1ãZ¡:å÷PÞ©ô*HÓ½%£ìBÁáS{ÃØNì÷øLÊŸGÿVCendstream
+endobj
+704 0 obj
+1723
+endobj
+705 0 obj<</Type/Page/Parent 539 0 R/Contents 706 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R>>>>>>endobj
+706 0 obj<</Length 707 0 R/Filter/FlateDecode>>stream
+xW]OÛH}çWÜ—ª©(+Q +´"°ÄUÊËØ'SlwfœÔûë÷Ü;¸&ZU•hÏǽçžsîõ?3:¿ÓÉ%ÅÁ×è`úí”f3Š2<9»8§(¥£ÉÑÑEÉÈ­EIn-‰^T™ê­¥yD‹«ûɧèÇÁŸMN±aÔ*ÍFJ°1–¤JëDžË”„%©p”!AU.TI™Ê%‰2¥Ê¨Ò‘ —£—‡§¿þ|zx~¤­6¯Øï”.I›öÎÙÉä˜ï ë—Ÿð„݈ÙQ%ŒS‰ª„“AÐ.øÊk]:£sZŽnî¯îæTÈ"–fLFÂ4ݺ$¬Ëí»{¿Šäµ®Þ¯\~šP¨¬(·%gjI‚{XLéE˜Š>Å1ݨ•,ô(ÜÚçèaЫ
+•‹a²•Ñi8;& I:£íZ%kr/Õ=™Š\—+Úù^ ‡å‹4¢l¨’ºBM‡Å_i
+ÛÕ€dµUåjLVS.ÝGN°!§)É¥0ž$B™áÉ·àBÓ»™lc,P€_kÛÕ\ûZ¹R–/H…±°2`»û™ „‚‚S(¨B¹ê‚¤Ò&F„ÈÈ(§D®þ lR%*S„Ï\#F• ¥œµï%Éjµ9.`¼ŸKõ“n„,ti¥'™©K,ˆ… ƒÛ{’åF]8j†ÈæÞ\
+ÑP)á
+ÄÌH‚¦Ã<™%{S
+
+»Vú5‚yuºb·aE ƒK¾;ÐßïõJ´Ç­o ¨¿'ж
+$ô4S²Ý2«ƒf'}1,üúabžÅû‡ˆEG¦–àáȯmÊ^¡lkÖ=ˆÏîŠòâYͬã^£iþ *ÎQBha¾q›Íj¤ÑEþvIP%\[
+½’ùYãMS~°ÍB;<dŠø‹Û—#5ÁüÙÈÒBí;Ô»‰ex;<œoõ‘ùyÊ`–AEÐÌÖ¨ã/=«Ê1u2uØñ¡Ä 
+>>#V¾Â)|êéùéäïÀ8ñógþá6:øûà?Q$$¤endstream
+endobj
+707 0 obj
+1722
+endobj
+708 0 obj<</Type/Page/Parent 539 0 R/Contents 709 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F8 10 0 R>>>>>>endobj
+709 0 obj<</Length 710 0 R/Filter/FlateDecode>>stream
+xmR»nÛ0Ýõgt³’¬HB7; C“´Q·, ue1¡H•¤äï{i…÷ò<õ'+óW )±©¡¦l×eßn+º'uÛ ë‘‹<ÏÑ©ÕÖL.DÐ;ùOôn’ÚâCƒQ¾îoðèõ$yx½ ¯œÞCÏ«Çë«ç »ÐSÐ^¾B%CJ5ž#^t¯YŽu±%+XñyÍd~g ;©ÞóyvGžBY‹*!t#@Ú¼˜–,fé£Vz–‘À^<ÍF+µ³pCZÁÓözå‹ „àÎÔ~±¨íþ‹èà6ž¥$-Xwt uWnšÙÒq+Ž,CÇÀRö:Dÿ)èM—q¨Ë ›©Ú†ï%O–ÊÚSeE݈T'·uV{Øm¹÷J*rdê01ÛÑfB_/¯Ö˳U+ZQ
+puƒÞü’Æe1•’ ßñD1²ßdä—“SºþÜ1S ÚPH¨US‰–ÿ!Îþ²>™ø™ý³Á•endstream
+endobj
+710 0 obj
+383
+endobj
+711 0 obj<</Type/Page/Parent 539 0 R/Contents 712 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+712 0 obj<</Length 713 0 R/Filter/FlateDecode>>stream
+x¥WMoÛF½ûW zrP[¶dG²{K‚Ð8n­ =ä²"—âÖä.Ã%Ũ¿¾ïí’M‚"Ž“»óñæÍ›áד¹\âß\V ¹ZJRž¼]Ÿ\ÜÝÊâRÖÞ,W7²Nårvy‰'Éé»\U®åv&Ÿ¬ÉŒNå·uÖËF7ÖV>›ºÎËýúÕúŸ“K9_\鲩|ºÿ·´ÞØ-OmpGènŽ3tw~5Ÿ-xüv6ŸÉ›oj•4ñÔµÌçý©ÅŠgÞÛFokÕgÅeÑ:Ý|0Ií¼ËšQ,Òäµk·¹ˆ’¶¼`à’+ÆŽÀdaR]#%%¿ä®Ø ¬›â—>ùU ÍàŽn«­v­Ü,«¶aZÚîLíl©mã%s5,ÏSê™|ÖRÕÚã¥Ä”–}J§Òñ2==Ã}w–wc“kyTåFMbò­i´ðD…¸jUzAZJ¼+²l\¸û<uœÝºD`Ñ» 8š×B¡LYá%G„a|âôˆó_ï$QEáÏä¡h·[³ò¦E´¶1I¼ÿÁ¥m¡q‚%b÷ªDȺޙYu¦IrÆ ;®J7qy¿–Ô•
+%@¤µÇ«J+
+¿ø_Ã×ЙC«\ß¼|<öæíl14E ¤C\´xq7°‰­û&ÄÕé¢'ë:#WÍÚ'W;àšš,Cƒ€‹¥Ku)^ëžÔ„…ea–“ºmÑ|’EK”‘D‚§G6äÖ¡+ ŠÁæ90°L …Ë  ¡o¥T©&Î Ì$mÑ€×D˜*¡CÉšÎI¬&±g‡ Oƒ®Þ ìY«ëP
+µœíúh5Û°‘ )w©Ú5ôMj8ò£´bAõ´Ç&I\Ku€±kÀx)õ%jhË ¥CÀ>ÄŒw‚ Hlüqß#„ž†’´!®j  ( [ ‚5h5í
+.ð¤ÔLŠ•ä\¦B¥ú{•òý’â^×úkk(Ó?˜íré€Y)´‚º°Æ6â[óo¤[/uÇ1…Ô'¾‡" Ò#¢03¶1F2"3CzlM ï©aÿ‡ú|WjÃåàè
+LH«Òóˆk €=†ãq`IlC:Â. ²£>íQRc¯6HØ ‚O½Â :}«¨*£#"F&Ð ÿ9äÅÇSo~»œ-0õæËx:ÞHogWX`8Á@#î”òÐOáHþ߇ñ7‹õ›!ÑPE•æ<PÛ°Éãù¹.T)–rã¾Ql¢šrY[¨J]n
+‘Ý?>†-câ3ä¿
+endobj
+713 0 obj
+1671
+endobj
+714 0 obj<</Type/Page/Parent 539 0 R/Contents 715 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+715 0 obj<</Length 716 0 R/Filter/FlateDecode>>stream
+x…WMsÔ8½çWtqª3_äãÈn-‡„,
+¹È¶Æ±%#Ùãõþú}-Ù¥€
+ÜDÎà*Q‡û„•„ÏdJqÇÑSS
+åsát-ɃÔT˜ Ïj>'é4{NÔ6zX„—¾^|Q:5-9éœBñ¨BLC ¯/£mŸ00*:2ñA™ÆŽ«uzà3î‹ñŒ”£X*1þ¡¤vºZ¼HŸùÞØr–èÝÇûÛÏÏãAžxô#Úå…ßZ&¨AØŽkP5‰¢0­ó6©¬¥-¹£!+Seer7$f‘{ £kkŠ=G”Vèõ QàT [«¤)„%tÀ¼€ Œv›«$§Ú6Ž_í¯ñ°r/­Ô‰LçØÞ¦©âdyw>&^YsP) ÝiÐ_˜pðð ’¡œp?z<M–‰¸t{rjVå½I&Ýóâñöþù5¹Y—@ÈPyõ j?2o
+ÝŽ“Ô0%UUôYºÐ¢YØDT"V…ª;°½8 f."â|If<t’[£Õ¿L"@í\klʬª[ ʇD9,¹Û“wX3®6h0ðø¡±8‘´¬ÇñyÑËþ‡–?¿öMúcwŸ ·›~n¯¯ðs?ˆ²¶rC+ȃme{så¥}4–›h­
+Ø„•¡7­è˜†þV¢i\g„’+Žåè“Þ¨Ü
+¦´ö!+}^ M@èÍíøïÞàóXñÎTYäå› Û
+…6¼ ܇§Y¬5:AlØè‚ɪ™6!ÔÛ~»Xôק§,(²"T€†Rû'Û
+ ìÂZ0™EÀ?bûˤ–,¿60ÔOOžðéYC<`Rn$Qs³†§ÑœåŒ ȵáÅL9RNˆå'Kæ\
+~E…ð
+¨ò8HY3XÏ~åeý&E“2élÀ³Zd¾µçëÏÉVyhÏö {·©Œ)p$S°Óg9.Ÿ™W€žw*h‡ßÍÀk6c#F#y´ªäïÎoÁ³"ßW5¬3wŒíí7<áw ÐÏ·ìœ7Äœ­¶À²Ý)Y¤`§ Ø¤Xm÷äû Û¯çƒ?3ÊÞàg‘«ÆV“}.”ÁŽ€˜ø@¾Ÿ¸´d¶HÝ”^ªÃìfx¡o–£ßqƒ2ñ¦‰ýT B¾˜…X˜=6³|DÌ#•wsìŽ ‰ï™ÿ¾®Œè#
+)ý}öüjÙèendstream
+endobj
+716 0 obj
+1690
+endobj
+717 0 obj<</Type/Page/Parent 539 0 R/Contents 718 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+718 0 obj<</Length 719 0 R/Filter/FlateDecode>>stream
+x…XMsÛ6½ûWìøäÎØ´%»þÈÍqš™캕2í­‘ Ä$
+ºÈ...h™ŸÜeWÙ<£'UkZh÷Zåøw[…|óÓòn^ÑložÍopód¹Ñ?:}JÖÑÓbqJ•'E¥V¡sšÂFþ†Z§½nð¹¡Z5;úúôåO²­v*TÍšüÎ]ûŒ¾RÆØ­g÷t6»Ìæì6 Ü/­«qÉ6ä»|CÊÓÆúÐ 
+Û•Jy0š‚:¯Ý›K,­4!k^uA¥³5UYj‡ø¦^mçr°>#;ý·ª[£O‘ž°­Œm4ÅL¶Ö½àK «V»Þ|ÊëM
+j…ZšrXj|§èÓÓ‚s}EäT߬‰ÏQ_³ôh~1V#â Rmkª<Ö¸uvíT]3vª&hW*
+Ás£uÁ™O"® ‘FÚ.L‘’0’(÷°Ÿ?"ÆADIÞ.X¬(è8™:ŽqÇs0ß' ‘“Êë,ÈW ¢Á0H%Ãf¨!rî[Ée ÷È.Ò«_–Gº4¿¾„’¸º½áÏø Ú)§ºx>¿Ë®”ñeFϦ[¯Õ
+yßq)B/AeL…±ö³Ç³.2ù½kP‘Æ[ziìÕõô|ÿ‘€fBžˆº‹|½òÁ) V¿zëùN Á¬«þ‰
+‰‚Î75v ÒÌP·
+endobj
+719 0 obj
+1819
+endobj
+720 0 obj<</Type/Page/Parent 539 0 R/Contents 721 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 232 0 R>>endobj
+721 0 obj<</Length 722 0 R/Filter/FlateDecode>>stream
+xWÛrG}ç+úM¸JB° @o‘­ØV_bãr\•viwÏì‚øûœîÙ…ÕÊqR*_3}9}útÏ÷Þˆ†øÑ,¡ñ”Ò¢÷rÑ»|=¡Ñˆ+|3Ïh‘Ñp0i‘ös³ôÊ(wî!Pµ¥rcQêlé]N+“k*eºÔ¾0VÓ~£J*\Vå:ð7¹S™œp¸ª‰T…liRUg)Ýèô”ÍÈX¹ûbqßÒÅh<HHßùLû-Ø«±p²R©¦B=ÀºÊ2c×0IVﻆƒö;ƒ£+ç髱K;L´
+‡sRyŽxªÕ:CBˆt©;¾3‡|àWÎqðüýåkÀ'`õ·ªø{M‚‹_6Hök ˆ ¤nk´ Ð±p x/ƒN+oÊÃe×£Ân?Þ¼{Šxà¬øt (¯s½S¶¤:qÀã5
+–©2ºFÆnÿ ÿQÔä@Ÿ5ŠY;Ì\Z(T,“ÀX8ÿ "]*“‡óë¢ÚÐ4&4™ÏðÿÅ*²ìšF“Ȳ«ùõ`ú„g׃ ~è ¢6¼ñd»»¥„¹ò¤ž0Uû_A'P â›¨õZ.2è^Kꕃ˜™Ûz¿Š˜’À†øƒT=(™#ÚïP÷ŒYº2¸û­ÿéîöÛ‹ÈÂìpD!7ëM™(3«•ö¸Çtúòþî/0Ú¤Ú(Tƒ¼²kMnÅÞ–Ú×¼â*qðBÚéA² `iÍ€ 
+ïwÝsÓ° 8<^Ž„ݕ̾º¼gîÝ’¢yÑ %!+iQ‰ÔdǸØ+IóàXP"Ƹ㹶émWf]yä
+‚¥ÄÌMR²­w©i»Í «£†‰M”€3 °ïŽ×å½^mxYÀs¿wòjg.‚& ÇŒ!qGX@”Ø°ÜBSô*šˆ#$U^†X2`ÄžX_™¡uF[àkB †ƒílåmNBkÔRM‹ +*³%5ÿK iÀº")ÙehÓIÌUxTÌÞ:Ú«C[y&ã1ôæçÊ3¾¾–Áršp¬<Wú$ÙÓ+•n4—¡=k­¹A
+¥j«–x¡oOU®ñÛ-Àå Ô¼¥âKE–ƒ[QæX ;íòi!ÚÝÚÈj›ü.úËëÅ™×ë*Wþ ,Š48‡îcC„p¢<Á¾ i*·Ø/±jl|1Ö©¹ÔäwZŽÜc \j(ɯì±õE.RVJ“žÉ¶°e*ï°SAÙÍŠ˜Hña" Rª ƒ+ËŠëÙ-¾Q(V^l?`°Èsœ ,™>²€×pPN^Ÿ8´Â"ÊÅƆ¹Ûö@<pã
+tùz^¿æFS.îtv5˜óBÑøèÝ= Ûöcˆ+p_̼’³þÿ|½LfX—ÓaÝ öþZúÑendstream
+endobj
+722 0 obj
+1779
+endobj
+723 0 obj<</Type/Page/Parent 539 0 R/Contents 724 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 235 0 R>>endobj
+724 0 obj<</Length 725 0 R/Filter/FlateDecode>>stream
+x¥XMsÛ6¼ûW¼žªÌH´DË’==tœ4i3Çn¢Ž/¾€$("æ‡JVõï» ”Ìƹt2±%xxûvü÷ÙBæø·u(+‰‹³·›³ó+Y,d“òÑêj-›DæÁ|>—M<yÈb³ªÍù(M%Mfì¯o6ß°+îvÍÖÁŒn’Éc¸Z‹¹ì^òÝ,\K¾ß`³¨<¯ö†´|½¹}{#*)LilS«¦ªyF­óƒT¥["ªÅʲ1±j ž:ÎV¶_ñysþ`ÊðÏËlq„<ëþ·w’ÒÎÙ*•¤*”¡¹"Òµ Dz3ÒZ<²’¼*·º–Rë„^eêY‹Õ;?5›œ¦â¸jËfpÊGKϺº”ôYƶ>!YÕg7Òˆ[%¦ÜºÃÁ¸-øÿKöw›;AÖmͶD$̉=ØF/Ï|LåPµ¢j-bŠ]®é
+dœÂß¾6ä›Ç7SÁžTç-‘tÖ–1»¯áP}C,!„‚NžË—ßÏá2¸–‹Ë9ä¬Åeˆßþ[._ÙÜs|]8­;¶t¢tQ•ˆç>‹åST¢KãÃQ§¦`øz\œ>ý^H¸¸|qìéw¼½X‹“½tŠÞ㨷ÒÇ1v°A¹|:÷:¶·ž~ Î ,LPð©
+l{P£9÷™‰3±í£žó¨\༮”ÇÁÅóœú|
+}/v]ëTQ:~!6Õžº8°WຆØrø\†DÓ–OöÑËÖÖç¸OøÇCõ¸üåÊŠ;çžB9:-:É‘…ÓQ\¾¨šµ&'—9E`“y(Bü»ð|‹õ}ˆ¢ñ.xlXôüÞ“ž».öµ4Û™Ë0z‚þ8â⮆’…vè¹ð˜4Åâù»#æsRWÏL¯âÐ{•î~”ÁÃB0Î'­Ÿ´\^ætÂÕ?"ùrKR"ó¼KBÇ5¸,_£7«Íeµ
+V¸Ç Ï4‹@Þu—?ðõ™qEy „“évð¼¼DR~¯¿T ã–c#ÀÍÝl³
+Â$«ë Þœ<.ïëꮘü=Û…GÏf~ñlιú•Ùr½ìÿê±ZpJöçÙ¿kE@mendstream
+endobj
+725 0 obj
+1988
+endobj
+726 0 obj<</Type/Page/Parent 539 0 R/Contents 727 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 248 0 R>>endobj
+727 0 obj<</Length 728 0 R/Filter/FlateDecode>>stream
+x¥WÛnÛF}÷W ‡(ˆEŠÔÕA[ ië"IÚZouQ¬È•Ä„äª\ÒŽ~|ÏÌrIÊ!PDqwæÌœ33»ÿžE4Á¿ˆ–1M”goÖg¿®Ï&ÁjEýGµÃÄâ³ÕŸQ< TiÚb턦³9Ý«éћŴߴX`©ìlƒëî.ÂË ]Ðz 8 ¸_§òzBëdTS?{±þx^Fn Ì΀|ŽTS›Ä”[÷º51–÷ã1ðšSû õIS’kU~«…ª í‚D%{ý­f‚ÐYi¢ñø6«÷ø(7Y™~«Eí{öRVÚZå¹³1£(bzÆ`xFãxÄœÛõ>³t›åù9mî(Õ[Õäõ¹ßJW¯ß½y'ò@œ‘QØØ*ÌM¢òЪb£Ž}ŒºÒšê½¦Ba³³’š¤)tY«:3%e[º3 ï›Ð8š:4·ª¬©6÷Ü[SèÛ½Fbunu@okAL*·†6M–§âªMwJú³NšZmrMªL)Ï6•ª2m‰B
+dBóÕêr¢g‘{e‡—m¦°f>=òE0€4 ŸE0Lµ <j·ŒJkA}²zM{s#Ã9zFì8}Hè™9zt¿ŠJ­S` UM)1»sïÞ§àØÞˆR¥ ä[*ÓìöäaŠE¶·A™CæŒcVÑ¡2]±¥AL9ÓgÏÉçíD„5@=(Ø%
+§–К¦Jtèa„ ßÿiá •:Žb`ÿ­£~kЛՈ"ÑÖªêŽC‘ŽÀiÞš<70¹#{WlLž%HeùéÕ×ÁÎK[óʇ?ñ“Èß›ÛsR–8C¬ÿŽ
+{Ÿ}VÚ³^ľ?;‹§ˆ?Z²ê
+Š/f <åtŇоh汬œÉ|ï„´Þk‹š@¼©¶I•m¤¨0òK ùÔÑFÔ 8oŽ<·×£Õõ †Ú¯‘o¼†U‹üîphx¤kuÉu™èkLšÕ­²üûX"èN(…I³m;'³2É›Ôsúaã[oKà_»ÜlTþ7Yðäìêç~›ó %”{Ýì‡ ~zìÅ3˜eýÔÈ#º |²Ðy”Ðô_ïéùËçç®ëþòáÝë·ï_ú×lªW|%˜ÄBf µòÔ’ÙçÕç>ù×rzJ}Ûkwtè®='?ÒKIl¼¼å3NM–¢EaRÁþXó±|ÙBçm°ãá¯&(Ú‚p»™‘|?…}añð‚â¡Ãµ$ùQЂf,PNÁß}|8Gøçà Å/ßOá_ðÍéaâáù»Ð»ƒ„.qH‡ øŒŽ®Ò¥†3Þ0ŽÀO9ë  Q~8…~º’±þ?{éŠñ^uCåÜé#Ï8&3íє闇Sžã弋瞔“®ÃKˆ_¼º .»|—ÅMÊ]r~¯ÌG:ý2¼ìˆ^¢ÅËÇËXî½n`ÐZ[>û âÓÒ‡F&úl9C×”u 9KBæœýÉúeendstream
+endobj
+728 0 obj
+1521
+endobj
+729 0 obj<</Type/Page/Parent 539 0 R/Contents 730 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 253 0 R>>endobj
+730 0 obj<</Length 731 0 R/Filter/FlateDecode>>stream
+x­VkoÛ6ýž_q×¢ˆ‹Úò[v CÚ$E´éÅ€~¡%ÚV"‰*IÅ3°¿sIÊvÜ$@±5…`‰{ï9çòûQŸzøëÓd@Ø’âèýìèbvÔ‹¦SÚ=ô/= ðM'xö§xhI LÅ[/ÞŽÄüs;Ç£hÖ ‡QìGËyû@„îeNh¶@61¢ÏR7Ü£YÒ"þ÷š–Ùƒ¤uVγ2¥ÚHmH`C‘“YÉ<§o-Uæ*¥LeJÙ‚ìJnh%°Êʼ”–D’Hc¾½};»óe6Iô9“?? ¸®xG*¨ßçäý[N7ŒÍ.c·i¦˜1Áüý„­,ª\XI+UÈ4Óo·ÔýÂÒýJ]žÑEQ¥í¾9ï¾¹ ©ùDâ1@"=†.vo/&ðGO'âz! `Ú ³Ú!CñxMw̼#t/O
+‘•®{9Úî×ø
+Z¥åùØ`¡ò\ %%ª(¨Ç.…¸©‡Ûß5Ai¡Më•Dê>Ò Dj_:»úü8|‹2ã6-E!y¨GþÐQÛR ¢ª5}…øÔÚ„ü‰ó9Øú,-²23V «ó»]ˆÖï4Œô4
+)ï–±Î+=d¹\JCɃ„ü‘ „lÔJÙ×~tÜMÝÚèn®‘w(æ¢Ë´›b^ cÖ)uîÈãBí ìÜÒ Õ
+ûb­‡¶å@mš×œ<wG¥ŒÉæ¹'—kRº«ñƒ¹ ±0KÛ •/2mlD4S>e t?¸9ûCon`ø¡ñ·6a]Ÿzÿ“ê\žeäê¸ ‘¯ÅU -J•¥ŽÊ<cdƒ™Öâdì¹fŒøDº.K¸VýdV†:BÒ?´Ô²j MŸMs¶BȃC'¦u"™œ
+üøŒ1¯ÅF™œ¬Ï2ÐÒ´ó°_ÿ¨×;uÿ¥±§ÚÏjú`ÑÞªÝYÌRo“Õi‰C×à„ƒ"1‰Ê 1gÕ0jáÇ7ç­píÿƒY˜ÚBQ§~³àG2ÿÎEr[ÎáÚ¬~·h²úûu›,¤}‰ÒåßǽlÓ•«— ÛZØæiÌq«àpãé ØfiëÃÅõ»,—ý ·±f|^ë÷f뽑5Àâûí'¡ƒîõÜ.ŸZ03W܇¸3Ý¢5Ùé;ßçOëzþ©Ú°k]ù›;kJŦ1öcTtìßüFÛC¸éA\¸Åž>.߻ړÝ_0ÈD”áT„£LBep`pgW|UÒ[j›Ü×ÞB«‚Ü*ˆíYöϾ¿”à—Ñ´õ亚[ú
+§áÄíãÎ;¡øÄ-ô–úE«;™X:WI]Àì\KðªN?žD€v2p³ýMŠf ” B›—KC×µck4An^<äÅ8Æþ8úÌñf×endstream
+endobj
+731 0 obj
+1278
+endobj
+732 0 obj<</Type/Page/Parent 539 0 R/Contents 733 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F1 4 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+733 0 obj<</Length 734 0 R/Filter/FlateDecode>>stream
+x½VmoÛ6þî_qÈŒÆÅbÉ’;.P ©“Å–—-Ú†aÙY¢#6©T<cÝß)ÙŽkeÃÞ@‰tGÞÝsÏsäc'€þ0 a8†¤è¼‹:çQgàœÀæ¡îñe
+e¬õ2uƦÀ­¥?É
+t&«<µÄ6uÌ&6˜¶|ÐøþÀ`%+ÏÃ÷|fßî=·‡ËјÛê u\tå/9â‚5s‚-igbf]yÅS}÷ö™É‚¤\±ÛÅ™C.e‹¸Ê fÎò\{õúꙎqÉ,|Ø,lT*¶[î`‡&…ÞçåmAôºv/Zi
+R•dà?ÅVs¾®æz¥‰eðéÜݵPEP,hñPÌT
+ÙïÜvœ~§÷Ͳ{%BËòp£á,ÆÑCS)¦K)RÒÞ>èbƒ'GV<~—vfÂZ]v&‘Ü¡¾eü‰Þeù¯É²r·IíÕ¼qRŸ¾Áxì5·ëÞíéå»S¸Qò#ÞGàL&UeÆt;$ÀúÁx‚ÎýIˆWð´çÎuˆðúL€DtÑp]òMFx °~ã}À+Ä·?
+endobj
+734 0 obj
+1172
+endobj
+735 0 obj<</Type/Page/Parent 539 0 R/Contents 736 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+736 0 obj<</Length 737 0 R/Filter/FlateDecode>>stream
+x­WkoÛ6ýž_q‘…Ø’íÄŠtmÐ`ëc­±aX†–蘵$º¤Ïößw.IɶgºlŠ÷uôדõñ? ÉÎÇ”ä'¯f'of'ýh:¥ÝÃÜãKŸ†ãè‚.¦| ñ0’ØÚ§ÉÇ^ ¦ÃÆd8Œ¦;“Ñðbg3áÏÎÂÃ!rjˆßôé’f ä9F^³Ô½îÓ,éPø[©,[ÍçéÙìËIŸz€ÍÍžOof¿^ÿ|õìå‘÷2Yê#¯~º}ÿúêôý»W§G6°-õ
+zvúyY•¥*î)Õ|gK²Ò<¨DÚt̾ɿø¯ü‡ßQÀoª˜«"=–ÄÿVÄÆÇyºçÇ ùƒžùfQO~?{¢^~³rVþ¤çÏÉäÔ[Pü LœédÛjn·6)žêÛé1@Œ,+ƒ&údZ.þáïñÍ ÌÍÞ€z!3îvA[]Ѷ¦¤r)Éo…Íš¦;ûN·½§¦ÂÁEÚÞ¸÷ÞfJ…ÌuaIp
+ÊÒZ«¢ìºÔìRWYJsIbžI*5%º(d‚šó­k=÷Y‘Ï…£±4$àìÎ…*(—ùK_*[òºò…o$†YZ 2ªÀþˆý9]NLF˜K¯Š`îã›Ë€ö\ŒÆü2EçÑ$¢u±P÷Ü.;<>^¿;l(ãÄj׋¥x”‹T’
+h,„ñX¬
+½AÍ@©Ò9õ5 „Úh³â‰.õ½6&"
+ÞˆÂ!†[ˆW 'téA!°¨`\”*¥Ò-´!Íî¨Ñ‡.­¤\ƒ7"E<„™9k‘ss\ÙÁReÒR!eÊîçíÐ"+Jhk»-å¾î:¯UxÚë\¬$ÍE²ªÖ–´kÒ2ê^èGrï(Þ¡X–IŒ„"7Úû\[pN/—Bƒc©Î-H
+ü¦`èüÚ‰Î×H+ á`â£ÄÃD`wÅVW&‘qa-¢$K_w=ÚJ•Álh³¥ù¸>hÏt1rŒä!P{ô3Z—?ø·Íð{ÐëXŒç_.‘u'ÐØ=O £s.¿Ý”&û£I"æØy*l‡¸Ÿ´S‰D¯•§gÀƒí8Ü«†ýï¡Ê¼µ2©Œ*·¡3™|€hlé“Lßbà Υ̻ž§È#õÅ™šÇµ£ã5V·‡Û£HÖĸ±¬µ{ßê=/ÊìÛÆì†Åjçî N5².÷Æ™’¥(îeÑ-yeÍä¢-´…uZ%싺æp9ê G¸mAóXiøbdä×
+ÌMë[ÒA)®NPÉ
+¬«%èÊw¤ÇØ;÷3\£D’è
+r÷ýNwôÞ?4ÁùÀ‘[&Zú‰,sj-ù\aÁª…ÖKE[dƒD;‘˜\…6¹ÈêÒ‚
+L9´ÛçjÞ5¿KšÑkÌ·³øfœÁx ,Ç—ƒhÌ3úùúÝ«kúhô¾u½ÖI•£ÃNV9no0fè{“!~礢n”|™-ñ´ô¡rgì~?áçïØ7­_NþÔücendstream
+endobj
+737 0 obj
+1384
+endobj
+738 0 obj<</Type/Page/Parent 539 0 R/Contents 739 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>>>endobj
+739 0 obj<</Length 740 0 R/Filter/FlateDecode>>stream
+x­X]oÛ6}ϯ¸ÈIlg@Òv¬E·xØ´DIl$R%©¸ú÷;—”l×q´‹[q(òÞ{Îý8Ì—“)MðoJ‹Ï)­OÞ¬N~[L’å’v[à˄Ηü¼X.ðœN®’YI9^žÐål™,ÃÒ9-æø1¬à0,ÂÂö“Æ·4Ò*‡áùrA«,¬Oh•Žn¥Ü7ä¤}T©tä mŒ} ÆšFÚª;¥Î´´QUE¢r†´”¿$•/¥%*Å£$¥3õ¨²VT”)+So¬ÂY9Ç[”™Z(M-Œ¸_VŸO&t6=G0«l$*+EÖÁœtR{2šÂöGÚS i)t!ÃoKSã´ÞBG^ÖM%<Ö *¤–vσ.Øp<Ú?°¼IˆV%,S*4­%IáTÕ o•.¢3¼s|
+ˆ#W¯“Ôè<þzÀvDEeÖ°0lGqñrسó•c@›þ\fóä‚qWý[³céÓq#ê$ƒ±ƒý”«jED,ƒóÀ¥ªÌüé5H
+T‹<;pÌj¡9U«J€,ÁõZô Dñù@ëýÙ¸µŽzCîTÆ<P¥˜Tå~¡LèŠSt
+ .#¢õ%Å•_ZÐŽðWj=v2m­ò#ò©RΑ 
+YqÍä‚Eíäu&52Þ_
+ôÄP$äšÑFt¨Š;OUÆyí^5±C–Kï»#L¾jŽ¾ ­V_9EQ:ŸreÿÔ·íåO«ærÈâ‡Õ&Ðx©]¾æóÕ¼;âõBc1k¹©½Þ¡¯WH{$ìj:ŘãÏÓNŒ¹è &Eì‡ÇkñN‡¾™ëä)Ý‘È2ÖÛ‰·ša
+ƒg-!C`gÝú¨`¶æbÁÖöDÉ– ž-‡%¸oD¬ «Ê“3S.[kŒG/@Kq„õ¨´ô¬«¸Yì»!ž…]¼Cóï¥ÒÓ蟯Ê}' ¹ïù6êÑ÷ä¸
+ˆ!«229A-˜.Ȣ̴ëJxÍX7>ê¾!¹]P6AáBÏNx´G=;ƒˆ4ëøöŠ¦Ð=¬Pg‹i2ÿF£^%ó„~‡Dñ‚s/´]€,šXÓŽþî5N Òé¶^#b8]ív²èQpÒÁ†‰neɇìMaþøRxÚH*¡~9xæ/eÕ‰yë[{sBT1Pô[7¸£¶æ08ŒÆC<
+¨-ÀjHüß•n¿+n„Ù%À)2Å—¦-JjŒ…ßìêa o0÷!~ ›Jë!»a°1®°—Ë}Hž½ó zsV½X>%Ž¼OþàÖ[€·¶r8rza‘F·Îôn³›°Ò°Ïaמ”÷ñ†A÷åကýXµE€¸Á0!* Cfš¬­ävÀôÐG—@³Uü_KpÃxÕ(qÂÏ5$èÿp ÐÇ›÷TðÝcpGà‚þúp÷(×™±.é+0í¥úÙð9Ç9õïl¾è×aÀËg—³(WÀ¤MPë9ôÌlàÀŠþ¼{ ¶T ‡5:C-2ÔcUàŽäË!Wœ€#“ \Â9Üó s¼#’M©
+r4á®6t¨R÷£âêÇË}$CÀ¤bNð5g“Á¢ž¢íÖ‘N|Mµmãá/20“Î[ÓÉì(öÃè9ìnÞÆ"xœ™} Œ×!{píÃ`ĽÀU!\~‚þJ"\v!)¹±зU€ ª·* ˆ¯…è=¤kF›¯Œ|ßÝË€ÀÌчKÕ6ľ?.—H»cíqÙ'çt¾Høo¸»ï]âïoÞ¿¹¡Ö|ÆÕ›Þ™´­QL!&fõ,î:‹ÛFÇÚéÅâ ͧŽæsÞ‡þ8ù_%>Éendstream
+endobj
+740 0 obj
+1577
+endobj
+741 0 obj<</Type/Page/Parent 539 0 R/Contents 742 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>>>endobj
+742 0 obj<</Length 743 0 R/Filter/FlateDecode>>stream
+xmRËnÛ0¼ë+昶*9‚ä4r°áÖ
+Ú+C®%¦éòaµߥe EP‚âÎÎÌe%
+~J4+ÜÖcvßfŸŸîPVh|R¯¹P(ò¢(ÐÊ›»¼Éñ`¢×Ö|j߸½BYÎíËUÃí7mO˜´yÕFÁÿñÆBïlìzþ¢'Øã¥Ü‰‘p wÖ’€Ã¤ƒìرëÄë@ØD˜ ¥̇­Uq ¿€0*‘X–·ù*‘ŠÓÉÙ“Ó"ð ­–Îz{ ø¶€ÃàÑ‹3+;‘b Œ8kEð$Fëmun&c‰ïs¾³;yìڼʎB›äÉy°D¼ìž\çHËpäã =ŸvŽDà?*Ê‹%Ʀ5j£}HܬÒú–ä¢1Út õoúhúÂÄ»`Y0&ë~æIßc›qf¨‹:¯Q­®Wü:ÂqŽx}ͬ¬›<ÅÏéþóa³½ß`ïìÉ€/VÆ‘C¸l%M_Ψå ûߥ¨š*_óýá\êæ*èköÔW¾/endstream
+endobj
+743 0 obj
+398
+endobj
+744 0 obj<</Type/Page/Parent 539 0 R/Contents 745 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F0 3 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R/Fc 12 0 R>>>>/Annots 262 0 R>>endobj
+745 0 obj<</Length 746 0 R/Filter/FlateDecode>>stream
+x¥W]oâF}ϯ¸â%‰6ÈJ«*‰’.j¾v¡ÝVâelà=ã‡å¥¿½çŽmHP»«¶‰DbÏ×sÏ=çòõh@}ühÑðœ’âèj~t3?ê“ í?Ì
+˜ ‚ˆF“1þ‚IK^Al³ûÀôðö‚¢>Í—Øý|<¡yêÇñ&9¹^‹ÒICƒ~@³ˆ®óL*G?ÏOç_Žxí`T¯í ùÈyz‚Ƀ€n/?ZžÒ§Þ{5¯1ðAo(Š¦”hµÌVB{œ…}¦¤k­”LiC¯ÞŽHXÍvƒó€£<Iê`–˜:E,~âqH{ÅßóÓÏGÑÙE0 ³q4
+'ø[?å4cTÂÛ õ=ÎÆÃ7\R¡b¢‹2—N’PvHœ&·Î,}­¤u™VþN±$ZêJ¥„>ÜÒ>À}BkçÊwa˜£ó`“)T/"Pyøg.eµ -_&Ü
+X¢‚2c¹ R¯Wo m2·öc±°’t)p<ìÖ:Y0ŹPÏípF~+s‘)d(S~1S¿Ég‹\!T%ò€¦Ëº0hÍ%)Ò-ÅR*¬õÁÉ´Kqåꬣ¶6Y;›a¿?耨Í3GÖàߥ
+ãçvf2GFjnFÚÍ"ám‚ïÌê«Î¤«Êfç©4‡ô¼LÓÅïfè(í(•61Y „ÚSj<<Q¿TÈB,ŒÌ·í¨VHÒáURTxŒhÐÌ ãˆîŸæ³àæ÷›.A@’gÎÐã/¯: F–î.Ÿfd=•çv¸,X¯p{¸™{:>þvóiGG DÇOF;èÜDsÖ Ž³ ¿‚¼¼p­j:¾®Œa}m#ðcUÌί휽»H‚­V’TUÄÒÔ¡g*iëÌÑÒè…‹³ Ä3{ Û)qT³{+` “ßk,YiP`‹ QhrP 8†r ý½b­!¯‰ºdøY™H¤)A ”($¸ ÉÁ #­Å“ö‡ØÃÖÇYâ9ˆÎƒ_{—Y×é²IØR&Ù[}ž>ÌšøX
+¸×Ê^99첺bð“¿ôýðš¹|‘9{œ?oÄ÷µI— eEðDÄ ‹¯®Úê(º`ɪ­ž ®uú×ÞsðÚÙ½IG?rã!€ärl\yqÚm\V߇†HA bãÊQð̓°·ä×æÚ‹ÆlV
+7QÒš’ßØ÷
+Ld>¸Å Ï.XP4‹È?5Ö¾ïuZîcÂø
+…ÍéÑx„Ö¢>‘[ „ûOç·ÖÝyÔÓîñüm<ù½–áãÝ{u;“öýM¦0Zx`¦®á$ ok"\0u²PôÐÖB h³k™ç]’)XÎUºä–b±
+@4¡J3ëëc_{-÷O<£ÐÞçMùŽ‡ü5ÅYy«`“]WÎÝæ>æ}/¡*›õ|Ò óñè/’Ñðendstream
+endobj
+746 0 obj
+1596
+endobj
+747 0 obj<</Type/Page/Parent 539 0 R/Contents 748 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F2 5 0 R/F4 7 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 265 0 R>>endobj
+748 0 obj<</Length 749 0 R/Filter/FlateDecode>>stream
+x­VaoÛ6ýî_qÈ'phËqì$H3$­³¦ÈÒ, ë0Ðe³£DU¤âùK{ßQrb;ë·!ˆ![äÝ»wïù­Ñ
+Ÿ²X“åGÒÎÕÊÑj©
+ú4ëéK—_>©Êi[|yCXAµS)IGòMüµ3 Ãh,N¡›­
+ÿ ÿÚ¿Q5ù‡~ûÈ1׶¦Ô’¤»iLŸo¦d+ŽÇ@èàZ“Ò}¥ Oô.¤ål]%Š®*»rª:èQai&ó¹$|epä–vEu)8ù4îp±¡bŠøéá×Nt|$&4ŽÅ€r5æ曡S¢Ð¢â%ŠMdA4W”éQõ| ì¥ôÉ’²ÊæØÍU-¨KKï˳~?‘•5b¥ 'ê')
+Óÿn”ªW}Çàûˆ)–>7»QvŽ"ˆbÐÒ¤[ic‡.S§* {Àý‘2»º
+ˆ¸2Ê ¾ óFºîgÚ½Ö•ó=J*†ÁŸ[r¥‰4…þyÿps¿øüÊ’žÂLzˆå©±hä;[®Yým¾“êbÍEðc^fQL/ÿMp”×Î“ó­ œ*eXè þ
+J)1ÓsÙJ/t! ä<€7±zÁn…õ
+endobj
+749 0 obj
+1117
+endobj
+750 0 obj<</Type/Page/Parent 539 0 R/Contents 751 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 272 0 R>>endobj
+751 0 obj<</Length 752 0 R/Filter/FlateDecode>>stream
+xWQoÛ6~÷¯8ä¥)P˶ìÄNž¶uK[ h·Æm0 /4EÙ¬%R#)kþ÷ûŽ’ÅéТhmYGÞÝwßwwýg4£)þÌh™Òüšd9úm=šÜÝP:¥uŽ7×Ë­3š&Ó)~‘—¯w¢
+ÊÑl–ÐÛëô«”Ê{ºåF·µ“Š¤ÍÔËõ·Ñ”Æéç/ZÐë/÷üß>Ã|ûx>KR~ëpá;œÍj´5­éŽ:ÓtɆ­í)SUØJe¤ CøjH™ƒv֔ʄ„è÷ÎÄyª½bÿôõòµ5²vôE9OÚléþèƒ*¿¾¤`»¸gó6² ¹Sr¯ÍΊÂ[ÚÛÀ£'º¶,u¸À1£šaîp}áé œ¶µÞ7N\çI"à"¡C
+€çÌ­0ÖËþ`í9È°SHÖ×"Ä¡‹‚°(²­N—ý±qÕbéhÆß>½¥««dFW‹4™RI‹t•,»§‚î¹öS<ΟT|ÍgVÖŒ*á» Òf:×w‹ Ùüyp¹­MF"PÌìi$nK—»ªÛÉÄ3oë¶í·‰<ødÊâY
+1Ä']ÍSTg±Zâ;§âå=s{n-nV sï‘» YšÄBtœ –NîÙßäîßÖÀ¼r§z´%WÆ¡ª7…–ű+¤Þ-ËOe½Ö)·®{ nE”aà<XêDÌ‚èiW ¹[å_J.‹:cÄ`_‘óG#ÁùŒ¾é
+=úÞY¢Å|ñc´§Óï¡ QwXw Q›ÿAúo[G]´¢x†Ÿ?¢»åâ€O=<<ÐÆÙÙ0
+Cå
+Ü˕ߨÐ(48aŽ±¾ðàà<ؾp××É5Íg7ø·¤”©ß=„>O§x9ÈgtIÎëó§÷tûÓº•[=ÞhÃÊíªû¤õ u;ŸÞ$«è6]> *ªºðž~D¢f;™8£¡æ˜I‚ÈXW¢æ¸‹d¡Û‰9´Õ°€)TÖr‡fM1}œ-Ȳjø:ø2K»ïsgÈÊ8Pl¨ÙY4Œ.´à¼FUøš’j|ZʸÎQ·!Ÿù `z¾S„ÀISåT®0ë2*UØÙŒ›A§ Ç4¸_ˆÓ,E§ ô­ö/¤ð¬‹^c쵧i2§ÙÍ8ÅCäŸíÓ‰[³þqÈ­5òÀà,¬Èbp’‚Ž~PœWTY1ˆ]ï¶WÛÏ°²išDQO™@†“ÕiôôL¼Lbžlµ?³“Ó‹·¶aä·*Fø:4ûvt
+^u»sxýƒ™Y
+endobj
+752 0 obj
+1479
+endobj
+753 0 obj<</Type/Page/Parent 539 0 R/Contents 754 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F1 4 0 R/F2 5 0 R/F4 7 0 R/F5 8 0 R/F6 9 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 275 0 R>>endobj
+754 0 obj<</Length 755 0 R/Filter/FlateDecode>>stream
+xTMo›@½ûW<åD¤B
+þÁ¹j)FqJbÁéÜü|êa¹†$ml ÄD`Á!–¥_lÐé-¯Nºm\¨Žå
+`{SðÒ“g
+¬¥ô˜¡©IYž°ôÔv‘z[@);Â’¾í8»Ý:#7UTaéغ®aÍеñ‰¬I¤8É£ø{g»@M$<½£ö¤¤ºâ gÚw‡jvbç²kHŽB
+~,G)›F®­8½/Ox(øÿ1Txš}¿ž½¤/é¿\y`J;n¤Œr£¶f¶Û-W¤Oí¥ëÍçü–/™¨¨ÝQtÜÿ"€RÉ–\n–þó½Ø;ÛOws¸õlvª€ÅáU4²†¶
+t«ÂÎMdø`ÁïæÚȆŠÉ&cºOéR¥ß5WHhÔ4éYœDÂÙ/›o¢à¿÷(´ªh !±_IjóÇvœZ$“Q”ôO ž<ø¨wrL™›º=øƒª[F£}+[šÜÐP+ê7WŸür²YöùT…
+endobj
+755 0 obj
+734
+endobj
+756 0 obj<</Type/Page/Parent 539 0 R/Contents 757 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 321 0 R>>endobj
+757 0 obj<</Length 758 0 R/Filter/FlateDecode>>stream
+xÍœ[s¹…ßý+æ-›ª„æp8¼ä%åK6ë*_6+m9¯45²ó¢”7ûïsh
+u„ËátÎí`2ý¨s•ˆââÉ«§O¤»¬Kzù»Ñü¯UËéfb•]?ZÀ*û^Z?\¨U>þ~ª6ˆ1Cá…1ÃvDVTÄÉŠ˜¤lO¸8·©£¥h] ±b&èmOÿ)éI‚>l§þaô¾ü4¬Š
+Œn<šÚJ$¬‡œo†T Vá¯Á’
+xÆnµÏ RGw“°žq»z?4™>¤9‹µ†…ñ<ˆ.Ô°Äœ&n²WkG“│9©>v=ë£9U„Úœ”ûž ʬêàÌIõÒgèF(ÒžÞm¶W›ýûÜ•¤DWNg☓ÐÄ&E*0 ZÃОñt³_7Ñ"`‚Ó‡s0É"¬=Œ—¨Cr4á‚ì¡•Ñfí¡sö úØw¬öPj{PBì<&DfE˜8{P};^È$Àˆ¬
+ŒÙBLÁ0"¶blv·‡ãyµ§ «hŨzÿ@€7³Šs‚Ç–É£¡ö6_©9kê—3¸Eµ¦xQ¬©_ŠÏ´Ö4µÖ”ô¡ç>XSM¨¬)Bׂ2}:kMIßNÆð
+ HxvVç2Õ]ˆù¹·”öö-¤£—øÏÔ$a=ã´{—}©û´ËŠ¡<c}Ø_oÞßWçÍ!O~¬­›ÃÄMRO»Þl‡Q°Íùמü&?õÁ!'C dˆ ïÔzg†ªŽ&Ãêh†N_¡ê£Å°^‰öïO ªºÅ@Gdz\VnB^Òˆùub~LHP‹øõp—W.,b6•q`Jµˆh7ÙüHÈ¢…'³-`!b.A"‰Þ§bs¦ZÀ"~Ùœo‚E@L§¾(
+pq^Ï›‘†ƒE †
+€é •5’P,©b0ZÀƒ®‡]òB,G&1ž…(×C6ûá|5Ç*¶
+xÄꔬ“E@LZ¯Ü6©@…ÈÒ€†‡%hO¸Z »Ã>L³²3ôuV.Ö’±ò/ë“pA–Üa·Ãø$D-Ù†âªú8²^o{Û1‰0d3­g‚Þö„Y6<’ÀîÆsqÍ Ðûpyü5õ‹€@¾fD*àÛÍÉLÒ¤”ñB3ÃўÓ4©ÀXˆغôWU—œnVÇ!/ËÄxgâŸME”ë+²ú¸ÚlÃ9::Ö‚4•CJ<‰I$ž ŽŠ+“¨ÁÑ7Ë
+Ø*¬·Ç ³þbj"—pamv,õK6.Èf±®´µÄ9 ³ZÕGc}´ÚŠPÛ­¢™1A™¾ g¹ªW+c€"= ¶Ý„ˆöňDõŒOZoB-äT¯7(¥{” ‡I&ööÙ D xÈ*™kÄ~Ã4f
+õ„ço.þ ,¤ïdþaH*à!o¯ß¾/Ò‚Þp-’Àe³_þ«`H¸kºIõD‰|æõeÆ°˜™œ$šgJ<¦y»ÙO>)ÁY†°’Ûh€=åÍÅãIaJN×ÃúÙ0´€§ ç5Æpê&ƒE|cR1ÎæÞéÐ8‰)L&¬xÅ#Ç‹â$¦K¬i\dˆ¶TÇYÑ °›£† ·=âíÍ*Çñ$Ú5ðÎSKÐÛžðâ:Õ€$Ræ ÷=àò;/%˜"(Xæ¸j$°Ç<?ì—…u  êž¢`Oy{8~øs˜dì+Nõt1õäLá•åL <ã&^-Ì%ºâ ¹ã$²XCQáùÃÑaÌ–`zÆóÍêýþp2ar•ª"Û°®. íQ?ÈÙ…#ç©dÏ<Pþ‚kVÛ¢¨¾¬»b‹† jQdaøuZ”¶B‹*b¹ÀPœ2B´B\¬·y+™4謒ѰLÐû¾/ž‡FDù{ý‡{à‡º´ Û#—)7l¸ †íïiÖr~;CmÛ!$›2AÚ՞ݬ‘’
+- ÒZFÂÚŠp,J°ê ZÀ`äçÃú°M…À,¥+Íäórø8l5 =ìP±ÝÖËi|„ êFBøã£ÆŽT„DsxvfHGVŒ›½Y™Nº²•iŒ) ì+cb;’2o!ZÀC~~ýâï¹/I&&!k ÑRRØXDñæa”ê%Æ$Ę²od ZÀž…ENz²c &𘟉YâÄà!¦Â™™ýpè"¡àuÃÙâDòðªÙ¯œŸF[TD‹”;D"Ì[¬/ë˜ú¤!+ë[ÍY÷ºpÛ8mK¡A¸ ÆAwÝ”SºØ8Šhñ/¬’Ò8ãÕêö–ã’É“å“$®¯ËÏØ Ú¯v1óhº€ì›5óœí­Ãì›cƒxQš´[Êá]eoe[64iB ûdåŠð­o0ÿäãnÒ 9ÃúÂô¾¯Ò}«5%ü²4öËÌV%ð¤‹!f(c…ô ÃŒÔ%’ÝÍå@S¢ã…6''@wp¡vZº/:±Bʲa…èRÂ>’ Aql†¾ 5ÓÊè}_‹Hú~Ä™ %ü‘(즇TT¢{Ö«‹äÈYÄ\–›¦6(€_x
+xÈÅj÷n¼µ¬|¿°Yç€ ¥œ®Ú…‹lŠ”ÝáE
+Üó8%î#…Œó^F¨Ñk_…Û»cn–a`aãŸC¹ò36Ù¿ÜìïÊV;‰‚­ºÆýžç³ØÆ Ù×üÂ#4Ù¤µÀNί5e¤ dH³Ó¸X`¡! ŠÐèˆÛÆ ô¾‡<Æ^áã›Ã)N ˜P¾Ú£¦GþmÿÚÂ9KXªKNM.¨ä…&z›Hš§ Ñøøª—¥L˜ñ¾C„ÆÁYéaû1ç`Ûö+ÙÂoj˜¥qñèn‰6âC„ j—±BÚ…ö0Bc*¡Åò
+†Ã…zH6œÜ2Ø”üâ3Ùoj*lšGŽ€s*V¼(Í3A†ˆŸ÷÷gß?ZœÓM‘ò,9w½ï!¡yö§‚…õMn¢ùüO;f»™ÌéÍ…xA ƒÕ¹ŸòŠÕ„?éÃìdôñvE¨¦¼D9Fü$õÑ*Dh…ÃÑMyE+Sžlvà8WòOSòwX
+Te6ˆ­„vŒã<„ìÂ3QAlc’ Ï/ÌåVjηf
+9Ì­É™”Ä·€„ j[¸€À-9;W’º¤çâŠñüu¶Rh³( yÆ+­ƒÞ÷µxy8|¸ /Åuÿ'‹wר88 GÌ¿NÂ5j8qô΃öØ‹Ùr:iÑž+ÆÛ¥UIkÅ~œ/WBïû„]jUÙ]þv£?›kk’8&cJïÔª¢~ Z 5Æ|ª‘œÑëmOào.Hô—*W"† LOxwÄö oU†5Læ`R…# ÕÒ'Ihº¾Û#Óð°Ï[„-ie† Á˜!iO2/°¢1Â7†b=ã¦|Œ‚UJ¾‚a¤žQŽóX©]5R¸n·‡œþÌB`Ð#{ü4©€Ç s_>)¢«ƒã_%{ 5,«žbîFÀdª¢XÏhðH²/Iõaµdk…h€Y©€gyÛc)vÿql‡èЀ”íAwlÁ¬%¤y
+
+
+r¼(ƒ¼]ø™¾¸Í0†“z.éF­·­¾,LH ¼œF¹Þ·r·(a ˆp±‡' nåZÊiXß7çlÇ,Éiø,Á(Ùb·Ö?NÆ¥¸NKÑ–ÂFL°
+vMš –À¾4 „
+S൘ $
+XN¬69–‚ðÏU&°ëC>Œd XœºM,á4 »ípÊ®Ÿ…2e~7Íš
+X BâÉY|)»ÞŸÚ.lMöJ ÛÏÑw¼ N´l0ƒý]!&BX·Bfâq3p˜Z4 áeACÐû>?´ŒlÖ€€S4zx¤4*ñ®`]?¶I
+ÒË:GѾ"¯/Ó“°œÇÉß•¶MQªGÐn‰€Àa<ŒAh
+±Ïµ †ü·Gh
+q‡suä­í§ #TòŠLÒ_ð8zŸE>ÐòƒÍÖ¤tH
+E^ßÄ ²ÞjÄ–‡¬L¿ŽOøK<[À)!ZoÅxµúÍ—Dè°0ç„Þ÷Ù²Æñ° p@` (€ŠyF9ô"…žl–Y½ð„Ý°{WR)X(Æ'¹Ú£dÁ·Ú4¶bÈãƒæM<‚>ÔD"\ا°-à¯ò¢“E2äàÆ Rp>•à`è¹vE€=¥x–`>À³øŠ(Ó#|ÈÀR€¦B™'B{jruØ­6ñ My×㿃n¬áçeo.h¬!)Éî5ÉXsû4QÓ@ì¶cDlä™~Ð$8–„6Æ TÀWÇŽ9Ò‚èÑS´€§³&øp¦iS-P!Š³&, Ǭs‡Ðâ~gM
+ßÇ“D
+›¨úŒJtÏúñÉ«<³
+ œ÷b¤†ð
+ÏY…áR5-C±žq…÷§›wwçräÆj¹r hX©€g’ž‰U` ©.?
+àž°F”vÄÌò‚’•˜B–²å(Ú“| Ÿ7Ìçˆ,± f®P*àA+ãŽd€…Ó£Ïð#­9-ÇÆeN ?gÃGE—[‘…ùßîYó[þŠÁšz)¬y¿:Þôr3/xÙ:g@¼ë´¦& ôHþ™½Þö
+»L§ß]È̼"ù||¤y~XßíñG: ošôÍç!_ô»ü
+_ÇÿÛ£Ç)endstream
+endobj
+758 0 obj
+5352
+endobj
+759 0 obj<</Type/Page/Parent 539 0 R/Contents 760 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 366 0 R>>endobj
+760 0 obj<</Length 761 0 R/Filter/FlateDecode>>stream
+xÍœoo[DZÆßûSE‘¾Ãsÿ¸(;¾u;n¬Þ\à¢(h‰–ØŠ¤JR±óíûÌììî3s”4v,å&@¢£Ýç§åîììììþëQÛŒñoÛÌ»¦Ÿ5çÛG_ž=úâÙ²éÆÍÙÛ¦.Gm3›Oš³‹f<ñÛóÏÎVo®×Íþmód¿;­w§ãïÏþñ諳GRAk5­üôí?êg£q3›,ñßm3ëGS{¸n^Ë
+‚ÃeóųIÓ¶ò§ÑšÙŽþîdÔâßÆþá¶Íb9ê<;ÂËýi­­í&£>÷ÙÅg£ÿGÿt}íÉfÖu£ºmÒŽ–ö`Ýöų©u:·ëQ‹{éÉÕêæ´>än"ù¶™v‘eÅ2-ÝLts?šû¶XqÔÿõåóÿÍ- ѶiûÅhâV¯Ö‡íæxÜìwÄZ`›°'í%ë˜\!¢¾ÜœŽB2@°Á
+²Ú]©¶M×Íb¯
+Œ¾+)¯3V!BÞn™b 0íŒÌãFH4–ʤßéº$Wˆ Z8IIJ| ««òiHƒ)†¥ma"áõjû¦PX'®c×á>J®)Ç«Õa-Û!üùVý¡]˜è [“ÉêM‚E\5ú0L­Þ}Êjãyý]kFRa¼ZqFŽaTÏpÖG4Œw„ õˆý»Ýúp¼ÚÜH_«ùÙäûú?Uc¡Ó'…>ÐXÌǘ[Þ!MÂh˜>õëÓh wŽ‡A¬ë˜’¸Ê#’úIfv
+²]ÿ™»”EØña&E„Q=¢¹YVÛ59-*âi~Érl»àE‰€õlu,›$ï¹æÁZMoÅ€d­ÄÛkF%ÓcT¦ÇæÜa±’ÌËAÄbÍÚl&$ËrƒÆfüˆÕÈÌËŒAwÙm¦Àmb‡À” ŽöèÉÄn%aá!V!BV§Óaóæ–f
+F’1™9%kÎ`Sß\!®W‡Ë²Ia(šìs'Wˆ”ÝíöM½NÀB`²ö#G ®‹ØÈ°ÖÔN»z„Q#B=O¶¦Éîô[S¿”d~;=Tkê—r%ZSÍC«µd‚Öu+ŽŒÇ4I†¾×M¢ƒXy„¼¤£-syã™y&—A$)@8¢\Uˆ ï7Õ°IÆR„oŒUˆ Þ—‘
+Æ„ulV!2âe R‚3•ì–k ÐøE¤ÔÓ_–
+.|=Ȳ\¢½áaXÐ-GZ½>аLfƒøÑzÉa¦~7BÚ9„•GÈÝ;­¤D×"s_ÆMÉèŠþ‹”àÌ2DŽc"'í,Š$!Ö)¤`+c"æÕêüŸ«Ët}{Ô‡Ê;„ÕK39ÓPÝ3EïWý_0#è1mÏ+– 3Èÿ‘#€1¬<ò)C@Jp¦2k'£#è¸>`¨Ñ‚Øõ§Œ†3é'F¥¥Þ½>ШÈUrºÅ-¾/†Å¦OýÇú4&0“·½ì?ÝßOÄ ¾CRþúZ3EeLH+³KŽHÉàõäzƒ ð:"rüôëŒHïn¾öȦ–S›ô@ƒ1÷㇣FŠ
+à¾j‰Õfâë ®¯ 6•œþ ÞovœÐ©:±)Éì9Šqc;Võ8Ž4 `ŠaàvdhDÔÄ‹Ä ä/0jD<õvIB1*I¼zŒUˆwNO2XR±-V!Bœm²N<¥rº¦ä
+‘O)K9lóþý¤·È)Ý5îôÁìGeH¹­VhjLI|PV'# z×W¤ ”›•Ž`徜›!‰XO+&ÌMÈLOÙ7Ö‚»[˜<Žb`OÛ÷J"1yóÐ#¬‚G$#Ö65’àéçbdx_Rñ»^îÐZ>'=ÐÐ×ûpmNitM¯K­Ó§âừr ˜4ú
+%†NiÖ€T<
+DnkÐœÏ,üÉ"Y´íª¾ùÀJp°ëŠCGŽvX(ïúÉý;ÿŒ1öÆìuJãàÍøË£õîJ’„ßåJRz(sZì@|@ ]gŽº;#µxµ®]Ÿ •–“âÕa}XÿëvsÜÔ뀬†ÕáàŽ”Y¹BlÏ·ë•œwŠáÁå=Èjœ·ƒÿû.–íL¹Ì”¬_¡áúƒ‹Ð°5÷ÝšÕrÓ ß¶ ,îÖø¹ÖËÃþvw!]§õqV2øLŸä¡cp³³Ä/­>PÇÌã…Od­Cט¾EÔ½€Ÿšëš"»JÚG±§—„*WˆÍá“dRëcsß¹ÕÞZãÝ-©ÄÝÊ!°o‡UˆíðÞ……pRð.mÀ9b‚w‘ùÞR’wïJúKî]©—Hdúgq¯3˜éõM:§7¢¬\LˆÇ,$DÏ#³‡.S¦5ÃÊ#æÅêüj³£U·
+Åäz«Ãdräœnå8Žu²bJÒS )øZLúúe,_4ïÁŸ*Wˆ Ú¡±
+ E<Ø`„B¦‚u  7CÇä
+±%)C^#RbáÄî1tMFGN°X”Þ•ö‹ùe‹3ê
+‘’ç¯Ú‡$ÒîÁûÂ+åNš¼”W2— ˆŠjÏ›ŒÄ-ö‹ð Œ°òùÍ7»Ï±p~þìú‡ßäøœÕâ8%©áX¹B„ Œ‰¤
+DÆD" N[1¹ùsejDcb%8˜˜dÌAü"R¼)‘
+ $t1ÇÃ*D
+›æק3¥‰»ÓØâʽ°ô@>¨ZO ß’u˜ ìMœ
+„°ª
+c­7ÃÃÊ}+8f#
+ëL…]Æz+Ž„'ûí¶.<$“Ñ—¯Ép%æë ¯{|}ݶD$¬¨äsÙGÉb[(ÆbÈñ`t ÃFÆW‡Ã>½»‰Wî1X¿c$G~(‘¯(ñ»þ\!›½1×Ë¢eb=®bq*Œò×?OërL_Eè9݃1!•F«ýõæ|³®cXubrŠÁÙ¹ >_UÈèIÎÝÉSñ ‡½¼M™Î$æy˜X‡r’ÏÚõ AOÆl¦?×\Ä›ôx Á ‰ñ¿EÃbÀœ¯V º&ß9}*~^¿Õ¤Š’,Á˜qµ¾¾)£o¢4úŠ#áœÿà
+À¹S#àyùûU¿+µ3/OÅQ~¹>išï·=¼éÀˆ&î—þJQ®ÖƒxË/<pbÞzLŒÐßS& «õ ä>×QE2ú62!•ÆXš£ô•Éø‹#e†Q#Ľ(U4
+d<ÐØ’¯÷—û]rüâ1ïaà&.Ác/ ³´oõç:T¸ªƒ,N?W‰L/Is°>•FÂO —5¤Õ^e’ × )?1`JiJèئð’%é0d¸÷‹¥¬_¬8BnË’Aèq3@^©#}"Fý·ûÕ–²Î¤“T–~å
+endobj
+761 0 obj
+5223
+endobj
+762 0 obj<</Type/Page/Parent 539 0 R/Contents 763 0 R/Resources<</ProcSet[/PDF/Text]/Font<</F4 7 0 R/F5 8 0 R/F8 10 0 R/F9 11 0 R>>>>/Annots 396 0 R>>endobj
+763 0 obj<</Length 764 0 R/Filter/FlateDecode>>stream
+xÍ›MsÜ6†ïú<ÊU»ãá7yJ)Ê:QUl'Öx½_F#Jfvfè̇”üû}h€ÝM¹¹¶,mª¶ ï#°»Ñ
+5O0cÇ0ÅóŒ\*I̶„³«ýa·\Ü«Ð(ý*xë¯éj,•‘—ƒ¥\ƒ-EöÉr<”y¤eÆ>¬Oçä¶J¼&ˆ‹ía7\W‡~Ø’‘.²gd$c¼VÍãÂ<)å>mžÜ˜‡õMJÓQê½u&„Ÿ–‡0—„ˆ’dN«‰DøçS„ŸK"…”'Sò“Äp‡ ç—Ýp×_wnÂD©ŸÊIÚ#e[!^6˜‹˜¾1z¤lk<´§´aJ—ÈŠÀ-c±ÜÝvÑ+Bs¦Õ,×–†eï÷ÞŽÙüùd„²‘)³lr·Ópqé®óBÇyP×4]”šyZÿÓpÂS((ÈçˆN¥ççZÏËE`H %íœ$t0”a÷_ÝYƒ©õ„yÚx¢j$!Â]Cx¢¦Ò^ˆEˇ0|R.%Â?Ÿ@^÷«Ý°nb”K)LZTä âÒ»n3ºè!¦¥}Æø ’Ϫ»>îF’ÐÒFm: ßaB:_®×ÞËßhîo–4ÒàM×Þ,k<´Þ—Xï-&¸-H) üØ2Þ,7ÑlBDÓ«¡l%üÜ".»Ý]¿Š)¤ Ö &t˜pîûÃêåüê'[Afe«R]‘»EÝ›Ï5„KŠb²¨³qY"X‹& *üÜB~YooÝÑGBÒŒ¥
+,éìxø„sc¿ZÒ*N4ðÓMḃŽÆ^lùâ[¤A㜠&ˆkoäédAÇÄÅÇ[› MMy_ø±e`5ŽGa!‚æ%¢T!j[€8wI
+x “M¨ÀÀ¼Å‘ã XË@¡í¦¿=î܈ÈQ8}cGiŸ¨nÅ-oŒ>)Z: YŸ˜#L ¤ñ6QèSÈs>uëÔT äP¸†°Ž[Ŭŭɋ(Î(—)„·Îò®ûýØïºM¨ÇVsûb:­R™‹ŠÊiÁ4®!LSQ½ÊšÆl\¡E!'ñ &xËL‹nå=¡ƒ}sª)
+?·#YPŽŒÕR©%îTSB‹y{te5ìýŸ´bdœRÒJÁ´Â5„SJë’*®X.z¬0§º¥’ós ø¹ßô—ÉÜ™¶{ŸJÅk^‹OáÂ49"t¼ÖÆ8¬§-T‘(€7Î\¿Z£ íK‹ÏÎ:¡HMŠ"M]žs—-¾ÁÆ‘9ªðºjñÐUN`á`;90³˜n!8|„}£Ðl”s àÇðö2
+À/b©Õð íŒ
+‹Á)“KÄ«³_}¹ƒöAÏa ‹‹™û‡1TCEX¬htÍ™»Æ˜!òFo„œq„yF Š¹TW€ªE[DÙQô§ ¥3‘Rós­_-·c¼ŽPáCS.Fý¨€¾¢ë%£÷´~Å{Ù±2#”à JÒŽ­9o/_Æù+ET: hS5âÃr¯Rný
+@ü@«·Ý*f
+:hD"C* GZ3 ´~·WRB
+›kûRíC¡–ôѲRVrì¤YB;–ã~üÆPÊ
+veE׈a+k–Èäæ<ŒëÔx¾(ɨµ$ždñsËxÎד3m§ µ ·';ùÛ _LgXÕÌ'm
+v˜ÓŸÒ(vIÙ„aÜ!TäTºU ÆN0"¹HHï ù.ÜaÂ@lÝwW®\Fgoï ï"ãÝ=·3®k—Töãjç1ÉFUt‰dK&Œ]ÂÃ`ÛI»d‚™º$0ð7Ap‰bxOO«;wƒ­éßÝõ?æÿ—ŸFÇÐΆþƈv6]øû…šú0q±½îþp+×ÞÊ=ÒµûÚoʉçþåþ²®Á¼tÓW`òãcÊñ§—g¯¿?Kð¥òotñð:Ò$ñ3#ÿ—Nÿ¬Ý‚~Ú÷=Yé÷ëÉÿ
+endobj
+764 0 obj
+3150
+endobj
+765 0 obj<</Count 13/First 766 0 R/Last 884 0 R>>endobj
+766 0 obj<</Parent 765 0 R/Title(Table of Contents)/Dest[756 0 R/XYZ null 756 null]/Next 767 0 R>>endobj
+767 0 obj<</Parent 765 0 R/Count -19/First 768 0 R/Last 786 0 R/Title(Chapter 1. How to Install and Test SAMBA)/Dest[543 0 R/XYZ null 750 null]/Prev 766 0 R/Next 787 0 R>>endobj
+768 0 obj<</Parent 767 0 R/Title(1.1. Step 0: Read the man pages)/Dest[543 0 R/XYZ null 726 null]/Next 769 0 R>>endobj
+769 0 obj<</Parent 767 0 R/Title(1.2. Step 1: Building the Binaries)/Dest[543 0 R/XYZ null 589 null]/Prev 768 0 R/Next 770 0 R>>endobj
+770 0 obj<</Parent 767 0 R/Title(1.3. Step 2: The all important step)/Dest[543 0 R/XYZ null 174 null]/Prev 769 0 R/Next 771 0 R>>endobj
+771 0 obj<</Parent 767 0 R/Title(1.4. Step 3: Create the smb configuration file.)/Dest[546 0 R/XYZ null 735 null]/Prev 770 0 R/Next 772 0 R>>endobj
+772 0 obj<</Parent 767 0 R/Title(1.5. Step 4: Test your config file with testparm)/Dest[546 0 R/XYZ null 375 null]/Prev 771 0 R/Next 773 0 R>>endobj
+773 0 obj<</Parent 767 0 R/Title(1.6. Step 5: Starting the smbd and nmbd)/Dest[546 0 R/XYZ null 264 null]/Prev 772 0 R/Next 774 0 R>>endobj
+774 0 obj<</Parent 767 0 R/Title(1.6.1. Step 5a: Starting from inetd.conf)/Dest[549 0 R/XYZ null 750 null]/Prev 773 0 R/Next 775 0 R>>endobj
+775 0 obj<</Parent 767 0 R/Title(1.6.2. Step 5b. Alternative: starting it as a daemon)/Dest[549 0 R/XYZ null 262 null]/Prev 774 0 R/Next 776 0 R>>endobj
+776 0 obj<</Parent 767 0 R/Title(1.7. Step 6: Try listing the shares available on your server)/Dest[552 0 R/XYZ null 682 null]/Prev 775 0 R/Next 777 0 R>>endobj
+777 0 obj<</Parent 767 0 R/Title(1.8. Step 7: Try connecting with the unix client)/Dest[552 0 R/XYZ null 505 null]/Prev 776 0 R/Next 778 0 R>>endobj
+778 0 obj<</Parent 767 0 R/Title(1.9. Step 8: Try connecting from a DOS, WfWg, Win9x, WinNT, Win2k, OS/2, etc... client)/Dest[552 0 R/XYZ null 328 null]/Prev 777 0 R/Next 779 0 R>>endobj
+779 0 obj<</Parent 767 0 R/Title(1.10. What If Things Don't Work?)/Dest[555 0 R/XYZ null 750 null]/Prev 778 0 R/Next 780 0 R>>endobj
+780 0 obj<</Parent 767 0 R/Title(1.10.1. Diagnosing Problems)/Dest[555 0 R/XYZ null 573 null]/Prev 779 0 R/Next 781 0 R>>endobj
+781 0 obj<</Parent 767 0 R/Title(1.10.2. Scope IDs)/Dest[555 0 R/XYZ null 501 null]/Prev 780 0 R/Next 782 0 R>>endobj
+782 0 obj<</Parent 767 0 R/Title(1.10.3. Choosing the Protocol Level)/Dest[555 0 R/XYZ null 390 null]/Prev 781 0 R/Next 783 0 R>>endobj
+783 0 obj<</Parent 767 0 R/Title(1.10.4. Printing from UNIX to a Client PC)/Dest[558 0 R/XYZ null 735 null]/Prev 782 0 R/Next 784 0 R>>endobj
+784 0 obj<</Parent 767 0 R/Title(1.10.5. Locking)/Dest[558 0 R/XYZ null 611 null]/Prev 783 0 R/Next 785 0 R>>endobj
+785 0 obj<</Parent 767 0 R/Title(1.10.6. Mapping Usernames)/Dest[561 0 R/XYZ null 750 null]/Prev 784 0 R/Next 786 0 R>>endobj
+786 0 obj<</Parent 767 0 R/Title(1.10.7. Other Character Sets)/Dest[561 0 R/XYZ null 679 null]/Prev 785 0 R>>endobj
+787 0 obj<</Parent 765 0 R/Count -18/First 788 0 R/Last 805 0 R/Title(Chapter 2. Integrating MS Windows networks with Samba)/Dest[564 0 R/XYZ null 750 null]/Prev 767 0 R/Next 806 0 R>>endobj
+788 0 obj<</Parent 787 0 R/Title(2.1. Agenda)/Dest[564 0 R/XYZ null 702 null]/Next 789 0 R>>endobj
+789 0 obj<</Parent 787 0 R/Title(2.2. Name Resolution in a pure Unix/Linux world)/Dest[564 0 R/XYZ null 459 null]/Prev 788 0 R/Next 790 0 R>>endobj
+790 0 obj<</Parent 787 0 R/Title(2.2.1. /etc/hosts)/Dest[564 0 R/XYZ null 321 null]/Prev 789 0 R/Next 791 0 R>>endobj
+791 0 obj<</Parent 787 0 R/Title(2.2.2. /etc/resolv.conf)/Dest[567 0 R/XYZ null 431 null]/Prev 790 0 R/Next 792 0 R>>endobj
+792 0 obj<</Parent 787 0 R/Title(2.2.3. /etc/host.conf)/Dest[567 0 R/XYZ null 281 null]/Prev 791 0 R/Next 793 0 R>>endobj
+793 0 obj<</Parent 787 0 R/Title(2.2.4. /etc/nsswitch.conf)/Dest[570 0 R/XYZ null 750 null]/Prev 792 0 R/Next 794 0 R>>endobj
+794 0 obj<</Parent 787 0 R/Title(2.3. Name resolution as used within MS Windows networking)/Dest[570 0 R/XYZ null 264 null]/Prev 793 0 R/Next 795 0 R>>endobj
+795 0 obj<</Parent 787 0 R/Title(2.3.1. The NetBIOS Name Cache)/Dest[573 0 R/XYZ null 206 null]/Prev 794 0 R/Next 796 0 R>>endobj
+796 0 obj<</Parent 787 0 R/Title(2.3.2. The LMHOSTS file)/Dest[576 0 R/XYZ null 656 null]/Prev 795 0 R/Next 797 0 R>>endobj
+797 0 obj<</Parent 787 0 R/Title(2.3.3. HOSTS file)/Dest[579 0 R/XYZ null 367 null]/Prev 796 0 R/Next 798 0 R>>endobj
+798 0 obj<</Parent 787 0 R/Title(2.3.4. DNS Lookup)/Dest[579 0 R/XYZ null 256 null]/Prev 797 0 R/Next 799 0 R>>endobj
+799 0 obj<</Parent 787 0 R/Title(2.3.5. WINS Lookup)/Dest[582 0 R/XYZ null 750 null]/Prev 798 0 R/Next 800 0 R>>endobj
+800 0 obj<</Parent 787 0 R/Title(2.4. How browsing functions and how to deploy stable and dependable browsing using Samba)/Dest[582 0 R/XYZ null 525 null]/Prev 799 0 R/Next 801 0 R>>endobj
+801 0 obj<</Parent 787 0 R/Title(2.5. MS Windows security options and how to configure Samba for seemless integration)/Dest[585 0 R/XYZ null 629 null]/Prev 800 0 R/Next 802 0 R>>endobj
+802 0 obj<</Parent 787 0 R/Title(2.5.1. Use MS Windows NT as an authentication server)/Dest[588 0 R/XYZ null 577 null]/Prev 801 0 R/Next 803 0 R>>endobj
+803 0 obj<</Parent 787 0 R/Title(2.5.2. Make Samba a member of an MS Windows NT security domain)/Dest[588 0 R/XYZ null 300 null]/Prev 802 0 R/Next 804 0 R>>endobj
+804 0 obj<</Parent 787 0 R/Title(2.5.3. Configure Samba as an authentication server)/Dest[591 0 R/XYZ null 590 null]/Prev 803 0 R/Next 805 0 R>>endobj
+805 0 obj<</Parent 787 0 R/Title(2.6. Conclusions)/Dest[594 0 R/XYZ null 635 null]/Prev 804 0 R>>endobj
+806 0 obj<</Parent 765 0 R/Count -3/First 807 0 R/Last 809 0 R/Title(Chapter 3. Configuring PAM for distributed but centrally managed authentication)/Dest[597 0 R/XYZ null 750 null]/Prev 787 0 R/Next 810 0 R>>endobj
+807 0 obj<</Parent 806 0 R/Title(3.1. Samba and PAM)/Dest[597 0 R/XYZ null 702 null]/Next 808 0 R>>endobj
+808 0 obj<</Parent 806 0 R/Title(3.2. Distributed Authentication)/Dest[600 0 R/XYZ null 175 null]/Prev 807 0 R/Next 809 0 R>>endobj
+809 0 obj<</Parent 806 0 R/Title(3.3. PAM Configuration in smb.conf)/Dest[603 0 R/XYZ null 722 null]/Prev 808 0 R>>endobj
+810 0 obj<</Parent 765 0 R/Count -2/First 811 0 R/Last 812 0 R/Title(Chapter 4. Hosting a Microsoft Distributed File System tree on Samba)/Dest[606 0 R/XYZ null 750 null]/Prev 806 0 R/Next 813 0 R>>endobj
+811 0 obj<</Parent 810 0 R/Title(4.1. Instructions)/Dest[606 0 R/XYZ null 702 null]/Next 812 0 R>>endobj
+812 0 obj<</Parent 810 0 R/Title(4.1.1. Notes)/Dest[609 0 R/XYZ null 669 null]/Prev 811 0 R>>endobj
+813 0 obj<</Parent 765 0 R/Count -9/First 814 0 R/Last 822 0 R/Title(Chapter 5. UNIX Permission Bits and Windows NT Access Control Lists)/Dest[612 0 R/XYZ null 750 null]/Prev 810 0 R/Next 823 0 R>>endobj
+814 0 obj<</Parent 813 0 R/Title(5.1. Viewing and changing UNIX permissions using the NT security dialogs)/Dest[612 0 R/XYZ null 702 null]/Next 815 0 R>>endobj
+815 0 obj<</Parent 813 0 R/Title(5.2. How to view file security on a Samba share)/Dest[612 0 R/XYZ null 521 null]/Prev 814 0 R/Next 816 0 R>>endobj
+816 0 obj<</Parent 813 0 R/Title(5.3. Viewing file ownership)/Dest[612 0 R/XYZ null 344 null]/Prev 815 0 R/Next 817 0 R>>endobj
+817 0 obj<</Parent 813 0 R/Title(5.4. Viewing file or directory permissions)/Dest[615 0 R/XYZ null 682 null]/Prev 816 0 R/Next 818 0 R>>endobj
+818 0 obj<</Parent 813 0 R/Title(5.4.1. File Permissions)/Dest[615 0 R/XYZ null 439 null]/Prev 817 0 R/Next 819 0 R>>endobj
+819 0 obj<</Parent 813 0 R/Title(5.4.2. Directory Permissions)/Dest[615 0 R/XYZ null 183 null]/Prev 818 0 R/Next 820 0 R>>endobj
+820 0 obj<</Parent 813 0 R/Title(5.5. Modifying file or directory permissions)/Dest[618 0 R/XYZ null 669 null]/Prev 819 0 R/Next 821 0 R>>endobj
+821 0 obj<</Parent 813 0 R/Title(5.6. Interaction with the standard Samba create mask parameters)/Dest[618 0 R/XYZ null 228 null]/Prev 820 0 R/Next 822 0 R>>endobj
+822 0 obj<</Parent 813 0 R/Title(5.7. Interaction with the standard Samba file attribute mapping)/Dest[624 0 R/XYZ null 590 null]/Prev 821 0 R>>endobj
+823 0 obj<</Parent 765 0 R/Count -13/First 824 0 R/Last 836 0 R/Title(Chapter 6. Printing Support in Samba 2.2.x)/Dest[627 0 R/XYZ null 750 null]/Prev 813 0 R/Next 837 0 R>>endobj
+824 0 obj<</Parent 823 0 R/Title(6.1. Introduction)/Dest[627 0 R/XYZ null 726 null]/Next 825 0 R>>endobj
+825 0 obj<</Parent 823 0 R/Title(6.2. Configuration)/Dest[627 0 R/XYZ null 298 null]/Prev 824 0 R/Next 826 0 R>>endobj
+826 0 obj<</Parent 823 0 R/Title(6.2.1. Creating [print$])/Dest[630 0 R/XYZ null 689 null]/Prev 825 0 R/Next 827 0 R>>endobj
+827 0 obj<</Parent 823 0 R/Title(6.2.2. Setting Drivers for Existing Printers)/Dest[633 0 R/XYZ null 459 null]/Prev 826 0 R/Next 828 0 R>>endobj
+828 0 obj<</Parent 823 0 R/Title(6.2.3. Support a large number of printers)/Dest[636 0 R/XYZ null 682 null]/Prev 827 0 R/Next 829 0 R>>endobj
+829 0 obj<</Parent 823 0 R/Title(6.2.4. Adding New Printers via the Windows NT APW)/Dest[636 0 R/XYZ null 298 null]/Prev 828 0 R/Next 830 0 R>>endobj
+830 0 obj<</Parent 823 0 R/Title(6.2.5. Samba and Printer Ports)/Dest[639 0 R/XYZ null 682 null]/Prev 829 0 R/Next 831 0 R>>endobj
+831 0 obj<</Parent 823 0 R/Title(6.3. The Imprints Toolset)/Dest[639 0 R/XYZ null 492 null]/Prev 830 0 R/Next 832 0 R>>endobj
+832 0 obj<</Parent 823 0 R/Title(6.3.1. What is Imprints?)/Dest[639 0 R/XYZ null 381 null]/Prev 831 0 R/Next 833 0 R>>endobj
+833 0 obj<</Parent 823 0 R/Title(6.3.2. Creating Printer Driver Packages)/Dest[639 0 R/XYZ null 243 null]/Prev 832 0 R/Next 834 0 R>>endobj
+834 0 obj<</Parent 823 0 R/Title(6.3.3. The Imprints server)/Dest[639 0 R/XYZ null 145 null]/Prev 833 0 R/Next 835 0 R>>endobj
+835 0 obj<</Parent 823 0 R/Title(6.3.4. The Installation Client)/Dest[642 0 R/XYZ null 709 null]/Prev 834 0 R/Next 836 0 R>>endobj
+836 0 obj<</Parent 823 0 R/Title(6.4. Migration to from Samba 2.0.x to 2.2.x)/Dest[645 0 R/XYZ null 750 null]/Prev 835 0 R>>endobj
+837 0 obj<</Parent 765 0 R/Count -3/First 838 0 R/Last 840 0 R/Title(Chapter 7. security = domain in Samba 2.x)/Dest[648 0 R/XYZ null 750 null]/Prev 823 0 R/Next 841 0 R>>endobj
+838 0 obj<</Parent 837 0 R/Title(7.1. Joining an NT Domain with Samba 2.2)/Dest[648 0 R/XYZ null 726 null]/Next 839 0 R>>endobj
+839 0 obj<</Parent 837 0 R/Title(7.2. Samba and Windows 2000 Domains)/Dest[651 0 R/XYZ null 379 null]/Prev 838 0 R/Next 840 0 R>>endobj
+840 0 obj<</Parent 837 0 R/Title(7.3. Why is this better than security = server?)/Dest[651 0 R/XYZ null 162 null]/Prev 839 0 R>>endobj
+841 0 obj<</Parent 765 0 R/Count -14/First 842 0 R/Last 855 0 R/Title(Chapter 8. How to Configure Samba 2.2 as a Primary Domain Controller)/Dest[657 0 R/XYZ null 750 null]/Prev 837 0 R/Next 856 0 R>>endobj
+842 0 obj<</Parent 841 0 R/Title(8.1. Prerequisite Reading)/Dest[657 0 R/XYZ null 702 null]/Next 843 0 R>>endobj
+843 0 obj<</Parent 841 0 R/Title(8.2. Background)/Dest[657 0 R/XYZ null 604 null]/Prev 842 0 R/Next 844 0 R>>endobj
+844 0 obj<</Parent 841 0 R/Title(8.3. Configuring the Samba Domain Controller)/Dest[660 0 R/XYZ null 722 null]/Prev 843 0 R/Next 845 0 R>>endobj
+845 0 obj<</Parent 841 0 R/Title(8.4. Creating Machine Trust Accounts and Joining Clients to the Domain)/Dest[663 0 R/XYZ null 603 null]/Prev 844 0 R/Next 846 0 R>>endobj
+846 0 obj<</Parent 841 0 R/Title(8.4.1. Manual Creation of Machine Trust Accounts)/Dest[663 0 R/XYZ null 228 null]/Prev 845 0 R/Next 847 0 R>>endobj
+847 0 obj<</Parent 841 0 R/Title(8.4.2. "On-the-Fly" Creation of Machine Trust Accounts)/Dest[666 0 R/XYZ null 355 null]/Prev 846 0 R/Next 848 0 R>>endobj
+848 0 obj<</Parent 841 0 R/Title(8.4.3. Joining the Client to the Domain)/Dest[669 0 R/XYZ null 750 null]/Prev 847 0 R/Next 849 0 R>>endobj
+849 0 obj<</Parent 841 0 R/Title(8.5. Common Problems and Errors)/Dest[669 0 R/XYZ null 388 null]/Prev 848 0 R/Next 850 0 R>>endobj
+850 0 obj<</Parent 841 0 R/Title(8.6. System Policies and Profiles)/Dest[675 0 R/XYZ null 735 null]/Prev 849 0 R/Next 851 0 R>>endobj
+851 0 obj<</Parent 841 0 R/Title(8.7. What other help can I get?)/Dest[678 0 R/XYZ null 682 null]/Prev 850 0 R/Next 852 0 R>>endobj
+852 0 obj<</Parent 841 0 R/Title(8.8. Domain Control for Windows 9x/ME)/Dest[684 0 R/XYZ null 299 null]/Prev 851 0 R/Next 853 0 R>>endobj
+853 0 obj<</Parent 841 0 R/Title(8.8.1. Configuration Instructions: Network Logons)/Dest[687 0 R/XYZ null 273 null]/Prev 852 0 R/Next 854 0 R>>endobj
+854 0 obj<</Parent 841 0 R/Title(8.8.2. Configuration Instructions: Setting up Roaming User Profiles)/Dest[690 0 R/XYZ null 478 null]/Prev 853 0 R/Next 855 0 R>>endobj
+855 0 obj<</Parent 841 0 R/Title(8.9. DOMAIN_CONTROL.txt : Windows NT Domain Control & Samba)/Dest[702 0 R/XYZ null 270 null]/Prev 854 0 R>>endobj
+856 0 obj<</Parent 765 0 R/Count -16/First 857 0 R/Last 872 0 R/Title(Chapter 9. Unified Logons between Windows NT and UNIX using Winbind)/Dest[711 0 R/XYZ null 750 null]/Prev 841 0 R/Next 873 0 R>>endobj
+857 0 obj<</Parent 856 0 R/Title(9.1. Abstract)/Dest[711 0 R/XYZ null 702 null]/Next 858 0 R>>endobj
+858 0 obj<</Parent 856 0 R/Title(9.2. Introduction)/Dest[711 0 R/XYZ null 565 null]/Prev 857 0 R/Next 859 0 R>>endobj
+859 0 obj<</Parent 856 0 R/Title(9.3. What Winbind Provides)/Dest[711 0 R/XYZ null 242 null]/Prev 858 0 R/Next 860 0 R>>endobj
+860 0 obj<</Parent 856 0 R/Title(9.3.1. Target Uses)/Dest[714 0 R/XYZ null 577 null]/Prev 859 0 R/Next 861 0 R>>endobj
+861 0 obj<</Parent 856 0 R/Title(9.4. How Winbind Works)/Dest[714 0 R/XYZ null 413 null]/Prev 860 0 R/Next 862 0 R>>endobj
+862 0 obj<</Parent 856 0 R/Title(9.4.1. Microsoft Remote Procedure Calls)/Dest[714 0 R/XYZ null 288 null]/Prev 861 0 R/Next 863 0 R>>endobj
+863 0 obj<</Parent 856 0 R/Title(9.4.2. Name Service Switch)/Dest[717 0 R/XYZ null 750 null]/Prev 862 0 R/Next 864 0 R>>endobj
+864 0 obj<</Parent 856 0 R/Title(9.4.3. Pluggable Authentication Modules)/Dest[717 0 R/XYZ null 309 null]/Prev 863 0 R/Next 865 0 R>>endobj
+865 0 obj<</Parent 856 0 R/Title(9.4.4. User and Group ID Allocation)/Dest[720 0 R/XYZ null 669 null]/Prev 864 0 R/Next 866 0 R>>endobj
+866 0 obj<</Parent 856 0 R/Title(9.4.5. Result Caching)/Dest[720 0 R/XYZ null 479 null]/Prev 865 0 R/Next 867 0 R>>endobj
+867 0 obj<</Parent 856 0 R/Title(9.5. Installation and Configuration)/Dest[720 0 R/XYZ null 328 null]/Prev 866 0 R/Next 868 0 R>>endobj
+868 0 obj<</Parent 856 0 R/Title(9.5.1. Introduction)/Dest[720 0 R/XYZ null 217 null]/Prev 867 0 R/Next 869 0 R>>endobj
+869 0 obj<</Parent 856 0 R/Title(9.5.2. Requirements)/Dest[723 0 R/XYZ null 577 null]/Prev 868 0 R/Next 870 0 R>>endobj
+870 0 obj<</Parent 856 0 R/Title(9.5.3. Testing Things Out)/Dest[723 0 R/XYZ null 294 null]/Prev 869 0 R/Next 871 0 R>>endobj
+871 0 obj<</Parent 856 0 R/Title(9.6. Limitations)/Dest[738 0 R/XYZ null 351 null]/Prev 870 0 R/Next 872 0 R>>endobj
+872 0 obj<</Parent 856 0 R/Title(9.7. Conclusion)/Dest[741 0 R/XYZ null 750 null]/Prev 871 0 R>>endobj
+873 0 obj<</Parent 765 0 R/Count -5/First 874 0 R/Last 878 0 R/Title(Chapter 10. OS2 Client HOWTO)/Dest[744 0 R/XYZ null 750 null]/Prev 856 0 R/Next 879 0 R>>endobj
+874 0 obj<</Parent 873 0 R/Title(10.1. FAQs)/Dest[744 0 R/XYZ null 726 null]/Next 875 0 R>>endobj
+875 0 obj<</Parent 873 0 R/Title(10.1.1. How can I configure OS/2 Warp Connect or OS/2 Warp 4 as a client for Samba?)/Dest[744 0 R/XYZ null 696 null]/Prev 874 0 R/Next 876 0 R>>endobj
+876 0 obj<</Parent 873 0 R/Title(10.1.2. How can I configure OS/2 Warp 3 \(not Connect\), OS/2 1.2, 1.3 or 2.x for Samba?)/Dest[744 0 R/XYZ null 344 null]/Prev 875 0 R/Next 877 0 R>>endobj
+877 0 obj<</Parent 873 0 R/Title(10.1.3. Are there any other issues when OS/2 \(any version\) is used as a client?)/Dest[747 0 R/XYZ null 750 null]/Prev 876 0 R/Next 878 0 R>>endobj
+878 0 obj<</Parent 873 0 R/Title(10.1.4. How do I get printer driver download working for OS/2 clients?)/Dest[747 0 R/XYZ null 635 null]/Prev 877 0 R>>endobj
+879 0 obj<</Parent 765 0 R/Count -4/First 880 0 R/Last 883 0 R/Title(Chapter 11. HOWTO Access Samba source code via CVS)/Dest[750 0 R/XYZ null 750 null]/Prev 873 0 R/Next 884 0 R>>endobj
+880 0 obj<</Parent 879 0 R/Title(11.1. Introduction)/Dest[750 0 R/XYZ null 702 null]/Next 881 0 R>>endobj
+881 0 obj<</Parent 879 0 R/Title(11.2. CVS Access to samba.org)/Dest[750 0 R/XYZ null 578 null]/Prev 880 0 R/Next 882 0 R>>endobj
+882 0 obj<</Parent 879 0 R/Title(11.2.1. Access via CVSweb)/Dest[750 0 R/XYZ null 480 null]/Prev 881 0 R/Next 883 0 R>>endobj
+883 0 obj<</Parent 879 0 R/Title(11.2.2. Access via cvs)/Dest[750 0 R/XYZ null 355 null]/Prev 882 0 R>>endobj
+884 0 obj<</Parent 765 0 R/Title(Index)/Dest[753 0 R/XYZ null 484 null]/Prev 879 0 R>>endobj
+885 0 obj<</Type/Catalog/Pages 539 0 R/Names 397 0 R/PageLayout/SinglePage/Outlines 765 0 R/OpenAction[540 0 R/XYZ null null null]/PageMode/UseOutlines/PageLabels<</Nums[0<</P(title)>>1<</S/r>>4<</S/D>>]>>>>endobj
+xref
+0 886
+0000000000 65535 f
+0000000015 00000 n
+0000000244 00000 n
+0000001810 00000 n
+0000001884 00000 n
+0000001963 00000 n
+0000002045 00000 n
+0000002131 00000 n
+0000002209 00000 n
+0000002286 00000 n
+0000002365 00000 n
+0000002442 00000 n
+0000002524 00000 n
+0000002583 00000 n
+0000002635 00000 n
+0000002720 00000 n
+0000002773 00000 n
+0000002857 00000 n
+0000002888 00000 n
+0000002940 00000 n
+0000003025 00000 n
+0000003049 00000 n
+0000003095 00000 n
+0000003180 00000 n
+0000003225 00000 n
+0000003309 00000 n
+0000003354 00000 n
+0000003438 00000 n
+0000003476 00000 n
+0000003519 00000 n
+0000003604 00000 n
+0000003647 00000 n
+0000003731 00000 n
+0000003762 00000 n
+0000003816 00000 n
+0000003900 00000 n
+0000003924 00000 n
+0000003975 00000 n
+0000004060 00000 n
+0000004108 00000 n
+0000004193 00000 n
+0000004224 00000 n
+0000004342 00000 n
+0000004426 00000 n
+0000004467 00000 n
+0000004552 00000 n
+0000004593 00000 n
+0000004678 00000 n
+0000004716 00000 n
+0000004760 00000 n
+0000004845 00000 n
+0000004869 00000 n
+0000004913 00000 n
+0000004997 00000 n
+0000005039 00000 n
+0000005124 00000 n
+0000005173 00000 n
+0000005258 00000 n
+0000005307 00000 n
+0000005390 00000 n
+0000005437 00000 n
+0000005522 00000 n
+0000005568 00000 n
+0000005652 00000 n
+0000005711 00000 n
+0000005773 00000 n
+0000005858 00000 n
+0000005915 00000 n
+0000006000 00000 n
+0000006093 00000 n
+0000006177 00000 n
+0000006215 00000 n
+0000006320 00000 n
+0000006361 00000 n
+0000006445 00000 n
+0000006491 00000 n
+0000006576 00000 n
+0000006615 00000 n
+0000006700 00000 n
+0000006742 00000 n
+0000006827 00000 n
+0000006869 00000 n
+0000006954 00000 n
+0000007013 00000 n
+0000007057 00000 n
+0000007142 00000 n
+0000007166 00000 n
+0000007213 00000 n
+0000007298 00000 n
+0000007350 00000 n
+0000007435 00000 n
+0000007484 00000 n
+0000007569 00000 n
+0000007618 00000 n
+0000007702 00000 n
+0000007747 00000 n
+0000007799 00000 n
+0000007884 00000 n
+0000007932 00000 n
+0000008017 00000 n
+0000008065 00000 n
+0000008150 00000 n
+0000008214 00000 n
+0000008301 00000 n
+0000008349 00000 n
+0000008413 00000 n
+0000008500 00000 n
+0000008526 00000 n
+0000008574 00000 n
+0000008661 00000 n
+0000008708 00000 n
+0000008795 00000 n
+0000008836 00000 n
+0000008922 00000 n
+0000008964 00000 n
+0000009006 00000 n
+0000009093 00000 n
+0000009142 00000 n
+0000009229 00000 n
+0000009276 00000 n
+0000009363 00000 n
+0000009405 00000 n
+0000009458 00000 n
+0000009545 00000 n
+0000009589 00000 n
+0000009676 00000 n
+0000009733 00000 n
+0000009820 00000 n
+0000009916 00000 n
+0000010002 00000 n
+0000010052 00000 n
+0000010099 00000 n
+0000010186 00000 n
+0000010233 00000 n
+0000010320 00000 n
+0000010369 00000 n
+0000010456 00000 n
+0000010503 00000 n
+0000010590 00000 n
+0000010640 00000 n
+0000010687 00000 n
+0000010774 00000 n
+0000010821 00000 n
+0000010906 00000 n
+0000010950 00000 n
+0000011036 00000 n
+0000011078 00000 n
+0000011164 00000 n
+0000011204 00000 n
+0000011290 00000 n
+0000011338 00000 n
+0000011424 00000 n
+0000011469 00000 n
+0000011555 00000 n
+0000011599 00000 n
+0000011685 00000 n
+0000011736 00000 n
+0000011822 00000 n
+0000011871 00000 n
+0000011957 00000 n
+0000012002 00000 n
+0000012088 00000 n
+0000012130 00000 n
+0000012216 00000 n
+0000012259 00000 n
+0000012345 00000 n
+0000012387 00000 n
+0000012473 00000 n
+0000012517 00000 n
+0000012603 00000 n
+0000012640 00000 n
+0000012726 00000 n
+0000012767 00000 n
+0000012853 00000 n
+0000012895 00000 n
+0000012981 00000 n
+0000013018 00000 n
+0000013104 00000 n
+0000013145 00000 n
+0000013231 00000 n
+0000013274 00000 n
+0000013360 00000 n
+0000013406 00000 n
+0000013492 00000 n
+0000013686 00000 n
+0000013733 00000 n
+0000013820 00000 n
+0000013869 00000 n
+0000013956 00000 n
+0000014005 00000 n
+0000014091 00000 n
+0000014133 00000 n
+0000014181 00000 n
+0000014267 00000 n
+0000014313 00000 n
+0000014400 00000 n
+0000014434 00000 n
+0000014549 00000 n
+0000014636 00000 n
+0000014662 00000 n
+0000014744 00000 n
+0000014831 00000 n
+0000014916 00000 n
+0000015003 00000 n
+0000015058 00000 n
+0000015145 00000 n
+0000015201 00000 n
+0000015288 00000 n
+0000015338 00000 n
+0000015386 00000 n
+0000015473 00000 n
+0000015547 00000 n
+0000015634 00000 n
+0000015702 00000 n
+0000015789 00000 n
+0000015843 00000 n
+0000015930 00000 n
+0000015998 00000 n
+0000016085 00000 n
+0000016159 00000 n
+0000016246 00000 n
+0000016294 00000 n
+0000016381 00000 n
+0000016438 00000 n
+0000016525 00000 n
+0000016607 00000 n
+0000016662 00000 n
+0000016749 00000 n
+0000016830 00000 n
+0000016917 00000 n
+0000016951 00000 n
+0000017013 00000 n
+0000017100 00000 n
+0000017126 00000 n
+0000017175 00000 n
+0000017262 00000 n
+0000017288 00000 n
+0000017335 00000 n
+0000017422 00000 n
+0000017471 00000 n
+0000017558 00000 n
+0000017601 00000 n
+0000017688 00000 n
+0000017731 00000 n
+0000017817 00000 n
+0000017866 00000 n
+0000017951 00000 n
+0000018000 00000 n
+0000018085 00000 n
+0000018151 00000 n
+0000018199 00000 n
+0000018286 00000 n
+0000018332 00000 n
+0000018419 00000 n
+0000018453 00000 n
+0000018532 00000 n
+0000018619 00000 n
+0000018701 00000 n
+0000018787 00000 n
+0000018862 00000 n
+0000018949 00000 n
+0000019022 00000 n
+0000019109 00000 n
+0000019159 00000 n
+0000019237 00000 n
+0000019324 00000 n
+0000019350 00000 n
+0000019413 00000 n
+0000019500 00000 n
+0000019563 00000 n
+0000019650 00000 n
+0000019704 00000 n
+0000019791 00000 n
+0000019833 00000 n
+0000019874 00000 n
+0000019961 00000 n
+0000019987 00000 n
+0000020092 00000 n
+0000020198 00000 n
+0000020304 00000 n
+0000020410 00000 n
+0000020516 00000 n
+0000020622 00000 n
+0000020728 00000 n
+0000020834 00000 n
+0000020940 00000 n
+0000021046 00000 n
+0000021152 00000 n
+0000021258 00000 n
+0000021364 00000 n
+0000021470 00000 n
+0000021576 00000 n
+0000021682 00000 n
+0000021788 00000 n
+0000021894 00000 n
+0000022000 00000 n
+0000022106 00000 n
+0000022211 00000 n
+0000022317 00000 n
+0000022423 00000 n
+0000022529 00000 n
+0000022635 00000 n
+0000022741 00000 n
+0000022847 00000 n
+0000022953 00000 n
+0000023059 00000 n
+0000023165 00000 n
+0000023271 00000 n
+0000023377 00000 n
+0000023483 00000 n
+0000023589 00000 n
+0000023695 00000 n
+0000023801 00000 n
+0000023907 00000 n
+0000024013 00000 n
+0000024119 00000 n
+0000024224 00000 n
+0000024330 00000 n
+0000024436 00000 n
+0000024542 00000 n
+0000024645 00000 n
+0000024749 00000 n
+0000025127 00000 n
+0000025233 00000 n
+0000025338 00000 n
+0000025444 00000 n
+0000025550 00000 n
+0000025656 00000 n
+0000025762 00000 n
+0000025868 00000 n
+0000025974 00000 n
+0000026080 00000 n
+0000026186 00000 n
+0000026292 00000 n
+0000026397 00000 n
+0000026503 00000 n
+0000026609 00000 n
+0000026715 00000 n
+0000026821 00000 n
+0000026927 00000 n
+0000027033 00000 n
+0000027139 00000 n
+0000027245 00000 n
+0000027351 00000 n
+0000027457 00000 n
+0000027563 00000 n
+0000027669 00000 n
+0000027775 00000 n
+0000027880 00000 n
+0000027986 00000 n
+0000028092 00000 n
+0000028198 00000 n
+0000028303 00000 n
+0000028409 00000 n
+0000028515 00000 n
+0000028621 00000 n
+0000028727 00000 n
+0000028833 00000 n
+0000028939 00000 n
+0000029045 00000 n
+0000029151 00000 n
+0000029257 00000 n
+0000029363 00000 n
+0000029469 00000 n
+0000029574 00000 n
+0000029678 00000 n
+0000029782 00000 n
+0000030152 00000 n
+0000030257 00000 n
+0000030363 00000 n
+0000030469 00000 n
+0000030575 00000 n
+0000030681 00000 n
+0000030787 00000 n
+0000030893 00000 n
+0000030999 00000 n
+0000031105 00000 n
+0000031211 00000 n
+0000031317 00000 n
+0000031423 00000 n
+0000031529 00000 n
+0000031635 00000 n
+0000031741 00000 n
+0000031847 00000 n
+0000031953 00000 n
+0000032058 00000 n
+0000032164 00000 n
+0000032270 00000 n
+0000032376 00000 n
+0000032482 00000 n
+0000032588 00000 n
+0000032693 00000 n
+0000032799 00000 n
+0000032905 00000 n
+0000033011 00000 n
+0000033117 00000 n
+0000033221 00000 n
+0000033471 00000 n
+0000033505 00000 n
+0000033539 00000 n
+0000035789 00000 n
+0000035838 00000 n
+0000035887 00000 n
+0000035936 00000 n
+0000035985 00000 n
+0000036034 00000 n
+0000036083 00000 n
+0000036132 00000 n
+0000036181 00000 n
+0000036230 00000 n
+0000036279 00000 n
+0000036328 00000 n
+0000036377 00000 n
+0000036426 00000 n
+0000036475 00000 n
+0000036524 00000 n
+0000036573 00000 n
+0000036622 00000 n
+0000036671 00000 n
+0000036720 00000 n
+0000036769 00000 n
+0000036818 00000 n
+0000036867 00000 n
+0000036916 00000 n
+0000036965 00000 n
+0000037014 00000 n
+0000037063 00000 n
+0000037112 00000 n
+0000037161 00000 n
+0000037210 00000 n
+0000037259 00000 n
+0000037308 00000 n
+0000037357 00000 n
+0000037406 00000 n
+0000037455 00000 n
+0000037504 00000 n
+0000037553 00000 n
+0000037602 00000 n
+0000037651 00000 n
+0000037700 00000 n
+0000037749 00000 n
+0000037798 00000 n
+0000037847 00000 n
+0000037896 00000 n
+0000037945 00000 n
+0000037994 00000 n
+0000038043 00000 n
+0000038092 00000 n
+0000038141 00000 n
+0000038190 00000 n
+0000038239 00000 n
+0000038288 00000 n
+0000038337 00000 n
+0000038386 00000 n
+0000038435 00000 n
+0000038484 00000 n
+0000038533 00000 n
+0000038582 00000 n
+0000038631 00000 n
+0000038680 00000 n
+0000038729 00000 n
+0000038778 00000 n
+0000038827 00000 n
+0000038876 00000 n
+0000038925 00000 n
+0000038974 00000 n
+0000039023 00000 n
+0000039072 00000 n
+0000039121 00000 n
+0000039170 00000 n
+0000039219 00000 n
+0000039268 00000 n
+0000039317 00000 n
+0000039366 00000 n
+0000039415 00000 n
+0000039464 00000 n
+0000039513 00000 n
+0000039562 00000 n
+0000039611 00000 n
+0000039660 00000 n
+0000039709 00000 n
+0000039758 00000 n
+0000039807 00000 n
+0000039856 00000 n
+0000039905 00000 n
+0000039954 00000 n
+0000040003 00000 n
+0000040052 00000 n
+0000040101 00000 n
+0000040150 00000 n
+0000040199 00000 n
+0000040248 00000 n
+0000040297 00000 n
+0000040346 00000 n
+0000040395 00000 n
+0000040444 00000 n
+0000040493 00000 n
+0000040542 00000 n
+0000040591 00000 n
+0000040640 00000 n
+0000040689 00000 n
+0000040738 00000 n
+0000040787 00000 n
+0000040836 00000 n
+0000040885 00000 n
+0000040934 00000 n
+0000040983 00000 n
+0000041032 00000 n
+0000041081 00000 n
+0000041130 00000 n
+0000041179 00000 n
+0000041228 00000 n
+0000041277 00000 n
+0000041326 00000 n
+0000041375 00000 n
+0000041424 00000 n
+0000041473 00000 n
+0000041522 00000 n
+0000041571 00000 n
+0000041620 00000 n
+0000041669 00000 n
+0000041718 00000 n
+0000041767 00000 n
+0000041816 00000 n
+0000041865 00000 n
+0000041914 00000 n
+0000041963 00000 n
+0000042012 00000 n
+0000042061 00000 n
+0000042110 00000 n
+0000042159 00000 n
+0000042208 00000 n
+0000042257 00000 n
+0000042306 00000 n
+0000042355 00000 n
+0000042404 00000 n
+0000042453 00000 n
+0000042502 00000 n
+0000042551 00000 n
+0000042600 00000 n
+0000043269 00000 n
+0000043425 00000 n
+0000043997 00000 n
+0000044018 00000 n
+0000044192 00000 n
+0000045354 00000 n
+0000045376 00000 n
+0000045527 00000 n
+0000047048 00000 n
+0000047070 00000 n
+0000047230 00000 n
+0000048666 00000 n
+0000048688 00000 n
+0000048866 00000 n
+0000050126 00000 n
+0000050148 00000 n
+0000050290 00000 n
+0000051874 00000 n
+0000051896 00000 n
+0000052029 00000 n
+0000053864 00000 n
+0000053886 00000 n
+0000054019 00000 n
+0000054542 00000 n
+0000054563 00000 n
+0000054724 00000 n
+0000056008 00000 n
+0000056030 00000 n
+0000056191 00000 n
+0000057946 00000 n
+0000057968 00000 n
+0000058128 00000 n
+0000059773 00000 n
+0000059795 00000 n
+0000059937 00000 n
+0000062007 00000 n
+0000062029 00000 n
+0000062171 00000 n
+0000063983 00000 n
+0000064005 00000 n
+0000064147 00000 n
+0000065872 00000 n
+0000065894 00000 n
+0000066045 00000 n
+0000067809 00000 n
+0000067831 00000 n
+0000068006 00000 n
+0000070113 00000 n
+0000070135 00000 n
+0000070295 00000 n
+0000071891 00000 n
+0000071913 00000 n
+0000072088 00000 n
+0000073583 00000 n
+0000073605 00000 n
+0000073757 00000 n
+0000074564 00000 n
+0000074585 00000 n
+0000074736 00000 n
+0000076374 00000 n
+0000076396 00000 n
+0000076561 00000 n
+0000078333 00000 n
+0000078355 00000 n
+0000078520 00000 n
+0000079413 00000 n
+0000079434 00000 n
+0000079608 00000 n
+0000081213 00000 n
+0000081235 00000 n
+0000081378 00000 n
+0000082136 00000 n
+0000082157 00000 n
+0000082340 00000 n
+0000084208 00000 n
+0000084230 00000 n
+0000084399 00000 n
+0000086253 00000 n
+0000086275 00000 n
+0000086435 00000 n
+0000088119 00000 n
+0000088141 00000 n
+0000088314 00000 n
+0000090043 00000 n
+0000090065 00000 n
+0000090216 00000 n
+0000091140 00000 n
+0000091161 00000 n
+0000091345 00000 n
+0000093170 00000 n
+0000093192 00000 n
+0000093366 00000 n
+0000095539 00000 n
+0000095561 00000 n
+0000095754 00000 n
+0000097628 00000 n
+0000097650 00000 n
+0000097834 00000 n
+0000099744 00000 n
+0000099766 00000 n
+0000099942 00000 n
+0000101743 00000 n
+0000101765 00000 n
+0000101935 00000 n
+0000103533 00000 n
+0000103555 00000 n
+0000103740 00000 n
+0000105216 00000 n
+0000105238 00000 n
+0000105431 00000 n
+0000107002 00000 n
+0000107024 00000 n
+0000107199 00000 n
+0000108979 00000 n
+0000109001 00000 n
+0000109157 00000 n
+0000110718 00000 n
+0000110740 00000 n
+0000110925 00000 n
+0000112777 00000 n
+0000112799 00000 n
+0000112965 00000 n
+0000114612 00000 n
+0000114634 00000 n
+0000114819 00000 n
+0000116768 00000 n
+0000116790 00000 n
+0000116974 00000 n
+0000118701 00000 n
+0000118723 00000 n
+0000118893 00000 n
+0000120498 00000 n
+0000120520 00000 n
+0000120689 00000 n
+0000122562 00000 n
+0000122584 00000 n
+0000122769 00000 n
+0000124633 00000 n
+0000124655 00000 n
+0000124831 00000 n
+0000126921 00000 n
+0000126943 00000 n
+0000127118 00000 n
+0000129058 00000 n
+0000129080 00000 n
+0000129256 00000 n
+0000131572 00000 n
+0000131594 00000 n
+0000131746 00000 n
+0000133726 00000 n
+0000133748 00000 n
+0000133908 00000 n
+0000135775 00000 n
+0000135797 00000 n
+0000135948 00000 n
+0000137700 00000 n
+0000137722 00000 n
+0000137854 00000 n
+0000139728 00000 n
+0000139750 00000 n
+0000139892 00000 n
+0000141963 00000 n
+0000141985 00000 n
+0000142136 00000 n
+0000143930 00000 n
+0000143952 00000 n
+0000144084 00000 n
+0000145877 00000 n
+0000145899 00000 n
+0000146022 00000 n
+0000146476 00000 n
+0000146497 00000 n
+0000146649 00000 n
+0000148391 00000 n
+0000148413 00000 n
+0000148555 00000 n
+0000150316 00000 n
+0000150338 00000 n
+0000150489 00000 n
+0000152379 00000 n
+0000152401 00000 n
+0000152558 00000 n
+0000154408 00000 n
+0000154430 00000 n
+0000154624 00000 n
+0000156683 00000 n
+0000156705 00000 n
+0000156880 00000 n
+0000158472 00000 n
+0000158494 00000 n
+0000158678 00000 n
+0000160027 00000 n
+0000160049 00000 n
+0000160209 00000 n
+0000161452 00000 n
+0000161474 00000 n
+0000161625 00000 n
+0000163080 00000 n
+0000163102 00000 n
+0000163263 00000 n
+0000164911 00000 n
+0000164933 00000 n
+0000165066 00000 n
+0000165535 00000 n
+0000165556 00000 n
+0000165723 00000 n
+0000167390 00000 n
+0000167412 00000 n
+0000167569 00000 n
+0000168757 00000 n
+0000168779 00000 n
+0000168936 00000 n
+0000170486 00000 n
+0000170508 00000 n
+0000170692 00000 n
+0000171497 00000 n
+0000171518 00000 n
+0000171675 00000 n
+0000177098 00000 n
+0000177120 00000 n
+0000177277 00000 n
+0000182571 00000 n
+0000182593 00000 n
+0000182750 00000 n
+0000185971 00000 n
+0000185993 00000 n
+0000186049 00000 n
+0000186154 00000 n
+0000186332 00000 n
+0000186451 00000 n
+0000186586 00000 n
+0000186722 00000 n
+0000186870 00000 n
+0000187020 00000 n
+0000187160 00000 n
+0000187301 00000 n
+0000187454 00000 n
+0000187616 00000 n
+0000187765 00000 n
+0000187953 00000 n
+0000188086 00000 n
+0000188214 00000 n
+0000188332 00000 n
+0000188468 00000 n
+0000188610 00000 n
+0000188726 00000 n
+0000188852 00000 n
+0000188968 00000 n
+0000189159 00000 n
+0000189258 00000 n
+0000189406 00000 n
+0000189524 00000 n
+0000189648 00000 n
+0000189770 00000 n
+0000189896 00000 n
+0000190054 00000 n
+0000190184 00000 n
+0000190308 00000 n
+0000190426 00000 n
+0000190544 00000 n
+0000190663 00000 n
+0000190853 00000 n
+0000191039 00000 n
+0000191192 00000 n
+0000191355 00000 n
+0000191506 00000 n
+0000191610 00000 n
+0000191827 00000 n
+0000191933 00000 n
+0000192065 00000 n
+0000192187 00000 n
+0000192392 00000 n
+0000192497 00000 n
+0000192597 00000 n
+0000192801 00000 n
+0000192962 00000 n
+0000193110 00000 n
+0000193238 00000 n
+0000193381 00000 n
+0000193505 00000 n
+0000193634 00000 n
+0000193779 00000 n
+0000193944 00000 n
+0000194096 00000 n
+0000194276 00000 n
+0000194381 00000 n
+0000194500 00000 n
+0000194625 00000 n
+0000194770 00000 n
+0000194912 00000 n
+0000195062 00000 n
+0000195193 00000 n
+0000195319 00000 n
+0000195444 00000 n
+0000195584 00000 n
+0000195711 00000 n
+0000195842 00000 n
+0000195973 00000 n
+0000196151 00000 n
+0000196279 00000 n
+0000196415 00000 n
+0000196550 00000 n
+0000196756 00000 n
+0000196869 00000 n
+0000196985 00000 n
+0000197130 00000 n
+0000197301 00000 n
+0000197450 00000 n
+0000197605 00000 n
+0000197745 00000 n
+0000197877 00000 n
+0000198011 00000 n
+0000198143 00000 n
+0000198281 00000 n
+0000198431 00000 n
+0000198599 00000 n
+0000198746 00000 n
+0000198951 00000 n
+0000199052 00000 n
+0000199170 00000 n
+0000199297 00000 n
+0000199416 00000 n
+0000199539 00000 n
+0000199679 00000 n
+0000199806 00000 n
+0000199946 00000 n
+0000200082 00000 n
+0000200204 00000 n
+0000200340 00000 n
+0000200460 00000 n
+0000200580 00000 n
+0000200706 00000 n
+0000200823 00000 n
+0000200926 00000 n
+0000201091 00000 n
+0000201189 00000 n
+0000201374 00000 n
+0000201564 00000 n
+0000201747 00000 n
+0000201906 00000 n
+0000202093 00000 n
+0000202199 00000 n
+0000202329 00000 n
+0000202455 00000 n
+0000202565 00000 n
+0000202658 00000 n
+trailer
+<</Size 886/Root 885 0 R/Info 1 0 R/ID[<063ee28ad25d00a6b7ea666000182d51><063ee28ad25d00a6b7ea666000182d51>]>>
+startxref
+202872
+%%EOF
diff --git a/docs/THANKS b/docs/THANKS
index 6405da3f9f4..789042f78e1 100644
--- a/docs/THANKS
+++ b/docs/THANKS
@@ -20,9 +20,11 @@ please contact Andrew.Tridgell@anu.edu.au, or via normal mail at
Lee Fisher (leefi@microsoft.com)
Charles Fox (cfox@microsoft.com)
Dan Perry (danp@exchnge.microsoft.com)
+Paul Leach (paulle@microsoft.com)
+Isaac Heizer (isaache@microsoft.com)
These Microsoft people have been very helpful and supportive of
- the development of Samba.
+ the development of Samba over some years.
Lee very kindly supplied me with a copy of the X/Open SMB
specs. These have been invaluable in getting the details of the
@@ -43,6 +45,11 @@ Dan Perry (danp@exchnge.microsoft.com)
NT browsing spec, which will help a lot in the development of the
Samba browser code.
+ Paul was responsible for Microsoft paying my flight to Seattle for the
+ first CIFS conference (see http://samba.org/cifs) and has been
+ generally helpful and cooperative as the SMB community moves towards
+ an Internet-ready specification. Isaac has regularly provided help on
+ the behaviour of NT networks.
Bruce Perens (bruce@pixar.com)
@@ -93,7 +100,7 @@ Steve Kennedy (steve@gbnet.net)
John Terpstra (jht@aquasoft.com.au)
- Aquasoft are a speciaist consulting company whose Samba using
+ Aquasoft are a specialist consulting company whose Samba-using
customers span the world.
Aquasoft have been avid supporters of the Samba project. As a
@@ -117,3 +124,14 @@ Steve Withers (swithers@vnet.IBM.COM)
OS/2 Warp installed. I hope this will allow me to finally fix
up those annoying OS/2 related Samba bugs that I have been
receiving reports of.
+
+Keith Wilkins (wilki1k@nectech.co.uk)
+
+ Keith from NEC in England very generously supplied a PC to
+ Luke Leighton to help with his nmbd development work. At the
+ same time Keith offered to help me with some new hardware, and
+ he sent me a pentium motherboard with 32MB of ram
+ onboard. This was very helpful as it allowed me to upgrade
+ my aging server to be a very powerful system. Thanks!
+
+
diff --git a/docs/announce b/docs/announce
index f761320f43e..f5716556ba0 100644
--- a/docs/announce
+++ b/docs/announce
@@ -1,24 +1,35 @@
- Announcing Samba version 1.9
+ Announcing Samba version 2.2
============================
What is Samba?
--------------
-Samba is a Unix based SMB file server. This allows a Unix host to
-act as a file and print server for SMB clients. This includes
-Lan-Manager compatible clients such as LanManager for DOS, Windows for
-Workgroups, Windows NT, Windows 95, OS/2, Pathworks and many more.
+Samba is a SMB file server that runs on Unix and other operating
+systems. It allows these operating systems (currently Unix, Netware,
+OS/2 and AmigaDOS) to act as a file and print server for SMB and CIFS
+clients. There are many Lan-Manager compatible clients such as
+LanManager for DOS, Windows for Workgroups, Windows NT, Windows 95,
+Linux smbfs, OS/2, Pathworks and more.
+
+The package also includes a SMB client for accessing other SMB servers,
+and an advanced netbios/WINS nameserver for browsing support.
-The package also includes a Unix SMB client and a netbios nameserver.
What can it do for me?
----------------------
If you have any PCs running SMB clients, such as a PC running Windows
-for Workgroups, then you can mount file space or printers from a unix
-host, so that directories, files and printers on the unix host are
+for Workgroups, then you can mount file space or printers on a Samba
+host, so that directories, files and printers on the host are
available on the PC.
+If you have any SMB servers such as Windows NT Server, Warp Server or
+Pathworks you may be able to replace them by or supplement them with
+Samba. One of Samba's big strengths is integration, so you can use it
+to tie together your Unix (or VMS etc) hosts and PC clients. If you
+are tired of the insecurity, expense and instability of PCNFS then Samba
+may be for you.
+
The client part of the package will also allow you to attach to other
SMB-based servers (such as windows NT and windows for workgroups) so
that you can copy files to and from your unix host. The client also
@@ -26,29 +37,36 @@ allows you to access a SMB printer (such as one attached to an OS/2 or
WfWg server) from Unix, using an entry in /etc/printcap, or by
explicitly specifying the command used to print files.
-What are it's features?
+
+What are its features?
------------------------
Samba supports many features that are not supported in other SMB
-implementations (all of which are commercial). Some of it's features
-include host as well as username/password security, a unix client,
-automatic home directory exporting, automatic printer exporting, dead
-connection timeouts, umask support, guest connections, name mangling
-and hidden and system attribute mapping. Look at the man pages
-included with the package for a full list of features.
-
-What's new since 1.8?
+implementations (all of which are commercial). These include host as
+well as username/password security, a client, automatic home directory
+exporting, automatic printer exporting, dead connection timeouts,
+umask support, guest connections, name mangling and hidden and system
+attribute mapping. Look at the FAQs included with the package for
+a full list of features.
+
+
+What's new since 2.0?
---------------------
Lots of stuff. See the change log and man pages for details.
+In particular, please check the WHATSNEW.txt file in the root directory
+of each release. This file has current change/update information.
+
Where can I get a client for my PC?
-----------------------------------
There is a free client for MS-DOS based PCs available from
ftp.microsoft.com in the directory bussys/Clients/MSCLIENT/. Please
-read the licencing information before downloading. The built in
-Windows for Workgroups client is also very good.
+read the licencing information before downloading. The add-on 32-bit
+TCP/IP Windows for Workgroups client is also very good. Windows 95/98/ME,
+Windows NT/2000 and OS/2 come with suitable clients by default.
+
What network protocols are supported?
-------------------------------------
@@ -59,6 +77,7 @@ about ports to other protocols but nothing is yet available.
There is a free TCP/IP implementation for Windows for Workgroups
available from ftp.microsoft.com (it's small, fast and quite reliable).
+
How much does it cost?
----------------------
@@ -66,7 +85,8 @@ Samba software is free software. It is available under the
GNU Public licence in source code form at no cost. Please read the
file COPYING that comes with the package for more information.
-What flavours of unix does it support?
+
+What operating systems does it support?
---------------------------------------
The code has been written to be as portable as possible. It has been
@@ -76,10 +96,13 @@ unixes:
Linux, SunOS, Solaris, SVR4, Ultrix, OSF1, AIX, BSDI, NetBSD,
Sequent, HP-UX, SGI, FreeBSD, NeXT, ISC, A/UX, SCO, Intergraph,
-Domain/OS and DGUX.
+Silicon Graphics Inc., Domain/OS and DGUX.
Some of these have received more testing than others. If it doesn't
-work with your unix then it should be easy to fix.
+work with your unix then it should be easy to fix. It has also been ported
+to Netware, OS/2 and the Amiga. A VMS port is available too. See the web site
+for more details.
+
Who wrote it?
-------------
@@ -90,11 +113,13 @@ large parts of the package were contributed by several people from all
over the world. Please look at the file `change-log' for information
on who did what bits.
+
Where can I get it?
-------------------
-The package is available via anonymous ftp from nimbus.anu.edu.au in
-the directory pub/tridge/samba/.
+The package is available via anonymous ftp from samba.org in
+the directory pub/samba/.
+
What about SMBServer?
---------------------
@@ -107,23 +132,19 @@ early incarnation of Samba was distributed as nbserver.
If you see any copies of nbserver or smbserver on ftp sites please let
me or the ftp archive maintainer know, as I want to get them deleted.
+
Where can I get more info?
---------------------------
Please join the mailing list if you want to discuss the development or
-use of Samba. To join the mailing list send mail to
-listproc@listproc.anu.edu.au with a body of "subscribe samba Your
-Name".
-
-There is also an announcement mailing list for new version
-announcements. Subscribe as above but with "subscribe samba-announce
-Your Name".
+use of Samba. To join the mailing list, please read the instructions
+at http://lists.samba.org/
There is also often quite a bit of discussion about Samba on the
newsgroup comp.protocols.smb.
A WWW site with lots of Samba info can be found at
-http://lake.canberra.edu.au/pub/samba/
+http://samba.org/samba/
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
+The Samba Team (Contact: samba@samba.org)
+March 2001
diff --git a/docs/docbook/.cvsignore b/docs/docbook/.cvsignore
new file mode 100644
index 00000000000..04290fcd2eb
--- /dev/null
+++ b/docs/docbook/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+config.cache
+config.log
+config.status
diff --git a/docs/docbook/Makefile.in b/docs/docbook/Makefile.in
new file mode 100644
index 00000000000..b0d445852ca
--- /dev/null
+++ b/docs/docbook/Makefile.in
@@ -0,0 +1,368 @@
+#################################################################
+# Makefile.in for Samba Documentation
+# Authors: James Moore <jmoore@php.net>
+# Gerald Carter <jerry@samba.org>
+#
+# Please see http://www.samba.org/samba/cvs.html
+# for information on getting the latest
+# source and documentation source files.
+#
+
+# Autoconf Variables
+SRCDIR = @srcdir@
+JADE = @JADE@
+NSGMLS = @NSGMLS@
+SGMLSPL=@SGMLSPL@
+HTMLDOC=@HTMLDOC@
+PERL=@PERL@
+#CATALOG = @CATALOG@
+MANDIR=../manpages
+HTMLDIR=../htmldocs
+
+#Stylesheets and Dependicies
+SGML_SHARE=@SGML_SHARE@
+#SGML_CATALOG_FILES=$(SGML_CATALOG_FILES):./dbsgml/catalog
+HTML_STYLESHEET = $(srcdir)/stylesheets/html.dsl
+HTML_DEPS = $(srcdir)/stylesheets/html-common.dsl $(srcdir)/stylesheets/common.dsl
+
+MANPAGES=$(MANDIR)/findsmb.1 $(MANDIR)/smbclient.1 \
+ $(MANDIR)/smbspool.8 $(MANDIR)/lmhosts.5 \
+ $(MANDIR)/smbcontrol.1 $(MANDIR)/smbstatus.1 \
+ $(MANDIR)/make_smbcodepage.1 $(MANDIR)/smbd.8 \
+ $(MANDIR)/smbtar.1 $(MANDIR)/nmbd.8 $(MANDIR)/smbmnt.8 \
+ $(MANDIR)/smbumount.8 $(MANDIR)/nmblookup.1 \
+ $(MANDIR)/smbmount.8 $(MANDIR)/swat.8 $(MANDIR)/rpcclient.1 \
+ $(MANDIR)/smbpasswd.5 $(MANDIR)/testparm.1 $(MANDIR)/samba.7 \
+ $(MANDIR)/smbpasswd.8 $(MANDIR)/testprns.1 \
+ $(MANDIR)/smb.conf.5 $(MANDIR)/wbinfo.1 \
+ $(MANDIR)/smbcacls.1 $(MANDIR)/smbsh.1 $(MANDIR)/winbindd.8 \
+ $(MANDIR)/make_unicodemap.1
+
+SGMLMANSRC=manpages/findsmb.1.sgml manpages/smbclient.1.sgml \
+ manpages/smbspool.8.sgml manpages/lmhosts.5.sgml \
+ manpages/smbcontrol.1.sgml manpages/smbstatus.1.sgml \
+ manpages/make_smbcodepage.1.sgml manpages/smbd.8.sgml \
+ manpages/smbtar.1.sgml manpages/nmbd.8.sgml manpages/smbmnt.8.sgml \
+ manpages/smbumount.8.sgml manpages/nmblookup.1.sgml \
+ manpages/smbmount.8.sgml manpages/swat.8.sgml \
+ manpages/rpcclient.1.sgml manpages/smbpasswd.5.sgml \
+ manpages/testparm.1.sgml manpages/samba.7.sgml \
+ manpages/smbpasswd.8.sgml manpages/testprns.1.sgml \
+ manpages/smb.conf.5.sgml \
+ manpages/wbinfo.1.sgml manpages/smbcacls.1.sgml \
+ manpages/smbsh.1.sgml manpages/winbindd.8.sgml \
+ manpages/make_unicodemap.1.sgml
+
+HOWTOSRC=projdoc/DOMAIN_MEMBER.sgml projdoc/NT_Security.sgml \
+ projdoc/msdfs_setup.sgml projdoc/printer_driver2.sgml \
+ projdoc/UNIX_INSTALL.sgml projdoc/winbind.sgml projdoc/OS2-Client-HOWTO.sgml \
+ projdoc/Samba-PDC-HOWTO.sgml projdoc/ENCRYPTION.sgml \
+ projdoc/CVS-Access.sgml projdoc/Integrating-with-Windows.sgml \
+ projdoc/PAM-Authentication-And-Samba.sgml
+
+FAQSRC=faq/samba-pdc-faq.sgml
+
+
+
+######################################################################
+# Make instructions
+######################################################################
+all: HOWTO proj-doc man-all man-html-all
+
+man: $(MANPAGES)
+
+FAQ: $(FAQSRC)
+ @echo Building SAMBA PDC FAQ...
+ @(for i in $?; do \
+ htmlfile=`echo $$i | sed 's,.*/,,' | sed "s/\.sgml/\.html/g"`; \
+ echo "Making $$htmlfile"; \
+ $(JADE) -t sgml -V nochunks -d $(SGML_SHARE)/dsssl/docbook/html/docbook.dsl \
+ -f /tmp/jade.log $$i > ../htmldocs/$$htmlfile; \
+ cat /tmp/jade.log | grep -v DTDDECL; \
+ /bin/rm -f /tmp/jade.log; \
+ done)
+
+HOWTO: $(HOWTOSRC)
+ @echo Building HOWTO pages...
+ @(for i in $?; do \
+ htmlfile=`echo $$i | sed 's,.*/,,' | sed "s/\.sgml/\.html/g"`; \
+ echo "Making $$htmlfile"; \
+ cat $$i | $(PERL) scripts/make-article.pl > /tmp/`echo $$i | sed 's,.*/,,'`; \
+ $(JADE) -t sgml -V nochunks -d $(SGML_SHARE)/dsssl/docbook/html/docbook.dsl \
+ -f /tmp/jade.log /tmp/`echo $$i | sed 's,.*/,,'` > ../htmldocs/$$htmlfile; \
+ cat /tmp/jade.log | grep -v DTDDECL; \
+ /bin/rm -f /tmp/jade.log /tmp/`echo $$i | sed 's,.*/,,'`; \
+ done)
+
+
+## I'm using htmldoc here to produc the PDF output. If you want
+## Postscript output, you can run
+##
+## sgmltools -b ps projdoc/samba-doc.sgml
+##
+proj-doc:
+ echo Building Samba-HOWTO-Collections...
+ @$(PERL) scripts/collateindex.pl -N -o projdoc/index.sgml
+ @$(JADE) -t sgml -V html-index -d $(SGML_SHARE)/dsssl/docbook/html/docbook.dsl projdoc/samba-doc.sgml
+ @$(PERL) scripts/collateindex.pl -o projdoc/index.sgml HTML.index
+ @/bin/rm HTML.index *.htm
+ @$(JADE) -t sgml -i html -V nochunks -d stylesheets/ldp.dsl\#html projdoc/samba-doc.sgml > samba-doc.html
+ @(cd scripts; ./ldp_print ../samba-doc.html)
+ @mv -f samba-doc.pdf ../Samba-HOWTO-Collection.pdf
+ @/bin/mv -f samba-doc.html ../htmldocs/Samba-HOWTO-Collection.html
+
+
+
+
+
+## generate all HTML man pages
+man-html-all: $(SGMLMANSRC)
+ @echo Building HTML formatted man pages...
+ @(for i in $?; do \
+ htmlfile=`echo $$i | sed 's,.*/,,' | sed "s/\.sgml/\.html/g"`; \
+ echo "Making $$htmlfile"; \
+ $(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html -f /tmp/jade.log $$i > ../htmldocs/$$htmlfile; \
+ cat /tmp/jade.log | grep -v DTDDECL; \
+ /bin/rm -f /tmp/jade.log; \
+ done)
+
+## generate all man pages
+man-all: $(SGMLMANSRC)
+ @echo Building man pages...
+ @(for i in $?; do \
+ manfile=`echo $$i | sed 's,.*/,,' | sed "s/\.sgml//g"`; \
+ echo "Making $$manfile"; \
+ $(NSGMLS) -f /tmp/docbook2x.log $$i | $(SGMLSPL) \
+ $(SGML_SHARE)/docbook2X/docbook2man-spec.pl; \
+ cat /tmp/docbook2x.log | grep -v DTDDECL; \
+ /bin/rm -f /tmp/docbook2x.log; \
+ cat $$manfile | $(PERL) scripts/strip-links.pl > $(MANDIR)/$$manfile; \
+ /bin/rm -f $$manfile; \
+ done)
+
+
+
+
+##
+## these rules are for building individual files
+##
+$(MANDIR)/findsmb.1: manpages/findsmb.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbclient.1: manpages/smbclient.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbspool.8: manpages/smbspool.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/lmhosts.5: manpages/lmhosts.5.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbcontrol.1: manpages/smbcontrol.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbstatus.1: manpages/smbstatus.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/make_smbcodepage.1: manpages/make_smbcodepage.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/make_unicodemap.1: manpages/make_unicodemap.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbd.8: manpages/smbd.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbtar.1: manpages/smbtar.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/nmbd.8: manpages/nmbd.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbmnt.8: manpages/smbmnt.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbumount.8: manpages/smbumount.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/nmblookup.1: manpages/nmblookup.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbmount.8: manpages/smbmount.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/swat.8: manpages/swat.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/rpcclient.1: manpages/rpcclient.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbpasswd.5: manpages/smbpasswd.5.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/testparm.1: manpages/testparm.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/samba.7: manpages/samba.7.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbpasswd.8: manpages/smbpasswd.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/testprns.1: manpages/testprns.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smb.conf.5: manpages/smb.conf.5.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/wbinfo.1: manpages/wbinfo.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbcacls.1: manpages/smbcacls.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/smbsh.1 : manpages/smbsh.1.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+$(MANDIR)/winbindd.8: manpages/winbindd.8.sgml
+ @echo "Making $@"
+ @$(NSGMLS) $< | $(SGMLSPL) $(SGML_SHARE)/docbook2X/docbook2man-spec.pl
+ @cat `echo $@ | sed 's,.*/,,'` | $(PERL) scripts/strip-links.pl > $@
+ @/bin/rm -f `echo $@ | sed 's,.*/,,'`
+ @echo "Making HTML version of $@"
+ @$(JADE) -t sgml -i html -V nochunks -d ./stylesheets/ldp.dsl\#html $< > $(HTMLDIR)/`echo $< | sed 's,.*/,,'| sed "s/\.sgml/\.html/g"`
+
+
+## Clean Rule
+clean:
+ /bin/rm -f manpage.*
diff --git a/docs/docbook/configure b/docs/docbook/configure
new file mode 100755
index 00000000000..26ea4674823
--- /dev/null
+++ b/docs/docbook/configure
@@ -0,0 +1,1067 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-sgml-share=DIR change the default location of SGML stylesheets"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=global.ent
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+## check for the necesary install tools
+## Openjade includes 'onsgmls' while
+## the older jade package includes 'nsgmls'
+# Extract the first word of "openjade", so it can be a program name with args.
+set dummy openjade; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:534: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_JADE'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$JADE" in
+ /*)
+ ac_cv_path_JADE="$JADE" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_JADE="$JADE" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_JADE="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+JADE="$ac_cv_path_JADE"
+if test -n "$JADE"; then
+ echo "$ac_t""$JADE" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$JADE"; then
+ # Extract the first word of "jade", so it can be a program name with args.
+set dummy jade; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:571: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_JADE'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$JADE" in
+ /*)
+ ac_cv_path_JADE="$JADE" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_JADE="$JADE" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_JADE="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+JADE="$ac_cv_path_JADE"
+if test -n "$JADE"; then
+ echo "$ac_t""$JADE" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ # Extract the first word of "nsgmls", so it can be a program name with args.
+set dummy nsgmls; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:606: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_NSGMLS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$NSGMLS" in
+ /*)
+ ac_cv_path_NSGMLS="$NSGMLS" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_NSGMLS="$NSGMLS" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_NSGMLS="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+NSGMLS="$ac_cv_path_NSGMLS"
+if test -n "$NSGMLS"; then
+ echo "$ac_t""$NSGMLS" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+ # Extract the first word of "onsgmls", so it can be a program name with args.
+set dummy onsgmls; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:642: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_NSGMLS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$NSGMLS" in
+ /*)
+ ac_cv_path_NSGMLS="$NSGMLS" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_NSGMLS="$NSGMLS" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_NSGMLS="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+NSGMLS="$ac_cv_path_NSGMLS"
+if test -n "$NSGMLS"; then
+ echo "$ac_t""$NSGMLS" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+# Extract the first word of "htmldoc", so it can be a program name with args.
+set dummy htmldoc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:679: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_HTMLDOC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$HTMLDOC" in
+ /*)
+ ac_cv_path_HTMLDOC="$HTMLDOC" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_HTMLDOC="$HTMLDOC" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_HTMLDOC="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+HTMLDOC="$ac_cv_path_HTMLDOC"
+if test -n "$HTMLDOC"; then
+ echo "$ac_t""$HTMLDOC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "sgmlspl", so it can be a program name with args.
+set dummy sgmlspl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:714: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SGMLSPL'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$SGMLSPL" in
+ /*)
+ ac_cv_path_SGMLSPL="$SGMLSPL" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_SGMLSPL="$SGMLSPL" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_SGMLSPL="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+SGMLSPL="$ac_cv_path_SGMLSPL"
+if test -n "$SGMLSPL"; then
+ echo "$ac_t""$SGMLSPL" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:749: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$PERL" in
+ /*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_PERL="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+PERL="$ac_cv_path_PERL"
+if test -n "$PERL"; then
+ echo "$ac_t""$PERL" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+SGML_SHARE="/usr/local/share/sgml"
+
+# Check whether --with-sgml-share or --without-sgml-share was given.
+if test "${with_sgml_share+set}" = set; then
+ withval="$with_sgml_share"
+ case "$withval" in
+ no) SGML_SHARE=""
+ ;;
+ yes)
+ ;;
+ /*|\\*)
+ SGML_SHARE="$withval"
+ ;;
+ *)
+ SGML_SHARE="/$withval"
+ ;;
+esac
+
+fi
+
+# The Makefile requires docbook2X in the share/sgml directory
+if ! test -f $SGML_SHARE/docbook2X/docbook2man-spec.pl ; then
+ { echo "configure: error: "Unable to find dockbook2X. Make sure it is installed and that the sgml-share path is correct."" 1>&2; exit 1; }
+fi
+
+
+DOC_BUILD_DATE=`date '+%d-%m-%Y'`
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile stylesheets/ldp.dsl " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@JADE@%$JADE%g
+s%@NSGMLS@%$NSGMLS%g
+s%@HTMLDOC@%$HTMLDOC%g
+s%@SGMLSPL@%$SGMLSPL%g
+s%@PERL@%$PERL%g
+s%@SGML_SHARE@%$SGML_SHARE%g
+s%@DOC_BUILD_DATE@%$DOC_BUILD_DATE%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile stylesheets/ldp.dsl "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/docs/docbook/configure.in b/docs/docbook/configure.in
new file mode 100644
index 00000000000..ad0613f2be8
--- /dev/null
+++ b/docs/docbook/configure.in
@@ -0,0 +1,49 @@
+AC_INIT(global.ent)
+
+## check for the necesary install tools
+## Openjade includes 'onsgmls' while
+## the older jade package includes 'nsgmls'
+AC_PATH_PROG(JADE,openjade)
+
+if test -z "$JADE"; then
+ AC_PATH_PROG(JADE,jade)
+ AC_PATH_PROG(NSGMLS, nsgmls)
+else
+ AC_PATH_PROG(NSGMLS, onsgmls)
+fi
+
+AC_PATH_PROG(HTMLDOC, htmldoc)
+AC_PATH_PROG(SGMLSPL, sgmlspl)
+AC_PATH_PROG(PERL, perl)
+
+dnl ----------------------------------------------------------------
+dnl --with-sgml-share
+SGML_SHARE="/usr/local/share/sgml"
+
+AC_ARG_WITH(sgml-share,
+[ --with-sgml-share=DIR change the default location of SGML stylesheets],
+[case "$withval" in
+ no) SGML_SHARE=""
+ ;;
+ yes)
+ ;;
+ /*|\\*)
+ SGML_SHARE="$withval"
+ ;;
+ *)
+ SGML_SHARE="/$withval"
+ ;;
+esac
+])dnl
+
+# The Makefile requires docbook2X in the share/sgml directory
+if [ ! test -f $SGML_SHARE/docbook2X/docbook2man-spec.pl ]; then
+ AC_MSG_ERROR("Unable to find dockbook2X. Make sure it is installed and that the sgml-share path is correct.")
+fi
+
+AC_SUBST(SGML_SHARE)dnl
+
+DOC_BUILD_DATE=`date '+%d-%m-%Y'`
+AC_SUBST(DOC_BUILD_DATE)
+
+AC_OUTPUT( Makefile stylesheets/ldp.dsl )
diff --git a/docs/docbook/dbsgml/40chg.txt b/docs/docbook/dbsgml/40chg.txt
new file mode 100644
index 00000000000..2d2467d9ebc
--- /dev/null
+++ b/docs/docbook/dbsgml/40chg.txt
@@ -0,0 +1,45 @@
+19 June 2000
+
+Changes from DocBook V3.1 to DocBook V4.1:
+
+Markup:
+
+- RFE 17: Added a common attribute 'Condition' for generic effectivity
+- RFE 38: The nav.class elements (ToC|LoT|Index|Glossary|Bibliography) are
+ now allowed at the beginning and end of components and sections
+- RFE 58: The 'optmult' and 'reqmult' attribute values have been
+ removed from Group
+- RFE 65: Added several class attribute values to Filename and SystemItem
+ at the request of the Linux community
+- RFE 73: Removed BookBiblio and SeriesInfo
+- RFE 81: Added SidebarInfo to Sidebar
+- RFE 87: Added 'xmlpi' and 'emptytag' as class values of SGMLTag
+- RFE 92: Added 'CO' to Synopsis and LiteralLayout
+- RFE 99: Added SimpleMsgEntry as an alternative to MsgEntry in order
+ to provide a simpler MsgSet construct
+- RFE 103: Added RevDescription as an alternative to RevRemark in
+ RevHistory; this allows longer descriptive text in a revision
+- RFE 104: Added 'Specification' to the list of document classes on Article
+- RFE 108: Allow admonitions in Answers
+- RFE 110: Allow a RevHistory on QandAEntry
+- RFE 115: Allow optional Title on OrderedList and ItemizedList
+- RFE 116: Added LineNumbering attribute to linespecific environments for
+ presentation of line numbers
+- Added a common attribute 'Security' for effectivity
+- Added synopsis markup for modern programming languages (e.g, object
+ oriented languages like Java, C++, and IDL)
+- Renamed DocInfo to PrefaceInfo, ChapterInfo, AppendixInfo, etc.
+- Comment was renamed Remark
+- InterfaceDefinition was removed
+
+Other:
+
+- RFE 88: Added PEs to include/ignore dbnotn.mod and dbcent.mod
+- RFE 102: Fixed some outstanding namecase problems
+- RFE 105: Added PNG notation
+- RFE 106: Removed some odd *.content PEs that interfered with
+ customization layers
+- RFE 109: Added FPI to content of dbgenent.mod (for consistency)
+- RFE 111: Added the Euro symbol
+- Fixed bug in cals-tbl.dtd; a model group was used for the element
+ declaration, but the attlist declaration used "Table" literally.
diff --git a/docs/docbook/dbsgml/41chg.txt b/docs/docbook/dbsgml/41chg.txt
new file mode 100644
index 00000000000..d2a91478878
--- /dev/null
+++ b/docs/docbook/dbsgml/41chg.txt
@@ -0,0 +1,7 @@
+19 June 2000
+
+Changes from DocBook V4.0 to DocBook V4.1:
+
+No user-visible changes; removed some 4.0 future use comments that had
+accidentally been left in the DTD and fixed a couple of incorrect FPIs.
+See 40chg.txt for a list of the significant changes.
diff --git a/docs/docbook/dbsgml/50issues.txt b/docs/docbook/dbsgml/50issues.txt
new file mode 100644
index 00000000000..31497420f0d
--- /dev/null
+++ b/docs/docbook/dbsgml/50issues.txt
@@ -0,0 +1,39 @@
+19 June 2000
+
+Backwards-incompatible changes to DocBook that are planned for V5.0:
+
+- DocBook V5.0 will be an XML DTD. This will require a wide range of
+ changes. As a result, DocBook V5.0 will more closely resemble
+ The XML version of DocBook V4.1 than the SGML version.
+
+- Parameter entity reorganization may greatly reduce many
+ content models. The goal of this effort is to remove a large
+ number of spurious elements that snuck into content models
+ during the first PE reorg, in practice these changes should have
+ very little "real world" impact.
+
+- The Coords attribute will be removed from AreaSet.
+
+- ArtHeader will be dropped from BiblioEntry
+
+- Contents attribute will be removed from BookInfo and SetInfo
+
+- The %indexdivcomponent.mix; will be restricted. Numbered figures
+ and other elements inappropriate for an Index or SetIndex will be
+ removed.
+
+- RevHistory will be removed from GlossTerm
+
+- Constant Class will be removed from SystemItem
+
+- Graphic and InlineGraphic will be removed
+
+- Tables will be restricted from full CALS to the OASIS Exchange model
+
+- An experimental XML Schema version of DocBook 5.0 will be
+ produced in parallel with the DTD version. It will be
+ backwards-incompatible in an unspecified number of ways. The
+ goal of the effort will be that most DocBook documents that
+ validate under the DTD will also validate under the Schema,
+ but the committee does not feel bound to guarantee this
+ condition.
diff --git a/docs/docbook/dbsgml/ChangeLog b/docs/docbook/dbsgml/ChangeLog
new file mode 100644
index 00000000000..c4673db15a9
--- /dev/null
+++ b/docs/docbook/dbsgml/ChangeLog
@@ -0,0 +1,85 @@
+2000-06-19 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt: Added notes about comment and interfacedefinition
+
+ * 41chg.txt: New file.
+
+ * 50issues.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, readme.txt:
+ Updated version numbers to 4.1
+
+ * dbhier.mod, dbpool.mod: Removed 4.0 future use comments
+
+ * docbook.cat: Fixed version number in comment
+
+ * docbook.dtd: DocBook V4.1 released.
+
+2000-05-18 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Removed references to beta6
+
+ * docbook.dtd: DocBook V4.0 released.
+
+2000-04-10 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Updated release date and version to 4.0beta6
+
+ * dbpool.mod: Added support for EBNF hook; fixed equation content bug
+
+2000-04-03 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt: Added note about renaming DocInfo to *Info.
+
+ * 40chg.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Updated version numbers
+
+2000-03-24 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Updated version numbers
+
+ * 50issues.txt: Added note about PE reorg
+
+ * dbefsyn.mod: Removed
+
+ * dbpool.mod: Removed ELEMENT from comments to ease text searching of the DTD.
+ Merged dbefsyn.mod into dbpool.mod
+ Added Modifier as an optional element at the end of MethodSynopsis
+ and MethodParam.
+
+2000-03-07 Norman Walsh <ndw@nwalsh.com>
+
+ * 40chg.txt, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Updated internal versions to beta3
+
+2000-03-03 Norman Walsh <ndw@nwalsh.com>
+
+ * dbpool.mod: Removed erroneous comment about inline synopses
+
+2000-03-02 Norman Walsh <ndw@nwalsh.com>
+
+ * 30chg.txt, 31chg.txt, 40issues.txt, 50issues.txt, announce.txt, cals-tbl.dtd, dbcent.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Version 3.1
+
+ * 30chg.txt, 40issues.txt, announce.txt, cals-tbl.dtd, dbgenent.mod, dbhier.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd:
+ branches: 1.1.1;
+ Initial revision
+
+ * 30chg.txt, 40issues.txt, announce.txt, cals-tbl.dtd, dbgenent.mod, dbhier.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd:
+ New file.
+
+ * 31chg.txt, 40chg.txt, 40issues.txt, 50issues.txt, cals-tbl.dtd, dbcent.mod, dbefsyn.mod, dbgenent.mod, dbhier.mod, dbnotn.mod, dbpool.mod, docbook.cat, docbook.dcl, docbook.dtd, readme.txt:
+ Version 4.0beta2
+
+ * 50issues.txt: Added warning about exchange table model
+
+ * dbefsyn.mod, dbpool.mod: Added ooclass, oointerface, and ooexception as wrappers for modifiers
+ and names in classsynopsis. Also allow them inline.
+
+ Fixed SGML PE parsing problem with hook PEs.
+
+ * dbhier.mod, dbpool.mod: Added hook PEs for future module extension
+
+ * dbpool.mod, docbook.dtd: Removed reference to sgml-features PE
+
diff --git a/docs/docbook/dbsgml/cals-tbl.dtd b/docs/docbook/dbsgml/cals-tbl.dtd
new file mode 100644
index 00000000000..78c7d5a3ae1
--- /dev/null
+++ b/docs/docbook/dbsgml/cals-tbl.dtd
@@ -0,0 +1,330 @@
+<!-- CALS TABLE MODEL DECLARATION MODULE -->
+
+<!-- This set of declarations defines the CALS Table Model as of the
+ date shown in the Formal Public Identifier (FPI) for this entity.
+
+ This set of declarations may be referred to using a public external
+ entity declaration and reference as shown in the following two lines:
+
+<!ENTITY % calstbls PUBLIC "-//USA-DOD//DTD Table Model 951010//EN">
+%calstbls;
+
+ If various parameter entities used within this set of declarations
+ are to be given non-default values, the appropriate declarations
+ should be given before calling in this package (i.e., before the
+ "%calstbls;" reference).
+
+ NOTE: This set of declarations assumes a NAMELEN of 32 as is used in
+ the standard CALS defined SGML declaration.
+-->
+
+<!-- This entity includes a set of element and attribute declarations
+ that partially defines the CALS table model. However, the model
+ is not well-defined without the accompanying natural language
+ description of the semantics (meanings) of these various elements,
+ attributes, and attribute values. The semantic writeup, available
+ as a separate entity, should be used in conjunction with this entity.
+-->
+
+<!-- In order to use the CALS table model, various parameter entity
+ declarations are required. A brief description is as follows:
+
+ ENTITY NAME WHERE USED WHAT IT IS
+
+ %bodyatt In ATTLIST of: Additional (non-table related)
+ table element(s) attributes on the overall
+ (wrapper) table element(s)
+
+ %secur In ATTLIST of: Additional (non-table related)
+ table element(s) attributes on all the listed
+ <tgroup> elements
+ <tbody>
+ table head and foot element(s)
+ <row>
+ <entrytbl>
+ <entry>
+
+ %yesorno In ATTLIST of: An attribute declared value
+ almost all elements for a "boolean" attribute
+
+ %titles In content model of: The "title" part of the model
+ table element(s) group for the table element(s)
+
+ %paracon In content model of: The "text" (data content) part
+ <entry> of the model group for <entry>
+
+ %tbl.table.name In declaration of: The name(s) of the "table"
+ table element(s) element(s)
+
+ %tbl.table-titles.mdl In content model of: The model group for the title
+ table elements(s) part of the content model for
+ table element(s)
+
+ %tbl.table-main.mdl In content model of: The model group for the main part
+ table elements(s) (not including titles) of the
+ content model for table element(s)
+
+ %tbl.table.mdl In content model of: The model group for the content
+ table elements(s) model for table element(s),
+ often (and by default) defined
+ in terms of %tbl.table-titles.mdl
+ and %tbl.table-main.mdl
+
+ %tbl.table.excep In content model of: The exceptions for the content
+ table element(s) model for table element(s)
+
+ %tbl.table.att In ATTLIST of: Additional attributes on the
+ table element(s) table element(s)
+
+ %tbl.tgroup.mdl In content model of: The model group for the content
+ <tgroup> model for <tgroup>
+
+ %tbl.tgroup.att In ATTLIST of: Additional attributes on the
+ <tgroup> <tgroup> and <entrytbl> elements
+ <entrytbl>
+
+ %tbl.hdft.name In declaration of: The name(s) of the table
+ head/foot element(s) head and foot element(s)
+
+ %tbl.hdft.mdl In content model of: The model group for the content
+ head/foot element(s) model for head/foot element(s)
+
+ %tbl.hdft.excep In content model of: The exceptions for the content
+ head/foot element(s) model for head/foot element(s)
+
+ %tbl.row.mdl In content model of: The model group for the content
+ <row> model for <row>
+
+ %tbl.row.excep In content model of: The exceptions for the content
+ <row> model for <row>
+
+ %tbl.entrytbl.mdl In content model of: The model group for the content
+ <entrytbl> model for <entrytbl>
+
+ %tbl.entrytbl.excep In content model of: The exceptions for the content
+ <entrytbl> model for <entrytbl>
+
+ %tbl.entry.mdl In content model of: The model group for the content
+ <entry> model for <entry>
+
+ %tbl.entry.excep In content model of: The exceptions for the content
+ <entry> model for <entry>
+
+ If any of these parameter entities are not declared before this set of
+ declarations is referenced, this set of declarations will make the
+ following default definitions for all of these have parameter entities.
+-->
+
+<!-- These definitions are not directly related to the table model, but are
+ used in the default CALS table model and are usually defined elsewhere
+ (and prior to the inclusion of this table module) in a CALS DTD. -->
+
+<!ENTITY % bodyatt "">
+<!ENTITY % secur "">
+<!ENTITY % yesorno 'NUMBER' -- no if zero(s),
+ yes if any other digits value -->
+<!ENTITY % titles 'title?'>
+<!ENTITY % paracon '#PCDATA' -- default for use in entry content -->
+
+<!--
+The parameter entities as defined below provide the CALS table model
+as published (as part of the Example DTD) in MIL-HDBK-28001.
+
+These following declarations provide the CALS-compliant default definitions
+for these entities. However, these entities can and should be redefined
+(by giving the appropriate parameter entity declaration(s) prior to the
+reference to this Table Model declaration set entity) to fit the needs
+of the current application.
+-->
+
+<!ENTITY % tbl.table.name "(table|chart)">
+<!ENTITY % tbl.table-titles.mdl "%titles,">
+<!ENTITY % tbl.table-main.mdl "(tgroup+|graphic+)">
+<!ENTITY % tbl.table.mdl "%tbl.table-titles.mdl; %tbl.table-main.mdl;">
+<!ENTITY % tbl.table.excep "-(table|chart|figure)">
+<!ENTITY % tbl.table.att '
+ tabstyle NMTOKEN #IMPLIED
+ tocentry %yesorno; #IMPLIED
+ shortentry %yesorno; #IMPLIED
+ orient (port|land) #IMPLIED
+ pgwide %yesorno; #IMPLIED '>
+<!ENTITY % tbl.tgroup.mdl "colspec*,spanspec*,thead?,tfoot?,tbody">
+<!ENTITY % tbl.tgroup.att '
+ tgroupstyle NMTOKEN #IMPLIED '>
+<!ENTITY % tbl.hdft.name "(thead|tfoot)">
+<!ENTITY % tbl.hdft.mdl "colspec*,row+">
+<!ENTITY % tbl.hdft.excep "-(entrytbl)">
+<!ENTITY % tbl.row.mdl "(entry|entrytbl)+">
+<!ENTITY % tbl.row.excep "-(pgbrk)">
+<!ENTITY % tbl.entrytbl.mdl "colspec*,spanspec*,thead?,tbody">
+<!ENTITY % tbl.entrytbl.excep "-(entrytbl|pgbrk)">
+<!ENTITY % tbl.entry.mdl "(para|warning|caution|note|legend|%paracon;)*">
+<!ENTITY % tbl.entry.excep "-(pgbrk)">
+
+<!-- ===== Element and attribute declarations follow. ===== -->
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % tbl.table.name "(table|chart)"
+ ENTITY % tbl.table-titles.mdl "%titles,"
+ ENTITY % tbl.table-main.mdl "(tgroup+|graphic+)"
+ ENTITY % tbl.table.mdl "%tbl.table-titles; %tbl.table-main.mdl;"
+ ENTITY % tbl.table.excep "-(table|chart|figure)"
+ ENTITY % tbl.table.att '
+ tabstyle NMTOKEN #IMPLIED
+ tocentry %yesorno; #IMPLIED
+ shortentry %yesorno; #IMPLIED
+ orient (port|land) #IMPLIED
+ pgwide %yesorno; #IMPLIED '
+-->
+
+<!ELEMENT %tbl.table.name; - - (%tbl.table.mdl;) %tbl.table.excep; >
+
+<!ATTLIST %tbl.table.name;
+ frame (top|bottom|topbot|all|sides|none) #IMPLIED
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ %tbl.table.att;
+ %bodyatt;
+ %secur;
+>
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % tbl.tgroup.mdl "colspec*,spanspec*,thead?,tfoot?,tbody"
+ ENTITY % tbl.tgroup.att '
+ tgroupstyle NMTOKEN #IMPLIED '
+-->
+
+<!ELEMENT tgroup - O (%tbl.tgroup.mdl;) >
+
+<!ATTLIST tgroup
+ cols NUMBER #REQUIRED
+ %tbl.tgroup.att;
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ align (left|right|center|justify|char) #IMPLIED
+ char CDATA #IMPLIED
+ charoff NUTOKEN #IMPLIED
+ %secur;
+>
+
+<!ELEMENT colspec - O EMPTY >
+
+<!ATTLIST colspec
+ colnum NUMBER #IMPLIED
+ colname NMTOKEN #IMPLIED
+ colwidth CDATA #IMPLIED
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ align (left|right|center|justify|char) #IMPLIED
+ char CDATA #IMPLIED
+ charoff NUTOKEN #IMPLIED
+>
+
+<!ELEMENT spanspec - O EMPTY >
+
+<!ATTLIST spanspec
+ namest NMTOKEN #REQUIRED
+ nameend NMTOKEN #REQUIRED
+ spanname NMTOKEN #REQUIRED
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ align (left|right|center|justify|char) #IMPLIED
+ char CDATA #IMPLIED
+ charoff NUTOKEN #IMPLIED
+>
+
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % tbl.hdft.name "(thead|tfoot)"
+ ENTITY % tbl.hdft.mdl "colspec*,row+"
+ ENTITY % tbl.hdft.excep "-(entrytbl)"
+-->
+
+<!ELEMENT %tbl.hdft.name; - O (%tbl.hdft.mdl;) %tbl.hdft.excep;>
+
+<!ATTLIST %tbl.hdft.name;
+ valign (top|middle|bottom) #IMPLIED
+ %secur;
+>
+
+
+<!ELEMENT tbody - O (row+)>
+
+<!ATTLIST tbody
+ valign (top|middle|bottom) #IMPLIED
+ %secur;
+>
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % tbl.row.mdl "(entry|entrytbl)+"
+ ENTITY % tbl.row.excep "-(pgbrk)"
+-->
+
+<!ELEMENT row - O (%tbl.row.mdl;) %tbl.row.excep;>
+
+<!ATTLIST row
+ rowsep %yesorno; #IMPLIED
+ valign (top|middle|bottom) #IMPLIED
+ %secur;
+>
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % tbl.entrytbl.mdl "colspec*,spanspec*,thead?,tbody"
+ ENTITY % tbl.entrytbl.excep "-(entrytbl|pgbrk)"
+ ENTITY % tbl.tgroup.att '
+ tgroupstyle NMTOKEN #IMPLIED '
+-->
+
+<!ELEMENT entrytbl - - (%tbl.entrytbl.mdl) %tbl.entrytbl.excep; >
+
+<!ATTLIST entrytbl
+ cols NUMBER #REQUIRED
+ %tbl.tgroup.att;
+ colname NMTOKEN #IMPLIED
+ spanname NMTOKEN #IMPLIED
+ namest NMTOKEN #IMPLIED
+ nameend NMTOKEN #IMPLIED
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ align (left|right|center|justify|char) #IMPLIED
+ char CDATA #IMPLIED
+ charoff NUTOKEN #IMPLIED
+ %secur;
+>
+
+
+<!--
+ Default declarations previously defined in this entity and
+ referenced below include:
+ ENTITY % paracon "#PCDATA"
+ ENTITY % tbl.entry.mdl "(para|warning|caution|note|legend|%paracon;)*"
+ ENTITY % tbl.entry.excep "-(pgbrk)"
+-->
+
+<!ELEMENT entry - O (%tbl.entry.mdl;) %tbl.entry.excep; >
+
+<!ATTLIST entry
+ colname NMTOKEN #IMPLIED
+ namest NMTOKEN #IMPLIED
+ nameend NMTOKEN #IMPLIED
+ spanname NMTOKEN #IMPLIED
+ morerows NUMBER #IMPLIED
+ colsep %yesorno; #IMPLIED
+ rowsep %yesorno; #IMPLIED
+ align (left|right|center|justify|char) #IMPLIED
+ char CDATA #IMPLIED
+ charoff NUTOKEN #IMPLIED
+ rotate %yesorno; #IMPLIED
+ valign (top|middle|bottom) #IMPLIED
+ %secur;
+>
diff --git a/docs/docbook/dbsgml/catalog b/docs/docbook/dbsgml/catalog
new file mode 100644
index 00000000000..521e8201c8c
--- /dev/null
+++ b/docs/docbook/dbsgml/catalog
@@ -0,0 +1,63 @@
+ -- ...................................................................... --
+ -- Catalog data for DocBook V4.1 ........................................ --
+ -- File docbook.cat ..................................................... --
+
+ -- Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/.
+ --
+
+ -- This is the catalog data file for DocBook V4.1. It is provided as
+ a convenience in building your own catalog files. You need not use
+ the filenames listed here, and need not use the filename method of
+ identifying storage objects at all. See the documentation for
+ detailed information on the files associated with the DocBook DTD.
+ See SGML Open Technical Resolution 9401 for detailed information
+ on supplying and using catalog data.
+ --
+
+ -- ...................................................................... --
+ -- SGML declaration associated with DocBook ............................. --
+
+DTDDECL "-//OASIS//DTD DocBook V4.1//EN" "docbook.dcl"
+
+ -- ...................................................................... --
+ -- DocBook driver file .................................................. --
+
+PUBLIC "-//OASIS//DTD DocBook V4.1//EN" "docbook.dtd"
+
+ -- ...................................................................... --
+ -- DocBook modules ...................................................... --
+
+PUBLIC "-//USA-DOD//DTD Table Model 951010//EN" "cals-tbl.dtd"
+PUBLIC "-//OASIS//ELEMENTS DocBook Information Pool V4.1//EN" "dbpool.mod"
+PUBLIC "-//OASIS//ELEMENTS DocBook Document Hierarchy V4.1//EN" "dbhier.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Additional General Entities V4.1//EN" "dbgenent.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Notations V4.1//EN" "dbnotn.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Character Entities V4.1//EN" "dbcent.mod"
+
+ -- ...................................................................... --
+ -- ISO entity sets ...................................................... --
+
+PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN" "ent/ISOdia"
+PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN" "ent/ISOnum"
+PUBLIC "ISO 8879:1986//ENTITIES Publishing//EN" "ent/ISOpub"
+PUBLIC "ISO 8879:1986//ENTITIES General Technical//EN" "ent/ISOtech"
+PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN" "ent/ISOlat1"
+PUBLIC "ISO 8879:1986//ENTITIES Added Latin 2//EN" "ent/ISOlat2"
+PUBLIC "ISO 8879:1986//ENTITIES Greek Letters//EN" "ent/ISOgrk1"
+PUBLIC "ISO 8879:1986//ENTITIES Monotoniko Greek//EN" "ent/ISOgrk2"
+PUBLIC "ISO 8879:1986//ENTITIES Greek Symbols//EN" "ent/ISOgrk3"
+PUBLIC "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN" "ent/ISOgrk4"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN" "ent/ISOamsa"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN" "ent/ISOamsb"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN" "ent/ISOamsc"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN" "ent/ISOamsn"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN" "ent/ISOamso"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN" "ent/ISOamsr"
+PUBLIC "ISO 8879:1986//ENTITIES Box and Line Drawing//EN" "ent/ISObox"
+PUBLIC "ISO 8879:1986//ENTITIES Russian Cyrillic//EN" "ent/ISOcyr1"
+PUBLIC "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN" "ent/ISOcyr2"
+
+ -- End of catalog data for DocBook V4.1 ................................. --
+ -- ...................................................................... --
diff --git a/docs/docbook/dbsgml/dbcent.mod b/docs/docbook/dbsgml/dbcent.mod
new file mode 100755
index 00000000000..7f052110197
--- /dev/null
+++ b/docs/docbook/dbsgml/dbcent.mod
@@ -0,0 +1,181 @@
+<!-- ...................................................................... -->
+<!-- DocBook character entities module V4.1 ............................... -->
+<!-- File dbcent.mod ...................................................... -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ $Id: dbcent.mod,v 1.3 2001/12/06 07:37:55 jerry Exp $
+
+ Permission to use, copy, modify and distribute the DocBook DTD and
+ its accompanying documentation for any purpose and without fee is
+ hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ If you modify the DocBook DTD in any way, except for declaring and
+ referencing additional sets of general entities and declaring
+ additional notations, label your DTD as a variant of DocBook. See
+ the maintenance documentation for more information.
+
+ Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/docbook/.
+-->
+
+<!-- ...................................................................... -->
+
+<!-- This module contains the entity declarations for the standard ISO
+ entity sets used by DocBook.
+
+ In DTD driver files referring to this module, please use an entity
+ declaration that uses the public identifier shown below:
+
+ <!ENTITY % dbcent PUBLIC
+ "-//OASIS//ENTITIES DocBook Character Entities V4.1//EN">
+ %dbcent;
+
+ See the documentation for detailed information on the parameter
+ entity and module scheme used in DocBook, customizing DocBook and
+ planning for interchange, and changes made since the last release
+ of DocBook.
+-->
+
+<!-- ...................................................................... -->
+
+<!ENTITY % ISOamsa.module "INCLUDE">
+<![ %ISOamsa.module; [
+<!ENTITY % ISOamsa PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN">
+%ISOamsa;
+<!--end of ISOamsa.module-->]]>
+
+<!ENTITY % ISOamsb.module "INCLUDE">
+<![ %ISOamsb.module; [
+<!ENTITY % ISOamsb PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN">
+%ISOamsb;
+<!--end of ISOamsb.module-->]]>
+
+<!ENTITY % ISOamsc.module "INCLUDE">
+<![ %ISOamsc.module; [
+<!ENTITY % ISOamsc PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN">
+%ISOamsc;
+<!--end of ISOamsc.module-->]]>
+
+<!ENTITY % ISOamsn.module "INCLUDE">
+<![ %ISOamsn.module; [
+<!ENTITY % ISOamsn PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN">
+%ISOamsn;
+<!--end of ISOamsn.module-->]]>
+
+<!ENTITY % ISOamso.module "INCLUDE">
+<![ %ISOamso.module; [
+<!ENTITY % ISOamso PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN">
+%ISOamso;
+<!--end of ISOamso.module-->]]>
+
+<!ENTITY % ISOamsr.module "INCLUDE">
+<![ %ISOamsr.module; [
+<!ENTITY % ISOamsr PUBLIC
+"ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN">
+%ISOamsr;
+<!--end of ISOamsr.module-->]]>
+
+<!ENTITY % ISObox.module "INCLUDE">
+<![ %ISObox.module; [
+<!ENTITY % ISObox PUBLIC
+"ISO 8879:1986//ENTITIES Box and Line Drawing//EN">
+%ISObox;
+<!--end of ISObox.module-->]]>
+
+<!ENTITY % ISOcyr1.module "INCLUDE">
+<![ %ISOcyr1.module; [
+<!ENTITY % ISOcyr1 PUBLIC
+"ISO 8879:1986//ENTITIES Russian Cyrillic//EN">
+%ISOcyr1;
+<!--end of ISOcyr1.module-->]]>
+
+<!ENTITY % ISOcyr2.module "INCLUDE">
+<![ %ISOcyr2.module; [
+<!ENTITY % ISOcyr2 PUBLIC
+"ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN">
+%ISOcyr2;
+<!--end of ISOcyr2.module-->]]>
+
+<!ENTITY % ISOdia.module "INCLUDE">
+<![ %ISOdia.module; [
+<!ENTITY % ISOdia PUBLIC
+"ISO 8879:1986//ENTITIES Diacritical Marks//EN">
+%ISOdia;
+<!--end of ISOdia.module-->]]>
+
+<!ENTITY % ISOgrk1.module "INCLUDE">
+<![ %ISOgrk1.module; [
+<!ENTITY % ISOgrk1 PUBLIC
+"ISO 8879:1986//ENTITIES Greek Letters//EN">
+%ISOgrk1;
+<!--end of ISOgrk1.module-->]]>
+
+<!ENTITY % ISOgrk2.module "INCLUDE">
+<![ %ISOgrk2.module; [
+<!ENTITY % ISOgrk2 PUBLIC
+"ISO 8879:1986//ENTITIES Monotoniko Greek//EN">
+%ISOgrk2;
+<!--end of ISOgrk2.module-->]]>
+
+<!ENTITY % ISOgrk3.module "INCLUDE">
+<![ %ISOgrk3.module; [
+<!ENTITY % ISOgrk3 PUBLIC
+"ISO 8879:1986//ENTITIES Greek Symbols//EN">
+%ISOgrk3;
+<!--end of ISOgrk3.module-->]]>
+
+<!ENTITY % ISOgrk4.module "INCLUDE">
+<![ %ISOgrk4.module; [
+<!ENTITY % ISOgrk4 PUBLIC
+"ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN">
+%ISOgrk4;
+<!--end of ISOgrk4.module-->]]>
+
+<!ENTITY % ISOlat1.module "INCLUDE">
+<![ %ISOlat1.module; [
+<!ENTITY % ISOlat1 PUBLIC
+"ISO 8879:1986//ENTITIES Added Latin 1//EN">
+%ISOlat1;
+<!--end of ISOlat1.module-->]]>
+
+<!ENTITY % ISOlat2.module "INCLUDE">
+<![ %ISOlat2.module; [
+<!ENTITY % ISOlat2 PUBLIC
+"ISO 8879:1986//ENTITIES Added Latin 2//EN">
+%ISOlat2;
+<!--end of ISOlat2.module-->]]>
+
+<!ENTITY % ISOnum.module "INCLUDE">
+<![ %ISOnum.module; [
+<!ENTITY % ISOnum PUBLIC
+"ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN">
+%ISOnum;
+<!--end of ISOnum.module-->]]>
+
+<!ENTITY % ISOpub.module "INCLUDE">
+<![ %ISOpub.module; [
+<!ENTITY % ISOpub PUBLIC
+"ISO 8879:1986//ENTITIES Publishing//EN">
+%ISOpub;
+<!--end of ISOpub.module-->]]>
+
+<!ENTITY % ISOtech.module "INCLUDE">
+<![ %ISOtech.module; [
+<!ENTITY % ISOtech PUBLIC
+"ISO 8879:1986//ENTITIES General Technical//EN">
+%ISOtech;
+<!--end of ISOtech.module-->]]>
diff --git a/docs/docbook/dbsgml/dbgenent.mod b/docs/docbook/dbsgml/dbgenent.mod
new file mode 100644
index 00000000000..b60c5b27140
--- /dev/null
+++ b/docs/docbook/dbsgml/dbgenent.mod
@@ -0,0 +1,39 @@
+<!-- ...................................................................... -->
+<!-- DocBook additional general entities V4.1 ............................. -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ In DTD driver files referring to this module, please use an entity
+ declaration that uses the public identifier shown below:
+
+ <!ENTITY % dbgenent PUBLIC
+ "-//OASIS//ENTITIES DocBook Additional General Entities V4.1//EN"
+ %dbgenent;
+-->
+
+<!-- File dbgenent.mod .................................................... -->
+
+<!-- You can edit this file to add the following:
+
+ o General entity declarations of any kind. For example:
+
+ <!ENTITY happyface SDATA "insert-face"> (system-specific data)
+ <!ENTITY productname "WinWidget"> (small boilerplate)
+ <!ENTITY legal-notice SYSTEM "notice.sgm"> (large boilerplate)
+
+ o Notation declarations. For example:
+
+ <!NOTATION chicken-scratch SYSTEM>
+
+ o Declarations for and references to external parameter entities
+ containing collections of any of the above. For example:
+
+ <!ENTITY % all-titles PUBLIC "-//DocTools//ELEMENTS Book Titles//EN">
+ %all-titles;
+-->
+
+<!-- End of DocBook additional general entities V4.1 ...................... -->
+<!-- ...................................................................... -->
diff --git a/docs/docbook/dbsgml/dbhier.mod b/docs/docbook/dbsgml/dbhier.mod
new file mode 100755
index 00000000000..10e1f3f33f7
--- /dev/null
+++ b/docs/docbook/dbsgml/dbhier.mod
@@ -0,0 +1,2100 @@
+<!-- ...................................................................... -->
+<!-- DocBook document hierarchy module V4.1 ............................... -->
+<!-- File dbhier.mod ...................................................... -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ $Id: dbhier.mod,v 1.3 2001/12/06 07:37:55 jerry Exp $
+
+ Permission to use, copy, modify and distribute the DocBook DTD and
+ its accompanying documentation for any purpose and without fee is
+ hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ If you modify the DocBook DTD in any way, except for declaring and
+ referencing additional sets of general entities and declaring
+ additional notations, label your DTD as a variant of DocBook. See
+ the maintenance documentation for more information.
+
+ Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/docbook/.
+-->
+
+<!-- ...................................................................... -->
+
+<!-- This module contains the definitions for the overall document
+ hierarchies of DocBook documents. It covers computer documentation
+ manuals and manual fragments, as well as reference entries (such as
+ man pages) and technical journals or anthologies containing
+ articles.
+
+ This module depends on the DocBook information pool module. All
+ elements and entities referenced but not defined here are assumed
+ to be defined in the information pool module.
+
+ In DTD driver files referring to this module, please use an entity
+ declaration that uses the public identifier shown below:
+
+ <!ENTITY % dbhier PUBLIC
+ "-//OASIS//ELEMENTS DocBook Document Hierarchy V4.1//EN">
+ %dbhier;
+
+ See the documentation for detailed information on the parameter
+ entity and module scheme used in DocBook, customizing DocBook and
+ planning for interchange, and changes made since the last release
+ of DocBook.
+-->
+
+<!-- ...................................................................... -->
+<!-- Entities for module inclusions ....................................... -->
+
+<!ENTITY % dbhier.redecl.module "IGNORE">
+<!ENTITY % dbhier.redecl2.module "IGNORE">
+
+<!-- ...................................................................... -->
+<!-- Entities for element classes ......................................... -->
+
+<!ENTITY % local.appendix.class "">
+<!ENTITY % appendix.class "Appendix %local.appendix.class;">
+
+<!ENTITY % local.article.class "">
+<!ENTITY % article.class "Article %local.article.class;">
+
+<!ENTITY % local.book.class "">
+<!ENTITY % book.class "Book %local.book.class;">
+
+<!ENTITY % local.chapter.class "">
+<!ENTITY % chapter.class "Chapter %local.chapter.class;">
+
+<!ENTITY % local.index.class "">
+<!ENTITY % index.class "Index|SetIndex %local.index.class;">
+
+<!ENTITY % local.refentry.class "">
+<!ENTITY % refentry.class "RefEntry %local.refentry.class;">
+
+<!ENTITY % local.nav.class "">
+<!ENTITY % nav.class "ToC|LoT|Index|Glossary|Bibliography
+ %local.nav.class;">
+
+<!-- Redeclaration placeholder ............................................ -->
+
+<!-- For redeclaring entities that are declared after this point while
+ retaining their references to the entities that are declared before
+ this point -->
+
+<![ %dbhier.redecl.module; [
+%rdbhier;
+<!--end of dbhier.redecl.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Entities for element mixtures ........................................ -->
+
+<!-- The DocBook TC may produce an official forms module for DocBook. -->
+<!-- This PE provides the hook by which it can be inserted into the DTD. -->
+<!ENTITY % forms.hook "">
+
+<!ENTITY % local.divcomponent.mix "">
+<!ENTITY % divcomponent.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |%compound.class;
+ |%genobj.class; |%descobj.class;
+ |%ndxterm.class;
+ %forms.hook;
+ %local.divcomponent.mix;">
+
+<!ENTITY % local.refcomponent.mix "">
+<!ENTITY % refcomponent.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |%compound.class;
+ |%genobj.class; |%descobj.class;
+ |%ndxterm.class;
+ %local.refcomponent.mix;">
+
+<!ENTITY % local.indexdivcomponent.mix "">
+<!ENTITY % indexdivcomponent.mix
+ "ItemizedList|OrderedList|VariableList|SimpleList
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |Anchor|Remark
+ |%link.char.class;
+ %local.indexdivcomponent.mix;">
+
+<!ENTITY % local.refname.char.mix "">
+<!ENTITY % refname.char.mix
+ "#PCDATA
+ |%tech.char.class;
+ %local.refname.char.mix;">
+
+<!ENTITY % local.partcontent.mix "">
+<!ENTITY % partcontent.mix
+ "%appendix.class;|%chapter.class;|%nav.class;|%article.class;
+ |Preface|%refentry.class;|Reference %local.partcontent.mix;">
+
+<!ENTITY % local.refinline.char.mix "">
+<!ENTITY % refinline.char.mix
+ "#PCDATA
+ |%xref.char.class; |%gen.char.class;
+ |%link.char.class; |%tech.char.class;
+ |%base.char.class; |%docinfo.char.class;
+ |%other.char.class;
+ |%ndxterm.class;
+ %local.refinline.char.mix;">
+
+<!ENTITY % local.refclass.char.mix "">
+<!ENTITY % refclass.char.mix
+ "#PCDATA
+ |Application
+ %local.refclass.char.mix;">
+
+<!-- Redeclaration placeholder 2 .......................................... -->
+
+<!-- For redeclaring entities that are declared after this point while
+ retaining their references to the entities that are declared before
+ this point -->
+
+<![ %dbhier.redecl2.module; [
+%rdbhier2;
+<!--end of dbhier.redecl2.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Entities for content models .......................................... -->
+
+<!ENTITY % div.title.content
+ "Title, Subtitle?, TitleAbbrev?">
+
+<!ENTITY % bookcomponent.title.content
+ "Title, Subtitle?, TitleAbbrev?">
+
+<!ENTITY % sect.title.content
+ "Title, Subtitle?, TitleAbbrev?">
+
+<!ENTITY % refsect.title.content
+ "Title, Subtitle?, TitleAbbrev?">
+
+<!ENTITY % bookcomponent.content
+ "((%divcomponent.mix;)+,
+ (Sect1*|(%refentry.class;)*|SimpleSect*|Section*))
+ | (Sect1+|(%refentry.class;)+|SimpleSect+|Section+)">
+
+<!-- ...................................................................... -->
+<!-- Set and SetInfo ...................................................... -->
+
+<!ENTITY % set.content.module "INCLUDE">
+<![ %set.content.module; [
+<!ENTITY % set.module "INCLUDE">
+<![ %set.module; [
+<!ENTITY % local.set.attrib "">
+<!ENTITY % set.role.attrib "%role.attrib;">
+
+<!ENTITY % set.element "INCLUDE">
+<![ %set.element; [
+<!ELEMENT Set - O ((%div.title.content;)?, SetInfo?, ToC?, (%book.class;)+,
+ SetIndex?) %ubiq.inclusion;>
+<!--end of set.element-->]]>
+
+<!ENTITY % set.attlist "INCLUDE">
+<![ %set.attlist; [
+<!ATTLIST Set
+ --
+ FPI: SGML formal public identifier
+ --
+ FPI CDATA #IMPLIED
+ %status.attrib;
+ %common.attrib;
+ %set.role.attrib;
+ %local.set.attrib;
+>
+<!--end of set.attlist-->]]>
+<!--end of set.module-->]]>
+
+<!ENTITY % setinfo.module "INCLUDE">
+<![ %setinfo.module; [
+<!ENTITY % local.setinfo.attrib "">
+<!ENTITY % setinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % setinfo.element "INCLUDE">
+<![ %setinfo.element; [
+<!ELEMENT SetInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec | SubjectSet
+ | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of setinfo.element-->]]>
+
+<!ENTITY % setinfo.attlist "INCLUDE">
+<![ %setinfo.attlist; [
+<!--FUTURE USE (V5.0):
+......................
+The Contents attribute will be removed from SetInfo
+......................
+-->
+<!ATTLIST SetInfo
+ --
+ Contents: IDs of the ToC, Books, and SetIndex that comprise
+ the set, in the order of their appearance
+ --
+ Contents IDREFS #IMPLIED
+ %common.attrib;
+ %setinfo.role.attrib;
+ %local.setinfo.attrib;
+>
+<!--end of setinfo.attlist-->]]>
+<!--end of setinfo.module-->]]>
+<!--end of set.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Book and BookInfo .................................................... -->
+
+<!ENTITY % book.content.module "INCLUDE">
+<![ %book.content.module; [
+<!ENTITY % book.module "INCLUDE">
+<![ %book.module; [
+
+<!ENTITY % local.book.attrib "">
+<!ENTITY % book.role.attrib "%role.attrib;">
+
+<!ENTITY % book.element "INCLUDE">
+<![ %book.element; [
+<!ELEMENT Book - O ((%div.title.content;)?, BookInfo?,
+ (Dedication | ToC | LoT
+ | Glossary | Bibliography | Preface
+ | %chapter.class; | Reference | Part
+ | %article.class;
+ | %appendix.class;
+ | %index.class;
+ | Colophon)*)
+ %ubiq.inclusion;>
+<!--end of book.element-->]]>
+
+<!ENTITY % book.attlist "INCLUDE">
+<![ %book.attlist; [
+<!ATTLIST Book
+ --
+ FPI: SGML formal public identifier
+ --
+ FPI CDATA #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %book.role.attrib;
+ %local.book.attrib;
+>
+<!--end of book.attlist-->]]>
+<!--end of book.module-->]]>
+
+<!ENTITY % bookinfo.module "INCLUDE">
+<![ %bookinfo.module; [
+<!ENTITY % local.bookinfo.attrib "">
+<!ENTITY % bookinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % bookinfo.element "INCLUDE">
+<![ %bookinfo.element; [
+<!ELEMENT BookInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec | SubjectSet
+ | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of bookinfo.element-->]]>
+
+<!ENTITY % bookinfo.attlist "INCLUDE">
+<![ %bookinfo.attlist; [
+<!--FUTURE USE (V5.0):
+......................
+The Contents attribute will be removed from BookInfo
+......................
+-->
+<!ATTLIST BookInfo
+ --
+ Contents: IDs of the ToC, LoTs, Prefaces, Parts, Chapters,
+ Appendixes, References, GLossary, Bibliography, and indexes
+ comprising the Book, in the order of their appearance
+ --
+ Contents IDREFS #IMPLIED
+ %common.attrib;
+ %bookinfo.role.attrib;
+ %local.bookinfo.attrib;
+>
+<!--end of bookinfo.attlist-->]]>
+<!--end of bookinfo.module-->]]>
+<!--end of book.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Dedication, ToC, and LoT ............................................. -->
+
+<!ENTITY % dedication.module "INCLUDE">
+<![ %dedication.module; [
+<!ENTITY % local.dedication.attrib "">
+<!ENTITY % dedication.role.attrib "%role.attrib;">
+
+<!ENTITY % dedication.element "INCLUDE">
+<![ %dedication.element; [
+<!ELEMENT Dedication - O ((%sect.title.content;)?, (%legalnotice.mix;)+)>
+<!--end of dedication.element-->]]>
+
+<!ENTITY % dedication.attlist "INCLUDE">
+<![ %dedication.attlist; [
+<!ATTLIST Dedication
+ %status.attrib;
+ %common.attrib;
+ %dedication.role.attrib;
+ %local.dedication.attrib;
+>
+<!--end of dedication.attlist-->]]>
+<!--end of dedication.module-->]]>
+
+<!ENTITY % colophon.module "INCLUDE">
+<![ %colophon.module; [
+<!ENTITY % local.colophon.attrib "">
+<!ENTITY % colophon.role.attrib "%role.attrib;">
+
+<!ENTITY % colophon.element "INCLUDE">
+<![ %colophon.element; [
+<!ELEMENT Colophon - O ((%sect.title.content;)?, (%textobject.mix;)+)>
+<!--end of colophon.element-->]]>
+
+<!ENTITY % colophon.attlist "INCLUDE">
+<![ %colophon.attlist; [
+<!ATTLIST Colophon
+ %status.attrib;
+ %common.attrib;
+ %colophon.role.attrib;
+ %local.colophon.attrib;>
+<!--end of colophon.attlist-->]]>
+<!--end of colophon.module-->]]>
+
+<!ENTITY % toc.content.module "INCLUDE">
+<![ %toc.content.module; [
+<!ENTITY % toc.module "INCLUDE">
+<![ %toc.module; [
+<!ENTITY % local.toc.attrib "">
+<!ENTITY % toc.role.attrib "%role.attrib;">
+
+<!ENTITY % toc.element "INCLUDE">
+<![ %toc.element; [
+<!ELEMENT ToC - O ((%bookcomponent.title.content;)?, ToCfront*,
+ (ToCpart | ToCchap)*, ToCback*)>
+<!--end of toc.element-->]]>
+
+<!ENTITY % toc.attlist "INCLUDE">
+<![ %toc.attlist; [
+<!ATTLIST ToC
+ %pagenum.attrib;
+ %common.attrib;
+ %toc.role.attrib;
+ %local.toc.attrib;
+>
+<!--end of toc.attlist-->]]>
+<!--end of toc.module-->]]>
+
+<!ENTITY % tocfront.module "INCLUDE">
+<![ %tocfront.module; [
+<!ENTITY % local.tocfront.attrib "">
+<!ENTITY % tocfront.role.attrib "%role.attrib;">
+
+<!ENTITY % tocfront.element "INCLUDE">
+<![ %tocfront.element; [
+<!ELEMENT ToCfront - O ((%para.char.mix;)+)>
+<!--end of tocfront.element-->]]>
+
+<!ENTITY % tocfront.attlist "INCLUDE">
+<![ %tocfront.attlist; [
+<!ATTLIST ToCfront
+ %label.attrib;
+ %linkend.attrib; --to element that this entry represents--
+ %pagenum.attrib;
+ %common.attrib;
+ %tocfront.role.attrib;
+ %local.tocfront.attrib;
+>
+<!--end of tocfront.attlist-->]]>
+<!--end of tocfront.module-->]]>
+
+<!ENTITY % tocentry.module "INCLUDE">
+<![ %tocentry.module; [
+<!ENTITY % local.tocentry.attrib "">
+<!ENTITY % tocentry.role.attrib "%role.attrib;">
+
+<!ENTITY % tocentry.element "INCLUDE">
+<![ %tocentry.element; [
+<!ELEMENT ToCentry - - ((%para.char.mix;)+)>
+<!--end of tocentry.element-->]]>
+
+<!ENTITY % tocentry.attlist "INCLUDE">
+<![ %tocentry.attlist; [
+<!ATTLIST ToCentry
+ %linkend.attrib; --to element that this entry represents--
+ %pagenum.attrib;
+ %common.attrib;
+ %tocentry.role.attrib;
+ %local.tocentry.attrib;
+>
+<!--end of tocentry.attlist-->]]>
+<!--end of tocentry.module-->]]>
+
+<!ENTITY % tocpart.module "INCLUDE">
+<![ %tocpart.module; [
+<!ENTITY % local.tocpart.attrib "">
+<!ENTITY % tocpart.role.attrib "%role.attrib;">
+
+<!ENTITY % tocpart.element "INCLUDE">
+<![ %tocpart.element; [
+<!ELEMENT ToCpart - O (ToCentry+, ToCchap*)>
+<!--end of tocpart.element-->]]>
+
+<!ENTITY % tocpart.attlist "INCLUDE">
+<![ %tocpart.attlist; [
+<!ATTLIST ToCpart
+ %common.attrib;
+ %tocpart.role.attrib;
+ %local.tocpart.attrib;
+>
+<!--end of tocpart.attlist-->]]>
+<!--end of tocpart.module-->]]>
+
+<!ENTITY % tocchap.module "INCLUDE">
+<![ %tocchap.module; [
+<!ENTITY % local.tocchap.attrib "">
+<!ENTITY % tocchap.role.attrib "%role.attrib;">
+
+<!ENTITY % tocchap.element "INCLUDE">
+<![ %tocchap.element; [
+<!ELEMENT ToCchap - O (ToCentry+, ToClevel1*)>
+<!--end of tocchap.element-->]]>
+
+<!ENTITY % tocchap.attlist "INCLUDE">
+<![ %tocchap.attlist; [
+<!ATTLIST ToCchap
+ %label.attrib;
+ %common.attrib;
+ %tocchap.role.attrib;
+ %local.tocchap.attrib;
+>
+<!--end of tocchap.attlist-->]]>
+<!--end of tocchap.module-->]]>
+
+<!ENTITY % toclevel1.module "INCLUDE">
+<![ %toclevel1.module; [
+<!ENTITY % local.toclevel1.attrib "">
+<!ENTITY % toclevel1.role.attrib "%role.attrib;">
+
+<!ENTITY % toclevel1.element "INCLUDE">
+<![ %toclevel1.element; [
+<!ELEMENT ToClevel1 - O (ToCentry+, ToClevel2*)>
+<!--end of toclevel1.element-->]]>
+
+<!ENTITY % toclevel1.attlist "INCLUDE">
+<![ %toclevel1.attlist; [
+<!ATTLIST ToClevel1
+ %common.attrib;
+ %toclevel1.role.attrib;
+ %local.toclevel1.attrib;
+>
+<!--end of toclevel1.attlist-->]]>
+<!--end of toclevel1.module-->]]>
+
+<!ENTITY % toclevel2.module "INCLUDE">
+<![ %toclevel2.module; [
+<!ENTITY % local.toclevel2.attrib "">
+<!ENTITY % toclevel2.role.attrib "%role.attrib;">
+
+<!ENTITY % toclevel2.element "INCLUDE">
+<![ %toclevel2.element; [
+<!ELEMENT ToClevel2 - O (ToCentry+, ToClevel3*)>
+<!--end of toclevel2.element-->]]>
+
+<!ENTITY % toclevel2.attlist "INCLUDE">
+<![ %toclevel2.attlist; [
+<!ATTLIST ToClevel2
+ %common.attrib;
+ %toclevel2.role.attrib;
+ %local.toclevel2.attrib;
+>
+<!--end of toclevel2.attlist-->]]>
+<!--end of toclevel2.module-->]]>
+
+<!ENTITY % toclevel3.module "INCLUDE">
+<![ %toclevel3.module; [
+<!ENTITY % local.toclevel3.attrib "">
+<!ENTITY % toclevel3.role.attrib "%role.attrib;">
+
+<!ENTITY % toclevel3.element "INCLUDE">
+<![ %toclevel3.element; [
+<!ELEMENT ToClevel3 - O (ToCentry+, ToClevel4*)>
+<!--end of toclevel3.element-->]]>
+
+<!ENTITY % toclevel3.attlist "INCLUDE">
+<![ %toclevel3.attlist; [
+<!ATTLIST ToClevel3
+ %common.attrib;
+ %toclevel3.role.attrib;
+ %local.toclevel3.attrib;
+>
+<!--end of toclevel3.attlist-->]]>
+<!--end of toclevel3.module-->]]>
+
+<!ENTITY % toclevel4.module "INCLUDE">
+<![ %toclevel4.module; [
+<!ENTITY % local.toclevel4.attrib "">
+<!ENTITY % toclevel4.role.attrib "%role.attrib;">
+
+<!ENTITY % toclevel4.element "INCLUDE">
+<![ %toclevel4.element; [
+<!ELEMENT ToClevel4 - O (ToCentry+, ToClevel5*)>
+<!--end of toclevel4.element-->]]>
+
+<!ENTITY % toclevel4.attlist "INCLUDE">
+<![ %toclevel4.attlist; [
+<!ATTLIST ToClevel4
+ %common.attrib;
+ %toclevel4.role.attrib;
+ %local.toclevel4.attrib;
+>
+<!--end of toclevel4.attlist-->]]>
+<!--end of toclevel4.module-->]]>
+
+<!ENTITY % toclevel5.module "INCLUDE">
+<![ %toclevel5.module; [
+<!ENTITY % local.toclevel5.attrib "">
+<!ENTITY % toclevel5.role.attrib "%role.attrib;">
+
+<!ENTITY % toclevel5.element "INCLUDE">
+<![ %toclevel5.element; [
+<!ELEMENT ToClevel5 - O (ToCentry+)>
+<!--end of toclevel5.element-->]]>
+
+<!ENTITY % toclevel5.attlist "INCLUDE">
+<![ %toclevel5.attlist; [
+<!ATTLIST ToClevel5
+ %common.attrib;
+ %toclevel5.role.attrib;
+ %local.toclevel5.attrib;
+>
+<!--end of toclevel5.attlist-->]]>
+<!--end of toclevel5.module-->]]>
+
+<!ENTITY % tocback.module "INCLUDE">
+<![ %tocback.module; [
+<!ENTITY % local.tocback.attrib "">
+<!ENTITY % tocback.role.attrib "%role.attrib;">
+
+<!ENTITY % tocback.element "INCLUDE">
+<![ %tocback.element; [
+<!ELEMENT ToCback - O ((%para.char.mix;)+)>
+<!--end of tocback.element-->]]>
+
+<!ENTITY % tocback.attlist "INCLUDE">
+<![ %tocback.attlist; [
+<!ATTLIST ToCback
+ %label.attrib;
+ %linkend.attrib; --to element that this entry represents--
+ %pagenum.attrib;
+ %common.attrib;
+ %tocback.role.attrib;
+ %local.tocback.attrib;
+>
+<!--end of tocback.attlist-->]]>
+<!--end of tocback.module-->]]>
+<!--end of toc.content.module-->]]>
+
+<!ENTITY % lot.content.module "INCLUDE">
+<![ %lot.content.module; [
+<!ENTITY % lot.module "INCLUDE">
+<![ %lot.module; [
+<!ENTITY % local.lot.attrib "">
+<!ENTITY % lot.role.attrib "%role.attrib;">
+
+<!ENTITY % lot.element "INCLUDE">
+<![ %lot.element; [
+<!ELEMENT LoT - O ((%bookcomponent.title.content;)?, LoTentry*)>
+<!--end of lot.element-->]]>
+
+<!ENTITY % lot.attlist "INCLUDE">
+<![ %lot.attlist; [
+<!ATTLIST LoT
+ %label.attrib;
+ %common.attrib;
+ %lot.role.attrib;
+ %local.lot.attrib;
+>
+<!--end of lot.attlist-->]]>
+<!--end of lot.module-->]]>
+
+<!ENTITY % lotentry.module "INCLUDE">
+<![ %lotentry.module; [
+<!ENTITY % local.lotentry.attrib "">
+<!ENTITY % lotentry.role.attrib "%role.attrib;">
+
+<!ENTITY % lotentry.element "INCLUDE">
+<![ %lotentry.element; [
+<!ELEMENT LoTentry - - ((%para.char.mix;)+ )>
+<!--end of lotentry.element-->]]>
+
+<!ENTITY % lotentry.attlist "INCLUDE">
+<![ %lotentry.attlist; [
+<!ATTLIST LoTentry
+ --
+ SrcCredit: Information about the source of the entry,
+ as for a list of illustrations
+ --
+ SrcCredit CDATA #IMPLIED
+ %pagenum.attrib;
+ %common.attrib;
+ %linkend.attrib; --to element that this entry represents--
+ %lotentry.role.attrib;
+ %local.lotentry.attrib;
+>
+<!--end of lotentry.attlist-->]]>
+<!--end of lotentry.module-->]]>
+<!--end of lot.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Appendix, Chapter, Part, Preface, Reference, PartIntro ............... -->
+
+<!ENTITY % appendix.module "INCLUDE">
+<![ %appendix.module; [
+<!ENTITY % local.appendix.attrib "">
+<!ENTITY % appendix.role.attrib "%role.attrib;">
+
+<!ENTITY % appendix.element "INCLUDE">
+<![ %appendix.element; [
+<!ELEMENT Appendix - O (AppendixInfo?,
+ (%bookcomponent.title.content;),
+ (%nav.class)*,
+ ToCchap?,
+ (%bookcomponent.content;),
+ (%nav.class)*)
+ %ubiq.inclusion;>
+<!--end of appendix.element-->]]>
+
+<!ENTITY % appendix.attlist "INCLUDE">
+<![ %appendix.attlist; [
+<!ATTLIST Appendix
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %appendix.role.attrib;
+ %local.appendix.attrib;
+>
+<!--end of appendix.attlist-->]]>
+<!--end of appendix.module-->]]>
+
+<!ENTITY % chapter.module "INCLUDE">
+<![ %chapter.module; [
+<!ENTITY % local.chapter.attrib "">
+<!ENTITY % chapter.role.attrib "%role.attrib;">
+
+<!ENTITY % chapter.element "INCLUDE">
+<![ %chapter.element; [
+<!ELEMENT Chapter - O (ChapterInfo?,
+ (%bookcomponent.title.content;),
+ (%nav.class)*,
+ ToCchap?,
+ (%bookcomponent.content;),
+ (%nav.class)*)
+ %ubiq.inclusion;>
+<!--end of chapter.element-->]]>
+
+<!ENTITY % chapter.attlist "INCLUDE">
+<![ %chapter.attlist; [
+<!ATTLIST Chapter
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %chapter.role.attrib;
+ %local.chapter.attrib;
+>
+<!--end of chapter.attlist-->]]>
+<!--end of chapter.module-->]]>
+
+<!ENTITY % part.module "INCLUDE">
+<![ %part.module; [
+
+<!-- Note that Part was to have its content model reduced in V4.1. This
+change will not be made after all. -->
+
+<!ENTITY % local.part.attrib "">
+<!ENTITY % part.role.attrib "%role.attrib;">
+
+<!ENTITY % part.element "INCLUDE">
+<![ %part.element; [
+<!ELEMENT Part - - (PartInfo?, (%bookcomponent.title.content;), PartIntro?,
+ (%partcontent.mix;)+) %ubiq.inclusion;>
+<!--end of part.element-->]]>
+
+<!ENTITY % part.attlist "INCLUDE">
+<![ %part.attlist; [
+<!ATTLIST Part
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %part.role.attrib;
+ %local.part.attrib;
+>
+<!--end of part.attlist-->]]>
+<!--ELEMENT PartIntro (defined below)-->
+<!--end of part.module-->]]>
+
+<!ENTITY % preface.module "INCLUDE">
+<![ %preface.module; [
+<!ENTITY % local.preface.attrib "">
+<!ENTITY % preface.role.attrib "%role.attrib;">
+
+<!ENTITY % preface.element "INCLUDE">
+<![ %preface.element; [
+<!ELEMENT Preface - O (PrefaceInfo?,
+ (%bookcomponent.title.content;),
+ (%nav.class)*,
+ ToCchap?,
+ (%bookcomponent.content;),
+ (%nav.class)*)
+ %ubiq.inclusion;>
+<!--end of preface.element-->]]>
+
+<!ENTITY % preface.attlist "INCLUDE">
+<![ %preface.attlist; [
+<!ATTLIST Preface
+ %status.attrib;
+ %common.attrib;
+ %preface.role.attrib;
+ %local.preface.attrib;
+>
+<!--end of preface.attlist-->]]>
+<!--end of preface.module-->]]>
+
+<!ENTITY % reference.module "INCLUDE">
+<![ %reference.module; [
+<!ENTITY % local.reference.attrib "">
+<!ENTITY % reference.role.attrib "%role.attrib;">
+
+<!ENTITY % reference.element "INCLUDE">
+<![ %reference.element; [
+<!ELEMENT Reference - O (ReferenceInfo?, (%bookcomponent.title.content;),
+ PartIntro?,
+ (%refentry.class;)+) %ubiq.inclusion;>
+<!--end of reference.element-->]]>
+
+<!ENTITY % reference.attlist "INCLUDE">
+<![ %reference.attlist; [
+<!ATTLIST Reference
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %reference.role.attrib;
+ %local.reference.attrib;
+>
+<!--end of reference.attlist-->]]>
+<!--ELEMENT PartIntro (defined below)-->
+<!--end of reference.module-->]]>
+
+<!ENTITY % partintro.module "INCLUDE">
+<![ %partintro.module; [
+<!ENTITY % local.partintro.attrib "">
+<!ENTITY % partintro.role.attrib "%role.attrib;">
+
+<!ENTITY % partintro.element "INCLUDE">
+<![ %partintro.element; [
+<!ELEMENT PartIntro - O ((%div.title.content;)?, (%bookcomponent.content;))
+ %ubiq.inclusion;>
+<!--end of partintro.element-->]]>
+
+<!ENTITY % partintro.attlist "INCLUDE">
+<![ %partintro.attlist; [
+<!ATTLIST PartIntro
+ %label.attrib;
+ %common.attrib;
+ %local.partintro.attrib;
+ %partintro.role.attrib;
+>
+<!--end of partintro.attlist-->]]>
+<!--end of partintro.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Other Info elements .................................................. -->
+
+<!ENTITY % appendixinfo.module "INCLUDE">
+<![ %appendixinfo.module; [
+<!ENTITY % local.appendixinfo.attrib "">
+<!ENTITY % appendixinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % appendixinfo.element "INCLUDE">
+<![ %appendixinfo.element; [
+<!ELEMENT AppendixInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of appendixinfo.element-->]]>
+
+<!ENTITY % appendixinfo.attlist "INCLUDE">
+<![ %appendixinfo.attlist; [
+<!ATTLIST AppendixInfo
+ %common.attrib;
+ %appendixinfo.role.attrib;
+ %local.appendixinfo.attrib;
+>
+<!--end of appendixinfo.attlist-->]]>
+<!--end of appendixinfo.module-->]]>
+
+
+<!ENTITY % bibliographyinfo.module "INCLUDE">
+<![ %bibliographyinfo.module; [
+<!ENTITY % local.bibliographyinfo.attrib "">
+<!ENTITY % bibliographyinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % bibliographyinfo.element "INCLUDE">
+<![ %bibliographyinfo.element; [
+<!ELEMENT BibliographyInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of bibliographyinfo.element-->]]>
+
+<!ENTITY % bibliographyinfo.attlist "INCLUDE">
+<![ %bibliographyinfo.attlist; [
+<!ATTLIST BibliographyInfo
+ %common.attrib;
+ %bibliographyinfo.role.attrib;
+ %local.bibliographyinfo.attrib;
+>
+<!--end of bibliographyinfo.attlist-->]]>
+<!--end of bibliographyinfo.module-->]]>
+
+<!ENTITY % chapterinfo.module "INCLUDE">
+<![ %chapterinfo.module; [
+<!ENTITY % local.chapterinfo.attrib "">
+<!ENTITY % chapterinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % chapterinfo.element "INCLUDE">
+<![ %chapterinfo.element; [
+<!ELEMENT ChapterInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of chapterinfo.element-->]]>
+
+<!ENTITY % chapterinfo.attlist "INCLUDE">
+<![ %chapterinfo.attlist; [
+<!ATTLIST ChapterInfo
+ %common.attrib;
+ %chapterinfo.role.attrib;
+ %local.chapterinfo.attrib;
+>
+<!--end of chapterinfo.attlist-->]]>
+<!--end of chapterinfo.module-->]]>
+
+<!ENTITY % glossaryinfo.module "INCLUDE">
+<![ %glossaryinfo.module; [
+<!ENTITY % local.glossaryinfo.attrib "">
+<!ENTITY % glossaryinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % glossaryinfo.element "INCLUDE">
+<![ %glossaryinfo.element; [
+<!ELEMENT GlossaryInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of glossaryinfo.element-->]]>
+
+<!ENTITY % glossaryinfo.attlist "INCLUDE">
+<![ %glossaryinfo.attlist; [
+<!ATTLIST GlossaryInfo
+ %common.attrib;
+ %glossaryinfo.role.attrib;
+ %local.glossaryinfo.attrib;
+>
+<!--end of glossaryinfo.attlist-->]]>
+<!--end of glossaryinfo.module-->]]>
+
+
+<!ENTITY % indexinfo.module "INCLUDE">
+<![ %indexinfo.module; [
+<!ENTITY % local.indexinfo.attrib "">
+<!ENTITY % indexinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % indexinfo.element "INCLUDE">
+<![ %indexinfo.element; [
+<!ELEMENT IndexInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of indexinfo.element-->]]>
+
+<!ENTITY % indexinfo.attlist "INCLUDE">
+<![ %indexinfo.attlist; [
+<!ATTLIST IndexInfo
+ %common.attrib;
+ %indexinfo.role.attrib;
+ %local.indexinfo.attrib;
+>
+<!--end of indexinfo.attlist-->]]>
+<!--end of indexinfo.module-->]]>
+
+<!ENTITY % partinfo.module "INCLUDE">
+<![ %partinfo.module; [
+<!ENTITY % local.partinfo.attrib "">
+<!ENTITY % partinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % partinfo.element "INCLUDE">
+<![ %partinfo.element; [
+<!ELEMENT PartInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of partinfo.element-->]]>
+
+<!ENTITY % partinfo.attlist "INCLUDE">
+<![ %partinfo.attlist; [
+<!ATTLIST PartInfo
+ %common.attrib;
+ %partinfo.role.attrib;
+ %local.partinfo.attrib;
+>
+<!--end of partinfo.attlist-->]]>
+<!--end of partinfo.module-->]]>
+
+
+<!ENTITY % prefaceinfo.module "INCLUDE">
+<![ %prefaceinfo.module; [
+<!ENTITY % local.prefaceinfo.attrib "">
+<!ENTITY % prefaceinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % prefaceinfo.element "INCLUDE">
+<![ %prefaceinfo.element; [
+<!ELEMENT PrefaceInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of prefaceinfo.element-->]]>
+
+<!ENTITY % prefaceinfo.attlist "INCLUDE">
+<![ %prefaceinfo.attlist; [
+<!ATTLIST PrefaceInfo
+ %common.attrib;
+ %prefaceinfo.role.attrib;
+ %local.prefaceinfo.attrib;
+>
+<!--end of prefaceinfo.attlist-->]]>
+<!--end of prefaceinfo.module-->]]>
+
+
+<!ENTITY % refentryinfo.module "INCLUDE">
+<![ %refentryinfo.module; [
+<!ENTITY % local.refentryinfo.attrib "">
+<!ENTITY % refentryinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % refentryinfo.element "INCLUDE">
+<![ %refentryinfo.element; [
+<!ELEMENT RefEntryInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of refentryinfo.element-->]]>
+
+<!ENTITY % refentryinfo.attlist "INCLUDE">
+<![ %refentryinfo.attlist; [
+<!ATTLIST RefEntryInfo
+ %common.attrib;
+ %refentryinfo.role.attrib;
+ %local.refentryinfo.attrib;
+>
+<!--end of refentryinfo.attlist-->]]>
+<!--end of refentryinfo.module-->]]>
+
+
+<!ENTITY % refsect1info.module "INCLUDE">
+<![ %refsect1info.module; [
+<!ENTITY % local.refsect1info.attrib "">
+<!ENTITY % refsect1info.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect1info.element "INCLUDE">
+<![ %refsect1info.element; [
+<!ELEMENT RefSect1Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of refsect1info.element-->]]>
+
+<!ENTITY % refsect1info.attlist "INCLUDE">
+<![ %refsect1info.attlist; [
+<!ATTLIST RefSect1Info
+ %common.attrib;
+ %refsect1info.role.attrib;
+ %local.refsect1info.attrib;
+>
+<!--end of refsect1info.attlist-->]]>
+<!--end of refsect1info.module-->]]>
+
+
+<!ENTITY % refsect2info.module "INCLUDE">
+<![ %refsect2info.module; [
+<!ENTITY % local.refsect2info.attrib "">
+<!ENTITY % refsect2info.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect2info.element "INCLUDE">
+<![ %refsect2info.element; [
+<!ELEMENT RefSect2Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of refsect2info.element-->]]>
+
+<!ENTITY % refsect2info.attlist "INCLUDE">
+<![ %refsect2info.attlist; [
+<!ATTLIST RefSect2Info
+ %common.attrib;
+ %refsect2info.role.attrib;
+ %local.refsect2info.attrib;
+>
+<!--end of refsect2info.attlist-->]]>
+<!--end of refsect2info.module-->]]>
+
+
+<!ENTITY % refsect3info.module "INCLUDE">
+<![ %refsect3info.module; [
+<!ENTITY % local.refsect3info.attrib "">
+<!ENTITY % refsect3info.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect3info.element "INCLUDE">
+<![ %refsect3info.element; [
+<!ELEMENT RefSect3Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of refsect3info.element-->]]>
+
+<!ENTITY % refsect3info.attlist "INCLUDE">
+<![ %refsect3info.attlist; [
+<!ATTLIST RefSect3Info
+ %common.attrib;
+ %refsect3info.role.attrib;
+ %local.refsect3info.attrib;
+>
+<!--end of refsect3info.attlist-->]]>
+<!--end of refsect3info.module-->]]>
+
+
+<!ENTITY % refsynopsisdivinfo.module "INCLUDE">
+<![ %refsynopsisdivinfo.module; [
+<!ENTITY % local.refsynopsisdivinfo.attrib "">
+<!ENTITY % refsynopsisdivinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % refsynopsisdivinfo.element "INCLUDE">
+<![ %refsynopsisdivinfo.element; [
+<!ELEMENT RefSynopsisDivInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of refsynopsisdivinfo.element-->]]>
+
+<!ENTITY % refsynopsisdivinfo.attlist "INCLUDE">
+<![ %refsynopsisdivinfo.attlist; [
+<!ATTLIST RefSynopsisDivInfo
+ %common.attrib;
+ %refsynopsisdivinfo.role.attrib;
+ %local.refsynopsisdivinfo.attrib;
+>
+<!--end of refsynopsisdivinfo.attlist-->]]>
+<!--end of refsynopsisdivinfo.module-->]]>
+
+
+<!ENTITY % referenceinfo.module "INCLUDE">
+<![ %referenceinfo.module; [
+<!ENTITY % local.referenceinfo.attrib "">
+<!ENTITY % referenceinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % referenceinfo.element "INCLUDE">
+<![ %referenceinfo.element; [
+<!ELEMENT ReferenceInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of referenceinfo.element-->]]>
+
+<!ENTITY % referenceinfo.attlist "INCLUDE">
+<![ %referenceinfo.attlist; [
+<!ATTLIST ReferenceInfo
+ %common.attrib;
+ %referenceinfo.role.attrib;
+ %local.referenceinfo.attrib;
+>
+<!--end of referenceinfo.attlist-->]]>
+<!--end of referenceinfo.module-->]]>
+
+
+<!ENTITY % sect1info.module "INCLUDE">
+<![ %sect1info.module; [
+<!ENTITY % local.sect1info.attrib "">
+<!ENTITY % sect1info.role.attrib "%role.attrib;">
+
+<!ENTITY % sect1info.element "INCLUDE">
+<![ %sect1info.element; [
+<!ELEMENT Sect1Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of sect1info.element-->]]>
+
+<!ENTITY % sect1info.attlist "INCLUDE">
+<![ %sect1info.attlist; [
+<!ATTLIST Sect1Info
+ %common.attrib;
+ %sect1info.role.attrib;
+ %local.sect1info.attrib;
+>
+<!--end of sect1info.attlist-->]]>
+<!--end of sect1info.module-->]]>
+
+
+<!ENTITY % sect2info.module "INCLUDE">
+<![ %sect2info.module; [
+<!ENTITY % local.sect2info.attrib "">
+<!ENTITY % sect2info.role.attrib "%role.attrib;">
+
+<!ENTITY % sect2info.element "INCLUDE">
+<![ %sect2info.element; [
+<!ELEMENT Sect2Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of sect2info.element-->]]>
+
+<!ENTITY % sect2info.attlist "INCLUDE">
+<![ %sect2info.attlist; [
+<!ATTLIST Sect2Info
+ %common.attrib;
+ %sect2info.role.attrib;
+ %local.sect2info.attrib;
+>
+<!--end of sect2info.attlist-->]]>
+<!--end of sect2info.module-->]]>
+
+
+<!ENTITY % sect3info.module "INCLUDE">
+<![ %sect3info.module; [
+<!ENTITY % local.sect3info.attrib "">
+<!ENTITY % sect3info.role.attrib "%role.attrib;">
+
+<!ENTITY % sect3info.element "INCLUDE">
+<![ %sect3info.element; [
+<!ELEMENT Sect3Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of sect3info.element-->]]>
+
+<!ENTITY % sect3info.attlist "INCLUDE">
+<![ %sect3info.attlist; [
+<!ATTLIST Sect3Info
+ %common.attrib;
+ %sect3info.role.attrib;
+ %local.sect3info.attrib;
+>
+<!--end of sect3info.attlist-->]]>
+<!--end of sect3info.module-->]]>
+
+
+<!ENTITY % sect4info.module "INCLUDE">
+<![ %sect4info.module; [
+<!ENTITY % local.sect4info.attrib "">
+<!ENTITY % sect4info.role.attrib "%role.attrib;">
+
+<!ENTITY % sect4info.element "INCLUDE">
+<![ %sect4info.element; [
+<!ELEMENT Sect4Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of sect4info.element-->]]>
+
+<!ENTITY % sect4info.attlist "INCLUDE">
+<![ %sect4info.attlist; [
+<!ATTLIST Sect4Info
+ %common.attrib;
+ %sect4info.role.attrib;
+ %local.sect4info.attrib;
+>
+<!--end of sect4info.attlist-->]]>
+<!--end of sect4info.module-->]]>
+
+
+<!ENTITY % sect5info.module "INCLUDE">
+<![ %sect5info.module; [
+<!ENTITY % local.sect5info.attrib "">
+<!ENTITY % sect5info.role.attrib "%role.attrib;">
+
+<!ENTITY % sect5info.element "INCLUDE">
+<![ %sect5info.element; [
+<!ELEMENT Sect5Info - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of sect5info.element-->]]>
+
+<!ENTITY % sect5info.attlist "INCLUDE">
+<![ %sect5info.attlist; [
+<!ATTLIST Sect5Info
+ %common.attrib;
+ %sect5info.role.attrib;
+ %local.sect5info.attrib;
+>
+<!--end of sect5info.attlist-->]]>
+<!--end of sect5info.module-->]]>
+
+
+<!ENTITY % setindexinfo.module "INCLUDE">
+<![ %setindexinfo.module; [
+<!ENTITY % local.setindexinfo.attrib "">
+<!ENTITY % setindexinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % setindexinfo.element "INCLUDE">
+<![ %setindexinfo.element; [
+<!ELEMENT SetIndexInfo - - ((Graphic | MediaObject
+ | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ %beginpage.exclusion;>
+<!--end of setindexinfo.element-->]]>
+
+<!ENTITY % setindexinfo.attlist "INCLUDE">
+<![ %setindexinfo.attlist; [
+<!ATTLIST SetIndexInfo
+ %common.attrib;
+ %setindexinfo.role.attrib;
+ %local.setindexinfo.attrib;
+>
+<!--end of setindexinfo.attlist-->]]>
+<!--end of setindexinfo.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Section (parallel to Sect*) ......................................... -->
+
+<!ENTITY % section.content.module "INCLUDE">
+<![ %section.content.module; [
+<!ENTITY % section.module "INCLUDE">
+<![ %section.module; [
+<!ENTITY % local.section.attrib "">
+<!ENTITY % section.role.attrib "%role.attrib;">
+
+<!ENTITY % section.element "INCLUDE">
+<![ %section.element; [
+<!ELEMENT Section - - (SectionInfo?,
+ (%sect.title.content;),
+ (%nav.class;)*,
+ (((%divcomponent.mix;)+,
+ ((%refentry.class;)*|Section*))
+ | (%refentry.class;)+|Section+),
+ (%nav.class;)*)
+ %ubiq.inclusion;>
+<!--end of section.element-->]]>
+
+<!ENTITY % section.attlist "INCLUDE">
+<![ %section.attlist; [
+<!ATTLIST Section
+ --
+ What did we decide about RenderAs?
+ Renderas (Sect1
+ |Sect2
+ |Sect3
+ |Sect4
+ |Sect5) #IMPLIED
+ --
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %section.role.attrib;
+ %local.section.attrib;
+>
+<!--end of section.attlist-->]]>
+<!--end of section.module-->]]>
+
+<!ENTITY % sectioninfo.module "INCLUDE">
+<![ %sectioninfo.module; [
+<!ENTITY % sectioninfo.role.attrib "%role.attrib;">
+<!ENTITY % local.sectioninfo.attrib "">
+
+<!ENTITY % sectioninfo.element "INCLUDE">
+<![ %sectioninfo.element; [
+<!ELEMENT SectionInfo - - ((Graphic | MediaObject | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ -(BeginPage)>
+<!--end of sectioninfo.element-->]]>
+
+<!ENTITY % sectioninfo.attlist "INCLUDE">
+<![ %sectioninfo.attlist; [
+<!ATTLIST SectionInfo
+ %common.attrib;
+ %sectioninfo.role.attrib;
+ %local.sectioninfo.attrib;
+>
+<!--end of sectioninfo.attlist-->]]>
+<!--end of sectioninfo.module-->]]>
+<!--end of section.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Sect1, Sect2, Sect3, Sect4, Sect5 .................................... -->
+
+<!ENTITY % sect1.module "INCLUDE">
+<![ %sect1.module; [
+<!ENTITY % local.sect1.attrib "">
+<!ENTITY % sect1.role.attrib "%role.attrib;">
+
+<!ENTITY % sect1.element "INCLUDE">
+<![ %sect1.element; [
+<!ELEMENT Sect1 - O (Sect1Info?, (%sect.title.content;), (%nav.class;)*,
+ (((%divcomponent.mix;)+,
+ ((%refentry.class;)* | Sect2* | SimpleSect*))
+ | (%refentry.class;)+ | Sect2+ | SimpleSect+), (%nav.class;)*)
+ %ubiq.inclusion;>
+<!--end of sect1.element-->]]>
+
+<!ENTITY % sect1.attlist "INCLUDE">
+<![ %sect1.attlist; [
+<!ATTLIST Sect1
+ --
+ Renderas: Indicates the format in which the heading should
+ appear
+ --
+ Renderas (Sect2
+ |Sect3
+ |Sect4
+ |Sect5) #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %sect1.role.attrib;
+ %local.sect1.attrib;
+>
+<!--end of sect1.attlist-->]]>
+<!--end of sect1.module-->]]>
+
+<!ENTITY % sect2.module "INCLUDE">
+<![ %sect2.module; [
+<!ENTITY % local.sect2.attrib "">
+<!ENTITY % sect2.role.attrib "%role.attrib;">
+
+<!ENTITY % sect2.element "INCLUDE">
+<![ %sect2.element; [
+<!ELEMENT Sect2 - O (Sect2Info?, (%sect.title.content;), (%nav.class;)*,
+ (((%divcomponent.mix;)+,
+ ((%refentry.class;)* | Sect3* | SimpleSect*))
+ | (%refentry.class;)+ | Sect3+ | SimpleSect+), (%nav.class;)*)>
+<!--end of sect2.element-->]]>
+
+<!ENTITY % sect2.attlist "INCLUDE">
+<![ %sect2.attlist; [
+<!ATTLIST Sect2
+ --
+ Renderas: Indicates the format in which the heading should
+ appear
+ --
+ Renderas (Sect1
+ |Sect3
+ |Sect4
+ |Sect5) #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %sect2.role.attrib;
+ %local.sect2.attrib;
+>
+<!--end of sect2.attlist-->]]>
+<!--end of sect2.module-->]]>
+
+<!ENTITY % sect3.module "INCLUDE">
+<![ %sect3.module; [
+<!ENTITY % local.sect3.attrib "">
+<!ENTITY % sect3.role.attrib "%role.attrib;">
+
+<!ENTITY % sect3.element "INCLUDE">
+<![ %sect3.element; [
+<!ELEMENT Sect3 - O (Sect3Info?, (%sect.title.content;), (%nav.class;)*,
+ (((%divcomponent.mix;)+,
+ ((%refentry.class;)* | Sect4* | SimpleSect*))
+ | (%refentry.class;)+ | Sect4+ | SimpleSect+), (%nav.class;)*)>
+<!--end of sect3.element-->]]>
+
+<!ENTITY % sect3.attlist "INCLUDE">
+<![ %sect3.attlist; [
+<!ATTLIST Sect3
+ --
+ Renderas: Indicates the format in which the heading should
+ appear
+ --
+ Renderas (Sect1
+ |Sect2
+ |Sect4
+ |Sect5) #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %sect3.role.attrib;
+ %local.sect3.attrib;
+>
+<!--end of sect3.attlist-->]]>
+<!--end of sect3.module-->]]>
+
+<!ENTITY % sect4.module "INCLUDE">
+<![ %sect4.module; [
+<!ENTITY % local.sect4.attrib "">
+<!ENTITY % sect4.role.attrib "%role.attrib;">
+
+<!ENTITY % sect4.element "INCLUDE">
+<![ %sect4.element; [
+<!ELEMENT Sect4 - O (Sect4Info?, (%sect.title.content;), (%nav.class;)*,
+ (((%divcomponent.mix;)+,
+ ((%refentry.class;)* | Sect5* | SimpleSect*))
+ | (%refentry.class;)+ | Sect5+ | SimpleSect+), (%nav.class;)*)>
+<!--end of sect4.element-->]]>
+
+<!ENTITY % sect4.attlist "INCLUDE">
+<![ %sect4.attlist; [
+<!ATTLIST Sect4
+ --
+ Renderas: Indicates the format in which the heading should
+ appear
+ --
+ Renderas (Sect1
+ |Sect2
+ |Sect3
+ |Sect5) #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %sect4.role.attrib;
+ %local.sect4.attrib;
+>
+<!--end of sect4.attlist-->]]>
+<!--end of sect4.module-->]]>
+
+<!ENTITY % sect5.module "INCLUDE">
+<![ %sect5.module; [
+<!ENTITY % local.sect5.attrib "">
+<!ENTITY % sect5.role.attrib "%role.attrib;">
+
+<!ENTITY % sect5.element "INCLUDE">
+<![ %sect5.element; [
+<!ELEMENT Sect5 - O (Sect5Info?, (%sect.title.content;), (%nav.class;)*,
+ (((%divcomponent.mix;)+, ((%refentry.class;)* | SimpleSect*))
+ | (%refentry.class;)+ | SimpleSect+), (%nav.class;)*)>
+<!--end of sect5.element-->]]>
+
+<!ENTITY % sect5.attlist "INCLUDE">
+<![ %sect5.attlist; [
+<!ATTLIST Sect5
+ --
+ Renderas: Indicates the format in which the heading should
+ appear
+ --
+ Renderas (Sect1
+ |Sect2
+ |Sect3
+ |Sect4) #IMPLIED
+ %label.attrib;
+ %status.attrib;
+ %common.attrib;
+ %sect5.role.attrib;
+ %local.sect5.attrib;
+>
+<!--end of sect5.attlist-->]]>
+<!--end of sect5.module-->]]>
+
+<!ENTITY % simplesect.module "INCLUDE">
+<![ %simplesect.module; [
+<!ENTITY % local.simplesect.attrib "">
+<!ENTITY % simplesect.role.attrib "%role.attrib;">
+
+<!ENTITY % simplesect.element "INCLUDE">
+<![ %simplesect.element; [
+<!ELEMENT SimpleSect - O ((%sect.title.content;), (%divcomponent.mix;)+)
+ %ubiq.inclusion;>
+<!--end of simplesect.element-->]]>
+
+<!ENTITY % simplesect.attlist "INCLUDE">
+<![ %simplesect.attlist; [
+<!ATTLIST SimpleSect
+ %common.attrib;
+ %simplesect.role.attrib;
+ %local.simplesect.attrib;
+>
+<!--end of simplesect.attlist-->]]>
+<!--end of simplesect.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Bibliography ......................................................... -->
+
+<!ENTITY % bibliography.content.module "INCLUDE">
+<![ %bibliography.content.module; [
+<!ENTITY % bibliography.module "INCLUDE">
+<![ %bibliography.module; [
+<!ENTITY % local.bibliography.attrib "">
+<!ENTITY % bibliography.role.attrib "%role.attrib;">
+
+<!ENTITY % bibliography.element "INCLUDE">
+<![ %bibliography.element; [
+<!ELEMENT Bibliography - O (BibliographyInfo?,
+ (%bookcomponent.title.content;)?,
+ (%component.mix;)*,
+ (BiblioDiv+ | (BiblioEntry|BiblioMixed)+))>
+<!--end of bibliography.element-->]]>
+
+<!ENTITY % bibliography.attlist "INCLUDE">
+<![ %bibliography.attlist; [
+<!ATTLIST Bibliography
+ %status.attrib;
+ %common.attrib;
+ %bibliography.role.attrib;
+ %local.bibliography.attrib;
+>
+<!--end of bibliography.attlist-->]]>
+<!--end of bibliography.module-->]]>
+
+<!ENTITY % bibliodiv.module "INCLUDE">
+<![ %bibliodiv.module; [
+<!ENTITY % local.bibliodiv.attrib "">
+<!ENTITY % bibliodiv.role.attrib "%role.attrib;">
+
+<!ENTITY % bibliodiv.element "INCLUDE">
+<![ %bibliodiv.element; [
+<!ELEMENT BiblioDiv - O ((%sect.title.content;)?, (%component.mix;)*,
+ (BiblioEntry|BiblioMixed)+)>
+<!--end of bibliodiv.element-->]]>
+
+<!ENTITY % bibliodiv.attlist "INCLUDE">
+<![ %bibliodiv.attlist; [
+<!ATTLIST BiblioDiv
+ %status.attrib;
+ %common.attrib;
+ %bibliodiv.role.attrib;
+ %local.bibliodiv.attrib;
+>
+<!--end of bibliodiv.attlist-->]]>
+<!--end of bibliodiv.module-->]]>
+<!--end of bibliography.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Glossary ............................................................. -->
+
+<!ENTITY % glossary.content.module "INCLUDE">
+<![ %glossary.content.module; [
+<!ENTITY % glossary.module "INCLUDE">
+<![ %glossary.module; [
+<!ENTITY % local.glossary.attrib "">
+<!ENTITY % glossary.role.attrib "%role.attrib;">
+
+<!ENTITY % glossary.element "INCLUDE">
+<![ %glossary.element; [
+<!ELEMENT Glossary - O (GlossaryInfo?,
+ (%bookcomponent.title.content;)?, (%component.mix;)*,
+ (GlossDiv+ | GlossEntry+), Bibliography?)>
+<!--end of glossary.element-->]]>
+
+<!ENTITY % glossary.attlist "INCLUDE">
+<![ %glossary.attlist; [
+<!ATTLIST Glossary
+ %status.attrib;
+ %common.attrib;
+ %glossary.role.attrib;
+ %local.glossary.attrib;
+>
+<!--end of glossary.attlist-->]]>
+<!--end of glossary.module-->]]>
+
+<!ENTITY % glossdiv.module "INCLUDE">
+<![ %glossdiv.module; [
+<!ENTITY % local.glossdiv.attrib "">
+<!ENTITY % glossdiv.role.attrib "%role.attrib;">
+
+<!ENTITY % glossdiv.element "INCLUDE">
+<![ %glossdiv.element; [
+<!ELEMENT GlossDiv - O ((%sect.title.content;), (%component.mix;)*,
+ GlossEntry+)>
+<!--end of glossdiv.element-->]]>
+
+<!ENTITY % glossdiv.attlist "INCLUDE">
+<![ %glossdiv.attlist; [
+<!ATTLIST GlossDiv
+ %status.attrib;
+ %common.attrib;
+ %glossdiv.role.attrib;
+ %local.glossdiv.attrib;
+>
+<!--end of glossdiv.attlist-->]]>
+<!--end of glossdiv.module-->]]>
+<!--end of glossary.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Index and SetIndex ................................................... -->
+
+<!ENTITY % index.content.module "INCLUDE">
+<![ %index.content.module; [
+<!ENTITY % index.module "INCLUDE">
+<![ %index.module; [
+<!ENTITY % local.index.attrib "">
+<!ENTITY % index.role.attrib "%role.attrib;">
+
+<!ENTITY % index.element "INCLUDE">
+<![ %index.element; [
+<!ELEMENT Index - O (IndexInfo?, (%bookcomponent.title.content;)?,
+ (%component.mix;)*, (IndexDiv* | IndexEntry*))
+ %ndxterm.exclusion;>
+<!--end of index.element-->]]>
+
+<!ENTITY % index.attlist "INCLUDE">
+<![ %index.attlist; [
+<!ATTLIST Index
+ %common.attrib;
+ %index.role.attrib;
+ %local.index.attrib;
+>
+<!--end of index.attlist-->]]>
+<!--end of index.module-->]]>
+
+<!ENTITY % setindex.module "INCLUDE">
+<![ %setindex.module; [
+<!ENTITY % local.setindex.attrib "">
+<!ENTITY % setindex.role.attrib "%role.attrib;">
+
+<!ENTITY % setindex.element "INCLUDE">
+<![ %setindex.element; [
+<!ELEMENT SetIndex - O (SetIndexInfo?, (%bookcomponent.title.content;)?,
+ (%component.mix;)*, (IndexDiv* | IndexEntry*))
+ %ndxterm.exclusion;>
+<!--end of setindex.element-->]]>
+
+<!ENTITY % setindex.attlist "INCLUDE">
+<![ %setindex.attlist; [
+<!ATTLIST SetIndex
+ %common.attrib;
+ %setindex.role.attrib;
+ %local.setindex.attrib;
+>
+<!--end of setindex.attlist-->]]>
+<!--end of setindex.module-->]]>
+
+<!ENTITY % indexdiv.module "INCLUDE">
+<![ %indexdiv.module; [
+
+<!-- SegmentedList in this content is useful for marking up permuted
+ indices. -->
+
+<!ENTITY % local.indexdiv.attrib "">
+<!ENTITY % indexdiv.role.attrib "%role.attrib;">
+
+<!ENTITY % indexdiv.element "INCLUDE">
+<![ %indexdiv.element; [
+<!ELEMENT IndexDiv - O ((%sect.title.content;)?, ((%indexdivcomponent.mix;)*,
+ (IndexEntry+ | SegmentedList)))>
+<!--end of indexdiv.element-->]]>
+
+<!ENTITY % indexdiv.attlist "INCLUDE">
+<![ %indexdiv.attlist; [
+<!ATTLIST IndexDiv
+ %common.attrib;
+ %indexdiv.role.attrib;
+ %local.indexdiv.attrib;
+>
+<!--end of indexdiv.attlist-->]]>
+<!--end of indexdiv.module-->]]>
+
+<!ENTITY % indexentry.module "INCLUDE">
+<![ %indexentry.module; [
+<!-- Index entries appear in the index, not the text. -->
+
+<!ENTITY % local.indexentry.attrib "">
+<!ENTITY % indexentry.role.attrib "%role.attrib;">
+
+<!ENTITY % indexentry.element "INCLUDE">
+<![ %indexentry.element; [
+<!ELEMENT IndexEntry - O (PrimaryIE, (SeeIE|SeeAlsoIE)*,
+ (SecondaryIE, (SeeIE|SeeAlsoIE|TertiaryIE)*)*)>
+<!--end of indexentry.element-->]]>
+
+<!ENTITY % indexentry.attlist "INCLUDE">
+<![ %indexentry.attlist; [
+<!ATTLIST IndexEntry
+ %common.attrib;
+ %indexentry.role.attrib;
+ %local.indexentry.attrib;
+>
+<!--end of indexentry.attlist-->]]>
+<!--end of indexentry.module-->]]>
+
+<!ENTITY % primsecterie.module "INCLUDE">
+<![ %primsecterie.module; [
+<!ENTITY % local.primsecterie.attrib "">
+<!ENTITY % primsecterie.role.attrib "%role.attrib;">
+
+<!ENTITY % primsecterie.elements "INCLUDE">
+<![ %primsecterie.elements; [
+<!ELEMENT (PrimaryIE | SecondaryIE | TertiaryIE) - O ((%ndxterm.char.mix;)+)>
+<!--end of primsecterie.elements-->]]>
+
+<!ENTITY % primsecterie.attlists "INCLUDE">
+<![ %primsecterie.attlists; [
+<!ATTLIST (PrimaryIE | SecondaryIE | TertiaryIE)
+ %linkends.attrib; --to IndexTerms that these entries represent--
+ %common.attrib;
+ %primsecterie.role.attrib;
+ %local.primsecterie.attrib;
+>
+<!--end of primsecterie.attlists-->]]>
+<!--end of primsecterie.module-->]]>
+
+<!ENTITY % seeie.module "INCLUDE">
+<![ %seeie.module; [
+<!ENTITY % local.seeie.attrib "">
+<!ENTITY % seeie.role.attrib "%role.attrib;">
+
+<!ENTITY % seeie.element "INCLUDE">
+<![ %seeie.element; [
+<!ELEMENT SeeIE - O ((%ndxterm.char.mix;)+)>
+<!--end of seeie.element-->]]>
+
+<!ENTITY % seeie.attlist "INCLUDE">
+<![ %seeie.attlist; [
+<!ATTLIST SeeIE
+ %linkend.attrib; --to IndexEntry to look up--
+ %common.attrib;
+ %seeie.role.attrib;
+ %local.seeie.attrib;
+>
+<!--end of seeie.attlist-->]]>
+<!--end of seeie.module-->]]>
+
+<!ENTITY % seealsoie.module "INCLUDE">
+<![ %seealsoie.module; [
+<!ENTITY % local.seealsoie.attrib "">
+<!ENTITY % seealsoie.role.attrib "%role.attrib;">
+
+<!ENTITY % seealsoie.element "INCLUDE">
+<![ %seealsoie.element; [
+<!ELEMENT SeeAlsoIE - O ((%ndxterm.char.mix;)+)>
+<!--end of seealsoie.element-->]]>
+
+<!ENTITY % seealsoie.attlist "INCLUDE">
+<![ %seealsoie.attlist; [
+<!ATTLIST SeeAlsoIE
+ %linkends.attrib; --to related IndexEntries--
+ %common.attrib;
+ %seealsoie.role.attrib;
+ %local.seealsoie.attrib;
+>
+<!--end of seealsoie.attlist-->]]>
+<!--end of seealsoie.module-->]]>
+<!--end of index.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- RefEntry ............................................................. -->
+
+<!ENTITY % refentry.content.module "INCLUDE">
+<![ %refentry.content.module; [
+<!ENTITY % refentry.module "INCLUDE">
+<![ %refentry.module; [
+<!ENTITY % local.refentry.attrib "">
+<!ENTITY % refentry.role.attrib "%role.attrib;">
+
+<!ENTITY % refentry.element "INCLUDE">
+<![ %refentry.element; [
+<!ELEMENT RefEntry - O (RefEntryInfo?, RefMeta?, (Remark|%link.char.class;)*,
+ RefNameDiv, RefSynopsisDiv?, RefSect1+) %ubiq.inclusion;>
+<!--end of refentry.element-->]]>
+
+<!ENTITY % refentry.attlist "INCLUDE">
+<![ %refentry.attlist; [
+<!ATTLIST RefEntry
+ %status.attrib;
+ %common.attrib;
+ %refentry.role.attrib;
+ %local.refentry.attrib;
+>
+<!--end of refentry.attlist-->]]>
+<!--end of refentry.module-->]]>
+
+<!ENTITY % refmeta.module "INCLUDE">
+<![ %refmeta.module; [
+<!ENTITY % local.refmeta.attrib "">
+<!ENTITY % refmeta.role.attrib "%role.attrib;">
+
+<!ENTITY % refmeta.element "INCLUDE">
+<![ %refmeta.element; [
+<!ELEMENT RefMeta - - (RefEntryTitle, ManVolNum?, RefMiscInfo*)
+ %beginpage.exclusion;>
+<!--end of refmeta.element-->]]>
+
+<!ENTITY % refmeta.attlist "INCLUDE">
+<![ %refmeta.attlist; [
+<!ATTLIST RefMeta
+ %common.attrib;
+ %refmeta.role.attrib;
+ %local.refmeta.attrib;
+>
+<!--end of refmeta.attlist-->]]>
+<!--end of refmeta.module-->]]>
+
+<!ENTITY % refmiscinfo.module "INCLUDE">
+<![ %refmiscinfo.module; [
+<!ENTITY % local.refmiscinfo.attrib "">
+<!ENTITY % refmiscinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % refmiscinfo.element "INCLUDE">
+<![ %refmiscinfo.element; [
+<!ELEMENT RefMiscInfo - - ((%docinfo.char.mix;)+)>
+<!--end of refmiscinfo.element-->]]>
+
+<!ENTITY % refmiscinfo.attlist "INCLUDE">
+<![ %refmiscinfo.attlist; [
+<!ATTLIST RefMiscInfo
+ --
+ Class: Freely assignable parameter; no default
+ --
+ Class CDATA #IMPLIED
+ %common.attrib;
+ %refmiscinfo.role.attrib;
+ %local.refmiscinfo.attrib;
+>
+<!--end of refmiscinfo.attlist-->]]>
+<!--end of refmiscinfo.module-->]]>
+
+<!ENTITY % refnamediv.module "INCLUDE">
+<![ %refnamediv.module; [
+<!ENTITY % local.refnamediv.attrib "">
+<!ENTITY % refnamediv.role.attrib "%role.attrib;">
+
+<!ENTITY % refnamediv.element "INCLUDE">
+<![ %refnamediv.element; [
+<!ELEMENT RefNameDiv - O (RefDescriptor?, RefName+, RefPurpose, RefClass*,
+ (Remark|%link.char.class;)*)>
+<!--end of refnamediv.element-->]]>
+
+<!ENTITY % refnamediv.attlist "INCLUDE">
+<![ %refnamediv.attlist; [
+<!ATTLIST RefNameDiv
+ %common.attrib;
+ %refnamediv.role.attrib;
+ %local.refnamediv.attrib;
+>
+<!--end of refnamediv.attlist-->]]>
+<!--end of refnamediv.module-->]]>
+
+<!ENTITY % refdescriptor.module "INCLUDE">
+<![ %refdescriptor.module; [
+<!ENTITY % local.refdescriptor.attrib "">
+<!ENTITY % refdescriptor.role.attrib "%role.attrib;">
+
+<!ENTITY % refdescriptor.element "INCLUDE">
+<![ %refdescriptor.element; [
+<!ELEMENT RefDescriptor - O ((%refname.char.mix;)+)>
+<!--end of refdescriptor.element-->]]>
+
+<!ENTITY % refdescriptor.attlist "INCLUDE">
+<![ %refdescriptor.attlist; [
+<!ATTLIST RefDescriptor
+ %common.attrib;
+ %refdescriptor.role.attrib;
+ %local.refdescriptor.attrib;
+>
+<!--end of refdescriptor.attlist-->]]>
+<!--end of refdescriptor.module-->]]>
+
+<!ENTITY % refname.module "INCLUDE">
+<![ %refname.module; [
+<!ENTITY % local.refname.attrib "">
+<!ENTITY % refname.role.attrib "%role.attrib;">
+
+<!ENTITY % refname.element "INCLUDE">
+<![ %refname.element; [
+<!ELEMENT RefName - O ((%refname.char.mix;)+)>
+<!--end of refname.element-->]]>
+
+<!ENTITY % refname.attlist "INCLUDE">
+<![ %refname.attlist; [
+<!ATTLIST RefName
+ %common.attrib;
+ %refname.role.attrib;
+ %local.refname.attrib;
+>
+<!--end of refname.attlist-->]]>
+<!--end of refname.module-->]]>
+
+<!ENTITY % refpurpose.module "INCLUDE">
+<![ %refpurpose.module; [
+<!ENTITY % local.refpurpose.attrib "">
+<!ENTITY % refpurpose.role.attrib "%role.attrib;">
+
+<!ENTITY % refpurpose.element "INCLUDE">
+<![ %refpurpose.element; [
+<!ELEMENT RefPurpose - O ((%refinline.char.mix;)+)>
+<!--end of refpurpose.element-->]]>
+
+<!ENTITY % refpurpose.attlist "INCLUDE">
+<![ %refpurpose.attlist; [
+<!ATTLIST RefPurpose
+ %common.attrib;
+ %refpurpose.role.attrib;
+ %local.refpurpose.attrib;
+>
+<!--end of refpurpose.attlist-->]]>
+<!--end of refpurpose.module-->]]>
+
+<!ENTITY % refclass.module "INCLUDE">
+<![ %refclass.module; [
+<!ENTITY % local.refclass.attrib "">
+<!ENTITY % refclass.role.attrib "%role.attrib;">
+
+<!ENTITY % refclass.element "INCLUDE">
+<![ %refclass.element; [
+<!ELEMENT RefClass - O ((%refclass.char.mix;)+)>
+<!--end of refclass.element-->]]>
+
+<!ENTITY % refclass.attlist "INCLUDE">
+<![ %refclass.attlist; [
+<!ATTLIST RefClass
+ %common.attrib;
+ %refclass.role.attrib;
+ %local.refclass.attrib;
+>
+<!--end of refclass.attlist-->]]>
+<!--end of refclass.module-->]]>
+
+<!ENTITY % refsynopsisdiv.module "INCLUDE">
+<![ %refsynopsisdiv.module; [
+<!ENTITY % local.refsynopsisdiv.attrib "">
+<!ENTITY % refsynopsisdiv.role.attrib "%role.attrib;">
+
+<!ENTITY % refsynopsisdiv.element "INCLUDE">
+<![ %refsynopsisdiv.element; [
+<!ELEMENT RefSynopsisDiv - O (RefSynopsisDivInfo?, (%refsect.title.content;)?,
+ (((%refcomponent.mix;)+, RefSect2*) | (RefSect2+)))>
+<!--end of refsynopsisdiv.element-->]]>
+
+<!ENTITY % refsynopsisdiv.attlist "INCLUDE">
+<![ %refsynopsisdiv.attlist; [
+<!ATTLIST RefSynopsisDiv
+ %common.attrib;
+ %refsynopsisdiv.role.attrib;
+ %local.refsynopsisdiv.attrib;
+>
+<!--end of refsynopsisdiv.attlist-->]]>
+<!--end of refsynopsisdiv.module-->]]>
+
+<!ENTITY % refsect1.module "INCLUDE">
+<![ %refsect1.module; [
+<!ENTITY % local.refsect1.attrib "">
+<!ENTITY % refsect1.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect1.element "INCLUDE">
+<![ %refsect1.element; [
+<!ELEMENT RefSect1 - O (RefSect1Info?, (%refsect.title.content;),
+ (((%refcomponent.mix;)+, RefSect2*) | RefSect2+))>
+<!--end of refsect1.element-->]]>
+
+<!ENTITY % refsect1.attlist "INCLUDE">
+<![ %refsect1.attlist; [
+<!ATTLIST RefSect1
+ %status.attrib;
+ %common.attrib;
+ %refsect1.role.attrib;
+ %local.refsect1.attrib;
+>
+<!--end of refsect1.attlist-->]]>
+<!--end of refsect1.module-->]]>
+
+<!ENTITY % refsect2.module "INCLUDE">
+<![ %refsect2.module; [
+<!ENTITY % local.refsect2.attrib "">
+<!ENTITY % refsect2.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect2.element "INCLUDE">
+<![ %refsect2.element; [
+<!ELEMENT RefSect2 - O (RefSect2Info?, (%refsect.title.content;),
+ (((%refcomponent.mix;)+, RefSect3*) | RefSect3+))>
+<!--end of refsect2.element-->]]>
+
+<!ENTITY % refsect2.attlist "INCLUDE">
+<![ %refsect2.attlist; [
+<!ATTLIST RefSect2
+ %status.attrib;
+ %common.attrib;
+ %refsect2.role.attrib;
+ %local.refsect2.attrib;
+>
+<!--end of refsect2.attlist-->]]>
+<!--end of refsect2.module-->]]>
+
+<!ENTITY % refsect3.module "INCLUDE">
+<![ %refsect3.module; [
+<!ENTITY % local.refsect3.attrib "">
+<!ENTITY % refsect3.role.attrib "%role.attrib;">
+
+<!ENTITY % refsect3.element "INCLUDE">
+<![ %refsect3.element; [
+<!ELEMENT RefSect3 - O (RefSect3Info?, (%refsect.title.content;),
+ (%refcomponent.mix;)+)>
+<!--end of refsect3.element-->]]>
+
+<!ENTITY % refsect3.attlist "INCLUDE">
+<![ %refsect3.attlist; [
+<!ATTLIST RefSect3
+ %status.attrib;
+ %common.attrib;
+ %refsect3.role.attrib;
+ %local.refsect3.attrib;
+>
+<!--end of refsect3.attlist-->]]>
+<!--end of refsect3.module-->]]>
+<!--end of refentry.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Article .............................................................. -->
+
+<!ENTITY % article.module "INCLUDE">
+<![ %article.module; [
+<!-- An Article is a chapter-level, stand-alone document that is often,
+ but need not be, collected into a Book. -->
+
+<!ENTITY % local.article.attrib "">
+<!ENTITY % article.role.attrib "%role.attrib;">
+
+<!ENTITY % article.element "INCLUDE">
+<![ %article.element; [
+<!ELEMENT Article - O ((%div.title.content;)?, ArticleInfo?, ToCchap?, LoT*,
+ (%bookcomponent.content;),
+ ((%nav.class;) | (%appendix.class;) | Ackno)*)
+ %ubiq.inclusion;>
+<!--end of article.element-->]]>
+
+<!ENTITY % article.attlist "INCLUDE">
+<![ %article.attlist; [
+<!ATTLIST Article
+ --
+ Class: Indicates the type of a particular article;
+ all articles have the same structure and general purpose.
+ No default.
+ --
+ Class (JournalArticle
+ |ProductSheet
+ |WhitePaper
+ |TechReport
+ |Specification
+ |FAQ) #IMPLIED
+ --
+ ParentBook: ID of the enclosing Book
+ --
+ ParentBook IDREF #IMPLIED
+ %status.attrib;
+ %common.attrib;
+ %article.role.attrib;
+ %local.article.attrib;
+>
+<!--end of article.attlist-->]]>
+<!--end of article.module-->]]>
+
+<!-- End of DocBook document hierarchy module V4.1 ........................ -->
+<!-- ...................................................................... -->
diff --git a/docs/docbook/dbsgml/dbnotn.mod b/docs/docbook/dbsgml/dbnotn.mod
new file mode 100755
index 00000000000..b980630bbaf
--- /dev/null
+++ b/docs/docbook/dbsgml/dbnotn.mod
@@ -0,0 +1,97 @@
+<!-- ...................................................................... -->
+<!-- DocBook notations module V4.1 ........................................ -->
+<!-- File dbnotn.mod ...................................................... -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ $Id: dbnotn.mod,v 1.3 2001/12/06 07:37:55 jerry Exp $
+
+ Permission to use, copy, modify and distribute the DocBook DTD and
+ its accompanying documentation for any purpose and without fee is
+ hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ If you modify the DocBook DTD in any way, except for declaring and
+ referencing additional sets of general entities and declaring
+ additional notations, label your DTD as a variant of DocBook. See
+ the maintenance documentation for more information.
+
+ Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/docbook/.
+-->
+
+<!-- ...................................................................... -->
+
+<!-- This module contains the entity declarations for the standard
+ notations used by DocBook.
+
+ In DTD driver files referring to this module, please use an entity
+ declaration that uses the public identifier shown below:
+
+ <!ENTITY % dbnotn PUBLIC
+ "-//OASIS//ENTITIES DocBook Notations V4.1//EN">
+ %dbnotn;
+
+ See the documentation for detailed information on the parameter
+ entity and module scheme used in DocBook, customizing DocBook and
+ planning for interchange, and changes made since the last release
+ of DocBook.
+-->
+
+<!ENTITY % local.notation.class "">
+<!ENTITY % notation.class
+ "BMP| CGM-CHAR | CGM-BINARY | CGM-CLEAR | DITROFF | DVI
+ | EPS | EQN | FAX | GIF | GIF87a | GIF89a
+ | JPG | JPEG | IGES | PCX
+ | PIC | PNG | PS | SGML | TBL | TEX | TIFF | WMF | WPG
+ | linespecific
+ %local.notation.class;">
+
+<!NOTATION BMP PUBLIC
+"+//ISBN 0-7923-9432-1::Graphic Notation//NOTATION Microsoft Windows bitmap//EN">
+<!NOTATION CGM-CHAR PUBLIC "ISO 8632/2//NOTATION Character encoding//EN">
+<!NOTATION CGM-BINARY PUBLIC "ISO 8632/3//NOTATION Binary encoding//EN">
+<!NOTATION CGM-CLEAR PUBLIC "ISO 8632/4//NOTATION Clear text encoding//EN">
+<!NOTATION DITROFF SYSTEM "DITROFF">
+<!NOTATION DVI SYSTEM "DVI">
+<!NOTATION EPS PUBLIC
+"+//ISBN 0-201-18127-4::Adobe//NOTATION PostScript Language Ref. Manual//EN">
+<!-- EQN was SYSTEM "-//AT&T//NOTATION EQN-1//EN" -->
+<!NOTATION EQN SYSTEM>
+<!NOTATION FAX PUBLIC
+"-//USA-DOD//NOTATION CCITT Group 4 Facsimile Type 1 Untiled Raster//EN">
+<!NOTATION GIF SYSTEM "GIF">
+<!NOTATION GIF87a PUBLIC
+"-//CompuServe//NOTATION Graphics Interchange Format 87a//EN">
+
+<!NOTATION GIF89a PUBLIC
+"-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">
+<!NOTATION JPG SYSTEM "JPG">
+<!NOTATION JPEG SYSTEM "JPG">
+<!NOTATION IGES PUBLIC
+"-//USA-DOD//NOTATION (ASME/ANSI Y14.26M-1987) Initial Graphics Exchange Specification//EN">
+<!NOTATION PCX PUBLIC
+"+//ISBN 0-7923-9432-1::Graphic Notation//NOTATION ZSoft PCX bitmap//EN">
+<!-- PIC was SYSTEM "-//AT&T//NOTATION EQN-1//EN" -->
+<!NOTATION PIC SYSTEM>
+<!NOTATION PNG SYSTEM "http://www.w3.org/TR/REC-png">
+<!NOTATION PS SYSTEM "PS">
+<!NOTATION SGML PUBLIC
+"ISO 8879:1986//NOTATION Standard Generalized Markup Language//EN">
+<!-- TBL was SYSTEM "-//AT&T//NOTATION EQN-1//EN" -->
+<!NOTATION TBL SYSTEM>
+<!NOTATION TEX PUBLIC
+"+//ISBN 0-201-13448-9::Knuth//NOTATION The TeXbook//EN">
+<!NOTATION TIFF SYSTEM "TIFF">
+<!NOTATION WMF PUBLIC
+"+//ISBN 0-7923-9432-1::Graphic Notation//NOTATION Microsoft Windows Metafile//EN">
+<!NOTATION WPG SYSTEM "WPG" --WordPerfect Graphic format-->
+<!NOTATION linespecific SYSTEM
+"line ends and leading white space must be preserved in output">
diff --git a/docs/docbook/dbsgml/dbpool.mod b/docs/docbook/dbsgml/dbpool.mod
new file mode 100755
index 00000000000..3867d070e80
--- /dev/null
+++ b/docs/docbook/dbsgml/dbpool.mod
@@ -0,0 +1,7396 @@
+<!-- ...................................................................... -->
+<!-- DocBook information pool module V4.1 ................................. -->
+<!-- File dbpool.mod ...................................................... -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ $Id: dbpool.mod,v 1.3 2001/12/06 07:37:55 jerry Exp $
+
+ Permission to use, copy, modify and distribute the DocBook DTD and
+ its accompanying documentation for any purpose and without fee is
+ hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ If you modify the DocBook DTD in any way, except for declaring and
+ referencing additional sets of general entities and declaring
+ additional notations, label your DTD as a variant of DocBook. See
+ the maintenance documentation for more information.
+
+ Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/docbook/.
+-->
+
+<!-- ...................................................................... -->
+
+<!-- This module contains the definitions for the objects, inline
+ elements, and so on that are available to be used as the main
+ content of DocBook documents. Some elements are useful for general
+ publishing, and others are useful specifically for computer
+ documentation.
+
+ This module has the following dependencies on other modules:
+
+ o It assumes that a %notation.class; entity is defined by the
+ driver file or other high-level module. This entity is
+ referenced in the NOTATION attributes for the graphic-related and
+ ModeSpec elements.
+
+ o It assumes that an appropriately parameterized table module is
+ available for use with the table-related elements.
+
+ In DTD driver files referring to this module, please use an entity
+ declaration that uses the public identifier shown below:
+
+ <!ENTITY % dbpool PUBLIC
+ "-//OASIS//ELEMENTS DocBook Information Pool V4.1//EN">
+ %dbpool;
+
+ See the documentation for detailed information on the parameter
+ entity and module scheme used in DocBook, customizing DocBook and
+ planning for interchange, and changes made since the last release
+ of DocBook.
+-->
+
+<!-- ...................................................................... -->
+<!-- General-purpose semantics entities ................................... -->
+
+<!ENTITY % yesorno.attvals "NUMBER">
+
+<![IGNORE[
+<!ENTITY % yes.attval "1"> <!-- never actually used -->
+]]>
+
+<!ENTITY % no.attval "0">
+
+<!-- ...................................................................... -->
+<!-- Entities for module inclusions ....................................... -->
+
+<!ENTITY % dbpool.redecl.module "IGNORE">
+
+<!-- ...................................................................... -->
+<!-- Entities for element classes and mixtures ............................ -->
+
+<!-- Object-level classes ................................................. -->
+
+<!ENTITY % local.list.class "">
+<!ENTITY % list.class
+ "CalloutList|GlossList|ItemizedList|OrderedList|SegmentedList
+ |SimpleList|VariableList %local.list.class;">
+
+<!ENTITY % local.admon.class "">
+<!ENTITY % admon.class
+ "Caution|Important|Note|Tip|Warning %local.admon.class;">
+
+<!ENTITY % local.linespecific.class "">
+<!ENTITY % linespecific.class
+ "LiteralLayout|ProgramListing|ProgramListingCO|Screen
+ |ScreenCO|ScreenShot %local.linespecific.class;">
+
+<!ENTITY % local.method.synop.class "">
+<!ENTITY % method.synop.class
+ "ConstructorSynopsis
+ |DestructorSynopsis
+ |MethodSynopsis %local.method.synop.class;">
+
+<!ENTITY % local.synop.class "">
+<!ENTITY % synop.class
+ "Synopsis|CmdSynopsis|FuncSynopsis
+ |ClassSynopsis|FieldSynopsis
+ |%method.synop.class; %local.synop.class;">
+
+<!ENTITY % local.para.class "">
+<!ENTITY % para.class
+ "FormalPara|Para|SimPara %local.para.class;">
+
+<!ENTITY % local.informal.class "">
+<!ENTITY % informal.class
+ "Address|BlockQuote
+ |Graphic|GraphicCO|MediaObject|MediaObjectCO
+ |InformalEquation
+ |InformalExample
+ |InformalFigure
+ |InformalTable %local.informal.class;">
+
+<!ENTITY % local.formal.class "">
+<!ENTITY % formal.class
+ "Equation|Example|Figure|Table %local.formal.class;">
+
+<!-- The DocBook TC may produce an official EBNF module for DocBook. -->
+<!-- This PE provides the hook by which it can be inserted into the DTD. -->
+<!ENTITY % ebnf.block.hook "">
+
+<!ENTITY % local.compound.class "">
+<!ENTITY % compound.class
+ "MsgSet|Procedure|Sidebar|QandASet
+ %ebnf.block.hook;
+ %local.compound.class;">
+
+<!ENTITY % local.genobj.class "">
+<!ENTITY % genobj.class
+ "Anchor|BridgeHead|Remark|Highlights
+ %local.genobj.class;">
+
+<!ENTITY % local.descobj.class "">
+<!ENTITY % descobj.class
+ "Abstract|AuthorBlurb|Epigraph
+ %local.descobj.class;">
+
+<!-- Character-level classes .............................................. -->
+
+<!ENTITY % local.ndxterm.class "">
+<!ENTITY % ndxterm.class
+ "IndexTerm %local.ndxterm.class;">
+
+<!ENTITY % local.xref.char.class "">
+<!ENTITY % xref.char.class
+ "FootnoteRef|XRef %local.xref.char.class;">
+
+<!ENTITY % local.gen.char.class "">
+<!ENTITY % gen.char.class
+ "Abbrev|Acronym|Citation|CiteRefEntry|CiteTitle|Emphasis
+ |FirstTerm|ForeignPhrase|GlossTerm|Footnote|Phrase
+ |Quote|Trademark|WordAsWord %local.gen.char.class;">
+
+<!ENTITY % local.link.char.class "">
+<!ENTITY % link.char.class
+ "Link|OLink|ULink %local.link.char.class;">
+
+<!-- The DocBook TC may produce an official EBNF module for DocBook. -->
+<!-- This PE provides the hook by which it can be inserted into the DTD. -->
+<!ENTITY % ebnf.inline.hook "">
+
+<!ENTITY % local.tech.char.class "">
+<!ENTITY % tech.char.class
+ "Action|Application
+ |ClassName|MethodName|InterfaceName|ExceptionName
+ |OOClass|OOInterface|OOException
+ |Command|ComputerOutput
+ |Database|Email|EnVar|ErrorCode|ErrorName|ErrorType|Filename
+ |Function|GUIButton|GUIIcon|GUILabel|GUIMenu|GUIMenuItem
+ |GUISubmenu|Hardware|Interface|KeyCap
+ |KeyCode|KeyCombo|KeySym|Literal|Constant|Markup|MediaLabel
+ |MenuChoice|MouseButton|Option|Optional|Parameter
+ |Prompt|Property|Replaceable|ReturnValue|SGMLTag|StructField
+ |StructName|Symbol|SystemItem|Token|Type|UserInput|VarName
+ %ebnf.inline.hook;
+ %local.tech.char.class;">
+
+<!ENTITY % local.base.char.class "">
+<!ENTITY % base.char.class
+ "Anchor %local.base.char.class;">
+
+<!ENTITY % local.docinfo.char.class "">
+<!ENTITY % docinfo.char.class
+ "Author|AuthorInitials|CorpAuthor|ModeSpec|OtherCredit
+ |ProductName|ProductNumber|RevHistory
+ %local.docinfo.char.class;">
+
+<!ENTITY % local.other.char.class "">
+<!ENTITY % other.char.class
+ "Remark|Subscript|Superscript %local.other.char.class;">
+
+<!ENTITY % local.inlineobj.char.class "">
+<!ENTITY % inlineobj.char.class
+ "InlineGraphic|InlineMediaObject|InlineEquation %local.inlineobj.char.class;">
+
+<!-- Redeclaration placeholder ............................................ -->
+
+<!-- For redeclaring entities that are declared after this point while
+ retaining their references to the entities that are declared before
+ this point -->
+
+<![ %dbpool.redecl.module; [
+%rdbpool;
+<!--end of dbpool.redecl.module-->]]>
+
+<!-- Object-level mixtures ................................................ -->
+
+<!--
+ list admn line synp para infm form cmpd gen desc
+Component mixture X X X X X X X X X X
+Sidebar mixture X X X X X X X a X
+Footnote mixture X X X X X
+Example mixture X X X X X
+Highlights mixture X X X
+Paragraph mixture X X X X
+Admonition mixture X X X X X X b c
+Figure mixture X X X
+Table entry mixture X X X X d
+Glossary def mixture X X X X X e
+Legal notice mixture X X X X f
+
+a. Just Procedure; not Sidebar itself or MsgSet.
+b. No MsgSet.
+c. No Highlights.
+d. Just Graphic; no other informal objects.
+e. No Anchor, BridgeHead, or Highlights.
+f. Just BlockQuote; no other informal objects.
+-->
+
+<!ENTITY % local.component.mix "">
+<!ENTITY % component.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |%compound.class;
+ |%genobj.class; |%descobj.class;
+ |%ndxterm.class;
+ %local.component.mix;">
+
+<!ENTITY % local.sidebar.mix "">
+<!ENTITY % sidebar.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |Procedure
+ |%genobj.class;
+ |%ndxterm.class;
+ %local.sidebar.mix;">
+
+<!ENTITY % local.qandaset.mix "">
+<!ENTITY % qandaset.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |Procedure
+ |%genobj.class;
+ |%ndxterm.class;
+ %local.qandaset.mix;">
+
+<!ENTITY % local.revdescription.mix "">
+<!ENTITY % revdescription.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |Procedure
+ |%genobj.class;
+ |%ndxterm.class;
+ %local.revdescription.mix;">
+
+<!ENTITY % local.footnote.mix "">
+<!ENTITY % footnote.mix
+ "%list.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ %local.footnote.mix;">
+
+<!ENTITY % local.example.mix "">
+<!ENTITY % example.mix
+ "%list.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%ndxterm.class;
+ %local.example.mix;">
+
+<!ENTITY % local.highlights.mix "">
+<!ENTITY % highlights.mix
+ "%list.class; |%admon.class;
+ |%para.class;
+ |%ndxterm.class;
+ %local.highlights.mix;">
+
+<!-- %formal.class; is explicitly excluded from many contexts in which
+ paragraphs are used -->
+
+<!ENTITY % local.para.mix "">
+<!ENTITY % para.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class;
+ |%informal.class;
+ |%formal.class;
+ %local.para.mix;">
+
+<!ENTITY % local.admon.mix "">
+<!ENTITY % admon.mix
+ "%list.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class; |Procedure|Sidebar
+ |Anchor|BridgeHead|Remark
+ |%ndxterm.class;
+ %local.admon.mix;">
+
+<!ENTITY % local.figure.mix "">
+<!ENTITY % figure.mix
+ "%linespecific.class; |%synop.class;
+ |%informal.class;
+ |%ndxterm.class;
+ %local.figure.mix;">
+
+<!ENTITY % local.tabentry.mix "">
+<!ENTITY % tabentry.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class;
+ |%para.class; |Graphic|MediaObject
+ %local.tabentry.mix;">
+
+<!ENTITY % local.glossdef.mix "">
+<!ENTITY % glossdef.mix
+ "%list.class;
+ |%linespecific.class; |%synop.class;
+ |%para.class; |%informal.class;
+ |%formal.class;
+ |Remark
+ |%ndxterm.class;
+ %local.glossdef.mix;">
+
+<!ENTITY % local.legalnotice.mix "">
+<!ENTITY % legalnotice.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class;
+ |%para.class; |BlockQuote
+ |%ndxterm.class;
+ %local.legalnotice.mix;">
+
+<!ENTITY % local.textobject.mix "">
+<!ENTITY % textobject.mix
+ "%list.class; |%admon.class;
+ |%linespecific.class;
+ |%para.class; |BlockQuote
+ %local.textobject.mix;">
+
+<!ENTITY % local.mediaobject.mix "">
+<!ENTITY % mediaobject.mix
+ "VideoObject|AudioObject|ImageObject %local.mediaobject.mix">
+
+<!-- Character-level mixtures ............................................. -->
+
+<!ENTITY % local.ubiq.mix "">
+<!ENTITY % ubiq.mix
+ "%ndxterm.class;|BeginPage %local.ubiq.mix;">
+
+<!ENTITY % ubiq.exclusion "-(%ubiq.mix)">
+<!ENTITY % ubiq.inclusion "+(%ubiq.mix)">
+
+<!ENTITY % footnote.exclusion "-(Footnote|%formal.class;)">
+<!ENTITY % highlights.exclusion "-(%ubiq.mix;|%formal.class;)">
+<!ENTITY % admon.exclusion "-(%admon.class;)">
+<!ENTITY % formal.exclusion "-(%formal.class;)">
+<!ENTITY % acronym.exclusion "-(Acronym)">
+<!ENTITY % beginpage.exclusion "-(BeginPage)">
+<!ENTITY % ndxterm.exclusion "-(%ndxterm.class;)">
+<!ENTITY % blockquote.exclusion "-(Epigraph)">
+<!ENTITY % remark.exclusion "-(Remark|%ubiq.mix;)">
+<!ENTITY % glossterm.exclusion "-(GlossTerm)">
+<!ENTITY % links.exclusion "-(Link|OLink|ULink|XRef)">
+
+<!--
+ #PCD xref word link cptr base dnfo othr inob (synop)
+para.char.mix X X X X X X X X X
+title.char.mix X X X X X X X X X
+ndxterm.char.mix X X X X X X X X a
+cptr.char.mix X X X X X a
+smallcptr.char.mix X b a
+word.char.mix X c X X X a
+docinfo.char.mix X d X b X a
+
+a. Just InlineGraphic; no InlineEquation.
+b. Just Replaceable; no other computer terms.
+c. Just Emphasis and Trademark; no other word elements.
+d. Just Acronym, Emphasis, and Trademark; no other word elements.
+-->
+
+<!-- The DocBook TC may produce an official forms module for DocBook. -->
+<!-- This PE provides the hook by which it can be inserted into the DTD. -->
+<!ENTITY % forminlines.hook "">
+
+<!ENTITY % local.para.char.mix "">
+<!ENTITY % para.char.mix
+ "#PCDATA
+ |%xref.char.class; |%gen.char.class;
+ |%link.char.class; |%tech.char.class;
+ |%base.char.class; |%docinfo.char.class;
+ |%other.char.class; |%inlineobj.char.class;
+ |%synop.class;
+ |%ndxterm.class;
+ %forminlines.hook;
+ %local.para.char.mix;">
+
+<!ENTITY % local.title.char.mix "">
+<!ENTITY % title.char.mix
+ "#PCDATA
+ |%xref.char.class; |%gen.char.class;
+ |%link.char.class; |%tech.char.class;
+ |%base.char.class; |%docinfo.char.class;
+ |%other.char.class; |%inlineobj.char.class;
+ |%ndxterm.class;
+ %local.title.char.mix;">
+
+<!ENTITY % local.ndxterm.char.mix "">
+<!ENTITY % ndxterm.char.mix
+ "#PCDATA
+ |%xref.char.class; |%gen.char.class;
+ |%link.char.class; |%tech.char.class;
+ |%base.char.class; |%docinfo.char.class;
+ |%other.char.class; |InlineGraphic|InlineMediaObject
+ %local.ndxterm.char.mix;">
+
+<!ENTITY % local.cptr.char.mix "">
+<!ENTITY % cptr.char.mix
+ "#PCDATA
+ |%link.char.class; |%tech.char.class;
+ |%base.char.class;
+ |%other.char.class; |InlineGraphic|InlineMediaObject
+ |%ndxterm.class;
+ %local.cptr.char.mix;">
+
+<!ENTITY % local.smallcptr.char.mix "">
+<!ENTITY % smallcptr.char.mix
+ "#PCDATA
+ |Replaceable
+ |InlineGraphic|InlineMediaObject
+ |%ndxterm.class;
+ %local.smallcptr.char.mix;">
+
+<!ENTITY % local.word.char.mix "">
+<!ENTITY % word.char.mix
+ "#PCDATA
+ |Acronym|Emphasis|Trademark
+ |%link.char.class;
+ |%base.char.class;
+ |%other.char.class; |InlineGraphic|InlineMediaObject
+ |%ndxterm.class;
+ %local.word.char.mix;">
+
+<!ENTITY % local.docinfo.char.mix "">
+<!ENTITY % docinfo.char.mix
+ "#PCDATA
+ |%link.char.class;
+ |Emphasis|Trademark
+ |Replaceable
+ |%other.char.class; |InlineGraphic|InlineMediaObject
+ |%ndxterm.class;
+ %local.docinfo.char.mix;">
+<!--ENTITY % bibliocomponent.mix (see Bibliographic section, below)-->
+<!--ENTITY % person.ident.mix (see Bibliographic section, below)-->
+
+<!-- ...................................................................... -->
+<!-- Entities for content models .......................................... -->
+
+<!ENTITY % formalobject.title.content "Title, TitleAbbrev?">
+
+<!-- ...................................................................... -->
+<!-- Entities for attributes and attribute components ..................... -->
+
+<!-- Effectivity attributes ............................................... -->
+
+<!ENTITY % arch.attrib
+ --Arch: Computer or chip architecture to which element applies; no
+ default--
+ "Arch CDATA #IMPLIED">
+
+<!ENTITY % condition.attrib
+ --Condition: General-purpose effectivity attribute--
+ "Condition CDATA #IMPLIED">
+
+<!ENTITY % conformance.attrib
+ --Conformance: Standards conformance characteristics--
+ "Conformance NMTOKENS #IMPLIED">
+
+<!ENTITY % os.attrib
+ --OS: Operating system to which element applies; no default--
+ "OS CDATA #IMPLIED">
+
+<!ENTITY % revision.attrib
+ --Revision: Editorial revision to which element belongs; no default--
+ "Revision CDATA #IMPLIED">
+
+<!ENTITY % security.attrib
+ --Security: Security classification; no default--
+ "Security CDATA #IMPLIED">
+
+<!ENTITY % userlevel.attrib
+ --UserLevel: Level of user experience to which element applies; no
+ default--
+ "UserLevel CDATA #IMPLIED">
+
+<!ENTITY % vendor.attrib
+ --Vendor: Computer vendor to which element applies; no default--
+ "Vendor CDATA #IMPLIED">
+
+<!ENTITY % local.effectivity.attrib "">
+<!ENTITY % effectivity.attrib
+ "%arch.attrib;
+ %condition.attrib;
+ %conformance.attrib;
+ %os.attrib;
+ %revision.attrib;
+ %security.attrib;
+ %userlevel.attrib;
+ %vendor.attrib;
+ %local.effectivity.attrib;"
+>
+
+<!-- Common attributes .................................................... -->
+
+<!ENTITY % id.attrib
+ --Id: Unique identifier of element; no default--
+ "Id ID #IMPLIED">
+
+<!ENTITY % idreq.attrib
+ --Id: Unique identifier of element; a value must be supplied; no
+ default--
+ "Id ID #REQUIRED">
+
+<!ENTITY % lang.attrib
+ --Lang: Indicator of language in which element is written, for
+ translation, character set management, etc.; no default--
+ "Lang CDATA #IMPLIED">
+
+<!ENTITY % remap.attrib
+ --Remap: Previous role of element before conversion; no default--
+ "Remap CDATA #IMPLIED">
+
+<!ENTITY % role.attrib
+ --Role: New role of element in local environment; no default--
+ "Role CDATA #IMPLIED">
+
+<!ENTITY % xreflabel.attrib
+ --XRefLabel: Alternate labeling string for XRef text generation;
+ default is usually title or other appropriate label text already
+ contained in element--
+ "XRefLabel CDATA #IMPLIED">
+
+<!ENTITY % revisionflag.attrib
+ --RevisionFlag: Revision status of element; default is that element
+ wasn't revised--
+ "RevisionFlag (Changed
+ |Added
+ |Deleted
+ |Off) #IMPLIED">
+
+<!ENTITY % local.common.attrib "">
+<!ENTITY % common.attrib
+ "%id.attrib;
+ %lang.attrib;
+ %remap.attrib;
+ --Role is included explicitly on each element--
+ %xreflabel.attrib;
+ %revisionflag.attrib;
+ %effectivity.attrib;
+ %local.common.attrib;"
+>
+
+<!ENTITY % idreq.common.attrib
+ "%idreq.attrib;
+ %lang.attrib;
+ %remap.attrib;
+ --Role is included explicitly on each element--
+ %xreflabel.attrib;
+ %revisionflag.attrib;
+ %effectivity.attrib;
+ %local.common.attrib;"
+>
+
+<!-- Semi-common attributes and other attribute entities .................. -->
+
+<!ENTITY % local.graphics.attrib "">
+<!ENTITY % graphics.attrib
+ "
+ --EntityRef: Name of an external entity containing the content
+ of the graphic--
+ EntityRef ENTITY #IMPLIED
+
+ --FileRef: Filename, qualified by a pathname if desired,
+ designating the file containing the content of the graphic--
+ FileRef CDATA #IMPLIED
+
+ --Format: Notation of the element content, if any--
+ Format (%notation.class;)
+ #IMPLIED
+
+ --SrcCredit: Information about the source of the Graphic--
+ SrcCredit CDATA #IMPLIED
+
+ --Width: Same as CALS reprowid (desired width)--
+ Width NUTOKEN #IMPLIED
+
+ --Depth: Same as CALS reprodep (desired depth)--
+ Depth NUTOKEN #IMPLIED
+
+ --Align: Same as CALS hplace with 'none' removed; #IMPLIED means
+ application-specific--
+ Align (Left
+ |Right
+ |Center) #IMPLIED
+
+ --Scale: Conflation of CALS hscale and vscale--
+ Scale NUMBER #IMPLIED
+
+ --Scalefit: Same as CALS scalefit--
+ Scalefit %yesorno.attvals;
+ #IMPLIED
+ %local.graphics.attrib;"
+>
+
+<!ENTITY % local.keyaction.attrib "">
+<!ENTITY % keyaction.attrib
+ "
+ --Action: Key combination type; default is unspecified if one
+ child element, Simul if there is more than one; if value is
+ Other, the OtherAction attribute must have a nonempty value--
+ Action (Click
+ |Double-Click
+ |Press
+ |Seq
+ |Simul
+ |Other) #IMPLIED
+
+ --OtherAction: User-defined key combination type--
+ OtherAction CDATA #IMPLIED
+ %local.keyaction.attrib;"
+>
+
+<!ENTITY % label.attrib
+ --Label: Identifying number or string; default is usually the
+ appropriate number or string autogenerated by a formatter--
+ "Label CDATA #IMPLIED">
+
+<!ENTITY % linespecific.attrib
+ --Format: whether element is assumed to contain significant white
+ space--
+ "Format NOTATION
+ (linespecific) linespecific
+ LineNumbering (Numbered|Unnumbered) #IMPLIED">
+
+<!ENTITY % linkend.attrib
+ --Linkend: link to related information; no default--
+ "Linkend IDREF #IMPLIED">
+
+<!ENTITY % linkendreq.attrib
+ --Linkend: required link to related information--
+ "Linkend IDREF #REQUIRED">
+
+<!ENTITY % linkends.attrib
+ --Linkends: link to one or more sets of related information; no
+ default--
+ "Linkends IDREFS #IMPLIED">
+
+<![IGNORE[
+<!-- Declared for completeness, but never used -->
+<!ENTITY % linkendsreq.attrib
+ --Linkends: required link to one or more sets of related information--
+ "Linkends IDREFS #REQUIRED">
+]]>
+
+<!ENTITY % local.mark.attrib "">
+<!ENTITY % mark.attrib
+ "Mark CDATA #IMPLIED
+ %local.mark.attrib;"
+>
+
+<!ENTITY % moreinfo.attrib
+ --MoreInfo: whether element's content has an associated RefEntry--
+ "MoreInfo (RefEntry|None) None">
+
+<!ENTITY % pagenum.attrib
+ --Pagenum: number of page on which element appears; no default--
+ "Pagenum CDATA #IMPLIED">
+
+<!ENTITY % local.status.attrib "">
+<!ENTITY % status.attrib
+ --Status: Editorial or publication status of the element
+ it applies to, such as "in review" or "approved for distribution"--
+ "Status CDATA #IMPLIED
+ %local.status.attrib;"
+>
+
+<!ENTITY % width.attrib
+ --Width: width of the longest line in the element to which it
+ pertains, in number of characters--
+ "Width NUMBER #IMPLIED">
+
+<!-- ...................................................................... -->
+<!-- Title elements ....................................................... -->
+
+<!ENTITY % title.module "INCLUDE">
+<![ %title.module; [
+<!ENTITY % local.title.attrib "">
+<!ENTITY % title.role.attrib "%role.attrib;">
+
+<!ENTITY % title.element "INCLUDE">
+<![ %title.element; [
+<!ELEMENT Title - O ((%title.char.mix;)+)>
+<!--end of title.element-->]]>
+
+<!ENTITY % title.attlist "INCLUDE">
+<![ %title.attlist; [
+<!ATTLIST Title
+ %pagenum.attrib;
+ %common.attrib;
+ %title.role.attrib;
+ %local.title.attrib;
+>
+<!--end of title.attlist-->]]>
+<!--end of title.module-->]]>
+
+<!ENTITY % titleabbrev.module "INCLUDE">
+<![ %titleabbrev.module; [
+<!ENTITY % local.titleabbrev.attrib "">
+<!ENTITY % titleabbrev.role.attrib "%role.attrib;">
+
+<!ENTITY % titleabbrev.element "INCLUDE">
+<![ %titleabbrev.element; [
+<!ELEMENT TitleAbbrev - O ((%title.char.mix;)+)>
+<!--end of titleabbrev.element-->]]>
+
+<!ENTITY % titleabbrev.attlist "INCLUDE">
+<![ %titleabbrev.attlist; [
+<!ATTLIST TitleAbbrev
+ %common.attrib;
+ %titleabbrev.role.attrib;
+ %local.titleabbrev.attrib;
+>
+<!--end of titleabbrev.attlist-->]]>
+<!--end of titleabbrev.module-->]]>
+
+<!ENTITY % subtitle.module "INCLUDE">
+<![ %subtitle.module; [
+<!ENTITY % local.subtitle.attrib "">
+<!ENTITY % subtitle.role.attrib "%role.attrib;">
+
+<!ENTITY % subtitle.element "INCLUDE">
+<![ %subtitle.element; [
+<!ELEMENT Subtitle - O ((%title.char.mix;)+)>
+<!--end of subtitle.element-->]]>
+
+<!ENTITY % subtitle.attlist "INCLUDE">
+<![ %subtitle.attlist; [
+<!ATTLIST Subtitle
+ %common.attrib;
+ %subtitle.role.attrib;
+ %local.subtitle.attrib;
+>
+<!--end of subtitle.attlist-->]]>
+<!--end of subtitle.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Bibliographic entities and elements .................................. -->
+
+<!-- The bibliographic elements are typically used in the document
+ hierarchy. They do not appear in content models of information
+ pool elements. See also the document information elements,
+ below. -->
+
+<!ENTITY % local.person.ident.mix "">
+<!ENTITY % person.ident.mix
+ "Honorific|FirstName|Surname|Lineage|OtherName|Affiliation
+ |AuthorBlurb|Contrib %local.person.ident.mix;">
+
+<!ENTITY % local.bibliocomponent.mix "">
+<!ENTITY % bibliocomponent.mix
+ "Abbrev|Abstract|Address|ArtPageNums|Author
+ |AuthorGroup|AuthorInitials|BiblioMisc|BiblioSet
+ |Collab|ConfGroup|ContractNum|ContractSponsor
+ |Copyright|CorpAuthor|CorpName|Date|Edition
+ |Editor|InvPartNumber|ISBN|ISSN|IssueNum|OrgName
+ |OtherCredit|PageNums|PrintHistory|ProductName
+ |ProductNumber|PubDate|Publisher|PublisherName
+ |PubsNumber|ReleaseInfo|RevHistory|SeriesVolNums
+ |Subtitle|Title|TitleAbbrev|VolumeNum|CiteTitle
+ |%person.ident.mix;
+ |%ndxterm.class;
+ %local.bibliocomponent.mix;">
+
+<!ENTITY % biblioentry.module "INCLUDE">
+<![ %biblioentry.module; [
+<!ENTITY % local.biblioentry.attrib "">
+
+<!ENTITY % biblioentry.role.attrib "%role.attrib;">
+
+<!ENTITY % biblioentry.element "INCLUDE">
+<![ %biblioentry.element; [
+<!--FUTURE USE (V5.0):
+......................
+ArticleInfo will be droped from BiblioEntry
+......................
+-->
+<!ELEMENT BiblioEntry - O ((ArticleInfo
+ | (%bibliocomponent.mix;))+)
+ %ubiq.exclusion;>
+<!--end of biblioentry.element-->]]>
+
+<!ENTITY % biblioentry.attlist "INCLUDE">
+<![ %biblioentry.attlist; [
+<!ATTLIST BiblioEntry
+ %common.attrib;
+ %biblioentry.role.attrib;
+ %local.biblioentry.attrib;
+>
+<!--end of biblioentry.attlist-->]]>
+<!--end of biblioentry.module-->]]>
+
+<!ENTITY % bibliomixed.module "INCLUDE">
+<![ %bibliomixed.module; [
+<!ENTITY % local.bibliomixed.attrib "">
+<!ENTITY % bibliomixed.role.attrib "%role.attrib;">
+
+<!ENTITY % bibliomixed.element "INCLUDE">
+<![ %bibliomixed.element; [
+<!ELEMENT BiblioMixed - O ((%bibliocomponent.mix; | BiblioMSet | #PCDATA)+)
+ %ubiq.exclusion;>
+<!--end of bibliomixed.element-->]]>
+
+<!ENTITY % bibliomixed.attlist "INCLUDE">
+<![ %bibliomixed.attlist; [
+<!ATTLIST BiblioMixed
+ %common.attrib;
+ %bibliomixed.role.attrib;
+ %local.bibliomixed.attrib;
+>
+<!--end of bibliomixed.attlist-->]]>
+<!--end of bibliomixed.module-->]]>
+
+<!ENTITY % articleinfo.module "INCLUDE">
+<![ %articleinfo.module; [
+<!ENTITY % local.articleinfo.attrib "">
+<!ENTITY % articleinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % articleinfo.element "INCLUDE">
+<![ %articleinfo.element; [
+<!ELEMENT ArticleInfo - - ((Graphic | MediaObject | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ -(BeginPage)>
+<!--end of articleinfo.element-->]]>
+
+<!ENTITY % articleinfo.attlist "INCLUDE">
+<![ %articleinfo.attlist; [
+<!ATTLIST ArticleInfo
+ %common.attrib;
+ %articleinfo.role.attrib;
+ %local.articleinfo.attrib;
+>
+<!--end of articleinfo.attlist-->]]>
+<!--end of articleinfo.module-->]]>
+
+<!ENTITY % biblioset.module "INCLUDE">
+<![ %biblioset.module; [
+<!ENTITY % local.biblioset.attrib "">
+<!ENTITY % biblioset.role.attrib "%role.attrib;">
+
+<!ENTITY % biblioset.element "INCLUDE">
+<![ %biblioset.element; [
+<!ELEMENT BiblioSet - - ((%bibliocomponent.mix;)+) %ubiq.exclusion;>
+<!--end of biblioset.element-->]]>
+
+<!ENTITY % biblioset.attlist "INCLUDE">
+<![ %biblioset.attlist; [
+<!ATTLIST BiblioSet
+ --
+ Relation: Relationship of elements contained within BiblioSet
+ --
+ Relation CDATA #IMPLIED
+ %common.attrib;
+ %biblioset.role.attrib;
+ %local.biblioset.attrib;
+>
+<!--end of biblioset.attlist-->]]>
+<!--end of biblioset.module-->]]>
+
+<!ENTITY % bibliomset.module "INCLUDE">
+<![ %bibliomset.module; [
+<!ENTITY % bibliomset.role.attrib "%role.attrib;">
+<!ENTITY % local.bibliomset.attrib "">
+
+<!ENTITY % bibliomset.element "INCLUDE">
+<![ %bibliomset.element; [
+<!ELEMENT BiblioMSet - - ((%bibliocomponent.mix; | BiblioMSet | #PCDATA)+)
+ %ubiq.exclusion;>
+<!--end of bibliomset.element-->]]>
+
+<!ENTITY % bibliomset.attlist "INCLUDE">
+<![ %bibliomset.attlist; [
+<!ATTLIST BiblioMSet
+ --
+ Relation: Relationship of elements contained within BiblioMSet
+ --
+ Relation CDATA #IMPLIED
+ %bibliomset.role.attrib;
+ %common.attrib;
+ %local.bibliomset.attrib;
+>
+<!--end of bibliomset.attlist-->]]>
+<!--end of bibliomset.module-->]]>
+
+<!ENTITY % bibliomisc.module "INCLUDE">
+<![ %bibliomisc.module; [
+<!ENTITY % local.bibliomisc.attrib "">
+<!ENTITY % bibliomisc.role.attrib "%role.attrib;">
+
+<!ENTITY % bibliomisc.element "INCLUDE">
+<![ %bibliomisc.element; [
+<!ELEMENT BiblioMisc - - ((%para.char.mix;)+)>
+<!--end of bibliomisc.element-->]]>
+
+<!ENTITY % bibliomisc.attlist "INCLUDE">
+<![ %bibliomisc.attlist; [
+<!ATTLIST BiblioMisc
+ %common.attrib;
+ %bibliomisc.role.attrib;
+ %local.bibliomisc.attrib;
+>
+<!--end of bibliomisc.attlist-->]]>
+<!--end of bibliomisc.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Subject, Keyword, and ITermSet elements .............................. -->
+
+<!ENTITY % subjectset.content.module "INCLUDE">
+<![ %subjectset.content.module; [
+<!ENTITY % subjectset.module "INCLUDE">
+<![ %subjectset.module; [
+<!ENTITY % local.subjectset.attrib "">
+<!ENTITY % subjectset.role.attrib "%role.attrib;">
+
+<!ENTITY % subjectset.element "INCLUDE">
+<![ %subjectset.element; [
+<!ELEMENT SubjectSet - - (Subject+)>
+<!--end of subjectset.element-->]]>
+
+<!ENTITY % subjectset.attlist "INCLUDE">
+<![ %subjectset.attlist; [
+<!ATTLIST SubjectSet
+ --
+ Scheme: Controlled vocabulary employed in SubjectTerms
+ --
+ Scheme NAME #IMPLIED
+ %common.attrib;
+ %subjectset.role.attrib;
+ %local.subjectset.attrib;
+>
+<!--end of subjectset.attlist-->]]>
+<!--end of subjectset.module-->]]>
+
+<!ENTITY % subject.module "INCLUDE">
+<![ %subject.module; [
+<!ENTITY % local.subject.attrib "">
+<!ENTITY % subject.role.attrib "%role.attrib;">
+
+<!ENTITY % subject.element "INCLUDE">
+<![ %subject.element; [
+<!ELEMENT Subject - - (SubjectTerm+)>
+<!--end of subject.element-->]]>
+
+<!ENTITY % subject.attlist "INCLUDE">
+<![ %subject.attlist; [
+<!ATTLIST Subject
+ --
+ Weight: Ranking of this group of SubjectTerms relative
+ to others, 0 is low, no highest value specified
+ --
+ Weight NUMBER #IMPLIED
+ %common.attrib;
+ %subject.role.attrib;
+ %local.subject.attrib;
+>
+<!--end of subject.attlist-->]]>
+<!--end of subject.module-->]]>
+
+<!ENTITY % subjectterm.module "INCLUDE">
+<![ %subjectterm.module; [
+<!ENTITY % local.subjectterm.attrib "">
+<!ENTITY % subjectterm.role.attrib "%role.attrib;">
+
+<!ENTITY % subjectterm.element "INCLUDE">
+<![ %subjectterm.element; [
+<!ELEMENT SubjectTerm - - (#PCDATA)>
+<!--end of subjectterm.element-->]]>
+
+<!ENTITY % subjectterm.attlist "INCLUDE">
+<![ %subjectterm.attlist; [
+<!ATTLIST SubjectTerm
+ %common.attrib;
+ %subjectterm.role.attrib;
+ %local.subjectterm.attrib;
+>
+<!--end of subjectterm.attlist-->]]>
+<!--end of subjectterm.module-->]]>
+<!--end of subjectset.content.module-->]]>
+
+<!ENTITY % keywordset.content.module "INCLUDE">
+<![ %keywordset.content.module; [
+<!ENTITY % local.keywordset.attrib "">
+<!ENTITY % keywordset.module "INCLUDE">
+<![ %keywordset.module; [
+<!ENTITY % local.keywordset.attrib "">
+<!ENTITY % keywordset.role.attrib "%role.attrib;">
+
+<!ENTITY % keywordset.element "INCLUDE">
+<![ %keywordset.element; [
+<!ELEMENT KeywordSet - - (Keyword+)>
+<!--end of keywordset.element-->]]>
+
+<!ENTITY % keywordset.attlist "INCLUDE">
+<![ %keywordset.attlist; [
+<!ATTLIST KeywordSet
+ %common.attrib;
+ %keywordset.role.attrib;
+ %local.keywordset.attrib;
+>
+<!--end of keywordset.attlist-->]]>
+<!--end of keywordset.module-->]]>
+
+<!ENTITY % keyword.module "INCLUDE">
+<![ %keyword.module; [
+<!ENTITY % local.keyword.attrib "">
+<!ENTITY % keyword.role.attrib "%role.attrib;">
+
+<!ENTITY % keyword.element "INCLUDE">
+<![ %keyword.element; [
+<!ELEMENT Keyword - - (#PCDATA)>
+<!--end of keyword.element-->]]>
+
+<!ENTITY % keyword.attlist "INCLUDE">
+<![ %keyword.attlist; [
+<!ATTLIST Keyword
+ %common.attrib;
+ %keyword.role.attrib;
+ %local.keyword.attrib;
+>
+<!--end of keyword.attlist-->]]>
+<!--end of keyword.module-->]]>
+<!--end of keywordset.content.module-->]]>
+
+<!ENTITY % itermset.module "INCLUDE">
+<![ %itermset.module; [
+<!ENTITY % local.itermset.attrib "">
+<!ENTITY % itermset.role.attrib "%role.attrib;">
+
+<!ENTITY % itermset.element "INCLUDE">
+<![ %itermset.element; [
+<!ELEMENT ITermSet - - (IndexTerm+)>
+<!--end of itermset.element-->]]>
+
+<!ENTITY % itermset.attlist "INCLUDE">
+<![ %itermset.attlist; [
+<!ATTLIST ITermSet
+ %common.attrib;
+ %itermset.role.attrib;
+ %local.itermset.attrib;
+>
+<!--end of itermset.attlist-->]]>
+<!--end of itermset.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Compound (section-ish) elements ...................................... -->
+
+<!-- Message set ...................... -->
+
+<!ENTITY % msgset.content.module "INCLUDE">
+<![ %msgset.content.module; [
+<!ENTITY % msgset.module "INCLUDE">
+<![ %msgset.module; [
+<!ENTITY % local.msgset.attrib "">
+<!ENTITY % msgset.role.attrib "%role.attrib;">
+
+<!ENTITY % msgset.element "INCLUDE">
+<![ %msgset.element; [
+<!ELEMENT MsgSet - - ((%formalobject.title.content;)?, (MsgEntry+|SimpleMsgEntry+))>
+<!--end of msgset.element-->]]>
+
+<!ENTITY % msgset.attlist "INCLUDE">
+<![ %msgset.attlist; [
+<!ATTLIST MsgSet
+ %common.attrib;
+ %msgset.role.attrib;
+ %local.msgset.attrib;
+>
+<!--end of msgset.attlist-->]]>
+<!--end of msgset.module-->]]>
+
+<!ENTITY % msgentry.module "INCLUDE">
+<![ %msgentry.module; [
+<!ENTITY % local.msgentry.attrib "">
+<!ENTITY % msgentry.role.attrib "%role.attrib;">
+
+<!ENTITY % msgentry.element "INCLUDE">
+<![ %msgentry.element; [
+<!ELEMENT MsgEntry - O (Msg+, MsgInfo?, MsgExplan*)>
+<!--end of msgentry.element-->]]>
+
+<!ENTITY % msgentry.attlist "INCLUDE">
+<![ %msgentry.attlist; [
+<!ATTLIST MsgEntry
+ %common.attrib;
+ %msgentry.role.attrib;
+ %local.msgentry.attrib;
+>
+<!--end of msgentry.attlist-->]]>
+<!--end of msgentry.module-->]]>
+
+<!ENTITY % simplemsgentry.module "INCLUDE">
+<![ %simplemsgentry.module; [
+<!ENTITY % local.simplemsgentry.attrib "">
+<!ENTITY % simplemsgentry.role.attrib "%role.attrib;">
+
+<!ENTITY % simplemsgentry.element "INCLUDE">
+<![ %simplemsgentry.element; [
+<!ELEMENT SimpleMsgEntry - O (MsgText, MsgExplan)>
+<!--end of simplemsgentry.element-->]]>
+
+<!ENTITY % simplemsgentry.attlist "INCLUDE">
+<![ %simplemsgentry.attlist; [
+<!ATTLIST SimpleMsgEntry
+ %common.attrib;
+ %simplemsgentry.role.attrib;
+ %local.simplemsgentry.attrib;
+ Audience CDATA #IMPLIED
+ Level CDATA #IMPLIED
+ Origin CDATA #IMPLIED
+>
+<!--end of simplemsgentry.attlist-->]]>
+<!--end of simplemsgentry.module-->]]>
+
+<!ENTITY % msg.module "INCLUDE">
+<![ %msg.module; [
+<!ENTITY % local.msg.attrib "">
+<!ENTITY % msg.role.attrib "%role.attrib;">
+
+<!ENTITY % msg.element "INCLUDE">
+<![ %msg.element; [
+<!ELEMENT Msg - O (Title?, MsgMain, (MsgSub | MsgRel)*)>
+<!--end of msg.element-->]]>
+
+<!ENTITY % msg.attlist "INCLUDE">
+<![ %msg.attlist; [
+<!ATTLIST Msg
+ %common.attrib;
+ %msg.role.attrib;
+ %local.msg.attrib;
+>
+<!--end of msg.attlist-->]]>
+<!--end of msg.module-->]]>
+
+<!ENTITY % msgmain.module "INCLUDE">
+<![ %msgmain.module; [
+<!ENTITY % local.msgmain.attrib "">
+<!ENTITY % msgmain.role.attrib "%role.attrib;">
+
+<!ENTITY % msgmain.element "INCLUDE">
+<![ %msgmain.element; [
+<!ELEMENT MsgMain - - (Title?, MsgText)>
+<!--end of msgmain.element-->]]>
+
+<!ENTITY % msgmain.attlist "INCLUDE">
+<![ %msgmain.attlist; [
+<!ATTLIST MsgMain
+ %common.attrib;
+ %msgmain.role.attrib;
+ %local.msgmain.attrib;
+>
+<!--end of msgmain.attlist-->]]>
+<!--end of msgmain.module-->]]>
+
+<!ENTITY % msgsub.module "INCLUDE">
+<![ %msgsub.module; [
+<!ENTITY % local.msgsub.attrib "">
+<!ENTITY % msgsub.role.attrib "%role.attrib;">
+
+<!ENTITY % msgsub.element "INCLUDE">
+<![ %msgsub.element; [
+<!ELEMENT MsgSub - - (Title?, MsgText)>
+<!--end of msgsub.element-->]]>
+
+<!ENTITY % msgsub.attlist "INCLUDE">
+<![ %msgsub.attlist; [
+<!ATTLIST MsgSub
+ %common.attrib;
+ %msgsub.role.attrib;
+ %local.msgsub.attrib;
+>
+<!--end of msgsub.attlist-->]]>
+<!--end of msgsub.module-->]]>
+
+<!ENTITY % msgrel.module "INCLUDE">
+<![ %msgrel.module; [
+<!ENTITY % local.msgrel.attrib "">
+<!ENTITY % msgrel.role.attrib "%role.attrib;">
+
+<!ENTITY % msgrel.element "INCLUDE">
+<![ %msgrel.element; [
+<!ELEMENT MsgRel - - (Title?, MsgText)>
+<!--end of msgrel.element-->]]>
+
+<!ENTITY % msgrel.attlist "INCLUDE">
+<![ %msgrel.attlist; [
+<!ATTLIST MsgRel
+ %common.attrib;
+ %msgrel.role.attrib;
+ %local.msgrel.attrib;
+>
+<!--end of msgrel.attlist-->]]>
+<!--end of msgrel.module-->]]>
+
+<!-- MsgText (defined in the Inlines section, below)-->
+
+<!ENTITY % msginfo.module "INCLUDE">
+<![ %msginfo.module; [
+<!ENTITY % local.msginfo.attrib "">
+<!ENTITY % msginfo.role.attrib "%role.attrib;">
+
+<!ENTITY % msginfo.element "INCLUDE">
+<![ %msginfo.element; [
+<!ELEMENT MsgInfo - - ((MsgLevel | MsgOrig | MsgAud)*)>
+<!--end of msginfo.element-->]]>
+
+<!ENTITY % msginfo.attlist "INCLUDE">
+<![ %msginfo.attlist; [
+<!ATTLIST MsgInfo
+ %common.attrib;
+ %msginfo.role.attrib;
+ %local.msginfo.attrib;
+>
+<!--end of msginfo.attlist-->]]>
+<!--end of msginfo.module-->]]>
+
+<!ENTITY % msglevel.module "INCLUDE">
+<![ %msglevel.module; [
+<!ENTITY % local.msglevel.attrib "">
+<!ENTITY % msglevel.role.attrib "%role.attrib;">
+
+<!ENTITY % msglevel.element "INCLUDE">
+<![ %msglevel.element; [
+<!ELEMENT MsgLevel - - ((%smallcptr.char.mix;)+)>
+<!--end of msglevel.element-->]]>
+
+<!ENTITY % msglevel.attlist "INCLUDE">
+<![ %msglevel.attlist; [
+<!ATTLIST MsgLevel
+ %common.attrib;
+ %msglevel.role.attrib;
+ %local.msglevel.attrib;
+>
+<!--end of msglevel.attlist-->]]>
+<!--end of msglevel.module-->]]>
+
+<!ENTITY % msgorig.module "INCLUDE">
+<![ %msgorig.module; [
+<!ENTITY % local.msgorig.attrib "">
+<!ENTITY % msgorig.role.attrib "%role.attrib;">
+
+<!ENTITY % msgorig.element "INCLUDE">
+<![ %msgorig.element; [
+<!ELEMENT MsgOrig - - ((%smallcptr.char.mix;)+)>
+<!--end of msgorig.element-->]]>
+
+<!ENTITY % msgorig.attlist "INCLUDE">
+<![ %msgorig.attlist; [
+<!ATTLIST MsgOrig
+ %common.attrib;
+ %msgorig.role.attrib;
+ %local.msgorig.attrib;
+>
+<!--end of msgorig.attlist-->]]>
+<!--end of msgorig.module-->]]>
+
+<!ENTITY % msgaud.module "INCLUDE">
+<![ %msgaud.module; [
+<!ENTITY % local.msgaud.attrib "">
+<!ENTITY % msgaud.role.attrib "%role.attrib;">
+
+<!ENTITY % msgaud.element "INCLUDE">
+<![ %msgaud.element; [
+<!ELEMENT MsgAud - - ((%para.char.mix;)+)>
+<!--end of msgaud.element-->]]>
+
+<!ENTITY % msgaud.attlist "INCLUDE">
+<![ %msgaud.attlist; [
+<!ATTLIST MsgAud
+ %common.attrib;
+ %msgaud.role.attrib;
+ %local.msgaud.attrib;
+>
+<!--end of msgaud.attlist-->]]>
+<!--end of msgaud.module-->]]>
+
+<!ENTITY % msgexplan.module "INCLUDE">
+<![ %msgexplan.module; [
+<!ENTITY % local.msgexplan.attrib "">
+<!ENTITY % msgexplan.role.attrib "%role.attrib;">
+
+<!ENTITY % msgexplan.element "INCLUDE">
+<![ %msgexplan.element; [
+<!ELEMENT MsgExplan - - (Title?, (%component.mix;)+)>
+<!--end of msgexplan.element-->]]>
+
+<!ENTITY % msgexplan.attlist "INCLUDE">
+<![ %msgexplan.attlist; [
+<!ATTLIST MsgExplan
+ %common.attrib;
+ %msgexplan.role.attrib;
+ %local.msgexplan.attrib;
+>
+<!--end of msgexplan.attlist-->]]>
+<!--end of msgexplan.module-->]]>
+<!--end of msgset.content.module-->]]>
+
+<!-- QandASet ........................ -->
+<!ENTITY % qandset.content.module "INCLUDE">
+<![ %qandset.content.module; [
+<!ENTITY % qandset.module "INCLUDE">
+<![ %qandset.module; [
+<!ENTITY % local.qandset.attrib "">
+<!ENTITY % qandset.role.attrib "%role.attrib;">
+
+<!ENTITY % qandset.element "INCLUDE">
+<![ %qandset.element; [
+<!ELEMENT QandASet - - ((%formalobject.title.content;)?,
+ (%qandaset.mix;)*,
+ (QandADiv+|QandAEntry+))>
+<!--end of qandset.element-->]]>
+
+<!ENTITY % qandset.attlist "INCLUDE">
+<![ %qandset.attlist; [
+<!ATTLIST QandASet
+ DefaultLabel (qanda|number|none) #IMPLIED
+ %common.attrib;
+ %qandset.role.attrib;
+ %local.qandset.attrib;>
+<!--end of qandset.attlist-->]]>
+<!--end of qandset.module-->]]>
+
+<!ENTITY % qandadiv.module "INCLUDE">
+<![ %qandadiv.module; [
+<!ENTITY % local.qandadiv.attrib "">
+<!ENTITY % qandadiv.role.attrib "%role.attrib;">
+
+<!ENTITY % qandadiv.element "INCLUDE">
+<![ %qandadiv.element; [
+<!ELEMENT QandADiv - - ((%formalobject.title.content;)?,
+ (%qandaset.mix;)*,
+ (QandADiv+|QandAEntry+))>
+<!--end of qandadiv.element-->]]>
+
+<!ENTITY % qandadiv.attlist "INCLUDE">
+<![ %qandadiv.attlist; [
+<!ATTLIST QandADiv
+ %common.attrib;
+ %qandadiv.role.attrib;
+ %local.qandadiv.attrib;>
+<!--end of qandadiv.attlist-->]]>
+<!--end of qandadiv.module-->]]>
+
+<!ENTITY % qandaentry.module "INCLUDE">
+<![ %qandaentry.module; [
+<!ENTITY % local.qandaentry.attrib "">
+<!ENTITY % qandaentry.role.attrib "%role.attrib;">
+
+<!ENTITY % qandaentry.element "INCLUDE">
+<![ %qandaentry.element; [
+<!ELEMENT QandAEntry - - (RevHistory?, Question, Answer*)>
+<!--end of qandaentry.element-->]]>
+
+<!ENTITY % qandaentry.attlist "INCLUDE">
+<![ %qandaentry.attlist; [
+<!ATTLIST QandAEntry
+ %common.attrib;
+ %qandaentry.role.attrib;
+ %local.qandaentry.attrib;>
+<!--end of qandaentry.attlist-->]]>
+<!--end of qandaentry.module-->]]>
+
+<!ENTITY % question.module "INCLUDE">
+<![ %question.module; [
+<!ENTITY % local.question.attrib "">
+<!ENTITY % question.role.attrib "%role.attrib;">
+
+<!ENTITY % question.element "INCLUDE">
+<![ %question.element; [
+<!ELEMENT Question - - (Label?, (%qandaset.mix;)+)>
+<!--end of question.element-->]]>
+
+<!ENTITY % question.attlist "INCLUDE">
+<![ %question.attlist; [
+<!ATTLIST Question
+ %common.attrib;
+ %question.role.attrib;
+ %local.question.attrib;
+>
+<!--end of question.attlist-->]]>
+<!--end of question.module-->]]>
+
+<!ENTITY % answer.module "INCLUDE">
+<![ %answer.module; [
+<!ENTITY % local.answer.attrib "">
+<!ENTITY % answer.role.attrib "%role.attrib;">
+
+<!ENTITY % answer.element "INCLUDE">
+<![ %answer.element; [
+<!ELEMENT Answer - - (Label?, (%qandaset.mix;)*, QandAEntry*)>
+<!--end of answer.element-->]]>
+
+<!ENTITY % answer.attlist "INCLUDE">
+<![ %answer.attlist; [
+<!ATTLIST Answer
+ %common.attrib;
+ %answer.role.attrib;
+ %local.answer.attrib;
+>
+<!--end of answer.attlist-->]]>
+<!--end of answer.module-->]]>
+
+<!ENTITY % label.module "INCLUDE">
+<![ %label.module; [
+<!ENTITY % local.label.attrib "">
+<!ENTITY % label.role.attrib "%role.attrib;">
+
+<!ENTITY % label.element "INCLUDE">
+<![ %label.element; [
+<!ELEMENT Label - - (%word.char.mix;)*>
+<!--end of label.element-->]]>
+
+<!ENTITY % label.attlist "INCLUDE">
+<![ %label.attlist; [
+<!ATTLIST Label
+ %common.attrib;
+ %label.role.attrib;
+ %local.label.attrib;
+>
+<!--end of label.attlist-->]]>
+<!--end of label.module-->]]>
+<!--end of qandset.content.module-->]]>
+
+<!-- Procedure ........................ -->
+
+<!ENTITY % procedure.content.module "INCLUDE">
+<![ %procedure.content.module; [
+<!ENTITY % procedure.module "INCLUDE">
+<![ %procedure.module; [
+<!ENTITY % local.procedure.attrib "">
+<!ENTITY % procedure.role.attrib "%role.attrib;">
+
+<!ENTITY % procedure.element "INCLUDE">
+<![ %procedure.element; [
+<!ELEMENT Procedure - - ((%formalobject.title.content;)?,
+ (%component.mix;)*, Step+)>
+<!--end of procedure.element-->]]>
+
+<!ENTITY % procedure.attlist "INCLUDE">
+<![ %procedure.attlist; [
+<!ATTLIST Procedure
+ %common.attrib;
+ %procedure.role.attrib;
+ %local.procedure.attrib;
+>
+<!--end of procedure.attlist-->]]>
+<!--end of procedure.module-->]]>
+
+<!ENTITY % step.module "INCLUDE">
+<![ %step.module; [
+<!ENTITY % local.step.attrib "">
+<!ENTITY % step.role.attrib "%role.attrib;">
+
+<!ENTITY % step.element "INCLUDE">
+<![ %step.element; [
+<!ELEMENT Step - O (Title?, (((%component.mix;)+, (SubSteps,
+ (%component.mix;)*)?) | (SubSteps, (%component.mix;)*)))>
+<!--end of step.element-->]]>
+
+<!ENTITY % step.attlist "INCLUDE">
+<![ %step.attlist; [
+<!ATTLIST Step
+ --
+ Performance: Whether the Step must be performed
+ --
+ Performance (Optional
+ |Required) Required -- not #REQUIRED! --
+ %common.attrib;
+ %step.role.attrib;
+ %local.step.attrib;
+>
+<!--end of step.attlist-->]]>
+<!--end of step.module-->]]>
+
+<!ENTITY % substeps.module "INCLUDE">
+<![ %substeps.module; [
+<!ENTITY % local.substeps.attrib "">
+<!ENTITY % substeps.role.attrib "%role.attrib;">
+
+<!ENTITY % substeps.element "INCLUDE">
+<![ %substeps.element; [
+<!ELEMENT SubSteps - - (Step+)>
+<!--end of substeps.element-->]]>
+
+<!ENTITY % substeps.attlist "INCLUDE">
+<![ %substeps.attlist; [
+<!ATTLIST SubSteps
+ --
+ Performance: whether entire set of substeps must be performed
+ --
+ Performance (Optional
+ |Required) Required -- not #REQUIRED! --
+ %common.attrib;
+ %substeps.role.attrib;
+ %local.substeps.attrib;
+>
+<!--end of substeps.attlist-->]]>
+<!--end of substeps.module-->]]>
+<!--end of procedure.content.module-->]]>
+
+<!-- Sidebar .......................... -->
+
+<!ENTITY % sidebar.content.model "INCLUDE">
+<![ %sidebar.content.model; [
+
+<!ENTITY % sidebarinfo.module "INCLUDE">
+<![ %sidebarinfo.module; [
+<!ENTITY % local.sidebarinfo.attrib "">
+<!ENTITY % sidebarinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % sidebarinfo.element "INCLUDE">
+<![ %sidebarinfo.element; [
+<!ELEMENT SidebarInfo - - ((Graphic | MediaObject | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ -(BeginPage)>
+<!--end of sidebarinfo.element-->]]>
+
+<!ENTITY % sidebarinfo.attlist "INCLUDE">
+<![ %sidebarinfo.attlist; [
+<!ATTLIST SidebarInfo
+ %common.attrib;
+ %sidebarinfo.role.attrib;
+ %local.sidebarinfo.attrib;
+>
+<!--end of sidebarinfo.attlist-->]]>
+<!--end of sidebarinfo.module-->]]>
+
+<!ENTITY % sidebar.module "INCLUDE">
+<![ %sidebar.module; [
+<!ENTITY % local.sidebar.attrib "">
+<!ENTITY % sidebar.role.attrib "%role.attrib;">
+
+<!ENTITY % sidebar.element "INCLUDE">
+<![ %sidebar.element; [
+<!ELEMENT Sidebar - - (SidebarInfo?,
+ (%formalobject.title.content;)?, (%sidebar.mix;)+)>
+<!--end of sidebar.element-->]]>
+
+<!ENTITY % sidebar.attlist "INCLUDE">
+<![ %sidebar.attlist; [
+<!ATTLIST Sidebar
+ %common.attrib;
+ %sidebar.role.attrib;
+ %local.sidebar.attrib;
+>
+<!--end of sidebar.attlist-->]]>
+<!--end of sidebar.module-->]]>
+<!--end of sidebar.content.model-->]]>
+
+<!-- ...................................................................... -->
+<!-- Paragraph-related elements ........................................... -->
+
+<!ENTITY % abstract.module "INCLUDE">
+<![ %abstract.module; [
+<!ENTITY % local.abstract.attrib "">
+<!ENTITY % abstract.role.attrib "%role.attrib;">
+
+<!ENTITY % abstract.element "INCLUDE">
+<![ %abstract.element; [
+<!ELEMENT Abstract - - (Title?, (%para.class;)+)>
+<!--end of abstract.element-->]]>
+
+<!ENTITY % abstract.attlist "INCLUDE">
+<![ %abstract.attlist; [
+<!ATTLIST Abstract
+ %common.attrib;
+ %abstract.role.attrib;
+ %local.abstract.attrib;
+>
+<!--end of abstract.attlist-->]]>
+<!--end of abstract.module-->]]>
+
+<!ENTITY % authorblurb.module "INCLUDE">
+<![ %authorblurb.module; [
+<!ENTITY % local.authorblurb.attrib "">
+<!ENTITY % authorblurb.role.attrib "%role.attrib;">
+
+<!ENTITY % authorblurb.element "INCLUDE">
+<![ %authorblurb.element; [
+<!ELEMENT AuthorBlurb - - (Title?, (%para.class;)+)>
+<!--end of authorblurb.element-->]]>
+
+<!ENTITY % authorblurb.attlist "INCLUDE">
+<![ %authorblurb.attlist; [
+<!ATTLIST AuthorBlurb
+ %common.attrib;
+ %authorblurb.role.attrib;
+ %local.authorblurb.attrib;
+>
+<!--end of authorblurb.attlist-->]]>
+<!--end of authorblurb.module-->]]>
+
+<!ENTITY % blockquote.module "INCLUDE">
+<![ %blockquote.module; [
+<!ENTITY % local.blockquote.attrib "">
+<!ENTITY % blockquote.role.attrib "%role.attrib;">
+
+<!ENTITY % blockquote.element "INCLUDE">
+<![ %blockquote.element; [
+<!ELEMENT BlockQuote - - (Title?, Attribution?, (%component.mix;)+)
+ %blockquote.exclusion;>
+<!--end of blockquote.element-->]]>
+
+<!ENTITY % blockquote.attlist "INCLUDE">
+<![ %blockquote.attlist; [
+<!ATTLIST BlockQuote
+ %common.attrib;
+ %blockquote.role.attrib;
+ %local.blockquote.attrib;
+>
+<!--end of blockquote.attlist-->]]>
+<!--end of blockquote.module-->]]>
+
+<!ENTITY % attribution.module "INCLUDE">
+<![ %attribution.module; [
+<!ENTITY % local.attribution.attrib "">
+<!ENTITY % attribution.role.attrib "%role.attrib;">
+
+<!ENTITY % attribution.element "INCLUDE">
+<![ %attribution.element; [
+<!ELEMENT Attribution - O ((%para.char.mix;)+)>
+<!--end of attribution.element-->]]>
+
+<!ENTITY % attribution.attlist "INCLUDE">
+<![ %attribution.attlist; [
+<!ATTLIST Attribution
+ %common.attrib;
+ %attribution.role.attrib;
+ %local.attribution.attrib;
+>
+<!--end of attribution.attlist-->]]>
+<!--end of attribution.module-->]]>
+
+<!ENTITY % bridgehead.module "INCLUDE">
+<![ %bridgehead.module; [
+<!ENTITY % local.bridgehead.attrib "">
+<!ENTITY % bridgehead.role.attrib "%role.attrib;">
+
+<!ENTITY % bridgehead.element "INCLUDE">
+<![ %bridgehead.element; [
+<!ELEMENT BridgeHead - - ((%title.char.mix;)+)>
+<!--end of bridgehead.element-->]]>
+
+<!ENTITY % bridgehead.attlist "INCLUDE">
+<![ %bridgehead.attlist; [
+<!ATTLIST BridgeHead
+ --
+ Renderas: Indicates the format in which the BridgeHead
+ should appear
+ --
+ Renderas (Other
+ |Sect1
+ |Sect2
+ |Sect3
+ |Sect4
+ |Sect5) #IMPLIED
+ %common.attrib;
+ %bridgehead.role.attrib;
+ %local.bridgehead.attrib;
+>
+<!--end of bridgehead.attlist-->]]>
+<!--end of bridgehead.module-->]]>
+
+<!ENTITY % remark.module "INCLUDE">
+<![ %remark.module; [
+<!ENTITY % local.remark.attrib "">
+<!ENTITY % remark.role.attrib "%role.attrib;">
+
+<!ENTITY % remark.element "INCLUDE">
+<![ %remark.element; [
+<!ELEMENT Remark - - ((%para.char.mix;)+) %remark.exclusion;>
+<!--end of remark.element-->]]>
+
+<!ENTITY % remark.attlist "INCLUDE">
+<![ %remark.attlist; [
+<!ATTLIST Remark
+ %common.attrib;
+ %remark.role.attrib;
+ %local.remark.attrib;
+>
+<!--end of remark.attlist-->]]>
+<!--end of remark.module-->]]>
+
+<!ENTITY % epigraph.module "INCLUDE">
+<![ %epigraph.module; [
+<!ENTITY % local.epigraph.attrib "">
+<!ENTITY % epigraph.role.attrib "%role.attrib;">
+
+<!ENTITY % epigraph.element "INCLUDE">
+<![ %epigraph.element; [
+<!ELEMENT Epigraph - - (Attribution?, (%para.class;)+)>
+<!--end of epigraph.element-->]]>
+
+<!ENTITY % epigraph.attlist "INCLUDE">
+<![ %epigraph.attlist; [
+<!ATTLIST Epigraph
+ %common.attrib;
+ %epigraph.role.attrib;
+ %local.epigraph.attrib;
+>
+<!--end of epigraph.attlist-->]]>
+<!-- Attribution (defined above)-->
+<!--end of epigraph.module-->]]>
+
+<!ENTITY % footnote.module "INCLUDE">
+<![ %footnote.module; [
+<!ENTITY % local.footnote.attrib "">
+<!ENTITY % footnote.role.attrib "%role.attrib;">
+
+<!ENTITY % footnote.element "INCLUDE">
+<![ %footnote.element; [
+<!ELEMENT Footnote - - ((%footnote.mix;)+) %footnote.exclusion;>
+<!--end of footnote.element-->]]>
+
+<!ENTITY % footnote.attlist "INCLUDE">
+<![ %footnote.attlist; [
+<!ATTLIST Footnote
+ %label.attrib;
+ %common.attrib;
+ %footnote.role.attrib;
+ %local.footnote.attrib;
+>
+<!--end of footnote.attlist-->]]>
+<!--end of footnote.module-->]]>
+
+<!ENTITY % highlights.module "INCLUDE">
+<![ %highlights.module; [
+<!ENTITY % local.highlights.attrib "">
+<!ENTITY % highlights.role.attrib "%role.attrib;">
+
+<!ENTITY % highlights.element "INCLUDE">
+<![ %highlights.element; [
+<!ELEMENT Highlights - - ((%highlights.mix;)+) %highlights.exclusion;>
+<!--end of highlights.element-->]]>
+
+<!ENTITY % highlights.attlist "INCLUDE">
+<![ %highlights.attlist; [
+<!ATTLIST Highlights
+ %common.attrib;
+ %highlights.role.attrib;
+ %local.highlights.attrib;
+>
+<!--end of highlights.attlist-->]]>
+<!--end of highlights.module-->]]>
+
+<!ENTITY % formalpara.module "INCLUDE">
+<![ %formalpara.module; [
+<!ENTITY % local.formalpara.attrib "">
+<!ENTITY % formalpara.role.attrib "%role.attrib;">
+
+<!ENTITY % formalpara.element "INCLUDE">
+<![ %formalpara.element; [
+<!ELEMENT FormalPara - O (Title, (%ndxterm.class;)*, Para)>
+<!--end of formalpara.element-->]]>
+
+<!ENTITY % formalpara.attlist "INCLUDE">
+<![ %formalpara.attlist; [
+<!ATTLIST FormalPara
+ %common.attrib;
+ %formalpara.role.attrib;
+ %local.formalpara.attrib;
+>
+<!--end of formalpara.attlist-->]]>
+<!--end of formalpara.module-->]]>
+
+<!ENTITY % para.module "INCLUDE">
+<![ %para.module; [
+<!ENTITY % local.para.attrib "">
+<!ENTITY % para.role.attrib "%role.attrib;">
+
+<!ENTITY % para.element "INCLUDE">
+<![ %para.element; [
+<!ELEMENT Para - O ((%para.char.mix; | %para.mix;)+)>
+<!--end of para.element-->]]>
+
+<!ENTITY % para.attlist "INCLUDE">
+<![ %para.attlist; [
+<!ATTLIST Para
+ %common.attrib;
+ %para.role.attrib;
+ %local.para.attrib;
+>
+<!--end of para.attlist-->]]>
+<!--end of para.module-->]]>
+
+<!ENTITY % simpara.module "INCLUDE">
+<![ %simpara.module; [
+<!ENTITY % local.simpara.attrib "">
+<!ENTITY % simpara.role.attrib "%role.attrib;">
+
+<!ENTITY % simpara.element "INCLUDE">
+<![ %simpara.element; [
+<!ELEMENT SimPara - O ((%para.char.mix;)+)>
+<!--end of simpara.element-->]]>
+
+<!ENTITY % simpara.attlist "INCLUDE">
+<![ %simpara.attlist; [
+<!ATTLIST SimPara
+ %common.attrib;
+ %simpara.role.attrib;
+ %local.simpara.attrib;
+>
+<!--end of simpara.attlist-->]]>
+<!--end of simpara.module-->]]>
+
+<!ENTITY % admon.module "INCLUDE">
+<![ %admon.module; [
+<!ENTITY % local.admon.attrib "">
+<!ENTITY % admon.role.attrib "%role.attrib;">
+
+<!ENTITY % admon.elements "INCLUDE">
+<![ %admon.elements; [
+<!ELEMENT (%admon.class;) - - (Title?, (%admon.mix;)+) %admon.exclusion;>
+<!--end of admon.elements-->]]>
+
+<!ENTITY % admon.attlists "INCLUDE">
+<![ %admon.attlists; [
+<!ATTLIST (%admon.class;)
+ %common.attrib;
+ %admon.role.attrib;
+ %local.admon.attrib;
+>
+<!--end of admon.attlists-->]]>
+<!--end of admon.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Lists ................................................................ -->
+
+<!-- GlossList ........................ -->
+
+<!ENTITY % glosslist.module "INCLUDE">
+<![ %glosslist.module; [
+<!ENTITY % local.glosslist.attrib "">
+<!ENTITY % glosslist.role.attrib "%role.attrib;">
+
+<!ENTITY % glosslist.element "INCLUDE">
+<![ %glosslist.element; [
+<!ELEMENT GlossList - - (GlossEntry+)>
+<!--end of glosslist.element-->]]>
+
+<!ENTITY % glosslist.attlist "INCLUDE">
+<![ %glosslist.attlist; [
+<!ATTLIST GlossList
+ %common.attrib;
+ %glosslist.role.attrib;
+ %local.glosslist.attrib;
+>
+<!--end of glosslist.attlist-->]]>
+<!--end of glosslist.module-->]]>
+
+<!ENTITY % glossentry.content.module "INCLUDE">
+<![ %glossentry.content.module; [
+<!ENTITY % glossentry.module "INCLUDE">
+<![ %glossentry.module; [
+<!ENTITY % local.glossentry.attrib "">
+<!ENTITY % glossentry.role.attrib "%role.attrib;">
+
+<!ENTITY % glossentry.element "INCLUDE">
+<![ %glossentry.element; [
+<!ELEMENT GlossEntry - O (GlossTerm, Acronym?, Abbrev?,
+ (%ndxterm.class;)*,
+ RevHistory?, (GlossSee|GlossDef+))>
+<!--end of glossentry.element-->]]>
+
+<!ENTITY % glossentry.attlist "INCLUDE">
+<![ %glossentry.attlist; [
+<!ATTLIST GlossEntry
+ --
+ SortAs: String by which the GlossEntry is to be sorted
+ (alphabetized) in lieu of its proper content
+ --
+ SortAs CDATA #IMPLIED
+ %common.attrib;
+ %glossentry.role.attrib;
+ %local.glossentry.attrib;
+>
+<!--end of glossentry.attlist-->]]>
+<!--end of glossentry.module-->]]>
+
+<!-- GlossTerm (defined in the Inlines section, below)-->
+<!ENTITY % glossdef.module "INCLUDE">
+<![ %glossdef.module; [
+<!ENTITY % local.glossdef.attrib "">
+<!ENTITY % glossdef.role.attrib "%role.attrib;">
+
+<!ENTITY % glossdef.element "INCLUDE">
+<![ %glossdef.element; [
+<!ELEMENT GlossDef - O ((%glossdef.mix;)+, GlossSeeAlso*)>
+<!--end of glossdef.element-->]]>
+
+<!ENTITY % glossdef.attlist "INCLUDE">
+<![ %glossdef.attlist; [
+<!ATTLIST GlossDef
+ --
+ Subject: List of subjects; keywords for the definition
+ --
+ Subject CDATA #IMPLIED
+ %common.attrib;
+ %glossdef.role.attrib;
+ %local.glossdef.attrib;
+>
+<!--end of glossdef.attlist-->]]>
+<!--end of glossdef.module-->]]>
+
+<!ENTITY % glosssee.module "INCLUDE">
+<![ %glosssee.module; [
+<!ENTITY % local.glosssee.attrib "">
+<!ENTITY % glosssee.role.attrib "%role.attrib;">
+
+<!ENTITY % glosssee.element "INCLUDE">
+<![ %glosssee.element; [
+<!ELEMENT GlossSee - O ((%para.char.mix;)+)>
+<!--end of glosssee.element-->]]>
+
+<!ENTITY % glosssee.attlist "INCLUDE">
+<![ %glosssee.attlist; [
+<!ATTLIST GlossSee
+ --
+ OtherTerm: Reference to the GlossEntry whose GlossTerm
+ should be displayed at the point of the GlossSee
+ --
+ OtherTerm IDREF #CONREF
+ %common.attrib;
+ %glosssee.role.attrib;
+ %local.glosssee.attrib;
+>
+<!--end of glosssee.attlist-->]]>
+<!--end of glosssee.module-->]]>
+
+<!ENTITY % glossseealso.module "INCLUDE">
+<![ %glossseealso.module; [
+<!ENTITY % local.glossseealso.attrib "">
+<!ENTITY % glossseealso.role.attrib "%role.attrib;">
+
+<!ENTITY % glossseealso.element "INCLUDE">
+<![ %glossseealso.element; [
+<!ELEMENT GlossSeeAlso - O ((%para.char.mix;)+)>
+<!--end of glossseealso.element-->]]>
+
+<!ENTITY % glossseealso.attlist "INCLUDE">
+<![ %glossseealso.attlist; [
+<!ATTLIST GlossSeeAlso
+ --
+ OtherTerm: Reference to the GlossEntry whose GlossTerm
+ should be displayed at the point of the GlossSeeAlso
+ --
+ OtherTerm IDREF #CONREF
+ %common.attrib;
+ %glossseealso.role.attrib;
+ %local.glossseealso.attrib;
+>
+<!--end of glossseealso.attlist-->]]>
+<!--end of glossseealso.module-->]]>
+<!--end of glossentry.content.module-->]]>
+
+<!-- ItemizedList and OrderedList ..... -->
+
+<!ENTITY % itemizedlist.module "INCLUDE">
+<![ %itemizedlist.module; [
+<!ENTITY % local.itemizedlist.attrib "">
+<!ENTITY % itemizedlist.role.attrib "%role.attrib;">
+
+<!ENTITY % itemizedlist.element "INCLUDE">
+<![ %itemizedlist.element; [
+<!ELEMENT ItemizedList - - ((%formalobject.title.content;)?, ListItem+)>
+<!--end of itemizedlist.element-->]]>
+
+<!ENTITY % itemizedlist.attlist "INCLUDE">
+<![ %itemizedlist.attlist; [
+<!ATTLIST ItemizedList
+ --
+ Spacing: Whether the vertical space in the list should be
+ compressed
+ --
+ Spacing (Normal
+ |Compact) #IMPLIED
+ --
+ Mark: Keyword, e.g., bullet, dash, checkbox, none;
+ list of keywords and defaults are implementation specific
+ --
+ %mark.attrib;
+ %common.attrib;
+ %itemizedlist.role.attrib;
+ %local.itemizedlist.attrib;
+>
+<!--end of itemizedlist.attlist-->]]>
+<!--end of itemizedlist.module-->]]>
+
+<!ENTITY % orderedlist.module "INCLUDE">
+<![ %orderedlist.module; [
+<!ENTITY % local.orderedlist.attrib "">
+<!ENTITY % orderedlist.role.attrib "%role.attrib;">
+
+<!ENTITY % orderedlist.element "INCLUDE">
+<![ %orderedlist.element; [
+<!ELEMENT OrderedList - - ((%formalobject.title.content;)?, ListItem+)>
+<!--end of orderedlist.element-->]]>
+
+<!ENTITY % orderedlist.attlist "INCLUDE">
+<![ %orderedlist.attlist; [
+<!ATTLIST OrderedList
+ --
+ Numeration: Style of ListItem numbered; default is expected
+ to be Arabic
+ --
+ Numeration (Arabic
+ |Upperalpha
+ |Loweralpha
+ |Upperroman
+ |Lowerroman) #IMPLIED
+ --
+ InheritNum: Specifies for a nested list that the numbering
+ of ListItems should include the number of the item
+ within which they are nested (e.g., 1a and 1b within 1,
+ rather than a and b)--
+ InheritNum (Inherit
+ |Ignore) Ignore
+ --
+ Continuation: Where list numbering begins afresh (Restarts,
+ the default) or continues that of the immediately preceding
+ list (Continues)
+ --
+ Continuation (Continues
+ |Restarts) Restarts
+ --
+ Spacing: Whether the vertical space in the list should be
+ compressed
+ --
+ Spacing (Normal
+ |Compact) #IMPLIED
+ %common.attrib;
+ %orderedlist.role.attrib;
+ %local.orderedlist.attrib;
+>
+<!--end of orderedlist.attlist-->]]>
+<!--end of orderedlist.module-->]]>
+
+<!ENTITY % listitem.module "INCLUDE">
+<![ %listitem.module; [
+<!ENTITY % local.listitem.attrib "">
+<!ENTITY % listitem.role.attrib "%role.attrib;">
+
+<!ENTITY % listitem.element "INCLUDE">
+<![ %listitem.element; [
+<!ELEMENT ListItem - O ((%component.mix;)+)>
+<!--end of listitem.element-->]]>
+
+<!ENTITY % listitem.attlist "INCLUDE">
+<![ %listitem.attlist; [
+<!ATTLIST ListItem
+ --
+ Override: Indicates the mark to be used for this ListItem
+ instead of the default mark or the mark specified by
+ the Mark attribute on the enclosing ItemizedList
+ --
+ Override CDATA #IMPLIED
+ %common.attrib;
+ %listitem.role.attrib;
+ %local.listitem.attrib;
+>
+<!--end of listitem.attlist-->]]>
+<!--end of listitem.module-->]]>
+
+<!-- SegmentedList .................... -->
+<!ENTITY % segmentedlist.content.module "INCLUDE">
+<![ %segmentedlist.content.module; [
+<!ENTITY % segmentedlist.module "INCLUDE">
+<![ %segmentedlist.module; [
+<!ENTITY % local.segmentedlist.attrib "">
+<!ENTITY % segmentedlist.role.attrib "%role.attrib;">
+
+<!ENTITY % segmentedlist.element "INCLUDE">
+<![ %segmentedlist.element; [
+<!ELEMENT SegmentedList - - ((%formalobject.title.content;)?,
+ SegTitle, SegTitle+,
+ SegListItem+)>
+<!--end of segmentedlist.element-->]]>
+
+<!ENTITY % segmentedlist.attlist "INCLUDE">
+<![ %segmentedlist.attlist; [
+<!ATTLIST SegmentedList
+ %common.attrib;
+ %segmentedlist.role.attrib;
+ %local.segmentedlist.attrib;
+>
+<!--end of segmentedlist.attlist-->]]>
+<!--end of segmentedlist.module-->]]>
+
+<!ENTITY % segtitle.module "INCLUDE">
+<![ %segtitle.module; [
+<!ENTITY % local.segtitle.attrib "">
+<!ENTITY % segtitle.role.attrib "%role.attrib;">
+
+<!ENTITY % segtitle.element "INCLUDE">
+<![ %segtitle.element; [
+<!ELEMENT SegTitle - O ((%title.char.mix;)+)>
+<!--end of segtitle.element-->]]>
+
+<!ENTITY % segtitle.attlist "INCLUDE">
+<![ %segtitle.attlist; [
+<!ATTLIST SegTitle
+ %common.attrib;
+ %segtitle.role.attrib;
+ %local.segtitle.attrib;
+>
+<!--end of segtitle.attlist-->]]>
+<!--end of segtitle.module-->]]>
+
+<!ENTITY % seglistitem.module "INCLUDE">
+<![ %seglistitem.module; [
+<!ENTITY % local.seglistitem.attrib "">
+<!ENTITY % seglistitem.role.attrib "%role.attrib;">
+
+<!ENTITY % seglistitem.element "INCLUDE">
+<![ %seglistitem.element; [
+<!ELEMENT SegListItem - O (Seg, Seg+)>
+<!--end of seglistitem.element-->]]>
+
+<!ENTITY % seglistitem.attlist "INCLUDE">
+<![ %seglistitem.attlist; [
+<!ATTLIST SegListItem
+ %common.attrib;
+ %seglistitem.role.attrib;
+ %local.seglistitem.attrib;
+>
+<!--end of seglistitem.attlist-->]]>
+<!--end of seglistitem.module-->]]>
+
+<!ENTITY % seg.module "INCLUDE">
+<![ %seg.module; [
+<!ENTITY % local.seg.attrib "">
+<!ENTITY % seg.role.attrib "%role.attrib;">
+
+<!ENTITY % seg.element "INCLUDE">
+<![ %seg.element; [
+<!ELEMENT Seg - O ((%para.char.mix;)+)>
+<!--end of seg.element-->]]>
+
+<!ENTITY % seg.attlist "INCLUDE">
+<![ %seg.attlist; [
+<!ATTLIST Seg
+ %common.attrib;
+ %seg.role.attrib;
+ %local.seg.attrib;
+>
+<!--end of seg.attlist-->]]>
+<!--end of seg.module-->]]>
+<!--end of segmentedlist.content.module-->]]>
+
+<!-- SimpleList ....................... -->
+
+<!ENTITY % simplelist.content.module "INCLUDE">
+<![ %simplelist.content.module; [
+<!ENTITY % simplelist.module "INCLUDE">
+<![ %simplelist.module; [
+<!ENTITY % local.simplelist.attrib "">
+<!ENTITY % simplelist.role.attrib "%role.attrib;">
+
+<!ENTITY % simplelist.element "INCLUDE">
+<![ %simplelist.element; [
+<!ELEMENT SimpleList - - (Member+)>
+<!--end of simplelist.element-->]]>
+
+<!ENTITY % simplelist.attlist "INCLUDE">
+<![ %simplelist.attlist; [
+<!ATTLIST SimpleList
+ --
+ Columns: The number of columns the array should contain
+ --
+ Columns NUMBER #IMPLIED
+ --
+ Type: How the Members of the SimpleList should be
+ formatted: Inline (members separated with commas etc.
+ inline), Vert (top to bottom in n Columns), or Horiz (in
+ the direction of text flow) in n Columns. If Column
+ is 1 or implied, Type=Vert and Type=Horiz give the same
+ results.
+ --
+ Type (Inline
+ |Vert
+ |Horiz) Vert
+ %common.attrib;
+ %simplelist.role.attrib;
+ %local.simplelist.attrib;
+>
+<!--end of simplelist.attlist-->]]>
+<!--end of simplelist.module-->]]>
+
+<!ENTITY % member.module "INCLUDE">
+<![ %member.module; [
+<!ENTITY % local.member.attrib "">
+<!ENTITY % member.role.attrib "%role.attrib;">
+
+<!ENTITY % member.element "INCLUDE">
+<![ %member.element; [
+<!ELEMENT Member - O ((%para.char.mix;)+)>
+<!--end of member.element-->]]>
+
+<!ENTITY % member.attlist "INCLUDE">
+<![ %member.attlist; [
+<!ATTLIST Member
+ %common.attrib;
+ %member.role.attrib;
+ %local.member.attrib;
+>
+<!--end of member.attlist-->]]>
+<!--end of member.module-->]]>
+<!--end of simplelist.content.module-->]]>
+
+<!-- VariableList ..................... -->
+
+<!ENTITY % variablelist.content.module "INCLUDE">
+<![ %variablelist.content.module; [
+<!ENTITY % variablelist.module "INCLUDE">
+<![ %variablelist.module; [
+<!ENTITY % local.variablelist.attrib "">
+<!ENTITY % variablelist.role.attrib "%role.attrib;">
+
+<!ENTITY % variablelist.element "INCLUDE">
+<![ %variablelist.element; [
+<!ELEMENT VariableList - - ((%formalobject.title.content;)?, VarListEntry+)>
+<!--end of variablelist.element-->]]>
+
+<!ENTITY % variablelist.attlist "INCLUDE">
+<![ %variablelist.attlist; [
+<!ATTLIST VariableList
+ --
+ TermLength: Length beyond which the presentation engine
+ may consider the Term too long and select an alternate
+ presentation of the Term and, or, its associated ListItem.
+ --
+ TermLength CDATA #IMPLIED
+ %common.attrib;
+ %variablelist.role.attrib;
+ %local.variablelist.attrib;
+>
+<!--end of variablelist.attlist-->]]>
+<!--end of variablelist.module-->]]>
+
+<!ENTITY % varlistentry.module "INCLUDE">
+<![ %varlistentry.module; [
+<!ENTITY % local.varlistentry.attrib "">
+<!ENTITY % varlistentry.role.attrib "%role.attrib;">
+
+<!ENTITY % varlistentry.element "INCLUDE">
+<![ %varlistentry.element; [
+<!ELEMENT VarListEntry - O (Term+, ListItem)>
+<!--end of varlistentry.element-->]]>
+
+<!ENTITY % varlistentry.attlist "INCLUDE">
+<![ %varlistentry.attlist; [
+<!ATTLIST VarListEntry
+ %common.attrib;
+ %varlistentry.role.attrib;
+ %local.varlistentry.attrib;
+>
+<!--end of varlistentry.attlist-->]]>
+<!--end of varlistentry.module-->]]>
+
+<!ENTITY % term.module "INCLUDE">
+<![ %term.module; [
+<!ENTITY % local.term.attrib "">
+<!ENTITY % term.role.attrib "%role.attrib;">
+
+<!ENTITY % term.element "INCLUDE">
+<![ %term.element; [
+<!ELEMENT Term - O ((%para.char.mix;)+)>
+<!--end of term.element-->]]>
+
+<!ENTITY % term.attlist "INCLUDE">
+<![ %term.attlist; [
+<!ATTLIST Term
+ %common.attrib;
+ %term.role.attrib;
+ %local.term.attrib;
+>
+<!--end of term.attlist-->]]>
+<!--end of term.module-->]]>
+
+<!-- ListItem (defined above)-->
+<!--end of variablelist.content.module-->]]>
+
+<!-- CalloutList ...................... -->
+
+<!ENTITY % calloutlist.content.module "INCLUDE">
+<![ %calloutlist.content.module; [
+<!ENTITY % calloutlist.module "INCLUDE">
+<![ %calloutlist.module; [
+<!ENTITY % local.calloutlist.attrib "">
+<!ENTITY % calloutlist.role.attrib "%role.attrib;">
+
+<!ENTITY % calloutlist.element "INCLUDE">
+<![ %calloutlist.element; [
+<!ELEMENT CalloutList - - ((%formalobject.title.content;)?, Callout+)>
+<!--end of calloutlist.element-->]]>
+
+<!ENTITY % calloutlist.attlist "INCLUDE">
+<![ %calloutlist.attlist; [
+<!ATTLIST CalloutList
+ %common.attrib;
+ %calloutlist.role.attrib;
+ %local.calloutlist.attrib;
+>
+<!--end of calloutlist.attlist-->]]>
+<!--end of calloutlist.module-->]]>
+
+<!ENTITY % callout.module "INCLUDE">
+<![ %callout.module; [
+<!ENTITY % local.callout.attrib "">
+<!ENTITY % callout.role.attrib "%role.attrib;">
+
+<!ENTITY % callout.element "INCLUDE">
+<![ %callout.element; [
+<!ELEMENT Callout - O ((%component.mix;)+)>
+<!--end of callout.element-->]]>
+
+<!ENTITY % callout.attlist "INCLUDE">
+<![ %callout.attlist; [
+<!ATTLIST Callout
+ --
+ AreaRefs: IDs of one or more Areas or AreaSets described
+ by this Callout
+ --
+ AreaRefs IDREFS #REQUIRED
+ %common.attrib;
+ %callout.role.attrib;
+ %local.callout.attrib;
+>
+<!--end of callout.attlist-->]]>
+<!--end of callout.module-->]]>
+<!--end of calloutlist.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Objects .............................................................. -->
+
+<!-- Examples etc. .................... -->
+
+<!ENTITY % example.module "INCLUDE">
+<![ %example.module; [
+<!ENTITY % local.example.attrib "">
+<!ENTITY % example.role.attrib "%role.attrib;">
+
+<!ENTITY % example.element "INCLUDE">
+<![ %example.element; [
+<!ELEMENT Example - - ((%formalobject.title.content;), (%example.mix;)+)
+ %formal.exclusion;>
+<!--end of example.element-->]]>
+
+<!ENTITY % example.attlist "INCLUDE">
+<![ %example.attlist; [
+<!ATTLIST Example
+ %label.attrib;
+ %width.attrib;
+ %common.attrib;
+ %example.role.attrib;
+ %local.example.attrib;
+>
+<!--end of example.attlist-->]]>
+<!--end of example.module-->]]>
+
+<!ENTITY % informalexample.module "INCLUDE">
+<![ %informalexample.module; [
+<!ENTITY % local.informalexample.attrib "">
+<!ENTITY % informalexample.role.attrib "%role.attrib;">
+
+<!ENTITY % informalexample.element "INCLUDE">
+<![ %informalexample.element; [
+<!ELEMENT InformalExample - - ((%example.mix;)+)>
+<!--end of informalexample.element-->]]>
+
+<!ENTITY % informalexample.attlist "INCLUDE">
+<![ %informalexample.attlist; [
+<!ATTLIST InformalExample
+ %width.attrib;
+ %common.attrib;
+ %informalexample.role.attrib;
+ %local.informalexample.attrib;
+>
+<!--end of informalexample.attlist-->]]>
+<!--end of informalexample.module-->]]>
+
+<!ENTITY % programlistingco.module "INCLUDE">
+<![ %programlistingco.module; [
+<!ENTITY % local.programlistingco.attrib "">
+<!ENTITY % programlistingco.role.attrib "%role.attrib;">
+
+<!ENTITY % programlistingco.element "INCLUDE">
+<![ %programlistingco.element; [
+<!ELEMENT ProgramListingCO - - (AreaSpec, ProgramListing, CalloutList*)>
+<!--end of programlistingco.element-->]]>
+
+<!ENTITY % programlistingco.attlist "INCLUDE">
+<![ %programlistingco.attlist; [
+<!ATTLIST ProgramListingCO
+ %common.attrib;
+ %programlistingco.role.attrib;
+ %local.programlistingco.attrib;
+>
+<!--end of programlistingco.attlist-->]]>
+<!-- CalloutList (defined above in Lists)-->
+<!--end of programlistingco.module-->]]>
+
+<!ENTITY % areaspec.content.module "INCLUDE">
+<![ %areaspec.content.module; [
+<!ENTITY % areaspec.module "INCLUDE">
+<![ %areaspec.module; [
+<!ENTITY % local.areaspec.attrib "">
+<!ENTITY % areaspec.role.attrib "%role.attrib;">
+
+<!ENTITY % areaspec.element "INCLUDE">
+<![ %areaspec.element; [
+<!ELEMENT AreaSpec - - ((Area|AreaSet)+)>
+<!--end of areaspec.element-->]]>
+
+<!ENTITY % areaspec.attlist "INCLUDE">
+<![ %areaspec.attlist; [
+<!ATTLIST AreaSpec
+ --
+ Units: global unit of measure in which coordinates in
+ this spec are expressed:
+
+ - CALSPair "x1,y1 x2,y2": lower-left and upper-right
+ coordinates in a rectangle describing repro area in which
+ graphic is placed, where X and Y dimensions are each some
+ number 0..10000 (taken from CALS graphic attributes)
+
+ - LineColumn "line column": line number and column number
+ at which to start callout text in "linespecific" content
+
+ - LineRange "startline endline": whole lines from startline
+ to endline in "linespecific" content
+
+ - LineColumnPair "line1 col1 line2 col2": starting and ending
+ points of area in "linespecific" content that starts at
+ first position and ends at second position (including the
+ beginnings of any intervening lines)
+
+ - Other: directive to look at value of OtherUnits attribute
+ to get implementation-specific keyword
+
+ The default is implementation-specific; usually dependent on
+ the parent element (GraphicCO gets CALSPair, ProgramListingCO
+ and ScreenCO get LineColumn)
+ --
+ Units (CALSPair
+ |LineColumn
+ |LineRange
+ |LineColumnPair
+ |Other) #IMPLIED
+ --
+ OtherUnits: User-defined units
+ --
+ OtherUnits NAME #IMPLIED
+ %common.attrib;
+ %areaspec.role.attrib;
+ %local.areaspec.attrib;
+>
+<!--end of areaspec.attlist-->]]>
+<!--end of areaspec.module-->]]>
+
+<!ENTITY % area.module "INCLUDE">
+<![ %area.module; [
+<!ENTITY % local.area.attrib "">
+<!ENTITY % area.role.attrib "%role.attrib;">
+
+<!ENTITY % area.element "INCLUDE">
+<![ %area.element; [
+<!ELEMENT Area - O EMPTY>
+<!--end of area.element-->]]>
+
+<!ENTITY % area.attlist "INCLUDE">
+<![ %area.attlist; [
+<!ATTLIST Area
+ %label.attrib; --bug number/symbol override or initialization--
+ %linkends.attrib; --to any related information--
+ --
+ Units: unit of measure in which coordinates in this
+ area are expressed; inherits from AreaSet and AreaSpec
+ --
+ Units (CALSPair
+ |LineColumn
+ |LineRange
+ |LineColumnPair
+ |Other) #IMPLIED
+ --
+ OtherUnits: User-defined units
+ --
+ OtherUnits NAME #IMPLIED
+ Coords CDATA #REQUIRED
+ %idreq.common.attrib;
+ %area.role.attrib;
+ %local.area.attrib;
+>
+<!--end of area.attlist-->]]>
+<!--end of area.module-->]]>
+
+<!ENTITY % areaset.module "INCLUDE">
+<![ %areaset.module; [
+<!ENTITY % local.areaset.attrib "">
+<!ENTITY % areaset.role.attrib "%role.attrib;">
+
+<!ENTITY % areaset.element "INCLUDE">
+<![ %areaset.element; [
+<!ELEMENT AreaSet - - (Area+)>
+<!--end of areaset.element-->]]>
+
+<!ENTITY % areaset.attlist "INCLUDE">
+<![ %areaset.attlist; [
+<!--FUTURE USE (V5.0):
+......................
+Coord attribute will be removed from AreaSet
+......................
+-->
+<!ATTLIST AreaSet
+ %label.attrib; --bug number/symbol override or initialization--
+
+ --
+ Units: unit of measure in which coordinates in this
+ area are expressed; inherits from AreaSpec
+ --
+ Units (CALSPair
+ |LineColumn
+ |LineRange
+ |LineColumnPair
+ |Other) #IMPLIED
+ OtherUnits NAME #IMPLIED
+ Coords CDATA #REQUIRED
+ %idreq.common.attrib;
+ %areaset.role.attrib;
+ %local.areaset.attrib;
+>
+<!--end of areaset.attlist-->]]>
+<!--end of areaset.module-->]]>
+<!--end of areaspec.content.module-->]]>
+
+<!ENTITY % programlisting.module "INCLUDE">
+<![ %programlisting.module; [
+<!ENTITY % local.programlisting.attrib "">
+<!ENTITY % programlisting.role.attrib "%role.attrib;">
+
+<!ENTITY % programlisting.element "INCLUDE">
+<![ %programlisting.element; [
+<!ELEMENT ProgramListing - - ((CO | LineAnnotation | %para.char.mix;)+)>
+<!--end of programlisting.element-->]]>
+
+<!ENTITY % programlisting.attlist "INCLUDE">
+<![ %programlisting.attlist; [
+<!ATTLIST ProgramListing
+ %width.attrib;
+ %linespecific.attrib;
+ %common.attrib;
+ %programlisting.role.attrib;
+ %local.programlisting.attrib;
+>
+<!--end of programlisting.attlist-->]]>
+<!--end of programlisting.module-->]]>
+
+<!ENTITY % literallayout.module "INCLUDE">
+<![ %literallayout.module; [
+<!ENTITY % local.literallayout.attrib "">
+<!ENTITY % literallayout.role.attrib "%role.attrib;">
+
+<!ENTITY % literallayout.element "INCLUDE">
+<![ %literallayout.element; [
+<!ELEMENT LiteralLayout - - ((CO | LineAnnotation | %para.char.mix;)+)>
+<!--end of literallayout.element-->]]>
+
+<!ENTITY % literallayout.attlist "INCLUDE">
+<![ %literallayout.attlist; [
+<!ATTLIST LiteralLayout
+ %width.attrib;
+ %linespecific.attrib;
+ Class (Monospaced|Normal) "Normal"
+ %common.attrib;
+ %literallayout.role.attrib;
+ %local.literallayout.attrib;
+>
+<!--end of literallayout.attlist-->]]>
+<!-- LineAnnotation (defined in the Inlines section, below)-->
+<!--end of literallayout.module-->]]>
+
+<!ENTITY % screenco.module "INCLUDE">
+<![ %screenco.module; [
+<!ENTITY % local.screenco.attrib "">
+<!ENTITY % screenco.role.attrib "%role.attrib;">
+
+<!ENTITY % screenco.element "INCLUDE">
+<![ %screenco.element; [
+<!ELEMENT ScreenCO - - (AreaSpec, Screen, CalloutList*)>
+<!--end of screenco.element-->]]>
+
+<!ENTITY % screenco.attlist "INCLUDE">
+<![ %screenco.attlist; [
+<!ATTLIST ScreenCO
+ %common.attrib;
+ %screenco.role.attrib;
+ %local.screenco.attrib;
+>
+<!--end of screenco.attlist-->]]>
+<!-- AreaSpec (defined above)-->
+<!-- CalloutList (defined above in Lists)-->
+<!--end of screenco.module-->]]>
+
+<!ENTITY % screen.module "INCLUDE">
+<![ %screen.module; [
+<!ENTITY % local.screen.attrib "">
+<!ENTITY % screen.role.attrib "%role.attrib;">
+
+<!ENTITY % screen.element "INCLUDE">
+<![ %screen.element; [
+<!ELEMENT Screen - - ((CO | LineAnnotation | %para.char.mix;)+)>
+<!--end of screen.element-->]]>
+
+<!ENTITY % screen.attlist "INCLUDE">
+<![ %screen.attlist; [
+<!ATTLIST Screen
+ %width.attrib;
+ %linespecific.attrib;
+ %common.attrib;
+ %screen.role.attrib;
+ %local.screen.attrib;
+>
+<!--end of screen.attlist-->]]>
+<!--end of screen.module-->]]>
+
+<!ENTITY % screenshot.content.module "INCLUDE">
+<![ %screenshot.content.module; [
+<!ENTITY % screenshot.module "INCLUDE">
+<![ %screenshot.module; [
+<!ENTITY % local.screenshot.attrib "">
+<!ENTITY % screenshot.role.attrib "%role.attrib;">
+
+<!ENTITY % screenshot.element "INCLUDE">
+<![ %screenshot.element; [
+<!ELEMENT ScreenShot - - (ScreenInfo?,
+ (Graphic|GraphicCO
+ |MediaObject|MediaObjectCO))>
+<!--end of screenshot.element-->]]>
+
+<!ENTITY % screenshot.attlist "INCLUDE">
+<![ %screenshot.attlist; [
+<!ATTLIST ScreenShot
+ %common.attrib;
+ %screenshot.role.attrib;
+ %local.screenshot.attrib;
+>
+<!--end of screenshot.attlist-->]]>
+<!--end of screenshot.module-->]]>
+
+<!ENTITY % screeninfo.module "INCLUDE">
+<![ %screeninfo.module; [
+<!ENTITY % local.screeninfo.attrib "">
+<!ENTITY % screeninfo.role.attrib "%role.attrib;">
+
+<!ENTITY % screeninfo.element "INCLUDE">
+<![ %screeninfo.element; [
+<!ELEMENT ScreenInfo - O ((%para.char.mix;)+) %ubiq.exclusion;>
+<!--end of screeninfo.element-->]]>
+
+<!ENTITY % screeninfo.attlist "INCLUDE">
+<![ %screeninfo.attlist; [
+<!ATTLIST ScreenInfo
+ %common.attrib;
+ %screeninfo.role.attrib;
+ %local.screeninfo.attrib;
+>
+<!--end of screeninfo.attlist-->]]>
+<!--end of screeninfo.module-->]]>
+<!--end of screenshot.content.module-->]]>
+
+<!-- Figures etc. ..................... -->
+
+<!ENTITY % figure.module "INCLUDE">
+<![ %figure.module; [
+<!ENTITY % local.figure.attrib "">
+<!ENTITY % figure.role.attrib "%role.attrib;">
+
+<!ENTITY % figure.element "INCLUDE">
+<![ %figure.element; [
+<!ELEMENT Figure - - ((%formalobject.title.content;), (%figure.mix; |
+ %link.char.class;)+)>
+<!--end of figure.element-->]]>
+
+<!ENTITY % figure.attlist "INCLUDE">
+<![ %figure.attlist; [
+<!ATTLIST Figure
+ --
+ Float: Whether the Figure is supposed to be rendered
+ where convenient (yes (1) value) or at the place it occurs
+ in the text (no (0) value, the default)
+ --
+ Float %yesorno.attvals; %no.attval;
+ PgWide %yesorno.attvals; #IMPLIED
+ %label.attrib;
+ %common.attrib;
+ %figure.role.attrib;
+ %local.figure.attrib;
+>
+<!--end of figure.attlist-->]]>
+<!--end of figure.module-->]]>
+
+<!ENTITY % informalfigure.module "INCLUDE">
+<![ %informalfigure.module; [
+<!ENTITY % local.informalfigure.attrib "">
+<!ENTITY % informalfigure.role.attrib "%role.attrib;">
+
+<!ENTITY % informalfigure.element "INCLUDE">
+<![ %informalfigure.element; [
+<!ELEMENT InformalFigure - - ((%figure.mix; | %link.char.class;)+)>
+<!--end of informalfigure.element-->]]>
+
+<!ENTITY % informalfigure.attlist "INCLUDE">
+<![ %informalfigure.attlist; [
+<!ATTLIST InformalFigure
+ --
+ Float: Whether the Figure is supposed to be rendered
+ where convenient (yes (1) value) or at the place it occurs
+ in the text (no (0) value, the default)
+ --
+ Float %yesorno.attvals; %no.attval;
+ PgWide %yesorno.attvals; #IMPLIED
+ %label.attrib;
+ %common.attrib;
+ %informalfigure.role.attrib;
+ %local.informalfigure.attrib;
+>
+<!--end of informalfigure.attlist-->]]>
+<!--end of informalfigure.module-->]]>
+
+<!ENTITY % graphicco.module "INCLUDE">
+<![ %graphicco.module; [
+<!ENTITY % local.graphicco.attrib "">
+<!ENTITY % graphicco.role.attrib "%role.attrib;">
+
+<!ENTITY % graphicco.element "INCLUDE">
+<![ %graphicco.element; [
+<!ELEMENT GraphicCO - - (AreaSpec, Graphic, CalloutList*)>
+<!--end of graphicco.element-->]]>
+
+<!ENTITY % graphicco.attlist "INCLUDE">
+<![ %graphicco.attlist; [
+<!ATTLIST GraphicCO
+ %common.attrib;
+ %graphicco.role.attrib;
+ %local.graphicco.attrib;
+>
+<!--end of graphicco.attlist-->]]>
+<!-- AreaSpec (defined above in Examples)-->
+<!-- CalloutList (defined above in Lists)-->
+<!--end of graphicco.module-->]]>
+
+<!-- Graphical data can be the content of Graphic, or you can reference
+ an external file either as an entity (Entitref) or a filename
+ (Fileref). -->
+
+<!ENTITY % graphic.module "INCLUDE">
+<![ %graphic.module; [
+<!ENTITY % local.graphic.attrib "">
+<!ENTITY % graphic.role.attrib "%role.attrib;">
+
+<!ENTITY % graphic.element "INCLUDE">
+<![ %graphic.element; [
+<!ELEMENT Graphic - O EMPTY>
+<!--end of graphic.element-->]]>
+
+<!ENTITY % graphic.attlist "INCLUDE">
+<![ %graphic.attlist; [
+<!ATTLIST Graphic
+ %graphics.attrib;
+ %common.attrib;
+ %graphic.role.attrib;
+ %local.graphic.attrib;
+>
+<!--end of graphic.attlist-->]]>
+<!--end of graphic.module-->]]>
+
+<!ENTITY % inlinegraphic.module "INCLUDE">
+<![ %inlinegraphic.module; [
+<!ENTITY % local.inlinegraphic.attrib "">
+<!ENTITY % inlinegraphic.role.attrib "%role.attrib;">
+
+<!ENTITY % inlinegraphic.element "INCLUDE">
+<![ %inlinegraphic.element; [
+<!ELEMENT InlineGraphic - O EMPTY>
+<!--end of inlinegraphic.element-->]]>
+
+<!ENTITY % inlinegraphic.attlist "INCLUDE">
+<![ %inlinegraphic.attlist; [
+<!ATTLIST InlineGraphic
+ %graphics.attrib;
+ %common.attrib;
+ %inlinegraphic.role.attrib;
+ %local.inlinegraphic.attrib;
+>
+<!--end of inlinegraphic.attlist-->]]>
+<!--end of inlinegraphic.module-->]]>
+
+<!ENTITY % mediaobject.content.module "INCLUDE">
+<![ %mediaobject.content.module; [
+
+<!ENTITY % mediaobject.module "INCLUDE">
+<![ %mediaobject.module; [
+<!ENTITY % local.mediaobject.attrib "">
+<!ENTITY % mediaobject.role.attrib "%role.attrib;">
+
+<!ENTITY % mediaobject.element "INCLUDE">
+<![ %mediaobject.element; [
+<!ELEMENT MediaObject - - (ObjectInfo?,
+ (%mediaobject.mix;),
+ (%mediaobject.mix;|TextObject)*,
+ Caption?)>
+<!--end of mediaobject.element-->]]>
+
+<!ENTITY % mediaobject.attlist "INCLUDE">
+<![ %mediaobject.attlist; [
+<!ATTLIST MediaObject
+ %common.attrib;
+ %mediaobject.role.attrib;
+ %local.mediaobject.attrib;
+>
+<!--end of mediaobject.attlist-->]]>
+<!--end of mediaobject.module-->]]>
+
+<!ENTITY % inlinemediaobject.module "INCLUDE">
+<![ %inlinemediaobject.module; [
+<!ENTITY % local.inlinemediaobject.attrib "">
+<!ENTITY % inlinemediaobject.role.attrib "%role.attrib;">
+
+<!ENTITY % inlinemediaobject.element "INCLUDE">
+<![ %inlinemediaobject.element; [
+<!ELEMENT InlineMediaObject - - (ObjectInfo?,
+ (%mediaobject.mix;),
+ (%mediaobject.mix;|TextObject)*)>
+<!--end of inlinemediaobject.element-->]]>
+
+<!ENTITY % inlinemediaobject.attlist "INCLUDE">
+<![ %inlinemediaobject.attlist; [
+<!ATTLIST InlineMediaObject
+ %common.attrib;
+ %inlinemediaobject.role.attrib;
+ %local.inlinemediaobject.attrib;
+>
+<!--end of inlinemediaobject.attlist-->]]>
+<!--end of inlinemediaobject.module-->]]>
+
+<!ENTITY % videoobject.module "INCLUDE">
+<![ %videoobject.module; [
+<!ENTITY % local.videoobject.attrib "">
+<!ENTITY % videoobject.role.attrib "%role.attrib;">
+
+<!ENTITY % videoobject.element "INCLUDE">
+<![ %videoobject.element; [
+<!ELEMENT VideoObject - - (ObjectInfo?, VideoData)>
+<!--end of videoobject.element-->]]>
+
+<!ENTITY % videoobject.attlist "INCLUDE">
+<![ %videoobject.attlist; [
+<!ATTLIST VideoObject
+ %common.attrib;
+ %videoobject.role.attrib;
+ %local.videoobject.attrib;
+>
+<!--end of videoobject.attlist-->]]>
+<!--end of videoobject.module-->]]>
+
+<!ENTITY % audioobject.module "INCLUDE">
+<![ %audioobject.module; [
+<!ENTITY % local.audioobject.attrib "">
+<!ENTITY % audioobject.role.attrib "%role.attrib;">
+
+<!ENTITY % audioobject.element "INCLUDE">
+<![ %audioobject.element; [
+<!ELEMENT AudioObject - - (ObjectInfo?, AudioData)>
+<!--end of audioobject.element-->]]>
+
+<!ENTITY % audioobject.attlist "INCLUDE">
+<![ %audioobject.attlist; [
+<!ATTLIST AudioObject
+ %common.attrib;
+ %audioobject.role.attrib;
+ %local.audioobject.attrib;
+>
+<!--end of audioobject.attlist-->]]>
+<!--end of audioobject.module-->]]>
+
+<!ENTITY % imageobject.module "INCLUDE">
+<![ %imageobject.module; [
+<!ENTITY % local.imageobject.attrib "">
+<!ENTITY % imageobject.role.attrib "%role.attrib;">
+
+<!ENTITY % imageobject.element "INCLUDE">
+<![ %imageobject.element; [
+<!ELEMENT ImageObject - - (ObjectInfo?, ImageData)>
+<!--end of imageobject.element-->]]>
+
+<!ENTITY % imageobject.attlist "INCLUDE">
+<![ %imageobject.attlist; [
+<!ATTLIST ImageObject
+ %common.attrib;
+ %imageobject.role.attrib;
+ %local.imageobject.attrib;
+>
+<!--end of imageobject.attlist-->]]>
+<!--end of imageobject.module-->]]>
+
+<!ENTITY % textobject.module "INCLUDE">
+<![ %textobject.module; [
+<!ENTITY % local.textobject.attrib "">
+<!ENTITY % textobject.role.attrib "%role.attrib;">
+
+<!ENTITY % textobject.element "INCLUDE">
+<![ %textobject.element; [
+<!ELEMENT TextObject - - (ObjectInfo?, (Phrase|(%textobject.mix;)+))>
+<!--end of textobject.element-->]]>
+
+<!ENTITY % textobject.attlist "INCLUDE">
+<![ %textobject.attlist; [
+<!ATTLIST TextObject
+ %common.attrib;
+ %textobject.role.attrib;
+ %local.textobject.attrib;
+>
+<!--end of textobject.attlist-->]]>
+<!--end of textobject.module-->]]>
+
+<!ENTITY % objectinfo.module "INCLUDE">
+<![ %objectinfo.module; [
+<!ENTITY % local.objectinfo.attrib "">
+<!ENTITY % objectinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % objectinfo.element "INCLUDE">
+<![ %objectinfo.element; [
+<!ELEMENT ObjectInfo - - ((Graphic | MediaObject | LegalNotice | ModeSpec
+ | SubjectSet | KeywordSet | ITermSet | %bibliocomponent.mix;)+)
+ -(BeginPage)>
+<!--end of objectinfo.element-->]]>
+
+<!ENTITY % objectinfo.attlist "INCLUDE">
+<![ %objectinfo.attlist; [
+<!ATTLIST ObjectInfo
+ %common.attrib;
+ %objectinfo.role.attrib;
+ %local.objectinfo.attrib;
+>
+<!--end of objectinfo.attlist-->]]>
+<!--end of objectinfo.module-->]]>
+
+<!ENTITY % local.objectdata.attrib "">
+<!ENTITY % objectdata.attrib
+ "
+ --EntityRef: Name of an external entity containing the content
+ of the object data--
+ EntityRef ENTITY #IMPLIED
+
+ --FileRef: Filename, qualified by a pathname if desired,
+ designating the file containing the content of the object data--
+ FileRef CDATA #IMPLIED
+
+ --Format: Notation of the element content, if any--
+ Format (%notation.class;)
+ #IMPLIED
+
+ --SrcCredit: Information about the source of the image--
+ SrcCredit CDATA #IMPLIED
+
+ %local.objectdata.attrib;"
+>
+
+<!ENTITY % videodata.module "INCLUDE">
+<![ %videodata.module; [
+<!ENTITY % local.videodata.attrib "">
+<!ENTITY % videodata.role.attrib "%role.attrib;">
+
+<!ENTITY % videodata.element "INCLUDE">
+<![ %videodata.element; [
+<!ELEMENT VideoData - O EMPTY>
+<!--end of videodata.element-->]]>
+
+<!ENTITY % videodata.attlist "INCLUDE">
+<![ %videodata.attlist; [
+<!ATTLIST VideoData
+ %common.attrib;
+ %objectdata.attrib;
+
+ --Width: Same as CALS reprowid (desired width)--
+ Width NUTOKEN #IMPLIED
+
+ --Depth: Same as CALS reprodep (desired depth)--
+ Depth NUTOKEN #IMPLIED
+
+ --Align: Same as CALS hplace with 'none' removed; #IMPLIED means
+ application-specific--
+ Align (Left
+ |Right
+ |Center) #IMPLIED
+
+ --Scale: Conflation of CALS hscale and vscale--
+ Scale NUMBER #IMPLIED
+
+ --Scalefit: Same as CALS scalefit--
+ Scalefit %yesorno.attvals;
+ #IMPLIED
+
+ %videodata.role.attrib;
+ %local.videodata.attrib;
+>
+<!--end of videodata.attlist-->]]>
+<!--end of videodata.module-->]]>
+
+<!ENTITY % audiodata.module "INCLUDE">
+<![ %audiodata.module; [
+<!ENTITY % local.audiodata.attrib "">
+<!ENTITY % audiodata.role.attrib "%role.attrib;">
+
+<!ENTITY % audiodata.element "INCLUDE">
+<![ %audiodata.element; [
+<!ELEMENT AudioData - O EMPTY>
+<!--end of audiodata.element-->]]>
+
+<!ENTITY % audiodata.attlist "INCLUDE">
+<![ %audiodata.attlist; [
+<!ATTLIST AudioData
+ %common.attrib;
+ %objectdata.attrib;
+ %local.audiodata.attrib;
+ %audiodata.role.attrib;
+>
+<!--end of audiodata.attlist-->]]>
+<!--end of audiodata.module-->]]>
+
+<!ENTITY % imagedata.module "INCLUDE">
+<![ %imagedata.module; [
+<!ENTITY % local.imagedata.attrib "">
+<!ENTITY % imagedata.role.attrib "%role.attrib;">
+
+<!ENTITY % imagedata.element "INCLUDE">
+<![ %imagedata.element; [
+<!ELEMENT ImageData - O EMPTY>
+<!--end of imagedata.element-->]]>
+
+<!ENTITY % imagedata.attlist "INCLUDE">
+<![ %imagedata.attlist; [
+<!ATTLIST ImageData
+ %common.attrib;
+ %objectdata.attrib;
+
+ --Width: Same as CALS reprowid (desired width)--
+ Width NUTOKEN #IMPLIED
+
+ --Depth: Same as CALS reprodep (desired depth)--
+ Depth NUTOKEN #IMPLIED
+
+ --Align: Same as CALS hplace with 'none' removed; #IMPLIED means
+ application-specific--
+ Align (Left
+ |Right
+ |Center) #IMPLIED
+
+ --Scale: Conflation of CALS hscale and vscale--
+ Scale NUMBER #IMPLIED
+
+ --Scalefit: Same as CALS scalefit--
+ Scalefit %yesorno.attvals;
+ #IMPLIED
+
+ %local.imagedata.attrib;
+ %imagedata.role.attrib;
+>
+<!--end of imagedata.attlist-->]]>
+<!--end of imagedata.module-->]]>
+
+<!ENTITY % caption.module "INCLUDE">
+<![ %caption.module; [
+<!ENTITY % local.caption.attrib "">
+<!ENTITY % caption.role.attrib "%role.attrib;">
+
+<!ENTITY % caption.element "INCLUDE">
+<![ %caption.element; [
+<!ELEMENT Caption - - (%textobject.mix;)*>
+<!--end of caption.element-->]]>
+
+<!ENTITY % caption.attlist "INCLUDE">
+<![ %caption.attlist; [
+<!ATTLIST Caption
+ %common.attrib;
+ %local.caption.attrib;
+ %caption.role.attrib;
+>
+<!--end of caption.attlist-->]]>
+<!--end of caption.module-->]]>
+
+<!ENTITY % mediaobjectco.module "INCLUDE">
+<![ %mediaobjectco.module; [
+<!ENTITY % local.mediaobjectco.attrib "">
+<!ENTITY % mediaobjectco.role.attrib "%role.attrib;">
+
+<!ENTITY % mediaobjectco.element "INCLUDE">
+<![ %mediaobjectco.element; [
+<!ELEMENT MediaObjectCO - - (ObjectInfo?, ImageObjectCO,
+ (ImageObjectCO|TextObject)*)>
+<!--end of mediaobjectco.element-->]]>
+
+<!ENTITY % mediaobjectco.attlist "INCLUDE">
+<![ %mediaobjectco.attlist; [
+<!ATTLIST MediaObjectCO
+ %common.attrib;
+ %mediaobjectco.role.attrib;
+ %local.mediaobjectco.attrib;
+>
+<!--end of mediaobjectco.attlist-->]]>
+<!--end of mediaobjectco.module-->]]>
+
+<!ENTITY % imageobjectco.module "INCLUDE">
+<![ %imageobjectco.module; [
+<!ENTITY % local.imageobjectco.attrib "">
+<!ENTITY % imageobjectco.role.attrib "%role.attrib;">
+
+<!ENTITY % imageobjectco.element "INCLUDE">
+<![ %imageobjectco.element; [
+<!ELEMENT ImageObjectCO - - (AreaSpec, ImageObject, CalloutList*)>
+<!--end of imageobjectco.element-->]]>
+
+<!ENTITY % imageobjectco.attlist "INCLUDE">
+<![ %imageobjectco.attlist; [
+<!ATTLIST ImageObjectCO
+ %common.attrib;
+ %imageobjectco.role.attrib;
+ %local.imageobjectco.attrib;
+>
+<!--end of imageobjectco.attlist-->]]>
+<!--end of imageobjectco.module-->]]>
+<!--end of mediaobject.content.module-->]]>
+
+<!-- Equations ........................ -->
+
+<!-- This PE provides a mechanism for replacing equation content, -->
+<!-- perhaps adding a new or different model (e.g., MathML) -->
+<!ENTITY % equation.content "(Alt?, (Graphic+|MediaObject+))">
+<!ENTITY % inlineequation.content "(Alt?, (Graphic+|InlineMediaObject+))">
+
+<!ENTITY % equation.module "INCLUDE">
+<![ %equation.module; [
+<!ENTITY % local.equation.attrib "">
+<!ENTITY % equation.role.attrib "%role.attrib;">
+
+<!ENTITY % equation.element "INCLUDE">
+<![ %equation.element; [
+<!ELEMENT Equation - - ((%formalobject.title.content;)?, (InformalEquation |
+ %equation.content;))>
+<!--end of equation.element-->]]>
+
+<!ENTITY % equation.attlist "INCLUDE">
+<![ %equation.attlist; [
+<!ATTLIST Equation
+ %label.attrib;
+ %common.attrib;
+ %equation.role.attrib;
+ %local.equation.attrib;
+>
+<!--end of equation.attlist-->]]>
+<!--end of equation.module-->]]>
+
+<!ENTITY % informalequation.module "INCLUDE">
+<![ %informalequation.module; [
+<!ENTITY % local.informalequation.attrib "">
+<!ENTITY % informalequation.role.attrib "%role.attrib;">
+
+<!ENTITY % informalequation.element "INCLUDE">
+<![ %informalequation.element; [
+<!ELEMENT InformalEquation - - (%equation.content;)>
+<!--end of informalequation.element-->]]>
+
+<!ENTITY % informalequation.attlist "INCLUDE">
+<![ %informalequation.attlist; [
+<!ATTLIST InformalEquation
+ %common.attrib;
+ %informalequation.role.attrib;
+ %local.informalequation.attrib;
+>
+<!--end of informalequation.attlist-->]]>
+<!--end of informalequation.module-->]]>
+
+<!ENTITY % inlineequation.module "INCLUDE">
+<![ %inlineequation.module; [
+<!ENTITY % local.inlineequation.attrib "">
+<!ENTITY % inlineequation.role.attrib "%role.attrib;">
+
+<!ENTITY % inlineequation.element "INCLUDE">
+<![ %inlineequation.element; [
+<!ELEMENT InlineEquation - - (%inlineequation.content;)>
+<!--end of inlineequation.element-->]]>
+
+<!ENTITY % inlineequation.attlist "INCLUDE">
+<![ %inlineequation.attlist; [
+<!ATTLIST InlineEquation
+ %common.attrib;
+ %inlineequation.role.attrib;
+ %local.inlineequation.attrib;
+>
+<!--end of inlineequation.attlist-->]]>
+<!--end of inlineequation.module-->]]>
+
+<!ENTITY % alt.module "INCLUDE">
+<![ %alt.module; [
+<!ENTITY % local.alt.attrib "">
+<!ENTITY % alt.role.attrib "%role.attrib;">
+
+<!ENTITY % alt.element "INCLUDE">
+<![ %alt.element; [
+<!ELEMENT Alt - - (#PCDATA)>
+<!--end of alt.element-->]]>
+
+<!ENTITY % alt.attlist "INCLUDE">
+<![ %alt.attlist; [
+<!ATTLIST Alt
+ %common.attrib;
+ %alt.role.attrib;
+ %local.alt.attrib;
+>
+<!--end of alt.attlist-->]]>
+<!--end of alt.module-->]]>
+
+<!-- Tables ........................... -->
+
+<!ENTITY % table.module "INCLUDE">
+<![ %table.module; [
+
+<!ENTITY % tables.role.attrib "%role.attrib;">
+
+<!-- Add Label attribute to Table element (and InformalTable element). -->
+<!ENTITY % bodyatt "%label.attrib;">
+
+<!-- Add common attributes to Table, TGroup, TBody, THead, TFoot, Row,
+ EntryTbl, and Entry (and InformalTable element). -->
+<!ENTITY % secur
+ "%common.attrib;
+ %tables.role.attrib;">
+
+<!-- Remove Chart. -->
+<!ENTITY % tbl.table.name "Table">
+
+<!-- Content model for Table. -->
+<!ENTITY % tbl.table.mdl
+ "((%formalobject.title.content;),
+ (%ndxterm.class;)*,
+ (Graphic+|MediaObject+|tgroup+))">
+
+<!-- Exclude all DocBook tables and formal objects. -->
+<!ENTITY % tbl.table.excep "-(InformalTable|%formal.class;)">
+
+<!-- Remove pgbrk exception on Row. -->
+<!ENTITY % tbl.row.excep "">
+
+<!-- Allow either objects or inlines; beware of REs between elements. -->
+<!ENTITY % tbl.entry.mdl "((%tabentry.mix;)+ | (%para.char.mix;)+)">
+
+<!-- Remove pgbrk exception on Entry. -->
+<!ENTITY % tbl.entry.excep "">
+
+<!-- Remove pgbrk exception on EntryTbl, but leave exclusion of itself. -->
+<!ENTITY % tbl.entrytbl.excep "-(entrytbl)">
+
+<!-- Reference CALS table module. -->
+<!ENTITY % calstbls PUBLIC "-//USA-DOD//DTD Table Model 951010//EN">
+%calstbls;
+<!--end of table.module-->]]>
+
+<!ENTITY % informaltable.module "INCLUDE">
+<![ %informaltable.module; [
+
+<!-- Note that InformalTable is dependent on some of the entity
+ declarations that customize Table. -->
+
+<!ENTITY % local.informaltable.attrib "">
+
+<!ENTITY % informaltable.element "INCLUDE">
+<![ %informaltable.element; [
+<!ELEMENT InformalTable - - (Graphic+|MediaObject+|tgroup+) %tbl.table.excep;>
+<!--end of informaltable.element-->]]>
+
+<!ENTITY % informaltable.attlist "INCLUDE">
+<![ %informaltable.attlist; [
+<!ATTLIST InformalTable
+ --
+ Frame, Colsep, and Rowsep must be repeated because
+ they are not in entities in the table module.
+ --
+ Frame (Top
+ |Bottom
+ |Topbot
+ |All
+ |Sides
+ |None) #IMPLIED
+ Colsep %yesorno.attvals; #IMPLIED
+ Rowsep %yesorno.attvals; #IMPLIED
+ %tbl.table.att; -- includes TabStyle, ToCentry, ShortEntry,
+ Orient, PgWide --
+ %bodyatt; -- includes Label --
+ %secur; -- includes common attributes --
+ %local.informaltable.attrib;
+>
+<!--end of informaltable.attlist-->]]>
+<!--end of informaltable.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Synopses ............................................................. -->
+
+<!-- Synopsis ......................... -->
+
+<!ENTITY % synopsis.module "INCLUDE">
+<![ %synopsis.module; [
+<!ENTITY % local.synopsis.attrib "">
+<!ENTITY % synopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % synopsis.element "INCLUDE">
+<![ %synopsis.element; [
+<!ELEMENT Synopsis - - ((CO | LineAnnotation | %para.char.mix;
+ | Graphic | MediaObject)+)>
+<!--end of synopsis.element-->]]>
+
+<!ENTITY % synopsis.attlist "INCLUDE">
+<![ %synopsis.attlist; [
+<!ATTLIST Synopsis
+ %label.attrib;
+ %linespecific.attrib;
+ %common.attrib;
+ %synopsis.role.attrib;
+ %local.synopsis.attrib;
+>
+<!--end of synopsis.attlist-->]]>
+
+<!-- LineAnnotation (defined in the Inlines section, below)-->
+<!--end of synopsis.module-->]]>
+
+<!-- CmdSynopsis ...................... -->
+
+<!ENTITY % cmdsynopsis.content.module "INCLUDE">
+<![ %cmdsynopsis.content.module; [
+<!ENTITY % cmdsynopsis.module "INCLUDE">
+<![ %cmdsynopsis.module; [
+<!ENTITY % local.cmdsynopsis.attrib "">
+<!ENTITY % cmdsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % cmdsynopsis.element "INCLUDE">
+<![ %cmdsynopsis.element; [
+<!ELEMENT CmdSynopsis - - ((Command | Arg | Group | SBR)+, SynopFragment*)>
+<!--end of cmdsynopsis.element-->]]>
+
+<!ENTITY % cmdsynopsis.attlist "INCLUDE">
+<![ %cmdsynopsis.attlist; [
+<!ATTLIST CmdSynopsis
+ %label.attrib;
+ --
+ Sepchar: Character that should separate command and all
+ top-level arguments; alternate value might be e.g., &Delta;
+ --
+ Sepchar CDATA " "
+ --
+ CmdLength: Length beyond which the presentation engine
+ may consider a Command too long and select an alternate
+ presentation of the Command and, or, its associated
+ arguments.
+ --
+ CmdLength CDATA #IMPLIED
+ %common.attrib;
+ %cmdsynopsis.role.attrib;
+ %local.cmdsynopsis.attrib;
+>
+<!--end of cmdsynopsis.attlist-->]]>
+<!--end of cmdsynopsis.module-->]]>
+
+<!ENTITY % arg.module "INCLUDE">
+<![ %arg.module; [
+<!ENTITY % local.arg.attrib "">
+<!ENTITY % arg.role.attrib "%role.attrib;">
+
+<!ENTITY % arg.element "INCLUDE">
+<![ %arg.element; [
+<!ELEMENT Arg - - ((#PCDATA
+ | Arg
+ | Group
+ | Option
+ | SynopFragmentRef
+ | Replaceable
+ | SBR)+)>
+<!--end of arg.element-->]]>
+
+<!ENTITY % arg.attlist "INCLUDE">
+<![ %arg.attlist; [
+<!ATTLIST Arg
+ --
+ Choice: Whether Arg must be supplied: Opt (optional to
+ supply, e.g. [arg]; the default), Req (required to supply,
+ e.g. {arg}), or Plain (required to supply, e.g. arg)
+ --
+ Choice (Opt
+ |Req
+ |Plain) Opt
+ --
+ Rep: whether Arg is repeatable: Norepeat (e.g. arg without
+ ellipsis; the default), or Repeat (e.g. arg...)
+ --
+ Rep (Norepeat
+ |Repeat) Norepeat
+ %common.attrib;
+ %arg.role.attrib;
+ %local.arg.attrib;
+>
+<!--end of arg.attlist-->]]>
+<!--end of arg.module-->]]>
+
+<!ENTITY % group.module "INCLUDE">
+<![ %group.module; [
+
+<!ENTITY % local.group.attrib "">
+<!ENTITY % group.role.attrib "%role.attrib;">
+
+<!ENTITY % group.element "INCLUDE">
+<![ %group.element; [
+<!ELEMENT Group - - ((Arg | Group | Option | SynopFragmentRef
+ | Replaceable | SBR)+)>
+<!--end of group.element-->]]>
+
+<!ENTITY % group.attlist "INCLUDE">
+<![ %group.attlist; [
+<!ATTLIST Group
+ --
+ Choice: Whether Group must be supplied: Opt (optional to
+ supply, e.g. [g1|g2|g3]; the default), Req (required to
+ supply, e.g. {g1|g2|g3}), Plain (required to supply,
+ e.g. g1|g2|g3), OptMult (can supply zero or more, e.g.
+ [[g1|g2|g3]]), or ReqMult (must supply one or more, e.g.
+ {{g1|g2|g3}})
+ --
+ Choice (Opt
+ |Req
+ |Plain) Opt
+ --
+ Rep: whether Group is repeatable: Norepeat (e.g. group
+ without ellipsis; the default), or Repeat (e.g. group...)
+ --
+ Rep (Norepeat
+ |Repeat) Norepeat
+ %common.attrib;
+ %group.role.attrib;
+ %local.group.attrib;
+>
+<!--end of group.attlist-->]]>
+<!--end of group.module-->]]>
+
+<!ENTITY % sbr.module "INCLUDE">
+<![ %sbr.module; [
+<!ENTITY % local.sbr.attrib "">
+<!-- Synopsis break -->
+<!ENTITY % sbr.role.attrib "%role.attrib;">
+
+<!ENTITY % sbr.element "INCLUDE">
+<![ %sbr.element; [
+<!ELEMENT SBR - O EMPTY>
+<!--end of sbr.element-->]]>
+
+<!ENTITY % sbr.attlist "INCLUDE">
+<![ %sbr.attlist; [
+<!ATTLIST SBR
+ %common.attrib;
+ %sbr.role.attrib;
+ %local.sbr.attrib;
+>
+<!--end of sbr.attlist-->]]>
+<!--end of sbr.module-->]]>
+
+<!ENTITY % synopfragmentref.module "INCLUDE">
+<![ %synopfragmentref.module; [
+<!ENTITY % local.synopfragmentref.attrib "">
+<!ENTITY % synopfragmentref.role.attrib "%role.attrib;">
+
+<!ENTITY % synopfragmentref.element "INCLUDE">
+<![ %synopfragmentref.element; [
+<!ELEMENT SynopFragmentRef - - RCDATA >
+<!--end of synopfragmentref.element-->]]>
+
+<!ENTITY % synopfragmentref.attlist "INCLUDE">
+<![ %synopfragmentref.attlist; [
+<!ATTLIST SynopFragmentRef
+ %linkendreq.attrib; --to SynopFragment of complex synopsis
+ material for separate referencing--
+ %common.attrib;
+ %synopfragmentref.role.attrib;
+ %local.synopfragmentref.attrib;
+>
+<!--end of synopfragmentref.attlist-->]]>
+<!--end of synopfragmentref.module-->]]>
+
+<!ENTITY % synopfragment.module "INCLUDE">
+<![ %synopfragment.module; [
+<!ENTITY % local.synopfragment.attrib "">
+<!ENTITY % synopfragment.role.attrib "%role.attrib;">
+
+<!ENTITY % synopfragment.element "INCLUDE">
+<![ %synopfragment.element; [
+<!ELEMENT SynopFragment - - ((Arg | Group)+)>
+<!--end of synopfragment.element-->]]>
+
+<!ENTITY % synopfragment.attlist "INCLUDE">
+<![ %synopfragment.attlist; [
+<!ATTLIST SynopFragment
+ %idreq.common.attrib;
+ %synopfragment.role.attrib;
+ %local.synopfragment.attrib;
+>
+<!--end of synopfragment.attlist-->]]>
+<!--end of synopfragment.module-->]]>
+
+<!-- Command (defined in the Inlines section, below)-->
+<!-- Option (defined in the Inlines section, below)-->
+<!-- Replaceable (defined in the Inlines section, below)-->
+<!--end of cmdsynopsis.content.module-->]]>
+
+<!-- FuncSynopsis ..................... -->
+
+<!ENTITY % funcsynopsis.content.module "INCLUDE">
+<![ %funcsynopsis.content.module; [
+<!ENTITY % funcsynopsis.module "INCLUDE">
+<![ %funcsynopsis.module; [
+
+<!ENTITY % local.funcsynopsis.attrib "">
+<!ENTITY % funcsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % funcsynopsis.element "INCLUDE">
+<![ %funcsynopsis.element; [
+<!ELEMENT FuncSynopsis - - (FuncSynopsisInfo|FuncPrototype)+>
+<!--end of funcsynopsis.element-->]]>
+
+<!ENTITY % funcsynopsis.attlist "INCLUDE">
+<![ %funcsynopsis.attlist; [
+<!ATTLIST FuncSynopsis
+ %label.attrib;
+ %common.attrib;
+ %funcsynopsis.role.attrib;
+ %local.funcsynopsis.attrib;
+>
+<!--end of funcsynopsis.attlist-->]]>
+<!--end of funcsynopsis.module-->]]>
+
+<!ENTITY % funcsynopsisinfo.module "INCLUDE">
+<![ %funcsynopsisinfo.module; [
+<!ENTITY % local.funcsynopsisinfo.attrib "">
+<!ENTITY % funcsynopsisinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % funcsynopsisinfo.element "INCLUDE">
+<![ %funcsynopsisinfo.element; [
+<!ELEMENT FuncSynopsisInfo - O ((LineAnnotation | %cptr.char.mix;)* )>
+<!--end of funcsynopsisinfo.element-->]]>
+
+<!ENTITY % funcsynopsisinfo.attlist "INCLUDE">
+<![ %funcsynopsisinfo.attlist; [
+<!ATTLIST FuncSynopsisInfo
+ %linespecific.attrib;
+ %common.attrib;
+ %funcsynopsisinfo.role.attrib;
+ %local.funcsynopsisinfo.attrib;
+>
+<!--end of funcsynopsisinfo.attlist-->]]>
+<!--end of funcsynopsisinfo.module-->]]>
+
+<!ENTITY % funcprototype.module "INCLUDE">
+<![ %funcprototype.module; [
+<!ENTITY % local.funcprototype.attrib "">
+<!ENTITY % funcprototype.role.attrib "%role.attrib;">
+
+<!ENTITY % funcprototype.element "INCLUDE">
+<![ %funcprototype.element; [
+<!ELEMENT FuncPrototype - O (FuncDef, (Void | VarArgs | ParamDef+))>
+<!--end of funcprototype.element-->]]>
+
+<!ENTITY % funcprototype.attlist "INCLUDE">
+<![ %funcprototype.attlist; [
+<!ATTLIST FuncPrototype
+ %common.attrib;
+ %funcprototype.role.attrib;
+ %local.funcprototype.attrib;
+>
+<!--end of funcprototype.attlist-->]]>
+<!--end of funcprototype.module-->]]>
+
+<!ENTITY % funcdef.module "INCLUDE">
+<![ %funcdef.module; [
+<!ENTITY % local.funcdef.attrib "">
+<!ENTITY % funcdef.role.attrib "%role.attrib;">
+
+<!ENTITY % funcdef.element "INCLUDE">
+<![ %funcdef.element; [
+<!ELEMENT FuncDef - - ((#PCDATA
+ | Replaceable
+ | Function)*)>
+<!--end of funcdef.element-->]]>
+
+<!ENTITY % funcdef.attlist "INCLUDE">
+<![ %funcdef.attlist; [
+<!ATTLIST FuncDef
+ %common.attrib;
+ %funcdef.role.attrib;
+ %local.funcdef.attrib;
+>
+<!--end of funcdef.attlist-->]]>
+<!--end of funcdef.module-->]]>
+
+<!ENTITY % void.module "INCLUDE">
+<![ %void.module; [
+<!ENTITY % local.void.attrib "">
+<!ENTITY % void.role.attrib "%role.attrib;">
+
+<!ENTITY % void.element "INCLUDE">
+<![ %void.element; [
+<!ELEMENT Void - O EMPTY>
+<!--end of void.element-->]]>
+
+<!ENTITY % void.attlist "INCLUDE">
+<![ %void.attlist; [
+<!ATTLIST Void
+ %common.attrib;
+ %void.role.attrib;
+ %local.void.attrib;
+>
+<!--end of void.attlist-->]]>
+<!--end of void.module-->]]>
+
+<!ENTITY % varargs.module "INCLUDE">
+<![ %varargs.module; [
+<!ENTITY % local.varargs.attrib "">
+<!ENTITY % varargs.role.attrib "%role.attrib;">
+
+<!ENTITY % varargs.element "INCLUDE">
+<![ %varargs.element; [
+<!ELEMENT VarArgs - O EMPTY>
+<!--end of varargs.element-->]]>
+
+<!ENTITY % varargs.attlist "INCLUDE">
+<![ %varargs.attlist; [
+<!ATTLIST VarArgs
+ %common.attrib;
+ %varargs.role.attrib;
+ %local.varargs.attrib;
+>
+<!--end of varargs.attlist-->]]>
+<!--end of varargs.module-->]]>
+
+<!-- Processing assumes that only one Parameter will appear in a
+ ParamDef, and that FuncParams will be used at most once, for
+ providing information on the "inner parameters" for parameters that
+ are pointers to functions. -->
+
+<!ENTITY % paramdef.module "INCLUDE">
+<![ %paramdef.module; [
+<!ENTITY % local.paramdef.attrib "">
+<!ENTITY % paramdef.role.attrib "%role.attrib;">
+
+<!ENTITY % paramdef.element "INCLUDE">
+<![ %paramdef.element; [
+<!ELEMENT ParamDef - - ((#PCDATA
+ | Replaceable
+ | Parameter
+ | FuncParams)*)>
+<!--end of paramdef.element-->]]>
+
+<!ENTITY % paramdef.attlist "INCLUDE">
+<![ %paramdef.attlist; [
+<!ATTLIST ParamDef
+ %common.attrib;
+ %paramdef.role.attrib;
+ %local.paramdef.attrib;
+>
+<!--end of paramdef.attlist-->]]>
+<!--end of paramdef.module-->]]>
+
+<!ENTITY % funcparams.module "INCLUDE">
+<![ %funcparams.module; [
+<!ENTITY % local.funcparams.attrib "">
+<!ENTITY % funcparams.role.attrib "%role.attrib;">
+
+<!ENTITY % funcparams.element "INCLUDE">
+<![ %funcparams.element; [
+<!ELEMENT FuncParams - - ((%cptr.char.mix;)*)>
+<!--end of funcparams.element-->]]>
+
+<!ENTITY % funcparams.attlist "INCLUDE">
+<![ %funcparams.attlist; [
+<!ATTLIST FuncParams
+ %common.attrib;
+ %funcparams.role.attrib;
+ %local.funcparams.attrib;
+>
+<!--end of funcparams.attlist-->]]>
+<!--end of funcparams.module-->]]>
+
+<!-- LineAnnotation (defined in the Inlines section, below)-->
+<!-- Replaceable (defined in the Inlines section, below)-->
+<!-- Function (defined in the Inlines section, below)-->
+<!-- Parameter (defined in the Inlines section, below)-->
+<!--end of funcsynopsis.content.module-->]]>
+
+<!-- ClassSynopsis ..................... -->
+
+<!ENTITY % classsynopsis.content.module "INCLUDE">
+<![%classsynopsis.content.module;[
+
+<!ENTITY % classsynopsis.module "INCLUDE">
+<![%classsynopsis.module;[
+<!ENTITY % local.classsynopsis.attrib "">
+<!ENTITY % classsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % classsynopsis.element "INCLUDE">
+<![%classsynopsis.element;[
+<!ELEMENT ClassSynopsis - - ((OOClass|OOInterface|OOException)+,
+ (ClassSynopsisInfo
+ |FieldSynopsis|%method.synop.class;)*)>
+<!--end of classsynopsis.element-->]]>
+
+<!ENTITY % classsynopsis.attlist "INCLUDE">
+<![%classsynopsis.attlist;[
+<!ATTLIST ClassSynopsis
+ %common.attrib;
+ %classsynopsis.role.attrib;
+ %local.classsynopsis.attrib;
+ Language CDATA #IMPLIED
+ Class (Class|Interface) "Class"
+>
+<!--end of classsynopsis.attlist-->]]>
+<!--end of classsynopsis.module-->]]>
+
+<!ENTITY % classsynopsisinfo.module "INCLUDE">
+<![ %classsynopsisinfo.module; [
+<!ENTITY % local.classsynopsisinfo.attrib "">
+<!ENTITY % classsynopsisinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % classsynopsisinfo.element "INCLUDE">
+<![ %classsynopsisinfo.element; [
+<!ELEMENT ClassSynopsisInfo - O ((LineAnnotation | %cptr.char.mix;)* )>
+<!--end of classsynopsisinfo.element-->]]>
+
+<!ENTITY % classsynopsisinfo.attlist "INCLUDE">
+<![ %classsynopsisinfo.attlist; [
+<!ATTLIST ClassSynopsisInfo
+ %linespecific.attrib;
+ %common.attrib;
+ %classsynopsisinfo.role.attrib;
+ %local.classsynopsisinfo.attrib;
+>
+<!--end of classsynopsisinfo.attlist-->]]>
+<!--end of classsynopsisinfo.module-->]]>
+
+<!ENTITY % ooclass.module "INCLUDE">
+<![%ooclass.module;[
+<!ENTITY % local.ooclass.attrib "">
+<!ENTITY % ooclass.role.attrib "%role.attrib;">
+
+<!ENTITY % ooclass.element "INCLUDE">
+<![%ooclass.element;[
+<!ELEMENT OOClass - - (Modifier*, ClassName)>
+<!--end of ooclass.element-->]]>
+
+<!ENTITY % ooclass.attlist "INCLUDE">
+<![%ooclass.attlist;[
+<!ATTLIST OOClass
+ %common.attrib;
+ %ooclass.role.attrib;
+ %local.ooclass.attrib;
+>
+<!--end of ooclass.attlist-->]]>
+<!--end of ooclass.module-->]]>
+
+<!ENTITY % oointerface.module "INCLUDE">
+<![%oointerface.module;[
+<!ENTITY % local.oointerface.attrib "">
+<!ENTITY % oointerface.role.attrib "%role.attrib;">
+
+<!ENTITY % oointerface.element "INCLUDE">
+<![%oointerface.element;[
+<!ELEMENT OOInterface - - (Modifier*, InterfaceName)>
+<!--end of oointerface.element-->]]>
+
+<!ENTITY % oointerface.attlist "INCLUDE">
+<![%oointerface.attlist;[
+<!ATTLIST OOInterface
+ %common.attrib;
+ %oointerface.role.attrib;
+ %local.oointerface.attrib;
+>
+<!--end of oointerface.attlist-->]]>
+<!--end of oointerface.module-->]]>
+
+<!ENTITY % ooexception.module "INCLUDE">
+<![%ooexception.module;[
+<!ENTITY % local.ooexception.attrib "">
+<!ENTITY % ooexception.role.attrib "%role.attrib;">
+
+<!ENTITY % ooexception.element "INCLUDE">
+<![%ooexception.element;[
+<!ELEMENT OOException - - (Modifier*, ExceptionName)>
+<!--end of ooexception.element-->]]>
+
+<!ENTITY % ooexception.attlist "INCLUDE">
+<![%ooexception.attlist;[
+<!ATTLIST OOException
+ %common.attrib;
+ %ooexception.role.attrib;
+ %local.ooexception.attrib;
+>
+<!--end of ooexception.attlist-->]]>
+<!--end of ooexception.module-->]]>
+
+<!ENTITY % modifier.module "INCLUDE">
+<![%modifier.module;[
+<!ENTITY % local.modifier.attrib "">
+<!ENTITY % modifier.role.attrib "%role.attrib;">
+
+<!ENTITY % modifier.element "INCLUDE">
+<![%modifier.element;[
+<!ELEMENT Modifier - - (%smallcptr.char.mix;)*>
+<!--end of modifier.element-->]]>
+
+<!ENTITY % modifier.attlist "INCLUDE">
+<![%modifier.attlist;[
+<!ATTLIST Modifier
+ %common.attrib;
+ %modifier.role.attrib;
+ %local.modifier.attrib;
+>
+<!--end of modifier.attlist-->]]>
+<!--end of modifier.module-->]]>
+
+<!ENTITY % interfacename.module "INCLUDE">
+<![%interfacename.module;[
+<!ENTITY % local.interfacename.attrib "">
+<!ENTITY % interfacename.role.attrib "%role.attrib;">
+
+<!ENTITY % interfacename.element "INCLUDE">
+<![%interfacename.element;[
+<!ELEMENT InterfaceName - - (%smallcptr.char.mix;)*>
+<!--end of interfacename.element-->]]>
+
+<!ENTITY % interfacename.attlist "INCLUDE">
+<![%interfacename.attlist;[
+<!ATTLIST InterfaceName
+ %common.attrib;
+ %interfacename.role.attrib;
+ %local.interfacename.attrib;
+>
+<!--end of interfacename.attlist-->]]>
+<!--end of interfacename.module-->]]>
+
+<!ENTITY % exceptionname.module "INCLUDE">
+<![%exceptionname.module;[
+<!ENTITY % local.exceptionname.attrib "">
+<!ENTITY % exceptionname.role.attrib "%role.attrib;">
+
+<!ENTITY % exceptionname.element "INCLUDE">
+<![%exceptionname.element;[
+<!ELEMENT ExceptionName - - (%smallcptr.char.mix;)*>
+<!--end of exceptionname.element-->]]>
+
+<!ENTITY % exceptionname.attlist "INCLUDE">
+<![%exceptionname.attlist;[
+<!ATTLIST ExceptionName
+ %common.attrib;
+ %exceptionname.role.attrib;
+ %local.exceptionname.attrib;
+>
+<!--end of exceptionname.attlist-->]]>
+<!--end of exceptionname.module-->]]>
+
+<!ENTITY % fieldsynopsis.module "INCLUDE">
+<![%fieldsynopsis.module;[
+<!ENTITY % local.fieldsynopsis.attrib "">
+<!ENTITY % fieldsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % fieldsynopsis.element "INCLUDE">
+<![%fieldsynopsis.element;[
+<!ELEMENT FieldSynopsis - - (Modifier*, Type?, VarName, Initializer?)>
+<!--end of fieldsynopsis.element-->]]>
+
+<!ENTITY % fieldsynopsis.attlist "INCLUDE">
+<![%fieldsynopsis.attlist;[
+<!ATTLIST FieldSynopsis
+ %common.attrib;
+ %fieldsynopsis.role.attrib;
+ %local.fieldsynopsis.attrib;
+>
+<!--end of fieldsynopsis.attlist-->]]>
+<!--end of fieldsynopsis.module-->]]>
+
+<!ENTITY % initializer.module "INCLUDE">
+<![%initializer.module;[
+<!ENTITY % local.initializer.attrib "">
+<!ENTITY % initializer.role.attrib "%role.attrib;">
+
+<!ENTITY % initializer.element "INCLUDE">
+<![%initializer.element;[
+<!ELEMENT Initializer - - (%smallcptr.char.mix;)*>
+<!--end of initializer.element-->]]>
+
+<!ENTITY % initializer.attlist "INCLUDE">
+<![%initializer.attlist;[
+<!ATTLIST Initializer
+ %common.attrib;
+ %initializer.role.attrib;
+ %local.initializer.attrib;
+>
+<!--end of initializer.attlist-->]]>
+<!--end of initializer.module-->]]>
+
+<!ENTITY % constructorsynopsis.module "INCLUDE">
+<![%constructorsynopsis.module;[
+<!ENTITY % local.constructorsynopsis.attrib "">
+<!ENTITY % constructorsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % constructorsynopsis.element "INCLUDE">
+<![%constructorsynopsis.element;[
+<!ELEMENT ConstructorSynopsis - - (Modifier*,
+ MethodName?,
+ (MethodParam+|Void),
+ ExceptionName*)>
+<!--end of constructorsynopsis.element-->]]>
+
+<!ENTITY % constructorsynopsis.attlist "INCLUDE">
+<![%constructorsynopsis.attlist;[
+<!ATTLIST ConstructorSynopsis
+ %common.attrib;
+ %constructorsynopsis.role.attrib;
+ %local.constructorsynopsis.attrib;
+>
+<!--end of constructorsynopsis.attlist-->]]>
+<!--end of constructorsynopsis.module-->]]>
+
+<!ENTITY % destructorsynopsis.module "INCLUDE">
+<![%destructorsynopsis.module;[
+<!ENTITY % local.destructorsynopsis.attrib "">
+<!ENTITY % destructorsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % destructorsynopsis.element "INCLUDE">
+<![%destructorsynopsis.element;[
+<!ELEMENT DestructorSynopsis - - (Modifier*,
+ MethodName?,
+ (MethodParam+|Void),
+ ExceptionName*)>
+<!--end of destructorsynopsis.element-->]]>
+
+<!ENTITY % destructorsynopsis.attlist "INCLUDE">
+<![%destructorsynopsis.attlist;[
+<!ATTLIST DestructorSynopsis
+ %common.attrib;
+ %destructorsynopsis.role.attrib;
+ %local.destructorsynopsis.attrib;
+>
+<!--end of destructorsynopsis.attlist-->]]>
+<!--end of destructorsynopsis.module-->]]>
+
+<!ENTITY % methodsynopsis.module "INCLUDE">
+<![%methodsynopsis.module;[
+<!ENTITY % local.methodsynopsis.attrib "">
+<!ENTITY % methodsynopsis.role.attrib "%role.attrib;">
+
+<!ENTITY % methodsynopsis.element "INCLUDE">
+<![%methodsynopsis.element;[
+<!ELEMENT MethodSynopsis - - (Modifier*,
+ (Type|Void)?,
+ MethodName,
+ (MethodParam+|Void),
+ ExceptionName*,
+ Modifier*)>
+<!--end of methodsynopsis.element-->]]>
+
+<!ENTITY % methodsynopsis.attlist "INCLUDE">
+<![%methodsynopsis.attlist;[
+<!ATTLIST MethodSynopsis
+ %common.attrib;
+ %methodsynopsis.role.attrib;
+ %local.methodsynopsis.attrib;
+>
+<!--end of methodsynopsis.attlist-->]]>
+<!--end of methodsynopsis.module-->]]>
+
+<!ENTITY % methodname.module "INCLUDE">
+<![%methodname.module;[
+<!ENTITY % local.methodname.attrib "">
+<!ENTITY % methodname.role.attrib "%role.attrib;">
+
+<!ENTITY % methodname.element "INCLUDE">
+<![%methodname.element;[
+<!ELEMENT MethodName - - (%smallcptr.char.mix;)*>
+<!--end of methodname.element-->]]>
+
+<!ENTITY % methodname.attlist "INCLUDE">
+<![%methodname.attlist;[
+<!ATTLIST MethodName
+ %common.attrib;
+ %methodname.role.attrib;
+ %local.methodname.attrib;
+>
+<!--end of methodname.attlist-->]]>
+<!--end of methodname.module-->]]>
+
+<!ENTITY % methodparam.module "INCLUDE">
+<![%methodparam.module;[
+<!ENTITY % local.methodparam.attrib "">
+<!ENTITY % methodparam.role.attrib "%role.attrib;">
+
+<!ENTITY % methodparam.element "INCLUDE">
+<![%methodparam.element;[
+<!ELEMENT MethodParam - - (Modifier*,
+ Type?, ((Parameter,Initializer?)|FuncParams),
+ Modifier*)>
+<!--end of methodparam.element-->]]>
+
+<!ENTITY % methodparam.attlist "INCLUDE">
+<![%methodparam.attlist;[
+<!ATTLIST MethodParam
+ %common.attrib;
+ %methodparam.role.attrib;
+ %local.methodparam.attrib;
+ Choice (Opt
+ |Req
+ |Plain) "Req"
+ Rep (Norepeat
+ |Repeat) "Norepeat"
+>
+<!--end of methodparam.attlist-->]]>
+<!--end of methodparam.module-->]]>
+<!--end of classsynopsis.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Document information entities and elements ........................... -->
+
+<!-- The document information elements include some elements that are
+ currently used only in the document hierarchy module. They are
+ defined here so that they will be available for use in customized
+ document hierarchies. -->
+
+<!-- .................................. -->
+
+<!ENTITY % docinfo.content.module "INCLUDE">
+<![ %docinfo.content.module; [
+
+<!-- Ackno ............................ -->
+
+<!ENTITY % ackno.module "INCLUDE">
+<![ %ackno.module; [
+<!ENTITY % local.ackno.attrib "">
+<!ENTITY % ackno.role.attrib "%role.attrib;">
+
+<!ENTITY % ackno.element "INCLUDE">
+<![ %ackno.element; [
+<!ELEMENT Ackno - - ((%docinfo.char.mix;)+)>
+<!--end of ackno.element-->]]>
+
+<!ENTITY % ackno.attlist "INCLUDE">
+<![ %ackno.attlist; [
+<!ATTLIST Ackno
+ %common.attrib;
+ %ackno.role.attrib;
+ %local.ackno.attrib;
+>
+<!--end of ackno.attlist-->]]>
+<!--end of ackno.module-->]]>
+
+<!-- Address .......................... -->
+
+<!ENTITY % address.content.module "INCLUDE">
+<![ %address.content.module; [
+<!ENTITY % address.module "INCLUDE">
+<![ %address.module; [
+<!ENTITY % local.address.attrib "">
+<!ENTITY % address.role.attrib "%role.attrib;">
+
+<!ENTITY % address.element "INCLUDE">
+<![ %address.element; [
+<!ELEMENT Address - - (#PCDATA|%person.ident.mix;
+ |Street|POB|Postcode|City|State|Country|Phone
+ |Fax|Email|OtherAddr)*>
+<!--end of address.element-->]]>
+
+<!ENTITY % address.attlist "INCLUDE">
+<![ %address.attlist; [
+<!ATTLIST Address
+ %linespecific.attrib;
+ %common.attrib;
+ %address.role.attrib;
+ %local.address.attrib;
+>
+<!--end of address.attlist-->]]>
+<!--end of address.module-->]]>
+
+ <!ENTITY % street.module "INCLUDE">
+ <![ %street.module; [
+ <!ENTITY % local.street.attrib "">
+ <!ENTITY % street.role.attrib "%role.attrib;">
+
+<!ENTITY % street.element "INCLUDE">
+<![ %street.element; [
+<!ELEMENT Street - - ((%docinfo.char.mix;)+)>
+<!--end of street.element-->]]>
+
+<!ENTITY % street.attlist "INCLUDE">
+<![ %street.attlist; [
+<!ATTLIST Street
+ %common.attrib;
+ %street.role.attrib;
+ %local.street.attrib;
+>
+<!--end of street.attlist-->]]>
+ <!--end of street.module-->]]>
+
+ <!ENTITY % pob.module "INCLUDE">
+ <![ %pob.module; [
+ <!ENTITY % local.pob.attrib "">
+ <!ENTITY % pob.role.attrib "%role.attrib;">
+
+<!ENTITY % pob.element "INCLUDE">
+<![ %pob.element; [
+<!ELEMENT POB - - ((%docinfo.char.mix;)+)>
+<!--end of pob.element-->]]>
+
+<!ENTITY % pob.attlist "INCLUDE">
+<![ %pob.attlist; [
+<!ATTLIST POB
+ %common.attrib;
+ %pob.role.attrib;
+ %local.pob.attrib;
+>
+<!--end of pob.attlist-->]]>
+ <!--end of pob.module-->]]>
+
+ <!ENTITY % postcode.module "INCLUDE">
+ <![ %postcode.module; [
+ <!ENTITY % local.postcode.attrib "">
+ <!ENTITY % postcode.role.attrib "%role.attrib;">
+
+<!ENTITY % postcode.element "INCLUDE">
+<![ %postcode.element; [
+<!ELEMENT Postcode - - ((%docinfo.char.mix;)+)>
+<!--end of postcode.element-->]]>
+
+<!ENTITY % postcode.attlist "INCLUDE">
+<![ %postcode.attlist; [
+<!ATTLIST Postcode
+ %common.attrib;
+ %postcode.role.attrib;
+ %local.postcode.attrib;
+>
+<!--end of postcode.attlist-->]]>
+ <!--end of postcode.module-->]]>
+
+ <!ENTITY % city.module "INCLUDE">
+ <![ %city.module; [
+ <!ENTITY % local.city.attrib "">
+ <!ENTITY % city.role.attrib "%role.attrib;">
+
+<!ENTITY % city.element "INCLUDE">
+<![ %city.element; [
+<!ELEMENT City - - ((%docinfo.char.mix;)+)>
+<!--end of city.element-->]]>
+
+<!ENTITY % city.attlist "INCLUDE">
+<![ %city.attlist; [
+<!ATTLIST City
+ %common.attrib;
+ %city.role.attrib;
+ %local.city.attrib;
+>
+<!--end of city.attlist-->]]>
+ <!--end of city.module-->]]>
+
+ <!ENTITY % state.module "INCLUDE">
+ <![ %state.module; [
+ <!ENTITY % local.state.attrib "">
+ <!ENTITY % state.role.attrib "%role.attrib;">
+
+<!ENTITY % state.element "INCLUDE">
+<![ %state.element; [
+<!ELEMENT State - - ((%docinfo.char.mix;)+)>
+<!--end of state.element-->]]>
+
+<!ENTITY % state.attlist "INCLUDE">
+<![ %state.attlist; [
+<!ATTLIST State
+ %common.attrib;
+ %state.role.attrib;
+ %local.state.attrib;
+>
+<!--end of state.attlist-->]]>
+ <!--end of state.module-->]]>
+
+ <!ENTITY % country.module "INCLUDE">
+ <![ %country.module; [
+ <!ENTITY % local.country.attrib "">
+ <!ENTITY % country.role.attrib "%role.attrib;">
+
+<!ENTITY % country.element "INCLUDE">
+<![ %country.element; [
+<!ELEMENT Country - - ((%docinfo.char.mix;)+)>
+<!--end of country.element-->]]>
+
+<!ENTITY % country.attlist "INCLUDE">
+<![ %country.attlist; [
+<!ATTLIST Country
+ %common.attrib;
+ %country.role.attrib;
+ %local.country.attrib;
+>
+<!--end of country.attlist-->]]>
+ <!--end of country.module-->]]>
+
+ <!ENTITY % phone.module "INCLUDE">
+ <![ %phone.module; [
+ <!ENTITY % local.phone.attrib "">
+ <!ENTITY % phone.role.attrib "%role.attrib;">
+
+<!ENTITY % phone.element "INCLUDE">
+<![ %phone.element; [
+<!ELEMENT Phone - - ((%docinfo.char.mix;)+)>
+<!--end of phone.element-->]]>
+
+<!ENTITY % phone.attlist "INCLUDE">
+<![ %phone.attlist; [
+<!ATTLIST Phone
+ %common.attrib;
+ %phone.role.attrib;
+ %local.phone.attrib;
+>
+<!--end of phone.attlist-->]]>
+ <!--end of phone.module-->]]>
+
+ <!ENTITY % fax.module "INCLUDE">
+ <![ %fax.module; [
+ <!ENTITY % local.fax.attrib "">
+ <!ENTITY % fax.role.attrib "%role.attrib;">
+
+<!ENTITY % fax.element "INCLUDE">
+<![ %fax.element; [
+<!ELEMENT Fax - - ((%docinfo.char.mix;)+)>
+<!--end of fax.element-->]]>
+
+<!ENTITY % fax.attlist "INCLUDE">
+<![ %fax.attlist; [
+<!ATTLIST Fax
+ %common.attrib;
+ %fax.role.attrib;
+ %local.fax.attrib;
+>
+<!--end of fax.attlist-->]]>
+ <!--end of fax.module-->]]>
+
+ <!-- Email (defined in the Inlines section, below)-->
+
+ <!ENTITY % otheraddr.module "INCLUDE">
+ <![ %otheraddr.module; [
+ <!ENTITY % local.otheraddr.attrib "">
+ <!ENTITY % otheraddr.role.attrib "%role.attrib;">
+
+<!ENTITY % otheraddr.element "INCLUDE">
+<![ %otheraddr.element; [
+<!ELEMENT OtherAddr - - ((%docinfo.char.mix;)+)>
+<!--end of otheraddr.element-->]]>
+
+<!ENTITY % otheraddr.attlist "INCLUDE">
+<![ %otheraddr.attlist; [
+<!ATTLIST OtherAddr
+ %common.attrib;
+ %otheraddr.role.attrib;
+ %local.otheraddr.attrib;
+>
+<!--end of otheraddr.attlist-->]]>
+ <!--end of otheraddr.module-->]]>
+<!--end of address.content.module-->]]>
+
+<!-- Affiliation ...................... -->
+
+<!ENTITY % affiliation.content.module "INCLUDE">
+<![ %affiliation.content.module; [
+<!ENTITY % affiliation.module "INCLUDE">
+<![ %affiliation.module; [
+<!ENTITY % local.affiliation.attrib "">
+<!ENTITY % affiliation.role.attrib "%role.attrib;">
+
+<!ENTITY % affiliation.element "INCLUDE">
+<![ %affiliation.element; [
+<!ELEMENT Affiliation - - (ShortAffil?, JobTitle*, OrgName?, OrgDiv*,
+ Address*)>
+<!--end of affiliation.element-->]]>
+
+<!ENTITY % affiliation.attlist "INCLUDE">
+<![ %affiliation.attlist; [
+<!ATTLIST Affiliation
+ %common.attrib;
+ %affiliation.role.attrib;
+ %local.affiliation.attrib;
+>
+<!--end of affiliation.attlist-->]]>
+<!--end of affiliation.module-->]]>
+
+ <!ENTITY % shortaffil.module "INCLUDE">
+ <![ %shortaffil.module; [
+ <!ENTITY % local.shortaffil.attrib "">
+ <!ENTITY % shortaffil.role.attrib "%role.attrib;">
+
+<!ENTITY % shortaffil.element "INCLUDE">
+<![ %shortaffil.element; [
+<!ELEMENT ShortAffil - - ((%docinfo.char.mix;)+)>
+<!--end of shortaffil.element-->]]>
+
+<!ENTITY % shortaffil.attlist "INCLUDE">
+<![ %shortaffil.attlist; [
+<!ATTLIST ShortAffil
+ %common.attrib;
+ %shortaffil.role.attrib;
+ %local.shortaffil.attrib;
+>
+<!--end of shortaffil.attlist-->]]>
+ <!--end of shortaffil.module-->]]>
+
+ <!ENTITY % jobtitle.module "INCLUDE">
+ <![ %jobtitle.module; [
+ <!ENTITY % local.jobtitle.attrib "">
+ <!ENTITY % jobtitle.role.attrib "%role.attrib;">
+
+<!ENTITY % jobtitle.element "INCLUDE">
+<![ %jobtitle.element; [
+<!ELEMENT JobTitle - - ((%docinfo.char.mix;)+)>
+<!--end of jobtitle.element-->]]>
+
+<!ENTITY % jobtitle.attlist "INCLUDE">
+<![ %jobtitle.attlist; [
+<!ATTLIST JobTitle
+ %common.attrib;
+ %jobtitle.role.attrib;
+ %local.jobtitle.attrib;
+>
+<!--end of jobtitle.attlist-->]]>
+ <!--end of jobtitle.module-->]]>
+
+ <!-- OrgName (defined elsewhere in this section)-->
+
+ <!ENTITY % orgdiv.module "INCLUDE">
+ <![ %orgdiv.module; [
+ <!ENTITY % local.orgdiv.attrib "">
+ <!ENTITY % orgdiv.role.attrib "%role.attrib;">
+
+<!ENTITY % orgdiv.element "INCLUDE">
+<![ %orgdiv.element; [
+<!ELEMENT OrgDiv - - ((%docinfo.char.mix;)+)>
+<!--end of orgdiv.element-->]]>
+
+<!ENTITY % orgdiv.attlist "INCLUDE">
+<![ %orgdiv.attlist; [
+<!ATTLIST OrgDiv
+ %common.attrib;
+ %orgdiv.role.attrib;
+ %local.orgdiv.attrib;
+>
+<!--end of orgdiv.attlist-->]]>
+ <!--end of orgdiv.module-->]]>
+
+ <!-- Address (defined elsewhere in this section)-->
+<!--end of affiliation.content.module-->]]>
+
+<!-- ArtPageNums ...................... -->
+
+<!ENTITY % artpagenums.module "INCLUDE">
+<![ %artpagenums.module; [
+<!ENTITY % local.artpagenums.attrib "">
+<!ENTITY % argpagenums.role.attrib "%role.attrib;">
+
+<!ENTITY % artpagenums.element "INCLUDE">
+<![ %artpagenums.element; [
+<!ELEMENT ArtPageNums - - ((%docinfo.char.mix;)+)>
+<!--end of artpagenums.element-->]]>
+
+<!ENTITY % artpagenums.attlist "INCLUDE">
+<![ %artpagenums.attlist; [
+<!ATTLIST ArtPageNums
+ %common.attrib;
+ %argpagenums.role.attrib;
+ %local.artpagenums.attrib;
+>
+<!--end of artpagenums.attlist-->]]>
+<!--end of artpagenums.module-->]]>
+
+<!-- Author ........................... -->
+
+<!ENTITY % author.module "INCLUDE">
+<![ %author.module; [
+<!ENTITY % local.author.attrib "">
+<!ENTITY % author.role.attrib "%role.attrib;">
+
+<!ENTITY % author.element "INCLUDE">
+<![ %author.element; [
+<!ELEMENT Author - - ((%person.ident.mix;)+)>
+<!--end of author.element-->]]>
+
+<!ENTITY % author.attlist "INCLUDE">
+<![ %author.attlist; [
+<!ATTLIST Author
+ %common.attrib;
+ %author.role.attrib;
+ %local.author.attrib;
+>
+<!--end of author.attlist-->]]>
+<!--(see "Personal identity elements" for %person.ident.mix;)-->
+<!--end of author.module-->]]>
+
+<!-- AuthorGroup ...................... -->
+
+<!ENTITY % authorgroup.content.module "INCLUDE">
+<![ %authorgroup.content.module; [
+<!ENTITY % authorgroup.module "INCLUDE">
+<![ %authorgroup.module; [
+<!ENTITY % local.authorgroup.attrib "">
+<!ENTITY % authorgroup.role.attrib "%role.attrib;">
+
+<!ENTITY % authorgroup.element "INCLUDE">
+<![ %authorgroup.element; [
+<!ELEMENT AuthorGroup - - ((Author|Editor|Collab|CorpAuthor|OtherCredit)+)>
+<!--end of authorgroup.element-->]]>
+
+<!ENTITY % authorgroup.attlist "INCLUDE">
+<![ %authorgroup.attlist; [
+<!ATTLIST AuthorGroup
+ %common.attrib;
+ %authorgroup.role.attrib;
+ %local.authorgroup.attrib;
+>
+<!--end of authorgroup.attlist-->]]>
+<!--end of authorgroup.module-->]]>
+
+ <!-- Author (defined elsewhere in this section)-->
+ <!-- Editor (defined elsewhere in this section)-->
+
+ <!ENTITY % collab.content.module "INCLUDE">
+ <![ %collab.content.module; [
+ <!ENTITY % collab.module "INCLUDE">
+ <![ %collab.module; [
+ <!ENTITY % local.collab.attrib "">
+ <!ENTITY % collab.role.attrib "%role.attrib;">
+
+<!ENTITY % collab.element "INCLUDE">
+<![ %collab.element; [
+<!ELEMENT Collab - - (CollabName, Affiliation*)>
+<!--end of collab.element-->]]>
+
+<!ENTITY % collab.attlist "INCLUDE">
+<![ %collab.attlist; [
+<!ATTLIST Collab
+ %common.attrib;
+ %collab.role.attrib;
+ %local.collab.attrib;
+>
+<!--end of collab.attlist-->]]>
+ <!--end of collab.module-->]]>
+
+ <!ENTITY % collabname.module "INCLUDE">
+ <![ %collabname.module; [
+ <!ENTITY % local.collabname.attrib "">
+ <!ENTITY % collabname.role.attrib "%role.attrib;">
+
+<!ENTITY % collabname.element "INCLUDE">
+<![ %collabname.element; [
+<!ELEMENT CollabName - - ((%docinfo.char.mix;)+)>
+<!--end of collabname.element-->]]>
+
+<!ENTITY % collabname.attlist "INCLUDE">
+<![ %collabname.attlist; [
+<!ATTLIST CollabName
+ %common.attrib;
+ %collabname.role.attrib;
+ %local.collabname.attrib;
+>
+<!--end of collabname.attlist-->]]>
+ <!--end of collabname.module-->]]>
+
+ <!-- Affiliation (defined elsewhere in this section)-->
+ <!--end of collab.content.module-->]]>
+
+ <!-- CorpAuthor (defined elsewhere in this section)-->
+ <!-- OtherCredit (defined elsewhere in this section)-->
+
+<!--end of authorgroup.content.module-->]]>
+
+<!-- AuthorInitials ................... -->
+
+<!ENTITY % authorinitials.module "INCLUDE">
+<![ %authorinitials.module; [
+<!ENTITY % local.authorinitials.attrib "">
+<!ENTITY % authorinitials.role.attrib "%role.attrib;">
+
+<!ENTITY % authorinitials.element "INCLUDE">
+<![ %authorinitials.element; [
+<!ELEMENT AuthorInitials - - ((%docinfo.char.mix;)+)>
+<!--end of authorinitials.element-->]]>
+
+<!ENTITY % authorinitials.attlist "INCLUDE">
+<![ %authorinitials.attlist; [
+<!ATTLIST AuthorInitials
+ %common.attrib;
+ %authorinitials.role.attrib;
+ %local.authorinitials.attrib;
+>
+<!--end of authorinitials.attlist-->]]>
+<!--end of authorinitials.module-->]]>
+
+<!-- ConfGroup ........................ -->
+
+<!ENTITY % confgroup.content.module "INCLUDE">
+<![ %confgroup.content.module; [
+<!ENTITY % confgroup.module "INCLUDE">
+<![ %confgroup.module; [
+<!ENTITY % local.confgroup.attrib "">
+<!ENTITY % confgroup.role.attrib "%role.attrib;">
+
+<!ENTITY % confgroup.element "INCLUDE">
+<![ %confgroup.element; [
+<!ELEMENT ConfGroup - - ((ConfDates|ConfTitle|ConfNum|Address|ConfSponsor)*)>
+<!--end of confgroup.element-->]]>
+
+<!ENTITY % confgroup.attlist "INCLUDE">
+<![ %confgroup.attlist; [
+<!ATTLIST ConfGroup
+ %common.attrib;
+ %confgroup.role.attrib;
+ %local.confgroup.attrib;
+>
+<!--end of confgroup.attlist-->]]>
+<!--end of confgroup.module-->]]>
+
+ <!ENTITY % confdates.module "INCLUDE">
+ <![ %confdates.module; [
+ <!ENTITY % local.confdates.attrib "">
+ <!ENTITY % confdates.role.attrib "%role.attrib;">
+
+<!ENTITY % confdates.element "INCLUDE">
+<![ %confdates.element; [
+<!ELEMENT ConfDates - - ((%docinfo.char.mix;)+)>
+<!--end of confdates.element-->]]>
+
+<!ENTITY % confdates.attlist "INCLUDE">
+<![ %confdates.attlist; [
+<!ATTLIST ConfDates
+ %common.attrib;
+ %confdates.role.attrib;
+ %local.confdates.attrib;
+>
+<!--end of confdates.attlist-->]]>
+ <!--end of confdates.module-->]]>
+
+ <!ENTITY % conftitle.module "INCLUDE">
+ <![ %conftitle.module; [
+ <!ENTITY % local.conftitle.attrib "">
+ <!ENTITY % conftitle.role.attrib "%role.attrib;">
+
+<!ENTITY % conftitle.element "INCLUDE">
+<![ %conftitle.element; [
+<!ELEMENT ConfTitle - - ((%docinfo.char.mix;)+)>
+<!--end of conftitle.element-->]]>
+
+<!ENTITY % conftitle.attlist "INCLUDE">
+<![ %conftitle.attlist; [
+<!ATTLIST ConfTitle
+ %common.attrib;
+ %conftitle.role.attrib;
+ %local.conftitle.attrib;
+>
+<!--end of conftitle.attlist-->]]>
+ <!--end of conftitle.module-->]]>
+
+ <!ENTITY % confnum.module "INCLUDE">
+ <![ %confnum.module; [
+ <!ENTITY % local.confnum.attrib "">
+ <!ENTITY % confnum.role.attrib "%role.attrib;">
+
+<!ENTITY % confnum.element "INCLUDE">
+<![ %confnum.element; [
+<!ELEMENT ConfNum - - ((%docinfo.char.mix;)+)>
+<!--end of confnum.element-->]]>
+
+<!ENTITY % confnum.attlist "INCLUDE">
+<![ %confnum.attlist; [
+<!ATTLIST ConfNum
+ %common.attrib;
+ %confnum.role.attrib;
+ %local.confnum.attrib;
+>
+<!--end of confnum.attlist-->]]>
+ <!--end of confnum.module-->]]>
+
+ <!-- Address (defined elsewhere in this section)-->
+
+ <!ENTITY % confsponsor.module "INCLUDE">
+ <![ %confsponsor.module; [
+ <!ENTITY % local.confsponsor.attrib "">
+ <!ENTITY % confsponsor.role.attrib "%role.attrib;">
+
+<!ENTITY % confsponsor.element "INCLUDE">
+<![ %confsponsor.element; [
+<!ELEMENT ConfSponsor - - ((%docinfo.char.mix;)+)>
+<!--end of confsponsor.element-->]]>
+
+<!ENTITY % confsponsor.attlist "INCLUDE">
+<![ %confsponsor.attlist; [
+<!ATTLIST ConfSponsor
+ %common.attrib;
+ %confsponsor.role.attrib;
+ %local.confsponsor.attrib;
+>
+<!--end of confsponsor.attlist-->]]>
+ <!--end of confsponsor.module-->]]>
+<!--end of confgroup.content.module-->]]>
+
+<!-- ContractNum ...................... -->
+
+<!ENTITY % contractnum.module "INCLUDE">
+<![ %contractnum.module; [
+<!ENTITY % local.contractnum.attrib "">
+<!ENTITY % contractnum.role.attrib "%role.attrib;">
+
+<!ENTITY % contractnum.element "INCLUDE">
+<![ %contractnum.element; [
+<!ELEMENT ContractNum - - ((%docinfo.char.mix;)+)>
+<!--end of contractnum.element-->]]>
+
+<!ENTITY % contractnum.attlist "INCLUDE">
+<![ %contractnum.attlist; [
+<!ATTLIST ContractNum
+ %common.attrib;
+ %contractnum.role.attrib;
+ %local.contractnum.attrib;
+>
+<!--end of contractnum.attlist-->]]>
+<!--end of contractnum.module-->]]>
+
+<!-- ContractSponsor .................. -->
+
+<!ENTITY % contractsponsor.module "INCLUDE">
+<![ %contractsponsor.module; [
+<!ENTITY % local.contractsponsor.attrib "">
+<!ENTITY % contractsponsor.role.attrib "%role.attrib;">
+
+<!ENTITY % contractsponsor.element "INCLUDE">
+<![ %contractsponsor.element; [
+<!ELEMENT ContractSponsor - - ((%docinfo.char.mix;)+)>
+<!--end of contractsponsor.element-->]]>
+
+<!ENTITY % contractsponsor.attlist "INCLUDE">
+<![ %contractsponsor.attlist; [
+<!ATTLIST ContractSponsor
+ %common.attrib;
+ %contractsponsor.role.attrib;
+ %local.contractsponsor.attrib;
+>
+<!--end of contractsponsor.attlist-->]]>
+<!--end of contractsponsor.module-->]]>
+
+<!-- Copyright ........................ -->
+
+<!ENTITY % copyright.content.module "INCLUDE">
+<![ %copyright.content.module; [
+<!ENTITY % copyright.module "INCLUDE">
+<![ %copyright.module; [
+<!ENTITY % local.copyright.attrib "">
+<!ENTITY % copyright.role.attrib "%role.attrib;">
+
+<!ENTITY % copyright.element "INCLUDE">
+<![ %copyright.element; [
+<!ELEMENT Copyright - - (Year+, Holder*)>
+<!--end of copyright.element-->]]>
+
+<!ENTITY % copyright.attlist "INCLUDE">
+<![ %copyright.attlist; [
+<!ATTLIST Copyright
+ %common.attrib;
+ %copyright.role.attrib;
+ %local.copyright.attrib;
+>
+<!--end of copyright.attlist-->]]>
+<!--end of copyright.module-->]]>
+
+ <!ENTITY % year.module "INCLUDE">
+ <![ %year.module; [
+ <!ENTITY % local.year.attrib "">
+ <!ENTITY % year.role.attrib "%role.attrib;">
+
+<!ENTITY % year.element "INCLUDE">
+<![ %year.element; [
+<!ELEMENT Year - - ((%docinfo.char.mix;)+)>
+<!--end of year.element-->]]>
+
+<!ENTITY % year.attlist "INCLUDE">
+<![ %year.attlist; [
+<!ATTLIST Year
+ %common.attrib;
+ %year.role.attrib;
+ %local.year.attrib;
+>
+<!--end of year.attlist-->]]>
+ <!--end of year.module-->]]>
+
+ <!ENTITY % holder.module "INCLUDE">
+ <![ %holder.module; [
+ <!ENTITY % local.holder.attrib "">
+ <!ENTITY % holder.role.attrib "%role.attrib;">
+
+<!ENTITY % holder.element "INCLUDE">
+<![ %holder.element; [
+<!ELEMENT Holder - - ((%docinfo.char.mix;)+)>
+<!--end of holder.element-->]]>
+
+<!ENTITY % holder.attlist "INCLUDE">
+<![ %holder.attlist; [
+<!ATTLIST Holder
+ %common.attrib;
+ %holder.role.attrib;
+ %local.holder.attrib;
+>
+<!--end of holder.attlist-->]]>
+ <!--end of holder.module-->]]>
+<!--end of copyright.content.module-->]]>
+
+<!-- CorpAuthor ....................... -->
+
+<!ENTITY % corpauthor.module "INCLUDE">
+<![ %corpauthor.module; [
+<!ENTITY % local.corpauthor.attrib "">
+<!ENTITY % corpauthor.role.attrib "%role.attrib;">
+
+<!ENTITY % corpauthor.element "INCLUDE">
+<![ %corpauthor.element; [
+<!ELEMENT CorpAuthor - - ((%docinfo.char.mix;)+)>
+<!--end of corpauthor.element-->]]>
+
+<!ENTITY % corpauthor.attlist "INCLUDE">
+<![ %corpauthor.attlist; [
+<!ATTLIST CorpAuthor
+ %common.attrib;
+ %corpauthor.role.attrib;
+ %local.corpauthor.attrib;
+>
+<!--end of corpauthor.attlist-->]]>
+<!--end of corpauthor.module-->]]>
+
+<!-- CorpName ......................... -->
+
+<!ENTITY % corpname.module "INCLUDE">
+<![ %corpname.module; [
+<!ENTITY % local.corpname.attrib "">
+
+<!ENTITY % corpname.element "INCLUDE">
+<![ %corpname.element; [
+<!ELEMENT CorpName - - ((%docinfo.char.mix;)+)>
+<!--end of corpname.element-->]]>
+<!ENTITY % corpname.role.attrib "%role.attrib;">
+
+<!ENTITY % corpname.attlist "INCLUDE">
+<![ %corpname.attlist; [
+<!ATTLIST CorpName
+ %common.attrib;
+ %corpname.role.attrib;
+ %local.corpname.attrib;
+>
+<!--end of corpname.attlist-->]]>
+<!--end of corpname.module-->]]>
+
+<!-- Date ............................. -->
+
+<!ENTITY % date.module "INCLUDE">
+<![ %date.module; [
+<!ENTITY % local.date.attrib "">
+<!ENTITY % date.role.attrib "%role.attrib;">
+
+<!ENTITY % date.element "INCLUDE">
+<![ %date.element; [
+<!ELEMENT Date - - ((%docinfo.char.mix;)+)>
+<!--end of date.element-->]]>
+
+<!ENTITY % date.attlist "INCLUDE">
+<![ %date.attlist; [
+<!ATTLIST Date
+ %common.attrib;
+ %date.role.attrib;
+ %local.date.attrib;
+>
+<!--end of date.attlist-->]]>
+<!--end of date.module-->]]>
+
+<!-- Edition .......................... -->
+
+<!ENTITY % edition.module "INCLUDE">
+<![ %edition.module; [
+<!ENTITY % local.edition.attrib "">
+<!ENTITY % edition.role.attrib "%role.attrib;">
+
+<!ENTITY % edition.element "INCLUDE">
+<![ %edition.element; [
+<!ELEMENT Edition - - ((%docinfo.char.mix;)+)>
+<!--end of edition.element-->]]>
+
+<!ENTITY % edition.attlist "INCLUDE">
+<![ %edition.attlist; [
+<!ATTLIST Edition
+ %common.attrib;
+ %edition.role.attrib;
+ %local.edition.attrib;
+>
+<!--end of edition.attlist-->]]>
+<!--end of edition.module-->]]>
+
+<!-- Editor ........................... -->
+
+<!ENTITY % editor.module "INCLUDE">
+<![ %editor.module; [
+<!ENTITY % local.editor.attrib "">
+<!ENTITY % editor.role.attrib "%role.attrib;">
+
+<!ENTITY % editor.element "INCLUDE">
+<![ %editor.element; [
+<!ELEMENT Editor - - ((%person.ident.mix;)+)>
+<!--end of editor.element-->]]>
+
+<!ENTITY % editor.attlist "INCLUDE">
+<![ %editor.attlist; [
+<!ATTLIST Editor
+ %common.attrib;
+ %editor.role.attrib;
+ %local.editor.attrib;
+>
+<!--end of editor.attlist-->]]>
+ <!--(see "Personal identity elements" for %person.ident.mix;)-->
+<!--end of editor.module-->]]>
+
+<!-- ISBN ............................. -->
+
+<!ENTITY % isbn.module "INCLUDE">
+<![ %isbn.module; [
+<!ENTITY % local.isbn.attrib "">
+<!ENTITY % isbn.role.attrib "%role.attrib;">
+
+<!ENTITY % isbn.element "INCLUDE">
+<![ %isbn.element; [
+<!ELEMENT ISBN - - ((%docinfo.char.mix;)+)>
+<!--end of isbn.element-->]]>
+
+<!ENTITY % isbn.attlist "INCLUDE">
+<![ %isbn.attlist; [
+<!ATTLIST ISBN
+ %common.attrib;
+ %isbn.role.attrib;
+ %local.isbn.attrib;
+>
+<!--end of isbn.attlist-->]]>
+<!--end of isbn.module-->]]>
+
+<!-- ISSN ............................. -->
+
+<!ENTITY % issn.module "INCLUDE">
+<![ %issn.module; [
+<!ENTITY % local.issn.attrib "">
+<!ENTITY % issn.role.attrib "%role.attrib;">
+
+<!ENTITY % issn.element "INCLUDE">
+<![ %issn.element; [
+<!ELEMENT ISSN - - ((%docinfo.char.mix;)+)>
+<!--end of issn.element-->]]>
+
+<!ENTITY % issn.attlist "INCLUDE">
+<![ %issn.attlist; [
+<!ATTLIST ISSN
+ %common.attrib;
+ %issn.role.attrib;
+ %local.issn.attrib;
+>
+<!--end of issn.attlist-->]]>
+<!--end of issn.module-->]]>
+
+<!-- InvPartNumber .................... -->
+
+<!ENTITY % invpartnumber.module "INCLUDE">
+<![ %invpartnumber.module; [
+<!ENTITY % local.invpartnumber.attrib "">
+<!ENTITY % invpartnumber.role.attrib "%role.attrib;">
+
+<!ENTITY % invpartnumber.element "INCLUDE">
+<![ %invpartnumber.element; [
+<!ELEMENT InvPartNumber - - ((%docinfo.char.mix;)+)>
+<!--end of invpartnumber.element-->]]>
+
+<!ENTITY % invpartnumber.attlist "INCLUDE">
+<![ %invpartnumber.attlist; [
+<!ATTLIST InvPartNumber
+ %common.attrib;
+ %invpartnumber.role.attrib;
+ %local.invpartnumber.attrib;
+>
+<!--end of invpartnumber.attlist-->]]>
+<!--end of invpartnumber.module-->]]>
+
+<!-- IssueNum ......................... -->
+
+<!ENTITY % issuenum.module "INCLUDE">
+<![ %issuenum.module; [
+<!ENTITY % local.issuenum.attrib "">
+<!ENTITY % issuenum.role.attrib "%role.attrib;">
+
+<!ENTITY % issuenum.element "INCLUDE">
+<![ %issuenum.element; [
+<!ELEMENT IssueNum - - ((%docinfo.char.mix;)+)>
+<!--end of issuenum.element-->]]>
+
+<!ENTITY % issuenum.attlist "INCLUDE">
+<![ %issuenum.attlist; [
+<!ATTLIST IssueNum
+ %common.attrib;
+ %issuenum.role.attrib;
+ %local.issuenum.attrib;
+>
+<!--end of issuenum.attlist-->]]>
+<!--end of issuenum.module-->]]>
+
+<!-- LegalNotice ...................... -->
+
+<!ENTITY % legalnotice.module "INCLUDE">
+<![ %legalnotice.module; [
+<!ENTITY % local.legalnotice.attrib "">
+<!ENTITY % legalnotice.role.attrib "%role.attrib;">
+
+<!ENTITY % legalnotice.element "INCLUDE">
+<![ %legalnotice.element; [
+<!ELEMENT LegalNotice - - (Title?, (%legalnotice.mix;)+) %formal.exclusion;>
+<!--end of legalnotice.element-->]]>
+
+<!ENTITY % legalnotice.attlist "INCLUDE">
+<![ %legalnotice.attlist; [
+<!ATTLIST LegalNotice
+ %common.attrib;
+ %legalnotice.role.attrib;
+ %local.legalnotice.attrib;
+>
+<!--end of legalnotice.attlist-->]]>
+<!--end of legalnotice.module-->]]>
+
+<!-- ModeSpec ......................... -->
+
+<!ENTITY % modespec.module "INCLUDE">
+<![ %modespec.module; [
+<!ENTITY % local.modespec.attrib "">
+<!ENTITY % modespec.role.attrib "%role.attrib;">
+
+<!ENTITY % modespec.element "INCLUDE">
+<![ %modespec.element; [
+<!ELEMENT ModeSpec - - ((%docinfo.char.mix;)+) %ubiq.exclusion;>
+<!--end of modespec.element-->]]>
+
+<!ENTITY % modespec.attlist "INCLUDE">
+<![ %modespec.attlist; [
+<!ATTLIST ModeSpec
+ --
+ Application: Type of action required for completion
+ of the links to which the ModeSpec is relevant (e.g.,
+ retrieval query)
+ --
+ Application NOTATION
+ (%notation.class;) #IMPLIED
+ %common.attrib;
+ %modespec.role.attrib;
+ %local.modespec.attrib;
+>
+<!--end of modespec.attlist-->]]>
+<!--end of modespec.module-->]]>
+
+<!-- OrgName .......................... -->
+
+<!ENTITY % orgname.module "INCLUDE">
+<![ %orgname.module; [
+<!ENTITY % local.orgname.attrib "">
+<!ENTITY % orgname.role.attrib "%role.attrib;">
+
+<!ENTITY % orgname.element "INCLUDE">
+<![ %orgname.element; [
+<!ELEMENT OrgName - - ((%docinfo.char.mix;)+)>
+<!--end of orgname.element-->]]>
+
+<!ENTITY % orgname.attlist "INCLUDE">
+<![ %orgname.attlist; [
+<!ATTLIST OrgName
+ %common.attrib;
+ %orgname.role.attrib;
+ %local.orgname.attrib;
+>
+<!--end of orgname.attlist-->]]>
+<!--end of orgname.module-->]]>
+
+<!-- OtherCredit ...................... -->
+
+<!ENTITY % othercredit.module "INCLUDE">
+<![ %othercredit.module; [
+<!ENTITY % local.othercredit.attrib "">
+<!ENTITY % othercredit.role.attrib "%role.attrib;">
+
+<!ENTITY % othercredit.element "INCLUDE">
+<![ %othercredit.element; [
+<!ELEMENT OtherCredit - - ((%person.ident.mix;)+)>
+<!--end of othercredit.element-->]]>
+
+<!ENTITY % othercredit.attlist "INCLUDE">
+<![ %othercredit.attlist; [
+<!ATTLIST OtherCredit
+ %common.attrib;
+ %othercredit.role.attrib;
+ %local.othercredit.attrib;
+>
+<!--end of othercredit.attlist-->]]>
+ <!--(see "Personal identity elements" for %person.ident.mix;)-->
+<!--end of othercredit.module-->]]>
+
+<!-- PageNums ......................... -->
+
+<!ENTITY % pagenums.module "INCLUDE">
+<![ %pagenums.module; [
+<!ENTITY % local.pagenums.attrib "">
+<!ENTITY % pagenums.role.attrib "%role.attrib;">
+
+<!ENTITY % pagenums.element "INCLUDE">
+<![ %pagenums.element; [
+<!ELEMENT PageNums - - ((%docinfo.char.mix;)+)>
+<!--end of pagenums.element-->]]>
+
+<!ENTITY % pagenums.attlist "INCLUDE">
+<![ %pagenums.attlist; [
+<!ATTLIST PageNums
+ %common.attrib;
+ %pagenums.role.attrib;
+ %local.pagenums.attrib;
+>
+<!--end of pagenums.attlist-->]]>
+<!--end of pagenums.module-->]]>
+
+<!-- Personal identity elements ....... -->
+
+<!-- These elements are used only within Author, Editor, and
+OtherCredit. -->
+
+<!ENTITY % person.ident.module "INCLUDE">
+<![ %person.ident.module; [
+ <!ENTITY % contrib.module "INCLUDE">
+ <![ %contrib.module; [
+ <!ENTITY % local.contrib.attrib "">
+ <!ENTITY % contrib.role.attrib "%role.attrib;">
+
+<!ENTITY % contrib.element "INCLUDE">
+<![ %contrib.element; [
+<!ELEMENT Contrib - - ((%docinfo.char.mix;)+)>
+<!--end of contrib.element-->]]>
+
+<!ENTITY % contrib.attlist "INCLUDE">
+<![ %contrib.attlist; [
+<!ATTLIST Contrib
+ %common.attrib;
+ %contrib.role.attrib;
+ %local.contrib.attrib;
+>
+<!--end of contrib.attlist-->]]>
+ <!--end of contrib.module-->]]>
+
+ <!ENTITY % firstname.module "INCLUDE">
+ <![ %firstname.module; [
+ <!ENTITY % local.firstname.attrib "">
+ <!ENTITY % firstname.role.attrib "%role.attrib;">
+
+<!ENTITY % firstname.element "INCLUDE">
+<![ %firstname.element; [
+<!ELEMENT FirstName - - ((%docinfo.char.mix;)+)>
+<!--end of firstname.element-->]]>
+
+<!ENTITY % firstname.attlist "INCLUDE">
+<![ %firstname.attlist; [
+<!ATTLIST FirstName
+ %common.attrib;
+ %firstname.role.attrib;
+ %local.firstname.attrib;
+>
+<!--end of firstname.attlist-->]]>
+ <!--end of firstname.module-->]]>
+
+ <!ENTITY % honorific.module "INCLUDE">
+ <![ %honorific.module; [
+ <!ENTITY % local.honorific.attrib "">
+ <!ENTITY % honorific.role.attrib "%role.attrib;">
+
+<!ENTITY % honorific.element "INCLUDE">
+<![ %honorific.element; [
+<!ELEMENT Honorific - - ((%docinfo.char.mix;)+)>
+<!--end of honorific.element-->]]>
+
+<!ENTITY % honorific.attlist "INCLUDE">
+<![ %honorific.attlist; [
+<!ATTLIST Honorific
+ %common.attrib;
+ %honorific.role.attrib;
+ %local.honorific.attrib;
+>
+<!--end of honorific.attlist-->]]>
+ <!--end of honorific.module-->]]>
+
+ <!ENTITY % lineage.module "INCLUDE">
+ <![ %lineage.module; [
+ <!ENTITY % local.lineage.attrib "">
+ <!ENTITY % lineage.role.attrib "%role.attrib;">
+
+<!ENTITY % lineage.element "INCLUDE">
+<![ %lineage.element; [
+<!ELEMENT Lineage - - ((%docinfo.char.mix;)+)>
+<!--end of lineage.element-->]]>
+
+<!ENTITY % lineage.attlist "INCLUDE">
+<![ %lineage.attlist; [
+<!ATTLIST Lineage
+ %common.attrib;
+ %lineage.role.attrib;
+ %local.lineage.attrib;
+>
+<!--end of lineage.attlist-->]]>
+ <!--end of lineage.module-->]]>
+
+ <!ENTITY % othername.module "INCLUDE">
+ <![ %othername.module; [
+ <!ENTITY % local.othername.attrib "">
+ <!ENTITY % othername.role.attrib "%role.attrib;">
+
+<!ENTITY % othername.element "INCLUDE">
+<![ %othername.element; [
+<!ELEMENT OtherName - - ((%docinfo.char.mix;)+)>
+<!--end of othername.element-->]]>
+
+<!ENTITY % othername.attlist "INCLUDE">
+<![ %othername.attlist; [
+<!ATTLIST OtherName
+ %common.attrib;
+ %othername.role.attrib;
+ %local.othername.attrib;
+>
+<!--end of othername.attlist-->]]>
+ <!--end of othername.module-->]]>
+
+ <!ENTITY % surname.module "INCLUDE">
+ <![ %surname.module; [
+ <!ENTITY % local.surname.attrib "">
+ <!ENTITY % surname.role.attrib "%role.attrib;">
+
+<!ENTITY % surname.element "INCLUDE">
+<![ %surname.element; [
+<!ELEMENT Surname - - ((%docinfo.char.mix;)+)>
+<!--end of surname.element-->]]>
+
+<!ENTITY % surname.attlist "INCLUDE">
+<![ %surname.attlist; [
+<!ATTLIST Surname
+ %common.attrib;
+ %surname.role.attrib;
+ %local.surname.attrib;
+>
+<!--end of surname.attlist-->]]>
+ <!--end of surname.module-->]]>
+<!--end of person.ident.module-->]]>
+
+<!-- PrintHistory ..................... -->
+
+<!ENTITY % printhistory.module "INCLUDE">
+<![ %printhistory.module; [
+<!ENTITY % local.printhistory.attrib "">
+<!ENTITY % printhistory.role.attrib "%role.attrib;">
+
+<!ENTITY % printhistory.element "INCLUDE">
+<![ %printhistory.element; [
+<!ELEMENT PrintHistory - - ((%para.class;)+)>
+<!--end of printhistory.element-->]]>
+
+<!ENTITY % printhistory.attlist "INCLUDE">
+<![ %printhistory.attlist; [
+<!ATTLIST PrintHistory
+ %common.attrib;
+ %printhistory.role.attrib;
+ %local.printhistory.attrib;
+>
+<!--end of printhistory.attlist-->]]>
+<!--end of printhistory.module-->]]>
+
+<!-- ProductName ...................... -->
+
+<!ENTITY % productname.module "INCLUDE">
+<![ %productname.module; [
+<!ENTITY % local.productname.attrib "">
+<!ENTITY % productname.role.attrib "%role.attrib;">
+
+<!ENTITY % productname.element "INCLUDE">
+<![ %productname.element; [
+<!ELEMENT ProductName - - ((%para.char.mix;)+)>
+<!--end of productname.element-->]]>
+
+<!ENTITY % productname.attlist "INCLUDE">
+<![ %productname.attlist; [
+<!ATTLIST ProductName
+ --
+ Class: More precisely identifies the item the element names
+ --
+ Class (Service
+ |Trade
+ |Registered
+ |Copyright) Trade
+ %common.attrib;
+ %productname.role.attrib;
+ %local.productname.attrib;
+>
+<!--end of productname.attlist-->]]>
+<!--end of productname.module-->]]>
+
+<!-- ProductNumber .................... -->
+
+<!ENTITY % productnumber.module "INCLUDE">
+<![ %productnumber.module; [
+<!ENTITY % local.productnumber.attrib "">
+<!ENTITY % productnumber.role.attrib "%role.attrib;">
+
+<!ENTITY % productnumber.element "INCLUDE">
+<![ %productnumber.element; [
+<!ELEMENT ProductNumber - - ((%docinfo.char.mix;)+)>
+<!--end of productnumber.element-->]]>
+
+<!ENTITY % productnumber.attlist "INCLUDE">
+<![ %productnumber.attlist; [
+<!ATTLIST ProductNumber
+ %common.attrib;
+ %productnumber.role.attrib;
+ %local.productnumber.attrib;
+>
+<!--end of productnumber.attlist-->]]>
+<!--end of productnumber.module-->]]>
+
+<!-- PubDate .......................... -->
+
+<!ENTITY % pubdate.module "INCLUDE">
+<![ %pubdate.module; [
+<!ENTITY % local.pubdate.attrib "">
+<!ENTITY % pubdate.role.attrib "%role.attrib;">
+
+<!ENTITY % pubdate.element "INCLUDE">
+<![ %pubdate.element; [
+<!ELEMENT PubDate - - ((%docinfo.char.mix;)+)>
+<!--end of pubdate.element-->]]>
+
+<!ENTITY % pubdate.attlist "INCLUDE">
+<![ %pubdate.attlist; [
+<!ATTLIST PubDate
+ %common.attrib;
+ %pubdate.role.attrib;
+ %local.pubdate.attrib;
+>
+<!--end of pubdate.attlist-->]]>
+<!--end of pubdate.module-->]]>
+
+<!-- Publisher ........................ -->
+
+<!ENTITY % publisher.content.module "INCLUDE">
+<![ %publisher.content.module; [
+<!ENTITY % publisher.module "INCLUDE">
+<![ %publisher.module; [
+<!ENTITY % local.publisher.attrib "">
+<!ENTITY % publisher.role.attrib "%role.attrib;">
+
+<!ENTITY % publisher.element "INCLUDE">
+<![ %publisher.element; [
+<!ELEMENT Publisher - - (PublisherName, Address*)>
+<!--end of publisher.element-->]]>
+
+<!ENTITY % publisher.attlist "INCLUDE">
+<![ %publisher.attlist; [
+<!ATTLIST Publisher
+ %common.attrib;
+ %publisher.role.attrib;
+ %local.publisher.attrib;
+>
+<!--end of publisher.attlist-->]]>
+<!--end of publisher.module-->]]>
+
+ <!ENTITY % publishername.module "INCLUDE">
+ <![ %publishername.module; [
+ <!ENTITY % local.publishername.attrib "">
+ <!ENTITY % publishername.role.attrib "%role.attrib;">
+
+<!ENTITY % publishername.element "INCLUDE">
+<![ %publishername.element; [
+<!ELEMENT PublisherName - - ((%docinfo.char.mix;)+)>
+<!--end of publishername.element-->]]>
+
+<!ENTITY % publishername.attlist "INCLUDE">
+<![ %publishername.attlist; [
+<!ATTLIST PublisherName
+ %common.attrib;
+ %publishername.role.attrib;
+ %local.publishername.attrib;
+>
+<!--end of publishername.attlist-->]]>
+ <!--end of publishername.module-->]]>
+
+ <!-- Address (defined elsewhere in this section)-->
+<!--end of publisher.content.module-->]]>
+
+<!-- PubsNumber ....................... -->
+
+<!ENTITY % pubsnumber.module "INCLUDE">
+<![ %pubsnumber.module; [
+<!ENTITY % local.pubsnumber.attrib "">
+<!ENTITY % pubsnumber.role.attrib "%role.attrib;">
+
+<!ENTITY % pubsnumber.element "INCLUDE">
+<![ %pubsnumber.element; [
+<!ELEMENT PubsNumber - - ((%docinfo.char.mix;)+)>
+<!--end of pubsnumber.element-->]]>
+
+<!ENTITY % pubsnumber.attlist "INCLUDE">
+<![ %pubsnumber.attlist; [
+<!ATTLIST PubsNumber
+ %common.attrib;
+ %pubsnumber.role.attrib;
+ %local.pubsnumber.attrib;
+>
+<!--end of pubsnumber.attlist-->]]>
+<!--end of pubsnumber.module-->]]>
+
+<!-- ReleaseInfo ...................... -->
+
+<!ENTITY % releaseinfo.module "INCLUDE">
+<![ %releaseinfo.module; [
+<!ENTITY % local.releaseinfo.attrib "">
+<!ENTITY % releaseinfo.role.attrib "%role.attrib;">
+
+<!ENTITY % releaseinfo.element "INCLUDE">
+<![ %releaseinfo.element; [
+<!ELEMENT ReleaseInfo - - ((%docinfo.char.mix;)+)>
+<!--end of releaseinfo.element-->]]>
+
+<!ENTITY % releaseinfo.attlist "INCLUDE">
+<![ %releaseinfo.attlist; [
+<!ATTLIST ReleaseInfo
+ %common.attrib;
+ %releaseinfo.role.attrib;
+ %local.releaseinfo.attrib;
+>
+<!--end of releaseinfo.attlist-->]]>
+<!--end of releaseinfo.module-->]]>
+
+<!-- RevHistory ....................... -->
+
+<!ENTITY % revhistory.content.module "INCLUDE">
+<![ %revhistory.content.module; [
+<!ENTITY % revhistory.module "INCLUDE">
+<![ %revhistory.module; [
+<!ENTITY % local.revhistory.attrib "">
+<!ENTITY % revhistory.role.attrib "%role.attrib;">
+
+<!ENTITY % revhistory.element "INCLUDE">
+<![ %revhistory.element; [
+<!ELEMENT RevHistory - - (Revision+)>
+<!--end of revhistory.element-->]]>
+
+<!ENTITY % revhistory.attlist "INCLUDE">
+<![ %revhistory.attlist; [
+<!ATTLIST RevHistory
+ %common.attrib;
+ %revhistory.role.attrib;
+ %local.revhistory.attrib;
+>
+<!--end of revhistory.attlist-->]]>
+<!--end of revhistory.module-->]]>
+
+ <!ENTITY % revision.module "INCLUDE">
+ <![ %revision.module; [
+ <!ENTITY % local.revision.attrib "">
+ <!ENTITY % revision.role.attrib "%role.attrib;">
+
+<!ENTITY % revision.element "INCLUDE">
+<![ %revision.element; [
+<!ELEMENT Revision - - (RevNumber, Date, AuthorInitials*, (RevRemark|RevDescription)?)>
+<!--end of revision.element-->]]>
+
+<!ENTITY % revision.attlist "INCLUDE">
+<![ %revision.attlist; [
+<!ATTLIST Revision
+ %common.attrib;
+ %revision.role.attrib;
+ %local.revision.attrib;
+>
+<!--end of revision.attlist-->]]>
+ <!--end of revision.module-->]]>
+
+ <!ENTITY % revnumber.module "INCLUDE">
+ <![ %revnumber.module; [
+ <!ENTITY % local.revnumber.attrib "">
+ <!ENTITY % revnumber.role.attrib "%role.attrib;">
+
+<!ENTITY % revnumber.element "INCLUDE">
+<![ %revnumber.element; [
+<!ELEMENT RevNumber - - ((%docinfo.char.mix;)+)>
+<!--end of revnumber.element-->]]>
+
+<!ENTITY % revnumber.attlist "INCLUDE">
+<![ %revnumber.attlist; [
+<!ATTLIST RevNumber
+ %common.attrib;
+ %revnumber.role.attrib;
+ %local.revnumber.attrib;
+>
+<!--end of revnumber.attlist-->]]>
+<!--end of revnumber.module-->]]>
+
+<!-- Date (defined elsewhere in this section)-->
+<!-- AuthorInitials (defined elsewhere in this section)-->
+
+<!ENTITY % revremark.module "INCLUDE">
+<![ %revremark.module; [
+<!ENTITY % local.revremark.attrib "">
+<!ENTITY % revremark.role.attrib "%role.attrib;">
+
+<!ENTITY % revremark.element "INCLUDE">
+<![ %revremark.element; [
+<!ELEMENT RevRemark - - ((%docinfo.char.mix;)+)>
+<!--end of revremark.element-->]]>
+
+<!ENTITY % revremark.attlist "INCLUDE">
+<![ %revremark.attlist; [
+<!ATTLIST RevRemark
+ %common.attrib;
+ %revremark.role.attrib;
+ %local.revremark.attrib;
+>
+<!--end of revremark.attlist-->]]>
+<!--end of revremark.module-->]]>
+
+<!ENTITY % revdescription.module "INCLUDE">
+<![ %revdescription.module; [
+<!ENTITY % local.revdescription.attrib "">
+<!ENTITY % revdescription.role.attrib "%role.attrib;">
+
+<!ENTITY % revdescription.element "INCLUDE">
+<![ %revdescription.element; [
+<!ELEMENT RevDescription - - ((%revdescription.mix;)+)>
+<!--end of revdescription.element-->]]>
+
+<!ENTITY % revdescription.attlist "INCLUDE">
+<![ %revdescription.attlist; [
+<!ATTLIST RevDescription
+ %common.attrib;
+ %revdescription.role.attrib;
+ %local.revdescription.attrib;
+>
+<!--end of revdescription.attlist-->]]>
+<!--end of revdescription.module-->]]>
+<!--end of revhistory.content.module-->]]>
+
+<!-- SeriesVolNums .................... -->
+
+<!ENTITY % seriesvolnums.module "INCLUDE">
+<![ %seriesvolnums.module; [
+<!ENTITY % local.seriesvolnums.attrib "">
+<!ENTITY % seriesvolnums.role.attrib "%role.attrib;">
+
+<!ENTITY % seriesvolnums.element "INCLUDE">
+<![ %seriesvolnums.element; [
+<!ELEMENT SeriesVolNums - - ((%docinfo.char.mix;)+)>
+<!--end of seriesvolnums.element-->]]>
+
+<!ENTITY % seriesvolnums.attlist "INCLUDE">
+<![ %seriesvolnums.attlist; [
+<!ATTLIST SeriesVolNums
+ %common.attrib;
+ %seriesvolnums.role.attrib;
+ %local.seriesvolnums.attrib;
+>
+<!--end of seriesvolnums.attlist-->]]>
+<!--end of seriesvolnums.module-->]]>
+
+<!-- VolumeNum ........................ -->
+
+<!ENTITY % volumenum.module "INCLUDE">
+<![ %volumenum.module; [
+<!ENTITY % local.volumenum.attrib "">
+<!ENTITY % volumenum.role.attrib "%role.attrib;">
+
+<!ENTITY % volumenum.element "INCLUDE">
+<![ %volumenum.element; [
+<!ELEMENT VolumeNum - - ((%docinfo.char.mix;)+)>
+<!--end of volumenum.element-->]]>
+
+<!ENTITY % volumenum.attlist "INCLUDE">
+<![ %volumenum.attlist; [
+<!ATTLIST VolumeNum
+ %common.attrib;
+ %volumenum.role.attrib;
+ %local.volumenum.attrib;
+>
+<!--end of volumenum.attlist-->]]>
+<!--end of volumenum.module-->]]>
+
+<!-- .................................. -->
+
+<!--end of docinfo.content.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Inline, link, and ubiquitous elements ................................ -->
+
+<!-- Technical and computer terms ......................................... -->
+
+<!ENTITY % accel.module "INCLUDE">
+<![ %accel.module; [
+<!ENTITY % local.accel.attrib "">
+<!ENTITY % accel.role.attrib "%role.attrib;">
+
+<!ENTITY % accel.element "INCLUDE">
+<![ %accel.element; [
+<!ELEMENT Accel - - ((%smallcptr.char.mix;)+)>
+<!--end of accel.element-->]]>
+
+<!ENTITY % accel.attlist "INCLUDE">
+<![ %accel.attlist; [
+<!ATTLIST Accel
+ %common.attrib;
+ %accel.role.attrib;
+ %local.accel.attrib;
+>
+<!--end of accel.attlist-->]]>
+<!--end of accel.module-->]]>
+
+<!ENTITY % action.module "INCLUDE">
+<![ %action.module; [
+<!ENTITY % local.action.attrib "">
+<!ENTITY % action.role.attrib "%role.attrib;">
+
+<!ENTITY % action.element "INCLUDE">
+<![ %action.element; [
+<!ELEMENT Action - - ((%smallcptr.char.mix;)+)>
+<!--end of action.element-->]]>
+
+<!ENTITY % action.attlist "INCLUDE">
+<![ %action.attlist; [
+<!ATTLIST Action
+ %moreinfo.attrib;
+ %common.attrib;
+ %action.role.attrib;
+ %local.action.attrib;
+>
+<!--end of action.attlist-->]]>
+<!--end of action.module-->]]>
+
+<!ENTITY % application.module "INCLUDE">
+<![ %application.module; [
+<!ENTITY % local.application.attrib "">
+<!ENTITY % application.role.attrib "%role.attrib;">
+
+<!ENTITY % application.element "INCLUDE">
+<![ %application.element; [
+<!ELEMENT Application - - ((%para.char.mix;)+)>
+<!--end of application.element-->]]>
+
+<!ENTITY % application.attlist "INCLUDE">
+<![ %application.attlist; [
+<!ATTLIST Application
+ Class (Hardware
+ |Software) #IMPLIED
+ %moreinfo.attrib;
+ %common.attrib;
+ %application.role.attrib;
+ %local.application.attrib;
+>
+<!--end of application.attlist-->]]>
+<!--end of application.module-->]]>
+
+<!ENTITY % classname.module "INCLUDE">
+<![ %classname.module; [
+<!ENTITY % local.classname.attrib "">
+<!ENTITY % classname.role.attrib "%role.attrib;">
+
+<!ENTITY % classname.element "INCLUDE">
+<![ %classname.element; [
+<!ELEMENT ClassName - - ((%smallcptr.char.mix;)+)>
+<!--end of classname.element-->]]>
+
+<!ENTITY % classname.attlist "INCLUDE">
+<![ %classname.attlist; [
+<!ATTLIST ClassName
+ %common.attrib;
+ %classname.role.attrib;
+ %local.classname.attrib;
+>
+<!--end of classname.attlist-->]]>
+<!--end of classname.module-->]]>
+
+<!ENTITY % co.module "INCLUDE">
+<![ %co.module; [
+<!ENTITY % local.co.attrib "">
+<!-- CO is a callout area of the LineColumn unit type (a single character
+ position); the position is directly indicated by the location of CO. -->
+<!ENTITY % co.role.attrib "%role.attrib;">
+
+<!ENTITY % co.element "INCLUDE">
+<![ %co.element; [
+<!ELEMENT CO - O EMPTY>
+<!--end of co.element-->]]>
+
+<!ENTITY % co.attlist "INCLUDE">
+<![ %co.attlist; [
+<!ATTLIST CO
+ %label.attrib; --bug number/symbol override or initialization--
+ %linkends.attrib; --to any related information--
+ %idreq.common.attrib;
+ %co.role.attrib;
+ %local.co.attrib;
+>
+<!--end of co.attlist-->]]>
+<!--end of co.module-->]]>
+
+<!ENTITY % command.module "INCLUDE">
+<![ %command.module; [
+<!ENTITY % local.command.attrib "">
+<!ENTITY % command.role.attrib "%role.attrib;">
+
+<!ENTITY % command.element "INCLUDE">
+<![ %command.element; [
+<!ELEMENT Command - - ((%cptr.char.mix;)+)>
+<!--end of command.element-->]]>
+
+<!ENTITY % command.attlist "INCLUDE">
+<![ %command.attlist; [
+<!ATTLIST Command
+ %moreinfo.attrib;
+ %common.attrib;
+ %command.role.attrib;
+ %local.command.attrib;
+>
+<!--end of command.attlist-->]]>
+<!--end of command.module-->]]>
+
+<!ENTITY % computeroutput.module "INCLUDE">
+<![ %computeroutput.module; [
+<!ENTITY % local.computeroutput.attrib "">
+<!ENTITY % computeroutput.role.attrib "%role.attrib;">
+
+<!ENTITY % computeroutput.element "INCLUDE">
+<![ %computeroutput.element; [
+<!ELEMENT ComputerOutput - - ((%cptr.char.mix;)+)>
+<!--end of computeroutput.element-->]]>
+
+<!ENTITY % computeroutput.attlist "INCLUDE">
+<![ %computeroutput.attlist; [
+<!ATTLIST ComputerOutput
+ %moreinfo.attrib;
+ %common.attrib;
+ %computeroutput.role.attrib;
+ %local.computeroutput.attrib;
+>
+<!--end of computeroutput.attlist-->]]>
+<!--end of computeroutput.module-->]]>
+
+<!ENTITY % database.module "INCLUDE">
+<![ %database.module; [
+<!ENTITY % local.database.attrib "">
+<!ENTITY % database.role.attrib "%role.attrib;">
+
+<!ENTITY % database.element "INCLUDE">
+<![ %database.element; [
+<!ELEMENT Database - - ((%smallcptr.char.mix;)+)>
+<!--end of database.element-->]]>
+
+<!ENTITY % database.attlist "INCLUDE">
+<![ %database.attlist; [
+<!ATTLIST Database
+ --
+ Class: Type of database the element names; no default
+ --
+ Class (Name
+ |Table
+ |Field
+ |Key1
+ |Key2
+ |Record) #IMPLIED
+ %moreinfo.attrib;
+ %common.attrib;
+ %database.role.attrib;
+ %local.database.attrib;
+>
+<!--end of database.attlist-->]]>
+<!--end of database.module-->]]>
+
+<!ENTITY % email.module "INCLUDE">
+<![ %email.module; [
+<!ENTITY % local.email.attrib "">
+<!ENTITY % email.role.attrib "%role.attrib;">
+
+<!ENTITY % email.element "INCLUDE">
+<![ %email.element; [
+<!ELEMENT Email - - ((%docinfo.char.mix;)+)>
+<!--end of email.element-->]]>
+
+<!ENTITY % email.attlist "INCLUDE">
+<![ %email.attlist; [
+<!ATTLIST Email
+ %common.attrib;
+ %email.role.attrib;
+ %local.email.attrib;
+>
+<!--end of email.attlist-->]]>
+<!--end of email.module-->]]>
+
+<!ENTITY % envar.module "INCLUDE">
+<![ %envar.module; [
+<!ENTITY % local.envar.attrib "">
+<!ENTITY % envar.role.attrib "%role.attrib;">
+
+<!ENTITY % envar.element "INCLUDE">
+<![ %envar.element; [
+<!ELEMENT EnVar - - ((%smallcptr.char.mix;)+)>
+<!--end of envar.element-->]]>
+
+<!ENTITY % envar.attlist "INCLUDE">
+<![ %envar.attlist; [
+<!ATTLIST EnVar
+ %common.attrib;
+ %envar.role.attrib;
+ %local.envar.attrib;
+>
+<!--end of envar.attlist-->]]>
+<!--end of envar.module-->]]>
+
+
+<!ENTITY % errorcode.module "INCLUDE">
+<![ %errorcode.module; [
+<!ENTITY % local.errorcode.attrib "">
+<!ENTITY % errorcode.role.attrib "%role.attrib;">
+
+<!ENTITY % errorcode.element "INCLUDE">
+<![ %errorcode.element; [
+<!ELEMENT ErrorCode - - ((%smallcptr.char.mix;)+)>
+<!--end of errorcode.element-->]]>
+
+<!ENTITY % errorcode.attlist "INCLUDE">
+<![ %errorcode.attlist; [
+<!ATTLIST ErrorCode
+ %moreinfo.attrib;
+ %common.attrib;
+ %errorcode.role.attrib;
+ %local.errorcode.attrib;
+>
+<!--end of errorcode.attlist-->]]>
+<!--end of errorcode.module-->]]>
+
+<!ENTITY % errorname.module "INCLUDE">
+<![ %errorname.module; [
+<!ENTITY % local.errorname.attrib "">
+<!ENTITY % errorname.role.attrib "%role.attrib;">
+
+<!ENTITY % errorname.element "INCLUDE">
+<![ %errorname.element; [
+<!ELEMENT ErrorName - - ((%smallcptr.char.mix;)+)>
+<!--end of errorname.element-->]]>
+
+<!ENTITY % errorname.attlist "INCLUDE">
+<![ %errorname.attlist; [
+<!ATTLIST ErrorName
+ %common.attrib;
+ %errorname.role.attrib;
+ %local.errorname.attrib;
+>
+<!--end of errorname.attlist-->]]>
+<!--end of errorname.module-->]]>
+
+<!ENTITY % errortype.module "INCLUDE">
+<![ %errortype.module; [
+<!ENTITY % local.errortype.attrib "">
+<!ENTITY % errortype.role.attrib "%role.attrib;">
+
+<!ENTITY % errortype.element "INCLUDE">
+<![ %errortype.element; [
+<!ELEMENT ErrorType - - ((%smallcptr.char.mix;)+)>
+<!--end of errortype.element-->]]>
+
+<!ENTITY % errortype.attlist "INCLUDE">
+<![ %errortype.attlist; [
+<!ATTLIST ErrorType
+ %common.attrib;
+ %errortype.role.attrib;
+ %local.errortype.attrib;
+>
+<!--end of errortype.attlist-->]]>
+<!--end of errortype.module-->]]>
+
+<!ENTITY % filename.module "INCLUDE">
+<![ %filename.module; [
+<!ENTITY % local.filename.attrib "">
+<!ENTITY % filename.role.attrib "%role.attrib;">
+
+<!ENTITY % filename.element "INCLUDE">
+<![ %filename.element; [
+<!ELEMENT Filename - - ((%smallcptr.char.mix;)+)>
+<!--end of filename.element-->]]>
+
+<!ENTITY % filename.attlist "INCLUDE">
+<![ %filename.attlist; [
+<!ATTLIST Filename
+ --
+ Class: Type of filename the element names; no default
+ --
+ Class (HeaderFile
+ |DeviceFile
+ |Directory
+ |LibraryFile
+ |SymLink) #IMPLIED
+ --
+ Path: Search path (possibly system-specific) in which
+ file can be found
+ --
+ Path CDATA #IMPLIED
+ %moreinfo.attrib;
+ %common.attrib;
+ %filename.role.attrib;
+ %local.filename.attrib;
+>
+<!--end of filename.attlist-->]]>
+<!--end of filename.module-->]]>
+
+<!ENTITY % function.module "INCLUDE">
+<![ %function.module; [
+<!ENTITY % local.function.attrib "">
+<!ENTITY % function.role.attrib "%role.attrib;">
+
+<!ENTITY % function.element "INCLUDE">
+<![ %function.element; [
+<!ELEMENT Function - - ((%cptr.char.mix;)+)>
+<!--end of function.element-->]]>
+
+<!ENTITY % function.attlist "INCLUDE">
+<![ %function.attlist; [
+<!ATTLIST Function
+ %moreinfo.attrib;
+ %common.attrib;
+ %function.role.attrib;
+ %local.function.attrib;
+>
+<!--end of function.attlist-->]]>
+<!--end of function.module-->]]>
+
+<!ENTITY % guibutton.module "INCLUDE">
+<![ %guibutton.module; [
+<!ENTITY % local.guibutton.attrib "">
+<!ENTITY % guibutton.role.attrib "%role.attrib;">
+
+<!ENTITY % guibutton.element "INCLUDE">
+<![ %guibutton.element; [
+<!ELEMENT GUIButton - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guibutton.element-->]]>
+
+<!ENTITY % guibutton.attlist "INCLUDE">
+<![ %guibutton.attlist; [
+<!ATTLIST GUIButton
+ %moreinfo.attrib;
+ %common.attrib;
+ %guibutton.role.attrib;
+ %local.guibutton.attrib;
+>
+<!--end of guibutton.attlist-->]]>
+<!--end of guibutton.module-->]]>
+
+<!ENTITY % guiicon.module "INCLUDE">
+<![ %guiicon.module; [
+<!ENTITY % local.guiicon.attrib "">
+<!ENTITY % guiicon.role.attrib "%role.attrib;">
+
+<!ENTITY % guiicon.element "INCLUDE">
+<![ %guiicon.element; [
+<!ELEMENT GUIIcon - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guiicon.element-->]]>
+
+<!ENTITY % guiicon.attlist "INCLUDE">
+<![ %guiicon.attlist; [
+<!ATTLIST GUIIcon
+ %moreinfo.attrib;
+ %common.attrib;
+ %guiicon.role.attrib;
+ %local.guiicon.attrib;
+>
+<!--end of guiicon.attlist-->]]>
+<!--end of guiicon.module-->]]>
+
+<!ENTITY % guilabel.module "INCLUDE">
+<![ %guilabel.module; [
+<!ENTITY % local.guilabel.attrib "">
+<!ENTITY % guilabel.role.attrib "%role.attrib;">
+
+<!ENTITY % guilabel.element "INCLUDE">
+<![ %guilabel.element; [
+<!ELEMENT GUILabel - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guilabel.element-->]]>
+
+<!ENTITY % guilabel.attlist "INCLUDE">
+<![ %guilabel.attlist; [
+<!ATTLIST GUILabel
+ %moreinfo.attrib;
+ %common.attrib;
+ %guilabel.role.attrib;
+ %local.guilabel.attrib;
+>
+<!--end of guilabel.attlist-->]]>
+<!--end of guilabel.module-->]]>
+
+<!ENTITY % guimenu.module "INCLUDE">
+<![ %guimenu.module; [
+<!ENTITY % local.guimenu.attrib "">
+<!ENTITY % guimenu.role.attrib "%role.attrib;">
+
+<!ENTITY % guimenu.element "INCLUDE">
+<![ %guimenu.element; [
+<!ELEMENT GUIMenu - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guimenu.element-->]]>
+
+<!ENTITY % guimenu.attlist "INCLUDE">
+<![ %guimenu.attlist; [
+<!ATTLIST GUIMenu
+ %moreinfo.attrib;
+ %common.attrib;
+ %guimenu.role.attrib;
+ %local.guimenu.attrib;
+>
+<!--end of guimenu.attlist-->]]>
+<!--end of guimenu.module-->]]>
+
+<!ENTITY % guimenuitem.module "INCLUDE">
+<![ %guimenuitem.module; [
+<!ENTITY % local.guimenuitem.attrib "">
+<!ENTITY % guimenuitem.role.attrib "%role.attrib;">
+
+<!ENTITY % guimenuitem.element "INCLUDE">
+<![ %guimenuitem.element; [
+<!ELEMENT GUIMenuItem - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guimenuitem.element-->]]>
+
+<!ENTITY % guimenuitem.attlist "INCLUDE">
+<![ %guimenuitem.attlist; [
+<!ATTLIST GUIMenuItem
+ %moreinfo.attrib;
+ %common.attrib;
+ %guimenuitem.role.attrib;
+ %local.guimenuitem.attrib;
+>
+<!--end of guimenuitem.attlist-->]]>
+<!--end of guimenuitem.module-->]]>
+
+<!ENTITY % guisubmenu.module "INCLUDE">
+<![ %guisubmenu.module; [
+<!ENTITY % local.guisubmenu.attrib "">
+<!ENTITY % guisubmenu.role.attrib "%role.attrib;">
+
+<!ENTITY % guisubmenu.element "INCLUDE">
+<![ %guisubmenu.element; [
+<!ELEMENT GUISubmenu - - ((%smallcptr.char.mix;|Accel)+)>
+<!--end of guisubmenu.element-->]]>
+
+<!ENTITY % guisubmenu.attlist "INCLUDE">
+<![ %guisubmenu.attlist; [
+<!ATTLIST GUISubmenu
+ %moreinfo.attrib;
+ %common.attrib;
+ %guisubmenu.role.attrib;
+ %local.guisubmenu.attrib;
+>
+<!--end of guisubmenu.attlist-->]]>
+<!--end of guisubmenu.module-->]]>
+
+<!ENTITY % hardware.module "INCLUDE">
+<![ %hardware.module; [
+<!ENTITY % local.hardware.attrib "">
+<!ENTITY % hardware.role.attrib "%role.attrib;">
+
+<!ENTITY % hardware.element "INCLUDE">
+<![ %hardware.element; [
+<!ELEMENT Hardware - - ((%smallcptr.char.mix;)+)>
+<!--end of hardware.element-->]]>
+
+<!ENTITY % hardware.attlist "INCLUDE">
+<![ %hardware.attlist; [
+<!ATTLIST Hardware
+ %moreinfo.attrib;
+ %common.attrib;
+ %hardware.role.attrib;
+ %local.hardware.attrib;
+>
+<!--end of hardware.attlist-->]]>
+<!--end of hardware.module-->]]>
+
+<!ENTITY % interface.module "INCLUDE">
+<![ %interface.module; [
+<!ENTITY % local.interface.attrib "">
+<!ENTITY % interface.role.attrib "%role.attrib;">
+
+<!ENTITY % interface.element "INCLUDE">
+<![ %interface.element; [
+<!ELEMENT Interface - - (%smallcptr.char.mix;|Accel)*>
+<!--end of interface.element-->]]>
+
+<!ENTITY % interface.attlist "INCLUDE">
+<![ %interface.attlist; [
+<!ATTLIST Interface
+ %moreinfo.attrib;
+ %common.attrib;
+ %interface.role.attrib;
+ %local.interface.attrib;
+>
+<!--end of interface.attlist-->]]>
+<!--end of interface.module-->]]>
+
+<!ENTITY % keycap.module "INCLUDE">
+<![ %keycap.module; [
+<!ENTITY % local.keycap.attrib "">
+<!ENTITY % keycap.role.attrib "%role.attrib;">
+
+<!ENTITY % keycap.element "INCLUDE">
+<![ %keycap.element; [
+<!ELEMENT KeyCap - - (%smallcptr.char.mix;)*>
+<!--end of keycap.element-->]]>
+
+<!ENTITY % keycap.attlist "INCLUDE">
+<![ %keycap.attlist; [
+<!ATTLIST KeyCap
+ %moreinfo.attrib;
+ %common.attrib;
+ %keycap.role.attrib;
+ %local.keycap.attrib;
+>
+<!--end of keycap.attlist-->]]>
+<!--end of keycap.module-->]]>
+
+<!ENTITY % keycode.module "INCLUDE">
+<![ %keycode.module; [
+<!ENTITY % local.keycode.attrib "">
+<!ENTITY % keycode.role.attrib "%role.attrib;">
+
+<!ENTITY % keycode.element "INCLUDE">
+<![ %keycode.element; [
+<!ELEMENT KeyCode - - ((%smallcptr.char.mix;)+)>
+<!--end of keycode.element-->]]>
+
+<!ENTITY % keycode.attlist "INCLUDE">
+<![ %keycode.attlist; [
+<!ATTLIST KeyCode
+ %common.attrib;
+ %keycode.role.attrib;
+ %local.keycode.attrib;
+>
+<!--end of keycode.attlist-->]]>
+<!--end of keycode.module-->]]>
+
+<!ENTITY % keycombo.module "INCLUDE">
+<![ %keycombo.module; [
+<!ENTITY % local.keycombo.attrib "">
+<!ENTITY % keycombo.role.attrib "%role.attrib;">
+
+<!ENTITY % keycombo.element "INCLUDE">
+<![ %keycombo.element; [
+<!ELEMENT KeyCombo - - ((KeyCap|KeyCombo|KeySym|MouseButton)+)>
+<!--end of keycombo.element-->]]>
+
+<!ENTITY % keycombo.attlist "INCLUDE">
+<![ %keycombo.attlist; [
+<!ATTLIST KeyCombo
+ %keyaction.attrib;
+ %moreinfo.attrib;
+ %common.attrib;
+ %keycombo.role.attrib;
+ %local.keycombo.attrib;
+>
+<!--end of keycombo.attlist-->]]>
+<!--end of keycombo.module-->]]>
+
+<!ENTITY % keysym.module "INCLUDE">
+<![ %keysym.module; [
+<!ENTITY % local.keysym.attrib "">
+<!ENTITY % keysysm.role.attrib "%role.attrib;">
+
+<!ENTITY % keysym.element "INCLUDE">
+<![ %keysym.element; [
+<!ELEMENT KeySym - - ((%smallcptr.char.mix;)+)>
+<!--end of keysym.element-->]]>
+
+<!ENTITY % keysym.attlist "INCLUDE">
+<![ %keysym.attlist; [
+<!ATTLIST KeySym
+ %common.attrib;
+ %keysysm.role.attrib;
+ %local.keysym.attrib;
+>
+<!--end of keysym.attlist-->]]>
+<!--end of keysym.module-->]]>
+
+<!ENTITY % lineannotation.module "INCLUDE">
+<![ %lineannotation.module; [
+<!ENTITY % local.lineannotation.attrib "">
+<!ENTITY % lineannotation.role.attrib "%role.attrib;">
+
+<!ENTITY % lineannotation.element "INCLUDE">
+<![ %lineannotation.element; [
+<!ELEMENT LineAnnotation - - ((%para.char.mix;)+)>
+<!--end of lineannotation.element-->]]>
+
+<!ENTITY % lineannotation.attlist "INCLUDE">
+<![ %lineannotation.attlist; [
+<!ATTLIST LineAnnotation
+ %common.attrib;
+ %lineannotation.role.attrib;
+ %local.lineannotation.attrib;
+>
+<!--end of lineannotation.attlist-->]]>
+<!--end of lineannotation.module-->]]>
+
+<!ENTITY % literal.module "INCLUDE">
+<![ %literal.module; [
+<!ENTITY % local.literal.attrib "">
+<!ENTITY % literal.role.attrib "%role.attrib;">
+
+<!ENTITY % literal.element "INCLUDE">
+<![ %literal.element; [
+<!ELEMENT Literal - - (%cptr.char.mix;)*>
+<!--end of literal.element-->]]>
+
+<!ENTITY % literal.attlist "INCLUDE">
+<![ %literal.attlist; [
+<!ATTLIST Literal
+ %moreinfo.attrib;
+ %common.attrib;
+ %literal.role.attrib;
+ %local.literal.attrib;
+>
+<!--end of literal.attlist-->]]>
+<!--end of literal.module-->]]>
+
+<!ENTITY % constant.module "INCLUDE">
+<![ %constant.module; [
+<!ENTITY % local.constant.attrib "">
+<!ENTITY % constant.role.attrib "%role.attrib;">
+
+<!ENTITY % constant.element "INCLUDE">
+<![ %constant.element; [
+<!ELEMENT Constant - - (%smallcptr.char.mix;)*>
+<!--end of constant.element-->]]>
+
+<!ENTITY % constant.attlist "INCLUDE">
+<![ %constant.attlist; [
+<!ATTLIST Constant
+ %common.attrib;
+ %constant.role.attrib;
+ %local.constant.attrib;
+ Class (Limit) #IMPLIED
+>
+<!--end of constant.attlist-->]]>
+<!--end of constant.module-->]]>
+
+<!ENTITY % varname.module "INCLUDE">
+<![ %varname.module; [
+<!ENTITY % local.varname.attrib "">
+<!ENTITY % varname.role.attrib "%role.attrib;">
+
+<!ENTITY % varname.element "INCLUDE">
+<![ %varname.element; [
+<!ELEMENT VarName - - (%smallcptr.char.mix;)*>
+<!--end of varname.element-->]]>
+
+<!ENTITY % varname.attlist "INCLUDE">
+<![ %varname.attlist; [
+<!ATTLIST VarName
+ %common.attrib;
+ %varname.role.attrib;
+ %local.varname.attrib;
+>
+<!--end of varname.attlist-->]]>
+<!--end of varname.module-->]]>
+
+<!ENTITY % markup.module "INCLUDE">
+<![ %markup.module; [
+<!ENTITY % local.markup.attrib "">
+<!ENTITY % markup.role.attrib "%role.attrib;">
+
+<!ENTITY % markup.element "INCLUDE">
+<![ %markup.element; [
+<!ELEMENT Markup - - ((%smallcptr.char.mix;)+)>
+<!--end of markup.element-->]]>
+
+<!ENTITY % markup.attlist "INCLUDE">
+<![ %markup.attlist; [
+<!ATTLIST Markup
+ %common.attrib;
+ %markup.role.attrib;
+ %local.markup.attrib;
+>
+<!--end of markup.attlist-->]]>
+<!--end of markup.module-->]]>
+
+<!ENTITY % medialabel.module "INCLUDE">
+<![ %medialabel.module; [
+<!ENTITY % local.medialabel.attrib "">
+<!ENTITY % medialabel.role.attrib "%role.attrib;">
+
+<!ENTITY % medialabel.element "INCLUDE">
+<![ %medialabel.element; [
+<!ELEMENT MediaLabel - - ((%smallcptr.char.mix;)+)>
+<!--end of medialabel.element-->]]>
+
+<!ENTITY % medialabel.attlist "INCLUDE">
+<![ %medialabel.attlist; [
+<!ATTLIST MediaLabel
+ --
+ Class: Type of medium named by the element; no default
+ --
+ Class (Cartridge
+ |CDRom
+ |Disk
+ |Tape) #IMPLIED
+ %common.attrib;
+ %medialabel.role.attrib;
+ %local.medialabel.attrib;
+>
+<!--end of medialabel.attlist-->]]>
+<!--end of medialabel.module-->]]>
+
+<!ENTITY % menuchoice.content.module "INCLUDE">
+<![ %menuchoice.content.module; [
+<!ENTITY % menuchoice.module "INCLUDE">
+<![ %menuchoice.module; [
+<!ENTITY % local.menuchoice.attrib "">
+<!ENTITY % menuchoice.role.attrib "%role.attrib;">
+
+<!ENTITY % menuchoice.element "INCLUDE">
+<![ %menuchoice.element; [
+<!ELEMENT MenuChoice - - (Shortcut?, (GUIButton|GUIIcon|GUILabel
+ |GUIMenu|GUIMenuItem|GUISubmenu|Interface)+)>
+<!--end of menuchoice.element-->]]>
+
+<!ENTITY % menuchoice.attlist "INCLUDE">
+<![ %menuchoice.attlist; [
+<!ATTLIST MenuChoice
+ %moreinfo.attrib;
+ %common.attrib;
+ %menuchoice.role.attrib;
+ %local.menuchoice.attrib;
+>
+<!--end of menuchoice.attlist-->]]>
+<!--end of menuchoice.module-->]]>
+
+<!ENTITY % shortcut.module "INCLUDE">
+<![ %shortcut.module; [
+<!-- See also KeyCombo -->
+<!ENTITY % local.shortcut.attrib "">
+<!ENTITY % shortcut.role.attrib "%role.attrib;">
+
+<!ENTITY % shortcut.element "INCLUDE">
+<![ %shortcut.element; [
+<!ELEMENT Shortcut - - ((KeyCap|KeyCombo|KeySym|MouseButton)+)>
+<!--end of shortcut.element-->]]>
+
+<!ENTITY % shortcut.attlist "INCLUDE">
+<![ %shortcut.attlist; [
+<!ATTLIST Shortcut
+ %keyaction.attrib;
+ %moreinfo.attrib;
+ %common.attrib;
+ %shortcut.role.attrib;
+ %local.shortcut.attrib;
+>
+<!--end of shortcut.attlist-->]]>
+<!--end of shortcut.module-->]]>
+<!--end of menuchoice.content.module-->]]>
+
+<!ENTITY % mousebutton.module "INCLUDE">
+<![ %mousebutton.module; [
+<!ENTITY % local.mousebutton.attrib "">
+<!ENTITY % mousebutton.role.attrib "%role.attrib;">
+
+<!ENTITY % mousebutton.element "INCLUDE">
+<![ %mousebutton.element; [
+<!ELEMENT MouseButton - - ((%smallcptr.char.mix;)+)>
+<!--end of mousebutton.element-->]]>
+
+<!ENTITY % mousebutton.attlist "INCLUDE">
+<![ %mousebutton.attlist; [
+<!ATTLIST MouseButton
+ %moreinfo.attrib;
+ %common.attrib;
+ %mousebutton.role.attrib;
+ %local.mousebutton.attrib;
+>
+<!--end of mousebutton.attlist-->]]>
+<!--end of mousebutton.module-->]]>
+
+<!ENTITY % msgtext.module "INCLUDE">
+<![ %msgtext.module; [
+<!ENTITY % local.msgtext.attrib "">
+<!ENTITY % msgtext.role.attrib "%role.attrib;">
+
+<!ENTITY % msgtext.element "INCLUDE">
+<![ %msgtext.element; [
+<!--FUTURE USE (V5.0):
+......................
+The content model of MsgText will be reduced. It will be made
+the same as %example.mix; although it may not use that PE.
+......................
+-->
+<!ELEMENT MsgText - - ((%component.mix;)+)>
+<!--end of msgtext.element-->]]>
+
+<!ENTITY % msgtext.attlist "INCLUDE">
+<![ %msgtext.attlist; [
+<!ATTLIST MsgText
+ %common.attrib;
+ %msgtext.role.attrib;
+ %local.msgtext.attrib;
+>
+<!--end of msgtext.attlist-->]]>
+<!--end of msgtext.module-->]]>
+
+<!ENTITY % option.module "INCLUDE">
+<![ %option.module; [
+<!ENTITY % local.option.attrib "">
+<!ENTITY % option.role.attrib "%role.attrib;">
+
+<!ENTITY % option.element "INCLUDE">
+<![ %option.element; [
+<!ELEMENT Option - - (%smallcptr.char.mix;)*>
+<!--end of option.element-->]]>
+
+<!ENTITY % option.attlist "INCLUDE">
+<![ %option.attlist; [
+<!ATTLIST Option
+ %common.attrib;
+ %option.role.attrib;
+ %local.option.attrib;
+>
+<!--end of option.attlist-->]]>
+<!--end of option.module-->]]>
+
+<!ENTITY % optional.module "INCLUDE">
+<![ %optional.module; [
+<!ENTITY % local.optional.attrib "">
+<!ENTITY % optional.role.attrib "%role.attrib;">
+
+<!ENTITY % optional.element "INCLUDE">
+<![ %optional.element; [
+<!ELEMENT Optional - - ((%cptr.char.mix;)+)>
+<!--end of optional.element-->]]>
+
+<!ENTITY % optional.attlist "INCLUDE">
+<![ %optional.attlist; [
+<!ATTLIST Optional
+ %common.attrib;
+ %optional.role.attrib;
+ %local.optional.attrib;
+>
+<!--end of optional.attlist-->]]>
+<!--end of optional.module-->]]>
+
+<!ENTITY % parameter.module "INCLUDE">
+<![ %parameter.module; [
+<!ENTITY % local.parameter.attrib "">
+<!ENTITY % parameter.role.attrib "%role.attrib;">
+
+<!ENTITY % parameter.element "INCLUDE">
+<![ %parameter.element; [
+<!ELEMENT Parameter - - (%smallcptr.char.mix;)*>
+<!--end of parameter.element-->]]>
+
+<!ENTITY % parameter.attlist "INCLUDE">
+<![ %parameter.attlist; [
+<!ATTLIST Parameter
+ --
+ Class: Type of the Parameter; no default
+ --
+ Class (Command
+ |Function
+ |Option) #IMPLIED
+ %moreinfo.attrib;
+ %common.attrib;
+ %parameter.role.attrib;
+ %local.parameter.attrib;
+>
+<!--end of parameter.attlist-->]]>
+<!--end of parameter.module-->]]>
+
+<!ENTITY % prompt.module "INCLUDE">
+<![ %prompt.module; [
+<!ENTITY % local.prompt.attrib "">
+<!ENTITY % prompt.role.attrib "%role.attrib;">
+
+<!ENTITY % prompt.element "INCLUDE">
+<![ %prompt.element; [
+<!ELEMENT Prompt - - ((%smallcptr.char.mix;)+)>
+<!--end of prompt.element-->]]>
+
+<!ENTITY % prompt.attlist "INCLUDE">
+<![ %prompt.attlist; [
+<!ATTLIST Prompt
+ %moreinfo.attrib;
+ %common.attrib;
+ %prompt.role.attrib;
+ %local.prompt.attrib;
+>
+<!--end of prompt.attlist-->]]>
+<!--end of prompt.module-->]]>
+
+<!ENTITY % property.module "INCLUDE">
+<![ %property.module; [
+<!ENTITY % local.property.attrib "">
+<!ENTITY % property.role.attrib "%role.attrib;">
+
+<!ENTITY % property.element "INCLUDE">
+<![ %property.element; [
+<!ELEMENT Property - - (%smallcptr.char.mix;)*>
+<!--end of property.element-->]]>
+
+<!ENTITY % property.attlist "INCLUDE">
+<![ %property.attlist; [
+<!ATTLIST Property
+ %moreinfo.attrib;
+ %common.attrib;
+ %property.role.attrib;
+ %local.property.attrib;
+>
+<!--end of property.attlist-->]]>
+<!--end of property.module-->]]>
+
+<!ENTITY % replaceable.module "INCLUDE">
+<![ %replaceable.module; [
+<!ENTITY % local.replaceable.attrib "">
+<!ENTITY % replaceable.role.attrib "%role.attrib;">
+
+<!ENTITY % replaceable.element "INCLUDE">
+<![ %replaceable.element; [
+<!ELEMENT Replaceable - - ((#PCDATA
+ | %link.char.class;
+ | Optional
+ | %base.char.class;
+ | %other.char.class;
+ | InlineGraphic
+ | InlineMediaObject)+)>
+<!--end of replaceable.element-->]]>
+
+<!ENTITY % replaceable.attlist "INCLUDE">
+<![ %replaceable.attlist; [
+<!ATTLIST Replaceable
+ --
+ Class: Type of information the element represents; no
+ default
+ --
+ Class (Command
+ |Function
+ |Option
+ |Parameter) #IMPLIED
+ %common.attrib;
+ %replaceable.role.attrib;
+ %local.replaceable.attrib;
+>
+<!--end of replaceable.attlist-->]]>
+<!--end of replaceable.module-->]]>
+
+<!ENTITY % returnvalue.module "INCLUDE">
+<![ %returnvalue.module; [
+<!ENTITY % local.returnvalue.attrib "">
+<!ENTITY % returnvalue.role.attrib "%role.attrib;">
+
+<!ENTITY % returnvalue.element "INCLUDE">
+<![ %returnvalue.element; [
+<!ELEMENT ReturnValue - - ((%smallcptr.char.mix;)+)>
+<!--end of returnvalue.element-->]]>
+
+<!ENTITY % returnvalue.attlist "INCLUDE">
+<![ %returnvalue.attlist; [
+<!ATTLIST ReturnValue
+ %common.attrib;
+ %returnvalue.role.attrib;
+ %local.returnvalue.attrib;
+>
+<!--end of returnvalue.attlist-->]]>
+<!--end of returnvalue.module-->]]>
+
+<!ENTITY % sgmltag.module "INCLUDE">
+<![ %sgmltag.module; [
+<!ENTITY % local.sgmltag.attrib "">
+<!ENTITY % sgmltag.role.attrib "%role.attrib;">
+
+<!ENTITY % sgmltag.element "INCLUDE">
+<![ %sgmltag.element; [
+<!ELEMENT SGMLTag - - ((%smallcptr.char.mix;)+)>
+<!--end of sgmltag.element-->]]>
+
+<!ENTITY % sgmltag.attlist "INCLUDE">
+<![ %sgmltag.attlist; [
+<!ATTLIST SGMLTag
+ --
+ Class: Type of SGML construct the element names; no default
+ --
+ Class (Attribute
+ |AttValue
+ |Element
+ |EndTag
+ |EmptyTag
+ |GenEntity
+ |NumCharRef
+ |ParamEntity
+ |PI
+ |XMLPI
+ |StartTag
+ |SGMLComment) #IMPLIED
+ %common.attrib;
+ %sgmltag.role.attrib;
+ %local.sgmltag.attrib;
+>
+<!--end of sgmltag.attlist-->]]>
+<!--end of sgmltag.module-->]]>
+
+<!ENTITY % structfield.module "INCLUDE">
+<![ %structfield.module; [
+<!ENTITY % local.structfield.attrib "">
+<!ENTITY % structfield.role.attrib "%role.attrib;">
+
+<!ENTITY % structfield.element "INCLUDE">
+<![ %structfield.element; [
+<!ELEMENT StructField - - ((%smallcptr.char.mix;)+)>
+<!--end of structfield.element-->]]>
+
+<!ENTITY % structfield.attlist "INCLUDE">
+<![ %structfield.attlist; [
+<!ATTLIST StructField
+ %common.attrib;
+ %structfield.role.attrib;
+ %local.structfield.attrib;
+>
+<!--end of structfield.attlist-->]]>
+<!--end of structfield.module-->]]>
+
+<!ENTITY % structname.module "INCLUDE">
+<![ %structname.module; [
+<!ENTITY % local.structname.attrib "">
+<!ENTITY % structname.role.attrib "%role.attrib;">
+
+<!ENTITY % structname.element "INCLUDE">
+<![ %structname.element; [
+<!ELEMENT StructName - - ((%smallcptr.char.mix;)+)>
+<!--end of structname.element-->]]>
+
+<!ENTITY % structname.attlist "INCLUDE">
+<![ %structname.attlist; [
+<!ATTLIST StructName
+ %common.attrib;
+ %structname.role.attrib;
+ %local.structname.attrib;
+>
+<!--end of structname.attlist-->]]>
+<!--end of structname.module-->]]>
+
+<!ENTITY % symbol.module "INCLUDE">
+<![ %symbol.module; [
+<!ENTITY % local.symbol.attrib "">
+<!ENTITY % symbol.role.attrib "%role.attrib;">
+
+<!ENTITY % symbol.element "INCLUDE">
+<![ %symbol.element; [
+<!ELEMENT Symbol - - ((%smallcptr.char.mix;)+)>
+<!--end of symbol.element-->]]>
+
+<!ENTITY % symbol.attlist "INCLUDE">
+<![ %symbol.attlist; [
+<!ATTLIST Symbol
+ --
+ Class: Type of symbol; no default
+ --
+ Class (Limit) #IMPLIED
+ %common.attrib;
+ %symbol.role.attrib;
+ %local.symbol.attrib;
+>
+<!--end of symbol.attlist-->]]>
+<!--end of symbol.module-->]]>
+
+<!ENTITY % systemitem.module "INCLUDE">
+<![ %systemitem.module; [
+<!ENTITY % local.systemitem.attrib "">
+<!ENTITY % systemitem.role.attrib "%role.attrib;">
+
+<!ENTITY % systemitem.element "INCLUDE">
+<![ %systemitem.element; [
+<!ELEMENT SystemItem - - ((%smallcptr.char.mix; | Acronym)*)>
+<!--end of systemitem.element-->]]>
+
+<!ENTITY % systemitem.attlist "INCLUDE">
+<![ %systemitem.attlist; [
+<!ATTLIST SystemItem
+ --
+ Class: Type of system item the element names; no default
+ --
+ Class (Constant
+ |GroupName
+ |Library
+ |Macro
+ |OSname
+ |Resource
+ |SystemName
+ |UserName) #IMPLIED
+ %moreinfo.attrib;
+ %common.attrib;
+ %systemitem.role.attrib;
+ %local.systemitem.attrib;
+>
+<!--end of systemitem.attlist-->]]>
+<!--end of systemitem.module-->]]>
+
+
+<!ENTITY % token.module "INCLUDE">
+<![ %token.module; [
+<!ENTITY % local.token.attrib "">
+<!ENTITY % token.role.attrib "%role.attrib;">
+
+<!ENTITY % token.element "INCLUDE">
+<![ %token.element; [
+<!ELEMENT Token - - ((%smallcptr.char.mix;)+)>
+<!--end of token.element-->]]>
+
+<!ENTITY % token.attlist "INCLUDE">
+<![ %token.attlist; [
+<!ATTLIST Token
+ %common.attrib;
+ %token.role.attrib;
+ %local.token.attrib;
+>
+<!--end of token.attlist-->]]>
+<!--end of token.module-->]]>
+
+<!ENTITY % type.module "INCLUDE">
+<![ %type.module; [
+<!ENTITY % local.type.attrib "">
+<!ENTITY % type.role.attrib "%role.attrib;">
+
+<!ENTITY % type.element "INCLUDE">
+<![ %type.element; [
+<!ELEMENT Type - - ((%smallcptr.char.mix;)+)>
+<!--end of type.element-->]]>
+
+<!ENTITY % type.attlist "INCLUDE">
+<![ %type.attlist; [
+<!ATTLIST Type
+ %common.attrib;
+ %type.role.attrib;
+ %local.type.attrib;
+>
+<!--end of type.attlist-->]]>
+<!--end of type.module-->]]>
+
+<!ENTITY % userinput.module "INCLUDE">
+<![ %userinput.module; [
+<!ENTITY % local.userinput.attrib "">
+<!ENTITY % userinput.role.attrib "%role.attrib;">
+
+<!ENTITY % userinput.element "INCLUDE">
+<![ %userinput.element; [
+<!ELEMENT UserInput - - ((%cptr.char.mix;)+)>
+<!--end of userinput.element-->]]>
+
+<!ENTITY % userinput.attlist "INCLUDE">
+<![ %userinput.attlist; [
+<!ATTLIST UserInput
+ %moreinfo.attrib;
+ %common.attrib;
+ %userinput.role.attrib;
+ %local.userinput.attrib;
+>
+<!--end of userinput.attlist-->]]>
+<!--end of userinput.module-->]]>
+
+<!-- General words and phrases ............................................ -->
+
+<!ENTITY % abbrev.module "INCLUDE">
+<![ %abbrev.module; [
+<!ENTITY % local.abbrev.attrib "">
+<!ENTITY % abbrev.role.attrib "%role.attrib;">
+
+<!ENTITY % abbrev.element "INCLUDE">
+<![ %abbrev.element; [
+<!ELEMENT Abbrev - - ((%word.char.mix;)+)>
+<!--end of abbrev.element-->]]>
+
+<!ENTITY % abbrev.attlist "INCLUDE">
+<![ %abbrev.attlist; [
+<!ATTLIST Abbrev
+ %common.attrib;
+ %abbrev.role.attrib;
+ %local.abbrev.attrib;
+>
+<!--end of abbrev.attlist-->]]>
+<!--end of abbrev.module-->]]>
+
+<!ENTITY % acronym.module "INCLUDE">
+<![ %acronym.module; [
+<!ENTITY % local.acronym.attrib "">
+<!ENTITY % acronym.role.attrib "%role.attrib;">
+
+<!ENTITY % acronym.element "INCLUDE">
+<![ %acronym.element; [
+<!ELEMENT Acronym - - ((%word.char.mix;)+) %acronym.exclusion;>
+<!--end of acronym.element-->]]>
+
+<!ENTITY % acronym.attlist "INCLUDE">
+<![ %acronym.attlist; [
+<!ATTLIST Acronym
+ %common.attrib;
+ %acronym.role.attrib;
+ %local.acronym.attrib;
+>
+<!--end of acronym.attlist-->]]>
+<!--end of acronym.module-->]]>
+
+<!ENTITY % citation.module "INCLUDE">
+<![ %citation.module; [
+<!ENTITY % local.citation.attrib "">
+<!ENTITY % citation.role.attrib "%role.attrib;">
+
+<!ENTITY % citation.element "INCLUDE">
+<![ %citation.element; [
+<!ELEMENT Citation - - ((%para.char.mix;)+)>
+<!--end of citation.element-->]]>
+
+<!ENTITY % citation.attlist "INCLUDE">
+<![ %citation.attlist; [
+<!ATTLIST Citation
+ %common.attrib;
+ %citation.role.attrib;
+ %local.citation.attrib;
+>
+<!--end of citation.attlist-->]]>
+<!--end of citation.module-->]]>
+
+<!ENTITY % citerefentry.module "INCLUDE">
+<![ %citerefentry.module; [
+<!ENTITY % local.citerefentry.attrib "">
+<!ENTITY % citerefentry.role.attrib "%role.attrib;">
+
+<!ENTITY % citerefentry.element "INCLUDE">
+<![ %citerefentry.element; [
+<!ELEMENT CiteRefEntry - - (RefEntryTitle, ManVolNum?)>
+<!--end of citerefentry.element-->]]>
+
+<!ENTITY % citerefentry.attlist "INCLUDE">
+<![ %citerefentry.attlist; [
+<!ATTLIST CiteRefEntry
+ %common.attrib;
+ %citerefentry.role.attrib;
+ %local.citerefentry.attrib;
+>
+<!--end of citerefentry.attlist-->]]>
+<!--end of citerefentry.module-->]]>
+
+<!ENTITY % refentrytitle.module "INCLUDE">
+<![ %refentrytitle.module; [
+<!ENTITY % local.refentrytitle.attrib "">
+<!ENTITY % refentrytitle.role.attrib "%role.attrib;">
+
+<!ENTITY % refentrytitle.element "INCLUDE">
+<![ %refentrytitle.element; [
+<!ELEMENT RefEntryTitle - O ((%para.char.mix;)+)>
+<!--end of refentrytitle.element-->]]>
+
+<!ENTITY % refentrytitle.attlist "INCLUDE">
+<![ %refentrytitle.attlist; [
+<!ATTLIST RefEntryTitle
+ %common.attrib;
+ %refentrytitle.role.attrib;
+ %local.refentrytitle.attrib;
+>
+<!--end of refentrytitle.attlist-->]]>
+<!--end of refentrytitle.module-->]]>
+
+<!ENTITY % manvolnum.module "INCLUDE">
+<![ %manvolnum.module; [
+<!ENTITY % local.manvolnum.attrib "">
+<!ENTITY % namvolnum.role.attrib "%role.attrib;">
+
+<!ENTITY % manvolnum.element "INCLUDE">
+<![ %manvolnum.element; [
+<!ELEMENT ManVolNum - O ((%word.char.mix;)+)>
+<!--end of manvolnum.element-->]]>
+
+<!ENTITY % manvolnum.attlist "INCLUDE">
+<![ %manvolnum.attlist; [
+<!ATTLIST ManVolNum
+ %common.attrib;
+ %namvolnum.role.attrib;
+ %local.manvolnum.attrib;
+>
+<!--end of manvolnum.attlist-->]]>
+<!--end of manvolnum.module-->]]>
+
+<!ENTITY % citetitle.module "INCLUDE">
+<![ %citetitle.module; [
+<!ENTITY % local.citetitle.attrib "">
+<!ENTITY % citetitle.role.attrib "%role.attrib;">
+
+<!ENTITY % citetitle.element "INCLUDE">
+<![ %citetitle.element; [
+<!ELEMENT CiteTitle - - ((%para.char.mix;)+)>
+<!--end of citetitle.element-->]]>
+
+<!ENTITY % citetitle.attlist "INCLUDE">
+<![ %citetitle.attlist; [
+<!ATTLIST CiteTitle
+ --
+ Pubwork: Genre of published work cited; no default
+ --
+ Pubwork (Article
+ |Book
+ |Chapter
+ |Part
+ |RefEntry
+ |Section
+ |Journal
+ |Series
+ |Set
+ |Manuscript) #IMPLIED
+ %common.attrib;
+ %citetitle.role.attrib;
+ %local.citetitle.attrib;
+>
+<!--end of citetitle.attlist-->]]>
+<!--end of citetitle.module-->]]>
+
+<!ENTITY % emphasis.module "INCLUDE">
+<![ %emphasis.module; [
+<!ENTITY % local.emphasis.attrib "">
+<!ENTITY % emphasis.role.attrib "%role.attrib;">
+
+<!ENTITY % emphasis.element "INCLUDE">
+<![ %emphasis.element; [
+<!ELEMENT Emphasis - - ((%para.char.mix;)+)>
+<!--end of emphasis.element-->]]>
+
+<!ENTITY % emphasis.attlist "INCLUDE">
+<![ %emphasis.attlist; [
+<!ATTLIST Emphasis
+ %common.attrib;
+ %emphasis.role.attrib;
+ %local.emphasis.attrib;
+>
+<!--end of emphasis.attlist-->]]>
+<!--end of emphasis.module-->]]>
+
+<!ENTITY % firstterm.module "INCLUDE">
+<![ %firstterm.module; [
+<!ENTITY % local.firstterm.attrib "">
+<!ENTITY % firstterm.role.attrib "%role.attrib;">
+
+<!ENTITY % firstterm.element "INCLUDE">
+<![ %firstterm.element; [
+<!ELEMENT FirstTerm - - ((%word.char.mix;)+)>
+<!--end of firstterm.element-->]]>
+
+<!ENTITY % firstterm.attlist "INCLUDE">
+<![ %firstterm.attlist; [
+<!ATTLIST FirstTerm
+ %linkend.attrib; --to GlossEntry or other explanation--
+ %common.attrib;
+ %firstterm.role.attrib;
+ %local.firstterm.attrib;
+>
+<!--end of firstterm.attlist-->]]>
+<!--end of firstterm.module-->]]>
+
+<!ENTITY % foreignphrase.module "INCLUDE">
+<![ %foreignphrase.module; [
+<!ENTITY % local.foreignphrase.attrib "">
+<!ENTITY % foreignphrase.role.attrib "%role.attrib;">
+
+<!ENTITY % foreignphrase.element "INCLUDE">
+<![ %foreignphrase.element; [
+<!ELEMENT ForeignPhrase - - ((%para.char.mix;)+)>
+<!--end of foreignphrase.element-->]]>
+
+<!ENTITY % foreignphrase.attlist "INCLUDE">
+<![ %foreignphrase.attlist; [
+<!ATTLIST ForeignPhrase
+ %common.attrib;
+ %foreignphrase.role.attrib;
+ %local.foreignphrase.attrib;
+>
+<!--end of foreignphrase.attlist-->]]>
+<!--end of foreignphrase.module-->]]>
+
+<!ENTITY % glossterm.module "INCLUDE">
+<![ %glossterm.module; [
+<!ENTITY % local.glossterm.attrib "">
+<!ENTITY % glossterm.role.attrib "%role.attrib;">
+
+<!ENTITY % glossterm.element "INCLUDE">
+<![ %glossterm.element; [
+<!ELEMENT GlossTerm - O ((%para.char.mix;)+) %glossterm.exclusion;>
+<!--end of glossterm.element-->]]>
+
+<!ENTITY % glossterm.attlist "INCLUDE">
+<![ %glossterm.attlist; [
+<!ATTLIST GlossTerm
+ %linkend.attrib; --to GlossEntry if Glossterm used in text--
+ --
+ BaseForm: Provides the form of GlossTerm to be used
+ for indexing
+ --
+ BaseForm CDATA #IMPLIED
+ %common.attrib;
+ %glossterm.role.attrib;
+ %local.glossterm.attrib;
+>
+<!--end of glossterm.attlist-->]]>
+<!--end of glossterm.module-->]]>
+
+<!ENTITY % phrase.module "INCLUDE">
+<![ %phrase.module; [
+<!ENTITY % local.phrase.attrib "">
+<!ENTITY % phrase.role.attrib "%role.attrib;">
+
+<!ENTITY % phrase.element "INCLUDE">
+<![ %phrase.element; [
+<!ELEMENT Phrase - - ((%para.char.mix;)+)>
+<!--end of phrase.element-->]]>
+
+<!ENTITY % phrase.attlist "INCLUDE">
+<![ %phrase.attlist; [
+<!ATTLIST Phrase
+ %common.attrib;
+ %phrase.role.attrib;
+ %local.phrase.attrib;
+>
+<!--end of phrase.attlist-->]]>
+<!--end of phrase.module-->]]>
+
+<!ENTITY % quote.module "INCLUDE">
+<![ %quote.module; [
+<!ENTITY % local.quote.attrib "">
+<!ENTITY % quote.role.attrib "%role.attrib;">
+
+<!ENTITY % quote.element "INCLUDE">
+<![ %quote.element; [
+<!ELEMENT Quote - - ((%para.char.mix;)+)>
+<!--end of quote.element-->]]>
+
+<!ENTITY % quote.attlist "INCLUDE">
+<![ %quote.attlist; [
+<!ATTLIST Quote
+ %common.attrib;
+ %quote.role.attrib;
+ %local.quote.attrib;
+>
+<!--end of quote.attlist-->]]>
+<!--end of quote.module-->]]>
+
+<!ENTITY % ssscript.module "INCLUDE">
+<![ %ssscript.module; [
+<!ENTITY % local.ssscript.attrib "">
+<!ENTITY % ssscript.role.attrib "%role.attrib;">
+
+<!ENTITY % ssscript.elements "INCLUDE">
+<![ %ssscript.elements [
+<!ELEMENT (Subscript | Superscript) - - ((#PCDATA
+ | %link.char.class;
+ | Emphasis
+ | Replaceable
+ | Symbol
+ | InlineGraphic
+ | InlineMediaObject
+ | %base.char.class;
+ | %other.char.class;)+)
+ %ubiq.exclusion;>
+<!--end of ssscript.elements-->]]>
+
+<!ENTITY % ssscript.attlists "INCLUDE">
+<![ %ssscript.attlists; [
+<!ATTLIST (Subscript | Superscript)
+ %common.attrib;
+ %ssscript.role.attrib;
+ %local.ssscript.attrib;
+>
+<!--end of ssscript.attlists-->]]>
+<!--end of ssscript.module-->]]>
+
+<!ENTITY % trademark.module "INCLUDE">
+<![ %trademark.module; [
+<!ENTITY % local.trademark.attrib "">
+<!ENTITY % trademark.role.attrib "%role.attrib;">
+
+<!ENTITY % trademark.element "INCLUDE">
+<![ %trademark.element; [
+<!ELEMENT Trademark - - ((#PCDATA
+ | %link.char.class;
+ | %tech.char.class;
+ | %base.char.class;
+ | %other.char.class;
+ | InlineGraphic
+ | InlineMediaObject
+ | Emphasis)+)>
+<!--end of trademark.element-->]]>
+
+<!ENTITY % trademark.attlist "INCLUDE">
+<![ %trademark.attlist; [
+<!ATTLIST Trademark
+ --
+ Class: More precisely identifies the item the element names
+ --
+ Class (Service
+ |Trade
+ |Registered
+ |Copyright) Trade
+ %common.attrib;
+ %trademark.role.attrib;
+ %local.trademark.attrib;
+>
+<!--end of trademark.attlist-->]]>
+<!--end of trademark.module-->]]>
+
+<!ENTITY % wordasword.module "INCLUDE">
+<![ %wordasword.module; [
+<!ENTITY % local.wordasword.attrib "">
+<!ENTITY % wordasword.role.attrib "%role.attrib;">
+
+<!ENTITY % wordasword.element "INCLUDE">
+<![ %wordasword.element; [
+<!ELEMENT WordAsWord - - ((%word.char.mix;)+)>
+<!--end of wordasword.element-->]]>
+
+<!ENTITY % wordasword.attlist "INCLUDE">
+<![ %wordasword.attlist; [
+<!ATTLIST WordAsWord
+ %common.attrib;
+ %wordasword.role.attrib;
+ %local.wordasword.attrib;
+>
+<!--end of wordasword.attlist-->]]>
+<!--end of wordasword.module-->]]>
+
+<!-- Links and cross-references ........................................... -->
+
+<!ENTITY % link.module "INCLUDE">
+<![ %link.module; [
+<!ENTITY % local.link.attrib "">
+<!ENTITY % link.role.attrib "%role.attrib;">
+
+<!ENTITY % link.element "INCLUDE">
+<![ %link.element; [
+<!ELEMENT Link - - ((%para.char.mix;)+) %links.exclusion;>
+<!--end of link.element-->]]>
+
+<!ENTITY % link.attlist "INCLUDE">
+<![ %link.attlist; [
+<!ATTLIST Link
+ --
+ Endterm: ID of element containing text that is to be
+ fetched from elsewhere in the document to appear as
+ the content of this element
+ --
+ Endterm IDREF #IMPLIED
+ %linkendreq.attrib; --to linked-to object--
+ --
+ Type: Freely assignable parameter
+ --
+ Type CDATA #IMPLIED
+ %common.attrib;
+ %link.role.attrib;
+ %local.link.attrib;
+>
+<!--end of link.attlist-->]]>
+<!--end of link.module-->]]>
+
+<!ENTITY % olink.module "INCLUDE">
+<![ %olink.module; [
+<!ENTITY % local.olink.attrib "">
+<!ENTITY % olink.role.attrib "%role.attrib;">
+
+<!ENTITY % olink.element "INCLUDE">
+<![ %olink.element; [
+<!ELEMENT OLink - - ((%para.char.mix;)+) %links.exclusion;>
+<!--end of olink.element-->]]>
+
+<!ENTITY % olink.attlist "INCLUDE">
+<![ %olink.attlist; [
+<!ATTLIST OLink
+ --
+ TargetDocEnt: Name of an entity to be the target of the link
+ --
+ TargetDocEnt ENTITY #IMPLIED
+ --
+ LinkMode: ID of a ModeSpec containing instructions for
+ operating on the entity named by TargetDocEnt
+ --
+ LinkMode IDREF #IMPLIED
+ --
+ LocalInfo: Information that may be passed to ModeSpec
+ --
+ LocalInfo CDATA #IMPLIED
+ --
+ Type: Freely assignable parameter
+ --
+ Type CDATA #IMPLIED
+ %common.attrib;
+ %olink.role.attrib;
+ %local.olink.attrib;
+>
+<!--end of olink.attlist-->]]>
+<!--end of olink.module-->]]>
+
+<!ENTITY % ulink.module "INCLUDE">
+<![ %ulink.module; [
+<!ENTITY % local.ulink.attrib "">
+<!ENTITY % ulink.role.attrib "%role.attrib;">
+
+<!ENTITY % ulink.element "INCLUDE">
+<![ %ulink.element; [
+<!ELEMENT ULink - - ((%para.char.mix;)+) %links.exclusion;>
+<!--end of ulink.element-->]]>
+
+<!ENTITY % ulink.attlist "INCLUDE">
+<![ %ulink.attlist; [
+<!ATTLIST ULink
+ --
+ URL: uniform resource locator; the target of the ULink
+ --
+ URL CDATA #REQUIRED
+ --
+ Type: Freely assignable parameter
+ --
+ Type CDATA #IMPLIED
+ %common.attrib;
+ %ulink.role.attrib;
+ %local.ulink.attrib;
+>
+<!--end of ulink.attlist-->]]>
+<!--end of ulink.module-->]]>
+
+<!ENTITY % footnoteref.module "INCLUDE">
+<![ %footnoteref.module; [
+<!ENTITY % local.footnoteref.attrib "">
+<!ENTITY % footnoteref.role.attrib "%role.attrib;">
+
+<!ENTITY % footnoteref.element "INCLUDE">
+<![ %footnoteref.element; [
+<!ELEMENT FootnoteRef - O EMPTY>
+<!--end of footnoteref.element-->]]>
+
+<!ENTITY % footnoteref.attlist "INCLUDE">
+<![ %footnoteref.attlist; [
+<!ATTLIST FootnoteRef
+ %linkendreq.attrib; --to footnote content supplied elsewhere--
+ %label.attrib;
+ %common.attrib;
+ %footnoteref.role.attrib;
+ %local.footnoteref.attrib;
+>
+<!--end of footnoteref.attlist-->]]>
+<!--end of footnoteref.module-->]]>
+
+<!ENTITY % xref.module "INCLUDE">
+<![ %xref.module; [
+<!ENTITY % local.xref.attrib "">
+<!ENTITY % xref.role.attrib "%role.attrib;">
+
+<!ENTITY % xref.element "INCLUDE">
+<![ %xref.element; [
+<!ELEMENT XRef - O EMPTY>
+<!--end of xref.element-->]]>
+
+<!ENTITY % xref.attlist "INCLUDE">
+<![ %xref.attlist; [
+<!ATTLIST XRef
+ --
+ Endterm: ID of element containing text that is to be
+ fetched from elsewhere in the document to appear as
+ the content of this element
+ --
+ Endterm IDREF #IMPLIED
+ %linkendreq.attrib; --to linked-to object--
+ %common.attrib;
+ %xref.role.attrib;
+ %local.xref.attrib;
+>
+<!--end of xref.attlist-->]]>
+<!--end of xref.module-->]]>
+
+<!-- Ubiquitous elements .................................................. -->
+
+<!ENTITY % anchor.module "INCLUDE">
+<![ %anchor.module; [
+<!ENTITY % local.anchor.attrib "">
+<!ENTITY % anchor.role.attrib "%role.attrib;">
+
+<!ENTITY % anchor.element "INCLUDE">
+<![ %anchor.element; [
+<!ELEMENT Anchor - O EMPTY>
+<!--end of anchor.element-->]]>
+
+<!ENTITY % anchor.attlist "INCLUDE">
+<![ %anchor.attlist; [
+<!ATTLIST Anchor
+ %idreq.attrib; -- required --
+ %pagenum.attrib; --replaces Lang --
+ %remap.attrib;
+ %xreflabel.attrib;
+ %revisionflag.attrib;
+ %effectivity.attrib;
+ %anchor.role.attrib;
+ %local.anchor.attrib;
+>
+<!--end of anchor.attlist-->]]>
+<!--end of anchor.module-->]]>
+
+<!ENTITY % beginpage.module "INCLUDE">
+<![ %beginpage.module; [
+<!ENTITY % local.beginpage.attrib "">
+<!ENTITY % beginpage.role.attrib "%role.attrib;">
+
+<!ENTITY % beginpage.element "INCLUDE">
+<![ %beginpage.element; [
+<!ELEMENT BeginPage - O EMPTY>
+<!--end of beginpage.element-->]]>
+
+<!ENTITY % beginpage.attlist "INCLUDE">
+<![ %beginpage.attlist; [
+<!ATTLIST BeginPage
+ --
+ PageNum: Number of page that begins at this point
+ --
+ %pagenum.attrib;
+ %common.attrib;
+ %beginpage.role.attrib;
+ %local.beginpage.attrib;
+>
+<!--end of beginpage.attlist-->]]>
+<!--end of beginpage.module-->]]>
+
+<!-- IndexTerms appear in the text flow for generating or linking an
+ index. -->
+
+<!ENTITY % indexterm.content.module "INCLUDE">
+<![ %indexterm.content.module; [
+<!ENTITY % indexterm.module "INCLUDE">
+<![ %indexterm.module; [
+<!ENTITY % local.indexterm.attrib "">
+<!ENTITY % indexterm.role.attrib "%role.attrib;">
+
+<!ENTITY % indexterm.element "INCLUDE">
+<![ %indexterm.element; [
+<!ELEMENT IndexTerm - O (Primary, ((Secondary, ((Tertiary, (See|SeeAlso+)?)
+ | See | SeeAlso+)?) | See | SeeAlso+)?) %ubiq.exclusion;>
+<!--end of indexterm.element-->]]>
+
+<!ENTITY % indexterm.attlist "INCLUDE">
+<![ %indexterm.attlist; [
+<!ATTLIST IndexTerm
+ %pagenum.attrib;
+ --
+ Scope: Indicates which generated indices the IndexTerm
+ should appear in: Global (whole document set), Local (this
+ document only), or All (both)
+ --
+ Scope (All
+ |Global
+ |Local) #IMPLIED
+ --
+ Significance: Whether this IndexTerm is the most pertinent
+ of its series (Preferred) or not (Normal, the default)
+ --
+ Significance (Preferred
+ |Normal) Normal
+ --
+ Class: Indicates type of IndexTerm; default is Singular,
+ or EndOfRange if StartRef is supplied; StartOfRange value
+ must be supplied explicitly on starts of ranges
+ --
+ Class (Singular
+ |StartOfRange
+ |EndOfRange) #IMPLIED
+ --
+ StartRef: ID of the IndexTerm that starts the indexing
+ range ended by this IndexTerm
+ --
+ StartRef IDREF #CONREF
+ --
+ Zone: IDs of the elements to which the IndexTerm applies,
+ and indicates that the IndexTerm applies to those entire
+ elements rather than the point at which the IndexTerm
+ occurs
+ --
+ Zone IDREFS #IMPLIED
+ %common.attrib;
+ %indexterm.role.attrib;
+ %local.indexterm.attrib;
+>
+<!--end of indexterm.attlist-->]]>
+<!--end of indexterm.module-->]]>
+
+<!ENTITY % primsecter.module "INCLUDE">
+<![ %primsecter.module; [
+<!ENTITY % local.primsecter.attrib "">
+<!ENTITY % primsecter.role.attrib "%role.attrib;">
+
+<!ENTITY % primsecter.elements "INCLUDE">
+<![ %primsecter.elements; [
+<!ELEMENT (Primary | Secondary | Tertiary) - O ((%ndxterm.char.mix;)+)>
+<!--end of primsecter.elements-->]]>
+
+<!ENTITY % primsecter.attlists "INCLUDE">
+<![ %primsecter.attlists; [
+<!ENTITY % containing.attlist "INCLUDE">
+<![ %containing.attlist; [
+<!ATTLIST (Primary | Secondary | Tertiary)
+ --
+ SortAs: Alternate sort string for index sorting, e.g.,
+ "fourteen" for an element containing "14"
+ --
+ SortAs CDATA #IMPLIED
+ %common.attrib;
+ %primsecter.role.attrib;
+ %local.primsecter.attrib;
+>
+<!--end of containing.attlist-->]]>
+<!--end of primsecter.attlist-->]]>
+<!--end of primsecter.module-->]]>
+
+<!ENTITY % seeseealso.module "INCLUDE">
+<![ %seeseealso.module; [
+<!ENTITY % local.seeseealso.attrib "">
+<!ENTITY % seeseealso.role.attrib "%role.attrib;">
+
+<!ENTITY % seeseealso.elements "INCLUDE">
+<![ %seeseealso.elements [
+<!ELEMENT (See | SeeAlso) - O ((%ndxterm.char.mix;)+)>
+<!--end of seeseealso.elements-->]]>
+
+<!ENTITY % seeseealso.attlists "INCLUDE">
+<![ %seeseealso.attlists [
+<!ATTLIST (See | SeeAlso)
+ %common.attrib;
+ %seeseealso.role.attrib;
+ %local.seeseealso.attrib;
+>
+<!--end of seeseealso.attlists-->]]>
+<!--end of seeseealso.module-->]]>
+<!--end of indexterm.content.module-->]]>
+
+<!-- End of DocBook information pool module V4.1 .......................... -->
+<!-- ...................................................................... -->
diff --git a/docs/docbook/dbsgml/docbook.cat b/docs/docbook/dbsgml/docbook.cat
new file mode 100644
index 00000000000..0f285d0d751
--- /dev/null
+++ b/docs/docbook/dbsgml/docbook.cat
@@ -0,0 +1,63 @@
+ -- ...................................................................... --
+ -- Catalog data for DocBook V4.1 ........................................ --
+ -- File docbook.cat ..................................................... --
+
+ -- Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/.
+ --
+
+ -- This is the catalog data file for DocBook V4.1. It is provided as
+ a convenience in building your own catalog files. You need not use
+ the filenames listed here, and need not use the filename method of
+ identifying storage objects at all. See the documentation for
+ detailed information on the files associated with the DocBook DTD.
+ See SGML Open Technical Resolution 9401 for detailed information
+ on supplying and using catalog data.
+ --
+
+ -- ...................................................................... --
+ -- SGML declaration associated with DocBook ............................. --
+
+DTDDECL "-//OASIS//DTD DocBook V4.1//EN" "docbook.dcl"
+
+ -- ...................................................................... --
+ -- DocBook driver file .................................................. --
+
+PUBLIC "-//OASIS//DTD DocBook V4.1//EN" "docbook.dtd"
+
+ -- ...................................................................... --
+ -- DocBook modules ...................................................... --
+
+PUBLIC "-//USA-DOD//DTD Table Model 951010//EN" "cals-tbl.dtd"
+PUBLIC "-//OASIS//ELEMENTS DocBook Information Pool V4.1//EN" "dbpool.mod"
+PUBLIC "-//OASIS//ELEMENTS DocBook Document Hierarchy V4.1//EN" "dbhier.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Additional General Entities V4.1//EN" "dbgenent.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Notations V4.1//EN" "dbnotn.mod"
+PUBLIC "-//OASIS//ENTITIES DocBook Character Entities V4.1//EN" "dbcent.mod"
+
+ -- ...................................................................... --
+ -- ISO entity sets ...................................................... --
+
+PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN" "ISOdia"
+PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN" "ISOnum"
+PUBLIC "ISO 8879:1986//ENTITIES Publishing//EN" "ISOpub"
+PUBLIC "ISO 8879:1986//ENTITIES General Technical//EN" "ISOtech"
+PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN" "ISOlat1"
+PUBLIC "ISO 8879:1986//ENTITIES Added Latin 2//EN" "ISOlat2"
+PUBLIC "ISO 8879:1986//ENTITIES Greek Letters//EN" "ISOgrk1"
+PUBLIC "ISO 8879:1986//ENTITIES Monotoniko Greek//EN" "ISOgrk2"
+PUBLIC "ISO 8879:1986//ENTITIES Greek Symbols//EN" "ISOgrk3"
+PUBLIC "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN" "ISOgrk4"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN" "ISOamsa"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN" "ISOamsb"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN" "ISOamsc"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN" "ISOamsn"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN" "ISOamso"
+PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN" "ISOamsr"
+PUBLIC "ISO 8879:1986//ENTITIES Box and Line Drawing//EN" "ISObox"
+PUBLIC "ISO 8879:1986//ENTITIES Russian Cyrillic//EN" "ISOcyr1"
+PUBLIC "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN" "ISOcyr2"
+
+ -- End of catalog data for DocBook V4.1 ................................. --
+ -- ...................................................................... --
diff --git a/docs/docbook/dbsgml/docbook.dcl b/docs/docbook/dbsgml/docbook.dcl
new file mode 100644
index 00000000000..c76de206cf4
--- /dev/null
+++ b/docs/docbook/dbsgml/docbook.dcl
@@ -0,0 +1,106 @@
+<!SGML "ISO 8879:1986"
+ -- ...................................................................... --
+ -- DocBook SGML declaration V4.1 ........................................ --
+ -- file docbook.dcl ..................................................... --
+
+CHARSET
+
+ BASESET
+ "ISO 646:1983//CHARSET International Reference Version (IRV)//ESC 2/5 4/0"
+ DESCSET
+ 0 9 UNUSED
+ 9 2 9
+ 11 2 UNUSED
+ 13 1 13
+ 14 18 UNUSED
+ 32 95 32
+ 127 1 UNUSED
+
+ BASESET
+ "ISO Registration Number 100//CHARSET ECMA-94 Right Part of Latin Alphabet Nr. 1//ESC 2/13 4/1"
+ DESCSET
+ 128 32 UNUSED
+ 160 96 32
+
+CAPACITY SGMLREF
+
+ TOTALCAP 99000000
+ ATTCAP 1000000
+ ATTCHCAP 1000000
+ AVGRPCAP 1000000
+ ELEMCAP 1000000
+ ENTCAP 1000000
+ ENTCHCAP 1000000
+ GRPCAP 1000000
+ IDCAP 32000000
+ IDREFCAP 32000000
+
+SCOPE DOCUMENT
+
+SYNTAX
+
+ SHUNCHAR CONTROLS 0 1 2 3 4 5 6 7 8 9
+ 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29
+ 30 31 127 128 129
+ 130 131 132 133 134 135 136 137 138 139
+ 140 141 142 143 144 145 146 147 148 149
+ 150 151 152 153 154 155 156 157 158 159
+
+ BASESET
+ "ISO 646:1983//CHARSET International Reference Version (IRV)//ESC 2/5 4/0"
+ DESCSET
+ 0 128 0
+
+ FUNCTION
+ RE 13
+ RS 10
+ SPACE 32
+ TAB SEPCHAR 9
+
+ NAMING
+ LCNMSTRT ""
+ UCNMSTRT ""
+ LCNMCHAR ".-_"
+ UCNMCHAR ".-_"
+ NAMECASE
+ GENERAL YES
+ ENTITY NO
+
+ DELIM
+ GENERAL SGMLREF
+ SHORTREF SGMLREF
+
+ NAMES SGMLREF
+
+ QUANTITY SGMLREF
+ ATTCNT 256
+ GRPCNT 253
+ GRPGTCNT 253
+ LITLEN 8092
+ NAMELEN 44
+ TAGLVL 100
+
+FEATURES
+
+ MINIMIZE
+ DATATAG NO
+ OMITTAG NO
+ RANK NO
+ SHORTTAG YES
+
+ LINK
+ SIMPLE NO
+ IMPLICIT NO
+ EXPLICIT NO
+
+ OTHER
+ CONCUR NO
+ SUBDOC NO
+ FORMAL YES
+
+APPINFO NONE
+
+ -- End of DocBook SGML declaration V4.1 ................................. --
+ -- ...................................................................... --
+>
diff --git a/docs/docbook/dbsgml/docbook.dtd b/docs/docbook/dbsgml/docbook.dtd
new file mode 100755
index 00000000000..4d784cc43fd
--- /dev/null
+++ b/docs/docbook/dbsgml/docbook.dtd
@@ -0,0 +1,117 @@
+<!-- ...................................................................... -->
+<!-- DocBook DTD V4.1 ..................................................... -->
+<!-- File docbook.dtd ..................................................... -->
+
+<!-- Copyright 1992-2000 HaL Computer Systems, Inc.,
+ O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
+ Corporation, and the Organization for the Advancement of
+ Structured Information Standards (OASIS).
+
+ $Id: docbook.dtd,v 1.3 2001/12/06 07:37:56 jerry Exp $
+
+ Permission to use, copy, modify and distribute the DocBook DTD and
+ its accompanying documentation for any purpose and without fee is
+ hereby granted in perpetuity, provided that the above copyright
+ notice and this paragraph appear in all copies. The copyright
+ holders make no representation about the suitability of the DTD for
+ any purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ If you modify the DocBook DTD in any way, except for declaring and
+ referencing additional sets of general entities and declaring
+ additional notations, label your DTD as a variant of DocBook. See
+ the maintenance documentation for more information.
+
+ Please direct all questions, bug reports, or suggestions for
+ changes to the docbook@lists.oasis-open.org mailing list. For more
+ information, see http://www.oasis-open.org/docbook/.
+-->
+
+<!-- ...................................................................... -->
+
+<!-- This is the driver file for V4.1 of the DocBook DTD.
+ Please use the following formal public identifier to identify it:
+
+ "-//OASIS//DTD DocBook V4.1//EN"
+
+ For example, if your document's top-level element is Book, and
+ you are using DocBook directly, use the FPI in the DOCTYPE
+ declaration:
+
+ <!DOCTYPE Book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [...]>
+
+ Or, if you have a higher-level driver file that customizes DocBook,
+ use the FPI in the parameter entity declaration:
+
+ <!ENTITY % DocBookDTD PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+ %DocBookDTD;
+
+ The DocBook DTD is accompanied by an SGML declaration.
+
+ See the documentation for detailed information on the parameter
+ entity and module scheme used in DocBook, customizing DocBook and
+ planning for interchange, and changes made since the last release
+ of DocBook.
+-->
+
+<!-- ...................................................................... -->
+<!-- Notation declarations ................................................ -->
+
+<!ENTITY % dbnotn.module "INCLUDE">
+<![ %dbnotn.module; [
+<!ENTITY % dbnotn PUBLIC
+"-//OASIS//ENTITIES DocBook Notations V4.1//EN">
+%dbnotn;
+<!--end of dbnotn.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- ISO character entity sets ............................................ -->
+
+<!ENTITY % dbcent.module "INCLUDE">
+<![ %dbcent.module; [
+<!ENTITY euro SDATA "[euro ]"><!-- euro sign, U+20AC NEW -->
+<!ENTITY % dbcent PUBLIC
+"-//OASIS//ENTITIES DocBook Character Entities V4.1//EN">
+%dbcent;
+<!--end of dbcent.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- DTD modules .......................................................... -->
+
+<!-- Information pool .............. -->
+
+<!ENTITY % dbpool.module "INCLUDE">
+<![ %dbpool.module; [
+<!ENTITY % dbpool PUBLIC
+"-//OASIS//ELEMENTS DocBook Information Pool V4.1//EN">
+%dbpool;
+<!--end of dbpool.module-->]]>
+
+<!-- Redeclaration placeholder ..... -->
+
+<!ENTITY % intermod.redecl.module "IGNORE">
+<![ %intermod.redecl.module; [
+%rdbmods;
+<!--end of intermod.redecl.module-->]]>
+
+<!-- Document hierarchy ............ -->
+
+<!ENTITY % dbhier.module "INCLUDE">
+<![ %dbhier.module; [
+<!ENTITY % dbhier PUBLIC
+"-//OASIS//ELEMENTS DocBook Document Hierarchy V4.1//EN">
+%dbhier;
+<!--end of dbhier.module-->]]>
+
+<!-- ...................................................................... -->
+<!-- Other general entities ............................................... -->
+
+<!ENTITY % dbgenent.module "INCLUDE">
+<![ %dbgenent.module; [
+<!ENTITY % dbgenent PUBLIC
+"-//OASIS//ENTITIES DocBook Additional General Entities V4.1//EN">
+%dbgenent;
+<!--end of dbgenent.module-->]]>
+
+<!-- End of DocBook DTD V4.1 .............................................. -->
+<!-- ...................................................................... -->
diff --git a/docs/docbook/dbsgml/ent/ISOamsa b/docs/docbook/dbsgml/ent/ISOamsa
new file mode 100644
index 00000000000..b77154cb024
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamsa
@@ -0,0 +1,66 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamsa PUBLIC
+ "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN">
+ %ISOamsa;
+-->
+<!ENTITY cularr SDATA "[cularr]"--/curvearrowleft A: left curved arrow -->
+<!ENTITY curarr SDATA "[curarr]"--/curvearrowright A: rt curved arrow -->
+<!ENTITY dArr SDATA "[dArr ]"--/Downarrow A: down dbl arrow -->
+<!ENTITY darr2 SDATA "[darr2 ]"--/downdownarrows A: two down arrows -->
+<!ENTITY dharl SDATA "[dharl ]"--/downleftharpoon A: dn harpoon-left -->
+<!ENTITY dharr SDATA "[dharr ]"--/downrightharpoon A: down harpoon-rt -->
+<!ENTITY lAarr SDATA "[lAarr ]"--/Lleftarrow A: left triple arrow -->
+<!ENTITY Larr SDATA "[Larr ]"--/twoheadleftarrow A:-->
+<!ENTITY larr2 SDATA "[larr2 ]"--/leftleftarrows A: two left arrows -->
+<!ENTITY larrhk SDATA "[larrhk]"--/hookleftarrow A: left arrow-hooked -->
+<!ENTITY larrlp SDATA "[larrlp]"--/looparrowleft A: left arrow-looped -->
+<!ENTITY larrtl SDATA "[larrtl]"--/leftarrowtail A: left arrow-tailed -->
+<!ENTITY lhard SDATA "[lhard ]"--/leftharpoondown A: l harpoon-down -->
+<!ENTITY lharu SDATA "[lharu ]"--/leftharpoonup A: left harpoon-up -->
+<!ENTITY hArr SDATA "[hArr ]"--/Leftrightarrow A: l&r dbl arrow -->
+<!ENTITY harr SDATA "[harr ]"--/leftrightarrow A: l&r arrow -->
+<!ENTITY lrarr2 SDATA "[lrarr2]"--/leftrightarrows A: l arr over r arr -->
+<!ENTITY rlarr2 SDATA "[rlarr2]"--/rightleftarrows A: r arr over l arr -->
+<!ENTITY harrw SDATA "[harrw ]"--/leftrightsquigarrow A: l&r arr-wavy -->
+<!ENTITY rlhar2 SDATA "[rlhar2]"--/rightleftharpoons A: r harp over l -->
+<!ENTITY lrhar2 SDATA "[lrhar2]"--/leftrightharpoons A: l harp over r -->
+<!ENTITY lsh SDATA "[lsh ]"--/Lsh A:-->
+<!ENTITY map SDATA "[map ]"--/mapsto A:-->
+<!ENTITY mumap SDATA "[mumap ]"--/multimap A:-->
+<!ENTITY nearr SDATA "[nearr ]"--/nearrow A: NE pointing arrow -->
+<!ENTITY nlArr SDATA "[nlArr ]"--/nLeftarrow A: not implied by -->
+<!ENTITY nlarr SDATA "[nlarr ]"--/nleftarrow A: not left arrow -->
+<!ENTITY nhArr SDATA "[nhArr ]"--/nLeftrightarrow A: not l&r dbl arr -->
+<!ENTITY nharr SDATA "[nharr ]"--/nleftrightarrow A: not l&r arrow -->
+<!ENTITY nrarr SDATA "[nrarr ]"--/nrightarrow A: not right arrow -->
+<!ENTITY nrArr SDATA "[nrArr ]"--/nRightarrow A: not implies -->
+<!ENTITY nwarr SDATA "[nwarr ]"--/nwarrow A: NW pointing arrow -->
+<!ENTITY olarr SDATA "[olarr ]"--/circlearrowleft A: l arr in circle -->
+<!ENTITY orarr SDATA "[orarr ]"--/circlearrowright A: r arr in circle -->
+<!ENTITY rAarr SDATA "[rAarr ]"--/Rrightarrow A: right triple arrow -->
+<!ENTITY Rarr SDATA "[Rarr ]"--/twoheadrightarrow A:-->
+<!ENTITY rarr2 SDATA "[rarr2 ]"--/rightrightarrows A: two rt arrows -->
+<!ENTITY rarrhk SDATA "[rarrhk]"--/hookrightarrow A: rt arrow-hooked -->
+<!ENTITY rarrlp SDATA "[rarrlp]"--/looparrowright A: rt arrow-looped -->
+<!ENTITY rarrtl SDATA "[rarrtl]"--/rightarrowtail A: rt arrow-tailed -->
+<!ENTITY rarrw SDATA "[rarrw ]"--/squigarrowright A: rt arrow-wavy -->
+<!ENTITY rhard SDATA "[rhard ]"--/rightharpoondown A: rt harpoon-down -->
+<!ENTITY rharu SDATA "[rharu ]"--/rightharpoonup A: rt harpoon-up -->
+<!ENTITY rsh SDATA "[rsh ]"--/Rsh A:-->
+<!ENTITY drarr SDATA "[drarr ]"--/searrow A: downward rt arrow -->
+<!ENTITY dlarr SDATA "[dlarr ]"--/swarrow A: downward l arrow -->
+<!ENTITY uArr SDATA "[uArr ]"--/Uparrow A: up dbl arrow -->
+<!ENTITY uarr2 SDATA "[uarr2 ]"--/upuparrows A: two up arrows -->
+<!ENTITY vArr SDATA "[vArr ]"--/Updownarrow A: up&down dbl arrow -->
+<!ENTITY varr SDATA "[varr ]"--/updownarrow A: up&down arrow -->
+<!ENTITY uharl SDATA "[uharl ]"--/upleftharpoon A: up harpoon-left -->
+<!ENTITY uharr SDATA "[uharr ]"--/uprightharpoon A: up harp-r-->
+<!ENTITY xlArr SDATA "[xlArr ]"--/Longleftarrow A: long l dbl arrow -->
+<!ENTITY xhArr SDATA "[xhArr ]"--/Longleftrightarrow A: long l&r dbl arr-->
+<!ENTITY xharr SDATA "[xharr ]"--/longleftrightarrow A: long l&r arr -->
+<!ENTITY xrArr SDATA "[xrArr ]"--/Longrightarrow A: long rt dbl arr -->
diff --git a/docs/docbook/dbsgml/ent/ISOamsb b/docs/docbook/dbsgml/ent/ISOamsb
new file mode 100644
index 00000000000..43944a732fb
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamsb
@@ -0,0 +1,52 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamsb PUBLIC
+ "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN">
+ %ISOamsb;
+-->
+<!ENTITY amalg SDATA "[amalg ]"--/amalg B: amalgamation or coproduct-->
+<!ENTITY Barwed SDATA "[Barwed]"--/doublebarwedge B: log and, dbl bar-->
+<!ENTITY barwed SDATA "[barwed]"--/barwedge B: logical and, bar above-->
+<!ENTITY Cap SDATA "[Cap ]"--/Cap /doublecap B: dbl intersection-->
+<!ENTITY Cup SDATA "[Cup ]"--/Cup /doublecup B: dbl union-->
+<!ENTITY cuvee SDATA "[cuvee ]"--/curlyvee B: curly logical or-->
+<!ENTITY cuwed SDATA "[cuwed ]"--/curlywedge B: curly logical and-->
+<!ENTITY diam SDATA "[diam ]"--/diamond B: open diamond-->
+<!ENTITY divonx SDATA "[divonx]"--/divideontimes B: division on times-->
+<!ENTITY intcal SDATA "[intcal]"--/intercal B: intercal-->
+<!ENTITY lthree SDATA "[lthree]"--/leftthreetimes B:-->
+<!ENTITY ltimes SDATA "[ltimes]"--/ltimes B: times sign, left closed-->
+<!ENTITY minusb SDATA "[minusb]"--/boxminus B: minus sign in box-->
+<!ENTITY oast SDATA "[oast ]"--/circledast B: asterisk in circle-->
+<!ENTITY ocir SDATA "[ocir ]"--/circledcirc B: open dot in circle-->
+<!ENTITY odash SDATA "[odash ]"--/circleddash B: hyphen in circle-->
+<!ENTITY odot SDATA "[odot ]"--/odot B: middle dot in circle-->
+<!ENTITY ominus SDATA "[ominus]"--/ominus B: minus sign in circle-->
+<!ENTITY oplus SDATA "[oplus ]"--/oplus B: plus sign in circle-->
+<!ENTITY osol SDATA "[osol ]"--/oslash B: solidus in circle-->
+<!ENTITY otimes SDATA "[otimes]"--/otimes B: multiply sign in circle-->
+<!ENTITY plusb SDATA "[plusb ]"--/boxplus B: plus sign in box-->
+<!ENTITY plusdo SDATA "[plusdo]"--/dotplus B: plus sign, dot above-->
+<!ENTITY rthree SDATA "[rthree]"--/rightthreetimes B:-->
+<!ENTITY rtimes SDATA "[rtimes]"--/rtimes B: times sign, right closed-->
+<!ENTITY sdot SDATA "[sdot ]"--/cdot B: small middle dot-->
+<!ENTITY sdotb SDATA "[sdotb ]"--/dotsquare /boxdot B: small dot in box-->
+<!ENTITY setmn SDATA "[setmn ]"--/setminus B: reverse solidus-->
+<!ENTITY sqcap SDATA "[sqcap ]"--/sqcap B: square intersection-->
+<!ENTITY sqcup SDATA "[sqcup ]"--/sqcup B: square union-->
+<!ENTITY ssetmn SDATA "[ssetmn]"--/smallsetminus B: sm reverse solidus-->
+<!ENTITY sstarf SDATA "[sstarf]"--/star B: small star, filled-->
+<!ENTITY timesb SDATA "[timesb]"--/boxtimes B: multiply sign in box-->
+<!ENTITY top SDATA "[top ]"--/top B: inverted perpendicular-->
+<!ENTITY uplus SDATA "[uplus ]"--/uplus B: plus sign in union-->
+<!ENTITY wreath SDATA "[wreath]"--/wr B: wreath product-->
+<!ENTITY xcirc SDATA "[xcirc ]"--/bigcirc B: large circle-->
+<!ENTITY xdtri SDATA "[xdtri ]"--/bigtriangledown B: big dn tri, open-->
+<!ENTITY xutri SDATA "[xutri ]"--/bigtriangleup B: big up tri, open-->
+<!ENTITY coprod SDATA "[coprod]"--/coprod L: coproduct operator-->
+<!ENTITY prod SDATA "[prod ]"--/prod L: product operator-->
+<!ENTITY sum SDATA "[sum ]"--/sum L: summation operator-->
diff --git a/docs/docbook/dbsgml/ent/ISOamsc b/docs/docbook/dbsgml/ent/ISOamsc
new file mode 100644
index 00000000000..06222d58cf4
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamsc
@@ -0,0 +1,20 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamsc PUBLIC
+ "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN">
+ %ISOamsc;
+-->
+<!ENTITY rceil SDATA "[rceil ]"--/rceil C: right ceiling-->
+<!ENTITY rfloor SDATA "[rfloor]"--/rfloor C: right floor-->
+<!ENTITY rpargt SDATA "[rpargt]"--/rightparengtr C: right paren, gt-->
+<!ENTITY urcorn SDATA "[urcorn]"--/urcorner C: upper right corner-->
+<!ENTITY drcorn SDATA "[drcorn]"--/lrcorner C: downward right corner-->
+<!ENTITY lceil SDATA "[lceil ]"--/lceil O: left ceiling-->
+<!ENTITY lfloor SDATA "[lfloor]"--/lfloor O: left floor-->
+<!ENTITY lpargt SDATA "[lpargt]"--/leftparengtr O: left parenthesis, gt-->
+<!ENTITY ulcorn SDATA "[ulcorn]"--/ulcorner O: upper left corner-->
+<!ENTITY dlcorn SDATA "[dlcorn]"--/llcorner O: downward left corner-->
diff --git a/docs/docbook/dbsgml/ent/ISOamsn b/docs/docbook/dbsgml/ent/ISOamsn
new file mode 100644
index 00000000000..0c8327a3267
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamsn
@@ -0,0 +1,70 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamsn PUBLIC
+ "ISO 8879:1986//ENTITIES
+ Added Math Symbols: Negated Relations//EN">
+ %ISOamsn;
+-->
+<!ENTITY gnap SDATA "[gnap ]"--/gnapprox N: greater, not approximate-->
+<!ENTITY gne SDATA "[gne ]"--/gneq N: greater, not equals-->
+<!ENTITY gnE SDATA "[gnE ]"--/gneqq N: greater, not dbl equals-->
+<!ENTITY gnsim SDATA "[gnsim ]"--/gnsim N: greater, not similar-->
+<!ENTITY gvnE SDATA "[gvnE ]"--/gvertneqq N: gt, vert, not dbl eq-->
+<!ENTITY lnap SDATA "[lnap ]"--/lnapprox N: less, not approximate-->
+<!ENTITY lnE SDATA "[lnE ]"--/lneqq N: less, not double equals-->
+<!ENTITY lne SDATA "[lne ]"--/lneq N: less, not equals-->
+<!ENTITY lnsim SDATA "[lnsim ]"--/lnsim N: less, not similar-->
+<!ENTITY lvnE SDATA "[lvnE ]"--/lvertneqq N: less, vert, not dbl eq-->
+<!ENTITY nap SDATA "[nap ]"--/napprox N: not approximate-->
+<!ENTITY ncong SDATA "[ncong ]"--/ncong N: not congruent with-->
+<!ENTITY nequiv SDATA "[nequiv]"--/nequiv N: not identical with-->
+<!ENTITY ngE SDATA "[ngE ]"--/ngeqq N: not greater, dbl equals-->
+<!ENTITY nge SDATA "[nge ]"--/ngeq N: not greater-than-or-equal-->
+<!ENTITY nges SDATA "[nges ]"--/ngeqslant N: not gt-or-eq, slanted-->
+<!ENTITY ngt SDATA "[ngt ]"--/ngtr N: not greater-than-->
+<!ENTITY nle SDATA "[nle ]"--/nleq N: not less-than-or-equal-->
+<!ENTITY nlE SDATA "[nlE ]"--/nleqq N: not less, dbl equals-->
+<!ENTITY nles SDATA "[nles ]"--/nleqslant N: not less-or-eq, slant-->
+<!ENTITY nlt SDATA "[nlt ]"--/nless N: not less-than-->
+<!ENTITY nltri SDATA "[nltri ]"--/ntriangleleft N: not left triangle-->
+<!ENTITY nltrie SDATA "[nltrie]"--/ntrianglelefteq N: not l tri, eq-->
+<!ENTITY nmid SDATA "[nmid ]"--/nmid-->
+<!ENTITY npar SDATA "[npar ]"--/nparallel N: not parallel-->
+<!ENTITY npr SDATA "[npr ]"--/nprec N: not precedes-->
+<!ENTITY npre SDATA "[npre ]"--/npreceq N: not precedes, equals-->
+<!ENTITY nrtri SDATA "[nrtri ]"--/ntriangleright N: not rt triangle-->
+<!ENTITY nrtrie SDATA "[nrtrie]"--/ntrianglerighteq N: not r tri, eq-->
+<!ENTITY nsc SDATA "[nsc ]"--/nsucc N: not succeeds-->
+<!ENTITY nsce SDATA "[nsce ]"--/nsucceq N: not succeeds, equals-->
+<!ENTITY nsim SDATA "[nsim ]"--/nsim N: not similar-->
+<!ENTITY nsime SDATA "[nsime ]"--/nsimeq N: not similar, equals-->
+<!ENTITY nsmid SDATA "[nsmid ]"--/nshortmid-->
+<!ENTITY nspar SDATA "[nspar ]"--/nshortparallel N: not short par-->
+<!ENTITY nsub SDATA "[nsub ]"--/nsubset N: not subset-->
+<!ENTITY nsube SDATA "[nsube ]"--/nsubseteq N: not subset, equals-->
+<!ENTITY nsubE SDATA "[nsubE ]"--/nsubseteqq N: not subset, dbl eq-->
+<!ENTITY nsup SDATA "[nsup ]"--/nsupset N: not superset-->
+<!ENTITY nsupE SDATA "[nsupE ]"--/nsupseteqq N: not superset, dbl eq-->
+<!ENTITY nsupe SDATA "[nsupe ]"--/nsupseteq N: not superset, equals-->
+<!ENTITY nvdash SDATA "[nvdash]"--/nvdash N: not vertical, dash-->
+<!ENTITY nvDash SDATA "[nvDash]"--/nvDash N: not vertical, dbl dash-->
+<!ENTITY nVDash SDATA "[nVDash]"--/nVDash N: not dbl vert, dbl dash-->
+<!ENTITY nVdash SDATA "[nVdash]"--/nVdash N: not dbl vertical, dash-->
+<!ENTITY prnap SDATA "[prnap ]"--/precnapprox N: precedes, not approx-->
+<!ENTITY prnE SDATA "[prnE ]"--/precneqq N: precedes, not dbl eq-->
+<!ENTITY prnsim SDATA "[prnsim]"--/precnsim N: precedes, not similar-->
+<!ENTITY scnap SDATA "[scnap ]"--/succnapprox N: succeeds, not approx-->
+<!ENTITY scnE SDATA "[scnE ]"--/succneqq N: succeeds, not dbl eq-->
+<!ENTITY scnsim SDATA "[scnsim]"--/succnsim N: succeeds, not similar-->
+<!ENTITY subne SDATA "[subne ]"--/subsetneq N: subset, not equals-->
+<!ENTITY subnE SDATA "[subnE ]"--/subsetneqq N: subset, not dbl eq-->
+<!ENTITY supne SDATA "[supne ]"--/supsetneq N: superset, not equals-->
+<!ENTITY supnE SDATA "[supnE ]"--/supsetneqq N: superset, not dbl eq-->
+<!ENTITY vsubnE SDATA "[vsubnE]"--/subsetneqq N: subset not dbl eq, var-->
+<!ENTITY vsubne SDATA "[vsubne]"--/subsetneq N: subset, not eq, var-->
+<!ENTITY vsupne SDATA "[vsupne]"--/supsetneq N: superset, not eq, var-->
+<!ENTITY vsupnE SDATA "[vsupnE]"--/supsetneqq N: super not dbl eq, var-->
diff --git a/docs/docbook/dbsgml/ent/ISOamso b/docs/docbook/dbsgml/ent/ISOamso
new file mode 100644
index 00000000000..ad9b329e54d
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamso
@@ -0,0 +1,29 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamso PUBLIC
+ "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN">
+ %ISOamso;
+-->
+<!ENTITY ang SDATA "[ang ]"--/angle - angle-->
+<!ENTITY angmsd SDATA "[angmsd]"--/measuredangle - angle-measured-->
+<!ENTITY beth SDATA "[beth ]"--/beth - beth, Hebrew-->
+<!ENTITY bprime SDATA "[bprime]"--/backprime - reverse prime-->
+<!ENTITY comp SDATA "[comp ]"--/complement - complement sign-->
+<!ENTITY daleth SDATA "[daleth]"--/daleth - daleth, Hebrew-->
+<!ENTITY ell SDATA "[ell ]"--/ell - cursive small l-->
+<!ENTITY empty SDATA "[empty ]"--/emptyset /varnothing =small o, slash-->
+<!ENTITY gimel SDATA "[gimel ]"--/gimel - gimel, Hebrew-->
+<!ENTITY image SDATA "[image ]"--/Im - imaginary-->
+<!ENTITY inodot SDATA "[inodot]"--/imath =small i, no dot-->
+<!ENTITY jnodot SDATA "[jnodot]"--/jmath - small j, no dot-->
+<!ENTITY nexist SDATA "[nexist]"--/nexists - negated exists-->
+<!ENTITY oS SDATA "[oS ]"--/circledS - capital S in circle-->
+<!ENTITY planck SDATA "[planck]"--/hbar /hslash - Planck's over 2pi-->
+<!ENTITY real SDATA "[real ]"--/Re - real-->
+<!ENTITY sbsol SDATA "[sbsol ]"--/sbs - short reverse solidus-->
+<!ENTITY vprime SDATA "[vprime]"--/varprime - prime, variant-->
+<!ENTITY weierp SDATA "[weierp]"--/wp - Weierstrass p-->
diff --git a/docs/docbook/dbsgml/ent/ISOamsr b/docs/docbook/dbsgml/ent/ISOamsr
new file mode 100644
index 00000000000..3f26c345c04
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOamsr
@@ -0,0 +1,94 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOamsr PUBLIC
+ "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN">
+ %ISOamsr;
+-->
+<!ENTITY ape SDATA "[ape ]"--/approxeq R: approximate, equals-->
+<!ENTITY asymp SDATA "[asymp ]"--/asymp R: asymptotically equal to-->
+<!ENTITY bcong SDATA "[bcong ]"--/backcong R: reverse congruent-->
+<!ENTITY bepsi SDATA "[bepsi ]"--/backepsilon R: such that-->
+<!ENTITY bowtie SDATA "[bowtie]"--/bowtie R:-->
+<!ENTITY bsim SDATA "[bsim ]"--/backsim R: reverse similar-->
+<!ENTITY bsime SDATA "[bsime ]"--/backsimeq R: reverse similar, eq-->
+<!ENTITY bump SDATA "[bump ]"--/Bumpeq R: bumpy equals-->
+<!ENTITY bumpe SDATA "[bumpe ]"--/bumpeq R: bumpy equals, equals-->
+<!ENTITY cire SDATA "[cire ]"--/circeq R: circle, equals-->
+<!ENTITY colone SDATA "[colone]"--/coloneq R: colon, equals-->
+<!ENTITY cuepr SDATA "[cuepr ]"--/curlyeqprec R: curly eq, precedes-->
+<!ENTITY cuesc SDATA "[cuesc ]"--/curlyeqsucc R: curly eq, succeeds-->
+<!ENTITY cupre SDATA "[cupre ]"--/curlypreceq R: curly precedes, eq-->
+<!ENTITY dashv SDATA "[dashv ]"--/dashv R: dash, vertical-->
+<!ENTITY ecir SDATA "[ecir ]"--/eqcirc R: circle on equals sign-->
+<!ENTITY ecolon SDATA "[ecolon]"--/eqcolon R: equals, colon-->
+<!ENTITY eDot SDATA "[eDot ]"--/doteqdot /Doteq R: eq, even dots-->
+<!ENTITY esdot SDATA "[esdot ]"--/doteq R: equals, single dot above-->
+<!ENTITY efDot SDATA "[efDot ]"--/fallingdotseq R: eq, falling dots-->
+<!ENTITY egs SDATA "[egs ]"--/eqslantgtr R: equal-or-gtr, slanted-->
+<!ENTITY els SDATA "[els ]"--/eqslantless R: eq-or-less, slanted-->
+<!ENTITY erDot SDATA "[erDot ]"--/risingdotseq R: eq, rising dots-->
+<!ENTITY fork SDATA "[fork ]"--/pitchfork R: pitchfork-->
+<!ENTITY frown SDATA "[frown ]"--/frown R: down curve-->
+<!ENTITY gap SDATA "[gap ]"--/gtrapprox R: greater, approximate-->
+<!ENTITY gsdot SDATA "[gsdot ]"--/gtrdot R: greater than, single dot-->
+<!ENTITY gE SDATA "[gE ]"--/geqq R: greater, double equals-->
+<!ENTITY gel SDATA "[gel ]"--/gtreqless R: greater, equals, less-->
+<!ENTITY gEl SDATA "[gEl ]"--/gtreqqless R: gt, dbl equals, less-->
+<!ENTITY ges SDATA "[ges ]"--/geqslant R: gt-or-equal, slanted-->
+<!ENTITY Gg SDATA "[Gg ]"--/ggg /Gg /gggtr R: triple gtr-than-->
+<!ENTITY gl SDATA "[gl ]"--/gtrless R: greater, less-->
+<!ENTITY gsim SDATA "[gsim ]"--/gtrsim R: greater, similar-->
+<!ENTITY Gt SDATA "[Gt ]"--/gg R: dbl greater-than sign-->
+<!ENTITY lap SDATA "[lap ]"--/lessapprox R: less, approximate-->
+<!ENTITY ldot SDATA "[ldot ]"--/lessdot R: less than, with dot-->
+<!ENTITY lE SDATA "[lE ]"--/leqq R: less, double equals-->
+<!ENTITY lEg SDATA "[lEg ]"--/lesseqqgtr R: less, dbl eq, greater-->
+<!ENTITY leg SDATA "[leg ]"--/lesseqgtr R: less, eq, greater-->
+<!ENTITY les SDATA "[les ]"--/leqslant R: less-than-or-eq, slant-->
+<!ENTITY lg SDATA "[lg ]"--/lessgtr R: less, greater-->
+<!ENTITY Ll SDATA "[Ll ]"--/Ll /lll /llless R: triple less-than-->
+<!ENTITY lsim SDATA "[lsim ]"--/lesssim R: less, similar-->
+<!ENTITY Lt SDATA "[Lt ]"--/ll R: double less-than sign-->
+<!ENTITY ltrie SDATA "[ltrie ]"--/trianglelefteq R: left triangle, eq-->
+<!ENTITY mid SDATA "[mid ]"--/mid R:-->
+<!ENTITY models SDATA "[models]"--/models R:-->
+<!ENTITY pr SDATA "[pr ]"--/prec R: precedes-->
+<!ENTITY prap SDATA "[prap ]"--/precapprox R: precedes, approximate-->
+<!ENTITY pre SDATA "[pre ]"--/preceq R: precedes, equals-->
+<!ENTITY prsim SDATA "[prsim ]"--/precsim R: precedes, similar-->
+<!ENTITY rtrie SDATA "[rtrie ]"--/trianglerighteq R: right tri, eq-->
+<!ENTITY samalg SDATA "[samalg]"--/smallamalg R: small amalg-->
+<!ENTITY sc SDATA "[sc ]"--/succ R: succeeds-->
+<!ENTITY scap SDATA "[scap ]"--/succapprox R: succeeds, approximate-->
+<!ENTITY sccue SDATA "[sccue ]"--/succcurlyeq R: succeeds, curly eq-->
+<!ENTITY sce SDATA "[sce ]"--/succeq R: succeeds, equals-->
+<!ENTITY scsim SDATA "[scsim ]"--/succsim R: succeeds, similar-->
+<!ENTITY sfrown SDATA "[sfrown]"--/smallfrown R: small down curve-->
+<!ENTITY smid SDATA "[smid ]"--/shortmid R:-->
+<!ENTITY smile SDATA "[smile ]"--/smile R: up curve-->
+<!ENTITY spar SDATA "[spar ]"--/shortparallel R: short parallel-->
+<!ENTITY sqsub SDATA "[sqsub ]"--/sqsubset R: square subset-->
+<!ENTITY sqsube SDATA "[sqsube]"--/sqsubseteq R: square subset, equals-->
+<!ENTITY sqsup SDATA "[sqsup ]"--/sqsupset R: square superset-->
+<!ENTITY sqsupe SDATA "[sqsupe]"--/sqsupseteq R: square superset, eq-->
+<!ENTITY ssmile SDATA "[ssmile]"--/smallsmile R: small up curve-->
+<!ENTITY Sub SDATA "[Sub ]"--/Subset R: double subset-->
+<!ENTITY subE SDATA "[subE ]"--/subseteqq R: subset, dbl equals-->
+<!ENTITY Sup SDATA "[Sup ]"--/Supset R: dbl superset-->
+<!ENTITY supE SDATA "[supE ]"--/supseteqq R: superset, dbl equals-->
+<!ENTITY thkap SDATA "[thkap ]"--/thickapprox R: thick approximate-->
+<!ENTITY thksim SDATA "[thksim]"--/thicksim R: thick similar-->
+<!ENTITY trie SDATA "[trie ]"--/triangleq R: triangle, equals-->
+<!ENTITY twixt SDATA "[twixt ]"--/between R: between-->
+<!ENTITY vdash SDATA "[vdash ]"--/vdash R: vertical, dash-->
+<!ENTITY Vdash SDATA "[Vdash ]"--/Vdash R: dbl vertical, dash-->
+<!ENTITY vDash SDATA "[vDash ]"--/vDash R: vertical, dbl dash-->
+<!ENTITY veebar SDATA "[veebar]"--/veebar R: logical or, bar below-->
+<!ENTITY vltri SDATA "[vltri ]"--/vartriangleleft R: l tri, open, var-->
+<!ENTITY vprop SDATA "[vprop ]"--/varpropto R: proportional, variant-->
+<!ENTITY vrtri SDATA "[vrtri ]"--/vartriangleright R: r tri, open, var-->
+<!ENTITY Vvdash SDATA "[Vvdash]"--/Vvdash R: triple vertical, dash-->
diff --git a/docs/docbook/dbsgml/ent/ISObox b/docs/docbook/dbsgml/ent/ISObox
new file mode 100644
index 00000000000..643e926edaa
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISObox
@@ -0,0 +1,62 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISObox PUBLIC
+ "ISO 8879:1986//ENTITIES Box and Line Drawing//EN">
+ %ISObox;
+-->
+<!-- All names are in the form: box1234, where:
+ box = constants that identify a box drawing entity.
+ 1&2 = v, V, u, U, d, D, Ud, or uD, as follows:
+ v = vertical line for full height.
+ u = upper half of vertical line.
+ d = downward (lower) half of vertical line.
+ 3&4 = h, H, l, L, r, R, Lr, or lR, as follows:
+ h = horizontal line for full width.
+ l = left half of horizontal line.
+ r = right half of horizontal line.
+ In all cases, an upper-case letter means a double or heavy line.
+-->
+<!ENTITY boxh SDATA "[boxh ]"--horizontal line -->
+<!ENTITY boxv SDATA "[boxv ]"--vertical line-->
+<!ENTITY boxur SDATA "[boxur ]"--upper right quadrant-->
+<!ENTITY boxul SDATA "[boxul ]"--upper left quadrant-->
+<!ENTITY boxdl SDATA "[boxdl ]"--lower left quadrant-->
+<!ENTITY boxdr SDATA "[boxdr ]"--lower right quadrant-->
+<!ENTITY boxvr SDATA "[boxvr ]"--upper and lower right quadrants-->
+<!ENTITY boxhu SDATA "[boxhu ]"--upper left and right quadrants-->
+<!ENTITY boxvl SDATA "[boxvl ]"--upper and lower left quadrants-->
+<!ENTITY boxhd SDATA "[boxhd ]"--lower left and right quadrants-->
+<!ENTITY boxvh SDATA "[boxvh ]"--all four quadrants-->
+<!ENTITY boxvR SDATA "[boxvR ]"--upper and lower right quadrants-->
+<!ENTITY boxhU SDATA "[boxhU ]"--upper left and right quadrants-->
+<!ENTITY boxvL SDATA "[boxvL ]"--upper and lower left quadrants-->
+<!ENTITY boxhD SDATA "[boxhD ]"--lower left and right quadrants-->
+<!ENTITY boxvH SDATA "[boxvH ]"--all four quadrants-->
+<!ENTITY boxH SDATA "[boxH ]"--horizontal line-->
+<!ENTITY boxV SDATA "[boxV ]"--vertical line-->
+<!ENTITY boxUR SDATA "[boxUR ]"--upper right quadrant-->
+<!ENTITY boxUL SDATA "[boxUL ]"--upper left quadrant-->
+<!ENTITY boxDL SDATA "[boxDL ]"--lower left quadrant-->
+<!ENTITY boxDR SDATA "[boxDR ]"--lower right quadrant-->
+<!ENTITY boxVR SDATA "[boxVR ]"--upper and lower right quadrants-->
+<!ENTITY boxHU SDATA "[boxHU ]"--upper left and right quadrants-->
+<!ENTITY boxVL SDATA "[boxVL ]"--upper and lower left quadrants-->
+<!ENTITY boxHD SDATA "[boxHD ]"--lower left and right quadrants-->
+<!ENTITY boxVH SDATA "[boxVH ]"--all four quadrants-->
+<!ENTITY boxVr SDATA "[boxVr ]"--upper and lower right quadrants-->
+<!ENTITY boxHu SDATA "[boxHu ]"--upper left and right quadrants-->
+<!ENTITY boxVl SDATA "[boxVl ]"--upper and lower left quadrants-->
+<!ENTITY boxHd SDATA "[boxHd ]"--lower left and right quadrants-->
+<!ENTITY boxVh SDATA "[boxVh ]"--all four quadrants-->
+<!ENTITY boxuR SDATA "[boxuR ]"--upper right quadrant-->
+<!ENTITY boxUl SDATA "[boxUl ]"--upper left quadrant-->
+<!ENTITY boxdL SDATA "[boxdL ]"--lower left quadrant-->
+<!ENTITY boxDr SDATA "[boxDr ]"--lower right quadrant-->
+<!ENTITY boxUr SDATA "[boxUr ]"--upper right quadrant-->
+<!ENTITY boxuL SDATA "[boxuL ]"--upper left quadrant-->
+<!ENTITY boxDl SDATA "[boxDl ]"--lower left quadrant-->
+<!ENTITY boxdR SDATA "[boxdR ]"--lower right quadrant-->
diff --git a/docs/docbook/dbsgml/ent/ISOcyr1 b/docs/docbook/dbsgml/ent/ISOcyr1
new file mode 100644
index 00000000000..97b961b1f0b
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOcyr1
@@ -0,0 +1,77 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOcyr1 PUBLIC
+ "ISO 8879:1986//ENTITIES Russian Cyrillic//EN">
+ %ISOcyr1;
+-->
+<!ENTITY acy SDATA "[acy ]"--=small a, Cyrillic-->
+<!ENTITY Acy SDATA "[Acy ]"--=capital A, Cyrillic-->
+<!ENTITY bcy SDATA "[bcy ]"--=small be, Cyrillic-->
+<!ENTITY Bcy SDATA "[Bcy ]"--=capital BE, Cyrillic-->
+<!ENTITY vcy SDATA "[vcy ]"--=small ve, Cyrillic-->
+<!ENTITY Vcy SDATA "[Vcy ]"--=capital VE, Cyrillic-->
+<!ENTITY gcy SDATA "[gcy ]"--=small ghe, Cyrillic-->
+<!ENTITY Gcy SDATA "[Gcy ]"--=capital GHE, Cyrillic-->
+<!ENTITY dcy SDATA "[dcy ]"--=small de, Cyrillic-->
+<!ENTITY Dcy SDATA "[Dcy ]"--=capital DE, Cyrillic-->
+<!ENTITY iecy SDATA "[iecy ]"--=small ie, Cyrillic-->
+<!ENTITY IEcy SDATA "[IEcy ]"--=capital IE, Cyrillic-->
+<!ENTITY iocy SDATA "[iocy ]"--=small io, Russian-->
+<!ENTITY IOcy SDATA "[IOcy ]"--=capital IO, Russian-->
+<!ENTITY zhcy SDATA "[zhcy ]"--=small zhe, Cyrillic-->
+<!ENTITY ZHcy SDATA "[ZHcy ]"--=capital ZHE, Cyrillic-->
+<!ENTITY zcy SDATA "[zcy ]"--=small ze, Cyrillic-->
+<!ENTITY Zcy SDATA "[Zcy ]"--=capital ZE, Cyrillic-->
+<!ENTITY icy SDATA "[icy ]"--=small i, Cyrillic-->
+<!ENTITY Icy SDATA "[Icy ]"--=capital I, Cyrillic-->
+<!ENTITY jcy SDATA "[jcy ]"--=small short i, Cyrillic-->
+<!ENTITY Jcy SDATA "[Jcy ]"--=capital short I, Cyrillic-->
+<!ENTITY kcy SDATA "[kcy ]"--=small ka, Cyrillic-->
+<!ENTITY Kcy SDATA "[Kcy ]"--=capital KA, Cyrillic-->
+<!ENTITY lcy SDATA "[lcy ]"--=small el, Cyrillic-->
+<!ENTITY Lcy SDATA "[Lcy ]"--=capital EL, Cyrillic-->
+<!ENTITY mcy SDATA "[mcy ]"--=small em, Cyrillic-->
+<!ENTITY Mcy SDATA "[Mcy ]"--=capital EM, Cyrillic-->
+<!ENTITY ncy SDATA "[ncy ]"--=small en, Cyrillic-->
+<!ENTITY Ncy SDATA "[Ncy ]"--=capital EN, Cyrillic-->
+<!ENTITY ocy SDATA "[ocy ]"--=small o, Cyrillic-->
+<!ENTITY Ocy SDATA "[Ocy ]"--=capital O, Cyrillic-->
+<!ENTITY pcy SDATA "[pcy ]"--=small pe, Cyrillic-->
+<!ENTITY Pcy SDATA "[Pcy ]"--=capital PE, Cyrillic-->
+<!ENTITY rcy SDATA "[rcy ]"--=small er, Cyrillic-->
+<!ENTITY Rcy SDATA "[Rcy ]"--=capital ER, Cyrillic-->
+<!ENTITY scy SDATA "[scy ]"--=small es, Cyrillic-->
+<!ENTITY Scy SDATA "[Scy ]"--=capital ES, Cyrillic-->
+<!ENTITY tcy SDATA "[tcy ]"--=small te, Cyrillic-->
+<!ENTITY Tcy SDATA "[Tcy ]"--=capital TE, Cyrillic-->
+<!ENTITY ucy SDATA "[ucy ]"--=small u, Cyrillic-->
+<!ENTITY Ucy SDATA "[Ucy ]"--=capital U, Cyrillic-->
+<!ENTITY fcy SDATA "[fcy ]"--=small ef, Cyrillic-->
+<!ENTITY Fcy SDATA "[Fcy ]"--=capital EF, Cyrillic-->
+<!ENTITY khcy SDATA "[khcy ]"--=small ha, Cyrillic-->
+<!ENTITY KHcy SDATA "[KHcy ]"--=capital HA, Cyrillic-->
+<!ENTITY tscy SDATA "[tscy ]"--=small tse, Cyrillic-->
+<!ENTITY TScy SDATA "[TScy ]"--=capital TSE, Cyrillic-->
+<!ENTITY chcy SDATA "[chcy ]"--=small che, Cyrillic-->
+<!ENTITY CHcy SDATA "[CHcy ]"--=capital CHE, Cyrillic-->
+<!ENTITY shcy SDATA "[shcy ]"--=small sha, Cyrillic-->
+<!ENTITY SHcy SDATA "[SHcy ]"--=capital SHA, Cyrillic-->
+<!ENTITY shchcy SDATA "[shchcy]"--=small shcha, Cyrillic-->
+<!ENTITY SHCHcy SDATA "[SHCHcy]"--=capital SHCHA, Cyrillic-->
+<!ENTITY hardcy SDATA "[hardcy]"--=small hard sign, Cyrillic-->
+<!ENTITY HARDcy SDATA "[HARDcy]"--=capital HARD sign, Cyrillic-->
+<!ENTITY ycy SDATA "[ycy ]"--=small yeru, Cyrillic-->
+<!ENTITY Ycy SDATA "[Ycy ]"--=capital YERU, Cyrillic-->
+<!ENTITY softcy SDATA "[softcy]"--=small soft sign, Cyrillic-->
+<!ENTITY SOFTcy SDATA "[SOFTcy]"--=capital SOFT sign, Cyrillic-->
+<!ENTITY ecy SDATA "[ecy ]"--=small e, Cyrillic-->
+<!ENTITY Ecy SDATA "[Ecy ]"--=capital E, Cyrillic-->
+<!ENTITY yucy SDATA "[yucy ]"--=small yu, Cyrillic-->
+<!ENTITY YUcy SDATA "[YUcy ]"--=capital YU, Cyrillic-->
+<!ENTITY yacy SDATA "[yacy ]"--=small ya, Cyrillic-->
+<!ENTITY YAcy SDATA "[YAcy ]"--=capital YA, Cyrillic-->
+<!ENTITY numero SDATA "[numero]"--=numero sign-->
diff --git a/docs/docbook/dbsgml/ent/ISOcyr2 b/docs/docbook/dbsgml/ent/ISOcyr2
new file mode 100644
index 00000000000..480b01c1df4
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOcyr2
@@ -0,0 +1,36 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOcyr2 PUBLIC
+ "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN">
+ %ISOcyr2;
+-->
+<!ENTITY djcy SDATA "[djcy ]"--=small dje, Serbian-->
+<!ENTITY DJcy SDATA "[DJcy ]"--=capital DJE, Serbian-->
+<!ENTITY gjcy SDATA "[gjcy ]"--=small gje, Macedonian-->
+<!ENTITY GJcy SDATA "[GJcy ]"--=capital GJE Macedonian-->
+<!ENTITY jukcy SDATA "[jukcy ]"--=small je, Ukrainian-->
+<!ENTITY Jukcy SDATA "[Jukcy ]"--=capital JE, Ukrainian-->
+<!ENTITY dscy SDATA "[dscy ]"--=small dse, Macedonian-->
+<!ENTITY DScy SDATA "[DScy ]"--=capital DSE, Macedonian-->
+<!ENTITY iukcy SDATA "[iukcy ]"--=small i, Ukrainian-->
+<!ENTITY Iukcy SDATA "[Iukcy ]"--=capital I, Ukrainian-->
+<!ENTITY yicy SDATA "[yicy ]"--=small yi, Ukrainian-->
+<!ENTITY YIcy SDATA "[YIcy ]"--=capital YI, Ukrainian-->
+<!ENTITY jsercy SDATA "[jsercy]"--=small je, Serbian-->
+<!ENTITY Jsercy SDATA "[Jsercy]"--=capital JE, Serbian-->
+<!ENTITY ljcy SDATA "[ljcy ]"--=small lje, Serbian-->
+<!ENTITY LJcy SDATA "[LJcy ]"--=capital LJE, Serbian-->
+<!ENTITY njcy SDATA "[njcy ]"--=small nje, Serbian-->
+<!ENTITY NJcy SDATA "[NJcy ]"--=capital NJE, Serbian-->
+<!ENTITY tshcy SDATA "[tshcy ]"--=small tshe, Serbian-->
+<!ENTITY TSHcy SDATA "[TSHcy ]"--=capital TSHE, Serbian-->
+<!ENTITY kjcy SDATA "[kjcy ]"--=small kje Macedonian-->
+<!ENTITY KJcy SDATA "[KJcy ]"--=capital KJE, Macedonian-->
+<!ENTITY ubrcy SDATA "[ubrcy ]"--=small u, Byelorussian-->
+<!ENTITY Ubrcy SDATA "[Ubrcy ]"--=capital U, Byelorussian-->
+<!ENTITY dzcy SDATA "[dzcy ]"--=small dze, Serbian-->
+<!ENTITY DZcy SDATA "[DZcy ]"--=capital dze, Serbian-->
diff --git a/docs/docbook/dbsgml/ent/ISOdia b/docs/docbook/dbsgml/ent/ISOdia
new file mode 100644
index 00000000000..3b6f98d6baa
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOdia
@@ -0,0 +1,24 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOdia PUBLIC
+ "ISO 8879:1986//ENTITIES Diacritical Marks//EN">
+ %ISOdia;
+-->
+<!ENTITY acute SDATA "[acute ]"--=acute accent-->
+<!ENTITY breve SDATA "[breve ]"--=breve-->
+<!ENTITY caron SDATA "[caron ]"--=caron-->
+<!ENTITY cedil SDATA "[cedil ]"--=cedilla-->
+<!ENTITY circ SDATA "[circ ]"--=circumflex accent-->
+<!ENTITY dblac SDATA "[dblac ]"--=double acute accent-->
+<!ENTITY die SDATA "[die ]"--=dieresis-->
+<!ENTITY dot SDATA "[dot ]"--=dot above-->
+<!ENTITY grave SDATA "[grave ]"--=grave accent-->
+<!ENTITY macr SDATA "[macr ]"--=macron-->
+<!ENTITY ogon SDATA "[ogon ]"--=ogonek-->
+<!ENTITY ring SDATA "[ring ]"--=ring-->
+<!ENTITY tilde SDATA "[tilde ]"--=tilde-->
+<!ENTITY uml SDATA "[uml ]"--=umlaut mark-->
diff --git a/docs/docbook/dbsgml/ent/ISOgrk1 b/docs/docbook/dbsgml/ent/ISOgrk1
new file mode 100644
index 00000000000..dea16bf8ef9
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOgrk1
@@ -0,0 +1,59 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOgrk1 PUBLIC
+ "ISO 8879:1986//ENTITIES Greek Letters//EN">
+ %ISOgrk1;
+-->
+<!ENTITY agr SDATA "[agr ]"--=small alpha, Greek-->
+<!ENTITY Agr SDATA "[Agr ]"--=capital Alpha, Greek-->
+<!ENTITY bgr SDATA "[bgr ]"--=small beta, Greek-->
+<!ENTITY Bgr SDATA "[Bgr ]"--=capital Beta, Greek-->
+<!ENTITY ggr SDATA "[ggr ]"--=small gamma, Greek-->
+<!ENTITY Ggr SDATA "[Ggr ]"--=capital Gamma, Greek-->
+<!ENTITY dgr SDATA "[dgr ]"--=small delta, Greek-->
+<!ENTITY Dgr SDATA "[Dgr ]"--=capital Delta, Greek-->
+<!ENTITY egr SDATA "[egr ]"--=small epsilon, Greek-->
+<!ENTITY Egr SDATA "[Egr ]"--=capital Epsilon, Greek-->
+<!ENTITY zgr SDATA "[zgr ]"--=small zeta, Greek-->
+<!ENTITY Zgr SDATA "[Zgr ]"--=capital Zeta, Greek-->
+<!ENTITY eegr SDATA "[eegr ]"--=small eta, Greek-->
+<!ENTITY EEgr SDATA "[EEgr ]"--=capital Eta, Greek-->
+<!ENTITY thgr SDATA "[thgr ]"--=small theta, Greek-->
+<!ENTITY THgr SDATA "[THgr ]"--=capital Theta, Greek-->
+<!ENTITY igr SDATA "[igr ]"--=small iota, Greek-->
+<!ENTITY Igr SDATA "[Igr ]"--=capital Iota, Greek-->
+<!ENTITY kgr SDATA "[kgr ]"--=small kappa, Greek-->
+<!ENTITY Kgr SDATA "[Kgr ]"--=capital Kappa, Greek-->
+<!ENTITY lgr SDATA "[lgr ]"--=small lambda, Greek-->
+<!ENTITY Lgr SDATA "[Lgr ]"--=capital Lambda, Greek-->
+<!ENTITY mgr SDATA "[mgr ]"--=small mu, Greek-->
+<!ENTITY Mgr SDATA "[Mgr ]"--=capital Mu, Greek-->
+<!ENTITY ngr SDATA "[ngr ]"--=small nu, Greek-->
+<!ENTITY Ngr SDATA "[Ngr ]"--=capital Nu, Greek-->
+<!ENTITY xgr SDATA "[xgr ]"--=small xi, Greek-->
+<!ENTITY Xgr SDATA "[Xgr ]"--=capital Xi, Greek-->
+<!ENTITY ogr SDATA "[ogr ]"--=small omicron, Greek-->
+<!ENTITY Ogr SDATA "[Ogr ]"--=capital Omicron, Greek-->
+<!ENTITY pgr SDATA "[pgr ]"--=small pi, Greek-->
+<!ENTITY Pgr SDATA "[Pgr ]"--=capital Pi, Greek-->
+<!ENTITY rgr SDATA "[rgr ]"--=small rho, Greek-->
+<!ENTITY Rgr SDATA "[Rgr ]"--=capital Rho, Greek-->
+<!ENTITY sgr SDATA "[sgr ]"--=small sigma, Greek-->
+<!ENTITY Sgr SDATA "[Sgr ]"--=capital Sigma, Greek-->
+<!ENTITY sfgr SDATA "[sfgr ]"--=final small sigma, Greek-->
+<!ENTITY tgr SDATA "[tgr ]"--=small tau, Greek-->
+<!ENTITY Tgr SDATA "[Tgr ]"--=capital Tau, Greek-->
+<!ENTITY ugr SDATA "[ugr ]"--=small upsilon, Greek-->
+<!ENTITY Ugr SDATA "[Ugr ]"--=capital Upsilon, Greek-->
+<!ENTITY phgr SDATA "[phgr ]"--=small phi, Greek-->
+<!ENTITY PHgr SDATA "[PHgr ]"--=capital Phi, Greek-->
+<!ENTITY khgr SDATA "[khgr ]"--=small chi, Greek-->
+<!ENTITY KHgr SDATA "[KHgr ]"--=capital Chi, Greek-->
+<!ENTITY psgr SDATA "[psgr ]"--=small psi, Greek-->
+<!ENTITY PSgr SDATA "[PSgr ]"--=capital Psi, Greek-->
+<!ENTITY ohgr SDATA "[ohgr ]"--=small omega, Greek-->
+<!ENTITY OHgr SDATA "[OHgr ]"--=capital Omega, Greek-->
diff --git a/docs/docbook/dbsgml/ent/ISOgrk2 b/docs/docbook/dbsgml/ent/ISOgrk2
new file mode 100644
index 00000000000..657bb99935e
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOgrk2
@@ -0,0 +1,30 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOgrk2 PUBLIC
+ "ISO 8879:1986//ENTITIES Monotoniko Greek//EN">
+ %ISOgrk2;
+-->
+<!ENTITY aacgr SDATA "[aacgr ]"--=small alpha, accent, Greek-->
+<!ENTITY Aacgr SDATA "[Aacgr ]"--=capital Alpha, accent, Greek-->
+<!ENTITY eacgr SDATA "[eacgr ]"--=small epsilon, accent, Greek-->
+<!ENTITY Eacgr SDATA "[Eacgr ]"--=capital Epsilon, accent, Greek-->
+<!ENTITY eeacgr SDATA "[eeacgr]"--=small eta, accent, Greek-->
+<!ENTITY EEacgr SDATA "[EEacgr]"--=capital Eta, accent, Greek-->
+<!ENTITY idigr SDATA "[idigr ]"--=small iota, dieresis, Greek-->
+<!ENTITY Idigr SDATA "[Idigr ]"--=capital Iota, dieresis, Greek-->
+<!ENTITY iacgr SDATA "[iacgr ]"--=small iota, accent, Greek-->
+<!ENTITY Iacgr SDATA "[Iacgr ]"--=capital Iota, accent, Greek-->
+<!ENTITY idiagr SDATA "[idiagr]"--=small iota, dieresis, accent, Greek-->
+<!ENTITY oacgr SDATA "[oacgr ]"--=small omicron, accent, Greek-->
+<!ENTITY Oacgr SDATA "[Oacgr ]"--=capital Omicron, accent, Greek-->
+<!ENTITY udigr SDATA "[udigr ]"--=small upsilon, dieresis, Greek-->
+<!ENTITY Udigr SDATA "[Udigr ]"--=capital Upsilon, dieresis, Greek-->
+<!ENTITY uacgr SDATA "[uacgr ]"--=small upsilon, accent, Greek-->
+<!ENTITY Uacgr SDATA "[Uacgr ]"--=capital Upsilon, accent, Greek-->
+<!ENTITY udiagr SDATA "[udiagr]"--=small upsilon, dieresis, accent, Greek-->
+<!ENTITY ohacgr SDATA "[ohacgr]"--=small omega, accent, Greek-->
+<!ENTITY OHacgr SDATA "[OHacgr]"--=capital Omega, accent, Greek-->
diff --git a/docs/docbook/dbsgml/ent/ISOgrk3 b/docs/docbook/dbsgml/ent/ISOgrk3
new file mode 100644
index 00000000000..f76c3a084f3
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOgrk3
@@ -0,0 +1,53 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOgrk3 PUBLIC
+ "ISO 8879:1986//ENTITIES Greek Symbols//EN">
+ %ISOgrk3;
+-->
+<!ENTITY alpha SDATA "[alpha ]"--=small alpha, Greek-->
+<!ENTITY beta SDATA "[beta ]"--=small beta, Greek-->
+<!ENTITY gamma SDATA "[gamma ]"--=small gamma, Greek-->
+<!ENTITY Gamma SDATA "[Gamma ]"--=capital Gamma, Greek-->
+<!ENTITY gammad SDATA "[gammad]"--/digamma-->
+<!ENTITY delta SDATA "[delta ]"--=small delta, Greek-->
+<!ENTITY Delta SDATA "[Delta ]"--=capital Delta, Greek-->
+<!ENTITY epsi SDATA "[epsi ]"--=small epsilon, Greek-->
+<!ENTITY epsiv SDATA "[epsiv ]"--/varepsilon-->
+<!ENTITY epsis SDATA "[epsis ]"--/straightepsilon-->
+<!ENTITY zeta SDATA "[zeta ]"--=small zeta, Greek-->
+<!ENTITY eta SDATA "[eta ]"--=small eta, Greek-->
+<!ENTITY thetas SDATA "[thetas]"--straight theta-->
+<!ENTITY Theta SDATA "[Theta ]"--=capital Theta, Greek-->
+<!ENTITY thetav SDATA "[thetav]"--/vartheta - curly or open theta-->
+<!ENTITY iota SDATA "[iota ]"--=small iota, Greek-->
+<!ENTITY kappa SDATA "[kappa ]"--=small kappa, Greek-->
+<!ENTITY kappav SDATA "[kappav]"--/varkappa-->
+<!ENTITY lambda SDATA "[lambda]"--=small lambda, Greek-->
+<!ENTITY Lambda SDATA "[Lambda]"--=capital Lambda, Greek-->
+<!ENTITY mu SDATA "[mu ]"--=small mu, Greek-->
+<!ENTITY nu SDATA "[nu ]"--=small nu, Greek-->
+<!ENTITY xi SDATA "[xi ]"--=small xi, Greek-->
+<!ENTITY Xi SDATA "[Xi ]"--=capital Xi, Greek-->
+<!ENTITY pi SDATA "[pi ]"--=small pi, Greek-->
+<!ENTITY piv SDATA "[piv ]"--/varpi-->
+<!ENTITY Pi SDATA "[Pi ]"--=capital Pi, Greek-->
+<!ENTITY rho SDATA "[rho ]"--=small rho, Greek-->
+<!ENTITY rhov SDATA "[rhov ]"--/varrho-->
+<!ENTITY sigma SDATA "[sigma ]"--=small sigma, Greek-->
+<!ENTITY Sigma SDATA "[Sigma ]"--=capital Sigma, Greek-->
+<!ENTITY sigmav SDATA "[sigmav]"--/varsigma-->
+<!ENTITY tau SDATA "[tau ]"--=small tau, Greek-->
+<!ENTITY upsi SDATA "[upsi ]"--=small upsilon, Greek-->
+<!ENTITY Upsi SDATA "[Upsi ]"--=capital Upsilon, Greek-->
+<!ENTITY phis SDATA "[phis ]"--/straightphi - straight phi-->
+<!ENTITY Phi SDATA "[Phi ]"--=capital Phi, Greek-->
+<!ENTITY phiv SDATA "[phiv ]"--/varphi - curly or open phi-->
+<!ENTITY chi SDATA "[chi ]"--=small chi, Greek-->
+<!ENTITY psi SDATA "[psi ]"--=small psi, Greek-->
+<!ENTITY Psi SDATA "[Psi ]"--=capital Psi, Greek-->
+<!ENTITY omega SDATA "[omega ]"--=small omega, Greek-->
+<!ENTITY Omega SDATA "[Omega ]"--=capital Omega, Greek-->
diff --git a/docs/docbook/dbsgml/ent/ISOgrk4 b/docs/docbook/dbsgml/ent/ISOgrk4
new file mode 100644
index 00000000000..e4427a0cb54
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOgrk4
@@ -0,0 +1,53 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOgrk4 PUBLIC
+ "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN">
+ %ISOgrk4;
+-->
+<!ENTITY b.alpha SDATA "[b.alpha ]"--=small alpha, Greek-->
+<!ENTITY b.beta SDATA "[b.beta ]"--=small beta, Greek-->
+<!ENTITY b.gamma SDATA "[b.gamma ]"--=small gamma, Greek-->
+<!ENTITY b.Gamma SDATA "[b.Gamma ]"--=capital Gamma, Greek-->
+<!ENTITY b.gammad SDATA "[b.gammad]"--/digamma-->
+<!ENTITY b.delta SDATA "[b.delta ]"--=small delta, Greek-->
+<!ENTITY b.Delta SDATA "[b.Delta ]"--=capital Delta, Greek-->
+<!ENTITY b.epsi SDATA "[b.epsi ]"--=small epsilon, Greek-->
+<!ENTITY b.epsiv SDATA "[b.epsiv ]"--/varepsilon-->
+<!ENTITY b.epsis SDATA "[b.epsis ]"--/straightepsilon-->
+<!ENTITY b.zeta SDATA "[b.zeta ]"--=small zeta, Greek-->
+<!ENTITY b.eta SDATA "[b.eta ]"--=small eta, Greek-->
+<!ENTITY b.thetas SDATA "[b.thetas]"--straight theta-->
+<!ENTITY b.Theta SDATA "[b.Theta ]"--=capital Theta, Greek-->
+<!ENTITY b.thetav SDATA "[b.thetav]"--/vartheta - curly or open theta-->
+<!ENTITY b.iota SDATA "[b.iota ]"--=small iota, Greek-->
+<!ENTITY b.kappa SDATA "[b.kappa ]"--=small kappa, Greek-->
+<!ENTITY b.kappav SDATA "[b.kappav]"--/varkappa-->
+<!ENTITY b.lambda SDATA "[b.lambda]"--=small lambda, Greek-->
+<!ENTITY b.Lambda SDATA "[b.Lambda]"--=capital Lambda, Greek-->
+<!ENTITY b.mu SDATA "[b.mu ]"--=small mu, Greek-->
+<!ENTITY b.nu SDATA "[b.nu ]"--=small nu, Greek-->
+<!ENTITY b.xi SDATA "[b.xi ]"--=small xi, Greek-->
+<!ENTITY b.Xi SDATA "[b.Xi ]"--=capital Xi, Greek-->
+<!ENTITY b.pi SDATA "[b.pi ]"--=small pi, Greek-->
+<!ENTITY b.Pi SDATA "[b.Pi ]"--=capital Pi, Greek-->
+<!ENTITY b.piv SDATA "[b.piv ]"--/varpi-->
+<!ENTITY b.rho SDATA "[b.rho ]"--=small rho, Greek-->
+<!ENTITY b.rhov SDATA "[b.rhov ]"--/varrho-->
+<!ENTITY b.sigma SDATA "[b.sigma ]"--=small sigma, Greek-->
+<!ENTITY b.Sigma SDATA "[b.Sigma ]"--=capital Sigma, Greek-->
+<!ENTITY b.sigmav SDATA "[b.sigmav]"--/varsigma-->
+<!ENTITY b.tau SDATA "[b.tau ]"--=small tau, Greek-->
+<!ENTITY b.upsi SDATA "[b.upsi ]"--=small upsilon, Greek-->
+<!ENTITY b.Upsi SDATA "[b.Upsi ]"--=capital Upsilon, Greek-->
+<!ENTITY b.phis SDATA "[b.phis ]"--/straightphi - straight phi-->
+<!ENTITY b.Phi SDATA "[b.Phi ]"--=capital Phi, Greek-->
+<!ENTITY b.phiv SDATA "[b.phiv ]"--/varphi - curly or open phi-->
+<!ENTITY b.chi SDATA "[b.chi ]"--=small chi, Greek-->
+<!ENTITY b.psi SDATA "[b.psi ]"--=small psi, Greek-->
+<!ENTITY b.Psi SDATA "[b.Psi ]"--=capital Psi, Greek-->
+<!ENTITY b.omega SDATA "[b.omega ]"--=small omega, Greek-->
+<!ENTITY b.Omega SDATA "[b.Omega ]"--=capital Omega, Greek-->
diff --git a/docs/docbook/dbsgml/ent/ISOlat1 b/docs/docbook/dbsgml/ent/ISOlat1
new file mode 100644
index 00000000000..0d7d0a7d937
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOlat1
@@ -0,0 +1,72 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOlat1 PUBLIC
+ "ISO 8879:1986//ENTITIES Added Latin 1//EN">
+ %ISOlat1;
+-->
+<!ENTITY aacute SDATA "[aacute]"--=small a, acute accent-->
+<!ENTITY Aacute SDATA "[Aacute]"--=capital A, acute accent-->
+<!ENTITY acirc SDATA "[acirc ]"--=small a, circumflex accent-->
+<!ENTITY Acirc SDATA "[Acirc ]"--=capital A, circumflex accent-->
+<!ENTITY agrave SDATA "[agrave]"--=small a, grave accent-->
+<!ENTITY Agrave SDATA "[Agrave]"--=capital A, grave accent-->
+<!ENTITY aring SDATA "[aring ]"--=small a, ring-->
+<!ENTITY Aring SDATA "[Aring ]"--=capital A, ring-->
+<!ENTITY atilde SDATA "[atilde]"--=small a, tilde-->
+<!ENTITY Atilde SDATA "[Atilde]"--=capital A, tilde-->
+<!ENTITY auml SDATA "[auml ]"--=small a, dieresis or umlaut mark-->
+<!ENTITY Auml SDATA "[Auml ]"--=capital A, dieresis or umlaut mark-->
+<!ENTITY aelig SDATA "[aelig ]"--=small ae diphthong (ligature)-->
+<!ENTITY AElig SDATA "[AElig ]"--=capital AE diphthong (ligature)-->
+<!ENTITY ccedil SDATA "[ccedil]"--=small c, cedilla-->
+<!ENTITY Ccedil SDATA "[Ccedil]"--=capital C, cedilla-->
+<!ENTITY eth SDATA "[eth ]"--=small eth, Icelandic-->
+<!ENTITY ETH SDATA "[ETH ]"--=capital Eth, Icelandic-->
+<!ENTITY eacute SDATA "[eacute]"--=small e, acute accent-->
+<!ENTITY Eacute SDATA "[Eacute]"--=capital E, acute accent-->
+<!ENTITY ecirc SDATA "[ecirc ]"--=small e, circumflex accent-->
+<!ENTITY Ecirc SDATA "[Ecirc ]"--=capital E, circumflex accent-->
+<!ENTITY egrave SDATA "[egrave]"--=small e, grave accent-->
+<!ENTITY Egrave SDATA "[Egrave]"--=capital E, grave accent-->
+<!ENTITY euml SDATA "[euml ]"--=small e, dieresis or umlaut mark-->
+<!ENTITY Euml SDATA "[Euml ]"--=capital E, dieresis or umlaut mark-->
+<!ENTITY iacute SDATA "[iacute]"--=small i, acute accent-->
+<!ENTITY Iacute SDATA "[Iacute]"--=capital I, acute accent-->
+<!ENTITY icirc SDATA "[icirc ]"--=small i, circumflex accent-->
+<!ENTITY Icirc SDATA "[Icirc ]"--=capital I, circumflex accent-->
+<!ENTITY igrave SDATA "[igrave]"--=small i, grave accent-->
+<!ENTITY Igrave SDATA "[Igrave]"--=capital I, grave accent-->
+<!ENTITY iuml SDATA "[iuml ]"--=small i, dieresis or umlaut mark-->
+<!ENTITY Iuml SDATA "[Iuml ]"--=capital I, dieresis or umlaut mark-->
+<!ENTITY ntilde SDATA "[ntilde]"--=small n, tilde-->
+<!ENTITY Ntilde SDATA "[Ntilde]"--=capital N, tilde-->
+<!ENTITY oacute SDATA "[oacute]"--=small o, acute accent-->
+<!ENTITY Oacute SDATA "[Oacute]"--=capital O, acute accent-->
+<!ENTITY ocirc SDATA "[ocirc ]"--=small o, circumflex accent-->
+<!ENTITY Ocirc SDATA "[Ocirc ]"--=capital O, circumflex accent-->
+<!ENTITY ograve SDATA "[ograve]"--=small o, grave accent-->
+<!ENTITY Ograve SDATA "[Ograve]"--=capital O, grave accent-->
+<!ENTITY oslash SDATA "[oslash]"--=small o, slash-->
+<!ENTITY Oslash SDATA "[Oslash]"--=capital O, slash-->
+<!ENTITY otilde SDATA "[otilde]"--=small o, tilde-->
+<!ENTITY Otilde SDATA "[Otilde]"--=capital O, tilde-->
+<!ENTITY ouml SDATA "[ouml ]"--=small o, dieresis or umlaut mark-->
+<!ENTITY Ouml SDATA "[Ouml ]"--=capital O, dieresis or umlaut mark-->
+<!ENTITY szlig SDATA "[szlig ]"--=small sharp s, German (sz ligature)-->
+<!ENTITY thorn SDATA "[thorn ]"--=small thorn, Icelandic-->
+<!ENTITY THORN SDATA "[THORN ]"--=capital THORN, Icelandic-->
+<!ENTITY uacute SDATA "[uacute]"--=small u, acute accent-->
+<!ENTITY Uacute SDATA "[Uacute]"--=capital U, acute accent-->
+<!ENTITY ucirc SDATA "[ucirc ]"--=small u, circumflex accent-->
+<!ENTITY Ucirc SDATA "[Ucirc ]"--=capital U, circumflex accent-->
+<!ENTITY ugrave SDATA "[ugrave]"--=small u, grave accent-->
+<!ENTITY Ugrave SDATA "[Ugrave]"--=capital U, grave accent-->
+<!ENTITY uuml SDATA "[uuml ]"--=small u, dieresis or umlaut mark-->
+<!ENTITY Uuml SDATA "[Uuml ]"--=capital U, dieresis or umlaut mark-->
+<!ENTITY yacute SDATA "[yacute]"--=small y, acute accent-->
+<!ENTITY Yacute SDATA "[Yacute]"--=capital Y, acute accent-->
+<!ENTITY yuml SDATA "[yuml ]"--=small y, dieresis or umlaut mark-->
diff --git a/docs/docbook/dbsgml/ent/ISOlat2 b/docs/docbook/dbsgml/ent/ISOlat2
new file mode 100644
index 00000000000..4bcb3378328
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOlat2
@@ -0,0 +1,131 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOlat2 PUBLIC
+ "ISO 8879:1986//ENTITIES Added Latin 2//EN">
+ %ISOlat2;
+-->
+<!ENTITY abreve SDATA "[abreve]"--=small a, breve-->
+<!ENTITY Abreve SDATA "[Abreve]"--=capital A, breve-->
+<!ENTITY amacr SDATA "[amacr ]"--=small a, macron-->
+<!ENTITY Amacr SDATA "[Amacr ]"--=capital A, macron-->
+<!ENTITY aogon SDATA "[aogon ]"--=small a, ogonek-->
+<!ENTITY Aogon SDATA "[Aogon ]"--=capital A, ogonek-->
+<!ENTITY cacute SDATA "[cacute]"--=small c, acute accent-->
+<!ENTITY Cacute SDATA "[Cacute]"--=capital C, acute accent-->
+<!ENTITY ccaron SDATA "[ccaron]"--=small c, caron-->
+<!ENTITY Ccaron SDATA "[Ccaron]"--=capital C, caron-->
+<!ENTITY ccirc SDATA "[ccirc ]"--=small c, circumflex accent-->
+<!ENTITY Ccirc SDATA "[Ccirc ]"--=capital C, circumflex accent-->
+<!ENTITY cdot SDATA "[cdot ]"--=small c, dot above-->
+<!ENTITY Cdot SDATA "[Cdot ]"--=capital C, dot above-->
+<!ENTITY dcaron SDATA "[dcaron]"--=small d, caron-->
+<!ENTITY Dcaron SDATA "[Dcaron]"--=capital D, caron-->
+<!ENTITY dstrok SDATA "[dstrok]"--=small d, stroke-->
+<!ENTITY Dstrok SDATA "[Dstrok]"--=capital D, stroke-->
+<!ENTITY ecaron SDATA "[ecaron]"--=small e, caron-->
+<!ENTITY Ecaron SDATA "[Ecaron]"--=capital E, caron-->
+<!ENTITY edot SDATA "[edot ]"--=small e, dot above-->
+<!ENTITY Edot SDATA "[Edot ]"--=capital E, dot above-->
+<!ENTITY emacr SDATA "[emacr ]"--=small e, macron-->
+<!ENTITY Emacr SDATA "[Emacr ]"--=capital E, macron-->
+<!ENTITY eogon SDATA "[eogon ]"--=small e, ogonek-->
+<!ENTITY Eogon SDATA "[Eogon ]"--=capital E, ogonek-->
+<!ENTITY gacute SDATA "[gacute]"--=small g, acute accent-->
+<!ENTITY gbreve SDATA "[gbreve]"--=small g, breve-->
+<!ENTITY Gbreve SDATA "[Gbreve]"--=capital G, breve-->
+<!ENTITY Gcedil SDATA "[Gcedil]"--=capital G, cedilla-->
+<!ENTITY gcirc SDATA "[gcirc ]"--=small g, circumflex accent-->
+<!ENTITY Gcirc SDATA "[Gcirc ]"--=capital G, circumflex accent-->
+<!ENTITY gdot SDATA "[gdot ]"--=small g, dot above-->
+<!ENTITY Gdot SDATA "[Gdot ]"--=capital G, dot above-->
+<!ENTITY hcirc SDATA "[hcirc ]"--=small h, circumflex accent-->
+<!ENTITY Hcirc SDATA "[Hcirc ]"--=capital H, circumflex accent-->
+<!ENTITY hstrok SDATA "[hstrok]"--=small h, stroke-->
+<!ENTITY Hstrok SDATA "[Hstrok]"--=capital H, stroke-->
+<!ENTITY Idot SDATA "[Idot ]"--=capital I, dot above-->
+<!ENTITY Imacr SDATA "[Imacr ]"--=capital I, macron-->
+<!ENTITY imacr SDATA "[imacr ]"--=small i, macron-->
+<!ENTITY ijlig SDATA "[ijlig ]"--=small ij ligature-->
+<!ENTITY IJlig SDATA "[IJlig ]"--=capital IJ ligature-->
+<!ENTITY inodot SDATA "[inodot]"--=small i without dot-->
+<!ENTITY iogon SDATA "[iogon ]"--=small i, ogonek-->
+<!ENTITY Iogon SDATA "[Iogon ]"--=capital I, ogonek-->
+<!ENTITY itilde SDATA "[itilde]"--=small i, tilde-->
+<!ENTITY Itilde SDATA "[Itilde]"--=capital I, tilde-->
+<!ENTITY jcirc SDATA "[jcirc ]"--=small j, circumflex accent-->
+<!ENTITY Jcirc SDATA "[Jcirc ]"--=capital J, circumflex accent-->
+<!ENTITY kcedil SDATA "[kcedil]"--=small k, cedilla-->
+<!ENTITY Kcedil SDATA "[Kcedil]"--=capital K, cedilla-->
+<!ENTITY kgreen SDATA "[kgreen]"--=small k, Greenlandic-->
+<!ENTITY lacute SDATA "[lacute]"--=small l, acute accent-->
+<!ENTITY Lacute SDATA "[Lacute]"--=capital L, acute accent-->
+<!ENTITY lcaron SDATA "[lcaron]"--=small l, caron-->
+<!ENTITY Lcaron SDATA "[Lcaron]"--=capital L, caron-->
+<!ENTITY lcedil SDATA "[lcedil]"--=small l, cedilla-->
+<!ENTITY Lcedil SDATA "[Lcedil]"--=capital L, cedilla-->
+<!ENTITY lmidot SDATA "[lmidot]"--=small l, middle dot-->
+<!ENTITY Lmidot SDATA "[Lmidot]"--=capital L, middle dot-->
+<!ENTITY lstrok SDATA "[lstrok]"--=small l, stroke-->
+<!ENTITY Lstrok SDATA "[Lstrok]"--=capital L, stroke-->
+<!ENTITY nacute SDATA "[nacute]"--=small n, acute accent-->
+<!ENTITY Nacute SDATA "[Nacute]"--=capital N, acute accent-->
+<!ENTITY eng SDATA "[eng ]"--=small eng, Lapp-->
+<!ENTITY ENG SDATA "[ENG ]"--=capital ENG, Lapp-->
+<!ENTITY napos SDATA "[napos ]"--=small n, apostrophe-->
+<!ENTITY ncaron SDATA "[ncaron]"--=small n, caron-->
+<!ENTITY Ncaron SDATA "[Ncaron]"--=capital N, caron-->
+<!ENTITY ncedil SDATA "[ncedil]"--=small n, cedilla-->
+<!ENTITY Ncedil SDATA "[Ncedil]"--=capital N, cedilla-->
+<!ENTITY odblac SDATA "[odblac]"--=small o, double acute accent-->
+<!ENTITY Odblac SDATA "[Odblac]"--=capital O, double acute accent-->
+<!ENTITY Omacr SDATA "[Omacr ]"--=capital O, macron-->
+<!ENTITY omacr SDATA "[omacr ]"--=small o, macron-->
+<!ENTITY oelig SDATA "[oelig ]"--=small oe ligature-->
+<!ENTITY OElig SDATA "[OElig ]"--=capital OE ligature-->
+<!ENTITY racute SDATA "[racute]"--=small r, acute accent-->
+<!ENTITY Racute SDATA "[Racute]"--=capital R, acute accent-->
+<!ENTITY rcaron SDATA "[rcaron]"--=small r, caron-->
+<!ENTITY Rcaron SDATA "[Rcaron]"--=capital R, caron-->
+<!ENTITY rcedil SDATA "[rcedil]"--=small r, cedilla-->
+<!ENTITY Rcedil SDATA "[Rcedil]"--=capital R, cedilla-->
+<!ENTITY sacute SDATA "[sacute]"--=small s, acute accent-->
+<!ENTITY Sacute SDATA "[Sacute]"--=capital S, acute accent-->
+<!ENTITY scaron SDATA "[scaron]"--=small s, caron-->
+<!ENTITY Scaron SDATA "[Scaron]"--=capital S, caron-->
+<!ENTITY scedil SDATA "[scedil]"--=small s, cedilla-->
+<!ENTITY Scedil SDATA "[Scedil]"--=capital S, cedilla-->
+<!ENTITY scirc SDATA "[scirc ]"--=small s, circumflex accent-->
+<!ENTITY Scirc SDATA "[Scirc ]"--=capital S, circumflex accent-->
+<!ENTITY tcaron SDATA "[tcaron]"--=small t, caron-->
+<!ENTITY Tcaron SDATA "[Tcaron]"--=capital T, caron-->
+<!ENTITY tcedil SDATA "[tcedil]"--=small t, cedilla-->
+<!ENTITY Tcedil SDATA "[Tcedil]"--=capital T, cedilla-->
+<!ENTITY tstrok SDATA "[tstrok]"--=small t, stroke-->
+<!ENTITY Tstrok SDATA "[Tstrok]"--=capital T, stroke-->
+<!ENTITY ubreve SDATA "[ubreve]"--=small u, breve-->
+<!ENTITY Ubreve SDATA "[Ubreve]"--=capital U, breve-->
+<!ENTITY udblac SDATA "[udblac]"--=small u, double acute accent-->
+<!ENTITY Udblac SDATA "[Udblac]"--=capital U, double acute accent-->
+<!ENTITY umacr SDATA "[umacr ]"--=small u, macron-->
+<!ENTITY Umacr SDATA "[Umacr ]"--=capital U, macron-->
+<!ENTITY uogon SDATA "[uogon ]"--=small u, ogonek-->
+<!ENTITY Uogon SDATA "[Uogon ]"--=capital U, ogonek-->
+<!ENTITY uring SDATA "[uring ]"--=small u, ring-->
+<!ENTITY Uring SDATA "[Uring ]"--=capital U, ring-->
+<!ENTITY utilde SDATA "[utilde]"--=small u, tilde-->
+<!ENTITY Utilde SDATA "[Utilde]"--=capital U, tilde-->
+<!ENTITY wcirc SDATA "[wcirc ]"--=small w, circumflex accent-->
+<!ENTITY Wcirc SDATA "[Wcirc ]"--=capital W, circumflex accent-->
+<!ENTITY ycirc SDATA "[ycirc ]"--=small y, circumflex accent-->
+<!ENTITY Ycirc SDATA "[Ycirc ]"--=capital Y, circumflex accent-->
+<!ENTITY Yuml SDATA "[Yuml ]"--=capital Y, dieresis or umlaut mark-->
+<!ENTITY zacute SDATA "[zacute]"--=small z, acute accent-->
+<!ENTITY Zacute SDATA "[Zacute]"--=capital Z, acute accent-->
+<!ENTITY zcaron SDATA "[zcaron]"--=small z, caron-->
+<!ENTITY Zcaron SDATA "[Zcaron]"--=capital Z, caron-->
+<!ENTITY zdot SDATA "[zdot ]"--=small z, dot above-->
+<!ENTITY Zdot SDATA "[Zdot ]"--=capital Z, dot above-->
diff --git a/docs/docbook/dbsgml/ent/ISOnum b/docs/docbook/dbsgml/ent/ISOnum
new file mode 100644
index 00000000000..d7b41c33ae3
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOnum
@@ -0,0 +1,91 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOnum PUBLIC
+ "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN">
+ %ISOnum;
+-->
+<!ENTITY half SDATA "[half ]"--=fraction one-half-->
+<!ENTITY frac12 SDATA "[frac12]"--=fraction one-half-->
+<!ENTITY frac14 SDATA "[frac14]"--=fraction one-quarter-->
+<!ENTITY frac34 SDATA "[frac34]"--=fraction three-quarters-->
+<!ENTITY frac18 SDATA "[frac18]"--=fraction one-eighth-->
+<!ENTITY frac38 SDATA "[frac38]"--=fraction three-eighths-->
+<!ENTITY frac58 SDATA "[frac58]"--=fraction five-eighths-->
+<!ENTITY frac78 SDATA "[frac78]"--=fraction seven-eighths-->
+
+<!ENTITY sup1 SDATA "[sup1 ]"--=superscript one-->
+<!ENTITY sup2 SDATA "[sup2 ]"--=superscript two-->
+<!ENTITY sup3 SDATA "[sup3 ]"--=superscript three-->
+
+<!ENTITY plus SDATA "[plus ]"--=plus sign B:-- >
+<!ENTITY plusmn SDATA "[plusmn]"--/pm B: =plus-or-minus sign-->
+<!ENTITY lt SDATA "[lt ]"--=less-than sign R:-->
+<!ENTITY equals SDATA "[equals]"--=equals sign R:-->
+<!ENTITY gt SDATA "[gt ]"--=greater-than sign R:-->
+<!ENTITY divide SDATA "[divide]"--/div B: =divide sign-->
+<!ENTITY times SDATA "[times ]"--/times B: =multiply sign-->
+
+<!ENTITY curren SDATA "[curren]"--=general currency sign-->
+<!ENTITY pound SDATA "[pound ]"--=pound sign-->
+<!ENTITY dollar SDATA "[dollar]"--=dollar sign-->
+<!ENTITY cent SDATA "[cent ]"--=cent sign-->
+<!ENTITY yen SDATA "[yen ]"--/yen =yen sign-->
+
+<!ENTITY num SDATA "[num ]"--=number sign-->
+<!ENTITY percnt SDATA "[percnt]"--=percent sign-->
+<!ENTITY amp SDATA "[amp ]"--=ampersand-->
+<!ENTITY ast SDATA "[ast ]"--/ast B: =asterisk-->
+<!ENTITY commat SDATA "[commat]"--=commercial at-->
+<!ENTITY lsqb SDATA "[lsqb ]"--/lbrack O: =left square bracket-->
+<!ENTITY bsol SDATA "[bsol ]"--/backslash =reverse solidus-->
+<!ENTITY rsqb SDATA "[rsqb ]"--/rbrack C: =right square bracket-->
+<!ENTITY lcub SDATA "[lcub ]"--/lbrace O: =left curly bracket-->
+<!ENTITY horbar SDATA "[horbar]"--=horizontal bar-->
+<!ENTITY verbar SDATA "[verbar]"--/vert =vertical bar-->
+<!ENTITY rcub SDATA "[rcub ]"--/rbrace C: =right curly bracket-->
+<!ENTITY micro SDATA "[micro ]"--=micro sign-->
+<!ENTITY ohm SDATA "[ohm ]"--=ohm sign-->
+<!ENTITY deg SDATA "[deg ]"--=degree sign-->
+<!ENTITY ordm SDATA "[ordm ]"--=ordinal indicator, masculine-->
+<!ENTITY ordf SDATA "[ordf ]"--=ordinal indicator, feminine-->
+<!ENTITY sect SDATA "[sect ]"--=section sign-->
+<!ENTITY para SDATA "[para ]"--=pilcrow (paragraph sign)-->
+<!ENTITY middot SDATA "[middot]"--/centerdot B: =middle dot-->
+<!ENTITY larr SDATA "[larr ]"--/leftarrow /gets A: =leftward arrow-->
+<!ENTITY rarr SDATA "[rarr ]"--/rightarrow /to A: =rightward arrow-->
+<!ENTITY uarr SDATA "[uarr ]"--/uparrow A: =upward arrow-->
+<!ENTITY darr SDATA "[darr ]"--/downarrow A: =downward arrow-->
+<!ENTITY copy SDATA "[copy ]"--=copyright sign-->
+<!ENTITY reg SDATA "[reg ]"--/circledR =registered sign-->
+<!ENTITY trade SDATA "[trade ]"--=trade mark sign-->
+<!ENTITY brvbar SDATA "[brvbar]"--=broken (vertical) bar-->
+<!ENTITY not SDATA "[not ]"--/neg /lnot =not sign-->
+<!ENTITY sung SDATA "[sung ]"--=music note (sung text sign)-->
+
+<!ENTITY excl SDATA "[excl ]"--=exclamation mark-->
+<!ENTITY iexcl SDATA "[iexcl ]"--=inverted exclamation mark-->
+<!ENTITY quot SDATA "[quot ]"--=quotation mark-->
+<!ENTITY apos SDATA "[apos ]"--=apostrophe-->
+<!ENTITY lpar SDATA "[lpar ]"--O: =left parenthesis-->
+<!ENTITY rpar SDATA "[rpar ]"--C: =right parenthesis-->
+<!ENTITY comma SDATA "[comma ]"--P: =comma-->
+<!ENTITY lowbar SDATA "[lowbar]"--=low line-->
+<!ENTITY hyphen SDATA "[hyphen]"--=hyphen-->
+<!ENTITY period SDATA "[period]"--=full stop, period-->
+<!ENTITY sol SDATA "[sol ]"--=solidus-->
+<!ENTITY colon SDATA "[colon ]"--/colon P:-->
+<!ENTITY semi SDATA "[semi ]"--=semicolon P:-->
+<!ENTITY quest SDATA "[quest ]"--=question mark-->
+<!ENTITY iquest SDATA "[iquest]"--=inverted question mark-->
+<!ENTITY laquo SDATA "[laquo ]"--=angle quotation mark, left-->
+<!ENTITY raquo SDATA "[raquo ]"--=angle quotation mark, right-->
+<!ENTITY lsquo SDATA "[lsquo ]"--=single quotation mark, left-->
+<!ENTITY rsquo SDATA "[rsquo ]"--=single quotation mark, right-->
+<!ENTITY ldquo SDATA "[ldquo ]"--=double quotation mark, left-->
+<!ENTITY rdquo SDATA "[rdquo ]"--=double quotation mark, right-->
+<!ENTITY nbsp SDATA "[nbsp ]"--=no break (required) space-->
+<!ENTITY shy SDATA "[shy ]"--=soft hyphen-->
diff --git a/docs/docbook/dbsgml/ent/ISOpub b/docs/docbook/dbsgml/ent/ISOpub
new file mode 100644
index 00000000000..c184973cfdf
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOpub
@@ -0,0 +1,100 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOpub PUBLIC
+ "ISO 8879:1986//ENTITIES Publishing//EN">
+ %ISOpub;
+-->
+<!ENTITY emsp SDATA "[emsp ]"--=em space-->
+<!ENTITY ensp SDATA "[ensp ]"--=en space (1/2-em)-->
+<!ENTITY emsp13 SDATA "[emsp3 ]"--=1/3-em space-->
+<!ENTITY emsp14 SDATA "[emsp4 ]"--=1/4-em space-->
+<!ENTITY numsp SDATA "[numsp ]"--=digit space (width of a number)-->
+<!ENTITY puncsp SDATA "[puncsp]"--=punctuation space (width of comma)-->
+<!ENTITY thinsp SDATA "[thinsp]"--=thin space (1/6-em)-->
+<!ENTITY hairsp SDATA "[hairsp]"--=hair space-->
+<!ENTITY mdash SDATA "[mdash ]"--=em dash-->
+<!ENTITY ndash SDATA "[ndash ]"--=en dash-->
+<!ENTITY dash SDATA "[dash ]"--=hyphen (true graphic)-->
+<!ENTITY blank SDATA "[blank ]"--=significant blank symbol-->
+<!ENTITY hellip SDATA "[hellip]"--=ellipsis (horizontal)-->
+<!ENTITY nldr SDATA "[nldr ]"--=double baseline dot (en leader)-->
+<!ENTITY frac13 SDATA "[frac13]"--=fraction one-third-->
+<!ENTITY frac23 SDATA "[frac23]"--=fraction two-thirds-->
+<!ENTITY frac15 SDATA "[frac15]"--=fraction one-fifth-->
+<!ENTITY frac25 SDATA "[frac25]"--=fraction two-fifths-->
+<!ENTITY frac35 SDATA "[frac35]"--=fraction three-fifths-->
+<!ENTITY frac45 SDATA "[frac45]"--=fraction four-fifths-->
+<!ENTITY frac16 SDATA "[frac16]"--=fraction one-sixth-->
+<!ENTITY frac56 SDATA "[frac56]"--=fraction five-sixths-->
+<!ENTITY incare SDATA "[incare]"--=in-care-of symbol-->
+<!ENTITY block SDATA "[block ]"--=full block-->
+<!ENTITY uhblk SDATA "[uhblk ]"--=upper half block-->
+<!ENTITY lhblk SDATA "[lhblk ]"--=lower half block-->
+<!ENTITY blk14 SDATA "[blk14 ]"--=25% shaded block-->
+<!ENTITY blk12 SDATA "[blk12 ]"--=50% shaded block-->
+<!ENTITY blk34 SDATA "[blk34 ]"--=75% shaded block-->
+<!ENTITY marker SDATA "[marker]"--=histogram marker-->
+<!ENTITY cir SDATA "[cir ]"--/circ B: =circle, open-->
+<!ENTITY squ SDATA "[squ ]"--=square, open-->
+<!ENTITY rect SDATA "[rect ]"--=rectangle, open-->
+<!ENTITY utri SDATA "[utri ]"--/triangle =up triangle, open-->
+<!ENTITY dtri SDATA "[dtri ]"--/triangledown =down triangle, open-->
+<!ENTITY star SDATA "[star ]"--=star, open-->
+<!ENTITY bull SDATA "[bull ]"--/bullet B: =round bullet, filled-->
+<!ENTITY squf SDATA "[squf ]"--/blacksquare =sq bullet, filled-->
+<!ENTITY utrif SDATA "[utrif ]"--/blacktriangle =up tri, filled-->
+<!ENTITY dtrif SDATA "[dtrif ]"--/blacktriangledown =dn tri, filled-->
+<!ENTITY ltrif SDATA "[ltrif ]"--/blacktriangleleft R: =l tri, filled-->
+<!ENTITY rtrif SDATA "[rtrif ]"--/blacktriangleright R: =r tri, filled-->
+<!ENTITY clubs SDATA "[clubs ]"--/clubsuit =club suit symbol-->
+<!ENTITY diams SDATA "[diams ]"--/diamondsuit =diamond suit symbol-->
+<!ENTITY hearts SDATA "[hearts]"--/heartsuit =heart suit symbol-->
+<!ENTITY spades SDATA "[spades]"--/spadesuit =spades suit symbol-->
+<!ENTITY malt SDATA "[malt ]"--/maltese =maltese cross-->
+<!ENTITY dagger SDATA "[dagger]"--/dagger B: =dagger-->
+<!ENTITY Dagger SDATA "[Dagger]"--/ddagger B: =double dagger-->
+<!ENTITY check SDATA "[check ]"--/checkmark =tick, check mark-->
+<!ENTITY cross SDATA "[ballot]"--=ballot cross-->
+<!ENTITY sharp SDATA "[sharp ]"--/sharp =musical sharp-->
+<!ENTITY flat SDATA "[flat ]"--/flat =musical flat-->
+<!ENTITY male SDATA "[male ]"--=male symbol-->
+<!ENTITY female SDATA "[female]"--=female symbol-->
+<!ENTITY phone SDATA "[phone ]"--=telephone symbol-->
+<!ENTITY telrec SDATA "[telrec]"--=telephone recorder symbol-->
+<!ENTITY copysr SDATA "[copysr]"--=sound recording copyright sign-->
+<!ENTITY caret SDATA "[caret ]"--=caret (insertion mark)-->
+<!ENTITY lsquor SDATA "[lsquor]"--=rising single quote, left (low)-->
+<!ENTITY ldquor SDATA "[ldquor]"--=rising dbl quote, left (low)-->
+
+<!ENTITY fflig SDATA "[fflig ]"--small ff ligature-->
+<!ENTITY filig SDATA "[filig ]"--small fi ligature-->
+<!ENTITY fjlig SDATA "[fjlig ]"--small fj ligature-->
+<!ENTITY ffilig SDATA "[ffilig]"--small ffi ligature-->
+<!ENTITY ffllig SDATA "[ffllig]"--small ffl ligature-->
+<!ENTITY fllig SDATA "[fllig ]"--small fl ligature-->
+
+<!ENTITY mldr SDATA "[mldr ]"--em leader-->
+<!ENTITY rdquor SDATA "[rdquor]"--rising dbl quote, right (high)-->
+<!ENTITY rsquor SDATA "[rsquor]"--rising single quote, right (high)-->
+<!ENTITY vellip SDATA "[vellip]"--vertical ellipsis-->
+
+<!ENTITY hybull SDATA "[hybull]"--rectangle, filled (hyphen bullet)-->
+<!ENTITY loz SDATA "[loz ]"--/lozenge - lozenge or total mark-->
+<!ENTITY lozf SDATA "[lozf ]"--/blacklozenge - lozenge, filled-->
+<!ENTITY ltri SDATA "[ltri ]"--/triangleleft B: l triangle, open-->
+<!ENTITY rtri SDATA "[rtri ]"--/triangleright B: r triangle, open-->
+<!ENTITY starf SDATA "[starf ]"--/bigstar - star, filled-->
+
+<!ENTITY natur SDATA "[natur ]"--/natural - music natural-->
+<!ENTITY rx SDATA "[rx ]"--pharmaceutical prescription (Rx)-->
+<!ENTITY sext SDATA "[sext ]"--sextile (6-pointed star)-->
+
+<!ENTITY target SDATA "[target]"--register mark or target-->
+<!ENTITY dlcrop SDATA "[dlcrop]"--downward left crop mark -->
+<!ENTITY drcrop SDATA "[drcrop]"--downward right crop mark -->
+<!ENTITY ulcrop SDATA "[ulcrop]"--upward left crop mark -->
+<!ENTITY urcrop SDATA "[urcrop]"--upward right crop mark -->
diff --git a/docs/docbook/dbsgml/ent/ISOtech b/docs/docbook/dbsgml/ent/ISOtech
new file mode 100644
index 00000000000..cbda344869a
--- /dev/null
+++ b/docs/docbook/dbsgml/ent/ISOtech
@@ -0,0 +1,73 @@
+<!-- (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % ISOtech PUBLIC
+ "ISO 8879:1986//ENTITIES General Technical//EN">
+ %ISOtech;
+-->
+<!ENTITY aleph SDATA "[aleph ]"--/aleph =aleph, Hebrew-->
+<!ENTITY and SDATA "[and ]"--/wedge /land B: =logical and-->
+<!ENTITY ang90 SDATA "[ang90 ]"--=right (90 degree) angle-->
+<!ENTITY angsph SDATA "[angsph]"--/sphericalangle =angle-spherical-->
+<!ENTITY ap SDATA "[ap ]"--/approx R: =approximate-->
+<!ENTITY becaus SDATA "[becaus]"--/because R: =because-->
+<!ENTITY bottom SDATA "[bottom]"--/bot B: =perpendicular-->
+<!ENTITY cap SDATA "[cap ]"--/cap B: =intersection-->
+<!ENTITY cong SDATA "[cong ]"--/cong R: =congruent with-->
+<!ENTITY conint SDATA "[conint]"--/oint L: =contour integral operator-->
+<!ENTITY cup SDATA "[cup ]"--/cup B: =union or logical sum-->
+<!ENTITY equiv SDATA "[equiv ]"--/equiv R: =identical with-->
+<!ENTITY exist SDATA "[exist ]"--/exists =at least one exists-->
+<!ENTITY forall SDATA "[forall]"--/forall =for all-->
+<!ENTITY fnof SDATA "[fnof ]"--=function of (italic small f)-->
+<!ENTITY ge SDATA "[ge ]"--/geq /ge R: =greater-than-or-equal-->
+<!ENTITY iff SDATA "[iff ]"--/iff =if and only if-->
+<!ENTITY infin SDATA "[infin ]"--/infty =infinity-->
+<!ENTITY int SDATA "[int ]"--/int L: =integral operator-->
+<!ENTITY isin SDATA "[isin ]"--/in R: =set membership-->
+<!ENTITY lang SDATA "[lang ]"--/langle O: =left angle bracket-->
+<!ENTITY lArr SDATA "[lArr ]"--/Leftarrow A: =is implied by-->
+<!ENTITY le SDATA "[le ]"--/leq /le R: =less-than-or-equal-->
+<!ENTITY minus SDATA "[minus ]"--B: =minus sign-->
+<!ENTITY mnplus SDATA "[mnplus]"--/mp B: =minus-or-plus sign-->
+<!ENTITY nabla SDATA "[nabla ]"--/nabla =del, Hamilton operator-->
+<!ENTITY ne SDATA "[ne ]"--/ne /neq R: =not equal-->
+<!ENTITY ni SDATA "[ni ]"--/ni /owns R: =contains-->
+<!ENTITY or SDATA "[or ]"--/vee /lor B: =logical or-->
+<!ENTITY par SDATA "[par ]"--/parallel R: =parallel-->
+<!ENTITY part SDATA "[part ]"--/partial =partial differential-->
+<!ENTITY permil SDATA "[permil]"--=per thousand-->
+<!ENTITY perp SDATA "[perp ]"--/perp R: =perpendicular-->
+<!ENTITY prime SDATA "[prime ]"--/prime =prime or minute-->
+<!ENTITY Prime SDATA "[Prime ]"--=double prime or second-->
+<!ENTITY prop SDATA "[prop ]"--/propto R: =is proportional to-->
+<!ENTITY radic SDATA "[radic ]"--/surd =radical-->
+<!ENTITY rang SDATA "[rang ]"--/rangle C: =right angle bracket-->
+<!ENTITY rArr SDATA "[rArr ]"--/Rightarrow A: =implies-->
+<!ENTITY sim SDATA "[sim ]"--/sim R: =similar-->
+<!ENTITY sime SDATA "[sime ]"--/simeq R: =similar, equals-->
+<!ENTITY square SDATA "[square]"--/square B: =square-->
+<!ENTITY sub SDATA "[sub ]"--/subset R: =subset or is implied by-->
+<!ENTITY sube SDATA "[sube ]"--/subseteq R: =subset, equals-->
+<!ENTITY sup SDATA "[sup ]"--/supset R: =superset or implies-->
+<!ENTITY supe SDATA "[supe ]"--/supseteq R: =superset, equals-->
+<!ENTITY there4 SDATA "[there4]"--/therefore R: =therefore-->
+<!ENTITY Verbar SDATA "[Verbar]"--/Vert =dbl vertical bar-->
+
+<!ENTITY angst SDATA "[angst ]"--Angstrom =capital A, ring-->
+<!ENTITY bernou SDATA "[bernou]"--Bernoulli function (script capital B)-->
+<!ENTITY compfn SDATA "[compfn]"--B: composite function (small circle)-->
+<!ENTITY Dot SDATA "[Dot ]"--=dieresis or umlaut mark-->
+<!ENTITY DotDot SDATA "[DotDot]"--four dots above-->
+<!ENTITY hamilt SDATA "[hamilt]"--Hamiltonian (script capital H)-->
+<!ENTITY lagran SDATA "[lagran]"--Lagrangian (script capital L)-->
+<!ENTITY lowast SDATA "[lowast]"--low asterisk-->
+<!ENTITY notin SDATA "[notin ]"--N: negated set membership-->
+<!ENTITY order SDATA "[order ]"--order of (script small o)-->
+<!ENTITY phmmat SDATA "[phmmat]"--physics M-matrix (script capital M)-->
+<!ENTITY tdot SDATA "[tdot ]"--three dots above-->
+<!ENTITY tprime SDATA "[tprime]"--triple prime-->
+<!ENTITY wedgeq SDATA "[wedgeq]"--R: corresponds to (wedge, equals)-->
diff --git a/docs/docbook/dbsgml/readme.txt b/docs/docbook/dbsgml/readme.txt
new file mode 100644
index 00000000000..52d3f9f4aaf
--- /dev/null
+++ b/docs/docbook/dbsgml/readme.txt
@@ -0,0 +1,12 @@
+README for DocBook V4.1
+
+This is DocBook V4.1, released 19 June 2000.
+
+See 40chg.txt for information about what has changed since DocBook 3.1.
+
+For more information about DocBook, please see
+
+ http://www.oasis-open.org/docbook/
+
+Please send all questions, comments, concerns, and bug reports to the
+DocBook mailing list: docbook@lists.oasis-open.org
diff --git a/docs/docbook/docbook.txt b/docs/docbook/docbook.txt
new file mode 100644
index 00000000000..388cd5cf9b7
--- /dev/null
+++ b/docs/docbook/docbook.txt
@@ -0,0 +1,136 @@
+!==
+!== docbook.txt for Samba 2.2.0 release
+!==
+!== Author: David Bannon, D.Bannon@latrobe.edu.au November, 2000
+!== Updates: Gerald (Jerry) Carter, jerry@samba.org, Feb. 2001
+
+What are DocBook documents doing in the Samba Distribution ?
+-----------------------------------------------------------
+
+We are planning to convert all of the samba docs to SGML/DocBook V4.1
+in order to make them easier to maintain and produce a nicer looking
+product.
+
+This short note (strange isn't it how it always starts out as a short note
+and becomes a long one ?) will explain very briefly how and why we are
+doing this.
+
+
+The format
+----------
+
+If you are new to sgml, regard an sgml file as 'source code'. You don't
+read it directly, use it to create other formats (like the txt and html
+included in ../txt and ../html).
+
+Docbook is a particular SGML style, particularly suited to producing
+technical manuals. In the two documents I have produced so far I have used
+DocBook 4.1, it seems that products like RedHat Linux is still include only
+version 3.1, the differences are minor. The Linux Documentation Project is
+using a modified version of 3.1 but are really geared up to make multi
+paged documents, something we want to avoid for logistic reasons.
+
+For more information on DocBook tags and format, see "DocBook: The
+Definitive Guide" by Walsh and Muellner, (c) O'Reilly Publishing.
+This book covers DocBook V3.1 and is available on-line
+at http://www.docbook.org/
+
+The Output
+----------
+
+The current Samba CVS tree contains the SGML/DocBook source files as well
+as the following autogenerated formats
+
+ * man pages
+ * HTML
+ * ASCII text (where appropriate)
+
+
+The Tools
+---------
+
+[
+ addendum: For a good general overview of installing the tools
+ needed for generating files from SGML/DocBook source, refer
+ to the DocBook-Install mini HOWTO at
+ http://www.ibiblio.org/pub/Linux/docs/HOWTO/mini/DocBook-Install
+
+ While the above link is to a Linux HOWTO, the tools can be installed
+ on almost any UNIX platform.
+
+ David's original notes follow below:
+]
+
+Any sgml document needs to be referred to a suitable style sheet
+(describing syntax) and other sheets that tell the translating programmes
+how to do the translations. The list of necessary 'included files is a
+bit messy but once installed is pretty easy.
+
+On one of my RedHat 6.2 systems I installed the following:
+* sgml-common (as an rpm)
+* docbook (as an rpm)
+* stylesheets (as an rpm)
+* jade (as an rpm)
+* Docbook 4.1 from http://docbook.org
+* DSSSL 157 from http://nwalsh.com/docbook/dsssl/
+
+There are several downloadable descriptions of the DocBook syntax at the
+web sites mentioned above. Note that a lot of the docs only talk about
+version 3.1 with 4.1 as an add-on.
+
+In either case you will need to include in the html/docbook.dsl and most
+likely a couple of defines to achieve a suitable output. I made a
+local dsl file that I called html.dsl that looks like this :
+
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY dbstyle SYSTEM "/usr/lib/sgml/dsssl-157/docbook/html/docbook.dsl"
+CDATA DSSSL>
+]>
+
+<style-sheet>
+<style-specification use="docbook">
+<style-specification-body>
+
+(define nochunks #t) ;; Dont make multiple pages
+(define rootchunk #t) ;; Do make a 'root' page
+(define %use-id-as-filename% #t) ;; Use book id as filename
+(define %html-ext% ".html") ;; give it a proper html extension
+
+</style-specification-body>
+</style-specification>
+<external-specification id="docbook" document="dbstyle">
+</style-sheet>
+
+Note the top block that refers to where the dsssl-157 style sheets are
+installed, if you don’t put them there make sure you edit the file.
+
+To use this stylesheet, have it in your working directory along with your
+sgml files. Jade does the actual conversion to html, call it like this :
+
+jade -t sgml -d html.dsl stuff.sgml
+
+To create the text version run the html through lynx :
+
+Lynx -dump -nolist stuff.html > stuff.txt
+
+These instructions are crude by might help someone get going. Please feel
+free to contact me if you have any questions or if you can correct any one
+of the many mistakes I must have made above.
+
+David
+
+==========================================================================
+
+This directory now contains a ./configure script and Makefile to
+support the automated building of man pages (including HTML versions).
+The DocBook V4.1 DTD and ISO entity files have also been included in CVS
+to make sure we are all working from the same plate.
+
+The SGML_CATALOG_FILES environment variable should be set as follows
+(this assumes you have a working local installation of jade and
+Norman's Walsh's DSSSL stylesheets):
+
+ export SGML_CATALOG_FILES=$SGML_CATALOG_FILES:./dbsgml/catalog
+
+
+--jerry
diff --git a/docs/docbook/global.ent b/docs/docbook/global.ent
new file mode 100644
index 00000000000..91286de98be
--- /dev/null
+++ b/docs/docbook/global.ent
@@ -0,0 +1,33 @@
+<!-- Global Entities File -->
+
+
+<!-- Email Address' -->
+<!ENTITY email.dbannon 'D.Bannon@latrobe.edu.au'>
+<!ENTITY email.jmoore 'jmoore@php.net'>
+<!ENTITY email.jerry 'jerry@samba.org'>
+<!ENTITY email.patches 'samba-patches@samba.org'>
+
+<!-- URL's -->
+<!ENTITY url.samba.cvsinfo 'http://pserver.samba.org/samba/cvs.html'>
+<!ENTITY url.pdc-howto.local 'samba-pdc-howto.html'>
+<!ENTITY url.samba-tng 'http://www.samba-tng.org'>
+<!ENTITY url.samba.doc 'http://bioserve.latrobe.edu.au/samba/'>
+<!ENTITY url.ultraedit 'http://www.ultraedit.com'>
+<!ENTITY url.vi-windows 'http://home.snafu.de/ramo/WinViEn.htm'>
+<!ENTITY url.pfe 'http://www.lancs.ac.uk/people/cpaap/pfe/'>
+<!ENTITY url.server-tools.win95 'ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE'>
+<!ENTITY url.server-tools.winnt 'ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE'>
+<!ENTITY url.tcpdump 'http://www.tcpdump.org/'>
+<!ENTITY url.samba 'http://samba.org'>
+<!ENTITY url.samba-ldap-howto 'http://www.unav.es/cti/ldap-smb-howto.html'>
+<!ENTITY url.samba-tng.home 'http://www.kneschke.de/projekte/samba_tng/'>
+<!ENTITY url.samba.mailinglist.ntdom 'http://lists.samba.org/mailman/roster/samba-ntdom'>
+<!ENTITY url.samba.cifs 'http://samba.org/cifs/'>
+<!ENTITY url.ntdomains-for-unix 'http://mailhost.cb1.com/~lkcl/ntdom/'>
+<!ENTITY url.samba.specs.old 'ftp://ftp.microsoft.com/developr/drg/CIFS/'>
+<!ENTITY url.rfc.1001 'http://ds.internic.net/rfc/rfc1001.txt'>
+<!ENTITY url.rfc.1002 'http://ds.internic.net/rfc/rfc1002.txt'>
+
+<!-- Misc -->
+<!ENTITY samba.pub.cvshost 'pserver.samba.org'>
+
diff --git a/docs/docbook/manpages/findsmb.1.sgml b/docs/docbook/manpages/findsmb.1.sgml
new file mode 100644
index 00000000000..d8f436c4a12
--- /dev/null
+++ b/docs/docbook/manpages/findsmb.1.sgml
@@ -0,0 +1,131 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="findsmb">
+
+<refmeta>
+ <refentrytitle>findsmb</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>findsmb</refname>
+ <refpurpose>list info about machines that respond to SMB
+ name queries on a subnet</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>findsmb</command>
+ <arg choice="opt">subnet broadcast address</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This perl script is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>findsmb</command> is a perl script that
+ prints out several pieces of information about machines
+ on a subnet that respond to SMB name query requests.
+ It uses <ulink url="nmblookup.1.html"><command>
+ nmblookup(1)</command></ulink> and <ulink url="smbclient.1.html">
+ <command>smbclient(1)</command></ulink> to obtain this information.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>subnet broadcast address</term>
+ <listitem><para>Without this option, <command>findsmb
+ </command> will probe the subnet of the machine where
+ <command>findsmb</command> is run. This value is passed
+ to <command>nmblookup</command> as part of the
+ <constant>-B</constant> option</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para>The output of <command>findsmb</command> lists the following
+ information for all machines that respond to the initial
+ <command>nmblookup</command> for any name: IP address, NetBIOS name,
+ Workgroup name, operating system, and SMB server version.</para>
+
+ <para>There will be a '+' in front of the workgroup name for
+ machines that are local master browsers for that workgroup. There
+ will be an '*' in front of the workgroup name for
+ machines that are the domain master browser for that workgroup.
+ Machines that are running Windows, Windows 95 or Windows 98 will
+ not show any information about the operating system or server
+ version.</para>
+
+ <para>The command must be run on a system without <ulink
+ url="nmbd.8.html"><command>nmbd</command></ulink> running.
+ If <command>nmbd</command> is running on the system, you will
+ only get the IP address and the DNS name of the machine. To
+ get proper responses from Windows 95 and Windows 98 machines,
+ the command must be run as root. </para>
+
+ <para>For example running <command>findsmb</command> on a machine
+ without <command>nmbd</command> running would yield output similar
+ to the following</para>
+
+ <screen><computeroutput>
+IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION
+---------------------------------------------------------------------
+192.168.35.10 MINESET-TEST1 [DMVENGR]
+192.168.35.55 LINUXBOX *[MYGROUP] [Unix] [Samba 2.0.6]
+192.168.35.56 HERBNT2 [HERB-NT]
+192.168.35.63 GANDALF [MVENGR] [Unix] [Samba 2.0.5a for IRIX]
+192.168.35.65 SAUNA [WORKGROUP] [Unix] [Samba 1.9.18p10]
+192.168.35.71 FROGSTAR [ENGR] [Unix] [Samba 2.0.0 for IRIX]
+192.168.35.78 HERBDHCP1 +[HERB]
+192.168.35.88 SCNT2 +[MVENGR] [Windows NT 4.0] [NT LAN Manager 4.0]
+192.168.35.93 FROGSTAR-PC [MVENGR] [Windows 5.0] [Windows 2000 LAN Manager]
+192.168.35.97 HERBNT1 *[HERB-NT] [Windows NT 4.0] [NT LAN Manager 4.0]
+ </computeroutput></screen>
+
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="nmbd.8.html"><command>nmbd(8)</command></ulink>,
+ <ulink url="smbclient.1.html"><command>smbclient(1)
+ </command></ulink>, and <ulink url="nmblookup.1.html">
+ <command>nmblookup(1)</command></ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/lmhosts.5.sgml b/docs/docbook/manpages/lmhosts.5.sgml
new file mode 100644
index 00000000000..7934c18e8ec
--- /dev/null
+++ b/docs/docbook/manpages/lmhosts.5.sgml
@@ -0,0 +1,114 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="lmhosts">
+
+<refmeta>
+ <refentrytitle>lmhosts</refentrytitle>
+ <manvolnum>5</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>lmhosts</refname>
+ <refpurpose>The Samba NetBIOS hosts file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <para><filename>lmhosts</filename> is the <ulink url="samba.7.html">
+ Samba</ulink> NetBIOS name to IP address mapping file.</para>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This file is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><filename>lmhosts</filename> is the <emphasis>Samba
+ </emphasis> NetBIOS name to IP address mapping file. It
+ is very similar to the <filename>/etc/hosts</filename> file
+ format, except that the hostname component must correspond
+ to the NetBIOS naming format.</para>
+</refsect1>
+
+<refsect1>
+ <title>FILE FORMAT</title>
+ <para>It is an ASCII file containing one line for NetBIOS name.
+ The two fields on each line are separated from each other by
+ white space. Any entry beginning with '#' is ignored. Each line
+ in the lmhosts file contains the following information :</para>
+
+ <itemizedlist>
+ <listitem><para>IP Address - in dotted decimal format.</para>
+ </listitem>
+
+ <listitem><para>NetBIOS Name - This name format is a
+ maximum fifteen character host name, with an optional
+ trailing '#' character followed by the NetBIOS name type
+ as two hexadecimal digits.</para>
+
+ <para>If the trailing '#' is omitted then the given IP
+ address will be returned for all names that match the given
+ name, whatever the NetBIOS name type in the lookup.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>An example follows :</para>
+
+ <para><programlisting>
+#
+# Sample Samba lmhosts file.
+#
+192.9.200.1 TESTPC
+192.9.200.20 NTSERVER#20
+192.9.200.21 SAMBASERVER
+ </programlisting></para>
+
+ <para>Contains three IP to NetBIOS name mappings. The first
+ and third will be returned for any queries for the names "TESTPC"
+ and "SAMBASERVER" respectively, whatever the type component of
+ the NetBIOS name requested.</para>
+
+ <para>The second mapping will be returned only when the "0x20" name
+ type for a name "NTSERVER" is queried. Any other name type will not
+ be resolved.</para>
+
+ <para>The default location of the <filename>lmhosts</filename> file
+ is in the same directory as the <ulink url="smb.conf.5.html">
+ smb.conf(5)></ulink> file.</para>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbclient.1.html"><command>smbclient(1)
+ </command></ulink>, <ulink url="smb.conf.5.html#NAMERESOLVEORDER">
+ smb.conf(5)</ulink>, and <ulink url="smbpasswd.8.html"><command>
+ smbpasswd(8)</command></ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/make_smbcodepage.1.sgml b/docs/docbook/manpages/make_smbcodepage.1.sgml
new file mode 100644
index 00000000000..a36f9b968c1
--- /dev/null
+++ b/docs/docbook/manpages/make_smbcodepage.1.sgml
@@ -0,0 +1,197 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="make-smbcodepage">
+
+<refmeta>
+ <refentrytitle>make_smbcodepage</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>make_smbcodepage</refname>
+ <refpurpose>construct a codepage file for Samba</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>make_smbcodepage</command>
+ <arg choice="req">c|d</arg>
+ <arg choice="req">codepage</arg>
+ <arg choice="req">inputfile</arg>
+ <arg choice="req">outputfile</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>make_smbcodepage</command> compiles or de-compiles
+ codepage files for use with the internationalization features
+ of Samba 2.2</para>
+</refsect1>
+
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>c|d</term>
+ <listitem><para>This tells <command>make_smbcodepage</command>
+ if it is compiling (<parameter>c</parameter>) a text format code
+ page file to binary, or (<parameter>d</parameter>) de-compiling
+ a binary codepage file to text. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>codepage</term>
+ <listitem><para>This is the codepage we are processing (a
+ number, e.g. 850). </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>inputfile</term>
+ <listitem><para>This is the input file to process. In
+ the <parameter>c</parameter> case this will be a text
+ codepage definition file such as the ones found in the Samba
+ <filename>source/codepages</filename> directory. In
+ the <parameter>d</parameter> case this will be the
+ binary format codepage definition file normally found in
+ the <filename>lib/codepages</filename> directory in the
+ Samba install directory path.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>outputfile</term>
+ <listitem><para>This is the output file to produce.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>Samba Codepage Files</title>
+
+ <para>A text Samba codepage definition file is a description
+ that tells Samba how to map from upper to lower case for
+ characters greater than ascii 127 in the specified DOS code page.
+ Note that for certain DOS codepages (437 for example) mapping
+ from lower to upper case may be non-symmetrical. For example, in
+ code page 437 lower case a acute maps to a plain upper case A
+ when going from lower to upper case, but plain upper case A maps
+ to plain lower case a when lower casing a character. </para>
+
+ <para>A binary Samba codepage definition file is a binary
+ representation of the same information, including a value that
+ specifies what codepage this file is describing. </para>
+
+ <para>As Samba does not yet use UNICODE (current for Samba version 2.2)
+ you must specify the client code page that your DOS and Windows
+ clients are using if you wish to have case insensitivity done
+ correctly for your particular language. The default codepage Samba
+ uses is 850 (Western European). Text codepage definition sample files
+ are provided in the Samba distribution for codepages 437 (USA), 737 (Greek),
+ 850 (Western European) 852 (MS-DOS Latin 2), 861 (Icelandic), 866 (Cyrillic),
+ 932 (Kanji SJIS), 936 (Simplified Chinese), 949 (Hangul) and 950 (Traditional
+ Chinese). Users are encouraged to write text codepage definition files for
+ their own code pages and donate them to samba@samba.org. All codepage files
+ in the Samba <filename>source/codepages</filename> directory are
+ compiled and installed when a <command>'make install'</command>
+ command is issued there. </para>
+
+ <para>The client codepage used by the <command>smbd</command> server
+ is configured using the <command>client code page</command> parameter
+ in the <command>smb.conf</command> file. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>Files</title>
+
+ <para><command>codepage_def.&lt;codepage&gt;</command></para>
+
+ <para>These are the input (text) codepage files provided in the
+ Samba <filename>source/codepages</filename> directory.</para>
+
+ <para>A text codepage definition file consists of multiple lines
+ containing four fields. These fields are:</para>
+
+ <itemizedlist>
+ <listitem><para><command>lower</command>: which is the
+ (hex) lower case character mapped on this line.</para>
+ </listitem>
+
+ <listitem><para><command>upper</command>: which is the (hex)
+ upper case character that the lower case character will map to.
+ </para></listitem>
+
+ <listitem><para><command>map upper to lower</command> which
+ is a boolean value (put either True or False here) which tells
+ Samba if it is to map the given upper case character to the
+ given lower case character when lower casing a filename.
+ </para></listitem>
+
+ <listitem><para><command>map lower to upper</command> which
+ is a boolean value (put either True or False here) which tells
+ Samba if it is to map the given lower case character to the
+ given upper case character when upper casing a filename.
+ </para></listitem>
+ </itemizedlist>
+
+
+ <para><command>codepage.&lt;codepage&gt;</command> - These are the
+ output (binary) codepage files produced and placed in the Samba
+ destination <filename>lib/codepage</filename> directory. </para>
+</refsect1>
+
+<refsect1>
+ <title>Installation</title>
+
+ <para>The location of the server and its support files is a
+ matter for individual system administrators. The following are
+ thus suggestions only. </para>
+
+ <para>It is recommended that the <command>make_smbcodepage
+ </command> program be installed under the <filename>/usr/local/samba
+ </filename> hierarchy, in a directory readable by all, writeable
+ only by root. The program itself should be executable by all. The
+ program should NOT be setuid or setgid! </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/make_unicodemap.1.sgml b/docs/docbook/manpages/make_unicodemap.1.sgml
new file mode 100644
index 00000000000..5e7292341b0
--- /dev/null
+++ b/docs/docbook/manpages/make_unicodemap.1.sgml
@@ -0,0 +1,172 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="make-unicodemap">
+
+<refmeta>
+ <refentrytitle>make_unicodemap</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>make_unicodemap</refname>
+ <refpurpose>construct a unicode map file for Samba</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>make_unicodemap</command>
+ <arg choice="req">codepage</arg>
+ <arg choice="req">inputfile</arg>
+ <arg choice="req">outputfile</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>
+ This tool is part of the <ulink url="samba.7.html">Samba</ulink>
+ suite.
+ </para>
+
+ <para>
+ <command>make_unicodemap</command> compiles text unicode map
+ files into binary unicode map files for use with the
+ internationalization features of Samba 2.2.
+ </para>
+</refsect1>
+
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>codepage</term>
+ <listitem><para>This is the codepage or UNIX character
+ set we are processing (a number, e.g. 850).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>inputfile</term>
+ <listitem><para>This is the input file to process. This is a
+ text unicode map file such as the ones found in the Samba
+ <filename>source/codepages</filename> directory.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>outputfile</term>
+ <listitem><para>This is the binary output file to produce.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>Samba Unicode Map Files</title>
+
+ <para>
+ A text Samba unicode map file is a description that tells Samba
+ how to map characters from a specified DOS code page or UNIX character
+ set to 16 bit unicode.
+ </para>
+
+ <para>A binary Samba unicode map file is a binary representation
+ of the same information, including a value that specifies what
+ codepage or UNIX character set this file is describing.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>Files</title>
+
+ <para><filename>CP&lt;codepage&gt;.TXT</filename></para>
+
+ <para>
+ These are the input (text) unicode map files provided
+ in the Samba <filename>source/codepages</filename>
+ directory.
+ </para>
+
+ <para>
+ A text unicode map file consists of multiple lines
+ containing two fields. These fields are :
+ </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>character</parameter> - which is
+ the (hex) character mapped on this line.
+ </para></listitem>
+
+ <listitem><para><parameter>unicode</parameter> - which
+ is the (hex) 16 bit unicode character that the character
+ will map to.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ <filename>unicode_map.&lt;codepage&gt;</filename> - These are
+ the output (binary) unicode map files produced and placed in
+ the Samba destination <filename>lib/codepage</filename>
+ directory.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>Installation</title>
+
+ <para>
+ The location of the server and its support files is a matter
+ for individual system administrators. The following are thus
+ suggestions only.
+ </para>
+
+ <para>
+ It is recommended that the <command>make_unicodemap</command>
+ program be installed under the
+ <filename>$prefix/samba</filename> hierarchy,
+ in a directory readable by all, writeable only by root. The
+ program itself should be executable by all. The program
+ should NOT be setuid or setgid!
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/nmbd.8.sgml b/docs/docbook/manpages/nmbd.8.sgml
new file mode 100644
index 00000000000..edfa9b4fca4
--- /dev/null
+++ b/docs/docbook/manpages/nmbd.8.sgml
@@ -0,0 +1,341 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="nmbd">
+
+<refmeta>
+ <refentrytitle>nmbd</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>nmbd</refname>
+ <refpurpose>NetBIOS name server to provide NetBIOS
+ over IP naming services to clients</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>nmbd</command>
+ <arg choice="opt">-D</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-o</arg>
+ <arg choice="opt">-P</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-V</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-H &lt;lmhosts file&gt;</arg>
+ <arg choice="opt">-l &lt;log directory&gt;</arg>
+ <arg choice="opt">-n &lt;primary netbios name&gt;</arg>
+ <arg choice="opt">-p &lt;port number&gt;</arg>
+ <arg choice="opt">-s &lt;configuration file&gt;</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+ <para>This program is part of the Samba suite.</para>
+
+ <para><command>nmbd</command> is a server that understands
+ and can reply to NetBIOS over IP name service requests, like
+ those produced by SMB/CIFS clients such as Windows 95/98/ME,
+ Windows NT, Windows 2000, and LanManager clients. It also
+ participates in the browsing protocols which make up the
+ Windows "Network Neighborhood" view.</para>
+
+ <para>SMB/CIFS clients, when they start up, may wish to
+ locate an SMB/CIFS server. That is, they wish to know what
+ IP number a specified host is using.</para>
+
+ <para>Amongst other services, <command>nmbd</command> will
+ listen for such requests, and if its own NetBIOS name is
+ specified it will respond with the IP number of the host it
+ is running on. Its "own NetBIOS name" is by
+ default the primary DNS name of the host it is running on,
+ but this can be overridden with the <emphasis>-n</emphasis>
+ option (see OPTIONS below). Thus <command>nmbd</command> will
+ reply to broadcast queries for its own name(s). Additional
+ names for <command>nmbd</command> to respond on can be set
+ via parameters in the <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> configuration file.</para>
+
+ <para><command>nmbd</command> can also be used as a WINS
+ (Windows Internet Name Server) server. What this basically means
+ is that it will act as a WINS database server, creating a
+ database from name registration requests that it receives and
+ replying to queries from clients for these names.</para>
+
+ <para>In addition, <command>nmbd</command> can act as a WINS
+ proxy, relaying broadcast queries from clients that do
+ not understand how to talk the WINS protocol to a WIN
+ server.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-D</term>
+ <listitem><para>If specified, this parameter causes
+ <command>nmbd</command> to operate as a daemon. That is,
+ it detaches itself and runs in the background, fielding
+ requests on the appropriate port. By default, <command>nmbd</command>
+ will operate as a daemon if launched from a command shell.
+ nmbd can also be operated from the <command>inetd</command>
+ meta-daemon, although this is not recommended.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>If this parameter is specified, each new
+ connection will append log messages to the log file.
+ This is the default.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o</term>
+ <listitem><para>If this parameter is specified, the
+ log files will be overwritten when opened. By default,
+ <command>smbd</command> will append entries to the log
+ files.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Prints the help information (usage)
+ for <command>nmbd</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;filename&gt;</term>
+ <listitem><para>NetBIOS lmhosts file. The lmhosts
+ file is a list of NetBIOS names to IP addresses that
+ is loaded by the nmbd server and used via the name
+ resolution mechanism <ulink url="smb.conf.5.html#nameresolveorder">
+ name resolve order</ulink> described in <ulink
+ url="smb.conf.5.html"> <filename>smb.conf(5)</filename></ulink>
+ to resolve any NetBIOS name queries needed by the server. Note
+ that the contents of this file are <emphasis>NOT</emphasis>
+ used by <command>nmbd</command> to answer any name queries.
+ Adding a line to this file affects name NetBIOS resolution
+ from this host <emphasis>ONLY</emphasis>.</para>
+
+ <para>The default path to this file is compiled into
+ Samba as part of the build process. Common defaults
+ are <filename>/usr/local/samba/lib/lmhosts</filename>,
+ <filename>/usr/samba/lib/lmhosts</filename> or
+ <filename>/etc/lmhosts</filename>. See the <ulink url="lmhosts.5.html">
+ <filename>lmhosts(5)</filename></ulink> man page for details on the
+ contents of this file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-V</term>
+ <listitem><para>Prints the version number for
+ <command>nmbd</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-d &lt;debug level&gt;</term>
+ <listitem><para>debuglevel is an integer
+ from 0 to 10. The default value if this parameter is
+ not specified is zero.</para>
+
+ <para>The higher this value, the more detail will
+ be logged to the log files about the activities of the
+ server. At level 0, only critical errors and serious
+ warnings will be logged. Level 1 is a reasonable level for
+ day to day running - it generates a small amount of
+ information about operations carried out.</para>
+
+ <para>Levels above 1 will generate considerable amounts
+ of log data, and should only be used when investigating
+ a problem. Levels above 3 are designed for use only by developers
+ and generate HUGE amounts of log data, most of which is extremely
+ cryptic.</para>
+
+ <para>Note that specifying this parameter here will override
+ the <ulink url="smb.conf.5.html#loglevel">log level</ulink>
+ parameter in the <ulink url="smb.conf.5.html"><filename>
+ smb.conf</filename></ulink> file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-l &lt;log directory&gt;</term>
+ <listitem><para>The -l parameter specifies a directory
+ into which the "log.nmbd" log file will be created
+ for operational data from the running
+ <command>nmbd</command> server.</para>
+
+ <para>The default log directory is compiled into Samba
+ as part of the build process. Common defaults are <filename>
+ /usr/local/samba/var/log.nmb</filename>, <filename>
+ /usr/samba/var/log.nmb</filename> or
+ <filename>/var/log/log.nmb</filename>.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-n &lt;primary NetBIOS name&gt;</term>
+ <listitem><para>This option allows you to override
+ the NetBIOS name that Samba uses for itself. This is identical
+ to setting the <ulink url="smb.conf.5.html#netbiosname">
+ NetBIOS name</ulink> parameter in the <ulink url="smb.conf.5.html">
+ <filename>smb.conf</filename></ulink> file. However, a command
+ line setting will take precedence over settings in
+ <filename>smb.conf</filename>.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-p &lt;UDP port number&gt;</term>
+ <listitem><para>UDP port number is a positive integer value.
+ This option changes the default UDP port number (normally 137)
+ that <command>nmbd</command> responds to name queries on. Don't
+ use this option unless you are an expert, in which case you
+ won't need help!</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s &lt;configuration file&gt;</term>
+ <listitem><para>The default configuration file name
+ is set at build time, typically as <filename>
+ /usr/local/samba/lib/smb.conf</filename>, but
+ this may be changed when Samba is autoconfigured.</para>
+
+ <para>The file specified contains the configuration details
+ required by the server. See <ulink url="smb.conf.5.html">
+ <filename>smb.conf(5)</filename></ulink> for more information.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/inetd.conf</filename></term>
+ <listitem><para>If the server is to be run by the
+ <command>inetd</command> meta-daemon, this file
+ must contain suitable startup information for the
+ meta-daemon. See the section INSTALLATION below.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/rc</filename></term>
+ <listitem><para>or whatever initialization script your
+ system uses).</para>
+
+ <para>If running the server as a daemon at startup,
+ this file will need to contain an appropriate startup
+ sequence for the server. See the section INSTALLATION
+ below.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/services</filename></term>
+ <listitem><para>If running the server via the
+ meta-daemon <command>inetd</command>, this file
+ must contain a mapping of service name (e.g., netbios-ssn)
+ to service port (e.g., 139) and protocol type (e.g., tcp).
+ See the section INSTALLATION below.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/usr/local/samba/lib/smb.conf</filename></term>
+ <listitem><para>This is the default location of the
+ <ulink url="smb.conf.5.html"><filename>smb.conf</filename></ulink>
+ server configuration file. Other common places that systems
+ install this file are <filename>/usr/samba/lib/smb.conf</filename>
+ and <filename>/etc/smb.conf</filename>.</para>
+
+ <para>When run as a WINS server (see the
+ <ulink url="smb.conf.5.html#winssupport">wins support</ulink>
+ parameter in the <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> man page), <command>nmbd</command>
+ will store the WINS database in the file <filename>wins.dat</filename>
+ in the <filename>var/locks</filename> directory configured under
+ wherever Samba was configured to install itself.</para>
+
+ <para>If <command>nmbd</command> is acting as a <emphasis>
+ browse master</emphasis> (see the <ulink
+ url="smb.conf.5.html#localmaster">local master</ulink>
+ parameter in the <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> man page), <command>nmbd</command>
+ will store the browsing database in the file <filename>browse.dat
+ </filename> in the <filename>var/locks</filename> directory
+ configured under wherever Samba was configured to install itself.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>SIGNALS</title>
+
+ <para>To shut down an <command>nmbd</command> process it is recommended
+ that SIGKILL (-9) <emphasis>NOT</emphasis> be used, except as a last
+ resort, as this may leave the name database in an inconsistent state.
+ The correct way to terminate <command>nmbd</command> is to send it
+ a SIGTERM (-15) signal and wait for it to die on its own.</para>
+
+ <para><command>nmbd</command> will accept SIGHUP, which will cause
+ it to dump out its namelists into the file <filename>namelist.debug
+ </filename> in the <filename>/usr/local/samba/var/locks</filename>
+ directory (or the <filename>var/locks</filename> directory configured
+ under wherever Samba was configured to install itself). This will also
+ cause <command>nmbd</command> to dump out its server database in
+ the <filename>log.nmb</filename> file.</para>
+
+ <para>The debug log level of nmbd may be raised or lowered using
+ <ulink url="smbcontrol.1.html"><command>smbcontrol(1)</command>
+ </ulink> (SIGUSR[1|2] signals are no longer used in Samba 2.2). This is
+ to allow transient problems to be diagnosed, whilst still running
+ at a normally low log level.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><command>inetd(8)</command>, <ulink
+ url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html"><filename>smb.conf(5)</filename>
+ </ulink>, <ulink url="smbclient.1.html"><command>smbclient(1)
+ </command></ulink>, <ulink url="testparm.1.html"><command>
+ testparm(1)</command></ulink>, <ulink url="testprns.1.html">
+ <command>testprns(1)</command></ulink>, and the Internet RFC's
+ <filename>rfc1001.txt</filename>, <filename>rfc1002.txt</filename>.
+ In addition the CIFS (formerly SMB) specification is available
+ as a link from the Web page <ulink url="http://samba.org/cifs/">
+ http://samba.org/cifs/</ulink>.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/nmblookup.1.sgml b/docs/docbook/manpages/nmblookup.1.sgml
new file mode 100644
index 00000000000..67efac56343
--- /dev/null
+++ b/docs/docbook/manpages/nmblookup.1.sgml
@@ -0,0 +1,249 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="nmblookup">
+
+<refmeta>
+ <refentrytitle>nmblookup</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>nmblookup</refname>
+ <refpurpose>NetBIOS over TCP/IP client used to lookup NetBIOS
+ names</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>nmblookup</command>
+ <arg choice="opt">-M</arg>
+ <arg choice="opt">-R</arg>
+ <arg choice="opt">-S</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-A</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-B &lt;broadcast address&gt;</arg>
+ <arg choice="opt">-U &lt;unicast address&gt;</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-i &lt;NetBIOS scope&gt;</arg>
+ <arg choice="opt">-T</arg>
+ <arg choice="req">name</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>nmblookup</command> is used to query NetBIOS names
+ and map them to IP addresses in a network using NetBIOS over TCP/IP
+ queries. The options allow the name queries to be directed at a
+ particular IP broadcast area or to a particular machine. All queries
+ are done over UDP.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-M</term>
+ <listitem><para>Searches for a master browser by looking
+ up the NetBIOS name <replaceable>name</replaceable> with a
+ type of <constant>0x1d</constant>. If <replaceable>
+ name</replaceable> is "-" then it does a lookup on the special name
+ <constant>__MSBROWSE__</constant>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-R</term>
+ <listitem><para>Set the recursion desired bit in the packet
+ to do a recursive lookup. This is used when sending a name
+ query to a machine running a WINS server and the user wishes
+ to query the names in the WINS server. If this bit is unset
+ the normal (broadcast responding) NetBIOS processing code
+ on a machine is used instead. See rfc1001, rfc1002 for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S</term>
+ <listitem><para>Once the name query has returned an IP
+ address then do a node status query as well. A node status
+ query returns the NetBIOS names registered by a host.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>Try and bind to UDP port 137 to send and receive UDP
+ datagrams. The reason for this option is a bug in Windows 95
+ where it ignores the source port of the requesting packet
+ and only replies to UDP port 137. Unfortunately, on most UNIX
+ systems root privilege is needed to bind to this port, and
+ in addition, if the <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ daemon is running on this machine it also binds to this port.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem><para>Interpret <replaceable>name</replaceable> as
+ an IP Address and do a node status query on this address.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Print a help (usage) message.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-B &lt;broadcast address&gt;</term>
+ <listitem><para>Send the query to the given broadcast address. Without
+ this option the default behavior of nmblookup is to send the
+ query to the broadcast address of the network interfaces as
+ either auto-detected or defined in the <ulink
+ url="smb.conf.5.html#INTERFACES"><parameter>interfaces</parameter>
+ </ulink> parameter of the <filename>smb.conf (5)</filename> file.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-U &lt;unicast address&gt;</term>
+ <listitem><para>Do a unicast query to the specified address or
+ host <replaceable>unicast address</replaceable>. This option
+ (along with the <parameter>-R</parameter> option) is needed to
+ query a WINS server.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-d &lt;debuglevel&gt;</term>
+ <listitem><para>debuglevel is an integer from 0 to 10.</para>
+
+ <para>The default value if this parameter is not specified
+ is zero.</para>
+
+ <para>The higher this value, the more detail will be logged
+ about the activities of <command>nmblookup</command>. At level
+ 0, only critical errors and serious warnings will be logged.</para>
+
+ <para>Levels above 1 will generate considerable amounts of
+ log data, and should only be used when investigating a problem.
+ Levels above 3 are designed for use only by developers and
+ generate HUGE amounts of data, most of which is extremely cryptic.</para>
+
+ <para>Note that specifying this parameter here will override
+ the <ulink url="smb.conf.5.html#LOGLEVEL"><parameter>
+ log level</parameter></ulink> parameter in the <filename>
+ smb.conf(5)</filename> file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s &lt;smb.conf&gt;</term>
+ <listitem><para>This parameter specifies the pathname to
+ the Samba configuration file, <ulink url="smb.conf.5.html">
+ smb.conf(5)</ulink>. This file controls all aspects of
+ the Samba setup on the machine.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i &lt;scope&gt;</term>
+ <listitem><para>This specifies a NetBIOS scope that
+ <command>nmblookup</command> will use to communicate with when
+ generating NetBIOS names. For details on the use of NetBIOS
+ scopes, see rfc1001.txt and rfc1002.txt. NetBIOS scopes are
+ <emphasis>very</emphasis> rarely used, only set this parameter
+ if you are the system administrator in charge of all the
+ NetBIOS systems you communicate with.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-T</term>
+ <listitem><para>This causes any IP addresses found in the
+ lookup to be looked up via a reverse DNS lookup into a
+ DNS name, and printed out before each</para>
+
+ <para><emphasis>IP address .... NetBIOS name</emphasis></para>
+
+ <para> pair that is the normal output.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>name</term>
+ <listitem><para>This is the NetBIOS name being queried. Depending
+ upon the previous options this may be a NetBIOS name or IP address.
+ If a NetBIOS name then the different name types may be specified
+ by appending '#&lt;type&gt' to the name. This name may also be
+ '*', which will return all registered names within a broadcast
+ area.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para><command>nmblookup</command> can be used to query
+ a WINS server (in the same way <command>nslookup</command> is
+ used to query DNS servers). To query a WINS server,
+ <command>nmblookup</command> must be called like this:</para>
+
+ <para><command>nmblookup -U server -R 'name'</command></para>
+
+ <para>For example, running :</para>
+
+ <para><command>nmblookup -U samba.org -R 'IRIX#1B'</command></para>
+
+ <para>would query the WINS server samba.org for the domain
+ master browser (1B name type) for the IRIX workgroup.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="nmbd.8.html"><command>nmbd(8)</command></ulink>,
+ <ulink url="samba.7.html">samba(7)</ulink>, and <ulink
+ url="smb.conf.5.html">smb.conf(5)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/rpcclient.1.sgml b/docs/docbook/manpages/rpcclient.1.sgml
new file mode 100644
index 00000000000..f32e2f9ece6
--- /dev/null
+++ b/docs/docbook/manpages/rpcclient.1.sgml
@@ -0,0 +1,420 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="rpcclient">
+
+<refmeta>
+ <refentrytitle>rpcclient</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>rpcclient</refname>
+ <refpurpose>tool for executing client side
+ MS-RPC functions</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>rpcclient</command>
+ <arg choice="req">server</arg>
+ <arg choice="opt">-A authfile</arg>
+ <arg choice="opt">-c &lt;command string&gt;</arg>
+ <arg choice="opt">-d debuglevel</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-l logfile</arg>
+ <arg choice="opt">-N</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-U username[%password]</arg>
+ <arg choice="opt">-W workgroup</arg>
+ <arg choice="opt">-N</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>rpcclient</command> is a utility initially developed
+ to test MS-RPC functionality in Samba itself. It has undergone
+ several stages of development and stability. Many system administrators
+ have now written scripts around it to manage Windows NT clients from
+ their UNIX workstation. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>server</term>
+ <listitem><para>NetBIOS name of Server to which to connect.
+ The server can be any SMB/CIFS server. The name is
+ resolved using the <ulink url="smb.conf.5.html#NAMERESOLVEORDER">
+ <parameter>name resolve order</parameter></ulink> line from
+ <filename>smb.conf(5)</filename>.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-A filename</term><listitem><para>This option allows
+ you to specify a file from which to read the username and
+ password used in the connection. The format of the file is
+ </para>
+
+ <para><programlisting>
+ username = &lt;value&gt;
+ password = &lt;value&gt;
+ domain = &lt;value&gt;
+ </programlisting></para>
+
+ <para>Make certain that the permissions on the file restrict
+ access from unwanted users. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-c 'command string'</term>
+ <listitem><para>execute semicolon separated commands (listed
+ below)) </para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term>-d debuglevel</term>
+ <listitem><para>set the debuglevel. Debug level 0 is the lowest
+ and 100 being the highest. This should be set to 100 if you are
+ planning on submitting a bug report to the Samba team (see <filename>BUGS.txt</filename>).
+ </para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Print a summary of command line options.
+ </para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term>-l logbasename</term>
+ <listitem><para>File name for log/debug files. The extension
+ <constant>'.client'</constant> will be appended. The log file is never removed
+ by the client.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-N</term>
+ <listitem><para>instruct <command>rpcclient</command> not to ask
+ for a password. By default, <command>rpcclient</command> will prompt
+ for a password. See also the <parameter>-U</parameter> option.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-s smb.conf</term>
+ <listitem><para>Specifies the location of the all important
+ <filename>smb.conf</filename> file. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-U username[%password]</term>
+ <listitem><para>Sets the SMB username or username and password. </para>
+
+ <para>If %password is not specified, the user will be prompted. The
+ client will first check the <envar>USER</envar> environment variable, then the
+ <envar>LOGNAME</envar> variable and if either exists, the
+ string is uppercased. If these environmental variables are not
+ found, the username <constant>GUEST</constant> is used. </para>
+
+ <para>A third option is to use a credentials file which
+ contains the plaintext of the username and password. This
+ option is mainly provided for scripts where the admin doesn't
+ desire to pass the credentials on the command line or via environment
+ variables. If this method is used, make certain that the permissions
+ on the file restrict access from unwanted users. See the
+ <parameter>-A</parameter> for more details. </para>
+
+ <para>Be cautious about including passwords in scripts. Also, on
+ many systems the command line of a running process may be seen
+ via the <command>ps</command> command. To be safe always allow
+ <command>rpcclient</command> to prompt for a password and type
+ it in directly. </para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term>-W domain</term>
+ <listitem><para>Set the SMB domain of the username. This
+ overrides the default domain which is the domain defined in
+ smb.conf. If the domain specified is the same as the server's NetBIOS name,
+ it causes the client to log on using the server's local SAM (as
+ opposed to the Domain SAM). </para></listitem>
+ </varlistentry>
+
+
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>COMMANDS</title>
+
+ <para><emphasis>LSARPC</emphasis></para>
+ <itemizedlist>
+ <listitem><para><command>lsaquery</command></para></listitem>
+
+ <listitem><para><command>lookupsids</command> - Resolve a list
+ of SIDs to usernames.
+ </para></listitem>
+
+ <listitem><para><command>lookupnames</command> - Resolve s list
+ of usernames to SIDs.
+ </para></listitem>
+
+ <listitem><para><command>enumtrusts</command></para></listitem>
+ </itemizedlist>
+ <para> </para>
+
+
+
+ <para><emphasis>SAMR</emphasis></para>
+ <itemizedlist>
+ <listitem><para><command>queryuser</command></para></listitem>
+ <listitem><para><command>querygroup</command></para></listitem>
+ <listitem><para><command>queryusergroups</command></para></listitem>
+ <listitem><para><command>querygroupmem</command></para></listitem>
+ <listitem><para><command>queryaliasmem</command></para></listitem>
+ <listitem><para><command>querydispinfo</command></para></listitem>
+ <listitem><para><command>querydominfo</command></para></listitem>
+ <listitem><para><command>enumdomgroups</command></para></listitem>
+ </itemizedlist>
+ <para> </para>
+
+
+
+ <para><emphasis>SPOOLSS</emphasis></para>
+
+ <itemizedlist>
+ <listitem><para><command>adddriver &lt;arch&gt &lt;config&gt;</command>
+ - Execute an AddPrinterDriver() RPC to install the printer driver
+ information on the server. Note that the driver files should
+ already exist in the directory returned by
+ <command>getdriverdir</command>. Possible values for
+ <parameter>arch</parameter> are the same as those for
+ the <command>getdriverdir</command> command.
+ The <parameter>config</parameter> parameter is defined as
+ follows: </para>
+
+ <para><programlisting>
+ Long Printer Name:\
+ Driver File Name:\
+ Data File Name:\
+ Config File Name:\
+ Help File Name:\
+ Language Monitor Name:\
+ Default Data Type:\
+ Comma Separated list of Files
+ </programlisting></para>
+
+ <para>Any empty fields should be enter as the string "NULL". </para>
+
+ <para>Samba does not need to support the concept of Print Monitors
+ since these only apply to local printers whose driver can make
+ use of a bi-directional link for communication. This field should
+ be "NULL". On a remote NT print server, the Print Monitor for a
+ driver must already be installed prior to adding the driver or
+ else the RPC will fail. </para></listitem>
+
+
+
+
+ <listitem><para><command>addprinter &lt;printername&gt;
+ &lt;sharename&gt; &lt;drivername&gt; &lt;port&gt;</command>
+ - Add a printer on the remote server. This printer
+ will be automatically shared. Be aware that the printer driver
+ must already be installed on the server (see <command>adddriver</command>)
+ and the <parameter>port</parameter>must be a valid port name (see
+ <command>enumports</command>.</para>
+ </listitem>
+
+
+ <listitem><para><command>deldriver</command> - Delete the
+ specified printer driver for all architectures. This
+ does not delete the actual driver files from the server,
+ only the entry from the server's list of drivers.
+ </para></listitem>
+
+ <listitem><para><command>enumdata</command> - Enumerate all
+ printer setting data stored on the server. On Windows NT clients,
+ these values are stored in the registry, while Samba servers
+ store them in the printers TDB. This command corresponds
+ to the MS Platform SDK GetPrinterData() function (* This
+ command is currently unimplemented).</para></listitem>
+
+
+
+ <listitem><para><command>enumjobs &lt;printer&gt;</command>
+ - List the jobs and status of a given printer.
+ This command corresponds to the MS Platform SDK EnumJobs()
+ function (* This command is currently unimplemented).</para></listitem>
+
+
+
+
+ <listitem><para><command>enumports [level]</command>
+ - Executes an EnumPorts() call using the specified
+ info level. Currently only info levels 1 and 2 are supported.
+ </para></listitem>
+
+
+
+ <listitem><para><command>enumdrivers [level]</command>
+ - Execute an EnumPrinterDrivers() call. This lists the various installed
+ printer drivers for all architectures. Refer to the MS Platform SDK
+ documentation for more details of the various flags and calling
+ options. Currently supported info levels are 1, 2, and 3.</para></listitem>
+
+
+
+ <listitem><para><command>enumprinters [level]</command>
+ - Execute an EnumPrinters() call. This lists the various installed
+ and share printers. Refer to the MS Platform SDK documentation for
+ more details of the various flags and calling options. Currently
+ supported info levels are 0, 1, and 2.</para></listitem>
+
+
+
+
+ <listitem><para><command>getdata &lt;printername&gt;</command>
+ - Retrieve the data for a given printer setting. See
+ the <command>enumdata</command> command for more information.
+ This command corresponds to the GetPrinterData() MS Platform
+ SDK function (* This command is currently unimplemented). </para></listitem>
+
+
+
+ <listitem><para><command>getdriver &lt;printername&gt;</command>
+ - Retrieve the printer driver information (such as driver file,
+ config file, dependent files, etc...) for
+ the given printer. This command corresponds to the GetPrinterDriver()
+ MS Platform SDK function. Currently info level 1, 2, and 3 are supported.
+ </para></listitem>
+
+
+ <listitem><para><command>getdriverdir &lt;arch&gt;</command>
+ - Execute a GetPrinterDriverDirectory()
+ RPC to retreive the SMB share name and subdirectory for
+ storing printer driver files for a given architecture. Possible
+ values for <parameter>arch</parameter> are "Windows 4.0"
+ (for Windows 95/98), "Windows NT x86", "Windows NT PowerPC", "Windows
+ Alpha_AXP", and "Windows NT R4000". </para></listitem>
+
+
+
+ <listitem><para><command>getprinter &lt;printername&gt;</command>
+ - Retrieve the current printer information. This command
+ corresponds to the GetPrinter() MS Platform SDK function.
+ </para></listitem>
+
+
+
+ <listitem><para><command>openprinter &lt;printername&gt;</command>
+ - Execute an OpenPrinterEx() and ClosePrinter() RPC
+ against a given printer. </para></listitem>
+
+
+ <listitem><para><command>setdriver &lt;printername&gt; &lt;drivername&gt;</command>
+ - Execute a SetPrinter() command to update the printer driver associated
+ with an installed printer. The printer driver must already be correctly
+ installed on the print server. </para>
+
+ <para>See also the <command>enumprinters</command> and
+ <command>enumdrivers</command> commands for obtaining a list of
+ of installed printers and drivers.</para></listitem>
+
+ </itemizedlist>
+
+
+ <para><emphasis>GENERAL OPTIONS</emphasis></para>
+
+ <itemizedlist>
+ <listitem><para><command>debuglevel</command> - Set the current debug level
+ used to log information.</para></listitem>
+
+ <listitem><para><command>help (?)</command> - Print a listing of all
+ known commands or extended help on a particular command.
+ </para></listitem>
+
+ <listitem><para><command>quit (exit)</command> - Exit <command>rpcclient
+ </command>.</para></listitem>
+ </itemizedlist>
+
+
+</refsect1>
+
+<refsect1>
+ <title>BUGS</title>
+
+ <para><command>rpcclient</command> is designed as a developer testing tool
+ and may not be robust in certain areas (such as command line parsing).
+ It has been known to generate a core dump upon failures when invalid
+ parameters where passed to the interpreter. </para>
+
+ <para>From Luke Leighton's original rpcclient man page:</para>
+
+ <para><emphasis>"WARNING!</emphasis> The MSRPC over SMB code has
+ been developed from examining Network traces. No documentation is
+ available from the original creators (Microsoft) on how MSRPC over
+ SMB works, or how the individual MSRPC services work. Microsoft's
+ implementation of these services has been demonstrated (and reported)
+ to be... a bit flaky in places. </para>
+
+ <para>The development of Samba's implementation is also a bit rough,
+ and as more of the services are understood, it can even result in
+ versions of <command>smbd(8)</command> and <command>rpcclient(1)</command>
+ that are incompatible for some commands or services. Additionally,
+ the developers are sending reports to Microsoft, and problems found
+ or reported to Microsoft are fixed in Service Packs, which may
+ result in incompatibilities." </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of the Samba
+ suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original rpcclient man page was written by Matthew
+ Geddes, Luke Kenneth Casson Leighton, and rewritten by Gerald Carter.
+ The conversion to DocBook for Samba 2.2 was done by Gerald
+ Carter.</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/samba.7.sgml b/docs/docbook/manpages/samba.7.sgml
new file mode 100644
index 00000000000..5d81d9d4468
--- /dev/null
+++ b/docs/docbook/manpages/samba.7.sgml
@@ -0,0 +1,213 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="samba">
+
+<refmeta>
+ <refentrytitle>samba</refentrytitle>
+ <manvolnum>7</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>SAMBA</refname>
+ <refpurpose>A Windows SMB/CIFS fileserver for UNIX</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis><command>Samba</command></cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>The Samba software suite is a collection of programs
+ that implements the Server Message Block (commonly abbreviated
+ as SMB) protocol for UNIX systems. This protocol is sometimes
+ also referred to as the Common Internet File System (CIFS),
+ LanManager or NetBIOS protocol.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><command>smbd</command></term>
+ <listitem><para>The <command>smbd </command>
+ daemon provides the file and print services to
+ SMB clients, such as Windows 95/98, Windows NT, Windows
+ for Workgroups or LanManager. The configuration file
+ for this daemon is described in <filename>smb.conf</filename>
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>nmbd</command></term>
+ <listitem><para>The <command>nmbd</command>
+ daemon provides NetBIOS nameserving and browsing
+ support. The configuration file for this daemon
+ is described in <filename>smb.conf</filename></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>smbclient</command></term>
+ <listitem><para>The <command>smbclient</command>
+ program implements a simple ftp-like client. This
+ is useful for accessing SMB shares on other compatible
+ servers (such as Windows NT), and can also be used
+ to allow a UNIX box to print to a printer attached to
+ any SMB server (such as a PC running Windows NT).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>testparm</command></term>
+ <listitem><para>The <command>testparm</command>
+ utility is a simple syntax checker for Samba's
+ <filename>smb.conf</filename>configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>testprns</command></term>
+ <listitem><para>The <command>testprns</command>
+ utility supports testing printer names defined
+ in your <filename>printcap></filename> file used
+ by Samba.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>smbstatus</command></term>
+ <listitem><para>The <command>smbstatus</command>
+ tool provides access to information about the
+ current connections to <command>smbd</command>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>nmblookup</command></term>
+ <listitem><para>The <command>nmblookup</command>
+ tools allows NetBIOS name queries to be made
+ from a UNIX host.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>make_smbcodepage</command></term>
+ <listitem><para>The <command>make_smbcodepage</command>
+ utility provides a means of creating SMB code page
+ definition files for your <command>smbd</command> server.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>smbpasswd</command></term>
+ <listitem><para>The <command>smbpasswd</command>
+ command is a tool for changing LanMan and Windows NT
+ password hashes on Samba and Windows NT servers.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>COMPONENTS</title>
+
+ <para>The Samba suite is made up of several components. Each
+ component is described in a separate manual page. It is strongly
+ recommended that you read the documentation that comes with Samba
+ and the manual pages of those components that you use. If the
+ manual pages aren't clear enough then please send a patch or
+ bug report to <ulink url="mailto:samba@samba.org">
+ samba@samba.org</ulink></para>
+
+
+
+</refsect1>
+
+<refsect1>
+ <title>AVAILABILITY</title>
+
+ <para>The Samba software suite is licensed under the
+ GNU Public License(GPL). A copy of that license should
+ have come with the package in the file COPYING. You are
+ encouraged to distribute copies of the Samba suite, but
+ please obey the terms of this license.</para>
+
+ <para>The latest version of the Samba suite can be
+ obtained via anonymous ftp from samba.org in the
+ directory pub/samba/. It is also available on several
+ mirror sites worldwide.</para>
+
+ <para>You may also find useful information about Samba
+ on the newsgroup <ulink url="news:comp.protocols.smb">
+ comp.protocol.smb</ulink> and the Samba mailing
+ list. Details on how to join the mailing list are given in
+ the README file that comes with Samba.</para>
+
+ <para>If you have access to a WWW viewer (such as Netscape
+ or Mosaic) then you will also find lots of useful information,
+ including back issues of the Samba mailing list, at
+ <ulink url="http://lists.samba.org/">http://lists.samba.org</ulink>.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of the
+ Samba suite. </para>
+</refsect1>
+
+<refsect1>
+ <title>CONTRIBUTIONS</title>
+
+ <para>If you wish to contribute to the Samba project,
+ then I suggest you join the Samba mailing list at
+ <ulink url="http://lists.samba.org/">http://lists.samba.org</ulink>.
+ </para>
+
+ <para>If you have patches to submit or bugs to report
+ then you may mail them directly to samba-patches@samba.org.
+ Note, however, that due to the enormous popularity of this
+ package the Samba Team may take some time to respond to mail. We
+ prefer patches in <command>diff -u</command> format.</para>
+</refsect1>
+
+<refsect1>
+ <title>CONTRIBUTORS</title>
+
+ <para>Contributors to the project are now too numerous
+ to mention here but all deserve the thanks of all Samba
+ users. To see a full list, look at <ulink
+ url="ftp://samba.org/pub/samba/alpha/change-log">
+ ftp://samba.org/pub/samba/alpha/change-log</ulink>
+ for the pre-CVS changes and at <ulink
+ url="ftp://samba.org/pub/samba/alpha/cvs.log">
+ ftp://samba.org/pub/samba/alpha/cvs.log</ulink>
+ for the contributors to Samba post-CVS. CVS is the Open Source
+ source code control system used by the Samba Team to develop
+ Samba. The project would have been unmanageable without it.</para>
+
+ <para>In addition, several commercial organizations now help
+ fund the Samba Team with money and equipment. For details see
+ the Samba Web pages at <ulink
+ url="http://samba.org/samba/samba-thanks.html">
+ http://samba.org/samba/samba-thanks.html</ulink>.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smb.conf.5.sgml b/docs/docbook/manpages/smb.conf.5.sgml
new file mode 100644
index 00000000000..a7328e7cf63
--- /dev/null
+++ b/docs/docbook/manpages/smb.conf.5.sgml
@@ -0,0 +1,8486 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smb.conf">
+
+<refmeta>
+ <refentrytitle>smb.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smb.conf</refname>
+ <refpurpose>The configuration file for the Samba suite</refpurpose>
+</refnamediv>
+
+<refsect1>
+ <title>SYNOPSIS</title>
+
+ <para>The <filename>smb.conf</filename> file is a configuration
+ file for the Samba suite. <filename>smb.conf</filename> contains
+ runtime configuration information for the Samba programs. The
+ <filename>smb.conf</filename> file is designed to be configured and
+ administered by the <ulink url="swat.8.html"><command>swat(8)</command>
+ </ulink> program. The complete description of the file format and
+ possible parameters held within are here for reference purposes.</para>
+</refsect1>
+
+<refsect1>
+ <title id="FILEFORMATSECT">FILE FORMAT</title>
+
+ <para>The file consists of sections and parameters. A section
+ begins with the name of the section in square brackets and continues
+ until the next section begins. Sections contain parameters of the
+ form</para>
+
+ <para><replaceable>name</replaceable> = <replaceable>value
+ </replaceable></para>
+
+ <para>The file is line-based - that is, each newline-terminated
+ line represents either a comment, a section name or a parameter.</para>
+
+ <para>Section and parameter names are not case sensitive.</para>
+
+ <para>Only the first equals sign in a parameter is significant.
+ Whitespace before or after the first equals sign is discarded.
+ Leading, trailing and internal whitespace in section and parameter
+ names is irrelevant. Leading and trailing whitespace in a parameter
+ value is discarded. Internal whitespace within a parameter value
+ is retained verbatim.</para>
+
+ <para>Any line beginning with a semicolon (';') or a hash ('#')
+ character is ignored, as are lines containing only whitespace.</para>
+
+ <para>Any line ending in a '\' is continued
+ on the next line in the customary UNIX fashion.</para>
+
+ <para>The values following the equals sign in parameters are all
+ either a string (no quotes needed) or a boolean, which may be given
+ as yes/no, 0/1 or true/false. Case is not significant in boolean
+ values, but is preserved in string values. Some items such as
+ create modes are numeric.</para>
+</refsect1>
+
+<refsect1>
+ <title>SECTION DESCRIPTIONS</title>
+
+ <para>Each section in the configuration file (except for the
+ [global] section) describes a shared resource (known
+ as a "share"). The section name is the name of the
+ shared resource and the parameters within the section define
+ the shares attributes.</para>
+
+ <para>There are three special sections, [global],
+ [homes] and [printers], which are
+ described under <emphasis>special sections</emphasis>. The
+ following notes apply to ordinary section descriptions.</para>
+
+ <para>A share consists of a directory to which access is being
+ given plus a description of the access rights which are granted
+ to the user of the service. Some housekeeping options are
+ also specifiable.</para>
+
+ <para>Sections are either file share services (used by the
+ client as an extension of their native file systems) or
+ printable services (used by the client to access print services
+ on the host running the server).</para>
+
+ <para>Sections may be designated <emphasis>guest</emphasis> services,
+ in which case no password is required to access them. A specified
+ UNIX <emphasis>guest account</emphasis> is used to define access
+ privileges in this case.</para>
+
+ <para>Sections other than guest services will require a password
+ to access them. The client provides the username. As older clients
+ only provide passwords and not usernames, you may specify a list
+ of usernames to check against the password using the "user ="
+ option in the share definition. For modern clients such as
+ Windows 95/98/ME/NT/2000, this should not be necessary.</para>
+
+ <para>Note that the access rights granted by the server are
+ masked by the access rights granted to the specified or guest
+ UNIX user by the host system. The server does not grant more
+ access than the host system grants.</para>
+
+ <para>The following sample section defines a file space share.
+ The user has write access to the path <filename>/home/bar</filename>.
+ The share is accessed via the share name "foo":</para>
+
+ <screen>
+ <computeroutput>
+ [foo]
+ path = /home/bar
+ writeable = true
+ </computeroutput>
+ </screen>
+
+ <para>The following sample section defines a printable share.
+ The share is readonly, but printable. That is, the only write
+ access permitted is via calls to open, write to and close a
+ spool file. The <emphasis>guest ok</emphasis> parameter means
+ access will be permitted as the default guest user (specified
+ elsewhere):</para>
+
+ <screen>
+ <computeroutput>
+ [aprinter]
+ path = /usr/spool/public
+ writeable = false
+ printable = true
+ guest ok = true
+ </computeroutput>
+ </screen>
+</refsect1>
+
+<refsect1>
+ <title>SPECIAL SECTIONS</title>
+
+ <refsect2>
+ <title>The [global] section</title>
+
+ <para>parameters in this section apply to the server
+ as a whole, or are defaults for sections which do not
+ specifically define certain items. See the notes
+ under PARAMETERS for more information.</para>
+ </refsect2>
+
+ <refsect2>
+ <title id="HOMESECT">The [homes] section</title>
+
+ <para>If a section called homes is included in the
+ configuration file, services connecting clients to their
+ home directories can be created on the fly by the server.</para>
+
+ <para>When the connection request is made, the existing
+ sections are scanned. If a match is found, it is used. If no
+ match is found, the requested section name is treated as a
+ user name and looked up in the local password file. If the
+ name exists and the correct password has been given, a share is
+ created by cloning the [homes] section.</para>
+
+ <para>Some modifications are then made to the newly
+ created share:</para>
+
+ <itemizedlist>
+ <listitem><para>The share name is changed from homes to
+ the located username.</para></listitem>
+
+ <listitem><para>If no path was given, the path is set to
+ the user's home directory.</para></listitem>
+ </itemizedlist>
+
+ <para>If you decide to use a <emphasis>path =</emphasis> line
+ in your [homes] section then you may find it useful
+ to use the %S macro. For example :</para>
+
+ <para><userinput>path = /data/pchome/%S</userinput></para>
+
+ <para>would be useful if you have different home directories
+ for your PCs than for UNIX access.</para>
+
+ <para>This is a fast and simple way to give a large number
+ of clients access to their home directories with a minimum
+ of fuss.</para>
+
+ <para>A similar process occurs if the requested section
+ name is "homes", except that the share name is not
+ changed to that of the requesting user. This method of using
+ the [homes] section works well if different users share
+ a client PC.</para>
+
+ <para>The [homes] section can specify all the parameters
+ a normal service section can specify, though some make more sense
+ than others. The following is a typical and suitable [homes]
+ section:</para>
+
+ <screen>
+ <computeroutput>
+ [homes]
+ writeable = yes
+ </computeroutput>
+ </screen>
+
+ <para>An important point is that if guest access is specified
+ in the [homes] section, all home directories will be
+ visible to all clients <emphasis>without a password</emphasis>.
+ In the very unlikely event that this is actually desirable, it
+ would be wise to also specify <emphasis>read only
+ access</emphasis>.</para>
+
+ <para>Note that the <emphasis>browseable</emphasis> flag for
+ auto home directories will be inherited from the global browseable
+ flag, not the [homes] browseable flag. This is useful as
+ it means setting <emphasis>browseable = no</emphasis> in
+ the [homes] section will hide the [homes] share but make
+ any auto home directories visible.</para>
+ </refsect2>
+
+ <refsect2>
+ <title id="PRINTERSSECT">The [printers] section</title>
+
+ <para>This section works like [homes],
+ but for printers.</para>
+
+ <para>If a [printers] section occurs in the
+ configuration file, users are able to connect to any printer
+ specified in the local host's printcap file.</para>
+
+ <para>When a connection request is made, the existing sections
+ are scanned. If a match is found, it is used. If no match is found,
+ but a [homes] section exists, it is used as described
+ above. Otherwise, the requested section name is treated as a
+ printer name and the appropriate printcap file is scanned to see
+ if the requested section name is a valid printer share name. If
+ a match is found, a new printer share is created by cloning
+ the [printers] section.</para>
+
+ <para>A few modifications are then made to the newly created
+ share:</para>
+
+ <itemizedlist>
+ <listitem><para>The share name is set to the located printer
+ name</para></listitem>
+
+ <listitem><para>If no printer name was given, the printer name
+ is set to the located printer name</para></listitem>
+
+ <listitem><para>If the share does not permit guest access and
+ no username was given, the username is set to the located
+ printer name.</para></listitem>
+ </itemizedlist>
+
+ <para>Note that the [printers] service MUST be
+ printable - if you specify otherwise, the server will refuse
+ to load the configuration file.</para>
+
+ <para>Typically the path specified would be that of a
+ world-writeable spool directory with the sticky bit set on
+ it. A typical [printers] entry would look like
+ this:</para>
+
+ <screen><computeroutput>
+ [printers]
+ path = /usr/spool/public
+ guest ok = yes
+ printable = yes
+ </computeroutput></screen>
+
+ <para>All aliases given for a printer in the printcap file
+ are legitimate printer names as far as the server is concerned.
+ If your printing subsystem doesn't work like that, you will have
+ to set up a pseudo-printcap. This is a file consisting of one or
+ more lines like this:</para>
+
+ <screen>
+ <computeroutput>
+ alias|alias|alias|alias...
+ </computeroutput>
+ </screen>
+
+ <para>Each alias should be an acceptable printer name for
+ your printing subsystem. In the [global] section, specify
+ the new file as your printcap. The server will then only recognize
+ names found in your pseudo-printcap, which of course can contain
+ whatever aliases you like. The same technique could be used
+ simply to limit access to a subset of your local printers.</para>
+
+ <para>An alias, by the way, is defined as any component of the
+ first entry of a printcap record. Records are separated by newlines,
+ components (if there are more than one) are separated by vertical
+ bar symbols ('|').</para>
+
+ <para>NOTE: On SYSV systems which use lpstat to determine what
+ printers are defined on the system you may be able to use
+ "printcap name = lpstat" to automatically obtain a list
+ of printers. See the "printcap name" option
+ for more details.</para>
+ </refsect2>
+</refsect1>
+
+<refsect1>
+ <title>PARAMETERS</title>
+
+ <para>parameters define the specific attributes of sections.</para>
+
+ <para>Some parameters are specific to the [global] section
+ (e.g., <emphasis>security</emphasis>). Some parameters are usable
+ in all sections (e.g., <emphasis>create mode</emphasis>). All others
+ are permissible only in normal sections. For the purposes of the
+ following descriptions the [homes] and [printers]
+ sections will be considered normal. The letter <emphasis>G</emphasis>
+ in parentheses indicates that a parameter is specific to the
+ [global] section. The letter <emphasis>S</emphasis>
+ indicates that a parameter can be specified in a service specific
+ section. Note that all <emphasis>S</emphasis> parameters can also be specified in
+ the [global] section - in which case they will define
+ the default behavior for all services.</para>
+
+ <para>parameters are arranged here in alphabetical order - this may
+ not create best bedfellows, but at least you can find them! Where
+ there are synonyms, the preferred synonym is described, others refer
+ to the preferred synonym.</para>
+</refsect1>
+
+<refsect1>
+ <title>VARIABLE SUBSTITUTIONS</title>
+
+ <para>Many of the strings that are settable in the config file
+ can take substitutions. For example the option "path =
+ /tmp/%u" would be interpreted as "path =
+ /tmp/john" if the user connected with the username john.</para>
+
+ <para>These substitutions are mostly noted in the descriptions below,
+ but there are some general substitutions which apply whenever they
+ might be relevant. These are:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>%S</term>
+ <listitem><para>the name of the current service, if any.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%P</term>
+ <listitem><para>the root directory of the current service,
+ if any.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%u</term>
+ <listitem><para>user name of the current service, if any.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%g</term>
+ <listitem><para>primary group name of %u.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%U</term>
+ <listitem><para>session user name (the user name that the client
+ wanted, not necessarily the same as the one they got).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%G</term>
+ <listitem><para>primary group name of %U.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%H</term>
+ <listitem><para>the home directory of the user given
+ by %u.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%v</term>
+ <listitem><para>the Samba version.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%h</term>
+ <listitem><para>the Internet hostname that Samba is running
+ on.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%m</term>
+ <listitem><para>the NetBIOS name of the client machine
+ (very useful).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%L</term>
+ <listitem><para>the NetBIOS name of the server. This allows you
+ to change your config based on what the client calls you. Your
+ server can have a "dual personality".</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%M</term>
+ <listitem><para>the Internet name of the client machine.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%N</term>
+ <listitem><para>the name of your NIS home directory server.
+ This is obtained from your NIS auto.map entry. If you have
+ not compiled Samba with the <emphasis>--with-automount</emphasis>
+ option then this value will be the same as %L.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%p</term>
+ <listitem><para>the path of the service's home directory,
+ obtained from your NIS auto.map entry. The NIS auto.map entry
+ is split up as "%N:%p".</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%R</term>
+ <listitem><para>the selected protocol level after
+ protocol negotiation. It can be one of CORE, COREPLUS,
+ LANMAN1, LANMAN2 or NT1.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%d</term>
+ <listitem><para>The process id of the current server
+ process.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%a</term>
+ <listitem><para>the architecture of the remote
+ machine. Only some are recognized, and those may not be
+ 100% reliable. It currently recognizes Samba, WfWg, Win95,
+ WinNT and Win2k. Anything else will be known as
+ "UNKNOWN". If it gets it wrong then sending a level
+ 3 log to <ulink url="mailto:samba@samba.org">samba@samba.org
+ </ulink> should allow it to be fixed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%I</term>
+ <listitem><para>The IP address of the client machine.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%T</term>
+ <listitem><para>the current date and time.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>%$(<replaceable>envvar</replaceable>)</term>
+ <listitem><para>The value of the environment variable
+ <replaceable>envar</replaceable>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>There are some quite creative things that can be done
+ with these substitutions and other smb.conf options.</para
+</refsect1>
+
+<refsect1>
+ <title id="NAMEMANGLINGSECT">NAME MANGLING</title>
+
+ <para>Samba supports "name mangling" so that DOS and
+ Windows clients can use files that don't conform to the 8.3 format.
+ It can also be set to adjust the case of 8.3 format filenames.</para>
+
+ <para>There are several options that control the way mangling is
+ performed, and they are grouped here rather than listed separately.
+ For the defaults look at the output of the testparm program. </para>
+
+ <para>All of these options can be set separately for each service
+ (or globally, of course). </para>
+
+ <para>The options are: </para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>mangle case = yes/no</term>
+ <listitem><para> controls if names that have characters that
+ aren't of the "default" case are mangled. For example,
+ if this is yes then a name like "Mail" would be mangled.
+ Default <emphasis>no</emphasis>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>case sensitive = yes/no</term>
+ <listitem><para>controls whether filenames are case sensitive. If
+ they aren't then Samba must do a filename search and match on passed
+ names. Default <emphasis>no</emphasis>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>default case = upper/lower</term>
+ <listitem><para>controls what the default case is for new
+ filenames. Default <emphasis>lower</emphasis>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>preserve case = yes/no</term>
+ <listitem><para>controls if new files are created with the
+ case that the client passes, or if they are forced to be the
+ "default" case. Default <emphasis>yes</emphasis>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>short preserve case = yes/no</term>
+ <listitem><para>controls if new files which conform to 8.3 syntax,
+ that is all in upper case and of suitable length, are created
+ upper case, or if they are forced to be the "default"
+ case. This option can be use with "preserve case = yes"
+ to permit long filenames to retain their case, while short names
+ are lowercased. Default <emphasis>yes</emphasis>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>By default, Samba 2.2 has the same semantics as a Windows
+ NT server, in that it is case insensitive but case preserving.</para>
+
+</refsect1>
+
+<refsect1>
+ <title id="VALIDATIONSECT">NOTE ABOUT USERNAME/PASSWORD VALIDATION</title>
+
+ <para>There are a number of ways in which a user can connect
+ to a service. The server uses the following steps in determining
+ if it will allow a connection to a specified service. If all the
+ steps fail, then the connection request is rejected. However, if one of the
+ steps succeeds, then the following steps are not checked.</para>
+
+ <para>If the service is marked "guest only = yes" then
+ steps 1 to 5 are skipped.</para>
+
+ <orderedlist numeration="Arabic">
+ <listitem><para>If the client has passed a username/password
+ pair and that username/password pair is validated by the UNIX
+ system's password programs then the connection is made as that
+ username. Note that this includes the
+ \\server\service%<replaceable>username</replaceable> method of passing
+ a username.</para></listitem>
+
+ <listitem><para>If the client has previously registered a username
+ with the system and now supplies a correct password for that
+ username then the connection is allowed.</para></listitem>
+
+ <listitem><para>The client's NetBIOS name and any previously
+ used user names are checked against the supplied password, if
+ they match then the connection is allowed as the corresponding
+ user.</para></listitem>
+
+ <listitem><para>If the client has previously validated a
+ username/password pair with the server and the client has passed
+ the validation token then that username is used. </para></listitem>
+
+ <listitem><para>If a "user = " field is given in the
+ <filename>smb.conf</filename> file for the service and the client
+ has supplied a password, and that password matches (according to
+ the UNIX system's password checking) with one of the usernames
+ from the "user =" field then the connection is made as
+ the username in the "user =" line. If one
+ of the username in the "user =" list begins with a
+ '@' then that name expands to a list of names in
+ the group of the same name.</para></listitem>
+
+ <listitem><para>If the service is a guest service then a
+ connection is made as the username given in the "guest
+ account =" for the service, irrespective of the
+ supplied password.</para></listitem>
+ </orderedlist>
+
+</refsect1>
+
+<refsect1>
+ <title>COMPLETE LIST OF GLOBAL PARAMETERS</title>
+
+ <para>Here is a list of all global parameters. See the section of
+ each parameter for details. Note that some are synonyms.</para>
+
+ <itemizedlist>
+ <listitem><para><link linkend="ABORTSHUTDOWNSCRIPT"><parameter>abort shutdown script</parameter></link></para></listitem>
+ <listitem><para><link linkend="ADDPRINTERCOMMAND"><parameter>add printer command</parameter></link></para></listitem>
+ <listitem><para><link linkend="ADDSHARECOMMAND"><parameter>add share command</parameter></link></para></listitem>
+ <listitem><para><link linkend="ADDUSERSCRIPT"><parameter>add user script</parameter></link></para></listitem>
+ <listitem><para><link linkend="ADDMACHINESCRIPT"><parameter>add machine script</parameter></link></para></listitem>
+ <listitem><para><link linkend="ALLOWTRUSTEDDOMAINS"><parameter>allow trusted domains</parameter></link></para></listitem>
+ <listitem><para><link linkend="ANNOUNCEAS"><parameter>announce as</parameter></link></para></listitem>
+ <listitem><para><link linkend="ANNOUNCEVERSION"><parameter>announce version</parameter></link></para></listitem>
+ <listitem><para><link linkend="AUTOSERVICES"><parameter>auto services</parameter></link></para></listitem>
+ <listitem><para><link linkend="BINDINTERFACESONLY"><parameter>bind interfaces only</parameter></link></para></listitem>
+ <listitem><para><link linkend="BROWSELIST"><parameter>browse list</parameter></link></para></listitem>
+ <listitem><para><link linkend="CHANGENOTIFYTIMEOUT"><parameter>change notify timeout</parameter></link></para></listitem>
+ <listitem><para><link linkend="CHANGESHARECOMMAND"><parameter>change share command</parameter></link></para></listitem>
+ <listitem><para><link linkend="CHARACTERSET"><parameter>character set</parameter></link></para></listitem>
+ <listitem><para><link linkend="CLIENTCODEPAGE"><parameter>client code page</parameter></link></para></listitem>
+ <listitem><para><link linkend="CODEPAGEDIRECTORY"><parameter>code page directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="CODINGSYSTEM"><parameter>coding system</parameter></link></para></listitem>
+ <listitem><para><link linkend="CONFIGFILE"><parameter>config file</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEADTIME"><parameter>deadtime</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEBUGHIRESTIMESTAMP"><parameter>debug hires timestamp</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEBUGPID"><parameter>debug pid</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEBUGTIMESTAMP"><parameter>debug timestamp</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEBUGUID"><parameter>debug uid</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEBUGLEVEL"><parameter>debuglevel</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEFAULT"><parameter>default</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEFAULTSERVICE"><parameter>default service</parameter></link></para></listitem>
+ <listitem><para><link linkend="DELETEPRINTERCOMMAND"><parameter>delete printer command</parameter></link></para></listitem>
+ <listitem><para><link linkend="DELETESHARECOMMAND"><parameter>delete share command</parameter></link></para></listitem>
+ <listitem><para><link linkend="DELETEUSERSCRIPT"><parameter>delete user script</parameter></link></para></listitem>
+ <listitem><para><link linkend="DFREECOMMAND"><parameter>dfree command</parameter></link></para></listitem>
+ <listitem><para><link linkend="DISABLESPOOLSS"><parameter>disable spoolss</parameter></link></para></listitem>
+ <listitem><para><link linkend="DNSPROXY"><parameter>dns proxy</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOMAINADMINGROUP"><parameter>domain admin group</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOMAINGUESTGROUP"><parameter>domain guest group</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOMAINLOGONS"><parameter>domain logons</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOMAINMASTER"><parameter>domain master</parameter></link></para></listitem>
+ <listitem><para><link linkend="ENCRYPTPASSWORDS"><parameter>encrypt passwords</parameter></link></para></listitem>
+ <listitem><para><link linkend="ENHANCEDBROWSING"><parameter>enhanced browsing</parameter></link></para></listitem>
+ <listitem><para><link linkend="ENUMPORTSCOMMAND"><parameter>enumports command</parameter></link></para></listitem>
+ <listitem><para><link linkend="GETWDCACHE"><parameter>getwd cache</parameter></link></para></listitem>
+ <listitem><para><link linkend="HIDELOCALUSERS"><parameter>hide local users</parameter></link></para></listitem>
+ <listitem><para><link linkend="HIDEUNREADABLE"><parameter>hide unreadable</parameter></link></para></listitem>
+ <listitem><para><link linkend="HOMEDIRMAP"><parameter>homedir map</parameter></link></para></listitem>
+ <listitem><para><link linkend="HOSTMSDFS"><parameter>host msdfs</parameter></link></para></listitem>
+ <listitem><para><link linkend="HOSTSEQUIV"><parameter>hosts equiv</parameter></link></para></listitem>
+ <listitem><para><link linkend="INTERFACES"><parameter>interfaces</parameter></link></para></listitem>
+ <listitem><para><link linkend="KEEPALIVE"><parameter>keepalive</parameter></link></para></listitem>
+ <listitem><para><link linkend="KERNELOPLOCKS"><parameter>kernel oplocks</parameter></link></para></listitem>
+ <listitem><para><link linkend="LANMANAUTH"><parameter>lanman auth</parameter></link></para></listitem>
+ <listitem><para><link linkend="LARGEREADWRITE"><parameter>large readwrite</parameter></link></para></listitem>
+
+ <listitem><para><link linkend="LDAPADMINDN"><parameter>ldap admin dn</parameter></link></para></listitem>
+ <listitem><para><link linkend="LDAPFILTER"><parameter>ldap filter</parameter></link></para></listitem>
+ <listitem><para><link linkend="LDAPPORT"><parameter>ldap port</parameter></link></para></listitem>
+ <listitem><para><link linkend="LDAPSERVER"><parameter>ldap server</parameter></link></para></listitem>
+ <listitem><para><link linkend="LDAPSSL"><parameter>ldap ssl</parameter></link></para></listitem>
+ <listitem><para><link linkend="LDAPSUFFIX"><parameter>ldap suffix</parameter></link></para></listitem>
+
+ <listitem><para><link linkend="LMANNOUNCE"><parameter>lm announce</parameter></link></para></listitem>
+ <listitem><para><link linkend="LMINTERVAL"><parameter>lm interval</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOADPRINTERS"><parameter>load printers</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOCALMASTER"><parameter>local master</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOCKDIR"><parameter>lock dir</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOCKDIRECTORY"><parameter>lock directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGFILE"><parameter>log file</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGLEVEL"><parameter>log level</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGONDRIVE"><parameter>logon drive</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGONHOME"><parameter>logon home</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGONPATH"><parameter>logon path</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOGONSCRIPT"><parameter>logon script</parameter></link></para></listitem>
+ <listitem><para><link linkend="LPQCACHETIME"><parameter>lpq cache time</parameter></link></para></listitem>
+ <listitem><para><link linkend="MACHINEPASSWORDTIMEOUT"><parameter>machine password timeout</parameter></link></para></listitem>
+ <listitem><para><link linkend="MANGLEDSTACK"><parameter>mangled stack</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAPTOGUEST"><parameter>map to guest</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXDISKSIZE"><parameter>max disk size</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXLOGSIZE"><parameter>max log size</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXMUX"><parameter>max mux</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXOPENFILES"><parameter>max open files</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXPROTOCOL"><parameter>max protocol</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXSMBDPROCESSES"><parameter>max smbd processes</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXTTL"><parameter>max ttl</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXWINSTTL"><parameter>max wins ttl</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXXMIT"><parameter>max xmit</parameter></link></para></listitem>
+ <listitem><para><link linkend="MESSAGECOMMAND"><parameter>message command</parameter></link></para></listitem>
+ <listitem><para><link linkend="MINPASSWDLENGTH"><parameter>min passwd length</parameter></link></para></listitem>
+ <listitem><para><link linkend="MINPASSWORDLENGTH"><parameter>min password length</parameter></link></para></listitem>
+ <listitem><para><link linkend="MINPROTOCOL"><parameter>min protocol</parameter></link></para></listitem>
+ <listitem><para><link linkend="MINWINSTTL"><parameter>min wins ttl</parameter></link></para></listitem>
+ <listitem><para><link linkend="NAMERESOLVEORDER"><parameter>name resolve order</parameter></link></para></listitem>
+ <listitem><para><link linkend="NETBIOSALIASES"><parameter>netbios aliases</parameter></link></para></listitem>
+ <listitem><para><link linkend="NETBIOSNAME"><parameter>netbios name</parameter></link></para></listitem>
+ <listitem><para><link linkend="NETBIOSSCOPE"><parameter>netbios scope</parameter></link></para></listitem>
+ <listitem><para><link linkend="NISHOMEDIR"><parameter>nis homedir</parameter></link></para></listitem>
+ <listitem><para><link linkend="NTPIPESUPPORT"><parameter>nt pipe support</parameter></link></para></listitem>
+ <listitem><para><link linkend="NTSMBSUPPORT"><parameter>nt smb support</parameter></link></para></listitem>
+ <listitem><para><link linkend="NULLPASSWORDS"><parameter>null passwords</parameter></link></para></listitem>
+ <listitem><para><link linkend="OBEYPAMRESTRICTIONS"><parameter>obey pam restrictions</parameter></link></para></listitem>
+ <listitem><para><link linkend="OPLOCKBREAKWAITTIME"><parameter>oplock break wait time</parameter></link></para></listitem>
+ <listitem><para><link linkend="OSLEVEL"><parameter>os level</parameter></link></para></listitem>
+ <listitem><para><link linkend="OS2DRIVERMAP"><parameter>os2 driver map</parameter></link></para></listitem>
+ <listitem><para><link linkend="PAMPASSWORDCHANGE"><parameter>pam password change</parameter></link></para></listitem>
+ <listitem><para><link linkend="PANICACTION"><parameter>panic action</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWDCHAT"><parameter>passwd chat</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWDCHATDEBUG"><parameter>passwd chat debug</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWDPROGRAM"><parameter>passwd program</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWORDLEVEL"><parameter>password level</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWORDSERVER"><parameter>password server</parameter></link></para></listitem>
+ <listitem><para><link linkend="PREFEREDMASTER"><parameter>prefered master</parameter></link></para></listitem>
+ <listitem><para><link linkend="PREFERREDMASTER"><parameter>preferred master</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRELOAD"><parameter>preload</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTCAP"><parameter>printcap</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTCAPNAME"><parameter>printcap name</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTERDRIVERFILE"><parameter>printer driver file</parameter></link></para></listitem>
+ <listitem><para><link linkend="PROTOCOL"><parameter>protocol</parameter></link></para></listitem>
+ <listitem><para><link linkend="READBMPX"><parameter>read bmpx</parameter></link></para></listitem>
+ <listitem><para><link linkend="READRAW"><parameter>read raw</parameter></link></para></listitem>
+ <listitem><para><link linkend="READSIZE"><parameter>read size</parameter></link></para></listitem>
+ <listitem><para><link linkend="REMOTEANNOUNCE"><parameter>remote announce</parameter></link></para></listitem>
+ <listitem><para><link linkend="REMOTEBROWSESYNC"><parameter>remote browse sync</parameter></link></para></listitem>
+ <listitem><para><link linkend="RESTRICTANONYMOUS"><parameter>restrict anonymous</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOT"><parameter>root</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOTDIR"><parameter>root dir</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOTDIRECTORY"><parameter>root directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="SECURITY"><parameter>security</parameter></link></para></listitem>
+ <listitem><para><link linkend="SERVERSTRING"><parameter>server string</parameter></link></para></listitem>
+ <listitem><para><link linkend="SHOWADDPRINTERWIZARD"><parameter>show add printer wizard</parameter></link></para></listitem>
+ <listitem><para><link linkend="SHUTDOWNSCRIPT"><parameter>shutdown script</parameter></link></para></listitem>
+ <listitem><para><link linkend="SMBPASSWDFILE"><parameter>smb passwd file</parameter></link></para></listitem>
+ <listitem><para><link linkend="SOCKETADDRESS"><parameter>socket address</parameter></link></para></listitem>
+ <listitem><para><link linkend="SOCKETOPTIONS"><parameter>socket options</parameter></link></para></listitem>
+ <listitem><para><link linkend="SOURCEENVIRONMENT"><parameter>source environment</parameter></link></para></listitem>
+
+ <listitem><para><link linkend="SSL"><parameter>ssl</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCACERTDIR"><parameter>ssl CA certDir</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCACERTFILE"><parameter>ssl CA certFile</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCIPHERS"><parameter>ssl ciphers</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCLIENTCERT"><parameter>ssl client cert</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCLIENTKEY"><parameter>ssl client key</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLCOMPATIBILITY"><parameter>ssl compatibility</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLEGDSOCKET"><parameter>ssl egd socket</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLENTROPYBYTES"><parameter>ssl entropy bytes</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLENTROPYFILE"><parameter>ssl entropy file</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLHOSTS"><parameter>ssl hosts</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLHOSTSRESIGN"><parameter>ssl hosts resign</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLREQUIRECLIENTCERT"><parameter>ssl require clientcert</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLREQUIRESERVERCERT"><parameter>ssl require servercert</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLSERVERCERT"><parameter>ssl server cert</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLSERVERKEY"><parameter>ssl server key</parameter></link></para></listitem>
+ <listitem><para><link linkend="SSLVERSION"><parameter>ssl version</parameter></link></para></listitem>
+
+ <listitem><para><link linkend="STATCACHE"><parameter>stat cache</parameter></link></para></listitem>
+ <listitem><para><link linkend="STATCACHESIZE"><parameter>stat cache size</parameter></link></para></listitem>
+ <listitem><para><link linkend="STRIPDOT"><parameter>strip dot</parameter></link></para></listitem>
+ <listitem><para><link linkend="SYSLOG"><parameter>syslog</parameter></link></para></listitem>
+ <listitem><para><link linkend="SYSLOGONLY"><parameter>syslog only</parameter></link></para></listitem>
+ <listitem><para><link linkend="TEMPLATEHOMEDIR"><parameter>template homedir</parameter></link></para></listitem>
+ <listitem><para><link linkend="TEMPLATESHELL"><parameter>template shell</parameter></link></para></listitem>
+ <listitem><para><link linkend="TIMEOFFSET"><parameter>time offset</parameter></link></para></listitem>
+ <listitem><para><link linkend="TIMESERVER"><parameter>time server</parameter></link></para></listitem>
+ <listitem><para><link linkend="TIMESTAMPLOGS"><parameter>timestamp logs</parameter></link></para></listitem>
+ <listitem><para><link linkend="TOTALPRINTJOBS"><parameter>total print jobs</parameter></link></para></listitem>
+ <listitem><para><link linkend="UNIXPASSWORDSYNC"><parameter>unix password sync</parameter></link></para></listitem>
+ <listitem><para><link linkend="UPDATEENCRYPTED"><parameter>update encrypted</parameter></link></para></listitem>
+ <listitem><para><link linkend="USEMMAP"><parameter>use mmap</parameter></link></para></listitem>
+ <listitem><para><link linkend="USERHOSTS"><parameter>use rhosts</parameter></link></para></listitem>
+ <listitem><para><link linkend="USERNAMELEVEL"><parameter>username level</parameter></link></para></listitem>
+ <listitem><para><link linkend="USERNAMEMAP"><parameter>username map</parameter></link></para></listitem>
+ <listitem><para><link linkend="UTMP"><parameter>utmp</parameter></link></para></listitem>
+ <listitem><para><link linkend="UTMPDIRECTORY"><parameter>utmp directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="VALIDCHARS"><parameter>valid chars</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDCACHETIME"><parameter>winbind cache time</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDENUMUSERS"><parameter>winbind enum users</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDENUMGROUPS"><parameter>winbind enum groups</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDGID"><parameter>winbind gid</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDSEPARATOR"><parameter>winbind separator</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINBINDUID"><parameter>winbind uid</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINSHOOK"><parameter>wins hook</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINSPROXY"><parameter>wins proxy</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINSSERVER"><parameter>wins server</parameter></link></para></listitem>
+ <listitem><para><link linkend="WINSSUPPORT"><parameter>wins support</parameter></link></para></listitem>
+ <listitem><para><link linkend="WORKGROUP"><parameter>workgroup</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITERAW"><parameter>write raw</parameter></link></para></listitem>
+ </itemizedlist>
+
+</refsect1>
+
+<refsect1>
+ <title>COMPLETE LIST OF SERVICE PARAMETERS</title>
+
+ <para>Here is a list of all service parameters. See the section on
+ each parameter for details. Note that some are synonyms.</para>
+
+ <itemizedlist>
+ <listitem><para><link linkend="ADMINUSERS"><parameter>admin users</parameter></link></para></listitem>
+ <listitem><para><link linkend="ALLOWHOSTS"><parameter>allow hosts</parameter></link></para></listitem>
+ <listitem><para><link linkend="AVAILABLE"><parameter>available</parameter></link></para></listitem>
+ <listitem><para><link linkend="BLOCKINGLOCKS"><parameter>blocking locks</parameter></link></para></listitem>
+ <listitem><para><link linkend="BROWSABLE"><parameter>browsable</parameter></link></para></listitem>
+ <listitem><para><link linkend="BROWSEABLE"><parameter>browseable</parameter></link></para></listitem>
+ <listitem><para><link linkend="CASESENSITIVE"><parameter>case sensitive</parameter></link></para></listitem>
+ <listitem><para><link linkend="CASESIGNAMES"><parameter>casesignames</parameter></link></para></listitem>
+ <listitem><para><link linkend="COMMENT"><parameter>comment</parameter></link></para></listitem>
+ <listitem><para><link linkend="COPY"><parameter>copy</parameter></link></para></listitem>
+ <listitem><para><link linkend="CREATEMASK"><parameter>create mask</parameter></link></para></listitem>
+ <listitem><para><link linkend="CREATEMODE"><parameter>create mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="DEFAULTCASE"><parameter>default case</parameter></link></para></listitem>
+ <listitem><para><link linkend="DELETEREADONLY"><parameter>delete readonly</parameter></link></para></listitem>
+ <listitem><para><link linkend="DELETEVETOFILES"><parameter>delete veto files</parameter></link></para></listitem>
+ <listitem><para><link linkend="DENYHOSTS"><parameter>deny hosts</parameter></link></para></listitem>
+ <listitem><para><link linkend="DIRECTORY"><parameter>directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="DIRECTORYMASK"><parameter>directory mask</parameter></link></para></listitem>
+ <listitem><para><link linkend="DIRECTORYMODE"><parameter>directory mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="DIRECTORYSECURITYMASK"><parameter>directory security mask</parameter></link></para></listitem>
+ <listitem><para><link linkend="DONTDESCEND"><parameter>dont descend</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOSFILEMODE"><parameter>dos filemode</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOSFILETIMERESOLUTION"><parameter>dos filetime resolution</parameter></link></para></listitem>
+ <listitem><para><link linkend="DOSFILETIMES"><parameter>dos filetimes</parameter></link></para></listitem>
+ <listitem><para><link linkend="EXEC"><parameter>exec</parameter></link></para></listitem>
+ <listitem><para><link linkend="FAKEDIRECTORYCREATETIMES"><parameter>fake directory create times</parameter></link></para></listitem>
+ <listitem><para><link linkend="FAKEOPLOCKS"><parameter>fake oplocks</parameter></link></para></listitem>
+ <listitem><para><link linkend="FOLLOWSYMLINKS"><parameter>follow symlinks</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCECREATEMODE"><parameter>force create mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCEDIRECTORYMODE"><parameter>force directory mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCEDIRECTORYSECURITYMODE"><parameter>force directory security mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCEGROUP"><parameter>force group</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCESECURITYMODE"><parameter>force security mode</parameter></link></para></listitem>
+ <listitem><para><link linkend="FORCEUSER"><parameter>force user</parameter></link></para></listitem>
+ <listitem><para><link linkend="FSTYPE"><parameter>fstype</parameter></link></para></listitem>
+ <listitem><para><link linkend="GROUP"><parameter>group</parameter></link></para></listitem>
+ <listitem><para><link linkend="GUESTACCOUNT"><parameter>guest account</parameter></link></para></listitem>
+ <listitem><para><link linkend="GUESTOK"><parameter>guest ok</parameter></link></para></listitem>
+ <listitem><para><link linkend="GUESTONLY"><parameter>guest only</parameter></link></para></listitem>
+ <listitem><para><link linkend="HIDEDOTFILES"><parameter>hide dot files</parameter></link></para></listitem>
+ <listitem><para><link linkend="HIDEFILES"><parameter>hide files</parameter></link></para></listitem>
+ <listitem><para><link linkend="HOSTSALLOW"><parameter>hosts allow</parameter></link></para></listitem>
+ <listitem><para><link linkend="HOSTSDENY"><parameter>hosts deny</parameter></link></para></listitem>
+ <listitem><para><link linkend="INCLUDE"><parameter>include</parameter></link></para></listitem>
+ <listitem><para><link linkend="INHERITPERMISSIONS"><parameter>inherit permissions</parameter></link></para></listitem>
+ <listitem><para><link linkend="INVALIDUSERS"><parameter>invalid users</parameter></link></para></listitem>
+ <listitem><para><link linkend="LEVEL2OPLOCKS"><parameter>level2 oplocks</parameter></link></para></listitem>
+ <listitem><para><link linkend="LOCKING"><parameter>locking</parameter></link></para></listitem>
+ <listitem><para><link linkend="LPPAUSECOMMAND"><parameter>lppause command</parameter></link></para></listitem>
+ <listitem><para><link linkend="LPQCOMMAND"><parameter>lpq command</parameter></link></para></listitem>
+ <listitem><para><link linkend="LPRESUMECOMMAND"><parameter>lpresume command</parameter></link></para></listitem>
+ <listitem><para><link linkend="LPRMCOMMAND"><parameter>lprm command</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAGICOUTPUT"><parameter>magic output</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAGICSCRIPT"><parameter>magic script</parameter></link></para></listitem>
+ <listitem><para><link linkend="MANGLECASE"><parameter>mangle case</parameter></link></para></listitem>
+ <listitem><para><link linkend="MANGLEDMAP"><parameter>mangled map</parameter></link></para></listitem>
+ <listitem><para><link linkend="MANGLEDNAMES"><parameter>mangled names</parameter></link></para></listitem>
+ <listitem><para><link linkend="MANGLINGCHAR"><parameter>mangling char</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAPARCHIVE"><parameter>map archive</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAPHIDDEN"><parameter>map hidden</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAPSYSTEM"><parameter>map system</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXCONNECTIONS"><parameter>max connections</parameter></link></para></listitem>
+ <listitem><para><link linkend="MAXPRINTJOBS"><parameter>max print jobs</parameter></link></para></listitem>
+ <listitem><para><link linkend="MINPRINTSPACE"><parameter>min print space</parameter></link></para></listitem>
+ <listitem><para><link linkend="MSDFSROOT"><parameter>msdfs root</parameter></link></para></listitem>
+ <listitem><para><link linkend="NTACLSUPPORT"><parameter>nt acl support</parameter></link></para></listitem>
+ <listitem><para><link linkend="ONLYGUEST"><parameter>only guest</parameter></link></para></listitem>
+ <listitem><para><link linkend="ONLYUSER"><parameter>only user</parameter></link></para></listitem>
+ <listitem><para><link linkend="OPLOCKCONTENTIONLIMIT"><parameter>oplock contention limit</parameter></link></para></listitem>
+ <listitem><para><link linkend="OPLOCKS"><parameter>oplocks</parameter></link></para></listitem>
+ <listitem><para><link linkend="PATH"><parameter>path</parameter></link></para></listitem>
+ <listitem><para><link linkend="POSIXLOCKING"><parameter>posix locking</parameter></link></para></listitem>
+ <listitem><para><link linkend="POSTEXEC"><parameter>postexec</parameter></link></para></listitem>
+ <listitem><para><link linkend="POSTSCRIPT"><parameter>postscript</parameter></link></para></listitem>
+ <listitem><para><link linkend="PREEXEC"><parameter>preexec</parameter></link></para></listitem>
+ <listitem><para><link linkend="PREEXECCLOSE"><parameter>preexec close</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRESERVECASE"><parameter>preserve case</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTCOMMAND"><parameter>print command</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTOK"><parameter>print ok</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTABLE"><parameter>printable</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTER"><parameter>printer</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTERADMIN"><parameter>printer admin</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTERDRIVER"><parameter>printer driver</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTERDRIVERLOCATION"><parameter>printer driver location</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTERNAME"><parameter>printer name</parameter></link></para></listitem>
+ <listitem><para><link linkend="PRINTING"><parameter>printing</parameter></link></para></listitem>
+ <listitem><para><link linkend="PUBLIC"><parameter>public</parameter></link></para></listitem>
+ <listitem><para><link linkend="QUEUEPAUSECOMMAND"><parameter>queuepause command</parameter></link></para></listitem>
+ <listitem><para><link linkend="QUEUERESUMECOMMAND"><parameter>queueresume command</parameter></link></para></listitem>
+ <listitem><para><link linkend="READLIST"><parameter>read list</parameter></link></para></listitem>
+ <listitem><para><link linkend="READONLY"><parameter>read only</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOTPOSTEXEC"><parameter>root postexec</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOTPREEXEC"><parameter>root preexec</parameter></link></para></listitem>
+ <listitem><para><link linkend="ROOTPREEXECCLOSE"><parameter>root preexec close</parameter></link></para></listitem>
+ <listitem><para><link linkend="SECURITYMASK"><parameter>security mask</parameter></link></para></listitem>
+ <listitem><para><link linkend="SETDIRECTORY"><parameter>set directory</parameter></link></para></listitem>
+ <listitem><para><link linkend="SHORTPRESERVECASE"><parameter>short preserve case</parameter></link></para></listitem>
+ <listitem><para><link linkend="STATUS"><parameter>status</parameter></link></para></listitem>
+ <listitem><para><link linkend="STRICTALLOCATE"><parameter>strict allocate</parameter></link></para></listitem>
+ <listitem><para><link linkend="STRICTLOCKING"><parameter>strict locking</parameter></link></para></listitem>
+ <listitem><para><link linkend="STRICTSYNC"><parameter>strict sync</parameter></link></para></listitem>
+ <listitem><para><link linkend="SYNCALWAYS"><parameter>sync always</parameter></link></para></listitem>
+ <listitem><para><link linkend="USECLIENTDRIVER"><parameter>use client driver</parameter></link></para></listitem>
+ <listitem><para><link linkend="USER"><parameter>user</parameter></link></para></listitem>
+ <listitem><para><link linkend="USERNAME"><parameter>username</parameter></link></para></listitem>
+ <listitem><para><link linkend="USERS"><parameter>users</parameter></link></para></listitem>
+ <listitem><para><link linkend="VALIDUSERS"><parameter>valid users</parameter></link></para></listitem>
+ <listitem><para><link linkend="VETOFILES"><parameter>veto files</parameter></link></para></listitem>
+ <listitem><para><link linkend="VETOOPLOCKFILES"><parameter>veto oplock files</parameter></link></para></listitem>
+ <listitem><para><link linkend="VFSOBJECT"><parameter>vfs object</parameter></link></para></listitem>
+ <listitem><para><link linkend="VFSOPTIONS"><parameter>vfs options</parameter></link></para></listitem>
+ <listitem><para><link linkend="VOLUME"><parameter>volume</parameter></link></para></listitem>
+ <listitem><para><link linkend="WIDELINKS"><parameter>wide links</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITABLE"><parameter>writable</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITECACHESIZE"><parameter>write cache size</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITELIST"><parameter>write list</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITEOK"><parameter>write ok</parameter></link></para></listitem>
+ <listitem><para><link linkend="WRITEABLE"><parameter>writeable</parameter></link></para></listitem>
+ </itemizedlist>
+
+</refsect1>
+
+<refsect1>
+ <title>EXPLANATION OF EACH PARAMETER</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><anchor id="ABORTSHUTDOWNSCRIPT">abort shutdown script (G)</term>
+ <listitem><para><emphasis>This parameter only exists in the HEAD cvs branch</emphasis>
+ This a full path name to a script called by
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink> that
+ should stop a shutdown procedure issued by the <link
+ linkend="SHUTDOWNSCRIPT"><parameter>shutdown script</parameter></link>.</para>
+
+ <para>This command will be run as user.</para>
+
+ <para>Default: <emphasis>None</emphasis>.</para>
+ <para>Example: <command>abort shutdown script = /sbin/shutdown -c</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="ADDPRINTERCOMMAND">add printer command (G)</term>
+ <listitem><para>With the introduction of MS-RPC based printing
+ support for Windows NT/2000 clients in Samba 2.2, The MS Add
+ Printer Wizard (APW) icon is now also available in the
+ "Printers..." folder displayed a share listing. The APW
+ allows for printers to be add remotely to a Samba or Windows
+ NT/2000 print server.</para>
+
+ <para>For a Samba host this means that the printer must be
+ physically added to the underlying printing system. The <parameter>add
+ printer command</parameter> defines a script to be run which
+ will perform the necessary operations for adding the printer
+ to the print system and to add the appropriate service definition
+ to the <filename>smb.conf</filename> file in order that it can be
+ shared by <ulink url="smbd.8.html"><command>smbd(8)</command>
+ </ulink>.</para>
+
+ <para>The <parameter>add printer command</parameter> is
+ automatically invoked with the following parameter (in
+ order:</para>
+
+ <itemizedlist>
+ <listitem><para><parameter>printer name</parameter></para></listitem>
+ <listitem><para><parameter>share name</parameter></para></listitem>
+ <listitem><para><parameter>port name</parameter></para></listitem>
+ <listitem><para><parameter>driver name</parameter></para></listitem>
+ <listitem><para><parameter>location</parameter></para></listitem>
+ <listitem><para><parameter>Windows 9x driver location</parameter>
+ </para></listitem>
+ </itemizedlist>
+
+ <para>All parameters are filled in from the PRINTER_INFO_2 structure sent
+ by the Windows NT/2000 client with one exception. The "Windows 9x
+ driver location" parameter is included for backwards compatibility
+ only. The remaining fields in the structure are generated from answers
+ to the APW questions.</para>
+
+ <para>Once the <parameter>add printer command</parameter> has
+ been executed, <command>smbd</command> will reparse the <filename>
+ smb.conf</filename> to determine if the share defined by the APW
+ exists. If the sharename is still invalid, then <command>smbd
+ </command> will return an ACCESS_DENIED error to the client.</para>
+
+ <para>See also <link linkend="DELETEPRINTERCOMMAND"><parameter>
+ delete printer command</parameter></link>, <link
+ linkend="printing"><parameter>printing</parameter></link>,
+ <link linkend="SHOWADDPRINTERWIZARD"><parameter>show add
+ printer wizard</parameter></link></para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>addprinter command = /usr/bin/addprinter
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ADDSHARECOMMAND">add share command (G)</term>
+ <listitem><para>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <parameter>add share command</parameter> is used to define an
+ external program or script which will add a new service definition
+ to <filename>smb.conf</filename>. In order to successfully
+ execute the <parameter>add share command</parameter>, <command>smbd</command>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </para>
+
+ <para>
+ When executed, <command>smbd</command> will automatically invoke the
+ <parameter>add share command</parameter> with four parameters.
+ </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>configFile</parameter> - the location
+ of the global <filename>smb.conf</filename> file.
+ </para></listitem>
+
+ <listitem><para><parameter>shareName</parameter> - the name of the new
+ share.
+ </para></listitem>
+
+ <listitem><para><parameter>pathName</parameter> - path to an **existing**
+ directory on disk.
+ </para></listitem>
+
+ <listitem><para><parameter>comment</parameter> - comment string to associate
+ with the new share.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ This parameter is only used for add file shares. To add printer shares,
+ see the <link linkend="ADDPRINTERCOMMAND"><parameter>add printer
+ command</parameter></link>.
+ </para>
+
+ <para>
+ See also <link linkend="CHANGESHARECOMMAND"><parameter>change share
+ command</parameter></link>, <link linkend="DELETESHARECOMMAND"><parameter>delete share
+ command</parameter></link>.
+ </para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>add share command = /usr/local/bin/addshare</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ADDMACHINESCRIPT">add machine script (G)</term>
+ <listitem><para>This is the full pathname to a script that will
+ be run by <ulink url="smbd.8.html">smbd(8)</ulink> when a machine is added
+ to it's domain using the administrator username and password method. </para>
+
+ <para>This option is only required when using sam back-ends tied to the
+ Unix uid method of RID calculation such as smbpasswd. This option is only
+ available in Samba 3.0.</para>
+
+ <para>Default: <command>add machine script = &lt;empty string&gt;
+ </command></para>
+
+ <para>Example: <command>add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="ADDUSERSCRIPT">add user script (G)</term>
+ <listitem><para>This is the full pathname to a script that will
+ be run <emphasis>AS ROOT</emphasis> by <ulink url="smbd.8.html">smbd(8)
+ </ulink> under special circumstances described below.</para>
+
+ <para>Normally, a Samba server requires that UNIX users are
+ created for all users accessing files on this server. For sites
+ that use Windows NT account databases as their primary user database
+ creating these users and keeping the user list in sync with the
+ Windows NT PDC is an onerous task. This option allows <ulink
+ url="smbd.8.html">smbd</ulink> to create the required UNIX users
+ <emphasis>ON DEMAND</emphasis> when a user accesses the Samba server.</para>
+
+ <para>In order to use this option, <ulink url="smbd.8.html">smbd</ulink>
+ must be set to <parameter>security = server</parameter> or <parameter>
+ security = domain</parameter> and <parameter>add user script</parameter>
+ must be set to a full pathname for a script that will create a UNIX
+ user given one argument of <parameter>%u</parameter>, which expands into
+ the UNIX user name to create.</para>
+
+ <para>When the Windows user attempts to access the Samba server,
+ at login (session setup in the SMB protocol) time, <ulink url="smbd.8.html">
+ smbd</ulink> contacts the <parameter>password server</parameter> and
+ attempts to authenticate the given user with the given password. If the
+ authentication succeeds then <command>smbd</command>
+ attempts to find a UNIX user in the UNIX password database to map the
+ Windows user into. If this lookup fails, and <parameter>add user script
+ </parameter> is set then <command>smbd</command> will
+ call the specified script <emphasis>AS ROOT</emphasis>, expanding
+ any <parameter>%u</parameter> argument to be the user name to create.</para>
+
+ <para>If this script successfully creates the user then <command>smbd
+ </command> will continue on as though the UNIX user
+ already existed. In this way, UNIX users are dynamically created to
+ match existing Windows NT accounts.</para>
+
+ <para>See also <link linkend="SECURITY"><parameter>
+ security</parameter></link>, <link linkend="PASSWORDSERVER">
+ <parameter>password server</parameter></link>,
+ <link linkend="DELETEUSERSCRIPT"><parameter>delete user
+ script</parameter></link>.</para>
+
+ <para>Default: <command>add user script = &lt;empty string&gt;
+ </command></para>
+
+ <para>Example: <command>add user script = /usr/local/samba/bin/add_user
+ %u</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ADMINUSERS">admin users (S)</term>
+ <listitem><para>This is a list of users who will be granted
+ administrative privileges on the share. This means that they
+ will do all file operations as the super-user (root).</para>
+
+ <para>You should use this option very carefully, as any user in
+ this list will be able to do anything they like on the share,
+ irrespective of file permissions.</para>
+
+ <para>Default: <emphasis>no admin users</emphasis></para>
+
+ <para>Example: <command>admin users = jason</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ALLOWHOSTS">allow hosts (S)</term>
+ <listitem><para>Synonym for <link linkend="HOSTSALLOW">
+ <parameter>hosts allow</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ALLOWTRUSTEDDOMAINS">allow trusted domains (G)</term>
+ <listitem><para>This option only takes effect when the <link
+ linkend="SECURITY"><parameter>security</parameter></link> option is set to
+ <constant>server</constant> or <constant>domain</constant>.
+ If it is set to no, then attempts to connect to a resource from
+ a domain or workgroup other than the one which <ulink url="smbd.8.html">smbd</ulink> is running
+ in will fail, even if that domain is trusted by the remote server
+ doing the authentication.</para>
+
+ <para>This is useful if you only want your Samba server to
+ serve resources to users in the domain it is a member of. As
+ an example, suppose that there are two domains DOMA and DOMB. DOMB
+ is trusted by DOMA, which contains the Samba server. Under normal
+ circumstances, a user with an account in DOMB can then access the
+ resources of a UNIX account with the same account name on the
+ Samba server even if they do not have an account in DOMA. This
+ can make implementing a security boundary difficult.</para>
+
+ <para>Default: <command>allow trusted domains = yes</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ANNOUNCEAS">announce as (G)</term>
+ <listitem><para>This specifies what type of server
+ <ulink url="nmbd.8.html"><command>nmbd</command></ulink>
+ will announce itself as, to a network neighborhood browse
+ list. By default this is set to Windows NT. The valid options
+ are : "NT Server" (which can also be written as "NT"),
+ "NT Workstation", "Win95" or "WfW" meaning Windows NT Server,
+ Windows NT Workstation, Windows 95 and Windows for Workgroups
+ respectively. Do not change this parameter unless you have a
+ specific need to stop Samba appearing as an NT server as this
+ may prevent Samba servers from participating as browser servers
+ correctly.</para>
+
+ <para>Default: <command>announce as = NT Server</command></para>
+
+ <para>Example: <command>announce as = Win95</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ANNOUNCEVERSION">announce version (G)</term>
+ <listitem><para>This specifies the major and minor version numbers
+ that nmbd will use when announcing itself as a server. The default
+ is 4.2. Do not change this parameter unless you have a specific
+ need to set a Samba server to be a downlevel server.</para>
+
+ <para>Default: <command>announce version = 4.5</command></para>
+
+ <para>Example: <command>announce version = 2.0</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="AUTOSERVICES">auto services (G)</term>
+ <listitem><para>This is a synonym for the <link linkend="PRELOAD">
+ <parameter>preload</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="AVAILABLE">available (S)</term>
+ <listitem><para>This parameter lets you "turn off" a service. If
+ <parameter>available = no</parameter>, then <emphasis>ALL</emphasis>
+ attempts to connect to the service will fail. Such failures are
+ logged.</para>
+
+ <para>Default: <command>available = yes</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="BINDINTERFACESONLY">bind interfaces only (G)</term>
+ <listitem><para>This global parameter allows the Samba admin
+ to limit what interfaces on a machine will serve SMB requests. If
+ affects file service <ulink url="smbd.8.html">smbd(8)</ulink> and
+ name service <ulink url="nmbd.8.html">nmbd(8)</ulink> in slightly
+ different ways.</para>
+
+ <para>For name service it causes <command>nmbd</command> to bind
+ to ports 137 and 138 on the interfaces listed in the <link
+ linkend="INTERFACES">interfaces</link> parameter. <command>nmbd
+ </command> also binds to the "all addresses" interface (0.0.0.0)
+ on ports 137 and 138 for the purposes of reading broadcast messages.
+ If this option is not set then <command>nmbd</command> will service
+ name requests on all of these sockets. If <parameter>bind interfaces
+ only</parameter> is set then <command>nmbd</command> will check the
+ source address of any packets coming in on the broadcast sockets
+ and discard any that don't match the broadcast addresses of the
+ interfaces in the <parameter>interfaces</parameter> parameter list.
+ As unicast packets are received on the other sockets it allows
+ <command>nmbd</command> to refuse to serve names to machines that
+ send packets that arrive through any interfaces not listed in the
+ <parameter>interfaces</parameter> list. IP Source address spoofing
+ does defeat this simple check, however so it must not be used
+ seriously as a security feature for <command>nmbd</command>.</para>
+
+ <para>For file service it causes <ulink url="smbd.8.html">smbd(8)</ulink>
+ to bind only to the interface list given in the <link linkend="INTERFACES">
+ interfaces</link> parameter. This restricts the networks that
+ <command>smbd</command> will serve to packets coming in those
+ interfaces. Note that you should not use this parameter for machines
+ that are serving PPP or other intermittent or non-broadcast network
+ interfaces as it will not cope with non-permanent interfaces.</para>
+
+ <para>If <parameter>bind interfaces only</parameter> is set then
+ unless the network address <emphasis>127.0.0.1</emphasis> is added
+ to the <parameter>interfaces</parameter> parameter list <ulink
+ url="smbpasswd.8.html"><command>smbpasswd(8)</command></ulink>
+ and <ulink url="swat.8.html"><command>swat(8)</command></ulink> may
+ not work as expected due to the reasons covered below.</para>
+
+ <para>To change a users SMB password, the <command>smbpasswd</command>
+ by default connects to the <emphasis>localhost - 127.0.0.1</emphasis>
+ address as an SMB client to issue the password change request. If
+ <parameter>bind interfaces only</parameter> is set then unless the
+ network address <emphasis>127.0.0.1</emphasis> is added to the
+ <parameter>interfaces</parameter> parameter list then <command>
+ smbpasswd</command> will fail to connect in it's default mode.
+ <command>smbpasswd</command> can be forced to use the primary IP interface
+ of the local host by using its <ulink url="smbpasswd.8.html#minusr">
+ <parameter>-r <replaceable>remote machine</replaceable></parameter>
+ </ulink> parameter, with <replaceable>remote machine</replaceable> set
+ to the IP name of the primary interface of the local host.</para>
+
+ <para>The <command>swat</command> status page tries to connect with
+ <command>smbd</command> and <command>nmbd</command> at the address
+ <emphasis>127.0.0.1</emphasis> to determine if they are running.
+ Not adding <emphasis>127.0.0.1</emphasis> will cause <command>
+ smbd</command> and <command>nmbd</command> to always show
+ "not running" even if they really are. This can prevent <command>
+ swat</command> from starting/stopping/restarting <command>smbd</command>
+ and <command>nmbd</command>.</para>
+
+ <para>Default: <command>bind interfaces only = no</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="BLOCKINGLOCKS">blocking locks (S)</term>
+ <listitem><para>This parameter controls the behavior of <ulink
+ url="smbd.8.html">smbd(8)</ulink> when given a request by a client
+ to obtain a byte range lock on a region of an open file, and the
+ request has a time limit associated with it.</para>
+
+ <para>If this parameter is set and the lock range requested
+ cannot be immediately satisfied, Samba 2.2 will internally
+ queue the lock request, and periodically attempt to obtain
+ the lock until the timeout period expires.</para>
+
+ <para>If this parameter is set to <constant>false</constant>, then
+ Samba 2.2 will behave as previous versions of Samba would and
+ will fail the lock request immediately if the lock range
+ cannot be obtained.</para>
+
+ <para>Default: <command>blocking locks = yes</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="BROWSABLE">browsable (S)</term>
+ <listitem><para>See the <link linkend="BROWSEABLE"><parameter>
+ browseable</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="BROWSELIST">browse list (G)</term>
+ <listitem><para>This controls whether <ulink url="smbd.8.html">
+ <command>smbd(8)</command></ulink> will serve a browse list to
+ a client doing a <command>NetServerEnum</command> call. Normally
+ set to <constant>true</constant>. You should never need to change
+ this.</para>
+
+ <para>Default: <command>browse list = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="BROWSEABLE">browseable (S)</term>
+ <listitem><para>This controls whether this share is seen in
+ the list of available shares in a net view and in the browse list.</para>
+
+ <para>Default: <command>browseable = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CASESENSITIVE">case sensitive (S)</term>
+ <listitem><para>See the discussion in the section <link
+ linkend="NAMEMANGLINGSECT">NAME MANGLING</link>.</para>
+
+ <para>Default: <command>case sensitive = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CASESIGNAMES">casesignames (S)</term>
+ <listitem><para>Synonym for <link linkend="CASESENSITIVE">case
+ sensitive</link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CHANGENOTIFYTIMEOUT">change notify timeout (G)</term>
+ <listitem><para>This SMB allows a client to tell a server to
+ "watch" a particular directory for any changes and only reply to
+ the SMB request when a change has occurred. Such constant scanning of
+ a directory is expensive under UNIX, hence an <ulink url="smbd.8.html">
+ <command>smbd(8)</command></ulink> daemon only performs such a scan
+ on each requested directory once every <parameter>change notify
+ timeout</parameter> seconds.</para>
+
+ <para>Default: <command>change notify timeout = 60</command></para>
+ <para>Example: <command>change notify timeout = 300</command></para>
+
+ <para>Would change the scan time to every 5 minutes.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CHANGESHARECOMMAND">change share command (G)</term>
+ <listitem><para>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <parameter>change share command</parameter> is used to define an
+ external program or script which will modify an existing service definition
+ in <filename>smb.conf</filename>. In order to successfully
+ execute the <parameter>change share command</parameter>, <command>smbd</command>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </para>
+
+ <para>
+ When executed, <command>smbd</command> will automatically invoke the
+ <parameter>change share command</parameter> with four parameters.
+ </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>configFile</parameter> - the location
+ of the global <filename>smb.conf</filename> file.
+ </para></listitem>
+
+ <listitem><para><parameter>shareName</parameter> - the name of the new
+ share.
+ </para></listitem>
+
+ <listitem><para><parameter>pathName</parameter> - path to an **existing**
+ directory on disk.
+ </para></listitem>
+
+ <listitem><para><parameter>comment</parameter> - comment string to associate
+ with the new share.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ This parameter is only used modify existing file shares definitions. To modify
+ printer shares, use the "Printers..." folder as seen when browsing the Samba host.
+ </para>
+
+ <para>
+ See also <link linkend="ADDSHARECOMMAND"><parameter>add share
+ command</parameter></link>, <link linkend="DELETESHARECOMMAND"><parameter>delete
+ share command</parameter></link>.
+ </para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>change share command = /usr/local/bin/addshare</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CHARACTERSET">character set (G)</term>
+ <listitem><para>This allows <ulink url="smbd.8.html">smbd</ulink> to map incoming filenames
+ from a DOS Code page (see the <link linkend="CLIENTCODEPAGE">client
+ code page</link> parameter) to several built in UNIX character sets.
+ The built in code page translations are:</para>
+
+ <itemizedlist>
+ <listitem><para><constant>ISO8859-1</constant> : Western European
+ UNIX character set. The parameter <parameter>client code page</parameter>
+ <emphasis>MUST</emphasis> be set to code page 850 if the
+ <parameter>character set</parameter> parameter is set to
+ <constant>ISO8859-1</constant> in order for the conversion to the
+ UNIX character set to be done correctly.</para></listitem>
+
+ <listitem><para><constant>ISO8859-2</constant> : Eastern European
+ UNIX character set. The parameter <parameter>client code page
+ </parameter> <emphasis>MUST</emphasis> be set to code page 852 if
+ the <parameter> character set</parameter> parameter is set
+ to <constant>ISO8859-2</constant> in order for the conversion
+ to the UNIX character set to be done correctly. </para></listitem>
+
+ <listitem><para><constant>ISO8859-5</constant> : Russian Cyrillic
+ UNIX character set. The parameter <parameter>client code page
+ </parameter> <emphasis>MUST</emphasis> be set to code page
+ 866 if the <parameter>character set </parameter> parameter is
+ set to <constant>ISO8859-5</constant> in order for the conversion
+ to the UNIX character set to be done correctly. </para></listitem>
+
+ <listitem><para><constant>ISO8859-7</constant> : Greek UNIX
+ character set. The parameter <parameter>client code page
+ </parameter> <emphasis>MUST</emphasis> be set to code page
+ 737 if the <parameter>character set</parameter> parameter is
+ set to <constant>ISO8859-7</constant> in order for the conversion
+ to the UNIX character set to be done correctly.</para></listitem>
+
+ <listitem><para><constant>KOI8-R</constant> : Alternate mapping
+ for Russian Cyrillic UNIX character set. The parameter
+ <parameter>client code page</parameter> <emphasis>MUST</emphasis>
+ be set to code page 866 if the <parameter>character set</parameter>
+ parameter is set to <constant>KOI8-R</constant> in order for the
+ conversion to the UNIX character set to be done correctly.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para><emphasis>BUG</emphasis>. These MSDOS code page to UNIX character
+ set mappings should be dynamic, like the loading of MS DOS code pages,
+ not static.</para>
+
+ <para>Normally this parameter is not set, meaning no filename
+ translation is done.</para>
+
+ <para>Default: <command>character set = &lt;empty string&gt;</command></para>
+ <para>Example: <command>character set = ISO8859-1</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CLIENTCODEPAGE">client code page (G)</term>
+ <listitem><para>This parameter specifies the DOS code page
+ that the clients accessing Samba are using. To determine what code
+ page a Windows or DOS client is using, open a DOS command prompt
+ and type the command <command>chcp</command>. This will output
+ the code page. The default for USA MS-DOS, Windows 95, and
+ Windows NT releases is code page 437. The default for western
+ European releases of the above operating systems is code page 850.</para>
+
+ <para>This parameter tells <ulink url="smbd.8.html">smbd(8)</ulink>
+ which of the <filename>codepage.<replaceable>XXX</replaceable>
+ </filename> files to dynamically load on startup. These files,
+ described more fully in the manual page <ulink url="make_smbcodepage.1.html">
+ <command>make_smbcodepage(1)</command></ulink>, tell <command>
+ smbd</command> how to map lower to upper case characters to provide
+ the case insensitivity of filenames that Windows clients expect.</para>
+
+ <para>Samba currently ships with the following code page files :</para>
+
+ <itemizedlist>
+ <listitem><para>Code Page 437 - MS-DOS Latin US</para></listitem>
+ <listitem><para>Code Page 737 - Windows '95 Greek</para></listitem>
+ <listitem><para>Code Page 850 - MS-DOS Latin 1</para></listitem>
+ <listitem><para>Code Page 852 - MS-DOS Latin 2</para></listitem>
+ <listitem><para>Code Page 861 - MS-DOS Icelandic</para></listitem>
+ <listitem><para>Code Page 866 - MS-DOS Cyrillic</para></listitem>
+ <listitem><para>Code Page 932 - MS-DOS Japanese SJIS</para></listitem>
+ <listitem><para>Code Page 936 - MS-DOS Simplified Chinese</para></listitem>
+ <listitem><para>Code Page 949 - MS-DOS Korean Hangul</para></listitem>
+ <listitem><para>Code Page 950 - MS-DOS Traditional Chinese</para></listitem>
+ </itemizedlist>
+
+ <para>Thus this parameter may have any of the values 437, 737, 850, 852,
+ 861, 932, 936, 949, or 950. If you don't find the codepage you need,
+ read the comments in one of the other codepage files and the
+ <command>make_smbcodepage(1)</command> man page and write one. Please
+ remember to donate it back to the Samba user community.</para>
+
+ <para>This parameter co-operates with the <parameter>valid
+ chars</parameter> parameter in determining what characters are
+ valid in filenames and how capitalization is done. If you set both
+ this parameter and the <parameter>valid chars</parameter> parameter
+ the <parameter>client code page</parameter> parameter
+ <emphasis>MUST</emphasis> be set before the <parameter>valid
+ chars</parameter> parameter in the <filename>smb.conf</filename>
+ file. The <parameter>valid chars</parameter> string will then
+ augment the character settings in the <parameter>client code page</parameter>
+ parameter.</para>
+
+ <para>If not set, <parameter>client code page</parameter> defaults
+ to 850.</para>
+
+ <para>See also : <link linkend="VALIDCHARS"><parameter>valid
+ chars</parameter></link>, <link linkend="CODEPAGEDIRECTORY">
+ <parameter>code page directory</parameter></link></para>
+
+ <para>Default: <command>client code page = 850</command></para>
+ <para>Example: <command>client code page = 936</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="CODEPAGEDIRECTORY">code page directory (G)</term>
+ <listitem><para>Define the location of the various client code page
+ files.</para>
+
+ <para>See also <link linkend="CLIENTCODEPAGE"><parameter>client
+ code page</parameter></link></para>
+
+ <para>Default: <command>code page directory = ${prefix}/lib/codepages
+ </command></para>
+ <para>Example: <command>code page directory = /usr/share/samba/codepages
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="CODINGSYSTEM">coding system (G)</term>
+ <listitem><para>This parameter is used to determine how incoming
+ Shift-JIS Japanese characters are mapped from the incoming <link
+ linkend="CLIENTCODEPAGE"><parameter>client code page</parameter>
+ </link> used by the client, into file names in the UNIX filesystem.
+ Only useful if <parameter>client code page</parameter> is set to
+ 932 (Japanese Shift-JIS). The options are :</para>
+
+ <itemizedlist>
+ <listitem><para><constant>SJIS</constant> - Shift-JIS. Does no
+ conversion of the incoming filename.</para></listitem>
+
+ <listitem><para><constant>JIS8, J8BB, J8BH, J8@B,
+ J8@J, J8@H </constant> - Convert from incoming Shift-JIS to eight
+ bit JIS code with different shift-in, shift out codes.</para></listitem>
+
+ <listitem><para><constant>JIS7, J7BB, J7BH, J7@B, J7@J,
+ J7@H </constant> - Convert from incoming Shift-JIS to seven bit
+ JIS code with different shift-in, shift out codes.</para></listitem>
+
+ <listitem><para><constant>JUNET, JUBB, JUBH, JU@B, JU@J, JU@H </constant>
+ - Convert from incoming Shift-JIS to JUNET code with different shift-in,
+ shift out codes.</para></listitem>
+
+ <listitem><para><constant>EUC</constant> - Convert an incoming
+ Shift-JIS character to EUC code.</para></listitem>
+
+ <listitem><para><constant>HEX</constant> - Convert an incoming
+ Shift-JIS character to a 3 byte hex representation, i.e.
+ <constant>:AB</constant>.</para></listitem>
+
+ <listitem><para><constant>CAP</constant> - Convert an incoming
+ Shift-JIS character to the 3 byte hex representation used by
+ the Columbia AppleTalk Program (CAP), i.e. <constant>:AB</constant>.
+ This is used for compatibility between Samba and CAP.</para></listitem>
+ </itemizedlist>
+
+ <para>Default: <command>coding system = &lt;empty value&gt;</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="COMMENT">comment (S)</term>
+ <listitem><para>This is a text field that is seen next to a share
+ when a client does a queries the server, either via the network
+ neighborhood or via <command>net view</command> to list what shares
+ are available.</para>
+
+ <para>If you want to set the string that is displayed next to the
+ machine name then see the <link linkend="SERVERSTRING"><parameter>
+ server string</parameter></link> parameter.</para>
+
+ <para>Default: <emphasis>No comment string</emphasis></para>
+ <para>Example: <command>comment = Fred's Files</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CONFIGFILE">config file (G)</term>
+ <listitem><para>This allows you to override the config file
+ to use, instead of the default (usually <filename>smb.conf</filename>).
+ There is a chicken and egg problem here as this option is set
+ in the config file!</para>
+
+ <para>For this reason, if the name of the config file has changed
+ when the parameters are loaded then it will reload them from
+ the new config file.</para>
+
+ <para>This option takes the usual substitutions, which can
+ be very useful.</para>
+
+ <para>If the config file doesn't exist then it won't be loaded
+ (allowing you to special case the config files of just a few
+ clients).</para>
+
+ <para>Example: <command>config file = /usr/local/samba/lib/smb.conf.%m
+ </command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="COPY">copy (S)</term>
+ <listitem><para>This parameter allows you to "clone" service
+ entries. The specified service is simply duplicated under the
+ current service's name. Any parameters specified in the current
+ section will override those in the section being copied.</para>
+
+ <para>This feature lets you set up a 'template' service and
+ create similar services easily. Note that the service being
+ copied must occur earlier in the configuration file than the
+ service doing the copying.</para>
+
+ <para>Default: <emphasis>no value</emphasis></para>
+ <para>Example: <command>copy = otherservice</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CREATEMASK">create mask (S)</term>
+ <listitem><para>A synonym for this parameter is
+ <link linkend="CREATEMODE"><parameter>create mode</parameter>
+ </link>.</para>
+
+ <para>When a file is created, the necessary permissions are
+ calculated according to the mapping from DOS modes to UNIX
+ permissions, and the resulting UNIX mode is then bit-wise 'AND'ed
+ with this parameter. This parameter may be thought of as a bit-wise
+ MASK for the UNIX modes of a file. Any bit <emphasis>not</emphasis>
+ set here will be removed from the modes set on a file when it is
+ created.</para>
+
+ <para>The default value of this parameter removes the
+ 'group' and 'other' write and execute bits from the UNIX modes.</para>
+
+ <para>Following this Samba will bit-wise 'OR' the UNIX mode created
+ from this parameter with the value of the <link
+ linkend="FORCECREATEMODE"><parameter>force create mode</parameter></link>
+ parameter which is set to 000 by default.</para>
+
+ <para>This parameter does not affect directory modes. See the
+ parameter <link linkend="DIRECTORYMODE"><parameter>directory mode
+ </parameter></link> for details.</para>
+
+ <para>See also the <link linkend="FORCECREATEMODE"><parameter>force
+ create mode</parameter></link> parameter for forcing particular mode
+ bits to be set on created files. See also the <link linkend="DIRECTORYMODE">
+ <parameter>directory mode</parameter></link> parameter for masking
+ mode bits on created directories. See also the <link linkend="INHERITPERMISSIONS">
+ <parameter>inherit permissions</parameter></link> parameter.</para>
+
+ <para>Note that this parameter does not apply to permissions
+ set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+ a mask on access control lists also, they need to set the <link
+ linkend="SECURITYMASK"><parameter>security mask</parameter></link>.</para>
+
+ <para>Default: <command>create mask = 0744</command></para>
+ <para>Example: <command>create mask = 0775</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="CREATEMODE">create mode (S)</term>
+ <listitem><para>This is a synonym for <link linkend="CREATEMASK"><parameter>
+ create mask</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEADTIME">deadtime (G)</term>
+ <listitem><para>The value of the parameter (a decimal integer)
+ represents the number of minutes of inactivity before a connection
+ is considered dead, and it is disconnected. The deadtime only takes
+ effect if the number of open files is zero.</para>
+
+ <para>This is useful to stop a server's resources being
+ exhausted by a large number of inactive connections.</para>
+
+ <para>Most clients have an auto-reconnect feature when a
+ connection is broken so in most cases this parameter should be
+ transparent to users.</para>
+
+ <para>Using this parameter with a timeout of a few minutes
+ is recommended for most systems.</para>
+
+ <para>A deadtime of zero indicates that no auto-disconnection
+ should be performed.</para>
+
+ <para>Default: <command>deadtime = 0</command></para>
+ <para>Example: <command>deadtime = 15</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEBUGHIRESTIMESTAMP">debug hires timestamp (G)</term>
+ <listitem><para>Sometimes the timestamps in the log messages
+ are needed with a resolution of higher that seconds, this
+ boolean parameter adds microsecond resolution to the timestamp
+ message header when turned on.</para>
+
+ <para>Note that the parameter <link linkend="DEBUGTIMESTAMP"><parameter>
+ debug timestamp</parameter></link> must be on for this to have an
+ effect.</para>
+
+ <para>Default: <command>debug hires timestamp = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEBUGPID">debug pid (G)</term>
+ <listitem><para>When using only one log file for more then one
+ forked <ulink url="smbd.8.html">smbd</ulink>-process there may be hard to follow which process
+ outputs which message. This boolean parameter is adds the process-id
+ to the timestamp message headers in the logfile when turned on.</para>
+
+ <para>Note that the parameter <link linkend="DEBUGTIMESTAMP"><parameter>
+ debug timestamp</parameter></link> must be on for this to have an
+ effect.</para>
+
+ <para>Default: <command>debug pid = no</command></para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="DEBUGTIMESTAMP">debug timestamp (G)</term>
+ <listitem><para>Samba 2.2 debug log messages are timestamped
+ by default. If you are running at a high <link linkend="DEBUGLEVEL">
+ <parameter>debug level</parameter></link> these timestamps
+ can be distracting. This boolean parameter allows timestamping
+ to be turned off.</para>
+
+ <para>Default: <command>debug timestamp = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEBUGUID">debug uid (G)</term>
+ <listitem><para>Samba is sometimes run as root and sometime
+ run as the connected user, this boolean parameter inserts the
+ current euid, egid, uid and gid to the timestamp message headers
+ in the log file if turned on.</para>
+
+ <para>Note that the parameter <link linkend="DEBUGTIMESTAMP"><parameter>
+ debug timestamp</parameter></link> must be on for this to have an
+ effect.</para>
+
+ <para>Default: <command>debug uid = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEBUGLEVEL">debuglevel (G)</term>
+ <listitem><para>Synonym for <link linkend="LOGLEVEL"><parameter>
+ log level</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEFAULT">default (G)</term>
+ <listitem><para>A synonym for <link linkend="DEFAULTSERVICE"><parameter>
+ default service</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEFAULTCASE">default case (S)</term>
+ <listitem><para>See the section on <link linkend="NAMEMANGLINGSECT">
+ NAME MANGLING</link>. Also note the <link linkend="SHORTPRESERVECASE">
+ <parameter>short preserve case</parameter></link> parameter.</para>
+
+ <para>Default: <command>default case = lower</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DEFAULTSERVICE">default service (G)</term>
+ <listitem><para>This parameter specifies the name of a service
+ which will be connected to if the service actually requested cannot
+ be found. Note that the square brackets are <emphasis>NOT</emphasis>
+ given in the parameter value (see example below).</para>
+
+ <para>There is no default value for this parameter. If this
+ parameter is not given, attempting to connect to a nonexistent
+ service results in an error.</para>
+
+ <para>Typically the default service would be a <link linkend="GUESTOK">
+ <parameter>guest ok</parameter></link>, <link linkend="READONLY">
+ <parameter>read-only</parameter></link> service.</para>
+
+ <para>Also note that the apparent service name will be changed
+ to equal that of the requested service, this is very useful as it
+ allows you to use macros like <parameter>%S</parameter> to make
+ a wildcard service.</para>
+
+ <para>Note also that any "_" characters in the name of the service
+ used in the default service will get mapped to a "/". This allows for
+ interesting things.</para>
+
+
+ <para>Example:</para>
+
+ <para><programlisting>
+[global]
+ default service = pub
+
+[pub]
+ path = /%S
+ </programlisting></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DELETEPRINTERCOMMAND">delete printer command (G)</term>
+ <listitem><para>With the introduction of MS-RPC based printer
+ support for Windows NT/2000 clients in Samba 2.2, it is now
+ possible to delete printer at run time by issuing the
+ DeletePrinter() RPC call.</para>
+
+ <para>For a Samba host this means that the printer must be
+ physically deleted from underlying printing system. The <parameter>
+ deleteprinter command</parameter> defines a script to be run which
+ will perform the necessary operations for removing the printer
+ from the print system and from <filename>smb.conf</filename>.
+ </para>
+
+ <para>The <parameter>delete printer command</parameter> is
+ automatically called with only one parameter: <parameter>
+ "printer name"</parameter>.</para>
+
+
+ <para>Once the <parameter>delete printer command</parameter> has
+ been executed, <command>smbd</command> will reparse the <filename>
+ smb.conf</filename> to associated printer no longer exists.
+ If the sharename is still valid, then <command>smbd
+ </command> will return an ACCESS_DENIED error to the client.</para>
+
+ <para>See also <link linkend="ADDPRINTERCOMMAND"><parameter>
+ add printer command</parameter></link>, <link
+ linkend="printing"><parameter>printing</parameter></link>,
+ <link linkend="SHOWADDPRINTERWIZARD"><parameter>show add
+ printer wizard</parameter></link></para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>deleteprinter command = /usr/bin/removeprinter
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DELETEREADONLY">delete readonly (S)</term>
+ <listitem><para>This parameter allows readonly files to be deleted.
+ This is not normal DOS semantics, but is allowed by UNIX.</para>
+
+ <para>This option may be useful for running applications such
+ as rcs, where UNIX file ownership prevents changing file
+ permissions, and DOS semantics prevent deletion of a read only file.</para>
+
+ <para>Default: <command>delete readonly = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DELETESHARECOMMAND">delete share command (G)</term>
+ <listitem><para>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <parameter>delete share command</parameter> is used to define an
+ external program or script which will remove an existing service
+ definition from <filename>smb.conf</filename>. In order to successfully
+ execute the <parameter>delete share command</parameter>, <command>smbd</command>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </para>
+
+ <para>
+ When executed, <command>smbd</command> will automatically invoke the
+ <parameter>delete share command</parameter> with two parameters.
+ </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>configFile</parameter> - the location
+ of the global <filename>smb.conf</filename> file.
+ </para></listitem>
+
+ <listitem><para><parameter>shareName</parameter> - the name of
+ the existing service.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ This parameter is only used to remove file shares. To delete printer shares,
+ see the <link linkend="DELETEPRINTERCOMMAND"><parameter>delete printer
+ command</parameter></link>.
+ </para>
+
+ <para>
+ See also <link linkend="ADDSHARECOMMAND"><parameter>add share
+ command</parameter></link>, <link linkend="CHANGESHARECOMMAND"><parameter>change
+ share command</parameter></link>.
+ </para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>delete share command = /usr/local/bin/delshare</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DELETEUSERSCRIPT">delete user script (G)</term>
+ <listitem><para>This is the full pathname to a script that will
+ be run <emphasis>AS ROOT</emphasis> by <ulink url="smbd.8.html">
+ <command>smbd(8)</command></ulink> under special circumstances
+ described below.</para>
+
+ <para>Normally, a Samba server requires that UNIX users are
+ created for all users accessing files on this server. For sites
+ that use Windows NT account databases as their primary user database
+ creating these users and keeping the user list in sync with the
+ Windows NT PDC is an onerous task. This option allows <command>
+ smbd</command> to delete the required UNIX users <emphasis>ON
+ DEMAND</emphasis> when a user accesses the Samba server and the
+ Windows NT user no longer exists.</para>
+
+ <para>In order to use this option, <command>smbd</command> must be
+ set to <parameter>security = domain</parameter> and <parameter>delete
+ user script</parameter> must be set to a full pathname for a script
+ that will delete a UNIX user given one argument of <parameter>%u
+ </parameter>, which expands into the UNIX user name to delete.
+ <emphasis>NOTE</emphasis> that this is different to the <link
+ linkend="ADDUSERSCRIPT"><parameter>add user script</parameter></link>
+ which will work with the <parameter>security = server</parameter> option
+ as well as <parameter>security = domain</parameter>. The reason for this
+ is only when Samba is a domain member does it get the information
+ on an attempted user logon that a user no longer exists. In the
+ <parameter>security = server</parameter> mode a missing user
+ is treated the same as an invalid password logon attempt. Deleting
+ the user in this circumstance would not be a good idea.</para>
+
+ <para>When the Windows user attempts to access the Samba server,
+ at <emphasis>login</emphasis> (session setup in the SMB protocol)
+ time, <command>smbd</command> contacts the <link linkend="PASSWORDSERVER">
+ <parameter>password server</parameter></link> and attempts to authenticate
+ the given user with the given password. If the authentication fails
+ with the specific Domain error code meaning that the user no longer
+ exists then <command>smbd</command> attempts to find a UNIX user in
+ the UNIX password database that matches the Windows user account. If
+ this lookup succeeds, and <parameter>delete user script</parameter> is
+ set then <command>smbd</command> will all the specified script
+ <emphasis>AS ROOT</emphasis>, expanding any <parameter>%u</parameter>
+ argument to be the user name to delete.</para>
+
+ <para>This script should delete the given UNIX username. In this way,
+ UNIX users are dynamically deleted to match existing Windows NT
+ accounts.</para>
+
+ <para>See also <link linkend="SECURITYEQUALSDOMAIN">security = domain</link>,
+ <link linkend="PASSWORDSERVER"><parameter>password server</parameter>
+ </link>, <link linkend="ADDUSERSCRIPT"><parameter>add user script</parameter>
+ </link>.</para>
+
+ <para>Default: <command>delete user script = &lt;empty string&gt;
+ </command></para>
+ <para>Example: <command>delete user script = /usr/local/samba/bin/del_user
+ %u</command></para></listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DELETEVETOFILES">delete veto files (S)</term>
+ <listitem><para>This option is used when Samba is attempting to
+ delete a directory that contains one or more vetoed directories
+ (see the <link linkend="VETOFILES"><parameter>veto files</parameter></link>
+ option). If this option is set to <constant>false</constant> (the default) then if a vetoed
+ directory contains any non-vetoed files or directories then the
+ directory delete will fail. This is usually what you want.</para>
+
+ <para>If this option is set to <constant>true</constant>, then Samba
+ will attempt to recursively delete any files and directories within
+ the vetoed directory. This can be useful for integration with file
+ serving systems such as NetAtalk which create meta-files within
+ directories you might normally veto DOS/Windows users from seeing
+ (e.g. <filename>.AppleDouble</filename>)</para>
+
+ <para>Setting <command>delete veto files = yes</command> allows these
+ directories to be transparently deleted when the parent directory
+ is deleted (so long as the user has permissions to do so).</para>
+
+ <para>See also the <link linkend="VETOFILES"><parameter>veto
+ files</parameter></link> parameter.</para>
+
+ <para>Default: <command>delete veto files = no</command></para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DENYHOSTS">deny hosts (S)</term>
+ <listitem><para>Synonym for <link linkend="HOSTSDENY"><parameter>hosts
+ deny</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DFREECOMMAND">dfree command (G)</term>
+ <listitem><para>The <parameter>dfree command</parameter> setting should
+ only be used on systems where a problem occurs with the internal
+ disk space calculations. This has been known to happen with Ultrix,
+ but may occur with other operating systems. The symptom that was
+ seen was an error of "Abort Retry Ignore" at the end of each
+ directory listing.</para>
+
+ <para>This setting allows the replacement of the internal routines to
+ calculate the total disk space and amount available with an external
+ routine. The example below gives a possible script that might fulfill
+ this function.</para>
+
+ <para>The external program will be passed a single parameter indicating
+ a directory in the filesystem being queried. This will typically consist
+ of the string <filename>./</filename>. The script should return two
+ integers in ASCII. The first should be the total disk space in blocks,
+ and the second should be the number of available blocks. An optional
+ third return value can give the block size in bytes. The default
+ blocksize is 1024 bytes.</para>
+
+ <para>Note: Your script should <emphasis>NOT</emphasis> be setuid or
+ setgid and should be owned by (and writeable only by) root!</para>
+
+ <para>Default: <emphasis>By default internal routines for
+ determining the disk capacity and remaining space will be used.
+ </emphasis></para>
+
+ <para>Example: <command>dfree command = /usr/local/samba/bin/dfree
+ </command></para>
+
+ <para>Where the script dfree (which must be made executable) could be:</para>
+
+ <para><programlisting>
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+ </programlisting></para>
+
+ <para>or perhaps (on Sys V based systems):</para>
+
+ <para><programlisting>
+ #!/bin/sh
+ /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
+ </programlisting></para>
+
+ <para>Note that you may have to replace the command names
+ with full path names on some systems.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DIRECTORY">directory (S)</term>
+ <listitem><para>Synonym for <link linkend="PATH"><parameter>path
+ </parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DIRECTORYMASK">directory mask (S)</term>
+ <listitem><para>This parameter is the octal modes which are
+ used when converting DOS modes to UNIX modes when creating UNIX
+ directories.</para>
+
+ <para>When a directory is created, the necessary permissions are
+ calculated according to the mapping from DOS modes to UNIX permissions,
+ and the resulting UNIX mode is then bit-wise 'AND'ed with this
+ parameter. This parameter may be thought of as a bit-wise MASK for
+ the UNIX modes of a directory. Any bit <emphasis>not</emphasis> set
+ here will be removed from the modes set on a directory when it is
+ created.</para>
+
+ <para>The default value of this parameter removes the 'group'
+ and 'other' write bits from the UNIX mode, allowing only the
+ user who owns the directory to modify it.</para>
+
+ <para>Following this Samba will bit-wise 'OR' the UNIX mode
+ created from this parameter with the value of the <link
+ linkend="FORCEDIRECTORYMODE"><parameter>force directory mode
+ </parameter></link> parameter. This parameter is set to 000 by
+ default (i.e. no extra mode bits are added).</para>
+
+ <para>Note that this parameter does not apply to permissions
+ set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+ a mask on access control lists also, they need to set the <link
+ linkend="DIRECTORYSECURITYMASK"><parameter>directory security mask</parameter></link>.</para>
+
+ <para>See the <link linkend="FORCEDIRECTORYMODE"><parameter>force
+ directory mode</parameter></link> parameter to cause particular mode
+ bits to always be set on created directories.</para>
+
+ <para>See also the <link linkend="CREATEMODE"><parameter>create mode
+ </parameter></link> parameter for masking mode bits on created files,
+ and the <link linkend="DIRECTORYSECURITYMASK"><parameter>directory
+ security mask</parameter></link> parameter.</para>
+
+ <para>Also refer to the <link linkend="INHERITPERMISSIONS"><parameter>
+ inherit permissions</parameter></link> parameter.</para>
+
+ <para>Default: <command>directory mask = 0755</command></para>
+ <para>Example: <command>directory mask = 0775</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DIRECTORYMODE">directory mode (S)</term>
+ <listitem><para>Synonym for <link linkend="DIRECTORYMASK"><parameter>
+ directory mask</parameter></link></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DIRECTORYSECURITYMASK">directory security mask (S)</term>
+ <listitem><para>This parameter controls what UNIX permission bits
+ can be modified when a Windows NT client is manipulating the UNIX
+ permission on a directory using the native NT security dialog
+ box.</para>
+
+ <para>This parameter is applied as a mask (AND'ed with) to
+ the changed permission bits, thus preventing any bits not in
+ this mask from being modified. Essentially, zero bits in this
+ mask may be treated as a set of bits the user is not allowed
+ to change.</para>
+
+ <para>If not set explicitly this parameter is set to 0777
+ meaning a user is allowed to modify all the user/group/world
+ permissions on a directory.</para>
+
+ <para><emphasis>Note</emphasis> that users who can access the
+ Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ it as the default of <constant>0777</constant>.</para>
+
+ <para>See also the <link linkend="FORCEDIRECTORYSECURITYMODE"><parameter>
+ force directory security mode</parameter></link>, <link
+ linkend="SECURITYMASK"><parameter>security mask</parameter></link>,
+ <link linkend="FORCESECURITYMODE"><parameter>force security mode
+ </parameter></link> parameters.</para>
+
+ <para>Default: <command>directory security mask = 0777</command></para>
+ <para>Example: <command>directory security mask = 0700</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DISABLESPOOLSS">disable spoolss (G)</term>
+ <listitem><para>Enabling this parameter will disables Samba's support
+ for the SPOOLSS set of MS-RPC's and will yield identical behavior
+ as Samba 2.0.x. Windows NT/2000 clients will downgrade to using
+ Lanman style printing commands. Windows 9x/ME will be uneffected by
+ the parameter. However, this will also disable the ability to upload
+ printer drivers to a Samba server via the Windows NT Add Printer
+ Wizard or by using the NT printer properties dialog window. It will
+ also disable the capability of Windows NT/2000 clients to download
+ print drivers from the Samba host upon demand.
+ <emphasis>Be very careful about enabling this parameter.</emphasis>
+ </para>
+
+ <para>See also <link linkend="USECLIENTDRIVER">use client driver</link>
+ </para>
+
+ <para>Default : <command>disable spoolss = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DNSPROXY">dns proxy (G)</term>
+ <listitem><para>Specifies that <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ when acting as a WINS server and finding that a NetBIOS name has not
+ been registered, should treat the NetBIOS name word-for-word as a DNS
+ name and do a lookup with the DNS server for that name on behalf of
+ the name-querying client.</para>
+
+ <para>Note that the maximum length for a NetBIOS name is 15
+ characters, so the DNS name (or DNS alias) can likewise only be
+ 15 characters, maximum.</para>
+
+ <para><command>nmbd</command> spawns a second copy of itself to do the
+ DNS name lookup requests, as doing a name lookup is a blocking
+ action.</para>
+
+ <para>See also the parameter <link linkend="WINSSUPPORT"><parameter>
+ wins support</parameter></link>.</para>
+
+ <para>Default: <command>dns proxy = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DOMAINADMINGROUP">domain admin group (G)</term>
+ <listitem><para>This parameter is intended as a temporary solution
+ to enable users to be a member of the "Domain Admins" group when
+ a Samba host is acting as a PDC. A complete solution will be provided
+ by a system for mapping Windows NT/2000 groups onto UNIX groups.
+ Please note that this parameter has a somewhat confusing name. It
+ accepts a list of usernames and of group names in standard
+ <filename>smb.conf</filename> notation.
+ </para>
+
+ <para>See also <link linkend="DOMAINGUESTGROUP"><parameter>domain
+ guest group</parameter></link>, <link linkend="DOMAINLOGONS"><parameter>domain
+ logons</parameter></link>
+ </para>
+
+ <para>Default: <emphasis>no domain administrators</emphasis></para>
+ <para>Example: <command>domain admin group = root @wheel</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DOMAINGUESTGROUP">domain guest group (G)</term>
+ <listitem><para>This parameter is intended as a temporary solution
+ to enable users to be a member of the "Domain Guests" group when
+ a Samba host is acting as a PDC. A complete solution will be provided
+ by a system for mapping Windows NT/2000 groups onto UNIX groups.
+ Please note that this parameter has a somewhat confusing name. It
+ accepts a list of usernames and of group names in standard
+ <filename>smb.conf</filename> notation.
+ </para>
+
+ <para>See also <link linkend="DOMAINADMINGROUP"><parameter>domain
+ admin group</parameter></link>, <link linkend="DOMAINLOGONS"><parameter>domain
+ logons</parameter></link>
+ </para>
+
+ <para>Default: <emphasis>no domain guests</emphasis></para>
+ <para>Example: <command>domain guest group = nobody @guest</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="DOMAINLOGONS">domain logons (G)</term>
+ <listitem><para>If set to <constant>true</constant>, the Samba server will serve
+ Windows 95/98 Domain logons for the <link linkend="WORKGROUP">
+ <parameter>workgroup</parameter></link> it is in. Samba 2.2 also
+ has limited capability to act as a domain controller for Windows
+ NT 4 Domains. For more details on setting up this feature see
+ the Samba-PDC-HOWTO included in the <filename>htmldocs/</filename>
+ directory shipped with the source code.</para>
+
+ <para>Default: <command>domain logons = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DOMAINMASTER">domain master (G)</term>
+ <listitem><para>Tell <ulink url="nmbd.8.html"><command>
+ nmbd(8)</command></ulink> to enable WAN-wide browse list
+ collation. Setting this option causes <command>nmbd</command> to
+ claim a special domain specific NetBIOS name that identifies
+ it as a domain master browser for its given <link linkend="WORKGROUP">
+ <parameter>workgroup</parameter></link>. Local master browsers
+ in the same <parameter>workgroup</parameter> on broadcast-isolated
+ subnets will give this <command>nmbd</command> their local browse lists,
+ and then ask <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>
+ for a complete copy of the browse list for the whole wide area
+ network. Browser clients will then contact their local master browser,
+ and will receive the domain-wide browse list, instead of just the list
+ for their broadcast-isolated subnet.</para>
+
+ <para>Note that Windows NT Primary Domain Controllers expect to be
+ able to claim this <parameter>workgroup</parameter> specific special
+ NetBIOS name that identifies them as domain master browsers for
+ that <parameter>workgroup</parameter> by default (i.e. there is no
+ way to prevent a Windows NT PDC from attempting to do this). This
+ means that if this parameter is set and <command>nmbd</command> claims
+ the special name for a <parameter>workgroup</parameter> before a Windows
+ NT PDC is able to do so then cross subnet browsing will behave
+ strangely and may fail.</para>
+
+ <para>If <link linkend="DOMAINLOGONS"><command>domain logons = yes</command>
+ </link>, then the default behavior is to enable the <parameter>domain
+ master</parameter> parameter. If <parameter>domain logons</parameter> is
+ not enabled (the default setting), then neither will <parameter>domain
+ master</parameter> be enabled by default.</para>
+
+ <para>Default: <command>domain master = auto</command></para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="DONTDESCEND">dont descend (S)</term>
+ <listitem><para>There are certain directories on some systems
+ (e.g., the <filename>/proc</filename> tree under Linux) that are either not
+ of interest to clients or are infinitely deep (recursive). This
+ parameter allows you to specify a comma-delimited list of directories
+ that the server should always show as empty.</para>
+
+ <para>Note that Samba can be very fussy about the exact format
+ of the "dont descend" entries. For example you may need <filename>
+ ./proc</filename> instead of just <filename>/proc</filename>.
+ Experimentation is the best policy :-) </para>
+
+ <para>Default: <emphasis>none (i.e., all directories are OK
+ to descend)</emphasis></para>
+ <para>Example: <command>dont descend = /proc,/dev</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DOSFILEMODE">dos filemode (S)</term>
+ <listitem><para> The default behavior in Samba is to provide
+ UNIX-like behavior where only the owner of a file/directory is
+ able to change the permissions on it. However, this behavior
+ is often confusing to DOS/Windows users. Enabling this parameter
+ allows a user who has write access to the file (by whatever
+ means) to modify the permissions on it. Note that a user
+ belonging to the group owning the file will not be allowed to
+ change permissions if the group is only granted read access.
+ Ownership of the file/directory is not changed, only the permissions
+ are modified.</para>
+
+ <para>Default: <command>dos filemode = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DOSFILETIMERESOLUTION">dos filetime resolution (S)</term>
+ <listitem><para>Under the DOS and Windows FAT filesystem, the finest
+ granularity on time resolution is two seconds. Setting this parameter
+ for a share causes Samba to round the reported time down to the
+ nearest two second boundary when a query call that requires one second
+ resolution is made to <ulink url="smbd.8.html"><command>smbd(8)</command>
+ </ulink>.</para>
+
+ <para>This option is mainly used as a compatibility option for Visual
+ C++ when used against Samba shares. If oplocks are enabled on a
+ share, Visual C++ uses two different time reading calls to check if a
+ file has changed since it was last read. One of these calls uses a
+ one-second granularity, the other uses a two second granularity. As
+ the two second call rounds any odd second down, then if the file has a
+ timestamp of an odd number of seconds then the two timestamps will not
+ match and Visual C++ will keep reporting the file has changed. Setting
+ this option causes the two timestamps to match, and Visual C++ is
+ happy.</para>
+
+ <para>Default: <command>dos filetime resolution = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="DOSFILETIMES">dos filetimes (S)</term>
+ <listitem><para>Under DOS and Windows, if a user can write to a
+ file they can change the timestamp on it. Under POSIX semantics,
+ only the owner of the file or root may change the timestamp. By
+ default, Samba runs with POSIX semantics and refuses to change the
+ timestamp on a file if the user <command>smbd</command> is acting
+ on behalf of is not the file owner. Setting this option to <constant>
+ true</constant> allows DOS semantics and <ulink url="smbd.8.html">smbd</ulink> will change the file
+ timestamp as DOS requires.</para>
+
+ <para>Default: <command>dos filetimes = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ENCRYPTPASSWORDS">encrypt passwords (G)</term>
+ <listitem><para>This boolean controls whether encrypted passwords
+ will be negotiated with the client. Note that Windows NT 4.0 SP3 and
+ above and also Windows 98 will by default expect encrypted passwords
+ unless a registry entry is changed. To use encrypted passwords in
+ Samba see the file ENCRYPTION.txt in the Samba documentation
+ directory <filename>docs/</filename> shipped with the source code.</para>
+
+ <para>In order for encrypted passwords to work correctly
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink> must either
+ have access to a local <ulink url="smbpasswd.5.html"><filename>smbpasswd(5)
+ </filename></ulink> file (see the <ulink url="smbpasswd.8.html"><command>
+ smbpasswd(8)</command></ulink> program for information on how to set up
+ and maintain this file), or set the <link
+ linkend="SECURITY">security = [server|domain]</link> parameter which
+ causes <command>smbd</command> to authenticate against another
+ server.</para>
+
+ <para>Default: <command>encrypt passwords = no</command></para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="ENHANCEDBROWSING">enhanced browsing (G)</term>
+ <listitem><para>This option enables a couple of enhancements to
+ cross-subnet browse propagation that have been added in Samba
+ but which are not standard in Microsoft implementations.
+ </para>
+
+ <para>The first enhancement to browse propagation consists of a regular
+ wildcard query to a Samba WINS server for all Domain Master Browsers,
+ followed by a browse synchronization with each of the returned
+ DMBs. The second enhancement consists of a regular randomised browse
+ synchronization with all currently known DMBs.</para>
+
+ <para>You may wish to disable this option if you have a problem with empty
+ workgroups not disappearing from browse lists. Due to the restrictions
+ of the browse protocols these enhancements can cause a empty workgroup
+ to stay around forever which can be annoying.</para>
+
+ <para>In general you should leave this option enabled as it makes
+ cross-subnet browse propagation much more reliable.</para>
+
+ <para>Default: <command>enhanced browsing = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="ENUMPORTSCOMMAND">enumports command (G)</term>
+ <listitem><para>The concept of a "port" is fairly foreign
+ to UNIX hosts. Under Windows NT/2000 print servers, a port
+ is associated with a port monitor and generally takes the form of
+ a local port (i.e. LPT1:, COM1:, FILE:) or a remote port
+ (i.e. LPD Port Monitor, etc...). By default, Samba has only one
+ port defined--<constant>"Samba Printer Port"</constant>. Under
+ Windows NT/2000, all printers must have a valid port name.
+ If you wish to have a list of ports displayed (<command>smbd
+ </command> does not use a port name for anything) other than
+ the default <constant>"Samba Printer Port"</constant>, you
+ can define <parameter>enumports command</parameter> to point to
+ a program which should generate a list of ports, one per line,
+ to standard output. This listing will then be used in response
+ to the level 1 and 2 EnumPorts() RPC.</para>
+
+ <para>Default: <emphasis>no enumports command</emphasis></para>
+ <para>Example: <command>enumports command = /usr/bin/listports
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><anchor id="EXEC">exec (S)</term>
+ <listitem><para>This is a synonym for <link linkend="PREEXEC">
+ <parameter>preexec</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FAKEDIRECTORYCREATETIMES">fake directory create times (S)</term>
+ <listitem><para>NTFS and Windows VFAT file systems keep a create
+ time for all files and directories. This is not the same as the
+ ctime - status change time - that Unix keeps, so Samba by default
+ reports the earliest of the various times Unix does keep. Setting
+ this parameter for a share causes Samba to always report midnight
+ 1-1-1980 as the create time for directories.</para>
+
+ <para>This option is mainly used as a compatibility option for
+ Visual C++ when used against Samba shares. Visual C++ generated
+ makefiles have the object directory as a dependency for each object
+ file, and a make rule to create the directory. Also, when NMAKE
+ compares timestamps it uses the creation time when examining a
+ directory. Thus the object directory will be created if it does not
+ exist, but once it does exist it will always have an earlier
+ timestamp than the object files it contains.</para>
+
+ <para>However, Unix time semantics mean that the create time
+ reported by Samba will be updated whenever a file is created or
+ or deleted in the directory. NMAKE finds all object files in
+ the object directory. The timestamp of the last one built is then
+ compared to the timestamp of the object directory. If the
+ directory's timestamp if newer, then all object files
+ will be rebuilt. Enabling this option
+ ensures directories always predate their contents and an NMAKE build
+ will proceed as expected.</para>
+
+ <para>Default: <command>fake directory create times = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FAKEOPLOCKS">fake oplocks (S)</term>
+ <listitem><para>Oplocks are the way that SMB clients get permission
+ from a server to locally cache file operations. If a server grants
+ an oplock (opportunistic lock) then the client is free to assume
+ that it is the only one accessing the file and it will aggressively
+ cache file data. With some oplock types the client may even cache
+ file open/close operations. This can give enormous performance benefits.
+ </para>
+
+ <para>When you set <command>fake oplocks = yes</command>, <ulink
+ url="smbd.8.html"><command>smbd(8)</command></ulink> will
+ always grant oplock requests no matter how many clients are using
+ the file.</para>
+
+ <para>It is generally much better to use the real <link
+ linkend="OPLOCKS"><parameter>oplocks</parameter></link> support rather
+ than this parameter.</para>
+
+ <para>If you enable this option on all read-only shares or
+ shares that you know will only be accessed from one client at a
+ time such as physically read-only media like CDROMs, you will see
+ a big performance improvement on many operations. If you enable
+ this option on shares where multiple clients may be accessing the
+ files read-write at the same time you can get data corruption. Use
+ this option carefully!</para>
+
+ <para>Default: <command>fake oplocks = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FOLLOWSYMLINKS">follow symlinks (S)</term>
+ <listitem><para>This parameter allows the Samba administrator
+ to stop <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>
+ from following symbolic links in a particular share. Setting this
+ parameter to <constant>no</constant> prevents any file or directory
+ that is a symbolic link from being followed (the user will get an
+ error). This option is very useful to stop users from adding a
+ symbolic link to <filename>/etc/passwd</filename> in their home
+ directory for instance. However it will slow filename lookups
+ down slightly.</para>
+
+ <para>This option is enabled (i.e. <command>smbd</command> will
+ follow symbolic links) by default.</para>
+
+ <para>Default: <command>follow symlinks = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCECREATEMODE">force create mode (S)</term>
+ <listitem><para>This parameter specifies a set of UNIX mode bit
+ permissions that will <emphasis>always</emphasis> be set on a
+ file created by Samba. This is done by bitwise 'OR'ing these bits onto
+ the mode bits of a file that is being created or having its
+ permissions changed. The default for this parameter is (in octal)
+ 000. The modes in this parameter are bitwise 'OR'ed onto the file
+ mode after the mask set in the <parameter>create mask</parameter>
+ parameter is applied.</para>
+
+ <para>See also the parameter <link linkend="CREATEMASK"><parameter>create
+ mask</parameter></link> for details on masking mode bits on files.</para>
+
+ <para>See also the <link linkend="INHERITPERMISSIONS"><parameter>inherit
+ permissions</parameter></link> parameter.</para>
+
+ <para>Default: <command>force create mode = 000</command></para>
+ <para>Example: <command>force create mode = 0755</command></para>
+
+ <para>would force all created files to have read and execute
+ permissions set for 'group' and 'other' as well as the
+ read/write/execute bits set for the 'user'.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCEDIRECTORYMODE">force directory mode (S)</term>
+ <listitem><para>This parameter specifies a set of UNIX mode bit
+ permissions that will <emphasis>always</emphasis> be set on a directory
+ created by Samba. This is done by bitwise 'OR'ing these bits onto the
+ mode bits of a directory that is being created. The default for this
+ parameter is (in octal) 0000 which will not add any extra permission
+ bits to a created directory. This operation is done after the mode
+ mask in the parameter <parameter>directory mask</parameter> is
+ applied.</para>
+
+ <para>See also the parameter <link linkend="DIRECTORYMASK"><parameter>
+ directory mask</parameter></link> for details on masking mode bits
+ on created directories.</para>
+
+ <para>See also the <link linkend="INHERITPERMISSIONS"><parameter>
+ inherit permissions</parameter></link> parameter.</para>
+
+ <para>Default: <command>force directory mode = 000</command></para>
+ <para>Example: <command>force directory mode = 0755</command></para>
+
+ <para>would force all created directories to have read and execute
+ permissions set for 'group' and 'other' as well as the
+ read/write/execute bits set for the 'user'.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCEDIRECTORYSECURITYMODE">force directory
+ security mode (S)</term>
+ <listitem><para>This parameter controls what UNIX permission bits
+ can be modified when a Windows NT client is manipulating the UNIX
+ permission on a directory using the native NT security dialog box.</para>
+
+ <para>This parameter is applied as a mask (OR'ed with) to the
+ changed permission bits, thus forcing any bits in this mask that
+ the user may have modified to be on. Essentially, one bits in this
+ mask may be treated as a set of bits that, when modifying security
+ on a directory, the user has always set to be 'on'.</para>
+
+ <para>If not set explicitly this parameter is 000, which
+ allows a user to modify all the user/group/world permissions on a
+ directory without restrictions.</para>
+
+ <para><emphasis>Note</emphasis> that users who can access the
+ Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ it set as 0000.</para>
+
+ <para>See also the <link linkend="DIRECTORYSECURITYMASK"><parameter>
+ directory security mask</parameter></link>, <link linkend="SECURITYMASK">
+ <parameter>security mask</parameter></link>,
+ <link linkend="FORCESECURITYMODE"><parameter>force security mode
+ </parameter></link> parameters.</para>
+
+ <para>Default: <command>force directory security mode = 0</command></para>
+ <para>Example: <command>force directory security mode = 700</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCEGROUP">force group (S)</term>
+ <listitem><para>This specifies a UNIX group name that will be
+ assigned as the default primary group for all users connecting
+ to this service. This is useful for sharing files by ensuring
+ that all access to files on service will use the named group for
+ their permissions checking. Thus, by assigning permissions for this
+ group to the files and directories within this service the Samba
+ administrator can restrict or allow sharing of these files.</para>
+
+ <para>In Samba 2.0.5 and above this parameter has extended
+ functionality in the following way. If the group name listed here
+ has a '+' character prepended to it then the current user accessing
+ the share only has the primary group default assigned to this group
+ if they are already assigned as a member of that group. This allows
+ an administrator to decide that only users who are already in a
+ particular group will create files with group ownership set to that
+ group. This gives a finer granularity of ownership assignment. For
+ example, the setting <filename>force group = +sys</filename> means
+ that only users who are already in group sys will have their default
+ primary group assigned to sys when accessing this Samba share. All
+ other users will retain their ordinary primary group.</para>
+
+ <para>If the <link linkend="FORCEUSER"><parameter>force user
+ </parameter></link> parameter is also set the group specified in
+ <parameter>force group</parameter> will override the primary group
+ set in <parameter>force user</parameter>.</para>
+
+ <para>See also <link linkend="FORCEUSER"><parameter>force
+ user</parameter></link>.</para>
+
+ <para>Default: <emphasis>no forced group</emphasis></para>
+ <para>Example: <command>force group = agroup</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCESECURITYMODE">force security mode (S)</term>
+ <listitem><para>This parameter controls what UNIX permission
+ bits can be modified when a Windows NT client is manipulating
+ the UNIX permission on a file using the native NT security dialog
+ box.</para>
+
+ <para>This parameter is applied as a mask (OR'ed with) to the
+ changed permission bits, thus forcing any bits in this mask that
+ the user may have modified to be on. Essentially, one bits in this
+ mask may be treated as a set of bits that, when modifying security
+ on a file, the user has always set to be 'on'.</para>
+
+ <para>If not set explicitly this parameter is set to 0,
+ and allows a user to modify all the user/group/world permissions on a file,
+ with no restrictions.</para>
+
+ <para><emphasis>Note</emphasis> that users who can access
+ the Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ this set to 0000.</para>
+
+ <para>See also the <link linkend="FORCEDIRECTORYSECURITYMODE"><parameter>
+ force directory security mode</parameter></link>,
+ <link linkend="DIRECTORYSECURITYMASK"><parameter>directory security
+ mask</parameter></link>, <link linkend="SECURITYMASK"><parameter>
+ security mask</parameter></link> parameters.</para>
+
+ <para>Default: <command>force security mode = 0</command></para>
+ <para>Example: <command>force security mode = 700</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FORCEUSER">force user (S)</term>
+ <listitem><para>This specifies a UNIX user name that will be
+ assigned as the default user for all users connecting to this service.
+ This is useful for sharing files. You should also use it carefully
+ as using it incorrectly can cause security problems.</para>
+
+ <para>This user name only gets used once a connection is established.
+ Thus clients still need to connect as a valid user and supply a
+ valid password. Once connected, all file operations will be performed
+ as the "forced user", no matter what username the client connected
+ as. This can be very useful.</para>
+
+ <para>In Samba 2.0.5 and above this parameter also causes the
+ primary group of the forced user to be used as the primary group
+ for all file activity. Prior to 2.0.5 the primary group was left
+ as the primary group of the connecting user (this was a bug).</para>
+
+ <para>See also <link linkend="FORCEGROUP"><parameter>force group
+ </parameter></link></para>
+
+ <para>Default: <emphasis>no forced user</emphasis></para>
+ <para>Example: <command>force user = auser</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="FSTYPE">fstype (S)</term>
+ <listitem><para>This parameter allows the administrator to
+ configure the string that specifies the type of filesystem a share
+ is using that is reported by <ulink url="smbd.8.html"><command>smbd(8)
+ </command></ulink> when a client queries the filesystem type
+ for a share. The default type is <constant>NTFS</constant> for
+ compatibility with Windows NT but this can be changed to other
+ strings such as <constant>Samba</constant> or <constant>FAT
+ </constant> if required.</para>
+
+ <para>Default: <command>fstype = NTFS</command></para>
+ <para>Example: <command>fstype = Samba</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="GETWDCACHE">getwd cache (G)</term>
+ <listitem><para>This is a tuning option. When this is enabled a
+ caching algorithm will be used to reduce the time taken for getwd()
+ calls. This can have a significant impact on performance, especially
+ when the <link linkend="WIDELINKS"><parameter>wide links</parameter>
+ </link>parameter is set to <constant>false</constant>.</para>
+
+ <para>Default: <command>getwd cache = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="GROUP">group (S)</term>
+ <listitem><para>Synonym for <link linkend="FORCEGROUP"><parameter>force
+ group</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="GUESTACCOUNT">guest account (S)</term>
+ <listitem><para>This is a username which will be used for access
+ to services which are specified as <link linkend="GUESTOK"><parameter>
+ guest ok</parameter></link> (see below). Whatever privileges this
+ user has will be available to any client connecting to the guest service.
+ Typically this user will exist in the password file, but will not
+ have a valid login. The user account "ftp" is often a good choice
+ for this parameter. If a username is specified in a given service,
+ the specified username overrides this one.</para>
+
+ <para>One some systems the default guest account "nobody" may not
+ be able to print. Use another account in this case. You should test
+ this by trying to log in as your guest user (perhaps by using the
+ <command>su -</command> command) and trying to print using the
+ system print command such as <command>lpr(1)</command> or <command>
+ lp(1)</command>.</para>
+
+ <para>Default: <emphasis>specified at compile time, usually
+ "nobody"</emphasis></para>
+
+ <para>Example: <command>guest account = ftp</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="GUESTOK">guest ok (S)</term>
+ <listitem><para>If this parameter is <constant>yes</constant> for
+ a service, then no password is required to connect to the service.
+ Privileges will be those of the <link linkend="GUESTACCOUNT"><parameter>
+ guest account</parameter></link>.</para>
+
+ <para>See the section below on <link linkend="SECURITY"><parameter>
+ security</parameter></link> for more information about this option.
+ </para>
+
+ <para>Default: <command>guest ok = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="GUESTONLY">guest only (S)</term>
+ <listitem><para>If this parameter is <constant>yes</constant> for
+ a service, then only guest connections to the service are permitted.
+ This parameter will have no effect if <link linkend="GUESTOK">
+ <parameter>guest ok</parameter></link> is not set for the service.</para>
+
+ <para>See the section below on <link linkend="SECURITY"><parameter>
+ security</parameter></link> for more information about this option.
+ </para>
+
+ <para>Default: <command>guest only = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HIDEDOTFILES">hide dot files (S)</term>
+ <listitem><para>This is a boolean parameter that controls whether
+ files starting with a dot appear as hidden files.</para>
+
+ <para>Default: <command>hide dot files = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HIDEFILES">hide files(S)</term>
+ <listitem><para>This is a list of files or directories that are not
+ visible but are accessible. The DOS 'hidden' attribute is applied
+ to any files or directories that match.</para>
+
+ <para>Each entry in the list must be separated by a '/',
+ which allows spaces to be included in the entry. '*'
+ and '?' can be used to specify multiple files or directories
+ as in DOS wildcards.</para>
+
+ <para>Each entry must be a Unix path, not a DOS path and must
+ not include the Unix directory separator '/'.</para>
+
+ <para>Note that the case sensitivity option is applicable
+ in hiding files.</para>
+
+ <para>Setting this parameter will affect the performance of Samba,
+ as it will be forced to check all files and directories for a match
+ as they are scanned.</para>
+
+ <para>See also <link linkend="HIDEDOTFILES"><parameter>hide
+ dot files</parameter></link>, <link linkend="VETOFILES"><parameter>
+ veto files</parameter></link> and <link linkend="CASESENSITIVE">
+ <parameter>case sensitive</parameter></link>.</para>
+
+ <para>Default: <emphasis>no file are hidden</emphasis></para>
+ <para>Example: <command>hide files =
+ /.*/DesktopFolderDB/TrashFor%m/resource.frk/</command></para>
+
+ <para>The above example is based on files that the Macintosh
+ SMB client (DAVE) available from <ulink url="http://www.thursby.com">
+ Thursby</ulink> creates for internal use, and also still hides
+ all files beginning with a dot.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HIDELOCALUSERS">hide local users(G)</term>
+ <listitem><para>This parameter toggles the hiding of local UNIX
+ users (root, wheel, floppy, etc) from remote clients.</para>
+
+ <para>Default: <command>hide local users = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HIDEUNREADABLE">hide unreadable (S)</term>
+ <listitem><para>This parameter prevents clients from seeing the
+ existance of files that cannot be read. Defaults to off.</para>
+
+ <para>Default: <command>hide unreadable = no</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HOMEDIRMAP">homedir map (G)</term>
+ <listitem><para>If<link linkend="NISHOMEDIR"><parameter>nis homedir
+ </parameter></link> is <constant>true</constant>, and <ulink
+ url="smbd.8.html"><command>smbd(8)</command></ulink> is also acting
+ as a Win95/98 <parameter>logon server</parameter> then this parameter
+ specifies the NIS (or YP) map from which the server for the user's
+ home directory should be extracted. At present, only the Sun
+ auto.home map format is understood. The form of the map is:</para>
+
+ <para><command>username server:/some/file/system</command></para>
+
+ <para>and the program will extract the servername from before
+ the first ':'. There should probably be a better parsing system
+ that copes with different map formats and also Amd (another
+ automounter) maps.</para>
+
+ <para><emphasis>NOTE :</emphasis>A working NIS client is required on
+ the system for this option to work.</para>
+
+ <para>See also <link linkend="NISHOMEDIR"><parameter>nis homedir</parameter>
+ </link>, <link linkend="DOMAINLOGONS"><parameter>domain logons</parameter>
+ </link>.</para>
+
+ <para>Default: <command>homedir map = &lt;empty string&gt;</command></para>
+ <para>Example: <command>homedir map = amd.homedir</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="HOSTMSDFS">host msdfs (G)</term>
+ <listitem><para>This boolean parameter is only available
+ if Samba has been configured and compiled with the <command>
+ --with-msdfs</command> option. If set to <constant>yes</constant>,
+ Samba will act as a Dfs server, and allow Dfs-aware clients
+ to browse Dfs trees hosted on the server.</para>
+
+ <para>See also the <link linkend="MSDFSROOT"><parameter>
+ msdfs root</parameter></link> share level parameter. For
+ more information on setting up a Dfs tree on Samba,
+ refer to <ulink url="msdfs_setup.html">msdfs_setup.html</ulink>.
+ </para>
+
+ <para>Default: <command>host msdfs = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="HOSTSALLOW">hosts allow (S)</term>
+ <listitem><para>A synonym for this parameter is <parameter>allow
+ hosts</parameter>.</para>
+
+ <para>This parameter is a comma, space, or tab delimited
+ set of hosts which are permitted to access a service.</para>
+
+ <para>If specified in the [global] section then it will
+ apply to all services, regardless of whether the individual
+ service has a different setting.</para>
+
+ <para>You can specify the hosts by name or IP number. For
+ example, you could restrict access to only the hosts on a
+ Class C subnet with something like <command>allow hosts = 150.203.5.
+ </command>. The full syntax of the list is described in the man
+ page <filename>hosts_access(5)</filename>. Note that this man
+ page may not be present on your system, so a brief description will
+ be given here also.</para>
+
+ <para>Note that the localhost address 127.0.0.1 will always
+ be allowed access unless specifically denied by a <link
+ linkend="HOSTSDENY"><parameter>hosts deny</parameter></link> option.</para>
+
+ <para>You can also specify hosts by network/netmask pairs and
+ by netgroup names if your system supports netgroups. The
+ <emphasis>EXCEPT</emphasis> keyword can also be used to limit a
+ wildcard list. The following examples may provide some help:</para>
+
+ <para>Example 1: allow all IPs in 150.203.*.*; except one</para>
+
+ <para><command>hosts allow = 150.203. EXCEPT 150.203.6.66</command></para>
+
+ <para>Example 2: allow hosts that match the given network/netmask</para>
+
+ <para><command>hosts allow = 150.203.15.0/255.255.255.0</command></para>
+
+ <para>Example 3: allow a couple of hosts</para>
+
+ <para><command>hosts allow = lapland, arvidsjaur</command></para>
+
+ <para>Example 4: allow only hosts in NIS netgroup "foonet", but
+ deny access from one particular host</para>
+
+ <para><command>hosts allow = @foonet</command></para>
+
+ <para><command>hosts deny = pirate</command></para>
+
+ <para>Note that access still requires suitable user-level passwords.</para>
+
+ <para>See <ulink url="testparm.1.html"><command>testparm(1)</command>
+ </ulink> for a way of testing your host access to see if it does
+ what you expect.</para>
+
+ <para>Default: <emphasis>none (i.e., all hosts permitted access)
+ </emphasis></para>
+
+ <para>Example: <command>allow hosts = 150.203.5. myhost.mynet.edu.au
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HOSTSDENY">hosts deny (S)</term>
+ <listitem><para>The opposite of <parameter>hosts allow</parameter>
+ - hosts listed here are <emphasis>NOT</emphasis> permitted access to
+ services unless the specific services have their own lists to override
+ this one. Where the lists conflict, the <parameter>allow</parameter>
+ list takes precedence.</para>
+
+ <para>Default: <emphasis>none (i.e., no hosts specifically excluded)
+ </emphasis></para>
+
+ <para>Example: <command>hosts deny = 150.203.4. badhost.mynet.edu.au
+ </command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="HOSTSEQUIV">hosts equiv (G)</term>
+ <listitem><para>If this global parameter is a non-null string,
+ it specifies the name of a file to read for the names of hosts
+ and users who will be allowed access without specifying a password.
+ </para>
+
+ <para>This is not be confused with <link linkend="HOSTSALLOW">
+ <parameter>hosts allow</parameter></link> which is about hosts
+ access to services and is more useful for guest services. <parameter>
+ hosts equiv</parameter> may be useful for NT clients which will
+ not supply passwords to Samba.</para>
+
+ <para><emphasis>NOTE :</emphasis> The use of <parameter>hosts equiv
+ </parameter> can be a major security hole. This is because you are
+ trusting the PC to supply the correct username. It is very easy to
+ get a PC to supply a false username. I recommend that the
+ <parameter>hosts equiv</parameter> option be only used if you really
+ know what you are doing, or perhaps on a home network where you trust
+ your spouse and kids. And only if you <emphasis>really</emphasis> trust
+ them :-).</para>
+
+ <para>Default: <emphasis>no host equivalences</emphasis></para>
+ <para>Example: <command>hosts equiv = /etc/hosts.equiv</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="INCLUDE">include (G)</term>
+ <listitem><para>This allows you to include one config file
+ inside another. The file is included literally, as though typed
+ in place.</para>
+
+ <para>It takes the standard substitutions, except <parameter>%u
+ </parameter>, <parameter>%P</parameter> and <parameter>%S</parameter>.
+ </para>
+
+ <para>Default: <emphasis>no file included</emphasis></para>
+ <para>Example: <command>include = /usr/local/samba/lib/admin_smb.conf
+ </command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="INHERITPERMISSIONS">inherit permissions (S)</term>
+ <listitem><para>The permissions on new files and directories
+ are normally governed by <link linkend="CREATEMASK"><parameter>
+ create mask</parameter></link>, <link linkend="DIRECTORYMASK">
+ <parameter>directory mask</parameter></link>, <link
+ linkend="FORCECREATEMODE"><parameter>force create mode</parameter>
+ </link> and <link linkend="FORCEDIRECTORYMODE"><parameter>force
+ directory mode</parameter></link> but the boolean inherit
+ permissions parameter overrides this.</para>
+
+ <para>New directories inherit the mode of the parent directory,
+ including bits such as setgid.</para>
+
+ <para>New files inherit their read/write bits from the parent
+ directory. Their execute bits continue to be determined by
+ <link linkend="MAPARCHIVE"><parameter>map archive</parameter>
+ </link>, <link linkend="MAPHIDDEN"><parameter>map hidden</parameter>
+ </link> and <link linkend="MAPSYSTEM"><parameter>map system</parameter>
+ </link> as usual.</para>
+
+ <para>Note that the setuid bit is <emphasis>never</emphasis> set via
+ inheritance (the code explicitly prohibits this).</para>
+
+ <para>This can be particularly useful on large systems with
+ many users, perhaps several thousand, to allow a single [homes]
+ share to be used flexibly by each user.</para>
+
+ <para>See also <link linkend="CREATEMASK"><parameter>create mask
+ </parameter></link>, <link linkend="DIRECTORYMASK"><parameter>
+ directory mask</parameter></link>, <link linkend="FORCECREATEMODE">
+ <parameter>force create mode</parameter></link> and <link
+ linkend="FORCEDIRECTORYMODE"><parameter>force directory mode</parameter>
+ </link>.</para>
+
+ <para>Default: <command>inherit permissions = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="INTERFACES">interfaces (G)</term>
+ <listitem><para>This option allows you to override the default
+ network interfaces list that Samba will use for browsing, name
+ registration and other NBT traffic. By default Samba will query
+ the kernel for the list of all active interfaces and use any
+ interfaces except 127.0.0.1 that are broadcast capable.</para>
+
+ <para>The option takes a list of interface strings. Each string
+ can be in any of the following forms:</para>
+
+ <itemizedlist>
+ <listitem><para>a network interface name (such as eth0).
+ This may include shell-like wildcards so eth* will match
+ any interface starting with the substring "eth"</para></listitem>
+
+ <listitem><para>an IP address. In this case the netmask is
+ determined from the list of interfaces obtained from the
+ kernel</para></listitem>
+
+ <listitem><para>an IP/mask pair. </para></listitem>
+
+ <listitem><para>a broadcast/mask pair.</para></listitem>
+ </itemizedlist>
+
+ <para>The "mask" parameters can either be a bit length (such
+ as 24 for a C class network) or a full netmask in dotted
+ decimal form.</para>
+
+ <para>The "IP" parameters above can either be a full dotted
+ decimal IP address or a hostname which will be looked up via
+ the OS's normal hostname resolution mechanisms.</para>
+
+ <para>For example, the following line:</para>
+
+ <para><command>interfaces = eth0 192.168.2.10/24 192.168.3.10/255.255.255.0
+ </command></para>
+
+ <para>would configure three network interfaces corresponding
+ to the eth0 device and IP addresses 192.168.2.10 and 192.168.3.10.
+ The netmasks of the latter two interfaces would be set to 255.255.255.0.</para>
+
+ <para>See also <link linkend="BINDINTERFACESONLY"><parameter>bind
+ interfaces only</parameter></link>.</para>
+
+ <para>Default: <emphasis>all active interfaces except 127.0.0.1
+ that are broadcast capable</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="INVALIDUSERS">invalid users (S)</term>
+ <listitem><para>This is a list of users that should not be allowed
+ to login to this service. This is really a <emphasis>paranoid</emphasis>
+ check to absolutely ensure an improper setting does not breach
+ your security.</para>
+
+ <para>A name starting with a '@' is interpreted as an NIS
+ netgroup first (if your system supports NIS), and then as a UNIX
+ group if the name was not found in the NIS netgroup database.</para>
+
+ <para>A name starting with '+' is interpreted only
+ by looking in the UNIX group database. A name starting with
+ '&' is interpreted only by looking in the NIS netgroup database
+ (this requires NIS to be working on your system). The characters
+ '+' and '&' may be used at the start of the name in either order
+ so the value <parameter>+&amp;group</parameter> means check the
+ UNIX group database, followed by the NIS netgroup database, and
+ the value <parameter>&+group</parameter> means check the NIS
+ netgroup database, followed by the UNIX group database (the
+ same as the '@' prefix).</para>
+
+ <para>The current servicename is substituted for <parameter>%S</parameter>.
+ This is useful in the [homes] section.</para>
+
+ <para>See also <link linkend="VALIDUSERS"><parameter>valid users
+ </parameter></link>.</para>
+
+ <para>Default: <emphasis>no invalid users</emphasis></para>
+ <para>Example: <command>invalid users = root fred admin @wheel
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="KEEPALIVE">keepalive (G)</term>
+ <listitem><para>The value of the parameter (an integer) represents
+ the number of seconds between <parameter>keepalive</parameter>
+ packets. If this parameter is zero, no keepalive packets will be
+ sent. Keepalive packets, if sent, allow the server to tell whether
+ a client is still present and responding.</para>
+
+ <para>Keepalives should, in general, not be needed if the socket
+ being used has the SO_KEEPALIVE attribute set on it (see <link
+ linkend="SOCKETOPTIONS"><parameter>socket options</parameter></link>).
+ Basically you should only use this option if you strike difficulties.</para>
+
+ <para>Default: <command>keepalive = 300</command></para>
+ <para>Example: <command>keepalive = 600</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="KERNELOPLOCKS">kernel oplocks (G)</term>
+ <listitem><para>For UNIXes that support kernel based <link
+ linkend="OPLOCKS"><parameter>oplocks</parameter></link>
+ (currently only IRIX and the Linux 2.4 kernel), this parameter
+ allows the use of them to be turned on or off.</para>
+
+ <para>Kernel oplocks support allows Samba <parameter>oplocks
+ </parameter> to be broken whenever a local UNIX process or NFS operation
+ accesses a file that <ulink url="smbd.8.html"><command>smbd(8)</command>
+ </ulink> has oplocked. This allows complete data consistency between
+ SMB/CIFS, NFS and local file access (and is a <emphasis>very</emphasis>
+ cool feature :-).</para>
+
+ <para>This parameter defaults to <constant>on</constant>, but is translated
+ to a no-op on systems that no not have the necessary kernel support.
+ You should never need to touch this parameter.</para>
+
+ <para>See also the <link linkend="OPLOCKS"><parameter>oplocks</parameter>
+ </link> and <link linkend="LEVEL2OPLOCKS"><parameter>level2 oplocks
+ </parameter></link> parameters.</para>
+
+ <para>Default: <command>kernel oplocks = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LANMANAUTH">lanman auth (G)</term>
+ <listitem><para>This parameter determines whether or not <ulink url="smbd.8.html">smbd</ulink> will
+ attempt to authenticate users using the LANMAN password hash.
+ If disabled, only clients which support NT password hashes (e.g. Windows
+ NT/2000 clients, smbclient, etc... but not Windows 95/98 or the MS DOS
+ network client) will be able to connect to the Samba host.</para>
+
+ <para>Default : <command>lanman auth = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LARGEREADWRITE">large readwrite (G)</term>
+ <listitem><para>This parameter determines whether or not <ulink url="smbd.8.html">smbd</ulink>
+ supports the new 64k streaming read and write varient SMB requests introduced
+ with Windows 2000. Note that due to Windows 2000 client redirector bugs
+ this requires Samba to be running on a 64-bit capable operating system such
+ as IRIX, Solaris or a Linux 2.4 kernel. Can improve performance by 10% with
+ Windows 2000 clients. Defaults to off. Not as tested as some other Samba
+ code paths.
+ </para>
+
+ <para>Default : <command>large readwrite = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPADMINDN">ldap admin dn (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+ <para>
+ The <parameter>ldap admin dn</parameter> defines the Distinguished
+ Name (DN) name used by Samba to contact the <link linkend="LDAPSERVER">ldap
+ server</link> when retreiving user account information. The <parameter>ldap
+ admin dn</parameter> is used in conjunction with the admin dn password
+ stored in the <filename>private/secrets.tdb</filename> file. See the
+ <ulink url="smbpasswd.8.html"><command>smbpasswd(8)</command></ulink> man
+ page for more information on how to accmplish this.
+ </para>
+
+
+ <para>Default : <emphasis>none</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPFILTER">ldap filter (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+ <para>
+ This parameter specifies the RFC 2254 compliant LDAP search filter.
+ The default is to match the login name with the <constant>uid</constant>
+ attribute for all entries matching the <constant>sambaAccount</constant>
+ objectclass. Note that this filter should only return one entry.
+ </para>
+
+
+ <para>Default : <command>ldap filter = (&(uid=%u)(objectclass=sambaAccount))</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPPORT">ldap port (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+ <para>
+ This option is used to control the tcp port number used to contact
+ the <link linkend="LDAPSERVER"><parameter>ldap server</parameter></link>.
+ The default is to use the stand LDAP port 389.
+ </para>
+
+ <para>Default : <command>ldap port = 389</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPSERVER">ldap server (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+ <para>
+ This parameter should contains the FQDN of the ldap directory
+ server which should be queried to locate user account information.
+ </para>
+
+
+
+ <para>Default : <command>ldap server = localhost</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPSSL">ldap ssl (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+ <para>
+ This option is used to define whether or not Samba should
+ use SSL when connecting to the <link linkend="LDAPSERVER"><parameter>ldap
+ server</parameter></link>. This is <emphasis>NOT</emphasis> related to
+ Samba SSL support which is enabled by specifying the
+ <command>--with-ssl</command> option to the <filename>configure</filename>
+ script (see <link linkend="SSL"><parameter>ssl</parameter></link>).
+ </para>
+
+ <para>
+ The <parameter>ldap ssl</parameter> can be set to one of three values:
+ (a) <command>on</command> - Always use SSL when contacting the
+ <parameter>ldap server</parameter>, (b) <command>off</command> -
+ Never use SSL when querying the directory, or (c) <command>start
+ tls</command> - Use the LDAPv3 StartTLS extended operation
+ (RFC2830) for communicating with the directory server.
+ </para>
+
+
+ <para>Default : <command>ldap ssl = off</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LDAPSUFFIX">ldap suffix (G)</term>
+ <listitem><para>This parameter is only available if Samba has been
+ configure to include the <command>--with-ldapsam</command> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </para>
+
+
+
+ <para>Default : <emphasis>none</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LEVEL2OPLOCKS">level2 oplocks (S)</term>
+ <listitem><para>This parameter controls whether Samba supports
+ level2 (read-only) oplocks on a share.</para>
+
+ <para>Level2, or read-only oplocks allow Windows NT clients
+ that have an oplock on a file to downgrade from a read-write oplock
+ to a read-only oplock once a second client opens the file (instead
+ of releasing all oplocks on a second open, as in traditional,
+ exclusive oplocks). This allows all openers of the file that
+ support level2 oplocks to cache the file for read-ahead only (ie.
+ they may not cache writes or lock requests) and increases performance
+ for many accesses of files that are not commonly written (such as
+ application .EXE files).</para>
+
+ <para>Once one of the clients which have a read-only oplock
+ writes to the file all clients are notified (no reply is needed
+ or waited for) and told to break their oplocks to "none" and
+ delete any read-ahead caches.</para>
+
+ <para>It is recommended that this parameter be turned on
+ to speed access to shared executables.</para>
+
+ <para>For more discussions on level2 oplocks see the CIFS spec.</para>
+
+ <para>Currently, if <link linkend="KERNELOPLOCKS"><parameter>kernel
+ oplocks</parameter></link> are supported then level2 oplocks are
+ not granted (even if this parameter is set to <constant>yes</constant>).
+ Note also, the <link linkend="OPLOCKS"><parameter>oplocks</parameter>
+ </link> parameter must be set to <constant>true</constant> on this share in order for
+ this parameter to have any effect.</para>
+
+ <para>See also the <link linkend="OPLOCKS"><parameter>oplocks</parameter>
+ </link> and <link linkend="OPLOCKS"><parameter>kernel oplocks</parameter>
+ </link> parameters.</para>
+
+ <para>Default: <command>level2 oplocks = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LMANNOUNCE">lm announce (G)</term>
+ <listitem><para>This parameter determines if <ulink url="nmbd.8.html">
+ <command>nmbd(8)</command></ulink> will produce Lanman announce
+ broadcasts that are needed by OS/2 clients in order for them to see
+ the Samba server in their browse list. This parameter can have three
+ values, <constant>true</constant>, <constant>false</constant>, or
+ <constant>auto</constant>. The default is <constant>auto</constant>.
+ If set to <constant>false</constant> Samba will never produce these
+ broadcasts. If set to <constant>true</constant> Samba will produce
+ Lanman announce broadcasts at a frequency set by the parameter
+ <parameter>lm interval</parameter>. If set to <constant>auto</constant>
+ Samba will not send Lanman announce broadcasts by default but will
+ listen for them. If it hears such a broadcast on the wire it will
+ then start sending them at a frequency set by the parameter
+ <parameter>lm interval</parameter>.</para>
+
+ <para>See also <link linkend="LMINTERVAL"><parameter>lm interval
+ </parameter></link>.</para>
+
+ <para>Default: <command>lm announce = auto</command></para>
+ <para>Example: <command>lm announce = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LMINTERVAL">lm interval (G)</term>
+ <listitem><para>If Samba is set to produce Lanman announce
+ broadcasts needed by OS/2 clients (see the <link linkend="LMANNOUNCE">
+ <parameter>lm announce</parameter></link> parameter) then this
+ parameter defines the frequency in seconds with which they will be
+ made. If this is set to zero then no Lanman announcements will be
+ made despite the setting of the <parameter>lm announce</parameter>
+ parameter.</para>
+
+ <para>See also <link linkend="LMANNOUNCE"><parameter>lm
+ announce</parameter></link>.</para>
+
+ <para>Default: <command>lm interval = 60</command></para>
+ <para>Example: <command>lm interval = 120</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOADPRINTERS">load printers (G)</term>
+ <listitem><para>A boolean variable that controls whether all
+ printers in the printcap will be loaded for browsing by default.
+ See the <link linkend="PRINTERSSECT">printers</link> section for
+ more details.</para>
+
+ <para>Default: <command>load printers = yes</command></para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="LOCALMASTER">local master (G)</term>
+ <listitem><para>This option allows <ulink url="nmbd.8.html"><command>
+ nmbd(8)</command></ulink> to try and become a local master browser
+ on a subnet. If set to <constant>false</constant> then <command>
+ nmbd</command> will not attempt to become a local master browser
+ on a subnet and will also lose in all browsing elections. By
+ default this value is set to <constant>true</constant>. Setting this value to <constant>true</constant> doesn't
+ mean that Samba will <emphasis>become</emphasis> the local master
+ browser on a subnet, just that <command>nmbd</command> will <emphasis>
+ participate</emphasis> in elections for local master browser.</para>
+
+ <para>Setting this value to <constant>false</constant> will cause <command>nmbd</command>
+ <emphasis>never</emphasis> to become a local master browser.</para>
+
+ <para>Default: <command>local master = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOCKDIR">lock dir (G)</term>
+ <listitem><para>Synonym for <link linkend="LOCKDIRECTORY"><parameter>
+ lock directory</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOCKDIRECTORY">lock directory (G)</term>
+ <listitem><para>This option specifies the directory where lock
+ files will be placed. The lock files are used to implement the
+ <link linkend="MAXCONNECTIONS"><parameter>max connections</parameter>
+ </link> option.</para>
+
+ <para>Default: <command>lock directory = ${prefix}/var/locks</command></para>
+ <para>Example: <command>lock directory = /var/run/samba/locks</command>
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOCKING">locking (S)</term>
+ <listitem><para>This controls whether or not locking will be
+ performed by the server in response to lock requests from the
+ client.</para>
+
+ <para>If <command>locking = no</command>, all lock and unlock
+ requests will appear to succeed and all lock queries will report
+ that the file in question is available for locking.</para>
+
+ <para>If <command>locking = yes</command>, real locking will be performed
+ by the server.</para>
+
+ <para>This option <emphasis>may</emphasis> be useful for read-only
+ filesystems which <emphasis>may</emphasis> not need locking (such as
+ CDROM drives), although setting this parameter of <constant>no</constant>
+ is not really recommended even in this case.</para>
+
+ <para>Be careful about disabling locking either globally or in a
+ specific service, as lack of locking may result in data corruption.
+ You should never need to set this parameter.</para>
+
+ <para>Default: <command>locking = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOGFILE">log file (G)</term>
+ <listitem><para>This option allows you to override the name
+ of the Samba log file (also known as the debug file).</para>
+
+ <para>This option takes the standard substitutions, allowing
+ you to have separate log files for each user or machine.</para>
+
+ <para>Example: <command>log file = /usr/local/samba/var/log.%m
+ </command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOGLEVEL">log level (G)</term>
+ <listitem><para>The value of the parameter (an integer) allows
+ the debug level (logging level) to be specified in the
+ <filename>smb.conf</filename> file. This is to give greater
+ flexibility in the configuration of the system.</para>
+
+ <para>The default will be the log level specified on
+ the command line or level zero if none was specified.</para>
+
+ <para>Example: <command>log level = 3</command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOGONDRIVE">logon drive (G)</term>
+ <listitem><para>This parameter specifies the local path to
+ which the home directory will be connected (see <link
+ linkend="LOGONHOME"><parameter>logon home</parameter></link>)
+ and is only used by NT Workstations. </para>
+
+ <para>Note that this option is only useful if Samba is set up as a
+ logon server.</para>
+
+ <para>Default: <command>logon drive = z:</command></para>
+ <para>Example: <command>logon drive = h:</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOGONHOME">logon home (G)</term>
+ <listitem><para>This parameter specifies the home directory
+ location when a Win95/98 or NT Workstation logs into a Samba PDC.
+ It allows you to do </para>
+
+ <para><prompt>C:\> </prompt><userinput>NET USE H: /HOME</userinput>
+ </para>
+
+ <para>from a command prompt, for example.</para>
+
+ <para>This option takes the standard substitutions, allowing
+ you to have separate logon scripts for each user or machine.</para>
+
+ <para>This parameter can be used with Win9X workstations to ensure
+ that roaming profiles are stored in a subdirectory of the user's
+ home directory. This is done in the following way:</para>
+
+ <para><command>logon home = \\%N\%U\profile</command></para>
+
+ <para>This tells Samba to return the above string, with
+ substitutions made when a client requests the info, generally
+ in a NetUserGetInfo request. Win9X clients truncate the info to
+ \\server\share when a user does <command>net use /home</command>
+ but use the whole string when dealing with profiles.</para>
+
+ <para>Note that in prior versions of Samba, the <link linkend="LOGONPATH">
+ <parameter>logon path</parameter></link> was returned rather than
+ <parameter>logon home</parameter>. This broke <command>net use
+ /home</command> but allowed profiles outside the home directory.
+ The current implementation is correct, and can be used for
+ profiles if you use the above trick.</para>
+
+ <para>This option is only useful if Samba is set up as a logon
+ server.</para>
+
+ <para>Default: <command>logon home = "\\%N\%U"</command></para>
+ <para>Example: <command>logon home = "\\remote_smb_server\%U"</command>
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="LOGONPATH">logon path (G)</term>
+ <listitem><para>This parameter specifies the home directory
+ where roaming profiles (NTuser.dat etc files for Windows NT) are
+ stored. Contrary to previous versions of these manual pages, it has
+ nothing to do with Win 9X roaming profiles. To find out how to
+ handle roaming profiles for Win 9X system, see the <link linkend="LOGONHOME">
+ <parameter>logon home</parameter></link> parameter.</para>
+
+ <para>This option takes the standard substitutions, allowing you
+ to have separate logon scripts for each user or machine. It also
+ specifies the directory from which the "Application Data",
+ (<filename>desktop</filename>, <filename>start menu</filename>,
+ <filename>network neighborhood</filename>, <filename>programs</filename>
+ and other folders, and their contents, are loaded and displayed on
+ your Windows NT client.</para>
+
+ <para>The share and the path must be readable by the user for
+ the preferences and directories to be loaded onto the Windows NT
+ client. The share must be writeable when the user logs in for the first
+ time, in order that the Windows NT client can create the NTuser.dat
+ and other directories.</para>
+
+ <para>Thereafter, the directories and any of the contents can,
+ if required, be made read-only. It is not advisable that the
+ NTuser.dat file be made read-only - rename it to NTuser.man to
+ achieve the desired effect (a <emphasis>MAN</emphasis>datory
+ profile). </para>
+
+ <para>Windows clients can sometimes maintain a connection to
+ the [homes] share, even though there is no user logged in.
+ Therefore, it is vital that the logon path does not include a
+ reference to the homes share (i.e. setting this parameter to
+ \%N\%U\profile_path will cause problems).</para>
+
+ <para>This option takes the standard substitutions, allowing
+ you to have separate logon scripts for each user or machine.</para>
+
+ <para>Note that this option is only useful if Samba is set up
+ as a logon server.</para>
+
+ <para>Default: <command>logon path = \\%N\%U\profile</command></para>
+ <para>Example: <command>logon path = \\PROFILESERVER\PROFILE\%U</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LOGONSCRIPT">logon script (G)</term>
+ <listitem><para>This parameter specifies the batch file (.bat) or
+ NT command file (.cmd) to be downloaded and run on a machine when
+ a user successfully logs in. The file must contain the DOS
+ style CR/LF line endings. Using a DOS-style editor to create the
+ file is recommended.</para>
+
+ <para>The script must be a relative path to the [netlogon]
+ service. If the [netlogon] service specifies a <link linkend="PATH">
+ <parameter>path</parameter></link> of <filename>/usr/local/samba/netlogon
+ </filename>, and <command>logon script = STARTUP.BAT</command>, then
+ the file that will be downloaded is:</para>
+
+ <para><filename>/usr/local/samba/netlogon/STARTUP.BAT</filename></para>
+
+ <para>The contents of the batch file are entirely your choice. A
+ suggested command would be to add <command>NET TIME \\SERVER /SET
+ /YES</command>, to force every machine to synchronize clocks with
+ the same time server. Another use would be to add <command>NET USE
+ U: \\SERVER\UTILS</command> for commonly used utilities, or <command>
+ NET USE Q: \\SERVER\ISO9001_QA</command> for example.</para>
+
+ <para>Note that it is particularly important not to allow write
+ access to the [netlogon] share, or to grant users write permission
+ on the batch files in a secure environment, as this would allow
+ the batch files to be arbitrarily modified and security to be
+ breached.</para>
+
+ <para>This option takes the standard substitutions, allowing you
+ to have separate logon scripts for each user or machine.</para>
+
+ <para>This option is only useful if Samba is set up as a logon
+ server.</para>
+
+ <para>Default: <emphasis>no logon script defined</emphasis></para>
+ <para>Example: <command>logon script = scripts\%U.bat</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LPPAUSECOMMAND">lppause command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to stop printing or spooling
+ a specific print job.</para>
+
+ <para>This command should be a program or script which takes
+ a printer name and job number to pause the print job. One way
+ of implementing this is by using job priorities, where jobs
+ having a too low priority won't be sent to the printer.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. A <parameter>%j</parameter> is replaced with
+ the job number (an integer). On HPUX (see <parameter>printing=hpux
+ </parameter>), if the <parameter>-p%p</parameter> option is added
+ to the lpq command, the job will show up with the correct status, i.e.
+ if the job priority is lower than the set fence priority it will
+ have the PAUSED status, whereas if the priority is equal or higher it
+ will have the SPOOLED or PRINTING status.</para>
+
+ <para>Note that it is good practice to include the absolute path
+ in the lppause command as the PATH may not be available to the server.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: Currently no default value is given to
+ this string, unless the value of the <parameter>printing</parameter>
+ parameter is <constant>SYSV</constant>, in which case the default is :</para>
+
+ <para><command>lp -i %p-%j -H hold</command></para>
+
+ <para>or if the value of the <parameter>printing</parameter> parameter
+ is <constant>SOFTQ</constant>, then the default is:</para>
+
+ <para><command>qstat -s -j%j -h</command></para>
+
+ <para>Example for HPUX: <command>lppause command = /usr/bin/lpalt
+ %p-%j -p0</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LPQCACHETIME">lpq cache time (G)</term>
+ <listitem><para>This controls how long lpq info will be cached
+ for to prevent the <command>lpq</command> command being called too
+ often. A separate cache is kept for each variation of the <command>
+ lpq</command> command used by the system, so if you use different
+ <command>lpq</command> commands for different users then they won't
+ share cache information.</para>
+
+ <para>The cache files are stored in <filename>/tmp/lpq.xxxx</filename>
+ where xxxx is a hash of the <command>lpq</command> command in use.</para>
+
+ <para>The default is 10 seconds, meaning that the cached results
+ of a previous identical <command>lpq</command> command will be used
+ if the cached data is less than 10 seconds old. A large value may
+ be advisable if your <command>lpq</command> command is very slow.</para>
+
+ <para>A value of 0 will disable caching completely.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: <command>lpq cache time = 10</command></para>
+ <para>Example: <command>lpq cache time = 30</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LPQCOMMAND">lpq command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to obtain <command>lpq
+ </command>-style printer status information.</para>
+
+ <para>This command should be a program or script which
+ takes a printer name as its only parameter and outputs printer
+ status information.</para>
+
+ <para>Currently eight styles of printer status information
+ are supported; BSD, AIX, LPRNG, PLP, SYSV, HPUX, QNX and SOFTQ.
+ This covers most UNIX systems. You control which type is expected
+ using the <parameter>printing =</parameter> option.</para>
+
+ <para>Some clients (notably Windows for Workgroups) may not
+ correctly send the connection number for the printer they are
+ requesting status information about. To get around this, the
+ server reports on the first printer service connected to by the
+ client. This only happens if the connection number sent is invalid.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the
+ command.</para>
+
+ <para>Note that it is good practice to include the absolute path
+ in the <parameter>lpq command</parameter> as the <envar>$PATH
+ </envar> may not be available to the server.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: <emphasis>depends on the setting of <parameter>
+ printing</parameter></emphasis></para>
+
+ <para>Example: <command>lpq command = /usr/bin/lpq -P%p</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LPRESUMECOMMAND">lpresume command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to restart or continue
+ printing or spooling a specific print job.</para>
+
+ <para>This command should be a program or script which takes
+ a printer name and job number to resume the print job. See
+ also the <link linkend="LPPAUSECOMMAND"><parameter>lppause command
+ </parameter></link> parameter.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. A <parameter>%j</parameter> is replaced with
+ the job number (an integer).</para>
+
+ <para>Note that it is good practice to include the absolute path
+ in the <parameter>lpresume command</parameter> as the PATH may not
+ be available to the server.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: Currently no default value is given
+ to this string, unless the value of the <parameter>printing</parameter>
+ parameter is <constant>SYSV</constant>, in which case the default is :</para>
+
+ <para><command>lp -i %p-%j -H resume</command></para>
+
+ <para>or if the value of the <parameter>printing</parameter> parameter
+ is <constant>SOFTQ</constant>, then the default is:</para>
+
+ <para><command>qstat -s -j%j -r</command></para>
+
+ <para>Example for HPUX: <command>lpresume command = /usr/bin/lpalt
+ %p-%j -p2</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="LPRMCOMMAND">lprm command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to delete a print job.</para>
+
+ <para>This command should be a program or script which takes
+ a printer name and job number, and deletes the print job.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. A <parameter>%j</parameter> is replaced with
+ the job number (an integer).</para>
+
+ <para>Note that it is good practice to include the absolute
+ path in the <parameter>lprm command</parameter> as the PATH may not be
+ available to the server.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: <emphasis>depends on the setting of <parameter>printing
+ </parameter></emphasis></para>
+
+ <para>Example 1: <command>lprm command = /usr/bin/lprm -P%p %j
+ </command></para>
+ <para>Example 2: <command>lprm command = /usr/bin/cancel %p-%j
+ </command></para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MACHINEPASSWORDTIMEOUT">machine password timeout (G)</term>
+ <listitem><para>If a Samba server is a member of a Windows
+ NT Domain (see the <link linkend="SECURITYEQUALSDOMAIN">security = domain</link>)
+ parameter) then periodically a running <ulink url="smbd.8.html">
+ smbd(8)</ulink> process will try and change the MACHINE ACCOUNT
+ PASSWORD stored in the TDB called <filename>private/secrets.tdb
+ </filename>. This parameter specifies how often this password
+ will be changed, in seconds. The default is one week (expressed in
+ seconds), the same as a Windows NT Domain member server.</para>
+
+ <para>See also <ulink url="smbpasswd.8.html"><command>smbpasswd(8)
+ </command></ulink>, and the <link linkend="SECURITYEQUALSDOMAIN">
+ security = domain</link>) parameter.</para>
+
+ <para>Default: <command>machine password timeout = 604800</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MAGICOUTPUT">magic output (S)</term>
+ <listitem><para>This parameter specifies the name of a file
+ which will contain output created by a magic script (see the
+ <link linkend="MAGICSCRIPT"><parameter>magic script</parameter></link>
+ parameter below).</para>
+
+ <para>Warning: If two clients use the same <parameter>magic script
+ </parameter> in the same directory the output file content
+ is undefined.</para>
+
+ <para>Default: <command>magic output = &lt;magic script name&gt;.out
+ </command></para>
+
+ <para>Example: <command>magic output = myfile.txt</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAGICSCRIPT">magic script (S)</term>
+ <listitem><para>This parameter specifies the name of a file which,
+ if opened, will be executed by the server when the file is closed.
+ This allows a UNIX script to be sent to the Samba host and
+ executed on behalf of the connected user.</para>
+
+ <para>Scripts executed in this way will be deleted upon
+ completion assuming that the user has the appropriate level
+ of privilege and the file permissions allow the deletion.</para>
+
+ <para>If the script generates output, output will be sent to
+ the file specified by the <link linkend="MAGICOUTPUT"><parameter>
+ magic output</parameter></link> parameter (see above).</para>
+
+ <para>Note that some shells are unable to interpret scripts
+ containing CR/LF instead of CR as
+ the end-of-line marker. Magic scripts must be executable
+ <emphasis>as is</emphasis> on the host, which for some hosts and
+ some shells will require filtering at the DOS end.</para>
+
+ <para>Magic scripts are <emphasis>EXPERIMENTAL</emphasis> and
+ should <emphasis>NOT</emphasis> be relied upon.</para>
+
+ <para>Default: <emphasis>None. Magic scripts disabled.</emphasis></para>
+ <para>Example: <command>magic script = user.csh</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MANGLECASE">mangle case (S)</term>
+ <listitem><para>See the section on <link linkend="NAMEMANGLINGSECT">
+ NAME MANGLING</link></para>
+
+ <para>Default: <command>mangle case = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MANGLEDMAP">mangled map (S)</term>
+ <listitem><para>This is for those who want to directly map UNIX
+ file names which cannot be represented on Windows/DOS. The mangling
+ of names is not always what is needed. In particular you may have
+ documents with file extensions that differ between DOS and UNIX.
+ For example, under UNIX it is common to use <filename>.html</filename>
+ for HTML files, whereas under Windows/DOS <filename>.htm</filename>
+ is more commonly used.</para>
+
+ <para>So to map <filename>html</filename> to <filename>htm</filename>
+ you would use:</para>
+
+ <para><command>mangled map = (*.html *.htm)</command></para>
+
+ <para>One very useful case is to remove the annoying <filename>;1
+ </filename> off the ends of filenames on some CDROMs (only visible
+ under some UNIXes). To do this use a map of (*;1 *;).</para>
+
+ <para>Default: <emphasis>no mangled map</emphasis></para>
+ <para>Example: <command>mangled map = (*;1 *;)</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MANGLEDNAMES">mangled names (S)</term>
+ <listitem><para>This controls whether non-DOS names under UNIX
+ should be mapped to DOS-compatible names ("mangled") and made visible,
+ or whether non-DOS names should simply be ignored.</para>
+
+ <para>See the section on <link linkend="NAMEMANGLINGSECT">
+ NAME MANGLING</link> for details on how to control the mangling process.</para>
+
+ <para>If mangling is used then the mangling algorithm is as follows:</para>
+
+ <itemizedlist>
+ <listitem><para>The first (up to) five alphanumeric characters
+ before the rightmost dot of the filename are preserved, forced
+ to upper case, and appear as the first (up to) five characters
+ of the mangled name.</para></listitem>
+
+ <listitem><para>A tilde "~" is appended to the first part of the mangled
+ name, followed by a two-character unique sequence, based on the
+ original root name (i.e., the original filename minus its final
+ extension). The final extension is included in the hash calculation
+ only if it contains any upper case characters or is longer than three
+ characters.</para>
+
+ <para>Note that the character to use may be specified using
+ the <link linkend="MANGLINGCHAR"><parameter>mangling char</parameter>
+ </link> option, if you don't like '~'.</para></listitem>
+
+ <listitem><para>The first three alphanumeric characters of the final
+ extension are preserved, forced to upper case and appear as the
+ extension of the mangled name. The final extension is defined as that
+ part of the original filename after the rightmost dot. If there are no
+ dots in the filename, the mangled name will have no extension (except
+ in the case of "hidden files" - see below).</para></listitem>
+
+ <listitem><para>Files whose UNIX name begins with a dot will be
+ presented as DOS hidden files. The mangled name will be created as
+ for other filenames, but with the leading dot removed and "___" as
+ its extension regardless of actual original extension (that's three
+ underscores).</para></listitem>
+ </itemizedlist>
+
+ <para>The two-digit hash value consists of upper case
+ alphanumeric characters.</para>
+
+ <para>This algorithm can cause name collisions only if files
+ in a directory share the same first five alphanumeric characters.
+ The probability of such a clash is 1/1300.</para>
+
+ <para>The name mangling (if enabled) allows a file to be
+ copied between UNIX directories from Windows/DOS while retaining
+ the long UNIX filename. UNIX files can be renamed to a new extension
+ from Windows/DOS and will retain the same basename. Mangled names
+ do not change between sessions.</para>
+
+ <para>Default: <command>mangled names = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MANGLEDSTACK">mangled stack (G)</term>
+ <listitem><para>This parameter controls the number of mangled names
+ that should be cached in the Samba server <ulink url="smbd.8.html">
+ smbd(8)</ulink>.</para>
+
+ <para>This stack is a list of recently mangled base names
+ (extensions are only maintained if they are longer than 3 characters
+ or contains upper case characters).</para>
+
+ <para>The larger this value, the more likely it is that mangled
+ names can be successfully converted to correct long UNIX names.
+ However, large stack sizes will slow most directory accesses. Smaller
+ stacks save memory in the server (each stack element costs 256 bytes).
+ </para>
+
+ <para>It is not possible to absolutely guarantee correct long
+ filenames, so be prepared for some surprises!</para>
+
+ <para>Default: <command>mangled stack = 50</command></para>
+ <para>Example: <command>mangled stack = 100</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MANGLINGCHAR">mangling char (S)</term>
+ <listitem><para>This controls what character is used as
+ the <emphasis>magic</emphasis> character in <link
+ linkend="NAMEMANGLINGSECT">name mangling</link>. The default is a '~'
+ but this may interfere with some software. Use this option to set
+ it to whatever you prefer.</para>
+
+ <para>Default: <command>mangling char = ~</command></para>
+ <para>Example: <command>mangling char = ^</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MAPARCHIVE">map archive (S)</term>
+ <listitem><para>This controls whether the DOS archive attribute
+ should be mapped to the UNIX owner execute bit. The DOS archive bit
+ is set when a file has been modified since its last backup. One
+ motivation for this option it to keep Samba/your PC from making
+ any file it touches from becoming executable under UNIX. This can
+ be quite annoying for shared source code, documents, etc...</para>
+
+ <para>Note that this requires the <parameter>create mask</parameter>
+ parameter to be set such that owner execute bit is not masked out
+ (i.e. it must include 100). See the parameter <link linkend="CREATEMASK">
+ <parameter>create mask</parameter></link> for details.</para>
+
+ <para>Default: <command>map archive = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAPHIDDEN">map hidden (S)</term>
+ <listitem><para>This controls whether DOS style hidden files
+ should be mapped to the UNIX world execute bit.</para>
+
+ <para>Note that this requires the <parameter>create mask</parameter>
+ to be set such that the world execute bit is not masked out (i.e.
+ it must include 001). See the parameter <link linkend="CREATEMASK">
+ <parameter>create mask</parameter></link> for details.</para>
+
+ <para>Default: <command>map hidden = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MAPSYSTEM">map system (S)</term>
+ <listitem><para>This controls whether DOS style system files
+ should be mapped to the UNIX group execute bit.</para>
+
+ <para>Note that this requires the <parameter>create mask</parameter>
+ to be set such that the group execute bit is not masked out (i.e.
+ it must include 010). See the parameter <link linkend="CREATEMASK">
+ <parameter>create mask</parameter></link> for details.</para>
+
+ <para>Default: <command>map system = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MAPTOGUEST">map to guest (G)</term>
+ <listitem><para>This parameter is only useful in <link linkend="SECURITY">
+ security</link> modes other than <parameter>security = share</parameter>
+ - i.e. <constant>user</constant>, <constant>server</constant>,
+ and <constant>domain</constant>.</para>
+
+ <para>This parameter can take three different values, which tell
+ <ulink url="smbd.8.html">smbd(8)</ulink> what to do with user
+ login requests that don't match a valid UNIX user in some way.</para>
+
+ <para>The three settings are :</para>
+
+ <itemizedlist>
+ <listitem><para><constant>Never</constant> - Means user login
+ requests with an invalid password are rejected. This is the
+ default.</para></listitem>
+
+ <listitem><para><constant>Bad User</constant> - Means user
+ logins with an invalid password are rejected, unless the username
+ does not exist, in which case it is treated as a guest login and
+ mapped into the <link linkend="GUESTACCOUNT"><parameter>
+ guest account</parameter></link>.</para></listitem>
+
+ <listitem><para><constant>Bad Password</constant> - Means user logins
+ with an invalid password are treated as a guest login and mapped
+ into the <link linkend="GUESTACCOUNT">guest account</link>. Note that
+ this can cause problems as it means that any user incorrectly typing
+ their password will be silently logged on as "guest" - and
+ will not know the reason they cannot access files they think
+ they should - there will have been no message given to them
+ that they got their password wrong. Helpdesk services will
+ <emphasis>hate</emphasis> you if you set the <parameter>map to
+ guest</parameter> parameter this way :-).</para></listitem>
+ </itemizedlist>
+
+ <para>Note that this parameter is needed to set up "Guest"
+ share services when using <parameter>security</parameter> modes other than
+ share. This is because in these modes the name of the resource being
+ requested is <emphasis>not</emphasis> sent to the server until after
+ the server has successfully authenticated the client so the server
+ cannot make authentication decisions at the correct time (connection
+ to the share) for "Guest" shares.</para>
+
+ <para>For people familiar with the older Samba releases, this
+ parameter maps to the old compile-time setting of the <constant>
+ GUEST_SESSSETUP</constant> value in local.h.</para>
+
+ <para>Default: <command>map to guest = Never</command></para>
+ <para>Example: <command>map to guest = Bad User</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXCONNECTIONS">max connections (S)</term>
+ <listitem><para>This option allows the number of simultaneous
+ connections to a service to be limited. If <parameter>max connections
+ </parameter> is greater than 0 then connections will be refused if
+ this number of connections to the service are already open. A value
+ of zero mean an unlimited number of connections may be made.</para>
+
+ <para>Record lock files are used to implement this feature. The
+ lock files will be stored in the directory specified by the <link
+ linkend="LOCKDIRECTORY"><parameter>lock directory</parameter></link>
+ option.</para>
+
+ <para>Default: <command>max connections = 0</command></para>
+ <para>Example: <command>max connections = 10</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXDISKSIZE">max disk size (G)</term>
+ <listitem><para>This option allows you to put an upper limit
+ on the apparent size of disks. If you set this option to 100
+ then all shares will appear to be not larger than 100 MB in
+ size.</para>
+
+ <para>Note that this option does not limit the amount of
+ data you can put on the disk. In the above case you could still
+ store much more than 100 MB on the disk, but if a client ever asks
+ for the amount of free disk space or the total disk size then the
+ result will be bounded by the amount specified in <parameter>max
+ disk size</parameter>.</para>
+
+ <para>This option is primarily useful to work around bugs
+ in some pieces of software that can't handle very large disks,
+ particularly disks over 1GB in size.</para>
+
+ <para>A <parameter>max disk size</parameter> of 0 means no limit.</para>
+
+ <para>Default: <command>max disk size = 0</command></para>
+ <para>Example: <command>max disk size = 1000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXLOGSIZE">max log size (G)</term>
+ <listitem><para>This option (an integer in kilobytes) specifies
+ the max size the log file should grow to. Samba periodically checks
+ the size and if it is exceeded it will rename the file, adding
+ a <filename>.old</filename> extension.</para>
+
+ <para>A size of 0 means no limit.</para>
+
+ <para>Default: <command>max log size = 5000</command></para>
+ <para>Example: <command>max log size = 1000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXMUX">max mux (G)</term>
+ <listitem><para>This option controls the maximum number of
+ outstanding simultaneous SMB operations that Samba tells the client
+ it will allow. You should never need to set this parameter.</para>
+
+ <para>Default: <command>max mux = 50</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXOPENFILES">max open files (G)</term>
+ <listitem><para>This parameter limits the maximum number of
+ open files that one <ulink url="smbd.8.html">smbd(8)</ulink> file
+ serving process may have open for a client at any one time. The
+ default for this parameter is set very high (10,000) as Samba uses
+ only one bit per unopened file.</para>
+
+ <para>The limit of the number of open files is usually set
+ by the UNIX per-process file descriptor limit rather than
+ this parameter so you should never need to touch this parameter.</para>
+
+ <para>Default: <command>max open files = 10000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXPRINTJOBS">max print jobs (S)</term>
+ <listitem><para>This parameter limits the maximum number of
+ jobs allowable in a Samba printer queue at any given moment.
+ If this number is exceeded, <ulink url="smbd.8.html"><command>
+ smbd(8)</command></ulink> will remote "Out of Space" to the client.
+ See all <link linkend="TOTALPRINTJOBS"><parameter>total
+ print jobs</parameter></link>.
+ </para>
+
+ <para>Default: <command>max print jobs = 1000</command></para>
+ <para>Example: <command>max print jobs = 5000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="MAXPROTOCOL">max protocol (G)</term>
+ <listitem><para>The value of the parameter (a string) is the highest
+ protocol level that will be supported by the server.</para>
+
+ <para>Possible values are :</para>
+ <itemizedlist>
+ <listitem><para><constant>CORE</constant>: Earliest version. No
+ concept of user names.</para></listitem>
+
+ <listitem><para><constant>COREPLUS</constant>: Slight improvements on
+ CORE for efficiency.</para></listitem>
+
+ <listitem><para><constant>LANMAN1</constant>: First <emphasis>
+ modern</emphasis> version of the protocol. Long filename
+ support.</para></listitem>
+
+ <listitem><para><constant>LANMAN2</constant>: Updates to Lanman1 protocol.
+ </para></listitem>
+
+ <listitem><para><constant>NT1</constant>: Current up to date version of
+ the protocol. Used by Windows NT. Known as CIFS.</para></listitem>
+ </itemizedlist>
+
+ <para>Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.</para>
+
+ <para>See also <link linkend="MINPROTOCOL"><parameter>min
+ protocol</parameter></link></para>
+
+ <para>Default: <command>max protocol = NT1</command></para>
+ <para>Example: <command>max protocol = LANMAN1</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXSMBDPROCESSES">max smbd processes (G)</term>
+ <listitem><para>This parameter limits the maximum number of
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>
+ processes concurrently running on a system and is intended
+ as a stopgap to prevent degrading service to clients in the event
+ that the server has insufficient resources to handle more than this
+ number of connections. Remember that under normal operating
+ conditions, each user will have an <ulink url="smbd.8.html">smbd</ulink> associated with him or her
+ to handle connections to all shares from a given host.
+ </para>
+
+ <para>Default: <command>max smbd processes = 0</command> ## no limit</para>
+ <para>Example: <command>max smbd processes = 1000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXTTL">max ttl (G)</term>
+ <listitem><para>This option tells <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ what the default 'time to live' of NetBIOS names should be (in seconds)
+ when <command>nmbd</command> is requesting a name using either a
+ broadcast packet or from a WINS server. You should never need to
+ change this parameter. The default is 3 days.</para>
+
+ <para>Default: <command>max ttl = 259200</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXWINSTTL">max wins ttl (G)</term>
+ <listitem><para>This option tells <ulink url="nmbd.8.html">nmbd(8)
+ </ulink> when acting as a WINS server (<link linkend="WINSSUPPORT">
+ <parameter>wins support = yes</parameter></link>) what the maximum
+ 'time to live' of NetBIOS names that <command>nmbd</command>
+ will grant will be (in seconds). You should never need to change this
+ parameter. The default is 6 days (518400 seconds).</para>
+
+ <para>See also the <link linkend="MINWINSTTL"><parameter>min
+ wins ttl</parameter></link> parameter.</para>
+
+ <para>Default: <command>max wins ttl = 518400</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MAXXMIT">max xmit (G)</term>
+ <listitem><para>This option controls the maximum packet size
+ that will be negotiated by Samba. The default is 65535, which
+ is the maximum. In some cases you may find you get better performance
+ with a smaller value. A value below 2048 is likely to cause problems.
+ </para>
+
+ <para>Default: <command>max xmit = 65535</command></para>
+ <para>Example: <command>max xmit = 8192</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MESSAGECOMMAND">message command (G)</term>
+ <listitem><para>This specifies what command to run when the
+ server receives a WinPopup style message.</para>
+
+ <para>This would normally be a command that would
+ deliver the message somehow. How this is to be done is
+ up to your imagination.</para>
+
+ <para>An example is:</para>
+
+ <para><command>message command = csh -c 'xedit %s;rm %s' &</command>
+ </para>
+
+ <para>This delivers the message using <command>xedit</command>, then
+ removes it afterwards. <emphasis>NOTE THAT IT IS VERY IMPORTANT
+ THAT THIS COMMAND RETURN IMMEDIATELY</emphasis>. That's why I
+ have the '&' on the end. If it doesn't return immediately then
+ your PCs may freeze when sending messages (they should recover
+ after 30 seconds, hopefully).</para>
+
+ <para>All messages are delivered as the global guest user.
+ The command takes the standard substitutions, although <parameter>
+ %u</parameter> won't work (<parameter>%U</parameter> may be better
+ in this case).</para>
+
+ <para>Apart from the standard substitutions, some additional
+ ones apply. In particular:</para>
+
+ <itemizedlist>
+ <listitem><para><parameter>%s</parameter> = the filename containing
+ the message.</para></listitem>
+
+ <listitem><para><parameter>%t</parameter> = the destination that
+ the message was sent to (probably the server name).</para></listitem>
+
+ <listitem><para><parameter>%f</parameter> = who the message
+ is from.</para></listitem>
+ </itemizedlist>
+
+ <para>You could make this command send mail, or whatever else
+ takes your fancy. Please let us know of any really interesting
+ ideas you have.</para>
+
+
+ <para>Here's a way of sending the messages as mail to root:</para>
+
+ <para><command>message command = /bin/mail -s 'message from %f on
+ %m' root &lt; %s; rm %s</command></para>
+
+ <para>If you don't have a message command then the message
+ won't be delivered and Samba will tell the sender there was
+ an error. Unfortunately WfWg totally ignores the error code
+ and carries on regardless, saying that the message was delivered.
+ </para>
+
+ <para>If you want to silently delete it then try:</para>
+
+ <para><command>message command = rm %s</command></para>
+
+ <para>Default: <emphasis>no message command</emphasis></para>
+ <para>Example: <command>message command = csh -c 'xedit %s;
+ rm %s' &</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MINPASSWDLENGTH">min passwd length (G)</term>
+ <listitem><para>Synonym for <link linkend="MINPASSWORDLENGTH">
+ <parameter>min password length</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MINPASSWORDLENGTH">min password length (G)</term>
+ <listitem><para>This option sets the minimum length in characters
+ of a plaintext password that <command>smbd</command> will accept when performing
+ UNIX password changing.</para>
+
+ <para>See also <link linkend="UNIXPASSWORDSYNC"><parameter>unix
+ password sync</parameter></link>, <link linkend="PASSWDPROGRAM">
+ <parameter>passwd program</parameter></link> and <link
+ linkend="PASSWDCHATDEBUG"><parameter>passwd chat debug</parameter>
+ </link>.</para>
+
+ <para>Default: <command>min password length = 5</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="MINPRINTSPACE">min print space (S)</term>
+ <listitem><para>This sets the minimum amount of free disk
+ space that must be available before a user will be able to spool
+ a print job. It is specified in kilobytes. The default is 0, which
+ means a user can always spool a print job.</para>
+
+ <para>See also the <link linkend="PRINTING"><parameter>printing
+ </parameter></link> parameter.</para>
+
+ <para>Default: <command>min print space = 0</command></para>
+ <para>Example: <command>min print space = 2000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MINPROTOCOL">min protocol (G)</term>
+ <listitem><para>The value of the parameter (a string) is the
+ lowest SMB protocol dialect than Samba will support. Please refer
+ to the <link linkend="MAXPROTOCOL"><parameter>max protocol</parameter></link>
+ parameter for a list of valid protocol names and a brief description
+ of each. You may also wish to refer to the C source code in
+ <filename>source/smbd/negprot.c</filename> for a listing of known protocol
+ dialects supported by clients.</para>
+
+ <para>If you are viewing this parameter as a security measure, you should
+ also refer to the <link linkend="LANMANAUTH"><parameter>lanman
+ auth</parameter></link> parameter. Otherwise, you should never need
+ to change this parameter.</para>
+
+ <para>Default : <command>min protocol = CORE</command></para>
+ <para>Example : <command>min protocol = NT1</command> # disable DOS
+ clients</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MINWINSTTL">min wins ttl (G)</term>
+ <listitem><para>This option tells <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ when acting as a WINS server (<link linkend="WINSSUPPORT"><parameter>
+ wins support = yes</parameter></link>) what the minimum 'time to live'
+ of NetBIOS names that <command>nmbd</command> will grant will be (in
+ seconds). You should never need to change this parameter. The default
+ is 6 hours (21600 seconds).</para>
+
+ <para>Default: <command>min wins ttl = 21600</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="MSDFSROOT">msdfs root (S)</term>
+ <listitem><para>This boolean parameter is only available if
+ Samba is configured and compiled with the <command>
+ --with-msdfs</command> option. If set to <constant>yes</constant>,
+ Samba treats the share as a Dfs root and allows clients to browse
+ the distributed file system tree rooted at the share directory.
+ Dfs links are specified in the share directory by symbolic
+ links of the form <filename>msdfs:serverA\shareA,serverB\shareB
+ </filename> and so on. For more information on setting up a Dfs tree
+ on Samba, refer to <ulink url="msdfs_setup.html">msdfs_setup.html
+ </ulink>.</para>
+
+ <para>See also <link linkend="HOSTMSDFS"><parameter>host msdfs
+ </parameter></link></para>
+
+ <para>Default: <command>msdfs root = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="NAMERESOLVEORDER">name resolve order (G)</term>
+ <listitem><para>This option is used by the programs in the Samba
+ suite to determine what naming services to use and in what order
+ to resolve host names to IP addresses. The option takes a space
+ separated string of name resolution options.</para>
+
+ <para>The options are :"lmhosts", "host", "wins" and "bcast". They
+ cause names to be resolved as follows :</para>
+
+ <itemizedlist>
+ <listitem><para><constant>lmhosts</constant> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <ulink
+ url="lmhosts.5.html">lmhosts(5)</ulink> for details) then
+ any name type matches for lookup.</para></listitem>
+
+ <listitem><para><constant>host</constant> : Do a standard host
+ name to IP address resolution, using the system <filename>/etc/hosts
+ </filename>, NIS, or DNS lookups. This method of name resolution
+ is operating system depended for instance on IRIX or Solaris this
+ may be controlled by the <filename>/etc/nsswitch.conf</filename>
+ file. Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</para></listitem>
+
+ <listitem><para><constant>wins</constant> : Query a name with
+ the IP address listed in the <link linkend="WINSSERVER"><parameter>
+ wins server</parameter></link> parameter. If no WINS server has
+ been specified this method will be ignored.</para></listitem>
+
+ <listitem><para><constant>bcast</constant> : Do a broadcast on
+ each of the known local interfaces listed in the <link
+ linkend="INTERFACES"><parameter>interfaces</parameter></link>
+ parameter. This is the least reliable of the name resolution
+ methods as it depends on the target host being on a locally
+ connected subnet.</para></listitem>
+ </itemizedlist>
+
+ <para>Default: <command>name resolve order = lmhosts host wins bcast
+ </command></para>
+ <para>Example: <command>name resolve order = lmhosts bcast host
+ </command></para>
+
+ <para>This will cause the local lmhosts file to be examined
+ first, followed by a broadcast attempt, followed by a normal
+ system hostname lookup.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="NETBIOSALIASES">netbios aliases (G)</term>
+ <listitem><para>This is a list of NetBIOS names that <ulink
+ url="nmbd.8.html">nmbd(8)</ulink> will advertise as additional
+ names by which the Samba server is known. This allows one machine
+ to appear in browse lists under multiple names. If a machine is
+ acting as a browse server or logon server none
+ of these names will be advertised as either browse server or logon
+ servers, only the primary name of the machine will be advertised
+ with these capabilities.</para>
+
+ <para>See also <link linkend="NETBIOSNAME"><parameter>netbios
+ name</parameter></link>.</para>
+
+ <para>Default: <emphasis>empty string (no additional names)</emphasis></para>
+ <para>Example: <command>netbios aliases = TEST TEST1 TEST2</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NETBIOSNAME">netbios name (G)</term>
+ <listitem><para>This sets the NetBIOS name by which a Samba
+ server is known. By default it is the same as the first component
+ of the host's DNS name. If a machine is a browse server or
+ logon server this name (or the first component
+ of the hosts DNS name) will be the name that these services are
+ advertised under.</para>
+
+ <para>See also <link linkend="NETBIOSALIASES"><parameter>netbios
+ aliases</parameter></link>.</para>
+
+ <para>Default: <emphasis>machine DNS name</emphasis></para>
+ <para>Example: <command>netbios name = MYNAME</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NETBIOSSCOPE">netbios scope (G)</term>
+ <listitem><para>This sets the NetBIOS scope that Samba will
+ operate under. This should not be set unless every machine
+ on your LAN also sets this value.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="NISHOMEDIR">nis homedir (G)</term>
+ <listitem><para>Get the home share server from a NIS map. For
+ UNIX systems that use an automounter, the user's home directory
+ will often be mounted on a workstation on demand from a remote
+ server. </para>
+
+ <para>When the Samba logon server is not the actual home directory
+ server, but is mounting the home directories via NFS then two
+ network hops would be required to access the users home directory
+ if the logon server told the client to use itself as the SMB server
+ for home directories (one over SMB and one over NFS). This can
+ be very slow.</para>
+
+ <para>This option allows Samba to return the home share as
+ being on a different server to the logon server and as
+ long as a Samba daemon is running on the home directory server,
+ it will be mounted on the Samba client directly from the directory
+ server. When Samba is returning the home share to the client, it
+ will consult the NIS map specified in <link linkend="HOMEDIRMAP">
+ <parameter>homedir map</parameter></link> and return the server
+ listed there.</para>
+
+ <para>Note that for this option to work there must be a working
+ NIS system and the Samba server with this option must also
+ be a logon server.</para>
+
+ <para>Default: <command>nis homedir = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NTACLSUPPORT">nt acl support (S)</term>
+ <listitem><para>This boolean parameter controls whether
+ <ulink url="smbd.8.html">smbd(8)</ulink> will attempt to map
+ UNIX permissions into Windows NT access control lists.
+ This parameter was formally a global parameter in releases
+ prior to 2.2.2.</para>
+
+ <para>Default: <command>nt acl support = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NTPIPESUPPORT">nt pipe support (G)</term>
+ <listitem><para>This boolean parameter controls whether
+ <ulink url="smbd.8.html">smbd(8)</ulink> will allow Windows NT
+ clients to connect to the NT SMB specific <constant>IPC$</constant>
+ pipes. This is a developer debugging option and can be left
+ alone.</para>
+
+ <para>Default: <command>nt pipe support = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NTSMBSUPPORT">nt smb support (G)</term>
+ <listitem><para>This boolean parameter controls whether <ulink
+ url="smbd.8.html">smbd(8)</ulink> will negotiate NT specific SMB
+ support with Windows NT clients. Although this is a developer
+ debugging option and should be left alone, benchmarking has discovered
+ that Windows NT clients give faster performance with this option
+ set to <constant>no</constant>. This is still being investigated.
+ If this option is set to <constant>no</constant> then Samba offers
+ exactly the same SMB calls that versions prior to Samba 2.0 offered.
+ This information may be of use if any users are having problems
+ with NT SMB support.</para>
+
+ <para>You should not need to ever disable this parameter.</para>
+
+ <para>Default: <command>nt smb support = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="NULLPASSWORDS">null passwords (G)</term>
+ <listitem><para>Allow or disallow client access to accounts
+ that have null passwords. </para>
+
+ <para>See also <ulink url="smbpasswd.5.html">smbpasswd (5)</ulink>.</para>
+
+ <para>Default: <command>null passwords = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="OBEYPAMRESTRICTIONS">obey pam restrictions (G)</term>
+ <listitem><para>When Samba 2.2 is configured to enable PAM support
+ (i.e. --with-pam), this parameter will control whether or not Samba
+ should obey PAM's account and session management directives. The
+ default behavior is to use PAM for clear text authentication only
+ and to ignore any account or session management. Note that Samba
+ always ignores PAM for authentication in the case of <link
+ linkend="ENCRYPTPASSWORDS"><parameter>encrypt passwords = yes</parameter>
+ </link>. The reason is that PAM modules cannot support the challenge/response
+ authentication mechanism needed in the presence of SMB password encryption.
+ </para>
+
+ <para>Default: <command>obey pam restrictions = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="ONLYUSER">only user (S)</term>
+ <listitem><para>This is a boolean option that controls whether
+ connections with usernames not in the <parameter>user</parameter>
+ list will be allowed. By default this option is disabled so that a
+ client can supply a username to be used by the server. Enabling
+ this parameter will force the server to only user the login
+ names from the <parameter>user</parameter> list and is only really
+ useful in <link linkend="SECURITYEQUALSSHARE">shave level</link>
+ security.</para>
+
+ <para>Note that this also means Samba won't try to deduce
+ usernames from the service name. This can be annoying for
+ the [homes] section. To get around this you could use <command>user =
+ %S</command> which means your <parameter>user</parameter> list
+ will be just the service name, which for home directories is the
+ name of the user.</para>
+
+ <para>See also the <link linkend="USER"><parameter>user</parameter>
+ </link> parameter.</para>
+
+ <para>Default: <command>only user = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="ONLYGUEST">only guest (S)</term>
+ <listitem><para>A synonym for <link linkend="GUESTONLY"><parameter>
+ guest only</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="OPLOCKBREAKWAITTIME">oplock break wait time (G)</term>
+ <listitem><para>This is a tuning parameter added due to bugs in
+ both Windows 9x and WinNT. If Samba responds to a client too
+ quickly when that client issues an SMB that can cause an oplock
+ break request, then the network client can fail and not respond
+ to the break request. This tuning parameter (which is set in milliseconds)
+ is the amount of time Samba will wait before sending an oplock break
+ request to such (broken) clients.</para>
+
+ <para><emphasis>DO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+ AND UNDERSTOOD THE SAMBA OPLOCK CODE</emphasis>.</para>
+
+ <para>Default: <command>oplock break wait time = 0</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="OPLOCKCONTENTIONLIMIT">oplock contention limit (S)</term>
+ <listitem><para>This is a <emphasis>very</emphasis> advanced
+ <ulink url="smbd.8.html">smbd(8)</ulink> tuning option to
+ improve the efficiency of the granting of oplocks under multiple
+ client contention for the same file.</para>
+
+ <para>In brief it specifies a number, which causes <ulink url="smbd.8.html">smbd</ulink> not to
+ grant an oplock even when requested if the approximate number of
+ clients contending for an oplock on the same file goes over this
+ limit. This causes <command>smbd</command> to behave in a similar
+ way to Windows NT.</para>
+
+ <para><emphasis>DO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+ AND UNDERSTOOD THE SAMBA OPLOCK CODE</emphasis>.</para>
+
+ <para>Default: <command>oplock contention limit = 2</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="OPLOCKS">oplocks (S)</term>
+ <listitem><para>This boolean option tells <command>smbd</command> whether to
+ issue oplocks (opportunistic locks) to file open requests on this
+ share. The oplock code can dramatically (approx. 30% or more) improve
+ the speed of access to files on Samba servers. It allows the clients
+ to aggressively cache files locally and you may want to disable this
+ option for unreliable network environments (it is turned on by
+ default in Windows NT Servers). For more information see the file
+ <filename>Speed.txt</filename> in the Samba <filename>docs/</filename>
+ directory.</para>
+
+ <para>Oplocks may be selectively turned off on certain files with a
+ share. See the <link linkend="VETOOPLOCKFILES"><parameter>
+ veto oplock files</parameter></link> parameter. On some systems
+ oplocks are recognized by the underlying operating system. This
+ allows data synchronization between all access to oplocked files,
+ whether it be via Samba or NFS or a local UNIX process. See the
+ <parameter>kernel oplocks</parameter> parameter for details.</para>
+
+ <para>See also the <link linkend="KERNELOPLOCKS"><parameter>kernel
+ oplocks</parameter></link> and <link linkend="LEVEL2OPLOCKS"><parameter>
+ level2 oplocks</parameter></link> parameters.</para>
+
+ <para>Default: <command>oplocks = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="OSLEVEL">os level (G)</term>
+ <listitem><para>This integer value controls what level Samba
+ advertises itself as for browse elections. The value of this
+ parameter determines whether <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ has a chance of becoming a local master browser for the <parameter>
+ WORKGROUP</parameter> in the local broadcast area.</para>
+
+ <para><emphasis>Note :</emphasis>By default, Samba will win
+ a local master browsing election over all Microsoft operating
+ systems except a Windows NT 4.0/2000 Domain Controller. This
+ means that a misconfigured Samba host can effectively isolate
+ a subnet for browsing purposes. See <filename>BROWSING.txt
+ </filename> in the Samba <filename>docs/</filename> directory
+ for details.</para>
+
+ <para>Default: <command>os level = 20</command></para>
+ <para>Example: <command>os level = 65 </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="OS2DRIVERMAP">os2 driver map (G)</term>
+ <listitem><para>The parameter is used to define the absolute
+ path to a file containing a mapping of Windows NT printer driver
+ names to OS/2 printer driver names. The format is:</para>
+
+ <para>&lt;nt driver name&gt; = &lt;os2 driver
+ name&gt;.&lt;device name&gt;</para>
+
+ <para>For example, a valid entry using the HP LaserJet 5
+ printer driver would appear as <command>HP LaserJet 5L = LASERJET.HP
+ LaserJet 5L</command>.</para>
+
+ <para>The need for the file is due to the printer driver namespace
+ problem described in the <ulink url="printer_driver2.html">Samba
+ Printing HOWTO</ulink>. For more details on OS/2 clients, please
+ refer to the <ulink url="OS2-Client-HOWTO.html">OS2-Client-HOWTO
+ </ulink> containing in the Samba documentation.</para>
+
+ <para>Default: <command>os2 driver map = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PAMPASSWORDCHANGE">pam password change (G)</term>
+ <listitem><para>With the addition of better PAM support in Samba 2.2,
+ this parameter, it is possible to use PAM's password change control
+ flag for Samba. If enabled, then PAM will be used for password
+ changes when requested by an SMB client instead of the program listed in
+ <link linkend="PASSWDPROGRAM"><parameter>passwd program</parameter></link>.
+ It should be possible to enable this without changing your
+ <link linkend="PASSWDCHAT"><parameter>passwd chat</parameter></link>
+ parameter for most setups.
+ </para>
+
+ <para>Default: <command>pam password change = no</command></para>
+
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PANICACTION">panic action (G)</term>
+ <listitem><para>This is a Samba developer option that allows a
+ system command to be called when either <ulink url="smbd.8.html">
+ smbd(8)</ulink> or <ulink url="nmbd.8.html">nmbd(8)</ulink>
+ crashes. This is usually used to draw attention to the fact that
+ a problem occurred.</para>
+
+ <para>Default: <command>panic action = &lt;empty string&gt;</command></para>
+ <para>Example: <command>panic action = "/bin/sleep 90000"</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PASSWDCHAT">passwd chat (G)</term>
+ <listitem><para>This string controls the <emphasis>"chat"</emphasis>
+ conversation that takes places between <ulink
+ url="smbd.8.html">smbd</ulink> and the local password changing
+ program to change the user's password. The string describes a
+ sequence of response-receive pairs that <ulink url="smbd.8.html">
+ smbd(8)</ulink> uses to determine what to send to the
+ <link linkend="PASSWDPROGRAM"><parameter>passwd program</parameter>
+ </link> and what to expect back. If the expected output is not
+ received then the password is not changed.</para>
+
+ <para>This chat sequence is often quite site specific, depending
+ on what local methods are used for password control (such as NIS
+ etc).</para>
+ <para>Note that this parameter only is only used if the <link
+ linkend="UNIXPASSWORDSYNC"><parameter>unix
+ password sync</parameter></link> parameter is set to <constant>yes</constant>. This
+ sequence is then called <emphasis>AS ROOT</emphasis> when the SMB password
+ in the smbpasswd file is being changed, without access to the old
+ password cleartext. This means that root must be able to reset the user's password
+ without knowing the text of the previous password. In the presence of NIS/YP,
+ this means that the <link linkend="PASSWDPROGRAM">passwd program</link> must be
+ executed on the NIS master.
+ </para>
+
+
+ <para>The string can contain the macro <parameter>%n</parameter> which is substituted
+ for the new password. The chat sequence can also contain the standard
+ macros <constant>\n</constant>, <constant>\r</constant>, <constant>
+ \t</constant> and <constant>\s</constant> to give line-feed,
+ carriage-return, tab and space. The chat sequence string can also contain
+ a '*' which matches any sequence of characters.
+ Double quotes can be used to collect strings with spaces
+ in them into a single string.</para>
+
+ <para>If the send string in any part of the chat sequence
+ is a full stop ".", then no string is sent. Similarly,
+ if the expect string is a full stop then no string is expected.</para>
+
+ <para>If the <link linkend="PAMPASSWORDCHANGE"><parameter>pam
+ password change</parameter></link> parameter is set to true, the chat pairs
+ may be matched in any order, and success is determined by the PAM result,
+ not any particular output. The \n macro is ignored for PAM conversions.
+ </para>
+
+ <para>See also <link linkend="UNIXPASSWORDSYNC"><parameter>unix password
+ sync</parameter></link>, <link linkend="PASSWDPROGRAM"><parameter>
+ passwd program</parameter></link> ,<link linkend="PASSWDCHATDEBUG">
+ <parameter>passwd chat debug</parameter></link> and <link linkend="PAMPASSWORDCHANGE">
+ <parameter>pam password change</parameter></link>.</para>
+
+ <para>Default: <command>passwd chat = *new*password* %n\n
+ *new*password* %n\n *changed*</command></para>
+ <para>Example: <command>passwd chat = "*Enter OLD password*" %o\n
+ "*Enter NEW password*" %n\n "*Reenter NEW password*" %n\n "*Password
+ changed*"</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PASSWDCHATDEBUG">passwd chat debug (G)</term>
+ <listitem><para>This boolean specifies if the passwd chat script
+ parameter is run in <emphasis>debug</emphasis> mode. In this mode the
+ strings passed to and received from the passwd chat are printed
+ in the <ulink url="smbd.8.html">smbd(8)</ulink> log with a
+ <link linkend="DEBUGLEVEL"><parameter>debug level</parameter></link>
+ of 100. This is a dangerous option as it will allow plaintext passwords
+ to be seen in the <command>smbd</command> log. It is available to help
+ Samba admins debug their <parameter>passwd chat</parameter> scripts
+ when calling the <parameter>passwd program</parameter> and should
+ be turned off after this has been done. This option has no effect if the
+ <link linkend="PAMPASSWORDCHANGE"><parameter>pam password change</parameter></link>
+ paramter is set. This parameter is off by default.</para>
+
+
+ <para>See also <link linkend="PASSWDCHAT"><parameter>passwd chat</parameter>
+ </link>, <link linkend="PAMPASSWORDCHANGE"><parameter>pam password change</parameter>
+ </link>, <link linkend="PASSWDPROGRAM"><parameter>passwd program</parameter>
+ </link>.</para>
+
+ <para>Default: <command>passwd chat debug = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PASSWDPROGRAM">passwd program (G)</term>
+ <listitem><para>The name of a program that can be used to set
+ UNIX user passwords. Any occurrences of <parameter>%u</parameter>
+ will be replaced with the user name. The user name is checked for
+ existence before calling the password changing program.</para>
+
+ <para>Also note that many passwd programs insist in <emphasis>reasonable
+ </emphasis> passwords, such as a minimum length, or the inclusion
+ of mixed case chars and digits. This can pose a problem as some clients
+ (such as Windows for Workgroups) uppercase the password before sending
+ it.</para>
+
+ <para><emphasis>Note</emphasis> that if the <parameter>unix
+ password sync</parameter> parameter is set to <constant>true
+ </constant> then this program is called <emphasis>AS ROOT</emphasis>
+ before the SMB password in the <ulink url="smbpasswd.5.html">smbpasswd(5)
+ </ulink> file is changed. If this UNIX password change fails, then
+ <command>smbd</command> will fail to change the SMB password also
+ (this is by design).</para>
+
+ <para>If the <parameter>unix password sync</parameter> parameter
+ is set this parameter <emphasis>MUST USE ABSOLUTE PATHS</emphasis>
+ for <emphasis>ALL</emphasis> programs called, and must be examined
+ for security implications. Note that by default <parameter>unix
+ password sync</parameter> is set to <constant>false</constant>.</para>
+
+ <para>See also <link linkend="UNIXPASSWORDSYNC"><parameter>unix
+ password sync</parameter></link>.</para>
+
+ <para>Default: <command>passwd program = /bin/passwd</command></para>
+ <para>Example: <command>passwd program = /sbin/npasswd %u</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PASSWORDLEVEL">password level (G)</term>
+ <listitem><para>Some client/server combinations have difficulty
+ with mixed-case passwords. One offending client is Windows for
+ Workgroups, which for some reason forces passwords to upper
+ case when using the LANMAN1 protocol, but leaves them alone when
+ using COREPLUS! Another problem child is the Windows 95/98
+ family of operating systems. These clients upper case clear
+ text passwords even when NT LM 0.12 selected by the protocol
+ negotiation request/response.</para>
+
+ <para>This parameter defines the maximum number of characters
+ that may be upper case in passwords.</para>
+
+ <para>For example, say the password given was "FRED". If <parameter>
+ password level</parameter> is set to 1, the following combinations
+ would be tried if "FRED" failed:</para>
+
+ <para>"Fred", "fred", "fRed", "frEd","freD"</para>
+
+ <para>If <parameter>password level</parameter> was set to 2,
+ the following combinations would also be tried: </para>
+
+ <para>"FRed", "FrEd", "FreD", "fREd", "fReD", "frED", ..</para>
+
+ <para>And so on.</para>
+
+ <para>The higher value this parameter is set to the more likely
+ it is that a mixed case password will be matched against a single
+ case password. However, you should be aware that use of this
+ parameter reduces security and increases the time taken to
+ process a new connection.</para>
+
+ <para>A value of zero will cause only two attempts to be
+ made - the password as is and the password in all-lower case.</para>
+
+ <para>Default: <command>password level = 0</command></para>
+ <para>Example: <command>password level = 4</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PASSWORDSERVER">password server (G)</term>
+ <listitem><para>By specifying the name of another SMB server (such
+ as a WinNT box) with this option, and using <command>security = domain
+ </command> or <command>security = server</command> you can get Samba
+ to do all its username/password validation via a remote server.</para>
+
+ <para>This option sets the name of the password server to use.
+ It must be a NetBIOS name, so if the machine's NetBIOS name is
+ different from its Internet name then you may have to add its NetBIOS
+ name to the lmhosts file which is stored in the same directory
+ as the <filename>smb.conf</filename> file.</para>
+
+ <para>The name of the password server is looked up using the
+ parameter <link linkend="NAMERESOLVEORDER"><parameter>name
+ resolve order</parameter></link> and so may resolved
+ by any method and order described in that parameter.</para>
+
+ <para>The password server much be a machine capable of using
+ the "LM1.2X002" or the "NT LM 0.12" protocol, and it must be in
+ user level security mode.</para>
+
+ <para><emphasis>NOTE:</emphasis> Using a password server
+ means your UNIX box (running Samba) is only as secure as your
+ password server. <emphasis>DO NOT CHOOSE A PASSWORD SERVER THAT
+ YOU DON'T COMPLETELY TRUST</emphasis>.</para>
+
+ <para>Never point a Samba server at itself for password
+ serving. This will cause a loop and could lock up your Samba
+ server!</para>
+
+ <para>The name of the password server takes the standard
+ substitutions, but probably the only useful one is <parameter>%m
+ </parameter>, which means the Samba server will use the incoming
+ client as the password server. If you use this then you better
+ trust your clients, and you had better restrict them with hosts allow!</para>
+
+ <para>If the <parameter>security</parameter> parameter is set to
+ <constant>domain</constant>, then the list of machines in this
+ option must be a list of Primary or Backup Domain controllers for the
+ Domain or the character '*', as the Samba server is effectively
+ in that domain, and will use cryptographically authenticated RPC calls
+ to authenticate the user logging on. The advantage of using <command>
+ security = domain</command> is that if you list several hosts in the
+ <parameter>password server</parameter> option then <command>smbd
+ </command> will try each in turn till it finds one that responds. This
+ is useful in case your primary server goes down.</para>
+
+ <para>If the <parameter>password server</parameter> option is set
+ to the character '*', then Samba will attempt to auto-locate the
+ Primary or Backup Domain controllers to authenticate against by
+ doing a query for the name <constant>WORKGROUP&lt;1C&gt;</constant>
+ and then contacting each server returned in the list of IP
+ addresses from the name resolution source. </para>
+
+ <para>If the <parameter>security</parameter> parameter is
+ set to <constant>server</constant>, then there are different
+ restrictions that <command>security = domain</command> doesn't
+ suffer from:</para>
+
+ <itemizedlist>
+ <listitem><para>You may list several password servers in
+ the <parameter>password server</parameter> parameter, however if an
+ <command>smbd</command> makes a connection to a password server,
+ and then the password server fails, no more users will be able
+ to be authenticated from this <command>smbd</command>. This is a
+ restriction of the SMB/CIFS protocol when in <command>security = server
+ </command> mode and cannot be fixed in Samba.</para></listitem>
+
+ <listitem><para>If you are using a Windows NT server as your
+ password server then you will have to ensure that your users
+ are able to login from the Samba server, as when in <command>
+ security = server</command> mode the network logon will appear to
+ come from there rather than from the users workstation.</para></listitem>
+ </itemizedlist>
+
+ <para>See also the <link linkend="SECURITY"><parameter>security
+ </parameter></link> parameter.</para>
+
+ <para>Default: <command>password server = &lt;empty string&gt;</command>
+ </para>
+ <para>Example: <command>password server = NT-PDC, NT-BDC1, NT-BDC2
+ </command></para>
+ <para>Example: <command>password server = *</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PATH">path (S)</term>
+ <listitem><para>This parameter specifies a directory to which
+ the user of the service is to be given access. In the case of
+ printable services, this is where print data will spool prior to
+ being submitted to the host for printing.</para>
+
+ <para>For a printable service offering guest access, the service
+ should be readonly and the path should be world-writeable and
+ have the sticky bit set. This is not mandatory of course, but
+ you probably won't get the results you expect if you do
+ otherwise.</para>
+
+ <para>Any occurrences of <parameter>%u</parameter> in the path
+ will be replaced with the UNIX username that the client is using
+ on this connection. Any occurrences of <parameter>%m</parameter>
+ will be replaced by the NetBIOS name of the machine they are
+ connecting from. These replacements are very useful for setting
+ up pseudo home directories for users.</para>
+
+ <para>Note that this path will be based on <link linkend="ROOTDIR">
+ <parameter>root dir</parameter></link> if one was specified.</para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ <para>Example: <command>path = /home/fred</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="POSIXLOCKING">posix locking (S)</term>
+ <listitem><para>The <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>
+ daemon maintains an database of file locks obtained by SMB clients.
+ The default behavior is to map this internal database to POSIX
+ locks. This means that file locks obtained by SMB clients are
+ consistent with those seen by POSIX compliant applications accessing
+ the files via a non-SMB method (e.g. NFS or local file access).
+ You should never need to disable this parameter.</para>
+
+ <para>Default: <command>posix locking = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="POSTEXEC">postexec (S)</term>
+ <listitem><para>This option specifies a command to be run
+ whenever the service is disconnected. It takes the usual
+ substitutions. The command may be run as the root on some
+ systems.</para>
+
+ <para>An interesting example may be to unmount server
+ resources:</para>
+
+ <para><command>postexec = /etc/umount /cdrom</command></para>
+
+ <para>See also <link linkend="PREEXEC"><parameter>preexec</parameter>
+ </link>.</para>
+
+ <para>Default: <emphasis>none (no command executed)</emphasis>
+ </para>
+
+ <para>Example: <command>postexec = echo \"%u disconnected from %S
+ from %m (%I)\" &gt;&gt; /tmp/log</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="POSTSCRIPT">postscript (S)</term>
+ <listitem><para>This parameter forces a printer to interpret
+ the print files as PostScript. This is done by adding a <constant>%!
+ </constant> to the start of print output.</para>
+
+ <para>This is most useful when you have lots of PCs that persist
+ in putting a control-D at the start of print jobs, which then
+ confuses your printer.</para>
+
+ <para>Default: <command>postscript = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PREEXEC">preexec (S)</term>
+ <listitem><para>This option specifies a command to be run whenever
+ the service is connected to. It takes the usual substitutions.</para>
+
+ <para>An interesting example is to send the users a welcome
+ message every time they log in. Maybe a message of the day? Here
+ is an example:</para>
+
+ <para><command>preexec = csh -c 'echo \"Welcome to %S!\" |
+ /usr/local/samba/bin/smbclient -M %m -I %I' & </command></para>
+
+ <para>Of course, this could get annoying after a while :-)</para>
+
+ <para>See also <link linkend="PREEXECCLOSE"><parameter>preexec close
+ </parameter</link> and <link linkend="POSTEXEC"><parameter>postexec
+ </parameter></link>.</para>
+
+ <para>Default: <emphasis>none (no command executed)</emphasis></para>
+ <para>Example: <command>preexec = echo \"%u connected to %S from %m
+ (%I)\" &gt;&gt; /tmp/log</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PREEXECCLOSE">preexec close (S)</term>
+ <listitem><para>This boolean option controls whether a non-zero
+ return code from <link linkend="PREEXEC"><parameter>preexec
+ </parameter></link> should close the service being connected to.</para>
+
+ <para>Default: <command>preexec close = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PREFERREDMASTER">preferred master (G)</term>
+ <listitem><para>This boolean parameter controls if <ulink
+ url="nmbd.8.html">nmbd(8)</ulink> is a preferred master browser
+ for its workgroup.</para>
+
+ <para>If this is set to <constant>true</constant>, on startup, <command>nmbd</command>
+ will force an election, and it will have a slight advantage in
+ winning the election. It is recommended that this parameter is
+ used in conjunction with <command><link linkend="DOMAINMASTER"><parameter>
+ domain master</parameter></link> = yes</command>, so that <command>
+ nmbd</command> can guarantee becoming a domain master.</para>
+
+ <para>Use this option with caution, because if there are several
+ hosts (whether Samba servers, Windows 95 or NT) that are preferred
+ master browsers on the same subnet, they will each periodically
+ and continuously attempt to become the local master browser.
+ This will result in unnecessary broadcast traffic and reduced browsing
+ capabilities.</para>
+
+ <para>See also <link linkend="OSLEVEL"><parameter>os level</parameter>
+ </link>.</para>
+
+ <para>Default: <command>preferred master = auto</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PREFEREDMASTER">prefered master (G)</term>
+ <listitem><para>Synonym for <link linkend="PREFERREDMASTER"><parameter>
+ preferred master</parameter></link> for people who cannot spell :-).</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRELOAD">preload</term>
+ <listitem><para>This is a list of services that you want to be
+ automatically added to the browse lists. This is most useful
+ for homes and printers services that would otherwise not be
+ visible.</para>
+
+ <para>Note that if you just want all printers in your
+ printcap file loaded then the <link linkend="LOADPRINTERS">
+ <parameter>load printers</parameter></link> option is easier.</para>
+
+ <para>Default: <emphasis>no preloaded services</emphasis></para>
+
+ <para>Example: <command>preload = fred lp colorlp</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PRESERVECASE">preserve case (S)</term>
+ <listitem><para> This controls if new filenames are created
+ with the case that the client passes, or if they are forced to
+ be the <link linkend="DEFAULTCASE"><parameter>default case
+ </parameter></link>.</para>
+
+ <para>Default: <command>preserve case = yes</command></para>
+
+ <para>See the section on <link linkend="NAMEMANGLINGSECT">NAME
+ MANGLING</link> for a fuller discussion.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTCOMMAND">print command (S)</term>
+ <listitem><para>After a print job has finished spooling to
+ a service, this command will be used via a <command>system()</command>
+ call to process the spool file. Typically the command specified will
+ submit the spool file to the host's printing subsystem, but there
+ is no requirement that this be the case. The server will not remove
+ the spool file, so whatever command you specify should remove the
+ spool file when it has been processed, otherwise you will need to
+ manually remove old spool files.</para>
+
+ <para>The print command is simply a text string. It will be used
+ verbatim, with two exceptions: All occurrences of <parameter>%s
+ </parameter> and <parameter>%f</parameter> will be replaced by the
+ appropriate spool file name, and all occurrences of <parameter>%p
+ </parameter> will be replaced by the appropriate printer name. The
+ spool file name is generated automatically by the server. The
+ <parameter>%J</parameter> macro can be used to access the job
+ name as transmitted by the client.</para>
+
+ <para>The print command <emphasis>MUST</emphasis> contain at least
+ one occurrence of <parameter>%s</parameter> or <parameter>%f
+ </parameter> - the <parameter>%p</parameter> is optional. At the time
+ a job is submitted, if no printer name is supplied the <parameter>%p
+ </parameter> will be silently removed from the printer command.</para>
+
+ <para>If specified in the [global] section, the print command given
+ will be used for any printable service that does not have its own
+ print command specified.</para>
+
+ <para>If there is neither a specified print command for a
+ printable service nor a global print command, spool files will
+ be created but not processed and (most importantly) not removed.</para>
+
+ <para>Note that printing may fail on some UNIXes from the
+ <constant>nobody</constant> account. If this happens then create
+ an alternative guest account that can print and set the <link
+ linkend="GUESTACCOUNT"><parameter>guest account</parameter></link>
+ in the [global] section.</para>
+
+ <para>You can form quite complex print commands by realizing
+ that they are just passed to a shell. For example the following
+ will log a print job, print the file, then remove it. Note that
+ ';' is the usual separator for command in shell scripts.</para>
+
+ <para><command>print command = echo Printing %s &gt;&gt;
+ /tmp/print.log; lpr -P %p %s; rm %s</command></para>
+
+ <para>You may have to vary this command considerably depending
+ on how you normally print files on your system. The default for
+ the parameter varies depending on the setting of the <link linkend="PRINTING">
+ <parameter>printing</parameter></link> parameter.</para>
+
+ <para>Default: For <command>printing = BSD, AIX, QNX, LPRNG
+ or PLP :</command></para>
+ <para><command>print command = lpr -r -P%p %s</command></para>
+
+ <para>For <command>printing = SYSV or HPUX :</command></para>
+ <para><command>print command = lp -c -d%p %s; rm %s</command></para>
+
+ <para>For <command>printing = SOFTQ :</command></para>
+ <para><command>print command = lp -d%p -s %s; rm %s</command></para>
+
+ <para>Example: <command>print command = /usr/local/samba/bin/myprintscript
+ %p %s</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTOK">print ok (S)</term>
+ <listitem><para>Synonym for <link linkend="PRINTABLE">
+ <parameter>printable</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTABLE">printable (S)</term>
+ <listitem><para>If this parameter is <constant>yes</constant>, then
+ clients may open, write to and submit spool files on the directory
+ specified for the service. </para>
+
+ <para>Note that a printable service will ALWAYS allow writing
+ to the service path (user privileges permitting) via the spooling
+ of print data. The <link linkend="WRITEABLE"><parameter>writeable
+ </parameter></link> parameter controls only non-printing access to
+ the resource.</para>
+
+ <para>Default: <command>printable = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTCAP">printcap (G)</term>
+ <listitem><para>Synonym for <link linkend="PRINTCAPNAME"><parameter>
+ printcap name</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTCAPNAME">printcap name (G)</term>
+ <listitem><para>This parameter may be used to override the
+ compiled-in default printcap name used by the server (usually <filename>
+ /etc/printcap</filename>). See the discussion of the <link
+ linkend="PRINTERSSECT">[printers]</link> section above for reasons
+ why you might want to do this.</para>
+
+ <para>On System V systems that use <command>lpstat</command> to
+ list available printers you can use <command>printcap name = lpstat
+ </command> to automatically obtain lists of available printers. This
+ is the default for systems that define SYSV at configure time in
+ Samba (this includes most System V based systems). If <parameter>
+ printcap name</parameter> is set to <command>lpstat</command> on
+ these systems then Samba will launch <command>lpstat -v</command> and
+ attempt to parse the output to obtain a printer list.</para>
+
+ <para>A minimal printcap file would look something like this:</para>
+
+ <para><programlisting>
+ print1|My Printer 1
+ print2|My Printer 2
+ print3|My Printer 3
+ print4|My Printer 4
+ print5|My Printer 5
+ </programlisting></para>
+
+ <para>where the '|' separates aliases of a printer. The fact
+ that the second alias has a space in it gives a hint to Samba
+ that it's a comment.</para>
+
+ <para><emphasis>NOTE</emphasis>: Under AIX the default printcap
+ name is <filename>/etc/qconfig</filename>. Samba will assume the
+ file is in AIX <filename>qconfig</filename> format if the string
+ <filename>qconfig</filename> appears in the printcap filename.</para>
+
+ <para>Default: <command>printcap name = /etc/printcap</command></para>
+ <para>Example: <command>printcap name = /etc/myprintcap</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTERADMIN">printer admin (S)</term>
+ <listitem><para>This is a list of users that can do anything to
+ printers via the remote administration interfaces offered by MS-RPC
+ (usually using a NT workstation). Note that the root user always
+ has admin rights.</para>
+
+ <para>Default: <command>printer admin = &lt;empty string&gt;</command>
+ </para>
+ <para>Example: <command>printer admin = admin, @staff</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTERDRIVER">printer driver (S)</term>
+ <listitem><para><emphasis>Note :</emphasis>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <ulink url="printer_driver2.html">Samba 2.2. Printing
+ HOWTO</ulink> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </para>
+
+ <para>This option allows you to control the string
+ that clients receive when they ask the server for the printer driver
+ associated with a printer. If you are using Windows95 or Windows NT
+ then you can use this to automate the setup of printers on your
+ system.</para>
+
+ <para>You need to set this parameter to the exact string (case
+ sensitive) that describes the appropriate printer driver for your
+ system. If you don't know the exact string to use then you should
+ first try with no <link linkend="PRINTERDRIVER"><parameter>
+ printer driver</parameter></link> option set and the client will
+ give you a list of printer drivers. The appropriate strings are
+ shown in a scroll box after you have chosen the printer manufacturer.</para>
+
+ <para>See also <link linkend="PRINTERDRIVERFILE"><parameter>printer
+ driver file</parameter></link>.</para>
+
+ <para>Example: <command>printer driver = HP LaserJet 4L</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTERDRIVERFILE">printer driver file (G)</term>
+ <listitem><para><emphasis>Note :</emphasis>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <ulink url="printer_driver2.html">Samba 2.2. Printing
+ HOWTO</ulink> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </para>
+
+ <para>This parameter tells Samba where the printer driver
+ definition file, used when serving drivers to Windows 95 clients, is
+ to be found. If this is not set, the default is :</para>
+
+ <para><filename><replaceable>SAMBA_INSTALL_DIRECTORY</replaceable>
+ /lib/printers.def</filename></para>
+
+ <para>This file is created from Windows 95 <filename>msprint.inf
+ </filename> files found on the Windows 95 client system. For more
+ details on setting up serving of printer drivers to Windows 95
+ clients, see the outdated documentation file in the <filename>docs/</filename>
+ directory, <filename>PRINTER_DRIVER.txt</filename>.</para>
+
+ <para>See also <link linkend="PRINTERDRIVERLOCATION"><parameter>
+ printer driver location</parameter></link>.</para>
+
+ <para>Default: <emphasis>None (set in compile).</emphasis></para>
+
+ <para>Example: <command>printer driver file =
+ /usr/local/samba/printers/drivers.def</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTERDRIVERLOCATION">printer driver location (S)</term>
+ <listitem><para><emphasis>Note :</emphasis>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <ulink url="printer_driver2.html">Samba 2.2. Printing
+ HOWTO</ulink> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </para>
+
+ <para>This parameter tells clients of a particular printer
+ share where to find the printer driver files for the automatic
+ installation of drivers for Windows 95 machines. If Samba is set up
+ to serve printer drivers to Windows 95 machines, this should be set to</para>
+
+ <para><command>\\MACHINE\PRINTER$</command></para>
+
+ <para>Where MACHINE is the NetBIOS name of your Samba server,
+ and PRINTER$ is a share you set up for serving printer driver
+ files. For more details on setting this up see the outdated documentation
+ file in the <filename>docs/</filename> directory, <filename>
+ PRINTER_DRIVER.txt</filename>.</para>
+
+ <para>See also <link linkend="PRINTERDRIVERFILE"><parameter>
+ printer driver file</parameter></link>.</para>
+
+ <para>Default: <command>none</command></para>
+ <para>Example: <command>printer driver location = \\MACHINE\PRINTER$
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTERNAME">printer name (S)</term>
+ <listitem><para>This parameter specifies the name of the printer
+ to which print jobs spooled through a printable service will be sent.</para>
+
+ <para>If specified in the [global] section, the printer
+ name given will be used for any printable service that does
+ not have its own printer name specified.</para>
+
+ <para>Default: <emphasis>none (but may be <constant>lp</constant>
+ on many systems)</emphasis></para>
+
+ <para>Example: <command>printer name = laserwriter</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="PRINTER">printer (S)</term>
+ <listitem><para>Synonym for <link linkend="PRINTERNAME"><parameter>
+ printer name</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PRINTING">printing (S)</term>
+ <listitem><para>This parameters controls how printer status
+ information is interpreted on your system. It also affects the
+ default values for the <parameter>print command</parameter>,
+ <parameter>lpq command</parameter>, <parameter>lppause command
+ </parameter>, <parameter>lpresume command</parameter>, and
+ <parameter>lprm command</parameter> if specified in the
+ [global] section.</para>
+
+ <para>Currently nine printing styles are supported. They are
+ <constant>BSD</constant>, <constant>AIX</constant>,
+ <constant>LPRNG</constant>, <constant>PLP</constant>,
+ <constant>SYSV</constant>, <constant>HPUX</constant>,
+ <constant>QNX</constant>, <constant>SOFTQ</constant>,
+ and <constant>CUPS</constant>.</para>
+
+ <para>To see what the defaults are for the other print
+ commands when using the various options use the <ulink
+ url="testparm.1.html">testparm(1)</ulink> program.</para>
+
+ <para>This option can be set on a per printer basis</para>
+
+ <para>See also the discussion in the <link linkend="PRINTERSSECT">
+ [printers]</link> section.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PROTOCOL">protocol (G)</term>
+ <listitem><para>Synonym for <link linkend="MAXPROTOCOL">
+ <parameter>max protocol</parameter></link>.</para></listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="PUBLIC">public (S)</term>
+ <listitem><para>Synonym for <link linkend="GUESTOK"><parameter>guest
+ ok</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="QUEUEPAUSECOMMAND">queuepause command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to pause the printer queue.</para>
+
+ <para>This command should be a program or script which takes
+ a printer name as its only parameter and stops the printer queue,
+ such that no longer jobs are submitted to the printer.</para>
+
+ <para>This command is not supported by Windows for Workgroups,
+ but can be issued from the Printers window under Windows 95
+ and NT.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the command.
+ </para>
+
+ <para>Note that it is good practice to include the absolute
+ path in the command as the PATH may not be available to the
+ server.</para>
+
+ <para>Default: <emphasis>depends on the setting of <parameter>printing
+ </parameter></emphasis></para>
+ <para>Example: <command>queuepause command = disable %p</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="QUEUERESUMECOMMAND">queueresume command (S)</term>
+ <listitem><para>This parameter specifies the command to be
+ executed on the server host in order to resume the printer queue. It
+ is the command to undo the behavior that is caused by the
+ previous parameter (<link linkend="QUEUEPAUSECOMMAND"><parameter>
+ queuepause command</parameter></link>).</para>
+
+ <para>This command should be a program or script which takes
+ a printer name as its only parameter and resumes the printer queue,
+ such that queued jobs are resubmitted to the printer.</para>
+
+ <para>This command is not supported by Windows for Workgroups,
+ but can be issued from the Printers window under Windows 95
+ and NT.</para>
+
+ <para>If a <parameter>%p</parameter> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the
+ command.</para>
+
+ <para>Note that it is good practice to include the absolute
+ path in the command as the PATH may not be available to the
+ server.</para>
+
+ <para>Default: <emphasis>depends on the setting of <link
+ linkend="PRINTING"><parameter>printing</parameter></link></emphasis>
+ </para>
+
+ <para>Example: <command>queuepause command = enable %p
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="READBMPX">read bmpx (G)</term>
+ <listitem><para>This boolean parameter controls whether <ulink
+ url="smbd.8.html">smbd(8)</ulink> will support the "Read
+ Block Multiplex" SMB. This is now rarely used and defaults to
+ <constant>no</constant>. You should never need to set this
+ parameter.</para>
+
+ <para>Default: <command>read bmpx = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="READLIST">read list (S)</term>
+ <listitem><para>This is a list of users that are given read-only
+ access to a service. If the connecting user is in this list then
+ they will not be given write access, no matter what the <link
+ linkend="WRITEABLE"><parameter>writeable</parameter></link>
+ option is set to. The list can include group names using the
+ syntax described in the <link linkend="INVALIDUSERS"><parameter>
+ invalid users</parameter></link> parameter.</para>
+
+ <para>See also the <link linkend="WRITELIST"><parameter>
+ write list</parameter></link> parameter and the <link
+ linkend="INVALIDUSERS"><parameter>invalid users</parameter>
+ </link> parameter.</para>
+
+ <para>Default: <command>read list = &lt;empty string&gt;</command></para>
+ <para>Example: <command>read list = mary, @students</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="READONLY">read only (S)</term>
+ <listitem><para>Note that this is an inverted synonym for <link
+ linkend="WRITEABLE"><parameter>writeable</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="READRAW">read raw (G)</term>
+ <listitem><para>This parameter controls whether or not the server
+ will support the raw read SMB requests when transferring data
+ to clients.</para>
+
+ <para>If enabled, raw reads allow reads of 65535 bytes in
+ one packet. This typically provides a major performance benefit.
+ </para>
+
+ <para>However, some clients either negotiate the allowable
+ block size incorrectly or are incapable of supporting larger block
+ sizes, and for these clients you may need to disable raw reads.</para>
+
+ <para>In general this parameter should be viewed as a system tuning
+ tool and left severely alone. See also <link linkend="WRITERAW">
+ <parameter>write raw</parameter></link>.</para>
+
+ <para>Default: <command>read raw = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="READSIZE">read size (G)</term>
+ <listitem><para>The option <parameter>read size</parameter>
+ affects the overlap of disk reads/writes with network reads/writes.
+ If the amount of data being transferred in several of the SMB
+ commands (currently SMBwrite, SMBwriteX and SMBreadbraw) is larger
+ than this value then the server begins writing the data before it
+ has received the whole packet from the network, or in the case of
+ SMBreadbraw, it begins writing to the network before all the data
+ has been read from disk.</para>
+
+ <para>This overlapping works best when the speeds of disk and
+ network access are similar, having very little effect when the
+ speed of one is much greater than the other.</para>
+
+ <para>The default value is 16384, but very little experimentation
+ has been done yet to determine the optimal value, and it is likely
+ that the best value will vary greatly between systems anyway.
+ A value over 65536 is pointless and will cause you to allocate
+ memory unnecessarily.</para>
+
+ <para>Default: <command>read size = 16384</command></para>
+ <para>Example: <command>read size = 8192</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="REMOTEANNOUNCE">remote announce (G)</term>
+ <listitem><para>This option allows you to setup <ulink
+ url="nmbd.8.html">nmbd(8)</ulink> to periodically announce itself
+ to arbitrary IP addresses with an arbitrary workgroup name.</para>
+
+ <para>This is useful if you want your Samba server to appear
+ in a remote workgroup for which the normal browse propagation
+ rules don't work. The remote workgroup can be anywhere that you
+ can send IP packets to.</para>
+
+ <para>For example:</para>
+
+ <para><command>remote announce = 192.168.2.255/SERVERS
+ 192.168.4.255/STAFF</command></para>
+
+ <para>the above line would cause <command>nmbd</command> to announce itself
+ to the two given IP addresses using the given workgroup names.
+ If you leave out the workgroup name then the one given in
+ the <link linkend="WORKGROUP"><parameter>workgroup</parameter></link>
+ parameter is used instead.</para>
+
+ <para>The IP addresses you choose would normally be the broadcast
+ addresses of the remote networks, but can also be the IP addresses
+ of known browse masters if your network config is that stable.</para>
+
+ <para>See the documentation file <filename>BROWSING.txt</filename>
+ in the <filename>docs/</filename> directory.</para>
+
+ <para>Default: <command>remote announce = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="REMOTEBROWSESYNC">remote browse sync (G)</term>
+ <listitem><para>This option allows you to setup <ulink
+ url="nmbd.8.html">nmbd(8)</ulink> to periodically request
+ synchronization of browse lists with the master browser of a Samba
+ server that is on a remote segment. This option will allow you to
+ gain browse lists for multiple workgroups across routed networks. This
+ is done in a manner that does not work with any non-Samba servers.</para>
+
+ <para>This is useful if you want your Samba server and all local
+ clients to appear in a remote workgroup for which the normal browse
+ propagation rules don't work. The remote workgroup can be anywhere
+ that you can send IP packets to.</para>
+
+ <para>For example:</para>
+
+ <para><command>remote browse sync = 192.168.2.255 192.168.4.255
+ </command></para>
+
+ <para>the above line would cause <command>nmbd</command> to request
+ the master browser on the specified subnets or addresses to
+ synchronize their browse lists with the local server.</para>
+
+ <para>The IP addresses you choose would normally be the broadcast
+ addresses of the remote networks, but can also be the IP addresses
+ of known browse masters if your network config is that stable. If
+ a machine IP address is given Samba makes NO attempt to validate
+ that the remote machine is available, is listening, nor that it
+ is in fact the browse master on its segment.</para>
+
+ <para>Default: <command>remote browse sync = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="RESTRICTANONYMOUS">restrict anonymous (G)</term>
+ <listitem><para>This is a boolean parameter. If it is <constant>true</constant>, then
+ anonymous access to the server will be restricted, namely in the
+ case where the server is expecting the client to send a username,
+ but it doesn't. Setting it to <constant>true</constant> will force these anonymous
+ connections to be denied, and the client will be required to always
+ supply a username and password when connecting. Use of this parameter
+ is only recommended for homogeneous NT client environments.</para>
+
+ <para>This parameter makes the use of macro expansions that rely
+ on the username (%U, %G, etc) consistent. NT 4.0
+ likes to use anonymous connections when refreshing the share list,
+ and this is a way to work around that.</para>
+
+ <para>When restrict anonymous is <constant>true</constant>, all anonymous connections
+ are denied no matter what they are for. This can effect the ability
+ of a machine to access the Samba Primary Domain Controller to revalidate
+ its machine account after someone else has logged on the client
+ interactively. The NT client will display a message saying that
+ the machine's account in the domain doesn't exist or the password is
+ bad. The best way to deal with this is to reboot NT client machines
+ between interactive logons, using "Shutdown and Restart", rather
+ than "Close all programs and logon as a different user".</para>
+
+ <para>Default: <command>restrict anonymous = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ROOT">root (G)</term>
+ <listitem><para>Synonym for <link linkend="ROOTDIRECTORY">
+ <parameter>root directory"</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ROOTDIR">root dir (G)</term>
+ <listitem><para>Synonym for <link linkend="ROOTDIRECTORY">
+ <parameter>root directory"</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="ROOTDIRECTORY">root directory (G)</term>
+ <listitem><para>The server will <command>chroot()</command> (i.e.
+ Change its root directory) to this directory on startup. This is
+ not strictly necessary for secure operation. Even without it the
+ server will deny access to files not in one of the service entries.
+ It may also check for, and deny access to, soft links to other
+ parts of the filesystem, or attempts to use ".." in file names
+ to access other directories (depending on the setting of the <link
+ linkend="WIDELINKS"><parameter>wide links</parameter></link>
+ parameter).</para>
+
+ <para>Adding a <parameter>root directory</parameter> entry other
+ than "/" adds an extra level of security, but at a price. It
+ absolutely ensures that no access is given to files not in the
+ sub-tree specified in the <parameter>root directory</parameter>
+ option, <emphasis>including</emphasis> some files needed for
+ complete operation of the server. To maintain full operability
+ of the server you will need to mirror some system files
+ into the <parameter>root directory</parameter> tree. In particular
+ you will need to mirror <filename>/etc/passwd</filename> (or a
+ subset of it), and any binaries or configuration files needed for
+ printing (if required). The set of files that must be mirrored is
+ operating system dependent.</para>
+
+ <para>Default: <command>root directory = /</command></para>
+ <para>Example: <command>root directory = /homes/smb</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ROOTPOSTEXEC">root postexec (S)</term>
+ <listitem><para>This is the same as the <parameter>postexec</parameter>
+ parameter except that the command is run as root. This
+ is useful for unmounting filesystems
+ (such as CDROMs) after a connection is closed.</para>
+
+ <para>See also <link linkend="POSTEXEC"><parameter>
+ postexec</parameter></link>.</para>
+
+ <para>Default: <command>root postexec = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><anchor id="ROOTPREEXEC">root preexec (S)</term>
+ <listitem><para>This is the same as the <parameter>preexec</parameter>
+ parameter except that the command is run as root. This
+ is useful for mounting filesystems (such as CDROMs) when a
+ connection is opened.</para>
+
+ <para>See also <link linkend="PREEXEC"><parameter>
+ preexec</parameter></link> and <link linkend="PREEXECCLOSE">
+ <parameter>preexec close</parameter></link>.</para>
+
+ <para>Default: <command>root preexec = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="ROOTPREEXECCLOSE">root preexec close (S)</term>
+ <listitem><para>This is the same as the <parameter>preexec close
+ </parameter> parameter except that the command is run as root.</para>
+
+ <para>See also <link linkend="PREEXEC"><parameter>
+ preexec</parameter></link> and <link linkend="PREEXECCLOSE">
+ <parameter>preexec close</parameter></link>.</para>
+
+ <para>Default: <command>root preexec close = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SECURITY">security (G)</term>
+ <listitem><para>This option affects how clients respond to
+ Samba and is one of the most important settings in the <filename>
+ smb.conf</filename> file.</para>
+
+ <para>The option sets the "security mode bit" in replies to
+ protocol negotiations with <ulink url="smbd.8.html">smbd(8)
+ </ulink> to turn share level security on or off. Clients decide
+ based on this bit whether (and how) to transfer user and password
+ information to the server.</para>
+
+
+ <para>The default is <command>security = user</command>, as this is
+ the most common setting needed when talking to Windows 98 and
+ Windows NT.</para>
+
+ <para>The alternatives are <command>security = share</command>,
+ <command>security = server</command> or <command>security = domain
+ </command>.</para>
+
+ <para>In versions of Samba prior to 2.0.0, the default was
+ <command>security = share</command> mainly because that was
+ the only option at one stage.</para>
+
+ <para>There is a bug in WfWg that has relevance to this
+ setting. When in user or server level security a WfWg client
+ will totally ignore the password you type in the "connect
+ drive" dialog box. This makes it very difficult (if not impossible)
+ to connect to a Samba service as anyone except the user that
+ you are logged into WfWg as.</para>
+
+ <para>If your PCs use usernames that are the same as their
+ usernames on the UNIX machine then you will want to use
+ <command>security = user</command>. If you mostly use usernames
+ that don't exist on the UNIX box then use <command>security =
+ share</command>.</para>
+
+ <para>You should also use <command>security = share</command> if you
+ want to mainly setup shares without a password (guest shares). This
+ is commonly used for a shared printer server. It is more difficult
+ to setup guest shares with <command>security = user</command>, see
+ the <link linkend="MAPTOGUEST"><parameter>map to guest</parameter>
+ </link>parameter for details.</para>
+
+ <para>It is possible to use <command>smbd</command> in a <emphasis>
+ hybrid mode</emphasis> where it is offers both user and share
+ level security under different <link linkend="NETBIOSALIASES">
+ <parameter>NetBIOS aliases</parameter></link>. </para>
+
+ <para>The different settings will now be explained.</para>
+
+
+ <para><anchor id="SECURITYEQUALSSHARE"><emphasis>SECURITY = SHARE
+ </emphasis></para>
+
+ <para>When clients connect to a share level security server they
+ need not log onto the server with a valid username and password before
+ attempting to connect to a shared resource (although modern clients
+ such as Windows 95/98 and Windows NT will send a logon request with
+ a username but no password when talking to a <command>security = share
+ </command> server). Instead, the clients send authentication information
+ (passwords) on a per-share basis, at the time they attempt to connect
+ to that share.</para>
+
+ <para>Note that <command>smbd</command> <emphasis>ALWAYS</emphasis>
+ uses a valid UNIX user to act on behalf of the client, even in
+ <command>security = share</command> level security.</para>
+
+ <para>As clients are not required to send a username to the server
+ in share level security, <command>smbd</command> uses several
+ techniques to determine the correct UNIX user to use on behalf
+ of the client.</para>
+
+ <para>A list of possible UNIX usernames to match with the given
+ client password is constructed using the following methods :</para>
+
+ <itemizedlist>
+ <listitem><para>If the <link linkend="GUESTONLY"><parameter>guest
+ only</parameter></link> parameter is set, then all the other
+ stages are missed and only the <link linkend="GUESTACCOUNT">
+ <parameter>guest account</parameter></link> username is checked.
+ </para></listitem>
+
+ <listitem><para>Is a username is sent with the share connection
+ request, then this username (after mapping - see <link
+ linkend="USERNAMEMAP"><parameter>username map</parameter></link>),
+ is added as a potential username.</para></listitem>
+
+ <listitem><para>If the client did a previous <emphasis>logon
+ </emphasis> request (the SessionSetup SMB call) then the
+ username sent in this SMB will be added as a potential username.
+ </para></listitem>
+
+ <listitem><para>The name of the service the client requested is
+ added as a potential username.</para></listitem>
+
+ <listitem><para>The NetBIOS name of the client is added to
+ the list as a potential username.</para></listitem>
+
+ <listitem><para>Any users on the <link linkend="USER"><parameter>
+ user</parameter></link> list are added as potential usernames.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>If the <parameter>guest only</parameter> parameter is
+ not set, then this list is then tried with the supplied password.
+ The first user for whom the password matches will be used as the
+ UNIX user.</para>
+
+ <para>If the <parameter>guest only</parameter> parameter is
+ set, or no username can be determined then if the share is marked
+ as available to the <parameter>guest account</parameter>, then this
+ guest user will be used, otherwise access is denied.</para>
+
+ <para>Note that it can be <emphasis>very</emphasis> confusing
+ in share-level security as to which UNIX username will eventually
+ be used in granting access.</para>
+
+ <para>See also the section <link linkend="VALIDATIONSECT">
+ NOTE ABOUT USERNAME/PASSWORD VALIDATION</link>.</para>
+
+ <para><anchor id="SECURITYEQUALSUSER"><emphasis>SECURITY = USER
+ </emphasis></para>
+
+ <para>This is the default security setting in Samba 2.2.
+ With user-level security a client must first "log-on" with a
+ valid username and password (which can be mapped using the <link
+ linkend="USERNAMEMAP"><parameter>username map</parameter></link>
+ parameter). Encrypted passwords (see the <link linkend="ENCRYPTPASSWORDS">
+ <parameter>encrypted passwords</parameter></link> parameter) can also
+ be used in this security mode. Parameters such as <link linkend="USER">
+ <parameter>user</parameter></link> and <link linkend="GUESTONLY">
+ <parameter>guest only</parameter></link> if set are then applied and
+ may change the UNIX user to use on this connection, but only after
+ the user has been successfully authenticated.</para>
+
+ <para><emphasis>Note</emphasis> that the name of the resource being
+ requested is <emphasis>not</emphasis> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <link
+ linkend="GUESTACCOUNT"><parameter>guest account</parameter></link>.
+ See the <link linkend="MAPTOGUEST"><parameter>map to guest</parameter>
+ </link> parameter for details on doing this.</para>
+
+ <para>See also the section <link linkend="VALIDATIONSECT">
+ NOTE ABOUT USERNAME/PASSWORD VALIDATION</link>.</para>
+
+ <para><anchor id="SECURITYEQUALSSERVER"><emphasis>SECURITY = SERVER
+ </emphasis></para>
+
+ <para>In this mode Samba will try to validate the username/password
+ by passing it to another SMB server, such as an NT box. If this
+ fails it will revert to <command>security = user</command>, but note
+ that if encrypted passwords have been negotiated then Samba cannot
+ revert back to checking the UNIX password file, it must have a valid
+ <filename>smbpasswd</filename> file to check users against. See the
+ documentation file in the <filename>docs/</filename> directory
+ <filename>ENCRYPTION.txt</filename> for details on how to set this
+ up.</para>
+
+ <para><emphasis>Note</emphasis> that from the client's point of
+ view <command>security = server</command> is the same as <command>
+ security = user</command>. It only affects how the server deals
+ with the authentication, it does not in any way affect what the
+ client sees.</para>
+
+ <para><emphasis>Note</emphasis> that the name of the resource being
+ requested is <emphasis>not</emphasis> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <link
+ linkend="GUESTACCOUNT"><parameter>guest account</parameter></link>.
+ See the <link linkend="MAPTOGUEST"><parameter>map to guest</parameter>
+ </link> parameter for details on doing this.</para>
+
+ <para>See also the section <link linkend="VALIDATIONSECT">
+ NOTE ABOUT USERNAME/PASSWORD VALIDATION</link>.</para>
+
+ <para>See also the <link linkend="PASSWORDSERVER"><parameter>password
+ server</parameter></link> parameter and the <link
+ linkend="ENCRYPTPASSWORDS"><parameter>encrypted passwords</parameter>
+ </link> parameter.</para>
+
+ <para><anchor id="SECURITYEQUALSDOMAIN"><emphasis>SECURITY = DOMAIN
+ </emphasis></para>
+
+ <para>This mode will only work correctly if <ulink
+ url="smbpasswd.8.html">smbpasswd(8)</ulink> has been used to add this
+ machine into a Windows NT Domain. It expects the <link
+ linkend="ENCRYPTPASSWORDS"><parameter>encrypted passwords</parameter>
+ </link> parameter to be set to <constant>true</constant>. In this
+ mode Samba will try to validate the username/password by passing
+ it to a Windows NT Primary or Backup Domain Controller, in exactly
+ the same way that a Windows NT Server would do.</para>
+
+ <para><emphasis>Note</emphasis> that a valid UNIX user must still
+ exist as well as the account on the Domain Controller to allow
+ Samba to have a valid UNIX account to map file access to.</para>
+
+ <para><emphasis>Note</emphasis> that from the client's point
+ of view <command>security = domain</command> is the same as <command>security = user
+ </command>. It only affects how the server deals with the authentication,
+ it does not in any way affect what the client sees.</para>
+
+ <para><emphasis>Note</emphasis> that the name of the resource being
+ requested is <emphasis>not</emphasis> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <link
+ linkend="GUESTACCOUNT"><parameter>guest account</parameter></link>.
+ See the <link linkend="MAPTOGUEST"><parameter>map to guest</parameter>
+ </link> parameter for details on doing this.</para>
+
+ <para><emphasis>BUG:</emphasis> There is currently a bug in the
+ implementation of <command>security = domain</command> with respect
+ to multi-byte character set usernames. The communication with a
+ Domain Controller must be done in UNICODE and Samba currently
+ does not widen multi-byte user names to UNICODE correctly, thus
+ a multi-byte username will not be recognized correctly at the
+ Domain Controller. This issue will be addressed in a future release.</para>
+
+ <para>See also the section <link linkend="VALIDATIONSECT">
+ NOTE ABOUT USERNAME/PASSWORD VALIDATION</link>.</para>
+
+ <para>See also the <link linkend="PASSWORDSERVER"><parameter>password
+ server</parameter></link> parameter and the <link
+ linkend="ENCRYPTPASSWORDS"><parameter>encrypted passwords</parameter>
+ </link> parameter.</para>
+
+ <para>Default: <command>security = USER</command></para>
+ <para>Example: <command>security = DOMAIN</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SECURITYMASK">security mask (S)</term>
+ <listitem><para>This parameter controls what UNIX permission
+ bits can be modified when a Windows NT client is manipulating
+ the UNIX permission on a file using the native NT security
+ dialog box.</para>
+
+ <para>This parameter is applied as a mask (AND'ed with) to
+ the changed permission bits, thus preventing any bits not in
+ this mask from being modified. Essentially, zero bits in this
+ mask may be treated as a set of bits the user is not allowed
+ to change.</para>
+
+ <para>If not set explicitly this parameter is 0777, allowing
+ a user to modify all the user/group/world permissions on a file.
+ </para>
+
+ <para><emphasis>Note</emphasis> that users who can access the
+ Samba server through other means can easily bypass this
+ restriction, so it is primarily useful for standalone
+ "appliance" systems. Administrators of most normal systems will
+ probably want to leave it set to <constant>0777</constant>.</para>
+
+ <para>See also the <link linkend="FORCEDIRECTORYSECURITYMODE">
+ <parameter>force directory security mode</parameter></link>,
+ <link linkend="DIRECTORYSECURITYMASK"><parameter>directory
+ security mask</parameter></link>, <link linkend="FORCESECURITYMODE">
+ <parameter>force security mode</parameter></link> parameters.</para>
+
+ <para>Default: <command>security mask = 0777</command></para>
+ <para>Example: <command>security mask = 0770</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SERVERSTRING">server string (G)</term>
+ <listitem><para>This controls what string will show up in the
+ printer comment box in print manager and next to the IPC connection
+ in <command>net view</command>. It can be any string that you wish
+ to show to your users.</para>
+
+ <para>It also sets what will appear in browse lists next
+ to the machine name.</para>
+
+ <para>A <parameter>%v</parameter> will be replaced with the Samba
+ version number.</para>
+
+ <para>A <parameter>%h</parameter> will be replaced with the
+ hostname.</para>
+
+ <para>Default: <command>server string = Samba %v</command></para>
+
+ <para>Example: <command>server string = University of GNUs Samba
+ Server</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SETDIRECTORY">set directory (S)</term>
+ <listitem><para>If <command>set directory = no</command>, then
+ users of the service may not use the setdir command to change
+ directory.</para>
+
+ <para>The <command>setdir</command> command is only implemented
+ in the Digital Pathworks client. See the Pathworks documentation
+ for details.</para>
+
+ <para>Default: <command>set directory = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="SHORTPRESERVECASE">short preserve case (S)</term>
+ <listitem><para>This boolean parameter controls if new files
+ which conform to 8.3 syntax, that is all in upper case and of
+ suitable length, are created upper case, or if they are forced
+ to be the <link linkend="DEFAULTCASE"><parameter>default case
+ </parameter></link>. This option can be use with <link
+ linkend="PRESERVECASE"><command>preserve case = yes</command>
+ </link> to permit long filenames to retain their case, while short
+ names are lowered. </para>
+
+ <para>See the section on <link linkend="NAMEMANGLINGSECT">
+ NAME MANGLING</link>.</para>
+
+ <para>Default: <command>short preserve case = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SHOWADDPRINTERWIZARD">show add printer wizard (G)</term>
+ <listitem><para>With the introduction of MS-RPC based printing support
+ for Windows NT/2000 client in Samba 2.2, a "Printers..." folder will
+ appear on Samba hosts in the share listing. Normally this folder will
+ contain an icon for the MS Add Printer Wizard (APW). However, it is
+ possible to disable this feature regardless of the level of privilege
+ of the connected user.</para>
+
+ <para>Under normal circumstances, the Windows NT/2000 client will
+ open a handle on the printer server with OpenPrinterEx() asking for
+ Administrator privileges. If the user does not have administrative
+ access on the print server (i.e is not root or a member of the
+ <parameter>printer admin</parameter> group), the OpenPrinterEx()
+ call fails and the client makes another open call with a request for
+ a lower privilege level. This should succeed, however the APW
+ icon will not be displayed.</para>
+
+ <para>Disabling the <parameter>show add printer wizard</parameter>
+ parameter will always cause the OpenPrinterEx() on the server
+ to fail. Thus the APW icon will never be displayed. <emphasis>
+ Note :</emphasis>This does not prevent the same user from having
+ administrative privilege on an individual printer.</para>
+
+ <para>See also <link linkend="ADDPRINTERCOMMAND"><parameter>addprinter
+ command</parameter></link>, <link linkend="DELETEPRINTERCOMMAND">
+ <parameter>deleteprinter command</parameter></link>, <link
+ linkend="PRINTERADMIN"><parameter>printer admin</parameter></link></para>
+
+ <para>Default :<command>show add printer wizard = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SHUTDOWNSCRIPT">shutdown script (G)</term>
+ <listitem><para><emphasis>This parameter only exists in the HEAD cvs branch</emphasis>
+ This a full path name to a script called by
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink> that
+ should start a shutdown procedure.</para>
+
+ <para>This command will be run as the user connected to the
+ server.</para>
+
+ <para>%m %t %r %f parameters are expanded</para>
+ <para><parameter>%m</parameter> will be substituted with the
+ shutdown message sent to the server.</para>
+ <para><parameter>%t</parameter> will be substituted with the
+ number of seconds to wait before effectively starting the
+ shutdown procedure.</para>
+ <para><parameter>%r</parameter> will be substituted with the
+ switch <emphasis>-r</emphasis>. It means reboot after shutdown
+ for NT.
+ </para>
+ <para><parameter>%f</parameter> will be substituted with the
+ switch <emphasis>-f</emphasis>. It means force the shutdown
+ even if applications do not respond for NT.</para>
+
+ <para>Default: <emphasis>None</emphasis>.</para>
+ <para>Example: <command>abort shutdown script = /usr/local/samba/sbin/shutdown %m %t %r %f</command></para>
+ <para>Shutdown script example:
+ <programlisting>
+ #!/bin/bash
+
+ $time=0
+ let "time/60"
+ let "time++"
+
+ /sbin/shutdown $3 $4 +$time $1 &
+ </programlisting>
+ Shutdown does not return so we need to launch it in background.
+ </para>
+
+ <para>See also <link linkend="ABORTSHUTDOWNSCRIPT"><parameter>abort shutdown script</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SMBPASSWDFILE">smb passwd file (G)</term>
+ <listitem><para>This option sets the path to the encrypted
+ smbpasswd file. By default the path to the smbpasswd file
+ is compiled into Samba.</para>
+
+ <para>Default: <command>smb passwd file = ${prefix}/private/smbpasswd
+ </command></para>
+
+ <para>Example: <command>smb passwd file = /etc/samba/smbpasswd
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="SOCKETADDRESS">socket address (G)</term>
+ <listitem><para>This option allows you to control what
+ address Samba will listen for connections on. This is used to
+ support multiple virtual interfaces on the one server, each
+ with a different configuration.</para>
+
+ <para>By default Samba will accept connections on any
+ address.</para>
+
+ <para>Example: <command>socket address = 192.168.2.20</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SOCKETOPTIONS">socket options (G)</term>
+ <listitem><para>This option allows you to set socket options
+ to be used when talking with the client.</para>
+
+ <para>Socket options are controls on the networking layer
+ of the operating systems which allow the connection to be
+ tuned.</para>
+
+ <para>This option will typically be used to tune your Samba
+ server for optimal performance for your local network. There is
+ no way that Samba can know what the optimal parameters are for
+ your net, so you must experiment and choose them yourself. We
+ strongly suggest you read the appropriate documentation for your
+ operating system first (perhaps <command>man setsockopt</command>
+ will help).</para>
+
+ <para>You may find that on some systems Samba will say
+ "Unknown socket option" when you supply an option. This means you
+ either incorrectly typed it or you need to add an include file
+ to includes.h for your OS. If the latter is the case please
+ send the patch to <ulink url="mailto:samba@samba.org">
+ samba@samba.org</ulink>.</para>
+
+ <para>Any of the supported socket options may be combined
+ in any way you like, as long as your OS allows it.</para>
+
+ <para>This is the list of socket options currently settable
+ using this option:</para>
+
+ <itemizedlist>
+ <listitem><para>SO_KEEPALIVE</para></listitem>
+ <listitem><para>SO_REUSEADDR</para></listitem>
+ <listitem><para>SO_BROADCAST</para></listitem>
+ <listitem><para>TCP_NODELAY</para></listitem>
+ <listitem><para>IPTOS_LOWDELAY</para></listitem>
+ <listitem><para>IPTOS_THROUGHPUT</para></listitem>
+ <listitem><para>SO_SNDBUF *</para></listitem>
+ <listitem><para>SO_RCVBUF *</para></listitem>
+ <listitem><para>SO_SNDLOWAT *</para></listitem>
+ <listitem><para>SO_RCVLOWAT *</para></listitem>
+ </itemizedlist>
+
+ <para>Those marked with a <emphasis>'*'</emphasis> take an integer
+ argument. The others can optionally take a 1 or 0 argument to enable
+ or disable the option, by default they will be enabled if you
+ don't specify 1 or 0.</para>
+
+ <para>To specify an argument use the syntax SOME_OPTION = VALUE
+ for example <command>SO_SNDBUF = 8192</command>. Note that you must
+ not have any spaces before or after the = sign.</para>
+
+ <para>If you are on a local network then a sensible option
+ might be</para>
+ <para><command>socket options = IPTOS_LOWDELAY</command></para>
+
+ <para>If you have a local network then you could try:</para>
+ <para><command>socket options = IPTOS_LOWDELAY TCP_NODELAY</command></para>
+
+ <para>If you are on a wide area network then perhaps try
+ setting IPTOS_THROUGHPUT. </para>
+
+ <para>Note that several of the options may cause your Samba
+ server to fail completely. Use these options with caution!</para>
+
+ <para>Default: <command>socket options = TCP_NODELAY</command></para>
+ <para>Example: <command>socket options = IPTOS_LOWDELAY</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="SOURCEENVIRONMENT">source environment (G)</term>
+ <listitem><para>This parameter causes Samba to set environment
+ variables as per the content of the file named.</para>
+
+ <para>If the value of this parameter starts with a "|" character
+ then Samba will treat that value as a pipe command to open and
+ will set the environment variables from the output of the pipe.</para>
+
+ <para>The contents of the file or the output of the pipe should
+ be formatted as the output of the standard Unix <command>env(1)
+ </command> command. This is of the form :</para>
+ <para>Example environment entry:</para>
+ <para><command>SAMBA_NETBIOS_NAME = myhostname</command></para>
+
+ <para>Default: <emphasis>No default value</emphasis></para>
+ <para>Examples: <command>source environment = |/etc/smb.conf.sh
+ </command></para>
+
+ <para>Example: <command>source environment =
+ /usr/local/smb_env_vars</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSL">ssl (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This variable enables or disables the entire SSL mode. If
+ it is set to <constant>no</constant>, the SSL-enabled Samba behaves
+ exactly like the non-SSL Samba. If set to <constant>yes</constant>,
+ it depends on the variables <link linkend="SSLHOSTS"><parameter>
+ ssl hosts</parameter></link> and <link linkend="SSLHOSTSRESIGN">
+ <parameter>ssl hosts resign</parameter></link> whether an SSL
+ connection will be required.</para>
+
+ <para>Default: <command>ssl = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLCACERTDIR">ssl CA certDir (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This variable defines where to look up the Certification
+ Authorities. The given directory should contain one file for
+ each CA that Samba will trust. The file name must be the hash
+ value over the "Distinguished Name" of the CA. How this directory
+ is set up is explained later in this document. All files within the
+ directory that don't fit into this naming scheme are ignored. You
+ don't need this variable if you don't verify client certificates.</para>
+
+ <para>Default: <command>ssl CA certDir = /usr/local/ssl/certs
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLCACERTFILE">ssl CA certFile (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This variable is a second way to define the trusted CAs.
+ The certificates of the trusted CAs are collected in one big
+ file and this variable points to the file. You will probably
+ only use one of the two ways to define your CAs. The first choice is
+ preferable if you have many CAs or want to be flexible, the second
+ is preferable if you only have one CA and want to keep things
+ simple (you won't need to create the hashed file names). You
+ don't need this variable if you don't verify client certificates.</para>
+
+ <para>Default: <command>ssl CA certFile = /usr/local/ssl/certs/trustedCAs.pem
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLCIPHERS">ssl ciphers (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This variable defines the ciphers that should be offered
+ during SSL negotiation. You should not set this variable unless
+ you know what you are doing.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLCLIENTCERT">ssl client cert (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>The certificate in this file is used by <ulink url="smbclient.1.html">
+ <command>smbclient(1)</command></ulink> if it exists. It's needed
+ if the server requires a client certificate.</para>
+
+ <para>Default: <command>ssl client cert = /usr/local/ssl/certs/smbclient.pem
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLCLIENTKEY">ssl client key (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This is the private key for <ulink url="smbclient.1.html">
+ <command>smbclient(1)</command></ulink>. It's only needed if the
+ client should have a certificate. </para>
+
+ <para>Default: <command>ssl client key = /usr/local/ssl/private/smbclient.pem
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLCOMPATIBILITY">ssl compatibility (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This variable defines whether OpenSSL should be configured
+ for bug compatibility with other SSL implementations. This is
+ probably not desirable because currently no clients with SSL
+ implementations other than OpenSSL exist.</para>
+
+ <para>Default: <command>ssl compatibility = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLEGDSOCKET">ssl egd socket (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>
+ This option is used to define the location of the communiation socket of
+ an EGD or PRNGD daemon, from which entropy can be retrieved. This option
+ can be used instead of or together with the <link
+ linkend="SSLENTROPYFILE"><parameter>ssl entropy file</parameter></link>
+ directive. 255 bytes of entropy will be retrieved from the daemon.
+ </para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLENTROPYBYTES">ssl entropy bytes (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>
+ This parameter is used to define the number of bytes which should
+ be read from the <link linkend="SSLENTROPYFILE"><parameter>ssl entropy
+ file</parameter></link> If a -1 is specified, the entire file will
+ be read.
+ </para>
+
+ <para>Default: <command>ssl entropy bytes = 255</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLENTROPYFILE">ssl entropy file (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>
+ This parameter is used to specify a file from which processes will
+ read "random bytes" on startup. In order to seed the internal pseudo
+ random number generator, entropy must be provided. On system with a
+ <filename>/dev/urandom</filename> device file, the processes
+ will retrieve its entropy from the kernel. On systems without kernel
+ entropy support, a file can be supplied that will be read on startup
+ and that will be used to seed the PRNG.
+ </para>
+
+ <para>Default: <emphasis>none</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLHOSTS">ssl hosts (G)</term>
+ <listitem><para>See <link linkend="SSLHOSTSRESIGN"><parameter>
+ ssl hosts resign</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLHOSTSRESIGN">ssl hosts resign (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>These two variables define whether Samba will go
+ into SSL mode or not. If none of them is defined, Samba will
+ allow only SSL connections. If the <link linkend="SSLHOSTS">
+ <parameter>ssl hosts</parameter></link> variable lists
+ hosts (by IP-address, IP-address range, net group or name),
+ only these hosts will be forced into SSL mode. If the <parameter>
+ ssl hosts resign</parameter> variable lists hosts, only these
+ hosts will <emphasis>NOT</emphasis> be forced into SSL mode. The syntax for these two
+ variables is the same as for the <link linkend="HOSTSALLOW"><parameter>
+ hosts allow</parameter></link> and <link linkend="HOSTSDENY">
+ <parameter>hosts deny</parameter></link> pair of variables, only
+ that the subject of the decision is different: It's not the access
+ right but whether SSL is used or not. </para>
+
+ <para>The example below requires SSL connections from all hosts
+ outside the local net (which is 192.168.*.*).</para>
+
+ <para>Default: <command>ssl hosts = &lt;empty string&gt;</command></para>
+ <para><command>ssl hosts resign = &lt;empty string&gt;</command></para>
+
+ <para>Example: <command>ssl hosts resign = 192.168.</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLREQUIRECLIENTCERT">ssl require clientcert (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>If this variable is set to <constant>yes</constant>, the
+ server will not tolerate connections from clients that don't
+ have a valid certificate. The directory/file given in <link
+ linkend="SSLCACERTDIR"><parameter>ssl CA certDir</parameter>
+ </link> and <link linkend="SSLCACERTFILE"><parameter>ssl CA certFile
+ </parameter></link> will be used to look up the CAs that issued
+ the client's certificate. If the certificate can't be verified
+ positively, the connection will be terminated. If this variable
+ is set to <constant>no</constant>, clients don't need certificates.
+ Contrary to web applications you really <emphasis>should</emphasis>
+ require client certificates. In the web environment the client's
+ data is sensitive (credit card numbers) and the server must prove
+ to be trustworthy. In a file server environment the server's data
+ will be sensitive and the clients must prove to be trustworthy.</para>
+
+ <para>Default: <command>ssl require clientcert = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SSLREQUIRESERVERCERT">ssl require servercert (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>If this variable is set to <constant>yes</constant>, the
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command>
+ </ulink> will request a certificate from the server. Same as
+ <link linkend="SSLREQUIRECLIENTCERT"><parameter>ssl require
+ clientcert</parameter></link> for the server.</para>
+
+ <para>Default: <command>ssl require servercert = no</command>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><anchor id="SSLSERVERCERT">ssl server cert (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This is the file containing the server's certificate.
+ The server <emphasis>must</emphasis> have a certificate. The
+ file may also contain the server's private key. See later for
+ how certificates and private keys are created.</para>
+
+ <para>Default: <command>ssl server cert = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLSERVERKEY">ssl server key (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This file contains the private key of the server. If
+ this variable is not defined, the key is looked up in the
+ certificate file (it may be appended to the certificate).
+ The server <emphasis>must</emphasis> have a private key
+ and the certificate <emphasis>must</emphasis>
+ match this private key.</para>
+
+ <para>Default: <command>ssl server key = &lt;empty string&gt;
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="SSLVERSION">ssl version (G)</term>
+ <listitem><para>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <command>--with-ssl</command> was
+ given at configure time.</para>
+
+ <para>This enumeration variable defines the versions of the
+ SSL protocol that will be used. <constant>ssl2or3</constant> allows
+ dynamic negotiation of SSL v2 or v3, <constant>ssl2</constant> results
+ in SSL v2, <constant>ssl3</constant> results in SSL v3 and
+ <constant>tls1</constant> results in TLS v1. TLS (Transport Layer
+ Security) is the new standard for SSL.</para>
+
+ <para>Default: <command>ssl version = "ssl2or3"</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="STATCACHE">stat cache (G)</term>
+ <listitem><para>This parameter determines if <ulink
+ url="smbd.8.html">smbd(8)</ulink> will use a cache in order to
+ speed up case insensitive name mappings. You should never need
+ to change this parameter.</para>
+
+ <para>Default: <command>stat cache = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><anchor id="STATCACHESIZE">stat cache size (G)</term>
+ <listitem><para>This parameter determines the number of
+ entries in the <parameter>stat cache</parameter>. You should
+ never need to change this parameter.</para>
+
+ <para>Default: <command>stat cache size = 50</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="STATUS">status (G)</term>
+ <listitem><para>This enables or disables logging of connections
+ to a status file that <ulink url="smbstatus.1.html">smbstatus(1)</ulink>
+ can read.</para>
+
+ <para>With this disabled <command>smbstatus</command> won't be able
+ to tell you what connections are active. You should never need to
+ change this parameter.</para>
+
+ <para>Default: <command>status = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="STRICTALLOCATE">strict allocate (S)</term>
+ <listitem><para>This is a boolean that controls the handling of
+ disk space allocation in the server. When this is set to <constant>yes</constant>
+ the server will change from UNIX behaviour of not committing real
+ disk storage blocks when a file is extended to the Windows behaviour
+ of actually forcing the disk system to allocate real storage blocks
+ when a file is created or extended to be a given size. In UNIX
+ terminology this means that Samba will stop creating sparse files.
+ This can be slow on some systems.</para>
+
+ <para>When strict allocate is <constant>no</constant> the server does sparse
+ disk block allocation when a file is extended.</para>
+
+ <para>Setting this to <constant>yes</constant> can help Samba return
+ out of quota messages on systems that are restricting the disk quota
+ of users.</para>
+
+ <para>Default: <command>strict allocate = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="STRICTLOCKING">strict locking (S)</term>
+ <listitem><para>This is a boolean that controls the handling of
+ file locking in the server. When this is set to <constant>yes</constant>
+ the server will check every read and write access for file locks, and
+ deny access if locks exist. This can be slow on some systems.</para>
+
+ <para>When strict locking is <constant>no</constant> the server does file
+ lock checks only when the client explicitly asks for them.</para>
+
+ <para>Well-behaved clients always ask for lock checks when it
+ is important, so in the vast majority of cases <command>strict
+ locking = no</command> is preferable.</para>
+
+ <para>Default: <command>strict locking = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="STRICTSYNC">strict sync (S)</term>
+ <listitem><para>Many Windows applications (including the Windows
+ 98 explorer shell) seem to confuse flushing buffer contents to
+ disk with doing a sync to disk. Under UNIX, a sync call forces
+ the process to be suspended until the kernel has ensured that
+ all outstanding data in kernel disk buffers has been safely stored
+ onto stable storage. This is very slow and should only be done
+ rarely. Setting this parameter to <constant>no</constant> (the
+ default) means that <ulink url="smbd.8.html">smbd</ulink> ignores the Windows applications requests for
+ a sync call. There is only a possibility of losing data if the
+ operating system itself that Samba is running on crashes, so there is
+ little danger in this default setting. In addition, this fixes many
+ performance problems that people have reported with the new Windows98
+ explorer shell file copies.</para>
+
+ <para>See also the <link linkend="SYNCALWAYS"><parameter>sync
+ always></parameter></link> parameter.</para>
+
+ <para>Default: <command>strict sync = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="STRIPDOT">strip dot (G)</term>
+ <listitem><para>This is a boolean that controls whether to
+ strip trailing dots off UNIX filenames. This helps with some
+ CDROMs that have filenames ending in a single dot.</para>
+
+ <para>Default: <command>strip dot = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SYNCALWAYS">sync always (S)</term>
+ <listitem><para>This is a boolean parameter that controls
+ whether writes will always be written to stable storage before
+ the write call returns. If this is <constant>false</constant> then the server will be
+ guided by the client's request in each write call (clients can
+ set a bit indicating that a particular write should be synchronous).
+ If this is <constant>true</constant> then every write will be followed by a <command>fsync()
+ </command> call to ensure the data is written to disk. Note that
+ the <parameter>strict sync</parameter> parameter must be set to
+ <constant>yes</constant> in order for this parameter to have
+ any affect.</para>
+
+ <para>See also the <link linkend="STRICTSYNC"><parameter>strict
+ sync</parameter></link> parameter.</para>
+
+ <para>Default: <command>sync always = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SYSLOG">syslog (G)</term>
+ <listitem><para>This parameter maps how Samba debug messages
+ are logged onto the system syslog logging levels. Samba debug
+ level zero maps onto syslog <constant>LOG_ERR</constant>, debug
+ level one maps onto <constant>LOG_WARNING</constant>, debug level
+ two maps onto <constant>LOG_NOTICE</constant>, debug level three
+ maps onto LOG_INFO. All higher levels are mapped to <constant>
+ LOG_DEBUG</constant>.</para>
+
+ <para>This parameter sets the threshold for sending messages
+ to syslog. Only messages with debug level less than this value
+ will be sent to syslog.</para>
+
+ <para>Default: <command>syslog = 1</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="SYSLOGONLY">syslog only (G)</term>
+ <listitem><para>If this parameter is set then Samba debug
+ messages are logged into the system syslog only, and not to
+ the debug log files.</para>
+
+ <para>Default: <command>syslog only = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="TEMPLATEHOMEDIR">template homedir (G)</term>
+ <listitem><para>When filling out the user information for a Windows NT
+ user, the <ulink url="winbindd.8.html">winbindd(8)</ulink> daemon
+ uses this parameter to fill in the home directory for that user.
+ If the string <parameter>%D</parameter> is present it is substituted
+ with the user's Windows NT domain name. If the string <parameter>%U
+ </parameter> is present it is substituted with the user's Windows
+ NT user name.</para>
+
+ <para>Default: <command>template homedir = /home/%D/%U</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="TEMPLATESHELL">template shell (G)</term>
+ <listitem><para>When filling out the user information for a Windows NT
+ user, the <ulink url="winbindd.8.html">winbindd(8)</ulink> daemon
+ uses this parameter to fill in the login shell for that user.</para>
+
+ <para>Default: <command>template shell = /bin/false</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="TIMEOFFSET">time offset (G)</term>
+ <listitem><para>This parameter is a setting in minutes to add
+ to the normal GMT to local time conversion. This is useful if
+ you are serving a lot of PCs that have incorrect daylight
+ saving time handling.</para>
+
+ <para>Default: <command>time offset = 0</command></para>
+ <para>Example: <command>time offset = 60</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="TIMESERVER">time server (G)</term>
+ <listitem><para>This parameter determines if <ulink url="nmbd.8.html">
+ nmbd(8)</ulink> advertises itself as a time server to Windows
+ clients.</para>
+
+ <para>Default: <command>time server = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="TIMESTAMPLOGS">timestamp logs (G)</term>
+ <listitem><para>Synonym for <link linkend="DEBUGTIMESTAMP"><parameter>
+ debug timestamp</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="TOTALPRINTJOBS">total print jobs (G)</term>
+ <listitem><para>This parameter accepts an integer value which defines
+ a limit on the maximum number of print jobs that will be accepted
+ system wide at any given time. If a print job is submitted
+ by a client which will exceed this number, then <ulink url="smbd.8.html">smbd</ulink> will return an
+ error indicating that no space is available on the server. The
+ default value of 0 means that no such limit exists. This parameter
+ can be used to prevent a server from exceeding its capacity and is
+ designed as a printing throttle. See also
+ <link linkend="MAXPRINTJOBS"><parameter>max print jobs</parameter</link>.
+ </para>
+
+ <para>Default: <command>total print jobs = 0</command></para>
+ <para>Example: <command>total print jobs = 5000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="UNIXPASSWORDSYNC">unix password sync (G)</term>
+ <listitem><para>This boolean parameter controls whether Samba
+ attempts to synchronize the UNIX password with the SMB password
+ when the encrypted SMB password in the smbpasswd file is changed.
+ If this is set to <constant>true</constant> the program specified in the <parameter>passwd
+ program</parameter>parameter is called <emphasis>AS ROOT</emphasis> -
+ to allow the new UNIX password to be set without access to the
+ old UNIX password (as the SMB password change code has no
+ access to the old password cleartext, only the new).</para>
+
+ <para>See also <link linkend="PASSWDPROGRAM"><parameter>passwd
+ program</parameter></link>, <link linkend="PASSWDCHAT"><parameter>
+ passwd chat</parameter></link>.</para>
+
+ <para>Default: <command>unix password sync = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="UPDATEENCRYPTED">update encrypted (G)</term>
+ <listitem><para>This boolean parameter allows a user logging
+ on with a plaintext password to have their encrypted (hashed)
+ password in the smbpasswd file to be updated automatically as
+ they log on. This option allows a site to migrate from plaintext
+ password authentication (users authenticate with plaintext
+ password over the wire, and are checked against a UNIX account
+ database) to encrypted password authentication (the SMB
+ challenge/response authentication mechanism) without forcing
+ all users to re-enter their passwords via smbpasswd at the time the
+ change is made. This is a convenience option to allow the change over
+ to encrypted passwords to be made over a longer period. Once all users
+ have encrypted representations of their passwords in the smbpasswd
+ file this parameter should be set to <constant>no</constant>.</para>
+
+ <para>In order for this parameter to work correctly the <link
+ linkend="ENCRYPTPASSWORDS"><parameter>encrypt passwords</parameter>
+ </link> parameter must be set to <constant>no</constant> when
+ this parameter is set to <constant>yes</constant>.</para>
+
+ <para>Note that even when this parameter is set a user
+ authenticating to <command>smbd</command> must still enter a valid
+ password in order to connect correctly, and to update their hashed
+ (smbpasswd) passwords.</para>
+
+ <para>Default: <command>update encrypted = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="USECLIENTDRIVER">use client driver (S)</term>
+ <listitem><para>This parameter applies only to Windows NT/2000
+ clients. It has no affect on Windows 95/98/ME clients. When
+ serving a printer to Windows NT/2000 clients without first installing
+ a valid printer driver on the Samba host, the client will be required
+ to install a local printer driver. From this point on, the client
+ will treat the print as a local printer and not a network printer
+ connection. This is much the same behavior that will occur
+ when <command>disable spoolss = yes</command>. </para>
+
+ <para>The differentiating
+ factor is that under normal circumstances, the NT/2000 client will
+ attempt to open the network printer using MS-RPC. The problem is that
+ because the client considers the printer to be local, it will attempt
+ to issue the OpenPrinterEx() call requesting access rights associated
+ with the logged on user. If the user possesses local administator rights
+ but not root privilegde on the Samba host (often the case), the OpenPrinterEx()
+ call will fail. The result is that the client will now display an "Access
+ Denied; Unable to connect" message in the printer queue window (even though
+ jobs may successfully be printed). </para>
+
+ <para>If this parameter is enabled for a printer, then any attempt
+ to open the printer with the PRINTER_ACCESS_ADMINISTER right is mapped
+ to PRINTER_ACCESS_USE instead. Thus allowing the OpenPrinterEx()
+ call to succeed. <emphasis>This parameter MUST not be able enabled
+ on a print share which has valid print driver installed on the Samba
+ server.</emphasis></para>
+
+ <para>See also <link linkend="DISABLESPOOLSS">disable spoolss</link>
+ </para>
+
+ <para>Default: <command>use client driver = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="USEMMAP">use mmap (G)</term>
+ <listitem><para>This global parameter determines if the tdb internals of Samba can
+ depend on mmap working correctly on the running system. Samba requires a coherent
+ mmap/read-write system memory cache. Currently only HPUX does not have such a
+ coherent cache, and so this parameter is set to <constant>false</constant> by
+ default on HPUX. On all other systems this parameter should be left alone. This
+ parameter is provided to help the Samba developers track down problems with
+ the tdb internal code.
+ </para>
+
+ <para>Default: <command>use mmap = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="USERHOSTS">use rhosts (G)</term>
+ <listitem><para>If this global parameter is <constant>true</constant>, it specifies
+ that the UNIX user's <filename>.rhosts</filename> file in their home directory
+ will be read to find the names of hosts and users who will be allowed
+ access without specifying a password.</para>
+
+ <para><emphasis>NOTE:</emphasis> The use of <parameter>use rhosts
+ </parameter> can be a major security hole. This is because you are
+ trusting the PC to supply the correct username. It is very easy to
+ get a PC to supply a false username. I recommend that the <parameter>
+ use rhosts</parameter> option be only used if you really know what
+ you are doing.</para>
+
+ <para>Default: <command>use rhosts = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="USER">user (S)</term>
+ <listitem><para>Synonym for <link linkend="USERNAME"><parameter>
+ username</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="USERS">users (S)</term>
+ <listitem><para>Synonym for <link linkend="USERNAME"><parameter>
+ username</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="USERNAME">username (S)</term>
+ <listitem><para>Multiple users may be specified in a comma-delimited
+ list, in which case the supplied password will be tested against
+ each username in turn (left to right).</para>
+
+ <para>The <parameter>username</parameter> line is needed only when
+ the PC is unable to supply its own username. This is the case
+ for the COREPLUS protocol or where your users have different WfWg
+ usernames to UNIX usernames. In both these cases you may also be
+ better using the \\server\share%user syntax instead.</para>
+
+ <para>The <parameter>username</parameter> line is not a great
+ solution in many cases as it means Samba will try to validate
+ the supplied password against each of the usernames in the
+ <parameter>username</parameter> line in turn. This is slow and
+ a bad idea for lots of users in case of duplicate passwords.
+ You may get timeouts or security breaches using this parameter
+ unwisely.</para>
+
+ <para>Samba relies on the underlying UNIX security. This
+ parameter does not restrict who can login, it just offers hints
+ to the Samba server as to what usernames might correspond to the
+ supplied password. Users can login as whoever they please and
+ they will be able to do no more damage than if they started a
+ telnet session. The daemon runs as the user that they log in as,
+ so they cannot do anything that user cannot do.</para>
+
+ <para>To restrict a service to a particular set of users you
+ can use the <link linkend="VALIDUSERS"><parameter>valid users
+ </parameter></link> parameter.</para>
+
+ <para>If any of the usernames begin with a '@' then the name
+ will be looked up first in the NIS netgroups list (if Samba
+ is compiled with netgroup support), followed by a lookup in
+ the UNIX groups database and will expand to a list of all users
+ in the group of that name.</para>
+
+ <para>If any of the usernames begin with a '+' then the name
+ will be looked up only in the UNIX groups database and will
+ expand to a list of all users in the group of that name.</para>
+
+ <para>If any of the usernames begin with a '&'then the name
+ will be looked up only in the NIS netgroups database (if Samba
+ is compiled with netgroup support) and will expand to a list
+ of all users in the netgroup group of that name.</para>
+
+ <para>Note that searching though a groups database can take
+ quite some time, and some clients may time out during the
+ search.</para>
+
+ <para>See the section <link linkend="VALIDATIONSECT">NOTE ABOUT
+ USERNAME/PASSWORD VALIDATION</link> for more information on how
+ this parameter determines access to the services.</para>
+
+ <para>Default: <command>The guest account if a guest service,
+ else &lt;empty string&gt;.</command></para>
+
+ <para>Examples:<command>username = fred, mary, jack, jane,
+ @users, @pcgroup</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="USERNAMELEVEL">username level (G)</term>
+ <listitem><para>This option helps Samba to try and 'guess' at
+ the real UNIX username, as many DOS clients send an all-uppercase
+ username. By default Samba tries all lowercase, followed by the
+ username with the first letter capitalized, and fails if the
+ username is not found on the UNIX machine.</para>
+
+ <para>If this parameter is set to non-zero the behavior changes.
+ This parameter is a number that specifies the number of uppercase
+ combinations to try while trying to determine the UNIX user name. The
+ higher the number the more combinations will be tried, but the slower
+ the discovery of usernames will be. Use this parameter when you have
+ strange usernames on your UNIX machine, such as <constant>AstrangeUser
+ </constant>.</para>
+
+ <para>Default: <command>username level = 0</command></para>
+ <para>Example: <command>username level = 5</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="USERNAMEMAP">username map (G)</term>
+ <listitem><para>This option allows you to specify a file containing
+ a mapping of usernames from the clients to the server. This can be
+ used for several purposes. The most common is to map usernames
+ that users use on DOS or Windows machines to those that the UNIX
+ box uses. The other is to map multiple users to a single username
+ so that they can more easily share files.</para>
+
+ <para>The map file is parsed line by line. Each line should
+ contain a single UNIX username on the left then a '=' followed
+ by a list of usernames on the right. The list of usernames on the
+ right may contain names of the form @group in which case they
+ will match any UNIX username in that group. The special client
+ name '*' is a wildcard and matches any name. Each line of the
+ map file may be up to 1023 characters long.</para>
+
+ <para>The file is processed on each line by taking the
+ supplied username and comparing it with each username on the right
+ hand side of the '=' signs. If the supplied name matches any of
+ the names on the right hand side then it is replaced with the name
+ on the left. Processing then continues with the next line.</para>
+
+ <para>If any line begins with a '#' or a ';' then it is
+ ignored</para>
+
+ <para>If any line begins with an '!' then the processing
+ will stop after that line if a mapping was done by the line.
+ Otherwise mapping continues with every line being processed.
+ Using '!' is most useful when you have a wildcard mapping line
+ later in the file.</para>
+
+ <para>For example to map from the name <constant>admin</constant>
+ or <constant>administrator</constant> to the UNIX name <constant>
+ root</constant> you would use:</para>
+
+ <para><command>root = admin administrator</command></para>
+
+ <para>Or to map anyone in the UNIX group <constant>system</constant>
+ to the UNIX name <constant>sys</constant> you would use:</para>
+
+ <para><command>sys = @system</command></para>
+
+ <para>You can have as many mappings as you like in a username
+ map file.</para>
+
+
+ <para>If your system supports the NIS NETGROUP option then
+ the netgroup database is checked before the <filename>/etc/group
+ </filename> database for matching groups.</para>
+
+ <para>You can map Windows usernames that have spaces in them
+ by using double quotes around the name. For example:</para>
+
+ <para><command>tridge = "Andrew Tridgell"</command></para>
+
+ <para>would map the windows username "Andrew Tridgell" to the
+ unix username "tridge".</para>
+
+ <para>The following example would map mary and fred to the
+ unix user sys, and map the rest to guest. Note the use of the
+ '!' to tell Samba to stop processing if it gets a match on
+ that line.</para>
+
+ <para><programlisting>
+ !sys = mary fred
+ guest = *
+ </programlisting></para>
+
+ <para>Note that the remapping is applied to all occurrences
+ of usernames. Thus if you connect to \\server\fred and <constant>
+ fred</constant> is remapped to <constant>mary</constant> then you
+ will actually be connecting to \\server\mary and will need to
+ supply a password suitable for <constant>mary</constant> not
+ <constant>fred</constant>. The only exception to this is the
+ username passed to the <link linkend="PASSWORDSERVER"><parameter>
+ password server</parameter></link> (if you have one). The password
+ server will receive whatever username the client supplies without
+ modification.</para>
+
+ <para>Also note that no reverse mapping is done. The main effect
+ this has is with printing. Users who have been mapped may have
+ trouble deleting print jobs as PrintManager under WfWg will think
+ they don't own the print job.</para>
+
+ <para>Default: <emphasis>no username map</emphasis></para>
+ <para>Example: <command>username map = /usr/local/samba/lib/users.map
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="UTMP">utmp (G)</term>
+ <listitem><para>This boolean parameter is only available if
+ Samba has been configured and compiled with the option <command>
+ --with-utmp</command>. If set to <constant>true</constant> then Samba will attempt
+ to add utmp or utmpx records (depending on the UNIX system) whenever a
+ connection is made to a Samba server. Sites may use this to record the
+ user connecting to a Samba share.</para>
+
+ <para>See also the <link linkend="UTMPDIRECTORY"><parameter>
+ utmp directory</parameter></link> parameter.</para>
+
+ <para>Default: <command>utmp = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="UTMPDIRECTORY">utmp directory(G)</term>
+ <listitem><para>This parameter is only available if Samba has
+ been configured and compiled with the option <command>
+ --with-utmp</command>. It specifies a directory pathname that is
+ used to store the utmp or utmpx files (depending on the UNIX system) that
+ record user connections to a Samba server. See also the <link linkend="UTMP">
+ <parameter>utmp</parameter></link> parameter. By default this is
+ not set, meaning the system will use whatever utmp file the
+ native system is set to use (usually
+ <filename>/var/run/utmp</filename> on Linux).</para>
+
+ <para>Default: <emphasis>no utmp directory</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="VALIDCHARS">valid chars (G)</term>
+ <listitem><para>The option allows you to specify additional
+ characters that should be considered valid by the server in
+ filenames. This is particularly useful for national character
+ sets, such as adding u-umlaut or a-ring.</para>
+
+ <para>The option takes a list of characters in either integer
+ or character form with spaces between them. If you give two
+ characters with a colon between them then it will be taken as
+ an lowercase:uppercase pair.</para>
+
+ <para>If you have an editor capable of entering the characters
+ into the config file then it is probably easiest to use this
+ method. Otherwise you can specify the characters in octal,
+ decimal or hexadecimal form using the usual C notation.</para>
+
+ <para>For example to add the single character 'Z' to the charset
+ (which is a pointless thing to do as it's already there) you could
+ do one of the following</para>
+
+ <para><programlisting>
+ valid chars = Z
+ valid chars = z:Z
+ valid chars = 0132:0172
+ </programlisting></para>
+
+ <para>The last two examples above actually add two characters,
+ and alter the uppercase and lowercase mappings appropriately.</para>
+
+ <para>Note that you <emphasis>MUST</emphasis> specify this parameter
+ after the <parameter>client code page</parameter> parameter if you
+ have both set. If <parameter>client code page</parameter> is set after
+ the <parameter>valid chars</parameter> parameter the <parameter>valid
+ chars</parameter> settings will be overwritten.</para>
+
+ <para>See also the <link linkend="CLIENTCODEPAGE"><parameter>client
+ code page</parameter></link> parameter.</para>
+
+ <para>Default: <emphasis>Samba defaults to using a reasonable set
+ of valid characters for English systems</emphasis></para>
+
+ <para>Example: <command>valid chars = 0345:0305 0366:0326 0344:0304
+ </command></para>
+
+ <para>The above example allows filenames to have the Swedish
+ characters in them.</para>
+
+ <para><emphasis>NOTE:</emphasis> It is actually quite difficult to
+ correctly produce a <parameter>valid chars</parameter> line for
+ a particular system. To automate the process <ulink
+ url="mailto:tino@augsburg.net">tino@augsburg.net</ulink> has written
+ a package called <command>validchars</command> which will automatically
+ produce a complete <parameter>valid chars</parameter> line for
+ a given client system. Look in the <filename>examples/validchars/
+ </filename> subdirectory of your Samba source code distribution
+ for this package.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="VALIDUSERS">valid users (S)</term>
+ <listitem><para>This is a list of users that should be allowed
+ to login to this service. Names starting with '@', '+' and '&'
+ are interpreted using the same rules as described in the
+ <parameter>invalid users</parameter> parameter.</para>
+
+ <para>If this is empty (the default) then any user can login.
+ If a username is in both this list and the <parameter>invalid
+ users</parameter> list then access is denied for that user.</para>
+
+ <para>The current servicename is substituted for <parameter>%S
+ </parameter>. This is useful in the [homes] section.</para>
+
+ <para>See also <link linkend="INVALIDUSERS"><parameter>invalid users
+ </parameter></link></para>
+
+ <para>Default: <emphasis>No valid users list (anyone can login)
+ </emphasis></para>
+
+ <para>Example: <command>valid users = greg, @pcusers</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="VETOFILES">veto files(S)</term>
+ <listitem><para>This is a list of files and directories that
+ are neither visible nor accessible. Each entry in the list must
+ be separated by a '/', which allows spaces to be included
+ in the entry. '*' and '?' can be used to specify multiple files
+ or directories as in DOS wildcards.</para>
+
+ <para>Each entry must be a unix path, not a DOS path and
+ must <emphasis>not</emphasis> include the unix directory
+ separator '/'.</para>
+
+ <para>Note that the <parameter>case sensitive</parameter> option
+ is applicable in vetoing files.</para>
+
+ <para>One feature of the veto files parameter that it
+ is important to be aware of is Samba's behaviour when
+ trying to delete a directory. If a directory that is
+ to be deleted contains nothing but veto files this
+ deletion will <emphasis>fail</emphasis> unless you also set
+ the <parameter>delete veto files</parameter> parameter to
+ <parameter>yes</parameter>.</para>
+
+ <para>Setting this parameter will affect the performance
+ of Samba, as it will be forced to check all files and directories
+ for a match as they are scanned.</para>
+
+ <para>See also <link linkend="HIDEFILES"><parameter>hide files
+ </parameter></link> and <link linkend="CASESENSITIVE"><parameter>
+ case sensitive</parameter></link>.</para>
+
+ <para>Default: <emphasis>No files or directories are vetoed.
+ </emphasis></para>
+
+<para>Examples:<programlisting>
+; Veto any files containing the word Security,
+; any ending in .tmp, and any directory containing the
+; word root.
+veto files = /*Security*/*.tmp/*root*/
+
+; Veto the Apple specific files that a NetAtalk server
+; creates.
+veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/
+</programlisting></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="VETOOPLOCKFILES">veto oplock files (S)</term>
+ <listitem><para>This parameter is only valid when the <link
+ linkend="OPLOCKS"><parameter>oplocks</parameter></link>
+ parameter is turned on for a share. It allows the Samba administrator
+ to selectively turn off the granting of oplocks on selected files that
+ match a wildcarded list, similar to the wildcarded list used in the
+ <link linkend="VETOFILES"><parameter>veto files</parameter></link>
+ parameter.</para>
+
+ <para>Default: <emphasis>No files are vetoed for oplock
+ grants</emphasis></para>
+
+ <para>You might want to do this on files that you know will
+ be heavily contended for by clients. A good example of this
+ is in the NetBench SMB benchmark program, which causes heavy
+ client contention for files ending in <filename>.SEM</filename>.
+ To cause Samba not to grant oplocks on these files you would use
+ the line (either in the [global] section or in the section for
+ the particular NetBench share :</para>
+
+ <para>Example: <command>veto oplock files = /*.SEM/
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="VFSOBJECT">vfs object (S)</term>
+ <listitem><para>This parameter specifies a shared object file that
+ is used for Samba VFS I/O operations. By default, normal
+ disk I/O operations are used but these can be overloaded
+ with a VFS object. The Samba VFS layer is new to Samba 2.2 and
+ must be enabled at compile time with --with-vfs.</para>
+
+ <para>Default : <emphasis>no value</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="VFSOPTIONS">vfs options (S)</term>
+ <listitem><para>This parameter allows parameters to be passed
+ to the vfs layer at initialization time. The Samba VFS layer
+ is new to Samba 2.2 and must be enabled at compile time
+ with --with-vfs. See also <link linkend="VFSOBJECT"><parameter>
+ vfs object</parameter></link>.</para>
+
+ <para>Default : <emphasis>no value</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="VOLUME">volume (S)</term>
+ <listitem><para> This allows you to override the volume label
+ returned for a share. Useful for CDROMs with installation programs
+ that insist on a particular volume label.</para>
+
+ <para>Default: <emphasis>the name of the share</emphasis></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WIDELINKS">wide links (S)</term>
+ <listitem><para>This parameter controls whether or not links
+ in the UNIX file system may be followed by the server. Links
+ that point to areas within the directory tree exported by the
+ server are always allowed; this parameter controls access only
+ to areas that are outside the directory tree being exported.</para>
+
+ <para>Note that setting this parameter can have a negative
+ effect on your server performance due to the extra system calls
+ that Samba has to do in order to perform the link checks.</para>
+
+ <para>Default: <command>wide links = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WINBINDCACHETIME">winbind cache time</term>
+ <listitem><para>This parameter specifies the number of seconds the
+ <ulink url="winbindd.8.html">winbindd(8)</ulink> daemon will cache
+ user and group information before querying a Windows NT server
+ again.</para>
+
+ <para>Default: <command>winbind cache type = 15</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="WINBINDENUMUSERS">winbind enum
+ users</term> <listitem><para>On large installations using
+ <ulink url="winbindd.8.html">winbindd(8)</ulink> it may be
+ necessary to suppress the enumeration of users through the
+ <command> setpwent()</command>,
+ <command>getpwent()</command> and
+ <command>endpwent()</command> group of system calls. If
+ the <parameter>winbind enum users</parameter> parameter is
+ false, calls to the <command>getpwent</command> system call
+ will not return any data. </para>
+
+ <para><emphasis>Warning:</emphasis> Turning off user
+ enumeration may cause some programs to behave oddly. For
+ example, the finger program relies on having access to the
+ full user list when searching for matching
+ usernames. </para>
+
+ <para>Default: <command>winbind enum users = yes </command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><anchor id="WINBINDENUMGROUPS">winbind enum
+ groups</term> <listitem><para>On large installations using
+ <ulink url="winbindd.8.html">winbindd(8)</ulink> it may be
+ necessary to suppress the enumeration of groups through the
+ <command> setgrent()</command>,
+ <command>getgrent()</command> and
+ <command>endgrent()</command> group of system calls. If
+ the <parameter>winbind enum groups</parameter> parameter is
+ false, calls to the <command>getgrent()</command> system
+ call will not return any data. </para>
+
+ <para><emphasis>Warning:</emphasis> Turning off group
+ enumeration may cause some programs to behave oddly.
+ </para>
+
+ <para>Default: <command>winbind enum groups = yes </command>
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="WINBINDGID">winbind gid</term>
+ <listitem><para>The winbind gid parameter specifies the range of group
+ ids that are allocated by the <ulink url="winbindd.8.html">
+ winbindd(8)</ulink> daemon. This range of group ids should have no
+ existing local or NIS groups within it as strange conflicts can
+ occur otherwise.</para>
+
+ <para>Default: <command>winbind gid = &lt;empty string&gt;
+ </command></para>
+
+ <para>Example: <command>winbind gid = 10000-20000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><anchor id="WINBINDSEPARATOR">winbind separator</term>
+ <listitem><para>This parameter allows an admin to define the character
+ used when listing a username of the form of <replaceable>DOMAIN
+ </replaceable>\<replaceable>user</replaceable>. This parameter
+ is only applicable when using the <filename>pam_winbind.so</filename>
+ and <filename>nss_winbind.so</filename> modules for UNIX services.
+ </para>
+
+ <para>Example: <command>winbind separator = \</command></para>
+ <para>Example: <command>winbind separator = +</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WINBINDUID">winbind uid</term>
+ <listitem><para>The winbind gid parameter specifies the range of group
+ ids that are allocated by the <ulink url="winbindd.8.html">
+ winbindd(8)</ulink> daemon. This range of ids should have no
+ existing local or NIS users within it as strange conflicts can
+ occur otherwise.</para>
+
+ <para>Default: <command>winbind uid = &lt;empty string&gt;
+ </command></para>
+
+ <para>Example: <command>winbind uid = 10000-20000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WINSHOOK">wins hook (G)</term>
+ <listitem><para>When Samba is running as a WINS server this
+ allows you to call an external program for all changes to the
+ WINS database. The primary use for this option is to allow the
+ dynamic update of external name resolution databases such as
+ dynamic DNS.</para>
+
+ <para>The wins hook parameter specifies the name of a script
+ or executable that will be called as follows:</para>
+
+ <para><command>wins_hook operation name nametype ttl IP_list
+ </command></para>
+
+ <itemizedlist>
+ <listitem><para>The first argument is the operation and is one
+ of "add", "delete", or "refresh". In most cases the operation can
+ be ignored as the rest of the parameters provide sufficient
+ information. Note that "refresh" may sometimes be called when the
+ name has not previously been added, in that case it should be treated
+ as an add.</para></listitem>
+
+ <listitem><para>The second argument is the NetBIOS name. If the
+ name is not a legal name then the wins hook is not called.
+ Legal names contain only letters, digits, hyphens, underscores
+ and periods.</para></listitem>
+
+ <listitem><para>The third argument is the NetBIOS name
+ type as a 2 digit hexadecimal number. </para></listitem>
+
+ <listitem><para>The fourth argument is the TTL (time to live)
+ for the name in seconds.</para></listitem>
+
+ <listitem><para>The fifth and subsequent arguments are the IP
+ addresses currently registered for that name. If this list is
+ empty then the name should be deleted.</para></listitem>
+ </itemizedlist>
+
+ <para>An example script that calls the BIND dynamic DNS update
+ program <command>nsupdate</command> is provided in the examples
+ directory of the Samba source code. </para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WINSPROXY">wins proxy (G)</term>
+ <listitem><para>This is a boolean that controls if <ulink
+ url="nmbd.8.html">nmbd(8)</ulink> will respond to broadcast name
+ queries on behalf of other hosts. You may need to set this
+ to <constant>yes</constant> for some older clients.</para>
+
+ <para>Default: <command>wins proxy = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WINSSERVER">wins server (G)</term>
+ <listitem><para>This specifies the IP address (or DNS name: IP
+ address for preference) of the WINS server that <ulink url="nmbd.8.html">
+ nmbd(8)</ulink> should register with. If you have a WINS server on
+ your network then you should set this to the WINS server's IP.</para>
+
+ <para>You should point this at your WINS server if you have a
+ multi-subnetted network.</para>
+
+ <para><emphasis>NOTE</emphasis>. You need to set up Samba to point
+ to a WINS server if you have multiple subnets and wish cross-subnet
+ browsing to work correctly.</para>
+
+ <para>See the documentation file <filename>BROWSING.txt</filename>
+ in the docs/ directory of your Samba source distribution.</para>
+
+ <para>Default: <emphasis>not enabled</emphasis></para>
+ <para>Example: <command>wins server = 192.9.200.1</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WINSSUPPORT">wins support (G)</term>
+ <listitem><para>This boolean controls if the <ulink url="nmbd.8.html">
+ nmbd(8)</ulink> process in Samba will act as a WINS server. You should
+ not set this to <constant>true</constant> unless you have a multi-subnetted network and
+ you wish a particular <command>nmbd</command> to be your WINS server.
+ Note that you should <emphasis>NEVER</emphasis> set this to <constant>true</constant>
+ on more than one machine in your network.</para>
+
+ <para>Default: <command>wins support = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WORKGROUP">workgroup (G)</term>
+ <listitem><para>This controls what workgroup your server will
+ appear to be in when queried by clients. Note that this parameter
+ also controls the Domain name used with the <link
+ linkend="SECURITYEQUALSDOMAIN"><command>security = domain</command></link>
+ setting.</para>
+
+ <para>Default: <emphasis>set at compile time to WORKGROUP</emphasis></para>
+ <para>Example: <command>workgroup = MYGROUP</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITABLE">writable (S)</term>
+ <listitem><para>Synonym for <link linkend="WRITEABLE"><parameter>
+ writeable</parameter></link> for people who can't spell :-).</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITECACHESIZE">write cache size (S)</term>
+ <listitem><para>If this integer parameter is set to non-zero value,
+ Samba will create an in-memory cache for each oplocked file
+ (it does <emphasis>not</emphasis> do this for
+ non-oplocked files). All writes that the client does not request
+ to be flushed directly to disk will be stored in this cache if possible.
+ The cache is flushed onto disk when a write comes in whose offset
+ would not fit into the cache or when the file is closed by the client.
+ Reads for the file are also served from this cache if the data is stored
+ within it.</para>
+
+ <para>This cache allows Samba to batch client writes into a more
+ efficient write size for RAID disks (i.e. writes may be tuned to
+ be the RAID stripe size) and can improve performance on systems
+ where the disk subsystem is a bottleneck but there is free
+ memory for userspace programs.</para>
+
+ <para>The integer parameter specifies the size of this cache
+ (per oplocked file) in bytes.</para>
+
+ <para>Default: <command>write cache size = 0</command></para>
+ <para>Example: <command>write cache size = 262144</command></para>
+
+ <para>for a 256k cache size per file.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITELIST">write list (S)</term>
+ <listitem><para>This is a list of users that are given read-write
+ access to a service. If the connecting user is in this list then
+ they will be given write access, no matter what the <link
+ linkend="WRITEABLE"><parameter>writeable</parameter></link>
+ option is set to. The list can include group names using the
+ @group syntax.</para>
+
+ <para>Note that if a user is in both the read list and the
+ write list then they will be given write access.</para>
+
+ <para>See also the <link linkend="READLIST"><parameter>read list
+ </parameter></link> option.</para>
+
+ <para>Default: <command>write list = &lt;empty string&gt;
+ </command></para>
+
+ <para>Example: <command>write list = admin, root, @staff
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITEOK">write ok (S)</term>
+ <listitem><para>Synonym for <link linkend="WRITEABLE"><parameter>
+ writeable</parameter></link>.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITERAW">write raw (G)</term>
+ <listitem><para>This parameter controls whether or not the server
+ will support raw write SMB's when transferring data from clients.
+ You should never need to change this parameter.</para>
+
+ <para>Default: <command>write raw = yes</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="WRITEABLE">writeable (S)</term>
+ <listitem><para>An inverted synonym is <link linkend="READONLY">
+ <parameter>read only</parameter></link>.</para>
+
+ <para>If this parameter is <constant>no</constant>, then users
+ of a service may not create or modify files in the service's
+ directory.</para>
+
+ <para>Note that a printable service (<command>printable = yes</command>)
+ will <emphasis>ALWAYS</emphasis> allow writing to the directory
+ (user privileges permitting), but only via spooling operations.</para>
+
+ <para>Default: <command>writeable = no</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>WARNINGS</title>
+
+ <para>Although the configuration file permits service names
+ to contain spaces, your client software may not. Spaces will
+ be ignored in comparisons anyway, so it shouldn't be a
+ problem - but be aware of the possibility.</para>
+
+ <para>On a similar note, many clients - especially DOS clients -
+ limit service names to eight characters. <ulink url="smbd.8.html">smbd(8)
+ </ulink> has no such limitation, but attempts to connect from such
+ clients will fail if they truncate the service names. For this reason
+ you should probably keep your service names down to eight characters
+ in length.</para>
+
+ <para>Use of the [homes] and [printers] special sections make life
+ for an administrator easy, but the various combinations of default
+ attributes can be tricky. Take extreme care when designing these
+ sections. In particular, ensure that the permissions on spool
+ directories are correct.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="samba.7.html">samba(7)</ulink>,
+ <ulink url="smbpasswd.8.html"><command>smbpasswd(8)</command></ulink>,
+ <ulink url="swat.8.html"><command>swat(8)</command></ulink>,
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="nmbd.8.html"><command>nmbd(8)</command></ulink>,
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command></ulink>,
+ <ulink url="nmblookup.1.html"><command>nmblookup(1)</command></ulink>,
+ <ulink url="testparm.1.html"><command>testparm(1)</command></ulink>,
+ <ulink url="testprns.1.html"><command>testprns(1)</command></ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbcacls.1.sgml b/docs/docbook/manpages/smbcacls.1.sgml
new file mode 100644
index 00000000000..69aa9674928
--- /dev/null
+++ b/docs/docbook/manpages/smbcacls.1.sgml
@@ -0,0 +1,255 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbcacls">
+
+<refmeta>
+ <refentrytitle>smbcacls</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbcacls</refname>
+ <refpurpose>Set or get ACLs on an NT file or directory names</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbcacls</command>
+ <arg choice="req">//server/share</arg>
+ <arg choice="req">filename</arg>
+ <arg choice="opt">-U username</arg>
+ <arg choice="opt">-A acls</arg>
+ <arg choice="opt">-M acls</arg>
+ <arg choice="opt">-D acls</arg>
+ <arg choice="opt">-S acls</arg>
+ <arg choice="opt">-C name</arg>
+ <arg choice="opt">-G name</arg>
+ <arg choice="opt">-n</arg>
+ <arg choice="opt">-h</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para>The <command>smbcacls</command> program manipulates NT Access Control Lists
+ (ACLs) on SMB file shares. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <para>The following options are available to the <command>smbcacls</command> program.
+ The format of ACLs is described in the section ACL FORMAT </para>
+
+
+ <variablelist>
+ <varlistentry>
+ <term>-A acls</term>
+ <listitem><para>Add the ACLs specified to the ACL list. Existing
+ access control entries are unchanged. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-M acls</term>
+ <listitem><para>Modify the mask value (permissions) for the ACLs
+ specified on the command line. An error will be printed for each
+ ACL specified that was not already present in the ACL list
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-D acls</term>
+ <listitem><para>Delete any ACLs specified on the command line.
+ An error will be printed for each ACL specified that was not
+ already present in the ACL list. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-S acls</term>
+ <listitem><para>This command sets the ACLs on the file with
+ only the ones specified on the command line. All other ACLs are
+ erased. Note that the ACL specified must contain at least a revision,
+ type, owner and group for the call to succeed. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-U username</term>
+ <listitem><para>Specifies a username used to connect to the
+ specified service. The username may be of the form "username" in
+ which case the user is prompted to enter in a password and the
+ workgroup specified in the <filename>smb.conf</filename> file is
+ used, or "username%password" or "DOMAIN\username%password" and the
+ password and workgroup names are used as provided. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-C name</term>
+ <listitem><para>The owner of a file or directory can be changed
+ to the name given using the <parameter>-C</parameter> option.
+ The name can be a sid in the form S-1-x-y-z or a name resolved
+ against the server specified in the first argument. </para>
+
+ <para>This command is a shortcut for -M OWNER:name.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-G name</term>
+ <listitem><para>The group owner of a file or directory can
+ be changed to the name given using the <parameter>-G</parameter>
+ option. The name can be a sid in the form S-1-x-y-z or a name
+ resolved against the server specified n the first argument.
+ </para>
+
+ <para>This command is a shortcut for -M GROUP:name.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-n</term>
+ <listitem><para>This option displays all ACL information in numeric
+ format. The default is to convert SIDs to names and ACE types
+ and masks to a readable string format. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Print usage information on the <command>smbcacls
+ </command> program.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>ACL FORMAT</title>
+
+ <para>The format of an ACL is one or more ACL entries separated by
+ either commas or newlines. An ACL entry is one of the following: </para>
+
+ <para><programlisting>
+REVISION:&lt;revision number&gt;
+OWNER:&lt;sid or name&gt;
+GROUP:&lt;sid or name&gt;
+ACL:&lt;sid or name&gt;:&lt;type&gt;/&lt;flags&gt;/&lt;mask&gt;
+ </programlisting></para>
+
+
+ <para>The revision of the ACL specifies the internal Windows
+ NT ACL revision for the security descriptor.
+ If not specified it defaults to 1. Using values other than 1 may
+ cause strange behaviour. </para>
+
+ <para>The owner and group specify the owner and group sids for the
+ object. If a SID in the format CWS-1-x-y-z is specified this is used,
+ otherwise the name specified is resolved using the server on which
+ the file or directory resides. </para>
+
+ <para>ACLs specify permissions granted to the SID. This SID again
+ can be specified in CWS-1-x-y-z format or as a name in which case
+ it is resolved against the server on which the file or directory
+ resides. The type, flags and mask values determine the type of
+ access granted to the SID. </para>
+
+ <para>The type can be either 0 or 1 corresponding to ALLOWED or
+ DENIED access to the SID. The flags values are generally
+ zero for file ACLs and either 9 or 2 for directory ACLs. Some
+ common flags are: </para>
+
+ <itemizedlist>
+ <listitem><para>#define SEC_ACE_FLAG_OBJECT_INHERIT 0x1</para></listitem>
+ <listitem><para>#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x2</para></listitem>
+ <listitem><para>#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x4
+ </para></listitem>
+ <listitem><para>#define SEC_ACE_FLAG_INHERIT_ONLY 0x8</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>At present flags can only be specified as decimal or
+ hexadecimal values.</para>
+
+ <para>The mask is a value which expresses the access right
+ granted to the SID. It can be given as a decimal or hexadecimal value,
+ or by using one of the following text strings which map to the NT
+ file permissions of the same name. </para>
+
+ <itemizedlist>
+ <listitem><para><emphasis>R</emphasis> - Allow read access </para></listitem>
+ <listitem><para><emphasis>W</emphasis> - Allow write access</para></listitem>
+ <listitem><para><emphasis>X</emphasis> - Execute permission on the object</para></listitem>
+ <listitem><para><emphasis>D</emphasis> - Delete the object</para></listitem>
+ <listitem><para><emphasis>P</emphasis> - Change permissions</para></listitem>
+ <listitem><para><emphasis>O</emphasis> - Take ownership</para></listitem>
+ </itemizedlist>
+
+
+ <para>The following combined permissions can be specified:</para>
+
+
+ <itemizedlist>
+ <listitem><para><emphasis>READ</emphasis> - Equivalent to 'RX'
+ permissions</para></listitem>
+ <listitem><para><emphasis>CHANGE</emphasis> - Equivalent to 'RXWD' permissions
+ </para></listitem>
+ <listitem><para><emphasis>FULL</emphasis> - Equivalent to 'RWXDPO'
+ permissions</para></listitem>
+ </itemizedlist>
+ </refsect1>
+
+<refsect1>
+ <title>EXIT STATUS</title>
+
+ <para>The <command>smbcacls</command> program sets the exit status
+ depending on the success or otherwise of the operations performed.
+ The exit status may be one of the following values. </para>
+
+ <para>If the operation succeeded, smbcacls returns and exit
+ status of 0. If <command>smbcacls</command> couldn't connect to the specified server,
+ or there was an error getting or setting the ACLs, an exit status
+ of 1 is returned. If there was an error parsing any command line
+ arguments, an exit status of 2 is returned. </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para><command>smbcacls</command> was written by Andrew Tridgell
+ and Tim Potter.</para>
+
+ <para>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbclient.1.sgml b/docs/docbook/manpages/smbclient.1.sgml
new file mode 100644
index 00000000000..6cc7be654ae
--- /dev/null
+++ b/docs/docbook/manpages/smbclient.1.sgml
@@ -0,0 +1,1023 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbclient">
+
+<refmeta>
+ <refentrytitle>smbclient</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbclient</refname>
+ <refpurpose>ftp-like client to access SMB/CIFS resources
+ on servers</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbclient</command>
+ <arg choice="req">servicename</arg>
+ <arg choice="opt">password</arg>
+ <arg choice="opt">-b &lt;buffer size&gt;</arg>
+ <arg choice="opt">-d debuglevel</arg>
+ <arg choice="opt">-D Directory</arg>
+ <arg choice="opt">-U username</arg>
+ <arg choice="opt">-W workgroup</arg>
+ <arg choice="opt">-M &lt;netbios name&gt;</arg>
+ <arg choice="opt">-m maxprotocol</arg>
+ <arg choice="opt">-A authfile</arg>
+ <arg choice="opt">-N</arg>
+ <arg choice="opt">-l logfile</arg>
+ <arg choice="opt">-L &lt;netbios name&gt;</arg>
+ <arg choice="opt">-I destinationIP</arg>
+ <arg choice="opt">-E &lt;terminal code&gt;</arg>
+ <arg choice="opt">-c &lt;command string&gt;</arg>
+ <arg choice="opt">-i scope</arg>
+ <arg choice="opt">-O &lt;socket options&gt;</arg>
+ <arg choice="opt">-p port</arg>
+ <arg choice="opt">-R &lt;name resolve order&gt;</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-T&lt;c|x&gt;IXFqgbNan</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>smbclient</command> is a client that can
+ 'talk' to an SMB/CIFS server. It offers an interface
+ similar to that of the ftp program (see <command>ftp(1)</command>).
+ Operations include things like getting files from the server
+ to the local machine, putting files from the local machine to
+ the server, retrieving directory information from the server
+ and so on. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>servicename</term>
+ <listitem><para>servicename is the name of the service
+ you want to use on the server. A service name takes the form
+ <filename>//server/service</filename> where <parameter>server
+ </parameter> is the NetBIOS name of the SMB/CIFS server
+ offering the desired service and <parameter>service</parameter>
+ is the name of the service offered. Thus to connect to
+ the service "printer" on the SMB/CIFS server "smbserver",
+ you would use the servicename <filename>//smbserver/printer
+ </filename></para>
+
+ <para>Note that the server name required is NOT necessarily
+ the IP (DNS) host name of the server ! The name required is
+ a NetBIOS server name, which may or may not be the
+ same as the IP hostname of the machine running the server.
+ </para>
+
+ <para>The server name is looked up according to either
+ the <parameter>-R</parameter> parameter to <command>smbclient</command> or
+ using the name resolve order parameter in the <filename>smb.conf</filename> file,
+ allowing an administrator to change the order and methods
+ by which server names are looked up. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>password</term>
+ <listitem><para>The password required to access the specified
+ service on the specified server. If this parameter is
+ supplied, the <parameter>-N</parameter> option (suppress
+ password prompt) is assumed. </para>
+
+ <para>There is no default password. If no password is supplied
+ on the command line (either by using this parameter or adding
+ a password to the <parameter>-U</parameter> option (see
+ below)) and the <parameter>-N</parameter> option is not
+ specified, the client will prompt for a password, even if
+ the desired service does not require one. (If no password is
+ required, simply press ENTER to provide a null password.)
+ </para>
+
+ <para>Note: Some servers (including OS/2 and Windows for
+ Workgroups) insist on an uppercase password. Lowercase
+ or mixed case passwords may be rejected by these servers.
+ </para>
+
+ <para>Be cautious about including passwords in scripts.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s smb.conf</term>
+ <listitem><para>Specifies the location of the all important
+ <filename>smb.conf</filename> file. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O socket options</term>
+ <listitem><para>TCP socket options to set on the client
+ socket. See the socket options parameter in the <filename>
+ smb.conf (5)</filename> manpage for the list of valid
+ options. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-R &lt;name resolve order&gt;</term>
+ <listitem><para>This option is used by the programs in the Samba
+ suite to determine what naming services and in what order to resolve
+ host names to IP addresses. The option takes a space-separated
+ string of different name resolution options.</para>
+
+ <para>The options are :"lmhosts", "host", "wins" and "bcast". They
+ cause names to be resolved as follows :</para>
+
+ <itemizedlist>
+ <listitem><para><constant>lmhosts</constant> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <ulink
+ url="lmhosts.5.html">lmhosts(5)</ulink> for details) then
+ any name type matches for lookup.</para></listitem>
+
+ <listitem><para><constant>host</constant> : Do a standard host
+ name to IP address resolution, using the system <filename>/etc/hosts
+ </filename>, NIS, or DNS lookups. This method of name resolution
+ is operating system dependent, for instance on IRIX or Solaris this
+ may be controlled by the <filename>/etc/nsswitch.conf</filename>
+ file). Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</para></listitem>
+
+ <listitem><para><constant>wins</constant> : Query a name with
+ the IP address listed in the <parameter>wins server</parameter>
+ parameter. If no WINS server has
+ been specified this method will be ignored.</para></listitem>
+
+ <listitem><para><constant>bcast</constant> : Do a broadcast on
+ each of the known local interfaces listed in the
+ <parameter>interfaces</parameter>
+ parameter. This is the least reliable of the name resolution
+ methods as it depends on the target host being on a locally
+ connected subnet.</para></listitem>
+ </itemizedlist>
+
+ <para>If this parameter is not set then the name resolve order
+ defined in the <filename>smb.conf</filename> file parameter
+ (name resolve order) will be used. </para>
+
+ <para>The default order is lmhosts, host, wins, bcast and without
+ this parameter or any entry in the <parameter>name resolve order
+ </parameter> parameter of the <filename>smb.conf</filename> file the name resolution
+ methods will be attempted in this order. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-M NetBIOS name</term>
+ <listitem><para>This options allows you to send messages, using
+ the "WinPopup" protocol, to another computer. Once a connection is
+ established you then type your message, pressing ^D (control-D) to
+ end. </para>
+
+ <para>If the receiving computer is running WinPopup the user will
+ receive the message and probably a beep. If they are not running
+ WinPopup the message will be lost, and no error message will
+ occur. </para>
+
+ <para>The message is also automatically truncated if the message
+ is over 1600 bytes, as this is the limit of the protocol.
+ </para>
+
+ <para>One useful trick is to cat the message through
+ <command>smbclient</command>. For example: <command>
+ cat mymessage.txt | smbclient -M FRED </command> will
+ send the message in the file <filename>mymessage.txt</filename>
+ to the machine FRED. </para>
+
+ <para>You may also find the <parameter>-U</parameter> and
+ <parameter>-I</parameter> options useful, as they allow you to
+ control the FROM and TO parts of the message. </para>
+
+ <para>See the message command parameter in the <filename>
+ smb.conf(5)</filename> for a description of how to handle incoming
+ WinPopup messages in Samba. </para>
+
+ <para><emphasis>Note</emphasis>: Copy WinPopup into the startup group
+ on your WfWg PCs if you want them to always be able to receive
+ messages. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i scope</term>
+ <listitem><para>This specifies a NetBIOS scope that smbclient will
+ use to communicate with when generating NetBIOS names. For details
+ on the use of NetBIOS scopes, see <filename>rfc1001.txt</filename>
+ and <filename>rfc1002.txt</filename>.
+ NetBIOS scopes are <emphasis>very</emphasis> rarely used, only set
+ this parameter if you are the system administrator in charge of all
+ the NetBIOS systems you communicate with. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-N</term>
+ <listitem><para>If specified, this parameter suppresses the normal
+ password prompt from the client to the user. This is useful when
+ accessing a service that does not require a password. </para>
+
+ <para>Unless a password is specified on the command line or
+ this parameter is specified, the client will request a
+ password.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-n NetBIOS name</term>
+ <listitem><para>By default, the client will use the local
+ machine's hostname (in uppercase) as its NetBIOS name. This parameter
+ allows you to override the host name and use whatever NetBIOS
+ name you wish. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-d debuglevel</term>
+ <listitem><para><replaceable>debuglevel</replaceable> is an integer from 0 to 10, or
+ the letter 'A'. </para>
+
+ <para>The default value if this parameter is not specified
+ is zero. </para>
+
+ <para>The higher this value, the more detail will be logged to
+ the log files about the activities of the
+ client. At level 0, only critical errors and serious warnings will
+ be logged. Level 1 is a reasonable level for day to day running -
+ it generates a small amount of information about operations
+ carried out. </para>
+
+ <para>Levels above 1 will generate considerable amounts of log
+ data, and should only be used when investigating a problem.
+ Levels above 3 are designed for use only by developers and
+ generate HUGE amounts of log data, most of which is extremely
+ cryptic. If <replaceable>debuglevel</replaceable> is set to the letter 'A', then <emphasis>all
+ </emphasis> debug messages will be printed. This setting
+ is for developers only (and people who <emphasis>really</emphasis> want
+ to know how the code works internally). </para>
+
+ <para>Note that specifying this parameter here will override
+ the log level parameter in the <filename>smb.conf (5)</filename>
+ file. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-p port</term>
+ <listitem><para>This number is the TCP port number that will be used
+ when making connections to the server. The standard (well-known)
+ TCP port number for an SMB/CIFS server is 139, which is the
+ default. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-l logfilename</term>
+ <listitem><para>If specified, <replaceable>logfilename</replaceable> specifies a base filename
+ into which operational data from the running client will be
+ logged. </para>
+
+ <para>The default base name is specified at compile time.</para>
+
+ <para>The base name is used to generate actual log file names.
+ For example, if the name specified was "log", the debug file
+ would be <filename>log.client</filename>.</para>
+
+ <para>The log file generated is never removed by the client.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-h</term><listitem>
+ <para>Print the usage message for the client. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-I IP-address</term>
+ <listitem><para><replaceable>IP address</replaceable> is the address of the server to connect to.
+ It should be specified in standard "a.b.c.d" notation. </para>
+
+ <para>Normally the client would attempt to locate a named
+ SMB/CIFS server by looking it up via the NetBIOS name resolution
+ mechanism described above in the <parameter>name resolve order</parameter>
+ parameter above. Using this parameter will force the client
+ to assume that the server is on the machine with the specified IP
+ address and the NetBIOS name component of the resource being
+ connected to will be ignored. </para>
+
+ <para>There is no default for this parameter. If not supplied,
+ it will be determined automatically by the client as described
+ above. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-E</term>
+ <listitem><para>This parameter causes the client to write messages
+ to the standard error stream (stderr) rather than to the standard
+ output stream. </para>
+
+ <para>By default, the client writes messages to standard output
+ - typically the user's tty. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-U username[%pass]</term>
+ <listitem><para>Sets the SMB username or username and password.
+ If %pass is not specified, The user will be prompted. The client
+ will first check the <envar>USER</envar> environment variable, then the
+ <envar>LOGNAME</envar> variable and if either exists, the
+ string is uppercased. Anything in these variables following a '%'
+ sign will be treated as the password. If these environment
+ variables are not found, the username <constant>GUEST</constant>
+ is used. </para>
+
+ <para>If the password is not included in these environment
+ variables (using the %pass syntax), <command>smbclient</command> will look for
+ a <envar>PASSWD</envar> environment variable from which
+ to read the password. </para>
+
+ <para>A third option is to use a credentials file which
+ contains the plaintext of the username and password. This
+ option is mainly provided for scripts where the admin doesn't
+ wish to pass the credentials on the command line or via environment
+ variables. If this method is used, make certain that the permissions
+ on the file restrict access from unwanted users. See the
+ <parameter>-A</parameter> for more details. </para>
+
+ <para>Be cautious about including passwords in scripts or in
+ the <envar>PASSWD</envar> environment variable. Also, on
+ many systems the command line of a running process may be seen
+ via the <command>ps</command> command to be safe always allow
+ <command>smbclient</command> to prompt for a password and type
+ it in directly. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-A filename</term><listitem><para>This option allows
+ you to specify a file from which to read the username and
+ password used in the connection. The format of the file is
+ </para>
+
+ <para><programlisting>
+username = &lt;value&gt;
+password = &lt;value&gt;
+ </programlisting></para>
+
+
+ <para>Make certain that the permissions on the file restrict
+ access from unwanted users. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-L</term>
+ <listitem><para>This option allows you to look at what services
+ are available on a server. You use it as <command>smbclient -L
+ host</command> and a list should appear. The <parameter>-I
+ </parameter> option may be useful if your NetBIOS names don't
+ match your TCP/IP DNS host names or if you are trying to reach a
+ host on another network. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-t terminal code</term>
+ <listitem><para>This option tells <command>smbclient</command> how to interpret
+ filenames coming from the remote server. Usually Asian language
+ multibyte UNIX implementations use different character sets than
+ SMB/CIFS servers (<emphasis>EUC</emphasis> instead of <emphasis>
+ SJIS</emphasis> for example). Setting this parameter will let
+ <command>smbclient</command> convert between the UNIX filenames and
+ the SMB filenames correctly. This option has not been seriously tested
+ and may have some problems. </para>
+
+ <para>The terminal codes include CWsjis, CWeuc, CWjis7, CWjis8,
+ CWjunet, CWhex, CWcap. This is not a complete list, check the Samba
+ source code for the complete list. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-b buffersize</term>
+ <listitem><para>This option changes the transmit/send buffer
+ size when getting or putting a file from/to the server. The default
+ is 65520 bytes. Setting this value smaller (to 1200 bytes) has been
+ observed to speed up file transfers to and from a Win9x server.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-W WORKGROUP</term>
+ <listitem><para>Override the default workgroup specified in the
+ workgroup parameter of the <filename>smb.conf</filename> file
+ for this connection. This may be needed to connect to some
+ servers. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-T tar options</term>
+ <listitem><para>smbclient may be used to create <command>tar(1)
+ </command> compatible backups of all the files on an SMB/CIFS
+ share. The secondary tar flags that can be given to this option
+ are : </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>c</parameter> - Create a tar file on UNIX.
+ Must be followed by the name of a tar file, tape device
+ or "-" for standard output. If using standard output you must
+ turn the log level to its lowest value -d0 to avoid corrupting
+ your tar file. This flag is mutually exclusive with the
+ <parameter>x</parameter> flag. </para></listitem>
+
+ <listitem><para><parameter>x</parameter> - Extract (restore) a local
+ tar file back to a share. Unless the -D option is given, the tar
+ files will be restored from the top level of the share. Must be
+ followed by the name of the tar file, device or "-" for standard
+ input. Mutually exclusive with the <parameter>c</parameter> flag.
+ Restored files have their creation times (mtime) set to the
+ date saved in the tar file. Directories currently do not get
+ their creation dates restored properly. </para></listitem>
+
+ <listitem><para><parameter>I</parameter> - Include files and directories.
+ Is the default behavior when filenames are specified above. Causes
+ tar files to be included in an extract or create (and therefore
+ everything else to be excluded). See example below. Filename globbing
+ works in one of two ways. See r below. </para></listitem>
+
+ <listitem><para><parameter>X</parameter> - Exclude files and directories.
+ Causes tar files to be excluded from an extract or create. See
+ example below. Filename globbing works in one of two ways now.
+ See <parameter>r</parameter> below. </para></listitem>
+
+ <listitem><para><parameter>b</parameter> - Blocksize. Must be followed
+ by a valid (greater than zero) blocksize. Causes tar file to be
+ written out in blocksize*TBLOCK (usually 512 byte) blocks.
+ </para></listitem>
+
+ <listitem><para><parameter>g</parameter> - Incremental. Only back up
+ files that have the archive bit set. Useful only with the
+ <parameter>c</parameter> flag. </para></listitem>
+
+ <listitem><para><parameter>q</parameter> - Quiet. Keeps tar from printing
+ diagnostics as it works. This is the same as tarmode quiet.
+ </para></listitem>
+
+ <listitem><para><parameter>r</parameter> - Regular expression include
+ or exclude. Uses regular expression matching for
+ excluding or excluding files if compiled with HAVE_REGEX_H.
+ However this mode can be very slow. If not compiled with
+ HAVE_REGEX_H, does a limited wildcard match on '*' and '?'.
+ </para></listitem>
+
+ <listitem><para><parameter>N</parameter> - Newer than. Must be followed
+ by the name of a file whose date is compared against files found
+ on the share during a create. Only files newer than the file
+ specified are backed up to the tar file. Useful only with the
+ <parameter>c</parameter> flag. </para></listitem>
+
+ <listitem><para><parameter>a</parameter> - Set archive bit. Causes the
+ archive bit to be reset when a file is backed up. Useful with the
+ <parameter>g</parameter> and <parameter>c</parameter> flags.
+ </para></listitem>
+ </itemizedlist>
+
+ <para><emphasis>Tar Long File Names</emphasis></para>
+
+ <para><command>smbclient</command>'s tar option now supports long
+ file names both on backup and restore. However, the full path
+ name of the file must be less than 1024 bytes. Also, when
+ a tar archive is created, <command>smbclient</command>'s tar option places all
+ files in the archive with relative names, not absolute names.
+ </para>
+
+ <para><emphasis>Tar Filenames</emphasis></para>
+
+ <para>All file names can be given as DOS path names (with '\'
+ as the component separator) or as UNIX path names (with '/' as
+ the component separator). </para>
+
+ <para><emphasis>Examples</emphasis></para>
+
+ <para>Restore from tar file <filename>backup.tar</filename> into myshare on mypc
+ (no password on share). </para>
+
+ <para><command>smbclient //mypc/yshare "" -N -Tx backup.tar
+ </command></para>
+
+ <para>Restore everything except <filename>users/docs</filename>
+ </para>
+
+ <para><command>smbclient //mypc/myshare "" -N -TXx backup.tar
+ users/docs</command></para>
+
+ <para>Create a tar file of the files beneath <filename>
+ users/docs</filename>. </para>
+
+ <para><command>smbclient //mypc/myshare "" -N -Tc
+ backup.tar users/docs </command></para>
+
+ <para>Create the same tar file as above, but now use
+ a DOS path name. </para>
+
+ <para><command>smbclient //mypc/myshare "" -N -tc backup.tar
+ users\edocs </command></para>
+
+ <para>Create a tar file of all the files and directories in
+ the share. </para>
+
+ <para><command>smbclient //mypc/myshare "" -N -Tc backup.tar *
+ </command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-D initial directory</term>
+ <listitem><para>Change to initial directory before starting. Probably
+ only of any use with the tar -T option. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-c command string</term>
+ <listitem><para>command string is a semicolon-separated list of
+ commands to be executed instead of prompting from stdin. <parameter>
+ -N</parameter> is implied by <parameter>-c</parameter>.</para>
+
+ <para>This is particularly useful in scripts and for printing stdin
+ to the server, e.g. <command>-c 'print -'</command>. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>OPERATIONS</title>
+
+ <para>Once the client is running, the user is presented with
+ a prompt : </para>
+
+ <para><prompt>smb:\&gt; </prompt></para>
+
+ <para>The backslash ("\") indicates the current working directory
+ on the server, and will change if the current working directory
+ is changed. </para>
+
+ <para>The prompt indicates that the client is ready and waiting to
+ carry out a user command. Each command is a single word, optionally
+ followed by parameters specific to that command. Command and parameters
+ are space-delimited unless these notes specifically
+ state otherwise. All commands are case-insensitive. Parameters to
+ commands may or may not be case sensitive, depending on the command.
+ </para>
+
+ <para>You can specify file names which have spaces in them by quoting
+ the name with double quotes, for example "a long file name". </para>
+
+ <para>Parameters shown in square brackets (e.g., "[parameter]") are
+ optional. If not given, the command will use suitable defaults. Parameters
+ shown in angle brackets (e.g., "&lt;parameter&gt;") are required.
+ </para>
+
+
+ <para>Note that all commands operating on the server are actually
+ performed by issuing a request to the server. Thus the behavior may
+ vary from server to server, depending on how the server was implemented.
+ </para>
+
+ <para>The commands available are given here in alphabetical order. </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>? [command]</term>
+ <listitem><para>If <replaceable>command</replaceable> is specified, the ? command will display
+ a brief informative message about the specified command. If no
+ command is specified, a list of available commands will
+ be displayed. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>! [shell command]</term>
+ <listitem><para>If <replaceable>shell command</replaceable> is specified, the !
+ command will execute a shell locally and run the specified shell
+ command. If no command is specified, a local shell will be run.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>cd [directory name]</term>
+ <listitem><para>If "directory name" is specified, the current
+ working directory on the server will be changed to the directory
+ specified. This operation will fail if for any reason the specified
+ directory is inaccessible. </para>
+
+ <para>If no directory name is specified, the current working
+ directory on the server will be reported. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>del &lt;mask&gt;</term>
+ <listitem><para>The client will request that the server attempt
+ to delete all files matching <replaceable>mask</replaceable> from the current working
+ directory on the server. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>dir &lt;mask&gt;</term>
+ <listitem><para>A list of the files matching <replaceable>mask</replaceable> in the current
+ working directory on the server will be retrieved from the server
+ and displayed. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>exit</term>
+ <listitem><para>Terminate the connection with the server and exit
+ from the program. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>get &lt;remote file name&gt; [local file name]</term>
+ <listitem><para>Copy the file called <filename>remote file name</filename> from
+ the server to the machine running the client. If specified, name
+ the local copy <filename>local file name</filename>. Note that all transfers in
+ <command>smbclient</command> are binary. See also the
+ lowercase command. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>help [command]</term>
+ <listitem><para>See the ? command above. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>lcd [directory name]</term>
+ <listitem><para>If <replaceable>directory name</replaceable> is specified, the current
+ working directory on the local machine will be changed to
+ the directory specified. This operation will fail if for any
+ reason the specified directory is inaccessible. </para>
+
+ <para>If no directory name is specified, the name of the
+ current working directory on the local machine will be reported.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>lowercase</term>
+ <listitem><para>Toggle lowercasing of filenames for the get and
+ mget commands. </para>
+
+ <para>When lowercasing is toggled ON, local filenames are converted
+ to lowercase when using the get and mget commands. This is
+ often useful when copying (say) MSDOS files from a server, because
+ lowercase filenames are the norm on UNIX systems. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>ls &lt;mask&gt;</term>
+ <listitem><para>See the dir command above. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>mask &lt;mask&gt;</term>
+ <listitem><para>This command allows the user to set up a mask
+ which will be used during recursive operation of the mget and
+ mput commands. </para>
+
+ <para>The masks specified to the mget and mput commands act as
+ filters for directories rather than files when recursion is
+ toggled ON. </para>
+
+ <para>The mask specified with the mask command is necessary
+ to filter files within those directories. For example, if the
+ mask specified in an mget command is "source*" and the mask
+ specified with the mask command is "*.c" and recursion is
+ toggled ON, the mget command will retrieve all files matching
+ "*.c" in all directories below and including all directories
+ matching "source*" in the current working directory. </para>
+
+ <para>Note that the value for mask defaults to blank (equivalent
+ to "*") and remains so until the mask command is used to change it.
+ It retains the most recently specified value indefinitely. To
+ avoid unexpected results it would be wise to change the value of
+ mask back to "*" after using the mget or mput commands. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>md &lt;directory name&gt;</term>
+ <listitem><para>See the mkdir command. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>mget &lt;mask&gt;</term>
+ <listitem><para>Copy all files matching <replaceable>mask</replaceable> from the server to
+ the machine running the client. </para>
+
+ <para>Note that <replaceable>mask</replaceable> is interpreted differently during recursive
+ operation and non-recursive operation - refer to the recurse and
+ mask commands for more information. Note that all transfers in
+ <command>smbclient</command> are binary. See also the lowercase command. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>mkdir &lt;directory name&gt;</term>
+ <listitem><para>Create a new directory on the server (user access
+ privileges permitting) with the specified name. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>mput &lt;mask&gt;</term>
+ <listitem><para>Copy all files matching <replaceable>mask</replaceable> in the current working
+ directory on the local machine to the current working directory on
+ the server. </para>
+
+ <para>Note that <replaceable>mask</replaceable> is interpreted differently during recursive
+ operation and non-recursive operation - refer to the recurse and mask
+ commands for more information. Note that all transfers in <command>smbclient</command>
+ are binary. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>print &lt;file name&gt;</term>
+ <listitem><para>Print the specified file from the local machine
+ through a printable service on the server. </para>
+
+ <para>See also the printmode command.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>printmode &lt;graphics or text&gt;</term>
+ <listitem><para>Set the print mode to suit either binary data
+ (such as graphical information) or text. Subsequent print
+ commands will use the currently set print mode. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>prompt</term>
+ <listitem><para>Toggle prompting for filenames during operation
+ of the mget and mput commands. </para>
+
+ <para>When toggled ON, the user will be prompted to confirm
+ the transfer of each file during these commands. When toggled
+ OFF, all specified files will be transferred without prompting.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>put &lt;local file name&gt; [remote file name]</term>
+ <listitem><para>Copy the file called <filename>local file name</filename> from the
+ machine running the client to the server. If specified,
+ name the remote copy <filename>remote file name</filename>. Note that all transfers
+ in <command>smbclient</command> are binary. See also the lowercase command.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>queue</term>
+ <listitem><para>Displays the print queue, showing the job id,
+ name, size and current status. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>quit</term>
+ <listitem><para>See the exit command. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>rd &lt;directory name&gt;</term>
+ <listitem><para>See the rmdir command. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>recurse</term>
+ <listitem><para>Toggle directory recursion for the commands mget
+ and mput. </para>
+
+ <para>When toggled ON, these commands will process all directories
+ in the source directory (i.e., the directory they are copying
+ from ) and will recurse into any that match the mask specified
+ to the command. Only files that match the mask specified using
+ the mask command will be retrieved. See also the mask command.
+ </para>
+
+ <para>When recursion is toggled OFF, only files from the current
+ working directory on the source machine that match the mask specified
+ to the mget or mput commands will be copied, and any mask specified
+ using the mask command will be ignored. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>rm &lt;mask&gt;</term>
+ <listitem><para>Remove all files matching <replaceable>mask</replaceable> from the current
+ working directory on the server. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>rmdir &lt;directory name&gt;</term>
+ <listitem><para>Remove the specified directory (user access
+ privileges permitting) from the server. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>tar &lt;c|x&gt;[IXbgNa]</term>
+ <listitem><para>Performs a tar operation - see the <parameter>-T
+ </parameter> command line option above. Behavior may be affected
+ by the tarmode command (see below). Using g (incremental) and N
+ (newer) will affect tarmode settings. Note that using the "-" option
+ with tar x may not work - use the command line option instead.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>blocksize &lt;blocksize&gt;</term>
+ <listitem><para>Blocksize. Must be followed by a valid (greater
+ than zero) blocksize. Causes tar file to be written out in
+ <replaceable>blocksize</replaceable>*TBLOCK (usually 512 byte) blocks. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>tarmode &lt;full|inc|reset|noreset&gt;</term>
+ <listitem><para>Changes tar's behavior with regard to archive
+ bits. In full mode, tar will back up everything regardless of the
+ archive bit setting (this is the default mode). In incremental mode,
+ tar will only back up files with the archive bit set. In reset mode,
+ tar will reset the archive bit on all files it backs up (implies
+ read/write share). </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>setmode &lt;filename&gt; &lt;perm=[+|\-]rsha&gt;</term>
+ <listitem><para>A version of the DOS attrib command to set
+ file permissions. For example: </para>
+
+ <para><command>setmode myfile +r </command></para>
+
+ <para>would make myfile read only. </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>NOTES</title>
+
+ <para>Some servers are fussy about the case of supplied usernames,
+ passwords, share names (AKA service names) and machine names.
+ If you fail to connect try giving all parameters in uppercase.
+ </para>
+
+ <para>It is often necessary to use the -n option when connecting
+ to some types of servers. For example OS/2 LanManager insists
+ on a valid NetBIOS name being used, so you need to supply a valid
+ name that would be known to the server.</para>
+
+ <para>smbclient supports long file names where the server
+ supports the LANMAN2 protocol or above. </para>
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT VARIABLES</title>
+
+ <para>The variable <envar>USER</envar> may contain the
+ username of the person using the client. This information is
+ used only if the protocol level is high enough to support
+ session-level passwords.</para>
+
+
+ <para>The variable <envar>PASSWD</envar> may contain
+ the password of the person using the client. This information is
+ used only if the protocol level is high enough to support
+ session-level passwords. </para>
+
+ <para>The variable <envar>LIBSMB_PROG</envar> may contain
+ the path, executed with system(), which the client should connect
+ to instead of connecting to a server. This functionality is primarily
+ intended as a development aid, and works best when using a LMHOSTS
+ file</para>
+</refsect1>
+
+
+<refsect1>
+ <title>INSTALLATION</title>
+
+ <para>The location of the client program is a matter for
+ individual system administrators. The following are thus
+ suggestions only. </para>
+
+ <para>It is recommended that the smbclient software be installed
+ in the <filename>/usr/local/samba/bin/</filename> or <filename>
+ /usr/samba/bin/</filename> directory, this directory readable
+ by all, writeable only by root. The client program itself should
+ be executable by all. The client should <emphasis>NOT</emphasis> be
+ setuid or setgid! </para>
+
+ <para>The client log files should be put in a directory readable
+ and writeable only by the user. </para>
+
+ <para>To test the client, you will need to know the name of a
+ running SMB/CIFS server. It is possible to run <command>smbd(8)
+ </command> as an ordinary user - running that server as a daemon
+ on a user-accessible port (typically any port number over 1024)
+ would provide a suitable test server. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>DIAGNOSTICS</title>
+
+ <para>Most diagnostics issued by the client are logged in a
+ specified log file. The log file name is specified at compile time,
+ but may be overridden on the command line. </para>
+
+ <para>The number and nature of diagnostics available depends
+ on the debug level used by the client. If you have problems,
+ set the debug level to 3 and peruse the log files. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbcontrol.1.sgml b/docs/docbook/manpages/smbcontrol.1.sgml
new file mode 100644
index 00000000000..05e05f4a6ab
--- /dev/null
+++ b/docs/docbook/manpages/smbcontrol.1.sgml
@@ -0,0 +1,174 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbcontrol">
+
+<refmeta>
+ <refentrytitle>smbcontrol</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbcontrol</refname>
+ <refpurpose>send messages to smbd or nmbd processes</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbcontrol</command>
+ <arg>-i</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>smbcontrol</command>
+ <arg>destination</arg>
+ <arg>message-type</arg>
+ <arg>parameter</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>smbcontrol</command> is a very small program, which
+ sends messages to an <ulink url="smbd.8.html">smbd(8)</ulink> or
+ an <ulink url="nmbd.8.html">nmbd(8)</ulink> daemon running on the
+ system.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-i</term>
+ <listitem><para>Run interactively. Individual commands
+ of the form destination message-type parameters can be entered
+ on STDIN. An empty command line or a "q" will quit the
+ program.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>destination</term>
+ <listitem><para>One of <parameter>nmbd</parameter>
+ <parameter>smbd</parameter> or a process ID.</para>
+
+ <para>The <parameter>smbd</parameter> destination causes the
+ message to "broadcast" to all smbd daemons.</para>
+
+ <para>The <parameter>nmbd</parameter> destination causes the
+ message to be sent to the nmbd daemon specified in the
+ <filename>nmbd.pid</filename> file.</para>
+
+ <para>If a single process ID is given, the message is sent
+ to only that process.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>message-type</term>
+ <listitem><para>One of: <constant>close-share</constant>,
+ <constant>debug</constant>,
+ <constant>force-election</constant>, <constant>ping
+ </constant>, <constant>profile</constant>, <constant>
+ debuglevel</constant>, <constant>profilelevel</constant>,
+ or <constant>printer-notify</constant>.</para>
+
+ <para>The <constant>close-share</constant> message-type sends a
+ message to smbd which will then close the client connections to
+ the named share. Note that this doesn't affect client connections
+ to any other shares. This message-type takes an argument of the
+ share name for which client connections will be close, or the
+ "*" character which will close all currently open shares.
+ This message can only be sent to <constant>smbd</constant>.</para>
+
+ <para>The <constant>debug</constant> message-type allows
+ the debug level to be set to the value specified by the
+ parameter. This can be sent to any of the destinations.</para>
+
+ <para>The <constant>force-election</constant> message-type can only be
+ sent to the <constant>nmbd</constant> destination. This message
+ causes the <command>nmbd</command> daemon to force a new browse
+ master election.</para>
+
+ <para>The <constant>ping</constant> message-type sends the
+ number of "ping" messages specified by the parameter and waits
+ for the same number of reply "pong" messages. This can be sent to
+ any of the destinations.</para>
+
+ <para>The <constant>profile</constant> message-type sends a
+ message to an smbd to change the profile settings based on the
+ parameter. The parameter can be "on" to turn on profile stats
+ collection, "off" to turn off profile stats collection, "count"
+ to enable only collection of count stats (time stats are
+ disabled), and "flush" to zero the current profile stats. This can
+ be sent to any of the destinations.</para>
+
+ <para>The <constant>debuglevel</constant> message-type sends
+ a "request debug level" message. The current debug level setting
+ is returned by a "debuglevel" message. This can be
+ sent to any of the destinations.</para>
+
+ <para>The <constant>profilelevel</constant> message-type sends
+ a "request profile level" message. The current profile level
+ setting is returned by a "profilelevel" message. This can be sent
+ to any of the destinations.</para>
+
+ <para>The <constant>printer-notify</constant> message-type sends a
+ message to smbd which in turn sends a printer notify message to
+ any Windows NT clients connected to a printer. This message-type
+ takes an argument of the printer name to send notify messages to.
+ This message can only be sent to <constant>smbd</constant>.</para>
+
+ <para>The <constant>close-share</constant> message-type sends a
+ message to smbd which forces smbd to close the share that was
+ specified as an argument. This may be useful if you made changes
+ to the access controls on the share. </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>parameters</term>
+ <listitem><para>any parameters required for the message-type</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="nmbd.8.html"><command>nmbd(8)</command></ulink>,
+ and <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbd.8.sgml b/docs/docbook/manpages/smbd.8.sgml
new file mode 100644
index 00000000000..e01e5477079
--- /dev/null
+++ b/docs/docbook/manpages/smbd.8.sgml
@@ -0,0 +1,611 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbd">
+
+<refmeta>
+ <refentrytitle>smbd</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbd</refname>
+ <refpurpose>server to provide SMB/CIFS services to clients</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbd</command>
+ <arg choice="opt">-D</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-o</arg>
+ <arg choice="opt">-P</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-V</arg>
+ <arg choice="opt">-b</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-l &lt;log directory&gt;</arg>
+ <arg choice="opt">-p &lt;port number&gt;</arg>
+ <arg choice="opt">-O &lt;socket option&gt;</arg>
+ <arg choice="opt">-s &lt;configuration file&gt;</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+ <para>This program is part of the Samba suite.</para>
+
+ <para><command>smbd</command> is the server daemon that
+ provides filesharing and printing services to Windows clients.
+ The server provides filespace and printer services to
+ clients using the SMB (or CIFS) protocol. This is compatible
+ with the LanManager protocol, and can service LanManager
+ clients. These include MSCLIENT 3.0 for DOS, Windows for
+ Workgroups, Windows 95/98/ME, Windows NT, Windows 2000,
+ OS/2, DAVE for Macintosh, and smbfs for Linux.</para>
+
+ <para>An extensive description of the services that the
+ server can provide is given in the man page for the
+ configuration file controlling the attributes of those
+ services (see <ulink url="smb.conf.5.html"><filename>smb.conf(5)
+ </filename></ulink>. This man page will not describe the
+ services, but will concentrate on the administrative aspects
+ of running the server.</para>
+
+ <para>Please note that there are significant security
+ implications to running this server, and the <ulink
+ url="smb.conf.5.html"><filename>smb.conf(5)</filename></ulink>
+ manpage should be regarded as mandatory reading before
+ proceeding with installation.</para>
+
+ <para>A session is created whenever a client requests one.
+ Each client gets a copy of the server for each session. This
+ copy then services all connections made by the client during
+ that session. When all connections from its client are closed,
+ the copy of the server for that client terminates.</para>
+
+ <para>The configuration file, and any files that it includes,
+ are automatically reloaded every minute, if they change. You
+ can force a reload by sending a SIGHUP to the server. Reloading
+ the configuration file will not affect connections to any service
+ that is already established. Either the user will have to
+ disconnect from the service, or <command>smbd</command> killed and restarted.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-D</term>
+ <listitem><para>If specified, this parameter causes
+ the server to operate as a daemon. That is, it detaches
+ itself and runs in the background, fielding requests
+ on the appropriate port. Operating the server as a
+ daemon is the recommended way of running <command>smbd</command> for
+ servers that provide more than casual use file and
+ print services. This switch is assumed if <command>smbd
+ </command> is executed on the command line of a shell.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>If this parameter is specified, each new
+ connection will append log messages to the log file.
+ This is the default.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o</term>
+ <listitem><para>If this parameter is specified, the
+ log files will be overwritten when opened. By default,
+ <command>smbd</command> will append entries to the log
+ files.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-P</term>
+ <listitem><para>Passive option. Causes <command>smbd</command> not to
+ send any network traffic out. Used for debugging by
+ the developers only.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Prints the help information (usage)
+ for <command>smbd</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>Prints the version number for
+ <command>smbd</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b</term>
+ <listitem><para>Prints information about how
+ Samba was built.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-d &lt;debug level&gt;</term>
+ <listitem><para><replaceable>debuglevel</replaceable> is an integer
+ from 0 to 10. The default value if this parameter is
+ not specified is zero.</para>
+
+ <para>The higher this value, the more detail will be
+ logged to the log files about the activities of the
+ server. At level 0, only critical errors and serious
+ warnings will be logged. Level 1 is a reasonable level for
+ day to day running - it generates a small amount of
+ information about operations carried out.</para>
+
+ <para>Levels above 1 will generate considerable
+ amounts of log data, and should only be used when
+ investigating a problem. Levels above 3 are designed for
+ use only by developers and generate HUGE amounts of log
+ data, most of which is extremely cryptic.</para>
+
+ <para>Note that specifying this parameter here will
+ override the <ulink url="smb.conf.5.html#loglevel">log
+ level</ulink> parameter in the <ulink url="smb.conf.5.html">
+ <filename>smb.conf(5)</filename></ulink> file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-l &lt;log directory&gt;</term>
+ <listitem><para>If specified,
+ <replaceable>log directory</replaceable>
+ specifies a log directory into which the "log.smbd" log
+ file will be created for informational and debug
+ messages from the running server. The log
+ file generated is never removed by the server although
+ its size may be controlled by the <ulink
+ url="smb.conf.5.html#maxlogsize">max log size</ulink>
+ option in the <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> file.
+ </para>
+
+ <para>The default log directory is specified at
+ compile time.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O &lt;socket options&gt;</term>
+ <listitem><para>See the <ulink
+ url="smb.conf.5.html#socketoptions">socket options</ulink>
+ parameter in the <ulink url="smb.conf.5.html"><filename>smb.conf(5)
+ </filename></ulink> file for details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-p &lt;port number&gt;</term>
+ <listitem><para><replaceable>port number</replaceable> is a positive integer
+ value. The default value if this parameter is not
+ specified is 139.</para>
+
+ <para>This number is the port number that will be
+ used when making connections to the server from client
+ software. The standard (well-known) port number for the
+ SMB over TCP is 139, hence the default. If you wish to
+ run the server as an ordinary user rather than
+ as root, most systems will require you to use a port
+ number greater than 1024 - ask your system administrator
+ for help if you are in this situation.</para>
+
+ <para>In order for the server to be useful by most
+ clients, should you configure it on a port other
+ than 139, you will require port redirection services
+ on port 139, details of which are outlined in rfc1002.txt
+ section 4.3.5.</para>
+
+ <para>This parameter is not normally specified except
+ in the above situation.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s &lt;configuration file&gt;</term>
+ <listitem><para>The file specified contains the
+ configuration details required by the server. The
+ information in this file includes server-specific
+ information such as what printcap file to use, as well
+ as descriptions of all the services that the server is
+ to provide. See <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> for more information.
+ The default configuration file name is determined at
+ compile time.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/inetd.conf</filename></term>
+ <listitem><para>If the server is to be run by the
+ <command>inetd</command> meta-daemon, this file
+ must contain suitable startup information for the
+ meta-daemon. See the section INSTALLATION below.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/rc</filename></term>
+ <listitem><para>or whatever initialization script your
+ system uses).</para>
+
+ <para>If running the server as a daemon at startup,
+ this file will need to contain an appropriate startup
+ sequence for the server. See the section INSTALLATION
+ below.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/services</filename></term>
+ <listitem><para>If running the server via the
+ meta-daemon <command>inetd</command>, this file
+ must contain a mapping of service name (e.g., netbios-ssn)
+ to service port (e.g., 139) and protocol type (e.g., tcp).
+ See the section INSTALLATION below.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/usr/local/samba/lib/smb.conf</filename></term>
+ <listitem><para>This is the default location of the
+ <ulink url="smb.conf.5.html"><filename>smb.conf</filename></ulink>
+ server configuration file. Other common places that systems
+ install this file are <filename>/usr/samba/lib/smb.conf</filename>
+ and <filename>/etc/smb.conf</filename>.</para>
+
+ <para>This file describes all the services the server
+ is to make available to clients. See <ulink url="smb.conf.5.html">
+ <filename>smb.conf(5)</filename></ulink> for more information.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>LIMITATIONS</title>
+ <para>On some systems <command>smbd</command> cannot change uid back
+ to root after a setuid() call. Such systems are called
+ trapdoor uid systems. If you have such a system,
+ you will be unable to connect from a client (such as a PC) as
+ two different users at once. Attempts to connect the
+ second user will result in access denied or
+ similar.</para>
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT VARIABLES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><envar>PRINTER</envar></term>
+ <listitem><para>If no printer name is specified to
+ printable services, most systems will use the value of
+ this variable (or <constant>lp</constant> if this variable is
+ not defined) as the name of the printer to use. This
+ is not specific to the server, however.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>INSTALLATION</title>
+
+ <para>The location of the server and its support files
+ is a matter for individual system administrators. The following
+ are thus suggestions only.</para>
+
+ <para>It is recommended that the server software be installed
+ under the <filename>/usr/local/samba/</filename> hierarchy,
+ in a directory readable by all, writeable only by root. The server
+ program itself should be executable by all, as users may wish to
+ run the server themselves (in which case it will of course run
+ with their privileges). The server should NOT be setuid. On some
+ systems it may be worthwhile to make <command>smbd</command> setgid to an empty group.
+ This is because some systems may have a security hole where daemon
+ processes that become a user can be attached to with a debugger.
+ Making the <command>smbd</command> file setgid to an empty group may prevent
+ this hole from being exploited. This security hole and the suggested
+ fix has only been confirmed on old versions (pre-kernel 2.0) of Linux
+ at the time this was written. It is possible that this hole only
+ exists in Linux, as testing on other systems has thus far shown them
+ to be immune.</para>
+
+ <para>The server log files should be put in a directory readable and
+ writeable only by root, as the log files may contain sensitive
+ information.</para>
+
+ <para>The configuration file should be placed in a directory
+ readable and writeable only by root, as the configuration file
+ controls security for the services offered by the server. The
+ configuration file can be made readable by all if desired, but
+ this is not necessary for correct operation of the server and is
+ not recommended. A sample configuration file <filename>smb.conf.sample
+ </filename> is supplied with the source to the server - this may
+ be renamed to <filename>smb.conf</filename> and modified to suit
+ your needs.</para>
+
+ <para>The remaining notes will assume the following:</para>
+
+ <itemizedlist>
+ <listitem><para><command>smbd</command> (the server program)
+ installed in <filename>/usr/local/samba/bin</filename></para>
+ </listitem>
+
+ <listitem><para><filename>smb.conf</filename> (the configuration
+ file) installed in <filename>/usr/local/samba/lib</filename></para>
+ </listitem>
+
+ <listitem><para>log files stored in <filename>/var/adm/smblogs
+ </filename></para></listitem>
+ </itemizedlist>
+
+ <para>The server may be run either as a daemon by users
+ or at startup, or it may be run from a meta-daemon such as
+ <command>inetd</command> upon request. If run as a daemon,
+ the server will always be ready, so starting sessions will be
+ faster. If run from a meta-daemon some memory will be saved and
+ utilities such as the tcpd TCP-wrapper may be used for extra
+ security. For serious use as file server it is recommended
+ that <command>smbd</command> be run as a daemon.</para>
+
+ <para>When you've decided, continue with either</para>
+
+ <itemizedlist>
+ <listitem><para>RUNNING THE SERVER AS A DAEMON or</para></listitem>
+ <listitem><para>RUNNING THE SERVER ON REQUEST.</para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>RUNNING THE SERVER AS A DAEMON</title>
+
+ <para>To run the server as a daemon from the command
+ line, simply put the <emphasis>-D</emphasis> option on the
+ command line. There is no need to place an ampersand at
+ the end of the command line - the <emphasis>-D</emphasis>
+ option causes the server to detach itself from the tty
+ anyway.</para>
+
+ <para>Any user can run the server as a daemon (execute
+ permissions permitting, of course). This is useful for
+ testing purposes, and may even be useful as a temporary
+ substitute for something like ftp. When run this way, however,
+ the server will only have the privileges of the user who ran
+ it.</para>
+
+ <para>To ensure that the server is run as a daemon whenever
+ the machine is started, and to ensure that it runs as root
+ so that it can serve multiple clients, you will need to modify
+ the system startup files. Wherever appropriate (for example, in
+ <filename>/etc/rc</filename>), insert the following line,
+ substituting port number, log file location, configuration file
+ location and debug level as desired:</para>
+
+ <para><command>/usr/local/samba/bin/smbd -D -l /var/adm/smblogs/log
+ -s /usr/local/samba/lib/smb.conf</command></para>
+
+ <para>(The above should appear in your initialization script
+ as a single line. Depending on your terminal characteristics,
+ it may not appear that way in this man page. If the above appears
+ as more than one line, please treat any newlines or indentation
+ as a single space or TAB character.)</para>
+
+ <para>If the options used at compile time are appropriate for
+ your system, all parameters except <emphasis>-D</emphasis> may
+ be omitted. See the section OPTIONS above.</para>
+</refsect1>
+
+<refsect1>
+ <title>RUNNING THE SERVER ON REQUEST</title>
+
+ <para>If your system uses a meta-daemon such as <command>inetd
+ </command>, you can arrange to have the <command>smbd</command> server started
+ whenever a process attempts to connect to it. This requires several
+ changes to the startup files on the host machine. If you are
+ experimenting as an ordinary user rather than as root, you will
+ need the assistance of your system administrator to modify the
+ system files.</para>
+
+ <para>You will probably want to set up the NetBIOS name server
+ <ulink url="nmbd.8.html"><command>nmbd</command></ulink> at
+ the same time as <command>smbd</command>. To do this refer to the
+ man page for <ulink url="nmbd.8.html"><command>nmbd(8)</command>
+ </ulink>.</para>
+
+ <para>First, ensure that a port is configured in the file
+ <filename>/etc/services</filename>. The well-known port 139
+ should be used if possible, though any port may be used.</para>
+
+ <para>Ensure that a line similar to the following is in
+ <filename>/etc/services</filename>:</para>
+
+ <para><command>netbios-ssn 139/tcp</command></para>
+
+ <para>Note for NIS/YP users - you may need to rebuild the
+ NIS service maps rather than alter your local <filename>/etc/services
+ </filename> file.</para>
+
+ <para>Next, put a suitable line in the file <filename>/etc/inetd.conf
+ </filename> (in the unlikely event that you are using a meta-daemon
+ other than inetd, you are on your own). Note that the first item
+ in this line matches the service name in <filename>/etc/services
+ </filename>. Substitute appropriate values for your system
+ in this line (see <command>inetd(8)</command>):</para>
+
+ <para><command>netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd
+ -d1 -l/var/adm/smblogs/log -s/usr/local/samba/lib/smb.conf</command></para>
+
+ <para>(The above should appear in <filename>/etc/inetd.conf</filename>
+ as a single line. Depending on your terminal characteristics, it may
+ not appear that way in this man page. If the above appears as more
+ than one line, please treat any newlines or indentation as a single
+ space or TAB character.)</para>
+
+ <para>Note that there is no need to specify a port number here,
+ even if you are using a non-standard port number.</para>
+
+ <para>Lastly, edit the configuration file to provide suitable
+ services. To start with, the following two services should be
+ all you need:</para>
+
+ <screen>
+ <computeroutput>
+ [homes]
+ writeable = yes
+
+ [printers]
+ writeable = no
+ printable = yes
+ path = /tmp
+ public = yes
+ </computeroutput>
+ </screen>
+
+ <para>This will allow you to connect to your home directory
+ and print to any printer supported by the host (user privileges
+ permitting).</para>
+</refsect1>
+
+<refsect1>
+ <title>PAM INTERACTION</title>
+ <para>Samba uses PAM for authentication (when presented with a plaintext
+ password), for account checking (is this account disabled?) and for
+ session management. The degree too which samba supports PAM is restricted
+ by the limitations of the SMB protocol and the
+ <ulink url="smb.conf.5.html#OBEYPAMRESRICTIONS">obey pam restricions</ulink>
+ smb.conf paramater. When this is set, the following restrictions apply:
+ </para>
+
+ <itemizedlist>
+ <listitem><para><emphasis>Account Validation</emphasis>: All acccesses to a
+ samba server are checked
+ against PAM to see if the account is vaild, not disabled and is permitted to
+ login at this time. This also applies to encrypted logins.
+ </para></listitem>
+
+ <listitem><para><emphasis>Session Management</emphasis>: When not using share
+ level secuirty, users must pass PAM's session checks before access
+ is granted. Note however, that this is bypassed in share level secuirty.
+ Note also that some older pam configuration files may need a line
+ added for session support.
+ </para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>TESTING THE INSTALLATION</title>
+
+ <para>If running the server as a daemon, execute it before
+ proceeding. If using a meta-daemon, either restart the system
+ or kill and restart the meta-daemon. Some versions of
+ <command>inetd</command> will reread their configuration
+ tables if they receive a HUP signal.</para>
+
+ <para>If your machine's name is <replaceable>fred</replaceable> and your
+ name is <replaceable>mary</replaceable>, you should now be able to connect
+ to the service <filename>\\fred\mary</filename>.
+ </para>
+
+ <para>To properly test and experiment with the server, we
+ recommend using the <command>smbclient</command> program (see
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command></ulink>)
+ and also going through the steps outlined in the file
+ <filename>DIAGNOSIS.txt</filename> in the <filename>docs/</filename>
+ directory of your Samba installation.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>DIAGNOSTICS</title>
+
+ <para>Most diagnostics issued by the server are logged
+ in a specified log file. The log file name is specified
+ at compile time, but may be overridden on the command line.</para>
+
+ <para>The number and nature of diagnostics available depends
+ on the debug level used by the server. If you have problems, set
+ the debug level to 3 and peruse the log files.</para>
+
+ <para>Most messages are reasonably self-explanatory. Unfortunately,
+ at the time this man page was created, there are too many diagnostics
+ available in the source code to warrant describing each and every
+ diagnostic. At this stage your best bet is still to grep the
+ source code and inspect the conditions that gave rise to the
+ diagnostics you are seeing.</para>
+</refsect1>
+
+<refsect1>
+ <title>SIGNALS</title>
+
+ <para>Sending the <command>smbd</command> a SIGHUP will cause it to
+ reload its <filename>smb.conf</filename> configuration
+ file within a short period of time.</para>
+
+ <para>To shut down a user's <command>smbd</command> process it is recommended
+ that <command>SIGKILL (-9)</command> <emphasis>NOT</emphasis>
+ be used, except as a last resort, as this may leave the shared
+ memory area in an inconsistent state. The safe way to terminate
+ an <command>smbd</command> is to send it a SIGTERM (-15) signal and wait for
+ it to die on its own.</para>
+
+ <para>The debug log level of <command>smbd</command> may be raised
+ or lowered using <ulink url="smbcontrol.1.html"><command>smbcontrol(1)
+ </command></ulink> program (SIGUSR[1|2] signals are no longer used in
+ Samba 2.2). This is to allow transient problems to be diagnosed,
+ whilst still running at a normally low log level.</para>
+
+ <para>Note that as the signal handlers send a debug write,
+ they are not re-entrant in <command>smbd</command>. This you should wait until
+ <command>smbd</command> is in a state of waiting for an incoming SMB before
+ issuing them. It is possible to make the signal handlers safe
+ by un-blocking the signals before the select call and re-blocking
+ them after, however this would affect performance.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para>hosts_access(5), <command>inetd(8)</command>,
+ <ulink url="nmbd.8.html"><command>nmbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html"><filename>smb.conf(5)</filename>
+ </ulink>, <ulink url="smbclient.1.html"><command>smbclient(1)
+ </command></ulink>, <ulink url="testparm.1.html"><command>
+ testparm(1)</command></ulink>, <ulink url="testprns.1.html">
+ <command>testprns(1)</command></ulink>, and the Internet RFC's
+ <filename>rfc1001.txt</filename>, <filename>rfc1002.txt</filename>.
+ In addition the CIFS (formerly SMB) specification is available
+ as a link from the Web page <ulink url="http://samba.org/cifs/">
+ http://samba.org/cifs/</ulink>.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbmnt.8.sgml b/docs/docbook/manpages/smbmnt.8.sgml
new file mode 100644
index 00000000000..55b66d5d25b
--- /dev/null
+++ b/docs/docbook/manpages/smbmnt.8.sgml
@@ -0,0 +1,113 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbmnt">
+
+<refmeta>
+ <refentrytitle>smbmnt</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbmnt</refname>
+ <refpurpose>helper utility for mounting SMB filesystems</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbmnt</command>
+ <arg choice="req">mount-point</arg>
+ <arg choice="opt">-s &lt;share&gt;</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-u &lt;uid&gt;</arg>
+ <arg choice="opt">-g &lt;gid&gt;</arg>
+ <arg choice="opt">-f &lt;mask&gt;</arg>
+ <arg choice="opt">-d &lt;mask&gt;</arg>
+ <arg choice="opt">-o &lt;options&gt;</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><command>smbmnt</command> is a helper application used
+ by the smbmount program to do the actual mounting of SMB shares.
+ <command>smbmnt</command> can be installed setuid root if you want
+ normal users to be able to mount their SMB shares.</para>
+
+ <para>A setuid smbmnt will only allow mounts on directories owned
+ by the user, and that the user has write permission on.</para>
+
+ <para>The <command>smbmnt</command> program is normally invoked
+ by <ulink url="smbmount.8.html"><command>smbmount(8)</command>
+ </ulink>. It should not be invoked directly by users. </para>
+
+ <para>smbmount searches the normal PATH for smbmnt. You must ensure
+ that the smbmnt version in your path matches the smbmount used.</para>
+
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>mount the filesystem read-only
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-u uid</term>
+ <listitem><para>specify the uid that the files will
+ be owned by </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-g gid</term>
+ <listitem><para>specify the gid that the files will be
+ owned by </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-f mask</term>
+ <listitem><para>specify the octal file mask applied
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-d mask</term>
+ <listitem><para>specify the octal directory mask
+ applied </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o options</term>
+ <listitem><para>
+ list of options that are passed as-is to smbfs, if this
+ command is run on a 2.4 or higher Linux kernel.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</para>
+
+ <para>The current maintainer of smbfs and the userspace
+ tools <command>smbmount</command>, <command>smbumount</command>,
+ and <command>smbmnt</command> is <ulink
+ url="mailto:urban@teststation.com">Urban Widmark</ulink>.
+ The <ulink url="mailto:samba@samba.org">SAMBA Mailing list</ulink>
+ is the preferred place to ask questions regarding these programs.
+ </para>
+
+ <para>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbmount.8.sgml b/docs/docbook/manpages/smbmount.8.sgml
new file mode 100644
index 00000000000..b4a77e51c9f
--- /dev/null
+++ b/docs/docbook/manpages/smbmount.8.sgml
@@ -0,0 +1,327 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbmount">
+
+<refmeta>
+ <refentrytitle>smbmount</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbmount</refname>
+ <refpurpose>mount an smbfs filesystem</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbumount</command>
+ <arg choice="req">service</arg>
+ <arg choice="req">mount-point</arg>
+ <arg choice="opt">-o options</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><command>smbmount</command> mounts a Linux SMB filesystem. It
+ is usually invoked as <command>mount.smbfs</command> by
+ the <command>mount(8)</command> command when using the
+ "-t smbfs" option. This command only works in Linux, and the kernel must
+ support the smbfs filesystem. </para>
+
+ <para>Options to <command>smbmount</command> are specified as a comma-separated
+ list of key=value pairs. It is possible to send options other
+ than those listed here, assuming that smbfs supports them. If
+ you get mount failures, check your kernel log for errors on
+ unknown options.</para>
+
+ <para><command>smbmount</command> is a daemon. After mounting it keeps running until
+ the mounted smbfs is umounted. It will log things that happen
+ when in daemon mode using the "machine name" smbmount, so
+ typically this output will end up in <filename>log.smbmount</filename>. The
+ <command>smbmount</command> process may also be called mount.smbfs.</para>
+
+ <para><emphasis>NOTE:</emphasis> <command>smbmount</command>
+ calls <command>smbmnt(8)</command> to do the actual mount. You
+ must make sure that <command>smbmnt</command> is in the path so
+ that it can be found. </para>
+
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>username=&lt;arg&gt;</term>
+ <listitem><para>specifies the username to connect as. If
+ this is not given, then the environment variable <envar>
+ USER</envar> is used. This option can also take the
+ form "user%password" or "user/workgroup" or
+ "user/workgroup%password" to allow the password and workgroup
+ to be specified as part of the username.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>password=&lt;arg&gt;</term>
+ <listitem><para>specifies the SMB password. If this
+ option is not given then the environment variable
+ <envar>PASSWD</envar> is used. If it can find
+ no password <command>smbmount</command> will prompt
+ for a passeword, unless the guest option is
+ given. </para>
+
+ <para>
+ Note that password which contain the arguement delimiter
+ character (i.e. a comma ',') will failed to be parsed correctly
+ on the command line. However, the same password defined
+ in the PASSWD environment variable or a credentials file (see
+ below) will be read correctly.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>credentials=&lt;filename&gt;</term>
+ <listitem><para>specifies a file that contains a username
+ and/or password. The format of the file is:</para>
+
+ <para>
+ <programlisting>
+ username = &lt;value&gt;
+ password = &lt;value&gt;
+ </programlisting>
+ </para>
+
+ <para>This is preferred over having passwords in plaintext in a
+ shared file, such as <filename>/etc/fstab</filename>. Be sure to protect any
+ credentials file properly.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>netbiosname=&lt;arg&gt;</term>
+ <listitem><para>sets the source NetBIOS name. It defaults
+ to the local hostname. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>uid=&lt;arg&gt;</term>
+ <listitem><para>sets the uid that will own all files on
+ the mounted filesystem.
+ It may be specified as either a username or a numeric uid.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>gid=&lt;arg&gt;</term>
+ <listitem><para>sets the gid that will own all files on
+ the mounted filesystem.
+ It may be specified as either a groupname or a numeric
+ gid. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>port=&lt;arg&gt;</term>
+ <listitem><para>sets the remote SMB port number. The default
+ is 139. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>fmask=&lt;arg&gt;</term>
+ <listitem><para>sets the file mask. This determines the
+ permissions that remote files have in the local filesystem.
+ The default is based on the current umask. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>dmask=&lt;arg&gt;</term>
+ <listitem><para>sets the directory mask. This determines the
+ permissions that remote directories have in the local filesystem.
+ The default is based on the current umask. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>debug=&lt;arg&gt;</term>
+ <listitem><para>sets the debug level. This is useful for
+ tracking down SMB connection problems. A suggested value to
+ start with is 4. If set too high there will be a lot of
+ output, possibly hiding the useful output.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>ip=&lt;arg&gt;</term>
+ <listitem><para>sets the destination host or IP address.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>workgroup=&lt;arg&gt;</term>
+ <listitem><para>sets the workgroup on the destination </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>sockopt=&lt;arg&gt;</term>
+ <listitem><para>sets the TCP socket options. See the <ulink
+ url="smb.conf.5.html#SOCKETOPTIONS"><filename>smb.conf
+ </filename></ulink> <parameter>socket options</parameter> option.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>scope=&lt;arg&gt;</term>
+ <listitem><para>sets the NetBIOS scope </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>guest</term>
+ <listitem><para>don't prompt for a password </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>ro</term>
+ <listitem><para>mount read-only </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>rw</term><listitem><para>mount read-write </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>iocharset=&lt;arg&gt;</term>
+ <listitem><para>
+ sets the charset used by the Linux side for codepage
+ to charset translations (NLS). Argument should be the
+ name of a charset, like iso8859-1. (Note: only kernel
+ 2.4.0 or later)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>codepage=&lt;arg&gt;</term>
+ <listitem><para>
+ sets the codepage the server uses. See the iocharset
+ option. Example value cp850. (Note: only kernel 2.4.0
+ or later)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ttl=&lt;arg&gt;</term>
+ <listitem><para>
+ how long a directory listing is cached in milliseconds
+ (also affects visibility of file size and date
+ changes). A higher value means that changes on the
+ server take longer to be noticed but it can give
+ better performance on large directories, especially
+ over long distances. Default is 1000ms but something
+ like 10000ms (10 seconds) is probably more reasonable
+ in many cases.
+ (Note: only kernel 2.4.2 or later)
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT VARIABLES</title>
+
+ <para>The variable <envar>USER</envar> may contain the username of the
+ person using the client. This information is used only if the
+ protocol level is high enough to support session-level
+ passwords. The variable can be used to set both username and
+ password by using the format username%password.</para>
+
+ <para>The variable <envar>PASSWD</envar> may contain the password of the
+ person using the client. This information is used only if the
+ protocol level is high enough to support session-level
+ passwords.</para>
+
+ <para>The variable <envar>PASSWD_FILE</envar> may contain the pathname
+ of a file to read the password from. A single line of input is
+ read and used as the password.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>BUGS</title>
+
+ <para>Passwords and other options containing , can not be handled.
+ For passwords an alternative way of passing them is in a credentials
+ file or in the PASSWD environment.</para>
+
+ <para>The credentials file does not handle usernames or passwords with
+ leading space.</para>
+
+ <para>One smbfs bug is important enough to mention here, even if it
+ is a bit misplaced:</para>
+
+ <itemizedlist>
+
+ <listitem><para>Mounts sometimes stop working. This is usually
+ caused by smbmount terminating. Since smbfs needs smbmount to
+ reconnect when the server disconnects, the mount will eventually go
+ dead. An umount/mount normally fixes this. At least 2 ways to
+ trigger this bug are known.</para></listitem>
+
+ </itemizedlist>
+
+ <para>Note that the typical response to a bug report is suggestion
+ to try the latest version first. So please try doing that first,
+ and always include which versions you use of relevant software
+ when reporting bugs (minimum: samba, kernel, distribution)</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>Documentation/filesystems/smbfs.txt in the linux kernel
+ source tree may contain additional options and information.</para>
+
+ <para>FreeBSD also has a smbfs, but it is not related to smbmount</para>
+
+ <para>For Solaris, HP-UX and others you may want to look at
+ <ulink url="smbsh.1.html"><command>smbsh(1)</command></ulink> or at other
+ solutions, such as sharity or perhaps replacing the SMB server with
+ a NFS server.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</para>
+
+ <para>The current maintainer of smbfs and the userspace
+ tools <command>smbmount</command>, <command>smbumount</command>,
+ and <command>smbmnt</command> is <ulink
+ url="mailto:urban@teststation.com">Urban Widmark</ulink>.
+ The <ulink url="mailto:samba@samba.org">SAMBA Mailing list</ulink>
+ is the preferred place to ask questions regarding these programs.
+ </para>
+
+ <para>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbpasswd.5.sgml b/docs/docbook/manpages/smbpasswd.5.sgml
new file mode 100644
index 00000000000..be751078192
--- /dev/null
+++ b/docs/docbook/manpages/smbpasswd.5.sgml
@@ -0,0 +1,204 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbpasswd">
+
+<refmeta>
+ <refentrytitle>smbpasswd</refentrytitle>
+ <manvolnum>5</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbpasswd</refname>
+ <refpurpose>The Samba encrypted password file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <para><filename>smbpasswd</filename></para>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para>smbpasswd is the Samba encrypted password file. It contains
+ the username, Unix user id and the SMB hashed passwords of the
+ user, as well as account flag information and the time the
+ password was last changed. This file format has been evolving with
+ Samba and has had several different formats in the past. </para>
+</refsect1>
+
+<refsect1>
+ <title>FILE FORMAT</title>
+
+ <para>The format of the smbpasswd file used by Samba 2.2
+ is very similar to the familiar Unix <filename>passwd(5)</filename>
+ file. It is an ASCII file containing one line for each user. Each field
+ ithin each line is separated from the next by a colon. Any entry
+ beginning with '#' is ignored. The smbpasswd file contains the
+ following information for each user: </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>name</term>
+ <listitem><para> This is the user name. It must be a name that
+ already exists in the standard UNIX passwd file. </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>uid</term>
+ <listitem><para>This is the UNIX uid. It must match the uid
+ field for the same user entry in the standard UNIX passwd file.
+ If this does not match then Samba will refuse to recognize
+ this smbpasswd file entry as being valid for a user.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>Lanman Password Hash</term>
+ <listitem><para>This is the LANMAN hash of the user's password,
+ encoded as 32 hex digits. The LANMAN hash is created by DES
+ encrypting a well known string with the user's password as the
+ DES key. This is the same password used by Windows 95/98 machines.
+ Note that this password hash is regarded as weak as it is
+ vulnerable to dictionary attacks and if two users choose the
+ same password this entry will be identical (i.e. the password
+ is not "salted" as the UNIX password is). If the user has a
+ null password this field will contain the characters "NO PASSWORD"
+ as the start of the hex string. If the hex string is equal to
+ 32 'X' characters then the user's account is marked as
+ <constant>disabled</constant> and the user will not be able to
+ log onto the Samba server. </para>
+
+ <para><emphasis>WARNING !!</emphasis> Note that, due to
+ the challenge-response nature of the SMB/CIFS authentication
+ protocol, anyone with a knowledge of this password hash will
+ be able to impersonate the user on the network. For this
+ reason these hashes are known as <emphasis>plain text
+ equivalents</emphasis> and must <emphasis>NOT</emphasis> be made
+ available to anyone but the root user. To protect these passwords
+ the smbpasswd file is placed in a directory with read and
+ traverse access only to the root user and the smbpasswd file
+ itself must be set to be read/write only by root, with no
+ other access. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>NT Password Hash</term>
+ <listitem><para>This is the Windows NT hash of the user's
+ password, encoded as 32 hex digits. The Windows NT hash is
+ created by taking the user's password as represented in
+ 16-bit, little-endian UNICODE and then applying the MD4
+ (internet rfc1321) hashing algorithm to it. </para>
+
+ <para>This password hash is considered more secure than
+ the LANMAN Password Hash as it preserves the case of the
+ password and uses a much higher quality hashing algorithm.
+ However, it is still the case that if two users choose the same
+ password this entry will be identical (i.e. the password is
+ not "salted" as the UNIX password is). </para>
+
+ <para><emphasis>WARNING !!</emphasis>. Note that, due to
+ the challenge-response nature of the SMB/CIFS authentication
+ protocol, anyone with a knowledge of this password hash will
+ be able to impersonate the user on the network. For this
+ reason these hashes are known as <emphasis>plain text
+ equivalents</emphasis> and must <emphasis>NOT</emphasis> be made
+ available to anyone but the root user. To protect these passwords
+ the smbpasswd file is placed in a directory with read and
+ traverse access only to the root user and the smbpasswd file
+ itself must be set to be read/write only by root, with no
+ other access. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>Account Flags</term>
+ <listitem><para>This section contains flags that describe
+ the attributes of the users account. In the Samba 2.2 release
+ this field is bracketed by '[' and ']' characters and is always
+ 13 characters in length (including the '[' and ']' characters).
+ The contents of this field may be any of the characters.
+ </para>
+
+ <itemizedlist>
+ <listitem><para><emphasis>U</emphasis> - This means
+ this is a "User" account, i.e. an ordinary user. Only User
+ and Workstation Trust accounts are currently supported
+ in the smbpasswd file. </para></listitem>
+
+ <listitem><para><emphasis>N</emphasis> - This means the
+ account has no password (the passwords in the fields LANMAN
+ Password Hash and NT Password Hash are ignored). Note that this
+ will only allow users to log on with no password if the <parameter>
+ null passwords</parameter> parameter is set in the <ulink
+ url="smb.conf.5.html#NULLPASSWORDS"><filename>smb.conf(5)
+ </filename></ulink> config file. </para></listitem>
+
+ <listitem><para><emphasis>D</emphasis> - This means the account
+ is disabled and no SMB/CIFS logins will be allowed for
+ this user. </para></listitem>
+
+ <listitem><para><emphasis>W</emphasis> - This means this account
+ is a "Workstation Trust" account. This kind of account is used
+ in the Samba PDC code stream to allow Windows NT Workstations
+ and Servers to join a Domain hosted by a Samba PDC. </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Other flags may be added as the code is extended in future.
+ The rest of this field space is filled in with spaces. </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>Last Change Time</term>
+ <listitem><para>This field consists of the time the account was
+ last modified. It consists of the characters 'LCT-' (standing for
+ "Last Change Time") followed by a numeric encoding of the UNIX time
+ in seconds since the epoch (1970) that the last change was made.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>All other colon separated fields are ignored at this time.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbpasswd.8.html"><command>smbpasswd(8)</command></ulink>,
+ <ulink url="samba.7.html">samba(7)</ulink>, and
+ the Internet RFC1321 for details on the MD4 algorithm.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbpasswd.8.sgml b/docs/docbook/manpages/smbpasswd.8.sgml
new file mode 100644
index 00000000000..098e874cc85
--- /dev/null
+++ b/docs/docbook/manpages/smbpasswd.8.sgml
@@ -0,0 +1,426 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbpasswd">
+
+<refmeta>
+ <refentrytitle>smbpasswd</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbpasswd</refname>
+ <refpurpose>change a user's SMB password</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbpasswd</command>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-x</arg>
+ <arg choice="opt">-d</arg>
+ <arg choice="opt">-e</arg>
+ <arg choice="opt">-D debuglevel</arg>
+ <arg choice="opt">-n</arg>
+ <arg choice="opt">-r &lt;remote machine&gt;</arg>
+ <arg choice="opt">-R &lt;name resolve order&gt;</arg>
+ <arg choice="opt">-m</arg>
+ <arg choice="opt">-j DOMAIN</arg>
+ <arg choice="opt">-U username[%password]</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-s</arg>
+ <arg choice="opt">-w pass</arg>
+ <arg choice="opt">username</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para>The smbpasswd program has several different
+ functions, depending on whether it is run by the <emphasis>root</emphasis>
+ user or not. When run as a normal user it allows the user to change
+ the password used for their SMB sessions on any machines that store
+ SMB passwords. </para>
+
+ <para>By default (when run with no arguments) it will attempt to
+ change the current user's SMB password on the local machine. This is
+ similar to the way the <command>passwd(1)</command> program works.
+ <command>smbpasswd</command> differs from how the passwd program works
+ however in that it is not <emphasis>setuid root</emphasis> but works in
+ a client-server mode and communicates with a locally running
+ <command>smbd(8)</command>. As a consequence in order for this to
+ succeed the smbd daemon must be running on the local machine. On a
+ UNIX machine the encrypted SMB passwords are usually stored in
+ the <filename>smbpasswd(5)</filename> file. </para>
+
+ <para>When run by an ordinary user with no options. smbpasswd
+ will prompt them for their old SMB password and then ask them
+ for their new password twice, to ensure that the new password
+ was typed correctly. No passwords will be echoed on the screen
+ whilst being typed. If you have a blank SMB password (specified by
+ the string "NO PASSWORD" in the smbpasswd file) then just press
+ the &lt;Enter&gt; key when asked for your old password. </para>
+
+ <para>smbpasswd can also be used by a normal user to change their
+ SMB password on remote machines, such as Windows NT Primary Domain
+ Controllers. See the (-r) and -U options below. </para>
+
+ <para>When run by root, smbpasswd allows new users to be added
+ and deleted in the smbpasswd file, as well as allows changes to
+ the attributes of the user in this file to be made. When run by root,
+ <command>smbpasswd</command> accesses the local smbpasswd file
+ directly, thus enabling changes to be made even if smbd is not
+ running. </para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>This option specifies that the username
+ following should be added to the local smbpasswd file, with the
+ new password typed (type &lt;Enter&gt; for the old password). This
+ option is ignored if the username following already exists in
+ the smbpasswd file and it is treated like a regular change
+ password command. Note that the user to be added must already exist
+ in the system password file (usually <filename>/etc/passwd</filename>)
+ else the request to add the user will fail. </para>
+
+ <para>This option is only available when running smbpasswd
+ as root. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-x</term>
+ <listitem><para>This option specifies that the username
+ following should be deleted from the local smbpasswd file.
+ </para>
+
+ <para>This option is only available when running smbpasswd as
+ root.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-d</term>
+ <listitem><para>This option specifies that the username following
+ should be <constant>disabled</constant> in the local smbpasswd
+ file. This is done by writing a <constant>'D'</constant> flag
+ into the account control space in the smbpasswd file. Once this
+ is done all attempts to authenticate via SMB using this username
+ will fail. </para>
+
+ <para>If the smbpasswd file is in the 'old' format (pre-Samba 2.0
+ format) there is no space in the user's password entry to write
+ this information and so the user is disabled by writing 'X' characters
+ into the password space in the smbpasswd file. See <command>smbpasswd(5)
+ </command> for details on the 'old' and new password file formats.
+ </para>
+
+ <para>This option is only available when running smbpasswd as
+ root.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-e</term>
+ <listitem><para>This option specifies that the username following
+ should be <constant>enabled</constant> in the local smbpasswd file,
+ if the account was previously disabled. If the account was not
+ disabled this option has no effect. Once the account is enabled then
+ the user will be able to authenticate via SMB once again. </para>
+
+ <para>If the smbpasswd file is in the 'old' format, then <command>
+ smbpasswd</command> will prompt for a new password for this user,
+ otherwise the account will be enabled by removing the <constant>'D'
+ </constant> flag from account control space in the <filename>
+ smbpasswd</filename> file. See <command>smbpasswd (5)</command> for
+ details on the 'old' and new password file formats. </para>
+
+ <para>This option is only available when running smbpasswd as root.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-D debuglevel</term>
+ <listitem><para><replaceable>debuglevel</replaceable> is an integer
+ from 0 to 10. The default value if this parameter is not specified
+ is zero. </para>
+
+ <para>The higher this value, the more detail will be logged to the
+ log files about the activities of smbpasswd. At level 0, only
+ critical errors and serious warnings will be logged. </para>
+
+ <para>Levels above 1 will generate considerable amounts of log
+ data, and should only be used when investigating a problem. Levels
+ above 3 are designed for use only by developers and generate
+ HUGE amounts of log data, most of which is extremely cryptic.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-n</term>
+ <listitem><para>This option specifies that the username following
+ should have their password set to null (i.e. a blank password) in
+ the local smbpasswd file. This is done by writing the string "NO
+ PASSWORD" as the first part of the first password stored in the
+ smbpasswd file. </para>
+
+ <para>Note that to allow users to logon to a Samba server once
+ the password has been set to "NO PASSWORD" in the smbpasswd
+ file the administrator must set the following parameter in the [global]
+ section of the <filename>smb.conf</filename> file : </para>
+
+ <para><command>null passwords = yes</command></para>
+
+ <para>This option is only available when running smbpasswd as
+ root.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-r remote machine name</term>
+ <listitem><para>This option allows a user to specify what machine
+ they wish to change their password on. Without this parameter
+ smbpasswd defaults to the local host. The <replaceable>remote
+ machine name</replaceable> is the NetBIOS name of the SMB/CIFS
+ server to contact to attempt the password change. This name is
+ resolved into an IP address using the standard name resolution
+ mechanism in all programs of the Samba suite. See the <parameter>-R
+ name resolve order</parameter> parameter for details on changing
+ this resolving mechanism. </para>
+
+ <para>The username whose password is changed is that of the
+ current UNIX logged on user. See the <parameter>-U username</parameter>
+ parameter for details on changing the password for a different
+ username. </para>
+
+ <para>Note that if changing a Windows NT Domain password the
+ remote machine specified must be the Primary Domain Controller for
+ the domain (Backup Domain Controllers only have a read-only
+ copy of the user account database and will not allow the password
+ change).</para>
+
+ <para><emphasis>Note</emphasis> that Windows 95/98 do not have
+ a real password database so it is not possible to change passwords
+ specifying a Win95/98 machine as remote machine target. </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-R name resolve order</term>
+ <listitem><para>This option allows the user of smbpasswd to determine
+ what name resolution services to use when looking up the NetBIOS
+ name of the host being connected to. </para>
+
+ <para>The options are :"lmhosts", "host", "wins" and "bcast". They cause
+ names to be resolved as follows : </para>
+ <itemizedlist>
+ <listitem><para><constant>lmhosts</constant> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <ulink
+ url="lmhosts.5.html">lmhosts(5)</ulink> for details) then
+ any name type matches for lookup.</para></listitem>
+
+ <listitem><para><constant>host</constant> : Do a standard host
+ name to IP address resolution, using the system <filename>/etc/hosts
+ </filename>, NIS, or DNS lookups. This method of name resolution
+ is operating system depended for instance on IRIX or Solaris this
+ may be controlled by the <filename>/etc/nsswitch.conf</filename>
+ file). Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</para></listitem>
+
+ <listitem><para><constant>wins</constant> : Query a name with
+ the IP address listed in the <parameter>wins server</parameter>
+ parameter. If no WINS server has been specified this method
+ will be ignored.</para></listitem>
+
+ <listitem><para><constant>bcast</constant> : Do a broadcast on
+ each of the known local interfaces listed in the
+ <parameter>interfaces</parameter> parameter. This is the least
+ reliable of the name resolution methods as it depends on the
+ target host being on a locally connected subnet.</para></listitem>
+ </itemizedlist>
+
+ <para>The default order is <command>lmhosts, host, wins, bcast</command>
+ and without this parameter or any entry in the
+ <filename>smb.conf</filename> file the name resolution methods will
+ be attempted in this order. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-m</term>
+ <listitem><para>This option tells smbpasswd that the account
+ being changed is a MACHINE account. Currently this is used
+ when Samba is being used as an NT Primary Domain Controller.</para>
+
+ <para>This option is only available when running smbpasswd as root.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-j DOMAIN</term>
+ <listitem><para>This option is used to add a Samba server
+ into a Windows NT Domain, as a Domain member capable of authenticating
+ user accounts to any Domain Controller in the same way as a Windows
+ NT Server. See the <command>security = domain</command> option in
+ the <filename>smb.conf(5)</filename> man page. </para>
+
+ <para>In order to be used in this way, the Administrator for
+ the Windows NT Domain must have used the program "Server Manager
+ for Domains" to add the primary NetBIOS name of the Samba server
+ as a member of the Domain. </para>
+
+ <para>After this has been done, to join the Domain invoke <command>
+ smbpasswd</command> with this parameter. smbpasswd will then
+ look up the Primary Domain Controller for the Domain (found in
+ the <filename>smb.conf</filename> file in the parameter
+ <parameter>password server</parameter> and change the machine account
+ password used to create the secure Domain communication. This
+ password is then stored by smbpasswd in a TDB, writeable only by root,
+ called <filename>secrets.tdb</filename> </para>
+
+ <para>Once this operation has been performed the <filename>
+ smb.conf</filename> file may be updated to set the <command>
+ security = domain</command> option and all future logins
+ to the Samba server will be authenticated to the Windows NT
+ PDC. </para>
+
+ <para>Note that even though the authentication is being
+ done to the PDC all users accessing the Samba server must still
+ have a valid UNIX account on that machine. </para>
+
+
+ <para>This option is only available when running smbpasswd as root.
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-U username</term>
+ <listitem><para>This option may only be used in conjunction
+ with the <parameter>-r</parameter> option. When changing
+ a password on a remote machine it allows the user to specify
+ the user name on that machine whose password will be changed. It
+ is present to allow users who have different user names on
+ different systems to change these passwords. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>This option prints the help string for <command>
+ smbpasswd</command>, selecting the correct one for running as root
+ or as an ordinary user. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-s</term>
+ <listitem><para>This option causes smbpasswd to be silent (i.e.
+ not issue prompts) and to read its old and new passwords from
+ standard input, rather than from <filename>/dev/tty</filename>
+ (like the <command>passwd(1)</command> program does). This option
+ is to aid people writing scripts to drive smbpasswd</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-w password</term>
+ <listitem><para>This parameter is only available is Samba
+ has been configured to use the experiemental
+ <command>--with-ldapsam</command> option. The <parameter>-w</parameter>
+ switch is used to specify the password to be used with the
+ <ulink url="smb.conf.5.html#LDAPADMINDN"><parameter>ldap admin
+ dn</parameter></ulink>. Note that the password is stored in
+ the <filename>private/secrets.tdb</filename> and is keyed off
+ of the admin's DN. This means that if the value of <parameter>ldap
+ admin dn</parameter> ever changes, the password will beed to be
+ manually updated as well.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>username</term>
+ <listitem><para>This specifies the username for all of the
+ <emphasis>root only</emphasis> options to operate on. Only root
+ can specify this parameter as only root has the permission needed
+ to modify attributes directly in the local smbpasswd file.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>NOTES</title>
+
+ <para>Since <command>smbpasswd</command> works in client-server
+ mode communicating with a local smbd for a non-root user then
+ the smbd daemon must be running for this to work. A common problem
+ is to add a restriction to the hosts that may access the <command>
+ smbd</command> running on the local machine by specifying a
+ <parameter>allow hosts</parameter> or <parameter>deny hosts</parameter>
+ entry in the <filename>smb.conf</filename> file and neglecting to
+ allow "localhost" access to the smbd. </para>
+
+ <para>In addition, the smbpasswd command is only useful if Samba
+ has been set up to use encrypted passwords. See the file
+ <filename>ENCRYPTION.txt</filename> in the docs directory for details
+ on how to do this. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbpasswd.5.html"><filename>smbpasswd(5)</filename></ulink>,
+ <ulink url="samba.7.html">samba(7)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbsh.1.sgml b/docs/docbook/manpages/smbsh.1.sgml
new file mode 100644
index 00000000000..46adac6b79d
--- /dev/null
+++ b/docs/docbook/manpages/smbsh.1.sgml
@@ -0,0 +1,105 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbsh">
+
+<refmeta>
+ <refentrytitle>smbsh</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbsh</refname>
+ <refpurpose>Allows access to Windows NT filesystem
+ using UNIX commands</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbsh</command>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>smbsh</command> allows you to access an NT filesystem
+ using UNIX commands such as <command>ls</command>, <command>
+ egrep</command>, and <command>rcp</command>. You must use a
+ shell that is dynamically linked in order for <command>smbsh</command>
+ to work correctly.</para>
+
+ <para>To use the <command>smbsh</command> command, execute <command>
+ smbsh</command> from the prompt and enter the username and password
+ that authenticates you to the machine running the Windows NT
+ operating system.</para>
+
+ <para><programlisting>
+ <prompt>system% </prompt><userinput>smbsh</userinput>
+ <prompt>Username: </prompt><userinput>user</userinput>
+ <prompt>Password: </prompt><userinput>XXXXXXX</userinput>
+ </programlisting></para>
+
+
+ <para>Any dynamically linked command you execute from
+ this shell will access the <filename>/smb</filename> directory
+ using the smb protocol. For example, the command <command>ls /smb
+ </command> will show a list of workgroups. The command
+ <command>ls /smb/MYGROUP </command> will show all the machines in
+ the workgroup MYGROUP. The command
+ <command>ls /smb/MYGROUP/&lt;machine-name&gt;</command> will show the share
+ names for that machine. You could then, for example, use the <command>
+ cd</command> command to change directories, <command>vi</command> to
+ edit files, and <command>rcp</command> to copy files.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>BUGS</title>
+
+ <para><command>smbsh</command> works by intercepting the standard
+ libc calls with the dynamically loaded versions in <filename>
+ smbwrapper.o</filename>. Not all calls have been "wrapped", so
+ some programs may not function correctly under <command>smbsh
+ </command>.</para>
+
+ <para>Programs which are not dynamically linked cannot make
+ use of <command>smbsh</command>'s functionality. Most versions
+ of UNIX have a <command>file</command> command that will
+ describe how a program was linked.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbspool.8.sgml b/docs/docbook/manpages/smbspool.8.sgml
new file mode 100644
index 00000000000..d5c9c0a1148
--- /dev/null
+++ b/docs/docbook/manpages/smbspool.8.sgml
@@ -0,0 +1,131 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbspool">
+
+<refmeta>
+ <refentrytitle>smbspool</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbspool</refname>
+ <refpurpose>send print file to an SMB printer</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbspool</command>
+ <arg>job</arg>
+ <arg>user</arg>
+ <arg>title</arg>
+ <arg>copies</arg>
+ <arg>options</arg>
+ <arg>filename</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para>smbspool is a very small print spooling program that
+ sends a print file to an SMB printer. The command-line arguments
+ are position-dependent for compatibility with the Common UNIX
+ Printing System, but you can use smbspool with any printing system
+ or from a program or script.</para>
+
+ <para><emphasis>DEVICE URI</emphasis></para>
+
+ <para>smbspool specifies the destination using a Uniform Resource
+ Identifier ("URI") with a method of "smb". This string can take
+ a number of forms:</para>
+
+ <itemizedlist>
+ <listitem><para>smb://server/printer</para></listitem>
+ <listitem><para>smb://workgroup/server/printer</para></listitem>
+ <listitem><para>smb://username:password@server/printer</para>
+ </listitem>
+ <listitem><para>smb://username:password@workgroup/server/printer
+ </para></listitem>
+ </itemizedlist>
+
+ <para>smbspool tries to get the URI from argv[0]. If argv[0]
+ contains the name of the program then it looks in the <envar>
+ DEVICE_URI</envar> environment variable.</para>
+
+ <para>Programs using the <command>exec(2)</command> functions can
+ pass the URI in argv[0], while shell scripts must set the
+ <envar>DEVICE_URI</envar> environment variable prior to
+ running smbspool.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <itemizedlist>
+ <listitem><para>The job argument (argv[1]) contains the
+ job ID number and is presently not used by smbspool.
+ </para></listitem>
+
+ <listitem><para>The user argument (argv[2]) contains the
+ print user's name and is presently not used by smbspool.
+ </para></listitem>
+
+ <listitem><para>The title argument (argv[3]) contains the
+ job title string and is passed as the remote file name
+ when sending the print job.</para></listitem>
+
+ <listitem><para>The copies argument (argv[4]) contains
+ the number of copies to be printed of the named file. If
+ no filename is provided than this argument is not used by
+ smbspool.</para></listitem>
+
+ <listitem><para>The options argument (argv[5]) contains
+ the print options in a single string and is presently
+ not used by smbspool.</para></listitem>
+
+ <listitem><para>The filename argument (argv[6]) contains the
+ name of the file to print. If this argument is not specified
+ then the print file is read from the standard input.</para>
+ </listitem>
+ </itemizedlist>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ and <ulink url="samba.7.html">samba(7)</ulink>.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para><command>smbspool</command> was written by Michael Sweet
+ at Easy Software Products.</para>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbstatus.1.sgml b/docs/docbook/manpages/smbstatus.1.sgml
new file mode 100644
index 00000000000..c2f638b88ef
--- /dev/null
+++ b/docs/docbook/manpages/smbstatus.1.sgml
@@ -0,0 +1,137 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbstatus">
+
+<refmeta>
+ <refentrytitle>smbstatus</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbstatus</refname>
+ <refpurpose>report on current Samba connections</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbstatus</command>
+ <arg choice="opt">-P</arg>
+ <arg choice="opt">-b</arg>
+ <arg choice="opt">-d</arg>
+ <arg choice="opt">-L</arg>
+ <arg choice="opt">-p</arg>
+ <arg choice="opt">-S</arg>
+ <arg choice="opt">-s &lt;configuration file&gt;</arg>
+ <arg choice="opt">-u &lt;username&gt;</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>smbstatus</command> is a very simple program to
+ list the current Samba connections.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-P</term>
+ <listitem><para>If samba has been compiled with the
+ profiling option, print only the contents of the profiling
+ shared memory area.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b</term>
+ <listitem><para>gives brief output.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-d</term>
+ <listitem><para>gives verbose output.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-L</term>
+ <listitem><para>causes smbstatus to only list locks.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-p</term>
+ <listitem><para>print a list of <ulink url="smbd.8.html">
+ <command>smbd(8)</command></ulink> processes and exit.
+ Useful for scripting.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-S</term>
+ <listitem><para>causes smbstatus to only list shares.</para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-s &lt;configuration file&gt;</term>
+ <listitem><para>The default configuration file name is
+ determined at compile time. The file specified contains the
+ configuration details required by the server. See <ulink
+ url="smb.conf.5.html"><filename>smb.conf(5)</filename>
+ </ulink> for more information.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-u &lt;username&gt;</term>
+ <listitem><para>selects information relevant to
+ <parameter>username</parameter> only.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink> and
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbtar.1.sgml b/docs/docbook/manpages/smbtar.1.sgml
new file mode 100644
index 00000000000..4e2ee5fff0a
--- /dev/null
+++ b/docs/docbook/manpages/smbtar.1.sgml
@@ -0,0 +1,226 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbtar">
+
+<refmeta>
+ <refentrytitle>smbtar</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbtar</refname>
+ <refpurpose>shell script for backing up SMB/CIFS shares
+ directly to UNIX tape drives</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbtar</command>
+ <arg choice="req">-s server</arg>
+ <arg choice="opt">-p password</arg>
+ <arg choice="opt">-x services</arg>
+ <arg choice="opt">-X</arg>
+ <arg choice="opt">-d directory</arg>
+ <arg choice="opt">-u user</arg>
+ <arg choice="opt">-t tape</arg>
+ <arg choice="opt">-t tape</arg>
+ <arg choice="opt">-b blocksize</arg>
+ <arg choice="opt">-N filename</arg>
+ <arg choice="opt">-i</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-l loglevel</arg>
+ <arg choice="opt">-v</arg>
+ <arg choice="req">filenames</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>smbtar</command> is a very small shell script on top
+ of <ulink url="smbclient.1.html"><command>smbclient(1)</command></ulink>
+ which dumps SMB shares directly to tape. </para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-s server</term>
+ <listitem><para>The SMB/CIFS server that the share resides
+ upon.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-x service</term>
+ <listitem><para>The share name on the server to connect to.
+ The default is "backup".</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-X</term>
+ <listitem><para>Exclude mode. Exclude filenames... from tar
+ create or restore. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-d directory</term>
+ <listitem><para>Change to initial <parameter>directory
+ </parameter> before restoring / backing up files. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>Verbose mode.</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-p password</term>
+ <listitem><para>The password to use to access a share.
+ Default: none </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-u user</term>
+ <listitem><para>The user id to connect as. Default:
+ UNIX login name. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-t tape</term>
+ <listitem><para>Tape device. May be regular file or tape
+ device. Default: <parameter>$TAPE</parameter> environmental
+ variable; if not set, a file called <filename>tar.out
+ </filename>. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-b blocksize</term>
+ <listitem><para>Blocking factor. Defaults to 20. See
+ <command>tar(1)</command> for a fuller explanation. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-N filename</term>
+ <listitem><para>Backup only files newer than filename. Could
+ be used (for example) on a log file to implement incremental
+ backups. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-i</term>
+ <listitem><para>Incremental mode; tar files are only backed
+ up if they have the archive bit set. The archive bit is reset
+ after each file is read. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>Restore. Files are restored to the share
+ from the tar file. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-l log level</term>
+ <listitem><para>Log (debug) level. Corresponds to the
+ <parameter>-d</parameter> flag of <command>smbclient(1)
+ </command>. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>ENVIRONMENT VARIABLES</title>
+
+ <para>The <parameter>$TAPE</parameter> variable specifies the
+ default tape device to write to. May be overridden
+ with the -t option. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>BUGS</title>
+
+ <para>The <command>smbtar</command> script has different
+ options from ordinary tar and tar called from smbclient. </para>
+
+</refsect1>
+
+<refsect1>
+ <title>CAVEATS</title>
+
+ <para>Sites that are more careful about security may not like
+ the way the script handles PC passwords. Backup and restore work
+ on entire shares, should work on file lists. smbtar works best
+ with GNU tar and may not work well with other versions. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>DIAGNOSTICS</title>
+
+ <para>See the <emphasis>DIAGNOSTICS</emphasis> section for the
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command>
+ </ulink> command.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>,
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para><ulink url="mailto:poultenr@logica.co.uk">Ricky Poulten</ulink>
+ wrote the tar extension and this man page. The <command>smbtar</command>
+ script was heavily rewritten and improved by <ulink
+ url="mailto:Martin.Kraemer@mch.sni.de">Martin Kraemer</ulink>. Many
+ thanks to everyone who suggested extensions, improvements, bug
+ fixes, etc. The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter.</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/smbumount.8.sgml b/docs/docbook/manpages/smbumount.8.sgml
new file mode 100644
index 00000000000..d6a1b65b578
--- /dev/null
+++ b/docs/docbook/manpages/smbumount.8.sgml
@@ -0,0 +1,73 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="smbumount">
+
+<refmeta>
+ <refentrytitle>smbumount</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbumount</refname>
+ <refpurpose>smbfs umount for normal users</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbumount</command>
+ <arg choice="req">mount-point</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>With this program, normal users can unmount smb-filesystems,
+ provided that it is suid root. <command>smbumount</command> has
+ been written to give normal Linux users more control over their
+ resources. It is safe to install this program suid root, because only
+ the user who has mounted a filesystem is allowed to unmount it again.
+ For root it is not necessary to use smbumount. The normal umount
+ program works perfectly well, but it would certainly be problematic
+ to make umount setuid root.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>mount-point</term>
+ <listitem><para>The directory to unmount.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para><ulink url="smbmount.8.html"><command>smbmount(8)</command>
+ </ulink></para>
+</refsect1>
+
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</para>
+
+ <para>The current maintainer of smbfs and the userspace
+ tools <command>smbmount</command>, <command>smbumount</command>,
+ and <command>smbmnt</command> is <ulink
+ url="mailto:urban@teststation.com">Urban Widmark</ulink>.
+ The <ulink url="mailto:samba@samba.org">SAMBA Mailing list</ulink>
+ is the preferred place to ask questions regarding these programs.
+ </para>
+
+ <para>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/swat.8.sgml b/docs/docbook/manpages/swat.8.sgml
new file mode 100644
index 00000000000..dc6989d5663
--- /dev/null
+++ b/docs/docbook/manpages/swat.8.sgml
@@ -0,0 +1,209 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="swat">
+
+<refmeta>
+ <refentrytitle>swat</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>swat</refname>
+ <refpurpose>Samba Web Administration Tool</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>swat</command>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-a</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+
+ <para><command>swat</command> allows a Samba administrator to
+ configure the complex <ulink url="smb.conf.5.html"><filename>
+ smb.conf(5)</filename></ulink> file via a Web browser. In addition,
+ a <command>swat</command> configuration page has help links
+ to all the configurable options in the <filename>smb.conf</filename> file allowing an
+ administrator to easily look up the effects of any change. </para>
+
+ <para><command>swat</command> is run from <command>inetd</command> </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-s smb configuration file</term>
+ <listitem><para>The default configuration file path is
+ determined at compile time. The file specified contains
+ the configuration details required by the <command>smbd
+ </command> server. This is the file that <command>swat</command> will modify.
+ The information in this file includes server-specific
+ information such as what printcap file to use, as well as
+ descriptions of all the services that the server is to provide.
+ See <filename>smb.conf</filename> for more information.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>This option disables authentication and puts
+ <command>swat</command> in demo mode. In that mode anyone will be able to modify
+ the <filename>smb.conf</filename> file. </para>
+
+ <para><emphasis>Do NOT enable this option on a production
+ server. </emphasis></para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+
+ <title>INSTALLATION</title>
+
+ <para>After you compile SWAT you need to run <command>make install
+ </command> to install the <command>swat</command> binary
+ and the various help files and images. A default install would put
+ these in: </para>
+
+ <itemizedlist>
+ <listitem><para>/usr/local/samba/bin/swat</para></listitem>
+ <listitem><para>/usr/local/samba/swat/images/*</para></listitem>
+ <listitem><para>/usr/local/samba/swat/help/*</para></listitem>
+ </itemizedlist>
+
+ <refsect2>
+ <title>Inetd Installation</title>
+
+ <para>You need to edit your <filename>/etc/inetd.conf
+ </filename> and <filename>/etc/services</filename>
+ to enable SWAT to be launched via <command>inetd</command>.</para>
+
+ <para>In <filename>/etc/services</filename> you need to
+ add a line like this: </para>
+
+ <para><command>swat 901/tcp</command></para>
+
+ <para>Note for NIS/YP users - you may need to rebuild the
+ NIS service maps rather than alter your local <filename>
+ /etc/services</filename> file. </para>
+
+ <para>the choice of port number isn't really important
+ except that it should be less than 1024 and not currently
+ used (using a number above 1024 presents an obscure security
+ hole depending on the implementation details of your
+ <command>inetd</command> daemon). </para>
+
+ <para>In <filename>/etc/inetd.conf</filename> you should
+ add a line like this: </para>
+
+ <para><command>swat stream tcp nowait.400 root
+ /usr/local/samba/bin/swat swat</command></para>
+
+ <para>One you have edited <filename>/etc/services</filename>
+ and <filename>/etc/inetd.conf</filename> you need to send a
+ HUP signal to inetd. To do this use <command>kill -1 PID
+ </command> where PID is the process ID of the inetd daemon. </para>
+
+ </refsect2>
+
+
+ <refsect2>
+ <title>Launching</title>
+
+ <para>To launch SWAT just run your favorite web browser and
+ point it at "http://localhost:901/".</para>
+
+ <para>Note that you can attach to SWAT from any IP connected
+ machine but connecting from a remote machine leaves your
+ connection open to password sniffing as passwords will be sent
+ in the clear over the wire. </para>
+ </refsect2>
+</refsect1>
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/inetd.conf</filename></term>
+ <listitem><para>This file must contain suitable startup
+ information for the meta-daemon.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/services</filename></term>
+ <listitem><para>This file must contain a mapping of service name
+ (e.g., swat) to service port (e.g., 901) and protocol type
+ (e.g., tcp). </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/usr/local/samba/lib/smb.conf</filename></term>
+ <listitem><para>This is the default location of the <filename>smb.conf(5)
+ </filename> server configuration file that swat edits. Other
+ common places that systems install this file are <filename>
+ /usr/samba/lib/smb.conf</filename> and <filename>/etc/smb.conf
+ </filename>. This file describes all the services the server
+ is to make available to clients. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>WARNINGS</title>
+
+ <para><command>swat</command> will rewrite your <filename>smb.conf
+ </filename> file. It will rearrange the entries and delete all
+ comments, <parameter>include=</parameter> and <parameter>copy="
+ </parameter> options. If you have a carefully crafted <filename>
+ smb.conf</filename> then back it up or don't use swat! </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><command>inetd(5)</command>,
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/testparm.1.sgml b/docs/docbook/manpages/testparm.1.sgml
new file mode 100644
index 00000000000..320e39e6f58
--- /dev/null
+++ b/docs/docbook/manpages/testparm.1.sgml
@@ -0,0 +1,168 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="testparm">
+
+<refmeta>
+ <refentrytitle>testparm</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>testparm</refname>
+ <refpurpose>check an smb.conf configuration file for
+ internal correctness</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>testparm</command>
+ <arg choice="opt">-s</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-L &lt;servername&gt;</arg>
+ <arg choice="req">config filename</arg>
+ <arg choice="opt">hostname hostIP</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>testparm</command> is a very simple test program
+ to check an <command>smbd</command> configuration file for
+ internal correctness. If this program reports no problems, you
+ can use the configuration file with confidence that <command>smbd
+ </command> will successfully load the configuration file.</para>
+
+
+ <para>Note that this is <emphasis>NOT</emphasis> a guarantee that
+ the services specified in the configuration file will be
+ available or will operate as expected. </para>
+
+ <para>If the optional host name and host IP address are
+ specified on the command line, this test program will run through
+ the service entries reporting whether the specified host
+ has access to each service. </para>
+
+ <para>If <command>testparm</command> finds an error in the <filename>
+ smb.conf</filename> file it returns an exit code of 1 to the calling
+ program, else it returns an exit code of 0. This allows shell scripts
+ to test the output from <command>testparm</command>.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-s</term>
+ <listitem><para>Without this option, <command>testparm</command>
+ will prompt for a carriage return after printing the service
+ names and before dumping the service definitions.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Print usage message </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-L servername</term>
+ <listitem><para>Sets the value of the %L macro to <replaceable>servername</replaceable>.
+ This is useful for testing include files specified with the
+ %L macro. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>configfilename</term>
+ <listitem><para>This is the name of the configuration file
+ to check. If this parameter is not present then the
+ default <filename>smb.conf</filename> file will be checked.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>hostname</term>
+ <listitem><para>If this parameter and the following are
+ specified, then <command>testparm</command> will examine the <parameter>hosts
+ allow</parameter> and <parameter>hosts deny</parameter>
+ parameters in the <filename>smb.conf</filename> file to
+ determine if the hostname with this IP address would be
+ allowed access to the <command>smbd</command> server. If
+ this parameter is supplied, the hostIP parameter must also
+ be supplied.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>hostIP</term>
+ <listitem><para>This is the IP address of the host specified
+ in the previous parameter. This address must be supplied
+ if the hostname parameter is supplied. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>smb.conf</filename></term>
+ <listitem><para>This is usually the name of the configuration
+ file used by <command>smbd</command>.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>DIAGNOSTICS</title>
+
+ <para>The program will issue a message saying whether the
+ configuration file loaded OK or not. This message may be preceded by
+ errors and warnings if the file did not load. If the file was
+ loaded OK, the program then dumps all known service details
+ to stdout. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smb.conf.5.html"><filename>smb.conf(5)</filename></ulink>,
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
+
diff --git a/docs/docbook/manpages/testprns.1.sgml b/docs/docbook/manpages/testprns.1.sgml
new file mode 100644
index 00000000000..cd99494a9af
--- /dev/null
+++ b/docs/docbook/manpages/testprns.1.sgml
@@ -0,0 +1,143 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="testprns">
+
+<refmeta>
+ <refentrytitle>testprns</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>testprns</refname>
+ <refpurpose>check printer name for validity with smbd</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>testprns</command>
+ <arg choice="req">printername</arg>
+ <arg choice="opt">printcapname</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>testprns</command> is a very simple test program
+ to determine whether a given printer name is valid for use in
+ a service to be provided by <ulink url="smbd.8.html"><command>
+ smbd(8)</command></ulink>. </para>
+
+ <para>"Valid" in this context means "can be found in the
+ printcap specified". This program is very stupid - so stupid in
+ fact that it would be wisest to always specify the printcap file
+ to use. </para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>printername</term>
+ <listitem><para>The printer name to validate.</para>
+
+ <para>Printer names are taken from the first field in each
+ record in the printcap file, single printer names and sets
+ of aliases separated by vertical bars ("|") are recognized.
+ Note that no validation or checking of the printcap syntax is
+ done beyond that required to extract the printer name. It may
+ be that the print spooling system is more forgiving or less
+ forgiving than <command>testprns</command>. However, if
+ <command>testprns</command> finds the printer then
+ <command>smbd</command> should do so as well. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>printcapname</term>
+ <listitem><para>This is the name of the printcap file within
+ which to search for the given printer name. </para>
+
+ <para>If no printcap name is specified <command>testprns
+ </command> will attempt to scan the printcap file name
+ specified at compile time. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/printcap</filename></term>
+ <listitem><para>This is usually the default printcap
+ file to scan. See <filename>printcap (5)</filename>.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>DIAGNOSTICS</title>
+
+ <para>If a printer is found to be valid, the message
+ "Printer name &lt;printername&gt; is valid" will be
+ displayed. </para>
+
+ <para>If a printer is found to be invalid, the message
+ "Printer name &lt;printername&gt; is not valid" will be
+ displayed. </para>
+
+ <para>All messages that would normally be logged during
+ operation of the Samba daemons are logged by this program to the
+ file <filename>test.log</filename> in the current directory. The
+ program runs at debuglevel 3, so quite extensive logging
+ information is written. The log should be checked carefully
+ for errors and warnings. </para>
+
+ <para>Other messages are self-explanatory. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><filename>printcap(5)</filename>,
+ <ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smbclient.1.html"><command>smbclient(1)</command></ulink>
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
+
diff --git a/docs/docbook/manpages/wbinfo.1.sgml b/docs/docbook/manpages/wbinfo.1.sgml
new file mode 100644
index 00000000000..7133573b140
--- /dev/null
+++ b/docs/docbook/manpages/wbinfo.1.sgml
@@ -0,0 +1,185 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="wbinfo">
+
+<refmeta>
+ <refentrytitle>wbinfo</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>wbinfo</refname>
+ <refpurpose>Query information from winbind daemon</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wbinfo</command>
+ <arg choice="opt">-u</arg>
+ <arg choice="opt">-g</arg>
+ <arg choice="opt">-n name</arg>
+ <arg choice="opt">-s sid</arg>
+ <arg choice="opt">-U uid</arg>
+ <arg choice="opt">-G gid</arg>
+ <arg choice="opt">-S sid</arg>
+ <arg choice="opt">-Y sid</arg>
+ <arg choice="opt">-t</arg>
+ <arg choice="opt">-m</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para>The <command>wbinfo</command> program queries and returns information
+ created and used by the <ulink url="winbindd.8.html"><command>
+ winbindd(8)</command></ulink> daemon. </para>
+
+ <para>The <command>winbindd(8)</command> daemon must be configured
+ and running for the <command>wbinfo</command> program to be able
+ to return information.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-u</term>
+ <listitem><para>This option will list all users available
+ in the Windows NT domain for which the <command>winbindd(8)
+ </command> daemon is operating in. Users in all trusted domains
+ will also be listed. Note that this operation does not assign
+ user ids to any users that have not already been seen by
+ <command>winbindd(8)</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-g</term>
+ <listitem><para>This option will list all groups available
+ in the Windows NT domain for which the <command>winbindd(8)
+ </command> daemon is operating in. Groups in all trusted domains
+ will also be listed. Note that this operation does not assign
+ group ids to any groups that have not already been seen by
+ <command>winbindd(8)</command>. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-n name</term>
+ <listitem><para>The <parameter>-n</parameter> option
+ queries <command>winbindd(8)</command> for the SID
+ associated with the name specified. Domain names can be specified
+ before the user name by using the winbind separator character.
+ For example CWDOM1/Administrator refers to the Administrator
+ user in the domain CWDOM1. If no domain is specified then the
+ domain used is the one specified in the <filename>smb.conf</filename>
+ <parameter>workgroup</parameter> parameter. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-s sid</term>
+ <listitem><para>Use <parameter>-s</parameter> to resolve
+ a SID to a name. This is the inverse of the <parameter>-n
+ </parameter> option above. SIDs must be specified as ASCII strings
+ in the traditional Microsoft format. For example,
+ S-1-5-21-1455342024-3071081365-2475485837-500. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-U uid</term>
+ <listitem><para>Try to convert a UNIX user id to a Windows NT
+ SID. If the uid specified does not refer to one within
+ the winbind uid range then the operation will fail. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-G gid</term>
+ <listitem><para>Try to convert a UNIX group id to a Windows
+ NT SID. If the gid specified does not refer to one within
+ the winbind gid range then the operation will fail. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-S sid</term>
+ <listitem><para>Convert a SID to a UNIX user id. If the SID
+ does not correspond to a UNIX user mapped by <command>
+ winbindd(8)</command> then the operation will fail. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-Y sid</term>
+ <listitem><para>Convert a SID to a UNIX group id. If the SID
+ does not correspond to a UNIX group mapped by <command>
+ winbindd(8)</command> then the operation will fail. </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>-t</term>
+ <listitem><para>Verify that the workstation trust account
+ created when the Samba server is added to the Windows NT
+ domain is working. </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-m</term>
+ <listitem><para>Produce a list of domains trusted by the
+ Windows NT server <command>winbindd(8)</command> contacts
+ when resolving names. This list does not include the Windows
+ NT domain the server is a Primary Domain Controller for.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>EXIT STATUS</title>
+
+ <para>The wbinfo program returns 0 if the operation
+ succeeded, or 1 if the operation failed. If the <command>winbindd(8)
+ </command> daemon is not working <command>wbinfo</command> will always return
+ failure. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="winbindd.8.html"><command>winbindd(8)</command>
+ </ulink></para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para><command>wbinfo</command> and <command>winbindd</command>
+ were written by Tim Potter.</para>
+
+ <para>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/manpages/winbindd.8.sgml b/docs/docbook/manpages/winbindd.8.sgml
new file mode 100644
index 00000000000..af851657f33
--- /dev/null
+++ b/docs/docbook/manpages/winbindd.8.sgml
@@ -0,0 +1,500 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="winbindd">
+
+<refmeta>
+ <refentrytitle>winbindd</refentrytitle>
+ <manvolnum>8</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>winbindd</refname>
+ <refpurpose>Name Service Switch daemon for resolving names
+ from NT servers</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>winbindd</command>
+ <arg choice="opt">-i</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This program is part of the <ulink url="samba.7.html">
+ Samba</ulink> suite.</para>
+
+ <para><command>winbindd</command> is a daemon that provides
+ a service for the Name Service Switch capability that is present
+ in most modern C libraries. The Name Service Switch allows user
+ and system information to be obtained from different databases
+ services such as NIS or DNS. The exact behaviour can be configured
+ throught the <filename>/etc/nsswitch.conf</filename> file.
+ Users and groups are allocated as they are resolved to a range
+ of user and group ids specified by the administrator of the
+ Samba system.</para>
+
+ <para>The service provided by <command>winbindd</command> is called `winbind' and
+ can be used to resolve user and group information from a
+ Windows NT server. The service can also provide authentication
+ services via an associated PAM module. </para>
+
+ <para>
+ The <filename>pam_winbind</filename> module in the 2.2.2 release only
+ supports the <parameter>auth</parameter> and <parameter>account</parameter>
+ module-types. The latter is simply
+ performs a getpwnam() to verify that the system can obtain a uid for the
+ user. If the <filename>libnss_winbind</filename> library has been correctly
+ installed, this should always suceed.
+ </para>
+
+ <para>The following nsswitch databases are implemented by
+ the winbindd service: </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>passwd</term>
+ <listitem><para>User information traditionally stored in
+ the <filename>passwd(5)</filename> file and used by
+ <command>getpwent(3)</command> functions. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>group</term>
+ <listitem><para>Group information traditionally stored in
+ the <filename>group(5)</filename> file and used by
+ <command>getgrent(3)</command> functions. </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>For example, the following simple configuration in the
+ <filename>/etc/nsswitch.conf</filename> file can be used to initially
+ resolve user and group information from <filename>/etc/passwd
+ </filename> and <filename>/etc/group</filename> and then from the
+ Windows NT server. </para>
+
+ <para><programlisting>
+passwd: files winbind
+group: files winbind
+ </programlisting></para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-d debuglevel</term>
+ <listitem><para>Sets the debuglevel to an integer between
+ 0 and 100. 0 is for no debugging and 100 is for reams and
+ reams. To submit a bug report to the Samba Team, use debug
+ level 100 (see BUGS.txt). </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i</term>
+ <listitem><para>Tells <command>winbindd</command> to not
+ become a daemon and detach from the current terminal. This
+ option is used by developers when interactive debugging
+ of <command>winbindd</command> is required. </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>NAME AND ID RESOLUTION</title>
+
+ <para>Users and groups on a Windows NT server are assigned
+ a relative id (rid) which is unique for the domain when the
+ user or group is created. To convert the Windows NT user or group
+ into a unix user or group, a mapping between rids and unix user
+ and group ids is required. This is one of the jobs that <command>
+ winbindd</command> performs. </para>
+
+ <para>As winbindd users and groups are resolved from a server, user
+ and group ids are allocated from a specified range. This
+ is done on a first come, first served basis, although all existing
+ users and groups will be mapped as soon as a client performs a user
+ or group enumeration command. The allocated unix ids are stored
+ in a database file under the Samba lock directory and will be
+ remembered. </para>
+
+ <para>WARNING: The rid to unix id database is the only location
+ where the user and group mappings are stored by winbindd. If this
+ file is deleted or corrupted, there is no way for winbindd to
+ determine which user and group ids correspond to Windows NT user
+ and group rids. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>CONFIGURATION</title>
+
+ <para>Configuration of the <command>winbindd</command> daemon
+ is done through configuration parameters in the <filename>smb.conf(5)
+ </filename> file. All parameters should be specified in the
+ [global] section of smb.conf. </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>winbind separator</term>
+ <listitem><para>The winbind separator option allows you
+ to specify how NT domain names and user names are combined
+ into unix user names when presented to users. By default,
+ <command>winbindd</command> will use the traditional '\'
+ separator so that the unix user names look like
+ DOMAIN\username. In some cases this separator character may
+ cause problems as the '\' character has special meaning in
+ unix shells. In that case you can use the winbind separator
+ option to specify an alternative separator character. Good
+ alternatives may be '/' (although that conflicts
+ with the unix directory separator) or a '+ 'character.
+ The '+' character appears to be the best choice for 100%
+ compatibility with existing unix utilities, but may be an
+ aesthetically bad choice depending on your taste. </para>
+
+ <para>Default: <command>winbind separator = \ </command>
+ </para>
+ <para>Example: <command>winbind separator = + </command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>winbind uid</term>
+ <listitem><para>The winbind uid parameter specifies the
+ range of user ids that are allocated by the winbindd daemon.
+ This range of ids should have no existing local or NIS users
+ within it as strange conflicts can occur otherwise. </para>
+
+ <para>Default: <command>winbind uid = &lt;empty string&gt;
+ </command></para>
+ <para>Example: <command>winbind uid = 10000-20000</command></para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>winbind gid</term>
+ <listitem><para>The winbind gid parameter specifies the
+ range of group ids that are allocated by the winbindd daemon.
+ This range of group ids should have no existing local or NIS
+ groups within it as strange conflicts can occur otherwise.</para>
+
+ <para>Default: <command>winbind gid = &lt;empty string&gt;
+ </command></para>
+ <para>Example: <command>winbind gid = 10000-20000
+ </command> </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>winbind cache time</term>
+ <listitem><para>This parameter specifies the number of
+ seconds the winbindd daemon will cache user and group information
+ before querying a Windows NT server again. When a item in the
+ cache is older than this time winbindd will ask the domain
+ controller for the sequence number of the server's account database.
+ If the sequence number has not changed then the cached item is
+ marked as valid for a further <parameter>winbind cache time
+ </parameter> seconds. Otherwise the item is fetched from the
+ server. This means that as long as the account database is not
+ actively changing winbindd will only have to send one sequence
+ number query packet every <parameter>winbind cache time
+ </parameter> seconds. </para>
+
+ <para>Default: <command>winbind cache time = 15</command>
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>winbind enum users</term>
+ <listitem><para>On large installations it may be necessary
+ to suppress the enumeration of users through the <command>
+ setpwent()</command>, <command>getpwent()</command> and
+ <command>endpwent()</command> group of system calls. If
+ the <parameter>winbind enum users</parameter> parameter is false,
+ calls to the <command>getpwent</command> system call will not
+ return any data. </para>
+
+ <para><emphasis>Warning:</emphasis> Turning off user enumeration
+ may cause some programs to behave oddly. For example, the <command>finger</command>
+ program relies on having access to the full user list when
+ searching for matching usernames. </para>
+
+ <para>Default: <command>winbind enum users = yes </command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>winbind enum groups</term>
+ <listitem><para>On large installations it may be necessary
+ to suppress the enumeration of groups through the <command>
+ setgrent()</command>, <command>getgrent()</command> and
+ <command>endgrent()</command> group of system calls. If
+ the <parameter>winbind enum groups</parameter> parameter is
+ false, calls to the <command>getgrent()</command> system
+ call will not return any data. </para>
+
+ <para><emphasis>Warning:</emphasis> Turning off group
+ enumeration may cause some programs to behave oddly.
+ </para>
+
+ <para>Default: <command>winbind enum groups = no </command>
+ </para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>template homedir</term>
+ <listitem><para>When filling out the user information
+ for a Windows NT user, the <command>winbindd</command> daemon
+ uses this parameter to fill in the home directory for that user.
+ If the string <parameter>%D</parameter> is present it is
+ substituted with the user's Windows NT domain name. If the
+ string <parameter>%U</parameter> is present it is substituted
+ with the user's Windows NT user name. </para>
+
+ <para>Default: <command>template homedir = /home/%D/%U </command>
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>template shell</term>
+ <listitem><para>When filling out the user information for
+ a Windows NT user, the <command>winbindd</command> daemon
+ uses this parameter to fill in the shell for that user.
+ </para>
+
+ <para>Default: <command>template shell = /bin/false </command>
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>EXAMPLE SETUP</title>
+
+ <para>To setup winbindd for user and group lookups plus
+ authentication from a domain controller use something like the
+ following setup. This was tested on a RedHat 6.2 Linux box. </para>
+
+ <para>In <filename>/etc/nsswitch.conf</filename> put the
+ following:</para>
+
+ <para><programlisting>
+passwd: files winbind
+group: files winbind
+ </programlisting></para>
+
+ <para>In <filename>/etc/pam.d/*</filename> replace the
+ <parameter>auth</parameter> lines with something like this: </para>
+
+
+ <para><programlisting>
+auth required /lib/security/pam_securetty.so
+auth required /lib/security/pam_nologin.so
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_pwdb.so use_first_pass shadow nullok
+ </programlisting></para>
+
+
+ <para>Note in particular the use of the <parameter>sufficient</parameter>
+ keyword and the <parameter>use_first_pass</parameter> keyword. </para>
+
+ <para>Now replace the account lines with this: </para>
+
+ <para><command>account required /lib/security/pam_winbind.so
+ </command></para>
+
+ <para>The next step is to join the domain. To do that use the
+ <command>smbpasswd</command> program like this: </para>
+
+ <para><command>smbpasswd -j DOMAIN -r PDC -U
+ Administrator</command></para>
+
+ <para>The username after the <parameter>-U</parameter> can be any
+ Domain user that has administrator privileges on the machine.
+ Substitute your domain name for "DOMAIN" and the name of your PDC
+ for "PDC".</para>
+
+ <para>Next copy <filename>libnss_winbind.so</filename> to
+ <filename>/lib</filename> and <filename>pam_winbind.so</filename>
+ to <filename>/lib/security</filename>. A symbolic link needs to be
+ made from <filename>/lib/libnss_winbind.so</filename> to
+ <filename>/lib/libnss_winbind.so.2</filename>. If you are using an
+ older version of glibc then the target of the link should be
+ <filename>/lib/libnss_winbind.so.1</filename>.</para>
+
+ <para>Finally, setup a <filename>smb.conf</filename> containing directives like the
+ following: </para>
+
+ <para><programlisting>
+[global]
+ winbind separator = +
+ winbind cache time = 10
+ template shell = /bin/bash
+ template homedir = /home/%D/%U
+ winbind uid = 10000-20000
+ winbind gid = 10000-20000
+ workgroup = DOMAIN
+ security = domain
+ password server = *
+ </programlisting></para>
+
+
+ <para>Now start winbindd and you should find that your user and
+ group database is expanded to include your NT users and groups,
+ and that you can login to your unix box as a domain user, using
+ the DOMAIN+user syntax for the username. You may wish to use the
+ commands <command>getent passwd</command> and <command>getent group
+ </command> to confirm the correct operation of winbindd.</para>
+</refsect1>
+
+
+<refsect1>
+ <title>NOTES</title>
+
+ <para>The following notes are useful when configuring and
+ running <command>winbindd</command>: </para>
+
+ <para><command>nmbd</command> must be running on the local machine
+ for <command>winbindd</command> to work. <command>winbindd</command>
+ queries the list of trusted domains for the Windows NT server
+ on startup and when a SIGHUP is received. Thus, for a running <command>
+ winbindd</command> to become aware of new trust relationships between
+ servers, it must be sent a SIGHUP signal. </para>
+
+ <para>Client processes resolving names through the <command>winbindd</command>
+ nsswitch module read an environment variable named <envar>
+ $WINBINDD_DOMAIN</envar>. If this variable contains a comma separated
+ list of Windows NT domain names, then winbindd will only resolve users
+ and groups within those Windows NT domains. </para>
+
+ <para>PAM is really easy to misconfigure. Make sure you know what
+ you are doing when modifying PAM configuration files. It is possible
+ to set up PAM such that you can no longer log into your system. </para>
+
+ <para>If more than one UNIX machine is running <command>winbindd</command>,
+ then in general the user and groups ids allocated by winbindd will not
+ be the same. The user and group ids will only be valid for the local
+ machine.</para>
+
+ <para>If the the Windows NT RID to UNIX user and group id mapping
+ file is damaged or destroyed then the mappings will be lost. </para>
+</refsect1>
+
+
+<refsect1>
+ <title>SIGNALS</title>
+
+ <para>The following signals can be used to manipulate the
+ <command>winbindd</command> daemon. </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>SIGHUP</term>
+ <listitem><para>Reload the <filename>smb.conf(5)</filename>
+ file and apply any parameter changes to the running
+ version of winbindd. This signal also clears any cached
+ user and group information. The list of other domains trusted
+ by winbindd is also reloaded. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>SIGUSR1</term>
+ <listitem><para>The SIGUSR1 signal will cause <command>
+ winbindd</command> to write status information to the winbind
+ log file including information about the number of user and
+ group ids allocated by <command>winbindd</command>.</para>
+
+ <para>Log files are stored in the filename specified by the
+ log file parameter.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>FILES</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/nsswitch.conf(5)</filename></term>
+ <listitem><para>Name service switch configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>/tmp/.winbindd/pipe</term>
+ <listitem><para>The UNIX pipe over which clients communicate with
+ the <command>winbindd</command> program. For security reasons, the
+ winbind client will only attempt to connect to the winbindd daemon
+ if both the <filename>/tmp/.winbindd</filename> directory
+ and <filename>/tmp/.winbindd/pipe</filename> file are owned by
+ root. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>/lib/libnss_winbind.so.X</term>
+ <listitem><para>Implementation of name service switch library.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>$LOCKDIR/winbindd_idmap.tdb</term>
+ <listitem><para>Storage for the Windows NT rid to UNIX user/group
+ id mapping. The lock directory is specified when Samba is initially
+ compiled using the <parameter>--with-lockdir</parameter> option.
+ This directory is by default <filename>/usr/local/samba/var/locks
+ </filename>. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>$LOCKDIR/winbindd_cache.tdb</term>
+ <listitem><para>Storage for cached user and group information.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para><filename>nsswitch.conf(5)</filename>,
+ <ulink url="samba.7.html">samba(7)</ulink>,
+ <ulink url="wbinfo.1.html">wbinfo(1)</ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink></para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para><command>wbinfo</command> and <command>winbindd</command>
+ were written by Tim Potter.</para>
+
+ <para>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/projdoc/CVS-Access.sgml b/docs/docbook/projdoc/CVS-Access.sgml
new file mode 100644
index 00000000000..98ef925f20f
--- /dev/null
+++ b/docs/docbook/projdoc/CVS-Access.sgml
@@ -0,0 +1,157 @@
+<chapter id="cvs-access">
+
+
+<chapterinfo>
+ <author>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ </affiliation>
+ </author>
+
+
+ <pubdate> (22 May 2001) </pubdate>
+</chapterinfo>
+
+<title>HOWTO Access Samba source code via CVS</title>
+
+<sect1>
+<title>Introduction</title>
+
+<para>
+Samba is developed in an open environment. Developers use CVS
+(Concurrent Versioning System) to "checkin" (also known as
+"commit") new source code. Samba's various CVS branches can
+be accessed via anonymous CVS using the instructions
+detailed in this chapter.
+</para>
+
+<para>
+This document is a modified version of the instructions found at
+<ulink url="http://samba.org/samba/cvs.html">http://samba.org/samba/cvs.html</ulink>
+</para>
+
+</sect1>
+
+
+<sect1>
+<title>CVS Access to samba.org</title>
+
+<para>
+The machine samba.org runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. There are two main ways of
+accessing the CVS server on this host.
+</para>
+
+<sect2>
+<title>Access via CVSweb</title>
+
+<para>
+You can access the source code via your
+favourite WWW browser. This allows you to access the contents of
+individual files in the repository and also to look at the revision
+history and commit logs of individual files. You can also ask for a diff
+listing between any two versions on the repository.
+</para>
+
+<para>
+Use the URL : <ulink
+url="http://samba.org/cgi-bin/cvsweb">http://samba.org/cgi-bin/cvsweb</ulink>
+</para>
+</sect2>
+
+<sect2>
+<title>Access via cvs</title>
+
+<para>
+You can also access the source code via a
+normal cvs client. This gives you much more control over you can
+do with the repository and allows you to checkout whole source trees
+and keep them up to date via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.
+</para>
+
+<para>
+To download the latest cvs source code, point your
+browser at the URL : <ulink url="http://www.cyclic.com/">http://www.cyclic.com/</ulink>.
+and click on the 'How to get cvs' link. CVS is free software under
+the GNU GPL (as is Samba). Note that there are several graphical CVS clients
+which provide a graphical interface to the sometimes mundane CVS commands.
+Links to theses clients are also available from http://www.cyclic.com.
+</para>
+
+<para>
+To gain access via anonymous cvs use the following steps.
+For this example it is assumed that you want a copy of the
+samba source code. For the other source code repositories
+on this system just substitute the correct package name
+</para>
+
+<orderedlist>
+<listitem>
+ <para>
+ Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ Run the command
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot login</command>
+ </para>
+
+ <para>
+ When it asks you for a password type <userinput>cvs</userinput>.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ Run the command
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot co samba</command>
+ </para>
+
+ <para>
+ This will create a directory called samba containing the
+ latest samba source code (i.e. the HEAD tagged cvs branch). This
+ currently corresponds to the 3.0 development tree.
+ </para>
+
+ <para>
+ CVS branches other HEAD can be obtained by using the <parameter>-r</parameter>
+ and defining a tag name. A list of branch tag names can be found on the
+ "Development" page of the samba web site. A common request is to obtain the
+ latest 2.2 release code. This could be done by using the following command.
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot co -r SAMBA_2_2 samba</command>
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ Whenever you want to merge in the latest code changes use
+ the following command from within the samba directory:
+ </para>
+
+ <para>
+ <command>cvs update -d -P</command>
+ </para>
+</listitem>
+</orderedlist>
+
+</sect2>
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/DOMAIN_MEMBER.sgml b/docs/docbook/projdoc/DOMAIN_MEMBER.sgml
new file mode 100644
index 00000000000..6d0b36eafcc
--- /dev/null
+++ b/docs/docbook/projdoc/DOMAIN_MEMBER.sgml
@@ -0,0 +1,224 @@
+<chapter id="domain-security">
+
+<chapterinfo>
+ <author>
+ <firstname>Jeremy</firstname><surname>Allison</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>samba@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Jerry</firstname><surname>Carter</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>jerry@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>16 Apr 2001</pubdate>
+</chapterinfo>
+
+
+<title>security = domain in Samba 2.x</title>
+
+<sect1>
+
+ <title>Joining an NT Domain with Samba 2.2</title>
+
+ <para>Assume you have a Samba 2.x server with a NetBIOS name of
+ <constant>SERV1</constant> and are joining an NT domain called
+ <constant>DOM</constant>, which has a PDC with a NetBIOS name
+ of <constant>DOMPDC</constant> and two backup domain controllers
+ with NetBIOS names <constant>DOMBDC1</constant> and <constant>DOMBDC2
+ </constant>.</para>
+
+ <para>In order to join the domain, first stop all Samba daemons
+ and run the command:</para>
+
+ <para><prompt>root# </prompt><userinput>smbpasswd -j DOM -r DOMPDC
+ -U<replaceable>Administrator%password</replaceable></userinput></para>
+
+ <para>as we are joining the domain DOM and the PDC for that domain
+ (the only machine that has write access to the domain SAM database)
+ is DOMPDC. The <replaceable>Administrator%password</replaceable> is
+ the login name and password for an account which has the necessary
+ privilege to add machines to the domain. If this is successful
+ you will see the message:</para>
+
+ <para><computeroutput>smbpasswd: Joined domain DOM.</computeroutput>
+ </para>
+
+ <para>in your terminal window. See the <ulink url="smbpasswd.8.html">
+ smbpasswd(8)</ulink> man page for more details.</para>
+
+ <para>There is existing development code to join a domain
+ without having to create the machine trust account on the PDC
+ beforehand. This code will hopefully be available soon
+ in release branches as well.</para>
+
+ <para>This command goes through the machine account password
+ change protocol, then writes the new (random) machine account
+ password for this Samba server into a file in the same directory
+ in which an smbpasswd file would be stored - normally :</para>
+
+ <para><filename>/usr/local/samba/private</filename></para>
+
+ <para>In Samba 2.0.x, the filename looks like this:</para>
+
+ <para><filename><replaceable>&lt;NT DOMAIN NAME&gt;</replaceable>.<replaceable>&lt;Samba
+ Server Name&gt;</replaceable>.mac</filename></para>
+
+ <para>The <filename>.mac</filename> suffix stands for machine account
+ password file. So in our example above, the file would be called:</para>
+
+ <para><filename>DOM.SERV1.mac</filename></para>
+
+ <para>In Samba 2.2, this file has been replaced with a TDB
+ (Trivial Database) file named <filename>secrets.tdb</filename>.
+ </para>
+
+
+ <para>This file is created and owned by root and is not
+ readable by any other user. It is the key to the domain-level
+ security for your system, and should be treated as carefully
+ as a shadow password file.</para>
+
+ <para>Now, before restarting the Samba daemons you must
+ edit your <ulink url="smb.conf.5.html"><filename>smb.conf(5)</filename>
+ </ulink> file to tell Samba it should now use domain security.</para>
+
+ <para>Change (or add) your <ulink url="smb.conf.5.html#SECURITY">
+ <parameter>security =</parameter></ulink> line in the [global] section
+ of your smb.conf to read:</para>
+
+ <para><command>security = domain</command></para>
+
+ <para>Next change the <ulink url="smb.conf.5.html#WORKGROUP"><parameter>
+ workgroup =</parameter></ulink> line in the [global] section to read: </para>
+
+ <para><command>workgroup = DOM</command></para>
+
+ <para>as this is the name of the domain we are joining. </para>
+
+ <para>You must also have the parameter <ulink url="smb.conf.5.html#ENCRYPTPASSWORDS">
+ <parameter>encrypt passwords</parameter></ulink> set to <constant>yes
+ </constant> in order for your users to authenticate to the NT PDC.</para>
+
+ <para>Finally, add (or modify) a <ulink url="smb.conf.5.html#PASSWORDSERVER">
+ <parameter>password server =</parameter></ulink> line in the [global]
+ section to read: </para>
+
+ <para><command>password server = DOMPDC DOMBDC1 DOMBDC2</command></para>
+
+ <para>These are the primary and backup domain controllers Samba
+ will attempt to contact in order to authenticate users. Samba will
+ try to contact each of these servers in order, so you may want to
+ rearrange this list in order to spread out the authentication load
+ among domain controllers.</para>
+
+ <para>Alternatively, if you want smbd to automatically determine
+ the list of Domain controllers to use for authentication, you may
+ set this line to be :</para>
+
+ <para><command>password server = *</command></para>
+
+ <para>This method, which was introduced in Samba 2.0.6,
+ allows Samba to use exactly the same mechanism that NT does. This
+ method either broadcasts or uses a WINS database in order to
+ find domain controllers to authenticate against.</para>
+
+ <para>Finally, restart your Samba daemons and get ready for
+ clients to begin using domain security!</para>
+</sect1>
+
+<sect1>
+<title>Samba and Windows 2000 Domains</title>
+
+<para>
+Many people have asked regarding the state of Samba's ability to participate in
+a Windows 2000 Domain. Samba 2.2 is able to act as a member server of a Windows
+2000 domain operating in mixed or native mode.
+</para>
+
+<para>
+There is much confusion between the circumstances that require a "mixed" mode
+Win2k DC and a when this host can be switched to "native" mode. A "mixed" mode
+Win2k domain controller is only needed if Windows NT BDCs must exist in the same
+domain. By default, a Win2k DC in "native" mode will still support
+NetBIOS and NTLMv1 for authentication of legacy clients such as Windows 9x and
+NT 4.0. Samba has the same requirements as a Windows NT 4.0 member server.
+</para>
+
+<para>
+The steps for adding a Samba 2.2 host to a Win2k domain are the same as those
+for adding a Samba server to a Windows NT 4.0 domain. The only exception is that
+the "Server Manager" from NT 4 has been replaced by the "Active Directory Users and
+Computers" MMC (Microsoft Management Console) plugin.
+</para>
+
+</sect1>
+
+
+<sect1>
+ <title>Why is this better than security = server?</title>
+
+ <para>Currently, domain security in Samba doesn't free you from
+ having to create local Unix users to represent the users attaching
+ to your server. This means that if domain user <constant>DOM\fred
+ </constant> attaches to your domain security Samba server, there needs
+ to be a local Unix user fred to represent that user in the Unix
+ filesystem. This is very similar to the older Samba security mode
+ <ulink url="smb.conf.5.html#SECURITYEQUALSSERVER">security = server</ulink>,
+ where Samba would pass through the authentication request to a Windows
+ NT server in the same way as a Windows 95 or Windows 98 server would.
+ </para>
+
+ <para>Please refer to the <ulink url="winbind.html">Winbind
+ paper</ulink> for information on a system to automatically
+ assign UNIX uids and gids to Windows NT Domain users and groups.
+ This code is available in development branches only at the moment,
+ but will be moved to release branches soon.</para>
+
+ <para>The advantage to domain-level security is that the
+ authentication in domain-level security is passed down the authenticated
+ RPC channel in exactly the same way that an NT server would do it. This
+ means Samba servers now participate in domain trust relationships in
+ exactly the same way NT servers do (i.e., you can add Samba servers into
+ a resource domain and have the authentication passed on from a resource
+ domain PDC to an account domain PDC.</para>
+
+ <para>In addition, with <command>security = server</command> every Samba
+ daemon on a server has to keep a connection open to the
+ authenticating server for as long as that daemon lasts. This can drain
+ the connection resources on a Microsoft NT server and cause it to run
+ out of available connections. With <command>security = domain</command>,
+ however, the Samba daemons connect to the PDC/BDC only for as long
+ as is necessary to authenticate the user, and then drop the connection,
+ thus conserving PDC connection resources.</para>
+
+ <para>And finally, acting in the same manner as an NT server
+ authenticating to a PDC means that as part of the authentication
+ reply, the Samba server gets the user identification information such
+ as the user SID, the list of NT groups the user belongs to, etc. All
+ this information will allow Samba to be extended in the future into
+ a mode the developers currently call appliance mode. In this mode,
+ no local Unix users will be necessary, and Samba will generate Unix
+ uids and gids from the information passed back from the PDC when a
+ user is authenticated, making a Samba server truly plug and play
+ in an NT domain environment. Watch for this code soon.</para>
+
+ <para><emphasis>NOTE:</emphasis> Much of the text of this document
+ was first published in the Web magazine <ulink url="http://www.linuxworld.com">
+ LinuxWorld</ulink> as the article <ulink
+ url="http://www.linuxworld.com/linuxworld/lw-1998-10/lw-10-samba.html">Doing
+ the NIS/NT Samba</ulink>.</para>
+
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/ENCRYPTION.sgml b/docs/docbook/projdoc/ENCRYPTION.sgml
new file mode 100644
index 00000000000..6a26dbeffac
--- /dev/null
+++ b/docs/docbook/projdoc/ENCRYPTION.sgml
@@ -0,0 +1,378 @@
+<chapter id="pwencrypt">
+
+
+<chapterinfo>
+ <author>
+ <firstname>Jeremy</firstname><surname>Allison</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>samba@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>19 Apr 1999</pubdate>
+</chapterinfo>
+
+<title>LanMan and NT Password Encryption in Samba 2.x</title>
+
+
+<sect1>
+ <title>Introduction</title>
+
+ <para>With the development of LanManager and Windows NT
+ compatible password encryption for Samba, it is now able
+ to validate user connections in exactly the same way as
+ a LanManager or Windows NT server.</para>
+
+ <para>This document describes how the SMB password encryption
+ algorithm works and what issues there are in choosing whether
+ you want to use it. You should read it carefully, especially
+ the part about security and the "PROS and CONS" section.</para>
+
+</sect1>
+
+<sect1>
+ <title>How does it work?</title>
+
+ <para>LanManager encryption is somewhat similar to UNIX
+ password encryption. The server uses a file containing a
+ hashed value of a user's password. This is created by taking
+ the user's plaintext password, capitalising it, and either
+ truncating to 14 bytes or padding to 14 bytes with null bytes.
+ This 14 byte value is used as two 56 bit DES keys to encrypt
+ a 'magic' eight byte value, forming a 16 byte value which is
+ stored by the server and client. Let this value be known as
+ the "hashed password".</para>
+
+ <para>Windows NT encryption is a higher quality mechanism,
+ consisting of doing an MD4 hash on a Unicode version of the user's
+ password. This also produces a 16 byte hash value that is
+ non-reversible.</para>
+
+ <para>When a client (LanManager, Windows for WorkGroups, Windows
+ 95 or Windows NT) wishes to mount a Samba drive (or use a Samba
+ resource), it first requests a connection and negotiates the
+ protocol that the client and server will use. In the reply to this
+ request the Samba server generates and appends an 8 byte, random
+ value - this is stored in the Samba server after the reply is sent
+ and is known as the "challenge". The challenge is different for
+ every client connection.</para>
+
+ <para>The client then uses the hashed password (16 byte values
+ described above), appended with 5 null bytes, as three 56 bit
+ DES keys, each of which is used to encrypt the challenge 8 byte
+ value, forming a 24 byte value known as the "response".</para>
+
+ <para>In the SMB call SMBsessionsetupX (when user level security
+ is selected) or the call SMBtconX (when share level security is
+ selected), the 24 byte response is returned by the client to the
+ Samba server. For Windows NT protocol levels the above calculation
+ is done on both hashes of the user's password and both responses are
+ returned in the SMB call, giving two 24 byte values.</para>
+
+ <para>The Samba server then reproduces the above calculation, using
+ its own stored value of the 16 byte hashed password (read from the
+ <filename>smbpasswd</filename> file - described later) and the challenge
+ value that it kept from the negotiate protocol reply. It then checks
+ to see if the 24 byte value it calculates matches the 24 byte value
+ returned to it from the client.</para>
+
+ <para>If these values match exactly, then the client knew the
+ correct password (or the 16 byte hashed value - see security note
+ below) and is thus allowed access. If not, then the client did not
+ know the correct password and is denied access.</para>
+
+ <para>Note that the Samba server never knows or stores the cleartext
+ of the user's password - just the 16 byte hashed values derived from
+ it. Also note that the cleartext password or 16 byte hashed values
+ are never transmitted over the network - thus increasing security.</para>
+</sect1>
+
+<sect1>
+ <title>Important Notes About Security</title>
+
+ <para>The unix and SMB password encryption techniques seem similar
+ on the surface. This similarity is, however, only skin deep. The unix
+ scheme typically sends clear text passwords over the network when
+ logging in. This is bad. The SMB encryption scheme never sends the
+ cleartext password over the network but it does store the 16 byte
+ hashed values on disk. This is also bad. Why? Because the 16 byte hashed
+ values are a "password equivalent". You cannot derive the user's
+ password from them, but they could potentially be used in a modified
+ client to gain access to a server. This would require considerable
+ technical knowledge on behalf of the attacker but is perfectly possible.
+ You should thus treat the smbpasswd file as though it contained the
+ cleartext passwords of all your users. Its contents must be kept
+ secret, and the file should be protected accordingly.</para>
+
+ <para>Ideally we would like a password scheme which neither requires
+ plain text passwords on the net or on disk. Unfortunately this
+ is not available as Samba is stuck with being compatible with
+ other SMB systems (WinNT, WfWg, Win95 etc). </para>
+
+ <warning>
+ <para>Note that Windows NT 4.0 Service pack 3 changed the
+ default for permissible authentication so that plaintext
+ passwords are <emphasis>never</emphasis> sent over the wire.
+ The solution to this is either to switch to encrypted passwords
+ with Samba or edit the Windows NT registry to re-enable plaintext
+ passwords. See the document WinNT.txt for details on how to do
+ this.</para>
+
+ <para>Other Microsoft operating systems which also exhibit
+ this behavior includes</para>
+
+ <itemizedlist>
+ <listitem><para>MS DOS Network client 3.0 with
+ the basic network redirector installed</para></listitem>
+
+ <listitem><para>Windows 95 with the network redirector
+ update installed</para></listitem>
+
+ <listitem><para>Windows 98 [se]</para></listitem>
+
+ <listitem><para>Windows 2000</para></listitem>
+ </itemizedlist>
+
+ <para><emphasis>Note :</emphasis>All current release of
+ Microsoft SMB/CIFS clients support authentication via the
+ SMB Challenge/Response mechanism described here. Enabling
+ clear text authentication does not disable the ability
+ of the client to participate in encrypted authentication.</para>
+ </warning>
+
+ <sect2>
+ <title>Advantages of SMB Encryption</title>
+
+ <itemizedlist>
+ <listitem><para>plain text passwords are not passed across
+ the network. Someone using a network sniffer cannot just
+ record passwords going to the SMB server.</para>
+ </listitem>
+
+ <listitem><para>WinNT doesn't like talking to a server
+ that isn't using SMB encrypted passwords. It will refuse
+ to browse the server if the server is also in user level
+ security mode. It will insist on prompting the user for the
+ password on each connection, which is very annoying. The
+ only things you can do to stop this is to use SMB encryption.
+ </para></listitem>
+ </itemizedlist>
+ </sect2>
+
+
+ <sect2>
+ <title>Advantages of non-encrypted passwords</title>
+
+ <itemizedlist>
+ <listitem><para>plain text passwords are not kept
+ on disk. </para></listitem>
+
+ <listitem><para>uses same password file as other unix
+ services such as login and ftp</para></listitem>
+
+ <listitem><para>you are probably already using other
+ services (such as telnet and ftp) which send plain text
+ passwords over the net, so sending them for SMB isn't
+ such a big deal.</para></listitem>
+ </itemizedlist>
+ </sect2>
+</sect1>
+
+
+<sect1>
+ <title><anchor id="SMBPASSWDFILEFORMAT">The smbpasswd file</title>
+
+ <para>In order for Samba to participate in the above protocol
+ it must be able to look up the 16 byte hashed values given a user name.
+ Unfortunately, as the UNIX password value is also a one way hash
+ function (ie. it is impossible to retrieve the cleartext of the user's
+ password given the UNIX hash of it), a separate password file
+ containing this 16 byte value must be kept. To minimise problems with
+ these two password files, getting out of sync, the UNIX <filename>
+ /etc/passwd</filename> and the <filename>smbpasswd</filename> file,
+ a utility, <command>mksmbpasswd.sh</command>, is provided to generate
+ a smbpasswd file from a UNIX <filename>/etc/passwd</filename> file.
+ </para
+
+
+ <para>To generate the smbpasswd file from your <filename>/etc/passwd
+ </filename> file use the following command :</para>
+
+ <para><prompt>$ </prompt><userinput>cat /etc/passwd | mksmbpasswd.sh
+ &gt; /usr/local/samba/private/smbpasswd</userinput></para>
+
+ <para>If you are running on a system that uses NIS, use</para>
+
+ <para><prompt>$ </prompt><userinput>ypcat passwd | mksmbpasswd.sh
+ &gt; /usr/local/samba/private/smbpasswd</userinput></para>
+
+ <para>The <command>mksmbpasswd.sh</command> program is found in
+ the Samba source directory. By default, the smbpasswd file is
+ stored in :</para>
+
+ <para><filename>/usr/local/samba/private/smbpasswd</filename></para>
+
+ <para>The owner of the <filename>/usr/local/samba/private/</filename>
+ directory should be set to root, and the permissions on it should
+ be set to 0500 (<command>chmod 500 /usr/local/samba/private</command>).
+ </para>
+
+ <para>Likewise, the smbpasswd file inside the private directory should
+ be owned by root and the permissions on is should be set to 0600
+ (<command>chmod 600 smbpasswd</command>).</para>
+
+
+ <para>The format of the smbpasswd file is (The line has been
+ wrapped here. It should appear as one entry per line in
+ your smbpasswd file.)</para>
+
+ <para><programlisting>
+username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:
+ [Account type]:LCT-&lt;last-change-time&gt;:Long name
+ </programlisting></para>
+
+ <para>Although only the <replaceable>username</replaceable>,
+ <replaceable>uid</replaceable>, <replaceable>
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</replaceable>,
+ [<replaceable>Account type</replaceable>] and <replaceable>
+ last-change-time</replaceable> sections are significant
+ and are looked at in the Samba code.</para>
+
+ <para>It is <emphasis>VITALLY</emphasis> important that there by 32
+ 'X' characters between the two ':' characters in the XXX sections -
+ the smbpasswd and Samba code will fail to validate any entries that
+ do not have 32 characters between ':' characters. The first XXX
+ section is for the Lanman password hash, the second is for the
+ Windows NT version.</para>
+
+ <para>When the password file is created all users have password entries
+ consisting of 32 'X' characters. By default this disallows any access
+ as this user. When a user has a password set, the 'X' characters change
+ to 32 ascii hexadecimal digits (0-9, A-F). These are an ascii
+ representation of the 16 byte hashed value of a user's password.</para>
+
+ <para>To set a user to have no password (not recommended), edit the file
+ using vi, and replace the first 11 characters with the ascii text
+ <constant>"NO PASSWORD"</constant> (minus the quotes).</para>
+
+ <para>For example, to clear the password for user bob, his smbpasswd file
+ entry would look like :</para>
+
+ <para><programlisting>
+ bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[U ]:LCT-00000000:Bob's full name:/bobhome:/bobshell
+ </programlisting></para>
+
+ <para>If you are allowing users to use the smbpasswd command to set
+ their own passwords, you may want to give users NO PASSWORD initially
+ so they do not have to enter a previous password when changing to their
+ new password (not recommended). In order for you to allow this the
+ <command>smbpasswd</command> program must be able to connect to the
+ <command>smbd</command> daemon as that user with no password. Enable this
+ by adding the line :</para>
+
+ <para><command>null passwords = yes</command></para>
+
+ <para>to the [global] section of the smb.conf file (this is why
+ the above scenario is not recommended). Preferably, allocate your
+ users a default password to begin with, so you do not have
+ to enable this on your server.</para>
+
+ <para><emphasis>Note : </emphasis>This file should be protected very
+ carefully. Anyone with access to this file can (with enough knowledge of
+ the protocols) gain access to your SMB server. The file is thus more
+ sensitive than a normal unix <filename>/etc/passwd</filename> file.</para>
+</sect1>
+
+
+<sect1>
+ <title>The smbpasswd Command</title>
+
+ <para>The smbpasswd command maintains the two 32 byte password fields
+ in the smbpasswd file. If you wish to make it similar to the unix
+ <command>passwd</command> or <command>yppasswd</command> programs,
+ install it in <filename>/usr/local/samba/bin/</filename> (or your
+ main Samba binary directory).</para>
+
+ <para>Note that as of Samba 1.9.18p4 this program <emphasis>MUST NOT
+ BE INSTALLED</emphasis> setuid root (the new <command>smbpasswd</command>
+ code enforces this restriction so it cannot be run this way by
+ accident).</para>
+
+ <para><command>smbpasswd</command> now works in a client-server mode
+ where it contacts the local smbd to change the user's password on its
+ behalf. This has enormous benefits - as follows.</para>
+
+ <itemizedlist>
+ <listitem><para>smbpasswd no longer has to be setuid root -
+ an enormous range of potential security problems is
+ eliminated.</para></listitem>
+
+ <listitem><para><command>smbpasswd</command> now has the capability
+ to change passwords on Windows NT servers (this only works when
+ the request is sent to the NT Primary Domain Controller if you
+ are changing an NT Domain user's password).</para></listitem>
+ </itemizedlist>
+
+ <para>To run smbpasswd as a normal user just type :</para>
+
+ <para><prompt>$ </prompt><userinput>smbpasswd</userinput></para>
+ <para><prompt>Old SMB password: </prompt><userinput>&lt;type old value here -
+ or hit return if there was no old password&gt;</userinput></para>
+ <para><prompt>New SMB Password: </prompt><userinput>&lt;type new value&gt;
+ </userinput></para>
+ <para><prompt>Repeat New SMB Password: </prompt><userinput>&lt;re-type new value
+ </userinput></para>
+
+ <para>If the old value does not match the current value stored for
+ that user, or the two new values do not match each other, then the
+ password will not be changed.</para>
+
+ <para>If invoked by an ordinary user it will only allow the user
+ to change his or her own Samba password.</para>
+
+ <para>If run by the root user smbpasswd may take an optional
+ argument, specifying the user name whose SMB password you wish to
+ change. Note that when run as root smbpasswd does not prompt for
+ or check the old password value, thus allowing root to set passwords
+ for users who have forgotten their passwords.</para>
+
+ <para><command>smbpasswd</command> is designed to work in the same way
+ and be familiar to UNIX users who use the <command>passwd</command> or
+ <command>yppasswd</command> commands.</para>
+
+ <para>For more details on using <command>smbpasswd</command> refer
+ to the man page which will always be the definitive reference.</para>
+</sect1>
+
+
+<sect1>
+ <title>Setting up Samba to support LanManager Encryption</title>
+
+ <para>This is a very brief description on how to setup samba to
+ support password encryption. </para>
+
+ <orderedlist numeration="Arabic">
+ <listitem><para>compile and install samba as usual</para>
+ </listitem>
+
+ <listitem><para>enable encrypted passwords in <filename>
+ smb.conf</filename> by adding the line <command>encrypt
+ passwords = yes</command> in the [global] section</para>
+ </listitem>
+
+ <listitem><para>create the initial <filename>smbpasswd</filename>
+ password file in the place you specified in the Makefile
+ (--prefix=&lt;dir&gt;). See the notes under the <link
+ linkend="SMBPASSWDFILEFORMAT">The smbpasswd File</link>
+ section earlier in the document for details.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>Note that you can test things using smbclient.</para>
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/Integrating-with-Windows.sgml b/docs/docbook/projdoc/Integrating-with-Windows.sgml
new file mode 100644
index 00000000000..0b6abaf80f6
--- /dev/null
+++ b/docs/docbook/projdoc/Integrating-with-Windows.sgml
@@ -0,0 +1,935 @@
+<chapter id="integrate-ms-networks">
+
+
+<chapterinfo>
+ <author>
+ <firstname>John</firstname><surname>Terpstra</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>jht@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate> (Jan 01 2001) </pubdate>
+</chapterinfo>
+
+<title>Integrating MS Windows networks with Samba</title>
+
+<sect1>
+<title>Agenda</title>
+
+<para>
+To identify the key functional mechanisms of MS Windows networking
+to enable the deployment of Samba as a means of extending and/or
+replacing MS Windows NT/2000 technology.
+</para>
+
+<para>
+We will examine:
+</para>
+
+<orderedlist>
+ <listitem><para>Name resolution in a pure Unix/Linux TCP/IP
+ environment
+ </para></listitem>
+
+ <listitem><para>Name resolution as used within MS Windows
+ networking
+ </para></listitem>
+
+ <listitem><para>How browsing functions and how to deploy stable
+ and dependable browsing using Samba
+ </para></listitem>
+
+ <listitem><para>MS Windows security options and how to
+ configure Samba for seemless integration
+ </para></listitem>
+
+ <listitem><para>Configuration of Samba as:</para>
+ <orderedlist>
+ <listitem><para>A stand-alone server</para></listitem>
+ <listitem><para>An MS Windows NT 3.x/4.0 security domain member
+ </para></listitem>
+ <listitem><para>An alternative to an MS Windows NT 3.x/4.0 Domain Controller
+ </para></listitem>
+ </orderedlist>
+ </listitem>
+</orderedlist>
+
+</sect1>
+
+
+<sect1>
+<title>Name Resolution in a pure Unix/Linux world</title>
+
+<para>
+The key configuration files covered in this section are:
+</para>
+
+<itemizedlist>
+ <listitem><para><filename>/etc/hosts</filename></para></listitem>
+ <listitem><para><filename>/etc/resolv.conf</filename></para></listitem>
+ <listitem><para><filename>/etc/host.conf</filename></para></listitem>
+ <listitem><para><filename>/etc/nsswitch.conf</filename></para></listitem>
+</itemizedlist>
+
+<sect2>
+<title><filename>/etc/hosts</filename></title>
+
+<para>
+Contains a static list of IP Addresses and names.
+eg:
+</para>
+<para><programlisting>
+ 127.0.0.1 localhost localhost.localdomain
+ 192.168.1.1 bigbox.caldera.com bigbox alias4box
+</programlisting></para>
+
+<para>
+The purpose of <filename>/etc/hosts</filename> is to provide a
+name resolution mechanism so that uses do not need to remember
+IP addresses.
+</para>
+
+
+<para>
+Network packets that are sent over the physical network transport
+layer communicate not via IP addresses but rather using the Media
+Access Control address, or MAC address. IP Addresses are currently
+32 bits in length and are typically presented as four (4) decimal
+numbers that are separated by a dot (or period). eg: 168.192.1.1
+</para>
+
+<para>
+MAC Addresses use 48 bits (or 6 bytes) and are typically represented
+as two digit hexadecimal numbers separated by colons. eg:
+40:8e:0a:12:34:56
+</para>
+
+<para>
+Every network interfrace must have an MAC address. Associated with
+a MAC address there may be one or more IP addresses. There is NO
+relationship between an IP address and a MAC address, all such assignments
+are arbitary or discretionary in nature. At the most basic level all
+network communications takes place using MAC addressing. Since MAC
+addresses must be globally unique, and generally remains fixed for
+any particular interface, the assignment of an IP address makes sense
+from a network management perspective. More than one IP address can
+be assigned per MAC address. One address must be the primary IP address,
+this is the address that will be returned in the ARP reply.
+</para>
+
+<para>
+When a user or a process wants to communicate with another machine
+the protocol implementation ensures that the "machine name" or "host
+name" is resolved to an IP address in a manner that is controlled
+by the TCP/IP configuration control files. The file
+<filename>/etc/hosts</filename> is one such file.
+</para>
+
+<para>
+When the IP address of the destination interface has been
+determined a protocol called ARP/RARP isused to identify
+the MAC address of the target interface. ARP stands for Address
+Resolution Protocol, and is a broadcast oriented method that
+uses UDP (User Datagram Protocol) to send a request to all
+interfaces on the local network segment using the all 1's MAC
+address. Network interfaces are programmed to respond to two
+MAC addresses only; their own unique address and the address
+ff:ff:ff:ff:ff:ff. The reply packet from an ARP request will
+contain the MAC address and the primary IP address for each
+interface.
+</para>
+
+<para>
+The <filename>/etc/hosts</filename> file is foundational to all
+Unix/Linux TCP/IP installations and as a minumum will contain
+the localhost and local network interface IP addresses and the
+primary names by which they are known within the local machine.
+This file helps to prime the pump so that a basic level of name
+resolution can exist before any other method of name resolution
+becomes available.
+</para>
+
+</sect2>
+
+
+<sect2>
+<title><filename>/etc/resolv.conf</filename></title>
+
+<para>
+This file tells the name resolution libraries:
+</para>
+
+<itemizedlist>
+ <listitem><para>The name of the domain to which the machine
+ belongs
+ </para></listitem>
+
+ <listitem><para>The name(s) of any domains that should be
+ automatically searched when trying to resolve unqualified
+ host names to their IP address
+ </para></listitem>
+
+ <listitem><para>The name or IP address of available Domain
+ Name Servers that may be asked to perform name to address
+ translation lookups
+ </para></listitem>
+</itemizedlist>
+
+</sect2>
+
+
+<sect2>
+<title><filename>/etc/host.conf</filename></title>
+
+
+<para>
+<filename>/etc/host.conf</filename> is the primary means by
+which the setting in /etc/resolv.conf may be affected. It is a
+critical configuration file. This file controls the order by
+which name resolution may procede. The typical structure is:
+</para>
+
+<para><programlisting>
+ order hosts,bind
+ multi on
+</programlisting></para>
+
+<para>
+then both addresses should be returned. Please refer to the
+man page for host.conf for further details.
+</para>
+
+
+</sect2>
+
+
+
+<sect2>
+<title><filename>/etc/nsswitch.conf</filename></title>
+
+<para>
+This file controls the actual name resolution targets. The
+file typically has resolver object specifications as follows:
+</para>
+
+
+<para><programlisting>
+ # /etc/nsswitch.conf
+ #
+ # Name Service Switch configuration file.
+ #
+
+ passwd: compat
+ # Alternative entries for password authentication are:
+ # passwd: compat files nis ldap winbind
+ shadow: compat
+ group: compat
+
+ hosts: files nis dns
+ # Alternative entries for host name resolution are:
+ # hosts: files dns nis nis+ hesoid db compat ldap wins
+ networks: nis files dns
+
+ ethers: nis files
+ protocols: nis files
+ rpc: nis files
+ services: nis files
+</programlisting></para>
+
+<para>
+Of course, each of these mechanisms requires that the appropriate
+facilities and/or services are correctly configured.
+</para>
+
+<para>
+It should be noted that unless a network request/message must be
+sent, TCP/IP networks are silent. All TCP/IP communications assumes a
+principal of speaking only when necessary.
+</para>
+
+<para>
+Samba version 2.2.0 will add Linux support for extensions to
+the name service switch infrastructure so that linux clients will
+be able to obtain resolution of MS Windows NetBIOS names to IP
+Addresses. To gain this functionality Samba needs to be compiled
+with appropriate arguments to the make command (ie: <command>make
+nsswitch/libnss_wins.so</command>). The resulting library should
+then be installed in the <filename>/lib</filename> directory and
+the "wins" parameter needs to be added to the "hosts:" line in
+the <filename>/etc/nsswitch.conf</filename> file. At this point it
+will be possible to ping any MS Windows machine by it's NetBIOS
+machine name, so long as that machine is within the workgroup to
+which both the samba machine and the MS Windows machine belong.
+</para>
+
+</sect2>
+</sect1>
+
+
+<sect1>
+<title>Name resolution as used within MS Windows networking</title>
+
+<para>
+MS Windows networking is predicated about the name each machine
+is given. This name is known variously (and inconsistently) as
+the "computer name", "machine name", "networking name", "netbios name",
+"SMB name". All terms mean the same thing with the exception of
+"netbios name" which can apply also to the name of the workgroup or the
+domain name. The terms "workgroup" and "domain" are really just a
+simply name with which the machine is associated. All NetBIOS names
+are exactly 16 characters in length. The 16th character is reserved.
+It is used to store a one byte value that indicates service level
+information for the NetBIOS name that is registered. A NetBIOS machine
+name is therefore registered for each service type that is provided by
+the client/server.
+</para>
+
+<para>
+The following are typical NetBIOS name/service type registrations:
+</para>
+
+<para><programlisting>
+ Unique NetBIOS Names:
+ MACHINENAME<00> = Server Service is running on MACHINENAME
+ MACHINENAME<03> = Generic Machine Name (NetBIOS name)
+ MACHINENAME<20> = LanMan Server service is running on MACHINENAME
+ WORKGROUP<1b> = Domain Master Browser
+
+ Group Names:
+ WORKGROUP<03> = Generic Name registered by all members of WORKGROUP
+ WORKGROUP<1c> = Domain Controllers / Netlogon Servers
+ WORKGROUP<1d> = Local Master Browsers
+ WORKGROUP<1e> = Internet Name Resolvers
+</programlisting></para>
+
+<para>
+It should be noted that all NetBIOS machines register their own
+names as per the above. This is in vast contrast to TCP/IP
+installations where traditionally the system administrator will
+determine in the /etc/hosts or in the DNS database what names
+are associated with each IP address.
+</para>
+
+<para>
+One further point of clarification should be noted, the <filename>/etc/hosts</filename>
+file and the DNS records do not provide the NetBIOS name type information
+that MS Windows clients depend on to locate the type of service that may
+be needed. An example of this is what happens when an MS Windows client
+wants to locate a domain logon server. It find this service and the IP
+address of a server that provides it by performing a lookup (via a
+NetBIOS broadcast) for enumeration of all machines that have
+registered the name type *<1c>. A logon request is then sent to each
+IP address that is returned in the enumerated list of IP addresses. Which
+ever machine first replies then ends up providing the logon services.
+</para>
+
+<para>
+The name "workgroup" or "domain" really can be confusing since these
+have the added significance of indicating what is the security
+architecture of the MS Windows network. The term "workgroup" indicates
+that the primary nature of the network environment is that of a
+peer-to-peer design. In a WORKGROUP all machines are responsible for
+their own security, and generally such security is limited to use of
+just a password (known as SHARE MORE security). In most situations
+with peer-to-peer networking the users who control their own machines
+will simply opt to have no security at all. It is possible to have
+USER MODE security in a WORKGROUP environment, thus requiring use
+of a user name and a matching password.
+</para>
+
+<para>
+MS Windows networking is thus predetermined to use machine names
+for all local and remote machine message passing. The protocol used is
+called Server Message Block (SMB) and this is implemented using
+the NetBIOS protocol (Network Basic Input Output System). NetBIOS can
+be encapsulated using LLC (Logical Link Control) protocol - in which case
+the resulting protocol is called NetBEUI (Network Basic Extended User
+Interface). NetBIOS can also be run over IPX (Internetworking Packet
+Exchange) protocol as used by Novell NetWare, and it can be run
+over TCP/IP protocols - in which case the resulting protocol is called
+NBT or NetBT, the NetBIOS over TCP/IP.
+</para>
+
+<para>
+MS Windows machines use a complex array of name resolution mechanisms.
+Since we are primarily concerned with TCP/IP this demonstration is
+limited to this area.
+</para>
+
+<sect2>
+<title>The NetBIOS Name Cache</title>
+
+<para>
+All MS Windows machines employ an in memory buffer in which is
+stored the NetBIOS names and their IP addresses for all external
+machines that that the local machine has communicated with over the
+past 10-15 minutes. It is more efficient to obtain an IP address
+for a machine from the local cache than it is to go through all the
+configured name resolution mechanisms.
+</para>
+
+<para>
+If a machine whose name is in the local name cache has been shut
+down before the name had been expired and flushed from the cache, then
+an attempt to exchange a message with that machine will be subject
+to time-out delays. ie: It's name is in the cache, so a name resolution
+lookup will succeed, but the machine can not respond. This can be
+frustrating for users - but it is a characteristic of the protocol.
+</para>
+
+<para>
+The MS Windows utility that allows examination of the NetBIOS
+name cache is called "nbtstat". The Samba equivalent of this
+is called "nmblookup".
+</para>
+
+</sect2>
+
+<sect2>
+<title>The LMHOSTS file</title>
+
+<para>
+This file is usually located in MS Windows NT 4.0 or
+2000 in <filename>C:\WINNT\SYSTEM32\DRIVERS\ETC</filename> and contains
+the IP Address and the machine name in matched pairs. The
+<filename>LMHOSTS</filename> file performs NetBIOS name
+to IP address mapping oriented.
+</para>
+
+<para>
+It typically looks like:
+</para>
+
+<para><programlisting>
+ # Copyright (c) 1998 Microsoft Corp.
+ #
+ # This is a sample LMHOSTS file used by the Microsoft Wins Client (NetBIOS
+ # over TCP/IP) stack for Windows98
+ #
+ # This file contains the mappings of IP addresses to NT computernames
+ # (NetBIOS) names. Each entry should be kept on an individual line.
+ # The IP address should be placed in the first column followed by the
+ # corresponding computername. The address and the comptername
+ # should be separated by at least one space or tab. The "#" character
+ # is generally used to denote the start of a comment (see the exceptions
+ # below).
+ #
+ # This file is compatible with Microsoft LAN Manager 2.x TCP/IP lmhosts
+ # files and offers the following extensions:
+ #
+ # #PRE
+ # #DOM:&lt;domain&gt;
+ # #INCLUDE &lt;filename&gt;
+ # #BEGIN_ALTERNATE
+ # #END_ALTERNATE
+ # \0xnn (non-printing character support)
+ #
+ # Following any entry in the file with the characters "#PRE" will cause
+ # the entry to be preloaded into the name cache. By default, entries are
+ # not preloaded, but are parsed only after dynamic name resolution fails.
+ #
+ # Following an entry with the "#DOM:&lt;domain&gt;" tag will associate the
+ # entry with the domain specified by &lt;domain&gt;. This affects how the
+ # browser and logon services behave in TCP/IP environments. To preload
+ # the host name associated with #DOM entry, it is necessary to also add a
+ # #PRE to the line. The &lt;domain&gt; is always preloaded although it will not
+ # be shown when the name cache is viewed.
+ #
+ # Specifying "#INCLUDE &lt;filename&gt;" will force the RFC NetBIOS (NBT)
+ # software to seek the specified &lt;filename&gt; and parse it as if it were
+ # local. &lt;filename&gt; is generally a UNC-based name, allowing a
+ # centralized lmhosts file to be maintained on a server.
+ # It is ALWAYS necessary to provide a mapping for the IP address of the
+ # server prior to the #INCLUDE. This mapping must use the #PRE directive.
+ # In addtion the share "public" in the example below must be in the
+ # LanManServer list of "NullSessionShares" in order for client machines to
+ # be able to read the lmhosts file successfully. This key is under
+ # \machine\system\currentcontrolset\services\lanmanserver\parameters\nullsessionshares
+ # in the registry. Simply add "public" to the list found there.
+ #
+ # The #BEGIN_ and #END_ALTERNATE keywords allow multiple #INCLUDE
+ # statements to be grouped together. Any single successful include
+ # will cause the group to succeed.
+ #
+ # Finally, non-printing characters can be embedded in mappings by
+ # first surrounding the NetBIOS name in quotations, then using the
+ # \0xnn notation to specify a hex value for a non-printing character.
+ #
+ # The following example illustrates all of these extensions:
+ #
+ # 102.54.94.97 rhino #PRE #DOM:networking #net group's DC
+ # 102.54.94.102 "appname \0x14" #special app server
+ # 102.54.94.123 popular #PRE #source server
+ # 102.54.94.117 localsrv #PRE #needed for the include
+ #
+ # #BEGIN_ALTERNATE
+ # #INCLUDE \\localsrv\public\lmhosts
+ # #INCLUDE \\rhino\public\lmhosts
+ # #END_ALTERNATE
+ #
+ # In the above example, the "appname" server contains a special
+ # character in its name, the "popular" and "localsrv" server names are
+ # preloaded, and the "rhino" server name is specified so it can be used
+ # to later #INCLUDE a centrally maintained lmhosts file if the "localsrv"
+ # system is unavailable.
+ #
+ # Note that the whole file is parsed including comments on each lookup,
+ # so keeping the number of comments to a minimum will improve performance.
+ # Therefore it is not advisable to simply add lmhosts file entries onto the
+ # end of this file.
+</programlisting></para>
+
+</sect2>
+
+<sect2>
+<title>HOSTS file</title>
+
+<para>
+This file is usually located in MS Windows NT 4.0 or 2000 in
+<filename>C:\WINNT\SYSTEM32\DRIVERS\ETC</filename> and contains
+the IP Address and the IP hostname in matched pairs. It can be
+used by the name resolution infrastructure in MS Windows, depending
+on how the TCP/IP environment is configured. This file is in
+every way the equivalent of the Unix/Linux <filename>/etc/hosts</filename> file.
+</para>
+</sect2>
+
+
+<sect2>
+<title>DNS Lookup</title>
+
+<para>
+This capability is configured in the TCP/IP setup area in the network
+configuration facility. If enabled an elaborate name resolution sequence
+is followed the precise nature of which isdependant on what the NetBIOS
+Node Type parameter is configured to. A Node Type of 0 means use
+NetBIOS broadcast (over UDP broadcast) is first used if the name
+that is the subject of a name lookup is not found in the NetBIOS name
+cache. If that fails then DNS, HOSTS and LMHOSTS are checked. If set to
+Node Type 8, then a NetBIOS Unicast (over UDP Unicast) is sent to the
+WINS Server to obtain a lookup before DNS, HOSTS, LMHOSTS, or broadcast
+lookup is used.
+</para>
+
+</sect2>
+
+<sect2>
+<title>WINS Lookup</title>
+
+<para>
+A WINS (Windows Internet Name Server) service is the equivaent of the
+rfc1001/1002 specified NBNS (NetBIOS Name Server). A WINS server stores
+the names and IP addresses that are registered by a Windows client
+if the TCP/IP setup has been given at least one WINS Server IP Address.
+</para>
+
+<para>
+To configure Samba to be a WINS server the following parameter needs
+to be added to the <filename>smb.conf</filename> file:
+</para>
+
+<para><programlisting>
+ wins support = Yes
+</programlisting></para>
+
+<para>
+To configure Samba to use a WINS server the following parameters are
+needed in the smb.conf file:
+</para>
+
+<para><programlisting>
+ wins support = No
+ wins server = xxx.xxx.xxx.xxx
+</programlisting></para>
+
+<para>
+where <replaceable>xxx.xxx.xxx.xxx</replaceable> is the IP address
+of the WINS server.
+</para>
+
+</sect2>
+</sect1>
+
+
+<sect1>
+<title>How browsing functions and how to deploy stable and
+dependable browsing using Samba</title>
+
+
+<para>
+As stated above, MS Windows machines register their NetBIOS names
+(ie: the machine name for each service type in operation) on start
+up. Also, as stated above, the exact method by which this name registration
+takes place is determined by whether or not the MS Windows client/server
+has been given a WINS server address, whether or not LMHOSTS lookup
+is enabled, or if DNS for NetBIOS name resolution is enabled, etc.
+</para>
+
+<para>
+In the case where there is no WINS server all name registrations as
+well as name lookups are done by UDP broadcast. This isolates name
+resolution to the local subnet, unless LMHOSTS is used to list all
+names and IP addresses. In such situations Samba provides a means by
+which the samba server name may be forcibly injected into the browse
+list of a remote MS Windows network (using the "remote announce" parameter).
+</para>
+
+<para>
+Where a WINS server is used, the MS Windows client will use UDP
+unicast to register with the WINS server. Such packets can be routed
+and thus WINS allows name resolution to function across routed networks.
+</para>
+
+<para>
+During the startup process an election will take place to create a
+local master browser if one does not already exist. On each NetBIOS network
+one machine will be elected to function as the domain master browser. This
+domain browsing has nothing to do with MS security domain control.
+Instead, the domain master browser serves the role of contacting each local
+master browser (found by asking WINS or from LMHOSTS) and exchanging browse
+list contents. This way every master browser will eventually obtain a complete
+list of all machines that are on the network. Every 11-15 minutes an election
+is held to determine which machine will be the master browser. By nature of
+the election criteria used, the machine with the highest uptime, or the
+most senior protocol version, or other criteria, will win the election
+as domain master browser.
+</para>
+
+<para>
+Clients wishing to browse the network make use of this list, but also depend
+on the availability of correct name resolution to the respective IP
+address/addresses.
+</para>
+
+<para>
+Any configuration that breaks name resolution and/or browsing intrinsics
+will annoy users because they will have to put up with protracted
+inability to use the network services.
+</para>
+
+<para>
+Samba supports a feature that allows forced synchonisation
+of browse lists across routed networks using the "remote
+browse sync" parameter in the smb.conf file. This causes Samba
+to contact the local master browser on a remote network and
+to request browse list synchronisation. This effectively bridges
+two networks that are separated by routers. The two remote
+networks may use either broadcast based name resolution or WINS
+based name resolution, but it should be noted that the "remote
+browse sync" parameter provides browse list synchronisation - and
+that is distinct from name to address resolution, in other
+words, for cross subnet browsing to function correctly it is
+essential that a name to address resolution mechanism be provided.
+This mechanism could be via DNS, <filename>/etc/hosts</filename>,
+and so on.
+</para>
+
+</sect1>
+
+<sect1>
+<title>MS Windows security options and how to configure
+Samba for seemless integration</title>
+
+<para>
+MS Windows clients may use encrypted passwords as part of a
+challenege/response authentication model (a.k.a. NTLMv1) or
+alone, or clear text strings for simple password based
+authentication. It should be realized that with the SMB
+protocol the password is passed over the network either
+in plain text or encrypted, but not both in the same
+authentication requets.
+</para>
+
+<para>
+When encrypted passwords are used a password that has been
+entered by the user is encrypted in two ways:
+</para>
+
+<itemizedlist>
+ <listitem><para>An MD4 hash of the UNICODE of the password
+ string. This is known as the NT hash.
+ </para></listitem>
+
+ <listitem><para>The password is converted to upper case,
+ and then padded or trucated to 14 bytes. This string is
+ then appended with 5 bytes of NULL characters and split to
+ form two 56 bit DES keys to encrypt a "magic" 8 byte value.
+ The resulting 16 bytes for the LanMan hash.
+ </para></listitem>
+</itemizedlist>
+
+<para>
+You should refer to the <ulink url="ENCRYPTION.html">
+Password Encryption</ulink> chapter in this HOWTO collection
+for more details on the inner workings
+</para>
+
+<para>
+MS Windows 95 pre-service pack 1, MS Windows NT versions 3.x
+and version 4.0 pre-service pack 3 will use either mode of
+password authentication. All versions of MS Windows that follow
+these versions no longer support plain text passwords by default.
+</para>
+
+<para>
+MS Windows clients have a habit of dropping network mappings that
+have been idle for 10 minutes or longer. When the user attempts to
+use the mapped drive connection that has been dropped the SMB protocol
+has a mechanism by which the connection can be re-established using
+a cached copy of the password.
+</para>
+
+<para>
+When Microsoft changed the default password mode, they dropped support for
+caching of the plain text password. This means that when the registry
+parameter is changed to re-enable use of plain text passwords it appears to
+work, but when a dropped mapping attempts to revalidate it will fail if
+the remote authentication server does not support encrypted passwords.
+This means that it is definitely not a good idea to re-enable plain text
+password support in such clients.
+</para>
+
+<para>
+The following parameters can be used to work around the
+issue of Windows 9x client upper casing usernames and
+password before transmitting them to the SMB server
+when using clear text authentication.
+</para>
+
+<para><programlisting>
+ <ulink url="smb.conf.5.html#PASSWORDLEVEL">passsword level</ulink> = <replaceable>integer</replaceable>
+ <ulink url="smb.conf.5.html#USERNAMELEVEL">username level</ulink> = <replaceable>integer</replaceable>
+</programlisting></para>
+
+<para>
+By default Samba will lower case the username before attempting
+to lookup the user in the database of local system accounts.
+Because UNIX usernames conventionally only contain lower case
+character, the <parameter>username level</parameter> parameter
+is rarely even needed.
+</para>
+
+<para>
+However, password on UNIX systems often make use of mixed case
+characters. This means that in order for a user on a Windows 9x
+client to connect to a Samba server using clear text authentication,
+the <parameter>password level</parameter> must be set to the maximum
+number of upper case letter which <emphasis>could</emphasis> appear
+is a password. Note that is the server OS uses the traditional
+DES version of crypt(), then a <parameter>password level</parameter>
+of 8 will result in case insensitive passwords as seen from Windows
+users. This will also result in longer login times as Samba
+hash to compute the permutations of the password string and
+try them one by one until a match is located (or all combinations fail).
+</para>
+
+<para>
+The best option to adopt is to enable support for encrypted passwords
+where ever Samba is used. There are three configuration possibilities
+for support of encrypted passwords:
+</para>
+
+
+<sect2>
+<title>Use MS Windows NT as an authentication server</title>
+
+<para>
+This method involves the additions of the following parameters
+in the smb.conf file:
+</para>
+
+<para><programlisting>
+ encrypt passwords = Yes
+ security = server
+ password server = "NetBIOS_name_of_PDC"
+</programlisting></para>
+
+
+<para>
+There are two ways of identifying whether or not a username and
+password pair was valid or not. One uses the reply information provided
+as part of the authentication messaging process, the other uses
+just and error code.
+</para>
+
+<para>
+The down-side of this mode of configuration is the fact that
+for security reasons Samba will send the password server a bogus
+username and a bogus password and if the remote server fails to
+reject the username and password pair then an alternative mode
+of identification of validation is used. Where a site uses password
+lock out after a certain number of failed authentication attempts
+this will result in user lockouts.
+</para>
+
+<para>
+Use of this mode of authentication does require there to be
+a standard Unix account for the user, this account can be blocked
+to prevent logons by other than MS Windows clients.
+</para>
+
+</sect2>
+
+<sect2>
+<title>Make Samba a member of an MS Windows NT security domain</title>
+
+<para>
+This method involves additon of the following paramters in the smb.conf file:
+</para>
+
+<para><programlisting>
+ encrypt passwords = Yes
+ security = domain
+ workgroup = "name of NT domain"
+ password server = *
+</programlisting></para>
+
+<para>
+The use of the "*" argument to "password server" will cause samba
+to locate the domain controller in a way analogous to the way
+this is done within MS Windows NT.
+</para>
+
+<para>
+In order for this method to work the Samba server needs to join the
+MS Windows NT security domain. This is done as follows:
+</para>
+
+<itemizedlist>
+ <listitem><para>On the MS Windows NT domain controller using
+ the Server Manager add a machine account for the Samba server.
+ </para></listitem>
+
+ <listitem><para>Next, on the Linux system execute:
+ <command>smbpasswd -r PDC_NAME -j DOMAIN_NAME</command>
+ </para></listitem>
+</itemizedlist>
+
+<para>
+Use of this mode of authentication does require there to be
+a standard Unix account for the user in order to assign
+a uid once the account has been authenticated by the remote
+Windows DC. This account can be blocked to prevent logons by
+other than MS Windows clients by things such as setting an invalid
+shell in the <filename>/etc/passwd</filename> entry.
+</para>
+
+<para>
+An alternative to assigning UIDs to Windows users on a
+Samba member server is presented in the <ulink
+url="winbind.html">Winbind Overview</ulink> chapter in
+this HOWTO collection.
+</para>
+
+
+</sect2>
+
+
+<sect2>
+<title>Configure Samba as an authentication server</title>
+
+<para>
+This mode of authentication demands that there be on the
+Unix/Linux system both a Unix style account as well as and
+smbpasswd entry for the user. The Unix system account can be
+locked if required as only the encrypted password will be
+used for SMB client authentication.
+</para>
+
+<para>
+This method involves addition of the following parameters to
+the smb.conf file:
+</para>
+
+<para><programlisting>
+## please refer to the Samba PDC HOWTO chapter later in
+## this collection for more details
+[global]
+ encrypt passwords = Yes
+ security = user
+ domain logons = Yes
+ ; an OS level of 33 or more is recommended
+ os level = 33
+
+[NETLOGON]
+ path = /somewhare/in/file/system
+ read only = yes
+</programlisting></para>
+
+<para>
+in order for this method to work a Unix system account needs
+to be created for each user, as well as for each MS Windows NT/2000
+machine. The following structure is required.
+</para>
+
+<sect3>
+<title>Users</title>
+
+<para>
+A user account that may provide a home directory should be
+created. The following Linux system commands are typical of
+the procedure for creating an account.
+</para>
+
+<para><programlisting>
+ # useradd -s /bin/bash -d /home/"userid" -m "userid"
+ # passwd "userid"
+ Enter Password: &lt;pw&gt;
+
+ # smbpasswd -a "userid"
+ Enter Password: &lt;pw&gt;
+</programlisting></para>
+</sect3>
+
+<sect3>
+<title>MS Windows NT Machine Accounts</title>
+
+<para>
+These are required only when Samba is used as a domain
+controller. Refer to the Samba-PDC-HOWTO for more details.
+</para>
+
+<para><programlisting>
+ # useradd -s /bin/false -d /dev/null "machine_name"\$
+ # passwd -l "machine_name"\$
+ # smbpasswd -a -m "machine_name"
+</programlisting></para>
+</sect3>
+</sect2>
+</sect1>
+
+
+<sect1>
+<title>Conclusions</title>
+
+<para>
+Samba provides a flexible means to operate as...
+</para>
+
+<itemizedlist>
+ <listitem><para>A Stand-alone server - No special action is needed
+ other than to create user accounts. Stand-alone servers do NOT
+ provide network logon services, meaning that machines that use this
+ server do NOT perform a domain logon but instead make use only of
+ the MS Windows logon which is local to the MS Windows
+ workstation/server.
+ </para></listitem>
+
+ <listitem><para>An MS Windows NT 3.x/4.0 security domain member.
+ </para></listitem>
+
+
+ <listitem><para>An alternative to an MS Windows NT 3.x/4.0
+ Domain Controller.
+ </para></listitem>
+
+</itemizedlist>
+
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/NT_Security.sgml b/docs/docbook/projdoc/NT_Security.sgml
new file mode 100644
index 00000000000..2259dae029e
--- /dev/null
+++ b/docs/docbook/projdoc/NT_Security.sgml
@@ -0,0 +1,358 @@
+<chapter id="unix-permissions">
+
+<chapterinfo>
+ <author>
+ <firstname>Jeremy</firstname><surname>Allison</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>samba@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>12 Apr 1999</pubdate>
+</chapterinfo>
+
+
+<title>UNIX Permission Bits and Windows NT Access Control Lists</title>
+
+<sect1>
+ <title>Viewing and changing UNIX permissions using the NT
+ security dialogs</title>
+
+
+ <para>New in the Samba 2.0.4 release is the ability for Windows
+ NT clients to use their native security settings dialog box to
+ view and modify the underlying UNIX permissions.</para>
+
+ <para>Note that this ability is careful not to compromise
+ the security of the UNIX host Samba is running on, and
+ still obeys all the file permission rules that a Samba
+ administrator can set.</para>
+
+ <para>In Samba 2.0.4 and above the default value of the
+ parameter <ulink url="smb.conf.5.html#NTACLSUPPORT"><parameter>
+ nt acl support</parameter></ulink> has been changed from
+ <constant>false</constant> to <constant>true</constant>, so
+ manipulation of permissions is turned on by default.</para>
+</sect1>
+
+<sect1>
+ <title>How to view file security on a Samba share</title>
+
+ <para>From an NT 4.0 client, single-click with the right
+ mouse button on any file or directory in a Samba mounted
+ drive letter or UNC path. When the menu pops-up, click
+ on the <emphasis>Properties</emphasis> entry at the bottom of
+ the menu. This brings up the normal file properties dialog
+ box, but with Samba 2.0.4 this will have a new tab along the top
+ marked <emphasis>Security</emphasis>. Click on this tab and you
+ will see three buttons, <emphasis>Permissions</emphasis>,
+ <emphasis>Auditing</emphasis>, and <emphasis>Ownership</emphasis>.
+ The <emphasis>Auditing</emphasis> button will cause either
+ an error message <errorname>A requested privilege is not held
+ by the client</errorname> to appear if the user is not the
+ NT Administrator, or a dialog which is intended to allow an
+ Administrator to add auditing requirements to a file if the
+ user is logged on as the NT Administrator. This dialog is
+ non-functional with a Samba share at this time, as the only
+ useful button, the <command>Add</command> button will not currently
+ allow a list of users to be seen.</para>
+
+</sect1>
+
+<sect1>
+ <title>Viewing file ownership</title>
+
+ <para>Clicking on the <command>"Ownership"</command> button
+ brings up a dialog box telling you who owns the given file. The
+ owner name will be of the form :</para>
+
+ <para><command>"SERVER\user (Long name)"</command></para>
+
+ <para>Where <replaceable>SERVER</replaceable> is the NetBIOS name of
+ the Samba server, <replaceable>user</replaceable> is the user name of
+ the UNIX user who owns the file, and <replaceable>(Long name)</replaceable>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database). Click on the <command>Close
+ </command> button to remove this dialog.</para>
+
+ <para>If the parameter <parameter>nt acl support</parameter>
+ is set to <constant>false</constant> then the file owner will
+ be shown as the NT user <command>"Everyone"</command>.</para>
+
+ <para>The <command>Take Ownership</command> button will not allow
+ you to change the ownership of this file to yourself (clicking on
+ it will display a dialog box complaining that the user you are
+ currently logged onto the NT client cannot be found). The reason
+ for this is that changing the ownership of a file is a privileged
+ operation in UNIX, available only to the <emphasis>root</emphasis>
+ user. As clicking on this button causes NT to attempt to change
+ the ownership of a file to the current user logged into the NT
+ client this will not work with Samba at this time.</para>
+
+ <para>There is an NT chown command that will work with Samba
+ and allow a user with Administrator privilege connected
+ to a Samba 2.0.4 server as root to change the ownership of
+ files on both a local NTFS filesystem or remote mounted NTFS
+ or Samba drive. This is available as part of the <emphasis>Seclib
+ </emphasis> NT security library written by Jeremy Allison of
+ the Samba Team, available from the main Samba ftp site.</para>
+
+</sect1>
+
+<sect1>
+ <title>Viewing file or directory permissions</title>
+
+ <para>The third button is the <command>"Permissions"</command>
+ button. Clicking on this brings up a dialog box that shows both
+ the permissions and the UNIX owner of the file or directory.
+ The owner is displayed in the form :</para>
+
+ <para><command>"SERVER\user (Long name)"</command></para>
+
+ <para>Where <replaceable>SERVER</replaceable> is the NetBIOS name of
+ the Samba server, <replaceable>user</replaceable> is the user name of
+ the UNIX user who owns the file, and <replaceable>(Long name)</replaceable>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database).</para>
+
+ <para>If the parameter <parameter>nt acl support</parameter>
+ is set to <constant>false</constant> then the file owner will
+ be shown as the NT user <command>"Everyone"</command> and the
+ permissions will be shown as NT "Full Control".</para>
+
+
+ <para>The permissions field is displayed differently for files
+ and directories, so I'll describe the way file permissions
+ are displayed first.</para>
+
+ <sect2>
+ <title>File Permissions</title>
+
+ <para>The standard UNIX user/group/world triple and
+ the corresponding "read", "write", "execute" permissions
+ triples are mapped by Samba into a three element NT ACL
+ with the 'r', 'w', and 'x' bits mapped into the corresponding
+ NT permissions. The UNIX world permissions are mapped into
+ the global NT group <command>Everyone</command>, followed
+ by the list of permissions allowed for UNIX world. The UNIX
+ owner and group permissions are displayed as an NT
+ <command>user</command> icon and an NT <command>local
+ group</command> icon respectively followed by the list
+ of permissions allowed for the UNIX user and group.</para>
+
+ <para>As many UNIX permission sets don't map into common
+ NT names such as <command>"read"</command>, <command>
+ "change"</command> or <command>"full control"</command> then
+ usually the permissions will be prefixed by the words <command>
+ "Special Access"</command> in the NT display list.</para>
+
+ <para>But what happens if the file has no permissions allowed
+ for a particular UNIX user group or world component ? In order
+ to allow "no permissions" to be seen and modified then Samba
+ overloads the NT <command>"Take Ownership"</command> ACL attribute
+ (which has no meaning in UNIX) and reports a component with
+ no permissions as having the NT <command>"O"</command> bit set.
+ This was chosen of course to make it look like a zero, meaning
+ zero permissions. More details on the decision behind this will
+ be given below.</para>
+ </sect2>
+
+ <sect2>
+ <title>Directory Permissions</title>
+
+ <para>Directories on an NT NTFS file system have two
+ different sets of permissions. The first set of permissions
+ is the ACL set on the directory itself, this is usually displayed
+ in the first set of parentheses in the normal <command>"RW"</command>
+ NT style. This first set of permissions is created by Samba in
+ exactly the same way as normal file permissions are, described
+ above, and is displayed in the same way.</para>
+
+ <para>The second set of directory permissions has no real meaning
+ in the UNIX permissions world and represents the <command>
+ "inherited"</command> permissions that any file created within
+ this directory would inherit.</para>
+
+ <para>Samba synthesises these inherited permissions for NT by
+ returning as an NT ACL the UNIX permission mode that a new file
+ created by Samba on this share would receive.</para>
+ </sect2>
+</sect1>
+
+<sect1>
+ <title>Modifying file or directory permissions</title>
+
+ <para>Modifying file and directory permissions is as simple
+ as changing the displayed permissions in the dialog box, and
+ clicking the <command>OK</command> button. However, there are
+ limitations that a user needs to be aware of, and also interactions
+ with the standard Samba permission masks and mapping of DOS
+ attributes that need to also be taken into account.</para>
+
+ <para>If the parameter <parameter>nt acl support</parameter>
+ is set to <constant>false</constant> then any attempt to set
+ security permissions will fail with an <command>"Access Denied"
+ </command> message.</para>
+
+ <para>The first thing to note is that the <command>"Add"</command>
+ button will not return a list of users in Samba 2.0.4 (it will give
+ an error message of <command>"The remote procedure call failed
+ and did not execute"</command>). This means that you can only
+ manipulate the current user/group/world permissions listed in
+ the dialog box. This actually works quite well as these are the
+ only permissions that UNIX actually has.</para>
+
+ <para>If a permission triple (either user, group, or world)
+ is removed from the list of permissions in the NT dialog box,
+ then when the <command>"OK"</command> button is pressed it will
+ be applied as "no permissions" on the UNIX side. If you then
+ view the permissions again the "no permissions" entry will appear
+ as the NT <command>"O"</command> flag, as described above. This
+ allows you to add permissions back to a file or directory once
+ you have removed them from a triple component.</para>
+
+ <para>As UNIX supports only the "r", "w" and "x" bits of
+ an NT ACL then if other NT security attributes such as "Delete
+ access" are selected then they will be ignored when applied on
+ the Samba server.</para>
+
+ <para>When setting permissions on a directory the second
+ set of permissions (in the second set of parentheses) is
+ by default applied to all files within that directory. If this
+ is not what you want you must uncheck the <command>"Replace
+ permissions on existing files"</command> checkbox in the NT
+ dialog before clicking <command>"OK"</command>.</para>
+
+ <para>If you wish to remove all permissions from a
+ user/group/world component then you may either highlight the
+ component and click the <command>"Remove"</command> button,
+ or set the component to only have the special <command>"Take
+ Ownership"</command> permission (displayed as <command>"O"
+ </command>) highlighted.</para>
+</sect1>
+
+<sect1>
+ <title>Interaction with the standard Samba create mask
+ parameters</title>
+
+ <para>Note that with Samba 2.0.5 there are four new parameters
+ to control this interaction. These are :</para>
+
+ <para><parameter>security mask</parameter></para>
+ <para><parameter>force security mode</parameter></para>
+ <para><parameter>directory security mask</parameter></para>
+ <para><parameter>force directory security mode</parameter></para>
+
+ <para>Once a user clicks <command>"OK"</command> to apply the
+ permissions Samba maps the given permissions into a user/group/world
+ r/w/x triple set, and then will check the changed permissions for a
+ file against the bits set in the <ulink url="smb.conf.5.html#SECURITYMASK">
+ <parameter>security mask</parameter></ulink> parameter. Any bits that
+ were changed that are not set to '1' in this parameter are left alone
+ in the file permissions.</para>
+
+ <para>Essentially, zero bits in the <parameter>security mask</parameter>
+ mask may be treated as a set of bits the user is <emphasis>not</emphasis>
+ allowed to change, and one bits are those the user is allowed to change.
+ </para>
+
+ <para>If not set explicitly this parameter is set to the same value as
+ the <ulink url="smb.conf.5.html#CREATEMASK"><parameter>create mask
+ </parameter></ulink> parameter to provide compatibility with Samba 2.0.4
+ where this permission change facility was introduced. To allow a user to
+ modify all the user/group/world permissions on a file, set this parameter
+ to 0777.</para>
+
+ <para>Next Samba checks the changed permissions for a file against
+ the bits set in the <ulink url="smb.conf.5.html#FORCESECURITYMODE">
+ <parameter>force security mode</parameter></ulink> parameter. Any bits
+ that were changed that correspond to bits set to '1' in this parameter
+ are forced to be set.</para>
+
+ <para>Essentially, bits set in the <parameter>force security mode
+ </parameter> parameter may be treated as a set of bits that, when
+ modifying security on a file, the user has always set to be 'on'.</para>
+
+ <para>If not set explicitly this parameter is set to the same value
+ as the <ulink url="smb.conf.5.html#FORCECREATEMODE"><parameter>force
+ create mode</parameter></ulink> parameter to provide compatibility
+ with Samba 2.0.4 where the permission change facility was introduced.
+ To allow a user to modify all the user/group/world permissions on a file
+ with no restrictions set this parameter to 000.</para>
+
+ <para>The <parameter>security mask</parameter> and <parameter>force
+ security mode</parameter> parameters are applied to the change
+ request in that order.</para>
+
+ <para>For a directory Samba will perform the same operations as
+ described above for a file except using the parameter <parameter>
+ directory security mask</parameter> instead of <parameter>security
+ mask</parameter>, and <parameter>force directory security mode
+ </parameter> parameter instead of <parameter>force security mode
+ </parameter>.</para>
+
+ <para>The <parameter>directory security mask</parameter> parameter
+ by default is set to the same value as the <parameter>directory mask
+ </parameter> parameter and the <parameter>force directory security
+ mode</parameter> parameter by default is set to the same value as
+ the <parameter>force directory mode</parameter> parameter to provide
+ compatibility with Samba 2.0.4 where the permission change facility
+ was introduced.</para>
+
+ <para>In this way Samba enforces the permission restrictions that
+ an administrator can set on a Samba share, whilst still allowing users
+ to modify the permission bits within that restriction.</para>
+
+ <para>If you want to set up a share that allows users full control
+ in modifying the permission bits on their files and directories and
+ doesn't force any particular bits to be set 'on', then set the following
+ parameters in the <ulink url="smb.conf.5.html"><filename>smb.conf(5)
+ </filename></ulink> file in that share specific section :</para>
+
+ <para><parameter>security mask = 0777</parameter></para>
+ <para><parameter>force security mode = 0</parameter></para>
+ <para><parameter>directory security mask = 0777</parameter></para>
+ <para><parameter>force directory security mode = 0</parameter></para>
+
+ <para>As described, in Samba 2.0.4 the parameters :</para>
+
+ <para><parameter>create mask</parameter></para>
+ <para><parameter>force create mode</parameter></para>
+ <para><parameter>directory mask</parameter></para>
+ <para><parameter>force directory mode</parameter></para>
+
+ <para>were used instead of the parameters discussed here.</para>
+</sect1>
+
+<sect1>
+ <title>Interaction with the standard Samba file attribute
+ mapping</title>
+
+ <para>Samba maps some of the DOS attribute bits (such as "read
+ only") into the UNIX permissions of a file. This means there can
+ be a conflict between the permission bits set via the security
+ dialog and the permission bits set by the file attribute mapping.
+ </para>
+
+ <para>One way this can show up is if a file has no UNIX read access
+ for the owner it will show up as "read only" in the standard
+ file attributes tabbed dialog. Unfortunately this dialog is
+ the same one that contains the security info in another tab.</para>
+
+ <para>What this can mean is that if the owner changes the permissions
+ to allow themselves read access using the security dialog, clicks
+ <command>"OK"</command> to get back to the standard attributes tab
+ dialog, and then clicks <command>"OK"</command> on that dialog, then
+ NT will set the file permissions back to read-only (as that is what
+ the attributes still say in the dialog). This means that after setting
+ permissions and clicking <command>"OK"</command> to get back to the
+ attributes dialog you should always hit <command>"Cancel"</command>
+ rather than <command>"OK"</command> to ensure that your changes
+ are not overridden.</para>
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/OS2-Client-HOWTO.sgml b/docs/docbook/projdoc/OS2-Client-HOWTO.sgml
new file mode 100644
index 00000000000..ca7ad6a754e
--- /dev/null
+++ b/docs/docbook/projdoc/OS2-Client-HOWTO.sgml
@@ -0,0 +1,142 @@
+<chapter id="os2">
+
+
+<chapterinfo>
+ <author>
+ <firstname>Jim</firstname><surname>McDonough</surname>
+ <affiliation>
+ <orgname>IBM</orgname>
+ <address>
+ <email>jerry@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>5 Mar 2001</pubdate>
+</chapterinfo>
+
+<title>OS2 Client HOWTO</title>
+
+<sect1>
+ <title>FAQs</title>
+
+ <sect2>
+ <title>How can I configure OS/2 Warp Connect or
+ OS/2 Warp 4 as a client for Samba?</title>
+
+ <para>A more complete answer to this question can be
+ found on <ulink url="http://carol.wins.uva.nl/~leeuw/samba/warp.html">
+ http://carol.wins.uva.nl/~leeuw/samba/warp.html</ulink>.</para>
+
+ <para>Basically, you need three components:</para>
+
+ <itemizedlist>
+ <listitem><para>The File and Print Client ('IBM Peer')
+ </para></listitem>
+ <listitem><para>TCP/IP ('Internet support')
+ </para></listitem>
+ <listitem><para>The "NetBIOS over TCP/IP" driver ('TCPBEUI')
+ </para></listitem>
+ </itemizedlist>
+
+ <para>Installing the first two together with the base operating
+ system on a blank system is explained in the Warp manual. If Warp
+ has already been installed, but you now want to install the
+ networking support, use the "Selective Install for Networking"
+ object in the "System Setup" folder.</para>
+
+ <para>Adding the "NetBIOS over TCP/IP" driver is not described
+ in the manual and just barely in the online documentation. Start
+ MPTS.EXE, click on OK, click on "Configure LAPS" and click
+ on "IBM OS/2 NETBIOS OVER TCP/IP" in 'Protocols'. This line
+ is then moved to 'Current Configuration'. Select that line,
+ click on "Change number" and increase it from 0 to 1. Save this
+ configuration.</para>
+
+ <para>If the Samba server(s) is not on your local subnet, you
+ can optionally add IP names and addresses of these servers
+ to the "Names List", or specify a WINS server ('NetBIOS
+ Nameserver' in IBM and RFC terminology). For Warp Connect you
+ may need to download an update for 'IBM Peer' to bring it on
+ the same level as Warp 4. See the webpage mentioned above.</para>
+ </sect2>
+
+ <sect2>
+ <title>How can I configure OS/2 Warp 3 (not Connect),
+ OS/2 1.2, 1.3 or 2.x for Samba?</title>
+
+ <para>You can use the free Microsoft LAN Manager 2.2c Client
+ for OS/2 from
+ <ulink url="ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/">
+ ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/</ulink>.
+ See <ulink url="http://carol.wins.uva.nl/~leeuw/lanman.html">
+ http://carol.wins.uva.nl/~leeuw/lanman.html</ulink> for
+ more information on how to install and use this client. In
+ a nutshell, edit the file \OS2VER in the root directory of
+ the OS/2 boot partition and add the lines:</para>
+
+ <para><programlisting>
+ 20=setup.exe
+ 20=netwksta.sys
+ 20=netvdd.sys
+ </programlisting></para>
+
+ <para>before you install the client. Also, don't use the
+ included NE2000 driver because it is buggy. Try the NE2000
+ or NS2000 driver from
+ <ulink url="ftp://ftp.cdrom.com/pub/os2/network/ndis/">
+ ftp://ftp.cdrom.com/pub/os2/network/ndis/</ulink> instead.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Are there any other issues when OS/2 (any version)
+ is used as a client?</title>
+
+ <para>When you do a NET VIEW or use the "File and Print
+ Client Resource Browser", no Samba servers show up. This can
+ be fixed by a patch from <ulink
+ url="http://carol.wins.uva.nl/~leeuw/samba/fix.html">
+ http://carol.wins.uva.nl/~leeuw/samba/fix.html</ulink>.
+ The patch will be included in a later version of Samba. It also
+ fixes a couple of other problems, such as preserving long
+ filenames when objects are dragged from the Workplace Shell
+ to the Samba server. </para>
+ </sect2>
+
+ <sect2>
+ <title>How do I get printer driver download working
+ for OS/2 clients?</title>
+
+ <para>First, create a share called [PRINTDRV] that is
+ world-readable. Copy your OS/2 driver files there. Note
+ that the .EA_ files must still be separate, so you will need
+ to use the original install files, and not copy an installed
+ driver from an OS/2 system.</para>
+
+ <para>Install the NT driver first for that printer. Then,
+ add to your smb.conf a parameter, "os2 driver map =
+ <replaceable>filename</replaceable>". Then, in the file
+ specified by <replaceable>filename</replaceable>, map the
+ name of the NT driver name to the OS/2 driver name as
+ follows:</para>
+
+ <para>&lt;nt driver name&gt; = &lt;os2 driver
+ name&gt;.&lt;device name&gt;, e.g.:
+ HP LaserJet 5L = LASERJET.HP LaserJet 5L</para>
+
+ <para>You can have multiple drivers mapped in this file.</para>
+
+ <para>If you only specify the OS/2 driver name, and not the
+ device name, the first attempt to download the driver will
+ actually download the files, but the OS/2 client will tell
+ you the driver is not available. On the second attempt, it
+ will work. This is fixed simply by adding the device name
+ to the mapping, after which it will work on the first attempt.
+ </para>
+ </sect2>
+</sect1>
+
+</chapter>
+
diff --git a/docs/docbook/projdoc/PAM-Authentication-And-Samba.sgml b/docs/docbook/projdoc/PAM-Authentication-And-Samba.sgml
new file mode 100644
index 00000000000..594516640de
--- /dev/null
+++ b/docs/docbook/projdoc/PAM-Authentication-And-Samba.sgml
@@ -0,0 +1,215 @@
+<chapter id="pam">
+
+
+<chapterinfo>
+ <author>
+ <firstname>John</firstname><surname>Terpstra</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>jht@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate> (Jun 21 2001) </pubdate>
+</chapterinfo>
+
+<title>Configuring PAM for distributed but centrally
+managed authentication</title>
+
+<sect1>
+<title>Samba and PAM</title>
+
+<para>
+A number of Unix systems (eg: Sun Solaris), as well as the
+xxxxBSD family and Linux, now utilize the Pluggable Authentication
+Modules (PAM) facility to provide all authentication,
+authorization and resource control services. Prior to the
+introduction of PAM, a decision to use an alternative to
+the system password database (<filename>/etc/passwd</filename>)
+would require the provision of alternatives for all programs that provide
+security services. Such a choice would involve provision of
+alternatives to such programs as: <command>login</command>,
+<command>passwd</command>, <command>chown</command>, etc.
+</para>
+
+<para>
+PAM provides a mechanism that disconnects these security programs
+from the underlying authentication/authorization infrastructure.
+PAM is configured either through one file <filename>/etc/pam.conf</filename> (Solaris),
+or by editing individual files that are located in <filename>/etc/pam.d</filename>.
+</para>
+
+<para>
+The following is an example <filename>/etc/pam.d/login</filename> configuration file.
+This example had all options been uncommented is probably not usable
+as it stacks many conditions before allowing successful completion
+of the login process. Essentially all conditions can be disabled
+by commenting them out except the calls to <filename>pam_pwdb.so</filename>.
+</para>
+
+<para><programlisting>
+#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_securetty.so
+auth required pam_nologin.so
+# auth required pam_dialup.so
+# auth optional pam_mail.so
+auth required pam_pwdb.so shadow md5
+# account requisite pam_time.so
+account required pam_pwdb.so
+session required pam_pwdb.so
+# session optional pam_lastlog.so
+# password required pam_cracklib.so retry=3
+password required pam_pwdb.so shadow md5
+</programlisting></para>
+
+<para>
+PAM allows use of replacable modules. Those available on a
+sample system include:
+</para>
+
+<para><programlisting>
+$ /bin/ls /lib/security
+pam_access.so pam_ftp.so pam_limits.so
+pam_ncp_auth.so pam_rhosts_auth.so pam_stress.so
+pam_cracklib.so pam_group.so pam_listfile.so
+pam_nologin.so pam_rootok.so pam_tally.so
+pam_deny.so pam_issue.so pam_mail.so
+pam_permit.so pam_securetty.so pam_time.so
+pam_dialup.so pam_lastlog.so pam_mkhomedir.so
+pam_pwdb.so pam_shells.so pam_unix.so
+pam_env.so pam_ldap.so pam_motd.so
+pam_radius.so pam_smbpass.so pam_unix_acct.so
+pam_wheel.so pam_unix_auth.so pam_unix_passwd.so
+pam_userdb.so pam_warn.so pam_unix_session.so
+</programlisting></para>
+
+<para>
+The following example for the login program replaces the use of
+the <filename>pam_pwdb.so</filename> module which uses the system
+password database (<filename>/etc/passwd</filename>,
+<filename>/etc/shadow</filename>, <filename>/etc/group</filename>) with
+the module <filename>pam_smbpass.so</filename> which uses the Samba
+database which contains the Microsoft MD4 encrypted password
+hashes. This database is stored in either
+<filename>/usr/local/samba/private/smbpasswd</filename>,
+<filename>/etc/samba/smbpasswd</filename>, or in
+<filename>/etc/samba.d/smbpasswd</filename>, depending on the
+Samba implementation for your Unix/Linux system. The
+<filename>pam_smbpass.so</filename> module is provided by
+Samba version 2.2.1 or later. It can be compiled by specifying the
+<command>--with-pam_smbpass</command> options when running Samba's
+<filename>configure</filename> script. For more information
+on the <filename>pam_smbpass</filename> module, see the documentation
+in the <filename>source/pam_smbpass</filename> directory of the Samba
+source distribution.
+</para>
+
+<para><programlisting>
+#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_smbpass.so nodelay
+account required pam_smbpass.so nodelay
+session required pam_smbpass.so nodelay
+password required pam_smbpass.so nodelay
+</programlisting></para>
+
+<para>
+The following is the PAM configuration file for a particular
+Linux system. The default condition uses <filename>pam_pwdb.so</filename>.
+</para>
+
+<para><programlisting>
+#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_pwdb.so nullok nodelay shadow audit
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_pwdb.so shadow md5
+</programlisting></para>
+
+<para>
+In the following example the decision has been made to use the
+smbpasswd database even for basic samba authentication. Such a
+decision could also be made for the passwd program and would
+thus allow the smbpasswd passwords to be changed using the passwd
+program.
+</para>
+
+<para><programlisting>
+#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_smbpass.so nodelay
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_smbpass.so nodelay smbconf=/etc/samba.d/smb.conf
+</programlisting></para>
+
+<para>
+Note: PAM allows stacking of authentication mechanisms. It is
+also possible to pass information obtained within on PAM module through
+to the next module in the PAM stack. Please refer to the documentation for
+your particular system implementation for details regarding the specific
+capabilities of PAM in this environment. Some Linux implmentations also
+provide the <filename>pam_stack.so</filename> module that allows all
+authentication to be configured in a single central file. The
+<filename>pam_stack.so</filename> method has some very devoted followers
+on the basis that it allows for easier administration. As with all issues in
+life though, every decision makes trade-offs, so you may want examine the
+PAM documentation for further helpful information.
+</para>
+
+</sect1>
+
+<sect1>
+<title>Distributed Authentication</title>
+
+<para>
+The astute administrator will realize from this that the
+combination of <filename>pam_smbpass.so</filename>,
+<command>winbindd</command>, and <command>rsync</command> (see
+<ulink url="http://rsync.samba.org/">http://rsync.samba.org/</ulink>)
+will allow the establishment of a centrally managed, distributed
+user/password database that can also be used by all
+PAM (eg: Linux) aware programs and applications. This arrangement
+can have particularly potent advantages compared with the
+use of Microsoft Active Directory Service (ADS) in so far as
+reduction of wide area network authentication traffic.
+</para>
+
+</sect1>
+
+<sect1>
+<title>PAM Configuration in smb.conf</title>
+
+<para>
+There is an option in smb.conf called <ulink
+url="smb.conf.5.html#OBEYPAMRESTRICTIONS">obey pam restrictions</ulink>.
+The following is from the on-line help for this option in SWAT;
+</para>
+
+<para>
+When Samba 2.2 is configure to enable PAM support (i.e.
+<constant>--with-pam</constant>), this parameter will
+control whether or not Samba should obey PAM's account
+and session management directives. The default behavior
+is to use PAM for clear text authentication only and to
+ignore any account or session management. Note that Samba always
+ignores PAM for authentication in the case of
+<ulink url="smb.conf.5.html#ENCRYPTPASSWORDS">encrypt passwords = yes</ulink>.
+The reason is that PAM modules cannot support the challenge/response
+authentication mechanism needed in the presence of SMB
+password encryption.
+</para>
+
+<para>Default: <command>obey pam restrictions = no</command></para>
+
+</sect1>
+</chapter>
diff --git a/docs/docbook/projdoc/Samba-PDC-HOWTO.sgml b/docs/docbook/projdoc/Samba-PDC-HOWTO.sgml
new file mode 100644
index 00000000000..475b66598c2
--- /dev/null
+++ b/docs/docbook/projdoc/Samba-PDC-HOWTO.sgml
@@ -0,0 +1,1828 @@
+<chapter id="samba-pdc">
+
+
+<chapterinfo>
+ <author>
+ <firstname>Gerald (Jerry)</firstname><surname>Carter</surname>
+ <affiliation>
+ <orgname>VA Linux Systems/Samba Team</orgname>
+ <address><email>jerry@samba.org</email></address>
+ </affiliation>
+ <firstname>David</firstname><surname>Bannon</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address><email>dbannon@samba.org</email></address>
+ </affiliation>
+
+ </author>
+ <pubdate> (26 Apr 2001) </pubdate>
+</chapterinfo>
+
+<title>
+How to Configure Samba 2.2 as a Primary Domain Controller
+</title>
+
+
+<!-- **********************************************************
+
+ Prerequisite Reading
+
+*************************************************************** -->
+<sect1>
+<title>Prerequisite Reading</title>
+
+<para>
+Before you continue reading in this chapter, please make sure
+that you are comfortable with configuring basic files services
+in smb.conf and how to enable and administer password
+encryption in Samba. Theses two topics are covered in the
+<ulink url="smb.conf.5.html"><filename>smb.conf(5)</filename></ulink>
+manpage and the <ulink url="ENCRYPTION.html">Encryption chapter</ulink>
+of this HOWTO Collection.
+</para>
+
+
+</sect1>
+
+
+
+<!-- **********************************************************
+
+ Background Information
+
+*************************************************************** -->
+<sect1>
+<title>
+Background
+</title>
+
+<note>
+<para>
+<emphasis>Author's Note:</emphasis> This document is a combination
+of David Bannon's "Samba 2.2 PDC HOWTO" and "Samba NT Domain FAQ".
+Both documents are superseded by this one.
+</para>
+</note>
+
+<para>
+Versions of Samba prior to release 2.2 had marginal capabilities to act
+as a Windows NT 4.0 Primary Domain Controller
+<indexterm><primary>Primary Domain Controller</primary></indexterm>
+(PDC). With Samba 2.2.0, we are proud to announce official support for
+Windows NT 4.0-style domain logons from Windows NT 4.0 and Windows
+2000 clients. This article outlines the steps
+necessary for configuring Samba as a PDC. It is necessary to have a
+working Samba server prior to implementing the PDC functionality. If
+you have not followed the steps outlined in <ulink
+url="UNIX_INSTALL.html"> UNIX_INSTALL.html</ulink>, please make sure
+that your server is configured correctly before proceeding. Another
+good resource in the <ulink url="smb.conf.5.html">smb.conf(5) man
+page</ulink>. The following functionality should work in 2.2:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+ domain logons for Windows NT 4.0/2000 clients.
+ </para></listitem>
+
+ <listitem><para>
+ placing a Windows 9x client in user level security
+ </para></listitem>
+
+ <listitem><para>
+ retrieving a list of users and groups from a Samba PDC to
+ Windows 9x/NT/2000 clients
+ </para></listitem>
+
+ <listitem><para>
+ roving (roaming) user profiles
+ </para></listitem>
+
+ <listitem><para>
+ Windows NT 4.0-style system policies
+ </para></listitem>
+</itemizedlist>
+
+
+<para>
+The following pieces of functionality are not included in the 2.2 release:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+ Windows NT 4 domain trusts
+ </para></listitem>
+
+ <listitem><para>
+ SAM replication with Windows NT 4.0 Domain Controllers
+ (i.e. a Samba PDC and a Windows NT BDC or vice versa)
+ </para></listitem>
+
+ <listitem><para>
+ Adding users via the User Manager for Domains
+ </para></listitem>
+
+ <listitem><para>
+ Acting as a Windows 2000 Domain Controller (i.e. Kerberos and
+ Active Directory)
+ </para></listitem>
+</itemizedlist>
+
+<para>
+Please note that Windows 9x clients are not true members of a domain
+for reasons outlined in this article. Therefore the protocol for
+support Windows 9x-style domain logons is completely different
+from NT4 domain logons and has been officially supported for some
+time.
+</para>
+
+
+<para>
+Implementing a Samba PDC can basically be divided into 2 broad
+steps.
+</para>
+
+<orderedlist numeration="Arabic">
+ <listitem><para>
+ Configuring the Samba PDC
+ </para></listitem>
+
+ <listitem><para>
+ Creating machine trust accounts and joining clients
+ to the domain
+ </para></listitem>
+</orderedlist>
+
+<para>
+There are other minor details such as user profiles, system
+policies, etc... However, these are not necessarily specific
+to a Samba PDC as much as they are related to Windows NT networking
+concepts. They will be mentioned only briefly here.
+</para>
+
+</sect1>
+
+
+<!-- **********************************************************
+
+ Configuring the Samba PDC
+
+*************************************************************** -->
+
+<sect1>
+<title>Configuring the Samba Domain Controller</title>
+
+<para>
+The first step in creating a working Samba PDC is to
+understand the parameters necessary in smb.conf. I will not
+attempt to re-explain the parameters here as they are more that
+adequately covered in <ulink url="smb.conf.5.html"> the smb.conf
+man page</ulink>. For convenience, the parameters have been
+linked with the actual smb.conf description.
+</para>
+
+<para>
+Here is an example <filename>smb.conf</filename> for acting as a PDC:
+</para>
+
+<para><programlisting>
+[global]
+ ; Basic server settings
+ <ulink url="smb.conf.5.html#NETBIOSNAME">netbios name</ulink> = <replaceable>POGO</replaceable>
+ <ulink url="smb.conf.5.html#WORKGROUP">workgroup</ulink> = <replaceable>NARNIA</replaceable>
+
+ ; we should act as the domain and local master browser
+ <ulink url="smb.conf.5.html#OSLEVEL">os level</ulink> = 64
+ <ulink url="smb.conf.5.html#PERFERREDMASTER">preferred master</ulink> = yes
+ <ulink url="smb.conf.5.html#DOMAINMASTER">domain master</ulink> = yes
+ <ulink url="smb.conf.5.html#LOCALMASTER">local master</ulink> = yes
+
+ ; security settings (must user security = user)
+ <ulink url="smb.conf.5.html#SECURITYEQUALSUSER">security</ulink> = user
+
+ ; encrypted passwords are a requirement for a PDC
+ <ulink url="smb.conf.5.html#ENCRYPTPASSWORDS">encrypt passwords</ulink> = yes
+
+ ; support domain logons
+ <ulink url="smb.conf.5.html#DOMAINLOGONS">domain logons</ulink> = yes
+
+ ; where to store user profiles?
+ <ulink url="smb.conf.5.html#LOGONPATH">logon path</ulink> = \\%N\profiles\%u
+
+ ; where is a user's home directory and where should it
+ ; be mounted at?
+ <ulink url="smb.conf.5.html#LOGONDRIVE">logon drive</ulink> = H:
+ <ulink url="smb.conf.5.html#LOGONHOME">logon home</ulink> = \\homeserver\%u
+
+ ; specify a generic logon script for all users
+ ; this is a relative **DOS** path to the [netlogon] share
+ <ulink url="smb.conf.5.html#LOGONSCRIPT">logon script</ulink> = logon.cmd
+
+; necessary share for domain controller
+[netlogon]
+ <ulink url="smb.conf.5.html#PATH">path</ulink> = /usr/local/samba/lib/netlogon
+ <ulink url="smb.conf.5.html#READONLY">read only</ulink> = yes
+ <ulink url="smb.conf.5.html#WRITELIST">write list</ulink> = <replaceable>ntadmin</replaceable>
+
+; share for storing user profiles
+[profiles]
+ <ulink url="smb.conf.5.html#PATH">path</ulink> = /export/smb/ntprofile
+ <ulink url="smb.conf.5.html#READONLY">read only</ulink> = no
+ <ulink url="smb.conf.5.html#CREATEMASK">create mask</ulink> = 0600
+ <ulink url="smb.conf.5.html#DIRECTORYMASK">directory mask</ulink> = 0700
+</programlisting></para>
+
+<para>
+There are a couple of points to emphasize in the above configuration.
+</para>
+
+<itemizedlist>
+ <listitem><para>
+ Encrypted passwords must be enabled. For more details on how
+ to do this, refer to <ulink url="ENCRYPTION.html">ENCRYPTION.html</ulink>.
+ </para></listitem>
+
+ <listitem><para>
+ The server must support domain logons and a
+ <filename>[netlogon]</filename> share
+ </para></listitem>
+
+ <listitem><para>
+ The server must be the domain master browser in order for Windows
+ client to locate the server as a DC. Please refer to the various
+ Network Browsing documentation included with this distribution for
+ details.
+ </para></listitem>
+</itemizedlist>
+
+<para>
+As Samba 2.2 does not offer a complete implementation of group mapping
+between Windows NT groups and Unix groups (this is really quite
+complicated to explain in a short space), you should refer to the
+<ulink url="smb.conf.5.html#DOMAINADMINGROUP">domain admin
+group</ulink> smb.conf parameter for information of creating "Domain
+Admins" style accounts.
+</para>
+
+</sect1>
+
+
+<sect1>
+<title>Creating Machine Trust Accounts and Joining Clients to the
+Domain</title>
+
+<para>
+A machine trust account is a Samba account that is used to
+authenticate a client machine (rather than a user) to the Samba
+server. In Windows terminology, this is known as a "Computer
+Account."</para>
+
+<para>
+The password of a machine trust account acts as the shared secret for
+secure communication with the Domain Controller. This is a security
+feature to prevent an unauthorized machine with the same NetBIOS name
+from joining the domain and gaining access to domain user/group
+accounts. Windows NT and 2000 clients use machine trust accounts, but
+Windows 9x clients do not. Hence, a Windows 9x client is never a true
+member of a domain because it does not possess a machine trust
+account, and thus has no shared secret with the domain controller.
+</para>
+
+<para>A Windows PDC stores each machine trust account in the Windows
+Registry. A Samba PDC, however, stores each machine trust account
+in two parts, as follows:
+
+<itemizedlist>
+ <listitem><para>A Samba account, stored in the same location as user
+ LanMan and NT password hashes (currently
+ <filename>smbpasswd</filename>). The Samba account
+ possesses and uses only the NT password hash.</para></listitem>
+
+ <listitem><para>A corresponding Unix account, typically stored in
+ <filename>/etc/passwd</filename>. (Future releases will alleviate the need to
+ create <filename>/etc/passwd</filename> entries.) </para></listitem>
+</itemizedlist>
+</para>
+
+<para>
+There are two ways to create machine trust accounts:
+</para>
+
+<itemizedlist>
+ <listitem><para> Manual creation. Both the Samba and corresponding
+ Unix account are created by hand.</para></listitem>
+
+ <listitem><para> "On-the-fly" creation. The Samba machine trust
+ account is automatically created by Samba at the time the client
+ is joined to the domain. (For security, this is the
+ recommended method.) The corresponding Unix account may be
+ created automatically or manually. </para>
+ </listitem>
+
+</itemizedlist>
+
+<sect2>
+<title>Manual Creation of Machine Trust Accounts</title>
+
+<para>
+The first step in manually creating a machine trust account is to
+manually create the corresponding Unix account in
+<filename>/etc/passwd</filename>. This can be done using
+<command>vipw</command> or other 'add user' command that is normally
+used to create new Unix accounts. The following is an example for a
+Linux based Samba server:
+</para>
+
+<para>
+ <prompt>root# </prompt><command>/usr/sbin/useradd -g 100 -d /dev/null -c <replaceable>"machine
+nickname"</replaceable> -s /bin/false <replaceable>machine_name</replaceable>$ </command>
+</para>
+<para>
+<prompt>root# </prompt><command>passwd -l <replaceable>machine_name</replaceable>$</command>
+</para>
+
+<para>
+The <filename>/etc/passwd</filename> entry will list the machine name
+with a "$" appended, won't have a password, will have a null shell and no
+home directory. For example a machine named 'doppy' would have an
+<filename>/etc/passwd</filename> entry like this:
+</para>
+
+<para><programlisting>
+doppy$:x:505:501:<replaceable>machine_nickname</replaceable>:/dev/null:/bin/false
+</programlisting></para>
+
+<para>
+Above, <replaceable>machine_nickname</replaceable> can be any
+descriptive name for the client, i.e., BasementComputer.
+<replaceable>machine_name</replaceable> absolutely must be the NetBIOS
+name of the client to be joined to the domain. The "$" must be
+appended to the NetBIOS name of the client or Samba will not recognize
+this as a machine trust account.
+</para>
+
+
+<para>
+Now that the corresponding Unix account has been created, the next step is to create
+the Samba account for the client containing the well-known initial
+machine trust account password. This can be done using the <ulink
+url="smbpasswd.8.html"><command>smbpasswd(8)</command></ulink> command
+as shown here:
+</para>
+
+<para>
+<prompt>root# </prompt><command>smbpasswd -a -m <replaceable>machine_name</replaceable></command>
+</para>
+
+<para>
+where <replaceable>machine_name</replaceable> is the machine's NetBIOS
+name. The RID of the new machine account is generated from the UID of
+the corresponding Unix account.
+</para>
+
+<warning>
+ <title>Join the client to the domain immediately</title>
+
+ <para>
+ Manually creating a machine trust account using this method is the
+ equivalent of creating a machine trust account on a Windows NT PDC using
+ the "Server Manager". From the time at which the account is created
+ to the time which the client joins the domain and changes the password,
+ your domain is vulnerable to an intruder joining your domain using a
+ a machine with the same NetBIOS name. A PDC inherently trusts
+ members of the domain and will serve out a large degree of user
+ information to such clients. You have been warned!
+ </para>
+</warning>
+</sect2>
+
+
+<sect2>
+<title>"On-the-Fly" Creation of Machine Trust Accounts</title>
+
+<para>
+The second (and recommended) way of creating machine trust accounts is
+simply to allow the Samba server to create them as needed when the client
+is joined to the domain. </para>
+
+<para>Since each Samba machine trust account requires a corresponding
+Unix account, a method for automatically creating the
+Unix account is usually supplied; this requires configuration of the
+<ulink url="smb.conf.5.html#ADDUSERSCRIPT">add user script</ulink>
+option in <filename>smb.conf</filename>. This
+method is not required, however; corresponding Unix accounts may also
+be created manually.
+</para>
+
+
+<para>Below is an example for a RedHat 6.2 Linux system.
+</para>
+
+<para><programlisting>
+[global]
+ # <...remainder of parameters...>
+ add user script = /usr/sbin/useradd -d /dev/null -g 100 -s /bin/false -M %u
+</programlisting></para>
+
+</sect2>
+
+
+<sect2><title>Joining the Client to the Domain</title>
+
+<para>
+The procedure for joining a client to the domain varies with the
+version of Windows.
+</para>
+
+<itemizedlist>
+<listitem><para><emphasis>Windows 2000</emphasis></para>
+
+ <para> When the user elects to join the client to a domain, Windows prompts for
+ an account and password that is privileged to join the domain. A
+ Samba administrative account (i.e., a Samba account that has root
+ privileges on the Samba server) must be entered here; the
+ operation will fail if an ordinary user account is given.
+ The password for this account should be
+ set to a different password than the associated
+ <filename>/etc/passwd</filename> entry, for security
+ reasons. </para>
+
+ <para>The session key of the Samba administrative account acts as an
+ encryption key for setting the password of the machine trust
+ account. The machine trust account will be created on-the-fly, or
+ updated if it already exists.</para>
+</listitem>
+
+<listitem><para><emphasis>Windows NT</emphasis></para>
+
+ <para> If the machine trust account was created manually, on the
+ Identification Changes menu enter the domain name, but do not
+ check the box "Create a Computer Account in the Domain." In this case,
+ the existing machine trust account is used to join the machine to
+ the domain.</para>
+
+ <para> If the machine trust account is to be created
+ on-the-fly, on the Identification Changes menu enter the domain
+ name, and check the box "Create a Computer Account in the Domain." In
+ this case, joining the domain proceeds as above for Windows 2000
+ (i.e., you must supply a Samba administrative account when
+ prompted).</para>
+</listitem>
+</itemizedlist>
+
+</sect2>
+</sect1>
+<!-- **********************************************************
+
+ Common Problems
+
+*************************************************************** -->
+
+<sect1>
+<title>Common Problems and Errors</title>
+
+<para>
+</para>
+<itemizedlist>
+<listitem>
+ <para>
+ <emphasis>I cannot include a '$' in a machine name.</emphasis>
+ </para>
+
+ <para>
+ A 'machine name' in (typically) <filename>/etc/passwd</>
+ of the machine name with a '$' appended. FreeBSD (and other BSD
+ systems?) won't create a user with a '$' in their name.
+ </para>
+
+ <para>
+ The problem is only in the program used to make the entry, once
+ made, it works perfectly. So create a user without the '$' and
+ use <command>vipw</> to edit the entry, adding the '$'. Or create
+ the whole entry with vipw if you like, make sure you use a
+ unique User ID !
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>I get told "You already have a connection to the Domain...."
+ or "Cannot join domain, the credentials supplied conflict with an
+ existing set.." when creating a machine trust account.</emphasis>
+ </para>
+
+ <para>
+ This happens if you try to create a machine trust account from the
+ machine itself and already have a connection (e.g. mapped drive)
+ to a share (or IPC$) on the Samba PDC. The following command
+ will remove all network drive connections:
+ </para>
+
+ <para>
+ <prompt>C:\WINNT\></prompt> <command>net use * /d</command>
+ </para>
+
+ <para>
+ Further, if the machine is a already a 'member of a workgroup' that
+ is the same name as the domain you are joining (bad idea) you will
+ get this message. Change the workgroup name to something else, it
+ does not matter what, reboot, and try again.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>The system can not log you on (C000019B)....</emphasis>
+ </para>
+
+ <para>I joined the domain successfully but after upgrading
+ to a newer version of the Samba code I get the message, "The system
+ can not log you on (C000019B), Please try a gain or consult your
+ system administrator" when attempting to logon.
+ </para>
+
+ <para>
+ This occurs when the domain SID stored in
+ <filename>private/WORKGROUP.SID</filename> is
+ changed. For example, you remove the file and <command>smbd</command> automatically
+ creates a new one. Or you are swapping back and forth between
+ versions 2.0.7, TNG and the HEAD branch code (not recommended). The
+ only way to correct the problem is to restore the original domain
+ SID or remove the domain client from the domain and rejoin.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>The machine trust account for this computer either does not
+ exist or is not accessible.</emphasis>
+ </para>
+
+ <para>
+ When I try to join the domain I get the message "The machine account
+ for this computer either does not exist or is not accessible". What's
+ wrong?
+ </para>
+
+ <para>
+ This problem is caused by the PDC not having a suitable machine trust account.
+ If you are using the <parameter>add user script</parameter> method to create
+ accounts then this would indicate that it has not worked. Ensure the domain
+ admin user system is working.
+ </para>
+
+ <para>
+ Alternatively if you are creating account entries manually then they
+ have not been created correctly. Make sure that you have the entry
+ correct for the machine trust account in smbpasswd file on the Samba PDC.
+ If you added the account using an editor rather than using the smbpasswd
+ utility, make sure that the account name is the machine NetBIOS name
+ with a '$' appended to it ( i.e. computer_name$ ). There must be an entry
+ in both /etc/passwd and the smbpasswd file. Some people have reported
+ that inconsistent subnet masks between the Samba server and the NT
+ client have caused this problem. Make sure that these are consistent
+ for both client and server.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>When I attempt to login to a Samba Domain from a NT4/W2K workstation,
+ I get a message about my account being disabled.</emphasis>
+ </para>
+
+ <para>
+ This problem is caused by a PAM related bug in Samba 2.2.0. This bug is
+ fixed in 2.2.1. Other symptoms could be unaccessible shares on
+ NT/W2K member servers in the domain or the following error in your smbd.log:
+ passdb/pampass.c:pam_account(268) PAM: UNKNOWN ERROR for User: %user%
+ </para>
+
+ <para>
+ At first be ensure to enable the useraccounts with <command>smbpasswd -e
+ %user%</command>, this is normally done, when you create an account.
+ </para>
+
+ <para>
+ In order to work around this problem in 2.2.0, configure the
+ <parameter>account</parameter> control flag in
+ <filename>/etc/pam.d/samba</filename> file as follows:
+ </para>
+
+ <para><programlisting>
+ account required pam_permit.so
+ </programlisting></para>
+
+ <para>
+ If you want to remain backward compatibility to samba 2.0.x use
+ <filename>pam_permit.so</filename>, it's also possible to use
+ <filename>pam_pwdb.so</filename>. There are some bugs if you try to
+ use <filename>pam_unix.so</filename>, if you need this, be ensure to use
+ the most recent version of this file.
+ </para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+
+
+<!-- **********************************************************
+
+ Policies and Profiles
+
+*************************************************************** -->
+
+<sect1>
+<title>
+System Policies and Profiles
+</title>
+
+<para>
+Much of the information necessary to implement System Policies and
+Roving User Profiles in a Samba domain is the same as that for
+implementing these same items in a Windows NT 4.0 domain.
+You should read the white paper <ulink url="http://www.microsoft.com/ntserver/management/deployment/planguide/prof_policies.asp">Implementing
+Profiles and Policies in Windows NT 4.0</ulink> available from Microsoft.
+</para>
+
+<para>
+Here are some additional details:
+</para>
+
+<itemizedlist>
+
+<listitem>
+ <para>
+ <emphasis>What about Windows NT Policy Editor?</emphasis>
+ </para>
+
+ <para>
+ To create or edit <filename>ntconfig.pol</filename> you must use
+ the NT Server Policy Editor, <command>poledit.exe</command> which
+ is included with NT Server but <emphasis>not NT Workstation</emphasis>.
+ There is a Policy Editor on a NTws
+ but it is not suitable for creating <emphasis>Domain Policies</emphasis>.
+ Further, although the Windows 95
+ Policy Editor can be installed on an NT Workstation/Server, it will not
+ work with NT policies because the registry key that are set by the policy templates.
+ However, the files from the NT Server will run happily enough on an NTws.
+ You need <filename>poledit.exe, common.adm</> and <filename>winnt.adm</>. It is convenient
+ to put the two *.adm files in <filename>c:\winnt\inf</> which is where
+ the binary will look for them unless told otherwise. Note also that that
+ directory is 'hidden'.
+ </para>
+
+ <para>
+ The Windows NT policy editor is also included with the Service Pack 3 (and
+ later) for Windows NT 4.0. Extract the files using <command>servicepackname /x</command>,
+ i.e. that's <command>Nt4sp6ai.exe /x</command> for service pack 6a. The policy editor,
+ <command>poledit.exe</command> and the associated template files (*.adm) should
+ be extracted as well. It is also possible to downloaded the policy template
+ files for Office97 and get a copy of the policy editor. Another possible
+ location is with the Zero Administration Kit available for download from Microsoft.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ <emphasis>Can Win95 do Policies?</emphasis>
+ </para>
+
+ <para>
+ Install the group policy handler for Win9x to pick up group
+ policies. Look on the Win98 CD in <filename>\tools\reskit\netadmin\poledit</filename>.
+ Install group policies on a Win9x client by double-clicking
+ <filename>grouppol.inf</filename>. Log off and on again a couple of
+ times and see if Win98 picks up group policies. Unfortunately this needs
+ to be done on every Win9x machine that uses group policies....
+ </para>
+
+ <para>
+ If group policies don't work one reports suggests getting the updated
+ (read: working) grouppol.dll for Windows 9x. The group list is grabbed
+ from /etc/group.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ <emphasis>How do I get 'User Manager' and 'Server Manager'</emphasis>
+ </para>
+
+ <para>
+ Since I don't need to buy an NT Server CD now, how do I get
+ the 'User Manager for Domains', the 'Server Manager'?
+ </para>
+
+ <para>
+ Microsoft distributes a version of these tools called nexus for
+ installation on Windows 95 systems. The tools set includes
+ </para>
+
+ <itemizedlist>
+ <listitem><para>Server Manager</para></listitem>
+
+ <listitem><para>User Manager for Domains</para></listitem>
+
+ <listitem><para>Event Viewer</para></listitem>
+ </itemizedlist>
+
+ <para>
+ Click here to download the archived file <ulink
+ url="ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE">ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE</ulink>
+ </para>
+
+ <para>
+ The Windows NT 4.0 version of the 'User Manager for
+ Domains' and 'Server Manager' are available from Microsoft via ftp
+ from <ulink url="ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE">ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE</ulink>
+ </para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+
+
+<!-- **********************************************************
+
+ Getting Help
+
+*************************************************************** -->
+
+
+<sect1>
+<title>What other help can I get? </title>
+
+<para>
+There are many sources of information available in the form
+of mailing lists, RFC's and documentation. The docs that come
+with the samba distribution contain very good explanations of
+general SMB topics such as browsing.</para>
+
+<itemizedlist>
+<listitem>
+ <para>
+ <emphasis>What are some diagnostics tools I can use to debug the domain logon
+ process and where can I find them?</emphasis>
+ </para>
+
+ <para>
+ One of the best diagnostic tools for debugging problems is Samba itself.
+ You can use the -d option for both smbd and nmbd to specify what
+ 'debug level' at which to run. See the man pages on smbd, nmbd and
+ smb.conf for more information on debugging options. The debug
+ level can range from 1 (the default) to 10 (100 for debugging passwords).
+ </para>
+
+ <para>
+ Another helpful method of debugging is to compile samba using the
+ <command>gcc -g </command> flag. This will include debug
+ information in the binaries and allow you to attach gdb to the
+ running smbd / nmbd process. In order to attach gdb to an smbd
+ process for an NT workstation, first get the workstation to make the
+ connection. Pressing ctrl-alt-delete and going down to the domain box
+ is sufficient (at least, on the first time you join the domain) to
+ generate a 'LsaEnumTrustedDomains'. Thereafter, the workstation
+ maintains an open connection, and therefore there will be an smbd
+ process running (assuming that you haven't set a really short smbd
+ idle timeout) So, in between pressing ctrl alt delete, and actually
+ typing in your password, you can gdb attach and continue.
+ </para>
+
+ <para>
+ Some useful samba commands worth investigating:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>testparam | more</para></listitem>
+ <listitem><para>smbclient -L //{netbios name of server}</para></listitem>
+ </itemizedlist>
+
+ <para>
+ An SMB enabled version of tcpdump is available from
+ <ulink url="http://www.tcpdump.org/">http://www.tcpdup.org/</ulink>.
+ Ethereal, another good packet sniffer for Unix and Win32
+ hosts, can be downloaded from <ulink
+ url="http://www.ethereal.com/">http://www.ethereal.com</ulink>.
+ </para>
+
+ <para>
+ For tracing things on the Microsoft Windows NT, Network Monitor
+ (aka. netmon) is available on the Microsoft Developer Network CD's,
+ the Windows NT Server install CD and the SMS CD's. The version of
+ netmon that ships with SMS allows for dumping packets between any two
+ computers (i.e. placing the network interface in promiscuous mode).
+ The version on the NT Server install CD will only allow monitoring
+ of network traffic directed to the local NT box and broadcasts on the
+ local subnet. Be aware that Ethereal can read and write netmon
+ formatted files.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ <emphasis>How do I install 'Network Monitor' on an NT Workstation
+ or a Windows 9x box?</emphasis>
+ </para>
+
+ <para>
+ Installing netmon on an NT workstation requires a couple
+ of steps. The following are for installing Netmon V4.00.349, which comes
+ with Microsoft Windows NT Server 4.0, on Microsoft Windows NT
+ Workstation 4.0. The process should be similar for other version of
+ Windows NT / Netmon. You will need both the Microsoft Windows
+ NT Server 4.0 Install CD and the Workstation 4.0 Install CD.
+ </para>
+
+ <para>
+ Initially you will need to install 'Network Monitor Tools and Agent'
+ on the NT Server. To do this
+ </para>
+
+ <itemizedlist>
+ <listitem><para>Goto Start - Settings - Control Panel -
+ Network - Services - Add </para></listitem>
+
+ <listitem><para>Select the 'Network Monitor Tools and Agent' and
+ click on 'OK'.</para></listitem>
+
+ <listitem><para>Click 'OK' on the Network Control Panel.
+ </para></listitem>
+
+ <listitem><para>Insert the Windows NT Server 4.0 install CD
+ when prompted.</para></listitem>
+ </itemizedlist>
+
+ <para>
+ At this point the Netmon files should exist in
+ <filename>%SYSTEMROOT%\System32\netmon\*.*</filename>.
+ Two subdirectories exist as well, <filename>parsers\</filename>
+ which contains the necessary DLL's for parsing the netmon packet
+ dump, and <filename>captures\</filename>.
+ </para>
+
+ <para>
+ In order to install the Netmon tools on an NT Workstation, you will
+ first need to install the 'Network Monitor Agent' from the Workstation
+ install CD.
+ </para>
+
+ <itemizedlist>
+ <listitem><para>Goto Start - Settings - Control Panel -
+ Network - Services - Add</para></listitem>
+
+ <listitem><para>Select the 'Network Monitor Agent' and click
+ on 'OK'.</para></listitem>
+
+ <listitem><para>Click 'OK' on the Network Control Panel.
+ </para></listitem>
+
+ <listitem><para>Insert the Windows NT Workstation 4.0 install
+ CD when prompted.</para></listitem>
+ </itemizedlist>
+
+
+ <para>
+ Now copy the files from the NT Server in %SYSTEMROOT%\System32\netmon\*.*
+ to %SYSTEMROOT%\System32\netmon\*.* on the Workstation and set
+ permissions as you deem appropriate for your site. You will need
+ administrative rights on the NT box to run netmon.
+ </para>
+
+ <para>
+ To install Netmon on a Windows 9x box install the network monitor agent
+ from the Windows 9x CD (\admin\nettools\netmon). There is a readme
+ file located with the netmon driver files on the CD if you need
+ information on how to do this. Copy the files from a working
+ Netmon installation.
+ </para>
+</listitem>
+
+
+
+
+<listitem>
+ <para>
+ The following is a list if helpful URLs and other links:
+ </para>
+
+ <itemizedlist>
+
+ <listitem><para>Home of Samba site <ulink url="http://samba.org">
+ http://samba.org</ulink>. We have a mirror near you !</para></listitem>
+
+ <listitem><para> The <emphasis>Development</emphasis> document
+ on the Samba mirrors might mention your problem. If so,
+ it might mean that the developers are working on it.</para></listitem>
+
+ <listitem><para>See how Scott Merrill simulates a BDC behavior at
+ <ulink url="http://www.skippy.net/linux/smb-howto.html">
+ http://www.skippy.net/linux/smb-howto.html</>. </para></listitem>
+
+ <listitem><para>Although 2.0.7 has almost had its day as a PDC, David Bannon will
+ keep the 2.0.7 PDC pages at <ulink url="http://bioserve.latrobe.edu.au/samba">
+ http://bioserve.latrobe.edu.au/samba</ulink> going for a while yet.</para></listitem>
+
+ <listitem><para>Misc links to CIFS information
+ <ulink url="http://samba.org/cifs/">http://samba.org/cifs/</ulink></para></listitem>
+
+ <listitem><para>NT Domains for Unix <ulink url="http://mailhost.cb1.com/~lkcl/ntdom/">
+ http://mailhost.cb1.com/~lkcl/ntdom/</ulink></para></listitem>
+
+ <listitem><para>FTP site for older SMB specs:
+ <ulink url="ftp://ftp.microsoft.com/developr/drg/CIFS/">
+ ftp://ftp.microsoft.com/developr/drg/CIFS/</ulink></para></listitem>
+
+ </itemizedlist>
+</listitem>
+</itemizedlist>
+
+
+<itemizedlist>
+<listitem>
+ <para>
+ <emphasis>How do I get help from the mailing lists?</emphasis>
+ </para>
+
+ <para>
+ There are a number of Samba related mailing lists. Go to <ulink
+ url="http://samba.org">http://samba.org</ulink>, click on your nearest mirror
+ and then click on <command>Support</> and then click on <command>
+ Samba related mailing lists</>.
+ </para>
+
+ <para>
+ For questions relating to Samba TNG go to
+ <ulink url="http://www.samba-tng.org/">http://www.samba-tng.org/</ulink>
+ It has been requested that you don't post questions about Samba-TNG to the
+ main stream Samba lists.</para>
+
+ <para>
+ If you post a message to one of the lists please observe the following guide lines :
+ </para>
+
+ <itemizedlist>
+
+ <listitem><para> Always remember that the developers are volunteers, they are
+ not paid and they never guarantee to produce a particular feature at
+ a particular time. Any time lines are 'best guess' and nothing more.
+ </para></listitem>
+
+ <listitem><para> Always mention what version of samba you are using and what
+ operating system its running under. You should probably list the
+ relevant sections of your smb.conf file, at least the options
+ in [global] that affect PDC support.</para></listitem>
+
+ <listitem><para>In addition to the version, if you obtained Samba via
+ CVS mention the date when you last checked it out.</para></listitem>
+
+ <listitem><para> Try and make your question clear and brief, lots of long,
+ convoluted questions get deleted before they are completely read !
+ Don't post html encoded messages (if you can select colour or font
+ size its html).</para></listitem>
+
+ <listitem><para> If you run one of those nifty 'I'm on holidays' things when
+ you are away, make sure its configured to not answer mailing lists.
+ </para></listitem>
+
+ <listitem><para> Don't cross post. Work out which is the best list to post to
+ and see what happens, i.e. don't post to both samba-ntdom and samba-technical.
+ Many people active on the lists subscribe to more
+ than one list and get annoyed to see the same message two or more times.
+ Often someone will see a message and thinking it would be better dealt
+ with on another, will forward it on for you.</para></listitem>
+
+ <listitem><para>You might include <emphasis>partial</emphasis>
+ log files written at a debug level set to as much as 20.
+ Please don't send the entire log but enough to give the context of the
+ error messages.</para></listitem>
+
+ <listitem><para>(Possibly) If you have a complete netmon trace ( from the opening of
+ the pipe to the error ) you can send the *.CAP file as well.</para></listitem>
+
+ <listitem><para>Please think carefully before attaching a document to an email.
+ Consider pasting the relevant parts into the body of the message. The samba
+ mailing lists go to a huge number of people, do they all need a copy of your
+ smb.conf in their attach directory?</para></listitem>
+
+ </itemizedlist>
+</listitem>
+
+
+<listitem>
+ <para>
+ <emphasis>How do I get off the mailing lists?</emphasis>
+ </para>
+
+ <para>To have your name removed from a samba mailing list, go to the
+ same place you went to to get on it. Go to <ulink
+ url="http://lists.samba.org/">http://lists.samba.org</ulink>,
+ click on your nearest mirror and then click on <command>Support</> and
+ then click on <command> Samba related mailing lists</>. Or perhaps see
+ <ulink url="http://lists.samba.org/mailman/roster/samba-ntdom">here</ulink>
+ </para>
+
+ <para>
+ Please don't post messages to the list asking to be removed, you will just
+ be referred to the above address (unless that process failed in some way...)
+ </para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+
+<!-- **********************************************************
+
+ Windows 9x domain control
+
+*************************************************************** -->
+<sect1>
+<title>Domain Control for Windows 9x/ME</title>
+
+<note>
+<para>
+The following section contains much of the original
+DOMAIN.txt file previously included with Samba. Much of
+the material is based on what went into the book <emphasis>Special
+Edition, Using Samba</emphasis>, by Richard Sharpe.
+</para>
+</note>
+
+<para>
+A domain and a workgroup are exactly the same thing in terms of network
+browsing. The difference is that a distributable authentication
+database is associated with a domain, for secure login access to a
+network. Also, different access rights can be granted to users if they
+successfully authenticate against a domain logon server (NT server and
+other systems based on NT server support this, as does at least Samba TNG now).
+</para>
+
+<para>
+The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+Network browsing functionality of domains and workgroups is
+identical and is explained in BROWSING.txt. It should be noted, that browsing
+is totally orthogonal to logon support.
+</para>
+
+<para>
+Issues related to the single-logon network model are discussed in this
+section. Samba supports domain logons, network logon scripts, and user
+profiles for MS Windows for workgroups and MS Windows 9X/ME clients
+which will be the focus of this section.
+</para>
+
+
+<para>
+When an SMB client in a domain wishes to logon it broadcast requests for a
+logon server. The first one to reply gets the job, and validates its
+password using whatever mechanism the Samba administrator has installed.
+It is possible (but very stupid) to create a domain where the user
+database is not shared between servers, i.e. they are effectively workgroup
+servers advertising themselves as participating in a domain. This
+demonstrates how authentication is quite different from but closely
+involved with domains.
+</para>
+
+
+<para>
+Using these features you can make your clients verify their logon via
+the Samba server; make clients run a batch file when they logon to
+the network and download their preferences, desktop and start menu.
+</para>
+
+<para>
+Before launching into the configuration instructions, it is
+worthwhile lookingat how a Windows 9x/ME client performs a logon:
+</para>
+
+<orderedlist>
+<listitem>
+ <para>
+ The client broadcasts (to the IP broadcast address of the subnet it is in)
+ a NetLogon request. This is sent to the NetBIOS name DOMAIN<1c> at the
+ NetBIOS layer. The client chooses the first response it receives, which
+ contains the NetBIOS name of the logon server to use in the format of
+ \\SERVER.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then connects to that server, logs on (does an SMBsessetupX) and
+ then connects to the IPC$ share (using an SMBtconX).
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then does a NetWkstaUserLogon request, which retrieves the name
+ of the user's logon script.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then connects to the NetLogon share and searches for this
+ and if it is found and can be read, is retrieved and executed by the client.
+ After this, the client disconnects from the NetLogon share.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then sends a NetUserGetInfo request to the server, to retrieve
+ the user's home share, which is used to search for profiles. Since the
+ response to the NetUserGetInfo request does not contain much more
+ the user's home share, profiles for Win9X clients MUST reside in the user
+ home directory.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then connects to the user's home share and searches for the
+ user's profile. As it turns out, you can specify the user's home share as
+ a sharename and path. For example, \\server\fred\.profile.
+ If the profiles are found, they are implemented.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ The client then disconnects from the user's home share, and reconnects to
+ the NetLogon share and looks for CONFIG.POL, the policies file. If this is
+ found, it is read and implemented.
+ </para>
+</listitem>
+</orderedlist>
+
+
+<sect2>
+<title>Configuration Instructions: Network Logons</title>
+
+<para>
+The main difference between a PDC and a Windows 9x logon
+server configuration is that
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+Password encryption is not required for a Windows 9x logon server.
+</para></listitem>
+
+<listitem><para>
+Windows 9x/ME clients do not possess machine trust accounts.
+</para></listitem>
+
+</itemizedlist>
+
+<para>
+Therefore, a Samba PDC will also act as a Windows 9x logon
+server.
+</para>
+
+
+<warning>
+<title>security mode and master browsers</title>
+
+<para>
+There are a few comments to make in order to tie up some
+loose ends. There has been much debate over the issue of whether
+or not it is ok to configure Samba as a Domain Controller in security
+modes other than <constant>USER</constant>. The only security mode
+which will not work due to technical reasons is <constant>SHARE</constant>
+mode security. <constant>DOMAIN</constant> and <constant>SERVER</constant>
+mode security is really just a variation on SMB user level security.
+</para>
+
+<para>
+Actually, this issue is also closely tied to the debate on whether
+or not Samba must be the domain master browser for its workgroup
+when operating as a DC. While it may technically be possible
+to configure a server as such (after all, browsing and domain logons
+are two distinctly different functions), it is not a good idea to
+so. You should remember that the DC must register the DOMAIN#1b NetBIOS
+name. This is the name used by Windows clients to locate the DC.
+Windows clients do not distinguish between the DC and the DMB.
+For this reason, it is very wise to configure the Samba DC as the DMB.
+</para>
+
+<para>
+Now back to the issue of configuring a Samba DC to use a mode other
+than "security = user". If a Samba host is configured to use
+another SMB server or DC in order to validate user connection
+requests, then it is a fact that some other machine on the network
+(the "password server") knows more about user than the Samba host.
+99% of the time, this other host is a domain controller. Now
+in order to operate in domain mode security, the "workgroup" parameter
+must be set to the name of the Windows NT domain (which already
+has a domain controller, right?)
+</para>
+
+<para>
+Therefore configuring a Samba box as a DC for a domain that
+already by definition has a PDC is asking for trouble.
+Therefore, you should always configure the Samba DC to be the DMB
+for its domain.
+</para>
+</warning>
+
+</sect2>
+
+
+<sect2>
+<title>Configuration Instructions: Setting up Roaming User Profiles</title>
+
+<warning>
+<para>
+<emphasis>NOTE!</emphasis> Roaming profiles support is different
+for Win9X and WinNT.
+</para>
+</warning>
+
+<para>
+Before discussing how to configure roaming profiles, it is useful to see how
+Win9X and WinNT clients implement these features.
+</para>
+
+<para>
+Win9X clients send a NetUserGetInfo request to the server to get the user's
+profiles location. However, the response does not have room for a separate
+profiles location field, only the user's home share. This means that Win9X
+profiles are restricted to being in the user's home directory.
+</para>
+
+
+<para>
+WinNT clients send a NetSAMLogon RPC request, which contains many fields,
+including a separate field for the location of the user's profiles.
+This means that support for profiles is different for Win9X and WinNT.
+</para>
+
+
+
+<sect3>
+<title>Windows NT Configuration</title>
+
+<para>
+To support WinNT clients, in the [global] section of smb.conf set the
+following (for example):
+</para>
+
+<para><programlisting>
+logon path = \\profileserver\profileshare\profilepath\%U\moreprofilepath
+</programlisting></para>
+
+<para>
+The default for this option is \\%N\%U\profile, namely
+\\sambaserver\username\profile. The \\N%\%U service is created
+automatically by the [homes] service.
+If you are using a samba server for the profiles, you _must_ make the
+share specified in the logon path browseable.
+</para>
+
+<note>
+<para>
+[lkcl 26aug96 - we have discovered a problem where Windows clients can
+maintain a connection to the [homes] share in between logins. The
+[homes] share must NOT therefore be used in a profile path.]
+</para>
+</note>
+
+</sect3>
+
+
+<sect3>
+<title>Windows 9X Configuration</title>
+
+<para>
+To support Win9X clients, you must use the "logon home" parameter. Samba has
+now been fixed so that "net use/home" now works as well, and it, too, relies
+on the "logon home" parameter.
+</para>
+
+<para>
+By using the logon home parameter, you are restricted to putting Win9X
+profiles in the user's home directory. But wait! There is a trick you
+can use. If you set the following in the [global] section of your
+smb.conf file:
+</para>
+
+<para><programlisting>
+logon home = \\%L\%U\.profiles
+</programlisting></para>
+
+<para>
+then your Win9X clients will dutifully put their clients in a subdirectory
+of your home directory called .profiles (thus making them hidden).
+</para>
+
+<para>
+Not only that, but 'net use/home' will also work, because of a feature in
+Win9X. It removes any directory stuff off the end of the home directory area
+and only uses the server and share portion. That is, it looks like you
+specified \\%L\%U for "logon home".
+</para>
+
+
+</sect3>
+
+
+<sect3>
+<title>Win9X and WinNT Configuration</title>
+
+<para>
+You can support profiles for both Win9X and WinNT clients by setting both the
+"logon home" and "logon path" parameters. For example:
+</para>
+
+<para><programlisting>
+logon home = \\%L\%U\.profiles
+logon path = \\%L\profiles\%U
+</programlisting></para>
+
+<note>
+<para>
+I have not checked what 'net use /home' does on NT when "logon home" is
+set as above.
+</para>
+</note>
+</sect3>
+
+
+
+<sect3>
+<title>Windows 9X Profile Setup</title>
+
+<para>
+When a user first logs in on Windows 9X, the file user.DAT is created,
+as are folders "Start Menu", "Desktop", "Programs" and "Nethood".
+These directories and their contents will be merged with the local
+versions stored in c:\windows\profiles\username on subsequent logins,
+taking the most recent from each. You will need to use the [global]
+options "preserve case = yes", "short preserve case = yes" and
+"case sensitive = no" in order to maintain capital letters in shortcuts
+in any of the profile folders.
+</para>
+
+
+<para>
+The user.DAT file contains all the user's preferences. If you wish to
+enforce a set of preferences, rename their user.DAT file to user.MAN,
+and deny them write access to this file.
+</para>
+
+<orderedlist>
+<listitem>
+ <para>
+ On the Windows 95 machine, go to Control Panel | Passwords and
+ select the User Profiles tab. Select the required level of
+ roaming preferences. Press OK, but do _not_ allow the computer
+ to reboot.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ On the Windows 95 machine, go to Control Panel | Network |
+ Client for Microsoft Networks | Preferences. Select 'Log on to
+ NT Domain'. Then, ensure that the Primary Logon is 'Client for
+ Microsoft Networks'. Press OK, and this time allow the computer
+ to reboot.
+ </para>
+</listitem>
+
+</orderedlist>
+
+<para>
+Under Windows 95, Profiles are downloaded from the Primary Logon.
+If you have the Primary Logon as 'Client for Novell Networks', then
+the profiles and logon script will be downloaded from your Novell
+Server. If you have the Primary Logon as 'Windows Logon', then the
+profiles will be loaded from the local machine - a bit against the
+concept of roaming profiles, if you ask me.
+</para>
+
+<para>
+You will now find that the Microsoft Networks Login box contains
+[user, password, domain] instead of just [user, password]. Type in
+the samba server's domain name (or any other domain known to exist,
+but bear in mind that the user will be authenticated against this
+domain and profiles downloaded from it, if that domain logon server
+supports it), user name and user's password.
+</para>
+
+<para>
+Once the user has been successfully validated, the Windows 95 machine
+will inform you that 'The user has not logged on before' and asks you
+if you wish to save the user's preferences? Select 'yes'.
+</para>
+
+<para>
+Once the Windows 95 client comes up with the desktop, you should be able
+to examine the contents of the directory specified in the "logon path"
+on the samba server and verify that the "Desktop", "Start Menu",
+"Programs" and "Nethood" folders have been created.
+</para>
+
+<para>
+These folders will be cached locally on the client, and updated when
+the user logs off (if you haven't made them read-only by then :-).
+You will find that if the user creates further folders or short-cuts,
+that the client will merge the profile contents downloaded with the
+contents of the profile directory already on the local client, taking
+the newest folders and short-cuts from each set.
+</para>
+
+<para>
+If you have made the folders / files read-only on the samba server,
+then you will get errors from the w95 machine on logon and logout, as
+it attempts to merge the local and the remote profile. Basically, if
+you have any errors reported by the w95 machine, check the Unix file
+permissions and ownership rights on the profile directory contents,
+on the samba server.
+</para>
+
+<para>
+If you have problems creating user profiles, you can reset the user's
+local desktop cache, as shown below. When this user then next logs in,
+they will be told that they are logging in "for the first time".
+</para>
+
+<orderedlist>
+<listitem>
+ <para>
+ instead of logging in under the [user, password, domain] dialog,
+ press escape.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ run the regedit.exe program, and look in:
+ </para>
+
+ <para>
+ HKEY_LOCAL_MACHINE\Windows\CurrentVersion\ProfileList
+ </para>
+
+ <para>
+ you will find an entry, for each user, of ProfilePath. Note the
+ contents of this key (likely to be c:\windows\profiles\username),
+ then delete the key ProfilePath for the required user.
+ </para>
+
+ <para>
+ [Exit the registry editor].
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>WARNING</emphasis> - before deleting the contents of the
+ directory listed in
+ the ProfilePath (this is likely to be c:\windows\profiles\username),
+ ask them if they have any important files stored on their desktop
+ or in their start menu. delete the contents of the directory
+ ProfilePath (making a backup if any of the files are needed).
+ </para>
+
+ <para>
+ This will have the effect of removing the local (read-only hidden
+ system file) user.DAT in their profile directory, as well as the
+ local "desktop", "nethood", "start menu" and "programs" folders.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ search for the user's .PWL password-caching file in the c:\windows
+ directory, and delete it.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ log off the windows 95 client.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ check the contents of the profile path (see "logon path" described
+ above), and delete the user.DAT or user.MAN file for the user,
+ making a backup if required.
+ </para>
+</listitem>
+
+</orderedlist>
+
+<para>
+If all else fails, increase samba's debug log levels to between 3 and 10,
+and / or run a packet trace program such as tcpdump or netmon.exe, and
+look for any error reports.
+</para>
+
+<para>
+If you have access to an NT server, then first set up roaming profiles
+and / or netlogons on the NT server. Make a packet trace, or examine
+the example packet traces provided with NT server, and see what the
+differences are with the equivalent samba trace.
+</para>
+
+</sect3>
+
+
+<sect3>
+<title>Windows NT Workstation 4.0</title>
+
+<para>
+When a user first logs in to a Windows NT Workstation, the profile
+NTuser.DAT is created. The profile location can be now specified
+through the "logon path" parameter.
+</para>
+
+<note>
+<para>
+[lkcl 10aug97 - i tried setting the path to
+\\samba-server\homes\profile, and discovered that this fails because
+a background process maintains the connection to the [homes] share
+which does _not_ close down in between user logins. you have to
+have \\samba-server\%L\profile, where user is the username created
+from the [homes] share].
+</para>
+</note>
+
+<para>
+There is a parameter that is now available for use with NT Profiles:
+"logon drive". This should be set to "h:" or any other drive, and
+should be used in conjunction with the new "logon home" parameter.
+</para>
+
+<para>
+The entry for the NT 4.0 profile is a _directory_ not a file. The NT
+help on profiles mentions that a directory is also created with a .PDS
+extension. The user, while logging in, must have write permission to
+create the full profile path (and the folder with the .PDS extension)
+[lkcl 10aug97 - i found that the creation of the .PDS directory failed,
+and had to create these manually for each user, with a shell script.
+also, i presume, but have not tested, that the full profile path must
+be browseable just as it is for w95, due to the manner in which they
+attempt to create the full profile path: test existence of each path
+component; create path component].
+</para>
+
+<para>
+In the profile directory, NT creates more folders than 95. It creates
+"Application Data" and others, as well as "Desktop", "Nethood",
+"Start Menu" and "Programs". The profile itself is stored in a file
+NTuser.DAT. Nothing appears to be stored in the .PDS directory, and
+its purpose is currently unknown.
+</para>
+
+<para>
+You can use the System Control Panel to copy a local profile onto
+a samba server (see NT Help on profiles: it is also capable of firing
+up the correct location in the System Control Panel for you). The
+NT Help file also mentions that renaming NTuser.DAT to NTuser.MAN
+turns a profile into a mandatory one.
+</para>
+
+<note>
+<para>
+[lkcl 10aug97 - i notice that NT Workstation tells me that it is
+downloading a profile from a slow link. whether this is actually the
+case, or whether there is some configuration issue, as yet unknown,
+that makes NT Workstation _think_ that the link is a slow one is a
+matter to be resolved].
+</para>
+
+<para>
+[lkcl 20aug97 - after samba digest correspondence, one user found, and
+another confirmed, that profiles cannot be loaded from a samba server
+unless "security = user" and "encrypt passwords = yes" (see the file
+ENCRYPTION.txt) or "security = server" and "password server = ip.address.
+of.yourNTserver" are used. Either of these options will allow the NT
+workstation to access the samba server using LAN manager encrypted
+passwords, without the user intervention normally required by NT
+workstation for clear-text passwords].
+</para>
+
+<para>
+[lkcl 25aug97 - more comments received about NT profiles: the case of
+the profile _matters_. the file _must_ be called NTuser.DAT or, for
+a mandatory profile, NTuser.MAN].
+</para>
+</note>
+
+</sect3>
+
+
+<sect3>
+<title>Windows NT Server</title>
+
+<para>
+There is nothing to stop you specifying any path that you like for the
+location of users' profiles. Therefore, you could specify that the
+profile be stored on a samba server, or any other SMB server, as long as
+that SMB server supports encrypted passwords.
+</para>
+
+</sect3>
+
+
+<sect3>
+<title>Sharing Profiles between W95 and NT Workstation 4.0</title>
+
+<warning>
+<title>Potentially outdated or incorrect material follows</title>
+<para>
+I think this is all bogus, but have not deleted it. (Richard Sharpe)
+</para>
+</warning>
+
+<para>
+The default logon path is \\%N\U%. NT Workstation will attempt to create
+a directory "\\samba-server\username.PDS" if you specify the logon path
+as "\\samba-server\username" with the NT User Manager. Therefore, you
+will need to specify (for example) "\\samba-server\username\profile".
+NT 4.0 will attempt to create "\\samba-server\username\profile.PDS", which
+is more likely to succeed.
+</para>
+
+<para>
+If you then want to share the same Start Menu / Desktop with W95, you will
+need to specify "logon path = \\samba-server\username\profile" [lkcl 10aug97
+this has its drawbacks: i created a shortcut to telnet.exe, which attempts
+to run from the c:\winnt\system32 directory. this directory is obviously
+unlikely to exist on a Win95-only host].
+</para>
+
+<para>
+
+If you have this set up correctly, you will find separate user.DAT and
+NTuser.DAT files in the same profile directory.
+</para>
+
+<note>
+<para>
+[lkcl 25aug97 - there are some issues to resolve with downloading of
+NT profiles, probably to do with time/date stamps. i have found that
+NTuser.DAT is never updated on the workstation after the first time that
+it is copied to the local workstation profile directory. this is in
+contrast to w95, where it _does_ transfer / update profiles correctly].
+</para>
+</note>
+
+</sect3>
+
+</sect2>
+</sect1>
+
+
+<!-- **********************************************************
+
+ Appendix - DOMAIN_CONTROL.txt
+
+*************************************************************** -->
+
+<sect1>
+<title>
+DOMAIN_CONTROL.txt : Windows NT Domain Control & Samba
+</title>
+
+<warning>
+ <title>Possibly Outdated Material</title>
+
+ <para>
+ This appendix was originally authored by John H Terpstra of
+ the Samba Team and is included here for posterity.
+ </para>
+</warning>
+
+
+<para>
+<emphasis>NOTE :</emphasis>
+The term "Domain Controller" and those related to it refer to one specific
+method of authentication that can underly an SMB domain. Domain Controllers
+prior to Windows NT Server 3.1 were sold by various companies and based on
+private extensions to the LAN Manager 2.1 protocol. Windows NT introduced
+Microsoft-specific ways of distributing the user authentication database.
+See DOMAIN.txt for examples of how Samba can participate in or create
+SMB domains based on shared authentication database schemes other than the
+Windows NT SAM.
+</para>
+
+<para>
+Windows NT Server can be installed as either a plain file and print server
+(WORKGROUP workstation or server) or as a server that participates in Domain
+Control (DOMAIN member, Primary Domain controller or Backup Domain controller).
+The same is true for OS/2 Warp Server, Digital Pathworks and other similar
+products, all of which can participate in Domain Control along with Windows NT.
+</para>
+
+<para>
+To many people these terms can be confusing, so let's try to clear the air.
+</para>
+
+<para>
+Every Windows NT system (workstation or server) has a registry database.
+The registry contains entries that describe the initialization information
+for all services (the equivalent of Unix Daemons) that run within the Windows
+NT environment. The registry also contains entries that tell application
+software where to find dynamically loadable libraries that they depend upon.
+In fact, the registry contains entries that describes everything that anything
+may need to know to interact with the rest of the system.
+</para>
+
+<para>
+The registry files can be located on any Windows NT machine by opening a
+command prompt and typing:
+</para>
+
+<para>
+<prompt>C:\WINNT\></prompt> dir %SystemRoot%\System32\config
+</para>
+
+<para>
+The environment variable %SystemRoot% value can be obtained by typing:
+</para>
+
+<para>
+<prompt>C:\WINNT></prompt>echo %SystemRoot%
+</para>
+
+<para>
+The active parts of the registry that you may want to be familiar with are
+the files called: default, system, software, sam and security.
+</para>
+
+<para>
+In a domain environment, Microsoft Windows NT domain controllers participate
+in replication of the SAM and SECURITY files so that all controllers within
+the domain have an exactly identical copy of each.
+</para>
+
+<para>
+The Microsoft Windows NT system is structured within a security model that
+says that all applications and services must authenticate themselves before
+they can obtain permission from the security manager to do what they set out
+to do.
+</para>
+
+<para>
+The Windows NT User database also resides within the registry. This part of
+the registry contains the user's security identifier, home directory, group
+memberships, desktop profile, and so on.
+</para>
+
+<para>
+Every Windows NT system (workstation as well as server) will have its own
+registry. Windows NT Servers that participate in Domain Security control
+have a database that they share in common - thus they do NOT own an
+independent full registry database of their own, as do Workstations and
+plain Servers.
+</para>
+
+<para>
+The User database is called the SAM (Security Access Manager) database and
+is used for all user authentication as well as for authentication of inter-
+process authentication (i.e. to ensure that the service action a user has
+requested is permitted within the limits of that user's privileges).
+</para>
+
+<para>
+The Samba team have produced a utility that can dump the Windows NT SAM into
+smbpasswd format: see ENCRYPTION.txt for information on smbpasswd and
+/pub/samba/pwdump on your nearest Samba mirror for the utility. This
+facility is useful but cannot be easily used to implement SAM replication
+to Samba systems.
+</para>
+
+<para>
+Windows for Workgroups, Windows 95, and Windows NT Workstations and Servers
+can participate in a Domain security system that is controlled by Windows NT
+servers that have been correctly configured. Almost every domain will have
+ONE Primary Domain Controller (PDC). It is desirable that each domain will
+have at least one Backup Domain Controller (BDC).
+</para>
+
+<para>
+The PDC and BDCs then participate in replication of the SAM database so that
+each Domain Controlling participant will have an up to date SAM component
+within its registry.
+</para>
+
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/projdoc/UNIX_INSTALL.sgml b/docs/docbook/projdoc/UNIX_INSTALL.sgml
new file mode 100644
index 00000000000..ee91f6e07aa
--- /dev/null
+++ b/docs/docbook/projdoc/UNIX_INSTALL.sgml
@@ -0,0 +1,451 @@
+<chapter id="install">
+
+<title>How to Install and Test SAMBA</title>
+
+<sect1>
+ <title>Step 0: Read the man pages</title>
+
+ <para>The man pages distributed with SAMBA contain
+ lots of useful info that will help to get you started.
+ If you don't know how to read man pages then try
+ something like:</para>
+
+ <para><prompt>$ </prompt><userinput>nroff -man smbd.8 | more
+ </userinput></para>
+
+ <para>Other sources of information are pointed to
+ by the Samba web site,<ulink url="http://www.samba.org/">
+ http://www.samba.org</ulink></para>
+</sect1>
+
+<sect1>
+ <title>Step 1: Building the Binaries</title>
+
+ <para>To do this, first run the program <command>./configure
+ </command> in the source directory. This should automatically
+ configure Samba for your operating system. If you have unusual
+ needs then you may wish to run</para>
+
+ <para><prompt>root# </prompt><userinput>./configure --help
+ </userinput></para>
+
+ <para>first to see what special options you can enable.
+ Then executing</para>
+
+ <para><prompt>root# </prompt><userinput>make</userinput></para>
+
+ <para>will create the binaries. Once it's successfully
+ compiled you can use </para>
+
+ <para><prompt>root# </prompt><userinput>make install</userinput></para>
+
+ <para>to install the binaries and manual pages. You can
+ separately install the binaries and/or man pages using</para>
+
+ <para><prompt>root# </prompt><userinput>make installbin
+ </userinput></para>
+
+ <para>and</para>
+
+ <para><prompt>root# </prompt><userinput>make installman
+ </userinput></para>
+
+ <para>Note that if you are upgrading for a previous version
+ of Samba you might like to know that the old versions of
+ the binaries will be renamed with a ".old" extension. You
+ can go back to the previous version with</para>
+
+ <para><prompt>root# </prompt><userinput>make revert
+ </userinput></para>
+
+ <para>if you find this version a disaster!</para>
+</sect1>
+
+<sect1>
+ <title>Step 2: The all important step</title>
+
+ <para>At this stage you must fetch yourself a
+ coffee or other drink you find stimulating. Getting the rest
+ of the install right can sometimes be tricky, so you will
+ probably need it.</para>
+
+ <para>If you have installed samba before then you can skip
+ this step.</para>
+</sect1>
+
+<sect1>
+ <title>Step 3: Create the smb configuration file. </title>
+
+ <para>There are sample configuration files in the examples
+ subdirectory in the distribution. I suggest you read them
+ carefully so you can see how the options go together in
+ practice. See the man page for all the options.</para>
+
+ <para>The simplest useful configuration file would be
+ something like this:</para>
+
+ <para><programlisting>
+ [global]
+ workgroup = MYGROUP
+
+ [homes]
+ guest ok = no
+ read only = no
+ </programlisting</para>
+
+ <para>which would allow connections by anyone with an
+ account on the server, using either their login name or
+ "homes" as the service name. (Note that I also set the
+ workgroup that Samba is part of. See BROWSING.txt for details)</para>
+
+ <para>Note that <command>make install</command> will not install
+ a <filename>smb.conf</filename> file. You need to create it
+ yourself. </para>
+
+ <para>Make sure you put the smb.conf file in the same place
+ you specified in the<filename>Makefile</filename> (the default is to
+ look for it in <filename>/usr/local/samba/lib/</filename>).</para>
+
+ <para>For more information about security settings for the
+ [homes] share please refer to the document UNIX_SECURITY.txt.</para>
+</sect1>
+
+<sect1>
+ <title>Step 4: Test your config file with
+ <command>testparm</command></title>
+
+ <para>It's important that you test the validity of your
+ <filename>smb.conf</filename> file using the testparm program.
+ If testparm runs OK then it will list the loaded services. If
+ not it will give an error message.</para>
+
+ <para>Make sure it runs OK and that the services look
+ reasonable before proceeding. </para>
+
+</sect1>
+
+<sect1>
+ <title>Step 5: Starting the smbd and nmbd</title>
+
+ <para>You must choose to start smbd and nmbd either
+ as daemons or from <command>inetd</command>. Don't try
+ to do both! Either you can put them in <filename>
+ inetd.conf</filename> and have them started on demand
+ by <command>inetd</command>, or you can start them as
+ daemons either from the command line or in <filename>
+ /etc/rc.local</filename>. See the man pages for details
+ on the command line options. Take particular care to read
+ the bit about what user you need to be in order to start
+ Samba. In many cases you must be root.</para>
+
+ <para>The main advantage of starting <command>smbd</command>
+ and <command>nmbd</command> as a daemon is that they will
+ respond slightly more quickly to an initial connection
+ request. This is, however, unlikely to be a problem.</para>
+
+ <sect2>
+ <title>Step 5a: Starting from inetd.conf</title>
+
+ <para>NOTE; The following will be different if
+ you use NIS or NIS+ to distributed services maps.</para>
+
+ <para>Look at your <filename>/etc/services</filename>.
+ What is defined at port 139/tcp. If nothing is defined
+ then add a line like this:</para>
+
+ <para><userinput>netbios-ssn 139/tcp</userinput></para>
+
+ <para>similarly for 137/udp you should have an entry like:</para>
+
+ <para><userinput>netbios-ns 137/udp</userinput></para>
+
+ <para>Next edit your <filename>/etc/inetd.conf</filename>
+ and add two lines something like this:</para>
+
+ <para><programlisting>
+ netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+ netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+ </programlisting></para>
+
+ <para>The exact syntax of <filename>/etc/inetd.conf</filename>
+ varies between unixes. Look at the other entries in inetd.conf
+ for a guide.</para>
+
+ <para>NOTE: Some unixes already have entries like netbios_ns
+ (note the underscore) in <filename>/etc/services</filename>.
+ You must either edit <filename>/etc/services</filename> or
+ <filename>/etc/inetd.conf</filename> to make them consistent.</para>
+
+ <para>NOTE: On many systems you may need to use the
+ "interfaces" option in smb.conf to specify the IP address
+ and netmask of your interfaces. Run <command>ifconfig</command>
+ as root if you don't know what the broadcast is for your
+ net. <command>nmbd</command> tries to determine it at run
+ time, but fails on some unixes. See the section on "testing nmbd"
+ for a method of finding if you need to do this.</para>
+
+ <para>!!!WARNING!!! Many unixes only accept around 5
+ parameters on the command line in <filename>inetd.conf</filename>.
+ This means you shouldn't use spaces between the options and
+ arguments, or you should use a script, and start the script
+ from <command>inetd</command>.</para>
+
+ <para>Restart <command>inetd</command>, perhaps just send
+ it a HUP. If you have installed an earlier version of <command>
+ nmbd</command> then you may need to kill nmbd as well.</para>
+ </sect2>
+
+ <sect2>
+ <title>Step 5b. Alternative: starting it as a daemon</title>
+
+ <para>To start the server as a daemon you should create
+ a script something like this one, perhaps calling
+ it <filename>startsmb</filename>.</para>
+
+ <para><programlisting>
+ #!/bin/sh
+ /usr/local/samba/bin/smbd -D
+ /usr/local/samba/bin/nmbd -D
+ </programlisting></para>
+
+ <para>then make it executable with <command>chmod
+ +x startsmb</command></para>
+
+ <para>You can then run <command>startsmb</command> by
+ hand or execute it from <filename>/etc/rc.local</filename>
+ </para>
+
+ <para>To kill it send a kill signal to the processes
+ <command>nmbd</command> and <command>smbd</command>.</para>
+
+ <para>NOTE: If you use the SVR4 style init system then
+ you may like to look at the <filename>examples/svr4-startup</filename>
+ script to make Samba fit into that system.</para>
+ </sect2>
+</sect1>
+
+<sect1>
+ <title>Step 6: Try listing the shares available on your
+ server</title>
+
+ <para><prompt>$ </prompt><userinput>smbclient -L
+ <replaceable>yourhostname</replaceable></userinput></para>
+
+ <para>Your should get back a list of shares available on
+ your server. If you don't then something is incorrectly setup.
+ Note that this method can also be used to see what shares
+ are available on other LanManager clients (such as WfWg).</para>
+
+ <para>If you choose user level security then you may find
+ that Samba requests a password before it will list the shares.
+ See the <command>smbclient</command> man page for details. (you
+ can force it to list the shares without a password by
+ adding the option -U% to the command line. This will not work
+ with non-Samba servers)</para>
+</sect1>
+
+<sect1>
+ <title>Step 7: Try connecting with the unix client</title>
+
+ <para><prompt>$ </prompt><userinput>smbclient <replaceable>
+ //yourhostname/aservice</replaceable></userinput></para>
+
+ <para>Typically the <replaceable>yourhostname</replaceable>
+ would be the name of the host where you installed <command>
+ smbd</command>. The <replaceable>aservice</replaceable> is
+ any service you have defined in the <filename>smb.conf</filename>
+ file. Try your user name if you just have a [homes] section
+ in <filename>smb.conf</filename>.</para>
+
+ <para>For example if your unix host is bambi and your login
+ name is fred you would type:</para>
+
+ <para><prompt>$ </prompt><userinput>smbclient //bambi/fred
+ </userinput></para>
+</sect1>
+
+<sect1>
+ <title>Step 8: Try connecting from a DOS, WfWg, Win9x, WinNT,
+ Win2k, OS/2, etc... client</title>
+
+ <para>Try mounting disks. eg:</para>
+
+ <para><prompt>C:\WINDOWS\> </prompt><userinput>net use d: \\servername\service
+ </userinput></para>
+
+ <para>Try printing. eg:</para>
+
+ <para><prompt>C:\WINDOWS\> </prompt><userinput>net use lpt1:
+ \\servername\spoolservice</userinput></para>
+
+ <para><prompt>C:\WINDOWS\> </prompt><userinput>print filename
+ </userinput></para>
+
+ <para>Celebrate, or send me a bug report!</para>
+</sect1>
+
+<sect1>
+ <title>What If Things Don't Work?</title>
+
+ <para>If nothing works and you start to think "who wrote
+ this pile of trash" then I suggest you do step 2 again (and
+ again) till you calm down.</para>
+
+ <para>Then you might read the file DIAGNOSIS.txt and the
+ FAQ. If you are still stuck then try the mailing list or
+ newsgroup (look in the README for details). Samba has been
+ successfully installed at thousands of sites worldwide, so maybe
+ someone else has hit your problem and has overcome it. You could
+ also use the WWW site to scan back issues of the samba-digest.</para>
+
+ <para>When you fix the problem PLEASE send me some updates to the
+ documentation (or source code) so that the next person will find it
+ easier. </para>
+
+ <sect2>
+ <title>Diagnosing Problems</title>
+
+ <para>If you have installation problems then go to
+ <filename>DIAGNOSIS.txt</filename> to try to find the
+ problem.</para>
+ </sect2>
+
+ <sect2>
+ <title>Scope IDs</title>
+
+ <para>By default Samba uses a blank scope ID. This means
+ all your windows boxes must also have a blank scope ID.
+ If you really want to use a non-blank scope ID then you will
+ need to use the -i &lt;scope&gt; option to nmbd, smbd, and
+ smbclient. All your PCs will need to have the same setting for
+ this to work. I do not recommend scope IDs.</para>
+ </sect2>
+
+
+ <sect2>
+ <title>Choosing the Protocol Level</title>
+
+ <para>The SMB protocol has many dialects. Currently
+ Samba supports 5, called CORE, COREPLUS, LANMAN1,
+ LANMAN2 and NT1.</para>
+
+ <para>You can choose what maximum protocol to support
+ in the <filename>smb.conf</filename> file. The default is
+ NT1 and that is the best for the vast majority of sites.</para>
+
+ <para>In older versions of Samba you may have found it
+ necessary to use COREPLUS. The limitations that led to
+ this have mostly been fixed. It is now less likely that you
+ will want to use less than LANMAN1. The only remaining advantage
+ of COREPLUS is that for some obscure reason WfWg preserves
+ the case of passwords in this protocol, whereas under LANMAN1,
+ LANMAN2 or NT1 it uppercases all passwords before sending them,
+ forcing you to use the "password level=" option in some cases.</para>
+
+ <para>The main advantage of LANMAN2 and NT1 is support for
+ long filenames with some clients (eg: smbclient, Windows NT
+ or Win95). </para>
+
+ <para>See the smb.conf(5) manual page for more details.</para>
+
+ <para>Note: To support print queue reporting you may find
+ that you have to use TCP/IP as the default protocol under
+ WfWg. For some reason if you leave Netbeui as the default
+ it may break the print queue reporting on some systems.
+ It is presumably a WfWg bug.</para>
+ </sect2>
+
+ <sect2>
+ <title>Printing from UNIX to a Client PC</title>
+
+ <para>To use a printer that is available via a smb-based
+ server from a unix host you will need to compile the
+ smbclient program. You then need to install the script
+ "smbprint". Read the instruction in smbprint for more details.
+ </para>
+
+ <para>There is also a SYSV style script that does much
+ the same thing called smbprint.sysv. It contains instructions.</para>
+ </sect2>
+
+ <sect2>
+ <title>Locking</title>
+
+ <para>One area which sometimes causes trouble is locking.</para>
+
+ <para>There are two types of locking which need to be
+ performed by a SMB server. The first is "record locking"
+ which allows a client to lock a range of bytes in a open file.
+ The second is the "deny modes" that are specified when a file
+ is open.</para>
+
+ <para>Record locking semantics under Unix is very
+ different from record locking under Windows. Versions
+ of Samba before 2.2 have tried to use the native
+ fcntl() unix system call to implement proper record
+ locking between different Samba clients. This can not
+ be fully correct due to several reasons. The simplest
+ is the fact that a Windows client is allowed to lock a
+ byte range up to 2^32 or 2^64, depending on the client
+ OS. The unix locking only supports byte ranges up to
+ 2^31. So it is not possible to correctly satisfy a
+ lock request above 2^31. There are many more
+ differences, too many to be listed here.</para>
+
+ <para>Samba 2.2 and above implements record locking
+ completely independent of the underlying unix
+ system. If a byte range lock that the client requests
+ happens to fall into the range 0-2^31, Samba hands
+ this request down to the Unix system. All other locks
+ can not be seen by unix anyway.</para>
+
+ <para>Strictly a SMB server should check for locks before
+ every read and write call on a file. Unfortunately with the
+ way fcntl() works this can be slow and may overstress the
+ rpc.lockd. It is also almost always unnecessary as clients
+ are supposed to independently make locking calls before reads
+ and writes anyway if locking is important to them. By default
+ Samba only makes locking calls when explicitly asked
+ to by a client, but if you set "strict locking = yes" then it will
+ make lock checking calls on every read and write. </para>
+
+ <para>You can also disable by range locking completely
+ using "locking = no". This is useful for those shares that
+ don't support locking or don't need it (such as cdroms). In
+ this case Samba fakes the return codes of locking calls to
+ tell clients that everything is OK.</para>
+
+ <para>The second class of locking is the "deny modes". These
+ are set by an application when it opens a file to determine
+ what types of access should be allowed simultaneously with
+ its open. A client may ask for DENY_NONE, DENY_READ, DENY_WRITE
+ or DENY_ALL. There are also special compatibility modes called
+ DENY_FCB and DENY_DOS.</para>
+
+ <para>You can disable share modes using "share modes = no".
+ This may be useful on a heavily loaded server as the share
+ modes code is very slow. See also the FAST_SHARE_MODES
+ option in the Makefile for a way to do full share modes
+ very fast using shared memory (if your OS supports it).</para>
+ </sect2>
+
+ <sect2>
+ <title>Mapping Usernames</title>
+
+ <para>If you have different usernames on the PCs and
+ the unix server then take a look at the "username map" option.
+ See the smb.conf man page for details.</para>
+ </sect2>
+
+ <sect2>
+ <title>Other Character Sets</title>
+
+ <para>If you have problems using filenames with accented
+ characters in them (like the German, French or Scandinavian
+ character sets) then I recommend you look at the "valid chars"
+ option in smb.conf and also take a look at the validchars
+ package in the examples directory.</para>
+ </sect2>
+
+</sect1>
+</chapter>
diff --git a/docs/docbook/projdoc/msdfs_setup.sgml b/docs/docbook/projdoc/msdfs_setup.sgml
new file mode 100644
index 00000000000..35c9d40840a
--- /dev/null
+++ b/docs/docbook/projdoc/msdfs_setup.sgml
@@ -0,0 +1,117 @@
+<chapter id="msdfs">
+
+<chapterinfo>
+ <author>
+ <firstname>Shirish</firstname><surname>Kalele</surname>
+ <affiliation>
+ <orgname>Samba Team & Veritas Software</orgname>
+ <address>
+ <email>samba@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>12 Jul 200</pubdate>
+</chapterinfo>
+
+
+<title>Hosting a Microsoft Distributed File System tree on Samba</title>
+
+<sect1>
+
+ <title>Instructions</title>
+
+ <para>The Distributed File System (or Dfs) provides a means of
+ separating the logical view of files and directories that users
+ see from the actual physical locations of these resources on the
+ network. It allows for higher availability, smoother storage expansion,
+ load balancing etc. For more information about Dfs, refer to <ulink
+ url="http://www.microsoft.com/NTServer/nts/downloads/winfeatures/NTSDistrFile/AdminGuide.asp">
+ Microsoft documentation</ulink>. </para>
+
+ <para>This document explains how to host a Dfs tree on a Unix
+ machine (for Dfs-aware clients to browse) using Samba.</para>
+
+ <para>To enable SMB-based DFS for Samba, configure it with the
+ <parameter>--with-msdfs</parameter> option. Once built, a
+ Samba server can be made a Dfs server by setting the global
+ boolean <ulink url="smb.conf.5.html#HOSTMSDFS"><parameter>
+ host msdfs</parameter></ulink> parameter in the <filename>smb.conf
+ </filename> file. You designate a share as a Dfs root using the share
+ level boolean <ulink url="smb.conf.5.html#MSDFSROOT"><parameter>
+ msdfs root</parameter></ulink> parameter. A Dfs root directory on
+ Samba hosts Dfs links in the form of symbolic links that point
+ to other servers. For example, a symbolic link
+ <filename>junction-&gt;msdfs:storage1\share1</filename> in
+ the share directory acts as the Dfs junction. When Dfs-aware
+ clients attempt to access the junction link, they are redirected
+ to the storage location (in this case, \\storage1\share1).</para>
+
+ <para>Dfs trees on Samba work with all Dfs-aware clients ranging
+ from Windows 95 to 2000.</para>
+
+ <para>Here's an example of setting up a Dfs tree on a Samba
+ server.</para>
+
+ <para><programlisting>
+# The smb.conf file:
+[global]
+ netbios name = SAMBA
+ host msdfs = yes
+
+[dfs]
+ path = /export/dfsroot
+ msdfs root = yes
+ </programlisting></para>
+
+
+ <para>In the /export/dfsroot directory we set up our dfs links to
+ other servers on the network.</para>
+
+ <para><prompt>root# </prompt><userinput>cd /export/dfsroot</userinput></para>
+ <para><prompt>root# </prompt><userinput>chown root /export/dfsroot</userinput></para>
+ <para><prompt>root# </prompt><userinput>chmod 755 /export/dfsroot</userinput></para>
+ <para><prompt>root# </prompt><userinput>ln -s msdfs:storageA\\shareA linka</userinput></para>
+ <para><prompt>root# </prompt><userinput>ln -s msdfs:serverB\\share,serverC\\share linkb</userinput></para>
+
+
+ <para>You should set up the permissions and ownership of
+ the directory acting as the Dfs root such that only designated
+ users can create, delete or modify the msdfs links. Also note
+ that symlink names should be all lowercase. This limitation exists
+ to have Samba avoid trying all the case combinations to get at
+ the link name. Finally set up the symbolic links to point to the
+ network shares you want, and start Samba.</para>
+
+ <para>Users on Dfs-aware clients can now browse the Dfs tree
+ on the Samba server at \\samba\dfs. Accessing
+ links linka or linkb (which appear as directories to the client)
+ takes users directly to the appropriate shares on the network.</para>
+
+ <sect2>
+ <title>Notes</title>
+
+ <itemizedlist>
+ <listitem><para>Windows clients need to be rebooted
+ if a previously mounted non-dfs share is made a dfs
+ root or vice versa. A better way is to introduce a
+ new share and make it the dfs root.</para>
+ </listitem>
+
+ <listitem><para>Currently there's a restriction that msdfs
+ symlink names should all be lowercase.</para>
+ </listitem>
+
+ <listitem><para>For security purposes, the directory
+ acting as the root of the Dfs tree should have ownership
+ and permissions set so that only designated users can
+ modify the symbolic links in the directory.</para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+</sect1>
+
+
+
+</chapter>
diff --git a/docs/docbook/projdoc/printer_driver2.sgml b/docs/docbook/projdoc/printer_driver2.sgml
new file mode 100644
index 00000000000..4377303ffb2
--- /dev/null
+++ b/docs/docbook/projdoc/printer_driver2.sgml
@@ -0,0 +1,687 @@
+<chapter id="printing">
+
+
+<chapterinfo>
+ <author>
+ <firstname>Gerald (Jerry)</firstname><surname>Carter</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address>
+ <email>jerry@samba.org</email>
+ </address>
+ </affiliation>
+ </author>
+
+
+ <pubdate> (3 May 2001) </pubdate>
+</chapterinfo>
+
+<title>Printing Support in Samba 2.2.x</title>
+
+<sect1>
+<title>Introduction</title>
+
+<para>Beginning with the 2.2.0 release, Samba supports
+the native Windows NT printing mechanisms implemented via
+MS-RPC (i.e. the SPOOLSS named pipe). Previous versions of
+Samba only supported LanMan printing calls.</para>
+
+<para>The additional functionality provided by the new
+SPOOLSS support includes:</para>
+
+<itemizedlist>
+ <listitem><para>Support for downloading printer driver
+ files to Windows 95/98/NT/2000 clients upon demand.
+ </para></listitem>
+
+ <listitem><para>Uploading of printer drivers via the
+ Windows NT Add Printer Wizard (APW) or the
+ Imprints tool set (refer to <ulink
+ url="http://imprints.sourceforge.net">http://imprints.sourceforge.net</ulink>).
+ </para></listitem>
+
+ <listitem><para>Support for the native MS-RPC printing
+ calls such as StartDocPrinter, EnumJobs(), etc... (See
+ the MSDN documentation at <ulink
+ url="http://msdn.microsoft.com/">http://msdn.microsoft.com/</ulink>
+ for more information on the Win32 printing API)
+ </para></listitem>
+
+ <listitem><para>Support for NT Access Control Lists (ACL)
+ on printer objects</para></listitem>
+
+ <listitem><para>Improved support for printer queue manipulation
+ through the use of an internal databases for spooled job
+ information</para></listitem>
+</itemizedlist>
+
+<para>
+There has been some initial confusion about what all this means
+and whether or not it is a requirement for printer drivers to be
+installed on a Samba host in order to support printing from Windows
+clients. A bug existed in Samba 2.2.0 which made Windows NT/2000 clients
+require that the Samba server possess a valid driver for the printer.
+This is fixed in Samba 2.2.1 and once again, Windows NT/2000 clients
+can use the local APW for installing drivers to be used with a Samba
+served printer. This is the same behavior exhibited by Windows 9x clients.
+As a side note, Samba does not use these drivers in any way to process
+spooled files. They are utilized entirely by the clients.
+</para>
+
+<para>
+The following MS KB article, may be of some help if you are dealing with
+Windows 2000 clients: <emphasis>How to Add Printers with No User
+Interaction in Windows 2000</emphasis>
+</para>
+
+<para>
+<ulink url="http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP">http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP</ulink>
+</para>
+
+</sect1>
+
+
+<sect1>
+<title>Configuration</title>
+
+<warning>
+<title>[print$] vs. [printer$]</title>
+
+<para>
+Previous versions of Samba recommended using a share named [printer$].
+This name was taken from the printer$ service created by Windows 9x
+clients when a printer was shared. Windows 9x printer servers always have
+a printer$ service which provides read-only access via no
+password in order to support printer driver downloads.
+</para>
+
+<para>
+However, the initial implementation allowed for a
+parameter named <parameter>printer driver location</parameter>
+to be used on a per share basis to specify the location of
+the driver files associated with that printer. Another
+parameter named <parameter>printer driver</parameter> provided
+a means of defining the printer driver name to be sent to
+the client.
+</para>
+
+<para>
+These parameters, including <parameter>printer driver
+file</parameter> parameter, are being depreciated and should not
+be used in new installations. For more information on this change,
+you should refer to the <link linkend="MIGRATION">Migration section</link>
+of this document.
+</para>
+</warning>
+
+<sect2>
+<title>Creating [print$]</title>
+
+<para>
+In order to support the uploading of printer driver
+files, you must first configure a file share named [print$].
+The name of this share is hard coded in Samba's internals so
+the name is very important (print$ is the service used by
+Windows NT print servers to provide support for printer driver
+download).
+</para>
+
+<para>You should modify the server's smb.conf file to add the global
+parameters and to create the
+following file share (of course, some of the parameter values,
+such as 'path' are arbitrary and should be replaced with
+appropriate values for your site):</para>
+
+<para><programlisting>
+[global]
+ ; members of the ntadmin group should be able
+ ; to add drivers and set printer properties
+ ; root is implicitly a 'printer admin'
+ printer admin = @ntadmin
+
+[print$]
+ path = /usr/local/samba/printers
+ guest ok = yes
+ browseable = yes
+ read only = yes
+ ; since this share is configured as read only, then we need
+ ; a 'write list'. Check the file system permissions to make
+ ; sure this account can copy files to the share. If this
+ ; is setup to a non-root account, then it should also exist
+ ; as a 'printer admin'
+ write list = @ntadmin,root
+</programlisting></para>
+
+<para>The <ulink url="smb.conf.5.html#WRITELIST"><parameter>
+write list</parameter></ulink> is used to allow administrative
+level user accounts to have write access in order to update files
+on the share. See the <ulink url="smb.conf.5.html">smb.conf(5)
+man page</ulink> for more information on configuring file shares.</para>
+
+<para>The requirement for <ulink url="smb.conf.5.html#GUESTOK"><command>guest
+ok = yes</command></ulink> depends upon how your
+site is configured. If users will be guaranteed to have
+an account on the Samba host, then this is a non-issue.</para>
+
+<note>
+<title>Author's Note</title>
+
+<para>
+The non-issue is that if all your Windows NT users are guaranteed to be
+authenticated by the Samba server (such as a domain member server and the NT
+user has already been validated by the Domain Controller in
+order to logon to the Windows NT console), then guest access
+is not necessary. Of course, in a workgroup environment where
+you just want to be able to print without worrying about
+silly accounts and security, then configure the share for
+guest access. You'll probably want to add <ulink
+url="smb.conf.5.html#MAPTOGUEST"><command>map to guest = Bad User
+</command></ulink> in the [global] section as well. Make sure
+you understand what this parameter does before using it
+though. --jerry
+</para>
+</note>
+
+<para>In order for a Windows NT print server to support
+the downloading of driver files by multiple client architectures,
+it must create subdirectories within the [print$] service
+which correspond to each of the supported client architectures.
+Samba follows this model as well.</para>
+
+<para>Next create the directory tree below the [print$] share
+for each architecture you wish to support.</para>
+
+<para><programlisting>
+[print$]-----
+ |-W32X86 ; "Windows NT x86"
+ |-WIN40 ; "Windows 95/98"
+ |-W32ALPHA ; "Windows NT Alpha_AXP"
+ |-W32MIPS ; "Windows NT R4000"
+ |-W32PPC ; "Windows NT PowerPC"
+</programlisting></para>
+
+<warning>
+<title>ATTENTION! REQUIRED PERMISSIONS</title>
+
+<para>
+In order to currently add a new driver to you Samba host,
+one of two conditions must hold true:
+</para>
+
+<itemizedlist>
+ <listitem><para>The account used to connect to the Samba host
+ must have a uid of 0 (i.e. a root account)</para></listitem>
+
+ <listitem><para>The account used to connect to the Samba host
+ must be a member of the <ulink
+ url="smb.conf.5.html#PRINTERADMIN"><parameter>printer
+ admin</parameter></ulink> list.</para></listitem>
+</itemizedlist>
+
+<para>
+Of course, the connected account must still possess access
+to add files to the subdirectories beneath [print$]. Remember
+that all file shares are set to 'read only' by default.
+</para>
+</warning>
+
+
+<para>
+Once you have created the required [print$] service and
+associated subdirectories, simply log onto the Samba server using
+a root (or <parameter>printer admin</parameter>) account
+from a Windows NT 4.0 client. Navigate to the "Printers" folder
+on the Samba server. You should see an initial listing of printers
+that matches the printer shares defined on your Samba host.
+</para>
+</sect2>
+
+<sect2>
+<title>Setting Drivers for Existing Printers</title>
+
+<para>The initial listing of printers in the Samba host's
+Printers folder will have no real printer driver assigned
+to them. By default, in Samba 2.2.0 this driver name was set to
+<emphasis>NO PRINTER DRIVER AVAILABLE FOR THIS PRINTER</emphasis>.
+Later versions changed this to a NULL string to allow the use
+tof the local Add Printer Wizard on NT/2000 clients.
+Attempting to view the printer properties for a printer
+which has this default driver assigned will result in
+the error message:</para>
+
+<para>
+<emphasis>Device settings cannot be displayed. The driver
+for the specified printer is not installed, only spooler
+properties will be displayed. Do you want to install the
+driver now?</emphasis>
+</para>
+
+<para>
+Click "No" in the error dialog and you will be presented with
+the printer properties window. The way assign a driver to a
+printer is to either
+</para>
+
+<itemizedlist>
+ <listitem><para>Use the "New Driver..." button to install
+ a new printer driver, or</para></listitem>
+
+ <listitem><para>Select a driver from the popup list of
+ installed drivers. Initially this list will be empty.</para>
+ </listitem>
+</itemizedlist>
+
+<para>If you wish to install printer drivers for client
+operating systems other than "Windows NT x86", you will need
+to use the "Sharing" tab of the printer properties dialog.</para>
+
+<para>Assuming you have connected with a root account, you
+will also be able modify other printer properties such as
+ACLs and device settings using this dialog box.</para>
+
+<para>A few closing comments for this section, it is possible
+on a Windows NT print server to have printers
+listed in the Printers folder which are not shared. Samba does
+not make this distinction. By definition, the only printers of
+which Samba is aware are those which are specified as shares in
+<filename>smb.conf</filename>.</para>
+
+<para>Another interesting side note is that Windows NT clients do
+not use the SMB printer share, but rather can print directly
+to any printer on another Windows NT host using MS-RPC. This
+of course assumes that the printing client has the necessary
+privileges on the remote host serving the printer. The default
+permissions assigned by Windows NT to a printer gives the "Print"
+permissions to the "Everyone" well-known group.
+</para>
+
+</sect2>
+
+
+<sect2>
+<title>Support a large number of printers</title>
+
+<para>One issue that has arisen during the development
+phase of Samba 2.2 is the need to support driver downloads for
+100's of printers. Using the Windows NT APW is somewhat
+awkward to say the list. If more than one printer are using the
+same driver, the <ulink url="rpcclient.1.html"><command>rpcclient's
+setdriver command</command></ulink> can be used to set the driver
+associated with an installed driver. The following is example
+of how this could be accomplished:</para>
+
+<para><programlisting>
+<prompt>$ </prompt>rpcclient pogo -U root%secret -c "enumdrivers"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+
+[Windows NT x86]
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4000 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 2100 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4Si/4SiMX PS]
+
+<prompt>$ </prompt>rpcclient pogo -U root%secret -c "enumprinters"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+ flags:[0x800000]
+ name:[\\POGO\hp-print]
+ description:[POGO\\POGO\hp-print,NO DRIVER AVAILABLE FOR THIS PRINTER,]
+ comment:[]
+
+<prompt>$ </prompt>rpcclient pogo -U root%secret \
+<prompt>&gt; </prompt> -c "setdriver hp-print \"HP LaserJet 4000 Series PS\""
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+Successfully set hp-print to driver HP LaserJet 4000 Series PS.
+</programlisting></para>
+</sect2>
+
+
+
+<sect2>
+<title>Adding New Printers via the Windows NT APW</title>
+
+<para>
+By default, Samba offers all printer shares defined in <filename>smb.conf</filename>
+in the "Printers..." folder. Also existing in this folder is the Windows NT
+Add Printer Wizard icon. The APW will be show only if
+</para>
+
+<itemizedlist>
+ <listitem><para>The connected user is able to successfully
+ execute an OpenPrinterEx(\\server) with administrative
+ privileges (i.e. root or <parameter>printer admin</parameter>).
+ </para></listitem>
+
+ <listitem><para><ulink url="smb.conf.5.html#SHOWADDPRINTERWIZARD"><parameter>show
+ add printer wizard = yes</parameter></ulink> (the default).
+ </para></listitem>
+</itemizedlist>
+
+<para>
+In order to be able to use the APW to successfully add a printer to a Samba
+server, the <ulink url="smb.conf.5.html#ADDPRINTERCOMMAND"><parameter>add
+printer command</parameter></ulink> must have a defined value. The program
+hook must successfully add the printer to the system (i.e.
+<filename>/etc/printcap</filename> or appropriate files) and
+<filename>smb.conf</filename> if necessary.
+</para>
+
+<para>
+When using the APW from a client, if the named printer share does
+not exist, <command>smbd</command> will execute the <parameter>add printer
+command</parameter> and reparse to the <filename>smb.conf</filename>
+to attempt to locate the new printer share. If the share is still not defined,
+an error of "Access Denied" is returned to the client. Note that the
+<parameter>add printer program</parameter> is executed under the context
+of the connected user, not necessarily a root account.
+</para>
+
+<para>
+There is a complementing <ulink url="smb.conf.5.html#DELETEPRINTERCOMMAND"><parameter>delete
+printer command</parameter></ulink> for removing entries from the "Printers..."
+folder.
+</para>
+
+</sect2>
+
+
+<sect2>
+<title>Samba and Printer Ports</title>
+
+<para>
+Windows NT/2000 print servers associate a port with each printer. These normally
+take the form of LPT1:, COM1:, FILE:, etc... Samba must also support the
+concept of ports associated with a printer. By default, only one printer port,
+named "Samba Printer Port", exists on a system. Samba does not really a port in
+order to print, rather it is a requirement of Windows clients.
+</para>
+
+<para>
+Note that Samba does not support the concept of "Printer Pooling" internally
+either. This is when a logical printer is assigned to multiple ports as
+a form of load balancing or fail over.
+</para>
+
+<para>
+If you require that multiple ports be defined for some reason,
+<filename>smb.conf</filename> possesses a <ulink
+url="smb.conf.5.html#ENUMPORTSCOMMAND"><parameter>enumports
+command</parameter></ulink> which can be used to define an external program
+that generates a listing of ports on a system.
+</para>
+
+</sect2>
+
+</sect1>
+
+
+<sect1>
+ <title>The Imprints Toolset</title>
+
+ <para>The Imprints tool set provides a UNIX equivalent of the
+ Windows NT Add Printer Wizard. For complete information, please
+ refer to the Imprints web site at <ulink url="http://imprints.sourceforge.net/">
+ http://imprints.sourceforge.net/</ulink> as well as the documentation
+ included with the imprints source distribution. This section will
+ only provide a brief introduction to the features of Imprints.</para>
+
+
+ <sect2>
+ <title>What is Imprints?</title>
+
+ <para>Imprints is a collection of tools for supporting the goals
+ of</para>
+
+ <itemizedlist>
+ <listitem><para>Providing a central repository information
+ regarding Windows NT and 95/98 printer driver packages</para>
+ </listitem>
+
+ <listitem><para>Providing the tools necessary for creating
+ the Imprints printer driver packages.</para></listitem>
+
+ <listitem><para>Providing an installation client which
+ will obtain and install printer drivers on remote Samba
+ and Windows NT 4 print servers.</para></listitem>
+ </itemizedlist>
+
+ </sect2>
+
+
+ <sect2>
+ <title>Creating Printer Driver Packages</title>
+
+ <para>The process of creating printer driver packages is beyond
+ the scope of this document (refer to Imprints.txt also included
+ with the Samba distribution for more information). In short,
+ an Imprints driver package is a gzipped tarball containing the
+ driver files, related INF files, and a control file needed by the
+ installation client.</para>
+ </sect2>
+
+
+ <sect2>
+ <title>The Imprints server</title>
+
+ <para>The Imprints server is really a database server that
+ may be queried via standard HTTP mechanisms. Each printer
+ entry in the database has an associated URL for the actual
+ downloading of the package. Each package is digitally signed
+ via GnuPG which can be used to verify that package downloaded
+ is actually the one referred in the Imprints database. It is
+ <emphasis>not</emphasis> recommended that this security check
+ be disabled.</para>
+ </sect2>
+
+ <sect2>
+ <title>The Installation Client</title>
+
+ <para>More information regarding the Imprints installation client
+ is available in the <filename>Imprints-Client-HOWTO.ps</filename>
+ file included with the imprints source package.</para>
+
+ <para>The Imprints installation client comes in two forms.</para>
+
+ <itemizedlist>
+ <listitem><para>a set of command line Perl scripts</para>
+ </listitem>
+
+ <listitem><para>a GTK+ based graphical interface to
+ the command line perl scripts</para></listitem>
+ </itemizedlist>
+
+ <para>The installation client (in both forms) provides a means
+ of querying the Imprints database server for a matching
+ list of known printer model names as well as a means to
+ download and install the drivers on remote Samba and Windows
+ NT print servers.</para>
+
+ <para>The basic installation process is in four steps and
+ perl code is wrapped around <command>smbclient</command>
+ and <command>rpcclient</command>.</para>
+
+<para><programlisting>
+foreach (supported architecture for a given driver)
+{
+ 1. rpcclient: Get the appropriate upload directory
+ on the remote server
+ 2. smbclient: Upload the driver files
+ 3. rpcclient: Issues an AddPrinterDriver() MS-RPC
+}
+
+4. rpcclient: Issue an AddPrinterEx() MS-RPC to actually
+ create the printer
+</programlisting></para>
+
+ <para>One of the problems encountered when implementing
+ the Imprints tool set was the name space issues between
+ various supported client architectures. For example, Windows
+ NT includes a driver named "Apple LaserWriter II NTX v51.8"
+ and Windows 95 calls its version of this driver "Apple
+ LaserWriter II NTX"</para>
+
+ <para>The problem is how to know what client drivers have
+ been uploaded for a printer. As astute reader will remember
+ that the Windows NT Printer Properties dialog only includes
+ space for one printer driver name. A quick look in the
+ Windows NT 4.0 system registry at</para>
+
+ <para><filename>HKLM\System\CurrentControlSet\Control\Print\Environment
+ </filename></para>
+
+ <para>will reveal that Windows NT always uses the NT driver
+ name. This is ok as Windows NT always requires that at least
+ the Windows NT version of the printer driver is present.
+ However, Samba does not have the requirement internally.
+ Therefore, how can you use the NT driver name if is has not
+ already been installed?</para>
+
+ <para>The way of sidestepping this limitation is to require
+ that all Imprints printer driver packages include both the Intel
+ Windows NT and 95/98 printer drivers and that NT driver is
+ installed first.</para>
+ </sect2>
+
+</sect1>
+
+
+<sect1>
+<title><anchor id="MIGRATION">Migration to from Samba 2.0.x to 2.2.x</title>
+
+<para>
+Given that printer driver management has changed (we hope improved) in
+2.2 over prior releases, migration from an existing setup to 2.2 can
+follow several paths. Here are the possible scenarios for
+migration:
+</para>
+
+<itemizedlist>
+ <listitem><para>If you do not desire the new Windows NT
+ print driver support, nothing needs to be done.
+ All existing parameters work the same.</para></listitem>
+
+ <listitem><para>If you want to take advantage of NT printer
+ driver support but do not want to migrate the
+ 9x drivers to the new setup, the leave the existing
+ <filename>printers.def</filename> file. When smbd attempts
+ to locate a
+ 9x driver for the printer in the TDB and fails it
+ will drop down to using the printers.def (and all
+ associated parameters). The <command>make_printerdef</command>
+ tool will also remain for backwards compatibility but will
+ be removed in the next major release.</para></listitem>
+
+ <listitem><para>If you install a Windows 9x driver for a printer
+ on your Samba host (in the printing TDB), this information will
+ take precedence and the three old printing parameters
+ will be ignored (including print driver location).</para></listitem>
+
+ <listitem><para>If you want to migrate an existing <filename>printers.def</filename>
+ file into the new setup, the current only solution is to use the Windows
+ NT APW to install the NT drivers and the 9x drivers. This can be scripted
+ using <command>smbclient</command> and <command>rpcclient</command>. See the
+ Imprints installation client at <ulink
+ url="http://imprints.sourceforge.net/">http://imprints.sourceforge.net/</ulink>
+ for an example.
+ </para></listitem>
+</itemizedlist>
+
+
+<warning>
+<title>Achtung!</title>
+
+<para>
+The following <filename>smb.conf</filename> parameters are considered to
+be deprecated and will be removed soon. Do not use them in new
+installations
+</para>
+
+<itemizedlist>
+ <listitem><para><parameter>printer driver file (G)</parameter>
+ </para></listitem>
+
+ <listitem><para><parameter>printer driver (S)</parameter>
+ </para></listitem>
+
+ <listitem><para><parameter>printer driver location (S)</parameter>
+ </para></listitem>
+</itemizedlist>
+</warning>
+
+
+<para>
+The have been two new parameters add in Samba 2.2.2 to for
+better support of Samba 2.0.x backwards capability (<parameter>disable
+spoolss</parameter>) and for using local printers drivers on Windows
+NT/2000 clients (<parameter>use client driver</parameter>). Both of
+these options are described in the smb.coinf(5) man page and are
+disabled by default.
+</para>
+
+
+</sect1>
+
+
+<!--
+
+ This comment from rpc_server/srv_spoolss_nt.c:_spoolss_open_printer_ex()
+ needs to be added into a section probably. This is to remind me it needs
+ to be done. -jerry
+
+ /*
+ * If the openprinterex rpc call contains a devmode,
+ * it's a per-user one. This per-user devmode is derivated
+ * from the global devmode. Openprinterex() contains a per-user
+ * devmode for when you do EMF printing and spooling.
+ * In the EMF case, the NT workstation is only doing half the job
+ * of rendering the page. The other half is done by running the printer
+ * driver on the server.
+ * The EMF file doesn't contain the page description (paper size, orientation, ...).
+ * The EMF file only contains what is to be printed on the page.
+ * So in order for the server to know how to print, the NT client sends
+ * a devicemode attached to the openprinterex call.
+ * But this devicemode is short lived, it's only valid for the current print job.
+ *
+ * If Samba would have supported EMF spooling, this devicemode would
+ * have been attached to the handle, to sent it to the driver to correctly
+ * rasterize the EMF file.
+ *
+ * As Samba only supports RAW spooling, we only receive a ready-to-print file,
+ * we just act as a pass-thru between windows and the printer.
+ *
+ * In order to know that Samba supports only RAW spooling, NT has to call
+ * getprinter() at level 2 (attribute field) or NT has to call startdoc()
+ * and until NT sends a RAW job, we refuse it.
+ *
+ * But to call getprinter() or startdoc(), you first need a valid handle,
+ * and to get an handle you have to call openprintex(). Hence why you have
+ * a devicemode in the openprinterex() call.
+ *
+ *
+ * Differences between NT4 and NT 2000.
+ * NT4:
+ *
+ * On NT4, you only have a global devicemode. This global devicemode can be changed
+ * by the administrator (or by a user with enough privs). Every time a user
+ * wants to print, the devicemode is reset to the default. In Word, every time
+ * you print, the printer's characteristics are always reset to the global devicemode.
+ *
+ * NT 2000:
+ *
+ * In W2K, there is the notion of per-user devicemode. The first time you use
+ * a printer, a per-user devicemode is build from the global devicemode.
+ * If you change your per-user devicemode, it is saved in the registry, under the
+ * H_KEY_CURRENT_KEY sub_tree. So that every time you print, you have your default
+ * printer preferences available.
+ *
+ * To change the per-user devicemode: it's the "Printing Preferences ..." button
+ * on the General Tab of the printer properties windows.
+ *
+ * To change the global devicemode: it's the "Printing Defaults..." button
+ * on the Advanced Tab of the printer properties window.
+-->
+
+</chapter>
diff --git a/docs/docbook/projdoc/samba-doc.sgml b/docs/docbook/projdoc/samba-doc.sgml
new file mode 100644
index 00000000000..f1211c0ac6a
--- /dev/null
+++ b/docs/docbook/projdoc/samba-doc.sgml
@@ -0,0 +1,66 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+<!ENTITY UNIX-INSTALL SYSTEM "UNIX_INSTALL.sgml">
+<!ENTITY ENCRYPTION SYSTEM "ENCRYPTION.sgml">
+<!ENTITY MS-Dfs-Setup SYSTEM "msdfs_setup.sgml">
+<!ENTITY PRINTER-DRIVER2 SYSTEM "printer_driver2.sgml">
+<!ENTITY DOMAIN-MEMBER SYSTEM "DOMAIN_MEMBER.sgml">
+<!ENTITY WINBIND SYSTEM "winbind.sgml">
+<!ENTITY NT-Security SYSTEM "NT_Security.sgml">
+<!ENTITY OS2-Client SYSTEM "OS2-Client-HOWTO.sgml">
+<!ENTITY Samba-PDC-HOWTO SYSTEM "Samba-PDC-HOWTO.sgml">
+<!ENTITY CVS-Access SYSTEM "CVS-Access.sgml">
+<!ENTITY IntegratingWithWindows SYSTEM "Integrating-with-Windows.sgml">
+<!ENTITY Samba-PAM SYSTEM "PAM-Authentication-And-Samba.sgml">
+<!ENTITY INDEX-FILE SYSTEM "index.sgml">
+]>
+
+<book id="Samba-Project-Documentation">
+
+<title>SAMBA Project Documentation</title>
+
+<bookinfo>
+ <author>
+ <surname>SAMBA Team</surname>
+ </author>
+ <address><email>samba@samba.org</email></address>
+</bookinfo>
+
+<dedication>
+<title>Abstract</title>
+
+<para>
+<emphasis>Last Update</emphasis> : Tue Jul 31 15:58:03 CDT 2001
+</para>
+
+<para>
+This book is a collection of HOWTOs added to Samba documentation over the years.
+I try to ensure that all are current, but sometimes the is a larger job
+than one person can maintain. The most recent version of this document
+can be found at <ulink url="http://www.samba.org/">http://www.samba.org/</ulink>
+on the "Documentation" page. Please send updates to <ulink
+url="mailto:jerry@samba.org">jerry@samba.org</ulink>.
+</para>
+
+<para>
+Cheers, jerry
+</para>
+
+</dedication>
+
+<!-- Chapters -->
+&UNIX-INSTALL;
+&IntegratingWithWindows;
+&Samba-PAM;
+&MS-Dfs-Setup;
+&NT-Security;
+&PRINTER-DRIVER2;
+&DOMAIN-MEMBER;
+&Samba-PDC-HOWTO;
+&WINBIND;
+&OS2-Client;
+&CVS-Access;
+
+<!-- Autogenerated Index -->
+&INDEX-FILE;
+
+</book>
diff --git a/docs/docbook/projdoc/winbind.sgml b/docs/docbook/projdoc/winbind.sgml
new file mode 100644
index 00000000000..8ea419d758f
--- /dev/null
+++ b/docs/docbook/projdoc/winbind.sgml
@@ -0,0 +1,919 @@
+<chapter id="winbind">
+
+
+<chapterinfo>
+ <author>
+ <firstname>Tim</firstname><surname>Potter</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address><email>tpot@linuxcare.com.au</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Andrew</firstname><surname>Trigdell</surname>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ <address><email>tridge@linuxcare.com.au</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>John</firstname><surname>Trostel</surname>
+ <affiliation>
+ <orgname>Snapserver</orgname>
+ <address><email>jtrostel@snapserver.com</email></address>
+ </affiliation>
+ </author>
+
+
+ <pubdate>16 Oct 2000</pubdate>
+</chapterinfo>
+
+<title>Unified Logons between Windows NT and UNIX using Winbind</title>
+
+<sect1>
+ <title>Abstract</title>
+
+ <para>Integration of UNIX and Microsoft Windows NT through
+ a unified logon has been considered a "holy grail" in heterogeneous
+ computing environments for a long time. We present
+ <emphasis>winbind</emphasis>, a component of the Samba suite
+ of programs as a solution to the unified logon problem. Winbind
+ uses a UNIX implementation
+ of Microsoft RPC calls, Pluggable Authentication Modules, and the Name
+ Service Switch to allow Windows NT domain users to appear and operate
+ as UNIX users on a UNIX machine. This paper describes the winbind
+ system, explaining the functionality it provides, how it is configured,
+ and how it works internally.</para>
+</sect1>
+
+
+<sect1>
+ <title>Introduction</title>
+
+ <para>It is well known that UNIX and Microsoft Windows NT have
+ different models for representing user and group information and
+ use different technologies for implementing them. This fact has
+ made it difficult to integrate the two systems in a satisfactory
+ manner.</para>
+
+ <para>One common solution in use today has been to create
+ identically named user accounts on both the UNIX and Windows systems
+ and use the Samba suite of programs to provide file and print services
+ between the two. This solution is far from perfect however, as
+ adding and deleting users on both sets of machines becomes a chore
+ and two sets of passwords are required both of which
+ can lead to synchronization problems between the UNIX and Windows
+ systems and confusion for users.</para>
+
+ <para>We divide the unified logon problem for UNIX machines into
+ three smaller problems:</para>
+
+ <itemizedlist>
+ <listitem><para>Obtaining Windows NT user and group information
+ </para></listitem>
+
+ <listitem><para>Authenticating Windows NT users
+ </para></listitem>
+
+ <listitem><para>Password changing for Windows NT users
+ </para></listitem>
+ </itemizedlist>
+
+
+ <para>Ideally, a prospective solution to the unified logon problem
+ would satisfy all the above components without duplication of
+ information on the UNIX machines and without creating additional
+ tasks for the system administrator when maintaining users and
+ groups on either system. The winbind system provides a simple
+ and elegant solution to all three components of the unified logon
+ problem.</para>
+</sect1>
+
+
+<sect1>
+ <title>What Winbind Provides</title>
+
+ <para>Winbind unifies UNIX and Windows NT account management by
+ allowing a UNIX box to become a full member of a NT domain. Once
+ this is done the UNIX box will see NT users and groups as if
+ they were native UNIX users and groups, allowing the NT domain
+ to be used in much the same manner that NIS+ is used within
+ UNIX-only environments.</para>
+
+ <para>The end result is that whenever any
+ program on the UNIX machine asks the operating system to lookup
+ a user or group name, the query will be resolved by asking the
+ NT domain controller for the specified domain to do the lookup.
+ Because Winbind hooks into the operating system at a low level
+ (via the NSS name resolution modules in the C library) this
+ redirection to the NT domain controller is completely
+ transparent.</para>
+
+ <para>Users on the UNIX machine can then use NT user and group
+ names as they would use "native" UNIX names. They can chown files
+ so that they are owned by NT domain users or even login to the
+ UNIX machine and run a UNIX X-Window session as a domain user.</para>
+
+ <para>The only obvious indication that Winbind is being used is
+ that user and group names take the form DOMAIN\user and
+ DOMAIN\group. This is necessary as it allows Winbind to determine
+ that redirection to a domain controller is wanted for a particular
+ lookup and which trusted domain is being referenced.</para>
+
+ <para>Additionally, Winbind provides an authentication service
+ that hooks into the Pluggable Authentication Modules (PAM) system
+ to provide authentication via a NT domain to any PAM enabled
+ applications. This capability solves the problem of synchronizing
+ passwords between systems since all passwords are stored in a single
+ location (on the domain controller).</para>
+
+ <sect2>
+ <title>Target Uses</title>
+
+ <para>Winbind is targeted at organizations that have an
+ existing NT based domain infrastructure into which they wish
+ to put UNIX workstations or servers. Winbind will allow these
+ organizations to deploy UNIX workstations without having to
+ maintain a separate account infrastructure. This greatly
+ simplifies the administrative overhead of deploying UNIX
+ workstations into a NT based organization.</para>
+
+ <para>Another interesting way in which we expect Winbind to
+ be used is as a central part of UNIX based appliances. Appliances
+ that provide file and print services to Microsoft based networks
+ will be able to use Winbind to provide seamless integration of
+ the appliance into the domain.</para>
+ </sect2>
+</sect1>
+
+
+
+<sect1>
+ <title>How Winbind Works</title>
+
+ <para>The winbind system is designed around a client/server
+ architecture. A long running <command>winbindd</command> daemon
+ listens on a UNIX domain socket waiting for requests
+ to arrive. These requests are generated by the NSS and PAM
+ clients and processed sequentially.</para>
+
+ <para>The technologies used to implement winbind are described
+ in detail below.</para>
+
+ <sect2>
+ <title>Microsoft Remote Procedure Calls</title>
+
+ <para>Over the last two years, efforts have been underway
+ by various Samba Team members to decode various aspects of
+ the Microsoft Remote Procedure Call (MSRPC) system. This
+ system is used for most network related operations between
+ Windows NT machines including remote management, user authentication
+ and print spooling. Although initially this work was done
+ to aid the implementation of Primary Domain Controller (PDC)
+ functionality in Samba, it has also yielded a body of code which
+ can be used for other purposes.</para>
+
+ <para>Winbind uses various MSRPC calls to enumerate domain users
+ and groups and to obtain detailed information about individual
+ users or groups. Other MSRPC calls can be used to authenticate
+ NT domain users and to change user passwords. By directly querying
+ a Windows PDC for user and group information, winbind maps the
+ NT account information onto UNIX user and group names.</para>
+ </sect2>
+
+ <sect2>
+ <title>Name Service Switch</title>
+
+ <para>The Name Service Switch, or NSS, is a feature that is
+ present in many UNIX operating systems. It allows system
+ information such as hostnames, mail aliases and user information
+ to be resolved from different sources. For example, a standalone
+ UNIX workstation may resolve system information from a series of
+ flat files stored on the local filesystem. A networked workstation
+ may first attempt to resolve system information from local files,
+ and then consult a NIS database for user information or a DNS server
+ for hostname information.</para>
+
+ <para>The NSS application programming interface allows winbind
+ to present itself as a source of system information when
+ resolving UNIX usernames and groups. Winbind uses this interface,
+ and information obtained from a Windows NT server using MSRPC
+ calls to provide a new source of account enumeration. Using standard
+ UNIX library calls, one can enumerate the users and groups on
+ a UNIX machine running winbind and see all users and groups in
+ a NT domain plus any trusted domain as though they were local
+ users and groups.</para>
+
+ <para>The primary control file for NSS is
+ <filename>/etc/nsswitch.conf</filename>.
+ When a UNIX application makes a request to do a lookup
+ the C library looks in <filename>/etc/nsswitch.conf</filename>
+ for a line which matches the service type being requested, for
+ example the "passwd" service type is used when user or group names
+ are looked up. This config line species which implementations
+ of that service should be tried and in what order. If the passwd
+ config line is:</para>
+
+ <para><command>passwd: files example</command></para>
+
+ <para>then the C library will first load a module called
+ <filename>/lib/libnss_files.so</filename> followed by
+ the module <filename>/lib/libnss_example.so</filename>. The
+ C library will dynamically load each of these modules in turn
+ and call resolver functions within the modules to try to resolve
+ the request. Once the request is resolved the C library returns the
+ result to the application.</para>
+
+ <para>This NSS interface provides a very easy way for Winbind
+ to hook into the operating system. All that needs to be done
+ is to put <filename>libnss_winbind.so</filename> in <filename>/lib/</filename>
+ then add "winbind" into <filename>/etc/nsswitch.conf</filename> at
+ the appropriate place. The C library will then call Winbind to
+ resolve user and group names.</para>
+ </sect2>
+
+ <sect2>
+ <title>Pluggable Authentication Modules</title>
+
+ <para>Pluggable Authentication Modules, also known as PAM,
+ is a system for abstracting authentication and authorization
+ technologies. With a PAM module it is possible to specify different
+ authentication methods for different system applications without
+ having to recompile these applications. PAM is also useful
+ for implementing a particular policy for authorization. For example,
+ a system administrator may only allow console logins from users
+ stored in the local password file but only allow users resolved from
+ a NIS database to log in over the network.</para>
+
+ <para>Winbind uses the authentication management and password
+ management PAM interface to integrate Windows NT users into a
+ UNIX system. This allows Windows NT users to log in to a UNIX
+ machine and be authenticated against a suitable Primary Domain
+ Controller. These users can also change their passwords and have
+ this change take effect directly on the Primary Domain Controller.
+ </para>
+
+ <para>PAM is configured by providing control files in the directory
+ <filename>/etc/pam.d/</filename> for each of the services that
+ require authentication. When an authentication request is made
+ by an application the PAM code in the C library looks up this
+ control file to determine what modules to load to do the
+ authentication check and in what order. This interface makes adding
+ a new authentication service for Winbind very easy, all that needs
+ to be done is that the <filename>pam_winbind.so</filename> module
+ is copied to <filename>/lib/security/</filename> and the PAM
+ control files for relevant services are updated to allow
+ authentication via winbind. See the PAM documentation
+ for more details.</para>
+ </sect2>
+
+
+ <sect2>
+ <title>User and Group ID Allocation</title>
+
+ <para>When a user or group is created under Windows NT
+ is it allocated a numerical relative identifier (RID). This is
+ slightly different to UNIX which has a range of numbers that are
+ used to identify users, and the same range in which to identify
+ groups. It is winbind's job to convert RIDs to UNIX id numbers and
+ vice versa. When winbind is configured it is given part of the UNIX
+ user id space and a part of the UNIX group id space in which to
+ store Windows NT users and groups. If a Windows NT user is
+ resolved for the first time, it is allocated the next UNIX id from
+ the range. The same process applies for Windows NT groups. Over
+ time, winbind will have mapped all Windows NT users and groups
+ to UNIX user ids and group ids.</para>
+
+ <para>The results of this mapping are stored persistently in
+ an ID mapping database held in a tdb database). This ensures that
+ RIDs are mapped to UNIX IDs in a consistent way.</para>
+ </sect2>
+
+
+ <sect2>
+ <title>Result Caching</title>
+
+ <para>An active system can generate a lot of user and group
+ name lookups. To reduce the network cost of these lookups winbind
+ uses a caching scheme based on the SAM sequence number supplied
+ by NT domain controllers. User or group information returned
+ by a PDC is cached by winbind along with a sequence number also
+ returned by the PDC. This sequence number is incremented by
+ Windows NT whenever any user or group information is modified. If
+ a cached entry has expired, the sequence number is requested from
+ the PDC and compared against the sequence number of the cached entry.
+ If the sequence numbers do not match, then the cached information
+ is discarded and up to date information is requested directly
+ from the PDC.</para>
+ </sect2>
+</sect1>
+
+
+<sect1>
+ <title>Installation and Configuration</title>
+
+<para>
+Many thanks to John Trostel <ulink
+url="mailto:jtrostel@snapserver.com">jtrostel@snapserver.com</ulink>
+for providing the HOWTO for this section.
+</para>
+
+<para>
+This HOWTO describes how to get winbind services up and running
+to control access and authenticate users on your Linux box using
+the winbind services which come with SAMBA 2.2.2.
+</para>
+
+
+<sect2>
+<title>Introduction</title>
+
+<para>
+This HOWTO describes the procedures used to get winbind up and
+running on my RedHat 7.1 system. Winbind is capable of providing access
+and authentication control for Windows Domain users through an NT
+or Win2K PDC for 'regular' services, such as telnet a nd ftp, as
+well for SAMBA services.
+</para>
+
+<para>
+This HOWTO has been written from a 'RedHat-centric' perspective, so if
+you are using another distribution, you may have to modify the instructions
+somewhat to fit the way your distribution works.
+</para>
+
+
+<itemizedlist>
+<listitem>
+ <para>
+ <emphasis>Why should I to this?</emphasis>
+ </para>
+
+ <para>This allows the SAMBA administrator to rely on the
+ authentication mechanisms on the NT/Win2K PDC for the authentication
+ of domain members. NT/Win2K users no longer need to have separate
+ accounts on the SAMBA server.
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ <emphasis>Who should be reading this document?</emphasis>
+ </para>
+
+ <para>
+ This HOWTO is designed for system administrators. If you are
+ implementing SAMBA on a file server and wish to (fairly easily)
+ integrate existing NT/Win2K users from your PDC onto the
+ SAMBA server, this HOWTO is for you. That said, I am no NT or PAM
+ expert, so you may find a better or easier way to accomplish
+ these tasks.
+ </para>
+</listitem>
+</itemizedlist>
+</sect2>
+
+
+<sect2>
+<title>Requirements</title>
+
+<para>
+If you have a samba configuration file that you are currently
+using... <emphasis>BACK IT UP!</emphasis> If your system already uses PAM,
+<emphasis>back up the <filename>/etc/pam.d</filename> directory
+contents!</emphasis> If you haven't already made a boot disk,
+<emphasis>MAKE ONE NOW!</emphasis>
+</para>
+
+<para>
+Messing with the pam configuration files can make it nearly impossible
+to log in to yourmachine. That's why you want to be able to boot back
+into your machine in single user mode and restore your
+<filename>/etc/pam.d</filename> back to the original state they were in if
+you get frustrated with the way things are going. ;-)
+</para>
+
+<para>
+The latest version of SAMBA (version 2.2.2 as of this writing), now
+includes a functioning winbindd daemon. Please refer to the
+<ulink url="http://samba.org/">main SAMBA web page</ulink> or,
+better yet, your closest SAMBA mirror site for instructions on
+downloading the source code.
+</para>
+
+<para>
+To allow Domain users the ability to access SAMBA shares and
+files, as well as potentially other services provided by your
+SAMBA machine, PAM (pluggable authentication modules) must
+be setup properly on your machine. In order to compile the
+winbind modules, you should have at least the pam libraries resident
+on your system. For recent RedHat systems (7.1, for instance), that
+means <filename>pam-0.74-22</filename>. For best results, it is helpful to also
+install the development packages in <filename>pam-devel-0.74-22</filename>.
+</para>
+
+</sect2>
+
+
+<sect2>
+<title>Testing Things Out</title>
+
+<para>
+Before starting, it is probably best to kill off all the SAMBA
+related daemons running on your server. Kill off all <command>smbd</command>,
+<command>nmbd</command>, and <command>winbindd</command> processes that may
+be running. To use PAM, you will want to make sure that you have the
+standard PAM package (for RedHat) which supplies the <filename>/etc/pam.d</filename>
+directory structure, including the pam modules are used by pam-aware
+services, several pam libraries, and the <filename>/usr/doc</filename>
+and <filename>/usr/man</filename> entries for pam. Winbind built better
+in SAMBA if the pam-devel package was also installed. This package includes
+the header files needed to compile pam-aware applications. For instance,
+my RedHat system has both <filename>pam-0.74-22</filename> and
+<filename>pam-devel-0.74-22</filename> RPMs installed.
+</para>
+
+<sect3>
+<title>Configure and compile SAMBA</title>
+
+<para>
+The configuration and compilation of SAMBA is pretty straightforward.
+The first three steps may not be necessary depending upon
+whether or not you have previously built the Samba binaries.
+</para>
+
+<para><programlisting>
+<prompt>root#</prompt> <command>autoconf</command>
+<prompt>root#</prompt> <command>make clean</command>
+<prompt>root#</prompt> <command>rm config.cache</command>
+<prompt>root#</prompt> <command>./configure --with-winbind</command>
+<prompt>root#</prompt> <command>make</command>
+<prompt>root#</prompt> <command>make install</command>
+</programlisting></para>
+
+
+<para>
+This will, by default, install SAMBA in <filename>/usr/local/samba</filename>.
+See the main SAMBA documentation if you want to install SAMBA somewhere else.
+It will also build the winbindd executable and libraries.
+</para>
+
+</sect3>
+
+<sect3>
+<title>Configure <filename>nsswitch.conf</filename> and the
+winbind libraries</title>
+
+<para>
+The libraries needed to run the <command>winbindd</command> daemon
+through nsswitch need to be copied to their proper locations, so
+</para>
+
+<para>
+<prompt>root#</prompt> <command>cp ../samba/source/nsswitch/libnss_winbind.so /lib</command>
+</para>
+
+<para>
+I also found it necessary to make the following symbolic link:
+</para>
+
+<para>
+<prompt>root#</prompt> <command>ln -s /lib/libnss_winbind.so /lib/libnss_winbind.so.2</command>
+</para>
+
+<para>
+Now, as root you need to edit <filename>/etc/nsswitch.conf</filename> to
+allow user and group entries to be visible from the <command>winbindd</command>
+daemon. My <filename>/etc/nsswitch.conf</filename> file look like
+this after editing:
+</para>
+
+<para><programlisting>
+ passwd: files winbind
+ shadow: files
+ group: files winbind
+</programlisting></para>
+
+<para>
+The libraries needed by the winbind daemon will be automatically
+entered into the <command>ldconfig</command> cache the next time
+your system reboots, but it
+is faster (and you don't need to reboot) if you do it manually:
+</para>
+
+<para>
+<prompt>root#</prompt> <command>/sbin/ldconfig -v | grep winbind</command>
+</para>
+
+<para>
+This makes <filename>libnss_winbind</filename> available to winbindd
+and echos back a check to you.
+</para>
+
+</sect3>
+
+
+<sect3>
+<title>Configure smb.conf</title>
+
+<para>
+Several parameters are needed in the smb.conf file to control
+the behavior of <command>winbindd</command>. Configure
+<filename>smb.conf</filename> These are described in more detail in
+the <ulink url="winbindd.8.html">winbindd(8)</ulink> man page. My
+<filename>smb.conf</filename> file was modified to
+include the following entries in the [global] section:
+</para>
+
+<para><programlisting>
+[global]
+ <...>
+ # separate domain and username with '+', like DOMAIN+username
+ <ulink url="winbindd.8.html#WINBINDSEPARATOR">winbind separator</ulink> = +
+ # use uids from 10000 to 20000 for domain users
+ <ulink url="winbindd.8.html#WINBINDUID">winbind uid</ulink> = 10000-20000
+ # use gids from 10000 to 20000 for domain groups
+ <ulink url="winbindd.8.html#WINBINDGID">winbind gid</ulink> = 10000-20000
+ # allow enumeration of winbind users and groups
+ <ulink url="winbindd.8.html#WINBINDENUMUSERS">winbind enum users</ulink> = yes
+ <ulink url="winbindd.8.html#WINBINDENUMGROUP">winbind enum groups</ulink> = yes
+ # give winbind users a real shell (only needed if they have telnet access)
+ <ulink url="winbindd.8.html#TEMPLATEHOMEDIR">template homedir</ulink> = /home/winnt/%D/%U
+ <ulink url="winbindd.8.html#TEMPLATESHELL">template shell</ulink> = /bin/bash
+</programlisting></para>
+
+</sect3>
+
+
+<sect3>
+<title>Join the SAMBA server to the PDC domain</title>
+
+<para>
+Enter the following command to make the SAMBA server join the
+PDC domain, where <replaceable>DOMAIN</replaceable> is the name of
+your Windows domain and <replaceable>Administrator</replaceable> is
+a domain user who has administrative privileges in the domain.
+</para>
+
+
+<para>
+<prompt>root#</prompt> <command>/usr/local/samba/bin/smbpasswd -j DOMAIN -r PDC -U Administrator</command>
+</para>
+
+
+<para>
+The proper response to the command should be: "Joined the domain
+<replaceable>DOMAIN</replaceable>" where <replaceable>DOMAIN</replaceable>
+is your DOMAIN name.
+</para>
+
+</sect3>
+
+
+<sect3>
+<title>Start up the winbindd daemon and test it!</title>
+
+<para>
+Eventually, you will want to modify your smb startup script to
+automatically invoke the winbindd daemon when the other parts of
+SAMBA start, but it is possible to test out just the winbind
+portion first. To start up winbind services, enter the following
+command as root:
+</para>
+
+<para>
+<prompt>root#</prompt> <command>/usr/local/samba/bin/winbindd</command>
+</para>
+
+<para>
+I'm always paranoid and like to make sure the daemon
+is really running...
+</para>
+
+<para>
+<prompt>root#</prompt> <command>ps -ae | grep winbindd</command>
+</para>
+<para>
+This command should produce output like this, if the daemon is running
+</para>
+<para>
+3025 ? 00:00:00 winbindd
+</para>
+
+<para>
+Now... for the real test, try to get some information about the
+users on your PDC
+</para>
+
+<para>
+<prompt>root#</prompt> <command>/usr/local/samba/bin/wbinfo -u</command>
+</para>
+
+<para>
+This should echo back a list of users on your Windows users on
+your PDC. For example, I get the following response:
+</para>
+
+<para><programlisting>
+CEO+Administrator
+CEO+burdell
+CEO+Guest
+CEO+jt-ad
+CEO+krbtgt
+CEO+TsInternetUser
+</programlisting></para>
+
+<para>
+Obviously, I have named my domain 'CEO' and my <parameter>winbindd
+separator</parameter> is '+'.
+</para>
+
+<para>
+You can do the same sort of thing to get group information from
+the PDC:
+</para>
+
+<para><programlisting>
+<prompt>root#</prompt> <command>/usr/local/samba/bin/wbinfo -g</command>
+CEO+Domain Admins
+CEO+Domain Users
+CEO+Domain Guests
+CEO+Domain Computers
+CEO+Domain Controllers
+CEO+Cert Publishers
+CEO+Schema Admins
+CEO+Enterprise Admins
+CEO+Group Policy Creator Owners
+</programlisting></para>
+
+<para>
+The function 'getent' can now be used to get unified
+lists of both local and PDC users and groups.
+Try the following command:
+</para>
+
+<para>
+<prompt>root#</prompt> <command>getent passwd</command>
+</para>
+
+<para>
+You should get a list that looks like your <filename>/etc/passwd</filename>
+list followed by the domain users with their new uids, gids, home
+directories and default shells.
+</para>
+
+<para>
+The same thing can be done for groups with the command
+</para>
+
+<para>
+<prompt>root#</prompt> <command>getent group</command>
+</para>
+
+</sect3>
+
+
+<sect3>
+<title>Fix the <filename>/etc/rc.d/init.d/smb</filename> startup files</title>
+
+<para>
+The <command>winbindd</command> daemon needs to start up after the
+<command>smbd</command> and <command>nmbd</command> daemons are running.
+To accomplish this task, you need to modify the <filename>/etc/init.d/smb</filename>
+script to add commands to invoke this daemon in the proper sequence. My
+<filename>/etc/init.d/smb</filename> file starts up <command>smbd</command>,
+<command>nmbd</command>, and <command>winbindd</command> from the
+<filename>/usr/local/samba/bin</filename> directory directly. The 'start'
+function in the script looks like this:
+</para>
+
+<para><programlisting>
+start() {
+ KIND="SMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/smbd $SMBDOPTIONS
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/nmbd $NMBDOPTIONS
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/winbindd
+ RETVAL3=$?
+ echo
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] && touch /var/lock/subsys/smb || \
+ RETVAL=1
+ return $RETVAL
+}
+</programlisting></para>
+
+<para>
+The 'stop' function has a corresponding entry to shut down the
+services and look s like this:
+</para>
+
+<para><programlisting>
+stop() {
+ KIND="SMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc smbd
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc nmbd
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Shutting down $KIND services: "
+ killproc winbindd
+ RETVAL3=$?
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] && rm -f /var/lock/subsys/smb
+ echo ""
+ return $RETVAL
+}
+</programlisting></para>
+
+<para>
+If you restart the <command>smbd</command>, <command>nmbd</command>,
+and <command>winbindd</command> daemons at this point, you
+should be able to connect to the samba server as a domain member just as
+if you were a local user.
+</para>
+
+</sect3>
+
+
+
+<sect3>
+<title>Configure Winbind and PAM</title>
+
+<para>
+If you have made it this far, you know that winbindd and samba are working
+together. If you want to use winbind to provide authentication for other
+services, keep reading. The pam configuration files need to be altered in
+this step. (Did you remember to make backups of your original
+<filename>/etc/pam.d</filename> files? If not, do it now.)
+</para>
+
+<para>
+You will need a pam module to use winbindd with these other services. This
+module will be compiled in the <filename>../source/nsswitch</filename> directory
+by invoking the command
+</para>
+
+<para>
+<prompt>root#</prompt> <command>make nsswitch/pam_winbind.so</command>
+</para>
+
+<para>
+from the <filename>../source</filename> directory. The
+<filename>pam_winbind.so</filename> file should be copied to the location of
+your other pam security modules. On my RedHat system, this was the
+<filename>/lib/security</filename> directory.
+</para>
+
+<para>
+<prompt>root#</prompt> <command>cp ../samba/source/nsswitch/pam_winbind.so /lib/security</command>
+</para>
+
+<para>
+The <filename>/etc/pam.d/samba</filename> file does not need to be changed. I
+just left this fileas it was:
+</para>
+
+
+<para><programlisting>
+auth required /lib/security/pam_stack.so service=system-auth
+account required /lib/security/pam_stack.so service=system-auth
+</programlisting></para>
+
+<para>
+The other services that I modified to allow the use of winbind
+as an authentication service were the normal login on the console (or a terminal
+session), telnet logins, and ftp service. In order to enable these
+services, you may first need to change the entries in
+<filename>/etc/xinetd.d</filename> (or <filename>/etc/inetd.conf</filename>).
+RedHat 7.1 uses the new xinetd.d structure, in this case you need
+to change the lines in <filename>/etc/xinetd.d/telnet</filename>
+and <filename>/etc/xinetd.d/wu-ftp</filename> from
+</para>
+
+<para><programlisting>
+enable = no
+</programlisting></para>
+
+<para>
+to
+</para>
+
+<para><programlisting>
+enable = yes
+</programlisting></para>
+
+<para>
+For ftp services to work properly, you will also need to either
+have individual directories for the domain users already present on
+the server, or change the home directory template to a general
+directory for all domain users. These can be easily set using
+the <filename>smb.conf</filename> global entry
+<command>template homedir</command>.
+</para>
+
+<para>
+The <filename>/etc/pam.d/ftp</filename> file can be changed
+to allow winbind ftp access in a manner similar to the
+samba file. My <filename>/etc/pam.d/ftp</filename> file was
+changed to look like this:
+</para>
+
+<para><programlisting>
+auth required /lib/security/pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_shells.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth
+</programlisting></para>
+
+<para>
+The <filename>/etc/pam.d/login</filename> file can be changed nearly the
+same way. It now looks like this:
+</para>
+
+<para><programlisting>
+auth required /lib/security/pam_securetty.so
+auth sufficient /lib/security/pam_winbind.so
+auth sufficient /lib/security/pam_unix.so use_first_pass
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_nologin.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+password required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth
+session optional /lib/security/pam_console.so
+</programlisting></para>
+
+<para>
+In this case, I added the <command>auth sufficient /lib/security/pam_winbind.so</command>
+lines as before, but also added the <command>required pam_securetty.so</command>
+above it, to disallow root logins over the network. I also added a
+<command>sufficient /lib/security/pam_unix.so use_first_pass</command>
+line after the <command>winbind.so</command> line to get rid of annoying
+double prompts for passwords.
+</para>
+
+
+</sect3>
+
+</sect2>
+
+</sect1>
+
+<sect1>
+ <title>Limitations</title>
+
+ <para>Winbind has a number of limitations in its current
+ released version that we hope to overcome in future
+ releases:</para>
+
+ <itemizedlist>
+ <listitem><para>Winbind is currently only available for
+ the Linux operating system, although ports to other operating
+ systems are certainly possible. For such ports to be feasible,
+ we require the C library of the target operating system to
+ support the Name Service Switch and Pluggable Authentication
+ Modules systems. This is becoming more common as NSS and
+ PAM gain support among UNIX vendors.</para></listitem>
+
+ <listitem><para>The mappings of Windows NT RIDs to UNIX ids
+ is not made algorithmically and depends on the order in which
+ unmapped users or groups are seen by winbind. It may be difficult
+ to recover the mappings of rid to UNIX id mapping if the file
+ containing this information is corrupted or destroyed.</para>
+ </listitem>
+
+ <listitem><para>Currently the winbind PAM module does not take
+ into account possible workstation and logon time restrictions
+ that may be been set for Windows NT users.</para></listitem>
+ </itemizedlist>
+</sect1>
+
+
+<sect1>
+ <title>Conclusion</title>
+
+ <para>The winbind system, through the use of the Name Service
+ Switch, Pluggable Authentication Modules, and appropriate
+ Microsoft RPC calls have allowed us to provide seamless
+ integration of Microsoft Windows NT domain users on a
+ UNIX system. The result is a great reduction in the administrative
+ cost of running a mixed UNIX and NT network.</para>
+
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/scripts/README.ldp_print b/docs/docbook/scripts/README.ldp_print
new file mode 100644
index 00000000000..8d61a855343
--- /dev/null
+++ b/docs/docbook/scripts/README.ldp_print
@@ -0,0 +1,60 @@
+
+######################################################################
+ ldp_print - print tool/script for DocBook SGML/XML documents
+######################################################################
+
+This process/script is used in the production environment for the
+LDP. It relies on the HTMLDOC software package (GPL'ed) which can be
+obtained from the Easy Software Products (c) web site:
+
+ http://www.easysw.com/htmldoc/
+
+This process creates a PDF variant from the single-file HTML
+representation of a DocBook SGML (or XML) instance. The simple
+wrapper script (ldp_print) assumes that the file was created using
+{open}jade in a manner similar to:
+
+ jade -t sgml -i html -V nochunks -d $style $fname > $fname.html
+
+Give the script the filename as an argument. It will then parse the
+file into 'title.html' and 'body.html' and send each to htmldoc (as
+the corresponding title page and body of the document).
+
+
+CAVEATS
+=======
+
+o Assumes perl is in /usr/bin; adjust if necessary
+
+o You may need to specify where the htmldoc executable resides.
+ The script assumes it's within your $PATH.
+
+o If you want Postscript as an output variant, uncomment the
+ appropriate lines (see below).
+
+o Relies on output from a DocBook instance created via DSSSL/{open}jade!
+
+o Cleans up (removes) the intermediate files it creates (but not the
+ PDF or Postscript files, obviously!)
+
+o Works silently; PDF (PostScript) will be created in the same directory
+ as was specified for the input (single-file HTML) file.
+
+o Provided without warranty or support!
+
+o I ran into a problem with htmldoc v1.8.8 which required a source
+ code change (I was getting a core dump from the htmldoc process).
+ Here is the change required:
+
+ htmldoc/ps-pdf.cxx :
+ 3662,3665d3661
+ < /* gjf = 11Oct2000 */
+ < if( temprow == NULL )
+ < break;
+ <
+
+
+====
+gferg (at) sgi.com / Ferg
+11 Jan 2000
+
diff --git a/docs/docbook/scripts/collateindex.pl b/docs/docbook/scripts/collateindex.pl
new file mode 100644
index 00000000000..fd757edb320
--- /dev/null
+++ b/docs/docbook/scripts/collateindex.pl
@@ -0,0 +1,595 @@
+# -*- Perl -*-
+#
+
+use Getopt::Std;
+
+$usage = "Usage: $0 <opts> file
+Where <opts> are:
+ -p Link to points in the document. The default is to link
+ to the closest containing section.
+ -g Group terms with IndexDiv based on the first letter
+ of the term (or its sortas attribute).
+ (This probably doesn't handle i10n particularly well)
+ -s name Name the IndexDiv that contains symbols. The default
+ is 'Symbols'. Meaningless if -g is not used.
+ -t name Title for the index.
+ -P file Read a preamble from file. The content of file will
+ be inserted before the <index> tag.
+ -i id The ID for the <index> tag.
+ -o file Output to file. Defaults to stdout.
+ -S scope Scope of the index, must be 'all', 'local', or 'global'.
+ If unspecified, 'all' is assumed.
+ -I scope The implied scope, must be 'all', 'local', or 'global'.
+ IndexTerms which do not specify a scope will have the
+ implied scope. If unspecified, 'all' is assumed.
+ -x Make a SetIndex.
+ -f Force the output file to be written, even if it appears
+ to have been edited by hand.
+ -N New index (generates an empty index file).
+ file The file containing index data generated by Jade
+ with the DocBook HTML Stylesheet.\n";
+
+die $usage if ! getopts('Dfgi:NpP:s:o:S:I:t:x');
+
+$linkpoints = $opt_p;
+$lettergroups = $opt_g;
+$symbolsname = $opt_s || "Symbols";
+$title = $opt_t;
+$preamble = $opt_P;
+$outfile = $opt_o || '-';
+$indexid = $opt_i;
+$scope = uc($opt_S) || 'ALL';
+$impliedscope = uc($opt_I) || 'ALL';
+$setindex = $opt_x;
+$forceoutput = $opt_f;
+$newindex = $opt_N;
+$debug = $opt_D;
+
+$indextag = $setindex ? 'setindex' : 'index';
+
+if ($newindex) {
+ safe_open(*OUT, $outfile);
+ if ($indexid) {
+ print OUT "<$indextag id='$indexid'>\n\n";
+ } else {
+ print OUT "<$indextag>\n\n";
+ }
+
+ print OUT "<!-- This file was produced by collateindex.pl. -->\n";
+ print OUT "<!-- Remove this comment if you edit this file by hand! -->\n";
+
+ print OUT "</$indextag>\n";
+ exit 0;
+}
+
+$dat = shift @ARGV || die $usage;
+die "$0: cannot find $dat.\n" if ! -f $dat;
+
+%legal_scopes = ('ALL' => 1, 'LOCAL' => 1, 'GLOBAL' => 1);
+if ($scope && !$legal_scopes{$scope}) {
+ die "Invalid scope.\n$usage\n";
+}
+if ($impliedscope && !$legal_scopes{$impliedscope}) {
+ die "Invalid implied scope.\n$usage\n";
+}
+
+@term = ();
+%id = ();
+
+$termcount = 0;
+
+print STDERR "Processing $dat...\n";
+
+# Read the index file, creating an array of objects. Each object
+# represents and indexterm and has fields for the content of the
+# indexterm
+
+open (F, $dat);
+while (<F>) {
+ chop;
+
+ if (/^\/indexterm/i) {
+ push (@term, $idx);
+ next;
+ }
+
+ if (/^indexterm (.*)$/i) {
+ $termcount++;
+ $idx = {};
+ $idx->{'zone'} = {};
+ $idx->{'href'} = $1;
+ $idx->{'count'} = $termcount;
+ $idx->{'scope'} = $impliedscope;
+ next;
+ }
+
+ if (/^indexpoint (.*)$/i) {
+ $idx->{'hrefpoint'} = $1;
+ next;
+ }
+
+ if (/^title (.*)$/i) {
+ $idx->{'title'} = $1;
+ next;
+ }
+
+ if (/^primary[\[ ](.*)$/i) {
+ if (/^primary\[(.*?)\] (.*)$/i) {
+ $idx->{'psortas'} = $1;
+ $idx->{'primary'} = $2;
+ } else {
+ $idx->{'psortas'} = $1;
+ $idx->{'primary'} = $1;
+ }
+ next;
+ }
+
+ if (/^secondary[\[ ](.*)$/i) {
+ if (/^secondary\[(.*?)\] (.*)$/i) {
+ $idx->{'ssortas'} = $1;
+ $idx->{'secondary'} = $2;
+ } else {
+ $idx->{'ssortas'} = $1;
+ $idx->{'secondary'} = $1;
+ }
+ next;
+ }
+
+ if (/^tertiary[\[ ](.*)$/i) {
+ if (/^tertiary\[(.*?)\] (.*)$/i) {
+ $idx->{'tsortas'} = $1;
+ $idx->{'tertiary'} = $2;
+ } else {
+ $idx->{'tsortas'} = $1;
+ $idx->{'tertiary'} = $1;
+ }
+ next;
+ }
+
+ if (/^see (.*)$/i) {
+ $idx->{'see'} = $1;
+ next;
+ }
+
+ if (/^seealso (.*)$/i) {
+ $idx->{'seealso'} = $1;
+ next;
+ }
+
+ if (/^significance (.*)$/i) {
+ $idx->{'significance'} = $1;
+ next;
+ }
+
+ if (/^class (.*)$/i) {
+ $idx->{'class'} = $1;
+ next;
+ }
+
+ if (/^scope (.*)$/i) {
+ $idx->{'scope'} = uc($1);
+ next;
+ }
+
+ if (/^startref (.*)$/i) {
+ $idx->{'startref'} = $1;
+ next;
+ }
+
+ if (/^id (.*)$/i) {
+ $idx->{'id'} = $1;
+ $id{$1} = $idx;
+ next;
+ }
+
+ if (/^zone (.*)$/i) {
+ my($href) = $1;
+ $_ = scalar(<F>);
+ chop;
+ die "Bad zone: $_\n" if !/^title (.*)$/i;
+ $idx->{'zone'}->{$href} = $1;
+ next;
+ }
+
+ die "Unrecognized: $_\n";
+}
+close (F);
+
+print STDERR "$termcount entries loaded...\n";
+
+# Fixup the startrefs...
+# In DocBook, STARTREF is a #CONREF attribute; support this by copying
+# all of the fields from the indexterm with the id specified by STARTREF
+# to the indexterm that has the STARTREF.
+foreach $idx (@term) {
+ my($ididx, $field);
+ if ($idx->{'startref'}) {
+ $ididx = $id{$idx->{'startref'}};
+ foreach $field ('primary', 'secondary', 'tertiary', 'see', 'seealso',
+ 'psortas', 'ssortas', 'tsortas', 'significance',
+ 'class', 'scope') {
+ $idx->{$field} = $ididx->{$field};
+ }
+ }
+}
+
+# Sort the index terms
+@term = sort termsort @term;
+
+# Move all of the non-alphabetic entries to the front of the index.
+@term = sortsymbols(@term);
+
+safe_open(*OUT, $outfile);
+
+# Write the index...
+if ($indexid) {
+ print OUT "<$indextag id='$indexid'>\n\n";
+} else {
+ print OUT "<$indextag>\n\n";
+}
+
+print OUT "<!-- This file was produced by collateindex.pl. -->\n";
+print OUT "<!-- Remove this comment if you edit this file by hand! -->\n";
+
+print OUT "<!-- ULINK is abused here.
+
+ The URL attribute holds the URL that points from the index entry
+ back to the appropriate place in the output produced by the HTML
+ stylesheet. (It's much easier to calculate this URL in the first
+ pass.)
+
+ The Role attribute holds the ID (either real or manufactured) of
+ the corresponding INDEXTERM. This is used by the print backends
+ to produce page numbers.
+
+ The entries below are sorted and collated into the correct order.
+ Duplicates may be removed in the HTML backend, but in the print
+ backends, it is impossible to suppress duplicate pages or coalesce
+ sequences of pages into a range.
+-->\n\n";
+
+print OUT "<title>$title</title>\n\n" if $title;
+
+$last = {}; # the last indexterm we processed
+$first = 1; # this is the first one
+$group = ""; # we're not in a group yet
+$lastout = ""; # we've not put anything out yet
+
+foreach $idx (@term) {
+ next if $idx->{'startref'}; # no way to represent spans...
+ next if ($idx->{'scope'} eq 'LOCAL') && ($scope eq 'GLOBAL');
+ next if ($idx->{'scope'} eq 'GLOBAL') && ($scope eq 'LOCAL');
+ next if &same($idx, $last); # suppress duplicates
+
+ $termcount--;
+
+ # If primary changes, output a whole new index term, otherwise just
+ # output another secondary or tertiary, as appropriate. We know from
+ # sorting that the terms will always be in the right order.
+ if (!&tsame($last, $idx, 'primary')) {
+ print "DIFF PRIM\n" if $debug;
+ &end_entry() if not $first;
+
+ if ($lettergroups) {
+ # If we're grouping, make the right indexdivs
+ $letter = $idx->{'psortas'};
+ $letter = $idx->{'primary'} if !$letter;
+ $letter = uc(substr($letter, 0, 1));
+
+ # symbols are a special case
+ if (($letter lt 'A') || ($letter gt 'Z')) {
+ if (($group eq '')
+ || (($group ge 'A') && ($group le 'Z'))) {
+ print OUT "</indexdiv>\n" if !$first;
+ print OUT "<indexdiv><title>$symbolsname</title>\n\n";
+ $group = $letter;
+ }
+ } elsif (($group eq '') || ($group ne $letter)) {
+ print OUT "</indexdiv>\n" if !$first;
+ print OUT "<indexdiv><title>$letter</title>\n\n";
+ $group = $letter;
+ }
+ }
+
+ $first = 0; # there can only be on first ;-)
+
+ print OUT "<indexentry>\n";
+ print OUT " <primaryie>", $idx->{'primary'};
+ $lastout = "primaryie";
+
+ if ($idx->{'secondary'}) {
+ print OUT "\n </primaryie>\n";
+ print OUT " <secondaryie>", $idx->{'secondary'};
+ $lastout = "secondaryie";
+ };
+
+ if ($idx->{'tertiary'}) {
+ print OUT "\n </secondaryie>\n";
+ print OUT " <tertiaryie>", $idx->{'tertiary'};
+ $lastout = "tertiaryie";
+ }
+ } elsif (!&tsame($last, $idx, 'secondary')) {
+ print "DIFF SEC\n" if $debug;
+
+ print OUT "\n </$lastout>\n" if $lastout;
+
+ print OUT " <secondaryie>", $idx->{'secondary'};
+ $lastout = "secondaryie";
+ if ($idx->{'tertiary'}) {
+ print OUT "\n </secondaryie>\n";
+ print OUT " <tertiaryie>", $idx->{'tertiary'};
+ $lastout = "tertiaryie";
+ }
+ } elsif (!&tsame($last, $idx, 'tertiary')) {
+ print "DIFF TERT\n" if $debug;
+
+ print OUT "\n </$lastout>\n" if $lastout;
+
+ if ($idx->{'tertiary'}) {
+ print OUT " <tertiaryie>", $idx->{'tertiary'};
+ $lastout = "tertiaryie";
+ }
+ }
+
+ &print_term($idx);
+
+ $last = $idx;
+}
+
+# Termcount is > 0 iff some entries were skipped.
+print STDERR "$termcount entries ignored...\n";
+
+&end_entry();
+
+print OUT "</indexdiv>\n" if $lettergroups;
+print OUT "</$indextag>\n";
+
+close (OUT);
+
+print STDERR "Done.\n";
+
+sub same {
+ my($a) = shift;
+ my($b) = shift;
+
+ my($aP) = $a->{'psortas'} || $a->{'primary'};
+ my($aS) = $a->{'ssortas'} || $a->{'secondary'};
+ my($aT) = $a->{'tsortas'} || $a->{'tertiary'};
+
+ my($bP) = $b->{'psortas'} || $b->{'primary'};
+ my($bS) = $b->{'ssortas'} || $b->{'secondary'};
+ my($bT) = $b->{'tsortas'} || $b->{'tertiary'};
+
+ my($same);
+
+ $aP =~ s/^\s*//; $aP =~ s/\s*$//; $aP = uc($aP);
+ $aS =~ s/^\s*//; $aS =~ s/\s*$//; $aS = uc($aS);
+ $aT =~ s/^\s*//; $aT =~ s/\s*$//; $aT = uc($aT);
+ $bP =~ s/^\s*//; $bP =~ s/\s*$//; $bP = uc($bP);
+ $bS =~ s/^\s*//; $bS =~ s/\s*$//; $bS = uc($bS);
+ $bT =~ s/^\s*//; $bT =~ s/\s*$//; $bT = uc($bT);
+
+# print "[$aP]=[$bP]\n";
+# print "[$aS]=[$bS]\n";
+# print "[$aT]=[$bT]\n";
+
+ # Two index terms are the same if:
+ # 1. the primary, secondary, and tertiary entries are the same
+ # (or have the same SORTAS)
+ # AND
+ # 2. They occur in the same titled section
+ # AND
+ # 3. They point to the same place
+ #
+ # Notes: Scope is used to suppress some entries, but can't be used
+ # for comparing duplicates.
+ # Interpretation of "the same place" depends on whether or
+ # not $linkpoints is true.
+
+ $same = (($aP eq $bP)
+ && ($aS eq $bS)
+ && ($aT eq $bT)
+ && ($a->{'title'} eq $b->{'title'})
+ && ($a->{'href'} eq $b->{'href'}));
+
+ # If we're linking to points, they're only the same if they link
+ # to exactly the same spot. (surely this is redundant?)
+ $same = $same && ($a->{'hrefpoint'} eq $b->{'hrefpoint'})
+ if $linkpoints;
+
+ $same;
+}
+
+sub tsame {
+ # Unlike same(), tsame only compares a single term
+ my($a) = shift;
+ my($b) = shift;
+ my($term) = shift;
+ my($sterm) = substr($term, 0, 1) . "sortas";
+ my($A, $B);
+
+ $A = $a->{$sterm} || $a->{$term};
+ $B = $b->{$sterm} || $b->{$term};
+
+ $A =~ s/^\s*//; $A =~ s/\s*$//; $A = uc($A);
+ $B =~ s/^\s*//; $B =~ s/\s*$//; $B = uc($B);
+
+ return $A eq $B;
+}
+
+sub end_entry {
+ # End any open elements...
+ print OUT "\n </$lastout>\n" if $lastout;
+ print OUT "</indexentry>\n\n";
+ $lastout = "";
+}
+
+sub print_term {
+ # Print out the links for an indexterm. There can be more than
+ # one if the term has a ZONE that points to more than one place.
+ # (do we do the right thing in that case?)
+ my($idx) = shift;
+ my($key, $indent, @hrefs);
+ my(%href) = ();
+ my(%phref) = ();
+
+ $indent = " ";
+
+ if ($idx->{'see'}) {
+ # it'd be nice to make this a link...
+ if ($lastout) {
+ print OUT "\n </$lastout>\n";
+ $lastout = "";
+ }
+ print OUT $indent, "<seeie>", $idx->{'see'}, "</seeie>\n";
+ return;
+ }
+
+ if ($idx->{'seealso'}) {
+ # it'd be nice to make this a link...
+ if ($lastout) {
+ print OUT "\n </$lastout>\n";
+ $lastout = "";
+ }
+ print OUT $indent, "<seealsoie>", $idx->{'seealso'}, "</seealsoie>\n";
+ return;
+ }
+
+ if (keys %{$idx->{'zone'}}) {
+ foreach $key (keys %{$idx->{'zone'}}) {
+ $href{$key} = $idx->{'zone'}->{$key};
+ $phref{$key} = $idx->{'zone'}->{$key};
+ }
+ } else {
+ $href{$idx->{'href'}} = $idx->{'title'};
+ $phref{$idx->{'href'}} = $idx->{'hrefpoint'};
+ }
+
+ # We can't use <LINK> because we don't know the ID of the term in the
+ # original source (and, in fact, it might not have one).
+ print OUT ",\n";
+ @hrefs = keys %href;
+ while (@hrefs) {
+ my($linkend) = "";
+ my($role) = "";
+ $key = shift @hrefs;
+ if ($linkpoints) {
+ $linkend = $phref{$key};
+ } else {
+ $linkend = $key;
+ }
+
+ $role = $linkend;
+ $role = $1 if $role =~ /\#(.*)$/;
+
+ print OUT $indent;
+ print OUT "<ulink url=\"$linkend\" role=\"$role\">";
+ print OUT "<emphasis>" if ($idx->{'significance'} eq 'PREFERRED');
+ print OUT $href{$key};
+ print OUT "</emphasis>" if ($idx->{'significance'} eq 'PREFERRED');
+ print OUT "</ulink>";
+ }
+}
+
+sub termsort {
+ my($aP) = $a->{'psortas'} || $a->{'primary'};
+ my($aS) = $a->{'ssortas'} || $a->{'secondary'};
+ my($aT) = $a->{'tsortas'} || $a->{'tertiary'};
+ my($ap) = $a->{'count'};
+
+ my($bP) = $b->{'psortas'} || $b->{'primary'};
+ my($bS) = $b->{'ssortas'} || $b->{'secondary'};
+ my($bT) = $b->{'tsortas'} || $b->{'tertiary'};
+ my($bp) = $b->{'count'};
+
+ $aP =~ s/^\s*//; $aP =~ s/\s*$//; $aP = uc($aP);
+ $aS =~ s/^\s*//; $aS =~ s/\s*$//; $aS = uc($aS);
+ $aT =~ s/^\s*//; $aT =~ s/\s*$//; $aT = uc($aT);
+ $bP =~ s/^\s*//; $bP =~ s/\s*$//; $bP = uc($bP);
+ $bS =~ s/^\s*//; $bS =~ s/\s*$//; $bS = uc($bS);
+ $bT =~ s/^\s*//; $bT =~ s/\s*$//; $bT = uc($bT);
+
+ if ($aP eq $bP) {
+ if ($aS eq $bS) {
+ if ($aT eq $bT) {
+ # make sure seealso's always sort to the bottom
+ return 1 if ($a->{'seealso'});
+ return -1 if ($b->{'seealso'});
+ # if everything else is the same, keep these elements
+ # in document order (so the index links are in the right
+ # order)
+ return $ap <=> $bp;
+ } else {
+ return $aT cmp $bT;
+ }
+ } else {
+ return $aS cmp $bS;
+ }
+ } else {
+ return $aP cmp $bP;
+ }
+}
+
+sub sortsymbols {
+ my(@term) = @_;
+ my(@new) = ();
+ my(@sym) = ();
+ my($letter);
+ my($idx);
+
+ # Move the non-letter things to the front. Should digits be thier
+ # own group? Maybe...
+ foreach $idx (@term) {
+ $letter = $idx->{'psortas'};
+ $letter = $idx->{'primary'} if !$letter;
+ $letter = uc(substr($letter, 0, 1));
+
+ if (($letter lt 'A') || ($letter gt 'Z')) {
+ push (@sym, $idx);
+ } else {
+ push (@new, $idx);
+ }
+ }
+
+ return (@sym, @new);
+}
+
+sub safe_open {
+ local(*OUT) = shift;
+ local(*F, $_);
+
+ if (($outfile ne '-') && (!$forceoutput)) {
+ my($handedit) = 1;
+ if (open (OUT, $outfile)) {
+ while (<OUT>) {
+ if (/<!-- Remove this comment if you edit this file by hand! -->/){
+ $handedit = 0;
+ last;
+ }
+ }
+ close (OUT);
+ } else {
+ $handedit = 0;
+ }
+
+ if ($handedit) {
+ print "\n$outfile appears to have been edited by hand; use -f or\n";
+ print " change the output file.\n";
+ exit 1;
+ }
+ }
+
+ open (OUT, ">$outfile") || die "$usage\nCannot write to $outfile.\n";
+
+ if ($preamble) {
+ # Copy the preamble
+ if (open(F, $preamble)) {
+ while (<F>) {
+ print OUT $_;
+ }
+ close(F);
+ } else {
+ warn "$0: cannot open preamble $preamble.\n";
+ }
+ }
+}
diff --git a/docs/docbook/scripts/fix_print_html.lib b/docs/docbook/scripts/fix_print_html.lib
new file mode 100644
index 00000000000..e8a9aaa4c77
--- /dev/null
+++ b/docs/docbook/scripts/fix_print_html.lib
@@ -0,0 +1,172 @@
+#
+# fix_print_html.lib
+#
+# Dan Scott / <dan.scott (at) acm.org>
+# Ferg / <gferg (at) sgi.com>
+#
+# Used to prepare single-file HTML variant for PDF/Postscript creation
+# thru htmldoc.
+#
+# log:
+# 16Oct2000 - initial entry <gferg (at) sgi.com>
+# 03Apr2001 - fix for <preface>
+#
+#
+
+sub fix_print_html {
+
+ my($in,$out,$ttl) = @_;
+
+ open(IN_FILE, "< $in") || do {
+ print "fix_print_html: cannot open $in: $!\n";
+ return 0;
+ };
+
+ my($buf,$ttl_buf) = '';
+ my($indx) = -1;
+ my($is_article) = 0;
+ while(<IN_FILE>) {
+
+ if( $indx == 1 ) {
+
+ # ignore everything until we see the chapter or sect
+ #
+ if( $_ =~ /CLASS="CHAP/i || $_ =~ /CLASS="PREF/i ) {
+
+ $buf .= $_;
+ $indx++;
+
+ } elsif( $_ =~ /CLASS="SECT/ || $_ =~ /CLASS="sect/ ) {
+
+ $buf .= $_;
+ $indx++;
+ $is_article = 1;
+
+ } else {
+ next;
+ }
+
+ } elsif( $indx == 0 ) {
+
+ # write out the title page file
+ #
+ if( $_ =~ /CLASS="TOC"/ ) {
+
+ $ttl_buf .= "></DIV>\n</BODY>\n</HTML>\n";
+ $ttl_buf =~ s/<\/H1\n/<\/H1\n><P><BR><BR\n/ms;
+
+ open(TOC_FILE, "> $ttl") || do {
+ print "fix_print_html: cannot open $ttl: $!\n";
+ close(IN_FILE);
+ return 0;
+ };
+ print TOC_FILE $ttl_buf;
+ close(TOC_FILE);
+ $ttl_buf = '';
+ $indx++;
+
+ } else {
+ $ttl_buf .= $_;
+ }
+
+ } elsif( $indx < 0 ) {
+
+ # up to this point, both buffers get the line
+ #
+ if( $_ =~ /CLASS="TITLEPAGE"/ ) {
+
+ $ttl_buf .= $_ . ">\n<P>\n<BR><BR><BR><BR>\n<\/P\n";
+ $indx++;
+
+ } else {
+ $buf .= $_;
+ $ttl_buf .= $_;
+ }
+
+ } else {
+
+ $buf .= $_;
+ }
+ }
+ close(IN_FILE);
+
+ open(OUT_FILE, "> $out") || do {
+ print "fix_print_html: cannot open $out: $!\n";
+ return 0;
+ };
+
+
+ # make these corrections and write out the file
+ #
+
+ $buf =~ s/(\n><LI\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ $buf =~ s/(\n><LI\n><DIV\nCLASS="FORMALPARA"\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ $buf =~ s/(\n><LI\nSTYLE="[^\"]+"\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ if( $is_article == 0 ) {
+ $buf =~ s/(\nCLASS="SECT[TION\d]+"\n>)<H1\n(.*?)<\/H1/$1<H2\n$2<\/H2/gims;
+ $buf =~ s/(\nCLASS="SECT[TION\d]+"\n><HR>)<H1\n(.*?)<\/H1/$1<H2\n$2<\/H2/gims;
+ }
+ $buf =~ s/<H1(\nCLASS="INDEXDIV"\n)(.*?)<\/H1/<H2$1$2<\/H2/gims;
+ if( ($indx = rindex($buf, "<H1\n><A\nNAME=\"DOC-INDEX\"")) > -1 ) {
+ $buf = substr($buf, 0, $indx);
+ $buf .= "\n<\/BODY>\n<\/HTML>\n\n";
+ } elsif( ($indx = rindex($buf, "<H1\n><A\nNAME=\"doc-index\"")) > -1 ) {
+ $buf = substr($buf, 0, $indx);
+ $buf .= "\n<\/BODY>\n<\/HTML>\n\n";
+ }
+ $buf =~ s/\&\#13;//g;
+ $buf =~ s/\&\#60;/\&lt;/g;
+ $buf =~ s/\&\#62;/\&gt;/g;
+ $buf =~ s/\&\#8211;/\-/g;
+ $buf =~ s/WIDTH=\"\d\"//g;
+ $buf =~ s/><[\/]*TBODY//g;
+ $buf =~ s/><[\/]*THEAD//g;
+ $buf =~ s/TYPE=\"1\"\n//gim;
+
+ if( $is_article == 0 ) {
+
+ # for books...decrement the headers by 1 and then re-set the
+ # chapter level only to H1...
+ #
+ my($cnt,$j) = 0;
+ for($cnt=5; $cnt > 0; $cnt--) {
+ $j = $cnt + 1;
+ $buf =~ s/<H${cnt}/<H${j}/g;
+ $buf =~ s/<\/H${cnt}/<\/H${j}/g;
+ }
+
+ my(@l) = split(/\n/, $buf);
+ for( $cnt=0; $cnt < (@l + 0); $cnt++ ) {
+
+ if( $j == 1 ) {
+ if( $l[$cnt] =~ /<DIV/ ) {
+ $j = 0;
+ next;
+ }
+ $l[$cnt] =~ s/<H2/<H1/g;
+ $l[$cnt] =~ s/<\/H2/<\/H1/g;
+ }
+ if( $l[$cnt] =~ /^CLASS=\"CHAP/i
+ ||
+ $l[$cnt] =~ /^CLASS=\"PREF/i ) {
+ $j = 1;
+ }
+ }
+
+ $buf = join("\n", @l);
+
+ }
+ $buf =~ s/><DIV\nCLASS="\w+"\n//gms;
+ $buf =~ s/><\/DIV\n//gms;
+ $buf =~ s/(><LI\n)><P\n(.*?)<\/P\n>(<\/LI\n)/$1$2$3/gms;
+
+ print OUT_FILE $buf;
+ close(OUT_FILE);
+
+ return 1;
+}
+
+# Return true from package include
+#
+1;
+
diff --git a/docs/docbook/scripts/ldp_print b/docs/docbook/scripts/ldp_print
new file mode 100755
index 00000000000..70bb801def4
--- /dev/null
+++ b/docs/docbook/scripts/ldp_print
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+#
+# usage: ldp_print <single_file.html>
+#
+# Creates a PDF variant of a single-file HTML representation of a
+# DocBook SGML (or XML) instance. This simple wrapper assumes that
+# the file was created using {open}jade in a manner similar to:
+#
+# jade -t sgml -i html -V nochunks -d $style $fname > $fname.html
+#
+# Give this script the filename as an argument. It will then parse
+# the file into 'title.html' and 'body.html' and send each to
+# htmldoc (as the corresponding title page and body of the document).
+#
+#
+# CAVEATS:
+#
+# Assumes perl is in /usr/bin; adjust if necessary
+#
+# You may need to specify where the htmldoc executable resides.
+# The script assumes it's within your $PATH.
+#
+# If you want Postscript as an output variant, uncomment the
+# appropriate lines (see below).
+#
+# Relies on output from a DocBook instance created via DSSSL/{open}jade!
+#
+# Cleans up (removes) the intermediate files it creates (but not the
+# PDF or Postscript files, obviously!)
+#
+# Works silently; PDF (PostScript) will be created in the same directory
+# as was specified for the input (single-file HTML) file.
+#
+# Provided without warranty or support!
+#
+# gferg@sgi.com / Ferg (used as part of the LDP production env)
+#
+
+use strict;
+push(@INC, "./");
+require 'fix_print_html.lib';
+
+if( $ARGV[0] eq '' || !(-r $ARGV[0]) ) {
+ die "\nusage: ldp_print <single_file.html>\n\n";
+}
+
+my($fname_wo_ext) = $ARGV[0];
+$fname_wo_ext =~ s/\.[\w]+$//;
+
+
+# create new files from single HTML file to use for print
+#
+&fix_print_html($ARGV[0], 'body.html', 'title.html');
+
+my($cmd) = "htmldoc --size universal -t pdf -f ${fname_wo_ext}.pdf " .
+ "--firstpage p1 --titlefile title.html body.html";
+
+# For postscript output; append onto the above cmd string:
+#
+# "; htmldoc --size universal -t ps -f -f ${fname_wo_ext}.ps " .
+# "--firstpage p1 --titlefile title.html body.html";
+#
+system($cmd);
+die "\nldp_print: could not create ${fname_wo_ext}.pdf ($!)\n" if ($?);
+
+# cleanup
+#
+system("rm -f body.html title.html");
+
+exit(0);
+
diff --git a/docs/docbook/scripts/make-article.pl b/docs/docbook/scripts/make-article.pl
new file mode 100644
index 00000000000..d1f8c668326
--- /dev/null
+++ b/docs/docbook/scripts/make-article.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+
+$ignore = 0;
+
+print "<!DOCTYPE article PUBLIC \"-//OASIS//DTD DocBook V4.1//EN\">\n";
+
+while (<STDIN>) {
+
+ $_ =~ s/<chapter/<article/g;
+ $_ =~ s/<\/chapter/<\/article/g;
+
+ if ( $_ =~ '<articleinfo>') {
+ $ignore = 1;
+ }
+
+ if ( $_ =~ '</articleinfo>') {
+ $ignore = 0;
+ $_ = "";
+ }
+
+
+ if (! $ignore) { print "$_"; }
+
+
+}
diff --git a/docs/docbook/scripts/strip-links.pl b/docs/docbook/scripts/strip-links.pl
new file mode 100644
index 00000000000..dbbdceaabcc
--- /dev/null
+++ b/docs/docbook/scripts/strip-links.pl
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+
+## small script to stirp the <URL:...> tags from
+## manpages generated from docbook2man. we'll leave
+## the <URL:ftp://...> and <URL:mailto:...> links for now
+
+while (<STDIN>) {
+
+ chomp ($_);
+ $_ =~ s/\s*<URL:.*html.*>\s*//g;
+ print "$_\n";
+
+}
+exit 0;
diff --git a/docs/docbook/stylesheets/ldp.dsl.in b/docs/docbook/stylesheets/ldp.dsl.in
new file mode 100644
index 00000000000..d6e06f4b6d1
--- /dev/null
+++ b/docs/docbook/stylesheets/ldp.dsl.in
@@ -0,0 +1,256 @@
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY % html "IGNORE">
+<![%html;[
+<!ENTITY % print "IGNORE">
+<!ENTITY docbook.dsl SYSTEM "@SGML_SHARE@/dsssl/docbook/html/docbook.dsl" CDATA dsssl>
+]]>
+<!ENTITY % print "INCLUDE">
+<![%print;[
+<!ENTITY docbook.dsl SYSTEM "@SGML_SHARE@/dsssl/docbook/print/docbook.dsl" CDATA dsssl>
+]]>
+]>
+
+<style-sheet>
+
+<style-specification id="print" use="docbook">
+<style-specification-body>
+
+;; ==============================
+;; customize the print stylesheet
+;; ==============================
+
+(declare-characteristic preserve-sdata?
+ ;; this is necessary because right now jadetex does not understand
+ ;; symbolic entities, whereas things work well with numeric entities.
+ "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
+ #f)
+
+(define %generate-article-toc%
+ ;; Should a Table of Contents be produced for Articles?
+ #t)
+
+(define (toc-depth nd)
+ 2)
+
+(define %generate-article-titlepage-on-separate-page%
+ ;; Should the article title page be on a separate page?
+ #t)
+
+(define %section-autolabel%
+ ;; Are sections enumerated?
+ #t)
+
+(define %footnote-ulinks%
+ ;; Generate footnotes for ULinks?
+ #f)
+
+(define %bop-footnotes%
+ ;; Make "bottom-of-page" footnotes?
+ #f)
+
+(define %body-start-indent%
+ ;; Default indent of body text
+ 0pi)
+
+(define %para-indent-firstpara%
+ ;; First line start-indent for the first paragraph
+ 0pt)
+
+(define %para-indent%
+ ;; First line start-indent for paragraphs (other than the first)
+ 0pt)
+
+(define %block-start-indent%
+ ;; Extra start-indent for block-elements
+ 0pt)
+
+(define formal-object-float
+ ;; Do formal objects float?
+ #t)
+
+(define %hyphenation%
+ ;; Allow automatic hyphenation?
+ #t)
+
+(define %admon-graphics%
+ ;; Use graphics in admonitions?
+ #f)
+
+</style-specification-body>
+</style-specification>
+
+
+<!--
+;; ===================================================
+;; customize the html stylesheet; borrowed from Cygnus
+;; at http://sourceware.cygnus.com/ (cygnus-both.dsl)
+;; ===================================================
+-->
+
+<style-specification id="html" use="docbook">
+<style-specification-body>
+
+(declare-characteristic preserve-sdata?
+ ;; this is necessary because right now jadetex does not understand
+ ;; symbolic entities, whereas things work well with numeric entities.
+ "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
+ #f)
+
+(define %generate-legalnotice-link%
+ ;; put the legal notice in a separate file
+ #t)
+
+(define %admon-graphics-path%
+ ;; use graphics in admonitions, set their
+ "../images/")
+
+(define %admon-graphics%
+ #f)
+
+(define %funcsynopsis-decoration%
+ ;; make funcsynopsis look pretty
+ #t)
+
+(define %html-ext%
+ ;; when producing HTML files, use this extension
+ ".html")
+
+(define %generate-book-toc%
+ ;; Should a Table of Contents be produced for books?
+ #t)
+
+(define %generate-article-toc%
+ ;; Should a Table of Contents be produced for articles?
+ #t)
+
+(define %generate-part-toc%
+ ;; Should a Table of Contents be produced for parts?
+ #t)
+
+(define %generate-book-titlepage%
+ ;; produce a title page for books
+ #t)
+
+(define %generate-article-titlepage%
+ ;; produce a title page for articles
+ #t)
+
+(define (chunk-skip-first-element-list)
+ ;; forces the Table of Contents on separate page
+ '())
+
+(define (list-element-list)
+ ;; fixes bug in Table of Contents generation
+ '())
+
+(define %root-filename%
+ ;; The filename of the root HTML document (e.g, "index").
+ "index")
+
+(define %shade-verbatim%
+ ;; verbatim sections will be shaded if t(rue)
+ #t)
+
+(define %use-id-as-filename%
+ ;; Use ID attributes as name for component HTML files?
+ #t)
+
+(define %graphic-extensions%
+ ;; graphic extensions allowed
+ '("gif" "png" "jpg" "jpeg" "tif" "tiff" "eps" "epsf" ))
+
+(define %graphic-default-extension%
+ "gif")
+
+(define %section-autolabel%
+ ;; For enumerated sections (1.1, 1.1.1, 1.2, etc.)
+ #t)
+
+(define (toc-depth nd)
+ ;; more depth (2 levels) to toc; instead of flat hierarchy
+ ;; 2)
+ 4)
+
+(element emphasis
+ ;; make role=strong equate to bold for emphasis tag
+ (if (equal? (attribute-string "role") "strong")
+ (make element gi: "STRONG" (process-children))
+ (make element gi: "EM" (process-children))))
+
+(define (book-titlepage-recto-elements)
+ ;; elements on a book's titlepage
+ ;; note: added revhistory to the default list
+ (list (normalize "title")
+ (normalize "subtitle")
+ (normalize "graphic")
+ (normalize "mediaobject")
+ (normalize "corpauthor")
+ (normalize "authorgroup")
+ (normalize "author")
+ (normalize "editor")
+ (normalize "copyright")
+ (normalize "revhistory")
+ (normalize "abstract")
+ (normalize "legalnotice")))
+
+(define (article-titlepage-recto-elements)
+ ;; elements on an article's titlepage
+ ;; note: added othercredit to the default list
+ (list (normalize "title")
+ (normalize "subtitle")
+ (normalize "authorgroup")
+ (normalize "author")
+ (normalize "othercredit")
+ (normalize "releaseinfo")
+ (normalize "copyright")
+ (normalize "pubdate")
+ (normalize "revhistory")
+ (normalize "abstract")))
+
+(mode article-titlepage-recto-mode
+
+ (element contrib
+ ;; print out with othercredit information; for translators, etc.
+ (make sequence
+ (make element gi: "SPAN"
+ attributes: (list (list "CLASS" (gi)))
+ (process-children))))
+
+ (element othercredit
+ ;; print out othercredit information; for translators, etc.
+ (let ((author-name (author-string))
+ (author-contrib (select-elements (children (current-node))
+ (normalize "contrib"))))
+ (make element gi: "P"
+ attributes: (list (list "CLASS" (gi)))
+ (make element gi: "B"
+ (literal author-name)
+ (literal " - "))
+ (process-node-list author-contrib))))
+)
+
+(define (article-title nd)
+ (let* ((artchild (children nd))
+ (artheader (select-elements artchild (normalize "artheader")))
+ (artinfo (select-elements artchild (normalize "articleinfo")))
+ (ahdr (if (node-list-empty? artheader)
+ artinfo
+ artheader))
+ (ahtitles (select-elements (children ahdr)
+ (normalize "title")))
+ (artitles (select-elements artchild (normalize "title")))
+ (titles (if (node-list-empty? artitles)
+ ahtitles
+ artitles)))
+ (if (node-list-empty? titles)
+ ""
+ (node-list-first titles))))
+
+
+</style-specification-body>
+</style-specification>
+
+<external-specification id="docbook" document="docbook.dsl">
+
+</style-sheet>
+
diff --git a/docs/faq/Samba-Server-FAQ-1.html b/docs/faq/Samba-Server-FAQ-1.html
new file mode 100644
index 00000000000..0bf7f046109
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ-1.html
@@ -0,0 +1,77 @@
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ: What is Samba?</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-Server-FAQ-2.html">Next</A>
+<A HREF="Samba-Server-FAQ.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. What is Samba?</A></H2>
+
+<P>
+<A NAME="WhatIsSamba"></A>
+</P>
+<P>See the
+<A HREF="Samba-meta-FAQ.html#introduction">meta FAQ introduction</A> if you don't have any idea what Samba does.</P>
+<P>Samba has many features that are not supported in other CIFS and SMB
+implementations, all of which are commercial. It approaches some
+problems from a different angle.</P>
+<P>Some of its features include:
+<UL>
+<LI>extremely dynamic runtime configuration</LI>
+<LI>host as well as username/password security</LI>
+<LI>scriptable SMB client</LI>
+<LI>automatic home directory exporting</LI>
+<LI>automatic printer exporting</LI>
+<LI>intelligent dead connection timeouts</LI>
+<LI>guest connections</LI>
+</UL>
+</P>
+<P>Look at the
+<A HREF="samba-man-index.html">manual pages</A> included with the package for a full list of
+features. The components of the suite are (in summary):</P>
+<P>
+<DL>
+
+<DT><B>smbd</B><DD><P>the SMB server. This handles actual connections from clients,
+doing all the interfacing with the
+<A HREF="Samba-meta-FAQ.html#DomainModeSecurity">authentication database</A> for file, permission and username work.</P>
+
+<DT><B>nmbd</B><DD><P>the NetBIOS name server, which helps clients locate servers,
+maintaining the
+<A HREF="Samba-meta-FAQ.html#BrowseAndDomainDefs">authentication database</A> doing the browsing work and managing
+domains as this capability is being built into Samba.</P>
+
+<DT><B>smbclient</B><DD><P>the scriptable commandline SMB client program.
+Useful for automated work, printer filters and testing purposes. It is
+more CIFS-compliant than most commercial implementations. Note that this
+is not a filesystem. The Samba team does not supply a network filesystem
+driver, although the smbfs filesystem for Linux is derived from
+smbclient code.</P>
+
+<DT><B>smbrun</B><DD><P>a little 'glue' program to help the server run
+external programs.</P>
+
+<DT><B>testprns</B><DD><P>a program to test server access to printers</P>
+
+<DT><B>testparms</B><DD><P>a program to test the Samba configuration file
+for correctness</P>
+
+<DT><B>smb.conf</B><DD><P>the Samba configuration file</P>
+
+<DT><B>examples</B><DD><P>many examples have been put together for the different
+operating systems that Samba supports.</P>
+
+<DT><B>Documentation!</B><DD><P>DON'T neglect to read it - you will save a great
+deal of time!</P>
+
+</DL>
+</P>
+
+<HR>
+Previous
+<A HREF="Samba-Server-FAQ-2.html">Next</A>
+<A HREF="Samba-Server-FAQ.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ-2.html b/docs/faq/Samba-Server-FAQ-2.html
new file mode 100644
index 00000000000..37a39833990
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ-2.html
@@ -0,0 +1,500 @@
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ: How do I get the CIFS, SMB and NetBIOS protocols?</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-Server-FAQ-1.html">Previous</A>
+Next
+<A HREF="Samba-Server-FAQ.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. How do I get the CIFS, SMB and NetBIOS protocols?</A></H2>
+
+<P>
+<A NAME="ServerProtocols"></A>
+</P>
+<P>See the
+<A HREF="Samba-meta-FAQ.html#CifsSmb">meta FAQ on CIFS and SMB</A> if you don't have any idea what these protocols are.</P>
+<P>CIFS and SMB are implemented by the main Samba fileserving daemon, smbd.
+<F>.....</F></P>
+<P>nmbd speaks a limited amount of CIFS (...) but is mostly concerned with
+NetBIOS. NetBIOS is <F>....</F></P>
+<P>RFC1001, RFC1002 <F>...</F></P>
+<P>So, provided you have got Samba correctly installed and running you have
+all three of these protocols. Some operating systems already come with
+stacks for all or some of these, such as SCO Unix, OS/2 and <F>...</F> In this
+case you must <F>...</F></P>
+
+<H2><A NAME="ss2.1">2.1 What server operating systems are supported?</A></H2>
+
+<P>
+<A NAME="PortInfo"></A>
+</P>
+<P>At the last count, Samba runs on about 40 operating systems! This
+section looks at general questions about running Samba on the different
+platforms. Issues specific to particular operating systems are dealt
+with in elsewhere in this document.</P>
+<P>Many of the ports have been done by people outside the Samba team keen
+to get the advantages of Samba. The Samba team is currently trying to
+bring as many of these ports as possible into the main source tree and
+integrate the documentation. Samba is an integration tool, and so it has
+been made as easy as possible to port. The platforms most widely used
+and thus best tested are Linux and SunOS.</P>
+<P>This migration has not been completed yet. This means that some
+documentation is on web sites <F>...</F></P>
+<P>There are two main families of Samba ports, Unix and other. The Unix
+ports cover anything that remotely resembles Unix and includes some
+extremely old products as well as best-sellers, tiny PCs to massive
+multiprocessor machines supporting hundreds of thousands of users. Samba
+has been run on more than 30 Unix and Unix-like operating systems.</P>
+
+<H3>Running Samba on a Unix or Unix-like system</H3>
+
+<P>
+<A NAME="OnUnix"></A>
+</P>
+<P>
+<A HREF="../UNIX-SMB.txt">../UNIX-SMB.txt</A> describes some of the issues that confront a
+SMB implementation on unix, and how Samba copes with them. They may help
+people who are looking at unix<->PC interoperability.</P>
+<P>There is great variation between Unix implementations, especially those
+not adhering to the Common Unix Specification agreed to in 1996. Things
+that can be quite tricky are <F>.....</F></P>
+<P>There are also some considerable advantages conferred on Samba running
+under Unix compared to, say, Windows NT or LAN Server. Unix has <F>...</F></P>
+<P>At time of writing, the Makefile claimed support for:
+<UL>
+<LI> A/UX 3.0</LI>
+<LI> AIX</LI>
+<LI> Altos Series 386/1000</LI>
+<LI> Amiga</LI>
+<LI> Apollo Domain/OS sr10.3</LI>
+<LI> BSDI </LI>
+<LI> B.O.S. (Bull Operating System)</LI>
+<LI> Cray, Unicos 8.0</LI>
+<LI> Convex</LI>
+<LI> DGUX. </LI>
+<LI> DNIX.</LI>
+<LI> FreeBSD</LI>
+<LI> HP-UX</LI>
+<LI> Intergraph. </LI>
+<LI> Linux with/without shadow passwords and quota</LI>
+<LI> LYNX 2.3.0</LI>
+<LI> MachTen (a unix like system for Macintoshes)</LI>
+<LI> Motorola 88xxx/9xx range of machines</LI>
+<LI> NetBSD</LI>
+<LI> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).</LI>
+<LI> OS/2 using EMX 0.9b</LI>
+<LI> OSF1</LI>
+<LI> QNX 4.22</LI>
+<LI> RiscIX. </LI>
+<LI> RISCOs 5.0B</LI>
+<LI> SEQUENT. </LI>
+<LI> SCO (including: 3.2v2, European dist., OpenServer 5)</LI>
+<LI> SGI.</LI>
+<LI> SMP_DC.OSx v1.1-94c079 on Pyramid S series</LI>
+<LI> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)</LI>
+<LI> SUNOS 4</LI>
+<LI> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')</LI>
+<LI> Sunsoft ISC SVR3V4</LI>
+<LI> SVR4</LI>
+<LI> System V with some berkely extensions (Motorola 88k R32V3.2).</LI>
+<LI> ULTRIX.</LI>
+<LI> UNIXWARE</LI>
+<LI> UXP/DS</LI>
+</UL>
+</P>
+
+
+<H3>Running Samba on systems unlike Unix</H3>
+
+<P>
+<A NAME="OnUnlikeUnix"></A>
+</P>
+<P>More recently Samba has been ported to a number of operating systems
+which can provide a BSD Unix-like implementation of TCP/IP sockets.
+These include OS/2, Netware, VMS, StratOS, Amiga and MVS. BeOS,
+Windows NT and several others are being worked on but not yet available
+for use.</P>
+<P>Home pages for these ports are:</P>
+<P><F>... </F></P>
+
+
+<H2><A NAME="ss2.2">2.2 Exporting server resources with Samba</A></H2>
+
+<P>
+<A NAME="Exporting"></A>
+</P>
+<P>Files, printers, CD ROMs and other local devices. Network devices,
+including networked filesystems and remote printer queues. Other devices
+such as <F>....</F></P>
+<P>1.4) Configuring SHARES
+1.4.1) Homes service
+1.4.2) Public services
+1.4.3) Application serving
+1.4.4) Team sharing a Samba resource</P>
+<P>1.5) Printer configuration
+1.5.1) Berkeley LPR/LPD systems
+1.5.2) ATT SysV lp systems
+1.5.3) Using a private printcap file
+1.5.4) Use of the smbprint utility
+1.5.5) Printing from Windows to Unix
+1.5.6) Printing from Unix to Windows</P>
+
+
+<H2><A NAME="ss2.3">2.3 Name Resolution and Browsing</A></H2>
+
+<P>
+<A NAME="NameBrowsing"></A>
+</P>
+<P>See also
+<A HREF="../BROWSING.txt">../BROWSING.txt</A></P>
+<P>1.6) Name resolution issues
+1.6.1) LMHOSTS file and when to use it
+1.6.2) configuring WINS (support, server, proxy)
+1.6.3) configuring DNS proxy</P>
+<P>1.7) Problem Diagnosis
+1.8) What NOT to do!!!!</P>
+<P>3.2) Browse list managment
+3.3) Name resolution mangement</P>
+
+
+
+<H2><A NAME="ss2.4">2.4 Handling SMB Encryption</A></H2>
+
+<P>
+<A NAME="SMBEncryptionSteps"></A>
+</P>
+<P>SMB encryption is ...</P>
+<P>...in
+<A HREF="../ENCRYPTION.txt">../ENCRYPTION.txt</A> there is...</P>
+<P>Samba compiled with libdes - enabling encrypted passwords</P>
+
+
+<H3>Laws in different countries affecting Samba</H3>
+
+<P>
+<A NAME="CryptoLaws"></A>
+</P>
+
+<H3>Relationship between encryption and Domain Authentication</H3>
+
+
+
+
+<H2><A NAME="ss2.5">2.5 Files and record locking</A> 3.1.1) Old DOS clients 3.1.2) Opportunistic locking and the consequences 3.1.3) Files caching under Windows for Workgroups, Win95 and NT Some of the foregoing links into Client-FAQ</H2>
+
+
+<H2><A NAME="ss2.6">2.6 Managing Samba Log files</A></H2>
+
+<P>
+<A NAME="LogFiles"></A>
+</P>
+
+
+<H2><A NAME="ss2.7">2.7 I can't see the Samba server in any browse lists!</A></H2>
+
+<P>
+<A NAME="no_browse"></A>
+
+See
+<A HREF="ftp://samba.org/pub/samba/BROWSING.txt">BROWSING.txt</A>
+for more information on browsing. Browsing.txt can also be found
+in the docs directory of the Samba source.</P>
+<P>If your GUI client does not permit you to select non-browsable
+servers, you may need to do so on the command line. For example, under
+Lan Manager you might connect to the above service as disk drive M:
+thusly:
+<BLOCKQUOTE><CODE>
+<PRE>
+ net use M: \\mary\fred
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.</P>
+
+
+<H2><A NAME="ss2.8">2.8 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="missing_files"></A>
+
+See the next question.</P>
+
+
+<H2><A NAME="ss2.9">2.9 Some files on the server show up with really wierd filenames when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="strange_filenames"></A>
+
+If you check what files are not showing up, you will note that they
+are files which contain upper case letters or which are otherwise not
+DOS-compatible (ie, they are not legal DOS filenames for some reason).</P>
+<P>The Samba server can be configured either to ignore such files
+completely, or to present them to the client in "mangled" form. If you
+are not seeing the files at all, the Samba server has most likely been
+configured to ignore them. Consult the man page smb.conf(5) for
+details of how to change this - the parameter you need to set is
+"mangled names = yes".</P>
+
+
+<H2><A NAME="ss2.10">2.10 My client reports "cannot locate specified computer" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_server"></A>
+
+This indicates one of three things: You supplied an incorrect server
+name, the underlying TCP/IP layer is not working correctly, or the
+name you specified cannot be resolved.</P>
+<P>After carefully checking that the name you typed is the name you
+should have typed, try doing things like pinging a host or telnetting
+to somewhere on your network to see if TCP/IP is functioning OK. If it
+is, the problem is most likely name resolution.</P>
+<P>If your client has a facility to do so, hardcode a mapping between the
+hosts IP and the name you want to use. For example, with Man Manager
+or Windows for Workgroups you would put a suitable entry in the file
+LMHOSTS. If this works, the problem is in the communication between
+your client and the netbios name server. If it does not work, then
+there is something fundamental wrong with your naming and the solution
+is beyond the scope of this document.</P>
+<P>If you do not have any server on your subnet supplying netbios name
+resolution, hardcoded mappings are your only option. If you DO have a
+netbios name server running (such as the Samba suite's nmbd program),
+the problem probably lies in the way it is set up. Refer to Section
+Two of this FAQ for more ideas.</P>
+<P>By the way, remember to REMOVE the hardcoded mapping before further
+tests :-) </P>
+
+
+<H2><A NAME="ss2.11">2.11 My client reports "cannot locate specified share name" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_share"></A>
+
+This message indicates that your client CAN locate the specified
+server, which is a good start, but that it cannot find a service of
+the name you gave.</P>
+<P>The first step is to check the exact name of the service you are
+trying to connect to (consult your system administrator). Assuming it
+exists and you specified it correctly (read your client's doco on how
+to specify a service name correctly), read on:</P>
+<P>
+<UL>
+<LI> Many clients cannot accept or use service names longer than eight characters.</LI>
+<LI> Many clients cannot accept or use service names containing spaces.</LI>
+<LI> Some servers (not Samba though) are case sensitive with service names.</LI>
+<LI> Some clients force service names into upper case.</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.12">2.12 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A></H2>
+
+<P>
+<A NAME="cant_see_net"></A>
+
+Nothing is wrong - Samba does not implement the primary domain name
+controller stuff for several reasons, including the fact that the
+whole concept of a primary domain controller and "logging in to a
+network" doesn't fit well with clients possibly running on multiuser
+machines (such as users of smbclient under Unix). Having said that,
+several developers are working hard on building it in to the next
+major version of Samba. If you can contribute, send a message to
+<A HREF="mailto:samba@samba.org">samba@samba.org</A> !</P>
+<P>Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.</P>
+<P>For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.</P>
+
+
+<H2><A NAME="ss2.13">2.13 Printing doesn't work :-(</A></H2>
+
+<P>
+<A NAME="no_printing"></A>
+ </P>
+<P>Make sure that the specified print command for the service you are
+connecting to is correct and that it has a fully-qualified path (eg.,
+use "/usr/bin/lpr" rather than just "lpr", if you happen to be using
+Unix).</P>
+<P>Make sure that the spool directory specified for the service is
+writable by the user connected to the service. </P>
+<P>Make sure that the user specified in the service is permitted to use
+the printer.</P>
+<P>Check the debug log produced by smbd. Search for the printer name and
+see if the log turns up any clues. Note that error messages to do with
+a service ipc$ are meaningless - they relate to the way the client
+attempts to retrieve status information when using the LANMAN1
+protocol.</P>
+<P>If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.</P>
+<P>If using the Lanman1 protocol (the default) then try switching to
+coreplus. Also not that print status error messages don't mean
+printing won't work. The print status is received by a different
+mechanism.</P>
+
+
+<H2><A NAME="ss2.14">2.14 My programs install on the server OK, but refuse to work properly</A></H2>
+
+<P>
+<A NAME="programs_wont_run"></A>
+
+There are numerous possible reasons for this, but one MAJOR
+possibility is that your software uses locking. Make sure you are
+using Samba 1.6.11 or later. It may also be possible to work around
+the problem by setting "locking=no" in the Samba configuration file
+for the service the software is installed on. This should be regarded
+as a strictly temporary solution.</P>
+<P>In earlier Samba versions there were some difficulties with the very
+latest Microsoft products, particularly Excel 5 and Word for Windows
+6. These should have all been solved. If not then please let Andrew
+Tridgell know via email at
+<A HREF="mailto:sambas@samba.org">samba@samba.org</A>.</P>
+
+
+<H2><A NAME="ss2.15">2.15 My "server string" doesn't seem to be recognised</A></H2>
+
+<P>
+<A NAME="bad_server_string"></A>
+
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.</P>
+<P>You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.</P>
+<P>Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.</P>
+
+
+<H2><A NAME="ss2.16">2.16 My client reports "This server is not configured to list shared resources" </A></H2>
+
+<P>
+<A NAME="cant_list_shares"></A>
+
+Your guest account is probably invalid for some reason. Samba uses the
+guest account for browsing in smbd. Check that your guest account is
+valid.</P>
+<P>See also 'guest account' in smb.conf man page.</P>
+
+
+<H2><A NAME="ss2.17">2.17 Issues specific to Unix and Unix-like systems</A></H2>
+
+<P>
+<A NAME="UnixIssues"></A>
+</P>
+
+<H3>Printing doesn't work with my Unix Samba server</H3>
+
+<P>
+<A NAME="no_printing"></A>
+ </P>
+<P>The user "nobody" often has problems with printing, even if it worked
+with an earlier version of Samba. Try creating another guest user other
+than "nobody".</P>
+
+<H3>Log message "you appear to have a trapdoor uid system" </H3>
+
+<P>
+<A NAME="trapdoor_uid"></A>
+
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.</P>
+<P>It might also mean that your OS has a trapdoor uid/gid system :-)</P>
+<P>This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.</P>
+<P>The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.</P>
+<P>Complain to your OS vendor and ask them to fix their system.</P>
+<P>Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!</P>
+
+
+<H2><A NAME="ss2.18">2.18 Issues specific to IBM OS/2 systems</A></H2>
+
+<P>
+<A NAME="OS2Issues"></A>
+</P>
+<P>
+<A HREF="http://carol.wins.uva.nl/~leeuw/samba/samba2.html">Samba for OS/2</A></P>
+
+
+<H2><A NAME="ss2.19">2.19 Issues specific to IBM MVS systems</A></H2>
+
+<P>
+<A NAME="MVSIssues"></A>
+</P>
+<P>
+<A HREF="ftp://ftp.mks.com/pub/samba/">Samba for OS/390 MVS</A></P>
+
+
+<H2><A NAME="ss2.20">2.20 Issues specific to Digital VMS systems</A></H2>
+
+<P>
+<A NAME="VMSIssues"></A>
+</P>
+
+
+<H2><A NAME="ss2.21">2.21 Issues specific to Amiga systems</A></H2>
+
+<P>
+<A NAME="AmigaIssues"></A>
+</P>
+<P>
+<A HREF="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/">Samba for Amiga</A></P>
+<P>There is a mailing list for Samba on the Amiga.</P>
+<P>Subscribing.</P>
+<P>Send an email to rask-samba-request@kampsax.dtu.dk with the word subscribe
+in the message. The list server will use the address in the Reply-To: or
+From: header field, in that order.</P>
+<P>Unsubscribing.</P>
+<P>Send an email to rask-samba-request@kampsax.dtu.dk with the word
+unsubscribe in the message. The list server will use the address in the
+Reply-To: or From: header field, in that order. If you are unsure which
+address you are subscribed with, look at the headers. You should see a
+"From " (no colon) or Return-Path: header looking something like</P>
+<P>rask-samba-owner-myname=my.domain@kampsax.dtu.dk</P>
+<P>where myname=my.domain gives you the address myname@my.domain. This also
+means that I will always be able to find out which address is causing
+bounces, for example.
+List archive.</P>
+<P>Messages sent to the list are archived in HTML. See the mailing list home
+page at
+<A HREF="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/">http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/</A></P>
+
+
+<H2><A NAME="ss2.22">2.22 Issues specific to Novell IntraNetware systems</A></H2>
+
+<P>
+<A NAME="NetwareIssues"></A>
+</P>
+
+
+<H2><A NAME="ss2.23">2.23 Issues specific to Stratus VOS systems</A></H2>
+
+<P>
+<A NAME="NetwareIssues"></A>
+</P>
+<P>
+<A HREF="ftp://ftp.stratus.com/pub/vos/tools/">Samba for Stratus VOS</A></P>
+
+
+<HR>
+<A HREF="Samba-Server-FAQ-1.html">Previous</A>
+Next
+<A HREF="Samba-Server-FAQ.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ.html b/docs/faq/Samba-Server-FAQ.html
new file mode 100644
index 00000000000..2abfe50db6b
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-Server-FAQ-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba Server FAQ</H1>
+
+<H2>Dan Shearer & Paul Blackman, <CODE>ictinus@samba.org</CODE></H2>v 0.3, 7 Oct '97
+<P><HR><EM> This is the <EM>Server</EM> Frequently Asked Questions (FAQ)
+document for Samba, the free and very popular SMB and CIFS server
+product. A general
+<A HREF="Samba-meta-FAQ.html">meta FAQ</A>
+exists and also a companion
+<A HREF="Samba-Client-FAQ.html">Client FAQ</A>, together with more detailed HOWTO documents on
+topics to do with Samba software. This is current to Samba version
+1.9.17. Please send any corrections to the author. </EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="Samba-Server-FAQ-1.html">What is Samba?</A></H2>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="Samba-Server-FAQ-2.html">How do I get the CIFS, SMB and NetBIOS protocols?</A></H2>
+<UL>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.1">2.1 What server operating systems are supported?</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.2">2.2 Exporting server resources with Samba</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.3">2.3 Name Resolution and Browsing</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.4">2.4 Handling SMB Encryption</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.5">2.5 Files and record locking</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.6">2.6 Managing Samba Log files</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.7">2.7 I can't see the Samba server in any browse lists!</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.8">2.8 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.9">2.9 Some files on the server show up with really wierd filenames when I view the files from my client! </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.10">2.10 My client reports "cannot locate specified computer" or similar</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.11">2.11 My client reports "cannot locate specified share name" or similar</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.12">2.12 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.13">2.13 Printing doesn't work :-(</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.14">2.14 My programs install on the server OK, but refuse to work properly</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.15">2.15 My "server string" doesn't seem to be recognised</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.16">2.16 My client reports "This server is not configured to list shared resources" </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.17">2.17 Issues specific to Unix and Unix-like systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.18">2.18 Issues specific to IBM OS/2 systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.19">2.19 Issues specific to IBM MVS systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.20">2.20 Issues specific to Digital VMS systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.21">2.21 Issues specific to Amiga systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.22">2.22 Issues specific to Novell IntraNetware systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.23">2.23 Issues specific to Stratus VOS systems</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="Samba-Server-FAQ-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ.sgml b/docs/faq/Samba-Server-FAQ.sgml
new file mode 100644
index 00000000000..da6b50f99e2
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ.sgml
@@ -0,0 +1,492 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.1 23 Aug 1997 Dan Shearer
+ Original Samba-Client-FAQ.sgml from Paul's sambafaq.sgml
+ v 0.2 25 Aug 1997 Dan
+ v 0.3 7 Oct 1997 Paul, changed email address from ictinus@lake... to ictinus@samba.anu
+-->
+
+
+<article>
+
+<title> Samba Server FAQ
+
+<author>Dan Shearer & Paul Blackman, <tt>ictinus@samba.org</tt>
+
+<date>v 0.3, 7 Oct '97
+
+<abstract> This is the <em>Server</em> Frequently Asked Questions (FAQ)
+document for Samba, the free and very popular SMB and CIFS server
+product. A general <url url="Samba-meta-FAQ.html" name="meta FAQ">
+exists and also a companion <url url="Samba-Client-FAQ.html"
+name="Client FAQ">, together with more detailed HOWTO documents on
+topics to do with Samba software. This is current to Samba version
+1.9.17. Please send any corrections to the author.
+
+</abstract>
+
+<toc>
+
+<sect>What is Samba?<p><label id="WhatIsSamba">
+
+See the <url url="Samba-meta-FAQ.html#introduction" name="meta FAQ
+introduction"> if you don't have any idea what Samba does.
+
+Samba has many features that are not supported in other CIFS and SMB
+implementations, all of which are commercial. It approaches some
+problems from a different angle.
+
+Some of its features include:
+<itemize>
+<item>extremely dynamic runtime configuration
+<item>host as well as username/password security
+<item>scriptable SMB client
+<item>automatic home directory exporting
+<item>automatic printer exporting
+<item>intelligent dead connection timeouts
+<item>guest connections
+</itemize>
+
+Look at the <url url="samba-man-index.html" name="manual pages"> included with the package for a full list of
+features. The components of the suite are (in summary):
+
+<descrip>
+
+<tag/smbd/ the SMB server. This handles actual connections from clients,
+doing all the interfacing with the <url
+url="Samba-meta-FAQ.html#DomainModeSecurity" name="authentication
+database"> for file, permission and username work.
+
+<tag/nmbd/ the NetBIOS name server, which helps clients locate servers,
+maintaining the <url url="Samba-meta-FAQ.html#BrowseAndDomainDefs"
+name="authentication database"> doing the browsing work and managing
+domains as this capability is being built into Samba.
+
+<tag/smbclient/ the scriptable commandline SMB client program.
+Useful for automated work, printer filters and testing purposes. It is
+more CIFS-compliant than most commercial implementations. Note that this
+is not a filesystem. The Samba team does not supply a network filesystem
+driver, although the smbfs filesystem for Linux is derived from
+smbclient code.
+
+<tag/smbrun/ a little 'glue' program to help the server run
+external programs.
+
+<tag/testprns/ a program to test server access to printers
+
+<tag/testparms/ a program to test the Samba configuration file
+for correctness
+
+<tag/smb.conf/ the Samba configuration file
+
+<tag/examples/ many examples have been put together for the different
+operating systems that Samba supports.
+
+<tag/Documentation!/ DON'T neglect to read it - you will save a great
+deal of time!
+
+</descrip>
+
+<sect>How do I get the CIFS, SMB and NetBIOS protocols?<p><label id="ServerProtocols">
+
+See the <url url="Samba-meta-FAQ.html#CifsSmb" name="meta FAQ
+on CIFS and SMB"> if you don't have any idea what these protocols are.
+
+CIFS and SMB are implemented by the main Samba fileserving daemon, smbd.
+[.....]
+
+nmbd speaks a limited amount of CIFS (...) but is mostly concerned with
+NetBIOS. NetBIOS is [....]
+
+RFC1001, RFC1002 [...]
+
+So, provided you have got Samba correctly installed and running you have
+all three of these protocols. Some operating systems already come with
+stacks for all or some of these, such as SCO Unix, OS/2 and [...] In this
+case you must [...]
+
+<sect1>What server operating systems are supported?<p><label id="PortInfo">
+
+At the last count, Samba runs on about 40 operating systems! This
+section looks at general questions about running Samba on the different
+platforms. Issues specific to particular operating systems are dealt
+with in elsewhere in this document.
+
+Many of the ports have been done by people outside the Samba team keen
+to get the advantages of Samba. The Samba team is currently trying to
+bring as many of these ports as possible into the main source tree and
+integrate the documentation. Samba is an integration tool, and so it has
+been made as easy as possible to port. The platforms most widely used
+and thus best tested are Linux and SunOS.
+
+This migration has not been completed yet. This means that some
+documentation is on web sites [...]
+
+There are two main families of Samba ports, Unix and other. The Unix
+ports cover anything that remotely resembles Unix and includes some
+extremely old products as well as best-sellers, tiny PCs to massive
+multiprocessor machines supporting hundreds of thousands of users. Samba
+has been run on more than 30 Unix and Unix-like operating systems.
+
+<sect2>Running Samba on a Unix or Unix-like system<p><label id="OnUnix">
+
+<url url="../UNIX-SMB.txt"> describes some of the issues that confront a
+SMB implementation on unix, and how Samba copes with them. They may help
+people who are looking at unix<->PC interoperability.
+
+There is great variation between Unix implementations, especially those
+not adhering to the Common Unix Specification agreed to in 1996. Things
+that can be quite tricky are [.....]
+
+There are also some considerable advantages conferred on Samba running
+under Unix compared to, say, Windows NT or LAN Server. Unix has [...]
+
+At time of writing, the Makefile claimed support for:
+<itemize>
+<item> A/UX 3.0
+<item> AIX
+<item> Altos Series 386/1000
+<item> Amiga
+<item> Apollo Domain/OS sr10.3
+<item> BSDI
+<item> B.O.S. (Bull Operating System)
+<item> Cray, Unicos 8.0
+<item> Convex
+<item> DGUX.
+<item> DNIX.
+<item> FreeBSD
+<item> HP-UX
+<item> Intergraph.
+<item> Linux with/without shadow passwords and quota
+<item> LYNX 2.3.0
+<item> MachTen (a unix like system for Macintoshes)
+<item> Motorola 88xxx/9xx range of machines
+<item> NetBSD
+<item> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).
+<item> OS/2 using EMX 0.9b
+<item> OSF1
+<item> QNX 4.22
+<item> RiscIX.
+<item> RISCOs 5.0B
+<item> SEQUENT.
+<item> SCO (including: 3.2v2, European dist., OpenServer 5)
+<item> SGI.
+<item> SMP_DC.OSx v1.1-94c079 on Pyramid S series
+<item> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+<item> SUNOS 4
+<item> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+<item> Sunsoft ISC SVR3V4
+<item> SVR4
+<item> System V with some berkely extensions (Motorola 88k R32V3.2).
+<item> ULTRIX.
+<item> UNIXWARE
+<item> UXP/DS
+</itemize>
+
+
+<sect2>Running Samba on systems unlike Unix<p><label id="OnUnlikeUnix">
+
+More recently Samba has been ported to a number of operating systems
+which can provide a BSD Unix-like implementation of TCP/IP sockets.
+These include OS/2, Netware, VMS, StratOS, Amiga and MVS. BeOS,
+Windows NT and several others are being worked on but not yet available
+for use.
+
+Home pages for these ports are:
+
+[... ]
+
+<sect1>Exporting server resources with Samba<p><label id="Exporting">
+
+Files, printers, CD ROMs and other local devices. Network devices,
+including networked filesystems and remote printer queues. Other devices
+such as [....]
+
+ 1.4) Configuring SHARES
+ 1.4.1) Homes service
+ 1.4.2) Public services
+ 1.4.3) Application serving
+ 1.4.4) Team sharing a Samba resource
+
+ 1.5) Printer configuration
+ 1.5.1) Berkeley LPR/LPD systems
+ 1.5.2) ATT SysV lp systems
+ 1.5.3) Using a private printcap file
+ 1.5.4) Use of the smbprint utility
+ 1.5.5) Printing from Windows to Unix
+ 1.5.6) Printing from Unix to Windows
+
+<sect1>Name Resolution and Browsing<p><label id="NameBrowsing">
+
+See also <url url="../BROWSING.txt">
+
+ 1.6) Name resolution issues
+ 1.6.1) LMHOSTS file and when to use it
+ 1.6.2) configuring WINS (support, server, proxy)
+ 1.6.3) configuring DNS proxy
+
+ 1.7) Problem Diagnosis
+ 1.8) What NOT to do!!!!
+
+ 3.2) Browse list managment
+ 3.3) Name resolution mangement
+
+
+<sect1>Handling SMB Encryption<p><label id="SMBEncryptionSteps">
+
+SMB encryption is ...
+
+...in <url url="../ENCRYPTION.txt"> there is...
+
+Samba compiled with libdes - enabling encrypted passwords
+
+
+<sect2>Laws in different countries affecting Samba<p><label id="CryptoLaws">
+
+<sect2>Relationship between encryption and Domain Authentication<p>
+
+<sect1> Files and record locking
+
+ 3.1.1) Old DOS clients
+ 3.1.2) Opportunistic locking and the consequences
+ 3.1.3) Files caching under Windows for Workgroups, Win95 and NT
+
+ Some of the foregoing links into Client-FAQ
+
+<sect1>Managing Samba Log files<p><label id="LogFiles">
+
+<sect1>I can't see the Samba server in any browse lists!<p><label id="no_browse">
+ See <url url="ftp://samba.org/pub/samba/BROWSING.txt" name="BROWSING.txt">
+ for more information on browsing. Browsing.txt can also be found
+ in the docs directory of the Samba source.
+
+If your GUI client does not permit you to select non-browsable
+servers, you may need to do so on the command line. For example, under
+Lan Manager you might connect to the above service as disk drive M:
+thusly:
+<tscreen><verb>
+ net use M: \\mary\fred
+</verb></tscreen>
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.
+
+<sect1>Some files that I KNOW are on the server doesn't show up when I view the files from my client! <p> <label id="missing_files">
+See the next question.
+
+<sect1>Some files on the server show up with really wierd filenames when I view the files from my client! <p> <label id="strange_filenames">
+If you check what files are not showing up, you will note that they
+are files which contain upper case letters or which are otherwise not
+DOS-compatible (ie, they are not legal DOS filenames for some reason).
+
+The Samba server can be configured either to ignore such files
+completely, or to present them to the client in "mangled" form. If you
+are not seeing the files at all, the Samba server has most likely been
+configured to ignore them. Consult the man page smb.conf(5) for
+details of how to change this - the parameter you need to set is
+"mangled names = yes".
+
+<sect1>My client reports "cannot locate specified computer" or similar<p><label id="cant_see_server">
+This indicates one of three things: You supplied an incorrect server
+name, the underlying TCP/IP layer is not working correctly, or the
+name you specified cannot be resolved.
+
+After carefully checking that the name you typed is the name you
+should have typed, try doing things like pinging a host or telnetting
+to somewhere on your network to see if TCP/IP is functioning OK. If it
+is, the problem is most likely name resolution.
+
+If your client has a facility to do so, hardcode a mapping between the
+hosts IP and the name you want to use. For example, with Man Manager
+or Windows for Workgroups you would put a suitable entry in the file
+LMHOSTS. If this works, the problem is in the communication between
+your client and the netbios name server. If it does not work, then
+there is something fundamental wrong with your naming and the solution
+is beyond the scope of this document.
+
+If you do not have any server on your subnet supplying netbios name
+resolution, hardcoded mappings are your only option. If you DO have a
+netbios name server running (such as the Samba suite's nmbd program),
+the problem probably lies in the way it is set up. Refer to Section
+Two of this FAQ for more ideas.
+
+By the way, remember to REMOVE the hardcoded mapping before further
+tests :-)
+
+<sect1>My client reports "cannot locate specified share name" or similar<p> <label id="cant_see_share">
+This message indicates that your client CAN locate the specified
+server, which is a good start, but that it cannot find a service of
+the name you gave.
+
+The first step is to check the exact name of the service you are
+trying to connect to (consult your system administrator). Assuming it
+exists and you specified it correctly (read your client's doco on how
+to specify a service name correctly), read on:
+
+<itemize>
+<item> Many clients cannot accept or use service names longer than eight characters.
+<item> Many clients cannot accept or use service names containing spaces.
+<item> Some servers (not Samba though) are case sensitive with service names.
+<item> Some clients force service names into upper case.
+</itemize>
+
+<sect1>My client reports "cannot find domain controller", "cannot log on to the network" or similar <p> <label id="cant_see_net">
+Nothing is wrong - Samba does not implement the primary domain name
+controller stuff for several reasons, including the fact that the
+whole concept of a primary domain controller and "logging in to a
+network" doesn't fit well with clients possibly running on multiuser
+machines (such as users of smbclient under Unix). Having said that,
+several developers are working hard on building it in to the next
+major version of Samba. If you can contribute, send a message to
+<htmlurl url="mailto:samba@samba.org" name="samba@samba.org"> !
+
+Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.
+
+For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.
+
+<sect1>Printing doesn't work :-(<p> <label id="no_printing">
+
+Make sure that the specified print command for the service you are
+connecting to is correct and that it has a fully-qualified path (eg.,
+use "/usr/bin/lpr" rather than just "lpr", if you happen to be using
+Unix).
+
+Make sure that the spool directory specified for the service is
+writable by the user connected to the service.
+
+Make sure that the user specified in the service is permitted to use
+the printer.
+
+Check the debug log produced by smbd. Search for the printer name and
+see if the log turns up any clues. Note that error messages to do with
+a service ipc$ are meaningless - they relate to the way the client
+attempts to retrieve status information when using the LANMAN1
+protocol.
+
+If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.
+
+If using the Lanman1 protocol (the default) then try switching to
+coreplus. Also not that print status error messages don't mean
+printing won't work. The print status is received by a different
+mechanism.
+
+<sect1>My programs install on the server OK, but refuse to work properly<p><label id="programs_wont_run">
+There are numerous possible reasons for this, but one MAJOR
+possibility is that your software uses locking. Make sure you are
+using Samba 1.6.11 or later. It may also be possible to work around
+the problem by setting "locking=no" in the Samba configuration file
+for the service the software is installed on. This should be regarded
+as a strictly temporary solution.
+
+In earlier Samba versions there were some difficulties with the very
+latest Microsoft products, particularly Excel 5 and Word for Windows
+6. These should have all been solved. If not then please let Andrew
+Tridgell know via email at <htmlurl url="mailto:samba@samba.org" name="samba@samba.org">.
+
+<sect1>My "server string" doesn't seem to be recognised<p><label id="bad_server_string">
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.
+
+You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.
+
+Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+<sect1>My client reports "This server is not configured to list shared resources" <p> <label id="cant_list_shares">
+Your guest account is probably invalid for some reason. Samba uses the
+guest account for browsing in smbd. Check that your guest account is
+valid.
+
+See also 'guest account' in smb.conf man page.
+
+<sect1>Issues specific to Unix and Unix-like systems<p><label id="UnixIssues">
+
+<sect2>Printing doesn't work with my Unix Samba server<p> <label id="no_printing">
+
+The user "nobody" often has problems with printing, even if it worked
+with an earlier version of Samba. Try creating another guest user other
+than "nobody".
+
+<sect2>Log message "you appear to have a trapdoor uid system" <p><label id="trapdoor_uid">
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.
+
+It might also mean that your OS has a trapdoor uid/gid system :-)
+
+This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.
+
+The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.
+
+Complain to your OS vendor and ask them to fix their system.
+
+Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!
+
+<sect1>Issues specific to IBM OS/2 systems<p><label id="OS2Issues">
+
+<url url="http://carol.wins.uva.nl/~leeuw/samba/samba2.html" name="Samba for OS/2">
+
+<sect1>Issues specific to IBM MVS systems<p><label id="MVSIssues">
+
+<url url="ftp://ftp.mks.com/pub/samba/" name="Samba for OS/390 MVS">
+
+<sect1>Issues specific to Digital VMS systems<p><label id="VMSIssues">
+
+<sect1>Issues specific to Amiga systems<p><label id="AmigaIssues">
+
+<url url="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/" name="Samba for Amiga">
+
+There is a mailing list for Samba on the Amiga.
+
+ Subscribing.
+
+ Send an email to rask-samba-request@kampsax.dtu.dk with the word subscribe
+in the message. The list server will use the address in the Reply-To: or
+From: header field, in that order.
+
+ Unsubscribing.
+
+ Send an email to rask-samba-request@kampsax.dtu.dk with the word
+unsubscribe in the message. The list server will use the address in the
+Reply-To: or From: header field, in that order. If you are unsure which
+address you are subscribed with, look at the headers. You should see a
+"From " (no colon) or Return-Path: header looking something like
+
+ rask-samba-owner-myname=my.domain@kampsax.dtu.dk
+
+where myname=my.domain gives you the address myname@my.domain. This also
+means that I will always be able to find out which address is causing
+bounces, for example.
+ List archive.
+
+ Messages sent to the list are archived in HTML. See the mailing list home
+page at <URL url="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/">
+
+<sect1>Issues specific to Novell IntraNetware systems<p><label id="NetwareIssues">
+
+<sect1>Issues specific to Stratos VOS systems<p><label id="NetwareIssues">
+
+<url url="ftp://ftp.stratus.com/pub/vos/tools/" name="Samba for Stratus VOS">
+
+</article>
diff --git a/docs/faq/Samba-meta-FAQ-1.html b/docs/faq/Samba-meta-FAQ-1.html
new file mode 100644
index 00000000000..7258a32f1e2
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-1.html
@@ -0,0 +1,160 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Quick Reference Guides to Samba Documentation</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-meta-FAQ-2.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. Quick Reference Guides to Samba Documentation</A></H2>
+
+<P>
+<A NAME="quickref"></A>
+</P>
+<P>We are endeavouring to provide links here to every major class of
+information about Samba or things related to Samba. We cannot list every
+document, but we are aiming for all documents to be at most two
+referrals from those listed here. This needs constant maintaining, so
+please send the author your feedback.</P>
+
+<H2><A NAME="ss1.1">1.1 Samba for the Impatient</A></H2>
+
+<P>
+<A NAME="impatient"></A>
+</P>
+<P>You know you should read the documentation but can't wait to start? What
+you need to do then is follow the instructions in the following
+documents in the order given. This should be enough to get a fairly
+simple site going quickly. If you have any problems, refer back to this
+meta-FAQ and follow the links to find more reading material.</P>
+<P>
+<DL>
+<P>
+<A NAME="ImpGet"></A>
+</P>
+<DT><B>Getting Samba:</B><DD><P>The fastest way to get Samba
+going is and install it is to have an operating system for which the
+Samba team has put together an installation package. To see if your OS
+is included have a look at the directory
+/pub/samba/Binary_Packages/"OS_Vendor" on your nearest
+<A HREF="../MIRRORS">mirror site</A>. If it is included follow the
+installation instructions in the README file there and then do some
+<A HREF="#ImpTest">basic testing</A>. If you are not so fortunate, follow the normal
+<A HREF="Samba-meta-FAQ-2.html#WhereFrom">download instructions</A> and then continue with
+<A HREF="#ImpInst">building and installing Samba</A>.</P>
+<P>
+<A NAME="ImpInst"></A>
+</P>
+<DT><B>Building and Installing Samba:</B><DD><P>At the moment
+there are two kinds of Samba server installs besides the prepackaged
+binaries mentioned in the previous step. You need to decide if you have a
+<A HREF="../UNIX_INSTALL.txt">Unix or close relative</A> or
+<A HREF="Samba-Server-FAQ.html#PortInfo">other supported operating system</A>.</P>
+<P>
+<A NAME="ImpTest"></A>
+</P>
+<DT><B>Basic Testing:</B><DD><P>Try to connect using the
+supplied smbclient command-line program. You need to know the IP
+hostname of your server. A service name must be defined in smb.conf, as
+given in the examples (under many operating systems if there is a
+<F>homes</F> service you can just use a valid username.) Then type
+<CODE>smbclient \\hostname\servicename</CODE>
+Under most Unixes you will need to put the parameters within quotation
+marks. If this works, try connecting from one of the SMB clients you
+were planning to use with Samba.</P>
+<P>
+<A NAME="ImpDebug"></A>
+</P>
+<DT><B>Debug sequence:</B><DD><P>If you think you have completed the
+previous step and things aren't working properly work through
+<A HREF="../DIAGNOSIS.txt">the diagnosis recipe.</A></P>
+<P>
+<A NAME="ImpExp"></A>
+</P>
+<DT><B>Exporting files to SMB clients:</B><DD><P>You should read the manual pages
+for smb.conf, but here is a
+<A HREF="Samba-Server-FAQ.html#Exporting">quick answer guide.</A></P>
+<P>
+<A NAME="ImpControl"></A>
+</P>
+<DT><B>Controlling user access:</B><DD><P>the quickest and dirtiest way of sharing
+resources is to use
+<A HREF="Samba-meta-FAQ-4.html#ShareModeSecurity">share level security.</A> If you want to spend more time and have a proper username
+and password database you must read the paragraph on
+<A HREF="Samba-meta-FAQ-4.html#DomainModeSecurity">domain mode security.</A> If you want
+encryption (eg you are using Windows NT clients) follow the
+<A HREF="Samba-Server-FAQ.html#SMBEncryptionSteps">SMB encryption instructions.</A></P>
+<P>
+<A NAME="ImpBrowse"></A>
+</P>
+<DT><B>Browsing:</B><DD><P>if you are happy to type in "\\samba-server\sharename"
+at the client end then do not read any further. Otherwise you need to
+understand the
+browsing terminology</A>
+and read
+<A HREF="Samba-Server-FAQ.html#NameBrowsing">Samba-Server-FAQ.html#NameBrowsing</A>. </P>
+<P>
+<A NAME="ImpPrint"></A>
+</P>
+<DT><B>Printing:</B><DD><P>See the
+<A HREF="Samba-Server-FAQ.html#Printing">printing quick answer guide.</A></P>
+
+</DL>
+</P>
+<P>If you have got everything working to this point, you can expect Samba
+to be stable and secure: these are its greatest strengths. However Samba
+has a great deal to offer and to go further you must do some more
+reading. Speed and security optimisations, printer accounting, network
+logons, roving profiles, browsing across multiple subnets and so on are
+all covered either in this document or in those it refers to.</P>
+
+
+<H2><A NAME="ss1.2">1.2 All Samba Documentation</A></H2>
+
+<P>
+<A NAME="AllDocs"></A>
+</P>
+<P>
+<UL>
+<LI> Meta-FAQ. This is the mother of all documents, and is the one you
+are reading now. The latest version is always at
+<A HREF="http://samba.org/[.....]">http://samba.org/[.....]</A> but there is probably a much
+nearer
+<A HREF="../MIRRORS">mirror site</A> which you should use
+instead.
+</LI>
+<LI>
+<A HREF="Samba-Server-FAQ.html">Samba-Server-FAQ.html</A> is the best starting point for
+information about server-side issues. Includes configuration tips and
+pointers for Samba on particular operating systems (with 40 to choose
+from...)
+</LI>
+<LI>
+<A HREF="Samba-Client-FAQ.html">Samba-Client-FAQ.html</A> is the best starting point for
+information about client-side issues, includes a list of all clients
+that are known to work with Samba.
+</LI>
+<LI>
+<A HREF="samba-man-index.html">manual pages</A> contains
+descriptions of and links to all the Samba manual pages, in Unix man and
+postscript format.
+</LI>
+<LI>
+<A HREF="samba-txt-index.html">samba-txt-index.html</A> has descriptions of and links to
+a large number of text files have been contributed to samba covering
+many topics. These are gradually being absorbed into the FAQs and HOWTOs
+but in the meantime you might find helpful answers here.
+</LI>
+<LI>
+</LI>
+</UL>
+</P>
+
+
+<HR>
+Previous
+<A HREF="Samba-meta-FAQ-2.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-2.html b/docs/faq/Samba-meta-FAQ-2.html
new file mode 100644
index 00000000000..1e36332d426
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-2.html
@@ -0,0 +1,384 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: General Information</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-1.html">Previous</A>
+<A HREF="Samba-meta-FAQ-3.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. General Information</A></H2>
+
+<P>
+<A NAME="general_info"></A>
+</P>
+<P>All about Samba - what it is, how to get it, related sources of
+information, how to understand the numbering scheme, pizza
+details.</P>
+
+<H2><A NAME="ss2.1">2.1 What is Samba?</A></H2>
+
+<P>
+<A NAME="introduction"></A>
+</P>
+<P>Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server Message
+Block) and CIFS (Common Internet Filesystem) protocols. Initially
+written for Unix, Samba now also runs on Netware, OS/2, VMS, StratOS and
+Amigas. Ports to BeOS and other operating systems are underway. Samba
+gives the capability for these operating systems to behave much like a
+LAN Server, Windows NT Server or Pathworks machine, only with added
+functionality and flexibility designed to make life easier for
+administrators. </P>
+<P>This means that using Samba you can share a server's disks and printers
+to many sorts of network clients, including Lan Manager, Windows for
+Workgroups, Windows NT, Linux, OS/2, and AIX. There is also a generic
+client program supplied as part of the Samba suite which gives a user on
+the server an ftp-like interface to access filespace and printers on any
+other SMB/CIFS servers.</P>
+<P>SMB has been implemented over many protocols, including XNS, NBT, IPX,
+NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to change
+although there have been some requests for NetBEUI support.</P>
+<P>Many users report that compared to other SMB implementations Samba is
+more stable, faster, and compatible with more clients. Administrators of
+some large installations say that Samba is the only SMB server available
+which will scale to many tens of thousands of users without crashing.
+The easy way to test these claims is to download it and try it for
+yourself!</P>
+<P>The suite is supplied with full source code under the
+<A HREF="../COPYING">GNU Public License</A>. The GPL means that you can
+use Samba for whatever purpose you wish (including changing the source
+or selling it for money) but under all circumstances the source code
+must be made freely available. A copy of the GPL must always be included
+in any copy of the package.</P>
+<P>The primary creator of the Samba suite is Andrew Tridgell. Later
+versions incorporate much effort by many net.helpers. The man pages
+and this FAQ were originally written by Karl Auer.</P>
+
+
+<H2><A NAME="ss2.2">2.2 What is the current version of Samba?</A></H2>
+
+<P>
+<A NAME="current_version"></A>
+</P>
+<P>At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file.
+<A HREF="ftp://samba.org/pub/samba/alpha/change-log">ftp://samba.org/pub/samba/alpha/change-log</A></P>
+<P>For more information see
+<A HREF="#version_nums">What do the version numbers mean?</A></P>
+
+
+<H2><A NAME="ss2.3">2.3 Where can I get it? </A></H2>
+
+<P>
+<A NAME="WhereFrom"></A>
+</P>
+<P>The Samba suite is available via anonymous ftp from samba.org and
+many
+<A HREF="../MIRRORS">mirror</A> sites. You will get much
+faster performance if you use a mirror site. The latest and greatest
+versions of the suite are in the directory:</P>
+<P>/pub/samba/</P>
+<P>Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are available
+in the directory:</P>
+<P>/pub/samba/alpha</P>
+<P>Note that binaries are NOT included in any of the above. Samba is
+distributed ONLY in source form, though binaries may be available from
+other sites. Most Linux distributions, for example, do contain Samba
+binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ports typically have binaries made available.</P>
+<P>A special case is vendor-provided binary packages. Samba binaries and
+default configuration files are put into packages for a specific
+operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+already included, and others such as OS/2 may follow. All packages are
+in the directory:</P>
+<P>/pub/samba/Binary_Packages/"OS_Vendor"</P>
+
+
+<H2><A NAME="ss2.4">2.4 What do the version numbers mean?</A></H2>
+
+<P>
+<A NAME="version_nums"></A>
+</P>
+<P>It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.</P>
+<P>How the scheme works:</P>
+<P>
+<OL>
+<LI>When major changes are made the version number is increased. For
+example, the transition from 1.9.16 to 1.9.17. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+</LI>
+<LI>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+</LI>
+<LI>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.17.
+</LI>
+<LI>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.17p2.
+</LI>
+</OL>
+</P>
+<P>So the progression goes:</P>
+<P>
+<PRE>
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+</PRE>
+</P>
+<P>The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.</P>
+
+
+<H2><A NAME="ss2.5">2.5 Where can I go for further information?</A></H2>
+
+<P>
+<A NAME="more"></A>
+</P>
+<P>There are a number of places to look for more information on Samba,
+including:</P>
+<P>
+<UL>
+<LI>Two mailing lists devoted to discussion of Samba-related matters.
+See below for subscription information.
+</LI>
+<LI>The newsgroup comp.protocols.smb, which has a great deal of
+discussion about Samba.
+</LI>
+<LI>The WWW site 'SAMBA Web Pages' at
+<A HREF="http://samba.org/samba/">http://samba.org/samba/</A> includes:
+
+<UL>
+<LI>Links to man pages and documentation, including this FAQ</LI>
+<LI>A comprehensive survey of Samba users</LI>
+<LI>A searchable hypertext archive of the Samba mailing list</LI>
+<LI>Links to Samba source code, binaries, and mirrors of both</LI>
+<LI>This FAQ and the rest in its family</LI>
+</UL>
+
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.6">2.6 How do I subscribe to the Samba Mailing Lists?</A></H2>
+
+<P>
+<A NAME="mailinglist"></A>
+</P>
+<P>Send email to
+<A HREF="mailto:listproc@samba.org">listproc@samba.org</A>. Make sure the subject line is blank,
+and include the following two lines in the body of the message:</P>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</PRE>
+</CODE></BLOCKQUOTE>
+</P>
+<P>Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature, it
+sometimes confuses the list processor.</P>
+<P>The samba list is a digest list - every eight hours or so it sends a
+single message containing all the messages that have been received by
+the list since the last time and sends a copy of this message to all
+subscribers. There are thousands of people on this list.</P>
+<P>If you stop being interested in Samba, please send another email to
+<A HREF="mailto:listproc@samba.org">listproc@samba.org</A>. Make sure the subject line is blank, and
+include the following two lines in the body of the message:</P>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+unsubscribe samba
+unsubscribe samba-announce
+</PRE>
+</CODE></BLOCKQUOTE>
+</P>
+<P>The <B>From:</B> line in your message <EM>MUST</EM> be the same
+address you used when you subscribed.</P>
+
+
+<H2><A NAME="ss2.7">2.7 Something's gone wrong - what should I do?</A></H2>
+
+<P>
+<A NAME="wrong"></A>
+</P>
+<P><B><F>#</F> *** IMPORTANT! *** <F>#</F></B></P>
+
+<P>DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!</P>
+<P>
+<OL>
+<LI> See if there are any likely looking entries in this FAQ!
+If you have just installed Samba, have you run through the checklist in
+<A HREF="ftp://samba.org/pub/samba/DIAGNOSIS.txt">DIAGNOSIS.txt</A>? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba
+distribution.
+</LI>
+<LI> Read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.
+</LI>
+<LI> If there is no obvious solution to hand, try to get a look at
+the log files for smbd and/or nmbd for the period during which you
+were having problems. You may need to reconfigure the servers to
+provide more extensive debugging information - usually level 2 or
+level 3 provide ample debugging info. Inspect these logs closely,
+looking particularly for the string "Error:".
+</LI>
+<LI> If you need urgent help and are willing to pay for it see
+<A HREF="#PaidSupport">Paid Support</A>.
+</LI>
+</OL>
+</P>
+<P>If you still haven't got anywhere, ask the mailing list or newsgroup. In
+general nobody minds answering questions provided you have followed the
+preceding steps. It might be a good idea to scan the archives of the
+mailing list, which are available through the Samba web site described
+in the previous section. When you post be sure to include a good
+description of your environment and your problem.</P>
+<P>If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+that an explanation can be incorporated into the next version.</P>
+
+
+<H2><A NAME="ss2.8">2.8 How do I submit patches or bug reports?</A></H2>
+
+
+<P>If you make changes to the source code, <EM>please</EM> submit these patches
+so that everyone else gets the benefit of your work. This is one of
+the most important aspects to the maintainence of Samba. Send all
+patches to
+<A HREF="mailto:samba@samba.org">samba@samba.org</A>. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.</P>
+<P>Patch format
+------------</P>
+<P>If you are sending a patch to fix a problem then please don't just use
+standard diff format. As an example, samba@samba.org received this patch from
+someone:</P>
+<P>382a
+#endif
+..
+381a
+#if !defined(NEWS61)</P>
+<P>How are we supposed to work out what this does and where it goes? These
+sort of patches only work if we both have identical files in the first
+place. The Samba sources are constantly changing at the hands of multiple
+developers, so it doesn't work.</P>
+<P>Please use either context diffs or (even better) unified diffs. You
+get these using "diff -c4" or "diff -u". If you don't have a diff that
+can generate these then please send manualy commented patches to I
+know what is being changed and where. Most patches are applied by hand so
+the info must be clear.</P>
+<P>This is a basic guideline that will assist us with assessing your problem
+more efficiently :</P>
+<P>Machine Arch:
+Machine OS:
+OS Version:
+Kernel:</P>
+<P>Compiler:
+Libc Version:</P>
+<P>Samba Version:</P>
+<P>Network Layout (description):</P>
+<P>What else is on machine (services, etc):</P>
+<P>Some extras :</P>
+<P>
+<UL>
+<LI> what you did and what happened
+</LI>
+<LI> relevant parts of a debugging output file with debuglevel higher.
+If you can't find the relevant parts, please ask before mailing
+huge files.
+</LI>
+<LI> anything else you think is useful to trace down the bug
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.9">2.9 What if I have an URGENT message for the developers?</A></H2>
+
+
+<P>If you have spotted something very serious and believe that it is
+important to contact the developers quickly send a message to
+samba-urgent@samba.org. This will be processed more quickly than
+mail to samba@samba.org. Please think carefully before using this address. An
+example of its use might be to report a security hole.</P>
+<P>Examples of things <EM>not</EM> to send to samba-urgent include problems
+getting Samba to work at all and bugs that cannot potentially cause damage.</P>
+
+
+<H2><A NAME="ss2.10">2.10 What if I need paid-for support?</A></H2>
+
+<P>
+<A NAME="PaidSupport"></A>
+</P>
+<P>Samba has a large network of consultants who provide Samba support on a
+commercial basis. The list is included in the package in
+<A HREF="../Support.txt">../Support.txt</A>, and the latest version will always be on the main
+samba ftp site. Any company in the world can request that the samba team
+include their details in Support.txt so we can give no guarantee of
+their services.</P>
+
+
+<H2><A NAME="ss2.11">2.11 Pizza supply details</A></H2>
+
+<P>
+<A NAME="pizza"></A>
+
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.</P>
+<P>
+<OL>
+<LI> Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US.
+</LI>
+<LI>Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+</LI>
+<LI>Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+</LI>
+<LI>Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+</LI>
+</OL>
+</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-1.html">Previous</A>
+<A HREF="Samba-meta-FAQ-3.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-3.html b/docs/faq/Samba-meta-FAQ-3.html
new file mode 100644
index 00000000000..8ebb38a3345
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-3.html
@@ -0,0 +1,101 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: About the CIFS and SMB Protocols</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-2.html">Previous</A>
+<A HREF="Samba-meta-FAQ-4.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc3">Table of Contents</A>
+<HR>
+<H2><A NAME="s3">3. About the CIFS and SMB Protocols</A></H2>
+
+<P>
+<A NAME="CifsSmb"></A>
+</P>
+
+<H2><A NAME="ss3.1">3.1 What is the Server Message Block (SMB) Protocol?</A></H2>
+
+<P>SMB is a filesharing protocol that has had several maintainers and
+contributors over the years including Xerox, 3Com and most recently
+Microsoft. Names for this protocol include LAN Manager and Microsoft
+Networking. Parts of the specification has been made public at several
+versions including in an X/Open document, as listed at
+<A HREF="ftp://ftp.microsoft.com/developr/drg/CIFS/">ftp://ftp.microsoft.com/developr/drg/CIFS/</A>. No specification
+releases were made between 1992 and 1996, and during that period
+Microsoft became the SMB implementor with the largest market share.
+Microsoft developed the specification further for its products but for
+various reasons connected with developer's workload rather than market
+strategy did not make the changes public. This culminated with the
+"Windows NT 0.12" version released with NT 3.5 in 1995 which had significant
+improvements and bugs. Because Microsoft client systems are so popular,
+it is fair to say that what Microsoft with Windows affects all suppliers
+of SMB server products.</P>
+<P>From 1994 Andrew Tridgell began doing some serious work on his
+Smbserver (now Samba) product and with some helpers started to
+implement more and more of these protocols. Samba began to take
+a significant share of the SMB server market.</P>
+
+
+<H2><A NAME="ss3.2">3.2 What is the Common Internet Filesystem (CIFS)?</A></H2>
+
+<P>The initial pressure for Microsoft to document their current SMB
+implementation came from the Samba team, who kept coming across things
+on the wire that Microsoft either didn't know about or hadn't documented
+anywhere (even in the sourcecode to Windows NT.) Then Sun Microsystems
+came out with their WebNFS initiative, designed to replace FTP for file
+transfers on the Internet. There are many drawbacks to WebNFS (including
+its scope - it aims to replace HTTP as well!) but the concept was
+attractive. FTP is not very clever, and why should it be harder to get
+files from across the world than across the room? </P>
+<P>Some hasty revisions were made and an Internet Draft for the Common
+Internet Filesystem (CIFS) was released. Note that CIFS is not an
+Internet standard and is a very long way from becoming one, BUT the
+protocol specification is in the public domain and ongoing discussions
+concerning the spec take place on a public mailing list according to the
+rules of the Internet Engineering Task Force. For more information and
+pointers see
+<A HREF="http://samba.org/cifs/">http://samba.org/cifs/</A></P>
+<P>The following is taken from
+<A HREF="http://www.microsoft.com/intdev/cifs/">http://www.microsoft.com/intdev/cifs/</A></P>
+<P>
+<PRE>
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft® Windows® and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX®. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work.&quot;
+</PRE>
+</P>
+<P>If you consider CIFS as a backwardsly-compatible refinement of SMB that
+will work reasonably efficiently over the Internet you won't be too far
+wrong.</P>
+<P>The net effect is that Microsoft is now documenting large parts of their
+Windows NT fileserver protocols. The security concepts embodied in
+Windows NT are part of the specification, which is why Samba
+documentation often talks in terms of Windows NT. However there is no
+reason why a site shouldn't conduct all its file and printer sharing
+with CIFS and yet have no Microsoft products at all.</P>
+
+
+<H2><A NAME="ss3.3">3.3 What is Browsing? </A></H2>
+
+<P>The term "Browsing" causes a lot of confusion. It is the part of the
+SMB/CIFS protocol which allows for resource discovery. For example, in
+the Windows NT Explorer it is possible to see a "Network Neighbourhood"
+of computers in the same SMB workgroup. Clicking on the name of one of
+these machines brings up a list of file and printer resources for
+connecting to. In this way you can cruise the network, seeing what
+things are available. How this scales to the Internet is a subject for
+debate. Look at the CIFS list archives to see what the experts think.</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-2.html">Previous</A>
+<A HREF="Samba-meta-FAQ-4.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc3">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-4.html b/docs/faq/Samba-meta-FAQ-4.html
new file mode 100644
index 00000000000..73a9eea8471
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-4.html
@@ -0,0 +1,215 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Designing A SMB and CIFS Network</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-3.html">Previous</A>
+<A HREF="Samba-meta-FAQ-5.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc4">Table of Contents</A>
+<HR>
+<H2><A NAME="s4">4. Designing A SMB and CIFS Network</A></H2>
+
+
+<P>The big issues for installing any network of LAN or WAN file and print
+servers are </P>
+<P>
+<UL>
+<LI>How and where usernames, passwords and other security information
+is stored
+</LI>
+<LI>What method can be used for locating the resources that users have
+permission to use
+</LI>
+<LI>What protocols the clients can converse with
+</LI>
+</UL>
+ </P>
+<P>If you buy Netware, Windows NT or just about any other LAN fileserver
+product you are expected to lock yourself into the product's preferred
+answers to these questions. This tendancy is restrictive and often very
+expensive for a site where there is only one kind of client or server,
+and for sites with a mixture of operating systems it often makes it
+impossible to share resources between some sets of users.</P>
+<P>The Samba philosophy is to make things as easy as possible for
+administators, which means allowing as many combinations of clients,
+servers, operating systems and protocols as possible.</P>
+
+<H2><A NAME="ss4.1">4.1 Workgroups, Domains, Authentication and Browsing</A></H2>
+
+
+<P>From the point of view of networking implementation, Domains and
+Workgroups are <EM>exactly</EM> the same, except for the client logon
+sequence. Some kind of distributed authentication database is associated
+with a domain (there are quite a few choices) and this adds so much
+flexibility that many people think of a domain as a completely different
+entity to a workgroup. From Samba's point of view a client connecting to
+a service presents an authentication token, and it if it is valid they
+have access. Samba does not care what mechanism was used to generate
+that token in the first place.</P>
+<P>The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+However the network browsing functionality of domains and workgroups is
+identical and is explained in
+<A HREF="../BROWSING.txt">../BROWSING.txt</A>.</P>
+<P>There are some implementation differences: Windows 95 can be a member of
+both a workgroup and a domain, but Windows NT cannot. Windows 95 also
+has the concept of an "alternative workgroup". Samba can only be a
+member of a single workgroup or domain, although this is due to change
+with a future version when nmbd will be split into two daemons, one for
+WINS and the other for browsing (
+<A HREF="../NetBIOS.txt">../NetBIOS.txt</A> explains
+what WINS is.)</P>
+
+<H3>Defining the Terms</H3>
+
+<P>
+<A NAME="BrowseAndDomainDefs"></A>
+</P>
+<P>
+<DL>
+
+<DT><B>Workgroup</B><DD><P>means a collection of machines that maintain a common
+browsing database containing information about their shared resources.
+They do not necessarily have any security information in common (if they
+do, it gets called a Domain.) The browsing database is dynamic, modified
+as servers come and go on the network and as resources are added or
+deleted. The term "browsing" refers to a user accessing the database via
+whatever interface the client provides, eg the OS/2 Workplace Shell or
+Windows 95 Explorer. SMB servers agree between themselves as to which
+ones will maintain the browsing database. Workgroups can be anywhere on
+a connected TCP/IP network, including on different subnets or even on
+the Interet. This is a very tricky part of SMB to implement.</P>
+
+<DT><B>Master Browsers</B><DD><P>are machines which holds the master browsing
+database for a workgroup or domain. There are two kinds of Master Browser:</P>
+<P>
+<UL>
+<LI> Domain Master Browser, which holds the master browsing
+information for an entire domain, which may well cross multiple TCP/IP
+subnets.
+</LI>
+<LI> Local Master Browser, which holds the master browsing database
+for a particular subnet and communicates with the Domain Master Browser
+to get information on other subnets.
+</LI>
+</UL>
+</P>
+<P>Subnets are differentiated because browsing is based on broadcasts, and
+broadcasts do not pass through routers. Subnets are not routed: while it
+is possible to have more than one subnet on a single network segment
+this is regarded as very bad practice.</P>
+<P>Master Browsers (both Domain and Local) are elected dynamically
+according to an algorithm which is supposed to take into account the
+machine's ability to sustain the browsing load. Samba can be configured
+to always act as a master browser, ie it always wins elections under all
+circumstances, even against systems such as a Windows NT Primary Domain
+Controller which themselves expect to win. </P>
+<P>There are also Backup Browsers which are promoted to Master Browsers in
+the event of a Master Browser disappearing from the network.</P>
+<P>Alternative terms include confusing variations such as "Browse Master",
+and "Master Browser" which we are trying to eliminate from the Samba
+documentation. </P>
+
+<DT><B>Domain Controller</B><DD><P>is a term which comes from the Microsoft and IBM
+etc implementation of the LAN Manager protocols. It is tied to
+authentication. There are other ways of doing domain authentication, but
+the Windows NT method has a large market share. The general issues are
+discussed in
+<A HREF="../DOMAIN.txt">../DOMAIN.txt</A> and a Windows NT-specific
+discussion is in
+<A HREF="../DOMAIN_CONTROL.txt">../DOMAIN_CONTROL.txt</A>.</P>
+
+</DL>
+</P>
+
+<H3>Sharelevel (Workgroup) Security Services</H3>
+
+<P>
+<A NAME="ShareModeSecurity"></A>
+</P>
+<P>With the Samba setting "security = SHARE", all shared resources
+information about what password is associated with them but only hints
+as to what usernames might be valid (the hint can be 'all users', in
+which case any username will work. This is usually a bad idea, but
+reflects both the initial implementations of SMB in the mid-80s and
+its reincarnation with Windows for Workgroups in 1992. The idea behind
+workgroup security was that small independant groups of people could
+share information on an ad-hoc basis without there being an
+authentication infrastructure present or requiring them to do more than
+fill in a dialogue box.</P>
+
+<H3>Authentication Domain Mode Services</H3>
+
+<P>
+<A NAME="DomainModeSecurity"></A>
+</P>
+<P>With the Samba settings "security = USER" or "security = SERVER"
+accesses to all resources are checked for username/password pair matches
+in a more rigorous manner. To the client, this has the effect of
+emulating a Microsoft Domain. The client is not concerned whether or not
+Samba looks up a Windows NT SAM or does it in some other way.</P>
+
+
+<H2><A NAME="ss4.2">4.2 Authentication Schemes</A></H2>
+
+
+<P>In the simple case authentication information is stored on a single
+server and the user types a password on connecting for the first time.
+However client operating systems often require a password before they
+can be used at all, and in addition users usually want access to more
+than one server. Asking users to remember many different passwords in
+different contexts just does not work. Some kind of distributed
+authentication database is needed. It must cope with password changes
+and provide for assigning groups of users the same level of access
+permissions. This is why Samba installations often choose to implement a
+Domain model straight away.</P>
+<P>Authentication decisions are some of the biggest in designing a network.
+Are you going to use a scheme native to the client operating system,
+native to the server operating system, or newly installed on both? A
+list of options relevant to Samba (ie that make sense in the context of
+the SMB protocol) follows. Any experiences with other setups would be
+appreciated. <F>refer to server FAQ for "passwd chat" passwd program
+password server etc etc...</F></P>
+
+<H3>NIS</H3>
+
+
+<P>For Windows 95, Windows for Workgroups and most other clients Samba can
+be a domain controller and share the password database via NIS
+transparently. Windows NT is different.
+<A HREF="http://www.dcs.qmw.ac.uk/~williams">Free NIS NT client</A></P>
+
+<H3>Kerberos</H3>
+
+
+<P>Kerberos for US users only:
+<A HREF="http://www.cygnus.com/product/unifying-security.html">Kerberos overview</A>
+<A HREF="http://www.cygnus.com/product/kerbnet-download.html">Download Kerberos</A></P>
+
+<H3>FTP</H3>
+
+
+<P>Other NT w/s logon hack via NT</P>
+
+<H3>Default Server Method</H3>
+
+
+
+<H3>Client-side Database Only</H3>
+
+
+
+
+<H2><A NAME="ss4.3">4.3 Post-Authentication: Netlogon, Logon Scripts, Profiles</A></H2>
+
+
+<P>See
+<A HREF="../DOMAIN.txt">../DOMAIN.txt</A></P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-3.html">Previous</A>
+<A HREF="Samba-meta-FAQ-5.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc4">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-5.html b/docs/faq/Samba-meta-FAQ-5.html
new file mode 100644
index 00000000000..ad528b0a975
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-5.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Cross-Protocol File Sharing</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-4.html">Previous</A>
+<A HREF="Samba-meta-FAQ-6.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc5">Table of Contents</A>
+<HR>
+<H2><A NAME="s5">5. Cross-Protocol File Sharing</A></H2>
+
+
+<P>Samba is an important tool for...</P>
+<P>It is possible to...</P>
+<P>File protocol gateways...</P>
+<P>"Setting up a Linux File Server" http://vetrec.mit.edu/people/narf/linux.html</P>
+<P>Two free implementations of Appletalk for Unix are Netatalk,
+<A HREF="http://www.umich.edu/~rsug/netatalk/">http://www.umich.edu/~rsug/netatalk/</A>, and CAP,
+<A HREF="http://www.cs.mu.oz.au/appletalk/atalk.html">http://www.cs.mu.oz.au/appletalk/atalk.html</A>. What Samba offers MS
+Windows users, these packages offer to Macs. For more info on these
+packages, Samba, and Linux (and other UNIX-based systems) see
+<A HREF="http://www.eats.com/linux_mac_win.html">http://www.eats.com/linux_mac_win.html</A> 3.5) Sniffing your nework</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-4.html">Previous</A>
+<A HREF="Samba-meta-FAQ-6.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc5">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-6.html b/docs/faq/Samba-meta-FAQ-6.html
new file mode 100644
index 00000000000..f8cd7817d69
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-6.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Miscellaneous</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-5.html">Previous</A>
+Next
+<A HREF="Samba-meta-FAQ.html#toc6">Table of Contents</A>
+<HR>
+<H2><A NAME="s6">6. Miscellaneous</A></H2>
+
+<P>
+<A NAME="miscellaneous"></A>
+</P>
+<H2><A NAME="ss6.1">6.1 Is Samba Year 2000 compliant?</A></H2>
+
+<P>
+<A NAME="Year2000Compliant"></A>
+
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-5.html">Previous</A>
+Next
+<A HREF="Samba-meta-FAQ.html#toc6">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ.html b/docs/faq/Samba-meta-FAQ.html
new file mode 100644
index 00000000000..38f094bf339
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-meta-FAQ-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba meta FAQ</H1>
+
+<H2>Dan Shearer & Paul Blackman, <CODE>ictinus@samba.org</CODE></H2>v 0.3, 7 Oct '97
+<P><HR><EM> This is the meta-Frequently Asked Questions (FAQ) document
+for Samba, the free and very popular SMB and CIFS server product. It
+contains overview information for the Samba suite of programs, a
+quick-start guide, and pointers to all other Samba documentation. Other
+FAQs exist for specific client and server issues, and HOWTO documents
+for more extended topics to do with Samba software. Current to version
+Samba 1.9.17. Please send any corrections to the author. </EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="Samba-meta-FAQ-1.html">Quick Reference Guides to Samba Documentation</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-1.html#ss1.1">1.1 Samba for the Impatient</A>
+<LI><A HREF="Samba-meta-FAQ-1.html#ss1.2">1.2 All Samba Documentation</A>
+</UL>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="Samba-meta-FAQ-2.html">General Information</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.1">2.1 What is Samba?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.2">2.2 What is the current version of Samba?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.3">2.3 Where can I get it? </A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.4">2.4 What do the version numbers mean?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.5">2.5 Where can I go for further information?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.6">2.6 How do I subscribe to the Samba Mailing Lists?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.7">2.7 Something's gone wrong - what should I do?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.8">2.8 How do I submit patches or bug reports?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.9">2.9 What if I have an URGENT message for the developers?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.10">2.10 What if I need paid-for support?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.11">2.11 Pizza supply details</A>
+</UL>
+
+<P>
+<H2><A NAME="toc3">3.</A> <A HREF="Samba-meta-FAQ-3.html">About the CIFS and SMB Protocols</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.1">3.1 What is the Server Message Block (SMB) Protocol?</A>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.2">3.2 What is the Common Internet Filesystem (CIFS)?</A>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.3">3.3 What is Browsing? </A>
+</UL>
+
+<P>
+<H2><A NAME="toc4">4.</A> <A HREF="Samba-meta-FAQ-4.html">Designing A SMB and CIFS Network</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.1">4.1 Workgroups, Domains, Authentication and Browsing</A>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.2">4.2 Authentication Schemes</A>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.3">4.3 Post-Authentication: Netlogon, Logon Scripts, Profiles</A>
+</UL>
+
+<P>
+<H2><A NAME="toc5">5.</A> <A HREF="Samba-meta-FAQ-5.html">Cross-Protocol File Sharing</A></H2>
+
+<P>
+<H2><A NAME="toc6">6.</A> <A HREF="Samba-meta-FAQ-6.html">Miscellaneous</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-6.html#ss6.1">6.1 Is Samba Year 2000 compliant?</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="Samba-meta-FAQ-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ.sgml b/docs/faq/Samba-meta-FAQ.sgml
new file mode 100644
index 00000000000..377d81663d7
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.sgml
@@ -0,0 +1,771 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.1 23 Aug 1997 Dan Shearer
+ Original Samba-meta-FAQ.sgml from Paul's sambafaq.sgml
+ v 0.2 25 Aug 1997 Dan
+ v 0.3 7 Oct 1997 Paul
+ Changed samba.canberra refs to samba.anu.../samba/
+-->
+
+<article>
+
+<title> Samba meta FAQ
+
+<author>Dan Shearer & Paul Blackman, <tt>ictinus@samba.org</tt>
+
+<date>v 0.3, 7 Oct '97
+
+<abstract> This is the meta-Frequently Asked Questions (FAQ) document
+for Samba, the free and very popular SMB and CIFS server product. It
+contains overview information for the Samba suite of programs, a
+quick-start guide, and pointers to all other Samba documentation. Other
+FAQs exist for specific client and server issues, and HOWTO documents
+for more extended topics to do with Samba software. Current to version
+Samba 1.9.17. Please send any corrections to the author.
+</abstract>
+
+<toc>
+
+<sect> Quick Reference Guides to Samba Documentation<p><label id=quickref>
+
+We are endeavouring to provide links here to every major class of
+information about Samba or things related to Samba. We cannot list every
+document, but we are aiming for all documents to be at most two
+referrals from those listed here. This needs constant maintaining, so
+please send the author your feedback.
+
+<sect1> Samba for the Impatient<p><label id="impatient">
+
+You know you should read the documentation but can't wait to start? What
+you need to do then is follow the instructions in the following
+documents in the order given. This should be enough to get a fairly
+simple site going quickly. If you have any problems, refer back to this
+meta-FAQ and follow the links to find more reading material.
+
+<descrip>
+
+<label id="ImpGet"><tag/Getting Samba:/ The fastest way to get Samba
+going is and install it is to have an operating system for which the
+Samba team has put together an installation package. To see if your OS
+is included have a look at the directory
+/pub/samba/Binary_Packages/"OS_Vendor" on your nearest <url
+url="../MIRRORS" name="mirror site">. If it is included follow the
+installation instructions in the README file there and then do some <ref id="ImpTest"
+name="basic testing">. If you are not so fortunate, follow the normal <ref
+id="WhereFrom" name="download instructions"> and then continue with <ref
+id="ImpInst" name="building and installing Samba">.
+
+<label id="ImpInst"><tag/Building and Installing Samba:/ At the moment
+there are two kinds of Samba server installs besides the prepackaged
+binaries mentioned in the previous step. You need to decide if you have a <url url="../UNIX_INSTALL.txt"
+name="Unix or close relative"> or <url
+url="Samba-Server-FAQ.html#PortInfo" name="other supported operating system">.
+
+<label id="ImpTest"><tag/Basic Testing:/ Try to connect using the
+supplied smbclient command-line program. You need to know the IP
+hostname of your server. A service name must be defined in smb.conf, as
+given in the examples (under many operating systems if there is a
+[homes] service you can just use a valid username.) Then type
+<tt>
+ smbclient \\hostname\servicename
+</tt>
+Under most Unixes you will need to put the parameters within quotation
+marks. If this works, try connecting from one of the SMB clients you
+were planning to use with Samba.
+
+<label id="ImpDebug"><tag/Debug sequence:/ If you think you have completed the
+previous step and things aren't working properly work through
+<url url="../DIAGNOSIS.txt" name="the diagnosis recipe.">
+
+<label id="ImpExp"><tag/Exporting files to SMB clients:/ You should read the manual pages
+for smb.conf, but here is a <url url="Samba-Server-FAQ.html#Exporting"
+name="quick answer guide.">
+
+<label id="ImpControl"><tag/Controlling user access:/ the quickest and dirtiest way of sharing
+resources is to use <ref id="ShareModeSecurity" name="share level
+security."> If you want to spend more time and have a proper username
+and password database you must read the paragraph on <ref
+id="DomainModeSecurity" name="domain mode security."> If you want
+encryption (eg you are using Windows NT clients) follow the <url
+url="Samba-Server-FAQ.html#SMBEncryptionSteps" name="SMB encryption
+instructions.">
+
+<label id="ImpBrowse"><tag/Browsing:/ if you are happy to type in "\\samba-server\sharename"
+at the client end then do not read any further. Otherwise you need to
+understand the <ref id="BrowsingDefinitions" name="browsing terminology">
+and read <url url="Samba-Server-FAQ.html#NameBrowsing">.
+
+<label id="ImpPrint"><tag/Printing:/ See the <url url="Samba-Server-FAQ.html#Printing"
+name="printing quick answer guide.">
+
+</descrip>
+
+If you have got everything working to this point, you can expect Samba
+to be stable and secure: these are its greatest strengths. However Samba
+has a great deal to offer and to go further you must do some more
+reading. Speed and security optimisations, printer accounting, network
+logons, roving profiles, browsing across multiple subnets and so on are
+all covered either in this document or in those it refers to.
+
+<sect1> All Samba Documentation<p><label id=AllDocs>
+
+<itemize>
+
+<item> Meta-FAQ. This is the mother of all documents, and is the one you
+are reading now. The latest version is always at <url
+url="http://samba.org/[.....]"> but there is probably a much
+nearer <url url="../MIRRORS" name="mirror site"> which you should use
+instead.
+
+<item> <url url="Samba-Server-FAQ.html"> is the best starting point for
+information about server-side issues. Includes configuration tips and
+pointers for Samba on particular operating systems (with 40 to choose
+from...)
+
+<item> <url url="Samba-Client-FAQ.html"> is the best starting point for
+information about client-side issues, includes a list of all clients
+that are known to work with Samba.
+
+<item> <url url="samba-man-index.html" name="manual pages"> contains
+descriptions of and links to all the Samba manual pages, in Unix man and
+postscript format.
+
+<item> <url url="samba-txt-index.html"> has descriptions of and links to
+a large number of text files have been contributed to samba covering
+many topics. These are gradually being absorbed into the FAQs and HOWTOs
+but in the meantime you might find helpful answers here.
+
+<item>
+
+</itemize>
+
+<sect> General Information<p><label id="general_info">
+
+All about Samba - what it is, how to get it, related sources of
+information, how to understand the numbering scheme, pizza
+details.
+
+<sect1> What is Samba?<p><label id="introduction">
+
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server Message
+Block) and CIFS (Common Internet Filesystem) protocols. Initially
+written for Unix, Samba now also runs on Netware, OS/2, VMS, StratOS and
+Amigas. Ports to BeOS and other operating systems are underway. Samba
+gives the capability for these operating systems to behave much like a
+LAN Server, Windows NT Server or Pathworks machine, only with added
+functionality and flexibility designed to make life easier for
+administrators.
+
+This means that using Samba you can share a server's disks and printers
+to many sorts of network clients, including Lan Manager, Windows for
+Workgroups, Windows NT, Linux, OS/2, and AIX. There is also a generic
+client program supplied as part of the Samba suite which gives a user on
+the server an ftp-like interface to access filespace and printers on any
+other SMB/CIFS servers.
+
+SMB has been implemented over many protocols, including XNS, NBT, IPX,
+NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to change
+although there have been some requests for NetBEUI support.
+
+Many users report that compared to other SMB implementations Samba is
+more stable, faster, and compatible with more clients. Administrators of
+some large installations say that Samba is the only SMB server available
+which will scale to many tens of thousands of users without crashing.
+The easy way to test these claims is to download it and try it for
+yourself!
+
+The suite is supplied with full source code under the <url
+url="../COPYING" name="GNU Public License">. The GPL means that you can
+use Samba for whatever purpose you wish (including changing the source
+or selling it for money) but under all circumstances the source code
+must be made freely available. A copy of the GPL must always be included
+in any copy of the package.
+
+The primary creator of the Samba suite is Andrew Tridgell. Later
+versions incorporate much effort by many net.helpers. The man pages
+and this FAQ were originally written by Karl Auer.
+
+<sect1> What is the current version of Samba?<p><label id="current_version">
+
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file. <url url="ftp://samba.org/pub/samba/alpha/change-log">
+
+For more information see <ref id="version_nums" name="What do the version numbers mean?">
+
+<sect1> Where can I get it? <p><label id="WhereFrom">
+
+The Samba suite is available via anonymous ftp from samba.org and
+many <url url="../MIRRORS" name="mirror"> sites. You will get much
+faster performance if you use a mirror site. The latest and greatest
+versions of the suite are in the directory:
+
+/pub/samba/
+
+Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are available
+in the directory:
+
+/pub/samba/alpha
+
+Note that binaries are NOT included in any of the above. Samba is
+distributed ONLY in source form, though binaries may be available from
+other sites. Most Linux distributions, for example, do contain Samba
+binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ports typically have binaries made available.
+
+A special case is vendor-provided binary packages. Samba binaries and
+default configuration files are put into packages for a specific
+operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+already included, and others such as OS/2 may follow. All packages are
+in the directory:
+
+/pub/samba/Binary_Packages/"OS_Vendor"
+
+<sect1>What do the version numbers mean?<p><label id="version_nums">
+
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.
+
+How the scheme works:
+
+<enum>
+
+<item>When major changes are made the version number is increased. For
+example, the transition from 1.9.16 to 1.9.17. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+
+<item>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+
+<item>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.17.
+
+<item>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.17p2.
+
+</enum>
+
+So the progression goes:
+
+<verb>
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+</verb>
+
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.
+
+<sect1> Where can I go for further information?<p><label id="more">
+
+There are a number of places to look for more information on Samba,
+including:
+
+<itemize>
+
+<item>Two mailing lists devoted to discussion of Samba-related matters.
+See below for subscription information.
+
+<item>The newsgroup comp.protocols.smb, which has a great deal of
+discussion about Samba.
+
+<item>The WWW site 'SAMBA Web Pages' at <url
+url="http://samba.org/samba/"> includes:
+
+ <itemize>
+ <item>Links to man pages and documentation, including this FAQ
+ <item>A comprehensive survey of Samba users
+ <item>A searchable hypertext archive of the Samba mailing list
+ <item>Links to Samba source code, binaries, and mirrors of both
+ <item>This FAQ and the rest in its family
+ </itemize>
+
+</itemize>
+
+<sect1>How do I subscribe to the Samba Mailing Lists?<p><label id="mailinglist">
+
+Send email to <htmlurl url="mailto:listproc@samba.org"
+name="listproc@samba.org">. Make sure the subject line is blank,
+and include the following two lines in the body of the message:
+
+<tscreen><verb>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</verb></tscreen>
+
+Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature, it
+sometimes confuses the list processor.
+
+The samba list is a digest list - every eight hours or so it sends a
+single message containing all the messages that have been received by
+the list since the last time and sends a copy of this message to all
+subscribers. There are thousands of people on this list.
+
+If you stop being interested in Samba, please send another email to
+<htmlurl url="mailto:listproc@samba.org" name="listproc@samba.org">. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+
+<tscreen><verb>
+unsubscribe samba
+unsubscribe samba-announce
+</verb></tscreen>
+
+The <bf>From:</bf> line in your message <em>MUST</em> be the same
+address you used when you subscribed.
+
+<sect1> Something's gone wrong - what should I do?<p><label id="wrong">
+
+<bf>[#] *** IMPORTANT! *** [#]</bf>
+<p>
+
+DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!
+
+<enum> <item> See if there are any likely looking entries in this FAQ!
+If you have just installed Samba, have you run through the checklist in
+<url url="ftp://samba.org/pub/samba/DIAGNOSIS.txt"
+name="DIAGNOSIS.txt">? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba
+distribution.
+
+<item> Read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.
+
+<item> If there is no obvious solution to hand, try to get a look at
+the log files for smbd and/or nmbd for the period during which you
+were having problems. You may need to reconfigure the servers to
+provide more extensive debugging information - usually level 2 or
+level 3 provide ample debugging info. Inspect these logs closely,
+looking particularly for the string "Error:".
+
+<item> If you need urgent help and are willing to pay for it see
+<ref id="PaidSupport" name="Paid Support">.
+
+</enum>
+
+If you still haven't got anywhere, ask the mailing list or newsgroup. In
+general nobody minds answering questions provided you have followed the
+preceding steps. It might be a good idea to scan the archives of the
+mailing list, which are available through the Samba web site described
+in the previous section. When you post be sure to include a good
+description of your environment and your problem.
+
+If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+that an explanation can be incorporated into the next version.
+
+<sect1> How do I submit patches or bug reports?<p>
+
+If you make changes to the source code, <em>please</em> submit these patches
+so that everyone else gets the benefit of your work. This is one of
+the most important aspects to the maintainence of Samba. Send all
+patches to <htmlurl url="mailto:samba@samba.org" name="samba@samba.org">. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.
+
+Patch format
+------------
+
+If you are sending a patch to fix a problem then please don't just use
+standard diff format. As an example, samba@samba.org received this patch from
+someone:
+
+382a
+#endif
+..
+381a
+#if !defined(NEWS61)
+
+How are we supposed to work out what this does and where it goes? These
+sort of patches only work if we both have identical files in the first
+place. The Samba sources are constantly changing at the hands of multiple
+developers, so it doesn't work.
+
+Please use either context diffs or (even better) unified diffs. You
+get these using "diff -c4" or "diff -u". If you don't have a diff that
+can generate these then please send manualy commented patches to I
+know what is being changed and where. Most patches are applied by hand so
+the info must be clear.
+
+This is a basic guideline that will assist us with assessing your problem
+more efficiently :
+
+Machine Arch:
+Machine OS:
+OS Version:
+Kernel:
+
+Compiler:
+Libc Version:
+
+Samba Version:
+
+Network Layout (description):
+
+What else is on machine (services, etc):
+
+Some extras :
+
+<itemize>
+
+<item> what you did and what happened
+
+<item> relevant parts of a debugging output file with debuglevel higher.
+ If you can't find the relevant parts, please ask before mailing
+ huge files.
+
+<item> anything else you think is useful to trace down the bug
+
+</itemize>
+
+<sect1> What if I have an URGENT message for the developers?<p>
+
+If you have spotted something very serious and believe that it is
+important to contact the developers quickly send a message to
+samba-urgent@samba.org. This will be processed more quickly than
+mail to samba@samba.org. Please think carefully before using this address. An
+example of its use might be to report a security hole.
+
+Examples of things <em>not</em> to send to samba-urgent include problems
+getting Samba to work at all and bugs that cannot potentially cause damage.
+
+<sect1> What if I need paid-for support?<p><label id=PaidSupport>
+
+Samba has a large network of consultants who provide Samba support on a
+commercial basis. The list is included in the package in <url
+url="../Support.txt">, and the latest version will always be on the main
+samba ftp site. Any company in the world can request that the samba team
+include their details in Support.txt so we can give no guarantee of
+their services.
+
+<sect1> Pizza supply details<p><label id="pizza">
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.
+
+<enum>
+<item> Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US.
+
+<item>Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+
+<item>Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+
+<item>Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+
+</enum>
+
+<sect>About the CIFS and SMB Protocols<p><label id="CifsSmb">
+
+<sect1> What is the Server Message Block (SMB) Protocol?<p>
+SMB is a filesharing protocol that has had several maintainers and
+contributors over the years including Xerox, 3Com and most recently
+Microsoft. Names for this protocol include LAN Manager and Microsoft
+Networking. Parts of the specification has been made public at several
+versions including in an X/Open document, as listed at
+<url url="ftp://ftp.microsoft.com/developr/drg/CIFS/">. No specification
+releases were made between 1992 and 1996, and during that period
+Microsoft became the SMB implementor with the largest market share.
+Microsoft developed the specification further for its products but for
+various reasons connected with developer's workload rather than market
+strategy did not make the changes public. This culminated with the
+"Windows NT 0.12" version released with NT 3.5 in 1995 which had significant
+improvements and bugs. Because Microsoft client systems are so popular,
+it is fair to say that what Microsoft with Windows affects all suppliers
+of SMB server products.
+
+From 1994 Andrew Tridgell began doing some serious work on his
+Smbserver (now Samba) product and with some helpers started to
+implement more and more of these protocols. Samba began to take
+a significant share of the SMB server market.
+
+<sect1> What is the Common Internet Filesystem (CIFS)?<p>
+The initial pressure for Microsoft to document their current SMB
+implementation came from the Samba team, who kept coming across things
+on the wire that Microsoft either didn't know about or hadn't documented
+anywhere (even in the sourcecode to Windows NT.) Then Sun Microsystems
+came out with their WebNFS initiative, designed to replace FTP for file
+transfers on the Internet. There are many drawbacks to WebNFS (including
+its scope - it aims to replace HTTP as well!) but the concept was
+attractive. FTP is not very clever, and why should it be harder to get
+files from across the world than across the room?
+
+Some hasty revisions were made and an Internet Draft for the Common
+Internet Filesystem (CIFS) was released. Note that CIFS is not an
+Internet standard and is a very long way from becoming one, BUT the
+protocol specification is in the public domain and ongoing discussions
+concerning the spec take place on a public mailing list according to the
+rules of the Internet Engineering Task Force. For more information and
+pointers see <url url="http://samba.org/cifs/">
+
+The following is taken from <url url="http://www.microsoft.com/intdev/cifs/">
+
+<verb>
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft® Windows® and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX®. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work."
+</verb>
+
+If you consider CIFS as a backwardsly-compatible refinement of SMB that
+will work reasonably efficiently over the Internet you won't be too far
+wrong.
+
+The net effect is that Microsoft is now documenting large parts of their
+Windows NT fileserver protocols. The security concepts embodied in
+Windows NT are part of the specification, which is why Samba
+documentation often talks in terms of Windows NT. However there is no
+reason why a site shouldn't conduct all its file and printer sharing
+with CIFS and yet have no Microsoft products at all.
+
+<sect1> What is Browsing? <p>
+The term "Browsing" causes a lot of confusion. It is the part of the
+SMB/CIFS protocol which allows for resource discovery. For example, in
+the Windows NT Explorer it is possible to see a "Network Neighbourhood"
+of computers in the same SMB workgroup. Clicking on the name of one of
+these machines brings up a list of file and printer resources for
+connecting to. In this way you can cruise the network, seeing what
+things are available. How this scales to the Internet is a subject for
+debate. Look at the CIFS list archives to see what the experts think.
+
+<sect>Designing A SMB and CIFS Network<p>
+
+The big issues for installing any network of LAN or WAN file and print
+servers are
+
+<itemize>
+
+<item>How and where usernames, passwords and other security information
+is stored
+
+<item>What method can be used for locating the resources that users have
+permission to use
+
+<item>What protocols the clients can converse with
+
+</itemize>
+
+If you buy Netware, Windows NT or just about any other LAN fileserver
+product you are expected to lock yourself into the product's preferred
+answers to these questions. This tendancy is restrictive and often very
+expensive for a site where there is only one kind of client or server,
+and for sites with a mixture of operating systems it often makes it
+impossible to share resources between some sets of users.
+
+The Samba philosophy is to make things as easy as possible for
+administators, which means allowing as many combinations of clients,
+servers, operating systems and protocols as possible.
+
+<sect1>Workgroups, Domains, Authentication and Browsing<p>
+
+From the point of view of networking implementation, Domains and
+Workgroups are <em>exactly</em> the same, except for the client logon
+sequence. Some kind of distributed authentication database is associated
+with a domain (there are quite a few choices) and this adds so much
+flexibility that many people think of a domain as a completely different
+entity to a workgroup. From Samba's point of view a client connecting to
+a service presents an authentication token, and it if it is valid they
+have access. Samba does not care what mechanism was used to generate
+that token in the first place.
+
+The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+However the network browsing functionality of domains and workgroups is
+identical and is explained in <url url="../BROWSING.txt">.
+
+There are some implementation differences: Windows 95 can be a member of
+both a workgroup and a domain, but Windows NT cannot. Windows 95 also
+has the concept of an "alternative workgroup". Samba can only be a
+member of a single workgroup or domain, although this is due to change
+with a future version when nmbd will be split into two daemons, one for
+WINS and the other for browsing (<url url="../NetBIOS.txt"> explains
+what WINS is.)
+
+<sect2> Defining the Terms<p><label id="BrowseAndDomainDefs">
+
+<descrip>
+
+<tag/Workgroup/ means a collection of machines that maintain a common
+browsing database containing information about their shared resources.
+They do not necessarily have any security information in common (if they
+do, it gets called a Domain.) The browsing database is dynamic, modified
+as servers come and go on the network and as resources are added or
+deleted. The term "browsing" refers to a user accessing the database via
+whatever interface the client provides, eg the OS/2 Workplace Shell or
+Windows 95 Explorer. SMB servers agree between themselves as to which
+ones will maintain the browsing database. Workgroups can be anywhere on
+a connected TCP/IP network, including on different subnets or even on
+the Interet. This is a very tricky part of SMB to implement.
+
+<tag/Master Browsers/ are machines which holds the master browsing
+database for a workgroup or domain. There are two kinds of Master Browser:
+
+<itemize>
+
+<item> Domain Master Browser, which holds the master browsing
+information for an entire domain, which may well cross multiple TCP/IP
+subnets.
+
+<item> Local Master Browser, which holds the master browsing database
+for a particular subnet and communicates with the Domain Master Browser
+to get information on other subnets.
+
+</itemize>
+
+Subnets are differentiated because browsing is based on broadcasts, and
+broadcasts do not pass through routers. Subnets are not routed: while it
+is possible to have more than one subnet on a single network segment
+this is regarded as very bad practice.
+
+Master Browsers (both Domain and Local) are elected dynamically
+according to an algorithm which is supposed to take into account the
+machine's ability to sustain the browsing load. Samba can be configured
+to always act as a master browser, ie it always wins elections under all
+circumstances, even against systems such as a Windows NT Primary Domain
+Controller which themselves expect to win.
+
+There are also Backup Browsers which are promoted to Master Browsers in
+the event of a Master Browser disappearing from the network.
+
+Alternative terms include confusing variations such as "Browse Master",
+and "Master Browser" which we are trying to eliminate from the Samba
+documentation.
+
+<tag/Domain Controller/ is a term which comes from the Microsoft and IBM
+etc implementation of the LAN Manager protocols. It is tied to
+authentication. There are other ways of doing domain authentication, but
+the Windows NT method has a large market share. The general issues are
+discussed in <url url="../DOMAIN.txt"> and a Windows NT-specific
+discussion is in <url url="../DOMAIN_CONTROL.txt">.
+
+</descrip>
+
+<sect2>Sharelevel (Workgroup) Security Services<p><label id="ShareModeSecurity">
+
+With the Samba setting "security = SHARE", all shared resources
+information about what password is associated with them but only hints
+as to what usernames might be valid (the hint can be 'all users', in
+which case any username will work. This is usually a bad idea, but
+reflects both the initial implementations of SMB in the mid-80s and
+its reincarnation with Windows for Workgroups in 1992. The idea behind
+workgroup security was that small independant groups of people could
+share information on an ad-hoc basis without there being an
+authentication infrastructure present or requiring them to do more than
+fill in a dialogue box.
+
+<sect2>Authentication Domain Mode Services<p><label id="DomainModeSecurity">
+
+With the Samba settings "security = USER" or "security = SERVER"
+accesses to all resources are checked for username/password pair matches
+in a more rigorous manner. To the client, this has the effect of
+emulating a Microsoft Domain. The client is not concerned whether or not
+Samba looks up a Windows NT SAM or does it in some other way.
+
+<sect1>Authentication Schemes<p>
+
+In the simple case authentication information is stored on a single
+server and the user types a password on connecting for the first time.
+However client operating systems often require a password before they
+can be used at all, and in addition users usually want access to more
+than one server. Asking users to remember many different passwords in
+different contexts just does not work. Some kind of distributed
+authentication database is needed. It must cope with password changes
+and provide for assigning groups of users the same level of access
+permissions. This is why Samba installations often choose to implement a
+Domain model straight away.
+
+Authentication decisions are some of the biggest in designing a network.
+Are you going to use a scheme native to the client operating system,
+native to the server operating system, or newly installed on both? A
+list of options relevant to Samba (ie that make sense in the context of
+the SMB protocol) follows. Any experiences with other setups would be
+appreciated. [refer to server FAQ for "passwd chat" passwd program
+password server etc etc...]
+
+<sect2>NIS<p>
+
+For Windows 95, Windows for Workgroups and most other clients Samba can
+be a domain controller and share the password database via NIS
+transparently. Windows NT is different.
+<url url="http://www.dcs.qmw.ac.uk/~williams" name="Free NIS NT client">
+
+<sect2>Kerberos<p>
+
+Kerberos for US users only:
+<url url="http://www.cygnus.com/product/unifying-security.html"
+name="Kerberos overview">
+<url url="http://www.cygnus.com/product/kerbnet-download.html"
+name="Download Kerberos">
+
+<sect2>FTP<p>
+
+Other NT w/s logon hack via NT
+
+<sect2>Default Server Method<p>
+
+<sect2>Client-side Database Only<p>
+
+<sect1>Post-Authentication: Netlogon, Logon Scripts, Profiles<p>
+
+See <url url="../DOMAIN.txt">
+
+<sect>Cross-Protocol File Sharing<p>
+
+Samba is an important tool for...
+
+It is possible to...
+
+File protocol gateways...
+
+"Setting up a Linux File Server" http://vetrec.mit.edu/people/narf/linux.html
+
+Two free implementations of Appletalk for Unix are Netatalk, <url
+url="http://www.umich.edu/~rsug/netatalk/">, and CAP, <url
+url="http://www.cs.mu.oz.au/appletalk/atalk.html">. What Samba offers MS
+Windows users, these packages offer to Macs. For more info on these
+packages, Samba, and Linux (and other UNIX-based systems) see <url
+url="http://www.eats.com/linux_mac_win.html"> 3.5) Sniffing your nework
+
+
+<sect>Miscellaneous<p><label id="miscellaneous">
+<sect1>Is Samba Year 2000 compliant?<p><label id="Year2000Compliant">
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.
+
+</article>
diff --git a/docs/faq/Samba-meta-FAQ.txt b/docs/faq/Samba-meta-FAQ.txt
new file mode 100644
index 00000000000..01fc8d6ccf1
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.txt
@@ -0,0 +1,924 @@
+ Samba meta FAQ
+ Dan Shearer & Paul Blackman, ictinus@samba.org
+ v 0.3, 7 Oct '97
+
+ This is the meta-Frequently Asked Questions (FAQ) document for Samba,
+ the free and very popular SMB and CIFS server product. It contains
+ overview information for the Samba suite of programs, a quick-start
+ guide, and pointers to all other Samba documentation. Other FAQs exist
+ for specific client and server issues, and HOWTO documents for more
+ extended topics to do with Samba software. Current to version Samba
+ 1.9.17. Please send any corrections to the author.
+ ______________________________________________________________________
+
+ Table of Contents:
+
+ 1. Quick Reference Guides to Samba Documentation
+
+ 1.1. Samba for the Impatient
+
+ 1.2. All Samba Documentation
+
+ 2. General Information
+
+ 2.1. What is Samba?
+
+ 2.2. What is the current version of Samba?
+
+ 2.3. Where can I get it?
+
+ 2.4. What do the version numbers mean?
+
+ 2.5. Where can I go for further information?
+
+ 2.6. How do I subscribe to the Samba Mailing Lists?
+
+ 2.7. Something's gone wrong - what should I do?
+
+ 2.8. How do I submit patches or bug reports?
+
+ 2.9. What if I have an URGENT message for the developers?
+
+ 2.10. What if I need paid-for support?
+
+ 2.11. Pizza supply details
+
+ 3. About the CIFS and SMB Protocols
+
+ 3.1. What is the Server Message Block (SMB) Protocol?
+
+ 3.2. What is the Common Internet Filesystem (CIFS)?
+
+ 3.3. What is Browsing?
+
+ 4. Designing A SMB and CIFS Network
+
+ 4.1. Workgroups, Domains, Authentication and Browsing
+
+ 4.1.1. Defining the Terms
+
+ 4.1.2. Sharelevel (Workgroup) Security Services
+
+ 4.1.3. Authentication Domain Mode Services
+
+ 4.2. Authentication Schemes
+
+
+ 4.2.1. NIS
+
+ 4.2.2. Kerberos
+
+ 4.2.3. FTP
+
+ 4.2.4. Default Server Method
+
+ 4.2.5. Client-side Database Only
+
+ 4.3. Post-Authentication: Netlogon, Logon Scripts, Profiles
+
+ 5. Cross-Protocol File Sharing
+
+ 6. Miscellaneous
+
+ 6.1. Is Samba Year 2000 compliant?
+ ______________________________________________________________________
+
+ 11.. QQuuiicckk RReeffeerreennccee GGuuiiddeess ttoo SSaammbbaa DDooccuummeennttaattiioonn
+
+
+ We are endeavouring to provide links here to every major class of
+ information about Samba or things related to Samba. We cannot list
+ every document, but we are aiming for all documents to be at most two
+ referrals from those listed here. This needs constant maintaining, so
+ please send the author your feedback.
+
+
+ 11..11.. SSaammbbaa ffoorr tthhee IImmppaattiieenntt
+
+
+ You know you should read the documentation but can't wait to start?
+ What you need to do then is follow the instructions in the following
+ documents in the order given. This should be enough to get a fairly
+ simple site going quickly. If you have any problems, refer back to
+ this meta-FAQ and follow the links to find more reading material.
+
+
+
+ GGeettttiinngg SSaammbbaa::
+ The fastest way to get Samba going is and install it is to have
+ an operating system for which the Samba team has put together an
+ installation package. To see if your OS is included have a look
+ at the directory /pub/samba/Binary_Packages/"OS_Vendor" on your
+ nearest mirror site <../MIRRORS>. If it is included follow the
+ installation instructions in the README file there and then do
+ some ``basic testing''. If you are not so fortunate, follow the
+ normal ``download instructions'' and then continue with
+ ``building and installing Samba''.
+
+
+ BBuuiillddiinngg aanndd IInnssttaalllliinngg SSaammbbaa::
+ At the moment there are two kinds of Samba server installs
+ besides the prepackaged binaries mentioned in the previous step.
+ You need to decide if you have a Unix or close relative
+ <../UNIX_INSTALL.txt> or other supported operating system
+ <Samba-Server-FAQ.html#PortInfo>.
+
+
+ BBaassiicc TTeessttiinngg::
+ Try to connect using the supplied smbclient command-line
+ program. You need to know the IP hostname of your server. A
+ service name must be defined in smb.conf, as given in the
+ examples (under many operating systems if there is a homes
+ service you can just use a valid username.) Then type smbclient
+ \hostnamevicename Under most Unixes you will need to put the
+ parameters within quotation marks. If this works, try connecting
+ from one of the SMB clients you were planning to use with Samba.
+
+
+ DDeebbuugg sseeqquueennccee::
+ If you think you have completed the previous step and things
+ aren't working properly work through the diagnosis recipe.
+ <../DIAGNOSIS.txt>
+
+
+ EExxppoorrttiinngg ffiilleess ttoo SSMMBB cclliieennttss::
+ You should read the manual pages for smb.conf, but here is a
+ quick answer guide. <Samba-Server-FAQ.html#Exporting>
+
+
+ CCoonnttrroolllliinngg uusseerr aacccceessss::
+ the quickest and dirtiest way of sharing resources is to use
+ ``share level security.'' If you want to spend more time and
+ have a proper username and password database you must read the
+ paragraph on ``domain mode security.'' If you want encryption
+ (eg you are using Windows NT clients) follow the SMB encryption
+ instructions. <Samba-Server-FAQ.html#SMBEncryptionSteps>
+
+
+ BBrroowwssiinngg::
+ if you are happy to type in "\samba-serverrename" at the client
+ end then do not read any further. Otherwise you need to
+ understand the ``browsing terminology'' and read <Samba-Server-
+ FAQ.html#NameBrowsing>.
+
+
+ PPrriinnttiinngg::
+ See the printing quick answer guide. <Samba-Server-
+ FAQ.html#Printing>
+
+
+ If you have got everything working to this point, you can expect Samba
+ to be stable and secure: these are its greatest strengths. However
+ Samba has a great deal to offer and to go further you must do some
+ more reading. Speed and security optimisations, printer accounting,
+ network logons, roving profiles, browsing across multiple subnets and
+ so on are all covered either in this document or in those it refers
+ to.
+
+
+ 11..22.. AAllll SSaammbbaa DDooccuummeennttaattiioonn
+
+
+
+ +o Meta-FAQ. This is the mother of all documents, and is the one you
+ are reading now. The latest version is always at
+ <http://samba.org/[.....]> but there is probably a much
+ nearer mirror site <../MIRRORS> which you should use instead.
+
+ +o <Samba-Server-FAQ.html> is the best starting point for information
+ about server-side issues. Includes configuration tips and pointers
+ for Samba on particular operating systems (with 40 to choose
+ from...)
+
+ +o <Samba-Client-FAQ.html> is the best starting point for information
+ about client-side issues, includes a list of all clients that are
+ known to work with Samba.
+
+ +o manual pages <samba-man-index.html> contains descriptions of and
+ links to all the Samba manual pages, in Unix man and postscript
+ format.
+
+ +o <samba-txt-index.html> has descriptions of and links to a large
+ number of text files have been contributed to samba covering many
+ topics. These are gradually being absorbed into the FAQs and HOWTOs
+ but in the meantime you might find helpful answers here.
+
+ +o
+
+
+ 22.. GGeenneerraall IInnffoorrmmaattiioonn
+
+
+ All about Samba - what it is, how to get it, related sources of
+ information, how to understand the numbering scheme, pizza details.
+
+
+ 22..11.. WWhhaatt iiss SSaammbbaa??
+
+
+ Samba is a suite of programs which work together to allow clients to
+ access to a server's filespace and printers via the SMB (Server
+ Message Block) and CIFS (Common Internet Filesystem) protocols.
+ Initially written for Unix, Samba now also runs on Netware, OS/2, VMS,
+ StratOS and Amigas. Ports to BeOS and other operating systems are
+ underway. Samba gives the capability for these operating systems to
+ behave much like a LAN Server, Windows NT Server or Pathworks machine,
+ only with added functionality and flexibility designed to make life
+ easier for administrators.
+
+ This means that using Samba you can share a server's disks and
+ printers to many sorts of network clients, including Lan Manager,
+ Windows for Workgroups, Windows NT, Linux, OS/2, and AIX. There is
+ also a generic client program supplied as part of the Samba suite
+ which gives a user on the server an ftp-like interface to access
+ filespace and printers on any other SMB/CIFS servers.
+
+ SMB has been implemented over many protocols, including XNS, NBT, IPX,
+ NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to
+ change although there have been some requests for NetBEUI support.
+
+ Many users report that compared to other SMB implementations Samba is
+ more stable, faster, and compatible with more clients. Administrators
+ of some large installations say that Samba is the only SMB server
+ available which will scale to many tens of thousands of users without
+ crashing. The easy way to test these claims is to download it and try
+ it for yourself!
+
+ The suite is supplied with full source code under the GNU Public
+ License <../COPYING>. The GPL means that you can use Samba for
+ whatever purpose you wish (including changing the source or selling it
+ for money) but under all circumstances the source code must be made
+ freely available. A copy of the GPL must always be included in any
+ copy of the package.
+
+ The primary creator of the Samba suite is Andrew Tridgell. Later
+ versions incorporate much effort by many net.helpers. The man pages
+ and this FAQ were originally written by Karl Auer.
+
+
+ 22..22.. WWhhaatt iiss tthhee ccuurrrreenntt vveerrssiioonn ooff SSaammbbaa??
+
+
+ At time of writing, the current version was 1.9.17. If you want to be
+ sure check the bottom of the change-log file.
+ <ftp://samba.org/pub/samba/alpha/change-log>
+ For more information see ``What do the version numbers mean?''
+
+
+ 22..33.. WWhheerree ccaann II ggeett iitt??
+
+
+ The Samba suite is available via anonymous ftp from samba.org
+ and many mirror <../MIRRORS> sites. You will get much faster
+ performance if you use a mirror site. The latest and greatest versions
+ of the suite are in the directory:
+
+ /pub/samba/
+
+ Development (read "alpha") versions, which are NOT necessarily stable
+ and which do NOT necessarily have accurate documentation, are
+ available in the directory:
+
+ /pub/samba/alpha
+
+ Note that binaries are NOT included in any of the above. Samba is
+ distributed ONLY in source form, though binaries may be available from
+ other sites. Most Linux distributions, for example, do contain Samba
+ binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ ports typically have binaries made available.
+
+ A special case is vendor-provided binary packages. Samba binaries and
+ default configuration files are put into packages for a specific
+ operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+ already included, and others such as OS/2 may follow. All packages are
+ in the directory:
+
+ /pub/samba/Binary_Packages/"OS_Vendor"
+
+
+ 22..44.. WWhhaatt ddoo tthhee vveerrssiioonn nnuummbbeerrss mmeeaann??
+
+
+ It is not recommended that you run a version of Samba with the word
+ "alpha" in its name unless you know what you are doing and are willing
+ to do some debugging. Many, many people just get the latest
+ recommended stable release version and are happy. If you are brave, by
+ all means take the plunge and help with the testing and development -
+ but don't install it on your departmental server. Samba is typically
+ very stable and safe, and this is mostly due to the policy of many
+ public releases.
+
+ How the scheme works:
+
+
+ 1. When major changes are made the version number is increased. For
+ example, the transition from 1.9.16 to 1.9.17. However, this
+ version number will not appear immediately and people should
+ continue to use 1.9.15 for production systems (see next point.)
+
+ 2. Just after major changes are made the software is considered
+ unstable, and a series of alpha releases are distributed, for
+ example 1.9.16alpha1. These are for testing by those who know what
+ they are doing. The "alpha" in the filename will hopefully scare
+ off those who are just looking for the latest version to install.
+
+ 3. When Andrew thinks that the alphas have stabilised to the point
+ where he would recommend new users install it, he renames it to the
+ same version number without the alpha, for example 1.9.17.
+
+ 4. Inevitably bugs are found in the "stable" releases and minor patch
+ levels are released which give us the pXX series, for example
+ 1.9.17p2.
+
+ So the progression goes:
+
+
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+
+
+
+ The above system means that whenever someone looks at the samba ftp
+ site they will be able to grab the highest numbered release without an
+ alpha in the name and be sure of getting the current recommended
+ version.
+
+
+ 22..55.. WWhheerree ccaann II ggoo ffoorr ffuurrtthheerr iinnffoorrmmaattiioonn??
+
+
+ There are a number of places to look for more information on Samba,
+ including:
+
+
+ +o Two mailing lists devoted to discussion of Samba-related matters.
+ See below for subscription information.
+
+ +o The newsgroup comp.protocols.smb, which has a great deal of
+ discussion about Samba.
+
+ +o The WWW site 'SAMBA Web Pages' at <http://samba.org/samba/>
+ includes:
+
+
+ +o Links to man pages and documentation, including this FAQ
+
+ +o A comprehensive survey of Samba users
+
+ +o A searchable hypertext archive of the Samba mailing list
+
+ +o Links to Samba source code, binaries, and mirrors of both
+
+ +o This FAQ and the rest in its family
+
+
+
+ 22..66.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.org. Make sure the subject line is
+ blank, and include the following two lines in the body of the message:
+
+
+
+ subscribe samba Firstname Lastname
+ subscribe samba-announce Firstname Lastname
+
+
+
+
+ Obviously you should substitute YOUR first name for "Firstname" and
+ YOUR last name for "Lastname"! Try not to send any signature, it
+ sometimes confuses the list processor.
+
+ The samba list is a digest list - every eight hours or so it sends a
+ single message containing all the messages that have been received by
+ the list since the last time and sends a copy of this message to all
+ subscribers. There are thousands of people on this list.
+
+ If you stop being interested in Samba, please send another email to
+ listproc@samba.org. Make sure the subject line is blank, and
+ include the following two lines in the body of the message:
+
+
+
+ unsubscribe samba
+ unsubscribe samba-announce
+
+
+
+
+ The FFrroomm:: line in your message _M_U_S_T be the same address you used when
+ you subscribed.
+
+
+ 22..77.. SSoommeetthhiinngg''ss ggoonnee wwrroonngg -- wwhhaatt sshhoouulldd II ddoo??
+
+
+ ## ****** IIMMPPOORRTTAANNTT!! ****** ##
+
+
+ DO NOT post messages on mailing lists or in newsgroups until you have
+ carried out the first three steps given here!
+
+
+ 1. See if there are any likely looking entries in this FAQ! If you
+ have just installed Samba, have you run through the checklist in
+ DIAGNOSIS.txt <ftp://samba.org/pub/samba/DIAGNOSIS.txt>? It
+ can save you a lot of time and effort. DIAGNOSIS.txt can also be
+ found in the docs directory of the Samba distribution.
+
+ 2. Read the man pages for smbd, nmbd and smb.conf, looking for topics
+ that relate to what you are trying to do.
+
+ 3. If there is no obvious solution to hand, try to get a look at the
+ log files for smbd and/or nmbd for the period during which you were
+ having problems. You may need to reconfigure the servers to provide
+ more extensive debugging information - usually level 2 or level 3
+ provide ample debugging info. Inspect these logs closely, looking
+ particularly for the string "Error:".
+
+ 4. If you need urgent help and are willing to pay for it see ``Paid
+ Support''.
+
+ If you still haven't got anywhere, ask the mailing list or newsgroup.
+ In general nobody minds answering questions provided you have followed
+ the preceding steps. It might be a good idea to scan the archives of
+ the mailing list, which are available through the Samba web site
+ described in the previous section. When you post be sure to include a
+ good description of your environment and your problem.
+
+ If you successfully solve a problem, please mail the FAQ maintainer a
+ succinct description of the symptom, the problem and the solution, so
+ that an explanation can be incorporated into the next version.
+
+
+
+
+ 22..88.. HHooww ddoo II ssuubbmmiitt ppaattcchheess oorr bbuugg rreeppoorrttss??
+
+
+ If you make changes to the source code, _p_l_e_a_s_e submit these patches so
+ that everyone else gets the benefit of your work. This is one of the
+ most important aspects to the maintainence of Samba. Send all patches
+ to samba@samba.org. Do not send patches to Andrew Tridgell
+ or any other individual, they may be lost if you do.
+
+ Patch format ------------
+
+ If you are sending a patch to fix a problem then please don't just use
+ standard diff format. As an example, samba@samba.org received this patch
+ from someone:
+
+ 382a #endif 381a #if !defined(NEWS61)
+
+ How are we supposed to work out what this does and where it goes?
+ These sort of patches only work if we both have identical files in the
+ first place. The Samba sources are constantly changing at the hands of
+ multiple developers, so it doesn't work.
+
+ Please use either context diffs or (even better) unified diffs. You
+ get these using "diff -c4" or "diff -u". If you don't have a diff that
+ can generate these then please send manualy commented patches to I
+ know what is being changed and where. Most patches are applied by hand
+ so the info must be clear.
+
+ This is a basic guideline that will assist us with assessing your
+ problem more efficiently :
+
+ Machine Arch: Machine OS: OS Version: Kernel:
+
+ Compiler: Libc Version:
+
+ Samba Version:
+
+ Network Layout (description):
+
+ What else is on machine (services, etc):
+
+ Some extras :
+
+
+ +o what you did and what happened
+
+ +o relevant parts of a debugging output file with debuglevel higher.
+ If you can't find the relevant parts, please ask before mailing
+ huge files.
+
+ +o anything else you think is useful to trace down the bug
+
+
+ 22..99.. WWhhaatt iiff II hhaavvee aann UURRGGEENNTT mmeessssaaggee ffoorr tthhee ddeevveellooppeerrss??
+
+
+ If you have spotted something very serious and believe that it is
+ important to contact the developers quickly send a message to samba-
+ urgent@samba.org. This will be processed more quickly than mail
+ to samba@samba.org. Please think carefully before using this address. An
+ example of its use might be to report a security hole.
+
+ Examples of things _n_o_t to send to samba-urgent include problems
+ getting Samba to work at all and bugs that cannot potentially cause
+ damage.
+
+ 22..1100.. WWhhaatt iiff II nneeeedd ppaaiidd--ffoorr ssuuppppoorrtt??
+
+
+ Samba has a large network of consultants who provide Samba support on
+ a commercial basis. The list is included in the package in
+ <../Support.txt>, and the latest version will always be on the main
+ samba ftp site. Any company in the world can request that the samba
+ team include their details in Support.txt so we can give no guarantee
+ of their services.
+
+
+ 22..1111.. PPiizzzzaa ssuuppppllyy ddeettaaiillss
+
+
+ Those who have registered in the Samba survey as "Pizza Factory" will
+ already know this, but the rest may need some help. Andrew doesn't ask
+ for payment, but he does appreciate it when people give him pizza.
+ This calls for a little organisation when the pizza donor is twenty
+ thousand kilometres away, but it has been done.
+
+
+ 1. Ring up your local branch of an international pizza chain and see
+ if they honour their vouchers internationally. Pizza Hut do, which
+ is how the entire Canberra Linux Users Group got to eat pizza one
+ night, courtesy of someone in the US.
+
+ 2. Ring up a local pizza shop in Canberra and quote a credit card
+ number for a certain amount, and tell them that Andrew will be
+ collecting it (don't forget to tell him.) One kind soul from
+ Germany did this.
+
+ 3. Purchase a pizza voucher from your local pizza shop that has no
+ international affiliations and send it to Andrew. It is completely
+ useless but he can hang it on the wall next to the one he already
+ has from Germany :-)
+
+ 4. Air freight him a pizza with your favourite regional flavours. It
+ will probably get stuck in customs or torn apart by hungry sniffer
+ dogs but it will have been a noble gesture.
+
+
+ 33.. AAbboouutt tthhee CCIIFFSS aanndd SSMMBB PPrroottooccoollss
+
+
+
+ 33..11.. WWhhaatt iiss tthhee SSeerrvveerr MMeessssaaggee BBlloocckk ((SSMMBB)) PPrroottooccooll??
+
+ SMB is a filesharing protocol that has had several maintainers and
+ contributors over the years including Xerox, 3Com and most recently
+ Microsoft. Names for this protocol include LAN Manager and Microsoft
+ Networking. Parts of the specification has been made public at several
+ versions including in an X/Open document, as listed at
+ <ftp://ftp.microsoft.com/developr/drg/CIFS/>. No specification
+ releases were made between 1992 and 1996, and during that period
+ Microsoft became the SMB implementor with the largest market share.
+ Microsoft developed the specification further for its products but for
+ various reasons connected with developer's workload rather than market
+ strategy did not make the changes public. This culminated with the
+ "Windows NT 0.12" version released with NT 3.5 in 1995 which had
+ significant improvements and bugs. Because Microsoft client systems
+ are so popular, it is fair to say that what Microsoft with Windows
+ affects all suppliers of SMB server products.
+
+ From 1994 Andrew Tridgell began doing some serious work on his
+ Smbserver (now Samba) product and with some helpers started to
+ implement more and more of these protocols. Samba began to take a
+ significant share of the SMB server market.
+
+
+ 33..22.. WWhhaatt iiss tthhee CCoommmmoonn IInntteerrnneett FFiilleessyysstteemm ((CCIIFFSS))??
+
+ The initial pressure for Microsoft to document their current SMB
+ implementation came from the Samba team, who kept coming across things
+ on the wire that Microsoft either didn't know about or hadn't
+ documented anywhere (even in the sourcecode to Windows NT.) Then Sun
+ Microsystems came out with their WebNFS initiative, designed to
+ replace FTP for file transfers on the Internet. There are many
+ drawbacks to WebNFS (including its scope - it aims to replace HTTP as
+ well!) but the concept was attractive. FTP is not very clever, and why
+ should it be harder to get files from across the world than across the
+ room?
+
+ Some hasty revisions were made and an Internet Draft for the Common
+ Internet Filesystem (CIFS) was released. Note that CIFS is not an
+ Internet standard and is a very long way from becoming one, BUT the
+ protocol specification is in the public domain and ongoing discussions
+ concerning the spec take place on a public mailing list according to
+ the rules of the Internet Engineering Task Force. For more information
+ and pointers see <http://samba.org/cifs/>
+
+ The following is taken from <http://www.microsoft.com/intdev/cifs/>
+
+
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft Windows and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work."
+
+
+
+ If you consider CIFS as a backwardsly-compatible refinement of SMB
+ that will work reasonably efficiently over the Internet you won't be
+ too far wrong.
+
+ The net effect is that Microsoft is now documenting large parts of
+ their Windows NT fileserver protocols. The security concepts embodied
+ in Windows NT are part of the specification, which is why Samba
+ documentation often talks in terms of Windows NT. However there is no
+ reason why a site shouldn't conduct all its file and printer sharing
+ with CIFS and yet have no Microsoft products at all.
+
+
+ 33..33.. WWhhaatt iiss BBrroowwssiinngg??
+
+ The term "Browsing" causes a lot of confusion. It is the part of the
+ SMB/CIFS protocol which allows for resource discovery. For example, in
+ the Windows NT Explorer it is possible to see a "Network
+ Neighbourhood" of computers in the same SMB workgroup. Clicking on the
+ name of one of these machines brings up a list of file and printer
+ resources for connecting to. In this way you can cruise the network,
+ seeing what things are available. How this scales to the Internet is a
+ subject for debate. Look at the CIFS list archives to see what the
+ experts think.
+
+
+
+
+ 44.. DDeessiiggnniinngg AA SSMMBB aanndd CCIIFFSS NNeettwwoorrkk
+
+
+ The big issues for installing any network of LAN or WAN file and print
+ servers are
+
+
+ +o How and where usernames, passwords and other security information
+ is stored
+
+ +o What method can be used for locating the resources that users have
+ permission to use
+
+ +o What protocols the clients can converse with
+
+
+ If you buy Netware, Windows NT or just about any other LAN fileserver
+ product you are expected to lock yourself into the product's preferred
+ answers to these questions. This tendancy is restrictive and often
+ very expensive for a site where there is only one kind of client or
+ server, and for sites with a mixture of operating systems it often
+ makes it impossible to share resources between some sets of users.
+
+ The Samba philosophy is to make things as easy as possible for
+ administators, which means allowing as many combinations of clients,
+ servers, operating systems and protocols as possible.
+
+
+ 44..11.. WWoorrkkggrroouuppss,, DDoommaaiinnss,, AAuutthheennttiiccaattiioonn aanndd BBrroowwssiinngg
+
+
+ From the point of view of networking implementation, Domains and
+ Workgroups are _e_x_a_c_t_l_y the same, except for the client logon sequence.
+ Some kind of distributed authentication database is associated with a
+ domain (there are quite a few choices) and this adds so much
+ flexibility that many people think of a domain as a completely
+ different entity to a workgroup. From Samba's point of view a client
+ connecting to a service presents an authentication token, and it if it
+ is valid they have access. Samba does not care what mechanism was used
+ to generate that token in the first place.
+
+ The SMB client logging on to a domain has an expectation that every
+ other server in the domain should accept the same authentication
+ information. However the network browsing functionality of domains
+ and workgroups is identical and is explained in <../BROWSING.txt>.
+
+ There are some implementation differences: Windows 95 can be a member
+ of both a workgroup and a domain, but Windows NT cannot. Windows 95
+ also has the concept of an "alternative workgroup". Samba can only be
+ a member of a single workgroup or domain, although this is due to
+ change with a future version when nmbd will be split into two daemons,
+ one for WINS and the other for browsing ( <../NetBIOS.txt> explains
+ what WINS is.)
+
+
+ 44..11..11.. DDeeffiinniinngg tthhee TTeerrmmss
+
+
+
+
+ WWoorrkkggrroouupp
+ means a collection of machines that maintain a common browsing
+ database containing information about their shared resources.
+ They do not necessarily have any security information in common
+ (if they do, it gets called a Domain.) The browsing database is
+ dynamic, modified as servers come and go on the network and as
+ resources are added or deleted. The term "browsing" refers to a
+ user accessing the database via whatever interface the client
+ provides, eg the OS/2 Workplace Shell or Windows 95 Explorer.
+ SMB servers agree between themselves as to which ones will
+ maintain the browsing database. Workgroups can be anywhere on a
+ connected TCP/IP network, including on different subnets or even
+ on the Interet. This is a very tricky part of SMB to implement.
+
+
+ MMaasstteerr BBrroowwsseerrss
+ are machines which holds the master browsing database for a
+ workgroup or domain. There are two kinds of Master Browser:
+
+
+ +o Domain Master Browser, which holds the master browsing
+ information for an entire domain, which may well cross multiple
+ TCP/IP subnets.
+
+ +o Local Master Browser, which holds the master browsing database
+ for a particular subnet and communicates with the Domain Master
+ Browser to get information on other subnets.
+
+ Subnets are differentiated because browsing is based on
+ broadcasts, and broadcasts do not pass through routers. Subnets
+ are not routed: while it is possible to have more than one
+ subnet on a single network segment this is regarded as very bad
+ practice.
+
+ Master Browsers (both Domain and Local) are elected dynamically
+ according to an algorithm which is supposed to take into account
+ the machine's ability to sustain the browsing load. Samba can be
+ configured to always act as a master browser, ie it always wins
+ elections under all circumstances, even against systems such as
+ a Windows NT Primary Domain Controller which themselves expect
+ to win.
+
+ There are also Backup Browsers which are promoted to Master
+ Browsers in the event of a Master Browser disappearing from the
+ network.
+
+ Alternative terms include confusing variations such as "Browse
+ Master", and "Master Browser" which we are trying to eliminate
+ from the Samba documentation.
+
+
+ DDoommaaiinn CCoonnttrroolllleerr
+ is a term which comes from the Microsoft and IBM etc
+ implementation of the LAN Manager protocols. It is tied to
+ authentication. There are other ways of doing domain
+ authentication, but the Windows NT method has a large market
+ share. The general issues are discussed in <../DOMAIN.txt> and
+ a Windows NT-specific discussion is in <../DOMAIN_CONTROL.txt>.
+
+
+
+ 44..11..22.. SShhaarreelleevveell ((WWoorrkkggrroouupp)) SSeeccuurriittyy SSeerrvviicceess
+
+
+ With the Samba setting "security = SHARE", all shared resources
+ information about what password is associated with them but only hints
+ as to what usernames might be valid (the hint can be 'all users', in
+ which case any username will work. This is usually a bad idea, but
+ reflects both the initial implementations of SMB in the mid-80s and
+ its reincarnation with Windows for Workgroups in 1992. The idea behind
+ workgroup security was that small independant groups of people could
+ share information on an ad-hoc basis without there being an
+ authentication infrastructure present or requiring them to do more
+ than fill in a dialogue box.
+
+
+ 44..11..33.. AAuutthheennttiiccaattiioonn DDoommaaiinn MMooddee SSeerrvviicceess
+
+
+ With the Samba settings "security = USER" or "security = SERVER"
+ accesses to all resources are checked for username/password pair
+ matches in a more rigorous manner. To the client, this has the effect
+ of emulating a Microsoft Domain. The client is not concerned whether
+ or not Samba looks up a Windows NT SAM or does it in some other way.
+
+
+ 44..22.. AAuutthheennttiiccaattiioonn SScchheemmeess
+
+
+ In the simple case authentication information is stored on a single
+ server and the user types a password on connecting for the first time.
+ However client operating systems often require a password before they
+ can be used at all, and in addition users usually want access to more
+ than one server. Asking users to remember many different passwords in
+ different contexts just does not work. Some kind of distributed
+ authentication database is needed. It must cope with password changes
+ and provide for assigning groups of users the same level of access
+ permissions. This is why Samba installations often choose to implement
+ a Domain model straight away.
+
+ Authentication decisions are some of the biggest in designing a
+ network. Are you going to use a scheme native to the client operating
+ system, native to the server operating system, or newly installed on
+ both? A list of options relevant to Samba (ie that make sense in the
+ context of the SMB protocol) follows. Any experiences with other
+ setups would be appreciated. refer to server FAQ for "passwd chat"
+ passwd program password server etc etc...
+
+
+ 44..22..11.. NNIISS
+
+
+ For Windows 95, Windows for Workgroups and most other clients Samba
+ can be a domain controller and share the password database via NIS
+ transparently. Windows NT is different. Free NIS NT client
+ <http://www.dcs.qmw.ac.uk/~williams>
+
+
+ 44..22..22.. KKeerrbbeerrooss
+
+
+ Kerberos for US users only: Kerberos overview
+ <http://www.cygnus.com/product/unifying-security.html> Download
+ Kerberos <http://www.cygnus.com/product/kerbnet-download.html>
+
+
+ 44..22..33.. FFTTPP
+
+
+ Other NT w/s logon hack via NT
+
+
+ 44..22..44.. DDeeffaauulltt SSeerrvveerr MMeetthhoodd
+
+
+
+
+
+ 44..22..55.. CClliieenntt--ssiiddee DDaattaabbaassee OOnnllyy
+
+
+
+ 44..33.. PPoosstt--AAuutthheennttiiccaattiioonn:: NNeettllooggoonn,, LLooggoonn SSccrriippttss,, PPrrooffiilleess
+
+
+ See <../DOMAIN.txt>
+
+
+ 55.. CCrroossss--PPrroottooccooll FFiillee SShhaarriinngg
+
+
+ Samba is an important tool for...
+
+ It is possible to...
+
+ File protocol gateways...
+
+ "Setting up a Linux File Server"
+ http://vetrec.mit.edu/people/narf/linux.html
+
+ Two free implementations of Appletalk for Unix are Netatalk,
+ <http://www.umich.edu/~rsug/netatalk/>, and CAP,
+ <http://www.cs.mu.oz.au/appletalk/atalk.html>. What Samba offers MS
+ Windows users, these packages offer to Macs. For more info on these
+ packages, Samba, and Linux (and other UNIX-based systems) see
+ <http://www.eats.com/linux_mac_win.html> 3.5) Sniffing your nework
+
+
+
+ 66.. MMiisscceellllaanneeoouuss
+
+
+ 66..11.. IIss SSaammbbaa YYeeaarr 22000000 ccoommpplliiaanntt??
+
+
+ The CIFS protocol that Samba implements negotiates times in various
+ formats, all of which are able to cope with dates beyond 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/faq/sambafaq-1.html b/docs/faq/sambafaq-1.html
new file mode 100644
index 00000000000..dde07840999
--- /dev/null
+++ b/docs/faq/sambafaq-1.html
@@ -0,0 +1,392 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: General Information</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="sambafaq-2.html">Next</A>
+<A HREF="sambafaq.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. General Information</A></H2>
+
+<P>
+<A NAME="general_info"></A>
+</P>
+<P>All about Samba - what it is, how to get it, related sources of
+information, how to understand the version numbering scheme, pizza
+details</P>
+
+<H2><A NAME="ss1.1">1.1 What is Samba? </A></H2>
+
+<P>
+<A NAME="introduction"></A>
+
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server
+Message Block) protocol. Initially written for Unix, Samba now also
+runs on Netware, OS/2 and VMS.</P>
+<P>In practice, this means that you can redirect disks and printers to
+Unix disks and printers from Lan Manager clients, Windows for
+Workgroups 3.11 clients, Windows NT clients, Linux clients and OS/2
+clients. There is also a generic Unix client program supplied as part
+of the suite which allows Unix users to use an ftp-like interface to
+access filespace and printers on any other SMB servers. This gives the
+capability for these operating systems to behave much like a LAN
+Server or Windows NT Server machine, only with added functionality and
+flexibility designed to make life easier for administrators.</P>
+<P>The components of the suite are (in summary):</P>
+<P>
+<UL>
+<LI><B>smbd</B>, the SMB server. This handles actual connections from clients, doing all the file, permission and username work</LI>
+<LI><B>nmbd</B>, the Netbios name server, which helps clients locate servers, doing the browsing work and managing domains as this capability is being built into Samba</LI>
+<LI><B>smbclient</B>, the Unix-hosted client program</LI>
+<LI><B>smbrun</B>, a little 'glue' program to help the server run external programs</LI>
+<LI><B>testprns</B>, a program to test server access to printers</LI>
+<LI><B>testparms</B>, a program to test the Samba configuration file for correctness</LI>
+<LI><B>smb.conf</B>, the Samba configuration file</LI>
+<LI><B>smbprint</B>, a sample script to allow a Unix host to use smbclient to print to an SMB server</LI>
+<LI><B>Documentation!</B> DON'T neglect to read it - you will save a great deal of time!</LI>
+</UL>
+</P>
+<P>The suite is supplied with full source (of course!) and is GPLed.</P>
+<P>The primary creator of the Samba suite is Andrew Tridgell. Later
+versions incorporate much effort by many net.helpers. The man pages
+and this FAQ were originally written by Karl Auer.</P>
+
+
+<H2><A NAME="ss1.2">1.2 What is the current version of Samba? </A></H2>
+
+<P>
+<A NAME="current_version"></A>
+
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file.
+<A HREF="ftp://samba.org/pub/samba/alpha/change-log">ftp://samba.org/pub/samba/alpha/change-log</A></P>
+<P>For more information see
+<A HREF="#version_nums">What do the version numbers mean?</A></P>
+
+
+<H2><A NAME="ss1.3">1.3 Where can I get it? </A></H2>
+
+<P>
+<A NAME="where"></A>
+
+The Samba suite is available via anonymous ftp from
+samba.org. The latest and greatest versions of the suite are in
+the directory:</P>
+<P>/pub/samba/</P>
+<P>Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are
+available in the directory:</P>
+<P>/pub/samba/alpha</P>
+<P>Note that binaries are NOT included in any of the above. Samba is
+distributed ONLY in source form, though binaries may be available from
+other sites. Recent versions of some Linux distributions, for example,
+do contain Samba binaries for that platform.</P>
+
+
+<H2><A NAME="ss1.4">1.4 What do the version numbers mean? </A></H2>
+
+<P>
+<A NAME="version_nums"></A>
+
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.</P>
+<P>How the scheme works:
+<OL>
+<LI>When major changes are made the version number is increased. For
+example, the transition from 1.9.15 to 1.9.16. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+</LI>
+<LI>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+</LI>
+<LI>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.16.
+</LI>
+<LI>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.16p2.</LI>
+</OL>
+
+So the progression goes:
+<PRE>
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+</PRE>
+
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.</P>
+
+
+<H2><A NAME="ss1.5">1.5 What platforms are supported? </A></H2>
+
+<P>
+<A NAME="platforms"></A>
+
+Many different platforms have run Samba successfully. The platforms
+most widely used and thus best tested are Linux and SunOS.</P>
+<P>At time of writing, the Makefile claimed support for:
+<UL>
+<LI> A/UX 3.0</LI>
+<LI> AIX</LI>
+<LI> Altos Series 386/1000</LI>
+<LI> Amiga</LI>
+<LI> Apollo Domain/OS sr10.3</LI>
+<LI> BSDI </LI>
+<LI> B.O.S. (Bull Operating System)</LI>
+<LI> Cray, Unicos 8.0</LI>
+<LI> Convex</LI>
+<LI> DGUX. </LI>
+<LI> DNIX.</LI>
+<LI> FreeBSD</LI>
+<LI> HP-UX</LI>
+<LI> Intergraph. </LI>
+<LI> Linux with/without shadow passwords and quota</LI>
+<LI> LYNX 2.3.0</LI>
+<LI> MachTen (a unix like system for Macintoshes)</LI>
+<LI> Motorola 88xxx/9xx range of machines</LI>
+<LI> NetBSD</LI>
+<LI> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).</LI>
+<LI> OS/2 using EMX 0.9b</LI>
+<LI> OSF1</LI>
+<LI> QNX 4.22</LI>
+<LI> RiscIX. </LI>
+<LI> RISCOs 5.0B</LI>
+<LI> SEQUENT. </LI>
+<LI> SCO (including: 3.2v2, European dist., OpenServer 5)</LI>
+<LI> SGI.</LI>
+<LI> SMP_DC.OSx v1.1-94c079 on Pyramid S series</LI>
+<LI> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)</LI>
+<LI> SUNOS 4</LI>
+<LI> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')</LI>
+<LI> Sunsoft ISC SVR3V4</LI>
+<LI> SVR4</LI>
+<LI> System V with some berkely extensions (Motorola 88k R32V3.2).</LI>
+<LI> ULTRIX.</LI>
+<LI> UNIXWARE</LI>
+<LI> UXP/DS</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss1.6">1.6 How can I find out more about Samba? </A></H2>
+
+<P>
+<A NAME="more"></A>
+
+There are a number of places to look for more information on Samba, including:
+<UL>
+<LI>Two mailing lists devoted to discussion of Samba-related matters. </LI>
+<LI>The newsgroup, comp.protocols.smb, which has a great deal of discussion on Samba. </LI>
+<LI>The WWW site 'SAMBA Web Pages' at
+<A HREF="http://samba.edu.au/samba/">http://samba.edu.au/samba/</A> includes:
+<UL>
+<LI>Links to man pages and documentation, including this FAQ</LI>
+<LI>A comprehensive survey of Samba users.</LI>
+<LI>A searchable hypertext archive of the Samba mailing list.</LI>
+<LI>Links to Samba source code, binaries, and mirrors of both.</LI>
+</UL>
+</LI>
+<LI>The long list of topic documentation. These files can be found in the 'docs' directory of the Samba source, or at
+<A HREF="ftp://samba.org/pub/samba/docs/">ftp://samba.org/pub/samba/docs/</A>
+<UL>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Application_Serving.txt">Application_Serving.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/BROWSING.txt">BROWSING.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/BUGS.txt">BUGS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/DIAGNOSIS.txt">DIAGNOSIS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/DNIX.txt">DNIX.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/DOMAIN.txt">DOMAIN.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/DOMAIN_CONTROL.txt">CONTROL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/ENCRYPTION.txt">ENCRYPTION.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Faxing.txt">Faxing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/GOTCHAS.txt">GOTCHAS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/HINTS.txt">HINTS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/INSTALL.sambatar">INSTALL.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/INSTALL.txt">INSTALL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/MIRRORS">MIRRORS</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/NetBIOS.txt">NetBIOS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/OS2.txt">OS2.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/PROJECTS">PROJECTS</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Passwords.txt">Passwords.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Printing.txt">Printing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/README.DCEDFS">README.DCEDFS</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/README.OS2">README.OS2</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/README.jis">README.jis</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/README.sambatar">README.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/SCO.txt">SCO.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/SMBTAR.notes">SMBTAR.notes</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Speed.txt">Speed.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Support.txt">Support.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/THANKS">THANKS</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Tracing.txt">Tracing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/UNIX-SMB.txt">SMB.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/Warp.txt">Warp.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/WinNT.txt">WinNT.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/history">history</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/security_level.txt">level.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.org/pub/samba/docs/wfw_slip.htm">slip.htm</A></LI>
+</UL>
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss1.7">1.7 How do I subscribe to the Samba Mailing Lists?</A></H2>
+
+<P>
+<A NAME="mailinglist"></A>
+
+Send email to
+<A HREF="mailto:listproc@samba.org">listproc@samba.org</A>. Make sure the subject line is
+blank, and include the following two lines in the body of the message:
+<BLOCKQUOTE><CODE>
+<PRE>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</PRE>
+</CODE></BLOCKQUOTE>
+
+Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature stuff, it
+sometimes confuses the list processor.</P>
+<P>The samba list is a digest list - every eight hours or so it
+regurgitates a single message containing all the messages that have
+been received by the list since the last time and sends a copy of this
+message to all subscribers.</P>
+<P>If you stop being interested in Samba, please send another email to
+<A HREF="mailto:listproc@samba.org">listproc@samba.org</A>. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+<BLOCKQUOTE><CODE>
+<PRE>
+unsubscribe samba
+unsubscribe samba-announce
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The <B>From:</B> line in your message <EM>MUST</EM> be the same address you used when
+you subscribed.</P>
+
+
+<H2><A NAME="ss1.8">1.8 Something's gone wrong - what should I do? </A></H2>
+
+<P>
+<A NAME="wrong"></A>
+
+<B><F>#</F> *** IMPORTANT! *** <F>#</F></B></P>
+<P>DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!</P>
+<P>Firstly, see if there are any likely looking entries in this FAQ! If
+you have just installed Samba, have you run through the checklist in
+<A HREF="ftp://samba.org/pub/samba/DIAGNOSIS.txt">DIAGNOSIS.txt</A>? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba distribution.</P>
+<P>Secondly, read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.</P>
+<P>Thirdly, if there is no obvious solution to hand, try to get a look at
+the log files for smbd and/or nmbd for the period during which you
+were having problems. You may need to reconfigure the servers to
+provide more extensive debugging information - usually level 2 or
+level 3 provide ample debugging info. Inspect these logs closely,
+looking particularly for the string "Error:".</P>
+<P>Fourthly, if you still haven't got anywhere, ask the mailing list or
+newsgroup. In general nobody minds answering questions provided you
+have followed the preceding steps. It might be a good idea to scan the
+archives of the mailing list, which are available through the Samba
+web site described in the previous
+section.</P>
+<P>If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+I can incorporate it in the next version.</P>
+<P>If you make changes to the source code, _please_ submit these patches
+so that everyone else gets the benefit of your work. This is one of
+the most important aspects to the maintainence of Samba. Send all
+patches to
+<A HREF="mailto:samba@samba.org">samba@samba.org</A>. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.</P>
+
+
+<H2><A NAME="ss1.9">1.9 Pizza supply details </A></H2>
+
+<P>
+<A NAME="pizza"></A>
+
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.</P>
+<P>Method 1: Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US</P>
+<P>Method 2: Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.</P>
+<P>Method 3: Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)</P>
+<P>Method 4: Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.</P>
+
+
+<HR>
+Previous
+<A HREF="sambafaq-2.html">Next</A>
+<A HREF="sambafaq.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-2.html b/docs/faq/sambafaq-2.html
new file mode 100644
index 00000000000..8978bc331ca
--- /dev/null
+++ b/docs/faq/sambafaq-2.html
@@ -0,0 +1,236 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Compiling and installing Samba on a Unix host</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-1.html">Previous</A>
+<A HREF="sambafaq-3.html">Next</A>
+<A HREF="sambafaq.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. Compiling and installing Samba on a Unix host</A></H2>
+
+<P>
+<A NAME="unix_install"></A>
+</P>
+
+<H2><A NAME="ss2.1">2.1 I can't see the Samba server in any browse lists!</A></H2>
+
+<P>
+<A NAME="no_browse"></A>
+
+See BROWSING.txt for more information on browsing. BROWSING.txt can
+be found in the docs directory of the Samba source.</P> <P>If your GUI
+client does not permit you to select non-browsable servers, you may
+need to do so on the command line. For example, under Lan Manager you
+might connect to the above service as disk drive M: thusly:
+<BLOCKQUOTE><CODE>
+<PRE>
+ net use M: \\mary\fred
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.</P>
+
+
+<H2><A NAME="ss2.2">2.2 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="missing_files"></A>
+
+See the next question.</P>
+
+<H2><A NAME="ss2.3">2.3 Some files on the server show up with really wierd filenames when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="strange_filenames"></A>
+
+If you check what files are not showing up, you will note that they
+are files which contain upper case letters or which are otherwise not
+DOS-compatible (ie, they are not legal DOS filenames for some reason).</P>
+<P>The Samba server can be configured either to ignore such files
+completely, or to present them to the client in "mangled" form. If you
+are not seeing the files at all, the Samba server has most likely been
+configured to ignore them. Consult the man page smb.conf(5) for
+details of how to change this - the parameter you need to set is
+"mangled names = yes".</P>
+
+
+<H2><A NAME="ss2.4">2.4 My client reports "cannot locate specified computer" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_server"></A>
+
+This indicates one of three things: You supplied an incorrect server
+name, the underlying TCP/IP layer is not working correctly, or the
+name you specified cannot be resolved.</P>
+<P>After carefully checking that the name you typed is the name you
+should have typed, try doing things like pinging a host or telnetting
+to somewhere on your network to see if TCP/IP is functioning OK. If it
+is, the problem is most likely name resolution.</P>
+<P>If your client has a facility to do so, hardcode a mapping between the
+hosts IP and the name you want to use. For example, with Man Manager
+or Windows for Workgroups you would put a suitable entry in the file
+LMHOSTS. If this works, the problem is in the communication between
+your client and the netbios name server. If it does not work, then
+there is something fundamental wrong with your naming and the solution
+is beyond the scope of this document.</P>
+<P>If you do not have any server on your subnet supplying netbios name
+resolution, hardcoded mappings are your only option. If you DO have a
+netbios name server running (such as the Samba suite's nmbd program),
+the problem probably lies in the way it is set up. Refer to Section
+Two of this FAQ for more ideas.</P>
+<P>By the way, remember to REMOVE the hardcoded mapping before further
+tests :-) </P>
+
+
+<H2><A NAME="ss2.5">2.5 My client reports "cannot locate specified share name" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_share"></A>
+
+This message indicates that your client CAN locate the specified
+server, which is a good start, but that it cannot find a service of
+the name you gave.</P>
+<P>The first step is to check the exact name of the service you are
+trying to connect to (consult your system administrator). Assuming it
+exists and you specified it correctly (read your client's doco on how
+to specify a service name correctly), read on:</P>
+<P>
+<UL>
+<LI> Many clients cannot accept or use service names longer than eight characters.</LI>
+<LI> Many clients cannot accept or use service names containing spaces.</LI>
+<LI> Some servers (not Samba though) are case sensitive with service names.</LI>
+<LI> Some clients force service names into upper case.</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.6">2.6 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A></H2>
+
+<P>
+<A NAME="cant_see_net"></A>
+
+Nothing is wrong - Samba does not implement the primary domain name
+controller stuff for several reasons, including the fact that the
+whole concept of a primary domain controller and "logging in to a
+network" doesn't fit well with clients possibly running on multiuser
+machines (such as users of smbclient under Unix). Having said that,
+several developers are working hard on building it in to the next
+major version of Samba. If you can contribute, send a message to
+<A HREF="mailto:samba@samba.org">samba@samba.org</A> !</P>
+<P>Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.</P>
+<P>For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.</P>
+
+
+<H2><A NAME="ss2.7">2.7 Printing doesn't work :-(</A></H2>
+
+<P>
+<A NAME="no_printing"></A>
+
+Make sure that the specified print command for the service you are
+connecting to is correct and that it has a fully-qualified path (eg.,
+use "/usr/bin/lpr" rather than just "lpr").</P>
+<P>Make sure that the spool directory specified for the service is
+writable by the user connected to the service. In particular the user
+"nobody" often has problems with printing, even if it worked with an
+earlier version of Samba. Try creating another guest user other than
+"nobody".</P>
+<P>Make sure that the user specified in the service is permitted to use
+the printer.</P>
+<P>Check the debug log produced by smbd. Search for the printer name and
+see if the log turns up any clues. Note that error messages to do with
+a service ipc$ are meaningless - they relate to the way the client
+attempts to retrieve status information when using the LANMAN1
+protocol.</P>
+<P>If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.</P>
+<P>If using the Lanman1 protocol (the default) then try switching to
+coreplus. Also not that print status error messages don't mean
+printing won't work. The print status is received by a different
+mechanism.</P>
+
+
+<H2><A NAME="ss2.8">2.8 My programs install on the server OK, but refuse to work properly</A></H2>
+
+<P>
+<A NAME="programs_wont_run"></A>
+
+There are numerous possible reasons for this, but one MAJOR
+possibility is that your software uses locking. Make sure you are
+using Samba 1.6.11 or later. It may also be possible to work around
+the problem by setting "locking=no" in the Samba configuration file
+for the service the software is installed on. This should be regarded
+as a strictly temporary solution.</P>
+<P>In earlier Samba versions there were some difficulties with the very
+latest Microsoft products, particularly Excel 5 and Word for Windows
+6. These should have all been solved. If not then please let Andrew
+Tridgell know via email at
+<A HREF="mailto:samba@samba.org">samba@samba.org</A>.</P>
+
+
+<H2><A NAME="ss2.9">2.9 My "server string" doesn't seem to be recognised</A></H2>
+
+<P>
+<A NAME="bad_server_string"></A>
+
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.</P>
+<P>You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.</P>
+<P>Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.</P>
+
+
+<H2><A NAME="ss2.10">2.10 My client reports "This server is not configured to list shared resources" </A></H2>
+
+<P>
+<A NAME="cant_list_shares"></A>
+
+Your guest account is probably invalid for some reason. Samba uses the
+guest account for browsing in smbd. Check that your guest account is
+valid.</P>
+<P>See also 'guest account' in smb.conf man page.</P>
+
+
+<H2><A NAME="ss2.11">2.11 Log message "you appear to have a trapdoor uid system" </A></H2>
+
+<P>
+<A NAME="trapdoor_uid"></A>
+
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.</P>
+<P>It might also mean that your OS has a trapdoor uid/gid system :-)</P>
+<P>This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.</P>
+<P>The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.</P>
+<P>Complain to your OS vendor and ask them to fix their system.</P>
+<P>Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!</P>
+
+
+<HR>
+<A HREF="sambafaq-1.html">Previous</A>
+<A HREF="sambafaq-3.html">Next</A>
+<A HREF="sambafaq.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-3.html b/docs/faq/sambafaq-3.html
new file mode 100644
index 00000000000..d7e0c7abd21
--- /dev/null
+++ b/docs/faq/sambafaq-3.html
@@ -0,0 +1,322 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Common client questions</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-2.html">Previous</A>
+<A HREF="sambafaq-4.html">Next</A>
+<A HREF="sambafaq.html#toc3">Table of Contents</A>
+<HR>
+<H2><A NAME="s3">3. Common client questions</A></H2>
+
+<P>
+<A NAME="client_questions"></A>
+</P>
+
+<H2><A NAME="ss3.1">3.1 Are there any Macintosh clients for Samba?</A></H2>
+
+<P>
+<A NAME="mac_clients"></A>
+
+Yes! Thursby now have a CIFS Client / Server called DAVE - see
+<A HREF="http://www.thursby.com/">http://www.thursby.com/</A>.
+They test it against Windows 95, Windows NT and samba for compatibility issues.
+At the time of writing, DAVE was at version 1.0.1. The 1.0.0 to 1.0.1 update is available
+as a free download from the Thursby web site (the speed of finder copies has
+been greatly enhanced, and there are bug-fixes included).</P>
+<P>Alternatives - There are two free implementations of AppleTalk for
+several kinds of UNIX machnes, and several more commercial ones.
+These products allow you to run file services and print services
+natively to Macintosh users, with no additional support required on
+the Macintosh. The two free omplementations are Netatalk,
+<A HREF="http://www.umich.edu/~rsug/netatalk/">http://www.umich.edu/~rsug/netatalk/</A>, and CAP,
+<A HREF="http://www.cs.mu.oz.au/appletalk/atalk.html">http://www.cs.mu.oz.au/appletalk/atalk.html</A>. What Samba offers
+MS Windows users, these packages offer to Macs. For more info on
+these packages, Samba, and Linux (and other UNIX-based systems)
+see
+<A HREF="http://www.eats.com/linux_mac_win.html">http://www.eats.com/linux_mac_win.html</A></P>
+
+
+<H2><A NAME="ss3.2">3.2 "Session request failed (131,130)" error</A></H2>
+
+<P>
+<A NAME="sess_req_fail"></A>
+
+The following answer is provided by John E. Miller:</P>
+<P>I'll assume that you're able to ping back and forth between the
+machines by IP address and name, and that you're using some security
+model where you're confident that you've got user IDs and passwords
+right. The logging options (-d3 or greater) can help a lot with that.
+DNS and WINS configuration can also impact connectivity as well.</P>
+<P>Now, on to 'scope id's. Somewhere in your Win95 TCP/IP network
+configuration (I'm too much of an NT bigot to know where it's located
+in the Win95 setup, but I'll have to learn someday since I teach for a
+Microsoft Solution Provider Authorized Tech Education Center - what an
+acronym...) <F>Note: It's under Control Panel | Network | TCP/IP | WINS
+Configuration</F> there's a little text entry field called something like
+'Scope ID'.</P>
+<P>This field essentially creates 'invisible' sub-workgroups on the same
+wire. Boxes can only see other boxes whose Scope IDs are set to the
+exact same value - it's sometimes used by OEMs to configure their
+boxes to browse only other boxes from the same vendor and, in most
+environments, this field should be left blank. If you, in fact, have
+something in this box that EXACT value (case-sensitive!) needs to be
+provided to smbclient and nmbd as the -i (lowercase) parameter. So, if
+your Scope ID is configured as the string 'SomeStr' in Win95 then
+you'd have to use smbclient -iSomeStr <F>otherparms</F> in connecting to
+it.</P>
+
+
+<H2><A NAME="ss3.3">3.3 How do I synchronise my PC's clock with my Samba server? </A></H2>
+
+<P>
+<A NAME="synchronise_clock"></A>
+
+To syncronize your PC's clock with your Samba server:
+<UL>
+<LI> Copy timesync.pif to your windows directory</LI>
+<LI> timesync.pif can be found at:
+<A HREF="http://samba.org/samba/binaries/miscellaneous/timesync.pif">http://samba.org/samba/binaries/miscellaneous/timesync.pif</A></LI>
+<LI> Add timesync.pif to your 'Start Up' group/folder</LI>
+<LI> Open the properties dialog box for the program/icon</LI>
+<LI> Make sure the 'Run Minimized' option is set in program 'Properties'</LI>
+<LI> Change the command line section that reads <F>\\sambahost</F> to reflect the name of your server.</LI>
+<LI> Close the properties dialog box by choosing 'OK'</LI>
+</UL>
+
+Each time you start your computer (or login for Win95) your PC will
+synchronize its clock with your Samba server.</P>
+<P>Alternativley, if you clients support Domain Logons, you can setup Domain Logons with Samba
+- see:
+<A HREF="ftp://samba.org/pub/samba/docs/BROWSING.txt">BROWSING.txt</A> *** for more information.</P>
+<P>Then add
+<BLOCKQUOTE><CODE>
+<PRE>
+NET TIME \\%L /SET /YES
+</PRE>
+</CODE></BLOCKQUOTE>
+
+as one of the lines in the logon script.</P>
+
+<H2><A NAME="ss3.4">3.4 Problems with WinDD, NTrigue, WinCenterPro etc</A></H2>
+
+<P>
+<A NAME="multiple_session_clients"></A>
+</P>
+<P>All of the above programs are applications that sit on an NT box and
+allow multiple users to access the NT GUI applications from remote
+workstations (often over X).</P>
+<P>What has this got to do with Samba? The problem comes when these users
+use filemanager to mount shares from a Samba server. The most common
+symptom is that the first user to connect get correct file permissions
+and has a nice day, but subsequent connections get logged in as the
+same user as the first person to login. They find that they cannot
+access files in their own home directory, but that they can access
+files in the first users home directory (maybe not such a nice day
+after all?)</P>
+<P>Why does this happen? The above products all share a common heritage
+(and code base I believe). They all open just a single TCP based SMB
+connection to the Samba server, and requests from all users are piped
+over this connection. This is unfortunate, but not fatal.</P>
+<P>It means that if you run your Samba server in share level security
+(the default) then things will definately break as described
+above. The share level SMB security model has no provision for
+multiple user IDs on the one SMB connection. See
+<A HREF="ftp://samba.org/pub/samba/docs/security_level.txt">security_level.txt</A> in
+the docs for more info on share/user/server level security.</P>
+<P>If you run in user or server level security then you have a chance,
+but only if you have a recent version of Samba (at least 1.9.15p6). In
+older versions bugs in Samba meant you still would have had problems.</P>
+<P>If you have a trapdoor uid system in your OS then it will never work
+properly. Samba needs to be able to switch uids on the connection and
+it can't if your OS has a trapdoor uid system. You'll know this
+because Samba will note it in your logs.</P>
+<P>Also note that you should not use the magic "homes" share name with
+products like these, as otherwise all users will end up with the same
+home directory. Use <F>\\server\username</F> instead.</P>
+
+
+<H2><A NAME="ss3.5">3.5 Problem with printers under NT</A></H2>
+
+<P>
+<A NAME="nt_printers"></A>
+
+This info from Stefan Hergeth
+hergeth@f7axp1.informatik.fh-muenchen.de may be useful:</P>
+<P>A network-printer (with ethernetcard) is connected to the NT-Clients
+via our UNIX-Fileserver (SAMBA-Server), like the configuration told by
+Matthew Harrell harrell@leech.nrl.navy.mil (see WinNT.txt)
+<OL>
+<LI>If a user has choosen this printer as the default printer in his
+NT-Session and this printer is not connected to the network
+(e.g. switched off) than this user has a problem with the SAMBA-
+connection of his filesystems. It's very slow.
+</LI>
+<LI>If the printer is connected to the network everything works fine.
+</LI>
+<LI>When the smbd ist started with debug level 3, you can see that the
+NT spooling system try to connect to the printer many times. If the
+printer ist not connected to the network this request fails and the
+NT spooler is wasting a lot of time to connect to the printer service.
+This seems to be the reason for the slow network connection.
+</LI>
+<LI>Maybe it's possible to change this behaviour by setting different
+printer properties in the Print-Manager-Menu of NT, but i didn't try it yet.</LI>
+</OL>
+</P>
+
+
+<H2><A NAME="ss3.6">3.6 Why are my file's timestamps off by an hour, or by a few hours?</A></H2>
+
+<P>
+<A NAME="dst_bugs"></A>
+
+This is from Paul Eggert eggert@twinsun.com.</P>
+<P>Most likely it's a problem with your time zone settings.</P>
+<P>Internally, Samba maintains time in traditional Unix format,
+namely, the number of seconds since 1970-01-01 00:00:00 Universal Time
+(or ``GMT''), not counting leap seconds.</P>
+<P>On the server side, Samba uses the Unix TZ variable to convert
+internal timestamps to and from local time. So on the server side, there are
+two things to get right.
+<OL>
+<LI>The Unix system clock must have the correct Universal time.
+Use the shell command "sh -c 'TZ=UTC0 date'" to check this.
+</LI>
+<LI>The TZ environment variable must be set on the server
+before Samba is invoked. The details of this depend on the
+server OS, but typically you must edit a file whose name is
+/etc/TIMEZONE or /etc/default/init, or run the command `zic -l'.
+</LI>
+<LI>TZ must have the correct value.
+<OL>
+<LI>If possible, use geographical time zone settings
+(e.g. TZ='America/Los_Angeles' or perhaps
+TZ=':US/Pacific'). These are supported by most
+popular Unix OSes, are easier to get right, and are
+more accurate for historical timestamps. If your
+operating system has out-of-date tables, you should be
+able to update them from the public domain time zone
+tables at
+<A HREF="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/</A>.
+</LI>
+<LI>If your system does not support geographical timezone
+settings, you must use a Posix-style TZ strings, e.g.
+TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time.
+Posix TZ strings can take the following form (with optional
+items in brackets):
+<PRE>
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+</PRE>
+
+where:
+<UL>
+<LI> `Std' is the standard time designation (e.g. `PST').
+</LI>
+<LI> `Offset' is the number of hours behind UTC (e.g. `8').
+Prepend a `-' if you are ahead of UTC, and
+append `:30' if you are at a half-hour offset.
+Omit all the remaining items if you do not use
+daylight-saving time.
+</LI>
+<LI> `Dst' is the daylight-saving time designation
+(e.g. `PDT').
+
+The optional second `Offset' is the number of
+hours that daylight-saving time is behind UTC.
+The default is 1 hour ahead of standard time.
+</LI>
+<LI> `Date/Time,Date/Time' specify when daylight-saving
+time starts and ends. The format for a date is
+`Mm.n.d', which specifies the dth day (0 is Sunday)
+of the nth week of the mth month, where week 5 means
+the last such day in the month. The format for a
+time is <F>h</F>h<F>:mm[:ss</F>], using a 24-hour clock.</LI>
+</UL>
+
+Other Posix string formats are allowed but you don't want
+to know about them.</LI>
+</OL>
+</LI>
+</OL>
+
+On the client side, you must make sure that your client's clock and
+time zone is also set appropriately. <F>[I don't know how to do this.</F>]
+Samba traditionally has had many problems dealing with time zones, due
+to the bizarre ways that Microsoft network protocols handle time
+zones. A common symptom is for file timestamps to be off by an hour.
+To work around the problem, try disconnecting from your Samba server
+and then reconnecting to it; or upgrade your Samba server to
+1.9.16alpha10 or later.</P>
+
+
+<H2><A NAME="ss3.7">3.7 How do I set the printer driver name correctly? </A></H2>
+
+<P>
+<A NAME="printer_driver_name"></A>
+
+Question:
+On NT, I opened "Printer Manager" and "Connect to Printer".
+Enter <F>"\\ptdi270\ps1"</F> in the box of printer. I got the
+following error message:
+<BLOCKQUOTE><CODE>
+<PRE>
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+</PRE>
+</CODE></BLOCKQUOTE>
+
+Answer:</P>
+<P>In the more recent versions of Samba you can now set the "printer
+driver" in smb.conf. This tells the client what driver to use. For
+example:
+<BLOCKQUOTE><CODE>
+<PRE>
+ printer driver = HP LaserJet 4L
+</PRE>
+</CODE></BLOCKQUOTE>
+
+with this, NT knows to use the right driver. You have to get this string
+exactly right.</P>
+<P>To find the exact string to use, you need to get to the dialog box in
+your client where you select which printer driver to install. The
+correct strings for all the different printers are shown in a listbox
+in that dialog box.</P>
+<P>You could also try setting the driver to NULL like this:
+<BLOCKQUOTE><CODE>
+<PRE>
+ printer driver = NULL
+</PRE>
+</CODE></BLOCKQUOTE>
+
+this is effectively what older versions of Samba did, so if that
+worked for you then give it a go. If this does work then let us know via
+<A HREF="mailto:samba@samba.org">samba@samba.org</A>,
+and we'll make it the default. Currently the default is a 0 length
+string.</P>
+
+
+<H2><A NAME="ss3.8">3.8 I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?</A></H2>
+
+<P>
+<A NAME="NT_SP3_FIX"></A>
+
+As of SP3, Microsoft has decided that they will no longer default to
+passing clear text passwords over the network. To enable access to
+Samba shares from NT 4.0 SP3, you must do <B>ONE</B> of two things:
+<OL>
+<LI> Set the Samba configuration option 'security = user' and implement all of the stuff detailed in
+<A HREF="ftp://samba.org/pub/samba/docs/ENCRYPTION.txt">ENCRYPTION.txt</A>.</LI>
+<LI> Follow Microsoft's directions for setting your NT box to allow plain text passwords. see
+<A HREF="http://www.microsoft.com/kb/articles/q166/7/30.htm">Knowledge Base Article Q166730</A></LI>
+</OL>
+</P>
+
+
+<HR>
+<A HREF="sambafaq-2.html">Previous</A>
+<A HREF="sambafaq-4.html">Next</A>
+<A HREF="sambafaq.html#toc3">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-4.html b/docs/faq/sambafaq-4.html
new file mode 100644
index 00000000000..94d5c419906
--- /dev/null
+++ b/docs/faq/sambafaq-4.html
@@ -0,0 +1,37 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Specific client application problems</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-3.html">Previous</A>
+<A HREF="sambafaq-5.html">Next</A>
+<A HREF="sambafaq.html#toc4">Table of Contents</A>
+<HR>
+<H2><A NAME="s4">4. Specific client application problems</A></H2>
+
+<P>
+<A NAME="client_problems"></A>
+</P>
+
+<H2><A NAME="ss4.1">4.1 MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"</A></H2>
+
+<P>
+<A NAME="cant_change_properties"></A>
+
+When installing MS Office on a Samba drive for which you have admin
+user permissions, ie. admin users = username, you will find the
+setup program unable to complete the installation.</P>
+<P>To get around this problem, do the installation without admin user
+permissions The problem is that MS Office Setup checks that a file is
+rdonly by trying to open it for writing.</P>
+<P>Admin users can always open a file for writing, as they run as root.
+You just have to install as a non-admin user and then use "chown -R"
+to fix the owner.</P>
+
+
+<HR>
+<A HREF="sambafaq-3.html">Previous</A>
+<A HREF="sambafaq-5.html">Next</A>
+<A HREF="sambafaq.html#toc4">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-5.html b/docs/faq/sambafaq-5.html
new file mode 100644
index 00000000000..0a6e9d08f03
--- /dev/null
+++ b/docs/faq/sambafaq-5.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Miscellaneous</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-4.html">Previous</A>
+Next
+<A HREF="sambafaq.html#toc5">Table of Contents</A>
+<HR>
+<H2><A NAME="s5">5. Miscellaneous</A></H2>
+
+<P>
+<A NAME="miscellaneous"></A>
+</P>
+<H2><A NAME="ss5.1">5.1 Is Samba Year 2000 compliant?</A></H2>
+
+<P>
+<A NAME="Year2000Compliant"></A>
+
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.</P>
+
+
+<HR>
+<A HREF="sambafaq-4.html">Previous</A>
+Next
+<A HREF="sambafaq.html#toc5">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq.html b/docs/faq/sambafaq.html
new file mode 100644
index 00000000000..2c703885cdf
--- /dev/null
+++ b/docs/faq/sambafaq.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="sambafaq-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba FAQ</H1>
+
+<H2>Paul Blackman, <CODE>ictinus@samba.org</CODE></H2>v 0.8, June '97
+<P><HR><EM> This is the Frequently Asked Questions (FAQ) document for
+Samba, the free and very popular SMB server product. An SMB server
+allows file and printer connections from clients such as Windows,
+OS/2, Linux and others. Current to version 1.9.17. Please send any
+corrections to the author.</EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="sambafaq-1.html">General Information</A></H2>
+<UL>
+<LI><A HREF="sambafaq-1.html#ss1.1">1.1 What is Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.2">1.2 What is the current version of Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.3">1.3 Where can I get it? </A>
+<LI><A HREF="sambafaq-1.html#ss1.4">1.4 What do the version numbers mean? </A>
+<LI><A HREF="sambafaq-1.html#ss1.5">1.5 What platforms are supported? </A>
+<LI><A HREF="sambafaq-1.html#ss1.6">1.6 How can I find out more about Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.7">1.7 How do I subscribe to the Samba Mailing Lists?</A>
+<LI><A HREF="sambafaq-1.html#ss1.8">1.8 Something's gone wrong - what should I do? </A>
+<LI><A HREF="sambafaq-1.html#ss1.9">1.9 Pizza supply details </A>
+</UL>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="sambafaq-2.html">Compiling and installing Samba on a Unix host</A></H2>
+<UL>
+<LI><A HREF="sambafaq-2.html#ss2.1">2.1 I can't see the Samba server in any browse lists!</A>
+<LI><A HREF="sambafaq-2.html#ss2.2">2.2 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A>
+<LI><A HREF="sambafaq-2.html#ss2.3">2.3 Some files on the server show up with really wierd filenames when I view the files from my client! </A>
+<LI><A HREF="sambafaq-2.html#ss2.4">2.4 My client reports "cannot locate specified computer" or similar</A>
+<LI><A HREF="sambafaq-2.html#ss2.5">2.5 My client reports "cannot locate specified share name" or similar</A>
+<LI><A HREF="sambafaq-2.html#ss2.6">2.6 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A>
+<LI><A HREF="sambafaq-2.html#ss2.7">2.7 Printing doesn't work :-(</A>
+<LI><A HREF="sambafaq-2.html#ss2.8">2.8 My programs install on the server OK, but refuse to work properly</A>
+<LI><A HREF="sambafaq-2.html#ss2.9">2.9 My "server string" doesn't seem to be recognised</A>
+<LI><A HREF="sambafaq-2.html#ss2.10">2.10 My client reports "This server is not configured to list shared resources" </A>
+<LI><A HREF="sambafaq-2.html#ss2.11">2.11 Log message "you appear to have a trapdoor uid system" </A>
+</UL>
+
+<P>
+<H2><A NAME="toc3">3.</A> <A HREF="sambafaq-3.html">Common client questions</A></H2>
+<UL>
+<LI><A HREF="sambafaq-3.html#ss3.1">3.1 Are there any Macintosh clients for Samba?</A>
+<LI><A HREF="sambafaq-3.html#ss3.2">3.2 "Session request failed (131,130)" error</A>
+<LI><A HREF="sambafaq-3.html#ss3.3">3.3 How do I synchronise my PC's clock with my Samba server? </A>
+<LI><A HREF="sambafaq-3.html#ss3.4">3.4 Problems with WinDD, NTrigue, WinCenterPro etc</A>
+<LI><A HREF="sambafaq-3.html#ss3.5">3.5 Problem with printers under NT</A>
+<LI><A HREF="sambafaq-3.html#ss3.6">3.6 Why are my file's timestamps off by an hour, or by a few hours?</A>
+<LI><A HREF="sambafaq-3.html#ss3.7">3.7 How do I set the printer driver name correctly? </A>
+<LI><A HREF="sambafaq-3.html#ss3.8">3.8 I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?</A>
+</UL>
+
+<P>
+<H2><A NAME="toc4">4.</A> <A HREF="sambafaq-4.html">Specific client application problems</A></H2>
+<UL>
+<LI><A HREF="sambafaq-4.html#ss4.1">4.1 MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"</A>
+</UL>
+
+<P>
+<H2><A NAME="toc5">5.</A> <A HREF="sambafaq-5.html">Miscellaneous</A></H2>
+<UL>
+<LI><A HREF="sambafaq-5.html#ss5.1">5.1 Is Samba Year 2000 compliant?</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="sambafaq-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq.sgml b/docs/faq/sambafaq.sgml
new file mode 100644
index 00000000000..333ac55f673
--- /dev/null
+++ b/docs/faq/sambafaq.sgml
@@ -0,0 +1,792 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.5 18 Oct 1996 Dan Shearer Dan.Shearer@unisa.edu.au
+ First linuxdoc-sgml version, outline only
+ v 0.6 25 Oct 1996 Dan
+ Filled in from current text faq
+ v 0.7 1 June 1997 Paul
+ Replicated changes in txt faq to sgml faq
+ 9 June 1997 Paul
+ Lots of changes, added doco list, updated compatible systems list
+ added NT SP3 entry, added Year 2000 entry, Getting ready for 1.9.17
+ v 0.8 7th Oct 97 Paul
+ changed samba.canberra entries to samba.anu.../samba/
+-->
+
+<article>
+
+<title> Samba FAQ
+
+<author>Paul Blackman, <tt>ictinus@samba.org</tt>
+
+<date>v 0.8, June '97
+
+<abstract> This is the Frequently Asked Questions (FAQ) document for
+Samba, the free and very popular SMB server product. An SMB server
+allows file and printer connections from clients such as Windows,
+OS/2, Linux and others. Current to version 1.9.17. Please send any
+corrections to the author.
+</abstract>
+
+<toc>
+
+<sect> General Information<p> <label id="general_info">
+
+All about Samba - what it is, how to get it, related sources of
+information, how to understand the version numbering scheme, pizza
+details
+
+<sect1> What is Samba? <p> <label id="introduction">
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server
+Message Block) protocol. Initially written for Unix, Samba now also
+runs on Netware, OS/2 and VMS.
+
+In practice, this means that you can redirect disks and printers to
+Unix disks and printers from Lan Manager clients, Windows for
+Workgroups 3.11 clients, Windows NT clients, Linux clients and OS/2
+clients. There is also a generic Unix client program supplied as part
+of the suite which allows Unix users to use an ftp-like interface to
+access filespace and printers on any other SMB servers. This gives the
+capability for these operating systems to behave much like a LAN
+Server or Windows NT Server machine, only with added functionality and
+flexibility designed to make life easier for administrators.
+
+The components of the suite are (in summary):
+
+<itemize>
+<item><bf>smbd</bf>, the SMB server. This handles actual connections from clients, doing all the file, permission and username work
+<item><bf>nmbd</bf>, the Netbios name server, which helps clients locate servers, doing the browsing work and managing domains as this capability is being built into Samba
+<item><bf>smbclient</bf>, the Unix-hosted client program
+<item><bf>smbrun</bf>, a little 'glue' program to help the server run external programs
+<item><bf>testprns</bf>, a program to test server access to printers
+<item><bf>testparms</bf>, a program to test the Samba configuration file for correctness
+<item><bf>smb.conf</bf>, the Samba configuration file
+<item><bf>smbprint</bf>, a sample script to allow a Unix host to use smbclient to print to an SMB server
+<item><bf>Documentation!</bf> DON'T neglect to read it - you will save a great deal of time!
+</itemize>
+
+The suite is supplied with full source (of course!) and is GPLed.
+
+The primary creator of the Samba suite is Andrew Tridgell. Later
+versions incorporate much effort by many net.helpers. The man pages
+and this FAQ were originally written by Karl Auer.
+
+<sect1> What is the current version of Samba? <p><label id="current_version">
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file. <url url="ftp://samba.org/pub/samba/alpha/change-log">
+
+For more information see <ref id="version_nums" name="What do the
+version numbers mean?">
+
+<sect1> Where can I get it? <p> <label id="where">
+The Samba suite is available via anonymous ftp from
+samba.org. The latest and greatest versions of the suite are in
+the directory:
+
+/pub/samba/
+
+Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are
+available in the directory:
+
+/pub/samba/alpha
+
+Note that binaries are NOT included in any of the above. Samba is
+distributed ONLY in source form, though binaries may be available from
+other sites. Recent versions of some Linux distributions, for example,
+do contain Samba binaries for that platform.
+
+<sect1> What do the version numbers mean? <p> <label id="version_nums">
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.
+
+How the scheme works:
+<enum>
+<item>When major changes are made the version number is increased. For
+example, the transition from 1.9.15 to 1.9.16. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+
+<item>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+
+<item>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.16.
+
+<item>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.16p2.
+</enum>
+So the progression goes:
+<verb>
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+</verb>
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.
+
+<sect1> What platforms are supported? <p> <label id="platforms">
+Many different platforms have run Samba successfully. The platforms
+most widely used and thus best tested are Linux and SunOS.
+
+At time of writing, the Makefile claimed support for:
+<itemize>
+<item> A/UX 3.0
+<item> AIX
+<item> Altos Series 386/1000
+<item> Amiga
+<item> Apollo Domain/OS sr10.3
+<item> BSDI
+<item> B.O.S. (Bull Operating System)
+<item> Cray, Unicos 8.0
+<item> Convex
+<item> DGUX.
+<item> DNIX.
+<item> FreeBSD
+<item> HP-UX
+<item> Intergraph.
+<item> Linux with/without shadow passwords and quota
+<item> LYNX 2.3.0
+<item> MachTen (a unix like system for Macintoshes)
+<item> Motorola 88xxx/9xx range of machines
+<item> NetBSD
+<item> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).
+<item> OS/2 using EMX 0.9b
+<item> OSF1
+<item> QNX 4.22
+<item> RiscIX.
+<item> RISCOs 5.0B
+<item> SEQUENT.
+<item> SCO (including: 3.2v2, European dist., OpenServer 5)
+<item> SGI.
+<item> SMP_DC.OSx v1.1-94c079 on Pyramid S series
+<item> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+<item> SUNOS 4
+<item> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+<item> Sunsoft ISC SVR3V4
+<item> SVR4
+<item> System V with some berkely extensions (Motorola 88k R32V3.2).
+<item> ULTRIX.
+<item> UNIXWARE
+<item> UXP/DS
+</itemize>
+
+<sect1> How can I find out more about Samba? <p> <label id="more">
+There are a number of places to look for more information on Samba, including:
+<itemize>
+<item>Two mailing lists devoted to discussion of Samba-related matters.
+<item>The newsgroup, comp.protocols.smb, which has a great deal of discussion on Samba.
+<item>The WWW site 'SAMBA Web Pages' at <url url="http://samba.edu.au/samba/"> includes:
+ <itemize>
+ <item>Links to man pages and documentation, including this FAQ
+ <item>A comprehensive survey of Samba users.
+ <item>A searchable hypertext archive of the Samba mailing list.
+ <item>Links to Samba source code, binaries, and mirrors of both.
+ </itemize>
+<item>The long list of topic documentation. These files can be found in the 'docs' directory of the Samba source, or at <url url="ftp://samba.org/pub/samba/docs/">
+ <itemize>
+ <item><url url="ftp://samba.org/pub/samba/docs/Application_Serving.txt" name="Application_Serving.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/BROWSING.txt" name="BROWSING.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/BUGS.txt" name="BUGS.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/DIAGNOSIS.txt" name="DIAGNOSIS.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/DNIX.txt" name="DNIX.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/DOMAIN.txt" name="DOMAIN.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/DOMAIN_CONTROL.txt" name="CONTROL.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/ENCRYPTION.txt" name="ENCRYPTION.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/Faxing.txt" name="Faxing.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/GOTCHAS.txt" name="GOTCHAS.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/HINTS.txt" name="HINTS.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/INSTALL.sambatar" name="INSTALL.sambatar">
+ <item><url url="ftp://samba.org/pub/samba/docs/INSTALL.txt" name="INSTALL.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/MIRRORS" name="MIRRORS">
+ <item><url url="ftp://samba.org/pub/samba/docs/NetBIOS.txt" name="NetBIOS.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/OS2.txt" name="OS2.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/PROJECTS" name="PROJECTS">
+ <item><url url="ftp://samba.org/pub/samba/docs/Passwords.txt" name="Passwords.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/Printing.txt" name="Printing.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/README.DCEDFS" name="README.DCEDFS">
+ <item><url url="ftp://samba.org/pub/samba/docs/README.OS2" name="README.OS2">
+ <item><url url="ftp://samba.org/pub/samba/docs/README.jis" name="README.jis">
+ <item><url url="ftp://samba.org/pub/samba/docs/README.sambatar" name="README.sambatar">
+ <item><url url="ftp://samba.org/pub/samba/docs/SCO.txt" name="SCO.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/SMBTAR.notes" name="SMBTAR.notes">
+ <item><url url="ftp://samba.org/pub/samba/docs/Speed.txt" name="Speed.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/Support.txt" name="Support.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/THANKS" name="THANKS">
+ <item><url url="ftp://samba.org/pub/samba/docs/Tracing.txt" name="Tracing.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/UNIX-SMB.txt" name="SMB.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/Warp.txt" name="Warp.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/WinNT.txt" name="WinNT.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/history" name="history">
+ <item><url url="ftp://samba.org/pub/samba/docs/security_level.txt" name="level.txt">
+ <item><url url="ftp://samba.org/pub/samba/docs/wfw_slip.htm" name="slip.htm">
+ </itemize>
+</itemize>
+
+<sect1>How do I subscribe to the Samba Mailing Lists?<p><label id="mailinglist">
+Send email to <htmlurl url="mailto:listproc@samba.org" name="listproc@samba.org">. Make sure the subject line is
+blank, and include the following two lines in the body of the message:
+<tscreen><verb>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</verb></tscreen>
+Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature stuff, it
+sometimes confuses the list processor.
+
+The samba list is a digest list - every eight hours or so it
+regurgitates a single message containing all the messages that have
+been received by the list since the last time and sends a copy of this
+message to all subscribers.
+
+If you stop being interested in Samba, please send another email to
+<htmlurl url="mailto:listproc@samba.org" name="listproc@samba.org">. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+<tscreen><verb>
+unsubscribe samba
+unsubscribe samba-announce
+</verb></tscreen>
+The <bf>From:</bf> line in your message <em>MUST</em> be the same address you used when
+you subscribed.
+
+<sect1> Something's gone wrong - what should I do? <p> <label id="wrong">
+<bf>[#] *** IMPORTANT! *** [#]</bf>
+<p>DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!
+
+Firstly, see if there are any likely looking entries in this FAQ! If
+you have just installed Samba, have you run through the checklist in
+<url url="ftp://samba.org/pub/samba/DIAGNOSIS.txt" name="DIAGNOSIS.txt">? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba distribution.
+
+Secondly, read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.
+
+Thirdly, if there is no obvious solution to hand, try to get a look at
+the log files for smbd and/or nmbd for the period during which you
+were having problems. You may need to reconfigure the servers to
+provide more extensive debugging information - usually level 2 or
+level 3 provide ample debugging info. Inspect these logs closely,
+looking particularly for the string "Error:".
+
+Fourthly, if you still haven't got anywhere, ask the mailing list or
+newsgroup. In general nobody minds answering questions provided you
+have followed the preceding steps. It might be a good idea to scan the
+archives of the mailing list, which are available through the Samba
+web site described in the previous
+section.
+
+If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+I can incorporate it in the next version.
+
+If you make changes to the source code, _please_ submit these patches
+so that everyone else gets the benefit of your work. This is one of
+the most important aspects to the maintainence of Samba. Send all
+patches to <htmlurl url="mailto:samba-patches@samba.org" name="samba-patches@samba.org">. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.
+
+<sect1> Pizza supply details <p> <label id="pizza">
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.
+
+Method 1: Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US
+
+Method 2: Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+
+Method 3: Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+
+Method 4: Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+
+<sect>Compiling and installing Samba on a Unix host<p><label id="unix_install">
+
+<sect1>I can't see the Samba server in any browse lists!<p><label id="no_browse">
+ See <url url="ftp://samba.org/pub/samba/BROWSING.txt" name="BROWSING.txt">
+ for more information on browsing. Browsing.txt can also be found
+ in the docs directory of the Samba source.
+
+If your GUI client does not permit you to select non-browsable
+servers, you may need to do so on the command line. For example, under
+Lan Manager you might connect to the above service as disk drive M:
+thusly:
+<tscreen><verb>
+ net use M: \\mary\fred
+</verb></tscreen>
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.
+
+<sect1>Some files that I KNOW are on the server doesn't show up when I view the files from my client! <p> <label id="missing_files">
+See the next question.
+<sect1>Some files on the server show up with really wierd filenames when I view the files from my client! <p> <label id="strange_filenames">
+If you check what files are not showing up, you will note that they
+are files which contain upper case letters or which are otherwise not
+DOS-compatible (ie, they are not legal DOS filenames for some reason).
+
+The Samba server can be configured either to ignore such files
+completely, or to present them to the client in "mangled" form. If you
+are not seeing the files at all, the Samba server has most likely been
+configured to ignore them. Consult the man page smb.conf(5) for
+details of how to change this - the parameter you need to set is
+"mangled names = yes".
+
+<sect1>My client reports "cannot locate specified computer" or similar<p><label id="cant_see_server">
+This indicates one of three things: You supplied an incorrect server
+name, the underlying TCP/IP layer is not working correctly, or the
+name you specified cannot be resolved.
+
+After carefully checking that the name you typed is the name you
+should have typed, try doing things like pinging a host or telnetting
+to somewhere on your network to see if TCP/IP is functioning OK. If it
+is, the problem is most likely name resolution.
+
+If your client has a facility to do so, hardcode a mapping between the
+hosts IP and the name you want to use. For example, with Man Manager
+or Windows for Workgroups you would put a suitable entry in the file
+LMHOSTS. If this works, the problem is in the communication between
+your client and the netbios name server. If it does not work, then
+there is something fundamental wrong with your naming and the solution
+is beyond the scope of this document.
+
+If you do not have any server on your subnet supplying netbios name
+resolution, hardcoded mappings are your only option. If you DO have a
+netbios name server running (such as the Samba suite's nmbd program),
+the problem probably lies in the way it is set up. Refer to Section
+Two of this FAQ for more ideas.
+
+By the way, remember to REMOVE the hardcoded mapping before further
+tests :-)
+
+<sect1>My client reports "cannot locate specified share name" or similar<p> <label id="cant_see_share">
+This message indicates that your client CAN locate the specified
+server, which is a good start, but that it cannot find a service of
+the name you gave.
+
+The first step is to check the exact name of the service you are
+trying to connect to (consult your system administrator). Assuming it
+exists and you specified it correctly (read your client's doco on how
+to specify a service name correctly), read on:
+
+<itemize>
+<item> Many clients cannot accept or use service names longer than eight characters.
+<item> Many clients cannot accept or use service names containing spaces.
+<item> Some servers (not Samba though) are case sensitive with service names.
+<item> Some clients force service names into upper case.
+</itemize>
+
+<sect1>My client reports "cannot find domain controller", "cannot log on to the network" or similar <p> <label id="cant_see_net">
+Nothing is wrong - Samba does not implement the primary domain name
+controller stuff for several reasons, including the fact that the
+whole concept of a primary domain controller and "logging in to a
+network" doesn't fit well with clients possibly running on multiuser
+machines (such as users of smbclient under Unix). Having said that,
+several developers are working hard on building it in to the next
+major version of Samba. If you can contribute, send a message to
+<htmlurl url="mailto:samba@samba.org" name="samba@samba.org"> !
+
+Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.
+
+For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.
+
+<sect1>Printing doesn't work :-(<p> <label id="no_printing">
+Make sure that the specified print command for the service you are
+connecting to is correct and that it has a fully-qualified path (eg.,
+use "/usr/bin/lpr" rather than just "lpr").
+
+Make sure that the spool directory specified for the service is
+writable by the user connected to the service. In particular the user
+"nobody" often has problems with printing, even if it worked with an
+earlier version of Samba. Try creating another guest user other than
+"nobody".
+
+Make sure that the user specified in the service is permitted to use
+the printer.
+
+Check the debug log produced by smbd. Search for the printer name and
+see if the log turns up any clues. Note that error messages to do with
+a service ipc$ are meaningless - they relate to the way the client
+attempts to retrieve status information when using the LANMAN1
+protocol.
+
+If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.
+
+If using the Lanman1 protocol (the default) then try switching to
+coreplus. Also not that print status error messages don't mean
+printing won't work. The print status is received by a different
+mechanism.
+
+<sect1>My programs install on the server OK, but refuse to work properly<p><label id="programs_wont_run">
+There are numerous possible reasons for this, but one MAJOR
+possibility is that your software uses locking. Make sure you are
+using Samba 1.6.11 or later. It may also be possible to work around
+the problem by setting "locking=no" in the Samba configuration file
+for the service the software is installed on. This should be regarded
+as a strictly temporary solution.
+
+In earlier Samba versions there were some difficulties with the very
+latest Microsoft products, particularly Excel 5 and Word for Windows
+6. These should have all been solved. If not then please let Andrew
+Tridgell know via email at <htmlurl url="mailto:samba@samba.org" name="samba@samba.org">.
+
+<sect1>My "server string" doesn't seem to be recognised<p><label id="bad_server_string">
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.
+
+You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.
+
+Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+<sect1>My client reports "This server is not configured to list shared resources" <p> <label id="cant_list_shares">
+Your guest account is probably invalid for some reason. Samba uses the
+guest account for browsing in smbd. Check that your guest account is
+valid.
+
+See also 'guest account' in smb.conf man page.
+
+<sect1>Log message "you appear to have a trapdoor uid system" <p><label id="trapdoor_uid">
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.
+
+It might also mean that your OS has a trapdoor uid/gid system :-)
+
+This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.
+
+The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.
+
+Complain to your OS vendor and ask them to fix their system.
+
+Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!
+
+<sect>Common client questions<p> <label id="client_questions">
+
+<sect1>Are there any Macintosh clients for Samba?<p> <label id="mac_clients">
+Yes! Thursby now have a CIFS Client / Server called DAVE - see <url url="http://www.thursby.com/">.
+They test it against Windows 95, Windows NT and samba for compatibility issues.
+At the time of writing, DAVE was at version 1.0.1. The 1.0.0 to 1.0.1 update is available
+as a free download from the Thursby web site (the speed of finder copies has
+been greatly enhanced, and there are bug-fixes included).
+
+Alternatives - There are two free implementations of AppleTalk for
+several kinds of UNIX machnes, and several more commercial ones.
+These products allow you to run file services and print services
+natively to Macintosh users, with no additional support required on
+the Macintosh. The two free omplementations are Netatalk,
+<url url="http://www.umich.edu/~rsug/netatalk/">, and CAP,
+<url url="http://www.cs.mu.oz.au/appletalk/atalk.html">. What Samba offers
+MS Windows users, these packages offer to Macs. For more info on
+these packages, Samba, and Linux (and other UNIX-based systems)
+see <url url="http://www.eats.com/linux_mac_win.html">
+
+<sect1>"Session request failed (131,130)" error<p> <label id="sess_req_fail">
+The following answer is provided by John E. Miller:
+
+I'll assume that you're able to ping back and forth between the
+machines by IP address and name, and that you're using some security
+model where you're confident that you've got user IDs and passwords
+right. The logging options (-d3 or greater) can help a lot with that.
+DNS and WINS configuration can also impact connectivity as well.
+
+Now, on to 'scope id's. Somewhere in your Win95 TCP/IP network
+configuration (I'm too much of an NT bigot to know where it's located
+in the Win95 setup, but I'll have to learn someday since I teach for a
+Microsoft Solution Provider Authorized Tech Education Center - what an
+acronym...) [Note: It's under Control Panel | Network | TCP/IP | WINS
+Configuration] there's a little text entry field called something like
+'Scope ID'.
+
+This field essentially creates 'invisible' sub-workgroups on the same
+wire. Boxes can only see other boxes whose Scope IDs are set to the
+exact same value - it's sometimes used by OEMs to configure their
+boxes to browse only other boxes from the same vendor and, in most
+environments, this field should be left blank. If you, in fact, have
+something in this box that EXACT value (case-sensitive!) needs to be
+provided to smbclient and nmbd as the -i (lowercase) parameter. So, if
+your Scope ID is configured as the string 'SomeStr' in Win95 then
+you'd have to use smbclient -iSomeStr [otherparms] in connecting to
+it.
+
+<sect1>How do I synchronise my PC's clock with my Samba server? <p><label id="synchronise_clock">
+To syncronize your PC's clock with your Samba server:
+<itemize>
+<item> Copy timesync.pif to your windows directory
+ <item> timesync.pif can be found at:
+ <url
+url="http://samba.org/samba/binaries/miscellaneous/timesync.pif">
+<item> Add timesync.pif to your 'Start Up' group/folder
+<item> Open the properties dialog box for the program/icon
+<item> Make sure the 'Run Minimized' option is set in program 'Properties'
+<iteM> Change the command line section that reads [\\sambahost] to reflect the name of your server.
+<item> Close the properties dialog box by choosing 'OK'
+</itemize>
+Each time you start your computer (or login for Win95) your PC will
+synchronize its clock with your Samba server.
+
+Alternativley, if you clients support Domain Logons, you can setup Domain Logons with Samba
+ - see: <url url="ftp://samba.org/pub/samba/docs/BROWSING.txt" name="BROWSING.txt"> *** for more information.
+<p>Then add
+<tscreen><verb>
+NET TIME \\%L /SET /YES
+</verb></tscreen>
+as one of the lines in the logon script.
+<sect1>Problems with WinDD, NTrigue, WinCenterPro etc<p>
+<label id="multiple_session_clients">
+
+All of the above programs are applications that sit on an NT box and
+allow multiple users to access the NT GUI applications from remote
+workstations (often over X).
+
+What has this got to do with Samba? The problem comes when these users
+use filemanager to mount shares from a Samba server. The most common
+symptom is that the first user to connect get correct file permissions
+and has a nice day, but subsequent connections get logged in as the
+same user as the first person to login. They find that they cannot
+access files in their own home directory, but that they can access
+files in the first users home directory (maybe not such a nice day
+after all?)
+
+Why does this happen? The above products all share a common heritage
+(and code base I believe). They all open just a single TCP based SMB
+connection to the Samba server, and requests from all users are piped
+over this connection. This is unfortunate, but not fatal.
+
+It means that if you run your Samba server in share level security
+(the default) then things will definately break as described
+above. The share level SMB security model has no provision for
+multiple user IDs on the one SMB connection. See <url url="ftp://samba.org/pub/samba/docs/security_level.txt" name="security_level.txt"> in
+the docs for more info on share/user/server level security.
+
+If you run in user or server level security then you have a chance,
+but only if you have a recent version of Samba (at least 1.9.15p6). In
+older versions bugs in Samba meant you still would have had problems.
+
+If you have a trapdoor uid system in your OS then it will never work
+properly. Samba needs to be able to switch uids on the connection and
+it can't if your OS has a trapdoor uid system. You'll know this
+because Samba will note it in your logs.
+
+Also note that you should not use the magic "homes" share name with
+products like these, as otherwise all users will end up with the same
+home directory. Use [\\server\username] instead.
+
+<sect1>Problem with printers under NT<p> <label id="nt_printers">
+This info from Stefan Hergeth
+hergeth@f7axp1.informatik.fh-muenchen.de may be useful:
+
+ A network-printer (with ethernetcard) is connected to the NT-Clients
+via our UNIX-Fileserver (SAMBA-Server), like the configuration told by
+ Matthew Harrell harrell@leech.nrl.navy.mil (see WinNT.txt)
+<enum>
+<item>If a user has choosen this printer as the default printer in his
+ NT-Session and this printer is not connected to the network
+ (e.g. switched off) than this user has a problem with the SAMBA-
+ connection of his filesystems. It's very slow.
+
+<item>If the printer is connected to the network everything works fine.
+
+<item>When the smbd ist started with debug level 3, you can see that the
+ NT spooling system try to connect to the printer many times. If the
+ printer ist not connected to the network this request fails and the
+ NT spooler is wasting a lot of time to connect to the printer service.
+ This seems to be the reason for the slow network connection.
+
+<item>Maybe it's possible to change this behaviour by setting different
+ printer properties in the Print-Manager-Menu of NT, but i didn't try it yet.
+</enum>
+
+<sect1>Why are my file's timestamps off by an hour, or by a few hours?<p><label id="dst_bugs">
+This is from Paul Eggert eggert@twinsun.com.
+
+Most likely it's a problem with your time zone settings.
+
+Internally, Samba maintains time in traditional Unix format,
+namely, the number of seconds since 1970-01-01 00:00:00 Universal Time
+(or ``GMT''), not counting leap seconds.
+
+On the server side, Samba uses the Unix TZ variable to convert
+internal timestamps to and from local time. So on the server side, there are
+two things to get right.
+<enum>
+<item>The Unix system clock must have the correct Universal time.
+ Use the shell command "sh -c 'TZ=UTC0 date'" to check this.
+
+<item>The TZ environment variable must be set on the server
+ before Samba is invoked. The details of this depend on the
+ server OS, but typically you must edit a file whose name is
+ /etc/TIMEZONE or /etc/default/init, or run the command `zic -l'.
+
+<item>TZ must have the correct value.
+<enum>
+ <item>If possible, use geographical time zone settings
+ (e.g. TZ='America/Los_Angeles' or perhaps
+ TZ=':US/Pacific'). These are supported by most
+ popular Unix OSes, are easier to get right, and are
+ more accurate for historical timestamps. If your
+ operating system has out-of-date tables, you should be
+ able to update them from the public domain time zone
+ tables at <url url="ftp://elsie.nci.nih.gov/pub/">.
+
+ <item>If your system does not support geographical timezone
+ settings, you must use a Posix-style TZ strings, e.g.
+ TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time.
+ Posix TZ strings can take the following form (with optional
+ items in brackets):
+<verb>
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+</verb>
+ where:
+<itemize>
+<item> `Std' is the standard time designation (e.g. `PST').
+
+<item> `Offset' is the number of hours behind UTC (e.g. `8').
+ Prepend a `-' if you are ahead of UTC, and
+ append `:30' if you are at a half-hour offset.
+ Omit all the remaining items if you do not use
+ daylight-saving time.
+
+<item> `Dst' is the daylight-saving time designation
+ (e.g. `PDT').
+
+ The optional second `Offset' is the number of
+ hours that daylight-saving time is behind UTC.
+ The default is 1 hour ahead of standard time.
+
+<item> `Date/Time,Date/Time' specify when daylight-saving
+ time starts and ends. The format for a date is
+ `Mm.n.d', which specifies the dth day (0 is Sunday)
+ of the nth week of the mth month, where week 5 means
+ the last such day in the month. The format for a
+ time is [h]h[:mm[:ss]], using a 24-hour clock.
+</itemize>
+ Other Posix string formats are allowed but you don't want
+ to know about them.
+</enum>
+</enum>
+On the client side, you must make sure that your client's clock and
+time zone is also set appropriately. [[I don't know how to do this.]]
+Samba traditionally has had many problems dealing with time zones, due
+to the bizarre ways that Microsoft network protocols handle time
+zones. A common symptom is for file timestamps to be off by an hour.
+To work around the problem, try disconnecting from your Samba server
+and then reconnecting to it; or upgrade your Samba server to
+1.9.16alpha10 or later.
+
+<sect1> How do I set the printer driver name correctly? <p><label id="printer_driver_name">
+Question:
+ On NT, I opened "Printer Manager" and "Connect to Printer".
+ Enter ["\\ptdi270\ps1"] in the box of printer. I got the
+ following error message:
+<tscreen><verb>
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+</verb></tscreen>
+Answer:
+
+In the more recent versions of Samba you can now set the "printer
+driver" in smb.conf. This tells the client what driver to use. For
+example:
+<tscreen><verb>
+ printer driver = HP LaserJet 4L
+</verb></tscreen>
+with this, NT knows to use the right driver. You have to get this string
+exactly right.
+
+To find the exact string to use, you need to get to the dialog box in
+your client where you select which printer driver to install. The
+correct strings for all the different printers are shown in a listbox
+in that dialog box.
+
+You could also try setting the driver to NULL like this:
+<tscreen><verb>
+ printer driver = NULL
+</verb></tscreen>
+this is effectively what older versions of Samba did, so if that
+worked for you then give it a go. If this does work then let us know via <htmlurl url="mailto:samba@samba.org" name="samba@samba.org">,
+and we'll make it the default. Currently the default is a 0 length
+string.
+
+<sect1>I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?<p><label id="NT_SP3_FIX">
+As of SP3, Microsoft has decided that they will no longer default to
+passing clear text passwords over the network. To enable access to
+Samba shares from NT 4.0 SP3, you must do <bf>ONE</bf> of two things:
+<enum>
+<item> Set the Samba configuration option 'security = user' and implement all of the stuff detailed in <url url="ftp://samba.org/pub/samba/docs/ENCRYPTION.txt" name="ENCRYPTION.txt">.
+<item> Follow Microsoft's directions for setting your NT box to allow plain text passwords. see <url url="http://www.microsoft.com/kb/articles/q166/7/30.htm" name="Knowledge Base Article Q166730">
+</enum>
+
+<sect>Specific client application problems<p> <label id="client_problems">
+
+<sect1>MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"<p> <label id="cant_change_properties">
+When installing MS Office on a Samba drive for which you have admin
+user permissions, ie. admin users = username, you will find the
+setup program unable to complete the installation.
+
+To get around this problem, do the installation without admin user
+permissions The problem is that MS Office Setup checks that a file is
+rdonly by trying to open it for writing.
+
+Admin users can always open a file for writing, as they run as root.
+You just have to install as a non-admin user and then use "chown -R"
+to fix the owner.
+
+<sect>Miscellaneous<p> <label id="miscellaneous">
+<sect1>Is Samba Year 2000 compliant?<p><label id="Year2000Compliant">
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.
+
+</article>
diff --git a/docs/faq/sambafaq.txt b/docs/faq/sambafaq.txt
new file mode 100644
index 00000000000..e629e8ad878
--- /dev/null
+++ b/docs/faq/sambafaq.txt
@@ -0,0 +1,1122 @@
+ Samba FAQ
+ Paul Blackman, ictinus@samba.org
+ v 0.8, June '97
+
+ This is the Frequently Asked Questions (FAQ) document for Samba, the
+ free and very popular SMB server product. An SMB server allows file
+ and printer connections from clients such as Windows, OS/2, Linux and
+ others. Current to version 1.9.17. Please send any corrections to the
+ author.
+ ______________________________________________________________________
+
+ Table of Contents:
+
+ 1. General Information
+
+ 1.1. What is Samba?
+
+ 1.2. What is the current version of Samba?
+
+ 1.3. Where can I get it?
+
+ 1.4. What do the version numbers mean?
+
+ 1.5. What platforms are supported?
+
+ 1.6. How can I find out more about Samba?
+
+ 1.7. How do I subscribe to the Samba Mailing Lists?
+
+ 1.8. Something's gone wrong - what should I do?
+
+ 1.9. Pizza supply details
+
+ 2. Compiling and installing Samba on a Unix host
+
+ 2.1. I can't see the Samba server in any browse lists!
+
+ 2.2. Some files that I KNOW are on the server doesn't show up when
+ I view the files from my client!
+
+ 2.3. Some files on the server show up with really wierd filenames
+ when I view the files from my client!
+
+ 2.4. My client reports "cannot locate specified computer" or
+ similar
+
+ 2.5. My client reports "cannot locate specified share name" or
+ similar
+
+ 2.6. My client reports "cannot find domain controller", "cannot log
+ on to the network" or similar
+
+ 2.7. Printing doesn't work :-(
+
+ 2.8. My programs install on the server OK, but refuse to work
+ properly
+
+ 2.9. My "server string" doesn't seem to be recognised
+
+ 2.10. My client reports "This server is not configured to list
+ shared resources"
+
+ 2.11. Log message "you appear to have a trapdoor uid system"
+
+ 3. Common client questions
+
+ 3.1. Are there any Macintosh clients for Samba?
+
+ 3.2. "Session request failed (131,130)" error
+
+ 3.3. How do I synchronise my PC's clock with my Samba server?
+
+ 3.4. Problems with WinDD, NTrigue, WinCenterPro etc
+
+ 3.5. Problem with printers under NT
+
+ 3.6. Why are my file's timestamps off by an hour, or by a few
+ hours?
+
+ 3.7. How do I set the printer driver name correctly?
+
+ 3.8. I've applied NT 4.0 SP3, and now I can't access Samba shares,
+ Why?
+
+ 4. Specific client application problems
+
+ 4.1. MS Office Setup reports "Cannot change properties of
+ 'MSOFFICEUP.INI'"
+
+ 5. Miscellaneous
+
+ 5.1. Is Samba Year 2000 compliant?
+ ______________________________________________________________________
+
+ 11.. GGeenneerraall IInnffoorrmmaattiioonn
+
+
+
+ All about Samba - what it is, how to get it, related sources of
+ information, how to understand the version numbering scheme, pizza
+ details
+
+
+ 11..11.. WWhhaatt iiss SSaammbbaa??
+
+
+ Samba is a suite of programs which work together to allow clients to
+ access to a server's filespace and printers via the SMB (Server
+ Message Block) protocol. Initially written for Unix, Samba now also
+ runs on Netware, OS/2 and VMS.
+
+ In practice, this means that you can redirect disks and printers to
+ Unix disks and printers from Lan Manager clients, Windows for
+ Workgroups 3.11 clients, Windows NT clients, Linux clients and OS/2
+ clients. There is also a generic Unix client program supplied as part
+ of the suite which allows Unix users to use an ftp-like interface to
+ access filespace and printers on any other SMB servers. This gives the
+ capability for these operating systems to behave much like a LAN
+ Server or Windows NT Server machine, only with added functionality and
+ flexibility designed to make life easier for administrators.
+
+ The components of the suite are (in summary):
+
+
+ +o ssmmbbdd, the SMB server. This handles actual connections from clients,
+ doing all the file, permission and username work
+
+ +o nnmmbbdd, the Netbios name server, which helps clients locate servers,
+ doing the browsing work and managing domains as this capability is
+ being built into Samba
+
+
+ +o ssmmbbcclliieenntt, the Unix-hosted client program
+
+ +o ssmmbbrruunn, a little 'glue' program to help the server run external
+ programs
+
+ +o tteessttpprrnnss, a program to test server access to printers
+
+ +o tteessttppaarrmmss, a program to test the Samba configuration file for
+ correctness
+
+ +o ssmmbb..ccoonnff, the Samba configuration file
+
+ +o ssmmbbpprriinntt, a sample script to allow a Unix host to use smbclient to
+ print to an SMB server
+
+ +o DDooccuummeennttaattiioonn!! DON'T neglect to read it - you will save a great
+ deal of time!
+
+ The suite is supplied with full source (of course!) and is GPLed.
+
+ The primary creator of the Samba suite is Andrew Tridgell. Later
+ versions incorporate much effort by many net.helpers. The man pages
+ and this FAQ were originally written by Karl Auer.
+
+
+ 11..22.. WWhhaatt iiss tthhee ccuurrrreenntt vveerrssiioonn ooff SSaammbbaa??
+
+
+ At time of writing, the current version was 1.9.17. If you want to be
+ sure check the bottom of the change-log file.
+ <ftp://samba.org/pub/samba/alpha/change-log>
+
+ For more information see ``What do the version numbers mean?''
+
+
+ 11..33.. WWhheerree ccaann II ggeett iitt??
+
+
+ The Samba suite is available via anonymous ftp from samba.org.
+ The latest and greatest versions of the suite are in the directory:
+
+ /pub/samba/
+
+ Development (read "alpha") versions, which are NOT necessarily stable
+ and which do NOT necessarily have accurate documentation, are
+ available in the directory:
+
+ /pub/samba/alpha
+
+ Note that binaries are NOT included in any of the above. Samba is
+ distributed ONLY in source form, though binaries may be available from
+ other sites. Recent versions of some Linux distributions, for example,
+ do contain Samba binaries for that platform.
+
+
+ 11..44.. WWhhaatt ddoo tthhee vveerrssiioonn nnuummbbeerrss mmeeaann??
+
+
+ It is not recommended that you run a version of Samba with the word
+ "alpha" in its name unless you know what you are doing and are willing
+ to do some debugging. Many, many people just get the latest
+ recommended stable release version and are happy. If you are brave, by
+ all means take the plunge and help with the testing and development -
+ but don't install it on your departmental server. Samba is typically
+ very stable and safe, and this is mostly due to the policy of many
+ public releases.
+ How the scheme works:
+
+ 1. When major changes are made the version number is increased. For
+ example, the transition from 1.9.15 to 1.9.16. However, this
+ version number will not appear immediately and people should
+ continue to use 1.9.15 for production systems (see next point.)
+
+ 2. Just after major changes are made the software is considered
+ unstable, and a series of alpha releases are distributed, for
+ example 1.9.16alpha1. These are for testing by those who know what
+ they are doing. The "alpha" in the filename will hopefully scare
+ off those who are just looking for the latest version to install.
+
+ 3. When Andrew thinks that the alphas have stabilised to the point
+ where he would recommend new users install it, he renames it to the
+ same version number without the alpha, for example 1.9.16.
+
+ 4. Inevitably bugs are found in the "stable" releases and minor patch
+ levels are released which give us the pXX series, for example
+ 1.9.16p2.
+
+ So the progression goes:
+
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+
+
+ The above system means that whenever someone looks at the samba ftp
+ site they will be able to grab the highest numbered release without an
+ alpha in the name and be sure of getting the current recommended ver-
+ sion.
+
+
+ 11..55.. WWhhaatt ppllaattffoorrmmss aarree ssuuppppoorrtteedd??
+
+
+ Many different platforms have run Samba successfully. The platforms
+ most widely used and thus best tested are Linux and SunOS.
+
+ At time of writing, the Makefile claimed support for:
+
+ +o A/UX 3.0
+
+ +o AIX
+
+ +o Altos Series 386/1000
+
+ +o Amiga
+
+ +o Apollo Domain/OS sr10.3
+
+ +o BSDI
+
+ +o B.O.S. (Bull Operating System)
+
+ +o Cray, Unicos 8.0
+
+ +o Convex
+
+ +o DGUX.
+
+ +o DNIX.
+
+ +o FreeBSD
+
+ +o HP-UX
+
+ +o Intergraph.
+
+ +o Linux with/without shadow passwords and quota
+
+ +o LYNX 2.3.0
+
+ +o MachTen (a unix like system for Macintoshes)
+
+ +o Motorola 88xxx/9xx range of machines
+
+ +o NetBSD
+
+ +o NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for
+ Mach).
+
+ +o OS/2 using EMX 0.9b
+
+ +o OSF1
+
+ +o QNX 4.22
+
+ +o RiscIX.
+
+ +o RISCOs 5.0B
+
+ +o SEQUENT.
+
+ +o SCO (including: 3.2v2, European dist., OpenServer 5)
+
+ +o SGI.
+
+ +o SMP_DC.OSx v1.1-94c079 on Pyramid S series
+
+ +o SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+
+ +o SUNOS 4
+
+ +o SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+
+ +o Sunsoft ISC SVR3V4
+
+ +o SVR4
+
+ +o System V with some berkely extensions (Motorola 88k R32V3.2).
+
+ +o ULTRIX.
+
+ +o UNIXWARE
+
+ +o UXP/DS
+
+
+ 11..66.. HHooww ccaann II ffiinndd oouutt mmoorree aabboouutt SSaammbbaa??
+
+
+ There are a number of places to look for more information on Samba,
+ including:
+
+ +o Two mailing lists devoted to discussion of Samba-related matters.
+
+ +o The newsgroup, comp.protocols.smb, which has a great deal of
+ discussion on Samba.
+
+ +o The WWW site 'SAMBA Web Pages' at <http://samba.edu.au/samba/>
+ includes:
+
+ +o Links to man pages and documentation, including this FAQ
+
+ +o A comprehensive survey of Samba users.
+
+ +o A searchable hypertext archive of the Samba mailing list.
+
+ +o Links to Samba source code, binaries, and mirrors of both.
+
+ +o The long list of topic documentation. These files can be found in
+ the 'docs' directory of the Samba source, or at
+ <ftp://samba.org/pub/samba/docs/>
+
+ +o Application_Serving.txt
+ <ftp://samba.org/pub/samba/docs/Application_Serving.txt>
+
+ +o BROWSING.txt <ftp://samba.org/pub/samba/docs/BROWSING.txt>
+
+ +o BUGS.txt <ftp://samba.org/pub/samba/docs/BUGS.txt>
+
+ +o DIAGNOSIS.txt <ftp://samba.org/pub/samba/docs/DIAGNOSIS.txt>
+
+ +o DNIX.txt <ftp://samba.org/pub/samba/docs/DNIX.txt>
+
+ +o DOMAIN.txt <ftp://samba.org/pub/samba/docs/DOMAIN.txt>
+
+ +o CONTROL.txt
+ <ftp://samba.org/pub/samba/docs/DOMAIN_CONTROL.txt>
+
+ +o ENCRYPTION.txt
+ <ftp://samba.org/pub/samba/docs/ENCRYPTION.txt>
+
+ +o Faxing.txt <ftp://samba.org/pub/samba/docs/Faxing.txt>
+
+ +o GOTCHAS.txt <ftp://samba.org/pub/samba/docs/GOTCHAS.txt>
+
+ +o HINTS.txt <ftp://samba.org/pub/samba/docs/HINTS.txt>
+
+ +o INSTALL.sambatar
+ <ftp://samba.org/pub/samba/docs/INSTALL.sambatar>
+
+ +o INSTALL.txt <ftp://samba.org/pub/samba/docs/INSTALL.txt>
+
+ +o MIRRORS <ftp://samba.org/pub/samba/docs/MIRRORS>
+
+ +o NetBIOS.txt <ftp://samba.org/pub/samba/docs/NetBIOS.txt>
+
+ +o OS2.txt <ftp://samba.org/pub/samba/docs/OS2.txt>
+
+ +o PROJECTS <ftp://samba.org/pub/samba/docs/PROJECTS>
+
+ +o Passwords.txt <ftp://samba.org/pub/samba/docs/Passwords.txt>
+
+ +o Printing.txt <ftp://samba.org/pub/samba/docs/Printing.txt>
+
+ +o README.DCEDFS <ftp://samba.org/pub/samba/docs/README.DCEDFS>
+
+ +o README.OS2 <ftp://samba.org/pub/samba/docs/README.OS2>
+
+ +o README.jis <ftp://samba.org/pub/samba/docs/README.jis>
+
+ +o README.sambatar
+ <ftp://samba.org/pub/samba/docs/README.sambatar>
+
+ +o SCO.txt <ftp://samba.org/pub/samba/docs/SCO.txt>
+
+ +o SMBTAR.notes <ftp://samba.org/pub/samba/docs/SMBTAR.notes>
+
+ +o Speed.txt <ftp://samba.org/pub/samba/docs/Speed.txt>
+
+ +o Support.txt <ftp://samba.org/pub/samba/docs/Support.txt>
+
+ +o THANKS <ftp://samba.org/pub/samba/docs/THANKS>
+
+ +o Tracing.txt <ftp://samba.org/pub/samba/docs/Tracing.txt>
+
+ +o SMB.txt <ftp://samba.org/pub/samba/docs/UNIX-SMB.txt>
+
+ +o Warp.txt <ftp://samba.org/pub/samba/docs/Warp.txt>
+
+ +o WinNT.txt <ftp://samba.org/pub/samba/docs/WinNT.txt>
+
+ +o history <ftp://samba.org/pub/samba/docs/history>
+
+ +o level.txt
+ <ftp://samba.org/pub/samba/docs/security_level.txt>
+
+ +o slip.htm <ftp://samba.org/pub/samba/docs/wfw_slip.htm>
+
+
+ 11..77.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.org. Make sure the subject line is
+ blank, and include the following two lines in the body of the message:
+
+
+ subscribe samba Firstname Lastname
+ subscribe samba-announce Firstname Lastname
+
+
+
+
+ Obviously you should substitute YOUR first name for "Firstname" and
+ YOUR last name for "Lastname"! Try not to send any signature stuff, it
+ sometimes confuses the list processor.
+
+ The samba list is a digest list - every eight hours or so it
+ regurgitates a single message containing all the messages that have
+ been received by the list since the last time and sends a copy of this
+ message to all subscribers.
+
+ If you stop being interested in Samba, please send another email to
+ listproc@samba.org. Make sure the subject line is blank, and
+ include the following two lines in the body of the message:
+
+
+ unsubscribe samba
+ unsubscribe samba-announce
+
+
+
+
+ The FFrroomm:: line in your message _M_U_S_T be the same address you used when
+ you subscribed.
+
+
+ 11..88.. SSoommeetthhiinngg''ss ggoonnee wwrroonngg -- wwhhaatt sshhoouulldd II ddoo??
+
+
+ ## ****** IIMMPPOORRTTAANNTT!! ****** ##
+
+ DO NOT post messages on mailing lists or in newsgroups until you have
+ carried out the first three steps given here!
+
+ Firstly, see if there are any likely looking entries in this FAQ! If
+ you have just installed Samba, have you run through the checklist in
+ DIAGNOSIS.txt <ftp://samba.org/pub/samba/DIAGNOSIS.txt>? It can
+ save you a lot of time and effort. DIAGNOSIS.txt can also be found in
+ the docs directory of the Samba distribution.
+
+ Secondly, read the man pages for smbd, nmbd and smb.conf, looking for
+ topics that relate to what you are trying to do.
+
+ Thirdly, if there is no obvious solution to hand, try to get a look at
+ the log files for smbd and/or nmbd for the period during which you
+ were having problems. You may need to reconfigure the servers to
+ provide more extensive debugging information - usually level 2 or
+ level 3 provide ample debugging info. Inspect these logs closely,
+ looking particularly for the string "Error:".
+
+ Fourthly, if you still haven't got anywhere, ask the mailing list or
+ newsgroup. In general nobody minds answering questions provided you
+ have followed the preceding steps. It might be a good idea to scan the
+ archives of the mailing list, which are available through the Samba
+ web site described in the previous section.
+
+ If you successfully solve a problem, please mail the FAQ maintainer a
+ succinct description of the symptom, the problem and the solution, so
+ I can incorporate it in the next version.
+
+ If you make changes to the source code, _please_ submit these patches
+ so that everyone else gets the benefit of your work. This is one of
+ the most important aspects to the maintainence of Samba. Send all
+ patches to samba@samba.org. Do not send patches to Andrew
+ Tridgell or any other individual, they may be lost if you do.
+
+
+ 11..99.. PPiizzzzaa ssuuppppllyy ddeettaaiillss
+
+
+ Those who have registered in the Samba survey as "Pizza Factory" will
+ already know this, but the rest may need some help. Andrew doesn't ask
+ for payment, but he does appreciate it when people give him pizza.
+ This calls for a little organisation when the pizza donor is twenty
+ thousand kilometres away, but it has been done.
+
+ Method 1: Ring up your local branch of an international pizza chain
+ and see if they honour their vouchers internationally. Pizza Hut do,
+ which is how the entire Canberra Linux Users Group got to eat pizza
+ one night, courtesy of someone in the US
+
+ Method 2: Ring up a local pizza shop in Canberra and quote a credit
+ card number for a certain amount, and tell them that Andrew will be
+ collecting it (don't forget to tell him.) One kind soul from Germany
+ did this.
+
+ Method 3: Purchase a pizza voucher from your local pizza shop that has
+ no international affiliations and send it to Andrew. It is completely
+ useless but he can hang it on the wall next to the one he already has
+ from Germany :-)
+
+
+ Method 4: Air freight him a pizza with your favourite regional
+ flavours. It will probably get stuck in customs or torn apart by
+ hungry sniffer dogs but it will have been a noble gesture.
+
+
+ 22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg SSaammbbaa oonn aa UUnniixx hhoosstt
+
+
+
+ 22..11.. II ccaann''tt sseeee tthhee SSaammbbaa sseerrvveerr iinn aannyy bbrroowwssee lliissttss!!
+
+
+ See BROWSING.txt <ftp://samba.org/pub/samba/BROWSING.txt> for
+ more information on browsing. Browsing.txt can also be found in the
+ docs directory of the Samba source.
+
+ If your GUI client does not permit you to select non-browsable
+ servers, you may need to do so on the command line. For example, under
+ Lan Manager you might connect to the above service as disk drive M:
+ thusly:
+
+
+ net use M: \\mary\fred
+
+
+
+
+ The details of how to do this and the specific syntax varies from
+ client to client - check your client's documentation.
+
+
+ 22..22.. SSoommee ffiilleess tthhaatt II KKNNOOWW aarree oonn tthhee sseerrvveerr ddooeessnn''tt sshhooww uupp wwhheenn II
+ vviieeww tthhee ffiilleess ffrroomm mmyy cclliieenntt!!
+
+
+ See the next question.
+
+ 22..33.. SSoommee ffiilleess oonn tthhee sseerrvveerr sshhooww uupp wwiitthh rreeaallllyy wwiieerrdd ffiilleennaammeess
+ wwhheenn II vviieeww tthhee ffiilleess ffrroomm mmyy cclliieenntt!!
+
+
+ If you check what files are not showing up, you will note that they
+ are files which contain upper case letters or which are otherwise not
+ DOS-compatible (ie, they are not legal DOS filenames for some reason).
+
+ The Samba server can be configured either to ignore such files
+ completely, or to present them to the client in "mangled" form. If you
+ are not seeing the files at all, the Samba server has most likely been
+ configured to ignore them. Consult the man page smb.conf(5) for
+ details of how to change this - the parameter you need to set is
+ "mangled names = yes".
+
+
+ 22..44.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott llooccaattee ssppeecciiffiieedd ccoommppuutteerr"" oorr ssiimmiillaarr
+
+
+ This indicates one of three things: You supplied an incorrect server
+ name, the underlying TCP/IP layer is not working correctly, or the
+ name you specified cannot be resolved.
+
+ After carefully checking that the name you typed is the name you
+ should have typed, try doing things like pinging a host or telnetting
+ to somewhere on your network to see if TCP/IP is functioning OK. If it
+ is, the problem is most likely name resolution.
+
+
+ If your client has a facility to do so, hardcode a mapping between the
+ hosts IP and the name you want to use. For example, with Man Manager
+ or Windows for Workgroups you would put a suitable entry in the file
+ LMHOSTS. If this works, the problem is in the communication between
+ your client and the netbios name server. If it does not work, then
+ there is something fundamental wrong with your naming and the solution
+ is beyond the scope of this document.
+
+ If you do not have any server on your subnet supplying netbios name
+ resolution, hardcoded mappings are your only option. If you DO have a
+ netbios name server running (such as the Samba suite's nmbd program),
+ the problem probably lies in the way it is set up. Refer to Section
+ Two of this FAQ for more ideas.
+
+ By the way, remember to REMOVE the hardcoded mapping before further
+ tests :-)
+
+
+ 22..55.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott llooccaattee ssppeecciiffiieedd sshhaarree nnaammee"" oorr ssiimmii--
+ llaarr
+
+
+ This message indicates that your client CAN locate the specified
+ server, which is a good start, but that it cannot find a service of
+ the name you gave.
+
+ The first step is to check the exact name of the service you are
+ trying to connect to (consult your system administrator). Assuming it
+ exists and you specified it correctly (read your client's doco on how
+ to specify a service name correctly), read on:
+
+
+ +o Many clients cannot accept or use service names longer than eight
+ characters.
+
+ +o Many clients cannot accept or use service names containing spaces.
+
+ +o Some servers (not Samba though) are case sensitive with service
+ names.
+
+ +o Some clients force service names into upper case.
+
+
+ 22..66.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott ffiinndd ddoommaaiinn ccoonnttrroolllleerr"",, ""ccaannnnoott lloogg
+ oonn ttoo tthhee nneettwwoorrkk"" oorr ssiimmiillaarr
+
+
+ Nothing is wrong - Samba does not implement the primary domain name
+ controller stuff for several reasons, including the fact that the
+ whole concept of a primary domain controller and "logging in to a
+ network" doesn't fit well with clients possibly running on multiuser
+ machines (such as users of smbclient under Unix). Having said that,
+ several developers are working hard on building it in to the next
+ major version of Samba. If you can contribute, send a message to
+ samba@samba.org !
+
+ Seeing this message should not affect your ability to mount redirected
+ disks and printers, which is really what all this is about.
+
+ For many clients (including Windows for Workgroups and Lan Manager),
+ setting the domain to STANDALONE at least gets rid of the message.
+
+
+
+
+
+ 22..77.. PPrriinnttiinngg ddooeessnn''tt wwoorrkk ::--((
+
+
+ Make sure that the specified print command for the service you are
+ connecting to is correct and that it has a fully-qualified path (eg.,
+ use "/usr/bin/lpr" rather than just "lpr").
+
+ Make sure that the spool directory specified for the service is
+ writable by the user connected to the service. In particular the user
+ "nobody" often has problems with printing, even if it worked with an
+ earlier version of Samba. Try creating another guest user other than
+ "nobody".
+
+ Make sure that the user specified in the service is permitted to use
+ the printer.
+
+ Check the debug log produced by smbd. Search for the printer name and
+ see if the log turns up any clues. Note that error messages to do with
+ a service ipc$ are meaningless - they relate to the way the client
+ attempts to retrieve status information when using the LANMAN1
+ protocol.
+
+ If using WfWg then you need to set the default protocol to TCP/IP, not
+ Netbeui. This is a WfWg bug.
+
+ If using the Lanman1 protocol (the default) then try switching to
+ coreplus. Also not that print status error messages don't mean
+ printing won't work. The print status is received by a different
+ mechanism.
+
+
+ 22..88.. MMyy pprrooggrraammss iinnssttaallll oonn tthhee sseerrvveerr OOKK,, bbuutt rreeffuussee ttoo wwoorrkk pprroopp--
+ eerrllyy
+
+
+ There are numerous possible reasons for this, but one MAJOR
+ possibility is that your software uses locking. Make sure you are
+ using Samba 1.6.11 or later. It may also be possible to work around
+ the problem by setting "locking=no" in the Samba configuration file
+ for the service the software is installed on. This should be regarded
+ as a strictly temporary solution.
+
+ In earlier Samba versions there were some difficulties with the very
+ latest Microsoft products, particularly Excel 5 and Word for Windows
+ 6. These should have all been solved. If not then please let Andrew
+ Tridgell know via email at samba@samba.org.
+
+
+ 22..99.. MMyy ""sseerrvveerr ssttrriinngg"" ddooeessnn''tt sseeeemm ttoo bbee rreeccooggnniisseedd
+
+
+ OR My client reports the default setting, eg. "Samba 1.9.15p4",
+ instead of what I have changed it to in the smb.conf file.
+
+ You need to use the -C option in nmbd. The "server string" affects
+ what smbd puts out and -C affects what nmbd puts out.
+
+ Current versions of Samba (1.9.16 +) have combined these options into
+ the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+
+ 22..1100.. MMyy cclliieenntt rreeppoorrttss ""TThhiiss sseerrvveerr iiss nnoott ccoonnffiigguurreedd ttoo lliisstt sshhaarreedd
+ rreessoouurrcceess""
+
+
+ Your guest account is probably invalid for some reason. Samba uses the
+ guest account for browsing in smbd. Check that your guest account is
+ valid.
+
+ See also 'guest account' in smb.conf man page.
+
+
+ 22..1111.. LLoogg mmeessssaaggee ""yyoouu aappppeeaarr ttoo hhaavvee aa ttrraappddoooorr uuiidd ssyysstteemm""
+
+
+ This can have several causes. It might be because you are using a uid
+ or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+ hole. Check carefully in your /etc/passwd file and make sure that no
+ user has uid 65535 or -1. Especially check the "nobody" user, as many
+ broken systems are shipped with nobody setup with a uid of 65535.
+
+ It might also mean that your OS has a trapdoor uid/gid system :-)
+
+ This means that once a process changes effective uid from root to
+ another user it can't go back to root. Unfortunately Samba relies on
+ being able to change effective uid from root to non-root and back
+ again to implement its security policy. If your OS has a trapdoor uid
+ system this won't work, and several things in Samba may break. Less
+ things will break if you use user or server level security instead of
+ the default share level security, but you may still strike problems.
+
+ The problems don't give rise to any security holes, so don't panic,
+ but it does mean some of Samba's capabilities will be unavailable. In
+ particular you will not be able to connect to the Samba server as two
+ different uids at once. This may happen if you try to print as a
+ "guest" while accessing a share as a normal user. It may also affect
+ your ability to list the available shares as this is normally done as
+ the guest user.
+
+ Complain to your OS vendor and ask them to fix their system.
+
+ Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+ it casts to -1 as a uid, and the setreuid() system call ignores (with
+ no error) uid changes to -1. This means any daemon attempting to run
+ as uid 65535 will actually run as root. This is not good!
+
+
+ 33.. CCoommmmoonn cclliieenntt qquueessttiioonnss
+
+
+
+
+ 33..11.. AArree tthheerree aannyy MMaacciinnttoosshh cclliieennttss ffoorr SSaammbbaa??
+
+
+ Yes! Thursby now have a CIFS Client / Server called DAVE - see
+ <http://www.thursby.com/>. They test it against Windows 95, Windows
+ NT and samba for compatibility issues. At the time of writing, DAVE
+ was at version 1.0.1. The 1.0.0 to 1.0.1 update is available as a free
+ download from the Thursby web site (the speed of finder copies has
+ been greatly enhanced, and there are bug-fixes included).
+
+ Alternatives - There are two free implementations of AppleTalk for
+ several kinds of UNIX machnes, and several more commercial ones.
+ These products allow you to run file services and print services
+ natively to Macintosh users, with no additional support required on
+ the Macintosh. The two free omplementations are Netatalk,
+ <http://www.umich.edu/~rsug/netatalk/>, and CAP,
+ <http://www.cs.mu.oz.au/appletalk/atalk.html>. What Samba offers MS
+ Windows users, these packages offer to Macs. For more info on these
+ packages, Samba, and Linux (and other UNIX-based systems) see
+ <http://www.eats.com/linux_mac_win.html>
+ 33..22.. SSeessssiioonn rreeqquueesstt ffaaiilleedd ((113311,,113300))"" eerrrroorr
+
+
+ The following answer is provided by John E. Miller:
+
+ I'll assume that you're able to ping back and forth between the
+ machines by IP address and name, and that you're using some security
+ model where you're confident that you've got user IDs and passwords
+ right. The logging options (-d3 or greater) can help a lot with that.
+ DNS and WINS configuration can also impact connectivity as well.
+
+ Now, on to 'scope id's. Somewhere in your Win95 TCP/IP network
+ configuration (I'm too much of an NT bigot to know where it's located
+ in the Win95 setup, but I'll have to learn someday since I teach for a
+ Microsoft Solution Provider Authorized Tech Education Center - what an
+ acronym...) Note: It's under Control Panel | Network | TCP/IP | WINS
+ Configuration there's a little text entry field called something like
+
+ This field essentially creates 'invisible' sub-workgroups on the same
+ wire. Boxes can only see other boxes whose Scope IDs are set to the
+ exact same value - it's sometimes used by OEMs to configure their
+ boxes to browse only other boxes from the same vendor and, in most
+ environments, this field should be left blank. If you, in fact, have
+ something in this box that EXACT value (case-sensitive!) needs to be
+ provided to smbclient and nmbd as the -i (lowercase) parameter. So, if
+ your Scope ID is configured as the string 'SomeStr' in Win95 then
+ you'd have to use smbclient -iSomeStr otherparms in connecting to it.
+
+
+ 33..33.. HHooww ddoo II ssyynncchhrroonniissee mmyy PPCC''ss cclloocckk wwiitthh mmyy SSaammbbaa sseerrvveerr??
+
+
+ To syncronize your PC's clock with your Samba server:
+
+ +o Copy timesync.pif to your windows directory
+
+ +o timesync.pif can be found at:
+ <http://samba.org/samba/binaries/miscellaneous/timesync.pif>
+
+ +o Add timesync.pif to your 'Start Up' group/folder
+
+ +o Open the properties dialog box for the program/icon
+
+ +o Make sure the 'Run Minimized' option is set in program 'Properties'
+
+ +o Change the command line section that reads \sambahost to reflect
+ the name of your server.
+
+ +o Close the properties dialog box by choosing 'OK'
+
+ Each time you start your computer (or login for Win95) your PC will
+ synchronize its clock with your Samba server.
+
+ Alternativley, if you clients support Domain Logons, you can setup
+ Domain Logons with Samba - see: BROWSING.txt
+ <ftp://samba.org/pub/samba/docs/BROWSING.txt> *** for more
+ information.
+
+ Then add
+
+
+ NET TIME \\%L /SET /YES
+
+
+
+
+ as one of the lines in the logon script.
+
+ 33..44.. PPrroobblleemmss wwiitthh WWiinnDDDD,, NNTTrriigguuee,, WWiinnCCeenntteerrPPrroo eettcc
+
+
+ All of the above programs are applications that sit on an NT box and
+ allow multiple users to access the NT GUI applications from remote
+ workstations (often over X).
+
+ What has this got to do with Samba? The problem comes when these users
+ use filemanager to mount shares from a Samba server. The most common
+ symptom is that the first user to connect get correct file permissions
+ and has a nice day, but subsequent connections get logged in as the
+ same user as the first person to login. They find that they cannot
+ access files in their own home directory, but that they can access
+ files in the first users home directory (maybe not such a nice day
+ after all?)
+
+ Why does this happen? The above products all share a common heritage
+ (and code base I believe). They all open just a single TCP based SMB
+ connection to the Samba server, and requests from all users are piped
+ over this connection. This is unfortunate, but not fatal.
+
+ It means that if you run your Samba server in share level security
+ (the default) then things will definately break as described above.
+ The share level SMB security model has no provision for multiple user
+ IDs on the one SMB connection. See security_level.txt
+ <ftp://samba.org/pub/samba/docs/security_level.txt> in the docs
+ for more info on share/user/server level security.
+
+ If you run in user or server level security then you have a chance,
+ but only if you have a recent version of Samba (at least 1.9.15p6). In
+ older versions bugs in Samba meant you still would have had problems.
+
+ If you have a trapdoor uid system in your OS then it will never work
+ properly. Samba needs to be able to switch uids on the connection and
+ it can't if your OS has a trapdoor uid system. You'll know this
+ because Samba will note it in your logs.
+
+ Also note that you should not use the magic "homes" share name with
+ products like these, as otherwise all users will end up with the same
+ home directory. Use \serversername instead.
+
+
+ 33..55.. PPrroobblleemm wwiitthh pprriinntteerrss uunnddeerr NNTT
+
+
+ This info from Stefan Hergeth hergeth@f7axp1.informatik.fh-muenchen.de
+ may be useful:
+
+ A network-printer (with ethernetcard) is connected to the NT-Clients
+ via our UNIX-Fileserver (SAMBA-Server), like the configuration told by
+ Matthew Harrell harrell@leech.nrl.navy.mil (see WinNT.txt)
+
+ 1. If a user has choosen this printer as the default printer in his
+ NT-Session and this printer is not connected to the network (e.g.
+ switched off) than this user has a problem with the SAMBA-
+ connection of his filesystems. It's very slow.
+
+ 2. If the printer is connected to the network everything works fine.
+
+ 3. When the smbd ist started with debug level 3, you can see that the
+ NT spooling system try to connect to the printer many times. If the
+ printer ist not connected to the network this request fails and the
+ NT spooler is wasting a lot of time to connect to the printer
+ service. This seems to be the reason for the slow network
+ connection.
+
+ 4. Maybe it's possible to change this behaviour by setting different
+ printer properties in the Print-Manager-Menu of NT, but i didn't
+ try it yet.
+
+
+ 33..66.. WWhhyy aarree mmyy ffiillee''ss ttiimmeessttaammppss ooffff bbyy aann hhoouurr,, oorr bbyy aa ffeeww hhoouurrss??
+
+
+ This is from Paul Eggert eggert@twinsun.com.
+
+ Most likely it's a problem with your time zone settings.
+
+ Internally, Samba maintains time in traditional Unix format, namely,
+ the number of seconds since 1970-01-01 00:00:00 Universal Time (or
+ ``GMT''), not counting leap seconds.
+
+ On the server side, Samba uses the Unix TZ variable to convert
+ internal timestamps to and from local time. So on the server side,
+ there are two things to get right.
+
+ 1. The Unix system clock must have the correct Universal time. Use
+ the shell command "sh -c 'TZ=UTC0 date'" to check this.
+
+ 2. The TZ environment variable must be set on the server before Samba
+ is invoked. The details of this depend on the server OS, but
+ typically you must edit a file whose name is /etc/TIMEZONE or
+ /etc/default/init, or run the command `zic -l'.
+
+ 3. TZ must have the correct value.
+
+ a. If possible, use geographical time zone settings (e.g.
+ TZ='America/Los_Angeles' or perhaps TZ=':US/Pacific'). These
+ are supported by most popular Unix OSes, are easier to get
+ right, and are more accurate for historical timestamps. If your
+ operating system has out-of-date tables, you should be able to
+ update them from the public domain time zone tables at
+ <ftp://elsie.nci.nih.gov/pub/>.
+
+ b. If your system does not support geographical timezone settings,
+ you must use a Posix-style TZ strings, e.g.
+ TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time. Posix TZ
+ strings can take the following form (with optional items in
+ brackets):
+
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+
+
+ where:
+
+ +o `Std' is the standard time designation (e.g. `PST').
+
+ +o `Offset' is the number of hours behind UTC (e.g. `8'). Prepend
+ a `-' if you are ahead of UTC, and append `:30' if you are at a
+ half-hour offset. Omit all the remaining items if you do not
+ use daylight-saving time.
+
+ +o `Dst' is the daylight-saving time designation (e.g. `PDT').
+
+ The optional second `Offset' is the number of hours that
+ daylight-saving time is behind UTC. The default is 1 hour ahead
+ of standard time.
+
+ +o `Date/Time,Date/Time' specify when daylight-saving time starts
+ and ends. The format for a date is `Mm.n.d', which specifies
+ the dth day (0 is Sunday) of the nth week of the mth month,
+ where week 5 means the last such day in the month. The format
+ for a time is hh:mm[:ss], using a 24-hour clock.
+
+ Other Posix string formats are allowed but you don't want to
+ know about them.
+
+ On the client side, you must make sure that your client's clock and
+ time zone is also set appropriately. [I don't know how to do
+ this.] Samba traditionally has had many problems dealing with time
+ zones, due to the bizarre ways that Microsoft network protocols
+ handle time zones. A common symptom is for file timestamps to be
+ off by an hour. To work around the problem, try disconnecting from
+ your Samba server and then reconnecting to it; or upgrade your
+ Samba server to 1.9.16alpha10 or later.
+
+
+ 33..77.. HHooww ddoo II sseett tthhee pprriinntteerr ddrriivveerr nnaammee ccoorrrreeccttllyy??
+
+
+ Question: On NT, I opened "Printer Manager" and "Connect to Printer".
+ Enter "\ptdi270s1"
+ in the box of printer. I got the following error message:
+
+
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+
+
+
+
+ Answer:
+
+ In the more recent versions of Samba you can now set the "printer
+ driver" in smb.conf. This tells the client what driver to use. For
+ example:
+
+
+ printer driver = HP LaserJet 4L
+
+
+
+
+ with this, NT knows to use the right driver. You have to get this
+ string exactly right.
+
+ To find the exact string to use, you need to get to the dialog box in
+ your client where you select which printer driver to install. The
+ correct strings for all the different printers are shown in a listbox
+ in that dialog box.
+
+ You could also try setting the driver to NULL like this:
+
+
+ printer driver = NULL
+
+
+
+
+ this is effectively what older versions of Samba did, so if that
+ worked for you then give it a go. If this does work then let us know
+ via samba@samba.org, and we'll make it the default. Cur-
+ rently the default is a 0 length string.
+
+
+ 33..88.. II''vvee aapppplliieedd NNTT 44..00 SSPP33,, aanndd nnooww II ccaann''tt aacccceessss SSaammbbaa sshhaarreess,,
+ WWhhyy??
+
+
+ As of SP3, Microsoft has decided that they will no longer default to
+ passing clear text passwords over the network. To enable access to
+ Samba shares from NT 4.0 SP3, you must do OONNEE of two things:
+
+ 1. Set the Samba configuration option 'security = user' and implement
+ all of the stuff detailed in ENCRYPTION.txt
+ <ftp://samba.org/pub/samba/docs/ENCRYPTION.txt>.
+
+ 2. Follow Microsoft's directions for setting your NT box to allow
+ plain text passwords. see Knowledge Base Article Q166730
+ <http://www.microsoft.com/kb/articles/q166/7/30.htm>
+
+
+ 44.. SSppeecciiffiicc cclliieenntt aapppplliiccaattiioonn pprroobblleemmss
+
+
+
+
+ 44..11.. MMSS OOffffiiccee SSeettuupp rreeppoorrttss ""CCaannnnoott cchhaannggee pprrooppeerrttiieess ooff ''MMSSOOFF--
+ FFIICCEEUUPP..IINNII''""
+
+
+ When installing MS Office on a Samba drive for which you have admin
+ user permissions, ie. admin users = username, you will find the setup
+ program unable to complete the installation.
+
+ To get around this problem, do the installation without admin user
+ permissions The problem is that MS Office Setup checks that a file is
+ rdonly by trying to open it for writing.
+
+ Admin users can always open a file for writing, as they run as root.
+ You just have to install as a non-admin user and then use "chown -R"
+ to fix the owner.
+
+
+ 55.. MMiisscceellllaanneeoouuss
+
+
+
+ 55..11.. IIss SSaammbbaa YYeeaarr 22000000 ccoommpplliiaanntt??
+
+
+ The CIFS protocol that Samba implements negotiates times in various
+ formats, all of which are able to cope with dates beyond 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/history b/docs/history
index 83761e23b86..7bcbe3564ad 100644
--- a/docs/history
+++ b/docs/history
@@ -1,8 +1,9 @@
-Note: This file is now quite out of date - but perhaps that's
-appropriate?
+Contributor: Andrew Tridgell and the Samba Team
+Date: June 27, 1997
+Satus: Always out of date! (Would not be the same without it!)
-
-=========
+Subject: A bit of history and a bit of fun
+============================================================================
This is a short history of this project. It's not supposed to be
comprehensive, just enough so that new users can get a feel for where
@@ -10,7 +11,7 @@ this project has come from and maybe where it's going to.
The whole thing really started in December 1991. I was (and still am)
a PhD student in the Computer Sciences Laboratory at the Australian
-Netional University, in Canberra, Australia. We had just got a
+National University, in Canberra, Australia. We had just got a
beta copy of eXcursion from Digital, and I was testing it on my PC. At
this stage I was a MS-DOS user, dabbling in windows.
@@ -111,7 +112,7 @@ code! I wrote back saying it was OK, but never heard from him again. I
don't know if it went on the cd-rom.
Anyway, the next big event was in December 1993, when Dan again sent
-me an e-mail saying my server had "raised it's ugly head" on
+me an e-mail saying my server had "raised its ugly head" on
comp.protocols.tcpip.ibmpc. I had a quick look on the group, and was
surprised to see that there were people interested in this thing.
@@ -163,3 +164,55 @@ support and the ability to do domain logons etc. Samba has also been
ported to OS/2, the amiga and NetWare. There are now 3000 people on
the samba mailing list.
---------------------
+
+
+---------------------
+It's now June 1997 and samba-1.9.17 is due out soon. My how time passes!
+Please refer to the WHATSNEW.txt for an update on new features. Just when
+you think you understand what is happening the ground rules change - this
+is a real world after all. Since the heady days of March 1996 there has
+been a concerted effort within the SMB protocol using community to document
+and standardize the protocols. The CIFS initiative has helped a long way
+towards creating a better understood and more interoperable environment.
+The Samba Team has grown in number and have been very active in the standards
+formation and documentation process.
+
+The net effect has been that we have had to do a lot of work to bring Samba
+into line with new features and capabilities in the SMB protocols.
+
+The past year has been a productive one with the following releases:
+ 1.9.16, 1.9.16p2, 1.9.16p6, 1.9.16p9, 1.9.16p10, 1.9.16p11
+
+There are some who believe that 1.9.15p8 was the best release and others
+who would not want to be without the latest. Whatever your perception we
+hope that 1.9.17 will close the gap and convince you all that the long
+wait and the rolling changes really were worth it. Here is functionality
+and a level of code maturity that ..., well - you can be the judge!
+
+Happy SMB networking!
+Samba Team
+
+ps: The bugs are ours, so please report any you find.
+---------------------
+
+---------------------
+It's now October 1998. We just got back from the 3rd CIFS conference
+in SanJose. The Samba Team was the biggest contingent there.
+
+Samba 2.0 should be shipping in the next few weeks with much better
+domain controller support, GUI configuration, a new user space SMB
+filesystem and lots of other neat stuff. I've also noticed that a
+search of job ads in DejaNews turned up 3900 that mention Samba. Looks
+like we've created a small industry.
+
+I've been asked again where the name Samba came from. I might as well
+put it down here for everyone to read. The code in Samba was first
+called just "server", it then got renamed "smbserver" when I
+discovered that the protocol is called SMB. Then in April 1994 I got
+an email from Syntax, the makers of "TotalNet advanced Server", a
+commercial SMB server. They told me that they had a trademark on the
+name SMBserver and I would have to change the name. I ran an egrep for
+words containing S, M, and B on /usr/dict/words and the name Samba
+looked like the best choice. Strangely enough when I repeat that now I
+notice that Samba isn't in /usr/dict/words on my system anymore!
+---------------------
diff --git a/docs/htmldocs/CVS-Access.html b/docs/htmldocs/CVS-Access.html
new file mode 100644
index 00000000000..1329433f1a1
--- /dev/null
+++ b/docs/htmldocs/CVS-Access.html
@@ -0,0 +1,193 @@
+<HTML
+><HEAD
+><TITLE
+>HOWTO Access Samba source code via CVS</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="CVS-ACCESS"
+>HOWTO Access Samba source code via CVS</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Introduction</A
+></H1
+><P
+>Samba is developed in an open environment. Developers use CVS
+(Concurrent Versioning System) to "checkin" (also known as
+"commit") new source code. Samba's various CVS branches can
+be accessed via anonymous CVS using the instructions
+detailed in this chapter.</P
+><P
+>This document is a modified version of the instructions found at
+<A
+HREF="http://samba.org/samba/cvs.html"
+TARGET="_top"
+>http://samba.org/samba/cvs.html</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN8"
+>CVS Access to samba.org</A
+></H1
+><P
+>The machine samba.org runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. There are two main ways of
+accessing the CVS server on this host.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN11"
+>Access via CVSweb</A
+></H2
+><P
+>You can access the source code via your
+favourite WWW browser. This allows you to access the contents of
+individual files in the repository and also to look at the revision
+history and commit logs of individual files. You can also ask for a diff
+listing between any two versions on the repository.</P
+><P
+>Use the URL : <A
+HREF="http://samba.org/cgi-bin/cvsweb"
+TARGET="_top"
+>http://samba.org/cgi-bin/cvsweb</A
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN16"
+>Access via cvs</A
+></H2
+><P
+>You can also access the source code via a
+normal cvs client. This gives you much more control over you can
+do with the repository and allows you to checkout whole source trees
+and keep them up to date via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.</P
+><P
+>To download the latest cvs source code, point your
+browser at the URL : <A
+HREF="http://www.cyclic.com/"
+TARGET="_top"
+>http://www.cyclic.com/</A
+>.
+and click on the 'How to get cvs' link. CVS is free software under
+the GNU GPL (as is Samba). Note that there are several graphical CVS clients
+which provide a graphical interface to the sometimes mundane CVS commands.
+Links to theses clients are also available from http://www.cyclic.com.</P
+><P
+>To gain access via anonymous cvs use the following steps.
+For this example it is assumed that you want a copy of the
+samba source code. For the other source code repositories
+on this system just substitute the correct package name</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot login</B
+>
+ </P
+><P
+> When it asks you for a password type <TT
+CLASS="USERINPUT"
+><B
+>cvs</B
+></TT
+>.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co samba</B
+>
+ </P
+><P
+> This will create a directory called samba containing the
+ latest samba source code (i.e. the HEAD tagged cvs branch). This
+ currently corresponds to the 3.0 development tree.
+ </P
+><P
+> CVS branches other HEAD can be obtained by using the <TT
+CLASS="PARAMETER"
+><I
+>-r</I
+></TT
+>
+ and defining a tag name. A list of branch tag names can be found on the
+ "Development" page of the samba web site. A common request is to obtain the
+ latest 2.2 release code. This could be done by using the following command.
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co -r SAMBA_2_2 samba</B
+>
+ </P
+></LI
+><LI
+><P
+> Whenever you want to merge in the latest code changes use
+ the following command from within the samba directory:
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs update -d -P</B
+>
+ </P
+></LI
+></OL
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/DOMAIN_MEMBER.html b/docs/htmldocs/DOMAIN_MEMBER.html
new file mode 100644
index 00000000000..b7ef4c9a61b
--- /dev/null
+++ b/docs/htmldocs/DOMAIN_MEMBER.html
@@ -0,0 +1,372 @@
+<HTML
+><HEAD
+><TITLE
+>security = domain in Samba 2.x</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="DOMAIN-SECURITY"
+>security = domain in Samba 2.x</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Joining an NT Domain with Samba 2.2</A
+></H1
+><P
+>Assume you have a Samba 2.x server with a NetBIOS name of
+ <TT
+CLASS="CONSTANT"
+>SERV1</TT
+> and are joining an NT domain called
+ <TT
+CLASS="CONSTANT"
+>DOM</TT
+>, which has a PDC with a NetBIOS name
+ of <TT
+CLASS="CONSTANT"
+>DOMPDC</TT
+> and two backup domain controllers
+ with NetBIOS names <TT
+CLASS="CONSTANT"
+>DOMBDC1</TT
+> and <TT
+CLASS="CONSTANT"
+>DOMBDC2
+ </TT
+>.</P
+><P
+>In order to join the domain, first stop all Samba daemons
+ and run the command:</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbpasswd -j DOM -r DOMPDC
+ -U<TT
+CLASS="REPLACEABLE"
+><I
+>Administrator%password</I
+></TT
+></B
+></TT
+></P
+><P
+>as we are joining the domain DOM and the PDC for that domain
+ (the only machine that has write access to the domain SAM database)
+ is DOMPDC. The <TT
+CLASS="REPLACEABLE"
+><I
+>Administrator%password</I
+></TT
+> is
+ the login name and password for an account which has the necessary
+ privilege to add machines to the domain. If this is successful
+ you will see the message:</P
+><P
+><TT
+CLASS="COMPUTEROUTPUT"
+>smbpasswd: Joined domain DOM.</TT
+>
+ </P
+><P
+>in your terminal window. See the <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+> smbpasswd(8)</A
+> man page for more details.</P
+><P
+>There is existing development code to join a domain
+ without having to create the machine trust account on the PDC
+ beforehand. This code will hopefully be available soon
+ in release branches as well.</P
+><P
+>This command goes through the machine account password
+ change protocol, then writes the new (random) machine account
+ password for this Samba server into a file in the same directory
+ in which an smbpasswd file would be stored - normally :</P
+><P
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/private</TT
+></P
+><P
+>In Samba 2.0.x, the filename looks like this:</P
+><P
+><TT
+CLASS="FILENAME"
+><TT
+CLASS="REPLACEABLE"
+><I
+>&lt;NT DOMAIN NAME&gt;</I
+></TT
+>.<TT
+CLASS="REPLACEABLE"
+><I
+>&lt;Samba
+ Server Name&gt;</I
+></TT
+>.mac</TT
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>.mac</TT
+> suffix stands for machine account
+ password file. So in our example above, the file would be called:</P
+><P
+><TT
+CLASS="FILENAME"
+>DOM.SERV1.mac</TT
+></P
+><P
+>In Samba 2.2, this file has been replaced with a TDB
+ (Trivial Database) file named <TT
+CLASS="FILENAME"
+>secrets.tdb</TT
+>.
+ </P
+><P
+>This file is created and owned by root and is not
+ readable by any other user. It is the key to the domain-level
+ security for your system, and should be treated as carefully
+ as a shadow password file.</P
+><P
+>Now, before restarting the Samba daemons you must
+ edit your <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ </A
+> file to tell Samba it should now use domain security.</P
+><P
+>Change (or add) your <A
+HREF="smb.conf.5.html#SECURITY"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>security =</I
+></TT
+></A
+> line in the [global] section
+ of your smb.conf to read:</P
+><P
+><B
+CLASS="COMMAND"
+>security = domain</B
+></P
+><P
+>Next change the <A
+HREF="smb.conf.5.html#WORKGROUP"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> workgroup =</I
+></TT
+></A
+> line in the [global] section to read: </P
+><P
+><B
+CLASS="COMMAND"
+>workgroup = DOM</B
+></P
+><P
+>as this is the name of the domain we are joining. </P
+><P
+>You must also have the parameter <A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>encrypt passwords</I
+></TT
+></A
+> set to <TT
+CLASS="CONSTANT"
+>yes
+ </TT
+> in order for your users to authenticate to the NT PDC.</P
+><P
+>Finally, add (or modify) a <A
+HREF="smb.conf.5.html#PASSWORDSERVER"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>password server =</I
+></TT
+></A
+> line in the [global]
+ section to read: </P
+><P
+><B
+CLASS="COMMAND"
+>password server = DOMPDC DOMBDC1 DOMBDC2</B
+></P
+><P
+>These are the primary and backup domain controllers Samba
+ will attempt to contact in order to authenticate users. Samba will
+ try to contact each of these servers in order, so you may want to
+ rearrange this list in order to spread out the authentication load
+ among domain controllers.</P
+><P
+>Alternatively, if you want smbd to automatically determine
+ the list of Domain controllers to use for authentication, you may
+ set this line to be :</P
+><P
+><B
+CLASS="COMMAND"
+>password server = *</B
+></P
+><P
+>This method, which was introduced in Samba 2.0.6,
+ allows Samba to use exactly the same mechanism that NT does. This
+ method either broadcasts or uses a WINS database in order to
+ find domain controllers to authenticate against.</P
+><P
+>Finally, restart your Samba daemons and get ready for
+ clients to begin using domain security!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN67"
+>Samba and Windows 2000 Domains</A
+></H1
+><P
+>Many people have asked regarding the state of Samba's ability to participate in
+a Windows 2000 Domain. Samba 2.2 is able to act as a member server of a Windows
+2000 domain operating in mixed or native mode.</P
+><P
+>There is much confusion between the circumstances that require a "mixed" mode
+Win2k DC and a when this host can be switched to "native" mode. A "mixed" mode
+Win2k domain controller is only needed if Windows NT BDCs must exist in the same
+domain. By default, a Win2k DC in "native" mode will still support
+NetBIOS and NTLMv1 for authentication of legacy clients such as Windows 9x and
+NT 4.0. Samba has the same requirements as a Windows NT 4.0 member server.</P
+><P
+>The steps for adding a Samba 2.2 host to a Win2k domain are the same as those
+for adding a Samba server to a Windows NT 4.0 domain. The only exception is that
+the "Server Manager" from NT 4 has been replaced by the "Active Directory Users and
+Computers" MMC (Microsoft Management Console) plugin.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN72"
+>Why is this better than security = server?</A
+></H1
+><P
+>Currently, domain security in Samba doesn't free you from
+ having to create local Unix users to represent the users attaching
+ to your server. This means that if domain user <TT
+CLASS="CONSTANT"
+>DOM\fred
+ </TT
+> attaches to your domain security Samba server, there needs
+ to be a local Unix user fred to represent that user in the Unix
+ filesystem. This is very similar to the older Samba security mode
+ <A
+HREF="smb.conf.5.html#SECURITYEQUALSSERVER"
+TARGET="_top"
+>security = server</A
+>,
+ where Samba would pass through the authentication request to a Windows
+ NT server in the same way as a Windows 95 or Windows 98 server would.
+ </P
+><P
+>Please refer to the <A
+HREF="winbind.html"
+TARGET="_top"
+>Winbind
+ paper</A
+> for information on a system to automatically
+ assign UNIX uids and gids to Windows NT Domain users and groups.
+ This code is available in development branches only at the moment,
+ but will be moved to release branches soon.</P
+><P
+>The advantage to domain-level security is that the
+ authentication in domain-level security is passed down the authenticated
+ RPC channel in exactly the same way that an NT server would do it. This
+ means Samba servers now participate in domain trust relationships in
+ exactly the same way NT servers do (i.e., you can add Samba servers into
+ a resource domain and have the authentication passed on from a resource
+ domain PDC to an account domain PDC.</P
+><P
+>In addition, with <B
+CLASS="COMMAND"
+>security = server</B
+> every Samba
+ daemon on a server has to keep a connection open to the
+ authenticating server for as long as that daemon lasts. This can drain
+ the connection resources on a Microsoft NT server and cause it to run
+ out of available connections. With <B
+CLASS="COMMAND"
+>security = domain</B
+>,
+ however, the Samba daemons connect to the PDC/BDC only for as long
+ as is necessary to authenticate the user, and then drop the connection,
+ thus conserving PDC connection resources.</P
+><P
+>And finally, acting in the same manner as an NT server
+ authenticating to a PDC means that as part of the authentication
+ reply, the Samba server gets the user identification information such
+ as the user SID, the list of NT groups the user belongs to, etc. All
+ this information will allow Samba to be extended in the future into
+ a mode the developers currently call appliance mode. In this mode,
+ no local Unix users will be necessary, and Samba will generate Unix
+ uids and gids from the information passed back from the PDC when a
+ user is authenticated, making a Samba server truly plug and play
+ in an NT domain environment. Watch for this code soon.</P
+><P
+><I
+CLASS="EMPHASIS"
+>NOTE:</I
+> Much of the text of this document
+ was first published in the Web magazine <A
+HREF="http://www.linuxworld.com"
+TARGET="_top"
+>
+ LinuxWorld</A
+> as the article <A
+HREF="http://www.linuxworld.com/linuxworld/lw-1998-10/lw-10-samba.html"
+TARGET="_top"
+>Doing
+ the NIS/NT Samba</A
+>.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/ENCRYPTION.html b/docs/htmldocs/ENCRYPTION.html
new file mode 100644
index 00000000000..e4d3ef5fed2
--- /dev/null
+++ b/docs/htmldocs/ENCRYPTION.html
@@ -0,0 +1,656 @@
+<HTML
+><HEAD
+><TITLE
+>LanMan and NT Password Encryption in Samba 2.x</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="PWENCRYPT"
+>LanMan and NT Password Encryption in Samba 2.x</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Introduction</A
+></H1
+><P
+>With the development of LanManager and Windows NT
+ compatible password encryption for Samba, it is now able
+ to validate user connections in exactly the same way as
+ a LanManager or Windows NT server.</P
+><P
+>This document describes how the SMB password encryption
+ algorithm works and what issues there are in choosing whether
+ you want to use it. You should read it carefully, especially
+ the part about security and the "PROS and CONS" section.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN7"
+>How does it work?</A
+></H1
+><P
+>LanManager encryption is somewhat similar to UNIX
+ password encryption. The server uses a file containing a
+ hashed value of a user's password. This is created by taking
+ the user's plaintext password, capitalising it, and either
+ truncating to 14 bytes or padding to 14 bytes with null bytes.
+ This 14 byte value is used as two 56 bit DES keys to encrypt
+ a 'magic' eight byte value, forming a 16 byte value which is
+ stored by the server and client. Let this value be known as
+ the "hashed password".</P
+><P
+>Windows NT encryption is a higher quality mechanism,
+ consisting of doing an MD4 hash on a Unicode version of the user's
+ password. This also produces a 16 byte hash value that is
+ non-reversible.</P
+><P
+>When a client (LanManager, Windows for WorkGroups, Windows
+ 95 or Windows NT) wishes to mount a Samba drive (or use a Samba
+ resource), it first requests a connection and negotiates the
+ protocol that the client and server will use. In the reply to this
+ request the Samba server generates and appends an 8 byte, random
+ value - this is stored in the Samba server after the reply is sent
+ and is known as the "challenge". The challenge is different for
+ every client connection.</P
+><P
+>The client then uses the hashed password (16 byte values
+ described above), appended with 5 null bytes, as three 56 bit
+ DES keys, each of which is used to encrypt the challenge 8 byte
+ value, forming a 24 byte value known as the "response".</P
+><P
+>In the SMB call SMBsessionsetupX (when user level security
+ is selected) or the call SMBtconX (when share level security is
+ selected), the 24 byte response is returned by the client to the
+ Samba server. For Windows NT protocol levels the above calculation
+ is done on both hashes of the user's password and both responses are
+ returned in the SMB call, giving two 24 byte values.</P
+><P
+>The Samba server then reproduces the above calculation, using
+ its own stored value of the 16 byte hashed password (read from the
+ <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+> file - described later) and the challenge
+ value that it kept from the negotiate protocol reply. It then checks
+ to see if the 24 byte value it calculates matches the 24 byte value
+ returned to it from the client.</P
+><P
+>If these values match exactly, then the client knew the
+ correct password (or the 16 byte hashed value - see security note
+ below) and is thus allowed access. If not, then the client did not
+ know the correct password and is denied access.</P
+><P
+>Note that the Samba server never knows or stores the cleartext
+ of the user's password - just the 16 byte hashed values derived from
+ it. Also note that the cleartext password or 16 byte hashed values
+ are never transmitted over the network - thus increasing security.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN18"
+>Important Notes About Security</A
+></H1
+><P
+>The unix and SMB password encryption techniques seem similar
+ on the surface. This similarity is, however, only skin deep. The unix
+ scheme typically sends clear text passwords over the network when
+ logging in. This is bad. The SMB encryption scheme never sends the
+ cleartext password over the network but it does store the 16 byte
+ hashed values on disk. This is also bad. Why? Because the 16 byte hashed
+ values are a "password equivalent". You cannot derive the user's
+ password from them, but they could potentially be used in a modified
+ client to gain access to a server. This would require considerable
+ technical knowledge on behalf of the attacker but is perfectly possible.
+ You should thus treat the smbpasswd file as though it contained the
+ cleartext passwords of all your users. Its contents must be kept
+ secret, and the file should be protected accordingly.</P
+><P
+>Ideally we would like a password scheme which neither requires
+ plain text passwords on the net or on disk. Unfortunately this
+ is not available as Samba is stuck with being compatible with
+ other SMB systems (WinNT, WfWg, Win95 etc). </P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Warning</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>Note that Windows NT 4.0 Service pack 3 changed the
+ default for permissible authentication so that plaintext
+ passwords are <I
+CLASS="EMPHASIS"
+>never</I
+> sent over the wire.
+ The solution to this is either to switch to encrypted passwords
+ with Samba or edit the Windows NT registry to re-enable plaintext
+ passwords. See the document WinNT.txt for details on how to do
+ this.</P
+><P
+>Other Microsoft operating systems which also exhibit
+ this behavior includes</P
+><P
+></P
+><UL
+><LI
+><P
+>MS DOS Network client 3.0 with
+ the basic network redirector installed</P
+></LI
+><LI
+><P
+>Windows 95 with the network redirector
+ update installed</P
+></LI
+><LI
+><P
+>Windows 98 [se]</P
+></LI
+><LI
+><P
+>Windows 2000</P
+></LI
+></UL
+><P
+><I
+CLASS="EMPHASIS"
+>Note :</I
+>All current release of
+ Microsoft SMB/CIFS clients support authentication via the
+ SMB Challenge/Response mechanism described here. Enabling
+ clear text authentication does not disable the ability
+ of the client to participate in encrypted authentication.</P
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN37"
+>Advantages of SMB Encryption</A
+></H2
+><P
+></P
+><UL
+><LI
+><P
+>plain text passwords are not passed across
+ the network. Someone using a network sniffer cannot just
+ record passwords going to the SMB server.</P
+></LI
+><LI
+><P
+>WinNT doesn't like talking to a server
+ that isn't using SMB encrypted passwords. It will refuse
+ to browse the server if the server is also in user level
+ security mode. It will insist on prompting the user for the
+ password on each connection, which is very annoying. The
+ only things you can do to stop this is to use SMB encryption.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN44"
+>Advantages of non-encrypted passwords</A
+></H2
+><P
+></P
+><UL
+><LI
+><P
+>plain text passwords are not kept
+ on disk. </P
+></LI
+><LI
+><P
+>uses same password file as other unix
+ services such as login and ftp</P
+></LI
+><LI
+><P
+>you are probably already using other
+ services (such as telnet and ftp) which send plain text
+ passwords over the net, so sending them for SMB isn't
+ such a big deal.</P
+></LI
+></UL
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN53"
+><A
+NAME="SMBPASSWDFILEFORMAT"
+></A
+>The smbpasswd file</A
+></H1
+><P
+>In order for Samba to participate in the above protocol
+ it must be able to look up the 16 byte hashed values given a user name.
+ Unfortunately, as the UNIX password value is also a one way hash
+ function (ie. it is impossible to retrieve the cleartext of the user's
+ password given the UNIX hash of it), a separate password file
+ containing this 16 byte value must be kept. To minimise problems with
+ these two password files, getting out of sync, the UNIX <TT
+CLASS="FILENAME"
+> /etc/passwd</TT
+> and the <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+> file,
+ a utility, <B
+CLASS="COMMAND"
+>mksmbpasswd.sh</B
+>, is provided to generate
+ a smbpasswd file from a UNIX <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> file.
+ </P
+><P
+>To generate the smbpasswd file from your <TT
+CLASS="FILENAME"
+>/etc/passwd
+ </TT
+> file use the following command :</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>cat /etc/passwd | mksmbpasswd.sh
+ &gt; /usr/local/samba/private/smbpasswd</B
+></TT
+></P
+><P
+>If you are running on a system that uses NIS, use</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>ypcat passwd | mksmbpasswd.sh
+ &gt; /usr/local/samba/private/smbpasswd</B
+></TT
+></P
+><P
+>The <B
+CLASS="COMMAND"
+>mksmbpasswd.sh</B
+> program is found in
+ the Samba source directory. By default, the smbpasswd file is
+ stored in :</P
+><P
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/private/smbpasswd</TT
+></P
+><P
+>The owner of the <TT
+CLASS="FILENAME"
+>/usr/local/samba/private/</TT
+>
+ directory should be set to root, and the permissions on it should
+ be set to 0500 (<B
+CLASS="COMMAND"
+>chmod 500 /usr/local/samba/private</B
+>).
+ </P
+><P
+>Likewise, the smbpasswd file inside the private directory should
+ be owned by root and the permissions on is should be set to 0600
+ (<B
+CLASS="COMMAND"
+>chmod 600 smbpasswd</B
+>).</P
+><P
+>The format of the smbpasswd file is (The line has been
+ wrapped here. It should appear as one entry per line in
+ your smbpasswd file.)</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:
+ [Account type]:LCT-&lt;last-change-time&gt;:Long name
+ </PRE
+></P
+><P
+>Although only the <TT
+CLASS="REPLACEABLE"
+><I
+>username</I
+></TT
+>,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>uid</I
+></TT
+>, <TT
+CLASS="REPLACEABLE"
+><I
+> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</I
+></TT
+>,
+ [<TT
+CLASS="REPLACEABLE"
+><I
+>Account type</I
+></TT
+>] and <TT
+CLASS="REPLACEABLE"
+><I
+> last-change-time</I
+></TT
+> sections are significant
+ and are looked at in the Samba code.</P
+><P
+>It is <I
+CLASS="EMPHASIS"
+>VITALLY</I
+> important that there by 32
+ 'X' characters between the two ':' characters in the XXX sections -
+ the smbpasswd and Samba code will fail to validate any entries that
+ do not have 32 characters between ':' characters. The first XXX
+ section is for the Lanman password hash, the second is for the
+ Windows NT version.</P
+><P
+>When the password file is created all users have password entries
+ consisting of 32 'X' characters. By default this disallows any access
+ as this user. When a user has a password set, the 'X' characters change
+ to 32 ascii hexadecimal digits (0-9, A-F). These are an ascii
+ representation of the 16 byte hashed value of a user's password.</P
+><P
+>To set a user to have no password (not recommended), edit the file
+ using vi, and replace the first 11 characters with the ascii text
+ <TT
+CLASS="CONSTANT"
+>"NO PASSWORD"</TT
+> (minus the quotes).</P
+><P
+>For example, to clear the password for user bob, his smbpasswd file
+ entry would look like :</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[U ]:LCT-00000000:Bob's full name:/bobhome:/bobshell
+ </PRE
+></P
+><P
+>If you are allowing users to use the smbpasswd command to set
+ their own passwords, you may want to give users NO PASSWORD initially
+ so they do not have to enter a previous password when changing to their
+ new password (not recommended). In order for you to allow this the
+ <B
+CLASS="COMMAND"
+>smbpasswd</B
+> program must be able to connect to the
+ <B
+CLASS="COMMAND"
+>smbd</B
+> daemon as that user with no password. Enable this
+ by adding the line :</P
+><P
+><B
+CLASS="COMMAND"
+>null passwords = yes</B
+></P
+><P
+>to the [global] section of the smb.conf file (this is why
+ the above scenario is not recommended). Preferably, allocate your
+ users a default password to begin with, so you do not have
+ to enable this on your server.</P
+><P
+><I
+CLASS="EMPHASIS"
+>Note : </I
+>This file should be protected very
+ carefully. Anyone with access to this file can (with enough knowledge of
+ the protocols) gain access to your SMB server. The file is thus more
+ sensitive than a normal unix <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> file.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN105"
+>The smbpasswd Command</A
+></H1
+><P
+>The smbpasswd command maintains the two 32 byte password fields
+ in the smbpasswd file. If you wish to make it similar to the unix
+ <B
+CLASS="COMMAND"
+>passwd</B
+> or <B
+CLASS="COMMAND"
+>yppasswd</B
+> programs,
+ install it in <TT
+CLASS="FILENAME"
+>/usr/local/samba/bin/</TT
+> (or your
+ main Samba binary directory).</P
+><P
+>Note that as of Samba 1.9.18p4 this program <I
+CLASS="EMPHASIS"
+>MUST NOT
+ BE INSTALLED</I
+> setuid root (the new <B
+CLASS="COMMAND"
+>smbpasswd</B
+>
+ code enforces this restriction so it cannot be run this way by
+ accident).</P
+><P
+><B
+CLASS="COMMAND"
+>smbpasswd</B
+> now works in a client-server mode
+ where it contacts the local smbd to change the user's password on its
+ behalf. This has enormous benefits - as follows.</P
+><P
+></P
+><UL
+><LI
+><P
+>smbpasswd no longer has to be setuid root -
+ an enormous range of potential security problems is
+ eliminated.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>smbpasswd</B
+> now has the capability
+ to change passwords on Windows NT servers (this only works when
+ the request is sent to the NT Primary Domain Controller if you
+ are changing an NT Domain user's password).</P
+></LI
+></UL
+><P
+>To run smbpasswd as a normal user just type :</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbpasswd</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>Old SMB password: </TT
+><TT
+CLASS="USERINPUT"
+><B
+>&lt;type old value here -
+ or hit return if there was no old password&gt;</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>New SMB Password: </TT
+><TT
+CLASS="USERINPUT"
+><B
+>&lt;type new value&gt;
+ </B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>Repeat New SMB Password: </TT
+><TT
+CLASS="USERINPUT"
+><B
+>&lt;re-type new value
+ </B
+></TT
+></P
+><P
+>If the old value does not match the current value stored for
+ that user, or the two new values do not match each other, then the
+ password will not be changed.</P
+><P
+>If invoked by an ordinary user it will only allow the user
+ to change his or her own Samba password.</P
+><P
+>If run by the root user smbpasswd may take an optional
+ argument, specifying the user name whose SMB password you wish to
+ change. Note that when run as root smbpasswd does not prompt for
+ or check the old password value, thus allowing root to set passwords
+ for users who have forgotten their passwords.</P
+><P
+><B
+CLASS="COMMAND"
+>smbpasswd</B
+> is designed to work in the same way
+ and be familiar to UNIX users who use the <B
+CLASS="COMMAND"
+>passwd</B
+> or
+ <B
+CLASS="COMMAND"
+>yppasswd</B
+> commands.</P
+><P
+>For more details on using <B
+CLASS="COMMAND"
+>smbpasswd</B
+> refer
+ to the man page which will always be the definitive reference.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN144"
+>Setting up Samba to support LanManager Encryption</A
+></H1
+><P
+>This is a very brief description on how to setup samba to
+ support password encryption. </P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+>compile and install samba as usual</P
+></LI
+><LI
+><P
+>enable encrypted passwords in <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> by adding the line <B
+CLASS="COMMAND"
+>encrypt
+ passwords = yes</B
+> in the [global] section</P
+></LI
+><LI
+><P
+>create the initial <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+>
+ password file in the place you specified in the Makefile
+ (--prefix=&lt;dir&gt;). See the notes under the <A
+HREF="#SMBPASSWDFILEFORMAT"
+>The smbpasswd File</A
+>
+ section earlier in the document for details.</P
+></LI
+></OL
+><P
+>Note that you can test things using smbclient.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/Integrating-with-Windows.html b/docs/htmldocs/Integrating-with-Windows.html
new file mode 100644
index 00000000000..7c5fe316272
--- /dev/null
+++ b/docs/htmldocs/Integrating-with-Windows.html
@@ -0,0 +1,1072 @@
+<HTML
+><HEAD
+><TITLE
+>Integrating MS Windows networks with Samba</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="INTEGRATE-MS-NETWORKS"
+>Integrating MS Windows networks with Samba</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Agenda</A
+></H1
+><P
+>To identify the key functional mechanisms of MS Windows networking
+to enable the deployment of Samba as a means of extending and/or
+replacing MS Windows NT/2000 technology.</P
+><P
+>We will examine:</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+>Name resolution in a pure Unix/Linux TCP/IP
+ environment
+ </P
+></LI
+><LI
+><P
+>Name resolution as used within MS Windows
+ networking
+ </P
+></LI
+><LI
+><P
+>How browsing functions and how to deploy stable
+ and dependable browsing using Samba
+ </P
+></LI
+><LI
+><P
+>MS Windows security options and how to
+ configure Samba for seemless integration
+ </P
+></LI
+><LI
+><P
+>Configuration of Samba as:</P
+><P
+></P
+><OL
+TYPE="a"
+><LI
+><P
+>A stand-alone server</P
+></LI
+><LI
+><P
+>An MS Windows NT 3.x/4.0 security domain member
+ </P
+></LI
+><LI
+><P
+>An alternative to an MS Windows NT 3.x/4.0 Domain Controller
+ </P
+></LI
+></OL
+></LI
+></OL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN25"
+>Name Resolution in a pure Unix/Linux world</A
+></H1
+><P
+>The key configuration files covered in this section are:</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+></P
+></LI
+></UL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN41"
+><TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+></A
+></H2
+><P
+>Contains a static list of IP Addresses and names.
+eg:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> 127.0.0.1 localhost localhost.localdomain
+ 192.168.1.1 bigbox.caldera.com bigbox alias4box</PRE
+></P
+><P
+>The purpose of <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> is to provide a
+name resolution mechanism so that uses do not need to remember
+IP addresses.</P
+><P
+>Network packets that are sent over the physical network transport
+layer communicate not via IP addresses but rather using the Media
+Access Control address, or MAC address. IP Addresses are currently
+32 bits in length and are typically presented as four (4) decimal
+numbers that are separated by a dot (or period). eg: 168.192.1.1</P
+><P
+>MAC Addresses use 48 bits (or 6 bytes) and are typically represented
+as two digit hexadecimal numbers separated by colons. eg:
+40:8e:0a:12:34:56</P
+><P
+>Every network interfrace must have an MAC address. Associated with
+a MAC address there may be one or more IP addresses. There is NO
+relationship between an IP address and a MAC address, all such assignments
+are arbitary or discretionary in nature. At the most basic level all
+network communications takes place using MAC addressing. Since MAC
+addresses must be globally unique, and generally remains fixed for
+any particular interface, the assignment of an IP address makes sense
+from a network management perspective. More than one IP address can
+be assigned per MAC address. One address must be the primary IP address,
+this is the address that will be returned in the ARP reply.</P
+><P
+>When a user or a process wants to communicate with another machine
+the protocol implementation ensures that the "machine name" or "host
+name" is resolved to an IP address in a manner that is controlled
+by the TCP/IP configuration control files. The file
+<TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> is one such file.</P
+><P
+>When the IP address of the destination interface has been
+determined a protocol called ARP/RARP isused to identify
+the MAC address of the target interface. ARP stands for Address
+Resolution Protocol, and is a broadcast oriented method that
+uses UDP (User Datagram Protocol) to send a request to all
+interfaces on the local network segment using the all 1's MAC
+address. Network interfaces are programmed to respond to two
+MAC addresses only; their own unique address and the address
+ff:ff:ff:ff:ff:ff. The reply packet from an ARP request will
+contain the MAC address and the primary IP address for each
+interface.</P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> file is foundational to all
+Unix/Linux TCP/IP installations and as a minumum will contain
+the localhost and local network interface IP addresses and the
+primary names by which they are known within the local machine.
+This file helps to prime the pump so that a basic level of name
+resolution can exist before any other method of name resolution
+becomes available.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN57"
+><TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></A
+></H2
+><P
+>This file tells the name resolution libraries:</P
+><P
+></P
+><UL
+><LI
+><P
+>The name of the domain to which the machine
+ belongs
+ </P
+></LI
+><LI
+><P
+>The name(s) of any domains that should be
+ automatically searched when trying to resolve unqualified
+ host names to their IP address
+ </P
+></LI
+><LI
+><P
+>The name or IP address of available Domain
+ Name Servers that may be asked to perform name to address
+ translation lookups
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN68"
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+></A
+></H2
+><P
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+> is the primary means by
+which the setting in /etc/resolv.conf may be affected. It is a
+critical configuration file. This file controls the order by
+which name resolution may procede. The typical structure is:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> order hosts,bind
+ multi on</PRE
+></P
+><P
+>then both addresses should be returned. Please refer to the
+man page for host.conf for further details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN76"
+><TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+></A
+></H2
+><P
+>This file controls the actual name resolution targets. The
+file typically has resolver object specifications as follows:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> # /etc/nsswitch.conf
+ #
+ # Name Service Switch configuration file.
+ #
+
+ passwd: compat
+ # Alternative entries for password authentication are:
+ # passwd: compat files nis ldap winbind
+ shadow: compat
+ group: compat
+
+ hosts: files nis dns
+ # Alternative entries for host name resolution are:
+ # hosts: files dns nis nis+ hesoid db compat ldap wins
+ networks: nis files dns
+
+ ethers: nis files
+ protocols: nis files
+ rpc: nis files
+ services: nis files</PRE
+></P
+><P
+>Of course, each of these mechanisms requires that the appropriate
+facilities and/or services are correctly configured.</P
+><P
+>It should be noted that unless a network request/message must be
+sent, TCP/IP networks are silent. All TCP/IP communications assumes a
+principal of speaking only when necessary.</P
+><P
+>Samba version 2.2.0 will add Linux support for extensions to
+the name service switch infrastructure so that linux clients will
+be able to obtain resolution of MS Windows NetBIOS names to IP
+Addresses. To gain this functionality Samba needs to be compiled
+with appropriate arguments to the make command (ie: <B
+CLASS="COMMAND"
+>make
+nsswitch/libnss_wins.so</B
+>). The resulting library should
+then be installed in the <TT
+CLASS="FILENAME"
+>/lib</TT
+> directory and
+the "wins" parameter needs to be added to the "hosts:" line in
+the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file. At this point it
+will be possible to ping any MS Windows machine by it's NetBIOS
+machine name, so long as that machine is within the workgroup to
+which both the samba machine and the MS Windows machine belong.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN88"
+>Name resolution as used within MS Windows networking</A
+></H1
+><P
+>MS Windows networking is predicated about the name each machine
+is given. This name is known variously (and inconsistently) as
+the "computer name", "machine name", "networking name", "netbios name",
+"SMB name". All terms mean the same thing with the exception of
+"netbios name" which can apply also to the name of the workgroup or the
+domain name. The terms "workgroup" and "domain" are really just a
+simply name with which the machine is associated. All NetBIOS names
+are exactly 16 characters in length. The 16th character is reserved.
+It is used to store a one byte value that indicates service level
+information for the NetBIOS name that is registered. A NetBIOS machine
+name is therefore registered for each service type that is provided by
+the client/server.</P
+><P
+>The following are typical NetBIOS name/service type registrations:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> Unique NetBIOS Names:
+ MACHINENAME&#60;00&#62; = Server Service is running on MACHINENAME
+ MACHINENAME&#60;03&#62; = Generic Machine Name (NetBIOS name)
+ MACHINENAME&#60;20&#62; = LanMan Server service is running on MACHINENAME
+ WORKGROUP&#60;1b&#62; = Domain Master Browser
+
+ Group Names:
+ WORKGROUP&#60;03&#62; = Generic Name registered by all members of WORKGROUP
+ WORKGROUP&#60;1c&#62; = Domain Controllers / Netlogon Servers
+ WORKGROUP&#60;1d&#62; = Local Master Browsers
+ WORKGROUP&#60;1e&#62; = Internet Name Resolvers</PRE
+></P
+><P
+>It should be noted that all NetBIOS machines register their own
+names as per the above. This is in vast contrast to TCP/IP
+installations where traditionally the system administrator will
+determine in the /etc/hosts or in the DNS database what names
+are associated with each IP address.</P
+><P
+>One further point of clarification should be noted, the <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>
+file and the DNS records do not provide the NetBIOS name type information
+that MS Windows clients depend on to locate the type of service that may
+be needed. An example of this is what happens when an MS Windows client
+wants to locate a domain logon server. It find this service and the IP
+address of a server that provides it by performing a lookup (via a
+NetBIOS broadcast) for enumeration of all machines that have
+registered the name type *&#60;1c&#62;. A logon request is then sent to each
+IP address that is returned in the enumerated list of IP addresses. Which
+ever machine first replies then ends up providing the logon services.</P
+><P
+>The name "workgroup" or "domain" really can be confusing since these
+have the added significance of indicating what is the security
+architecture of the MS Windows network. The term "workgroup" indicates
+that the primary nature of the network environment is that of a
+peer-to-peer design. In a WORKGROUP all machines are responsible for
+their own security, and generally such security is limited to use of
+just a password (known as SHARE MORE security). In most situations
+with peer-to-peer networking the users who control their own machines
+will simply opt to have no security at all. It is possible to have
+USER MODE security in a WORKGROUP environment, thus requiring use
+of a user name and a matching password.</P
+><P
+>MS Windows networking is thus predetermined to use machine names
+for all local and remote machine message passing. The protocol used is
+called Server Message Block (SMB) and this is implemented using
+the NetBIOS protocol (Network Basic Input Output System). NetBIOS can
+be encapsulated using LLC (Logical Link Control) protocol - in which case
+the resulting protocol is called NetBEUI (Network Basic Extended User
+Interface). NetBIOS can also be run over IPX (Internetworking Packet
+Exchange) protocol as used by Novell NetWare, and it can be run
+over TCP/IP protocols - in which case the resulting protocol is called
+NBT or NetBT, the NetBIOS over TCP/IP.</P
+><P
+>MS Windows machines use a complex array of name resolution mechanisms.
+Since we are primarily concerned with TCP/IP this demonstration is
+limited to this area.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN100"
+>The NetBIOS Name Cache</A
+></H2
+><P
+>All MS Windows machines employ an in memory buffer in which is
+stored the NetBIOS names and their IP addresses for all external
+machines that that the local machine has communicated with over the
+past 10-15 minutes. It is more efficient to obtain an IP address
+for a machine from the local cache than it is to go through all the
+configured name resolution mechanisms.</P
+><P
+>If a machine whose name is in the local name cache has been shut
+down before the name had been expired and flushed from the cache, then
+an attempt to exchange a message with that machine will be subject
+to time-out delays. ie: It's name is in the cache, so a name resolution
+lookup will succeed, but the machine can not respond. This can be
+frustrating for users - but it is a characteristic of the protocol.</P
+><P
+>The MS Windows utility that allows examination of the NetBIOS
+name cache is called "nbtstat". The Samba equivalent of this
+is called "nmblookup".</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN105"
+>The LMHOSTS file</A
+></H2
+><P
+>This file is usually located in MS Windows NT 4.0 or
+2000 in <TT
+CLASS="FILENAME"
+>C:\WINNT\SYSTEM32\DRIVERS\ETC</TT
+> and contains
+the IP Address and the machine name in matched pairs. The
+<TT
+CLASS="FILENAME"
+>LMHOSTS</TT
+> file performs NetBIOS name
+to IP address mapping oriented.</P
+><P
+>It typically looks like:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> # Copyright (c) 1998 Microsoft Corp.
+ #
+ # This is a sample LMHOSTS file used by the Microsoft Wins Client (NetBIOS
+ # over TCP/IP) stack for Windows98
+ #
+ # This file contains the mappings of IP addresses to NT computernames
+ # (NetBIOS) names. Each entry should be kept on an individual line.
+ # The IP address should be placed in the first column followed by the
+ # corresponding computername. The address and the comptername
+ # should be separated by at least one space or tab. The "#" character
+ # is generally used to denote the start of a comment (see the exceptions
+ # below).
+ #
+ # This file is compatible with Microsoft LAN Manager 2.x TCP/IP lmhosts
+ # files and offers the following extensions:
+ #
+ # #PRE
+ # #DOM:&lt;domain&gt;
+ # #INCLUDE &lt;filename&gt;
+ # #BEGIN_ALTERNATE
+ # #END_ALTERNATE
+ # \0xnn (non-printing character support)
+ #
+ # Following any entry in the file with the characters "#PRE" will cause
+ # the entry to be preloaded into the name cache. By default, entries are
+ # not preloaded, but are parsed only after dynamic name resolution fails.
+ #
+ # Following an entry with the "#DOM:&lt;domain&gt;" tag will associate the
+ # entry with the domain specified by &lt;domain&gt;. This affects how the
+ # browser and logon services behave in TCP/IP environments. To preload
+ # the host name associated with #DOM entry, it is necessary to also add a
+ # #PRE to the line. The &lt;domain&gt; is always preloaded although it will not
+ # be shown when the name cache is viewed.
+ #
+ # Specifying "#INCLUDE &lt;filename&gt;" will force the RFC NetBIOS (NBT)
+ # software to seek the specified &lt;filename&gt; and parse it as if it were
+ # local. &lt;filename&gt; is generally a UNC-based name, allowing a
+ # centralized lmhosts file to be maintained on a server.
+ # It is ALWAYS necessary to provide a mapping for the IP address of the
+ # server prior to the #INCLUDE. This mapping must use the #PRE directive.
+ # In addtion the share "public" in the example below must be in the
+ # LanManServer list of "NullSessionShares" in order for client machines to
+ # be able to read the lmhosts file successfully. This key is under
+ # \machine\system\currentcontrolset\services\lanmanserver\parameters\nullsessionshares
+ # in the registry. Simply add "public" to the list found there.
+ #
+ # The #BEGIN_ and #END_ALTERNATE keywords allow multiple #INCLUDE
+ # statements to be grouped together. Any single successful include
+ # will cause the group to succeed.
+ #
+ # Finally, non-printing characters can be embedded in mappings by
+ # first surrounding the NetBIOS name in quotations, then using the
+ # \0xnn notation to specify a hex value for a non-printing character.
+ #
+ # The following example illustrates all of these extensions:
+ #
+ # 102.54.94.97 rhino #PRE #DOM:networking #net group's DC
+ # 102.54.94.102 "appname \0x14" #special app server
+ # 102.54.94.123 popular #PRE #source server
+ # 102.54.94.117 localsrv #PRE #needed for the include
+ #
+ # #BEGIN_ALTERNATE
+ # #INCLUDE \\localsrv\public\lmhosts
+ # #INCLUDE \\rhino\public\lmhosts
+ # #END_ALTERNATE
+ #
+ # In the above example, the "appname" server contains a special
+ # character in its name, the "popular" and "localsrv" server names are
+ # preloaded, and the "rhino" server name is specified so it can be used
+ # to later #INCLUDE a centrally maintained lmhosts file if the "localsrv"
+ # system is unavailable.
+ #
+ # Note that the whole file is parsed including comments on each lookup,
+ # so keeping the number of comments to a minimum will improve performance.
+ # Therefore it is not advisable to simply add lmhosts file entries onto the
+ # end of this file.</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN113"
+>HOSTS file</A
+></H2
+><P
+>This file is usually located in MS Windows NT 4.0 or 2000 in
+<TT
+CLASS="FILENAME"
+>C:\WINNT\SYSTEM32\DRIVERS\ETC</TT
+> and contains
+the IP Address and the IP hostname in matched pairs. It can be
+used by the name resolution infrastructure in MS Windows, depending
+on how the TCP/IP environment is configured. This file is in
+every way the equivalent of the Unix/Linux <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> file.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN118"
+>DNS Lookup</A
+></H2
+><P
+>This capability is configured in the TCP/IP setup area in the network
+configuration facility. If enabled an elaborate name resolution sequence
+is followed the precise nature of which isdependant on what the NetBIOS
+Node Type parameter is configured to. A Node Type of 0 means use
+NetBIOS broadcast (over UDP broadcast) is first used if the name
+that is the subject of a name lookup is not found in the NetBIOS name
+cache. If that fails then DNS, HOSTS and LMHOSTS are checked. If set to
+Node Type 8, then a NetBIOS Unicast (over UDP Unicast) is sent to the
+WINS Server to obtain a lookup before DNS, HOSTS, LMHOSTS, or broadcast
+lookup is used.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN121"
+>WINS Lookup</A
+></H2
+><P
+>A WINS (Windows Internet Name Server) service is the equivaent of the
+rfc1001/1002 specified NBNS (NetBIOS Name Server). A WINS server stores
+the names and IP addresses that are registered by a Windows client
+if the TCP/IP setup has been given at least one WINS Server IP Address.</P
+><P
+>To configure Samba to be a WINS server the following parameter needs
+to be added to the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> wins support = Yes</PRE
+></P
+><P
+>To configure Samba to use a WINS server the following parameters are
+needed in the smb.conf file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> wins support = No
+ wins server = xxx.xxx.xxx.xxx</PRE
+></P
+><P
+>where <TT
+CLASS="REPLACEABLE"
+><I
+>xxx.xxx.xxx.xxx</I
+></TT
+> is the IP address
+of the WINS server.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN133"
+>How browsing functions and how to deploy stable and
+dependable browsing using Samba</A
+></H1
+><P
+>As stated above, MS Windows machines register their NetBIOS names
+(ie: the machine name for each service type in operation) on start
+up. Also, as stated above, the exact method by which this name registration
+takes place is determined by whether or not the MS Windows client/server
+has been given a WINS server address, whether or not LMHOSTS lookup
+is enabled, or if DNS for NetBIOS name resolution is enabled, etc.</P
+><P
+>In the case where there is no WINS server all name registrations as
+well as name lookups are done by UDP broadcast. This isolates name
+resolution to the local subnet, unless LMHOSTS is used to list all
+names and IP addresses. In such situations Samba provides a means by
+which the samba server name may be forcibly injected into the browse
+list of a remote MS Windows network (using the "remote announce" parameter).</P
+><P
+>Where a WINS server is used, the MS Windows client will use UDP
+unicast to register with the WINS server. Such packets can be routed
+and thus WINS allows name resolution to function across routed networks.</P
+><P
+>During the startup process an election will take place to create a
+local master browser if one does not already exist. On each NetBIOS network
+one machine will be elected to function as the domain master browser. This
+domain browsing has nothing to do with MS security domain control.
+Instead, the domain master browser serves the role of contacting each local
+master browser (found by asking WINS or from LMHOSTS) and exchanging browse
+list contents. This way every master browser will eventually obtain a complete
+list of all machines that are on the network. Every 11-15 minutes an election
+is held to determine which machine will be the master browser. By nature of
+the election criteria used, the machine with the highest uptime, or the
+most senior protocol version, or other criteria, will win the election
+as domain master browser.</P
+><P
+>Clients wishing to browse the network make use of this list, but also depend
+on the availability of correct name resolution to the respective IP
+address/addresses. </P
+><P
+>Any configuration that breaks name resolution and/or browsing intrinsics
+will annoy users because they will have to put up with protracted
+inability to use the network services.</P
+><P
+>Samba supports a feature that allows forced synchonisation
+of browse lists across routed networks using the "remote
+browse sync" parameter in the smb.conf file. This causes Samba
+to contact the local master browser on a remote network and
+to request browse list synchronisation. This effectively bridges
+two networks that are separated by routers. The two remote
+networks may use either broadcast based name resolution or WINS
+based name resolution, but it should be noted that the "remote
+browse sync" parameter provides browse list synchronisation - and
+that is distinct from name to address resolution, in other
+words, for cross subnet browsing to function correctly it is
+essential that a name to address resolution mechanism be provided.
+This mechanism could be via DNS, <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>,
+and so on.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN143"
+>MS Windows security options and how to configure
+Samba for seemless integration</A
+></H1
+><P
+>MS Windows clients may use encrypted passwords as part of a
+challenege/response authentication model (a.k.a. NTLMv1) or
+alone, or clear text strings for simple password based
+authentication. It should be realized that with the SMB
+protocol the password is passed over the network either
+in plain text or encrypted, but not both in the same
+authentication requets.</P
+><P
+>When encrypted passwords are used a password that has been
+entered by the user is encrypted in two ways:</P
+><P
+></P
+><UL
+><LI
+><P
+>An MD4 hash of the UNICODE of the password
+ string. This is known as the NT hash.
+ </P
+></LI
+><LI
+><P
+>The password is converted to upper case,
+ and then padded or trucated to 14 bytes. This string is
+ then appended with 5 bytes of NULL characters and split to
+ form two 56 bit DES keys to encrypt a "magic" 8 byte value.
+ The resulting 16 bytes for the LanMan hash.
+ </P
+></LI
+></UL
+><P
+>You should refer to the <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>Password Encryption</A
+> chapter in this HOWTO collection
+for more details on the inner workings</P
+><P
+>MS Windows 95 pre-service pack 1, MS Windows NT versions 3.x
+and version 4.0 pre-service pack 3 will use either mode of
+password authentication. All versions of MS Windows that follow
+these versions no longer support plain text passwords by default.</P
+><P
+>MS Windows clients have a habit of dropping network mappings that
+have been idle for 10 minutes or longer. When the user attempts to
+use the mapped drive connection that has been dropped the SMB protocol
+has a mechanism by which the connection can be re-established using
+a cached copy of the password.</P
+><P
+>When Microsoft changed the default password mode, they dropped support for
+caching of the plain text password. This means that when the registry
+parameter is changed to re-enable use of plain text passwords it appears to
+work, but when a dropped mapping attempts to revalidate it will fail if
+the remote authentication server does not support encrypted passwords.
+This means that it is definitely not a good idea to re-enable plain text
+password support in such clients.</P
+><P
+>The following parameters can be used to work around the
+issue of Windows 9x client upper casing usernames and
+password before transmitting them to the SMB server
+when using clear text authentication.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> <A
+HREF="smb.conf.5.html#PASSWORDLEVEL"
+TARGET="_top"
+>passsword level</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>integer</I
+></TT
+>
+ <A
+HREF="smb.conf.5.html#USERNAMELEVEL"
+TARGET="_top"
+>username level</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>integer</I
+></TT
+></PRE
+></P
+><P
+>By default Samba will lower case the username before attempting
+to lookup the user in the database of local system accounts.
+Because UNIX usernames conventionally only contain lower case
+character, the <TT
+CLASS="PARAMETER"
+><I
+>username level</I
+></TT
+> parameter
+is rarely even needed.</P
+><P
+>However, password on UNIX systems often make use of mixed case
+characters. This means that in order for a user on a Windows 9x
+client to connect to a Samba server using clear text authentication,
+the <TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+> must be set to the maximum
+number of upper case letter which <I
+CLASS="EMPHASIS"
+>could</I
+> appear
+is a password. Note that is the server OS uses the traditional
+DES version of crypt(), then a <TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+>
+of 8 will result in case insensitive passwords as seen from Windows
+users. This will also result in longer login times as Samba
+hash to compute the permutations of the password string and
+try them one by one until a match is located (or all combinations fail).</P
+><P
+>The best option to adopt is to enable support for encrypted passwords
+where ever Samba is used. There are three configuration possibilities
+for support of encrypted passwords:</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN171"
+>Use MS Windows NT as an authentication server</A
+></H2
+><P
+>This method involves the additions of the following parameters
+in the smb.conf file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> encrypt passwords = Yes
+ security = server
+ password server = "NetBIOS_name_of_PDC"</PRE
+></P
+><P
+>There are two ways of identifying whether or not a username and
+password pair was valid or not. One uses the reply information provided
+as part of the authentication messaging process, the other uses
+just and error code.</P
+><P
+>The down-side of this mode of configuration is the fact that
+for security reasons Samba will send the password server a bogus
+username and a bogus password and if the remote server fails to
+reject the username and password pair then an alternative mode
+of identification of validation is used. Where a site uses password
+lock out after a certain number of failed authentication attempts
+this will result in user lockouts.</P
+><P
+>Use of this mode of authentication does require there to be
+a standard Unix account for the user, this account can be blocked
+to prevent logons by other than MS Windows clients.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN179"
+>Make Samba a member of an MS Windows NT security domain</A
+></H2
+><P
+>This method involves additon of the following paramters in the smb.conf file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> encrypt passwords = Yes
+ security = domain
+ workgroup = "name of NT domain"
+ password server = *</PRE
+></P
+><P
+>The use of the "*" argument to "password server" will cause samba
+to locate the domain controller in a way analogous to the way
+this is done within MS Windows NT.</P
+><P
+>In order for this method to work the Samba server needs to join the
+MS Windows NT security domain. This is done as follows:</P
+><P
+></P
+><UL
+><LI
+><P
+>On the MS Windows NT domain controller using
+ the Server Manager add a machine account for the Samba server.
+ </P
+></LI
+><LI
+><P
+>Next, on the Linux system execute:
+ <B
+CLASS="COMMAND"
+>smbpasswd -r PDC_NAME -j DOMAIN_NAME</B
+>
+ </P
+></LI
+></UL
+><P
+>Use of this mode of authentication does require there to be
+a standard Unix account for the user in order to assign
+a uid once the account has been authenticated by the remote
+Windows DC. This account can be blocked to prevent logons by
+other than MS Windows clients by things such as setting an invalid
+shell in the <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry.</P
+><P
+>An alternative to assigning UIDs to Windows users on a
+Samba member server is presented in the <A
+HREF="winbind.html"
+TARGET="_top"
+>Winbind Overview</A
+> chapter in
+this HOWTO collection.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN196"
+>Configure Samba as an authentication server</A
+></H2
+><P
+>This mode of authentication demands that there be on the
+Unix/Linux system both a Unix style account as well as and
+smbpasswd entry for the user. The Unix system account can be
+locked if required as only the encrypted password will be
+used for SMB client authentication.</P
+><P
+>This method involves addition of the following parameters to
+the smb.conf file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>## please refer to the Samba PDC HOWTO chapter later in
+## this collection for more details
+[global]
+ encrypt passwords = Yes
+ security = user
+ domain logons = Yes
+ ; an OS level of 33 or more is recommended
+ os level = 33
+
+[NETLOGON]
+ path = /somewhare/in/file/system
+ read only = yes</PRE
+></P
+><P
+>in order for this method to work a Unix system account needs
+to be created for each user, as well as for each MS Windows NT/2000
+machine. The following structure is required.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN203"
+>Users</A
+></H3
+><P
+>A user account that may provide a home directory should be
+created. The following Linux system commands are typical of
+the procedure for creating an account.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> # useradd -s /bin/bash -d /home/"userid" -m "userid"
+ # passwd "userid"
+ Enter Password: &lt;pw&gt;
+
+ # smbpasswd -a "userid"
+ Enter Password: &lt;pw&gt;</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN208"
+>MS Windows NT Machine Accounts</A
+></H3
+><P
+>These are required only when Samba is used as a domain
+controller. Refer to the Samba-PDC-HOWTO for more details.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> # useradd -s /bin/false -d /dev/null "machine_name"\$
+ # passwd -l "machine_name"\$
+ # smbpasswd -a -m "machine_name"</PRE
+></P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN213"
+>Conclusions</A
+></H1
+><P
+>Samba provides a flexible means to operate as...</P
+><P
+></P
+><UL
+><LI
+><P
+>A Stand-alone server - No special action is needed
+ other than to create user accounts. Stand-alone servers do NOT
+ provide network logon services, meaning that machines that use this
+ server do NOT perform a domain logon but instead make use only of
+ the MS Windows logon which is local to the MS Windows
+ workstation/server.
+ </P
+></LI
+><LI
+><P
+>An MS Windows NT 3.x/4.0 security domain member.
+ </P
+></LI
+><LI
+><P
+>An alternative to an MS Windows NT 3.x/4.0
+ Domain Controller.
+ </P
+></LI
+></UL
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/NT_Security.html b/docs/htmldocs/NT_Security.html
new file mode 100644
index 00000000000..ab8797563e3
--- /dev/null
+++ b/docs/htmldocs/NT_Security.html
@@ -0,0 +1,783 @@
+<HTML
+><HEAD
+><TITLE
+>UNIX Permission Bits and Windows NT Access Control Lists</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="UNIX-PERMISSIONS"
+>UNIX Permission Bits and Windows NT Access Control Lists</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Viewing and changing UNIX permissions using the NT
+ security dialogs</A
+></H1
+><P
+>New in the Samba 2.0.4 release is the ability for Windows
+ NT clients to use their native security settings dialog box to
+ view and modify the underlying UNIX permissions.</P
+><P
+>Note that this ability is careful not to compromise
+ the security of the UNIX host Samba is running on, and
+ still obeys all the file permission rules that a Samba
+ administrator can set.</P
+><P
+>In Samba 2.0.4 and above the default value of the
+ parameter <A
+HREF="smb.conf.5.html#NTACLSUPPORT"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> nt acl support</I
+></TT
+></A
+> has been changed from
+ <TT
+CLASS="CONSTANT"
+>false</TT
+> to <TT
+CLASS="CONSTANT"
+>true</TT
+>, so
+ manipulation of permissions is turned on by default.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN12"
+>How to view file security on a Samba share</A
+></H1
+><P
+>From an NT 4.0 client, single-click with the right
+ mouse button on any file or directory in a Samba mounted
+ drive letter or UNC path. When the menu pops-up, click
+ on the <I
+CLASS="EMPHASIS"
+>Properties</I
+> entry at the bottom of
+ the menu. This brings up the normal file properties dialog
+ box, but with Samba 2.0.4 this will have a new tab along the top
+ marked <I
+CLASS="EMPHASIS"
+>Security</I
+>. Click on this tab and you
+ will see three buttons, <I
+CLASS="EMPHASIS"
+>Permissions</I
+>,
+ <I
+CLASS="EMPHASIS"
+>Auditing</I
+>, and <I
+CLASS="EMPHASIS"
+>Ownership</I
+>.
+ The <I
+CLASS="EMPHASIS"
+>Auditing</I
+> button will cause either
+ an error message <SPAN
+CLASS="ERRORNAME"
+>A requested privilege is not held
+ by the client</SPAN
+> to appear if the user is not the
+ NT Administrator, or a dialog which is intended to allow an
+ Administrator to add auditing requirements to a file if the
+ user is logged on as the NT Administrator. This dialog is
+ non-functional with a Samba share at this time, as the only
+ useful button, the <B
+CLASS="COMMAND"
+>Add</B
+> button will not currently
+ allow a list of users to be seen.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN23"
+>Viewing file ownership</A
+></H1
+><P
+>Clicking on the <B
+CLASS="COMMAND"
+>"Ownership"</B
+> button
+ brings up a dialog box telling you who owns the given file. The
+ owner name will be of the form :</P
+><P
+><B
+CLASS="COMMAND"
+>"SERVER\user (Long name)"</B
+></P
+><P
+>Where <TT
+CLASS="REPLACEABLE"
+><I
+>SERVER</I
+></TT
+> is the NetBIOS name of
+ the Samba server, <TT
+CLASS="REPLACEABLE"
+><I
+>user</I
+></TT
+> is the user name of
+ the UNIX user who owns the file, and <TT
+CLASS="REPLACEABLE"
+><I
+>(Long name)</I
+></TT
+>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database). Click on the <B
+CLASS="COMMAND"
+>Close
+ </B
+> button to remove this dialog.</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then the file owner will
+ be shown as the NT user <B
+CLASS="COMMAND"
+>"Everyone"</B
+>.</P
+><P
+>The <B
+CLASS="COMMAND"
+>Take Ownership</B
+> button will not allow
+ you to change the ownership of this file to yourself (clicking on
+ it will display a dialog box complaining that the user you are
+ currently logged onto the NT client cannot be found). The reason
+ for this is that changing the ownership of a file is a privileged
+ operation in UNIX, available only to the <I
+CLASS="EMPHASIS"
+>root</I
+>
+ user. As clicking on this button causes NT to attempt to change
+ the ownership of a file to the current user logged into the NT
+ client this will not work with Samba at this time.</P
+><P
+>There is an NT chown command that will work with Samba
+ and allow a user with Administrator privilege connected
+ to a Samba 2.0.4 server as root to change the ownership of
+ files on both a local NTFS filesystem or remote mounted NTFS
+ or Samba drive. This is available as part of the <I
+CLASS="EMPHASIS"
+>Seclib
+ </I
+> NT security library written by Jeremy Allison of
+ the Samba Team, available from the main Samba ftp site.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN43"
+>Viewing file or directory permissions</A
+></H1
+><P
+>The third button is the <B
+CLASS="COMMAND"
+>"Permissions"</B
+>
+ button. Clicking on this brings up a dialog box that shows both
+ the permissions and the UNIX owner of the file or directory.
+ The owner is displayed in the form :</P
+><P
+><B
+CLASS="COMMAND"
+>"SERVER\user (Long name)"</B
+></P
+><P
+>Where <TT
+CLASS="REPLACEABLE"
+><I
+>SERVER</I
+></TT
+> is the NetBIOS name of
+ the Samba server, <TT
+CLASS="REPLACEABLE"
+><I
+>user</I
+></TT
+> is the user name of
+ the UNIX user who owns the file, and <TT
+CLASS="REPLACEABLE"
+><I
+>(Long name)</I
+></TT
+>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database).</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then the file owner will
+ be shown as the NT user <B
+CLASS="COMMAND"
+>"Everyone"</B
+> and the
+ permissions will be shown as NT "Full Control".</P
+><P
+>The permissions field is displayed differently for files
+ and directories, so I'll describe the way file permissions
+ are displayed first.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN58"
+>File Permissions</A
+></H2
+><P
+>The standard UNIX user/group/world triple and
+ the corresponding "read", "write", "execute" permissions
+ triples are mapped by Samba into a three element NT ACL
+ with the 'r', 'w', and 'x' bits mapped into the corresponding
+ NT permissions. The UNIX world permissions are mapped into
+ the global NT group <B
+CLASS="COMMAND"
+>Everyone</B
+>, followed
+ by the list of permissions allowed for UNIX world. The UNIX
+ owner and group permissions are displayed as an NT
+ <B
+CLASS="COMMAND"
+>user</B
+> icon and an NT <B
+CLASS="COMMAND"
+>local
+ group</B
+> icon respectively followed by the list
+ of permissions allowed for the UNIX user and group.</P
+><P
+>As many UNIX permission sets don't map into common
+ NT names such as <B
+CLASS="COMMAND"
+>"read"</B
+>, <B
+CLASS="COMMAND"
+> "change"</B
+> or <B
+CLASS="COMMAND"
+>"full control"</B
+> then
+ usually the permissions will be prefixed by the words <B
+CLASS="COMMAND"
+> "Special Access"</B
+> in the NT display list.</P
+><P
+>But what happens if the file has no permissions allowed
+ for a particular UNIX user group or world component ? In order
+ to allow "no permissions" to be seen and modified then Samba
+ overloads the NT <B
+CLASS="COMMAND"
+>"Take Ownership"</B
+> ACL attribute
+ (which has no meaning in UNIX) and reports a component with
+ no permissions as having the NT <B
+CLASS="COMMAND"
+>"O"</B
+> bit set.
+ This was chosen of course to make it look like a zero, meaning
+ zero permissions. More details on the decision behind this will
+ be given below.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN72"
+>Directory Permissions</A
+></H2
+><P
+>Directories on an NT NTFS file system have two
+ different sets of permissions. The first set of permissions
+ is the ACL set on the directory itself, this is usually displayed
+ in the first set of parentheses in the normal <B
+CLASS="COMMAND"
+>"RW"</B
+>
+ NT style. This first set of permissions is created by Samba in
+ exactly the same way as normal file permissions are, described
+ above, and is displayed in the same way.</P
+><P
+>The second set of directory permissions has no real meaning
+ in the UNIX permissions world and represents the <B
+CLASS="COMMAND"
+> "inherited"</B
+> permissions that any file created within
+ this directory would inherit.</P
+><P
+>Samba synthesises these inherited permissions for NT by
+ returning as an NT ACL the UNIX permission mode that a new file
+ created by Samba on this share would receive.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN79"
+>Modifying file or directory permissions</A
+></H1
+><P
+>Modifying file and directory permissions is as simple
+ as changing the displayed permissions in the dialog box, and
+ clicking the <B
+CLASS="COMMAND"
+>OK</B
+> button. However, there are
+ limitations that a user needs to be aware of, and also interactions
+ with the standard Samba permission masks and mapping of DOS
+ attributes that need to also be taken into account.</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then any attempt to set
+ security permissions will fail with an <B
+CLASS="COMMAND"
+>"Access Denied"
+ </B
+> message.</P
+><P
+>The first thing to note is that the <B
+CLASS="COMMAND"
+>"Add"</B
+>
+ button will not return a list of users in Samba 2.0.4 (it will give
+ an error message of <B
+CLASS="COMMAND"
+>"The remote procedure call failed
+ and did not execute"</B
+>). This means that you can only
+ manipulate the current user/group/world permissions listed in
+ the dialog box. This actually works quite well as these are the
+ only permissions that UNIX actually has.</P
+><P
+>If a permission triple (either user, group, or world)
+ is removed from the list of permissions in the NT dialog box,
+ then when the <B
+CLASS="COMMAND"
+>"OK"</B
+> button is pressed it will
+ be applied as "no permissions" on the UNIX side. If you then
+ view the permissions again the "no permissions" entry will appear
+ as the NT <B
+CLASS="COMMAND"
+>"O"</B
+> flag, as described above. This
+ allows you to add permissions back to a file or directory once
+ you have removed them from a triple component.</P
+><P
+>As UNIX supports only the "r", "w" and "x" bits of
+ an NT ACL then if other NT security attributes such as "Delete
+ access" are selected then they will be ignored when applied on
+ the Samba server.</P
+><P
+>When setting permissions on a directory the second
+ set of permissions (in the second set of parentheses) is
+ by default applied to all files within that directory. If this
+ is not what you want you must uncheck the <B
+CLASS="COMMAND"
+>"Replace
+ permissions on existing files"</B
+> checkbox in the NT
+ dialog before clicking <B
+CLASS="COMMAND"
+>"OK"</B
+>.</P
+><P
+>If you wish to remove all permissions from a
+ user/group/world component then you may either highlight the
+ component and click the <B
+CLASS="COMMAND"
+>"Remove"</B
+> button,
+ or set the component to only have the special <B
+CLASS="COMMAND"
+>"Take
+ Ownership"</B
+> permission (displayed as <B
+CLASS="COMMAND"
+>"O"
+ </B
+>) highlighted.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN101"
+>Interaction with the standard Samba create mask
+ parameters</A
+></H1
+><P
+>Note that with Samba 2.0.5 there are four new parameters
+ to control this interaction. These are :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory security mode</I
+></TT
+></P
+><P
+>Once a user clicks <B
+CLASS="COMMAND"
+>"OK"</B
+> to apply the
+ permissions Samba maps the given permissions into a user/group/world
+ r/w/x triple set, and then will check the changed permissions for a
+ file against the bits set in the <A
+HREF="smb.conf.5.html#SECURITYMASK"
+TARGET="_top"
+>
+ <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+> parameter. Any bits that
+ were changed that are not set to '1' in this parameter are left alone
+ in the file permissions.</P
+><P
+>Essentially, zero bits in the <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+>
+ mask may be treated as a set of bits the user is <I
+CLASS="EMPHASIS"
+>not</I
+>
+ allowed to change, and one bits are those the user is allowed to change.
+ </P
+><P
+>If not set explicitly this parameter is set to the same value as
+ the <A
+HREF="smb.conf.5.html#CREATEMASK"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>create mask
+ </I
+></TT
+></A
+> parameter to provide compatibility with Samba 2.0.4
+ where this permission change facility was introduced. To allow a user to
+ modify all the user/group/world permissions on a file, set this parameter
+ to 0777.</P
+><P
+>Next Samba checks the changed permissions for a file against
+ the bits set in the <A
+HREF="smb.conf.5.html#FORCESECURITYMODE"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></A
+> parameter. Any bits
+ that were changed that correspond to bits set to '1' in this parameter
+ are forced to be set.</P
+><P
+>Essentially, bits set in the <TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+> parameter may be treated as a set of bits that, when
+ modifying security on a file, the user has always set to be 'on'.</P
+><P
+>If not set explicitly this parameter is set to the same value
+ as the <A
+HREF="smb.conf.5.html#FORCECREATEMODE"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ create mode</I
+></TT
+></A
+> parameter to provide compatibility
+ with Samba 2.0.4 where the permission change facility was introduced.
+ To allow a user to modify all the user/group/world permissions on a file
+ with no restrictions set this parameter to 000.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>force
+ security mode</I
+></TT
+> parameters are applied to the change
+ request in that order.</P
+><P
+>For a directory Samba will perform the same operations as
+ described above for a file except using the parameter <TT
+CLASS="PARAMETER"
+><I
+> directory security mask</I
+></TT
+> instead of <TT
+CLASS="PARAMETER"
+><I
+>security
+ mask</I
+></TT
+>, and <TT
+CLASS="PARAMETER"
+><I
+>force directory security mode
+ </I
+></TT
+> parameter instead of <TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+>.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+> parameter
+ by default is set to the same value as the <TT
+CLASS="PARAMETER"
+><I
+>directory mask
+ </I
+></TT
+> parameter and the <TT
+CLASS="PARAMETER"
+><I
+>force directory security
+ mode</I
+></TT
+> parameter by default is set to the same value as
+ the <TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+> parameter to provide
+ compatibility with Samba 2.0.4 where the permission change facility
+ was introduced.</P
+><P
+>In this way Samba enforces the permission restrictions that
+ an administrator can set on a Samba share, whilst still allowing users
+ to modify the permission bits within that restriction.</P
+><P
+>If you want to set up a share that allows users full control
+ in modifying the permission bits on their files and directories and
+ doesn't force any particular bits to be set 'on', then set the following
+ parameters in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+></A
+> file in that share specific section :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>security mask = 0777</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode = 0</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask = 0777</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory security mode = 0</I
+></TT
+></P
+><P
+>As described, in Samba 2.0.4 the parameters :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+></P
+><P
+>were used instead of the parameters discussed here.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN165"
+>Interaction with the standard Samba file attribute
+ mapping</A
+></H1
+><P
+>Samba maps some of the DOS attribute bits (such as "read
+ only") into the UNIX permissions of a file. This means there can
+ be a conflict between the permission bits set via the security
+ dialog and the permission bits set by the file attribute mapping.
+ </P
+><P
+>One way this can show up is if a file has no UNIX read access
+ for the owner it will show up as "read only" in the standard
+ file attributes tabbed dialog. Unfortunately this dialog is
+ the same one that contains the security info in another tab.</P
+><P
+>What this can mean is that if the owner changes the permissions
+ to allow themselves read access using the security dialog, clicks
+ <B
+CLASS="COMMAND"
+>"OK"</B
+> to get back to the standard attributes tab
+ dialog, and then clicks <B
+CLASS="COMMAND"
+>"OK"</B
+> on that dialog, then
+ NT will set the file permissions back to read-only (as that is what
+ the attributes still say in the dialog). This means that after setting
+ permissions and clicking <B
+CLASS="COMMAND"
+>"OK"</B
+> to get back to the
+ attributes dialog you should always hit <B
+CLASS="COMMAND"
+>"Cancel"</B
+>
+ rather than <B
+CLASS="COMMAND"
+>"OK"</B
+> to ensure that your changes
+ are not overridden.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/OS2-Client-HOWTO.html b/docs/htmldocs/OS2-Client-HOWTO.html
new file mode 100644
index 00000000000..90f62306e82
--- /dev/null
+++ b/docs/htmldocs/OS2-Client-HOWTO.html
@@ -0,0 +1,210 @@
+<HTML
+><HEAD
+><TITLE
+>OS2 Client HOWTO</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="OS2"
+>OS2 Client HOWTO</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>FAQs</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN5"
+>How can I configure OS/2 Warp Connect or
+ OS/2 Warp 4 as a client for Samba?</A
+></H2
+><P
+>A more complete answer to this question can be
+ found on <A
+HREF="http://carol.wins.uva.nl/~leeuw/samba/warp.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/samba/warp.html</A
+>.</P
+><P
+>Basically, you need three components:</P
+><P
+></P
+><UL
+><LI
+><P
+>The File and Print Client ('IBM Peer')
+ </P
+></LI
+><LI
+><P
+>TCP/IP ('Internet support')
+ </P
+></LI
+><LI
+><P
+>The "NetBIOS over TCP/IP" driver ('TCPBEUI')
+ </P
+></LI
+></UL
+><P
+>Installing the first two together with the base operating
+ system on a blank system is explained in the Warp manual. If Warp
+ has already been installed, but you now want to install the
+ networking support, use the "Selective Install for Networking"
+ object in the "System Setup" folder.</P
+><P
+>Adding the "NetBIOS over TCP/IP" driver is not described
+ in the manual and just barely in the online documentation. Start
+ MPTS.EXE, click on OK, click on "Configure LAPS" and click
+ on "IBM OS/2 NETBIOS OVER TCP/IP" in 'Protocols'. This line
+ is then moved to 'Current Configuration'. Select that line,
+ click on "Change number" and increase it from 0 to 1. Save this
+ configuration.</P
+><P
+>If the Samba server(s) is not on your local subnet, you
+ can optionally add IP names and addresses of these servers
+ to the "Names List", or specify a WINS server ('NetBIOS
+ Nameserver' in IBM and RFC terminology). For Warp Connect you
+ may need to download an update for 'IBM Peer' to bring it on
+ the same level as Warp 4. See the webpage mentioned above.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN20"
+>How can I configure OS/2 Warp 3 (not Connect),
+ OS/2 1.2, 1.3 or 2.x for Samba?</A
+></H2
+><P
+>You can use the free Microsoft LAN Manager 2.2c Client
+ for OS/2 from
+ <A
+HREF="ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/"
+TARGET="_top"
+> ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/</A
+>.
+ See <A
+HREF="http://carol.wins.uva.nl/~leeuw/lanman.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/lanman.html</A
+> for
+ more information on how to install and use this client. In
+ a nutshell, edit the file \OS2VER in the root directory of
+ the OS/2 boot partition and add the lines:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> 20=setup.exe
+ 20=netwksta.sys
+ 20=netvdd.sys
+ </PRE
+></P
+><P
+>before you install the client. Also, don't use the
+ included NE2000 driver because it is buggy. Try the NE2000
+ or NS2000 driver from
+ <A
+HREF="ftp://ftp.cdrom.com/pub/os2/network/ndis/"
+TARGET="_top"
+> ftp://ftp.cdrom.com/pub/os2/network/ndis/</A
+> instead.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN29"
+>Are there any other issues when OS/2 (any version)
+ is used as a client?</A
+></H2
+><P
+>When you do a NET VIEW or use the "File and Print
+ Client Resource Browser", no Samba servers show up. This can
+ be fixed by a patch from <A
+HREF="http://carol.wins.uva.nl/~leeuw/samba/fix.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/samba/fix.html</A
+>.
+ The patch will be included in a later version of Samba. It also
+ fixes a couple of other problems, such as preserving long
+ filenames when objects are dragged from the Workplace Shell
+ to the Samba server. </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN33"
+>How do I get printer driver download working
+ for OS/2 clients?</A
+></H2
+><P
+>First, create a share called [PRINTDRV] that is
+ world-readable. Copy your OS/2 driver files there. Note
+ that the .EA_ files must still be separate, so you will need
+ to use the original install files, and not copy an installed
+ driver from an OS/2 system.</P
+><P
+>Install the NT driver first for that printer. Then,
+ add to your smb.conf a parameter, "os2 driver map =
+ <TT
+CLASS="REPLACEABLE"
+><I
+>filename</I
+></TT
+>". Then, in the file
+ specified by <TT
+CLASS="REPLACEABLE"
+><I
+>filename</I
+></TT
+>, map the
+ name of the NT driver name to the OS/2 driver name as
+ follows:</P
+><P
+>&lt;nt driver name&gt; = &lt;os2 driver
+ name&gt;.&lt;device name&gt;, e.g.:
+ HP LaserJet 5L = LASERJET.HP LaserJet 5L</P
+><P
+>You can have multiple drivers mapped in this file.</P
+><P
+>If you only specify the OS/2 driver name, and not the
+ device name, the first attempt to download the driver will
+ actually download the files, but the OS/2 client will tell
+ you the driver is not available. On the second attempt, it
+ will work. This is fixed simply by adding the device name
+ to the mapping, after which it will work on the first attempt.
+ </P
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/PAM-Authentication-And-Samba.html b/docs/htmldocs/PAM-Authentication-And-Samba.html
new file mode 100644
index 00000000000..6dc815b87bf
--- /dev/null
+++ b/docs/htmldocs/PAM-Authentication-And-Samba.html
@@ -0,0 +1,318 @@
+<HTML
+><HEAD
+><TITLE
+>Configuring PAM for distributed but centrally
+managed authentication</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="PAM"
+>Configuring PAM for distributed but centrally
+managed authentication</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Samba and PAM</A
+></H1
+><P
+>A number of Unix systems (eg: Sun Solaris), as well as the
+xxxxBSD family and Linux, now utilize the Pluggable Authentication
+Modules (PAM) facility to provide all authentication,
+authorization and resource control services. Prior to the
+introduction of PAM, a decision to use an alternative to
+the system password database (<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>)
+would require the provision of alternatives for all programs that provide
+security services. Such a choice would involve provision of
+alternatives to such programs as: <B
+CLASS="COMMAND"
+>login</B
+>,
+<B
+CLASS="COMMAND"
+>passwd</B
+>, <B
+CLASS="COMMAND"
+>chown</B
+>, etc.</P
+><P
+>PAM provides a mechanism that disconnects these security programs
+from the underlying authentication/authorization infrastructure.
+PAM is configured either through one file <TT
+CLASS="FILENAME"
+>/etc/pam.conf</TT
+> (Solaris),
+or by editing individual files that are located in <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+>.</P
+><P
+>The following is an example <TT
+CLASS="FILENAME"
+>/etc/pam.d/login</TT
+> configuration file.
+This example had all options been uncommented is probably not usable
+as it stacks many conditions before allowing successful completion
+of the login process. Essentially all conditions can be disabled
+by commenting them out except the calls to <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_securetty.so
+auth required pam_nologin.so
+# auth required pam_dialup.so
+# auth optional pam_mail.so
+auth required pam_pwdb.so shadow md5
+# account requisite pam_time.so
+account required pam_pwdb.so
+session required pam_pwdb.so
+# session optional pam_lastlog.so
+# password required pam_cracklib.so retry=3
+password required pam_pwdb.so shadow md5</PRE
+></P
+><P
+>PAM allows use of replacable modules. Those available on a
+sample system include:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>$ /bin/ls /lib/security
+pam_access.so pam_ftp.so pam_limits.so
+pam_ncp_auth.so pam_rhosts_auth.so pam_stress.so
+pam_cracklib.so pam_group.so pam_listfile.so
+pam_nologin.so pam_rootok.so pam_tally.so
+pam_deny.so pam_issue.so pam_mail.so
+pam_permit.so pam_securetty.so pam_time.so
+pam_dialup.so pam_lastlog.so pam_mkhomedir.so
+pam_pwdb.so pam_shells.so pam_unix.so
+pam_env.so pam_ldap.so pam_motd.so
+pam_radius.so pam_smbpass.so pam_unix_acct.so
+pam_wheel.so pam_unix_auth.so pam_unix_passwd.so
+pam_userdb.so pam_warn.so pam_unix_session.so</PRE
+></P
+><P
+>The following example for the login program replaces the use of
+the <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+> module which uses the system
+password database (<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>,
+<TT
+CLASS="FILENAME"
+>/etc/shadow</TT
+>, <TT
+CLASS="FILENAME"
+>/etc/group</TT
+>) with
+the module <TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+> which uses the Samba
+database which contains the Microsoft MD4 encrypted password
+hashes. This database is stored in either
+<TT
+CLASS="FILENAME"
+>/usr/local/samba/private/smbpasswd</TT
+>,
+<TT
+CLASS="FILENAME"
+>/etc/samba/smbpasswd</TT
+>, or in
+<TT
+CLASS="FILENAME"
+>/etc/samba.d/smbpasswd</TT
+>, depending on the
+Samba implementation for your Unix/Linux system. The
+<TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+> module is provided by
+Samba version 2.2.1 or later. It can be compiled by specifying the
+<B
+CLASS="COMMAND"
+>--with-pam_smbpass</B
+> options when running Samba's
+<TT
+CLASS="FILENAME"
+>configure</TT
+> script. For more information
+on the <TT
+CLASS="FILENAME"
+>pam_smbpass</TT
+> module, see the documentation
+in the <TT
+CLASS="FILENAME"
+>source/pam_smbpass</TT
+> directory of the Samba
+source distribution.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_smbpass.so nodelay
+account required pam_smbpass.so nodelay
+session required pam_smbpass.so nodelay
+password required pam_smbpass.so nodelay</PRE
+></P
+><P
+>The following is the PAM configuration file for a particular
+Linux system. The default condition uses <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_pwdb.so nullok nodelay shadow audit
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_pwdb.so shadow md5</PRE
+></P
+><P
+>In the following example the decision has been made to use the
+smbpasswd database even for basic samba authentication. Such a
+decision could also be made for the passwd program and would
+thus allow the smbpasswd passwords to be changed using the passwd
+program.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_smbpass.so nodelay
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_smbpass.so nodelay smbconf=/etc/samba.d/smb.conf</PRE
+></P
+><P
+>Note: PAM allows stacking of authentication mechanisms. It is
+also possible to pass information obtained within on PAM module through
+to the next module in the PAM stack. Please refer to the documentation for
+your particular system implementation for details regarding the specific
+capabilities of PAM in this environment. Some Linux implmentations also
+provide the <TT
+CLASS="FILENAME"
+>pam_stack.so</TT
+> module that allows all
+authentication to be configured in a single central file. The
+<TT
+CLASS="FILENAME"
+>pam_stack.so</TT
+> method has some very devoted followers
+on the basis that it allows for easier administration. As with all issues in
+life though, every decision makes trade-offs, so you may want examine the
+PAM documentation for further helpful information.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN47"
+>Distributed Authentication</A
+></H1
+><P
+>The astute administrator will realize from this that the
+combination of <TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+>,
+<B
+CLASS="COMMAND"
+>winbindd</B
+>, and <B
+CLASS="COMMAND"
+>rsync</B
+> (see
+<A
+HREF="http://rsync.samba.org/"
+TARGET="_top"
+>http://rsync.samba.org/</A
+>)
+will allow the establishment of a centrally managed, distributed
+user/password database that can also be used by all
+PAM (eg: Linux) aware programs and applications. This arrangement
+can have particularly potent advantages compared with the
+use of Microsoft Active Directory Service (ADS) in so far as
+reduction of wide area network authentication traffic.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN54"
+>PAM Configuration in smb.conf</A
+></H1
+><P
+>There is an option in smb.conf called <A
+HREF="smb.conf.5.html#OBEYPAMRESTRICTIONS"
+TARGET="_top"
+>obey pam restrictions</A
+>.
+The following is from the on-line help for this option in SWAT;</P
+><P
+>When Samba 2.2 is configure to enable PAM support (i.e.
+<TT
+CLASS="CONSTANT"
+>--with-pam</TT
+>), this parameter will
+control whether or not Samba should obey PAM's account
+and session management directives. The default behavior
+is to use PAM for clear text authentication only and to
+ignore any account or session management. Note that Samba always
+ignores PAM for authentication in the case of
+<A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+>encrypt passwords = yes</A
+>.
+The reason is that PAM modules cannot support the challenge/response
+authentication mechanism needed in the presence of SMB
+password encryption. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>obey pam restrictions = no</B
+></P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/Samba-HOWTO-Collection.html b/docs/htmldocs/Samba-HOWTO-Collection.html
new file mode 100644
index 00000000000..db3c6598df8
--- /dev/null
+++ b/docs/htmldocs/Samba-HOWTO-Collection.html
@@ -0,0 +1,9612 @@
+<HTML
+><HEAD
+><TITLE
+>SAMBA Project Documentation</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="BOOK"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="BOOK"
+><A
+NAME="SAMBA-PROJECT-DOCUMENTATION"
+></A
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="SAMBA-PROJECT-DOCUMENTATION"
+>SAMBA Project Documentation</A
+></H1
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN4"
+>SAMBA Team</A
+></H3
+><HR></DIV
+><HR><H1
+><A
+NAME="AEN8"
+>Abstract</A
+></H1
+><P
+><EM
+>Last Update</EM
+> : Tue Jul 31 15:58:03 CDT 2001</P
+><P
+>This book is a collection of HOWTOs added to Samba documentation over the years.
+I try to ensure that all are current, but sometimes the is a larger job
+than one person can maintain. The most recent version of this document
+can be found at <A
+HREF="http://www.samba.org/"
+TARGET="_top"
+>http://www.samba.org/</A
+>
+on the "Documentation" page. Please send updates to <A
+HREF="mailto:jerry@samba.org"
+TARGET="_top"
+>jerry@samba.org</A
+>.</P
+><P
+>Cheers, jerry</P
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+>1. <A
+HREF="#INSTALL"
+>How to Install and Test SAMBA</A
+></DT
+><DD
+><DL
+><DT
+>1.1. <A
+HREF="#AEN18"
+>Step 0: Read the man pages</A
+></DT
+><DT
+>1.2. <A
+HREF="#AEN26"
+>Step 1: Building the Binaries</A
+></DT
+><DT
+>1.3. <A
+HREF="#AEN54"
+>Step 2: The all important step</A
+></DT
+><DT
+>1.4. <A
+HREF="#AEN58"
+>Step 3: Create the smb configuration file.</A
+></DT
+><DT
+>1.5. <A
+HREF="#AEN72"
+>Step 4: Test your config file with
+ <B
+CLASS="COMMAND"
+>testparm</B
+></A
+></DT
+><DT
+>1.6. <A
+HREF="#AEN78"
+>Step 5: Starting the smbd and nmbd</A
+></DT
+><DD
+><DL
+><DT
+>1.6.1. <A
+HREF="#AEN88"
+>Step 5a: Starting from inetd.conf</A
+></DT
+><DT
+>1.6.2. <A
+HREF="#AEN117"
+>Step 5b. Alternative: starting it as a daemon</A
+></DT
+></DL
+></DD
+><DT
+>1.7. <A
+HREF="#AEN133"
+>Step 6: Try listing the shares available on your
+ server</A
+></DT
+><DT
+>1.8. <A
+HREF="#AEN142"
+>Step 7: Try connecting with the unix client</A
+></DT
+><DT
+>1.9. <A
+HREF="#AEN158"
+>Step 8: Try connecting from a DOS, WfWg, Win9x, WinNT,
+ Win2k, OS/2, etc... client</A
+></DT
+><DT
+>1.10. <A
+HREF="#AEN172"
+>What If Things Don't Work?</A
+></DT
+><DD
+><DL
+><DT
+>1.10.1. <A
+HREF="#AEN177"
+>Diagnosing Problems</A
+></DT
+><DT
+>1.10.2. <A
+HREF="#AEN181"
+>Scope IDs</A
+></DT
+><DT
+>1.10.3. <A
+HREF="#AEN184"
+>Choosing the Protocol Level</A
+></DT
+><DT
+>1.10.4. <A
+HREF="#AEN193"
+>Printing from UNIX to a Client PC</A
+></DT
+><DT
+>1.10.5. <A
+HREF="#AEN197"
+>Locking</A
+></DT
+><DT
+>1.10.6. <A
+HREF="#AEN207"
+>Mapping Usernames</A
+></DT
+><DT
+>1.10.7. <A
+HREF="#AEN210"
+>Other Character Sets</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>2. <A
+HREF="#INTEGRATE-MS-NETWORKS"
+>Integrating MS Windows networks with Samba</A
+></DT
+><DD
+><DL
+><DT
+>2.1. <A
+HREF="#AEN224"
+>Agenda</A
+></DT
+><DT
+>2.2. <A
+HREF="#AEN246"
+>Name Resolution in a pure Unix/Linux world</A
+></DT
+><DD
+><DL
+><DT
+>2.2.1. <A
+HREF="#AEN262"
+><TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+></A
+></DT
+><DT
+>2.2.2. <A
+HREF="#AEN278"
+><TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></A
+></DT
+><DT
+>2.2.3. <A
+HREF="#AEN289"
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+></A
+></DT
+><DT
+>2.2.4. <A
+HREF="#AEN297"
+><TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+></A
+></DT
+></DL
+></DD
+><DT
+>2.3. <A
+HREF="#AEN309"
+>Name resolution as used within MS Windows networking</A
+></DT
+><DD
+><DL
+><DT
+>2.3.1. <A
+HREF="#AEN321"
+>The NetBIOS Name Cache</A
+></DT
+><DT
+>2.3.2. <A
+HREF="#AEN326"
+>The LMHOSTS file</A
+></DT
+><DT
+>2.3.3. <A
+HREF="#AEN334"
+>HOSTS file</A
+></DT
+><DT
+>2.3.4. <A
+HREF="#AEN339"
+>DNS Lookup</A
+></DT
+><DT
+>2.3.5. <A
+HREF="#AEN342"
+>WINS Lookup</A
+></DT
+></DL
+></DD
+><DT
+>2.4. <A
+HREF="#AEN354"
+>How browsing functions and how to deploy stable and
+dependable browsing using Samba</A
+></DT
+><DT
+>2.5. <A
+HREF="#AEN364"
+>MS Windows security options and how to configure
+Samba for seemless integration</A
+></DT
+><DD
+><DL
+><DT
+>2.5.1. <A
+HREF="#AEN392"
+>Use MS Windows NT as an authentication server</A
+></DT
+><DT
+>2.5.2. <A
+HREF="#AEN400"
+>Make Samba a member of an MS Windows NT security domain</A
+></DT
+><DT
+>2.5.3. <A
+HREF="#AEN417"
+>Configure Samba as an authentication server</A
+></DT
+><DD
+><DL
+><DT
+>2.5.3.1. <A
+HREF="#AEN424"
+>Users</A
+></DT
+><DT
+>2.5.3.2. <A
+HREF="#AEN429"
+>MS Windows NT Machine Accounts</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>2.6. <A
+HREF="#AEN434"
+>Conclusions</A
+></DT
+></DL
+></DD
+><DT
+>3. <A
+HREF="#PAM"
+>Configuring PAM for distributed but centrally
+managed authentication</A
+></DT
+><DD
+><DL
+><DT
+>3.1. <A
+HREF="#AEN455"
+>Samba and PAM</A
+></DT
+><DT
+>3.2. <A
+HREF="#AEN499"
+>Distributed Authentication</A
+></DT
+><DT
+>3.3. <A
+HREF="#AEN506"
+>PAM Configuration in smb.conf</A
+></DT
+></DL
+></DD
+><DT
+>4. <A
+HREF="#MSDFS"
+>Hosting a Microsoft Distributed File System tree on Samba</A
+></DT
+><DD
+><DL
+><DT
+>4.1. <A
+HREF="#AEN526"
+>Instructions</A
+></DT
+><DD
+><DL
+><DT
+>4.1.1. <A
+HREF="#AEN561"
+>Notes</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>5. <A
+HREF="#UNIX-PERMISSIONS"
+>UNIX Permission Bits and Windows NT Access Control Lists</A
+></DT
+><DD
+><DL
+><DT
+>5.1. <A
+HREF="#AEN581"
+>Viewing and changing UNIX permissions using the NT
+ security dialogs</A
+></DT
+><DT
+>5.2. <A
+HREF="#AEN590"
+>How to view file security on a Samba share</A
+></DT
+><DT
+>5.3. <A
+HREF="#AEN601"
+>Viewing file ownership</A
+></DT
+><DT
+>5.4. <A
+HREF="#AEN621"
+>Viewing file or directory permissions</A
+></DT
+><DD
+><DL
+><DT
+>5.4.1. <A
+HREF="#AEN636"
+>File Permissions</A
+></DT
+><DT
+>5.4.2. <A
+HREF="#AEN650"
+>Directory Permissions</A
+></DT
+></DL
+></DD
+><DT
+>5.5. <A
+HREF="#AEN657"
+>Modifying file or directory permissions</A
+></DT
+><DT
+>5.6. <A
+HREF="#AEN679"
+>Interaction with the standard Samba create mask
+ parameters</A
+></DT
+><DT
+>5.7. <A
+HREF="#AEN743"
+>Interaction with the standard Samba file attribute
+ mapping</A
+></DT
+></DL
+></DD
+><DT
+>6. <A
+HREF="#PRINTING"
+>Printing Support in Samba 2.2.x</A
+></DT
+><DD
+><DL
+><DT
+>6.1. <A
+HREF="#AEN764"
+>Introduction</A
+></DT
+><DT
+>6.2. <A
+HREF="#AEN786"
+>Configuration</A
+></DT
+><DD
+><DL
+><DT
+>6.2.1. <A
+HREF="#AEN797"
+>Creating [print$]</A
+></DT
+><DT
+>6.2.2. <A
+HREF="#AEN832"
+>Setting Drivers for Existing Printers</A
+></DT
+><DT
+>6.2.3. <A
+HREF="#AEN849"
+>Support a large number of printers</A
+></DT
+><DT
+>6.2.4. <A
+HREF="#AEN860"
+>Adding New Printers via the Windows NT APW</A
+></DT
+><DT
+>6.2.5. <A
+HREF="#AEN885"
+>Samba and Printer Ports</A
+></DT
+></DL
+></DD
+><DT
+>6.3. <A
+HREF="#AEN893"
+>The Imprints Toolset</A
+></DT
+><DD
+><DL
+><DT
+>6.3.1. <A
+HREF="#AEN897"
+>What is Imprints?</A
+></DT
+><DT
+>6.3.2. <A
+HREF="#AEN907"
+>Creating Printer Driver Packages</A
+></DT
+><DT
+>6.3.3. <A
+HREF="#AEN910"
+>The Imprints server</A
+></DT
+><DT
+>6.3.4. <A
+HREF="#AEN914"
+>The Installation Client</A
+></DT
+></DL
+></DD
+><DT
+>6.4. <A
+HREF="#AEN936"
+><A
+NAME="MIGRATION"
+></A
+>Migration to from Samba 2.0.x to 2.2.x</A
+></DT
+></DL
+></DD
+><DT
+>7. <A
+HREF="#DOMAIN-SECURITY"
+>security = domain in Samba 2.x</A
+></DT
+><DD
+><DL
+><DT
+>7.1. <A
+HREF="#AEN990"
+>Joining an NT Domain with Samba 2.2</A
+></DT
+><DT
+>7.2. <A
+HREF="#AEN1054"
+>Samba and Windows 2000 Domains</A
+></DT
+><DT
+>7.3. <A
+HREF="#AEN1059"
+>Why is this better than security = server?</A
+></DT
+></DL
+></DD
+><DT
+>8. <A
+HREF="#SAMBA-PDC"
+>How to Configure Samba 2.2 as a Primary Domain Controller</A
+></DT
+><DD
+><DL
+><DT
+>8.1. <A
+HREF="#AEN1092"
+>Prerequisite Reading</A
+></DT
+><DT
+>8.2. <A
+HREF="#AEN1098"
+>Background</A
+></DT
+><DT
+>8.3. <A
+HREF="#AEN1137"
+>Configuring the Samba Domain Controller</A
+></DT
+><DT
+>8.4. <A
+HREF="#AEN1180"
+>Creating Machine Trust Accounts and Joining Clients to the
+Domain</A
+></DT
+><DD
+><DL
+><DT
+>8.4.1. <A
+HREF="#AEN1199"
+>Manual Creation of Machine Trust Accounts</A
+></DT
+><DT
+>8.4.2. <A
+HREF="#AEN1234"
+>"On-the-Fly" Creation of Machine Trust Accounts</A
+></DT
+><DT
+>8.4.3. <A
+HREF="#AEN1243"
+>Joining the Client to the Domain</A
+></DT
+></DL
+></DD
+><DT
+>8.5. <A
+HREF="#AEN1258"
+>Common Problems and Errors</A
+></DT
+><DT
+>8.6. <A
+HREF="#AEN1306"
+>System Policies and Profiles</A
+></DT
+><DT
+>8.7. <A
+HREF="#AEN1350"
+>What other help can I get?</A
+></DT
+><DT
+>8.8. <A
+HREF="#AEN1464"
+>Domain Control for Windows 9x/ME</A
+></DT
+><DD
+><DL
+><DT
+>8.8.1. <A
+HREF="#AEN1490"
+>Configuration Instructions: Network Logons</A
+></DT
+><DT
+>8.8.2. <A
+HREF="#AEN1509"
+>Configuration Instructions: Setting up Roaming User Profiles</A
+></DT
+><DD
+><DL
+><DT
+>8.8.2.1. <A
+HREF="#AEN1517"
+>Windows NT Configuration</A
+></DT
+><DT
+>8.8.2.2. <A
+HREF="#AEN1525"
+>Windows 9X Configuration</A
+></DT
+><DT
+>8.8.2.3. <A
+HREF="#AEN1533"
+>Win9X and WinNT Configuration</A
+></DT
+><DT
+>8.8.2.4. <A
+HREF="#AEN1540"
+>Windows 9X Profile Setup</A
+></DT
+><DT
+>8.8.2.5. <A
+HREF="#AEN1576"
+>Windows NT Workstation 4.0</A
+></DT
+><DT
+>8.8.2.6. <A
+HREF="#AEN1589"
+>Windows NT Server</A
+></DT
+><DT
+>8.8.2.7. <A
+HREF="#AEN1592"
+>Sharing Profiles between W95 and NT Workstation 4.0</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>8.9. <A
+HREF="#AEN1602"
+>DOMAIN_CONTROL.txt : Windows NT Domain Control &#38; Samba</A
+></DT
+></DL
+></DD
+><DT
+>9. <A
+HREF="#WINBIND"
+>Unified Logons between Windows NT and UNIX using Winbind</A
+></DT
+><DD
+><DL
+><DT
+>9.1. <A
+HREF="#AEN1652"
+>Abstract</A
+></DT
+><DT
+>9.2. <A
+HREF="#AEN1656"
+>Introduction</A
+></DT
+><DT
+>9.3. <A
+HREF="#AEN1669"
+>What Winbind Provides</A
+></DT
+><DD
+><DL
+><DT
+>9.3.1. <A
+HREF="#AEN1676"
+>Target Uses</A
+></DT
+></DL
+></DD
+><DT
+>9.4. <A
+HREF="#AEN1680"
+>How Winbind Works</A
+></DT
+><DD
+><DL
+><DT
+>9.4.1. <A
+HREF="#AEN1685"
+>Microsoft Remote Procedure Calls</A
+></DT
+><DT
+>9.4.2. <A
+HREF="#AEN1689"
+>Name Service Switch</A
+></DT
+><DT
+>9.4.3. <A
+HREF="#AEN1705"
+>Pluggable Authentication Modules</A
+></DT
+><DT
+>9.4.4. <A
+HREF="#AEN1713"
+>User and Group ID Allocation</A
+></DT
+><DT
+>9.4.5. <A
+HREF="#AEN1717"
+>Result Caching</A
+></DT
+></DL
+></DD
+><DT
+>9.5. <A
+HREF="#AEN1720"
+>Installation and Configuration</A
+></DT
+><DD
+><DL
+><DT
+>9.5.1. <A
+HREF="#AEN1725"
+>Introduction</A
+></DT
+><DT
+>9.5.2. <A
+HREF="#AEN1738"
+>Requirements</A
+></DT
+><DT
+>9.5.3. <A
+HREF="#AEN1752"
+>Testing Things Out</A
+></DT
+><DD
+><DL
+><DT
+>9.5.3.1. <A
+HREF="#AEN1763"
+>Configure and compile SAMBA</A
+></DT
+><DT
+>9.5.3.2. <A
+HREF="#AEN1782"
+>Configure <TT
+CLASS="FILENAME"
+>nsswitch.conf</TT
+> and the
+winbind libraries</A
+></DT
+><DT
+>9.5.3.3. <A
+HREF="#AEN1807"
+>Configure smb.conf</A
+></DT
+><DT
+>9.5.3.4. <A
+HREF="#AEN1823"
+>Join the SAMBA server to the PDC domain</A
+></DT
+><DT
+>9.5.3.5. <A
+HREF="#AEN1834"
+>Start up the winbindd daemon and test it!</A
+></DT
+><DT
+>9.5.3.6. <A
+HREF="#AEN1870"
+>Fix the <TT
+CLASS="FILENAME"
+>/etc/rc.d/init.d/smb</TT
+> startup files</A
+></DT
+><DT
+>9.5.3.7. <A
+HREF="#AEN1892"
+>Configure Winbind and PAM</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>9.6. <A
+HREF="#AEN1939"
+>Limitations</A
+></DT
+><DT
+>9.7. <A
+HREF="#AEN1949"
+>Conclusion</A
+></DT
+></DL
+></DD
+><DT
+>10. <A
+HREF="#OS2"
+>OS2 Client HOWTO</A
+></DT
+><DD
+><DL
+><DT
+>10.1. <A
+HREF="#AEN1963"
+>FAQs</A
+></DT
+><DD
+><DL
+><DT
+>10.1.1. <A
+HREF="#AEN1965"
+>How can I configure OS/2 Warp Connect or
+ OS/2 Warp 4 as a client for Samba?</A
+></DT
+><DT
+>10.1.2. <A
+HREF="#AEN1980"
+>How can I configure OS/2 Warp 3 (not Connect),
+ OS/2 1.2, 1.3 or 2.x for Samba?</A
+></DT
+><DT
+>10.1.3. <A
+HREF="#AEN1989"
+>Are there any other issues when OS/2 (any version)
+ is used as a client?</A
+></DT
+><DT
+>10.1.4. <A
+HREF="#AEN1993"
+>How do I get printer driver download working
+ for OS/2 clients?</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>11. <A
+HREF="#CVS-ACCESS"
+>HOWTO Access Samba source code via CVS</A
+></DT
+><DD
+><DL
+><DT
+>11.1. <A
+HREF="#AEN2009"
+>Introduction</A
+></DT
+><DT
+>11.2. <A
+HREF="#AEN2014"
+>CVS Access to samba.org</A
+></DT
+><DD
+><DL
+><DT
+>11.2.1. <A
+HREF="#AEN2017"
+>Access via CVSweb</A
+></DT
+><DT
+>11.2.2. <A
+HREF="#AEN2022"
+>Access via cvs</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+><A
+HREF="#AEN2050"
+>Index</A
+></DT
+></DL
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INSTALL"
+>Chapter 1. How to Install and Test SAMBA</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN18"
+>1.1. Step 0: Read the man pages</A
+></H1
+><P
+>The man pages distributed with SAMBA contain
+ lots of useful info that will help to get you started.
+ If you don't know how to read man pages then try
+ something like:</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>nroff -man smbd.8 | more
+ </B
+></TT
+></P
+><P
+>Other sources of information are pointed to
+ by the Samba web site,<A
+HREF="http://www.samba.org/"
+TARGET="_top"
+> http://www.samba.org</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN26"
+>1.2. Step 1: Building the Binaries</A
+></H1
+><P
+>To do this, first run the program <B
+CLASS="COMMAND"
+>./configure
+ </B
+> in the source directory. This should automatically
+ configure Samba for your operating system. If you have unusual
+ needs then you may wish to run</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>./configure --help
+ </B
+></TT
+></P
+><P
+>first to see what special options you can enable.
+ Then executing</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make</B
+></TT
+></P
+><P
+>will create the binaries. Once it's successfully
+ compiled you can use </P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make install</B
+></TT
+></P
+><P
+>to install the binaries and manual pages. You can
+ separately install the binaries and/or man pages using</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make installbin
+ </B
+></TT
+></P
+><P
+>and</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make installman
+ </B
+></TT
+></P
+><P
+>Note that if you are upgrading for a previous version
+ of Samba you might like to know that the old versions of
+ the binaries will be renamed with a ".old" extension. You
+ can go back to the previous version with</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make revert
+ </B
+></TT
+></P
+><P
+>if you find this version a disaster!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN54"
+>1.3. Step 2: The all important step</A
+></H1
+><P
+>At this stage you must fetch yourself a
+ coffee or other drink you find stimulating. Getting the rest
+ of the install right can sometimes be tricky, so you will
+ probably need it.</P
+><P
+>If you have installed samba before then you can skip
+ this step.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN58"
+>1.4. Step 3: Create the smb configuration file.</A
+></H1
+><P
+>There are sample configuration files in the examples
+ subdirectory in the distribution. I suggest you read them
+ carefully so you can see how the options go together in
+ practice. See the man page for all the options.</P
+><P
+>The simplest useful configuration file would be
+ something like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> [global]
+ workgroup = MYGROUP
+
+ [homes]
+ guest ok = no
+ read only = no
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>which would allow connections by anyone with an
+ account on the server, using either their login name or
+ "homes" as the service name. (Note that I also set the
+ workgroup that Samba is part of. See BROWSING.txt for details)</P
+><P
+>Note that <B
+CLASS="COMMAND"
+>make install</B
+> will not install
+ a <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. You need to create it
+ yourself. </P
+><P
+>Make sure you put the smb.conf file in the same place
+ you specified in the<TT
+CLASS="FILENAME"
+>Makefile</TT
+> (the default is to
+ look for it in <TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/</TT
+>).</P
+><P
+>For more information about security settings for the
+ [homes] share please refer to the document UNIX_SECURITY.txt.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN72"
+>1.5. Step 4: Test your config file with
+ <B
+CLASS="COMMAND"
+>testparm</B
+></A
+></H1
+><P
+>It's important that you test the validity of your
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file using the testparm program.
+ If testparm runs OK then it will list the loaded services. If
+ not it will give an error message.</P
+><P
+>Make sure it runs OK and that the services look
+ reasonable before proceeding. </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN78"
+>1.6. Step 5: Starting the smbd and nmbd</A
+></H1
+><P
+>You must choose to start smbd and nmbd either
+ as daemons or from <B
+CLASS="COMMAND"
+>inetd</B
+>. Don't try
+ to do both! Either you can put them in <TT
+CLASS="FILENAME"
+> inetd.conf</TT
+> and have them started on demand
+ by <B
+CLASS="COMMAND"
+>inetd</B
+>, or you can start them as
+ daemons either from the command line or in <TT
+CLASS="FILENAME"
+> /etc/rc.local</TT
+>. See the man pages for details
+ on the command line options. Take particular care to read
+ the bit about what user you need to be in order to start
+ Samba. In many cases you must be root.</P
+><P
+>The main advantage of starting <B
+CLASS="COMMAND"
+>smbd</B
+>
+ and <B
+CLASS="COMMAND"
+>nmbd</B
+> as a daemon is that they will
+ respond slightly more quickly to an initial connection
+ request. This is, however, unlikely to be a problem.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN88"
+>1.6.1. Step 5a: Starting from inetd.conf</A
+></H2
+><P
+>NOTE; The following will be different if
+ you use NIS or NIS+ to distributed services maps.</P
+><P
+>Look at your <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>.
+ What is defined at port 139/tcp. If nothing is defined
+ then add a line like this:</P
+><P
+><TT
+CLASS="USERINPUT"
+><B
+>netbios-ssn 139/tcp</B
+></TT
+></P
+><P
+>similarly for 137/udp you should have an entry like:</P
+><P
+><TT
+CLASS="USERINPUT"
+><B
+>netbios-ns 137/udp</B
+></TT
+></P
+><P
+>Next edit your <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>
+ and add two lines something like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+ netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The exact syntax of <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>
+ varies between unixes. Look at the other entries in inetd.conf
+ for a guide.</P
+><P
+>NOTE: Some unixes already have entries like netbios_ns
+ (note the underscore) in <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>.
+ You must either edit <TT
+CLASS="FILENAME"
+>/etc/services</TT
+> or
+ <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+> to make them consistent.</P
+><P
+>NOTE: On many systems you may need to use the
+ "interfaces" option in smb.conf to specify the IP address
+ and netmask of your interfaces. Run <B
+CLASS="COMMAND"
+>ifconfig</B
+>
+ as root if you don't know what the broadcast is for your
+ net. <B
+CLASS="COMMAND"
+>nmbd</B
+> tries to determine it at run
+ time, but fails on some unixes. See the section on "testing nmbd"
+ for a method of finding if you need to do this.</P
+><P
+>!!!WARNING!!! Many unixes only accept around 5
+ parameters on the command line in <TT
+CLASS="FILENAME"
+>inetd.conf</TT
+>.
+ This means you shouldn't use spaces between the options and
+ arguments, or you should use a script, and start the script
+ from <B
+CLASS="COMMAND"
+>inetd</B
+>.</P
+><P
+>Restart <B
+CLASS="COMMAND"
+>inetd</B
+>, perhaps just send
+ it a HUP. If you have installed an earlier version of <B
+CLASS="COMMAND"
+> nmbd</B
+> then you may need to kill nmbd as well.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN117"
+>1.6.2. Step 5b. Alternative: starting it as a daemon</A
+></H2
+><P
+>To start the server as a daemon you should create
+ a script something like this one, perhaps calling
+ it <TT
+CLASS="FILENAME"
+>startsmb</TT
+>.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> #!/bin/sh
+ /usr/local/samba/bin/smbd -D
+ /usr/local/samba/bin/nmbd -D
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>then make it executable with <B
+CLASS="COMMAND"
+>chmod
+ +x startsmb</B
+></P
+><P
+>You can then run <B
+CLASS="COMMAND"
+>startsmb</B
+> by
+ hand or execute it from <TT
+CLASS="FILENAME"
+>/etc/rc.local</TT
+>
+ </P
+><P
+>To kill it send a kill signal to the processes
+ <B
+CLASS="COMMAND"
+>nmbd</B
+> and <B
+CLASS="COMMAND"
+>smbd</B
+>.</P
+><P
+>NOTE: If you use the SVR4 style init system then
+ you may like to look at the <TT
+CLASS="FILENAME"
+>examples/svr4-startup</TT
+>
+ script to make Samba fit into that system.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN133"
+>1.7. Step 6: Try listing the shares available on your
+ server</A
+></H1
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient -L
+ <TT
+CLASS="REPLACEABLE"
+><I
+>yourhostname</I
+></TT
+></B
+></TT
+></P
+><P
+>Your should get back a list of shares available on
+ your server. If you don't then something is incorrectly setup.
+ Note that this method can also be used to see what shares
+ are available on other LanManager clients (such as WfWg).</P
+><P
+>If you choose user level security then you may find
+ that Samba requests a password before it will list the shares.
+ See the <B
+CLASS="COMMAND"
+>smbclient</B
+> man page for details. (you
+ can force it to list the shares without a password by
+ adding the option -U% to the command line. This will not work
+ with non-Samba servers)</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN142"
+>1.8. Step 7: Try connecting with the unix client</A
+></H1
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient <TT
+CLASS="REPLACEABLE"
+><I
+> //yourhostname/aservice</I
+></TT
+></B
+></TT
+></P
+><P
+>Typically the <TT
+CLASS="REPLACEABLE"
+><I
+>yourhostname</I
+></TT
+>
+ would be the name of the host where you installed <B
+CLASS="COMMAND"
+> smbd</B
+>. The <TT
+CLASS="REPLACEABLE"
+><I
+>aservice</I
+></TT
+> is
+ any service you have defined in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+ file. Try your user name if you just have a [homes] section
+ in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.</P
+><P
+>For example if your unix host is bambi and your login
+ name is fred you would type:</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient //bambi/fred
+ </B
+></TT
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN158"
+>1.9. Step 8: Try connecting from a DOS, WfWg, Win9x, WinNT,
+ Win2k, OS/2, etc... client</A
+></H1
+><P
+>Try mounting disks. eg:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>net use d: \\servername\service
+ </B
+></TT
+></P
+><P
+>Try printing. eg:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>net use lpt1:
+ \\servername\spoolservice</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>print filename
+ </B
+></TT
+></P
+><P
+>Celebrate, or send me a bug report!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN172"
+>1.10. What If Things Don't Work?</A
+></H1
+><P
+>If nothing works and you start to think "who wrote
+ this pile of trash" then I suggest you do step 2 again (and
+ again) till you calm down.</P
+><P
+>Then you might read the file DIAGNOSIS.txt and the
+ FAQ. If you are still stuck then try the mailing list or
+ newsgroup (look in the README for details). Samba has been
+ successfully installed at thousands of sites worldwide, so maybe
+ someone else has hit your problem and has overcome it. You could
+ also use the WWW site to scan back issues of the samba-digest.</P
+><P
+>When you fix the problem PLEASE send me some updates to the
+ documentation (or source code) so that the next person will find it
+ easier. </P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN177"
+>1.10.1. Diagnosing Problems</A
+></H2
+><P
+>If you have installation problems then go to
+ <TT
+CLASS="FILENAME"
+>DIAGNOSIS.txt</TT
+> to try to find the
+ problem.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN181"
+>1.10.2. Scope IDs</A
+></H2
+><P
+>By default Samba uses a blank scope ID. This means
+ all your windows boxes must also have a blank scope ID.
+ If you really want to use a non-blank scope ID then you will
+ need to use the -i &#60;scope&#62; option to nmbd, smbd, and
+ smbclient. All your PCs will need to have the same setting for
+ this to work. I do not recommend scope IDs.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN184"
+>1.10.3. Choosing the Protocol Level</A
+></H2
+><P
+>The SMB protocol has many dialects. Currently
+ Samba supports 5, called CORE, COREPLUS, LANMAN1,
+ LANMAN2 and NT1.</P
+><P
+>You can choose what maximum protocol to support
+ in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. The default is
+ NT1 and that is the best for the vast majority of sites.</P
+><P
+>In older versions of Samba you may have found it
+ necessary to use COREPLUS. The limitations that led to
+ this have mostly been fixed. It is now less likely that you
+ will want to use less than LANMAN1. The only remaining advantage
+ of COREPLUS is that for some obscure reason WfWg preserves
+ the case of passwords in this protocol, whereas under LANMAN1,
+ LANMAN2 or NT1 it uppercases all passwords before sending them,
+ forcing you to use the "password level=" option in some cases.</P
+><P
+>The main advantage of LANMAN2 and NT1 is support for
+ long filenames with some clients (eg: smbclient, Windows NT
+ or Win95). </P
+><P
+>See the smb.conf(5) manual page for more details.</P
+><P
+>Note: To support print queue reporting you may find
+ that you have to use TCP/IP as the default protocol under
+ WfWg. For some reason if you leave Netbeui as the default
+ it may break the print queue reporting on some systems.
+ It is presumably a WfWg bug.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN193"
+>1.10.4. Printing from UNIX to a Client PC</A
+></H2
+><P
+>To use a printer that is available via a smb-based
+ server from a unix host you will need to compile the
+ smbclient program. You then need to install the script
+ "smbprint". Read the instruction in smbprint for more details.
+ </P
+><P
+>There is also a SYSV style script that does much
+ the same thing called smbprint.sysv. It contains instructions.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN197"
+>1.10.5. Locking</A
+></H2
+><P
+>One area which sometimes causes trouble is locking.</P
+><P
+>There are two types of locking which need to be
+ performed by a SMB server. The first is "record locking"
+ which allows a client to lock a range of bytes in a open file.
+ The second is the "deny modes" that are specified when a file
+ is open.</P
+><P
+>Record locking semantics under Unix is very
+ different from record locking under Windows. Versions
+ of Samba before 2.2 have tried to use the native
+ fcntl() unix system call to implement proper record
+ locking between different Samba clients. This can not
+ be fully correct due to several reasons. The simplest
+ is the fact that a Windows client is allowed to lock a
+ byte range up to 2^32 or 2^64, depending on the client
+ OS. The unix locking only supports byte ranges up to
+ 2^31. So it is not possible to correctly satisfy a
+ lock request above 2^31. There are many more
+ differences, too many to be listed here.</P
+><P
+>Samba 2.2 and above implements record locking
+ completely independent of the underlying unix
+ system. If a byte range lock that the client requests
+ happens to fall into the range 0-2^31, Samba hands
+ this request down to the Unix system. All other locks
+ can not be seen by unix anyway.</P
+><P
+>Strictly a SMB server should check for locks before
+ every read and write call on a file. Unfortunately with the
+ way fcntl() works this can be slow and may overstress the
+ rpc.lockd. It is also almost always unnecessary as clients
+ are supposed to independently make locking calls before reads
+ and writes anyway if locking is important to them. By default
+ Samba only makes locking calls when explicitly asked
+ to by a client, but if you set "strict locking = yes" then it will
+ make lock checking calls on every read and write. </P
+><P
+>You can also disable by range locking completely
+ using "locking = no". This is useful for those shares that
+ don't support locking or don't need it (such as cdroms). In
+ this case Samba fakes the return codes of locking calls to
+ tell clients that everything is OK.</P
+><P
+>The second class of locking is the "deny modes". These
+ are set by an application when it opens a file to determine
+ what types of access should be allowed simultaneously with
+ its open. A client may ask for DENY_NONE, DENY_READ, DENY_WRITE
+ or DENY_ALL. There are also special compatibility modes called
+ DENY_FCB and DENY_DOS.</P
+><P
+>You can disable share modes using "share modes = no".
+ This may be useful on a heavily loaded server as the share
+ modes code is very slow. See also the FAST_SHARE_MODES
+ option in the Makefile for a way to do full share modes
+ very fast using shared memory (if your OS supports it).</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN207"
+>1.10.6. Mapping Usernames</A
+></H2
+><P
+>If you have different usernames on the PCs and
+ the unix server then take a look at the "username map" option.
+ See the smb.conf man page for details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN210"
+>1.10.7. Other Character Sets</A
+></H2
+><P
+>If you have problems using filenames with accented
+ characters in them (like the German, French or Scandinavian
+ character sets) then I recommend you look at the "valid chars"
+ option in smb.conf and also take a look at the validchars
+ package in the examples directory.</P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTEGRATE-MS-NETWORKS"
+>Chapter 2. Integrating MS Windows networks with Samba</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN224"
+>2.1. Agenda</A
+></H1
+><P
+>To identify the key functional mechanisms of MS Windows networking
+to enable the deployment of Samba as a means of extending and/or
+replacing MS Windows NT/2000 technology.</P
+><P
+>We will examine:</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+>Name resolution in a pure Unix/Linux TCP/IP
+ environment
+ </P
+></LI
+><LI
+><P
+>Name resolution as used within MS Windows
+ networking
+ </P
+></LI
+><LI
+><P
+>How browsing functions and how to deploy stable
+ and dependable browsing using Samba
+ </P
+></LI
+><LI
+><P
+>MS Windows security options and how to
+ configure Samba for seemless integration
+ </P
+></LI
+><LI
+><P
+>Configuration of Samba as:</P
+><P
+></P
+><OL
+TYPE="a"
+><LI
+><P
+>A stand-alone server</P
+></LI
+><LI
+><P
+>An MS Windows NT 3.x/4.0 security domain member
+ </P
+></LI
+><LI
+><P
+>An alternative to an MS Windows NT 3.x/4.0 Domain Controller
+ </P
+></LI
+></OL
+></LI
+></OL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN246"
+>2.2. Name Resolution in a pure Unix/Linux world</A
+></H1
+><P
+>The key configuration files covered in this section are:</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+></P
+></LI
+></UL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN262"
+>2.2.1. <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+></A
+></H2
+><P
+>Contains a static list of IP Addresses and names.
+eg:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> 127.0.0.1 localhost localhost.localdomain
+ 192.168.1.1 bigbox.caldera.com bigbox alias4box</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The purpose of <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> is to provide a
+name resolution mechanism so that uses do not need to remember
+IP addresses.</P
+><P
+>Network packets that are sent over the physical network transport
+layer communicate not via IP addresses but rather using the Media
+Access Control address, or MAC address. IP Addresses are currently
+32 bits in length and are typically presented as four (4) decimal
+numbers that are separated by a dot (or period). eg: 168.192.1.1</P
+><P
+>MAC Addresses use 48 bits (or 6 bytes) and are typically represented
+as two digit hexadecimal numbers separated by colons. eg:
+40:8e:0a:12:34:56</P
+><P
+>Every network interfrace must have an MAC address. Associated with
+a MAC address there may be one or more IP addresses. There is NO
+relationship between an IP address and a MAC address, all such assignments
+are arbitary or discretionary in nature. At the most basic level all
+network communications takes place using MAC addressing. Since MAC
+addresses must be globally unique, and generally remains fixed for
+any particular interface, the assignment of an IP address makes sense
+from a network management perspective. More than one IP address can
+be assigned per MAC address. One address must be the primary IP address,
+this is the address that will be returned in the ARP reply.</P
+><P
+>When a user or a process wants to communicate with another machine
+the protocol implementation ensures that the "machine name" or "host
+name" is resolved to an IP address in a manner that is controlled
+by the TCP/IP configuration control files. The file
+<TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> is one such file.</P
+><P
+>When the IP address of the destination interface has been
+determined a protocol called ARP/RARP isused to identify
+the MAC address of the target interface. ARP stands for Address
+Resolution Protocol, and is a broadcast oriented method that
+uses UDP (User Datagram Protocol) to send a request to all
+interfaces on the local network segment using the all 1's MAC
+address. Network interfaces are programmed to respond to two
+MAC addresses only; their own unique address and the address
+ff:ff:ff:ff:ff:ff. The reply packet from an ARP request will
+contain the MAC address and the primary IP address for each
+interface.</P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> file is foundational to all
+Unix/Linux TCP/IP installations and as a minumum will contain
+the localhost and local network interface IP addresses and the
+primary names by which they are known within the local machine.
+This file helps to prime the pump so that a basic level of name
+resolution can exist before any other method of name resolution
+becomes available.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN278"
+>2.2.2. <TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></A
+></H2
+><P
+>This file tells the name resolution libraries:</P
+><P
+></P
+><UL
+><LI
+><P
+>The name of the domain to which the machine
+ belongs
+ </P
+></LI
+><LI
+><P
+>The name(s) of any domains that should be
+ automatically searched when trying to resolve unqualified
+ host names to their IP address
+ </P
+></LI
+><LI
+><P
+>The name or IP address of available Domain
+ Name Servers that may be asked to perform name to address
+ translation lookups
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN289"
+>2.2.3. <TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+></A
+></H2
+><P
+><TT
+CLASS="FILENAME"
+>/etc/host.conf</TT
+> is the primary means by
+which the setting in /etc/resolv.conf may be affected. It is a
+critical configuration file. This file controls the order by
+which name resolution may procede. The typical structure is:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> order hosts,bind
+ multi on</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>then both addresses should be returned. Please refer to the
+man page for host.conf for further details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN297"
+>2.2.4. <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+></A
+></H2
+><P
+>This file controls the actual name resolution targets. The
+file typically has resolver object specifications as follows:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> # /etc/nsswitch.conf
+ #
+ # Name Service Switch configuration file.
+ #
+
+ passwd: compat
+ # Alternative entries for password authentication are:
+ # passwd: compat files nis ldap winbind
+ shadow: compat
+ group: compat
+
+ hosts: files nis dns
+ # Alternative entries for host name resolution are:
+ # hosts: files dns nis nis+ hesoid db compat ldap wins
+ networks: nis files dns
+
+ ethers: nis files
+ protocols: nis files
+ rpc: nis files
+ services: nis files</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Of course, each of these mechanisms requires that the appropriate
+facilities and/or services are correctly configured.</P
+><P
+>It should be noted that unless a network request/message must be
+sent, TCP/IP networks are silent. All TCP/IP communications assumes a
+principal of speaking only when necessary.</P
+><P
+>Samba version 2.2.0 will add Linux support for extensions to
+the name service switch infrastructure so that linux clients will
+be able to obtain resolution of MS Windows NetBIOS names to IP
+Addresses. To gain this functionality Samba needs to be compiled
+with appropriate arguments to the make command (ie: <B
+CLASS="COMMAND"
+>make
+nsswitch/libnss_wins.so</B
+>). The resulting library should
+then be installed in the <TT
+CLASS="FILENAME"
+>/lib</TT
+> directory and
+the "wins" parameter needs to be added to the "hosts:" line in
+the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file. At this point it
+will be possible to ping any MS Windows machine by it's NetBIOS
+machine name, so long as that machine is within the workgroup to
+which both the samba machine and the MS Windows machine belong.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN309"
+>2.3. Name resolution as used within MS Windows networking</A
+></H1
+><P
+>MS Windows networking is predicated about the name each machine
+is given. This name is known variously (and inconsistently) as
+the "computer name", "machine name", "networking name", "netbios name",
+"SMB name". All terms mean the same thing with the exception of
+"netbios name" which can apply also to the name of the workgroup or the
+domain name. The terms "workgroup" and "domain" are really just a
+simply name with which the machine is associated. All NetBIOS names
+are exactly 16 characters in length. The 16th character is reserved.
+It is used to store a one byte value that indicates service level
+information for the NetBIOS name that is registered. A NetBIOS machine
+name is therefore registered for each service type that is provided by
+the client/server.</P
+><P
+>The following are typical NetBIOS name/service type registrations:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> Unique NetBIOS Names:
+ MACHINENAME&#60;00&#62; = Server Service is running on MACHINENAME
+ MACHINENAME&#60;03&#62; = Generic Machine Name (NetBIOS name)
+ MACHINENAME&#60;20&#62; = LanMan Server service is running on MACHINENAME
+ WORKGROUP&#60;1b&#62; = Domain Master Browser
+
+ Group Names:
+ WORKGROUP&#60;03&#62; = Generic Name registered by all members of WORKGROUP
+ WORKGROUP&#60;1c&#62; = Domain Controllers / Netlogon Servers
+ WORKGROUP&#60;1d&#62; = Local Master Browsers
+ WORKGROUP&#60;1e&#62; = Internet Name Resolvers</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>It should be noted that all NetBIOS machines register their own
+names as per the above. This is in vast contrast to TCP/IP
+installations where traditionally the system administrator will
+determine in the /etc/hosts or in the DNS database what names
+are associated with each IP address.</P
+><P
+>One further point of clarification should be noted, the <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>
+file and the DNS records do not provide the NetBIOS name type information
+that MS Windows clients depend on to locate the type of service that may
+be needed. An example of this is what happens when an MS Windows client
+wants to locate a domain logon server. It find this service and the IP
+address of a server that provides it by performing a lookup (via a
+NetBIOS broadcast) for enumeration of all machines that have
+registered the name type *&#60;1c&#62;. A logon request is then sent to each
+IP address that is returned in the enumerated list of IP addresses. Which
+ever machine first replies then ends up providing the logon services.</P
+><P
+>The name "workgroup" or "domain" really can be confusing since these
+have the added significance of indicating what is the security
+architecture of the MS Windows network. The term "workgroup" indicates
+that the primary nature of the network environment is that of a
+peer-to-peer design. In a WORKGROUP all machines are responsible for
+their own security, and generally such security is limited to use of
+just a password (known as SHARE MORE security). In most situations
+with peer-to-peer networking the users who control their own machines
+will simply opt to have no security at all. It is possible to have
+USER MODE security in a WORKGROUP environment, thus requiring use
+of a user name and a matching password.</P
+><P
+>MS Windows networking is thus predetermined to use machine names
+for all local and remote machine message passing. The protocol used is
+called Server Message Block (SMB) and this is implemented using
+the NetBIOS protocol (Network Basic Input Output System). NetBIOS can
+be encapsulated using LLC (Logical Link Control) protocol - in which case
+the resulting protocol is called NetBEUI (Network Basic Extended User
+Interface). NetBIOS can also be run over IPX (Internetworking Packet
+Exchange) protocol as used by Novell NetWare, and it can be run
+over TCP/IP protocols - in which case the resulting protocol is called
+NBT or NetBT, the NetBIOS over TCP/IP.</P
+><P
+>MS Windows machines use a complex array of name resolution mechanisms.
+Since we are primarily concerned with TCP/IP this demonstration is
+limited to this area.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN321"
+>2.3.1. The NetBIOS Name Cache</A
+></H2
+><P
+>All MS Windows machines employ an in memory buffer in which is
+stored the NetBIOS names and their IP addresses for all external
+machines that that the local machine has communicated with over the
+past 10-15 minutes. It is more efficient to obtain an IP address
+for a machine from the local cache than it is to go through all the
+configured name resolution mechanisms.</P
+><P
+>If a machine whose name is in the local name cache has been shut
+down before the name had been expired and flushed from the cache, then
+an attempt to exchange a message with that machine will be subject
+to time-out delays. ie: It's name is in the cache, so a name resolution
+lookup will succeed, but the machine can not respond. This can be
+frustrating for users - but it is a characteristic of the protocol.</P
+><P
+>The MS Windows utility that allows examination of the NetBIOS
+name cache is called "nbtstat". The Samba equivalent of this
+is called "nmblookup".</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN326"
+>2.3.2. The LMHOSTS file</A
+></H2
+><P
+>This file is usually located in MS Windows NT 4.0 or
+2000 in <TT
+CLASS="FILENAME"
+>C:\WINNT\SYSTEM32\DRIVERS\ETC</TT
+> and contains
+the IP Address and the machine name in matched pairs. The
+<TT
+CLASS="FILENAME"
+>LMHOSTS</TT
+> file performs NetBIOS name
+to IP address mapping oriented.</P
+><P
+>It typically looks like:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> # Copyright (c) 1998 Microsoft Corp.
+ #
+ # This is a sample LMHOSTS file used by the Microsoft Wins Client (NetBIOS
+ # over TCP/IP) stack for Windows98
+ #
+ # This file contains the mappings of IP addresses to NT computernames
+ # (NetBIOS) names. Each entry should be kept on an individual line.
+ # The IP address should be placed in the first column followed by the
+ # corresponding computername. The address and the comptername
+ # should be separated by at least one space or tab. The "#" character
+ # is generally used to denote the start of a comment (see the exceptions
+ # below).
+ #
+ # This file is compatible with Microsoft LAN Manager 2.x TCP/IP lmhosts
+ # files and offers the following extensions:
+ #
+ # #PRE
+ # #DOM:&#60;domain&#62;
+ # #INCLUDE &#60;filename&#62;
+ # #BEGIN_ALTERNATE
+ # #END_ALTERNATE
+ # \0xnn (non-printing character support)
+ #
+ # Following any entry in the file with the characters "#PRE" will cause
+ # the entry to be preloaded into the name cache. By default, entries are
+ # not preloaded, but are parsed only after dynamic name resolution fails.
+ #
+ # Following an entry with the "#DOM:&#60;domain&#62;" tag will associate the
+ # entry with the domain specified by &#60;domain&#62;. This affects how the
+ # browser and logon services behave in TCP/IP environments. To preload
+ # the host name associated with #DOM entry, it is necessary to also add a
+ # #PRE to the line. The &#60;domain&#62; is always preloaded although it will not
+ # be shown when the name cache is viewed.
+ #
+ # Specifying "#INCLUDE &#60;filename&#62;" will force the RFC NetBIOS (NBT)
+ # software to seek the specified &#60;filename&#62; and parse it as if it were
+ # local. &#60;filename&#62; is generally a UNC-based name, allowing a
+ # centralized lmhosts file to be maintained on a server.
+ # It is ALWAYS necessary to provide a mapping for the IP address of the
+ # server prior to the #INCLUDE. This mapping must use the #PRE directive.
+ # In addtion the share "public" in the example below must be in the
+ # LanManServer list of "NullSessionShares" in order for client machines to
+ # be able to read the lmhosts file successfully. This key is under
+ # \machine\system\currentcontrolset\services\lanmanserver\parameters\nullsessionshares
+ # in the registry. Simply add "public" to the list found there.
+ #
+ # The #BEGIN_ and #END_ALTERNATE keywords allow multiple #INCLUDE
+ # statements to be grouped together. Any single successful include
+ # will cause the group to succeed.
+ #
+ # Finally, non-printing characters can be embedded in mappings by
+ # first surrounding the NetBIOS name in quotations, then using the
+ # \0xnn notation to specify a hex value for a non-printing character.
+ #
+ # The following example illustrates all of these extensions:
+ #
+ # 102.54.94.97 rhino #PRE #DOM:networking #net group's DC
+ # 102.54.94.102 "appname \0x14" #special app server
+ # 102.54.94.123 popular #PRE #source server
+ # 102.54.94.117 localsrv #PRE #needed for the include
+ #
+ # #BEGIN_ALTERNATE
+ # #INCLUDE \\localsrv\public\lmhosts
+ # #INCLUDE \\rhino\public\lmhosts
+ # #END_ALTERNATE
+ #
+ # In the above example, the "appname" server contains a special
+ # character in its name, the "popular" and "localsrv" server names are
+ # preloaded, and the "rhino" server name is specified so it can be used
+ # to later #INCLUDE a centrally maintained lmhosts file if the "localsrv"
+ # system is unavailable.
+ #
+ # Note that the whole file is parsed including comments on each lookup,
+ # so keeping the number of comments to a minimum will improve performance.
+ # Therefore it is not advisable to simply add lmhosts file entries onto the
+ # end of this file.</PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN334"
+>2.3.3. HOSTS file</A
+></H2
+><P
+>This file is usually located in MS Windows NT 4.0 or 2000 in
+<TT
+CLASS="FILENAME"
+>C:\WINNT\SYSTEM32\DRIVERS\ETC</TT
+> and contains
+the IP Address and the IP hostname in matched pairs. It can be
+used by the name resolution infrastructure in MS Windows, depending
+on how the TCP/IP environment is configured. This file is in
+every way the equivalent of the Unix/Linux <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> file.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN339"
+>2.3.4. DNS Lookup</A
+></H2
+><P
+>This capability is configured in the TCP/IP setup area in the network
+configuration facility. If enabled an elaborate name resolution sequence
+is followed the precise nature of which isdependant on what the NetBIOS
+Node Type parameter is configured to. A Node Type of 0 means use
+NetBIOS broadcast (over UDP broadcast) is first used if the name
+that is the subject of a name lookup is not found in the NetBIOS name
+cache. If that fails then DNS, HOSTS and LMHOSTS are checked. If set to
+Node Type 8, then a NetBIOS Unicast (over UDP Unicast) is sent to the
+WINS Server to obtain a lookup before DNS, HOSTS, LMHOSTS, or broadcast
+lookup is used.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN342"
+>2.3.5. WINS Lookup</A
+></H2
+><P
+>A WINS (Windows Internet Name Server) service is the equivaent of the
+rfc1001/1002 specified NBNS (NetBIOS Name Server). A WINS server stores
+the names and IP addresses that are registered by a Windows client
+if the TCP/IP setup has been given at least one WINS Server IP Address.</P
+><P
+>To configure Samba to be a WINS server the following parameter needs
+to be added to the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> wins support = Yes</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>To configure Samba to use a WINS server the following parameters are
+needed in the smb.conf file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> wins support = No
+ wins server = xxx.xxx.xxx.xxx</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>where <TT
+CLASS="REPLACEABLE"
+><I
+>xxx.xxx.xxx.xxx</I
+></TT
+> is the IP address
+of the WINS server.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN354"
+>2.4. How browsing functions and how to deploy stable and
+dependable browsing using Samba</A
+></H1
+><P
+>As stated above, MS Windows machines register their NetBIOS names
+(ie: the machine name for each service type in operation) on start
+up. Also, as stated above, the exact method by which this name registration
+takes place is determined by whether or not the MS Windows client/server
+has been given a WINS server address, whether or not LMHOSTS lookup
+is enabled, or if DNS for NetBIOS name resolution is enabled, etc.</P
+><P
+>In the case where there is no WINS server all name registrations as
+well as name lookups are done by UDP broadcast. This isolates name
+resolution to the local subnet, unless LMHOSTS is used to list all
+names and IP addresses. In such situations Samba provides a means by
+which the samba server name may be forcibly injected into the browse
+list of a remote MS Windows network (using the "remote announce" parameter).</P
+><P
+>Where a WINS server is used, the MS Windows client will use UDP
+unicast to register with the WINS server. Such packets can be routed
+and thus WINS allows name resolution to function across routed networks.</P
+><P
+>During the startup process an election will take place to create a
+local master browser if one does not already exist. On each NetBIOS network
+one machine will be elected to function as the domain master browser. This
+domain browsing has nothing to do with MS security domain control.
+Instead, the domain master browser serves the role of contacting each local
+master browser (found by asking WINS or from LMHOSTS) and exchanging browse
+list contents. This way every master browser will eventually obtain a complete
+list of all machines that are on the network. Every 11-15 minutes an election
+is held to determine which machine will be the master browser. By nature of
+the election criteria used, the machine with the highest uptime, or the
+most senior protocol version, or other criteria, will win the election
+as domain master browser.</P
+><P
+>Clients wishing to browse the network make use of this list, but also depend
+on the availability of correct name resolution to the respective IP
+address/addresses. </P
+><P
+>Any configuration that breaks name resolution and/or browsing intrinsics
+will annoy users because they will have to put up with protracted
+inability to use the network services.</P
+><P
+>Samba supports a feature that allows forced synchonisation
+of browse lists across routed networks using the "remote
+browse sync" parameter in the smb.conf file. This causes Samba
+to contact the local master browser on a remote network and
+to request browse list synchronisation. This effectively bridges
+two networks that are separated by routers. The two remote
+networks may use either broadcast based name resolution or WINS
+based name resolution, but it should be noted that the "remote
+browse sync" parameter provides browse list synchronisation - and
+that is distinct from name to address resolution, in other
+words, for cross subnet browsing to function correctly it is
+essential that a name to address resolution mechanism be provided.
+This mechanism could be via DNS, <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>,
+and so on.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN364"
+>2.5. MS Windows security options and how to configure
+Samba for seemless integration</A
+></H1
+><P
+>MS Windows clients may use encrypted passwords as part of a
+challenege/response authentication model (a.k.a. NTLMv1) or
+alone, or clear text strings for simple password based
+authentication. It should be realized that with the SMB
+protocol the password is passed over the network either
+in plain text or encrypted, but not both in the same
+authentication requets.</P
+><P
+>When encrypted passwords are used a password that has been
+entered by the user is encrypted in two ways:</P
+><P
+></P
+><UL
+><LI
+><P
+>An MD4 hash of the UNICODE of the password
+ string. This is known as the NT hash.
+ </P
+></LI
+><LI
+><P
+>The password is converted to upper case,
+ and then padded or trucated to 14 bytes. This string is
+ then appended with 5 bytes of NULL characters and split to
+ form two 56 bit DES keys to encrypt a "magic" 8 byte value.
+ The resulting 16 bytes for the LanMan hash.
+ </P
+></LI
+></UL
+><P
+>You should refer to the <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>Password Encryption</A
+> chapter in this HOWTO collection
+for more details on the inner workings</P
+><P
+>MS Windows 95 pre-service pack 1, MS Windows NT versions 3.x
+and version 4.0 pre-service pack 3 will use either mode of
+password authentication. All versions of MS Windows that follow
+these versions no longer support plain text passwords by default.</P
+><P
+>MS Windows clients have a habit of dropping network mappings that
+have been idle for 10 minutes or longer. When the user attempts to
+use the mapped drive connection that has been dropped the SMB protocol
+has a mechanism by which the connection can be re-established using
+a cached copy of the password.</P
+><P
+>When Microsoft changed the default password mode, they dropped support for
+caching of the plain text password. This means that when the registry
+parameter is changed to re-enable use of plain text passwords it appears to
+work, but when a dropped mapping attempts to revalidate it will fail if
+the remote authentication server does not support encrypted passwords.
+This means that it is definitely not a good idea to re-enable plain text
+password support in such clients.</P
+><P
+>The following parameters can be used to work around the
+issue of Windows 9x client upper casing usernames and
+password before transmitting them to the SMB server
+when using clear text authentication.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> <A
+HREF="smb.conf.5.html#PASSWORDLEVEL"
+TARGET="_top"
+>passsword level</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>integer</I
+></TT
+>
+ <A
+HREF="smb.conf.5.html#USERNAMELEVEL"
+TARGET="_top"
+>username level</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>integer</I
+></TT
+></PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>By default Samba will lower case the username before attempting
+to lookup the user in the database of local system accounts.
+Because UNIX usernames conventionally only contain lower case
+character, the <TT
+CLASS="PARAMETER"
+><I
+>username level</I
+></TT
+> parameter
+is rarely even needed.</P
+><P
+>However, password on UNIX systems often make use of mixed case
+characters. This means that in order for a user on a Windows 9x
+client to connect to a Samba server using clear text authentication,
+the <TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+> must be set to the maximum
+number of upper case letter which <EM
+>could</EM
+> appear
+is a password. Note that is the server OS uses the traditional
+DES version of crypt(), then a <TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+>
+of 8 will result in case insensitive passwords as seen from Windows
+users. This will also result in longer login times as Samba
+hash to compute the permutations of the password string and
+try them one by one until a match is located (or all combinations fail).</P
+><P
+>The best option to adopt is to enable support for encrypted passwords
+where ever Samba is used. There are three configuration possibilities
+for support of encrypted passwords:</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN392"
+>2.5.1. Use MS Windows NT as an authentication server</A
+></H2
+><P
+>This method involves the additions of the following parameters
+in the smb.conf file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> encrypt passwords = Yes
+ security = server
+ password server = "NetBIOS_name_of_PDC"</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>There are two ways of identifying whether or not a username and
+password pair was valid or not. One uses the reply information provided
+as part of the authentication messaging process, the other uses
+just and error code.</P
+><P
+>The down-side of this mode of configuration is the fact that
+for security reasons Samba will send the password server a bogus
+username and a bogus password and if the remote server fails to
+reject the username and password pair then an alternative mode
+of identification of validation is used. Where a site uses password
+lock out after a certain number of failed authentication attempts
+this will result in user lockouts.</P
+><P
+>Use of this mode of authentication does require there to be
+a standard Unix account for the user, this account can be blocked
+to prevent logons by other than MS Windows clients.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN400"
+>2.5.2. Make Samba a member of an MS Windows NT security domain</A
+></H2
+><P
+>This method involves additon of the following paramters in the smb.conf file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> encrypt passwords = Yes
+ security = domain
+ workgroup = "name of NT domain"
+ password server = *</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The use of the "*" argument to "password server" will cause samba
+to locate the domain controller in a way analogous to the way
+this is done within MS Windows NT.</P
+><P
+>In order for this method to work the Samba server needs to join the
+MS Windows NT security domain. This is done as follows:</P
+><P
+></P
+><UL
+><LI
+><P
+>On the MS Windows NT domain controller using
+ the Server Manager add a machine account for the Samba server.
+ </P
+></LI
+><LI
+><P
+>Next, on the Linux system execute:
+ <B
+CLASS="COMMAND"
+>smbpasswd -r PDC_NAME -j DOMAIN_NAME</B
+>
+ </P
+></LI
+></UL
+><P
+>Use of this mode of authentication does require there to be
+a standard Unix account for the user in order to assign
+a uid once the account has been authenticated by the remote
+Windows DC. This account can be blocked to prevent logons by
+other than MS Windows clients by things such as setting an invalid
+shell in the <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry.</P
+><P
+>An alternative to assigning UIDs to Windows users on a
+Samba member server is presented in the <A
+HREF="winbind.html"
+TARGET="_top"
+>Winbind Overview</A
+> chapter in
+this HOWTO collection.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN417"
+>2.5.3. Configure Samba as an authentication server</A
+></H2
+><P
+>This mode of authentication demands that there be on the
+Unix/Linux system both a Unix style account as well as and
+smbpasswd entry for the user. The Unix system account can be
+locked if required as only the encrypted password will be
+used for SMB client authentication.</P
+><P
+>This method involves addition of the following parameters to
+the smb.conf file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>## please refer to the Samba PDC HOWTO chapter later in
+## this collection for more details
+[global]
+ encrypt passwords = Yes
+ security = user
+ domain logons = Yes
+ ; an OS level of 33 or more is recommended
+ os level = 33
+
+[NETLOGON]
+ path = /somewhare/in/file/system
+ read only = yes</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>in order for this method to work a Unix system account needs
+to be created for each user, as well as for each MS Windows NT/2000
+machine. The following structure is required.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN424"
+>2.5.3.1. Users</A
+></H3
+><P
+>A user account that may provide a home directory should be
+created. The following Linux system commands are typical of
+the procedure for creating an account.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> # useradd -s /bin/bash -d /home/"userid" -m "userid"
+ # passwd "userid"
+ Enter Password: &#60;pw&#62;
+
+ # smbpasswd -a "userid"
+ Enter Password: &#60;pw&#62;</PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN429"
+>2.5.3.2. MS Windows NT Machine Accounts</A
+></H3
+><P
+>These are required only when Samba is used as a domain
+controller. Refer to the Samba-PDC-HOWTO for more details.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> # useradd -s /bin/false -d /dev/null "machine_name"\$
+ # passwd -l "machine_name"\$
+ # smbpasswd -a -m "machine_name"</PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN434"
+>2.6. Conclusions</A
+></H1
+><P
+>Samba provides a flexible means to operate as...</P
+><P
+></P
+><UL
+><LI
+><P
+>A Stand-alone server - No special action is needed
+ other than to create user accounts. Stand-alone servers do NOT
+ provide network logon services, meaning that machines that use this
+ server do NOT perform a domain logon but instead make use only of
+ the MS Windows logon which is local to the MS Windows
+ workstation/server.
+ </P
+></LI
+><LI
+><P
+>An MS Windows NT 3.x/4.0 security domain member.
+ </P
+></LI
+><LI
+><P
+>An alternative to an MS Windows NT 3.x/4.0
+ Domain Controller.
+ </P
+></LI
+></UL
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="PAM"
+>Chapter 3. Configuring PAM for distributed but centrally
+managed authentication</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN455"
+>3.1. Samba and PAM</A
+></H1
+><P
+>A number of Unix systems (eg: Sun Solaris), as well as the
+xxxxBSD family and Linux, now utilize the Pluggable Authentication
+Modules (PAM) facility to provide all authentication,
+authorization and resource control services. Prior to the
+introduction of PAM, a decision to use an alternative to
+the system password database (<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>)
+would require the provision of alternatives for all programs that provide
+security services. Such a choice would involve provision of
+alternatives to such programs as: <B
+CLASS="COMMAND"
+>login</B
+>,
+<B
+CLASS="COMMAND"
+>passwd</B
+>, <B
+CLASS="COMMAND"
+>chown</B
+>, etc.</P
+><P
+>PAM provides a mechanism that disconnects these security programs
+from the underlying authentication/authorization infrastructure.
+PAM is configured either through one file <TT
+CLASS="FILENAME"
+>/etc/pam.conf</TT
+> (Solaris),
+or by editing individual files that are located in <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+>.</P
+><P
+>The following is an example <TT
+CLASS="FILENAME"
+>/etc/pam.d/login</TT
+> configuration file.
+This example had all options been uncommented is probably not usable
+as it stacks many conditions before allowing successful completion
+of the login process. Essentially all conditions can be disabled
+by commenting them out except the calls to <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_securetty.so
+auth required pam_nologin.so
+# auth required pam_dialup.so
+# auth optional pam_mail.so
+auth required pam_pwdb.so shadow md5
+# account requisite pam_time.so
+account required pam_pwdb.so
+session required pam_pwdb.so
+# session optional pam_lastlog.so
+# password required pam_cracklib.so retry=3
+password required pam_pwdb.so shadow md5</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>PAM allows use of replacable modules. Those available on a
+sample system include:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>$ /bin/ls /lib/security
+pam_access.so pam_ftp.so pam_limits.so
+pam_ncp_auth.so pam_rhosts_auth.so pam_stress.so
+pam_cracklib.so pam_group.so pam_listfile.so
+pam_nologin.so pam_rootok.so pam_tally.so
+pam_deny.so pam_issue.so pam_mail.so
+pam_permit.so pam_securetty.so pam_time.so
+pam_dialup.so pam_lastlog.so pam_mkhomedir.so
+pam_pwdb.so pam_shells.so pam_unix.so
+pam_env.so pam_ldap.so pam_motd.so
+pam_radius.so pam_smbpass.so pam_unix_acct.so
+pam_wheel.so pam_unix_auth.so pam_unix_passwd.so
+pam_userdb.so pam_warn.so pam_unix_session.so</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The following example for the login program replaces the use of
+the <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+> module which uses the system
+password database (<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>,
+<TT
+CLASS="FILENAME"
+>/etc/shadow</TT
+>, <TT
+CLASS="FILENAME"
+>/etc/group</TT
+>) with
+the module <TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+> which uses the Samba
+database which contains the Microsoft MD4 encrypted password
+hashes. This database is stored in either
+<TT
+CLASS="FILENAME"
+>/usr/local/samba/private/smbpasswd</TT
+>,
+<TT
+CLASS="FILENAME"
+>/etc/samba/smbpasswd</TT
+>, or in
+<TT
+CLASS="FILENAME"
+>/etc/samba.d/smbpasswd</TT
+>, depending on the
+Samba implementation for your Unix/Linux system. The
+<TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+> module is provided by
+Samba version 2.2.1 or later. It can be compiled by specifying the
+<B
+CLASS="COMMAND"
+>--with-pam_smbpass</B
+> options when running Samba's
+<TT
+CLASS="FILENAME"
+>configure</TT
+> script. For more information
+on the <TT
+CLASS="FILENAME"
+>pam_smbpass</TT
+> module, see the documentation
+in the <TT
+CLASS="FILENAME"
+>source/pam_smbpass</TT
+> directory of the Samba
+source distribution.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `login' service
+#
+auth required pam_smbpass.so nodelay
+account required pam_smbpass.so nodelay
+session required pam_smbpass.so nodelay
+password required pam_smbpass.so nodelay</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The following is the PAM configuration file for a particular
+Linux system. The default condition uses <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_pwdb.so nullok nodelay shadow audit
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_pwdb.so shadow md5</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>In the following example the decision has been made to use the
+smbpasswd database even for basic samba authentication. Such a
+decision could also be made for the passwd program and would
+thus allow the smbpasswd passwords to be changed using the passwd
+program.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#%PAM-1.0
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_smbpass.so nodelay
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_smbpass.so nodelay smbconf=/etc/samba.d/smb.conf</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Note: PAM allows stacking of authentication mechanisms. It is
+also possible to pass information obtained within on PAM module through
+to the next module in the PAM stack. Please refer to the documentation for
+your particular system implementation for details regarding the specific
+capabilities of PAM in this environment. Some Linux implmentations also
+provide the <TT
+CLASS="FILENAME"
+>pam_stack.so</TT
+> module that allows all
+authentication to be configured in a single central file. The
+<TT
+CLASS="FILENAME"
+>pam_stack.so</TT
+> method has some very devoted followers
+on the basis that it allows for easier administration. As with all issues in
+life though, every decision makes trade-offs, so you may want examine the
+PAM documentation for further helpful information.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN499"
+>3.2. Distributed Authentication</A
+></H1
+><P
+>The astute administrator will realize from this that the
+combination of <TT
+CLASS="FILENAME"
+>pam_smbpass.so</TT
+>,
+<B
+CLASS="COMMAND"
+>winbindd</B
+>, and <B
+CLASS="COMMAND"
+>rsync</B
+> (see
+<A
+HREF="http://rsync.samba.org/"
+TARGET="_top"
+>http://rsync.samba.org/</A
+>)
+will allow the establishment of a centrally managed, distributed
+user/password database that can also be used by all
+PAM (eg: Linux) aware programs and applications. This arrangement
+can have particularly potent advantages compared with the
+use of Microsoft Active Directory Service (ADS) in so far as
+reduction of wide area network authentication traffic.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN506"
+>3.3. PAM Configuration in smb.conf</A
+></H1
+><P
+>There is an option in smb.conf called <A
+HREF="smb.conf.5.html#OBEYPAMRESTRICTIONS"
+TARGET="_top"
+>obey pam restrictions</A
+>.
+The following is from the on-line help for this option in SWAT;</P
+><P
+>When Samba 2.2 is configure to enable PAM support (i.e.
+<TT
+CLASS="CONSTANT"
+>--with-pam</TT
+>), this parameter will
+control whether or not Samba should obey PAM's account
+and session management directives. The default behavior
+is to use PAM for clear text authentication only and to
+ignore any account or session management. Note that Samba always
+ignores PAM for authentication in the case of
+<A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+>encrypt passwords = yes</A
+>.
+The reason is that PAM modules cannot support the challenge/response
+authentication mechanism needed in the presence of SMB
+password encryption. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>obey pam restrictions = no</B
+></P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="MSDFS"
+>Chapter 4. Hosting a Microsoft Distributed File System tree on Samba</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN526"
+>4.1. Instructions</A
+></H1
+><P
+>The Distributed File System (or Dfs) provides a means of
+ separating the logical view of files and directories that users
+ see from the actual physical locations of these resources on the
+ network. It allows for higher availability, smoother storage expansion,
+ load balancing etc. For more information about Dfs, refer to <A
+HREF="http://www.microsoft.com/NTServer/nts/downloads/winfeatures/NTSDistrFile/AdminGuide.asp"
+TARGET="_top"
+> Microsoft documentation</A
+>. </P
+><P
+>This document explains how to host a Dfs tree on a Unix
+ machine (for Dfs-aware clients to browse) using Samba.</P
+><P
+>To enable SMB-based DFS for Samba, configure it with the
+ <TT
+CLASS="PARAMETER"
+><I
+>--with-msdfs</I
+></TT
+> option. Once built, a
+ Samba server can be made a Dfs server by setting the global
+ boolean <A
+HREF="smb.conf.5.html#HOSTMSDFS"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> host msdfs</I
+></TT
+></A
+> parameter in the <TT
+CLASS="FILENAME"
+>smb.conf
+ </TT
+> file. You designate a share as a Dfs root using the share
+ level boolean <A
+HREF="smb.conf.5.html#MSDFSROOT"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> msdfs root</I
+></TT
+></A
+> parameter. A Dfs root directory on
+ Samba hosts Dfs links in the form of symbolic links that point
+ to other servers. For example, a symbolic link
+ <TT
+CLASS="FILENAME"
+>junction-&#62;msdfs:storage1\share1</TT
+> in
+ the share directory acts as the Dfs junction. When Dfs-aware
+ clients attempt to access the junction link, they are redirected
+ to the storage location (in this case, \\storage1\share1).</P
+><P
+>Dfs trees on Samba work with all Dfs-aware clients ranging
+ from Windows 95 to 2000.</P
+><P
+>Here's an example of setting up a Dfs tree on a Samba
+ server.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+># The smb.conf file:
+[global]
+ netbios name = SAMBA
+ host msdfs = yes
+
+[dfs]
+ path = /export/dfsroot
+ msdfs root = yes
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>In the /export/dfsroot directory we set up our dfs links to
+ other servers on the network.</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>cd /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>chown root /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>chmod 755 /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>ln -s msdfs:storageA\\shareA linka</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>ln -s msdfs:serverB\\share,serverC\\share linkb</B
+></TT
+></P
+><P
+>You should set up the permissions and ownership of
+ the directory acting as the Dfs root such that only designated
+ users can create, delete or modify the msdfs links. Also note
+ that symlink names should be all lowercase. This limitation exists
+ to have Samba avoid trying all the case combinations to get at
+ the link name. Finally set up the symbolic links to point to the
+ network shares you want, and start Samba.</P
+><P
+>Users on Dfs-aware clients can now browse the Dfs tree
+ on the Samba server at \\samba\dfs. Accessing
+ links linka or linkb (which appear as directories to the client)
+ takes users directly to the appropriate shares on the network.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN561"
+>4.1.1. Notes</A
+></H2
+><P
+></P
+><UL
+><LI
+><P
+>Windows clients need to be rebooted
+ if a previously mounted non-dfs share is made a dfs
+ root or vice versa. A better way is to introduce a
+ new share and make it the dfs root.</P
+></LI
+><LI
+><P
+>Currently there's a restriction that msdfs
+ symlink names should all be lowercase.</P
+></LI
+><LI
+><P
+>For security purposes, the directory
+ acting as the root of the Dfs tree should have ownership
+ and permissions set so that only designated users can
+ modify the symbolic links in the directory.</P
+></LI
+></UL
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="UNIX-PERMISSIONS"
+>Chapter 5. UNIX Permission Bits and Windows NT Access Control Lists</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN581"
+>5.1. Viewing and changing UNIX permissions using the NT
+ security dialogs</A
+></H1
+><P
+>New in the Samba 2.0.4 release is the ability for Windows
+ NT clients to use their native security settings dialog box to
+ view and modify the underlying UNIX permissions.</P
+><P
+>Note that this ability is careful not to compromise
+ the security of the UNIX host Samba is running on, and
+ still obeys all the file permission rules that a Samba
+ administrator can set.</P
+><P
+>In Samba 2.0.4 and above the default value of the
+ parameter <A
+HREF="smb.conf.5.html#NTACLSUPPORT"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> nt acl support</I
+></TT
+></A
+> has been changed from
+ <TT
+CLASS="CONSTANT"
+>false</TT
+> to <TT
+CLASS="CONSTANT"
+>true</TT
+>, so
+ manipulation of permissions is turned on by default.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN590"
+>5.2. How to view file security on a Samba share</A
+></H1
+><P
+>From an NT 4.0 client, single-click with the right
+ mouse button on any file or directory in a Samba mounted
+ drive letter or UNC path. When the menu pops-up, click
+ on the <EM
+>Properties</EM
+> entry at the bottom of
+ the menu. This brings up the normal file properties dialog
+ box, but with Samba 2.0.4 this will have a new tab along the top
+ marked <EM
+>Security</EM
+>. Click on this tab and you
+ will see three buttons, <EM
+>Permissions</EM
+>,
+ <EM
+>Auditing</EM
+>, and <EM
+>Ownership</EM
+>.
+ The <EM
+>Auditing</EM
+> button will cause either
+ an error message <SPAN
+CLASS="ERRORNAME"
+>A requested privilege is not held
+ by the client</SPAN
+> to appear if the user is not the
+ NT Administrator, or a dialog which is intended to allow an
+ Administrator to add auditing requirements to a file if the
+ user is logged on as the NT Administrator. This dialog is
+ non-functional with a Samba share at this time, as the only
+ useful button, the <B
+CLASS="COMMAND"
+>Add</B
+> button will not currently
+ allow a list of users to be seen.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN601"
+>5.3. Viewing file ownership</A
+></H1
+><P
+>Clicking on the <B
+CLASS="COMMAND"
+>"Ownership"</B
+> button
+ brings up a dialog box telling you who owns the given file. The
+ owner name will be of the form :</P
+><P
+><B
+CLASS="COMMAND"
+>"SERVER\user (Long name)"</B
+></P
+><P
+>Where <TT
+CLASS="REPLACEABLE"
+><I
+>SERVER</I
+></TT
+> is the NetBIOS name of
+ the Samba server, <TT
+CLASS="REPLACEABLE"
+><I
+>user</I
+></TT
+> is the user name of
+ the UNIX user who owns the file, and <TT
+CLASS="REPLACEABLE"
+><I
+>(Long name)</I
+></TT
+>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database). Click on the <B
+CLASS="COMMAND"
+>Close
+ </B
+> button to remove this dialog.</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then the file owner will
+ be shown as the NT user <B
+CLASS="COMMAND"
+>"Everyone"</B
+>.</P
+><P
+>The <B
+CLASS="COMMAND"
+>Take Ownership</B
+> button will not allow
+ you to change the ownership of this file to yourself (clicking on
+ it will display a dialog box complaining that the user you are
+ currently logged onto the NT client cannot be found). The reason
+ for this is that changing the ownership of a file is a privileged
+ operation in UNIX, available only to the <EM
+>root</EM
+>
+ user. As clicking on this button causes NT to attempt to change
+ the ownership of a file to the current user logged into the NT
+ client this will not work with Samba at this time.</P
+><P
+>There is an NT chown command that will work with Samba
+ and allow a user with Administrator privilege connected
+ to a Samba 2.0.4 server as root to change the ownership of
+ files on both a local NTFS filesystem or remote mounted NTFS
+ or Samba drive. This is available as part of the <EM
+>Seclib
+ </EM
+> NT security library written by Jeremy Allison of
+ the Samba Team, available from the main Samba ftp site.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN621"
+>5.4. Viewing file or directory permissions</A
+></H1
+><P
+>The third button is the <B
+CLASS="COMMAND"
+>"Permissions"</B
+>
+ button. Clicking on this brings up a dialog box that shows both
+ the permissions and the UNIX owner of the file or directory.
+ The owner is displayed in the form :</P
+><P
+><B
+CLASS="COMMAND"
+>"SERVER\user (Long name)"</B
+></P
+><P
+>Where <TT
+CLASS="REPLACEABLE"
+><I
+>SERVER</I
+></TT
+> is the NetBIOS name of
+ the Samba server, <TT
+CLASS="REPLACEABLE"
+><I
+>user</I
+></TT
+> is the user name of
+ the UNIX user who owns the file, and <TT
+CLASS="REPLACEABLE"
+><I
+>(Long name)</I
+></TT
+>
+ is the descriptive string identifying the user (normally found in the
+ GECOS field of the UNIX password database).</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then the file owner will
+ be shown as the NT user <B
+CLASS="COMMAND"
+>"Everyone"</B
+> and the
+ permissions will be shown as NT "Full Control".</P
+><P
+>The permissions field is displayed differently for files
+ and directories, so I'll describe the way file permissions
+ are displayed first.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN636"
+>5.4.1. File Permissions</A
+></H2
+><P
+>The standard UNIX user/group/world triple and
+ the corresponding "read", "write", "execute" permissions
+ triples are mapped by Samba into a three element NT ACL
+ with the 'r', 'w', and 'x' bits mapped into the corresponding
+ NT permissions. The UNIX world permissions are mapped into
+ the global NT group <B
+CLASS="COMMAND"
+>Everyone</B
+>, followed
+ by the list of permissions allowed for UNIX world. The UNIX
+ owner and group permissions are displayed as an NT
+ <B
+CLASS="COMMAND"
+>user</B
+> icon and an NT <B
+CLASS="COMMAND"
+>local
+ group</B
+> icon respectively followed by the list
+ of permissions allowed for the UNIX user and group.</P
+><P
+>As many UNIX permission sets don't map into common
+ NT names such as <B
+CLASS="COMMAND"
+>"read"</B
+>, <B
+CLASS="COMMAND"
+> "change"</B
+> or <B
+CLASS="COMMAND"
+>"full control"</B
+> then
+ usually the permissions will be prefixed by the words <B
+CLASS="COMMAND"
+> "Special Access"</B
+> in the NT display list.</P
+><P
+>But what happens if the file has no permissions allowed
+ for a particular UNIX user group or world component ? In order
+ to allow "no permissions" to be seen and modified then Samba
+ overloads the NT <B
+CLASS="COMMAND"
+>"Take Ownership"</B
+> ACL attribute
+ (which has no meaning in UNIX) and reports a component with
+ no permissions as having the NT <B
+CLASS="COMMAND"
+>"O"</B
+> bit set.
+ This was chosen of course to make it look like a zero, meaning
+ zero permissions. More details on the decision behind this will
+ be given below.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN650"
+>5.4.2. Directory Permissions</A
+></H2
+><P
+>Directories on an NT NTFS file system have two
+ different sets of permissions. The first set of permissions
+ is the ACL set on the directory itself, this is usually displayed
+ in the first set of parentheses in the normal <B
+CLASS="COMMAND"
+>"RW"</B
+>
+ NT style. This first set of permissions is created by Samba in
+ exactly the same way as normal file permissions are, described
+ above, and is displayed in the same way.</P
+><P
+>The second set of directory permissions has no real meaning
+ in the UNIX permissions world and represents the <B
+CLASS="COMMAND"
+> "inherited"</B
+> permissions that any file created within
+ this directory would inherit.</P
+><P
+>Samba synthesises these inherited permissions for NT by
+ returning as an NT ACL the UNIX permission mode that a new file
+ created by Samba on this share would receive.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN657"
+>5.5. Modifying file or directory permissions</A
+></H1
+><P
+>Modifying file and directory permissions is as simple
+ as changing the displayed permissions in the dialog box, and
+ clicking the <B
+CLASS="COMMAND"
+>OK</B
+> button. However, there are
+ limitations that a user needs to be aware of, and also interactions
+ with the standard Samba permission masks and mapping of DOS
+ attributes that need to also be taken into account.</P
+><P
+>If the parameter <TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+>
+ is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then any attempt to set
+ security permissions will fail with an <B
+CLASS="COMMAND"
+>"Access Denied"
+ </B
+> message.</P
+><P
+>The first thing to note is that the <B
+CLASS="COMMAND"
+>"Add"</B
+>
+ button will not return a list of users in Samba 2.0.4 (it will give
+ an error message of <B
+CLASS="COMMAND"
+>"The remote procedure call failed
+ and did not execute"</B
+>). This means that you can only
+ manipulate the current user/group/world permissions listed in
+ the dialog box. This actually works quite well as these are the
+ only permissions that UNIX actually has.</P
+><P
+>If a permission triple (either user, group, or world)
+ is removed from the list of permissions in the NT dialog box,
+ then when the <B
+CLASS="COMMAND"
+>"OK"</B
+> button is pressed it will
+ be applied as "no permissions" on the UNIX side. If you then
+ view the permissions again the "no permissions" entry will appear
+ as the NT <B
+CLASS="COMMAND"
+>"O"</B
+> flag, as described above. This
+ allows you to add permissions back to a file or directory once
+ you have removed them from a triple component.</P
+><P
+>As UNIX supports only the "r", "w" and "x" bits of
+ an NT ACL then if other NT security attributes such as "Delete
+ access" are selected then they will be ignored when applied on
+ the Samba server.</P
+><P
+>When setting permissions on a directory the second
+ set of permissions (in the second set of parentheses) is
+ by default applied to all files within that directory. If this
+ is not what you want you must uncheck the <B
+CLASS="COMMAND"
+>"Replace
+ permissions on existing files"</B
+> checkbox in the NT
+ dialog before clicking <B
+CLASS="COMMAND"
+>"OK"</B
+>.</P
+><P
+>If you wish to remove all permissions from a
+ user/group/world component then you may either highlight the
+ component and click the <B
+CLASS="COMMAND"
+>"Remove"</B
+> button,
+ or set the component to only have the special <B
+CLASS="COMMAND"
+>"Take
+ Ownership"</B
+> permission (displayed as <B
+CLASS="COMMAND"
+>"O"
+ </B
+>) highlighted.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN679"
+>5.6. Interaction with the standard Samba create mask
+ parameters</A
+></H1
+><P
+>Note that with Samba 2.0.5 there are four new parameters
+ to control this interaction. These are :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory security mode</I
+></TT
+></P
+><P
+>Once a user clicks <B
+CLASS="COMMAND"
+>"OK"</B
+> to apply the
+ permissions Samba maps the given permissions into a user/group/world
+ r/w/x triple set, and then will check the changed permissions for a
+ file against the bits set in the <A
+HREF="smb.conf.5.html#SECURITYMASK"
+TARGET="_top"
+>
+ <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+> parameter. Any bits that
+ were changed that are not set to '1' in this parameter are left alone
+ in the file permissions.</P
+><P
+>Essentially, zero bits in the <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+>
+ mask may be treated as a set of bits the user is <EM
+>not</EM
+>
+ allowed to change, and one bits are those the user is allowed to change.
+ </P
+><P
+>If not set explicitly this parameter is set to the same value as
+ the <A
+HREF="smb.conf.5.html#CREATEMASK"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>create mask
+ </I
+></TT
+></A
+> parameter to provide compatibility with Samba 2.0.4
+ where this permission change facility was introduced. To allow a user to
+ modify all the user/group/world permissions on a file, set this parameter
+ to 0777.</P
+><P
+>Next Samba checks the changed permissions for a file against
+ the bits set in the <A
+HREF="smb.conf.5.html#FORCESECURITYMODE"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></A
+> parameter. Any bits
+ that were changed that correspond to bits set to '1' in this parameter
+ are forced to be set.</P
+><P
+>Essentially, bits set in the <TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+> parameter may be treated as a set of bits that, when
+ modifying security on a file, the user has always set to be 'on'.</P
+><P
+>If not set explicitly this parameter is set to the same value
+ as the <A
+HREF="smb.conf.5.html#FORCECREATEMODE"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ create mode</I
+></TT
+></A
+> parameter to provide compatibility
+ with Samba 2.0.4 where the permission change facility was introduced.
+ To allow a user to modify all the user/group/world permissions on a file
+ with no restrictions set this parameter to 000.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>force
+ security mode</I
+></TT
+> parameters are applied to the change
+ request in that order.</P
+><P
+>For a directory Samba will perform the same operations as
+ described above for a file except using the parameter <TT
+CLASS="PARAMETER"
+><I
+> directory security mask</I
+></TT
+> instead of <TT
+CLASS="PARAMETER"
+><I
+>security
+ mask</I
+></TT
+>, and <TT
+CLASS="PARAMETER"
+><I
+>force directory security mode
+ </I
+></TT
+> parameter instead of <TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+>.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+> parameter
+ by default is set to the same value as the <TT
+CLASS="PARAMETER"
+><I
+>directory mask
+ </I
+></TT
+> parameter and the <TT
+CLASS="PARAMETER"
+><I
+>force directory security
+ mode</I
+></TT
+> parameter by default is set to the same value as
+ the <TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+> parameter to provide
+ compatibility with Samba 2.0.4 where the permission change facility
+ was introduced.</P
+><P
+>In this way Samba enforces the permission restrictions that
+ an administrator can set on a Samba share, whilst still allowing users
+ to modify the permission bits within that restriction.</P
+><P
+>If you want to set up a share that allows users full control
+ in modifying the permission bits on their files and directories and
+ doesn't force any particular bits to be set 'on', then set the following
+ parameters in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+></A
+> file in that share specific section :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>security mask = 0777</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode = 0</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask = 0777</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory security mode = 0</I
+></TT
+></P
+><P
+>As described, in Samba 2.0.4 the parameters :</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>directory mask</I
+></TT
+></P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+></P
+><P
+>were used instead of the parameters discussed here.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN743"
+>5.7. Interaction with the standard Samba file attribute
+ mapping</A
+></H1
+><P
+>Samba maps some of the DOS attribute bits (such as "read
+ only") into the UNIX permissions of a file. This means there can
+ be a conflict between the permission bits set via the security
+ dialog and the permission bits set by the file attribute mapping.
+ </P
+><P
+>One way this can show up is if a file has no UNIX read access
+ for the owner it will show up as "read only" in the standard
+ file attributes tabbed dialog. Unfortunately this dialog is
+ the same one that contains the security info in another tab.</P
+><P
+>What this can mean is that if the owner changes the permissions
+ to allow themselves read access using the security dialog, clicks
+ <B
+CLASS="COMMAND"
+>"OK"</B
+> to get back to the standard attributes tab
+ dialog, and then clicks <B
+CLASS="COMMAND"
+>"OK"</B
+> on that dialog, then
+ NT will set the file permissions back to read-only (as that is what
+ the attributes still say in the dialog). This means that after setting
+ permissions and clicking <B
+CLASS="COMMAND"
+>"OK"</B
+> to get back to the
+ attributes dialog you should always hit <B
+CLASS="COMMAND"
+>"Cancel"</B
+>
+ rather than <B
+CLASS="COMMAND"
+>"OK"</B
+> to ensure that your changes
+ are not overridden.</P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="PRINTING"
+>Chapter 6. Printing Support in Samba 2.2.x</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN764"
+>6.1. Introduction</A
+></H1
+><P
+>Beginning with the 2.2.0 release, Samba supports
+the native Windows NT printing mechanisms implemented via
+MS-RPC (i.e. the SPOOLSS named pipe). Previous versions of
+Samba only supported LanMan printing calls.</P
+><P
+>The additional functionality provided by the new
+SPOOLSS support includes:</P
+><P
+></P
+><UL
+><LI
+><P
+>Support for downloading printer driver
+ files to Windows 95/98/NT/2000 clients upon demand.
+ </P
+></LI
+><LI
+><P
+>Uploading of printer drivers via the
+ Windows NT Add Printer Wizard (APW) or the
+ Imprints tool set (refer to <A
+HREF="http://imprints.sourceforge.net"
+TARGET="_top"
+>http://imprints.sourceforge.net</A
+>).
+ </P
+></LI
+><LI
+><P
+>Support for the native MS-RPC printing
+ calls such as StartDocPrinter, EnumJobs(), etc... (See
+ the MSDN documentation at <A
+HREF="http://msdn.microsoft.com/"
+TARGET="_top"
+>http://msdn.microsoft.com/</A
+>
+ for more information on the Win32 printing API)
+ </P
+></LI
+><LI
+><P
+>Support for NT Access Control Lists (ACL)
+ on printer objects</P
+></LI
+><LI
+><P
+>Improved support for printer queue manipulation
+ through the use of an internal databases for spooled job
+ information</P
+></LI
+></UL
+><P
+>There has been some initial confusion about what all this means
+and whether or not it is a requirement for printer drivers to be
+installed on a Samba host in order to support printing from Windows
+clients. A bug existed in Samba 2.2.0 which made Windows NT/2000 clients
+require that the Samba server possess a valid driver for the printer.
+This is fixed in Samba 2.2.1 and once again, Windows NT/2000 clients
+can use the local APW for installing drivers to be used with a Samba
+served printer. This is the same behavior exhibited by Windows 9x clients.
+As a side note, Samba does not use these drivers in any way to process
+spooled files. They are utilized entirely by the clients.</P
+><P
+>The following MS KB article, may be of some help if you are dealing with
+Windows 2000 clients: <EM
+>How to Add Printers with No User
+Interaction in Windows 2000</EM
+></P
+><P
+><A
+HREF="http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP"
+TARGET="_top"
+>http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN786"
+>6.2. Configuration</A
+></H1
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>[print$] vs. [printer$]</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>Previous versions of Samba recommended using a share named [printer$].
+This name was taken from the printer$ service created by Windows 9x
+clients when a printer was shared. Windows 9x printer servers always have
+a printer$ service which provides read-only access via no
+password in order to support printer driver downloads.</P
+><P
+>However, the initial implementation allowed for a
+parameter named <TT
+CLASS="PARAMETER"
+><I
+>printer driver location</I
+></TT
+>
+to be used on a per share basis to specify the location of
+the driver files associated with that printer. Another
+parameter named <TT
+CLASS="PARAMETER"
+><I
+>printer driver</I
+></TT
+> provided
+a means of defining the printer driver name to be sent to
+the client.</P
+><P
+>These parameters, including <TT
+CLASS="PARAMETER"
+><I
+>printer driver
+file</I
+></TT
+> parameter, are being depreciated and should not
+be used in new installations. For more information on this change,
+you should refer to the <A
+HREF="#MIGRATION"
+>Migration section</A
+>
+of this document.</P
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN797"
+>6.2.1. Creating [print$]</A
+></H2
+><P
+>In order to support the uploading of printer driver
+files, you must first configure a file share named [print$].
+The name of this share is hard coded in Samba's internals so
+the name is very important (print$ is the service used by
+Windows NT print servers to provide support for printer driver
+download).</P
+><P
+>You should modify the server's smb.conf file to add the global
+parameters and to create the
+following file share (of course, some of the parameter values,
+such as 'path' are arbitrary and should be replaced with
+appropriate values for your site):</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ ; members of the ntadmin group should be able
+ ; to add drivers and set printer properties
+ ; root is implicitly a 'printer admin'
+ printer admin = @ntadmin
+
+[print$]
+ path = /usr/local/samba/printers
+ guest ok = yes
+ browseable = yes
+ read only = yes
+ ; since this share is configured as read only, then we need
+ ; a 'write list'. Check the file system permissions to make
+ ; sure this account can copy files to the share. If this
+ ; is setup to a non-root account, then it should also exist
+ ; as a 'printer admin'
+ write list = @ntadmin,root</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The <A
+HREF="smb.conf.5.html#WRITELIST"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>write list</I
+></TT
+></A
+> is used to allow administrative
+level user accounts to have write access in order to update files
+on the share. See the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)
+man page</A
+> for more information on configuring file shares.</P
+><P
+>The requirement for <A
+HREF="smb.conf.5.html#GUESTOK"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>guest
+ok = yes</B
+></A
+> depends upon how your
+site is configured. If users will be guaranteed to have
+an account on the Samba host, then this is a non-issue.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Author's Note: </B
+>The non-issue is that if all your Windows NT users are guaranteed to be
+authenticated by the Samba server (such as a domain member server and the NT
+user has already been validated by the Domain Controller in
+order to logon to the Windows NT console), then guest access
+is not necessary. Of course, in a workgroup environment where
+you just want to be able to print without worrying about
+silly accounts and security, then configure the share for
+guest access. You'll probably want to add <A
+HREF="smb.conf.5.html#MAPTOGUEST"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>map to guest = Bad User</B
+></A
+> in the [global] section as well. Make sure
+you understand what this parameter does before using it
+though. --jerry</P
+></BLOCKQUOTE
+></DIV
+><P
+>In order for a Windows NT print server to support
+the downloading of driver files by multiple client architectures,
+it must create subdirectories within the [print$] service
+which correspond to each of the supported client architectures.
+Samba follows this model as well.</P
+><P
+>Next create the directory tree below the [print$] share
+for each architecture you wish to support.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[print$]-----
+ |-W32X86 ; "Windows NT x86"
+ |-WIN40 ; "Windows 95/98"
+ |-W32ALPHA ; "Windows NT Alpha_AXP"
+ |-W32MIPS ; "Windows NT R4000"
+ |-W32PPC ; "Windows NT PowerPC"</PRE
+></TD
+></TR
+></TABLE
+></P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>ATTENTION! REQUIRED PERMISSIONS</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>In order to currently add a new driver to you Samba host,
+one of two conditions must hold true:</P
+><P
+></P
+><UL
+><LI
+><P
+>The account used to connect to the Samba host
+ must have a uid of 0 (i.e. a root account)</P
+></LI
+><LI
+><P
+>The account used to connect to the Samba host
+ must be a member of the <A
+HREF="smb.conf.5.html#PRINTERADMIN"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>printer
+ admin</I
+></TT
+></A
+> list.</P
+></LI
+></UL
+><P
+>Of course, the connected account must still possess access
+to add files to the subdirectories beneath [print$]. Remember
+that all file shares are set to 'read only' by default.</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>Once you have created the required [print$] service and
+associated subdirectories, simply log onto the Samba server using
+a root (or <TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+>) account
+from a Windows NT 4.0 client. Navigate to the "Printers" folder
+on the Samba server. You should see an initial listing of printers
+that matches the printer shares defined on your Samba host.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN832"
+>6.2.2. Setting Drivers for Existing Printers</A
+></H2
+><P
+>The initial listing of printers in the Samba host's
+Printers folder will have no real printer driver assigned
+to them. By default, in Samba 2.2.0 this driver name was set to
+<EM
+>NO PRINTER DRIVER AVAILABLE FOR THIS PRINTER</EM
+>.
+Later versions changed this to a NULL string to allow the use
+tof the local Add Printer Wizard on NT/2000 clients.
+Attempting to view the printer properties for a printer
+which has this default driver assigned will result in
+the error message:</P
+><P
+><EM
+>Device settings cannot be displayed. The driver
+for the specified printer is not installed, only spooler
+properties will be displayed. Do you want to install the
+driver now?</EM
+></P
+><P
+>Click "No" in the error dialog and you will be presented with
+the printer properties window. The way assign a driver to a
+printer is to either</P
+><P
+></P
+><UL
+><LI
+><P
+>Use the "New Driver..." button to install
+ a new printer driver, or</P
+></LI
+><LI
+><P
+>Select a driver from the popup list of
+ installed drivers. Initially this list will be empty.</P
+></LI
+></UL
+><P
+>If you wish to install printer drivers for client
+operating systems other than "Windows NT x86", you will need
+to use the "Sharing" tab of the printer properties dialog.</P
+><P
+>Assuming you have connected with a root account, you
+will also be able modify other printer properties such as
+ACLs and device settings using this dialog box.</P
+><P
+>A few closing comments for this section, it is possible
+on a Windows NT print server to have printers
+listed in the Printers folder which are not shared. Samba does
+not make this distinction. By definition, the only printers of
+which Samba is aware are those which are specified as shares in
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.</P
+><P
+>Another interesting side note is that Windows NT clients do
+not use the SMB printer share, but rather can print directly
+to any printer on another Windows NT host using MS-RPC. This
+of course assumes that the printing client has the necessary
+privileges on the remote host serving the printer. The default
+permissions assigned by Windows NT to a printer gives the "Print"
+permissions to the "Everyone" well-known group.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN849"
+>6.2.3. Support a large number of printers</A
+></H2
+><P
+>One issue that has arisen during the development
+phase of Samba 2.2 is the need to support driver downloads for
+100's of printers. Using the Windows NT APW is somewhat
+awkward to say the list. If more than one printer are using the
+same driver, the <A
+HREF="rpcclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>rpcclient's
+setdriver command</B
+></A
+> can be used to set the driver
+associated with an installed driver. The following is example
+of how this could be accomplished:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret -c "enumdrivers"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+
+[Windows NT x86]
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4000 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 2100 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4Si/4SiMX PS]
+
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret -c "enumprinters"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+ flags:[0x800000]
+ name:[\\POGO\hp-print]
+ description:[POGO\\POGO\hp-print,NO DRIVER AVAILABLE FOR THIS PRINTER,]
+ comment:[]
+
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret \
+<TT
+CLASS="PROMPT"
+>&#62; </TT
+> -c "setdriver hp-print \"HP LaserJet 4000 Series PS\""
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+Successfully set hp-print to driver HP LaserJet 4000 Series PS.</PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN860"
+>6.2.4. Adding New Printers via the Windows NT APW</A
+></H2
+><P
+>By default, Samba offers all printer shares defined in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+in the "Printers..." folder. Also existing in this folder is the Windows NT
+Add Printer Wizard icon. The APW will be show only if</P
+><P
+></P
+><UL
+><LI
+><P
+>The connected user is able to successfully
+ execute an OpenPrinterEx(\\server) with administrative
+ privileges (i.e. root or <TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+>).
+ </P
+></LI
+><LI
+><P
+><A
+HREF="smb.conf.5.html#SHOWADDPRINTERWIZARD"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>show
+ add printer wizard = yes</I
+></TT
+></A
+> (the default).
+ </P
+></LI
+></UL
+><P
+>In order to be able to use the APW to successfully add a printer to a Samba
+server, the <A
+HREF="smb.conf.5.html#ADDPRINTERCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>add
+printer command</I
+></TT
+></A
+> must have a defined value. The program
+hook must successfully add the printer to the system (i.e.
+<TT
+CLASS="FILENAME"
+>/etc/printcap</TT
+> or appropriate files) and
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> if necessary.</P
+><P
+>When using the APW from a client, if the named printer share does
+not exist, <B
+CLASS="COMMAND"
+>smbd</B
+> will execute the <TT
+CLASS="PARAMETER"
+><I
+>add printer
+command</I
+></TT
+> and reparse to the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+to attempt to locate the new printer share. If the share is still not defined,
+an error of "Access Denied" is returned to the client. Note that the
+<TT
+CLASS="PARAMETER"
+><I
+>add printer program</I
+></TT
+> is executed under the context
+of the connected user, not necessarily a root account.</P
+><P
+>There is a complementing <A
+HREF="smb.conf.5.html#DELETEPRINTERCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>delete
+printer command</I
+></TT
+></A
+> for removing entries from the "Printers..."
+folder.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN885"
+>6.2.5. Samba and Printer Ports</A
+></H2
+><P
+>Windows NT/2000 print servers associate a port with each printer. These normally
+take the form of LPT1:, COM1:, FILE:, etc... Samba must also support the
+concept of ports associated with a printer. By default, only one printer port,
+named "Samba Printer Port", exists on a system. Samba does not really a port in
+order to print, rather it is a requirement of Windows clients. </P
+><P
+>Note that Samba does not support the concept of "Printer Pooling" internally
+either. This is when a logical printer is assigned to multiple ports as
+a form of load balancing or fail over.</P
+><P
+>If you require that multiple ports be defined for some reason,
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> possesses a <A
+HREF="smb.conf.5.html#ENUMPORTSCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>enumports
+command</I
+></TT
+></A
+> which can be used to define an external program
+that generates a listing of ports on a system.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN893"
+>6.3. The Imprints Toolset</A
+></H1
+><P
+>The Imprints tool set provides a UNIX equivalent of the
+ Windows NT Add Printer Wizard. For complete information, please
+ refer to the Imprints web site at <A
+HREF="http://imprints.sourceforge.net/"
+TARGET="_top"
+> http://imprints.sourceforge.net/</A
+> as well as the documentation
+ included with the imprints source distribution. This section will
+ only provide a brief introduction to the features of Imprints.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN897"
+>6.3.1. What is Imprints?</A
+></H2
+><P
+>Imprints is a collection of tools for supporting the goals
+ of</P
+><P
+></P
+><UL
+><LI
+><P
+>Providing a central repository information
+ regarding Windows NT and 95/98 printer driver packages</P
+></LI
+><LI
+><P
+>Providing the tools necessary for creating
+ the Imprints printer driver packages.</P
+></LI
+><LI
+><P
+>Providing an installation client which
+ will obtain and install printer drivers on remote Samba
+ and Windows NT 4 print servers.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN907"
+>6.3.2. Creating Printer Driver Packages</A
+></H2
+><P
+>The process of creating printer driver packages is beyond
+ the scope of this document (refer to Imprints.txt also included
+ with the Samba distribution for more information). In short,
+ an Imprints driver package is a gzipped tarball containing the
+ driver files, related INF files, and a control file needed by the
+ installation client.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN910"
+>6.3.3. The Imprints server</A
+></H2
+><P
+>The Imprints server is really a database server that
+ may be queried via standard HTTP mechanisms. Each printer
+ entry in the database has an associated URL for the actual
+ downloading of the package. Each package is digitally signed
+ via GnuPG which can be used to verify that package downloaded
+ is actually the one referred in the Imprints database. It is
+ <EM
+>not</EM
+> recommended that this security check
+ be disabled.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN914"
+>6.3.4. The Installation Client</A
+></H2
+><P
+>More information regarding the Imprints installation client
+ is available in the <TT
+CLASS="FILENAME"
+>Imprints-Client-HOWTO.ps</TT
+>
+ file included with the imprints source package.</P
+><P
+>The Imprints installation client comes in two forms.</P
+><P
+></P
+><UL
+><LI
+><P
+>a set of command line Perl scripts</P
+></LI
+><LI
+><P
+>a GTK+ based graphical interface to
+ the command line perl scripts</P
+></LI
+></UL
+><P
+>The installation client (in both forms) provides a means
+ of querying the Imprints database server for a matching
+ list of known printer model names as well as a means to
+ download and install the drivers on remote Samba and Windows
+ NT print servers.</P
+><P
+>The basic installation process is in four steps and
+ perl code is wrapped around <B
+CLASS="COMMAND"
+>smbclient</B
+>
+ and <B
+CLASS="COMMAND"
+>rpcclient</B
+>.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>
+foreach (supported architecture for a given driver)
+{
+ 1. rpcclient: Get the appropriate upload directory
+ on the remote server
+ 2. smbclient: Upload the driver files
+ 3. rpcclient: Issues an AddPrinterDriver() MS-RPC
+}
+
+4. rpcclient: Issue an AddPrinterEx() MS-RPC to actually
+ create the printer</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>One of the problems encountered when implementing
+ the Imprints tool set was the name space issues between
+ various supported client architectures. For example, Windows
+ NT includes a driver named "Apple LaserWriter II NTX v51.8"
+ and Windows 95 calls its version of this driver "Apple
+ LaserWriter II NTX"</P
+><P
+>The problem is how to know what client drivers have
+ been uploaded for a printer. As astute reader will remember
+ that the Windows NT Printer Properties dialog only includes
+ space for one printer driver name. A quick look in the
+ Windows NT 4.0 system registry at</P
+><P
+><TT
+CLASS="FILENAME"
+>HKLM\System\CurrentControlSet\Control\Print\Environment
+ </TT
+></P
+><P
+>will reveal that Windows NT always uses the NT driver
+ name. This is ok as Windows NT always requires that at least
+ the Windows NT version of the printer driver is present.
+ However, Samba does not have the requirement internally.
+ Therefore, how can you use the NT driver name if is has not
+ already been installed?</P
+><P
+>The way of sidestepping this limitation is to require
+ that all Imprints printer driver packages include both the Intel
+ Windows NT and 95/98 printer drivers and that NT driver is
+ installed first.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN936"
+>6.4. <A
+NAME="MIGRATION"
+></A
+>Migration to from Samba 2.0.x to 2.2.x</A
+></H1
+><P
+>Given that printer driver management has changed (we hope improved) in
+2.2 over prior releases, migration from an existing setup to 2.2 can
+follow several paths. Here are the possible scenarios for
+migration:</P
+><P
+></P
+><UL
+><LI
+><P
+>If you do not desire the new Windows NT
+ print driver support, nothing needs to be done.
+ All existing parameters work the same.</P
+></LI
+><LI
+><P
+>If you want to take advantage of NT printer
+ driver support but do not want to migrate the
+ 9x drivers to the new setup, the leave the existing
+ <TT
+CLASS="FILENAME"
+>printers.def</TT
+> file. When smbd attempts
+ to locate a
+ 9x driver for the printer in the TDB and fails it
+ will drop down to using the printers.def (and all
+ associated parameters). The <B
+CLASS="COMMAND"
+>make_printerdef</B
+>
+ tool will also remain for backwards compatibility but will
+ be removed in the next major release.</P
+></LI
+><LI
+><P
+>If you install a Windows 9x driver for a printer
+ on your Samba host (in the printing TDB), this information will
+ take precedence and the three old printing parameters
+ will be ignored (including print driver location).</P
+></LI
+><LI
+><P
+>If you want to migrate an existing <TT
+CLASS="FILENAME"
+>printers.def</TT
+>
+ file into the new setup, the current only solution is to use the Windows
+ NT APW to install the NT drivers and the 9x drivers. This can be scripted
+ using <B
+CLASS="COMMAND"
+>smbclient</B
+> and <B
+CLASS="COMMAND"
+>rpcclient</B
+>. See the
+ Imprints installation client at <A
+HREF="http://imprints.sourceforge.net/"
+TARGET="_top"
+>http://imprints.sourceforge.net/</A
+>
+ for an example.
+ </P
+></LI
+></UL
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Achtung!</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>The following <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> parameters are considered to
+be deprecated and will be removed soon. Do not use them in new
+installations</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver file (G)</I
+></TT
+>
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver (S)</I
+></TT
+>
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver location (S)</I
+></TT
+>
+ </P
+></LI
+></UL
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>The have been two new parameters add in Samba 2.2.2 to for
+better support of Samba 2.0.x backwards capability (<TT
+CLASS="PARAMETER"
+><I
+>disable
+spoolss</I
+></TT
+>) and for using local printers drivers on Windows
+NT/2000 clients (<TT
+CLASS="PARAMETER"
+><I
+>use client driver</I
+></TT
+>). Both of
+these options are described in the smb.coinf(5) man page and are
+disabled by default.</P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="DOMAIN-SECURITY"
+>Chapter 7. security = domain in Samba 2.x</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN990"
+>7.1. Joining an NT Domain with Samba 2.2</A
+></H1
+><P
+>Assume you have a Samba 2.x server with a NetBIOS name of
+ <TT
+CLASS="CONSTANT"
+>SERV1</TT
+> and are joining an NT domain called
+ <TT
+CLASS="CONSTANT"
+>DOM</TT
+>, which has a PDC with a NetBIOS name
+ of <TT
+CLASS="CONSTANT"
+>DOMPDC</TT
+> and two backup domain controllers
+ with NetBIOS names <TT
+CLASS="CONSTANT"
+>DOMBDC1</TT
+> and <TT
+CLASS="CONSTANT"
+>DOMBDC2
+ </TT
+>.</P
+><P
+>In order to join the domain, first stop all Samba daemons
+ and run the command:</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbpasswd -j DOM -r DOMPDC
+ -U<TT
+CLASS="REPLACEABLE"
+><I
+>Administrator%password</I
+></TT
+></B
+></TT
+></P
+><P
+>as we are joining the domain DOM and the PDC for that domain
+ (the only machine that has write access to the domain SAM database)
+ is DOMPDC. The <TT
+CLASS="REPLACEABLE"
+><I
+>Administrator%password</I
+></TT
+> is
+ the login name and password for an account which has the necessary
+ privilege to add machines to the domain. If this is successful
+ you will see the message:</P
+><P
+><TT
+CLASS="COMPUTEROUTPUT"
+>smbpasswd: Joined domain DOM.</TT
+>
+ </P
+><P
+>in your terminal window. See the <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+> smbpasswd(8)</A
+> man page for more details.</P
+><P
+>There is existing development code to join a domain
+ without having to create the machine trust account on the PDC
+ beforehand. This code will hopefully be available soon
+ in release branches as well.</P
+><P
+>This command goes through the machine account password
+ change protocol, then writes the new (random) machine account
+ password for this Samba server into a file in the same directory
+ in which an smbpasswd file would be stored - normally :</P
+><P
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/private</TT
+></P
+><P
+>In Samba 2.0.x, the filename looks like this:</P
+><P
+><TT
+CLASS="FILENAME"
+><TT
+CLASS="REPLACEABLE"
+><I
+>&#60;NT DOMAIN NAME&#62;</I
+></TT
+>.<TT
+CLASS="REPLACEABLE"
+><I
+>&#60;Samba
+ Server Name&#62;</I
+></TT
+>.mac</TT
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>.mac</TT
+> suffix stands for machine account
+ password file. So in our example above, the file would be called:</P
+><P
+><TT
+CLASS="FILENAME"
+>DOM.SERV1.mac</TT
+></P
+><P
+>In Samba 2.2, this file has been replaced with a TDB
+ (Trivial Database) file named <TT
+CLASS="FILENAME"
+>secrets.tdb</TT
+>.
+ </P
+><P
+>This file is created and owned by root and is not
+ readable by any other user. It is the key to the domain-level
+ security for your system, and should be treated as carefully
+ as a shadow password file.</P
+><P
+>Now, before restarting the Samba daemons you must
+ edit your <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ </A
+> file to tell Samba it should now use domain security.</P
+><P
+>Change (or add) your <A
+HREF="smb.conf.5.html#SECURITY"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>security =</I
+></TT
+></A
+> line in the [global] section
+ of your smb.conf to read:</P
+><P
+><B
+CLASS="COMMAND"
+>security = domain</B
+></P
+><P
+>Next change the <A
+HREF="smb.conf.5.html#WORKGROUP"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> workgroup =</I
+></TT
+></A
+> line in the [global] section to read: </P
+><P
+><B
+CLASS="COMMAND"
+>workgroup = DOM</B
+></P
+><P
+>as this is the name of the domain we are joining. </P
+><P
+>You must also have the parameter <A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>encrypt passwords</I
+></TT
+></A
+> set to <TT
+CLASS="CONSTANT"
+>yes
+ </TT
+> in order for your users to authenticate to the NT PDC.</P
+><P
+>Finally, add (or modify) a <A
+HREF="smb.conf.5.html#PASSWORDSERVER"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>password server =</I
+></TT
+></A
+> line in the [global]
+ section to read: </P
+><P
+><B
+CLASS="COMMAND"
+>password server = DOMPDC DOMBDC1 DOMBDC2</B
+></P
+><P
+>These are the primary and backup domain controllers Samba
+ will attempt to contact in order to authenticate users. Samba will
+ try to contact each of these servers in order, so you may want to
+ rearrange this list in order to spread out the authentication load
+ among domain controllers.</P
+><P
+>Alternatively, if you want smbd to automatically determine
+ the list of Domain controllers to use for authentication, you may
+ set this line to be :</P
+><P
+><B
+CLASS="COMMAND"
+>password server = *</B
+></P
+><P
+>This method, which was introduced in Samba 2.0.6,
+ allows Samba to use exactly the same mechanism that NT does. This
+ method either broadcasts or uses a WINS database in order to
+ find domain controllers to authenticate against.</P
+><P
+>Finally, restart your Samba daemons and get ready for
+ clients to begin using domain security!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1054"
+>7.2. Samba and Windows 2000 Domains</A
+></H1
+><P
+>Many people have asked regarding the state of Samba's ability to participate in
+a Windows 2000 Domain. Samba 2.2 is able to act as a member server of a Windows
+2000 domain operating in mixed or native mode.</P
+><P
+>There is much confusion between the circumstances that require a "mixed" mode
+Win2k DC and a when this host can be switched to "native" mode. A "mixed" mode
+Win2k domain controller is only needed if Windows NT BDCs must exist in the same
+domain. By default, a Win2k DC in "native" mode will still support
+NetBIOS and NTLMv1 for authentication of legacy clients such as Windows 9x and
+NT 4.0. Samba has the same requirements as a Windows NT 4.0 member server.</P
+><P
+>The steps for adding a Samba 2.2 host to a Win2k domain are the same as those
+for adding a Samba server to a Windows NT 4.0 domain. The only exception is that
+the "Server Manager" from NT 4 has been replaced by the "Active Directory Users and
+Computers" MMC (Microsoft Management Console) plugin.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1059"
+>7.3. Why is this better than security = server?</A
+></H1
+><P
+>Currently, domain security in Samba doesn't free you from
+ having to create local Unix users to represent the users attaching
+ to your server. This means that if domain user <TT
+CLASS="CONSTANT"
+>DOM\fred
+ </TT
+> attaches to your domain security Samba server, there needs
+ to be a local Unix user fred to represent that user in the Unix
+ filesystem. This is very similar to the older Samba security mode
+ <A
+HREF="smb.conf.5.html#SECURITYEQUALSSERVER"
+TARGET="_top"
+>security = server</A
+>,
+ where Samba would pass through the authentication request to a Windows
+ NT server in the same way as a Windows 95 or Windows 98 server would.
+ </P
+><P
+>Please refer to the <A
+HREF="winbind.html"
+TARGET="_top"
+>Winbind
+ paper</A
+> for information on a system to automatically
+ assign UNIX uids and gids to Windows NT Domain users and groups.
+ This code is available in development branches only at the moment,
+ but will be moved to release branches soon.</P
+><P
+>The advantage to domain-level security is that the
+ authentication in domain-level security is passed down the authenticated
+ RPC channel in exactly the same way that an NT server would do it. This
+ means Samba servers now participate in domain trust relationships in
+ exactly the same way NT servers do (i.e., you can add Samba servers into
+ a resource domain and have the authentication passed on from a resource
+ domain PDC to an account domain PDC.</P
+><P
+>In addition, with <B
+CLASS="COMMAND"
+>security = server</B
+> every Samba
+ daemon on a server has to keep a connection open to the
+ authenticating server for as long as that daemon lasts. This can drain
+ the connection resources on a Microsoft NT server and cause it to run
+ out of available connections. With <B
+CLASS="COMMAND"
+>security = domain</B
+>,
+ however, the Samba daemons connect to the PDC/BDC only for as long
+ as is necessary to authenticate the user, and then drop the connection,
+ thus conserving PDC connection resources.</P
+><P
+>And finally, acting in the same manner as an NT server
+ authenticating to a PDC means that as part of the authentication
+ reply, the Samba server gets the user identification information such
+ as the user SID, the list of NT groups the user belongs to, etc. All
+ this information will allow Samba to be extended in the future into
+ a mode the developers currently call appliance mode. In this mode,
+ no local Unix users will be necessary, and Samba will generate Unix
+ uids and gids from the information passed back from the PDC when a
+ user is authenticated, making a Samba server truly plug and play
+ in an NT domain environment. Watch for this code soon.</P
+><P
+><EM
+>NOTE:</EM
+> Much of the text of this document
+ was first published in the Web magazine <A
+HREF="http://www.linuxworld.com"
+TARGET="_top"
+>
+ LinuxWorld</A
+> as the article <A
+HREF="http://www.linuxworld.com/linuxworld/lw-1998-10/lw-10-samba.html"
+TARGET="_top"
+>Doing
+ the NIS/NT Samba</A
+>.</P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="SAMBA-PDC"
+>Chapter 8. How to Configure Samba 2.2 as a Primary Domain Controller</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN1092"
+>8.1. Prerequisite Reading</A
+></H1
+><P
+>Before you continue reading in this chapter, please make sure
+that you are comfortable with configuring basic files services
+in smb.conf and how to enable and administer password
+encryption in Samba. Theses two topics are covered in the
+<A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+>
+manpage and the <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>Encryption chapter</A
+>
+of this HOWTO Collection.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1098"
+>8.2. Background</A
+></H1
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+><EM
+>Author's Note:</EM
+> This document is a combination
+of David Bannon's "Samba 2.2 PDC HOWTO" and "Samba NT Domain FAQ".
+Both documents are superseded by this one.</P
+></BLOCKQUOTE
+></DIV
+><P
+>Versions of Samba prior to release 2.2 had marginal capabilities to act
+as a Windows NT 4.0 Primary Domain Controller
+
+(PDC). With Samba 2.2.0, we are proud to announce official support for
+Windows NT 4.0-style domain logons from Windows NT 4.0 and Windows
+2000 clients. This article outlines the steps
+necessary for configuring Samba as a PDC. It is necessary to have a
+working Samba server prior to implementing the PDC functionality. If
+you have not followed the steps outlined in <A
+HREF="UNIX_INSTALL.html"
+TARGET="_top"
+> UNIX_INSTALL.html</A
+>, please make sure
+that your server is configured correctly before proceeding. Another
+good resource in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5) man
+page</A
+>. The following functionality should work in 2.2:</P
+><P
+></P
+><UL
+><LI
+><P
+> domain logons for Windows NT 4.0/2000 clients.
+ </P
+></LI
+><LI
+><P
+> placing a Windows 9x client in user level security
+ </P
+></LI
+><LI
+><P
+> retrieving a list of users and groups from a Samba PDC to
+ Windows 9x/NT/2000 clients
+ </P
+></LI
+><LI
+><P
+> roving (roaming) user profiles
+ </P
+></LI
+><LI
+><P
+> Windows NT 4.0-style system policies
+ </P
+></LI
+></UL
+><P
+>The following pieces of functionality are not included in the 2.2 release:</P
+><P
+></P
+><UL
+><LI
+><P
+> Windows NT 4 domain trusts
+ </P
+></LI
+><LI
+><P
+> SAM replication with Windows NT 4.0 Domain Controllers
+ (i.e. a Samba PDC and a Windows NT BDC or vice versa)
+ </P
+></LI
+><LI
+><P
+> Adding users via the User Manager for Domains
+ </P
+></LI
+><LI
+><P
+> Acting as a Windows 2000 Domain Controller (i.e. Kerberos and
+ Active Directory)
+ </P
+></LI
+></UL
+><P
+>Please note that Windows 9x clients are not true members of a domain
+for reasons outlined in this article. Therefore the protocol for
+support Windows 9x-style domain logons is completely different
+from NT4 domain logons and has been officially supported for some
+time.</P
+><P
+>Implementing a Samba PDC can basically be divided into 2 broad
+steps.</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> Configuring the Samba PDC
+ </P
+></LI
+><LI
+><P
+> Creating machine trust accounts and joining clients
+ to the domain
+ </P
+></LI
+></OL
+><P
+>There are other minor details such as user profiles, system
+policies, etc... However, these are not necessarily specific
+to a Samba PDC as much as they are related to Windows NT networking
+concepts. They will be mentioned only briefly here.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1137"
+>8.3. Configuring the Samba Domain Controller</A
+></H1
+><P
+>The first step in creating a working Samba PDC is to
+understand the parameters necessary in smb.conf. I will not
+attempt to re-explain the parameters here as they are more that
+adequately covered in <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> the smb.conf
+man page</A
+>. For convenience, the parameters have been
+linked with the actual smb.conf description.</P
+><P
+>Here is an example <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> for acting as a PDC:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ ; Basic server settings
+ <A
+HREF="smb.conf.5.html#NETBIOSNAME"
+TARGET="_top"
+>netbios name</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>POGO</I
+></TT
+>
+ <A
+HREF="smb.conf.5.html#WORKGROUP"
+TARGET="_top"
+>workgroup</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>NARNIA</I
+></TT
+>
+
+ ; we should act as the domain and local master browser
+ <A
+HREF="smb.conf.5.html#OSLEVEL"
+TARGET="_top"
+>os level</A
+> = 64
+ <A
+HREF="smb.conf.5.html#PERFERREDMASTER"
+TARGET="_top"
+>preferred master</A
+> = yes
+ <A
+HREF="smb.conf.5.html#DOMAINMASTER"
+TARGET="_top"
+>domain master</A
+> = yes
+ <A
+HREF="smb.conf.5.html#LOCALMASTER"
+TARGET="_top"
+>local master</A
+> = yes
+
+ ; security settings (must user security = user)
+ <A
+HREF="smb.conf.5.html#SECURITYEQUALSUSER"
+TARGET="_top"
+>security</A
+> = user
+
+ ; encrypted passwords are a requirement for a PDC
+ <A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+>encrypt passwords</A
+> = yes
+
+ ; support domain logons
+ <A
+HREF="smb.conf.5.html#DOMAINLOGONS"
+TARGET="_top"
+>domain logons</A
+> = yes
+
+ ; where to store user profiles?
+ <A
+HREF="smb.conf.5.html#LOGONPATH"
+TARGET="_top"
+>logon path</A
+> = \\%N\profiles\%u
+
+ ; where is a user's home directory and where should it
+ ; be mounted at?
+ <A
+HREF="smb.conf.5.html#LOGONDRIVE"
+TARGET="_top"
+>logon drive</A
+> = H:
+ <A
+HREF="smb.conf.5.html#LOGONHOME"
+TARGET="_top"
+>logon home</A
+> = \\homeserver\%u
+
+ ; specify a generic logon script for all users
+ ; this is a relative **DOS** path to the [netlogon] share
+ <A
+HREF="smb.conf.5.html#LOGONSCRIPT"
+TARGET="_top"
+>logon script</A
+> = logon.cmd
+
+; necessary share for domain controller
+[netlogon]
+ <A
+HREF="smb.conf.5.html#PATH"
+TARGET="_top"
+>path</A
+> = /usr/local/samba/lib/netlogon
+ <A
+HREF="smb.conf.5.html#READONLY"
+TARGET="_top"
+>read only</A
+> = yes
+ <A
+HREF="smb.conf.5.html#WRITELIST"
+TARGET="_top"
+>write list</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>ntadmin</I
+></TT
+>
+
+; share for storing user profiles
+[profiles]
+ <A
+HREF="smb.conf.5.html#PATH"
+TARGET="_top"
+>path</A
+> = /export/smb/ntprofile
+ <A
+HREF="smb.conf.5.html#READONLY"
+TARGET="_top"
+>read only</A
+> = no
+ <A
+HREF="smb.conf.5.html#CREATEMASK"
+TARGET="_top"
+>create mask</A
+> = 0600
+ <A
+HREF="smb.conf.5.html#DIRECTORYMASK"
+TARGET="_top"
+>directory mask</A
+> = 0700</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>There are a couple of points to emphasize in the above configuration.</P
+><P
+></P
+><UL
+><LI
+><P
+> Encrypted passwords must be enabled. For more details on how
+ to do this, refer to <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>ENCRYPTION.html</A
+>.
+ </P
+></LI
+><LI
+><P
+> The server must support domain logons and a
+ <TT
+CLASS="FILENAME"
+>[netlogon]</TT
+> share
+ </P
+></LI
+><LI
+><P
+> The server must be the domain master browser in order for Windows
+ client to locate the server as a DC. Please refer to the various
+ Network Browsing documentation included with this distribution for
+ details.
+ </P
+></LI
+></UL
+><P
+>As Samba 2.2 does not offer a complete implementation of group mapping
+between Windows NT groups and Unix groups (this is really quite
+complicated to explain in a short space), you should refer to the
+<A
+HREF="smb.conf.5.html#DOMAINADMINGROUP"
+TARGET="_top"
+>domain admin
+group</A
+> smb.conf parameter for information of creating "Domain
+Admins" style accounts.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1180"
+>8.4. Creating Machine Trust Accounts and Joining Clients to the
+Domain</A
+></H1
+><P
+>A machine trust account is a Samba account that is used to
+authenticate a client machine (rather than a user) to the Samba
+server. In Windows terminology, this is known as a "Computer
+Account."</P
+><P
+>The password of a machine trust account acts as the shared secret for
+secure communication with the Domain Controller. This is a security
+feature to prevent an unauthorized machine with the same NetBIOS name
+from joining the domain and gaining access to domain user/group
+accounts. Windows NT and 2000 clients use machine trust accounts, but
+Windows 9x clients do not. Hence, a Windows 9x client is never a true
+member of a domain because it does not possess a machine trust
+account, and thus has no shared secret with the domain controller.</P
+><P
+>A Windows PDC stores each machine trust account in the Windows
+Registry. A Samba PDC, however, stores each machine trust account
+in two parts, as follows:
+
+<P
+></P
+><UL
+><LI
+><P
+>A Samba account, stored in the same location as user
+ LanMan and NT password hashes (currently
+ <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+>). The Samba account
+ possesses and uses only the NT password hash.</P
+></LI
+><LI
+><P
+>A corresponding Unix account, typically stored in
+ <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>. (Future releases will alleviate the need to
+ create <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entries.) </P
+></LI
+></UL
+></P
+><P
+>There are two ways to create machine trust accounts:</P
+><P
+></P
+><UL
+><LI
+><P
+> Manual creation. Both the Samba and corresponding
+ Unix account are created by hand.</P
+></LI
+><LI
+><P
+> "On-the-fly" creation. The Samba machine trust
+ account is automatically created by Samba at the time the client
+ is joined to the domain. (For security, this is the
+ recommended method.) The corresponding Unix account may be
+ created automatically or manually. </P
+></LI
+></UL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1199"
+>8.4.1. Manual Creation of Machine Trust Accounts</A
+></H2
+><P
+>The first step in manually creating a machine trust account is to
+manually create the corresponding Unix account in
+<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>. This can be done using
+<B
+CLASS="COMMAND"
+>vipw</B
+> or other 'add user' command that is normally
+used to create new Unix accounts. The following is an example for a
+Linux based Samba server:</P
+><P
+> <TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>/usr/sbin/useradd -g 100 -d /dev/null -c <TT
+CLASS="REPLACEABLE"
+><I
+>"machine
+nickname"</I
+></TT
+> -s /bin/false <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+>$ </B
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>passwd -l <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+>$</B
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry will list the machine name
+with a "$" appended, won't have a password, will have a null shell and no
+home directory. For example a machine named 'doppy' would have an
+<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>doppy$:x:505:501:<TT
+CLASS="REPLACEABLE"
+><I
+>machine_nickname</I
+></TT
+>:/dev/null:/bin/false</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Above, <TT
+CLASS="REPLACEABLE"
+><I
+>machine_nickname</I
+></TT
+> can be any
+descriptive name for the client, i.e., BasementComputer.
+<TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+> absolutely must be the NetBIOS
+name of the client to be joined to the domain. The "$" must be
+appended to the NetBIOS name of the client or Samba will not recognize
+this as a machine trust account.</P
+><P
+>Now that the corresponding Unix account has been created, the next step is to create
+the Samba account for the client containing the well-known initial
+machine trust account password. This can be done using the <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+> command
+as shown here:</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>smbpasswd -a -m <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+></B
+></P
+><P
+>where <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+> is the machine's NetBIOS
+name. The RID of the new machine account is generated from the UID of
+the corresponding Unix account.</P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Join the client to the domain immediately</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+> Manually creating a machine trust account using this method is the
+ equivalent of creating a machine trust account on a Windows NT PDC using
+ the "Server Manager". From the time at which the account is created
+ to the time which the client joins the domain and changes the password,
+ your domain is vulnerable to an intruder joining your domain using a
+ a machine with the same NetBIOS name. A PDC inherently trusts
+ members of the domain and will serve out a large degree of user
+ information to such clients. You have been warned!
+ </P
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1234"
+>8.4.2. "On-the-Fly" Creation of Machine Trust Accounts</A
+></H2
+><P
+>The second (and recommended) way of creating machine trust accounts is
+simply to allow the Samba server to create them as needed when the client
+is joined to the domain. </P
+><P
+>Since each Samba machine trust account requires a corresponding
+Unix account, a method for automatically creating the
+Unix account is usually supplied; this requires configuration of the
+<A
+HREF="smb.conf.5.html#ADDUSERSCRIPT"
+TARGET="_top"
+>add user script</A
+>
+option in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>. This
+method is not required, however; corresponding Unix accounts may also
+be created manually.</P
+><P
+>Below is an example for a RedHat 6.2 Linux system.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ # &#60;...remainder of parameters...&#62;
+ add user script = /usr/sbin/useradd -d /dev/null -g 100 -s /bin/false -M %u </PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1243"
+>8.4.3. Joining the Client to the Domain</A
+></H2
+><P
+>The procedure for joining a client to the domain varies with the
+version of Windows.</P
+><P
+></P
+><UL
+><LI
+><P
+><EM
+>Windows 2000</EM
+></P
+><P
+> When the user elects to join the client to a domain, Windows prompts for
+ an account and password that is privileged to join the domain. A
+ Samba administrative account (i.e., a Samba account that has root
+ privileges on the Samba server) must be entered here; the
+ operation will fail if an ordinary user account is given.
+ The password for this account should be
+ set to a different password than the associated
+ <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry, for security
+ reasons. </P
+><P
+>The session key of the Samba administrative account acts as an
+ encryption key for setting the password of the machine trust
+ account. The machine trust account will be created on-the-fly, or
+ updated if it already exists.</P
+></LI
+><LI
+><P
+><EM
+>Windows NT</EM
+></P
+><P
+> If the machine trust account was created manually, on the
+ Identification Changes menu enter the domain name, but do not
+ check the box "Create a Computer Account in the Domain." In this case,
+ the existing machine trust account is used to join the machine to
+ the domain.</P
+><P
+> If the machine trust account is to be created
+ on-the-fly, on the Identification Changes menu enter the domain
+ name, and check the box "Create a Computer Account in the Domain." In
+ this case, joining the domain proceeds as above for Windows 2000
+ (i.e., you must supply a Samba administrative account when
+ prompted).</P
+></LI
+></UL
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1258"
+>8.5. Common Problems and Errors</A
+></H1
+><P
+></P
+><P
+></P
+><UL
+><LI
+><P
+> <EM
+>I cannot include a '$' in a machine name.</EM
+>
+ </P
+><P
+> A 'machine name' in (typically) <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>
+ of the machine name with a '$' appended. FreeBSD (and other BSD
+ systems?) won't create a user with a '$' in their name.
+ </P
+><P
+> The problem is only in the program used to make the entry, once
+ made, it works perfectly. So create a user without the '$' and
+ use <B
+CLASS="COMMAND"
+>vipw</B
+> to edit the entry, adding the '$'. Or create
+ the whole entry with vipw if you like, make sure you use a
+ unique User ID !
+ </P
+></LI
+><LI
+><P
+> <EM
+>I get told "You already have a connection to the Domain...."
+ or "Cannot join domain, the credentials supplied conflict with an
+ existing set.." when creating a machine trust account.</EM
+>
+ </P
+><P
+> This happens if you try to create a machine trust account from the
+ machine itself and already have a connection (e.g. mapped drive)
+ to a share (or IPC$) on the Samba PDC. The following command
+ will remove all network drive connections:
+ </P
+><P
+> <TT
+CLASS="PROMPT"
+>C:\WINNT\&#62;</TT
+> <B
+CLASS="COMMAND"
+>net use * /d</B
+>
+ </P
+><P
+> Further, if the machine is a already a 'member of a workgroup' that
+ is the same name as the domain you are joining (bad idea) you will
+ get this message. Change the workgroup name to something else, it
+ does not matter what, reboot, and try again.
+ </P
+></LI
+><LI
+><P
+> <EM
+>The system can not log you on (C000019B)....</EM
+>
+ </P
+><P
+>I joined the domain successfully but after upgrading
+ to a newer version of the Samba code I get the message, "The system
+ can not log you on (C000019B), Please try a gain or consult your
+ system administrator" when attempting to logon.
+ </P
+><P
+> This occurs when the domain SID stored in
+ <TT
+CLASS="FILENAME"
+>private/WORKGROUP.SID</TT
+> is
+ changed. For example, you remove the file and <B
+CLASS="COMMAND"
+>smbd</B
+> automatically
+ creates a new one. Or you are swapping back and forth between
+ versions 2.0.7, TNG and the HEAD branch code (not recommended). The
+ only way to correct the problem is to restore the original domain
+ SID or remove the domain client from the domain and rejoin.
+ </P
+></LI
+><LI
+><P
+> <EM
+>The machine trust account for this computer either does not
+ exist or is not accessible.</EM
+>
+ </P
+><P
+> When I try to join the domain I get the message "The machine account
+ for this computer either does not exist or is not accessible". What's
+ wrong?
+ </P
+><P
+> This problem is caused by the PDC not having a suitable machine trust account.
+ If you are using the <TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+> method to create
+ accounts then this would indicate that it has not worked. Ensure the domain
+ admin user system is working.
+ </P
+><P
+> Alternatively if you are creating account entries manually then they
+ have not been created correctly. Make sure that you have the entry
+ correct for the machine trust account in smbpasswd file on the Samba PDC.
+ If you added the account using an editor rather than using the smbpasswd
+ utility, make sure that the account name is the machine NetBIOS name
+ with a '$' appended to it ( i.e. computer_name$ ). There must be an entry
+ in both /etc/passwd and the smbpasswd file. Some people have reported
+ that inconsistent subnet masks between the Samba server and the NT
+ client have caused this problem. Make sure that these are consistent
+ for both client and server.
+ </P
+></LI
+><LI
+><P
+> <EM
+>When I attempt to login to a Samba Domain from a NT4/W2K workstation,
+ I get a message about my account being disabled.</EM
+>
+ </P
+><P
+> This problem is caused by a PAM related bug in Samba 2.2.0. This bug is
+ fixed in 2.2.1. Other symptoms could be unaccessible shares on
+ NT/W2K member servers in the domain or the following error in your smbd.log:
+ passdb/pampass.c:pam_account(268) PAM: UNKNOWN ERROR for User: %user%
+ </P
+><P
+> At first be ensure to enable the useraccounts with <B
+CLASS="COMMAND"
+>smbpasswd -e
+ %user%</B
+>, this is normally done, when you create an account.
+ </P
+><P
+> In order to work around this problem in 2.2.0, configure the
+ <TT
+CLASS="PARAMETER"
+><I
+>account</I
+></TT
+> control flag in
+ <TT
+CLASS="FILENAME"
+>/etc/pam.d/samba</TT
+> file as follows:
+ </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> account required pam_permit.so
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+> If you want to remain backward compatibility to samba 2.0.x use
+ <TT
+CLASS="FILENAME"
+>pam_permit.so</TT
+>, it's also possible to use
+ <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>. There are some bugs if you try to
+ use <TT
+CLASS="FILENAME"
+>pam_unix.so</TT
+>, if you need this, be ensure to use
+ the most recent version of this file.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1306"
+>8.6. System Policies and Profiles</A
+></H1
+><P
+>Much of the information necessary to implement System Policies and
+Roving User Profiles in a Samba domain is the same as that for
+implementing these same items in a Windows NT 4.0 domain.
+You should read the white paper <A
+HREF="http://www.microsoft.com/ntserver/management/deployment/planguide/prof_policies.asp"
+TARGET="_top"
+>Implementing
+Profiles and Policies in Windows NT 4.0</A
+> available from Microsoft.</P
+><P
+>Here are some additional details:</P
+><P
+></P
+><UL
+><LI
+><P
+> <EM
+>What about Windows NT Policy Editor?</EM
+>
+ </P
+><P
+> To create or edit <TT
+CLASS="FILENAME"
+>ntconfig.pol</TT
+> you must use
+ the NT Server Policy Editor, <B
+CLASS="COMMAND"
+>poledit.exe</B
+> which
+ is included with NT Server but <EM
+>not NT Workstation</EM
+>.
+ There is a Policy Editor on a NTws
+ but it is not suitable for creating <EM
+>Domain Policies</EM
+>.
+ Further, although the Windows 95
+ Policy Editor can be installed on an NT Workstation/Server, it will not
+ work with NT policies because the registry key that are set by the policy templates.
+ However, the files from the NT Server will run happily enough on an NTws.
+ You need <TT
+CLASS="FILENAME"
+>poledit.exe, common.adm</TT
+> and <TT
+CLASS="FILENAME"
+>winnt.adm</TT
+>. It is convenient
+ to put the two *.adm files in <TT
+CLASS="FILENAME"
+>c:\winnt\inf</TT
+> which is where
+ the binary will look for them unless told otherwise. Note also that that
+ directory is 'hidden'.
+ </P
+><P
+> The Windows NT policy editor is also included with the Service Pack 3 (and
+ later) for Windows NT 4.0. Extract the files using <B
+CLASS="COMMAND"
+>servicepackname /x</B
+>,
+ i.e. that's <B
+CLASS="COMMAND"
+>Nt4sp6ai.exe /x</B
+> for service pack 6a. The policy editor,
+ <B
+CLASS="COMMAND"
+>poledit.exe</B
+> and the associated template files (*.adm) should
+ be extracted as well. It is also possible to downloaded the policy template
+ files for Office97 and get a copy of the policy editor. Another possible
+ location is with the Zero Administration Kit available for download from Microsoft.
+ </P
+></LI
+><LI
+><P
+> <EM
+>Can Win95 do Policies?</EM
+>
+ </P
+><P
+> Install the group policy handler for Win9x to pick up group
+ policies. Look on the Win98 CD in <TT
+CLASS="FILENAME"
+>\tools\reskit\netadmin\poledit</TT
+>.
+ Install group policies on a Win9x client by double-clicking
+ <TT
+CLASS="FILENAME"
+>grouppol.inf</TT
+>. Log off and on again a couple of
+ times and see if Win98 picks up group policies. Unfortunately this needs
+ to be done on every Win9x machine that uses group policies....
+ </P
+><P
+> If group policies don't work one reports suggests getting the updated
+ (read: working) grouppol.dll for Windows 9x. The group list is grabbed
+ from /etc/group.
+ </P
+></LI
+><LI
+><P
+> <EM
+>How do I get 'User Manager' and 'Server Manager'</EM
+>
+ </P
+><P
+> Since I don't need to buy an NT Server CD now, how do I get
+ the 'User Manager for Domains', the 'Server Manager'?
+ </P
+><P
+> Microsoft distributes a version of these tools called nexus for
+ installation on Windows 95 systems. The tools set includes
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Server Manager</P
+></LI
+><LI
+><P
+>User Manager for Domains</P
+></LI
+><LI
+><P
+>Event Viewer</P
+></LI
+></UL
+><P
+> Click here to download the archived file <A
+HREF="ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE"
+TARGET="_top"
+>ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE</A
+>
+ </P
+><P
+> The Windows NT 4.0 version of the 'User Manager for
+ Domains' and 'Server Manager' are available from Microsoft via ftp
+ from <A
+HREF="ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE"
+TARGET="_top"
+>ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE</A
+>
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1350"
+>8.7. What other help can I get?</A
+></H1
+><P
+>There are many sources of information available in the form
+of mailing lists, RFC's and documentation. The docs that come
+with the samba distribution contain very good explanations of
+general SMB topics such as browsing.</P
+><P
+></P
+><UL
+><LI
+><P
+> <EM
+>What are some diagnostics tools I can use to debug the domain logon
+ process and where can I find them?</EM
+>
+ </P
+><P
+> One of the best diagnostic tools for debugging problems is Samba itself.
+ You can use the -d option for both smbd and nmbd to specify what
+ 'debug level' at which to run. See the man pages on smbd, nmbd and
+ smb.conf for more information on debugging options. The debug
+ level can range from 1 (the default) to 10 (100 for debugging passwords).
+ </P
+><P
+> Another helpful method of debugging is to compile samba using the
+ <B
+CLASS="COMMAND"
+>gcc -g </B
+> flag. This will include debug
+ information in the binaries and allow you to attach gdb to the
+ running smbd / nmbd process. In order to attach gdb to an smbd
+ process for an NT workstation, first get the workstation to make the
+ connection. Pressing ctrl-alt-delete and going down to the domain box
+ is sufficient (at least, on the first time you join the domain) to
+ generate a 'LsaEnumTrustedDomains'. Thereafter, the workstation
+ maintains an open connection, and therefore there will be an smbd
+ process running (assuming that you haven't set a really short smbd
+ idle timeout) So, in between pressing ctrl alt delete, and actually
+ typing in your password, you can gdb attach and continue.
+ </P
+><P
+> Some useful samba commands worth investigating:
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>testparam | more</P
+></LI
+><LI
+><P
+>smbclient -L //{netbios name of server}</P
+></LI
+></UL
+><P
+> An SMB enabled version of tcpdump is available from
+ <A
+HREF="http://www.tcpdump.org/"
+TARGET="_top"
+>http://www.tcpdup.org/</A
+>.
+ Ethereal, another good packet sniffer for Unix and Win32
+ hosts, can be downloaded from <A
+HREF="http://www.ethereal.com/"
+TARGET="_top"
+>http://www.ethereal.com</A
+>.
+ </P
+><P
+> For tracing things on the Microsoft Windows NT, Network Monitor
+ (aka. netmon) is available on the Microsoft Developer Network CD's,
+ the Windows NT Server install CD and the SMS CD's. The version of
+ netmon that ships with SMS allows for dumping packets between any two
+ computers (i.e. placing the network interface in promiscuous mode).
+ The version on the NT Server install CD will only allow monitoring
+ of network traffic directed to the local NT box and broadcasts on the
+ local subnet. Be aware that Ethereal can read and write netmon
+ formatted files.
+ </P
+></LI
+><LI
+><P
+> <EM
+>How do I install 'Network Monitor' on an NT Workstation
+ or a Windows 9x box?</EM
+>
+ </P
+><P
+> Installing netmon on an NT workstation requires a couple
+ of steps. The following are for installing Netmon V4.00.349, which comes
+ with Microsoft Windows NT Server 4.0, on Microsoft Windows NT
+ Workstation 4.0. The process should be similar for other version of
+ Windows NT / Netmon. You will need both the Microsoft Windows
+ NT Server 4.0 Install CD and the Workstation 4.0 Install CD.
+ </P
+><P
+> Initially you will need to install 'Network Monitor Tools and Agent'
+ on the NT Server. To do this
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Goto Start - Settings - Control Panel -
+ Network - Services - Add </P
+></LI
+><LI
+><P
+>Select the 'Network Monitor Tools and Agent' and
+ click on 'OK'.</P
+></LI
+><LI
+><P
+>Click 'OK' on the Network Control Panel.
+ </P
+></LI
+><LI
+><P
+>Insert the Windows NT Server 4.0 install CD
+ when prompted.</P
+></LI
+></UL
+><P
+> At this point the Netmon files should exist in
+ <TT
+CLASS="FILENAME"
+>%SYSTEMROOT%\System32\netmon\*.*</TT
+>.
+ Two subdirectories exist as well, <TT
+CLASS="FILENAME"
+>parsers\</TT
+>
+ which contains the necessary DLL's for parsing the netmon packet
+ dump, and <TT
+CLASS="FILENAME"
+>captures\</TT
+>.
+ </P
+><P
+> In order to install the Netmon tools on an NT Workstation, you will
+ first need to install the 'Network Monitor Agent' from the Workstation
+ install CD.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Goto Start - Settings - Control Panel -
+ Network - Services - Add</P
+></LI
+><LI
+><P
+>Select the 'Network Monitor Agent' and click
+ on 'OK'.</P
+></LI
+><LI
+><P
+>Click 'OK' on the Network Control Panel.
+ </P
+></LI
+><LI
+><P
+>Insert the Windows NT Workstation 4.0 install
+ CD when prompted.</P
+></LI
+></UL
+><P
+> Now copy the files from the NT Server in %SYSTEMROOT%\System32\netmon\*.*
+ to %SYSTEMROOT%\System32\netmon\*.* on the Workstation and set
+ permissions as you deem appropriate for your site. You will need
+ administrative rights on the NT box to run netmon.
+ </P
+><P
+> To install Netmon on a Windows 9x box install the network monitor agent
+ from the Windows 9x CD (\admin\nettools\netmon). There is a readme
+ file located with the netmon driver files on the CD if you need
+ information on how to do this. Copy the files from a working
+ Netmon installation.
+ </P
+></LI
+><LI
+><P
+> The following is a list if helpful URLs and other links:
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Home of Samba site <A
+HREF="http://samba.org"
+TARGET="_top"
+> http://samba.org</A
+>. We have a mirror near you !</P
+></LI
+><LI
+><P
+> The <EM
+>Development</EM
+> document
+ on the Samba mirrors might mention your problem. If so,
+ it might mean that the developers are working on it.</P
+></LI
+><LI
+><P
+>See how Scott Merrill simulates a BDC behavior at
+ <A
+HREF="http://www.skippy.net/linux/smb-howto.html"
+TARGET="_top"
+> http://www.skippy.net/linux/smb-howto.html</A
+>. </P
+></LI
+><LI
+><P
+>Although 2.0.7 has almost had its day as a PDC, David Bannon will
+ keep the 2.0.7 PDC pages at <A
+HREF="http://bioserve.latrobe.edu.au/samba"
+TARGET="_top"
+> http://bioserve.latrobe.edu.au/samba</A
+> going for a while yet.</P
+></LI
+><LI
+><P
+>Misc links to CIFS information
+ <A
+HREF="http://samba.org/cifs/"
+TARGET="_top"
+>http://samba.org/cifs/</A
+></P
+></LI
+><LI
+><P
+>NT Domains for Unix <A
+HREF="http://mailhost.cb1.com/~lkcl/ntdom/"
+TARGET="_top"
+> http://mailhost.cb1.com/~lkcl/ntdom/</A
+></P
+></LI
+><LI
+><P
+>FTP site for older SMB specs:
+ <A
+HREF="ftp://ftp.microsoft.com/developr/drg/CIFS/"
+TARGET="_top"
+> ftp://ftp.microsoft.com/developr/drg/CIFS/</A
+></P
+></LI
+></UL
+></LI
+></UL
+><P
+></P
+><UL
+><LI
+><P
+> <EM
+>How do I get help from the mailing lists?</EM
+>
+ </P
+><P
+> There are a number of Samba related mailing lists. Go to <A
+HREF="http://samba.org"
+TARGET="_top"
+>http://samba.org</A
+>, click on your nearest mirror
+ and then click on <B
+CLASS="COMMAND"
+>Support</B
+> and then click on <B
+CLASS="COMMAND"
+> Samba related mailing lists</B
+>.
+ </P
+><P
+> For questions relating to Samba TNG go to
+ <A
+HREF="http://www.samba-tng.org/"
+TARGET="_top"
+>http://www.samba-tng.org/</A
+>
+ It has been requested that you don't post questions about Samba-TNG to the
+ main stream Samba lists.</P
+><P
+> If you post a message to one of the lists please observe the following guide lines :
+ </P
+><P
+></P
+><UL
+><LI
+><P
+> Always remember that the developers are volunteers, they are
+ not paid and they never guarantee to produce a particular feature at
+ a particular time. Any time lines are 'best guess' and nothing more.
+ </P
+></LI
+><LI
+><P
+> Always mention what version of samba you are using and what
+ operating system its running under. You should probably list the
+ relevant sections of your smb.conf file, at least the options
+ in [global] that affect PDC support.</P
+></LI
+><LI
+><P
+>In addition to the version, if you obtained Samba via
+ CVS mention the date when you last checked it out.</P
+></LI
+><LI
+><P
+> Try and make your question clear and brief, lots of long,
+ convoluted questions get deleted before they are completely read !
+ Don't post html encoded messages (if you can select colour or font
+ size its html).</P
+></LI
+><LI
+><P
+> If you run one of those nifty 'I'm on holidays' things when
+ you are away, make sure its configured to not answer mailing lists.
+ </P
+></LI
+><LI
+><P
+> Don't cross post. Work out which is the best list to post to
+ and see what happens, i.e. don't post to both samba-ntdom and samba-technical.
+ Many people active on the lists subscribe to more
+ than one list and get annoyed to see the same message two or more times.
+ Often someone will see a message and thinking it would be better dealt
+ with on another, will forward it on for you.</P
+></LI
+><LI
+><P
+>You might include <EM
+>partial</EM
+>
+ log files written at a debug level set to as much as 20.
+ Please don't send the entire log but enough to give the context of the
+ error messages.</P
+></LI
+><LI
+><P
+>(Possibly) If you have a complete netmon trace ( from the opening of
+ the pipe to the error ) you can send the *.CAP file as well.</P
+></LI
+><LI
+><P
+>Please think carefully before attaching a document to an email.
+ Consider pasting the relevant parts into the body of the message. The samba
+ mailing lists go to a huge number of people, do they all need a copy of your
+ smb.conf in their attach directory?</P
+></LI
+></UL
+></LI
+><LI
+><P
+> <EM
+>How do I get off the mailing lists?</EM
+>
+ </P
+><P
+>To have your name removed from a samba mailing list, go to the
+ same place you went to to get on it. Go to <A
+HREF="http://lists.samba.org/"
+TARGET="_top"
+>http://lists.samba.org</A
+>,
+ click on your nearest mirror and then click on <B
+CLASS="COMMAND"
+>Support</B
+> and
+ then click on <B
+CLASS="COMMAND"
+> Samba related mailing lists</B
+>. Or perhaps see
+ <A
+HREF="http://lists.samba.org/mailman/roster/samba-ntdom"
+TARGET="_top"
+>here</A
+>
+ </P
+><P
+> Please don't post messages to the list asking to be removed, you will just
+ be referred to the above address (unless that process failed in some way...)
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1464"
+>8.8. Domain Control for Windows 9x/ME</A
+></H1
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>The following section contains much of the original
+DOMAIN.txt file previously included with Samba. Much of
+the material is based on what went into the book <EM
+>Special
+Edition, Using Samba</EM
+>, by Richard Sharpe.</P
+></BLOCKQUOTE
+></DIV
+><P
+>A domain and a workgroup are exactly the same thing in terms of network
+browsing. The difference is that a distributable authentication
+database is associated with a domain, for secure login access to a
+network. Also, different access rights can be granted to users if they
+successfully authenticate against a domain logon server (NT server and
+other systems based on NT server support this, as does at least Samba TNG now).</P
+><P
+>The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+Network browsing functionality of domains and workgroups is
+identical and is explained in BROWSING.txt. It should be noted, that browsing
+is totally orthogonal to logon support.</P
+><P
+>Issues related to the single-logon network model are discussed in this
+section. Samba supports domain logons, network logon scripts, and user
+profiles for MS Windows for workgroups and MS Windows 9X/ME clients
+which will be the focus of this section.</P
+><P
+>When an SMB client in a domain wishes to logon it broadcast requests for a
+logon server. The first one to reply gets the job, and validates its
+password using whatever mechanism the Samba administrator has installed.
+It is possible (but very stupid) to create a domain where the user
+database is not shared between servers, i.e. they are effectively workgroup
+servers advertising themselves as participating in a domain. This
+demonstrates how authentication is quite different from but closely
+involved with domains.</P
+><P
+>Using these features you can make your clients verify their logon via
+the Samba server; make clients run a batch file when they logon to
+the network and download their preferences, desktop and start menu.</P
+><P
+>Before launching into the configuration instructions, it is
+worthwhile lookingat how a Windows 9x/ME client performs a logon:</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> The client broadcasts (to the IP broadcast address of the subnet it is in)
+ a NetLogon request. This is sent to the NetBIOS name DOMAIN&#60;1c&#62; at the
+ NetBIOS layer. The client chooses the first response it receives, which
+ contains the NetBIOS name of the logon server to use in the format of
+ \\SERVER.
+ </P
+></LI
+><LI
+><P
+> The client then connects to that server, logs on (does an SMBsessetupX) and
+ then connects to the IPC$ share (using an SMBtconX).
+ </P
+></LI
+><LI
+><P
+> The client then does a NetWkstaUserLogon request, which retrieves the name
+ of the user's logon script.
+ </P
+></LI
+><LI
+><P
+> The client then connects to the NetLogon share and searches for this
+ and if it is found and can be read, is retrieved and executed by the client.
+ After this, the client disconnects from the NetLogon share.
+ </P
+></LI
+><LI
+><P
+> The client then sends a NetUserGetInfo request to the server, to retrieve
+ the user's home share, which is used to search for profiles. Since the
+ response to the NetUserGetInfo request does not contain much more
+ the user's home share, profiles for Win9X clients MUST reside in the user
+ home directory.
+ </P
+></LI
+><LI
+><P
+> The client then connects to the user's home share and searches for the
+ user's profile. As it turns out, you can specify the user's home share as
+ a sharename and path. For example, \\server\fred\.profile.
+ If the profiles are found, they are implemented.
+ </P
+></LI
+><LI
+><P
+> The client then disconnects from the user's home share, and reconnects to
+ the NetLogon share and looks for CONFIG.POL, the policies file. If this is
+ found, it is read and implemented.
+ </P
+></LI
+></OL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1490"
+>8.8.1. Configuration Instructions: Network Logons</A
+></H2
+><P
+>The main difference between a PDC and a Windows 9x logon
+server configuration is that</P
+><P
+></P
+><UL
+><LI
+><P
+>Password encryption is not required for a Windows 9x logon server.</P
+></LI
+><LI
+><P
+>Windows 9x/ME clients do not possess machine trust accounts.</P
+></LI
+></UL
+><P
+>Therefore, a Samba PDC will also act as a Windows 9x logon
+server.</P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>security mode and master browsers</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>There are a few comments to make in order to tie up some
+loose ends. There has been much debate over the issue of whether
+or not it is ok to configure Samba as a Domain Controller in security
+modes other than <TT
+CLASS="CONSTANT"
+>USER</TT
+>. The only security mode
+which will not work due to technical reasons is <TT
+CLASS="CONSTANT"
+>SHARE</TT
+>
+mode security. <TT
+CLASS="CONSTANT"
+>DOMAIN</TT
+> and <TT
+CLASS="CONSTANT"
+>SERVER</TT
+>
+mode security is really just a variation on SMB user level security.</P
+><P
+>Actually, this issue is also closely tied to the debate on whether
+or not Samba must be the domain master browser for its workgroup
+when operating as a DC. While it may technically be possible
+to configure a server as such (after all, browsing and domain logons
+are two distinctly different functions), it is not a good idea to
+so. You should remember that the DC must register the DOMAIN#1b NetBIOS
+name. This is the name used by Windows clients to locate the DC.
+Windows clients do not distinguish between the DC and the DMB.
+For this reason, it is very wise to configure the Samba DC as the DMB.</P
+><P
+>Now back to the issue of configuring a Samba DC to use a mode other
+than "security = user". If a Samba host is configured to use
+another SMB server or DC in order to validate user connection
+requests, then it is a fact that some other machine on the network
+(the "password server") knows more about user than the Samba host.
+99% of the time, this other host is a domain controller. Now
+in order to operate in domain mode security, the "workgroup" parameter
+must be set to the name of the Windows NT domain (which already
+has a domain controller, right?)</P
+><P
+>Therefore configuring a Samba box as a DC for a domain that
+already by definition has a PDC is asking for trouble.
+Therefore, you should always configure the Samba DC to be the DMB
+for its domain.</P
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1509"
+>8.8.2. Configuration Instructions: Setting up Roaming User Profiles</A
+></H2
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Warning</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+><EM
+>NOTE!</EM
+> Roaming profiles support is different
+for Win9X and WinNT.</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>Before discussing how to configure roaming profiles, it is useful to see how
+Win9X and WinNT clients implement these features.</P
+><P
+>Win9X clients send a NetUserGetInfo request to the server to get the user's
+profiles location. However, the response does not have room for a separate
+profiles location field, only the user's home share. This means that Win9X
+profiles are restricted to being in the user's home directory.</P
+><P
+>WinNT clients send a NetSAMLogon RPC request, which contains many fields,
+including a separate field for the location of the user's profiles.
+This means that support for profiles is different for Win9X and WinNT.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1517"
+>8.8.2.1. Windows NT Configuration</A
+></H3
+><P
+>To support WinNT clients, in the [global] section of smb.conf set the
+following (for example):</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>logon path = \\profileserver\profileshare\profilepath\%U\moreprofilepath</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The default for this option is \\%N\%U\profile, namely
+\\sambaserver\username\profile. The \\N%\%U service is created
+automatically by the [homes] service.
+If you are using a samba server for the profiles, you _must_ make the
+share specified in the logon path browseable. </P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 26aug96 - we have discovered a problem where Windows clients can
+maintain a connection to the [homes] share in between logins. The
+[homes] share must NOT therefore be used in a profile path.]</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1525"
+>8.8.2.2. Windows 9X Configuration</A
+></H3
+><P
+>To support Win9X clients, you must use the "logon home" parameter. Samba has
+now been fixed so that "net use/home" now works as well, and it, too, relies
+on the "logon home" parameter.</P
+><P
+>By using the logon home parameter, you are restricted to putting Win9X
+profiles in the user's home directory. But wait! There is a trick you
+can use. If you set the following in the [global] section of your
+smb.conf file:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>logon home = \\%L\%U\.profiles</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>then your Win9X clients will dutifully put their clients in a subdirectory
+of your home directory called .profiles (thus making them hidden).</P
+><P
+>Not only that, but 'net use/home' will also work, because of a feature in
+Win9X. It removes any directory stuff off the end of the home directory area
+and only uses the server and share portion. That is, it looks like you
+specified \\%L\%U for "logon home".</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1533"
+>8.8.2.3. Win9X and WinNT Configuration</A
+></H3
+><P
+>You can support profiles for both Win9X and WinNT clients by setting both the
+"logon home" and "logon path" parameters. For example:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>logon home = \\%L\%U\.profiles
+logon path = \\%L\profiles\%U</PRE
+></TD
+></TR
+></TABLE
+></P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>I have not checked what 'net use /home' does on NT when "logon home" is
+set as above.</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1540"
+>8.8.2.4. Windows 9X Profile Setup</A
+></H3
+><P
+>When a user first logs in on Windows 9X, the file user.DAT is created,
+as are folders "Start Menu", "Desktop", "Programs" and "Nethood".
+These directories and their contents will be merged with the local
+versions stored in c:\windows\profiles\username on subsequent logins,
+taking the most recent from each. You will need to use the [global]
+options "preserve case = yes", "short preserve case = yes" and
+"case sensitive = no" in order to maintain capital letters in shortcuts
+in any of the profile folders.</P
+><P
+>The user.DAT file contains all the user's preferences. If you wish to
+enforce a set of preferences, rename their user.DAT file to user.MAN,
+and deny them write access to this file.</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> On the Windows 95 machine, go to Control Panel | Passwords and
+ select the User Profiles tab. Select the required level of
+ roaming preferences. Press OK, but do _not_ allow the computer
+ to reboot.
+ </P
+></LI
+><LI
+><P
+> On the Windows 95 machine, go to Control Panel | Network |
+ Client for Microsoft Networks | Preferences. Select 'Log on to
+ NT Domain'. Then, ensure that the Primary Logon is 'Client for
+ Microsoft Networks'. Press OK, and this time allow the computer
+ to reboot.
+ </P
+></LI
+></OL
+><P
+>Under Windows 95, Profiles are downloaded from the Primary Logon.
+If you have the Primary Logon as 'Client for Novell Networks', then
+the profiles and logon script will be downloaded from your Novell
+Server. If you have the Primary Logon as 'Windows Logon', then the
+profiles will be loaded from the local machine - a bit against the
+concept of roaming profiles, if you ask me.</P
+><P
+>You will now find that the Microsoft Networks Login box contains
+[user, password, domain] instead of just [user, password]. Type in
+the samba server's domain name (or any other domain known to exist,
+but bear in mind that the user will be authenticated against this
+domain and profiles downloaded from it, if that domain logon server
+supports it), user name and user's password.</P
+><P
+>Once the user has been successfully validated, the Windows 95 machine
+will inform you that 'The user has not logged on before' and asks you
+if you wish to save the user's preferences? Select 'yes'.</P
+><P
+>Once the Windows 95 client comes up with the desktop, you should be able
+to examine the contents of the directory specified in the "logon path"
+on the samba server and verify that the "Desktop", "Start Menu",
+"Programs" and "Nethood" folders have been created.</P
+><P
+>These folders will be cached locally on the client, and updated when
+the user logs off (if you haven't made them read-only by then :-).
+You will find that if the user creates further folders or short-cuts,
+that the client will merge the profile contents downloaded with the
+contents of the profile directory already on the local client, taking
+the newest folders and short-cuts from each set.</P
+><P
+>If you have made the folders / files read-only on the samba server,
+then you will get errors from the w95 machine on logon and logout, as
+it attempts to merge the local and the remote profile. Basically, if
+you have any errors reported by the w95 machine, check the Unix file
+permissions and ownership rights on the profile directory contents,
+on the samba server.</P
+><P
+>If you have problems creating user profiles, you can reset the user's
+local desktop cache, as shown below. When this user then next logs in,
+they will be told that they are logging in "for the first time".</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> instead of logging in under the [user, password, domain] dialog,
+ press escape.
+ </P
+></LI
+><LI
+><P
+> run the regedit.exe program, and look in:
+ </P
+><P
+> HKEY_LOCAL_MACHINE\Windows\CurrentVersion\ProfileList
+ </P
+><P
+> you will find an entry, for each user, of ProfilePath. Note the
+ contents of this key (likely to be c:\windows\profiles\username),
+ then delete the key ProfilePath for the required user.
+ </P
+><P
+> [Exit the registry editor].
+ </P
+></LI
+><LI
+><P
+> <EM
+>WARNING</EM
+> - before deleting the contents of the
+ directory listed in
+ the ProfilePath (this is likely to be c:\windows\profiles\username),
+ ask them if they have any important files stored on their desktop
+ or in their start menu. delete the contents of the directory
+ ProfilePath (making a backup if any of the files are needed).
+ </P
+><P
+> This will have the effect of removing the local (read-only hidden
+ system file) user.DAT in their profile directory, as well as the
+ local "desktop", "nethood", "start menu" and "programs" folders.
+ </P
+></LI
+><LI
+><P
+> search for the user's .PWL password-caching file in the c:\windows
+ directory, and delete it.
+ </P
+></LI
+><LI
+><P
+> log off the windows 95 client.
+ </P
+></LI
+><LI
+><P
+> check the contents of the profile path (see "logon path" described
+ above), and delete the user.DAT or user.MAN file for the user,
+ making a backup if required.
+ </P
+></LI
+></OL
+><P
+>If all else fails, increase samba's debug log levels to between 3 and 10,
+and / or run a packet trace program such as tcpdump or netmon.exe, and
+look for any error reports.</P
+><P
+>If you have access to an NT server, then first set up roaming profiles
+and / or netlogons on the NT server. Make a packet trace, or examine
+the example packet traces provided with NT server, and see what the
+differences are with the equivalent samba trace.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1576"
+>8.8.2.5. Windows NT Workstation 4.0</A
+></H3
+><P
+>When a user first logs in to a Windows NT Workstation, the profile
+NTuser.DAT is created. The profile location can be now specified
+through the "logon path" parameter. </P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 10aug97 - i tried setting the path to
+\\samba-server\homes\profile, and discovered that this fails because
+a background process maintains the connection to the [homes] share
+which does _not_ close down in between user logins. you have to
+have \\samba-server\%L\profile, where user is the username created
+from the [homes] share].</P
+></BLOCKQUOTE
+></DIV
+><P
+>There is a parameter that is now available for use with NT Profiles:
+"logon drive". This should be set to "h:" or any other drive, and
+should be used in conjunction with the new "logon home" parameter.</P
+><P
+>The entry for the NT 4.0 profile is a _directory_ not a file. The NT
+help on profiles mentions that a directory is also created with a .PDS
+extension. The user, while logging in, must have write permission to
+create the full profile path (and the folder with the .PDS extension)
+[lkcl 10aug97 - i found that the creation of the .PDS directory failed,
+and had to create these manually for each user, with a shell script.
+also, i presume, but have not tested, that the full profile path must
+be browseable just as it is for w95, due to the manner in which they
+attempt to create the full profile path: test existence of each path
+component; create path component].</P
+><P
+>In the profile directory, NT creates more folders than 95. It creates
+"Application Data" and others, as well as "Desktop", "Nethood",
+"Start Menu" and "Programs". The profile itself is stored in a file
+NTuser.DAT. Nothing appears to be stored in the .PDS directory, and
+its purpose is currently unknown.</P
+><P
+>You can use the System Control Panel to copy a local profile onto
+a samba server (see NT Help on profiles: it is also capable of firing
+up the correct location in the System Control Panel for you). The
+NT Help file also mentions that renaming NTuser.DAT to NTuser.MAN
+turns a profile into a mandatory one.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 10aug97 - i notice that NT Workstation tells me that it is
+downloading a profile from a slow link. whether this is actually the
+case, or whether there is some configuration issue, as yet unknown,
+that makes NT Workstation _think_ that the link is a slow one is a
+matter to be resolved].</P
+><P
+>[lkcl 20aug97 - after samba digest correspondence, one user found, and
+another confirmed, that profiles cannot be loaded from a samba server
+unless "security = user" and "encrypt passwords = yes" (see the file
+ENCRYPTION.txt) or "security = server" and "password server = ip.address.
+of.yourNTserver" are used. Either of these options will allow the NT
+workstation to access the samba server using LAN manager encrypted
+passwords, without the user intervention normally required by NT
+workstation for clear-text passwords].</P
+><P
+>[lkcl 25aug97 - more comments received about NT profiles: the case of
+the profile _matters_. the file _must_ be called NTuser.DAT or, for
+a mandatory profile, NTuser.MAN].</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1589"
+>8.8.2.6. Windows NT Server</A
+></H3
+><P
+>There is nothing to stop you specifying any path that you like for the
+location of users' profiles. Therefore, you could specify that the
+profile be stored on a samba server, or any other SMB server, as long as
+that SMB server supports encrypted passwords.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1592"
+>8.8.2.7. Sharing Profiles between W95 and NT Workstation 4.0</A
+></H3
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Potentially outdated or incorrect material follows</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>I think this is all bogus, but have not deleted it. (Richard Sharpe)</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>The default logon path is \\%N\U%. NT Workstation will attempt to create
+a directory "\\samba-server\username.PDS" if you specify the logon path
+as "\\samba-server\username" with the NT User Manager. Therefore, you
+will need to specify (for example) "\\samba-server\username\profile".
+NT 4.0 will attempt to create "\\samba-server\username\profile.PDS", which
+is more likely to succeed.</P
+><P
+>If you then want to share the same Start Menu / Desktop with W95, you will
+need to specify "logon path = \\samba-server\username\profile" [lkcl 10aug97
+this has its drawbacks: i created a shortcut to telnet.exe, which attempts
+to run from the c:\winnt\system32 directory. this directory is obviously
+unlikely to exist on a Win95-only host].</P
+><P
+>&#13;If you have this set up correctly, you will find separate user.DAT and
+NTuser.DAT files in the same profile directory.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 25aug97 - there are some issues to resolve with downloading of
+NT profiles, probably to do with time/date stamps. i have found that
+NTuser.DAT is never updated on the workstation after the first time that
+it is copied to the local workstation profile directory. this is in
+contrast to w95, where it _does_ transfer / update profiles correctly].</P
+></BLOCKQUOTE
+></DIV
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1602"
+>8.9. DOMAIN_CONTROL.txt : Windows NT Domain Control &#38; Samba</A
+></H1
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Possibly Outdated Material</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+> This appendix was originally authored by John H Terpstra of
+ the Samba Team and is included here for posterity.
+ </P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+><EM
+>NOTE :</EM
+>
+The term "Domain Controller" and those related to it refer to one specific
+method of authentication that can underly an SMB domain. Domain Controllers
+prior to Windows NT Server 3.1 were sold by various companies and based on
+private extensions to the LAN Manager 2.1 protocol. Windows NT introduced
+Microsoft-specific ways of distributing the user authentication database.
+See DOMAIN.txt for examples of how Samba can participate in or create
+SMB domains based on shared authentication database schemes other than the
+Windows NT SAM.</P
+><P
+>Windows NT Server can be installed as either a plain file and print server
+(WORKGROUP workstation or server) or as a server that participates in Domain
+Control (DOMAIN member, Primary Domain controller or Backup Domain controller).
+The same is true for OS/2 Warp Server, Digital Pathworks and other similar
+products, all of which can participate in Domain Control along with Windows NT.</P
+><P
+>To many people these terms can be confusing, so let's try to clear the air.</P
+><P
+>Every Windows NT system (workstation or server) has a registry database.
+The registry contains entries that describe the initialization information
+for all services (the equivalent of Unix Daemons) that run within the Windows
+NT environment. The registry also contains entries that tell application
+software where to find dynamically loadable libraries that they depend upon.
+In fact, the registry contains entries that describes everything that anything
+may need to know to interact with the rest of the system.</P
+><P
+>The registry files can be located on any Windows NT machine by opening a
+command prompt and typing:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINNT\&#62;</TT
+> dir %SystemRoot%\System32\config</P
+><P
+>The environment variable %SystemRoot% value can be obtained by typing:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINNT&#62;</TT
+>echo %SystemRoot%</P
+><P
+>The active parts of the registry that you may want to be familiar with are
+the files called: default, system, software, sam and security.</P
+><P
+>In a domain environment, Microsoft Windows NT domain controllers participate
+in replication of the SAM and SECURITY files so that all controllers within
+the domain have an exactly identical copy of each.</P
+><P
+>The Microsoft Windows NT system is structured within a security model that
+says that all applications and services must authenticate themselves before
+they can obtain permission from the security manager to do what they set out
+to do.</P
+><P
+>The Windows NT User database also resides within the registry. This part of
+the registry contains the user's security identifier, home directory, group
+memberships, desktop profile, and so on.</P
+><P
+>Every Windows NT system (workstation as well as server) will have its own
+registry. Windows NT Servers that participate in Domain Security control
+have a database that they share in common - thus they do NOT own an
+independent full registry database of their own, as do Workstations and
+plain Servers.</P
+><P
+>The User database is called the SAM (Security Access Manager) database and
+is used for all user authentication as well as for authentication of inter-
+process authentication (i.e. to ensure that the service action a user has
+requested is permitted within the limits of that user's privileges).</P
+><P
+>The Samba team have produced a utility that can dump the Windows NT SAM into
+smbpasswd format: see ENCRYPTION.txt for information on smbpasswd and
+/pub/samba/pwdump on your nearest Samba mirror for the utility. This
+facility is useful but cannot be easily used to implement SAM replication
+to Samba systems.</P
+><P
+>Windows for Workgroups, Windows 95, and Windows NT Workstations and Servers
+can participate in a Domain security system that is controlled by Windows NT
+servers that have been correctly configured. Almost every domain will have
+ONE Primary Domain Controller (PDC). It is desirable that each domain will
+have at least one Backup Domain Controller (BDC).</P
+><P
+>The PDC and BDCs then participate in replication of the SAM database so that
+each Domain Controlling participant will have an up to date SAM component
+within its registry.</P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="WINBIND"
+>Chapter 9. Unified Logons between Windows NT and UNIX using Winbind</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN1652"
+>9.1. Abstract</A
+></H1
+><P
+>Integration of UNIX and Microsoft Windows NT through
+ a unified logon has been considered a "holy grail" in heterogeneous
+ computing environments for a long time. We present
+ <EM
+>winbind</EM
+>, a component of the Samba suite
+ of programs as a solution to the unified logon problem. Winbind
+ uses a UNIX implementation
+ of Microsoft RPC calls, Pluggable Authentication Modules, and the Name
+ Service Switch to allow Windows NT domain users to appear and operate
+ as UNIX users on a UNIX machine. This paper describes the winbind
+ system, explaining the functionality it provides, how it is configured,
+ and how it works internally.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1656"
+>9.2. Introduction</A
+></H1
+><P
+>It is well known that UNIX and Microsoft Windows NT have
+ different models for representing user and group information and
+ use different technologies for implementing them. This fact has
+ made it difficult to integrate the two systems in a satisfactory
+ manner.</P
+><P
+>One common solution in use today has been to create
+ identically named user accounts on both the UNIX and Windows systems
+ and use the Samba suite of programs to provide file and print services
+ between the two. This solution is far from perfect however, as
+ adding and deleting users on both sets of machines becomes a chore
+ and two sets of passwords are required both of which
+ can lead to synchronization problems between the UNIX and Windows
+ systems and confusion for users.</P
+><P
+>We divide the unified logon problem for UNIX machines into
+ three smaller problems:</P
+><P
+></P
+><UL
+><LI
+><P
+>Obtaining Windows NT user and group information
+ </P
+></LI
+><LI
+><P
+>Authenticating Windows NT users
+ </P
+></LI
+><LI
+><P
+>Password changing for Windows NT users
+ </P
+></LI
+></UL
+><P
+>Ideally, a prospective solution to the unified logon problem
+ would satisfy all the above components without duplication of
+ information on the UNIX machines and without creating additional
+ tasks for the system administrator when maintaining users and
+ groups on either system. The winbind system provides a simple
+ and elegant solution to all three components of the unified logon
+ problem.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1669"
+>9.3. What Winbind Provides</A
+></H1
+><P
+>Winbind unifies UNIX and Windows NT account management by
+ allowing a UNIX box to become a full member of a NT domain. Once
+ this is done the UNIX box will see NT users and groups as if
+ they were native UNIX users and groups, allowing the NT domain
+ to be used in much the same manner that NIS+ is used within
+ UNIX-only environments.</P
+><P
+>The end result is that whenever any
+ program on the UNIX machine asks the operating system to lookup
+ a user or group name, the query will be resolved by asking the
+ NT domain controller for the specified domain to do the lookup.
+ Because Winbind hooks into the operating system at a low level
+ (via the NSS name resolution modules in the C library) this
+ redirection to the NT domain controller is completely
+ transparent.</P
+><P
+>Users on the UNIX machine can then use NT user and group
+ names as they would use "native" UNIX names. They can chown files
+ so that they are owned by NT domain users or even login to the
+ UNIX machine and run a UNIX X-Window session as a domain user.</P
+><P
+>The only obvious indication that Winbind is being used is
+ that user and group names take the form DOMAIN\user and
+ DOMAIN\group. This is necessary as it allows Winbind to determine
+ that redirection to a domain controller is wanted for a particular
+ lookup and which trusted domain is being referenced.</P
+><P
+>Additionally, Winbind provides an authentication service
+ that hooks into the Pluggable Authentication Modules (PAM) system
+ to provide authentication via a NT domain to any PAM enabled
+ applications. This capability solves the problem of synchronizing
+ passwords between systems since all passwords are stored in a single
+ location (on the domain controller).</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1676"
+>9.3.1. Target Uses</A
+></H2
+><P
+>Winbind is targeted at organizations that have an
+ existing NT based domain infrastructure into which they wish
+ to put UNIX workstations or servers. Winbind will allow these
+ organizations to deploy UNIX workstations without having to
+ maintain a separate account infrastructure. This greatly
+ simplifies the administrative overhead of deploying UNIX
+ workstations into a NT based organization.</P
+><P
+>Another interesting way in which we expect Winbind to
+ be used is as a central part of UNIX based appliances. Appliances
+ that provide file and print services to Microsoft based networks
+ will be able to use Winbind to provide seamless integration of
+ the appliance into the domain.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1680"
+>9.4. How Winbind Works</A
+></H1
+><P
+>The winbind system is designed around a client/server
+ architecture. A long running <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+ listens on a UNIX domain socket waiting for requests
+ to arrive. These requests are generated by the NSS and PAM
+ clients and processed sequentially.</P
+><P
+>The technologies used to implement winbind are described
+ in detail below.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1685"
+>9.4.1. Microsoft Remote Procedure Calls</A
+></H2
+><P
+>Over the last two years, efforts have been underway
+ by various Samba Team members to decode various aspects of
+ the Microsoft Remote Procedure Call (MSRPC) system. This
+ system is used for most network related operations between
+ Windows NT machines including remote management, user authentication
+ and print spooling. Although initially this work was done
+ to aid the implementation of Primary Domain Controller (PDC)
+ functionality in Samba, it has also yielded a body of code which
+ can be used for other purposes.</P
+><P
+>Winbind uses various MSRPC calls to enumerate domain users
+ and groups and to obtain detailed information about individual
+ users or groups. Other MSRPC calls can be used to authenticate
+ NT domain users and to change user passwords. By directly querying
+ a Windows PDC for user and group information, winbind maps the
+ NT account information onto UNIX user and group names.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1689"
+>9.4.2. Name Service Switch</A
+></H2
+><P
+>The Name Service Switch, or NSS, is a feature that is
+ present in many UNIX operating systems. It allows system
+ information such as hostnames, mail aliases and user information
+ to be resolved from different sources. For example, a standalone
+ UNIX workstation may resolve system information from a series of
+ flat files stored on the local filesystem. A networked workstation
+ may first attempt to resolve system information from local files,
+ and then consult a NIS database for user information or a DNS server
+ for hostname information.</P
+><P
+>The NSS application programming interface allows winbind
+ to present itself as a source of system information when
+ resolving UNIX usernames and groups. Winbind uses this interface,
+ and information obtained from a Windows NT server using MSRPC
+ calls to provide a new source of account enumeration. Using standard
+ UNIX library calls, one can enumerate the users and groups on
+ a UNIX machine running winbind and see all users and groups in
+ a NT domain plus any trusted domain as though they were local
+ users and groups.</P
+><P
+>The primary control file for NSS is
+ <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>.
+ When a UNIX application makes a request to do a lookup
+ the C library looks in <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>
+ for a line which matches the service type being requested, for
+ example the "passwd" service type is used when user or group names
+ are looked up. This config line species which implementations
+ of that service should be tried and in what order. If the passwd
+ config line is:</P
+><P
+><B
+CLASS="COMMAND"
+>passwd: files example</B
+></P
+><P
+>then the C library will first load a module called
+ <TT
+CLASS="FILENAME"
+>/lib/libnss_files.so</TT
+> followed by
+ the module <TT
+CLASS="FILENAME"
+>/lib/libnss_example.so</TT
+>. The
+ C library will dynamically load each of these modules in turn
+ and call resolver functions within the modules to try to resolve
+ the request. Once the request is resolved the C library returns the
+ result to the application.</P
+><P
+>This NSS interface provides a very easy way for Winbind
+ to hook into the operating system. All that needs to be done
+ is to put <TT
+CLASS="FILENAME"
+>libnss_winbind.so</TT
+> in <TT
+CLASS="FILENAME"
+>/lib/</TT
+>
+ then add "winbind" into <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> at
+ the appropriate place. The C library will then call Winbind to
+ resolve user and group names.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1705"
+>9.4.3. Pluggable Authentication Modules</A
+></H2
+><P
+>Pluggable Authentication Modules, also known as PAM,
+ is a system for abstracting authentication and authorization
+ technologies. With a PAM module it is possible to specify different
+ authentication methods for different system applications without
+ having to recompile these applications. PAM is also useful
+ for implementing a particular policy for authorization. For example,
+ a system administrator may only allow console logins from users
+ stored in the local password file but only allow users resolved from
+ a NIS database to log in over the network.</P
+><P
+>Winbind uses the authentication management and password
+ management PAM interface to integrate Windows NT users into a
+ UNIX system. This allows Windows NT users to log in to a UNIX
+ machine and be authenticated against a suitable Primary Domain
+ Controller. These users can also change their passwords and have
+ this change take effect directly on the Primary Domain Controller.
+ </P
+><P
+>PAM is configured by providing control files in the directory
+ <TT
+CLASS="FILENAME"
+>/etc/pam.d/</TT
+> for each of the services that
+ require authentication. When an authentication request is made
+ by an application the PAM code in the C library looks up this
+ control file to determine what modules to load to do the
+ authentication check and in what order. This interface makes adding
+ a new authentication service for Winbind very easy, all that needs
+ to be done is that the <TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+> module
+ is copied to <TT
+CLASS="FILENAME"
+>/lib/security/</TT
+> and the PAM
+ control files for relevant services are updated to allow
+ authentication via winbind. See the PAM documentation
+ for more details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1713"
+>9.4.4. User and Group ID Allocation</A
+></H2
+><P
+>When a user or group is created under Windows NT
+ is it allocated a numerical relative identifier (RID). This is
+ slightly different to UNIX which has a range of numbers that are
+ used to identify users, and the same range in which to identify
+ groups. It is winbind's job to convert RIDs to UNIX id numbers and
+ vice versa. When winbind is configured it is given part of the UNIX
+ user id space and a part of the UNIX group id space in which to
+ store Windows NT users and groups. If a Windows NT user is
+ resolved for the first time, it is allocated the next UNIX id from
+ the range. The same process applies for Windows NT groups. Over
+ time, winbind will have mapped all Windows NT users and groups
+ to UNIX user ids and group ids.</P
+><P
+>The results of this mapping are stored persistently in
+ an ID mapping database held in a tdb database). This ensures that
+ RIDs are mapped to UNIX IDs in a consistent way.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1717"
+>9.4.5. Result Caching</A
+></H2
+><P
+>An active system can generate a lot of user and group
+ name lookups. To reduce the network cost of these lookups winbind
+ uses a caching scheme based on the SAM sequence number supplied
+ by NT domain controllers. User or group information returned
+ by a PDC is cached by winbind along with a sequence number also
+ returned by the PDC. This sequence number is incremented by
+ Windows NT whenever any user or group information is modified. If
+ a cached entry has expired, the sequence number is requested from
+ the PDC and compared against the sequence number of the cached entry.
+ If the sequence numbers do not match, then the cached information
+ is discarded and up to date information is requested directly
+ from the PDC.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1720"
+>9.5. Installation and Configuration</A
+></H1
+><P
+>Many thanks to John Trostel <A
+HREF="mailto:jtrostel@snapserver.com"
+TARGET="_top"
+>jtrostel@snapserver.com</A
+>
+for providing the HOWTO for this section.</P
+><P
+>This HOWTO describes how to get winbind services up and running
+to control access and authenticate users on your Linux box using
+the winbind services which come with SAMBA 2.2.2.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1725"
+>9.5.1. Introduction</A
+></H2
+><P
+>This HOWTO describes the procedures used to get winbind up and
+running on my RedHat 7.1 system. Winbind is capable of providing access
+and authentication control for Windows Domain users through an NT
+or Win2K PDC for 'regular' services, such as telnet a nd ftp, as
+well for SAMBA services.</P
+><P
+>This HOWTO has been written from a 'RedHat-centric' perspective, so if
+you are using another distribution, you may have to modify the instructions
+somewhat to fit the way your distribution works.</P
+><P
+></P
+><UL
+><LI
+><P
+> <EM
+>Why should I to this?</EM
+>
+ </P
+><P
+>This allows the SAMBA administrator to rely on the
+ authentication mechanisms on the NT/Win2K PDC for the authentication
+ of domain members. NT/Win2K users no longer need to have separate
+ accounts on the SAMBA server.
+ </P
+></LI
+><LI
+><P
+> <EM
+>Who should be reading this document?</EM
+>
+ </P
+><P
+> This HOWTO is designed for system administrators. If you are
+ implementing SAMBA on a file server and wish to (fairly easily)
+ integrate existing NT/Win2K users from your PDC onto the
+ SAMBA server, this HOWTO is for you. That said, I am no NT or PAM
+ expert, so you may find a better or easier way to accomplish
+ these tasks.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1738"
+>9.5.2. Requirements</A
+></H2
+><P
+>If you have a samba configuration file that you are currently
+using... <EM
+>BACK IT UP!</EM
+> If your system already uses PAM,
+<EM
+>back up the <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> directory
+contents!</EM
+> If you haven't already made a boot disk,
+<EM
+>MAKE ONE NOW!</EM
+></P
+><P
+>Messing with the pam configuration files can make it nearly impossible
+to log in to yourmachine. That's why you want to be able to boot back
+into your machine in single user mode and restore your
+<TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> back to the original state they were in if
+you get frustrated with the way things are going. ;-)</P
+><P
+>The latest version of SAMBA (version 2.2.2 as of this writing), now
+includes a functioning winbindd daemon. Please refer to the
+<A
+HREF="http://samba.org/"
+TARGET="_top"
+>main SAMBA web page</A
+> or,
+better yet, your closest SAMBA mirror site for instructions on
+downloading the source code.</P
+><P
+>To allow Domain users the ability to access SAMBA shares and
+files, as well as potentially other services provided by your
+SAMBA machine, PAM (pluggable authentication modules) must
+be setup properly on your machine. In order to compile the
+winbind modules, you should have at least the pam libraries resident
+on your system. For recent RedHat systems (7.1, for instance), that
+means <TT
+CLASS="FILENAME"
+>pam-0.74-22</TT
+>. For best results, it is helpful to also
+install the development packages in <TT
+CLASS="FILENAME"
+>pam-devel-0.74-22</TT
+>.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1752"
+>9.5.3. Testing Things Out</A
+></H2
+><P
+>Before starting, it is probably best to kill off all the SAMBA
+related daemons running on your server. Kill off all <B
+CLASS="COMMAND"
+>smbd</B
+>,
+<B
+CLASS="COMMAND"
+>nmbd</B
+>, and <B
+CLASS="COMMAND"
+>winbindd</B
+> processes that may
+be running. To use PAM, you will want to make sure that you have the
+standard PAM package (for RedHat) which supplies the <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+>
+directory structure, including the pam modules are used by pam-aware
+services, several pam libraries, and the <TT
+CLASS="FILENAME"
+>/usr/doc</TT
+>
+and <TT
+CLASS="FILENAME"
+>/usr/man</TT
+> entries for pam. Winbind built better
+in SAMBA if the pam-devel package was also installed. This package includes
+the header files needed to compile pam-aware applications. For instance,
+my RedHat system has both <TT
+CLASS="FILENAME"
+>pam-0.74-22</TT
+> and
+<TT
+CLASS="FILENAME"
+>pam-devel-0.74-22</TT
+> RPMs installed.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1763"
+>9.5.3.1. Configure and compile SAMBA</A
+></H3
+><P
+>The configuration and compilation of SAMBA is pretty straightforward.
+The first three steps may not be necessary depending upon
+whether or not you have previously built the Samba binaries.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>autoconf</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make clean</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>rm config.cache</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>./configure --with-winbind</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make install</B
+></PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>This will, by default, install SAMBA in <TT
+CLASS="FILENAME"
+>/usr/local/samba</TT
+>.
+See the main SAMBA documentation if you want to install SAMBA somewhere else.
+It will also build the winbindd executable and libraries. </P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1782"
+>9.5.3.2. Configure <TT
+CLASS="FILENAME"
+>nsswitch.conf</TT
+> and the
+winbind libraries</A
+></H3
+><P
+>The libraries needed to run the <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+through nsswitch need to be copied to their proper locations, so</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>cp ../samba/source/nsswitch/libnss_winbind.so /lib</B
+></P
+><P
+>I also found it necessary to make the following symbolic link:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>ln -s /lib/libnss_winbind.so /lib/libnss_winbind.so.2</B
+></P
+><P
+>Now, as root you need to edit <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> to
+allow user and group entries to be visible from the <B
+CLASS="COMMAND"
+>winbindd</B
+>
+daemon. My <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file look like
+this after editing:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> passwd: files winbind
+ shadow: files
+ group: files winbind</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>
+The libraries needed by the winbind daemon will be automatically
+entered into the <B
+CLASS="COMMAND"
+>ldconfig</B
+> cache the next time
+your system reboots, but it
+is faster (and you don't need to reboot) if you do it manually:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/sbin/ldconfig -v | grep winbind</B
+></P
+><P
+>This makes <TT
+CLASS="FILENAME"
+>libnss_winbind</TT
+> available to winbindd
+and echos back a check to you.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1807"
+>9.5.3.3. Configure smb.conf</A
+></H3
+><P
+>Several parameters are needed in the smb.conf file to control
+the behavior of <B
+CLASS="COMMAND"
+>winbindd</B
+>. Configure
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> These are described in more detail in
+the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> man page. My
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file was modified to
+include the following entries in the [global] section:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ &#60;...&#62;
+ # separate domain and username with '+', like DOMAIN+username
+ <A
+HREF="winbindd.8.html#WINBINDSEPARATOR"
+TARGET="_top"
+>winbind separator</A
+> = +
+ # use uids from 10000 to 20000 for domain users
+ <A
+HREF="winbindd.8.html#WINBINDUID"
+TARGET="_top"
+>winbind uid</A
+> = 10000-20000
+ # use gids from 10000 to 20000 for domain groups
+ <A
+HREF="winbindd.8.html#WINBINDGID"
+TARGET="_top"
+>winbind gid</A
+> = 10000-20000
+ # allow enumeration of winbind users and groups
+ <A
+HREF="winbindd.8.html#WINBINDENUMUSERS"
+TARGET="_top"
+>winbind enum users</A
+> = yes
+ <A
+HREF="winbindd.8.html#WINBINDENUMGROUP"
+TARGET="_top"
+>winbind enum groups</A
+> = yes
+ # give winbind users a real shell (only needed if they have telnet access)
+ <A
+HREF="winbindd.8.html#TEMPLATEHOMEDIR"
+TARGET="_top"
+>template homedir</A
+> = /home/winnt/%D/%U
+ <A
+HREF="winbindd.8.html#TEMPLATESHELL"
+TARGET="_top"
+>template shell</A
+> = /bin/bash</PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1823"
+>9.5.3.4. Join the SAMBA server to the PDC domain</A
+></H3
+><P
+>Enter the following command to make the SAMBA server join the
+PDC domain, where <TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+> is the name of
+your Windows domain and <TT
+CLASS="REPLACEABLE"
+><I
+>Administrator</I
+></TT
+> is
+a domain user who has administrative privileges in the domain.</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/smbpasswd -j DOMAIN -r PDC -U Administrator</B
+></P
+><P
+>The proper response to the command should be: "Joined the domain
+<TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+>" where <TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+>
+is your DOMAIN name.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1834"
+>9.5.3.5. Start up the winbindd daemon and test it!</A
+></H3
+><P
+>Eventually, you will want to modify your smb startup script to
+automatically invoke the winbindd daemon when the other parts of
+SAMBA start, but it is possible to test out just the winbind
+portion first. To start up winbind services, enter the following
+command as root:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/winbindd</B
+></P
+><P
+>I'm always paranoid and like to make sure the daemon
+is really running...</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>ps -ae | grep winbindd</B
+></P
+><P
+>This command should produce output like this, if the daemon is running</P
+><P
+>3025 ? 00:00:00 winbindd</P
+><P
+>Now... for the real test, try to get some information about the
+users on your PDC</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/wbinfo -u</B
+></P
+><P
+>
+This should echo back a list of users on your Windows users on
+your PDC. For example, I get the following response:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>CEO+Administrator
+CEO+burdell
+CEO+Guest
+CEO+jt-ad
+CEO+krbtgt
+CEO+TsInternetUser</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Obviously, I have named my domain 'CEO' and my <TT
+CLASS="PARAMETER"
+><I
+>winbindd
+separator</I
+></TT
+> is '+'.</P
+><P
+>You can do the same sort of thing to get group information from
+the PDC:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/wbinfo -g</B
+>
+CEO+Domain Admins
+CEO+Domain Users
+CEO+Domain Guests
+CEO+Domain Computers
+CEO+Domain Controllers
+CEO+Cert Publishers
+CEO+Schema Admins
+CEO+Enterprise Admins
+CEO+Group Policy Creator Owners</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The function 'getent' can now be used to get unified
+lists of both local and PDC users and groups.
+Try the following command:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>getent passwd</B
+></P
+><P
+>You should get a list that looks like your <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>
+list followed by the domain users with their new uids, gids, home
+directories and default shells.</P
+><P
+>The same thing can be done for groups with the command</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>getent group</B
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1870"
+>9.5.3.6. Fix the <TT
+CLASS="FILENAME"
+>/etc/rc.d/init.d/smb</TT
+> startup files</A
+></H3
+><P
+>The <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon needs to start up after the
+<B
+CLASS="COMMAND"
+>smbd</B
+> and <B
+CLASS="COMMAND"
+>nmbd</B
+> daemons are running.
+To accomplish this task, you need to modify the <TT
+CLASS="FILENAME"
+>/etc/init.d/smb</TT
+>
+script to add commands to invoke this daemon in the proper sequence. My
+<TT
+CLASS="FILENAME"
+>/etc/init.d/smb</TT
+> file starts up <B
+CLASS="COMMAND"
+>smbd</B
+>,
+<B
+CLASS="COMMAND"
+>nmbd</B
+>, and <B
+CLASS="COMMAND"
+>winbindd</B
+> from the
+<TT
+CLASS="FILENAME"
+>/usr/local/samba/bin</TT
+> directory directly. The 'start'
+function in the script looks like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>start() {
+ KIND="SMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/smbd $SMBDOPTIONS
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/nmbd $NMBDOPTIONS
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/winbindd
+ RETVAL3=$?
+ echo
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] &#38;&#38; touch /var/lock/subsys/smb || \
+ RETVAL=1
+ return $RETVAL
+}</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The 'stop' function has a corresponding entry to shut down the
+services and look s like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>stop() {
+ KIND="SMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc smbd
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc nmbd
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Shutting down $KIND services: "
+ killproc winbindd
+ RETVAL3=$?
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] &#38;&#38; rm -f /var/lock/subsys/smb
+ echo ""
+ return $RETVAL
+}</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>If you restart the <B
+CLASS="COMMAND"
+>smbd</B
+>, <B
+CLASS="COMMAND"
+>nmbd</B
+>,
+and <B
+CLASS="COMMAND"
+>winbindd</B
+> daemons at this point, you
+should be able to connect to the samba server as a domain member just as
+if you were a local user.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN1892"
+>9.5.3.7. Configure Winbind and PAM</A
+></H3
+><P
+>If you have made it this far, you know that winbindd and samba are working
+together. If you want to use winbind to provide authentication for other
+services, keep reading. The pam configuration files need to be altered in
+this step. (Did you remember to make backups of your original
+<TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> files? If not, do it now.)</P
+><P
+>You will need a pam module to use winbindd with these other services. This
+module will be compiled in the <TT
+CLASS="FILENAME"
+>../source/nsswitch</TT
+> directory
+by invoking the command</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make nsswitch/pam_winbind.so</B
+></P
+><P
+>from the <TT
+CLASS="FILENAME"
+>../source</TT
+> directory. The
+<TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+> file should be copied to the location of
+your other pam security modules. On my RedHat system, this was the
+<TT
+CLASS="FILENAME"
+>/lib/security</TT
+> directory.</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>cp ../samba/source/nsswitch/pam_winbind.so /lib/security</B
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/samba</TT
+> file does not need to be changed. I
+just left this fileas it was:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_stack.so service=system-auth
+account required /lib/security/pam_stack.so service=system-auth</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The other services that I modified to allow the use of winbind
+as an authentication service were the normal login on the console (or a terminal
+session), telnet logins, and ftp service. In order to enable these
+services, you may first need to change the entries in
+<TT
+CLASS="FILENAME"
+>/etc/xinetd.d</TT
+> (or <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>).
+RedHat 7.1 uses the new xinetd.d structure, in this case you need
+to change the lines in <TT
+CLASS="FILENAME"
+>/etc/xinetd.d/telnet</TT
+>
+and <TT
+CLASS="FILENAME"
+>/etc/xinetd.d/wu-ftp</TT
+> from </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>enable = no</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>to</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>enable = yes</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>
+For ftp services to work properly, you will also need to either
+have individual directories for the domain users already present on
+the server, or change the home directory template to a general
+directory for all domain users. These can be easily set using
+the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> global entry
+<B
+CLASS="COMMAND"
+>template homedir</B
+>.</P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/ftp</TT
+> file can be changed
+to allow winbind ftp access in a manner similar to the
+samba file. My <TT
+CLASS="FILENAME"
+>/etc/pam.d/ftp</TT
+> file was
+changed to look like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_shells.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/login</TT
+> file can be changed nearly the
+same way. It now looks like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_securetty.so
+auth sufficient /lib/security/pam_winbind.so
+auth sufficient /lib/security/pam_unix.so use_first_pass
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_nologin.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+password required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth
+session optional /lib/security/pam_console.so</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>In this case, I added the <B
+CLASS="COMMAND"
+>auth sufficient /lib/security/pam_winbind.so</B
+>
+lines as before, but also added the <B
+CLASS="COMMAND"
+>required pam_securetty.so</B
+>
+above it, to disallow root logins over the network. I also added a
+<B
+CLASS="COMMAND"
+>sufficient /lib/security/pam_unix.so use_first_pass</B
+>
+line after the <B
+CLASS="COMMAND"
+>winbind.so</B
+> line to get rid of annoying
+double prompts for passwords.</P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1939"
+>9.6. Limitations</A
+></H1
+><P
+>Winbind has a number of limitations in its current
+ released version that we hope to overcome in future
+ releases:</P
+><P
+></P
+><UL
+><LI
+><P
+>Winbind is currently only available for
+ the Linux operating system, although ports to other operating
+ systems are certainly possible. For such ports to be feasible,
+ we require the C library of the target operating system to
+ support the Name Service Switch and Pluggable Authentication
+ Modules systems. This is becoming more common as NSS and
+ PAM gain support among UNIX vendors.</P
+></LI
+><LI
+><P
+>The mappings of Windows NT RIDs to UNIX ids
+ is not made algorithmically and depends on the order in which
+ unmapped users or groups are seen by winbind. It may be difficult
+ to recover the mappings of rid to UNIX id mapping if the file
+ containing this information is corrupted or destroyed.</P
+></LI
+><LI
+><P
+>Currently the winbind PAM module does not take
+ into account possible workstation and logon time restrictions
+ that may be been set for Windows NT users.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN1949"
+>9.7. Conclusion</A
+></H1
+><P
+>The winbind system, through the use of the Name Service
+ Switch, Pluggable Authentication Modules, and appropriate
+ Microsoft RPC calls have allowed us to provide seamless
+ integration of Microsoft Windows NT domain users on a
+ UNIX system. The result is a great reduction in the administrative
+ cost of running a mixed UNIX and NT network.</P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="OS2"
+>Chapter 10. OS2 Client HOWTO</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN1963"
+>10.1. FAQs</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1965"
+>10.1.1. How can I configure OS/2 Warp Connect or
+ OS/2 Warp 4 as a client for Samba?</A
+></H2
+><P
+>A more complete answer to this question can be
+ found on <A
+HREF="http://carol.wins.uva.nl/~leeuw/samba/warp.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/samba/warp.html</A
+>.</P
+><P
+>Basically, you need three components:</P
+><P
+></P
+><UL
+><LI
+><P
+>The File and Print Client ('IBM Peer')
+ </P
+></LI
+><LI
+><P
+>TCP/IP ('Internet support')
+ </P
+></LI
+><LI
+><P
+>The "NetBIOS over TCP/IP" driver ('TCPBEUI')
+ </P
+></LI
+></UL
+><P
+>Installing the first two together with the base operating
+ system on a blank system is explained in the Warp manual. If Warp
+ has already been installed, but you now want to install the
+ networking support, use the "Selective Install for Networking"
+ object in the "System Setup" folder.</P
+><P
+>Adding the "NetBIOS over TCP/IP" driver is not described
+ in the manual and just barely in the online documentation. Start
+ MPTS.EXE, click on OK, click on "Configure LAPS" and click
+ on "IBM OS/2 NETBIOS OVER TCP/IP" in 'Protocols'. This line
+ is then moved to 'Current Configuration'. Select that line,
+ click on "Change number" and increase it from 0 to 1. Save this
+ configuration.</P
+><P
+>If the Samba server(s) is not on your local subnet, you
+ can optionally add IP names and addresses of these servers
+ to the "Names List", or specify a WINS server ('NetBIOS
+ Nameserver' in IBM and RFC terminology). For Warp Connect you
+ may need to download an update for 'IBM Peer' to bring it on
+ the same level as Warp 4. See the webpage mentioned above.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1980"
+>10.1.2. How can I configure OS/2 Warp 3 (not Connect),
+ OS/2 1.2, 1.3 or 2.x for Samba?</A
+></H2
+><P
+>You can use the free Microsoft LAN Manager 2.2c Client
+ for OS/2 from
+ <A
+HREF="ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/"
+TARGET="_top"
+> ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/</A
+>.
+ See <A
+HREF="http://carol.wins.uva.nl/~leeuw/lanman.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/lanman.html</A
+> for
+ more information on how to install and use this client. In
+ a nutshell, edit the file \OS2VER in the root directory of
+ the OS/2 boot partition and add the lines:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> 20=setup.exe
+ 20=netwksta.sys
+ 20=netvdd.sys
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>before you install the client. Also, don't use the
+ included NE2000 driver because it is buggy. Try the NE2000
+ or NS2000 driver from
+ <A
+HREF="ftp://ftp.cdrom.com/pub/os2/network/ndis/"
+TARGET="_top"
+> ftp://ftp.cdrom.com/pub/os2/network/ndis/</A
+> instead.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1989"
+>10.1.3. Are there any other issues when OS/2 (any version)
+ is used as a client?</A
+></H2
+><P
+>When you do a NET VIEW or use the "File and Print
+ Client Resource Browser", no Samba servers show up. This can
+ be fixed by a patch from <A
+HREF="http://carol.wins.uva.nl/~leeuw/samba/fix.html"
+TARGET="_top"
+> http://carol.wins.uva.nl/~leeuw/samba/fix.html</A
+>.
+ The patch will be included in a later version of Samba. It also
+ fixes a couple of other problems, such as preserving long
+ filenames when objects are dragged from the Workplace Shell
+ to the Samba server. </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN1993"
+>10.1.4. How do I get printer driver download working
+ for OS/2 clients?</A
+></H2
+><P
+>First, create a share called [PRINTDRV] that is
+ world-readable. Copy your OS/2 driver files there. Note
+ that the .EA_ files must still be separate, so you will need
+ to use the original install files, and not copy an installed
+ driver from an OS/2 system.</P
+><P
+>Install the NT driver first for that printer. Then,
+ add to your smb.conf a parameter, "os2 driver map =
+ <TT
+CLASS="REPLACEABLE"
+><I
+>filename</I
+></TT
+>". Then, in the file
+ specified by <TT
+CLASS="REPLACEABLE"
+><I
+>filename</I
+></TT
+>, map the
+ name of the NT driver name to the OS/2 driver name as
+ follows:</P
+><P
+>&#60;nt driver name&#62; = &#60;os2 driver
+ name&#62;.&#60;device name&#62;, e.g.:
+ HP LaserJet 5L = LASERJET.HP LaserJet 5L</P
+><P
+>You can have multiple drivers mapped in this file.</P
+><P
+>If you only specify the OS/2 driver name, and not the
+ device name, the first attempt to download the driver will
+ actually download the files, but the OS/2 client will tell
+ you the driver is not available. On the second attempt, it
+ will work. This is fixed simply by adding the device name
+ to the mapping, after which it will work on the first attempt.
+ </P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="CVS-ACCESS"
+>Chapter 11. HOWTO Access Samba source code via CVS</A
+></H1
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN2009"
+>11.1. Introduction</A
+></H1
+><P
+>Samba is developed in an open environment. Developers use CVS
+(Concurrent Versioning System) to "checkin" (also known as
+"commit") new source code. Samba's various CVS branches can
+be accessed via anonymous CVS using the instructions
+detailed in this chapter.</P
+><P
+>This document is a modified version of the instructions found at
+<A
+HREF="http://samba.org/samba/cvs.html"
+TARGET="_top"
+>http://samba.org/samba/cvs.html</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN2014"
+>11.2. CVS Access to samba.org</A
+></H1
+><P
+>The machine samba.org runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. There are two main ways of
+accessing the CVS server on this host.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN2017"
+>11.2.1. Access via CVSweb</A
+></H2
+><P
+>You can access the source code via your
+favourite WWW browser. This allows you to access the contents of
+individual files in the repository and also to look at the revision
+history and commit logs of individual files. You can also ask for a diff
+listing between any two versions on the repository.</P
+><P
+>Use the URL : <A
+HREF="http://samba.org/cgi-bin/cvsweb"
+TARGET="_top"
+>http://samba.org/cgi-bin/cvsweb</A
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN2022"
+>11.2.2. Access via cvs</A
+></H2
+><P
+>You can also access the source code via a
+normal cvs client. This gives you much more control over you can
+do with the repository and allows you to checkout whole source trees
+and keep them up to date via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.</P
+><P
+>To download the latest cvs source code, point your
+browser at the URL : <A
+HREF="http://www.cyclic.com/"
+TARGET="_top"
+>http://www.cyclic.com/</A
+>.
+and click on the 'How to get cvs' link. CVS is free software under
+the GNU GPL (as is Samba). Note that there are several graphical CVS clients
+which provide a graphical interface to the sometimes mundane CVS commands.
+Links to theses clients are also available from http://www.cyclic.com.</P
+><P
+>To gain access via anonymous cvs use the following steps.
+For this example it is assumed that you want a copy of the
+samba source code. For the other source code repositories
+on this system just substitute the correct package name</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot login</B
+>
+ </P
+><P
+> When it asks you for a password type <TT
+CLASS="USERINPUT"
+><B
+>cvs</B
+></TT
+>.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co samba</B
+>
+ </P
+><P
+> This will create a directory called samba containing the
+ latest samba source code (i.e. the HEAD tagged cvs branch). This
+ currently corresponds to the 3.0 development tree.
+ </P
+><P
+> CVS branches other HEAD can be obtained by using the <TT
+CLASS="PARAMETER"
+><I
+>-r</I
+></TT
+>
+ and defining a tag name. A list of branch tag names can be found on the
+ "Development" page of the samba web site. A common request is to obtain the
+ latest 2.2 release code. This could be done by using the following command.
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co -r SAMBA_2_2 samba</B
+>
+ </P
+></LI
+><LI
+><P
+> Whenever you want to merge in the latest code changes use
+ the following command from within the samba directory:
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs update -d -P</B
+>
+ </P
+></LI
+></OL
+></DIV
+></DIV
+></DIV
+><HR><H1
+><A
+NAME="AEN2050"
+>Index</A
+></H1
+><DL
+><DT
+>Primary Domain Controller,
+ <A
+HREF="x1098.htm"
+>Background</A
+>
+ </DT
+></DL
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/Samba-PDC-HOWTO.html b/docs/htmldocs/Samba-PDC-HOWTO.html
new file mode 100644
index 00000000000..58f3989b4f0
--- /dev/null
+++ b/docs/htmldocs/Samba-PDC-HOWTO.html
@@ -0,0 +1,2284 @@
+<HTML
+><HEAD
+><TITLE
+>How to Configure Samba 2.2 as a Primary Domain Controller</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="SAMBA-PDC"
+>How to Configure Samba 2.2 as a Primary Domain Controller</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Prerequisite Reading</A
+></H1
+><P
+>Before you continue reading in this chapter, please make sure
+that you are comfortable with configuring basic files services
+in smb.conf and how to enable and administer password
+encryption in Samba. Theses two topics are covered in the
+<A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+>
+manpage and the <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>Encryption chapter</A
+>
+of this HOWTO Collection.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN9"
+>Background</A
+></H1
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+><I
+CLASS="EMPHASIS"
+>Author's Note:</I
+> This document is a combination
+of David Bannon's "Samba 2.2 PDC HOWTO" and "Samba NT Domain FAQ".
+Both documents are superseded by this one.</P
+></BLOCKQUOTE
+></DIV
+><P
+>Versions of Samba prior to release 2.2 had marginal capabilities to act
+as a Windows NT 4.0 Primary Domain Controller
+
+(PDC). With Samba 2.2.0, we are proud to announce official support for
+Windows NT 4.0-style domain logons from Windows NT 4.0 and Windows
+2000 clients. This article outlines the steps
+necessary for configuring Samba as a PDC. It is necessary to have a
+working Samba server prior to implementing the PDC functionality. If
+you have not followed the steps outlined in <A
+HREF="UNIX_INSTALL.html"
+TARGET="_top"
+> UNIX_INSTALL.html</A
+>, please make sure
+that your server is configured correctly before proceeding. Another
+good resource in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5) man
+page</A
+>. The following functionality should work in 2.2:</P
+><P
+></P
+><UL
+><LI
+><P
+> domain logons for Windows NT 4.0/2000 clients.
+ </P
+></LI
+><LI
+><P
+> placing a Windows 9x client in user level security
+ </P
+></LI
+><LI
+><P
+> retrieving a list of users and groups from a Samba PDC to
+ Windows 9x/NT/2000 clients
+ </P
+></LI
+><LI
+><P
+> roving (roaming) user profiles
+ </P
+></LI
+><LI
+><P
+> Windows NT 4.0-style system policies
+ </P
+></LI
+></UL
+><P
+>The following pieces of functionality are not included in the 2.2 release:</P
+><P
+></P
+><UL
+><LI
+><P
+> Windows NT 4 domain trusts
+ </P
+></LI
+><LI
+><P
+> SAM replication with Windows NT 4.0 Domain Controllers
+ (i.e. a Samba PDC and a Windows NT BDC or vice versa)
+ </P
+></LI
+><LI
+><P
+> Adding users via the User Manager for Domains
+ </P
+></LI
+><LI
+><P
+> Acting as a Windows 2000 Domain Controller (i.e. Kerberos and
+ Active Directory)
+ </P
+></LI
+></UL
+><P
+>Please note that Windows 9x clients are not true members of a domain
+for reasons outlined in this article. Therefore the protocol for
+support Windows 9x-style domain logons is completely different
+from NT4 domain logons and has been officially supported for some
+time.</P
+><P
+>Implementing a Samba PDC can basically be divided into 2 broad
+steps.</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> Configuring the Samba PDC
+ </P
+></LI
+><LI
+><P
+> Creating machine trust accounts and joining clients
+ to the domain
+ </P
+></LI
+></OL
+><P
+>There are other minor details such as user profiles, system
+policies, etc... However, these are not necessarily specific
+to a Samba PDC as much as they are related to Windows NT networking
+concepts. They will be mentioned only briefly here.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN48"
+>Configuring the Samba Domain Controller</A
+></H1
+><P
+>The first step in creating a working Samba PDC is to
+understand the parameters necessary in smb.conf. I will not
+attempt to re-explain the parameters here as they are more that
+adequately covered in <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> the smb.conf
+man page</A
+>. For convenience, the parameters have been
+linked with the actual smb.conf description.</P
+><P
+>Here is an example <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> for acting as a PDC:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ ; Basic server settings
+ <A
+HREF="smb.conf.5.html#NETBIOSNAME"
+TARGET="_top"
+>netbios name</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>POGO</I
+></TT
+>
+ <A
+HREF="smb.conf.5.html#WORKGROUP"
+TARGET="_top"
+>workgroup</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>NARNIA</I
+></TT
+>
+
+ ; we should act as the domain and local master browser
+ <A
+HREF="smb.conf.5.html#OSLEVEL"
+TARGET="_top"
+>os level</A
+> = 64
+ <A
+HREF="smb.conf.5.html#PERFERREDMASTER"
+TARGET="_top"
+>preferred master</A
+> = yes
+ <A
+HREF="smb.conf.5.html#DOMAINMASTER"
+TARGET="_top"
+>domain master</A
+> = yes
+ <A
+HREF="smb.conf.5.html#LOCALMASTER"
+TARGET="_top"
+>local master</A
+> = yes
+
+ ; security settings (must user security = user)
+ <A
+HREF="smb.conf.5.html#SECURITYEQUALSUSER"
+TARGET="_top"
+>security</A
+> = user
+
+ ; encrypted passwords are a requirement for a PDC
+ <A
+HREF="smb.conf.5.html#ENCRYPTPASSWORDS"
+TARGET="_top"
+>encrypt passwords</A
+> = yes
+
+ ; support domain logons
+ <A
+HREF="smb.conf.5.html#DOMAINLOGONS"
+TARGET="_top"
+>domain logons</A
+> = yes
+
+ ; where to store user profiles?
+ <A
+HREF="smb.conf.5.html#LOGONPATH"
+TARGET="_top"
+>logon path</A
+> = \\%N\profiles\%u
+
+ ; where is a user's home directory and where should it
+ ; be mounted at?
+ <A
+HREF="smb.conf.5.html#LOGONDRIVE"
+TARGET="_top"
+>logon drive</A
+> = H:
+ <A
+HREF="smb.conf.5.html#LOGONHOME"
+TARGET="_top"
+>logon home</A
+> = \\homeserver\%u
+
+ ; specify a generic logon script for all users
+ ; this is a relative **DOS** path to the [netlogon] share
+ <A
+HREF="smb.conf.5.html#LOGONSCRIPT"
+TARGET="_top"
+>logon script</A
+> = logon.cmd
+
+; necessary share for domain controller
+[netlogon]
+ <A
+HREF="smb.conf.5.html#PATH"
+TARGET="_top"
+>path</A
+> = /usr/local/samba/lib/netlogon
+ <A
+HREF="smb.conf.5.html#READONLY"
+TARGET="_top"
+>read only</A
+> = yes
+ <A
+HREF="smb.conf.5.html#WRITELIST"
+TARGET="_top"
+>write list</A
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>ntadmin</I
+></TT
+>
+
+; share for storing user profiles
+[profiles]
+ <A
+HREF="smb.conf.5.html#PATH"
+TARGET="_top"
+>path</A
+> = /export/smb/ntprofile
+ <A
+HREF="smb.conf.5.html#READONLY"
+TARGET="_top"
+>read only</A
+> = no
+ <A
+HREF="smb.conf.5.html#CREATEMASK"
+TARGET="_top"
+>create mask</A
+> = 0600
+ <A
+HREF="smb.conf.5.html#DIRECTORYMASK"
+TARGET="_top"
+>directory mask</A
+> = 0700</PRE
+></P
+><P
+>There are a couple of points to emphasize in the above configuration.</P
+><P
+></P
+><UL
+><LI
+><P
+> Encrypted passwords must be enabled. For more details on how
+ to do this, refer to <A
+HREF="ENCRYPTION.html"
+TARGET="_top"
+>ENCRYPTION.html</A
+>.
+ </P
+></LI
+><LI
+><P
+> The server must support domain logons and a
+ <TT
+CLASS="FILENAME"
+>[netlogon]</TT
+> share
+ </P
+></LI
+><LI
+><P
+> The server must be the domain master browser in order for Windows
+ client to locate the server as a DC. Please refer to the various
+ Network Browsing documentation included with this distribution for
+ details.
+ </P
+></LI
+></UL
+><P
+>As Samba 2.2 does not offer a complete implementation of group mapping
+between Windows NT groups and Unix groups (this is really quite
+complicated to explain in a short space), you should refer to the
+<A
+HREF="smb.conf.5.html#DOMAINADMINGROUP"
+TARGET="_top"
+>domain admin
+group</A
+> smb.conf parameter for information of creating "Domain
+Admins" style accounts.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN91"
+>Creating Machine Trust Accounts and Joining Clients to the
+Domain</A
+></H1
+><P
+>A machine trust account is a Samba account that is used to
+authenticate a client machine (rather than a user) to the Samba
+server. In Windows terminology, this is known as a "Computer
+Account."</P
+><P
+>The password of a machine trust account acts as the shared secret for
+secure communication with the Domain Controller. This is a security
+feature to prevent an unauthorized machine with the same NetBIOS name
+from joining the domain and gaining access to domain user/group
+accounts. Windows NT and 2000 clients use machine trust accounts, but
+Windows 9x clients do not. Hence, a Windows 9x client is never a true
+member of a domain because it does not possess a machine trust
+account, and thus has no shared secret with the domain controller.</P
+><P
+>A Windows PDC stores each machine trust account in the Windows
+Registry. A Samba PDC, however, stores each machine trust account
+in two parts, as follows:
+
+<P
+></P
+><UL
+><LI
+><P
+>A Samba account, stored in the same location as user
+ LanMan and NT password hashes (currently
+ <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+>). The Samba account
+ possesses and uses only the NT password hash.</P
+></LI
+><LI
+><P
+>A corresponding Unix account, typically stored in
+ <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>. (Future releases will alleviate the need to
+ create <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entries.) </P
+></LI
+></UL
+></P
+><P
+>There are two ways to create machine trust accounts:</P
+><P
+></P
+><UL
+><LI
+><P
+> Manual creation. Both the Samba and corresponding
+ Unix account are created by hand.</P
+></LI
+><LI
+><P
+> "On-the-fly" creation. The Samba machine trust
+ account is automatically created by Samba at the time the client
+ is joined to the domain. (For security, this is the
+ recommended method.) The corresponding Unix account may be
+ created automatically or manually. </P
+></LI
+></UL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN110"
+>Manual Creation of Machine Trust Accounts</A
+></H2
+><P
+>The first step in manually creating a machine trust account is to
+manually create the corresponding Unix account in
+<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>. This can be done using
+<B
+CLASS="COMMAND"
+>vipw</B
+> or other 'add user' command that is normally
+used to create new Unix accounts. The following is an example for a
+Linux based Samba server:</P
+><P
+> <TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>/usr/sbin/useradd -g 100 -d /dev/null -c <TT
+CLASS="REPLACEABLE"
+><I
+>"machine
+nickname"</I
+></TT
+> -s /bin/false <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+>$ </B
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>passwd -l <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+>$</B
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry will list the machine name
+with a "$" appended, won't have a password, will have a null shell and no
+home directory. For example a machine named 'doppy' would have an
+<TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>doppy$:x:505:501:<TT
+CLASS="REPLACEABLE"
+><I
+>machine_nickname</I
+></TT
+>:/dev/null:/bin/false</PRE
+></P
+><P
+>Above, <TT
+CLASS="REPLACEABLE"
+><I
+>machine_nickname</I
+></TT
+> can be any
+descriptive name for the client, i.e., BasementComputer.
+<TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+> absolutely must be the NetBIOS
+name of the client to be joined to the domain. The "$" must be
+appended to the NetBIOS name of the client or Samba will not recognize
+this as a machine trust account.</P
+><P
+>Now that the corresponding Unix account has been created, the next step is to create
+the Samba account for the client containing the well-known initial
+machine trust account password. This can be done using the <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+> command
+as shown here:</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><B
+CLASS="COMMAND"
+>smbpasswd -a -m <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+></B
+></P
+><P
+>where <TT
+CLASS="REPLACEABLE"
+><I
+>machine_name</I
+></TT
+> is the machine's NetBIOS
+name. The RID of the new machine account is generated from the UID of
+the corresponding Unix account.</P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Join the client to the domain immediately</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+> Manually creating a machine trust account using this method is the
+ equivalent of creating a machine trust account on a Windows NT PDC using
+ the "Server Manager". From the time at which the account is created
+ to the time which the client joins the domain and changes the password,
+ your domain is vulnerable to an intruder joining your domain using a
+ a machine with the same NetBIOS name. A PDC inherently trusts
+ members of the domain and will serve out a large degree of user
+ information to such clients. You have been warned!
+ </P
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN145"
+>"On-the-Fly" Creation of Machine Trust Accounts</A
+></H2
+><P
+>The second (and recommended) way of creating machine trust accounts is
+simply to allow the Samba server to create them as needed when the client
+is joined to the domain. </P
+><P
+>Since each Samba machine trust account requires a corresponding
+Unix account, a method for automatically creating the
+Unix account is usually supplied; this requires configuration of the
+<A
+HREF="smb.conf.5.html#ADDUSERSCRIPT"
+TARGET="_top"
+>add user script</A
+>
+option in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>. This
+method is not required, however; corresponding Unix accounts may also
+be created manually.</P
+><P
+>Below is an example for a RedHat 6.2 Linux system.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ # &#60;...remainder of parameters...&#62;
+ add user script = /usr/sbin/useradd -d /dev/null -g 100 -s /bin/false -M %u </PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN154"
+>Joining the Client to the Domain</A
+></H2
+><P
+>The procedure for joining a client to the domain varies with the
+version of Windows.</P
+><P
+></P
+><UL
+><LI
+><P
+><I
+CLASS="EMPHASIS"
+>Windows 2000</I
+></P
+><P
+> When the user elects to join the client to a domain, Windows prompts for
+ an account and password that is privileged to join the domain. A
+ Samba administrative account (i.e., a Samba account that has root
+ privileges on the Samba server) must be entered here; the
+ operation will fail if an ordinary user account is given.
+ The password for this account should be
+ set to a different password than the associated
+ <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> entry, for security
+ reasons. </P
+><P
+>The session key of the Samba administrative account acts as an
+ encryption key for setting the password of the machine trust
+ account. The machine trust account will be created on-the-fly, or
+ updated if it already exists.</P
+></LI
+><LI
+><P
+><I
+CLASS="EMPHASIS"
+>Windows NT</I
+></P
+><P
+> If the machine trust account was created manually, on the
+ Identification Changes menu enter the domain name, but do not
+ check the box "Create a Computer Account in the Domain." In this case,
+ the existing machine trust account is used to join the machine to
+ the domain.</P
+><P
+> If the machine trust account is to be created
+ on-the-fly, on the Identification Changes menu enter the domain
+ name, and check the box "Create a Computer Account in the Domain." In
+ this case, joining the domain proceeds as above for Windows 2000
+ (i.e., you must supply a Samba administrative account when
+ prompted).</P
+></LI
+></UL
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN169"
+>Common Problems and Errors</A
+></H1
+><P
+></P
+><P
+></P
+><UL
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>I cannot include a '$' in a machine name.</I
+>
+ </P
+><P
+> A 'machine name' in (typically) <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>
+ of the machine name with a '$' appended. FreeBSD (and other BSD
+ systems?) won't create a user with a '$' in their name.
+ </P
+><P
+> The problem is only in the program used to make the entry, once
+ made, it works perfectly. So create a user without the '$' and
+ use <B
+CLASS="COMMAND"
+>vipw</B
+> to edit the entry, adding the '$'. Or create
+ the whole entry with vipw if you like, make sure you use a
+ unique User ID !
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>I get told "You already have a connection to the Domain...."
+ or "Cannot join domain, the credentials supplied conflict with an
+ existing set.." when creating a machine trust account.</I
+>
+ </P
+><P
+> This happens if you try to create a machine trust account from the
+ machine itself and already have a connection (e.g. mapped drive)
+ to a share (or IPC$) on the Samba PDC. The following command
+ will remove all network drive connections:
+ </P
+><P
+> <TT
+CLASS="PROMPT"
+>C:\WINNT\&#62;</TT
+> <B
+CLASS="COMMAND"
+>net use * /d</B
+>
+ </P
+><P
+> Further, if the machine is a already a 'member of a workgroup' that
+ is the same name as the domain you are joining (bad idea) you will
+ get this message. Change the workgroup name to something else, it
+ does not matter what, reboot, and try again.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>The system can not log you on (C000019B)....</I
+>
+ </P
+><P
+>I joined the domain successfully but after upgrading
+ to a newer version of the Samba code I get the message, "The system
+ can not log you on (C000019B), Please try a gain or consult your
+ system administrator" when attempting to logon.
+ </P
+><P
+> This occurs when the domain SID stored in
+ <TT
+CLASS="FILENAME"
+>private/WORKGROUP.SID</TT
+> is
+ changed. For example, you remove the file and <B
+CLASS="COMMAND"
+>smbd</B
+> automatically
+ creates a new one. Or you are swapping back and forth between
+ versions 2.0.7, TNG and the HEAD branch code (not recommended). The
+ only way to correct the problem is to restore the original domain
+ SID or remove the domain client from the domain and rejoin.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>The machine trust account for this computer either does not
+ exist or is not accessible.</I
+>
+ </P
+><P
+> When I try to join the domain I get the message "The machine account
+ for this computer either does not exist or is not accessible". What's
+ wrong?
+ </P
+><P
+> This problem is caused by the PDC not having a suitable machine trust account.
+ If you are using the <TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+> method to create
+ accounts then this would indicate that it has not worked. Ensure the domain
+ admin user system is working.
+ </P
+><P
+> Alternatively if you are creating account entries manually then they
+ have not been created correctly. Make sure that you have the entry
+ correct for the machine trust account in smbpasswd file on the Samba PDC.
+ If you added the account using an editor rather than using the smbpasswd
+ utility, make sure that the account name is the machine NetBIOS name
+ with a '$' appended to it ( i.e. computer_name$ ). There must be an entry
+ in both /etc/passwd and the smbpasswd file. Some people have reported
+ that inconsistent subnet masks between the Samba server and the NT
+ client have caused this problem. Make sure that these are consistent
+ for both client and server.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>When I attempt to login to a Samba Domain from a NT4/W2K workstation,
+ I get a message about my account being disabled.</I
+>
+ </P
+><P
+> This problem is caused by a PAM related bug in Samba 2.2.0. This bug is
+ fixed in 2.2.1. Other symptoms could be unaccessible shares on
+ NT/W2K member servers in the domain or the following error in your smbd.log:
+ passdb/pampass.c:pam_account(268) PAM: UNKNOWN ERROR for User: %user%
+ </P
+><P
+> At first be ensure to enable the useraccounts with <B
+CLASS="COMMAND"
+>smbpasswd -e
+ %user%</B
+>, this is normally done, when you create an account.
+ </P
+><P
+> In order to work around this problem in 2.2.0, configure the
+ <TT
+CLASS="PARAMETER"
+><I
+>account</I
+></TT
+> control flag in
+ <TT
+CLASS="FILENAME"
+>/etc/pam.d/samba</TT
+> file as follows:
+ </P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> account required pam_permit.so
+ </PRE
+></P
+><P
+> If you want to remain backward compatibility to samba 2.0.x use
+ <TT
+CLASS="FILENAME"
+>pam_permit.so</TT
+>, it's also possible to use
+ <TT
+CLASS="FILENAME"
+>pam_pwdb.so</TT
+>. There are some bugs if you try to
+ use <TT
+CLASS="FILENAME"
+>pam_unix.so</TT
+>, if you need this, be ensure to use
+ the most recent version of this file.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN217"
+>System Policies and Profiles</A
+></H1
+><P
+>Much of the information necessary to implement System Policies and
+Roving User Profiles in a Samba domain is the same as that for
+implementing these same items in a Windows NT 4.0 domain.
+You should read the white paper <A
+HREF="http://www.microsoft.com/ntserver/management/deployment/planguide/prof_policies.asp"
+TARGET="_top"
+>Implementing
+Profiles and Policies in Windows NT 4.0</A
+> available from Microsoft.</P
+><P
+>Here are some additional details:</P
+><P
+></P
+><UL
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>What about Windows NT Policy Editor?</I
+>
+ </P
+><P
+> To create or edit <TT
+CLASS="FILENAME"
+>ntconfig.pol</TT
+> you must use
+ the NT Server Policy Editor, <B
+CLASS="COMMAND"
+>poledit.exe</B
+> which
+ is included with NT Server but <I
+CLASS="EMPHASIS"
+>not NT Workstation</I
+>.
+ There is a Policy Editor on a NTws
+ but it is not suitable for creating <I
+CLASS="EMPHASIS"
+>Domain Policies</I
+>.
+ Further, although the Windows 95
+ Policy Editor can be installed on an NT Workstation/Server, it will not
+ work with NT policies because the registry key that are set by the policy templates.
+ However, the files from the NT Server will run happily enough on an NTws.
+ You need <TT
+CLASS="FILENAME"
+>poledit.exe, common.adm</TT
+> and <TT
+CLASS="FILENAME"
+>winnt.adm</TT
+>. It is convenient
+ to put the two *.adm files in <TT
+CLASS="FILENAME"
+>c:\winnt\inf</TT
+> which is where
+ the binary will look for them unless told otherwise. Note also that that
+ directory is 'hidden'.
+ </P
+><P
+> The Windows NT policy editor is also included with the Service Pack 3 (and
+ later) for Windows NT 4.0. Extract the files using <B
+CLASS="COMMAND"
+>servicepackname /x</B
+>,
+ i.e. that's <B
+CLASS="COMMAND"
+>Nt4sp6ai.exe /x</B
+> for service pack 6a. The policy editor,
+ <B
+CLASS="COMMAND"
+>poledit.exe</B
+> and the associated template files (*.adm) should
+ be extracted as well. It is also possible to downloaded the policy template
+ files for Office97 and get a copy of the policy editor. Another possible
+ location is with the Zero Administration Kit available for download from Microsoft.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>Can Win95 do Policies?</I
+>
+ </P
+><P
+> Install the group policy handler for Win9x to pick up group
+ policies. Look on the Win98 CD in <TT
+CLASS="FILENAME"
+>\tools\reskit\netadmin\poledit</TT
+>.
+ Install group policies on a Win9x client by double-clicking
+ <TT
+CLASS="FILENAME"
+>grouppol.inf</TT
+>. Log off and on again a couple of
+ times and see if Win98 picks up group policies. Unfortunately this needs
+ to be done on every Win9x machine that uses group policies....
+ </P
+><P
+> If group policies don't work one reports suggests getting the updated
+ (read: working) grouppol.dll for Windows 9x. The group list is grabbed
+ from /etc/group.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>How do I get 'User Manager' and 'Server Manager'</I
+>
+ </P
+><P
+> Since I don't need to buy an NT Server CD now, how do I get
+ the 'User Manager for Domains', the 'Server Manager'?
+ </P
+><P
+> Microsoft distributes a version of these tools called nexus for
+ installation on Windows 95 systems. The tools set includes
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Server Manager</P
+></LI
+><LI
+><P
+>User Manager for Domains</P
+></LI
+><LI
+><P
+>Event Viewer</P
+></LI
+></UL
+><P
+> Click here to download the archived file <A
+HREF="ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE"
+TARGET="_top"
+>ftp://ftp.microsoft.com/Softlib/MSLFILES/NEXUS.EXE</A
+>
+ </P
+><P
+> The Windows NT 4.0 version of the 'User Manager for
+ Domains' and 'Server Manager' are available from Microsoft via ftp
+ from <A
+HREF="ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE"
+TARGET="_top"
+>ftp://ftp.microsoft.com/Softlib/MSLFILES/SRVTOOLS.EXE</A
+>
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN261"
+>What other help can I get?</A
+></H1
+><P
+>There are many sources of information available in the form
+of mailing lists, RFC's and documentation. The docs that come
+with the samba distribution contain very good explanations of
+general SMB topics such as browsing.</P
+><P
+></P
+><UL
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>What are some diagnostics tools I can use to debug the domain logon
+ process and where can I find them?</I
+>
+ </P
+><P
+> One of the best diagnostic tools for debugging problems is Samba itself.
+ You can use the -d option for both smbd and nmbd to specify what
+ 'debug level' at which to run. See the man pages on smbd, nmbd and
+ smb.conf for more information on debugging options. The debug
+ level can range from 1 (the default) to 10 (100 for debugging passwords).
+ </P
+><P
+> Another helpful method of debugging is to compile samba using the
+ <B
+CLASS="COMMAND"
+>gcc -g </B
+> flag. This will include debug
+ information in the binaries and allow you to attach gdb to the
+ running smbd / nmbd process. In order to attach gdb to an smbd
+ process for an NT workstation, first get the workstation to make the
+ connection. Pressing ctrl-alt-delete and going down to the domain box
+ is sufficient (at least, on the first time you join the domain) to
+ generate a 'LsaEnumTrustedDomains'. Thereafter, the workstation
+ maintains an open connection, and therefore there will be an smbd
+ process running (assuming that you haven't set a really short smbd
+ idle timeout) So, in between pressing ctrl alt delete, and actually
+ typing in your password, you can gdb attach and continue.
+ </P
+><P
+> Some useful samba commands worth investigating:
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>testparam | more</P
+></LI
+><LI
+><P
+>smbclient -L //{netbios name of server}</P
+></LI
+></UL
+><P
+> An SMB enabled version of tcpdump is available from
+ <A
+HREF="http://www.tcpdump.org/"
+TARGET="_top"
+>http://www.tcpdup.org/</A
+>.
+ Ethereal, another good packet sniffer for Unix and Win32
+ hosts, can be downloaded from <A
+HREF="http://www.ethereal.com/"
+TARGET="_top"
+>http://www.ethereal.com</A
+>.
+ </P
+><P
+> For tracing things on the Microsoft Windows NT, Network Monitor
+ (aka. netmon) is available on the Microsoft Developer Network CD's,
+ the Windows NT Server install CD and the SMS CD's. The version of
+ netmon that ships with SMS allows for dumping packets between any two
+ computers (i.e. placing the network interface in promiscuous mode).
+ The version on the NT Server install CD will only allow monitoring
+ of network traffic directed to the local NT box and broadcasts on the
+ local subnet. Be aware that Ethereal can read and write netmon
+ formatted files.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>How do I install 'Network Monitor' on an NT Workstation
+ or a Windows 9x box?</I
+>
+ </P
+><P
+> Installing netmon on an NT workstation requires a couple
+ of steps. The following are for installing Netmon V4.00.349, which comes
+ with Microsoft Windows NT Server 4.0, on Microsoft Windows NT
+ Workstation 4.0. The process should be similar for other version of
+ Windows NT / Netmon. You will need both the Microsoft Windows
+ NT Server 4.0 Install CD and the Workstation 4.0 Install CD.
+ </P
+><P
+> Initially you will need to install 'Network Monitor Tools and Agent'
+ on the NT Server. To do this
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Goto Start - Settings - Control Panel -
+ Network - Services - Add </P
+></LI
+><LI
+><P
+>Select the 'Network Monitor Tools and Agent' and
+ click on 'OK'.</P
+></LI
+><LI
+><P
+>Click 'OK' on the Network Control Panel.
+ </P
+></LI
+><LI
+><P
+>Insert the Windows NT Server 4.0 install CD
+ when prompted.</P
+></LI
+></UL
+><P
+> At this point the Netmon files should exist in
+ <TT
+CLASS="FILENAME"
+>%SYSTEMROOT%\System32\netmon\*.*</TT
+>.
+ Two subdirectories exist as well, <TT
+CLASS="FILENAME"
+>parsers\</TT
+>
+ which contains the necessary DLL's for parsing the netmon packet
+ dump, and <TT
+CLASS="FILENAME"
+>captures\</TT
+>.
+ </P
+><P
+> In order to install the Netmon tools on an NT Workstation, you will
+ first need to install the 'Network Monitor Agent' from the Workstation
+ install CD.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Goto Start - Settings - Control Panel -
+ Network - Services - Add</P
+></LI
+><LI
+><P
+>Select the 'Network Monitor Agent' and click
+ on 'OK'.</P
+></LI
+><LI
+><P
+>Click 'OK' on the Network Control Panel.
+ </P
+></LI
+><LI
+><P
+>Insert the Windows NT Workstation 4.0 install
+ CD when prompted.</P
+></LI
+></UL
+><P
+> Now copy the files from the NT Server in %SYSTEMROOT%\System32\netmon\*.*
+ to %SYSTEMROOT%\System32\netmon\*.* on the Workstation and set
+ permissions as you deem appropriate for your site. You will need
+ administrative rights on the NT box to run netmon.
+ </P
+><P
+> To install Netmon on a Windows 9x box install the network monitor agent
+ from the Windows 9x CD (\admin\nettools\netmon). There is a readme
+ file located with the netmon driver files on the CD if you need
+ information on how to do this. Copy the files from a working
+ Netmon installation.
+ </P
+></LI
+><LI
+><P
+> The following is a list if helpful URLs and other links:
+ </P
+><P
+></P
+><UL
+><LI
+><P
+>Home of Samba site <A
+HREF="http://samba.org"
+TARGET="_top"
+> http://samba.org</A
+>. We have a mirror near you !</P
+></LI
+><LI
+><P
+> The <I
+CLASS="EMPHASIS"
+>Development</I
+> document
+ on the Samba mirrors might mention your problem. If so,
+ it might mean that the developers are working on it.</P
+></LI
+><LI
+><P
+>See how Scott Merrill simulates a BDC behavior at
+ <A
+HREF="http://www.skippy.net/linux/smb-howto.html"
+TARGET="_top"
+> http://www.skippy.net/linux/smb-howto.html</A
+>. </P
+></LI
+><LI
+><P
+>Although 2.0.7 has almost had its day as a PDC, David Bannon will
+ keep the 2.0.7 PDC pages at <A
+HREF="http://bioserve.latrobe.edu.au/samba"
+TARGET="_top"
+> http://bioserve.latrobe.edu.au/samba</A
+> going for a while yet.</P
+></LI
+><LI
+><P
+>Misc links to CIFS information
+ <A
+HREF="http://samba.org/cifs/"
+TARGET="_top"
+>http://samba.org/cifs/</A
+></P
+></LI
+><LI
+><P
+>NT Domains for Unix <A
+HREF="http://mailhost.cb1.com/~lkcl/ntdom/"
+TARGET="_top"
+> http://mailhost.cb1.com/~lkcl/ntdom/</A
+></P
+></LI
+><LI
+><P
+>FTP site for older SMB specs:
+ <A
+HREF="ftp://ftp.microsoft.com/developr/drg/CIFS/"
+TARGET="_top"
+> ftp://ftp.microsoft.com/developr/drg/CIFS/</A
+></P
+></LI
+></UL
+></LI
+></UL
+><P
+></P
+><UL
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>How do I get help from the mailing lists?</I
+>
+ </P
+><P
+> There are a number of Samba related mailing lists. Go to <A
+HREF="http://samba.org"
+TARGET="_top"
+>http://samba.org</A
+>, click on your nearest mirror
+ and then click on <B
+CLASS="COMMAND"
+>Support</B
+> and then click on <B
+CLASS="COMMAND"
+> Samba related mailing lists</B
+>.
+ </P
+><P
+> For questions relating to Samba TNG go to
+ <A
+HREF="http://www.samba-tng.org/"
+TARGET="_top"
+>http://www.samba-tng.org/</A
+>
+ It has been requested that you don't post questions about Samba-TNG to the
+ main stream Samba lists.</P
+><P
+> If you post a message to one of the lists please observe the following guide lines :
+ </P
+><P
+></P
+><UL
+><LI
+><P
+> Always remember that the developers are volunteers, they are
+ not paid and they never guarantee to produce a particular feature at
+ a particular time. Any time lines are 'best guess' and nothing more.
+ </P
+></LI
+><LI
+><P
+> Always mention what version of samba you are using and what
+ operating system its running under. You should probably list the
+ relevant sections of your smb.conf file, at least the options
+ in [global] that affect PDC support.</P
+></LI
+><LI
+><P
+>In addition to the version, if you obtained Samba via
+ CVS mention the date when you last checked it out.</P
+></LI
+><LI
+><P
+> Try and make your question clear and brief, lots of long,
+ convoluted questions get deleted before they are completely read !
+ Don't post html encoded messages (if you can select colour or font
+ size its html).</P
+></LI
+><LI
+><P
+> If you run one of those nifty 'I'm on holidays' things when
+ you are away, make sure its configured to not answer mailing lists.
+ </P
+></LI
+><LI
+><P
+> Don't cross post. Work out which is the best list to post to
+ and see what happens, i.e. don't post to both samba-ntdom and samba-technical.
+ Many people active on the lists subscribe to more
+ than one list and get annoyed to see the same message two or more times.
+ Often someone will see a message and thinking it would be better dealt
+ with on another, will forward it on for you.</P
+></LI
+><LI
+><P
+>You might include <I
+CLASS="EMPHASIS"
+>partial</I
+>
+ log files written at a debug level set to as much as 20.
+ Please don't send the entire log but enough to give the context of the
+ error messages.</P
+></LI
+><LI
+><P
+>(Possibly) If you have a complete netmon trace ( from the opening of
+ the pipe to the error ) you can send the *.CAP file as well.</P
+></LI
+><LI
+><P
+>Please think carefully before attaching a document to an email.
+ Consider pasting the relevant parts into the body of the message. The samba
+ mailing lists go to a huge number of people, do they all need a copy of your
+ smb.conf in their attach directory?</P
+></LI
+></UL
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>How do I get off the mailing lists?</I
+>
+ </P
+><P
+>To have your name removed from a samba mailing list, go to the
+ same place you went to to get on it. Go to <A
+HREF="http://lists.samba.org/"
+TARGET="_top"
+>http://lists.samba.org</A
+>,
+ click on your nearest mirror and then click on <B
+CLASS="COMMAND"
+>Support</B
+> and
+ then click on <B
+CLASS="COMMAND"
+> Samba related mailing lists</B
+>. Or perhaps see
+ <A
+HREF="http://lists.samba.org/mailman/roster/samba-ntdom"
+TARGET="_top"
+>here</A
+>
+ </P
+><P
+> Please don't post messages to the list asking to be removed, you will just
+ be referred to the above address (unless that process failed in some way...)
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN375"
+>Domain Control for Windows 9x/ME</A
+></H1
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>The following section contains much of the original
+DOMAIN.txt file previously included with Samba. Much of
+the material is based on what went into the book <I
+CLASS="EMPHASIS"
+>Special
+Edition, Using Samba</I
+>, by Richard Sharpe.</P
+></BLOCKQUOTE
+></DIV
+><P
+>A domain and a workgroup are exactly the same thing in terms of network
+browsing. The difference is that a distributable authentication
+database is associated with a domain, for secure login access to a
+network. Also, different access rights can be granted to users if they
+successfully authenticate against a domain logon server (NT server and
+other systems based on NT server support this, as does at least Samba TNG now).</P
+><P
+>The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+Network browsing functionality of domains and workgroups is
+identical and is explained in BROWSING.txt. It should be noted, that browsing
+is totally orthogonal to logon support.</P
+><P
+>Issues related to the single-logon network model are discussed in this
+section. Samba supports domain logons, network logon scripts, and user
+profiles for MS Windows for workgroups and MS Windows 9X/ME clients
+which will be the focus of this section.</P
+><P
+>When an SMB client in a domain wishes to logon it broadcast requests for a
+logon server. The first one to reply gets the job, and validates its
+password using whatever mechanism the Samba administrator has installed.
+It is possible (but very stupid) to create a domain where the user
+database is not shared between servers, i.e. they are effectively workgroup
+servers advertising themselves as participating in a domain. This
+demonstrates how authentication is quite different from but closely
+involved with domains.</P
+><P
+>Using these features you can make your clients verify their logon via
+the Samba server; make clients run a batch file when they logon to
+the network and download their preferences, desktop and start menu.</P
+><P
+>Before launching into the configuration instructions, it is
+worthwhile lookingat how a Windows 9x/ME client performs a logon:</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> The client broadcasts (to the IP broadcast address of the subnet it is in)
+ a NetLogon request. This is sent to the NetBIOS name DOMAIN&#60;1c&#62; at the
+ NetBIOS layer. The client chooses the first response it receives, which
+ contains the NetBIOS name of the logon server to use in the format of
+ \\SERVER.
+ </P
+></LI
+><LI
+><P
+> The client then connects to that server, logs on (does an SMBsessetupX) and
+ then connects to the IPC$ share (using an SMBtconX).
+ </P
+></LI
+><LI
+><P
+> The client then does a NetWkstaUserLogon request, which retrieves the name
+ of the user's logon script.
+ </P
+></LI
+><LI
+><P
+> The client then connects to the NetLogon share and searches for this
+ and if it is found and can be read, is retrieved and executed by the client.
+ After this, the client disconnects from the NetLogon share.
+ </P
+></LI
+><LI
+><P
+> The client then sends a NetUserGetInfo request to the server, to retrieve
+ the user's home share, which is used to search for profiles. Since the
+ response to the NetUserGetInfo request does not contain much more
+ the user's home share, profiles for Win9X clients MUST reside in the user
+ home directory.
+ </P
+></LI
+><LI
+><P
+> The client then connects to the user's home share and searches for the
+ user's profile. As it turns out, you can specify the user's home share as
+ a sharename and path. For example, \\server\fred\.profile.
+ If the profiles are found, they are implemented.
+ </P
+></LI
+><LI
+><P
+> The client then disconnects from the user's home share, and reconnects to
+ the NetLogon share and looks for CONFIG.POL, the policies file. If this is
+ found, it is read and implemented.
+ </P
+></LI
+></OL
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN401"
+>Configuration Instructions: Network Logons</A
+></H2
+><P
+>The main difference between a PDC and a Windows 9x logon
+server configuration is that</P
+><P
+></P
+><UL
+><LI
+><P
+>Password encryption is not required for a Windows 9x logon server.</P
+></LI
+><LI
+><P
+>Windows 9x/ME clients do not possess machine trust accounts.</P
+></LI
+></UL
+><P
+>Therefore, a Samba PDC will also act as a Windows 9x logon
+server.</P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>security mode and master browsers</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>There are a few comments to make in order to tie up some
+loose ends. There has been much debate over the issue of whether
+or not it is ok to configure Samba as a Domain Controller in security
+modes other than <TT
+CLASS="CONSTANT"
+>USER</TT
+>. The only security mode
+which will not work due to technical reasons is <TT
+CLASS="CONSTANT"
+>SHARE</TT
+>
+mode security. <TT
+CLASS="CONSTANT"
+>DOMAIN</TT
+> and <TT
+CLASS="CONSTANT"
+>SERVER</TT
+>
+mode security is really just a variation on SMB user level security.</P
+><P
+>Actually, this issue is also closely tied to the debate on whether
+or not Samba must be the domain master browser for its workgroup
+when operating as a DC. While it may technically be possible
+to configure a server as such (after all, browsing and domain logons
+are two distinctly different functions), it is not a good idea to
+so. You should remember that the DC must register the DOMAIN#1b NetBIOS
+name. This is the name used by Windows clients to locate the DC.
+Windows clients do not distinguish between the DC and the DMB.
+For this reason, it is very wise to configure the Samba DC as the DMB.</P
+><P
+>Now back to the issue of configuring a Samba DC to use a mode other
+than "security = user". If a Samba host is configured to use
+another SMB server or DC in order to validate user connection
+requests, then it is a fact that some other machine on the network
+(the "password server") knows more about user than the Samba host.
+99% of the time, this other host is a domain controller. Now
+in order to operate in domain mode security, the "workgroup" parameter
+must be set to the name of the Windows NT domain (which already
+has a domain controller, right?)</P
+><P
+>Therefore configuring a Samba box as a DC for a domain that
+already by definition has a PDC is asking for trouble.
+Therefore, you should always configure the Samba DC to be the DMB
+for its domain.</P
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN420"
+>Configuration Instructions: Setting up Roaming User Profiles</A
+></H2
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Warning</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+><I
+CLASS="EMPHASIS"
+>NOTE!</I
+> Roaming profiles support is different
+for Win9X and WinNT.</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>Before discussing how to configure roaming profiles, it is useful to see how
+Win9X and WinNT clients implement these features.</P
+><P
+>Win9X clients send a NetUserGetInfo request to the server to get the user's
+profiles location. However, the response does not have room for a separate
+profiles location field, only the user's home share. This means that Win9X
+profiles are restricted to being in the user's home directory.</P
+><P
+>WinNT clients send a NetSAMLogon RPC request, which contains many fields,
+including a separate field for the location of the user's profiles.
+This means that support for profiles is different for Win9X and WinNT.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN428"
+>Windows NT Configuration</A
+></H3
+><P
+>To support WinNT clients, in the [global] section of smb.conf set the
+following (for example):</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>logon path = \\profileserver\profileshare\profilepath\%U\moreprofilepath</PRE
+></P
+><P
+>The default for this option is \\%N\%U\profile, namely
+\\sambaserver\username\profile. The \\N%\%U service is created
+automatically by the [homes] service.
+If you are using a samba server for the profiles, you _must_ make the
+share specified in the logon path browseable. </P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 26aug96 - we have discovered a problem where Windows clients can
+maintain a connection to the [homes] share in between logins. The
+[homes] share must NOT therefore be used in a profile path.]</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN436"
+>Windows 9X Configuration</A
+></H3
+><P
+>To support Win9X clients, you must use the "logon home" parameter. Samba has
+now been fixed so that "net use/home" now works as well, and it, too, relies
+on the "logon home" parameter.</P
+><P
+>By using the logon home parameter, you are restricted to putting Win9X
+profiles in the user's home directory. But wait! There is a trick you
+can use. If you set the following in the [global] section of your
+smb.conf file:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>logon home = \\%L\%U\.profiles</PRE
+></P
+><P
+>then your Win9X clients will dutifully put their clients in a subdirectory
+of your home directory called .profiles (thus making them hidden).</P
+><P
+>Not only that, but 'net use/home' will also work, because of a feature in
+Win9X. It removes any directory stuff off the end of the home directory area
+and only uses the server and share portion. That is, it looks like you
+specified \\%L\%U for "logon home".</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN444"
+>Win9X and WinNT Configuration</A
+></H3
+><P
+>You can support profiles for both Win9X and WinNT clients by setting both the
+"logon home" and "logon path" parameters. For example:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>logon home = \\%L\%U\.profiles
+logon path = \\%L\profiles\%U</PRE
+></P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>I have not checked what 'net use /home' does on NT when "logon home" is
+set as above.</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN451"
+>Windows 9X Profile Setup</A
+></H3
+><P
+>When a user first logs in on Windows 9X, the file user.DAT is created,
+as are folders "Start Menu", "Desktop", "Programs" and "Nethood".
+These directories and their contents will be merged with the local
+versions stored in c:\windows\profiles\username on subsequent logins,
+taking the most recent from each. You will need to use the [global]
+options "preserve case = yes", "short preserve case = yes" and
+"case sensitive = no" in order to maintain capital letters in shortcuts
+in any of the profile folders.</P
+><P
+>The user.DAT file contains all the user's preferences. If you wish to
+enforce a set of preferences, rename their user.DAT file to user.MAN,
+and deny them write access to this file.</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> On the Windows 95 machine, go to Control Panel | Passwords and
+ select the User Profiles tab. Select the required level of
+ roaming preferences. Press OK, but do _not_ allow the computer
+ to reboot.
+ </P
+></LI
+><LI
+><P
+> On the Windows 95 machine, go to Control Panel | Network |
+ Client for Microsoft Networks | Preferences. Select 'Log on to
+ NT Domain'. Then, ensure that the Primary Logon is 'Client for
+ Microsoft Networks'. Press OK, and this time allow the computer
+ to reboot.
+ </P
+></LI
+></OL
+><P
+>Under Windows 95, Profiles are downloaded from the Primary Logon.
+If you have the Primary Logon as 'Client for Novell Networks', then
+the profiles and logon script will be downloaded from your Novell
+Server. If you have the Primary Logon as 'Windows Logon', then the
+profiles will be loaded from the local machine - a bit against the
+concept of roaming profiles, if you ask me.</P
+><P
+>You will now find that the Microsoft Networks Login box contains
+[user, password, domain] instead of just [user, password]. Type in
+the samba server's domain name (or any other domain known to exist,
+but bear in mind that the user will be authenticated against this
+domain and profiles downloaded from it, if that domain logon server
+supports it), user name and user's password.</P
+><P
+>Once the user has been successfully validated, the Windows 95 machine
+will inform you that 'The user has not logged on before' and asks you
+if you wish to save the user's preferences? Select 'yes'.</P
+><P
+>Once the Windows 95 client comes up with the desktop, you should be able
+to examine the contents of the directory specified in the "logon path"
+on the samba server and verify that the "Desktop", "Start Menu",
+"Programs" and "Nethood" folders have been created.</P
+><P
+>These folders will be cached locally on the client, and updated when
+the user logs off (if you haven't made them read-only by then :-).
+You will find that if the user creates further folders or short-cuts,
+that the client will merge the profile contents downloaded with the
+contents of the profile directory already on the local client, taking
+the newest folders and short-cuts from each set.</P
+><P
+>If you have made the folders / files read-only on the samba server,
+then you will get errors from the w95 machine on logon and logout, as
+it attempts to merge the local and the remote profile. Basically, if
+you have any errors reported by the w95 machine, check the Unix file
+permissions and ownership rights on the profile directory contents,
+on the samba server.</P
+><P
+>If you have problems creating user profiles, you can reset the user's
+local desktop cache, as shown below. When this user then next logs in,
+they will be told that they are logging in "for the first time".</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> instead of logging in under the [user, password, domain] dialog,
+ press escape.
+ </P
+></LI
+><LI
+><P
+> run the regedit.exe program, and look in:
+ </P
+><P
+> HKEY_LOCAL_MACHINE\Windows\CurrentVersion\ProfileList
+ </P
+><P
+> you will find an entry, for each user, of ProfilePath. Note the
+ contents of this key (likely to be c:\windows\profiles\username),
+ then delete the key ProfilePath for the required user.
+ </P
+><P
+> [Exit the registry editor].
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>WARNING</I
+> - before deleting the contents of the
+ directory listed in
+ the ProfilePath (this is likely to be c:\windows\profiles\username),
+ ask them if they have any important files stored on their desktop
+ or in their start menu. delete the contents of the directory
+ ProfilePath (making a backup if any of the files are needed).
+ </P
+><P
+> This will have the effect of removing the local (read-only hidden
+ system file) user.DAT in their profile directory, as well as the
+ local "desktop", "nethood", "start menu" and "programs" folders.
+ </P
+></LI
+><LI
+><P
+> search for the user's .PWL password-caching file in the c:\windows
+ directory, and delete it.
+ </P
+></LI
+><LI
+><P
+> log off the windows 95 client.
+ </P
+></LI
+><LI
+><P
+> check the contents of the profile path (see "logon path" described
+ above), and delete the user.DAT or user.MAN file for the user,
+ making a backup if required.
+ </P
+></LI
+></OL
+><P
+>If all else fails, increase samba's debug log levels to between 3 and 10,
+and / or run a packet trace program such as tcpdump or netmon.exe, and
+look for any error reports.</P
+><P
+>If you have access to an NT server, then first set up roaming profiles
+and / or netlogons on the NT server. Make a packet trace, or examine
+the example packet traces provided with NT server, and see what the
+differences are with the equivalent samba trace.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN487"
+>Windows NT Workstation 4.0</A
+></H3
+><P
+>When a user first logs in to a Windows NT Workstation, the profile
+NTuser.DAT is created. The profile location can be now specified
+through the "logon path" parameter. </P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 10aug97 - i tried setting the path to
+\\samba-server\homes\profile, and discovered that this fails because
+a background process maintains the connection to the [homes] share
+which does _not_ close down in between user logins. you have to
+have \\samba-server\%L\profile, where user is the username created
+from the [homes] share].</P
+></BLOCKQUOTE
+></DIV
+><P
+>There is a parameter that is now available for use with NT Profiles:
+"logon drive". This should be set to "h:" or any other drive, and
+should be used in conjunction with the new "logon home" parameter.</P
+><P
+>The entry for the NT 4.0 profile is a _directory_ not a file. The NT
+help on profiles mentions that a directory is also created with a .PDS
+extension. The user, while logging in, must have write permission to
+create the full profile path (and the folder with the .PDS extension)
+[lkcl 10aug97 - i found that the creation of the .PDS directory failed,
+and had to create these manually for each user, with a shell script.
+also, i presume, but have not tested, that the full profile path must
+be browseable just as it is for w95, due to the manner in which they
+attempt to create the full profile path: test existence of each path
+component; create path component].</P
+><P
+>In the profile directory, NT creates more folders than 95. It creates
+"Application Data" and others, as well as "Desktop", "Nethood",
+"Start Menu" and "Programs". The profile itself is stored in a file
+NTuser.DAT. Nothing appears to be stored in the .PDS directory, and
+its purpose is currently unknown.</P
+><P
+>You can use the System Control Panel to copy a local profile onto
+a samba server (see NT Help on profiles: it is also capable of firing
+up the correct location in the System Control Panel for you). The
+NT Help file also mentions that renaming NTuser.DAT to NTuser.MAN
+turns a profile into a mandatory one.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 10aug97 - i notice that NT Workstation tells me that it is
+downloading a profile from a slow link. whether this is actually the
+case, or whether there is some configuration issue, as yet unknown,
+that makes NT Workstation _think_ that the link is a slow one is a
+matter to be resolved].</P
+><P
+>[lkcl 20aug97 - after samba digest correspondence, one user found, and
+another confirmed, that profiles cannot be loaded from a samba server
+unless "security = user" and "encrypt passwords = yes" (see the file
+ENCRYPTION.txt) or "security = server" and "password server = ip.address.
+of.yourNTserver" are used. Either of these options will allow the NT
+workstation to access the samba server using LAN manager encrypted
+passwords, without the user intervention normally required by NT
+workstation for clear-text passwords].</P
+><P
+>[lkcl 25aug97 - more comments received about NT profiles: the case of
+the profile _matters_. the file _must_ be called NTuser.DAT or, for
+a mandatory profile, NTuser.MAN].</P
+></BLOCKQUOTE
+></DIV
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN500"
+>Windows NT Server</A
+></H3
+><P
+>There is nothing to stop you specifying any path that you like for the
+location of users' profiles. Therefore, you could specify that the
+profile be stored on a samba server, or any other SMB server, as long as
+that SMB server supports encrypted passwords.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN503"
+>Sharing Profiles between W95 and NT Workstation 4.0</A
+></H3
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Potentially outdated or incorrect material follows</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>I think this is all bogus, but have not deleted it. (Richard Sharpe)</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>The default logon path is \\%N\U%. NT Workstation will attempt to create
+a directory "\\samba-server\username.PDS" if you specify the logon path
+as "\\samba-server\username" with the NT User Manager. Therefore, you
+will need to specify (for example) "\\samba-server\username\profile".
+NT 4.0 will attempt to create "\\samba-server\username\profile.PDS", which
+is more likely to succeed.</P
+><P
+>If you then want to share the same Start Menu / Desktop with W95, you will
+need to specify "logon path = \\samba-server\username\profile" [lkcl 10aug97
+this has its drawbacks: i created a shortcut to telnet.exe, which attempts
+to run from the c:\winnt\system32 directory. this directory is obviously
+unlikely to exist on a Win95-only host].</P
+><P
+>&#13;If you have this set up correctly, you will find separate user.DAT and
+NTuser.DAT files in the same profile directory.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>[lkcl 25aug97 - there are some issues to resolve with downloading of
+NT profiles, probably to do with time/date stamps. i have found that
+NTuser.DAT is never updated on the workstation after the first time that
+it is copied to the local workstation profile directory. this is in
+contrast to w95, where it _does_ transfer / update profiles correctly].</P
+></BLOCKQUOTE
+></DIV
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN513"
+>DOMAIN_CONTROL.txt : Windows NT Domain Control &#38; Samba</A
+></H1
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Possibly Outdated Material</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+> This appendix was originally authored by John H Terpstra of
+ the Samba Team and is included here for posterity.
+ </P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+><I
+CLASS="EMPHASIS"
+>NOTE :</I
+>
+The term "Domain Controller" and those related to it refer to one specific
+method of authentication that can underly an SMB domain. Domain Controllers
+prior to Windows NT Server 3.1 were sold by various companies and based on
+private extensions to the LAN Manager 2.1 protocol. Windows NT introduced
+Microsoft-specific ways of distributing the user authentication database.
+See DOMAIN.txt for examples of how Samba can participate in or create
+SMB domains based on shared authentication database schemes other than the
+Windows NT SAM.</P
+><P
+>Windows NT Server can be installed as either a plain file and print server
+(WORKGROUP workstation or server) or as a server that participates in Domain
+Control (DOMAIN member, Primary Domain controller or Backup Domain controller).
+The same is true for OS/2 Warp Server, Digital Pathworks and other similar
+products, all of which can participate in Domain Control along with Windows NT.</P
+><P
+>To many people these terms can be confusing, so let's try to clear the air.</P
+><P
+>Every Windows NT system (workstation or server) has a registry database.
+The registry contains entries that describe the initialization information
+for all services (the equivalent of Unix Daemons) that run within the Windows
+NT environment. The registry also contains entries that tell application
+software where to find dynamically loadable libraries that they depend upon.
+In fact, the registry contains entries that describes everything that anything
+may need to know to interact with the rest of the system.</P
+><P
+>The registry files can be located on any Windows NT machine by opening a
+command prompt and typing:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINNT\&#62;</TT
+> dir %SystemRoot%\System32\config</P
+><P
+>The environment variable %SystemRoot% value can be obtained by typing:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINNT&#62;</TT
+>echo %SystemRoot%</P
+><P
+>The active parts of the registry that you may want to be familiar with are
+the files called: default, system, software, sam and security.</P
+><P
+>In a domain environment, Microsoft Windows NT domain controllers participate
+in replication of the SAM and SECURITY files so that all controllers within
+the domain have an exactly identical copy of each.</P
+><P
+>The Microsoft Windows NT system is structured within a security model that
+says that all applications and services must authenticate themselves before
+they can obtain permission from the security manager to do what they set out
+to do.</P
+><P
+>The Windows NT User database also resides within the registry. This part of
+the registry contains the user's security identifier, home directory, group
+memberships, desktop profile, and so on.</P
+><P
+>Every Windows NT system (workstation as well as server) will have its own
+registry. Windows NT Servers that participate in Domain Security control
+have a database that they share in common - thus they do NOT own an
+independent full registry database of their own, as do Workstations and
+plain Servers.</P
+><P
+>The User database is called the SAM (Security Access Manager) database and
+is used for all user authentication as well as for authentication of inter-
+process authentication (i.e. to ensure that the service action a user has
+requested is permitted within the limits of that user's privileges).</P
+><P
+>The Samba team have produced a utility that can dump the Windows NT SAM into
+smbpasswd format: see ENCRYPTION.txt for information on smbpasswd and
+/pub/samba/pwdump on your nearest Samba mirror for the utility. This
+facility is useful but cannot be easily used to implement SAM replication
+to Samba systems.</P
+><P
+>Windows for Workgroups, Windows 95, and Windows NT Workstations and Servers
+can participate in a Domain security system that is controlled by Windows NT
+servers that have been correctly configured. Almost every domain will have
+ONE Primary Domain Controller (PDC). It is desirable that each domain will
+have at least one Backup Domain Controller (BDC).</P
+><P
+>The PDC and BDCs then participate in replication of the SAM database so that
+each Domain Controlling participant will have an up to date SAM component
+within its registry.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/UNIX_INSTALL.html b/docs/htmldocs/UNIX_INSTALL.html
new file mode 100644
index 00000000000..7194e1154ec
--- /dev/null
+++ b/docs/htmldocs/UNIX_INSTALL.html
@@ -0,0 +1,820 @@
+<HTML
+><HEAD
+><TITLE
+>How to Install and Test SAMBA</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="INSTALL"
+>How to Install and Test SAMBA</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Step 0: Read the man pages</A
+></H1
+><P
+>The man pages distributed with SAMBA contain
+ lots of useful info that will help to get you started.
+ If you don't know how to read man pages then try
+ something like:</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>nroff -man smbd.8 | more
+ </B
+></TT
+></P
+><P
+>Other sources of information are pointed to
+ by the Samba web site,<A
+HREF="http://www.samba.org/"
+TARGET="_top"
+> http://www.samba.org</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN11"
+>Step 1: Building the Binaries</A
+></H1
+><P
+>To do this, first run the program <B
+CLASS="COMMAND"
+>./configure
+ </B
+> in the source directory. This should automatically
+ configure Samba for your operating system. If you have unusual
+ needs then you may wish to run</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>./configure --help
+ </B
+></TT
+></P
+><P
+>first to see what special options you can enable.
+ Then executing</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make</B
+></TT
+></P
+><P
+>will create the binaries. Once it's successfully
+ compiled you can use </P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make install</B
+></TT
+></P
+><P
+>to install the binaries and manual pages. You can
+ separately install the binaries and/or man pages using</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make installbin
+ </B
+></TT
+></P
+><P
+>and</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make installman
+ </B
+></TT
+></P
+><P
+>Note that if you are upgrading for a previous version
+ of Samba you might like to know that the old versions of
+ the binaries will be renamed with a ".old" extension. You
+ can go back to the previous version with</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>make revert
+ </B
+></TT
+></P
+><P
+>if you find this version a disaster!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN39"
+>Step 2: The all important step</A
+></H1
+><P
+>At this stage you must fetch yourself a
+ coffee or other drink you find stimulating. Getting the rest
+ of the install right can sometimes be tricky, so you will
+ probably need it.</P
+><P
+>If you have installed samba before then you can skip
+ this step.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN43"
+>Step 3: Create the smb configuration file.</A
+></H1
+><P
+>There are sample configuration files in the examples
+ subdirectory in the distribution. I suggest you read them
+ carefully so you can see how the options go together in
+ practice. See the man page for all the options.</P
+><P
+>The simplest useful configuration file would be
+ something like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> [global]
+ workgroup = MYGROUP
+
+ [homes]
+ guest ok = no
+ read only = no
+ </PRE
+></P
+><P
+>which would allow connections by anyone with an
+ account on the server, using either their login name or
+ "homes" as the service name. (Note that I also set the
+ workgroup that Samba is part of. See BROWSING.txt for details)</P
+><P
+>Note that <B
+CLASS="COMMAND"
+>make install</B
+> will not install
+ a <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. You need to create it
+ yourself. </P
+><P
+>Make sure you put the smb.conf file in the same place
+ you specified in the<TT
+CLASS="FILENAME"
+>Makefile</TT
+> (the default is to
+ look for it in <TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/</TT
+>).</P
+><P
+>For more information about security settings for the
+ [homes] share please refer to the document UNIX_SECURITY.txt.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN57"
+>Step 4: Test your config file with
+ <B
+CLASS="COMMAND"
+>testparm</B
+></A
+></H1
+><P
+>It's important that you test the validity of your
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file using the testparm program.
+ If testparm runs OK then it will list the loaded services. If
+ not it will give an error message.</P
+><P
+>Make sure it runs OK and that the services look
+ reasonable before proceeding. </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN63"
+>Step 5: Starting the smbd and nmbd</A
+></H1
+><P
+>You must choose to start smbd and nmbd either
+ as daemons or from <B
+CLASS="COMMAND"
+>inetd</B
+>. Don't try
+ to do both! Either you can put them in <TT
+CLASS="FILENAME"
+> inetd.conf</TT
+> and have them started on demand
+ by <B
+CLASS="COMMAND"
+>inetd</B
+>, or you can start them as
+ daemons either from the command line or in <TT
+CLASS="FILENAME"
+> /etc/rc.local</TT
+>. See the man pages for details
+ on the command line options. Take particular care to read
+ the bit about what user you need to be in order to start
+ Samba. In many cases you must be root.</P
+><P
+>The main advantage of starting <B
+CLASS="COMMAND"
+>smbd</B
+>
+ and <B
+CLASS="COMMAND"
+>nmbd</B
+> as a daemon is that they will
+ respond slightly more quickly to an initial connection
+ request. This is, however, unlikely to be a problem.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN73"
+>Step 5a: Starting from inetd.conf</A
+></H2
+><P
+>NOTE; The following will be different if
+ you use NIS or NIS+ to distributed services maps.</P
+><P
+>Look at your <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>.
+ What is defined at port 139/tcp. If nothing is defined
+ then add a line like this:</P
+><P
+><TT
+CLASS="USERINPUT"
+><B
+>netbios-ssn 139/tcp</B
+></TT
+></P
+><P
+>similarly for 137/udp you should have an entry like:</P
+><P
+><TT
+CLASS="USERINPUT"
+><B
+>netbios-ns 137/udp</B
+></TT
+></P
+><P
+>Next edit your <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>
+ and add two lines something like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+ netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+ </PRE
+></P
+><P
+>The exact syntax of <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>
+ varies between unixes. Look at the other entries in inetd.conf
+ for a guide.</P
+><P
+>NOTE: Some unixes already have entries like netbios_ns
+ (note the underscore) in <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>.
+ You must either edit <TT
+CLASS="FILENAME"
+>/etc/services</TT
+> or
+ <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+> to make them consistent.</P
+><P
+>NOTE: On many systems you may need to use the
+ "interfaces" option in smb.conf to specify the IP address
+ and netmask of your interfaces. Run <B
+CLASS="COMMAND"
+>ifconfig</B
+>
+ as root if you don't know what the broadcast is for your
+ net. <B
+CLASS="COMMAND"
+>nmbd</B
+> tries to determine it at run
+ time, but fails on some unixes. See the section on "testing nmbd"
+ for a method of finding if you need to do this.</P
+><P
+>!!!WARNING!!! Many unixes only accept around 5
+ parameters on the command line in <TT
+CLASS="FILENAME"
+>inetd.conf</TT
+>.
+ This means you shouldn't use spaces between the options and
+ arguments, or you should use a script, and start the script
+ from <B
+CLASS="COMMAND"
+>inetd</B
+>.</P
+><P
+>Restart <B
+CLASS="COMMAND"
+>inetd</B
+>, perhaps just send
+ it a HUP. If you have installed an earlier version of <B
+CLASS="COMMAND"
+> nmbd</B
+> then you may need to kill nmbd as well.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN102"
+>Step 5b. Alternative: starting it as a daemon</A
+></H2
+><P
+>To start the server as a daemon you should create
+ a script something like this one, perhaps calling
+ it <TT
+CLASS="FILENAME"
+>startsmb</TT
+>.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> #!/bin/sh
+ /usr/local/samba/bin/smbd -D
+ /usr/local/samba/bin/nmbd -D
+ </PRE
+></P
+><P
+>then make it executable with <B
+CLASS="COMMAND"
+>chmod
+ +x startsmb</B
+></P
+><P
+>You can then run <B
+CLASS="COMMAND"
+>startsmb</B
+> by
+ hand or execute it from <TT
+CLASS="FILENAME"
+>/etc/rc.local</TT
+>
+ </P
+><P
+>To kill it send a kill signal to the processes
+ <B
+CLASS="COMMAND"
+>nmbd</B
+> and <B
+CLASS="COMMAND"
+>smbd</B
+>.</P
+><P
+>NOTE: If you use the SVR4 style init system then
+ you may like to look at the <TT
+CLASS="FILENAME"
+>examples/svr4-startup</TT
+>
+ script to make Samba fit into that system.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN118"
+>Step 6: Try listing the shares available on your
+ server</A
+></H1
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient -L
+ <TT
+CLASS="REPLACEABLE"
+><I
+>yourhostname</I
+></TT
+></B
+></TT
+></P
+><P
+>Your should get back a list of shares available on
+ your server. If you don't then something is incorrectly setup.
+ Note that this method can also be used to see what shares
+ are available on other LanManager clients (such as WfWg).</P
+><P
+>If you choose user level security then you may find
+ that Samba requests a password before it will list the shares.
+ See the <B
+CLASS="COMMAND"
+>smbclient</B
+> man page for details. (you
+ can force it to list the shares without a password by
+ adding the option -U% to the command line. This will not work
+ with non-Samba servers)</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN127"
+>Step 7: Try connecting with the unix client</A
+></H1
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient <TT
+CLASS="REPLACEABLE"
+><I
+> //yourhostname/aservice</I
+></TT
+></B
+></TT
+></P
+><P
+>Typically the <TT
+CLASS="REPLACEABLE"
+><I
+>yourhostname</I
+></TT
+>
+ would be the name of the host where you installed <B
+CLASS="COMMAND"
+> smbd</B
+>. The <TT
+CLASS="REPLACEABLE"
+><I
+>aservice</I
+></TT
+> is
+ any service you have defined in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+ file. Try your user name if you just have a [homes] section
+ in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.</P
+><P
+>For example if your unix host is bambi and your login
+ name is fred you would type:</P
+><P
+><TT
+CLASS="PROMPT"
+>$ </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbclient //bambi/fred
+ </B
+></TT
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN143"
+>Step 8: Try connecting from a DOS, WfWg, Win9x, WinNT,
+ Win2k, OS/2, etc... client</A
+></H1
+><P
+>Try mounting disks. eg:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>net use d: \\servername\service
+ </B
+></TT
+></P
+><P
+>Try printing. eg:</P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>net use lpt1:
+ \\servername\spoolservice</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>C:\WINDOWS\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>print filename
+ </B
+></TT
+></P
+><P
+>Celebrate, or send me a bug report!</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN157"
+>What If Things Don't Work?</A
+></H1
+><P
+>If nothing works and you start to think "who wrote
+ this pile of trash" then I suggest you do step 2 again (and
+ again) till you calm down.</P
+><P
+>Then you might read the file DIAGNOSIS.txt and the
+ FAQ. If you are still stuck then try the mailing list or
+ newsgroup (look in the README for details). Samba has been
+ successfully installed at thousands of sites worldwide, so maybe
+ someone else has hit your problem and has overcome it. You could
+ also use the WWW site to scan back issues of the samba-digest.</P
+><P
+>When you fix the problem PLEASE send me some updates to the
+ documentation (or source code) so that the next person will find it
+ easier. </P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN162"
+>Diagnosing Problems</A
+></H2
+><P
+>If you have installation problems then go to
+ <TT
+CLASS="FILENAME"
+>DIAGNOSIS.txt</TT
+> to try to find the
+ problem.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN166"
+>Scope IDs</A
+></H2
+><P
+>By default Samba uses a blank scope ID. This means
+ all your windows boxes must also have a blank scope ID.
+ If you really want to use a non-blank scope ID then you will
+ need to use the -i &lt;scope&gt; option to nmbd, smbd, and
+ smbclient. All your PCs will need to have the same setting for
+ this to work. I do not recommend scope IDs.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN169"
+>Choosing the Protocol Level</A
+></H2
+><P
+>The SMB protocol has many dialects. Currently
+ Samba supports 5, called CORE, COREPLUS, LANMAN1,
+ LANMAN2 and NT1.</P
+><P
+>You can choose what maximum protocol to support
+ in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. The default is
+ NT1 and that is the best for the vast majority of sites.</P
+><P
+>In older versions of Samba you may have found it
+ necessary to use COREPLUS. The limitations that led to
+ this have mostly been fixed. It is now less likely that you
+ will want to use less than LANMAN1. The only remaining advantage
+ of COREPLUS is that for some obscure reason WfWg preserves
+ the case of passwords in this protocol, whereas under LANMAN1,
+ LANMAN2 or NT1 it uppercases all passwords before sending them,
+ forcing you to use the "password level=" option in some cases.</P
+><P
+>The main advantage of LANMAN2 and NT1 is support for
+ long filenames with some clients (eg: smbclient, Windows NT
+ or Win95). </P
+><P
+>See the smb.conf(5) manual page for more details.</P
+><P
+>Note: To support print queue reporting you may find
+ that you have to use TCP/IP as the default protocol under
+ WfWg. For some reason if you leave Netbeui as the default
+ it may break the print queue reporting on some systems.
+ It is presumably a WfWg bug.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN178"
+>Printing from UNIX to a Client PC</A
+></H2
+><P
+>To use a printer that is available via a smb-based
+ server from a unix host you will need to compile the
+ smbclient program. You then need to install the script
+ "smbprint". Read the instruction in smbprint for more details.
+ </P
+><P
+>There is also a SYSV style script that does much
+ the same thing called smbprint.sysv. It contains instructions.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN182"
+>Locking</A
+></H2
+><P
+>One area which sometimes causes trouble is locking.</P
+><P
+>There are two types of locking which need to be
+ performed by a SMB server. The first is "record locking"
+ which allows a client to lock a range of bytes in a open file.
+ The second is the "deny modes" that are specified when a file
+ is open.</P
+><P
+>Record locking semantics under Unix is very
+ different from record locking under Windows. Versions
+ of Samba before 2.2 have tried to use the native
+ fcntl() unix system call to implement proper record
+ locking between different Samba clients. This can not
+ be fully correct due to several reasons. The simplest
+ is the fact that a Windows client is allowed to lock a
+ byte range up to 2^32 or 2^64, depending on the client
+ OS. The unix locking only supports byte ranges up to
+ 2^31. So it is not possible to correctly satisfy a
+ lock request above 2^31. There are many more
+ differences, too many to be listed here.</P
+><P
+>Samba 2.2 and above implements record locking
+ completely independent of the underlying unix
+ system. If a byte range lock that the client requests
+ happens to fall into the range 0-2^31, Samba hands
+ this request down to the Unix system. All other locks
+ can not be seen by unix anyway.</P
+><P
+>Strictly a SMB server should check for locks before
+ every read and write call on a file. Unfortunately with the
+ way fcntl() works this can be slow and may overstress the
+ rpc.lockd. It is also almost always unnecessary as clients
+ are supposed to independently make locking calls before reads
+ and writes anyway if locking is important to them. By default
+ Samba only makes locking calls when explicitly asked
+ to by a client, but if you set "strict locking = yes" then it will
+ make lock checking calls on every read and write. </P
+><P
+>You can also disable by range locking completely
+ using "locking = no". This is useful for those shares that
+ don't support locking or don't need it (such as cdroms). In
+ this case Samba fakes the return codes of locking calls to
+ tell clients that everything is OK.</P
+><P
+>The second class of locking is the "deny modes". These
+ are set by an application when it opens a file to determine
+ what types of access should be allowed simultaneously with
+ its open. A client may ask for DENY_NONE, DENY_READ, DENY_WRITE
+ or DENY_ALL. There are also special compatibility modes called
+ DENY_FCB and DENY_DOS.</P
+><P
+>You can disable share modes using "share modes = no".
+ This may be useful on a heavily loaded server as the share
+ modes code is very slow. See also the FAST_SHARE_MODES
+ option in the Makefile for a way to do full share modes
+ very fast using shared memory (if your OS supports it).</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN192"
+>Mapping Usernames</A
+></H2
+><P
+>If you have different usernames on the PCs and
+ the unix server then take a look at the "username map" option.
+ See the smb.conf man page for details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN195"
+>Other Character Sets</A
+></H2
+><P
+>If you have problems using filenames with accented
+ characters in them (like the German, French or Scandinavian
+ character sets) then I recommend you look at the "valid chars"
+ option in smb.conf and also take a look at the validchars
+ package in the examples directory.</P
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/findsmb.1.html b/docs/htmldocs/findsmb.1.html
new file mode 100644
index 00000000000..2f246d666d8
--- /dev/null
+++ b/docs/htmldocs/findsmb.1.html
@@ -0,0 +1,267 @@
+<HTML
+><HEAD
+><TITLE
+>findsmb</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="FINDSMB"
+>findsmb</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>findsmb&nbsp;--&nbsp;list info about machines that respond to SMB
+ name queries on a subnet</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>findsmb</B
+> [subnet broadcast address]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN12"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This perl script is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>findsmb</B
+> is a perl script that
+ prints out several pieces of information about machines
+ on a subnet that respond to SMB name query requests.
+ It uses <A
+HREF="nmblookup.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> nmblookup(1)</B
+></A
+> and <A
+HREF="smbclient.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+> to obtain this information.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN22"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>subnet broadcast address</DT
+><DD
+><P
+>Without this option, <B
+CLASS="COMMAND"
+>findsmb
+ </B
+> will probe the subnet of the machine where
+ <B
+CLASS="COMMAND"
+>findsmb</B
+> is run. This value is passed
+ to <B
+CLASS="COMMAND"
+>nmblookup</B
+> as part of the
+ <TT
+CLASS="CONSTANT"
+>-B</TT
+> option</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN33"
+></A
+><H2
+>EXAMPLES</H2
+><P
+>The output of <B
+CLASS="COMMAND"
+>findsmb</B
+> lists the following
+ information for all machines that respond to the initial
+ <B
+CLASS="COMMAND"
+>nmblookup</B
+> for any name: IP address, NetBIOS name,
+ Workgroup name, operating system, and SMB server version.</P
+><P
+>There will be a '+' in front of the workgroup name for
+ machines that are local master browsers for that workgroup. There
+ will be an '*' in front of the workgroup name for
+ machines that are the domain master browser for that workgroup.
+ Machines that are running Windows, Windows 95 or Windows 98 will
+ not show any information about the operating system or server
+ version.</P
+><P
+>The command must be run on a system without <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd</B
+></A
+> running.
+ If <B
+CLASS="COMMAND"
+>nmbd</B
+> is running on the system, you will
+ only get the IP address and the DNS name of the machine. To
+ get proper responses from Windows 95 and Windows 98 machines,
+ the command must be run as root. </P
+><P
+>For example running <B
+CLASS="COMMAND"
+>findsmb</B
+> on a machine
+ without <B
+CLASS="COMMAND"
+>nmbd</B
+> running would yield output similar
+ to the following</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><TT
+CLASS="COMPUTEROUTPUT"
+>IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION
+---------------------------------------------------------------------
+192.168.35.10 MINESET-TEST1 [DMVENGR]
+192.168.35.55 LINUXBOX *[MYGROUP] [Unix] [Samba 2.0.6]
+192.168.35.56 HERBNT2 [HERB-NT]
+192.168.35.63 GANDALF [MVENGR] [Unix] [Samba 2.0.5a for IRIX]
+192.168.35.65 SAUNA [WORKGROUP] [Unix] [Samba 1.9.18p10]
+192.168.35.71 FROGSTAR [ENGR] [Unix] [Samba 2.0.0 for IRIX]
+192.168.35.78 HERBDHCP1 +[HERB]
+192.168.35.88 SCNT2 +[MVENGR] [Windows NT 4.0] [NT LAN Manager 4.0]
+192.168.35.93 FROGSTAR-PC [MVENGR] [Windows 5.0] [Windows 2000 LAN Manager]
+192.168.35.97 HERBNT1 *[HERB-NT] [Windows NT 4.0] [NT LAN Manager 4.0]
+ </TT
+></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN48"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN51"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+>,
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)
+ </B
+></A
+>, and <A
+HREF="nmblookup.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>nmblookup(1)</B
+></A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN60"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/lmhosts.5.html b/docs/htmldocs/lmhosts.5.html
new file mode 100644
index 00000000000..13b162ce44f
--- /dev/null
+++ b/docs/htmldocs/lmhosts.5.html
@@ -0,0 +1,214 @@
+<HTML
+><HEAD
+><TITLE
+>lmhosts</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="LMHOSTS"
+>lmhosts</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>lmhosts&nbsp;--&nbsp;The Samba NetBIOS hosts file</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><TT
+CLASS="FILENAME"
+>lmhosts</TT
+> is the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> NetBIOS name to IP address mapping file.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN12"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This file is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><TT
+CLASS="FILENAME"
+>lmhosts</TT
+> is the <EM
+>Samba
+ </EM
+> NetBIOS name to IP address mapping file. It
+ is very similar to the <TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+> file
+ format, except that the hostname component must correspond
+ to the NetBIOS naming format.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN20"
+></A
+><H2
+>FILE FORMAT</H2
+><P
+>It is an ASCII file containing one line for NetBIOS name.
+ The two fields on each line are separated from each other by
+ white space. Any entry beginning with '#' is ignored. Each line
+ in the lmhosts file contains the following information :</P
+><P
+></P
+><UL
+><LI
+><P
+>IP Address - in dotted decimal format.</P
+></LI
+><LI
+><P
+>NetBIOS Name - This name format is a
+ maximum fifteen character host name, with an optional
+ trailing '#' character followed by the NetBIOS name type
+ as two hexadecimal digits.</P
+><P
+>If the trailing '#' is omitted then the given IP
+ address will be returned for all names that match the given
+ name, whatever the NetBIOS name type in the lookup.</P
+></LI
+></UL
+><P
+>An example follows :</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#
+# Sample Samba lmhosts file.
+#
+192.9.200.1 TESTPC
+192.9.200.20 NTSERVER#20
+192.9.200.21 SAMBASERVER
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Contains three IP to NetBIOS name mappings. The first
+ and third will be returned for any queries for the names "TESTPC"
+ and "SAMBASERVER" respectively, whatever the type component of
+ the NetBIOS name requested.</P
+><P
+>The second mapping will be returned only when the "0x20" name
+ type for a name "NTSERVER" is queried. Any other name type will not
+ be resolved.</P
+><P
+>The default location of the <TT
+CLASS="FILENAME"
+>lmhosts</TT
+> file
+ is in the same directory as the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>
+ smb.conf(5)&#62;</A
+> file.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN37"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)
+ </B
+></A
+>, <A
+HREF="smb.conf.5.html#NAMERESOLVEORDER"
+TARGET="_top"
+> smb.conf(5)</A
+>, and <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> smbpasswd(8)</B
+></A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN48"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/make_smbcodepage.1.html b/docs/htmldocs/make_smbcodepage.1.html
new file mode 100644
index 00000000000..8e792e31221
--- /dev/null
+++ b/docs/htmldocs/make_smbcodepage.1.html
@@ -0,0 +1,354 @@
+<HTML
+><HEAD
+><TITLE
+>make_smbcodepage</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="MAKE-SMBCODEPAGE"
+>make_smbcodepage</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>make_smbcodepage&nbsp;--&nbsp;construct a codepage file for Samba</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>make_smbcodepage</B
+> {c|d} {codepage} {inputfile} {outputfile}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN15"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>make_smbcodepage</B
+> compiles or de-compiles
+ codepage files for use with the internationalization features
+ of Samba 2.2</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN21"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>c|d</DT
+><DD
+><P
+>This tells <B
+CLASS="COMMAND"
+>make_smbcodepage</B
+>
+ if it is compiling (<TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+>) a text format code
+ page file to binary, or (<TT
+CLASS="PARAMETER"
+><I
+>d</I
+></TT
+>) de-compiling
+ a binary codepage file to text. </P
+></DD
+><DT
+>codepage</DT
+><DD
+><P
+>This is the codepage we are processing (a
+ number, e.g. 850). </P
+></DD
+><DT
+>inputfile</DT
+><DD
+><P
+>This is the input file to process. In
+ the <TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> case this will be a text
+ codepage definition file such as the ones found in the Samba
+ <TT
+CLASS="FILENAME"
+>source/codepages</TT
+> directory. In
+ the <TT
+CLASS="PARAMETER"
+><I
+>d</I
+></TT
+> case this will be the
+ binary format codepage definition file normally found in
+ the <TT
+CLASS="FILENAME"
+>lib/codepages</TT
+> directory in the
+ Samba install directory path.</P
+></DD
+><DT
+>outputfile</DT
+><DD
+><P
+>This is the output file to produce.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN47"
+></A
+><H2
+>Samba Codepage Files</H2
+><P
+>A text Samba codepage definition file is a description
+ that tells Samba how to map from upper to lower case for
+ characters greater than ascii 127 in the specified DOS code page.
+ Note that for certain DOS codepages (437 for example) mapping
+ from lower to upper case may be non-symmetrical. For example, in
+ code page 437 lower case a acute maps to a plain upper case A
+ when going from lower to upper case, but plain upper case A maps
+ to plain lower case a when lower casing a character. </P
+><P
+>A binary Samba codepage definition file is a binary
+ representation of the same information, including a value that
+ specifies what codepage this file is describing. </P
+><P
+>As Samba does not yet use UNICODE (current for Samba version 2.2)
+ you must specify the client code page that your DOS and Windows
+ clients are using if you wish to have case insensitivity done
+ correctly for your particular language. The default codepage Samba
+ uses is 850 (Western European). Text codepage definition sample files
+ are provided in the Samba distribution for codepages 437 (USA), 737 (Greek),
+ 850 (Western European) 852 (MS-DOS Latin 2), 861 (Icelandic), 866 (Cyrillic),
+ 932 (Kanji SJIS), 936 (Simplified Chinese), 949 (Hangul) and 950 (Traditional
+ Chinese). Users are encouraged to write text codepage definition files for
+ their own code pages and donate them to samba@samba.org. All codepage files
+ in the Samba <TT
+CLASS="FILENAME"
+>source/codepages</TT
+> directory are
+ compiled and installed when a <B
+CLASS="COMMAND"
+>'make install'</B
+>
+ command is issued there. </P
+><P
+>The client codepage used by the <B
+CLASS="COMMAND"
+>smbd</B
+> server
+ is configured using the <B
+CLASS="COMMAND"
+>client code page</B
+> parameter
+ in the <B
+CLASS="COMMAND"
+>smb.conf</B
+> file. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN58"
+></A
+><H2
+>Files</H2
+><P
+><B
+CLASS="COMMAND"
+>codepage_def.&#60;codepage&#62;</B
+></P
+><P
+>These are the input (text) codepage files provided in the
+ Samba <TT
+CLASS="FILENAME"
+>source/codepages</TT
+> directory.</P
+><P
+>A text codepage definition file consists of multiple lines
+ containing four fields. These fields are:</P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>lower</B
+>: which is the
+ (hex) lower case character mapped on this line.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>upper</B
+>: which is the (hex)
+ upper case character that the lower case character will map to.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>map upper to lower</B
+> which
+ is a boolean value (put either True or False here) which tells
+ Samba if it is to map the given upper case character to the
+ given lower case character when lower casing a filename.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>map lower to upper</B
+> which
+ is a boolean value (put either True or False here) which tells
+ Samba if it is to map the given lower case character to the
+ given upper case character when upper casing a filename.
+ </P
+></LI
+></UL
+><P
+><B
+CLASS="COMMAND"
+>codepage.&#60;codepage&#62;</B
+> - These are the
+ output (binary) codepage files produced and placed in the Samba
+ destination <TT
+CLASS="FILENAME"
+>lib/codepage</TT
+> directory. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN81"
+></A
+><H2
+>Installation</H2
+><P
+>The location of the server and its support files is a
+ matter for individual system administrators. The following are
+ thus suggestions only. </P
+><P
+>It is recommended that the <B
+CLASS="COMMAND"
+>make_smbcodepage
+ </B
+> program be installed under the <TT
+CLASS="FILENAME"
+>/usr/local/samba
+ </TT
+> hierarchy, in a directory readable by all, writeable
+ only by root. The program itself should be executable by all. The
+ program should NOT be setuid or setgid! </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN87"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN90"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN96"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/make_unicodemap.1.html b/docs/htmldocs/make_unicodemap.1.html
new file mode 100644
index 00000000000..b8b768ce40d
--- /dev/null
+++ b/docs/htmldocs/make_unicodemap.1.html
@@ -0,0 +1,276 @@
+<HTML
+><HEAD
+><TITLE
+>make_unicodemap</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="MAKE-UNICODEMAP"
+>make_unicodemap</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>make_unicodemap&nbsp;--&nbsp;construct a unicode map file for Samba</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>make_unicodemap</B
+> {codepage} {inputfile} {outputfile}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN14"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+> This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+>Samba</A
+>
+ suite.
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>make_unicodemap</B
+> compiles text unicode map
+ files into binary unicode map files for use with the
+ internationalization features of Samba 2.2.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN20"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>codepage</DT
+><DD
+><P
+>This is the codepage or UNIX character
+ set we are processing (a number, e.g. 850).
+ </P
+></DD
+><DT
+>inputfile</DT
+><DD
+><P
+>This is the input file to process. This is a
+ text unicode map file such as the ones found in the Samba
+ <TT
+CLASS="FILENAME"
+>source/codepages</TT
+> directory.
+ </P
+></DD
+><DT
+>outputfile</DT
+><DD
+><P
+>This is the binary output file to produce.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN36"
+></A
+><H2
+>Samba Unicode Map Files</H2
+><P
+> A text Samba unicode map file is a description that tells Samba
+ how to map characters from a specified DOS code page or UNIX character
+ set to 16 bit unicode.
+ </P
+><P
+>A binary Samba unicode map file is a binary representation
+ of the same information, including a value that specifies what
+ codepage or UNIX character set this file is describing.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>Files</H2
+><P
+><TT
+CLASS="FILENAME"
+>CP&#60;codepage&#62;.TXT</TT
+></P
+><P
+> These are the input (text) unicode map files provided
+ in the Samba <TT
+CLASS="FILENAME"
+>source/codepages</TT
+>
+ directory.
+ </P
+><P
+> A text unicode map file consists of multiple lines
+ containing two fields. These fields are :
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>character</I
+></TT
+> - which is
+ the (hex) character mapped on this line.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>unicode</I
+></TT
+> - which
+ is the (hex) 16 bit unicode character that the character
+ will map to.
+ </P
+></LI
+></UL
+><P
+> <TT
+CLASS="FILENAME"
+>unicode_map.&#60;codepage&#62;</TT
+> - These are
+ the output (binary) unicode map files produced and placed in
+ the Samba destination <TT
+CLASS="FILENAME"
+>lib/codepage</TT
+>
+ directory.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>Installation</H2
+><P
+> The location of the server and its support files is a matter
+ for individual system administrators. The following are thus
+ suggestions only.
+ </P
+><P
+> It is recommended that the <B
+CLASS="COMMAND"
+>make_unicodemap</B
+>
+ program be installed under the
+ <TT
+CLASS="FILENAME"
+>$prefix/samba</TT
+> hierarchy,
+ in a directory readable by all, writeable only by root. The
+ program itself should be executable by all. The program
+ should NOT be setuid or setgid!
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN63"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN66"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN72"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/msdfs_setup.html b/docs/htmldocs/msdfs_setup.html
new file mode 100644
index 00000000000..36b9911baec
--- /dev/null
+++ b/docs/htmldocs/msdfs_setup.html
@@ -0,0 +1,210 @@
+<HTML
+><HEAD
+><TITLE
+>Hosting a Microsoft Distributed File System tree on Samba</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="MSDFS"
+>Hosting a Microsoft Distributed File System tree on Samba</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Instructions</A
+></H1
+><P
+>The Distributed File System (or Dfs) provides a means of
+ separating the logical view of files and directories that users
+ see from the actual physical locations of these resources on the
+ network. It allows for higher availability, smoother storage expansion,
+ load balancing etc. For more information about Dfs, refer to <A
+HREF="http://www.microsoft.com/NTServer/nts/downloads/winfeatures/NTSDistrFile/AdminGuide.asp"
+TARGET="_top"
+> Microsoft documentation</A
+>. </P
+><P
+>This document explains how to host a Dfs tree on a Unix
+ machine (for Dfs-aware clients to browse) using Samba.</P
+><P
+>To enable SMB-based DFS for Samba, configure it with the
+ <TT
+CLASS="PARAMETER"
+><I
+>--with-msdfs</I
+></TT
+> option. Once built, a
+ Samba server can be made a Dfs server by setting the global
+ boolean <A
+HREF="smb.conf.5.html#HOSTMSDFS"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> host msdfs</I
+></TT
+></A
+> parameter in the <TT
+CLASS="FILENAME"
+>smb.conf
+ </TT
+> file. You designate a share as a Dfs root using the share
+ level boolean <A
+HREF="smb.conf.5.html#MSDFSROOT"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> msdfs root</I
+></TT
+></A
+> parameter. A Dfs root directory on
+ Samba hosts Dfs links in the form of symbolic links that point
+ to other servers. For example, a symbolic link
+ <TT
+CLASS="FILENAME"
+>junction-&gt;msdfs:storage1\share1</TT
+> in
+ the share directory acts as the Dfs junction. When Dfs-aware
+ clients attempt to access the junction link, they are redirected
+ to the storage location (in this case, \\storage1\share1).</P
+><P
+>Dfs trees on Samba work with all Dfs-aware clients ranging
+ from Windows 95 to 2000.</P
+><P
+>Here's an example of setting up a Dfs tree on a Samba
+ server.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+># The smb.conf file:
+[global]
+ netbios name = SAMBA
+ host msdfs = yes
+
+[dfs]
+ path = /export/dfsroot
+ msdfs root = yes
+ </PRE
+></P
+><P
+>In the /export/dfsroot directory we set up our dfs links to
+ other servers on the network.</P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>cd /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>chown root /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>chmod 755 /export/dfsroot</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>ln -s msdfs:storageA\\shareA linka</B
+></TT
+></P
+><P
+><TT
+CLASS="PROMPT"
+>root# </TT
+><TT
+CLASS="USERINPUT"
+><B
+>ln -s msdfs:serverB\\share,serverC\\share linkb</B
+></TT
+></P
+><P
+>You should set up the permissions and ownership of
+ the directory acting as the Dfs root such that only designated
+ users can create, delete or modify the msdfs links. Also note
+ that symlink names should be all lowercase. This limitation exists
+ to have Samba avoid trying all the case combinations to get at
+ the link name. Finally set up the symbolic links to point to the
+ network shares you want, and start Samba.</P
+><P
+>Users on Dfs-aware clients can now browse the Dfs tree
+ on the Samba server at \\samba\dfs. Accessing
+ links linka or linkb (which appear as directories to the client)
+ takes users directly to the appropriate shares on the network.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN38"
+>Notes</A
+></H2
+><P
+></P
+><UL
+><LI
+><P
+>Windows clients need to be rebooted
+ if a previously mounted non-dfs share is made a dfs
+ root or vice versa. A better way is to introduce a
+ new share and make it the dfs root.</P
+></LI
+><LI
+><P
+>Currently there's a restriction that msdfs
+ symlink names should all be lowercase.</P
+></LI
+><LI
+><P
+>For security purposes, the directory
+ acting as the root of the Dfs tree should have ownership
+ and permissions set so that only designated users can
+ modify the symbolic links in the directory.</P
+></LI
+></UL
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/nmbd.8.html b/docs/htmldocs/nmbd.8.html
new file mode 100644
index 00000000000..ad8c7c61ab7
--- /dev/null
+++ b/docs/htmldocs/nmbd.8.html
@@ -0,0 +1,676 @@
+<HTML
+><HEAD
+><TITLE
+>nmbd</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="NMBD"
+>nmbd</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>nmbd&nbsp;--&nbsp;NetBIOS name server to provide NetBIOS
+ over IP naming services to clients</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> [-D] [-a] [-o] [-P] [-h] [-V] [-d &#60;debug level&#62;] [-H &#60;lmhosts file&#62;] [-l &#60;log directory&#62;] [-n &#60;primary netbios name&#62;] [-p &#60;port number&#62;] [-s &#60;configuration file&#62;]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN23"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This program is part of the Samba suite.</P
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> is a server that understands
+ and can reply to NetBIOS over IP name service requests, like
+ those produced by SMB/CIFS clients such as Windows 95/98/ME,
+ Windows NT, Windows 2000, and LanManager clients. It also
+ participates in the browsing protocols which make up the
+ Windows "Network Neighborhood" view.</P
+><P
+>SMB/CIFS clients, when they start up, may wish to
+ locate an SMB/CIFS server. That is, they wish to know what
+ IP number a specified host is using.</P
+><P
+>Amongst other services, <B
+CLASS="COMMAND"
+>nmbd</B
+> will
+ listen for such requests, and if its own NetBIOS name is
+ specified it will respond with the IP number of the host it
+ is running on. Its "own NetBIOS name" is by
+ default the primary DNS name of the host it is running on,
+ but this can be overridden with the <EM
+>-n</EM
+>
+ option (see OPTIONS below). Thus <B
+CLASS="COMMAND"
+>nmbd</B
+> will
+ reply to broadcast queries for its own name(s). Additional
+ names for <B
+CLASS="COMMAND"
+>nmbd</B
+> to respond on can be set
+ via parameters in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> configuration file.</P
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> can also be used as a WINS
+ (Windows Internet Name Server) server. What this basically means
+ is that it will act as a WINS database server, creating a
+ database from name registration requests that it receives and
+ replying to queries from clients for these names.</P
+><P
+>In addition, <B
+CLASS="COMMAND"
+>nmbd</B
+> can act as a WINS
+ proxy, relaying broadcast queries from clients that do
+ not understand how to talk the WINS protocol to a WIN
+ server.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-D</DT
+><DD
+><P
+>If specified, this parameter causes
+ <B
+CLASS="COMMAND"
+>nmbd</B
+> to operate as a daemon. That is,
+ it detaches itself and runs in the background, fielding
+ requests on the appropriate port. By default, <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ will operate as a daemon if launched from a command shell.
+ nmbd can also be operated from the <B
+CLASS="COMMAND"
+>inetd</B
+>
+ meta-daemon, although this is not recommended.
+ </P
+></DD
+><DT
+>-a</DT
+><DD
+><P
+>If this parameter is specified, each new
+ connection will append log messages to the log file.
+ This is the default.</P
+></DD
+><DT
+>-o</DT
+><DD
+><P
+>If this parameter is specified, the
+ log files will be overwritten when opened. By default,
+ <B
+CLASS="COMMAND"
+>smbd</B
+> will append entries to the log
+ files.</P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Prints the help information (usage)
+ for <B
+CLASS="COMMAND"
+>nmbd</B
+>.</P
+></DD
+><DT
+>-H &#60;filename&#62;</DT
+><DD
+><P
+>NetBIOS lmhosts file. The lmhosts
+ file is a list of NetBIOS names to IP addresses that
+ is loaded by the nmbd server and used via the name
+ resolution mechanism <A
+HREF="smb.conf.5.html#nameresolveorder"
+TARGET="_top"
+> name resolve order</A
+> described in <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+>
+ to resolve any NetBIOS name queries needed by the server. Note
+ that the contents of this file are <EM
+>NOT</EM
+>
+ used by <B
+CLASS="COMMAND"
+>nmbd</B
+> to answer any name queries.
+ Adding a line to this file affects name NetBIOS resolution
+ from this host <EM
+>ONLY</EM
+>.</P
+><P
+>The default path to this file is compiled into
+ Samba as part of the build process. Common defaults
+ are <TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/lmhosts</TT
+>,
+ <TT
+CLASS="FILENAME"
+>/usr/samba/lib/lmhosts</TT
+> or
+ <TT
+CLASS="FILENAME"
+>/etc/lmhosts</TT
+>. See the <A
+HREF="lmhosts.5.html"
+TARGET="_top"
+> <TT
+CLASS="FILENAME"
+>lmhosts(5)</TT
+></A
+> man page for details on the
+ contents of this file.</P
+></DD
+><DT
+>-V</DT
+><DD
+><P
+>Prints the version number for
+ <B
+CLASS="COMMAND"
+>nmbd</B
+>.</P
+></DD
+><DT
+>-d &#60;debug level&#62;</DT
+><DD
+><P
+>debuglevel is an integer
+ from 0 to 10. The default value if this parameter is
+ not specified is zero.</P
+><P
+>The higher this value, the more detail will
+ be logged to the log files about the activities of the
+ server. At level 0, only critical errors and serious
+ warnings will be logged. Level 1 is a reasonable level for
+ day to day running - it generates a small amount of
+ information about operations carried out.</P
+><P
+>Levels above 1 will generate considerable amounts
+ of log data, and should only be used when investigating
+ a problem. Levels above 3 are designed for use only by developers
+ and generate HUGE amounts of log data, most of which is extremely
+ cryptic.</P
+><P
+>Note that specifying this parameter here will override
+ the <A
+HREF="smb.conf.5.html#loglevel"
+TARGET="_top"
+>log level</A
+>
+ parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf</TT
+></A
+> file.</P
+></DD
+><DT
+>-l &#60;log directory&#62;</DT
+><DD
+><P
+>The -l parameter specifies a directory
+ into which the "log.nmbd" log file will be created
+ for operational data from the running
+ <B
+CLASS="COMMAND"
+>nmbd</B
+> server.</P
+><P
+>The default log directory is compiled into Samba
+ as part of the build process. Common defaults are <TT
+CLASS="FILENAME"
+> /usr/local/samba/var/log.nmb</TT
+>, <TT
+CLASS="FILENAME"
+> /usr/samba/var/log.nmb</TT
+> or
+ <TT
+CLASS="FILENAME"
+>/var/log/log.nmb</TT
+>.</P
+></DD
+><DT
+>-n &#60;primary NetBIOS name&#62;</DT
+><DD
+><P
+>This option allows you to override
+ the NetBIOS name that Samba uses for itself. This is identical
+ to setting the <A
+HREF="smb.conf.5.html#netbiosname"
+TARGET="_top"
+> NetBIOS name</A
+> parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+></A
+> file. However, a command
+ line setting will take precedence over settings in
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.</P
+></DD
+><DT
+>-p &#60;UDP port number&#62;</DT
+><DD
+><P
+>UDP port number is a positive integer value.
+ This option changes the default UDP port number (normally 137)
+ that <B
+CLASS="COMMAND"
+>nmbd</B
+> responds to name queries on. Don't
+ use this option unless you are an expert, in which case you
+ won't need help!</P
+></DD
+><DT
+>-s &#60;configuration file&#62;</DT
+><DD
+><P
+>The default configuration file name
+ is set at build time, typically as <TT
+CLASS="FILENAME"
+> /usr/local/samba/lib/smb.conf</TT
+>, but
+ this may be changed when Samba is autoconfigured.</P
+><P
+>The file specified contains the configuration details
+ required by the server. See <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>
+ <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+> for more information.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN125"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+></DT
+><DD
+><P
+>If the server is to be run by the
+ <B
+CLASS="COMMAND"
+>inetd</B
+> meta-daemon, this file
+ must contain suitable startup information for the
+ meta-daemon. See the section INSTALLATION below.
+ </P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/rc</TT
+></DT
+><DD
+><P
+>or whatever initialization script your
+ system uses).</P
+><P
+>If running the server as a daemon at startup,
+ this file will need to contain an appropriate startup
+ sequence for the server. See the section INSTALLATION
+ below.</P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/services</TT
+></DT
+><DD
+><P
+>If running the server via the
+ meta-daemon <B
+CLASS="COMMAND"
+>inetd</B
+>, this file
+ must contain a mapping of service name (e.g., netbios-ssn)
+ to service port (e.g., 139) and protocol type (e.g., tcp).
+ See the section INSTALLATION below.</P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/smb.conf</TT
+></DT
+><DD
+><P
+>This is the default location of the
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf</TT
+></A
+>
+ server configuration file. Other common places that systems
+ install this file are <TT
+CLASS="FILENAME"
+>/usr/samba/lib/smb.conf</TT
+>
+ and <TT
+CLASS="FILENAME"
+>/etc/smb.conf</TT
+>.</P
+><P
+>When run as a WINS server (see the
+ <A
+HREF="smb.conf.5.html#winssupport"
+TARGET="_top"
+>wins support</A
+>
+ parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> man page), <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ will store the WINS database in the file <TT
+CLASS="FILENAME"
+>wins.dat</TT
+>
+ in the <TT
+CLASS="FILENAME"
+>var/locks</TT
+> directory configured under
+ wherever Samba was configured to install itself.</P
+><P
+>If <B
+CLASS="COMMAND"
+>nmbd</B
+> is acting as a <EM
+> browse master</EM
+> (see the <A
+HREF="smb.conf.5.html#localmaster"
+TARGET="_top"
+>local master</A
+>
+ parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> man page), <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ will store the browsing database in the file <TT
+CLASS="FILENAME"
+>browse.dat
+ </TT
+> in the <TT
+CLASS="FILENAME"
+>var/locks</TT
+> directory
+ configured under wherever Samba was configured to install itself.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN171"
+></A
+><H2
+>SIGNALS</H2
+><P
+>To shut down an <B
+CLASS="COMMAND"
+>nmbd</B
+> process it is recommended
+ that SIGKILL (-9) <EM
+>NOT</EM
+> be used, except as a last
+ resort, as this may leave the name database in an inconsistent state.
+ The correct way to terminate <B
+CLASS="COMMAND"
+>nmbd</B
+> is to send it
+ a SIGTERM (-15) signal and wait for it to die on its own.</P
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> will accept SIGHUP, which will cause
+ it to dump out its namelists into the file <TT
+CLASS="FILENAME"
+>namelist.debug
+ </TT
+> in the <TT
+CLASS="FILENAME"
+>/usr/local/samba/var/locks</TT
+>
+ directory (or the <TT
+CLASS="FILENAME"
+>var/locks</TT
+> directory configured
+ under wherever Samba was configured to install itself). This will also
+ cause <B
+CLASS="COMMAND"
+>nmbd</B
+> to dump out its server database in
+ the <TT
+CLASS="FILENAME"
+>log.nmb</TT
+> file.</P
+><P
+>The debug log level of nmbd may be raised or lowered using
+ <A
+HREF="smbcontrol.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbcontrol(1)</B
+>
+ </A
+> (SIGUSR[1|2] signals are no longer used in Samba 2.2). This is
+ to allow transient problems to be diagnosed, whilst still running
+ at a normally low log level.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN187"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN190"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><B
+CLASS="COMMAND"
+>inetd(8)</B
+>, <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ </A
+>, <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)
+ </B
+></A
+>, <A
+HREF="testparm.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> testparm(1)</B
+></A
+>, <A
+HREF="testprns.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>testprns(1)</B
+></A
+>, and the Internet RFC's
+ <TT
+CLASS="FILENAME"
+>rfc1001.txt</TT
+>, <TT
+CLASS="FILENAME"
+>rfc1002.txt</TT
+>.
+ In addition the CIFS (formerly SMB) specification is available
+ as a link from the Web page <A
+HREF="http://samba.org/cifs/"
+TARGET="_top"
+>
+ http://samba.org/cifs/</A
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN207"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/nmblookup.1.html b/docs/htmldocs/nmblookup.1.html
new file mode 100644
index 00000000000..c87d7d35db9
--- /dev/null
+++ b/docs/htmldocs/nmblookup.1.html
@@ -0,0 +1,394 @@
+<HTML
+><HEAD
+><TITLE
+>nmblookup</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="NMBLOOKUP"
+>nmblookup</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>nmblookup&nbsp;--&nbsp;NetBIOS over TCP/IP client used to lookup NetBIOS
+ names</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>nmblookup</B
+> [-M] [-R] [-S] [-r] [-A] [-h] [-B &#60;broadcast address&#62;] [-U &#60;unicast address&#62;] [-d &#60;debug level&#62;] [-s &#60;smb config file&#62;] [-i &#60;NetBIOS scope&#62;] [-T] {name}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN24"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>nmblookup</B
+> is used to query NetBIOS names
+ and map them to IP addresses in a network using NetBIOS over TCP/IP
+ queries. The options allow the name queries to be directed at a
+ particular IP broadcast area or to a particular machine. All queries
+ are done over UDP.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN30"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-M</DT
+><DD
+><P
+>Searches for a master browser by looking
+ up the NetBIOS name <TT
+CLASS="REPLACEABLE"
+><I
+>name</I
+></TT
+> with a
+ type of <TT
+CLASS="CONSTANT"
+>0x1d</TT
+>. If <TT
+CLASS="REPLACEABLE"
+><I
+> name</I
+></TT
+> is "-" then it does a lookup on the special name
+ <TT
+CLASS="CONSTANT"
+>__MSBROWSE__</TT
+>.</P
+></DD
+><DT
+>-R</DT
+><DD
+><P
+>Set the recursion desired bit in the packet
+ to do a recursive lookup. This is used when sending a name
+ query to a machine running a WINS server and the user wishes
+ to query the names in the WINS server. If this bit is unset
+ the normal (broadcast responding) NetBIOS processing code
+ on a machine is used instead. See rfc1001, rfc1002 for details.
+ </P
+></DD
+><DT
+>-S</DT
+><DD
+><P
+>Once the name query has returned an IP
+ address then do a node status query as well. A node status
+ query returns the NetBIOS names registered by a host.
+ </P
+></DD
+><DT
+>-r</DT
+><DD
+><P
+>Try and bind to UDP port 137 to send and receive UDP
+ datagrams. The reason for this option is a bug in Windows 95
+ where it ignores the source port of the requesting packet
+ and only replies to UDP port 137. Unfortunately, on most UNIX
+ systems root privilege is needed to bind to this port, and
+ in addition, if the <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ daemon is running on this machine it also binds to this port.
+ </P
+></DD
+><DT
+>-A</DT
+><DD
+><P
+>Interpret <TT
+CLASS="REPLACEABLE"
+><I
+>name</I
+></TT
+> as
+ an IP Address and do a node status query on this address.</P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Print a help (usage) message.</P
+></DD
+><DT
+>-B &#60;broadcast address&#62;</DT
+><DD
+><P
+>Send the query to the given broadcast address. Without
+ this option the default behavior of nmblookup is to send the
+ query to the broadcast address of the network interfaces as
+ either auto-detected or defined in the <A
+HREF="smb.conf.5.html#INTERFACES"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+>
+ </A
+> parameter of the <TT
+CLASS="FILENAME"
+>smb.conf (5)</TT
+> file.
+ </P
+></DD
+><DT
+>-U &#60;unicast address&#62;</DT
+><DD
+><P
+>Do a unicast query to the specified address or
+ host <TT
+CLASS="REPLACEABLE"
+><I
+>unicast address</I
+></TT
+>. This option
+ (along with the <TT
+CLASS="PARAMETER"
+><I
+>-R</I
+></TT
+> option) is needed to
+ query a WINS server.</P
+></DD
+><DT
+>-d &#60;debuglevel&#62;</DT
+><DD
+><P
+>debuglevel is an integer from 0 to 10.</P
+><P
+>The default value if this parameter is not specified
+ is zero.</P
+><P
+>The higher this value, the more detail will be logged
+ about the activities of <B
+CLASS="COMMAND"
+>nmblookup</B
+>. At level
+ 0, only critical errors and serious warnings will be logged.</P
+><P
+>Levels above 1 will generate considerable amounts of
+ log data, and should only be used when investigating a problem.
+ Levels above 3 are designed for use only by developers and
+ generate HUGE amounts of data, most of which is extremely cryptic.</P
+><P
+>Note that specifying this parameter here will override
+ the <A
+HREF="smb.conf.5.html#LOGLEVEL"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+> log level</I
+></TT
+></A
+> parameter in the <TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+> file.</P
+></DD
+><DT
+>-s &#60;smb.conf&#62;</DT
+><DD
+><P
+>This parameter specifies the pathname to
+ the Samba configuration file, <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> smb.conf(5)</A
+>. This file controls all aspects of
+ the Samba setup on the machine.</P
+></DD
+><DT
+>-i &#60;scope&#62;</DT
+><DD
+><P
+>This specifies a NetBIOS scope that
+ <B
+CLASS="COMMAND"
+>nmblookup</B
+> will use to communicate with when
+ generating NetBIOS names. For details on the use of NetBIOS
+ scopes, see rfc1001.txt and rfc1002.txt. NetBIOS scopes are
+ <EM
+>very</EM
+> rarely used, only set this parameter
+ if you are the system administrator in charge of all the
+ NetBIOS systems you communicate with.</P
+></DD
+><DT
+>-T</DT
+><DD
+><P
+>This causes any IP addresses found in the
+ lookup to be looked up via a reverse DNS lookup into a
+ DNS name, and printed out before each</P
+><P
+><EM
+>IP address .... NetBIOS name</EM
+></P
+><P
+> pair that is the normal output.</P
+></DD
+><DT
+>name</DT
+><DD
+><P
+>This is the NetBIOS name being queried. Depending
+ upon the previous options this may be a NetBIOS name or IP address.
+ If a NetBIOS name then the different name types may be specified
+ by appending '#&#60;type&#62;' to the name. This name may also be
+ '*', which will return all registered names within a broadcast
+ area.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN110"
+></A
+><H2
+>EXAMPLES</H2
+><P
+><B
+CLASS="COMMAND"
+>nmblookup</B
+> can be used to query
+ a WINS server (in the same way <B
+CLASS="COMMAND"
+>nslookup</B
+> is
+ used to query DNS servers). To query a WINS server,
+ <B
+CLASS="COMMAND"
+>nmblookup</B
+> must be called like this:</P
+><P
+><B
+CLASS="COMMAND"
+>nmblookup -U server -R 'name'</B
+></P
+><P
+>For example, running :</P
+><P
+><B
+CLASS="COMMAND"
+>nmblookup -U samba.org -R 'IRIX#1B'</B
+></P
+><P
+>would query the WINS server samba.org for the domain
+ master browser (1B name type) for the IRIX workgroup.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN122"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN125"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+>,
+ <A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>, and <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN132"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/printer_driver2.html b/docs/htmldocs/printer_driver2.html
new file mode 100644
index 00000000000..e6cc23b02cf
--- /dev/null
+++ b/docs/htmldocs/printer_driver2.html
@@ -0,0 +1,985 @@
+<HTML
+><HEAD
+><TITLE
+>Printing Support in Samba 2.2.x</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="PRINTING"
+>Printing Support in Samba 2.2.x</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Introduction</A
+></H1
+><P
+>Beginning with the 2.2.0 release, Samba supports
+the native Windows NT printing mechanisms implemented via
+MS-RPC (i.e. the SPOOLSS named pipe). Previous versions of
+Samba only supported LanMan printing calls.</P
+><P
+>The additional functionality provided by the new
+SPOOLSS support includes:</P
+><P
+></P
+><UL
+><LI
+><P
+>Support for downloading printer driver
+ files to Windows 95/98/NT/2000 clients upon demand.
+ </P
+></LI
+><LI
+><P
+>Uploading of printer drivers via the
+ Windows NT Add Printer Wizard (APW) or the
+ Imprints tool set (refer to <A
+HREF="http://imprints.sourceforge.net"
+TARGET="_top"
+>http://imprints.sourceforge.net</A
+>).
+ </P
+></LI
+><LI
+><P
+>Support for the native MS-RPC printing
+ calls such as StartDocPrinter, EnumJobs(), etc... (See
+ the MSDN documentation at <A
+HREF="http://msdn.microsoft.com/"
+TARGET="_top"
+>http://msdn.microsoft.com/</A
+>
+ for more information on the Win32 printing API)
+ </P
+></LI
+><LI
+><P
+>Support for NT Access Control Lists (ACL)
+ on printer objects</P
+></LI
+><LI
+><P
+>Improved support for printer queue manipulation
+ through the use of an internal databases for spooled job
+ information</P
+></LI
+></UL
+><P
+>There has been some initial confusion about what all this means
+and whether or not it is a requirement for printer drivers to be
+installed on a Samba host in order to support printing from Windows
+clients. A bug existed in Samba 2.2.0 which made Windows NT/2000 clients
+require that the Samba server possess a valid driver for the printer.
+This is fixed in Samba 2.2.1 and once again, Windows NT/2000 clients
+can use the local APW for installing drivers to be used with a Samba
+served printer. This is the same behavior exhibited by Windows 9x clients.
+As a side note, Samba does not use these drivers in any way to process
+spooled files. They are utilized entirely by the clients.</P
+><P
+>The following MS KB article, may be of some help if you are dealing with
+Windows 2000 clients: <I
+CLASS="EMPHASIS"
+>How to Add Printers with No User
+Interaction in Windows 2000</I
+></P
+><P
+><A
+HREF="http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP"
+TARGET="_top"
+>http://support.microsoft.com/support/kb/articles/Q189/1/05.ASP</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN25"
+>Configuration</A
+></H1
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>[print$] vs. [printer$]</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>Previous versions of Samba recommended using a share named [printer$].
+This name was taken from the printer$ service created by Windows 9x
+clients when a printer was shared. Windows 9x printer servers always have
+a printer$ service which provides read-only access via no
+password in order to support printer driver downloads.</P
+><P
+>However, the initial implementation allowed for a
+parameter named <TT
+CLASS="PARAMETER"
+><I
+>printer driver location</I
+></TT
+>
+to be used on a per share basis to specify the location of
+the driver files associated with that printer. Another
+parameter named <TT
+CLASS="PARAMETER"
+><I
+>printer driver</I
+></TT
+> provided
+a means of defining the printer driver name to be sent to
+the client.</P
+><P
+>These parameters, including <TT
+CLASS="PARAMETER"
+><I
+>printer driver
+file</I
+></TT
+> parameter, are being depreciated and should not
+be used in new installations. For more information on this change,
+you should refer to the <A
+HREF="#MIGRATION"
+>Migration section</A
+>
+of this document.</P
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN36"
+>Creating [print$]</A
+></H2
+><P
+>In order to support the uploading of printer driver
+files, you must first configure a file share named [print$].
+The name of this share is hard coded in Samba's internals so
+the name is very important (print$ is the service used by
+Windows NT print servers to provide support for printer driver
+download).</P
+><P
+>You should modify the server's smb.conf file to add the global
+parameters and to create the
+following file share (of course, some of the parameter values,
+such as 'path' are arbitrary and should be replaced with
+appropriate values for your site):</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ ; members of the ntadmin group should be able
+ ; to add drivers and set printer properties
+ ; root is implicitly a 'printer admin'
+ printer admin = @ntadmin
+
+[print$]
+ path = /usr/local/samba/printers
+ guest ok = yes
+ browseable = yes
+ read only = yes
+ ; since this share is configured as read only, then we need
+ ; a 'write list'. Check the file system permissions to make
+ ; sure this account can copy files to the share. If this
+ ; is setup to a non-root account, then it should also exist
+ ; as a 'printer admin'
+ write list = @ntadmin,root</PRE
+></P
+><P
+>The <A
+HREF="smb.conf.5.html#WRITELIST"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>write list</I
+></TT
+></A
+> is used to allow administrative
+level user accounts to have write access in order to update files
+on the share. See the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)
+man page</A
+> for more information on configuring file shares.</P
+><P
+>The requirement for <A
+HREF="smb.conf.5.html#GUESTOK"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>guest
+ok = yes</B
+></A
+> depends upon how your
+site is configured. If users will be guaranteed to have
+an account on the Samba host, then this is a non-issue.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Author's Note: </B
+>The non-issue is that if all your Windows NT users are guaranteed to be
+authenticated by the Samba server (such as a domain member server and the NT
+user has already been validated by the Domain Controller in
+order to logon to the Windows NT console), then guest access
+is not necessary. Of course, in a workgroup environment where
+you just want to be able to print without worrying about
+silly accounts and security, then configure the share for
+guest access. You'll probably want to add <A
+HREF="smb.conf.5.html#MAPTOGUEST"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>map to guest = Bad User</B
+></A
+> in the [global] section as well. Make sure
+you understand what this parameter does before using it
+though. --jerry</P
+></BLOCKQUOTE
+></DIV
+><P
+>In order for a Windows NT print server to support
+the downloading of driver files by multiple client architectures,
+it must create subdirectories within the [print$] service
+which correspond to each of the supported client architectures.
+Samba follows this model as well.</P
+><P
+>Next create the directory tree below the [print$] share
+for each architecture you wish to support.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>[print$]-----
+ |-W32X86 ; "Windows NT x86"
+ |-WIN40 ; "Windows 95/98"
+ |-W32ALPHA ; "Windows NT Alpha_AXP"
+ |-W32MIPS ; "Windows NT R4000"
+ |-W32PPC ; "Windows NT PowerPC"</PRE
+></P
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>ATTENTION! REQUIRED PERMISSIONS</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>In order to currently add a new driver to you Samba host,
+one of two conditions must hold true:</P
+><P
+></P
+><UL
+><LI
+><P
+>The account used to connect to the Samba host
+ must have a uid of 0 (i.e. a root account)</P
+></LI
+><LI
+><P
+>The account used to connect to the Samba host
+ must be a member of the <A
+HREF="smb.conf.5.html#PRINTERADMIN"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>printer
+ admin</I
+></TT
+></A
+> list.</P
+></LI
+></UL
+><P
+>Of course, the connected account must still possess access
+to add files to the subdirectories beneath [print$]. Remember
+that all file shares are set to 'read only' by default.</P
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>Once you have created the required [print$] service and
+associated subdirectories, simply log onto the Samba server using
+a root (or <TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+>) account
+from a Windows NT 4.0 client. Navigate to the "Printers" folder
+on the Samba server. You should see an initial listing of printers
+that matches the printer shares defined on your Samba host.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN71"
+>Setting Drivers for Existing Printers</A
+></H2
+><P
+>The initial listing of printers in the Samba host's
+Printers folder will have no real printer driver assigned
+to them. By default, in Samba 2.2.0 this driver name was set to
+<I
+CLASS="EMPHASIS"
+>NO PRINTER DRIVER AVAILABLE FOR THIS PRINTER</I
+>.
+Later versions changed this to a NULL string to allow the use
+tof the local Add Printer Wizard on NT/2000 clients.
+Attempting to view the printer properties for a printer
+which has this default driver assigned will result in
+the error message:</P
+><P
+><I
+CLASS="EMPHASIS"
+>Device settings cannot be displayed. The driver
+for the specified printer is not installed, only spooler
+properties will be displayed. Do you want to install the
+driver now?</I
+></P
+><P
+>Click "No" in the error dialog and you will be presented with
+the printer properties window. The way assign a driver to a
+printer is to either</P
+><P
+></P
+><UL
+><LI
+><P
+>Use the "New Driver..." button to install
+ a new printer driver, or</P
+></LI
+><LI
+><P
+>Select a driver from the popup list of
+ installed drivers. Initially this list will be empty.</P
+></LI
+></UL
+><P
+>If you wish to install printer drivers for client
+operating systems other than "Windows NT x86", you will need
+to use the "Sharing" tab of the printer properties dialog.</P
+><P
+>Assuming you have connected with a root account, you
+will also be able modify other printer properties such as
+ACLs and device settings using this dialog box.</P
+><P
+>A few closing comments for this section, it is possible
+on a Windows NT print server to have printers
+listed in the Printers folder which are not shared. Samba does
+not make this distinction. By definition, the only printers of
+which Samba is aware are those which are specified as shares in
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.</P
+><P
+>Another interesting side note is that Windows NT clients do
+not use the SMB printer share, but rather can print directly
+to any printer on another Windows NT host using MS-RPC. This
+of course assumes that the printing client has the necessary
+privileges on the remote host serving the printer. The default
+permissions assigned by Windows NT to a printer gives the "Print"
+permissions to the "Everyone" well-known group.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN88"
+>Support a large number of printers</A
+></H2
+><P
+>One issue that has arisen during the development
+phase of Samba 2.2 is the need to support driver downloads for
+100's of printers. Using the Windows NT APW is somewhat
+awkward to say the list. If more than one printer are using the
+same driver, the <A
+HREF="rpcclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>rpcclient's
+setdriver command</B
+></A
+> can be used to set the driver
+associated with an installed driver. The following is example
+of how this could be accomplished:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret -c "enumdrivers"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+
+[Windows NT x86]
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4000 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 2100 Series PS]
+
+Printer Driver Info 1:
+ Driver Name: [HP LaserJet 4Si/4SiMX PS]
+
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret -c "enumprinters"
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+ flags:[0x800000]
+ name:[\\POGO\hp-print]
+ description:[POGO\\POGO\hp-print,NO DRIVER AVAILABLE FOR THIS PRINTER,]
+ comment:[]
+
+<TT
+CLASS="PROMPT"
+>$ </TT
+>rpcclient pogo -U root%secret \
+<TT
+CLASS="PROMPT"
+>&gt; </TT
+> -c "setdriver hp-print \"HP LaserJet 4000 Series PS\""
+Domain=[NARNIA] OS=[Unix] Server=[Samba 2.2.0-alpha3]
+Successfully set hp-print to driver HP LaserJet 4000 Series PS.</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN99"
+>Adding New Printers via the Windows NT APW</A
+></H2
+><P
+>By default, Samba offers all printer shares defined in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+in the "Printers..." folder. Also existing in this folder is the Windows NT
+Add Printer Wizard icon. The APW will be show only if</P
+><P
+></P
+><UL
+><LI
+><P
+>The connected user is able to successfully
+ execute an OpenPrinterEx(\\server) with administrative
+ privileges (i.e. root or <TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+>).
+ </P
+></LI
+><LI
+><P
+><A
+HREF="smb.conf.5.html#SHOWADDPRINTERWIZARD"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>show
+ add printer wizard = yes</I
+></TT
+></A
+> (the default).
+ </P
+></LI
+></UL
+><P
+>In order to be able to use the APW to successfully add a printer to a Samba
+server, the <A
+HREF="smb.conf.5.html#ADDPRINTERCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>add
+printer command</I
+></TT
+></A
+> must have a defined value. The program
+hook must successfully add the printer to the system (i.e.
+<TT
+CLASS="FILENAME"
+>/etc/printcap</TT
+> or appropriate files) and
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> if necessary.</P
+><P
+>When using the APW from a client, if the named printer share does
+not exist, <B
+CLASS="COMMAND"
+>smbd</B
+> will execute the <TT
+CLASS="PARAMETER"
+><I
+>add printer
+command</I
+></TT
+> and reparse to the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+to attempt to locate the new printer share. If the share is still not defined,
+an error of "Access Denied" is returned to the client. Note that the
+<TT
+CLASS="PARAMETER"
+><I
+>add printer program</I
+></TT
+> is executed under the context
+of the connected user, not necessarily a root account.</P
+><P
+>There is a complementing <A
+HREF="smb.conf.5.html#DELETEPRINTERCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>delete
+printer command</I
+></TT
+></A
+> for removing entries from the "Printers..."
+folder.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN124"
+>Samba and Printer Ports</A
+></H2
+><P
+>Windows NT/2000 print servers associate a port with each printer. These normally
+take the form of LPT1:, COM1:, FILE:, etc... Samba must also support the
+concept of ports associated with a printer. By default, only one printer port,
+named "Samba Printer Port", exists on a system. Samba does not really a port in
+order to print, rather it is a requirement of Windows clients. </P
+><P
+>Note that Samba does not support the concept of "Printer Pooling" internally
+either. This is when a logical printer is assigned to multiple ports as
+a form of load balancing or fail over.</P
+><P
+>If you require that multiple ports be defined for some reason,
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> possesses a <A
+HREF="smb.conf.5.html#ENUMPORTSCOMMAND"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>enumports
+command</I
+></TT
+></A
+> which can be used to define an external program
+that generates a listing of ports on a system.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN132"
+>The Imprints Toolset</A
+></H1
+><P
+>The Imprints tool set provides a UNIX equivalent of the
+ Windows NT Add Printer Wizard. For complete information, please
+ refer to the Imprints web site at <A
+HREF="http://imprints.sourceforge.net/"
+TARGET="_top"
+> http://imprints.sourceforge.net/</A
+> as well as the documentation
+ included with the imprints source distribution. This section will
+ only provide a brief introduction to the features of Imprints.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN136"
+>What is Imprints?</A
+></H2
+><P
+>Imprints is a collection of tools for supporting the goals
+ of</P
+><P
+></P
+><UL
+><LI
+><P
+>Providing a central repository information
+ regarding Windows NT and 95/98 printer driver packages</P
+></LI
+><LI
+><P
+>Providing the tools necessary for creating
+ the Imprints printer driver packages.</P
+></LI
+><LI
+><P
+>Providing an installation client which
+ will obtain and install printer drivers on remote Samba
+ and Windows NT 4 print servers.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN146"
+>Creating Printer Driver Packages</A
+></H2
+><P
+>The process of creating printer driver packages is beyond
+ the scope of this document (refer to Imprints.txt also included
+ with the Samba distribution for more information). In short,
+ an Imprints driver package is a gzipped tarball containing the
+ driver files, related INF files, and a control file needed by the
+ installation client.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN149"
+>The Imprints server</A
+></H2
+><P
+>The Imprints server is really a database server that
+ may be queried via standard HTTP mechanisms. Each printer
+ entry in the database has an associated URL for the actual
+ downloading of the package. Each package is digitally signed
+ via GnuPG which can be used to verify that package downloaded
+ is actually the one referred in the Imprints database. It is
+ <I
+CLASS="EMPHASIS"
+>not</I
+> recommended that this security check
+ be disabled.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN153"
+>The Installation Client</A
+></H2
+><P
+>More information regarding the Imprints installation client
+ is available in the <TT
+CLASS="FILENAME"
+>Imprints-Client-HOWTO.ps</TT
+>
+ file included with the imprints source package.</P
+><P
+>The Imprints installation client comes in two forms.</P
+><P
+></P
+><UL
+><LI
+><P
+>a set of command line Perl scripts</P
+></LI
+><LI
+><P
+>a GTK+ based graphical interface to
+ the command line perl scripts</P
+></LI
+></UL
+><P
+>The installation client (in both forms) provides a means
+ of querying the Imprints database server for a matching
+ list of known printer model names as well as a means to
+ download and install the drivers on remote Samba and Windows
+ NT print servers.</P
+><P
+>The basic installation process is in four steps and
+ perl code is wrapped around <B
+CLASS="COMMAND"
+>smbclient</B
+>
+ and <B
+CLASS="COMMAND"
+>rpcclient</B
+>.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>
+foreach (supported architecture for a given driver)
+{
+ 1. rpcclient: Get the appropriate upload directory
+ on the remote server
+ 2. smbclient: Upload the driver files
+ 3. rpcclient: Issues an AddPrinterDriver() MS-RPC
+}
+
+4. rpcclient: Issue an AddPrinterEx() MS-RPC to actually
+ create the printer</PRE
+></P
+><P
+>One of the problems encountered when implementing
+ the Imprints tool set was the name space issues between
+ various supported client architectures. For example, Windows
+ NT includes a driver named "Apple LaserWriter II NTX v51.8"
+ and Windows 95 calls its version of this driver "Apple
+ LaserWriter II NTX"</P
+><P
+>The problem is how to know what client drivers have
+ been uploaded for a printer. As astute reader will remember
+ that the Windows NT Printer Properties dialog only includes
+ space for one printer driver name. A quick look in the
+ Windows NT 4.0 system registry at</P
+><P
+><TT
+CLASS="FILENAME"
+>HKLM\System\CurrentControlSet\Control\Print\Environment
+ </TT
+></P
+><P
+>will reveal that Windows NT always uses the NT driver
+ name. This is ok as Windows NT always requires that at least
+ the Windows NT version of the printer driver is present.
+ However, Samba does not have the requirement internally.
+ Therefore, how can you use the NT driver name if is has not
+ already been installed?</P
+><P
+>The way of sidestepping this limitation is to require
+ that all Imprints printer driver packages include both the Intel
+ Windows NT and 95/98 printer drivers and that NT driver is
+ installed first.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN175"
+><A
+NAME="MIGRATION"
+></A
+>Migration to from Samba 2.0.x to 2.2.x</A
+></H1
+><P
+>Given that printer driver management has changed (we hope improved) in
+2.2 over prior releases, migration from an existing setup to 2.2 can
+follow several paths. Here are the possible scenarios for
+migration:</P
+><P
+></P
+><UL
+><LI
+><P
+>If you do not desire the new Windows NT
+ print driver support, nothing needs to be done.
+ All existing parameters work the same.</P
+></LI
+><LI
+><P
+>If you want to take advantage of NT printer
+ driver support but do not want to migrate the
+ 9x drivers to the new setup, the leave the existing
+ <TT
+CLASS="FILENAME"
+>printers.def</TT
+> file. When smbd attempts
+ to locate a
+ 9x driver for the printer in the TDB and fails it
+ will drop down to using the printers.def (and all
+ associated parameters). The <B
+CLASS="COMMAND"
+>make_printerdef</B
+>
+ tool will also remain for backwards compatibility but will
+ be removed in the next major release.</P
+></LI
+><LI
+><P
+>If you install a Windows 9x driver for a printer
+ on your Samba host (in the printing TDB), this information will
+ take precedence and the three old printing parameters
+ will be ignored (including print driver location).</P
+></LI
+><LI
+><P
+>If you want to migrate an existing <TT
+CLASS="FILENAME"
+>printers.def</TT
+>
+ file into the new setup, the current only solution is to use the Windows
+ NT APW to install the NT drivers and the 9x drivers. This can be scripted
+ using <B
+CLASS="COMMAND"
+>smbclient</B
+> and <B
+CLASS="COMMAND"
+>rpcclient</B
+>. See the
+ Imprints installation client at <A
+HREF="http://imprints.sourceforge.net/"
+TARGET="_top"
+>http://imprints.sourceforge.net/</A
+>
+ for an example.
+ </P
+></LI
+></UL
+><DIV
+CLASS="WARNING"
+><P
+></P
+><TABLE
+CLASS="WARNING"
+BORDER="1"
+WIDTH="100%"
+><TR
+><TD
+ALIGN="CENTER"
+><B
+>Achtung!</B
+></TD
+></TR
+><TR
+><TD
+ALIGN="LEFT"
+><P
+>The following <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> parameters are considered to
+be deprecated and will be removed soon. Do not use them in new
+installations</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver file (G)</I
+></TT
+>
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver (S)</I
+></TT
+>
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver location (S)</I
+></TT
+>
+ </P
+></LI
+></UL
+></TD
+></TR
+></TABLE
+></DIV
+><P
+>The have been two new parameters add in Samba 2.2.2 to for
+better support of Samba 2.0.x backwards capability (<TT
+CLASS="PARAMETER"
+><I
+>disable
+spoolss</I
+></TT
+>) and for using local printers drivers on Windows
+NT/2000 clients (<TT
+CLASS="PARAMETER"
+><I
+>use client driver</I
+></TT
+>). Both of
+these options are described in the smb.coinf(5) man page and are
+disabled by default.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/rpcclient.1.html b/docs/htmldocs/rpcclient.1.html
new file mode 100644
index 00000000000..98a19c6ea2d
--- /dev/null
+++ b/docs/htmldocs/rpcclient.1.html
@@ -0,0 +1,719 @@
+<HTML
+><HEAD
+><TITLE
+>rpcclient</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="RPCCLIENT"
+>rpcclient</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>rpcclient&nbsp;--&nbsp;tool for executing client side
+ MS-RPC functions</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>rpcclient</B
+> {server} [-A authfile] [-c &#60;command string&#62;] [-d debuglevel] [-h] [-l logfile] [-N] [-s &#60;smb config file&#62;] [-U username[%password]] [-W workgroup] [-N]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN22"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>rpcclient</B
+> is a utility initially developed
+ to test MS-RPC functionality in Samba itself. It has undergone
+ several stages of development and stability. Many system administrators
+ have now written scripts around it to manage Windows NT clients from
+ their UNIX workstation. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN28"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>server</DT
+><DD
+><P
+>NetBIOS name of Server to which to connect.
+ The server can be any SMB/CIFS server. The name is
+ resolved using the <A
+HREF="smb.conf.5.html#NAMERESOLVEORDER"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>name resolve order</I
+></TT
+></A
+> line from
+ <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>.</P
+></DD
+><DT
+>-A filename</DT
+><DD
+><P
+>This option allows
+ you to specify a file from which to read the username and
+ password used in the connection. The format of the file is
+ </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> username = &#60;value&#62;
+ password = &#60;value&#62;
+ domain = &#60;value&#62;
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Make certain that the permissions on the file restrict
+ access from unwanted users. </P
+></DD
+><DT
+>-c 'command string'</DT
+><DD
+><P
+>execute semicolon separated commands (listed
+ below)) </P
+></DD
+><DT
+>-d debuglevel</DT
+><DD
+><P
+>set the debuglevel. Debug level 0 is the lowest
+ and 100 being the highest. This should be set to 100 if you are
+ planning on submitting a bug report to the Samba team (see <TT
+CLASS="FILENAME"
+>BUGS.txt</TT
+>).
+ </P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Print a summary of command line options.
+ </P
+></DD
+><DT
+>-l logbasename</DT
+><DD
+><P
+>File name for log/debug files. The extension
+ <TT
+CLASS="CONSTANT"
+>'.client'</TT
+> will be appended. The log file is never removed
+ by the client.
+ </P
+></DD
+><DT
+>-N</DT
+><DD
+><P
+>instruct <B
+CLASS="COMMAND"
+>rpcclient</B
+> not to ask
+ for a password. By default, <B
+CLASS="COMMAND"
+>rpcclient</B
+> will prompt
+ for a password. See also the <TT
+CLASS="PARAMETER"
+><I
+>-U</I
+></TT
+> option.</P
+></DD
+><DT
+>-s smb.conf</DT
+><DD
+><P
+>Specifies the location of the all important
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. </P
+></DD
+><DT
+>-U username[%password]</DT
+><DD
+><P
+>Sets the SMB username or username and password. </P
+><P
+>If %password is not specified, the user will be prompted. The
+ client will first check the <TT
+CLASS="ENVAR"
+>USER</TT
+> environment variable, then the
+ <TT
+CLASS="ENVAR"
+>LOGNAME</TT
+> variable and if either exists, the
+ string is uppercased. If these environmental variables are not
+ found, the username <TT
+CLASS="CONSTANT"
+>GUEST</TT
+> is used. </P
+><P
+>A third option is to use a credentials file which
+ contains the plaintext of the username and password. This
+ option is mainly provided for scripts where the admin doesn't
+ desire to pass the credentials on the command line or via environment
+ variables. If this method is used, make certain that the permissions
+ on the file restrict access from unwanted users. See the
+ <TT
+CLASS="PARAMETER"
+><I
+>-A</I
+></TT
+> for more details. </P
+><P
+>Be cautious about including passwords in scripts. Also, on
+ many systems the command line of a running process may be seen
+ via the <B
+CLASS="COMMAND"
+>ps</B
+> command. To be safe always allow
+ <B
+CLASS="COMMAND"
+>rpcclient</B
+> to prompt for a password and type
+ it in directly. </P
+></DD
+><DT
+>-W domain</DT
+><DD
+><P
+>Set the SMB domain of the username. This
+ overrides the default domain which is the domain defined in
+ smb.conf. If the domain specified is the same as the server's NetBIOS name,
+ it causes the client to log on using the server's local SAM (as
+ opposed to the Domain SAM). </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN92"
+></A
+><H2
+>COMMANDS</H2
+><P
+><EM
+>LSARPC</EM
+></P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>lsaquery</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>lookupsids</B
+> - Resolve a list
+ of SIDs to usernames.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>lookupnames</B
+> - Resolve s list
+ of usernames to SIDs.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumtrusts</B
+></P
+></LI
+></UL
+><P
+> </P
+><P
+><EM
+>SAMR</EM
+></P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>queryuser</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>querygroup</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>queryusergroups</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>querygroupmem</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>queryaliasmem</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>querydispinfo</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>querydominfo</B
+></P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumdomgroups</B
+></P
+></LI
+></UL
+><P
+> </P
+><P
+><EM
+>SPOOLSS</EM
+></P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>adddriver &#60;arch&#62; &#60;config&#62;</B
+>
+ - Execute an AddPrinterDriver() RPC to install the printer driver
+ information on the server. Note that the driver files should
+ already exist in the directory returned by
+ <B
+CLASS="COMMAND"
+>getdriverdir</B
+>. Possible values for
+ <TT
+CLASS="PARAMETER"
+><I
+>arch</I
+></TT
+> are the same as those for
+ the <B
+CLASS="COMMAND"
+>getdriverdir</B
+> command.
+ The <TT
+CLASS="PARAMETER"
+><I
+>config</I
+></TT
+> parameter is defined as
+ follows: </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> Long Printer Name:\
+ Driver File Name:\
+ Data File Name:\
+ Config File Name:\
+ Help File Name:\
+ Language Monitor Name:\
+ Default Data Type:\
+ Comma Separated list of Files
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Any empty fields should be enter as the string "NULL". </P
+><P
+>Samba does not need to support the concept of Print Monitors
+ since these only apply to local printers whose driver can make
+ use of a bi-directional link for communication. This field should
+ be "NULL". On a remote NT print server, the Print Monitor for a
+ driver must already be installed prior to adding the driver or
+ else the RPC will fail. </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>addprinter &#60;printername&#62;
+ &#60;sharename&#62; &#60;drivername&#62; &#60;port&#62;</B
+>
+ - Add a printer on the remote server. This printer
+ will be automatically shared. Be aware that the printer driver
+ must already be installed on the server (see <B
+CLASS="COMMAND"
+>adddriver</B
+>)
+ and the <TT
+CLASS="PARAMETER"
+><I
+>port</I
+></TT
+>must be a valid port name (see
+ <B
+CLASS="COMMAND"
+>enumports</B
+>.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>deldriver</B
+> - Delete the
+ specified printer driver for all architectures. This
+ does not delete the actual driver files from the server,
+ only the entry from the server's list of drivers.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumdata</B
+> - Enumerate all
+ printer setting data stored on the server. On Windows NT clients,
+ these values are stored in the registry, while Samba servers
+ store them in the printers TDB. This command corresponds
+ to the MS Platform SDK GetPrinterData() function (* This
+ command is currently unimplemented).</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumjobs &#60;printer&#62;</B
+>
+ - List the jobs and status of a given printer.
+ This command corresponds to the MS Platform SDK EnumJobs()
+ function (* This command is currently unimplemented).</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumports [level]</B
+>
+ - Executes an EnumPorts() call using the specified
+ info level. Currently only info levels 1 and 2 are supported.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumdrivers [level]</B
+>
+ - Execute an EnumPrinterDrivers() call. This lists the various installed
+ printer drivers for all architectures. Refer to the MS Platform SDK
+ documentation for more details of the various flags and calling
+ options. Currently supported info levels are 1, 2, and 3.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>enumprinters [level]</B
+>
+ - Execute an EnumPrinters() call. This lists the various installed
+ and share printers. Refer to the MS Platform SDK documentation for
+ more details of the various flags and calling options. Currently
+ supported info levels are 0, 1, and 2.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>getdata &#60;printername&#62;</B
+>
+ - Retrieve the data for a given printer setting. See
+ the <B
+CLASS="COMMAND"
+>enumdata</B
+> command for more information.
+ This command corresponds to the GetPrinterData() MS Platform
+ SDK function (* This command is currently unimplemented). </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>getdriver &#60;printername&#62;</B
+>
+ - Retrieve the printer driver information (such as driver file,
+ config file, dependent files, etc...) for
+ the given printer. This command corresponds to the GetPrinterDriver()
+ MS Platform SDK function. Currently info level 1, 2, and 3 are supported.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>getdriverdir &#60;arch&#62;</B
+>
+ - Execute a GetPrinterDriverDirectory()
+ RPC to retreive the SMB share name and subdirectory for
+ storing printer driver files for a given architecture. Possible
+ values for <TT
+CLASS="PARAMETER"
+><I
+>arch</I
+></TT
+> are "Windows 4.0"
+ (for Windows 95/98), "Windows NT x86", "Windows NT PowerPC", "Windows
+ Alpha_AXP", and "Windows NT R4000". </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>getprinter &#60;printername&#62;</B
+>
+ - Retrieve the current printer information. This command
+ corresponds to the GetPrinter() MS Platform SDK function.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>openprinter &#60;printername&#62;</B
+>
+ - Execute an OpenPrinterEx() and ClosePrinter() RPC
+ against a given printer. </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>setdriver &#60;printername&#62; &#60;drivername&#62;</B
+>
+ - Execute a SetPrinter() command to update the printer driver associated
+ with an installed printer. The printer driver must already be correctly
+ installed on the print server. </P
+><P
+>See also the <B
+CLASS="COMMAND"
+>enumprinters</B
+> and
+ <B
+CLASS="COMMAND"
+>enumdrivers</B
+> commands for obtaining a list of
+ of installed printers and drivers.</P
+></LI
+></UL
+><P
+><EM
+>GENERAL OPTIONS</EM
+></P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>debuglevel</B
+> - Set the current debug level
+ used to log information.</P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>help (?)</B
+> - Print a listing of all
+ known commands or extended help on a particular command.
+ </P
+></LI
+><LI
+><P
+><B
+CLASS="COMMAND"
+>quit (exit)</B
+> - Exit <B
+CLASS="COMMAND"
+>rpcclient
+ </B
+>.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN212"
+></A
+><H2
+>BUGS</H2
+><P
+><B
+CLASS="COMMAND"
+>rpcclient</B
+> is designed as a developer testing tool
+ and may not be robust in certain areas (such as command line parsing).
+ It has been known to generate a core dump upon failures when invalid
+ parameters where passed to the interpreter. </P
+><P
+>From Luke Leighton's original rpcclient man page:</P
+><P
+><EM
+>"WARNING!</EM
+> The MSRPC over SMB code has
+ been developed from examining Network traces. No documentation is
+ available from the original creators (Microsoft) on how MSRPC over
+ SMB works, or how the individual MSRPC services work. Microsoft's
+ implementation of these services has been demonstrated (and reported)
+ to be... a bit flaky in places. </P
+><P
+>The development of Samba's implementation is also a bit rough,
+ and as more of the services are understood, it can even result in
+ versions of <B
+CLASS="COMMAND"
+>smbd(8)</B
+> and <B
+CLASS="COMMAND"
+>rpcclient(1)</B
+>
+ that are incompatible for some commands or services. Additionally,
+ the developers are sending reports to Microsoft, and problems found
+ or reported to Microsoft are fixed in Service Packs, which may
+ result in incompatibilities." </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN222"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of the Samba
+ suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN225"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original rpcclient man page was written by Matthew
+ Geddes, Luke Kenneth Casson Leighton, and rewritten by Gerald Carter.
+ The conversion to DocBook for Samba 2.2 was done by Gerald
+ Carter.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/samba.7.html b/docs/htmldocs/samba.7.html
new file mode 100644
index 00000000000..6fb9eac5784
--- /dev/null
+++ b/docs/htmldocs/samba.7.html
@@ -0,0 +1,365 @@
+<HTML
+><HEAD
+><TITLE
+>samba</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SAMBA"
+>samba</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>SAMBA&nbsp;--&nbsp;A Windows SMB/CIFS fileserver for UNIX</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>Samba</B
+> </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN11"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>The Samba software suite is a collection of programs
+ that implements the Server Message Block (commonly abbreviated
+ as SMB) protocol for UNIX systems. This protocol is sometimes
+ also referred to as the Common Internet File System (CIFS),
+ LanManager or NetBIOS protocol.</P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><B
+CLASS="COMMAND"
+>smbd</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>smbd </B
+>
+ daemon provides the file and print services to
+ SMB clients, such as Windows 95/98, Windows NT, Windows
+ for Workgroups or LanManager. The configuration file
+ for this daemon is described in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+ </P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>nmbd</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ daemon provides NetBIOS nameserving and browsing
+ support. The configuration file for this daemon
+ is described in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+></P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>smbclient</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>smbclient</B
+>
+ program implements a simple ftp-like client. This
+ is useful for accessing SMB shares on other compatible
+ servers (such as Windows NT), and can also be used
+ to allow a UNIX box to print to a printer attached to
+ any SMB server (such as a PC running Windows NT).</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>testparm</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>testparm</B
+>
+ utility is a simple syntax checker for Samba's
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>configuration file.</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>testprns</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>testprns</B
+>
+ utility supports testing printer names defined
+ in your <TT
+CLASS="FILENAME"
+>printcap&#62;</TT
+> file used
+ by Samba.</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>smbstatus</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>smbstatus</B
+>
+ tool provides access to information about the
+ current connections to <B
+CLASS="COMMAND"
+>smbd</B
+>.</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>nmblookup</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>nmblookup</B
+>
+ tools allows NetBIOS name queries to be made
+ from a UNIX host.</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>make_smbcodepage</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>make_smbcodepage</B
+>
+ utility provides a means of creating SMB code page
+ definition files for your <B
+CLASS="COMMAND"
+>smbd</B
+> server.</P
+></DD
+><DT
+><B
+CLASS="COMMAND"
+>smbpasswd</B
+></DT
+><DD
+><P
+>The <B
+CLASS="COMMAND"
+>smbpasswd</B
+>
+ command is a tool for changing LanMan and Windows NT
+ password hashes on Samba and Windows NT servers.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN75"
+></A
+><H2
+>COMPONENTS</H2
+><P
+>The Samba suite is made up of several components. Each
+ component is described in a separate manual page. It is strongly
+ recommended that you read the documentation that comes with Samba
+ and the manual pages of those components that you use. If the
+ manual pages aren't clear enough then please send a patch or
+ bug report to <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+> samba@samba.org</A
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN79"
+></A
+><H2
+>AVAILABILITY</H2
+><P
+>The Samba software suite is licensed under the
+ GNU Public License(GPL). A copy of that license should
+ have come with the package in the file COPYING. You are
+ encouraged to distribute copies of the Samba suite, but
+ please obey the terms of this license.</P
+><P
+>The latest version of the Samba suite can be
+ obtained via anonymous ftp from samba.org in the
+ directory pub/samba/. It is also available on several
+ mirror sites worldwide.</P
+><P
+>You may also find useful information about Samba
+ on the newsgroup <A
+HREF="news:comp.protocols.smb"
+TARGET="_top"
+> comp.protocol.smb</A
+> and the Samba mailing
+ list. Details on how to join the mailing list are given in
+ the README file that comes with Samba.</P
+><P
+>If you have access to a WWW viewer (such as Netscape
+ or Mosaic) then you will also find lots of useful information,
+ including back issues of the Samba mailing list, at
+ <A
+HREF="http://lists.samba.org/"
+TARGET="_top"
+>http://lists.samba.org</A
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN87"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of the
+ Samba suite. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN90"
+></A
+><H2
+>CONTRIBUTIONS</H2
+><P
+>If you wish to contribute to the Samba project,
+ then I suggest you join the Samba mailing list at
+ <A
+HREF="http://lists.samba.org/"
+TARGET="_top"
+>http://lists.samba.org</A
+>.
+ </P
+><P
+>If you have patches to submit or bugs to report
+ then you may mail them directly to samba-patches@samba.org.
+ Note, however, that due to the enormous popularity of this
+ package the Samba Team may take some time to respond to mail. We
+ prefer patches in <B
+CLASS="COMMAND"
+>diff -u</B
+> format.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN96"
+></A
+><H2
+>CONTRIBUTORS</H2
+><P
+>Contributors to the project are now too numerous
+ to mention here but all deserve the thanks of all Samba
+ users. To see a full list, look at <A
+HREF="ftp://samba.org/pub/samba/alpha/change-log"
+TARGET="_top"
+> ftp://samba.org/pub/samba/alpha/change-log</A
+>
+ for the pre-CVS changes and at <A
+HREF="ftp://samba.org/pub/samba/alpha/cvs.log"
+TARGET="_top"
+> ftp://samba.org/pub/samba/alpha/cvs.log</A
+>
+ for the contributors to Samba post-CVS. CVS is the Open Source
+ source code control system used by the Samba Team to develop
+ Samba. The project would have been unmanageable without it.</P
+><P
+>In addition, several commercial organizations now help
+ fund the Samba Team with money and equipment. For details see
+ the Samba Web pages at <A
+HREF="http://samba.org/samba/samba-thanks.html"
+TARGET="_top"
+> http://samba.org/samba/samba-thanks.html</A
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN103"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smb.conf.5.html b/docs/htmldocs/smb.conf.5.html
new file mode 100644
index 00000000000..f60cd595cf8
--- /dev/null
+++ b/docs/htmldocs/smb.conf.5.html
@@ -0,0 +1,19333 @@
+<HTML
+><HEAD
+><TITLE
+>smb.conf</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMB.CONF"
+>smb.conf</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smb.conf&nbsp;--&nbsp;The configuration file for the Samba suite</DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN8"
+></A
+><H2
+>SYNOPSIS</H2
+><P
+>The <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file is a configuration
+ file for the Samba suite. <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> contains
+ runtime configuration information for the Samba programs. The
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file is designed to be configured and
+ administered by the <A
+HREF="swat.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>swat(8)</B
+>
+ </A
+> program. The complete description of the file format and
+ possible parameters held within are here for reference purposes.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN16"
+></A
+><H2
+>FILE FORMAT</H2
+><P
+>The file consists of sections and parameters. A section
+ begins with the name of the section in square brackets and continues
+ until the next section begins. Sections contain parameters of the
+ form</P
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>name</I
+></TT
+> = <TT
+CLASS="REPLACEABLE"
+><I
+>value
+ </I
+></TT
+></P
+><P
+>The file is line-based - that is, each newline-terminated
+ line represents either a comment, a section name or a parameter.</P
+><P
+>Section and parameter names are not case sensitive.</P
+><P
+>Only the first equals sign in a parameter is significant.
+ Whitespace before or after the first equals sign is discarded.
+ Leading, trailing and internal whitespace in section and parameter
+ names is irrelevant. Leading and trailing whitespace in a parameter
+ value is discarded. Internal whitespace within a parameter value
+ is retained verbatim.</P
+><P
+>Any line beginning with a semicolon (';') or a hash ('#')
+ character is ignored, as are lines containing only whitespace.</P
+><P
+>Any line ending in a '\' is continued
+ on the next line in the customary UNIX fashion.</P
+><P
+>The values following the equals sign in parameters are all
+ either a string (no quotes needed) or a boolean, which may be given
+ as yes/no, 0/1 or true/false. Case is not significant in boolean
+ values, but is preserved in string values. Some items such as
+ create modes are numeric.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN28"
+></A
+><H2
+>SECTION DESCRIPTIONS</H2
+><P
+>Each section in the configuration file (except for the
+ [global] section) describes a shared resource (known
+ as a "share"). The section name is the name of the
+ shared resource and the parameters within the section define
+ the shares attributes.</P
+><P
+>There are three special sections, [global],
+ [homes] and [printers], which are
+ described under <EM
+>special sections</EM
+>. The
+ following notes apply to ordinary section descriptions.</P
+><P
+>A share consists of a directory to which access is being
+ given plus a description of the access rights which are granted
+ to the user of the service. Some housekeeping options are
+ also specifiable.</P
+><P
+>Sections are either file share services (used by the
+ client as an extension of their native file systems) or
+ printable services (used by the client to access print services
+ on the host running the server).</P
+><P
+>Sections may be designated <EM
+>guest</EM
+> services,
+ in which case no password is required to access them. A specified
+ UNIX <EM
+>guest account</EM
+> is used to define access
+ privileges in this case.</P
+><P
+>Sections other than guest services will require a password
+ to access them. The client provides the username. As older clients
+ only provide passwords and not usernames, you may specify a list
+ of usernames to check against the password using the "user ="
+ option in the share definition. For modern clients such as
+ Windows 95/98/ME/NT/2000, this should not be necessary.</P
+><P
+>Note that the access rights granted by the server are
+ masked by the access rights granted to the specified or guest
+ UNIX user by the host system. The server does not grant more
+ access than the host system grants.</P
+><P
+>The following sample section defines a file space share.
+ The user has write access to the path <TT
+CLASS="FILENAME"
+>/home/bar</TT
+>.
+ The share is accessed via the share name "foo":</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+> <TT
+CLASS="COMPUTEROUTPUT"
+> [foo]
+ path = /home/bar
+ writeable = true
+ </TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+><P
+>The following sample section defines a printable share.
+ The share is readonly, but printable. That is, the only write
+ access permitted is via calls to open, write to and close a
+ spool file. The <EM
+>guest ok</EM
+> parameter means
+ access will be permitted as the default guest user (specified
+ elsewhere):</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+> <TT
+CLASS="COMPUTEROUTPUT"
+> [aprinter]
+ path = /usr/spool/public
+ writeable = false
+ printable = true
+ guest ok = true
+ </TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN48"
+></A
+><H2
+>SPECIAL SECTIONS</H2
+><DIV
+CLASS="REFSECT2"
+><A
+NAME="AEN50"
+></A
+><H3
+>The [global] section</H3
+><P
+>parameters in this section apply to the server
+ as a whole, or are defaults for sections which do not
+ specifically define certain items. See the notes
+ under PARAMETERS for more information.</P
+></DIV
+><DIV
+CLASS="REFSECT2"
+><A
+NAME="AEN53"
+></A
+><H3
+>The [homes] section</H3
+><P
+>If a section called homes is included in the
+ configuration file, services connecting clients to their
+ home directories can be created on the fly by the server.</P
+><P
+>When the connection request is made, the existing
+ sections are scanned. If a match is found, it is used. If no
+ match is found, the requested section name is treated as a
+ user name and looked up in the local password file. If the
+ name exists and the correct password has been given, a share is
+ created by cloning the [homes] section.</P
+><P
+>Some modifications are then made to the newly
+ created share:</P
+><P
+></P
+><UL
+><LI
+><P
+>The share name is changed from homes to
+ the located username.</P
+></LI
+><LI
+><P
+>If no path was given, the path is set to
+ the user's home directory.</P
+></LI
+></UL
+><P
+>If you decide to use a <EM
+>path =</EM
+> line
+ in your [homes] section then you may find it useful
+ to use the %S macro. For example :</P
+><P
+><TT
+CLASS="USERINPUT"
+><B
+>path = /data/pchome/%S</B
+></TT
+></P
+><P
+>would be useful if you have different home directories
+ for your PCs than for UNIX access.</P
+><P
+>This is a fast and simple way to give a large number
+ of clients access to their home directories with a minimum
+ of fuss.</P
+><P
+>A similar process occurs if the requested section
+ name is "homes", except that the share name is not
+ changed to that of the requesting user. This method of using
+ the [homes] section works well if different users share
+ a client PC.</P
+><P
+>The [homes] section can specify all the parameters
+ a normal service section can specify, though some make more sense
+ than others. The following is a typical and suitable [homes]
+ section:</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+> <TT
+CLASS="COMPUTEROUTPUT"
+> [homes]
+ writeable = yes
+ </TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+><P
+>An important point is that if guest access is specified
+ in the [homes] section, all home directories will be
+ visible to all clients <EM
+>without a password</EM
+>.
+ In the very unlikely event that this is actually desirable, it
+ would be wise to also specify <EM
+>read only
+ access</EM
+>.</P
+><P
+>Note that the <EM
+>browseable</EM
+> flag for
+ auto home directories will be inherited from the global browseable
+ flag, not the [homes] browseable flag. This is useful as
+ it means setting <EM
+>browseable = no</EM
+> in
+ the [homes] section will hide the [homes] share but make
+ any auto home directories visible.</P
+></DIV
+><DIV
+CLASS="REFSECT2"
+><A
+NAME="AEN79"
+></A
+><H3
+>The [printers] section</H3
+><P
+>This section works like [homes],
+ but for printers.</P
+><P
+>If a [printers] section occurs in the
+ configuration file, users are able to connect to any printer
+ specified in the local host's printcap file.</P
+><P
+>When a connection request is made, the existing sections
+ are scanned. If a match is found, it is used. If no match is found,
+ but a [homes] section exists, it is used as described
+ above. Otherwise, the requested section name is treated as a
+ printer name and the appropriate printcap file is scanned to see
+ if the requested section name is a valid printer share name. If
+ a match is found, a new printer share is created by cloning
+ the [printers] section.</P
+><P
+>A few modifications are then made to the newly created
+ share:</P
+><P
+></P
+><UL
+><LI
+><P
+>The share name is set to the located printer
+ name</P
+></LI
+><LI
+><P
+>If no printer name was given, the printer name
+ is set to the located printer name</P
+></LI
+><LI
+><P
+>If the share does not permit guest access and
+ no username was given, the username is set to the located
+ printer name.</P
+></LI
+></UL
+><P
+>Note that the [printers] service MUST be
+ printable - if you specify otherwise, the server will refuse
+ to load the configuration file.</P
+><P
+>Typically the path specified would be that of a
+ world-writeable spool directory with the sticky bit set on
+ it. A typical [printers] entry would look like
+ this:</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><TT
+CLASS="COMPUTEROUTPUT"
+> [printers]
+ path = /usr/spool/public
+ guest ok = yes
+ printable = yes
+ </TT
+></PRE
+></TD
+></TR
+></TABLE
+><P
+>All aliases given for a printer in the printcap file
+ are legitimate printer names as far as the server is concerned.
+ If your printing subsystem doesn't work like that, you will have
+ to set up a pseudo-printcap. This is a file consisting of one or
+ more lines like this:</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+> <TT
+CLASS="COMPUTEROUTPUT"
+> alias|alias|alias|alias...
+ </TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+><P
+>Each alias should be an acceptable printer name for
+ your printing subsystem. In the [global] section, specify
+ the new file as your printcap. The server will then only recognize
+ names found in your pseudo-printcap, which of course can contain
+ whatever aliases you like. The same technique could be used
+ simply to limit access to a subset of your local printers.</P
+><P
+>An alias, by the way, is defined as any component of the
+ first entry of a printcap record. Records are separated by newlines,
+ components (if there are more than one) are separated by vertical
+ bar symbols ('|').</P
+><P
+>NOTE: On SYSV systems which use lpstat to determine what
+ printers are defined on the system you may be able to use
+ "printcap name = lpstat" to automatically obtain a list
+ of printers. See the "printcap name" option
+ for more details.</P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN102"
+></A
+><H2
+>PARAMETERS</H2
+><P
+>parameters define the specific attributes of sections.</P
+><P
+>Some parameters are specific to the [global] section
+ (e.g., <EM
+>security</EM
+>). Some parameters are usable
+ in all sections (e.g., <EM
+>create mode</EM
+>). All others
+ are permissible only in normal sections. For the purposes of the
+ following descriptions the [homes] and [printers]
+ sections will be considered normal. The letter <EM
+>G</EM
+>
+ in parentheses indicates that a parameter is specific to the
+ [global] section. The letter <EM
+>S</EM
+>
+ indicates that a parameter can be specified in a service specific
+ section. Note that all <EM
+>S</EM
+> parameters can also be specified in
+ the [global] section - in which case they will define
+ the default behavior for all services.</P
+><P
+>parameters are arranged here in alphabetical order - this may
+ not create best bedfellows, but at least you can find them! Where
+ there are synonyms, the preferred synonym is described, others refer
+ to the preferred synonym.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN112"
+></A
+><H2
+>VARIABLE SUBSTITUTIONS</H2
+><P
+>Many of the strings that are settable in the config file
+ can take substitutions. For example the option "path =
+ /tmp/%u" would be interpreted as "path =
+ /tmp/john" if the user connected with the username john.</P
+><P
+>These substitutions are mostly noted in the descriptions below,
+ but there are some general substitutions which apply whenever they
+ might be relevant. These are:</P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>%S</DT
+><DD
+><P
+>the name of the current service, if any.</P
+></DD
+><DT
+>%P</DT
+><DD
+><P
+>the root directory of the current service,
+ if any.</P
+></DD
+><DT
+>%u</DT
+><DD
+><P
+>user name of the current service, if any.</P
+></DD
+><DT
+>%g</DT
+><DD
+><P
+>primary group name of %u.</P
+></DD
+><DT
+>%U</DT
+><DD
+><P
+>session user name (the user name that the client
+ wanted, not necessarily the same as the one they got).</P
+></DD
+><DT
+>%G</DT
+><DD
+><P
+>primary group name of %U.</P
+></DD
+><DT
+>%H</DT
+><DD
+><P
+>the home directory of the user given
+ by %u.</P
+></DD
+><DT
+>%v</DT
+><DD
+><P
+>the Samba version.</P
+></DD
+><DT
+>%h</DT
+><DD
+><P
+>the Internet hostname that Samba is running
+ on.</P
+></DD
+><DT
+>%m</DT
+><DD
+><P
+>the NetBIOS name of the client machine
+ (very useful).</P
+></DD
+><DT
+>%L</DT
+><DD
+><P
+>the NetBIOS name of the server. This allows you
+ to change your config based on what the client calls you. Your
+ server can have a "dual personality".</P
+></DD
+><DT
+>%M</DT
+><DD
+><P
+>the Internet name of the client machine.
+ </P
+></DD
+><DT
+>%N</DT
+><DD
+><P
+>the name of your NIS home directory server.
+ This is obtained from your NIS auto.map entry. If you have
+ not compiled Samba with the <EM
+>--with-automount</EM
+>
+ option then this value will be the same as %L.</P
+></DD
+><DT
+>%p</DT
+><DD
+><P
+>the path of the service's home directory,
+ obtained from your NIS auto.map entry. The NIS auto.map entry
+ is split up as "%N:%p".</P
+></DD
+><DT
+>%R</DT
+><DD
+><P
+>the selected protocol level after
+ protocol negotiation. It can be one of CORE, COREPLUS,
+ LANMAN1, LANMAN2 or NT1.</P
+></DD
+><DT
+>%d</DT
+><DD
+><P
+>The process id of the current server
+ process.</P
+></DD
+><DT
+>%a</DT
+><DD
+><P
+>the architecture of the remote
+ machine. Only some are recognized, and those may not be
+ 100% reliable. It currently recognizes Samba, WfWg, Win95,
+ WinNT and Win2k. Anything else will be known as
+ "UNKNOWN". If it gets it wrong then sending a level
+ 3 log to <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+>samba@samba.org
+ </A
+> should allow it to be fixed.</P
+></DD
+><DT
+>%I</DT
+><DD
+><P
+>The IP address of the client machine.</P
+></DD
+><DT
+>%T</DT
+><DD
+><P
+>the current date and time.</P
+></DD
+><DT
+>%$(<TT
+CLASS="REPLACEABLE"
+><I
+>envvar</I
+></TT
+>)</DT
+><DD
+><P
+>The value of the environment variable
+ <TT
+CLASS="REPLACEABLE"
+><I
+>envar</I
+></TT
+>.</P
+></DD
+></DL
+></DIV
+><P
+>There are some quite creative things that can be done
+ with these substitutions and other smb.conf options.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN202"
+></A
+><H2
+>NAME MANGLING</H2
+><P
+>Samba supports "name mangling" so that DOS and
+ Windows clients can use files that don't conform to the 8.3 format.
+ It can also be set to adjust the case of 8.3 format filenames.</P
+><P
+>There are several options that control the way mangling is
+ performed, and they are grouped here rather than listed separately.
+ For the defaults look at the output of the testparm program. </P
+><P
+>All of these options can be set separately for each service
+ (or globally, of course). </P
+><P
+>The options are: </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>mangle case = yes/no</DT
+><DD
+><P
+> controls if names that have characters that
+ aren't of the "default" case are mangled. For example,
+ if this is yes then a name like "Mail" would be mangled.
+ Default <EM
+>no</EM
+>.</P
+></DD
+><DT
+>case sensitive = yes/no</DT
+><DD
+><P
+>controls whether filenames are case sensitive. If
+ they aren't then Samba must do a filename search and match on passed
+ names. Default <EM
+>no</EM
+>.</P
+></DD
+><DT
+>default case = upper/lower</DT
+><DD
+><P
+>controls what the default case is for new
+ filenames. Default <EM
+>lower</EM
+>.</P
+></DD
+><DT
+>preserve case = yes/no</DT
+><DD
+><P
+>controls if new files are created with the
+ case that the client passes, or if they are forced to be the
+ "default" case. Default <EM
+>yes</EM
+>.
+ </P
+></DD
+><DT
+>short preserve case = yes/no</DT
+><DD
+><P
+>controls if new files which conform to 8.3 syntax,
+ that is all in upper case and of suitable length, are created
+ upper case, or if they are forced to be the "default"
+ case. This option can be use with "preserve case = yes"
+ to permit long filenames to retain their case, while short names
+ are lowercased. Default <EM
+>yes</EM
+>.</P
+></DD
+></DL
+></DIV
+><P
+>By default, Samba 2.2 has the same semantics as a Windows
+ NT server, in that it is case insensitive but case preserving.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN235"
+></A
+><H2
+>NOTE ABOUT USERNAME/PASSWORD VALIDATION</H2
+><P
+>There are a number of ways in which a user can connect
+ to a service. The server uses the following steps in determining
+ if it will allow a connection to a specified service. If all the
+ steps fail, then the connection request is rejected. However, if one of the
+ steps succeeds, then the following steps are not checked.</P
+><P
+>If the service is marked "guest only = yes" then
+ steps 1 to 5 are skipped.</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+>If the client has passed a username/password
+ pair and that username/password pair is validated by the UNIX
+ system's password programs then the connection is made as that
+ username. Note that this includes the
+ \\server\service%<TT
+CLASS="REPLACEABLE"
+><I
+>username</I
+></TT
+> method of passing
+ a username.</P
+></LI
+><LI
+><P
+>If the client has previously registered a username
+ with the system and now supplies a correct password for that
+ username then the connection is allowed.</P
+></LI
+><LI
+><P
+>The client's NetBIOS name and any previously
+ used user names are checked against the supplied password, if
+ they match then the connection is allowed as the corresponding
+ user.</P
+></LI
+><LI
+><P
+>If the client has previously validated a
+ username/password pair with the server and the client has passed
+ the validation token then that username is used. </P
+></LI
+><LI
+><P
+>If a "user = " field is given in the
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file for the service and the client
+ has supplied a password, and that password matches (according to
+ the UNIX system's password checking) with one of the usernames
+ from the "user =" field then the connection is made as
+ the username in the "user =" line. If one
+ of the username in the "user =" list begins with a
+ '@' then that name expands to a list of names in
+ the group of the same name.</P
+></LI
+><LI
+><P
+>If the service is a guest service then a
+ connection is made as the username given in the "guest
+ account =" for the service, irrespective of the
+ supplied password.</P
+></LI
+></OL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN254"
+></A
+><H2
+>COMPLETE LIST OF GLOBAL PARAMETERS</H2
+><P
+>Here is a list of all global parameters. See the section of
+ each parameter for details. Note that some are synonyms.</P
+><P
+></P
+><UL
+><LI
+><P
+><A
+HREF="#ABORTSHUTDOWNSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>abort shutdown script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ADDPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>add printer command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ADDSHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>add share command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ADDUSERSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ADDMACHINESCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>add machine script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ALLOWTRUSTEDDOMAINS"
+><TT
+CLASS="PARAMETER"
+><I
+>allow trusted domains</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ANNOUNCEAS"
+><TT
+CLASS="PARAMETER"
+><I
+>announce as</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ANNOUNCEVERSION"
+><TT
+CLASS="PARAMETER"
+><I
+>announce version</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#AUTOSERVICES"
+><TT
+CLASS="PARAMETER"
+><I
+>auto services</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#BINDINTERFACESONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>bind interfaces only</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#BROWSELIST"
+><TT
+CLASS="PARAMETER"
+><I
+>browse list</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CHANGENOTIFYTIMEOUT"
+><TT
+CLASS="PARAMETER"
+><I
+>change notify timeout</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CHANGESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>change share command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CHARACTERSET"
+><TT
+CLASS="PARAMETER"
+><I
+>character set</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CLIENTCODEPAGE"
+><TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CODEPAGEDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>code page directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CODINGSYSTEM"
+><TT
+CLASS="PARAMETER"
+><I
+>coding system</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CONFIGFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>config file</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEADTIME"
+><TT
+CLASS="PARAMETER"
+><I
+>deadtime</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEBUGHIRESTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+>debug hires timestamp</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEBUGPID"
+><TT
+CLASS="PARAMETER"
+><I
+>debug pid</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEBUGTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+>debug timestamp</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEBUGUID"
+><TT
+CLASS="PARAMETER"
+><I
+>debug uid</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEBUGLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>debuglevel</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEFAULT"
+><TT
+CLASS="PARAMETER"
+><I
+>default</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEFAULTSERVICE"
+><TT
+CLASS="PARAMETER"
+><I
+>default service</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DELETEPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>delete printer command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DELETESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>delete share command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DELETEUSERSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>delete user script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DFREECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>dfree command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DISABLESPOOLSS"
+><TT
+CLASS="PARAMETER"
+><I
+>disable spoolss</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DNSPROXY"
+><TT
+CLASS="PARAMETER"
+><I
+>dns proxy</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOMAINADMINGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>domain admin group</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOMAINGUESTGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>domain guest group</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOMAINLOGONS"
+><TT
+CLASS="PARAMETER"
+><I
+>domain logons</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOMAINMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+>domain master</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypt passwords</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ENHANCEDBROWSING"
+><TT
+CLASS="PARAMETER"
+><I
+>enhanced browsing</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ENUMPORTSCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>enumports command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#GETWDCACHE"
+><TT
+CLASS="PARAMETER"
+><I
+>getwd cache</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HIDELOCALUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>hide local users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HIDEUNREADABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>hide unreadable</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HOMEDIRMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>homedir map</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HOSTMSDFS"
+><TT
+CLASS="PARAMETER"
+><I
+>host msdfs</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HOSTSEQUIV"
+><TT
+CLASS="PARAMETER"
+><I
+>hosts equiv</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#INTERFACES"
+><TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#KEEPALIVE"
+><TT
+CLASS="PARAMETER"
+><I
+>keepalive</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#KERNELOPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>kernel oplocks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LANMANAUTH"
+><TT
+CLASS="PARAMETER"
+><I
+>lanman auth</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LARGEREADWRITE"
+><TT
+CLASS="PARAMETER"
+><I
+>large readwrite</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPADMINDN"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap admin dn</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPFILTER"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap filter</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap port</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap server</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPSSL"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap ssl</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LDAPSUFFIX"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap suffix</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LMANNOUNCE"
+><TT
+CLASS="PARAMETER"
+><I
+>lm announce</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LMINTERVAL"
+><TT
+CLASS="PARAMETER"
+><I
+>lm interval</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOADPRINTERS"
+><TT
+CLASS="PARAMETER"
+><I
+>load printers</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOCALMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+>local master</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOCKDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>lock dir</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOCKDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>lock directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>log file</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>log level</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGONDRIVE"
+><TT
+CLASS="PARAMETER"
+><I
+>logon drive</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGONHOME"
+><TT
+CLASS="PARAMETER"
+><I
+>logon home</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGONPATH"
+><TT
+CLASS="PARAMETER"
+><I
+>logon path</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOGONSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>logon script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LPQCACHETIME"
+><TT
+CLASS="PARAMETER"
+><I
+>lpq cache time</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MACHINEPASSWORDTIMEOUT"
+><TT
+CLASS="PARAMETER"
+><I
+>machine password timeout</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MANGLEDSTACK"
+><TT
+CLASS="PARAMETER"
+><I
+>mangled stack</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAPTOGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>map to guest</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXDISKSIZE"
+><TT
+CLASS="PARAMETER"
+><I
+>max disk size</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXLOGSIZE"
+><TT
+CLASS="PARAMETER"
+><I
+>max log size</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXMUX"
+><TT
+CLASS="PARAMETER"
+><I
+>max mux</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXOPENFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>max open files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXPROTOCOL"
+><TT
+CLASS="PARAMETER"
+><I
+>max protocol</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXSMBDPROCESSES"
+><TT
+CLASS="PARAMETER"
+><I
+>max smbd processes</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXTTL"
+><TT
+CLASS="PARAMETER"
+><I
+>max ttl</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXWINSTTL"
+><TT
+CLASS="PARAMETER"
+><I
+>max wins ttl</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXXMIT"
+><TT
+CLASS="PARAMETER"
+><I
+>max xmit</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MESSAGECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>message command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MINPASSWDLENGTH"
+><TT
+CLASS="PARAMETER"
+><I
+>min passwd length</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MINPASSWORDLENGTH"
+><TT
+CLASS="PARAMETER"
+><I
+>min password length</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MINPROTOCOL"
+><TT
+CLASS="PARAMETER"
+><I
+>min protocol</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MINWINSTTL"
+><TT
+CLASS="PARAMETER"
+><I
+>min wins ttl</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NAMERESOLVEORDER"
+><TT
+CLASS="PARAMETER"
+><I
+>name resolve order</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NETBIOSALIASES"
+><TT
+CLASS="PARAMETER"
+><I
+>netbios aliases</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NETBIOSNAME"
+><TT
+CLASS="PARAMETER"
+><I
+>netbios name</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NETBIOSSCOPE"
+><TT
+CLASS="PARAMETER"
+><I
+>netbios scope</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NISHOMEDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>nis homedir</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NTPIPESUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+>nt pipe support</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NTSMBSUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+>nt smb support</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NULLPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>null passwords</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OBEYPAMRESTRICTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>obey pam restrictions</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OPLOCKBREAKWAITTIME"
+><TT
+CLASS="PARAMETER"
+><I
+>oplock break wait time</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OSLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>os level</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OS2DRIVERMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>os2 driver map</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PAMPASSWORDCHANGE"
+><TT
+CLASS="PARAMETER"
+><I
+>pam password change</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PANICACTION"
+><TT
+CLASS="PARAMETER"
+><I
+>panic action</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PASSWDCHAT"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd chat</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PASSWDCHATDEBUG"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd chat debug</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PASSWORDLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PASSWORDSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PREFEREDMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+>prefered master</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PREFERREDMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+>preferred master</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRELOAD"
+><TT
+CLASS="PARAMETER"
+><I
+>preload</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTCAP"
+><TT
+CLASS="PARAMETER"
+><I
+>printcap</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTCAPNAME"
+><TT
+CLASS="PARAMETER"
+><I
+>printcap name</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTERDRIVERFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver file</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PROTOCOL"
+><TT
+CLASS="PARAMETER"
+><I
+>protocol</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#READBMPX"
+><TT
+CLASS="PARAMETER"
+><I
+>read bmpx</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#READRAW"
+><TT
+CLASS="PARAMETER"
+><I
+>read raw</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#READSIZE"
+><TT
+CLASS="PARAMETER"
+><I
+>read size</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#REMOTEANNOUNCE"
+><TT
+CLASS="PARAMETER"
+><I
+>remote announce</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#REMOTEBROWSESYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>remote browse sync</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#RESTRICTANONYMOUS"
+><TT
+CLASS="PARAMETER"
+><I
+>restrict anonymous</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOT"
+><TT
+CLASS="PARAMETER"
+><I
+>root</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOTDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>root dir</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOTDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>root directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+>security</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SERVERSTRING"
+><TT
+CLASS="PARAMETER"
+><I
+>server string</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SHOWADDPRINTERWIZARD"
+><TT
+CLASS="PARAMETER"
+><I
+>show add printer wizard</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SHUTDOWNSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>shutdown script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SMBPASSWDFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>smb passwd file</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SOCKETADDRESS"
+><TT
+CLASS="PARAMETER"
+><I
+>socket address</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SOCKETOPTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>socket options</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SOURCEENVIRONMENT"
+><TT
+CLASS="PARAMETER"
+><I
+>source environment</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSL"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCACERTDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl CA certDir</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCACERTFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl CA certFile</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCIPHERS"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl ciphers</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCLIENTCERT"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl client cert</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCLIENTKEY"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl client key</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLCOMPATIBILITY"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl compatibility</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLEGDSOCKET"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl egd socket</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLENTROPYBYTES"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl entropy bytes</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLENTROPYFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl entropy file</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLHOSTS"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl hosts</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLHOSTSRESIGN"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl hosts resign</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLREQUIRECLIENTCERT"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl require clientcert</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLREQUIRESERVERCERT"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl require servercert</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLSERVERCERT"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl server cert</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLSERVERKEY"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl server key</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SSLVERSION"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl version</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STATCACHE"
+><TT
+CLASS="PARAMETER"
+><I
+>stat cache</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STATCACHESIZE"
+><TT
+CLASS="PARAMETER"
+><I
+>stat cache size</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STRIPDOT"
+><TT
+CLASS="PARAMETER"
+><I
+>strip dot</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SYSLOG"
+><TT
+CLASS="PARAMETER"
+><I
+>syslog</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SYSLOGONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>syslog only</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TEMPLATEHOMEDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>template homedir</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TEMPLATESHELL"
+><TT
+CLASS="PARAMETER"
+><I
+>template shell</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TIMEOFFSET"
+><TT
+CLASS="PARAMETER"
+><I
+>time offset</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TIMESERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>time server</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TIMESTAMPLOGS"
+><TT
+CLASS="PARAMETER"
+><I
+>timestamp logs</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#TOTALPRINTJOBS"
+><TT
+CLASS="PARAMETER"
+><I
+>total print jobs</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#UNIXPASSWORDSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>unix password sync</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#UPDATEENCRYPTED"
+><TT
+CLASS="PARAMETER"
+><I
+>update encrypted</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USEMMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>use mmap</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USERHOSTS"
+><TT
+CLASS="PARAMETER"
+><I
+>use rhosts</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USERNAMELEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>username level</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USERNAMEMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>username map</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#UTMP"
+><TT
+CLASS="PARAMETER"
+><I
+>utmp</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#UTMPDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>utmp directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VALIDCHARS"
+><TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDCACHETIME"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind cache time</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDENUMUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind enum users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDENUMGROUPS"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind enum groups</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDGID"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind gid</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDSEPARATOR"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind separator</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINBINDUID"
+><TT
+CLASS="PARAMETER"
+><I
+>winbind uid</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINSHOOK"
+><TT
+CLASS="PARAMETER"
+><I
+>wins hook</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINSPROXY"
+><TT
+CLASS="PARAMETER"
+><I
+>wins proxy</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINSSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>wins server</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WINSSUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+>wins support</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WORKGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITERAW"
+><TT
+CLASS="PARAMETER"
+><I
+>write raw</I
+></TT
+></A
+></P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN970"
+></A
+><H2
+>COMPLETE LIST OF SERVICE PARAMETERS</H2
+><P
+>Here is a list of all service parameters. See the section on
+ each parameter for details. Note that some are synonyms.</P
+><P
+></P
+><UL
+><LI
+><P
+><A
+HREF="#ADMINUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>admin users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ALLOWHOSTS"
+><TT
+CLASS="PARAMETER"
+><I
+>allow hosts</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#AVAILABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>available</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#BLOCKINGLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>blocking locks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#BROWSABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>browsable</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#BROWSEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>browseable</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CASESENSITIVE"
+><TT
+CLASS="PARAMETER"
+><I
+>case sensitive</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CASESIGNAMES"
+><TT
+CLASS="PARAMETER"
+><I
+>casesignames</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#COMMENT"
+><TT
+CLASS="PARAMETER"
+><I
+>comment</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#COPY"
+><TT
+CLASS="PARAMETER"
+><I
+>copy</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CREATEMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#CREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>create mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DEFAULTCASE"
+><TT
+CLASS="PARAMETER"
+><I
+>default case</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DELETEREADONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>delete readonly</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DELETEVETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>delete veto files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DENYHOSTS"
+><TT
+CLASS="PARAMETER"
+><I
+>deny hosts</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DIRECTORYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory mask</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>directory mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DONTDESCEND"
+><TT
+CLASS="PARAMETER"
+><I
+>dont descend</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOSFILEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>dos filemode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOSFILETIMERESOLUTION"
+><TT
+CLASS="PARAMETER"
+><I
+>dos filetime resolution</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#DOSFILETIMES"
+><TT
+CLASS="PARAMETER"
+><I
+>dos filetimes</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#EXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>exec</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FAKEDIRECTORYCREATETIMES"
+><TT
+CLASS="PARAMETER"
+><I
+>fake directory create times</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FAKEOPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>fake oplocks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FOLLOWSYMLINKS"
+><TT
+CLASS="PARAMETER"
+><I
+>follow symlinks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCECREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCEDIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCEDIRECTORYSECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force directory security mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCEGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>force group</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCESECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FORCEUSER"
+><TT
+CLASS="PARAMETER"
+><I
+>force user</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#FSTYPE"
+><TT
+CLASS="PARAMETER"
+><I
+>fstype</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#GROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>group</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#GUESTOK"
+><TT
+CLASS="PARAMETER"
+><I
+>guest ok</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#GUESTONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>guest only</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HIDEDOTFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>hide dot files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HIDEFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>hide files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HOSTSALLOW"
+><TT
+CLASS="PARAMETER"
+><I
+>hosts allow</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#HOSTSDENY"
+><TT
+CLASS="PARAMETER"
+><I
+>hosts deny</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#INCLUDE"
+><TT
+CLASS="PARAMETER"
+><I
+>include</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#INHERITPERMISSIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>inherit permissions</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#INVALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>invalid users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LEVEL2OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>level2 oplocks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LOCKING"
+><TT
+CLASS="PARAMETER"
+><I
+>locking</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LPPAUSECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>lppause command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LPQCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>lpq command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LPRESUMECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>lpresume command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#LPRMCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>lprm command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAGICOUTPUT"
+><TT
+CLASS="PARAMETER"
+><I
+>magic output</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAGICSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>magic script</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MANGLECASE"
+><TT
+CLASS="PARAMETER"
+><I
+>mangle case</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MANGLEDMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>mangled map</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MANGLEDNAMES"
+><TT
+CLASS="PARAMETER"
+><I
+>mangled names</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MANGLINGCHAR"
+><TT
+CLASS="PARAMETER"
+><I
+>mangling char</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAPARCHIVE"
+><TT
+CLASS="PARAMETER"
+><I
+>map archive</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAPHIDDEN"
+><TT
+CLASS="PARAMETER"
+><I
+>map hidden</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAPSYSTEM"
+><TT
+CLASS="PARAMETER"
+><I
+>map system</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXCONNECTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>max connections</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MAXPRINTJOBS"
+><TT
+CLASS="PARAMETER"
+><I
+>max print jobs</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MINPRINTSPACE"
+><TT
+CLASS="PARAMETER"
+><I
+>min print space</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#MSDFSROOT"
+><TT
+CLASS="PARAMETER"
+><I
+>msdfs root</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#NTACLSUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+>nt acl support</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ONLYGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>only guest</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ONLYUSER"
+><TT
+CLASS="PARAMETER"
+><I
+>only user</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OPLOCKCONTENTIONLIMIT"
+><TT
+CLASS="PARAMETER"
+><I
+>oplock contention limit</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PATH"
+><TT
+CLASS="PARAMETER"
+><I
+>path</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#POSIXLOCKING"
+><TT
+CLASS="PARAMETER"
+><I
+>posix locking</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#POSTEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>postexec</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#POSTSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>postscript</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>preexec</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PREEXECCLOSE"
+><TT
+CLASS="PARAMETER"
+><I
+>preexec close</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRESERVECASE"
+><TT
+CLASS="PARAMETER"
+><I
+>preserve case</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>print command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTOK"
+><TT
+CLASS="PARAMETER"
+><I
+>print ok</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>printable</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTER"
+><TT
+CLASS="PARAMETER"
+><I
+>printer</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTERADMIN"
+><TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTERDRIVER"
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTERDRIVERLOCATION"
+><TT
+CLASS="PARAMETER"
+><I
+>printer driver location</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTERNAME"
+><TT
+CLASS="PARAMETER"
+><I
+>printer name</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#PUBLIC"
+><TT
+CLASS="PARAMETER"
+><I
+>public</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#QUEUEPAUSECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>queuepause command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#QUEUERESUMECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>queueresume command</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#READLIST"
+><TT
+CLASS="PARAMETER"
+><I
+>read list</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#READONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>read only</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOTPOSTEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>root postexec</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOTPREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>root preexec</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#ROOTPREEXECCLOSE"
+><TT
+CLASS="PARAMETER"
+><I
+>root preexec close</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SETDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>set directory</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SHORTPRESERVECASE"
+><TT
+CLASS="PARAMETER"
+><I
+>short preserve case</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STATUS"
+><TT
+CLASS="PARAMETER"
+><I
+>status</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STRICTALLOCATE"
+><TT
+CLASS="PARAMETER"
+><I
+>strict allocate</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STRICTLOCKING"
+><TT
+CLASS="PARAMETER"
+><I
+>strict locking</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#STRICTSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>strict sync</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#SYNCALWAYS"
+><TT
+CLASS="PARAMETER"
+><I
+>sync always</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USECLIENTDRIVER"
+><TT
+CLASS="PARAMETER"
+><I
+>use client driver</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USER"
+><TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USERNAME"
+><TT
+CLASS="PARAMETER"
+><I
+>username</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#USERS"
+><TT
+CLASS="PARAMETER"
+><I
+>users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>valid users</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>veto files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VETOOPLOCKFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>veto oplock files</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VFSOBJECT"
+><TT
+CLASS="PARAMETER"
+><I
+>vfs object</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VFSOPTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>vfs options</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#VOLUME"
+><TT
+CLASS="PARAMETER"
+><I
+>volume</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WIDELINKS"
+><TT
+CLASS="PARAMETER"
+><I
+>wide links</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writable</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITECACHESIZE"
+><TT
+CLASS="PARAMETER"
+><I
+>write cache size</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITELIST"
+><TT
+CLASS="PARAMETER"
+><I
+>write list</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITEOK"
+><TT
+CLASS="PARAMETER"
+><I
+>write ok</I
+></TT
+></A
+></P
+></LI
+><LI
+><P
+><A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writeable</I
+></TT
+></A
+></P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN1446"
+></A
+><H2
+>EXPLANATION OF EACH PARAMETER</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><A
+NAME="ABORTSHUTDOWNSCRIPT"
+></A
+>abort shutdown script (G)</DT
+><DD
+><P
+><EM
+>This parameter only exists in the HEAD cvs branch</EM
+>
+ This a full path name to a script called by
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> that
+ should stop a shutdown procedure issued by the <A
+HREF="#SHUTDOWNSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>shutdown script</I
+></TT
+></A
+>.</P
+><P
+>This command will be run as user.</P
+><P
+>Default: <EM
+>None</EM
+>.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>abort shutdown script = /sbin/shutdown -c</B
+></P
+></DD
+><DT
+><A
+NAME="ADDPRINTERCOMMAND"
+></A
+>add printer command (G)</DT
+><DD
+><P
+>With the introduction of MS-RPC based printing
+ support for Windows NT/2000 clients in Samba 2.2, The MS Add
+ Printer Wizard (APW) icon is now also available in the
+ "Printers..." folder displayed a share listing. The APW
+ allows for printers to be add remotely to a Samba or Windows
+ NT/2000 print server.</P
+><P
+>For a Samba host this means that the printer must be
+ physically added to the underlying printing system. The <TT
+CLASS="PARAMETER"
+><I
+>add
+ printer command</I
+></TT
+> defines a script to be run which
+ will perform the necessary operations for adding the printer
+ to the print system and to add the appropriate service definition
+ to the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file in order that it can be
+ shared by <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+>
+ </A
+>.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>add printer command</I
+></TT
+> is
+ automatically invoked with the following parameter (in
+ order:</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>printer name</I
+></TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>share name</I
+></TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>port name</I
+></TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>driver name</I
+></TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>location</I
+></TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>Windows 9x driver location</I
+></TT
+>
+ </P
+></LI
+></UL
+><P
+>All parameters are filled in from the PRINTER_INFO_2 structure sent
+ by the Windows NT/2000 client with one exception. The "Windows 9x
+ driver location" parameter is included for backwards compatibility
+ only. The remaining fields in the structure are generated from answers
+ to the APW questions.</P
+><P
+>Once the <TT
+CLASS="PARAMETER"
+><I
+>add printer command</I
+></TT
+> has
+ been executed, <B
+CLASS="COMMAND"
+>smbd</B
+> will reparse the <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> to determine if the share defined by the APW
+ exists. If the sharename is still invalid, then <B
+CLASS="COMMAND"
+>smbd
+ </B
+> will return an ACCESS_DENIED error to the client.</P
+><P
+>See also <A
+HREF="#DELETEPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+> delete printer command</I
+></TT
+></A
+>, <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+></A
+>,
+ <A
+HREF="#SHOWADDPRINTERWIZARD"
+><TT
+CLASS="PARAMETER"
+><I
+>show add
+ printer wizard</I
+></TT
+></A
+></P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>addprinter command = /usr/bin/addprinter
+ </B
+></P
+></DD
+><DT
+><A
+NAME="ADDSHARECOMMAND"
+></A
+>add share command (G)</DT
+><DD
+><P
+>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <TT
+CLASS="PARAMETER"
+><I
+>add share command</I
+></TT
+> is used to define an
+ external program or script which will add a new service definition
+ to <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>. In order to successfully
+ execute the <TT
+CLASS="PARAMETER"
+><I
+>add share command</I
+></TT
+>, <B
+CLASS="COMMAND"
+>smbd</B
+>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </P
+><P
+> When executed, <B
+CLASS="COMMAND"
+>smbd</B
+> will automatically invoke the
+ <TT
+CLASS="PARAMETER"
+><I
+>add share command</I
+></TT
+> with four parameters.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>configFile</I
+></TT
+> - the location
+ of the global <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>shareName</I
+></TT
+> - the name of the new
+ share.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>pathName</I
+></TT
+> - path to an **existing**
+ directory on disk.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>comment</I
+></TT
+> - comment string to associate
+ with the new share.
+ </P
+></LI
+></UL
+><P
+> This parameter is only used for add file shares. To add printer shares,
+ see the <A
+HREF="#ADDPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>add printer
+ command</I
+></TT
+></A
+>.
+ </P
+><P
+> See also <A
+HREF="#CHANGESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>change share
+ command</I
+></TT
+></A
+>, <A
+HREF="#DELETESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>delete share
+ command</I
+></TT
+></A
+>.
+ </P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>add share command = /usr/local/bin/addshare</B
+></P
+></DD
+><DT
+><A
+NAME="ADDMACHINESCRIPT"
+></A
+>add machine script (G)</DT
+><DD
+><P
+>This is the full pathname to a script that will
+ be run by <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> when a machine is added
+ to it's domain using the administrator username and password method. </P
+><P
+>This option is only required when using sam back-ends tied to the
+ Unix uid method of RID calculation such as smbpasswd. This option is only
+ available in Samba 3.0.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>add machine script = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
+ </B
+></P
+></DD
+><DT
+><A
+NAME="ADDUSERSCRIPT"
+></A
+>add user script (G)</DT
+><DD
+><P
+>This is the full pathname to a script that will
+ be run <EM
+>AS ROOT</EM
+> by <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)
+ </A
+> under special circumstances described below.</P
+><P
+>Normally, a Samba server requires that UNIX users are
+ created for all users accessing files on this server. For sites
+ that use Windows NT account databases as their primary user database
+ creating these users and keeping the user list in sync with the
+ Windows NT PDC is an onerous task. This option allows <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> to create the required UNIX users
+ <EM
+>ON DEMAND</EM
+> when a user accesses the Samba server.</P
+><P
+>In order to use this option, <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+>
+ must be set to <TT
+CLASS="PARAMETER"
+><I
+>security = server</I
+></TT
+> or <TT
+CLASS="PARAMETER"
+><I
+> security = domain</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+>
+ must be set to a full pathname for a script that will create a UNIX
+ user given one argument of <TT
+CLASS="PARAMETER"
+><I
+>%u</I
+></TT
+>, which expands into
+ the UNIX user name to create.</P
+><P
+>When the Windows user attempts to access the Samba server,
+ at login (session setup in the SMB protocol) time, <A
+HREF="smbd.8.html"
+TARGET="_top"
+> smbd</A
+> contacts the <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+> and
+ attempts to authenticate the given user with the given password. If the
+ authentication succeeds then <B
+CLASS="COMMAND"
+>smbd</B
+>
+ attempts to find a UNIX user in the UNIX password database to map the
+ Windows user into. If this lookup fails, and <TT
+CLASS="PARAMETER"
+><I
+>add user script
+ </I
+></TT
+> is set then <B
+CLASS="COMMAND"
+>smbd</B
+> will
+ call the specified script <EM
+>AS ROOT</EM
+>, expanding
+ any <TT
+CLASS="PARAMETER"
+><I
+>%u</I
+></TT
+> argument to be the user name to create.</P
+><P
+>If this script successfully creates the user then <B
+CLASS="COMMAND"
+>smbd
+ </B
+> will continue on as though the UNIX user
+ already existed. In this way, UNIX users are dynamically created to
+ match existing Windows NT accounts.</P
+><P
+>See also <A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+> security</I
+></TT
+></A
+>, <A
+HREF="#PASSWORDSERVER"
+> <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+></A
+>,
+ <A
+HREF="#DELETEUSERSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>delete user
+ script</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>add user script = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>add user script = /usr/local/samba/bin/add_user
+ %u</B
+></P
+></DD
+><DT
+><A
+NAME="ADMINUSERS"
+></A
+>admin users (S)</DT
+><DD
+><P
+>This is a list of users who will be granted
+ administrative privileges on the share. This means that they
+ will do all file operations as the super-user (root).</P
+><P
+>You should use this option very carefully, as any user in
+ this list will be able to do anything they like on the share,
+ irrespective of file permissions.</P
+><P
+>Default: <EM
+>no admin users</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>admin users = jason</B
+></P
+></DD
+><DT
+><A
+NAME="ALLOWHOSTS"
+></A
+>allow hosts (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#HOSTSALLOW"
+> <TT
+CLASS="PARAMETER"
+><I
+>hosts allow</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="ALLOWTRUSTEDDOMAINS"
+></A
+>allow trusted domains (G)</DT
+><DD
+><P
+>This option only takes effect when the <A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+>security</I
+></TT
+></A
+> option is set to
+ <TT
+CLASS="CONSTANT"
+>server</TT
+> or <TT
+CLASS="CONSTANT"
+>domain</TT
+>.
+ If it is set to no, then attempts to connect to a resource from
+ a domain or workgroup other than the one which <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> is running
+ in will fail, even if that domain is trusted by the remote server
+ doing the authentication.</P
+><P
+>This is useful if you only want your Samba server to
+ serve resources to users in the domain it is a member of. As
+ an example, suppose that there are two domains DOMA and DOMB. DOMB
+ is trusted by DOMA, which contains the Samba server. Under normal
+ circumstances, a user with an account in DOMB can then access the
+ resources of a UNIX account with the same account name on the
+ Samba server even if they do not have an account in DOMA. This
+ can make implementing a security boundary difficult.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>allow trusted domains = yes</B
+></P
+></DD
+><DT
+><A
+NAME="ANNOUNCEAS"
+></A
+>announce as (G)</DT
+><DD
+><P
+>This specifies what type of server
+ <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd</B
+></A
+>
+ will announce itself as, to a network neighborhood browse
+ list. By default this is set to Windows NT. The valid options
+ are : "NT Server" (which can also be written as "NT"),
+ "NT Workstation", "Win95" or "WfW" meaning Windows NT Server,
+ Windows NT Workstation, Windows 95 and Windows for Workgroups
+ respectively. Do not change this parameter unless you have a
+ specific need to stop Samba appearing as an NT server as this
+ may prevent Samba servers from participating as browser servers
+ correctly.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>announce as = NT Server</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>announce as = Win95</B
+></P
+></DD
+><DT
+><A
+NAME="ANNOUNCEVERSION"
+></A
+>announce version (G)</DT
+><DD
+><P
+>This specifies the major and minor version numbers
+ that nmbd will use when announcing itself as a server. The default
+ is 4.2. Do not change this parameter unless you have a specific
+ need to set a Samba server to be a downlevel server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>announce version = 4.5</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>announce version = 2.0</B
+></P
+></DD
+><DT
+><A
+NAME="AUTOSERVICES"
+></A
+>auto services (G)</DT
+><DD
+><P
+>This is a synonym for the <A
+HREF="#PRELOAD"
+> <TT
+CLASS="PARAMETER"
+><I
+>preload</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="AVAILABLE"
+></A
+>available (S)</DT
+><DD
+><P
+>This parameter lets you "turn off" a service. If
+ <TT
+CLASS="PARAMETER"
+><I
+>available = no</I
+></TT
+>, then <EM
+>ALL</EM
+>
+ attempts to connect to the service will fail. Such failures are
+ logged.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>available = yes</B
+></P
+></DD
+><DT
+><A
+NAME="BINDINTERFACESONLY"
+></A
+>bind interfaces only (G)</DT
+><DD
+><P
+>This global parameter allows the Samba admin
+ to limit what interfaces on a machine will serve SMB requests. If
+ affects file service <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> and
+ name service <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> in slightly
+ different ways.</P
+><P
+>For name service it causes <B
+CLASS="COMMAND"
+>nmbd</B
+> to bind
+ to ports 137 and 138 on the interfaces listed in the <A
+HREF="#INTERFACES"
+>interfaces</A
+> parameter. <B
+CLASS="COMMAND"
+>nmbd
+ </B
+> also binds to the "all addresses" interface (0.0.0.0)
+ on ports 137 and 138 for the purposes of reading broadcast messages.
+ If this option is not set then <B
+CLASS="COMMAND"
+>nmbd</B
+> will service
+ name requests on all of these sockets. If <TT
+CLASS="PARAMETER"
+><I
+>bind interfaces
+ only</I
+></TT
+> is set then <B
+CLASS="COMMAND"
+>nmbd</B
+> will check the
+ source address of any packets coming in on the broadcast sockets
+ and discard any that don't match the broadcast addresses of the
+ interfaces in the <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+> parameter list.
+ As unicast packets are received on the other sockets it allows
+ <B
+CLASS="COMMAND"
+>nmbd</B
+> to refuse to serve names to machines that
+ send packets that arrive through any interfaces not listed in the
+ <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+> list. IP Source address spoofing
+ does defeat this simple check, however so it must not be used
+ seriously as a security feature for <B
+CLASS="COMMAND"
+>nmbd</B
+>.</P
+><P
+>For file service it causes <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+>
+ to bind only to the interface list given in the <A
+HREF="#INTERFACES"
+> interfaces</A
+> parameter. This restricts the networks that
+ <B
+CLASS="COMMAND"
+>smbd</B
+> will serve to packets coming in those
+ interfaces. Note that you should not use this parameter for machines
+ that are serving PPP or other intermittent or non-broadcast network
+ interfaces as it will not cope with non-permanent interfaces.</P
+><P
+>If <TT
+CLASS="PARAMETER"
+><I
+>bind interfaces only</I
+></TT
+> is set then
+ unless the network address <EM
+>127.0.0.1</EM
+> is added
+ to the <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+> parameter list <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+>
+ and <A
+HREF="swat.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>swat(8)</B
+></A
+> may
+ not work as expected due to the reasons covered below.</P
+><P
+>To change a users SMB password, the <B
+CLASS="COMMAND"
+>smbpasswd</B
+>
+ by default connects to the <EM
+>localhost - 127.0.0.1</EM
+>
+ address as an SMB client to issue the password change request. If
+ <TT
+CLASS="PARAMETER"
+><I
+>bind interfaces only</I
+></TT
+> is set then unless the
+ network address <EM
+>127.0.0.1</EM
+> is added to the
+ <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+> parameter list then <B
+CLASS="COMMAND"
+> smbpasswd</B
+> will fail to connect in it's default mode.
+ <B
+CLASS="COMMAND"
+>smbpasswd</B
+> can be forced to use the primary IP interface
+ of the local host by using its <A
+HREF="smbpasswd.8.html#minusr"
+TARGET="_top"
+> <TT
+CLASS="PARAMETER"
+><I
+>-r <TT
+CLASS="REPLACEABLE"
+><I
+>remote machine</I
+></TT
+></I
+></TT
+>
+ </A
+> parameter, with <TT
+CLASS="REPLACEABLE"
+><I
+>remote machine</I
+></TT
+> set
+ to the IP name of the primary interface of the local host.</P
+><P
+>The <B
+CLASS="COMMAND"
+>swat</B
+> status page tries to connect with
+ <B
+CLASS="COMMAND"
+>smbd</B
+> and <B
+CLASS="COMMAND"
+>nmbd</B
+> at the address
+ <EM
+>127.0.0.1</EM
+> to determine if they are running.
+ Not adding <EM
+>127.0.0.1</EM
+> will cause <B
+CLASS="COMMAND"
+> smbd</B
+> and <B
+CLASS="COMMAND"
+>nmbd</B
+> to always show
+ "not running" even if they really are. This can prevent <B
+CLASS="COMMAND"
+> swat</B
+> from starting/stopping/restarting <B
+CLASS="COMMAND"
+>smbd</B
+>
+ and <B
+CLASS="COMMAND"
+>nmbd</B
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>bind interfaces only = no</B
+></P
+></DD
+><DT
+><A
+NAME="BLOCKINGLOCKS"
+></A
+>blocking locks (S)</DT
+><DD
+><P
+>This parameter controls the behavior of <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> when given a request by a client
+ to obtain a byte range lock on a region of an open file, and the
+ request has a time limit associated with it.</P
+><P
+>If this parameter is set and the lock range requested
+ cannot be immediately satisfied, Samba 2.2 will internally
+ queue the lock request, and periodically attempt to obtain
+ the lock until the timeout period expires.</P
+><P
+>If this parameter is set to <TT
+CLASS="CONSTANT"
+>false</TT
+>, then
+ Samba 2.2 will behave as previous versions of Samba would and
+ will fail the lock request immediately if the lock range
+ cannot be obtained.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>blocking locks = yes</B
+></P
+></DD
+><DT
+><A
+NAME="BROWSABLE"
+></A
+>browsable (S)</DT
+><DD
+><P
+>See the <A
+HREF="#BROWSEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+> browseable</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="BROWSELIST"
+></A
+>browse list (G)</DT
+><DD
+><P
+>This controls whether <A
+HREF="smbd.8.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> will serve a browse list to
+ a client doing a <B
+CLASS="COMMAND"
+>NetServerEnum</B
+> call. Normally
+ set to <TT
+CLASS="CONSTANT"
+>true</TT
+>. You should never need to change
+ this.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>browse list = yes</B
+></P
+></DD
+><DT
+><A
+NAME="BROWSEABLE"
+></A
+>browseable (S)</DT
+><DD
+><P
+>This controls whether this share is seen in
+ the list of available shares in a net view and in the browse list.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>browseable = yes</B
+></P
+></DD
+><DT
+><A
+NAME="CASESENSITIVE"
+></A
+>case sensitive (S)</DT
+><DD
+><P
+>See the discussion in the section <A
+HREF="#AEN202"
+>NAME MANGLING</A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>case sensitive = no</B
+></P
+></DD
+><DT
+><A
+NAME="CASESIGNAMES"
+></A
+>casesignames (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#CASESENSITIVE"
+>case
+ sensitive</A
+>.</P
+></DD
+><DT
+><A
+NAME="CHANGENOTIFYTIMEOUT"
+></A
+>change notify timeout (G)</DT
+><DD
+><P
+>This SMB allows a client to tell a server to
+ "watch" a particular directory for any changes and only reply to
+ the SMB request when a change has occurred. Such constant scanning of
+ a directory is expensive under UNIX, hence an <A
+HREF="smbd.8.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> daemon only performs such a scan
+ on each requested directory once every <TT
+CLASS="PARAMETER"
+><I
+>change notify
+ timeout</I
+></TT
+> seconds.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>change notify timeout = 60</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>change notify timeout = 300</B
+></P
+><P
+>Would change the scan time to every 5 minutes.</P
+></DD
+><DT
+><A
+NAME="CHANGESHARECOMMAND"
+></A
+>change share command (G)</DT
+><DD
+><P
+>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <TT
+CLASS="PARAMETER"
+><I
+>change share command</I
+></TT
+> is used to define an
+ external program or script which will modify an existing service definition
+ in <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>. In order to successfully
+ execute the <TT
+CLASS="PARAMETER"
+><I
+>change share command</I
+></TT
+>, <B
+CLASS="COMMAND"
+>smbd</B
+>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </P
+><P
+> When executed, <B
+CLASS="COMMAND"
+>smbd</B
+> will automatically invoke the
+ <TT
+CLASS="PARAMETER"
+><I
+>change share command</I
+></TT
+> with four parameters.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>configFile</I
+></TT
+> - the location
+ of the global <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>shareName</I
+></TT
+> - the name of the new
+ share.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>pathName</I
+></TT
+> - path to an **existing**
+ directory on disk.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>comment</I
+></TT
+> - comment string to associate
+ with the new share.
+ </P
+></LI
+></UL
+><P
+> This parameter is only used modify existing file shares definitions. To modify
+ printer shares, use the "Printers..." folder as seen when browsing the Samba host.
+ </P
+><P
+> See also <A
+HREF="#ADDSHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>add share
+ command</I
+></TT
+></A
+>, <A
+HREF="#DELETESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>delete
+ share command</I
+></TT
+></A
+>.
+ </P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>change share command = /usr/local/bin/addshare</B
+></P
+></DD
+><DT
+><A
+NAME="CHARACTERSET"
+></A
+>character set (G)</DT
+><DD
+><P
+>This allows <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> to map incoming filenames
+ from a DOS Code page (see the <A
+HREF="#CLIENTCODEPAGE"
+>client
+ code page</A
+> parameter) to several built in UNIX character sets.
+ The built in code page translations are:</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>ISO8859-1</TT
+> : Western European
+ UNIX character set. The parameter <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+>
+ <EM
+>MUST</EM
+> be set to code page 850 if the
+ <TT
+CLASS="PARAMETER"
+><I
+>character set</I
+></TT
+> parameter is set to
+ <TT
+CLASS="CONSTANT"
+>ISO8859-1</TT
+> in order for the conversion to the
+ UNIX character set to be done correctly.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>ISO8859-2</TT
+> : Eastern European
+ UNIX character set. The parameter <TT
+CLASS="PARAMETER"
+><I
+>client code page
+ </I
+></TT
+> <EM
+>MUST</EM
+> be set to code page 852 if
+ the <TT
+CLASS="PARAMETER"
+><I
+> character set</I
+></TT
+> parameter is set
+ to <TT
+CLASS="CONSTANT"
+>ISO8859-2</TT
+> in order for the conversion
+ to the UNIX character set to be done correctly. </P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>ISO8859-5</TT
+> : Russian Cyrillic
+ UNIX character set. The parameter <TT
+CLASS="PARAMETER"
+><I
+>client code page
+ </I
+></TT
+> <EM
+>MUST</EM
+> be set to code page
+ 866 if the <TT
+CLASS="PARAMETER"
+><I
+>character set </I
+></TT
+> parameter is
+ set to <TT
+CLASS="CONSTANT"
+>ISO8859-5</TT
+> in order for the conversion
+ to the UNIX character set to be done correctly. </P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>ISO8859-7</TT
+> : Greek UNIX
+ character set. The parameter <TT
+CLASS="PARAMETER"
+><I
+>client code page
+ </I
+></TT
+> <EM
+>MUST</EM
+> be set to code page
+ 737 if the <TT
+CLASS="PARAMETER"
+><I
+>character set</I
+></TT
+> parameter is
+ set to <TT
+CLASS="CONSTANT"
+>ISO8859-7</TT
+> in order for the conversion
+ to the UNIX character set to be done correctly.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>KOI8-R</TT
+> : Alternate mapping
+ for Russian Cyrillic UNIX character set. The parameter
+ <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> <EM
+>MUST</EM
+>
+ be set to code page 866 if the <TT
+CLASS="PARAMETER"
+><I
+>character set</I
+></TT
+>
+ parameter is set to <TT
+CLASS="CONSTANT"
+>KOI8-R</TT
+> in order for the
+ conversion to the UNIX character set to be done correctly.</P
+></LI
+></UL
+><P
+><EM
+>BUG</EM
+>. These MSDOS code page to UNIX character
+ set mappings should be dynamic, like the loading of MS DOS code pages,
+ not static.</P
+><P
+>Normally this parameter is not set, meaning no filename
+ translation is done.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>character set = &#60;empty string&#62;</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>character set = ISO8859-1</B
+></P
+></DD
+><DT
+><A
+NAME="CLIENTCODEPAGE"
+></A
+>client code page (G)</DT
+><DD
+><P
+>This parameter specifies the DOS code page
+ that the clients accessing Samba are using. To determine what code
+ page a Windows or DOS client is using, open a DOS command prompt
+ and type the command <B
+CLASS="COMMAND"
+>chcp</B
+>. This will output
+ the code page. The default for USA MS-DOS, Windows 95, and
+ Windows NT releases is code page 437. The default for western
+ European releases of the above operating systems is code page 850.</P
+><P
+>This parameter tells <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+>
+ which of the <TT
+CLASS="FILENAME"
+>codepage.<TT
+CLASS="REPLACEABLE"
+><I
+>XXX</I
+></TT
+>
+ </TT
+> files to dynamically load on startup. These files,
+ described more fully in the manual page <A
+HREF="make_smbcodepage.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>make_smbcodepage(1)</B
+></A
+>, tell <B
+CLASS="COMMAND"
+> smbd</B
+> how to map lower to upper case characters to provide
+ the case insensitivity of filenames that Windows clients expect.</P
+><P
+>Samba currently ships with the following code page files :</P
+><P
+></P
+><UL
+><LI
+><P
+>Code Page 437 - MS-DOS Latin US</P
+></LI
+><LI
+><P
+>Code Page 737 - Windows '95 Greek</P
+></LI
+><LI
+><P
+>Code Page 850 - MS-DOS Latin 1</P
+></LI
+><LI
+><P
+>Code Page 852 - MS-DOS Latin 2</P
+></LI
+><LI
+><P
+>Code Page 861 - MS-DOS Icelandic</P
+></LI
+><LI
+><P
+>Code Page 866 - MS-DOS Cyrillic</P
+></LI
+><LI
+><P
+>Code Page 932 - MS-DOS Japanese SJIS</P
+></LI
+><LI
+><P
+>Code Page 936 - MS-DOS Simplified Chinese</P
+></LI
+><LI
+><P
+>Code Page 949 - MS-DOS Korean Hangul</P
+></LI
+><LI
+><P
+>Code Page 950 - MS-DOS Traditional Chinese</P
+></LI
+></UL
+><P
+>Thus this parameter may have any of the values 437, 737, 850, 852,
+ 861, 932, 936, 949, or 950. If you don't find the codepage you need,
+ read the comments in one of the other codepage files and the
+ <B
+CLASS="COMMAND"
+>make_smbcodepage(1)</B
+> man page and write one. Please
+ remember to donate it back to the Samba user community.</P
+><P
+>This parameter co-operates with the <TT
+CLASS="PARAMETER"
+><I
+>valid
+ chars</I
+></TT
+> parameter in determining what characters are
+ valid in filenames and how capitalization is done. If you set both
+ this parameter and the <TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+> parameter
+ the <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> parameter
+ <EM
+>MUST</EM
+> be set before the <TT
+CLASS="PARAMETER"
+><I
+>valid
+ chars</I
+></TT
+> parameter in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+ file. The <TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+> string will then
+ augment the character settings in the <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+>
+ parameter.</P
+><P
+>If not set, <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> defaults
+ to 850.</P
+><P
+>See also : <A
+HREF="#VALIDCHARS"
+><TT
+CLASS="PARAMETER"
+><I
+>valid
+ chars</I
+></TT
+></A
+>, <A
+HREF="#CODEPAGEDIRECTORY"
+> <TT
+CLASS="PARAMETER"
+><I
+>code page directory</I
+></TT
+></A
+></P
+><P
+>Default: <B
+CLASS="COMMAND"
+>client code page = 850</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>client code page = 936</B
+></P
+></DD
+><DT
+><A
+NAME="CODEPAGEDIRECTORY"
+></A
+>code page directory (G)</DT
+><DD
+><P
+>Define the location of the various client code page
+ files.</P
+><P
+>See also <A
+HREF="#CLIENTCODEPAGE"
+><TT
+CLASS="PARAMETER"
+><I
+>client
+ code page</I
+></TT
+></A
+></P
+><P
+>Default: <B
+CLASS="COMMAND"
+>code page directory = ${prefix}/lib/codepages
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>code page directory = /usr/share/samba/codepages
+ </B
+></P
+></DD
+><DT
+><A
+NAME="CODINGSYSTEM"
+></A
+>coding system (G)</DT
+><DD
+><P
+>This parameter is used to determine how incoming
+ Shift-JIS Japanese characters are mapped from the incoming <A
+HREF="#CLIENTCODEPAGE"
+><TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+>
+ </A
+> used by the client, into file names in the UNIX filesystem.
+ Only useful if <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> is set to
+ 932 (Japanese Shift-JIS). The options are :</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>SJIS</TT
+> - Shift-JIS. Does no
+ conversion of the incoming filename.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>JIS8, J8BB, J8BH, J8@B,
+ J8@J, J8@H </TT
+> - Convert from incoming Shift-JIS to eight
+ bit JIS code with different shift-in, shift out codes.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>JIS7, J7BB, J7BH, J7@B, J7@J,
+ J7@H </TT
+> - Convert from incoming Shift-JIS to seven bit
+ JIS code with different shift-in, shift out codes.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>JUNET, JUBB, JUBH, JU@B, JU@J, JU@H </TT
+>
+ - Convert from incoming Shift-JIS to JUNET code with different shift-in,
+ shift out codes.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>EUC</TT
+> - Convert an incoming
+ Shift-JIS character to EUC code.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>HEX</TT
+> - Convert an incoming
+ Shift-JIS character to a 3 byte hex representation, i.e.
+ <TT
+CLASS="CONSTANT"
+>:AB</TT
+>.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>CAP</TT
+> - Convert an incoming
+ Shift-JIS character to the 3 byte hex representation used by
+ the Columbia AppleTalk Program (CAP), i.e. <TT
+CLASS="CONSTANT"
+>:AB</TT
+>.
+ This is used for compatibility between Samba and CAP.</P
+></LI
+></UL
+><P
+>Default: <B
+CLASS="COMMAND"
+>coding system = &#60;empty value&#62;</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="COMMENT"
+></A
+>comment (S)</DT
+><DD
+><P
+>This is a text field that is seen next to a share
+ when a client does a queries the server, either via the network
+ neighborhood or via <B
+CLASS="COMMAND"
+>net view</B
+> to list what shares
+ are available.</P
+><P
+>If you want to set the string that is displayed next to the
+ machine name then see the <A
+HREF="#SERVERSTRING"
+><TT
+CLASS="PARAMETER"
+><I
+> server string</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <EM
+>No comment string</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>comment = Fred's Files</B
+></P
+></DD
+><DT
+><A
+NAME="CONFIGFILE"
+></A
+>config file (G)</DT
+><DD
+><P
+>This allows you to override the config file
+ to use, instead of the default (usually <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>).
+ There is a chicken and egg problem here as this option is set
+ in the config file!</P
+><P
+>For this reason, if the name of the config file has changed
+ when the parameters are loaded then it will reload them from
+ the new config file.</P
+><P
+>This option takes the usual substitutions, which can
+ be very useful.</P
+><P
+>If the config file doesn't exist then it won't be loaded
+ (allowing you to special case the config files of just a few
+ clients).</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>config file = /usr/local/samba/lib/smb.conf.%m
+ </B
+></P
+></DD
+><DT
+><A
+NAME="COPY"
+></A
+>copy (S)</DT
+><DD
+><P
+>This parameter allows you to "clone" service
+ entries. The specified service is simply duplicated under the
+ current service's name. Any parameters specified in the current
+ section will override those in the section being copied.</P
+><P
+>This feature lets you set up a 'template' service and
+ create similar services easily. Note that the service being
+ copied must occur earlier in the configuration file than the
+ service doing the copying.</P
+><P
+>Default: <EM
+>no value</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>copy = otherservice</B
+></P
+></DD
+><DT
+><A
+NAME="CREATEMASK"
+></A
+>create mask (S)</DT
+><DD
+><P
+>A synonym for this parameter is
+ <A
+HREF="#CREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>create mode</I
+></TT
+>
+ </A
+>.</P
+><P
+>When a file is created, the necessary permissions are
+ calculated according to the mapping from DOS modes to UNIX
+ permissions, and the resulting UNIX mode is then bit-wise 'AND'ed
+ with this parameter. This parameter may be thought of as a bit-wise
+ MASK for the UNIX modes of a file. Any bit <EM
+>not</EM
+>
+ set here will be removed from the modes set on a file when it is
+ created.</P
+><P
+>The default value of this parameter removes the
+ 'group' and 'other' write and execute bits from the UNIX modes.</P
+><P
+>Following this Samba will bit-wise 'OR' the UNIX mode created
+ from this parameter with the value of the <A
+HREF="#FORCECREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+></A
+>
+ parameter which is set to 000 by default.</P
+><P
+>This parameter does not affect directory modes. See the
+ parameter <A
+HREF="#DIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>directory mode
+ </I
+></TT
+></A
+> for details.</P
+><P
+>See also the <A
+HREF="#FORCECREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ create mode</I
+></TT
+></A
+> parameter for forcing particular mode
+ bits to be set on created files. See also the <A
+HREF="#DIRECTORYMODE"
+> <TT
+CLASS="PARAMETER"
+><I
+>directory mode</I
+></TT
+></A
+> parameter for masking
+ mode bits on created directories. See also the <A
+HREF="#INHERITPERMISSIONS"
+> <TT
+CLASS="PARAMETER"
+><I
+>inherit permissions</I
+></TT
+></A
+> parameter.</P
+><P
+>Note that this parameter does not apply to permissions
+ set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+ a mask on access control lists also, they need to set the <A
+HREF="#SECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>create mask = 0744</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>create mask = 0775</B
+></P
+></DD
+><DT
+><A
+NAME="CREATEMODE"
+></A
+>create mode (S)</DT
+><DD
+><P
+>This is a synonym for <A
+HREF="#CREATEMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> create mask</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="DEADTIME"
+></A
+>deadtime (G)</DT
+><DD
+><P
+>The value of the parameter (a decimal integer)
+ represents the number of minutes of inactivity before a connection
+ is considered dead, and it is disconnected. The deadtime only takes
+ effect if the number of open files is zero.</P
+><P
+>This is useful to stop a server's resources being
+ exhausted by a large number of inactive connections.</P
+><P
+>Most clients have an auto-reconnect feature when a
+ connection is broken so in most cases this parameter should be
+ transparent to users.</P
+><P
+>Using this parameter with a timeout of a few minutes
+ is recommended for most systems.</P
+><P
+>A deadtime of zero indicates that no auto-disconnection
+ should be performed.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>deadtime = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>deadtime = 15</B
+></P
+></DD
+><DT
+><A
+NAME="DEBUGHIRESTIMESTAMP"
+></A
+>debug hires timestamp (G)</DT
+><DD
+><P
+>Sometimes the timestamps in the log messages
+ are needed with a resolution of higher that seconds, this
+ boolean parameter adds microsecond resolution to the timestamp
+ message header when turned on.</P
+><P
+>Note that the parameter <A
+HREF="#DEBUGTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+> debug timestamp</I
+></TT
+></A
+> must be on for this to have an
+ effect.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>debug hires timestamp = no</B
+></P
+></DD
+><DT
+><A
+NAME="DEBUGPID"
+></A
+>debug pid (G)</DT
+><DD
+><P
+>When using only one log file for more then one
+ forked <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+>-process there may be hard to follow which process
+ outputs which message. This boolean parameter is adds the process-id
+ to the timestamp message headers in the logfile when turned on.</P
+><P
+>Note that the parameter <A
+HREF="#DEBUGTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+> debug timestamp</I
+></TT
+></A
+> must be on for this to have an
+ effect.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>debug pid = no</B
+></P
+></DD
+><DT
+><A
+NAME="DEBUGTIMESTAMP"
+></A
+>debug timestamp (G)</DT
+><DD
+><P
+>Samba 2.2 debug log messages are timestamped
+ by default. If you are running at a high <A
+HREF="#DEBUGLEVEL"
+> <TT
+CLASS="PARAMETER"
+><I
+>debug level</I
+></TT
+></A
+> these timestamps
+ can be distracting. This boolean parameter allows timestamping
+ to be turned off.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>debug timestamp = yes</B
+></P
+></DD
+><DT
+><A
+NAME="DEBUGUID"
+></A
+>debug uid (G)</DT
+><DD
+><P
+>Samba is sometimes run as root and sometime
+ run as the connected user, this boolean parameter inserts the
+ current euid, egid, uid and gid to the timestamp message headers
+ in the log file if turned on.</P
+><P
+>Note that the parameter <A
+HREF="#DEBUGTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+> debug timestamp</I
+></TT
+></A
+> must be on for this to have an
+ effect.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>debug uid = no</B
+></P
+></DD
+><DT
+><A
+NAME="DEBUGLEVEL"
+></A
+>debuglevel (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#LOGLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+> log level</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="DEFAULT"
+></A
+>default (G)</DT
+><DD
+><P
+>A synonym for <A
+HREF="#DEFAULTSERVICE"
+><TT
+CLASS="PARAMETER"
+><I
+> default service</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="DEFAULTCASE"
+></A
+>default case (S)</DT
+><DD
+><P
+>See the section on <A
+HREF="#AEN202"
+> NAME MANGLING</A
+>. Also note the <A
+HREF="#SHORTPRESERVECASE"
+> <TT
+CLASS="PARAMETER"
+><I
+>short preserve case</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>default case = lower</B
+></P
+></DD
+><DT
+><A
+NAME="DEFAULTSERVICE"
+></A
+>default service (G)</DT
+><DD
+><P
+>This parameter specifies the name of a service
+ which will be connected to if the service actually requested cannot
+ be found. Note that the square brackets are <EM
+>NOT</EM
+>
+ given in the parameter value (see example below).</P
+><P
+>There is no default value for this parameter. If this
+ parameter is not given, attempting to connect to a nonexistent
+ service results in an error.</P
+><P
+>Typically the default service would be a <A
+HREF="#GUESTOK"
+> <TT
+CLASS="PARAMETER"
+><I
+>guest ok</I
+></TT
+></A
+>, <A
+HREF="#READONLY"
+> <TT
+CLASS="PARAMETER"
+><I
+>read-only</I
+></TT
+></A
+> service.</P
+><P
+>Also note that the apparent service name will be changed
+ to equal that of the requested service, this is very useful as it
+ allows you to use macros like <TT
+CLASS="PARAMETER"
+><I
+>%S</I
+></TT
+> to make
+ a wildcard service.</P
+><P
+>Note also that any "_" characters in the name of the service
+ used in the default service will get mapped to a "/". This allows for
+ interesting things.</P
+><P
+>Example:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ default service = pub
+
+[pub]
+ path = /%S
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+></DD
+><DT
+><A
+NAME="DELETEPRINTERCOMMAND"
+></A
+>delete printer command (G)</DT
+><DD
+><P
+>With the introduction of MS-RPC based printer
+ support for Windows NT/2000 clients in Samba 2.2, it is now
+ possible to delete printer at run time by issuing the
+ DeletePrinter() RPC call.</P
+><P
+>For a Samba host this means that the printer must be
+ physically deleted from underlying printing system. The <TT
+CLASS="PARAMETER"
+><I
+> deleteprinter command</I
+></TT
+> defines a script to be run which
+ will perform the necessary operations for removing the printer
+ from the print system and from <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>.
+ </P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>delete printer command</I
+></TT
+> is
+ automatically called with only one parameter: <TT
+CLASS="PARAMETER"
+><I
+> "printer name"</I
+></TT
+>.</P
+><P
+>Once the <TT
+CLASS="PARAMETER"
+><I
+>delete printer command</I
+></TT
+> has
+ been executed, <B
+CLASS="COMMAND"
+>smbd</B
+> will reparse the <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> to associated printer no longer exists.
+ If the sharename is still valid, then <B
+CLASS="COMMAND"
+>smbd
+ </B
+> will return an ACCESS_DENIED error to the client.</P
+><P
+>See also <A
+HREF="#ADDPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+> add printer command</I
+></TT
+></A
+>, <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+></A
+>,
+ <A
+HREF="#SHOWADDPRINTERWIZARD"
+><TT
+CLASS="PARAMETER"
+><I
+>show add
+ printer wizard</I
+></TT
+></A
+></P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>deleteprinter command = /usr/bin/removeprinter
+ </B
+></P
+></DD
+><DT
+><A
+NAME="DELETEREADONLY"
+></A
+>delete readonly (S)</DT
+><DD
+><P
+>This parameter allows readonly files to be deleted.
+ This is not normal DOS semantics, but is allowed by UNIX.</P
+><P
+>This option may be useful for running applications such
+ as rcs, where UNIX file ownership prevents changing file
+ permissions, and DOS semantics prevent deletion of a read only file.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>delete readonly = no</B
+></P
+></DD
+><DT
+><A
+NAME="DELETESHARECOMMAND"
+></A
+>delete share command (G)</DT
+><DD
+><P
+>Samba 2.2.0 introduced the ability to dynamically
+ add and delete shares via the Windows NT 4.0 Server Manager. The
+ <TT
+CLASS="PARAMETER"
+><I
+>delete share command</I
+></TT
+> is used to define an
+ external program or script which will remove an existing service
+ definition from <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>. In order to successfully
+ execute the <TT
+CLASS="PARAMETER"
+><I
+>delete share command</I
+></TT
+>, <B
+CLASS="COMMAND"
+>smbd</B
+>
+ requires that the administrator be connected using a root account (i.e.
+ uid == 0).
+ </P
+><P
+> When executed, <B
+CLASS="COMMAND"
+>smbd</B
+> will automatically invoke the
+ <TT
+CLASS="PARAMETER"
+><I
+>delete share command</I
+></TT
+> with two parameters.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>configFile</I
+></TT
+> - the location
+ of the global <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>shareName</I
+></TT
+> - the name of
+ the existing service.
+ </P
+></LI
+></UL
+><P
+> This parameter is only used to remove file shares. To delete printer shares,
+ see the <A
+HREF="#DELETEPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>delete printer
+ command</I
+></TT
+></A
+>.
+ </P
+><P
+> See also <A
+HREF="#ADDSHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>add share
+ command</I
+></TT
+></A
+>, <A
+HREF="#CHANGESHARECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>change
+ share command</I
+></TT
+></A
+>.
+ </P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>delete share command = /usr/local/bin/delshare</B
+></P
+></DD
+><DT
+><A
+NAME="DELETEUSERSCRIPT"
+></A
+>delete user script (G)</DT
+><DD
+><P
+>This is the full pathname to a script that will
+ be run <EM
+>AS ROOT</EM
+> by <A
+HREF="smbd.8.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> under special circumstances
+ described below.</P
+><P
+>Normally, a Samba server requires that UNIX users are
+ created for all users accessing files on this server. For sites
+ that use Windows NT account databases as their primary user database
+ creating these users and keeping the user list in sync with the
+ Windows NT PDC is an onerous task. This option allows <B
+CLASS="COMMAND"
+> smbd</B
+> to delete the required UNIX users <EM
+>ON
+ DEMAND</EM
+> when a user accesses the Samba server and the
+ Windows NT user no longer exists.</P
+><P
+>In order to use this option, <B
+CLASS="COMMAND"
+>smbd</B
+> must be
+ set to <TT
+CLASS="PARAMETER"
+><I
+>security = domain</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>delete
+ user script</I
+></TT
+> must be set to a full pathname for a script
+ that will delete a UNIX user given one argument of <TT
+CLASS="PARAMETER"
+><I
+>%u
+ </I
+></TT
+>, which expands into the UNIX user name to delete.
+ <EM
+>NOTE</EM
+> that this is different to the <A
+HREF="#ADDUSERSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+></A
+>
+ which will work with the <TT
+CLASS="PARAMETER"
+><I
+>security = server</I
+></TT
+> option
+ as well as <TT
+CLASS="PARAMETER"
+><I
+>security = domain</I
+></TT
+>. The reason for this
+ is only when Samba is a domain member does it get the information
+ on an attempted user logon that a user no longer exists. In the
+ <TT
+CLASS="PARAMETER"
+><I
+>security = server</I
+></TT
+> mode a missing user
+ is treated the same as an invalid password logon attempt. Deleting
+ the user in this circumstance would not be a good idea.</P
+><P
+>When the Windows user attempts to access the Samba server,
+ at <EM
+>login</EM
+> (session setup in the SMB protocol)
+ time, <B
+CLASS="COMMAND"
+>smbd</B
+> contacts the <A
+HREF="#PASSWORDSERVER"
+> <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+></A
+> and attempts to authenticate
+ the given user with the given password. If the authentication fails
+ with the specific Domain error code meaning that the user no longer
+ exists then <B
+CLASS="COMMAND"
+>smbd</B
+> attempts to find a UNIX user in
+ the UNIX password database that matches the Windows user account. If
+ this lookup succeeds, and <TT
+CLASS="PARAMETER"
+><I
+>delete user script</I
+></TT
+> is
+ set then <B
+CLASS="COMMAND"
+>smbd</B
+> will all the specified script
+ <EM
+>AS ROOT</EM
+>, expanding any <TT
+CLASS="PARAMETER"
+><I
+>%u</I
+></TT
+>
+ argument to be the user name to delete.</P
+><P
+>This script should delete the given UNIX username. In this way,
+ UNIX users are dynamically deleted to match existing Windows NT
+ accounts.</P
+><P
+>See also <A
+HREF="#SECURITYEQUALSDOMAIN"
+>security = domain</A
+>,
+ <A
+HREF="#PASSWORDSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+>
+ </A
+>, <A
+HREF="#ADDUSERSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>add user script</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>delete user script = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>delete user script = /usr/local/samba/bin/del_user
+ %u</B
+></P
+></DD
+><DT
+><A
+NAME="DELETEVETOFILES"
+></A
+>delete veto files (S)</DT
+><DD
+><P
+>This option is used when Samba is attempting to
+ delete a directory that contains one or more vetoed directories
+ (see the <A
+HREF="#VETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>veto files</I
+></TT
+></A
+>
+ option). If this option is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> (the default) then if a vetoed
+ directory contains any non-vetoed files or directories then the
+ directory delete will fail. This is usually what you want.</P
+><P
+>If this option is set to <TT
+CLASS="CONSTANT"
+>true</TT
+>, then Samba
+ will attempt to recursively delete any files and directories within
+ the vetoed directory. This can be useful for integration with file
+ serving systems such as NetAtalk which create meta-files within
+ directories you might normally veto DOS/Windows users from seeing
+ (e.g. <TT
+CLASS="FILENAME"
+>.AppleDouble</TT
+>)</P
+><P
+>Setting <B
+CLASS="COMMAND"
+>delete veto files = yes</B
+> allows these
+ directories to be transparently deleted when the parent directory
+ is deleted (so long as the user has permissions to do so).</P
+><P
+>See also the <A
+HREF="#VETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>veto
+ files</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>delete veto files = no</B
+></P
+></DD
+><DT
+><A
+NAME="DENYHOSTS"
+></A
+>deny hosts (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#HOSTSDENY"
+><TT
+CLASS="PARAMETER"
+><I
+>hosts
+ deny</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="DFREECOMMAND"
+></A
+>dfree command (G)</DT
+><DD
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>dfree command</I
+></TT
+> setting should
+ only be used on systems where a problem occurs with the internal
+ disk space calculations. This has been known to happen with Ultrix,
+ but may occur with other operating systems. The symptom that was
+ seen was an error of "Abort Retry Ignore" at the end of each
+ directory listing.</P
+><P
+>This setting allows the replacement of the internal routines to
+ calculate the total disk space and amount available with an external
+ routine. The example below gives a possible script that might fulfill
+ this function.</P
+><P
+>The external program will be passed a single parameter indicating
+ a directory in the filesystem being queried. This will typically consist
+ of the string <TT
+CLASS="FILENAME"
+>./</TT
+>. The script should return two
+ integers in ASCII. The first should be the total disk space in blocks,
+ and the second should be the number of available blocks. An optional
+ third return value can give the block size in bytes. The default
+ blocksize is 1024 bytes.</P
+><P
+>Note: Your script should <EM
+>NOT</EM
+> be setuid or
+ setgid and should be owned by (and writeable only by) root!</P
+><P
+>Default: <EM
+>By default internal routines for
+ determining the disk capacity and remaining space will be used.
+ </EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>dfree command = /usr/local/samba/bin/dfree
+ </B
+></P
+><P
+>Where the script dfree (which must be made executable) could be:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>or perhaps (on Sys V based systems):</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>
+ #!/bin/sh
+ /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Note that you may have to replace the command names
+ with full path names on some systems.</P
+></DD
+><DT
+><A
+NAME="DIRECTORY"
+></A
+>directory (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#PATH"
+><TT
+CLASS="PARAMETER"
+><I
+>path
+ </I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="DIRECTORYMASK"
+></A
+>directory mask (S)</DT
+><DD
+><P
+>This parameter is the octal modes which are
+ used when converting DOS modes to UNIX modes when creating UNIX
+ directories.</P
+><P
+>When a directory is created, the necessary permissions are
+ calculated according to the mapping from DOS modes to UNIX permissions,
+ and the resulting UNIX mode is then bit-wise 'AND'ed with this
+ parameter. This parameter may be thought of as a bit-wise MASK for
+ the UNIX modes of a directory. Any bit <EM
+>not</EM
+> set
+ here will be removed from the modes set on a directory when it is
+ created.</P
+><P
+>The default value of this parameter removes the 'group'
+ and 'other' write bits from the UNIX mode, allowing only the
+ user who owns the directory to modify it.</P
+><P
+>Following this Samba will bit-wise 'OR' the UNIX mode
+ created from this parameter with the value of the <A
+HREF="#FORCEDIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force directory mode
+ </I
+></TT
+></A
+> parameter. This parameter is set to 000 by
+ default (i.e. no extra mode bits are added).</P
+><P
+>Note that this parameter does not apply to permissions
+ set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+ a mask on access control lists also, they need to set the <A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory security mask</I
+></TT
+></A
+>.</P
+><P
+>See the <A
+HREF="#FORCEDIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ directory mode</I
+></TT
+></A
+> parameter to cause particular mode
+ bits to always be set on created directories.</P
+><P
+>See also the <A
+HREF="#CREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>create mode
+ </I
+></TT
+></A
+> parameter for masking mode bits on created files,
+ and the <A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory
+ security mask</I
+></TT
+></A
+> parameter.</P
+><P
+>Also refer to the <A
+HREF="#INHERITPERMISSIONS"
+><TT
+CLASS="PARAMETER"
+><I
+> inherit permissions</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>directory mask = 0755</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>directory mask = 0775</B
+></P
+></DD
+><DT
+><A
+NAME="DIRECTORYMODE"
+></A
+>directory mode (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#DIRECTORYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> directory mask</I
+></TT
+></A
+></P
+></DD
+><DT
+><A
+NAME="DIRECTORYSECURITYMASK"
+></A
+>directory security mask (S)</DT
+><DD
+><P
+>This parameter controls what UNIX permission bits
+ can be modified when a Windows NT client is manipulating the UNIX
+ permission on a directory using the native NT security dialog
+ box.</P
+><P
+>This parameter is applied as a mask (AND'ed with) to
+ the changed permission bits, thus preventing any bits not in
+ this mask from being modified. Essentially, zero bits in this
+ mask may be treated as a set of bits the user is not allowed
+ to change.</P
+><P
+>If not set explicitly this parameter is set to 0777
+ meaning a user is allowed to modify all the user/group/world
+ permissions on a directory.</P
+><P
+><EM
+>Note</EM
+> that users who can access the
+ Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ it as the default of <TT
+CLASS="CONSTANT"
+>0777</TT
+>.</P
+><P
+>See also the <A
+HREF="#FORCEDIRECTORYSECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+> force directory security mode</I
+></TT
+></A
+>, <A
+HREF="#SECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+>,
+ <A
+HREF="#FORCESECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>directory security mask = 0777</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>directory security mask = 0700</B
+></P
+></DD
+><DT
+><A
+NAME="DISABLESPOOLSS"
+></A
+>disable spoolss (G)</DT
+><DD
+><P
+>Enabling this parameter will disables Samba's support
+ for the SPOOLSS set of MS-RPC's and will yield identical behavior
+ as Samba 2.0.x. Windows NT/2000 clients will downgrade to using
+ Lanman style printing commands. Windows 9x/ME will be uneffected by
+ the parameter. However, this will also disable the ability to upload
+ printer drivers to a Samba server via the Windows NT Add Printer
+ Wizard or by using the NT printer properties dialog window. It will
+ also disable the capability of Windows NT/2000 clients to download
+ print drivers from the Samba host upon demand.
+ <EM
+>Be very careful about enabling this parameter.</EM
+>
+ </P
+><P
+>See also <A
+HREF="#USECLIENTDRIVER"
+>use client driver</A
+>
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>disable spoolss = no</B
+></P
+></DD
+><DT
+><A
+NAME="DNSPROXY"
+></A
+>dns proxy (G)</DT
+><DD
+><P
+>Specifies that <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ when acting as a WINS server and finding that a NetBIOS name has not
+ been registered, should treat the NetBIOS name word-for-word as a DNS
+ name and do a lookup with the DNS server for that name on behalf of
+ the name-querying client.</P
+><P
+>Note that the maximum length for a NetBIOS name is 15
+ characters, so the DNS name (or DNS alias) can likewise only be
+ 15 characters, maximum.</P
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> spawns a second copy of itself to do the
+ DNS name lookup requests, as doing a name lookup is a blocking
+ action.</P
+><P
+>See also the parameter <A
+HREF="#WINSSUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+> wins support</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>dns proxy = yes</B
+></P
+></DD
+><DT
+><A
+NAME="DOMAINADMINGROUP"
+></A
+>domain admin group (G)</DT
+><DD
+><P
+>This parameter is intended as a temporary solution
+ to enable users to be a member of the "Domain Admins" group when
+ a Samba host is acting as a PDC. A complete solution will be provided
+ by a system for mapping Windows NT/2000 groups onto UNIX groups.
+ Please note that this parameter has a somewhat confusing name. It
+ accepts a list of usernames and of group names in standard
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> notation.
+ </P
+><P
+>See also <A
+HREF="#DOMAINGUESTGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>domain
+ guest group</I
+></TT
+></A
+>, <A
+HREF="#DOMAINLOGONS"
+><TT
+CLASS="PARAMETER"
+><I
+>domain
+ logons</I
+></TT
+></A
+>
+ </P
+><P
+>Default: <EM
+>no domain administrators</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>domain admin group = root @wheel</B
+></P
+></DD
+><DT
+><A
+NAME="DOMAINGUESTGROUP"
+></A
+>domain guest group (G)</DT
+><DD
+><P
+>This parameter is intended as a temporary solution
+ to enable users to be a member of the "Domain Guests" group when
+ a Samba host is acting as a PDC. A complete solution will be provided
+ by a system for mapping Windows NT/2000 groups onto UNIX groups.
+ Please note that this parameter has a somewhat confusing name. It
+ accepts a list of usernames and of group names in standard
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> notation.
+ </P
+><P
+>See also <A
+HREF="#DOMAINADMINGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>domain
+ admin group</I
+></TT
+></A
+>, <A
+HREF="#DOMAINLOGONS"
+><TT
+CLASS="PARAMETER"
+><I
+>domain
+ logons</I
+></TT
+></A
+>
+ </P
+><P
+>Default: <EM
+>no domain guests</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>domain guest group = nobody @guest</B
+></P
+></DD
+><DT
+><A
+NAME="DOMAINLOGONS"
+></A
+>domain logons (G)</DT
+><DD
+><P
+>If set to <TT
+CLASS="CONSTANT"
+>true</TT
+>, the Samba server will serve
+ Windows 95/98 Domain logons for the <A
+HREF="#WORKGROUP"
+> <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+></A
+> it is in. Samba 2.2 also
+ has limited capability to act as a domain controller for Windows
+ NT 4 Domains. For more details on setting up this feature see
+ the Samba-PDC-HOWTO included in the <TT
+CLASS="FILENAME"
+>htmldocs/</TT
+>
+ directory shipped with the source code.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>domain logons = no</B
+></P
+></DD
+><DT
+><A
+NAME="DOMAINMASTER"
+></A
+>domain master (G)</DT
+><DD
+><P
+>Tell <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> nmbd(8)</B
+></A
+> to enable WAN-wide browse list
+ collation. Setting this option causes <B
+CLASS="COMMAND"
+>nmbd</B
+> to
+ claim a special domain specific NetBIOS name that identifies
+ it as a domain master browser for its given <A
+HREF="#WORKGROUP"
+> <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+></A
+>. Local master browsers
+ in the same <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+> on broadcast-isolated
+ subnets will give this <B
+CLASS="COMMAND"
+>nmbd</B
+> their local browse lists,
+ and then ask <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>
+ for a complete copy of the browse list for the whole wide area
+ network. Browser clients will then contact their local master browser,
+ and will receive the domain-wide browse list, instead of just the list
+ for their broadcast-isolated subnet.</P
+><P
+>Note that Windows NT Primary Domain Controllers expect to be
+ able to claim this <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+> specific special
+ NetBIOS name that identifies them as domain master browsers for
+ that <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+> by default (i.e. there is no
+ way to prevent a Windows NT PDC from attempting to do this). This
+ means that if this parameter is set and <B
+CLASS="COMMAND"
+>nmbd</B
+> claims
+ the special name for a <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+> before a Windows
+ NT PDC is able to do so then cross subnet browsing will behave
+ strangely and may fail.</P
+><P
+>If <A
+HREF="#DOMAINLOGONS"
+><B
+CLASS="COMMAND"
+>domain logons = yes</B
+>
+ </A
+>, then the default behavior is to enable the <TT
+CLASS="PARAMETER"
+><I
+>domain
+ master</I
+></TT
+> parameter. If <TT
+CLASS="PARAMETER"
+><I
+>domain logons</I
+></TT
+> is
+ not enabled (the default setting), then neither will <TT
+CLASS="PARAMETER"
+><I
+>domain
+ master</I
+></TT
+> be enabled by default.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>domain master = auto</B
+></P
+></DD
+><DT
+><A
+NAME="DONTDESCEND"
+></A
+>dont descend (S)</DT
+><DD
+><P
+>There are certain directories on some systems
+ (e.g., the <TT
+CLASS="FILENAME"
+>/proc</TT
+> tree under Linux) that are either not
+ of interest to clients or are infinitely deep (recursive). This
+ parameter allows you to specify a comma-delimited list of directories
+ that the server should always show as empty.</P
+><P
+>Note that Samba can be very fussy about the exact format
+ of the "dont descend" entries. For example you may need <TT
+CLASS="FILENAME"
+> ./proc</TT
+> instead of just <TT
+CLASS="FILENAME"
+>/proc</TT
+>.
+ Experimentation is the best policy :-) </P
+><P
+>Default: <EM
+>none (i.e., all directories are OK
+ to descend)</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>dont descend = /proc,/dev</B
+></P
+></DD
+><DT
+><A
+NAME="DOSFILEMODE"
+></A
+>dos filemode (S)</DT
+><DD
+><P
+> The default behavior in Samba is to provide
+ UNIX-like behavior where only the owner of a file/directory is
+ able to change the permissions on it. However, this behavior
+ is often confusing to DOS/Windows users. Enabling this parameter
+ allows a user who has write access to the file (by whatever
+ means) to modify the permissions on it. Note that a user
+ belonging to the group owning the file will not be allowed to
+ change permissions if the group is only granted read access.
+ Ownership of the file/directory is not changed, only the permissions
+ are modified.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>dos filemode = no</B
+></P
+></DD
+><DT
+><A
+NAME="DOSFILETIMERESOLUTION"
+></A
+>dos filetime resolution (S)</DT
+><DD
+><P
+>Under the DOS and Windows FAT filesystem, the finest
+ granularity on time resolution is two seconds. Setting this parameter
+ for a share causes Samba to round the reported time down to the
+ nearest two second boundary when a query call that requires one second
+ resolution is made to <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+>
+ </A
+>.</P
+><P
+>This option is mainly used as a compatibility option for Visual
+ C++ when used against Samba shares. If oplocks are enabled on a
+ share, Visual C++ uses two different time reading calls to check if a
+ file has changed since it was last read. One of these calls uses a
+ one-second granularity, the other uses a two second granularity. As
+ the two second call rounds any odd second down, then if the file has a
+ timestamp of an odd number of seconds then the two timestamps will not
+ match and Visual C++ will keep reporting the file has changed. Setting
+ this option causes the two timestamps to match, and Visual C++ is
+ happy.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>dos filetime resolution = no</B
+></P
+></DD
+><DT
+><A
+NAME="DOSFILETIMES"
+></A
+>dos filetimes (S)</DT
+><DD
+><P
+>Under DOS and Windows, if a user can write to a
+ file they can change the timestamp on it. Under POSIX semantics,
+ only the owner of the file or root may change the timestamp. By
+ default, Samba runs with POSIX semantics and refuses to change the
+ timestamp on a file if the user <B
+CLASS="COMMAND"
+>smbd</B
+> is acting
+ on behalf of is not the file owner. Setting this option to <TT
+CLASS="CONSTANT"
+> true</TT
+> allows DOS semantics and <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> will change the file
+ timestamp as DOS requires.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>dos filetimes = no</B
+></P
+></DD
+><DT
+><A
+NAME="ENCRYPTPASSWORDS"
+></A
+>encrypt passwords (G)</DT
+><DD
+><P
+>This boolean controls whether encrypted passwords
+ will be negotiated with the client. Note that Windows NT 4.0 SP3 and
+ above and also Windows 98 will by default expect encrypted passwords
+ unless a registry entry is changed. To use encrypted passwords in
+ Samba see the file ENCRYPTION.txt in the Samba documentation
+ directory <TT
+CLASS="FILENAME"
+>docs/</TT
+> shipped with the source code.</P
+><P
+>In order for encrypted passwords to work correctly
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> must either
+ have access to a local <A
+HREF="smbpasswd.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smbpasswd(5)
+ </TT
+></A
+> file (see the <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> smbpasswd(8)</B
+></A
+> program for information on how to set up
+ and maintain this file), or set the <A
+HREF="#SECURITY"
+>security = [server|domain]</A
+> parameter which
+ causes <B
+CLASS="COMMAND"
+>smbd</B
+> to authenticate against another
+ server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>encrypt passwords = no</B
+></P
+></DD
+><DT
+><A
+NAME="ENHANCEDBROWSING"
+></A
+>enhanced browsing (G)</DT
+><DD
+><P
+>This option enables a couple of enhancements to
+ cross-subnet browse propagation that have been added in Samba
+ but which are not standard in Microsoft implementations.
+ </P
+><P
+>The first enhancement to browse propagation consists of a regular
+ wildcard query to a Samba WINS server for all Domain Master Browsers,
+ followed by a browse synchronization with each of the returned
+ DMBs. The second enhancement consists of a regular randomised browse
+ synchronization with all currently known DMBs.</P
+><P
+>You may wish to disable this option if you have a problem with empty
+ workgroups not disappearing from browse lists. Due to the restrictions
+ of the browse protocols these enhancements can cause a empty workgroup
+ to stay around forever which can be annoying.</P
+><P
+>In general you should leave this option enabled as it makes
+ cross-subnet browse propagation much more reliable.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>enhanced browsing = yes</B
+></P
+></DD
+><DT
+><A
+NAME="ENUMPORTSCOMMAND"
+></A
+>enumports command (G)</DT
+><DD
+><P
+>The concept of a "port" is fairly foreign
+ to UNIX hosts. Under Windows NT/2000 print servers, a port
+ is associated with a port monitor and generally takes the form of
+ a local port (i.e. LPT1:, COM1:, FILE:) or a remote port
+ (i.e. LPD Port Monitor, etc...). By default, Samba has only one
+ port defined--<TT
+CLASS="CONSTANT"
+>"Samba Printer Port"</TT
+>. Under
+ Windows NT/2000, all printers must have a valid port name.
+ If you wish to have a list of ports displayed (<B
+CLASS="COMMAND"
+>smbd
+ </B
+> does not use a port name for anything) other than
+ the default <TT
+CLASS="CONSTANT"
+>"Samba Printer Port"</TT
+>, you
+ can define <TT
+CLASS="PARAMETER"
+><I
+>enumports command</I
+></TT
+> to point to
+ a program which should generate a list of ports, one per line,
+ to standard output. This listing will then be used in response
+ to the level 1 and 2 EnumPorts() RPC.</P
+><P
+>Default: <EM
+>no enumports command</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>enumports command = /usr/bin/listports
+ </B
+></P
+></DD
+><DT
+><A
+NAME="EXEC"
+></A
+>exec (S)</DT
+><DD
+><P
+>This is a synonym for <A
+HREF="#PREEXEC"
+> <TT
+CLASS="PARAMETER"
+><I
+>preexec</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="FAKEDIRECTORYCREATETIMES"
+></A
+>fake directory create times (S)</DT
+><DD
+><P
+>NTFS and Windows VFAT file systems keep a create
+ time for all files and directories. This is not the same as the
+ ctime - status change time - that Unix keeps, so Samba by default
+ reports the earliest of the various times Unix does keep. Setting
+ this parameter for a share causes Samba to always report midnight
+ 1-1-1980 as the create time for directories.</P
+><P
+>This option is mainly used as a compatibility option for
+ Visual C++ when used against Samba shares. Visual C++ generated
+ makefiles have the object directory as a dependency for each object
+ file, and a make rule to create the directory. Also, when NMAKE
+ compares timestamps it uses the creation time when examining a
+ directory. Thus the object directory will be created if it does not
+ exist, but once it does exist it will always have an earlier
+ timestamp than the object files it contains.</P
+><P
+>However, Unix time semantics mean that the create time
+ reported by Samba will be updated whenever a file is created or
+ or deleted in the directory. NMAKE finds all object files in
+ the object directory. The timestamp of the last one built is then
+ compared to the timestamp of the object directory. If the
+ directory's timestamp if newer, then all object files
+ will be rebuilt. Enabling this option
+ ensures directories always predate their contents and an NMAKE build
+ will proceed as expected.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>fake directory create times = no</B
+></P
+></DD
+><DT
+><A
+NAME="FAKEOPLOCKS"
+></A
+>fake oplocks (S)</DT
+><DD
+><P
+>Oplocks are the way that SMB clients get permission
+ from a server to locally cache file operations. If a server grants
+ an oplock (opportunistic lock) then the client is free to assume
+ that it is the only one accessing the file and it will aggressively
+ cache file data. With some oplock types the client may even cache
+ file open/close operations. This can give enormous performance benefits.
+ </P
+><P
+>When you set <B
+CLASS="COMMAND"
+>fake oplocks = yes</B
+>, <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> will
+ always grant oplock requests no matter how many clients are using
+ the file.</P
+><P
+>It is generally much better to use the real <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+></A
+> support rather
+ than this parameter.</P
+><P
+>If you enable this option on all read-only shares or
+ shares that you know will only be accessed from one client at a
+ time such as physically read-only media like CDROMs, you will see
+ a big performance improvement on many operations. If you enable
+ this option on shares where multiple clients may be accessing the
+ files read-write at the same time you can get data corruption. Use
+ this option carefully!</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>fake oplocks = no</B
+></P
+></DD
+><DT
+><A
+NAME="FOLLOWSYMLINKS"
+></A
+>follow symlinks (S)</DT
+><DD
+><P
+>This parameter allows the Samba administrator
+ to stop <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>
+ from following symbolic links in a particular share. Setting this
+ parameter to <TT
+CLASS="CONSTANT"
+>no</TT
+> prevents any file or directory
+ that is a symbolic link from being followed (the user will get an
+ error). This option is very useful to stop users from adding a
+ symbolic link to <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> in their home
+ directory for instance. However it will slow filename lookups
+ down slightly.</P
+><P
+>This option is enabled (i.e. <B
+CLASS="COMMAND"
+>smbd</B
+> will
+ follow symbolic links) by default.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>follow symlinks = yes</B
+></P
+></DD
+><DT
+><A
+NAME="FORCECREATEMODE"
+></A
+>force create mode (S)</DT
+><DD
+><P
+>This parameter specifies a set of UNIX mode bit
+ permissions that will <EM
+>always</EM
+> be set on a
+ file created by Samba. This is done by bitwise 'OR'ing these bits onto
+ the mode bits of a file that is being created or having its
+ permissions changed. The default for this parameter is (in octal)
+ 000. The modes in this parameter are bitwise 'OR'ed onto the file
+ mode after the mask set in the <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+>
+ parameter is applied.</P
+><P
+>See also the parameter <A
+HREF="#CREATEMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>create
+ mask</I
+></TT
+></A
+> for details on masking mode bits on files.</P
+><P
+>See also the <A
+HREF="#INHERITPERMISSIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>inherit
+ permissions</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>force create mode = 000</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force create mode = 0755</B
+></P
+><P
+>would force all created files to have read and execute
+ permissions set for 'group' and 'other' as well as the
+ read/write/execute bits set for the 'user'.</P
+></DD
+><DT
+><A
+NAME="FORCEDIRECTORYMODE"
+></A
+>force directory mode (S)</DT
+><DD
+><P
+>This parameter specifies a set of UNIX mode bit
+ permissions that will <EM
+>always</EM
+> be set on a directory
+ created by Samba. This is done by bitwise 'OR'ing these bits onto the
+ mode bits of a directory that is being created. The default for this
+ parameter is (in octal) 0000 which will not add any extra permission
+ bits to a created directory. This operation is done after the mode
+ mask in the parameter <TT
+CLASS="PARAMETER"
+><I
+>directory mask</I
+></TT
+> is
+ applied.</P
+><P
+>See also the parameter <A
+HREF="#DIRECTORYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> directory mask</I
+></TT
+></A
+> for details on masking mode bits
+ on created directories.</P
+><P
+>See also the <A
+HREF="#INHERITPERMISSIONS"
+><TT
+CLASS="PARAMETER"
+><I
+> inherit permissions</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>force directory mode = 000</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force directory mode = 0755</B
+></P
+><P
+>would force all created directories to have read and execute
+ permissions set for 'group' and 'other' as well as the
+ read/write/execute bits set for the 'user'.</P
+></DD
+><DT
+><A
+NAME="FORCEDIRECTORYSECURITYMODE"
+></A
+>force directory
+ security mode (S)</DT
+><DD
+><P
+>This parameter controls what UNIX permission bits
+ can be modified when a Windows NT client is manipulating the UNIX
+ permission on a directory using the native NT security dialog box.</P
+><P
+>This parameter is applied as a mask (OR'ed with) to the
+ changed permission bits, thus forcing any bits in this mask that
+ the user may have modified to be on. Essentially, one bits in this
+ mask may be treated as a set of bits that, when modifying security
+ on a directory, the user has always set to be 'on'.</P
+><P
+>If not set explicitly this parameter is 000, which
+ allows a user to modify all the user/group/world permissions on a
+ directory without restrictions.</P
+><P
+><EM
+>Note</EM
+> that users who can access the
+ Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ it set as 0000.</P
+><P
+>See also the <A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> directory security mask</I
+></TT
+></A
+>, <A
+HREF="#SECURITYMASK"
+> <TT
+CLASS="PARAMETER"
+><I
+>security mask</I
+></TT
+></A
+>,
+ <A
+HREF="#FORCESECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force security mode
+ </I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>force directory security mode = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force directory security mode = 700</B
+></P
+></DD
+><DT
+><A
+NAME="FORCEGROUP"
+></A
+>force group (S)</DT
+><DD
+><P
+>This specifies a UNIX group name that will be
+ assigned as the default primary group for all users connecting
+ to this service. This is useful for sharing files by ensuring
+ that all access to files on service will use the named group for
+ their permissions checking. Thus, by assigning permissions for this
+ group to the files and directories within this service the Samba
+ administrator can restrict or allow sharing of these files.</P
+><P
+>In Samba 2.0.5 and above this parameter has extended
+ functionality in the following way. If the group name listed here
+ has a '+' character prepended to it then the current user accessing
+ the share only has the primary group default assigned to this group
+ if they are already assigned as a member of that group. This allows
+ an administrator to decide that only users who are already in a
+ particular group will create files with group ownership set to that
+ group. This gives a finer granularity of ownership assignment. For
+ example, the setting <TT
+CLASS="FILENAME"
+>force group = +sys</TT
+> means
+ that only users who are already in group sys will have their default
+ primary group assigned to sys when accessing this Samba share. All
+ other users will retain their ordinary primary group.</P
+><P
+>If the <A
+HREF="#FORCEUSER"
+><TT
+CLASS="PARAMETER"
+><I
+>force user
+ </I
+></TT
+></A
+> parameter is also set the group specified in
+ <TT
+CLASS="PARAMETER"
+><I
+>force group</I
+></TT
+> will override the primary group
+ set in <TT
+CLASS="PARAMETER"
+><I
+>force user</I
+></TT
+>.</P
+><P
+>See also <A
+HREF="#FORCEUSER"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ user</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>no forced group</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force group = agroup</B
+></P
+></DD
+><DT
+><A
+NAME="FORCESECURITYMODE"
+></A
+>force security mode (S)</DT
+><DD
+><P
+>This parameter controls what UNIX permission
+ bits can be modified when a Windows NT client is manipulating
+ the UNIX permission on a file using the native NT security dialog
+ box.</P
+><P
+>This parameter is applied as a mask (OR'ed with) to the
+ changed permission bits, thus forcing any bits in this mask that
+ the user may have modified to be on. Essentially, one bits in this
+ mask may be treated as a set of bits that, when modifying security
+ on a file, the user has always set to be 'on'.</P
+><P
+>If not set explicitly this parameter is set to 0,
+ and allows a user to modify all the user/group/world permissions on a file,
+ with no restrictions.</P
+><P
+><EM
+>Note</EM
+> that users who can access
+ the Samba server through other means can easily bypass this restriction,
+ so it is primarily useful for standalone "appliance" systems.
+ Administrators of most normal systems will probably want to leave
+ this set to 0000.</P
+><P
+>See also the <A
+HREF="#FORCEDIRECTORYSECURITYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+> force directory security mode</I
+></TT
+></A
+>,
+ <A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory security
+ mask</I
+></TT
+></A
+>, <A
+HREF="#SECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> security mask</I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>force security mode = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force security mode = 700</B
+></P
+></DD
+><DT
+><A
+NAME="FORCEUSER"
+></A
+>force user (S)</DT
+><DD
+><P
+>This specifies a UNIX user name that will be
+ assigned as the default user for all users connecting to this service.
+ This is useful for sharing files. You should also use it carefully
+ as using it incorrectly can cause security problems.</P
+><P
+>This user name only gets used once a connection is established.
+ Thus clients still need to connect as a valid user and supply a
+ valid password. Once connected, all file operations will be performed
+ as the "forced user", no matter what username the client connected
+ as. This can be very useful.</P
+><P
+>In Samba 2.0.5 and above this parameter also causes the
+ primary group of the forced user to be used as the primary group
+ for all file activity. Prior to 2.0.5 the primary group was left
+ as the primary group of the connecting user (this was a bug).</P
+><P
+>See also <A
+HREF="#FORCEGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>force group
+ </I
+></TT
+></A
+></P
+><P
+>Default: <EM
+>no forced user</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>force user = auser</B
+></P
+></DD
+><DT
+><A
+NAME="FSTYPE"
+></A
+>fstype (S)</DT
+><DD
+><P
+>This parameter allows the administrator to
+ configure the string that specifies the type of filesystem a share
+ is using that is reported by <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)
+ </B
+></A
+> when a client queries the filesystem type
+ for a share. The default type is <TT
+CLASS="CONSTANT"
+>NTFS</TT
+> for
+ compatibility with Windows NT but this can be changed to other
+ strings such as <TT
+CLASS="CONSTANT"
+>Samba</TT
+> or <TT
+CLASS="CONSTANT"
+>FAT
+ </TT
+> if required.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>fstype = NTFS</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>fstype = Samba</B
+></P
+></DD
+><DT
+><A
+NAME="GETWDCACHE"
+></A
+>getwd cache (G)</DT
+><DD
+><P
+>This is a tuning option. When this is enabled a
+ caching algorithm will be used to reduce the time taken for getwd()
+ calls. This can have a significant impact on performance, especially
+ when the <A
+HREF="#WIDELINKS"
+><TT
+CLASS="PARAMETER"
+><I
+>wide links</I
+></TT
+>
+ </A
+>parameter is set to <TT
+CLASS="CONSTANT"
+>false</TT
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>getwd cache = yes</B
+></P
+></DD
+><DT
+><A
+NAME="GROUP"
+></A
+>group (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#FORCEGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ group</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="GUESTACCOUNT"
+></A
+>guest account (S)</DT
+><DD
+><P
+>This is a username which will be used for access
+ to services which are specified as <A
+HREF="#GUESTOK"
+><TT
+CLASS="PARAMETER"
+><I
+> guest ok</I
+></TT
+></A
+> (see below). Whatever privileges this
+ user has will be available to any client connecting to the guest service.
+ Typically this user will exist in the password file, but will not
+ have a valid login. The user account "ftp" is often a good choice
+ for this parameter. If a username is specified in a given service,
+ the specified username overrides this one.</P
+><P
+>One some systems the default guest account "nobody" may not
+ be able to print. Use another account in this case. You should test
+ this by trying to log in as your guest user (perhaps by using the
+ <B
+CLASS="COMMAND"
+>su -</B
+> command) and trying to print using the
+ system print command such as <B
+CLASS="COMMAND"
+>lpr(1)</B
+> or <B
+CLASS="COMMAND"
+> lp(1)</B
+>.</P
+><P
+>Default: <EM
+>specified at compile time, usually
+ "nobody"</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>guest account = ftp</B
+></P
+></DD
+><DT
+><A
+NAME="GUESTOK"
+></A
+>guest ok (S)</DT
+><DD
+><P
+>If this parameter is <TT
+CLASS="CONSTANT"
+>yes</TT
+> for
+ a service, then no password is required to connect to the service.
+ Privileges will be those of the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+> guest account</I
+></TT
+></A
+>.</P
+><P
+>See the section below on <A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+> security</I
+></TT
+></A
+> for more information about this option.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>guest ok = no</B
+></P
+></DD
+><DT
+><A
+NAME="GUESTONLY"
+></A
+>guest only (S)</DT
+><DD
+><P
+>If this parameter is <TT
+CLASS="CONSTANT"
+>yes</TT
+> for
+ a service, then only guest connections to the service are permitted.
+ This parameter will have no effect if <A
+HREF="#GUESTOK"
+> <TT
+CLASS="PARAMETER"
+><I
+>guest ok</I
+></TT
+></A
+> is not set for the service.</P
+><P
+>See the section below on <A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+> security</I
+></TT
+></A
+> for more information about this option.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>guest only = no</B
+></P
+></DD
+><DT
+><A
+NAME="HIDEDOTFILES"
+></A
+>hide dot files (S)</DT
+><DD
+><P
+>This is a boolean parameter that controls whether
+ files starting with a dot appear as hidden files.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>hide dot files = yes</B
+></P
+></DD
+><DT
+><A
+NAME="HIDEFILES"
+></A
+>hide files(S)</DT
+><DD
+><P
+>This is a list of files or directories that are not
+ visible but are accessible. The DOS 'hidden' attribute is applied
+ to any files or directories that match.</P
+><P
+>Each entry in the list must be separated by a '/',
+ which allows spaces to be included in the entry. '*'
+ and '?' can be used to specify multiple files or directories
+ as in DOS wildcards.</P
+><P
+>Each entry must be a Unix path, not a DOS path and must
+ not include the Unix directory separator '/'.</P
+><P
+>Note that the case sensitivity option is applicable
+ in hiding files.</P
+><P
+>Setting this parameter will affect the performance of Samba,
+ as it will be forced to check all files and directories for a match
+ as they are scanned.</P
+><P
+>See also <A
+HREF="#HIDEDOTFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>hide
+ dot files</I
+></TT
+></A
+>, <A
+HREF="#VETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+> veto files</I
+></TT
+></A
+> and <A
+HREF="#CASESENSITIVE"
+> <TT
+CLASS="PARAMETER"
+><I
+>case sensitive</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>no file are hidden</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>hide files =
+ /.*/DesktopFolderDB/TrashFor%m/resource.frk/</B
+></P
+><P
+>The above example is based on files that the Macintosh
+ SMB client (DAVE) available from <A
+HREF="http://www.thursby.com"
+TARGET="_top"
+>
+ Thursby</A
+> creates for internal use, and also still hides
+ all files beginning with a dot.</P
+></DD
+><DT
+><A
+NAME="HIDELOCALUSERS"
+></A
+>hide local users(G)</DT
+><DD
+><P
+>This parameter toggles the hiding of local UNIX
+ users (root, wheel, floppy, etc) from remote clients.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>hide local users = no</B
+></P
+></DD
+><DT
+><A
+NAME="HIDEUNREADABLE"
+></A
+>hide unreadable (S)</DT
+><DD
+><P
+>This parameter prevents clients from seeing the
+ existance of files that cannot be read. Defaults to off.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>hide unreadable = no</B
+></P
+></DD
+><DT
+><A
+NAME="HOMEDIRMAP"
+></A
+>homedir map (G)</DT
+><DD
+><P
+>If<A
+HREF="#NISHOMEDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>nis homedir
+ </I
+></TT
+></A
+> is <TT
+CLASS="CONSTANT"
+>true</TT
+>, and <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> is also acting
+ as a Win95/98 <TT
+CLASS="PARAMETER"
+><I
+>logon server</I
+></TT
+> then this parameter
+ specifies the NIS (or YP) map from which the server for the user's
+ home directory should be extracted. At present, only the Sun
+ auto.home map format is understood. The form of the map is:</P
+><P
+><B
+CLASS="COMMAND"
+>username server:/some/file/system</B
+></P
+><P
+>and the program will extract the servername from before
+ the first ':'. There should probably be a better parsing system
+ that copes with different map formats and also Amd (another
+ automounter) maps.</P
+><P
+><EM
+>NOTE :</EM
+>A working NIS client is required on
+ the system for this option to work.</P
+><P
+>See also <A
+HREF="#NISHOMEDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>nis homedir</I
+></TT
+>
+ </A
+>, <A
+HREF="#DOMAINLOGONS"
+><TT
+CLASS="PARAMETER"
+><I
+>domain logons</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>homedir map = &#60;empty string&#62;</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>homedir map = amd.homedir</B
+></P
+></DD
+><DT
+><A
+NAME="HOSTMSDFS"
+></A
+>host msdfs (G)</DT
+><DD
+><P
+>This boolean parameter is only available
+ if Samba has been configured and compiled with the <B
+CLASS="COMMAND"
+> --with-msdfs</B
+> option. If set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>,
+ Samba will act as a Dfs server, and allow Dfs-aware clients
+ to browse Dfs trees hosted on the server.</P
+><P
+>See also the <A
+HREF="#MSDFSROOT"
+><TT
+CLASS="PARAMETER"
+><I
+> msdfs root</I
+></TT
+></A
+> share level parameter. For
+ more information on setting up a Dfs tree on Samba,
+ refer to <A
+HREF="msdfs_setup.html"
+TARGET="_top"
+>msdfs_setup.html</A
+>.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>host msdfs = no</B
+></P
+></DD
+><DT
+><A
+NAME="HOSTSALLOW"
+></A
+>hosts allow (S)</DT
+><DD
+><P
+>A synonym for this parameter is <TT
+CLASS="PARAMETER"
+><I
+>allow
+ hosts</I
+></TT
+>.</P
+><P
+>This parameter is a comma, space, or tab delimited
+ set of hosts which are permitted to access a service.</P
+><P
+>If specified in the [global] section then it will
+ apply to all services, regardless of whether the individual
+ service has a different setting.</P
+><P
+>You can specify the hosts by name or IP number. For
+ example, you could restrict access to only the hosts on a
+ Class C subnet with something like <B
+CLASS="COMMAND"
+>allow hosts = 150.203.5.
+ </B
+>. The full syntax of the list is described in the man
+ page <TT
+CLASS="FILENAME"
+>hosts_access(5)</TT
+>. Note that this man
+ page may not be present on your system, so a brief description will
+ be given here also.</P
+><P
+>Note that the localhost address 127.0.0.1 will always
+ be allowed access unless specifically denied by a <A
+HREF="#HOSTSDENY"
+><TT
+CLASS="PARAMETER"
+><I
+>hosts deny</I
+></TT
+></A
+> option.</P
+><P
+>You can also specify hosts by network/netmask pairs and
+ by netgroup names if your system supports netgroups. The
+ <EM
+>EXCEPT</EM
+> keyword can also be used to limit a
+ wildcard list. The following examples may provide some help:</P
+><P
+>Example 1: allow all IPs in 150.203.*.*; except one</P
+><P
+><B
+CLASS="COMMAND"
+>hosts allow = 150.203. EXCEPT 150.203.6.66</B
+></P
+><P
+>Example 2: allow hosts that match the given network/netmask</P
+><P
+><B
+CLASS="COMMAND"
+>hosts allow = 150.203.15.0/255.255.255.0</B
+></P
+><P
+>Example 3: allow a couple of hosts</P
+><P
+><B
+CLASS="COMMAND"
+>hosts allow = lapland, arvidsjaur</B
+></P
+><P
+>Example 4: allow only hosts in NIS netgroup "foonet", but
+ deny access from one particular host</P
+><P
+><B
+CLASS="COMMAND"
+>hosts allow = @foonet</B
+></P
+><P
+><B
+CLASS="COMMAND"
+>hosts deny = pirate</B
+></P
+><P
+>Note that access still requires suitable user-level passwords.</P
+><P
+>See <A
+HREF="testparm.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>testparm(1)</B
+>
+ </A
+> for a way of testing your host access to see if it does
+ what you expect.</P
+><P
+>Default: <EM
+>none (i.e., all hosts permitted access)
+ </EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>allow hosts = 150.203.5. myhost.mynet.edu.au
+ </B
+></P
+></DD
+><DT
+><A
+NAME="HOSTSDENY"
+></A
+>hosts deny (S)</DT
+><DD
+><P
+>The opposite of <TT
+CLASS="PARAMETER"
+><I
+>hosts allow</I
+></TT
+>
+ - hosts listed here are <EM
+>NOT</EM
+> permitted access to
+ services unless the specific services have their own lists to override
+ this one. Where the lists conflict, the <TT
+CLASS="PARAMETER"
+><I
+>allow</I
+></TT
+>
+ list takes precedence.</P
+><P
+>Default: <EM
+>none (i.e., no hosts specifically excluded)
+ </EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>hosts deny = 150.203.4. badhost.mynet.edu.au
+ </B
+></P
+></DD
+><DT
+><A
+NAME="HOSTSEQUIV"
+></A
+>hosts equiv (G)</DT
+><DD
+><P
+>If this global parameter is a non-null string,
+ it specifies the name of a file to read for the names of hosts
+ and users who will be allowed access without specifying a password.
+ </P
+><P
+>This is not be confused with <A
+HREF="#HOSTSALLOW"
+> <TT
+CLASS="PARAMETER"
+><I
+>hosts allow</I
+></TT
+></A
+> which is about hosts
+ access to services and is more useful for guest services. <TT
+CLASS="PARAMETER"
+><I
+> hosts equiv</I
+></TT
+> may be useful for NT clients which will
+ not supply passwords to Samba.</P
+><P
+><EM
+>NOTE :</EM
+> The use of <TT
+CLASS="PARAMETER"
+><I
+>hosts equiv
+ </I
+></TT
+> can be a major security hole. This is because you are
+ trusting the PC to supply the correct username. It is very easy to
+ get a PC to supply a false username. I recommend that the
+ <TT
+CLASS="PARAMETER"
+><I
+>hosts equiv</I
+></TT
+> option be only used if you really
+ know what you are doing, or perhaps on a home network where you trust
+ your spouse and kids. And only if you <EM
+>really</EM
+> trust
+ them :-).</P
+><P
+>Default: <EM
+>no host equivalences</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>hosts equiv = /etc/hosts.equiv</B
+></P
+></DD
+><DT
+><A
+NAME="INCLUDE"
+></A
+>include (G)</DT
+><DD
+><P
+>This allows you to include one config file
+ inside another. The file is included literally, as though typed
+ in place.</P
+><P
+>It takes the standard substitutions, except <TT
+CLASS="PARAMETER"
+><I
+>%u
+ </I
+></TT
+>, <TT
+CLASS="PARAMETER"
+><I
+>%P</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>%S</I
+></TT
+>.
+ </P
+><P
+>Default: <EM
+>no file included</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>include = /usr/local/samba/lib/admin_smb.conf
+ </B
+></P
+></DD
+><DT
+><A
+NAME="INHERITPERMISSIONS"
+></A
+>inherit permissions (S)</DT
+><DD
+><P
+>The permissions on new files and directories
+ are normally governed by <A
+HREF="#CREATEMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> create mask</I
+></TT
+></A
+>, <A
+HREF="#DIRECTORYMASK"
+> <TT
+CLASS="PARAMETER"
+><I
+>directory mask</I
+></TT
+></A
+>, <A
+HREF="#FORCECREATEMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+>
+ </A
+> and <A
+HREF="#FORCEDIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force
+ directory mode</I
+></TT
+></A
+> but the boolean inherit
+ permissions parameter overrides this.</P
+><P
+>New directories inherit the mode of the parent directory,
+ including bits such as setgid.</P
+><P
+>New files inherit their read/write bits from the parent
+ directory. Their execute bits continue to be determined by
+ <A
+HREF="#MAPARCHIVE"
+><TT
+CLASS="PARAMETER"
+><I
+>map archive</I
+></TT
+>
+ </A
+>, <A
+HREF="#MAPHIDDEN"
+><TT
+CLASS="PARAMETER"
+><I
+>map hidden</I
+></TT
+>
+ </A
+> and <A
+HREF="#MAPSYSTEM"
+><TT
+CLASS="PARAMETER"
+><I
+>map system</I
+></TT
+>
+ </A
+> as usual.</P
+><P
+>Note that the setuid bit is <EM
+>never</EM
+> set via
+ inheritance (the code explicitly prohibits this).</P
+><P
+>This can be particularly useful on large systems with
+ many users, perhaps several thousand, to allow a single [homes]
+ share to be used flexibly by each user.</P
+><P
+>See also <A
+HREF="#CREATEMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>create mask
+ </I
+></TT
+></A
+>, <A
+HREF="#DIRECTORYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+> directory mask</I
+></TT
+></A
+>, <A
+HREF="#FORCECREATEMODE"
+> <TT
+CLASS="PARAMETER"
+><I
+>force create mode</I
+></TT
+></A
+> and <A
+HREF="#FORCEDIRECTORYMODE"
+><TT
+CLASS="PARAMETER"
+><I
+>force directory mode</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>inherit permissions = no</B
+></P
+></DD
+><DT
+><A
+NAME="INTERFACES"
+></A
+>interfaces (G)</DT
+><DD
+><P
+>This option allows you to override the default
+ network interfaces list that Samba will use for browsing, name
+ registration and other NBT traffic. By default Samba will query
+ the kernel for the list of all active interfaces and use any
+ interfaces except 127.0.0.1 that are broadcast capable.</P
+><P
+>The option takes a list of interface strings. Each string
+ can be in any of the following forms:</P
+><P
+></P
+><UL
+><LI
+><P
+>a network interface name (such as eth0).
+ This may include shell-like wildcards so eth* will match
+ any interface starting with the substring "eth"</P
+></LI
+><LI
+><P
+>an IP address. In this case the netmask is
+ determined from the list of interfaces obtained from the
+ kernel</P
+></LI
+><LI
+><P
+>an IP/mask pair. </P
+></LI
+><LI
+><P
+>a broadcast/mask pair.</P
+></LI
+></UL
+><P
+>The "mask" parameters can either be a bit length (such
+ as 24 for a C class network) or a full netmask in dotted
+ decimal form.</P
+><P
+>The "IP" parameters above can either be a full dotted
+ decimal IP address or a hostname which will be looked up via
+ the OS's normal hostname resolution mechanisms.</P
+><P
+>For example, the following line:</P
+><P
+><B
+CLASS="COMMAND"
+>interfaces = eth0 192.168.2.10/24 192.168.3.10/255.255.255.0
+ </B
+></P
+><P
+>would configure three network interfaces corresponding
+ to the eth0 device and IP addresses 192.168.2.10 and 192.168.3.10.
+ The netmasks of the latter two interfaces would be set to 255.255.255.0.</P
+><P
+>See also <A
+HREF="#BINDINTERFACESONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>bind
+ interfaces only</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>all active interfaces except 127.0.0.1
+ that are broadcast capable</EM
+></P
+></DD
+><DT
+><A
+NAME="INVALIDUSERS"
+></A
+>invalid users (S)</DT
+><DD
+><P
+>This is a list of users that should not be allowed
+ to login to this service. This is really a <EM
+>paranoid</EM
+>
+ check to absolutely ensure an improper setting does not breach
+ your security.</P
+><P
+>A name starting with a '@' is interpreted as an NIS
+ netgroup first (if your system supports NIS), and then as a UNIX
+ group if the name was not found in the NIS netgroup database.</P
+><P
+>A name starting with '+' is interpreted only
+ by looking in the UNIX group database. A name starting with
+ '&#38;' is interpreted only by looking in the NIS netgroup database
+ (this requires NIS to be working on your system). The characters
+ '+' and '&#38;' may be used at the start of the name in either order
+ so the value <TT
+CLASS="PARAMETER"
+><I
+>+&#38;group</I
+></TT
+> means check the
+ UNIX group database, followed by the NIS netgroup database, and
+ the value <TT
+CLASS="PARAMETER"
+><I
+>&#38;+group</I
+></TT
+> means check the NIS
+ netgroup database, followed by the UNIX group database (the
+ same as the '@' prefix).</P
+><P
+>The current servicename is substituted for <TT
+CLASS="PARAMETER"
+><I
+>%S</I
+></TT
+>.
+ This is useful in the [homes] section.</P
+><P
+>See also <A
+HREF="#VALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>valid users
+ </I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>no invalid users</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>invalid users = root fred admin @wheel
+ </B
+></P
+></DD
+><DT
+><A
+NAME="KEEPALIVE"
+></A
+>keepalive (G)</DT
+><DD
+><P
+>The value of the parameter (an integer) represents
+ the number of seconds between <TT
+CLASS="PARAMETER"
+><I
+>keepalive</I
+></TT
+>
+ packets. If this parameter is zero, no keepalive packets will be
+ sent. Keepalive packets, if sent, allow the server to tell whether
+ a client is still present and responding.</P
+><P
+>Keepalives should, in general, not be needed if the socket
+ being used has the SO_KEEPALIVE attribute set on it (see <A
+HREF="#SOCKETOPTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>socket options</I
+></TT
+></A
+>).
+ Basically you should only use this option if you strike difficulties.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>keepalive = 300</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>keepalive = 600</B
+></P
+></DD
+><DT
+><A
+NAME="KERNELOPLOCKS"
+></A
+>kernel oplocks (G)</DT
+><DD
+><P
+>For UNIXes that support kernel based <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+></A
+>
+ (currently only IRIX and the Linux 2.4 kernel), this parameter
+ allows the use of them to be turned on or off.</P
+><P
+>Kernel oplocks support allows Samba <TT
+CLASS="PARAMETER"
+><I
+>oplocks
+ </I
+></TT
+> to be broken whenever a local UNIX process or NFS operation
+ accesses a file that <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+>
+ </A
+> has oplocked. This allows complete data consistency between
+ SMB/CIFS, NFS and local file access (and is a <EM
+>very</EM
+>
+ cool feature :-).</P
+><P
+>This parameter defaults to <TT
+CLASS="CONSTANT"
+>on</TT
+>, but is translated
+ to a no-op on systems that no not have the necessary kernel support.
+ You should never need to touch this parameter.</P
+><P
+>See also the <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+>
+ </A
+> and <A
+HREF="#LEVEL2OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>level2 oplocks
+ </I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>kernel oplocks = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LANMANAUTH"
+></A
+>lanman auth (G)</DT
+><DD
+><P
+>This parameter determines whether or not <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> will
+ attempt to authenticate users using the LANMAN password hash.
+ If disabled, only clients which support NT password hashes (e.g. Windows
+ NT/2000 clients, smbclient, etc... but not Windows 95/98 or the MS DOS
+ network client) will be able to connect to the Samba host.</P
+><P
+>Default : <B
+CLASS="COMMAND"
+>lanman auth = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LARGEREADWRITE"
+></A
+>large readwrite (G)</DT
+><DD
+><P
+>This parameter determines whether or not <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+>
+ supports the new 64k streaming read and write varient SMB requests introduced
+ with Windows 2000. Note that due to Windows 2000 client redirector bugs
+ this requires Samba to be running on a 64-bit capable operating system such
+ as IRIX, Solaris or a Linux 2.4 kernel. Can improve performance by 10% with
+ Windows 2000 clients. Defaults to off. Not as tested as some other Samba
+ code paths.
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>large readwrite = no</B
+></P
+></DD
+><DT
+><A
+NAME="LDAPADMINDN"
+></A
+>ldap admin dn (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+> The <TT
+CLASS="PARAMETER"
+><I
+>ldap admin dn</I
+></TT
+> defines the Distinguished
+ Name (DN) name used by Samba to contact the <A
+HREF="#LDAPSERVER"
+>ldap
+ server</A
+> when retreiving user account information. The <TT
+CLASS="PARAMETER"
+><I
+>ldap
+ admin dn</I
+></TT
+> is used in conjunction with the admin dn password
+ stored in the <TT
+CLASS="FILENAME"
+>private/secrets.tdb</TT
+> file. See the
+ <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+> man
+ page for more information on how to accmplish this.
+ </P
+><P
+>Default : <EM
+>none</EM
+></P
+></DD
+><DT
+><A
+NAME="LDAPFILTER"
+></A
+>ldap filter (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+> This parameter specifies the RFC 2254 compliant LDAP search filter.
+ The default is to match the login name with the <TT
+CLASS="CONSTANT"
+>uid</TT
+>
+ attribute for all entries matching the <TT
+CLASS="CONSTANT"
+>sambaAccount</TT
+>
+ objectclass. Note that this filter should only return one entry.
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>ldap filter = (&#38;(uid=%u)(objectclass=sambaAccount))</B
+></P
+></DD
+><DT
+><A
+NAME="LDAPPORT"
+></A
+>ldap port (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+> This option is used to control the tcp port number used to contact
+ the <A
+HREF="#LDAPSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap server</I
+></TT
+></A
+>.
+ The default is to use the stand LDAP port 389.
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>ldap port = 389</B
+></P
+></DD
+><DT
+><A
+NAME="LDAPSERVER"
+></A
+>ldap server (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+> This parameter should contains the FQDN of the ldap directory
+ server which should be queried to locate user account information.
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>ldap server = localhost</B
+></P
+></DD
+><DT
+><A
+NAME="LDAPSSL"
+></A
+>ldap ssl (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+> This option is used to define whether or not Samba should
+ use SSL when connecting to the <A
+HREF="#LDAPSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap
+ server</I
+></TT
+></A
+>. This is <EM
+>NOT</EM
+> related to
+ Samba SSL support which is enabled by specifying the
+ <B
+CLASS="COMMAND"
+>--with-ssl</B
+> option to the <TT
+CLASS="FILENAME"
+>configure</TT
+>
+ script (see <A
+HREF="#SSL"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl</I
+></TT
+></A
+>).
+ </P
+><P
+> The <TT
+CLASS="PARAMETER"
+><I
+>ldap ssl</I
+></TT
+> can be set to one of three values:
+ (a) <B
+CLASS="COMMAND"
+>on</B
+> - Always use SSL when contacting the
+ <TT
+CLASS="PARAMETER"
+><I
+>ldap server</I
+></TT
+>, (b) <B
+CLASS="COMMAND"
+>off</B
+> -
+ Never use SSL when querying the directory, or (c) <B
+CLASS="COMMAND"
+>start
+ tls</B
+> - Use the LDAPv3 StartTLS extended operation
+ (RFC2830) for communicating with the directory server.
+ </P
+><P
+>Default : <B
+CLASS="COMMAND"
+>ldap ssl = off</B
+></P
+></DD
+><DT
+><A
+NAME="LDAPSUFFIX"
+></A
+>ldap suffix (G)</DT
+><DD
+><P
+>This parameter is only available if Samba has been
+ configure to include the <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option
+ at compile time. This option should be considered experimental and
+ under active development.
+ </P
+><P
+>Default : <EM
+>none</EM
+></P
+></DD
+><DT
+><A
+NAME="LEVEL2OPLOCKS"
+></A
+>level2 oplocks (S)</DT
+><DD
+><P
+>This parameter controls whether Samba supports
+ level2 (read-only) oplocks on a share.</P
+><P
+>Level2, or read-only oplocks allow Windows NT clients
+ that have an oplock on a file to downgrade from a read-write oplock
+ to a read-only oplock once a second client opens the file (instead
+ of releasing all oplocks on a second open, as in traditional,
+ exclusive oplocks). This allows all openers of the file that
+ support level2 oplocks to cache the file for read-ahead only (ie.
+ they may not cache writes or lock requests) and increases performance
+ for many accesses of files that are not commonly written (such as
+ application .EXE files).</P
+><P
+>Once one of the clients which have a read-only oplock
+ writes to the file all clients are notified (no reply is needed
+ or waited for) and told to break their oplocks to "none" and
+ delete any read-ahead caches.</P
+><P
+>It is recommended that this parameter be turned on
+ to speed access to shared executables.</P
+><P
+>For more discussions on level2 oplocks see the CIFS spec.</P
+><P
+>Currently, if <A
+HREF="#KERNELOPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>kernel
+ oplocks</I
+></TT
+></A
+> are supported then level2 oplocks are
+ not granted (even if this parameter is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>).
+ Note also, the <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+>
+ </A
+> parameter must be set to <TT
+CLASS="CONSTANT"
+>true</TT
+> on this share in order for
+ this parameter to have any effect.</P
+><P
+>See also the <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+>
+ </A
+> and <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>kernel oplocks</I
+></TT
+>
+ </A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>level2 oplocks = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LMANNOUNCE"
+></A
+>lm announce (G)</DT
+><DD
+><P
+>This parameter determines if <A
+HREF="nmbd.8.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+> will produce Lanman announce
+ broadcasts that are needed by OS/2 clients in order for them to see
+ the Samba server in their browse list. This parameter can have three
+ values, <TT
+CLASS="CONSTANT"
+>true</TT
+>, <TT
+CLASS="CONSTANT"
+>false</TT
+>, or
+ <TT
+CLASS="CONSTANT"
+>auto</TT
+>. The default is <TT
+CLASS="CONSTANT"
+>auto</TT
+>.
+ If set to <TT
+CLASS="CONSTANT"
+>false</TT
+> Samba will never produce these
+ broadcasts. If set to <TT
+CLASS="CONSTANT"
+>true</TT
+> Samba will produce
+ Lanman announce broadcasts at a frequency set by the parameter
+ <TT
+CLASS="PARAMETER"
+><I
+>lm interval</I
+></TT
+>. If set to <TT
+CLASS="CONSTANT"
+>auto</TT
+>
+ Samba will not send Lanman announce broadcasts by default but will
+ listen for them. If it hears such a broadcast on the wire it will
+ then start sending them at a frequency set by the parameter
+ <TT
+CLASS="PARAMETER"
+><I
+>lm interval</I
+></TT
+>.</P
+><P
+>See also <A
+HREF="#LMINTERVAL"
+><TT
+CLASS="PARAMETER"
+><I
+>lm interval
+ </I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>lm announce = auto</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>lm announce = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LMINTERVAL"
+></A
+>lm interval (G)</DT
+><DD
+><P
+>If Samba is set to produce Lanman announce
+ broadcasts needed by OS/2 clients (see the <A
+HREF="#LMANNOUNCE"
+> <TT
+CLASS="PARAMETER"
+><I
+>lm announce</I
+></TT
+></A
+> parameter) then this
+ parameter defines the frequency in seconds with which they will be
+ made. If this is set to zero then no Lanman announcements will be
+ made despite the setting of the <TT
+CLASS="PARAMETER"
+><I
+>lm announce</I
+></TT
+>
+ parameter.</P
+><P
+>See also <A
+HREF="#LMANNOUNCE"
+><TT
+CLASS="PARAMETER"
+><I
+>lm
+ announce</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>lm interval = 60</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>lm interval = 120</B
+></P
+></DD
+><DT
+><A
+NAME="LOADPRINTERS"
+></A
+>load printers (G)</DT
+><DD
+><P
+>A boolean variable that controls whether all
+ printers in the printcap will be loaded for browsing by default.
+ See the <A
+HREF="#AEN79"
+>printers</A
+> section for
+ more details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>load printers = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LOCALMASTER"
+></A
+>local master (G)</DT
+><DD
+><P
+>This option allows <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> nmbd(8)</B
+></A
+> to try and become a local master browser
+ on a subnet. If set to <TT
+CLASS="CONSTANT"
+>false</TT
+> then <B
+CLASS="COMMAND"
+> nmbd</B
+> will not attempt to become a local master browser
+ on a subnet and will also lose in all browsing elections. By
+ default this value is set to <TT
+CLASS="CONSTANT"
+>true</TT
+>. Setting this value to <TT
+CLASS="CONSTANT"
+>true</TT
+> doesn't
+ mean that Samba will <EM
+>become</EM
+> the local master
+ browser on a subnet, just that <B
+CLASS="COMMAND"
+>nmbd</B
+> will <EM
+> participate</EM
+> in elections for local master browser.</P
+><P
+>Setting this value to <TT
+CLASS="CONSTANT"
+>false</TT
+> will cause <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ <EM
+>never</EM
+> to become a local master browser.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>local master = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LOCKDIR"
+></A
+>lock dir (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#LOCKDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+> lock directory</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="LOCKDIRECTORY"
+></A
+>lock directory (G)</DT
+><DD
+><P
+>This option specifies the directory where lock
+ files will be placed. The lock files are used to implement the
+ <A
+HREF="#MAXCONNECTIONS"
+><TT
+CLASS="PARAMETER"
+><I
+>max connections</I
+></TT
+>
+ </A
+> option.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>lock directory = ${prefix}/var/locks</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>lock directory = /var/run/samba/locks</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="LOCKING"
+></A
+>locking (S)</DT
+><DD
+><P
+>This controls whether or not locking will be
+ performed by the server in response to lock requests from the
+ client.</P
+><P
+>If <B
+CLASS="COMMAND"
+>locking = no</B
+>, all lock and unlock
+ requests will appear to succeed and all lock queries will report
+ that the file in question is available for locking.</P
+><P
+>If <B
+CLASS="COMMAND"
+>locking = yes</B
+>, real locking will be performed
+ by the server.</P
+><P
+>This option <EM
+>may</EM
+> be useful for read-only
+ filesystems which <EM
+>may</EM
+> not need locking (such as
+ CDROM drives), although setting this parameter of <TT
+CLASS="CONSTANT"
+>no</TT
+>
+ is not really recommended even in this case.</P
+><P
+>Be careful about disabling locking either globally or in a
+ specific service, as lack of locking may result in data corruption.
+ You should never need to set this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>locking = yes</B
+></P
+></DD
+><DT
+><A
+NAME="LOGFILE"
+></A
+>log file (G)</DT
+><DD
+><P
+>This option allows you to override the name
+ of the Samba log file (also known as the debug file).</P
+><P
+>This option takes the standard substitutions, allowing
+ you to have separate log files for each user or machine.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>log file = /usr/local/samba/var/log.%m
+ </B
+></P
+></DD
+><DT
+><A
+NAME="LOGLEVEL"
+></A
+>log level (G)</DT
+><DD
+><P
+>The value of the parameter (an integer) allows
+ the debug level (logging level) to be specified in the
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. This is to give greater
+ flexibility in the configuration of the system.</P
+><P
+>The default will be the log level specified on
+ the command line or level zero if none was specified.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>log level = 3</B
+></P
+></DD
+><DT
+><A
+NAME="LOGONDRIVE"
+></A
+>logon drive (G)</DT
+><DD
+><P
+>This parameter specifies the local path to
+ which the home directory will be connected (see <A
+HREF="#LOGONHOME"
+><TT
+CLASS="PARAMETER"
+><I
+>logon home</I
+></TT
+></A
+>)
+ and is only used by NT Workstations. </P
+><P
+>Note that this option is only useful if Samba is set up as a
+ logon server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>logon drive = z:</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>logon drive = h:</B
+></P
+></DD
+><DT
+><A
+NAME="LOGONHOME"
+></A
+>logon home (G)</DT
+><DD
+><P
+>This parameter specifies the home directory
+ location when a Win95/98 or NT Workstation logs into a Samba PDC.
+ It allows you to do </P
+><P
+><TT
+CLASS="PROMPT"
+>C:\&#62; </TT
+><TT
+CLASS="USERINPUT"
+><B
+>NET USE H: /HOME</B
+></TT
+>
+ </P
+><P
+>from a command prompt, for example.</P
+><P
+>This option takes the standard substitutions, allowing
+ you to have separate logon scripts for each user or machine.</P
+><P
+>This parameter can be used with Win9X workstations to ensure
+ that roaming profiles are stored in a subdirectory of the user's
+ home directory. This is done in the following way:</P
+><P
+><B
+CLASS="COMMAND"
+>logon home = \\%N\%U\profile</B
+></P
+><P
+>This tells Samba to return the above string, with
+ substitutions made when a client requests the info, generally
+ in a NetUserGetInfo request. Win9X clients truncate the info to
+ \\server\share when a user does <B
+CLASS="COMMAND"
+>net use /home</B
+>
+ but use the whole string when dealing with profiles.</P
+><P
+>Note that in prior versions of Samba, the <A
+HREF="#LOGONPATH"
+> <TT
+CLASS="PARAMETER"
+><I
+>logon path</I
+></TT
+></A
+> was returned rather than
+ <TT
+CLASS="PARAMETER"
+><I
+>logon home</I
+></TT
+>. This broke <B
+CLASS="COMMAND"
+>net use
+ /home</B
+> but allowed profiles outside the home directory.
+ The current implementation is correct, and can be used for
+ profiles if you use the above trick.</P
+><P
+>This option is only useful if Samba is set up as a logon
+ server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>logon home = "\\%N\%U"</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>logon home = "\\remote_smb_server\%U"</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="LOGONPATH"
+></A
+>logon path (G)</DT
+><DD
+><P
+>This parameter specifies the home directory
+ where roaming profiles (NTuser.dat etc files for Windows NT) are
+ stored. Contrary to previous versions of these manual pages, it has
+ nothing to do with Win 9X roaming profiles. To find out how to
+ handle roaming profiles for Win 9X system, see the <A
+HREF="#LOGONHOME"
+> <TT
+CLASS="PARAMETER"
+><I
+>logon home</I
+></TT
+></A
+> parameter.</P
+><P
+>This option takes the standard substitutions, allowing you
+ to have separate logon scripts for each user or machine. It also
+ specifies the directory from which the "Application Data",
+ (<TT
+CLASS="FILENAME"
+>desktop</TT
+>, <TT
+CLASS="FILENAME"
+>start menu</TT
+>,
+ <TT
+CLASS="FILENAME"
+>network neighborhood</TT
+>, <TT
+CLASS="FILENAME"
+>programs</TT
+>
+ and other folders, and their contents, are loaded and displayed on
+ your Windows NT client.</P
+><P
+>The share and the path must be readable by the user for
+ the preferences and directories to be loaded onto the Windows NT
+ client. The share must be writeable when the user logs in for the first
+ time, in order that the Windows NT client can create the NTuser.dat
+ and other directories.</P
+><P
+>Thereafter, the directories and any of the contents can,
+ if required, be made read-only. It is not advisable that the
+ NTuser.dat file be made read-only - rename it to NTuser.man to
+ achieve the desired effect (a <EM
+>MAN</EM
+>datory
+ profile). </P
+><P
+>Windows clients can sometimes maintain a connection to
+ the [homes] share, even though there is no user logged in.
+ Therefore, it is vital that the logon path does not include a
+ reference to the homes share (i.e. setting this parameter to
+ \%N\%U\profile_path will cause problems).</P
+><P
+>This option takes the standard substitutions, allowing
+ you to have separate logon scripts for each user or machine.</P
+><P
+>Note that this option is only useful if Samba is set up
+ as a logon server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>logon path = \\%N\%U\profile</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>logon path = \\PROFILESERVER\PROFILE\%U</B
+></P
+></DD
+><DT
+><A
+NAME="LOGONSCRIPT"
+></A
+>logon script (G)</DT
+><DD
+><P
+>This parameter specifies the batch file (.bat) or
+ NT command file (.cmd) to be downloaded and run on a machine when
+ a user successfully logs in. The file must contain the DOS
+ style CR/LF line endings. Using a DOS-style editor to create the
+ file is recommended.</P
+><P
+>The script must be a relative path to the [netlogon]
+ service. If the [netlogon] service specifies a <A
+HREF="#PATH"
+> <TT
+CLASS="PARAMETER"
+><I
+>path</I
+></TT
+></A
+> of <TT
+CLASS="FILENAME"
+>/usr/local/samba/netlogon
+ </TT
+>, and <B
+CLASS="COMMAND"
+>logon script = STARTUP.BAT</B
+>, then
+ the file that will be downloaded is:</P
+><P
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/netlogon/STARTUP.BAT</TT
+></P
+><P
+>The contents of the batch file are entirely your choice. A
+ suggested command would be to add <B
+CLASS="COMMAND"
+>NET TIME \\SERVER /SET
+ /YES</B
+>, to force every machine to synchronize clocks with
+ the same time server. Another use would be to add <B
+CLASS="COMMAND"
+>NET USE
+ U: \\SERVER\UTILS</B
+> for commonly used utilities, or <B
+CLASS="COMMAND"
+> NET USE Q: \\SERVER\ISO9001_QA</B
+> for example.</P
+><P
+>Note that it is particularly important not to allow write
+ access to the [netlogon] share, or to grant users write permission
+ on the batch files in a secure environment, as this would allow
+ the batch files to be arbitrarily modified and security to be
+ breached.</P
+><P
+>This option takes the standard substitutions, allowing you
+ to have separate logon scripts for each user or machine.</P
+><P
+>This option is only useful if Samba is set up as a logon
+ server.</P
+><P
+>Default: <EM
+>no logon script defined</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>logon script = scripts\%U.bat</B
+></P
+></DD
+><DT
+><A
+NAME="LPPAUSECOMMAND"
+></A
+>lppause command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to stop printing or spooling
+ a specific print job.</P
+><P
+>This command should be a program or script which takes
+ a printer name and job number to pause the print job. One way
+ of implementing this is by using job priorities, where jobs
+ having a too low priority won't be sent to the printer.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. A <TT
+CLASS="PARAMETER"
+><I
+>%j</I
+></TT
+> is replaced with
+ the job number (an integer). On HPUX (see <TT
+CLASS="PARAMETER"
+><I
+>printing=hpux
+ </I
+></TT
+>), if the <TT
+CLASS="PARAMETER"
+><I
+>-p%p</I
+></TT
+> option is added
+ to the lpq command, the job will show up with the correct status, i.e.
+ if the job priority is lower than the set fence priority it will
+ have the PAUSED status, whereas if the priority is equal or higher it
+ will have the SPOOLED or PRINTING status.</P
+><P
+>Note that it is good practice to include the absolute path
+ in the lppause command as the PATH may not be available to the server.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: Currently no default value is given to
+ this string, unless the value of the <TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+>
+ parameter is <TT
+CLASS="CONSTANT"
+>SYSV</TT
+>, in which case the default is :</P
+><P
+><B
+CLASS="COMMAND"
+>lp -i %p-%j -H hold</B
+></P
+><P
+>or if the value of the <TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+> parameter
+ is <TT
+CLASS="CONSTANT"
+>SOFTQ</TT
+>, then the default is:</P
+><P
+><B
+CLASS="COMMAND"
+>qstat -s -j%j -h</B
+></P
+><P
+>Example for HPUX: <B
+CLASS="COMMAND"
+>lppause command = /usr/bin/lpalt
+ %p-%j -p0</B
+></P
+></DD
+><DT
+><A
+NAME="LPQCACHETIME"
+></A
+>lpq cache time (G)</DT
+><DD
+><P
+>This controls how long lpq info will be cached
+ for to prevent the <B
+CLASS="COMMAND"
+>lpq</B
+> command being called too
+ often. A separate cache is kept for each variation of the <B
+CLASS="COMMAND"
+> lpq</B
+> command used by the system, so if you use different
+ <B
+CLASS="COMMAND"
+>lpq</B
+> commands for different users then they won't
+ share cache information.</P
+><P
+>The cache files are stored in <TT
+CLASS="FILENAME"
+>/tmp/lpq.xxxx</TT
+>
+ where xxxx is a hash of the <B
+CLASS="COMMAND"
+>lpq</B
+> command in use.</P
+><P
+>The default is 10 seconds, meaning that the cached results
+ of a previous identical <B
+CLASS="COMMAND"
+>lpq</B
+> command will be used
+ if the cached data is less than 10 seconds old. A large value may
+ be advisable if your <B
+CLASS="COMMAND"
+>lpq</B
+> command is very slow.</P
+><P
+>A value of 0 will disable caching completely.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>lpq cache time = 10</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>lpq cache time = 30</B
+></P
+></DD
+><DT
+><A
+NAME="LPQCOMMAND"
+></A
+>lpq command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to obtain <B
+CLASS="COMMAND"
+>lpq
+ </B
+>-style printer status information.</P
+><P
+>This command should be a program or script which
+ takes a printer name as its only parameter and outputs printer
+ status information.</P
+><P
+>Currently eight styles of printer status information
+ are supported; BSD, AIX, LPRNG, PLP, SYSV, HPUX, QNX and SOFTQ.
+ This covers most UNIX systems. You control which type is expected
+ using the <TT
+CLASS="PARAMETER"
+><I
+>printing =</I
+></TT
+> option.</P
+><P
+>Some clients (notably Windows for Workgroups) may not
+ correctly send the connection number for the printer they are
+ requesting status information about. To get around this, the
+ server reports on the first printer service connected to by the
+ client. This only happens if the connection number sent is invalid.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the
+ command.</P
+><P
+>Note that it is good practice to include the absolute path
+ in the <TT
+CLASS="PARAMETER"
+><I
+>lpq command</I
+></TT
+> as the <TT
+CLASS="ENVAR"
+>$PATH
+ </TT
+> may not be available to the server.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <EM
+>depends on the setting of <TT
+CLASS="PARAMETER"
+><I
+> printing</I
+></TT
+></EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>lpq command = /usr/bin/lpq -P%p</B
+></P
+></DD
+><DT
+><A
+NAME="LPRESUMECOMMAND"
+></A
+>lpresume command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to restart or continue
+ printing or spooling a specific print job.</P
+><P
+>This command should be a program or script which takes
+ a printer name and job number to resume the print job. See
+ also the <A
+HREF="#LPPAUSECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>lppause command
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. A <TT
+CLASS="PARAMETER"
+><I
+>%j</I
+></TT
+> is replaced with
+ the job number (an integer).</P
+><P
+>Note that it is good practice to include the absolute path
+ in the <TT
+CLASS="PARAMETER"
+><I
+>lpresume command</I
+></TT
+> as the PATH may not
+ be available to the server.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: Currently no default value is given
+ to this string, unless the value of the <TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+>
+ parameter is <TT
+CLASS="CONSTANT"
+>SYSV</TT
+>, in which case the default is :</P
+><P
+><B
+CLASS="COMMAND"
+>lp -i %p-%j -H resume</B
+></P
+><P
+>or if the value of the <TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+> parameter
+ is <TT
+CLASS="CONSTANT"
+>SOFTQ</TT
+>, then the default is:</P
+><P
+><B
+CLASS="COMMAND"
+>qstat -s -j%j -r</B
+></P
+><P
+>Example for HPUX: <B
+CLASS="COMMAND"
+>lpresume command = /usr/bin/lpalt
+ %p-%j -p2</B
+></P
+></DD
+><DT
+><A
+NAME="LPRMCOMMAND"
+></A
+>lprm command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to delete a print job.</P
+><P
+>This command should be a program or script which takes
+ a printer name and job number, and deletes the print job.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. A <TT
+CLASS="PARAMETER"
+><I
+>%j</I
+></TT
+> is replaced with
+ the job number (an integer).</P
+><P
+>Note that it is good practice to include the absolute
+ path in the <TT
+CLASS="PARAMETER"
+><I
+>lprm command</I
+></TT
+> as the PATH may not be
+ available to the server.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <EM
+>depends on the setting of <TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></EM
+></P
+><P
+>Example 1: <B
+CLASS="COMMAND"
+>lprm command = /usr/bin/lprm -P%p %j
+ </B
+></P
+><P
+>Example 2: <B
+CLASS="COMMAND"
+>lprm command = /usr/bin/cancel %p-%j
+ </B
+></P
+></DD
+><DT
+><A
+NAME="MACHINEPASSWORDTIMEOUT"
+></A
+>machine password timeout (G)</DT
+><DD
+><P
+>If a Samba server is a member of a Windows
+ NT Domain (see the <A
+HREF="#SECURITYEQUALSDOMAIN"
+>security = domain</A
+>)
+ parameter) then periodically a running <A
+HREF="smbd.8.html"
+TARGET="_top"
+> smbd(8)</A
+> process will try and change the MACHINE ACCOUNT
+ PASSWORD stored in the TDB called <TT
+CLASS="FILENAME"
+>private/secrets.tdb
+ </TT
+>. This parameter specifies how often this password
+ will be changed, in seconds. The default is one week (expressed in
+ seconds), the same as a Windows NT Domain member server.</P
+><P
+>See also <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)
+ </B
+></A
+>, and the <A
+HREF="#SECURITYEQUALSDOMAIN"
+> security = domain</A
+>) parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>machine password timeout = 604800</B
+></P
+></DD
+><DT
+><A
+NAME="MAGICOUTPUT"
+></A
+>magic output (S)</DT
+><DD
+><P
+>This parameter specifies the name of a file
+ which will contain output created by a magic script (see the
+ <A
+HREF="#MAGICSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>magic script</I
+></TT
+></A
+>
+ parameter below).</P
+><P
+>Warning: If two clients use the same <TT
+CLASS="PARAMETER"
+><I
+>magic script
+ </I
+></TT
+> in the same directory the output file content
+ is undefined.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>magic output = &#60;magic script name&#62;.out
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>magic output = myfile.txt</B
+></P
+></DD
+><DT
+><A
+NAME="MAGICSCRIPT"
+></A
+>magic script (S)</DT
+><DD
+><P
+>This parameter specifies the name of a file which,
+ if opened, will be executed by the server when the file is closed.
+ This allows a UNIX script to be sent to the Samba host and
+ executed on behalf of the connected user.</P
+><P
+>Scripts executed in this way will be deleted upon
+ completion assuming that the user has the appropriate level
+ of privilege and the file permissions allow the deletion.</P
+><P
+>If the script generates output, output will be sent to
+ the file specified by the <A
+HREF="#MAGICOUTPUT"
+><TT
+CLASS="PARAMETER"
+><I
+> magic output</I
+></TT
+></A
+> parameter (see above).</P
+><P
+>Note that some shells are unable to interpret scripts
+ containing CR/LF instead of CR as
+ the end-of-line marker. Magic scripts must be executable
+ <EM
+>as is</EM
+> on the host, which for some hosts and
+ some shells will require filtering at the DOS end.</P
+><P
+>Magic scripts are <EM
+>EXPERIMENTAL</EM
+> and
+ should <EM
+>NOT</EM
+> be relied upon.</P
+><P
+>Default: <EM
+>None. Magic scripts disabled.</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>magic script = user.csh</B
+></P
+></DD
+><DT
+><A
+NAME="MANGLECASE"
+></A
+>mangle case (S)</DT
+><DD
+><P
+>See the section on <A
+HREF="#AEN202"
+> NAME MANGLING</A
+></P
+><P
+>Default: <B
+CLASS="COMMAND"
+>mangle case = no</B
+></P
+></DD
+><DT
+><A
+NAME="MANGLEDMAP"
+></A
+>mangled map (S)</DT
+><DD
+><P
+>This is for those who want to directly map UNIX
+ file names which cannot be represented on Windows/DOS. The mangling
+ of names is not always what is needed. In particular you may have
+ documents with file extensions that differ between DOS and UNIX.
+ For example, under UNIX it is common to use <TT
+CLASS="FILENAME"
+>.html</TT
+>
+ for HTML files, whereas under Windows/DOS <TT
+CLASS="FILENAME"
+>.htm</TT
+>
+ is more commonly used.</P
+><P
+>So to map <TT
+CLASS="FILENAME"
+>html</TT
+> to <TT
+CLASS="FILENAME"
+>htm</TT
+>
+ you would use:</P
+><P
+><B
+CLASS="COMMAND"
+>mangled map = (*.html *.htm)</B
+></P
+><P
+>One very useful case is to remove the annoying <TT
+CLASS="FILENAME"
+>;1
+ </TT
+> off the ends of filenames on some CDROMs (only visible
+ under some UNIXes). To do this use a map of (*;1 *;).</P
+><P
+>Default: <EM
+>no mangled map</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>mangled map = (*;1 *;)</B
+></P
+></DD
+><DT
+><A
+NAME="MANGLEDNAMES"
+></A
+>mangled names (S)</DT
+><DD
+><P
+>This controls whether non-DOS names under UNIX
+ should be mapped to DOS-compatible names ("mangled") and made visible,
+ or whether non-DOS names should simply be ignored.</P
+><P
+>See the section on <A
+HREF="#AEN202"
+> NAME MANGLING</A
+> for details on how to control the mangling process.</P
+><P
+>If mangling is used then the mangling algorithm is as follows:</P
+><P
+></P
+><UL
+><LI
+><P
+>The first (up to) five alphanumeric characters
+ before the rightmost dot of the filename are preserved, forced
+ to upper case, and appear as the first (up to) five characters
+ of the mangled name.</P
+></LI
+><LI
+><P
+>A tilde "~" is appended to the first part of the mangled
+ name, followed by a two-character unique sequence, based on the
+ original root name (i.e., the original filename minus its final
+ extension). The final extension is included in the hash calculation
+ only if it contains any upper case characters or is longer than three
+ characters.</P
+><P
+>Note that the character to use may be specified using
+ the <A
+HREF="#MANGLINGCHAR"
+><TT
+CLASS="PARAMETER"
+><I
+>mangling char</I
+></TT
+>
+ </A
+> option, if you don't like '~'.</P
+></LI
+><LI
+><P
+>The first three alphanumeric characters of the final
+ extension are preserved, forced to upper case and appear as the
+ extension of the mangled name. The final extension is defined as that
+ part of the original filename after the rightmost dot. If there are no
+ dots in the filename, the mangled name will have no extension (except
+ in the case of "hidden files" - see below).</P
+></LI
+><LI
+><P
+>Files whose UNIX name begins with a dot will be
+ presented as DOS hidden files. The mangled name will be created as
+ for other filenames, but with the leading dot removed and "___" as
+ its extension regardless of actual original extension (that's three
+ underscores).</P
+></LI
+></UL
+><P
+>The two-digit hash value consists of upper case
+ alphanumeric characters.</P
+><P
+>This algorithm can cause name collisions only if files
+ in a directory share the same first five alphanumeric characters.
+ The probability of such a clash is 1/1300.</P
+><P
+>The name mangling (if enabled) allows a file to be
+ copied between UNIX directories from Windows/DOS while retaining
+ the long UNIX filename. UNIX files can be renamed to a new extension
+ from Windows/DOS and will retain the same basename. Mangled names
+ do not change between sessions.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>mangled names = yes</B
+></P
+></DD
+><DT
+><A
+NAME="MANGLEDSTACK"
+></A
+>mangled stack (G)</DT
+><DD
+><P
+>This parameter controls the number of mangled names
+ that should be cached in the Samba server <A
+HREF="smbd.8.html"
+TARGET="_top"
+> smbd(8)</A
+>.</P
+><P
+>This stack is a list of recently mangled base names
+ (extensions are only maintained if they are longer than 3 characters
+ or contains upper case characters).</P
+><P
+>The larger this value, the more likely it is that mangled
+ names can be successfully converted to correct long UNIX names.
+ However, large stack sizes will slow most directory accesses. Smaller
+ stacks save memory in the server (each stack element costs 256 bytes).
+ </P
+><P
+>It is not possible to absolutely guarantee correct long
+ filenames, so be prepared for some surprises!</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>mangled stack = 50</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>mangled stack = 100</B
+></P
+></DD
+><DT
+><A
+NAME="MANGLINGCHAR"
+></A
+>mangling char (S)</DT
+><DD
+><P
+>This controls what character is used as
+ the <EM
+>magic</EM
+> character in <A
+HREF="#AEN202"
+>name mangling</A
+>. The default is a '~'
+ but this may interfere with some software. Use this option to set
+ it to whatever you prefer.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>mangling char = ~</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>mangling char = ^</B
+></P
+></DD
+><DT
+><A
+NAME="MAPARCHIVE"
+></A
+>map archive (S)</DT
+><DD
+><P
+>This controls whether the DOS archive attribute
+ should be mapped to the UNIX owner execute bit. The DOS archive bit
+ is set when a file has been modified since its last backup. One
+ motivation for this option it to keep Samba/your PC from making
+ any file it touches from becoming executable under UNIX. This can
+ be quite annoying for shared source code, documents, etc...</P
+><P
+>Note that this requires the <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+>
+ parameter to be set such that owner execute bit is not masked out
+ (i.e. it must include 100). See the parameter <A
+HREF="#CREATEMASK"
+> <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></A
+> for details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>map archive = yes</B
+></P
+></DD
+><DT
+><A
+NAME="MAPHIDDEN"
+></A
+>map hidden (S)</DT
+><DD
+><P
+>This controls whether DOS style hidden files
+ should be mapped to the UNIX world execute bit.</P
+><P
+>Note that this requires the <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+>
+ to be set such that the world execute bit is not masked out (i.e.
+ it must include 001). See the parameter <A
+HREF="#CREATEMASK"
+> <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></A
+> for details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>map hidden = no</B
+></P
+></DD
+><DT
+><A
+NAME="MAPSYSTEM"
+></A
+>map system (S)</DT
+><DD
+><P
+>This controls whether DOS style system files
+ should be mapped to the UNIX group execute bit.</P
+><P
+>Note that this requires the <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+>
+ to be set such that the group execute bit is not masked out (i.e.
+ it must include 010). See the parameter <A
+HREF="#CREATEMASK"
+> <TT
+CLASS="PARAMETER"
+><I
+>create mask</I
+></TT
+></A
+> for details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>map system = no</B
+></P
+></DD
+><DT
+><A
+NAME="MAPTOGUEST"
+></A
+>map to guest (G)</DT
+><DD
+><P
+>This parameter is only useful in <A
+HREF="#SECURITY"
+> security</A
+> modes other than <TT
+CLASS="PARAMETER"
+><I
+>security = share</I
+></TT
+>
+ - i.e. <TT
+CLASS="CONSTANT"
+>user</TT
+>, <TT
+CLASS="CONSTANT"
+>server</TT
+>,
+ and <TT
+CLASS="CONSTANT"
+>domain</TT
+>.</P
+><P
+>This parameter can take three different values, which tell
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> what to do with user
+ login requests that don't match a valid UNIX user in some way.</P
+><P
+>The three settings are :</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>Never</TT
+> - Means user login
+ requests with an invalid password are rejected. This is the
+ default.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>Bad User</TT
+> - Means user
+ logins with an invalid password are rejected, unless the username
+ does not exist, in which case it is treated as a guest login and
+ mapped into the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+> guest account</I
+></TT
+></A
+>.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>Bad Password</TT
+> - Means user logins
+ with an invalid password are treated as a guest login and mapped
+ into the <A
+HREF="#GUESTACCOUNT"
+>guest account</A
+>. Note that
+ this can cause problems as it means that any user incorrectly typing
+ their password will be silently logged on as "guest" - and
+ will not know the reason they cannot access files they think
+ they should - there will have been no message given to them
+ that they got their password wrong. Helpdesk services will
+ <EM
+>hate</EM
+> you if you set the <TT
+CLASS="PARAMETER"
+><I
+>map to
+ guest</I
+></TT
+> parameter this way :-).</P
+></LI
+></UL
+><P
+>Note that this parameter is needed to set up "Guest"
+ share services when using <TT
+CLASS="PARAMETER"
+><I
+>security</I
+></TT
+> modes other than
+ share. This is because in these modes the name of the resource being
+ requested is <EM
+>not</EM
+> sent to the server until after
+ the server has successfully authenticated the client so the server
+ cannot make authentication decisions at the correct time (connection
+ to the share) for "Guest" shares.</P
+><P
+>For people familiar with the older Samba releases, this
+ parameter maps to the old compile-time setting of the <TT
+CLASS="CONSTANT"
+> GUEST_SESSSETUP</TT
+> value in local.h.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>map to guest = Never</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>map to guest = Bad User</B
+></P
+></DD
+><DT
+><A
+NAME="MAXCONNECTIONS"
+></A
+>max connections (S)</DT
+><DD
+><P
+>This option allows the number of simultaneous
+ connections to a service to be limited. If <TT
+CLASS="PARAMETER"
+><I
+>max connections
+ </I
+></TT
+> is greater than 0 then connections will be refused if
+ this number of connections to the service are already open. A value
+ of zero mean an unlimited number of connections may be made.</P
+><P
+>Record lock files are used to implement this feature. The
+ lock files will be stored in the directory specified by the <A
+HREF="#LOCKDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+>lock directory</I
+></TT
+></A
+>
+ option.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max connections = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max connections = 10</B
+></P
+></DD
+><DT
+><A
+NAME="MAXDISKSIZE"
+></A
+>max disk size (G)</DT
+><DD
+><P
+>This option allows you to put an upper limit
+ on the apparent size of disks. If you set this option to 100
+ then all shares will appear to be not larger than 100 MB in
+ size.</P
+><P
+>Note that this option does not limit the amount of
+ data you can put on the disk. In the above case you could still
+ store much more than 100 MB on the disk, but if a client ever asks
+ for the amount of free disk space or the total disk size then the
+ result will be bounded by the amount specified in <TT
+CLASS="PARAMETER"
+><I
+>max
+ disk size</I
+></TT
+>.</P
+><P
+>This option is primarily useful to work around bugs
+ in some pieces of software that can't handle very large disks,
+ particularly disks over 1GB in size.</P
+><P
+>A <TT
+CLASS="PARAMETER"
+><I
+>max disk size</I
+></TT
+> of 0 means no limit.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max disk size = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max disk size = 1000</B
+></P
+></DD
+><DT
+><A
+NAME="MAXLOGSIZE"
+></A
+>max log size (G)</DT
+><DD
+><P
+>This option (an integer in kilobytes) specifies
+ the max size the log file should grow to. Samba periodically checks
+ the size and if it is exceeded it will rename the file, adding
+ a <TT
+CLASS="FILENAME"
+>.old</TT
+> extension.</P
+><P
+>A size of 0 means no limit.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max log size = 5000</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max log size = 1000</B
+></P
+></DD
+><DT
+><A
+NAME="MAXMUX"
+></A
+>max mux (G)</DT
+><DD
+><P
+>This option controls the maximum number of
+ outstanding simultaneous SMB operations that Samba tells the client
+ it will allow. You should never need to set this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max mux = 50</B
+></P
+></DD
+><DT
+><A
+NAME="MAXOPENFILES"
+></A
+>max open files (G)</DT
+><DD
+><P
+>This parameter limits the maximum number of
+ open files that one <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> file
+ serving process may have open for a client at any one time. The
+ default for this parameter is set very high (10,000) as Samba uses
+ only one bit per unopened file.</P
+><P
+>The limit of the number of open files is usually set
+ by the UNIX per-process file descriptor limit rather than
+ this parameter so you should never need to touch this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max open files = 10000</B
+></P
+></DD
+><DT
+><A
+NAME="MAXPRINTJOBS"
+></A
+>max print jobs (S)</DT
+><DD
+><P
+>This parameter limits the maximum number of
+ jobs allowable in a Samba printer queue at any given moment.
+ If this number is exceeded, <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> smbd(8)</B
+></A
+> will remote "Out of Space" to the client.
+ See all <A
+HREF="#TOTALPRINTJOBS"
+><TT
+CLASS="PARAMETER"
+><I
+>total
+ print jobs</I
+></TT
+></A
+>.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max print jobs = 1000</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max print jobs = 5000</B
+></P
+></DD
+><DT
+><A
+NAME="MAXPROTOCOL"
+></A
+>max protocol (G)</DT
+><DD
+><P
+>The value of the parameter (a string) is the highest
+ protocol level that will be supported by the server.</P
+><P
+>Possible values are :</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>CORE</TT
+>: Earliest version. No
+ concept of user names.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>COREPLUS</TT
+>: Slight improvements on
+ CORE for efficiency.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>LANMAN1</TT
+>: First <EM
+> modern</EM
+> version of the protocol. Long filename
+ support.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>LANMAN2</TT
+>: Updates to Lanman1 protocol.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>NT1</TT
+>: Current up to date version of
+ the protocol. Used by Windows NT. Known as CIFS.</P
+></LI
+></UL
+><P
+>Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.</P
+><P
+>See also <A
+HREF="#MINPROTOCOL"
+><TT
+CLASS="PARAMETER"
+><I
+>min
+ protocol</I
+></TT
+></A
+></P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max protocol = NT1</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max protocol = LANMAN1</B
+></P
+></DD
+><DT
+><A
+NAME="MAXSMBDPROCESSES"
+></A
+>max smbd processes (G)</DT
+><DD
+><P
+>This parameter limits the maximum number of
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>
+ processes concurrently running on a system and is intended
+ as a stopgap to prevent degrading service to clients in the event
+ that the server has insufficient resources to handle more than this
+ number of connections. Remember that under normal operating
+ conditions, each user will have an <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> associated with him or her
+ to handle connections to all shares from a given host.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max smbd processes = 0</B
+> ## no limit</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max smbd processes = 1000</B
+></P
+></DD
+><DT
+><A
+NAME="MAXTTL"
+></A
+>max ttl (G)</DT
+><DD
+><P
+>This option tells <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ what the default 'time to live' of NetBIOS names should be (in seconds)
+ when <B
+CLASS="COMMAND"
+>nmbd</B
+> is requesting a name using either a
+ broadcast packet or from a WINS server. You should never need to
+ change this parameter. The default is 3 days.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max ttl = 259200</B
+></P
+></DD
+><DT
+><A
+NAME="MAXWINSTTL"
+></A
+>max wins ttl (G)</DT
+><DD
+><P
+>This option tells <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)
+ </A
+> when acting as a WINS server (<A
+HREF="#WINSSUPPORT"
+> <TT
+CLASS="PARAMETER"
+><I
+>wins support = yes</I
+></TT
+></A
+>) what the maximum
+ 'time to live' of NetBIOS names that <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ will grant will be (in seconds). You should never need to change this
+ parameter. The default is 6 days (518400 seconds).</P
+><P
+>See also the <A
+HREF="#MINWINSTTL"
+><TT
+CLASS="PARAMETER"
+><I
+>min
+ wins ttl</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max wins ttl = 518400</B
+></P
+></DD
+><DT
+><A
+NAME="MAXXMIT"
+></A
+>max xmit (G)</DT
+><DD
+><P
+>This option controls the maximum packet size
+ that will be negotiated by Samba. The default is 65535, which
+ is the maximum. In some cases you may find you get better performance
+ with a smaller value. A value below 2048 is likely to cause problems.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>max xmit = 65535</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>max xmit = 8192</B
+></P
+></DD
+><DT
+><A
+NAME="MESSAGECOMMAND"
+></A
+>message command (G)</DT
+><DD
+><P
+>This specifies what command to run when the
+ server receives a WinPopup style message.</P
+><P
+>This would normally be a command that would
+ deliver the message somehow. How this is to be done is
+ up to your imagination.</P
+><P
+>An example is:</P
+><P
+><B
+CLASS="COMMAND"
+>message command = csh -c 'xedit %s;rm %s' &#38;</B
+>
+ </P
+><P
+>This delivers the message using <B
+CLASS="COMMAND"
+>xedit</B
+>, then
+ removes it afterwards. <EM
+>NOTE THAT IT IS VERY IMPORTANT
+ THAT THIS COMMAND RETURN IMMEDIATELY</EM
+>. That's why I
+ have the '&#38;' on the end. If it doesn't return immediately then
+ your PCs may freeze when sending messages (they should recover
+ after 30 seconds, hopefully).</P
+><P
+>All messages are delivered as the global guest user.
+ The command takes the standard substitutions, although <TT
+CLASS="PARAMETER"
+><I
+> %u</I
+></TT
+> won't work (<TT
+CLASS="PARAMETER"
+><I
+>%U</I
+></TT
+> may be better
+ in this case).</P
+><P
+>Apart from the standard substitutions, some additional
+ ones apply. In particular:</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%s</I
+></TT
+> = the filename containing
+ the message.</P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%t</I
+></TT
+> = the destination that
+ the message was sent to (probably the server name).</P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%f</I
+></TT
+> = who the message
+ is from.</P
+></LI
+></UL
+><P
+>You could make this command send mail, or whatever else
+ takes your fancy. Please let us know of any really interesting
+ ideas you have.</P
+><P
+>Here's a way of sending the messages as mail to root:</P
+><P
+><B
+CLASS="COMMAND"
+>message command = /bin/mail -s 'message from %f on
+ %m' root &#60; %s; rm %s</B
+></P
+><P
+>If you don't have a message command then the message
+ won't be delivered and Samba will tell the sender there was
+ an error. Unfortunately WfWg totally ignores the error code
+ and carries on regardless, saying that the message was delivered.
+ </P
+><P
+>If you want to silently delete it then try:</P
+><P
+><B
+CLASS="COMMAND"
+>message command = rm %s</B
+></P
+><P
+>Default: <EM
+>no message command</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>message command = csh -c 'xedit %s;
+ rm %s' &#38;</B
+></P
+></DD
+><DT
+><A
+NAME="MINPASSWDLENGTH"
+></A
+>min passwd length (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#MINPASSWORDLENGTH"
+> <TT
+CLASS="PARAMETER"
+><I
+>min password length</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="MINPASSWORDLENGTH"
+></A
+>min password length (G)</DT
+><DD
+><P
+>This option sets the minimum length in characters
+ of a plaintext password that <B
+CLASS="COMMAND"
+>smbd</B
+> will accept when performing
+ UNIX password changing.</P
+><P
+>See also <A
+HREF="#UNIXPASSWORDSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>unix
+ password sync</I
+></TT
+></A
+>, <A
+HREF="#PASSWDPROGRAM"
+> <TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+></A
+> and <A
+HREF="#PASSWDCHATDEBUG"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd chat debug</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>min password length = 5</B
+></P
+></DD
+><DT
+><A
+NAME="MINPRINTSPACE"
+></A
+>min print space (S)</DT
+><DD
+><P
+>This sets the minimum amount of free disk
+ space that must be available before a user will be able to spool
+ a print job. It is specified in kilobytes. The default is 0, which
+ means a user can always spool a print job.</P
+><P
+>See also the <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>min print space = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>min print space = 2000</B
+></P
+></DD
+><DT
+><A
+NAME="MINPROTOCOL"
+></A
+>min protocol (G)</DT
+><DD
+><P
+>The value of the parameter (a string) is the
+ lowest SMB protocol dialect than Samba will support. Please refer
+ to the <A
+HREF="#MAXPROTOCOL"
+><TT
+CLASS="PARAMETER"
+><I
+>max protocol</I
+></TT
+></A
+>
+ parameter for a list of valid protocol names and a brief description
+ of each. You may also wish to refer to the C source code in
+ <TT
+CLASS="FILENAME"
+>source/smbd/negprot.c</TT
+> for a listing of known protocol
+ dialects supported by clients.</P
+><P
+>If you are viewing this parameter as a security measure, you should
+ also refer to the <A
+HREF="#LANMANAUTH"
+><TT
+CLASS="PARAMETER"
+><I
+>lanman
+ auth</I
+></TT
+></A
+> parameter. Otherwise, you should never need
+ to change this parameter.</P
+><P
+>Default : <B
+CLASS="COMMAND"
+>min protocol = CORE</B
+></P
+><P
+>Example : <B
+CLASS="COMMAND"
+>min protocol = NT1</B
+> # disable DOS
+ clients</P
+></DD
+><DT
+><A
+NAME="MINWINSTTL"
+></A
+>min wins ttl (G)</DT
+><DD
+><P
+>This option tells <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ when acting as a WINS server (<A
+HREF="#WINSSUPPORT"
+><TT
+CLASS="PARAMETER"
+><I
+> wins support = yes</I
+></TT
+></A
+>) what the minimum 'time to live'
+ of NetBIOS names that <B
+CLASS="COMMAND"
+>nmbd</B
+> will grant will be (in
+ seconds). You should never need to change this parameter. The default
+ is 6 hours (21600 seconds).</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>min wins ttl = 21600</B
+></P
+></DD
+><DT
+><A
+NAME="MSDFSROOT"
+></A
+>msdfs root (S)</DT
+><DD
+><P
+>This boolean parameter is only available if
+ Samba is configured and compiled with the <B
+CLASS="COMMAND"
+> --with-msdfs</B
+> option. If set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>,
+ Samba treats the share as a Dfs root and allows clients to browse
+ the distributed file system tree rooted at the share directory.
+ Dfs links are specified in the share directory by symbolic
+ links of the form <TT
+CLASS="FILENAME"
+>msdfs:serverA\shareA,serverB\shareB
+ </TT
+> and so on. For more information on setting up a Dfs tree
+ on Samba, refer to <A
+HREF="msdfs_setup.html"
+TARGET="_top"
+>msdfs_setup.html
+ </A
+>.</P
+><P
+>See also <A
+HREF="#HOSTMSDFS"
+><TT
+CLASS="PARAMETER"
+><I
+>host msdfs
+ </I
+></TT
+></A
+></P
+><P
+>Default: <B
+CLASS="COMMAND"
+>msdfs root = no</B
+></P
+></DD
+><DT
+><A
+NAME="NAMERESOLVEORDER"
+></A
+>name resolve order (G)</DT
+><DD
+><P
+>This option is used by the programs in the Samba
+ suite to determine what naming services to use and in what order
+ to resolve host names to IP addresses. The option takes a space
+ separated string of name resolution options.</P
+><P
+>The options are :"lmhosts", "host", "wins" and "bcast". They
+ cause names to be resolved as follows :</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>lmhosts</TT
+> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <A
+HREF="lmhosts.5.html"
+TARGET="_top"
+>lmhosts(5)</A
+> for details) then
+ any name type matches for lookup.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>host</TT
+> : Do a standard host
+ name to IP address resolution, using the system <TT
+CLASS="FILENAME"
+>/etc/hosts
+ </TT
+>, NIS, or DNS lookups. This method of name resolution
+ is operating system depended for instance on IRIX or Solaris this
+ may be controlled by the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>
+ file. Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>wins</TT
+> : Query a name with
+ the IP address listed in the <A
+HREF="#WINSSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+> wins server</I
+></TT
+></A
+> parameter. If no WINS server has
+ been specified this method will be ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>bcast</TT
+> : Do a broadcast on
+ each of the known local interfaces listed in the <A
+HREF="#INTERFACES"
+><TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+></A
+>
+ parameter. This is the least reliable of the name resolution
+ methods as it depends on the target host being on a locally
+ connected subnet.</P
+></LI
+></UL
+><P
+>Default: <B
+CLASS="COMMAND"
+>name resolve order = lmhosts host wins bcast
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>name resolve order = lmhosts bcast host
+ </B
+></P
+><P
+>This will cause the local lmhosts file to be examined
+ first, followed by a broadcast attempt, followed by a normal
+ system hostname lookup.</P
+></DD
+><DT
+><A
+NAME="NETBIOSALIASES"
+></A
+>netbios aliases (G)</DT
+><DD
+><P
+>This is a list of NetBIOS names that <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> will advertise as additional
+ names by which the Samba server is known. This allows one machine
+ to appear in browse lists under multiple names. If a machine is
+ acting as a browse server or logon server none
+ of these names will be advertised as either browse server or logon
+ servers, only the primary name of the machine will be advertised
+ with these capabilities.</P
+><P
+>See also <A
+HREF="#NETBIOSNAME"
+><TT
+CLASS="PARAMETER"
+><I
+>netbios
+ name</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>empty string (no additional names)</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>netbios aliases = TEST TEST1 TEST2</B
+></P
+></DD
+><DT
+><A
+NAME="NETBIOSNAME"
+></A
+>netbios name (G)</DT
+><DD
+><P
+>This sets the NetBIOS name by which a Samba
+ server is known. By default it is the same as the first component
+ of the host's DNS name. If a machine is a browse server or
+ logon server this name (or the first component
+ of the hosts DNS name) will be the name that these services are
+ advertised under.</P
+><P
+>See also <A
+HREF="#NETBIOSALIASES"
+><TT
+CLASS="PARAMETER"
+><I
+>netbios
+ aliases</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>machine DNS name</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>netbios name = MYNAME</B
+></P
+></DD
+><DT
+><A
+NAME="NETBIOSSCOPE"
+></A
+>netbios scope (G)</DT
+><DD
+><P
+>This sets the NetBIOS scope that Samba will
+ operate under. This should not be set unless every machine
+ on your LAN also sets this value.</P
+></DD
+><DT
+><A
+NAME="NISHOMEDIR"
+></A
+>nis homedir (G)</DT
+><DD
+><P
+>Get the home share server from a NIS map. For
+ UNIX systems that use an automounter, the user's home directory
+ will often be mounted on a workstation on demand from a remote
+ server. </P
+><P
+>When the Samba logon server is not the actual home directory
+ server, but is mounting the home directories via NFS then two
+ network hops would be required to access the users home directory
+ if the logon server told the client to use itself as the SMB server
+ for home directories (one over SMB and one over NFS). This can
+ be very slow.</P
+><P
+>This option allows Samba to return the home share as
+ being on a different server to the logon server and as
+ long as a Samba daemon is running on the home directory server,
+ it will be mounted on the Samba client directly from the directory
+ server. When Samba is returning the home share to the client, it
+ will consult the NIS map specified in <A
+HREF="#HOMEDIRMAP"
+> <TT
+CLASS="PARAMETER"
+><I
+>homedir map</I
+></TT
+></A
+> and return the server
+ listed there.</P
+><P
+>Note that for this option to work there must be a working
+ NIS system and the Samba server with this option must also
+ be a logon server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>nis homedir = no</B
+></P
+></DD
+><DT
+><A
+NAME="NTACLSUPPORT"
+></A
+>nt acl support (S)</DT
+><DD
+><P
+>This boolean parameter controls whether
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> will attempt to map
+ UNIX permissions into Windows NT access control lists.
+ This parameter was formally a global parameter in releases
+ prior to 2.2.2.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>nt acl support = yes</B
+></P
+></DD
+><DT
+><A
+NAME="NTPIPESUPPORT"
+></A
+>nt pipe support (G)</DT
+><DD
+><P
+>This boolean parameter controls whether
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> will allow Windows NT
+ clients to connect to the NT SMB specific <TT
+CLASS="CONSTANT"
+>IPC$</TT
+>
+ pipes. This is a developer debugging option and can be left
+ alone.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>nt pipe support = yes</B
+></P
+></DD
+><DT
+><A
+NAME="NTSMBSUPPORT"
+></A
+>nt smb support (G)</DT
+><DD
+><P
+>This boolean parameter controls whether <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> will negotiate NT specific SMB
+ support with Windows NT clients. Although this is a developer
+ debugging option and should be left alone, benchmarking has discovered
+ that Windows NT clients give faster performance with this option
+ set to <TT
+CLASS="CONSTANT"
+>no</TT
+>. This is still being investigated.
+ If this option is set to <TT
+CLASS="CONSTANT"
+>no</TT
+> then Samba offers
+ exactly the same SMB calls that versions prior to Samba 2.0 offered.
+ This information may be of use if any users are having problems
+ with NT SMB support.</P
+><P
+>You should not need to ever disable this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>nt smb support = yes</B
+></P
+></DD
+><DT
+><A
+NAME="NULLPASSWORDS"
+></A
+>null passwords (G)</DT
+><DD
+><P
+>Allow or disallow client access to accounts
+ that have null passwords. </P
+><P
+>See also <A
+HREF="smbpasswd.5.html"
+TARGET="_top"
+>smbpasswd (5)</A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>null passwords = no</B
+></P
+></DD
+><DT
+><A
+NAME="OBEYPAMRESTRICTIONS"
+></A
+>obey pam restrictions (G)</DT
+><DD
+><P
+>When Samba 2.2 is configured to enable PAM support
+ (i.e. --with-pam), this parameter will control whether or not Samba
+ should obey PAM's account and session management directives. The
+ default behavior is to use PAM for clear text authentication only
+ and to ignore any account or session management. Note that Samba
+ always ignores PAM for authentication in the case of <A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypt passwords = yes</I
+></TT
+>
+ </A
+>. The reason is that PAM modules cannot support the challenge/response
+ authentication mechanism needed in the presence of SMB password encryption.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>obey pam restrictions = no</B
+></P
+></DD
+><DT
+><A
+NAME="ONLYUSER"
+></A
+>only user (S)</DT
+><DD
+><P
+>This is a boolean option that controls whether
+ connections with usernames not in the <TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+>
+ list will be allowed. By default this option is disabled so that a
+ client can supply a username to be used by the server. Enabling
+ this parameter will force the server to only user the login
+ names from the <TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+> list and is only really
+ useful in <A
+HREF="#SECURITYEQUALSSHARE"
+>shave level</A
+>
+ security.</P
+><P
+>Note that this also means Samba won't try to deduce
+ usernames from the service name. This can be annoying for
+ the [homes] section. To get around this you could use <B
+CLASS="COMMAND"
+>user =
+ %S</B
+> which means your <TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+> list
+ will be just the service name, which for home directories is the
+ name of the user.</P
+><P
+>See also the <A
+HREF="#USER"
+><TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+>
+ </A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>only user = no</B
+></P
+></DD
+><DT
+><A
+NAME="ONLYGUEST"
+></A
+>only guest (S)</DT
+><DD
+><P
+>A synonym for <A
+HREF="#GUESTONLY"
+><TT
+CLASS="PARAMETER"
+><I
+> guest only</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="OPLOCKBREAKWAITTIME"
+></A
+>oplock break wait time (G)</DT
+><DD
+><P
+>This is a tuning parameter added due to bugs in
+ both Windows 9x and WinNT. If Samba responds to a client too
+ quickly when that client issues an SMB that can cause an oplock
+ break request, then the network client can fail and not respond
+ to the break request. This tuning parameter (which is set in milliseconds)
+ is the amount of time Samba will wait before sending an oplock break
+ request to such (broken) clients.</P
+><P
+><EM
+>DO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+ AND UNDERSTOOD THE SAMBA OPLOCK CODE</EM
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>oplock break wait time = 0</B
+></P
+></DD
+><DT
+><A
+NAME="OPLOCKCONTENTIONLIMIT"
+></A
+>oplock contention limit (S)</DT
+><DD
+><P
+>This is a <EM
+>very</EM
+> advanced
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> tuning option to
+ improve the efficiency of the granting of oplocks under multiple
+ client contention for the same file.</P
+><P
+>In brief it specifies a number, which causes <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> not to
+ grant an oplock even when requested if the approximate number of
+ clients contending for an oplock on the same file goes over this
+ limit. This causes <B
+CLASS="COMMAND"
+>smbd</B
+> to behave in a similar
+ way to Windows NT.</P
+><P
+><EM
+>DO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+ AND UNDERSTOOD THE SAMBA OPLOCK CODE</EM
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>oplock contention limit = 2</B
+></P
+></DD
+><DT
+><A
+NAME="OPLOCKS"
+></A
+>oplocks (S)</DT
+><DD
+><P
+>This boolean option tells <B
+CLASS="COMMAND"
+>smbd</B
+> whether to
+ issue oplocks (opportunistic locks) to file open requests on this
+ share. The oplock code can dramatically (approx. 30% or more) improve
+ the speed of access to files on Samba servers. It allows the clients
+ to aggressively cache files locally and you may want to disable this
+ option for unreliable network environments (it is turned on by
+ default in Windows NT Servers). For more information see the file
+ <TT
+CLASS="FILENAME"
+>Speed.txt</TT
+> in the Samba <TT
+CLASS="FILENAME"
+>docs/</TT
+>
+ directory.</P
+><P
+>Oplocks may be selectively turned off on certain files with a
+ share. See the <A
+HREF="#VETOOPLOCKFILES"
+><TT
+CLASS="PARAMETER"
+><I
+> veto oplock files</I
+></TT
+></A
+> parameter. On some systems
+ oplocks are recognized by the underlying operating system. This
+ allows data synchronization between all access to oplocked files,
+ whether it be via Samba or NFS or a local UNIX process. See the
+ <TT
+CLASS="PARAMETER"
+><I
+>kernel oplocks</I
+></TT
+> parameter for details.</P
+><P
+>See also the <A
+HREF="#KERNELOPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>kernel
+ oplocks</I
+></TT
+></A
+> and <A
+HREF="#LEVEL2OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+> level2 oplocks</I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>oplocks = yes</B
+></P
+></DD
+><DT
+><A
+NAME="OSLEVEL"
+></A
+>os level (G)</DT
+><DD
+><P
+>This integer value controls what level Samba
+ advertises itself as for browse elections. The value of this
+ parameter determines whether <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ has a chance of becoming a local master browser for the <TT
+CLASS="PARAMETER"
+><I
+> WORKGROUP</I
+></TT
+> in the local broadcast area.</P
+><P
+><EM
+>Note :</EM
+>By default, Samba will win
+ a local master browsing election over all Microsoft operating
+ systems except a Windows NT 4.0/2000 Domain Controller. This
+ means that a misconfigured Samba host can effectively isolate
+ a subnet for browsing purposes. See <TT
+CLASS="FILENAME"
+>BROWSING.txt
+ </TT
+> in the Samba <TT
+CLASS="FILENAME"
+>docs/</TT
+> directory
+ for details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>os level = 20</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>os level = 65 </B
+></P
+></DD
+><DT
+><A
+NAME="OS2DRIVERMAP"
+></A
+>os2 driver map (G)</DT
+><DD
+><P
+>The parameter is used to define the absolute
+ path to a file containing a mapping of Windows NT printer driver
+ names to OS/2 printer driver names. The format is:</P
+><P
+>&#60;nt driver name&#62; = &#60;os2 driver
+ name&#62;.&#60;device name&#62;</P
+><P
+>For example, a valid entry using the HP LaserJet 5
+ printer driver would appear as <B
+CLASS="COMMAND"
+>HP LaserJet 5L = LASERJET.HP
+ LaserJet 5L</B
+>.</P
+><P
+>The need for the file is due to the printer driver namespace
+ problem described in the <A
+HREF="printer_driver2.html"
+TARGET="_top"
+>Samba
+ Printing HOWTO</A
+>. For more details on OS/2 clients, please
+ refer to the <A
+HREF="OS2-Client-HOWTO.html"
+TARGET="_top"
+>OS2-Client-HOWTO
+ </A
+> containing in the Samba documentation.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>os2 driver map = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="PAMPASSWORDCHANGE"
+></A
+>pam password change (G)</DT
+><DD
+><P
+>With the addition of better PAM support in Samba 2.2,
+ this parameter, it is possible to use PAM's password change control
+ flag for Samba. If enabled, then PAM will be used for password
+ changes when requested by an SMB client instead of the program listed in
+ <A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+></A
+>.
+ It should be possible to enable this without changing your
+ <A
+HREF="#PASSWDCHAT"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd chat</I
+></TT
+></A
+>
+ parameter for most setups.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>pam password change = no</B
+></P
+></DD
+><DT
+><A
+NAME="PANICACTION"
+></A
+>panic action (G)</DT
+><DD
+><P
+>This is a Samba developer option that allows a
+ system command to be called when either <A
+HREF="smbd.8.html"
+TARGET="_top"
+> smbd(8)</A
+> or <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+>
+ crashes. This is usually used to draw attention to the fact that
+ a problem occurred.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>panic action = &#60;empty string&#62;</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>panic action = "/bin/sleep 90000"</B
+></P
+></DD
+><DT
+><A
+NAME="PASSWDCHAT"
+></A
+>passwd chat (G)</DT
+><DD
+><P
+>This string controls the <EM
+>"chat"</EM
+>
+ conversation that takes places between <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> and the local password changing
+ program to change the user's password. The string describes a
+ sequence of response-receive pairs that <A
+HREF="smbd.8.html"
+TARGET="_top"
+> smbd(8)</A
+> uses to determine what to send to the
+ <A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+>
+ </A
+> and what to expect back. If the expected output is not
+ received then the password is not changed.</P
+><P
+>This chat sequence is often quite site specific, depending
+ on what local methods are used for password control (such as NIS
+ etc).</P
+><P
+>Note that this parameter only is only used if the <A
+HREF="#UNIXPASSWORDSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>unix
+ password sync</I
+></TT
+></A
+> parameter is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>. This
+ sequence is then called <EM
+>AS ROOT</EM
+> when the SMB password
+ in the smbpasswd file is being changed, without access to the old
+ password cleartext. This means that root must be able to reset the user's password
+ without knowing the text of the previous password. In the presence of NIS/YP,
+ this means that the <A
+HREF="#PASSWDPROGRAM"
+>passwd program</A
+> must be
+ executed on the NIS master.
+ </P
+><P
+>The string can contain the macro <TT
+CLASS="PARAMETER"
+><I
+>%n</I
+></TT
+> which is substituted
+ for the new password. The chat sequence can also contain the standard
+ macros <TT
+CLASS="CONSTANT"
+>\n</TT
+>, <TT
+CLASS="CONSTANT"
+>\r</TT
+>, <TT
+CLASS="CONSTANT"
+> \t</TT
+> and <TT
+CLASS="CONSTANT"
+>\s</TT
+> to give line-feed,
+ carriage-return, tab and space. The chat sequence string can also contain
+ a '*' which matches any sequence of characters.
+ Double quotes can be used to collect strings with spaces
+ in them into a single string.</P
+><P
+>If the send string in any part of the chat sequence
+ is a full stop ".", then no string is sent. Similarly,
+ if the expect string is a full stop then no string is expected.</P
+><P
+>If the <A
+HREF="#PAMPASSWORDCHANGE"
+><TT
+CLASS="PARAMETER"
+><I
+>pam
+ password change</I
+></TT
+></A
+> parameter is set to true, the chat pairs
+ may be matched in any order, and success is determined by the PAM result,
+ not any particular output. The \n macro is ignored for PAM conversions.
+ </P
+><P
+>See also <A
+HREF="#UNIXPASSWORDSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>unix password
+ sync</I
+></TT
+></A
+>, <A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+> passwd program</I
+></TT
+></A
+> ,<A
+HREF="#PASSWDCHATDEBUG"
+> <TT
+CLASS="PARAMETER"
+><I
+>passwd chat debug</I
+></TT
+></A
+> and <A
+HREF="#PAMPASSWORDCHANGE"
+> <TT
+CLASS="PARAMETER"
+><I
+>pam password change</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>passwd chat = *new*password* %n\n
+ *new*password* %n\n *changed*</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>passwd chat = "*Enter OLD password*" %o\n
+ "*Enter NEW password*" %n\n "*Reenter NEW password*" %n\n "*Password
+ changed*"</B
+></P
+></DD
+><DT
+><A
+NAME="PASSWDCHATDEBUG"
+></A
+>passwd chat debug (G)</DT
+><DD
+><P
+>This boolean specifies if the passwd chat script
+ parameter is run in <EM
+>debug</EM
+> mode. In this mode the
+ strings passed to and received from the passwd chat are printed
+ in the <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> log with a
+ <A
+HREF="#DEBUGLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>debug level</I
+></TT
+></A
+>
+ of 100. This is a dangerous option as it will allow plaintext passwords
+ to be seen in the <B
+CLASS="COMMAND"
+>smbd</B
+> log. It is available to help
+ Samba admins debug their <TT
+CLASS="PARAMETER"
+><I
+>passwd chat</I
+></TT
+> scripts
+ when calling the <TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+> and should
+ be turned off after this has been done. This option has no effect if the
+ <A
+HREF="#PAMPASSWORDCHANGE"
+><TT
+CLASS="PARAMETER"
+><I
+>pam password change</I
+></TT
+></A
+>
+ paramter is set. This parameter is off by default.</P
+><P
+>See also <A
+HREF="#PASSWDCHAT"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd chat</I
+></TT
+>
+ </A
+>, <A
+HREF="#PAMPASSWORDCHANGE"
+><TT
+CLASS="PARAMETER"
+><I
+>pam password change</I
+></TT
+>
+ </A
+>, <A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd program</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>passwd chat debug = no</B
+></P
+></DD
+><DT
+><A
+NAME="PASSWDPROGRAM"
+></A
+>passwd program (G)</DT
+><DD
+><P
+>The name of a program that can be used to set
+ UNIX user passwords. Any occurrences of <TT
+CLASS="PARAMETER"
+><I
+>%u</I
+></TT
+>
+ will be replaced with the user name. The user name is checked for
+ existence before calling the password changing program.</P
+><P
+>Also note that many passwd programs insist in <EM
+>reasonable
+ </EM
+> passwords, such as a minimum length, or the inclusion
+ of mixed case chars and digits. This can pose a problem as some clients
+ (such as Windows for Workgroups) uppercase the password before sending
+ it.</P
+><P
+><EM
+>Note</EM
+> that if the <TT
+CLASS="PARAMETER"
+><I
+>unix
+ password sync</I
+></TT
+> parameter is set to <TT
+CLASS="CONSTANT"
+>true
+ </TT
+> then this program is called <EM
+>AS ROOT</EM
+>
+ before the SMB password in the <A
+HREF="smbpasswd.5.html"
+TARGET="_top"
+>smbpasswd(5)
+ </A
+> file is changed. If this UNIX password change fails, then
+ <B
+CLASS="COMMAND"
+>smbd</B
+> will fail to change the SMB password also
+ (this is by design).</P
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>unix password sync</I
+></TT
+> parameter
+ is set this parameter <EM
+>MUST USE ABSOLUTE PATHS</EM
+>
+ for <EM
+>ALL</EM
+> programs called, and must be examined
+ for security implications. Note that by default <TT
+CLASS="PARAMETER"
+><I
+>unix
+ password sync</I
+></TT
+> is set to <TT
+CLASS="CONSTANT"
+>false</TT
+>.</P
+><P
+>See also <A
+HREF="#UNIXPASSWORDSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>unix
+ password sync</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>passwd program = /bin/passwd</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>passwd program = /sbin/npasswd %u</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="PASSWORDLEVEL"
+></A
+>password level (G)</DT
+><DD
+><P
+>Some client/server combinations have difficulty
+ with mixed-case passwords. One offending client is Windows for
+ Workgroups, which for some reason forces passwords to upper
+ case when using the LANMAN1 protocol, but leaves them alone when
+ using COREPLUS! Another problem child is the Windows 95/98
+ family of operating systems. These clients upper case clear
+ text passwords even when NT LM 0.12 selected by the protocol
+ negotiation request/response.</P
+><P
+>This parameter defines the maximum number of characters
+ that may be upper case in passwords.</P
+><P
+>For example, say the password given was "FRED". If <TT
+CLASS="PARAMETER"
+><I
+> password level</I
+></TT
+> is set to 1, the following combinations
+ would be tried if "FRED" failed:</P
+><P
+>"Fred", "fred", "fRed", "frEd","freD"</P
+><P
+>If <TT
+CLASS="PARAMETER"
+><I
+>password level</I
+></TT
+> was set to 2,
+ the following combinations would also be tried: </P
+><P
+>"FRed", "FrEd", "FreD", "fREd", "fReD", "frED", ..</P
+><P
+>And so on.</P
+><P
+>The higher value this parameter is set to the more likely
+ it is that a mixed case password will be matched against a single
+ case password. However, you should be aware that use of this
+ parameter reduces security and increases the time taken to
+ process a new connection.</P
+><P
+>A value of zero will cause only two attempts to be
+ made - the password as is and the password in all-lower case.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>password level = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>password level = 4</B
+></P
+></DD
+><DT
+><A
+NAME="PASSWORDSERVER"
+></A
+>password server (G)</DT
+><DD
+><P
+>By specifying the name of another SMB server (such
+ as a WinNT box) with this option, and using <B
+CLASS="COMMAND"
+>security = domain
+ </B
+> or <B
+CLASS="COMMAND"
+>security = server</B
+> you can get Samba
+ to do all its username/password validation via a remote server.</P
+><P
+>This option sets the name of the password server to use.
+ It must be a NetBIOS name, so if the machine's NetBIOS name is
+ different from its Internet name then you may have to add its NetBIOS
+ name to the lmhosts file which is stored in the same directory
+ as the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file.</P
+><P
+>The name of the password server is looked up using the
+ parameter <A
+HREF="#NAMERESOLVEORDER"
+><TT
+CLASS="PARAMETER"
+><I
+>name
+ resolve order</I
+></TT
+></A
+> and so may resolved
+ by any method and order described in that parameter.</P
+><P
+>The password server much be a machine capable of using
+ the "LM1.2X002" or the "NT LM 0.12" protocol, and it must be in
+ user level security mode.</P
+><P
+><EM
+>NOTE:</EM
+> Using a password server
+ means your UNIX box (running Samba) is only as secure as your
+ password server. <EM
+>DO NOT CHOOSE A PASSWORD SERVER THAT
+ YOU DON'T COMPLETELY TRUST</EM
+>.</P
+><P
+>Never point a Samba server at itself for password
+ serving. This will cause a loop and could lock up your Samba
+ server!</P
+><P
+>The name of the password server takes the standard
+ substitutions, but probably the only useful one is <TT
+CLASS="PARAMETER"
+><I
+>%m
+ </I
+></TT
+>, which means the Samba server will use the incoming
+ client as the password server. If you use this then you better
+ trust your clients, and you had better restrict them with hosts allow!</P
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>security</I
+></TT
+> parameter is set to
+ <TT
+CLASS="CONSTANT"
+>domain</TT
+>, then the list of machines in this
+ option must be a list of Primary or Backup Domain controllers for the
+ Domain or the character '*', as the Samba server is effectively
+ in that domain, and will use cryptographically authenticated RPC calls
+ to authenticate the user logging on. The advantage of using <B
+CLASS="COMMAND"
+> security = domain</B
+> is that if you list several hosts in the
+ <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+> option then <B
+CLASS="COMMAND"
+>smbd
+ </B
+> will try each in turn till it finds one that responds. This
+ is useful in case your primary server goes down.</P
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+> option is set
+ to the character '*', then Samba will attempt to auto-locate the
+ Primary or Backup Domain controllers to authenticate against by
+ doing a query for the name <TT
+CLASS="CONSTANT"
+>WORKGROUP&#60;1C&#62;</TT
+>
+ and then contacting each server returned in the list of IP
+ addresses from the name resolution source. </P
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>security</I
+></TT
+> parameter is
+ set to <TT
+CLASS="CONSTANT"
+>server</TT
+>, then there are different
+ restrictions that <B
+CLASS="COMMAND"
+>security = domain</B
+> doesn't
+ suffer from:</P
+><P
+></P
+><UL
+><LI
+><P
+>You may list several password servers in
+ the <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+> parameter, however if an
+ <B
+CLASS="COMMAND"
+>smbd</B
+> makes a connection to a password server,
+ and then the password server fails, no more users will be able
+ to be authenticated from this <B
+CLASS="COMMAND"
+>smbd</B
+>. This is a
+ restriction of the SMB/CIFS protocol when in <B
+CLASS="COMMAND"
+>security = server
+ </B
+> mode and cannot be fixed in Samba.</P
+></LI
+><LI
+><P
+>If you are using a Windows NT server as your
+ password server then you will have to ensure that your users
+ are able to login from the Samba server, as when in <B
+CLASS="COMMAND"
+> security = server</B
+> mode the network logon will appear to
+ come from there rather than from the users workstation.</P
+></LI
+></UL
+><P
+>See also the <A
+HREF="#SECURITY"
+><TT
+CLASS="PARAMETER"
+><I
+>security
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>password server = &#60;empty string&#62;</B
+>
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>password server = NT-PDC, NT-BDC1, NT-BDC2
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>password server = *</B
+></P
+></DD
+><DT
+><A
+NAME="PATH"
+></A
+>path (S)</DT
+><DD
+><P
+>This parameter specifies a directory to which
+ the user of the service is to be given access. In the case of
+ printable services, this is where print data will spool prior to
+ being submitted to the host for printing.</P
+><P
+>For a printable service offering guest access, the service
+ should be readonly and the path should be world-writeable and
+ have the sticky bit set. This is not mandatory of course, but
+ you probably won't get the results you expect if you do
+ otherwise.</P
+><P
+>Any occurrences of <TT
+CLASS="PARAMETER"
+><I
+>%u</I
+></TT
+> in the path
+ will be replaced with the UNIX username that the client is using
+ on this connection. Any occurrences of <TT
+CLASS="PARAMETER"
+><I
+>%m</I
+></TT
+>
+ will be replaced by the NetBIOS name of the machine they are
+ connecting from. These replacements are very useful for setting
+ up pseudo home directories for users.</P
+><P
+>Note that this path will be based on <A
+HREF="#ROOTDIR"
+> <TT
+CLASS="PARAMETER"
+><I
+>root dir</I
+></TT
+></A
+> if one was specified.</P
+><P
+>Default: <EM
+>none</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>path = /home/fred</B
+></P
+></DD
+><DT
+><A
+NAME="POSIXLOCKING"
+></A
+>posix locking (S)</DT
+><DD
+><P
+>The <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>
+ daemon maintains an database of file locks obtained by SMB clients.
+ The default behavior is to map this internal database to POSIX
+ locks. This means that file locks obtained by SMB clients are
+ consistent with those seen by POSIX compliant applications accessing
+ the files via a non-SMB method (e.g. NFS or local file access).
+ You should never need to disable this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>posix locking = yes</B
+></P
+></DD
+><DT
+><A
+NAME="POSTEXEC"
+></A
+>postexec (S)</DT
+><DD
+><P
+>This option specifies a command to be run
+ whenever the service is disconnected. It takes the usual
+ substitutions. The command may be run as the root on some
+ systems.</P
+><P
+>An interesting example may be to unmount server
+ resources:</P
+><P
+><B
+CLASS="COMMAND"
+>postexec = /etc/umount /cdrom</B
+></P
+><P
+>See also <A
+HREF="#PREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>preexec</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <EM
+>none (no command executed)</EM
+>
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>postexec = echo \"%u disconnected from %S
+ from %m (%I)\" &#62;&#62; /tmp/log</B
+></P
+></DD
+><DT
+><A
+NAME="POSTSCRIPT"
+></A
+>postscript (S)</DT
+><DD
+><P
+>This parameter forces a printer to interpret
+ the print files as PostScript. This is done by adding a <TT
+CLASS="CONSTANT"
+>%!
+ </TT
+> to the start of print output.</P
+><P
+>This is most useful when you have lots of PCs that persist
+ in putting a control-D at the start of print jobs, which then
+ confuses your printer.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>postscript = no</B
+></P
+></DD
+><DT
+><A
+NAME="PREEXEC"
+></A
+>preexec (S)</DT
+><DD
+><P
+>This option specifies a command to be run whenever
+ the service is connected to. It takes the usual substitutions.</P
+><P
+>An interesting example is to send the users a welcome
+ message every time they log in. Maybe a message of the day? Here
+ is an example:</P
+><P
+><B
+CLASS="COMMAND"
+>preexec = csh -c 'echo \"Welcome to %S!\" |
+ /usr/local/samba/bin/smbclient -M %m -I %I' &#38; </B
+></P
+><P
+>Of course, this could get annoying after a while :-)</P
+><P
+>See also <A
+HREF="#PREEXECCLOSE"
+><TT
+CLASS="PARAMETER"
+><I
+>preexec close
+ </I
+></TT
+></A
+> and <A
+HREF="#POSTEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>postexec
+ </I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>none (no command executed)</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>preexec = echo \"%u connected to %S from %m
+ (%I)\" &#62;&#62; /tmp/log</B
+></P
+></DD
+><DT
+><A
+NAME="PREEXECCLOSE"
+></A
+>preexec close (S)</DT
+><DD
+><P
+>This boolean option controls whether a non-zero
+ return code from <A
+HREF="#PREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+>preexec
+ </I
+></TT
+></A
+> should close the service being connected to.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>preexec close = no</B
+></P
+></DD
+><DT
+><A
+NAME="PREFERREDMASTER"
+></A
+>preferred master (G)</DT
+><DD
+><P
+>This boolean parameter controls if <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> is a preferred master browser
+ for its workgroup.</P
+><P
+>If this is set to <TT
+CLASS="CONSTANT"
+>true</TT
+>, on startup, <B
+CLASS="COMMAND"
+>nmbd</B
+>
+ will force an election, and it will have a slight advantage in
+ winning the election. It is recommended that this parameter is
+ used in conjunction with <B
+CLASS="COMMAND"
+><A
+HREF="#DOMAINMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+> domain master</I
+></TT
+></A
+> = yes</B
+>, so that <B
+CLASS="COMMAND"
+> nmbd</B
+> can guarantee becoming a domain master.</P
+><P
+>Use this option with caution, because if there are several
+ hosts (whether Samba servers, Windows 95 or NT) that are preferred
+ master browsers on the same subnet, they will each periodically
+ and continuously attempt to become the local master browser.
+ This will result in unnecessary broadcast traffic and reduced browsing
+ capabilities.</P
+><P
+>See also <A
+HREF="#OSLEVEL"
+><TT
+CLASS="PARAMETER"
+><I
+>os level</I
+></TT
+>
+ </A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>preferred master = auto</B
+></P
+></DD
+><DT
+><A
+NAME="PREFEREDMASTER"
+></A
+>prefered master (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#PREFERREDMASTER"
+><TT
+CLASS="PARAMETER"
+><I
+> preferred master</I
+></TT
+></A
+> for people who cannot spell :-).</P
+></DD
+><DT
+><A
+NAME="PRELOAD"
+></A
+>preload</DT
+><DD
+><P
+>This is a list of services that you want to be
+ automatically added to the browse lists. This is most useful
+ for homes and printers services that would otherwise not be
+ visible.</P
+><P
+>Note that if you just want all printers in your
+ printcap file loaded then the <A
+HREF="#LOADPRINTERS"
+> <TT
+CLASS="PARAMETER"
+><I
+>load printers</I
+></TT
+></A
+> option is easier.</P
+><P
+>Default: <EM
+>no preloaded services</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>preload = fred lp colorlp</B
+></P
+></DD
+><DT
+><A
+NAME="PRESERVECASE"
+></A
+>preserve case (S)</DT
+><DD
+><P
+> This controls if new filenames are created
+ with the case that the client passes, or if they are forced to
+ be the <A
+HREF="#DEFAULTCASE"
+><TT
+CLASS="PARAMETER"
+><I
+>default case
+ </I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>preserve case = yes</B
+></P
+><P
+>See the section on <A
+HREF="#AEN202"
+>NAME
+ MANGLING</A
+> for a fuller discussion.</P
+></DD
+><DT
+><A
+NAME="PRINTCOMMAND"
+></A
+>print command (S)</DT
+><DD
+><P
+>After a print job has finished spooling to
+ a service, this command will be used via a <B
+CLASS="COMMAND"
+>system()</B
+>
+ call to process the spool file. Typically the command specified will
+ submit the spool file to the host's printing subsystem, but there
+ is no requirement that this be the case. The server will not remove
+ the spool file, so whatever command you specify should remove the
+ spool file when it has been processed, otherwise you will need to
+ manually remove old spool files.</P
+><P
+>The print command is simply a text string. It will be used
+ verbatim, with two exceptions: All occurrences of <TT
+CLASS="PARAMETER"
+><I
+>%s
+ </I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>%f</I
+></TT
+> will be replaced by the
+ appropriate spool file name, and all occurrences of <TT
+CLASS="PARAMETER"
+><I
+>%p
+ </I
+></TT
+> will be replaced by the appropriate printer name. The
+ spool file name is generated automatically by the server. The
+ <TT
+CLASS="PARAMETER"
+><I
+>%J</I
+></TT
+> macro can be used to access the job
+ name as transmitted by the client.</P
+><P
+>The print command <EM
+>MUST</EM
+> contain at least
+ one occurrence of <TT
+CLASS="PARAMETER"
+><I
+>%s</I
+></TT
+> or <TT
+CLASS="PARAMETER"
+><I
+>%f
+ </I
+></TT
+> - the <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is optional. At the time
+ a job is submitted, if no printer name is supplied the <TT
+CLASS="PARAMETER"
+><I
+>%p
+ </I
+></TT
+> will be silently removed from the printer command.</P
+><P
+>If specified in the [global] section, the print command given
+ will be used for any printable service that does not have its own
+ print command specified.</P
+><P
+>If there is neither a specified print command for a
+ printable service nor a global print command, spool files will
+ be created but not processed and (most importantly) not removed.</P
+><P
+>Note that printing may fail on some UNIXes from the
+ <TT
+CLASS="CONSTANT"
+>nobody</TT
+> account. If this happens then create
+ an alternative guest account that can print and set the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+>
+ in the [global] section.</P
+><P
+>You can form quite complex print commands by realizing
+ that they are just passed to a shell. For example the following
+ will log a print job, print the file, then remove it. Note that
+ ';' is the usual separator for command in shell scripts.</P
+><P
+><B
+CLASS="COMMAND"
+>print command = echo Printing %s &#62;&#62;
+ /tmp/print.log; lpr -P %p %s; rm %s</B
+></P
+><P
+>You may have to vary this command considerably depending
+ on how you normally print files on your system. The default for
+ the parameter varies depending on the setting of the <A
+HREF="#PRINTING"
+> <TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: For <B
+CLASS="COMMAND"
+>printing = BSD, AIX, QNX, LPRNG
+ or PLP :</B
+></P
+><P
+><B
+CLASS="COMMAND"
+>print command = lpr -r -P%p %s</B
+></P
+><P
+>For <B
+CLASS="COMMAND"
+>printing = SYSV or HPUX :</B
+></P
+><P
+><B
+CLASS="COMMAND"
+>print command = lp -c -d%p %s; rm %s</B
+></P
+><P
+>For <B
+CLASS="COMMAND"
+>printing = SOFTQ :</B
+></P
+><P
+><B
+CLASS="COMMAND"
+>print command = lp -d%p -s %s; rm %s</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>print command = /usr/local/samba/bin/myprintscript
+ %p %s</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTOK"
+></A
+>print ok (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#PRINTABLE"
+> <TT
+CLASS="PARAMETER"
+><I
+>printable</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="PRINTABLE"
+></A
+>printable (S)</DT
+><DD
+><P
+>If this parameter is <TT
+CLASS="CONSTANT"
+>yes</TT
+>, then
+ clients may open, write to and submit spool files on the directory
+ specified for the service. </P
+><P
+>Note that a printable service will ALWAYS allow writing
+ to the service path (user privileges permitting) via the spooling
+ of print data. The <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writeable
+ </I
+></TT
+></A
+> parameter controls only non-printing access to
+ the resource.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>printable = no</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTCAP"
+></A
+>printcap (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#PRINTCAPNAME"
+><TT
+CLASS="PARAMETER"
+><I
+> printcap name</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="PRINTCAPNAME"
+></A
+>printcap name (G)</DT
+><DD
+><P
+>This parameter may be used to override the
+ compiled-in default printcap name used by the server (usually <TT
+CLASS="FILENAME"
+> /etc/printcap</TT
+>). See the discussion of the <A
+HREF="#AEN79"
+>[printers]</A
+> section above for reasons
+ why you might want to do this.</P
+><P
+>On System V systems that use <B
+CLASS="COMMAND"
+>lpstat</B
+> to
+ list available printers you can use <B
+CLASS="COMMAND"
+>printcap name = lpstat
+ </B
+> to automatically obtain lists of available printers. This
+ is the default for systems that define SYSV at configure time in
+ Samba (this includes most System V based systems). If <TT
+CLASS="PARAMETER"
+><I
+> printcap name</I
+></TT
+> is set to <B
+CLASS="COMMAND"
+>lpstat</B
+> on
+ these systems then Samba will launch <B
+CLASS="COMMAND"
+>lpstat -v</B
+> and
+ attempt to parse the output to obtain a printer list.</P
+><P
+>A minimal printcap file would look something like this:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> print1|My Printer 1
+ print2|My Printer 2
+ print3|My Printer 3
+ print4|My Printer 4
+ print5|My Printer 5
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>where the '|' separates aliases of a printer. The fact
+ that the second alias has a space in it gives a hint to Samba
+ that it's a comment.</P
+><P
+><EM
+>NOTE</EM
+>: Under AIX the default printcap
+ name is <TT
+CLASS="FILENAME"
+>/etc/qconfig</TT
+>. Samba will assume the
+ file is in AIX <TT
+CLASS="FILENAME"
+>qconfig</TT
+> format if the string
+ <TT
+CLASS="FILENAME"
+>qconfig</TT
+> appears in the printcap filename.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>printcap name = /etc/printcap</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printcap name = /etc/myprintcap</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTERADMIN"
+></A
+>printer admin (S)</DT
+><DD
+><P
+>This is a list of users that can do anything to
+ printers via the remote administration interfaces offered by MS-RPC
+ (usually using a NT workstation). Note that the root user always
+ has admin rights.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>printer admin = &#60;empty string&#62;</B
+>
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printer admin = admin, @staff</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTERDRIVER"
+></A
+>printer driver (S)</DT
+><DD
+><P
+><EM
+>Note :</EM
+>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <A
+HREF="printer_driver2.html"
+TARGET="_top"
+>Samba 2.2. Printing
+ HOWTO</A
+> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </P
+><P
+>This option allows you to control the string
+ that clients receive when they ask the server for the printer driver
+ associated with a printer. If you are using Windows95 or Windows NT
+ then you can use this to automate the setup of printers on your
+ system.</P
+><P
+>You need to set this parameter to the exact string (case
+ sensitive) that describes the appropriate printer driver for your
+ system. If you don't know the exact string to use then you should
+ first try with no <A
+HREF="#PRINTERDRIVER"
+><TT
+CLASS="PARAMETER"
+><I
+> printer driver</I
+></TT
+></A
+> option set and the client will
+ give you a list of printer drivers. The appropriate strings are
+ shown in a scroll box after you have chosen the printer manufacturer.</P
+><P
+>See also <A
+HREF="#PRINTERDRIVERFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>printer
+ driver file</I
+></TT
+></A
+>.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printer driver = HP LaserJet 4L</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTERDRIVERFILE"
+></A
+>printer driver file (G)</DT
+><DD
+><P
+><EM
+>Note :</EM
+>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <A
+HREF="printer_driver2.html"
+TARGET="_top"
+>Samba 2.2. Printing
+ HOWTO</A
+> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </P
+><P
+>This parameter tells Samba where the printer driver
+ definition file, used when serving drivers to Windows 95 clients, is
+ to be found. If this is not set, the default is :</P
+><P
+><TT
+CLASS="FILENAME"
+><TT
+CLASS="REPLACEABLE"
+><I
+>SAMBA_INSTALL_DIRECTORY</I
+></TT
+>
+ /lib/printers.def</TT
+></P
+><P
+>This file is created from Windows 95 <TT
+CLASS="FILENAME"
+>msprint.inf
+ </TT
+> files found on the Windows 95 client system. For more
+ details on setting up serving of printer drivers to Windows 95
+ clients, see the outdated documentation file in the <TT
+CLASS="FILENAME"
+>docs/</TT
+>
+ directory, <TT
+CLASS="FILENAME"
+>PRINTER_DRIVER.txt</TT
+>.</P
+><P
+>See also <A
+HREF="#PRINTERDRIVERLOCATION"
+><TT
+CLASS="PARAMETER"
+><I
+> printer driver location</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>None (set in compile).</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printer driver file =
+ /usr/local/samba/printers/drivers.def</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTERDRIVERLOCATION"
+></A
+>printer driver location (S)</DT
+><DD
+><P
+><EM
+>Note :</EM
+>This is a deprecated
+ parameter and will be removed in the next major release
+ following version 2.2. Please see the instructions in
+ the <A
+HREF="printer_driver2.html"
+TARGET="_top"
+>Samba 2.2. Printing
+ HOWTO</A
+> for more information
+ on the new method of loading printer drivers onto a Samba server.
+ </P
+><P
+>This parameter tells clients of a particular printer
+ share where to find the printer driver files for the automatic
+ installation of drivers for Windows 95 machines. If Samba is set up
+ to serve printer drivers to Windows 95 machines, this should be set to</P
+><P
+><B
+CLASS="COMMAND"
+>\\MACHINE\PRINTER$</B
+></P
+><P
+>Where MACHINE is the NetBIOS name of your Samba server,
+ and PRINTER$ is a share you set up for serving printer driver
+ files. For more details on setting this up see the outdated documentation
+ file in the <TT
+CLASS="FILENAME"
+>docs/</TT
+> directory, <TT
+CLASS="FILENAME"
+> PRINTER_DRIVER.txt</TT
+>.</P
+><P
+>See also <A
+HREF="#PRINTERDRIVERFILE"
+><TT
+CLASS="PARAMETER"
+><I
+> printer driver file</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>none</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printer driver location = \\MACHINE\PRINTER$
+ </B
+></P
+></DD
+><DT
+><A
+NAME="PRINTERNAME"
+></A
+>printer name (S)</DT
+><DD
+><P
+>This parameter specifies the name of the printer
+ to which print jobs spooled through a printable service will be sent.</P
+><P
+>If specified in the [global] section, the printer
+ name given will be used for any printable service that does
+ not have its own printer name specified.</P
+><P
+>Default: <EM
+>none (but may be <TT
+CLASS="CONSTANT"
+>lp</TT
+>
+ on many systems)</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>printer name = laserwriter</B
+></P
+></DD
+><DT
+><A
+NAME="PRINTER"
+></A
+>printer (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#PRINTERNAME"
+><TT
+CLASS="PARAMETER"
+><I
+> printer name</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="PRINTING"
+></A
+>printing (S)</DT
+><DD
+><P
+>This parameters controls how printer status
+ information is interpreted on your system. It also affects the
+ default values for the <TT
+CLASS="PARAMETER"
+><I
+>print command</I
+></TT
+>,
+ <TT
+CLASS="PARAMETER"
+><I
+>lpq command</I
+></TT
+>, <TT
+CLASS="PARAMETER"
+><I
+>lppause command
+ </I
+></TT
+>, <TT
+CLASS="PARAMETER"
+><I
+>lpresume command</I
+></TT
+>, and
+ <TT
+CLASS="PARAMETER"
+><I
+>lprm command</I
+></TT
+> if specified in the
+ [global] section.</P
+><P
+>Currently nine printing styles are supported. They are
+ <TT
+CLASS="CONSTANT"
+>BSD</TT
+>, <TT
+CLASS="CONSTANT"
+>AIX</TT
+>,
+ <TT
+CLASS="CONSTANT"
+>LPRNG</TT
+>, <TT
+CLASS="CONSTANT"
+>PLP</TT
+>,
+ <TT
+CLASS="CONSTANT"
+>SYSV</TT
+>, <TT
+CLASS="CONSTANT"
+>HPUX</TT
+>,
+ <TT
+CLASS="CONSTANT"
+>QNX</TT
+>, <TT
+CLASS="CONSTANT"
+>SOFTQ</TT
+>,
+ and <TT
+CLASS="CONSTANT"
+>CUPS</TT
+>.</P
+><P
+>To see what the defaults are for the other print
+ commands when using the various options use the <A
+HREF="testparm.1.html"
+TARGET="_top"
+>testparm(1)</A
+> program.</P
+><P
+>This option can be set on a per printer basis</P
+><P
+>See also the discussion in the <A
+HREF="#AEN79"
+> [printers]</A
+> section.</P
+></DD
+><DT
+><A
+NAME="PROTOCOL"
+></A
+>protocol (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#MAXPROTOCOL"
+> <TT
+CLASS="PARAMETER"
+><I
+>max protocol</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="PUBLIC"
+></A
+>public (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#GUESTOK"
+><TT
+CLASS="PARAMETER"
+><I
+>guest
+ ok</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="QUEUEPAUSECOMMAND"
+></A
+>queuepause command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to pause the printer queue.</P
+><P
+>This command should be a program or script which takes
+ a printer name as its only parameter and stops the printer queue,
+ such that no longer jobs are submitted to the printer.</P
+><P
+>This command is not supported by Windows for Workgroups,
+ but can be issued from the Printers window under Windows 95
+ and NT.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the command.
+ </P
+><P
+>Note that it is good practice to include the absolute
+ path in the command as the PATH may not be available to the
+ server.</P
+><P
+>Default: <EM
+>depends on the setting of <TT
+CLASS="PARAMETER"
+><I
+>printing
+ </I
+></TT
+></EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>queuepause command = disable %p</B
+></P
+></DD
+><DT
+><A
+NAME="QUEUERESUMECOMMAND"
+></A
+>queueresume command (S)</DT
+><DD
+><P
+>This parameter specifies the command to be
+ executed on the server host in order to resume the printer queue. It
+ is the command to undo the behavior that is caused by the
+ previous parameter (<A
+HREF="#QUEUEPAUSECOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+> queuepause command</I
+></TT
+></A
+>).</P
+><P
+>This command should be a program or script which takes
+ a printer name as its only parameter and resumes the printer queue,
+ such that queued jobs are resubmitted to the printer.</P
+><P
+>This command is not supported by Windows for Workgroups,
+ but can be issued from the Printers window under Windows 95
+ and NT.</P
+><P
+>If a <TT
+CLASS="PARAMETER"
+><I
+>%p</I
+></TT
+> is given then the printer name
+ is put in its place. Otherwise it is placed at the end of the
+ command.</P
+><P
+>Note that it is good practice to include the absolute
+ path in the command as the PATH may not be available to the
+ server.</P
+><P
+>Default: <EM
+>depends on the setting of <A
+HREF="#PRINTING"
+><TT
+CLASS="PARAMETER"
+><I
+>printing</I
+></TT
+></A
+></EM
+>
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>queuepause command = enable %p
+ </B
+></P
+></DD
+><DT
+><A
+NAME="READBMPX"
+></A
+>read bmpx (G)</DT
+><DD
+><P
+>This boolean parameter controls whether <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> will support the "Read
+ Block Multiplex" SMB. This is now rarely used and defaults to
+ <TT
+CLASS="CONSTANT"
+>no</TT
+>. You should never need to set this
+ parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>read bmpx = no</B
+></P
+></DD
+><DT
+><A
+NAME="READLIST"
+></A
+>read list (S)</DT
+><DD
+><P
+>This is a list of users that are given read-only
+ access to a service. If the connecting user is in this list then
+ they will not be given write access, no matter what the <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writeable</I
+></TT
+></A
+>
+ option is set to. The list can include group names using the
+ syntax described in the <A
+HREF="#INVALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+> invalid users</I
+></TT
+></A
+> parameter.</P
+><P
+>See also the <A
+HREF="#WRITELIST"
+><TT
+CLASS="PARAMETER"
+><I
+> write list</I
+></TT
+></A
+> parameter and the <A
+HREF="#INVALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>invalid users</I
+></TT
+>
+ </A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>read list = &#60;empty string&#62;</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>read list = mary, @students</B
+></P
+></DD
+><DT
+><A
+NAME="READONLY"
+></A
+>read only (S)</DT
+><DD
+><P
+>Note that this is an inverted synonym for <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writeable</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="READRAW"
+></A
+>read raw (G)</DT
+><DD
+><P
+>This parameter controls whether or not the server
+ will support the raw read SMB requests when transferring data
+ to clients.</P
+><P
+>If enabled, raw reads allow reads of 65535 bytes in
+ one packet. This typically provides a major performance benefit.
+ </P
+><P
+>However, some clients either negotiate the allowable
+ block size incorrectly or are incapable of supporting larger block
+ sizes, and for these clients you may need to disable raw reads.</P
+><P
+>In general this parameter should be viewed as a system tuning
+ tool and left severely alone. See also <A
+HREF="#WRITERAW"
+> <TT
+CLASS="PARAMETER"
+><I
+>write raw</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>read raw = yes</B
+></P
+></DD
+><DT
+><A
+NAME="READSIZE"
+></A
+>read size (G)</DT
+><DD
+><P
+>The option <TT
+CLASS="PARAMETER"
+><I
+>read size</I
+></TT
+>
+ affects the overlap of disk reads/writes with network reads/writes.
+ If the amount of data being transferred in several of the SMB
+ commands (currently SMBwrite, SMBwriteX and SMBreadbraw) is larger
+ than this value then the server begins writing the data before it
+ has received the whole packet from the network, or in the case of
+ SMBreadbraw, it begins writing to the network before all the data
+ has been read from disk.</P
+><P
+>This overlapping works best when the speeds of disk and
+ network access are similar, having very little effect when the
+ speed of one is much greater than the other.</P
+><P
+>The default value is 16384, but very little experimentation
+ has been done yet to determine the optimal value, and it is likely
+ that the best value will vary greatly between systems anyway.
+ A value over 65536 is pointless and will cause you to allocate
+ memory unnecessarily.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>read size = 16384</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>read size = 8192</B
+></P
+></DD
+><DT
+><A
+NAME="REMOTEANNOUNCE"
+></A
+>remote announce (G)</DT
+><DD
+><P
+>This option allows you to setup <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> to periodically announce itself
+ to arbitrary IP addresses with an arbitrary workgroup name.</P
+><P
+>This is useful if you want your Samba server to appear
+ in a remote workgroup for which the normal browse propagation
+ rules don't work. The remote workgroup can be anywhere that you
+ can send IP packets to.</P
+><P
+>For example:</P
+><P
+><B
+CLASS="COMMAND"
+>remote announce = 192.168.2.255/SERVERS
+ 192.168.4.255/STAFF</B
+></P
+><P
+>the above line would cause <B
+CLASS="COMMAND"
+>nmbd</B
+> to announce itself
+ to the two given IP addresses using the given workgroup names.
+ If you leave out the workgroup name then the one given in
+ the <A
+HREF="#WORKGROUP"
+><TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+></A
+>
+ parameter is used instead.</P
+><P
+>The IP addresses you choose would normally be the broadcast
+ addresses of the remote networks, but can also be the IP addresses
+ of known browse masters if your network config is that stable.</P
+><P
+>See the documentation file <TT
+CLASS="FILENAME"
+>BROWSING.txt</TT
+>
+ in the <TT
+CLASS="FILENAME"
+>docs/</TT
+> directory.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>remote announce = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="REMOTEBROWSESYNC"
+></A
+>remote browse sync (G)</DT
+><DD
+><P
+>This option allows you to setup <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> to periodically request
+ synchronization of browse lists with the master browser of a Samba
+ server that is on a remote segment. This option will allow you to
+ gain browse lists for multiple workgroups across routed networks. This
+ is done in a manner that does not work with any non-Samba servers.</P
+><P
+>This is useful if you want your Samba server and all local
+ clients to appear in a remote workgroup for which the normal browse
+ propagation rules don't work. The remote workgroup can be anywhere
+ that you can send IP packets to.</P
+><P
+>For example:</P
+><P
+><B
+CLASS="COMMAND"
+>remote browse sync = 192.168.2.255 192.168.4.255
+ </B
+></P
+><P
+>the above line would cause <B
+CLASS="COMMAND"
+>nmbd</B
+> to request
+ the master browser on the specified subnets or addresses to
+ synchronize their browse lists with the local server.</P
+><P
+>The IP addresses you choose would normally be the broadcast
+ addresses of the remote networks, but can also be the IP addresses
+ of known browse masters if your network config is that stable. If
+ a machine IP address is given Samba makes NO attempt to validate
+ that the remote machine is available, is listening, nor that it
+ is in fact the browse master on its segment.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>remote browse sync = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="RESTRICTANONYMOUS"
+></A
+>restrict anonymous (G)</DT
+><DD
+><P
+>This is a boolean parameter. If it is <TT
+CLASS="CONSTANT"
+>true</TT
+>, then
+ anonymous access to the server will be restricted, namely in the
+ case where the server is expecting the client to send a username,
+ but it doesn't. Setting it to <TT
+CLASS="CONSTANT"
+>true</TT
+> will force these anonymous
+ connections to be denied, and the client will be required to always
+ supply a username and password when connecting. Use of this parameter
+ is only recommended for homogeneous NT client environments.</P
+><P
+>This parameter makes the use of macro expansions that rely
+ on the username (%U, %G, etc) consistent. NT 4.0
+ likes to use anonymous connections when refreshing the share list,
+ and this is a way to work around that.</P
+><P
+>When restrict anonymous is <TT
+CLASS="CONSTANT"
+>true</TT
+>, all anonymous connections
+ are denied no matter what they are for. This can effect the ability
+ of a machine to access the Samba Primary Domain Controller to revalidate
+ its machine account after someone else has logged on the client
+ interactively. The NT client will display a message saying that
+ the machine's account in the domain doesn't exist or the password is
+ bad. The best way to deal with this is to reboot NT client machines
+ between interactive logons, using "Shutdown and Restart", rather
+ than "Close all programs and logon as a different user".</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>restrict anonymous = no</B
+></P
+></DD
+><DT
+><A
+NAME="ROOT"
+></A
+>root (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#ROOTDIRECTORY"
+> <TT
+CLASS="PARAMETER"
+><I
+>root directory"</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="ROOTDIR"
+></A
+>root dir (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#ROOTDIRECTORY"
+> <TT
+CLASS="PARAMETER"
+><I
+>root directory"</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="ROOTDIRECTORY"
+></A
+>root directory (G)</DT
+><DD
+><P
+>The server will <B
+CLASS="COMMAND"
+>chroot()</B
+> (i.e.
+ Change its root directory) to this directory on startup. This is
+ not strictly necessary for secure operation. Even without it the
+ server will deny access to files not in one of the service entries.
+ It may also check for, and deny access to, soft links to other
+ parts of the filesystem, or attempts to use ".." in file names
+ to access other directories (depending on the setting of the <A
+HREF="#WIDELINKS"
+><TT
+CLASS="PARAMETER"
+><I
+>wide links</I
+></TT
+></A
+>
+ parameter).</P
+><P
+>Adding a <TT
+CLASS="PARAMETER"
+><I
+>root directory</I
+></TT
+> entry other
+ than "/" adds an extra level of security, but at a price. It
+ absolutely ensures that no access is given to files not in the
+ sub-tree specified in the <TT
+CLASS="PARAMETER"
+><I
+>root directory</I
+></TT
+>
+ option, <EM
+>including</EM
+> some files needed for
+ complete operation of the server. To maintain full operability
+ of the server you will need to mirror some system files
+ into the <TT
+CLASS="PARAMETER"
+><I
+>root directory</I
+></TT
+> tree. In particular
+ you will need to mirror <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+> (or a
+ subset of it), and any binaries or configuration files needed for
+ printing (if required). The set of files that must be mirrored is
+ operating system dependent.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>root directory = /</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>root directory = /homes/smb</B
+></P
+></DD
+><DT
+><A
+NAME="ROOTPOSTEXEC"
+></A
+>root postexec (S)</DT
+><DD
+><P
+>This is the same as the <TT
+CLASS="PARAMETER"
+><I
+>postexec</I
+></TT
+>
+ parameter except that the command is run as root. This
+ is useful for unmounting filesystems
+ (such as CDROMs) after a connection is closed.</P
+><P
+>See also <A
+HREF="#POSTEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+> postexec</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>root postexec = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="ROOTPREEXEC"
+></A
+>root preexec (S)</DT
+><DD
+><P
+>This is the same as the <TT
+CLASS="PARAMETER"
+><I
+>preexec</I
+></TT
+>
+ parameter except that the command is run as root. This
+ is useful for mounting filesystems (such as CDROMs) when a
+ connection is opened.</P
+><P
+>See also <A
+HREF="#PREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+> preexec</I
+></TT
+></A
+> and <A
+HREF="#PREEXECCLOSE"
+> <TT
+CLASS="PARAMETER"
+><I
+>preexec close</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>root preexec = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="ROOTPREEXECCLOSE"
+></A
+>root preexec close (S)</DT
+><DD
+><P
+>This is the same as the <TT
+CLASS="PARAMETER"
+><I
+>preexec close
+ </I
+></TT
+> parameter except that the command is run as root.</P
+><P
+>See also <A
+HREF="#PREEXEC"
+><TT
+CLASS="PARAMETER"
+><I
+> preexec</I
+></TT
+></A
+> and <A
+HREF="#PREEXECCLOSE"
+> <TT
+CLASS="PARAMETER"
+><I
+>preexec close</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>root preexec close = no</B
+></P
+></DD
+><DT
+><A
+NAME="SECURITY"
+></A
+>security (G)</DT
+><DD
+><P
+>This option affects how clients respond to
+ Samba and is one of the most important settings in the <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> file.</P
+><P
+>The option sets the "security mode bit" in replies to
+ protocol negotiations with <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)
+ </A
+> to turn share level security on or off. Clients decide
+ based on this bit whether (and how) to transfer user and password
+ information to the server.</P
+><P
+>The default is <B
+CLASS="COMMAND"
+>security = user</B
+>, as this is
+ the most common setting needed when talking to Windows 98 and
+ Windows NT.</P
+><P
+>The alternatives are <B
+CLASS="COMMAND"
+>security = share</B
+>,
+ <B
+CLASS="COMMAND"
+>security = server</B
+> or <B
+CLASS="COMMAND"
+>security = domain
+ </B
+>.</P
+><P
+>In versions of Samba prior to 2.0.0, the default was
+ <B
+CLASS="COMMAND"
+>security = share</B
+> mainly because that was
+ the only option at one stage.</P
+><P
+>There is a bug in WfWg that has relevance to this
+ setting. When in user or server level security a WfWg client
+ will totally ignore the password you type in the "connect
+ drive" dialog box. This makes it very difficult (if not impossible)
+ to connect to a Samba service as anyone except the user that
+ you are logged into WfWg as.</P
+><P
+>If your PCs use usernames that are the same as their
+ usernames on the UNIX machine then you will want to use
+ <B
+CLASS="COMMAND"
+>security = user</B
+>. If you mostly use usernames
+ that don't exist on the UNIX box then use <B
+CLASS="COMMAND"
+>security =
+ share</B
+>.</P
+><P
+>You should also use <B
+CLASS="COMMAND"
+>security = share</B
+> if you
+ want to mainly setup shares without a password (guest shares). This
+ is commonly used for a shared printer server. It is more difficult
+ to setup guest shares with <B
+CLASS="COMMAND"
+>security = user</B
+>, see
+ the <A
+HREF="#MAPTOGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>map to guest</I
+></TT
+>
+ </A
+>parameter for details.</P
+><P
+>It is possible to use <B
+CLASS="COMMAND"
+>smbd</B
+> in a <EM
+> hybrid mode</EM
+> where it is offers both user and share
+ level security under different <A
+HREF="#NETBIOSALIASES"
+> <TT
+CLASS="PARAMETER"
+><I
+>NetBIOS aliases</I
+></TT
+></A
+>. </P
+><P
+>The different settings will now be explained.</P
+><P
+><A
+NAME="SECURITYEQUALSSHARE"
+></A
+><EM
+>SECURITY = SHARE
+ </EM
+></P
+><P
+>When clients connect to a share level security server they
+ need not log onto the server with a valid username and password before
+ attempting to connect to a shared resource (although modern clients
+ such as Windows 95/98 and Windows NT will send a logon request with
+ a username but no password when talking to a <B
+CLASS="COMMAND"
+>security = share
+ </B
+> server). Instead, the clients send authentication information
+ (passwords) on a per-share basis, at the time they attempt to connect
+ to that share.</P
+><P
+>Note that <B
+CLASS="COMMAND"
+>smbd</B
+> <EM
+>ALWAYS</EM
+>
+ uses a valid UNIX user to act on behalf of the client, even in
+ <B
+CLASS="COMMAND"
+>security = share</B
+> level security.</P
+><P
+>As clients are not required to send a username to the server
+ in share level security, <B
+CLASS="COMMAND"
+>smbd</B
+> uses several
+ techniques to determine the correct UNIX user to use on behalf
+ of the client.</P
+><P
+>A list of possible UNIX usernames to match with the given
+ client password is constructed using the following methods :</P
+><P
+></P
+><UL
+><LI
+><P
+>If the <A
+HREF="#GUESTONLY"
+><TT
+CLASS="PARAMETER"
+><I
+>guest
+ only</I
+></TT
+></A
+> parameter is set, then all the other
+ stages are missed and only the <A
+HREF="#GUESTACCOUNT"
+> <TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+> username is checked.
+ </P
+></LI
+><LI
+><P
+>Is a username is sent with the share connection
+ request, then this username (after mapping - see <A
+HREF="#USERNAMEMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>username map</I
+></TT
+></A
+>),
+ is added as a potential username.</P
+></LI
+><LI
+><P
+>If the client did a previous <EM
+>logon
+ </EM
+> request (the SessionSetup SMB call) then the
+ username sent in this SMB will be added as a potential username.
+ </P
+></LI
+><LI
+><P
+>The name of the service the client requested is
+ added as a potential username.</P
+></LI
+><LI
+><P
+>The NetBIOS name of the client is added to
+ the list as a potential username.</P
+></LI
+><LI
+><P
+>Any users on the <A
+HREF="#USER"
+><TT
+CLASS="PARAMETER"
+><I
+> user</I
+></TT
+></A
+> list are added as potential usernames.
+ </P
+></LI
+></UL
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>guest only</I
+></TT
+> parameter is
+ not set, then this list is then tried with the supplied password.
+ The first user for whom the password matches will be used as the
+ UNIX user.</P
+><P
+>If the <TT
+CLASS="PARAMETER"
+><I
+>guest only</I
+></TT
+> parameter is
+ set, or no username can be determined then if the share is marked
+ as available to the <TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+>, then this
+ guest user will be used, otherwise access is denied.</P
+><P
+>Note that it can be <EM
+>very</EM
+> confusing
+ in share-level security as to which UNIX username will eventually
+ be used in granting access.</P
+><P
+>See also the section <A
+HREF="#AEN235"
+> NOTE ABOUT USERNAME/PASSWORD VALIDATION</A
+>.</P
+><P
+><A
+NAME="SECURITYEQUALSUSER"
+></A
+><EM
+>SECURITY = USER
+ </EM
+></P
+><P
+>This is the default security setting in Samba 2.2.
+ With user-level security a client must first "log-on" with a
+ valid username and password (which can be mapped using the <A
+HREF="#USERNAMEMAP"
+><TT
+CLASS="PARAMETER"
+><I
+>username map</I
+></TT
+></A
+>
+ parameter). Encrypted passwords (see the <A
+HREF="#ENCRYPTPASSWORDS"
+> <TT
+CLASS="PARAMETER"
+><I
+>encrypted passwords</I
+></TT
+></A
+> parameter) can also
+ be used in this security mode. Parameters such as <A
+HREF="#USER"
+> <TT
+CLASS="PARAMETER"
+><I
+>user</I
+></TT
+></A
+> and <A
+HREF="#GUESTONLY"
+> <TT
+CLASS="PARAMETER"
+><I
+>guest only</I
+></TT
+></A
+> if set are then applied and
+ may change the UNIX user to use on this connection, but only after
+ the user has been successfully authenticated.</P
+><P
+><EM
+>Note</EM
+> that the name of the resource being
+ requested is <EM
+>not</EM
+> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+>.
+ See the <A
+HREF="#MAPTOGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>map to guest</I
+></TT
+>
+ </A
+> parameter for details on doing this.</P
+><P
+>See also the section <A
+HREF="#AEN235"
+> NOTE ABOUT USERNAME/PASSWORD VALIDATION</A
+>.</P
+><P
+><A
+NAME="SECURITYEQUALSSERVER"
+></A
+><EM
+>SECURITY = SERVER
+ </EM
+></P
+><P
+>In this mode Samba will try to validate the username/password
+ by passing it to another SMB server, such as an NT box. If this
+ fails it will revert to <B
+CLASS="COMMAND"
+>security = user</B
+>, but note
+ that if encrypted passwords have been negotiated then Samba cannot
+ revert back to checking the UNIX password file, it must have a valid
+ <TT
+CLASS="FILENAME"
+>smbpasswd</TT
+> file to check users against. See the
+ documentation file in the <TT
+CLASS="FILENAME"
+>docs/</TT
+> directory
+ <TT
+CLASS="FILENAME"
+>ENCRYPTION.txt</TT
+> for details on how to set this
+ up.</P
+><P
+><EM
+>Note</EM
+> that from the client's point of
+ view <B
+CLASS="COMMAND"
+>security = server</B
+> is the same as <B
+CLASS="COMMAND"
+> security = user</B
+>. It only affects how the server deals
+ with the authentication, it does not in any way affect what the
+ client sees.</P
+><P
+><EM
+>Note</EM
+> that the name of the resource being
+ requested is <EM
+>not</EM
+> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+>.
+ See the <A
+HREF="#MAPTOGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>map to guest</I
+></TT
+>
+ </A
+> parameter for details on doing this.</P
+><P
+>See also the section <A
+HREF="#AEN235"
+> NOTE ABOUT USERNAME/PASSWORD VALIDATION</A
+>.</P
+><P
+>See also the <A
+HREF="#PASSWORDSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>password
+ server</I
+></TT
+></A
+> parameter and the <A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypted passwords</I
+></TT
+>
+ </A
+> parameter.</P
+><P
+><A
+NAME="SECURITYEQUALSDOMAIN"
+></A
+><EM
+>SECURITY = DOMAIN
+ </EM
+></P
+><P
+>This mode will only work correctly if <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+>smbpasswd(8)</A
+> has been used to add this
+ machine into a Windows NT Domain. It expects the <A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypted passwords</I
+></TT
+>
+ </A
+> parameter to be set to <TT
+CLASS="CONSTANT"
+>true</TT
+>. In this
+ mode Samba will try to validate the username/password by passing
+ it to a Windows NT Primary or Backup Domain Controller, in exactly
+ the same way that a Windows NT Server would do.</P
+><P
+><EM
+>Note</EM
+> that a valid UNIX user must still
+ exist as well as the account on the Domain Controller to allow
+ Samba to have a valid UNIX account to map file access to.</P
+><P
+><EM
+>Note</EM
+> that from the client's point
+ of view <B
+CLASS="COMMAND"
+>security = domain</B
+> is the same as <B
+CLASS="COMMAND"
+>security = user
+ </B
+>. It only affects how the server deals with the authentication,
+ it does not in any way affect what the client sees.</P
+><P
+><EM
+>Note</EM
+> that the name of the resource being
+ requested is <EM
+>not</EM
+> sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the <A
+HREF="#GUESTACCOUNT"
+><TT
+CLASS="PARAMETER"
+><I
+>guest account</I
+></TT
+></A
+>.
+ See the <A
+HREF="#MAPTOGUEST"
+><TT
+CLASS="PARAMETER"
+><I
+>map to guest</I
+></TT
+>
+ </A
+> parameter for details on doing this.</P
+><P
+><EM
+>BUG:</EM
+> There is currently a bug in the
+ implementation of <B
+CLASS="COMMAND"
+>security = domain</B
+> with respect
+ to multi-byte character set usernames. The communication with a
+ Domain Controller must be done in UNICODE and Samba currently
+ does not widen multi-byte user names to UNICODE correctly, thus
+ a multi-byte username will not be recognized correctly at the
+ Domain Controller. This issue will be addressed in a future release.</P
+><P
+>See also the section <A
+HREF="#AEN235"
+> NOTE ABOUT USERNAME/PASSWORD VALIDATION</A
+>.</P
+><P
+>See also the <A
+HREF="#PASSWORDSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+>password
+ server</I
+></TT
+></A
+> parameter and the <A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypted passwords</I
+></TT
+>
+ </A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>security = USER</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>security = DOMAIN</B
+></P
+></DD
+><DT
+><A
+NAME="SECURITYMASK"
+></A
+>security mask (S)</DT
+><DD
+><P
+>This parameter controls what UNIX permission
+ bits can be modified when a Windows NT client is manipulating
+ the UNIX permission on a file using the native NT security
+ dialog box.</P
+><P
+>This parameter is applied as a mask (AND'ed with) to
+ the changed permission bits, thus preventing any bits not in
+ this mask from being modified. Essentially, zero bits in this
+ mask may be treated as a set of bits the user is not allowed
+ to change.</P
+><P
+>If not set explicitly this parameter is 0777, allowing
+ a user to modify all the user/group/world permissions on a file.
+ </P
+><P
+><EM
+>Note</EM
+> that users who can access the
+ Samba server through other means can easily bypass this
+ restriction, so it is primarily useful for standalone
+ "appliance" systems. Administrators of most normal systems will
+ probably want to leave it set to <TT
+CLASS="CONSTANT"
+>0777</TT
+>.</P
+><P
+>See also the <A
+HREF="#FORCEDIRECTORYSECURITYMODE"
+> <TT
+CLASS="PARAMETER"
+><I
+>force directory security mode</I
+></TT
+></A
+>,
+ <A
+HREF="#DIRECTORYSECURITYMASK"
+><TT
+CLASS="PARAMETER"
+><I
+>directory
+ security mask</I
+></TT
+></A
+>, <A
+HREF="#FORCESECURITYMODE"
+> <TT
+CLASS="PARAMETER"
+><I
+>force security mode</I
+></TT
+></A
+> parameters.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>security mask = 0777</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>security mask = 0770</B
+></P
+></DD
+><DT
+><A
+NAME="SERVERSTRING"
+></A
+>server string (G)</DT
+><DD
+><P
+>This controls what string will show up in the
+ printer comment box in print manager and next to the IPC connection
+ in <B
+CLASS="COMMAND"
+>net view</B
+>. It can be any string that you wish
+ to show to your users.</P
+><P
+>It also sets what will appear in browse lists next
+ to the machine name.</P
+><P
+>A <TT
+CLASS="PARAMETER"
+><I
+>%v</I
+></TT
+> will be replaced with the Samba
+ version number.</P
+><P
+>A <TT
+CLASS="PARAMETER"
+><I
+>%h</I
+></TT
+> will be replaced with the
+ hostname.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>server string = Samba %v</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>server string = University of GNUs Samba
+ Server</B
+></P
+></DD
+><DT
+><A
+NAME="SETDIRECTORY"
+></A
+>set directory (S)</DT
+><DD
+><P
+>If <B
+CLASS="COMMAND"
+>set directory = no</B
+>, then
+ users of the service may not use the setdir command to change
+ directory.</P
+><P
+>The <B
+CLASS="COMMAND"
+>setdir</B
+> command is only implemented
+ in the Digital Pathworks client. See the Pathworks documentation
+ for details.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>set directory = no</B
+></P
+></DD
+><DT
+><A
+NAME="SHORTPRESERVECASE"
+></A
+>short preserve case (S)</DT
+><DD
+><P
+>This boolean parameter controls if new files
+ which conform to 8.3 syntax, that is all in upper case and of
+ suitable length, are created upper case, or if they are forced
+ to be the <A
+HREF="#DEFAULTCASE"
+><TT
+CLASS="PARAMETER"
+><I
+>default case
+ </I
+></TT
+></A
+>. This option can be use with <A
+HREF="#PRESERVECASE"
+><B
+CLASS="COMMAND"
+>preserve case = yes</B
+>
+ </A
+> to permit long filenames to retain their case, while short
+ names are lowered. </P
+><P
+>See the section on <A
+HREF="#AEN202"
+> NAME MANGLING</A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>short preserve case = yes</B
+></P
+></DD
+><DT
+><A
+NAME="SHOWADDPRINTERWIZARD"
+></A
+>show add printer wizard (G)</DT
+><DD
+><P
+>With the introduction of MS-RPC based printing support
+ for Windows NT/2000 client in Samba 2.2, a "Printers..." folder will
+ appear on Samba hosts in the share listing. Normally this folder will
+ contain an icon for the MS Add Printer Wizard (APW). However, it is
+ possible to disable this feature regardless of the level of privilege
+ of the connected user.</P
+><P
+>Under normal circumstances, the Windows NT/2000 client will
+ open a handle on the printer server with OpenPrinterEx() asking for
+ Administrator privileges. If the user does not have administrative
+ access on the print server (i.e is not root or a member of the
+ <TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+> group), the OpenPrinterEx()
+ call fails and the client makes another open call with a request for
+ a lower privilege level. This should succeed, however the APW
+ icon will not be displayed.</P
+><P
+>Disabling the <TT
+CLASS="PARAMETER"
+><I
+>show add printer wizard</I
+></TT
+>
+ parameter will always cause the OpenPrinterEx() on the server
+ to fail. Thus the APW icon will never be displayed. <EM
+> Note :</EM
+>This does not prevent the same user from having
+ administrative privilege on an individual printer.</P
+><P
+>See also <A
+HREF="#ADDPRINTERCOMMAND"
+><TT
+CLASS="PARAMETER"
+><I
+>addprinter
+ command</I
+></TT
+></A
+>, <A
+HREF="#DELETEPRINTERCOMMAND"
+> <TT
+CLASS="PARAMETER"
+><I
+>deleteprinter command</I
+></TT
+></A
+>, <A
+HREF="#PRINTERADMIN"
+><TT
+CLASS="PARAMETER"
+><I
+>printer admin</I
+></TT
+></A
+></P
+><P
+>Default :<B
+CLASS="COMMAND"
+>show add printer wizard = yes</B
+></P
+></DD
+><DT
+><A
+NAME="SHUTDOWNSCRIPT"
+></A
+>shutdown script (G)</DT
+><DD
+><P
+><EM
+>This parameter only exists in the HEAD cvs branch</EM
+>
+ This a full path name to a script called by
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> that
+ should start a shutdown procedure.</P
+><P
+>This command will be run as the user connected to the
+ server.</P
+><P
+>%m %t %r %f parameters are expanded</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%m</I
+></TT
+> will be substituted with the
+ shutdown message sent to the server.</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%t</I
+></TT
+> will be substituted with the
+ number of seconds to wait before effectively starting the
+ shutdown procedure.</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%r</I
+></TT
+> will be substituted with the
+ switch <EM
+>-r</EM
+>. It means reboot after shutdown
+ for NT.
+ </P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>%f</I
+></TT
+> will be substituted with the
+ switch <EM
+>-f</EM
+>. It means force the shutdown
+ even if applications do not respond for NT.</P
+><P
+>Default: <EM
+>None</EM
+>.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>abort shutdown script = /usr/local/samba/sbin/shutdown %m %t %r %f</B
+></P
+><P
+>Shutdown script example:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> #!/bin/bash
+
+ $time=0
+ let "time/60"
+ let "time++"
+
+ /sbin/shutdown $3 $4 +$time $1 &#38;
+ </PRE
+></TD
+></TR
+></TABLE
+>
+ Shutdown does not return so we need to launch it in background.
+ </P
+><P
+>See also <A
+HREF="#ABORTSHUTDOWNSCRIPT"
+><TT
+CLASS="PARAMETER"
+><I
+>abort shutdown script</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="SMBPASSWDFILE"
+></A
+>smb passwd file (G)</DT
+><DD
+><P
+>This option sets the path to the encrypted
+ smbpasswd file. By default the path to the smbpasswd file
+ is compiled into Samba.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>smb passwd file = ${prefix}/private/smbpasswd
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>smb passwd file = /etc/samba/smbpasswd
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SOCKETADDRESS"
+></A
+>socket address (G)</DT
+><DD
+><P
+>This option allows you to control what
+ address Samba will listen for connections on. This is used to
+ support multiple virtual interfaces on the one server, each
+ with a different configuration.</P
+><P
+>By default Samba will accept connections on any
+ address.</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>socket address = 192.168.2.20</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="SOCKETOPTIONS"
+></A
+>socket options (G)</DT
+><DD
+><P
+>This option allows you to set socket options
+ to be used when talking with the client.</P
+><P
+>Socket options are controls on the networking layer
+ of the operating systems which allow the connection to be
+ tuned.</P
+><P
+>This option will typically be used to tune your Samba
+ server for optimal performance for your local network. There is
+ no way that Samba can know what the optimal parameters are for
+ your net, so you must experiment and choose them yourself. We
+ strongly suggest you read the appropriate documentation for your
+ operating system first (perhaps <B
+CLASS="COMMAND"
+>man setsockopt</B
+>
+ will help).</P
+><P
+>You may find that on some systems Samba will say
+ "Unknown socket option" when you supply an option. This means you
+ either incorrectly typed it or you need to add an include file
+ to includes.h for your OS. If the latter is the case please
+ send the patch to <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+> samba@samba.org</A
+>.</P
+><P
+>Any of the supported socket options may be combined
+ in any way you like, as long as your OS allows it.</P
+><P
+>This is the list of socket options currently settable
+ using this option:</P
+><P
+></P
+><UL
+><LI
+><P
+>SO_KEEPALIVE</P
+></LI
+><LI
+><P
+>SO_REUSEADDR</P
+></LI
+><LI
+><P
+>SO_BROADCAST</P
+></LI
+><LI
+><P
+>TCP_NODELAY</P
+></LI
+><LI
+><P
+>IPTOS_LOWDELAY</P
+></LI
+><LI
+><P
+>IPTOS_THROUGHPUT</P
+></LI
+><LI
+><P
+>SO_SNDBUF *</P
+></LI
+><LI
+><P
+>SO_RCVBUF *</P
+></LI
+><LI
+><P
+>SO_SNDLOWAT *</P
+></LI
+><LI
+><P
+>SO_RCVLOWAT *</P
+></LI
+></UL
+><P
+>Those marked with a <EM
+>'*'</EM
+> take an integer
+ argument. The others can optionally take a 1 or 0 argument to enable
+ or disable the option, by default they will be enabled if you
+ don't specify 1 or 0.</P
+><P
+>To specify an argument use the syntax SOME_OPTION = VALUE
+ for example <B
+CLASS="COMMAND"
+>SO_SNDBUF = 8192</B
+>. Note that you must
+ not have any spaces before or after the = sign.</P
+><P
+>If you are on a local network then a sensible option
+ might be</P
+><P
+><B
+CLASS="COMMAND"
+>socket options = IPTOS_LOWDELAY</B
+></P
+><P
+>If you have a local network then you could try:</P
+><P
+><B
+CLASS="COMMAND"
+>socket options = IPTOS_LOWDELAY TCP_NODELAY</B
+></P
+><P
+>If you are on a wide area network then perhaps try
+ setting IPTOS_THROUGHPUT. </P
+><P
+>Note that several of the options may cause your Samba
+ server to fail completely. Use these options with caution!</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>socket options = TCP_NODELAY</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>socket options = IPTOS_LOWDELAY</B
+></P
+></DD
+><DT
+><A
+NAME="SOURCEENVIRONMENT"
+></A
+>source environment (G)</DT
+><DD
+><P
+>This parameter causes Samba to set environment
+ variables as per the content of the file named.</P
+><P
+>If the value of this parameter starts with a "|" character
+ then Samba will treat that value as a pipe command to open and
+ will set the environment variables from the output of the pipe.</P
+><P
+>The contents of the file or the output of the pipe should
+ be formatted as the output of the standard Unix <B
+CLASS="COMMAND"
+>env(1)
+ </B
+> command. This is of the form :</P
+><P
+>Example environment entry:</P
+><P
+><B
+CLASS="COMMAND"
+>SAMBA_NETBIOS_NAME = myhostname</B
+></P
+><P
+>Default: <EM
+>No default value</EM
+></P
+><P
+>Examples: <B
+CLASS="COMMAND"
+>source environment = |/etc/smb.conf.sh
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>source environment =
+ /usr/local/smb_env_vars</B
+></P
+></DD
+><DT
+><A
+NAME="SSL"
+></A
+>ssl (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This variable enables or disables the entire SSL mode. If
+ it is set to <TT
+CLASS="CONSTANT"
+>no</TT
+>, the SSL-enabled Samba behaves
+ exactly like the non-SSL Samba. If set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>,
+ it depends on the variables <A
+HREF="#SSLHOSTS"
+><TT
+CLASS="PARAMETER"
+><I
+> ssl hosts</I
+></TT
+></A
+> and <A
+HREF="#SSLHOSTSRESIGN"
+> <TT
+CLASS="PARAMETER"
+><I
+>ssl hosts resign</I
+></TT
+></A
+> whether an SSL
+ connection will be required.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl = no</B
+></P
+></DD
+><DT
+><A
+NAME="SSLCACERTDIR"
+></A
+>ssl CA certDir (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This variable defines where to look up the Certification
+ Authorities. The given directory should contain one file for
+ each CA that Samba will trust. The file name must be the hash
+ value over the "Distinguished Name" of the CA. How this directory
+ is set up is explained later in this document. All files within the
+ directory that don't fit into this naming scheme are ignored. You
+ don't need this variable if you don't verify client certificates.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl CA certDir = /usr/local/ssl/certs
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLCACERTFILE"
+></A
+>ssl CA certFile (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This variable is a second way to define the trusted CAs.
+ The certificates of the trusted CAs are collected in one big
+ file and this variable points to the file. You will probably
+ only use one of the two ways to define your CAs. The first choice is
+ preferable if you have many CAs or want to be flexible, the second
+ is preferable if you only have one CA and want to keep things
+ simple (you won't need to create the hashed file names). You
+ don't need this variable if you don't verify client certificates.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl CA certFile = /usr/local/ssl/certs/trustedCAs.pem
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLCIPHERS"
+></A
+>ssl ciphers (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This variable defines the ciphers that should be offered
+ during SSL negotiation. You should not set this variable unless
+ you know what you are doing.</P
+></DD
+><DT
+><A
+NAME="SSLCLIENTCERT"
+></A
+>ssl client cert (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>The certificate in this file is used by <A
+HREF="smbclient.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+> if it exists. It's needed
+ if the server requires a client certificate.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl client cert = /usr/local/ssl/certs/smbclient.pem
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLCLIENTKEY"
+></A
+>ssl client key (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This is the private key for <A
+HREF="smbclient.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>. It's only needed if the
+ client should have a certificate. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl client key = /usr/local/ssl/private/smbclient.pem
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLCOMPATIBILITY"
+></A
+>ssl compatibility (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This variable defines whether OpenSSL should be configured
+ for bug compatibility with other SSL implementations. This is
+ probably not desirable because currently no clients with SSL
+ implementations other than OpenSSL exist.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl compatibility = no</B
+></P
+></DD
+><DT
+><A
+NAME="SSLEGDSOCKET"
+></A
+>ssl egd socket (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+> This option is used to define the location of the communiation socket of
+ an EGD or PRNGD daemon, from which entropy can be retrieved. This option
+ can be used instead of or together with the <A
+HREF="#SSLENTROPYFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl entropy file</I
+></TT
+></A
+>
+ directive. 255 bytes of entropy will be retrieved from the daemon.
+ </P
+><P
+>Default: <EM
+>none</EM
+></P
+></DD
+><DT
+><A
+NAME="SSLENTROPYBYTES"
+></A
+>ssl entropy bytes (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+> This parameter is used to define the number of bytes which should
+ be read from the <A
+HREF="#SSLENTROPYFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl entropy
+ file</I
+></TT
+></A
+> If a -1 is specified, the entire file will
+ be read.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl entropy bytes = 255</B
+></P
+></DD
+><DT
+><A
+NAME="SSLENTROPYFILE"
+></A
+>ssl entropy file (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+> This parameter is used to specify a file from which processes will
+ read "random bytes" on startup. In order to seed the internal pseudo
+ random number generator, entropy must be provided. On system with a
+ <TT
+CLASS="FILENAME"
+>/dev/urandom</TT
+> device file, the processes
+ will retrieve its entropy from the kernel. On systems without kernel
+ entropy support, a file can be supplied that will be read on startup
+ and that will be used to seed the PRNG.
+ </P
+><P
+>Default: <EM
+>none</EM
+></P
+></DD
+><DT
+><A
+NAME="SSLHOSTS"
+></A
+>ssl hosts (G)</DT
+><DD
+><P
+>See <A
+HREF="#SSLHOSTSRESIGN"
+><TT
+CLASS="PARAMETER"
+><I
+> ssl hosts resign</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="SSLHOSTSRESIGN"
+></A
+>ssl hosts resign (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>These two variables define whether Samba will go
+ into SSL mode or not. If none of them is defined, Samba will
+ allow only SSL connections. If the <A
+HREF="#SSLHOSTS"
+> <TT
+CLASS="PARAMETER"
+><I
+>ssl hosts</I
+></TT
+></A
+> variable lists
+ hosts (by IP-address, IP-address range, net group or name),
+ only these hosts will be forced into SSL mode. If the <TT
+CLASS="PARAMETER"
+><I
+> ssl hosts resign</I
+></TT
+> variable lists hosts, only these
+ hosts will <EM
+>NOT</EM
+> be forced into SSL mode. The syntax for these two
+ variables is the same as for the <A
+HREF="#HOSTSALLOW"
+><TT
+CLASS="PARAMETER"
+><I
+> hosts allow</I
+></TT
+></A
+> and <A
+HREF="#HOSTSDENY"
+> <TT
+CLASS="PARAMETER"
+><I
+>hosts deny</I
+></TT
+></A
+> pair of variables, only
+ that the subject of the decision is different: It's not the access
+ right but whether SSL is used or not. </P
+><P
+>The example below requires SSL connections from all hosts
+ outside the local net (which is 192.168.*.*).</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl hosts = &#60;empty string&#62;</B
+></P
+><P
+><B
+CLASS="COMMAND"
+>ssl hosts resign = &#60;empty string&#62;</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>ssl hosts resign = 192.168.</B
+></P
+></DD
+><DT
+><A
+NAME="SSLREQUIRECLIENTCERT"
+></A
+>ssl require clientcert (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>If this variable is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>, the
+ server will not tolerate connections from clients that don't
+ have a valid certificate. The directory/file given in <A
+HREF="#SSLCACERTDIR"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl CA certDir</I
+></TT
+>
+ </A
+> and <A
+HREF="#SSLCACERTFILE"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl CA certFile
+ </I
+></TT
+></A
+> will be used to look up the CAs that issued
+ the client's certificate. If the certificate can't be verified
+ positively, the connection will be terminated. If this variable
+ is set to <TT
+CLASS="CONSTANT"
+>no</TT
+>, clients don't need certificates.
+ Contrary to web applications you really <EM
+>should</EM
+>
+ require client certificates. In the web environment the client's
+ data is sensitive (credit card numbers) and the server must prove
+ to be trustworthy. In a file server environment the server's data
+ will be sensitive and the clients must prove to be trustworthy.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl require clientcert = no</B
+></P
+></DD
+><DT
+><A
+NAME="SSLREQUIRESERVERCERT"
+></A
+>ssl require servercert (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>If this variable is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>, the
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+>
+ </A
+> will request a certificate from the server. Same as
+ <A
+HREF="#SSLREQUIRECLIENTCERT"
+><TT
+CLASS="PARAMETER"
+><I
+>ssl require
+ clientcert</I
+></TT
+></A
+> for the server.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl require servercert = no</B
+>
+ </P
+></DD
+><DT
+><A
+NAME="SSLSERVERCERT"
+></A
+>ssl server cert (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This is the file containing the server's certificate.
+ The server <EM
+>must</EM
+> have a certificate. The
+ file may also contain the server's private key. See later for
+ how certificates and private keys are created.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl server cert = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLSERVERKEY"
+></A
+>ssl server key (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This file contains the private key of the server. If
+ this variable is not defined, the key is looked up in the
+ certificate file (it may be appended to the certificate).
+ The server <EM
+>must</EM
+> have a private key
+ and the certificate <EM
+>must</EM
+>
+ match this private key.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl server key = &#60;empty string&#62;
+ </B
+></P
+></DD
+><DT
+><A
+NAME="SSLVERSION"
+></A
+>ssl version (G)</DT
+><DD
+><P
+>This variable is part of SSL-enabled Samba. This
+ is only available if the SSL libraries have been compiled on your
+ system and the configure option <B
+CLASS="COMMAND"
+>--with-ssl</B
+> was
+ given at configure time.</P
+><P
+>This enumeration variable defines the versions of the
+ SSL protocol that will be used. <TT
+CLASS="CONSTANT"
+>ssl2or3</TT
+> allows
+ dynamic negotiation of SSL v2 or v3, <TT
+CLASS="CONSTANT"
+>ssl2</TT
+> results
+ in SSL v2, <TT
+CLASS="CONSTANT"
+>ssl3</TT
+> results in SSL v3 and
+ <TT
+CLASS="CONSTANT"
+>tls1</TT
+> results in TLS v1. TLS (Transport Layer
+ Security) is the new standard for SSL.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>ssl version = "ssl2or3"</B
+></P
+></DD
+><DT
+><A
+NAME="STATCACHE"
+></A
+>stat cache (G)</DT
+><DD
+><P
+>This parameter determines if <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> will use a cache in order to
+ speed up case insensitive name mappings. You should never need
+ to change this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>stat cache = yes</B
+></P
+></DD
+><DT
+><A
+NAME="STATCACHESIZE"
+></A
+>stat cache size (G)</DT
+><DD
+><P
+>This parameter determines the number of
+ entries in the <TT
+CLASS="PARAMETER"
+><I
+>stat cache</I
+></TT
+>. You should
+ never need to change this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>stat cache size = 50</B
+></P
+></DD
+><DT
+><A
+NAME="STATUS"
+></A
+>status (G)</DT
+><DD
+><P
+>This enables or disables logging of connections
+ to a status file that <A
+HREF="smbstatus.1.html"
+TARGET="_top"
+>smbstatus(1)</A
+>
+ can read.</P
+><P
+>With this disabled <B
+CLASS="COMMAND"
+>smbstatus</B
+> won't be able
+ to tell you what connections are active. You should never need to
+ change this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>status = yes</B
+></P
+></DD
+><DT
+><A
+NAME="STRICTALLOCATE"
+></A
+>strict allocate (S)</DT
+><DD
+><P
+>This is a boolean that controls the handling of
+ disk space allocation in the server. When this is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>
+ the server will change from UNIX behaviour of not committing real
+ disk storage blocks when a file is extended to the Windows behaviour
+ of actually forcing the disk system to allocate real storage blocks
+ when a file is created or extended to be a given size. In UNIX
+ terminology this means that Samba will stop creating sparse files.
+ This can be slow on some systems.</P
+><P
+>When strict allocate is <TT
+CLASS="CONSTANT"
+>no</TT
+> the server does sparse
+ disk block allocation when a file is extended.</P
+><P
+>Setting this to <TT
+CLASS="CONSTANT"
+>yes</TT
+> can help Samba return
+ out of quota messages on systems that are restricting the disk quota
+ of users.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>strict allocate = no</B
+></P
+></DD
+><DT
+><A
+NAME="STRICTLOCKING"
+></A
+>strict locking (S)</DT
+><DD
+><P
+>This is a boolean that controls the handling of
+ file locking in the server. When this is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>
+ the server will check every read and write access for file locks, and
+ deny access if locks exist. This can be slow on some systems.</P
+><P
+>When strict locking is <TT
+CLASS="CONSTANT"
+>no</TT
+> the server does file
+ lock checks only when the client explicitly asks for them.</P
+><P
+>Well-behaved clients always ask for lock checks when it
+ is important, so in the vast majority of cases <B
+CLASS="COMMAND"
+>strict
+ locking = no</B
+> is preferable.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>strict locking = no</B
+></P
+></DD
+><DT
+><A
+NAME="STRICTSYNC"
+></A
+>strict sync (S)</DT
+><DD
+><P
+>Many Windows applications (including the Windows
+ 98 explorer shell) seem to confuse flushing buffer contents to
+ disk with doing a sync to disk. Under UNIX, a sync call forces
+ the process to be suspended until the kernel has ensured that
+ all outstanding data in kernel disk buffers has been safely stored
+ onto stable storage. This is very slow and should only be done
+ rarely. Setting this parameter to <TT
+CLASS="CONSTANT"
+>no</TT
+> (the
+ default) means that <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> ignores the Windows applications requests for
+ a sync call. There is only a possibility of losing data if the
+ operating system itself that Samba is running on crashes, so there is
+ little danger in this default setting. In addition, this fixes many
+ performance problems that people have reported with the new Windows98
+ explorer shell file copies.</P
+><P
+>See also the <A
+HREF="#SYNCALWAYS"
+><TT
+CLASS="PARAMETER"
+><I
+>sync
+ always&#62;</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>strict sync = no</B
+></P
+></DD
+><DT
+><A
+NAME="STRIPDOT"
+></A
+>strip dot (G)</DT
+><DD
+><P
+>This is a boolean that controls whether to
+ strip trailing dots off UNIX filenames. This helps with some
+ CDROMs that have filenames ending in a single dot.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>strip dot = no</B
+></P
+></DD
+><DT
+><A
+NAME="SYNCALWAYS"
+></A
+>sync always (S)</DT
+><DD
+><P
+>This is a boolean parameter that controls
+ whether writes will always be written to stable storage before
+ the write call returns. If this is <TT
+CLASS="CONSTANT"
+>false</TT
+> then the server will be
+ guided by the client's request in each write call (clients can
+ set a bit indicating that a particular write should be synchronous).
+ If this is <TT
+CLASS="CONSTANT"
+>true</TT
+> then every write will be followed by a <B
+CLASS="COMMAND"
+>fsync()
+ </B
+> call to ensure the data is written to disk. Note that
+ the <TT
+CLASS="PARAMETER"
+><I
+>strict sync</I
+></TT
+> parameter must be set to
+ <TT
+CLASS="CONSTANT"
+>yes</TT
+> in order for this parameter to have
+ any affect.</P
+><P
+>See also the <A
+HREF="#STRICTSYNC"
+><TT
+CLASS="PARAMETER"
+><I
+>strict
+ sync</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>sync always = no</B
+></P
+></DD
+><DT
+><A
+NAME="SYSLOG"
+></A
+>syslog (G)</DT
+><DD
+><P
+>This parameter maps how Samba debug messages
+ are logged onto the system syslog logging levels. Samba debug
+ level zero maps onto syslog <TT
+CLASS="CONSTANT"
+>LOG_ERR</TT
+>, debug
+ level one maps onto <TT
+CLASS="CONSTANT"
+>LOG_WARNING</TT
+>, debug level
+ two maps onto <TT
+CLASS="CONSTANT"
+>LOG_NOTICE</TT
+>, debug level three
+ maps onto LOG_INFO. All higher levels are mapped to <TT
+CLASS="CONSTANT"
+> LOG_DEBUG</TT
+>.</P
+><P
+>This parameter sets the threshold for sending messages
+ to syslog. Only messages with debug level less than this value
+ will be sent to syslog.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>syslog = 1</B
+></P
+></DD
+><DT
+><A
+NAME="SYSLOGONLY"
+></A
+>syslog only (G)</DT
+><DD
+><P
+>If this parameter is set then Samba debug
+ messages are logged into the system syslog only, and not to
+ the debug log files.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>syslog only = no</B
+></P
+></DD
+><DT
+><A
+NAME="TEMPLATEHOMEDIR"
+></A
+>template homedir (G)</DT
+><DD
+><P
+>When filling out the user information for a Windows NT
+ user, the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> daemon
+ uses this parameter to fill in the home directory for that user.
+ If the string <TT
+CLASS="PARAMETER"
+><I
+>%D</I
+></TT
+> is present it is substituted
+ with the user's Windows NT domain name. If the string <TT
+CLASS="PARAMETER"
+><I
+>%U
+ </I
+></TT
+> is present it is substituted with the user's Windows
+ NT user name.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>template homedir = /home/%D/%U</B
+></P
+></DD
+><DT
+><A
+NAME="TEMPLATESHELL"
+></A
+>template shell (G)</DT
+><DD
+><P
+>When filling out the user information for a Windows NT
+ user, the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> daemon
+ uses this parameter to fill in the login shell for that user.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>template shell = /bin/false</B
+></P
+></DD
+><DT
+><A
+NAME="TIMEOFFSET"
+></A
+>time offset (G)</DT
+><DD
+><P
+>This parameter is a setting in minutes to add
+ to the normal GMT to local time conversion. This is useful if
+ you are serving a lot of PCs that have incorrect daylight
+ saving time handling.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>time offset = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>time offset = 60</B
+></P
+></DD
+><DT
+><A
+NAME="TIMESERVER"
+></A
+>time server (G)</DT
+><DD
+><P
+>This parameter determines if <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>
+ nmbd(8)</A
+> advertises itself as a time server to Windows
+ clients.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>time server = no</B
+></P
+></DD
+><DT
+><A
+NAME="TIMESTAMPLOGS"
+></A
+>timestamp logs (G)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#DEBUGTIMESTAMP"
+><TT
+CLASS="PARAMETER"
+><I
+> debug timestamp</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="TOTALPRINTJOBS"
+></A
+>total print jobs (G)</DT
+><DD
+><P
+>This parameter accepts an integer value which defines
+ a limit on the maximum number of print jobs that will be accepted
+ system wide at any given time. If a print job is submitted
+ by a client which will exceed this number, then <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd</A
+> will return an
+ error indicating that no space is available on the server. The
+ default value of 0 means that no such limit exists. This parameter
+ can be used to prevent a server from exceeding its capacity and is
+ designed as a printing throttle. See also
+ <A
+HREF="#MAXPRINTJOBS"
+><TT
+CLASS="PARAMETER"
+><I
+>max print jobs</I
+></TT
+></A
+>.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>total print jobs = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>total print jobs = 5000</B
+></P
+></DD
+><DT
+><A
+NAME="UNIXPASSWORDSYNC"
+></A
+>unix password sync (G)</DT
+><DD
+><P
+>This boolean parameter controls whether Samba
+ attempts to synchronize the UNIX password with the SMB password
+ when the encrypted SMB password in the smbpasswd file is changed.
+ If this is set to <TT
+CLASS="CONSTANT"
+>true</TT
+> the program specified in the <TT
+CLASS="PARAMETER"
+><I
+>passwd
+ program</I
+></TT
+>parameter is called <EM
+>AS ROOT</EM
+> -
+ to allow the new UNIX password to be set without access to the
+ old UNIX password (as the SMB password change code has no
+ access to the old password cleartext, only the new).</P
+><P
+>See also <A
+HREF="#PASSWDPROGRAM"
+><TT
+CLASS="PARAMETER"
+><I
+>passwd
+ program</I
+></TT
+></A
+>, <A
+HREF="#PASSWDCHAT"
+><TT
+CLASS="PARAMETER"
+><I
+> passwd chat</I
+></TT
+></A
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>unix password sync = no</B
+></P
+></DD
+><DT
+><A
+NAME="UPDATEENCRYPTED"
+></A
+>update encrypted (G)</DT
+><DD
+><P
+>This boolean parameter allows a user logging
+ on with a plaintext password to have their encrypted (hashed)
+ password in the smbpasswd file to be updated automatically as
+ they log on. This option allows a site to migrate from plaintext
+ password authentication (users authenticate with plaintext
+ password over the wire, and are checked against a UNIX account
+ database) to encrypted password authentication (the SMB
+ challenge/response authentication mechanism) without forcing
+ all users to re-enter their passwords via smbpasswd at the time the
+ change is made. This is a convenience option to allow the change over
+ to encrypted passwords to be made over a longer period. Once all users
+ have encrypted representations of their passwords in the smbpasswd
+ file this parameter should be set to <TT
+CLASS="CONSTANT"
+>no</TT
+>.</P
+><P
+>In order for this parameter to work correctly the <A
+HREF="#ENCRYPTPASSWORDS"
+><TT
+CLASS="PARAMETER"
+><I
+>encrypt passwords</I
+></TT
+>
+ </A
+> parameter must be set to <TT
+CLASS="CONSTANT"
+>no</TT
+> when
+ this parameter is set to <TT
+CLASS="CONSTANT"
+>yes</TT
+>.</P
+><P
+>Note that even when this parameter is set a user
+ authenticating to <B
+CLASS="COMMAND"
+>smbd</B
+> must still enter a valid
+ password in order to connect correctly, and to update their hashed
+ (smbpasswd) passwords.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>update encrypted = no</B
+></P
+></DD
+><DT
+><A
+NAME="USECLIENTDRIVER"
+></A
+>use client driver (S)</DT
+><DD
+><P
+>This parameter applies only to Windows NT/2000
+ clients. It has no affect on Windows 95/98/ME clients. When
+ serving a printer to Windows NT/2000 clients without first installing
+ a valid printer driver on the Samba host, the client will be required
+ to install a local printer driver. From this point on, the client
+ will treat the print as a local printer and not a network printer
+ connection. This is much the same behavior that will occur
+ when <B
+CLASS="COMMAND"
+>disable spoolss = yes</B
+>. </P
+><P
+>The differentiating
+ factor is that under normal circumstances, the NT/2000 client will
+ attempt to open the network printer using MS-RPC. The problem is that
+ because the client considers the printer to be local, it will attempt
+ to issue the OpenPrinterEx() call requesting access rights associated
+ with the logged on user. If the user possesses local administator rights
+ but not root privilegde on the Samba host (often the case), the OpenPrinterEx()
+ call will fail. The result is that the client will now display an "Access
+ Denied; Unable to connect" message in the printer queue window (even though
+ jobs may successfully be printed). </P
+><P
+>If this parameter is enabled for a printer, then any attempt
+ to open the printer with the PRINTER_ACCESS_ADMINISTER right is mapped
+ to PRINTER_ACCESS_USE instead. Thus allowing the OpenPrinterEx()
+ call to succeed. <EM
+>This parameter MUST not be able enabled
+ on a print share which has valid print driver installed on the Samba
+ server.</EM
+></P
+><P
+>See also <A
+HREF="#DISABLESPOOLSS"
+>disable spoolss</A
+>
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>use client driver = no</B
+></P
+></DD
+><DT
+><A
+NAME="USEMMAP"
+></A
+>use mmap (G)</DT
+><DD
+><P
+>This global parameter determines if the tdb internals of Samba can
+ depend on mmap working correctly on the running system. Samba requires a coherent
+ mmap/read-write system memory cache. Currently only HPUX does not have such a
+ coherent cache, and so this parameter is set to <TT
+CLASS="CONSTANT"
+>false</TT
+> by
+ default on HPUX. On all other systems this parameter should be left alone. This
+ parameter is provided to help the Samba developers track down problems with
+ the tdb internal code.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>use mmap = yes</B
+></P
+></DD
+><DT
+><A
+NAME="USERHOSTS"
+></A
+>use rhosts (G)</DT
+><DD
+><P
+>If this global parameter is <TT
+CLASS="CONSTANT"
+>true</TT
+>, it specifies
+ that the UNIX user's <TT
+CLASS="FILENAME"
+>.rhosts</TT
+> file in their home directory
+ will be read to find the names of hosts and users who will be allowed
+ access without specifying a password.</P
+><P
+><EM
+>NOTE:</EM
+> The use of <TT
+CLASS="PARAMETER"
+><I
+>use rhosts
+ </I
+></TT
+> can be a major security hole. This is because you are
+ trusting the PC to supply the correct username. It is very easy to
+ get a PC to supply a false username. I recommend that the <TT
+CLASS="PARAMETER"
+><I
+> use rhosts</I
+></TT
+> option be only used if you really know what
+ you are doing.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>use rhosts = no</B
+></P
+></DD
+><DT
+><A
+NAME="USER"
+></A
+>user (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#USERNAME"
+><TT
+CLASS="PARAMETER"
+><I
+> username</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="USERS"
+></A
+>users (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#USERNAME"
+><TT
+CLASS="PARAMETER"
+><I
+> username</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="USERNAME"
+></A
+>username (S)</DT
+><DD
+><P
+>Multiple users may be specified in a comma-delimited
+ list, in which case the supplied password will be tested against
+ each username in turn (left to right).</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>username</I
+></TT
+> line is needed only when
+ the PC is unable to supply its own username. This is the case
+ for the COREPLUS protocol or where your users have different WfWg
+ usernames to UNIX usernames. In both these cases you may also be
+ better using the \\server\share%user syntax instead.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>username</I
+></TT
+> line is not a great
+ solution in many cases as it means Samba will try to validate
+ the supplied password against each of the usernames in the
+ <TT
+CLASS="PARAMETER"
+><I
+>username</I
+></TT
+> line in turn. This is slow and
+ a bad idea for lots of users in case of duplicate passwords.
+ You may get timeouts or security breaches using this parameter
+ unwisely.</P
+><P
+>Samba relies on the underlying UNIX security. This
+ parameter does not restrict who can login, it just offers hints
+ to the Samba server as to what usernames might correspond to the
+ supplied password. Users can login as whoever they please and
+ they will be able to do no more damage than if they started a
+ telnet session. The daemon runs as the user that they log in as,
+ so they cannot do anything that user cannot do.</P
+><P
+>To restrict a service to a particular set of users you
+ can use the <A
+HREF="#VALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>valid users
+ </I
+></TT
+></A
+> parameter.</P
+><P
+>If any of the usernames begin with a '@' then the name
+ will be looked up first in the NIS netgroups list (if Samba
+ is compiled with netgroup support), followed by a lookup in
+ the UNIX groups database and will expand to a list of all users
+ in the group of that name.</P
+><P
+>If any of the usernames begin with a '+' then the name
+ will be looked up only in the UNIX groups database and will
+ expand to a list of all users in the group of that name.</P
+><P
+>If any of the usernames begin with a '&#38;'then the name
+ will be looked up only in the NIS netgroups database (if Samba
+ is compiled with netgroup support) and will expand to a list
+ of all users in the netgroup group of that name.</P
+><P
+>Note that searching though a groups database can take
+ quite some time, and some clients may time out during the
+ search.</P
+><P
+>See the section <A
+HREF="#AEN235"
+>NOTE ABOUT
+ USERNAME/PASSWORD VALIDATION</A
+> for more information on how
+ this parameter determines access to the services.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>The guest account if a guest service,
+ else &#60;empty string&#62;.</B
+></P
+><P
+>Examples:<B
+CLASS="COMMAND"
+>username = fred, mary, jack, jane,
+ @users, @pcgroup</B
+></P
+></DD
+><DT
+><A
+NAME="USERNAMELEVEL"
+></A
+>username level (G)</DT
+><DD
+><P
+>This option helps Samba to try and 'guess' at
+ the real UNIX username, as many DOS clients send an all-uppercase
+ username. By default Samba tries all lowercase, followed by the
+ username with the first letter capitalized, and fails if the
+ username is not found on the UNIX machine.</P
+><P
+>If this parameter is set to non-zero the behavior changes.
+ This parameter is a number that specifies the number of uppercase
+ combinations to try while trying to determine the UNIX user name. The
+ higher the number the more combinations will be tried, but the slower
+ the discovery of usernames will be. Use this parameter when you have
+ strange usernames on your UNIX machine, such as <TT
+CLASS="CONSTANT"
+>AstrangeUser
+ </TT
+>.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>username level = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>username level = 5</B
+></P
+></DD
+><DT
+><A
+NAME="USERNAMEMAP"
+></A
+>username map (G)</DT
+><DD
+><P
+>This option allows you to specify a file containing
+ a mapping of usernames from the clients to the server. This can be
+ used for several purposes. The most common is to map usernames
+ that users use on DOS or Windows machines to those that the UNIX
+ box uses. The other is to map multiple users to a single username
+ so that they can more easily share files.</P
+><P
+>The map file is parsed line by line. Each line should
+ contain a single UNIX username on the left then a '=' followed
+ by a list of usernames on the right. The list of usernames on the
+ right may contain names of the form @group in which case they
+ will match any UNIX username in that group. The special client
+ name '*' is a wildcard and matches any name. Each line of the
+ map file may be up to 1023 characters long.</P
+><P
+>The file is processed on each line by taking the
+ supplied username and comparing it with each username on the right
+ hand side of the '=' signs. If the supplied name matches any of
+ the names on the right hand side then it is replaced with the name
+ on the left. Processing then continues with the next line.</P
+><P
+>If any line begins with a '#' or a ';' then it is
+ ignored</P
+><P
+>If any line begins with an '!' then the processing
+ will stop after that line if a mapping was done by the line.
+ Otherwise mapping continues with every line being processed.
+ Using '!' is most useful when you have a wildcard mapping line
+ later in the file.</P
+><P
+>For example to map from the name <TT
+CLASS="CONSTANT"
+>admin</TT
+>
+ or <TT
+CLASS="CONSTANT"
+>administrator</TT
+> to the UNIX name <TT
+CLASS="CONSTANT"
+> root</TT
+> you would use:</P
+><P
+><B
+CLASS="COMMAND"
+>root = admin administrator</B
+></P
+><P
+>Or to map anyone in the UNIX group <TT
+CLASS="CONSTANT"
+>system</TT
+>
+ to the UNIX name <TT
+CLASS="CONSTANT"
+>sys</TT
+> you would use:</P
+><P
+><B
+CLASS="COMMAND"
+>sys = @system</B
+></P
+><P
+>You can have as many mappings as you like in a username
+ map file.</P
+><P
+>If your system supports the NIS NETGROUP option then
+ the netgroup database is checked before the <TT
+CLASS="FILENAME"
+>/etc/group
+ </TT
+> database for matching groups.</P
+><P
+>You can map Windows usernames that have spaces in them
+ by using double quotes around the name. For example:</P
+><P
+><B
+CLASS="COMMAND"
+>tridge = "Andrew Tridgell"</B
+></P
+><P
+>would map the windows username "Andrew Tridgell" to the
+ unix username "tridge".</P
+><P
+>The following example would map mary and fred to the
+ unix user sys, and map the rest to guest. Note the use of the
+ '!' to tell Samba to stop processing if it gets a match on
+ that line.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> !sys = mary fred
+ guest = *
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Note that the remapping is applied to all occurrences
+ of usernames. Thus if you connect to \\server\fred and <TT
+CLASS="CONSTANT"
+> fred</TT
+> is remapped to <TT
+CLASS="CONSTANT"
+>mary</TT
+> then you
+ will actually be connecting to \\server\mary and will need to
+ supply a password suitable for <TT
+CLASS="CONSTANT"
+>mary</TT
+> not
+ <TT
+CLASS="CONSTANT"
+>fred</TT
+>. The only exception to this is the
+ username passed to the <A
+HREF="#PASSWORDSERVER"
+><TT
+CLASS="PARAMETER"
+><I
+> password server</I
+></TT
+></A
+> (if you have one). The password
+ server will receive whatever username the client supplies without
+ modification.</P
+><P
+>Also note that no reverse mapping is done. The main effect
+ this has is with printing. Users who have been mapped may have
+ trouble deleting print jobs as PrintManager under WfWg will think
+ they don't own the print job.</P
+><P
+>Default: <EM
+>no username map</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>username map = /usr/local/samba/lib/users.map
+ </B
+></P
+></DD
+><DT
+><A
+NAME="UTMP"
+></A
+>utmp (G)</DT
+><DD
+><P
+>This boolean parameter is only available if
+ Samba has been configured and compiled with the option <B
+CLASS="COMMAND"
+> --with-utmp</B
+>. If set to <TT
+CLASS="CONSTANT"
+>true</TT
+> then Samba will attempt
+ to add utmp or utmpx records (depending on the UNIX system) whenever a
+ connection is made to a Samba server. Sites may use this to record the
+ user connecting to a Samba share.</P
+><P
+>See also the <A
+HREF="#UTMPDIRECTORY"
+><TT
+CLASS="PARAMETER"
+><I
+> utmp directory</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>utmp = no</B
+></P
+></DD
+><DT
+><A
+NAME="UTMPDIRECTORY"
+></A
+>utmp directory(G)</DT
+><DD
+><P
+>This parameter is only available if Samba has
+ been configured and compiled with the option <B
+CLASS="COMMAND"
+> --with-utmp</B
+>. It specifies a directory pathname that is
+ used to store the utmp or utmpx files (depending on the UNIX system) that
+ record user connections to a Samba server. See also the <A
+HREF="#UTMP"
+> <TT
+CLASS="PARAMETER"
+><I
+>utmp</I
+></TT
+></A
+> parameter. By default this is
+ not set, meaning the system will use whatever utmp file the
+ native system is set to use (usually
+ <TT
+CLASS="FILENAME"
+>/var/run/utmp</TT
+> on Linux).</P
+><P
+>Default: <EM
+>no utmp directory</EM
+></P
+></DD
+><DT
+><A
+NAME="VALIDCHARS"
+></A
+>valid chars (G)</DT
+><DD
+><P
+>The option allows you to specify additional
+ characters that should be considered valid by the server in
+ filenames. This is particularly useful for national character
+ sets, such as adding u-umlaut or a-ring.</P
+><P
+>The option takes a list of characters in either integer
+ or character form with spaces between them. If you give two
+ characters with a colon between them then it will be taken as
+ an lowercase:uppercase pair.</P
+><P
+>If you have an editor capable of entering the characters
+ into the config file then it is probably easiest to use this
+ method. Otherwise you can specify the characters in octal,
+ decimal or hexadecimal form using the usual C notation.</P
+><P
+>For example to add the single character 'Z' to the charset
+ (which is a pointless thing to do as it's already there) you could
+ do one of the following</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> valid chars = Z
+ valid chars = z:Z
+ valid chars = 0132:0172
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The last two examples above actually add two characters,
+ and alter the uppercase and lowercase mappings appropriately.</P
+><P
+>Note that you <EM
+>MUST</EM
+> specify this parameter
+ after the <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> parameter if you
+ have both set. If <TT
+CLASS="PARAMETER"
+><I
+>client code page</I
+></TT
+> is set after
+ the <TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+> parameter the <TT
+CLASS="PARAMETER"
+><I
+>valid
+ chars</I
+></TT
+> settings will be overwritten.</P
+><P
+>See also the <A
+HREF="#CLIENTCODEPAGE"
+><TT
+CLASS="PARAMETER"
+><I
+>client
+ code page</I
+></TT
+></A
+> parameter.</P
+><P
+>Default: <EM
+>Samba defaults to using a reasonable set
+ of valid characters for English systems</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>valid chars = 0345:0305 0366:0326 0344:0304
+ </B
+></P
+><P
+>The above example allows filenames to have the Swedish
+ characters in them.</P
+><P
+><EM
+>NOTE:</EM
+> It is actually quite difficult to
+ correctly produce a <TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+> line for
+ a particular system. To automate the process <A
+HREF="mailto:tino@augsburg.net"
+TARGET="_top"
+>tino@augsburg.net</A
+> has written
+ a package called <B
+CLASS="COMMAND"
+>validchars</B
+> which will automatically
+ produce a complete <TT
+CLASS="PARAMETER"
+><I
+>valid chars</I
+></TT
+> line for
+ a given client system. Look in the <TT
+CLASS="FILENAME"
+>examples/validchars/
+ </TT
+> subdirectory of your Samba source code distribution
+ for this package.</P
+></DD
+><DT
+><A
+NAME="VALIDUSERS"
+></A
+>valid users (S)</DT
+><DD
+><P
+>This is a list of users that should be allowed
+ to login to this service. Names starting with '@', '+' and '&#38;'
+ are interpreted using the same rules as described in the
+ <TT
+CLASS="PARAMETER"
+><I
+>invalid users</I
+></TT
+> parameter.</P
+><P
+>If this is empty (the default) then any user can login.
+ If a username is in both this list and the <TT
+CLASS="PARAMETER"
+><I
+>invalid
+ users</I
+></TT
+> list then access is denied for that user.</P
+><P
+>The current servicename is substituted for <TT
+CLASS="PARAMETER"
+><I
+>%S
+ </I
+></TT
+>. This is useful in the [homes] section.</P
+><P
+>See also <A
+HREF="#INVALIDUSERS"
+><TT
+CLASS="PARAMETER"
+><I
+>invalid users
+ </I
+></TT
+></A
+></P
+><P
+>Default: <EM
+>No valid users list (anyone can login)
+ </EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>valid users = greg, @pcusers</B
+></P
+></DD
+><DT
+><A
+NAME="VETOFILES"
+></A
+>veto files(S)</DT
+><DD
+><P
+>This is a list of files and directories that
+ are neither visible nor accessible. Each entry in the list must
+ be separated by a '/', which allows spaces to be included
+ in the entry. '*' and '?' can be used to specify multiple files
+ or directories as in DOS wildcards.</P
+><P
+>Each entry must be a unix path, not a DOS path and
+ must <EM
+>not</EM
+> include the unix directory
+ separator '/'.</P
+><P
+>Note that the <TT
+CLASS="PARAMETER"
+><I
+>case sensitive</I
+></TT
+> option
+ is applicable in vetoing files.</P
+><P
+>One feature of the veto files parameter that it
+ is important to be aware of is Samba's behaviour when
+ trying to delete a directory. If a directory that is
+ to be deleted contains nothing but veto files this
+ deletion will <EM
+>fail</EM
+> unless you also set
+ the <TT
+CLASS="PARAMETER"
+><I
+>delete veto files</I
+></TT
+> parameter to
+ <TT
+CLASS="PARAMETER"
+><I
+>yes</I
+></TT
+>.</P
+><P
+>Setting this parameter will affect the performance
+ of Samba, as it will be forced to check all files and directories
+ for a match as they are scanned.</P
+><P
+>See also <A
+HREF="#HIDEFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>hide files
+ </I
+></TT
+></A
+> and <A
+HREF="#CASESENSITIVE"
+><TT
+CLASS="PARAMETER"
+><I
+> case sensitive</I
+></TT
+></A
+>.</P
+><P
+>Default: <EM
+>No files or directories are vetoed.
+ </EM
+></P
+><P
+>Examples:<TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>; Veto any files containing the word Security,
+; any ending in .tmp, and any directory containing the
+; word root.
+veto files = /*Security*/*.tmp/*root*/
+
+; Veto the Apple specific files that a NetAtalk server
+; creates.
+veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/</PRE
+></TD
+></TR
+></TABLE
+></P
+></DD
+><DT
+><A
+NAME="VETOOPLOCKFILES"
+></A
+>veto oplock files (S)</DT
+><DD
+><P
+>This parameter is only valid when the <A
+HREF="#OPLOCKS"
+><TT
+CLASS="PARAMETER"
+><I
+>oplocks</I
+></TT
+></A
+>
+ parameter is turned on for a share. It allows the Samba administrator
+ to selectively turn off the granting of oplocks on selected files that
+ match a wildcarded list, similar to the wildcarded list used in the
+ <A
+HREF="#VETOFILES"
+><TT
+CLASS="PARAMETER"
+><I
+>veto files</I
+></TT
+></A
+>
+ parameter.</P
+><P
+>Default: <EM
+>No files are vetoed for oplock
+ grants</EM
+></P
+><P
+>You might want to do this on files that you know will
+ be heavily contended for by clients. A good example of this
+ is in the NetBench SMB benchmark program, which causes heavy
+ client contention for files ending in <TT
+CLASS="FILENAME"
+>.SEM</TT
+>.
+ To cause Samba not to grant oplocks on these files you would use
+ the line (either in the [global] section or in the section for
+ the particular NetBench share :</P
+><P
+>Example: <B
+CLASS="COMMAND"
+>veto oplock files = /*.SEM/
+ </B
+></P
+></DD
+><DT
+><A
+NAME="VFSOBJECT"
+></A
+>vfs object (S)</DT
+><DD
+><P
+>This parameter specifies a shared object file that
+ is used for Samba VFS I/O operations. By default, normal
+ disk I/O operations are used but these can be overloaded
+ with a VFS object. The Samba VFS layer is new to Samba 2.2 and
+ must be enabled at compile time with --with-vfs.</P
+><P
+>Default : <EM
+>no value</EM
+></P
+></DD
+><DT
+><A
+NAME="VFSOPTIONS"
+></A
+>vfs options (S)</DT
+><DD
+><P
+>This parameter allows parameters to be passed
+ to the vfs layer at initialization time. The Samba VFS layer
+ is new to Samba 2.2 and must be enabled at compile time
+ with --with-vfs. See also <A
+HREF="#VFSOBJECT"
+><TT
+CLASS="PARAMETER"
+><I
+> vfs object</I
+></TT
+></A
+>.</P
+><P
+>Default : <EM
+>no value</EM
+></P
+></DD
+><DT
+><A
+NAME="VOLUME"
+></A
+>volume (S)</DT
+><DD
+><P
+> This allows you to override the volume label
+ returned for a share. Useful for CDROMs with installation programs
+ that insist on a particular volume label.</P
+><P
+>Default: <EM
+>the name of the share</EM
+></P
+></DD
+><DT
+><A
+NAME="WIDELINKS"
+></A
+>wide links (S)</DT
+><DD
+><P
+>This parameter controls whether or not links
+ in the UNIX file system may be followed by the server. Links
+ that point to areas within the directory tree exported by the
+ server are always allowed; this parameter controls access only
+ to areas that are outside the directory tree being exported.</P
+><P
+>Note that setting this parameter can have a negative
+ effect on your server performance due to the extra system calls
+ that Samba has to do in order to perform the link checks.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>wide links = yes</B
+></P
+></DD
+><DT
+><A
+NAME="WINBINDCACHETIME"
+></A
+>winbind cache time</DT
+><DD
+><P
+>This parameter specifies the number of seconds the
+ <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> daemon will cache
+ user and group information before querying a Windows NT server
+ again.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind cache type = 15</B
+></P
+></DD
+><DT
+><A
+NAME="WINBINDENUMUSERS"
+></A
+>winbind enum
+ users</DT
+><DD
+><P
+>On large installations using
+ <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> it may be
+ necessary to suppress the enumeration of users through the
+ <B
+CLASS="COMMAND"
+> setpwent()</B
+>,
+ <B
+CLASS="COMMAND"
+>getpwent()</B
+> and
+ <B
+CLASS="COMMAND"
+>endpwent()</B
+> group of system calls. If
+ the <TT
+CLASS="PARAMETER"
+><I
+>winbind enum users</I
+></TT
+> parameter is
+ false, calls to the <B
+CLASS="COMMAND"
+>getpwent</B
+> system call
+ will not return any data. </P
+><P
+><EM
+>Warning:</EM
+> Turning off user
+ enumeration may cause some programs to behave oddly. For
+ example, the finger program relies on having access to the
+ full user list when searching for matching
+ usernames. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind enum users = yes </B
+></P
+></DD
+><DT
+><A
+NAME="WINBINDENUMGROUPS"
+></A
+>winbind enum
+ groups</DT
+><DD
+><P
+>On large installations using
+ <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> it may be
+ necessary to suppress the enumeration of groups through the
+ <B
+CLASS="COMMAND"
+> setgrent()</B
+>,
+ <B
+CLASS="COMMAND"
+>getgrent()</B
+> and
+ <B
+CLASS="COMMAND"
+>endgrent()</B
+> group of system calls. If
+ the <TT
+CLASS="PARAMETER"
+><I
+>winbind enum groups</I
+></TT
+> parameter is
+ false, calls to the <B
+CLASS="COMMAND"
+>getgrent()</B
+> system
+ call will not return any data. </P
+><P
+><EM
+>Warning:</EM
+> Turning off group
+ enumeration may cause some programs to behave oddly.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind enum groups = yes </B
+>
+ </P
+></DD
+><DT
+><A
+NAME="WINBINDGID"
+></A
+>winbind gid</DT
+><DD
+><P
+>The winbind gid parameter specifies the range of group
+ ids that are allocated by the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+> winbindd(8)</A
+> daemon. This range of group ids should have no
+ existing local or NIS groups within it as strange conflicts can
+ occur otherwise.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind gid = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind gid = 10000-20000</B
+></P
+></DD
+><DT
+><A
+NAME="WINBINDSEPARATOR"
+></A
+>winbind separator</DT
+><DD
+><P
+>This parameter allows an admin to define the character
+ used when listing a username of the form of <TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN
+ </I
+></TT
+>\<TT
+CLASS="REPLACEABLE"
+><I
+>user</I
+></TT
+>. This parameter
+ is only applicable when using the <TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+>
+ and <TT
+CLASS="FILENAME"
+>nss_winbind.so</TT
+> modules for UNIX services.
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind separator = \</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind separator = +</B
+></P
+></DD
+><DT
+><A
+NAME="WINBINDUID"
+></A
+>winbind uid</DT
+><DD
+><P
+>The winbind gid parameter specifies the range of group
+ ids that are allocated by the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+> winbindd(8)</A
+> daemon. This range of ids should have no
+ existing local or NIS users within it as strange conflicts can
+ occur otherwise.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind uid = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind uid = 10000-20000</B
+></P
+></DD
+><DT
+><A
+NAME="WINSHOOK"
+></A
+>wins hook (G)</DT
+><DD
+><P
+>When Samba is running as a WINS server this
+ allows you to call an external program for all changes to the
+ WINS database. The primary use for this option is to allow the
+ dynamic update of external name resolution databases such as
+ dynamic DNS.</P
+><P
+>The wins hook parameter specifies the name of a script
+ or executable that will be called as follows:</P
+><P
+><B
+CLASS="COMMAND"
+>wins_hook operation name nametype ttl IP_list
+ </B
+></P
+><P
+></P
+><UL
+><LI
+><P
+>The first argument is the operation and is one
+ of "add", "delete", or "refresh". In most cases the operation can
+ be ignored as the rest of the parameters provide sufficient
+ information. Note that "refresh" may sometimes be called when the
+ name has not previously been added, in that case it should be treated
+ as an add.</P
+></LI
+><LI
+><P
+>The second argument is the NetBIOS name. If the
+ name is not a legal name then the wins hook is not called.
+ Legal names contain only letters, digits, hyphens, underscores
+ and periods.</P
+></LI
+><LI
+><P
+>The third argument is the NetBIOS name
+ type as a 2 digit hexadecimal number. </P
+></LI
+><LI
+><P
+>The fourth argument is the TTL (time to live)
+ for the name in seconds.</P
+></LI
+><LI
+><P
+>The fifth and subsequent arguments are the IP
+ addresses currently registered for that name. If this list is
+ empty then the name should be deleted.</P
+></LI
+></UL
+><P
+>An example script that calls the BIND dynamic DNS update
+ program <B
+CLASS="COMMAND"
+>nsupdate</B
+> is provided in the examples
+ directory of the Samba source code. </P
+></DD
+><DT
+><A
+NAME="WINSPROXY"
+></A
+>wins proxy (G)</DT
+><DD
+><P
+>This is a boolean that controls if <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> will respond to broadcast name
+ queries on behalf of other hosts. You may need to set this
+ to <TT
+CLASS="CONSTANT"
+>yes</TT
+> for some older clients.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>wins proxy = no</B
+></P
+></DD
+><DT
+><A
+NAME="WINSSERVER"
+></A
+>wins server (G)</DT
+><DD
+><P
+>This specifies the IP address (or DNS name: IP
+ address for preference) of the WINS server that <A
+HREF="nmbd.8.html"
+TARGET="_top"
+> nmbd(8)</A
+> should register with. If you have a WINS server on
+ your network then you should set this to the WINS server's IP.</P
+><P
+>You should point this at your WINS server if you have a
+ multi-subnetted network.</P
+><P
+><EM
+>NOTE</EM
+>. You need to set up Samba to point
+ to a WINS server if you have multiple subnets and wish cross-subnet
+ browsing to work correctly.</P
+><P
+>See the documentation file <TT
+CLASS="FILENAME"
+>BROWSING.txt</TT
+>
+ in the docs/ directory of your Samba source distribution.</P
+><P
+>Default: <EM
+>not enabled</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>wins server = 192.9.200.1</B
+></P
+></DD
+><DT
+><A
+NAME="WINSSUPPORT"
+></A
+>wins support (G)</DT
+><DD
+><P
+>This boolean controls if the <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>
+ nmbd(8)</A
+> process in Samba will act as a WINS server. You should
+ not set this to <TT
+CLASS="CONSTANT"
+>true</TT
+> unless you have a multi-subnetted network and
+ you wish a particular <B
+CLASS="COMMAND"
+>nmbd</B
+> to be your WINS server.
+ Note that you should <EM
+>NEVER</EM
+> set this to <TT
+CLASS="CONSTANT"
+>true</TT
+>
+ on more than one machine in your network.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>wins support = no</B
+></P
+></DD
+><DT
+><A
+NAME="WORKGROUP"
+></A
+>workgroup (G)</DT
+><DD
+><P
+>This controls what workgroup your server will
+ appear to be in when queried by clients. Note that this parameter
+ also controls the Domain name used with the <A
+HREF="#SECURITYEQUALSDOMAIN"
+><B
+CLASS="COMMAND"
+>security = domain</B
+></A
+>
+ setting.</P
+><P
+>Default: <EM
+>set at compile time to WORKGROUP</EM
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>workgroup = MYGROUP</B
+></P
+></DD
+><DT
+><A
+NAME="WRITABLE"
+></A
+>writable (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+> writeable</I
+></TT
+></A
+> for people who can't spell :-).</P
+></DD
+><DT
+><A
+NAME="WRITECACHESIZE"
+></A
+>write cache size (S)</DT
+><DD
+><P
+>If this integer parameter is set to non-zero value,
+ Samba will create an in-memory cache for each oplocked file
+ (it does <EM
+>not</EM
+> do this for
+ non-oplocked files). All writes that the client does not request
+ to be flushed directly to disk will be stored in this cache if possible.
+ The cache is flushed onto disk when a write comes in whose offset
+ would not fit into the cache or when the file is closed by the client.
+ Reads for the file are also served from this cache if the data is stored
+ within it.</P
+><P
+>This cache allows Samba to batch client writes into a more
+ efficient write size for RAID disks (i.e. writes may be tuned to
+ be the RAID stripe size) and can improve performance on systems
+ where the disk subsystem is a bottleneck but there is free
+ memory for userspace programs.</P
+><P
+>The integer parameter specifies the size of this cache
+ (per oplocked file) in bytes.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>write cache size = 0</B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>write cache size = 262144</B
+></P
+><P
+>for a 256k cache size per file.</P
+></DD
+><DT
+><A
+NAME="WRITELIST"
+></A
+>write list (S)</DT
+><DD
+><P
+>This is a list of users that are given read-write
+ access to a service. If the connecting user is in this list then
+ they will be given write access, no matter what the <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+>writeable</I
+></TT
+></A
+>
+ option is set to. The list can include group names using the
+ @group syntax.</P
+><P
+>Note that if a user is in both the read list and the
+ write list then they will be given write access.</P
+><P
+>See also the <A
+HREF="#READLIST"
+><TT
+CLASS="PARAMETER"
+><I
+>read list
+ </I
+></TT
+></A
+> option.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>write list = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>write list = admin, root, @staff
+ </B
+></P
+></DD
+><DT
+><A
+NAME="WRITEOK"
+></A
+>write ok (S)</DT
+><DD
+><P
+>Synonym for <A
+HREF="#WRITEABLE"
+><TT
+CLASS="PARAMETER"
+><I
+> writeable</I
+></TT
+></A
+>.</P
+></DD
+><DT
+><A
+NAME="WRITERAW"
+></A
+>write raw (G)</DT
+><DD
+><P
+>This parameter controls whether or not the server
+ will support raw write SMB's when transferring data from clients.
+ You should never need to change this parameter.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>write raw = yes</B
+></P
+></DD
+><DT
+><A
+NAME="WRITEABLE"
+></A
+>writeable (S)</DT
+><DD
+><P
+>An inverted synonym is <A
+HREF="#READONLY"
+> <TT
+CLASS="PARAMETER"
+><I
+>read only</I
+></TT
+></A
+>.</P
+><P
+>If this parameter is <TT
+CLASS="CONSTANT"
+>no</TT
+>, then users
+ of a service may not create or modify files in the service's
+ directory.</P
+><P
+>Note that a printable service (<B
+CLASS="COMMAND"
+>printable = yes</B
+>)
+ will <EM
+>ALWAYS</EM
+> allow writing to the directory
+ (user privileges permitting), but only via spooling operations.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>writeable = no</B
+></P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN6052"
+></A
+><H2
+>WARNINGS</H2
+><P
+>Although the configuration file permits service names
+ to contain spaces, your client software may not. Spaces will
+ be ignored in comparisons anyway, so it shouldn't be a
+ problem - but be aware of the possibility.</P
+><P
+>On a similar note, many clients - especially DOS clients -
+ limit service names to eight characters. <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)
+ </A
+> has no such limitation, but attempts to connect from such
+ clients will fail if they truncate the service names. For this reason
+ you should probably keep your service names down to eight characters
+ in length.</P
+><P
+>Use of the [homes] and [printers] special sections make life
+ for an administrator easy, but the various combinations of default
+ attributes can be tricky. Take extreme care when designing these
+ sections. In particular, ensure that the permissions on spool
+ directories are correct.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN6058"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN6061"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>,
+ <A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+>,
+ <A
+HREF="swat.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>swat(8)</B
+></A
+>,
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+>,
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>,
+ <A
+HREF="nmblookup.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmblookup(1)</B
+></A
+>,
+ <A
+HREF="testparm.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>testparm(1)</B
+></A
+>,
+ <A
+HREF="testprns.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>testprns(1)</B
+></A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN6081"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbcacls.1.html b/docs/htmldocs/smbcacls.1.html
new file mode 100644
index 00000000000..637720fa6ba
--- /dev/null
+++ b/docs/htmldocs/smbcacls.1.html
@@ -0,0 +1,387 @@
+<HTML
+><HEAD
+><TITLE
+>smbcacls</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBCACLS"
+>smbcacls</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbcacls&nbsp;--&nbsp;Set or get ACLs on an NT file or directory names</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbcacls</B
+> {//server/share} {filename} [-U username] [-A acls] [-M acls] [-D acls] [-S acls] [-C name] [-G name] [-n] [-h]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN22"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+>The <B
+CLASS="COMMAND"
+>smbcacls</B
+> program manipulates NT Access Control Lists
+ (ACLs) on SMB file shares. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN28"
+></A
+><H2
+>OPTIONS</H2
+><P
+>The following options are available to the <B
+CLASS="COMMAND"
+>smbcacls</B
+> program.
+ The format of ACLs is described in the section ACL FORMAT </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-A acls</DT
+><DD
+><P
+>Add the ACLs specified to the ACL list. Existing
+ access control entries are unchanged. </P
+></DD
+><DT
+>-M acls</DT
+><DD
+><P
+>Modify the mask value (permissions) for the ACLs
+ specified on the command line. An error will be printed for each
+ ACL specified that was not already present in the ACL list
+ </P
+></DD
+><DT
+>-D acls</DT
+><DD
+><P
+>Delete any ACLs specified on the command line.
+ An error will be printed for each ACL specified that was not
+ already present in the ACL list. </P
+></DD
+><DT
+>-S acls</DT
+><DD
+><P
+>This command sets the ACLs on the file with
+ only the ones specified on the command line. All other ACLs are
+ erased. Note that the ACL specified must contain at least a revision,
+ type, owner and group for the call to succeed. </P
+></DD
+><DT
+>-U username</DT
+><DD
+><P
+>Specifies a username used to connect to the
+ specified service. The username may be of the form "username" in
+ which case the user is prompted to enter in a password and the
+ workgroup specified in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file is
+ used, or "username%password" or "DOMAIN\username%password" and the
+ password and workgroup names are used as provided. </P
+></DD
+><DT
+>-C name</DT
+><DD
+><P
+>The owner of a file or directory can be changed
+ to the name given using the <TT
+CLASS="PARAMETER"
+><I
+>-C</I
+></TT
+> option.
+ The name can be a sid in the form S-1-x-y-z or a name resolved
+ against the server specified in the first argument. </P
+><P
+>This command is a shortcut for -M OWNER:name.
+ </P
+></DD
+><DT
+>-G name</DT
+><DD
+><P
+>The group owner of a file or directory can
+ be changed to the name given using the <TT
+CLASS="PARAMETER"
+><I
+>-G</I
+></TT
+>
+ option. The name can be a sid in the form S-1-x-y-z or a name
+ resolved against the server specified n the first argument.
+ </P
+><P
+>This command is a shortcut for -M GROUP:name.</P
+></DD
+><DT
+>-n</DT
+><DD
+><P
+>This option displays all ACL information in numeric
+ format. The default is to convert SIDs to names and ACE types
+ and masks to a readable string format. </P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Print usage information on the <B
+CLASS="COMMAND"
+>smbcacls
+ </B
+> program.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN75"
+></A
+><H2
+>ACL FORMAT</H2
+><P
+>The format of an ACL is one or more ACL entries separated by
+ either commas or newlines. An ACL entry is one of the following: </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>
+REVISION:&#60;revision number&#62;
+OWNER:&#60;sid or name&#62;
+GROUP:&#60;sid or name&#62;
+ACL:&#60;sid or name&#62;:&#60;type&#62;/&#60;flags&#62;/&#60;mask&#62;
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>The revision of the ACL specifies the internal Windows
+ NT ACL revision for the security descriptor.
+ If not specified it defaults to 1. Using values other than 1 may
+ cause strange behaviour. </P
+><P
+>The owner and group specify the owner and group sids for the
+ object. If a SID in the format CWS-1-x-y-z is specified this is used,
+ otherwise the name specified is resolved using the server on which
+ the file or directory resides. </P
+><P
+>ACLs specify permissions granted to the SID. This SID again
+ can be specified in CWS-1-x-y-z format or as a name in which case
+ it is resolved against the server on which the file or directory
+ resides. The type, flags and mask values determine the type of
+ access granted to the SID. </P
+><P
+>The type can be either 0 or 1 corresponding to ALLOWED or
+ DENIED access to the SID. The flags values are generally
+ zero for file ACLs and either 9 or 2 for directory ACLs. Some
+ common flags are: </P
+><P
+></P
+><UL
+><LI
+><P
+>#define SEC_ACE_FLAG_OBJECT_INHERIT 0x1</P
+></LI
+><LI
+><P
+>#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x2</P
+></LI
+><LI
+><P
+>#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x4
+ </P
+></LI
+><LI
+><P
+>#define SEC_ACE_FLAG_INHERIT_ONLY 0x8</P
+></LI
+></UL
+><P
+>At present flags can only be specified as decimal or
+ hexadecimal values.</P
+><P
+>The mask is a value which expresses the access right
+ granted to the SID. It can be given as a decimal or hexadecimal value,
+ or by using one of the following text strings which map to the NT
+ file permissions of the same name. </P
+><P
+></P
+><UL
+><LI
+><P
+><EM
+>R</EM
+> - Allow read access </P
+></LI
+><LI
+><P
+><EM
+>W</EM
+> - Allow write access</P
+></LI
+><LI
+><P
+><EM
+>X</EM
+> - Execute permission on the object</P
+></LI
+><LI
+><P
+><EM
+>D</EM
+> - Delete the object</P
+></LI
+><LI
+><P
+><EM
+>P</EM
+> - Change permissions</P
+></LI
+><LI
+><P
+><EM
+>O</EM
+> - Take ownership</P
+></LI
+></UL
+><P
+>The following combined permissions can be specified:</P
+><P
+></P
+><UL
+><LI
+><P
+><EM
+>READ</EM
+> - Equivalent to 'RX'
+ permissions</P
+></LI
+><LI
+><P
+><EM
+>CHANGE</EM
+> - Equivalent to 'RXWD' permissions
+ </P
+></LI
+><LI
+><P
+><EM
+>FULL</EM
+> - Equivalent to 'RWXDPO'
+ permissions</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN125"
+></A
+><H2
+>EXIT STATUS</H2
+><P
+>The <B
+CLASS="COMMAND"
+>smbcacls</B
+> program sets the exit status
+ depending on the success or otherwise of the operations performed.
+ The exit status may be one of the following values. </P
+><P
+>If the operation succeeded, smbcacls returns and exit
+ status of 0. If <B
+CLASS="COMMAND"
+>smbcacls</B
+> couldn't connect to the specified server,
+ or there was an error getting or setting the ACLs, an exit status
+ of 1 is returned. If there was an error parsing any command line
+ arguments, an exit status of 2 is returned. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN131"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN134"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+><B
+CLASS="COMMAND"
+>smbcacls</B
+> was written by Andrew Tridgell
+ and Tim Potter.</P
+><P
+>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbclient.1.html b/docs/htmldocs/smbclient.1.html
new file mode 100644
index 00000000000..16fc134405a
--- /dev/null
+++ b/docs/htmldocs/smbclient.1.html
@@ -0,0 +1,1554 @@
+<HTML
+><HEAD
+><TITLE
+>smbclient</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBCLIENT"
+>smbclient</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbclient&nbsp;--&nbsp;ftp-like client to access SMB/CIFS resources
+ on servers</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbclient</B
+> {servicename} [password] [-b &#60;buffer size&#62;] [-d debuglevel] [-D Directory] [-U username] [-W workgroup] [-M &#60;netbios name&#62;] [-m maxprotocol] [-A authfile] [-N] [-l logfile] [-L &#60;netbios name&#62;] [-I destinationIP] [-E &#60;terminal code&#62;] [-c &#60;command string&#62;] [-i scope] [-O &#60;socket options&#62;] [-p port] [-R &#60;name resolve order&#62;] [-s &#60;smb config file&#62;] [-T&#60;c|x&#62;IXFqgbNan]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN33"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbclient</B
+> is a client that can
+ 'talk' to an SMB/CIFS server. It offers an interface
+ similar to that of the ftp program (see <B
+CLASS="COMMAND"
+>ftp(1)</B
+>).
+ Operations include things like getting files from the server
+ to the local machine, putting files from the local machine to
+ the server, retrieving directory information from the server
+ and so on. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>servicename</DT
+><DD
+><P
+>servicename is the name of the service
+ you want to use on the server. A service name takes the form
+ <TT
+CLASS="FILENAME"
+>//server/service</TT
+> where <TT
+CLASS="PARAMETER"
+><I
+>server
+ </I
+></TT
+> is the NetBIOS name of the SMB/CIFS server
+ offering the desired service and <TT
+CLASS="PARAMETER"
+><I
+>service</I
+></TT
+>
+ is the name of the service offered. Thus to connect to
+ the service "printer" on the SMB/CIFS server "smbserver",
+ you would use the servicename <TT
+CLASS="FILENAME"
+>//smbserver/printer
+ </TT
+></P
+><P
+>Note that the server name required is NOT necessarily
+ the IP (DNS) host name of the server ! The name required is
+ a NetBIOS server name, which may or may not be the
+ same as the IP hostname of the machine running the server.
+ </P
+><P
+>The server name is looked up according to either
+ the <TT
+CLASS="PARAMETER"
+><I
+>-R</I
+></TT
+> parameter to <B
+CLASS="COMMAND"
+>smbclient</B
+> or
+ using the name resolve order parameter in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file,
+ allowing an administrator to change the order and methods
+ by which server names are looked up. </P
+></DD
+><DT
+>password</DT
+><DD
+><P
+>The password required to access the specified
+ service on the specified server. If this parameter is
+ supplied, the <TT
+CLASS="PARAMETER"
+><I
+>-N</I
+></TT
+> option (suppress
+ password prompt) is assumed. </P
+><P
+>There is no default password. If no password is supplied
+ on the command line (either by using this parameter or adding
+ a password to the <TT
+CLASS="PARAMETER"
+><I
+>-U</I
+></TT
+> option (see
+ below)) and the <TT
+CLASS="PARAMETER"
+><I
+>-N</I
+></TT
+> option is not
+ specified, the client will prompt for a password, even if
+ the desired service does not require one. (If no password is
+ required, simply press ENTER to provide a null password.)
+ </P
+><P
+>Note: Some servers (including OS/2 and Windows for
+ Workgroups) insist on an uppercase password. Lowercase
+ or mixed case passwords may be rejected by these servers.
+ </P
+><P
+>Be cautious about including passwords in scripts.
+ </P
+></DD
+><DT
+>-s smb.conf</DT
+><DD
+><P
+>Specifies the location of the all important
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. </P
+></DD
+><DT
+>-O socket options</DT
+><DD
+><P
+>TCP socket options to set on the client
+ socket. See the socket options parameter in the <TT
+CLASS="FILENAME"
+> smb.conf (5)</TT
+> manpage for the list of valid
+ options. </P
+></DD
+><DT
+>-R &#60;name resolve order&#62;</DT
+><DD
+><P
+>This option is used by the programs in the Samba
+ suite to determine what naming services and in what order to resolve
+ host names to IP addresses. The option takes a space-separated
+ string of different name resolution options.</P
+><P
+>The options are :"lmhosts", "host", "wins" and "bcast". They
+ cause names to be resolved as follows :</P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>lmhosts</TT
+> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <A
+HREF="lmhosts.5.html"
+TARGET="_top"
+>lmhosts(5)</A
+> for details) then
+ any name type matches for lookup.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>host</TT
+> : Do a standard host
+ name to IP address resolution, using the system <TT
+CLASS="FILENAME"
+>/etc/hosts
+ </TT
+>, NIS, or DNS lookups. This method of name resolution
+ is operating system dependent, for instance on IRIX or Solaris this
+ may be controlled by the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>
+ file). Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>wins</TT
+> : Query a name with
+ the IP address listed in the <TT
+CLASS="PARAMETER"
+><I
+>wins server</I
+></TT
+>
+ parameter. If no WINS server has
+ been specified this method will be ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>bcast</TT
+> : Do a broadcast on
+ each of the known local interfaces listed in the
+ <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+>
+ parameter. This is the least reliable of the name resolution
+ methods as it depends on the target host being on a locally
+ connected subnet.</P
+></LI
+></UL
+><P
+>If this parameter is not set then the name resolve order
+ defined in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file parameter
+ (name resolve order) will be used. </P
+><P
+>The default order is lmhosts, host, wins, bcast and without
+ this parameter or any entry in the <TT
+CLASS="PARAMETER"
+><I
+>name resolve order
+ </I
+></TT
+> parameter of the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file the name resolution
+ methods will be attempted in this order. </P
+></DD
+><DT
+>-M NetBIOS name</DT
+><DD
+><P
+>This options allows you to send messages, using
+ the "WinPopup" protocol, to another computer. Once a connection is
+ established you then type your message, pressing ^D (control-D) to
+ end. </P
+><P
+>If the receiving computer is running WinPopup the user will
+ receive the message and probably a beep. If they are not running
+ WinPopup the message will be lost, and no error message will
+ occur. </P
+><P
+>The message is also automatically truncated if the message
+ is over 1600 bytes, as this is the limit of the protocol.
+ </P
+><P
+>One useful trick is to cat the message through
+ <B
+CLASS="COMMAND"
+>smbclient</B
+>. For example: <B
+CLASS="COMMAND"
+> cat mymessage.txt | smbclient -M FRED </B
+> will
+ send the message in the file <TT
+CLASS="FILENAME"
+>mymessage.txt</TT
+>
+ to the machine FRED. </P
+><P
+>You may also find the <TT
+CLASS="PARAMETER"
+><I
+>-U</I
+></TT
+> and
+ <TT
+CLASS="PARAMETER"
+><I
+>-I</I
+></TT
+> options useful, as they allow you to
+ control the FROM and TO parts of the message. </P
+><P
+>See the message command parameter in the <TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+> for a description of how to handle incoming
+ WinPopup messages in Samba. </P
+><P
+><EM
+>Note</EM
+>: Copy WinPopup into the startup group
+ on your WfWg PCs if you want them to always be able to receive
+ messages. </P
+></DD
+><DT
+>-i scope</DT
+><DD
+><P
+>This specifies a NetBIOS scope that smbclient will
+ use to communicate with when generating NetBIOS names. For details
+ on the use of NetBIOS scopes, see <TT
+CLASS="FILENAME"
+>rfc1001.txt</TT
+>
+ and <TT
+CLASS="FILENAME"
+>rfc1002.txt</TT
+>.
+ NetBIOS scopes are <EM
+>very</EM
+> rarely used, only set
+ this parameter if you are the system administrator in charge of all
+ the NetBIOS systems you communicate with. </P
+></DD
+><DT
+>-N</DT
+><DD
+><P
+>If specified, this parameter suppresses the normal
+ password prompt from the client to the user. This is useful when
+ accessing a service that does not require a password. </P
+><P
+>Unless a password is specified on the command line or
+ this parameter is specified, the client will request a
+ password.</P
+></DD
+><DT
+>-n NetBIOS name</DT
+><DD
+><P
+>By default, the client will use the local
+ machine's hostname (in uppercase) as its NetBIOS name. This parameter
+ allows you to override the host name and use whatever NetBIOS
+ name you wish. </P
+></DD
+><DT
+>-d debuglevel</DT
+><DD
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>debuglevel</I
+></TT
+> is an integer from 0 to 10, or
+ the letter 'A'. </P
+><P
+>The default value if this parameter is not specified
+ is zero. </P
+><P
+>The higher this value, the more detail will be logged to
+ the log files about the activities of the
+ client. At level 0, only critical errors and serious warnings will
+ be logged. Level 1 is a reasonable level for day to day running -
+ it generates a small amount of information about operations
+ carried out. </P
+><P
+>Levels above 1 will generate considerable amounts of log
+ data, and should only be used when investigating a problem.
+ Levels above 3 are designed for use only by developers and
+ generate HUGE amounts of log data, most of which is extremely
+ cryptic. If <TT
+CLASS="REPLACEABLE"
+><I
+>debuglevel</I
+></TT
+> is set to the letter 'A', then <EM
+>all
+ </EM
+> debug messages will be printed. This setting
+ is for developers only (and people who <EM
+>really</EM
+> want
+ to know how the code works internally). </P
+><P
+>Note that specifying this parameter here will override
+ the log level parameter in the <TT
+CLASS="FILENAME"
+>smb.conf (5)</TT
+>
+ file. </P
+></DD
+><DT
+>-p port</DT
+><DD
+><P
+>This number is the TCP port number that will be used
+ when making connections to the server. The standard (well-known)
+ TCP port number for an SMB/CIFS server is 139, which is the
+ default. </P
+></DD
+><DT
+>-l logfilename</DT
+><DD
+><P
+>If specified, <TT
+CLASS="REPLACEABLE"
+><I
+>logfilename</I
+></TT
+> specifies a base filename
+ into which operational data from the running client will be
+ logged. </P
+><P
+>The default base name is specified at compile time.</P
+><P
+>The base name is used to generate actual log file names.
+ For example, if the name specified was "log", the debug file
+ would be <TT
+CLASS="FILENAME"
+>log.client</TT
+>.</P
+><P
+>The log file generated is never removed by the client.
+ </P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Print the usage message for the client. </P
+></DD
+><DT
+>-I IP-address</DT
+><DD
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>IP address</I
+></TT
+> is the address of the server to connect to.
+ It should be specified in standard "a.b.c.d" notation. </P
+><P
+>Normally the client would attempt to locate a named
+ SMB/CIFS server by looking it up via the NetBIOS name resolution
+ mechanism described above in the <TT
+CLASS="PARAMETER"
+><I
+>name resolve order</I
+></TT
+>
+ parameter above. Using this parameter will force the client
+ to assume that the server is on the machine with the specified IP
+ address and the NetBIOS name component of the resource being
+ connected to will be ignored. </P
+><P
+>There is no default for this parameter. If not supplied,
+ it will be determined automatically by the client as described
+ above. </P
+></DD
+><DT
+>-E</DT
+><DD
+><P
+>This parameter causes the client to write messages
+ to the standard error stream (stderr) rather than to the standard
+ output stream. </P
+><P
+>By default, the client writes messages to standard output
+ - typically the user's tty. </P
+></DD
+><DT
+>-U username[%pass]</DT
+><DD
+><P
+>Sets the SMB username or username and password.
+ If %pass is not specified, The user will be prompted. The client
+ will first check the <TT
+CLASS="ENVAR"
+>USER</TT
+> environment variable, then the
+ <TT
+CLASS="ENVAR"
+>LOGNAME</TT
+> variable and if either exists, the
+ string is uppercased. Anything in these variables following a '%'
+ sign will be treated as the password. If these environment
+ variables are not found, the username <TT
+CLASS="CONSTANT"
+>GUEST</TT
+>
+ is used. </P
+><P
+>If the password is not included in these environment
+ variables (using the %pass syntax), <B
+CLASS="COMMAND"
+>smbclient</B
+> will look for
+ a <TT
+CLASS="ENVAR"
+>PASSWD</TT
+> environment variable from which
+ to read the password. </P
+><P
+>A third option is to use a credentials file which
+ contains the plaintext of the username and password. This
+ option is mainly provided for scripts where the admin doesn't
+ wish to pass the credentials on the command line or via environment
+ variables. If this method is used, make certain that the permissions
+ on the file restrict access from unwanted users. See the
+ <TT
+CLASS="PARAMETER"
+><I
+>-A</I
+></TT
+> for more details. </P
+><P
+>Be cautious about including passwords in scripts or in
+ the <TT
+CLASS="ENVAR"
+>PASSWD</TT
+> environment variable. Also, on
+ many systems the command line of a running process may be seen
+ via the <B
+CLASS="COMMAND"
+>ps</B
+> command to be safe always allow
+ <B
+CLASS="COMMAND"
+>smbclient</B
+> to prompt for a password and type
+ it in directly. </P
+></DD
+><DT
+>-A filename</DT
+><DD
+><P
+>This option allows
+ you to specify a file from which to read the username and
+ password used in the connection. The format of the file is
+ </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>username = &#60;value&#62;
+password = &#60;value&#62;
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Make certain that the permissions on the file restrict
+ access from unwanted users. </P
+></DD
+><DT
+>-L</DT
+><DD
+><P
+>This option allows you to look at what services
+ are available on a server. You use it as <B
+CLASS="COMMAND"
+>smbclient -L
+ host</B
+> and a list should appear. The <TT
+CLASS="PARAMETER"
+><I
+>-I
+ </I
+></TT
+> option may be useful if your NetBIOS names don't
+ match your TCP/IP DNS host names or if you are trying to reach a
+ host on another network. </P
+></DD
+><DT
+>-t terminal code</DT
+><DD
+><P
+>This option tells <B
+CLASS="COMMAND"
+>smbclient</B
+> how to interpret
+ filenames coming from the remote server. Usually Asian language
+ multibyte UNIX implementations use different character sets than
+ SMB/CIFS servers (<EM
+>EUC</EM
+> instead of <EM
+> SJIS</EM
+> for example). Setting this parameter will let
+ <B
+CLASS="COMMAND"
+>smbclient</B
+> convert between the UNIX filenames and
+ the SMB filenames correctly. This option has not been seriously tested
+ and may have some problems. </P
+><P
+>The terminal codes include CWsjis, CWeuc, CWjis7, CWjis8,
+ CWjunet, CWhex, CWcap. This is not a complete list, check the Samba
+ source code for the complete list. </P
+></DD
+><DT
+>-b buffersize</DT
+><DD
+><P
+>This option changes the transmit/send buffer
+ size when getting or putting a file from/to the server. The default
+ is 65520 bytes. Setting this value smaller (to 1200 bytes) has been
+ observed to speed up file transfers to and from a Win9x server.
+ </P
+></DD
+><DT
+>-W WORKGROUP</DT
+><DD
+><P
+>Override the default workgroup specified in the
+ workgroup parameter of the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file
+ for this connection. This may be needed to connect to some
+ servers. </P
+></DD
+><DT
+>-T tar options</DT
+><DD
+><P
+>smbclient may be used to create <B
+CLASS="COMMAND"
+>tar(1)
+ </B
+> compatible backups of all the files on an SMB/CIFS
+ share. The secondary tar flags that can be given to this option
+ are : </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> - Create a tar file on UNIX.
+ Must be followed by the name of a tar file, tape device
+ or "-" for standard output. If using standard output you must
+ turn the log level to its lowest value -d0 to avoid corrupting
+ your tar file. This flag is mutually exclusive with the
+ <TT
+CLASS="PARAMETER"
+><I
+>x</I
+></TT
+> flag. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>x</I
+></TT
+> - Extract (restore) a local
+ tar file back to a share. Unless the -D option is given, the tar
+ files will be restored from the top level of the share. Must be
+ followed by the name of the tar file, device or "-" for standard
+ input. Mutually exclusive with the <TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> flag.
+ Restored files have their creation times (mtime) set to the
+ date saved in the tar file. Directories currently do not get
+ their creation dates restored properly. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>I</I
+></TT
+> - Include files and directories.
+ Is the default behavior when filenames are specified above. Causes
+ tar files to be included in an extract or create (and therefore
+ everything else to be excluded). See example below. Filename globbing
+ works in one of two ways. See r below. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>X</I
+></TT
+> - Exclude files and directories.
+ Causes tar files to be excluded from an extract or create. See
+ example below. Filename globbing works in one of two ways now.
+ See <TT
+CLASS="PARAMETER"
+><I
+>r</I
+></TT
+> below. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+> - Blocksize. Must be followed
+ by a valid (greater than zero) blocksize. Causes tar file to be
+ written out in blocksize*TBLOCK (usually 512 byte) blocks.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>g</I
+></TT
+> - Incremental. Only back up
+ files that have the archive bit set. Useful only with the
+ <TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> flag. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>q</I
+></TT
+> - Quiet. Keeps tar from printing
+ diagnostics as it works. This is the same as tarmode quiet.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>r</I
+></TT
+> - Regular expression include
+ or exclude. Uses regular expression matching for
+ excluding or excluding files if compiled with HAVE_REGEX_H.
+ However this mode can be very slow. If not compiled with
+ HAVE_REGEX_H, does a limited wildcard match on '*' and '?'.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>N</I
+></TT
+> - Newer than. Must be followed
+ by the name of a file whose date is compared against files found
+ on the share during a create. Only files newer than the file
+ specified are backed up to the tar file. Useful only with the
+ <TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> flag. </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>a</I
+></TT
+> - Set archive bit. Causes the
+ archive bit to be reset when a file is backed up. Useful with the
+ <TT
+CLASS="PARAMETER"
+><I
+>g</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>c</I
+></TT
+> flags.
+ </P
+></LI
+></UL
+><P
+><EM
+>Tar Long File Names</EM
+></P
+><P
+><B
+CLASS="COMMAND"
+>smbclient</B
+>'s tar option now supports long
+ file names both on backup and restore. However, the full path
+ name of the file must be less than 1024 bytes. Also, when
+ a tar archive is created, <B
+CLASS="COMMAND"
+>smbclient</B
+>'s tar option places all
+ files in the archive with relative names, not absolute names.
+ </P
+><P
+><EM
+>Tar Filenames</EM
+></P
+><P
+>All file names can be given as DOS path names (with '\'
+ as the component separator) or as UNIX path names (with '/' as
+ the component separator). </P
+><P
+><EM
+>Examples</EM
+></P
+><P
+>Restore from tar file <TT
+CLASS="FILENAME"
+>backup.tar</TT
+> into myshare on mypc
+ (no password on share). </P
+><P
+><B
+CLASS="COMMAND"
+>smbclient //mypc/yshare "" -N -Tx backup.tar
+ </B
+></P
+><P
+>Restore everything except <TT
+CLASS="FILENAME"
+>users/docs</TT
+>
+ </P
+><P
+><B
+CLASS="COMMAND"
+>smbclient //mypc/myshare "" -N -TXx backup.tar
+ users/docs</B
+></P
+><P
+>Create a tar file of the files beneath <TT
+CLASS="FILENAME"
+> users/docs</TT
+>. </P
+><P
+><B
+CLASS="COMMAND"
+>smbclient //mypc/myshare "" -N -Tc
+ backup.tar users/docs </B
+></P
+><P
+>Create the same tar file as above, but now use
+ a DOS path name. </P
+><P
+><B
+CLASS="COMMAND"
+>smbclient //mypc/myshare "" -N -tc backup.tar
+ users\edocs </B
+></P
+><P
+>Create a tar file of all the files and directories in
+ the share. </P
+><P
+><B
+CLASS="COMMAND"
+>smbclient //mypc/myshare "" -N -Tc backup.tar *
+ </B
+></P
+></DD
+><DT
+>-D initial directory</DT
+><DD
+><P
+>Change to initial directory before starting. Probably
+ only of any use with the tar -T option. </P
+></DD
+><DT
+>-c command string</DT
+><DD
+><P
+>command string is a semicolon-separated list of
+ commands to be executed instead of prompting from stdin. <TT
+CLASS="PARAMETER"
+><I
+> -N</I
+></TT
+> is implied by <TT
+CLASS="PARAMETER"
+><I
+>-c</I
+></TT
+>.</P
+><P
+>This is particularly useful in scripts and for printing stdin
+ to the server, e.g. <B
+CLASS="COMMAND"
+>-c 'print -'</B
+>. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN310"
+></A
+><H2
+>OPERATIONS</H2
+><P
+>Once the client is running, the user is presented with
+ a prompt : </P
+><P
+><TT
+CLASS="PROMPT"
+>smb:\&#62; </TT
+></P
+><P
+>The backslash ("\") indicates the current working directory
+ on the server, and will change if the current working directory
+ is changed. </P
+><P
+>The prompt indicates that the client is ready and waiting to
+ carry out a user command. Each command is a single word, optionally
+ followed by parameters specific to that command. Command and parameters
+ are space-delimited unless these notes specifically
+ state otherwise. All commands are case-insensitive. Parameters to
+ commands may or may not be case sensitive, depending on the command.
+ </P
+><P
+>You can specify file names which have spaces in them by quoting
+ the name with double quotes, for example "a long file name". </P
+><P
+>Parameters shown in square brackets (e.g., "[parameter]") are
+ optional. If not given, the command will use suitable defaults. Parameters
+ shown in angle brackets (e.g., "&#60;parameter&#62;") are required.
+ </P
+><P
+>Note that all commands operating on the server are actually
+ performed by issuing a request to the server. Thus the behavior may
+ vary from server to server, depending on how the server was implemented.
+ </P
+><P
+>The commands available are given here in alphabetical order. </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>? [command]</DT
+><DD
+><P
+>If <TT
+CLASS="REPLACEABLE"
+><I
+>command</I
+></TT
+> is specified, the ? command will display
+ a brief informative message about the specified command. If no
+ command is specified, a list of available commands will
+ be displayed. </P
+></DD
+><DT
+>! [shell command]</DT
+><DD
+><P
+>If <TT
+CLASS="REPLACEABLE"
+><I
+>shell command</I
+></TT
+> is specified, the !
+ command will execute a shell locally and run the specified shell
+ command. If no command is specified, a local shell will be run.
+ </P
+></DD
+><DT
+>cd [directory name]</DT
+><DD
+><P
+>If "directory name" is specified, the current
+ working directory on the server will be changed to the directory
+ specified. This operation will fail if for any reason the specified
+ directory is inaccessible. </P
+><P
+>If no directory name is specified, the current working
+ directory on the server will be reported. </P
+></DD
+><DT
+>del &#60;mask&#62;</DT
+><DD
+><P
+>The client will request that the server attempt
+ to delete all files matching <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> from the current working
+ directory on the server. </P
+></DD
+><DT
+>dir &#60;mask&#62;</DT
+><DD
+><P
+>A list of the files matching <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> in the current
+ working directory on the server will be retrieved from the server
+ and displayed. </P
+></DD
+><DT
+>exit</DT
+><DD
+><P
+>Terminate the connection with the server and exit
+ from the program. </P
+></DD
+><DT
+>get &#60;remote file name&#62; [local file name]</DT
+><DD
+><P
+>Copy the file called <TT
+CLASS="FILENAME"
+>remote file name</TT
+> from
+ the server to the machine running the client. If specified, name
+ the local copy <TT
+CLASS="FILENAME"
+>local file name</TT
+>. Note that all transfers in
+ <B
+CLASS="COMMAND"
+>smbclient</B
+> are binary. See also the
+ lowercase command. </P
+></DD
+><DT
+>help [command]</DT
+><DD
+><P
+>See the ? command above. </P
+></DD
+><DT
+>lcd [directory name]</DT
+><DD
+><P
+>If <TT
+CLASS="REPLACEABLE"
+><I
+>directory name</I
+></TT
+> is specified, the current
+ working directory on the local machine will be changed to
+ the directory specified. This operation will fail if for any
+ reason the specified directory is inaccessible. </P
+><P
+>If no directory name is specified, the name of the
+ current working directory on the local machine will be reported.
+ </P
+></DD
+><DT
+>lowercase</DT
+><DD
+><P
+>Toggle lowercasing of filenames for the get and
+ mget commands. </P
+><P
+>When lowercasing is toggled ON, local filenames are converted
+ to lowercase when using the get and mget commands. This is
+ often useful when copying (say) MSDOS files from a server, because
+ lowercase filenames are the norm on UNIX systems. </P
+></DD
+><DT
+>ls &#60;mask&#62;</DT
+><DD
+><P
+>See the dir command above. </P
+></DD
+><DT
+>mask &#60;mask&#62;</DT
+><DD
+><P
+>This command allows the user to set up a mask
+ which will be used during recursive operation of the mget and
+ mput commands. </P
+><P
+>The masks specified to the mget and mput commands act as
+ filters for directories rather than files when recursion is
+ toggled ON. </P
+><P
+>The mask specified with the mask command is necessary
+ to filter files within those directories. For example, if the
+ mask specified in an mget command is "source*" and the mask
+ specified with the mask command is "*.c" and recursion is
+ toggled ON, the mget command will retrieve all files matching
+ "*.c" in all directories below and including all directories
+ matching "source*" in the current working directory. </P
+><P
+>Note that the value for mask defaults to blank (equivalent
+ to "*") and remains so until the mask command is used to change it.
+ It retains the most recently specified value indefinitely. To
+ avoid unexpected results it would be wise to change the value of
+ mask back to "*" after using the mget or mput commands. </P
+></DD
+><DT
+>md &#60;directory name&#62;</DT
+><DD
+><P
+>See the mkdir command. </P
+></DD
+><DT
+>mget &#60;mask&#62;</DT
+><DD
+><P
+>Copy all files matching <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> from the server to
+ the machine running the client. </P
+><P
+>Note that <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> is interpreted differently during recursive
+ operation and non-recursive operation - refer to the recurse and
+ mask commands for more information. Note that all transfers in
+ <B
+CLASS="COMMAND"
+>smbclient</B
+> are binary. See also the lowercase command. </P
+></DD
+><DT
+>mkdir &#60;directory name&#62;</DT
+><DD
+><P
+>Create a new directory on the server (user access
+ privileges permitting) with the specified name. </P
+></DD
+><DT
+>mput &#60;mask&#62;</DT
+><DD
+><P
+>Copy all files matching <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> in the current working
+ directory on the local machine to the current working directory on
+ the server. </P
+><P
+>Note that <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> is interpreted differently during recursive
+ operation and non-recursive operation - refer to the recurse and mask
+ commands for more information. Note that all transfers in <B
+CLASS="COMMAND"
+>smbclient</B
+>
+ are binary. </P
+></DD
+><DT
+>print &#60;file name&#62;</DT
+><DD
+><P
+>Print the specified file from the local machine
+ through a printable service on the server. </P
+><P
+>See also the printmode command.</P
+></DD
+><DT
+>printmode &#60;graphics or text&#62;</DT
+><DD
+><P
+>Set the print mode to suit either binary data
+ (such as graphical information) or text. Subsequent print
+ commands will use the currently set print mode. </P
+></DD
+><DT
+>prompt</DT
+><DD
+><P
+>Toggle prompting for filenames during operation
+ of the mget and mput commands. </P
+><P
+>When toggled ON, the user will be prompted to confirm
+ the transfer of each file during these commands. When toggled
+ OFF, all specified files will be transferred without prompting.
+ </P
+></DD
+><DT
+>put &#60;local file name&#62; [remote file name]</DT
+><DD
+><P
+>Copy the file called <TT
+CLASS="FILENAME"
+>local file name</TT
+> from the
+ machine running the client to the server. If specified,
+ name the remote copy <TT
+CLASS="FILENAME"
+>remote file name</TT
+>. Note that all transfers
+ in <B
+CLASS="COMMAND"
+>smbclient</B
+> are binary. See also the lowercase command.
+ </P
+></DD
+><DT
+>queue</DT
+><DD
+><P
+>Displays the print queue, showing the job id,
+ name, size and current status. </P
+></DD
+><DT
+>quit</DT
+><DD
+><P
+>See the exit command. </P
+></DD
+><DT
+>rd &#60;directory name&#62;</DT
+><DD
+><P
+>See the rmdir command. </P
+></DD
+><DT
+>recurse</DT
+><DD
+><P
+>Toggle directory recursion for the commands mget
+ and mput. </P
+><P
+>When toggled ON, these commands will process all directories
+ in the source directory (i.e., the directory they are copying
+ from ) and will recurse into any that match the mask specified
+ to the command. Only files that match the mask specified using
+ the mask command will be retrieved. See also the mask command.
+ </P
+><P
+>When recursion is toggled OFF, only files from the current
+ working directory on the source machine that match the mask specified
+ to the mget or mput commands will be copied, and any mask specified
+ using the mask command will be ignored. </P
+></DD
+><DT
+>rm &#60;mask&#62;</DT
+><DD
+><P
+>Remove all files matching <TT
+CLASS="REPLACEABLE"
+><I
+>mask</I
+></TT
+> from the current
+ working directory on the server. </P
+></DD
+><DT
+>rmdir &#60;directory name&#62;</DT
+><DD
+><P
+>Remove the specified directory (user access
+ privileges permitting) from the server. </P
+></DD
+><DT
+>tar &#60;c|x&#62;[IXbgNa]</DT
+><DD
+><P
+>Performs a tar operation - see the <TT
+CLASS="PARAMETER"
+><I
+>-T
+ </I
+></TT
+> command line option above. Behavior may be affected
+ by the tarmode command (see below). Using g (incremental) and N
+ (newer) will affect tarmode settings. Note that using the "-" option
+ with tar x may not work - use the command line option instead.
+ </P
+></DD
+><DT
+>blocksize &#60;blocksize&#62;</DT
+><DD
+><P
+>Blocksize. Must be followed by a valid (greater
+ than zero) blocksize. Causes tar file to be written out in
+ <TT
+CLASS="REPLACEABLE"
+><I
+>blocksize</I
+></TT
+>*TBLOCK (usually 512 byte) blocks. </P
+></DD
+><DT
+>tarmode &#60;full|inc|reset|noreset&#62;</DT
+><DD
+><P
+>Changes tar's behavior with regard to archive
+ bits. In full mode, tar will back up everything regardless of the
+ archive bit setting (this is the default mode). In incremental mode,
+ tar will only back up files with the archive bit set. In reset mode,
+ tar will reset the archive bit on all files it backs up (implies
+ read/write share). </P
+></DD
+><DT
+>setmode &#60;filename&#62; &#60;perm=[+|\-]rsha&#62;</DT
+><DD
+><P
+>A version of the DOS attrib command to set
+ file permissions. For example: </P
+><P
+><B
+CLASS="COMMAND"
+>setmode myfile +r </B
+></P
+><P
+>would make myfile read only. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN477"
+></A
+><H2
+>NOTES</H2
+><P
+>Some servers are fussy about the case of supplied usernames,
+ passwords, share names (AKA service names) and machine names.
+ If you fail to connect try giving all parameters in uppercase.
+ </P
+><P
+>It is often necessary to use the -n option when connecting
+ to some types of servers. For example OS/2 LanManager insists
+ on a valid NetBIOS name being used, so you need to supply a valid
+ name that would be known to the server.</P
+><P
+>smbclient supports long file names where the server
+ supports the LANMAN2 protocol or above. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN482"
+></A
+><H2
+>ENVIRONMENT VARIABLES</H2
+><P
+>The variable <TT
+CLASS="ENVAR"
+>USER</TT
+> may contain the
+ username of the person using the client. This information is
+ used only if the protocol level is high enough to support
+ session-level passwords.</P
+><P
+>The variable <TT
+CLASS="ENVAR"
+>PASSWD</TT
+> may contain
+ the password of the person using the client. This information is
+ used only if the protocol level is high enough to support
+ session-level passwords. </P
+><P
+>The variable <TT
+CLASS="ENVAR"
+>LIBSMB_PROG</TT
+> may contain
+ the path, executed with system(), which the client should connect
+ to instead of connecting to a server. This functionality is primarily
+ intended as a development aid, and works best when using a LMHOSTS
+ file</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN490"
+></A
+><H2
+>INSTALLATION</H2
+><P
+>The location of the client program is a matter for
+ individual system administrators. The following are thus
+ suggestions only. </P
+><P
+>It is recommended that the smbclient software be installed
+ in the <TT
+CLASS="FILENAME"
+>/usr/local/samba/bin/</TT
+> or <TT
+CLASS="FILENAME"
+> /usr/samba/bin/</TT
+> directory, this directory readable
+ by all, writeable only by root. The client program itself should
+ be executable by all. The client should <EM
+>NOT</EM
+> be
+ setuid or setgid! </P
+><P
+>The client log files should be put in a directory readable
+ and writeable only by the user. </P
+><P
+>To test the client, you will need to know the name of a
+ running SMB/CIFS server. It is possible to run <B
+CLASS="COMMAND"
+>smbd(8)
+ </B
+> as an ordinary user - running that server as a daemon
+ on a user-accessible port (typically any port number over 1024)
+ would provide a suitable test server. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN500"
+></A
+><H2
+>DIAGNOSTICS</H2
+><P
+>Most diagnostics issued by the client are logged in a
+ specified log file. The log file name is specified at compile time,
+ but may be overridden on the command line. </P
+><P
+>The number and nature of diagnostics available depends
+ on the debug level used by the client. If you have problems,
+ set the debug level to 3 and peruse the log files. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN504"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN507"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbcontrol.1.html b/docs/htmldocs/smbcontrol.1.html
new file mode 100644
index 00000000000..c824a7cd093
--- /dev/null
+++ b/docs/htmldocs/smbcontrol.1.html
@@ -0,0 +1,333 @@
+<HTML
+><HEAD
+><TITLE
+>smbcontrol</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBCONTROL"
+>smbcontrol</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbcontrol&nbsp;--&nbsp;send messages to smbd or nmbd processes</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbcontrol</B
+> [-i]</P
+><P
+><B
+CLASS="COMMAND"
+>smbcontrol</B
+> [destination] [message-type] [parameter]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN17"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbcontrol</B
+> is a very small program, which
+ sends messages to an <A
+HREF="smbd.8.html"
+TARGET="_top"
+>smbd(8)</A
+> or
+ an <A
+HREF="nmbd.8.html"
+TARGET="_top"
+>nmbd(8)</A
+> daemon running on the
+ system.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN25"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-i</DT
+><DD
+><P
+>Run interactively. Individual commands
+ of the form destination message-type parameters can be entered
+ on STDIN. An empty command line or a "q" will quit the
+ program.</P
+></DD
+><DT
+>destination</DT
+><DD
+><P
+>One of <TT
+CLASS="PARAMETER"
+><I
+>nmbd</I
+></TT
+>
+ <TT
+CLASS="PARAMETER"
+><I
+>smbd</I
+></TT
+> or a process ID.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>smbd</I
+></TT
+> destination causes the
+ message to "broadcast" to all smbd daemons.</P
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>nmbd</I
+></TT
+> destination causes the
+ message to be sent to the nmbd daemon specified in the
+ <TT
+CLASS="FILENAME"
+>nmbd.pid</TT
+> file.</P
+><P
+>If a single process ID is given, the message is sent
+ to only that process.</P
+></DD
+><DT
+>message-type</DT
+><DD
+><P
+>One of: <TT
+CLASS="CONSTANT"
+>close-share</TT
+>,
+ <TT
+CLASS="CONSTANT"
+>debug</TT
+>,
+ <TT
+CLASS="CONSTANT"
+>force-election</TT
+>, <TT
+CLASS="CONSTANT"
+>ping
+ </TT
+>, <TT
+CLASS="CONSTANT"
+>profile</TT
+>, <TT
+CLASS="CONSTANT"
+> debuglevel</TT
+>, <TT
+CLASS="CONSTANT"
+>profilelevel</TT
+>,
+ or <TT
+CLASS="CONSTANT"
+>printer-notify</TT
+>.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>close-share</TT
+> message-type sends a
+ message to smbd which will then close the client connections to
+ the named share. Note that this doesn't affect client connections
+ to any other shares. This message-type takes an argument of the
+ share name for which client connections will be close, or the
+ "*" character which will close all currently open shares.
+ This message can only be sent to <TT
+CLASS="CONSTANT"
+>smbd</TT
+>.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>debug</TT
+> message-type allows
+ the debug level to be set to the value specified by the
+ parameter. This can be sent to any of the destinations.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>force-election</TT
+> message-type can only be
+ sent to the <TT
+CLASS="CONSTANT"
+>nmbd</TT
+> destination. This message
+ causes the <B
+CLASS="COMMAND"
+>nmbd</B
+> daemon to force a new browse
+ master election.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>ping</TT
+> message-type sends the
+ number of "ping" messages specified by the parameter and waits
+ for the same number of reply "pong" messages. This can be sent to
+ any of the destinations.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>profile</TT
+> message-type sends a
+ message to an smbd to change the profile settings based on the
+ parameter. The parameter can be "on" to turn on profile stats
+ collection, "off" to turn off profile stats collection, "count"
+ to enable only collection of count stats (time stats are
+ disabled), and "flush" to zero the current profile stats. This can
+ be sent to any of the destinations.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>debuglevel</TT
+> message-type sends
+ a "request debug level" message. The current debug level setting
+ is returned by a "debuglevel" message. This can be
+ sent to any of the destinations.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>profilelevel</TT
+> message-type sends
+ a "request profile level" message. The current profile level
+ setting is returned by a "profilelevel" message. This can be sent
+ to any of the destinations.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>printer-notify</TT
+> message-type sends a
+ message to smbd which in turn sends a printer notify message to
+ any Windows NT clients connected to a printer. This message-type
+ takes an argument of the printer name to send notify messages to.
+ This message can only be sent to <TT
+CLASS="CONSTANT"
+>smbd</TT
+>.</P
+><P
+>The <TT
+CLASS="CONSTANT"
+>close-share</TT
+> message-type sends a
+ message to smbd which forces smbd to close the share that was
+ specified as an argument. This may be useful if you made changes
+ to the access controls on the share. </P
+></DD
+><DT
+>parameters</DT
+><DD
+><P
+>any parameters required for the message-type</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN82"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN85"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+>,
+ and <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN92"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbd.8.html b/docs/htmldocs/smbd.8.html
new file mode 100644
index 00000000000..ba7116704d1
--- /dev/null
+++ b/docs/htmldocs/smbd.8.html
@@ -0,0 +1,1098 @@
+<HTML
+><HEAD
+><TITLE
+>smbd</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBD"
+>smbd</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbd&nbsp;--&nbsp;server to provide SMB/CIFS services to clients</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbd</B
+> [-D] [-a] [-o] [-P] [-h] [-V] [-b] [-d &#60;debug level&#62;] [-l &#60;log directory&#62;] [-p &#60;port number&#62;] [-O &#60;socket option&#62;] [-s &#60;configuration file&#62;]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN23"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This program is part of the Samba suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbd</B
+> is the server daemon that
+ provides filesharing and printing services to Windows clients.
+ The server provides filespace and printer services to
+ clients using the SMB (or CIFS) protocol. This is compatible
+ with the LanManager protocol, and can service LanManager
+ clients. These include MSCLIENT 3.0 for DOS, Windows for
+ Workgroups, Windows 95/98/ME, Windows NT, Windows 2000,
+ OS/2, DAVE for Macintosh, and smbfs for Linux.</P
+><P
+>An extensive description of the services that the
+ server can provide is given in the man page for the
+ configuration file controlling the attributes of those
+ services (see <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+></A
+>. This man page will not describe the
+ services, but will concentrate on the administrative aspects
+ of running the server.</P
+><P
+>Please note that there are significant security
+ implications to running this server, and the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+>
+ manpage should be regarded as mandatory reading before
+ proceeding with installation.</P
+><P
+>A session is created whenever a client requests one.
+ Each client gets a copy of the server for each session. This
+ copy then services all connections made by the client during
+ that session. When all connections from its client are closed,
+ the copy of the server for that client terminates.</P
+><P
+>The configuration file, and any files that it includes,
+ are automatically reloaded every minute, if they change. You
+ can force a reload by sending a SIGHUP to the server. Reloading
+ the configuration file will not affect connections to any service
+ that is already established. Either the user will have to
+ disconnect from the service, or <B
+CLASS="COMMAND"
+>smbd</B
+> killed and restarted.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN37"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-D</DT
+><DD
+><P
+>If specified, this parameter causes
+ the server to operate as a daemon. That is, it detaches
+ itself and runs in the background, fielding requests
+ on the appropriate port. Operating the server as a
+ daemon is the recommended way of running <B
+CLASS="COMMAND"
+>smbd</B
+> for
+ servers that provide more than casual use file and
+ print services. This switch is assumed if <B
+CLASS="COMMAND"
+>smbd
+ </B
+> is executed on the command line of a shell.
+ </P
+></DD
+><DT
+>-a</DT
+><DD
+><P
+>If this parameter is specified, each new
+ connection will append log messages to the log file.
+ This is the default.</P
+></DD
+><DT
+>-o</DT
+><DD
+><P
+>If this parameter is specified, the
+ log files will be overwritten when opened. By default,
+ <B
+CLASS="COMMAND"
+>smbd</B
+> will append entries to the log
+ files.</P
+></DD
+><DT
+>-P</DT
+><DD
+><P
+>Passive option. Causes <B
+CLASS="COMMAND"
+>smbd</B
+> not to
+ send any network traffic out. Used for debugging by
+ the developers only.</P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Prints the help information (usage)
+ for <B
+CLASS="COMMAND"
+>smbd</B
+>.</P
+></DD
+><DT
+>-v</DT
+><DD
+><P
+>Prints the version number for
+ <B
+CLASS="COMMAND"
+>smbd</B
+>.</P
+></DD
+><DT
+>-b</DT
+><DD
+><P
+>Prints information about how
+ Samba was built.</P
+></DD
+><DT
+>-d &#60;debug level&#62;</DT
+><DD
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>debuglevel</I
+></TT
+> is an integer
+ from 0 to 10. The default value if this parameter is
+ not specified is zero.</P
+><P
+>The higher this value, the more detail will be
+ logged to the log files about the activities of the
+ server. At level 0, only critical errors and serious
+ warnings will be logged. Level 1 is a reasonable level for
+ day to day running - it generates a small amount of
+ information about operations carried out.</P
+><P
+>Levels above 1 will generate considerable
+ amounts of log data, and should only be used when
+ investigating a problem. Levels above 3 are designed for
+ use only by developers and generate HUGE amounts of log
+ data, most of which is extremely cryptic.</P
+><P
+>Note that specifying this parameter here will
+ override the <A
+HREF="smb.conf.5.html#loglevel"
+TARGET="_top"
+>log
+ level</A
+> parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+> file.</P
+></DD
+><DT
+>-l &#60;log directory&#62;</DT
+><DD
+><P
+>If specified,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>log directory</I
+></TT
+>
+ specifies a log directory into which the "log.smbd" log
+ file will be created for informational and debug
+ messages from the running server. The log
+ file generated is never removed by the server although
+ its size may be controlled by the <A
+HREF="smb.conf.5.html#maxlogsize"
+TARGET="_top"
+>max log size</A
+>
+ option in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> file.
+ </P
+><P
+>The default log directory is specified at
+ compile time.</P
+></DD
+><DT
+>-O &#60;socket options&#62;</DT
+><DD
+><P
+>See the <A
+HREF="smb.conf.5.html#socketoptions"
+TARGET="_top"
+>socket options</A
+>
+ parameter in the <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+></A
+> file for details.</P
+></DD
+><DT
+>-p &#60;port number&#62;</DT
+><DD
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>port number</I
+></TT
+> is a positive integer
+ value. The default value if this parameter is not
+ specified is 139.</P
+><P
+>This number is the port number that will be
+ used when making connections to the server from client
+ software. The standard (well-known) port number for the
+ SMB over TCP is 139, hence the default. If you wish to
+ run the server as an ordinary user rather than
+ as root, most systems will require you to use a port
+ number greater than 1024 - ask your system administrator
+ for help if you are in this situation.</P
+><P
+>In order for the server to be useful by most
+ clients, should you configure it on a port other
+ than 139, you will require port redirection services
+ on port 139, details of which are outlined in rfc1002.txt
+ section 4.3.5.</P
+><P
+>This parameter is not normally specified except
+ in the above situation.</P
+></DD
+><DT
+>-s &#60;configuration file&#62;</DT
+><DD
+><P
+>The file specified contains the
+ configuration details required by the server. The
+ information in this file includes server-specific
+ information such as what printcap file to use, as well
+ as descriptions of all the services that the server is
+ to provide. See <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> for more information.
+ The default configuration file name is determined at
+ compile time.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN115"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+></DT
+><DD
+><P
+>If the server is to be run by the
+ <B
+CLASS="COMMAND"
+>inetd</B
+> meta-daemon, this file
+ must contain suitable startup information for the
+ meta-daemon. See the section INSTALLATION below.
+ </P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/rc</TT
+></DT
+><DD
+><P
+>or whatever initialization script your
+ system uses).</P
+><P
+>If running the server as a daemon at startup,
+ this file will need to contain an appropriate startup
+ sequence for the server. See the section INSTALLATION
+ below.</P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/services</TT
+></DT
+><DD
+><P
+>If running the server via the
+ meta-daemon <B
+CLASS="COMMAND"
+>inetd</B
+>, this file
+ must contain a mapping of service name (e.g., netbios-ssn)
+ to service port (e.g., 139) and protocol type (e.g., tcp).
+ See the section INSTALLATION below.</P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/smb.conf</TT
+></DT
+><DD
+><P
+>This is the default location of the
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf</TT
+></A
+>
+ server configuration file. Other common places that systems
+ install this file are <TT
+CLASS="FILENAME"
+>/usr/samba/lib/smb.conf</TT
+>
+ and <TT
+CLASS="FILENAME"
+>/etc/smb.conf</TT
+>.</P
+><P
+>This file describes all the services the server
+ is to make available to clients. See <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+> <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+> for more information.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN148"
+></A
+><H2
+>LIMITATIONS</H2
+><P
+>On some systems <B
+CLASS="COMMAND"
+>smbd</B
+> cannot change uid back
+ to root after a setuid() call. Such systems are called
+ trapdoor uid systems. If you have such a system,
+ you will be unable to connect from a client (such as a PC) as
+ two different users at once. Attempts to connect the
+ second user will result in access denied or
+ similar.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN152"
+></A
+><H2
+>ENVIRONMENT VARIABLES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="ENVAR"
+>PRINTER</TT
+></DT
+><DD
+><P
+>If no printer name is specified to
+ printable services, most systems will use the value of
+ this variable (or <TT
+CLASS="CONSTANT"
+>lp</TT
+> if this variable is
+ not defined) as the name of the printer to use. This
+ is not specific to the server, however.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN161"
+></A
+><H2
+>INSTALLATION</H2
+><P
+>The location of the server and its support files
+ is a matter for individual system administrators. The following
+ are thus suggestions only.</P
+><P
+>It is recommended that the server software be installed
+ under the <TT
+CLASS="FILENAME"
+>/usr/local/samba/</TT
+> hierarchy,
+ in a directory readable by all, writeable only by root. The server
+ program itself should be executable by all, as users may wish to
+ run the server themselves (in which case it will of course run
+ with their privileges). The server should NOT be setuid. On some
+ systems it may be worthwhile to make <B
+CLASS="COMMAND"
+>smbd</B
+> setgid to an empty group.
+ This is because some systems may have a security hole where daemon
+ processes that become a user can be attached to with a debugger.
+ Making the <B
+CLASS="COMMAND"
+>smbd</B
+> file setgid to an empty group may prevent
+ this hole from being exploited. This security hole and the suggested
+ fix has only been confirmed on old versions (pre-kernel 2.0) of Linux
+ at the time this was written. It is possible that this hole only
+ exists in Linux, as testing on other systems has thus far shown them
+ to be immune.</P
+><P
+>The server log files should be put in a directory readable and
+ writeable only by root, as the log files may contain sensitive
+ information.</P
+><P
+>The configuration file should be placed in a directory
+ readable and writeable only by root, as the configuration file
+ controls security for the services offered by the server. The
+ configuration file can be made readable by all if desired, but
+ this is not necessary for correct operation of the server and is
+ not recommended. A sample configuration file <TT
+CLASS="FILENAME"
+>smb.conf.sample
+ </TT
+> is supplied with the source to the server - this may
+ be renamed to <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> and modified to suit
+ your needs.</P
+><P
+>The remaining notes will assume the following:</P
+><P
+></P
+><UL
+><LI
+><P
+><B
+CLASS="COMMAND"
+>smbd</B
+> (the server program)
+ installed in <TT
+CLASS="FILENAME"
+>/usr/local/samba/bin</TT
+></P
+></LI
+><LI
+><P
+><TT
+CLASS="FILENAME"
+>smb.conf</TT
+> (the configuration
+ file) installed in <TT
+CLASS="FILENAME"
+>/usr/local/samba/lib</TT
+></P
+></LI
+><LI
+><P
+>log files stored in <TT
+CLASS="FILENAME"
+>/var/adm/smblogs
+ </TT
+></P
+></LI
+></UL
+><P
+>The server may be run either as a daemon by users
+ or at startup, or it may be run from a meta-daemon such as
+ <B
+CLASS="COMMAND"
+>inetd</B
+> upon request. If run as a daemon,
+ the server will always be ready, so starting sessions will be
+ faster. If run from a meta-daemon some memory will be saved and
+ utilities such as the tcpd TCP-wrapper may be used for extra
+ security. For serious use as file server it is recommended
+ that <B
+CLASS="COMMAND"
+>smbd</B
+> be run as a daemon.</P
+><P
+>When you've decided, continue with either</P
+><P
+></P
+><UL
+><LI
+><P
+>RUNNING THE SERVER AS A DAEMON or</P
+></LI
+><LI
+><P
+>RUNNING THE SERVER ON REQUEST.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN194"
+></A
+><H2
+>RUNNING THE SERVER AS A DAEMON</H2
+><P
+>To run the server as a daemon from the command
+ line, simply put the <EM
+>-D</EM
+> option on the
+ command line. There is no need to place an ampersand at
+ the end of the command line - the <EM
+>-D</EM
+>
+ option causes the server to detach itself from the tty
+ anyway.</P
+><P
+>Any user can run the server as a daemon (execute
+ permissions permitting, of course). This is useful for
+ testing purposes, and may even be useful as a temporary
+ substitute for something like ftp. When run this way, however,
+ the server will only have the privileges of the user who ran
+ it.</P
+><P
+>To ensure that the server is run as a daemon whenever
+ the machine is started, and to ensure that it runs as root
+ so that it can serve multiple clients, you will need to modify
+ the system startup files. Wherever appropriate (for example, in
+ <TT
+CLASS="FILENAME"
+>/etc/rc</TT
+>), insert the following line,
+ substituting port number, log file location, configuration file
+ location and debug level as desired:</P
+><P
+><B
+CLASS="COMMAND"
+>/usr/local/samba/bin/smbd -D -l /var/adm/smblogs/log
+ -s /usr/local/samba/lib/smb.conf</B
+></P
+><P
+>(The above should appear in your initialization script
+ as a single line. Depending on your terminal characteristics,
+ it may not appear that way in this man page. If the above appears
+ as more than one line, please treat any newlines or indentation
+ as a single space or TAB character.)</P
+><P
+>If the options used at compile time are appropriate for
+ your system, all parameters except <EM
+>-D</EM
+> may
+ be omitted. See the section OPTIONS above.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN207"
+></A
+><H2
+>RUNNING THE SERVER ON REQUEST</H2
+><P
+>If your system uses a meta-daemon such as <B
+CLASS="COMMAND"
+>inetd
+ </B
+>, you can arrange to have the <B
+CLASS="COMMAND"
+>smbd</B
+> server started
+ whenever a process attempts to connect to it. This requires several
+ changes to the startup files on the host machine. If you are
+ experimenting as an ordinary user rather than as root, you will
+ need the assistance of your system administrator to modify the
+ system files.</P
+><P
+>You will probably want to set up the NetBIOS name server
+ <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd</B
+></A
+> at
+ the same time as <B
+CLASS="COMMAND"
+>smbd</B
+>. To do this refer to the
+ man page for <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+>
+ </A
+>.</P
+><P
+>First, ensure that a port is configured in the file
+ <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>. The well-known port 139
+ should be used if possible, though any port may be used.</P
+><P
+>Ensure that a line similar to the following is in
+ <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>:</P
+><P
+><B
+CLASS="COMMAND"
+>netbios-ssn 139/tcp</B
+></P
+><P
+>Note for NIS/YP users - you may need to rebuild the
+ NIS service maps rather than alter your local <TT
+CLASS="FILENAME"
+>/etc/services
+ </TT
+> file.</P
+><P
+>Next, put a suitable line in the file <TT
+CLASS="FILENAME"
+>/etc/inetd.conf
+ </TT
+> (in the unlikely event that you are using a meta-daemon
+ other than inetd, you are on your own). Note that the first item
+ in this line matches the service name in <TT
+CLASS="FILENAME"
+>/etc/services
+ </TT
+>. Substitute appropriate values for your system
+ in this line (see <B
+CLASS="COMMAND"
+>inetd(8)</B
+>):</P
+><P
+><B
+CLASS="COMMAND"
+>netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd
+ -d1 -l/var/adm/smblogs/log -s/usr/local/samba/lib/smb.conf</B
+></P
+><P
+>(The above should appear in <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>
+ as a single line. Depending on your terminal characteristics, it may
+ not appear that way in this man page. If the above appears as more
+ than one line, please treat any newlines or indentation as a single
+ space or TAB character.)</P
+><P
+>Note that there is no need to specify a port number here,
+ even if you are using a non-standard port number.</P
+><P
+>Lastly, edit the configuration file to provide suitable
+ services. To start with, the following two services should be
+ all you need:</P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+> <TT
+CLASS="COMPUTEROUTPUT"
+> [homes]
+ writeable = yes
+
+ [printers]
+ writeable = no
+ printable = yes
+ path = /tmp
+ public = yes
+ </TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+><P
+>This will allow you to connect to your home directory
+ and print to any printer supported by the host (user privileges
+ permitting).</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN239"
+></A
+><H2
+>PAM INTERACTION</H2
+><P
+>Samba uses PAM for authentication (when presented with a plaintext
+ password), for account checking (is this account disabled?) and for
+ session management. The degree too which samba supports PAM is restricted
+ by the limitations of the SMB protocol and the
+ <A
+HREF="smb.conf.5.html#OBEYPAMRESRICTIONS"
+TARGET="_top"
+>obey pam restricions</A
+>
+ smb.conf paramater. When this is set, the following restrictions apply:
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><EM
+>Account Validation</EM
+>: All acccesses to a
+ samba server are checked
+ against PAM to see if the account is vaild, not disabled and is permitted to
+ login at this time. This also applies to encrypted logins.
+ </P
+></LI
+><LI
+><P
+><EM
+>Session Management</EM
+>: When not using share
+ level secuirty, users must pass PAM's session checks before access
+ is granted. Note however, that this is bypassed in share level secuirty.
+ Note also that some older pam configuration files may need a line
+ added for session support.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN250"
+></A
+><H2
+>TESTING THE INSTALLATION</H2
+><P
+>If running the server as a daemon, execute it before
+ proceeding. If using a meta-daemon, either restart the system
+ or kill and restart the meta-daemon. Some versions of
+ <B
+CLASS="COMMAND"
+>inetd</B
+> will reread their configuration
+ tables if they receive a HUP signal.</P
+><P
+>If your machine's name is <TT
+CLASS="REPLACEABLE"
+><I
+>fred</I
+></TT
+> and your
+ name is <TT
+CLASS="REPLACEABLE"
+><I
+>mary</I
+></TT
+>, you should now be able to connect
+ to the service <TT
+CLASS="FILENAME"
+>\\fred\mary</TT
+>.
+ </P
+><P
+>To properly test and experiment with the server, we
+ recommend using the <B
+CLASS="COMMAND"
+>smbclient</B
+> program (see
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>)
+ and also going through the steps outlined in the file
+ <TT
+CLASS="FILENAME"
+>DIAGNOSIS.txt</TT
+> in the <TT
+CLASS="FILENAME"
+>docs/</TT
+>
+ directory of your Samba installation.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN264"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN267"
+></A
+><H2
+>DIAGNOSTICS</H2
+><P
+>Most diagnostics issued by the server are logged
+ in a specified log file. The log file name is specified
+ at compile time, but may be overridden on the command line.</P
+><P
+>The number and nature of diagnostics available depends
+ on the debug level used by the server. If you have problems, set
+ the debug level to 3 and peruse the log files.</P
+><P
+>Most messages are reasonably self-explanatory. Unfortunately,
+ at the time this man page was created, there are too many diagnostics
+ available in the source code to warrant describing each and every
+ diagnostic. At this stage your best bet is still to grep the
+ source code and inspect the conditions that gave rise to the
+ diagnostics you are seeing.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN272"
+></A
+><H2
+>SIGNALS</H2
+><P
+>Sending the <B
+CLASS="COMMAND"
+>smbd</B
+> a SIGHUP will cause it to
+ reload its <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> configuration
+ file within a short period of time.</P
+><P
+>To shut down a user's <B
+CLASS="COMMAND"
+>smbd</B
+> process it is recommended
+ that <B
+CLASS="COMMAND"
+>SIGKILL (-9)</B
+> <EM
+>NOT</EM
+>
+ be used, except as a last resort, as this may leave the shared
+ memory area in an inconsistent state. The safe way to terminate
+ an <B
+CLASS="COMMAND"
+>smbd</B
+> is to send it a SIGTERM (-15) signal and wait for
+ it to die on its own.</P
+><P
+>The debug log level of <B
+CLASS="COMMAND"
+>smbd</B
+> may be raised
+ or lowered using <A
+HREF="smbcontrol.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbcontrol(1)
+ </B
+></A
+> program (SIGUSR[1|2] signals are no longer used in
+ Samba 2.2). This is to allow transient problems to be diagnosed,
+ whilst still running at a normally low log level.</P
+><P
+>Note that as the signal handlers send a debug write,
+ they are not re-entrant in <B
+CLASS="COMMAND"
+>smbd</B
+>. This you should wait until
+ <B
+CLASS="COMMAND"
+>smbd</B
+> is in a state of waiting for an incoming SMB before
+ issuing them. It is possible to make the signal handlers safe
+ by un-blocking the signals before the select call and re-blocking
+ them after, however this would affect performance.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN289"
+></A
+><H2
+>SEE ALSO</H2
+><P
+>hosts_access(5), <B
+CLASS="COMMAND"
+>inetd(8)</B
+>,
+ <A
+HREF="nmbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>nmbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ </A
+>, <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)
+ </B
+></A
+>, <A
+HREF="testparm.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> testparm(1)</B
+></A
+>, <A
+HREF="testprns.1.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>testprns(1)</B
+></A
+>, and the Internet RFC's
+ <TT
+CLASS="FILENAME"
+>rfc1001.txt</TT
+>, <TT
+CLASS="FILENAME"
+>rfc1002.txt</TT
+>.
+ In addition the CIFS (formerly SMB) specification is available
+ as a link from the Web page <A
+HREF="http://samba.org/cifs/"
+TARGET="_top"
+>
+ http://samba.org/cifs/</A
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN306"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbmnt.8.html b/docs/htmldocs/smbmnt.8.html
new file mode 100644
index 00000000000..a7d10b6e191
--- /dev/null
+++ b/docs/htmldocs/smbmnt.8.html
@@ -0,0 +1,178 @@
+<HTML
+><HEAD
+><TITLE
+>smbmnt</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBMNT"
+>smbmnt</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbmnt&nbsp;--&nbsp;helper utility for mounting SMB filesystems</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbmnt</B
+> {mount-point} [-s &#60;share&#62;] [-r] [-u &#60;uid&#62;] [-g &#60;gid&#62;] [-f &#60;mask&#62;] [-d &#60;mask&#62;] [-o &#60;options&#62;]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN19"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><B
+CLASS="COMMAND"
+>smbmnt</B
+> is a helper application used
+ by the smbmount program to do the actual mounting of SMB shares.
+ <B
+CLASS="COMMAND"
+>smbmnt</B
+> can be installed setuid root if you want
+ normal users to be able to mount their SMB shares.</P
+><P
+>A setuid smbmnt will only allow mounts on directories owned
+ by the user, and that the user has write permission on.</P
+><P
+>The <B
+CLASS="COMMAND"
+>smbmnt</B
+> program is normally invoked
+ by <A
+HREF="smbmount.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbmount(8)</B
+>
+ </A
+>. It should not be invoked directly by users. </P
+><P
+>smbmount searches the normal PATH for smbmnt. You must ensure
+ that the smbmnt version in your path matches the smbmount used.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN30"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-r</DT
+><DD
+><P
+>mount the filesystem read-only
+ </P
+></DD
+><DT
+>-u uid</DT
+><DD
+><P
+>specify the uid that the files will
+ be owned by </P
+></DD
+><DT
+>-g gid</DT
+><DD
+><P
+>specify the gid that the files will be
+ owned by </P
+></DD
+><DT
+>-f mask</DT
+><DD
+><P
+>specify the octal file mask applied
+ </P
+></DD
+><DT
+>-d mask</DT
+><DD
+><P
+>specify the octal directory mask
+ applied </P
+></DD
+><DT
+>-o options</DT
+><DD
+><P
+> list of options that are passed as-is to smbfs, if this
+ command is run on a 2.4 or higher Linux kernel.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>AUTHOR</H2
+><P
+>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</P
+><P
+>The current maintainer of smbfs and the userspace
+ tools <B
+CLASS="COMMAND"
+>smbmount</B
+>, <B
+CLASS="COMMAND"
+>smbumount</B
+>,
+ and <B
+CLASS="COMMAND"
+>smbmnt</B
+> is <A
+HREF="mailto:urban@teststation.com"
+TARGET="_top"
+>Urban Widmark</A
+>.
+ The <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+>SAMBA Mailing list</A
+>
+ is the preferred place to ask questions regarding these programs.
+ </P
+><P
+>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbmount.8.html b/docs/htmldocs/smbmount.8.html
new file mode 100644
index 00000000000..b7263ebf83d
--- /dev/null
+++ b/docs/htmldocs/smbmount.8.html
@@ -0,0 +1,468 @@
+<HTML
+><HEAD
+><TITLE
+>smbmount</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBMOUNT"
+>smbmount</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbmount&nbsp;--&nbsp;mount an smbfs filesystem</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbumount</B
+> {service} {mount-point} [-o options]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN14"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><B
+CLASS="COMMAND"
+>smbmount</B
+> mounts a Linux SMB filesystem. It
+ is usually invoked as <B
+CLASS="COMMAND"
+>mount.smbfs</B
+> by
+ the <B
+CLASS="COMMAND"
+>mount(8)</B
+> command when using the
+ "-t smbfs" option. This command only works in Linux, and the kernel must
+ support the smbfs filesystem. </P
+><P
+>Options to <B
+CLASS="COMMAND"
+>smbmount</B
+> are specified as a comma-separated
+ list of key=value pairs. It is possible to send options other
+ than those listed here, assuming that smbfs supports them. If
+ you get mount failures, check your kernel log for errors on
+ unknown options.</P
+><P
+><B
+CLASS="COMMAND"
+>smbmount</B
+> is a daemon. After mounting it keeps running until
+ the mounted smbfs is umounted. It will log things that happen
+ when in daemon mode using the "machine name" smbmount, so
+ typically this output will end up in <TT
+CLASS="FILENAME"
+>log.smbmount</TT
+>. The
+ <B
+CLASS="COMMAND"
+>smbmount</B
+> process may also be called mount.smbfs.</P
+><P
+><EM
+>NOTE:</EM
+> <B
+CLASS="COMMAND"
+>smbmount</B
+>
+ calls <B
+CLASS="COMMAND"
+>smbmnt(8)</B
+> to do the actual mount. You
+ must make sure that <B
+CLASS="COMMAND"
+>smbmnt</B
+> is in the path so
+ that it can be found. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN31"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>username=&#60;arg&#62;</DT
+><DD
+><P
+>specifies the username to connect as. If
+ this is not given, then the environment variable <TT
+CLASS="ENVAR"
+> USER</TT
+> is used. This option can also take the
+ form "user%password" or "user/workgroup" or
+ "user/workgroup%password" to allow the password and workgroup
+ to be specified as part of the username.</P
+></DD
+><DT
+>password=&#60;arg&#62;</DT
+><DD
+><P
+>specifies the SMB password. If this
+ option is not given then the environment variable
+ <TT
+CLASS="ENVAR"
+>PASSWD</TT
+> is used. If it can find
+ no password <B
+CLASS="COMMAND"
+>smbmount</B
+> will prompt
+ for a passeword, unless the guest option is
+ given. </P
+><P
+> Note that password which contain the arguement delimiter
+ character (i.e. a comma ',') will failed to be parsed correctly
+ on the command line. However, the same password defined
+ in the PASSWD environment variable or a credentials file (see
+ below) will be read correctly.
+ </P
+></DD
+><DT
+>credentials=&#60;filename&#62;</DT
+><DD
+><P
+>specifies a file that contains a username
+ and/or password. The format of the file is:</P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> username = &#60;value&#62;
+ password = &#60;value&#62;
+ </PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+>This is preferred over having passwords in plaintext in a
+ shared file, such as <TT
+CLASS="FILENAME"
+>/etc/fstab</TT
+>. Be sure to protect any
+ credentials file properly.
+ </P
+></DD
+><DT
+>netbiosname=&#60;arg&#62;</DT
+><DD
+><P
+>sets the source NetBIOS name. It defaults
+ to the local hostname. </P
+></DD
+><DT
+>uid=&#60;arg&#62;</DT
+><DD
+><P
+>sets the uid that will own all files on
+ the mounted filesystem.
+ It may be specified as either a username or a numeric uid.
+ </P
+></DD
+><DT
+>gid=&#60;arg&#62;</DT
+><DD
+><P
+>sets the gid that will own all files on
+ the mounted filesystem.
+ It may be specified as either a groupname or a numeric
+ gid. </P
+></DD
+><DT
+>port=&#60;arg&#62;</DT
+><DD
+><P
+>sets the remote SMB port number. The default
+ is 139. </P
+></DD
+><DT
+>fmask=&#60;arg&#62;</DT
+><DD
+><P
+>sets the file mask. This determines the
+ permissions that remote files have in the local filesystem.
+ The default is based on the current umask. </P
+></DD
+><DT
+>dmask=&#60;arg&#62;</DT
+><DD
+><P
+>sets the directory mask. This determines the
+ permissions that remote directories have in the local filesystem.
+ The default is based on the current umask. </P
+></DD
+><DT
+>debug=&#60;arg&#62;</DT
+><DD
+><P
+>sets the debug level. This is useful for
+ tracking down SMB connection problems. A suggested value to
+ start with is 4. If set too high there will be a lot of
+ output, possibly hiding the useful output.</P
+></DD
+><DT
+>ip=&#60;arg&#62;</DT
+><DD
+><P
+>sets the destination host or IP address.
+ </P
+></DD
+><DT
+>workgroup=&#60;arg&#62;</DT
+><DD
+><P
+>sets the workgroup on the destination </P
+></DD
+><DT
+>sockopt=&#60;arg&#62;</DT
+><DD
+><P
+>sets the TCP socket options. See the <A
+HREF="smb.conf.5.html#SOCKETOPTIONS"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf
+ </TT
+></A
+> <TT
+CLASS="PARAMETER"
+><I
+>socket options</I
+></TT
+> option.
+ </P
+></DD
+><DT
+>scope=&#60;arg&#62;</DT
+><DD
+><P
+>sets the NetBIOS scope </P
+></DD
+><DT
+>guest</DT
+><DD
+><P
+>don't prompt for a password </P
+></DD
+><DT
+>ro</DT
+><DD
+><P
+>mount read-only </P
+></DD
+><DT
+>rw</DT
+><DD
+><P
+>mount read-write </P
+></DD
+><DT
+>iocharset=&#60;arg&#62;</DT
+><DD
+><P
+> sets the charset used by the Linux side for codepage
+ to charset translations (NLS). Argument should be the
+ name of a charset, like iso8859-1. (Note: only kernel
+ 2.4.0 or later)
+ </P
+></DD
+><DT
+>codepage=&#60;arg&#62;</DT
+><DD
+><P
+> sets the codepage the server uses. See the iocharset
+ option. Example value cp850. (Note: only kernel 2.4.0
+ or later)
+ </P
+></DD
+><DT
+>ttl=&#60;arg&#62;</DT
+><DD
+><P
+> how long a directory listing is cached in milliseconds
+ (also affects visibility of file size and date
+ changes). A higher value means that changes on the
+ server take longer to be noticed but it can give
+ better performance on large directories, especially
+ over long distances. Default is 1000ms but something
+ like 10000ms (10 seconds) is probably more reasonable
+ in many cases.
+ (Note: only kernel 2.4.2 or later)
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN125"
+></A
+><H2
+>ENVIRONMENT VARIABLES</H2
+><P
+>The variable <TT
+CLASS="ENVAR"
+>USER</TT
+> may contain the username of the
+ person using the client. This information is used only if the
+ protocol level is high enough to support session-level
+ passwords. The variable can be used to set both username and
+ password by using the format username%password.</P
+><P
+>The variable <TT
+CLASS="ENVAR"
+>PASSWD</TT
+> may contain the password of the
+ person using the client. This information is used only if the
+ protocol level is high enough to support session-level
+ passwords.</P
+><P
+>The variable <TT
+CLASS="ENVAR"
+>PASSWD_FILE</TT
+> may contain the pathname
+ of a file to read the password from. A single line of input is
+ read and used as the password.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN133"
+></A
+><H2
+>BUGS</H2
+><P
+>Passwords and other options containing , can not be handled.
+ For passwords an alternative way of passing them is in a credentials
+ file or in the PASSWD environment.</P
+><P
+>The credentials file does not handle usernames or passwords with
+ leading space.</P
+><P
+>One smbfs bug is important enough to mention here, even if it
+ is a bit misplaced:</P
+><P
+></P
+><UL
+><LI
+><P
+>Mounts sometimes stop working. This is usually
+ caused by smbmount terminating. Since smbfs needs smbmount to
+ reconnect when the server disconnects, the mount will eventually go
+ dead. An umount/mount normally fixes this. At least 2 ways to
+ trigger this bug are known.</P
+></LI
+></UL
+><P
+>Note that the typical response to a bug report is suggestion
+ to try the latest version first. So please try doing that first,
+ and always include which versions you use of relevant software
+ when reporting bugs (minimum: samba, kernel, distribution)</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN142"
+></A
+><H2
+>SEE ALSO</H2
+><P
+>Documentation/filesystems/smbfs.txt in the linux kernel
+ source tree may contain additional options and information.</P
+><P
+>FreeBSD also has a smbfs, but it is not related to smbmount</P
+><P
+>For Solaris, HP-UX and others you may want to look at
+ <A
+HREF="smbsh.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbsh(1)</B
+></A
+> or at other
+ solutions, such as sharity or perhaps replacing the SMB server with
+ a NFS server.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN149"
+></A
+><H2
+>AUTHOR</H2
+><P
+>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</P
+><P
+>The current maintainer of smbfs and the userspace
+ tools <B
+CLASS="COMMAND"
+>smbmount</B
+>, <B
+CLASS="COMMAND"
+>smbumount</B
+>,
+ and <B
+CLASS="COMMAND"
+>smbmnt</B
+> is <A
+HREF="mailto:urban@teststation.com"
+TARGET="_top"
+>Urban Widmark</A
+>.
+ The <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+>SAMBA Mailing list</A
+>
+ is the preferred place to ask questions regarding these programs.
+ </P
+><P
+>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbpasswd.5.html b/docs/htmldocs/smbpasswd.5.html
new file mode 100644
index 00000000000..1f862b66114
--- /dev/null
+++ b/docs/htmldocs/smbpasswd.5.html
@@ -0,0 +1,316 @@
+<HTML
+><HEAD
+><TITLE
+>smbpasswd</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBPASSWD"
+>smbpasswd</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbpasswd&nbsp;--&nbsp;The Samba encrypted password file</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><TT
+CLASS="FILENAME"
+>smbpasswd</TT
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN11"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+>smbpasswd is the Samba encrypted password file. It contains
+ the username, Unix user id and the SMB hashed passwords of the
+ user, as well as account flag information and the time the
+ password was last changed. This file format has been evolving with
+ Samba and has had several different formats in the past. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN16"
+></A
+><H2
+>FILE FORMAT</H2
+><P
+>The format of the smbpasswd file used by Samba 2.2
+ is very similar to the familiar Unix <TT
+CLASS="FILENAME"
+>passwd(5)</TT
+>
+ file. It is an ASCII file containing one line for each user. Each field
+ ithin each line is separated from the next by a colon. Any entry
+ beginning with '#' is ignored. The smbpasswd file contains the
+ following information for each user: </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>name</DT
+><DD
+><P
+> This is the user name. It must be a name that
+ already exists in the standard UNIX passwd file. </P
+></DD
+><DT
+>uid</DT
+><DD
+><P
+>This is the UNIX uid. It must match the uid
+ field for the same user entry in the standard UNIX passwd file.
+ If this does not match then Samba will refuse to recognize
+ this smbpasswd file entry as being valid for a user.
+ </P
+></DD
+><DT
+>Lanman Password Hash</DT
+><DD
+><P
+>This is the LANMAN hash of the user's password,
+ encoded as 32 hex digits. The LANMAN hash is created by DES
+ encrypting a well known string with the user's password as the
+ DES key. This is the same password used by Windows 95/98 machines.
+ Note that this password hash is regarded as weak as it is
+ vulnerable to dictionary attacks and if two users choose the
+ same password this entry will be identical (i.e. the password
+ is not "salted" as the UNIX password is). If the user has a
+ null password this field will contain the characters "NO PASSWORD"
+ as the start of the hex string. If the hex string is equal to
+ 32 'X' characters then the user's account is marked as
+ <TT
+CLASS="CONSTANT"
+>disabled</TT
+> and the user will not be able to
+ log onto the Samba server. </P
+><P
+><EM
+>WARNING !!</EM
+> Note that, due to
+ the challenge-response nature of the SMB/CIFS authentication
+ protocol, anyone with a knowledge of this password hash will
+ be able to impersonate the user on the network. For this
+ reason these hashes are known as <EM
+>plain text
+ equivalents</EM
+> and must <EM
+>NOT</EM
+> be made
+ available to anyone but the root user. To protect these passwords
+ the smbpasswd file is placed in a directory with read and
+ traverse access only to the root user and the smbpasswd file
+ itself must be set to be read/write only by root, with no
+ other access. </P
+></DD
+><DT
+>NT Password Hash</DT
+><DD
+><P
+>This is the Windows NT hash of the user's
+ password, encoded as 32 hex digits. The Windows NT hash is
+ created by taking the user's password as represented in
+ 16-bit, little-endian UNICODE and then applying the MD4
+ (internet rfc1321) hashing algorithm to it. </P
+><P
+>This password hash is considered more secure than
+ the LANMAN Password Hash as it preserves the case of the
+ password and uses a much higher quality hashing algorithm.
+ However, it is still the case that if two users choose the same
+ password this entry will be identical (i.e. the password is
+ not "salted" as the UNIX password is). </P
+><P
+><EM
+>WARNING !!</EM
+>. Note that, due to
+ the challenge-response nature of the SMB/CIFS authentication
+ protocol, anyone with a knowledge of this password hash will
+ be able to impersonate the user on the network. For this
+ reason these hashes are known as <EM
+>plain text
+ equivalents</EM
+> and must <EM
+>NOT</EM
+> be made
+ available to anyone but the root user. To protect these passwords
+ the smbpasswd file is placed in a directory with read and
+ traverse access only to the root user and the smbpasswd file
+ itself must be set to be read/write only by root, with no
+ other access. </P
+></DD
+><DT
+>Account Flags</DT
+><DD
+><P
+>This section contains flags that describe
+ the attributes of the users account. In the Samba 2.2 release
+ this field is bracketed by '[' and ']' characters and is always
+ 13 characters in length (including the '[' and ']' characters).
+ The contents of this field may be any of the characters.
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><EM
+>U</EM
+> - This means
+ this is a "User" account, i.e. an ordinary user. Only User
+ and Workstation Trust accounts are currently supported
+ in the smbpasswd file. </P
+></LI
+><LI
+><P
+><EM
+>N</EM
+> - This means the
+ account has no password (the passwords in the fields LANMAN
+ Password Hash and NT Password Hash are ignored). Note that this
+ will only allow users to log on with no password if the <TT
+CLASS="PARAMETER"
+><I
+> null passwords</I
+></TT
+> parameter is set in the <A
+HREF="smb.conf.5.html#NULLPASSWORDS"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+></A
+> config file. </P
+></LI
+><LI
+><P
+><EM
+>D</EM
+> - This means the account
+ is disabled and no SMB/CIFS logins will be allowed for
+ this user. </P
+></LI
+><LI
+><P
+><EM
+>W</EM
+> - This means this account
+ is a "Workstation Trust" account. This kind of account is used
+ in the Samba PDC code stream to allow Windows NT Workstations
+ and Servers to join a Domain hosted by a Samba PDC. </P
+></LI
+></UL
+><P
+>Other flags may be added as the code is extended in future.
+ The rest of this field space is filled in with spaces. </P
+></DD
+><DT
+>Last Change Time</DT
+><DD
+><P
+>This field consists of the time the account was
+ last modified. It consists of the characters 'LCT-' (standing for
+ "Last Change Time") followed by a numeric encoding of the UNIX time
+ in seconds since the epoch (1970) that the last change was made.
+ </P
+></DD
+></DL
+></DIV
+><P
+>All other colon separated fields are ignored at this time.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN73"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN76"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbpasswd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbpasswd(8)</B
+></A
+>,
+ <A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>, and
+ the Internet RFC1321 for details on the MD4 algorithm.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN82"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbpasswd.8.html b/docs/htmldocs/smbpasswd.8.html
new file mode 100644
index 00000000000..c8f97c89d13
--- /dev/null
+++ b/docs/htmldocs/smbpasswd.8.html
@@ -0,0 +1,673 @@
+<HTML
+><HEAD
+><TITLE
+>smbpasswd</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBPASSWD"
+>smbpasswd</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbpasswd&nbsp;--&nbsp;change a user's SMB password</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbpasswd</B
+> [-a] [-x] [-d] [-e] [-D debuglevel] [-n] [-r &#60;remote machine&#62;] [-R &#60;name resolve order&#62;] [-m] [-j DOMAIN] [-U username[%password]] [-h] [-s] [-w pass] [username]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN26"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+>The smbpasswd program has several different
+ functions, depending on whether it is run by the <EM
+>root</EM
+>
+ user or not. When run as a normal user it allows the user to change
+ the password used for their SMB sessions on any machines that store
+ SMB passwords. </P
+><P
+>By default (when run with no arguments) it will attempt to
+ change the current user's SMB password on the local machine. This is
+ similar to the way the <B
+CLASS="COMMAND"
+>passwd(1)</B
+> program works.
+ <B
+CLASS="COMMAND"
+>smbpasswd</B
+> differs from how the passwd program works
+ however in that it is not <EM
+>setuid root</EM
+> but works in
+ a client-server mode and communicates with a locally running
+ <B
+CLASS="COMMAND"
+>smbd(8)</B
+>. As a consequence in order for this to
+ succeed the smbd daemon must be running on the local machine. On a
+ UNIX machine the encrypted SMB passwords are usually stored in
+ the <TT
+CLASS="FILENAME"
+>smbpasswd(5)</TT
+> file. </P
+><P
+>When run by an ordinary user with no options. smbpasswd
+ will prompt them for their old SMB password and then ask them
+ for their new password twice, to ensure that the new password
+ was typed correctly. No passwords will be echoed on the screen
+ whilst being typed. If you have a blank SMB password (specified by
+ the string "NO PASSWORD" in the smbpasswd file) then just press
+ the &#60;Enter&#62; key when asked for your old password. </P
+><P
+>smbpasswd can also be used by a normal user to change their
+ SMB password on remote machines, such as Windows NT Primary Domain
+ Controllers. See the (-r) and -U options below. </P
+><P
+>When run by root, smbpasswd allows new users to be added
+ and deleted in the smbpasswd file, as well as allows changes to
+ the attributes of the user in this file to be made. When run by root,
+ <B
+CLASS="COMMAND"
+>smbpasswd</B
+> accesses the local smbpasswd file
+ directly, thus enabling changes to be made even if smbd is not
+ running. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN42"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-a</DT
+><DD
+><P
+>This option specifies that the username
+ following should be added to the local smbpasswd file, with the
+ new password typed (type &#60;Enter&#62; for the old password). This
+ option is ignored if the username following already exists in
+ the smbpasswd file and it is treated like a regular change
+ password command. Note that the user to be added must already exist
+ in the system password file (usually <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>)
+ else the request to add the user will fail. </P
+><P
+>This option is only available when running smbpasswd
+ as root. </P
+></DD
+><DT
+>-x</DT
+><DD
+><P
+>This option specifies that the username
+ following should be deleted from the local smbpasswd file.
+ </P
+><P
+>This option is only available when running smbpasswd as
+ root.</P
+></DD
+><DT
+>-d</DT
+><DD
+><P
+>This option specifies that the username following
+ should be <TT
+CLASS="CONSTANT"
+>disabled</TT
+> in the local smbpasswd
+ file. This is done by writing a <TT
+CLASS="CONSTANT"
+>'D'</TT
+> flag
+ into the account control space in the smbpasswd file. Once this
+ is done all attempts to authenticate via SMB using this username
+ will fail. </P
+><P
+>If the smbpasswd file is in the 'old' format (pre-Samba 2.0
+ format) there is no space in the user's password entry to write
+ this information and so the user is disabled by writing 'X' characters
+ into the password space in the smbpasswd file. See <B
+CLASS="COMMAND"
+>smbpasswd(5)
+ </B
+> for details on the 'old' and new password file formats.
+ </P
+><P
+>This option is only available when running smbpasswd as
+ root.</P
+></DD
+><DT
+>-e</DT
+><DD
+><P
+>This option specifies that the username following
+ should be <TT
+CLASS="CONSTANT"
+>enabled</TT
+> in the local smbpasswd file,
+ if the account was previously disabled. If the account was not
+ disabled this option has no effect. Once the account is enabled then
+ the user will be able to authenticate via SMB once again. </P
+><P
+>If the smbpasswd file is in the 'old' format, then <B
+CLASS="COMMAND"
+> smbpasswd</B
+> will prompt for a new password for this user,
+ otherwise the account will be enabled by removing the <TT
+CLASS="CONSTANT"
+>'D'
+ </TT
+> flag from account control space in the <TT
+CLASS="FILENAME"
+> smbpasswd</TT
+> file. See <B
+CLASS="COMMAND"
+>smbpasswd (5)</B
+> for
+ details on the 'old' and new password file formats. </P
+><P
+>This option is only available when running smbpasswd as root.
+ </P
+></DD
+><DT
+>-D debuglevel</DT
+><DD
+><P
+><TT
+CLASS="REPLACEABLE"
+><I
+>debuglevel</I
+></TT
+> is an integer
+ from 0 to 10. The default value if this parameter is not specified
+ is zero. </P
+><P
+>The higher this value, the more detail will be logged to the
+ log files about the activities of smbpasswd. At level 0, only
+ critical errors and serious warnings will be logged. </P
+><P
+>Levels above 1 will generate considerable amounts of log
+ data, and should only be used when investigating a problem. Levels
+ above 3 are designed for use only by developers and generate
+ HUGE amounts of log data, most of which is extremely cryptic.
+ </P
+></DD
+><DT
+>-n</DT
+><DD
+><P
+>This option specifies that the username following
+ should have their password set to null (i.e. a blank password) in
+ the local smbpasswd file. This is done by writing the string "NO
+ PASSWORD" as the first part of the first password stored in the
+ smbpasswd file. </P
+><P
+>Note that to allow users to logon to a Samba server once
+ the password has been set to "NO PASSWORD" in the smbpasswd
+ file the administrator must set the following parameter in the [global]
+ section of the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file : </P
+><P
+><B
+CLASS="COMMAND"
+>null passwords = yes</B
+></P
+><P
+>This option is only available when running smbpasswd as
+ root.</P
+></DD
+><DT
+>-r remote machine name</DT
+><DD
+><P
+>This option allows a user to specify what machine
+ they wish to change their password on. Without this parameter
+ smbpasswd defaults to the local host. The <TT
+CLASS="REPLACEABLE"
+><I
+>remote
+ machine name</I
+></TT
+> is the NetBIOS name of the SMB/CIFS
+ server to contact to attempt the password change. This name is
+ resolved into an IP address using the standard name resolution
+ mechanism in all programs of the Samba suite. See the <TT
+CLASS="PARAMETER"
+><I
+>-R
+ name resolve order</I
+></TT
+> parameter for details on changing
+ this resolving mechanism. </P
+><P
+>The username whose password is changed is that of the
+ current UNIX logged on user. See the <TT
+CLASS="PARAMETER"
+><I
+>-U username</I
+></TT
+>
+ parameter for details on changing the password for a different
+ username. </P
+><P
+>Note that if changing a Windows NT Domain password the
+ remote machine specified must be the Primary Domain Controller for
+ the domain (Backup Domain Controllers only have a read-only
+ copy of the user account database and will not allow the password
+ change).</P
+><P
+><EM
+>Note</EM
+> that Windows 95/98 do not have
+ a real password database so it is not possible to change passwords
+ specifying a Win95/98 machine as remote machine target. </P
+></DD
+><DT
+>-R name resolve order</DT
+><DD
+><P
+>This option allows the user of smbpasswd to determine
+ what name resolution services to use when looking up the NetBIOS
+ name of the host being connected to. </P
+><P
+>The options are :"lmhosts", "host", "wins" and "bcast". They cause
+ names to be resolved as follows : </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>lmhosts</TT
+> : Lookup an IP
+ address in the Samba lmhosts file. If the line in lmhosts has
+ no name type attached to the NetBIOS name (see the <A
+HREF="lmhosts.5.html"
+TARGET="_top"
+>lmhosts(5)</A
+> for details) then
+ any name type matches for lookup.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>host</TT
+> : Do a standard host
+ name to IP address resolution, using the system <TT
+CLASS="FILENAME"
+>/etc/hosts
+ </TT
+>, NIS, or DNS lookups. This method of name resolution
+ is operating system depended for instance on IRIX or Solaris this
+ may be controlled by the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>
+ file). Note that this method is only used if the NetBIOS name
+ type being queried is the 0x20 (server) name type, otherwise
+ it is ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>wins</TT
+> : Query a name with
+ the IP address listed in the <TT
+CLASS="PARAMETER"
+><I
+>wins server</I
+></TT
+>
+ parameter. If no WINS server has been specified this method
+ will be ignored.</P
+></LI
+><LI
+><P
+><TT
+CLASS="CONSTANT"
+>bcast</TT
+> : Do a broadcast on
+ each of the known local interfaces listed in the
+ <TT
+CLASS="PARAMETER"
+><I
+>interfaces</I
+></TT
+> parameter. This is the least
+ reliable of the name resolution methods as it depends on the
+ target host being on a locally connected subnet.</P
+></LI
+></UL
+><P
+>The default order is <B
+CLASS="COMMAND"
+>lmhosts, host, wins, bcast</B
+>
+ and without this parameter or any entry in the
+ <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file the name resolution methods will
+ be attempted in this order. </P
+></DD
+><DT
+>-m</DT
+><DD
+><P
+>This option tells smbpasswd that the account
+ being changed is a MACHINE account. Currently this is used
+ when Samba is being used as an NT Primary Domain Controller.</P
+><P
+>This option is only available when running smbpasswd as root.
+ </P
+></DD
+><DT
+>-j DOMAIN</DT
+><DD
+><P
+>This option is used to add a Samba server
+ into a Windows NT Domain, as a Domain member capable of authenticating
+ user accounts to any Domain Controller in the same way as a Windows
+ NT Server. See the <B
+CLASS="COMMAND"
+>security = domain</B
+> option in
+ the <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+> man page. </P
+><P
+>In order to be used in this way, the Administrator for
+ the Windows NT Domain must have used the program "Server Manager
+ for Domains" to add the primary NetBIOS name of the Samba server
+ as a member of the Domain. </P
+><P
+>After this has been done, to join the Domain invoke <B
+CLASS="COMMAND"
+> smbpasswd</B
+> with this parameter. smbpasswd will then
+ look up the Primary Domain Controller for the Domain (found in
+ the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file in the parameter
+ <TT
+CLASS="PARAMETER"
+><I
+>password server</I
+></TT
+> and change the machine account
+ password used to create the secure Domain communication. This
+ password is then stored by smbpasswd in a TDB, writeable only by root,
+ called <TT
+CLASS="FILENAME"
+>secrets.tdb</TT
+> </P
+><P
+>Once this operation has been performed the <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> file may be updated to set the <B
+CLASS="COMMAND"
+> security = domain</B
+> option and all future logins
+ to the Samba server will be authenticated to the Windows NT
+ PDC. </P
+><P
+>Note that even though the authentication is being
+ done to the PDC all users accessing the Samba server must still
+ have a valid UNIX account on that machine. </P
+><P
+>This option is only available when running smbpasswd as root.
+ </P
+></DD
+><DT
+>-U username</DT
+><DD
+><P
+>This option may only be used in conjunction
+ with the <TT
+CLASS="PARAMETER"
+><I
+>-r</I
+></TT
+> option. When changing
+ a password on a remote machine it allows the user to specify
+ the user name on that machine whose password will be changed. It
+ is present to allow users who have different user names on
+ different systems to change these passwords. </P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>This option prints the help string for <B
+CLASS="COMMAND"
+> smbpasswd</B
+>, selecting the correct one for running as root
+ or as an ordinary user. </P
+></DD
+><DT
+>-s</DT
+><DD
+><P
+>This option causes smbpasswd to be silent (i.e.
+ not issue prompts) and to read its old and new passwords from
+ standard input, rather than from <TT
+CLASS="FILENAME"
+>/dev/tty</TT
+>
+ (like the <B
+CLASS="COMMAND"
+>passwd(1)</B
+> program does). This option
+ is to aid people writing scripts to drive smbpasswd</P
+></DD
+><DT
+>-w password</DT
+><DD
+><P
+>This parameter is only available is Samba
+ has been configured to use the experiemental
+ <B
+CLASS="COMMAND"
+>--with-ldapsam</B
+> option. The <TT
+CLASS="PARAMETER"
+><I
+>-w</I
+></TT
+>
+ switch is used to specify the password to be used with the
+ <A
+HREF="smb.conf.5.html#LDAPADMINDN"
+TARGET="_top"
+><TT
+CLASS="PARAMETER"
+><I
+>ldap admin
+ dn</I
+></TT
+></A
+>. Note that the password is stored in
+ the <TT
+CLASS="FILENAME"
+>private/secrets.tdb</TT
+> and is keyed off
+ of the admin's DN. This means that if the value of <TT
+CLASS="PARAMETER"
+><I
+>ldap
+ admin dn</I
+></TT
+> ever changes, the password will beed to be
+ manually updated as well.
+ </P
+></DD
+><DT
+>username</DT
+><DD
+><P
+>This specifies the username for all of the
+ <EM
+>root only</EM
+> options to operate on. Only root
+ can specify this parameter as only root has the permission needed
+ to modify attributes directly in the local smbpasswd file.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN182"
+></A
+><H2
+>NOTES</H2
+><P
+>Since <B
+CLASS="COMMAND"
+>smbpasswd</B
+> works in client-server
+ mode communicating with a local smbd for a non-root user then
+ the smbd daemon must be running for this to work. A common problem
+ is to add a restriction to the hosts that may access the <B
+CLASS="COMMAND"
+> smbd</B
+> running on the local machine by specifying a
+ <TT
+CLASS="PARAMETER"
+><I
+>allow hosts</I
+></TT
+> or <TT
+CLASS="PARAMETER"
+><I
+>deny hosts</I
+></TT
+>
+ entry in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file and neglecting to
+ allow "localhost" access to the smbd. </P
+><P
+>In addition, the smbpasswd command is only useful if Samba
+ has been set up to use encrypted passwords. See the file
+ <TT
+CLASS="FILENAME"
+>ENCRYPTION.txt</TT
+> in the docs directory for details
+ on how to do this. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN192"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN195"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbpasswd.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smbpasswd(5)</TT
+></A
+>,
+ <A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN201"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbsh.1.html b/docs/htmldocs/smbsh.1.html
new file mode 100644
index 00000000000..66081bbe22c
--- /dev/null
+++ b/docs/htmldocs/smbsh.1.html
@@ -0,0 +1,251 @@
+<HTML
+><HEAD
+><TITLE
+>smbsh</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBSH"
+>smbsh</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbsh&nbsp;--&nbsp;Allows access to Windows NT filesystem
+ using UNIX commands</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbsh</B
+> </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN11"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbsh</B
+> allows you to access an NT filesystem
+ using UNIX commands such as <B
+CLASS="COMMAND"
+>ls</B
+>, <B
+CLASS="COMMAND"
+> egrep</B
+>, and <B
+CLASS="COMMAND"
+>rcp</B
+>. You must use a
+ shell that is dynamically linked in order for <B
+CLASS="COMMAND"
+>smbsh</B
+>
+ to work correctly.</P
+><P
+>To use the <B
+CLASS="COMMAND"
+>smbsh</B
+> command, execute <B
+CLASS="COMMAND"
+> smbsh</B
+> from the prompt and enter the username and password
+ that authenticates you to the machine running the Windows NT
+ operating system.</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> <TT
+CLASS="PROMPT"
+>system% </TT
+><TT
+CLASS="USERINPUT"
+><B
+>smbsh</B
+></TT
+>
+ <TT
+CLASS="PROMPT"
+>Username: </TT
+><TT
+CLASS="USERINPUT"
+><B
+>user</B
+></TT
+>
+ <TT
+CLASS="PROMPT"
+>Password: </TT
+><TT
+CLASS="USERINPUT"
+><B
+>XXXXXXX</B
+></TT
+>
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Any dynamically linked command you execute from
+ this shell will access the <TT
+CLASS="FILENAME"
+>/smb</TT
+> directory
+ using the smb protocol. For example, the command <B
+CLASS="COMMAND"
+>ls /smb
+ </B
+> will show a list of workgroups. The command
+ <B
+CLASS="COMMAND"
+>ls /smb/MYGROUP </B
+> will show all the machines in
+ the workgroup MYGROUP. The command
+ <B
+CLASS="COMMAND"
+>ls /smb/MYGROUP/&#60;machine-name&#62;</B
+> will show the share
+ names for that machine. You could then, for example, use the <B
+CLASS="COMMAND"
+> cd</B
+> command to change directories, <B
+CLASS="COMMAND"
+>vi</B
+> to
+ edit files, and <B
+CLASS="COMMAND"
+>rcp</B
+> to copy files.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN43"
+></A
+><H2
+>BUGS</H2
+><P
+><B
+CLASS="COMMAND"
+>smbsh</B
+> works by intercepting the standard
+ libc calls with the dynamically loaded versions in <TT
+CLASS="FILENAME"
+> smbwrapper.o</TT
+>. Not all calls have been "wrapped", so
+ some programs may not function correctly under <B
+CLASS="COMMAND"
+>smbsh
+ </B
+>.</P
+><P
+>Programs which are not dynamically linked cannot make
+ use of <B
+CLASS="COMMAND"
+>smbsh</B
+>'s functionality. Most versions
+ of UNIX have a <B
+CLASS="COMMAND"
+>file</B
+> command that will
+ describe how a program was linked.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN52"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN58"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbspool.8.html b/docs/htmldocs/smbspool.8.html
new file mode 100644
index 00000000000..254abe9a9de
--- /dev/null
+++ b/docs/htmldocs/smbspool.8.html
@@ -0,0 +1,222 @@
+<HTML
+><HEAD
+><TITLE
+>smbspool</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBSPOOL"
+>smbspool</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbspool&nbsp;--&nbsp;send print file to an SMB printer</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbspool</B
+> [job] [user] [title] [copies] [options] [filename]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN17"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+>smbspool is a very small print spooling program that
+ sends a print file to an SMB printer. The command-line arguments
+ are position-dependent for compatibility with the Common UNIX
+ Printing System, but you can use smbspool with any printing system
+ or from a program or script.</P
+><P
+><EM
+>DEVICE URI</EM
+></P
+><P
+>smbspool specifies the destination using a Uniform Resource
+ Identifier ("URI") with a method of "smb". This string can take
+ a number of forms:</P
+><P
+></P
+><UL
+><LI
+><P
+>smb://server/printer</P
+></LI
+><LI
+><P
+>smb://workgroup/server/printer</P
+></LI
+><LI
+><P
+>smb://username:password@server/printer</P
+></LI
+><LI
+><P
+>smb://username:password@workgroup/server/printer
+ </P
+></LI
+></UL
+><P
+>smbspool tries to get the URI from argv[0]. If argv[0]
+ contains the name of the program then it looks in the <TT
+CLASS="ENVAR"
+> DEVICE_URI</TT
+> environment variable.</P
+><P
+>Programs using the <B
+CLASS="COMMAND"
+>exec(2)</B
+> functions can
+ pass the URI in argv[0], while shell scripts must set the
+ <TT
+CLASS="ENVAR"
+>DEVICE_URI</TT
+> environment variable prior to
+ running smbspool.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN39"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><UL
+><LI
+><P
+>The job argument (argv[1]) contains the
+ job ID number and is presently not used by smbspool.
+ </P
+></LI
+><LI
+><P
+>The user argument (argv[2]) contains the
+ print user's name and is presently not used by smbspool.
+ </P
+></LI
+><LI
+><P
+>The title argument (argv[3]) contains the
+ job title string and is passed as the remote file name
+ when sending the print job.</P
+></LI
+><LI
+><P
+>The copies argument (argv[4]) contains
+ the number of copies to be printed of the named file. If
+ no filename is provided than this argument is not used by
+ smbspool.</P
+></LI
+><LI
+><P
+>The options argument (argv[5]) contains
+ the print options in a single string and is presently
+ not used by smbspool.</P
+></LI
+><LI
+><P
+>The filename argument (argv[6]) contains the
+ name of the file to print. If this argument is not specified
+ then the print file is read from the standard input.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN54"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ and <A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN63"
+></A
+><H2
+>AUTHOR</H2
+><P
+><B
+CLASS="COMMAND"
+>smbspool</B
+> was written by Michael Sweet
+ at Easy Software Products.</P
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbstatus.1.html b/docs/htmldocs/smbstatus.1.html
new file mode 100644
index 00000000000..1d3dc9f952a
--- /dev/null
+++ b/docs/htmldocs/smbstatus.1.html
@@ -0,0 +1,209 @@
+<HTML
+><HEAD
+><TITLE
+>smbstatus</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBSTATUS"
+>smbstatus</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbstatus&nbsp;--&nbsp;report on current Samba connections</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbstatus</B
+> [-P] [-b] [-d] [-L] [-p] [-S] [-s &#60;configuration file&#62;] [-u &#60;username&#62;]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN19"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbstatus</B
+> is a very simple program to
+ list the current Samba connections.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN25"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-P</DT
+><DD
+><P
+>If samba has been compiled with the
+ profiling option, print only the contents of the profiling
+ shared memory area.</P
+></DD
+><DT
+>-b</DT
+><DD
+><P
+>gives brief output.</P
+></DD
+><DT
+>-d</DT
+><DD
+><P
+>gives verbose output.</P
+></DD
+><DT
+>-L</DT
+><DD
+><P
+>causes smbstatus to only list locks.</P
+></DD
+><DT
+>-p</DT
+><DD
+><P
+>print a list of <A
+HREF="smbd.8.html"
+TARGET="_top"
+> <B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> processes and exit.
+ Useful for scripting.</P
+></DD
+><DT
+>-S</DT
+><DD
+><P
+>causes smbstatus to only list shares.</P
+></DD
+><DT
+>-s &#60;configuration file&#62;</DT
+><DD
+><P
+>The default configuration file name is
+ determined at compile time. The file specified contains the
+ configuration details required by the server. See <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ </A
+> for more information.</P
+></DD
+><DT
+>-u &#60;username&#62;</DT
+><DD
+><P
+>selects information relevant to
+ <TT
+CLASS="PARAMETER"
+><I
+>username</I
+></TT
+> only.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN65"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN68"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+> and
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN74"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbtar.1.html b/docs/htmldocs/smbtar.1.html
new file mode 100644
index 00000000000..47c41a015a9
--- /dev/null
+++ b/docs/htmldocs/smbtar.1.html
@@ -0,0 +1,351 @@
+<HTML
+><HEAD
+><TITLE
+>smbtar</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBTAR"
+>smbtar</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbtar&nbsp;--&nbsp;shell script for backing up SMB/CIFS shares
+ directly to UNIX tape drives</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbtar</B
+> {-s server} [-p password] [-x services] [-X] [-d directory] [-u user] [-t tape] [-t tape] [-b blocksize] [-N filename] [-i] [-r] [-l loglevel] [-v] {filenames}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN26"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>smbtar</B
+> is a very small shell script on top
+ of <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>
+ which dumps SMB shares directly to tape. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN34"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-s server</DT
+><DD
+><P
+>The SMB/CIFS server that the share resides
+ upon.</P
+></DD
+><DT
+>-x service</DT
+><DD
+><P
+>The share name on the server to connect to.
+ The default is "backup".</P
+></DD
+><DT
+>-X</DT
+><DD
+><P
+>Exclude mode. Exclude filenames... from tar
+ create or restore. </P
+></DD
+><DT
+>-d directory</DT
+><DD
+><P
+>Change to initial <TT
+CLASS="PARAMETER"
+><I
+>directory
+ </I
+></TT
+> before restoring / backing up files. </P
+></DD
+><DT
+>-v</DT
+><DD
+><P
+>Verbose mode.</P
+></DD
+><DT
+>-p password</DT
+><DD
+><P
+>The password to use to access a share.
+ Default: none </P
+></DD
+><DT
+>-u user</DT
+><DD
+><P
+>The user id to connect as. Default:
+ UNIX login name. </P
+></DD
+><DT
+>-t tape</DT
+><DD
+><P
+>Tape device. May be regular file or tape
+ device. Default: <TT
+CLASS="PARAMETER"
+><I
+>$TAPE</I
+></TT
+> environmental
+ variable; if not set, a file called <TT
+CLASS="FILENAME"
+>tar.out
+ </TT
+>. </P
+></DD
+><DT
+>-b blocksize</DT
+><DD
+><P
+>Blocking factor. Defaults to 20. See
+ <B
+CLASS="COMMAND"
+>tar(1)</B
+> for a fuller explanation. </P
+></DD
+><DT
+>-N filename</DT
+><DD
+><P
+>Backup only files newer than filename. Could
+ be used (for example) on a log file to implement incremental
+ backups. </P
+></DD
+><DT
+>-i</DT
+><DD
+><P
+>Incremental mode; tar files are only backed
+ up if they have the archive bit set. The archive bit is reset
+ after each file is read. </P
+></DD
+><DT
+>-r</DT
+><DD
+><P
+>Restore. Files are restored to the share
+ from the tar file. </P
+></DD
+><DT
+>-l log level</DT
+><DD
+><P
+>Log (debug) level. Corresponds to the
+ <TT
+CLASS="PARAMETER"
+><I
+>-d</I
+></TT
+> flag of <B
+CLASS="COMMAND"
+>smbclient(1)
+ </B
+>. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN95"
+></A
+><H2
+>ENVIRONMENT VARIABLES</H2
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>$TAPE</I
+></TT
+> variable specifies the
+ default tape device to write to. May be overridden
+ with the -t option. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN99"
+></A
+><H2
+>BUGS</H2
+><P
+>The <B
+CLASS="COMMAND"
+>smbtar</B
+> script has different
+ options from ordinary tar and tar called from smbclient. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN103"
+></A
+><H2
+>CAVEATS</H2
+><P
+>Sites that are more careful about security may not like
+ the way the script handles PC passwords. Backup and restore work
+ on entire shares, should work on file lists. smbtar works best
+ with GNU tar and may not work well with other versions. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN106"
+></A
+><H2
+>DIAGNOSTICS</H2
+><P
+>See the <EM
+>DIAGNOSTICS</EM
+> section for the
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+>
+ </A
+> command.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN112"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN115"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>,
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN123"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+><A
+HREF="mailto:poultenr@logica.co.uk"
+TARGET="_top"
+>Ricky Poulten</A
+>
+ wrote the tar extension and this man page. The <B
+CLASS="COMMAND"
+>smbtar</B
+>
+ script was heavily rewritten and improved by <A
+HREF="mailto:Martin.Kraemer@mch.sni.de"
+TARGET="_top"
+>Martin Kraemer</A
+>. Many
+ thanks to everyone who suggested extensions, improvements, bug
+ fixes, etc. The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/smbumount.8.html b/docs/htmldocs/smbumount.8.html
new file mode 100644
index 00000000000..68929fd5f91
--- /dev/null
+++ b/docs/htmldocs/smbumount.8.html
@@ -0,0 +1,140 @@
+<HTML
+><HEAD
+><TITLE
+>smbumount</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SMBUMOUNT"
+>smbumount</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>smbumount&nbsp;--&nbsp;smbfs umount for normal users</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>smbumount</B
+> {mount-point}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN12"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>With this program, normal users can unmount smb-filesystems,
+ provided that it is suid root. <B
+CLASS="COMMAND"
+>smbumount</B
+> has
+ been written to give normal Linux users more control over their
+ resources. It is safe to install this program suid root, because only
+ the user who has mounted a filesystem is allowed to unmount it again.
+ For root it is not necessary to use smbumount. The normal umount
+ program works perfectly well, but it would certainly be problematic
+ to make umount setuid root.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN16"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>mount-point</DT
+><DD
+><P
+>The directory to unmount.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN23"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbmount.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbmount(8)</B
+>
+ </A
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN28"
+></A
+><H2
+>AUTHOR</H2
+><P
+>Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+ and others.</P
+><P
+>The current maintainer of smbfs and the userspace
+ tools <B
+CLASS="COMMAND"
+>smbmount</B
+>, <B
+CLASS="COMMAND"
+>smbumount</B
+>,
+ and <B
+CLASS="COMMAND"
+>smbmnt</B
+> is <A
+HREF="mailto:urban@teststation.com"
+TARGET="_top"
+>Urban Widmark</A
+>.
+ The <A
+HREF="mailto:samba@samba.org"
+TARGET="_top"
+>SAMBA Mailing list</A
+>
+ is the preferred place to ask questions regarding these programs.
+ </P
+><P
+>The conversion of this manpage for Samba 2.2 was performed
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/swat.8.html b/docs/htmldocs/swat.8.html
new file mode 100644
index 00000000000..386fe5bc7af
--- /dev/null
+++ b/docs/htmldocs/swat.8.html
@@ -0,0 +1,420 @@
+<HTML
+><HEAD
+><TITLE
+>swat</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="SWAT"
+>swat</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>swat&nbsp;--&nbsp;Samba Web Administration Tool</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>swat</B
+> [-s &#60;smb config file&#62;] [-a]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN13"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>swat</B
+> allows a Samba administrator to
+ configure the complex <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+> smb.conf(5)</TT
+></A
+> file via a Web browser. In addition,
+ a <B
+CLASS="COMMAND"
+>swat</B
+> configuration page has help links
+ to all the configurable options in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file allowing an
+ administrator to easily look up the effects of any change. </P
+><P
+><B
+CLASS="COMMAND"
+>swat</B
+> is run from <B
+CLASS="COMMAND"
+>inetd</B
+> </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN26"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-s smb configuration file</DT
+><DD
+><P
+>The default configuration file path is
+ determined at compile time. The file specified contains
+ the configuration details required by the <B
+CLASS="COMMAND"
+>smbd
+ </B
+> server. This is the file that <B
+CLASS="COMMAND"
+>swat</B
+> will modify.
+ The information in this file includes server-specific
+ information such as what printcap file to use, as well as
+ descriptions of all the services that the server is to provide.
+ See <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> for more information.
+ </P
+></DD
+><DT
+>-a</DT
+><DD
+><P
+>This option disables authentication and puts
+ <B
+CLASS="COMMAND"
+>swat</B
+> in demo mode. In that mode anyone will be able to modify
+ the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file. </P
+><P
+><EM
+>Do NOT enable this option on a production
+ server. </EM
+></P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN44"
+></A
+><H2
+>INSTALLATION</H2
+><P
+>After you compile SWAT you need to run <B
+CLASS="COMMAND"
+>make install
+ </B
+> to install the <B
+CLASS="COMMAND"
+>swat</B
+> binary
+ and the various help files and images. A default install would put
+ these in: </P
+><P
+></P
+><UL
+><LI
+><P
+>/usr/local/samba/bin/swat</P
+></LI
+><LI
+><P
+>/usr/local/samba/swat/images/*</P
+></LI
+><LI
+><P
+>/usr/local/samba/swat/help/*</P
+></LI
+></UL
+><DIV
+CLASS="REFSECT2"
+><A
+NAME="AEN56"
+></A
+><H3
+>Inetd Installation</H3
+><P
+>You need to edit your <TT
+CLASS="FILENAME"
+>/etc/inetd.conf
+ </TT
+> and <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>
+ to enable SWAT to be launched via <B
+CLASS="COMMAND"
+>inetd</B
+>.</P
+><P
+>In <TT
+CLASS="FILENAME"
+>/etc/services</TT
+> you need to
+ add a line like this: </P
+><P
+><B
+CLASS="COMMAND"
+>swat 901/tcp</B
+></P
+><P
+>Note for NIS/YP users - you may need to rebuild the
+ NIS service maps rather than alter your local <TT
+CLASS="FILENAME"
+> /etc/services</TT
+> file. </P
+><P
+>the choice of port number isn't really important
+ except that it should be less than 1024 and not currently
+ used (using a number above 1024 presents an obscure security
+ hole depending on the implementation details of your
+ <B
+CLASS="COMMAND"
+>inetd</B
+> daemon). </P
+><P
+>In <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+> you should
+ add a line like this: </P
+><P
+><B
+CLASS="COMMAND"
+>swat stream tcp nowait.400 root
+ /usr/local/samba/bin/swat swat</B
+></P
+><P
+>One you have edited <TT
+CLASS="FILENAME"
+>/etc/services</TT
+>
+ and <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+> you need to send a
+ HUP signal to inetd. To do this use <B
+CLASS="COMMAND"
+>kill -1 PID
+ </B
+> where PID is the process ID of the inetd daemon. </P
+></DIV
+><DIV
+CLASS="REFSECT2"
+><A
+NAME="AEN78"
+></A
+><H3
+>Launching</H3
+><P
+>To launch SWAT just run your favorite web browser and
+ point it at "http://localhost:901/".</P
+><P
+>Note that you can attach to SWAT from any IP connected
+ machine but connecting from a remote machine leaves your
+ connection open to password sniffing as passwords will be sent
+ in the clear over the wire. </P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN82"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+></DT
+><DD
+><P
+>This file must contain suitable startup
+ information for the meta-daemon.</P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/services</TT
+></DT
+><DD
+><P
+>This file must contain a mapping of service name
+ (e.g., swat) to service port (e.g., 901) and protocol type
+ (e.g., tcp). </P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>/usr/local/samba/lib/smb.conf</TT
+></DT
+><DD
+><P
+>This is the default location of the <TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+> server configuration file that swat edits. Other
+ common places that systems install this file are <TT
+CLASS="FILENAME"
+> /usr/samba/lib/smb.conf</TT
+> and <TT
+CLASS="FILENAME"
+>/etc/smb.conf
+ </TT
+>. This file describes all the services the server
+ is to make available to clients. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN103"
+></A
+><H2
+>WARNINGS</H2
+><P
+><B
+CLASS="COMMAND"
+>swat</B
+> will rewrite your <TT
+CLASS="FILENAME"
+>smb.conf
+ </TT
+> file. It will rearrange the entries and delete all
+ comments, <TT
+CLASS="PARAMETER"
+><I
+>include=</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>copy="
+ </I
+></TT
+> options. If you have a carefully crafted <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> then back it up or don't use swat! </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN111"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN114"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><B
+CLASS="COMMAND"
+>inetd(5)</B
+>,
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN121"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/testparm.1.html b/docs/htmldocs/testparm.1.html
new file mode 100644
index 00000000000..bae907c687a
--- /dev/null
+++ b/docs/htmldocs/testparm.1.html
@@ -0,0 +1,298 @@
+<HTML
+><HEAD
+><TITLE
+>testparm</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="TESTPARM"
+>testparm</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>testparm&nbsp;--&nbsp;check an smb.conf configuration file for
+ internal correctness</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>testparm</B
+> [-s] [-h] [-L &#60;servername&#62;] {config filename} [hostname hostIP]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN16"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>testparm</B
+> is a very simple test program
+ to check an <B
+CLASS="COMMAND"
+>smbd</B
+> configuration file for
+ internal correctness. If this program reports no problems, you
+ can use the configuration file with confidence that <B
+CLASS="COMMAND"
+>smbd
+ </B
+> will successfully load the configuration file.</P
+><P
+>Note that this is <EM
+>NOT</EM
+> a guarantee that
+ the services specified in the configuration file will be
+ available or will operate as expected. </P
+><P
+>If the optional host name and host IP address are
+ specified on the command line, this test program will run through
+ the service entries reporting whether the specified host
+ has access to each service. </P
+><P
+>If <B
+CLASS="COMMAND"
+>testparm</B
+> finds an error in the <TT
+CLASS="FILENAME"
+> smb.conf</TT
+> file it returns an exit code of 1 to the calling
+ program, else it returns an exit code of 0. This allows shell scripts
+ to test the output from <B
+CLASS="COMMAND"
+>testparm</B
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN31"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-s</DT
+><DD
+><P
+>Without this option, <B
+CLASS="COMMAND"
+>testparm</B
+>
+ will prompt for a carriage return after printing the service
+ names and before dumping the service definitions.</P
+></DD
+><DT
+>-h</DT
+><DD
+><P
+>Print usage message </P
+></DD
+><DT
+>-L servername</DT
+><DD
+><P
+>Sets the value of the %L macro to <TT
+CLASS="REPLACEABLE"
+><I
+>servername</I
+></TT
+>.
+ This is useful for testing include files specified with the
+ %L macro. </P
+></DD
+><DT
+>configfilename</DT
+><DD
+><P
+>This is the name of the configuration file
+ to check. If this parameter is not present then the
+ default <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file will be checked.
+ </P
+></DD
+><DT
+>hostname</DT
+><DD
+><P
+>If this parameter and the following are
+ specified, then <B
+CLASS="COMMAND"
+>testparm</B
+> will examine the <TT
+CLASS="PARAMETER"
+><I
+>hosts
+ allow</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>hosts deny</I
+></TT
+>
+ parameters in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file to
+ determine if the hostname with this IP address would be
+ allowed access to the <B
+CLASS="COMMAND"
+>smbd</B
+> server. If
+ this parameter is supplied, the hostIP parameter must also
+ be supplied.</P
+></DD
+><DT
+>hostIP</DT
+><DD
+><P
+>This is the IP address of the host specified
+ in the previous parameter. This address must be supplied
+ if the hostname parameter is supplied. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN66"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>smb.conf</TT
+></DT
+><DD
+><P
+>This is usually the name of the configuration
+ file used by <B
+CLASS="COMMAND"
+>smbd</B
+>.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN75"
+></A
+><H2
+>DIAGNOSTICS</H2
+><P
+>The program will issue a message saying whether the
+ configuration file loaded OK or not. This message may be preceded by
+ errors and warnings if the file did not load. If the file was
+ loaded OK, the program then dumps all known service details
+ to stdout. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN78"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN81"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smb.conf.5.html"
+TARGET="_top"
+><TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+></A
+>,
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN88"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/testprns.1.html b/docs/htmldocs/testprns.1.html
new file mode 100644
index 00000000000..4929415da02
--- /dev/null
+++ b/docs/htmldocs/testprns.1.html
@@ -0,0 +1,252 @@
+<HTML
+><HEAD
+><TITLE
+>testprns</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="TESTPRNS"
+>testprns</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>testprns&nbsp;--&nbsp;check printer name for validity with smbd</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>testprns</B
+> {printername} [printcapname]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN13"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>testprns</B
+> is a very simple test program
+ to determine whether a given printer name is valid for use in
+ a service to be provided by <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> smbd(8)</B
+></A
+>. </P
+><P
+>"Valid" in this context means "can be found in the
+ printcap specified". This program is very stupid - so stupid in
+ fact that it would be wisest to always specify the printcap file
+ to use. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN22"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>printername</DT
+><DD
+><P
+>The printer name to validate.</P
+><P
+>Printer names are taken from the first field in each
+ record in the printcap file, single printer names and sets
+ of aliases separated by vertical bars ("|") are recognized.
+ Note that no validation or checking of the printcap syntax is
+ done beyond that required to extract the printer name. It may
+ be that the print spooling system is more forgiving or less
+ forgiving than <B
+CLASS="COMMAND"
+>testprns</B
+>. However, if
+ <B
+CLASS="COMMAND"
+>testprns</B
+> finds the printer then
+ <B
+CLASS="COMMAND"
+>smbd</B
+> should do so as well. </P
+></DD
+><DT
+>printcapname</DT
+><DD
+><P
+>This is the name of the printcap file within
+ which to search for the given printer name. </P
+><P
+>If no printcap name is specified <B
+CLASS="COMMAND"
+>testprns
+ </B
+> will attempt to scan the printcap file name
+ specified at compile time. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN39"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/printcap</TT
+></DT
+><DD
+><P
+>This is usually the default printcap
+ file to scan. See <TT
+CLASS="FILENAME"
+>printcap (5)</TT
+>.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN48"
+></A
+><H2
+>DIAGNOSTICS</H2
+><P
+>If a printer is found to be valid, the message
+ "Printer name &#60;printername&#62; is valid" will be
+ displayed. </P
+><P
+>If a printer is found to be invalid, the message
+ "Printer name &#60;printername&#62; is not valid" will be
+ displayed. </P
+><P
+>All messages that would normally be logged during
+ operation of the Samba daemons are logged by this program to the
+ file <TT
+CLASS="FILENAME"
+>test.log</TT
+> in the current directory. The
+ program runs at debuglevel 3, so quite extensive logging
+ information is written. The log should be checked carefully
+ for errors and warnings. </P
+><P
+>Other messages are self-explanatory. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN55"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN58"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><TT
+CLASS="FILENAME"
+>printcap(5)</TT
+>,
+ <A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smbclient.1.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbclient(1)</B
+></A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN66"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/using_samba/appa_01.html b/docs/htmldocs/using_samba/appa_01.html
new file mode 100644
index 00000000000..30080dffbf6
--- /dev/null
+++ b/docs/htmldocs/using_samba/appa_01.html
@@ -0,0 +1,153 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix A] Configuring Samba with SSL</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:36Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_03.html" TITLE="9.3 Extra Resources">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.3 Extra Resources" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix A</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_02.html" TITLE="A.2 Requirements">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.2 Requirements" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="appendix">
+<A CLASS="title" NAME="appa-73322">
+A. Configuring Samba with SSL</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#appa-pgfId-986440" TITLE="A.1 About Certificates">
+About Certificates</a><br>
+<A CLASS="sect1" HREF="appa_02.html" TITLE="A.2 Requirements">
+Requirements</a><br>
+<A CLASS="sect1" HREF="appa_03.html" TITLE="A.3 Installing SSLeay">
+Installing SSLeay</a><br>
+<A CLASS="sect1" HREF="appa_04.html" TITLE="A.4 Setting Up SSL Proxy">
+Setting Up SSL Proxy</a><br>
+<A CLASS="sect1" HREF="appa_05.html" TITLE="A.5 SSL Configuration Options">
+SSL Configuration Options</a></p><P>
+</p></div><P CLASS="para">This appendix describes how to set up Samba to use secure connections between the Samba server and its clients. The protocol used here is Netscape's Secure Sockets Layer (SSL). For this example, we will establish a secure connection between a Samba server and a Windows NT workstation. </p><P CLASS="para">
+Before we begin, we will assume that you are familiar with the fundamentals of public-key cryptography and X.509 certificates. If not, we highly recommend Bruce Schneier's <I CLASS="filename">
+Applied Cryptography, 2nd Edition</i> (Wiley) as the premiere source for learning the many secret faces of cryptography.</p><P CLASS="para">
+If you would like more information on Samba and SSL, be sure to look at the document <I CLASS="filename">
+SSLeay.txt</i> in the <I CLASS="filename">
+docs/textdocs</i> directory of the Samba distribution, which is the basis for this appendix.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appa-pgfId-986440">
+A.1 About Certificates</a></h2><P CLASS="para">
+Here are a few quick questions and answers from the <I CLASS="filename">
+SSLeay.txt</i> file in the Samba documentation, regarding the benefits of SSL and certificates. This text was written by Christian Starkjohann for the Samba projects. </p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-990471">
+A.1.1 What is a Certificate?</a></h3><P CLASS="para">
+A certifcate is issued by an issuer, usually a <EM CLASS="emphasis">
+Certification Authority</em> (CA), who confirms something by issuing the certificate. The subject of this confirmation depends on the CA's policy. CAs for secure web servers (used for shopping malls, etc.) usually attest only that the given public key belongs the given domain name. Company-wide CAs might attest that you are an employee of the company, that you have permissions to use a server, and so on. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-990473">
+A.1.2 What is an X.509 certificate, technically?</a></h3><P CLASS="para">
+Technically, the certificate is a block of data signed by the certificate issuer (the CA). The relevant fields are:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990475">
+</a>Unique identifier (name) of the certificate issuer</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990476">
+</a>Time range during which the certificate is valid</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990477">
+</a>Unique identifier (name) of the certified object</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990478">
+</a>Public key of the certified object</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990479">
+</a>The issuer's signature over all the above</p></li></ul><P CLASS="para">
+If this certificate is to be verified, the verifier must have a table of the names and public keys of trusted CAs. For simplicity, these tables should list certificates issued by the respective CAs for themselves (self-signed certificates).</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-990481">
+A.1.3 What are the implications of this certificate structure?</a></h3><P CLASS="para">
+Four implications follow:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990485">
+</a>Because the certificate contains the subjects's public key, the certificate and the private key together are all that is needed to encrypt and decrypt.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990489">
+</a>To verify certificates, you need the certificates of all CAs you trust. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990490">
+</a>The simplest form of a dummy-certificate is one that is signed by the subject.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-990491">
+</a>A CA is needed. The client can't simply issue local certificates for servers it trusts because the server determines which certificate it presents. </p></li></ul></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_03.html" TITLE="9.3 Extra Resources">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.3 Extra Resources" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_02.html" TITLE="A.2 Requirements">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.2 Requirements" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+9.3 Extra Resources</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+A.2 Requirements</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appa_02.html b/docs/htmldocs/using_samba/appa_02.html
new file mode 100644
index 00000000000..e69b2fd9128
--- /dev/null
+++ b/docs/htmldocs/using_samba/appa_02.html
@@ -0,0 +1,100 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix A] A.2 Requirements</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:37Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_01.html" TITLE="A.1 About Certificates">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.1 About Certificates" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+Appendix A<br>
+Configuring Samba with SSL</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_03.html" TITLE="A.3 Installing SSLeay">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.3 Installing SSLeay" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appa-pgfId-990469">
+A.2 Requirements</a></h2><P CLASS="para">To set up SSL connections, you will need to download two programs in addition to Samba:</p><DL CLASS="variablelist">
+<DT CLASS="term">SSLeay</dt><DD CLASS="listitem">
+<P CLASS="para">
+Eric Young's implementation of the Secure Socket's Layer (SSL) protocol as a series of Unix programming libraries</p></dd><DT CLASS="term">SSL Proxy</dt><DD CLASS="listitem">
+<P CLASS="para">
+A freeware SSL application from Objective Development, which can be used to proxy a secure link on Unix or Windows NT platforms</p></dd></dl><P CLASS="para">
+These two products assist with the server and client side of the encrypted SSL connection. The SSLeay libraries are compiled and installed directly on the Unix system. SSL Proxy, on the other hand, can be downloaded and compiled (or downloaded in binary format) and located on the client side. If you intend to have a Windows NT client or a Samba client on the other end of the SSL connection, you will not require a special setup.</p><P CLASS="para">
+SSL Proxy, however, does not work on Windows 95/98 machines. Therefore, if you want to have a secure connection between a Samba server and Windows 95/98 client, you will need to place either a Unix server or a Windows NT machine on the same subnet with the Windows 9<EM CLASS="emphasis">
+x</em> clients and route all network connections through the SSL-Proxy-enabled machine. See <A CLASS="xref" HREF="appa_02.html#appa-89929">
+Figure A.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="appa-89929">
+Figure A.1: Two possible ways of proxying Windows 95/98 clients</a></h4><IMG CLASS="graphic" SRC="figs/sam.aa01.gif" ALT="Figure A.1"><P CLASS="para">
+For the purposes of this chapter, we will create a simple SSL connection between the Samba server and a Windows NT client. This configuration can be used to set up more complex networks at the administrator's discretion.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_01.html" TITLE="A.1 About Certificates">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.1 About Certificates" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_03.html" TITLE="A.3 Installing SSLeay">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.3 Installing SSLeay" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+A.1 About Certificates</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+A.3 Installing SSLeay</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appa_03.html b/docs/htmldocs/using_samba/appa_03.html
new file mode 100644
index 00000000000..f8cdb139315
--- /dev/null
+++ b/docs/htmldocs/using_samba/appa_03.html
@@ -0,0 +1,325 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix A] A.3 Installing SSLeay</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:37Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_02.html" TITLE="A.2 Requirements">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.2 Requirements" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+Appendix A<br>
+Configuring Samba with SSL</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_04.html" TITLE="A.4 Setting Up SSL Proxy">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.4 Setting Up SSL Proxy" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appa-pgfId-985777">
+A.3 Installing SSLeay</a></h2><P CLASS="para">
+Samba uses the SSLeay package, written by Eric Young, to provide Secure Sockets Layer support on the server side. Because of U.S. export law, however, the SSLeay package cannot be shipped with Samba distributions that are based in the United States. For that reason, the Samba creators decided to leave it as a separate package entirely. You can download the SSLeay distribution from any of the following sites:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-985779">
+</a><A CLASS="systemitem.url" HREF="ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/">
+ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/</a></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-985781">
+</a><A CLASS="systemitem.url" HREF="ftp://ftp.uni-mainz.de/pub/internet/security/ssl">
+ftp://ftp.uni-mainz.de/pub/internet/security/ssl</a></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-985782">
+</a><A CLASS="systemitem.url" HREF="ftp://ftp.cert.dfn.de/pub/tools/crypt/sslapps">
+ftp://ftp.cert.dfn.de/pub/tools/crypt/sslapps</a></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-985783">
+</a><A CLASS="systemitem.url" HREF="ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au">
+ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au</a></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-985784">
+</a><A CLASS="systemitem.url" HREF="ftp://ftp.sunet.se/ftp/pub/security/tools/crypt/ssleay">
+ftp://ftp.sunet.se/ftp/pub/security/tools/crypt/ssleay</a></p></li></ul><P CLASS="para">
+The latest version as of this printing is 0.9.0b. Download it to the same server as the Samba distribution, then uncompress and untar it. You should be left with a directory entitled <I CLASS="filename">
+SSLeay-0.9.0b</i>. After changing to that directory, you will need to configure and build the SSL encryption package in the same way that you did with Samba.</p><P CLASS="para">
+SSLeay uses a Perl-based <I CLASS="filename">
+configure</i> script. This script modifies the Makefile that constructs the utilities and libraries of the SSLeay package. However, the default script is hardcoded to find Perl at <I CLASS="filename">
+/usr/local/bin/perl</i>. You may need to change the <I CLASS="filename">
+configure</i> script to point to the location of the Perl executable file on your Unix system. For example, you can type the following to locate the Perl executable:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>which perl</b></code>
+/usr/bin/perl</pre><P CLASS="para">
+Then modify the first line of the <I CLASS="filename">
+configure</i> script to force it to use the correct Perl executable. For example, on our Red Hat Linux system:</p><PRE CLASS="programlisting">
+#!/usr/bin/perl
+#
+# see PROBLEMS for instructions on what sort of things to do
+# when tracking a bug -tjh
+...</pre><P CLASS="para">
+After that, you need to run the <I CLASS="filename">
+configure</i> script by specifying a target platform for the distribution. This target platform can be any of the following:</p><PRE CLASS="programlisting">
+BC-16 BC-32 FreeBSD NetBSD-m86
+NetBSD-sparc NetBSD-x86 SINIX-N VC-MSDOS
+VC-NT VC-W31-16 VC-W31-32 VC-WIN16
+VC-WIN32 aix-cc aix-gcc alpha-cc
+alpha-gcc alpha400-cc cc cray-t90-cc
+debug debug-irix-cc debug-linux-elf dgux-R3-gcc
+dgux-R4-gcc dgux-R4-x86-gcc dist gcc
+hpux-cc hpux-gcc hpux-kr-cc irix-cc
+irix-gcc linux-aout linux-elf ncr-scde
+nextstep purify sco5-cc solaris-sparc-cc
+solaris-sparc-gcc solaris-sparc-sc4 solaris-usparc-sc4 solaris-x86-gcc
+sunos-cc sunos-gcc unixware-2.0 unixware</pre><P CLASS="para">
+For our system, we would enter the following:</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>./Configure linux-elf</b></code>
+CC =gcc
+CFLAG =-DL_ENDIAN -DTERMIO -DBN_ASM -O3 -fomit-frame-pointer
+EX_LIBS =
+BN_MULW =asm/bn86-elf.o
+DES_ENC =asm/dx86-elf.o asm/yx86-elf.o
+BF_ENC =asm/bx86-elf.o
+CAST_ENC =asm/cx86-elf.o
+RC4_ENC =asm/rx86-elf.o
+RC5_ENC =asm/r586-elf.o
+MD5_OBJ_ASM =asm/mx86-elf.o
+SHA1_OBJ_ASM =asm/sx86-elf.o
+RMD160_OBJ_ASM=asm/rm86-elf.o
+THIRTY_TWO_BIT mode
+DES_PTR used
+DES_RISC1 used
+DES_UNROLL used
+BN_LLONG mode
+RC4_INDEX mode </pre><P CLASS="para">
+After the package has been configured, you can build it by typing <CODE CLASS="literal">
+make</code>. If the build did not successfully complete, consult the documentation that comes with the distribution or the FAQ at <a href="http://www.cryptsoft.com/ssleay/"><I CLASS="filename">http://www.cryptsoft.com/ssleay/</i></a> for more information on what may have happened. If the build did complete, type <CODE CLASS="literal">
+make</code> <CODE CLASS="literal">
+install</code> to install the libraries on the system. Note that the makefile installs the package in <I CLASS="filename">
+/usr/local/ssl</i> by default. If you decide to install it in another directory, remember the directory when configuring Samba to use SSL.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-985829">
+A.3.1 Configuring SSLeay for Your System</a></h3><P CLASS="para">
+The first thing you need to do is to set the <CODE CLASS="literal">
+PATH</code> environment variable on your system to include the <I CLASS="filename">
+/bin</i> directory of the SSL distribution. This can be done with the following statement:</p><PRE CLASS="programlisting">
+PATH=$PATH:/usr/local/ssl/bin</pre><P CLASS="para">
+That's the easy part. Following that, you will need to create a random series of characters that will be used to prime SSLeay's random number generator. The random number generator will be used to create key pairs for both the clients and the server. You can create this random series by filling a text file of a long series of random characters. For example, you can use your favorite editor to create a text file with random characters, or use this command and enter arbitrary characters at the standard input:</p><PRE CLASS="programlisting">
+cat &gt;/tmp/private.txt</pre><P CLASS="para">
+The Samba documentation recommends that you type characters for longer than a minute before interrupting the input stream by hitting Control-D. Try not to type only the characters that are under your fingers on the keyboard; throw in some symbols and numbers as well. Once you've completed the random file, you can prime the random number generator with the following command:</p><PRE CLASS="programlisting">
+# ssleay genrsa -rand /tmp/private.txt &gt;/dev/null
+2451 semi-random bytes loaded
+Generating RSA private key, 512 bit long modulus
+..+++++
+.................................+++++
+e is 65537 (0x10001)</pre><P CLASS="para">
+You can safely ignore the output of this command. After it has completed, remove the series of characters used to create the key because this could be used to recreate any private keys that were generated from this random number generator:</p><PRE CLASS="programlisting">
+rm -f /tmp/private.txt</pre><P CLASS="para">
+The result of this command is the hidden file .<EM CLASS="emphasis">
+rnd</em>, which is stored in your home directory. SSLeay will use this file when creating key pairs in the future.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-985843">
+A.3.2 Configuring Samba to use SSL</a></h3><P CLASS="para">At this point, you can compile Samba to use SSL. Recall that in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>, we said you have to first run the configure script, which initializes the makefile, before you compile Samba. In order to use SSL with Samba, you will need to reconfigure the makefile:</p><PRE CLASS="programlisting">
+./configure --with-ssl</pre><P CLASS="para">
+After that, you can compile Samba with the following commands:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>make clean</b></code>
+# <CODE CLASS="userinput"><B>make all</b></code></pre><P CLASS="para">
+If you encounter an error that says the <I CLASS="filename">
+smbd</i> executable is missing the file <I CLASS="filename">
+ssl.h</i>, you probably didn't install SSLeay in the default directory. Use the configure option <CODE CLASS="literal">
+--with-sslinc</code> to point to the base directory of the SSL distribution&nbsp;- in this case, the directory that contains <EM CLASS="emphasis">
+include/ssl.h</em>.</p><P CLASS="para">
+On the other hand, if you have a clean compile, you're ready to move on to the next step: creating certificates.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-62097">
+A.3.3 Becoming a Certificate Authority</a></h3><P CLASS="para">
+<I CLASS="firstterm">
+</i>The SSL protocol requires the use of X.509 certificates in the protocol handshake to ensure that either one or both parties involved in the communication are indeed who they say they are. Certificates in real life, such as those use for SSL connections on public web sites, can cost in the arena of $300 a year. This is because the certificate must have a digital signature placed on it by a <I CLASS="firstterm">
+certificate authority</i>. A certificate authority is an entity that vouches for the authenticity of a digital certificate by signing it with its own private key. This way, anyone who wishes to check the authenticity of the certificate can simply use the certificate authority's public key to check the signature.</p><P CLASS="para">
+You are allowed to use a public certificate authority with SSLeay. However, you don't have to. Instead, SSLeay will allow you to declare yourself a trusted certificate authority&nbsp;- specifying which clients you choose to trust and which clients you do not. In order to do this, you will need to perform several tasks with the SSLeay distribution.</p><P CLASS="para">
+The first thing you need to do is specify a secure location where the certificates of the clients and potentially the server will be stored. We have chosen <I CLASS="filename">
+/etc/certificates</i> as our default. Execute the following commands as <CODE CLASS="literal">
+root</code>: </p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>cd /etc</b></code>
+# <CODE CLASS="userinput"><B>mkdir certificates</b></code>
+# <CODE CLASS="userinput"><B>chmod 700 certificates</b></code></pre><P CLASS="para">
+Note that we shut out all access to users other than <CODE CLASS="literal">
+root</code> for this directory. This is very important.</p><P CLASS="para">
+Next, you need to set up the SSLeay scripts and configuration files to use the certificates stored in this directory. In order to do this, first modify the <I CLASS="filename">
+CA.sh</i> script located at <EM CLASS="emphasis">
+/usr/local/ssl/bin/CA.sh</em> to specify the location of the directory you just created. Find the line that contains the following entry:</p><PRE CLASS="programlisting">
+CATOP=./demoCA</pre><P CLASS="para">
+Then change it to:</p><PRE CLASS="programlisting">
+CATOP=/etc/certificates</pre><P CLASS="para">
+Next, you need to modify the <EM CLASS="emphasis">
+/usr/local/ssl/lib/ssleay.cnf</em> file to specify the same directory. Find the entry:</p><PRE CLASS="programlisting">
+[ CA_default ]
+dir = ./demoCA # Where everything is kept</pre><P CLASS="para">
+Then change it to:</p><PRE CLASS="programlisting">
+[ CA_default ]
+dir = /etc/certificates # Where everything is kept</pre><P CLASS="para">
+Next, run the certificate authority setup script, <I CLASS="filename">
+CA.sh</i>, in order to create the certificates. Be sure to do this as the same user that you used to prime the random number generator above:</p><PRE CLASS="programlisting">
+/usr/local/ssl/bin/CA.sh -newca
+mkdir: cannot make directory '/etc/certificates': File exists
+CA certificate filename (or enter to create)</pre><P CLASS="para">
+Press the Enter key to create a certificate for the CA. You should then see:</p><PRE CLASS="programlisting">
+Making CA certificate ...
+Using configuration from /usr/local/ssl/lib/ssleay.cnf
+Generating a 1024 bit RSA private key
+.............................+++++
+.....................+++++
+writing new private key to /etc/certificates/private/cakey.pem
+Enter PEM pass phrase:</pre><P CLASS="para">
+Enter a new pass phrase for your certificate. You will need to enter it twice correctly before SSLeay will accept it:</p><PRE CLASS="programlisting">
+Enter PEM pass phrase:
+Verifying password - Enter PEM pass phrase:</pre><P CLASS="para">
+Be sure to remember this pass phrase. You will need it to sign the client certificates in the future. Once SSLeay has accepted the pass phrase, it will continue on with a series of questions for each of the fields in the X509 certificate:</p><PRE CLASS="programlisting">
+You are about to be asked to enter information that will be
+incorporated into your certificate request.
+What you are about to enter is what is called a Distinguished
+Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.</pre><P CLASS="para">
+Fill out the remainder of the fields with information about your organization. For example, our certificate looks like this:</p><PRE CLASS="programlisting">
+Country Name (2 letter code) [AU]:<CODE CLASS="userinput">
+<B>
+US</b></code>
+State or Province Name (full name) [Some-State]:<CODE CLASS="userinput">
+<B>
+California</b></code>
+Locality Name (eg, city) []:<CODE CLASS="userinput">
+<B>
+Sebastopol</b></code>
+Organization Name (eg, company) []:<CODE CLASS="userinput">
+<B>
+O'Reilly</b></code>
+Organizational Unit Name (eg, section) []:<CODE CLASS="userinput">
+<B>
+Books</b></code>
+Common Name (eg, YOUR name) []:<CODE CLASS="userinput">
+<B>
+John Doe</b></code>
+Email Address []:<CODE CLASS="userinput">
+<B>
+doe@ora.com</b></code></pre><P CLASS="para">
+After that, SSLeay will be configured as a certificate authority and can be used to sign certificates for client machines that will be connecting to the Samba server.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986381">
+A.3.4 Creating Certificates for Clients</a></h3><P CLASS="para">
+It's simple to create a certificate for a client machine. First, you need to generate a public/private key pair for each entity, create a certificate request file, and then use <EM CLASS="emphasis">
+SSLeay</em> to sign the file as a trusted authority.</p><P CLASS="para">
+For our example client <CODE CLASS="literal">
+phoenix</code>, this boils down to three SSLeay commands. The first generates a key pair for the client and places it in the file <I CLASS="filename">
+phoenix.key</i>. The private key will be encrypted, in this case using triple DES. Enter a pass phrase when requested below&nbsp;- you'll need it for the next step:</p><PRE CLASS="programlisting">
+# ssleay genrsa -des3 1024 &gt;phoenix.key
+1112 semi-random bytes loaded
+Generating RSA private key, 1024 bit long modulus
+........................................+++++
+.............+++++
+e is 65537 (0x10001)
+Enter PEM pass phrase:
+Verifying password - Enter PEM pass phrase:</pre><P CLASS="para">
+After that command has completed, type in the following command:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>ssleay req -new -key phoenix.key -out phoenix-csr</b></code>
+Enter PEM pass phrase:</pre><P CLASS="para">
+Enter the pass phrase for the client certificate you just created (not the certificate authority). At this point, you will need to answer the questionnaire again, this time for the client machine. In addition, you must type in a challenge password and an optional company name&nbsp;- those do not matter here. When the command completes, you will have a certificate request in the file <EM CLASS="emphasis">
+phoenix-csr.</em></p><P CLASS="para">
+Then, you must sign the certificate request as the trusted certificate authority. Type in the following command:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>ssleay ca -days 1000 -inflies phoenix-csr &gt;phoenix.pem</b></code></pre><P CLASS="para">
+This command will prompt you to enter the PEM pass phrase of the <EM CLASS="emphasis">
+certificate authority</em>. Be sure that you do not enter the PEM pass phrase of the client certificate that you just created. After entering the correct pass phrase, you should see the following:</p><PRE CLASS="programlisting">
+Check that the request matches the signature
+Signature ok
+The Subjects Distinguished Name is as follows:
+...</pre><P CLASS="para">
+This will be followed by the information that you just entered for the client certificate. If there is an error in the fields, the program will notify you. On the other hand, if everything is fine, SSLeay will confirm that it should sign the certificate and commit it to the database. This adds a record of the certificate to the <I CLASS="filename">
+/etc/certificates/newcerts</i> directory.</p><P CLASS="para">
+The operative files at the end of this exercise are the <EM CLASS="emphasis">
+phoenix.key</em> and <EM CLASS="emphasis">
+phoenix.pem </em>files, which reside in the current directory. These files will be passed off to the client with whom the SSL-enabled Samba server will interact, and will be used by SSL Proxy.<I CLASS="firstterm">
+</i></p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986754">A.3.5 Configuring the Samba Server</a></h3><P CLASS="para">
+The next step is to modify the Samba configuration file to include the following setup options. These options assume that you created the certificates directory for the certificate authority at <I CLASS="filename">
+/etc/certificates </i>:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl server cert = /etc/certificates/cacert.pem
+ ssl server key = /etc/certificates/private/cakey.pem
+ ssl CA certDir = /etc/certificates</pre><P CLASS="para">
+At this point, you will need to kill the Samba daemons and restart them manually:</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>nmbd -D</b></code>
+# <CODE CLASS="userinput"><B>smbd -D</b></code>
+Enter PEM pass phrase:</pre><P CLASS="para">
+You will need to enter the PEM pass phrase of the certificate authority to start up the Samba daemons. Note that this may present a problem in terms of starting the program using ordinary means. However, you can get around this using advanced scripting languages, such as Expect or Python.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986870">
+A.3.6 Testing with smbclient</a></h3><P CLASS="para">
+A good way to test whether Samba is working properly is to use the<EM CLASS="emphasis">
+ smbclient</em> program. On the Samba server, enter the following command, substituting the appropriate share and user for a connection:</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>smbclient //hydra/data -U tom</b></code></pre><P CLASS="para">
+You should see several debugging statements followed by a line indicating the negotiated cipher, such as:</p><PRE CLASS="programlisting">
+SSL: negotiated cipher: DES-CBC3-SHA</pre><P CLASS="para">
+After that, you can enter your password and connect to the share normally. If this works, you can be sure that Samba is correctly supporting SSL connections. Now, on to the client setup. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_02.html" TITLE="A.2 Requirements">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.2 Requirements" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_04.html" TITLE="A.4 Setting Up SSL Proxy">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.4 Setting Up SSL Proxy" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+A.2 Requirements</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+A.4 Setting Up SSL Proxy</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appa_04.html b/docs/htmldocs/using_samba/appa_04.html
new file mode 100644
index 00000000000..d4f99e29511
--- /dev/null
+++ b/docs/htmldocs/using_samba/appa_04.html
@@ -0,0 +1,135 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix A] A.4 Setting Up SSL Proxy</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:41Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_03.html" TITLE="A.3 Installing SSLeay">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.3 Installing SSLeay" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+Appendix A<br>
+Configuring Samba with SSL</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_05.html" TITLE="A.5 SSL Configuration Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.5 SSL Configuration Options" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appa-pgfId-986788">
+A.4 Setting Up SSL Proxy</a></h2><P CLASS="para">
+The SSL Proxy program is available as a standalone binary or as source code. You can download it from <A CLASS="systemitem.url" HREF="http://obdev.at/Products/sslproxy.html">
+http://obdev.at/Products/sslproxy.html</a>.</p><P CLASS="para">
+Once it is downloaded, you can configure and compile it like Samba. We will configure it on a Windows NT system. However, setting it up for a Unix system involves a nearly identical series of steps. Be sure that you are the superuser (administrator) for the next series of steps.</p><P CLASS="para">
+If you downloaded the binary for Windows NT, you should have the following files in a directory:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-986793">
+</a><I CLASS="filename">
+cygwinb19.dll</i></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-986794">
+</a><I CLASS="filename">
+README.TXT</i></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-986795">
+</a><I CLASS="filename">
+sslproxy.exe</i></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appa-pgfId-986796">
+</a><I CLASS="filename">
+dummyCert.pem</i></p></li></ul><P CLASS="para">
+The only one that you will be interested in is the SSL Proxy executable. Copy over the <EM CLASS="emphasis">
+phoenix.pem</em> and <EM CLASS="emphasis">
+phoenix.key</em> files that you generated earlier for the client to the same directory as the SSL proxy executable. Make sure that the directory is secure from the prying eyes of other users.</p><P CLASS="para">
+The next step is to ensure that the Windows NT machine can resolve the NetBIOS name of the Samba server. This means that you should either have a WINS server up and running (the Samba server can perform this task with the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+support</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option) or have it listed in the appropriate <EM CLASS="emphasis">
+hosts</em> file of the system. See <a href="ch07_01.html"><b>Chapter 7, <CITE CLASS="chapter">Printing and Name Resolution</cite></b></a>, for more information on WINS server.[<A CLASS="footnote" HREF="#appa-pgfId-986801">1</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="appa-pgfId-986801">[1]</a> If you are running SSL Proxy on a Unix server, you should ensure that the DNS name of the Samba server can be resolved.</p></div></blockquote><P CLASS="para">
+Finally, start up SSL Proxy with the following command. Here, we assume that <CODE CLASS="literal">
+hydra</code> is the name of the Samba server:</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>C:\SSLProxy&gt;sslproxy -l 139 -R hydra -r 139 -n -c phoenix.pem -k phoenix.key</b></code></pre><P CLASS="para">
+This tells SSL Proxy to listen for connections to port 139 and relay those requests to port 139 on the NetBIOS machine <CODE CLASS="literal">
+hydra</code>. It also instructs SSL Proxy to use the <I CLASS="filename">
+phoenix.pem</i> and <I CLASS="filename">
+phoenix.key</i> files to generate the certificate and keys necessary to initiate the SSL connection. SSL Proxy responds with:</p><PRE CLASS="programlisting">
+Enter PEM pass phrase:</pre><P CLASS="para">
+Enter the PEM pass phrase of the client keypair that you generated, <EM CLASS="emphasis">
+not</em> the certificate authority. You should then see the following output:</p><PRE CLASS="programlisting">
+SSL: No verify locations, trying default
+proxy ready, listening for connections</pre><P CLASS="para">
+That should take care of the client. You can place this command in a startup sequence on either Unix or Windows NT if you want this functionality available at all times. Be sure to set any clients you have connecting to the NT server (including the NT server itself) to point to this server instead of the Samba server.</p><P CLASS="para">
+After you've completed setting this up, try to connect using clients that proxy through the NT server. You should find that it works almost transparently.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_03.html" TITLE="A.3 Installing SSLeay">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.3 Installing SSLeay" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_05.html" TITLE="A.5 SSL Configuration Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A.5 SSL Configuration Options" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+A.3 Installing SSLeay</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+A.5 SSL Configuration Options</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appa_05.html b/docs/htmldocs/using_samba/appa_05.html
new file mode 100644
index 00000000000..2048040ec97
--- /dev/null
+++ b/docs/htmldocs/using_samba/appa_05.html
@@ -0,0 +1,460 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix A] A.5 SSL Configuration Options</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:44Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_04.html" TITLE="A.4 Setting Up SSL Proxy">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.4 Setting Up SSL Proxy" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+Appendix A<br>
+Configuring Samba with SSL</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appb_01.html" TITLE="B. Samba Performance Tuning">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B. Samba Performance Tuning" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appa-pgfId-985845">
+A.5 SSL Configuration Options</a></h2><P CLASS="para">
+<A CLASS="xref" HREF="appa_05.html#appa-61150">Table A.1</a> summarizes the configuration options introduced in the previous section for using SSL. Note that all of these options are global in scope; in other words, they must appear in the <CODE CLASS="literal">
+[global]</code> section of the configuration file. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appa-61150">
+Table A.1: SSL Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether SSL mode is enabled with Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl hosts</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of addresses)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of hosts that must always connect using SSL.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl hosts resign</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of addresses)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of hosts that never connect using SS.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl CA certDir</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the directory where the certificates are stored.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl CA certFile</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a file that contains all of the certificates for Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl server cert</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the location of the server's certificate.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl server key</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the location of the server's private key.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl client cert</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the location of the client's certificate.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl client key</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the location of the client's private key.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl require clientcert</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether Samba should require each client to have a certificate.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl require servercert</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether the server itself should have a certificate.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl ciphers</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+String </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the cipher suite to use during protocol negotiation.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl version</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl2or3</code>, <CODE CLASS="literal">
+ssl3</code>, or <CODE CLASS="literal">
+tls1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the version of SSL to use.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl2or3</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ssl compatibility</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether compatibility with other implementations of SSL should be activated.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986013">
+A.5.1 ssl</a></h3><P CLASS="para">
+This global option configures Samba to use SSL for communication between itself and clients. The default value of this option is <CODE CLASS="literal">
+no</code>. You can reset it as follows:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes</pre><P CLASS="para">
+Note that in order to use this option, you must have a proxy for Windows 95/98 clients, such as in the model presented earlier in this chapter.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986018">
+A.5.2 ssl hosts</a></h3><P CLASS="para">
+This option specifies the hosts that will be forced into using SSL. The syntax for specifying hosts and addresses is the same as the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> configuration options. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.</pre><P CLASS="para">
+This example specifies that all hosts that fall into the 192.168.220 subnet must use SSL connections with the client. This type of structure is useful if you know that various connections will be made by a subnet that lies across an untrusted network, such as the Internet. If neither this option nor the <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+resign</code> option has been specified, and <CODE CLASS="literal">
+ssl</code> is set to <CODE CLASS="literal">
+yes</code>, Samba will allow only SSL connections from all clients.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986024">
+A.5.3 ssl hosts resign</a></h3><P CLASS="para">
+This option specifies the hosts that will <EM CLASS="emphasis">
+not</em> be forced into SSL mode. The syntax for specifying hosts and addresses is the same as the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> configuration options. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts resign = 160.2.310. 160.2.320.</pre><P CLASS="para">
+This example specifies that all hosts that fall into the 160.2.310 or 160.2.320 subnets will not use SSL connections with the client. If neither this option nor the <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+hosts</code> option has been specified, and <CODE CLASS="literal">
+ssl</code> is set to <CODE CLASS="literal">
+yes</code>, Samba will allow only SSL connections from all clients.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986030">
+A.5.4 ssl CA certDir</a></h3><P CLASS="para">
+This option specifies the directory containing the certificate authority's certificates that Samba will use to authenticate clients. There must be one file in this directory for each certificate authority, named as specified earlier in this chapter. Any other files in this directory are ignored. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certDir = /usr/local/samba/cert</pre><P CLASS="para">
+There is no default for this option. You can alternatively use the option <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+CA</code> <CODE CLASS="literal">
+certFile</code> if you wish to place all the certificate authority information in the same file.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986037">
+A.5.5 ssl CA certFile</a></h3><P CLASS="para">
+This option specifies a file that contains the certificate authority's certificates that Samba will use to authenticate clients. This option differs from <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+CA</code> <CODE CLASS="literal">
+certDir</code> in that there is only one file used for all the certificate authorities. An example of its usage follows:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile</pre><P CLASS="para">
+There is no default for this option. You can also use the option <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+CA</code> <CODE CLASS="literal">
+certDir</code> if you wish to have a separate file for each certificate authority that Samba trusts.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986044">
+A.5.6 ssl server cert</a></h3><P CLASS="para">
+This option specifies the location of the server's certificate. This option is mandatory; the server must have a certificate in order to use SSL. For example: </p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile
+ ssl server cert = /usr/local/samba/private/server.pem</pre><P CLASS="para">
+There is no default for this option. Note that the certificate may contain the private key for the server.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986052">
+A.5.7 ssl server key</a></h3><P CLASS="para">
+This option specifies the location of the server's private key. You should ensure that the location of the file cannot be accessed by anyone other than <CODE CLASS="literal">
+root</code>. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile
+ ssl server key = /usr/local/samba/private/samba.pem</pre><P CLASS="para">
+There is no default for this option. Note that the private key may be contained in the certificate for the server. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986060">
+A.5.8 ssl client cert</a></h3><P CLASS="para">
+This option specifies the location of the client's certificate. The certificate may be requested by the Samba server with the <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+require</code> <CODE CLASS="literal">
+clientcert</code> option; the certificate is also used by <I CLASS="filename">
+smbclient</i>. For example: </p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile
+ ssl server cert = /usr/local/ssl/private/server.pem
+ ssl client cert= /usr/local/ssl/private/clientcert.pem</pre><P CLASS="para">
+There is no default for this option. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986069">
+A.5.9 ssl client key</a></h3><P CLASS="para">
+This option specifies the location of the client's private key. You should ensure that the location of the file cannot be accessed by anyone other than <CODE CLASS="literal">
+root</code>. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certDir = /usr/local/samba/cert/
+ ssl server key = /usr/local/ssl/private/samba.pem
+ ssl client key = /usr/local/ssl/private/clients.pem</pre><P CLASS="para">
+There is no default for this option. This option is only needed if the client has a certificate. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986078">
+A.5.10 ssl require clientcert</a></h3><P CLASS="para">
+This option specifies whether the client is required to have a certificate. The certificates listed with either the <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+CA</code> <CODE CLASS="literal">
+certDir</code> or the <CODE CLASS="literal">
+ssl</code> <CODE CLASS="literal">
+CA</code> <CODE CLASS="literal">
+certFile</code> will be searched to confirm that the client has a valid certificate and is authorized to connect to the Samba server. The value of this option is a simple boolean. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile
+ ssl require clientcert = yes</pre><P CLASS="para">
+We recommend that you require certificates from all clients that could be connecting to the Samba server. The default value for this option is <CODE CLASS="literal">
+no</code>.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-990571">
+A.5.11 ssl require servercert</a></h3><P CLASS="para">
+This option specifies whether the server is required to have a certificate. Again, this will be used by the <I CLASS="filename">
+smbclient</i> program. The value of this option is a simple boolean. For example:</p><PRE CLASS="programlisting">
+[global]
+ ssl = yes
+ ssl hosts = 192.168.220.
+ ssl CA certFile = /usr/local/samba/cert/certFile
+ ssl require clientcert = yes
+ ssl require servercert = yes</pre><P CLASS="para">
+Although we recommend that you require certificates from all clients that could be connecting to the Samba server, a server certificate is not required. It is, however, recommended. The default value for this option is <CODE CLASS="literal">
+no</code>.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986095">
+A.5.12 ssl ciphers</a></h3><P CLASS="para">
+This option sets the ciphers on which SSL will decide during the negotiation phase of the SSL connection. Samba can use any of the following ciphers:</p><PRE CLASS="programlisting">
+DEFAULT
+DES-CFB-M1
+NULL-MD5
+RC4-MD5
+EXP-RC4-MD5
+RC2-CBC-MD5
+EXP-RC2-CBC-MD5
+IDEA-CBC-MD5
+DES-CBC-MD5
+DES-CBC-SHA
+DES-CBC3-MD5
+DES-CBC3-SHA
+RC4-64-MD5
+NULL</pre><P CLASS="para">
+It is best not to set this option unless you are familiar with the SSL protocol and want to mandate a specific cipher suite.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-986097">
+A.5.13 ssl version</a></h3><P CLASS="para">
+This global option specifies the version of SSL that Samba will use when handling encrypted connections. The default value is <CODE CLASS="literal">
+ssl2or3</code>, which specifies that either version 2 or 3 of the SSL protocol can be used, depending on which version is negotiated in the handshake between the server and the client. However, if you want Samba to use only a specific version of the protocol, you can specify the following:</p><PRE CLASS="programlisting">
+[global]
+ ssl version = ssl3</pre><P CLASS="para">
+Again, it is best not to set this option unless you are familiar with the SSL protocol and want to mandate a specific version.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appa-pgfId-990580">
+A.5.14 ssl compatibility</a></h3><P CLASS="para">
+This global option specifies whether Samba should be configured to use other versions of SSL. However, because no other versions exist at this writing, the issue is moot and the variable should always be left at the default.</p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_04.html" TITLE="A.4 Setting Up SSL Proxy">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.4 Setting Up SSL Proxy" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appb_01.html" TITLE="B. Samba Performance Tuning">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B. Samba Performance Tuning" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">A.4 Setting Up SSL Proxy</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+B. Samba Performance Tuning</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appb_01.html b/docs/htmldocs/using_samba/appb_01.html
new file mode 100644
index 00000000000..4e1ec529af7
--- /dev/null
+++ b/docs/htmldocs/using_samba/appb_01.html
@@ -0,0 +1,162 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix B] Samba Performance Tuning</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:42:02Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_05.html" TITLE="A.5 SSL Configuration Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.5 SSL Configuration Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix B</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_02.html" TITLE="B.2 Samba Tuning">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B.2 Samba Tuning" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="appendix">
+<A CLASS="title" NAME="appb-66714">
+B. Samba Performance Tuning</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#appb-47134" TITLE="B.1 A Simple Benchmark">
+A Simple Benchmark</a><br>
+<A CLASS="sect1" HREF="appb_02.html" TITLE="B.2 Samba Tuning">
+Samba Tuning</a><br>
+<A CLASS="sect1" HREF="appb_03.html" TITLE="B.3 Sizing Samba Servers">
+Sizing Samba Servers</a></p><P>
+</p></div><P CLASS="para">This appendix discusses various ways of performance tuning and system sizing with Samba. <I CLASS="firstterm">
+Performance tuning</i> is the art of finding bottlenecks and adjusting to eliminate them. <EM CLASS="emphasis">
+Sizing</em> is the practice of eliminating bottlenecks by spending money to avoid having them in the first place. Normally, you won't have to worry about either with Samba. On a completely untuned server, Samba will happily support a small community of users. However, on a properly tuned server, Samba will support at least twice as many users. This chapter is devoted to outlining various performance-tuning and sizing techniques that you can use if you want to stretch your Samba server to the limit.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appb-47134">
+B.1 A Simple Benchmark</a></h2><P CLASS="para">How do you know if you're getting reasonable performance? A simple benchmark is to compare Samba with FTP. <A CLASS="xref" HREF="appb_01.html#appb-73167">
+Table B.1</a> shows the throughput, in kilobytes per second, of a pair of servers: a medium-size Sun SPARC Ultra and a small Linux Pentium server. Numbers are reported in kilobytes per second (KB/s). </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-73167">
+Table B.1: Sample Benchmark Benchmarks </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Command</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+FTP</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Untuned Samba</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Tuned Samba</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sparc get</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1014.5</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+645.3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+866.7</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sparc put</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+379.8 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+386.1</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+329.5</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Pentium get</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+973.27</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+N/A</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+725</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Pentium put</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1014.5</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+N/A</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1100</p></td></tr></tbody></table><P CLASS="para">
+If you run the same tests on your server, you probably won't see the same numbers. However, you <EM CLASS="emphasis">
+should </em>see similar ratios of Samba to FTP, probably in the range of 68 to 80 percent. It's not a good idea to base <EM CLASS="emphasis">
+all</em> of Samba's throughput against FTP. The golden rule to remember is this: if Samba is much slower than FTP, it's time to tune it.</p><P CLASS="para">
+You might think that an equivalent test would be to compare Samba to NFS. In reality, however, it's much less useful to compare their speeds. Depending entirely on whose version of NFS you have and how well it's tuned, Samba can be slower or faster than NFS. We usually find that Samba is faster, but watch out; NFS uses a different algorithm from Samba, so tuning options that are optimal for NFS may be detrimental for Samba. If you run Samba on a well-tuned NFS server, Samba may perform rather badly.</p><P CLASS="para">
+A more popular benchmark is Ziff-Davis' <EM CLASS="emphasis">
+NetBench, </em>a simulation of many users on client machines running word processors and accessing data on the SMB server. It's not a prefect measure (each NetBench client does about ten times the work of a normal user on our site), but it is a fair comparison of similar servers. In tests performed by Jeremy Allison in November 1998, Samba 2.0 on a SGI multiprocessor outperformed NT Server 4.0 (Patch Level 2) on an equivalent high-end Compaq. This was confirmed and strengthened by a Sm@rt Reseller test of NT and Linux on identical hardware in February 1999. </p><P CLASS="para">
+In April 1999, the Mindcraft test lab released a report about a test showing that Samba on a four-processor Linux machine was significantly slower than native file serving on the same machine running Windows NT. While the original report was slammed by the Open Source community because it was commissioned by Microsoft and tuned the systems to favor Windows NT, a subsequent test was fairer and generally admitted to reveal some areas where Linux needed to improve its performance, especially on multiprocessors. Little was said about Samba itself. Samba is known to scale well on multiprocessors, and exceeds 440MB/s on a four-processor SGI O200, beating Mindcraft's 310MB/s.</p><P CLASS="para">
+Relative performance will probably change as NT and PC hardware get faster, of course, but Samba is improving as well. For example, Samba 1.9.18 was faster only with more than 35 clients. Samba 2.0, however, is faster regardless of the number of clients. In short, Samba is very competitive with the best networking software in the industry, and is only getting better. </p><P CLASS="para">
+As we went to press, Andrew Tridgell released the alpha-test version suite of benchmarking programs for Samba and SMB networks. Expect even more work on performance from the Samba team in the future.</p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appa_05.html" TITLE="A.5 SSL Configuration Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: A.5 SSL Configuration Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_02.html" TITLE="B.2 Samba Tuning">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B.2 Samba Tuning" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+A.5 SSL Configuration Options</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+B.2 Samba Tuning</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appb_02.html b/docs/htmldocs/using_samba/appb_02.html
new file mode 100644
index 00000000000..4d2ce9ae3aa
--- /dev/null
+++ b/docs/htmldocs/using_samba/appb_02.html
@@ -0,0 +1,342 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix B] B.2 Samba Tuning</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:42:03Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_01.html" TITLE="B.1 A Simple Benchmark">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.1 A Simple Benchmark" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appb_01.html" TITLE="B. Samba Performance Tuning">
+Appendix B<br>
+Samba Performance Tuning</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_03.html" TITLE="B.3 Sizing Samba Servers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B.3 Sizing Samba Servers" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appb-50295">
+B.2 Samba Tuning</a></h2><P CLASS="para">That being said, let's discuss how you can take an already fast networking package and make it even faster.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948325">
+B.2.1 Benchmarking</a></h3><P CLASS="para">Benchmarking is an arcane and somewhat black art, but the level of expertise needed for simple performance tuning is fairly low. Since the Samba server's goal in life is to transfer files, we will examine only throughput, not response time to particular events, under the benchmarking microscope. After all, it's relatively easy to measure file transfer speed, and Samba doesn't suffer too badly from response-time problems that would require more sophisticated techniques. </p><P CLASS="para">
+Our basic strategy for this work will be:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948328">
+</a>Find a reasonably-sized file to copy and a program that reports on copy speeds, such as <I CLASS="filename">
+smbclient</i>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948329">
+</a>Find a quiet (or typical) time to do the test.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948330">
+</a>Pre-run each test a few times to preload buffers.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948331">
+</a>Run tests several times and watch for unusual results.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948332">
+</a>Record each run in detail.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-948333">
+</a>Compare the average of the valid runs to expected values.</p></li></ul><P CLASS="para">
+After establishing a baseline using this method, we can adjust a single parameter and do the measurements all over again. An empty table for your tests is provided at the end of this chapter.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948336">
+B.2.2 Things to Tweak</a></h3><P CLASS="para">
+There are literally thousands of Samba setting combinations that you can use in search of that perfect server. Those of us with lives outside of system administration, however, can narrow down the number of options to those listed in this section, which are the most likely to affect overall throughput. They are presented roughly in order of impact.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948339">
+B.2.2.1 Log level</a></h4><P CLASS="para">This is an obvious one. Increasing the logging level (<CODE CLASS="literal">log</code> <CODE CLASS="literal">
+level</code> or <CODE CLASS="literal">
+debug</code> <CODE CLASS="literal">
+level</code> configuration options) is a good way to debug a problem, unless you happen to be searching for a performance problem! As mentioned in <a href="ch04_01.html"><b>Chapter 4, <CITE CLASS="chapter">Disk Shares</cite></b></a>, Samba produces a ton of debugging messages at level 3 and above, and writing them to disk or syslog is a slow operation. In our <I CLASS="filename">
+smbclient/ftp</i> tests, raising the log level from 0 to 3 cut the untuned <CODE CLASS="literal">
+get</code> <CODE CLASS="literal">
+speed</code> from 645.3 to 622.2KB/s, or roughly 5 percent. Higher log levels were even worse.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948342">
+B.2.2.2 Socket options</a></h4><P CLASS="para">
+The next thing to look at are the <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+options</code> configuration options. These are really host system tuning options, but they're set on a per-connection basis, and can be reset by Samba on the sockets it employs by adding <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+options</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+option</code> to the <CODE CLASS="literal">
+[global]</code> section of your <I CLASS="filename">
+smb.conf </i>file. Not all of these options are supported by all vendors; check your vendor's manual pages on <I CLASS="function">
+setsockopt </i>(1) or <I CLASS="function">
+socket </i>(5) for details.</p><P CLASS="para">
+The main options are:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<CODE CLASS="literal">
+TCP_NODELAY</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Have the server send as many packets as necessary to keep delay low. This is used on telnet connections to give good response time, and is used&nbsp;- somewhat counter-intuitively&nbsp;- to get good speed even when doing small requests or when acknowledgments are delayed (as seems to occur with Microsoft TCP/IP). This is worth a 30-50 percent speedup by itself. Incidentally, in Samba 2.0.4, <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+options</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+TCP_NODELAY</code> became the default value for that option.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+IPTOS_LOWDELAY</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+This is another option that trades off throughput for lower delay, but which affects routers and other systems, not the server. All the IPTOS options are new; they're not supported by all operating systems and routers. If they are supported, set <CODE CLASS="literal">
+IPTOS_LOWDELAY</code> whenever you set <CODE CLASS="literal">
+TCP_NODELAY</code>.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+SO_SNDBUF</code> <CODE CLASS="literal">
+and</code> <CODE CLASS="literal">
+SO_RCVBUF</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+The send and receive buffers can often be the reset to a value higher than that of the operating system. This yields a marginal increase of speed (until it reaches a point of diminishing returns). </p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+SO_KEEPALIVE</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+This initiates a periodic (four-hour) check to see if the client has disappeared. Expired connections are addressed somewhat better with Samba's <CODE CLASS="literal">
+keepalive</code> and <CODE CLASS="literal">
+dead</code> <CODE CLASS="literal">
+time</code> options. All three eventually arrange to close dead connections, returning unused memory and process-table entries to the operating system.</p></dd></dl><P CLASS="para">
+There are several other socket options you might look at, (e.g., <CODE CLASS="literal">
+SO_SNDLOWAT</code>), but they vary in availability from vendor to vendor. You probably want to look at <CITE CLASS="citetitle">
+TCP/IP Illustrated</cite> if you're interested in exploring more of these options for performance tuning with Samba.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948370">
+B.2.2.3 read raw and write raw</a></h4><P CLASS="para">These are important performance configuration options; they enable Samba to use large reads and writes to the network, of up to 64KB in a single SMB request. They also require the largest SMB packet structures, <CODE CLASS="literal">
+SMBreadraw</code> and <CODE CLASS="literal">
+SMBwriteraw</code>, from which the options take their names. Note that this is not the same as a Unix <EM CLASS="emphasis">
+raw read</em>. This Unix term usually refers to reading disks without using the files system, quite a different sense from the one described here for Samba.</p><P CLASS="para">
+In the past, some client programs failed if you tried to use <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+raw</code>. As far as we know, no client suffers from this problem any more. Read and write raw default to <CODE CLASS="literal">
+yes</code>, and should be left on unless you find you have one of the buggy clients.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948374">
+B.2.2.4 Opportunistic locking</a></h4><P CLASS="para">Opportunistic locks, or <EM CLASS="emphasis">
+oplocks</em>, allow clients to cache files locally, improving performance on the order of 30 percent. This option is now enabled by default. For read-only files, the <CODE CLASS="literal">
+fake</code> <CODE CLASS="literal">
+oplocks</code> provides the same functionality without actually doing any caching. If you have files that cannot be cached, <EM CLASS="emphasis">
+oplocks</em> can be turned off.</p><P CLASS="para">
+Database files should never be cached, nor should any files that are updated both on the server and the client and whose changes must be immediately visible. For these files, the <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+oplock</code> <CODE CLASS="literal">
+files</code> option allows you to specify a list of individual files or a pattern containing wildcards to avoid caching. <EM CLASS="emphasis">
+oplocks</em> can be turned off on a share-by-share basis if you have large groups of files you don't want cached on clients. See <a href="ch05_01.html"><b>Chapter 5, <CITE CLASS="chapter">Browsing and Advanced Disk Shares</cite></b></a>, for more information on opportunistic locks.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948378">
+B.2.2.5 IP packet size (MTU)</a></h4><P CLASS="para">Networks generally set a limit to the size of an individual transmission or packet This is called the Maximum Segment Size, or if the packet header size is included, the Maximum Transport Unit (MTU). This MTU is not set by Samba, but Samba needs to use a <CODE CLASS="literal">
+max</code> <CODE CLASS="literal">
+xmit</code> (write size) bigger than the MTU, or throughput will be reduced. This is discussed in further detail in the following note. The MTU is normally preset to 1500 bytes on an Ethernet and 4098 bytes on FDDI. In general, having it too low cuts throughput, and having it too high causes a sudden performance dropoff due to fragmentation and retransmissions.</p><P CLASS="para">
+If you are communicating over a router, some systems will assume the router is a serial link (e.g., a T1) and set the MTU to more or less 536 bytes. Windows 95 makes this mistake, which causes nearby clients to perform well, but clients on the other side of the router to be noticeably slower. If the client makes the opposite error and uses a large MTU on a link which demands a small one, the packets will be broken up into fragments. This slows transfers slightly, and any networking errors will cause multiple fragments to be retransmitted, which slows Samba significantly. Fortunately, you can modify the Windows MTU size to prevent either error. To understand this in more detail, see "The Windows 95 Networking Frequently Asked Questions (FAQ)" at <A CLASS="systemitem.url" HREF="http://www.stanford.edu/~llurch/win95netbugs/faq.html">
+http://www.stanford.edu/~llurch/win95netbugs/faq.html</a>, which explains how to override the Windows MTU and Window Size.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-19919">
+<a name="b226"></a>
+B.2.2.6 The TCP receive window</a></h4><P CLASS="para">TCP/IP works by breaking down data into small packets that can be transmitted from one machine to another. When each packet is transmitted, it contains a checksum that allows the receiver to check the packet data for potential errors in transmission. Theoretically, when a packet is received and verified, an acknowledgment packet should be sent back to the sender that essentially says, "Everything arrived intact: please continue."</p><P CLASS="para">
+In order to keep things moving, however, TCP accepts a range (window) of packets that allows a sender to keep transmitting without having to wait for an acknowledgment of every single packet. (It can then bundle a group of acknowledgments and transmit them back to the sender at the same time.) In other words, this receive window is the number of bytes that the sender can transmit before it has to stop and wait for a receiver's acknowledgment. Like the MTU, it is automatically set based on the type of connection. Having the window too small causes a lot of unnecessary waiting for acknowledgment messages. Various operating systems set moderate buffer sizes on a per-socket basis to keep one program from hogging all the memory.</p><P CLASS="para">
+The buffer sizes are assigned in bytes, such as <CODE CLASS="literal">
+SO_SNDBUF=8192</code> in the <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+options</code> line. Thus, an example <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+options</code> configuration option is: </p><PRE CLASS="programlisting">
+<CODE CLASS="literal">socket</code> <CODE CLASS="literal">options</code> <CODE CLASS="literal">=</code> <CODE CLASS="literal">SO_SNDBUF=8192</code> </pre><P CLASS="para">
+Normally, one tries to set these socket options higher than the default: 4098 in SunOS 4.1.3 and SVR4, and 8192-16384 in AIX, Solaris, and BSD. 16384 has been suggested as a good starting point: in a non-Samba test mentioned in Stevens' book, it yielded a 40 percent improvement. You'll need to experiment, because performance will fall off again if you set the sizes too high. This is illustrated in <A CLASS="xref" HREF="appb_02.html#appb-34738">
+Figure B.1</a>, a test done on a particular Linux system. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="appb-34738">
+Figure B.1: SO_SNDBUF size and performance</a></h4><IMG CLASS="graphic" SRC="figs/sam.ab01.gif" ALT="Figure B.1"><P CLASS="para">
+Setting the socket options <CODE CLASS="literal">
+O_SNDBUF</code> and <CODE CLASS="literal">
+SO_RCVBUF</code> to less than the default is inadvisable. Setting them higher improves performance, up to a network-specific limit. However, once you exceed that limit, performance will abruptly level off.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-960372">
+B.2.2.7 max xmit</a></h4><P CLASS="para">In Samba, the option that is directly related with the MTU and window size is <CODE CLASS="literal">
+max</code> <CODE CLASS="literal">
+xmit</code>. This option sets the largest block of data Samba will try to write at any one time. It's sometimes known as the <I CLASS="firstterm">
+write size</i>, although that is not the name of the Samba configuration option.</p><P CLASS="para">
+Because the percentage of each block required for overhead falls as the blocks get larger, max xmit is conventionally set as large as possible. It defaults to the protocol's upper limit, which is 64 kilobytes. The smallest value that doesn't cause significant slowdowns is 2048. If it is set low enough, it will limit the largest packet size that Samba will be able to negotiate. This can be used to simulate a small MTU if you need to test an unreliable network connection. However, such a test should not be used in production for reducing the effective MTU.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948396">
+B.2.2.8 read size</a></h4><P CLASS="para">If <CODE CLASS="literal">
+max</code> <CODE CLASS="literal">
+xmit</code> is commonly called the write size, you'd expect <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+size</code> to be the maximum amount of data that Samba would want to read from the client via the network. Actually, it's not. In fact, it's an option to trigger <I CLASS="firstterm">
+write ahead</i>. This means that if Samba gets behind reading from the disk and writing to the network (or vice versa) by the specified amount, it will start overlapping network writes with disk reads (or vice versa).</p><P CLASS="para">
+The read size doesn't have a big performance effect on Unix, unless you set its value quite small. At that point, it causes a detectable slowdown. For this reason, it defaults to 2048 and can't be set lower than 1024.</p></div><DIV CLASS="sect3">
+
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-950907">
+B.2.2.9 read prediction </a></h4>
+
+<P CLASS="para">Besides being counterintuitive, this option is also
+obsolete. It enables Samba to read ahead on files opened read only by the
+clients. The option is disabled in Samba 2.0 (and late 1.9) because it
+interferes with opportunistic locking.</p>
+
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-950907-add1">
+B.2.2.10 write cache size </a></h4>
+
+<P CLASS="para">
+This parameter was introduced in Samba 2.0.7 to allow tuning the
+write-size of RAID disks, as well as allowing general caching of
+writes on machines with lots of memory but slow disks.</p>
+
+<p> It specifies in bytes the size of a per-file write cache that
+Samba will create for an oplocked file. This can improve performance
+significantly by causing writes to be done in large
+chunk sizes. </p>
+
+<p> Up to 10 write caches can be active simultaneously per smbd, each of
+the specified size, allocated to the first 10 oplocked files. As with
+other filesystem caches, crashing before the data is written can corrupt
+files. </P>
+
+<p> Setting <CODE CLASS="literal"> sync always </CODE> will override the
+write caching, and setting <CODE CLASS="literal">strict sync</CODE> will
+allow Windows clients to override it. Alas, Windows Explorer defaults
+to setting the sync bit, so setting <CODE CLASS="literal">strict sync</CODE>
+can be a big performance hit.</p>
+
+<p> As it's new, we haven't many reports on the performance increase, and
+merely suspect it will be considerable.</p>
+</div></div><DIV CLASS="sect2">
+
+
+
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948407">
+B.2.3 Other Samba Options</a></h3><P CLASS="para">The following Samba options will affect performance if they're set incorrectly, much like the debug level. They're mentioned here so you will know what to look out for:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<CODE CLASS="literal">hide files</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Providing a pattern to identify files hidden by the Windows client <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> will result in any file matching the pattern being passed to the client with the DOS hidden attribute set. It requires a pattern match per file when listing directories, and slows the server noticeably.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+lpq cache time</code></dt><DD CLASS="listitem">
+<P CLASS="para">If your <CODE CLASS="literal">
+lpq</code> (printer queue contents) command takes a long time to complete, you should increase <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+cache</code> <CODE CLASS="literal">
+time</code> to a value higher than the actual time required for <CODE CLASS="literal">
+lpq</code> to execute, so as to keep Samba from starting a new query when one's already running. The default is 10 seconds, which is reasonable.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+strict locking</code></dt><DD CLASS="listitem">
+<P CLASS="para">Setting the <CODE CLASS="literal">
+strict</code> <CODE CLASS="literal">
+locking</code> option causes Samba to check for locks on every access, not just when asked to by the client. The option is primarily a bug-avoidance feature, and can prevent ill-behaved DOS and Windows applications from corrupting shared files. However, it is slow and should typically be avoided.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+strict sync</code></dt><DD CLASS="listitem">
+<P CLASS="para">Setting <CODE CLASS="literal">
+strict</code> <CODE CLASS="literal">
+sync</code> will cause Samba to write each packet to disk and wait for the write to complete whenever the client sets the sync bit in a packet. Windows 98 Explorer sets the bit in all packets transmitted, so if you turn this on, anyone with Windows 98 will think Samba servers are horribly slow.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+sync always</code></dt><DD CLASS="listitem">
+<P CLASS="para">Setting <CODE CLASS="literal">
+sync</code> <CODE CLASS="literal">
+always</code> causes Samba to flush every write to disk. This is good if your server crashes constantly, but the performance costs are immense. SMB servers normally use oplocks and automatic reconnection to avoid the ill effects of crashes, so setting this option is not normally necessary.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">wide links</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Turning off <CODE CLASS="literal">
+wide</code> <CODE CLASS="literal">
+links</code> prevents Samba from following symbolic links in one file share to files that are not in the share. It is turned on by default, since following links in Unix is not a security problem. Turning it off requires extra processing on every file open. If you do turn off wide links, be sure to turn on <CODE CLASS="literal">
+getwd</code> <CODE CLASS="literal">
+cache</code> to cache some of the required data.</p><P CLASS="para">
+There is also a <CODE CLASS="literal">
+follow</code> <CODE CLASS="literal">
+symlinks</code> option that can be turned off to prevent following any symbolic links at all. However, this option does not pose a performance problem.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">getwd cache</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+This option caches the path to the current directory, avoiding long tree-walks to discover it. It's a nice performance improvement on a printer server or if you've turned off <CODE CLASS="literal">
+wide</code> <CODE CLASS="literal">
+links</code>.</p></dd></dl></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948430">
+B.2.4 Our Recommendations </a></h3><P CLASS="para">Here's an <I CLASS="filename">
+smb.conf</i> file that incorporates the recommended performance enhancements so far. Comments have been added on the right side.</p><PRE CLASS="programlisting">
+[global]
+ log level = 1 # Default is 0
+ socket options = TCP_NODELAY IPTOS_LOWDELAY
+ read raw = yes # Default
+ write raw = yes # Default
+ oplocks = yes # Default
+ max xmit = 65535 # Default
+ dead time = 15 # Default is 0
+ getwd cache = yes
+ lpq cache = 30
+[okplace]
+ veto oplock files = this/that/theotherfile
+[badplace]
+ oplocks = no</pre></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_01.html" TITLE="B.1 A Simple Benchmark">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.1 A Simple Benchmark" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_03.html" TITLE="B.3 Sizing Samba Servers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: B.3 Sizing Samba Servers" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+B.1 A Simple Benchmark</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+B.3 Sizing Samba Servers</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appb_03.html b/docs/htmldocs/using_samba/appb_03.html
new file mode 100644
index 00000000000..115be4daa37
--- /dev/null
+++ b/docs/htmldocs/using_samba/appb_03.html
@@ -0,0 +1,876 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix B] B.3 Sizing Samba Servers</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:42:12Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_02.html" TITLE="B.2 Samba Tuning">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.2 Samba Tuning" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="appendix" REL="up" HREF="appb_01.html" TITLE="B. Samba Performance Tuning">
+Appendix B<br>
+Samba Performance Tuning</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appc_01.html" TITLE="C. Samba Configuration Option Quick Reference">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: C. Samba Configuration Option Quick Reference" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="appb-22511">
+B.3 Sizing Samba Servers</a></h2><P CLASS="para">Sizing is a way to prevent bottlenecks before they occur. The preferred way to do this is to know how many requests per second or how many kilobytes per second the clients will need, and ensure that all the components of the server provide at least that many.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948449">
+B.3.1 The Bottlenecks</a></h3><P CLASS="para">The three primary bottlenecks you should worry about are CPU, disk I/O, and the network. For most machines, CPUs are rarely a bottleneck. A single Sun SPARC 10 CPU can start (and complete) between 700 and 800 I/O operations a second, giving approximately 5,600 to 6,400KB/s of throughput when the data averages around 8KBs (a common buffer size). A single Intel Pentium 133 can do less only because of somewhat slower cache and bus interfaces, not due to lack of CPU power. Purpose-designed Pentium servers, like some Compaq servers, will be able to start 700 operations per CPUs, on up to four CPUs.</p><P CLASS="para">
+Too little memory, on the other hand, can easily be a bottleneck; each Samba process will use between 600 and 800KB on Intel Linux, and more on RISC CPUs. Having less will cause an increase in virtual memory paging and therefore a performance hit. On Solaris, where it has been measured, <EM CLASS="emphasis">
+smbd</em> will use 2.6 MB for program and shared libraries, plus 768KB for each connected client. <EM CLASS="emphasis">
+nmbd</em> occupies 2.1 MB, plus 496KB extra for its (single) auxiliary process.</p><P CLASS="para">
+Hard disks will always bottleneck at a specific number of I/O operations per second: for example, each 7200 RPM SCSI disk is capable of performing 70 operations per second, for a throughput of 560KB/s; a 4800 RPM disk will perform fewer than 50, for a throughput of 360KB/s. A single IDE disk will do still fewer. If the disks are independent, or striped together in a RAID 1 configuration, they will each peak out at 400 to 560KB/s and will scale linearly as you add more. Note that this is true only of RAID 1. RAID levels other than 1 (striping) add extra overhead. </p><P CLASS="para">
+Ethernets (and other networks) are obvious bottleneck: a 10 Mb/s (mega<EM CLASS="emphasis">
+bits</em>/second) Ethernet will handle around 1100KB/s (kilo<EM CLASS="emphasis">
+bytes</em>/s) using 1500-byte packets A 100 Mb/s Fast Ethernet will bottleneck below 65,000KB/s with the same packet size. FDDI, at 155 Mb/s will top out at approximately 6,250KB/s, but gives good service at even 100 percent load and transmits much larger packets (4KB).</p><P CLASS="para">
+ATM should be much better, but as of the writing of this book it was too new to live up to its potential; it seems to deliver around 7,125 Mb/s using 9KB packets. </p><P CLASS="para">
+Of course, there can be other bottlenecks: more than one IDE disk per controller is not good, as are more than three 3600 SCSI-I disks per slow/narrow controller, or more than three 7200 SCSI-II disks per SCSI-II fast/wide controller. RAID 5 is also slow, as it requires twice as many writes as independent disks or RAID 1.</p><P CLASS="para">
+After the second set of Ethernets and the second disk controller, start worrying about bus bandwidth, especially if you are using ISA/EISA buses.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948459">
+B.3.2 Reducing Bottlenecks </a></h3><P CLASS="para">From the information above we can work out a model that will tell us the maximum capability of a given machine. The data is mostly taken from Brian Wong's <CITE CLASS="citetitle">
+Configuration and Capacity Planning for Solaris Servers</cite>,<CITE CLASS="citetitle">
+[<A CLASS="footnote" HREF="#appb-pgfId-951214">1</a>]</cite> so there is a slight Sun bias to our examples.</p><P CLASS="para">
+A word of warning: this is not a complete model. Don't assume that this model will predict every bottleneck or even be within 10 percent in its estimates. A model to predict performance instead of one to warn you of bottlenecks would be much more complex and would contain rules like "not more than three disks per SCSI chain". (A good book on real models is Raj Jain's <CITE CLASS="citetitle">
+The Art of Computer Systems Performance Analysis</cite>.[<A CLASS="footnote" HREF="#appb-pgfId-951230">2</a>]) With that warning, we present the system in <A CLASS="xref" HREF="appb_03.html#appb-98866">
+Figure B.2</a>. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="appb-pgfId-951230">[2]</a> See Jain. Raj, <EM CLASS="emphasis">
+The Art of Computer Systems Performance Analysis</em>, New York, NY (John Wiley and Sons), 1991, ISBN 0-47-150336-3.</p></div></blockquote><H4 CLASS="figure">
+<A CLASS="title" NAME="appb-98866">
+Figure B.2: Data flow through a Samba server, with possible bottlenecks</a></h4><IMG CLASS="graphic" SRC="figs/sam.ab02.gif" ALT="Figure B.2"><P CLASS="para">
+The flow of data should be obvious. For example, on a read, data flows from the disk, across the bus, through or past the CPU, and to the network interface card (NIC). It is then broken up into packets and sent across the network. Our strategy here is to follow the data through the system and see what bottlenecks will choke it off. Believe it or not, it's rather easy to make a set of tables that list the maximum performance of common disks, CPUs, and network cards on a system. So that's exactly what we're going to do.</p><P CLASS="para">
+Let's take a concrete example: a Linux Pentium 133 MHz machine with a single 7200 RPM data disk, a PCI bus, and a 10-Mb/s Ethernet card. This is a perfectly reasonable server. We start with <A CLASS="xref" HREF="appb_03.html#appb-78077">
+Table B.2</a>, which describes the hard drive&nbsp;- the first potential bottleneck in the system. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-78077">
+Table B.2: Disk Throughput </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Disk RPM</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+I/O Operations/second</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+KB/second</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+7200</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+70</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+560</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4800</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+60</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+480</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3600</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+40</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+320</p></td></tr></tbody></table><P CLASS="para">
+Disk throughput is the number of kilobytes of data that a disk can transfer per second. It is computed from the number of 8KB I/O operations per second a disk can perform, which in turn is strongly influenced by disk RPM and bit density. In effect, the question is: how much data can pass below the drive heads in one second? With a single 7200 RPM disk, the example server will give us 70 I/O operations per second at roughly 560KB/s.</p><P CLASS="para">
+The second possible bottleneck is the CPU. The data doesn't actually flow through the CPU on any modern machines, so we have to compute throughput somewhat indirectly.</p><P CLASS="para">
+The CPU has to issue I/O requests and handle the interrupts coming back, then transfer the data across the bus to the network card. From much past experimentation, we know that the overhead that dominates the processing is consistently in the filesystem code, so we can ignore the other software being run. We compute the throughput by just multiplying the (measured) number of file I/O operations per second that a CPU can process by the same 8K average request size. This gives us the results shown in <A CLASS="xref" HREF="appb_03.html#appb-42029">
+Table B.3</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-42029">
+Table B.3: CPU Throughput </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+CPU</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+I/O Operations/second</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+KB/second</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Intel Pentium 133</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+700</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+5,600</p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Dual Pentium 133</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1,200</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+9,600</p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sun SPARC II</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+660</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+5,280</p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sun SPARC 10</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+750</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6,000</p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sun Ultra 200</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2,650</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+21,200</p>
+</td></tr></tbody></table><P CLASS="para">
+Now we put the disk and the CPU together: in the Linux example, we have a single 7200 RPM disk, which can give us 560KB/s, and a CPU capable of starting 700 I/O operations, which could give us 5600KB/s. So far, as you would expect, our bottleneck is clearly going to be the hard disk.</p><P CLASS="para">
+The last potential bottleneck is the network. If the network speed is below 100 Mb/s, the bottleneck will be the network speed. After that, the design of the network card is more likely to slow us down. <A CLASS="xref" HREF="appb_03.html#appb-67604">
+Table B.4</a> shows us the average throughput of many types of data networks. Although network speed is conventionally measured in bits per second, <A CLASS="xref" HREF="appb_03.html#appb-67604">
+Table B.4</a> lists bytes per second to make comparison with the disk and CPU (<A CLASS="xref" HREF="appb_03.html#appb-78077">Table B.2</a> and <A CLASS="xref" HREF="appb_03.html#appb-42029">
+Table B.3</a>) easier.</p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-67604">
+Table B.4: Network Throughput </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Type</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+KB/second</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ ISDN </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 16 </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ T1 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 197 </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ Ethernet 10m </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 1,113 </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ Token ring </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 1,500 </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ FDDI </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 6,250 </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ Ethernet 100m </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 6,500[<A CLASS="footnote" HREF="#appb-pgfId-960131">3</a>]</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ ATM 155 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ 7,125a </p></td></tr></tbody></table><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="appb-pgfId-960131">[3]</a> These will increase. For example, Crays, Sun Ultras, and DEC/Compaq Alphas already have bettered these figures.</p></div></blockquote><P CLASS="para">
+In the running example, we have a bottleneck at 560KB/s due to the disk. <A CLASS="xref" HREF="appb_03.html#appb-67604">
+Table B.4</a> shows us that a standard 10 megabit per second Ethernet (1,113KB/s) is far faster than the disk. Therefore, the hard disk is still the limiting factor. (This scenario, by the way, is very common.) Just by looking at the tables, we can predict that small servers won't have CPU problems, and that large ones with multiple CPUs will support striping and multiple Ethernets long before they start running out of CPU power. This, in fact, is exactly what happens.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948657">
+B.3.3 Practical Examples</a></h3><P CLASS="para">
+An example from <EM CLASS="emphasis">
+Configuration and Capacity Planning for Solaris Servers</em> (Wong) shows that a dual-processor SPARCstation 20/712 with four Ethernets and six 2.1 GB disks will spend all its time waiting for the disks to return some data. If it was loaded with disks (Brian Wong suggests as many as 34 of them), it would still be held below 1,200KB/s by the Ethernet cards. To get the performance the machine is capable of, we would need to configure multiple Ethernets, 100 Mbps Fast Ethernet, or 155 Mbps FDDI. </p><P CLASS="para">
+The progression you'd work through to get that conclusion looks something like <A CLASS="xref" HREF="appb_03.html#appb-26613">
+Table B.5</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-26613">
+Table B.5: Tuning a Medium-Sized Server </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Machine</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Disk Throughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+CPU Throughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Throughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Actual Throughput</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Dual SPARC 10, 1 disk </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+560</em></p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6000 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1,113 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+560 </p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Add 5 more disks </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3,360 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6000</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+1,113 </em></p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1,113 </p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Add 3 more Ethernets </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+3,360 </em></p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+16000</p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4,452 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3,360 </p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Change to using a 20-disk array </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+11,200 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6000 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+4,452</em> </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4,452 </p>
+</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Use dual 100 Mbps ether </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+11,200 </em></p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6000 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+13,000 </p>
+</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+11,200</p>
+</td></tr></tbody></table><P CLASS="para">
+Initially, the bottleneck is the disk with only 560 MB/s of throughput available. Our solution is to add five more disks. This gives us more throughput on the disks than on the Ethernet, so then the Ethernet becomes the problem. Consequently, as we continue to expand, we go back and forth several times between these two. As you add disks, CPUs, and network cards, the bottleneck moves. Essentially, the strategy is to add more equipment to try to avoid each bottleneck until you reach your target performance, or (unfortunately) you either can't add any more or run out of money.</p><P CLASS="para">
+Our experience bears out this kind of calculation; a large SPARC 10 file server that one author maintained was quite capable of saturating an Ethernet plus about a third of an FDDI ring when using two processors. It did nearly as well with a single processor, albeit with a fast operating system and judicious over-optimization.</p><P CLASS="para">
+The same process applies to other brands of purpose-designed servers. We found the same rules applied to DECstation 2100s as to the newest Alphas or Compaqs, old MIPS 3350s and new SGI O2s. In general, a machine offering multi-CPU server configurations will have enough bus bandwidth and CPU power to reliably bottleneck on hard disk I/O when doing file service. As one would hope, considering the cost!</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-pgfId-948730">
+B.3.4 How Many Clients can Samba Handle?</a></h3><P CLASS="para">
+Well, that depends entirely on how much data each user consumes. A small server with three SCSI-1 disks, which can serve about 960KB/s of data, will support between 36 and 80 clients in an ordinary office environment where they are typically loading, and saving equal-sized spreadsheets or word processing documents (36 clients × 2.3 transfers/second × 12k file 1 MB/s).</p><P CLASS="para">
+On the same server in a development environment with programmers running a fairly heavy edit-compile-test cycle, one can easily see requests for 1 MB/s, limiting the server to 25 or fewer clients. To take this a bit further, an imaging system whose clients each require 10 MB/s will perform poorly no matter how big a server is if they're all on a 10 MB/s Ethernet. And so on. </p><P CLASS="para">
+If you don't know how much data an average user consumes, you can size your Samba servers by patterning them after existing NFS, Netware, or LAN Manager servers. You should be especially careful that the new servers have as many disks and disk controllers as the ones you've copied. This technique is appropriately called "punt and hope."</p><P CLASS="para">
+If you know how many clients an existing server can support, you're in <EM CLASS="emphasis">
+much</em> better shape. You can analyze the server to see what its maximum capacity is and use that to estimate how much data they must be demanding. For example, if serving home directories to 30 PCs from a PC server with two IDE disks is just too slow, and 25 clients is about right, then you can safely assume you're bottlenecked on Ethernet I/O (approximately 375KB) rather than disk I/O (up to 640KB). If so, you can then conclude that the clients are demanding 15 (that is, 375/25)KB/s on average.</p><P CLASS="para">
+Supporting a new lab of 75 clients will mean you'll need 1,125KB/s, spread over multiple (preferably three) Ethernets, and a server with at least three 7200 RPM disks and a CPU capable of keeping up. These requirements can be met by a Pentium 133 or above with the bus architecture to drive them all at full speed (e.g., PCI).</p><P CLASS="para">
+A custom-built PC server or a multiprocessor-capable workstation like a Sun Sparc, a DEC/Compaq Alpha, an SGI, or the like, would scale up easier, as would a machine with fast Ethernet, plus a switching hub to drive the client machines on individual 10 MB/s Ethernets.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="appb-pgfId-948739">
+B.3.4.1 How to guess</a></h4><P CLASS="para">
+If you have no idea at all what you need, the best thing is to try to guess based on someone else's experience. Each individual client machine can average from less than 1 I/O per second (normal PC or Mac used for sales/accounting) to as much as 4 (fast workstation using large applications). A fast workstation running a compiler can happily average 3-4 MB/s in data transfer requests, and an imaging system can demand even more. </p><P CLASS="para">
+Our recommendation? Spy on someone with a similar configuration and try to estimate their bandwidth requirements from their bottlenecks and the volume of the screams from their users. We also recommend Brian Wong's <CITE CLASS="citetitle">
+Configuration and Capacity Planning for Solaris Servers</cite>. While he uses Sun Solaris foremost in his examples, his bottlenecks are disks and network cards, which are common among all the major vendors. His tables for FTP servers also come very close to what we calculated for Samba servers, and make a good starting point.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="appb-90359">B.3.5 Measurement Forms</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="appb_03.html#appb-82208">Table B.6</a> and <A CLASS="xref" HREF="appb_03.html#appb-34846">
+Table B.7</a> are empty tables that you can use for copying and recording data. The bottleneck calculation in the previous example can be done in a spreadsheet, or manually with Table B-8. If Samba is as good as or better than FTP, and if there aren't any individual test runs that are much different from the average, you have a well-configured system. If loopback isn't much faster than anything else, you have a problem with your TCP/IP software. If both FTP and Samba are slow, you probably have a problem with your networking: a faulty Ethernet card will produce this, as will accidentally setting an Ethernet card to half-duplex when it's not connected to a half-duplex hub. Remember that CPU and disk speeds are commonly measured in bytes, network speeds in bits. </p><P CLASS="para">
+We've included columns for both bytes and bits in the tables. In the last column, we compare results to 10 Mb/s because that's the speed of a traditional Ethernet. <EM CLASS="emphasis">
+ </em></p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-82208">
+Table B.6: Ethernet Interface to Same Host: FTP </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Run No</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Size in Bytes</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Time (sec) </p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bytes/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bits/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+% of 10 Mb/s</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+5</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Average:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deviation:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr></tbody></table><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-34846">
+Table B.7: Ethernet Interface to Same Host: FTP </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Run No</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Size in Bytes</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Time, sec </p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bytes/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bits/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+% of 10 Mb/s</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+5</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Average:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deviation:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr></tbody></table><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-51003">
+Table B.8: Bottleneck Calculation Table</a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+CPU</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+CPUThroughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Number of Disks</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Disk Throughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Number of Networks</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Throughput</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Total Throughput</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr></tbody></table><P CLASS="para">
+In <A CLASS="xref" HREF="appb_03.html#appb-51003">
+Table B.8</a>:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-960325">
+</a>CPU throughput = (KB/second from Figure 6-5) × (number of CPUs)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-960301">
+</a>Disk throughput = (KB/second from Figure 6-4) × (number of disks)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-960305">
+</a>Network throughput = (KB/second from Figure 6-6) × (number of networks)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="appb-pgfId-960306">
+</a>Total throughput = min (Disk, CPU, and Network throughput)</p></li></ul><P CLASS="para">
+A typical test, in this case for an FTP <CODE CLASS="literal">
+get</code>, would be entered as in Table B-9: <EM CLASS="emphasis">
+ </em> </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appb-37370">
+Table B.9: Ethernet Interface to Same Host: FTP </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Run No</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Size in Bytes</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Time, sec </p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bytes/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Bits/sec</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+% of 10 Mb/s</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1812898</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+761580</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+767820</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.4</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+747420</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+760020</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+5</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+772700</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Average:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2.32</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+777310</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+6218480</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+62</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deviation:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+0.04</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr></tbody></table><P CLASS="para">
+The Sparc example we used earlier would look like Table B-10. <EM CLASS="emphasis">
+ </em> </p><P CLASS="para">
+</p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_02.html" TITLE="B.2 Samba Tuning">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.2 Samba Tuning" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appc_01.html" TITLE="C. Samba Configuration Option Quick Reference">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: C. Samba Configuration Option Quick Reference" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+B.2 Samba Tuning</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+C. Samba Configuration Option Quick Reference</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appc_01.html b/docs/htmldocs/using_samba/appc_01.html
new file mode 100644
index 00000000000..cd9d1ede353
--- /dev/null
+++ b/docs/htmldocs/using_samba/appc_01.html
@@ -0,0 +1,3497 @@
+<HTML>
+<HEAD>
+<TITLE>[Appendix C] Samba Configuration Option Quick Reference</title>
+</head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_03.html" TITLE="B.3 Sizing Samba Servers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.3 Sizing Samba Servers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix C</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="D. Downloading Samba with CVS">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: D. Downloading Samba with CVS" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="appendix">
+<A CLASS="title" NAME="appc-23653">
+C. Samba Configuration Option Quick Reference</a></h1><P CLASS="para">The following pages list each of the Samba configuration options. If an option is applicable only to the global section, "[global]" will appear before its name. Any lists mentioned are space separated, except where noted. A glossary of terms follows the options.</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>admin users = user list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: user list</p>
+
+<P CLASS="para">
+List of users who will be granted root permissions on the share by Samba.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>allow hosts = host list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: any</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+hosts allow</code>. List of machines that may connect to a share.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>alternate permissions = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Obsolete. Has no effect in Samba 2. Files will be shown as read-only if the owner can't write them. In Samba 1.9 and earlier, setting this option would set the DOS filesystem read-only attribute on any file the user couldn't read. This in turn required the <CODE CLASS="literal">
+delete readonly</code> option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] announce as = system type</i></b>
+<P CLASS="refpurpose">Default: NT</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NT, Win95, WfW</p>
+
+<P CLASS="para">
+Have Samba announce itself as something other than an NT server. Discouraged because it interferes with serving browse lists.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] announce version = number.number</i></b>
+<P CLASS="refpurpose">Default: 4.2</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: any</p>
+
+<P CLASS="para">
+Instructs Samba to announce itself as an older version SMB server. Discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] auto services = share list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: any shares</p>
+
+<P CLASS="para">
+List of shares that will always appear in browse lists. A synonym is <CODE CLASS="literal">
+preload</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>available = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to NO, denies access to a share. Doesn't affect browsing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] bind interfaces only = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, shares and browsing will be provided only on interfaces in an interfaces list (see <CODE CLASS="literal">
+interfaces</code>). New in Samba 1.9.18. If you set this option to YES, be sure to add 127.0.0.1 to the interfaces list to allow <EM CLASS="emphasis">
+smbpasswd</em> to connect to the local machine to change passwords. This is a convienence option; it does not improve security.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>browsable = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allows a share to be announced in browse lists.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>blocking locks = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, honors byte range lock requests with time limits for queuing the request and retrying it until the time period expires. New in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] browse list = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Turns on/off <CODE CLASS="literal">
+browse</code> <CODE CLASS="literal">
+list</code> from this server. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] case sensitive = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, uses exactly the case the client supplied when trying to resolve a filename. If NO, matches either upper- or lowercase name. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] case sig names = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+case sensitive</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] change notify timeout = number</i></b>
+<P CLASS="refpurpose">Default: 60</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: positive number</p>
+
+<P CLASS="para">
+Sets the number of seconds between checks when a client asks for notification of changes in a directory. Introduced in Samba 2.0 to limit the performance cost of the checks. Avoid lowering.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>character set = name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: ISO8859-1, ISO8859-2, ISO8859-5, KOI8-R</p>
+
+<P CLASS="para">
+If set, translates from DOS code pages to the Western European (ISO8859-1), Eastern European (ISO8859-2), Russian Cyrillic (ISO8859-5), or Alternate Russian (KOI8-R) character set. The <CODE CLASS="literal">
+client code page</code> must be set to 850.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>client code page = name</i></b>
+<P CLASS="refpurpose">Default: 437 (US MS-DOS)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: See <a href="ch08_03.html#ch08-20815"><b>Table 8.4</b></a></p>
+
+<P CLASS="para">
+Sets the DOS code page explicitly, overriding any previous <CODE CLASS="literal">
+valid chars</code> settings. Examples of values are 850 for European, 437 is the US standard, and 932 for Japanese Shift-JIS. Introduced in Samba 1.9.19.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>coding system = code</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: euc, cap, hex, hexN, sjis, j8bb, j8bj, jis8, j8bh, j8@b, j8@j, j8@h, j7bb, j7bj, jis7, j7bh, j7@b, j7@j, j7@h, jubb, jubj, junet, jubh, ju@b, ju@j, ju@h</p>
+
+<P CLASS="para">
+Sets the coding system used, notably for Kanji. This is employed for filenames and should correspond to the code page in use. The <CODE CLASS="literal">
+client code page</code> option must be set to 932 (Japanese Shift-JIS). Introduced in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>comment = text</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: a text string or NULL</p>
+
+<P CLASS="para">
+Sets the comment that appears beside a share in a NET VIEW or the details list of a Microsoft directory window. See also the <CODE CLASS="literal">
+server string</code> configuration option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] config file = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Selects an additional Samba configuration file to read instead of the current one. Used to relocate the configuration file, or used with %-variables to select custom configuration files for some users or machines. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>copy = section name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: existing section's name</p>
+
+<P CLASS="para">
+Copies the configuration of a previously seen share into the share where it appears. Used with %-variables to select custom configurations for machines, architectures and users. The copied section must be earlier in the configuration file. Copied options are of lesser priority than those explicitly listed in the section.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>create mask = octal value</i></b>
+<P CLASS="refpurpose">Default: 0744</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal permission bits, 0-0777</p>
+
+<P CLASS="para">
+Also called <CODE CLASS="literal">
+create mode</code>. Sets the maximum allowable permissions for new files (e.g., 0755). See also <CODE CLASS="literal">
+directory mask</code>. To require certain permissions to be set, see <CODE CLASS="literal">
+force create mask/force directory mask</code>. This option stopped affecting directories in Samba 1.9.17, and the default value changed in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>create mode = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0744</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal permission bits, 0-0777</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+create mask</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] deadtime = minutes</i></b>
+<P CLASS="refpurpose">Default: 0 </p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: minutes</p>
+
+<P CLASS="para">
+The time in minutes before an unused connection will be terminated. Zero means forever. Used to keep clients from tying up server resources forever. If used, clients will have to auto-reconnect after minutes of inactivity. See also <CODE CLASS="literal">
+keepalive</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] debug level = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets the logging level used. Values of 3 or more slow Samba noticeably. A synonym is <CODE CLASS="literal">
+log level</code>. Recommended value: 1.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] debug timestamp = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Timestamps all log messages. Can be turned off when it's not useful (e.g., in debugging). New in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] default = name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: share name</p>
+
+<P CLASS="para">
+Also called <CODE CLASS="literal">
+default service</code>. The name of a service (share) to provide if someone requests a service they don't have permission to use or which doesn't exist. As of Samba 1.9.14, the path will be set from the name the client specified, with any "_" characters changed to "/" characters, allowing access to any directory on the Samba server. Use is strongly discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>default case = case</i></b>
+<P CLASS="refpurpose">Default: LOWER</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: LOWER, UPPER</p>
+
+<P CLASS="para">
+Sets the case in which to store new filenames. LOWER indicates mixed case, UPPER indicates uppercase letters.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] default service = share name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: share name</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+default</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>delete readonly = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NO, YES</p>
+
+<P CLASS="para">
+Allow delete requests to remove read-only files. This is not allowed in DOS/Windows, but is normal in Unix, which has separate directory permissions. Used with programs like RCS, or with the older <CODE CLASS="literal">
+alternate permissions</code> option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>delete veto files = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NO, YES</p>
+
+<P CLASS="para">
+Allow delete requests for a directory containing files or subdirectories the user can't see due to the <CODE CLASS="literal">
+veto files</code> option. If set to NO, the directory will not be deleted and will still contain invisible files.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>deny hosts = host list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: host list</p>
+
+<P CLASS="para">
+A synonym is <CODE CLASS="literal">
+hosts deny</code>. Specifies a list of machines from which to refuse connections or shares.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] dfree command = command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: shell command</p>
+
+<P CLASS="para">
+A command to run on the server to return disk free space. Not needed unless the OS command does not work properly.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>directory = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+path</code>. A directory provided by a file share, or used by a printer share. Set automatically in the <CODE CLASS="literal">
+[homes]</code> share to user's home directory, otherwise defaults to<I CLASS="filename">
+ /tmp</i>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>directory mask = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0755</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Also called <CODE CLASS="literal">
+directory mode</code>. Sets the maximum allowable permissions for newly created directories. To require certain permissions be set, see the <CODE CLASS="literal">
+force create mask</code> and <CODE CLASS="literal">
+force directory mask</code> options.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>directory mode = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0755</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+directory mask</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] dns proxy = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, and if <CODE CLASS="literal">
+wins server = YES</code>, look up hostnames in DNS if they are not found using WINS.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] domain logons = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allow Windows 95/98 or NT clients to log on to an NT-like domain.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] domain master = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Become a domain master browser list collector if possible for the entire workgroup/domain. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>dont descend = comma-list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: comma-separated list of paths</p>
+
+<P CLASS="para">
+Does not allow a change directory or search in the directories specified. This is a browsing convenience option; it doesn't provide any extra security.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>dos filetimes = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allow non-owners to change file times if they can write to the file. See also <CODE CLASS="literal">
+dos filetime resolution</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>dos filetime resolution = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Set file times on Unix to match DOS standards (round to next even second). Recommended if using Visual C++ or a PC <EM CLASS="emphasis">
+make</em> program to avoid remaking the programs unnecesarily. Use with the <CODE CLASS="literal">
+dos filetimes</code> option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] encrypt passwords = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Uses Windows NT-style password encryption. Requires an <I CLASS="filename">
+smbpasswd</i> on the Samba server.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>exec = command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: shell command</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+preexec</code>, a command to run as the user just before connecting to the share.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>fake directory create times = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Bug fix for users of Microsoft <EM CLASS="emphasis">
+nmake</em>. If set, Samba will set directory create times such that <EM CLASS="emphasis">
+nmake</em> won't remake all files every time.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>fake oplocks = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Return YES whenever a client asks if it can lock a file and cache it locally, but does not enforce lock on the server. Use only for read-only disks, as Samba now supports real <CODE CLASS="literal">
+oplocks</code> and has per-file overrides. See also <CODE CLASS="literal">
+oplocks</code> and <CODE CLASS="literal">
+veto oplock files</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>follow symlinks = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, Samba will follow symlinks in a file share or shares. See the <CODE CLASS="literal">
+wide links</code> option if you want to restrict symlinks to just the current share.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force create mask = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Provides bits that will be <CODE CLASS="literal">
+OR</code>ed into the permissions of newly created files. Used with the <CODE CLASS="literal">
+create mode</code> configuration option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force create mode = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+force create mask</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force directory mask = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Provides bits that will be <CODE CLASS="literal">
+OR</code>ed into the permissions of newly created directories, forcing those bits to be set. Used with <CODE CLASS="literal">
+directory mode</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force directory mode = octal permission bits</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: octal value from 0 to 0777</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+mask</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force group = unix group</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: group</p>
+
+<P CLASS="para">
+Sets the effective group name assigned to all users accessing a share. Used to override user's normal groups.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>force user = name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: username</p>
+
+<P CLASS="para">
+Sets the effective username assigned to all users accessing a share. Discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>fstype = string</i></b>
+<P CLASS="refpurpose">Default: NTFS</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NTFS, FAT, Samba</p>
+
+<P CLASS="para">
+Sets the filesystem type reported to the client. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] getwd cache = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Cache current directory for performance. Recommended with the <CODE CLASS="literal">
+wide links</code> option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>group = group</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: unix group</p>
+
+<P CLASS="para">
+An obsolete form of <CODE CLASS="literal">
+force group</code>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>guest account = user</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: username</p>
+
+<P CLASS="para">
+Sets the name of the unprivileged Unix account to use for tasks like printing and for accessing shares marked with <CODE CLASS="literal">
+guest ok</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>guest ok = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, passwords are not needed for this share. Synonym of <CODE CLASS="literal">
+public</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>guest only = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Forces user of a share to do so as the guest account. Requires <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> or <CODE CLASS="literal">
+public</code> to be <CODE CLASS="literal">
+yes</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>hide dot files = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Treats files beginning with a dot in a share as if they had the DOS/Windows hidden attribute set.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>hide files = slash-separated list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of patterns, separated by <CODE CLASS="literal">
+/</code> characters</p>
+
+<P CLASS="para">
+List of file or directory names to set the DOS hidden attribute on. Names may contain <CODE CLASS="literal">
+?</code> or <CODE CLASS="literal">
+*</code> pattern-characters and <CODE CLASS="literal">
+%</code>-variables. See also <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+dot</code> <CODE CLASS="literal">
+files</code> and <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+files</code>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] homedir map = NIS map name</i></b>
+<P CLASS="refpurpose">Default: auto.home</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NIS map name</p>
+
+<P CLASS="para">
+Used with <CODE CLASS="literal">
+nis homedir</code> to locate user's Unix home directory from Sun NIS (not NIS+).</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>hosts allow = host list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of hostnames</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+allow hosts</code>, a list of machines that can access a share or shares. If NULL (the default) any machine can access the share unless there is a <CODE CLASS="literal">
+hosts deny</code> option. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>hosts deny = host list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of hostnames</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+deny hosts</code>, a list of machines that cannot connect to a share or shares. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] hosts equiv = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Path to a file of trusted machines from which password-less logins are allowed. Strongly discouraged, because Windows/NT users can always override the user name, the only security in this scheme.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>include = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Include the named file in <I CLASS="filename">
+smb.conf</i> at the line where it appears. This option does not understand the variables <CODE CLASS="literal">
+%u</code> (user), <CODE CLASS="literal">
+%P</code> (current share's root directory), or <CODE CLASS="literal">
+%S</code> (current share name), because they are not set at the time the file is read.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- added for 2.0.7,. davecb -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>inherit permissions = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set, subdirectories will be created with the same permissions
+as the directory they are in. This overrides
+<CODE CLASS="literal">create mask, directory mask, force create mode
+</CODE> and <CODE CLASS="literal"> force directory mode</CODE>, but
+not <CODE CLASS="literal">map archive, map hidden </CODE> and <CODE CLASS="literal">
+map system</CODE>. Will never set the <CODE CLASS="literal">setuid
+</CODE> bit. New in 2.0.7, this is a means of ensuring Unix permissions
+can be propagated to subdirectories, especially in [homes].<p>
+
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- end of 2.0.7 -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] interfaces = interface list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: IP addresses separated by spaces</p>
+
+<P CLASS="para">
+Sets the interfaces to which Samba will respond. The default is the machine's primary interface only. Recommended on multihomed machines or to override erroneous addresses and netmasks.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>invalid users = user list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of users</p>
+
+<P CLASS="para">
+List of users that will not be permitted access to a share or shares. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] keepalive = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number of seconds</p>
+
+<P CLASS="para">
+Number of seconds between checks for a crashed client. The default of 0 causes no checks to be performed. Recommended if you want checks more often than every four hours. 3600 (10 minutes) is reasonable. See also <CODE CLASS="literal">
+socket options</code> for another approach.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] kernel oplocks = boolean</i></b>
+<P CLASS="refpurpose">Default: automatic</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Break oplock when a Unix process accesses an <EM CLASS="emphasis">
+oplocked</em> file, preventing corruption. Set to YES on operating systems supporting this, otherwise set to NO. New in Samba 2.0; supported on SGI, and hopefully soon on Linux and BSD. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] ldap filter = various</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: various</p>
+
+<P CLASS="para">
+Options beginning with <CODE CLASS="literal">
+ldap</code> are part of an experimental (circa Samba 2.0) use of the Lightweight Directory Access Protocol (LDAP) general directory/distributed database for user, name, and host information. This option is reserved for future use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] ldap port = various</i></b>
+<P CLASS="refpurpose">Default: various</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: various</p>
+
+<P CLASS="para">
+Options beginning with <CODE CLASS="literal">
+ldap</code> are part of an experimental (circa Samba 2.0) use of the Lightweight Directory Access Protocol (LDAP) general directory/distributed database for user, name, and host information. This option is reserved for future use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] ldap root = various</i></b>
+<P CLASS="refpurpose">Default: various</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: various</p>
+
+<P CLASS="para">
+Options beginning with <CODE CLASS="literal">
+ldap</code> are part of an experimental (circa Samba 2.0) use of the Lightweight Directory Access Protocol (LDAP) general directory/distributed database for user, name, and host information. This option is reserved for future use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] ldap server = various</i></b>
+<P CLASS="refpurpose">Default: various</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: various</p>
+
+<P CLASS="para">
+Options beginning with <CODE CLASS="literal">
+ldap</code> are part of an experimental (circa Samba 2.0) use of the Lightweight Directory Access Protocol (LDAP) general directory/distributed database for user, name, and host information. This option is reserved for future use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] ldap suffix = various</i></b>
+<P CLASS="refpurpose">Default: various</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: various</p>
+
+<P CLASS="para">
+Options beginning with <CODE CLASS="literal">
+ldap</code> are part of an experimental (circa Samba 2.0) use of the Lightweight Directory Access Protocol (LDAP) general directory/distributed database for user, name, and host information. This option is reserved for future use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] load printers = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Load all printer names from the system printer capabilities into browse list. Uses configuration options from the <CODE CLASS="literal">
+[printers]</code> section.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] local master = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Stands for election as the local master browser. See also <CODE CLASS="literal">
+domain master</code> and <CODE CLASS="literal">
+os level</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] lm announce = value</i></b>
+<P CLASS="refpurpose">Default: AUTO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: AUTO, YES, NO</p>
+
+<P CLASS="para">
+Produce OS/2 SMB broadcasts at an interval specified by the <CODE CLASS="literal">
+lm interval</code> option. YES/NO turns them on/off unconditionally. AUTO causes the Samba server to wait for a LAN Manager announcement from another client before sending one out. Required for OS/2 client browsing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] lm interval = seconds</i></b>
+<P CLASS="refpurpose">Default: 60</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets the time period, in seconds, between OS/2 SMB broadcast announcements.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] lock directory = pathname</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+/usr/local/samba/var/locks</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Set a directory to keep lock files in. The directory must be writable by Samba, readable by everyone.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>locking = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Perform file locking. If set to NO, Samba will accept lock requests but will not actually lock resources. Recommended only for read-only file systems.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] log file = pathname</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Set name and location of the log file. Allows all %-variables.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] log level = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+A synonym of <CODE CLASS="literal">
+debug level</code>. Sets the logging level used. Values of 3 or more slow the system noticeably.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] logon drive = drive</i></b>
+<P CLASS="refpurpose">Default: None</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: DOS drive name</p>
+
+<P CLASS="para">
+Sets the drive on Windows NT (only) of the <CODE CLASS="literal">
+logon path</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] logon home = path</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+\\</em><CODE CLASS="replaceable"><I>%</i></code></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Sets the home directory of a Windows 95/98 or NT Workstation user. Allows <CODE CLASS="literal">
+NET</code> <CODE CLASS="literal">
+USE</code> <CODE CLASS="literal">
+H:/HOME</code> from the command prompt.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] logon path = pathname</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+\\</em><CODE CLASS="replaceable"><I>N</i></code><EM CLASS="emphasis">\</em><CODE CLASS="replaceable"><I>%U</i></code><EM CLASS="emphasis">\profile</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Windows pathname</p>
+
+<P CLASS="para">
+Sets path to Windows profile directory. This contains <EM CLASS="emphasis">
+USER.MAN</em> and/or <EM CLASS="emphasis">
+USER.DAT</em> profile files and the Windows 95 Desktop, Start Menu, Network Neighborhood, and programs folders. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] logon script = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Sets pathname relative to <CODE CLASS="literal">
+[netlogin]</code> share of a DOS/NT script to run on the client at login time. Allows all %-variables.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>lppause command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualfied Unix shell command</p>
+
+<P CLASS="para">
+Sets the command to pause a print job. Honors the <CODE CLASS="literal">
+%p</code> (printer name) and <CODE CLASS="literal">
+%j</code> (job number) variables. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>lpresume command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets the command to resume a paused print job. Honors the <CODE CLASS="literal">
+%p</code> (printer name) and <CODE CLASS="literal">
+%j</code> (job number) variables. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] lpq cache time = seconds</i></b>
+<P CLASS="refpurpose">Default: 10</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number of seconds</p>
+
+<P CLASS="para">
+Sets how long to keep print queue (<CODE CLASS="literal">lpq</code>) status is cached, in seconds.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>lpq command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualfied Unix shell command</p>
+
+<P CLASS="para">
+Sets the command used to get printer status. Usually initialized to a default value by the <CODE CLASS="literal">
+printing</code> option. Honors the <CODE CLASS="literal">
+%p</code> (printer name) variable.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>lprm command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets the command to delete a print job. Usually initialized to a default value by the <CODE CLASS="literal">
+printing</code> option. Honors the <CODE CLASS="literal">
+%p</code> (printer name) and <CODE CLASS="literal">
+%j</code> (job number) variables.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>machine password timeout = seconds</i></b>
+<P CLASS="refpurpose">Default: 604,800</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number of seconds</p>
+
+<P CLASS="para">
+Sets the period between (NT domain) machine password changes. Default is 1 week, or 604,800 seconds.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>magic output = pathname</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+script.out</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Sets the output file for the discouraged <CODE CLASS="literal">
+magic scripts</code> option. Default is the script name, followed by the extension <EM CLASS="emphasis">
+.out</em>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>magic script = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Sets a filename for execution via a shell whenever the file is closed from the client, to allow clients to run commands on the server. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>mangle case = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: allowable values: YES, NO</p>
+
+<P CLASS="para">
+Mangle a name if it is in mixed case.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>mangled map = map list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of to-from pairs</p>
+
+<P CLASS="para">
+Set up a table of names to remap (e.g., <EM CLASS="emphasis">
+.html</em> to <EM CLASS="emphasis">
+.htm</em>). </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>mangled names = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Sets Samba to abbreviate names that are too long or have unsupported characters to the DOS 8.3 style. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>mangling char = character</i></b>
+<P CLASS="refpurpose">Default: ~</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: character</p>
+
+<P CLASS="para">
+Sets the unique mangling character used in all mangled names.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] mangled stack = number</i></b>
+<P CLASS="refpurpose">Default: 50</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets the size of a cache of recently-mangled filenames.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>map aliasname = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Points to a file of Unix group/NT group pairs, one per line. This is used to map NT aliases to Unix group names. See also the configuration options <CODE CLASS="literal">
+username</code> <CODE CLASS="literal">
+map</code> and <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+groupname</code>. Introduced in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>map archive = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, Samba sets the executable-by-user (0100) bit on Unix files if the DOS archive attribute is set. Recommended: if used, the <CODE CLASS="literal">
+create mask</code> must contain the 0100 bit.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>map hidden = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, sets executable-by-other (0001) bit on Unix files if the DOS hidden attribute is set. If used, the <CODE CLASS="literal">
+create mask</code> option must contain the 0001 bit.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>map groupname = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Points to a file of Unix group/NT group, one per line. This is used to map NT group names to Unix group names. See also the configuration options <CODE CLASS="literal">
+username</code> <CODE CLASS="literal">
+map</code> and <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+aliasname</code>. Introduced in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>map system = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, Samba sets the executable-by-group (0010) bit on Unix files if the DOS system attribute is set. If used, the <CODE CLASS="literal">
+create mask</code> must contain the 0010 bit.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>max connections = number</i></b>
+<P CLASS="refpurpose">Default: 0 (infinity)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Set maximum number of connections allowed to a share from each individual client machine.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max disk size = number</i></b>
+<P CLASS="refpurpose">Default: 0 (unchanged)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: size in MB</p>
+
+<P CLASS="para">
+Sets maximum disk size/free-space size (in megabytes) to return to client. Some clients or applications can't understand large maximum disk sizes.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max log size = number</i></b>
+<P CLASS="refpurpose">Default: 5000</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: size in KB</p>
+
+<P CLASS="para">
+Sets the size (in kilobytes) at which Samba will start a new log file. The current log file will be renamed with an <EM CLASS="emphasis">
+.old</em> extension, replacing any previous file with that name. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max mux = number</i></b>
+<P CLASS="refpurpose">Default: 50</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets the number of simultaneous operations that Samba clients may make. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max packet = number</i></b>
+<P CLASS="refpurpose">Default: N/A</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+packet size</code>. Obsolete as of Samba 1.7. Use <CODE CLASS="literal">
+max xmit</code> instead.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max open files = number</i></b>
+<P CLASS="refpurpose">Default: 10,000</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Limits the number of files a Samba process will try to keep open at one time. Samba allows you to set this to less than the Unix maximum. This option is a workaround for a separate problem. Avoid changing. This option was introduced in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max ttl = seconds</i></b>
+<P CLASS="refpurpose">Default: 14400 (4 hrs)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: time in seconds</p>
+
+<P CLASS="para">
+Sets the time to keep NetBIOS names in <EM CLASS="emphasis">
+nmbd</em> cache while trying to perform a lookup on it. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max wins ttl = seconds</i></b>
+<P CLASS="refpurpose">Default: 259200 (3 days)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: time in seconds</p>
+
+<P CLASS="para">
+Limits time-to-live of a NetBIOS name in <EM CLASS="emphasis">
+nmbd</em> WINS cache, in seconds. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] max xmit = bytes</i></b>
+<P CLASS="refpurpose">Default: 65535</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: size in bytes</p>
+
+<P CLASS="para">
+Sets maximum packet size that will be negotiated by Samba. Tuning parameter for slow links and older client bugs. Values less than 2048 are discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] message command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: shell command</p>
+
+<P CLASS="para">
+Sets the command on the server to run when a WinPopup message arrives from a client. The command must end in "<CODE CLASS="literal">&amp;</code>" to allow immediate return. Honors all %-variables except <CODE CLASS="literal">
+%u</code> (user), and supports the extra variables <CODE CLASS="literal">
+%s</code> (filename the message is in), <CODE CLASS="literal">
+%t</code> (destination machine), and <CODE CLASS="literal">
+%f</code> (from).</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>min print space = kilobytes</i></b>
+<P CLASS="refpurpose">Default: 0 (unlimited)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: space in KB</p>
+
+<P CLASS="para">
+Sets minimum spool space required before accepting a print request.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- 2.0.7, davecb -->
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>min password length = characters</i></b>
+<P CLASS="refpurpose">Default: 5</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: decimal number of characters</p>
+
+<P CLASS="para">
+Sets the shortest password Samba will pass to the Unix passwd command.
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- sne 2.0.7 -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] min wins ttl = seconds</i></b>
+<P CLASS="refpurpose">Default: 21600 (6 hrs)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: time in seconds</p>
+
+<P CLASS="para">
+Sets minimum time-to-live of a NetBIOS name in <EM CLASS="emphasis">
+nmbd</em> WINS cache, in seconds. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>name resolve order = list</i></b>
+<P CLASS="refpurpose">Default: lmhosts wins hosts bcast</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of lmhosts, wins, hosts and bcast</p>
+
+<P CLASS="para">
+Sets order of lookup when trying to get IP address from names. The <CODE CLASS="literal">
+hosts</code> parameter carrries out a regular name look up using the server's normal sources: <EM CLASS="emphasis">
+/etc/hosts</em>, DNS, NIS, or a combination of them. Introduced in Samba 1.9.18p4.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] netbios aliases = list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of netbios names</p>
+
+<P CLASS="para">
+Adds additional NetBIOS names by which a Samba server will advertise itself.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>netbios name = hostname</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: host name</p>
+
+<P CLASS="para">
+Sets the NetBIOS name by which a Samba server is known, or primary name if NetBIOS aliases exist. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- 2.0.7, davecb -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>netbios scope = string</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: string</p>
+
+<P CLASS="para">
+Sets the NetBIOS scope string. Samba will not communicate with a machine
+with a different scope. This was an early predecessor of workgroups: avoid
+setting it. Added in 2.0.7. <!-- why was it added, anyway? -->
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- end 2.0.7 -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] networkstation user login = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to NO, clients will not do a full login when <CODE CLASS="literal">
+security = server</code>. Avoid changing. Turning it off is a temporary workaround (introduced in Samba 1.9.18p3) for NT trusted domains bug. Automatic correction was introduced in Samba 1.9.18p10; the parameter may eventually be removed.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] nis homedir = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, the <CODE CLASS="literal">
+homedir map</code> will be used to look up the user's home-directory server name and return it to the client. The client will contact that machine to connect to the share. This avoids mounting from a machine that doesn't actually have the disk. The machine with the home directories must be an SMB server.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] nt pipe support = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allows turning off NT-specific pipe calls. This is a developer/benchmarking option and may be removed in the future. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] nt smb support = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, allow NT-specific SMBs to be used. This is a developer/benchmarking option and may be removed in the future. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] null passwords = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, allows access to accounts that have null passwords. Strongly discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>ole locking compatibility = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, locking ranges will be mapped to avoid Unix locks crashing when Windows uses locks above 32KB. You should avoid changing this option. Introduced in Samba 1.9.18p10. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>only guest = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+A synonym for <CODE CLASS="literal">
+guest only</code>. Forces user of a share to login as the guest account. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>only user = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Requires that users of the share be on a <CODE CLASS="literal">
+username =</code> list. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>oplocks = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, support local caching of <EM CLASS="emphasis">
+opportunistic</em> locked files on client. This option is recommended because it improves performance by about 30%. See also <CODE CLASS="literal">
+fake</code> <CODE CLASS="literal">
+oplocks</code> and <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+oplock</code> <CODE CLASS="literal">
+files</code>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] os level = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets the candidacy of the server when electing a browse master. Used with the <CODE CLASS="literal">
+domain</code> <CODE CLASS="literal">
+master</code> or <CODE CLASS="literal">
+local</code> <CODE CLASS="literal">
+master</code> options. You can set a higher value than a competing operating system if you want Samba to win. Windows for Workgroups and Windows 95 use 1, Windows NT client uses 17, and Windows NT Server uses 33.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] packet size = bytes</i></b>
+<P CLASS="refpurpose">Default: 65535</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number in bytes</p>
+
+<P CLASS="para">
+Obsolete. Discouraged synonym of <CODE CLASS="literal">
+max packet</code>. See <CODE CLASS="literal">
+max xmit</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] passwd chat debug = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Logs an entire password chat, including passwords passed, with a log level of 100. For debugging only. Introduced in Samba 1.9.18p5.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] passwd chat = command sequence</i></b>
+<P CLASS="refpurpose">Default: compiled-in value</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix server commands</p>
+
+<P CLASS="para">
+Sets the command used to change passwords on the server. Supports the variables <CODE CLASS="literal">
+%o</code> (old password) and <CODE CLASS="literal">
+%n</code> (new password) and allows <CODE CLASS="literal">
+\r</code> <CODE CLASS="literal">
+\n</code> <CODE CLASS="literal">
+\t</code> and <CODE CLASS="literal">
+\s</code> (space) escapes in the sequence.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] passwd program = program</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix server program</p>
+
+<P CLASS="para">
+Sets the command used to change user's password. Will be run as <CODE CLASS="literal">
+root</code>. Supports <CODE CLASS="literal">
+%u</code> (user).</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] password level = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Specifies the number of uppercase letter permutations used to match passwords. Workaround for clients that change passwords to a single case before sending them to the Samba server. Causes repeated login attempts with passwords in different cases, which can trigger account lockouts. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] password server = netbios names</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of NetBIOS names</p>
+
+<P CLASS="para">
+A list of SMB servers that will validate passwords for you. Used with an NT password server (PDC or BDC) and the <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+server</code> or <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+domain</code> configuration options. Caution: an NT password server must allow logins from the Samba server.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>panic action = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualfied Unix shell command</p>
+
+<P CLASS="para">
+Sets the command to run when Samba panics. For Samba developers and testers, <CODE CLASS="literal">
+/usr/bin/X11/xterm -display :0 -e gdb /samba/bin/smbd %d</code> is a possible value.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>path = pathname</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Sets the path to the directory provided by a file share or used by a printer share. Set automatically in <CODE CLASS="literal">
+[homes]</code> share to user's home directory, otherwise defaults to<I CLASS="filename">
+ /tmp</i>. Honors the <CODE CLASS="literal">
+%u</code> (user) and <CODE CLASS="literal">
+%m</code> (machine) variables.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>postexec = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets a command to run as the user after disconnecting from the share. See also the options <CODE CLASS="literal">
+preexec</code>, <CODE CLASS="literal">
+root preexec</code>, and <CODE CLASS="literal">
+root postexec</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>postscript = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Flags a printer as PostScript to avoid a Windows bug by inserting <CODE CLASS="literal">
+%!</code> as the first line. Works only if printer actually is PostScript compatible.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>preexec = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets a command to run as the user before connecting to the share. See also the options <CODE CLASS="literal">
+postexec</code>, <CODE CLASS="literal">
+root preexec</code>, and <CODE CLASS="literal">
+root postexec</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] preferred master = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, Samba is preferred to become the master browser. Causes Samba to call a browsing election when it comes online.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>preload = share list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of services</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+auto</code> <CODE CLASS="literal">
+services</code>. Specifies a list of shares that will always appear in browse lists.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>preserve case = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, this option leaves filenames in the case sent by client. If no, it forces filenames to the case specified by the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option. See also <CODE CLASS="literal">
+short preserve case</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>print command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets the command used to send a spooled file to the printer. Usually initialized to a default value by the <CODE CLASS="literal">
+printing</code> option. This option honors the <CODE CLASS="literal">
+%p</code> (printer name), <CODE CLASS="literal">
+%s</code> (spool file) and <CODE CLASS="literal">
+%f</code> (spool file as a relative path) variables. Note that the command in the value of the option must include file deletion of the spool file.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>print ok = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+printable</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printable = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Sets a share to be a print share. Required for all printers.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] printcap name = pathname</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+/etc/printcap</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Sets the path to the printer capabilities file used by the <CODE CLASS="literal">
+[printers]</code> share. The default value changes to <I CLASS="filename">
+/etc/qconfig</i> under AIX and <I CLASS="filename">
+lpstat</i> on System V.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printer = name</i></b>
+<P CLASS="refpurpose">Default: <CODE CLASS="literal">
+lp</code></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: printer name</p>
+
+<P CLASS="para">
+Sets the name of the Unix printer.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printer driver = printer driver name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: exact printer driver string used by Windows</p>
+
+<P CLASS="para">
+Sets the string to pass to Windows when asked what driver to use to prepare files for a printer share. Note that the value is case sensitive.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] printer driver file = path</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+samba-lib/printers.def</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Sets the location of a<EM CLASS="emphasis">
+ msprint.def</em> file, usable by Windows 95/98.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printer driver location = path</i></b>
+<P CLASS="refpurpose">Default: <EM CLASS="emphasis">
+\\</em><CODE CLASS="replaceable"><I>server</i></code><EM CLASS="emphasis">\PRINTER$</em></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Windows network path</p>
+
+<P CLASS="para">
+Sets the location of the driver for a particular printer. The value is a pathname for a share that stores the printer driver files.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printer name = name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: name</p>
+
+<P CLASS="para">
+Synonym of <CODE CLASS="literal">
+printer</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>printing = style</i></b>
+<P CLASS="refpurpose">Default: bsd</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: bsd, sysv, hpux, aix, qnx, plp, lprng</p>
+
+<P CLASS="para">
+Sets printing style to one of the above, instead of the compiled-in value. This sets initial values of at least the <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code>, <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code>, <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+command</code>, and <CODE CLASS="literal">
+lprm</code> <CODE CLASS="literal">
+command</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] protocol = protocol</i></b>
+<P CLASS="refpurpose">Default: NT1</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: NT1, LANMAN2, LANMAN1, COREPLUS, CORE</p>
+
+<P CLASS="para">
+Sets SMB protocol version to one of the allowable values. Resetting is highly discouraged. Only for backwards compatibility with older-client bugs.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>public = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, passwords are not needed for this share. A synonym is <CODE CLASS="literal">
+guest ok</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>queuepause command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: valid Unix command</p>
+
+<P CLASS="para">
+Sets the command used to pause a print queue. Usually initialized to a default value by the <CODE CLASS="literal">
+printing</code> option. Introduced in Samba 1.9.18p10.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>queueresume command = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: varies</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: valid Unix command</p>
+
+<P CLASS="para">
+Sets the command used to resume a print queue. Usually initialized to a default value by the <CODE CLASS="literal">
+printing</code> option. Introduced in Samba 1.9.18p10.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>read bmpx = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Obsolete. Do not change.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>read list = comma-separated list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: comma-separated list of users</p>
+
+<P CLASS="para">
+Specifies a list of users given read-only access to a writeable share. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>read only = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Sets a share to read-only. Antonym of <CODE CLASS="literal">
+writable</code> and <CODE CLASS="literal">
+write ok</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] read prediction = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Reads ahead data for read-only files. Obsolete; removed in Samba 2.0.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] read raw = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allows fast streaming reads over TCP using 64K buffers. Recommended.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] read size = bytes</i></b>
+<P CLASS="refpurpose">Default: 2048</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: size in bytes</p>
+
+<P CLASS="para">
+Sets a buffering option for servers with mismatched disk and network speeds. Requires experimentation. Avoid changing. Should not exceed 65536.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] remote announce = remote list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of remote addresses</p>
+
+<P CLASS="para">
+Adds workgroups to the list on which the Samba server will announce itself. Specified as IP address/workgroup (for instance, 192.168.220.215/SIMPLE) with multiple groups separated by spaces. Allows directed broadcasts. The server will appear on those workgroup's browse lists. Does not require WINS.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] remote browse sync = address list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: IP-address list</p>
+
+<P CLASS="para">
+Enables Samba-only browse list synchronization with other Samba local master browsers. Addresses can be specific addresses or directed broadcasts (i.e., ###.###.###.255). The latter will cause Samba to hunt down the local master.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>revalidate = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, requires users to re-enter passwords even after a successful initial logon to a share with a password.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] root = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+root directory</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] root dir = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+root directory</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] root directory = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Specifies a directory to <CODE CLASS="literal">
+chroot()</code> to before starting daemons. Prevents any access below that directory tree. See also the <CODE CLASS="literal">
+wide links</code> configuration option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>root postexec = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets a command to run as root after disconnecting from the share. See also <CODE CLASS="literal">
+preexec</code>, <CODE CLASS="literal">
+postexec</code>, and <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+preexec</code> configuration options. Runs after the user's <CODE CLASS="literal">
+postexec</code> command. Use with caution.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>root preexec = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: fully-qualified Unix shell command</p>
+
+<P CLASS="para">
+Sets a command to run as root before connecting to the share. See also <CODE CLASS="literal">
+preexec</code>, <CODE CLASS="literal">
+postexec</code>, and <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+postexec</code> configuration options. Runs before the user's <CODE CLASS="literal">
+preexec</code> command. Use with caution.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] security = value</i></b>
+<P CLASS="refpurpose">Default: share in Samba 1.0, user in 2.0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: share, user, server, domain</p>
+
+<P CLASS="para">
+Sets password-security policy. If <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+share</code>, services have a shared password, available to everyone. If <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+user</code>, users have (Unix) accounts and passwords. If <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+server</code>, users have accounts and passwords and a separate machine authenticates them for Samba. If <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+domain</code>, full NT-domain authentication is done. See also the <CODE CLASS="literal">
+password server</code> and <CODE CLASS="literal">
+encrypted passwords</code> configuration options. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] server string = text</i></b>
+<P CLASS="refpurpose">Default: Samba <CODE CLASS="literal">
+%v</code> in 2.0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: string</p>
+
+<P CLASS="para">
+Sets the name that appears beside a server in browse lists. Honors the <CODE CLASS="literal">
+%v</code> (Samba version number) and <CODE CLASS="literal">
+%h</code> (hostname) variables.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>set directory = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allows DEC Pathworks client to use the <EM CLASS="emphasis">
+set dir</em> command.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] shared file entries = number</i></b>
+<P CLASS="refpurpose">Default: 113</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Obsolete; do not use.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>shared mem size = bytes</i></b>
+<P CLASS="refpurpose">Default: 102400</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: size in bytes</p>
+
+<P CLASS="para">
+If compiled with FAST_SHARE_MODES (mmap), sets the shared memory size in bytes. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] smb passwd file = path</i></b>
+<P CLASS="refpurpose">Default: <I CLASS="filename">
+/usr/local/samba/private/smbpasswd</i></p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: Unix pathname</p>
+
+<P CLASS="para">
+Overrides compiled-in path to password file if <CODE CLASS="literal">
+encrypted passwords</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] smbrun = /absolute_ path/command</i></b>
+<P CLASS="refpurpose">Default: compiled-in value</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: smbrun command</p>
+
+<P CLASS="para">
+Overrides compiled-in path to <I CLASS="filename">
+smbrun</i> binary. Avoid changing.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>share modes = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, this option supports Windows-style whole-file (deny mode) locks.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>short preserve case = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, leaves mangled 8.3-style filenames in the case sent by client. If no, it forces the case to that specified by the <CODE CLASS="literal">
+default case</code> option. See also <CODE CLASS="literal">
+preserve case</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] socket address = IP address</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: IP address</p>
+
+<P CLASS="para">
+Sets address on which to listen for connections. Default is to listen to all addresses. Used to support multiple virtual interfaces on one server. Highly discouraged. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] socket options = socket option list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list</p>
+
+<P CLASS="para">
+Sets OS-specific socket options. <CODE CLASS="literal">
+SO_KEEPALIVE</code> has TCP check clients every 4 hours to see if they are still accessible. <CODE CLASS="literal">
+TCP_NODELAY</code> sends even tiny packets to keep delay low. Recommended wherever the operating system supports them. See <a href="appb_01.html"><b>Appendix B, <CITE CLASS="appendix">Samba Performance Tuning</cite></b></a>, for more information.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- 2.0.7, davecb -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] source environment = string</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+This pathname parameter causes Samba to read a list of environment
+variables from a named file on startup. This can be useful in setting
+up Samba in a clustered environment. This is new in 2.0.7.</p>
+
+<p> The file must be owned by root and not be world writable,
+and if the filename begins with a "|" (pipe) character, it must point to
+a command which is neither world writable nor resides
+in a world writable directory.</p>
+
+<p> The data should be in the form of lines such as
+<CODE CLASS="literal">SAMBA_NETBIOS_NAME=myhostname</CODE>.
+This variable will then be available in the smb.conf files as $%SAMBA_NETBIOS_NAME.</p>
+
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- end of 2.0.7 -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] status = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, logs connections to a file (or shared memory) accessible to <I CLASS="filename">
+smbstatus</i>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>strict sync = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, Samba will synchronize to disk whenever the client sets the sync bit in a packet. If set to NO, Samba flushes data to disk whenever buffers fill. Defaults to NO because Windows 98 Explorer sets the bit (incorrectly) in all packets. Introduced in Samba 1.9.18p10.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>strict locking = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, Samba checks locks on every access, not just on demand and at open time. Not recommended.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] strip dot = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Removes trailing dots from filenames. Use <CODE CLASS="literal">
+mangled map</code> instead.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] syslog = number</i></b>
+<P CLASS="refpurpose">Default: 1</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Sets number of Samba log messages to send to <I CLASS="filename">
+syslog</i>. Higher is more verbose. The <I CLASS="filename">
+syslog.conf</i> file must have suitable logging enabled.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] syslog only = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, log only to <EM CLASS="emphasis">
+syslog, </em>not standard Samba log files.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>sync always = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, Samba calls<EM CLASS="emphasis">
+ fsync</em>(3) after every write. Avoid except for debugging crashing servers.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] time offset = minutes</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: minutes</p>
+
+<P CLASS="para">
+Sets number of minutes to add to system time zone calculation. Provided to fix a client daylight-savings bug; not recommended.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] time server = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If YES, <EM CLASS="emphasis">
+nmbd</em> will provide time service to its clients.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>unix password sync = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set, will attempt to change the user's Unix password whenever the user changes his or her SMB password. Used to ease synchronization of Unix and Microsoft password databases. Added in Samba 1.9.18p4. See also <CODE CLASS="literal">
+passwd chat</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>unix realname = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set, will provide the GCOS field of <I CLASS="filename">
+/etc/passwd</i> to the client as the user's full name.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>update encrypted = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Updates the Microsoft-format password file when a user logs in with unencrypted passwords. Provided to ease conversion to encryped passwords for Windows 95/98 and NT. Added in Samba 1.9.18p5.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>user = comma-separated list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: comma-separated list of user names</p>
+
+<P CLASS="para">
+Synonym for <CODE CLASS="literal">
+username</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>username = comma-separated list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: comma-separated list of user names</p>
+
+<P CLASS="para">
+Sets a list of users to try to log in as for a share or shares with share-level security. Synonyms are <CODE CLASS="literal">
+user</code> and <CODE CLASS="literal">
+users</code>. Discouraged. Use <CODE CLASS="literal">
+NET USE \\</code><CODE CLASS="replaceable"><I>server</i></code><CODE CLASS="literal">\</code><CODE CLASS="replaceable"><I>share </i></code><CODE CLASS="literal">%</code><CODE CLASS="replaceable"><I>user</i></code> from the client instead.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>username level = number</i></b>
+<P CLASS="refpurpose">Default: 0</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: number</p>
+
+<P CLASS="para">
+Number of uppercase letter permutations allowed to match Unix usernames. Workaround for Windows feature (single-case usernames). Use is discouraged.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] username map = pathname</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+Names a file of Unix-to-Windows name pairs; used to map different spellings of account names and those Windows usernames longer than eight characters.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- 2.0.7 -->
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] utmp = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+This is available if Samba has been configured with the option
+<CODE CLASS="literal"> --with-utmp</CODE>.
+If set, Samba will add utmp/utmpx records whenever a
+connection is made to a Samba server. New in 2.0.7, sites may use this
+to record the user connecting to a Samba share.
+</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] utmp directory = string</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: pathname</p>
+
+<P CLASS="para">
+This is available if Samba has been configured with the option
+<CODE CLASS="literal">--with-utmp</CODE>. If it and <CODE CLASS="literal">
+utmp </CODE> are set, Samba will look in the specified directory
+insteqad of the default system directory for utmp/utmpx files.
+New in 2.0.7, also called <CODE CLASS="literal"> utmp dir</CODE>.
+</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- end of 2.0.7 ->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>valid chars = list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of numeric values</p>
+
+<P CLASS="para">
+Semi-obsolete. Adds national characters to a character set map. Overridden by <CODE CLASS="literal">
+client code page</code>. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>valid users = user list</i></b>
+<P CLASS="refpurpose">Default: NULL (everyone)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: list of users</p>
+
+<P CLASS="para">
+List of users that can log in to a share. </p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>veto files = slash-list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: slash-separated list of filenames</p>
+
+<P CLASS="para">
+List of files not to allow the client to see when listing a directory's contents. See also <CODE CLASS="literal">
+delete veto files</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>veto oplock files = slash-list</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: slash-separated list of filenames</p>
+
+<P CLASS="para">
+List of files not to oplock (and cache on clients). See also <CODE CLASS="literal">
+oplocks</code> and <CODE CLASS="literal">
+fake oplocks</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>volume = share name</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: string</p>
+
+<P CLASS="para">
+Sets the volume label of a disk share, notably a CD-ROM.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>wide links = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, Samba will follow symlinks out of the current disk share(s). See also the <CODE CLASS="literal">
+root dir</code> and <CODE CLASS="literal">
+follow symlinks</code> options.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] wins proxy = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, <EM CLASS="emphasis">
+nmbd</em> will proxy resolution requests to WINS servers on behalf of old clients, which use broadcasts. WINS server is typically on another subnet.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] wins server = host</i></b>
+<P CLASS="refpurpose">Default: NULL</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: hostname</p>
+
+<P CLASS="para">
+Sets the DNS name or IP address of the WINS server.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] wins support = boolean</i></b>
+<P CLASS="refpurpose">Default: NO</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+If set to YES, Samba activates WINS service. The <CODE CLASS="literal">
+wins server</code> option must not be set if <CODE CLASS="literal">
+wins support = yes</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] workgroup = name</i></b>
+<P CLASS="refpurpose">Default: compiled-in</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: workgroup name</p>
+
+<P CLASS="para">
+Sets the workgroup to which things will be served. Overrides compiled-in value. Choosing a name other than <CODE CLASS="literal">
+WORKGROUP</code> is strongly recommended.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>writable = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Antonym for <CODE CLASS="literal">
+read only</code>; synonym of <CODE CLASS="literal">
+write ok</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>write list = comma-separated list</i></b>
+<P CLASS="refpurpose">Default: NULL (everyone)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: comma-separated list of users</p>
+
+<P CLASS="para">
+List of users that are given read-write access to a read-only share. See also <CODE CLASS="literal">
+read list</code>.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<!-- 2.0.7 addendum, davecb -->
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>write cache size = decimal number</i></b>
+<P CLASS="refpurpose">Default: 0 (Disabled)</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: decimal number of bytes</p>
+
+<P CLASS="para">
+Sets the size of a write buffer that Samba uses to pre-accumulate
+write into, so as to write with a particular size that's optimal for
+a given filesystem. Typically this is used with RAID drives, which
+have a preferred write size, systems with large memory and slow disks, etc.</p>
+
+<p> As of Samba 2.0.7, this applies to the first 10 oplocked files,
+which are also found in shares where this option is set.
+</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+<!-- end of 2.0.7 addendum -->
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>write ok = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Synonym of the <CODE CLASS="literal">
+writable</code> configuration option.</p>
+</div>
+</blockquote>
+</div>
+<p>&nbsp;</p>
+
+<DIV CLASS="refentry">
+<DIV CLASS="refnamediv"><b><i>[global] write raw = boolean</i></b>
+<P CLASS="refpurpose">Default: YES</p></div><BLOCKQUOTE>
+<DIV CLASS="refsynopsisdiv">
+<P CLASS="para">Allowable values: YES, NO</p>
+
+<P CLASS="para">
+Allows fast streaming writes over TCP, using 64KB buffers. Recommended.</p>
+</div>
+</blockquote>
+
+<DIV CLASS="refsect1"><h2>Glossary of Configuration Values</h2>
+<DL CLASS="variablelist">
+<DT CLASS="term">Address list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of IP addresses in ###.###.###.### format.</p></dd><DT CLASS="term">
+Comma-separated list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A list of items separated by commas.</p></dd><DT CLASS="term">
+Command</dt><DD CLASS="listitem">
+<P CLASS="para">
+A Unix command, with full path and parameters.</p></dd><DT CLASS="term">
+Host list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of hosts. Allows IP addresses, address masks, domain names, ALL, and EXCEPT</p></dd><DT CLASS="term">
+Interface list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of interfaces, in either address/netmask or address/n-bits format. For example, 192.168.2.10/24 or 192.168.2.10/255.255.255.0</p></dd><DT CLASS="term">
+Map list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of file-remapping strings such as <CODE CLASS="literal">
+(*.html</code> <CODE CLASS="literal">
+*.htm)</code>.</p></dd><DT CLASS="term">
+Remote list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of subnet-broadcast-address/workgroup pairs. For example, 192.168.2.255/SERVERS 192.168.4.255/STAFF.</p></dd><DT CLASS="term">
+Service (share) list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of share names, without the enclosing square brackets.</p></dd><DT CLASS="term">
+Slash-list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A list of filenames, separated by "/" characters to allow embedded spaces. For example, <CODE CLASS="literal">
+/.*/fred</code> <CODE CLASS="literal">
+flintstone/*.frk/</code>.</p></dd><DT CLASS="term">
+Text</dt><DD CLASS="listitem">
+<P CLASS="para">
+One line of text. </p></dd><DT CLASS="term">
+User list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A space-separated list of usernames. In Samba 1.9, <CODE CLASS="literal">
+@group-name</code> will include everyone in Unix group <CODE CLASS="literal">
+group-name</code>. In Samba 2.0, <CODE CLASS="literal">
+@group-name</code> includes whomever is in the NIS netgroup <CODE CLASS="literal">
+group_name</code> if one exists, otherwise whomever is in the Unix group <CODE CLASS="literal">
+group_name</code>. In addition, +<CODE CLASS="literal">
+group_name</code> is a Unix group, &amp;<CODE CLASS="literal">
+group_name</code> is an NIS netgroup, and &amp;+ and +&amp; cause an ordered search of both Unix and NIS groups.</p></dd></dl></div>
+<DIV CLASS="refsect1">
+<h2>Configuration File Variables</h2>
+<P CLASS="para">
+<A CLASS="xref" HREF="appc_01.html#appc-88529">
+Table C.1</a> lists of Samba configuration file variables. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="appc-88529">
+Table C.1: Variables in Alphabetic Order </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Meaning</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%a</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's architecture (one of Samba, WfWg, WinNT, Win95, or UNKNOWN)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%d</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current server process's processID </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%f</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Print-spool file as a relative path (printing only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%f</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+User from which a message was sent (messages only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%G</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary group name of <CODE CLASS="literal">
+%U</code> (requested username) </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%g</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary group name of <CODE CLASS="literal">
+%u</code> (actual username)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%H</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Home directory of <CODE CLASS="literal">
+%u</code> (actual username)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%h</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba server's (Internet) hostname</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%I</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's IP address </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%j</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Print job number (printing only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%L</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba server's NetBIOS name (virtual servers have multiple names)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%M</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's (Internet) hostname </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%m</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's NetBIOS name </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%n</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+New password (password change only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%N</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name of the NIS home directory server (without NIS, same as <CODE CLASS="literal">
+%L</code>)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%o</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Old password (password change only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%P</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's root directory (actual)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%p</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's root directory (in an NIS homedir map)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%p</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Print filename (printing only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%R</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Protocol level in use (one of CORE, COREPLUS, LANMAN1, LANMAN2, or NT1)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%S</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's name </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%s</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Filename the message is in (messages only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%s</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Print-spool file name (printing only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%T</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current date and time </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%t</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Destination machine (messages only)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%u</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's username </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%U</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Requested username for current share </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%v</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba version</p></td></tr></tbody></table></div></blockquote></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appb_03.html" TITLE="B.3 Sizing Samba Servers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: B.3 Sizing Samba Servers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="D. Summary of Samba Daemons and Commands">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: D. Summary of Samba Daemons and Commands" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+B.3 Sizing Samba Servers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+D. Summary of Samba Daemons and Commands</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appd_01.html b/docs/htmldocs/using_samba/appd_01.html
new file mode 100644
index 00000000000..5e3bd16aa46
--- /dev/null
+++ b/docs/htmldocs/using_samba/appd_01.html
@@ -0,0 +1,1907 @@
+<HTML>
+<HEAD>
+<TITLE>Appendix D</title>
+</head>
+
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="appc_01.html" TITLE="C. Samba Configuration Option Quick Reference">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: C. Samba Configuration Option Quick Reference" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix D</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appe_01.html" TITLE="E. Downloading Samba with CVS">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: E. Downloading Samba with CVS" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+
+<blockquote>
+<div class="samplechapter">
+<h1>Appendix D<br>
+Summary of Samba Daemons and Commands</h1>
+
+<p>
+This appendix is a reference listing of command-line options and other information to help you use the executables that come with Samba distribution.
+
+<DIV>
+<H2 CLASS="FM-HeadA">Samba Distribution Programs</h2>
+<P CLASS="Body">The following sections provide information about the command-line parameters for Samba programs.</p>
+<DIV>
+<H3 CLASS="HeadB">smbd</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbd</em>
+ program provides Samba's file and printer services, using one TCP/IP stream and one daemon per client. It is controlled from the default configuration file, <EM CLASS="Replaceable">samba_dir</em><EM CLASS="Emphasis">/lib/smb.conf</em>, and can be overridden by command-line options.</p>
+<P CLASS="Body">The configuration file is automatically re-evaluated every minute. If it has changed, most new options are immediately effective. You can force Samba to immediately reload the configuration file if you send a SIGHUP to <EM CLASS="Emphasis">smbd</em>
+. Reloading the configuration file, however, will not affect any clients that are already connected. To escape this &quot;grandfather&quot; configuration, a client would need to disconnect and reconnect, or the server itself would have to be restarted, forcing all clients to reconnect.</p>
+<DIV>
+<H4 CLASS="HeadC">Other signals</h4>
+<P CLASS="Body">To shut down a <EM CLASS="Emphasis">smbd</em>
+ process, send it the termination signal SIGTERM (-15) which allows it to die gracefully instead of a SIGKILL (-9). To increment the debug logging level of <EM CLASS="Emphasis">smbd</em>
+ at runtime, send the program a SIGUSR1 signal. To decrement it at runtime, send the program a SIGUSR2 signal. </p>
+</div>
+<DIV>
+<H4 CLASS="HeadC">Command-line options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-D</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">The <EM CLASS="Emphasis">smbd</em>
+ program is run as a daemon. This is the recommended way to use <EM CLASS="Emphasis">smbd</em> (it is also the default action). In addition, <EM CLASS="Emphasis">smbd</em> can also be run from <EM CLASS="Emphasis">inetd</em>.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">debuglevel</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (sometimes called logging) level. The level can range from 0 all the way to 10. Specifying the value on the command line overrides the value specified in the <EM CLASS="Filename">smb.conf</em>
+ file. Debug level 0 logs only the most important messages; level 1 is normal; levels 3 and above are primarily for debugging and slow <EM CLASS="Emphasis">smbd</em>
+ considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+ </h4>
+<UL>
+<LI CLASS="ListVariable">Prints command-line usage information for the <EM CLASS="Filename">smbd</em>
+ program.</li>
+</ul>
+<DIV>
+<H4 CLASS="HeadC">Testing/debugging options</h4>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-a</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">If this is specified, each new connection to the Samba server will append all logging messages to the log file. This option is the opposite of <EM CLASS="Literal">-o</em>, and is the default.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-i</em>
+ <EM CLASS="Replaceable">scope</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">&nbsp;</li>
+<LI CLASS="ListVariable">This sets a NetBIOS scope identifier. Only machines with the same identifier will communicate with the server. The scope identifier was a predecessor to workgroups, and this option is included only for backwards compatibility.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-l</em>
+ <EM CLASS="Replaceable">log_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Send the log messages to somewhere other than the location compiled in or specified in the <EM CLASS="Filename">smb.conf</em> file. The default is often <EM CLASS="Filename">/usr/local/samba/var/log.smb</em>, <EM CLASS="Filename">/usr/samba/var/log.smb,</em> or <EM CLASS="Filename">/var/log/log.smb</em>. The first two are strongly discouraged on Linux, where <EM CLASS="Filename">/usr</em>
+ may be a read-only filesystem. </li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-O</em>
+ <EM CLASS="Replaceable">socket_options</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets the TCP/IP socket options, using the same parameters as the <EM CLASS="Literal">socket</em>
+ <EM CLASS="Literal">options</em>
+ configuration option. It is often used for performance tuning and testing.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-o</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option is the opposite of <EM CLASS="Literal">-a</em>. It causes log files to be overwritten when opened. Using this option saves hunting for the right log entries if you are performing a series of tests and inspecting the log file each time.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-P</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option forces <EM CLASS="Filename">smbd</em>
+ not to send any network data out. This option is typically used only by Samba developers.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-P</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option forces <EM CLASS="Filename">smbd</em>
+ not to send any network data out. This option is typically used only by Samba developers. </li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-p</em>
+ <EM CLASS="Replaceable">port_number</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets the TCP/IP port number that the server will accept requests from. Currently, all Microsoft clients send only to the default port: 139.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">configuration_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the location of the Samba configuration file. Although the file defaults to <EM CLASS="Filename">/usr/local/samba/lib/smb.conf</em>, you can override it here on the command line, typically for debugging.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">nmbd</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">nmbd</em>
+ program is Samba's NetBIOS name and browsing daemon. It replies to broadcast NetBIOS over TCP/IP (NBT) name-service requests from SMB clients and optionally to Microsoft's Windows Internet Name Service (WINS) requests. Both of these are versions of the name-to-address lookup required by SMB clients. The broadcast version uses UDP/IP broadcast on the local subnet only, while WINS uses TCP/IP, which may be routed. If running as a WINS server, <EM CLASS="Emphasis">nmbd</em>
+ keeps a current name and address database in the file <EM CLASS="Filename">wins.dat</em> in the <EM CLASS="Literal">samba_dir</em><EM CLASS="Filename">/var/locks</em> directory.</p>
+<P CLASS="Body">An active <EM CLASS="Emphasis">nmbd</em>
+ program can also respond to browsing protocol requests used by the Windows Network Neighborhood. Browsing is a combined advertising, service announcement, and active directory protocol. This protocol provides a dynamic directory of servers and the disks and printers that the servers are providing. As with WINS, this was initially done by making UDP/IP broadcasts on the local subnet. Now, with the concept of a local master browser, it is done by making TCP/IP connections to a server. If <EM CLASS="Emphasis">nmbd</em>
+ is acting as a local master browser, it stores the browsing database in the file <EM CLASS="Filename">browse.dat</em> in the <EM CLASS="Literal">samba_dir</em><EM CLASS="Filename">/var/locks</em> directory.</p>
+<DIV>
+<H4 CLASS="HeadC">Signals</h4>
+<P CLASS="Body">Like <EM CLASS="Emphasis">smbd</em>, the <EM CLASS="Emphasis">nmbd</em> program responds to several Unix signals. Sending <EM CLASS="Emphasis">nmbd</em>
+ a SIGHUP signal will cause it to dump the names it knows about to the file <EM CLASS="Filename">namelist.debug</em>
+ in the <EM CLASS="Literal">samba_dir</em>
+/<EM CLASS="Emphasis">locks</em>
+ directory and its browsing database to the <EM CLASS="Filename">browse.dat </em>
+file in the same directory. To shut down a <EM CLASS="Emphasis">nmbd</em>
+ process send it a SIGTERM (-15) signal instead of a SIGKILL (-9) to allow it to die gracefully. You can increment the debug logging level of <EM CLASS="Emphasis">nmbd</em>
+ by sending it a SIGUSR1 signal; you can decrement it by sending a SIGUSR2 signal.</p>
+</div>
+<DIV>
+<H4 CLASS="HeadC">Command-line options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-D</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Instructs the <EM CLASS="Filename">nmbd</em>
+ program to run as a daemon. This is the recommended way to use <EM CLASS="Filename">nmbd</em>. In addition, <EM CLASS="Filename">nmbd</em> can also be run from <EM CLASS="FirstTerm">inetd</em>.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">debuglevel</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (sometimes called logging) level. The level can range from 0, all the way to 10. Specifying the value on the command line overrides the value specified in the <EM CLASS="Filename">smb.conf</em>
+ file. Debug level 0 logs only the most important messages; level 1 is normal; level 3 and above are primarily for debugging, and slow <EM CLASS="Emphasis">nmbd</em>
+ considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+ </h4>
+<UL>
+<LI CLASS="ListVariable">Prints command-line usage information for the <EM CLASS="Filename">nmbd</em> program (also <EM CLASS="Literal">-?</em>).</li>
+</ul>
+<DIV>
+<H4 CLASS="HeadC">Testing/debugging options</h4>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-a</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">If this is specified, each new connection to the Samba server will append all logging messages to the log file. This option is the opposite of <EM CLASS="Literal">-o</em>, and is the default.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-H</em>
+ <EM CLASS="Replaceable">hosts_ file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option loads a standard <EM CLASS="Emphasis">hosts</em>
+ file for name resolution. </li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-i</em>
+ <EM CLASS="Replaceable">scope</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets a NetBIOS scope identifier. Only machines with the same identifier will communicate with the server. The scope identifier was a predecessor to workgroups, and this option is included only for backward compatibility.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-l</em>
+ <EM CLASS="Replaceable">log_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sends the log messages to somewhere other than the location compiled-in or specified in the <EM CLASS="Filename">smb.conf</em> file. The default is often <EM CLASS="Filename">/usr/local/samba/var/log.nmb</em>, <EM CLASS="Filename">/usr/samba/var/log.nmb,</em> or <EM CLASS="Filename">/var/log/log.nmb</em>. The first two are strongly discouraged on Linux, where <EM CLASS="Filename">/usr</em>
+ may be a read-only filesystem. </li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-n</em>
+ <EM CLASS="Replaceable">NetBIOS_name</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option allows you to override the NetBIOS name by which the daemon will advertise itself. Specifying the option on the command line overrides the <EM CLASS="Literal">netbios</em>
+ <EM CLASS="Literal">name</em>
+ option in the Samba configuration file.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-O</em>
+ <EM CLASS="Replaceable">socket_options</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets the TCP/IP socket options, using the same parameters as the <EM CLASS="Literal">socket</em>
+ <EM CLASS="Literal">options</em>
+ configuration option. It is often used for performance tuning and testing.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-o</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option is the opposite of <EM CLASS="Literal">-a</em>
+. It causes log files to be overwritten when opened. Using this option saves hunting for the right log entries if you are performing a series of tests and inspecting the log file each time.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-p</em>
+ <EM CLASS="Replaceable">port_number</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets the UDP/IP port number from which the server will accept requests. Currently, all Microsoft clients send only to the default port: 137.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">configuration_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the location of the Samba configuration file. Although the file defaults to <EM CLASS="Filename">/usr/local/samba/lib/smb.conf</em>, you can override it here on the command line, typically for debugging.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-v</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option prints the current version of Samba.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">Samba Startup File </h3>
+<P CLASS="Body">Samba is normally started by running it from your Unix system's <EM CLASS="Filename">rc</em>
+ files at boot time. For systems with a System V-like set of <EM CLASS="Filename">/etc/rcN.d</em>
+ directories, this can be done by placing a suitably named script in the <EM CLASS="Filename">/rc</em>
+ directory. Usually, the script starting Samba is called <EM CLASS="Emphasis">S91samba</em>
+, while the script stopping or &quot;killing&quot; Samba is called <EM CLASS="Emphasis">K91samba. </em>
+On Linux, the usual subdirectory for the scripts is <EM CLASS="Filename">/etc/rc2.d.</em>
+ On Solaris, the directory is <EM CLASS="Filename">/etc/rc3.d</em>
+. For machines with <EM CLASS="Filename">/etc/rc.local</em>
+ files, you would normally add the following lines to that file:</p>
+<P CLASS="Code">/usr/local/samba/bin/smbd -D</p>
+<P CLASS="Code">/usr/local/samba/bin/nmbd -D </p>
+<P CLASS="Body">The following example script supports two extra commands, <EM CLASS="Literal">status</em>
+ and <EM CLASS="Literal">restart</em>, in addition to the normal <EM CLASS="Literal">start</em>
+ and <EM CLASS="Literal">stop</em>
+ for System V machines:</p>
+
+<pre>
+#!/bin/sh
+#
+# /etc/rc2.d./S91Samba --manage the SMB server in a System V manner
+#
+OPTS=&quot;-D&quot;
+#DEBUG=-d3
+PS=&quot;ps ax&quot;
+SAMBA_DIR=/usr/local/samba
+case &quot;$1&quot; in
+'start')
+ echo &quot;samba &quot;
+ $SAMBA_DIR/bin/smbd $OPTS $DEBUG
+ $SAMBA_DIR/bin/nmbd $OPTS $DEBUG
+ ;;
+'stop')
+ echo &quot;Stopping samba&quot;
+ $PS | awk '/usr.local.samba.bin/ { print $1}' |&#92;
+ xargs kill
+ ;;
+'status')
+ x=`$PS | grep -v grep | grep '$SAMBA_DIR/bin'`
+ if [ ! &quot;$x&quot; ]; then
+ echo &quot;No samba processes running&quot;
+ else
+ echo &quot; PID TT STAT TIME COMMAND&quot;
+ echo &quot;$x&quot;
+ fi
+ ;;
+'restart')
+ /etc/rc2.d/S91samba stop
+ /etc/rc2.d/S91samba start
+ /etc/rc2.d/S91samba status
+ ;;
+*)
+ echo &quot;$0: Usage error -- you must say $0 start, stop, status or restart.&quot;
+ ;;
+esac
+exit
+</pre>
+<P CLASS="Body">You'll need to set the actual paths and <EM CLASS="Literal">ps</em>
+ options to suit the machine you're using. In addition, you might want to add additional commands to tell Samba to reload its <EM CLASS="Filename">smb.conf</em>
+ file or dump its <EM CLASS="Emphasis">nmbd</em>
+ tables, depending on your actual needs. </p>
+</div>
+<DIV>
+<H3 CLASS="HeadB">smbsh</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbsh</em>
+ program lets you use a remote Windows share on your Samba server as if the share was a regular Unix directory. When it's run, it provides an extra directory tree under <EM CLASS="Filename">/smb</em>. Subdirectories of <EM CLASS="Filename">/smb</em>
+ are servers, and subdirectories of the servers are their individual disk and printer shares. Commands run by <EM CLASS="Emphasis">smbsh</em>
+ treat the <EM CLASS="Filename">/smb</em>
+ filesystem as if it were local to Unix. This means that you don't need <EM CLASS="Emphasis">smbmount</em>
+ in your kernel to mount Windows filesystems the way you mount with NFS filesystems. However, you do need to configure Samba with the <EM CLASS="Literal">--with-smbwrappers</em>
+ option to enable <EM CLASS="Filename">smbsh</em>.</p>
+<DIV>
+<H4 CLASS="HeadC">Options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ debuglevel</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (sometimes called logging) level. The level can range from 0, the default, all the way to 10. Debug level 0 logs only the most important messages; level 1 is normal; level 3 and above are primarily for debugging, and slow <EM CLASS="Emphasis">smbsh</em>
+ considerably.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-l</em>
+ <EM CLASS="Replaceable">logfile</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the name of the logfile to use.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-P</em>
+ <EM CLASS="Replaceable">prefix</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the root directory to mount the SMB filesystem. The default is <EM CLASS="Filename">/smb</em>.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-R</em>
+ <EM CLASS="Replaceable">resolve order</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the resolve order of the name servers. This option is similar to the <EM CLASS="Literal">resolve order</em>
+ configuration option, and can take any of the four parameters, <EM CLASS="Literal">lmhosts</em>, <EM CLASS="Literal">host</em>, <EM CLASS="Literal">wins</em>, and <EM CLASS="Literal">bcast</em>, in any order.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-U</em>
+ <EM CLASS="Replaceable">user</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Supports <EM CLASS="Replaceable">user%password.</em>
+</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-W</em>
+ <EM CLASS="Replaceable">workgroup</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the NetBIOS workgroup to which the client will connect.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">smbclient</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbclient</em>
+ program is the maid-of-all-work of the Samba suite. Initially intended as a testing tool, it has become a full command-line Unix client, with an FTP-like interactive client. Some of its options are still used for testing and tuning, and it makes a simple tool for ensuring that Samba is running on a server.</p>
+<P CLASS="Body">It's convenient to look at <EM CLASS="Emphasis">smbclient</em>
+ as a suite of programs:</p>
+<UL>
+<LI CLASS="ListBullet">FTP-like interactive file transfer program</li>
+<LI CLASS="ListBullet">Interactive printing program</li>
+<LI CLASS="ListBullet">Interactive tar program </li>
+<LI CLASS="ListBullet">Command-line message program</li>
+<LI CLASS="ListBullet">Command-line <EM CLASS="Emphasis">tar</em>
+ program (but see <EM CLASS="Emphasis">smbtar</em>
+ later)</li>
+<LI CLASS="ListBullet">&quot;What services do you have&quot; query program</li>
+<LI CLASS="ListBullet">Command-line debugging program</li>
+</ul>
+<DIV>
+<H4 CLASS="HeadC">General command-line options</h4>
+<P CLASS="Body">The program has the usual set of <EM CLASS="Emphasis">smbd</em>
+-like options, which apply to all the interactive and command-line use. The syntax is:</p>
+<P CLASS="Code">smbclient //<EM CLASS="Replaceable">server_name</em>
+/<EM CLASS="Replaceable">share_name</em>
+ [<EM CLASS="Replaceable">password</em>
+] [-<EM CLASS="Replaceable">options</em>
+]</p>
+<P CLASS="Body">Here is an explanation of each of the command-line options:</p>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">debug_level</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (logging) level, from 0 to 10, with <EM CLASS="Literal">A</em>
+ for all. Overrides the value in <EM CLASS="Filename">smb.conf</em>. Debug level 0 logs only the most important messages; level 1 is normal; debug level 3 and above are for debugging, and slow <EM CLASS="Emphasis">smbclient</em>
+ considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints the command-line help information (usage) for smbclient.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-n</em>
+ <EM CLASS="Replaceable">NetBIOS_name</em>
+</h4>
+<P CLASS="ListSimple">Allows you to override the NetBIOS name by which the program will advertise itself. </p>
+<DIV>
+<H4 CLASS="HeadC">Smbclient operations</h4>
+<P CLASS="Body">Running <EM CLASS="Literal">smbclient</em><EM CLASS="Literal">//</em><EM CLASS="Replaceable">server_name</em><EM CLASS="Literal">/</em><EM CLASS="Replaceable">share</em>
+ will cause it to prompt you for a username and password. If the login is successful, it will connect to the share and give you a prompt much like an FTP prompt (the backslash in the prompt will be replaced by the current directory within the share as you move around the filesystem):</p>
+<P CLASS="Code">smb:&#92;&gt;</p>
+<P CLASS="Body">From this command line, you can use several FTP-like commands, as listed below. Arguments in square brackets are optional. </p>
+<TABLE>
+<CAPTION>
+<H4 CLASS="TableLabel"><A NAME="89417"></a>&nbsp;</h4>
+<H4 CLASS="TableTitle">smbclient Commands </h4>
+</caption>
+<TR>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Command</p>
+</th>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Description</p>
+</th>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">?</em>
+ <EM CLASS="Replaceable">command</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Provides list of commands or help on specified command.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">help</em>
+ [<EM CLASS="Replaceable">command</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Provides list of commands or help on specified command.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">!</em>
+ [<EM CLASS="Replaceable">command</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">If a command is specified, it will be run in a local shell. If not, you will be placed into a local shell on the client.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">dir</em>
+ [<EM CLASS="Replaceable">filename</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Displays any files matching <EM CLASS="Replaceable">filename</em>
+ in the current directory on the server, or all files if <EM CLASS="Replaceable">filename</em>
+ is omitted.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">ls</em>
+ [<EM CLASS="Replaceable">filename</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Displays any files matching <EM CLASS="Replaceable">filename</em>
+ in the current directory on the server, or all files if <EM CLASS="Replaceable">filename</em>
+ is omitted.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">cd</em>
+ [<EM CLASS="Replaceable">directory</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">If <EM CLASS="Replaceable">directory</em>
+ is specified, changes to the specified directory on the remote server. If not, reports the current directory on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">lcd</em>
+ [<EM CLASS="Replaceable">directory</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">If <EM CLASS="Replaceable">directory</em>
+ is specified, the current directory on the local machine will be changed. If not, the name of the current directory on the local machine will be reported.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">get</em>
+ <EM CLASS="Emphasis">remotefile </em>
+[<EM CLASS="Replaceable">localfile</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Copies the file <EM CLASS="Replaceable">remotefile</em> to the local machine. If a <EM CLASS="Replaceable">localfile</em>
+ is specified, uses that name to copy the file to. Treats the file as binary; does <EM CLASS="Emphasis">not</em>
+ do LF to CR/LF conversions.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">put</em>
+ <EM CLASS="Emphasis">localfile </em>
+[<EM CLASS="Replaceable">remotefile</em>]</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Copies <EM CLASS="Replaceable">localfile</em>
+ to the remote machine. If a <EM CLASS="Replaceable">remotefile</em>
+ is specified, uses that as the name to copy to on the remote server. Treats the file as binary; does <EM CLASS="Emphasis">not</em>
+ do LF to CR/LF conversions.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">mget</em>
+ <EM CLASS="Replaceable">pattern</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Gets all files matching <EM CLASS="Replaceable">pattern</em>
+ from the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">mput</em>
+<EM CLASS="Replaceable"> pattern</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Places all local files matching <EM CLASS="Replaceable">pattern</em>
+ on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">prompt</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Toggles interactive prompting on and off for <EM CLASS="Literal">mget</em> and <EM CLASS="Literal">mput</em>.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">lowercase ON </em>
+ <br>
+
+(or<EM CLASS="Literal"> OFF</em>)</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">If lowercase is on, <EM CLASS="Emphasis">smbclient</em>
+ will convert filenames to lowercase during an <EM CLASS="Literal">mget</em>
+ or <EM CLASS="Literal">get</em>
+ (but not a <EM CLASS="Literal">mput</em> or <EM CLASS="Literal">put</em>).</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">del</em>
+ <EM CLASS="Replaceable">filename</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Delete a file on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">md</em>
+ <EM CLASS="Replaceable">directory</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Create a directory on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">mkdir</em>
+ <EM CLASS="Replaceable">directory</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Create a directory on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">rd</em>
+ <EM CLASS="Replaceable">directory</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Remove the specified directory on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">rmdir</em>
+ <EM CLASS="Replaceable">directory</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Remove the specified directory on the remote machine.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">setmode</em>
+ <EM CLASS="Replaceable">filename</em>
+ <EM CLASS="Literal">[+|-]rsha</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Set DOS filesystem attribute bits, using Unix-like modes. <EM CLASS="Literal">r</em>
+ is read-only, <EM CLASS="Literal">s</em>
+ is system, <EM CLASS="Literal">h</em>
+ is hidden, and <EM CLASS="Literal">a</em>
+ is archive.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">exit</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Exits <EM CLASS="Emphasis">smbclient</em>.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">quit</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Exits <EM CLASS="Emphasis">smbclient</em>.</p>
+</td>
+</tr>
+</table>
+<P CLASS="Body">There are also mask and recursive commands for large copies; see the <EM CLASS="Filename">smbclient</em>
+ manual page for details on how to use these. With the exception of mask, recursive, and the lack of an ASCII transfer mode, <EM CLASS="Emphasis">smbclient</em>
+ works exactly the same as FTP. Note that because it does binary transfers, Windows files copied to Unix will have lines ending in carriage-return and linefeed (<EM CLASS="Literal">&#92;r&#92;n</em>), not Unix's linefeed (<EM CLASS="Literal">&#92;n</em>).</p>
+</div>
+<DIV>
+<H4 CLASS="HeadC">Printing commands</h4>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbclient</em>
+ program can also be used for access to a printer by connecting to a print share. Once connected, the commands shown below can be used to print. </p>
+<TABLE>
+<CAPTION>
+<H4 CLASS="TableLabel"><A NAME="39300"></a>&nbsp;</h4>
+<H4 CLASS="TableTitle">smbclient Printing Commands </h4>
+</caption>
+<TR>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Command</p>
+</th>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Description</p>
+</th>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">print</em>
+<EM CLASS="Replaceable"> filename</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Prints the file by copying it from the local machine to the remote one and then submitting it as a print job there.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">printmode</em>
+ <EM CLASS="Replaceable">text </em>
+|<EM CLASS="Replaceable"> graphics</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Instructs the server that the following files will be plain text (ASCII) or the binary graphics format that the printer requires. It's up to the user to ensure that the file is indeed the right kind.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">queue</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Displays the queue for the print share you're connected to, showing job ID, name, size, and status.</p>
+</td>
+</tr>
+</table>
+</div>
+</div>
+<DIV>
+<H4 CLASS="SidebarBody">Finally, to print from the <EM CLASS="Emphasis">smbclient</em>, use the <EM CLASS="Literal">-c</em>
+ option:</h4>
+<P CLASS="Code">cat <EM CLASS="Replaceable">printfile</em>
+ | smbclient //<EM CLASS="Replaceable">server</em>
+/<EM CLASS="Replaceable">printer_name</em>
+ -c &quot;print -&quot;</p>
+<DIV>
+<H4 CLASS="HeadC">Tar commands</h4>
+<P CLASS="Body"><EM CLASS="Emphasis">smbclient</em>
+ can tar up files from a file share. This is normally done from the command line using the <EM CLASS="Emphasis">smbtar</em>
+ command, but the commands shown below are also available interactively. </p>
+<TABLE>
+<CAPTION>
+<H4 CLASS="TableLabel"><A NAME="54517"></a>&nbsp;</h4>
+<H4 CLASS="TableTitle">smbclient Tar Commands </h4>
+</caption>
+<TR>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Command</p>
+</th>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Description</p>
+</th>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">tar c|x[IXbgNa]</em>
+ <EM CLASS="Replaceable">operands</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Performs a creation or extraction <EM CLASS="Emphasis">tar</em> similar to the command-line program. </p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">blocksize</em>
+ <EM CLASS="Replaceable">size</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Sets the block size to be used by <EM CLASS="Emphasis">tar</em>, in 512-byte blocks.</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">tarmode full|inc|reset|<br>
+
+noreset</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Makes <EM CLASS="Emphasis">tar</em>
+ pay attention to DOS archive bit for all following commands. In <EM CLASS="Literal">full</em>
+ mode (the default), <EM CLASS="Emphasis">tar</em>
+ will back up everything. In <EM CLASS="Literal">inc</em>
+ (incremental) mode, <EM CLASS="Emphasis">tar</em>
+ will back up only those files with the archive bit set. In <EM CLASS="Literal">reset</em>
+ mode, <EM CLASS="Emphasis">tar</em>
+ will reset the archive bit on all files it backs up (this requires the share to be writable), and in <EM CLASS="Literal">noreset</em>
+ mode the archive bit will not be reset even after the file has been backed up.</p>
+</td>
+</tr>
+</table>
+</div>
+<DIV>
+<H4 CLASS="HeadC">Command-line message program options</h4>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-M</em>
+ <EM CLASS="Replaceable">NetBIOS_machine_name</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option allows you to send immediate messages using the WinPopup protocol to another computer. Once a connection is established, you can type your message, pressing control-D to end. If WinPopup is not running on the receiving machine, the program returns an error.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-U</em>
+ <EM CLASS="Replaceable">user</em>
+ </h4>
+<UL>
+<LI CLASS="ListVariable">This<EM CLASS="Replaceable"> </em>
+option allows you to indirectly control the FROM part of the message. </li>
+</ul>
+<DIV>
+<H4 CLASS="HeadC">Command-line tar program options</h4>
+<P CLASS="Body">The <EM CLASS="Literal">-T</em>
+ (tar), <EM CLASS="Literal">-D</em>
+ (starting directory), and <EM CLASS="Literal">-c</em>
+ (command) options are used together to tar up files interactively. This is better done with <EM CLASS="Filename">smbtar</em>, which will be discussed shortly. We don't recommend using <EM CLASS="Emphasis">smbclient</em>
+ directly as a <EM CLASS="Emphasis">tar</em>
+ program. </p>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-D</em>
+ <EM CLASS="Replaceable">initial_directory</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Changes to initial directory before starting.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-c</em>
+ <EM CLASS="Replaceable">command_string</em>
+ </h4>
+<UL>
+<LI CLASS="ListVariable">Passes a command string to the <EM CLASS="Emphasis">smbclient</em>
+ command interpreter, which treats it as a semicolon-separated list of commands to be executed. This is handy to say things such as <EM CLASS="Literal">tarmode</em> <EM CLASS="Literal">inc</em>, for example, which forces <EM CLASS="Literal">smbclient</em>
+ <EM CLASS="Literal">-T</em>
+ to back up only files with the archive bit set.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-T</em>
+ <EM CLASS="Replaceable">command filename</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Runs the <EM CLASS="Emphasis">tar</em>
+ driver, which is <EM CLASS="Emphasis">gtar</em>
+ compatible. The two main commands are: <EM CLASS="Literal">c</em>
+ (create) and <EM CLASS="Literal">x</em>
+ (extract), which may be followed by any of:</li>
+</ul>
+<DIV>
+<H4 CLASS="FM-ListVariableTermRunin"><EM CLASS="Literal">a</em>
+</h4>
+<P CLASS="FM-ListVariable">Resets archive bits once files are saved.</p>
+</div>
+<DIV>
+<H5 CLASS="FM-ListVariableTerm"><EM CLASS="Literal">b</em>
+ <EM CLASS="Replaceable">size</em>
+</h5>
+<P CLASS="FM-ListVariable">Sets blocksize in 512-byte units.</p>
+<DIV>
+<H4 CLASS="FM-ListVariableTermRunin"><EM CLASS="Literal">g</em>
+</h4>
+<P CLASS="FM-ListVariable">Backs up only files with the archive bit set.</p>
+</div>
+</div>
+<DIV>
+<H5 CLASS="FM-ListVariableTerm"><EM CLASS="Literal">I</em>
+ <EM CLASS="Replaceable">file</em>
+</h5>
+<P CLASS="FM-ListVariable">Includes files and directories (this is the default). Does not do pattern-matching.</p>
+</div>
+<DIV>
+<H5 CLASS="FM-ListVariableTerm"><EM CLASS="Literal">N</em>
+ <EM CLASS="Replaceable">filename</em>
+</h5>
+<P CLASS="FM-ListVariable">Backs up only those files newer than <EM CLASS="Replaceable">filename.</em>
+</p>
+<DIV>
+<H4 CLASS="FM-ListVariableTermRunin"><EM CLASS="Literal">q</em>
+</h4>
+<P CLASS="FM-ListVariable">Does not produce diagnostics.</p>
+</div>
+</div>
+<DIV>
+<H5 CLASS="FM-ListVariableTerm"><EM CLASS="Literal">X</em>
+ <EM CLASS="Replaceable">file</em>
+</h5>
+<P CLASS="FM-ListVariable">Excludes files.</p>
+<DIV>
+<H4 CLASS="HeadC">Command-line query program</h4>
+<P CLASS="Body">If <EM CLASS="Filename">smbclient</em>
+ is run as:</p>
+<P CLASS="Code">smbclient -L <EM CLASS="Replaceable">server_name</em>
+</p>
+<P CLASS="Body">it will list the shares and other services that machine provides. This is handy if you don't have <EM CLASS="Filename">smbwrappers</em>. It can also be helpful as a testing program in its own right.</p>
+</div>
+<DIV>
+<H4 CLASS="HeadC">Command-line debugging /diagnostic program options</h4>
+<P CLASS="Body">Any of the various modes of operation of <EM CLASS="Emphasis">smbclient</em>
+ can be used with the debugging and testing command-line options:</p>
+</div>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-B</em>
+ <EM CLASS="Replaceable">IP_addr</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the broadcast address.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">debug_level</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (sometimes called logging) level. The level can range from 0 all the way to 10. In addition, you can specify <EM CLASS="Literal">A</em>
+ for all debugging options. Debug level 0 logs only the most important messages; level 1 is normal; level 3 and above are primarily for debugging and slow operations considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-E</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sends all messages to stderr instead of stdout.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-I</em>
+ <EM CLASS="Replaceable">IP_address</em>
+ </h4>
+<UL>
+<LI CLASS="ListVariable">Sets the IP address of the server to which it connects.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-i</em>
+ <EM CLASS="Replaceable">scope</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This sets a NetBIOS scope identifier. Only machines with the same identifier will communicate with the server. The scope identifier was a predecessor to workgroups, and this option is included only for backward compatibility.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-l</em>
+ <EM CLASS="Replaceable">log_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sends the log messages to the specified file. </li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-N</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Suppresses the password prompt. Unless a password is specified on the command line or this parameter is specified, the client will prompt for a password.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-n</em>
+ <EM CLASS="Replaceable">NetBIOS_name</em>
+</h4>
+<P CLASS="ListSimple">This option allows you to override the NetBIOS name by which the daemon will advertise itself. </p>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-O</em>
+ <EM CLASS="Replaceable">socket_options</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the TCP/IP socket options using the same parameters as the <EM CLASS="Literal">socket</em>
+ <EM CLASS="Literal">options</em>
+ configuration option. It is often used for performance tuning and testing.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-p</em>
+ <EM CLASS="Replaceable">port_number</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the port number from which the client will accept requests. </li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-R</em>
+ <EM CLASS="Replaceable">resolve_order</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the resolve order of the name servers. This option is similar to the <EM CLASS="Literal">resolve</em>
+ <EM CLASS="Literal">order</em>
+ configuration option, and can take any of the four parameters, <EM CLASS="Literal">lmhosts</em>, <EM CLASS="Literal">host</em>, <EM CLASS="Literal">wins</em>, and <EM CLASS="Literal">bcast</em>, in any order.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">configuration_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the location of the Samba configuration file. Used for debugging.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-t</em>
+ <EM CLASS="Replaceable">terminal_code</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the terminal code for Asian languages.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-U</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the username and optionally password (e.g., <EM CLASS="Literal">-U</em>
+ <EM CLASS="Literal">fred%secret</em>).</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-W</em>
+ <EM CLASS="Replaceable">workgroup</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the workgroup that you want the client to connect as.</li>
+</ul>
+<P CLASS="Body">If you want to test a particular name service, run <EM CLASS="Emphasis">smbclient</em>
+ with <EM CLASS="Literal">-R</em>
+ and just the name of the service. This will force <EM CLASS="Emphasis">smbclient</em>
+ to use only the service you gave.<EM CLASS="Emphasis"></em>
+</p>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">smbstatus</h3>
+<P CLASS="Body">The <EM CLASS="Filename">smbstatus</em>
+ program lists the current connections on a Samba server. There are three separate sections. The first section lists various shares that are in use by specific users. The second section lists the locked files that Samba currently has on all of its shares. Finally, the third section lists the amount of memory usage for each of the shares. For example:</p>
+<pre>
+# <EM CLASS="LineEmphasis">smbstatus</em>
+
+Samba version 2.0.3
+Service uid gid pid machine
+----------------------------------------------
+network davecb davecb 7470 phoenix (192.168.220.101) Sun May 16
+network davecb davecb 7589 chimaera (192.168.220.102) Sun May 16
+&nbsp;
+Locked files:
+Pid DenyMode R/W Oplock Name
+--------------------------------------------------
+7589 DENY_NONE RDONLY EXCLUSIVE+BATCH /home/samba/quicken/inet/common/system/help.bmp Sun May 16 21:23:40 1999
+7470 DENY_WRITE RDONLY NONE /home/samba/word/office/findfast.exe Sun May 16 20:51:08 1999
+7589 DENY_WRITE RDONLY EXCLUSIVE+BATCH /home/samba/quicken/lfbmp70n.dll Sun May 16 21:23:39 1999
+7589 DENY_WRITE RDWR EXCLUSIVE+BATCH /home/samba/quicken/inet/qdata/runtime.dat Sun May 16 21:23:41 1999
+7470 DENY_WRITE RDONLY EXCLUSIVE+BATCH /home/samba/word/office/osa.exe Sun May 16 20:51:09 1999
+7589 DENY_WRITE RDONLY NONE /home/samba/quicken/qversion.dll Sun May 16 21:20:33 1999
+7470 DENY_WRITE RDONLY NONE /home/samba/quicken/qversion.dll Sun May 16 20:51:11 1999
+&nbsp;
+Share mode memory usage (bytes):
+ 1043432(99%) free + 4312(0%) used + 832(0%) overhead = 1048576(100%) total
+</pre>
+<DIV>
+<H4 CLASS="HeadC">Options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-b</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Forces <EM CLASS="Filename">smbstatus</em>
+ to produce brief output. This includes the version of Samba and auditing information about the users that have logged into the server.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-d</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Gives verbose output, including each of the three reporting sections listed in the previous example. This is the default.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-L</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Forces <EM CLASS="Filename">smbstatus</em>
+ to print only the current file locks it has. This corresponds to the second section in a verbose output. </li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-p</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints a list of <EM CLASS="Filename">smbd</em>
+ process IDs only. This is often used for scripts.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-S</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints only a list of shares and their connections. This corresponds to the first section in a verbose output.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">configuration_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the Samba configuration file to use when processing this command.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-u</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Limits the <EM CLASS="Filename">smbstatus</em>
+ report to the activity of a single user.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">smbtar</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbtar</em>
+ program is a shell script on top of <EM CLASS="Emphasis">smbclient</em>
+ that gives the program more intelligible options when doing tar operations. Functionally, it is equivalent to the Unix <EM CLASS="Emphasis">tar</em>
+ program.</p>
+<DIV>
+<H4 CLASS="HeadC">Options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-a</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Resets the archive bit mode</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-b</em>
+ <EM CLASS="Replaceable">blocksize</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Blocking size. Defaults to 20.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">directory</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Changes to initial directory before restoring or backing up files.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-i</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Incremental mode; tar files are backed up only if they have the DOS archive bit set. The archive bit is reset after each file is read.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-l</em>
+ <EM CLASS="Replaceable">log_level</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable"> Sets the logging level.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-N</em>
+ <EM CLASS="Replaceable">filename</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Backs up only the files newer than the last modification date of <EM CLASS="Replaceable">filename</em>. For incremental backups.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-p</em>
+ <EM CLASS="Replaceable">password</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the password to use to access a share.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-r</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Restores files to the share from the tar file.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">server</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the SMB/CIFS server in which the share resides.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-t</em>
+ <EM CLASS="Replaceable">tape</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Tape device or file. Default is the value of the environment variable <EM CLASS="Literal">$TAPE</em>, or <EM CLASS="Emphasis">tar.out</em>
+ if <EM CLASS="Literal">$TAPE</em>
+ isn't set.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-u</em>
+ <EM CLASS="Replaceable">user</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the user to connect to the share as. You can specify the password as well, in the format <EM CLASS="Replaceable">username</em><EM CLASS="Literal">%</em><EM CLASS="Replaceable">password</em>.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-v</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the use of verbose mode.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-X</em>
+ <EM CLASS="Replaceable">file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Tells <EM CLASS="FirstTerm">smbtar</em>
+ to exclude the specified file from the <EM CLASS="Emphasis">tar</em>
+ create or restore.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-x</em>
+ <EM CLASS="Replaceable">share</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">States the share name on the server to connect to. The default is <EM CLASS="Literal">backup</em>, which is a common share name to perform backups with.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="SidebarBody">For example, a trivial backup command to archive the data for user <EM CLASS="Literal">sue</em>
+ is:</h4>
+<P CLASS="Code"># <EM CLASS="LineEmphasis">smbtar -s pc_name -x sue -u sue -p secret -t sue.tar </em>
+</p>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">nmblookup</h3>
+<P CLASS="Body">The <EM CLASS="Filename">nmblookup</em>
+ program is a client program that exercises the NetBIOS-over-UDP/IP name service for resolving NBT machine names into IP addresses. The command works by broadcasting its queries on the local subnet until a machine with that name responds. You can think of it as a Windows <EM CLASS="Emphasis">nslookup(1) </em>
+or <EM CLASS="EmailSite">dig(1). </em>
+This is useful for looking up both normal NetBIOS names, and the odd ones like <EM CLASS="Literal">__MSBROWSE__</em>
+ that the Windows name services use to provide directory-like services. If you wish to query for a particular type of NetBIOS name, add the NetBIOS <EM CLASS="Literal">&lt;type&gt;</em>
+ to the end of the name.</p>
+<P CLASS="Body">The command line is:</p>
+<P CLASS="Code">nmblookup [-options] <EM CLASS="Replaceable">name</em>
+</p>
+<P CLASS="Body">The options supported are:</p>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-A</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Interprets <EM CLASS="Replaceable">name</em>
+ as an IP address and do a node-status query on this address.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-B</em>
+ <EM CLASS="Replaceable">broadcast _address</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sends the query to the given broadcast address. The default is to send the query to the broadcast address of the primary network interface.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">debuglevel</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (sometimes called logging) level. The level can range from 0 all the way to 10. Debug level 0 logs only the most important messages; level 1 is normal; level 3 and above are primarily for debugging and slow the program considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints command-line usage information for the program.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-i</em>
+ <EM CLASS="Replaceable">scope</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets a NetBIOS scope identifier. Only machines with the same identifier will communicate with the server. The scope identifier was a predecessor to workgroups, and this option is included only for backward compatibility.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-M</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Searches for a local master browser. This is done with a broadcast searching for a machine that will respond to the special name <EM CLASS="Literal">__MSBROWSE__</em>, and then asking that machine for information, instead of broadcasting the query itself.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-R</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the recursion desired bit in the packet. This will cause the machine that responds to try to do a WINS lookup and return the address and any other information the WINS server has saved.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-r</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Use the root port of 137 for Windows 95 machines.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-S</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Once the name query has returned an IP address, does a node status query as well. This returns all the resource types that the machine knows about, with their numeric attributes. For example:</li>
+</ul>
+<pre>
+% <EM CLASS="LineEmphasis">nmblookup -d 4 -S elsbeth</em>
+received 6 names
+ ELSBETH &lt;00&gt; - &lt;GROUP&gt; B &lt;ACTIVE&gt;
+ ELSBETH &lt;03&gt; - B &lt;ACTIVE&gt;
+ ELSBETH &lt;1d&gt; - B &lt;ACTIVE&gt;
+ ELSBETH &lt;1e&gt; - &lt;GROUP&gt; B &lt;ACTIVE&gt;
+ ELSBETH &lt;20&gt; - B &lt;ACTIVE&gt;
+ ..__MSBROWSE__.. &lt;01&gt; - &lt;GROUP&gt; B &lt;ACTIVE&gt;
+</pre>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">configuration_file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies the location of the Samba configuration file. Although the file defaults to <EM CLASS="Filename">/usr/local/samba/lib/smb.conf</em>, you can override it here on the command-line, normally for debugging.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-T</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option can be used to translate IP addresses into resolved names. </li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-U</em>
+ <EM CLASS="Replaceable">unicast_address</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Performs a unicast query to the specified address. Used with <EM CLASS="Literal">-R</em>
+ to query WINS servers.</li>
+</ul>
+<P CLASS="Body">Note that there is no workgroup option for <EM CLASS="Emphasis">nmblookup</em>; you can get around this by putting <EM CLASS="Literal">workgroup</em>
+ <EM CLASS="Literal">=</em>
+ <EM CLASS="Replaceable">workgroup_name </em>
+in a file and passing it to <EM CLASS="Emphasis">nmblookup</em>
+ with the <EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">smb.conf_file</em>
+ option. </p>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">smbpasswd</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">smbpasswd</em>
+ password has two distinct sets of functions. When run by users, it changes their encrypted passwords. When run by <EM CLASS="Literal">root</em>, it updates the encrypted password file. When run by an ordinary user with no options, it connects to the primary domain controller and changes his or her Windows password.</p>
+<P CLASS="Body">The program will fail if <EM CLASS="Emphasis">smbd</em>
+ is not operating, if the <EM CLASS="Literal">hosts</em>
+ <EM CLASS="Literal">allow</em>
+ or <EM CLASS="Literal">hosts</em>
+ <EM CLASS="Literal">deny</em>
+ configuration options will not permit connections from localhost (IP address 127.0.0.1), or the <EM CLASS="Literal">encrypted</em>
+ <EM CLASS="Literal">passwords</em>
+ <EM CLASS="Literal">=</em>
+ <EM CLASS="Literal">no</em>
+ option is set.</p>
+<DIV>
+<H4 CLASS="HeadC">Regular user options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-D</em>
+ <EM CLASS="Replaceable">debug_level</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the debug (also called logging) level. The level can range from 0 to 10. Debug level 0 logs only the most important messages; level 1 is normal; level 3 and above are primarily for debugging and slow the program considerably.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints command-line usage information for the program.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-r</em>
+ <EM CLASS="Replaceable">remote_machine_name</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Specifies on which machine the password should change. The remote machine must be a primary domain controller (PDC).</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-R</em>
+ <EM CLASS="Replaceable">resolve_order</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets the resolve order of the name servers. This option is similar to the <EM CLASS="Literal">resolve</em>
+ <EM CLASS="Literal">order</em>
+ configuration option, and can take any of the four parameters, <EM CLASS="Literal">lmhosts</em>, <EM CLASS="Literal">host</em>, <EM CLASS="Literal">wins</em>, and <EM CLASS="Literal">bcast</em>,<EM CLASS="Literal"> </em> in any order.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-U</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Used only with <EM CLASS="Literal">-r</em>, to modify a username that is spelled differently on the remote machine.</li>
+</ul>
+<DIV>
+<H4 CLASS="HeadC">Root-only options</h4>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-a</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Adds a user to the encrypted password file.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-d</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Disables a user in the encrypted password file.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-e</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Enables a disabled user in the encrypted password file.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-m</em>
+ <EM CLASS="Replaceable">machine_name</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Changes a machine account's password. The machine accounts are used to authenticate machines when they connect to a primary or backup domain controller.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-j</em>
+ <EM CLASS="Replaceable">domain_name</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Adds a Samba server to a Windows NT Domain.</li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-n</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Sets no password for the user.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">username</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Causes <EM CLASS="Emphasis">smbpasswd</em>
+ to be silent and to read its old and new passwords from standard input, rather than from <EM CLASS="Filename">/dev/tty</em>. This is useful for writing scripts.</li>
+</ul>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">testparm</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">testparm</em>
+ program checks an <EM CLASS="Filename">smb.conf</em>
+ file for obvious errors and self-consistency. Its command line is:</p>
+<P CLASS="Code">testparm [options] <EM CLASS="Replaceable">configfile_name [hostname IP_addr]</em>
+</p>
+<P CLASS="Body">If the configuration file is not specified, the file at <EM CLASS="Replaceable">samba_dir</em>
+<EM CLASS="Filename">/lib/smb.conf</em>
+ is checked by default. If you specify a hostname and an IP address, an extra check will be made to ensure that the specified machine would be allowed to connect to Samba. If a hostname is specified, an IP address should be present as well.</p>
+<DIV>
+<H4 CLASS="HeadC">Options</h4>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-h</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Prints command-line information for the program.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-L</em>
+ server_name</h4>
+<UL>
+<LI CLASS="ListVariable">Resets the <EM CLASS="Literal">%L</em>
+ configuration variable to the specified server name. </li>
+</ul>
+<DIV>
+<H4 CLASS="ListVariableTermRunin"><EM CLASS="Literal">-s</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">This option prevents the <EM CLASS="Emphasis">testparm</em>
+ program from prompting the user to press the Enter key before printing a list of the configuration options for the server.</li>
+</ul>
+</div>
+</div>
+</div>
+<DIV>
+<H3 CLASS="HeadB">testprns</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">testprns</em>
+ program checks a specified printer name against the system printer capabilities (<EM CLASS="Filename">printcap</em>) file. Its command line is:</p>
+<P CLASS="Code">testprns <EM CLASS="Replaceable">printername</em>
+ [<EM CLASS="Replaceable">printcapname</em>]</p>
+<P CLASS="Body">If the <EM CLASS="Literal">printcapname</em>
+ isn't specified, Samba attempts to use one located in the <EM CLASS="Filename">smb.conf</em>
+ file. If one isn't specified there, Samba will try <EM CLASS="Filename">/etc/printcap</em>. If that fails, the program will generate an error.</p>
+</div>
+<DIV>
+<H3 CLASS="HeadB">rpcclient</h3>
+<P CLASS="Body">This is a new client that exercises the RPC (remote procedure call) interfaces of an SMB server. Like <EM CLASS="Emphasis">smbclient</em>, <EM CLASS="Emphasis">rpcclient</em>
+ started its life as a test program for the Samba developers and will likely stay that way for a while. Its command line is:</p>
+<P CLASS="Code">rpcclient //<EM CLASS="Replaceable">server</em>/<EM CLASS="Replaceable">share</em>
+</p>
+<P CLASS="Body">The command-line options are the same as the Samba 2.0 <EM CLASS="Emphasis">smbclient</em>, and the operations you can try are listed below. </p>
+<TABLE>
+<CAPTION>
+<H4 CLASS="TableLabel"><A NAME="65243"></a>&nbsp;</h4>
+<H4 CLASS="TableTitle">rpcclient commands </h4>
+</caption>
+<TR>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Command</p>
+</th>
+<TH ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellHeading">Description</p>
+</th>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regenum keyname</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Enumeration (keys, values)</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regdeletekey keyname </em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Key Delete</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regcreatekey keyname [keyvalue]</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Key Create</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regquerykey keyname</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Key Query</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regdeleteval valname</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Value Delete</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regcreateval valname valtype value</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Key Create</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">reggetsec keyname</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Registry Key Security</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">regtestsec keyname</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Test Registry Key Security</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">ntlogin [username] [password]</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">NT Domain Login Test</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">wksinfo</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Workstation Query Info</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">srvinfo</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Server Query Info</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">srvsessions</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">List Sessions on a Server</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">srvshares</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">List shares on a server</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">srvconnections</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">List connections on a server </p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">srvfiles</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">List files on a server</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">lsaquery</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Query Info Policy (domain member or server)</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">lookupsids</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">Resolve names from SIDs</p>
+</td>
+</tr>
+<TR>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody"><EM CLASS="Literal">ntpass</em>
+</p>
+</td>
+<TD ROWSPAN="1" COLSPAN="1">
+<P CLASS="CellBody">NT SAM Password Change</p>
+</td>
+</tr>
+</table>
+</div>
+<DIV>
+<H3 CLASS="HeadB">tcpdump</h3>
+<P CLASS="Body">The <EM CLASS="Emphasis">tcpdump</em>
+ utility, a classic system administration tool, dumps all the packet headers it sees on an interface that match an expression. The version included in the Samba distribution is enhanced to understand the SMB protocol. The <EM CLASS="Emphasis">expression</em>
+ is a logical expression with &quot;and,&quot; &quot;or,&quot; and &quot;not,&quot; although sometimes it's very simple. For example, <EM CLASS="Literal">host</em>
+ <EM CLASS="Literal">escrime</em>
+ would select every packet going to or from <EM CLASS="Literal">escrime</em>. The expression is normally one or more of:</p>
+<UL>
+<LI CLASS="ListBullet"><EM CLASS="Literal">host</em>
+ <EM CLASS="Replaceable">name</em>
+</li>
+<LI CLASS="ListBullet"><EM CLASS="Literal">net network_number</em>
+</li>
+<LI CLASS="ListBullet"><EM CLASS="Literal">port</em>
+ <EM CLASS="Replaceable">number</em>
+</li>
+<LI CLASS="ListBullet"><EM CLASS="Literal">src</em>
+ <EM CLASS="Replaceable">name </em>
+</li>
+<LI CLASS="ListBullet"><EM CLASS="Literal">dst</em>
+ <EM CLASS="Replaceable">name</em>
+ </li>
+</ul>
+<P CLASS="Body">The most common options are <EM CLASS="Literal">src</em>
+ (source), <EM CLASS="Literal">dst</em>
+ (destination), and <EM CLASS="Literal">port</em>. For example, in the book we used the command: </p>
+<P CLASS="Code">tcpdump port not telnet</p>
+<P CLASS="Body">This dumps all the packets except telnet; we were logged-in via telnet and wanted to see only the SMB packets. </p>
+<P CLASS="Body">Another <EM CLASS="Emphasis">tcpdump</em>
+ example is selecting traffic between server and either <EM CLASS="Literal">sue</em>
+ or <EM CLASS="Literal">joe</em>:</p>
+<P CLASS="Code">tcpdump host server and &#92;(sue or joe &#92;)</p>
+<P CLASS="Body">We recommend using the <EM CLASS="Literal">-s</em>
+ <EM CLASS="Literal">1500</em>
+ option so that you capture all of the SMB messages sent, instead of just the header information. </p>
+<DIV>
+<H4 CLASS="HeadC">Options</h4>
+<P CLASS="Body">There are many options, and many other kinds of expressions that can be used with <EM CLASS="Emphasis">tcpdump</em>. See the manual page for details on the advanced options. The most common options are as follows: </p>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-c</em>
+ <EM CLASS="Replaceable">count</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Forces the program to exit after receiving the specified number of packets.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-F</em>
+ <EM CLASS="Replaceable">file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Reads the expression from the specified file and ignores expressions on the command line.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-i</em>
+ <EM CLASS="Replaceable">interface</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Forces the program to listen on the specified interface.</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-r</em>
+ <EM CLASS="Replaceable">file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Reads packets from the specified file (captured with <EM CLASS="Literal">-w</em>).</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-s</em>
+ <EM CLASS="Replaceable">length</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Saves the specified number of bytes of data from each packet (rather than 68 bytes).</li>
+</ul>
+</div>
+<DIV>
+<H4 CLASS="ListVariableTerm"><EM CLASS="Literal">-w</em>
+ <EM CLASS="Replaceable">file</em>
+</h4>
+<UL>
+<LI CLASS="ListVariable">Writes the packets to the specified file.</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+</blockquote>
+
+
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appc_01.html" TITLE="">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: Appendix C." BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appe_01.html" TITLE="">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: Appendix E." BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+C. Samba Configuration Option Quick Reference</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+E. Downloading Samba with CVS</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+
+</html>
diff --git a/docs/htmldocs/using_samba/appe_01.html b/docs/htmldocs/using_samba/appe_01.html
new file mode 100644
index 00000000000..199fade6967
--- /dev/null
+++ b/docs/htmldocs/using_samba/appe_01.html
@@ -0,0 +1,96 @@
+<HTML>
+<HEAD>
+<TITLE>[Appendix E] Downloading Samba with CVS</title>
+</head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: Appendix D." BORDER="0"></a></td>
+<TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix E</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appf_01.html" TITLE="">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: Appendix F." BORDER="0"></a></td></tr>
+</table>
+&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="appendix"><A CLASS="title" NAME="appe-58937">Appendix E. Downloading Samba with CVS</a></h1>
+<P CLASS="para">This appendix contains information on how to download the latest source version of Samba using the Concurrent Versions System (CVS). CVS is a freely available configuration management tool available from Cyclic Software and is distributed under the GNU General Public License. You can download the latest copy from <A CLASS="systemitem.url" HREF="http://www.cyclic.com/">
+http://www.cyclic.com/</a>.</p><P CLASS="para">CVS works on top of the GNU Revision Control System (RCS). Many Unix systems come preinstalled with RCS. However, if you want to download the latest version of RCS, you can find it at <A CLASS="systemitem.url" HREF="http://ftp.gnu.org/gnu/rcs/">http://ftp.gnu.org/gnu/rcs/</a>.</p><P CLASS="para">
+One of the nicest things about CVS is its ability to handle remote logins. This means that people across the globe on the Internet can download and update various source files for any project that uses a CVS repository. Such is the case with Samba. Once you have RCS and CVS installed on your system, you must first log in to the Samba source server with the following command:</p><PRE CLASS="programlisting">
+cvs -d :pserver:cvs@cvs.samba.org:/cvsroot login</pre><P CLASS="para">
+This tells CVS to connect to the CVS server at <I CLASS="filename">
+cvs.samba.org</i>. Once you are connected, you can download the latest source tree with the following command:</p><PRE CLASS="programlisting">
+cvs -d :pserver:cvs@cvs.samba.org:/cvsroot co samba</pre><P CLASS="para">
+This will download the entire Samba distribution (file by file) into a directory entitled <I CLASS="filename">
+/samba</i>, which it will create on your hard drive. This directory will have the same structure as the Samba source distribution described in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>. It includes source and header files, documentation, and sample configuration files to help get you started. After that is completed, you can follow the instructions in <a href="ch02_01.html"><b>Chapter 2</b></a> to configure and compile Samba on your server.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: Appendix D." BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appf_01.html" TITLE="">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: Appendix F." BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+Appendix D: Summary of Samba Daemons and Commands</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+F. Sample Configuration File</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/appf_01.html b/docs/htmldocs/using_samba/appf_01.html
new file mode 100644
index 00000000000..9b709472256
--- /dev/null
+++ b/docs/htmldocs/using_samba/appf_01.html
@@ -0,0 +1,315 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Appendix F] Sample Configuration File
+</title>
+<META NAME="DC.title" CONTENT="">
+<META NAME="DC.creator" CONTENT="">
+<META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc.">
+<META NAME="DC.date" CONTENT="1999-11-08T16:28:53Z">
+<META NAME="DC.type" CONTENT="Text.Monograph">
+<META NAME="DC.format" CONTENT="text/html" SCHEME="MIME">
+<META NAME="DC.source" CONTENT="" SCHEME="ISBN">
+<META NAME="DC.language" CONTENT="en-US">
+<META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0">
+</head>
+
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<A HREF="index.html">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</a>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="D. Downloading Samba with CVS">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: D. Downloading Samba with CVS" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Appendix F</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+&nbsp;</td></tr></table>&nbsp;
+
+<hr noshade size=1></center>
+
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="appendix">
+<A CLASS="title" NAME="appf-10509">
+F. Sample Configuration File</a></h1><P CLASS="para">This appendix gives an example of a production <I CLASS="filename">
+smb.conf</i> file and looks at how many of the options are used in practice. The following is a slightly disguised version of one we used at a corporation with five Linux servers, five Windows for Workgroups clients and three NT Workstation clients:</p><PRE CLASS="programlisting">
+# smb.conf -- File Server System for: 1 Example.COM BSC &amp; Management Office
+[globals]
+ workgroup = 1EG_BSC
+ interfaces = 10.10.1.14/24 </pre><P CLASS="para">
+We provide this service on only one of the machine's interfaces. The <CODE CLASS="literal">
+interfaces</code> option sets its address and netmask, where <CODE CLASS="literal">
+/24</code> is the same as using the netmask 255.255.255.0:</p><PRE CLASS="programlisting">
+ comment = Samba ver. %v
+ preexec = csh -c `echo /usr/samba/bin/smbclient \
+ -M %m -I %I` &amp;</pre><P CLASS="para">
+We use the <KBD CLASS="command">
+preexec</kbd> command to log information about all connections by machine name (<CODE CLASS="literal">%m</code>) and IP address (<CODE CLASS="literal">%I)</code>:</p><PRE CLASS="programlisting">
+ # smbstatus will output various info on current status
+ status = yes
+ browseable = yes
+ printing = bsd
+
+ # the username that will be used for access to services
+ # specified with 'guest = ok'
+ guest account = samba </pre><P CLASS="para">
+The default guest account was <CODE CLASS="literal">
+nobody</code>, uid -1, which produced log messages on one of our machines saying "your server is being unfriendly," so we created a specific Samba guest account for browsing and printing:</p><PRE CLASS="programlisting">
+ # superuser account - admin privilages to shares, with no
+ # restrictions
+ # WARNING - use this with care: files can be modified,
+ # regardless of file permissions
+ admin users = root
+
+ # who is NOT allowed to connect to ANY service
+ invalid users = @wheel, mail, deamon, adt</pre><P CLASS="para">
+Daemons can't use Samba, only people. The <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> option closes a security hole; it prevents intruders from breaking in by pretending to be a daemon process.</p><PRE CLASS="programlisting">
+ # hosts that are ALLOWED or DENIED from connecting to ANY service
+ hosts allow = 10.10.1.
+ hosts deny = 10.10.1.6
+
+ # where the lock files will be located
+ lock directory = /var/lock/samba/locks
+
+ # debug log files
+ # %m = separate log for each NetBIOS name (each machine)
+ log file = /var/log/samba/log.%m
+
+ # We send priority 0, 1 and 2 messages to the system logs
+ syslog = 2
+
+ # If a WinPopup message is sent to the server,
+ # redirect it to a user via e-mail
+
+ message command = /bin/mail -s 'message from #% on %m' \
+ pkelly &lt; %s; rm %s
+
+# ---------------------------------------------------
+# [globals] Performance Tuning
+# ---------------------------------------------------
+
+ # caching algorithm to reduce time doing getwd() calls.
+ getwd cache = yes
+
+ socket options = TCP_NODELAY
+
+ # tell the server whether the client is present and
+ # responding in seconds
+ keep alive = 60
+
+ # num minutes of inactivity before a connection is
+ # considered dead
+ dead time = 30
+
+ read prediction = yes
+ share modes = yes
+ max xmit = 17384
+ read size = 512</pre><P CLASS="para">
+The <CODE CLASS="literal">
+share</code> <CODE CLASS="literal">
+modes</code>, <CODE CLASS="literal">
+max</code>, <CODE CLASS="literal">
+xinit</code>, and <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+size</code> options are machine-specific (see <a href="appb_01.html"><b>Appendix B, <CITE CLASS="appendix">Samba Performance Tuning</cite></b></a>): </p><PRE CLASS="programlisting">
+ # locking is done by the server
+ locking = yes
+
+ # control whether dos style attributes should be mapped
+ # to unix execute bits
+ map hidden = yes
+ map archive = yes
+ map system = yes</pre><P CLASS="para">
+The three <CODE CLASS="literal">
+map</code> options will work only on shares with a create mode that includes the execute bits (0111). Our <CODE CLASS="literal">
+homes</code> and <CODE CLASS="literal">
+printers</code> shares won't honor them, but the [<CODE CLASS="literal">www]</code> share will:</p><PRE CLASS="programlisting">
+# ---------------------------------------------------------
+# [globals] Security and Domain Logon Services
+# ---------------------------------------------------------
+# connections are made with UID and GID, not as shares
+ security = user
+
+# boolean variable that controls whether passwords
+# will be encrypted
+ encrypt passwords = yes
+ passwd chat = &quot;*New password:*&quot; %n\r &quot;*New password (again):*&quot; %n\r \ &quot;*Password changed*&quot;
+ passwd program = /usr/bin/passwd %u
+
+# Always become the local master browser
+ domain master = yes
+ preferred master = yes
+ os level = 34
+
+# For domain logons to work correctly. Samba acts as a
+# primary domain controller.
+ domain logons = yes
+
+# Logon script to run for user off the server each time
+# username (%U) logs in. Set the time, connect to shares,
+# virus checks, etc.
+ logon script = scripts\%U.bat
+
+[netlogon]
+ comment = &quot;Domain Logon Services&quot;
+ path = /u/netlogon
+ writable = yes
+ create mode = 444
+ guest ok = no
+ volume = &quot;Network&quot;</pre><P CLASS="para">
+This share, discussed in <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a>, is required for Samba to work smoothly in a Windows NT domain:</p><PRE CLASS="programlisting">
+# -----------------------------------------------------------
+# [homes] User Home Directories
+# -----------------------------------------------------------
+[homes]
+ comment = &quot;Home Directory for : %u &quot;
+ path = /u/users/%u</pre><P CLASS="para">
+The password file of the Samba server specifies each person's home directory as <EM CLASS="emphasis">
+/home/</em><CODE CLASS="replaceable"><I>machine_name</i></code><EM CLASS="emphasis">/</em><CODE CLASS="replaceable"><I>person</i></code>, which NFS converts to point to the actual physicl location under <EM CLASS="emphasis">
+/u/users</em>. The <CODE CLASS="literal">
+path</code> option in the <CODE CLASS="literal">
+[homes]</code> share tells Samba the actual (non-NFS) location:</p><PRE CLASS="programlisting">
+ guest ok = no
+ read only = no
+ create mode = 644
+ writable = yes
+ browseable = no
+
+# -----------------------------------------------------------
+# [printers] System Printers
+# -----------------------------------------------------------
+[printers]
+ comment = &quot;Printers&quot;
+ path = /var/spool/lpd/samba
+ printcap name = /etc/printcap
+ printable = yes
+ public = no
+ writable = no
+
+ lpq command = /usr/bin/lpq -P%p
+ lprm command = /usr/bin/lprm -P%p %j
+ lppause command = /usr/sbin/lpc stop %p
+ lpresume command = /usr/sbin/lpc start %p
+
+ create mode = 0700
+
+ browseable = no
+ load printers = yes
+
+# -----------------------------------------------------------
+# Specific Descriptions: [programs] [data] [retail]
+# -----------------------------------------------------------
+[programs]
+ comment = &quot;Shared Programs %T&quot;
+ volume = &quot;programs&quot;</pre><P CLASS="para">
+Shared Programs shows up in the Network Neighborhood, and <CODE CLASS="literal">
+programs</code> is the volume name you specify when an installation program wants to know the label of the CD-ROM from which it thinks it's loading:</p><PRE CLASS="programlisting">
+ path = /u/programs
+ public = yes
+ writeable = yes
+ printable = no
+ create mode = 664
+[cdrom]
+ comment = &quot;Unix CDROM&quot;
+ path = /u/cdrom
+ public = no
+ writeable = no
+ printable = no
+ volume = &quot;cdrom&quot;
+
+[data]
+ comment = &quot;Data Directories %T&quot;
+ path = /u/data
+ public = no
+ create mode = 770
+ writeable = yes
+ volume = &quot;data&quot;
+
+[nt4]
+ comment = &quot;NT4 Server&quot;
+ path = /u/systems/nt4
+ public = yes
+ create mode = 770
+ writeable = yes
+ volume = &quot;nt4_server&quot;
+
+[www]
+ comment = &quot;WWW System&quot;
+ path = /usr/www/http
+ public = yes
+ create mode = 775
+ writeable = yes
+ volume = &quot;www_system&quot;</pre><P CLASS="para">
+The <CODE CLASS="literal">
+[www]</code> share is the directory used on the Unix server to serve web pages. Samba makes the directory available to local PC users so the art department can update web pages.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appd_01.html" TITLE="D. Downloading Samba with CVS">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: D. Downloading Samba with CVS" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">&nbsp;</td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+D. Downloading Samba with CVS</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+&nbsp;</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_01.html b/docs/htmldocs/using_samba/ch01_01.html
new file mode 100644
index 00000000000..0651fa823c3
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_01.html
@@ -0,0 +1,167 @@
+<HTML>
+<HEAD>
+<TITLE>[Chapter 1] 1.1 Learning Samba</title>
+</head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+</td>
+<TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+</td>
+<TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_02.html" TITLE="1.2 What Can Samba Do For Me?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.2 What Can Samba Do For Me?" BORDER="0"></a>
+</td>
+</tr>
+</table>&nbsp;
+<hr noshade size=1>
+</center>
+</div>
+<blockquote>
+<div>
+<H1 CLASS="sect1">1. Learning the Samba</h1>
+<p>If you are a typical system administrator, then you know what it means to be <i>swamped</i> with work. Your daily routine is filled with endless hardware incompatibility issues, system outages, data backup problems, and a steady stream of angry users. So adding another program to the mix of tools that you have to maintain may sound a bit perplexing. However, if you're determined to reduce the complexity of your work environment, as well as the workload of keeping it running smoothly, Samba may be the tool you've been waiting for.</p>
+
+<p>A case in point: one of the authors of this book used to look after 70 Unix developers sharing 5 Unix servers. His neighbor administered 20 Windows 3.1 users and 5 OS/2 and Windows NT servers. To put it mildly, the Windows 3.1 administrator was swamped. When he finally left - and the domain controller melted - Samba was brought to the rescue. Our author quickly replaced the Windows NT and OS/2 servers with Samba running on a Unix server, and eventually bought PCs for most of the company developers. However, he did the latter without hiring a new PC administrator; the administrator now manages one centralized Unix application instead of fifty distributed PCs. </p>
+
+<p>If you know you're facing a problem with your network and you're sure there is a better way, we encourage you to start reading this book. Or, if you've heard about Samba and you want to see what it can do for you, this is also the place to start. We'll get you started on the path to understanding Samba and its potential. Before long, you can provide Unix services to all your Windows machines - all without spending tons of extra time or money. Sound enticing? Great, then let's get started.</p>
+
+<a name="s1"></a>
+<h2 id="ch01-28119">1.1 What is Samba?</h2>
+
+<p>Samba is a suite of Unix applications that speak the SMB (Server Message Block) protocol. Many operating systems, including Windows and OS/2, use SMB to perform client-server networking. By supporting this protocol, Samba allows Unix servers to get in on the action, communicating with the same networking protocol as Microsoft Windows products. Thus, a Samba-enabled Unix machine can masquerade as a server on your Microsoft network and offer the following services:</p>
+
+<ul>
+<li id="ch01-pgfId-940463">
+
+<p>Share one or more filesystems</p>
+
+</li>
+<li id="ch01-pgfId-940464">
+
+<p>Share printers installed on both the server and its clients</p>
+
+</li>
+<li id="ch01-pgfId-940465">
+
+<p>Assist clients with Network Neighborhood browsing</p>
+
+</li>
+<li id="ch01-pgfId-940489">
+
+<p>Authenticate clients logging onto a Windows domain</p>
+
+</li>
+<li id="ch01-pgfId-940472">
+
+<p>Provide or assist with WINS name server resolution</p>
+
+</li>
+</ul>
+
+<p>Samba is the brainchild of Andrew Tridgell, who currently heads the Samba development team from his home of Canberra, Australia. The project was born in 1991 when Andrew created a fileserver program for his local network that supported an odd DEC protocol from Digital Pathworks. Although he didn't know it at the time, that protocol later turned out to be SMB. A few years later, he expanded upon his custom-made SMB server and began distributing it as a product on the Internet under the name SMB Server. However, Andrew couldn't keep that name - it already belonged to another company's product - so he tried the following Unix renaming approach:</p>
+
+<pre>
+grep -i 's.*m.*b' /usr/dict/words </pre>
+
+<p>And the response was:</p>
+
+<Pre>
+salmonberry samba sawtimber scramble</pre>
+
+<p>Thus, the name "Samba" was born.<footnote id="ch01-pgfId-946532">
+
+<p>Which is a good thing, because our marketing people highly doubt you would have picked up a book called "Using Salmonberry"!</p>
+
+</footnote></p>
+
+<p>Today, the Samba suite revolves around a pair of Unix daemons that provide shared resources - or <i>shares</i> - to SMB clients on the network. (Shares are sometimes called s<i>ervices</i> as well.) These daemons are:</p>
+
+<dl>
+<dt>smbd</dt>
+<dd>
+
+<p id="ch01-pgfId-949804">A daemon that allows file and printer sharing on an SMB network and provides authentication and authorization for SMB clients.</p>
+
+</dd>
+
+<dt>nmbd</dt>
+<dd>
+
+<p id="ch01-pgfId-949805">A daemon that looks after the Windows Internet Name Service (WINS), and assists with browsing.</p>
+
+</dd>
+</dl>
+
+<p>Samba is currently maintained and extended by a group of volunteers under the active supervision of Andrew Tridgell. Like the Linux operating system, Samba is considered <i>Open Source software </i>(OSS) by its authors, and is distributed under the GNU General Public License (GPL). Since its inception, development of Samba has been sponsored in part by the Australian National University, where Andrew Tridgell earned his Ph.D.<a href = "#footnote"> [1]</a>
+ In addition, some development has been sponsored by independent vendors such as Whistle and SGI. It is a true testament to Samba that both commercial and non-commercial entities are prepared to spend money to support an Open Source effort.</p>
+<blockquote><a name="footnote">
+<p>[1] At the time of this printing, Andrew had completed his Ph.D. work and had joined San Francisco-based LinuxCare.</p>
+</blockquote>
+<p>Microsoft has also contributed materially by putting forward its definition of SMB and the Internet-savvy Common Internet File System (CIFS), as a public Request for Comments (RFC), a standards document. The CIFS protocol is Microsoft's renaming of future versions of the SMB protocol that will be used in Windows products - the two terms can be used interchangeably in this book. Hence, you will often see the protocol written as "SMB/CIFS."</p> </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+
+</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_02.html" TITLE="1.2 What Can Samba Do For Me?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.2 What Can Samba Do For Me?" BORDER="0"></a></td></tr><TR>
+
+<TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.1 Learning Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_02.html b/docs/htmldocs/using_samba/ch01_02.html
new file mode 100644
index 00000000000..9ccb2dfeee2
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_02.html
@@ -0,0 +1,212 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.2 What Can Samba Do For Me?</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:50Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_01.html" TITLE="1.1 What is Samba?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.1 What is Samba?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_03.html" TITLE="1.3 Getting Familiar with a SMB/CIFS Network">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.3 Getting Familiar with a SMB/CIFS Network" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-pgfId-937232">
+1.2 What Can Samba Do For Me?</a></h2><P CLASS="para">
+As explained earlier, Samba can help Windows and Unix machines coexist in the same network. However, there are some specific reasons why you might want to set up a Samba server on your network:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-941390">
+</a>You don't want to pay for&nbsp;- or can't afford&nbsp;- a full-fledged Windows NT server, yet you still need the functionality that one provides.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-941391">
+</a>You want to provide a common area for data or user directories in order to transition from a Windows server to a Unix one, or vice versa.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-941394">
+</a>You want to be able to share printers across both Windows and Unix workstations.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-941973">
+</a>You want to be able to access NT files from a Unix server.</p></li></ul><P CLASS="para">
+Let's take a quick tour of Samba in action. Assume that we have the following basic network configuration: a Samba-enabled Unix machine, to which we will assign the name <CODE CLASS="literal">
+hydra</code>, and a pair of Windows clients, to which we will assign the names <CODE CLASS="literal">
+phoenix</code> and <CODE CLASS="literal">
+chimaera</code>, all connected via a local area network (LAN). Let's also assume that <CODE CLASS="literal">
+hydra</code> also has a local inkjet printer connected to it, <CODE CLASS="literal">
+lp</code>, and a disk share named <CODE CLASS="literal">
+network</code>&nbsp;- both of which it can offer to the other two machines. A graphic of this network is shown in <A CLASS="xref" HREF="ch01_02.html#ch01-45964">
+Figure 1.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-45964">
+Figure 1.1: A simple network setup with a Samba server</a></h4><IMG CLASS="graphic" SRC="figs/sam.0101.gif" ALT="Figure 1.1"><P CLASS="para">
+In this network, each of the computers listed share the same <I CLASS="firstterm">
+workgroup</i>. A workgroup is simply a group nametag that identifies an arbitrary collection of computers and their resources on an SMB network. There can be several workgroups on the network at any time, but for our basic network example, we'll have only one: the SIMPLE workgroup.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937316">
+1.2.1 Sharing a Disk Service</a></h3><P CLASS="para">If everything is properly configured, we should be able to see the Samba server, <CODE CLASS="literal">
+hydra</code>, through the Network Neighborhood of the <CODE CLASS="literal">
+phoenix</code> Windows desktop. In fact, <A CLASS="xref" HREF="ch01_02.html#ch01-60493">
+Figure 1.2</a> shows the Network Neighborhood of the <CODE CLASS="literal">
+phoenix</code> computer, including <CODE CLASS="literal">
+hydra</code> and each of the computers that reside in the SIMPLE workgroup. Note the Entire Network icon at the top of the list. As we just mentioned, there can be more than one workgroup on an SMB network at any given time. If a user clicks on the Entire Network icon, he or she will see a list of all the workgroups that currently exist on the network. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-60493">
+Figure 1.2: The Network Neighborhood directory</a></h4><IMG CLASS="graphic" SRC="figs/sam.0102.gif" ALT="Figure 1.2"><P CLASS="para">
+We can take a closer look at the <CODE CLASS="literal">
+hydra</code> server by double-clicking on its icon. This contacts <CODE CLASS="literal">
+hydra</code> itself and requests a list of its <I CLASS="firstterm">
+shares</i>&nbsp;- the file and printer resources&nbsp;- that the machine provides. In this case, there is a printer entitled <CODE CLASS="literal">
+lp</code> and a disk share entitled <CODE CLASS="literal">
+network</code> on the server, as shown in <A CLASS="xref" HREF="ch01_02.html#ch01-76011">
+Figure 1.3</a>. Note that the Windows display shows hostnames in mixed case (Hydra). Case is irrelevant in hostnames, so you may see hydra, Hydra, and HYDRA in various displays or command output, but they all refer to a single system. Thanks to Samba, Windows 98 sees the Unix server as a valid SMB server, and can access the <CODE CLASS="literal">
+network</code> folder as if it were just another system folder. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-76011">
+Figure 1.3: Shares available on the hydra sever as viewed from phoenix</a></h4><IMG CLASS="graphic" SRC="figs/sam.0103.gif" ALT="Figure 1.3"><P CLASS="para">
+One popular feature of Windows 95/98/NT is that you can map a letter-drive to a known network directory using the Map Network Drive option in the Windows Explorer.[<A CLASS="footnote" HREF="#ch01-pgfId-941061">3</a>] Once you do so, your applications can access the folder across the network with a standard drive letter. Hence, you can store data on it, install and run programs from it, and even password-protect it against unwanted visitors. See <A CLASS="xref" HREF="ch01_02.html#ch01-55465">
+Figure 1.4</a> for an example of mapping a letter-drive to a network directory. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch01-pgfId-941061">[3]</a> You can also right-click on the shared resource in the Network Neighborhood, and then select the Map Network Drive menu item.</p></div></blockquote><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-55465">
+Figure 1.4: Mapping a network drive to a Windows letter-drive</a></h4><IMG CLASS="graphic" SRC="figs/sam.0104.gif" ALT="Figure 1.4"><P CLASS="para">
+Take a look at the Path: entry in the dialog box of <A CLASS="xref" HREF="ch01_02.html#ch01-55465">
+Figure 1.4</a>. An equivalent way to represent a directory on a network machine is by using two backslashes, followed by the name of the networked machine, another backslash, and the networked directory of the machine, as shown below:</p>
+
+<PRE><I>\\network-machine\directory</i></pre>
+
+<P CLASS="para">
+This is known as the <I CLASS="firstterm">
+UNC</i> (Universal Naming Convention) in the Windows world. For example, the dialog box in <A CLASS="xref" HREF="ch01_02.html#ch01-55465">
+Figure 1.4</a> represents the network directory on the <CODE CLASS="literal">
+hydra</code> server as:</p>
+
+<PRE CLASS="programlisting">\\HYDRA\<CODE CLASS="replaceable"><I>network</i></code></pre><P CLASS="para">
+
+If this looks somewhat familiar to you, you're probably thinking of <I CLASS="firstterm">
+uniform resource locators</i> (URLs), which are addresses that web browsers such as Netscape Navigator and Internet Explorer use to resolve machines across the Internet. Be sure not to confuse the two: web browsers typically use forward slashes instead of back slashes, and they precede the initial slashes with the data transfer protocol (i.e., ftp, http) and a colon (:). In reality, URLs and UNCs are two completely separate things.</p><P CLASS="para">
+Once the network drive is set up, Windows and its programs will behave as if the networked directory was a fixed disk. If you have any applications that support multiuser functionality on a network, you can install those programs on the network drive.[<A CLASS="footnote" HREF="#ch01-pgfId-952017">4</a>] <A CLASS="xref" HREF="ch01_02.html#ch01-32686">
+Figure 1.5</a> shows the resulting network drive as it would appear with other storage devices in the Windows 98 client. Note the pipeline attachment in the icon for the G: drive; this indicates that it is a network drive instead of a fixed drive. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch01-pgfId-952017">[4]</a> Be warned that many end-user license agreements forbid installing a program on a network such that multiple clients can access it. Check the legal agreements that accompany the product to be absolutely sure.</p></div></blockquote><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-32686">
+Figure 1.5: The Network directory mapped to the client letter-drive G</a></h4><IMG CLASS="graphic" SRC="figs/sam.0105.gif" ALT="Figure 1.5"><P CLASS="para">
+From our Windows NT Workstation machine, <CODE CLASS="literal">
+chimaera</code>, Samba looks almost identical to Windows 98. <A CLASS="xref" HREF="ch01_02.html#ch01-29255">
+Figure 1.6</a> shows the same view of the <CODE CLASS="literal">
+hydra</code> server from the Windows NT 4.0 Network Neighborhood. Setting up the network drive using the Map Network Drive option in Windows NT Workstation 4.0 would have identical results as well. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-29255">
+Figure 1.6: Shares available on hydra (viewed from chimaera) </a></h4><IMG CLASS="graphic" SRC="figs/sam.0106.gif" ALT="Figure 1.6"></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-942088">
+1.2.2 Sharing a Printer</a></h3><P CLASS="para">You probably noticed that the printer <CODE CLASS="literal">
+lp</code> appeared under the available shares for <CODE CLASS="literal">
+hydra</code> in <A CLASS="xref" HREF="ch01_02.html#ch01-76011">
+Figure 1.3</a>. This indicates that the Unix server has a printer that can be shared by the various SMB clients in the workgroup. Data sent to the printer from any of the clients will be spooled on the Unix server and printed in the order it is received.</p><P CLASS="para">Setting up a Samba-enabled printer on the Windows side is even easier than setting up a disk share. By double-clicking on the printer and identifying the manufacturer and model, you can install a driver for this printer on the Windows client. Windows can then properly format any information sent to the network printer and access it as if it were a local printer (we show you how to do this later in the chapter). <A CLASS="xref" HREF="ch01_02.html#ch01-46265">
+Figure 1.7</a> shows the resulting network printer in the Printers window of Windows 98. Again, note the pipeline attachment below the printer, which identifies it as being on a network. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-46265">
+Figure 1.7: A network printer available on hydra (viewed from chimaera)</a></h4><IMG CLASS="graphic" SRC="figs/sam.0107.gif" ALT="Figure 1.7"><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-937586">
+1.2.2.1 Seeing things from the Unix side</a></h4><P CLASS="para">
+As mentioned earlier, Samba appears in Unix as a set of daemon programs. You can view them with the Unix <CODE CLASS="literal">
+ps</code> and <CODE CLASS="literal">
+netstat</code> commands, you can read any messages they generate through custom debug files or the Unix <CODE CLASS="literal">
+syslog</code> (depending on how Samba is set up), and you can configure it from a single Samba properties file: <i>smb.conf</i>. In addition, if you want to get an idea of what each of the daemons are doing, Samba has a program called
+<i>smbstatus</i> that will lay it all on the line. Here is how it works:</p>
+
+<PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">#</code> smbstatus</b>
+</pre><PRE CLASS="programlisting">
+Samba version 2.0.4
+Service uid gid pid machine
+----------------------------------------------
+network davecb davecb 7470 phoenix (192.168.220.101) Sun May 16
+network davecb davecb 7589 chimaera (192.168.220.102) Sun May 16
+
+Locked files:
+Pid DenyMode R/W Oplock Name
+--------------------------------------------------
+7589 DENY_NONE RDONLY EXCLUSIVE+BATCH /home/samba/quicken/inet/common/system/help.bmp Sun May 16 21:23:40 1999
+7470 DENY_WRITE RDONLY NONE /home/samba/word/office/findfast.exe Sun May 16 20:51:08 1999
+7589 DENY_WRITE RDONLY EXCLUSIVE+BATCH /home/samba/quicken/lfbmp70n.dll Sun May 16 21:23:39 1999
+7589 DENY_WRITE RDWR EXCLUSIVE+BATCH /home/samba/quicken/inet/qdata/runtime.dat Sun May 16 21:23:41 1999
+7470 DENY_WRITE RDONLY EXCLUSIVE+BATCH /home/samba/word/office/osa.exe Sun May 16 20:51:09 1999
+7589 DENY_WRITE RDONLY NONE /home/samba/quicken/qversion.dll Sun May 16 21:20:33 1999
+7470 DENY_WRITE RDONLY NONE /home/samba/quicken/qversion.dll Sun May 16 20:51:11 1999
+
+Share mode memory usage (bytes):
+ 1043432(99%) free + 4312(0%) used + 832(0%) overhead = 1048576(100%) total</pre><P CLASS="para">
+The Samba status from this output provides three sets of data, each divided into separate sections. The first section tells which systems have connected to the Samba server, identifying each client by its machine name (<CODE CLASS="literal">phoenix</code> and <CODE CLASS="literal">chimaera</code>) and IP address. The second section reports the name and status of the files that are currently in use on a share on the server, including the read/write status and any locks on the files. Finally, Samba reports the amount of memory it has currently allocated to the shares that it administers, including the amount actively used by the shares plus additional overhead. (Note that this is not the same as the total amount of memory that the <EM CLASS="emphasis">
+smbd</em> or <EM CLASS="emphasis">
+nmbd</em> processes are using.)</p><P CLASS="para">
+Don't worry if you don't understand these statistics; they will become easier to understand as you move through the book. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_01.html" TITLE="1.1 What is Samba?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.1 What is Samba?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_03.html" TITLE="1.3 Getting Familiar with a SMB/CIFS Network">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.3 Getting Familiar with a SMB/CIFS Network" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.1 What is Samba?</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.3 Getting Familiar with a SMB/CIFS Network</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_03.html b/docs/htmldocs/using_samba/ch01_03.html
new file mode 100644
index 00000000000..67a86775301
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_03.html
@@ -0,0 +1,444 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.3 Getting Familiar with a SMB/CIFS Network</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:52Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_02.html" TITLE="1.2 What Can Samba Do For Me?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.2 What Can Samba Do For Me?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_04.html" TITLE="1.4 Microsoft Implementations">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.4 Microsoft Implementations" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-88536">
+1.3 Getting Familiar with a SMB/CIFS Network</a></h2><P CLASS="para">Now that you have had a brief tour of Samba, let's take some time to get familiar with Samba's adopted environment: an SMB/CIFS network. Networking with SMB is significantly different from working with a Unix TCP/IP network, because there are several new concepts to learn and a lot of information to cover. First, we will discuss the basic concepts behind an SMB network, followed by some Microsoft implementations of it, and finally we will show you where a Samba server can and cannot fit into the picture.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-941409">
+1.3.1 Understanding NetBIOS</a></h3><P CLASS="para">
+To begin, let's step back in time. In 1984, IBM authored a simple application programming interface (API) for networking its computers called the <I CLASS="firstterm">
+Network Basic Input/Output System </i>(NetBIOS). The NetBIOS API provided a rudimentary design for an application to connect and share data with other computers.</p><P CLASS="para">
+It's helpful to think of the NetBIOS API as networking extensions to the standard BIOS API calls. With BIOS, each low-level call is confined to the hardware of the local machine and doesn't need any help traveling to its destination. NetBIOS, however, originally had to exchange instructions with computers across IBM PC or Token Ring networks. It therefore required a low-level transport protocol to carry its requests from one computer to the next.</p><P CLASS="para">
+In late 1985, IBM released one such protocol, which it merged with the NetBIOS API to become the <I CLASS="firstterm">
+NetBIOS Extended User Interface</i> (<EM CLASS="emphasis">NetBEUI</em>). NetBEUI was designed for small local area networks (LANs), and it let each machine claim a name (up to 15 characters) that wasn't already in use on the network. By a "small LAN," we mean fewer than 255 nodes on the network&nbsp;- which was considered a practical restriction in 1985!</p><P CLASS="para">
+The NetBEUI protocol was very popular with networking applications, including those running under Windows for Workgroups. Later, implementations of NetBIOS over Novell's IPX networking protocols also emerged, which competed with NetBEUI. However, the networking protocols of choice for the burgeoning Internet community were TCP/IP and UDP/IP, and implementing the NetBIOS APIs over those protocols soon became a necessity.</p><P CLASS="para">
+Recall that TCP/IP uses numbers to represent computer addresses, such as 192.168.220.100, while NetBIOS uses only names. This was a major issue when trying to mesh the two protocols together. In 1987, the Internet Engineering Task Force (IETF) published a series of standardization documents, titled RFC 1001 and 1002, that outlined how NetBIOS would work over a TCP/UDP network. This set of documents still governs each of the implementations that exist today, including those provided by Microsoft with their Windows operating systems as well as the Samba suite.</p><P CLASS="para">
+Since then, the standard this document governs has become known as <I CLASS="firstterm">
+NetBIOS over TCP/IP</i>, or NBT for short. The NBT standard (RFC 1001/1002) currently outlines a trio of services on a network:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-946789">
+</a>A name service</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-946790">
+</a>Two communication services: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-952037">
+</a>Datagrams </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-952038">
+</a>Sessions</p></li></ul></li></ul><P CLASS="para">
+The name service solves the name-to-address problem mentioned earlier; it allows each computer to declare a specific name on the network that can be translated to a machine-readable IP address, much like today's DNS on the Internet. The datagram and session services are both secondary communication protocols used to transmit data back and forth from NetBIOS machines across the network.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-945521">
+1.3.2 Getting a Name</a></h3><P CLASS="para">For a human being, getting a name is easy. However, for a machine on a NetBIOS network, it can be a little more complicated. Let's look at a few of the issues.</p><P CLASS="para">
+In the NetBIOS world, when each machine comes online, it wants to claim a name for itself; this is called <I CLASS="firstterm">
+name registration</i>. However, no two machines in the same workgroup should be able to claim the same name; this would cause endless confusion for any machine that wanted to communicate with either machine. There are two different approaches to ensuring that this doesn't happen:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-945120">
+</a>Use a <I CLASS="firstterm">
+NetBIOS Name Server</i> (NBNS) to keep track of which hosts have registered a NetBIOS name. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-945121">
+</a>Allow each machine on the network to defend its name in the event that another machine attempts to use it.</p></li></ul><P CLASS="para">
+<A CLASS="xref" HREF="ch01_03.html#ch01-86658">
+Figure 1.8</a> illustrates a (failed) name registration, with and without a NetBIOS Name Server. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-86658">
+Figure 1.8: NBNS versus non-NBNS name registration</a></h4><IMG CLASS="graphic" SRC="figs/sam.0108.gif" ALT="Figure 1.8"><P CLASS="para">
+In addition, there must be a way to resolve a NetBIOS name to a specific IP address as mentioned earlier; this is known as <I CLASS="firstterm">
+name resolution</i>. There are two different approaches with NBT here as well:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-945526">
+</a>Have each machine report back its IP address when it "hears" a broadcast request for its NetBIOS name.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-945527">
+</a>Use the NBNS to help resolve NetBIOS names to IP addresses. </p></li></ul><P CLASS="para">
+<A CLASS="xref" HREF="ch01_03.html#ch01-72484">
+Figure 1.9</a> illustrates the two types of name resolution. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-72484">
+Figure 1.9: NBNS versus non-NBNS name resolution</a></h4><IMG CLASS="graphic" SRC="figs/sam.0109.gif" ALT="Figure 1.9"><P CLASS="para">
+As you might expect, having an NBNS on your network can help out tremendously. To see exactly why, let's look at the non-NBNS method.</p><P CLASS="para">
+Here, when a client machine boots, it will broadcast a message declaring that it wishes to register a specified NetBIOS name as its own. If nobody objects to the use of the name after multiple registration attempts, it keeps the name. On the other hand, if another machine on the local subnet is currently using the requested name, it will send a message back to the requesting client that the name is already taken. This is known as <I CLASS="firstterm">
+defending</i> the hostname. This type of system comes in handy when one client has unexpectedly dropped off the network&nbsp;- another can take its name unchallenged&nbsp;- but it does incur an inordinate amount of traffic on the network for something as simple as name registration.</p><P CLASS="para">
+With an NBNS, the same thing occurs, except that the communication is confined to the requesting machine and the NBNS server. No broadcasting occurs when the machine wishes to register the name; the registration message is simply sent directly from the client to NBNS server and the NBNS server replies whether or not the name is already taken. This is known as <I CLASS="firstterm">
+point-to-point communication</i>, and is often beneficial on networks with more than one subnet. This is because routers are often preconfigured to block incoming packets that are broadcast to all machines in the subnet.</p><P CLASS="para">
+The same principles apply to name resolution. Without an NBNS, NetBIOS name resolution would also be done with a broadcast mechanism. All request packets would be sent to each computer in the network, with the hope that one machine that might be affected will respond directly back to the machine that asked. At this point, it's clear that using an NBNS server and point-to-point communication for this purpose is far less taxing on the network than flooding the network with broadcasts for every name resolution request. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-945664">
+1.3.3 Node Types</a></h3><P CLASS="para">How can you tell what strategy each client on your network will use when performing name registration and resolution? Each machine on an NBT network earns one of the following designations, depending on how it handles name registration and resolution: b-node, p-node, m-node, and h-node. The behaviors of each type of node are summarized in <A CLASS="xref" HREF="ch01_03.html#ch01-91681">
+Table 1.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-91681">
+Table 1.1: NetBIOS Node Types </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Role</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Value</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+b-node</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Uses broadcast registration and resolution only.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+p-node</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Uses point-to-point registration and resolution only.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+m-node</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Uses broadcast for registration. If successful, it notifies the NBNS server of the result. Uses broadcast for resolution; uses NBNS server if broadcast is unsuccessful.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+h-node (hybrid)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Uses NBNS server for registration and resolution; uses broadcast if the NBNS server is unresponsive or inoperative.</p></td></tr></tbody></table><P CLASS="para">
+In the case of Windows clients, you will usually find them listed as <I CLASS="firstterm">
+h-nodes</i> or <I CLASS="firstterm">
+hybrid nodes</i>. Incidentally, h-nodes were invented later by Microsoft, as a more fault-tolerant route, and do not appear in RFC 1001/1002.</p><P CLASS="para">
+You can find out the node type of any Windows machine by typing the command <CODE CLASS="literal">
+ipconfig</code> <CODE CLASS="literal">
+/all</code> and searching for the line that says <CODE CLASS="literal">
+Node Type</code>.</p>
+
+<PRE CLASS="programlisting"><B CLASS="emphasis.bold">C:\&gt; ipconfig /all</b>
+</pre><PRE CLASS="programlisting">
+Windows 98 IP Configuration
+...
+ Node Type . . . . . . . . . . : Hybrid
+...</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-945128">
+1.3.4 What's in a Name?</a></h3><P CLASS="para">
+The names NetBIOS uses are quite different from the DNS hostnames you might be familiar with. First, NetBIOS names exist in a flat namespace. In other words, there are no qualifiers such as <i>ora.com</i> or <i>samba.org</i> to section off hostnames; there is only a single unique name to represent each computer. Second, NetBIOS names are allowed to be only 15 characters, may not begin with an asterisk (*), and can consist only of standard alphanumeric characters (a-z, A-Z, 0-9) and the following:</p><PRE CLASS="programlisting">
+! @ # $ % ^ &amp; ( ) - ' { } . ~ </pre><P CLASS="para">
+Although you are allowed to use a period (.) in a NetBIOS name, we recommend against it because those names are not guaranteed to work in future versions of NetBIOS over TCP/IP.</p><P CLASS="para">
+It's not a coincidence that all valid DNS names are also valid NetBIOS names. In fact, the DNS name for a Samba server is often reused as its NetBIOS name. For example, if you had a machine <CODE CLASS="literal">
+phoenix.ora.com</code>, its NetBIOS name would likely be PHOENIX (followed by 8 blanks).</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-946016">
+1.3.4.1 Resource names and types</a></h4><P CLASS="para">
+With NetBIOS, a machine not only advertises its presence, but also tells others what types of services it offers. For example, <CODE CLASS="literal">
+phoenix</code> can indicate that it's not just a workstation, but is also a file server and can receive WinPopup messages. This is done by adding a 16th byte to the end of the machine (resource) name, called the <I CLASS="firstterm">resource type</i>, and registering the name more than once. See <A CLASS="xref" HREF="ch01_03.html#ch01-74707">
+Figure 1.10</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-74707">
+Figure 1.10: The structure of NetBIOS names</a></h4><IMG CLASS="graphic" SRC="figs/sam.0110.gif" ALT="Figure 1.10"><P CLASS="para">
+The one-byte resource type indicates a unique service the named machine provides. In this book, you will often see the resource type shown in angled brackets (&lt;&gt;) after the NetBIOS name, such as:</p><PRE CLASS="programlisting">PHOENIX&lt;00&gt;</pre><P CLASS="para">
+You can see which names are registered for a particular NBT machine using the Windows command-line NBTSTAT utility. Because these services are unique (i.e., there cannot be more than one registered), you will see them listed as type UNIQUE in the output. For example, the following partial output describes the <CODE CLASS="literal">
+hydra</code> server:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold">D:\&gt; NBTSTAT -a hydra</b><B CLASS="emphasis.bold"></b></pre><PRE CLASS="programlisting">
+ NetBIOS Remote Machine Name Table
+ Name Type Status
+---------------------------------------------
+HYDRA &lt;00&gt; UNIQUE Registered
+HYDRA &lt;03&gt; UNIQUE Registered
+HYDRA &lt;20&gt; UNIQUE Registered
+...</pre><P CLASS="para">
+This says the server has registered the NetBIOS name <CODE CLASS="literal">
+hydra</code> as a machine (workstation) name, a recipient of WinPopup messages, and a file server. Some possible attributes a name can have are listed in <A CLASS="xref" HREF="ch01_03.html#ch01-11471">
+Table 1.2</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-11471">
+Table 1.2: NetBIOS Unique Resource Types </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Named Resource</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Hexidecimal Byte Value</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Standard Workstation Service</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+00</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Messenger Service (WinPopup)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+03</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+RAS Server Service</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+06</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Domain Master Browser Service (associated with primary domain controller)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1B</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Master Browser name</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1D</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+NetDDE Service</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1F</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Fileserver (including printer server)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+20</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+RAS Client Service</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+21</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Monitor Agent</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+BE</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Monitor Utility</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+BF</p></td></tr></tbody></table><P CLASS="para">
+Note that because DNS names don't have resource types, the designers intentionally made hexidecimal value 20 (an ASCII space) default to the type for a file server.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-946074">
+1.3.4.2 Group names and types</a></h4><P CLASS="para">SMB also uses the concept of groups, with which machines can register themselves. Earlier, we mentioned that the machines in our example belonged to a <I CLASS="firstterm">
+workgroup</i>, which is a partition of machines on the same network. For example, a business might very easily have an ACCOUNTING and a SALES workgroup, each with different servers and printers. In the Windows world, a workgroup and an SMB group are the same thing.</p><P CLASS="para">
+Continuing our NBTSTAT example, the <CODE CLASS="literal">
+hydra</code> Samba server is also a member of the SIMPLE workgroup (the GROUP attribute hex 00), and will stand for election as a browse master (GROUP attribute 1E). Here is the remainder of the NBTSTAT utility output:</p><PRE CLASS="programlisting">
+ NetBIOS Remote Machine Name Table, continued
+ Name Type Status
+---------------------------------------------
+SIMPLE &lt;00&gt; GROUP Registered
+SIMPLE &lt;1E&gt; GROUP Registered
+..__MSBROWSE__. &lt;01&gt; GROUP Registered</pre><P CLASS="para">
+The possible group attributes a machine can have are illustrated in <A CLASS="xref" HREF="ch01_03.html#ch01-52395">
+Table 1.3</a>. More information is available in <i>Windows NT in a Nutshell</i> by Eric Pearce, also published by O'Reilly. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-52395">
+Table 1.3: NetBIOS Group Resource Types </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Named Resource </p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Hexidecimal Byte Value</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Standard Workstation group</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+00</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Logon Server </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1C</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Master Browser name </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1D</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Normal Group name (used in browser elections)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1E</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Internet Group name (administrative)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+20</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+&lt;01&gt;&lt;02&gt;__MSBROWSE__&lt;02&gt;</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+01</p></td></tr></tbody></table><P CLASS="para">
+The final entry, <CODE CLASS="literal">
+__MSBROWSE__</code>, is used to announce a group to other master browsers. The nonprinting characters in the name show up as dots in a NBTSTAT printout. Don't worry if you don't understand all of the resource or group types. Some of them you will not need with Samba, and others you will pick up as you move through the rest of the chapter. The important thing to remember here is the logistics of the naming mechanism. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-946130">
+1.3.5 Datagrams and Sessions</a></h3><P CLASS="para">
+<I CLASS="firstterm">
+</i>At this point, let's digress to introduce another responsibility of NBT: to provide connection services between two NetBIOS machines. There are actually two services offered by NetBIOS over TCP/IP: the <I CLASS="firstterm">
+session service</i> and the <I CLASS="firstterm">
+datagram service</i>. Understanding how these two services work is not essential to using Samba, but it does give you an idea of how NBT works and how to troubleshoot Samba when it doesn't work.</p><P CLASS="para">
+The datagram service has no stable connection between one machine and another. Packets of data are simply sent or broadcast from one machine to another, without regard for the order that they arrive at the destination, or even if they arrive at all. The use of datagrams is not as network intensive as sessions, although they can bog down a network if used unwisely (remember broadcast name resolution earlier?) Datagrams, therefore, are used for quickly sending simple blocks of data to one or more machines. The datagram service communicates using the simple primitives shown in <A CLASS="xref" HREF="ch01_03.html#ch01-pgfId-946185">
+Table 1.4</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-pgfId-946185">
+Table 1.4: Datagram Primitives </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primitive</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Send Datagram</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Send datagram packet to machine or groups of machines.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Send Broadcast Datagram</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Broadcast datagram to any machine waiting with a Receive Broadcast Datagram.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Receive Datagram</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Receive a datagram from a machine.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Receive Broadcast Datagram</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Wait for a broadcast datagram.</p></td></tr></tbody></table><P CLASS="para">
+The session service is more complex. Sessions are a communication method that, in theory, offers the ability to detect problematic or inoperable connections between two NetBIOS applications. It helps to think of an NBT session in terms of a telephone call.[<A CLASS="footnote" HREF="#ch01-pgfId-946249">5</a>] A full-duplex connection is opened between a caller machine and a called machine, and it must remain open throughout the duration of their conversation. Each side knows who the caller and the called machine is, and can communicate with the simple primitives shown in <A CLASS="xref" HREF="ch01_03.html#ch01-pgfId-946256">
+Table 1.5</a>. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch01-pgfId-946249">[5]</a> As you can see in RFC 1001, the telephone analogy was strongly evident in the creation of the NBT service.</p></div></blockquote><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-pgfId-946256">
+Table 1.5: Session Primitives </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primitive</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Call</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Initiate a session with a machine listening under a specified name.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Listen</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Wait for a call from a known caller or any caller.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Hang-up</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Exit a call.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Send</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Send data to the other machine.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Receive</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Receive data from the other machine.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Session Status</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Get information on requested sessions.</p></td></tr></tbody></table><P CLASS="para">
+Sessions are the backbone of resource sharing on an NBT network. They are typically used for establishing stable connections from client machines to disk or printer shares on a server. The client "calls" the server and starts trading information such as which files it wishes to open, which data it wishes to exchange, etc. These calls can last a long time&nbsp;- hours, even days&nbsp;- and all of this occurs within the context of a single connection. If there is an error, the session software (TCP) will retransmit until the data is received properly, unlike the "punt-and-pray" approach of the datagram service (UDP).</p><P CLASS="para">
+In truth, while sessions are supposed to be able to handle problematic communications, they often don't. As you've probably already discovered when using Windows networks, this is a serious detriment to using NBT sessions. If the connection is interrupted for some reason, session information that is open between the two computers can easily become invalidated. If that happens, the only way to regain the session information is for the same two computers to call each other again and start over.</p><P CLASS="para">
+If you want more information on each of these services, we recommend you look at RFC 1001. However, there are two important things to remember here:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-946210">
+</a>Sessions always occur between <EM CLASS="emphasis">
+two</em> NetBIOS machines&nbsp;- no more and no less. If a session service is interrupted, the client is supposed to store sufficient state information for it to re-establish the connection. However, in practice, this is rarely the case.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-946211">
+</a>Datagrams can be broadcast to multiple machines, but they are unreliable. In other words, there is no way for the source to know that the datagrams it sent have indeed arrived at their<I CLASS="firstterm">
+</i> destinations. </p></li></ul></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_02.html" TITLE="1.2 What Can Samba Do For Me?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.2 What Can Samba Do For Me?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_04.html" TITLE="1.4 Microsoft Implementations">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.4 Microsoft Implementations" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.2 What Can Samba Do For Me?</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.4 Microsoft Implementations</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_04.html b/docs/htmldocs/using_samba/ch01_04.html
new file mode 100644
index 00000000000..15a1943e6eb
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_04.html
@@ -0,0 +1,277 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.4 Microsoft Implementations</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:54Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_03.html" TITLE="1.3 Getting Familiar with a SMB/CIFS Network">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.3 Getting Familiar with a SMB/CIFS Network" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_05.html" TITLE="1.5 An Overview of the Samba Distribution">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.5 An Overview of the Samba Distribution" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-43359">
+1.4 Microsoft Implementations</a></h2><P CLASS="para">With that amount of background, we can now talk about some of Microsoft's implementations of the preceding concepts in the CIFS/SMB networking world. And, as you might expect, there are some complex extensions to introduce as well.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-946918">
+1.4.1 Windows Domains</a></h3><P CLASS="para">Recall that a workgroup is a collection of SMB computers that all reside on a subnet and subscribe to the same SMB group. A <I CLASS="firstterm">
+Windows domain</i> goes a step further. It is a workgroup of SMB machines that has one addition: a server acting as a <I CLASS="firstterm">
+domain controller</i>. You must have a domain controller in order to have a Windows domain.[<A CLASS="footnote" HREF="#ch01-pgfId-947021">6</a>] Otherwise, it is only a workgroup. See <A CLASS="xref" HREF="ch01_04.html#ch01-96972">
+Figure 1.11</a>. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch01-pgfId-947021">[6]</a> Windows domains are called "Windows NT domains" by Microsoft because they assume that Windows NT machines will take the role of the domain controller. However, because Samba can perform this function as well, we'll simply call them "Windows domains" to avoid confusion.</p></div></blockquote><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-96972">
+Figure 1.11: A simple Windows domain</a></h4><IMG CLASS="graphic" SRC="figs/sam.0111.gif" ALT="Figure 1.11"><P CLASS="para">There are currently two separate protocols used by a domain controller (logon server): one for communicating with Windows 95/98 machines and one for communicating with Windows NT machines. While Samba currently implements the domain controller protocol for Windows 95/98 (which allows it to act as a domain controller for Windows 9<EM CLASS="emphasis">
+x</em> machines), it still does not fully support the protocol for Windows NT computers. However, the Samba team promises that support for the Windows NT domain controller protocol is forthcoming in Samba 2.1.</p><P CLASS="para">
+Why all the difficulty? The protocol that Windows domain controllers use to communicate with their clients and other domain controllers is proprietary and has not been released by Microsoft. This has forced the Samba development team to reverse-engineer the domain controller protocol to see which codes perform specific tasks.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-946969">
+1.4.1.1 Domain controllers</a></h4><P CLASS="para">
+The domain controller is the nerve center of a Windows domain, much like an NIS server is the nerve center of the Unix network information service. Domain controllers have a variety of responsibilities. One responsibility that you need to be concerned with is <I CLASS="firstterm">
+authentication</i>. Authentication is the process of granting or denying a user access to a shared resource on another network machine, typically through the use of a password.</p><P CLASS="para">
+Each domain controller uses a <I CLASS="firstterm">
+security account manager</i> (SAM) to maintain a list of username-password combinations. The domain controller then forms a central repository of passwords that are tied to usernames (one password per user), which is more efficient than each client machine maintaining hundreds of passwords for every network resource available.</p><P CLASS="para">
+On a Windows domain, when a non-authenticated client requests access to a server's shares, the server will turn around and ask the domain controller whether that user is authenticated. If it is, the server will establish a session connection with the access rights it has for that service and user. If not, the connection is denied. Once a user is authenticated by the domain controller, a special authenticated token will be returned to the client so that the user will not need to relogin to other resources on that domain. At this point, the user is considered "logged in" to the domain itself. See <A CLASS="xref" HREF="ch01_04.html#ch01-49344">
+Figure 1.12</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-49344">
+Figure 1.12: Using a domain controller for authentication</a></h4><IMG CLASS="graphic" SRC="figs/sam.0112.gif" ALT="Figure 1.12"></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-939079">
+1.4.1.2 Primary and backup domain controllers</a></h4><P CLASS="para">Redundancy is a key idea behind a Windows domain. The domain controller that is currently active on a domain is called the <I CLASS="firstterm">
+primary domain controller</i> (PDC). There can be one or more <I CLASS="firstterm">
+backup domain controllers</i> (BDCs) in the domain as well, which will take over in the event that the primary domain controller fails or becomes inaccessible. BDCs frequently synchronize their SAM data with the primary domain controller so that, if the need arises, any one of them can perform DC services transparently without impacting its clients. Note that BDCs, however, have only read-only copies of the SAM; they can update their data only by synchronizing with a PDC. A server in a Windows domain can use the SAM of any primary or backup domain controller to authenticate a user who attempts to access its resources and logon to the domain.</p><P CLASS="para">
+Note that in many aspects, the behaviors of a Windows workgroup and a Windows domain overlap. This is not accidental since the concept of Windows domains did not evolve until Windows NT 3.5 was introduced, and Windows domains were forced to remain backwards compatible with the workgroups present in Windows for Workgroups 3.1. The key thing to remember here is that a Windows domain is simply a Windows workgroup with one or more domain controllers added.</p><P CLASS="para">
+Samba can function as a primary domain controller for Windows 95/98 machines without any problems. However, Samba 2.0 can act as a primary domain controller only for authentication purposes; it currently cannot assume any other PDC responsibilities. (By the time you read this, Samba 2.1 may be available so you can use Samba as a PDC for NT clients.) Also, because of the closed protocol used by Microsoft to synchronize SAM data, Samba currently cannot serve as a backup domain controller. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-951817">
+1.4.2 Browsing</a></h3><P CLASS="para">Browsing is a high-level answer to the user question: "What machines are out there on the Windows network?" Note that there is no connection with a World Wide Web browser, apart from the general idea of "discovering what's there." And, like the Web, what's out there can change without warning.</p><P CLASS="para">
+Before browsing, users had to know the name of the specific computer they wanted to connect to on the network, and then manually enter a UNC such as the following into an application or file manager to access resources:</p><PRE CLASS="programlisting">
+\\HYDRA\network\</pre><P CLASS="para">
+With browsing, however, you can examine the contents of a machine using a standard point-and-click GUI&nbsp;- in this case, the Network Neighborhood window in a Windows client.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-950089">
+1.4.2.1 Levels of browsing</a></h4><P CLASS="para">
+As we hinted at the beginning of the chapter, there are actually two types of browsing that you will encounter in an SMB/CIFS network:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-944661">
+</a>Browsing a list of machines (with shared resources)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-944662">
+</a>Browsing the shared resources of a specific machine</p></li></ul><P CLASS="para">Let's look at the first one. On each Windows workgroup (or domain) subnet, one computer has the responsibility of maintaining a list of the machines that are currently accessible through the network. This computer is called the <I CLASS="firstterm">
+local master browser</i>, and the list that it maintains is called the <I CLASS="firstterm">
+browse list</i>. Machines on a subnet use the browse list in order to cut down on the amount of network traffic generated while browsing. Instead of each computer dynamically polling to determine a list of the currently available machines, the computer can simply query the local master browser to obtain a complete, up-to-date list.</p><P CLASS="para">To browse the actual resources on a machine, a user must connect to the specific machine; this information cannot be obtained from the browse list. Browsing the list of resources on a machine can be done by clicking on the machine's icon when it is presented in the Network Neighborhood in Windows 95/98 or NT. As you saw at the opening of the chapter, the machine will respond with a list of shared resources that can be accessed if that user is successfully authenticated.</p><P CLASS="para">
+Each of the servers on a Windows workgroup is required to announce its presence to the local master browser after it has registered a NetBIOS name, and (theoretically) announce that it is leaving the workgroup when it is shut down. It is the local master browser's responsibility to record what the servers have announced. Note that the local master browser is not necessarily the same machine as a NetBIOS name server (NBNS), which we discussed earlier. </p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> The Windows Network Neighborhood can behave oddly: until you select a particular machine to browse, the Network Neighborhood window may contain data that is not up-to-date. That means that the Network Neighborhood window can be showing machines that have crashed, or can be missing machines that haven't been noticed yet. Put succinctly, once you've selected a server and connected to it, you can be a lot more confident that the shares and printers really exist on the network.</p></blockquote><P CLASS="para">
+Unlike the roles you've seen earlier, almost any Windows machine (NT Server, NT Workstation, 98, 95, or Windows 3.1 for Workgroups) can act as a local master browser. As with the domain controller, the local master browser can have one or more <I CLASS="firstterm">
+backup browsers</i> on the local subnet that will take over in the event that the local master browser fails or becomes inaccessible. To ensure fluid operation, the local backup browsers will frequently synchronize their browse list with the local master browser. Let's update our Windows domain diagram to include both a local master and local backup browser. The result is shown in <A CLASS="xref" HREF="ch01_04.html#ch01-77521">
+Figure 1.13</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-77521">
+Figure 1.13: A Windows domain with a local master and local backup browser</a></h4><IMG CLASS="graphic" SRC="figs/sam.0113.gif" ALT="Figure 1.13"><P CLASS="para">
+Here is how to calculate the minimum number of backup browsers that will be allocated on a workgroup:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-944330">
+</a>If there are between 1 and 32 Windows NT workstations on the network, or between 1 and 16 Windows 95/98 machines on the network, the local master browser allocates one backup browser in addition to the local master browser.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-950113">
+</a>If the number of Windows NT workstations falls between 33 and 64, or the number of Windows 95/98 workstations falls between 17 and 32, the local master browser allocates two backup browsers.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-944332">
+</a>For each group of 32 NT workstations or 16 Windows 95/98 machines beyond this, the local master browser allocates another backup browser.</p></li></ul><P CLASS="para">
+There is currently no upper limit on the number of backup browsers that can be allocated by the local master browser. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch01-pgfId-946408">
+1.4.2.2 Browsing elections</a></h4><P CLASS="para">
+Browsing is a critical aspect of any Windows workgroup. However, not everything runs perfectly on any network. For example, let's say that the Windows NT Server on the desk of a small company's CEO is the local master browser&nbsp;- that is, until he switches it off while plugging in his massage chair. At this point the Windows NT Workstation in the spare parts department might agree to take over the job. However, that computer is currently running a large, poorly written program that has brought its processor to its knees. The moral: browsing has to be very tolerant of servers coming and going. Because nearly every Windows machine can serve as a browser, there has to be a way of deciding at any time who will take on the job. This decision-making process is called an <I CLASS="firstterm">
+election</i>.</p><P CLASS="para">
+An election algorithm is built into nearly all Windows operating systems such that they can each agree who is going to be a local master browser and who will be local backup browsers. An election can be forced at any time. For example, let's assume that the CEO has finished his massage and reboots his server. As the server comes online, it will announce its presence and an election will take place to see if the PC in the spare parts department should still be the master browser. </p><P CLASS="para">
+When an election is performed, each machine broadcasts via datagrams information about itself. This information includes the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-939575">
+</a>The version of the election protocol used</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-939577">
+</a>The operating system on the machine</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-939576">
+</a>The amount of time the client has been on the network</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-939578">
+</a>The hostname of the client</p></li></ul><P CLASS="para">
+These values determine which operating system has seniority and will fulfill the role of the local master browser. (<a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a>, describes the election process in more detail.) The architecture developed to achieve this is not elegant and has built-in security problems. While a browsing domain can be integrated with domain security, the election algorithm does not take into consideration which computers become browsers. Thus it is possible for any machine running a browser service to register itself as participating in the browsing election, and (after winning) being able to change the browse list. Nevertheless, browsing is a key feature of Windows networking and backwards compatibility requirements will ensure that it is in use for years to come. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-939834">
+1.4.3 Can a Windows Workgroup Span Multiple Subnets?</a></h3><P CLASS="para">Yes, but most people who have done it have had their share of headaches. Spanning multiple subnets was not part of the initial design of Windows NT 3.5 or Windows for Workgroups. As a result, a Windows domain that spans two or more subnets is, in reality, the "gluing" together of two or more workgroups that share an identical name. The good news is that you can still use a primary domain controller to control authentication across each of the subnets. The bad news is that things are not as simple with browsing.</p><P CLASS="para">
+As mentioned previously, each subnet must have its own local master browser. When a Windows domain spans multiple subnets, a system administrator will have to assign one of the machines as the <I CLASS="firstterm">
+domain master browser</i>. The domain master browser will keep a browse list for the entire Windows domain. This browse list is created by periodically synchronizing the browse lists of each of the local master browsers with the browse list of the domain master browser. After the synchronization, the local master browser and the domain master browser should contain identical entries. See <A CLASS="xref" HREF="ch01_04.html#ch01-52572">
+Figure 1.14</a> for an illustration. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch01-52572">
+Figure 1.14: A workgroup that spans more than one subnet</a></h4><IMG CLASS="graphic" SRC="figs/sam.0114.gif" ALT="Figure 1.14"><P CLASS="para">
+Sound good? Well, it's not quite nirvana for the following reasons:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-947419">
+</a>If it exists, a primary domain controller always plays the role of the domain master browser. By Microsoft design, the two always share the NetBIOS resource type &lt;1B&gt;, and (unfortunately) cannot be separated.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-947420">
+</a>Windows 95/98 machines cannot become <EM CLASS="emphasis">
+or</em> <EM CLASS="emphasis">
+even contact</em> a domain master browser. The Samba group feels that this is a marketing decision from Microsoft that forces customers to have at least one Windows NT workstation (or Samba server) on each subnet of a multi-subnet workgroup.</p></li></ul><P CLASS="para">
+Each subnet's local master browser continues to maintain the browse list for its subnet, for which it becomes authoritative. So if a computer wants to see a list of servers within its own subnet, the local master browser of that subnet will be queried. If a computer wants to see a list of servers outside the subnet, it can still go only as far as the local master browser. This works because, at appointed intervals, the authoritative browse list of a subnet's local master browser is synchronized with the domain master browser, which is synchronized with the local master browser of the other subnets in the domain. This is called <I CLASS="firstterm">
+browse list propagation</i>.</p><P CLASS="para">
+Samba can act as a domain master browser on a Windows domain if required. In addition, it can also act as a local master browser for a Windows subnet, synchronizing its browse list with the domain master browser.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-938926">
+1.4.4 The Windows Internet Name Service (WINS)</a></h3><P CLASS="para">
+The Windows Internet Name Service (WINS) is Microsoft's implementation of a NetBIOS name server (NBNS). As such, WINS inherits much of NetBIOS's characteristics. First, WINS is flat; you can only have machines named <CODE CLASS="literal">
+fred</code> or workgroups like CANADA or USA. In addition, WINS is dynamic: when a client first comes online, it is required to report its hostname, its address, and its workgroup to the local WINS server. This WINS server will retain the information so long as the client periodically refreshes its WINS registration, which indicates that it's still connected to the network. Note that WINS servers are not domain or workgroup specific; they can appear anywhere and serve anyone.</p><P CLASS="para">
+Multiple WINS servers can be set to synchronize with each other after a specified amount of time. This allows entries for machines that come online and offline on the network to propagate from one WINS server to another. While in theory this seems efficient, it can quickly become cumbersome if there are several WINS servers covering a network. Because WINS services can cross multiple subnets (you'll either hardcode the address of a WINS server in each of your clients or obtain it via DHCP), it is often more efficient to have each Windows client, no matter how many Windows domains there are, point themselves to the same WINS server. That way, there will only be one authoritative WINS server with the correct information, instead of several WINS servers continually struggling to synchronize themselves with the most recent changes.</p><P CLASS="para">
+The currently active WINS server is known as the <I CLASS="firstterm">
+primary WINS server</i>. You can also install a secondary WINS server, which will take over in the event that the primary WINS server fails or becomes inaccessible. Note that there is no election to determine which machine becomes a primary or backup WINS server&nbsp;- the choice of WINS servers is static and must be predetermined by the system administrator. Both the primary and any backup WINS servers will synchronize their address databases on a periodic basis.</p><P CLASS="para">
+In the Windows family of operating systems, only an NT Workstation or an NT server can serve as a <I CLASS="firstterm">
+</i>WINS server. Samba can also function as a primary WINS server, but not a secondary WINS server.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-12452">
+1.4.5 What Can Samba Do?</a></h3><P CLASS="para">Whew! Bet you never thought Microsoft networks would be that complex, did you? Now, let's wrap up by showing where Samba can help out. <A CLASS="xref" HREF="ch01_04.html#ch01-pgfId-939957">
+Table 1.6</a> summarizes which roles Samba can and cannot play in a Windows NT Domain or Windows workgroup. As you can see, because many of the NT domain protocols are proprietary and have not been documented by Microsoft, Samba cannot properly synchronize its data with a Microsoft server and cannot act as a backup in most roles. However, with version 2.0.<EM CLASS="emphasis">
+x</em>, Samba does have limited support for the primary domain controller's authentication protocols and is gaining more functionality every day. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch01-pgfId-939957">
+Table 1.6: Samba Roles (as of 2.0.4b) </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Role</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Can Perform?</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+File Server</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Printer Server</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary Domain Controller</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes (Samba 2.1 or higher recommended)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Backup Domain Controller</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+No</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 95/98 Authentication</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Local Master Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Local Backup Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+No</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Domain Master Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary WINS Server</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Yes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Secondary WINS Server</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+No </p></td></tr></tbody></table></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_03.html" TITLE="1.3 Getting Familiar with a SMB/CIFS Network">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.3 Getting Familiar with a SMB/CIFS Network" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_05.html" TITLE="1.5 An Overview of the Samba Distribution">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.5 An Overview of the Samba Distribution" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.3 Getting Familiar with a SMB/CIFS Network</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.5 An Overview of the Samba Distribution</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_05.html b/docs/htmldocs/using_samba/ch01_05.html
new file mode 100644
index 00000000000..0989ddfb91b
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_05.html
@@ -0,0 +1,130 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.5 An Overview of the Samba Distribution</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:30:00Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_04.html" TITLE="1.4 Microsoft Implementations">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.4 Microsoft Implementations" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_06.html" TITLE="1.6 How Can I Get Samba?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.6 How Can I Get Samba?" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-32691">
+1.5 An Overview of the Samba Distribution</a></h2><P CLASS="para">
+As mentioned earlier, Samba actually contains several programs that serve different but related purposes. Let's introduce each of them briefly, and show how they work together. The majority of the programs that come with the Samba distribution center on its two daemons. Let's take a refined look at the responsibilities of each daemon:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<EM CLASS="emphasis">
+smbd</em></dt><DD CLASS="listitem">
+<P CLASS="para">
+The <EM CLASS="emphasis">
+smbd</em> daemon is responsible for managing the shared resources between the Samba server machine and its clients. It provides file, print, and browser services to <SPAN CLASS="acronym">
+SMB</span> clients across one or more networks. <EM CLASS="emphasis">
+smdb</em> handles all notifications between the Samba server and the network clients. In addition, it is responsible for user authentication, resource locking, and data sharing through the <SPAN CLASS="acronym">
+SMB</span> protocol.</p></dd><DT CLASS="term">
+<EM CLASS="emphasis">
+nmbd</em></dt><DD CLASS="listitem">
+<P CLASS="para">
+The <EM CLASS="emphasis">
+nmbd</em> daemon is a simple nameserver that mimics the WINS and NetBIOS name server functionality, as you might expect to encounter with the LAN Manager package. This daemon listens for nameserver requests and provides the appropriate information when called upon. It also provides browse lists for the Network Neighborhood and participates in browsing elections.</p></dd></dl><P CLASS="para">
+The Samba distribution also comes with a small set of Unix command-line tools:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<i>smbclient</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+An FTP-like Unix client that can be used to connect to Samba shares</p></dd><DT CLASS="term">
+<i>smbtar</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A program for backing up data in shares, similar to the Unix <I CLASS="filename">
+tar</i> command</p></dd><DT CLASS="term">
+<i>nmblookup</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A program that provides NetBIOS over TCP/IP name lookups</p></dd><DT CLASS="term">
+<i>smbpasswd</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A program that allows an administrator to change the encrypted passwords used by Samba</p></dd><DT CLASS="term">
+<i>smbstatus</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A program for reporting the current network connections to the shares on a Samba server</p></dd><DT CLASS="term">
+<i>testparm</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A simple program to validate the Samba configuration file</p></dd><DT CLASS="term">
+<i>testprns</i></dt><DD CLASS="listitem">
+<P CLASS="para">
+A program that tests whether various printers are recognized by the <I CLASS="filename">
+smbd</i> daemon</p></dd></dl><P CLASS="para">
+Each significant release of Samba goes through a significant exposure test before it's announced. In addition, it is quickly updated afterward if problems or unwanted side-effects are found. The latest stable distribution as of this writing is Samba 2.0.5, the long-awaited production version of Samba 2.0. This book focuses on the functionality supported in Samba 2.0, as opposed to the older 1.9.<EM CLASS="emphasis">
+x</em> versions of Samba, which are now obsolete.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_04.html" TITLE="1.4 Microsoft Implementations">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.4 Microsoft Implementations" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_06.html" TITLE="1.6 How Can I Get Samba?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.6 How Can I Get Samba?" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.4 Microsoft Implementations</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.6 How Can I Get Samba?</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_06.html b/docs/htmldocs/using_samba/ch01_06.html
new file mode 100644
index 00000000000..f3b46b2313b
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_06.html
@@ -0,0 +1,90 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.6 How Can I Get Samba?</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:30:01Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_05.html" TITLE="1.5 An Overview of the Samba Distribution">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.5 An Overview of the Samba Distribution" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_07.html" TITLE="1.7 What's New in Samba 2.0?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.7 What's New in Samba 2.0?" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-pgfId-946850">
+1.6 How Can I Get Samba?</a></h2><P CLASS="para">Samba is available in both binary and source format from a set of mirror sites across the Internet. The primary home site for Samba is located at <A CLASS="systemitem.url" HREF="http://www.samba.org/">http://www.samba.org/</a>.</p><P CLASS="para">
+However, if you don't want to wait for packets to arrive all the way from Australia, mirror sites for Samba can be found at any of several locations on the Internet. A list of mirrors is given at the primary Samba home page.</p><P CLASS="para">
+In addition, a CD-ROM distribution is available in the back of this book. We strongly encourage you to start with the CD-ROM if this is your first time using Samba. We've included source and binaries up to Samba 2.0.5 with this book. In addition, several of the testing tools that we refer to through the book are conveniently packaged on the CD-ROM.</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_05.html" TITLE="1.5 An Overview of the Samba Distribution">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.5 An Overview of the Samba Distribution" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_07.html" TITLE="1.7 What's New in Samba 2.0?">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.7 What's New in Samba 2.0?" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.5 An Overview of the Samba Distribution</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.7 What's New in Samba 2.0?</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_07.html b/docs/htmldocs/using_samba/ch01_07.html
new file mode 100644
index 00000000000..a5fd482b03b
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_07.html
@@ -0,0 +1,138 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.7 What's New in Samba 2.0?</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:30:01Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_06.html" TITLE="1.6 How Can I Get Samba?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.6 How Can I Get Samba?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_08.html" TITLE="1.8 And That's Not All...">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.8 And That's Not All..." BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-40528">
+1.7 What's New in Samba 2.0?</a></h2><P CLASS="para">Samba 2.0 was an eagerly-awaited package. The big additions to Samba 2.0 are more concrete support for NT Domains and the new Samba Web Administration Tool (SWAT), a browser-based utility for configuring Samba. However, there are dozens of other improvements that were introduced in the summer and fall of 1998. </p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937019">
+1.7.1 NT Domains</a></h3><P CLASS="para">
+Samba's support for NT Domains (starting with version 2.0.<EM CLASS="emphasis">
+x</em>) produced a big improvement: it allows SMB servers to use its authentication mechanisms, which is essential for future NT compatibility, and to support <I CLASS="firstterm">
+NT domain logons</i>. Domain logons allow a user to log in to a Windows NT domain and use all the computers in the domain without logging into them individually. Previous to version 2.0.0, Samba supported Windows 95/98 logon services, but not NT domain logons. Although domain logons support is not complete is Samba 2.0, it is partially implemented.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937021">
+1.7.2 Ease of Administration</a></h3><P CLASS="para">SWAT, the Samba Web Administration Tool, makes it easy to set up a server and change its configuration, without giving up the simple text-based configuration file. SWAT provides a graphical interface to the resources that Samba shares with its clients. In addition, SWAT saves considerable experimentation and memory work in setting up or changing configurations across the network. You can even create an initial setup with SWAT and then modify the file later by hand, or vice versa. Samba will not complain.</p><P CLASS="para">
+On the compilation side, GNU <I CLASS="filename">
+autoconf</i> is now used to make the task of initial compilation and setup easier so you can get to SWAT quicker.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937024">
+1.7.3 Performance</a></h3><P CLASS="para">
+There are major performance and scalability increases in Samba: the code has been reorganized and <EM CLASS="emphasis">
+nmbd</em> (the Samba name service daemon) heavily rewritten:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-937026">
+</a>Name/browsing service now supports approximately 35,000 simultaneous clients.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-937027">
+</a>File and print services support 500 concurrent users from a single medium-sized server without noticeable performance degradation.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-937028">
+</a>Linux/Samba on identical hardware now consistently performs better than NT Server. And best of all, Samba is improving.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch01-pgfId-937029">
+</a>Improved "opportunistic" locking allows client machines to cache entire files locally, greatly improving speed without running the risk of accidentally overwriting the cached files.</p></li></ul></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937030">
+1.7.4 More Features</a></h3><P CLASS="para">
+There are several additional features in Samba 2.0. You can now have multiple Samba aliases on the same machine, each pretending to be a different server, a feature similar to virtual hosts in modern web servers. This allows a host to serve multiple departments and groups, or provide disk shares with normal username/password security while also providing printers to everyone without any security. Printing has been changed to make it easier for Unix System V owners: Samba can now find the available printers automatically, just as it does with Berkeley-style printing. In addition, Samba now has the capability to use multiple code pages, so it can be used with non-European languages, and to use the Secure Sockets Layer protocol (SSL) to encrypt all the data it sends across the Internet, instead of just passwords.[<A CLASS="footnote" HREF="#ch01-pgfId-938280">7</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch01-pgfId-938280">[7]</a> If you reside in the United States, there are some federal rules and regulations dealing with strong cryptography. We'll talk about his later when we set up Samba and SSL in <a href="appa_01.html"><b>Appendix A, <CITE CLASS="appendix">
+Configuring Samba with SSL</cite></b></a>.</p></div></blockquote></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937035">
+1.7.5 Compatibility Improvements</a></h3><P CLASS="para">
+At the same time as it's becoming more capable, Samba is also becoming more compatible with Windows NT. Samba has always supported Microsoft-style password encryption. It now provides tools and options for changing over to Microsoft encryption, and for keeping the Unix and Microsoft password files synchronized while doing so. Finally, a Samba master browser can be instructed to hunt down and synchronize itself with other SMB servers on different LANs, allowing SMB to work seamlessly across multiple networks. Samba uses a different method of accomplishing this from the Microsoft method, which is undocumented.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch01-pgfId-937039">
+1.7.6 Smbwrapper</a></h3><P CLASS="para">
+Finally, there is an entirely new version of the Unix client called <I CLASS="firstterm">
+smbwrapper</i>. Instead of a kernel module that allows Linux to act as a Samba client, there is now a command-line entry to load the library that provides a complete SMB filesystem on some brands of Unix. Once loaded, the command <CODE CLASS="literal">
+ls</code> <CODE CLASS="literal">
+/smb</code> will list all the machines in your workgroup, and <CODE CLASS="literal">
+cd</code> <CODE CLASS="literal">/smb/</code><CODE CLASS="replaceable"><I>server_name</i></code><CODE CLASS="literal">/</code><CODE CLASS="replaceable"><I>share_name</i></code> will take you to a particular share (shared directory), similar to the Network File System (NFS). As of this writing, <EM CLASS="emphasis">
+smbwrapper</em> currently runs on Linux, Solaris, SunOS 4, IRIX, and OSF/1, and is expected to run on several more operating systems in the near future.</p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_06.html" TITLE="1.6 How Can I Get Samba?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.6 How Can I Get Samba?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_08.html" TITLE="1.8 And That's Not All...">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 1.8 And That's Not All..." BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.6 How Can I Get Samba?</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+1.8 And That's Not All...</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch01_08.html b/docs/htmldocs/using_samba/ch01_08.html
new file mode 100644
index 00000000000..0ea2d0331ce
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch01_08.html
@@ -0,0 +1,89 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 1] 1.8 And That's Not All...</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:30:04Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_07.html" TITLE="1.7 What's New in Samba 2.0?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.7 What's New in Samba 2.0?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch01_01.html" TITLE="1. Learning the Samba">
+Chapter 1<br>
+Learning the Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2. Installing Samba on a Unix System" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch01-99818">
+1.8 And That's Not All...</a></h2><P CLASS="para">
+Samba is a wonderful tool with potential for even the smallest SMB/CIFS network. This chapter presented you with a thorough introduction to what Samba is, and more importantly, how it fits into a Windows network. The next series of chapters will help you set up Samba on both the Unix server side, where its two daemons reside, as well as configure the Windows 95, 98, and NT clients to work with Samba. Before long, the aches and pains of your heterogeneous network may seem like a thing of the past. Welcome to the wonderful world of Samba!</p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_07.html" TITLE="1.7 What's New in Samba 2.0?">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.7 What's New in Samba 2.0?" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2. Installing Samba on a Unix System" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.7 What's New in Samba 2.0?</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2. Installing Samba on a Unix System</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_01.html b/docs/htmldocs/using_samba/ch02_01.html
new file mode 100644
index 00000000000..a90a52d8abe
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_01.html
@@ -0,0 +1,197 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] Installing Samba on a Unix System</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:03Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_08.html" TITLE="1.8 And That's Not All...">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.8 And That's Not All..." BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 2</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_02.html" TITLE="2.2 Configuring Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.2 Configuring Samba" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch02-46174">
+2. Installing Samba on a Unix System</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch02-85028" TITLE="2.1 Downloading the Samba Distribution">
+Downloading the Samba Distribution</a><br>
+<A CLASS="sect1" HREF="ch02_02.html" TITLE="2.2 Configuring Samba">
+Configuring Samba</a><br>
+<A CLASS="sect1" HREF="ch02_03.html" TITLE="2.3 Compiling and Installing Samba">
+Compiling and Installing Samba</a><br>
+<A CLASS="sect1" HREF="ch02_04.html" TITLE="2.4 A Basic Samba Configuration File">
+A Basic Samba Configuration File</a><br>
+<A CLASS="sect1" HREF="ch02_05.html" TITLE="2.5 Starting the Samba Daemons">
+Starting the Samba Daemons</a><br>
+<A CLASS="sect1" HREF="ch02_06.html" TITLE="2.6 Testing the Samba Daemons">
+Testing the Samba Daemons</a></p><P>
+</p></div><P CLASS="para">Now that you know what Samba can do for you and your users, it's time to get your own network set up. Let's start with the installation of Samba itself on a Unix system. When dancing the samba, one learns by taking small steps. It's just the same when installing Samba; we need to teach it step by step. This chapter will help you to start off on the right foot. </p><P CLASS="para">
+For illustrative purposes, we will be installing the 2.0.4 version of the Samba server on a Linux[<A CLASS="footnote" HREF="#ch02-pgfId-939741">1</a>] system running version 2.0.31 of the kernel. However, the installation steps are the same for all of the platforms that Samba supports. A typical installation will take about an hour to complete, including downloading the source files and compiling them, setting up the configuration files, and testing the server. </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch02-pgfId-939741">[1]</a> If you haven't heard of Linux yet, then you're in for a treat. Linux is a freely distributed Unix-like operating system that runs on the Intel x86, Motorola PowerPC, and Sun Sparc platforms. The operating system is relatively easy to configure, extremely robust, and is gaining in popularity. You can get more information on the Linux operating system at <a href="http://www.linux.org/"><EM CLASS="emphasis">http://www.linux.org/</a></em>.</p></div></blockquote><P CLASS="para">Here is an overview of the steps:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938543">
+</a>Download the source or binary files.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938544">
+</a>Read the installation documentation.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938545">
+</a>Configure a makefile.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938546">
+</a>Compile the server code.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938547">
+</a>Install the server files.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938548">
+</a>Create a Samba configuration file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938549">
+</a>Test the configuration file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938550">
+</a>Start the Samba daemons.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938551">
+</a>Test the Samba daemons.</p></li></ol><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch02-85028">
+2.1 Downloading the Samba Distribution</a></h2><P CLASS="para">If you want to get started quickly, the CD-ROM packaged with this book contains both the sources and binaries of Samba that were available as this book went to print. The CD is a mirror image of the files and directories on the Samba download server: <EM CLASS="emphasis">
+ftp.samba.org</em>.</p><P CLASS="para">
+On the other hand, if you want to download the latest version, the primary web site for the Samba software is <A CLASS="systemitem.url" HREF="http://www.samba.org">http://www.samba.org</a>. Once connected to this page, you'll see links to several Samba mirror sites across the world, both for the standard Samba web pages and sites devoted exclusively to downloading Samba. For the best performance, choose a site that is closest to your own geographic location.</p><P CLASS="para">
+The standard Samba web sites have Samba documentation and tutorials, mailing list archives, and the latest Samba news, as well as source and binary distributions of Samba. The download sites (sometimes called <EM CLASS="emphasis">
+FTP sites</em>) have only the source and binary distributions. Unless you specifically want an older version of the Samba server or are going to install a binary distribution, download the latest source distribution from the closest mirror site. This distribution is always named:</p><PRE CLASS="programlisting">samba-latest.tar.gz</pre><P CLASS="para">
+If you choose to use the version of Samba that is located on the CD-ROM packaged with this book, you should find the latest Samba distribution in the base directory.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-938556">
+2.1.1 Binary or Source?</a></h3><P CLASS="para">Precompiled packages are also available for a large number of Unix platforms. These packages contain binaries for each of the Samba executables as well as the standard Samba documentation. Note that while installing a binary distribution can save you a fair amount of trouble and time, there are a couple of issues that you should keep in mind when deciding whether to use the binary or compile the source yourself:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938558">
+</a>The binary packages can lag behind the latest version of the software by one or two (maybe more) minor releases, especially after a series of small changes and for less popular platforms. Compare the release notes for the source and binary packages to make sure that there aren't any new features that you need on your platform. This is especially true of the sources and binaries on the CD-ROM: at the time this book went to print, they were from the latest production release of Samba. However, development is ongoing, so the beta-test versions on the Internet will be newer.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938560">
+</a>If you use a precompiled binary, you will need to ensure that you have the correct libraries required by the executables. On some platforms the executables are statically linked so this isn't an issue, but on modern Unix operating systems (e.g., Linux, SGI Irix, Solaris, HP-UX, etc.), libraries are often dynamically linked. This means that the binary looks for the right version of each library on your system, so you may have to install a new version of a library. The <I CLASS="filename">
+README</i> file or <I CLASS="filename">
+makefile</i> that accompanies the binary distribution should list any special requirements.[<A CLASS="footnote" HREF="#ch02-pgfId-943622">2</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch02-pgfId-943622">[2]</a> This is especially true with programs that use <EM CLASS="emphasis">
+glibc-2.1</em> (which comes standard with Red Hat Linux 6). This library caused quite a consternation in the development community when it was released because it was incompatable with previous versions of <EM CLASS="emphasis">g</em><I CLASS="filename">libc</i>.</p></div></blockquote><P CLASS="para">Many machines with shared libraries come with a nifty tool called <EM CLASS="emphasis">ldd</em>. This tool will tell you which libraries a specific binary requires and which libraries on the system satisfy that requirement. For example, checking the <EM CLASS="emphasis">
+smbd</em> program on our test machine gave us:</p></li></ul><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">$</code> ldd smbd</b>
+</pre><PRE CLASS="programlisting">
+libreadline.so.3 =&gt; /usr/lib/libreadline.so.3
+libdl.so.2 =&gt; /lib/libdl.so.2
+libcrypt.so.1 =&gt; /lib/libcrypt.so.1
+libc.so.6 =&gt; /lib/libc.so.6
+libtermcap.so.2 =&gt; /lib/libtermcap.so.2
+/lib/ld-linux.so.2 =&gt; /lib/ld-linux.so.2</pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+If there are any incompatibilities between Samba and specific libraries on your machine, the distribution-specific documentation should highlight those.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938567">
+</a>Keep in mind that each binary distribution carries preset values about the target platform, such as default directories and configuration option values. Again, check the documentation and the makefile included in the source directory to see which directives and variables were used when the binary was compiled. In some cases, these will not be appropriate for your situation. </p><P CLASS="para">
+A few configuration items can be reset with command-line options at runtime instead of at compile time. For example, if your binary tries to place any log, lock, or status files in the "wrong" place (for example, in <I CLASS="filename">
+/usr/local</i>), you can override this without recompiling. </p></li></ul><P CLASS="para">
+One point worth mentioning is that the Samba source requires an ANSI C compiler. If you are on a platform with a non-ANSI compiler, such as the <EM CLASS="emphasis">
+cc</em> compiler on SunOS version 4, you'll have to install an ANSI-compliant compiler such as <EM CLASS="emphasis">
+gcc </em>before you do anything else.[<A CLASS="footnote" HREF="#ch02-pgfId-939049">3</a>] If installing a compiler isn't something you want to wrestle with, you can start off with a binary package. However, for the most flexibility and compatibility on your system, we always recommend compiling from the latest source.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch02-pgfId-939049">[3]</a> <EM CLASS="emphasis">
+gcc</em> binaries are available for almost every modern machine. See <A CLASS="systemitem.url" HREF="http://www.gnu.org/">
+http://www.gnu.org/</a> for a list of sites with <EM CLASS="emphasis">
+gcc</em> and other GNU software.</p></div></blockquote></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-938574">
+2.1.2 Read the Documentation</a></h3><P CLASS="para">This sounds like an obvious thing to say, but there have probably been times where you have uncompressed a package, blindly typed <CODE CLASS="literal">
+configure</code>, <CODE CLASS="literal">
+make</code>, and <CODE CLASS="literal">
+make</code> <CODE CLASS="literal">
+install</code>, and walked away to get another cup of coffee. We'll be the first to admit that we do that, many more times than we should. It's a bad idea&nbsp;- especially when planning a network with Samba.</p><P CLASS="para">
+Samba 2.0 automatically configures itself prior to compilation. This reduces the likelihood of a machine-specific problem, but there may be an option mentioned in the <I CLASS="filename">
+README</i> file that you end up wishing for after Samba's been installed. With both source and binary packages you'll find a large number of documents in the <I CLASS="filename">
+docs</i> directory, in a variety of formats. The most important files to look at in the distribution are:</p><PRE CLASS="programlisting">
+WHATSNEW.txt
+docs/textdocs/UNIX_INSTALL.txt</pre><P CLASS="para">
+These files tell you what features you can expect in your Samba distribution, and will highlight common installation problems that you're likely to face. Be sure to look over both of them before you start the compilation process. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch01_08.html" TITLE="1.8 And That's Not All...">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 1.8 And That's Not All..." BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_02.html" TITLE="2.2 Configuring Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.2 Configuring Samba" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+1.8 And That's Not All...</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2.2 Configuring Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_02.html b/docs/htmldocs/using_samba/ch02_02.html
new file mode 100644
index 00000000000..3556314b438
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_02.html
@@ -0,0 +1,338 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] 2.2 Configuring Samba</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:05Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_01.html" TITLE="2.1 Downloading the Samba Distribution">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.1 Downloading the Samba Distribution" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+Chapter 2<br>
+Installing Samba on a Unix System</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_03.html" TITLE="2.3 Compiling and Installing Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.3 Compiling and Installing Samba" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch02-28558">
+2.2 Configuring Samba</a></h2><P CLASS="para">The source distribution of Samba 2.0 and above doesn't initially have a makefile. Instead, one is generated through a GNU <I CLASS="filename">
+configure</i> script, which is located in the <I CLASS="filename">
+samba-2.0.x /source/</i> directory. The <I CLASS="firstterm">
+configure</i> script, which must be run as root, takes care of the machine-specific issues of building Samba. However, you still may want to decide on some global options. Global options can be set by passing options on the command-line:</p><PRE CLASS="programlisting">
+# ./configure --with-ssl</pre><P CLASS="para">
+For example, this will configure the Samba makefile with support for the Secure Sockets Layer (SSL) encryption protocol. If you would like a complete list of options, type the following:</p><PRE CLASS="programlisting">
+# ./configure --help</pre><P CLASS="para">Each of these options enable or disable various features. You typically enable a feature by specifying the <CODE CLASS="literal">
+--with-</code><CODE CLASS="replaceable">
+<I>
+feature</i></code> option, which will cause the feature to be compiled and installed. Likewise, if you specify a <CODE CLASS="literal">
+--without-</code><CODE CLASS="replaceable">
+<I>
+feature</i></code> option, the feature will be disabled. As of Samba 2.0.5, each of the following features is disabled by default:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<CODE CLASS="literal">
+--with-smbwrapper</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include SMB wrapper support, which allows executables on the Unix side to access SMB/CIFS filesystems as if they were regular Unix filesystems. We recommend using this option. However, at this time this book went to press, there were several incompatibilities between the <I CLASS="filename">
+smbwrapper</i> package and the GNU <I CLASS="filename">
+libc</i> version 2.1, and it would not compile on Red Hat 6.0. Look for more information on these incompatibilities on the Samba home page.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-afs</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support of the Andrew Filesystem from Carnegie Mellon University. If you're going to serve AFS files via Samba, we recommend compiling Samba once first without enabling this feature to ensure that everything runs smoothly. Once that version is working smoothly, recompile Samba with this feature enabled and compare any errors you might receive against the previous setup.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-dfs</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for DFS, a later version of AFS, used by OSF/1 (Digital Unix). Note that this is <EM CLASS="emphasis">
+not</em> the same as Microsoft DFS, which is an entirely different filesystem. Again, we recommend compiling Samba once first without this feature to ensure that everything runs smoothly, then recompile with this feature to compare any errors against the previous setup.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-krb4</code>=<CODE CLASS="replaceable"><I>base-directory</i></code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for Kerberos version 4.0, explicitly specifying the base directory of the distribution. Kerberos is a network security protocol from MIT that uses private key cryptography to provide strong security between nodes. Incidentally, Microsoft has announced that Kerberos 5.0 will be the standard authentication mechanism for Microsoft Windows 2000 (NT 5.0). However, the Kerberos 5.0 authentication mechanisms are quite different from the Kerberos 4.0 security mechanisms. If you have Kerberos version 4 on your system, the Samba team recommends that you upgrade and use the <CODE CLASS="literal">
+--with-krb5</code> option (see the next item). You can find more information on Kerberos at <a href="http://web.mit.edu/kerberos/www"><EM CLASS="emphasis">http://web.mit.edu/kerberos/www</a></em>.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-krb5</code>=<CODE CLASS="replaceable"><I>base-directory</i></code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for Kerberos version 5.0, explicitly specifying the base directory of the distribution. Microsoft has announced that Kerberos 5.0 will be the standard authentication mechanism for Microsoft Windows 2000 (NT 5.0). However, there is no guarantee that Microsoft will not extend Kerberos for their own needs in the future. Currently, Samba's Kerberos support only uses a plaintext password interface and not an encrypted one. You can find more information on Kerberos at its home page: <a href="http://web.mit.edu/kerberos/www"><EM CLASS="emphasis">http://web.mit.edu/kerberos/www</a></em>.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-automount</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for automounter, a feature often used on sites that offer NFS. </p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-smbmount</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include <EM CLASS="emphasis">
+smbmount</em> support, which is for Linux only. This feature wasn't being maintained at the time the book was written, so the Samba team made it an optional feature and provided <EM CLASS="emphasis">
+smbwrapper</em> instead. The <EM CLASS="emphasis">
+smbwrapper</em> feature works on more Unix platforms than <EM CLASS="emphasis">
+smbmount</em>, so you'll usually want to use <CODE CLASS="literal">
+--with-smbwrapper</code> instead of this option.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-pam</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for pluggable authentication modules (PAM), an authentication feature common in the Linux operating system.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-ldap</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for the Lightweight Directory Access Protocol (LDAP). A future version of LDAP will be used in the Windows 2000 (NT 5.0) operating system; this Samba support is experimental. LDAP is a flexible client-server directory protocol that can carry information such as certificates and group memberships.[<A CLASS="footnote" HREF="#ch02-pgfId-943655">4</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch02-pgfId-943655">[4]</a> By <EM CLASS="emphasis">
+directory</em>, we don't mean a directory in a file system, but instead an indexed directory (such as a phone directory). Information is stored and can be easily retrieved in a public LDAP system.</p></div></blockquote></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-nis</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for getting password-file information from NIS (network yellow pages).</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-nisplus</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for obtaining password-file information from NIS+, the successor to NIS.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-ssl</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include experimental support for the Secure Sockets Layer (SSL), which is used to provide encrypted connections from client to server. <a href="appa_01.html"><b>Appendix A, <CITE CLASS="appendix">Configuring Samba with SSL</cite></b></a>, describes setting up Samba with SSL support.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-nisplus-home</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for locating which server contains a particular user's home directory and telling the client to connect to it. Requires <CODE CLASS="literal">
+--with-nis</code> and, usually, <CODE CLASS="literal">
+--with-automounter</code>. </p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-mmap</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include experimental memory mapping code. This is not required for fast locking, which already uses mmap or System V shared memory.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-syslog</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include support for using the SYSLOG utility for logging information generated from the Samba server. There are a couple of Samba configuration options that you can use to enable SYSLOG support; <a href="ch04_01.html"><b>Chapter 4, <CITE CLASS="chapter">Disk Shares </cite></b></a>, discusses these options.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-netatalk</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include experimental support for interoperating with the (Macintosh) Netatalk file server.</p></dd><DT CLASS="term">
+<CODE CLASS="literal">
+--with-quotas</code></dt><DD CLASS="listitem">
+<P CLASS="para">
+Include disk-quota support.</p></dd></dl><P CLASS="para">
+Because each of these options is disabled by default, none of these features are essential to Samba. However, you may want to come back and build a modified version of Samba if you discover that you need one at a later time.</p><P CLASS="para">
+In addition, <A CLASS="xref" HREF="ch02_02.html#ch02-85125">
+Table 2.1</a> shows some other parameters that you can give the <I CLASS="filename">
+configure</i> script if you wish to store parts of the Samba distribution in different places, perhaps to make use of multiple disks or partitions. Note that the defaults sometimes refer to a prefix specified earlier in the table. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch02-85125">
+Table 2.1: Additional Configure Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Meaning</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--prefix</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install architecture-independent files at the base directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<I CLASS="filename">
+/usr/local/samba</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--eprefix</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install architecture-dependent files at the base directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<I CLASS="filename">
+/usr/local/samba</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--bindir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install user executables in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+eprefix</i></code><I CLASS="filename">/bin</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--sbindir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install administrator executables in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+eprefix</i></code><I CLASS="filename">/bin</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--libexecdir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install program executables in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+eprefix</i></code><I CLASS="filename">/libexec</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--datadir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install read-only architecture independent data in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+prefix</i></code><I CLASS="filename">/share</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--libdir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install program libraries in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+eprefix</i></code><I CLASS="filename">/lib</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--includedir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install package include files in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+prefix</i></code><I CLASS="filename">/include</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--infodir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install additional information files in the directory specified.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+prefix</i></code><I CLASS="filename">/info</i></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+--mandir</code>=<CODE CLASS="replaceable"><I>directory</i></code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Install manual pages in the directory specified. </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="replaceable">
+<I>
+prefix</i></code><I CLASS="filename">/man</i></p></td></tr></tbody></table><P CLASS="para">
+Again, before running the <I CLASS="filename">
+configure</i> script, it is important that you are the root user on the system. Otherwise, you may get a warning such as:</p><PRE CLASS="programlisting">
+configure: warning: running as non-root will disable some tests</pre><P CLASS="para">
+You don't want any test to be disabled when the Samba makefile is being created; this leaves the potential for errors down the road when compiling or running Samba on your system.</p><P CLASS="para">
+Here is a sample execution of the <I CLASS="filename">
+configure</i> script, which creates a Samba 2.0.4 makefile for the Linux platform. Note that you must run the configure script in the <EM CLASS="emphasis">
+source</em> directory, and that several lines from the middle of the excerpt have been omitted:</p><PRE CLASS="programlisting">
+# cd samba-2.0.4b/source/
+# ./configure | tee mylog
+
+loading cache ./config.cache
+checking for gcc... (cached) gcc
+checking whether the C compiler (gcc -O) works... yes
+checking whether the C compiler (gcc -O) is a cross-compiler... no
+checking whether we are using GNU C... (cached) yes
+checking whether gcc accepts -g... (cached) yes
+checking for a BSD compatible install... (cached) /usr/bin/install -c
+
+<EM CLASS="emphasis">...(content omitted)...</em>
+
+checking configure summary
+configure OK
+creating ./config.status
+creating include/stamp-h
+creating Makefile
+creating include/config.h</pre><P CLASS="para">
+In general, any message from <I CLASS="filename">
+configure</i> that doesn't begin with the words <CODE CLASS="literal">
+checking</code> or <CODE CLASS="literal">
+creating</code> is an error; it often helps to redirect the output of the configure script to a file so you can quickly search for errors, as we did with the <CODE CLASS="literal">
+tee</code> command above. If there was an error during configuration, more detailed information about it can be found in the <I CLASS="filename">
+config.log</i> file, which is written to the local directory by the <I CLASS="filename">
+configure</i> script.</p><P CLASS="para">
+If the configuration works, you'll see a <CODE CLASS="literal">
+checking</code> <CODE CLASS="literal">
+configure</code> <CODE CLASS="literal">
+summary</code> message followed by a <CODE CLASS="literal">
+configure</code> <CODE CLASS="literal">
+OK</code> message and four or five file creation messages. So far, so good.... Next step: compiling. </p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_01.html" TITLE="2.1 Downloading the Samba Distribution">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.1 Downloading the Samba Distribution" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_03.html" TITLE="2.3 Compiling and Installing Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.3 Compiling and Installing Samba" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.1 Downloading the Samba Distribution</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2.3 Compiling and Installing Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_03.html b/docs/htmldocs/using_samba/ch02_03.html
new file mode 100644
index 00000000000..c4313736d8b
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_03.html
@@ -0,0 +1,235 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] 2.3 Compiling and Installing Samba</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:09Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_02.html" TITLE="2.2 Configuring Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.2 Configuring Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+Chapter 2<br>
+Installing Samba on a Unix System</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_04.html" TITLE="2.4 A Basic Samba Configuration File">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.4 A Basic Samba Configuration File" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch02-13217">
+2.3 Compiling and Installing Samba</a></h2><P CLASS="para">At this point you should be ready to build the Samba executables. Compiling is also easy: in the <I CLASS="filename">
+source</i> directory, type <CODE CLASS="literal">
+make</code> on the command line. The <I CLASS="filename">
+make</i> utility will produce a stream of explanatory and success messages, beginning with:</p><PRE CLASS="programlisting">
+Using FLAGS = -O -Iinclude ...</pre><P CLASS="para">
+This build includes compiles for both <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em>, and ends in a linking command for <I CLASS="filename">
+bin/make_ printerdef</i>. For example, here is a sample make of Samba version 2.0.4 on a Linux server:</p><PRE CLASS="programlisting"><CODE CLASS="literal"># </code>make
+Using FLAGS = -O -Iinclude -I./include -I./ubiqx -I./smbwrapper -DSMBLOGFILE=&quot;/usr/local/samba/var/log.smb&quot; -DNMBLOGFILE=&quot;/usr/local/samba/var/log.nmb&quot; -DCONFIGFILE=&quot;/usr/local/samba/lib/smb.conf&quot; -DLMHOSTSFILE=&quot;/usr/local/samba/lib/lmhosts&quot; -DSWATDIR=&quot;/usr/local/samba/swat&quot; -DSBINDIR=&quot;/usr/local/samba/bin&quot; -DLOCKDIR=&quot;/usr/local/samba/var/locks&quot; -DSMBRUN=&quot;/usr/local/samba/bin/smbrun&quot; -DCODEPAGEDIR=&quot;/usr/local/samba/lib/codepages&quot; -DDRIVERFILE=&quot;/usr/local/samba/lib/printers.def&quot; -DBINDIR=&quot;/usr/local/samba/bin&quot; -DHAVE_INCLUDES_H -DPASSWD_PROGRAM=&quot;/bin/passwd&quot; -DSMB_PASSWD_FILE=&quot;/usr/local/samba/private/smbpasswd&quot;
+Using FLAGS32 = -O -Iinclude -I./include -I./ubiqx -I./smbwrapper -DSMBLOGFILE=&quot;/usr/local/samba/var/log.smb&quot; -DNMBLOGFILE=&quot;/usr/local/samba/var/log.nmb&quot; -DCONFIGFILE=&quot;/usr/local/samba/lib/smb.conf&quot; -DLMHOSTSFILE=&quot;/usr/local/samba/lib/lmhosts&quot; -DSWATDIR=&quot;/usr/local/samba/swat&quot; -DSBINDIR=&quot;/usr/local/samba/bin&quot; -DLOCKDIR=&quot;/usr/local/samba/var/locks&quot; -DSMBRUN=&quot;/usr/local/samba/bin/smbrun&quot; -DCODEPAGEDIR=&quot;/usr/local/samba/lib/codepages&quot; -DDRIVERFILE=&quot;/usr/local/samba/lib/printers.def&quot; -DBINDIR=&quot;/usr/local/samba/bin&quot; -DHAVE_INCLUDES_H -DPASSWD_PROGRAM=&quot;/bin/passwd&quot; -DSMB_PASSWD_FILE=&quot;/usr/local/samba/private/smbpasswd&quot;
+Using LIBS = -lreadline -ldl -lcrypt -lpam
+Compiling smbd/server.c
+Compiling smbd/files.c
+Compiling smbd/chgpasswd.c
+
+<EM CLASS="emphasis">...(content omitted)...</em>
+
+Compiling rpcclient/cmd_samr.c
+Compiling rpcclient/cmd_reg.c
+Compiling rpcclient/cmd_srvsvc.c
+Compiling rpcclient/cmd_netlogon.c
+Linking bin/rpcclient
+Compiling utils/smbpasswd.c
+Linking bin/smbpasswd
+Compiling utils/make_smbcodepage.c
+Linking bin/make_smbcodepage
+Compiling utils/nmblookup.c
+Linking bin/nmblookup
+Compiling utils/make_printerdef.c
+Linking bin/make_printerdef</pre><P CLASS="para">
+If you encounter problems when compiling, check the Samba documentation to see if it is easily fixable. Another possibility is to search or post to the Samba mailing lists, which are given at the end of <a href="ch09_03.html">Chapter 9</a>, and on the Samba home page. Most compilation issues are system specific and almost always easy to overcome.</p><P CLASS="para">
+Now that the files have been compiled, you can install them into the directories you identified with the command:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>make install</b></code></pre><P CLASS="para">
+If you happen to be upgrading, your old Samba files will be saved with the extension <EM CLASS="emphasis">
+ .old</em>, and you can go back to that previous version with the command <CODE CLASS="literal">
+make</code> <CODE CLASS="literal">
+revert</code>. After doing a <CODE CLASS="literal">
+make</code> <CODE CLASS="literal">
+install</code>, you should copy the <EM CLASS="emphasis">
+.old </em>files (if they exist) to a new location or name. Otherwise, the next time you install Samba, the original <EM CLASS="emphasis">
+.old</em> will be overwritten without warning and you could lose your earlier version. If you configured Samba to use the default locations for files, the new files will be installed in the directories listed in <A CLASS="xref" HREF="ch02_03.html#ch02-pgfId-939627">
+Table 2.2</a>. Remember that you need to perform the installation from an account that has write privileges on these target directories; this is typically the root account. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch02-pgfId-939627">
+Table 2.2: Samba Installation Directories </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Directory</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Main tree</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/bin</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Binaries</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/lib</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+smb.conf</em>, <EM CLASS="emphasis">
+lmhosts</em>, configuration files, etc.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/man</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba documentation</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/private</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba encrypted password file</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/swat</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SWAT files</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+/usr/local/samba/var</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba log files, lock files, browse list info, shared memory files, process ID files</p></td></tr></tbody></table><P CLASS="para">
+Throughout the remainder of the book, we occasionally refer to the location of the main tree as <CODE CLASS="replaceable">
+<I>
+samba_dir</i></code>. In most configurations, this is the base directory of the installed Samba package: <I CLASS="filename">
+/usr/local/samba</i>.</p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Watch out if you've made <I CLASS="filename">
+/usr</i> a read-only partition. You will want to put the logs, locks, and password files somewhere else.</p></blockquote><P CLASS="para">
+Here is the installation that we performed on our machine. You can see that we used <I CLASS="filename">
+/usr/local/samba</i> as the base directory for the distribution (e.g., <CODE CLASS="replaceable">
+<I>
+samba_dir</i></code>):</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>make install</b></code>
+Using FLAGS = -O -Iinclude -I./include -I./ubiqx -I./smbwrapper -DSMBLOGFILE=&quot;/usr/local/samba/var/log.smb&quot; -DNMBLOGFILE=&quot;/usr/local/samba/var/log.nmb&quot; -DCONFIGFILE=&quot;/usr/local/samba/lib/smb.conf&quot; -
+
+<I CLASS="lineannotation">...(content omitted)...</i>
+
+The binaries are installed. You may restore the old binaries
+(if there were any) using the command &quot;make revert&quot;. You may
+uninstall the binaries using the command &quot;make uninstallbin&quot;
+or &quot;make uninstall&quot; to uninstall binaries, man pages and shell
+scripts.
+
+<I CLASS="lineannotation">...(content omitted)...</i>
+
+============================================================
+The SWAT files have been installed. Remember to read the
+README for information on enabling and using SWAT.
+============================================================</pre><P CLASS="para">
+If the last message is about SWAT, you've successfully installed all the files. Congratulations! You now have Samba on your system!</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-943188">
+2.3.1 Final Installation Steps</a></h3><P CLASS="para">There are a couple of final steps to perform. Specifically, add the Samba Web Administration Tool (SWAT) to the <I CLASS="filename">
+/etc/services</i> and <I CLASS="filename">
+/etc/inetd.conf</i> configuration files. SWAT runs as a daemon under <EM CLASS="emphasis">
+inetd</em> and provides a forms-based editor in your web browser for creating and modifying SMB configuration files.</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-943198">
+</a>To add SWAT, add the following line to the end of the <I CLASS="filename">
+/etc/services</i> file:</p></li></ol><PRE CLASS="programlisting">
+swat 901/tcp</pre><OL CLASS="orderedlist" START="2">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-938792">
+</a>Add these lines to <I CLASS="filename">
+/etc/inetd.conf.</i> (Check your <I CLASS="filename">
+inetd.conf</i> manual page to see the exact format of the<I CLASS="filename">
+ inetd.conf</i> file if it differs from the following example.) Don't forget to change the path to the SWAT binary if you installed it in a different location from the default <I CLASS="filename">
+/usr/local/samba</i>.</p></li></ol><PRE CLASS="programlisting">
+swat stream tcp nowait.400 root /usr/local/samba/bin/swat swat</pre><P CLASS="para">
+And that's pretty much it for the installation. Before you can start up Samba, however, you need to create a configuration file for it. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_02.html" TITLE="2.2 Configuring Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.2 Configuring Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_04.html" TITLE="2.4 A Basic Samba Configuration File">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.4 A Basic Samba Configuration File" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.2 Configuring Samba</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2.4 A Basic Samba Configuration File</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_04.html b/docs/htmldocs/using_samba/ch02_04.html
new file mode 100644
index 00000000000..608a1e2c40b
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_04.html
@@ -0,0 +1,186 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] 2.4 A Basic Samba Configuration File</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:10Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_03.html" TITLE="2.3 Compiling and Installing Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.3 Compiling and Installing Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+Chapter 2<br>
+Installing Samba on a Unix System</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_05.html" TITLE="2.5 Starting the Samba Daemons">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.5 Starting the Samba Daemons" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch02-13464">
+2.4 A Basic Samba Configuration File</a></h2><P CLASS="para">
+The key to configuring Samba is its lone configuration file: <I CLASS="filename">
+smb.conf</i>. This configuration file can be very simple or extremely complex, and the rest of this book is devoted to helping you get deeply personal with this file. For now, however, we'll show you how to set up a single file service, which will allow you to fire up the Samba daemons and see that everything is running as it should be. In later chapters, you will see how to configure Samba for more complicated and interesting tasks. </p><P CLASS="para">
+The installation process does not automatically create an <I CLASS="filename">
+smb.conf</i> configuration file, although several example files are included in the Samba distribution. To test the server software, though, we'll use the following file. It should be named <I CLASS="filename">
+smb.conf</i> and placed in the <EM CLASS="emphasis">
+/usr/local/samba/lib</em> directory.[<A CLASS="footnote" HREF="#ch02-pgfId-943223">5</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch02-pgfId-943223">[5]</a> If you did not compile Samba, but instead downloaded a binary, check with the documentation for the package to find out where it expects the <I CLASS="filename">
+smb.conf</i> file. If Samba came preinstalled with your Unix system, there is probably already an <I CLASS="filename">
+smb.conf</i> file somewhere on your system.</p></div></blockquote><PRE CLASS="programlisting">
+[global]
+ workgroup = SIMPLE
+[test]
+ comment = For testing only, please
+ path = /export/samba/test
+ read only = no
+ guest ok = yes</pre><P CLASS="para">
+This brief configuration file tells the Samba server to offer the directory <I CLASS="filename">
+/export/samba/test</i> on the server as an SMB/CIFS share called <CODE CLASS="literal">test</code>. The server also becomes part of the named workgroup SIMPLE, which each of the clients must also be a part of. (Use your own workgroup here if you already know what it is.) We'll use the <CODE CLASS="literal">
+[test]</code> share in the next chapter to set up the Windows clients. For now, you can complete the setup by performing the following commands as root on your Unix server:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>mkdir /export/samba/test</b></code>
+# <CODE CLASS="userinput"><B>chmod 777 /export/samba/test</b></code></pre><P CLASS="para">
+We should point out that in terms of system security, this is the worst setup possible. For the moment, however, we only wish to test Samba, so we'll leave security out of the picture. In addition, there are some encrypted password issues that we will encounter with Windows clients later on, so this setup will afford us the least amount of headaches.</p><P CLASS="para">
+If you are using Windows 98 or Windows NT Service Pack 3 or above, you must add the following entry to the <CODE CLASS="literal">
+[global]</code> section of the Samba configuration file: <CODE CLASS="literal">
+encrypt passwords = yes</code>. In addition, you must use the <I CLASS="filename">
+smbpassword</i> program (typically located in <I CLASS="filename">
+/usr/local/samba/bin/</i>) to reenter the username/password combinations of those users on the Unix server who should be able to access shares into Samba's encrypted client database. For example, if you wanted to allow Unix user <CODE CLASS="literal">
+steve</code> to access shares from an SMB client, you could type: <CODE CLASS="literal">
+smbpassword -a steve</code>. The first time a user is added, the program will output an error saying that the encrypted password database does not exist. Don't worry, it will then create the database for you. Make sure that the username/password combinations that you add to the encrypted database match the usernames and passwords that you intend to use on the Windows client side.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-942383">
+2.4.1 Using SWAT</a></h3><P CLASS="para">With Samba 2.0, creating a configuration file is even easier than writing a configuration file by hand. You can use your browser to connect to <a href="http://localhost:901"><EM CLASS="emphasis">http://localhost:901</em></a>, and log on as the root account, as shown in <A CLASS="xref" HREF="ch02_04.html#ch02-60915">
+Figure 2.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch02-60915">
+Figure 2.1: SWAT login</a></h4><IMG CLASS="graphic" SRC="figs/sam.0201.gif" ALT="Figure 2.1"><P CLASS="para">
+After logging in, press the GLOBALS button at the top of the screen. You should see the Global Variables page shown in <A CLASS="xref" HREF="ch02_04.html#ch02-49138">
+Figure 2.2</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch02-49138">
+Figure 2.2: SWAT Global Variables page</a></h4><IMG CLASS="graphic" SRC="figs/sam.0202.gif" ALT="Figure 2.2"><P CLASS="para">
+In this example, set the workgroup field to SIMPLE and the security field to USER. The only other option you need to change from the menu is one determining which system on the LAN resolves NetBIOS addresses; this system is called the <EM CLASS="emphasis">
+WINS server</em>. At the very bottom of the page, set the wins support field to Yes, unless you already have a WINS server on your network. If you do, put the WINS server's IP address in the wins server field instead. Then return to the top and press the Commit Changes button to write the changes out to the <EM CLASS="emphasis">
+smb.conf</em> file. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch02-29175">
+Figure 2.3: SWAT Share Creation screen</a></h4><IMG CLASS="graphic" SRC="figs/sam.0203.gif" ALT="Figure 2.3"><P CLASS="para">
+Next, press the Shares icon. You should see a page similar to <A CLASS="xref" HREF="ch02_04.html#ch02-29175">
+Figure 2.3</a>. Choose Test in the field beside the Choose Share button. You will see the Share Parameters screen, as shown in <A CLASS="xref" HREF="ch02_04.html#ch02-37186">
+Figure 2.4</a>. We added a comment to remind us that this is a test share in the <I CLASS="filename">
+smb.conf</i> file. SWAT has copies of all that information here.</p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch02-37186">
+Figure 2.4: SWAT Share Parameters screen</a></h4><IMG CLASS="graphic" SRC="figs/sam.0204.gif" ALT="Figure 2.4"><P CLASS="para">
+If you press the View button, SWAT shows you the following <I CLASS="filename">
+smb.conf</i> file:</p><PRE CLASS="programlisting">
+# Samba config file created using SWAT
+# from localhost (127.0.0.1)
+# Date: 1998/11/27 15:42:40
+
+# Global parameters
+ workgroup = SIMPLE
+[test]
+ comment = For testing only, please
+ path = /export/samba/test
+ read only = no
+ guest ok = yes</pre><P CLASS="para">
+Once this configuration file is completed, you can skip the next step because the output of SWAT is guaranteed to be syntactically correct. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-938862">
+2.4.2 Testing the Configuration File</a></h3><P CLASS="para">If you didn't use SWAT to create your configuration file, you should probably test it to ensure that it is syntactically correct. It may seem silly to run a test program against an eight-line configuration file, but it's good practice for the real ones that we'll be writing later on.</p><P CLASS="para">
+The test parser, <I CLASS="filename">
+testparm</i>, examines an <I CLASS="filename">
+smb.conf</i> file for syntax errors and reports any it finds along with a list of the services enabled on your machine. An example follows; you'll notice that in our haste to get the server running we mistyped <CODE CLASS="literal">
+workgroup</code> as <CODE CLASS="literal">
+workgrp</code> (the output is often lengthy, so we recommend capturing the last parts with the <CODE CLASS="literal">
+tee</code> command):</p><PRE CLASS="programlisting">
+Load smb config files from smb.conf
+Unknown parameter encountered: &quot;workgrp&quot;
+Ignoring unknown parameter &quot;workgrp&quot;
+Processing section &quot;[test]&quot;
+Loaded services file OK.
+Press enter to see a dump of your service definitions
+# Global parameters
+[global]
+ workgroup = WORKGROUP
+ netbios name =
+ netbios aliases =
+ server string = Samba 2.0.5a
+ interfaces =
+ bind interfaces only = No
+
+<I CLASS="lineannotation">...(content omitted)...</i>
+
+[test]
+ comment = For testing only, please
+ path = /export/samba/test
+ read only = No
+ guest ok = Yes</pre><P CLASS="para">
+The interesting parts are at the top and bottom. The top of the output will flag any syntax errors that you may have made, and the bottom lists the services that the server thinks it should offer. A word of advice: make sure that you and the server have the same expectations. </p><P CLASS="para">
+If everything looks good, then you are ready to fire up the server daemons! </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_03.html" TITLE="2.3 Compiling and Installing Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.3 Compiling and Installing Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_05.html" TITLE="2.5 Starting the Samba Daemons">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.5 Starting the Samba Daemons" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.3 Compiling and Installing Samba</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2.5 Starting the Samba Daemons</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_05.html b/docs/htmldocs/using_samba/ch02_05.html
new file mode 100644
index 00000000000..95d506e5e96
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_05.html
@@ -0,0 +1,195 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] 2.5 Starting the Samba Daemons</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:11Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_04.html" TITLE="2.4 A Basic Samba Configuration File">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.4 A Basic Samba Configuration File" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+Chapter 2<br>
+Installing Samba on a Unix System</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_06.html" TITLE="2.6 Testing the Samba Daemons">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.6 Testing the Samba Daemons" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch02-29069">
+2.5 Starting the Samba Daemons</a></h2><P CLASS="para">
+There are two Samba processes, <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em>, that need to be running for Samba to work correctly. There are three ways to start:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-943268">
+</a>By hand</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-943266">
+</a>As stand-alone daemons</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch02-pgfId-947794">
+</a>From <EM CLASS="emphasis">
+inetd</em></p></li></ul><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-938883">
+2.5.1 Starting the Daemons by Hand</a></h3><P CLASS="para">
+If you're in a hurry, you can start the Samba daemons by hand. As root, simply enter the following commands:</p><PRE CLASS="programlisting">
+#<CODE CLASS="userinput"> <B>/usr/local/samba/bin/smbd -D</b></code>
+#<CODE CLASS="userinput"> <B>/usr/local/samba/bin/nmbd -D</b></code></pre><P CLASS="para">
+At this point, Samba will be running on your system and will be ready to accept connections.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-943275">
+2.5.2 Stand-alone Daemons</a></h3><P CLASS="para">
+To run the Samba processes as stand-alone daemons, you need to add the commands listed in the previous section to your standard Unix startup scripts. This varies depending on whether you have a BSD-style Unix system or a System V Unix.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch02-pgfId-947593">
+2.5.2.1 BSD Unix</a></h4><P CLASS="para">
+WIth a BSD-style Unix, you need to append the following code to the <I CLASS="filename">
+rc.local </i>file, which is typically found in the <I CLASS="filename">
+/etc</i> or <I CLASS="filename">
+/etc/rc.d</i> directories:</p><PRE CLASS="programlisting">
+if [ -x /usr/local/samba/bin/smbd]; then
+ echo &quot;Starting smbd...&quot;
+ /usr/local/samba/bin/smbd -D
+ echo &quot;Starting nmbd...&quot;
+ /usr/local/samba/bin/nmbd -D
+fi</pre><P CLASS="para">
+This code is very simple; it checks to see if the <I CLASS="filename">
+smbd</i> file has execute permissions on it, and if it does, it starts up each of the Samba daemons on system boot.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch02-pgfId-943333">
+2.5.2.2 System V Unix</a></h4><P CLASS="para">
+With System V, things can get a little more complex. System V typically uses scripts to start and stop daemons on the system. Hence, you need to instruct Samba how to operate when it starts and when it stops. You can modify the contents of the <I CLASS="filename">
+/etc/rc.local</i> directory and add something similar to the following program entitled <I CLASS="filename">
+smb</i>:</p><PRE CLASS="programlisting">
+#!/bin/sh
+
+# Contains the &quot;killproc&quot; function on Red Hat Linux
+./etc/rc.d/init.d/functions
+
+PATH=&quot;/usr/local/samba/bin:$PATH&quot;
+
+case $1 in
+ 'start')
+ echo &quot;Starting smbd...&quot;
+ smbd -D
+ echo &quot;Starting nmbd...&quot;
+ nmbd -D
+ ;;
+ 'stop')
+ echo &quot;Stopping smbd and nmbd...&quot;
+ killproc smbd
+ killproc nmbd
+ rm -f /usr/local/samba/var/locks/smbd.pid
+ rm -f /usr/local/samba/var/locks/nmbd.pid
+ ;;
+ *)
+ echo &quot;usage: smb {start|stop}&quot;
+ ;;
+esac</pre><P CLASS="para">
+With this script, you can start and stop the SMB service with the following commands:</p><PRE CLASS="programlisting">
+# /etc/rc.local/smb start
+Starting smbd...
+Starting nmbd...
+# /etc/rc.local/smb stop
+Stopping smbd and nmbd...</pre></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch02-pgfId-943302">
+2.5.3 Starting From Inetd</a></h3><P CLASS="para">
+The <EM CLASS="emphasis">
+inetd</em> daemon is a Unix system's Internet "super daemon." It listens on TCP ports defined in <I CLASS="filename">
+/etc/services</i> and executes the appropriate program for each port, which is defined in <I CLASS="filename">
+/etc/inetd.conf</i>. The advantage of this scheme is that you can have a large number of daemons ready to answer queries, but they don't all have to be running. Instead, the <EM CLASS="emphasis">
+inetd</em> daemon listens in places of all the others. The penalty is a small overhead cost of creating a new daemon process, and the fact that you need to edit two files rather than one to set things up. This is handy if you have only one or two users or your machine has too many daemons already. It's also easier to perform an upgrade without disturbing an existing connection.</p><P CLASS="para">
+If you wish to start from <I CLASS="filename">
+inetd</i>, first open <I CLASS="filename">
+/etc/services</i> in your text editor. If you don't already have them defined, add the following two lines:</p><PRE CLASS="programlisting">
+netbios-ssn 139/tcp
+netbios-ns 137/udp</pre><P CLASS="para">
+Next, edit <I CLASS="filename">
+/etc/inetd.conf</i>. Look for the following two lines and add them if they don't exist. If you already have <CODE CLASS="literal">
+smbd</code> and <CODE CLASS="literal">
+nmbd</code> lines in the file, edit them to point at the new <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em> you've installed. Your brand of Unix may use a slightly different syntax in this file; use the existing entries and the <I CLASS="filename">
+inetd.conf </i><KBD CLASS="command"></kbd>manual page <KBD CLASS="command"></kbd>as a guide:</p><PRE CLASS="programlisting">
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd</pre><P CLASS="para">
+Finally, kill any <EM CLASS="emphasis">
+smbd</em> or <EM CLASS="emphasis">
+nmbd</em> processes and send the <EM CLASS="emphasis">
+inetd</em> process a hangup (HUP) signal. (The <EM CLASS="emphasis">
+inetd</em> daemon rereads its configuration file on a HUP signal.) To do this, use the <CODE CLASS="literal">
+ps</code> command to find its process ID, then signal it with the following command:</p><PRE CLASS="programlisting">
+# <CODE CLASS="userinput"><B>kill -HUP process_id</b></code></pre><P CLASS="para">
+After that, Samba should be up and running. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_04.html" TITLE="2.4 A Basic Samba Configuration File">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.4 A Basic Samba Configuration File" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_06.html" TITLE="2.6 Testing the Samba Daemons">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 2.6 Testing the Samba Daemons" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.4 A Basic Samba Configuration File</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+2.6 Testing the Samba Daemons</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch02_06.html b/docs/htmldocs/using_samba/ch02_06.html
new file mode 100644
index 00000000000..46adba5d3b6
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch02_06.html
@@ -0,0 +1,108 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 2] 2.6 Testing the Samba Daemons</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:29:12Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_05.html" TITLE="2.5 Starting the Samba Daemons">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.5 Starting the Samba Daemons" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch02_01.html" TITLE="2. Installing Samba on a Unix System">
+Chapter 2<br>
+Installing Samba on a Unix System</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch03_01.html" TITLE="3. Configuring Windows Clients">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3. Configuring Windows Clients" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch02-67898">
+2.6 Testing the Samba Daemons</a></h2><P CLASS="para">It's hard to believe, but we're nearly done with the Samba server setup. All that's left to do is to make sure that everything is working as we think it should. A convenient way to do this is to use the <I CLASS="filename"> smbclient</i> program to examine what the server is offering to the network. If everything is set up properly, you should be able to do the following:</p><PRE CLASS="programlisting">
+<CODE CLASS="userinput"><B># smbclient -U% -L localhost</b></code>
+
+Added interface ip=192.168.220.100 bcast=192.168.220.255 nmask=255.255.255.0
+Domain=[SIMPLE] OS=[Unix] Server=[Samba 2.0.5a]
+
+ Sharename Type Comment
+ --------- ---- -------
+ test Disk For testing only, please
+ IPC$ IPC IPC Service (Samba 2.0.5a)
+
+ Server Comment
+ --------- -------
+ HYDRA Samba 2.0.5a
+
+ Workgroup Master
+ --------- -------
+ SIMPLE HYDRA</pre><P CLASS="para">
+If there is a problem, don't panic! Try to start the daemons manually, and check the system output or the debug files at <I CLASS="filename">
+/usr/local/samba/var/log.smb</i> to see if you can determine what happened. If you think it may be a more serious problem, skip to <a href="ch07_01.html"><b>Chapter 7, <CITE CLASS="chapter"> Printing and Name Resolution</cite></b></a>, for help on troubleshooting the Samba daemons. </p><P CLASS="para">
+If it worked, congratulations! You now have successfully set up the Samba server with a disk share. It's a simple one, but we can use it to set up and test the Windows 95 and NT clients in the next chapter. Then we will start making it more interesting by adding services such as home directories, printers, and security, and seeing how to integrate the server into a larger Windows domain. </p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_05.html" TITLE="2.5 Starting the Samba Daemons">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.5 Starting the Samba Daemons" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch03_01.html" TITLE="3. Configuring Windows Clients">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3. Configuring Windows Clients" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.5 Starting the Samba Daemons</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+3. Configuring Windows Clients</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch03_01.html b/docs/htmldocs/using_samba/ch03_01.html
new file mode 100644
index 00000000000..915befad0f4
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch03_01.html
@@ -0,0 +1,277 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 3] Configuring Windows Clients</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:31:14Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_06.html" TITLE="2.6 Testing the Samba Daemons">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.6 Testing the Samba Daemons" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 3</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_02.html" TITLE="3.2 Setting Up Windows NT 4.0 Computers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3.2 Setting Up Windows NT 4.0 Computers" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch03-91548">
+3. Configuring Windows Clients</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch03-55770" TITLE="3.1 Setting Up Windows 95/98 Computers">
+Setting Up Windows 95/98 Computers</a><br>
+<A CLASS="sect1" HREF="ch03_02.html" TITLE="3.2 Setting Up Windows NT 4.0 Computers">
+Setting Up Windows NT 4.0 Computers</a><br>
+<A CLASS="sect1" HREF="ch03_03.html" TITLE="3.3 An Introduction to SMB/CIFS">
+An Introduction to SMB/CIFS</a></p><P>
+</p></div><P CLASS="para">You'll be glad to know that configuring Windows to use your new Samba server is quite simple. SMB is Microsoft's native language for resource sharing on a local area network, so much of the installation and setup on the Windows client side has been taken care of already. The primary issues that we will cover in this chapter involve communication and coordination between Windows and Unix, two completely different operating systems.</p><P CLASS="para">
+Samba uses TCP/IP to talk to its clients on the network. If you aren't already using TCP/IP on your Windows computers, this chapter will show you how to install it. Then you'll need to configure your Windows machines to operate on a TCP/IP network. Once these two requirements have been taken care of, we can show how to access a shared disk on the Samba server.</p><P CLASS="para">
+This chapter is divided into three sections. The first section covers setting up Windows 95/98 computers while the second covers Windows NT 4.0 machines. The final section provides some prerequisite information on how SMB connections are made from Windows clients and servers, which is useful as we move into the later chapters of the book.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch03-55770">
+3.1 Setting Up Windows 95/98 Computers</a></h2><P CLASS="para">Unfortunately, Windows 95/98 wasn't designed for a PC to have more than one user; that concept is more inherent to a Unix operating system or Windows NT. However, Windows 95/98 does have <EM CLASS="emphasis">
+limited</em> support for multiple users: if you tell it, the operating system will keep a separate profile (desktop layout) and password file for each user. This is a far cry from true multiuser security. In other words, Windows 95/98 won't try to keep one user from destroying the work of another on the local hard drive like Unix, but profiles are a place to start.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-941931">
+3.1.1 Accounts and Passwords</a></h3><P CLASS="para">The first thing we need to do is to tell Windows to keep user profiles separate, and to collect usernames and passwords to authenticate anyone trying to access a Samba share. We do so via the Password settings in the Control Panel. If you are not familiar with the Windows Control Panel, you can access it by choosing the Settings menu item from the pop-up menu of the Start button in the lower-left corner of the screen. Alternatively, you'll find it as a folder under the icon in the upper-left corner that represents your computer and is typically labeled My Computer.</p><P CLASS="para">
+After selecting the Passwords icon in the Control Panel, click on the User Profiles tab on the far right. You should see the dialog box shown in <A CLASS="xref" HREF="ch03_01.html#ch03-84319">
+Figure 3.1</a>. Then click the lower of the two radio buttons that starts "Users can customize their preferences...." This causes Windows to store a separate profile for each user, and saves the username and password you provide, which it will use later when it connects to an SMB/CIFS server. Finally, check <EM CLASS="emphasis">
+both</em> the options under the User Profile Settings border, as shown in the figure. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-84319">
+Figure 3.1: The Passwords Properties panel</a></h4><IMG CLASS="graphic" SRC="figs/sam.0301.gif" ALT="Figure 3.1"><P CLASS="para">
+The next step is to select the Change Passwords tab on the left side of the dialog box. In order for Samba to allow you access to its shares, the username and password you give to Windows must match the account and password on the Samba server. If you don't have this tab in your dialog box, don't worry; it's probably because you haven't given yourself a Windows username and password yet. Simply click the OK button at the bottom and respond Yes when Windows asks to reboot. Then, skip down to the section entitled <A CLASS="xref" HREF="ch03_01.html#ch03-57581">
+Section 3.1.1.2, Logging in for the first time</a>.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-941948">
+3.1.1.1 Changing the Windows password</a></h4><P CLASS="para">After selecting the Change Passwords tab, the dialog box in <A CLASS="xref" HREF="ch03_01.html#ch03-26778">
+Figure 3.2</a> will appear.</p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-26778">
+Figure 3.2: The Change Passwords tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0302.gif" ALT="Figure 3.2"><P CLASS="para">
+Select the Change Windows Password button. The Change Windows Password dialog box should appear, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-97002">
+Figure 3.3</a>. From here, you can change your password to match the password of the account on the Samba server through which you intend to log in. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-97002">
+Figure 3.3: The Change Windows Password dialog box</a></h4><IMG CLASS="graphic" SRC="figs/sam.0303.gif" ALT="Figure 3.3"></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-57581">
+3.1.1.2 Logging in for the first time</a></h4><P CLASS="para">If you didn't have a Change Passwords tab in the Passwords Properties window, then after Windows has finished rebooting, it will ask you to log in with a username and a password. Give yourself the same username and password that you have on the Samba server. After confirming your new username and password, or if you already have one, Windows should ask you if you want to have a profile, using the dialog shown in <A CLASS="xref" HREF="ch03_01.html#ch03-48947">
+Figure 3.4</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-48947">
+Figure 3.4: Windows Networking profiles</a></h4><IMG CLASS="graphic" SRC="figs/sam.0304.gif" ALT="Figure 3.4"><P CLASS="para">
+Answer Yes, upon which Windows will create a separate profile and password file for you and save a copy of your password in the file. Now when you connect to Samba, Windows will send its password, which will be used to authenticate you for each share. We won't worry about profiles for the moment; we'll cover them in <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a>. We should point out, however, that there is a small security risk: someone can steal the password file and decrypt the passwords because it's weakly encrypted. Unfortunately, there isn't a solution to this with Windows 95/98. In Windows 2000 (NT 5.0), the password encryption should be replaced with a much better algorithm.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-36280">
+3.1.2 Setting Up the Network</a></h3><P CLASS="para">The next thing we need to do is make sure we have the TCP/IP networking protocol set up correctly. To do this, double-click on the Network icon in the Control Panel. You should see the network configuration dialog box, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-15320">
+Figure 3.5</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-15320">
+Figure 3.5: The Windows 95/98 Network panel</a></h4><IMG CLASS="graphic" SRC="figs/sam.0305.gif" ALT="Figure 3.5"><P CLASS="para">
+Microsoft networking works by binding specific protocols, such as IPX or TCP/IP, to a specific hardware device, such as an Ethernet card or a dialup connection. By routing a protocol through a hardware device, the machine can act as a client or server for a particular type of network. For Samba, we are interested in binding the TCP/IP protocol through a networking device, making the machine a client for Microsoft networks. Thus, when the dialog box appears, you should see at least the Client for Microsoft Networks component installed on the machine, and hopefully a networking device (preferably an Ethernet card) bound to the TCP/IP protocol. If there is only one networking hardware device, you'll see the TCP/IP protocol listed below that device. If it appears similar to <A CLASS="xref" HREF="ch03_01.html#ch03-15320">
+Figure 3.5</a>, the protocol is bound to the device.</p><P CLASS="para">
+You may also see "File and printer sharing for Microsoft Networks," which is useful. In addition, you might see NetBEUI or Novell Networking, which are standard with Windows installations but undesirable when TCP/IP is running. Remove NetBEUI if you possibly can&nbsp;- it's unnecessary and makes debugging Windows browsing difficult. If you don't have any Novell servers on your network, you can remove Novell (IPX/SPX) as well.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942014">
+3.1.2.1 Adding TCP/IP</a></h4><P CLASS="para">If you don't see TCP/IP listed at all, you'll need to install the protocol. If you already have TCP/IP, skip this section, and continue with the section <A CLASS="xref" HREF="ch03_01.html#ch03-48802">
+Section 3.1.3, Setting Your Name and Workgroup</a>, later in this chapter.</p><P CLASS="para">
+Installing TCP/IP isn't difficult since Microsoft distributes its own version of TCP/IP for free on their installation CD-ROM. You can add the protocol by clicking on the Add button below the component window. Indicate that you wish to add a specific protocol by selecting Protocol and clicking Add... on the following dialog box, which should look similar to <A CLASS="xref" HREF="ch03_01.html#ch03-24245">
+Figure 3.6</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-24245">
+Figure 3.6: Selecting a protocol to install</a></h4><IMG CLASS="graphic" SRC="figs/sam.0306.gif" ALT="Figure 3.6"><P CLASS="para">
+After that, select the protocol TCP/IP from manufacturer Microsoft, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-50801">
+Figure 3.7</a>, then click OK. After doing so, you will be returned to the network dialog. Click OK there to close the dialog box, upon which Windows will install the necessary components from disk and reboot the machine. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-50801">
+Figure 3.7: Selecting a protocol to install</a></h4><IMG CLASS="graphic" SRC="figs/sam.0307.gif" ALT="Figure 3.7"></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942047">
+3.1.2.2 Configuring TCP/IP</a></h4><P CLASS="para">If you have more than one networking device (for example, both an Ethernet card and a dialup networking modem), each appropriate hardware device should be "linked" to the TCP/IP protocol with an arrow, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-61576">
+Figure 3.8</a>. Select the TCP/IP protocol linked to the networking device that will be accessing the Samba network. When it is highlighted, click the Properties button. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-61576">
+Figure 3.8: Selecting the correct TCP/IP protocol</a></h4><IMG CLASS="graphic" SRC="figs/sam.0308.gif" ALT="Figure 3.8"><P CLASS="para">
+After doing so, the TCP/IP Properties panel for that device is displayed, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-73526">
+Figure 3.9</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-73526">
+Figure 3.9: STCP/IP Properties panel</a></h4><IMG CLASS="graphic" SRC="figs/sam.0309.gif" ALT="Figure 3.9"><P CLASS="para">
+There are seven tabs near the top of this panel, and you will need to configure four of them: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942078">
+</a>IP address</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942079">
+</a>DNS configuration</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942080">
+</a>WINS configuration</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942081">
+</a>Bindings</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-948031">
+3.1.2.3 IP Address tab </a></h4><P CLASS="para">
+The IP Address tab is shown in <A CLASS="xref" HREF="ch03_01.html#ch03-73526">
+Figure 3.9</a>. Press the "Specify an IP address" radio button and enter the client's address and subnet mask in the space provided. You or your network manager should have selected an address for the machine. The values should place the computer on the same subnet as the Samba server. For example, if the server's address is 192.168.236.86, and its network mask 255.255.255.0, you might use address 192.168.236.10 (if it is available) for the Windows 98 computer, along with the same netmask as the server. If you already use DHCP on your network to provide IP addresses to Windows machines, select the "Obtain an IP address automatically" button.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942087">
+3.1.2.4 DNS Configuration tab</a></h4><P CLASS="para">Domain Name Service (DNS) is responsible for translating Internet computer names such as <EM CLASS="emphasis">
+hobbes.example.com</em> into machine-readable IP addresses such as 192.168.236.10. There are two ways to accomplish this on a Windows 98 machine: you can specify a server to do the translation for you or you can keep a local list of name/address pairs to refer to. </p><P CLASS="para">
+Networks that are connected to the Internet typically use a server, since the hosts files required would otherwise be huge. For an unconnected LAN, the list of possible hosts is small and well-known and might be kept on a Unix machine in the <EM CLASS="emphasis">
+/etc/hosts</em> file. If you are in doubt as to whether a DNS server is being used, or what its address might be, look at the file <EM CLASS="emphasis">
+/etc/resolv.conf</em> on your Unix servers. Any machine using DNS will have this file, which looks like:</p><PRE CLASS="programlisting">
+#resolv.conf
+domain example.com
+nameserver 127.0.0.1
+nameserver 192.168.236.20</pre><P CLASS="para">
+In the example shown, the second <CODE CLASS="literal">
+nameserver</code> line in the list contains the IP address of another machine on the local network: 192.168.236.20. It's a good candidate for a DNS server.[<A CLASS="footnote" HREF="#ch03-pgfId-942097">1</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch03-pgfId-942097">[1]</a> We can disqualify the other address because every Unix machine has a localhost address of 127.0.0.1 whether it is connected to a network or not. This address is required for some system tools to operate correctly.</p></div></blockquote><P CLASS="para">
+You must type the correct IP address of one or more DNS servers (note that you <EM CLASS="emphasis">
+cannot</em> use its Internet name, such as <EM CLASS="emphasis">
+dns.oreilly.com</em>) into the appropriate field in <A CLASS="xref" HREF="ch03_01.html#ch03-86883">
+Figure 3.10</a>. Be sure not to use 127.0.0.1&nbsp;- that will never be the correct DNS server address!</p><P CLASS="para">
+Try to select addresses on your own network. Any name servers listed in <EM CLASS="emphasis">
+/etc/resolv.conf</em> should work, but you'll get better performance by using a server nearby. (If you don't find <EM CLASS="emphasis">
+/etc/resolv.conf</em> files on your Unix machines, just disable DNS until you can find the address of at least one DNS server.) Let's assume you only have one DNS server, and its address is 192.168.236.20. Click the Enable DNS radio button, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-86883">
+Figure 3.10</a>, and add the server's address to the top DNS Server Search Order field. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-86883">
+Figure 3.10: The DNS Configuration tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0310.gif" ALT="Figure 3.10"><P CLASS="para">
+Also, provide the name of the Windows 95/98 machine and the Internet domain you're in. You can safely ignore the Domain Suffix Search Order field for anything related to Samba.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942117">
+3.1.2.5 WINS Configuration tab</a></h4><P CLASS="para">WINS is the Windows Internet Name Service, its version of a NetBIOS name server. If you've enabled WINS on Samba, you must tell Windows the Samba server's address. If you are using WINS servers that are entirely Windows NT, enter each of them here as well. The dialog box shown after selecting the WINS Configuration tab is shown in <A CLASS="xref" HREF="ch03_01.html#ch03-95608">
+Figure 3.11</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-95608">
+Figure 3.11: The WINS Configuration tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0311.gif" ALT="Figure 3.11"><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Do <EM CLASS="emphasis">
+not</em> mix a Samba WINS server and a Windows NT server as a primary/backup combination in the WINS dialog. Because the two cannot replicate their databases, this will cause name resolution to perform incorrectly.</p></blockquote><P CLASS="para">
+From here, select Enable WINS Resolution and enter the WINS server's address in the space provided, then press Add. Do not enter anything in the Scope ID field.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942134">
+3.1.2.6 Hosts files</a></h4><P CLASS="para">If you do not have either DNS or WINS, and you don't wish to use broadcast resolution, you'll need to provide a table of IP addresses and hostnames, in the standard Unix <I CLASS="filename">
+/etc/hosts</i> format. On a Windows machine, this goes in \WINDOWS\HOSTS under whichever drive you installed Windows on (typically C:\). A sample host file follows:</p><PRE CLASS="programlisting">
+# 127.0.0.1 localhost
+192.168.236.1 escrime.example.com escrime
+192.168.236.2 riposte.example.com riposte
+192.168.236.3 wizzin.example.com wizzin
+192.168.236.4 touche.example.com touche
+192.168.236.10 hobbes.example.com hobbes</pre><P CLASS="para">
+You can copy this file directly from any of your Unix machines' <EM CLASS="emphasis">
+/etc/hosts</em>; the format is identical. However, <EM CLASS="emphasis">
+you should only use hosts files in Windows as a last resort for name resolution</em>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942143">
+3.1.2.7 Check the bindings</a></h4><P CLASS="para">
+The final tab to look at is Bindings, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-42906">
+Figure 3.12</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-42906">
+Figure 3.12: The Bindings tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0312.gif" ALT="Figure 3.12"><P CLASS="para">
+You should have a check beside Client for Microsoft Networks, indicating that it's using TCP/IP. If you have "File and printer sharing for Microsoft Networks" in the dialog, it should also be checked, as shown in the figure. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-48802">
+3.1.3 Setting Your Name and Workgroup </a></h3><P CLASS="para">Finally, press the OK button in the TCP/IP configuration panel, and you'll be taken back to the Network Configuration screen. Then select the Identification tab, which will take you to the dialog box shown in <A CLASS="xref" HREF="ch03_01.html#ch03-42408">
+Figure 3.13</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-42408">
+Figure 3.13: The Identification tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0313.gif" ALT="Figure 3.13"><P CLASS="para">
+Here, for the second time, set your machine's name. This time, instead of your DNS hostname and domain, you're setting your NetBIOS name. However, it is best to make this the <EM CLASS="emphasis">
+same</em> as your hostname. Try not to make a spelling mistake: it can be very confusing to configure a machine if TCP thinks it's <CODE CLASS="literal">
+fred</code> and SMB thinks its <CODE CLASS="literal">
+ferd</code> !</p><P CLASS="para">
+You also set your workgroup name here. In our case, it's SIMPLE, but if you used a different one in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>, when creating the Samba configuration file, use that here as well. Try to avoid calling it WORKGROUP or you'll be in the same workgroup as every unconfigured (or ill-configured) machine in the world. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-13238">
+3.1.4 Accessing the Samba Server</a></h3><P CLASS="para">Click on the OK button to complete the configuration; you will need to reboot in order for your changes to take effect. </p><P CLASS="para">
+Now for the big moment. Your Samba server is running, and you have set up your Windows 95/98 client to communicate with it. After rebooting, log in and double-click the Network Neighborhood icon on the desktop. You should see your Samba server listed as a member of the workgroup, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-88553">
+Figure 3.14</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-88553">
+Figure 3.14: Windows Network Neighborhood</a></h4><IMG CLASS="graphic" SRC="figs/sam.0314.gif" ALT="Figure 3.14"><P CLASS="para">
+Double-clicking the server name will show the resources that the server is offering to the network, as shown in <A CLASS="xref" HREF="ch03_01.html#ch03-17463">
+Figure 3.15</a> (in this case a printer and the <EM CLASS="emphasis">
+test </em>directory). </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-17463">
+Figure 3.15: Shares on Server</a></h4><IMG CLASS="graphic" SRC="figs/sam.0315.gif" ALT="Figure 3.15"><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> If you are presented with a dialog requesting the password for a user <CODE CLASS="literal">
+IPC$</code>, then Samba did not accept the password that was sent from the client. In this case, the username and the password that were created on the client side <EM CLASS="emphasis">
+must</em> match the username/password combination on the Samba server. If you are using Windows 98 or Windows NT Service Pack 3 or above, this is probably because the client is sending encrypted passwords instead of plaintext passwords. You can remedy this situation by performing two steps on the Samba server. First, add the following entry to the <CODE CLASS="literal">
+[global]</code> section of your Samba configuration file: <CODE CLASS="literal">
+encrypt password=yes</code>. Second, find the <I CLASS="filename">
+smbpasswd</i> program on the samba server (it is located in <I CLASS="filename">
+/usr/local/samba/bin</i> by default) and use it to add an entry to Samba's encrypted password database. For example, to add user <CODE CLASS="literal">
+steve</code> to Samba's encrypted password database, type <CODE CLASS="replaceable">
+<I>
+smbpasswd -a steve</i></code>. The first time you enter this password, the program will output an error message indicating that the password database does not exist; it will then create the database, which is typically stored in <I CLASS="filename">
+/usr/local/samba/private/smbpasswd</i>.</p></blockquote><P CLASS="para">
+If you don't see the server listed, start Windows Explorer (not Internet Explorer!) and select Map Network Drive from the Tools menu. This will give you a dialog box into which you can type the name of your server and the share <CODE CLASS="literal">
+test </code>in the Windows UNC format: <I CLASS="filename">\\</i><CODE CLASS="replaceable"><I>server</i></code><I CLASS="filename">\test</i>, like we did in the first chapter. This should attempt to contact the Samba server and its temporary share. If things still aren't right, go to <a href="ch09_01.html"><b>Chapter 9, <CITE CLASS="chapter">Troubleshooting Samba</cite></b></a>, for troubleshooting assistance. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch02_06.html" TITLE="2.6 Testing the Samba Daemons">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 2.6 Testing the Samba Daemons" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_02.html" TITLE="3.2 Setting Up Windows NT 4.0 Computers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3.2 Setting Up Windows NT 4.0 Computers" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+2.6 Testing the Samba Daemons</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+3.2 Setting Up Windows NT 4.0 Computers</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch03_02.html b/docs/htmldocs/using_samba/ch03_02.html
new file mode 100644
index 00000000000..fd87daac726
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch03_02.html
@@ -0,0 +1,260 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 3] 3.2 Setting Up Windows NT 4.0 Computers</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:31:26Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_01.html" TITLE="3.1 Setting Up Windows 95/98 Computers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.1 Setting Up Windows 95/98 Computers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch03_01.html" TITLE="3. Configuring Windows Clients">
+Chapter 3<br>
+Configuring Windows Clients</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_03.html" TITLE="3.3 An Introduction to SMB/CIFS">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3.3 An Introduction to SMB/CIFS" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch03-23093">
+3.2 Setting Up Windows NT 4.0 Computers</a></h2><P CLASS="para">Configuring Windows NT is a little different than configuring Windows 95/98. In order to use Samba with Windows NT, you will need both the Workstation service and the TCP/IP protocol. Both come standard with NT, but we'll work through installing and configuring them because they may not be configured correctly.</p><P CLASS="para">
+There are six basic steps:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942212">
+</a>Assign the machine a name.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942213">
+</a>Install the Workstation service.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942214">
+</a>Install the TCP/IP protocol.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942215">
+</a>Set the machine's name and IP address.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-948102">
+</a>Configure the DNS and WINS name services.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-948103">
+</a>Bind the protocol and service together.</p></li></ol><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-948104">
+3.2.1 Basic Configuration</a></h3><P CLASS="para">This section presents an outline of the steps to follow for getting Windows NT to cooperate with Samba. If you need more details on Windows NT network administration, refer to Craig Hunt and Robert Bruce Thompsom's <CITE CLASS="citetitle">
+Windows NT TCP/IP Network Administration </cite>(O'Reilly), an excellent guide. You should perform these steps as the "Administrator" user.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942220">
+3.2.1.1 Name the machine</a></h4><P CLASS="para">The first thing you need to do is to give the machine a NetBIOS name. From the Control Panel, double click on the Network icon. This will take you to the Network dialog box for the machine. The first tab in this dialog box should be the Identification tab, as illustrated in <A CLASS="xref" HREF="ch03_02.html#ch03-82592">
+Figure 3.16</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-82592">
+Figure 3.16: Network panel Identification tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0316.gif" ALT="Figure 3.16"><P CLASS="para">
+Here, you need to identify your machine with a name (we use the name Artish here) and change the default workgroup to the one you specified in the <EM CLASS="emphasis">
+smb.conf</em> file of your Samba server. In this case, the workgroup name is SIMPLE. However, you cannot edit either name here (as you could in Windows 95/98), but instead must use the Change button below the two text fields. Pressing this button raises an Identification Changes dialog box, where you can reset the workgroup and the machine name, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-67735">
+Figure 3.17</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-67735">
+Figure 3.17: Changing the identification</a></h4><IMG CLASS="graphic" SRC="figs/sam.0317.gif" ALT="Figure 3.17"><P CLASS="para">A word of warning: you will have to set the machine name again later while configuring TCP/IP, so be sure that the two names match. The name you set here is the NetBIOS name. You're allowed to make it different from the TCP/IP hostname, but doing so is usually not a good thing. Don't worry that Windows NT forces the computer name and the workgroup to be all capital letters; it's smart enough to figure out what you mean when it connects to the network.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942248">
+3.2.1.2 Installing the TCP/IP protocol</a></h4><P CLASS="para">Next, select the Protocols tab in the Network dialog box, and look to see if you have the TCP/IP protocol installed, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-66055">
+Figure 3.18</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-66055">
+Figure 3.18: The Protocols tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0318.gif" ALT="Figure 3.18"><P CLASS="para">
+If the protocol is not installed, you need to add it. Press the Add button, which will display the Select Network Protocol dialog box shown in <A CLASS="xref" HREF="ch03_02.html#ch03-22321">
+Figure 3.19</a>. Unlike Windows 95/98, you should immediately see the TCP/IP protocol as one of the last protocols listed. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-22321">
+Figure 3.19: Select Network Protocol dialog box</a></h4><IMG CLASS="graphic" SRC="figs/sam.0319.gif" ALT="Figure 3.19"><P CLASS="para">
+Select TCP/IP<EM CLASS="emphasis">
+ </em>as the protocol and confirm it. If possible, install only the TCP/IP protocol. You usually do not want NetBEUI installed because this causes the machine to look for services under two different protocols, only one of which is likely in use.[<A CLASS="footnote" HREF="#ch03-pgfId-943371">2</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch03-pgfId-943371">[2]</a> A common occurrence: after looking at the unused protocol for a while, the machine will time out and try the good one. This fruitless searching gives you terrible performance and mysterious delays.</p></div></blockquote></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942278">
+3.2.1.3 Installing the Workstation service</a></h4><P CLASS="para">After installing TCP/IP, press the Services tab in the Network panel and check that you have a Workstation service, as shown at the end of the list in <A CLASS="xref" HREF="ch03_02.html#ch03-97222">
+Figure 3.20</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-97222">
+Figure 3.20: Network Services panel dialog box</a></h4><IMG CLASS="graphic" SRC="figs/sam.0320.gif" ALT="Figure 3.20"><P CLASS="para">
+This service is actually the Microsoft Networking Client, which allows the machine to access SMB services. The Workstation service is mandatory. The service is installed by default on both Windows NT Workstation 4.0 and Server 4.0. If it's not there, you can install it much like TCP/IP. In this case you need to press the Add button and then select Workstation Service, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-40000">
+Figure 3.21</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-40000">
+Figure 3.21: Select Network Service dialog box </a></h4><IMG CLASS="graphic" SRC="figs/sam.0321.gif" ALT="Figure 3.21"></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-85837">
+3.2.2 Configuring TCP/IP</a></h3><P CLASS="para">After you've installed the Workstation service, return to the Protocols tab and select the TCP/IP Protocol entry in the window. Then click the Properties button below the window. The Microsoft TCP/IP Protocol panel will be displayed. There are five tabs on the Windows NT panel, and (like Windows 95/98) you will need to work on three of them: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942313">
+</a>IP address</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942314">
+</a>DNS</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942315">
+</a>WINS address</p></li></ul><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942317">
+3.2.2.1 IP Address tab</a></h4><P CLASS="para">The IP Address tab is shown in <A CLASS="xref" HREF="ch03_02.html#ch03-97098">
+Figure 3.22</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-97098">
+Figure 3.22: Microsoft TCP/IP Properties for Windows NT</a></h4><IMG CLASS="graphic" SRC="figs/sam.0322.gif" ALT="Figure 3.22"><P CLASS="para">Select the "Specify an IP address" radio button and enter the computer's address and subnet mask in the space provided for the proper adapter (Ethernet card). You or your network manager should have selected an address for the client on the same subnet (LAN) as the Samba server. For example, if the server's address is 192.168.236.86 and its network mask 255.255.255.0, you might use the address 192.168.236.10, if it is available, for the NT workstation, along with the same netmask. If you use DHCP on your network, select the "Obtain an IP Address from a DHCP server" button.</p><P CLASS="para">
+If you don't have an IP address to use, and you are on a network by yourself, steal ours, as the 192.168.<EM CLASS="emphasis">
+x.x</em> subnet is specifically reserved by the Internic for LANs. If you're not by yourself, see your system administrator for some available addresses on your network.</p><P CLASS="para">
+The gateway field refers to a machine typically known as a <EM CLASS="emphasis">
+router</em>. If you have routers connecting multiple networks, you should put in the IP address of the one on your subnet.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942339">
+3.2.2.2 DNS tab</a></h4><P CLASS="para">Next we go to the tab for DNS, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-61878">
+Figure 3.23</a>. This brings up the DNS panel. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-61878">
+Figure 3.23: The DNS panel</a></h4><IMG CLASS="graphic" SRC="figs/sam.0323.gif" ALT="Figure 3.23"><P CLASS="para">
+The Domain Name System (DNS) is responsible for translating human-readable computer names such as <EM CLASS="emphasis">
+atrish.example.com</em> into IP addresses such as 192.168.236.10. There are two ways to accomplish this on a NT machine. First, you can specify a DNS server to do the translation for you, or you can keep a local list of name/address pairs for your workstation to refer to.</p><P CLASS="para">
+For a LAN that's not on the Internet, the list of possible hosts is typically small and well known, and may be kept in a file locally. Networks that are connected to the Internet typically use DNS service since it isn't possible to guess ahead of time what addresses you might be accessing out on the net. If you are in doubt as to whether a DNS server is being used, or what its address might be, look at the file <EM CLASS="emphasis">
+/etc/resolv.conf</em> on your Samba server: any machine using DNS will have this file. It looks like the following:</p><PRE CLASS="programlisting">
+#resolv.conf
+domain example.com
+nameserver 127.0.0.1
+nameserver 192.168.236.20</pre><P CLASS="para">
+In this example, the first nameserver in the list is 127.0.0.1, which indicates that the Samba server is also a DNS server for this LAN.[<A CLASS="footnote" HREF="#ch03-pgfId-946587">3</a>] In that case, you would use its network IP address (not 127.0.0.1, its localhost address) when filling in the DNS Configuration dialog box. Otherwise, use the other addresses you find in the lines beginning with <CODE CLASS="literal">
+nameserver</code>. Try to select ones on your own network. Any name servers listed in <EM CLASS="emphasis">
+/etc/resolv.conf</em> should work, but you'll get better performance by using a server nearby.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch03-pgfId-946587">[3]</a> The address 127.0.0.1 is known as the <EM CLASS="emphasis">
+localhost</em> address, and always refers to itself. For example, if you type <CODE CLASS="literal">
+ping 127.0.0.1</code> on a Unix server, you should always get a response, as you're pinging the host itself.</p></div></blockquote><P CLASS="para">
+Finally, enter the machine name once more, making sure that it's the same one listed in the Identification tab of the Network dialog box (before the NetBIOS name). Also, enter the DNS domain on which this machine resides. For example, if your workstation has a domain name such as <EM CLASS="emphasis">
+example.com</em>, enter it here. You can safely ignore the other options.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942365">
+3.2.2.3 WINS Address tab</a></h4><P CLASS="para">If you are not using a DNS server, you still need a way of translating NetBIOS names to addresses and back again. We recommend that you configure both DNS and WINS; NT has a preference for WINS and WINS can use DNS as a fallback if it cannot resolve any machine address. The WINS Address tab is shown in <A CLASS="xref" HREF="ch03_02.html#ch03-20855">
+Figure 3.24</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-20855">
+Figure 3.24: The WINS Address tab</a></h4><IMG CLASS="graphic" SRC="figs/sam.0324.gif" ALT="Figure 3.24"><P CLASS="para">
+If you have a WINS server, enter its address in the space marked Primary WINS Server. If your Samba server is providing WINS service (in other words, you have the line <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+service</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in the <EM CLASS="emphasis">
+smb.conf</em> file of your Samba server), provide the Samba server's IP address here. Otherwise, provide the address of another WINS server on your network.</p><P CLASS="para">
+You probably noticed that there is a field here for the adaptor; this field must specify the Ethernet adaptor that you're running TCP/IP on so that WINS will provide name service on the correct network. If you have both a LAN and a dialup adaptor, make sure you have the LAN's adaptor here.</p><P CLASS="para">
+Finally, select the "Enable DNS for Windows Resolution" checkbox, so WINS will try DNS as a fallback if it can't find a name. You can safely ignore the other options.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942383">
+3.2.2.4 Hosts files</a></h4><P CLASS="para">If you don't have either DNS or WINS, and you don't wish to use broadcast name resolution, you'll need to provide a table of IP addresses and hosts names, in standard Unix <I CLASS="filename">
+/etc/hosts</i> format. We recommend against this because maintenance of this file on any dynamic network is troublesome, but we will explain it just the same. The Windows host file should appear in the <EM CLASS="emphasis">
+\WINDOWS\HOSTS</em> directory of whatever local drive Windows is installed on. A sample follows:</p><PRE CLASS="programlisting">
+127.0.0.1 localhost
+192.168.236.1 escrime escrime.example.com
+192.168.236.2 riposte riposte.example.com
+192.168.236.3 wizzin wizzin.example.com
+192.168.236.4 touche touche.example.com
+192.168.236.5 gurgi gurgi.example.com
+192.168.236.6 jessiac jessiac.example.com
+192.168.236.7 skyline skyline.example.com </pre><P CLASS="para">
+If you wish, you can copy the contents directly from the Samba server's<I CLASS="filename">
+ /etc/hosts</i>. The format is identical. This file will then serve the same purpose as the hosts file on the Unix server. Again, <EM CLASS="emphasis">
+hosts</em> files on Windows should only be used as a last resort.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942394">
+3.2.2.5 Bindings</a></h4><P CLASS="para">
+The term <I CLASS="firstterm">
+bindings</i> is a way of saying "connected together at configuration time." It means that the TCP/IP protocol will channel through the Ethernet card (instead of, say, a dialup connection), and is actually connected properly. If you return to the Network dialog box and set the Show field to "all services" and click on all the + buttons in the tree, you should see a display similar to <A CLASS="xref" HREF="ch03_02.html#ch03-83060">
+Figure 3.25</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-83060">
+Figure 3.25: Service bindings</a></h4><IMG CLASS="graphic" SRC="figs/sam.0325.gif" ALT="Figure 3.25"><P CLASS="para">
+This means that the Workstation, Server, and NetBIOS interface services are connected to the WINS client. This is the correct binding for Microsoft TCP/IP. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942410">
+3.2.3 Connecting to the Samba Server</a></h3><P CLASS="para">You can safely leave the default values for the remainder of the tabs in the Network dialog box. Click on the OK button to complete the configuration. Once the proper files are loaded (if any), you will need to reboot in order for your changes to take effect.</p><P CLASS="para">
+Now for the big moment. Your Samba server is running and you have set up your NT client to communicate with it. After the machine reboots, login and double-click the Network Neighborhood icon on the desktop, and you should see your Samba server listed as a member of the workgroup, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-50785">
+Figure 3.26</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-50785">
+Figure 3.26: Windows NT Network Neighborhood</a></h4><IMG CLASS="graphic" SRC="figs/sam.0326.gif" ALT="Figure 3.26"><P CLASS="para">Double-clicking the server name will show the resources that the server is offering to the network, as shown in <A CLASS="xref" HREF="ch03_02.html#ch03-89532">
+Figure 3.27</a>. In this case, the test and the default printer are offered to the Window NT workstation. For more information, see the warning under the "Accessing the Samba Server" section, earlier in this chapter. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-89532">
+Figure 3.27: Server's shares</a></h4><IMG CLASS="graphic" SRC="figs/sam.0327.gif" ALT="Figure 3.27"><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> If you are presented with a dialog requesting the password for a user <CODE CLASS="literal">
+IPC$</code>, then Samba did not accept the password that was sent from the client. In this case, the username and the password that were created on the client side <EM CLASS="emphasis">
+must</em> match the username/password combination on the Samba server. If you are using Windows 98 or Windows NT Service Pack 3 or above, this is probably because the client is sending encrypted passwords instead of plaintext passwords. You can remedy this situation by performing two steps on the Samba server. First, add the following entry to the <CODE CLASS="literal">
+[global]</code> section of your Samba configuration file: <CODE CLASS="literal">
+encrypt password=yes</code>. Second, find the <I CLASS="filename">
+smbpasswd</i> program on the samba server (it is located in <I CLASS="filename">
+/usr/local/samba/bin</i> by default) and use it to add an entry to Samba's encrypted password database. For example, to add user <CODE CLASS="literal">
+steve</code> to Samba's encrypted password database, type <CODE CLASS="replaceable">
+<I>
+smbpasswd -a steve</i></code>. The first time you enter this password, the program will output an error message indicating that the password database does not exist; it will then create the database, which is typically stored in <I CLASS="filename">
+/usr/local/samba/private/smbpasswd</i>.</p></blockquote><P CLASS="para">
+If you don't see the server listed, don't panic. Start the Windows NT Explorer (not Internet Explorer!) and select Map Network Drive from the Tools menu. A dialog box appears that allows you to type the name of your server and its share directory in Windows format. For example, you would enter <I CLASS="filename">
+\\</i><CODE CLASS="replaceable"><I>server</i></code><I CLASS="filename">\temp</i> if your server happened to be named "server." If things still aren't right, go directly to the section "The Fault Tree" in <a href="ch09_01.html"><b>Chapter 9</b></a>, to see if you can troubleshoot what is wrong with the network.</p><P CLASS="para">
+If it works, congratulations! Try writing to the server and sending data to the network printer. You will be pleasantly surprised how seamlessly everything works! Now that you've finished setting up the Samba server and its clients, we can starting talking about how Samba works and how to configure it to your liking. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_01.html" TITLE="3.1 Setting Up Windows 95/98 Computers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.1 Setting Up Windows 95/98 Computers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_03.html" TITLE="3.3 An Introduction to SMB/CIFS">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 3.3 An Introduction to SMB/CIFS" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+3.1 Setting Up Windows 95/98 Computers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+3.3 An Introduction to SMB/CIFS</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch03_03.html b/docs/htmldocs/using_samba/ch03_03.html
new file mode 100644
index 00000000000..d3efd007aa6
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch03_03.html
@@ -0,0 +1,579 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 3] 3.3 An Introduction to SMB/CIFS</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:31:30Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_02.html" TITLE="3.2 Setting Up Windows NT 4.0 Computers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.2 Setting Up Windows NT 4.0 Computers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch03_01.html" TITLE="3. Configuring Windows Clients">
+Chapter 3<br>
+Configuring Windows Clients</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4. Disk Shares " BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch03-64069">
+3.3 An Introduction to SMB/CIFS</a></h2><P CLASS="para">We'll wrap up this chapter with a short tutorial on SMB/CIFS. SMB/CIFS is the protocol that Windows 95/98 and NT machines use to communicate with the Samba server and each other. At a high level, the SMB protocol suite is relatively simple. It includes commands for all of the file and print operations that you might do on a local disk or printer, such as:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942445">
+</a> Opening and closing a file</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942446">
+</a> Creating and deleting files and directories</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942447">
+</a> Reading and writing a file</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942853">
+</a> Searching for files</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942448">
+</a> Queueing and dequeueing files to a print spool</p></li></ul><P CLASS="para">
+Each of these operations can be encoded into an SMB message and transmitted to and from a server. The original name SMB comes from their data format: these are versions of the standard DOS system-call data structures, or <I CLASS="firstterm">
+Server Message Blocks</i>, redesigned for transmitting to another machine across a network.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942451">
+3.3.1 SMB Format</a></h3><P CLASS="para">Richard Sharpe of the Samba team defines SMB as a "request-response" protocol.[<A CLASS="footnote" HREF="#ch03-pgfId-942928">4</a>] In effect, this means that a client sends an SMB request to a server, and the server sends an SMB response back to the client. Rarely does a server send a message that is not in response to a client.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch03-pgfId-942928">[4]</a> See <I CLASS="filename">
+<a href="http://anu.samba.org/cifs/docs/what-is-smb.html">http://anu.samba.org/cifs/docs/what-is-smb.html</i></a> for Richard's excellent summary of SMB.</p></div></blockquote><P CLASS="para">
+An SMB message is not as complex as you might think. Let's take a closer look at the internal structure of such a message. It can be broken down into two parts: the <I CLASS="firstterm">
+header</i>, which is a fixed size, and the <I CLASS="firstterm">
+command string</i>, whose size can vary dramatically based on the contents of the message.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942453">
+3.3.1.1 SMB header format</a></h4><P CLASS="para">
+<A CLASS="xref" HREF="ch03_03.html#ch03-31015">
+Table 3.1</a> shows the format of an SMB header. SMB commands are not required to use all the fields in the SMB header. For example, when a client first attempts to connect to a server, it does not yet have a tree identifier (TID) value&nbsp;- one is assigned after it successfully connects&nbsp;- so a null TID (0xFFFF) is placed in its header field. Other fields may be padded with zeros when not used. </p><P CLASS="para">
+The fields of the SMB header are listed in <A CLASS="xref" HREF="ch03_03.html#ch03-31015">
+Table 3.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch03-31015">
+Table 3.1: SMB Header Fields </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Field</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Size (bytes)</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0xFF 'SMB'</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Protocol identifier</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+COM</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Command code, from 0x00 to 0xFF</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+RCLS</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Error class</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+REH</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Reserved</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ERR</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Error code</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+REB</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Reserved</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+RES</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+14</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Reserved</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+TID</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Tree identifier; a unique ID for a resource in use by client</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+PID</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Caller process ID</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+UID</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+User identifier</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+MID</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Multiplex identifier; used to route requests inside a process</p></td></tr></tbody></table></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942527">
+3.3.1.2 SMB command format</a></h4><P CLASS="para">
+<I CLASS="firstterm">
+</i>Immediately after the header is a variable number of bytes that constitute an SMB command or reply. Each command, such as Open File (COM field identifier: <CODE CLASS="literal">SMBopen</code>) or Get Print Queue (<CODE CLASS="literal">SMBsplretq</code>), has its own set of parameters and data. Like the SMB header fields, not all of the command fields need to be filled, depending on the specific command. For example, the Get Server Attributes (<CODE CLASS="literal">SMBdskattr</code>) command sets the WCT and BCC fields to zero. The fields of the command segment are shown in <A CLASS="xref" HREF="ch03_03.html#ch03-38178">
+Table 3.2</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch03-38178">
+Table 3.2: SMB Command Contents </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Field</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Size in Bytes</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+WCT</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<I CLASS="firstterm">
+</i>Word count</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+VWV</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameter words (size given by WCT)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+BCC</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameter byte count</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DATA</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Data (size given by BCC)</p></td></tr></tbody></table><P CLASS="para">
+Don't worry if you don't understand each of these fields; they are not necessary for using Samba at an administrator level. However, they do come in handy when debugging system messages. We will show you some of the more common SMB messages that clients and servers send using a modified version of <I CLASS="filename">
+tcpdump</i> later in this section. (If you would like an SMB sniffer with a graphical interface, try "ethereal," which uses the GTK libraries; see the Samba homepage for more information on this tool.)</p><P CLASS="para">
+If you would like more information on each of the commands for the SMB protocol, see the SMB/CIFS documentation at <a href="ftp://ftp.microsoft.com/developr/drg/CIFS/"><I CLASS="filename">ftp://ftp.microsoft.com/developr/drg/CIFS/</i></a>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942573">
+3.3.1.3 SMB variations</a></h4><P CLASS="para">
+The SMB protocol has been extended with new commands several times since its inception. Each new version is backwards compatible with the previous versions. This makes it quite possible for a LAN to have various clients and servers running different versions of the SMB protocol at once.</p><P CLASS="para">
+<A CLASS="xref" HREF="ch03_03.html#ch03-67366">
+Table 3.3</a> outlines the major versions of the SMB protocol. Within each "dialect" of SMB are many sub-versions that include commands supporting particular releases of major operating systems. The ID string is used by clients and servers to determine what level of the protocol they will speak to each other. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch03-67366">
+Table 3.3: SMB Protocol Dialects </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Protocol Name</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+ID String</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Used By</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Core</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+PC NETWORK PROGRAM 1.0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Core Plus </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+MICROSOFT NETWORKS 1.03 </code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+LAN Manager 1.0 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LANMAN1.0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+LAN Manager 2.0 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LM1.2X002</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+LAN Manager 2.1 </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LANMAN2.1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+NT LAN Manager 1.0</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+NT LM 0.12</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT 4.0</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba's NT LM 0.12</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+Samba</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Common Internet File System</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+CIFS 1.0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 2000</p></td></tr></tbody></table><P CLASS="para">
+Samba implements the <CODE CLASS="literal">
+NT</code> <CODE CLASS="literal">
+LM</code> <CODE CLASS="literal">
+0.12</code> specification for NT LAN Manager 1.0. It is backwards compatible with all of the other SMB variants. The CIFS specification is, in reality, LAN Manager 0.12 with a few specific additions.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942627">
+3.3.2 SMB Clients and Servers</a></h3><P CLASS="para">
+As mentioned earlier, SMB is a client/server protocol. In the purest sense, this means that a client sends a request to a server, which acts on the request and returns a reply. However, the client/server roles can often be reversed, sometimes within the context of a single SMB session. For example, consider the two Windows 95/98 computers in <A CLASS="xref" HREF="ch03_03.html#ch03-69480">
+Figure 3.28</a>. The computer named WIZZIN shares a printer to the network, and the computer named ESCRIME shares a disk directory. WIZZIN is in the client role when accessing ESCRIME's network drive, and in the server role when printing a job for ESCRIME. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch03-69480">
+Figure 3.28: Two computers that both have resources to share</a></h4><IMG CLASS="graphic" SRC="figs/sam.0328.gif" ALT="Figure 3.28"><P CLASS="para">
+This brings out an important point in Samba terminology:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-server-defined-in-Samba-terminology">
+</a>A <I CLASS="firstterm">
+server</i> is a machine with a resource to share.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-client-defined-in-Samba-terminology">
+</a>A <I CLASS="firstterm">
+client</i> is a machine that wishes to use that resource.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-943256">
+</a>A server can be a client (of another computer's resource) at any given time.</p></li></ul><P CLASS="para">
+Note that there are no implications as to the amount of resources that make up a server, or whether it has a large disk space or fast processor. A server could be an old 486 with a printer attached to it, or it could be an UltraSparc station with a 10 gigabyte disk service.</p><P CLASS="para">
+Microsoft Windows products have both the SMB client and server built in to the operating system. Wndows NT 4.0 uses a newer SMB protocol than Windows for Workgroups, and it offers an enhanced form of network security which will be discussed in <a href="ch06_01.html"><b>Chapter 6</b></a>. In addition, there are a large number of commercial SMB server products available from companies such as Sun, Compaq, SCO, Hewlett-Packard, Syntax, and IBM. Unfortunately, on the client side there are far fewer offerings, limited mainly to Digital Equipment's Pathworks product, and of course, Samba.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942638">
+3.3.3 A Simple SMB Connection</a></h3><P CLASS="para">Before we close this chapter, let's take a look at a simple SMB connection. This is some pretty technical data&nbsp;- which isn't really necessary to administer Samba&nbsp;- so you can skip over it if you like. We present this information largely as a way to help you get familiar with how the SMB protocol negotiates connections with other computers on the network. </p><P CLASS="para">
+There are four steps that the client and server must complete in order to establish a connection to a resource:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942687">
+</a> Establish a virtual connection.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942688">
+</a> Negotiate the protocol variant to speak.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942689">
+</a> Set session parameters.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942690">
+</a> Make a tree connection to a resource.</p></li></ol><P CLASS="para">
+We will examine each of these steps through the eyes of a useful tool that we mentioned earlier: the modified <I CLASS="filename">
+tcpdump</i> that is available from the Samba web site.</p><P CLASS="para">
+You can download this program at <I CLASS="filename">
+samba.org</i> in the <I CLASS="filename">
+samba/ftp/tcpdump-smb</i> directory; the latest version as of this writing is 3.4-5. Use this program as you would use the standard <I CLASS="filename">
+tcpdump</i> application, but add the <CODE CLASS="literal">
+-s 1500</code> switch to ensure that you get the whole packet and not just the first few bytes.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch03-pgfId-942691">
+3.3.3.1 Establishing a virtual connection</a></h4><P CLASS="para">When a user first makes a request to access a network disk or send a print job to a remote printer, NetBIOS takes care of making a connection at the session layer. The result is a bidirectional virtual channel between the client and server. In reality, there are only two messages that the client and server need to establish this connection. This is shown in the following example session request and response, as captured by <I CLASS="filename">
+tcpdump</i> :</p><PRE CLASS="programlisting">
+&gt;&gt;&gt; NBT Packet
+NBT Session Request
+Flags=0x81000044
+Destination=ESCRIME NameType=0x20 (Server)
+Source=WIZZIN NameType=0x00 (Workstation)
+
+&gt;&gt;&gt; NBT Packet
+NBT Session Granted
+Flags=0x82000000</pre></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942713">
+3.3.4 Negotiating the Protocol Variant</a></h3><P CLASS="para">At this point, there is an open channel between the client and server. Next, the client sends a message to the server to negotiate an SMB protocol. As mentioned earlier, the client sets its tree identifier (TID) field to zero, since it does not yet know what TID to use. A <EM CLASS="emphasis">
+tree identifier</em> is a number that represents a connection to a share on a server.</p><P CLASS="para">
+The command in the message is <CODE CLASS="literal">
+SMBnegprot</code>, a request to negotiate a protocol variant that will be used for the entire session. Note that the client sends to the server a list of all of the variants that it can speak, not vice versa.</p><P CLASS="para">
+The server responds to the <CODE CLASS="literal">
+SMBnegprot</code> request with an index into the list of variants that the client offered, starting with index 0, or with the value 0xFF if none of the protocol variants are acceptable. Continuing this example, the server responds with the value 5, which indicates that the <CODE CLASS="literal">
+NT</code> <CODE CLASS="literal">
+LM</code> <CODE CLASS="literal">
+0.12</code> dialect will be used for the remainder of the session:</p><PRE CLASS="programlisting">
+&gt;&gt;&gt; NBT Packet
+NBT Session Packet
+Flags=0x0
+Length=154
+
+SMB PACKET: SMBnegprot (REQUEST)
+SMB Command = 0x72
+Error class = 0x0
+Error code = 0
+Flags1 = 0x0
+Flags2 = 0x0
+Tree ID = 0
+Proc ID = 5371
+UID = 0
+MID = 385
+Word Count = 0
+Dialect=PC NETWORK PROGRAM 1.0
+Dialect=MICROSOFT NETWORKS 3.0
+Dialect=DOS LM1.2X002
+Dialect=DOS LANMAN2.1
+Dialect=Windows for Workgroups 3.1a
+Dialect=NT LM 0.12
+
+&gt;&gt;&gt; NBT Packet
+NBT Session Packet
+Flags=0x0
+Length=69
+
+SMB PACKET: SMBnegprot (REPLY)
+SMB Command = 0x72
+Error class = 0x0
+Error code = 0
+Flags1 = 0x0
+Flags2 = 0x1
+Tree ID = 0
+Proc ID = 5371
+UID = 0
+MID = 385
+Word Count = 02
+[000] 05 00</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942762">
+3.3.5 Set Session and Login Parameters</a></h3><P CLASS="para">The next step is to transmit session and login parameters for the session. This includes the account name and password (if there is one), the workgroup name, the maximum size of data that can be transferred, and the number of pending requests that may be in the queue at any one time.</p><P CLASS="para">
+In the following example, the Session Setup command presented allows for an additional SMB command to be piggybacked onto it. The letter X at the end of the command name indicates this, and the hexadecimal code of the second command is given in the <CODE CLASS="literal">
+Com2</code> field. In this case the command is <CODE CLASS="literal">
+0x75</code>, which is the Tree Connect and X command. The <CODE CLASS="literal">
+SMBtconX</code> message looks for the name of the resource in the <KBD CLASS="command">
+smb_buf</kbd> buffer. (This is the last field listed in the following request.) In this example, <KBD CLASS="command">
+smb_buf</kbd> contains the string <CODE CLASS="literal">
+\\ESCRIME\PUBLIC</code>, which is the full pathname to a shared directory on node ESCRIME. Using the "and X" commands like this speeds up each transaction, since the server doesn't have to wait on the client to make a second request.</p><P CLASS="para">
+Note that the TID is still zero. The server will provide a TID to the client once the session has been established and a connection has been made to the requested resource. In addition, note that the password is sent in the open. We can change this later using encrypted passwords:</p><PRE CLASS="programlisting">
+&gt;&gt;&gt; NBT Packet
+NBT Session Packet
+Flags=0x0
+Length=139
+
+SMB PACKET: SMBsesssetupX (REQUEST)
+SMB Command = 0x73
+Error class = 0x0
+Error code = 0
+Flags1 = 0x10
+Flags2 = 0x0
+Tree ID = 0
+Proc ID = 5371
+UID = 1
+MID = 385
+Word Count = 13
+Com2=0x75
+Res1=0x0
+Off2=106
+MaxBuffer=2920
+MaxMpx=2
+VcNumber=0
+SessionKey=0x1FF2
+CaseInsensitivePasswordLength=1
+CaseSensitivePasswordLength=1
+Res=0x0
+Capabilities=0x1
+Pass1&amp;Pass2&amp;Account&amp;Domain&amp;OS&amp;LanMan=
+ KRISTIN PARKSTR Windows 4.0 Windows 4.0
+PassLen=2
+Passwd&amp;Path&amp;Device=
+smb_bcc=22
+smb_buf[]=\\ESCRIME\PUBLIC</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch03-pgfId-942801">
+3.3.6 Making Connection to a Resource</a></h3><P CLASS="para">For the final step, the server returns a TID to the client, indicating that the user has been authorized access and that the resource is ready to be used. It also sets the <KBD CLASS="command">
+ServiceType</kbd> field to "A" to indicate that this is a file service. Available service types are:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942803">
+</a> "A" for a disk or file</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942804">
+</a> "LPT1" for a spooled output</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942805">
+</a> "COMM" for a direct-connect printer or modem</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch03-pgfId-942806">
+</a> "IPC" for a named pipe</p></li></ul><P CLASS="para">
+The output is:</p><PRE CLASS="programlisting">
+&gt;&gt;&gt; NBT Packet
+NBT Session Packet
+Flags=0x0
+Length=78
+
+SMB PACKET: SMBsesssetupX (REPLY)
+SMB Command = 0x73
+Error class = 0x0
+Error code = 0
+Flags1 = 0x80
+Flags2 = 0x1
+Tree ID = 121
+Proc ID = 5371
+UID = 1
+MID = 385
+Word Count = 3
+Com2=0x75
+Off2=68
+Action=0x1
+[000] Unix Samba 1.9.1
+[010] PARKSTR
+
+SMB PACKET: SMBtconX (REPLY) (CHAINED)
+smbvwv[]=
+Com2=0xFF
+Off2=78
+smbbuf[]=
+ServiceType=A:</pre><P CLASS="para">
+Now that a TID has been assigned, the client may issue any sort of command that it would use on a local disk drive. It can open files, read and write to them, delete them, create new files, search for filenames, and so on. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_02.html" TITLE="3.2 Setting Up Windows NT 4.0 Computers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.2 Setting Up Windows NT 4.0 Computers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4. Disk Shares " BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+3.2 Setting Up Windows NT 4.0 Computers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4. Disk Shares </td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_01.html b/docs/htmldocs/using_samba/ch04_01.html
new file mode 100644
index 00000000000..1cc3494d290
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_01.html
@@ -0,0 +1,415 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] Disk Shares </title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:31:52Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_03.html" TITLE="3.3 An Introduction to SMB/CIFS">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.3 An Introduction to SMB/CIFS" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 4</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_02.html" TITLE="4.2 Special Sections">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.2 Special Sections" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch04-21486">
+4. Disk Shares </a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch04-76968" TITLE="4.1 Learning the Samba Configuration File">
+Learning the Samba Configuration File</a><br>
+<A CLASS="sect1" HREF="ch04_02.html" TITLE="4.2 Special Sections">
+Special Sections</a><br>
+<A CLASS="sect1" HREF="ch04_03.html" TITLE="4.3 Configuration File Options">
+Configuration File Options</a><br>
+<A CLASS="sect1" HREF="ch04_04.html" TITLE="4.4 Server Configuration">
+Server Configuration</a><br>
+<A CLASS="sect1" HREF="ch04_05.html" TITLE="4.5 Disk Share Configuration">
+Disk Share Configuration</a><br>
+<A CLASS="sect1" HREF="ch04_06.html" TITLE="4.6 Networking Options with Samba">
+Networking Options with Samba</a><br>
+<A CLASS="sect1" HREF="ch04_07.html" TITLE="4.7 Virtual Servers">
+Virtual Servers</a><br>
+<A CLASS="sect1" HREF="ch04_08.html" TITLE="4.8 Logging Configuration Options">
+Logging Configuration Options</a></p><P>
+</p></div><P CLASS="para">In the previous three chapters, we showed you how to install Samba on a Unix server and set up Windows clients to use a simple disk share. This chapter will show you how Samba can assume more productive roles on your network.</p><P CLASS="para">
+Samba's daemons, <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em>, are controlled through a single ASCII file, <I CLASS="filename">
+smb.conf</i>, that can contain over 200 unique options. These options define how Samba reacts to the network around it, including everything from simple permissions to encrypted connections and NT domains. The next five chapters are designed to help you get familiar with this file and its options. Some of these options you will use and change frequently; others you may never use&nbsp;- it all depends on how much functionality you want Samba to offer its clients.</p><P CLASS="para">
+This chapter introduces the structure of the Samba configuration file and shows you how to use these options to create and modify disk shares. Subsequent chapters will discuss browsing, how to configure users, security, domains, and printers, and a host of other myriad topics that you can implement with Samba on your network.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch04-76968">
+4.1 Learning the Samba Configuration File</a></h2><P CLASS="para">
+<I CLASS="filename">
+</i>Here is an <I CLASS="filename">
+</i>example of a Samba configuration file. If you have worked with a Windows .INI file, the structure of the <I CLASS="filename">
+smb.conf </i> file should look very familiar: </p><PRE CLASS="programlisting">
+[global]
+ log level = 1
+ max log size = 1000
+ socket options = TCP_NODELAY IPTOS_LOWDELAY
+ guest ok = no
+[homes]
+ browseable = no
+ map archive = yes
+[printers]
+ path = /usr/tmp
+ guest ok = yes
+ printable = yes
+ min print space = 2000
+[test]
+ browseable = yes
+ read only = yes
+ guest ok = yes
+ path = /export/samba/test</pre><P CLASS="para">
+Although you may not understand the contents yet, this is a good configuration file to grab if you're in a hurry. (If you're not, we'll create a new one from scratch shortly.) In a nutshell, this configuration file sets up basic debug logging in a default log file not to exceed 1MB, optimizes TCP/IP socket connections between the Samba server and any SMB clients, and allows Samba to create a disk share for each user that has a standard Unix account on the server. In addition, each of the printers registered on the server will be publicly available, as will a single read-only share that maps to the <I CLASS="filename">
+/export/samba/test</i> directory. The last part of this file is similar to the disk share you used to test Samba in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-52415">
+4.1.1 Configuration File Structure</a></h3><P CLASS="para">
+<I CLASS="filename">
+</i>Let's take another look at this configuration file, this time from a higher level:</p><PRE CLASS="programlisting">
+[global]
+ ...
+[homes]
+ ...
+[printers]
+ ...
+[test]
+ ...</pre><P CLASS="para">
+The names inside the square brackets delineate unique sections of the <I CLASS="filename">
+smb.conf</i> file; each section names the <I CLASS="firstterm">
+share</i> (or service) that the section refers to. For example, the <CODE CLASS="literal">
+[test]</code> and <CODE CLASS="literal">
+[homes]</code> sections are each unique disk shares; they contain options that map to specific directories on the Samba server. The <CODE CLASS="literal">
+[printers]</code> share contains options that map to various printers on the server. All the sections defined in the <I CLASS="filename">
+smb.conf</i> file, with the exception of the <CODE CLASS="literal">
+[global]</code> section, will be available as a disk or printer share to clients connecting to the Samba server.</p><P CLASS="para">
+The remaining lines are individual configuration options unique to that share. These options will continue until a new bracketed section is encountered, or until the end of the file is reached. Each configuration option follows a simple format:</p><PRE CLASS="programlisting"><CODE CLASS="replaceable"><I>option</i></code> = <CODE CLASS="replaceable"><I>value</i></code></pre><P CLASS="para">
+Options in the <I CLASS="filename">
+smb.conf</i> file are set by assigning a value to them. We should warn you up front that some of the option names in Samba are poorly chosen. For example, <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+only</code> is self-explanatory, and is typical of many recent Samba options. <CODE CLASS="literal">
+public</code> is an older option, and is vague; it now has a less-confusing synonym <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> (may be accessed by guests). We describe some of the more common historical names in this chapter in sections that highlight each major task. In addition, <a href="appc_01.html"><b>Appendix C, <CITE CLASS="appendix">Samba Configuration Option Quick Reference</cite></b></a>, contains an alphabetical index of all the configuration options and their meanings.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955562">
+4.1.1.1 Whitespaces, quotes, and commas</a></h4><P CLASS="para">
+An important item to remember about configuration options is that all whitespaces in the <CODE CLASS="replaceable">
+<I>
+value</i></code> are significant. For example, consider the following option:</p><PRE CLASS="programlisting">
+volume = The Big Bad Hard Drive Number 3543</pre><P CLASS="para">
+Samba strips away the spaces between the final <CODE CLASS="literal">
+e</code> in <CODE CLASS="literal">
+volume</code> and the first <CODE CLASS="literal">
+T</code> in <CODE CLASS="literal">
+The</code>. These whitespaces are insignificant. The rest of the whitespaces are significant and will be recognized and preserved by Samba when reading in the file. Space is not significant in option names (such as <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code>), but we recommend you follow convention and keep spaces between the words of options.</p><P CLASS="para">
+If you feel safer including quotation marks at the beginning and ending of a configuration option's value, you may do so. Samba will ignore these quotation marks when it encounters them. Never use quotation marks around an option itself; Samba will treat this as an error.</p><P CLASS="para">
+Finally, you can use whitespaces to separate a series of values in a list, or you can use commas. These two options are equivalent:</p><PRE CLASS="programlisting">
+netbios aliases = sales, accounting, payroll
+netbios aliases = sales accounting payroll</pre><P CLASS="para">
+In some values, however, you must use one form of separation&nbsp;- spaces in some cases, commas in others.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-960466">
+4.1.1.2 Capitalization</a></h4><P CLASS="para">Capitalization is not important in the Samba configuration file except in locations where it would confuse the underlying operating system. For example, let's assume that you included the following option in a share that pointed to <I CLASS="filename">
+/export/samba/simple </i>:</p><PRE CLASS="programlisting">
+PATH = /EXPORT/SAMBA/SIMPLE</pre><P CLASS="para">
+Samba would have no problem with the <CODE CLASS="literal">
+path</code> configuration option appearing entirely in capital letters. However, when it tries to connect to the given directory, it would be unsuccessful because the Unix filesystem in the underlying operating system <EM CLASS="emphasis">
+is</em> case sensitive. Consequently, the path listed would not be found and clients would be unable to connect to the share.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-960474">
+4.1.1.3 Line continuation</a></h4><P CLASS="para">
+You can continue a line in the Samba configuration file using the backslash, as follows:</p><PRE CLASS="programlisting">
+comment = The first share that has the primary copies \
+ of the new Teamworks software product.</pre><P CLASS="para">
+Because of the backslash, these two lines will be treated as one line by Samba. The second line begins at the first non-whitespace character that Samba encounters; in this case, the <CODE CLASS="literal">
+o</code> in <CODE CLASS="literal">
+of</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955588">
+4.1.1.4 Comments</a></h4><P CLASS="para">
+You can insert comments in the <I CLASS="filename">
+smb.conf</i> configuration file by preceding a line with either a hash mark (#) or a semicolon (;). Both characters are equivalent. For example, the first three lines in the following example would be considered comments:</p><PRE CLASS="programlisting">
+# This is the printers section. We have given a minimum print
+; space of 2000 to prevent some errors that we've seen when
+; the spooler runs out of space.
+
+[printers]
+ public = yes
+ min print space = 2000</pre><P CLASS="para">
+Samba will ignore all comment lines in its configuration file; there are no limitations to what can be placed on a comment line after the initial hash mark or semicolon. Note that the line continuation character (<CODE CLASS="literal">\</code>) will <EM CLASS="emphasis">
+not</em> be honored on a commented line. Like the rest of the line, it is ignored.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955563">
+4.1.1.5 Changes at runtime</a></h4><P CLASS="para">You can modify the <I CLASS="filename">
+smb.conf</i> configuration file and any of its options at any time while the Samba daemons are running. By default, Samba checks the configuration file every 60 seconds for changes. If it finds any, the changes are immediately put into effect. If you don't wish to wait that long, you can force a reload by either sending a SIGHUP signal to the <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em> processes, or simply restarting the daemons.</p><P CLASS="para">
+For example, if the <EM CLASS="emphasis">
+smbd</em> process was 893, you could force it to reread the configuration file with the following command:</p><PRE CLASS="programlisting">
+<B CLASS="emphasis.bold"><CODE CLASS="literal">#</code> kill -SIGHUP 893</b></pre><P CLASS="para">
+Not all changes will be immediately recognized by clients. For example, changes to a share that is currently in use will not be registered until the client disconnects and reconnects to that share. In addition, server-specific parameters such as the workgroup or NetBIOS name of the server will not register immediately either. This keeps active clients from being suddenly disconnected or encountering unexpected access problems while a session is open.<I CLASS="filename">
+</i> </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-87365">
+4.1.2 Variables</a></h3><P CLASS="para">
+<I CLASS="filename">
+</i>Samba includes a complete set of variables for determining characteristics of the Samba server and the clients to which it connects. Each of these variables begins with a percent sign, followed by a single uppercase or lowercase letter, and can be used only on the right side of a configuration option (e.g., after the equal sign):</p><PRE CLASS="programlisting">
+[pub]
+ path = /home/ftp/pub/%a </pre><P CLASS="para">
+The <CODE CLASS="literal">
+%a</code> stands for the client machine's architecture (e.g., <CODE CLASS="literal">
+WinNT</code> for Windows NT, <CODE CLASS="literal">
+Win95</code> for Windows 95 or 98, or <CODE CLASS="literal">
+WfWg</code> for Windows for Workgroups). Because of this, Samba will assign a unique path for the <CODE CLASS="literal">
+[pub]</code> share to client machines running Windows NT, a different path for client machines running Windows 95, and another path for Windows for Workgroups. In other words, the paths that each client would see as its share differ according to the client's architecture, as follows:</p><PRE CLASS="programlisting">
+/home/ftp/pub/WinNT
+/home/ftp/pub/Win95
+/home/ftp/pub/WfWg</pre><P CLASS="para">
+Using variables in this manner comes in handy if you wish to have different users run custom configurations based on their own unique characteristics or conditions. Samba has 19 variables, as shown in <A CLASS="xref" HREF="ch04_01.html#ch04-10883">
+Table 4.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-10883">
+Table 4.1: Samba Variables </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">Client variables</b></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%a</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<I CLASS="filename">
+</i>Client's architecture (e.g., Samba, WfWg, WinNT, Win95, or UNKNOWN)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%I</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's IP address (e.g., 192.168.220.100)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">%m</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's NetBIOS name</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%M</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Client's DNS name</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">User variables</b></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%g</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary group of <CODE CLASS="literal">
+%u</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%G</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Primary group of <CODE CLASS="literal">
+%U</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%H</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Home directory of <CODE CLASS="literal">
+%u</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%u</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current Unix username</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%U</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Requested client username (not always used by Samba)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+Share variables</b></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%p</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Automounter's path to the share's root directory, if different from <CODE CLASS="literal">
+%P</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%P</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's root directory</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%S</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current share's name</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+Server variables</b></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%d</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Current server process ID</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%h</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba server's DNS hostname</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%L</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba server's NetBIOS name</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%N</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Home directory server, from the automount map</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%v</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba version</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+Miscellaneous variables</b></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%R</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The SMB protocol level that was negotiated</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%T</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The current date and time</p></td></tr></tbody></table><P CLASS="para">Here's another example of using variables: let's say that there are five clients on your network, but one client, <CODE CLASS="literal">
+fred</code>, requires a slightly different <CODE CLASS="literal">
+[homes]</code> configuration loaded when it connects to the Samba server. With Samba, it's simple to attack such a problem: </p><PRE CLASS="programlisting">
+[homes]
+ ...
+ include = /usr/local/samba/lib/smb.conf.%m
+ ...</pre><P CLASS="para">
+The <CODE CLASS="literal">
+include</code> option here causes a separate configuration file for each particular NetBIOS machine (<CODE CLASS="literal">%m</code>) to be read in addition to the current file. If the hostname of the client machine is <CODE CLASS="literal">
+fred</code>, and if a <I CLASS="filename">
+smb.conf.fred</i> file exists in the <CODE CLASS="replaceable">
+<I>
+samba_dir</i></code><I CLASS="filename">
+/lib/</i> directory (or whatever directory you've specified for your configuration files), Samba will insert that configuration file into the default one. If any configuration options are restated in <I CLASS="filename">
+smb.conf.fred</i>, those values will override any options previously encountered in that share. Note that we say "previously." If any options are restated in the main configuration file after the <CODE CLASS="literal">
+include</code> option, Samba will honor those restated values for the share in which they are defined.</p><P CLASS="para">
+Here's the important part: if there is no such file, Samba will not generate an error. In fact, it won't do anything at all. This allows you to create only one extra configuration file for <CODE CLASS="literal">
+fred</code> when using this strategy, instead of one for each NetBIOS machine that is on the network.</p><P CLASS="para">
+Machine-specific configuration files can be used both to customize particular clients and to make debugging Samba easier. Consider the latter; if we have one client with a problem, we can use this approach to give it a private log file with a more verbose logging level. This allows us to see what Samba is doing without slowing down all the other clients or overflowing the disk with useless logs. Remember, with large networks you may not always have the option to restart the Samba server to perform debugging!</p><P CLASS="para">
+You can use each of the variables in <A CLASS="xref" HREF="ch04_01.html#ch04-10883">
+Table 4.1</a> to give custom values to a variety of Samba options. We will highlight several of these options as we move through the next few chapters.<I CLASS="filename">
+</i> </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch03_03.html" TITLE="3.3 An Introduction to SMB/CIFS">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 3.3 An Introduction to SMB/CIFS" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_02.html" TITLE="4.2 Special Sections">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.2 Special Sections" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+3.3 An Introduction to SMB/CIFS</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.2 Special Sections</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_02.html b/docs/htmldocs/using_samba/ch04_02.html
new file mode 100644
index 00000000000..d0b554e941a
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_02.html
@@ -0,0 +1,211 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.2 Special Sections</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:00Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_01.html" TITLE="4.1 Learning the Samba Configuration File">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.1 Learning the Samba Configuration File" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_03.html" TITLE="4.3 Configuration File Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.3 Configuration File Options" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-81402">
+4.2 Special Sections</a></h2><P CLASS="para">
+<I CLASS="filename">
+</i>Now that we've gotten our feet wet with variables, there are a few special sections of the Samba configuration file that we should talk about. Again, don't worry if you do not understand each and every configuration options listed below; we'll go over each of them over the course of the upcoming chapters.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-943263">
+4.2.1 The [ globals] Section</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+[globals]</code> section appears in virtually every Samba configuration file, even though it is not mandatory to define one. Any option set in this section of the file will apply to all the other shares, as if the contents of the section were copied into the share itself. There is one catch: other sections can list the same option in their section with a new value; this has the effect of overriding the value specified in the <CODE CLASS="literal">
+[globals]</code> section. </p><P CLASS="para">
+To illustrate this, let's again look at the opening example of the chapter:</p><PRE CLASS="programlisting">
+[global]
+ log level = 1
+ max log size = 1000
+ socket options = TCP_NODELAY IPTOS_LOWDELAY
+ guest ok = no
+[homes]
+ browseable = no
+ map archive = yes
+[printers]
+ path = /usr/tmp
+ guest ok = yes
+ printable = yes
+ min print space = 2000
+[test]
+ browseable = yes
+ read only = yes
+ guest ok = yes
+ path = /export/samba/test</pre><P CLASS="para">
+In the previous example, if we were going to connect a client to the <CODE CLASS="literal">
+[test]</code> share, Samba would first read in the <CODE CLASS="literal">
+[globals]</code> section. At that point, it would set the option <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+no</code> as the global default for each share it encounters throughout the configuration file. This includes the <CODE CLASS="literal">
+[homes]</code> and <CODE CLASS="literal">
+[printers]</code> shares. When it reads in the <CODE CLASS="literal">
+[test]</code> share, however, it would then find the configuration option <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code>, and override the default from the <CODE CLASS="literal">
+[globals]</code> section with the value <CODE CLASS="literal">
+yes</code> in the context of the <CODE CLASS="literal">
+[pub]</code> share.</p><P CLASS="para">
+Any option that appears outside of a section (before the first marked section) is also assumed to be a global option.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-942795">
+4.2.2 The [homes] Section</a></h3><P CLASS="para">
+If a client attempts to connect to a share that doesn't appear in the <I CLASS="filename">
+smb.conf</i> file, Samba will search for a <CODE CLASS="literal">
+[homes]</code> share in the configuration file. If one exists, the unidentified share name is assumed to be a Unix username, which is queried in the password database of the Samba server. If that username appears, Samba assumes the client is a Unix user trying to connect to his or her home directory on the server.</p><P CLASS="para">
+For example, assume a client machine is connecting to the Samba server <CODE CLASS="literal">
+hydra</code> for the first time, and tries to connect to a share named [<CODE CLASS="literal">alice]</code>. There is no <CODE CLASS="literal">
+[alice]</code> share defined in the <I CLASS="filename">
+smb.conf</i> file, but there is a <CODE CLASS="literal">
+[homes]</code>, so Samba searches the password database file and finds an <CODE CLASS="literal">alice</code> user account is present on the system. Samba then checks the password provided by the client against user <CODE CLASS="literal">alice</code>'s Unix password&nbsp;- either with the password database file if it's using non-encrypted passwords, or Samba's <I CLASS="filename">
+smbpasswd</i> file if encrypted passwords are in use. If the passwords match, then Samba knows it has guessed right: the user <CODE CLASS="literal">alice</code> is trying to connect to her home directory. Samba will then create a share called <CODE CLASS="literal">[alice]</code> for her.</p><P CLASS="para">
+The process of using the <CODE CLASS="literal">
+[homes]</code> section to create users (and dealing with their passwords) is discussed in more detail in the <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a>.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-942816">
+4.2.3 The [printers] Section</a></h3><P CLASS="para">
+The third special section is called <CODE CLASS="literal">
+[printers]</code> and is similar to <CODE CLASS="literal">
+[homes]</code>. If a client attempts to connect to a share that isn't in the <I CLASS="filename">
+smb.conf</i> file, and its name can't be found in the password file, Samba will check to see if it is a printer share. Samba does this by reading the printer capabilities file (usually <I CLASS="filename">
+/etc/printcap</i>) to see if the share name appears there.[<A CLASS="footnote" HREF="#ch04-pgfId-960558">1</a>] If it does, Samba creates a share named after the printer.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch04-pgfId-960558">[1]</a> Depending on your system, this file may not be <EM CLASS="emphasis">
+/etc/printcap</em>. You can use the <EM CLASS="emphasis">
+testparm</em> command that comes with Samba to determine the value of the <CODE CLASS="literal">
+printcap</code> <CODE CLASS="literal">
+name</code> configuration option; this was the default value chosen when Samba was compiled.</p></div></blockquote><P CLASS="para">
+Like <CODE CLASS="literal">
+[homes]</code>, this means you don't have to maintain a share for each of your system printers in the <I CLASS="filename">
+smb.conf</i> file. Instead, Samba honors the Unix printer registry if you request it to, and provides the registered printers to the client machines. There is, however, an obvious limitation: if you have an account named <CODE CLASS="literal">
+fred</code> and a printer named <CODE CLASS="literal">
+fred</code>, Samba will always find the user account first, even if the client really needed to connect to the printer.</p><P CLASS="para">
+The process of setting up the <CODE CLASS="literal">
+[printers]</code> share is discussed in more detail in <a href="ch07_01.html"><b>Chapter 7, <CITE CLASS="chapter">Printing and Name Resolution</cite></b></a>.<I CLASS="filename">
+</i> </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-968226">
+4.2.4 Configuration Options</a></h3><P CLASS="para">
+<I CLASS="filename">
+</i>Options in the Samba configuration files fall into one of two categories: <I CLASS="firstterm">
+global</i> or <I CLASS="firstterm">
+share</i>. Each category dictates where an option can appear in the configuration file.</p><DL CLASS="variablelist">
+<DT CLASS="term">
+Global</dt><DD CLASS="listitem">
+<P CLASS="para">Global options <EM CLASS="emphasis">
+must</em> appear in the <CODE CLASS="literal">
+[global]</code> section and nowhere else. These are options that typically apply to the behavior of the Samba server itself, and not to any of its shares.</p></dd><DT CLASS="term">
+Share</dt><DD CLASS="listitem">
+<P CLASS="para">Share options can appear in specific shares, or they can appear in the <CODE CLASS="literal">
+[global]</code> section. If they appear in the <CODE CLASS="literal">
+[global]</code> section, they will define a default behavior for all shares, unless a share overrides the option with a value of its own.</p></dd></dl><P CLASS="para">
+In addition, the values that a configuration option can take can be divided into four categories. They are as follows:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+Boolean</dt><DD CLASS="listitem">
+<P CLASS="para">These are simply yes or no values, but can be represented by any of the following: <CODE CLASS="literal">
+yes</code>, <CODE CLASS="literal">
+no</code>, <CODE CLASS="literal">
+true</code>, <CODE CLASS="literal">
+false</code>, <CODE CLASS="literal">
+0</code>, <CODE CLASS="literal">
+1</code>. The values are case insensitive: <CODE CLASS="literal">
+YES</code> is the same as <CODE CLASS="literal">
+yes</code>.</p></dd><DT CLASS="term">
+Numerical</dt><DD CLASS="listitem">
+<P CLASS="para">An integer, hexidecimal, or octal number. The standard <CODE CLASS="literal">
+0x</code><EM CLASS="emphasis">
+nn</em> syntax is used for hexadecimal and <CODE CLASS="literal">
+0</code><EM CLASS="emphasis">
+nnn</em> for octal.</p></dd><DT CLASS="term">
+String</dt><DD CLASS="listitem">
+<P CLASS="para">
+A string of case-sensitive characters, such as a filename or a username.</p></dd><DT CLASS="term">
+Enumerated list</dt><DD CLASS="listitem">
+<P CLASS="para">
+A finite list of known values. In effect, a boolean is an enumerated list with only two values.<I CLASS="filename">
+</i> </p></dd></dl></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_01.html" TITLE="4.1 Learning the Samba Configuration File">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.1 Learning the Samba Configuration File" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_03.html" TITLE="4.3 Configuration File Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.3 Configuration File Options" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.1 Learning the Samba Configuration File</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.3 Configuration File Options</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_03.html b/docs/htmldocs/using_samba/ch04_03.html
new file mode 100644
index 00000000000..3e5ae738659
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_03.html
@@ -0,0 +1,190 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.3 Configuration File Options</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:06Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_02.html" TITLE="4.2 Special Sections">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.2 Special Sections" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_04.html" TITLE="4.4 Server Configuration">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.4 Server Configuration" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-46076">
+4.3 Configuration File Options</a></h2><P CLASS="para">
+Samba has well over 200 configuration options at its disposal. So let's start off easy by introducing some of the options you can use to modify the configuration file itself. </p><P CLASS="para">
+As we hinted earlier in the chapter, configuration files are by no means static. You can instruct Samba to include or even replace configuration options as it is processing them. The options to do this are summarized in <A CLASS="xref" HREF="ch04_03.html#ch04-94939">
+Table 4.2</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-94939">
+Table 4.2: Configuration File Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+config file</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the location of a configuration file to use instead of the current one.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+include</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies an additional segment of configuration options to be included at this point in the configuration file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+copy</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (name of share)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows you to clone the configuration options of another share in the current share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-960146">
+4.3.1 config file</a></h3><P CLASS="para">
+The global <CODE CLASS="literal">
+config</code> <CODE CLASS="literal">
+file</code> option specifies a replacement configuration file that will be loaded when the option is encountered. If the target file exists, the remainder of the current configuration file, as well as the options encounter so far, will be discarded; Samba will configure itself entirely with the options in the new file. The <CODE CLASS="literal">
+config</code> <CODE CLASS="literal">
+file</code> option takes advantage of the variables above, which is useful in the event that you want load a special configuration file based on the machine name or user of the client that it connecting. </p><P CLASS="para">
+For example, the following line instructs Samba to use a configuration file specified by the NetBIOS name of the client connecting, if such a file exists. If it does, options specified in the original configuration file are ignored. The following example attempts to lead a new configuration file based on the client's NetBIOS name: </p><PRE CLASS="programlisting">
+[global]
+ config file = /usr/local/samba/lib/smb.conf.%m</pre><P CLASS="para">
+If the configuration file specified does not exist, the option is ignored and Samba will continue to configure itself based on the current file.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-960151">
+4.3.2 include</a></h3><P CLASS="para">
+This option, discussed in greater detail earlier, copies the target file into the current configuration file at the point specified, as shown in <A CLASS="xref" HREF="ch04_03.html#ch04-97340">
+Figure 4.1</a>. This option also takes advantage of the variables specified earlier in the chapter, which is useful in the event that you want load configuration options based on the machine name or user of the client that it connecting. You can use this option as follows:</p><PRE CLASS="programlisting">
+[global]
+ include = /usr/local/samba/lib/smb.conf.%m</pre><P CLASS="para">
+If the configuration file specified does not exist, the option is ignored. Remember that any option specified previously is overridden. In <A CLASS="xref" HREF="ch04_03.html#ch04-97340">
+Figure 4.1</a>, all three options will override their previous values. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-97340">
+Figure 4.1: The include option in a Samba configuration file</a></h4><IMG CLASS="graphic" SRC="figs/sam.0401.gif" ALT="Figure 4.1"><P CLASS="para">
+The <CODE CLASS="literal">
+include</code> option cannot understand the variables <CODE CLASS="literal">
+%u</code> (user), <CODE CLASS="literal">
+%p</code> (current share's rout directory), or <CODE CLASS="literal">
+%s</code> (current share) because they are not set at the time the file is read.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-960290">
+4.3.3 copy</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+copy</code> configuration option allows you to clone the configuration options of the share name that you specify in the current share. The target share must appear earlier in the configuration file than the share that is performing the copy. For example:</p><PRE CLASS="programlisting">
+[template]
+ writable = yes
+ browsable = yes
+ valid users = andy, dave, peter
+
+[data]
+ path = /usr/local/samba
+ copy = template</pre><P CLASS="para">
+Note that any options in the share that invoked the <CODE CLASS="literal">
+copy</code> directive will override those in the cloned share; it does not matter whether they appear before or after the <CODE CLASS="literal">
+copy</code><I CLASS="filename">
+</i> directive.<I CLASS="filename">
+</i> </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_02.html" TITLE="4.2 Special Sections">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.2 Special Sections" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_04.html" TITLE="4.4 Server Configuration">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.4 Server Configuration" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.2 Special Sections</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.4 Server Configuration</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_04.html b/docs/htmldocs/using_samba/ch04_04.html
new file mode 100644
index 00000000000..5eac6db9e5d
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_04.html
@@ -0,0 +1,214 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.4 Server Configuration</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:07Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_03.html" TITLE="4.3 Configuration File Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.3 Configuration File Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_05.html" TITLE="4.5 Disk Share Configuration">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.5 Disk Share Configuration" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-71382">
+4.4 Server Configuration</a></h2><P CLASS="para">Now it's time to begin configuring your Samba server. Let's introduce three basic configuration options that can appear in the <CODE CLASS="literal">
+[global]</code> section of your <I CLASS="filename">
+smb.conf</i> file:</p><PRE CLASS="programlisting">
+[global]
+ # Server configuration parameters
+ netbios name = HYDRA
+ server string = Samba %v on (%L)
+ workgroup = SIMPLE</pre><P CLASS="para">
+This configuration file is pretty simple; it advertises the Samba server on a NBT network under the NetBIOS name <CODE CLASS="literal">
+hydra</code>. In addition, the machine belongs to the workgroup SIMPLE and displays a description to clients that includes the Samba version number as well as the NetBIOS name of the Samba server.</p><P CLASS="para">
+If you had to enter <CODE CLASS="literal">
+encrypt passwords=yes </code>in your earlier configuration file, you should do so here as well.</p><P CLASS="para">
+Go ahead and try this configuration file. Create a file named <I CLASS="filename">
+smb.conf</i> under the <I CLASS="filename">
+/usr/local/samba/lib</i> directory with the text listed above. Then reset the Samba server and use a Windows client to verify the results. Be sure that your Windows clients are in the SIMPLE workgroup as well. After clicking on the Network Neighborhood on a Windows client, you should see a window similar to <A CLASS="xref" HREF="ch04_04.html#ch04-38915">
+Figure 4.2</a>. (In this figure, <CODE CLASS="literal">
+phoenix</code> and <CODE CLASS="literal">
+chimaera</code> are our Windows clients.) </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-38915">
+Figure 4.2: Network Neighborhood showing the Samba server</a></h4><IMG CLASS="graphic" SRC="figs/sam.0402.gif" ALT="Figure 4.2"><P CLASS="para">
+You can verify the <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+string</code> by listing the details of the Network Neighborhood window (select the Details menu item under the View menu), at which point you should see a window similar to <A CLASS="xref" HREF="ch04_04.html#ch04-50900">
+Figure 4.3</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-50900">
+Figure 4.3: Network Neighborhood details listing</a></h4><IMG CLASS="graphic" SRC="figs/sam.0403.gif" ALT="Figure 4.3"><P CLASS="para">
+If you were to click on the Hydra icon, a window should appear that shows the services that it provides. In this case, the window would be completely empty because there are no shares on the server yet.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-961293">
+4.4.1 Server Configuration Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch04_04.html#ch04-61150">Table 4.3</a> summarizes the server configuration options introduced previously. Note that all three of these options are global in scope; in other words, they must appear in the <CODE CLASS="literal">
+[global]</code> section of the configuration file. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-61150">
+Table 4.3: Server Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+netbios name</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the primary NetBIOS name of the Samba server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Server DNS hostname</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+server string</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a descriptive string for the Samba server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+Samba %v</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+workgroup</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the NetBIOS group of machines that the server belongs to.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Defined at compile time</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955762">
+4.4.1.1 netbios name</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+netbios</code> <CODE CLASS="literal">
+name</code> option allows you to set the NetBIOS name of the server. For example:</p><PRE CLASS="programlisting">
+netbios name = YORKVM1</pre><P CLASS="para">
+The default value for this configuration option is the server's hostname; that is, the first part of its complete DNS machine name. For example, a machine with the DNS name <CODE CLASS="literal">
+ruby.ora.com</code> would be given the NetBIOS name <CODE CLASS="literal">
+RUBY</code> by default. While you can use this option to restate the machine's NetBIOS name in the configuration file (as we did previously), it is more commonly used to assign the Samba server a NetBIOS name other than its current DNS name. Remember that the name given must follow the rules for valid NetBIOS machine names as outlines in <a href="ch01_01.html"><b>Chapter 1, <CITE CLASS="chapter">Learning the Samba</cite></b></a>.</p><P CLASS="para">
+Changing the NetBIOS name of the server is not recommended unless you have a good reason. One such reason might be if the hostname of the machine is not unique because the LAN is divided over two or more DNS domains. For example, YORKVM1 is a good NetBIOS candidate for <i>vm1.york.example.com</i> to differentiate it from <EM CLASS="emphasis">
+vm1.falkirk.example.com</em>, which has the same hostname but resides in a different DNS domain.</p><P CLASS="para">
+Another use of this option is for relocating SMB services from a dead or retired machine. For example, if <CODE CLASS="literal">
+SALES</code> is the SMB server for the department, and it suddenly dies, you could immediately reset <CODE CLASS="literal">
+netbios</code> <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+SALES</code> on a backup Samba machine that's taking over for it. Users won't have to change their drive mappings to a different machine; new connections to <CODE CLASS="literal">
+SALES</code> will simply go to the new machine.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955977">
+4.4.1.2 server string</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+string</code> parameter defines a comment string that will appear next to the server name in both the Network Neighborhood (when shown with the Details menu) and the comment entry of the Microsoft Windows print manager. You can use the standard variables to provide information in the description. For example, our entry earlier was:</p><PRE CLASS="programlisting">
+[global]
+ server string = Samba %v on (%h)</pre><P CLASS="para">
+The default for this option simply presents the current version of Samba and is equivalent to:</p><PRE CLASS="programlisting">
+server string = Samba %v</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-955973">
+4.4.1.3 workgroup</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+workgroup</code> parameter sets the current workgroup where the Samba server will advertise itself. Clients that wish to access shares on the Samba server should be on the same NetBIOS workgroup. Remember that workgroups are really just NetBIOS group names, and must follow the standard NetBIOS naming conventions outlined in <a href="ch01_01.html"><b>Chapter 1</b></a>. For example:</p><PRE CLASS="programlisting">
+[global]
+ workgroup = SIMPLE</pre><P CLASS="para">
+The default option for this parameter is set at compile time. If the entry is not changed in the makefile, it will be <CODE CLASS="literal">
+WORKGROUP</code>. Because this tends to be the workgroup name of every unconfigured NetBIOS network, we recommend that you always set your workgroup name in the Samba configuration file.[<A CLASS="footnote" HREF="#ch04-pgfId-962322">2</a>] </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch04-pgfId-962322">[2]</a> We should also mention that it is an inherently bad idea to have a workgroup that shares the same name as a server.</p></div></blockquote></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_03.html" TITLE="4.3 Configuration File Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.3 Configuration File Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_05.html" TITLE="4.5 Disk Share Configuration">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.5 Disk Share Configuration" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.3 Configuration File Options</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.5 Disk Share Configuration</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_05.html b/docs/htmldocs/using_samba/ch04_05.html
new file mode 100644
index 00000000000..ecb8acfebf4
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_05.html
@@ -0,0 +1,309 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.5 Disk Share Configuration</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:13Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_04.html" TITLE="4.4 Server Configuration">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.4 Server Configuration" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_06.html" TITLE="4.6 Networking Options with Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.6 Networking Options with Samba" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-14274">
+4.5 Disk Share Configuration</a></h2><P CLASS="para">We mentioned in the previous section that there were no disk shares on the <CODE CLASS="literal">
+hydra</code> server. Let's continue with the configuration file and create an empty disk share called [<CODE CLASS="literal">data</code>]. Here are the additions that will do it:</p><PRE CLASS="programlisting">
+[global]
+ netbios name = HYDRA
+ server string = Samba %v on (%L)
+ workgroup = SIMPLE
+
+[data]
+ path = /export/samba/data
+ comment = Data Drive
+ volume = Sample-Data-Drive
+ writeable = yes
+ guest ok = yes</pre><P CLASS="para">
+The <CODE CLASS="literal">
+[data]</code> share is typical for a Samba disk share. The share maps to a directory on the Samba server: <I CLASS="filename">
+/export/samba/data</i>. We've also provided a comment that describes the share as a <CODE CLASS="literal">
+Data</code> <CODE CLASS="literal">
+Drive</code>, as well as a volume name for the share itself.</p><P CLASS="para">
+The share is set to writeable so that users can write data to it; the default with Samba is to create a read-only share. As a result, this option needs to be explicitly set for each disk share you wish to make writeable.</p><P CLASS="para">
+You may have noticed that we set the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> parameter to <CODE CLASS="literal">
+yes</code>. While this isn't very security-conscious, there are some password issues that we need to understand before setting up individual users and authentication. For the moment, this will sidestep those issues and let anyone connect to the share.</p><P CLASS="para">
+Go ahead and make these additions to your configuration file. In addition, create the <I CLASS="filename">
+/export/samba/data</i> directory as root on your Samba machine with the following commands:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">#</code> mkdir /export/samba/data</b><B CLASS="emphasis.bold">
+<CODE CLASS="literal"># </code>chmod 777 /export/samba/data</b></pre><P CLASS="para">
+Now, if you connect to the <CODE CLASS="literal">
+hydra</code> server again (you can do this by clicking on its icon in the Windows Network Neighborhood), you should see a single share listed entitled <CODE CLASS="literal">
+data</code>, as shown in <A CLASS="xref" HREF="ch04_05.html#ch04-13866">
+Figure 4.4</a>. This share should also have read/write access to it. Try creating or copying a file into the share. Or, if you're really feeling adventurous, you can even try mapping a network drive to it! </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-13866">
+Figure 4.4: The initial data share on the Samba server</a></h4><IMG CLASS="graphic" SRC="figs/sam.0404.gif" ALT="Figure 4.4"><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-961433">
+4.5.1 Disk Share Configuration Options</a></h3><P CLASS="para">The basic Samba configuration options for disk shares previously introduced are listed in <A CLASS="xref" HREF="ch04_05.html#ch04-82964">
+Table 4.4</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-82964">
+Table 4.4: Basic Share Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+path (directory)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix directory that will be provided for a disk share or used for spooling by a printer share</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+/tmp</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+guest ok (public)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, authentication is not needed to access this share</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+comment</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the comment that appears with the share</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+volume</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the volume name: the DOS name of the physical drive</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share name</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+read only</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, allows read only access to a share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+writeable (write ok)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+no</code>, allows read only access to a share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-959473">
+4.5.1.1 path</a></h4><P CLASS="para">This option, which has the synonym <CODE CLASS="literal">
+directory</code>, indicates the pathname at the root of the file or printing share. You can choose any path on the Samba server, so long as the owner of the Samba process that is connecting has read and write access to that directory. If the path is for a printing share, it should point to a temporary directory where files can be written on the server before being spooled to the target printer (<I CLASS="filename">/tmp</i> and <I CLASS="filename">
+/var/spool</i> are popular choices). If this path is for a disk share, the contents of the folder representing the share name on the client will match the content of the directory on the Samba server. For example, if we have the following disk share listed in our configuration file:</p><PRE CLASS="programlisting">
+[network]
+ path = /export/samba/network
+ writable = yes
+<CODE CLASS="literal">
+ guest ok = yes</code></pre><P CLASS="para">
+And the contents of the directory <I CLASS="filename">
+/usr/local/network</i> on the Unix side are:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">$</code> ls -al /export/samba/network</b>
+</pre><PRE CLASS="programlisting">
+drwxrwxrwx 9 root nobody 1024 Feb 16 17:17 .
+drwxr-xr-x 9 nobody nobody 1024 Feb 16 17:17 ..
+drwxr-xr-x 9 nobody nobody 1024 Feb 16 17:17 quicken
+drwxr-xr-x 9 nobody nobody 1024 Feb 16 17:17 tax98
+drwxr-xr-x 9 nobody nobody 1024 Feb 16 17:17 taxdocuments</pre><P CLASS="para">
+Then we should see the equivalent of <A CLASS="xref" HREF="ch04_05.html#ch04-88746">
+Figure 4.5</a> on the client side. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-88746">
+Figure 4.5: Windows client view of a network filesystem specified by path</a></h4><IMG CLASS="graphic" SRC="figs/sam.0405.gif" ALT="Figure 4.5"></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-943587">
+4.5.1.2 guest ok</a></h4><P CLASS="para">
+This option (which has an older synonym <CODE CLASS="literal">
+public</code>) allows or prohibits guest access to a share. The default value is <CODE CLASS="literal">
+no</code>. If set to <CODE CLASS="literal">
+yes</code>, it means that no username or password will be needed to connect to the share. When a user connects, the access rights will be equivalent to the designated guest user. The default account to which Samba offers the share is <CODE CLASS="literal">
+nobody</code>. However, this can be reset with the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> configuration option. For example, the following lines allow guest user access to the <CODE CLASS="literal">
+[accounting]</code> share with the permissions of the <EM CLASS="emphasis">
+ftp</em> account:</p><PRE CLASS="programlisting">
+[global]
+ guest account = ftp
+[accounting]
+ path = /usr/local/account
+ guest ok = yes</pre><P CLASS="para">
+Note that users can still connect to the share using a valid username/password combination. If successful, they will hold the access rights granted by their own account and not the guest account. If a user attempts to log in and fails, however, he or she will default to the access rights of the guest account. You can mandate that every user who attaches to the share will be using the guest account (and will have the permissions of the guest) by setting the option <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+only</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-943593">
+4.5.1.3 comment</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+comment</code> option allows you to enter a comment that will be sent to the client when it attempts to browse the share. The user can see the comment by listing Details on the share folder under the appropriate computer in the Windows Network Neighborhood, or type the command <CODE CLASS="literal">
+NET</code> <CODE CLASS="literal">
+VIEW</code> at an MS-DOS prompt. For example, here is how you might insert a comment for a <CODE CLASS="literal">
+[network]</code> share:</p><PRE CLASS="programlisting">
+[network]
+ comment = Network Drive
+ path = /export/samba/network</pre><P CLASS="para">
+This yields a folder similar to <A CLASS="xref" HREF="ch04_05.html#ch04-34850">
+Figure 4.6</a> on the client side. Note that with the current configuration of Windows, this comment will not be shown once a share is mapped to a Windows network drive. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-34850">
+Figure 4.6: Windows client view of a share comment</a></h4><IMG CLASS="graphic" SRC="figs/sam.0406.gif" ALT="Figure 4.6"><P CLASS="para">
+Be sure not to confuse the <CODE CLASS="literal">
+comment</code> option, which documents a Samba server's shares, with the <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+string</code> option, which documents the server itself.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-967445">
+4.5.1.4 volume</a></h4><P CLASS="para">
+This option allows you to specify the volume name of the share as reported by SMB. This normally resolves to the name of the share given in the <I CLASS="filename">
+smb.conf</i> file. However, if you wish to name it something else (for whatever reason) you can do so with this option.</p><P CLASS="para">
+For example, an installer program may check the volume name of a CD-ROM to make sure the right CD-ROM is in the drive before attempting to install it. If you copy the contents of the CD-ROM into a network share, and wish to install from there, you can use this option to get around the issue:</p><PRE CLASS="programlisting">
+[network]
+ comment = Network Drive
+ volume = ASVP-102-RTYUIKA
+ path = /home/samba/network</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-952861">
+4.5.1.5 read only and writeable</a></h4><P CLASS="para">
+The options <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+only</code> and <CODE CLASS="literal">
+writeable</code> (or <CODE CLASS="literal">
+write</code> <CODE CLASS="literal">
+ok</code>) are really two ways of saying the same thing, but approached from opposite ends. For example, you can set either of the following options in the <CODE CLASS="literal">
+[global]</code> section or in an individual share:</p><PRE CLASS="programlisting">
+read only = yes
+writeable = no</pre><P CLASS="para">
+If either option is set as shown, data can be read from a share, but cannot be written to it. You might think you would need this option only if you were creating a read-only share. However, note that this read-only behavior is the <EM CLASS="emphasis">
+default</em> action for shares; if you want to be able to write data to a share, you must explicitly specify one of the following options in the configuration file for each share:</p><PRE CLASS="programlisting">
+read only = no
+writeable = yes</pre><P CLASS="para">
+Note that if you specify more than one occurrence of either option, Samba will adhere to the last value it encounters for the share. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_04.html" TITLE="4.4 Server Configuration">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.4 Server Configuration" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_06.html" TITLE="4.6 Networking Options with Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.6 Networking Options with Samba" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.4 Server Configuration</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.6 Networking Options with Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_06.html b/docs/htmldocs/using_samba/ch04_06.html
new file mode 100644
index 00000000000..897523cc55c
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_06.html
@@ -0,0 +1,414 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.6 Networking Options with Samba</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:15Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_05.html" TITLE="4.5 Disk Share Configuration">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.5 Disk Share Configuration" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_07.html" TITLE="4.7 Virtual Servers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.7 Virtual Servers" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-86705">
+4.6 Networking Options with Samba</a></h2><P CLASS="para">If you're running Samba on a multi-homed machine (that is, one on multiple subnets), or even if you want to implement a security policy on your own subnet, you should take a close look at the networking configuration options: </p><P CLASS="para">
+For the purposes of this exercise, let's assume that our Samba server is connected to a network with more than one subnet. Specifically, the machine can access both the 192.168.220.* and 134.213.233.* subnets. Here are our additions to the ongoing configuration file for the networking configuration options:</p><PRE CLASS="programlisting">
+[global]
+ netbios name = HYDRA
+ server string = Samba %v on (%L)
+ workgroup = SIMPLE
+
+ # Networking configuration options
+ hosts allow = 192.168.220. 134.213.233. localhost
+ hosts deny = 192.168.220.102
+ interfaces = 192.168.220.100/255.255.255.0 \
+ 134.213.233.110/255.255.255.0
+ bind interfaces only = yes
+
+[data]
+ path = /home/samba/data
+ guest ok = yes
+ comment = Data Drive
+ volume = Sample-Data-Drive
+ writeable = yes
+ </pre><P CLASS="para">Let's first talk about the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> options. If these options sound familiar, you're probably thinking of the <I CLASS="filename">
+hosts.allow</i> and <I CLASS="filename">
+hosts.deny</i> files that are found in the <I CLASS="filename">
+/etc</i> directories of many Unix systems. The purpose of these options is identical to those files; they provide a means of security by allowing or denying the connections of other hosts based on their IP addresses. Why not just use the <I CLASS="filename">
+hosts.allow</i> and <I CLASS="filename">
+hosts.deny</i> files themselves? Because there may be services on the server that you want others to access without giving them access Samba's disk or printer shares</p><P CLASS="para">
+With the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option above, we've specified a cropped IP address: 192.168.220. (Note that there is still a third period; it's just missing the fourth number.) This is equivalent to saying: "All hosts on the 192.168.220 subnet." However, we've explicitly specified in a hosts deny line that 192.168.220.102 is not to be allowed access.</p><P CLASS="para">
+You might be wondering: why will 192.168.220.102 be denied even though it is still in the subnet matched by the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option? Here is how Samba sorts out the rules specified by <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code>:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-961914">
+</a>If there are no <CODE CLASS="literal">
+allow</code> or <CODE CLASS="literal">
+deny</code> options defined anywhere in <I CLASS="filename">
+smb.conf</i>, Samba will allow connections from any machine allowed by the system itself.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-961915">
+</a>If there are <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> or <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> options defined in the <CODE CLASS="literal">
+[global]</code> section of <I CLASS="filename">
+smb.conf</i>, they will apply to all shares, even if the shares have an overriding option defined.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-961916">
+</a>If there is only a <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option defined for a share, only the hosts listed will be allowed to use the share. All others will be denied.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-961917">
+</a>If there is only a <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> option defined for a share, any machine which is not on the list will be able to use the share.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-961918">
+</a>If both a <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> option are defined, a host must appear in the allow list and not appear in the deny list (in any form) in order to access the share. Otherwise, the host will not be allowed.</p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Take care that you don't explicitly allow a host to access a share, but then deny access to the entire subnet of which the host is part.</p></blockquote></li></ol><P CLASS="para">
+Let's look at another example of that final item. Consider the following options:</p><PRE CLASS="programlisting">
+hosts allow = 111.222.
+hosts deny = 111.222.333.</pre><P CLASS="para">
+In this case, only the hosts that belong to the subnet 111.222.*.* will be allowed access to the Samba shares. However, if a client belongs to the 111.222.333.* subnet, it will be denied access, even though it still matches the qualifications outlined by <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code>. The client must appear on the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> list and <EM CLASS="emphasis">
+must not</em> appear on the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> list in order to gain access to a Samba share. If a computer attempts to access a share to which it is not allowed access, it will receive an error message.</p><P CLASS="para">
+The other two options that we've specified are the <CODE CLASS="literal">
+interfaces</code> and the <CODE CLASS="literal">
+bind</code> <CODE CLASS="literal">
+interface</code> <CODE CLASS="literal">
+only</code> address. Let's look at the <CODE CLASS="literal">
+interfaces</code> option first. Samba, by default, sends data only from the primary network interface, which in our example is the 192.168.220.100 subnet. If we would like it to send data to more than that one interface, we need to specify the complete list with the <CODE CLASS="literal">
+interfaces</code> option. In the previous example, we've bound Samba to interface with both subnets (192.168.220 and 134.213.233) on which the machine is operating by specifying the other network interface address: 134.213.233.100. If you have more than one interface on your computer, you should always set this option as there is no guarantee that the primary interface that Samba chooses will be the right one.</p><P CLASS="para">
+Finally, the <CODE CLASS="literal">
+bind</code> <CODE CLASS="literal">
+interfaces</code> <CODE CLASS="literal">
+only</code> option instructs the <I CLASS="filename">
+nmbd</i> process not to accept any broadcast messages other than those subnets specified with the <CODE CLASS="literal">
+interfaces</code> option. Note that this is different from the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> options, which prevent machines from making connections to services, but not from receiving broadcast messages. Using the <CODE CLASS="literal">
+bind</code> <CODE CLASS="literal">
+interfaces</code> <CODE CLASS="literal">
+only</code> option is a way to shut out even datagrams from foreign subnets from being received by the Samba server. In addition, it instructs the <EM CLASS="emphasis">
+smbd </em>process to bind to only the interface list given by the <EM CLASS="emphasis">
+interfaces</em> option. This restricts the networks that Samba will serve.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-961674">
+4.6.1 Networking Options</a></h3><P CLASS="para">The networking options we introduced above are summarized in <A CLASS="xref" HREF="ch04_06.html#ch04-32963">
+Table 4.5</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-32963">
+Table 4.5: Networking Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+hosts allow (allow hosts)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of hostnames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the machines that can connect to Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+none</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+hosts deny (deny hosts)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of hostnames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the machines that cannot connect to Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+none</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+interfaces</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of IP/netmask combinations)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the network interfaces Samba will respond to. Allows correcting defaults.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+system-dependent</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+bind</code></p><P CLASS="para">
+<CODE CLASS="literal">
+interfaces only</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, Samba will bind only to those interfaces specified by the <CODE CLASS="literal">
+interfaces</code> option.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+socket</code></p><P CLASS="para">
+<CODE CLASS="literal">
+address</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (IP address)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets IP address to listen on, for use with multiple virtual interfaces on a server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+none</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-961754">
+4.6.1.1 hosts allow</a></h4><P CLASS="para">The <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option (sometimes written as <CODE CLASS="literal">
+allow</code> <CODE CLASS="literal">
+hosts</code>) specifies the machines that have permission to access shares on the Samba server, written as a comma- or space-separated list of names of machines or their IP addresses. You can gain quite a bit of security by simply placing your LAN's subnet address in this option. For example, we specified the following in our example:</p><PRE CLASS="programlisting">
+hosts allow = 192.168.220. localhost</pre><P CLASS="para">
+Note that we placed <CODE CLASS="literal">
+localhost</code> after the subnet address. One of the most common mistakes when attempting to use the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option is to accidentally disallow the Samba server from communicating with itself. The <I CLASS="filename">
+smbpasswd</i> program will occasionally need to connect to the Samba server as a client in order to change a user's encrypted password. In addition, local browsing propagation requires local host access. If this option is enabled and the localhost address is not specified, the locally-generated packets requesting the change of the encrypted password will be discarded by Samba, and browsing propagation will not work properly. To avoid this, explicitly allow the loopback address (either <CODE CLASS="literal">
+localhost</code> or <CODE CLASS="literal">
+127.0.0.1</code>) to be used.[<A CLASS="footnote" HREF="#ch04-pgfId-965714">3</a>] </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch04-pgfId-965714">[3]</a> Starting with Samba 2.0.5, <CODE CLASS="literal">
+localhost</code> will automatically be allowed unless it is explicitly denied.</p></div></blockquote><P CLASS="para">
+You can specify any of the following formats for this option: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959824">
+</a>Hostnames, such as <CODE CLASS="literal">
+ftp.example.com</code>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959825">
+</a>IP addresses, like <CODE CLASS="literal">
+130.63.9.252</code>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959826">
+</a>Domain names, which can be differentiated from individual hostnames because they start with a dot. For example, <CODE CLASS="literal">.ora.com</code> represents all machines within the <EM CLASS="emphasis">
+ora.com</em> domain.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959827">
+</a>Netgroups, which start with an at-sign, such as <CODE CLASS="literal">
+@printerhosts</code>. Netgroups are available on systems running yellow pages/NIS or NIS+, but rarely otherwise. If netgroups are supported on your system, there should be a <CODE CLASS="literal">
+netgroups</code> manual page that describes them in more detail.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959828">
+</a>Subnets, which end with a dot. For example, <CODE CLASS="literal">
+130.63.9.</code> means all the machines whose IP addresses begin with 130.63.9.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959830">
+</a>The keyword <CODE CLASS="literal">
+ALL</code>, which allows any client access.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch04-pgfId-959831">
+</a>The keyword <CODE CLASS="literal">
+EXCEPT</code> followed by more one or more names, IP addresses, domain names, netgroups, or subnets. For example, you could specify that Samba allow all hosts except those on the 192.168.110 subnet with <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+ALL</code> <CODE CLASS="literal">
+EXCEPT</code> <CODE CLASS="literal">
+192.168.110.</code> (remember the trailing dot).</p></li></ul><P CLASS="para">
+Using the <CODE CLASS="literal">
+ALL</code> keyword is almost always a bad idea, since it means that anyone on any network can browse your files if they guess the name of your server. </p><P CLASS="para">
+Note that there is no default value for the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> configuration option, although the default course of action in the event that neither option is specified is to allow access from all sources. In addition, if you specify this option in the <CODE CLASS="literal">
+[global]</code> section of the configuration file, it will override any <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> options defined shares.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-959836">
+4.6.1.2 hosts deny</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> option (also <CODE CLASS="literal">
+deny</code> <CODE CLASS="literal">
+hosts</code>) specifies machines that do not have permission to access a share, written as a comma- or space-separated list of machine names or their IP addresses. Use the same format as specifying clients as the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> option above. For example, to restrict access to the server from everywhere but <I CLASS="filename">
+example.com</i>, you could write:</p><PRE CLASS="programlisting">
+hosts deny = ALL EXCEPT .example.com</pre><P CLASS="para">
+Like <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code>, there is no default value for the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> configuration option, although the default course of action in the event that neither option is specified is to allow access from all sources. Also, if you specify this option in the <CODE CLASS="literal">
+[global]</code> section of the configuration file, it will override any <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> options defined in shares. If you wish to deny <EM CLASS="emphasis">
+hosts</em> access to specific shares, omit both the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> options in the <CODE CLASS="literal">
+[global]</code> section of the configuration file.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-958192">
+4.6.1.3 interfaces</a></h4><P CLASS="para">The <CODE CLASS="literal">
+interfaces</code> option outlines the network addresses to which you want the Samba server to recognize and respond. This option is handy if you have a computer that resides on more than one network subnet. If this option is not set, Samba searches for the primary network interface of the server (typically the first Ethernet card) upon startup and configures itself to operate on only that subnet. If the server is configured for more than one subnet and you do not specify this option, Samba will only work on the first subnet it encounters. You must use this option to force Samba to serve the other subnets on your network.</p><P CLASS="para">
+The value of this option is one or more sets of IP address/netmask pairs, such as the following:</p><PRE CLASS="programlisting">
+interfaces = 192.168.220.100/255.255.255.0 192.168.210.30/255.255.255.0</pre><P CLASS="para">
+You can optionally specify a CIDR format bitmask, as follows:</p><PRE CLASS="programlisting">
+interfaces = 192.168.220.100/24 192.168.210.30/24</pre><P CLASS="para">
+The bitmask number specifies the first number of bits that will be turned on in the netmask. For example, the number 24 means that the first 24 (of 32) bits will be activated in the bit mask, which is the same as saying 255.255.255.0. Likewise, 16 would be equal to 255.255.0.0, and 8 would be equal to 255.0.0.0.</p><P CLASS="para">
+This option may not work correctly if you are using DHCP.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-968052">
+4.6.1.4 bind interfaces only</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+bind</code> <CODE CLASS="literal">
+interfaces</code> <CODE CLASS="literal">
+only</code> option can be used to force the <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em> processes to serve SMB requests to only those addresses specified by the <CODE CLASS="literal">
+interfaces</code> option. The <EM CLASS="emphasis">
+nmbd</em> process normally binds to the all addresses interface (0.0.0.0.) on ports 137 and 138, allowing it to receive broadcasts from anywhere. However, you can override this behavior with the following:</p><PRE CLASS="programlisting">
+bind interfaces only = yes</pre><P CLASS="para">
+This will cause both Samba processes to ignore any packets whose origination address does not match the broadcast address(es) specified by the <CODE CLASS="literal">
+interfaces</code> option, including broadcast packets. With <EM CLASS="emphasis">
+smbd</em>, this option will cause Samba to not serve file requests to subnets other than those listed in the <CODE CLASS="literal">
+interfaces</code> option. You should avoid using this option if you want to allow temporary network connections, such as those created through SLIP or PPP. It's very rare that this option is needed, and it should only be used by experts.</p><P CLASS="para">
+If you set <CODE CLASS="literal">
+bind interfaces only</code> to <CODE CLASS="literal">
+yes</code>, you should add the localhost address (127.0.01) to the "interfaces" list. Otherwise, <EM CLASS="emphasis">
+smbpasswd</em> will be unable to connect to the server using its default mode in order to change a password. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-958204">
+4.6.1.5 socket address</a></h4><P CLASS="para">The <CODE CLASS="literal">
+socket</code> <CODE CLASS="literal">
+address</code> option dictates which of the addresses specified with the <CODE CLASS="literal">
+interfaces</code> parameter Samba should listen on for connections. Samba accepts connections on all addresses specified by default. When used in an <I CLASS="filename">
+smb.conf</i> file, this option will force Samba to listen on only one IP address. For example:</p><PRE CLASS="programlisting">
+interfaces = 192.168.220.100/24 192.168.210.30/24
+socket address = 192.168.210.30</pre><P CLASS="para">
+This option is a programmer's tool and we recommend that you do not use it. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_05.html" TITLE="4.5 Disk Share Configuration">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.5 Disk Share Configuration" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_07.html" TITLE="4.7 Virtual Servers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.7 Virtual Servers" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.5 Disk Share Configuration</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.7 Virtual Servers</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_07.html b/docs/htmldocs/using_samba/ch04_07.html
new file mode 100644
index 00000000000..6f5d495a0b1
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_07.html
@@ -0,0 +1,151 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.7 Virtual Servers</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:17Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_06.html" TITLE="4.6 Networking Options with Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.6 Networking Options with Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_08.html" TITLE="4.8 Logging Configuration Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.8 Logging Configuration Options" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-16899">
+4.7 Virtual Servers</a></h2><P CLASS="para">Virtual servers are a technique for creating the illusion of multiple NetBIOS servers on the network, when in reality there is only one. The technique is simple to implement: a machine simply registers more than one NetBIOS name in association with its IP address. There are tangible benefits to doing this.</p><P CLASS="para">
+The accounting department, for example, might have an <CODE CLASS="literal">
+accounting</code> server, and clients of it would see just the accounting disks and printers. The marketing department could have their own server, <CODE CLASS="literal">
+marketing</code>, with their own reports, and so on. However, all the services would be provided by one medium-sized Unix workstation (and one relaxed administrator), instead of having one small server and one administrator per department.</p><P CLASS="para">
+Samba will allow a Unix server to use more than one NetBIOS name with the <CODE CLASS="literal">
+netbios</code> <CODE CLASS="literal">
+aliases</code> option. See <A CLASS="xref" HREF="ch04_07.html#ch04-92259">
+Table 4.6</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-92259">
+Table 4.6: Virtual Server Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+netbios aliases</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">List of NetBIOS names</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Additional NetBIOS names to respond to, for use with multiple "virtual" Samba servers.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-962377">
+4.7.1 netbios aliases</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+netbios</code> <CODE CLASS="literal">
+aliases</code> option can be used to give the Samba server more than one NetBIOS name. Each NetBIOS name listed as a value will be displayed in the Network Neighborhood of a browsing machine. When a connection is requested to any machine, however, it will connect to the same Samba server.</p><P CLASS="para">
+This might come in handy, for example, if you're transferring three departments' data to a single Unix server with modern large disks, and are retiring or reallocating the old NT servers. If the three servers are called <CODE CLASS="literal">
+sales</code>, <CODE CLASS="literal">
+accounting</code>, and <CODE CLASS="literal">
+admin</code>, you can have Samba represent all three servers with the following options:</p><PRE CLASS="programlisting">
+[global]
+ netbios aliases = sales accounting admin
+ include = /usr/local/samba/lib/smb.conf.%L</pre><P CLASS="para">
+See <A CLASS="xref" HREF="ch04_07.html#ch04-28393">
+Figure 4.7</a> for what the Network Neighborhood would display from a client.When a client attempts to connect to Samba, it will specify the name of the server that it's trying to connect to, which you can access through the <CODE CLASS="literal">
+%L</code> variable. If the requested server is <CODE CLASS="literal">
+sales</code>, Samba will include the <I CLASS="filename">
+/usr/local/samba/lib/smb.conf.sales</i> file. This file might contain global and share declarations exclusively for the sales team, such as the following:</p><PRE CLASS="programlisting">
+[global]
+ workgroup = SALES
+ hosts allow = 192.168.10.255
+
+[sales1998]
+ path = /usr/local/samba/sales/sales1998/
+...</pre><P CLASS="para">
+This particular example would set the workgroup to SALES as well, and set the IP address to allow connections only from the SALES subnet (192.168.10). In addition, it would offer shares specific to the sales department. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch04-28393">
+Figure 4.7: Using NetBIOS aliases for a Samba server </a></h4><IMG CLASS="graphic" SRC="figs/sam.0407.gif" ALT="Figure 4.7"></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_06.html" TITLE="4.6 Networking Options with Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.6 Networking Options with Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_08.html" TITLE="4.8 Logging Configuration Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 4.8 Logging Configuration Options" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.6 Networking Options with Samba</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+4.8 Logging Configuration Options</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch04_08.html b/docs/htmldocs/using_samba/ch04_08.html
new file mode 100644
index 00000000000..7336022e151
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch04_08.html
@@ -0,0 +1,423 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 4] 4.8 Logging Configuration Options</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:18Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_07.html" TITLE="4.7 Virtual Servers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.7 Virtual Servers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch04_01.html" TITLE="4. Disk Shares ">
+Chapter 4<br>
+Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5. Browsing and Advanced Disk Shares " BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch04-29331">
+4.8 Logging Configuration Options</a></h2><P CLASS="para">Occasionally, we need to find out what Samba is up to. This is especially true when Samba is performing an unexpected action or is not performing at all. To find out this information, we need to check Samba's log files to see exactly why it did what it did.</p><P CLASS="para">
+Samba log files can be as brief or verbose as you like. Here is an example of what a Samba log file looks like:</p><PRE CLASS="programlisting">
+[1999/07/21 13:23:25, 3] smbd/service.c:close_cnum(514)
+ phoenix (192.168.220.101) closed connection to service IPC$
+[1999/07/21 13:23:25, 3] smbd/connection.c:yield_connection(40)
+ Yielding connection to IPC$
+[1999/07/21 13:23:25, 3] smbd/process.c:process_smb(615)
+ Transaction 923 of length 49
+[1999/07/21 13:23:25, 3] smbd/process.c:switch_message(448)
+ switch message SMBread (pid 467)
+[1999/07/21 13:23:25, 3] lib/doscalls.c:dos_ChDir(336)
+ dos_ChDir to /home/samba
+[1999/07/21 13:23:25, 3] smbd/reply.c:reply_read(2199)
+ read fnum=4207 num=2820 nread=2820
+[1999/07/21 13:23:25, 3] smbd/process.c:process_smb(615)
+ Transaction 924 of length 55
+[1999/07/21 13:23:25, 3] smbd/process.c:switch_message(448)
+ switch message SMBreadbraw (pid 467)
+[1999/07/21 13:23:25, 3] smbd/reply.c:reply_readbraw(2053)
+ readbraw fnum=4207 start=130820 max=1276 min=0 nread=1276
+[1999/07/21 13:23:25, 3] smbd/process.c:process_smb(615)
+ Transaction 925 of length 55
+[1999/07/21 13:23:25, 3] smbd/process.c:switch_message(448)
+ switch message SMBreadbraw (pid 467) </pre><P CLASS="para">
+Many of these options are of use only to Samba programmers. However, we will go over the meaning of some of these entries in more detail in <a href="ch09_01.html"><b>Chapter 9, <CITE CLASS="chapter">Troubleshooting Samba</cite></b></a>.</p><P CLASS="para">
+Samba contains six options that allow users to describe how and where logging information should be written. Each of these options are global options and cannot appear inside a share definition. Here is an up-to-date configuration file that covers each of the share and logging options that we've seen so far:</p><PRE CLASS="programlisting">
+[global]
+ netbios name = HYDRA
+ server string = Samba %v on (%I)
+ workgroup = SIMPLE
+
+ # Networking configuration options
+ hosts allow = 192.168.220. 134.213.233. localhost
+ hosts deny = 192.168.220.102
+ interfaces = 192.168.220.100/255.255.255.0 \
+ 134.213.233.110/255.255.255.0
+ bind interfaces only = yes
+
+ # Debug logging information
+ log level = 2
+ log file = /var/log/samba.log.%m
+ max log size = 50
+ debug timestamp = yes
+
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ comment = Data Drive
+ volume = Sample-Data-Drive
+ writeable = yes
+ </pre><P CLASS="para">
+ Here, we've added a custom log file that reports information up to debug level 2. This is a relatively light debugging level. The logging level ranges from 1 to 10, where level 1 provides only a small amount of information and level 10 provides a plethora of low-level information. Level 2 will provide us with useful debugging information without wasting disk space on our server. In practice, you should avoid using log levels greater than 3 unless you are programming Samba.</p><P CLASS="para">
+This file is located in the <I CLASS="filename">
+/var/log</i> directory thanks to the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+file</code> configuration option. However, we can use variable substitution to create log files specifically for individual users or clients, such as with the <CODE CLASS="literal">
+%m</code> variable in the following line:</p><PRE CLASS="programlisting">
+log file = /usr/local/logs/samba.log.%m</pre><P CLASS="para">
+Isolating the log messages can be invaluable in tracking down a network error if you know the problem is coming from a specific machine or user.</p><P CLASS="para">
+We've added another precaution to the log files: no one log file can exceed 50 kilobytes in size, as specified by the <CODE CLASS="literal">
+max</code> <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+size</code> option. If a log file exceeds this size, the contents are moved to a file with the same name but with the suffix <EM CLASS="emphasis">
+.old</em> appended. If the <EM CLASS="emphasis">
+.old</em> file already exists, it is overwritten and its contents are lost. The original file is cleared, waiting to receive new logging information. This prevents the hard drive from being overwhelmed with Samba log files during the life of our daemons.</p><P CLASS="para">
+For convenience, we have decided to leave the debug timestamp in the logs with the <CODE CLASS="literal">
+debug</code> <CODE CLASS="literal">
+timestamp</code> option, which is the default behavior. This will place a timestamp next to each message in the logging file. If we were not interested in this information, we could specify <CODE CLASS="literal">
+no</code> for this option instead.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-97929">
+4.8.1 Using syslog</a></h3><P CLASS="para">
+If you wish to use the system logger (<I CLASS="filename">syslog</i>) in addition to or in place of the standard Samba logging file, Samba provides options for this as well. However, to use <I CLASS="filename">
+syslog</i>, the first thing you will have to do is make sure that Samba was built with the <CODE CLASS="literal">
+configure</code> <CODE CLASS="literal">
+--with-syslog</code> option. See <a href="ch02_01.html"><b>Chapter 2</b></a> for more information on configuring and compiling Samba.</p><P CLASS="para">
+Once that is done, you will need to configure your <I CLASS="filename">
+/etc/syslog.conf</i> to accept logging information from Samba. If there is not already a <CODE CLASS="literal">
+daemon.*</code> entry in the <CODE CLASS="replaceable">
+<I>
+/etc/syslog.conf</i></code> file, add the following:</p><PRE CLASS="programlisting">
+daemon.* /var/log/daemon.log</pre><P CLASS="para">
+This specifies that any logging information from system daemons will be stored in the <I CLASS="filename">
+/var/log/daemon.log</i> file. This is where the Samba information will be stored as well. From there, you can specify the following global option in your configuration file:</p><PRE CLASS="programlisting">
+syslog = 2</pre><P CLASS="para">
+This specifies that any logging messages with a level of 1 will be sent to both the <I CLASS="filename">
+syslog</i> and the Samba logging files. (The mappings to <I CLASS="filename">
+syslog</i> priorities are described in the upcoming section "syslog.") Let's assume that we set the regular <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> option above to 4. Any logging messages with a level of 2, 3, or 4 will be sent to the Samba logging files, but not to the <I CLASS="filename">
+syslog</i>. Only level 1 logging messages will be sent to both. If the <CODE CLASS="literal">
+syslog</code> value exceeds the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> value, nothing will be written to the <I CLASS="filename">
+syslog</i>.</p><P CLASS="para">
+If you want to specify that messages be sent only to <I CLASS="filename">
+syslog</i>&nbsp;- and not to the standard Samba logging files&nbsp;- you can place this option in the configuration file:</p><PRE CLASS="programlisting">
+syslog only = yes</pre><P CLASS="para">
+If this is the case, any logging information above the number specified in the <CODE CLASS="literal">
+syslog</code> option will be discarded, just like the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> option.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch04-pgfId-961771">
+4.8.2 Logging Configuration Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch04_08.html#ch04-92838">
+Table 4.7</a> lists each of the logging configuration options that Samba can use. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-92838">
+Table 4.7: Global Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+log file</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified filename)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the name and location of the log file that Samba is to use. Uses standard variables.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specified in Samba makefile</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+log level</code></p><P CLASS="para">
+<CODE CLASS="literal">
+(debug level)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (0-10)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the amount of log/debug messages that are sent to the log file. 0 is none, 3 is considerable.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max log size</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (size in KB)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the maximum size of log file. After the log exceeds this size, the file will be renamed to <EM CLASS="emphasis">
+.bak </em>and a new log file started.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+5000</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+debug</code></p><P CLASS="para">
+<CODE CLASS="literal">
+timestamp (timestamp logs)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If no, doesn't timestamp logs, making them easier to read during heavy debugging.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+syslog</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (0-10)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets level of messages sent to <EM CLASS="emphasis">
+syslog</em>. Those levels below <CODE CLASS="literal">
+syslog level</code> will be sent to the system logger.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+syslog only</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If yes, uses <EM CLASS="emphasis">
+syslog</em> entirely and sends no output to the standard Samba log files.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-log-file-option">
+4.8.2.1 log file</a></h4><P CLASS="para">
+On our server, Samba outputs log information to text files in the <I CLASS="filename">
+var</i> subdirectory of the Samba home directory, as set by the makefile during the build. The <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+file</code> option can be used to reset the name of the log file to another location. For example, to reset the name and location of the Samba log file to <I CLASS="filename">
+/usr/local/logs/samba.log</i>, you could use the following:</p><PRE CLASS="programlisting">
+[global]
+ log file = /usr/local/logs/samba.log</pre><P CLASS="para">
+You may use variable substitution to create log files specifically for individual users or clients.</p><P CLASS="para">
+You can override the default log file location using the <CODE CLASS="literal">
+-l</code> command-line switch when either daemon is started. However, this does not override the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+file</code> option. If you do specify this parameter, initial logging information will be sent to the file specified after <CODE CLASS="literal">
+-l</code> (or the default specified in the Samba makefile) until the daemons have processed the <I CLASS="filename">
+smb.conf</i> file and know to redirect it to a new log file.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-953284">
+4.8.2.2 log level</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> option sets the amount of data to be logged. Normally this is left at 0 or 1. However, if you have a specific problem you may want to set it at 3, which provides the most useful debugging information you would need to track down a problem. Levels above 3 provide information that's primarily for the developers to use for chasing internal bugs, and slows down the server considerably. Therefore, we recommend that you avoid setting this option to anything above 3. </p><PRE CLASS="programlisting">
+[global]
+log file = /usr/local/logs/samba.log.%m
+log level = 3</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-960212">
+4.8.2.3 max log size</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+max</code> <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+size</code> option sets the maximum size, in kilobytes, of the debugging log file that Samba keeps. When the log file exceeds this size, the current log file is renamed to add an <EM CLASS="emphasis">
+.old</em> extension (erasing any previous file with that name) and a new debugging log file is started with the original name. For example:</p><PRE CLASS="programlisting">
+[global]
+log file = /usr/local/logs/samba.log.%m
+max log size = 1000</pre><P CLASS="para">
+Here, if the size of any log file exceeds one megabyte in size, Samba renames the log file <EM CLASS="emphasis">
+samba.log. </em><CODE CLASS="replaceable">
+<I>
+machine-name</i></code><EM CLASS="emphasis">
+.old</em> and a new log file is generated. If there was a file there previously with the <EM CLASS="emphasis">
+.old</em> extension, Samba deletes it. We highly recommend setting this option in your configuration files because debug logging (even at lower levels) can covertly eat away at your available disk space. Using this option protects unwary administrators from suddenly discovering that most of their disk space has been swallowed up by a single Samba log file.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-953294">
+4.8.2.4 debug timestamp or timestamp logs</a></h4><P CLASS="para">
+If you happen to be debugging a network problem and you find that the date-stamp and timestamp information within the Samba log lines gets in the way, you can turn it off by giving either the <CODE CLASS="literal">
+timestamp</code> <CODE CLASS="literal">
+logs</code> or the <CODE CLASS="literal">
+debug</code> <CODE CLASS="literal">
+timestamp</code> option (they're synonymous) a value of <CODE CLASS="literal">
+no</code>. For example, a regular Samba log file presents its output in the following form:</p><PRE CLASS="programlisting">
+12/31/98 12:03:34 hydra (192.168.220.101) connect to server network as user davecb</pre><P CLASS="para">
+With a <CODE CLASS="literal">
+no</code> value for this option, the output would appear without the datestamp or the timestamp:</p><PRE CLASS="programlisting">
+hydra (192.168.220.101) connect to server network as user davecb</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-78696">
+4.8.2.5 syslog</a></h4><P CLASS="para">The <CODE CLASS="literal">
+syslog</code> option causes Samba log messages to be sent to the Unix system logger. The type of log information to be sent is specified as the parameter for this argument. Like the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> option, it can be a number from 0 to 10. Logging information with a level less than the number specified will be sent to the system logger. However, debug logs equal to or above the <CODE CLASS="literal">
+syslog</code> level, but less than log level, will still be sent to the standard Samba log files. To get around this, use the <CODE CLASS="literal">
+syslog</code> <CODE CLASS="literal">
+only</code> option. For example:</p><PRE CLASS="programlisting">
+[global]
+ log level = 3
+ syslog = 1</pre><P CLASS="para">
+With this, all logging information with a level of 0 would be sent to the standard Samba logs and the system logger, while information with levels 1, 2, and 3 would be sent only to the standard Samba logs. Levels above 3 are not logged at all. Note that all messages sent to the system logger are mapped to a priority level that the <EM CLASS="emphasis">
+syslog</em> process understands, as shown in <A CLASS="xref" HREF="ch04_08.html#ch04-80576">
+Table 4.8</a>. The default level is 1. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch04-80576">
+Table 4.8: Syslog Priority Conversion </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Log Level</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Syslog Priority</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+0</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LOG_ERR</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LOG_WARNING</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LOG_NOTICE</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LOG_INFO</code></p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4 and above</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+LOG_DEBUG</code></p></td></tr></tbody></table><P CLASS="para">
+If you wish to use <EM CLASS="emphasis">
+syslog</em>, you will have to run <CODE CLASS="literal">
+configure</code> <CODE CLASS="literal">
+--with-syslog</code> when compiling Samba, and you will need to configure your <I CLASS="filename">
+/etc/syslog.conf</i> to suit. (See the section <A CLASS="xref" HREF="ch04_08.html#ch04-97929">
+Section 4.8.1, Using syslog</a>, earlier in this chapter.)</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch04-pgfId-953338">
+4.8.2.6 syslog only</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+syslog</code> <CODE CLASS="literal">
+only</code> option tells Samba not to use the regular logging files&nbsp;- the system logger only. To enable this, specify the following option in the global ection of the Samba configuration file:</p><PRE CLASS="programlisting">
+[global]
+ syslog only = yes </pre></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_07.html" TITLE="4.7 Virtual Servers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.7 Virtual Servers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5. Browsing and Advanced Disk Shares " BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.7 Virtual Servers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+5. Browsing and Advanced Disk Shares </td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch05_01.html b/docs/htmldocs/using_samba/ch05_01.html
new file mode 100644
index 00000000000..d45bd13f32d
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch05_01.html
@@ -0,0 +1,786 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 5] Browsing and Advanced Disk Shares </title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:41Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_08.html" TITLE="4.8 Logging Configuration Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.8 Logging Configuration Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 5</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_02.html" TITLE="5.2 Filesystem Differences">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.2 Filesystem Differences" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch05-51347">
+5. Browsing and Advanced Disk Shares </a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch05-23763" TITLE="5.1 Browsing">
+Browsing</a><br>
+<A CLASS="sect1" HREF="ch05_02.html" TITLE="5.2 Filesystem Differences">
+Filesystem Differences</a><br>
+<A CLASS="sect1" HREF="ch05_03.html" TITLE="5.3 File Permissions and Attributes on MS-DOS and Unix">
+File Permissions and Attributes on MS-DOS and Unix</a><br>
+<A CLASS="sect1" HREF="ch05_04.html" TITLE="5.4 Name Mangling and Case">
+Name Mangling and Case</a><br>
+<A CLASS="sect1" HREF="ch05_05.html" TITLE="5.5 Locks and Oplocks">
+Locks and Oplocks</a></p><P>
+</p></div><P CLASS="para">This chapter continues our discussion of disk shares from the previous chapter. Here, we will discuss various differences between the Windows and Unix filesystems&nbsp;- and how Samba works to bridge the gap. There are a surprising number of inconsistencies between a DOS filesystem and a Unix filesystem. In addition, we will talk briefly about name mangling, file locking, and a relatively new feature for Samba: opportunistic locking, or oplocks. However, before we move into that territory, we should first discuss the somewhat arcane topic of browsing with Samba.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch05-23763">
+5.1 Browsing</a></h2><P CLASS="para">
+Browsing is the ability to examine the servers and shares that are currently available on your network. On a Windows NT 4.0 or 95/98 client, a user can browse network servers through the Network Neighborhood folder. By double-clicking the icon representing the server, the user should be able to see the printer and disk share resources available on that machine as well. (If you have Windows NT 3.<EM CLASS="emphasis">
+x</em>, you can use the Disk-Connect Network Drive menu in the File Manager to display the available shares on a server.) </p><P CLASS="para">
+From the Windows command line, you can also use the <CODE CLASS="literal">
+net</code> <CODE CLASS="literal">
+view</code> option to see which servers are currently on the network. Here is an example of the <CODE CLASS="literal">
+net</code> <CODE CLASS="literal">
+view</code> command in action:</p><PRE CLASS="programlisting">C:\&gt;<CODE CLASS="userinput"><B> net view</b></code>
+Servers available in workgroup SIMPLE
+Server name Remark
+----------------------------------------------------------
+\\CHIMAERA Windows NT 4.0
+\\HYDRA Samba 2.0.4 on (hydra)
+\\PHOENIX Windows 98</pre><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-962596">
+5.1.1 Preventing Browsing</a></h3><P CLASS="para">You can restrict a share from being in a browse list by using the <CODE CLASS="literal">
+browseable</code> option. This boolean option prevents a share from being seen in the Network Neighborhood at all. For example, to prevent the <CODE CLASS="literal">
+[data]</code> share from the previous chapter from being visible, we could write:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = no
+ guest ok = yes
+ comment = Data Drive
+ volume = Sample-Data-Drive
+ writeable = yes</pre><P CLASS="para">
+Although you typically don't want to do this to an ordinary disk share, the browseable option is useful in the event that you need to create a share with contents that you do not want others to see, such as a <CODE CLASS="literal">
+[netlogin]</code> share for storing logon scripts for Windows domain control (see <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a> for more information on logon scripts).</p><P CLASS="para">
+Another example is the <CODE CLASS="literal">
+[homes]</code> share. This share is often marked non-browsable so that a share named <CODE CLASS="literal">
+[homes]</code> won't appear when its machine's resources are browsed. However, if a user <CODE CLASS="literal">
+alice</code> logs on and looks at the machine's shares, an <CODE CLASS="literal">
+[alice]</code> share will appear under the machine. What if we wanted to make sure <CODE CLASS="literal">
+alice</code>'s share appeared to everyone before she logs in? This could be done with the global <CODE CLASS="literal">
+auto</code> <CODE CLASS="literal">
+services</code> option. This option preloads shares into the browse list to ensure that they are always visible: </p><PRE CLASS="programlisting">
+[global]
+ ...
+ auto services = alice
+ ...</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-962409">
+5.1.2 Default Services</a></h3><P CLASS="para">
+In the event that a user cannot successfully connect to a share, you can specify a default share to which they can connect. Since you do not know who will default to this share at any time, you will probably want to set the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> option to <CODE CLASS="literal">
+yes</code> for this share. Specifying a <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+service</code> can be useful when sending the utterly befuddled to a directory of help files. For example:</p><PRE CLASS="programlisting">
+[global]
+ ...
+ default service = helpshare
+ ...
+
+[helpshare]
+ path = /home/samba/helpshare/%S
+ browseable = yes
+ guest ok = yes
+ comment = Default Share for Unsuccessful Connections
+ volume = Sample-Data-Drive
+ writeable = no</pre><P CLASS="para">
+Note that we used the <CODE CLASS="literal">
+%S</code> variable in the <CODE CLASS="literal">
+path</code> option. If you use the <CODE CLASS="literal">
+%S</code> variable, it will refer to the requested nonexistent share (the original share requested by the user), not the name of the resulting default share. This allows us to create different paths with the names of each server, which can provide more customized help files for users. In addition, any underscores (_) specified in the requested share will be converted to slashes (/) when the <CODE CLASS="literal">
+%S</code> variable is used.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-969505">
+5.1.3 Browsing Elections</a></h3><P CLASS="para">As mentioned in <a href="ch01_01.html"><b>Chapter 1, <CITE CLASS="chapter">Learning the Samba</cite></b></a>, one machine in each subnet always keeps a list of the currently active machines. This list is called the <I CLASS="firstterm">
+browse list</i> and the server that maintains it is called the <I CLASS="firstterm">local master browser</i>. As machines come on and off the network, the local master browser continually updates the information in the browse list and provides it to any machine that requests it.</p><P CLASS="para">
+A computer becomes a local master browser by holding a browsing election on the local subnet. Browsing elections can be called at any time. Samba can rig a browsing election for a variety of outcomes, including always becoming the local master browser of the subnet or never becoming it. For example, the following options, which we've added to the configuration file from <a href="ch04_01.html"><b>Chapter 4, <CITE CLASS="chapter">Disk Shares</cite></b></a>, will ensure that Samba always wins the election for local master browser no matter which machines are also present:</p><PRE CLASS="programlisting">
+[global]
+ netbios name = HYDRA
+ server string = Samba %v on (%L)
+ workgroup = SIMPLE
+
+ # Browsing election options
+ os level = 34
+ local master = yes
+
+ # Networking configuration options
+ hosts allow = 192.168.220. 134.213.233. localhost
+ hosts deny = 192.168.220.102
+ interfaces = 192.168.220.100/255.255.255.0 \
+ 134.213.233.110/255.255.255.0
+
+ # Debug logging information
+ log level = 2
+ log file = /var/log/samba.log.%m
+ max log size = 50
+ debug timestamp = yes
+
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ comment = Data Drive
+ volume = Sample-Data-Drive
+ writable = yes</pre><P CLASS="para">
+However, what if we didn't always want to win the election? What if we wanted to yield browsing to a Windows NT Server if present? In order to do that, we need to learn how browsing elections work. As you already know, each machine that takes place in the election must broadcast information about itself. This information includes the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962259">
+</a>The version of the election protocol used</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962260">
+</a>The operating system on the machine</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962261">
+</a>The amount of time the client has been on the network</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962267">
+</a>The hostname of the client</p></li></ul><P CLASS="para">
+Here is how the election is decided. Operating systems are assigned a binary value according to their version, as shown in <A CLASS="xref" HREF="ch05_01.html#ch05-51423">
+Table 5.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-51423">
+Table 5.1: Operating System Values in an Election </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Operating System</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Value</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Windows NT Server 4.0</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+33</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT Server 3.51</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+32</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT Workstation 4.0</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+17</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT Workstation 3.51</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+16</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 98</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 95</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 3.1 for Workgroups</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td></tr></tbody></table><P CLASS="para">
+Following that, each computer on the network is assigned a separate value according to its role, as shown in <A CLASS="xref" HREF="ch05_01.html#ch05-pgfId-962213">
+Table 5.2</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-pgfId-962213">
+Table 5.2: Computer Role Settings in an Election </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Role</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Value</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Primary Domain Controller</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+128</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+WINS Client</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+32</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Preferred Master Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+8</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Active Master Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+4</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Standby Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+2</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Active Backup Browser</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+1</p></td></tr></tbody></table><P CLASS="para">Elections are decided in the following order:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962245">
+</a>The machine with the highest version of the election protocol will win. (So far, this is meaningless, as all Windows clients have version 1 of the election protocol.)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962246">
+</a>The machine with the highest operating system value wins the election.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962247">
+</a>If there is a tie, the machine with the setting of Preferred Master Browser (role 8) wins the election.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962248">
+</a>If there is still a tie, the client who has been online the longest wins the election.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962282">
+</a>And finally, if there is still a tie, the client name that comes first alphabetically wins.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-969905">
+</a>The machine that is the "runner-up" can become a backup browser.</p></li></ol><P CLASS="para">
+As a result, if you want Samba to take the role of a local master browser, but only if there isn't a Windows NT Server (4.0 or 3.51) on the network, you could change the <CODE CLASS="literal">
+os</code> <CODE CLASS="literal">
+level</code> parameter in the previous example to:</p><PRE CLASS="programlisting">
+os level = 31</pre><P CLASS="para">
+This will cause Samba to immediately lose the election to a Windows NT 4.0 or Windows NT 3.5 Server, both of which have a higher operating systems level. On the other hand, if you wanted to decide the local master browser on the basis of the network role, such as which machine is the primary domain controller, you could set the <CODE CLASS="literal">
+os</code> <CODE CLASS="literal">
+level</code> to match the highest type of operating system on the network and let the election protocol fall down to the next level.</p><P CLASS="para">How can you can tell if a machine is a local master browser? By using the <CODE CLASS="literal">
+nbtstat</code> command. Place the NetBIOS name of the machine you wish to check after the <CODE CLASS="literal">
+-a</code> option:</p><PRE CLASS="programlisting">C:\&gt;<CODE CLASS="userinput"><B> nbtstat -a hydra</b></code>
+
+ NetBIOS Remote Machine Name Table
+
+ Name Type Status
+----------------------------------------------------------
+ HYDRA &lt;00&gt; UNIQUE Registered
+ HYDRA &lt;03&gt; UNIQUE Registered
+ HYDRA &lt;20&gt; UNIQUE Registered
+ ..__MSBROWSE__. &lt;01&gt; GROUP Registered
+ SIMPLE &lt;00&gt; GROUP Registered
+ SIMPLE &lt;1D&gt; UNIQUE Registered
+ SIMPLE &lt;1E&gt; GROUP Registered
+
+ MAC Address = 00-00-00-00-00-00</pre><P CLASS="para">
+The resource entry that you're looking for is the <CODE CLASS="literal">
+..__MSBROWSE__.&lt;01&gt;</code>. This indicates that the server is currently acting as the local master browser for the current subnet. In addition, if the machine is a Samba server, you can check the Samba <I CLASS="filename">
+nmbd</i> log file for an entry such as:</p><PRE CLASS="programlisting">
+nmbd/nmbd_become_lmb.c:become_local_master_stage2(406)
+*****
+Samba name server HYDRA is now a local master browser for
+workgroup SIMPLE on subnet 192.168.220.100
+****</pre><P CLASS="para">
+Finally, Windows NT servers serving as primary domain controllers contain a sneak that allows them to assume the role of the local master browser in certain conditions; this is called the <EM CLASS="emphasis">
+preferred</em> <EM CLASS="emphasis">
+master browser</em> bit. Earlier, we mentioned that Samba could set this bit on itself as well. You can enable it with the <CODE CLASS="literal">
+preferred</code> <CODE CLASS="literal">
+master</code> option:</p><PRE CLASS="programlisting">
+# Browsing election options
+os level = 33
+local master = yes
+preferred master = yes</pre><P CLASS="para">
+If the preferred master bit is set, the machine will force a browsing election at startup. Of course, this is needed only if you set the <CODE CLASS="literal">
+os</code> <CODE CLASS="literal">
+level</code> option to match the Windows NT machine. We recommend that you don't use this option if another machine also has the role of preferred master, such as an NT server. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-962289">
+5.1.4 Domain Master Browser</a></h3><P CLASS="para">In the opening chapter, we mentioned that in order for a Windows workgroup or domain to extend into multiple subnets, one machine would have to take the role of the <I CLASS="firstterm">
+domain master browser</i>. The domain master browser propagates browse lists across each of the subnets in the workgroup. This works because each local master browser periodically synchronizes its browse list with the domain master browser. During this synchronization, the local master browser passes on any server that the domain master browser does not have in its browse list, and vice versa. In a perfect world, each local master browser would eventually have the browse list for the entire domain.</p><P CLASS="para">
+Unlike the local master browser, there is no election to determine which machine assumes the role of the domain master browser. Instead, the administrator has to set it manually. By Microsoft design, however, the domain master browser and the primary domain controller (PDC) both register a resource type of &lt;1B&gt;, so the roles&nbsp;- and the machines&nbsp;- are inseparable. </p><P CLASS="para">
+If you have a Windows NT server on the network acting as a PDC, we recommend that you do not use Samba to become the domain master browser. The reverse is true as well: if Samba is taking on the responsibilities of a PDC, we recommend making it the domain master browser as well. Although it is possible to split the roles with Samba, this is not a good idea. Using two different machines to serve as the PDC and the domain master browser can cause random errors to occur on a Windows workgroup.</p><P CLASS="para">
+Samba can assume the role of a domain master browser for all subnets in the workgroup with the following option:</p><PRE CLASS="programlisting">
+domain master = yes</pre><P CLASS="para">
+You can verify that a Samba machine is in fact the domain master browser by checking the <EM CLASS="emphasis">
+nmbd</em> log file:</p><PRE CLASS="programlisting">
+nmbd/nmbd_become_dmb.c:become_domain_master_stage2(118)
+*****
+Samba name server HYDRA is now a domain master browser for
+workgroup SIMPLE on subnet 192.168.220.100
+*****</pre><P CLASS="para">
+Or you can use the <CODE CLASS="literal">nmblookup</code> command that comes with the Samba distribution to query for a unique &lt;1B&gt; resource type in the workgroup:</p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>nmblookup SIMPLE#1B</b></code>
+Sending queries to 192.168.220.255
+192.168.220.100 SIMPLE&lt;1b&gt;</pre><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-963109">
+5.1.4.1 Multiple subnets</a></h4><P CLASS="para">There are three rules that you must remember when creating a workgroup/domain that spans more than one subnet:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962339">
+</a>You must have either a Windows NT or Samba machine acting as a local master browser on each subnet in the workgroup/domain. (If you have a domain master browser in a subnet, a local master browser is not needed.)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962340">
+</a>You must have a Windows NT Server or a Samba machine acting as a domain master browser somewhere in the workgroup.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-962343">
+</a>Each local master browser must be instructed to synchronize with the domain master browser.</p></li></ul><P CLASS="para">
+Samba has a few other features in this arena in the event that you don't have or want a domain master browser on your network. Consider the subnets shown in <A CLASS="xref" HREF="ch05_01.html#ch05-15706">
+Figure 5.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-15706">
+Figure 5.1: Multiple subnets with Samba servers</a></h4><IMG CLASS="graphic" SRC="figs/sam.0501.gif" ALT="Figure 5.1"><P CLASS="para">
+First, a Samba server that is a local master browser can use the <CODE CLASS="literal">
+remote</code> <CODE CLASS="literal">
+announce</code> configuration option to make sure that computers in different subnets are sent broadcast announcements about the server. This has the effect of ensuring that the Samba server appears in the browse lists of foreign subnets. To achieve this, however, the directed broadcasts must reach the local master browser on the other subnet. Be aware that many routers do not allow directed broadcasts by default; you may have to change this setting on the router for the directed broadcasts to get through to its subnet.</p><P CLASS="para">
+With the <CODE CLASS="literal">
+remote</code> <CODE CLASS="literal">
+announce</code> option, list the subnets and the workgroup that should receive the broadcast. For example, to ensure that machines in the 192.168.221 and 192.168.222 subnets and SIMPLE workgroup are sent broadcast information from our Samba server, we could specify the following:</p><PRE CLASS="programlisting">
+# Browsing election options
+os level = 34
+local master = yes
+remote announce = 192.168.221.255/SIMPLE \
+ 192.168.222.255/SIMPLE</pre><P CLASS="para">
+In addition, you are allowed to specify the exact address to send broadcasts to if the local master browser on the foreign subnet is guaranteed to always have a fixed IP address.</p><P CLASS="para">
+A Samba local master browser can synchronize its browse list directly with another Samba server acting as a local master browser on a different subnet. For example, let's assume that Samba is configured as a local master browser, and Samba local master browsers exist at 192.168.221.130 and 192.168.222.120. We can use the <CODE CLASS="literal">
+remote</code> <CODE CLASS="literal">
+browse</code> <CODE CLASS="literal">
+sync</code> option to sync directly with the Samba servers, as follows:</p><PRE CLASS="programlisting">
+# Browsing election options
+os level = 34
+local master = yes
+remote browse sync = 192.168.221.130 192.168.222.120</pre><P CLASS="para">
+In order for this to work, the other Samba machines must also be local master browsers. You can also use directed broadcasts with this option if you do not know specific IP addresses of local master browsers. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-969941">
+5.1.5 Browsing Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch05_01.html#ch05-81028">Table 5.3</a> shows 14 options that define how Samba handles browsing tasks. We recommend the defaults for a site that prefers to be easy on its users with respect to locating shares and printers. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-81028">
+Table 5.3: Browsing Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+announce as</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+NT</code> or <CODE CLASS="literal">
+Win95</code> or <CODE CLASS="literal">
+WfW</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the operating system that Samba will announce itself as.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+NT</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+announce version</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the version of the operating system that Samba will announce itself as.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+4.2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+browseable (browsable)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows share to be displayed in list of machine resources.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+browse list</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will provide a browse list on this server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+auto services (preload)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (share list)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a list of shares that will always appear in the browse list.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+default service (default)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (share name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Names a share (service) that will be provided if the client requests a share not listed in <EM CLASS="emphasis">
+smb.conf.</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+local master</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will try to become a master browser on the local subnet.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lm announce</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code> or <CODE CLASS="literal">
+no</code> or <CODE CLASS="literal">
+auto</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Enables or disables LAN Manager style host announcements.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+auto</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lm interval</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the frequency in seconds that LAN Manager announcements will be made if activated.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+60</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+preferred master (prefered master)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will use the preferred master browser bit to attempt to become the local master browser.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+domain master</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will try to become the main browser master for the workgroup.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+os level</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the operating system level of Samba in an election for local master browser.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+remote browse sync</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of IP addresses)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Lists Samba servers to synchronize browse lists with.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+remote announce</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (IP address/ workgroup pairs)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Lists subnets and workgroups to send directed broadcast packets to, allowing Samba to appear to browse lists.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959886">
+5.1.5.1 announce as</a></h4><P CLASS="para">
+This global configuration option specifies the type of operating system that Samba will announce to other machines on the network. The default value for this option is <CODE CLASS="literal">
+NT</code>, which represents a Windows NT operating system. Other possible values are <CODE CLASS="literal">
+Win95</code>, which represents a Windows 95 operating system, and <CODE CLASS="literal">
+WfW</code> for a Windows for Workgroup operating system. You can override the default value with the following:</p><PRE CLASS="programlisting">
+[global]
+ announce as = Win95</pre><P CLASS="para">
+We recommend against changing the default value of this configuration option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959896">
+5.1.5.2 announce version</a></h4><P CLASS="para">
+This global option is frequently used with the <CODE CLASS="literal">
+announce</code> <CODE CLASS="literal">
+as</code> configuration option; it specifies the version of the operating system that Samba will announce to other machines on the network. The default value of this options is 4.2, which places itself above the current Windows NT version of 4.0. You can specify a new value with a global entry such as the following:</p><PRE CLASS="programlisting">
+[global]
+ announce version = 4.3</pre><P CLASS="para">
+We recommend against changing the default value of this configuration option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-38345">
+5.1.5.3 browseable</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+browseable</code> option (also spelled <CODE CLASS="literal">
+browsable</code>) indicates whether the share referenced should appear in the list of available resources of the machine on which it resides. This option is always set to <CODE CLASS="literal">
+yes</code> by default. If you wish to prevent the share from being seen in a client's browser, you can reset this option to <CODE CLASS="literal">
+no</code>.</p><P CLASS="para">
+Note that this does not prevent someone from accessing the share using other means, such as specifying a UNC location (<CODE CLASS="literal">//server/accounting)</code> in Windows Explorer. It only prevents the share from being listed under the machine's resources when being browsed.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959474">
+5.1.5.4 browse list</a></h4><P CLASS="para">You should never need to change this parameter from its default value of <CODE CLASS="literal">
+yes</code>. If your Samba server is acting as a local master browser (i.e., it has won the browsing election), you can use the global <CODE CLASS="literal">
+browse</code> <CODE CLASS="literal">
+list</code> option to instruct Samba to provide or withhold its browse list to all clients. By default, Samba always provides a browse list. You can withhold this information by specifying the following:</p><PRE CLASS="programlisting">
+[global]
+ browse list = no</pre><P CLASS="para">
+If you disable the browse list, clients cannot browse the names of other machines, their services, and other domains currently available on the network. Note that this won't make any particular machine inaccessible; if someone knows a valid machine name/address and a share on that machine, they can still connect to it explicitly using NET USE or by mapping a drive letter to it using Windows Explorer. It simply prevents information in the browse list from being retrieved by any client that requests it.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957885">
+5.1.5.5 auto services</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+auto</code> <CODE CLASS="literal">
+services</code> option, which is also called <CODE CLASS="literal">
+preload</code>, ensures that the specified shares are always visible in the browse list. One common use for this option is to advertise specific user or printer shares that are created by the <CODE CLASS="literal">
+[homes]</code> or <CODE CLASS="literal">
+[printers]</code> shares, but are not otherwise browsable.</p><P CLASS="para">
+This option works best with disk shares. If you wish to force each of your system printers (i.e., those listed in the printer capabilities file) into the browse list using this option, we recommend using the <CODE CLASS="literal">
+load</code> <CODE CLASS="literal">
+printers</code> option instead. Any shares listed with the <CODE CLASS="literal">
+auto</code> <CODE CLASS="literal">
+services</code> option will not be displayed if the <CODE CLASS="literal">
+browse</code> <CODE CLASS="literal">
+list</code> option is set to <CODE CLASS="literal">
+no</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-962615">
+5.1.5.6 default service</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+service</code> option (sometimes called <CODE CLASS="literal">
+default</code>) names a "last-ditch" share. If set to an existing share name, and a client requests a nonexistent disk or printer share, Samba will attempt to connect the user to the share specified by this option instead. The option is specified as follows:</p><PRE CLASS="programlisting">
+default service = helpshare</pre><P CLASS="para">
+Note that there are no braces surrounding the share name <CODE CLASS="literal">
+helpshare</code>, even though the definition of the share later in the Samba configuration file will have braces. Also, if you use the <CODE CLASS="literal">
+%S</code> variable in the share specified by this option, it will represent the requested, nonexistent share, not the default service. Any underscores (<CODE CLASS="literal">_</code>) specified in the request share will be converted to slashes (<CODE CLASS="literal">/</code>) when the variable is used.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957903">
+5.1.5.7 local master</a></h4><P CLASS="para">This global option specifies whether Samba will attempt to become the local master browser for the subnet when it starts up. If this option is set to <CODE CLASS="literal">
+yes</code>, Samba will take place in elections. However, setting this option by itself does not guarantee victory. (Other parameters, such as <CODE CLASS="literal">
+preferred</code> <CODE CLASS="literal">
+master</code> and <CODE CLASS="literal">
+os</code> <CODE CLASS="literal">
+level</code> help Samba win browsing elections.) If this option is set to <CODE CLASS="literal">
+no</code>, Samba will lose all browsing elections, no matter which values are specified by the other configuration options. The default value is <CODE CLASS="literal">
+yes</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957907">
+5.1.5.8 lm announce</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+lm</code> <CODE CLASS="literal">
+announce</code> option tells Samba's <EM CLASS="emphasis">
+nmbd</em> whether or not to send LAN Manager host announcements on behalf of the server. These host announcements may be required by older clients, such as IBM's OS/2 operating system. This announcement allows the server to be added to the browse lists of the client. If activated, Samba will announce itself repetitively at the number of seconds specified by the <CODE CLASS="literal">
+lm</code> <CODE CLASS="literal">
+interval</code> option.</p><P CLASS="para">
+This configuration option takes the standard boolean values, <CODE CLASS="literal">
+yes</code> and <CODE CLASS="literal">
+no</code>, which engage or disengage LAN Manager announcements, respectively. In addition, there is a third option, <CODE CLASS="literal">
+auto</code>, which causes <EM CLASS="emphasis">
+nmbd</em> to passively listen for LAN Manager announcements, but not send any of its own initially. If LAN Manager announcements are detected for another machine on the network, <EM CLASS="emphasis">
+nmbd</em> will start sending its own LAN Manager announcements to ensure that it is visible. You can specify the option as follows:</p><PRE CLASS="programlisting">
+[global]
+ lm announce = yes</pre><P CLASS="para">
+The default value is <CODE CLASS="literal">
+auto</code>. You probably won't need to change this value from its default.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959967">
+5.1.5.9 lm interval</a></h4><P CLASS="para">
+This option, which is used in conjunction with <CODE CLASS="literal">
+lm</code> <CODE CLASS="literal">
+announce</code>, indicates the number of seconds <EM CLASS="emphasis">
+nmbd</em> will wait before repeatedly broadcasting LAN Manager-style announcements. Remember that LAN Manager announcements must be activated in order for this option to be used. The default value is 60 seconds. If you set this value to 0, Samba will not send any LAN Manager host announcements, no matter what the value of the <CODE CLASS="literal">
+lm</code> <CODE CLASS="literal">
+announce</code> option. You can reset the value of this option as follows:</p><PRE CLASS="programlisting">
+[global]
+ lm interval = 90</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959947">
+5.1.5.10 preferred master</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+preferred</code> <CODE CLASS="literal">
+master</code> option requests that Samba set the preferred master bit when participating in an election. This gives the server a higher preferred status in the workgroup than other machines at the same operating system level. If you are configuring your Samba machine to become the local master browser, it is wise to set the following value:</p><PRE CLASS="programlisting">
+[global]
+ preferred master = yes</pre><P CLASS="para">
+Otherwise, you should leave it set to its default, <CODE CLASS="literal">
+no</code>. If Samba is configured as a preferred master browser, it will force an election when it first comes online.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957912">
+5.1.5.11 os level</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+os</code> <CODE CLASS="literal">
+level</code> option dictates the operating system level at which Samba will masquerade during a browser election. If you wish to have Samba win an election and become the master browser, you can set the level above that of the operating system on your network with the highest current value. The values are shown in Table 5-1. The default level is 0, which means that Samba will lose all elections. If you wish Samba to win all elections, you can reset its value as follows:</p><PRE CLASS="programlisting">
+os level = 34</pre><P CLASS="para">
+This means that the server will vote for itself 34 times each time an election is called, which ensures a victory.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957960">
+5.1.5.12 domain master</a></h4><P CLASS="para">
+If Samba is the primary domain controller for your workgroup or NT domain, it should also be the domain master browser. The domain master browser is a special machine that has the NetBIOS resource type &lt;1B&gt; and is used to propagate browse lists to and from each of the local master browsers in individual subnets across the domain. To force Samba to become the domain master browser, set the following in the <CODE CLASS="literal">
+[global]</code> section of the <I CLASS="filename">
+smb.conf</i>:</p><PRE CLASS="programlisting">
+[global]
+ domain master = yes</pre><P CLASS="para">
+If you have a Windows NT server on the network acting as a primary domain controller (PDC), we recommend that you do not use Samba to become the domain master browser. The reverse is true as well: if Samba is taking on the responsibilities of a PDC, we recommend making it the domain master browser. Splitting the PDC and the domain master browser will cause unpredictable errors to occur on the network.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957965">
+5.1.5.13 remote browse sync</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+remote</code> <CODE CLASS="literal">
+browse</code> <CODE CLASS="literal">
+sync</code> option specifies that Samba should synchronize its browse lists with local master browsers in other subnets. However, the synchronization can occur only with other Samba servers, and not with Windows computers. For example, if your Samba server was a master browser on the subnet 192.168.235, and Samba local master browsers existed on other subnets at 192.168.234.92 and 192.168.236.2, you could specify the following:</p><PRE CLASS="programlisting">
+remote browse sync = 192.168.234.92 192.168.236.2 </pre><P CLASS="para">
+The Samba server would then directly contact the other machines on the address list and synchronize browse lists. You can also say:</p><PRE CLASS="programlisting">
+remote browse sync = 192.168.234.255 192.168.236.255</pre><P CLASS="para">
+This forces Samba to broadcast queries to determine the IP addresses of the local master browser on each subnet, with which it will then synchronize browse lists. This only works, however, if your router doesn't block directed broadcast requests ending in 255.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-957971">
+5.1.5.14 remote announce</a></h4><P CLASS="para">
+Samba servers are capable of providing browse lists to foreign subnets with the <CODE CLASS="literal">
+remote</code> <CODE CLASS="literal">
+announce</code> option. This is typically sent to the local master browser of the foreign subnet in question. However, if you do not know the address of the local master browser, you can do the following:</p><PRE CLASS="programlisting">
+[global]
+ remote announce = 192.168.234.255/ACCOUNTING \
+ 192.168.236.255/ACCOUNTING</pre><P CLASS="para">
+With this, Samba will broadcast host announcements to all machines on subnets 192.168.234 and 192.168.236, which will hopefully reach the local master browser of the subnet. You can also specify exact IP addresses, if they are known.</p></div></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch04_08.html" TITLE="4.8 Logging Configuration Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 4.8 Logging Configuration Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_02.html" TITLE="5.2 Filesystem Differences">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.2 Filesystem Differences" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+4.8 Logging Configuration Options</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+5.2 Filesystem Differences</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch05_02.html b/docs/htmldocs/using_samba/ch05_02.html
new file mode 100644
index 00000000000..462e23f3c09
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch05_02.html
@@ -0,0 +1,429 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 5] 5.2 Filesystem Differences</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:56Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_01.html" TITLE="5.1 Browsing">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.1 Browsing" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+Chapter 5<br>
+Browsing and Advanced Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_03.html" TITLE="5.3 File Permissions and Attributes on MS-DOS and Unix">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.3 File Permissions and Attributes on MS-DOS and Unix" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch05-34221">
+5.2 Filesystem Differences</a></h2><P CLASS="para">One of the biggest issues for which Samba has to correct is the difference between Unix and non-Unix filesystems. This includes items such as handling symbolic links, hidden files, and dot files. In addition, file permissions can also be a headache if not accounted for properly. This section describes how to use Samba to make up for some of those annoying differences, and even how to add some new functionality of its own.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-963262">
+5.2.1 Hiding and Vetoing Files</a></h3><P CLASS="para">There are some cases when we need to ensure that a user cannot see or access a file at all. Other times, we don't want to keep a user from accessing a file&nbsp;- we just want to hide it when they view the contents of the directory. On Windows systems, an attribute of files allows them to be hidden from a folder listing. With Unix, the traditional way of hiding files in a directory is to precede them with a dot (.). This prevents items such as configuration files or defaults from being seen when performing an ordinary <CODE CLASS="literal">
+ls</code> command. Keeping a user from accessing a file at all, however, involves working with permissions on files and or directories.</p><P CLASS="para">
+The first option we should discuss is the boolean <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+dot</code> <CODE CLASS="literal">
+files</code>. This option does exactly what it says. When set to <CODE CLASS="literal">
+yes</code>, the option treats files beginning with a period (.) as hidden. If set to <CODE CLASS="literal">
+no</code>, those files are always shown. The important thing to remember is that the files are only hidden. If the user has chosen to show all hidden files while browsing (e.g., using the Folder Options menu item under the View menu in Windows 98), they will still be able to see the files, as shown in <A CLASS="xref" HREF="ch05_02.html#ch05-77260">
+Figure 5.2</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-77260">
+Figure 5.2: Hidden files in the [data] share</a></h4><IMG CLASS="graphic" SRC="figs/sam.0502.gif" ALT="Figure 5.2"><P CLASS="para">
+Instead of simply hiding files beginning with a dot, you can also specify a string pattern to Samba for files to hide, using the <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> option. For example, let's assume that we specified the following in our example <CODE CLASS="literal">
+[data]</code> share:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ case sensitive = no
+ hide files = /*.java/*README*/</pre><P CLASS="para">
+Each entry for this option must begin, end, or be separated from another with a slash (/) character, even if there is only one pattern listed. This convention allows spaces to appear in filenames. In this example, the share directory would appear as shown in <A CLASS="xref" HREF="ch05_02.html#ch05-19743">
+Figure 5.3</a>. Again, note that we have set the Windows 98 option to view hidden files for the window. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-19743">
+Figure 5.3: Hiding files based on filename patterns</a></h4><IMG CLASS="graphic" SRC="figs/sam.0503.gif" ALT="Figure 5.3"><P CLASS="para">If we want to prevent users from seeing files at all, we can instead use the <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+files</code> option. This option, which takes the same syntax as the <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> option, specifies a list of files that should never be seen by the user. For example, let's change the <CODE CLASS="literal">
+[data]</code> share to the following:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ case sensitive = no
+ veto files = /*.java/*README*/</pre><P CLASS="para">
+The syntax of this option is identical to the <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> configuration option: each entry must begin, end, or be separated from another with a slash (<CODE CLASS="literal">/</code>) character, even if there is only one pattern listed. By doing so, the files <CODE CLASS="literal">
+hello.java</code> and <CODE CLASS="literal">
+README</code> will simply disappear from the directory, and the user will not be able to access them through SMB. </p><P CLASS="para">
+There is one other question that we need to address. What happens if the user tries to delete a directory that contains vetoed files? This is where the <CODE CLASS="literal">
+delete</code> <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+files</code> option comes in. If this boolean option is set to <CODE CLASS="literal">
+yes</code>, the user is allowed to delete both the regular files and the vetoed files in the directory, and the directory itself will be removed. If the option is set to <CODE CLASS="literal">
+no</code>, the user will not be able to delete the vetoed files, and consequently the directory will not be deleted either. From the user's perspective, the directory will appear to be empty, but cannot be removed.</p><P CLASS="para">
+The <CODE CLASS="literal">
+dont</code> <CODE CLASS="literal">
+descend</code> directive specifies a list of directories whose contents Samba should not allow to be visible. Note that we say <EM CLASS="emphasis">
+contents</em>, not the directory itself. Users will be able to enter a directory marked as such, but they are prohibited from descending the directory tree any farther&nbsp;- they will always see an empty folder. For example, let's use this option with a more basic form of the share that we defined earlier in the chapter:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ case sensitive = no
+ dont descend = config defaults</pre><P CLASS="para">
+In addition, let's assume that the <I CLASS="filename">
+/home/samba/data</i> directory has the following contents:</p><PRE CLASS="programlisting">
+drwxr-xr-x 6 tom users 1024 Jun 13 09:24 .
+drwxr-xr-x 8 root root 1024 Jun 10 17:53 ..
+-rw-r--r-- 2 tom users 1024 Jun 9 11:43 README
+drwxr-xr-x 3 tom users 1024 Jun 13 09:28 config
+drwxr-xr-x 3 tom users 1024 Jun 13 09:28 defaults
+drwxr-xr-x 3 tom users 1024 Jun 13 09:28 market</pre><P CLASS="para">
+If the user then connects to the share, he or she would see the directories shown in <A CLASS="xref" HREF="ch05_02.html#ch05-62659">
+Figure 5.4</a>. However, the contents of the <I CLASS="filename">
+/config</i> and <I CLASS="filename">
+/defaults</i> directories would appear empty to the user, even if other folders or files existed in them. In addition, users cannot write any data to the folder (which prevents them from creating a file or folder with the same name as one that is already there but invisible). If a user attempts to do so, he or she will receive an "Access Denied" message. <CODE CLASS="literal">
+dont</code> <CODE CLASS="literal">
+descend</code> is an administrative option, not a security option, and is not a substitute for good file permissions. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-62659">
+Figure 5.4: Contents of the [data] share with dont descend </a></h4><IMG CLASS="graphic" SRC="figs/sam.0504.gif" ALT="Figure 5.4"></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-963441">
+5.2.2 Links</a></h3><P CLASS="para">DOS and NT filesystems don't have symbolic links; Windows 95/98/NT systems approximate this with "shortcuts" instead. Therefore, when a client tries to open a symbolic link on a Samba server share, Samba attempts to follow the link to find the real file and let the client open it, as if he or she were on a Unix machine. If you don't want to allow this, set the <CODE CLASS="literal">
+follow</code> <CODE CLASS="literal">
+symlinks</code> option:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ case sensitive = no
+ follow symlinks = no</pre><P CLASS="para">
+You can test this by creating a directory on the Unix server inside the share as the user that you are logging in with. Enter the following commands:</p><PRE CLASS="programlisting">
+% <CODE CLASS="userinput"><B>mkdir hello; cd hello</b></code>
+% <CODE CLASS="userinput"><B>cat &quot;This is a test&quot; &gt;hello.txt</b></code>
+% <CODE CLASS="userinput"><B>ln -s hello.txt &quot;Link to hello&quot;</b></code></pre><P CLASS="para">
+This results in the two files shown in the window in <A CLASS="xref" HREF="ch05_02.html#ch05-36377">
+Figure 5.5</a>. Normally, if you click on either one, you will receive a file which has the text "This is a test" inside of it. However, with the <CODE CLASS="literal">
+follow</code> <CODE CLASS="literal">
+symlinks</code> option set to <CODE CLASS="literal">
+no</code>, you should receive an error similar to the dialog in <A CLASS="xref" HREF="ch05_02.html#ch05-36377">
+Figure 5.5</a> if you click on "Link to hello." </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-36377">
+Figure 5.5: An error dialog trying to follow symbolic links when forbidden by Samba</a></h4><IMG CLASS="graphic" SRC="figs/sam.0505.gif" ALT="Figure 5.5"><P CLASS="para">
+Finally, let's discuss the <CODE CLASS="literal">
+wide</code> <CODE CLASS="literal">
+links</code> option. This option, if set to <CODE CLASS="literal">
+yes</code>, allows the client user to follow symbolic links that point outside the shared directory tree, including files or directories at the other end of the link. For example, let's assume that we modified the <CODE CLASS="literal">
+[data]</code> share as follows:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ case sensitive = no
+ follow symlinks = yes
+ wide links = yes</pre><P CLASS="para">
+As long as the <CODE CLASS="literal">
+follow</code> <CODE CLASS="literal">
+symlinks</code> option is enabled, this will cause Samba to follow all symbolic links outside the current share tree. If we create a file outside the share (for example, in someone's home directory) and then create a link to it in the share as follows:</p><PRE CLASS="programlisting">
+ln -s ~tom/datafile ./datafile</pre><P CLASS="para">
+then you will be able to open the file in Tom's directory as per the target file's permissions.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-963127">
+5.2.3 Filesystem Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch05_02.html#ch05-48353">Table 5.4</a> shows a breakdown of the options we discussed earlier. We recommend the defaults for most, except those listed in the following descriptions. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-48353">
+Table 5.4: Filesystem Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+unix realname</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Provides Unix user's full name to client.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+dont descend</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of directories)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates a list of directories whose contents Samba should make invisible to clients.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+follow symlinks</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+no</code>, Samba will not honor symbolic links.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+getwd cache</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, Samba will use a cache for <CODE CLASS="literal">
+getwd()</code> calls.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+wide links</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, Samba will follow symbolic links outside the share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+hide dot files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, treats Unix hidden files as hidden files in Windows.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+hide files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of files)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+List of file patterns to treat as hidden.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+veto files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of files)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+List of file patterns to never show.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+delete veto files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, will delete files matched by <CODE CLASS="literal">
+veto files</code> when the directory they reside in is deleted.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958657">
+5.2.3.1 unix realname</a></h4><P CLASS="para">
+Some programs require a full username in order to operate. For example, a Windows email program often needs to associate a username with a given real name. If your system password file contains the real names of users in the GCOS field, the <CODE CLASS="literal">
+unix</code> <CODE CLASS="literal">
+realname</code> option instructs Samba to provide this information to clients. Without it, the name of the user will simply be his or her login ID. For example, if your Unix password file contains the following line:</p><PRE CLASS="programlisting">
+rcollins:/KaBfco47Rer5:500:500:Robert Collins:
+/home/rcollins:/bin/ksh</pre><P CLASS="para">
+And the option in the configuration file is:</p><PRE CLASS="programlisting">
+[global]
+ unix realname = yes</pre><P CLASS="para">
+then the name Robert Collins will be provided to any client that requests the real name of user <CODE CLASS="literal">
+rcollins</code>. You typically don't need to bother with this option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958929">
+5.2.3.2 dont descend</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+dont</code> <CODE CLASS="literal">
+descend</code> option can be used to specify various directories that should appear empty to the client. Note that the directory itself will still appear. However, Samba will not show any of the contents of the directory to the client user. This is not a good option to use as a security feature (a user could probably find a way around it); it really is meant only as a convenience to keep client users from browsing into directories that might have sensitive files. See our example earlier in this section.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958663">
+5.2.3.3 follow symlinks</a></h4><P CLASS="para">This option, which is discussed in greater detail earlier, controls whether Samba will follow a symbolic link in the Unix operating system to the target, or if it should return an error to the client user. If the option is set to <CODE CLASS="literal">
+yes</code>, the target of the link will be interpreted as the file.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-963512">
+5.2.3.4 getwd cache</a></h4><P CLASS="para">
+This global option specifies whether Samba should use a local cache for the Unix <CODE CLASS="literal">
+getwd()</code> (get current working directory) system call. You can override the default value of <CODE CLASS="literal">
+yes</code> as follows:</p><PRE CLASS="programlisting">
+[global]
+ getwd cache = no</pre><P CLASS="para">
+Setting this option to <CODE CLASS="literal">
+yes</code> can significantly increase the time it takes to resolve the working directory, especially if the <CODE CLASS="literal">
+wide</code> <CODE CLASS="literal">
+links</code> option is set to <CODE CLASS="literal">
+no</code>. You should normally not need to alter this option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-960186">
+5.2.3.5 wide links</a></h4><P CLASS="para">
+This option specifies whether the client user can follow symbolic links that point outside the shared directory tree. This includes any files or directories at the other end of the link, as long as the permissions are correct for the user. The default value for this option is <CODE CLASS="literal">
+yes</code>. Note that this option will not be honored if the <CODE CLASS="literal">
+follow</code> <CODE CLASS="literal">
+symlinks</code> options is set to <CODE CLASS="literal">
+no</code>. Setting this option to <CODE CLASS="literal">
+no</code> slows <EM CLASS="emphasis">
+smbd</em> considerably.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958655">
+5.2.3.6 hide files</a></h4><P CLASS="para">The <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> option provides one or more directory or filename patterns to Samba. Any file matching this pattern will be treated as a hidden file from the perspective of the client. Note that this simply means that the DOS hidden attribute is set, which may or may not mean that the user can actually see it while browsing.</p><P CLASS="para">
+Each entry in the list must begin, end, or be separated from another entry with a slash (<CODE CLASS="literal">/</code>) character, even if there is only one pattern listed. This allows spaces to appear in the list. Asterisks can be used as a wildcard to represent zero or more characters. Questions marks can be used to represent exactly one character. For example:</p><PRE CLASS="programlisting">
+hide files = /.jav*/README.???/</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-963549">
+5.2.3.7 hide dot files</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+dot</code> <CODE CLASS="literal">
+files</code> option hides any files on the server that begin with a dot (.) character, in order to mimic the functionality behind several shell commands that are present on Unix systems. Like <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code>, those files that begin with a dot have the DOS hidden attribute set, which doesn't necessarily guarantee that a client cannot view them. The default value for this option is <CODE CLASS="literal">
+yes</code>. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-963556">
+5.2.3.8 veto files</a></h4><P CLASS="para">
+More stringent than the hidden files state is the state provided by the <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+files</code> configuration option. Samba won't even admit these files exist. You cannot list or open them from the client. In reality, this isn't a trustworthy security option. It is actually a mechanism to keep PC programs from deleting special files, such as ones used to store the resource fork of a Macintosh file on a Unix filesystem. If both Windows and Macs are sharing the same files, this can prevent ill-advised power users from removing files the Mac users need.</p><P CLASS="para">
+The syntax of this option is identical to that of the <CODE CLASS="literal">
+hide</code> <CODE CLASS="literal">
+files</code> configuration option: each entry must begin, end, or be separated from another with a slash (/) character, even if only one pattern is listed. Asterisks can be used as a wildcard to represent zero or more characters. Questions marks can be used to represent exactly one character. For example:</p><PRE CLASS="programlisting">
+veto files = /*config/*default?/</pre><P CLASS="para">
+This option is primarily administrative&nbsp;- not a substitute for good file permissions.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958851">
+5.2.3.9 delete veto files</a></h4><P CLASS="para">This option tells Samba to delete vetoed files when a user attempts to delete the directory in which they reside. The default value is <CODE CLASS="literal">
+no</code>. This means if a user tries to delete a directory that contains a vetoed file, the file (and the directory) will not be deleted. Instead, the directory will remain and appear to be empty from the perspective of the user. If set to <CODE CLASS="literal">
+yes</code>, the directory and the vetoed files will be deleted.</p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_01.html" TITLE="5.1 Browsing">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.1 Browsing" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_03.html" TITLE="5.3 File Permissions and Attributes on MS-DOS and Unix">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.3 File Permissions and Attributes on MS-DOS and Unix" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+5.1 Browsing</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+5.3 File Permissions and Attributes on MS-DOS and Unix</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch05_03.html b/docs/htmldocs/using_samba/ch05_03.html
new file mode 100644
index 00000000000..aaa5648c6cb
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch05_03.html
@@ -0,0 +1,426 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 5] 5.3 File Permissions and Attributes on MS-DOS and Unix</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:32:58Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_02.html" TITLE="5.2 Filesystem Differences">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.2 Filesystem Differences" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+Chapter 5<br>
+Browsing and Advanced Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_04.html" TITLE="5.4 Name Mangling and Case">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.4 Name Mangling and Case" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch05-34062">
+5.3 File Permissions and Attributes on MS-DOS and Unix</a></h2><P CLASS="para">DOS was never intended to be a multiuser, networked operating system. Unix, on the other hand, was designed that way from the start. Consequently, there are inconsistencies and gaps in coverage between the two filesystems that Samba must not only be aware of, but also provide solutions for. One of the biggest gaps is how Unix and DOS handle permissions with files.</p><P CLASS="para">
+Let's take a look at how Unix assigns permissions. All Unix files have read, write, and execute bits for three classifications of users: owner, group, and world. These permissions can be seen at the extreme left-hand side when a <CODE CLASS="literal">
+ls</code> <CODE CLASS="literal">
+-al</code> command is issued in a Unix directory. For example:</p><PRE CLASS="programlisting">
+-rwxr--r-- 1 tom users 2014 Apr 13 14:11 access.conf </pre><P CLASS="para">
+Windows, on the other hand, has four principal bits that it uses with any file: read-only, system, hidden, and archive. You can view these bits by right-clicking on the file and choosing the Properties menu item. You should see a dialog similar to <A CLASS="xref" HREF="ch05_03.html#ch05-76568">
+Figure 5.6</a>.[<A CLASS="footnote" HREF="#ch05-pgfId-964268">1</a>] </p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch05-pgfId-964268">[1]</a> The system checkbox will probably be greyed for your file. Don't worry about that&nbsp;- you should still be able to see when the box is checked and when it isn't.</p></div></blockquote><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-76568">
+Figure 5.6: DOS and Windows file properties</a></h4><IMG CLASS="graphic" SRC="figs/sam.0506.gif" ALT="Figure 5.6"><P CLASS="para">
+The definition of each of those bits follows:</p><DL CLASS="variablelist">
+<DT CLASS="term">Read-only</dt><DD CLASS="listitem">
+<P CLASS="para">
+The file's contents can be read by a user but cannot be written to. </p></dd><DT CLASS="term">System</dt><DD CLASS="listitem">
+<P CLASS="para">
+This file has a specific purpose required by the operating system.</p></dd><DT CLASS="term">Hidden</dt><DD CLASS="listitem">
+<P CLASS="para">
+This file has been marked to be invisible to the user, unless the operating systems is explicitly set to show it.</p></dd><DT CLASS="term">Archive</dt><DD CLASS="listitem">
+<P CLASS="para">
+This file has been touched since the last DOS backup was performed on it.</p></dd></dl><P CLASS="para">
+Note that there is no bit to specify that a file is executable. DOS and Windows NT filesystems identify executable files by giving them the extensions .EXE, .COM, .CMD, or .BAT.</p><P CLASS="para">
+Consequently, there is no use for any of the three Unix executable bits that are present on a file in a Samba disk share. DOS files, however, have their own attributes that need to be preserved when they are stored in a Unix environment: the archive, system, and hidden bits. Samba can preserve these bits by reusing the executable permission bits of the file on the Unix side&nbsp;- if it is instructed to do so. Mapping these bits, however, has an unfortunate side-effect: if a Windows user stores a file in a Samba share, and you view it on Unix with the <CODE CLASS="literal">
+ls</code> <CODE CLASS="literal">
+-al</code> command, some of the executable bits won't mean what you'd expect them to.</p><P CLASS="para">
+Three Samba options decide whether the bits are mapped: <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+archive</code>, <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+system</code>, and <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+hidden</code>. These options map the archive, system, and hidden attributes to the owner, group, and world execute bits of the file, respectively. You can add these options to the <CODE CLASS="literal">
+[data]</code> share, setting each of their values as follows:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ map archive = yes
+ map system = yes
+ map hidden = yes</pre><P CLASS="para">
+After that, try creating a file in the share under Unix&nbsp;- such as <CODE CLASS="literal">
+hello.java</code>&nbsp;- and change the permissions of the file to 755. With these Samba options set, you should be able to check the permissions on the Windows side and see that each of the three values has been checked in the Properties dialog box. What about the read-only attribute? By default, Samba 2.0 sets this whenever a file does not have the Unix owner write permission bit set. In other words, you can set this bit by changing the permissions of the file to 555.</p><P CLASS="para">
+We should warn you that the default value of the <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+archive</code> option is <CODE CLASS="literal">
+yes</code>, while the other two options have a default value of <CODE CLASS="literal">
+no</code>. This is because many programs do not work properly if the archive bit is not stored correctly for DOS and Windows files. The system and hidden attributes, however, are not critical for a program's operation and are left to the discretion of the administrator.</p><P CLASS="para">
+<A CLASS="xref" HREF="ch05_03.html#ch05-56404">
+Figure 5.7</a> summarizes the Unix permission bits and illustrates how Samba maps those bits to DOS attributes. Note that the group read/write and world read/write bits do not directly translate to a DOS attribute, but they still retain their original Unix definitions on the Samba server. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-56404">
+Figure 5.7: How Samba and Unix view the permissions of a file</a></h4><IMG CLASS="graphic" SRC="figs/sam.0507.gif" ALT="Figure 5.7"><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-964095">
+5.3.1 Creation masks</a></h3><P CLASS="para">
+Samba has several options to help with file creation masks. File creation masks (or <I CLASS="firstterm">
+umasks</i>) help to define the permissions a file or directory will receive at the time it is created. In Unix, this means that you can control what permissions a file or directory does not have when it is created. For files accessed from Windows, this means you can disable the read-only, archive, system, and hidden attributes of a file as well.</p><P CLASS="para">
+For example, the <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+mask</code> option will force the permissions of a file created by a Windows client to be at most 744:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ create mask = 744</pre><P CLASS="para">
+while the <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+mask</code> option shown here will force the permissions of a newly created directory to be at most 755:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+ directory mask = 755</pre><P CLASS="para">
+Alternatively, you can also force various bits with the <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+mode</code> and <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+mode</code> options. These options will perform a logical OR against the file and directory creation masks, ensuring that those bits that are specified will always be set. You would typically set these options globally in order to ensure that group and world read/write permissions have been set appropriately for new files or directories in each share.</p><P CLASS="para">
+In the same spirit, if you wish to explicitly set the Unix user and group attributes of a file that is created on the Windows side, you can use the <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+user</code> and <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+group</code> options. For example:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+
+ create mask = 744
+ directory mask = 755
+ force user = joe
+ force group = accounting</pre><P CLASS="para">
+These options actually assign a static Unix user and group to each connection that is made to a share. However, this occurs <EM CLASS="emphasis">
+after</em> the client authenticates; it does not allow free access to a share. These options are frequently used for their side effects of assigning a specific user and group to each new file or directory that is created in a share. Use these options with discretion.</p><P CLASS="para">
+Finally, one of the capabilities of Unix that DOS lacks is the ability to delete a read-only file from a writable directory. In Unix, if a directory is writable, a read-only file in that directory can still be removed. This could permit you to delete files in any of your directories, even if the file was left by someone else.</p><P CLASS="para">
+DOS filesystems are not designed for multiple users, and so its designers decided that read-only means "protected against accidental change, including deletion," rather than "protected against some other user on a single-user machine." So the designers of DOS prohibited removal of a read-only file. Even today, Windows file systems exhibit the same behavior.</p><P CLASS="para">
+Normally, this is harmless. Windows programs don't try to remove read-only files because they know it's a bad idea. However, a number of source-code control programs&nbsp;- which were first written for Unix&nbsp;- run on Windows and require the ability to delete read-only files. Samba permits this behavior with the <CODE CLASS="literal">
+delete</code> <CODE CLASS="literal">
+readonly</code> option. In order to enable this functionality, set the option to <CODE CLASS="literal">
+yes</code>:</p><PRE CLASS="programlisting">
+[data]
+ path = /home/samba/data
+ browseable = yes
+ guest ok = yes
+ writeable = yes
+
+ create mask = 744
+ directory mask = 755
+ force user = joe
+ force group = accounting
+ delete readonly = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-964323">
+5.3.2 File and Directory Permission Options</a></h3><P CLASS="para">The options for file and directory permissions are summarized in <A CLASS="xref" HREF="ch05_03.html#ch05-96508">
+Table 5.5</a>; each option is then described in detail. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-96508">
+Table 5.5: File and Directory Permission Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+map archive</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Preserve DOS archive attribute in user execute bit (0100).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+map system</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Preserve DOS system attribute in group execute bit (0010).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+map hidden</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Preserve DOS hidden attribute in world execute bit (0001).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+create mask (create mode)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the maximum permissions for files created by Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0744</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+directory mask (directory mode)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the maximum permissions for directories created by Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0755</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+force create mode</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Forces the specified permissions (bitwise or) for directories created by Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0000</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+force directory mode</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Forces the specified permissions (bitwise or) for directories created by Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0000</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+force group (group)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (group name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the effective group for a user accessing this share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+force user</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (username)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the effective username for a user accessing this share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+delete readonly</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows a user to delete a read-only file from a writable directory.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961746">
+5.3.2.1 create mask</a></h4><P CLASS="para">
+The argument for this option is an octal number indicating which permission flags may be set at file creation by a client in a share. The default is 0755, which means the Unix owner can at most read, write, and optionally execute his or her own files, while members of the user's group and others can only read or execute them. If you need to change it for non-executable files, we recommend 0644, or <CODE CLASS="literal">
+rw-r--r--</code>. Keep in mind that the execute bits may be used by the server to map certain DOS file attributes, as described earlier. If you're altering the create mask, those bits have to be part of the create mask as well.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961749">
+5.3.2.2 directory mask</a></h4><P CLASS="para">
+The argument for this option is an octal number indicating which permission flags may be set at directory creation by a client in a share. The default is 0755, which allows everyone on the Unix side to at most read and traverse the directories, but allows only you to modify them. We recommend the mask 0750, removing access by world users.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961751">
+5.3.2.3 force create mode</a></h4><P CLASS="para">
+This option sets the permission bits that Samba will force to be set when a file permission change is made. It's often used to force group permissions, mentioned previously. It can also be used to preset any of the DOS attributes we mentioned: archive (0100), system (0010), or hidden (0001). This option always takes effect after the <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+archive</code>, <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+system </code>, <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+hidden</code>, and <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+mask</code> options.</p><P CLASS="para">
+Many Windows applications rename their data files to <EM CLASS="emphasis">
+datafile.bak</em> and create new ones, thus changing their ownership and permissions so that members of the same Unix group can't edit them. Setting <CODE CLASS="literal">
+force create mask = 0660</code> will keep the new file editable by members of the group.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961753">
+5.3.2.4 force directory mode</a></h4><P CLASS="para">
+This option sets the permission bits which Samba will force when a directory permission change is made or a directory is created. It's often used to force group permissions, as mentioned previously. This option defaults to 0000, and can be used just like the <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+mode</code> to add group or other permissions if needed. This option always takes effect after the <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+archive</code>, <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+system</code>, <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+hidden</code>, and <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+mask</code> options.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961755">
+5.3.2.5 force group</a></h4><P CLASS="para">
+This option, sometimes called <CODE CLASS="literal">
+group</code>, assigns a static group ID that will be used on all connections to a service after the client has successfully authenticated. This assigns a specific group to each new file or directory created from an SMB client.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961757">
+5.3.2.6 force user</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+force</code> <CODE CLASS="literal">
+user</code> option assigns a static user ID that will be used on all connections to a service after the client has successfully authenticated. This assigns a specific user to each new file or directory created from an SMB client.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961759">
+5.3.2.7 delete readonly</a></h4><P CLASS="para">This option allows a user to delete a directory containing a read-only file. By default, DOS and Windows will not allow such an operation. You probably will want to leave this option turned off unless a program needs this capability; many Windows users would be appalled to find that they'd accidentally deleted a file which they had set read-only. In fact, even the Unix <CODE CLASS="literal">
+rm</code> command will ask users if they really want to override the protection and delete read-only files. It's a good idea to have Samba be at least as cautious. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961826">
+5.3.2.8 map archive</a></h4><P CLASS="para">
+The DOS archive bit is used to flag a file that has been changed since it was last archived (e.g., backed up with the DOS archive program.) Setting the Samba option <CODE CLASS="literal">
+map</code> <CODE CLASS="literal">
+archive</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> causes the DOS archive flag to be mapped to the Unix execute-by-owner (0100) bit. It's best to leave this option on if your Windows users are doing their own backups, or are using programs that require the archive bit. Unix lacks the notion of an archive bit entirely. Backup programs typically keep a file that lists what files were backed up on what date, so comparing file modification dates serves the same purpose.</p><P CLASS="para">
+Setting this option to <CODE CLASS="literal">
+yes</code> causes an occasional surprise on Unix when a user notices that a data file is marked as executable, but rarely causes harm. If a user tries to run it, he or she will normally get a string of error messages as the shell tries to execute the first few lines as commands. The reverse is also possible; an executable Unix program looks like it hasn't been backed up recently on Windows. But again, this is rare, and is usually harmless. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961836">
+5.3.2.9 map system</a></h4><P CLASS="para">
+The DOS system attribute is used to indicate files that are required by the operating system, and should not be deleted, renamed, or moved without special effort. Set this option only if you need to store Windows system files on the Unix file server. Executable Unix programs will appear to be non-removable special Windows files when viewed from Windows clients. This may prove mildly inconvenient if you want to move or remove one. For most sites, however, this is fairly harmless.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-961845">
+5.3.2.10 map hidden</a></h4><P CLASS="para">DOS uses the hidden attribute to indicate that a file should not ordinarily be visible in directory listings. Unix doesn't have such a facility; it's up to individual programs (notably the shell) to decide what to display and what not to display. Normally, you won't have any DOS files that need to be hidden, so the best thing to do is to leave this option turned off.</p><P CLASS="para">
+Setting this option to <CODE CLASS="literal">
+yes</code> causes the server to map the hidden flag onto the executable-by-others bit (0001). This feature can produce a rather startling effect. Any Unix program that is executable by world seems to vanish when you look for it from a Windows client. If this option is not set, however, and a Windows user attempts to mark a file hidden on a Samba share, it will not work&nbsp;- Samba has no place to store the hidden attribute! </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_02.html" TITLE="5.2 Filesystem Differences">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.2 Filesystem Differences" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_04.html" TITLE="5.4 Name Mangling and Case">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.4 Name Mangling and Case" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+5.2 Filesystem Differences</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+5.4 Name Mangling and Case</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch05_04.html b/docs/htmldocs/using_samba/ch05_04.html
new file mode 100644
index 00000000000..e506445c103
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch05_04.html
@@ -0,0 +1,433 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 5] 5.4 Name Mangling and Case</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:01Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_03.html" TITLE="5.3 File Permissions and Attributes on MS-DOS and Unix">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.3 File Permissions and Attributes on MS-DOS and Unix" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+Chapter 5<br>
+Browsing and Advanced Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_05.html" TITLE="5.5 Locks and Oplocks">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.5 Locks and Oplocks" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch05-30534">
+5.4 Name Mangling and Case</a></h2><P CLASS="para">Back in the days of DOS and Windows 3.1, every filename was limited to eight upper-case characters, followed by a dot, and three more uppercase characters. This was known as the <I CLASS="firstterm">
+8.3 format</i>, and was a huge nuisance. Windows 95/98, Windows NT, and Unix have since relaxed this problem by allowing many more case-sensitive characters to make up a filename. <A CLASS="xref" HREF="ch05_04.html#ch05-24354">
+Table 5.6</a> shows the current naming state of several popular operating systems. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-24354">
+Table 5.6: Operating System Filename Limitations </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Operating System</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+File Naming Rules</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+DOS 6.22 or below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Eight characters followed by a dot followed by a three-letter extension (8.3 format); case insensitive</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 3.1 for Workgroups</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight characters followed by a dot followed by a three-letter extension (8.3 format); case insensitive</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 95/98</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+127 characters; case sensitive</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+127 characters; case sensitive</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Unix</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+255 characters; case sensitive</p></td></tr></tbody></table><P CLASS="para">Samba still has to remain backwards compatible with network clients who store files only in the 8.3 format, such as Windows for Workgroups. If a user creates a file on a share called <EM CLASS="emphasis">
+antidisestablishmentarianism.txt</em>, a Windows for Workgroups client couldn't tell it apart from another file in the same directory called <EM CLASS="emphasis">
+antidisease.txt</em>. Like Windows 95/98 and Windows NT, Samba has to employ a special methodology of translating a long filename to an 8.3 filename in such a way that similar filenames will not cause collisions. This is called <I CLASS="firstterm">
+name mangling</i>, and Samba deals with this in a manner that is similar, but not identical to, Windows 95 and its successors.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-959448">
+5.4.1 The Samba Mangling Operation</a></h3><P CLASS="para">Here is how Samba mangles a long filename into an 8.3 filename:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-959148">
+</a>If the original filename does not begin with a dot, up to the first five alphanumeric characters that occur before the last dot (if there is one) are converted to uppercase. These characters are used as the first five characters of the 8.3 mangled filename.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-959229">
+</a>If the original filename begins with a dot, the dot is removed and up to the first five alphanumeric characters that occur before the last dot (if there is one) are converted to uppercase. These characters are used as the first five characters of the 8.3 mangled filename.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-959228">
+</a>These characters are immediately followed a special mangling character: by default, a tilde (~), although Samba allows you to change this character.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-959149">
+</a>The base of the long filename before the last period is hashed into a two-character code; parts of the name after the last dot may be used if necessary. This two character code is appended to the 8.3 filename after the mangling character.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch05-pgfId-967828">
+</a>The first three characters after the last dot (if there is one) of the original filename are converted to uppercase and appended onto the mangled name as the extension. If the original filename began with a dot, three underscores (<CODE CLASS="literal">___</code>) are used as the extension instead.</p></li></ul><P CLASS="para">
+Here are some examples:</p><PRE CLASS="programlisting">
+virtuosity.dat VIRTU~F1.DAT
+.htaccess HTACC~U0.___
+hello.java HELLO~1F.JAV
+team.config.txt TEAMC~04.TXT
+antidisestablishmentarianism.txt ANTID~E3.TXT
+antidiseast.txt ANTID~9K.TXT</pre><P CLASS="para">
+Using these rules will allow Windows for Workgroups to differentiate the two files on behalf of the poor individual who is forced to see the network through the eyes of that operating system. Note that the same long filename should always hash to the same mangled name with Samba; this doesn't always happen with Windows. The downside of this approach is that there can still be collisions; however, the chances are greatly reduced.</p><P CLASS="para">
+You generally want to use the mangling configuration options with only the oldest clients. We recommend doing this without disrupting other clients by adding an <CODE CLASS="literal">
+include</code> directive to the <I CLASS="filename">
+smb.conf</i> file:</p><PRE CLASS="programlisting">
+[global]
+ include = /ucsr/local/samba/lib/smb.conf.%m</pre><P CLASS="para">
+This resolves to <I CLASS="filename">
+smb.conf.WfWg</i> when a Window for Workgroups client attaches. Now you can create a file <I CLASS="filename">
+/usr/local/samba/lib/smb.conf.WfWg</i> which might contain these options:</p><PRE CLASS="programlisting">
+[global]
+ case sensitive = no
+ default case = upper
+ preserve case = no
+ short preserve case = no
+ mangle case = yes
+ mangled names= yes</pre><P CLASS="para">
+If you are not using Windows for Workgroups 3.1, then you probably do not need to change any of these options from their defaults.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959447">
+5.4.1.1 Representing and resolving filenames with Samba</a></h4><P CLASS="para">Another item that we should point out is that there is a difference between how an operating system <EM CLASS="emphasis">
+represents</em> a file and how it <EM CLASS="emphasis">
+resolves</em> it. For example, if you've used Windows 95/98/NT, you have likely run across a file called <I CLASS="filename">
+README.TXT</i>. The file can be represented by the operating system entirely in uppercase letters. However, if you open an MS-DOS prompt and enter the command <CODE CLASS="literal">
+edit</code> <CODE CLASS="literal">
+readme.txt</code>, the all-caps file is loaded into the editing program, even though you typed the name in lowercase letters!</p><P CLASS="para">
+This is because the Windows 95/98/NT family of operating systems resolves files in a case-insensitive manner, even though the files are represented it in a case-sensitive manner. Unix-based operating systems, on the other hand, always resolve files in a case-sensitive manner; if you try to edit <I CLASS="filename">
+README.TXT</i> with the command <CODE CLASS="literal">
+vi</code> <CODE CLASS="literal">
+readme.txt</code>, you will likely be editing the empty buffer of a new file.</p><P CLASS="para">
+Here is how Samba handles case: if the <CODE CLASS="literal">
+preserve</code> <CODE CLASS="literal">
+case</code> is set to <CODE CLASS="literal">
+yes</code>, Samba will always use the case provided by the operating system for representing (not resolving) filenames. If it is set to <CODE CLASS="literal">
+no</code>, it will use the case specified by the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option. The same is true for <CODE CLASS="literal">
+short</code> <CODE CLASS="literal">
+preserve</code> <CODE CLASS="literal">
+case</code>. If this option is set to <CODE CLASS="literal">
+yes</code>, Samba will use the default case of the operating system for representing 8.3 filenames; otherwise it will use the case specified by the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option. Finally, Samba will always resolve filenames in its shares based on the value of the <CODE CLASS="literal">
+case</code> <CODE CLASS="literal">
+sensitive</code> option.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-970053">
+5.4.2 Mangling Options</a></h3><P CLASS="para">Samba allows you to give it more refined instructions on how it should perform name mangling, including those controlling the case sensitivity, the character inserted to form a mangled name, and the ability to manually map filenames from one format to another. These options are shown in <A CLASS="xref" HREF="ch05_04.html#ch05-47431">
+Table 5.7</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-47431">
+Table 5.7: Name Mangling Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+case sensitive</code></p><P CLASS="para">
+<CODE CLASS="literal">
+(casesignames)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will treat filenames as case-sensitive (Windows doesn't).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+default case</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+(<CODE CLASS="literal">upper</code> or <CODE CLASS="literal">
+lower</code>)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Case to assume as default (only used when preserve case is <CODE CLASS="literal">
+no</code>).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Lower</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+preserve case</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, keep the case the client supplied (i.e., do not convert to <CODE CLASS="literal">
+default case</code>).</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+short preserve case</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, preserve case of 8.3-format names that the client provides.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+mangle case</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Mangle a name if it is mixed case.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+mangled names</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Mangles long names into 8.3 DOS format.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+mangling char</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (single character)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Gives mangling character.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+~</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+mangled stack</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Number of mangled names to keep on the local mangling stack.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+50</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+mangled map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of patterns)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows mapping of filenames from one format into another.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-960977">
+5.4.2.1 case sensitive</a></h4><P CLASS="para">This share-level option, which has the obtuse synonym <CODE CLASS="literal">
+casesignames</code>, specifies whether Samba should preserve case when resolving filenames in a specific share. The default value for this option is <CODE CLASS="literal">
+no</code>, which is how Windows handles file resolution. If clients are using an operating system that takes advantage of case-sensitive filenames, you can set this configuration option to <CODE CLASS="literal">
+yes</code> as shown here:</p><PRE CLASS="programlisting">
+[accounting]
+ case sensitive = yes</pre><P CLASS="para">
+Otherwise, we recommend that you leave this option set to its default.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958897">
+5.4.2.2 default case</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option is used with <CODE CLASS="literal">
+preserve</code> <CODE CLASS="literal">
+case</code>. This specifies the default case (upper or lower) that Samba will use when it creates a file on one of its shares on behalf of a client. The default case is <CODE CLASS="literal">
+lower</code>, which means that newly created files will use the mixed-case names given to them by the client. If you need to, you can override this global option by specifying the following:</p><PRE CLASS="programlisting">
+[global]
+ default case = upper</pre><P CLASS="para">
+If you specify this value, the names of newly created files will be translated into uppercase, and cannot be overridden in a program. We recommend that you use the default value unless you are dealing with a Windows for Workgroups or other 8.3 client, in which case it should be <CODE CLASS="literal">
+upper</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958899">
+5.4.2.3 preserve case</a></h4><P CLASS="para">
+This option specifies whether a file created by Samba on behalf of the client is created with the case provided by the client operating system, or the case specified by the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> configuration option above. The default value is <CODE CLASS="literal">
+yes</code>, which uses the case provided by the client operating system. If it is set to <CODE CLASS="literal">
+no</code>, the value of the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option is used.</p><P CLASS="para">
+Note that this option does not handle 8.3 file requests sent from the client&nbsp;- see the <CODE CLASS="literal">
+short</code> <CODE CLASS="literal">
+preserve</code> <CODE CLASS="literal">
+case</code> option below. You may want to set this option to <CODE CLASS="literal">
+yes</code> if applications that create files on the Samba server are sensitive to the case used when creating the file. If you want to force Samba, for example, to mimic the behavior of a Windows NT filesystem, you can leave this option to its default, <CODE CLASS="literal">
+yes</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958901">
+5.4.2.4 short preserve case</a></h4><P CLASS="para">
+This option specifies whether an 8.3 filename created by Samba on behalf of the client is created with the default case of the client operating system, or the case specified by the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> configuration option. The default value is <CODE CLASS="literal">
+yes</code>, which uses the case provided by the client operating system. You can let Samba choose the case through the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> option by setting it as follows:</p><PRE CLASS="programlisting">
+[global]
+ short preserve case = no</pre><P CLASS="para">
+If you want to force Samba to mimic the behavior of a Windows NT filesystem, you can leave this option set to its default, <CODE CLASS="literal">
+yes</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958984">
+5.4.2.5 mangled names</a></h4><P CLASS="para">
+This share-level option specifies whether Samba will mangle filenames for 8.3 clients in that share. If the option is set to <CODE CLASS="literal">
+no</code>, Samba will not mangle the names and (depending on the client), they will either be invisible or appear truncated to those using 8.3 operating systems. The default value is <CODE CLASS="literal">
+yes</code>. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[data]
+ mangled names = no</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958903">
+5.4.2.6 mangle case</a></h4><P CLASS="para">
+This option tells Samba whether it should mangle filenames that are not composed entirely of the case specified using the <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+case</code> configuration option. The default for this option is <CODE CLASS="literal">
+no</code>. If you set it to <CODE CLASS="literal">
+yes</code>, you should be sure that all clients will be able to handle the mangled filenames that result. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[data]
+ mangle case = yes</pre><P CLASS="para">
+We recommend that you leave this option alone unless you have a well-justified need to change it.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958976">
+5.4.2.7 mangling char</a></h4><P CLASS="para">
+This share-level option specifies the mangling character used when Samba mangles filenames into the 8.3 format. The default character used is a tilde (~). You can reset it to whatever character you wish, for instance:</p><PRE CLASS="programlisting">
+[data]
+ mangling char = #</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959322">
+5.4.2.8 mangled stack</a></h4><P CLASS="para">
+Samba maintains a local stack of recently mangled 8.3 filenames; this stack can be used to reverse map mangled filenames back to their original state. This is often needed by applications that create and save a file, close it, and need to modify it later. The default number of long filename/mangled filename pairs stored on this stack is 50. However, if you want to cut down on the amount of processor time used to mangle filenames, you can increase the size of the stack to whatever you wish, at the expense of memory and slightly slower file access.</p><PRE CLASS="programlisting">
+[global]
+ mangled stack = 100</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959327">
+5.4.2.9 mangled map</a></h4><P CLASS="para">
+If the default behavior of name mangling is not sufficient, you can give Samba further instructions on how to behave using the <CODE CLASS="literal">
+mangled</code> <CODE CLASS="literal">
+map</code> option. This option allows you to specify mapping patterns that can be used before or even in place of name mangling performed by Samba. For example:</p><PRE CLASS="programlisting">
+[data]
+ mangled map =(*.database *.db) (*.class *.cls)</pre><P CLASS="para">
+Here, Samba is instructed to search each file it encounters for characters that match the first pattern specified in the parenthesis and convert them to the modified second pattern in the parenthesis for display on an 8.3 client. This is useful in the event that name mangling converts the filename incorrectly or to a format that the client cannot understand readily. Patterns are separated by whitespaces. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_03.html" TITLE="5.3 File Permissions and Attributes on MS-DOS and Unix">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.3 File Permissions and Attributes on MS-DOS and Unix" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_05.html" TITLE="5.5 Locks and Oplocks">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 5.5 Locks and Oplocks" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+5.3 File Permissions and Attributes on MS-DOS and Unix</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+5.5 Locks and Oplocks</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch05_05.html b/docs/htmldocs/using_samba/ch05_05.html
new file mode 100644
index 00000000000..b0298624f87
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch05_05.html
@@ -0,0 +1,399 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 5] 5.5 Locks and Oplocks</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:03Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_04.html" TITLE="5.4 Name Mangling and Case">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.4 Name Mangling and Case" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch05_01.html" TITLE="5. Browsing and Advanced Disk Shares ">
+Chapter 5<br>
+Browsing and Advanced Disk Shares </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6. Users, Security, and Domains " BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch05-75933">
+5.5 Locks and Oplocks</a></h2><P CLASS="para">Concurrent writes to a single file are not desirable in any operating system. To prevent this, most operating systems use <I CLASS="firstterm">
+locks</i> to guarantee that only one process can write to a file at a time. Operating systems traditionally lock entire files, although newer ones allow a range of bytes within a file to be locked. If another process attempts to write to a file (or section of one) that is already locked, it will receive an error from the operating system and will wait until the lock is released.</p><P CLASS="para">
+Samba supports the standard DOS and NT filesystem (deny-mode) locking requests, which allow only one process to write to an entire file on a server at a give time, as well as byte-range locking. In addition, Samba supports a new locking mechanism known in the Windows NT world as <I CLASS="firstterm">
+opportunistic locking&nbsp;- </i><EM CLASS="emphasis">
+oplock</em> for short.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-964663">
+5.5.1 Opportunistic Locking</a></h3><P CLASS="para">
+Opportunistic locking allows a client to notify the Samba server that it will not only be the exclusive writer of a file, but will also cache its changes to that file on its own machine (and not on the Samba server) in order to speed up file access for that client. When Samba knows that a file has been opportunistically locked by a client, it marks its version as having an opportunistic lock and waits for the client to complete work on the file, at which point it expects the client to send the final changes back to the Samba server for synchronization.</p><P CLASS="para">
+If a second client requests access to that file before the first client has finished working on it, Samba can send an <I CLASS="firstterm">
+oplock break</i> request to the first client. This tells the client to stop caching its changes and return the current state of the file to the server so that the interrupting client can use it as it sees fit. An opportunistic lock, however, is not a replacement for a standard deny-mode lock. It is not unheard of for the interrupting process to be granted an oplock break only to discover that the original process also has a deny-mode lock on a file as well. <A CLASS="xref" HREF="ch05_05.html#ch05-74304">
+Figure 5.8</a> illustrates this opportunistic locking process. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch05-74304">
+Figure 5.8: Opportunistic locking</a></h4><IMG CLASS="graphic" SRC="figs/sam.0508.gif" ALT="Figure 5.8"><P CLASS="para">
+In terms of locks, we highly recommend using the defaults provided by Samba: standard DOS/Windows deny-mode locks for compatibility and oplocks for the extra performance that local caching allows. If your operating system can take advantage of oplocks, it should provide significant performance improvements. Unless you have a specific reason for changing any of these options, it's best to leave them as they are.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch05-pgfId-969392">
+5.5.2 Unix and Locking</a></h3><P CLASS="para">Windows systems cooperate well to avoid overwriting each other's changes. But if a file stored on a Samba system is accessed by a Unix process, this process won't know a thing about Windows oplocks and could easily ride roughshod over a lock. Some Unix systems have been enhanced to understand the Windows oplocks maintained by Samba. Currently the support exists only in SGI Irix 6.5.2f and later; Linux and FreeBSD should soon follow.</p><P CLASS="para">
+If you have a system that understands oplocks, set <CODE CLASS="literal">
+kernel</code> <CODE CLASS="literal">
+oplocks</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in the Samba configuration file. That should eliminate conflicts between Unix processes and Windows users. </p><P CLASS="para">
+If your system does not support kernel oplocks, you could end up with corrupted data when somebody runs a Unix process that reads or writes a file that Windows users also access. However, Samba provides a rough protection mechanism in the absence of kernel oplocks: the <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+oplock</code> <CODE CLASS="literal">
+files</code> option. If you can anticipate which Samba files are used by both Windows users and Unix users, set their names in a <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+oplock</code> <CODE CLASS="literal">
+files</code> option. This will suppress the use of oplocks on matching filenames, which will supress client caching, and let the Windows and Unix programs use system locking or update times to detect competition for the same file. A sample option is: </p><PRE CLASS="programlisting">
+veto oplock files = /*.dbm/</pre><P CLASS="para">
+This option allows both Unix processes and Windows users to edit files ending in the suffix <EM CLASS="emphasis">
+.dbm</em>. Note that the syntax of this option is similar to <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+files</code>.</p><P CLASS="para">
+Samba's options for locks and oplocks are given in <A CLASS="xref" HREF="ch05_05.html#ch05-53407">
+Table 5.8</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-53407">
+Table 5.8: Locks and Oplocks Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+share modes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, turns on support for DOS-style whole-file locks.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+locking</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, turns on byte-range locks.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+strict locking</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, denies access to an entire file if a byte-range lock exists in it.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+oplocks</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, turn on local caching of files on the client for this share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+kernel oplocks</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, indicates that the kernel supports oplocks.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+fake oplocks</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, tells client the lock was obtained, but doesn't actually lock it.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+blocking locks </code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows lock requestor to wait for the lock to be granted.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+veto oplock files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of filenames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Does not oplock specified files.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lock directory</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the location where various Samba files, including locks, are stored.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+As specified in Samba makefile</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958552">
+5.5.2.1 share modes</a></h4><P CLASS="para">
+The most primitive locks available to Samba are deny-mode locks, known as <I CLASS="firstterm">
+share modes</i>, which are employed by programs such as text editors to avoid accidental overwriting of files. For reference, the deny-mode locks are listed in <A CLASS="xref" HREF="ch05_05.html#ch05-55885">
+Table 5.9</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch05-55885">
+Table 5.9: SMB Deny-Mode Locks </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Lock</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Description</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_NONE</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Do not deny any other file requests.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_ALL</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deny all open requests on the current file.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_READ</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deny any read-only open requests on the current file.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_WRITE</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Deny any write-only open requests on the current file.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_DOS</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If opened for reading, others can read but cannot write to the file. If opened for writing, others cannot open the file at all.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+DENY_FCB</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Obsolete.</p></td></tr></tbody></table><P CLASS="para">
+The <CODE CLASS="literal">
+share</code> <CODE CLASS="literal">
+modes</code> parameter, which enforces the use of these locks, is enabled by default. To disable it, use the following command:</p><PRE CLASS="programlisting">
+[accounting]
+ share modes = no</pre><P CLASS="para">
+We highly recommend against disabling the default locking mechanism unless you have a justifiable reason for doing so. Most Windows and DOS applications rely on these locking mechanisms in order to work correctly, and will complain bitterly if this functionality is taken away.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958557">
+5.5.2.2 locking</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+locking</code> option can be used to tell Samba to engage or disengage server-side byte-range locks on behalf of the client. Samba implements byte-range locks on the server side with normal Unix advisory locks and will consequently prevent other properly-behaved Unix processes from overwriting a locked byte range.</p><P CLASS="para">
+This option can be specified per share as follows:</p><PRE CLASS="programlisting">
+[accounting]
+ locking = yes</pre><P CLASS="para">
+If the <CODE CLASS="literal">
+locking</code> option is set to <CODE CLASS="literal">
+yes</code>, the requestor will be delayed until the holder of either type of lock releases it (or crashes). If, however, the option is set to <CODE CLASS="literal">
+no</code>, no byte-range locks will be kept for the files, although requests to lock and unlock files will appear to succeed. The option is set to <CODE CLASS="literal">
+yes</code> by default; however, you can turn this option off if you have read-only media.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-959694">
+5.5.2.3 strict locking</a></h4><P CLASS="para">
+This option checks every file access for a byte-range lock on the range of bytes being accessed. This is typically not needed if a client adheres to all the locking mechanisms in place. This option is set to <CODE CLASS="literal">
+no</code> by default; however, you can reset it per share as follows:</p><PRE CLASS="programlisting">
+[accounting]
+ strict locking = yes</pre><P CLASS="para">
+If this option is set to <CODE CLASS="literal">
+yes</code>, mandatory locks are enforced on any file with byte-range locks.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958563">
+5.5.2.4 blocking locks</a></h4><P CLASS="para">
+Samba also supports <I CLASS="firstterm">
+blocking locks</i>, a minor variant of range locks. Here, if the range of bytes is not available, the client specifies an amount of time that it's willing to wait. The server then caches the lock request, periodically checking to see if the file is available. If it is, it notifies the client; however, if time expires, Samba will tell the client that the request has failed. This strategy prevents the client from continually polling to see if the lock is available.</p><P CLASS="para">
+You can disable this option per share as follows:</p><PRE CLASS="programlisting">
+[accounting]
+ blocking locks = no</pre><P CLASS="para">
+When set to <CODE CLASS="literal">
+yes</code>, blocking locks will be enforced on the file. If this option is set to <CODE CLASS="literal">
+no</code>, Samba behaves as if normal locking mechanisms are in place on the file. The default is <CODE CLASS="literal">
+yes</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958571">
+5.5.2.5 oplocks</a></h4><P CLASS="para">
+This option enables or disables support for oplocks on the client. The option is enabled by default. However, you can disable it with the following command:</p><PRE CLASS="programlisting">
+[data]
+ oplocks = no</pre><P CLASS="para">
+If you are in an extremely unstable network environment or have many clients that cannot take advantage of opportunistic locking, it may be better to shut this Samba feature off. Oplocks should be disabled if you are accessing the same files from both Unix applications (such as <EM CLASS="emphasis">
+vi</em>) and SMB clients (unless you are lucky enough to have an operating system that supports kernel oplocks as discussed earlier).</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958575">
+5.5.2.6 fake oplocks</a></h4><P CLASS="para">
+Before opportunistic locking was available on Samba, the Samba daemons pretended to allow oplocks via the <CODE CLASS="literal">
+fake</code> <CODE CLASS="literal">
+oplocks</code> option. If this option was enabled, all clients were told that the file is available for opportunistic locking, and never warned of simultaneous access. This option is deprecated now that real oplocks are available on Samba.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958577">
+5.5.2.7 kernel oplocks</a></h4><P CLASS="para">
+If a Unix application separate from Samba tries to update a file that Samba has oplocked to a Windows client, it will likely succeed (depending on the operating system) and both Samba and the client will never be aware of it. However, if the local Unix operating system supports it, Samba can warn it of oplocked files, which can suspend the Unix process, notify the client via Samba to write its copy back, and only then allow the open to complete. Essentially, this means that the operating system kernel on the Samba system has the ability to handle oplocks as well as Samba.</p><P CLASS="para">
+You can enable this behavior with the <CODE CLASS="literal">
+kernel</code> <CODE CLASS="literal">
+oplocks</code> option, as follows:</p><PRE CLASS="programlisting">
+[global]
+ kernel oplocks = yes</pre><P CLASS="para">
+Samba can automatically detect kernel oplocks and use them if present. At the time of this writing, this feature is supported only by SGI Irix 6.5.2f and later. However, Linux and FreeBSD support are expected in the near future. A system without kernel oplocks will allow the Unix process to update the file, but the client programs will notice the change only at a later time, if at all. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-958581">
+5.5.2.8 veto oplock files</a></h4><P CLASS="para">
+You can provide a list of filenames that are never granted opportunistic locks with the <CODE CLASS="literal">
+veto</code> <CODE CLASS="literal">
+oplock</code> <CODE CLASS="literal">
+files</code> option. This option can be set either globally or on a per-share basis. For example:</p><PRE CLASS="programlisting">
+veto oplock files = /*.bat/*.htm/</pre><P CLASS="para">
+The value of this option is a series of patterns. Each pattern entry must begin, end, or be separated from another with a slash (/) character, even if there is only one pattern listed. Asterisks can be used as a wildcard to represent zero or more characters. Questions marks can be used to represent exactly one character.</p><P CLASS="para">
+We recommend that you disable oplocks on any files that are meant to be updated by Unix or are intended to be shared by several processes simultaneously.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch05-pgfId-960237">
+5.5.2.9 lock directory</a></h4><P CLASS="para">
+This option (sometimes called <CODE CLASS="literal">
+lock</code> <CODE CLASS="literal">
+dir</code>) specifies the location of a directory where Samba will store SMB deny-mode lock files. Samba stores other files in this directory as well, such as browse lists and its shared memory file. If WINS is enabled, the WINS database is written to this directory as well. The default for this option is specified in the Samba makefile; it is typically <I CLASS="filename">
+/usr/local/samba/var/locks</i>. You can override this location as follows:</p><PRE CLASS="programlisting">
+[global]
+ lock directory = /usr/local/samba/locks</pre><P CLASS="para">
+You typically would not need to override this option, unless you want to move the lock files to a more standardized location, such as <I CLASS="filename">
+/var/spool/locks</i>. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_04.html" TITLE="5.4 Name Mangling and Case">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.4 Name Mangling and Case" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6. Users, Security, and Domains " BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+5.4 Name Mangling and Case</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6. Users, Security, and Domains </td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_01.html b/docs/htmldocs/using_samba/ch06_01.html
new file mode 100644
index 00000000000..439e66f3944
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_01.html
@@ -0,0 +1,221 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] Users, Security, and Domains </title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:28Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_05.html" TITLE="5.5 Locks and Oplocks">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.5 Locks and Oplocks" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 6</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_02.html" TITLE="6.2 Controlling Access to Shares">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.2 Controlling Access to Shares" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch06-88749">
+6. Users, Security, and Domains </a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch06-92902" TITLE="6.1 Users and Groups">
+Users and Groups</a><br>
+<A CLASS="sect1" HREF="ch06_02.html" TITLE="6.2 Controlling Access to Shares">
+Controlling Access to Shares</a><br>
+<A CLASS="sect1" HREF="ch06_03.html" TITLE="6.3 Authentication Security">
+Authentication Security</a><br>
+<A CLASS="sect1" HREF="ch06_04.html" TITLE="6.4 Passwords">
+Passwords</a><br>
+<A CLASS="sect1" HREF="ch06_05.html" TITLE="6.5 Windows Domains">
+Windows Domains</a><br>
+<A CLASS="sect1" HREF="ch06_06.html" TITLE="6.6 Logon Scripts">
+Logon Scripts</a></p><P>
+</p></div><P CLASS="para">
+This chapter discusses how to configure users with the Samba server. This topic may seem straightforward at first, but you'll soon discover that there are several ancillary problems that can crop up. One issue that Samba administrators have difficulty with is user authentication&nbsp;- password and security problems are by far the most common support questions on the Samba mailing lists. Learning why various authentication mechanisms work on certain architectures (and don't on others) can save you a tremendous amount of time testing and debugging Samba users in the future.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch06-92902">
+6.1 Users and Groups</a></h2><P CLASS="para">Before we start, we need to warn you up front that if you are connecting to Samba with a Windows 98 or NT 4.0 Workstation SP3, you need to configure your server for encrypted passwords before you can make a connection; otherwise, the clients will refuse to connect to the Samba server. This is because each of those Windows clients sends encrypted passwords, and Samba needs to be configured to expect and decrypt them. We'll show you how to set up Samba for this task later in the chapter, assuming you haven't already tackled this problem in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>.</p><P CLASS="para">Let's start with a single user. The easiest way to set up a client user is to create a Unix account (and home directory) for that individual on the server, and notify Samba of the user's existence. You can do the latter by creating a disk share that maps to the user's home directory in the Samba configuration file, and restricting access to that user with the <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> option. For example:</p><PRE CLASS="programlisting">
+[dave]
+ path = /home/dave
+ comment = Dave's home directory
+ writeable = yes<B CLASS="emphasis.bold">
+ valid users = dave</b></pre><P CLASS="para">
+The <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> option lists the users that will be allowed to access the share. In this case, only the user <CODE CLASS="literal">
+dave</code> is allowed to access the share. In the previous chapters, we specified that any user could access a disk share using the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> parameter. Because we don't wish to allow guest access, that option is absent here. We could grant both authenticated users and guest users access to a specific share if we wanted to. The difference between the two typically involves access rights for each of the files. </p><P CLASS="para">
+Remember that you can abbreviate the user's home directory by using the <CODE CLASS="literal">
+%H</code> variable. In addition, you can use the Unix username variable <CODE CLASS="literal">
+%u</code> and/or the client username variable <CODE CLASS="literal">
+%U</code> in your options as well. For example<EM CLASS="emphasis"></em>:</p><PRE CLASS="programlisting">
+[dave]
+ comment = %U home directory
+ writeable = yes
+ valid users = dave
+ path = %H</pre><P CLASS="para">
+Both of these examples work as long as the Unix user that Samba uses to represent the client has read/write access to the directory referenced by the <CODE CLASS="literal">
+path</code> option. In other words, a client must first pass Samba's security mechanisms (e.g., encrypted passwords, the <CODE CLASS="literal">
+valid users</code> option, etc.) as well as the normal Unix file and directory permissions of its Unix-side user <EM CLASS="emphasis">
+before</em> it can gain read/write access to a share.</p><P CLASS="para">
+With a single user accessing a home directory, access permissions are taken care of when the operating system creates the user account. However, if you're creating a shared directory for group access, there are a few more steps you need to perform. Let's take a stab at a group share for the accounting department in the <EM CLASS="emphasis">
+smb.conf</em> file:</p><PRE CLASS="programlisting">
+[accounting]
+ comment = Accounting Department Directory
+ writeable = yes
+ valid users = @account
+ path = /home/samba/accounting
+ create mode = 0660
+ directory mode = 0770</pre><P CLASS="para">
+The first thing that you might notice we did differently is to specify <CODE CLASS="literal">
+@account</code> as the valid user instead of one or more individual usernames. This is shorthand for saying that the valid users are represented by the Unix group <CODE CLASS="literal">
+account</code>. These users will need to be added to the group entry <CODE CLASS="literal">
+account</code> in the system group file (<I CLASS="filename">/etc/group</i> or equivalent) to be recognized as part of the group. Once they are, Samba will recognize those users as valid users for the share.</p><P CLASS="para">
+In addition, you will need to create a shared directory that the members of the group can access, which is pointed to by the <CODE CLASS="literal">
+path</code> configuration option. Here are the Unix commands that create the shared directory for the accounting department (assuming <EM CLASS="emphasis">
+/home/samba</em> already exists):</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">#</code> mkdir /home/samba/accounting</b><B CLASS="emphasis.bold">
+<CODE CLASS="literal">#</code> chgrp account /home/samba/accounting</b><B CLASS="emphasis.bold">
+<CODE CLASS="literal">#</code> chmod 770 /home/samba/accounting</b></pre><P CLASS="para">
+There are two other options in this <I CLASS="filename">
+smb.conf</i> example, both of which we saw in the previous chapter. These options are <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+mode</code> and <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+mode</code>. These options set the maximum file and directory permissions that a new file or directory can have. In this case, we have denied all world access to the contents of this share. (This is reinforced by the <EM CLASS="emphasis">
+chmod</em> command, shown earlier.).</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-968835">
+6.1.1 The [homes] Share</a></h3><P CLASS="para">
+Let's return to user shares for a moment. If we have several users to set up home directory shares for, we probably want to use the special <CODE CLASS="literal">
+[homes]</code> share that we introduced in <a href="ch05_01.html"><b>Chapter 5, <CITE CLASS="chapter">Browsing and Advanced Disk Shares</cite></b></a>. With the <CODE CLASS="literal">
+[homes]</code> share, all we need to say is: </p><PRE CLASS="programlisting">
+[homes]
+<CODE CLASS="literal">
+ </code>browsable = no
+ writable = yes</pre><P CLASS="para">
+The <CODE CLASS="literal">
+[homes]</code> share is a special section of the Samba configuration file. If a user attempts to connect to an ordinary share that doesn't appear in the <I CLASS="filename">
+smb.conf</i> file (such as specifying it with a UNC in Windows Explorer), Samba will search for a <CODE CLASS="literal">
+[homes]</code> share. If one exists, the incoming share name is assumed to be a username and is queried as such in the password database (<I CLASS="filename">/etc/passwd</i> or equivalent) file of the Samba server. If it appears, Samba assumes the client is a Unix user trying to connect to his or her home directory.</p><P CLASS="para">
+As an illustration, let's assume that <CODE CLASS="literal">
+sofia</code> is attempting to connect to a share called [<CODE CLASS="literal">sofia]</code> on the Samba server. There is no share by that name in the configuration file, but a <CODE CLASS="literal">
+[homes]</code> share exists and user <CODE CLASS="literal">
+sofia</code> is present in the password database, so Samba takes the following steps:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957527">
+</a>Samba creates a new disk share called <CODE CLASS="literal">
+[sofia]</code> with the <CODE CLASS="literal">
+path</code> specified in the <CODE CLASS="literal">
+[homes]</code> section. If there is no <CODE CLASS="literal">
+path</code> option specified in <CODE CLASS="literal">
+[homes]</code>, Samba initializes it to her home directory.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957528">
+</a>Samba initializes the new share's options from the defaults in <CODE CLASS="literal">
+[globals]</code>, and any overriding options in <CODE CLASS="literal">
+[homes]</code> with the exception of <CODE CLASS="literal">
+browseable</code>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957529">
+</a>Samba connects <CODE CLASS="literal">
+sofia</code>'s client to that share.</p></li></ol><P CLASS="para">
+The <CODE CLASS="literal">
+[homes]</code> share is a fast, painless way to create shares for your user community without having to duplicate the information from the password database file in the <I CLASS="filename">
+smb.conf</i> file. It does have some peculiarities, however, that we need to point out:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957531">
+</a>The <CODE CLASS="literal">
+[homes]</code> section can represent any account on the machine, which isn't always desirable. For example, it can potentially create a share for <EM CLASS="emphasis">
+root</em>, <EM CLASS="emphasis">
+bin</em>, <EM CLASS="emphasis">
+sys</em>, <EM CLASS="emphasis">
+uucp</em>, and the like. (You can set a global <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> option to protect against this.)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957533">
+</a>The meaning of the <CODE CLASS="literal">
+browseable</code> configuration option is different from other shares; it indicates only that a <CODE CLASS="literal">
+[homes]</code> section won't show up in the local browse list, not that the <CODE CLASS="literal">
+[alice]</code> share won't. When the <CODE CLASS="literal">
+[alice]</code> section is created (after the initial connection), it will use the browsable value from the <CODE CLASS="literal">
+[globals]</code> section for that share, not the value from <CODE CLASS="literal">
+[homes]</code>.</p></li></ul><P CLASS="para">
+As we mentioned, there is no need for a path statement in <CODE CLASS="literal">
+[homes]</code> if the users have Unix home directories in the server's <I CLASS="filename">
+/etc/passwd</i> file. You should ensure that a valid home directory does exist, however, as Samba will not automatically create a home directory for a user, and will refuse a tree connect if the user's directory does not exist or is not accessible. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch05_05.html" TITLE="5.5 Locks and Oplocks">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 5.5 Locks and Oplocks" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_02.html" TITLE="6.2 Controlling Access to Shares">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.2 Controlling Access to Shares" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+5.5 Locks and Oplocks</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6.2 Controlling Access to Shares</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_02.html b/docs/htmldocs/using_samba/ch06_02.html
new file mode 100644
index 00000000000..a5b7bf4d520
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_02.html
@@ -0,0 +1,423 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] 6.2 Controlling Access to Shares</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:37Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_01.html" TITLE="6.1 Users and Groups">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.1 Users and Groups" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+Chapter 6<br>
+Users, Security, and Domains </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_03.html" TITLE="6.3 Authentication Security">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.3 Authentication Security" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch06-27678">
+6.2 Controlling Access to Shares</a></h2><P CLASS="para">Often you will need to restrict the users who can access a specific share for security reasons. This is very easy to do with Samba since it contains a wealth of options for creating practically any security configuration. Let's introduce a few configurations that you might want to use in your own Samba setup.</p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Again, if you are connecting with Windows 98 or NT 4.0 with Service Pack 3 (or above), those clients will send encrypted passwords to the Samba server. If Samba is not configured for this, it will continually refuse the connection. This chapter describes how to set up Samba for encrypted passwords. See the <A CLASS="xref" HREF="ch06_04.html">
+Section 6.4, Passwords</a> section.</p></blockquote><P CLASS="para">
+We've seen what happens when you specify valid users. However, you are also allowed to specify a list of invalid users&nbsp;- users who should never be allowed access to Samba or its shares. This is done with the <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> option. We hinted at one frequent use of this option earlier: a global default with the <CODE CLASS="literal">
+[homes]</code> section to ensure that various system users and superusers cannot be forged for access. For example:</p><PRE CLASS="programlisting">
+[global]
+ invalid users = root bin daemon adm sync shutdown \
+ halt mail news uucp operator gopher
+ auto services = dave peter bob
+
+[homes]
+ browsable = no
+ writeable = yes</pre><P CLASS="para">
+The <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> option, like <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code>, can take group names as well as usernames. In the event that a user or group appears in both lists, the <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> option takes precedence and the user or group will be denied access to the share.</p><P CLASS="para">
+At the other end of the spectrum, you can explicitly specify users who will be allowed superuser (root) access to a share with the <CODE CLASS="literal">
+admin</code> <CODE CLASS="literal">
+users</code> option. An example follows:</p><PRE CLASS="programlisting">
+[sales]
+ path = /home/sales
+ comment = Fiction Corp Sales Data
+ writeable = yes
+ valid users = tom dick harry
+ admin users = mike</pre><P CLASS="para">
+This option takes both group names and usernames. In addition, you can specify NIS netgroups by preceding them with an <CODE CLASS="literal">
+@</code> as well; if the netgroup is not found, Samba will assume that you are referring to a standard Unix group. </p><P CLASS="para">
+Be careful if you assign an entire group administrative privileges to a share. The Samba team highly recommends you avoid using this option, as it essentially gives root access to the specified users or groups for that share.</p><P CLASS="para">
+If you wish to force read-only or read-write access to users who access a share, you can do so with the <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+list</code> and <CODE CLASS="literal">
+write</code> <CODE CLASS="literal">
+list</code> options, respectively. These options can be used on a per-share basis to restrict a writable share or grant write access to specific users in a read-only share, respectively. For example:</p><PRE CLASS="programlisting">
+[sales]
+ path = /home/sales
+ comment = Fiction Corp Sales Data
+ read only = yes
+ write list = tom dick</pre><P CLASS="para">
+The <CODE CLASS="literal">
+write</code> <CODE CLASS="literal">
+list</code> option cannot override Unix permissions. If you've created the share without giving the write-list user write permission on the Unix system, he or she will be denied write access regardless of the setting of <CODE CLASS="literal">
+write</code> <CODE CLASS="literal">
+list</code>.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-968870">
+6.2.1 Guest Access</a></h3><P CLASS="para">As mentioned earlier, you can specify users who have guest access to a share. The options that control guest access are easy to work with. The first option, <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code>, specifies the Unix account that guest users should be assigned when connecting to the Samba server. The default value for this is set during compilation, and is typically <CODE CLASS="literal">
+nobody</code>. However, you may want to reset the guest user to <CODE CLASS="literal">
+ftp</code> if you have trouble accessing various system services. </p><P CLASS="para">
+If you wish to restrict access in a share only to guests&nbsp;- in other words, all clients connect as the guest account when accessing the share&nbsp;- you can use the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+only</code> option in conjunction with the <CODE CLASS="literal">
+guest ok</code> option, as shown in the following example:</p><PRE CLASS="programlisting">
+[sales]
+ path = /home/sales
+ comment = Fiction Corp Sales Data
+ writeable = yes
+ guest ok = yes
+ guest account = ftp
+ guest only = yes</pre><P CLASS="para">
+Make sure you specify <CODE CLASS="literal">
+yes</code> for both <CODE CLASS="literal">
+guest only</code> and <CODE CLASS="literal">
+guest ok</code> in this scenario; otherwise, Samba will not use the guest acount that you specify.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-960007">
+6.2.2 Access Control Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch06_02.html#ch06-28077">Table 6.1</a> summarizes the options that you can use to control access to shares. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-28077">
+Table 6.1: Share-level Access Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+admin users</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users who can perform operations as root.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+valid users</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users that can connect to a share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+invalid users</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users that will be denied access to a share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+read list</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users that have read-only access to a writable share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+write list</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users that have read-write access to a read-only share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max connections</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates the maximum number of connections for a share at a given time.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+guest only (only guest)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies that this share allows only guest access.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+guest account</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (name of account)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Names the Unix account that will be used for guest access.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+nobody</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959222">
+6.2.2.1 admin users</a></h4><P CLASS="para">
+This option specifies a list of users that perform file operations as if they were <CODE CLASS="literal">
+root</code>. This means that they can modify or destroy any other user's work, no matter what the permissions. Any files that they create will have root ownership and will use the default group of the admin user. The <CODE CLASS="literal">
+admin</code> <CODE CLASS="literal">
+users</code> option is used to allow PC users to act as administrators for particular shares. We urge you to avoid this option. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960368">
+6.2.2.2 valid users and invalid users</a></h4><P CLASS="para">
+These two options let you enumerate the users and groups who are granted or denied access to a particular share. You can enter a list of comma-delimited users, or indicate an NIS or Unix group name by prefixing the name with an at-sign (<CODE CLASS="literal">@</code>). </p><P CLASS="para">
+The important rule to remember with these options is that any name or group in the <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> list will <EM CLASS="emphasis">
+always</em> be denied access, even if it is included (in any form) in the <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> list. By default, neither option has a value associated with it. If both options have no value, any user is allowed to access the share.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959243">
+6.2.2.3 read list and write list</a></h4><P CLASS="para">
+Like the <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> <CODE CLASS="literal">
+and</code> <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> options, this pair of options specifies which users have read-only access to a writeable share and read-write access to a read-only share, respectively. The value of either options is a list of users. <CODE CLASS="literal">
+read</code> <CODE CLASS="literal">
+list</code> overrides any other Samba permissions granted&nbsp;- as well as Unix file permissions on the server system&nbsp;- to deny users write access. <CODE CLASS="literal">
+write</code> <CODE CLASS="literal">
+list</code> overrides other Samba permissions to grant write access, but cannot grant write access if the user lacks write permissions for the file on the Unix system. You can specify NIS or Unix group names by prefixing the name with an at sign (such as <CODE CLASS="literal">
+@users</code>). Neither configuration option has a default value associated with it.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959253">
+6.2.2.4 max connections</a></h4><P CLASS="para">
+This option specifies the maximum number of client connections that a share can have at any given time. Any connections that are attempted after the maximum is reached will be rejected. The default value is <CODE CLASS="literal">
+0</code>, which means that an unlimited number of connections are allowed. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[accounting]
+ max connections = 30</pre><P CLASS="para">
+This option is useful in the event that you need to limit the number of users who are accessing a licensed program or piece of data concurrently.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-958842">
+6.2.2.5 guest only</a></h4><P CLASS="para">
+This share-level option (sometimes called <CODE CLASS="literal">
+only</code> <CODE CLASS="literal">
+guest</code>) forces a connection to a share to be performed with the user specified by the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> option. The share to which this is applied must explicitly specify <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in order for this option to be recognized by Samba. The default value for this option is <CODE CLASS="literal">
+no</code>. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960637">
+6.2.2.6 guest account</a></h4><P CLASS="para">
+This option specifies the name of account to be used for guest access to shares in Samba. The default for this option varies from system to system, but it is often set to <CODE CLASS="literal">
+nobody</code>. Some default user accounts have trouble connecting as guest users. If that occurs on your system, the Samba team recommends using the ftp account as the guest user. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-959934">
+6.2.3 Username Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch06_02.html#ch06-82964">Table 6.2</a> shows two additional options that Samba can use to correct for incompatibilities in usernames between Windows and Unix. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-82964">
+Table 6.2: Username Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+username map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the name of the username mapping file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+username level</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates the number of capital letters to use when trying to match a username.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959982">
+6.2.3.1 username map</a></h4><P CLASS="para">Client usernames on an SMB network can be relatively large (up to 255 characters), while usernames on a Unix network often cannot be larger than eight characters. This means that an individual user may have one username on a client and another (shorter) one on the Samba server. You can get past this issue by<I CLASS="firstterm">
+ mapping</i> a free-form client username to a Unix username of eight or fewer characters. It is placed in a standard text file, using a format that we'll describe shortly. You can then specify the pathname to Samba with the global <CODE CLASS="literal">
+username</code> <CODE CLASS="literal">
+map</code> option. Be sure to restrict access to this file; make the root user the file's owner and deny write access to others. Otherwise, an untrusted user who can access the file can easily map their client username to the root user of the Samba server.</p><P CLASS="para">
+You can specify this option as follows:</p><PRE CLASS="programlisting">
+[global]
+ username map = /etc/samba/usermap.txt</pre><P CLASS="para">
+Each of the entries in the username map file should be listed as follows: the Unix username, followed by an equal sign (<CODE CLASS="literal">=</code>), followed by one or more whitespace-separated SMB client usernames. Note that unless instructed otherwise, (i.e., a guest connection), Samba will expect both the client and the server user to have the same password. You can also map NT groups to one or more specific Unix groups using the <CODE CLASS="literal">
+@</code> sign. Here are some examples:</p><PRE CLASS="programlisting">
+jarwin = JosephArwin
+manderso = MarkAnderson
+users = @account</pre><P CLASS="para">
+Also, you can use the asterisk to specify a wildcard that matches any free-form client username as an entry in the username map file:</p><PRE CLASS="programlisting">
+nobody = *</pre><P CLASS="para">
+Comments in the file can be specified as lines beginning with (<CODE CLASS="literal">#</code>) and (<CODE CLASS="literal">;</code>).</p><P CLASS="para">
+Note that you can also use this file to redirect one Unix user to another user. Be careful if you do so because Samba and your client may not notify the user that the mapping has been made and Samba may be expecting a different password. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959994">
+6.2.3.2 username level</a></h4><P CLASS="para">SMB clients (such as Windows) will often send usernames in SMB connection requests entirely in capital letters; in other words, client usernames are not necessarily case sensitive. On a Unix server, however, usernames <EM CLASS="emphasis">
+are</em> case sensitive: the user <CODE CLASS="literal">
+ANDY</code> is different from the user <CODE CLASS="literal">
+andy</code>. By default, Samba attacks this problem by doing the following:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-959996">
+</a>Checking for a user account with the exact name sent by the client</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-969146">
+</a>Testing the username in all lowercase letters</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-969147">
+</a>Testing the username in lowercase letters with only the first letter capitalized</p></li></ol><P CLASS="para">
+If you wish to have Samba attempt more combinations of uppercase and lowercase letters, you can use the <CODE CLASS="literal">
+username</code> <CODE CLASS="literal">
+level</code> global configuration option. This option takes an integer value that specifies how many letters in the username should be capitalized when attempting to connect to a share. You can specify this options as follows:</p><PRE CLASS="programlisting">
+[global]
+ username level = 3</pre><P CLASS="para">
+In this case, Samba will then attempt all permutations of usernames it can compute having three capital letters. The larger the number, the more computations Samba will have to perform to match the username and the longer the authentication will take. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_01.html" TITLE="6.1 Users and Groups">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.1 Users and Groups" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_03.html" TITLE="6.3 Authentication Security">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.3 Authentication Security" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.1 Users and Groups</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6.3 Authentication Security</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_03.html b/docs/htmldocs/using_samba/ch06_03.html
new file mode 100644
index 00000000000..a9e1b7ace71
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_03.html
@@ -0,0 +1,384 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] 6.3 Authentication Security</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:44Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_02.html" TITLE="6.2 Controlling Access to Shares">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.2 Controlling Access to Shares" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+Chapter 6<br>
+Users, Security, and Domains </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_04.html" TITLE="6.4 Passwords">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.4 Passwords" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch06-88596">
+6.3 Authentication Security</a></h2><P CLASS="para">At this point, we should discuss how Samba authenticates users. Each user who attempts to connect to a share that does not allow guest access must provide a password to make a successful connection. What Samba does with that password&nbsp;- and consequently the strategy Samba will use to handle user authentication&nbsp;- is the arena of the <CODE CLASS="literal">
+security</code> configuration option. There are currently four security levels that Samba supports on its network: <I CLASS="firstterm">
+share</i>, <I CLASS="firstterm">
+user</i>, <I CLASS="firstterm">
+server</i>, and <I CLASS="firstterm">
+domain</i>.</p><DL CLASS="variablelist">
+<DT CLASS="term">Share-level security</dt><DD CLASS="listitem">
+<P CLASS="para">
+Each share in the workgroup has one or more passwords associated with it. Anyone who knows a valid password for the share can access it.</p></dd><DT CLASS="term">User-level security</dt><DD CLASS="listitem">
+<P CLASS="para">
+Each share in the workgroup is configured to allow access from certain users. With each initial tree connection, the Samba server verifies users and their passwords to allow them access to the share.</p></dd><DT CLASS="term">
+Server-level security</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is the same as user-level security, except that the Samba server uses a separate SMB server to validate users and their passwords before granting access to the share.</p></dd><DT CLASS="term">Domain-level security</dt><DD CLASS="listitem">
+<P CLASS="para">
+Samba becomes a member of a Windows domain and uses the domain's primary domain controller (PDC) to perform authentication. Once authenticated, the user is given a special token that allows him or her access to any share with appropriate access rights. With this token, the PDC will not have to revalidate the user's password each time he or she attempts to access another share within the domain.</p></dd></dl><P CLASS="para">
+Each of these security policies can be implemented with the global <CODE CLASS="literal">
+security</code> option, as shown in <A CLASS="xref" HREF="ch06_03.html#ch06-73905">
+Table 6.3</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-73905">
+Table 6.3: Security Option </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+security</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">domain</code>, <CODE CLASS="literal">
+server</code>, <CODE CLASS="literal">
+share</code>, or <CODE CLASS="literal">
+user</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates the type of security that the Samba server will use.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+user</code> (Samba 2.0) or <CODE CLASS="literal">
+share</code> (Samba 1.9)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-957225">
+6.3.1 Share-level Security</a></h3><P CLASS="para">With share-level security, each share has one or more passwords associated with it. This differs from the other modes of security in that there are no restrictions as to whom can access a share, as long as that individual knows the correct password. Shares often have multiple passwords. For example, one password may grant read-only access, while another may grant read-write access, and so on. Security is maintained as long as unauthorized users do not discover the password for a share to which they shouldn't have access.</p><P CLASS="para">OS/2 and Window 95/98 both support share-level security on their resources. You can set up share-level security with Windows 95/98 by first enabling share-level security using the Access Control tab of the Network Control Panel dialog. Then select the Share-level Access Control radio button (which deselects the user-level access control radio button), as shown in <A CLASS="xref" HREF="ch06_03.html#ch06-33100">
+Figure 6.1</a>, and press the OK button. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-33100">
+Figure 6.1: Selecting share-level security on a Windows machine</a></h4><IMG CLASS="graphic" SRC="figs/sam.0601.gif" ALT="Figure 6.1"><P CLASS="para">
+Next, right click on a resource&nbsp;- such as a hard drive or a CD-ROM&nbsp;- and select the Properties menu item. This will bring up the Resource Properties dialog box. Select the Sharing tab at the top of the dialog box and enable the resource as Shared As. From here, you can configure how the shared resource will appear to individual users, as well as assigning whether the resource will appear as read-only, read-write, or a mix, depending on the password that is supplied.</p><P CLASS="para">
+You might be thinking that this security model is not a good fit for Samba&nbsp;- and you would be right. In fact, if you set the <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+share</code> option in the Samba configuration file, Samba will still reuse the username/passwords combinations in the system password files to authenticate access. More precisely, Samba will take the following steps when a client requests a connection using share-level security:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957239">
+</a>When a connection is requested, Samba will accept the password and (if sent) the username of the client.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-958140">
+</a>If the share is <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+only</code>, the user is immediately granted access to the share with the rights of the user specified by the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> parameter; no password checking is performed.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957243">
+</a>For other shares, Samba appends the username to a list of users who are allowed access to the share. It then attempts to validate the password given in association with that username. If successful, Samba grants the user access to the share with the rights assigned to that user. The user will not need to authenticate again unless a <CODE CLASS="literal">
+revalidate</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option has been set inside the share.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957257">
+</a>If the authentication is unsuccessful, Samba will attempt to validate the password against the list of users it has previously compiled throughout the attempted connections, as well as any specified under the share in the configuration file. If the password does not match any usernames (as specified in the system password file, typically <I CLASS="filename">
+/etc/passwd</i>), the user is not granted access to the share under that username.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-958141">
+</a>However, if the share has a <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> or <CODE CLASS="literal">
+public</code> option set, the user will default to access with the rights of the user specified by the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> option.</p></li></ol><P CLASS="para">
+You can indicate in the configuration file which users should be initially placed on the share-level security user list by using the <CODE CLASS="literal">
+username</code> configuration option, as shown below:</p><PRE CLASS="programlisting">
+[global]
+ security = share
+[accounting1]
+ path = /home/samba/accounting1
+ guest ok = no
+ writable = yes
+ username = davecb, pkelly, andyo</pre><P CLASS="para">
+Here, when a user attempts to connect to a share, Samba will verify the password that was sent against each of the users in its own list, in addition to the passwords of users <CODE CLASS="literal">
+davecb</code>, <CODE CLASS="literal">
+pkelly</code>, and <CODE CLASS="literal">
+andyo</code>. If any of the passwords match, the connection will be verified and the user will be allowed. Otherwise, connection to the specific share will fail.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960345">
+6.3.1.1 Share Level Security Options</a></h4><P CLASS="para">
+<A CLASS="xref" HREF="ch06_03.html#ch06-80998">
+Table 6.4</a> shows the options typically associated with share-level security. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-80998">
+Table 6.4: Share-Level Access Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+only user</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether usernames specified by <CODE CLASS="literal">
+username</code> will be the only ones allowed.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+username </code>(user or users)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (list of usernames)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a list of users against which a client's password will be tested. </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960350">
+6.3.1.2 only user</a></h4><P CLASS="para">
+This boolean option indicates whether Samba will allow connections to a share using share-level security based solely on the individuals specified in the <CODE CLASS="literal">
+username</code> option, instead of those users compiled on Samba's internal list. The default value for this option is <CODE CLASS="literal">
+no</code>. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[global]
+ security = share
+[data]
+ username = andy, peter, valerie
+ only user = yes</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960355">
+6.3.1.3 username</a></h4><P CLASS="para">
+This option presents a list of users against which Samba will test a connection password to allow access. It is typically used with clients that have share-level security to allow connections to a particular service based solely on a qualifying password&nbsp;- in this case, one that matches a password set up for a specific user:</p><PRE CLASS="programlisting">
+[global]
+ security = share
+[data]
+ username = andy, peter, terry</pre><P CLASS="para">
+We recommend against using this option unless you are implementing a Samba server with share-level security. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-957260">
+6.3.2 User-level Security</a></h3><P CLASS="para">The preferred mode of security with Samba is <I CLASS="firstterm">
+user-level security</i>. With this method, each share is assigned specific users that can access it. When a user requests a connection to a share, Samba authenticates by validating the given username and password with the authorized users in the configuration file and the passwords in the password database of the Samba server. As mentioned earlier in the chapter, one way to isolate which users are allowed access to a specific share is by using the <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> option for each share:</p><PRE CLASS="programlisting">
+[global]
+ security = user
+[accounting1]
+ writable = yes
+ valid users = bob, joe, sandy</pre><P CLASS="para">
+Each of the users listed will be allowed to connect to the share if the password provided matches the password stored in the system password database on the server. Once the initial authentication succeeds, the user will not need to re-enter a password again to access that share unless the <CODE CLASS="literal">
+revalidate</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option has been set.</p><P CLASS="para">Passwords can be sent to the Samba server in either an encrypted or a non-encrypted format. If you have both types of systems on your network, you should ensure that the passwords represented by each user are stored both in a traditional account database and Samba's encrypted password database. This way, authorized users can gain access to their shares from any type of client.[<A CLASS="footnote" HREF="#ch06-pgfId-968956">1</a>] However, we recommend that you move your system to encrypted passwords and abandon non-encrypted passwords if security is an issue. The <A CLASS="xref" HREF="ch06_04.html">
+Section 6.4</a> section of this chapter explains how to use encrypted as well as non-encrypted passwords.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch06-pgfId-968956">[1]</a> Having both encrypted and non-encrypted password clients on your network is another reason why Samba allows you to include (or not include) various options in the Samba configuration file based on the client operating system or machine name variables. </p></div></blockquote></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-957282">
+6.3.3 Server-level Security</a></h3><P CLASS="para">Server-level security is similar to user-level security. However, with server-level security, Samba delegates password authentication to another SMB password server, typically another Samba server or a Windows NT Server acting as a PDC on the network. Note that Samba still maintains its list of shares and their configuration in its <I CLASS="filename">
+smb.conf</i> file. When a client attempts to make a connection to a particular share, Samba validates that the user is indeed authorized to connect to the share. Samba will then attempt to validate the password by contacting the SMB password server through a known protocol and presenting the username and password to the SMB password server. If the password is accepted, a session will be established with the client. See <A CLASS="xref" HREF="ch06_03.html#ch06-89929">
+Figure 6.2</a> for an illustration of this setup. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-89929">
+Figure 6.2: A typical system setup using server level security</a></h4><IMG CLASS="graphic" SRC="figs/sam.0602.gif" ALT="Figure 6.2"><P CLASS="para">
+You can configure Samba to use a separate password server under server-level security with the use of the <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+server</code> global configuration option, as follows:</p><PRE CLASS="programlisting">
+[global]
+ security = server
+ password server = PHOENIX120 HYDRA134</pre><P CLASS="para">
+Note that you can specify more than one machine as the target of the <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+server</code>; Samba will move down the list of servers in the event that its first choice is unreachable. The servers identified by the <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+server</code> option are given as NetBIOS names, not their DNS names or equivalent IP addresses. Also, if any of the servers reject the given password, the connection will automatically fail&nbsp;- Samba will not attempt another server.</p><P CLASS="para">
+One caveat: when using this option, you will still need an account representing that user on the regular Samba server. This is because the Unix operating system needs a username to perform various I/O operations. The preferable method of handling this is to give the user an account on the Samba server but disable the account's password by replacing it in the system password file (e.g., <I CLASS="filename">
+/etc/passwd </i>) with an asterisk (*).</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-957298">
+6.3.4 Domain-level Security</a></h3><P CLASS="para">Domain-level security is similar to server-level security. However, with domainlevel security, the Samba server is acting as a member of a Windows domain. Recall from Chapter 1 that each domain has a <I CLASS="firstterm">
+domain controller</i>, which is usually a Windows NT server offering password authentication. Including these controllers provides the workgroup with a definitive password server. The domain controllers keep track of users and passwords in their own security authentication module (SAM), and authenticates each user when he or she first logs on and wishes to access another machine's shares.</p><P CLASS="para">
+As mentioned earlier in this chapter, Samba has a similar ability to offer user-level security, but this option is Unix-centric and assumes that the authentication occurs via Unix password files. If the Unix machine is part of a NIS or NIS+ domain, Samba will authenticate the users transparently against a shared password file, in typical Unix fashion. Samba then provides access to the NIS or NIS+ domain from Windows. There is, of course, no relationship between the NIS concept of a domain and the Windows concept of a domain.</p><P CLASS="para">With domain-level security, we now have the option of using the native NT mechanism. This has a number of advantages:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963199">
+</a>It provides far better integration with NT: there are fewer "kludges" in the <I CLASS="filename">
+smb.conf</i> options dealing with domains than with most Windows features. This allows more extensive use of NT management tools, such as the User Manager for Domains tool allowing PC support individuals to treat Samba servers as if they were large NT machines.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963200">
+</a>With the better integration comes protocol and code cleanups, allowing the Samba team to track the evolving NT implementation. NT Service Pack 4 corrects several problems in the protocol, and Samba's better integration makes it easier to track and adapt to these changes.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963202">
+</a>There is less overhead on the PDC because there is one less permanent network connection between it and the Samba server. Unlike the protocol used by the <CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+server</code> option, the Samba server can make a Remote Procedure Call (RPC) call only when it needs authentication information. It can not keep a connection permanently up just for that.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963203">
+</a>Finally, the NT domain authentication scheme returns the full set of user attributes, not just success or failure. The attributes include a longer, more network-oriented version of the Unix uid, NT groups, and other information. This includes:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963204">
+</a>Username</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963205">
+</a>Full name</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963206">
+</a>Description</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963207">
+</a>Security identifier (a domain-wide extension of the Unix uid)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963208">
+</a>NT group memberships</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963209">
+</a>Logon hours, and whether to force the user to log out immediately</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963210">
+</a>Workstations the user is allowed to use</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963211">
+</a>Account expiration date</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963212">
+</a>Home directory</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963213">
+</a>Login script</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963214">
+</a>Profile</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963215">
+</a>Account type</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963216">
+</a>The Samba developers used domain-level security in Samba version 2.0.4 to add and delete domain users on Samba servers semi-automatically. In addition, it adds room for other NT-like additions, such as supporting access control lists and changing permissions of files from the client.</p></li></ul><P CLASS="para">
+The advantage to this approach is less administration; there is only one authentication database to keep synchronized. The only local administration required on the Samba server will be creating directories for users to work in and <I CLASS="filename">
+/etc/passwd</i> entries to keep their UIDs and groups in. </p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-963191">
+6.3.4.1 Adding a Samba server to a Windows NT Domain</a></h4><P CLASS="para">
+If you already have an NT domain, you can easily add a Samba server to it. First, you will need to stop the Samba daemons. Then, add the Samba server to the NT domain on the PDC using the "Windows NT Server Manager for Domains" tool. When it asks for the computer type, choose "Windows NT Workstation or Server," and give it the NetBIOS name of the Samba server. This creates the machine account on the NT server.</p><P CLASS="para">
+Next, generate a Microsoft-format machine password using the <I CLASS="filename">
+smbpasswd</i> tool, which is explained in further detail in the next section. For example, if our domain is SIMPLE and the Windows NT PDC is <CODE CLASS="literal">
+beowulf</code>, we could use the following command on the Samba server to accomplish this:</p><PRE CLASS="programlisting">
+<CODE CLASS="literal">
+smbpasswd -j SIMPLE -r beowulf</code></pre><P CLASS="para">
+Finally, add the following options to the <CODE CLASS="literal">
+[global]</code> section of your <I CLASS="filename">
+smb.conf</i> and restart the Samba daemons.</p><PRE CLASS="programlisting">
+[global]
+ security = domain
+ domain logins = yes
+ workgroup = SIMPLE
+ password server = beowulf</pre><P CLASS="para">
+Samba should now be configured for domain-level security. The <CODE CLASS="literal">
+domain</code> <CODE CLASS="literal">
+logins</code> option is explained in more detail later in this chapter. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_02.html" TITLE="6.2 Controlling Access to Shares">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.2 Controlling Access to Shares" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_04.html" TITLE="6.4 Passwords">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.4 Passwords" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.2 Controlling Access to Shares</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6.4 Passwords</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_04.html b/docs/htmldocs/using_samba/ch06_04.html
new file mode 100644
index 00000000000..646c6128f40
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_04.html
@@ -0,0 +1,738 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] 6.4 Passwords</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:33:50Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_03.html" TITLE="6.3 Authentication Security">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.3 Authentication Security" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+Chapter 6<br>
+Users, Security, and Domains </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_05.html" TITLE="6.5 Windows Domains">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.5 Windows Domains" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch06-61393">
+6.4 Passwords</a></h2><P CLASS="para">Passwords are a thorny issue with Samba. So much so, in fact, that they are almost always the first major problem that users encounter when they install Samba, and generate by far the most questions sent to Samba support groups. In previous chapters, we've gotten around the need for passwords by placing the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> option in each of our configuration files, which allows connections without authenticating passwords. However, at this point, we need to delve deeper into Samba to discover what is happening on the network.</p><P CLASS="para">Passwords sent from individual clients can be either encrypted or non-encrypted. Encrypted passwords are, of course, more secure. A non-encrypted password can be easily read with a packet sniffing program, such as the modified <EM CLASS="emphasis">
+tcpdump</em> program for Samba that we used in <a href="ch03_01.html"><b>Chapter 3, <CITE CLASS="chapter">Configuring Windows Clients</cite></b></a>. Whether passwords are encrypted depends on the operating system that the client is using to connect to the Samba server. <A CLASS="xref" HREF="ch06_04.html#ch06-75183">
+Table 6.5</a> lists which Windows operating systems encrypt their passwords before sending them to the primary domain controller for authentication. If your client is not Windows, check the system documentation to see if SMB passwords are encrypted. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-75183">
+Table 6.5: Windows Operating Systems with Encrypted Passwords </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Operating System</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Encrypted or Non-encrypted</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+</code>Windows 95</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Non-encrypted</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 95 with SMB Update</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Encrypted</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 98</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Encrypted</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT 3.<EM CLASS="emphasis">
+x</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Non-encrypted</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT 4.0 before SP<CODE CLASS="literal">
+ 3</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Non-encrypted</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows NT 4.0 after SP 3</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Encrypted</p></td></tr></tbody></table><P CLASS="para">
+There are actually two different encryption methods used: one for Windows 95 and 98 clients that reuses Microsoft's LAN Manager encryption style, and a separate one for Windows NT clients and servers. Windows 95 and 98 use an older encryption system inherited from the LAN Manager network software, while Windows NT clients and servers use a newer encryption system.</p><P CLASS="para">
+If encrypted passwords are supported, Samba stores the encrypted passwords in a file called <I CLASS="filename">
+smbpasswd</i>. By default, this file is located in the <I CLASS="filename">
+private</i> directory of the Samba distribution (<I CLASS="filename">/usr/local/samba/private</i>). At the same time, the client stores an encrypted version of a user's password on its own system. The plaintext password is never stored on either system. Each system encrypts the password automatically using a known algorithm when the password is set or changed.</p><P CLASS="para">
+When a client requests a connection to an SMB server that supports encrypted passwords (such as Samba or Windows NT), the two computers undergo the following negotiations:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957427">
+</a>The client attempts to negotiate a protocol with the server.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957428">
+</a>The server responds with a protocol and indicates that it supports encrypted passwords. At this time, it sends back a randomly-generated 8-byte challenge string.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957433">
+</a>The client uses the challenge string as a key to encrypt its already encrypted password using an algorithm predefined by the negotiated protocol. It then sends the result to the server.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957436">
+</a>The server does the same thing with the encrypted password stored in its database. If the results match, the passwords are equivalent and the user is authenticated.</p></li></ol><P CLASS="para">
+Note that even though the original passwords are not involved in the authentication process, you need to be very careful that the encrypted passwords located inside of the <I CLASS="filename">
+smbpasswd</i> file are guarded from unauthorized users. If they are compromised, an unauthorized user can break into the system by replaying the steps of the previous algorithm. The encrypted passwords are just as sensitive as the plaintext passwords&nbsp;- this is known as <I CLASS="firstterm">
+plaintext-equivalent</i> data in the cryptography world. Of course, you should also ensure that the clients safeguard their plaintext-equivalent passwords as well.</p><P CLASS="para">
+You can configure Samba to accept encrypted passwords with the following global additions to <I CLASS="filename">
+smb.conf</i>. Note that we explicitly name the location of the Samba password file:</p><PRE CLASS="programlisting">
+[global]
+ security = user
+ encrypt passwords = yes
+ smb passwd file = /usr/local/samba/private/smbpasswd</pre><P CLASS="para">
+Samba, however, will not accept any users until the <I CLASS="filename">
+smbpasswd</i> file has been initialized.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-959309">
+6.4.1 Disabling encrypted passwords on the client</a></h3><P CLASS="para">While Unix authentication has been in use for decades, including the use of <EM CLASS="emphasis">
+telnet</em> and <EM CLASS="emphasis">
+rlogin</em> access across the Internet, it embodies well-known security risks. Plaintext passwords are sent over the Internet and can be retrieved from TCP packets by malicious snoopers. However, if you feel that your network is secure and you wish to use standard Unix <I CLASS="filename">
+/etc/passwd</i> authentication for all clients, you can do so, but you must disable encrypted passwords on those Windows clients that default to using them. </p><P CLASS="para">
+In order to do this, you must modify the Windows registry by installing two files on each system. Depending on the platform involved, the files are either <I CLASS="filename">
+NT4_PlainPassword.reg</i> or <I CLASS="filename">
+Win95_PlainPassword.reg</i>. You can perform this installation by copying the appropriate <I CLASS="filename">
+.reg</i> files from the Samba distribution's <I CLASS="filename">
+/docs</i> directory to a DOS floppy, and running it from the Run menu item on the client's Start Menu button. Incidentally, the Windows 95 <I CLASS="filename">
+.reg</i> file works fine on Windows 98 as well.</p><P CLASS="para">
+After you reboot the machine, the client will not encrypt its hashed passwords before sending them to the server. This means that the plaintext-equivalent passwords can been seen in the TCP packets that are broadcast across the network. Again, we encourage you not to do this unless you are absolutely sure that your network is secure.</p><P CLASS="para">
+If passwords are not encrypted, you can indicate as much in your Samba configuration file:</p><PRE CLASS="programlisting">
+[global]
+ security = user
+ encrypt passwords = no</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-17782">
+6.4.2 The smbpasswd File</a></h3><P CLASS="para">
+<I CLASS="filename">
+</i>Samba stores its encrypted passwords in a file called <I CLASS="filename">
+smbpasswd</i>, which by default resides in the <I CLASS="filename">
+/usr/local/samba/private</i> directory. The <I CLASS="filename">
+smbpasswd</i> file should be guarded as closely as the <I CLASS="filename">
+passwd</i> file; it should be placed in a directory to which only the root user has read/write access. All other users should not be able to read from the directory at all. In addition, the file should have all access closed off to all users except for root.</p><P CLASS="para">
+Before you can use encrypted passwords, you will need to create an entry for each Unix user in the <I CLASS="filename">
+smbpasswd</i> file. The structure of the file is somewhat similar to a Unix <I CLASS="filename">
+passwd</i> file, but has different fields. <A CLASS="xref" HREF="ch06_04.html#ch06-54128">
+Figure 6.3</a> illustrates the layout of the <I CLASS="filename">
+smbpasswd</i> file; the entry shown is actually one line in the file. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-54128">
+Figure 6.3: Structure of the smbpasswd file entry (actually one line)</a></h4><IMG CLASS="graphic" SRC="figs/sam.0603.gif" ALT="Figure 6.3"><P CLASS="para">
+Here is a breakdown of the individual fields:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+Username</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is the username of the account. It is taken directly from the system password file.</p></dd><DT CLASS="term">
+UID</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is the user ID of the account. Like the username, it is taken directly from the system password file and must match the user it represents there.</p></dd><DT CLASS="term">
+LAN Manager Password Hash</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is a 32-bit hexadecimal sequence that represents the password Windows 95 and 98 clients will use. It is derived by encrypting the string <CODE CLASS="literal">
+KGS!@#$%</code> with a 56-bit DES algorithm using the user's password (forced to 14 bytes and converted to capital letters) twice repeated as the key. If there is currently no password for this user, the first 11 characters of the hash will consist of the sequence <CODE CLASS="literal">
+NO</code> <CODE CLASS="literal">
+PASSWORD</code> followed by <CODE CLASS="literal">
+X</code> characters for the remainder. Anyone can access the share with no password. On the other hand, if the password has been disabled, it will consist of 32 <CODE CLASS="literal">
+X</code> characters. Samba will not grant access to a user without a password unless the <CODE CLASS="literal">
+null</code> <CODE CLASS="literal">
+passwords</code> option has been set.</p></dd><DT CLASS="term">
+NT Password Hash</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is a 32-bit hexadecimal sequence that represents the password Windows NT clients will use. It is derived by hashing the user's password (represented as a 16-bit little-endian Unicode sequence) with an MD4 hash. The password is not converted to uppercase letters first.</p></dd><DT CLASS="term">
+Account Flags</dt><DD CLASS="listitem">
+<P CLASS="para">
+This field consists of 11 characters between two braces ([]). Any of the following characters can appear in any order; the remaining characters should be spaces:</p><P CLASS="para">
+U</p><P CLASS="para">
+This account is a standard user account.</p><P CLASS="para">
+D</p><P CLASS="para">
+This account is currently disabled and Samba should not allow any logins.</p><P CLASS="para">
+N</p><P CLASS="para">
+This account has no password associated with it.</p><P CLASS="para">
+W</p><P CLASS="para">
+This is a workstation trust account that can be used to configure Samba as a primary domain controller (PDC) when allowing Windows NT machines to join its domain.</p></dd></dl><DL CLASS="variablelist">
+<DT CLASS="term">
+Last Change Time</dt><DD CLASS="listitem">
+<P CLASS="para">
+This code consists of the characters <CODE CLASS="literal">
+LCT-</code> followed by a hexidecimal representation of the amount of seconds since the epoch (midnight on January 1, 1970) that the entry was last changed.</p></dd></dl><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-957988">
+6.4.2.1 Adding entries to smbpasswd</a></h4><P CLASS="para">
+<I CLASS="filename">
+</i>There are a few ways you can add a new entry to the <I CLASS="filename">
+smbpasswd</i> file:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-961684">
+</a>You can use the <I CLASS="firstterm">
+smbpasswd</i> program with the <CODE CLASS="literal">
+-a</code> option to automatically add any user that currently has a standard Unix system account on the server. This program resides in the <I CLASS="filename">
+/usr/local/samba/bin</i> directory.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957867">
+</a>You can use the <I CLASS="firstterm">
+addtosmbpass</i> executable inside the <I CLASS="firstterm">
+/usr/local/samba/bin</i> directory. This is actually a simple <EM CLASS="emphasis">
+awk</em> script that parses a system password file and extracts the username and UID of each entry you wish to add to the SMB password file. It then adds default fields for the remainder of the user's entry, which can be updated using the <I CLASS="filename">
+smbpasswd</i> program later. In order to use this program, you will probably need to edit the first line of the file to correctly point to <EM CLASS="emphasis">
+awk</em> on your system.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957870">
+</a>In the event that the neither of those options work for you, you can create a default entry by hand in the <I CLASS="filename">
+smbpasswd</i> file. The entry should be entirely on one line. Each field should be colon-separated and should look similar to the following:</p></li></ul><PRE CLASS="programlisting">
+dave:500:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[U ]:LCT-00000000:</pre><P CLASS="para">
+This consists of the username and the UID as specified in the system password file, followed by two sets of exactly 32 <CODE CLASS="literal">
+X</code> characters, followed by the account flags and last change time as it appears above. After you've added this entry, you must use the <I CLASS="firstterm">
+smbpasswd</i> program to change the password for the user.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-958012">
+6.4.2.2 Changing the encrypted password</a></h4><P CLASS="para">If you need to change the encrypted password in the <I CLASS="filename">
+smbpasswd</i> file, you can also use the <I CLASS="filename">
+smbpasswd</i> program. Note that this program shares the same name as the encrypted password file itself, so be sure not to accidentally confuse the password file with the password-changing program.</p><P CLASS="para">
+The <I CLASS="filename">
+smbpasswd</i> program is almost identical to the <I CLASS="filename">
+passwd</i> program that is used to change Unix account passwords. The program simply asks you to enter your old password (unless you're the root user), and duplicate entries of your new password. No password characters are shown on the screen. </p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">#</code> smbpasswd dave</b>
+</pre><PRE CLASS="programlisting">
+Old SMB password:
+New SMB password:
+Retype new SMB password:
+Password changed for user dave</pre><P CLASS="para">
+You can look at the <I CLASS="filename">
+smbpasswd</i> file after this command completes to verify that both the LAN Manager and the NT hashes of the passwords have been stored in their respective positions. Once users have encrypted password entries in the database, they should be able to connect to shares using encrypted passwords!<I CLASS="filename">
+</i> </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-97004">
+6.4.3 Password Synchronization</a></h3><P CLASS="para">Having a regular password and an encrypted version of the same password can be troublesome when you need to change both of them. Luckily, Samba affords you a limited ability to keep your passwords synchronized. Samba has a pair of configuration options that can be used to automatically update a user's regular Unix password when the encrypted password is changed on the system. The feature can be activated by specifying the <CODE CLASS="literal">
+unix</code> <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+sync</code> global configuration option:</p><PRE CLASS="programlisting">
+[global]
+ encrypt passwords = yes
+ smb passwd file = /usr/local/samba/private/smbpasswd
+
+ unix password sync = yes</pre><P CLASS="para">
+With this option enabled, Samba will attempt to change the user's regular password (as <CODE CLASS="literal">
+root</code>) when the encrypted version is changed with <I CLASS="filename">
+smbpasswd</i>. However, there are two other options that have to be set correctly in order for this to work.</p><P CLASS="para">
+The easier of the two is <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+program</code>. This option simply specifies the Unix command used to change a user's standard system password. It is set to <CODE CLASS="literal">
+/bin/passw</code>d <CODE CLASS="literal">
+%u</code> by default. With some Unix systems, this is sufficient and you do not need to change anything. Others, such as Red Hat Linux, use <I CLASS="filename">
+/usr/bin/passwd</i> instead. In addition, you may want to change this to another program or script at some point in the future. For example, let's assume that you want to use a script called <CODE CLASS="literal">
+changepass</code> to change a user's password. Recall that you can use the variable <CODE CLASS="literal">
+%u</code> to represent the current Unix username. So the example becomes:</p><PRE CLASS="programlisting">
+[global]
+ encrypt passwords = yes
+ smb passwd file = /usr/local/samba/private/smbpasswd
+
+ unix password sync = yes
+ passwd program = changepass %u</pre><P CLASS="para">
+Note that this program will be called as the <CODE CLASS="literal">
+root</code> user when the <CODE CLASS="literal">
+unix</code> <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+sync</code> option is set to <CODE CLASS="literal">
+yes</code>. This is because Samba does not necessarily have the plaintext old password of the user. </p><P CLASS="para">
+The harder option to configure is <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code>. The <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> option works like a Unix chat script. It specifies a series of strings to send as well as responses to expect from the program specified by the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+program</code> option. For example, this is what the default <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> looks like. The delimiters are the spaces between each groupings of characters:</p><PRE CLASS="programlisting">
+passwd chat = *old*password* %o\n *new*password* %n\n *new*password* %n\n *changed*</pre><P CLASS="para">
+The first grouping represents a response expected from the password-changing program. Note that it can contain wildcards (*), which help to generalize the chat programs to be able to handle a variety of similar outputs. Here, <CODE CLASS="literal">
+*old*password*</code> indicates that Samba is expecting any line from the password program containing the letters <CODE CLASS="literal">
+old</code> followed by the letters <CODE CLASS="literal">
+password</code>, without regard for what comes on either side or between them. Once instructed to, Samba will wait indefinitely for such a match. Is Samba does not receive the expected response, the password will fail.</p><P CLASS="para">
+The second grouping indicates what Samba should send back once the data in the first grouping has been matched. In this case, you see <CODE CLASS="literal">
+%o\n</code>. This response is actually two items: the variable <CODE CLASS="literal">
+%o</code> represents the old password, while the <CODE CLASS="literal">
+\n</code> is a newline character. So, in effect, this will "type" the old password into the standard input of the password changing program, and then "press" Enter.</p><P CLASS="para">
+Following that is another response grouping, followed by data that will be sent back to the password changing program. (In fact, this response/send pattern continues indefinitely in any standard Unix <EM CLASS="emphasis">
+chat</em> script.) The script continues until the final pattern is matched.[<A CLASS="footnote" HREF="#ch06-pgfId-969009">2</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch06-pgfId-969009">[2]</a> This may not work under Red Hat Linux, as the password program typically responds "All authentication tokens updated successfully," instead of "Password changed." We provide a fix for this later in this section.</p></div></blockquote><P CLASS="para">
+You can help match the response strings sent from the password program with the characters listed in <A CLASS="xref" HREF="ch06_04.html#ch06-77246">
+Table 6.6</a>. In addition, you can use the characters listed in <A CLASS="xref" HREF="ch06_04.html#ch06-38512">
+Table 6.7</a> to help formulate your response. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-77246">
+Table 6.6: Password Chat Response Characters </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Character</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+*</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Zero or more occurrences of any character.</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+&quot; &quot;</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows you to include matching strings that contain spaces. Asterisks are still considered wildcards even inside of quotes, and you can represent a null response with empty quotes.</p></td></tr></tbody></table><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-38512">
+Table 6.7: Password Chat Send Characters </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Character</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%o</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The user's old password</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%n</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The user's new password</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\n</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The linefeed character</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\r</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The carriage-return character</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\t</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The tab character</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\s</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+A space</p></td></tr></tbody></table><P CLASS="para">
+For example, you may want to change your password chat to the following entry. This will handle scenarios in which you do not have to enter the old password. In addition, this will also handle the new <CODE CLASS="literal">
+all</code> <CODE CLASS="literal">
+tokens</code> <CODE CLASS="literal">
+updated</code> <CODE CLASS="literal">
+successfully</code> string that Red Hat Linux sends:</p><PRE CLASS="programlisting">
+passwd chat = *new password* %n\n *new password* %n\n *success*</pre><P CLASS="para">
+Again, the default chat should be sufficient for many Unix systems. If it isn't, you can use the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> <CODE CLASS="literal">
+debug</code> global option to set up a new chat script for the password change program. The <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> <CODE CLASS="literal">
+debug</code> option logs everything during a password chat. This option is a simple boolean, as shown below:</p><PRE CLASS="programlisting">
+[global]
+ encrypted passwords = yes
+ smb passwd file = /usr/local/samba/private/smbpasswd
+
+ unix password sync = yes
+ passwd chat debug = yes
+ log level = 100</pre><P CLASS="para">
+After you activate the password chat debug feature, all I/O received by Samba through the password chat will be sent to the Samba logs with a debug level of 100, which is why we entered a new log level option as well. As this can often generate multitudes of error logs, it may be more efficient to use your own script, by setting the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+program</code> option, in place of <I CLASS="filename">
+/bin/passwd</i> to record what happens during the exchange. Also, make sure to protect your log files with strict file permissions and to delete them as soon as you've grabbed the information you need, because they contain the passwords in plaintext.</p><P CLASS="para">
+The operating system on which Samba is running may have strict requirements for valid passwords in order to make them more impervious to dictionary attacks and the like. Users should be made aware of these restrictions when changing their passwords.</p><P CLASS="para">
+Earlier we said that password synchronization is limited. This is because there is no reverse synchronization of the encrypted <I CLASS="filename">
+smbpasswd</i> file when a standard Unix password is updated by a user. There are various strategies to get around this, including NIS and freely available implementations of the pluggable authentication modules (PAM) standard, but none of them really solve all the problems yet. In the future, when Windows 2000 emerges, we will see more compliance with the Lightweight Directory Access Protocol (LDAP), which promises to make password synchronization a thing of the past. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-958652">
+6.4.4 Password Configuration Options</a></h3><P CLASS="para">
+The options in <A CLASS="xref" HREF="ch06_04.html#ch06-68460">
+Table 6.8</a> will help you work with passwords in Samba. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-68460">
+Table 6.8: Password Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+encrypt passwords</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Turns on encrypted passwords.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+unix password sync </code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba updates the standard Unix password database when a user changes his or her encrypted password.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+passwd chat</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (chat commands)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a sequence of commands that will be sent to the password program.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See earlier section on this option</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+passwd chat debug</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sends debug logs of the password-change process to the log files with a level of 100.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+passwd program</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the program to be used to change passwords.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+/bin/passwd %u</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+password level</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the number of capital letter permutations to attempt when matching a client's password.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+update encrypted</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba updates the encrypted password file when a client connects to a share with a plaintext password.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+null passwords</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba allows access for users with null passwords.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+smb passwd file</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the name of the encrypted password file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+/usr/local/samba/private/smbpasswd</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+hosts equiv</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the name of a file that contains hosts and users that can connect without using a password.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+use rhosts</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the name of an .<EM CLASS="emphasis">
+rhosts</em> file that allows users to connect without using a password.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-968072">
+6.4.4.1 unix password sync</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+unix</code> <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+sync</code> global option allows Samba to update the standard Unix password file when a user changes his or her encrypted password. The encrypted password is stored on a Samba server in the <I CLASS="filename">
+smbpasswd</i> file, which is located in <I CLASS="filename">
+/usr/local/samba/private</i> by default. You can activate this feature as follows:</p><PRE CLASS="programlisting">
+[global]
+ unix password sync = yes</pre><P CLASS="para">
+If this option is enabled, Samba changes the encrypted password and, in addition, attempts to change the standard Unix password by passing the username and new password to the program specified by the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+program</code> option (described earlier). Note that Samba does not necessarily have access to the plaintext password for this user, so the password changing program must be invoked as <CODE CLASS="literal">
+root</code>.[<A CLASS="footnote" HREF="#ch06-pgfId-959675">3</a>] If the Unix password change does not succeed, for whatever reason, the SMB password will not be changed either.</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch06-pgfId-959675">[3]</a> This is because the Unix <EM CLASS="emphasis">
+passwd</em> program, which is the usual target for this operation, allows <CODE CLASS="literal">
+root</code> to change a user's password without the security restriction that requests the old password of that user.</p></div></blockquote></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-958684">
+6.4.4.2 encrypt passwords</a></h4><P CLASS="para">The <CODE CLASS="literal">
+encrypt</code> <CODE CLASS="literal">
+passwords</code> global option switches Samba from using plaintext passwords to encrypted passwords for authentication. Encrypted passwords will be expected from clients if the option is set to <CODE CLASS="literal">
+yes</code>:</p><PRE CLASS="programlisting">
+encrypt passwords = yes</pre><P CLASS="para">
+By default, Windows NT 4.0 with Service Pack 3 or above and Windows 98 transmit encrypted passwords over the network. If you are enabling encrypted passwords, you must have a valid <I CLASS="filename">
+smbpasswd</i> file in place and populated with usernames that will authenticate with encrypted passwords. (See the section <A CLASS="xref" HREF="ch06_04.html#ch06-17782">
+Section 6.4.2, The smbpasswd File</a>, earlier in this chapter.) In addition, Samba must know the location of the <I CLASS="filename">
+smbpasswd</i> file; if it is not in the default location (typically <I CLASS="filename">
+/usr/local/samba/private/smbpasswd</i>), you can explicitly name it using the <CODE CLASS="literal">
+smb</code> <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+file</code> option.</p><P CLASS="para">
+If you wish, you can use the <CODE CLASS="literal">
+update</code> <CODE CLASS="literal">
+encrypted</code> to force Samba to update the <I CLASS="filename">
+smbpasswd</i> file with encrypted passwords each time a client connects to a non-encrypted password.</p><P CLASS="para">
+A common strategy to ensure that hosts who need encrypted password authentication indeed receive it is with the <CODE CLASS="literal">
+include</code> option. With this, you can create individual configuration files that will be read in based on OS-type (<CODE CLASS="literal">%a</code>) or client name (<CODE CLASS="literal">%m</code>). These host-specific or OS-specific configuration files can contain an <CODE CLASS="literal">
+encrypted</code> <CODE CLASS="literal">
+passwords</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option that will activate only when those clients are connecting to the server.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-954367">
+6.4.4.3 passwd program</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+program</code> is used to specify a program on the Unix Samba server that Samba can use to update the standard system password file when the encrypted password file is updated. This option defaults to the standard<EM CLASS="emphasis">
+ passwd</em> program, usually located in the <I CLASS="filename">
+/bin</i> directory. The <CODE CLASS="literal">
+%u</code> variable is typically used here as the requesting user when the command is executed. The actual handling of input and output to this program during execution is handled through the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> option. The "Password Synchronization" section, earlier in this chapter, covers this option in detail.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-954372">
+6.4.4.4 passwd chat</a></h4><P CLASS="para">
+This option specifies a series of send/response strings similar to a Unix chat script, which are used to interface with the password-changing program on the Samba server. The "Password Synchronization" section, earlier in this chapter, covers this option in detail.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-954442">
+6.4.4.5 passwd chat debug</a></h4><P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, the <CODE CLASS="literal">
+passwd</code> <CODE CLASS="literal">
+chat</code> <CODE CLASS="literal">
+debug</code> global option logs everything sent or received by Samba during a password chat. All the I/O received by Samba through the password chat is sent to the Samba logs with a debug level of 100; you will need to specify <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+100</code> in order for the information to be recorded. The "Password Synchronization" section<EM CLASS="emphasis">
+,</em> earlier in this chapter, describes this option in more detail. Be aware that if you do set this option, the plaintext passwords will be visible in the debugging logs, which could be a security hazard if they are not properly secured.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-958069">
+6.4.4.6 password level</a></h4><P CLASS="para">
+With SMB, non-encrypted (or plaintext) passwords are sent with capital letters, just like the usernames mentioned previously. Many Unix users, however, choose passwords with both uppercase and lowercase letters. Samba, by default, only attempts to match the password entirely in lowercase letters, and not capitalizing the first letter.</p><P CLASS="para">
+Like <CODE CLASS="literal">
+username</code> <CODE CLASS="literal">
+level</code>, there is a <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+level</code> option that can be used to attempt various permutations of the password with capital letters. This option takes an integer value that specifies how many letters in the password should be capitalized when attempting to connect to a share. You can specify this options as follows:</p><PRE CLASS="programlisting">
+[global]
+ password level = 3</pre><P CLASS="para">
+In this case, Samba will then attempt all permutations of the password it can compute having three capital letters. The larger the number, the more computations Samba will have to perform to match the password, and the longer a connection to a specific share may take. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-954452">
+6.4.4.7 update encrypted</a></h4><P CLASS="para">
+For sites switching over to the encrypted password format, Samba provides an option that should help with the transition. The <CODE CLASS="literal">
+update</code> <CODE CLASS="literal">
+encrypted</code> option allows a site to ease into using encrypted passwords from plaintext passwords. You can activate this option as follows:</p><PRE CLASS="programlisting">
+[global]
+ update encrypted = yes</pre><P CLASS="para">
+This instructs Samba to create an encrypted version of each user's Unix password in the <I CLASS="filename">
+smbpasswd</i> file each time he or she connects to a share. When this option is enabled, you must have the <CODE CLASS="literal">
+encrypt</code> <CODE CLASS="literal">
+passwords</code> option set to <CODE CLASS="literal">
+no</code> so that the client will pass plaintext passwords to Samba to use to update the files. Once each user has connected at least once, you can set <CODE CLASS="literal">
+encrypted</code> <CODE CLASS="literal">
+passwords</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code>, allowing you to use only the encrypted passwords. The user must already have a valid entry in the <I CLASS="filename">
+smbpasswd</i> file for this option to work.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-958716">
+6.4.4.8 null passwords</a></h4><P CLASS="para">
+This global option tells Samba whether or not to allow access from users that have null passwords (encrypted or non-encrypted) set in their accounts. The default value is <CODE CLASS="literal">
+no</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+null passwords = yes</pre><P CLASS="para">
+We highly recommend against doing so unless you are familiar with the security risks this option can present to your system, including inadvertent access to system users (such as <I CLASS="filename">
+bin</i>) in the system password file who have null passwords set.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959357">
+6.4.4.9 smb passwd file</a></h4><P CLASS="para">This global option identifies the location of the encrypted password database. By default, it is set to <I CLASS="filename">
+/usr/local/samba/private/smbpasswd</i>. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ smb passwd file = /etc/smbpasswd</pre><P CLASS="para">
+This location, for example, is common on many Red Hat distributions.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-969088">
+6.4.4.10 hosts equiv</a></h4><P CLASS="para">
+This global option specifies the name of a standard Unix <I CLASS="filename">
+hosts.equiv</i> file that will allow hosts or users to access shares without specifying a password. You can specify the location of such a file as follows:</p><PRE CLASS="programlisting">
+[global]
+ hosts equiv = /etc/hosts.equiv</pre><P CLASS="para">
+The default value for this option does not specify any <I CLASS="filename">
+hosts.equiv</i> file. Because using such a file is essentially a huge security risk, we highly recommend that you do not use this option unless you are confident in the security of your network.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-959358">
+6.4.4.11 use rhosts</a></h4><P CLASS="para">
+This global option specifies the name of a standard Unix user's <I CLASS="filename">
+.rhosts</i> file that will allow foreign hosts to access shares without specifying a password. You can specify the location of such a file as follows:</p><PRE CLASS="programlisting">
+[global]
+ use rhosts = /home/dave/.rhosts</pre><P CLASS="para">
+The default value for this option does not specify any <I CLASS="filename">
+.rhosts</i> file. Like the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+equiv</code> option above, using such a file is a security risk. We highly recommend that you do use this option unless you are confident in the security of your network. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_03.html" TITLE="6.3 Authentication Security">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.3 Authentication Security" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_05.html" TITLE="6.5 Windows Domains">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.5 Windows Domains" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.3 Authentication Security</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6.5 Windows Domains</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_05.html b/docs/htmldocs/using_samba/ch06_05.html
new file mode 100644
index 00000000000..fbf6d245a16
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_05.html
@@ -0,0 +1,333 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] 6.5 Windows Domains</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:34:04Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_04.html" TITLE="6.4 Passwords">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.4 Passwords" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+Chapter 6<br>
+Users, Security, and Domains </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_06.html" TITLE="6.6 Logon Scripts">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.6 Logon Scripts" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch06-23084">
+6.5 Windows Domains</a></h2><P CLASS="para">Now that you are comfortable with users and passwords on a Samba server, we can show you how to set up Samba to become a primary domain controller for Windows 95/98 and NT machines. Why use domains? The answer probably isn't obvious until you look behind the scenes, especially with Windows 95/98.</p><P CLASS="para">
+Recall that with traditional workgroups, Windows 95/98 simply accepts each username and password that you enter when logging on to the system. There are no unauthorized users with Windows 95/98; if a new user logs on, the operating system simply asks for a new password and authenticates the user against that password from then on. The only time that Windows 95/98 attempts to use the password you entered is when connecting to another share.</p><P CLASS="para">Domain logons, on the other hand, are similar to Unix systems. In order to log on to the domain, a valid username and password must be presented at startup, which is then authenticated against the primary domain controller's password database. If the password is invalid, the user is immediately notified and they cannot log on to the domain.</p><P CLASS="para">
+There's more good news: once you have successfully logged on to the domain, you can access any of the shares in the domain to which you have rights without having to reauthenticate yourself. More precisely, the primary domain controller returns a token to the client machine that allows it to access any share without consulting the PDC again. Although you probably won't notice the shift, this can be beneficial in cutting down network traffic. (You can disable this behavior if you wish by using the <CODE CLASS="literal">
+revalidate</code> option.)</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-36822">
+6.5.1 Configuring Samba for Windows Domain Logons</a></h3><P CLASS="para">
+If you wish to allow Samba to act as a domain controller, use the following sections to configure Samba and your clients to allow domain access. </p><P CLASS="para">
+If you would like more information on how to set up domains, see the <I CLASS="filename">
+DOMAINS.TXT</i> file that comes with the Samba distribution.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962093">
+6.5.1.1 Windows 95/98 clients</a></h4><P CLASS="para">Setting up Samba as a PDC for Windows 95/98 clients is somewhat anticlimactic. All you really need to do on the server side is ensure that:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-962098">
+</a>Samba is the only primary domain controller for the current workgroup.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-963241">
+</a>There is a WINS server available on the network, either a Samba machine or a Windows NT server. (See <a href="ch07_01.html"><b>Chapter 7, <CITE CLASS="chapter">Printing and Name Resolution</cite></b></a>, for more information on WINS.)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-962099">
+</a>Samba is using user-level security (i.e., it doesn't hand off password authentication to anyone else). You do not want to use domain-level security if Samba itself is acting as the PDC.</p></li></ul><P CLASS="para">
+At that point, you can insert the following options into your Samba configuration file:</p><PRE CLASS="programlisting">
+[global]
+ workgroup = SIMPLE
+ domain logons = yes
+
+# Be sure to set user-level security!
+
+ security = user
+
+# Be sure to become the primary domain controller!
+
+ os level = 34
+ local master = yes
+ preferred master = yes
+ domain master = yes</pre><P CLASS="para">
+The <CODE CLASS="literal">
+domain</code> <CODE CLASS="literal">
+logons</code> option enables Samba to perform domain authentication on behalf of other clients that request it. The name of the domain will be the same as the workgroup listed in the Samba configuration file, in this case: SIMPLE.</p><P CLASS="para">
+After that, you need to create a non-writable, non-public, non-browesable disk share called <CODE CLASS="literal">
+[netlogon]</code> (it does not matter where this share points to as long as each Windows client can connect to it): </p><PRE CLASS="programlisting">
+[netlogon]
+ comment = The domain logon service
+ path = /export/samba/logon
+ public = no
+ writeable = no
+ browsable = no</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-961711">
+6.5.1.2 Windows NT clients</a></h4><P CLASS="para">If you have Window NT clients on your system, there are a few more steps that need to be taken in order for Samba to act as their primary domain controller.</p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> You will need to use at least Samba 2.1 to ensure that PDC functionality for Windows NT clients is present. Prior to Samba 2.1, only limited user authentication for NT clients was present. At the time this book went to press, Samba 2.0.5 was the latest version, but Samba 2.1 was available through CVS download. Instructions on downloading alpha versions of Samba are given in <a href="appe_01.html"><b>Appendix E, <CITE CLASS="appendix">Downloading Samba with CVS</cite></b></a>.</p></blockquote><P CLASS="para">
+As before, you need to ensure that Samba is a primary domain controller for the current workgroup and is using user-level security. However, you must also ensure that Samba is using encrypted passwords. In other words, alter the <CODE CLASS="literal">
+[global]</code> options the previous example to include the <CODE CLASS="literal">
+encrypted</code> <CODE CLASS="literal">
+passwords</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option, as shown here: </p><PRE CLASS="programlisting">
+[global]
+ workgroup = SIMPLE
+ encrypted passwords = yes
+ domain logons = yes
+
+ security = user </pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-961829">
+6.5.1.3 Creating trust accounts for NT clients</a></h4><P CLASS="para">
+This step is exclusively for Windows NT clients. All NT clients that connect to a primary domain controller make use of <I CLASS="firstterm">
+trust accounts</i>. These accounts allow a machine to log in to the PDC itself (not one of its shares), which means that the PDC can trust any further connections from users on that client. For all intents and purposes, a trust account is identical to a user account. In fact, we will be using standard Unix user accounts to emulate trust accounts for the Samba server.</p><P CLASS="para">
+The login name of a machine's trust account is the name of the machine with a dollar sign appended to it. For example, if our Windows NT machine is named <CODE CLASS="literal">
+chimaera</code>, the login account would be <CODE CLASS="literal">
+chimaera$</code>. The initial password of the account is simply the name of the machine in lowercase letters. In order to forge the trust account on the Samba server, you need to create a Unix account with the appropriate machine name, as well as an encrypted password entry in the <I CLASS="filename">
+smbpasswd</i> database.</p><P CLASS="para">
+Let's tackle the first part. Here, we only need to modify the <I CLASS="filename">
+/etc/passwd</i> file to support the trust account; there is no need to create a home directory or assign a shell to the "user" because the only part we are interested in is whether a login is permitted. Therefore, we can create a "dummy" account with the following entry:</p><PRE CLASS="programlisting">
+chimaera$:*:1000:900:Trust Account:/dev/null:/dev/null</pre><P CLASS="para">
+Note that we have also disabled the password field by placing a <CODE CLASS="literal">
+*</code> in it. This is because Samba will use the <I CLASS="filename">
+smbpasswd</i> file to contain the password instead, and we don't want anyone to telnet into the machine using that account. In fact, the only value other than the account name that is used here is the UID of the account for the encrypted password database (1000). This number must map to a unique resource ID on the NT server and cannot conflict with any other resource IDs. Hence, no NT user or group should map to this number or a networking error will occur.</p><P CLASS="para">
+Next, add the encrypted password using the <I CLASS="filename">
+smbpasswd</i> command, as follows: </p><PRE CLASS="programlisting"># <CODE CLASS="userinput"><B>smbpasswd -a -m chimaera</b></code>
+Added user chimaera$
+Password changed for user chimaera$</pre><P CLASS="para">
+The <CODE CLASS="literal">
+-m</code> option specifies that a machine trust account is being generated. The <I CLASS="filename">
+smbpasswd</i> program will automatically set the initial encrypted password as the NetBIOS name of the machine in lowercase letters; you don't need to enter it. When specifying this option on the command line, do not put a dollar sign after the machine name&nbsp;- it will be appended automatically. Once the encrypted password has been added, Samba is ready to handle domain logins from a NT client.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-961709">
+6.5.2 Configuring Windows Clients for Domain Logons</a></h3><P CLASS="para">
+Once you have Samba configured for domain logons, you need to set up your Windows clients to log on to the domain at startup.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962166">
+6.5.2.1 Windows 95/98</a></h4><P CLASS="para">With Windows 95/98, this can be done by raising the Network configuration dialog in the Windows Control Panel and selecting the Properties for "Client for Microsoft Networks." At this point, you should see a dialog box similar to <A CLASS="xref" HREF="ch06_05.html#ch06-48609">
+Figure 6.4</a>. Select the "Logon to Windows Domain" checkbox at the top of the dialog box, and enter the workgroup that is listed in the Samba configuration file as the Windows NT domain. Then click on OK and reboot the machine when asked. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-48609">
+Figure 6.4: Configuring a Windows 95/98 client for domain logons</a></h4><IMG CLASS="graphic" SRC="figs/sam.0604.gif" ALT="Figure 6.4"><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> If Windows complains that you are already logged into the domain, you probably have an active connection to a share in the workgroup (such as a mapped network drive). Simply disconnect the resource temporarily by right-clicking on its icon and choosing the Disconnect pop-up menu item.</p></blockquote><P CLASS="para">
+When Windows reboots, you should see the standard login dialog with an addition: a field for a domain. The domain name should already be filled in, so simply enter your password and click on the OK button. At this point, Windows should consult the primary domain controller (Samba) to see if the password is correct. (You can check the log files if you want to see this in action.) If it worked, congratulations! You have properly configured Samba to act as a domain controller for Windows 95/98 machines and your client is successfully connected.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-961780">
+6.5.2.2 Windows NT 4.0</a></h4><P CLASS="para">To configure Windows NT for domain logons, open the Network configuration dialog in the Windows NT Control Panel. The first tab that you see should list the identification of the machine.</p><P CLASS="para">
+Press the Change button and you should see the dialog box shown in <A CLASS="xref" HREF="ch06_05.html#ch06-89804">
+Figure 6.5</a>. In this dialog box, you can choose to have the Windows NT client become a member of the domain by selecting the radio button marked Domain in the "Member of" box. Then, type in the domain that you wish the client to login to; it should be the same as the workgroup that you specified in the Samba configuration file. Do not check the box marked "Create a Computer Account in the Domain"&nbsp;- Samba does not currently support this functionality. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-89804">
+Figure 6.5: Configuring a Windows NT client for domain logons</a></h4><IMG CLASS="graphic" SRC="figs/sam.0605.gif" ALT="Figure 6.5"><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Like Windows 95/98, if NT complains that you are already logged in, you probably have an active connection to a share in the workgroup (such as a mapped network drive). Disconnect the resource temporarily by right-clicking on its icon and choosing the Disconnect pop-up menu item.</p></blockquote><P CLASS="para">
+After you press the OK button, Windows should present you with a small dialog box welcoming you to the domain. At this point, you will need to reset the Windows NT machine. Once it comes up again, the machine will automatically present you with a log on screen similar to the one for Windows 95/98 clients. You can now log in using any account that you have already on the Samba server that is configured to accept logins.</p><BLOCKQUOTE CLASS="warning">
+<P CLASS="para">
+<STRONG>
+WARNING:</strong> Be sure to select the correct domain in the Windows NT logon dialog box. Once selected, it may take a moment for Windows NT to build the list of available domains.</p></blockquote><P CLASS="para">
+After you enter the password, Windows NT should consult the primary domain controller (Samba) to see if the password is correct. Again, you can check the log files if you want to see this in action. If it worked, you have successfully configured Samba to act as a domain controller for Windows NT machines.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-961353">
+6.5.3 Domain Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch06_05.html#ch06-53106">
+Table 6.9</a> shows the options that are commonly used in association with domain logons. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-53106">
+Table 6.9: Windows 95/98 Domain Logon Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+domain logons</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Indicates whether Windows domain logons are to be used.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+domain group map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name of the file used to map Unix to Windows NT domain groups.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+domain user map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name of the file used to map Unix to Windows NT domain users.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+local group map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name of the file used to map Unix to Windows NT local groups.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+revalidate</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba forces users to authenticate themselves with each connection to a share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960379">
+6.5.3.1 domain logons</a></h4><P CLASS="para">
+This option configures Samba to accept domain logons as a primary domain controller. When a client successfully logs on to the domain, Samba will return a special token to the client that allows the client to access domain shares without consulting the PDC again for authentication. Note that the Samba machine must be in user-level security (<CODE CLASS="literal">security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+user</code>) and must be the PDC in order for this option to function. In addition, Windows machines will expect a <CODE CLASS="literal">
+[netlogon]</code> share to exist on the Samba server (see the section <A CLASS="xref" HREF="ch06_05.html#ch06-36822">
+Section 6.5.1, Configuring Samba for Windows Domain Logons</a>, earlier in this chapter).</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-966160">
+6.5.3.2 domain group map</a></h4><P CLASS="para">
+This option specifies the location of a mapping file designed to translate Windows NT domain group names to Unix group names. The file should reside on the Samba server. For example:</p><PRE CLASS="programlisting">
+/usr/local/samba/private/groups.mapping</pre><P CLASS="para">
+The file has a simple format:</p><PRE CLASS="programlisting"><CODE CLASS="replaceable"><I>UnixGroup = NTGroup</i></code></pre><P CLASS="para">
+An example is:</p><PRE CLASS="programlisting">
+admin = Administrative</pre><P CLASS="para">
+The specified Unix group should be a valid group in the <I CLASS="filename">
+/etc/group</i> file. The NT group should be the name to which you want the Unix group to map on an NT client. This option will work only with Windows NT clients.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-961959">
+6.5.3.3 domain user map</a></h4><P CLASS="para">
+This option specifies the location of a mapping file designed to translate Unix usernames to Windows NT domain usernames. The file should reside on the Samba server. For example:</p><PRE CLASS="programlisting">/usr/local/samba/private/domainuser.mapping</pre><P CLASS="para">The file has a simple format:</p><PRE CLASS="programlisting"><CODE CLASS="replaceable"><I>UnixUsername</i></code> = [\\<CODE CLASS="replaceable"><I>Domain</i></code>\\]<CODE CLASS="replaceable"><I>NTUserName</i></code></pre><P CLASS="para">
+An example entry is:</p><PRE CLASS="programlisting">
+joe = Joseph Miller</pre><P CLASS="para">
+The Unix name specified should be a valid username in the <I CLASS="filename">
+/etc/passwd</i> file. The NT name should be the username to which you want to Unix username to map on an NT client. This option will work with Windows NT clients only.</p><P CLASS="para">
+If you would like more information on how Windows NT uses domain usernames and local groups, we recommend Eric Pearce's <CITE CLASS="citetitle">
+Windows NT in a Nutshell</cite>, published by O'Reilly.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-961962">
+6.5.3.4 local group map</a></h4><P CLASS="para">
+This option specifies the location of a mapping file designed to translate Windows NT local group names to Unix group names. Local group names include those such as Administrator and Users. The file should reside on the Samba server. For example:</p><PRE CLASS="programlisting">/usr/local/samba/private/localgroup.mapping</pre><P CLASS="para">The file has a simple format:</p><PRE CLASS="programlisting"><CODE CLASS="replaceable"><I>UnixGroup</i></code> = [BUILTIN\]<CODE CLASS="replaceable"><I>NTGroup</i></code></pre><P CLASS="para">
+An example entry is:</p><PRE CLASS="programlisting">
+root = BUILTIN\Administrators</pre><P CLASS="para">
+This option will work with Windows NT clients only. For more information, see Eric Pearce's <CITE CLASS="citetitle">
+Windows NT in a Nutshell</cite> (O'Reilly).</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962075">
+6.5.3.5 revalidate</a></h4><P CLASS="para">
+This share-level option tells Samba to force users to authenticate with passwords each time they connect to a different share on a machine, no matter what level of security is in place on the Samba server. The default value is <CODE CLASS="literal">
+no</code>, which allows users to be trusted once they successfully authenticate themselves. You can override it as:</p><PRE CLASS="programlisting">
+revalidate = yes</pre><P CLASS="para">
+You can use this option to increase security on your system. However, you should weigh it against the inconvenience of having users revalidate themselves to every share. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_04.html" TITLE="6.4 Passwords">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.4 Passwords" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_06.html" TITLE="6.6 Logon Scripts">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 6.6 Logon Scripts" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.4 Passwords</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+6.6 Logon Scripts</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch06_06.html b/docs/htmldocs/using_samba/ch06_06.html
new file mode 100644
index 00000000000..f80e4d37464
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch06_06.html
@@ -0,0 +1,537 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 6] 6.6 Logon Scripts</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:34:19Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_05.html" TITLE="6.5 Windows Domains">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.5 Windows Domains" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch06_01.html" TITLE="6. Users, Security, and Domains ">
+Chapter 6<br>
+Users, Security, and Domains </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch07_01.html" TITLE="7. Printing and Name Resolution">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7. Printing and Name Resolution" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch06-38153">
+6.6 Logon Scripts</a></h2><P CLASS="para">Samba supports the execution of Windows logon scripts, which are scripts (.BAT or .CMD) that are executed on the client when a user logs on to a Windows domain. Note that these scripts are stored on the Unix side, but are transported across the network to the client side and executed once a user logs on. These scripts are invaluable for dynamically setting up network configurations for users when they log on. The downside is that because they run on Windows, they must use the Windows network configuration commands.</p><P CLASS="para">
+If you would like more information on NET commands, we recommend the following O'Reilly handbooks: <EM CLASS="emphasis">
+Windows NT in a Nutshell</em>, <EM CLASS="emphasis">
+Windows 95 in a Nutshell</em>, and <EM CLASS="emphasis">
+Windows 98 in a Nutshell.</em></p><P CLASS="para">
+You can instruct Samba to use a logon script with the <CODE CLASS="literal">
+logon</code> <CODE CLASS="literal">
+script</code> option, as follows:</p><PRE CLASS="programlisting">
+[global]
+ domain logons = yes
+ security = user
+ workgroup = SIMPLE
+
+ os level = 34
+ local master = yes
+ preferred master = yes
+ domain master = yes
+ logon script = %U.bat
+
+[netlogon]
+ comment = The domain logon service
+ path = /export/samba/logon
+ public = no
+ writeable = no
+ browsable = no</pre><P CLASS="para">
+Note that this example uses the <CODE CLASS="literal">
+%U</code> variable, which will individualize the script based on the user that is logging in. It is common to customize logon scripts based on the user or machine name that is logging onto the domain. These scripts can then be used to configure individual settings for users or clients.</p><P CLASS="para">
+Each logon script should be stored at the base of the <CODE CLASS="literal">
+[netlogon]</code> share. For example, if the base of the <CODE CLASS="literal">
+[netlogon]</code> share is <I CLASS="filename">
+/export/samba/logon</i> and the logon script is <I CLASS="filename">
+jeff.bat</i>, the file should be located at <I CLASS="filename">
+/export/samba/logon/jeff.bat</i>. When a user logs on to a domain that contains a startup script, he or she will see a small dialog that informs them that the script is executing, as well as any output the script generates in an MS-DOS-like box.</p><P CLASS="para">
+One warning: because these scripts are loaded by Windows and executed on the Windows side, they must consist of DOS formatted carriage-return/linefeed characters instead of Unix carriage returns. It's best to use a DOS- or Windows-based editor to create them.</p><P CLASS="para">
+Here is an example of a logon script that sets the current time to match that of the Samba server and maps two network drives, <CODE CLASS="literal">
+h</code> and <CODE CLASS="literal">
+i</code>, to individual shares on the server:</p><PRE CLASS="programlisting">
+# Reset the current time to that shown by the server.
+# We must have the &quot;time server = yes&quot; option in the
+# smb.conf for this to work.
+
+echo Setting Current Time...
+net time \\hydra /set /yes
+
+# Here we map network drives to shares on the Samba
+# server
+echo Mapping Network Drives to Samba Server Hydra...
+net use h: \\hydra\data
+net use i: \\hydra\network</pre><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-960385">
+6.6.1 Roaming profiles</a></h3><P CLASS="para">
+<I CLASS="firstterm">
+</i>In Windows 95 and NT, each user can have his or her own <I CLASS="firstterm">
+profile</i>. A profile bundles information such as: the appearance of a user's desktop, the applications that appear on the start menus, the background, and other miscellaneous items. If the profile is stored on a local disk, it's called a <I CLASS="firstterm">
+local profile</i>, since it describes what a user's environment is like on one machine. If the profile is stored on a server, on the other hand, the user can download the same profile to any client machine that is connected to the server. The latter is called a <I CLASS="firstterm">
+roaming profile</i> because the user can roam around from machine to machine and still use the same profile. This makes it particularly convenient when someone might be logging in from his or her desk one day and from a portable in the field the next. <A CLASS="xref" HREF="ch06_06.html#ch06-71393">
+Figure 6.6</a> illustrates local and roaming profiles. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch06-71393">
+Figure 6.6: Local profiles versus roaming profiles</a></h4><IMG CLASS="graphic" SRC="figs/sam.0606.gif" ALT="Figure 6.6"><P CLASS="para">
+
+
+<!-- 2.0.7 amendment begins, davecb -->
+<P>Samba will provide roaming profiles if it is configured for domain logons
+and you set <CODE CLASS="literal">logon path</CODE> to the user's home
+directory and <CODE CLASS="literal">logon home </CODE> to a
+subdirectory of the user's home directory used to store profiles. These
+options are typically used with one of the user variables, as shown in this
+example:
+<PRE CLASS="programlisting">
+[global]
+ domain logons = yes
+ security = user
+ workgroup = SIMPLE
+ os level = 34
+ local master = yes
+ preferred master = yes
+ domain master = yes
+
+ logon home = \\%N\%U
+ logon path = \\%N\%U\profile <!-- from the man page -->
+</PRE>
+<P> Samba versions previous to 2.0.6 allowed Win9X machines to store
+profiles in separate shares, but that prevented the clients from setting
+their <CODE CLASS="literal">logon path</CODE> so they could get their home
+directory mounted by saying "net use /home". This was corrected in
+2.0.6.</P>
+
+<!-- end of profiles modification -->
+<!-- WARNING: we never warn anywhere that "Windows clients can sometimes
+maintain a connection to the [homes] share, even though there is
+no user logged in. Therefore, it is vital that the logon path does not
+include a reference to the homes share." I read the above as being
+equivalen to the homes share, just not leiterally [homes]. I expect
+the bug will persist. davecb-->
+
+
+Once a user initially logs on, the Windows client will create a <I CLASS="filename">
+user.dat</i> or <I CLASS="filename">
+ntuser.dat</i> file&nbsp;- depending on which operating system the client is running. The client then uploads the contents of the desktop, the Start Menu, the Network Neighborhood, and the programs folders in individual folders in the directory. When the user subsequently logs on, those contents will be downloaded from the server and activated for the client machine with which the user is logging on. When he or she logs off, those contents will be uploaded back on the server until the next time the user connects. If you look at the directory listing of a profile folder, you'll see the following:</p><PRE CLASS="programlisting">
+# ls -al
+
+total 321
+drwxrwxr-x 9 root simple Jul 21 20:44 .
+drwxrwxr-x 4 root simple Jul 22 14:32 ..
+drwxrwx--- 3 fred develope Jul 12 07:15 Application Data
+drwxrwx--- 3 fred develope Jul 12 07:15 Start Menu
+drwxrwx--- 2 fred develope Jul 12 07:15 cookies
+drwxrwx--- 2 fred develope Jul 12 07:15 desktop
+drwxrwx--- 7 fred develope Jul 12 07:15 history
+drwxrwx--- 2 fred develope Jul 12 07:15 nethood
+drwxrwx--- 2 fred develope Jul 19 21:05 recent
+-rw------- 1 fred develope Jul 21 21:59 user.dat</pre><P CLASS="para">
+The <I CLASS="filename">
+user.dat</i> files are binary configuration files, created automatically by Windows. They can be edited with the Profile Editor on a Windows client, but they can be somewhat tricky to get correct. Samba supports them correctly for all clients up to NT 5.0 beta, but they're still relatively new<I CLASS="firstterm"></i>.</p><P CLASS="para">
+Hints and HOWTOs for handling logon scripts are available in the Samba documentation tree, in both <I CLASS="filename">
+docs/textdocs/DOMAIN.txt</i> and <I CLASS="filename">
+docs/textdocs/PROFILES.txt</i>.<I CLASS="firstterm">
+</i> </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-961462">
+6.6.2 Mandatory profiles</a></h3><P CLASS="para">Users can also have <I CLASS="firstterm">
+mandatory profiles</i>, which are roaming profiles that they cannot change. For example, with a mandatory profile, if a user adds a command to the Start Menu on Tuesday, it will be gone when he or she logs in again on Wednesday. The mandatory profile is simply a <I CLASS="filename">
+user.dat</i> file that has been renamed to <I CLASS="filename">
+user.man</i> and made read-only on the Unix server. It normally contains settings that the administrator wishes to ensure the user always executes. For example, if an administrator wants to create a fixed user configuration, he or she can do the following:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957763">
+</a>Create the read-write directory on the Samba server. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957764">
+</a>Set the <CODE CLASS="literal">
+logon</code> <CODE CLASS="literal">
+path</code> option in the <EM CLASS="emphasis">
+smb.conf</em> file to point to this directory.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957765">
+</a>Logon as the user from Windows 95/98 to have the client populate the directory. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957766">
+</a>Rename the resulting <I CLASS="filename">
+user.dat</i> to <I CLASS="filename">
+user.man</i>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch06-pgfId-957767">
+</a>Make the directory and its contents read only.</p></li></ol><P CLASS="para">
+Mandatory profiles are fairly unusual. Roaming profiles, on the other hand, are one of the more desirable features of Windows that Samba can support.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-962637">
+6.6.3 Logon Script Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch06_06.html#ch06-46661">Table 6.10</a> summarizes the options commonly used in association with Windows domain logon scripts. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-46661">
+Table 6.10: Logon Script Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+logon script</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (DOS path)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Name of DOS/NT batch file</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+logon path</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (UNC server and share name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Location of roaming profile for user</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\\%N\%U\profile</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+logon drive</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (drive letter)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the logon drive for a home directory (NT only)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+Z</code>:</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+logon home</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (UNC server and share name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies a location for home directories for clients logging on to the domain</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+\\%N\%U</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962334">
+6.6.3.1 logon script</a></h4><P CLASS="para">
+This option specifies a Windows .BAT or .CMD file with lines ending in carriage-return/line feed that will be executed on the client after a user has logged on to the domain. Each logon script should be stored at the base of a share entitled <CODE CLASS="literal">
+[netlogin]</code> (see the section <A CLASS="xref" HREF="ch06_05.html#ch06-36822">
+Section 6.5.1</a> for details.) This option frequently uses the <CODE CLASS="literal">
+%U</code> or <CODE CLASS="literal">
+%m</code> variables (user or NetBIOS name) to point to an individual script. For example:</p><PRE CLASS="programlisting">
+logon script = %U.bat</pre><P CLASS="para">
+will execute a script based on the username located at the base of the <CODE CLASS="literal">
+[netlogin]</code> share. If the user who is connecting is <CODE CLASS="literal">
+fred</code> and the path of the <CODE CLASS="literal">
+[netlogin]</code> share maps to the directory <I CLASS="filename">
+/export/samba/netlogin</i>, the script should be <I CLASS="filename">
+/export/samba/netlogin/fred.bat</i>. Because these scripts are downloaded to the client and executed on the Windows side, they must consist of DOS formatted carriage-return/linefeed characters instead of Unix carriage returns.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962671">
+6.6.3.2 logon path</a></h4><P CLASS="para">
+This option provides a location for roaming profiles. When the user logs on, a roaming profile will be downloaded from the server to the client and activated for the user who is logging on. When the user logs off, those contents will be uploaded back on the server until the next time the user connects. </p><P CLASS="para">
+It is often more secure to create a separate share exclusively for storing user profiles:</p><PRE CLASS="programlisting">
+logon path = \\hydra\profile\%U</pre><P CLASS="para">
+For more informaiton on this option, see the section <A CLASS="xref" HREF="ch06_06.html">
+Section 6.6, Logon Scripts</a>, earlier in this chapter.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962332">
+6.6.3.3 logon drive</a></h4><P CLASS="para">
+This option specifies the drive letter on an NT client to which the home directory specified with the <CODE CLASS="literal">
+logon</code> <CODE CLASS="literal">
+home</code> option will be mapped. Note that this option will work with Windows NT clients only. For example:</p><PRE CLASS="programlisting">
+logon home = I:</pre><P CLASS="para">
+You should always use drive letters that will not conflict with fixed drives on the client machine. The default is Z:, which is a good choice because it is as far away from A:, C:, and D: as possible.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-962319">
+6.6.3.4 logon home </a></h4><P CLASS="para">
+This option specifies the location of a user's home directory for use by the DOS NET commands. For example, to specify a home directory as a share on a Samba server, use the following:</p><PRE CLASS="programlisting">
+logon home = \\hydra\%U</pre><P CLASS="para">
+Note that this works nicely with the <CODE CLASS="literal">
+[homes]</code> service, although you can specify any directory you wish. Home directories can be mapped with a logon script using the following command:</p><PRE CLASS="programlisting">
+NET USE I: /HOME</pre><P CLASS="para">
+In addition, you can use the User Environment Profile under User Properties in the Windows NT User Manager to verify that the home directory has automatically been set. </p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-960476">
+6.6.4 Other Connection Scripts</a></h3><P CLASS="para">After a user successfully makes a connection to any Samba share, you may want the Samba server to execute a program on its side to prepare the share for use. Samba allows scripts to be executed before and after someone connects to a share. You do not need to be using Windows domains to take advantage of the options. <A CLASS="xref" HREF="ch06_06.html#ch06-67528">
+Table 6.11</a> introduces some of the configuration options provided for setting up users. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-67528">
+Table 6.11: Connection Script Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+root preexec</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a command to run as <CODE CLASS="literal">
+root</code>, before connecting to the share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+preexec (exec)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a Unix command to run as the user before connecting to the share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+postexec</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a Unix command to run as the user after disconnecting from the share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+root postexec</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a Unix command to run as <CODE CLASS="literal">
+root</code> after disconnecting from the share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960575">
+6.6.4.1 root preexec</a></h4><P CLASS="para">
+The first form of the logon command is called <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+preexec</code>. This option specifies a Unix command as its value that will be run <EM CLASS="emphasis">
+as the root user</em> before any connection to a share is completed. You should use this option specifically for performing actions that require root privilege. For example, <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+preexec</code> can be used to mount CD-ROMs for a share that makes them available to the clients, or to create necessary directories. If no <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+preexec</code> option is specified, there is no default action. Here is an example of how you can use the command to mount a CD-ROM:</p><PRE CLASS="programlisting">
+[homes]
+ browseable = no
+ writeable = yes
+ root preexec = /etc/mount /dev/cdrom2</pre><P CLASS="para">
+Remember that these commands will be run as the root user. Therefore, in order to ensure security, users should never be able to modify the target of the <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+preexec</code> command.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960582">
+6.6.4.2 preexec</a></h4><P CLASS="para">
+The next option run before logon is the <CODE CLASS="literal">
+preexec</code> option, sometimes just called <CODE CLASS="literal">
+exec</code>. This is an ordinary unprivileged command run by Samba as the user specified by the variable <CODE CLASS="literal">
+%u</code>. For example, a common use of this option is to perform logging, such as the following:</p><PRE CLASS="programlisting">
+[homes]
+<CODE CLASS="userinput"><B>preexec = echo &quot;%u connected to %S from %m (%I)\&quot; &gt;&gt;/tmp/.log</b></code> </pre><P CLASS="para">
+Be warned that any information the command sends to standard output will not be seen by the user, but is instead thrown away. If you intend to use a <CODE CLASS="literal">
+preexec</code> script, you should ensure that it will run correctly before having Samba invoke it.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960594">
+6.6.4.3 postexec</a></h4><P CLASS="para">
+Once the user disconnects from the share, the command specified with <CODE CLASS="literal">
+postexec</code> is run as the user on the Samba server to do any necessary cleanup. This option is essentially the same as the <CODE CLASS="literal">
+preexec</code> option. Again, remember that the command is run as the user represented by <CODE CLASS="literal">
+%u</code> and any information sent to standard output will be ignored.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960596">
+6.6.4.4 root postexec</a></h4><P CLASS="para">
+Following the <CODE CLASS="literal">
+postexec</code> option, the <CODE CLASS="literal">
+root</code> <CODE CLASS="literal">
+postexec</code> command is run, if one has been specified. Again, this option specifies a Unix command as its value that will be run <EM CLASS="emphasis">
+as the </em><EM CLASS="emphasis">root user</em> before disconnecting from a share. You should use this option specifically for performing actions that require root privilege.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch06-pgfId-960610">
+6.6.5 Working with NIS and NFS</a></h3><P CLASS="para">
+Finally, Samba has the ability to work with NIS and NIS+. If there is more than one file server, and each runs Samba, it may be desirable to have the SMB client connect to the server whose disks actually house the user's home directory. It isn't normally a good idea to ship files across the network once via NFS to a Samba server, only to be sent across the network once again to the client via SMB. (For one thing, it's slow&nbsp;- about 30 percent of normal Samba speed). Therefore, there are a pair of options to tell Samba that NIS knows the name of the right server and indicate in which NIS map the information lives.</p><P CLASS="para">
+<A CLASS="xref" HREF="ch06_06.html#ch06-27466">
+Table 6.12</a> introduces some of the other configuration options specifically for setting up users. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch06-27466">
+Table 6.12: NIS Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+nis homedir</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, use NIS instead of <I CLASS="filename">
+/etc/passwd</i> to look up the path of a user's home directory</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+homedir map</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (NIS map name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the NIS map to use to look up a user's home directory</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch06-pgfId-960612">
+6.6.5.1 nis homedir and homedir map</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+nis</code> <CODE CLASS="literal">
+homedir</code> and <CODE CLASS="literal">
+homedir</code> <CODE CLASS="literal">
+map</code> options are for Samba servers on network sites where Unix home directories are provided using NFS, the automounter, and NIS (Yellow Pages).</p><P CLASS="para">
+The <CODE CLASS="literal">
+nis</code> <CODE CLASS="literal">
+homedir</code> option indicates that the home directory server for the user needs to be looked up in NIS. The <CODE CLASS="literal">
+homedir</code> <CODE CLASS="literal">
+map</code> option tells Samba what NIS map to look in for the server that has the user's home directory. The server needs to be a Samba server, so the client can do an SMB connect to it, and the other Samba servers need to have NIS installed so they can do the lookup.</p><P CLASS="para">
+For example, if user <CODE CLASS="literal">
+joe</code> asks for a share called <CODE CLASS="literal">
+[joe]</code>, and the <CODE CLASS="literal">
+nis</code> <CODE CLASS="literal">
+homedir</code> option is set to <CODE CLASS="literal">
+yes</code>, Samba will look in the file specified by <CODE CLASS="literal">
+homedir</code> <CODE CLASS="literal">
+map</code> for a home directory for <CODE CLASS="literal">
+joe</code>. If it finds one, Samba will return the associated machine name to the client. The client will then try to connect to <EM CLASS="emphasis">
+that</em> machine and get the share from there. Enabling NIS lookups looks like the following:</p><PRE CLASS="programlisting">
+[globals]
+ nis homedir = yes
+ homedir map = amd.map</pre></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_05.html" TITLE="6.5 Windows Domains">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.5 Windows Domains" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch07_01.html" TITLE="7. Printing and Name Resolution">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7. Printing and Name Resolution" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.5 Windows Domains</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+7. Printing and Name Resolution</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch07_01.html b/docs/htmldocs/using_samba/ch07_01.html
new file mode 100644
index 00000000000..a061c6a94ee
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch07_01.html
@@ -0,0 +1,565 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 7] Printing and Name Resolution</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:34:47Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_06.html" TITLE="6.6 Logon Scripts">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.6 Logon Scripts" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 7</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_02.html" TITLE="7.2 Printing to Windows Client Printers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7.2 Printing to Windows Client Printers" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch07-98459">
+7. Printing and Name Resolution</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch07-61388" TITLE="7.1 Sending Print Jobs to Samba">
+Sending Print Jobs to Samba</a><br>
+<A CLASS="sect1" HREF="ch07_02.html" TITLE="7.2 Printing to Windows Client Printers">
+Printing to Windows Client Printers</a><br>
+<A CLASS="sect1" HREF="ch07_03.html" TITLE="7.3 Name Resolution with Samba">
+Name Resolution with Samba</a></p><P>
+</p></div><P CLASS="para">This chapter tackles two Samba topics: setting up printers for use with a Samba server and configuring Samba to use or become a Windows Internet Name Service (WINS) server. Samba allows client machines to send documents to printers connected to the Samba server. In addition, Samba can also assist you with printing Unix documents to a printer on a Windows machine. In the first part of this chapter, we will discuss how to get printers configured to work on either side.</p><P CLASS="para">
+In the second half of the chapter, we will introduce the Windows Internet Name Service, Microsoft's implementation of a NetBIOS Name Server (NBNS). As mentioned in <a href="ch01_01.html"><b>Chapter 1, <CITE CLASS="chapter">Learning the Samba</cite></b></a>, an NBNS allows machines to perform name resolution on a NetBIOS network without having to rely on broadcasts. Instead, each machine knows exactly where the WINS server is and can query it for the IP addresses of other machines on the network.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch07-61388">
+7.1 Sending Print Jobs to Samba</a></h2><P CLASS="para">A printer attached to the Samba server shows up in the list of shares offered in the Network Neighborhood. If the printer is registered on the client machine and the client has the correct printer driver installed, the client can effortlessly send print jobs to a printer attached to a Samba server. <A CLASS="xref" HREF="ch07_01.html#ch07-35075">
+Figure 7.1</a> shows a Samba printer as it appears in the Network Neighborhood of a Windows client. </p><P CLASS="para">To administer printers with Samba, you should understand the basic process by which printing takes place on a network. Sending a print job to a printer on a Samba server involves four steps:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-948964">
+</a>Opening and authenticating a connection to the printer share</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-948965">
+</a>Copying the file over the network</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-948966">
+</a>Closing the connection</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-948967">
+</a>Printing and deleting the copy of the file </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-35075">
+Figure 7.1: A Samba printer in the Network Neighborhood</a></h4><IMG CLASS="graphic" SRC="figs/sam.0701.gif" ALT="Figure 7.1"></li></ol><P CLASS="para">
+When a print job arrives at a Samba server, the print data is temporarily written to disk in the directory specified by the <CODE CLASS="literal">
+path</code> option of the printer share. Samba then executes a Unix print command to send that data file to the printer. The job is printed as the authenticated user of the share. Note that this may be the guest user, depending on how the share is configured.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-951370">
+7.1.1 Print Commands</a></h3><P CLASS="para">In order to print the document, you'll need to tell Samba what the command is to print and delete a file. On Linux, such a command is:</p><PRE CLASS="programlisting">
+lpr -r -P<CODE CLASS="replaceable"><I>printer</i></code> <CODE CLASS="replaceable"><I>file</i></code></pre><P CLASS="para">
+This tells <CODE CLASS="literal">
+lpr</code> to copy the document to a spool area, usually <I CLASS="filename">
+/var/spool</i>, retrieve the name of the printer in the system configuration file (<I CLASS="filename">/etc/printcap</i>), and interpret the rules it finds there to decide how to process the data and which physical device to send it to. Note that because the <CODE CLASS="literal">
+-r</code> option has been listed, the file specified on the command line will be deleted after it has been printed. Of course, the file removed is just a copy stored on the Samba server; the original file on the client is unaffected.</p><P CLASS="para">
+Linux uses a Berkeley (BSD) style of printing. However, the process is similar on System V Unix. Here, printing and deleting becomes a compound command:</p><PRE CLASS="programlisting">lp -d<CODE CLASS="replaceable"><I>printer</i></code> -s <CODE CLASS="replaceable"><I>file</i></code>; rm <CODE CLASS="replaceable"> <I>file</i></code></pre><P CLASS="para">
+With System V, the <I CLASS="filename">
+/etc/printcap</i> file is replaced with different set of configuration files hiding in <I CLASS="filename">
+/usr/spool/lp</i>, and there is no option to delete the file. You have to do it yourself, which is why we have added the <CODE CLASS="literal">
+rm</code> command afterward.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-951469">
+7.1.2 Printing Variables</a></h3><P CLASS="para">Samba provides four variables specifically for use with printing configuration options. They are shown in <A CLASS="xref" HREF="ch07_01.html#ch07-29758">
+Table 7.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch07-29758">
+Table 7.1: Printing Variables </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%s</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The full pathname of the file on the Samba server to be printed</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%f</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The name of the file itself (without the preceding path) on the Samba server to be printed</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%p</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The name of the Unix printer to use</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%j</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The number of the print job (for use with <CODE CLASS="literal">
+lprm</code>, <CODE CLASS="literal">
+lppause</code>, and <CODE CLASS="literal">
+lpresume</code>)</p></td></tr></tbody></table></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-943749">
+7.1.3 A Minimal Printing Setup</a></h3><P CLASS="para">Let's start with a simple but illustrative printing share. Assuming that you're on a Linux system and you have a printer called <CODE CLASS="literal">
+lp</code> listed in the printer capabilities file, the following addition to your <I CLASS="filename">
+smb.conf</i> file will make the printer accessible through the network:</p><PRE CLASS="programlisting">
+[printer1]
+ printable = yes
+ print command = /usr/bin/lpr -r %s
+ printer = lp
+ printing = BSD
+ read only = yes
+ guest ok = yes</pre><P CLASS="para">
+This configuration allows anyone to send data to the printer, something we may want to change later. For the moment, what's important to understand is that the variable <CODE CLASS="literal">
+%s</code> in the <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code> option will be replaced with the name of the file to be printed when Samba executes the command. Changing the <CODE CLASS="literal">
+print command</code> to reflect a different style of Unix machine typically involves only replacing the right side of the <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code> option with whatever command you need for your system and changing the target of the <CODE CLASS="literal">
+printing</code> option.</p><P CLASS="para">
+Let's look at the commands for a System V Unix. With variable substitution, the System V Unix command becomes:</p><PRE CLASS="programlisting">
+print command = lp -d%p -s %s; rm %s</pre><P CLASS="para">
+As mentioned earlier, the <CODE CLASS="literal">
+%p</code> variable resolves to the name of the printer, while the <CODE CLASS="literal">
+%s</code> variable resolves to the name of the file. After that, you can change the <CODE CLASS="literal">
+printing</code> option to reflect that you're using a System V architecture:</p><PRE CLASS="programlisting">
+printing = SYSV</pre><P CLASS="para">
+If you are using share-level security, pay special attention to the guest account used by Samba. The typical setting, <CODE CLASS="literal">
+nobody</code>, may not be allowed to print by the operating system. If that's true for your operating system, you should place a <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> option under the printing share (or even perhaps the global share) specifying an account that can. A popular candidate with the Samba authors is the <CODE CLASS="literal">
+ftp</code> account, which is often preconfigured to be safe for untrusted guest users. You can set it with the following command:</p><PRE CLASS="programlisting">
+guest account = ftp</pre><P CLASS="para">
+Another common printing issue is that clients may need to request the status of a print job sent to the Samba server. Samba will not reject a document from being sent to an already busy printer share. Consequently, Samba needs the ability to communicate not only the status of the current printing job to the client, but also which documents are currently waiting to be printed on that printer. Samba also has to provide the client the ability to pause print jobs, resume print jobs, and remove print jobs from the printing queue. Samba provides options for each of these tasks. As you might expect, they borrow functionality from existing Unix commands. The options are: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956989">
+</a><CODE CLASS="literal">
+lpq command</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956990">
+</a><CODE CLASS="literal">
+lprm command</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956991">
+</a><CODE CLASS="literal">
+lppause command</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956992">
+</a><CODE CLASS="literal">
+lpresume command</code></p></li></ul><P CLASS="para">
+We will cover these options in more detail below. For the most part, however, the value of the <CODE CLASS="literal">
+printing</code> configuration option will determine their values, and you should not need to alter the default values of these options.</p><P CLASS="para">
+Here are a few important items to remember about printing shares:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-951650">
+</a>You must put <CODE CLASS="literal">
+printable</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in all printer shares (even <CODE CLASS="literal">
+[printers]</code>), so that Samba will know that they are printer shares. If you forget, the shares will not be usable for printing and will instead be treated as disk shares.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-951651">
+</a>If you set the <CODE CLASS="literal">
+path</code> configuration option in the printer section, any files sent to the printer(s) will be copied to the directory you specify instead of to the default location of <I CLASS="filename">
+/tmp</i>. As the amount of disk space allocated to <I CLASS="filename">
+/tmp</i> can be relatively small in some Unix operating systems, many administrators opt to use <I CLASS="filename">
+/var/spool</i> or some other directory instead.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-951652">
+</a>The <CODE CLASS="literal">
+read only</code> option is ignored for printer shares.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-951648">
+</a>If you set <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in a printer share and Samba is configured for share-level security, it will allow anyone to send data to the printer as the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> user. </p></li></ul><P CLASS="para">
+Using one or more Samba machines as a print server gives you a great deal of flexibility on your LAN. You can easily partition your available printers, restricting some to members of one department, or you can maintain a bank of printers available to all. In addition, you can restrict a printer to a selected few by adding the trusty <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> option to its share definition:</p><PRE CLASS="programlisting">
+[deskjet]
+ printable = yes
+ path = /var/spool/samba/print
+ valid users = gail sam</pre><P CLASS="para">
+All of the other share accessibility options defined in the previous chapter should work for printing shares as well. Since the printers themselves are accessed through Samba by name, it's also simple to delegate print services among several servers using familiar Unix commands for tasks such as load balancing or maintenance. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-951458">
+7.1.4 The [printers] Share</a></h3><P CLASS="para">
+<a href="ch04_01.html"><b>Chapter 4, <CITE CLASS="chapter">Disk Shares </cite></b></a>, briefly introduced <CODE CLASS="literal">
+[printers]</code>, a special share for automatically creating printing services. Let's review how it works: if you create a share named <CODE CLASS="literal">
+[printers]</code> in the configuration file, Samba will automatically read in your printer capabilities file and create a printing share for each printer that appears in the file. For example, if the Samba server had <CODE CLASS="literal">
+lp</code>, <CODE CLASS="literal">
+pcl</code> and <CODE CLASS="literal">
+ps</code> printers in its printer capabilities file, Samba would provide three printer shares with those names, each configured with the options in the <CODE CLASS="literal">
+[printers]</code> share.</p><P CLASS="para">Recall that Samba obeys following rules when a client requests a share that has not been created through the <I CLASS="filename">
+smb.conf</i> file:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949501">
+</a>If the share name matches a username in the system password file and a <CODE CLASS="literal">
+[homes]</code> share exists, a new share is created with the name of the user and is initialized using the values given in the <CODE CLASS="literal">
+[homes]</code> and <CODE CLASS="literal">
+[global]</code> sections.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949506">
+</a>Otherwise, if the name matches a printer in the system printer capabilities file, and a <CODE CLASS="literal">
+[printers]</code> share exists, a new share is created with the name of the printer and initialized using the values given in the <CODE CLASS="literal">
+[printers]</code> section. (Variables in the <CODE CLASS="literal">
+[global]</code> section do not apply here.) </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949507">
+</a>If neither of those succeed, Samba looks for a <CODE CLASS="literal">
+default</code> <CODE CLASS="literal">
+service</code> share. If none is found, it returns an error.</p></li></ul><P CLASS="para">
+This brings to light an important point: be careful that you do not give a printer the same name as a user. Otherwise, you will end up connecting to a disk share when you may have wanted a printer share instead.</p><P CLASS="para">
+Here is an example <CODE CLASS="literal">
+[printers]</code> share for a Linux (BSD) system. Some of these options are already defaults; however, we have listed them anyway for illustrative purposes:</p><PRE CLASS="programlisting">
+[global]
+ printing = BSD
+ print command = /usr/bin/lpr -P%p -r %s
+ printcap file = /etc/printcap
+ min print space = 2000
+
+[printers]
+ path = /usr/spool/public
+ printable = true
+ guest ok = true
+ guest account = pcguest </pre><P CLASS="para">
+Here, we've given Samba global options that specify the printing type (BSD), a print command to send data to the printer and remove a temporary file, our default printer capabilities file, and a minimum printing space of 2 megabytes.</p><P CLASS="para">
+In addition, we've created a <CODE CLASS="literal">
+[printers]</code> share for each of the system printers. Our temporary spooling directory is specified by the <CODE CLASS="literal">
+path</code> option: <I CLASS="filename">
+/usr/spool/public</i>. Each of the shares is marked as printable&nbsp;- this is necessary, even in the <CODE CLASS="literal">
+[printers]</code> section. The two <CODE CLASS="literal">
+guest</code> options are useful in the event that Samba is using share-level security: we allow guest access to the printer and we specify the guest user that Samba should use to execute print commands. </p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-943839">
+7.1.5 Test Printing</a></h3><P CLASS="para">Here is how you can test printing from the Samba server. Let's assume the most complex case and use a guest account. First, run the Samba <EM CLASS="emphasis">
+testparm</em> command on your configuration file that contains the print shares, as we did in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>. This will tell you if there are any syntactical problems with the configuration file. For example, here is what you would see if you left out the <CODE CLASS="literal">
+path</code> configuration option in the previous example:</p><PRE CLASS="programlisting">
+# testparm
+Load smb config files from /usr/local/samba/lib/smb.conf
+Processing configuration file &quot;/usr/local/samba/lib/smb.conf&quot;
+Processing section &quot;[global]&quot;
+Processing section &quot;[homes]&quot;
+Processing section &quot;[data]&quot;
+Processing section &quot;[printers]&quot;
+No path in service printers - using /tmp
+Loaded services file OK.
+Press enter to see a dump of your service definitions
+Global parameters:
+ load printers: Yes
+ printcap name: /etc/printcap
+Default service parameters:
+ guest account: ftp
+ min print space: 0
+ print command: lpr -r -P%p %s
+ lpq command: lpq -P%p
+ lprm command: lprm -P%p %j
+lppause command:
+ lpresume command:
+ Service parameters [printers]:
+ path: /tmp
+ print ok: Yes
+ read only: true
+ public: true </pre><P CLASS="para">
+Second, try the command <CODE CLASS="literal">
+testprns</code> <CODE CLASS="replaceable">
+<I>
+printername</i></code>. This is a simple program that verifies that the specified printer is available in your <EM CLASS="emphasis">
+printcap</em> file. If your <EM CLASS="emphasis">
+printcap</em> file is not in the usual place, you can specify its full pathname as the second argument to the <EM CLASS="emphasis">
+testprns</em> command:</p><PRE CLASS="programlisting">
+# testprns lp /etc/printcap
+Looking for printer lp in printcap file /etc/printcap
+Printer name lp is valid.</pre><P CLASS="para">
+Next, log on as the guest user, go to the spooling directory, and ensure that you can print using the same command that <EM CLASS="emphasis">
+testparm</em> says Samba will use. As mentioned before, this will tell you if you need to change the guest account, as the default account may not be allowed to print.</p><P CLASS="para">
+Finally, print something to the Samba server via <CODE CLASS="literal">
+smbclient</code>, and see if the following actions occur:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-943874">
+</a>The job appears (briefly) in the Samba spool directory specified by the path.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-943875">
+</a>The job shows up in your print systems spool directory.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-943876">
+</a>The job disappears from the spool directory that Samba used.</p></li></ul><P CLASS="para">
+If <EM CLASS="emphasis">
+smbclient</em> cannot print, you can reset the <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code> option to collect debugging information:</p><PRE CLASS="programlisting">
+print command = /bin/cat %s &gt;&gt;/tmp/printlog; rm %s</pre><P CLASS="para">
+or:</p><PRE CLASS="programlisting">
+print command = echo &quot;printed %s on %p&quot; &gt;&gt;/tmp/printlog</pre><P CLASS="para">
+A common problem with Samba printer configuration is forgetting to use the full pathnames for commands; simple commands often don't work because the guest account's PATH doesn't include them. Another frequent problem is not having the correct permissions on the spooling directory. </p><P CLASS="para">There is more information on debugging printers in the Samba documentation (<I CLASS="filename">Printing.txt</i>). In addition, the Unix print systems are covered in detail in AEleen Frisch's <EM CLASS="emphasis">
+Essential Systems Administration</em> (published by O'Reilly).</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-943883">
+7.1.6 Setting Up and Testing a Windows Client</a></h3><P CLASS="para">Now that Samba is offering a workable printer, you need to set it up on a Windows client. Look at the Samba server in the Network Neighborhood. It should now show each of the printers that are available. For example, in <A CLASS="xref" HREF="ch07_01.html#ch07-35075">
+Figure 7.1</a>, we saw a printer called <CODE CLASS="literal">
+lp</code>.</p><P CLASS="para">
+Next, you need to have the Windows client recognize the printer. Double-click on the printer icon to get started. If you try to select an uninstalled printer (as you just did), Windows will ask you if it should help configure it for the Windows system. Respond "Yes," which will open the Printer Wizard. </p><P CLASS="para">
+The first thing the wizard will ask is whether you need to print from DOS. Let's assume you don't, so choose No and press the Next button to get to the manufacturer/model window as shown in <A CLASS="xref" HREF="ch07_01.html#ch07-60084">
+Figure 7.2</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-60084">
+Figure 7.2: A printer in the Network Neighborhood</a></h4><IMG CLASS="graphic" SRC="figs/sam.0702.gif" ALT="Figure 7.2"><P CLASS="para">
+In this dialog box, you should see a large list of manufacturers and models for almost every printer imaginable. If you don't see your printer on the list, but you know it's a PostScript printer, select Apple as the manufacturer and Apple LaserWriter as the model. This will give you the most basic Postscript printer setup, and arguably one of the most reliable. If you already have any Postscript printers attached, you will be asked about replacing or reusing the existing driver. Be aware that if you replace it with a new one, you may make your other printers fail. Therefore, we recommend you keep using your existing printer drivers as long as they're working properly.</p><P CLASS="para">
+Following that, the Printer Wizard will ask you to name the printer. <A CLASS="xref" HREF="ch07_01.html#ch07-69466">
+Figure 7.3</a> shows this example, where the name has defaulted to our second laserwriter. Here, you rename it from Apple Laserwriter (Copy 2) to "ps on Samba server," so you know where to look for the printouts. In reality, you can name the printer anything you want. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-69466">
+Figure 7.3: Printer manufacturers and models</a></h4><IMG CLASS="graphic" SRC="figs/sam.0703.gif" ALT="Figure 7.3"><P CLASS="para">
+Finally, the Printing Wizard asks if it should print a test page. Click on Yes, and you should be presented with the dialog in <A CLASS="xref" HREF="ch07_01.html#ch07-43374">
+Figure 7.4</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-43374">
+Figure 7.4: Printing successfully completed</a></h4><IMG CLASS="graphic" SRC="figs/sam.0704.gif" ALT="Figure 7.4"><P CLASS="para">
+If the test printing was unsuccessful, press the No button in <A CLASS="xref" HREF="ch07_01.html#ch07-43374">
+Figure 7.4</a> and the Printing Wizard will walk you through some debugging steps for the client side of the process. If the test printing does work, congratulations! The remote printer will now be available to all your PC applications through the File and Print menu items.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-30008">
+7.1.7 Automatically Setting Up Printer Drivers</a></h3><P CLASS="para">The previous section described how to manually configure a printer driver for your Windows system. As a system administrator, however, you can't always guarantee that users can perform such a process without making mistakes. Luckily, however, you can ask Samba to automatically set up the printer drivers for a specific printer.</p><P CLASS="para">
+Samba has three options that can be used to automatically set up printer drivers for clients who are connecting for the first time. These options are <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code>, <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+file</code>, and <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+location</code>. This section explains how to use these options to allow users to skip over the Manufacturer dialog in the Add Printer Wizard above.</p><P CLASS="para">
+For more information on how to do this, see the <I CLASS="filename">
+PRINTER_DRIVER.TXT</i> file in the Samba distribution documentation.</p><P CLASS="para">
+There are four major steps:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949602">
+</a>Install the drivers for the printer on a Windows client (the printer need not be attached).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949746">
+</a>Create a printer definition file from the information on a Windows machine.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949600">
+</a>Create a <CODE CLASS="literal">
+PRINTER$</code> share where the resulting driver files can be placed.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949601">
+</a>Modify the Samba configuration file accordingly.</p></li></ol><P CLASS="para">
+Let's go over each of the four steps in greater detail.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949749">
+7.1.7.1 Install the drivers on a windows client</a></h4><P CLASS="para">
+Use Windows 95/98 for this step. It doesn't matter which client you choose, as long as it has the ability to load the appropriate drivers for the printer. In fact, you don't even need to have the printer attached to the machine. All you're interested in here is getting the appropriate driver files into the Windows directory. First, go to the Printers window of My Computer and double-click on the Add Printer icon, as shown in <A CLASS="xref" HREF="ch07_01.html#ch07-52397">
+Figure 7.5</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-52397">
+Figure 7.5: The Printers window</a></h4><IMG CLASS="graphic" SRC="figs/sam.0705.gif" ALT="Figure 7.5"><P CLASS="para">
+At this point, you can follow the Add Printer Wizard dialogs through to select the manufacturer and model of the printer in question. If it asks you if you want to print from MS-DOS, answer No. Windows should load the appropriate driver resources from its CD-ROM and ask you if you want to print a test page. Again, respond No and close the Add Printer Wizard dialog.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949606">
+7.1.7.2 Create a printer definition file</a></h4><P CLASS="para">
+You can create a printer definition file by using the <I CLASS="filename">
+make_ printerdef</i> script in the <I CLASS="filename">
+/usr/local/samba/bin</i> directory. In order to use this script, you need to copy over the following four files from a Windows client:[<A CLASS="footnote" HREF="#ch07-pgfId-951615">1</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch07-pgfId-951615">[1]</a> Older Windows 95 clients may have only the first two files.</p></div></blockquote><TABLE CLASS="simplelist" BORDER="0">
+<TR>
+<TD CLASS="member">
+<EM CLASS="emphasis">
+C:\WINDOWS\INF\MSPRINT.INF</em></td></tr><TR>
+<TD CLASS="member">
+<EM CLASS="emphasis">
+C:\WINDOWS\INF\MSPRINT2.INF</em></td></tr><TR>
+<TD CLASS="member">
+<EM CLASS="emphasis">
+C:\WINDOWS\INF\MSPRINT3.INF</em></td></tr><TR>
+<TD CLASS="member">
+<EM CLASS="emphasis">
+C:\WINDOWS\INF\MSPRINT4.INF</em></td></tr></table><P CLASS="para">
+Once you have the four files, you can create a printer definition file using the appropriate printer driver and its .INF file. If the printer driver starts with the letters A-K, use either the <EM CLASS="emphasis">
+MSPRINT.INF</em> file or the <EM CLASS="emphasis">
+MSPRINT3.INF</em> file. If it begins with the letters L-Z, use the <EM CLASS="emphasis">
+MSPRINT2.INF</em> file or the <EM CLASS="emphasis">
+MSPRINT4.INF</em> file. You may need to <EM CLASS="emphasis">
+grep</em> through each of the files to see where your specific driver is. For the following example, we have located our driver in <EM CLASS="emphasis">
+MSPRINT3.INF</em> and created a printer definition file for a HP DeskJet 560C printer:</p><PRE CLASS="programlisting">
+$grep &quot;HP DeskJet 560C Printer&quot; MSPRINT.INF MSPRINT3.INF
+MSPRINT3.INF: &quot;HP DeskJet 560C Printer&quot;=DESKJETC.DRV,HP_DeskJet_ ...
+
+$make_printerdef MSPRINT3.INF &quot;HP DeskJet 560C Printer&quot; &gt;printers.def
+FOUND:DESKJETC.DRV
+End of section found
+CopyFiles: DESKJETC,COLOR_DESKJETC
+Datasection: (null)
+Datafile: DESKJETC.DRV
+Driverfile: DESKJETC.DRV
+Helpfile: HPVDJC.HLP
+LanguageMonitor: (null)
+
+Copy the following files to your printer$ share location:
+DESKJETC.DRV
+HPVCM.HPM
+HPVIOL.DLL
+HPVMON.DLL
+HPVRES.DLL
+HPCOLOR.DLL
+HPVUI.DLL
+HPVDJCC.HLP
+color\HPDESK.ICM</pre><P CLASS="para">
+Note the files that the script asks you to copy. You'll need those for the next step.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949683">
+7.1.7.3 Create a PRINTER$ share</a></h4><P CLASS="para">This part is relatively easy. Create a share called <CODE CLASS="literal">
+[PRINTER$]</code> in your <I CLASS="filename">
+smb.conf</i> that points to an empty directory on the Samba server. Once that is done, copy over the files that the <I CLASS="filename">
+make_ printerdef</i> script requested of you into the location of the <CODE CLASS="literal">
+path</code> configuration option for the <CODE CLASS="literal">
+[PRINTER$]</code> share. For example, you can put the following in your configuration file:</p><PRE CLASS="programlisting">
+[PRINTER$]
+ path = /usr/local/samba/print
+ read only = yes
+ browsable = no
+ guest ok = yes</pre><P CLASS="para">
+The files requested by the <I CLASS="filename">
+make_ printerdef</i> script are typically located in the <EM CLASS="emphasis">
+C:\WINDOWS\SYSTEM</em> directory, although you can use the following commands to find out exactly where they are:</p><PRE CLASS="programlisting">
+cd C:\WINDOWS
+dir <CODE CLASS="replaceable">
+<I>
+filename</i></code> /s</pre><P CLASS="para">
+In this case, each of the files needs to be copied to the <I CLASS="filename">
+/usr/local/samba/print</i> directory on the Samba server. In addition, copy the <I CLASS="filename">
+printers.def</i> file that you created over to that share as well. Once you've done that, you're almost ready to go. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949694">
+7.1.7.4 Modify the Samba configuration file</a></h4><P CLASS="para">
+<I CLASS="filename">
+</i>The last step is to modify the Samba configuration file by adding the following three options: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956995">
+</a><CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956996">
+</a><CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+file</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-956997">
+</a><CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+location</code></p></li></ul><P CLASS="para">
+The <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+file</code> is a global option that points to the <I CLASS="filename">
+printers.def</i> file; place that option in your <CODE CLASS="literal">
+[global]</code> section. The other options should be set in the printer share for which you wish to automatically configure the drivers. The value for <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> should match the string that shows up in the Printer Wizard on the Windows system. The value of the <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> <CODE CLASS="literal">
+location</code> is the pathname of the PRINTER$ share you set up, not the Unix pathname on the server. Thus, you could use the following:</p><PRE CLASS="programlisting">
+[global]
+ printer driver file = /usr/local/samba/print/printers.def
+[hpdeskjet]
+ path = /var/spool/samba/printers
+ printable = yes
+
+ printer driver = HP DeskJet 560C Printer
+ printer driver location = \\%L\PRINTER$</pre><P CLASS="para">
+Now you're ready to test it out. At this point, remove the Windows printer that you "set up" in the first step from the list of printers in the Printers window of My Computer. If Samba asks you to delete unneeded files, do so. These files will be replaced shortly on the client, as they now exist on the Samba server.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949710">
+7.1.7.5 Testing the configuration</a></h4><P CLASS="para">
+Restart the Samba daemons and look for the <CODE CLASS="literal">
+[hpdeskjet]</code> share under the machine name in the Network Neighborhood. At this point, if you click on the printer icon, you should begin the printer setup process and come to the dialog shown in <A CLASS="xref" HREF="ch07_01.html#ch07-60108">
+Figure 7.6</a>.</p><P CLASS="para">
+This is different from the dialog you saw earlier when setting up a printer. Essentially, the dialog is asking if you wish to accept the driver that is "already installed"&nbsp;- in other words, offered by Samba. Go ahead and keep the existing driver, and press the Next button. At this point, you can give the printer a name and print out a test page. If it works, the setup should be complete. You should be able to repeat the process now from any Windows client. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-60108">
+Figure 7.6: Automatically configuring the printer driver</a></h4><IMG CLASS="graphic" SRC="figs/sam.0706.gif" ALT="Figure 7.6"></div></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch06_06.html" TITLE="6.6 Logon Scripts">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 6.6 Logon Scripts" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_02.html" TITLE="7.2 Printing to Windows Client Printers">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7.2 Printing to Windows Client Printers" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+6.6 Logon Scripts</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+7.2 Printing to Windows Client Printers</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch07_02.html b/docs/htmldocs/using_samba/ch07_02.html
new file mode 100644
index 00000000000..c9a9010e976
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch07_02.html
@@ -0,0 +1,757 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 7] 7.2 Printing to Windows Client Printers</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:34:58Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_01.html" TITLE="7.1 Sending Print Jobs to Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.1 Sending Print Jobs to Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch07_01.html" TITLE="7. Printing and Name Resolution">
+Chapter 7<br>
+Printing and Name Resolution</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_03.html" TITLE="7.3 Name Resolution with Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7.3 Name Resolution with Samba" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch07-31526">
+7.2 Printing to Windows Client Printers</a></h2><P CLASS="para">If you have printers connected to clients running Windows 95/98 or NT 4.0, those printers can also be accessed from Samba. Samba comes equipped with a tool called <EM CLASS="emphasis">
+smbprint</em> that can be used to spool print jobs to Windows-based printers. In order to use this, however, you need to set up the printer as a shared resource on the client machine. If you haven't already done this, you can reset this from the Printers window, reached from the Start button, as shown in <A CLASS="xref" HREF="ch07_02.html#ch07-32814">
+Figure 7.7</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-32814">
+Figure 7.7: The Printers window</a></h4><IMG CLASS="graphic" SRC="figs/sam.0707.gif" ALT="Figure 7.7"><P CLASS="para">
+Select a printer that's locally connected (for example, ours is the Canon printer), press the right mouse button to bring up a menu, and select Sharing. This will give you the Sharing tab of the Printer Properties frame, as shown in <A CLASS="xref" HREF="ch07_02.html#ch07-92021">
+Figure 7.8</a>. If you want it available to everybody on your LAN as the Windows guest user, enter a blank password. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-92021">
+Figure 7.8: The Sharing tab of the printer</a></h4><IMG CLASS="graphic" SRC="figs/sam.0708.gif" ALT="Figure 7.8"><P CLASS="para">
+Once you've got this working, you can add your printer to the list of standard printers and Samba can make it available to all the other PCs in the workgroup. To make installation on Unix easier, the Samba distribution provides two sample scripts: <I CLASS="filename">
+smbprint</i> and <I CLASS="filename">
+smbprint.sysv</i>. The first works with BSD-style printers; the second is designed for System V printers.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-949813">
+7.2.1 BSD printers</a></h3><P CLASS="para">There are two steps you need to have a BSD Unix recognize a remote printer:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949817">
+</a>Place an entry for the printer in the <I CLASS="filename">
+/etc/printcap</i> file (or equivalent).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949818">
+</a>Place a configuration file in the <I CLASS="filename">
+/var/spool</i> directory for the printer.</p></li></ol><P CLASS="para">
+First, edit your <I CLASS="filename">
+/etc/printcap</i> file and add an entry for the remote printer. Note that the input filter (<CODE CLASS="literal">if</code>) entry needs to point to the <EM CLASS="emphasis">
+smbprint</em> program if the machine is on Windows 95/98. The following set of lines will accomplish on a Linux machine, for example:</p><PRE CLASS="programlisting">
+laserjet:\
+ :sd=/var/spool/lpd/laser:\ <CODE CLASS="replaceable">
+<I>
+# spool directory</i></code>
+ :mx#0:\ <CODE CLASS="replaceable">
+<I>
+# maximum file size (none)</i></code>
+ :sh:\ <CODE CLASS="replaceable">
+<I>
+# surpress burst header (no)</i></code>
+ :if=/usr/local/samba/bin/smbprint: <CODE CLASS="replaceable">
+<I>
+# text filter</i></code></pre><P CLASS="para">
+After that, you need to create a configuration file in the spool directory that you specified with the <CODE CLASS="literal">
+sd</code> parameter above. (You may need to create that directory.) The file must have the name <EM CLASS="emphasis">
+.config</em> and should contain the following information: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-954773">
+</a>The NetBIOS name of the Windows machine with the printer</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-954774">
+</a>The service name that represents the printer</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-954775">
+</a>The password used to access that service</p></li></ul><P CLASS="para">
+The last two parameters were set up in the Sharing dialog for the requested resource on the Windows machine. In this case, the <EM CLASS="emphasis">
+.config</em> file would have three lines:</p><PRE CLASS="programlisting">
+server = phoenix
+service = CANON
+password = &quot;&quot;</pre><P CLASS="para">
+After you've done that, reset the Samba server machine and try printing to it using any standard Unix program.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-949855">
+7.2.2 System V printers</a></h3><P CLASS="para">Sending print jobs from a System V Unix system is a little easier. Here, you need to get obtain the <I CLASS="filename">
+smbprint.sysv</i> script in the <I CLASS="filename">
+/usr/local/samba/examples/printing</i> directory and do the following:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949865">
+</a>Change the <CODE CLASS="literal">
+server</code>, <CODE CLASS="literal">
+service</code>, and <CODE CLASS="literal">
+password</code> parameters in the script to match the NetBIOS machine, its shared printer service, and its password, respectively. For example, the following entries would be correct for the service in the previous example:</p></li></ol><PRE CLASS="programlisting">
+server = phoenix
+service = CANON
+password = &quot;&quot;</pre><OL CLASS="orderedlist" START="2">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-949876">
+</a>Run the following commands, which create a reference for the printer in the printer capabilities file. Note that the new Unix printer entry <CODE CLASS="literal">canon_printer</code> is named:</p></li></ol><PRE CLASS="programlisting">
+# lpadmin -p canon_printer -v /dev/null -i ./smbprint.sysv
+# enable canon_printer
+# accept canon_printer</pre><P CLASS="para">
+After you've done that, restart the Samba daemons and try printing to it using any standard Unix program. You should now be able to send data to a printer on a Windows client across the network.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-950287">
+7.2.3 Samba Printing Options</a></h3><P CLASS="para">
+<A CLASS="xref" HREF="ch07_02.html#ch07-19361">Table 7.2</a> summarizes the Samba printing options. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch07-19361">
+Table 7.2: Printing Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printing</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+bsd</code>, <CODE CLASS="literal">
+sysv</code>, <CODE CLASS="literal">
+hpux</code>, <CODE CLASS="literal">
+aix</code>, <CODE CLASS="literal">
+qnx</code>, <CODE CLASS="literal">
+plp</code>, <CODE CLASS="literal">
+softq</code>, or <CODE CLASS="literal">
+lprng</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the print system type for your Unix system.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+System dependent</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printable (print ok)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Marks a share as a printing share.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printer (printer name)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (Unix printer name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the name of the printer to be shown to clients.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+System dependent</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printer driver</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (printer driver name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the driver name that should be used by the client to send data to the printer.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printer driver file</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the name of the printer driver file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printer driver location</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (network pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the pathname of the share for the printer driver file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lpq cache time</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric (time in seconds)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the amount of time in seconds that Samba will cache the lpq status.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+10</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+postscript</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Treats all print jobs sent as postscript by prepending <CODE CLASS="literal">
+%!</code> at the beginning of each file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+load printers</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Automatically loads each of the printers in the <EM CLASS="emphasis">
+printcap</em> file as printing shares.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+print command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to perform printing.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lpq command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to return the status of the printing queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lprm command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to remove a job from the printing queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lppause command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to pause a job on the printing queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lpresume command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to resume a paused job on the printing queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+printcap name</code></p><P CLASS="para">
+<CODE CLASS="literal">
+(printcap)</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the location of the printer capabilities file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+System dependent</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+min print space</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numeric (size in kilobytes)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the minimum amount of disk free space that must be present to print.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+queuepause command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to pause a queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+queueresume command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (shell command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the Unix command to resume a queue.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+See below</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950502">
+7.2.3.1 printing</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+printing</code> configuration option tells Samba a little about your Unix printing system, in this case which printing parser to use. With Unix, there are several different families of commands to control printing and print statusing. Samba supports seven different types, as shown in <A CLASS="xref" HREF="ch07_02.html#ch07-28758">
+Table 7.3</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch07-28758">
+Table 7.3: Printing Types </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+BSD</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Berkeley Unix system</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SYSV</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+System V</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+AIX</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+AIX Operating System (IBM)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+HPUX</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Hewlett-Packard Unix </p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+QNX</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+QNX Realtime Operating System (QNX)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+LPRNG</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+LPR Next Generation (Powell)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SOFTQ</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SOFTQ system</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+PLP</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Portable Line Printer (Powell)</p></td></tr></tbody></table><P CLASS="para">
+The value for this optio.n will be one of these seven options. For example:</p><PRE CLASS="programlisting">
+printing = SYSV</pre><P CLASS="para">
+The default value of this option is system dependent and is configured when Samba is first compiled. For most systems, the <I CLASS="filename">
+configure</i> script will automatically detect the printing system to be used and configure it properly in the Samba makefile. However, if your system is a PLP, LPRNG, or QNX printing system, you will need to explicitly specify this in the makefile or the printing share.</p><P CLASS="para">
+The most common system types are BSD and SYSV. Each of the printers on a BSD Unix server are described in the printer capabilities file&nbsp;- normally <I CLASS="filename">
+/etc/printcap</i>.</p><P CLASS="para">
+Setting the <CODE CLASS="literal">
+printing</code> configuration option automatically sets at least three other printing options for the service in question: <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code>, <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+command</code>, and <CODE CLASS="literal">
+lprm</code> <CODE CLASS="literal">
+command</code>. If you are running Samba on a system that doesn't support any of these printing styles, simply set the commands for each of these manually.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950507">
+7.2.3.2 printable</a></h4><P CLASS="para">
+The printable option must be set to <CODE CLASS="literal">
+yes</code> in order to flag a share as a printing service. If this option is not set, the share will be treated as a disk share instead. You can set the option as follows:</p><PRE CLASS="programlisting">
+[printer1]
+ printable = yes</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950511">
+7.2.3.3 printer</a></h4><P CLASS="para">The option, sometimes called <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+name</code>, specifies the name of the printer on the server to which the share points. This option has no default and should be set explicitly in the configuration file, even though Unix systems themselves often recognize a default name such as <CODE CLASS="literal">
+lp</code> for a printer. For example:</p><PRE CLASS="programlisting">
+[deskjet]
+ printer = hpdkjet1</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950515">
+7.2.3.4 printer driver</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+printer</code> <CODE CLASS="literal">
+driver</code> option sets the string that Samba uses to tell Windows what the printer is. If this option is set correctly, the Windows Printer Wizard will already know what the printer is, making installation easier for end users by giving them one less dialog to worry about. The string given should match the string that shows up in the Printer Wizard, as shown in <A CLASS="xref" HREF="ch07_02.html#ch07-46183">
+Figure 7.9</a>. For example, an Apple LaserWriter typically uses <CODE CLASS="literal">
+Apple</code> <CODE CLASS="literal">LaserWriter</code>; a Hewlett Packard Deskjet 560C uses <CODE CLASS="literal">
+HP</code> <CODE CLASS="literal">
+DeskJet</code> <CODE CLASS="literal">
+560C</code> <CODE CLASS="literal">
+Printer</code>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch07-46183">
+Figure 7.9: The Add Printer Wizard dialog box in Windows 98</a></h4><IMG CLASS="graphic" SRC="figs/sam.0709.gif" ALT="Figure 7.9"><P CLASS="para">
+Automatically configuring printer drivers with Samba is explained in greater detail in the section <A CLASS="xref" HREF="ch07_01.html#ch07-30008">
+Section 7.1.7, Automatically Setting Up Printer Drivers</a>, earlier in this chapter.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-954814">
+7.2.3.5 printer driver file</a></h4><P CLASS="para">
+This global option gives the location of the Windows 95/98 printer driver definition file, which is needed to give printer drivers to clients using a Samba printer. The default value of this option is <I CLASS="filename">
+/usr/local/samba/lib/printers.def</i>. You can override this default as shown below:</p><PRE CLASS="programlisting">
+[deskjet]
+ printer driver file = /var/printers/printers.def</pre><P CLASS="para">
+This option is explained in greater detail in the section <A CLASS="xref" HREF="ch07_01.html#ch07-30008">
+Section 7.1.7</a>, earlier in this chapter.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950552">
+7.2.3.6 printer driver location</a></h4><P CLASS="para">
+This option specifies a specific share that contains Windows 95 and 98 printer driver and definition files. There is no default parameter for this value. You can specify the location as a network pathname. A frequent approach is to use a share on your own machine, as shown here:</p><PRE CLASS="programlisting">
+[deskjet]
+ printer driver location = \\%L\PRINTER$</pre><P CLASS="para">
+This option is also explained in greater detail in the section <A CLASS="xref" HREF="ch07_01.html#ch07-30008">
+Section 7.1.7</a>, earlier in this chapter. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950560">
+7.2.3.7 lpq cache time</a></h4><P CLASS="para">The global <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+cache</code> <CODE CLASS="literal">
+time</code> option allows you to set the number of seconds that Samba will remember the current printer status. After this time elapses, Samba will issue an <EM CLASS="emphasis">
+lpq</em> command (or whatever command you specify with the <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+command</code> option) to get a more up-to-date status. This defaults to 10 seconds, but can be increased if your <CODE CLASS="literal">
+lpq</code> <CODE CLASS="literal">
+command</code> takes an unusually long time to run or you have lots of clients. The following example resets the time to 30 seconds:</p><PRE CLASS="programlisting">
+[deskjet]
+ lpq cache time = 30</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950564">
+7.2.3.8 postscript</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+postscript</code> option forces the printer to treat all data sent to it as Postscript. It does this by prepending the characters <CODE CLASS="literal">
+%!</code> at the beginning of the first line of each job. It is normally used with PCs that insert a <CODE CLASS="literal">
+^D</code> (control-D or end-of-file mark) in front of the first line of a PostScript file. It will not, obviously, turn a non-PostScript printer into a PostScript one. The default value of this options is <CODE CLASS="literal">
+no</code>. You can override it as follows:</p><PRE CLASS="programlisting">[deskjet]
+ postscript = yes</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950568">
+7.2.3.9 print command, lpq command, lprm command, lppause command, lpresume command</a></h4><P CLASS="para">These options tell Samba which Unix commands used to control and send data to the printer. The Unix commands involved are: <EM CLASS="emphasis">
+lpr</em> (send to Line PRinter), <EM CLASS="emphasis">
+lpq</em> (List Printer Queue), <EM CLASS="emphasis">
+lprm</em> (Line printer ReMove), and optionally <EM CLASS="emphasis">
+lppause</em> and <EM CLASS="emphasis">
+lpresume</em>. Samba provides an option named after each of these commands, in case you need to override any of the system defaults. For example, consider:</p><PRE CLASS="programlisting">
+lpq command = /usr/ucb/lpq %p</pre><P CLASS="para">
+This would set the <CODE CLASS="literal">
+lpq command</code> to use <I CLASS="filename">
+/usr/ucb/lpq</i>. Similarly:</p><PRE CLASS="programlisting">
+lprm command = /usr/local/lprm -P%p %j</pre><P CLASS="para">
+would set the Samba printer remove command to <I CLASS="filename">
+/usr/local/lprm</i>, and provide it the print job number using the <CODE CLASS="literal">
+%j</code> variable.</p><P CLASS="para">
+The default values for each of these options are dependent on the value of the <CODE CLASS="literal">
+printing</code> option. <A CLASS="xref" HREF="ch07_02.html#ch07-82964">
+Table 7.4</a> shows the default commands for each of the printing options. The most popular printing system is BSD. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch07-82964">
+Table 7.4: Default Commands for Various Printing Commands </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+BSD, AIX, PLP, LPRNG</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SYSV, HPUX</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+QNX</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+SOFTQ</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+print command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpr -r -P%p %s</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">lp -c -d%p %s; rm %s</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lp -r -P%p %s</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lp -d%p -s %s; rm %s</code></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lpq command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpq -P%p</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpstat -o%p</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpq -P%p</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpstat -o%p</code></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lprm command</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lprm -P%p %j</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+cancel %p-%j</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+cancel %p-%j</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+cancel %p-%j</code></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lppause command</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lp -i %p-%j -H hold </code>(SYSV only)</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+None</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+None</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+None</td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lpresume command</code></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+lp -i %p-%j -H resume</code>(SYSV only)</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+None</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+None</td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<CODE CLASS="literal">
+qstat -s -j%j -r</code>
+</td></tr></tbody></table><P CLASS="para">
+It is typically not necessary to reset these options in Samba, with the possible exception of <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+command</code>. This option may need to be explicitly set if your printing system doesn't have a <CODE CLASS="literal">
+-r</code> (remove after printing) option on the printing command. For example: </p><PRE CLASS="programlisting">
+/usr/local/lpr -P%p %s; /bin/rm %s</pre><P CLASS="para">
+With a bit of judicious programming, these <I CLASS="filename">
+smb.conf</i> options can also used for debugging:</p><PRE CLASS="programlisting">
+print command = cat %s &gt;&gt;/tmp/printlog; lpr -r -P%p %s</pre><P CLASS="para">
+For example, this configuration can verify that files are actually being delivered to the Samba server. If they are, their contents will show up in the <I CLASS="filename">
+/tmp/printlog</i> file.</p><P CLASS="para">
+After BSD, the next most popular kind of printing system is SYSV (or System V) printing, plus some SYSV variants for IBM's AIX and Hewlett-Packard's HP-UX. These system do not have an <I CLASS="filename">
+/etc/printcap</i> file. Instead, the <CODE CLASS="literal">
+printcap</code> <CODE CLASS="literal">
+file</code> option can be set to an appropriate <EM CLASS="emphasis">
+lpstat</em> command for the system. This tells Samba to get a list of printers from the <EM CLASS="emphasis">
+lpstat</em> command. Alternatively, you can set the global configuration option <CODE CLASS="literal">
+printcap</code> <CODE CLASS="literal">
+name</code> to the name of a dummy <I CLASS="filename">
+printcap</i> file you provide. In the latter case, the file must contain a series of lines such as:</p><PRE CLASS="programlisting">
+lp|print1|My Printer 1
+print2|My Printer 2
+print3|My Printer 3</pre><P CLASS="para">
+Each line names a printer, and provides aliases for it. In this example, the first printer is called <CODE CLASS="literal">
+lp</code>, <CODE CLASS="literal">
+print1</code>, or <CODE CLASS="literal">
+My</code> <CODE CLASS="literal">
+Printer</code> <CODE CLASS="literal">
+1</code>, whichever the user prefers to use. The first name will be used in place of <CODE CLASS="literal">
+%p</code> in any command Samba executes for that printer.</p><P CLASS="para">
+Two additional printer types are also supported by Samba: LPRNG (LPR New Generation) and PLP (Public Line Printer). These are public domain and Open Source printing systems, and are used by many sites to overcome problems with vendor-supplied software. In addition, the SOFTQ and QNX realtime operating systems are supported by Samba.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950650">
+7.2.3.10 load printers</a></h4><P CLASS="para">The <CODE CLASS="literal">
+load</code> <CODE CLASS="literal">
+printers</code> option tells Samba to create shares for all known printer names and load those shares into the browse list. Samba will create and list a printer share for each printer name in <I CLASS="filename">
+/etc/printcap</i> (or system equivalent). For example, if your <I CLASS="filename">
+printcap</i> file looks like this:[<A CLASS="footnote" HREF="#ch07-pgfId-950654">2</a>]</p><BLOCKQUOTE CLASS="footnote">
+<DIV CLASS="footnote">
+<P CLASS="para">
+<A CLASS="footnote" NAME="ch07-pgfId-950654">[2]</a> We have placed annotated comments off to the side in case you've never dealt with this file before.</p></div></blockquote><PRE CLASS="programlisting">
+lp:\
+ :sd=/var/spool/lpd/lp:\ <CODE CLASS="replaceable">
+<I>
+# spool directory</i></code>
+ :mx#0:\ <CODE CLASS="replaceable">
+<I>
+# maximum file size (none)</i></code>
+ :sh:\ <CODE CLASS="replaceable">
+<I>
+# surpress burst header (no)</i></code>
+ :lp=/dev/lp1:\ <CODE CLASS="replaceable">
+<I>
+# device name for output</i></code>
+ :if=/var/spool/lpd/lp/filter: <CODE CLASS="replaceable">
+<I>
+# text filter</i></code>
+
+laser:\
+ :sd=/var/spool/lpd/laser:\ <CODE CLASS="replaceable">
+<I>
+# spool directory</i></code>
+ :mx#0:\ <CODE CLASS="replaceable">
+<I>
+# maximum file size (none)</i></code>
+ :sh:\ <CODE CLASS="replaceable">
+<I>
+# surpress burst header (no)</i></code>
+ :lp=/dev/laser:\ <CODE CLASS="replaceable">
+<I>
+# device name for output</i></code>
+ :if=/var/spool/lpd/lp/filter: <CODE CLASS="replaceable">
+<I>
+# text filter</i></code></pre><P CLASS="para">
+and you specify:</p><PRE CLASS="programlisting">
+load printers = yes</pre><P CLASS="para">
+the shares <CODE CLASS="literal">
+[lp]</code> and <CODE CLASS="literal">
+[laser]</code> will automatically be created as valid print shares when Samba is started. Both shares will borrow the configuration options specified in the <CODE CLASS="literal">
+[printers]</code> section to configure themselves, and will be available in the browse list for the Samba server.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950671">
+7.2.3.11 printcap name</a></h4><P CLASS="para">
+If the <CODE CLASS="literal">
+printcap</code> <CODE CLASS="literal">
+name</code> option (also called <CODE CLASS="literal">
+printcap</code>) appears in a printing share, Samba will use the file specified as the system printer capabilities file. This is normally <I CLASS="filename">
+/etc/printcap</i>. However, you can reset it to a file consisting of only the printers you want to share over the network. The value must be a fully-qualified filename of a printer capabilities file on the server:</p><PRE CLASS="programlisting">
+[deskjet]
+ printcap name = /usr/local/printcap</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950678">
+7.2.3.12 min print space</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+min</code> <CODE CLASS="literal">
+print</code> <CODE CLASS="literal">
+space</code> option sets the amount of spool space that must be available on the disk before printing is allowed. Setting it to zero (the default) turns the check off; setting it to any other number sets the amount of free space in kilobytes required. This option helps avoid having print jobs fill up the remaining disk space on the server, which may cause other processes to fail:</p><PRE CLASS="programlisting">
+[deskjet]
+ min print space = 4000</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950682">
+7.2.3.13 queuepause command</a></h4><P CLASS="para">
+This configuration option specifies a command that tells Samba how to pause a print queue entirely, as opposed to a single job on the queue. The default value depends on the printing type chosen. You should not need to alter this option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-950684">
+7.2.3.14 queueresume command</a></h4><P CLASS="para">
+This configuration option specifies a command that tells Samba how to resume a paused print queue, as opposed to resuming a single job on the print queue. The default value depends on the printing type chosen. You should not need to alter this option. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_01.html" TITLE="7.1 Sending Print Jobs to Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.1 Sending Print Jobs to Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_03.html" TITLE="7.3 Name Resolution with Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 7.3 Name Resolution with Samba" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+7.1 Sending Print Jobs to Samba</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+7.3 Name Resolution with Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch07_03.html b/docs/htmldocs/using_samba/ch07_03.html
new file mode 100644
index 00000000000..56a531681ca
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch07_03.html
@@ -0,0 +1,404 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 7] 7.3 Name Resolution with Samba</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:08Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_02.html" TITLE="7.2 Printing to Windows Client Printers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.2 Printing to Windows Client Printers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch07_01.html" TITLE="7. Printing and Name Resolution">
+Chapter 7<br>
+Printing and Name Resolution</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8. Additional Samba Information " BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch07-12219">
+7.3 Name Resolution with Samba</a></h2><P CLASS="para">Before NetBIOS Name Servers (NBNS) came about, name resolution worked entirely by broadcast. If you needed a machine's address, you simply broadcast its name across the network and, in theory, the machine itself would reply. This approach is still possible: anyone looking for a machine named <CODE CLASS="literal">
+fred</code> can still broadcast a query and find out if it exists and what its IP address is. (We use this capability to troubleshoot Samba name services with the <CODE CLASS="literal">
+nmblookup</code> command in <a href="ch09_01.html"><b>Chapter 9, <CITE CLASS="chapter">Troubleshooting Samba</cite></b></a>.)</p><P CLASS="para">
+As you saw in the first chapter, however, broadcasting&nbsp;- whether it be browsing or name registration and resolution&nbsp;- does not pass easily across multiple subnets. In addition, many broadcasts tend to bog down networks. To solve this problem, Microsoft now provides the Windows Internet Naming Service (WINS), a cross-subnet NBNS, which Samba supports. With it, an administrator can designate a single machine to act as a WINS server, and can then provide each client that requires name resolution the address of the WINS server. Consequently, name registration and resolution requests can be directed to a single machine from any point on the network, instead of broadcast.</p><P CLASS="para">
+WINS and broadcasting are not the only means of name resolution, however. There are actually four mechanisms that can be used with Samba:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-950848">
+</a>WINS</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-950856">
+</a>Broadcasting</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-950851">
+</a>Unix <I CLASS="filename">
+/etc/hosts</i> or NIS/NIS+ matches</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch07-pgfId-951953">
+</a><EM CLASS="emphasis">
+LMHOSTS</em> file</p></li></ul><P CLASS="para">
+Samba can use any or all of these name resolution methods in the order that you specify in the Samba configuration file using the <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+resolve</code> <CODE CLASS="literal">
+order</code> parameter. However, before delving into configuration options, let's discuss the one that you've probably not encountered before: the <I CLASS="filename">
+LMHOSTS</i> file.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-949950">
+7.3.1 The LMHOSTS File</a></h3><P CLASS="para">
+<I CLASS="filename">
+LMHOSTS</i> is the standard LAN Manager <EM CLASS="emphasis">
+hosts</em> file used to resolve names into IP addresses on the system. It is the NBT equivalent of the <I CLASS="filename">
+/etc/hosts</i> file that is standard on all Unix systems. By default, the file is usually stored as <I CLASS="filename">
+/usr/local/samba/lib/LMHOSTS</i> and shares a format similar to <I CLASS="filename">
+/etc/hosts</i>. For example:</p><PRE CLASS="programlisting">
+192.168.220.100 hydra
+192.168.220.101 phoenix</pre><P CLASS="para">
+The only difference is that the names on the right side of the entries are NetBIOS names instead of DNS names. Because they are NetBIOS names, you can assign resource types to them as well:</p><PRE CLASS="programlisting">
+192.168.220.100 hydra#20
+192.168.220.100 simple#1b
+192.168.220.101 phoenix#20</pre><P CLASS="para">
+Here, we've assigned the <CODE CLASS="literal">
+hydra</code> machine to be the primary domain controller of the <CODE CLASS="literal">
+SIMPLE</code> domain, as indicated by the resource type &lt;1B&gt; assigned to the name after <CODE CLASS="literal">
+hydra</code>'s IP address in the second line. The other two are standard workstations.</p><P CLASS="para">
+If you wish to place an <EM CLASS="emphasis">
+LMHOSTS</em> file somewhere other than the default location, you will need to notify the <EM CLASS="emphasis">
+nmbd</em> process upon start up, as follows:</p><PRE CLASS="programlisting">
+nmbd -H /etc/samba/lmhosts -D</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-951120">
+7.3.2 Setting Up Samba to Use Another WINS Server</a></h3><P CLASS="para">You can set up Samba to use a WINS server somewhere else on the network by simply pointing it to the IP address of the WINS server. This is done with the global <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+server</code> configuration option, as shown here:</p><PRE CLASS="programlisting">
+[global]
+ wins server = 192.168.200.122</pre><P CLASS="para">
+With this option enabled, Samba will direct all WINS requests to the server at 192.168.200.122. Note that because the request is directed at a single machine, we don't have to worry about any of the problems inherent to broadcasting. However, though you have specified an IP address for a WINS server in the configuration file, Samba will not necessarily use the WINS server before other forms of name resolution. The order in which Samba attempts various name-resolution techniques is given with the <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+resolve</code> <CODE CLASS="literal">
+order</code> configuration option, which we will discuss shortly.</p><P CLASS="para">
+If you have a Samba server on a subnet that still uses broadcasting and the Samba server knows the correct location of a WINS server on another subnet, you can configure the Samba server to forward any name resolution requests with the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+proxy</code> option:</p><PRE CLASS="programlisting">
+[global]
+ wins server = 192.168.200.12
+ wins proxy = yes</pre><P CLASS="para">
+Use this only in situations where the WINS server resides on another subnet. Otherwise, the broadcast will reach the WINS server regardless of any proxying.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-83429">
+7.3.3 Setting Up Samba as a WINS Server</a></h3><P CLASS="para">You can set up Samba as a WINS server by setting two global options in the configuration file, as shown below:</p><PRE CLASS="programlisting">
+[global]
+ wins support = yes
+ name resolve order = wins lmhosts hosts bcast</pre><P CLASS="para">
+The <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+support</code> option turns Samba into a WINS server. Believe it or not, that's all you need to do! Samba handles the rest of the details behind the scenes, leaving you a relaxed administrator. The <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+support=yes</code> and the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+server</code> option are mutually exclusive; you cannot simultaneously offer Samba as the WINS server and point to another system as the server.</p><P CLASS="para">
+If Samba is acting as a WINS server, you should probably get familiar with the <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+resolve</code> <CODE CLASS="literal">
+order</code> option mentioned earlier. This option tells Samba the order of methods in which it tries to resolve a NetBIOS name. It can take up to four values:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+lmhosts</dt><DD CLASS="listitem">
+<P CLASS="para">
+Uses a LAN Manager <EM CLASS="emphasis">
+LMHOSTS</em> file</p></dd><DT CLASS="term">
+hosts</dt><DD CLASS="listitem">
+<P CLASS="para">
+Uses the standard name resolution methods of the Unix system, <EM CLASS="emphasis">
+/etc/hosts</em>, DNS, NIS, or a combination (as configured for the system)</p></dd><DT CLASS="term">
+wins</dt><DD CLASS="listitem">
+<P CLASS="para">
+Uses the WINS server</p></dd><DT CLASS="term">
+bcast</dt><DD CLASS="listitem">
+<P CLASS="para">
+Uses a broadcast method</p></dd></dl><P CLASS="para">
+The order in which you specify them in the value is the order in which Samba will attempt name resolution when acting as a WINS server. For example, let's look at the value specified previously:</p><PRE CLASS="programlisting">
+name resolve order = wins lmhosts hosts bcast</pre><P CLASS="para">
+This means that Samba will attempt to use its WINS entries first for name resolution, followed by the LAN Manager <EM CLASS="emphasis">
+LMHOSTS</em> file on its system. Next, the hosts value causes it to use Unix name resolution methods. The word <CODE CLASS="literal">
+hosts</code> may be misleading; it covers not only the <I CLASS="filename">
+/etc/hosts</i> file, but also the use of DNS or NIS (as configured on the Unix host). Finally, if those three do not work, it will use a broadcast to try to locate the correct machine.</p><P CLASS="para">
+Finally, you can instruct a Samba server that is acting as a WINS server to check with the system's DNS server if a requested host cannot be found in its WINS database. With a typical Linux system, for example, you can find the IP address of the DNS server by searching the <I CLASS="filename">
+/etc/resolv.conf</i> file. In it, you might see an entry such as the following:</p><PRE CLASS="programlisting">
+nameserver 127.0.0.1
+nameserver 192.168.200.192</pre><P CLASS="para">
+This tells us that a DNS server is located at 192.168.220.192. (The 127.0.0.1 is the localhost address and is never a valid DNS server address.) </p><P CLASS="para">
+Use the global <CODE CLASS="literal">
+dns</code> <CODE CLASS="literal">
+proxy</code> option to alert Samba to use the configured DNS server:</p><PRE CLASS="programlisting">
+[global]
+ wins support = yes
+ name resolve order = wins lmhosts hosts bcast
+ dns proxy = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch07-pgfId-949952">
+7.3.4 Name Resolution Configuration Options</a></h3><P CLASS="para">Samba's WINS options are shown in <A CLASS="xref" HREF="ch07_03.html#ch07-82331">
+Table 7.5</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch07-82331">
+Table 7.5: WINS Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+wins support</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, Samba will act as a WINS server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+wins server</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (IP address or DNS name)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Identifies a WINS server for Samba to use for name registration and resolution.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+wins proxy</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows Samba to act as a proxy to a WINS server on another subnet.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+dns proxy</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If set to <CODE CLASS="literal">
+yes</code>, a Samba WINS server will search DNS if it cannot find a name in WINS.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+name resolve order</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lmhosts</code>, <CODE CLASS="literal">
+hosts</code>, <CODE CLASS="literal">
+wins</code>, or <CODE CLASS="literal">
+bcast</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies an order of the methods used to resolve NetBIOS names.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+lmhosts hosts wins bcast</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max ttl</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the maximum time-to-live in seconds for a requested NetBIOS names.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+259200</code> (3 days)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max wins ttl</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the maximum time-to-live in seconds for NetBIOS names given out by Samba as a WINS server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+518400</code> (6 days)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+min wins ttl</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the minimum time-to-live in seconds for NetBIOS names given out by Samba as a WINS server.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+21600</code> (6 hours)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-946762">
+7.3.4.1 wins support</a></h4><P CLASS="para">
+Samba will provide WINS name service to all machines in the network if you set the following in the <CODE CLASS="literal">
+[global]</code> section of the <I CLASS="filename">
+smb.conf</i> file:</p><PRE CLASS="programlisting">
+[global]
+ wins support = yes</pre><P CLASS="para">
+The default value is <CODE CLASS="literal">
+no</code>, which is typically used to allow another Windows NT server to become a WINS server. If you do enable this option, remember that a Samba WINS server currently cannot exchange data with any backup WINS servers. If activated, this option is mutually exclusive with the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+server</code> parameter; you cannot set both to <CODE CLASS="literal">
+yes</code> at the same time or Samba will flag an error.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-946766">
+7.3.4.2 wins server</a></h4><P CLASS="para">
+Samba will use an existing WINS server on the network if you specify the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+server</code> global option in your configuration file. The value of this option is either the IP address or DNS name (not NetBIOS name) of the WINS server. For example:</p><PRE CLASS="programlisting">
+[global]
+ wins server = 192.168.220.110</pre><P CLASS="para">
+or:</p><PRE CLASS="programlisting">
+[global]
+ wins server = wins.example.com</pre><P CLASS="para">
+In order for this option to work, the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+support</code> option must be set to <CODE CLASS="literal">
+no</code> (the default). Otherwise, Samba will report an error. You can specify only one WINS server using this option.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-947973">
+7.3.4.3 wins proxy</a></h4><P CLASS="para">
+This option allows Samba to act as a proxy to another WINS server, and thus relay name registration and resolution requests from itself to the real WINS server, often outside the current subnet. The WINS server can be indicated through the <CODE CLASS="literal">
+wins</code> <CODE CLASS="literal">
+server</code> option. The proxy will then return the WINS response back to the client. You can enable this option by specifying the following in the <CODE CLASS="literal">
+[global]</code> section:</p><PRE CLASS="programlisting">
+[global]
+ wins proxy = yes</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-946778">
+7.3.4.4 dns proxy</a></h4><P CLASS="para">
+If you want the domain name service (DNS) to be used if a name isn't found in WINS, you can set the following option:</p><PRE CLASS="programlisting">
+[global]
+ dns proxy = yes</pre><P CLASS="para">
+This will cause <I CLASS="filename">
+nmbd</i> to query for machine names using the server's standard domain name service. You may wish to deactivate this option if you do not have a permanent connection to your DNS server. Despite this option, we recommend using a WINS server. If you don't already have any WINS servers on your network, make one Samba machine a WINS server. Do not, however, make two Samba machines WINS servers (one primary and one backup) as they currently cannot exchange WINS databases.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949945">
+7.3.4.5 name resolve order</a></h4><P CLASS="para">
+The global <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+resolve</code> <CODE CLASS="literal">
+order</code> option specifies the order of services that Samba will use in attempting name resolution. The default order is to use the <EM CLASS="emphasis">
+LMHOSTS</em> file, followed by standard Unix name resolution methods (some combination of <I CLASS="filename">
+/etc/hosts</i>, DNS, and NIS), then query a WINS server, and finally use broadcasting to determine the address of a NetBIOS name. You can override this option by specifying something like the following:</p><PRE CLASS="programlisting">
+[global]
+ name resolve order = lmhosts wins hosts bcast</pre><P CLASS="para">
+This causes resolution to use the <EM CLASS="emphasis">
+LMHOSTS</em> file first, followed by a query to a WINS server, the system password file, and finally broadcasting. You need not use all four options if you don't want to. This option is covered in more detail in the section <A CLASS="xref" HREF="ch07_03.html#ch07-83429">
+Section 7.3.3, Setting Up Samba as a WINS Server</a>, earlier in this chapter.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949986">
+7.3.4.6 max ttl</a></h4><P CLASS="para">
+This option gives the maximum time to live (TTL) during which a NetBIOS name registered with the Samba server will remain active. You should never need to alter this value.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949988">
+7.3.4.7 max wins ttl</a></h4><P CLASS="para">
+This option give the maximum time to live (TTL) during which a NetBIOS name resolved from a WINS server will remain active. You should never need to change this value from its default.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch07-pgfId-949990">
+7.3.4.8 min wins ttl</a></h4><P CLASS="para">
+This option give the minimum time to live (TTL) during which a NetBIOS name resolved from a WINS server will remain active. You should never need to alter this value from its default. </p></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_02.html" TITLE="7.2 Printing to Windows Client Printers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.2 Printing to Windows Client Printers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8. Additional Samba Information " BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+7.2 Printing to Windows Client Printers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8. Additional Samba Information </td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_01.html b/docs/htmldocs/using_samba/ch08_01.html
new file mode 100644
index 00000000000..a6767271b62
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_01.html
@@ -0,0 +1,267 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] Additional Samba Information </title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:49Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_03.html" TITLE="7.3 Name Resolution with Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.3 Name Resolution with Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 8</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_02.html" TITLE="8.2 Magic Scripts">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.2 Magic Scripts" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch08-74589">
+8. Additional Samba Information </a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch08-56646" TITLE="8.1 Supporting Programmers">
+Supporting Programmers</a><br>
+<A CLASS="sect1" HREF="ch08_02.html" TITLE="8.2 Magic Scripts">
+Magic Scripts</a><br>
+<A CLASS="sect1" HREF="ch08_03.html" TITLE="8.3 Internationalization">
+Internationalization</a><br>
+<A CLASS="sect1" HREF="ch08_04.html" TITLE="8.4 WinPopup Messages">
+WinPopup Messages</a><br>
+<A CLASS="sect1" HREF="ch08_05.html" TITLE="8.5 Recently Added Options">
+Recently Added Options</a><br>
+<A CLASS="sect1" HREF="ch08_06.html" TITLE="8.6 Miscellaneous Options">
+Miscellaneous Options</a><br>
+<A CLASS="sect1" HREF="ch08_07.html" TITLE="8.7 Backups with smbtar">
+Backups with smbtar</a></p><P>
+</p></div><P CLASS="para">
+This chapter wraps up our coverage of the <I CLASS="filename">
+smb.conf</i> configuration file with some miscellaneous options that can perform a variety of tasks. We will talk briefly about options for supporting programmers, internationalization, messages, and common Windows bugs. For the most part, you will use these options only in isolated circumstances. We also cover performing automated backups with the <I CLASS="filename">
+smbtar</i> command at the end of this chapter. So without further ado, let's jump into our first subject: options to help programmers.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch08-56646">
+8.1 Supporting Programmers</a></h2><P CLASS="para">If you have programmers accessing your Samba server, you'll want to be aware of the special options listed in <A CLASS="xref" HREF="ch08_01.html#ch08-73167">
+Table 8.1</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-73167">
+Table 8.1: Programming Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+time server</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, <EM CLASS="emphasis">
+nmbd</em> announces itself as a SMB time service to Windows clients.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+time offset</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (number of minutes)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Adds a specified number of minutes to the reported time.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+dos filetimes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Allows non-owners of a file to change its time if they can write to it.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+dos filetime</code></p><P CLASS="para">
+<CODE CLASS="literal">
+resolution</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Causes file times to be rounded to the next even second.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+fake directory create times</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets directory times to avoid a MS <EM CLASS="emphasis">
+nmake</em> bug.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958487">
+8.1.1 Time Synchronization</a></h3><P CLASS="para">Time synchronization can be very important to programmers. Consider the following options:</p><PRE CLASS="programlisting">
+time service = yes
+dos filetimes = yes
+fake directory create times = yes
+dos filetime resolution = yes
+delete readonly = yes</pre><P CLASS="para">
+If you set these options, Samba shares will provide the kind of compatible file times that Visual C++, <EM CLASS="emphasis">
+nmake</em>, and other Microsoft programming tools require. Otherwise, PC <EM CLASS="emphasis">
+make</em> programs will tend to think that all the files in a directory need to be recompiled every time. Obviously, this is not the behavior you want.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch08-pgfId-958495">
+8.1.1.1 time server</a></h4><P CLASS="para">
+If your Samba server has an accurate clock, or if it's a client of one of the Unix network time servers, you can instruct it to advertise itself as an SMB time server by setting the <CODE CLASS="literal">
+time</code> <CODE CLASS="literal">
+server</code> option as follows:</p><PRE CLASS="programlisting">
+[global]
+ time service = yes</pre><P CLASS="para">
+The client will still have to request the correct time with the following DOS command, substituting the Samba server name in at the appropriate point:</p><PRE CLASS="programlisting">
+C:\NET TIME \\<CODE CLASS="replaceable"><I>server</i></code> /YES /SET</pre><P CLASS="para">
+This command can be placed in a Windows logon script (see <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains </cite></b></a>).</p><P CLASS="para">
+By default, the <CODE CLASS="literal">
+time</code> <CODE CLASS="literal">
+server</code> option is normally set to <CODE CLASS="literal">
+no</code>. If you turn this service on, you can use the command above to keep the client clocks from drifting. Time synchronization is important to clients using programs such as <EM CLASS="emphasis">
+make</em>, which compile based on the last time the file was changed. Incorrectly synchronized times can cause such programs to either remake all files in a directory, which wastes time, or not recompile a source file that was just modified because of a slight clock drift.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch08-pgfId-958501">
+8.1.1.2 time offset</a></h4><P CLASS="para">
+To deal with clients that don't process daylight savings time properly, Samba provides the <CODE CLASS="literal">
+time</code> <CODE CLASS="literal">
+offset</code> option. If set, it adds the specified number of minutes to the current time. This is handy if you're in Newfoundland and Windows doesn't know about the 30-minute time difference there:</p><PRE CLASS="programlisting">
+[global]
+ time offset = 30</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch08-pgfId-958505">
+8.1.1.3 dos filetimes</a></h4><P CLASS="para">
+Traditionally, only the root user and the owner of a file can change its last-modified date on a Unix system. The share-level <CODE CLASS="literal">
+dos</code> <CODE CLASS="literal">
+filetimes</code> option allows the Samba server to mimic the characteristics of a DOS/Windows machine: any user can change the last modified date on a file in that share if he or she has write permission to it. In order to do this, Samba uses its root privileges to modify the timestamp on the file. </p><P CLASS="para">
+By default, this option is disabled. Setting this option to <CODE CLASS="literal">
+yes</code> is often necessary to allow PC <EM CLASS="emphasis">
+make</em> programs to work properly. Without it, they cannot change the last-modified date themselves. This often results in the program thinking <EM CLASS="emphasis">
+all</em> files need recompiling when they really don't. </p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch08-pgfId-958509">
+8.1.1.4 dos filetime resolution</a></h4><P CLASS="para">
+<CODE CLASS="literal">
+dos</code> <CODE CLASS="literal">
+filetime</code> <CODE CLASS="literal">
+resolution</code> is share-level option. If set to <CODE CLASS="literal">
+yes</code>, Samba will arrange to have the file times rounded to the closest two-second boundary. This option exists primarily to satisfy a quirk in Windows that prevents Visual C++ from correctly recognizing that a file has not changed. You can enable it as follows:</p><PRE CLASS="programlisting">
+[data]
+ dos filetime resolution = yes</pre><P CLASS="para">
+We recommend using this option only if you are using Microsoft Visual C++ on a Samba share that supports opportunistic locking.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch08-pgfId-958515">
+8.1.1.5 fake directory create times</a></h4><P CLASS="para">
+The <CODE CLASS="literal">
+fake</code> <CODE CLASS="literal">
+directory</code> <CODE CLASS="literal">
+create</code> <CODE CLASS="literal">
+times</code> option exists to keep PC <EM CLASS="emphasis">
+make</em> programs sane. VFAT and NTFS filesystems record the creation date of a specific directory while Unix does not. Without this option, Samba takes the earliest recorded date it has for the directory (often the last-modified date of a file) and returns it to the client. If this is not sufficient, set the following option under a share definition:</p><PRE CLASS="programlisting">
+[data]
+ fake directory create times = yes</pre><P CLASS="para">
+If set, Samba will adjust the directory create time it reports to the hardcoded value January 1st, 1980. This is primarily used to convince the Visual C++ <EM CLASS="emphasis">
+nmake</em> program that any object files in its build directories are indeed younger than the creation date of the directory itself and need to be recompiled.</p></div></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch07_03.html" TITLE="7.3 Name Resolution with Samba">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 7.3 Name Resolution with Samba" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_02.html" TITLE="8.2 Magic Scripts">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.2 Magic Scripts" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">7.3 Name Resolution with Samba</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.2 Magic Scripts</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_02.html b/docs/htmldocs/using_samba/ch08_02.html
new file mode 100644
index 00000000000..54b24800711
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_02.html
@@ -0,0 +1,156 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.2 Magic Scripts</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:51Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_01.html" TITLE="8.1 Supporting Programmers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.1 Supporting Programmers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_03.html" TITLE="8.3 Internationalization">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.3 Internationalization" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-79987">
+8.2 Magic Scripts</a></h2><P CLASS="para">The following options deal with <I CLASS="firstterm">
+magic scripts</i> on the Samba server. Magic scripts are a method of running programs on Unix and redirecting the output back to the SMB client. These are essentially an experimental hack. However, some users and their programs still rely on these two options for their programs to function correctly. Magic scripts are not widely trusted and their use is highly discouraged by the Samba team. See <A CLASS="xref" HREF="ch08_02.html#ch08-33693">
+Table 8.2</a> for more information. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-33693">
+Table 8.2: Networking Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+magic script</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">string (fully-qualified filename)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the name of a file to be executed by Samba, as the logged-on user, when closed.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+magic output</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified filename)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a file to log output from the magic file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<EM CLASS="emphasis">
+scriptname.out</em></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958578">
+8.2.1 magic script</a></h3><P CLASS="para">
+If the <CODE CLASS="literal">
+magic</code> <CODE CLASS="literal">
+script</code> option is set to a filename and the client creates a file by that name in that share, Samba will run the file as soon as the user has opened and closed it. For example, let's assume that the following option was created in the share <CODE CLASS="literal">
+[accounting]</code>:</p><PRE CLASS="programlisting">
+[accounting]
+ magic script = tally.sh</pre><P CLASS="para">
+Samba continually monitors the files in that share. If one by the name of <EM CLASS="emphasis">
+tally.sh</em> is closed (after being opened) by a user, Samba will execute the contents of that file locally. The file will be passed to the shell to execute; it must therefore be a legal Unix shell script. This means that it must have newline characters as line endings instead of Windows CR/LFs. In addition, it helps if you use the <CODE CLASS="literal">
+#!</code> directive at the beginning of the file to indicate under which shell the script should run.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958584">
+8.2.2 magic output</a></h3><P CLASS="para">
+This option specifies an output file that the script specified by the <CODE CLASS="literal">
+magic</code> <CODE CLASS="literal">
+script</code> option will send output to. You must specify a filename in a writable directory:</p><PRE CLASS="programlisting">
+[accounting]
+ magic script = tally.sh
+ magic output = /var/log/magicoutput</pre><P CLASS="para">
+If this option is omitted, the default output file is the name of the script (as stated in the <CODE CLASS="literal">
+magic</code> <CODE CLASS="literal">
+script</code> option) with the extension <EM CLASS="emphasis">
+.out</em> appended onto it. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_01.html" TITLE="8.1 Supporting Programmers">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.1 Supporting Programmers" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_03.html" TITLE="8.3 Internationalization">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.3 Internationalization" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+8.1 Supporting Programmers</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.3 Internationalization</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_03.html b/docs/htmldocs/using_samba/ch08_03.html
new file mode 100644
index 00000000000..9e2f60c4328
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_03.html
@@ -0,0 +1,472 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.3 Internationalization</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:51Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_02.html" TITLE="8.2 Magic Scripts">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.2 Magic Scripts" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_04.html" TITLE="8.4 WinPopup Messages">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.4 WinPopup Messages" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-91233">
+8.3 Internationalization</a></h2><P CLASS="para">Samba has a limited ability to speak foreign tongues: if you need to deal with characters that aren't in standard ASCII, some options that can help you are shown in <A CLASS="xref" HREF="ch08_03.html#ch08-40870">
+Table 8.3</a>. Otherwise, you can skip over this section. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-40870">
+Table 8.3: Networking Configuration Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+client code page</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Described in this section</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a code page to expect from clients</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+850</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+character set</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Described in this section</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Translates code pages into alternate UNIX character sets</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+coding system</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Described in this section</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Translates code page 932 into an Asian character set</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+valid chars</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (set of characters)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Obsolete: formerly added individual characters to a code page, and had to be used after setting client code page</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-17721">
+8.3.1 client code page</a></h3><P CLASS="para">
+The character sets on Windows platforms hark back to the original concept of a <EM CLASS="emphasis">
+code page</em>. These code pages are used by DOS and Windows clients to determine rules for mapping lowercase letters to uppercase letters. Samba can be instructed to use a variety of code pages through the use of the global <CODE CLASS="literal">
+client</code> <CODE CLASS="literal">
+code</code> <CODE CLASS="literal">
+page</code> option in order to match the corresponding code page in use on the client. This option loads a code-page definition file, and can take the values specified in <A CLASS="xref" HREF="ch08_03.html#ch08-20815">
+Table 8.4</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-20815">
+Table 8.4: Valid Code Pages with Samba 2.0 </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Code Page</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+437</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">MS-DOS Latin (United States)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+737</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Windows 95 Greek</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+850</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Latin 1 (Western European)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+852</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Latin 2 (Eastern European)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+861</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Icelandic</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+866</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Cyrillic (Russian)</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+932</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Japanese Shift-JIS</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+936</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Simplified Chinese</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+949</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Korean Hangul</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+950</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+MS-DOS Traditional Chinese</p></td></tr></tbody></table><P CLASS="para">
+You can set the client code page as follows:</p><PRE CLASS="programlisting">
+[global]
+ client code page = 852</pre><P CLASS="para">
+The default value of this option is 850. You can use the <EM CLASS="emphasis">
+make_smbcodepage</em> tool that comes with Samba (by default in <I CLASS="filename">
+/usr/local/samba/bin</i>) to create your own SMB code pages, in the event that those listed earlier are not sufficient.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-965812">
+8.3.2 character set</a></h3><P CLASS="para">
+The global <CODE CLASS="literal">
+character</code> <CODE CLASS="literal">
+set</code> option can be used to convert filenames offered through a DOS code page (see the previous section, <A CLASS="xref" HREF="ch08_03.html#ch08-17721">
+Section 8.3.1, client code page</a>) to equivalents that can be represented by Unix character sets other than those in the United States. For example, if you want to convert the Western European MS-DOS character set on the client to a Western European Unix character set on the server, you can use the following in your configuration file:</p><PRE CLASS="programlisting">
+[global]
+ client code page = 850
+ character set = ISO8859-1</pre><P CLASS="para">
+Note that you must include a <CODE CLASS="literal">
+client</code> <CODE CLASS="literal">
+code</code> <CODE CLASS="literal">
+page</code> option to specify the character set from which you are converting. The valid character sets (and their matching code pages) that Samba 2.0 accepts are listed in <A CLASS="xref" HREF="ch08_03.html#ch08-14126">
+Table 8.5</a>: </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-14126">
+Table 8.5: Valid Character Sets with Samba 2.0 </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Character Set</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Matching Code Page</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ISO8859-1</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+850</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Western European Unix</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ISO8859-2</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+852</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eastern European Unix</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ISO8859-5</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+866</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Russian Cyrillic Unix</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+KOI8-R</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+866</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Alternate Russian Cyrillic Unix</p></td></tr></tbody></table><P CLASS="para">
+Normally, the <CODE CLASS="literal">
+character</code> <CODE CLASS="literal">
+set</code> option is disabled completely.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958761">
+8.3.3 coding system</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+coding</code> <CODE CLASS="literal">
+system</code> option is similar to the <CODE CLASS="literal">
+character</code> <CODE CLASS="literal">
+set</code> option. However, its purpose is to determine how to convert a Japanese Shift JIS code page into an appropriate Unix character set. In order to use this option, the <CODE CLASS="literal">
+client</code> <CODE CLASS="literal">
+code</code> <CODE CLASS="literal">
+page</code> option described previously must be set to page 932. The valid coding systems that Samba 2.0 accepts are listed in <A CLASS="xref" HREF="ch08_03.html#ch08-57476">
+Table 8.6</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-57476">
+Table 8.6: Valid Coding System Parameters with Samba 2.0 </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Character Set</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+SJIS</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Standard Shift JIS</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JIS8</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J8BB</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J8BH</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J8@B</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J8@J</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J8@H</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Eight-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JIS7</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J7BB</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J7BH</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J7@B</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J7@J</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+J7@H</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Seven-bit JIS codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JUNET</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JUBB</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JUBH</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JU@B</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JU@J</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+JU@H</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+JUNET codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+EUC</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+EUC codes</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+HEX</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Three-byte hexidecimal code</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+CAP</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Three-byte hexidecimal code (Columbia Appletalk Program)</p></td></tr></tbody></table></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958865">
+8.3.4 valid chars</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+chars</code> option is an older Samba feature that will add individual characters to a code page. However, this option is being phased out in favor of more modern coding systems. You can use this option as follows:</p><PRE CLASS="programlisting">
+valid chars = Î
+valid chars = 0450:0420 0x0A20:0x0A00
+valid chars = A:a</pre><P CLASS="para">
+Each of the characters in the list specified should be separated by spaces. If there is a colon between two characters or their numerical equivalents, the data to the left of the colon is considered an uppercase character, while the data to the right is considered the lowercase character. You can represent characters both by literals (if you can type them) and by octal, hexidecimal, or decimal Unicode equivalents.</p><P CLASS="para">
+We recommend against using this option. Instead, go with one of the standard code pages listed earlier in this section. If you do use this option, however, it must be listed after the <CODE CLASS="literal">
+client</code> <CODE CLASS="literal">
+code</code> <CODE CLASS="literal">
+page</code> to which you wish to add the character. Otherwise, the characters will not be added.</p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_02.html" TITLE="8.2 Magic Scripts">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.2 Magic Scripts" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_04.html" TITLE="8.4 WinPopup Messages">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.4 WinPopup Messages" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">8.2 Magic Scripts</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.4 WinPopup Messages</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_04.html b/docs/htmldocs/using_samba/ch08_04.html
new file mode 100644
index 00000000000..d45ce31474a
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_04.html
@@ -0,0 +1,168 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.4 WinPopup Messages</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:55Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_03.html" TITLE="8.3 Internationalization">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.3 Internationalization" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_05.html" TITLE="8.5 Recently Added Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.5 Recently Added Options" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-82569">
+8.4 WinPopup Messages</a></h2><P CLASS="para">You can use the WinPopup tool (<I CLASS="filename">WINPOPUP.EXE</i>) in Windows to send messages to users, machines, or entire workgroups on the network. This tool is provided with Windows 95 OSR2 and comes standard with Windows 98. With either Windows 95 or 98, however, you need to be running WinPopup to receive and send WinPopup messages. With Windows NT, you can still receive messages without starting such a tool; they will automatically appear in a small dialog box on the screen when received. The WinPopup application is shown in <A CLASS="xref" HREF="ch08_04.html#ch08-66444">
+Figure 8.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch08-66444">
+Figure 8.1: The WinPopup application</a></h4><IMG CLASS="graphic" SRC="figs/sam.0801.gif" ALT="Figure 8.1"><P CLASS="para">
+Samba has a single WinPopup messaging option, <CODE CLASS="literal">
+message</code> <CODE CLASS="literal">
+command</code>, as shown in <A CLASS="xref" HREF="ch08_04.html#ch08-18671">
+Table 8.7</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-18671">
+Table 8.7: WinPopup Configuration Option </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameter</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+message command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">string (fully-qualified pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a command to run on Unix when a WinPopup message is received.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-958949">
+8.4.1 message command</a></h3><P CLASS="para">
+Samba's <CODE CLASS="literal">
+message</code> <CODE CLASS="literal">
+command</code> option sets the path to a program that will run on the server when a Windows popup message arrives at the server. The command will be executed using the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+account</code> user. What to do with one of these is questionable since it's probably for the Samba administrator, and Samba doesn't know his or her name. If you know there's a human using the console, the Samba team once suggested the following:</p><PRE CLASS="programlisting">
+[global]
+ message command = /bin/csh -c 'xedit %s; rm %s' &amp;</pre><P CLASS="para">
+Note the use of variables here. The <CODE CLASS="literal">
+%s</code> variable will become the file that the message is in. This file should be deleted when the command is finished with it; otherwise, there will be a buildup of pop-up files collecting on the Samba server. In addition, the command must fork its own process (note the &amp; after the command); otherwise the client may suspend and wait for notification that the command was sent successfully before continuing.</p><P CLASS="para">
+In addition to the standard variables, <A CLASS="xref" HREF="ch08_04.html#ch08-29758">
+Table 8.8</a> shows the three unique variables that you can use in a <CODE CLASS="literal">
+message</code> <CODE CLASS="literal">
+command</code>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-29758">
+Table 8.8: Message Command Variables </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%s</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The name of the file in which the message resides</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%</code>f</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The name of the client that sent the message</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+%t</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+The name of the machine that is the destination of the message </p></td></tr></tbody></table></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_03.html" TITLE="8.3 Internationalization">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.3 Internationalization" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_05.html" TITLE="8.5 Recently Added Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.5 Recently Added Options" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+8.3 Internationalization</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.5 Recently Added Options</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_05.html b/docs/htmldocs/using_samba/ch08_05.html
new file mode 100644
index 00000000000..90fa20a8cda
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_05.html
@@ -0,0 +1,396 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.5 Recently Added Options</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:55Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_04.html" TITLE="8.4 WinPopup Messages">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.4 WinPopup Messages" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_06.html" TITLE="8.6 Miscellaneous Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.6 Miscellaneous Options" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-pgfId-958954">
+
+<!-- 2.0.7 amendments begin, davecb --> 8.5 Recently Added
+Options</a></h2><P CLASS="para">Samba has several options that appeared
+around the time of Samba 2.0, but either were not entirely supported or were
+in the process of being developed. With Samba 2.0.7, several more were
+introduced. We will give you a brief overview of their workings in this
+section. These options are shown in <A CLASS="xref"
+HREF="ch08_05.html#ch08-72538">
+<!-- end of first addition -->
+
+Table 8.9</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-72538">
+Table 8.9: Recently Added Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+change notify timeout</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (number of seconds)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the interval between checks when a client asks to wait for a change in a specified directory.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+60</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+machine password timeout</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (number of seconds)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the renewal interval for NT domain machine passwords.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+604,800</code> (1 week)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+stat cache</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, Samba will cache recent name mappings.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+stat cache size</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the size of the stat cache.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+50</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr>
+
+<!-- 2.0.7 table insertions begin -->
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+utmp</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Turns on logging of Samba users in the utmp file. Requires --with-utmp. </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+utmp dir</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the directory where Samba expects to find the utmp/utmpx file.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+None</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+inherit permissions</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the permissions of newly created directories to the same as their parent.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+write cache size</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (bytes)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the size of a write cache (buffer) used for oplocked files.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Share</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+source environment</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (pathname)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets a file to read environment variable from.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+None</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr>
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+min password length</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (number of characters)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the minimum length of a new password which Samba will try to update the password file with .</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+5</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr>
+
+
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+netbios scope</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the NetBIOS scope.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+None</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr>
+<!-- end of 2.0.7 insertions-->
+</tbody></table>
+
+<DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-959050">
+8.5.1 change notify timeout</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+change</code> <CODE CLASS="literal">
+notify</code> <CODE CLASS="literal">
+timeout</code> global option emulates a Windows NT SMB feature called <I CLASS="firstterm">
+change notification</i>. This allows a client to request that a Windows NT server periodically monitor a specific directory on a share for any changes. If any changes occur, the server will notify the client.</p><P CLASS="para">
+As of version 2.0, Samba will perform this function for its clients. However, performing these checks too often can slow the server down considerably. This option sets the time period that Samba should wait between such checks. The default is one minute (60 seconds); however, you can use this option to specify an alternate time that Samba should wait between performing checks:</p><PRE CLASS="programlisting">
+[global]
+ change notify timeout = 30</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-959054">
+8.5.2 machine password timeout</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+machine</code> <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+timeout</code> global option sets a retention period for NT domain machine passwords. The default is currently set to the same time period that Windows NT 4.0 uses: 604,800 seconds (one week). Samba will periodically attempt to change the <I CLASS="firstterm">
+machine account password</i>, which is a password used specifically by another server to report changes to it. This option specifies the number of seconds that Samba should wait before attempting to change that password. The following example changes it to a single day, by specifying the following:</p><PRE CLASS="programlisting">
+[global]
+ machine password timeout = 86400</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-959058">
+8.5.3 stat cache</a></h3><P CLASS="para">
+The <CODE CLASS="literal">
+stat</code> <CODE CLASS="literal">
+cache</code> global option turns on caching of recent case-insensitive name mappings. The default is <CODE CLASS="literal">
+yes</code>. The Samba team recommends that you never change this parameter.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-959060">
+8.5.4 stat cache size</a></h3><P CLASS="para">The <CODE CLASS="literal">
+stat</code> <CODE CLASS="literal">
+cache</code> <CODE CLASS="literal">
+size</code> global option sets the size of the cache entries to be used for the <CODE CLASS="literal">
+stat</code> <CODE CLASS="literal">
+cache</code> option. The default here is 50. Again, the Samba team recommends that you never change this parameter.</p>
+
+===
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add1">
+8.5.5 utmp</a></h3>
+<P CLASS="para">If you specified <CODE CLASS="literal">
+--with-utmp </CODE> when configuring, this option will turn on utmp logging
+of users: they will appear in the utmp file and you will be able to see if
+they are on with <I>last(1)</I>. It defaults to <CODE
+CLASS="literal">no</code>.</p>
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add2">
+8.5.6 utmp dir</a></h3>
+<P CLASS="para">
+If <CODE CLASS="literal">utmp</CODE> is set, the utmp dir option will change the directory Samba
+looks in for the utmp files. If it is not set, the default system
+location will be used.</p>
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add3">
+8.5.7 inherit permissions</a></h3>
+<P CLASS="para">
+This option causes new files and directories to be created with
+the same permissions as the directory they're in. For example,
+subdirectories will inherit setgid bits from their parents.
+This option will override the <CODE CLASS="literal">create
+mask, directory mask, force create mode</CODE> and <CODE CLASS="literal">
+force directory mode</CODE> options, but not the <CODE CLASS="literal">
+map archive, map hidden</CODE> and <CODE CLASS="literal">map system</CODE>
+options. It will never set the <CODE CLASS="literal">setuid</CODE> bit.
+This option defaults to off.</p>
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add4">
+8.5.8 write cache size</a></h3>
+<P CLASS="para">The <CODE CLASS="literal">write cache size</code>
+share option sets the size of a cache used by Samba while
+writing oplocked files. The files will be written in <I>cachesize</I>
+blocks, so you can tune Samba's write size to the optimum size for
+your filesystem or RAID disk array.</p>
+
+<p>The caching applies to the first 10 files opened with oplocks if set,
+and defaults to zero (off) initially.</p>
+
+<p>As with all caching schemes, data that hasn't been written
+will be lost if the system crashes.</p>
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add5">
+8.5.9 source environment</a></h3>
+<P CLASS="para">
+This options specifies a file of environment variables that Samba
+will read on startup. <!-- and when else? When an smb.conf is read?
+when a child server process is started? --> The variables set in this
+files can then be used in smb.conf files as $%<I>name</I>. For example,
+HOME=/home/sofia in the environment file could be used in a smb.conf
+file as "path = "$HOME"</p>
+
+<p>If the pathname begins with a "|" (pipe) symbol, Samba will attempt
+to run it and read its standard output.</p>
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add6">
+8.5.10 min password length</a></h3>
+<P CLASS="para">This option sets the minimum length, in characters,
+of a plain text password that Samba will accept when performing UNIX
+password changing. This is used to tell Samba about system-defined
+minimums, so it can return an appropriate error to the client.</p>
+
+
+<H3 CLASS="sect2"> <A CLASS="title" NAME="ch08-pgfId-959060-add1">
+8.5.11 netbios scope</a></h3>
+<P CLASS="para">
+This sets the NetBIOS scope that Samba will operate under: Samba
+will not communicate with any machine with a different scope.
+This should not be set unless every machine on your LAN also sets
+this value. It was a predecessor to workgroups, and the Samba
+team recommends against using it.</p>
+
+<!-- end of 2.0.7 additions. -->
+
+<div></div></div></blockquote>
+
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_04.html" TITLE="8.4 WinPopup Messages">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.4 WinPopup Messages" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_06.html" TITLE="8.6 Miscellaneous Options">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.6 Miscellaneous Options" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+8.4 WinPopup Messages</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.6 Miscellaneous Options</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_06.html b/docs/htmldocs/using_samba/ch08_06.html
new file mode 100644
index 00000000000..97e4e3c9767
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_06.html
@@ -0,0 +1,509 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.6 Miscellaneous Options</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:35:56Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_05.html" TITLE="8.5 Recently Added Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.5 Recently Added Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_07.html" TITLE="8.7 Backups with smbtar">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.7 Backups with smbtar" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-70923">
+8.6 Miscellaneous Options</a></h2><P CLASS="para">Many Samba options are present to deal with operating system issues on either Unix or Windows. The options shown in <A CLASS="xref" HREF="ch08_06.html#ch08-83566">
+Table 8.10</a> deal specifically with some of these known problems. We usually don't change these and we recommend the same to you. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-83566">
+Table 8.10: Miscellaneous Options </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Option</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Parameters</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Function</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Default</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Scope</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+deadtime</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">numerical (number of minutes)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the number of minutes of inactivity before a connection should be terminated.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+0</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+dfree command</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Used to provide a command that returns disk free space in a format recognized by Samba.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+fstype</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+NTFS</code>, <CODE CLASS="literal">
+FAT</code>, or <CODE CLASS="literal">
+Samba</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the filesystem type reported by the server to the client.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+NTFS</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+keep alive</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+seconds</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the number of seconds between checks for an inoperative client.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+0 (none)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max disk size</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical (size in MB)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the largest disk size to return to a client, some of which have limits. Does not affect actual operations on the disk.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+0 (infinity)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max mux</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the maximum number of simultaneous SMB operations that clients may make.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+50</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max open files</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Limits number of open files to be below Unix limits.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+10,000</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+max xmit</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+numerical</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Specifies the maximum packet size that Samba will send.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+65,535</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+nt pipe support</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Turns off an experimental NT feature, for benchmarking or in case of an error.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+nt smb support</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Turns off an experimental NT feature, for benchmarking or in case of an error.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+ole locking compatib-ility</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Remaps out-of-range lock requests used on Windows to fit in allowable range on Unix. Turning it off causes Unix lock errors.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+panic action</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+command</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Program to run if Samba server fails; for debugging.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+set directory</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, allows VMS clients to issue <CODE CLASS="literal">
+set</code> <CODE CLASS="literal">
+dir</code> commands.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+smbrun</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+string (fully-qualified command)</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Sets the command Samba uses as a wrapper for shell commands.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+None</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+status</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, allows Samba to monitor status for <CODE CLASS="literal">
+smbstatus</code> command.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+yes</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+strict sync</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+no</code>, ignores Windows applications requests to perform a sync-to-disk.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+sync always</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, forces all client writes to be committed to disk before returning from the call.</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+strip dot</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+boolean</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+If <CODE CLASS="literal">
+yes</code>, strips trailing dots from Unix filenames. </p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<CODE CLASS="literal">
+no</code></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Global</p></td></tr></tbody></table><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960795">
+8.6.1 deadtime</a></h3><P CLASS="para">
+This global option sets the number of minutes that Samba will wait for an inactive client before closing its session with the Samba server. A client is considered inactive when it has no open files and there is no data being sent from it. The default value for this option is 0, which means that Samba never closes any connections no matter how long they have been inactive. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ deadtime = 10</pre><P CLASS="para">
+This tells Samba to terminate any inactive client sessions after 10 minutes. For most networks, setting this option as such will work because reconnections from the client are generally performed transparently to the user.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960118">
+8.6.2 dfree command</a></h3><P CLASS="para">This global option is used on systems that incorrectly determine the free space left on the disk. So far, the only confirmed system that needs this option set is Ultrix. There is no default value for this option, which means that Samba already knows how to compute the free disk space on its own and the results are considered reliable. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ dfree command = /usr/local/bin/dfree</pre><P CLASS="para">
+This option should point to a script that should return the total disk space in a block, and the number of available blocks. The Samba documentation recommends the following as a usable script:</p><PRE CLASS="programlisting">
+#!/bin/sh
+df $1 | tail -1 | awk '{print $2&quot; &quot;$4}'</pre><P CLASS="para">
+On System V machines, the following will work:</p><PRE CLASS="programlisting">
+#!/bin/sh
+/usr/bin/df $1 | tail -1 | awk '{print $3&quot; &quot;$5}'</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960122">
+8.6.3 fstype</a></h3><P CLASS="para">
+This share-level option sets the type of filesystem that Samba reports when queried by the client. There are three strings that can be used as a value to this configuration option, as listed in <A CLASS="xref" HREF="ch08_06.html#ch08-80519">
+Table 8.11</a>. </p><br>
+<TABLE CLASS="table" BORDER="1" CELLPADDING="3">
+<CAPTION CLASS="table">
+<A CLASS="title" NAME="ch08-80519">
+Table 8.11: Filesystem Types </a></caption><THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Variable</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Definition</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+NTFS</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">Microsoft Windows NT filesystem</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+FAT</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+DOS FAT filesystem</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Samba filesystem</p></td></tr></tbody></table><P CLASS="para">
+The default value for this option is <CODE CLASS="literal">
+NTFS</code>, which represents a Windows NT filesystem. There probably isn't a need to specify any other type of filesystem. However, if you need to, you can override it per share as follows:</p><PRE CLASS="programlisting">
+[data]
+ fstype = FAT</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960124">
+8.6.4 keep alive</a></h3><P CLASS="para">This global option specifies the number of seconds that Samba waits between sending NetBIOS <EM CLASS="emphasis">
+keep-alive packets</em>. These packets are used to ping a client to detect whether it is still alive and on the network. The default value for this option is <CODE CLASS="literal">
+0</code>, which means that Samba will not send any such packets at all. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ keep alive = 10</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960128">
+8.6.5 max disk size</a></h3><P CLASS="para">This global option specifies an illusory limit, in megabytes, for each of the shares that Samba is using. You would typically set this option to prevent clients with older operating systems from incorrectly processing large disk spaces, such as those over one gigabyte.</p><P CLASS="para">
+The default value for this option is <CODE CLASS="literal">
+0</code>, which means there is no upper limit at all. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ max disk size = 1000</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960130">
+8.6.6 max mux</a></h3><P CLASS="para">This global option specifies the maximum number of concurrent SMB operations that Samba allows. The default value for this option is <CODE CLASS="literal">
+50</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ max mux = 100</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960132">
+8.6.7 max open files</a></h3><P CLASS="para">This global option specifies the maximum number of open files that Samba should allow at any given time for all processes. This value must be equal to or less than the amount allowed by the operating system, which varies from system to system. The default value for this option is <CODE CLASS="literal">
+10,000</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ max open files = 8000</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960136">
+8.6.8 max xmit</a></h3><P CLASS="para">This global option sets the maximum size of packets that Samba exchanges with a client. In some cases, setting a smaller maximum packet size can increase performance, especially with Windows for Workgroups. The default value for this option is <CODE CLASS="literal">
+65535</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ max xmit = 4096</pre><P CLASS="para">
+
+The section <a href="appb_02.html#b226"><b>Section B.2.2.6, The TCP receive window</b></a> in <a href="appb_01.html"><b>Appendix B,<CITE CLASS="appendix">
+Samba Performance Tuning</cite></b></a>,
+
+shows some uses for this option.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960138">
+8.6.9 nt pipe support</a></h3><P CLASS="para">This global option is used by developers to allow or disallow Windows NT clients the ability to make connections to the NT SMB-specific IPC$ pipes. As a user, you should never need to override the default:</p><PRE CLASS="programlisting">
+[global]
+ nt pipe support = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960140">
+8.6.10 nt smb support</a></h3><P CLASS="para">This global option is used by developers to negotiate NT-specific SMB options with Windows NT clients. The Samba team has discovered that slightly better performance comes from setting this value to <CODE CLASS="literal">
+no</code>. However, as a user, you should probably not override the default:</p><PRE CLASS="programlisting">
+[global]
+ nt smb support = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960178">
+8.6.11 ole locking compatibility</a></h3><P CLASS="para">
+This global option turns off Samba's internal byte-range locking manipulation in files, which gives compatibility with Object Linking and Embedding (OLE) applications that use high byte-range locks as a method of interprocess communication. The default value for this option is <CODE CLASS="literal">
+yes</code>. If you trust your Unix locking mechanisms, you can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ ole locking compatibility = no</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960182">
+8.6.12 panic action</a></h3><P CLASS="para">This global option specifies a command to execute in the event that Samba itself encounters a fatal error when loading or running. There is no default value for this option. You can specify an action as follows:</p><PRE CLASS="programlisting">
+[global]
+ panic action = /bin/csh -c
+ 'xedit &lt; &quot;Samba has shutdown unexpectedly!'</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960190">
+8.6.13 set directory</a></h3><P CLASS="para">
+This boolean share-level option allows Digital Pathworks clients to use the <CODE CLASS="literal">
+setdir</code> command to change directories on the server. If you are not using the Digital Pathworks client, you should not need to alter this option. The default value for this option is <CODE CLASS="literal">
+no</code>. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[data]
+ set directory = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960192">
+8.6.14 smbrun</a></h3><P CLASS="para">
+This option sets the location of the <EM CLASS="emphasis">
+smbrun</em> executable, which Samba uses as a wrapper to run shell commands. The default value for this option is automatically configured by Samba when it is compiled. If you did not install Samba to the standard directory, you can specify where the binary is as follows:</p><PRE CLASS="programlisting">
+[global]
+ smbrun = /usr/local/bin/smbrun</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960194">
+8.6.15 status</a></h3><P CLASS="para">
+This global option indicates whether Samba should log all active connections to a status file. This file is used only by the <EM CLASS="emphasis">
+smbstatus</em> command. If you have no intentions of using this command, you can set this option to <CODE CLASS="literal">
+no</code>, which can result in a small increase of speed on the server. The default value for this option is <CODE CLASS="literal">
+yes</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+[global]
+ status = no</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960196">
+8.6.16 strict sync</a></h3><P CLASS="para">
+This share-level option determines whether Samba honors all requests to perform a disk sync when requested to do so by a client. Many clients request a disk sync when they are really just trying to flush data to their own open files. As a result, this can substantially slow a Samba server down. The default value for this option is <CODE CLASS="literal">
+no</code>. You can override it as follows:</p><PRE CLASS="programlisting">
+[data]
+ strict sync = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960202">
+8.6.17 sync always</a></h3><P CLASS="para">
+This share-level option decides whether every write to disk should be followed by a disk synchronization before the write call returns control to the client. Even if the value of this option is <CODE CLASS="literal">
+no</code>, clients can request a disk synchronization; see the <CODE CLASS="literal">
+strict</code> <CODE CLASS="literal">
+sync</code> option above. The default value for this option is <CODE CLASS="literal">
+no</code>. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[data]
+ sync always = yes</pre></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch08-pgfId-960204">
+8.6.18 strip dot</a></h3><P CLASS="para">
+This global option determines whether to remove the trailing dot from Unix filenames that are formatted with a dot at the end. The default value for this option is <CODE CLASS="literal">
+no</code>. You can override it per share as follows:</p><PRE CLASS="programlisting">
+[global]
+ strip dot = yes</pre><P CLASS="para">
+This option is now considered obsolete; the user should use the <CODE CLASS="literal">
+mangled</code> <CODE CLASS="literal">
+map</code> option insead. </p></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_05.html" TITLE="8.5 Recently Added Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.5 Recently Added Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_07.html" TITLE="8.7 Backups with smbtar">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 8.7 Backups with smbtar" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+8.5 Recently Added Options</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+8.7 Backups with smbtar</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch08_07.html b/docs/htmldocs/using_samba/ch08_07.html
new file mode 100644
index 00000000000..c0aa0837020
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch08_07.html
@@ -0,0 +1,143 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 8] 8.7 Backups with smbtar</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:36:02Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_06.html" TITLE="8.6 Miscellaneous Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.6 Miscellaneous Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch08_01.html" TITLE="8. Additional Samba Information ">
+Chapter 8<br>
+Additional Samba Information </a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch09_01.html" TITLE="9. Troubleshooting Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9. Troubleshooting Samba" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch08-74829">
+8.7 Backups with smbtar</a></h2><P CLASS="para">Our final topic in this chapter is the <I CLASS="filename">
+smbtar</i> tool. One common problem with modem PCs is that floppies and even CD-ROMs are often too small to use for backups. However, buying one tape drive per machine would also be silly. Consequently, many sites don't back up their PCs at all. Instead, they reinstall them using floppy disks and CD-ROMs when they fail.</p><P CLASS="para">
+Thankfully, Samba provides us with another option: you can back up PCs' data using the <I CLASS="filename">
+smbtar</i> tool. This can be done on a regular basis if you keep user data on your Samba system, or only occasionally, to save the local applications and configuration files and thus make repairs and reinstallations quicker.</p><P CLASS="para">
+To back up PCs from a Unix server, you need to do three things:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961555">
+</a>Ensure that File and Printer Sharing is installed on the PC and is bound to the TCP/IP protocol.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961564">
+</a>Explicitly share a disk on the PC so it can be read from the server.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961567">
+</a>Set up the backup scripts on the server.</p></li></ol><P CLASS="para">
+We'll use Windows 95/98 to illustrate the first two steps. Go to the Networking icon in the Control Panel window, and check that File and Printer Sharing for Microsoft Networks is currently listed in the top window, as shown in <A CLASS="xref" HREF="ch08_07.html#ch08-18303">
+Figure 8.2</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch08-18303">
+Figure 8.2: The Networking window</a></h4><IMG CLASS="graphic" SRC="figs/sam.0802.gif" ALT="Figure 8.2"><P CLASS="para">
+If "File and printer sharing for Microsoft Networks" isn't installed, you can install it by clicking on the Add button on the Network panel. After pressing it, you will be asked what service to add. Select Service and move forward, and you will be asked for a vendor and a service to install. Finally, select "File and printer sharing for Microsoft Networks," and click on Done to install the service.</p><P CLASS="para">
+Once you've installed "File and printer sharing for Microsoft Networks," return to the Network panel and select the TCP/IP protocol that is tied to your Samba network adapter. Then, click on the Properties button and choose the Bindings tab at the top. You should see a dialog box similar to <A CLASS="xref" HREF="ch08_07.html#ch08-41042">
+Figure 8.3</a>. Here, you'll need to verify that the "File and Printer Sharing" checkbox is checked, giving it access to TCP/IP. At this point you can share disks with other machines on the net. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch08-41042">
+Figure 8.3: TCP/IP Bindings</a></h4><IMG CLASS="graphic" SRC="figs/sam.0803.gif" ALT="Figure 8.3"><P CLASS="para">
+The next step is to share the disk you want to back up with the tape server. Go to My Computer and select, for example, the My Documents directory. Then right-click on the icon and select its Properties. This should yield the dialog box in <A CLASS="xref" HREF="ch08_07.html#ch08-64918">
+Figure 8.4</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch08-64918">
+Figure 8.4: My Documents Properties</a></h4><IMG CLASS="graphic" SRC="figs/sam.0804.gif" ALT="Figure 8.4"><P CLASS="para">
+Select the Sharing tab and turn file sharing on. You now have the choice to share the disk as read-only, read-write (Full), or either, each with separate password. This is the Windows 95/98 version, so it provides only share-level security. In this example, we made it read/write and set a password, as shown in <A CLASS="xref" HREF="ch08_07.html#ch08-29192">
+Figure 8.5</a>. When you enter the password and click on OK, you'll be prompted to re-enter it. After that, you have finished the second step. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch08-29192">
+Figure 8.5: MyFiles Properties as shared</a></h4><IMG CLASS="graphic" SRC="figs/sam.0805.gif" ALT="Figure 8.5"><P CLASS="para">
+Finally, the last step is to set up a backup script on the tape server, using the <I CLASS="filename">
+smbtar</i> program. The simplest script might contain only a single line and would be something like the following:</p><PRE CLASS="programlisting">
+smbtar -s client -t /dev/rst0 -x &quot;My Documents&quot; -p <CODE CLASS="replaceable"><I>password</i></code></pre><P CLASS="para">
+This unconditionally backs up the <EM CLASS="emphasis">
+//client/My Documents</em> share to the device <I CLASS="filename">
+/dev/rst0</i>. Of course, this is excessively simple and quite insecure. What you will want to do will depend on your existing backup scheme. </p><P CLASS="para">
+However, to whet your appetite, here are some possibilities of what <I CLASS="filename">
+smbtar</i> can do:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961280">
+</a>Back up files incrementally using the DOS archive bit (the <CODE CLASS="literal">
+-i</code> option). This requires the client share to be accessed read-write so the bit can be cleared by <I CLASS="filename">
+smbtar</i></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961281">
+</a>Back up only files that have changed since a specified date (using the <CODE CLASS="literal">
+-N</code> <CODE CLASS="replaceable">
+<I>
+filename </i></code>option)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch08-pgfId-961282">
+</a>Back up entire PC drives, by sharing all of C: or D:, for example, and backing that up</p></li></ul><P CLASS="para">
+Except for the first example, each of these can be done with the PC sharing set to read-only, reducing the security risk of having passwords in scripts and passing them on the command line. </p></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_06.html" TITLE="8.6 Miscellaneous Options">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.6 Miscellaneous Options" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="chapter" HREF="ch09_01.html" TITLE="9. Troubleshooting Samba">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9. Troubleshooting Samba" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+8.6 Miscellaneous Options</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+9. Troubleshooting Samba</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch09_01.html b/docs/htmldocs/using_samba/ch09_01.html
new file mode 100644
index 00000000000..8dc0e80bc56
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch09_01.html
@@ -0,0 +1,397 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 9] Troubleshooting Samba</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:36:14Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_07.html" TITLE="8.7 Backups with smbtar">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.7 Backups with smbtar" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+Chapter 9</font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_02.html" TITLE="9.2 The Fault Tree">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9.2 The Fault Tree" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div class="samplechapter">
+<H1 CLASS="chapter">
+<A CLASS="title" NAME="ch09-80975">
+9. Troubleshooting Samba</a></h1><DIV CLASS="htmltoc">
+<P>
+<B>
+Contents:</b><br>
+<A CLASS="sect1" HREF="#ch09-36385" TITLE="9.1 The Tool Bag">
+The Tool Bag</a><br>
+<A CLASS="sect1" HREF="ch09_02.html" TITLE="9.2 The Fault Tree">
+The Fault Tree</a><br>
+<A CLASS="sect1" HREF="ch09_03.html" TITLE="9.3 Extra Resources">
+Extra Resources</a></p><P>
+</p></div><P CLASS="para">Samba is extremely robust. Once you've got everything set up the way you want, you'll probably forget that it is running. When trouble occurs, it's typically during installation or when you're trying to add something new to the server. Fortunately, there are a wide variety of resources that you can use to diagnose these troubles. While we can't describe in detail the solution to every problem that you might encounter, you should be able to get a good start at a resolution by following the advice given in this chapter.</p><P CLASS="para">
+The first section of the chapter lists the tool bag, a collection of tools available for troubleshooting Samba; the second section is a detailed how-to, and the last section lists extra resources you may need to track down particularly stubborn problems.</p><DIV CLASS="sect1">
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="s1"></a>
+<A CLASS="title" NAME="ch09-36385">
+9.1 The Tool Bag</a></h2><P CLASS="para">Sometimes Unix seems to be made up of a handful of applications and tools. There are tools to troubleshoot tools. And of course, there are several ways to accomplish the same task. When you are trying to solve a problem related to Samba, a good plan of attack is to check the following:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944982">
+</a>Samba logs </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944983">
+</a>Fault tree </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944984">
+</a>Unix utilities </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944985">
+</a>Samba test utilities </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944986">
+</a>Documentation and FAQs </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944987">
+</a>Searchable archives </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-944988">
+</a>Samba newsgroups</p></li></ol><P CLASS="para">
+Let's go over each of these one by one in the following sections.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-950956">
+9.1.1 Samba Logs</a></h3><P CLASS="para">Your first line of attack should always be to check the log files. The Samba log files can help diagnose the vast majority of the problems that beginning to intermediate Samba administrators are likely to face. Samba is quite flexible when it comes to logging. You can set up the server to log as little or as much as you want. Substitution variables that allow you to isolate individual logs for each machine, share, or combination thereof.</p><P CLASS="para">
+By default, logs are placed in <CODE CLASS="replaceable">
+<I>
+samba_directory</i></code><EM CLASS="emphasis">
+/var/smbd.log</em> and <CODE CLASS="replaceable">
+<I>
+samba_directory</i></code><EM CLASS="emphasis">
+/var/nmbd.log</em>, where <CODE CLASS="literal">
+samba_directory</code> is the location where Samba was installed (typically, <I CLASS="filename">
+/usr/local/samba</i>). As we mentioned in <a href=ch04_01.html><b>Chapter 4, <CITE CLASS="chapter">Disk Shares</cite></b></a>, you can override the location and name using the <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+file</code> configuration option in <I CLASS="filename">
+smb.conf</i>. This option accepts all of the substitution variables mentioned in <a href="ch02_01.html"><b>Chapter 2, <CITE CLASS="chapter">Installing Samba on a Unix System</cite></b></a>, so you could easily have the server keep a separate log for each connecting client by specifying the following in the <CODE CLASS="literal">
+[global]</code> section of <I CLASS="filename">
+smb.conf</i>:</p><PRE CLASS="programlisting">
+log file = %m.log</pre><P CLASS="para">
+Alternatively, you can specify a log directory to use with the <CODE CLASS="literal">
+-l</code> flag on the command line. For example:</p><PRE CLASS="programlisting">
+smbd -l /usr/local/var/samba</pre><P CLASS="para">
+Another useful trick is to have the server keep a log for each service (share) that is offered, especially if you suspect a particular share is causing trouble. Use the <CODE CLASS="literal">
+%S</code> variable to set this up in the <CODE CLASS="literal">
+[global]</code> section of the configuration file:</p><PRE CLASS="programlisting">
+log file = %S.log</pre><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-28969">
+9.1.1.1 Log levels</a></h4><P CLASS="para">The level of logging that Samba uses can be set in the <I CLASS="filename">
+smb.conf</i> file using the global <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> or <CODE CLASS="literal">
+debug</code> <CODE CLASS="literal">
+level</code> option; they are equivalent. The logging level is an integer which ranges from 0 (no logging), and increases the logging to voluminous by <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+3</code>. For example, let's assume that we are going to use a Windows client to browse a directory on a Samba server. For a small amount of log information, you can use <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+1</code>, which instructs Samba to show only cursory information, in this case only the connection itself: </p><PRE CLASS="programlisting">
+105/25/98 22:02:11 server (192.168.236.86) connect to service public as user pcguest (uid=503,gid=100) (pid 3377) </pre><P CLASS="para">
+Higher debug levels produce more detailed information. Usually you won't need any more than level 3; this is more than adequate for most Samba administrators. Levels above 3 are for use by the developers and dump enormous amounts of cryptic information.</p><P CLASS="para">
+Here is example output at levels 2 and 3 for the same operation. Don't worry if you don't understand the intricacies of an SMB connection; the point is simply to show you what types of information are shown at the different logging levels: </p><PRE CLASS="programlisting">
+ /* Level 2 */
+Got SIGHUP
+Processing section &quot;[homes]&quot;
+Processing section &quot;[public]&quot;
+Processing section &quot;[temp]&quot;
+Allowed connection from 192.168.236.86 (192.168.236.86) to IPC$
+Allowed connection from 192.168.236.86 (192.168.236.86) to IPC/
+
+
+/* Level 3 */
+05/25/98 22:15:09 Transaction 63 of length 67
+switch message SMBtconX (pid 3377)
+Allowed connection from 192.168.236.86 (192.168.236.86) to IPC$
+ACCEPTED: guest account and guest ok
+found free connection number 105
+Connect path is /tmp
+chdir to /tmp
+chdir to /
+05/25/98 22:15:09 server (192.168.236.86) connect to service IPC$ as user pcguest (uid=503,gid=100) (pid 3377)
+05/25/98 22:15:09 tconX service=ipc$ user=pcguest cnum=105
+05/25/98 22:15:09 Transaction 64 of length 99
+switch message SMBtrans (pid 3377)
+chdir to /tmp
+trans &lt;\PIPE\LANMAN&gt; data=0 params=19 setup=0
+Got API command 0 of form &lt;WrLeh&gt; &lt;B13BWz&gt; (tdscnt=0,tpscnt=19,mdrcnt=4096,mprcnt=8)
+Doing RNetShareEnum
+RNetShareEnum gave 4 entries of 4 (1 4096 126 4096)
+05/25/98 22:15:11 Transaction 65 of length 99
+switch message SMBtrans (pid 3377)
+chdir to /
+chdir to /tmp
+trans &lt;\PIPE\LANMAN&gt; data=0 params=19 setup=0
+Got API command 0 of form &lt;WrLeh&gt; &lt;B13BWz&gt; (tdscnt=0,tpscnt=19,mdrcnt=4096,mprcnt=8)
+Doing RNetShareEnum
+RNetShareEnum gave 4 entries of 4 (1 4096 126 4096)
+05/25/98 22:15:11 Transaction 66 of length 95
+switch message SMBtrans2 (pid 3377)
+chdir to /
+chdir to /pcdisk/public
+call_trans2findfirst: dirtype = 0, maxentries = 6, close_after_first=0, close_if_end = 0 requires_resume_key = 0 level = 260, max_data_bytes = 2432
+unix_clean_name [./DESKTOP.INI]
+unix_clean_name [desktop.ini]
+unix_clean_name [./]
+creating new dirptr 1 for path ./, expect_close = 1
+05/25/98 22:15:11 Transaction 67 of length 53
+switch message SMBgetatr (pid 3377)
+chdir to /
+
+[...]</pre><P CLASS="para">
+We cut off this listing after the first packet because it runs on for many pages. However, you should be aware that log levels above 3 will quickly fill your disk with megabytes of excruciating detail concerning Samba internal operations. Log level 3 is extremely useful for following exactly what the server is doing, and most of the time it will be obvious where an error is occurring by glancing through the log file.</p><P CLASS="para">
+A word of warning: using a high log level (3 or above) will <EM CLASS="emphasis">
+seriously</em> slow down the Samba server. Remember that every log message generated causes a write to disk (an inherently slow operation) and log levels greater than 2 produce massive amounts of data. Essentially, you should turn on logging level 3 only when you're actively tracking a problem in the Samba server.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946537">9.1.1.2 Activating and deactivating logging</a></h4><P CLASS="para">To turn logging on and off, set the appropriate level in the <CODE CLASS="literal">
+[global]</code> section of <I CLASS="filename">
+smb.conf</i>. Then, you can either restart Samba, or force the current daemon to reprocess the configuration file. You also can send the <EM CLASS="emphasis">
+smbd</em> process a SIGUSR1 signal to increase its log level by one while it's running, and a SIGUSR2 signal to decrease it by one:</p><PRE CLASS="programlisting">
+# Increase the logging level by 1
+kill -SIGUSR1 1234
+
+# Decrease the logging level by 1
+kill -SIGUSR2 1234</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-34448">
+9.1.1.3 Logging by individual client machines or users</a></h4><P CLASS="para">An effective way to diagnose problems without hampering other users is to assign different log levels for different machines in <CODE CLASS="literal">
+[global]</code> section of the <I CLASS="filename">
+smb.conf</i> file. We can do this by building on the strategy we presented earlier:</p><PRE CLASS="programlisting">
+[global]
+ log level = 0
+ log file = /usr/local/samba/lib/log.%m
+ include = /usr/local/samba/lib/smb.conf.%m</pre><P CLASS="para">
+These options instruct Samba to use unique configuration and log files for each client that connects. Now all you have to do is create an <I CLASS="filename">
+smb.conf</i> file for a specific client machine with a <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+3</code> entry in it (the others will pick up the default log level of 0) and use that log file to track down the problem.</p><P CLASS="para">
+Similarly, if only particular users are experiencing a problem, and it travels from machine to machine with them, you can isolate logging to a specific user by adding the following to the <I CLASS="filename">
+smb.conf</i> file:</p><PRE CLASS="programlisting">
+[global]
+ log level = 0
+ log file = /usr/local/samba/lib/log.%u
+ include = /usr/local/samba/lib/smb.conf.%u</pre><P CLASS="para">
+Then you can create a unique <I CLASS="filename">
+smb.conf</i> file for each user (e.g., <I CLASS="filename">
+/usr/local/samba/lib/smb.conf.tim</i>) files containing the configuration option <CODE CLASS="literal">
+log</code> <CODE CLASS="literal">
+level</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+3</code> and only those users will get more detailed logging.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-945079">9.1.2 Samba Test Utilities</a></h3><P CLASS="para">A rigorous set of tests that exercise the major parts of Samba are described in various files in the <EM CLASS="emphasis">
+/docs/textdocs</em> directory of the Samba distribution kit, starting with <EM CLASS="emphasis">
+DIAGNOSIS.TXT.</em> The fault tree in this chapter is a more detailed version of the basic tests suggested by the Samba team, but covers only installation and reconfiguration diagnosis, like <EM CLASS="emphasis">
+DIAGNOSIS.TXT.</em> The other files in the <EM CLASS="emphasis">
+/docs</em> subdirectoryies address specific problems (such as Windows NT clients) and instruct you how to troubleshoot items not included in this book. If the fault tree doesn't suffice, be sure to look at <EM CLASS="emphasis">
+DIAGNOSIS.TXT</em> and its friends.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-945083">
+9.1.3 Unix Utilities</a></h3><P CLASS="para">Sometimes it's useful to use a tool outside of the Samba suite to examine what's happening inside the server. Unix has always been a "kitchen-sink" operating system. Two diagnostic tools can be of particular help in debugging Samba troubles: <EM CLASS="emphasis">
+trace</em> and <EM CLASS="emphasis">
+tcpdump</em>.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945085">
+9.1.3.1 Using trace</a></h4><P CLASS="para">
+The <EM CLASS="emphasis">
+trace</em> command masquerades under several different names, depending on the operating system that you are using. On Linux it will be <EM CLASS="emphasis">
+strace</em>, on Solaris you'll use <EM CLASS="emphasis">
+truss</em>, and SGI will have <EM CLASS="emphasis">
+padc</em> and <EM CLASS="emphasis">
+par</em>. All have essentially the same function, which is to display each operating system function call as it is executed. This allows you to follow the execution of a program, such as the Samba server, and will often pinpoint the exact call that is causing the difficulty.</p><P CLASS="para">
+One problem that <EM CLASS="emphasis">
+trace</em> can highlight is the location of an incorrect version of a dynamically linked library. This can happen if you've downloaded prebuilt binaries of Samba. You'll typically see the offending call at the end of the <EM CLASS="emphasis">
+trace</em>, just before the program terminates.</p><P CLASS="para">
+A sample <CODE CLASS="literal">
+strace</code> output for the Linux operating system follows. This is a small section of a larger file created during the opening of a directory on the Samba server. Each line is a system-call name, and includes its parameters and the return value. If there was an error, the error value (e.g., <CODE CLASS="literal">
+ENOENT</code>) and its explanation are also shown. You can look up the parameter types and the errors that can occur in the appropriate <CODE CLASS="literal">
+trace</code> manual page for the operating system that you are using.</p><PRE CLASS="programlisting">
+chdir(&quot;/pcdisk/public&quot;) = 0
+stat(&quot;mini/desktop.ini&quot;, 0xbffff7ec) = -1 ENOENT (No such file or directory)
+stat(&quot;mini&quot;, {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
+stat(&quot;mini/desktop.ini&quot;, 0xbffff7ec) = -1 ENOENT (No such file or directory)
+open(&quot;mini&quot;, O_RDONLY) = 5
+fcntl(5, F_SETFD, FD_CLOEXEC) = 0
+fstat(5, {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
+lseek(5, 0, SEEK_CUR) = 0
+SYS_141(0x5, 0xbfffdbbc, 0xedc, 0xbfffdbbc, 0x80ba708) = 196
+lseek(5, 0, SEEK_CUR) = 1024
+SYS_141(0x5, 0xbfffdbbc, 0xedc, 0xbfffdbbc, 0x80ba708) = 0
+close(5) = 0
+stat(&quot;mini/desktop.ini&quot;, 0xbffff86c) = -1 ENOENT (No such file or directory)
+write(3, &quot;\0\0\0#\377SMB\10\1\0\2\0\200\1\0&quot;..., 39) = 39
+SYS_142(0xff, 0xbffffc3c, 0, 0, 0xbffffc08) = 1
+read(3, &quot;\0\0\0?&quot;, 4) = 4
+read(3, &quot;\377SMBu\0\0\0\0\0\0\0\0\0\0\0\0&quot;..., 63) = 63
+time(NULL) = 896143871</pre><P CLASS="para">
+This example shows several <CODE CLASS="literal">
+stat</code> calls failing to find the files they were expecting. You don't have to be a expert to see that the file <EM CLASS="emphasis">
+desktop.ini</em> is missing from that directory. In fact, many difficult problems can be identified by looking for obvious, repeatable errors with <EM CLASS="emphasis">
+trace</em>. Often, you need not look farther than the last message before a crash.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945114">
+9.1.3.2 Using tcpdump</a></h4><P CLASS="para">
+The <EM CLASS="emphasis">
+tcpdump</em> program, written by Van Jacobson, Craig Leres, and Steven McCanne, and extended by Andrew Tridgell, allows you to monitor network traffic in real time. A variety of output formats are available and you can filter the output to look at only a particular type of traffic. The <EM CLASS="emphasis">
+tcpdump</em> program lets you examine all conversations between client and server, including SMB and NMB broadcast messages. While its troubleshooting capabilities lie mainly at the OSI network layer, you can still use its output to get a general idea of what the server and client are attempting to accomplish.</p><P CLASS="para">
+A sample <EM CLASS="emphasis">
+tcpdump</em> log follows. In this instance, the client has requested a directory listing and the server has responded appropriately, giving the directory names <CODE CLASS="literal">
+homes</code>, <CODE CLASS="literal">
+public</code>, <CODE CLASS="literal">
+IPC$</code>, and <CODE CLASS="literal">
+temp</code> (we've added a few explanations on the right):</p><PRE CLASS="programlisting">$<CODE CLASS="userinput"><B> tcpdump -v -s 255 -i eth0 port not telnet</b></code>
+SMB PACKET: SMBtrans (REQUEST) <CODE CLASS="replaceable">
+<I>
+Request packet</i></code>
+SMB Command = 0x25 <CODE CLASS="replaceable">
+<I>
+Request was ls or dir</i></code>.
+
+[000] 01 00 00 10 ....
+
+
+&gt;&gt;&gt; NBT Packet <CODE CLASS="replaceable">
+<I>
+Outer frame of SMB packe</i></code>t
+NBT Session Packet
+Flags=0x0
+Length=226
+[lines skipped]
+
+SMB PACKET: SMBtrans (REPLY) <CODE CLASS="replaceable">
+<I>
+Beginning of a reply to request </i></code>
+SMB Command = 0x25 <CODE CLASS="replaceable">
+<I>
+Command was an ls or dir</i></code>
+Error class = 0x0
+Error code = 0 <CODE CLASS="replaceable">
+<I>
+No errors</i></code>
+Flags1 = 0x80
+Flags2 = 0x1
+Tree ID = 105
+Proc ID = 6075
+UID = 100
+MID = 30337
+Word Count = 10
+TotParamCnt=8
+TotDataCnt=163
+Res1=0
+ParamCnt=8
+ParamOff=55
+Res2=0
+DataCnt=163
+DataOff=63
+Res3=0
+Lsetup=0
+Param Data: (8 bytes)
+[000] 00 00 00 00 05 00 05 00 ........
+
+Data Data: (135 bytes) <CODE CLASS="replaceable">
+<I>
+ Actual directory contents:</i></code>
+[000] 68 6F 6D 65 73 00 00 00 00 00 00 00 00 00 00 00 homes... ........
+[010] 64 00 00 00 70 75 62 6C 69 63 00 00 00 00 00 00 d...publ ic......
+[020] 00 00 00 00 75 00 00 00 74 65 6D 70 00 00 00 00 ....u... temp....
+[030] 00 00 00 00 00 00 00 00 76 00 00 00 49 50 43 24 ........ v...IPC$
+[040] 00 00 00 00 00 00 00 00 00 00 03 00 77 00 00 00 ........ ....w...
+[050] 64 6F 6E 68 61 6D 00 00 00 00 00 00 00 00 00 00 donham.. ........
+[060] 92 00 00 00 48 6F 6D 65 20 44 69 72 65 63 74 6F ....Home Directo
+[070] 72 69 65 73 00 00 00 49 50 43 20 53 65 72 76 69 ries...I PC Servi
+[080] 63 65 20 28 53 61 6D ce (Sam</pre><P CLASS="para">
+This is more of the same debugging session as with the
+<i>trace</i> command; the listing of a directory. The options we used were <CODE CLASS="literal">
+-v</code> (verbose), <CODE CLASS="literal">
+-i</code> <CODE CLASS="literal">
+eth0</code> to tell <EM CLASS="emphasis">
+tcpdump</em> the interface to listen on (an Ethernet port), and <CODE CLASS="literal">
+-s</code> <CODE CLASS="literal">
+255</code> to tell it to save the first 255 bytes of each packet instead of the default: the first 68. The option <CODE CLASS="literal">
+port</code> <CODE CLASS="literal">
+not</code> <CODE CLASS="literal">
+telnet</code> is used to avoid screens of telnet traffic, since we were logged in to the server remotely. The <EM CLASS="emphasis">
+tcpdump</em> program actually has quite a number of options to filter just the traffic you want to look at. If you've used <EM CLASS="emphasis">
+snoop</em> or <EM CLASS="emphasis">
+etherdump</em>, they'll look vaguely familiar.</p><P CLASS="para">
+You can download the modified <EM CLASS="emphasis">
+tcpdump</em> from the Samba FTP server at <I CLASS="filename">
+<a href="ftp://samba.anu.edu.au/pub/samba/tcpdump-smb">ftp://samba.anu.edu.au/pub/samba/tcpdump-smb</i></a>. Other versions don't include support for the SMB protocol; if you don't see output such as that shown in the example, you'll need to<EM CLASS="emphasis">
+</em> use the SMB-enabled version.</p></div></div></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch08_07.html" TITLE="8.7 Backups with smbtar">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 8.7 Backups with smbtar" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_02.html" TITLE="9.2 The Fault Tree">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9.2 The Fault Tree" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">8.7 Backups with smbtar</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+9.2 The Fault Tree</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch09_02.html b/docs/htmldocs/using_samba/ch09_02.html
new file mode 100644
index 00000000000..e4c740fe278
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch09_02.html
@@ -0,0 +1,1772 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 9] 9.2 The Fault Tree</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:36:27Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_01.html" TITLE="9.1 The Tool Bag">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.1 The Tool Bag" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch09_01.html" TITLE="9. Troubleshooting Samba">
+Chapter 9<br>
+Troubleshooting Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_03.html" TITLE="9.3 Extra Resources">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9.3 Extra Resources" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch09-29538">
+9.2 The Fault Tree</a></h2><P CLASS="para">The fault tree is for diagnosing and fixing problems that occur when you're installing and reconfiguring Samba. It's an expanded form of a trouble and diagnostic document that is part of the Samba distribution.</p><P CLASS="para">Before you set out to troubleshoot any part of the Samba suite, you should know the following information:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945178">
+</a> Your client IP address (we use 192.168.236.10) </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945179">
+</a> Your server IP address (we use 192.168.236.86) </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945180">
+</a> The netmask for your network (typically 255.255.255.0)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945181">
+</a> Whether the machines are all on the same subnet (ours are)</p></li></ul><P CLASS="para">
+For clarity, we've renamed the server in the following examples to <EM CLASS="emphasis">
+server.example.com</em>, and the client machine to <EM CLASS="emphasis">
+client.example.com</em>.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-945183">
+9.2.1 How to use the fault tree</a></h3><P CLASS="para">Start the tests here, without skipping forward; it won't take long (about five minutes) and may actually save you time backtracking. Whenever a test succeeds, you will be given a section name and page number to which you can safely skip.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-953555">
+9.2.2 Troubleshooting Low-level IP </a></h3><P CLASS="para">The first series of tests is that of the low-level services that Samba needs in order to run. The tests in this section will verify that:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945191">
+</a> The IP software works</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945192">
+</a> The Ethernet hardware works</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945193">
+</a> Basic name service is in place</p></li></ul><P CLASS="para">
+Subsequent sections will add TCP software, the Samba daemons <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em>, host-based access control, authentication and per-user access control, file services, and browsing. The tests are described in considerable detail in order to make them understandable by both technically oriented end users and experienced systems and network administrators.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945197">
+9.2.2.1 Testing the networking software with ping </a></h4><P CLASS="para">
+The first command to enter on both the server and the client is <CODE CLASS="literal">
+ping 127.0.0.1</code>. This is the <I CLASS="firstterm">
+loopback</i> <EM CLASS="emphasis">
+address</em> and testing it will indicate whether any networking support is functioning at all. On Unix, you can use <CODE CLASS="literal">
+ping</code> <CODE CLASS="literal">
+127.0.0.1</code> with the statistics option and interrupt it after a few lines. On Sun workstations, the command is typically <CODE CLASS="literal">
+/usr/etc/ping</code> <CODE CLASS="literal">
+-s</code> <CODE CLASS="literal">
+127.0.0.1</code>; on Linux, just <CODE CLASS="literal">
+ping</code> <CODE CLASS="literal">
+127.0.0.1</code>. On Windows clients, run <CODE CLASS="literal">
+ping</code> <CODE CLASS="literal">
+127.0.0.1</code> in an MS-DOS window and it will stop by itself after four lines.</p><P CLASS="para">
+Here is an example on a Linux server:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> ping 127.0.0.1 </b>
+</pre><PRE CLASS="programlisting">
+PING localhost: 56 data bytes 64 bytes from localhost (127.0.0.1):
+icmp-seq=0. time=1. ms 64 bytes from localhost (127.0.0.1):
+icmp-seq=1. time=0. ms 64 bytes from localhost (127.0.0.1):
+icmp-seq=2. time=1. ms ^C
+----127.0.0.1 PING Statistics----
+3 packets transmitted, 3 packets received, 0% packet loss round-trip (ms)
+min/avg/max = 0/0/1 </pre><P CLASS="para">
+If you get "ping: no answer from..." or "100% packet loss," you have no IP networking at all installed on the machine. The address <CODE CLASS="literal">
+127.0.0.1</code> is the internal loopback address and doesn't depend on the computer being physically connected to a network. If this test fails, you have a serious local problem. TCP/IP either isn't installed or is seriously misconfigured. See your operating system documentation if it is a Unix server. If it is a Windows client, follow the instructions in <a href="ch03_01.html"><b>Chapter 3, <CITE CLASS="chapter">Configuring Windows Clients</cite></b></a>, to install networking support.</p><P CLASS="para">
+If <EM CLASS="emphasis">
+you're</em> the network manager, some good references are Craig Hunt's <EM CLASS="emphasis">
+TCP/IP Network Administration</em>, Chapter 11, and Craig Hunt &amp; Robert Bruce Thompson's new book, <EM CLASS="emphasis">
+Windows NT TCP/IP Network Administration, </em>both published by O'Reilly.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-20350">
+9.2.2.2 Testing local name services with ping </a></h4><P CLASS="para">Next, try to ping <CODE CLASS="literal">
+localhost</code> on the Samba server. <CODE CLASS="literal">
+localhost</code> is the conventional hostname for the 127.0.0.1 loopback, and it should resolve to that address. After typing <CODE CLASS="literal">
+ping</code> <CODE CLASS="literal">
+localhost</code>, you should see output similar to the following:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> ping localhost </b>
+</pre><PRE CLASS="programlisting">
+PING localhost: 56 data bytes 64 bytes from localhost (127.0.0.1):
+icmp-seq=0. time=0. ms 64 bytes from localhost (127.0.0.1):
+icmp-seq=1. time=0. ms 64 bytes from localhost (127.0.0.1):
+icmp-seq=2. time=0. ms ^C</pre><P CLASS="para">
+If this succeeds, try the same test on the client. Otherwise:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-951025">
+</a>If you get "unknown host: localhost," there is a problem resolving the host name localhost into a valid IP address. (This may be as simple as a missing entry in a local <EM CLASS="emphasis">
+hosts</em> file.) From here, skip down to the section <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8, Troubleshooting Name Services</a>. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946775">
+</a>If you get "ping: no answer," or "100% packet loss," but pinging 127.0.0.1 worked, then name services is resolving to an address, but it isn't the correct one. Check the file or database (typically <I CLASS="filename">
+/etc/hosts</i> on a Unix system) that the name service is using to resolve addresses to ensure that the entry is corrected.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946776">
+9.2.2.3 Testing the networking hardware with ping </a></h4><P CLASS="para">Next, ping the server's network IP address from itself. This should get you exactly the same results as pinging 127.0.0.1:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> ping 192.168.236.86 </b>
+</pre><PRE CLASS="programlisting">
+PING 192.168.236.86: 56 data bytes 64 bytes from 192.168.236.86 (192.168.236.86):
+icmp-seq=0. time=1. ms 64 bytes from 192.168.236.86 (192.168.236.86):
+icmp-seq=1. time=0. ms 64 bytes from 192.168.236.86 (192.168.236.86):
+icmp-seq=2. time=1. ms ^C
+----192.168.236.86 PING Statistics----
+3 packets transmitted, 3 packets received, 0% packet loss round-trip (ms)
+min/avg/max = 0/0/1</pre><P CLASS="para">
+If this works on the server, repeat it for the client. Otherwise:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945243">
+</a>If <CODE CLASS="literal">
+ping</code> <CODE CLASS="replaceable">
+<I>
+network_ip</i></code> fails on either the server or client, but ping 127.0.0.1 works on that machine, you have a TCP/IP problem that is specific to the Ethernet network interface card on the computer. Check with the documentation for the network card or the host operating system to determine how to correctly configure it. However, be aware that on some operating systems, the <EM CLASS="emphasis">
+ping</em> command appears to work even if the network is disconnected, so this test doesn't always diagnose all hardware problems. </p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-84079">
+9.2.2.4 Testing connections with ping</a></h4><P CLASS="para">Now, ping the server by name (instead of its IP address), once from the server and once from the client. This is the general test for working network hardware:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> ping server </b>
+</pre><PRE CLASS="programlisting">
+PING server.example.com: 56 data bytes 64 bytes from server.example.com (192.168.236.86):
+icmp-seq=0. time=1. ms 64 bytes from server.example.com (192.168.236.86):
+icmp-seq=1. time=0. ms 64 bytes from server.example.com (192.168.236.86):
+icmp-seq=2. time=1. ms ^C
+----server.example.com PING Statistics----
+3 packets transmitted, 3 packets received, 0% packet loss round-trip (ms)
+min/avg/max = 0/0/1</pre><P CLASS="para">
+On Microsoft Windows, a ping of the server would look like <A CLASS="xref" HREF="ch09_02.html#ch09-91668">
+Figure 9.1</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch09-91668">
+Figure 9.1: Pinging the Samba server from a Windows client</a></h4><IMG CLASS="graphic" SRC="figs/sam.0901.gif" ALT="Figure 9.1"><P CLASS="para">
+If successful, this test tells us five things:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946836">
+</a>The hostname (e.g., "server") is being found by your local nameserver.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946837">
+</a>The hostname has been expanded to the full name (e.g., <A CLASS="email" HREF="mailto:server.example.com" TITLE="server.example.com">
+server.example.com</a>).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945264">
+</a>Its address is being returned (192.168.236.86).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945265">
+</a>The client has sent the Samba server four 56-byte UDP/IP packets.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945266">
+</a>The Samba server has replied to all four packets.</p></li></ol><P CLASS="para">
+If this test isn't successful, there can be one of several things wrong with the network:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945267">
+</a>First, if you get "ping: no answer," or "100% packet loss," you're not connecting to the network, the other machine isn't connecting, or one of the addresses is incorrect. Check the addresses that the <CODE CLASS="literal">
+ping</code> command reports on each machine, and ensure that they match the ones you set up initially.</p><P CLASS="para">
+If not, there is at least one mismatched address between the two machines. Try entering the command <CODE CLASS="literal">
+arp</code> <CODE CLASS="literal">
+-a</code>, and see if there is an entry for the other machine. The <CODE CLASS="literal">
+arp</code> command stands for the Address Resolution Protocol. The <CODE CLASS="literal">
+arp</code> <CODE CLASS="literal">
+-a</code> command lists all the addresses known on the local machine. Here are some things to try:</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946854">
+</a>If you receive a message like "192.168.236.86 at (incomplete)," the Ethernet address of 192.168.236.86 is unknown. This indicates a complete lack of connectivity, and you're likely having a problem at the very bottom of the TCP/IP Network Administration protocol stack, at the Ethernet-interface layer. This is discussed in Chapters 5 and 6 of <CITE CLASS="citetitle">
+TCP/IP Network Administration </cite>(O'Reilly).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945274">
+</a>If you receive a response similar to "server (192.168.236.86) at 8:0:20:12:7c:94," then the server has been reached at some time, or another machine is answering on its behalf. However, this means that <EM CLASS="emphasis">
+ping</em> should have worked: you may have an intermittent networking or ARP problem.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945275">
+</a>If the IP address from ARP doesn't match the addresses you expected, investigate and correct the addresses manually.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945284">
+</a>If each machine can ping itself but not another, something is wrong on the network between them.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945287">
+</a>If you get "ping: network unreachable" or "ICMP Host Unreachable," then you're not receiving an answer and there is likely more than one network involved.</p><P CLASS="para">
+In principle, you shouldn't try to troubleshoot SMB clients and servers on different networks. Try to test a server and client on the same network. The three tests that follow assume you might be testing between two networks:</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-951057">
+</a>First, perform the tests for no answer described earlier in this section. If this doesn't identify the problem, the remaining possibilities are the following: an address is wrong, your netmask is wrong, a network is down, or just possibly you've been stopped by a firewall.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-951077">
+</a>Check both the address and the netmasks on source and destination machines to see if something is obviously wrong. Assuming both machines really are on the same network, they both should have the same netmasks and <EM CLASS="emphasis">
+ping</em> should report the correct addresses. If the addresses are wrong, you'll need to correct them. If they're right, the programs may be confused by an incorrect netmask. See <A CLASS="xref" HREF="ch09_02.html#ch09-21203">
+Section 9.2.9.1, Netmasks</a>, later in this chapter.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945300">
+</a>If the commands are still reporting that the network is unreachable and neither of the previous two conditions is in error, one network really may be unreachable from the other. This, too, is a network manager issue.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946936">
+</a>If you get "ICMP Administratively Prohibited," you've struck a firewall of some sort or a misconfigured router. You will need to speak to your network security officer.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946938">
+</a>If you get "ICMP Host redirect," and <EM CLASS="emphasis">
+ping</em> reports packets getting through, this is generally harmless: you're simply being rerouted over the network.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945305">
+</a>If you get a host redirect and no <EM CLASS="emphasis">
+ping</em> responses, you are being redirected, but no one is responding. Treat this just like the "Network unreachable" response and check your addresses and netmasks.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945308">
+</a>If you get "ICMP Host Unreachable from gateway <EM CLASS="emphasis">
+gateway_name</em>," ping packets are being routed to another network, but the other machine isn't responding and the router is reporting the problem on its behalf. Again, treat this like a "Network unreachable" response and start checking addresses and netmasks.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946955">
+</a>If you get "ping: unknown host <EM CLASS="emphasis">
+hostname</em>," your machine's name is not known. This tends to indicate a name-service problem, which didn't affect <CODE CLASS="literal">
+localhost</code>. Have a look at <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8</a>, later in this chapter.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946959">
+</a>If you get a partial success, with some pings failing but others succeeding, you either have an intermittent problem between the machines or an overloaded network. Ping for longer, and see if more than about 3 percent of the packets fail. If so, check it with your network manager: a problem may just be starting. However, if only a few fail, or if you happen to know some massive network program is running, don't worry unduly. Ping's ICMP (and UDP) are designed to drop occasional packets.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945319">
+</a>If you get a response like "smtsvr.antares.net is alive" when you actually pinged <EM CLASS="emphasis">
+client.example.com</em>, you're either using someone else's address or the machine has multiple names and addresses. If the address is wrong, name service is clearly the culprit; you'll need to change the address in the name service database to refer to the right machine. This is discussed in <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8</a>, later in this chapter.</p><P CLASS="para">
+Server machines are often <EM CLASS="emphasis">
+multihomed</em> : connected to more than one network, with different names on each net. If you are getting a response from an unexpected name on a multihomed server, look at the address and see if it's on your network (see the section <A CLASS="xref" HREF="ch09_02.html#ch09-21203">
+Section 9.2.9.1</a>, later in this chapter). If so, you should use that address, rather than one on a different network, for both performance and reliability reasons.</p><P CLASS="para">
+Servers may also have multiple names for a single Ethernet address, especially if they are web servers. This is harmless, if otherwise startling. You probably will want to use the official (and permanent) name, rather than an alias which may change.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945333">
+</a>If everything works, but the IP address reported is 127.0.0.1, you have a name service error. This typically occurs when a operating system installation program generates an <I CLASS="filename">
+/etc/hosts</i> line similar to <CODE CLASS="literal">
+127.0.0.1</code> <CODE CLASS="literal">
+localhost</code> <EM CLASS="emphasis">
+hostnamedomainname</em>. The localhost line should say <CODE CLASS="literal">
+127.0.0.1</code> <CODE CLASS="literal">
+localhost</code> or <CODE CLASS="literal">
+127.0.0.1</code> <CODE CLASS="literal">
+localhost</code> <CODE CLASS="literal">
+loghost</code>. Correct it, lest it cause failures to negotiate who is the master browse list holder and who is the master browser. It can, also cause (ambiguous) errors in later tests.</p></li></ul><P CLASS="para">
+If this worked from the server, repeat it from the client.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-945336">9.2.3 Troubleshooting TCP</a></h3><P CLASS="para">Now that you've tested IP, UDP, and a name service with <EM CLASS="emphasis">
+ping</em>, it's time to test TCP. <EM CLASS="emphasis">
+ping</em> and browsing use ICMP and UDP; file and print services (shares) use TCP. Both depend on IP as a lower layer and all four depend on name services. Testing TCP is most conveniently done using the FTP (file transfer protocol) program.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-78512">
+9.2.3.1 Testing TCP with FTP </a></h4><P CLASS="para">
+Try connecting via FTP, once from the server to itself, and once from the client to the server: </p><PRE CLASS="programlisting">
+server% <CODE CLASS="userinput"><B>ftp server</b></code>
+Connected to server.example.com.
+220 server.example.com FTP server (Version 6.2/OpenBSD/Linux-0.10) ready.
+ Name (server:davecb):
+331 Password required for davecb.
+Password:
+230 User davecb logged in.
+ ftp&gt;<CODE CLASS="userinput"><B> quit </b></code>
+221 Goodbye. </pre><P CLASS="para">
+If this worked, skip to the section <A CLASS="xref" HREF="ch09_02.html#ch09-88968">
+Section 9.2.4, Troubleshooting Server Daemons</a>. Otherwise:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945357">
+</a>If you received the message "server: unknown host," then nameservice has failed. Go back to the corresponding <EM CLASS="emphasis">
+ping</em> step, <A CLASS="xref" HREF="ch09_02.html#ch09-20350">
+Section 9.2.2.2, Testing local name services with ping </a>, and rerun those tests to see why name lookup failed.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945362">
+</a>If you received "ftp: connect: Connection refused," the machine isn't running an FTP daemon. This is mildly unusual on Unix servers. Optionally, you might try this test by connecting to the machine using telnet instead of FTP; the messages are very similar and telnet uses TCP as well.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945364">
+</a>If there was a long pause, then "ftp: connect: Connection timed out," the machine isn't reachable. Return to the section <A CLASS="xref" HREF="ch09_02.html#ch09-84079">
+Section 9.2.2.4, Testing connections with ping</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945369">
+</a>If you received "530 Logon Incorrect," you connected successfully, but you've just found a different problem. You likely provided an incorrect username or password. Try again, making sure you use your username from the Unix server and type your password correctly.</p></li></ul></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-88968">
+9.2.4 Troubleshooting Server Daemons</a></h3><P CLASS="para">Once you've confirmed that TCP networking is working properly, the next step is to make sure the daemons are running on the server. This takes three separate tests because no single one of the following will decisively prove that they're working correctly.</p><P CLASS="para">
+To be sure they're running, you need to find out if:</p><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945374">
+</a>The daemon has started</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945375">
+</a>The daemons are registered or bound to a TCP/IP port by the operating system</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945376">
+</a>They're actually paying attention</p></li></ol><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-947020">
+9.2.4.1 Before you start</a></h4><P CLASS="para">
+First, check the logs. If you've started the daemons, the message "smbd version <EM CLASS="emphasis">
+some_number</em> started" should appear. If it doesn't, you will need to restart the Samba daemons.</p><P CLASS="para">
+If the daemon reports that it has indeed started, look out for "bind failed on port 139 socket_addr=0 (Address already in use)". This means another daemon has been started on port 139 (<EM CLASS="emphasis">smbd</em>). Also, <EM CLASS="emphasis">
+nmbd</em> will report a similar failure if it cannot bind to port 137. Either you've started them twice, or the <EM CLASS="emphasis">
+inetd</em> server has tried to provide a daemon for you. If it's the latter, we'll diagnose that in a moment.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-49239">
+9.2.4.2 Looking for daemon processes with ps</a></h4><P CLASS="para">
+Next, you need to see if the daemons have been started. Use the <CODE CLASS="literal">
+ps</code> command on the server with the <CODE CLASS="literal">
+long</code> option for your machine type (commonly <CODE CLASS="literal">
+ps</code> <CODE CLASS="literal">
+ax</code> or <CODE CLASS="literal">
+ps</code> <CODE CLASS="literal">
+-ef</code>), and see if you have either <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em> already running. This often looks like the following:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> ps ax</b>
+</pre><PRE CLASS="programlisting">
+ PID TTY STAT TIME COMMAND
+ 1 ? S 0:03 init [2]
+ 2 ? SW 0:00 (kflushd)
+<EM CLASS="emphasis">
+(...many lines of processes...)</em>
+ 234 ? S 0:14 nmbd -D3
+ 237 ? S 0:11 smbd -D3
+<EM CLASS="emphasis">
+(...more lines, possibly including more smbd lines...) </em></pre><P CLASS="para">
+This example illustrates that <EM CLASS="emphasis">
+smbd</em> and <EM CLASS="emphasis">
+nmbd</em> have already started as stand-alone daemons (the <CODE CLASS="literal">
+-D</code> option) at log level 3.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945392">
+9.2.4.3 Looking for daemons bound to ports</a></h4><P CLASS="para">
+Next, the daemons have to be registered with the operating system so they can get access to TCP/IP ports. The <CODE CLASS="literal">
+netstat</code> command will tell you if this has been done. Run the command <CODE CLASS="literal">
+netstat</code> <CODE CLASS="literal">
+-a</code> on the server, and look for lines mentioning <CODE CLASS="literal">
+netbios</code>, <CODE CLASS="literal">
+137</code> or <CODE CLASS="literal">
+139</code>:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> netstat -a </b>
+</pre><PRE CLASS="programlisting">
+Active Internet connections (including servers)
+Proto Recv-Q Send-Q Local Address Foreign Address (state)
+udp 0 0 *.netbios- *.*
+tcp 0 0 *.netbios- *.* LISTEN
+tcp 8370 8760 server.netbios- client.1439
+ESTABLISHED </pre><P CLASS="para">
+or:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> netstat -a </b>
+</pre><PRE CLASS="programlisting">
+Active Internet connections (including servers)
+Proto Recv-Q Send-Q Local Address Foreign Address (state)
+udp 0 0 *.137 *.*
+tcp 0 0 *.139 *.* LISTEN
+tcp 8370 8760 server.139 client.1439 ESTABLISHED </pre><P CLASS="para">
+Among many similar lines, there should be at least one UDP line for <CODE CLASS="literal">
+*.netbios-</code> or <CODE CLASS="literal">
+*.137</code>. This indicates that the <EM CLASS="emphasis">
+nmbd</em> server is registered and (we hope) is waiting to answer requests. There should also be at least one TCP line mentioning <CODE CLASS="literal">
+*.netbios-</code> or <CODE CLASS="literal">
+*.139</code>, and it will probably be in the LISTENING state. This means that <EM CLASS="emphasis">
+smbd</em> is up and listening for connections.</p><P CLASS="para">
+There may be other TCP lines indicating connections from <EM CLASS="emphasis">
+smbd</em> to clients, one for each client. These are usually in the ESTABLISHED state. If there are <EM CLASS="emphasis">
+smbd</em> lines in the ESTABLISHED state, <EM CLASS="emphasis">
+smbd</em> is definitely running. If there is only one line in the LISTENING state, we're not sure yet. If both of the lines is missing, a daemon has not succeeded in starting, so it's time to check the logs and then go back to <a href="ch02_01.html"><b>Chapter 2</b></a>.</p><P CLASS="para">
+If there is a line for each client, it may be coming either from a Samba daemon or from the master IP daemon, <EM CLASS="emphasis">
+inetd</em>. It's quite possible that your <EM CLASS="emphasis">
+inetd</em> startup file contains lines that start Samba daemons without your realizing it; for instance, the lines may have been placed there if you installed Samba as part of a Linux distribution. The daemons started by <EM CLASS="emphasis">
+inetd</em> prevent ours from running. This problem typically produces log messages such as "bind failed on port 139 socket_addr=0 (Address already in use)."</p><P CLASS="para">
+Check your <I CLASS="filename">
+/etc/inetd.conf</i> ; unless you're intentionally starting the daemons from there, there <EM CLASS="emphasis">
+must not</em> be any <CODE CLASS="literal">
+netbios-ns</code> (udp port 137) or <CODE CLASS="literal">
+netbios-ssn</code> (tcp port 139) servers mentioned there. <EM CLASS="emphasis">
+inetd</em> is a daemon that provides numerous services, controlled by entries in <EM CLASS="emphasis">
+/etc/inetd.conf</em>. If your system is providing an SMB daemon via <EM CLASS="emphasis">
+inetd</em>, there will be lines like the following in the file:</p><PRE CLASS="programlisting">
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd</pre></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945425">
+9.2.4.4 Checking smbd with telnet</a></h4><P CLASS="para">
+Ironically, the easiest way to test that the <EM CLASS="emphasis">
+smbd</em> server is actually working is to send it a meaningless message and see if it rejects it. Try something like the following:</p><PRE CLASS="programlisting"><CODE CLASS="userinput"><B>echo hello | telnet localhost 139</b></code></pre><P CLASS="para">
+This sends an erroneous but harmless message to <EM CLASS="emphasis">
+smbd</em>. The <CODE CLASS="literal">
+hello</code> message is important. Don't try telneting to the port and typing just anything; you'll probably just hang your process. <CODE CLASS="literal">
+hello</code>, however, is generally a harmless message.</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> echo &quot;hello&quot; | telnet localhost 139 </b>
+</pre><PRE CLASS="programlisting">
+Trying
+Trying 192.168.236.86 ...
+Connected to localhost. Escape character is '^]'.
+Connection closed by foreign host. </pre><P CLASS="para">
+If you get a "Connected" message followed by a "Connection closed" message, the test was a success. You have an <EM CLASS="emphasis">
+smbd</em> daemon listening on the port and rejecting improper connection messages. On the other hand, if you get "telnet: connect: Connection refused," there is probably no daemon present. Check the logs and go back to <a href="ch01_01.html"><b>Chapter 2</b></a>.</p><P CLASS="para">
+Regrettably, there isn't an easy test for <EM CLASS="emphasis">
+nmbd</em>. If the <CODE CLASS="literal">
+telnet</code> test and the <CODE CLASS="literal">
+netstat</code> test both say that there is an <EM CLASS="emphasis">
+smbd</em> running, there is a good chance that <CODE CLASS="literal">
+netstat</code> will also be correct about <EM CLASS="emphasis">
+nmbd</em> running.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-67494">
+9.2.4.5 Testing daemons with testparm</a></h4><P CLASS="para">Once you know there's a daemon, you should always run <CODE CLASS="literal">
+testparm</code>, in hopes of getting:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server%</code> testparm </b>
+</pre><PRE CLASS="programlisting">
+Load smb config files from /opt/samba/lib/smb.conf
+Processing section &quot;[homes]&quot;
+Processing section &quot;[printers]&quot; ...
+Processing section &quot;[tmp]&quot;
+Loaded services file OK. ... </pre><P CLASS="para">
+The <CODE CLASS="literal">
+testparm</code> program normally reports processing a series of sections, and responds with "Loaded services file OK" if it succeeds. If not, it will report one or more of the following messages, which will also appear in the logs as noted:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+<EM CLASS="emphasis">
+"Allow/Deny connection from account (n) to service"</em></dt><DD CLASS="listitem">
+<P CLASS="para">
+A <EM CLASS="emphasis">
+testparm</em>-only message produced if you have valid/invalid user options set in your <EM CLASS="emphasis">
+smb.conf</em>. You will want to make sure that you are on the valid user list, and that root, bin, etc., are on the invalid user list. If you don't, you will not be able to connect, or folks who shouldn't <EM CLASS="emphasis">
+will</em> be able to.</p></dd><DT CLASS="term">
+<EM CLASS="emphasis">
+"Warning: You have some share names that are longer than eight chars"</em></dt><DD CLASS="listitem">
+<P CLASS="para">
+For anyone using Windows for Workgroups and older clients. They will fail to connect to shares with long names, producing an overflow message that sounds confusingly like a memory overflow.</p></dd><DT CLASS="term">
+"Warning: [name] service MUST be printable!"</dt><DD CLASS="listitem">
+<P CLASS="para">
+A printer share lacks a <CODE CLASS="literal">
+printable</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option.</p></dd><DT CLASS="term">
+"No path in service name using [name]"</dt><DD CLASS="listitem">
+<P CLASS="para">
+A file share doesn't know which directory to provide to the user, or a print share doesn't know which directory to use for spooling. If no path is specified, the service will try to run with a path of <EM CLASS="emphasis">
+/tmp</em>, which may not be what you want.</p></dd><DT CLASS="term">
+"Note: Servicename is flagged unavailable"</dt><DD CLASS="listitem">
+<P CLASS="para">
+Just a reminder that you have used the <CODE CLASS="literal">
+available</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+no</code> option in a share.</p></dd><DT CLASS="term">
+"Can't find include file [name]" </dt><DD CLASS="listitem">
+<P CLASS="para">
+A configuration file referred to by an <CODE CLASS="literal">
+include</code> option did not exist. If you were including the file unconditionally, this is an error and probably a serious one: the share will not have the configuration you intended. If you were including it based one of the <CODE CLASS="literal">
+%</code> variables, such as <CODE CLASS="literal">
+%a</code> (architecture), you will need to decide if, for example, a missing Windows for Workgroups configuration file is a problem. It often isn't.</p></dd><DT CLASS="term">
+"Can't copy service name, unable to copy to itself"</dt><DD CLASS="listitem">
+<P CLASS="para">
+You tried to copy a <I CLASS="filename">
+smb.conf</i> section into itself.</p></dd><DT CLASS="term">
+"Unable to copy service&nbsp;- source not found: [name]"</dt><DD CLASS="listitem">
+<P CLASS="para">
+Indicates a missing or misspelled section in a <CODE CLASS="literal">
+copy</code> <CODE CLASS="literal">
+=</code> option.</p></dd><DT CLASS="term">
+"Ignoring unknown parameter name" </dt><DD CLASS="listitem">
+<P CLASS="para">
+Typically indicates an obsolete, misspelled or unsupported option.</p></dd><DT CLASS="term">
+"Global parameter name found in service section" </dt><DD CLASS="listitem">
+<P CLASS="para">
+Indicates a global-only parameter has been used in an individual share. Samba will ignore the parameter.</p></dd></dl><P CLASS="para">
+After the <CODE CLASS="literal">
+testparm</code> test, repeat it with (exactly) three parameters: the name of your <I CLASS="filename">
+smb.conf</i> file, the name of your client, and its IP address:</p><PRE CLASS="programlisting">testparm <CODE CLASS="replaceable"><I>samba_directory</i></code>/lib/smb.conf client 192.168.236.10</pre><P CLASS="para">
+This will run one more test that checks the host name and address against <CODE CLASS="literal">
+host</code> <CODE CLASS="literal">
+allow</code> and <CODE CLASS="literal">
+host</code> <CODE CLASS="literal">
+deny</code> options and may produce the "Allow/Deny connection from account account_name" to service message for the client machine. This message indicates you have valid/invalid host options in your <I CLASS="filename">
+smb.conf</i>, and they prohibit access from the client machine. Entering <CODE CLASS="literal">
+testparm</code> <CODE CLASS="literal">
+/usr/local/lib/experimental.conf</code> is also an effective way to test an experimental <I CLASS="filename">
+smb.conf</i> file before putting it into production.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-945478">9.2.5 Troubleshooting SMB Connections</a></h3><P CLASS="para">Now that you know the servers are up, you need to make sure that they're running properly. We start with the <I CLASS="filename">
+smb.conf</i> file in the <CODE CLASS="replaceable">
+<I>
+samba_directory</i></code><I CLASS="filename">
+/lib</i> directory.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-67928">
+9.2.5.1 A minimal smb.conf file</a></h4><P CLASS="para">
+In the following tests, we assume you have a <CODE CLASS="literal">
+[temp]</code> share suitable for testing, plus at least one account. An <I CLASS="filename">
+smb.conf</i> file that includes just these is:</p><PRE CLASS="programlisting">
+[global]
+ workgroup = <CODE CLASS="replaceable">
+<I>
+EXAMPLE</i></code>
+ security = user
+ browsable = yes
+ local master = yes
+[homes]
+ guest ok = no
+ browseble = no
+[temp]
+ path = /tmp
+ public = yes </pre><P CLASS="para">
+A word of warning: the <CODE CLASS="literal">
+public</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option in the <CODE CLASS="literal">
+[temp]</code> share is just for testing. You probably don't want people without accounts to be able to store things on your Samba server, so you should comment it out when you're done.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-40595">
+9.2.5.2 Testing locally with smbclient</a></h4><P CLASS="para">The first test is to ensure the server can list its own services (shares). Run the command <CODE CLASS="literal">
+smbclient</code> with a <CODE CLASS="literal">
+-L</code> option of <CODE CLASS="literal">
+localhost</code> to connect to itself, and a <CODE CLASS="literal">
+-U</code> option of just <CODE CLASS="literal">
+%</code> to specify the guest user. You should see the following: </p><PRE CLASS="programlisting">server% <CODE CLASS="userinput"><B>smbclient -L localhost -U% </b></code>
+Server time is Wed May 27 17:57:40 1998 Timezone is UTC-4.0
+Server=[localhost]
+User=[davecb]
+Workgroup=[EXAMPLE]
+Domain=[EXAMPLE]
+ Sharename Type Comment
+ --------- ----- ----------
+ temp Disk
+ IPC$ IPC IPC Service (Samba 1.9.18)
+ homes Disk Home directories
+This machine does not have a browse list </pre><P CLASS="para">
+If you received this output, move on to the next test, <A CLASS="xref" HREF="ch09_02.html#ch09-77154">
+Section 9.2.5.3, Testing connections with smbclient</a>. On the other hand, if you receive an error, check the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-950443">
+</a>If you get "Get_hostbyname: unknown host localhost," either you've spelled its name wrong or there actually is a problem (which should have been seen back in <A CLASS="xref" HREF="ch09_02.html#ch09-20350">
+Section 9.2.2.2</a>) In the latter case, move on to "Troubleshooting Name Services."</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945526">
+</a>If you get "Connect error: Connection refused," the server machine was found, but it wasn't running an <EM CLASS="emphasis">
+nmbd</em> daemon. Skip back to <A CLASS="xref" HREF="ch09_02.html#ch09-88968">
+Section 9.2.4</a>, and retest the daemons.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945531">
+</a>If you get the message "Your server software is being unfriendly," the initial session request packet got a garbage response from the server. The server may have crashed or started improperly. The common causes of this can be discovered by scanning the logs for:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945533">
+</a>Invalid command-line parameters to <EM CLASS="emphasis">
+smbd</em>; see the <EM CLASS="emphasis">
+smbd</em> manual page.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945534">
+</a>A fatal problem with the <I CLASS="filename">
+smb.conf</i> file that prevents the startup of <EM CLASS="emphasis">
+smbd</em>. Always check your changes, as was done in the section <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5, Testing daemons with testparm</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947160">
+</a>The directories where Samba keeps its log and lock files are missing.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947165">
+</a>There is already a server on the port (139 for <EM CLASS="emphasis">
+smbd</em>, 137 for <EM CLASS="emphasis">
+nmbd </em>), preventing it from starting.</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945543">
+</a>If you're using <EM CLASS="emphasis">
+inetd</em> instead of stand-alone daemons, check your <I CLASS="filename">
+/etc/inetd.conf</i> and <I CLASS="filename">
+/etc/services</i> entries against their manual pages for errors as well.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945544">
+</a>If you get a <CODE CLASS="literal">
+Password:</code> prompt, your guest account is not set up properly. The <CODE CLASS="literal">
+%U</code> option tells <EM CLASS="emphasis">
+smbclient</em> to do a "null login," which requires that the guest account be present but does not require it to have any privileges.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947172">
+</a>If you get the message "SMBtconX failed. ERRSRV&nbsp;- ERRaccess," you aren't permitted access to the server. This normally means you have a <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+hosts</code> option that doesn't include the server, or an <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+hosts</code> option that does. Recheck with the command <CODE CLASS="literal">
+testparm</code> <CODE CLASS="literal">
+smb.conf</code> <CODE CLASS="replaceable">
+<I>
+your_hostname</i></code> <CODE CLASS="replaceable">
+<I>
+your_ip_address</i></code> (see the section <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>) and correct any unintended prohibitions. </p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-77154">
+9.2.5.3 Testing connections with smbclient</a></h4><P CLASS="para">Run the command <CODE CLASS="literal"> smbclient</code><CODE CLASS="literal">\\</code><CODE CLASS="replaceable"><I>server</i></code><CODE CLASS="literal">\temp</code>, which connects to your server's <I CLASS="filename">
+/tmp</i> share, to see if you can connect to a file service. You should get the following response:</p><PRE CLASS="programlisting"><B CLASS="emphasis.bold"><CODE CLASS="literal">server% </code>smbclient '\\server\temp' </b>
+</pre><PRE CLASS="programlisting">
+Server time is Tue May 5 09:49:32 1998 Timezone is UTC-4.0 Password:
+<B CLASS="emphasis.bold"><CODE CLASS="literal">
+smb:\&gt;</code> quit</b></pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947183">
+</a>If you get "Get_Hostbyname: Unknown host name," "Connect error: Connection refused," or "Your server software is being unfriendly," see the section <A CLASS="xref" HREF="ch09_02.html#ch09-40595">
+Section 9.2.5.2, Testing locally with smbclient</a> for the diagnoses.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947188">
+</a>If you get the message "servertemp: Not enough `\' characters in service," you likely didn't quote the address, so Unix stripped off backslashes. You can also write the command:</p></li></ul><PRE CLASS="programlisting"><CODE CLASS="literal">smbclient</code> <CODE CLASS="literal">\\\\</code><CODE CLASS="replaceable"><I>server</i></code><CODE CLASS="literal">\\temp</code> </pre><P CLASS="para">
+or: </p><PRE CLASS="programlisting">smbclient //<CODE CLASS="replaceable"><I>server</i></code>/temp </pre><P CLASS="para">
+Now, provide your Unix account password to the <CODE CLASS="literal">
+Password</code> prompt. If you then get an <CODE CLASS="literal">
+smb\&gt;</code> prompt, it worked. Enter <CODE CLASS="literal">
+quit</code>, and continue on to <A CLASS="xref" HREF="ch09_02.html#ch09-97081">
+Section 9.2.5.4, Testing connections with NET USE</a>. If you then get "SMBtconX failed. ERRSRV&nbsp;- ERRinvnetname," the problem can be any of the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947201">
+</a>A wrong share name: you may have spelled it wrong, it may be too long, it may be in mixed case, or it may not be available. Check that it's what you expect with testparm (see the section <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>.)</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947205">
+</a><CODE CLASS="literal">
+security</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+share</code>, in which you may have to add <CODE CLASS="replaceable">
+<I>
+-U your_account</i></code> to the <EM CLASS="emphasis">
+smbclient</em> command, or know the password of a Unix account named temp. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945578">
+</a>An erroneous username.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945579">
+</a>An erroneous password.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945580">
+</a>An <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> or <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> option in your <EM CLASS="emphasis">
+smb.conf</em> file that doesn't allow your account to connect. Recheck with <CODE CLASS="literal">
+testparm</code> <CODE CLASS="literal">
+smb.conf</code> <CODE CLASS="replaceable">
+<I>
+your_hostname your_ip_address</i></code> (see <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945584">
+</a>A <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+hosts</code> option that doesn't include the server, or an <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+hosts</code> option that does. Also test this with <EM CLASS="emphasis">
+testparm</em>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945585">
+</a>A problem in authentication, such as if shadow passwords or the PAM (Password Authentication Module) is used on the server, but Samba is not compiled to use it. This is rare, but occasionally happens when a SunOS 4 Samba binary (no shadow passwords) is run without recompilation on a Solaris system (with shadow passwords).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945586">
+</a>The <CODE CLASS="literal">
+encrypted</code> <CODE CLASS="literal">
+passwords</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option in the configuration file, but no password for your account in the <EM CLASS="emphasis">
+smbpasswd</em> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945587">
+</a>You have a null password entry, either in Unix <I CLASS="filename">
+/etc/passwd</i> or in the <EM CLASS="emphasis">
+smbpasswd</em> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945588">
+</a>You are connecting to <CODE CLASS="literal">
+[temp]</code>, and you do not have the <CODE CLASS="literal">
+guest</code> <CODE CLASS="literal">
+ok</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> option in the <CODE CLASS="literal">
+[temp]</code> section of the <EM CLASS="emphasis">
+smb.conf</em> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947992">
+</a>You are connecting to <CODE CLASS="literal">
+[temp]</code> before connecting to your home directory, and your guest account isn't set up correctly. If you can connect to your home directory and then connect to <CODE CLASS="literal">
+[temp]</code>, that's the problem. See <a href="ch02_01.html"><b>Chapter 2</b></a> for more information on creating a basic Samba configuration file.</p><P CLASS="para">
+A bad guest account will also prevent you from printing or browsing until after you've logged in to your home directory. </p></li></ul><P CLASS="para">
+There is one more reason for this failure that has nothing at all to do with passwords: the <CODE CLASS="literal">
+path</code> <CODE CLASS="literal">
+=</code> line in your <I CLASS="filename">
+smb.conf</i> file may point somewhere that doesn't exist. This will not be diagnosed by <EM CLASS="emphasis">
+testparm</em>, and most SMB clients can't tell it from other types of bad user accounts. You will have to check it manually.</p><P CLASS="para">
+Once you have connected to <CODE CLASS="literal">
+[temp]</code> successfully, repeat the test, this time logging in to your home directory (e.g., map network drive <CODE CLASS="replaceable">
+<I>
+server</i></code><CODE CLASS="literal">
+\davecb</code>) looking for failures in doing that. If you have to change anything to get that to work, re-test <CODE CLASS="literal">
+[temp]</code> again afterwards.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-97081">
+9.2.5.4 Testing connections with NET USE</a></h4><P CLASS="para">Run the command <CODE CLASS="literal">
+net</code> <CODE CLASS="literal">use</code> <CODE CLASS="literal">* </code><CODE CLASS="literal">\</code><CODE CLASS="replaceable"><I>server</i></code><CODE CLASS="literal">\temp</code> on the DOS or Windows client to see if it can connect to the server. You should be prompted for a password, then receive the response "The command was completed successfully," as shown in <A CLASS="xref" HREF="ch09_02.html#ch09-99328">
+Figure 9.2</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch09-99328">
+Figure 9.2: Results of the NET USE command</a></h4><IMG CLASS="graphic" SRC="figs/sam.0902.gif" ALT="Figure 9.2"><P CLASS="para">
+If that succeeded, continue with the steps in the section <A CLASS="xref" HREF="ch09_02.html#ch09-57065">
+Section 9.2.5.5, Testing connections with Windows Explorer</a>. Otherwise:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945608">
+</a>If you get "The specified shared directory cannot be found," or "Cannot locate specified share name," the directory name is either misspelled or not in the <EM CLASS="emphasis">
+smb.conf</em> file. This message can also warn of a name in mixed case, including spaces, or is longer than eight characters.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945610">
+</a>If you get "The computer name specified in the network path cannot be located," or "Cannot locate specified computer," the directory name has been misspelled, the name service has failed, there is a networking problem, or the <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> <CODE CLASS="literal">
+=</code> option includes your host.</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945612">
+</a>If it is not a spelling mistake, you need to double back to at least the section <A CLASS="xref" HREF="ch09_02.html#ch09-77154">
+Section 9.2.5.3</a>, to investigate why it doesn't connect.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945617">
+</a>If <EM CLASS="emphasis">
+smbclient</em> does work, it's a name service problem with the client name service, and you need to go forward to the section <A CLASS="xref" HREF="ch09_02.html#ch09-12446">
+Section 9.2.6.2, Testing the server with nmblookup</a>, and see if you can look up both client and server with <EM CLASS="emphasis">
+nmblookup</em>.</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945622">
+</a>If you get "The password is invalid for <CODE CLASS="literal">\</code><CODE CLASS="replaceable"><I>server</i></code><CODE CLASS="literal">\</code><CODE CLASS="replaceable"><I>username</i></code>," your locally cached copy on the client doesn't match the one on the server. You will be prompted for a replacement.</p></li></ul><P CLASS="para">
+Windows 95 and 98 clients keep a local <EM CLASS="emphasis">
+password</em> file, but it's really just a cached copy of the password it sends to Samba and NT servers to authenticate you. That's what is being prompted for here. You can still log on to a Windows machine without a password (but not to NT).</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+If you provide your password, and it still fails, your password is not being matched on the server, you have a <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> or <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> list denying you permission, NetBEUI is interfering, or the encrypted password problem described in the next paragraph exists.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945627">
+</a>If your client is NT 4.0, NT 3.5 with Patch 3, Windows 95 with Patch 3, Windows 98 or any of these with Internet Explorer 4.0, these default to using Microsoft encryption for passwords (discussed in <a href="ch06_01.html"><b>Chapter 6, <CITE CLASS="chapter">Users, Security, and Domains</cite></b></a>'s <a href="ch06_04.html"><b>Section 6.4, Passwords</b> in <b>Chapter 6</b></a> section, along with the alternatives). In general, if you have installed a major Microsoft product recently, you may have applied an update and turned on encrypted passwords.</p></li></ul><P CLASS="para">
+Because of Internet Explorer's willingness to honor URLs such as <I CLASS="filename">
+file://somehost/somefile</i> by making SMB connections, clients up to and including Windows 95 Patch Level 2 would happily send your password, in plaintext, to SMB servers anywhere on the Internet. This was considered a bad idea, and Microsoft quite promptly switched to using only encrypted passwords in the SMB protocol. All subsequent releases of their products have included this correction. Encrypted passwords aren't actually needed unless you're using Internet Explorer 4.0 without a firewall, so it's reasonable to keep using unencrypted passwords on your own networks.</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-953889">
+</a>If you have a mixed-case password on Unix, the client is probably sending it in all one case. If changing your password to all one case works, this was the problem. Regrettably, all but the oldest clients support uppercase passwords, so Samba will try once with it in uppercase and once in lower case. If you wish to use mixed-case passwords, see the <CODE CLASS="literal">
+password</code> <CODE CLASS="literal">
+level</code> option in <a href="ch06_01.html"><b>Chapter 6</b></a> for a workaround.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-953895">
+</a>You may have a <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> problem, as tested with <EM CLASS="emphasis">
+smbclient</em> (see <A CLASS="xref" HREF="ch09_02.html#ch09-77154">
+Section 9.2.5.3</a>).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945642">
+</a>You may have the NetBEUI protocol bound to the Microsoft client. This often produces long timeouts and erratic failures, and is known to have caused failures to accept passwords in the past.</p></li></ul><P CLASS="para">
+The term "bind" is used to mean connecting a piece of software to another in this case. The Microsoft SMB client is "bound to" TCP/IP in the bindings section of the TCP/IP properties panel under the Windows 95/98 Network icon in the Control Panel. TCP/IP in turn is bound to an Ethernet card. This is not the same sense of the word as binding an SMB daemon to a TCP/IP port.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-57065">9.2.5.5 Testing connections with Windows Explorer</a></h4><P CLASS="para">Start Windows Explorer or NT Explorer (not Internet Explorer), select Tools&#8594;Map Network Drive and specify \\<CODE CLASS="replaceable">
+<I>
+server</i></code>\<CODE CLASS="literal">
+temp</code> to see if you can make Explorer connect to the <I CLASS="filename">
+/tmp</i> directory. You should see a screen similar to the one in <A CLASS="xref" HREF="ch09_02.html#ch09-74414">
+Figure 9.3</a>. If so, you've succeeded and can skip to <A CLASS="xref" HREF="ch09_02.html#ch09-23573">
+Section 9.2.6, Troubleshooting Browsing </a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch09-74414">
+Figure 9.3: Accessing the /tmp directory with Windows Explorer</a></h4><IMG CLASS="graphic" SRC="figs/sam.0903.gif" ALT="Figure 9.3"><P CLASS="para">
+A word of caution: Windows Explorer and NT Explorer are rather poor as diagnostic tools: they do tell you that something's wrong, but rarely what it is. If you get a failure, you'll need to track it down with the NET USE command, which has far superior error reporting:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945661">
+</a>If you get "The password for this connection that is in your password file is no longer correct," you may have any of the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945662">
+</a>Your locally cached copy on the client doesn't match the one on the server.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945663">
+</a>You didn't provide a username and password when logging on to the client. Most Explorers will continue to send a username and password of null, even if you provide a password.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945664">
+</a>You have misspelled the password.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945665">
+</a>You have an <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> or <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> list denying permission.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945666">
+</a>Your client is NT 4.0, NT 3.5 with Patch 3, Windows 95 with Patch 3, Windows 98, or any of these with Internet Explorer 4. They will all want encrypted passwords.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945667">
+</a>You have a mixed-case password, which the client is supplying in all one case.</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945669">
+</a>If you get "The network name is either incorrect, or a network to which you do not have full access," or "Cannot locate specified computer," you may have any of the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945671">
+</a> Misspelled name</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945672">
+</a> Malfunctioning service </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945673">
+</a> Failed share</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945674">
+</a> Networking problem</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945675">
+</a> Bad <CODE CLASS="literal">
+path</code> line</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945676">
+</a> <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> line that excludes you</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945677">
+</a>If you get "You must supply a password to make this connection," the password on the client is out of synchronization with the server, or this is the first time you've tried from this client machine and the client hasn't cached it locally yet.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945681">
+</a>If you get "Cannot locate specified share name," you have a wrong share name or a syntax error in specifying it, a share name longer than eight characters, or one containing spaces or in mixed case.</p></li></ul><P CLASS="para">
+Once you can reliably connect to the <CODE CLASS="literal">
+[temp]</code> directory, try once again, this time using your home directory. If you have to change something to get home directories working, then retest with <CODE CLASS="literal">
+[temp]</code>, and vice versa, as we showed in the section <A CLASS="xref" HREF="ch09_02.html#ch09-97081">
+Section 9.2.5.4</a>. As always, if Explorer fails, drop back to that section and debug it there.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-23573">9.2.6 Troubleshooting Browsing </a></h3><P CLASS="para">Finally, we come to browsing. This was left to last, not because it is hardest, but because it's both optional and partially dependent on a protocol that doesn't guarantee delivery of a packet. Browsing is hard to diagnose if you don't already know all the other services are running. </p><P CLASS="para">
+Browsing is purely optional: it's just a way to find the servers on your net and the shares that they provide. Unix has nothing of the sort and happily does without. Browsing also assumes all your machines are on a local area network (LAN) where broadcasts are allowable.</p><P CLASS="para">
+First, the browsing mechanism identifies a machine using the unreliable UDP protocol; then it makes a normal (reliable) TCP/IP connection to list the shares the machine provides.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-96207">
+9.2.6.1 Testing browsing with smbclient </a></h4><P CLASS="para">We'll start with testing the reliable connection first. From the server, try listing its own shares via <EM CLASS="emphasis">
+smbclient</em> with a <CODE CLASS="literal">
+-L</code> option of your server's name. You should get: </p><PRE CLASS="programlisting">server% <CODE CLASS="userinput"><B>smbclient -L server</b></code>
+Added interface ip=192.168.236.86 bcast=192.168.236.255 nmask=255.255.255.0 Server time is Tue Apr 28 09:57:28 1998 Timezone is UTC-4.0
+Password:
+Domain=[EXAMPLE]
+OS=[Unix]
+Server=[Samba 1.9.18]
+Server=[server]
+User=[davecb]
+Workgroup=[EXAMPLE]
+Domain=[EXAMPLE]
+ Sharename Type Comment
+ --------- ---- -------
+ cdrom Disk CD-ROM
+ cl Printer Color Printer 1
+ davecb Disk Home Directories
+
+ This machine has a browse list:
+ Server Comment
+ --------- -------
+ SERVER Samba 1.9.18
+
+ This machine has a workgroup list:
+ Workgroup Master
+ --------- -------
+ EXAMPLE SERVER</pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-950922">
+</a>If you didn't get a Sharename list, the server is not allowing you to browse any shares. This should not be the case if you've tested any of the shares with Windows Explorer or the NET USE command. If you haven't done the <CODE CLASS="literal">
+smbclient</code> <CODE CLASS="literal">
+-L</code> <CODE CLASS="literal">
+localhost</code> <CODE CLASS="literal">
+-U%</code> test yet (see <A CLASS="xref" HREF="ch09_02.html#ch09-40595">
+Section 9.2.5.2</a>), do it now. An erroneous guest account can prevent the shares from being seen. Also, check the <I CLASS="filename">
+smb.conf</i> file to make sure you do not have the option <CODE CLASS="literal">
+browsable</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+no</code> anywhere in it: we suggest a minimal <I CLASS="filename">
+smb.conf</i> file (see <A CLASS="xref" HREF="ch09_02.html#ch09-67928">
+Section 9.2.5.1, A minimal smb.conf file</a>) for you to steal from. You need to have <CODE CLASS="literal">
+browseable</code> enabled in order to be able to see at least the <CODE CLASS="literal">
+[temp]</code> share.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945728">
+</a>If you didn't get a browse list, the server is not providing information about the machines on the network. At least one machine on the net must support browse lists. Make sure you have <CODE CLASS="literal">
+local</code> <CODE CLASS="literal">
+master</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> in the <I CLASS="filename">
+smb.conf</i> file if you want Samba be the local master browser.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945730">
+</a>If you got a browse list but didn't get <EM CLASS="emphasis">
+/tmp</em>, you probably have a <I CLASS="filename">
+smb.conf</i> problem. Go back to <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945734">
+</a>If you didn't get a workgroup list with your workgroup name in it, it is possible that your workgroup is set incorrectly in the <I CLASS="filename">
+smb.conf</i> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945735">
+</a>If you didn't get a workgroup list at all, ensure that <CODE CLASS="literal">
+workgroup</code> <CODE CLASS="literal">
+=EXAMPLE</code> is present in the <I CLASS="filename">
+smb.conf</i> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945736">
+</a>If you get nothing, try once more with the options <CODE CLASS="literal">
+-I</code> <CODE CLASS="replaceable">
+<I>
+ip_address</i></code> <CODE CLASS="literal">
+-n</code> <CODE CLASS="replaceable">
+<I>
+netbios_name</i></code> <CODE CLASS="literal">
+-W</code> <CODE CLASS="replaceable">
+<I>
+workgroup</i></code> <CODE CLASS="literal">
+-d3</code> with the NetBIOS and workgroup name in uppercase. (The <CODE CLASS="literal">
+-d</code> <CODE CLASS="literal">
+3</code> option sets the log /debugging level to 3.)</p></li></ul><P CLASS="para">
+If you're still getting nothing, you shouldn't have gotten this far. Double back to at least <A CLASS="xref" HREF="ch09_02.html#ch09-78512">
+Section 9.2.3.1, Testing TCP with FTP </a>, or perhaps <A CLASS="xref" HREF="ch09_02.html#ch09-84079">
+Section 9.2.2.4</a>. On the other hand:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945746">
+</a>If you get "SMBtconX failed. ERRSRV&nbsp;- ERRaccess," you aren't permitted access to the server. This normally means you have a <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+hosts</code> option that doesn't include the server, or an invalid hosts option that does.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945748">
+</a> If you get "Bad password," then you presumably have one of the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945749">
+</a> An incorrect <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> or <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> line</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945750">
+</a> An incorrect <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> or <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> line</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945751">
+</a> A lowercase password and OS/2 or Windows for Workgroups clients</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945752">
+</a> A missing or invalid guest account</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+Check what your guest account is (see <A CLASS="xref" HREF="ch09_02.html#ch09-40595">
+Section 9.2.5.2</a>) and verify your <I CLASS="filename">
+smb.conf</i> file with <CODE CLASS="literal">
+testparm</code> <CODE CLASS="literal">
+smb.conf</code> <CODE CLASS="replaceable">
+<I>
+your_hostname your_ip_address</i></code> (see <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>) and change or comment out any <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code>, <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code>, <CODE CLASS="literal">
+valid</code> <CODE CLASS="literal">
+users</code> or <CODE CLASS="literal">
+invalid</code> <CODE CLASS="literal">
+users</code> lines.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945761">
+</a>If you get "Connection refused," the <EM CLASS="emphasis">
+smbd</em> server is not running or has crashed. Check that it's up, running, and listening to the network with <EM CLASS="emphasis">
+netstat</em>, see step <A CLASS="xref" HREF="ch09_02.html#ch09-67494">
+Section 9.2.4.5</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-952948">
+</a>If you get "Get_Hostbyname: Unknown host name," you've made a spelling error, there is a mismatch between Unix and NetBIOS hostname, or there is a name service problem. Start nameservice debugging with <A CLASS="xref" HREF="ch09_02.html#ch09-97081">
+Section 9.2.5.4</a>. If this works, suspect a name mismatch and go to step <A CLASS="xref" HREF="ch09_02.html#ch09-35552">
+Section 9.2.10, Troubleshooting NetBIOS Names</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945777">
+</a>If you get "Session request failed," the server refused the connection. This usually indicates an internal error, such as insufficient memory to fork a process.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945778">
+</a>If you get "Your server software is being unfriendly," the initial session request packet received a garbage response from the server. The server may have crashed or started improperly. Go back to <A CLASS="xref" HREF="ch09_02.html#ch09-40595">
+Section 9.2.5.2</a>, where the problem is first analyzed.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945785">
+</a>If you suspect the server is not running, go back to <A CLASS="xref" HREF="ch09_02.html#ch09-49239">
+Section 9.2.4.2, Looking for daemon processes with ps</a> to see why the server daemon isn't responding.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-12446">9.2.6.2 Testing the server with nmblookup</a></h4><P CLASS="para">
+This will test the "advertising" system used for Windows name services and browsing. Advertising works by broadcasting one's presence or willingness to provide services. It is the part of browsing that uses an unreliable protocol (UDP), and works only on broadcast networks like Ethernets. The <EM CLASS="emphasis">
+nmblookup</em> program broadcasts name queries for the hostname you provide, and returns its IP address and the name of the machine, much like <EM CLASS="emphasis">
+nslookup</em> does with DNS. Here, the <CODE CLASS="literal">
+-d</code> (debug- or log-level) option, and the <CODE CLASS="literal">
+-B</code> (broadcast address) options direct queries to specific machines.</p><P CLASS="para">
+First, we check the server from itself. Run <EM CLASS="emphasis">
+nmblookup</em> with a <CODE CLASS="literal">
+-B</code> option of your server's name to tell it to send the query to the Samba server, and a parameter of <CODE CLASS="literal">
+__SAMBA__</code> as the symbolic name to look up. You should get: </p><PRE CLASS="programlisting">server% <B CLASS="emphasis.bold">nmblookup -B </b><CODE CLASS="replaceable"><I>server</i></code> <B CLASS="emphasis.bold">__SAMBA__ </b>
+Added interface ip=192.168.236.86 bcast=192.168.236.255 nmask=255.255.255.0
+Sending queries to 192.168.236.86 192.168.236.86 __SAMBA__ </pre><P CLASS="para">
+You should get the IP address of the server, followed by the name <CODE CLASS="literal">
+__SAMBA__ </code>, which means that the server has successfully advertised that it has a service called <CODE CLASS="literal">
+__SAMBA__ </code>, and therefore at least part of NetBIOS nameservice works.</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945802">
+</a>If you get "Name_query failed to find name __SAMBA__" you may have specified the wrong address to the <CODE CLASS="literal">
+-B</code> option, or <EM CLASS="emphasis">
+nmbd</em> is not running. The <CODE CLASS="literal">
+-B</code> option actually takes a broadcast address: we're using a machine-name to get a unicast address, and to ask server if it has claimed <CODE CLASS="literal">
+__SAMBA__</code>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947471">
+</a>Try again with <CODE CLASS="literal">
+-B</code><CODE CLASS="replaceable">
+<I>
+ ip_address</i></code>, and if that fails too, <EM CLASS="emphasis">
+nmbd</em> isn't claiming the name. Go back briefly to "Testing daemons with testparm" to see if <EM CLASS="emphasis">
+nmbd</em> is running. If so, it may not claiming names; this means that Samba is not providing the browsing service&nbsp;- a configuratiuon problem. If that is the case, make sure that <I CLASS="filename">
+smb.conf</i> doesn't contain the option <CODE CLASS="literal">
+browsing</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+no</code>.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-32122">
+9.2.6.3 Testing the client with nmblookup</a></h4><P CLASS="para">
+Next, check the IP address of the client from the server with <EM CLASS="emphasis">
+nmblookup</em> using <CODE CLASS="literal">
+-B</code> option for the client's name and a parameter of <CODE CLASS="literal">
+'*'</code> meaning "anything," as shown here: </p><PRE CLASS="programlisting">server% <B CLASS="emphasis.bold">nmblookup -B client '*'</b>
+Sending queries to 192.168.236.10 192.168.236.10 *
+Got a positive name query response from 192.168.236.10 (192.168.236.10)</pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945817">
+</a>If you receive "Name-query failed to find name *," you have made a spelling mistake, or the client software on the PC isn't installed, started, or bound to TCP/IP. Double back to <a href="ch02_01.html"><b>Chapter 2</b></a> or <a href="ch03_01.html"><b>Chapter 3</b></a> and ensure you have a client installed and listening to the network. </p></li></ul><P CLASS="para">
+Repeat the command with the following options if you had any failures:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945824">
+</a>If <CODE CLASS="literal">
+nmblookup</code> <CODE CLASS="literal">
+-B</code> <CODE CLASS="replaceable">
+<I>
+client_IP_address</i></code> succeeds but <CODE CLASS="literal">
+-B</code> <CODE CLASS="replaceable">
+<I>
+client_name</i></code> fails, there is a name service problem with the client's name; go to <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945825">
+</a>If <CODE CLASS="literal">
+nmblookup</code> <CODE CLASS="literal">
+-B</code> <CODE CLASS="literal">
+127.0.0.1'*'</code> succeeds, but <CODE CLASS="literal">
+-B</code> <CODE CLASS="replaceable">
+<I>
+client_IP_address</i></code> fails, there is a hardware problem and ping should have failed. See your network manager. </p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-98123">
+9.2.6.4 Testing the network with nmblookup</a></h4><P CLASS="para">
+Run the command <EM CLASS="emphasis">
+nmblookup</em> again with a <CODE CLASS="literal">
+-d</code> option (debug level) of 2 and a parameter of <CODE CLASS="literal">
+'*'</code> again. This time we are testing the ability of programs (such as <EM CLASS="emphasis">
+nmbd </em>) to use broadcast. It's essentially a connectivity test, done via a broadcast to the default broadcast address. </p><P CLASS="para">
+A number of NetBIOS/TCP-IP hosts on the network should respond with "got a positive name query response" messages. Samba may not catch all of the responses in the short time it listens, so you won't always see all the SMB clients on the network. However, you should see most of them:</p><PRE CLASS="programlisting">server% <B CLASS="emphasis.bold">nmblookup -d 2 '*' </b>
+Added interface ip=192.168.236.86 bcast=192.168.236.255 nmask=255.255.255.0 Sending queries to 192.168.236.255
+Got a positive name query response from 192.168.236.191 (192.168.236.191)
+Got a positive name query response from 192.168.236.228 (192.168.236.228)
+Got a positive name query response from 192.168.236.75 (192.168.236.75)
+Got a positive name query response from 192.168.236.79 (192.168.236.79)
+Got a positive name query response from 192.168.236.206 (192.168.236.206)
+Got a positive name query response from 192.168.236.207 (192.168.236.207)
+Got a positive name query response from 192.168.236.217 (192.168.236.217)
+Got a positive name query response from 192.168.236.72 (192.168.236.72) 192.168.236.86 * </pre><P CLASS="para">
+However:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945841">
+</a>If this doesn't give at least the client address you previously tested, the default broadcast address is wrong. Try <CODE CLASS="literal">
+nmblookup</code> <CODE CLASS="literal">
+-B</code> <CODE CLASS="literal">
+255.255.255.255</code> <CODE CLASS="literal">
+-d</code> <CODE CLASS="literal">
+2</code> <CODE CLASS="literal">
+'*'</code>, which is a last-ditch variant (a broadcast address of all ones). If this draws responses, the broadcast address you've been using before is wrong. Troubleshooting these is discussed in the <A CLASS="xref" HREF="ch09_02.html#ch09-45060">
+Section 9.2.9.2, Broadcast addresses</a> section, later in this chapter.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-951306">
+</a>If the address 255.255.255.255 fails too, check your notes to see if your PC and server are on different subnets, as discovered in <A CLASS="xref" HREF="ch09_02.html#ch09-84079">
+Section 9.2.2.4</a>. You should try to diagnose this with a server and client on the same subnet, but if you can't, you can try specifying the remote subnet's broadcast address with <CODE CLASS="literal">
+-B</code>. Finding that address is discussed in the same place as troubleshooting broadcast addresses, in the section <A CLASS="xref" HREF="ch09_02.html#ch09-45060">
+Section 9.2.9.2</a>, later in this chapter. The <CODE CLASS="literal">
+-B</code> option will work if your router supports directed broadcasts; if it doesn't, you may be forced to test with a client on the same network.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-947520">
+9.2.6.5 Testing client browsing with net view</a></h4><P CLASS="para">On the client, run the command <CODE CLASS="replaceable"><I>net view \\server</i></code> in a DOS window to see if you can connect to the client and ask what shares it provides. You should get back a list of available shares on the server, as shown in <A CLASS="xref" HREF="ch09_02.html#ch09-83710">
+Figure 9.4</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch09-83710">
+Figure 9.4: Using the net view command</a></h4><IMG CLASS="graphic" SRC="figs/sam.0904.gif" ALT="Figure 9.4"><P CLASS="para">
+If you received this, continue with the section <A CLASS="xref" HREF="ch09_02.html#ch09-21713">
+Section 9.2.7, Other Things that Fail</a>.</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-953009">
+</a>If you get "Network name not found" for the name you just tested in the section <A CLASS="xref" HREF="ch09_02.html#ch09-32122">
+Section 9.2.6.3, Testing the client with nmblookup</a>, there is a problem with the client software itself. Double-check this by running <EM CLASS="emphasis">
+nmblookup</em> on the client; if it works and NET VIEW doesn't, the client is at fault.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945868">
+</a>Of course, if <EM CLASS="emphasis">
+nmblookup</em> fails, there is a NetBIOS nameservice problem, as discussed in the section <A CLASS="xref" HREF="ch09_02.html#ch09-35552">
+Section 9.2.10</a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945874">
+</a>If you get "You do not have the necessary access rights," or "This server is not configured to list shared resources," either your guest account is misconfigured (see <A CLASS="xref" HREF="ch09_02.html#ch09-40595">
+Section 9.2.5.2</a>), or you have a <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+allow</code> or <CODE CLASS="literal">
+hosts</code> <CODE CLASS="literal">
+deny</code> line that prohibits connections from your machine. These problems should have been detected by the <EM CLASS="emphasis">
+smbclient</em> tests starting in the section <A CLASS="xref" HREF="ch09_02.html#ch09-96207">
+Section 9.2.6.1, Testing browsing with smbclient </a>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945882">
+</a>If you get "The specified computer is not receiving requests," you have misspelled the name, the machine is unreachable by broadcast (tested in "Testing the network with nmblookup"), or it's not running <EM CLASS="emphasis">
+nmbd</em>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-954090">
+</a>If you get "Bad password error," you're probably encountering the Microsoft-encrypted password problem, as discussed in <a href="ch06_01.html"><b>Chapter 6</b></a>, with its corrections.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-954094">
+9.2.6.6 Browsing the server from the client</a></h4><P CLASS="para">From the Network Neighborhood (File Manager in older releases), try to browse the server. Your Samba server should appear in the browse list of your local workgroup. You should be able to double click on the name of the server and get a list of shares, as illustrated in <A CLASS="xref" HREF="ch09_02.html#ch09-60004">
+Figure 9.5</a>. </p><H4 CLASS="figure">
+<A CLASS="title" NAME="ch09-60004">
+Figure 9.5: List of shares on a server</a></h4><IMG CLASS="graphic" SRC="figs/sam.0905.gif" ALT="Figure 9.5"><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945897">
+</a>If you get an "Invalid password" error with NT 4.0, NT 3.5 with Patch 3, Windows 95 with Patch 3, Windows 98 or any of these with Internet Explorer 4.0, it's most likely the encryption problem again. All of these clients default to using Microsoft encryption for passwords (see <a href="ch06_01.html"><b>Chapter 6</b></a>).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945903">
+</a>If you receive an "Unable to browse the network" error, one of the following has ocurred:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945904">
+</a>You have looked too soon, before the broadcasts and updates have completed; try waiting 30 seconds before re-attempting.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945905">
+</a>There is a network problem you've not yet diagnosed.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945906">
+</a>There is no browse master. Add the configuration option <CODE CLASS="literal">
+local</code> <CODE CLASS="literal">
+master</code> <CODE CLASS="literal">
+=</code> <CODE CLASS="literal">
+yes</code> to your <EM CLASS="emphasis">
+smb.conf</em> file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945907">
+</a>No shares are marked <CODE CLASS="literal">
+browsable</code> in the <EM CLASS="emphasis">
+smb.conf</em> file.</p></li></ul></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945909">
+</a>If you receive the message "\\server is not accessible," then:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945910">
+</a> You have the encrypted password problem</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945911">
+</a> The machine really isn't accessible </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945912">
+</a> The machine doesn't support browsing</p></li></ul></li></ul></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-21713">9.2.7 Other Things that Fail </a></h3><P CLASS="para">
+If you've made it here, either the problem is solved or it's not one we've seen. The next sections cover troubleshooting tasks that are required to have the infrastructure to run Samba, not Samba itself.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945916">
+9.2.7.1 Not logging on</a></h4><P CLASS="para">An occasional problem is forgetting to log in to the client or logging in as a wrong (account-less) person. The former is not diagnosed at all: Windows tries to be friendly and lets you on. Locally! The only warning of the latter is that Windows welcomes you and asks about your new account. Either of these leads to repeated refusals to connect and endless requests for passwords. If nothing else seems to work, try logging out or shutting down and logging in again.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-23768">
+9.2.8 Troubleshooting Name Services</a></h3><P CLASS="para">This section looks at simple troubleshooting of all the name services that you will encounter, but only for the common problems that affect Samba.</p><P CLASS="para">
+There are several good references for troubleshooting particular name services: Paul Albitz and Cricket Liu's <EM CLASS="emphasis">
+DNS and Bind</em> covers the Domain Name Service (DNS), Hal Stern's <EM CLASS="emphasis">
+NFS and NIS</em> (both from O'Reilly) covers NIS ("Yellow pages") while WINS (Windows Internet Name Service), <I CLASS="filename">
+hosts/LMHOSTS</i> files and NIS+ are best covered by their respective vendor's manuals.</p><P CLASS="para">
+The problems addressed in this section are:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945926">
+</a>Identifying name services</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945927">
+</a>A hostname can't be looked up</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945928">
+</a>The long (FQDN) form of a hostname works but the short form doesn't </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945929">
+</a>The short form of the name works, but the long form doesn't</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945930">
+</a>A long delay ocurrs before the expected result </p></li></ul><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-945931">
+9.2.8.1 Identifying what's in use</a></h4><P CLASS="para">First, see if both the server and the client are using DNS, WINS, NIS, or <I CLASS="filename">
+hosts</i> files to look up IP addresses when you give them a name. Each kind of machine will have a different preference: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945934">
+</a>Windows 95 and 98 machines will look in WINS and <I CLASS="filename">
+LMHOSTS</i> files first, then broadcast, and finally try DNS and <I CLASS="filename">
+hosts</i> files.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945935">
+</a>NT will look in WINS, then broadcast, LMHOSTS files, and finally <I CLASS="filename">
+hosts</i> and DNS.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945936">
+</a>Windows programs using the WINSOCK standard (like PC-NFSs) will use hosts files, DNS, WINS, and then broadcast. Don't assume that if a different program's name service works, the SMB client program's name service will!</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945937">
+</a>Samba daemons will use <I CLASS="filename">
+LMHOSTS</i>, WINS, the Unix host's preference, and then broadcast.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945938">
+</a>Unix hosts can be configured to use any combination of DNS, <I CLASS="filename">
+hosts</i> files, and NIS and NIS+, generally in any order.</p></li></ul><P CLASS="para">
+We recommend that the client machines be configured to use WINS and DNS, the Samba daemons to use WINS and DNS, and the Unix server to use DNS. You'll have to look at your notes and the actual machines to see which is in use.</p><P CLASS="para">
+On the clients, the name services are all set in the TCP/IP Properties panel of the Networking Control Panel, as discussed in <a href="ch03_01.html"><b>Chapter 3</b></a>. You may need to check there to see what you've actually turned on. On the server, see if an <I CLASS="filename">
+/etc/resolv.conf</i> file exists. If it does, you're using DNS. You may be using the others as well, though. You'll need to check for NIS and combinations of services.</p><P CLASS="para">
+Check for an <I CLASS="filename">
+/etc/nsswitch.conf</i> file on Solaris and other System V Unix operating systems. If you have one, look for a line that begins <CODE CLASS="literal">
+host</code>:, followed by one or more of <CODE CLASS="literal">
+files</code>, <CODE CLASS="literal">
+bind</code>, <CODE CLASS="literal">
+nis</code> or <CODE CLASS="literal">
+nis+</code>. These are the name services to use, in order, with optional extra material in square brackets. <EM CLASS="emphasis">
+files</em> stands for using<EM CLASS="emphasis">
+ hosts</em> files, while <EM CLASS="emphasis">
+bind</em> (the Berkeley Internet Name Daemon) stands for using DNS.</p><P CLASS="para">
+If the client and server differ, the first thing to do is to get them in sync. Clients can only use only DNS, WINS, <EM CLASS="emphasis">
+hosts </em>files and <EM CLASS="emphasis">
+lmhosts</em> files, not NIS or NIS+. Servers can use <EM CLASS="emphasis">
+hosts</em> files, DNS, and NIS or NIS+, but not WINS&nbsp;- even if your Samba server provides WINS services. If you can't get all the systems to use the same services, you'll have to carefully check the server and the client for the same data.</p><P CLASS="para">
+Samba 2.0 (and late 1.9 versions) added a <CODE CLASS="literal">
+-R</code><I CLASS="option">
+ </i>(resolve order) option to <EM CLASS="emphasis">
+smbclient</em>. If you want to troubleshoot WINS, for example, you'd say:</p><PRE CLASS="programlisting"> smbclient -L <CODE CLASS="replaceable"><I>server</i></code> -R wins</pre><P CLASS="para">
+The possible settings are <CODE CLASS="literal">
+hosts</code> (which means whatever the Unix machine is using, not just<I CLASS="filename">
+ /etc/hosts</i> files), <CODE CLASS="literal">
+lmhosts</code>, <CODE CLASS="literal">
+wins</code> and <CODE CLASS="literal">
+bcast</code> (broadcast).</p><P CLASS="para">
+In the following sections, we use the term <EM CLASS="emphasis">
+long name</em> for a fully-qualified domain name (FQDN), like <CODE CLASS="literal">
+server.example.com</code>, and the term <EM CLASS="emphasis">
+short name</em> for the host part of a FQDN, like <CODE CLASS="literal">
+server</code>.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-947590">
+9.2.8.2 Cannot look up hostnames</a></h4><P CLASS="para">
+ Try the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945950">
+</a>In DNS:</p><P CLASS="para">
+Run <CODE CLASS="literal">
+nslookup</code> <CODE CLASS="replaceable">
+<I>
+name</i></code>. If this fails, look for a <I CLASS="filename">
+resolv.conf</i> error, a downed DNS server, or a short/long name problem (see the next section). Try the following:</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945952">
+</a>Your <I CLASS="filename">
+/etc/resolv.conf</i> should contain one or more name-server lines, each with an IP address. These are the addresses of your DNS servers.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947597">
+</a>ping each of the server addresses you find. If this fails for one, suspect the machine. If it fails for each, suspect your network.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947600">
+</a>Retry the lookup using the full domain name (e.g., <EM CLASS="emphasis">
+server.example.com</em>) if you tried the short name first, or the short name if you tried the long name first. If results differ, skip to the next section. </p></li></ul><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945958">
+</a>In Broadcast/ WINS:</p><P CLASS="para">
+Broadcast/ WINS does only short names such as <CODE CLASS="literal">
+server</code>, (not long ones, such as <CODE CLASS="literal">
+server.example.com)</code>. Run <CODE CLASS="literal">
+nmblookup</code> <CODE CLASS="literal">
+-S</code> <CODE CLASS="replaceable">
+<I>
+server</i></code>.<CODE CLASS="replaceable">
+<I>
+ </i></code>This reports everything broadcast has registered for the name. In our example, it looks like this:</p></li></ul><PRE CLASS="programlisting">
+Looking up status of 192.168.236.86
+received 10 names
+ SERVER &lt;00&gt; - M &lt;ACTIVE&gt;
+ SERVER &lt;03&gt; - M &lt;ACTIVE&gt;
+ SERVER &lt;1f&gt; - M &lt;ACTIVE&gt;
+ SERVER &lt;20&gt; - M &lt;ACTIVE&gt;
+ ..__MSBROWSE__. &lt;01&gt; - &lt;GROUP&gt; M &lt;ACTIVE&gt;
+ MYGROUP &lt;00&gt; - &lt;GROUP&gt; M &lt;ACTIVE&gt;
+ MYGROUP &lt;1b&gt; - M &lt;ACTIVE&gt;
+ MYGROUP &lt;1c&gt; - &lt;GROUP&gt; M &lt;ACTIVE&gt;
+ MYGROUP &lt;1d&gt; - M &lt;ACTIVE&gt;
+ MYGROUP &lt;1e&gt; - &lt;GROUP&gt; M &lt;ACTIVE&gt;</pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+The required entry is <CODE CLASS="literal">
+SERVER</code> <CODE CLASS="literal">
+&lt;00&gt;</code>, which identifies <CODE CLASS="replaceable">
+<I>
+server</i></code> as being this machine's NetBIOS name. You should also see your workgroup mentioned one or more times. If these lines are missing, Broadcast/WINS cannot look up names and will need attention.</p></li></ul><P CLASS="para">
+The numbers in angle brackets in the previous output identify NetBIOS names as being workgroups, workstations, and file users of the messenger service, master browsers, domain master browsers, domain controllers and a plethora of others. We primarily use <CODE CLASS="literal">
+&lt;00&gt;</code> to identify machine and workgroup names and <CODE CLASS="literal">
+&lt;20&gt;</code> to identify machines as servers. The complete list is available at <A CLASS="systemitem.url" HREF="http://support.microsoft.com/support/kb/articles/q163/4/09.asp">
+http://support.microsoft.com/support/kb/articles/q163/4/09.asp</a>.</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945982">
+</a>In NIS:</p><P CLASS="para">
+Try <CODE CLASS="literal">
+ypmatch</code> <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+hosts</code>. If this fails, NIS is down. Find out the NIS server's name by running<EM CLASS="emphasis">
+ ypwhich</em>, and ping the machine it to see if it's accessible.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945985">
+</a>In NIS+:</p><P CLASS="para">
+If you're running NIS+, try <CODE CLASS="literal">
+nismatch</code> <CODE CLASS="literal">
+name</code> <CODE CLASS="literal">
+hosts</code>. If this fails, NIS is down. Find out the NIS server's name by running <EM CLASS="emphasis">
+niswhich</em>, and ping that machine to see if it's accessible.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-945988">
+</a>In <I CLASS="filename">
+hosts</i> files:</p><P CLASS="para">
+Inspect <I CLASS="filename">
+/etc/hosts</i> on the client (<CODE CLASS="literal">C:\WINDOWS\HOSTS</code>). Each line should have an IP number and one or more names, the primary name first, then any optional aliases. An example follows:</p></li></ul><PRE CLASS="programlisting">
+ 127.0.0.1 localhost
+ 192.168.236.1 dns.svc.example.com
+ 192.168.236.10 client.example.com client
+ 192.168.236.11 backup.example.com loghost
+ 192.168.236.86 server.example.com server
+ 192.168.236.254 router.svc.example.com </pre><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+On Unix, <CODE CLASS="literal">
+localhost</code> should always be 127.0.0.1, although it may be just an alias for a hostname on the PC. On the client, check that there are no <CODE CLASS="literal">
+#XXX</code> directives at the ends of the lines; these are LAN Manager/NetBIOS directives, and should appear only in <EM CLASS="emphasis">
+LMHOSTS</em> files (<CODE CLASS="literal">C:\WINDOWS\LMHOSTS</code>). </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946000">
+</a>In <EM CLASS="emphasis">
+LMHOSTS</em> files:</p><P CLASS="para">
+This file is a local source for LAN Manager (NetBIOS) names. It has a format very similar to <I CLASS="filename">
+/etc/hosts</i> files, but does not support long-form domain names (e.g., <CODE CLASS="literal">
+server.example.com</code>), and may have a number of optional <CODE CLASS="literal">
+#XXX</code> directives following the names. Note there usually is a <EM CLASS="emphasis">
+lmhosts.sam</em> (for sample) file in <CODE CLASS="literal">
+C:\WINDOWS</code>, but it's not used unless renamed to <CODE CLASS="literal">
+C:\WINDOWS\LMHOSTS</code>.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946005">
+9.2.8.3 Long and short hostnames</a></h4><P CLASS="para">Where the long (FQDN) form of a hostname works but the short name doesn't (for example, <CODE CLASS="literal">
+client.example.com</code> works but <CODE CLASS="literal">
+client</code> doesn't), consider the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946007">
+</a>DNS: </p><P CLASS="para">
+This usually indicates there is no default domain in which to look up the short names. Look for a <CODE CLASS="literal">
+default</code> line in <I CLASS="filename">
+/etc/resolv.conf</i> on the Samba server with your domain in it, or a <CODE CLASS="literal">
+search</code> line with one or more domains in it. One or the other may need to be present to make short names usable; which one depends on vendor and version of the DNS resolver. Try adding <CODE CLASS="literal">
+domain</code> <CODE CLASS="replaceable">
+<I>
+your domain</i></code> to <I CLASS="filename">
+resolv.conf</i> and ask your network or DNS administrator what should have been in the file.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946010">
+</a>Broadcast/WINS: </p><P CLASS="para">
+Broadcast/WINS doesn't support long names; it won't suffer from this problem. </p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946012">
+</a>NIS: </p><P CLASS="para">
+Try the command <CODE CLASS="literal">
+ypmatch</code> <CODE CLASS="literal">
+hostname</code> <CODE CLASS="literal">
+hosts</code>. If you don't get a match, your tables don't include short names. Speak to your network manager; short names may be missing by accident, or may be unsupported as a matter of policy. Some sites don't ever use (ambiguous) short names.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946014">
+</a>NIS+ :</p><P CLASS="para">
+Try <CODE CLASS="literal">
+nismatch</code> <CODE CLASS="replaceable">
+<I>
+hostname</i></code> <CODE CLASS="literal">
+hosts</code>, and treat failure exactly as with NIS above.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946016">
+</a><EM CLASS="emphasis">
+hosts:</em> </p><P CLASS="para">
+If the short name is not in <I CLASS="filename">
+/etc/hosts</i>, consider adding it as an alias. Avoid, if you can, short names as primary names (the first one on a line). Have them as aliases if your system permits.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946018">
+</a><I CLASS="filename">
+LMHOSTS</i>: </p><P CLASS="para">
+LAN Manager doesn't support long names, so it won't suffer from this problem. </p></li></ul><P CLASS="para">
+On the other hand, if the short form of the name works and the long doesn't, consider the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946022">
+</a>DNS: </p><P CLASS="para">
+This is bizarre; see your network or DNS administrator, as this is probably a DNS setup bug.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947697">
+</a>Broadcast/WINS: </p><P CLASS="para">
+This is a normal bug; Broadcast/WINS can't use the long form. Optionally, consider DNS. Microsoft has stated that they will switch to DNS, though it's not providing name types like &lt;00&gt;.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947709">
+</a>NIS:</p><P CLASS="para">
+If you can use <CODE CLASS="literal">
+ypmatch</code> to look up the short form but not the long, consider adding the long form to the table as at least an alias.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947718">
+</a>NIS+: </p><P CLASS="para">
+Same as NIS, except you use <CODE CLASS="literal">
+nismatch</code> instead of <CODE CLASS="literal">
+ypmatch</code> to look up names.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947720">
+</a><I CLASS="filename">
+hosts:</i></p><P CLASS="para">
+Add the long name as at least an alias, and preferably as the primary form. Also consider using DNS if it's practical.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947727">
+</a><I CLASS="filename">
+LMHOSTS</i>: </p><P CLASS="para">
+This is a normal bug. LAN Manager can't use the long form; consider switching to DNS or <I CLASS="filename">
+hosts</i>.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946040">
+9.2.8.4 Unusual delays</a></h4><P CLASS="para">When there is a long delay before the expected result: </p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-947733">
+</a>DNS: </p><P CLASS="para">
+Test the same name with the <KBD CLASS="command">
+nslookup</kbd> command on the machine (client or server) that is slow. If <KBD CLASS="command">
+nslookup</kbd> is also slow, you have a DNS problem. If it's slower on a client, you have too many protocols bound to the Ethernet card. Eliminate NetBEUI, which is infamously slow, and optionally, Novel, assuming you don't need them. This is especially important on Windows 95, which is particularly sensitive to excess protocols.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946044">
+</a>Broadcast/ WINS:</p><P CLASS="para">
+Test the client using <CODE CLASS="literal">
+nmblookup</code>, and if it's faster, you probably have the protocols problem as mentioned in the previous item.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946047">
+</a>NIS:</p><P CLASS="para">
+Try <CODE CLASS="literal">
+ypmatch</code>, and if it's slow, report the problem to your network manager.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946049">
+</a>NIS+: </p><P CLASS="para">
+Try <CODE CLASS="literal">
+nismatch</code>, similarly.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946051">
+</a><EM CLASS="emphasis">
+hosts</em>:</p><P CLASS="para">
+<EM CLASS="emphasis">
+hosts</em> files, if of reasonable size, are always fast. You probably have the protocols problem mentioned under DNS, above.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946053">
+</a><EM CLASS="emphasis">
+LMHOSTS</em>:</p><P CLASS="para">
+This is not a name lookup problem; <EM CLASS="emphasis">
+LMHOSTS</em> files are as fast as <EM CLASS="emphasis">
+hosts</em> files.</p></li></ul></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946055">
+9.2.8.5 Localhost issues</a></h4><P CLASS="para">When a localhost isn't 127.0.0.1, try the following:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946056">
+</a>DNS:</p><P CLASS="para">
+There is probably no record for <CODE CLASS="literal">
+localhost.</code> <CODE CLASS="literal">
+A</code> <CODE CLASS="literal">
+127.0.0.1</code>. Arrange to add one, and a reverse entry, <CODE CLASS="literal">
+1.0.0.127.IN-ADDR.ARPA</code> <CODE CLASS="literal">
+PTR</code> <CODE CLASS="literal">
+127.0.0.1</code>.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946058">
+</a>Broadcast/WINS:</p><P CLASS="para">
+Not applicable.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946060">
+</a>NIS:</p><P CLASS="para">
+If <CODE CLASS="literal">
+localhost</code> isn't in the table, add it.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946062">
+</a>NIS+: </p><P CLASS="para">
+If <CODE CLASS="literal">
+localhost</code> isn't in the table, add it.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946064">
+</a><I CLASS="filename">
+hosts:</i></p><P CLASS="para">
+Add a line is the <EM CLASS="emphasis">
+hosts</em> file that says <CODE CLASS="literal">
+127.0.0.1</code> <CODE CLASS="literal">
+localhost</code></p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946066">
+</a><I CLASS="filename">
+LMHOSTS</i>:</p><P CLASS="para">
+Not applicable.</p></li></ul></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-953970">9.2.9 Troubleshooting Network Addresses</a></h3><P CLASS="para">
+A number of common problems are caused by incorrect Internet address routing or the incorrect assignment of addresses. This section helps you determine what your addresses are.</p><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-21203">
+9.2.9.1 Netmasks</a></h4><P CLASS="para">The netmasks tell each machine which addresses can be reached directly (are on your local network) and which addresses require forwarding packets through a router. If the netmask is wrong, the machines will make one of two mistakes. One is to try to route local packets via a router, which is an expensive way to waste time&nbsp;- it may work reasonably fast, it may run slowly, or it may fail utterly. The second mistake is to fail to send packets for a remote machine to the router, which will prevent them from being forwarded to the remote machine.</p><P CLASS="para">
+The netmask is a number like an IP address, with one-bits for the network part of an address and zero-bits for the host portion. The netmask is literally used to mask off parts of the address inside the TCP/IP code. If the mask is 255.255.0.0, the first 2 bytes are the network part and the last 2 are the host part. More common is 255.255.255.0, in which the first 3 bytes are the network part and the last one is the host part.</p><P CLASS="para">
+For example, let's say your IP address is 192.168.0.10 and the Samba server is 192.168.236.86. If your netmask happens to be 255.255.255.0, the network part of the addresses is the first 3 bytes and the host part is the last byte. In this case, the network parts are different, and the machines are on different networks: </p><TABLE CLASS="informaltable" BORDER="1" CELLPADDING="3">
+<THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Part</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Host Part</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168 000</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+10</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168 235</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+86</p></td></tr></tbody></table><P CLASS="para">
+If your netmask happens to be 255.255.0.0, the network part is just the first two bytes. In this case, the network parts match and so the two machines are on the same network: </p><TABLE CLASS="informaltable" BORDER="1" CELLPADDING="3">
+<THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Part</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Host Part</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+000 10</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+236 86</p></td></tr></tbody></table><P CLASS="para">
+Of course, if your netmask says one thing and your network manager says another, the netmask is wrong.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-45060">
+9.2.9.2 Broadcast addresses</a></h4><P CLASS="para">
+The broadcast address is a normal address, with the hosts part all one-bits. It means "all hosts on your network." You can compute it easily from your netmask and address: take the address and put one-bits in it for all the bits that are zero at the end of the netmask (the host part). The following table illustrates this: </p><TABLE CLASS="informaltable" BORDER="1" CELLPADDING="3">
+<THEAD CLASS="thead">
+<TR CLASS="row" VALIGN="TOP">
+<TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Network Part</p></th><TH CLASS="entry" ALIGN="LEFT" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+Host Part</p></th></tr></thead><TBODY CLASS="tbody">
+<TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+IP address</b></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168 236</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+86</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+Netmask</b></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+255 255 255</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+000</p></td></tr><TR CLASS="row" VALIGN="TOP">
+<TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+<B CLASS="emphasis.bold">
+Broadcast</b></p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+192 168 236</p></td><TD CLASS="entry" ROWSPAN="1" COLSPAN="1">
+<P CLASS="para">
+255</p></td></tr></tbody></table><P CLASS="para">
+In this example, the broadcast address on the 192.168.236 network is 192.168.236.255. There is also an old "universal" broadcast address, 255.255.255.255. Routers are prohibited from forwarding these, but most machines on your local network will respond to broadcasts to this address.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-946136">
+9.2.9.3 Network address ranges</a></h4><P CLASS="para">A number of address ranges have been reserved for testing and for non-connected networks; we use one of these for the book. If you don't have an address yet, feel free to use one of these to start with. They include one class A (large) network, 10.*.*.*, and 254 class C (smaller) networks, 192.168.1.* through to 192.168.254.*. In this book we use one of the latter, 192.168.236.*. The domain <I CLASS="filename">
+example.com</i> is also reserved for unconnected networks, explanatory examples, and books.</p><P CLASS="para">
+If you're actually connecting to the Internet, you'll need to get a real network and a domain name, probably through the same company that provides your connection.</p></div><DIV CLASS="sect3">
+<H4 CLASS="sect3">
+<A CLASS="title" NAME="ch09-pgfId-947786">
+9.2.9.4 Finding your network address</a></h4><P CLASS="para">If you haven't recorded your IP address, it will be displayed by the <KBD CLASS="command">
+ifconfig</kbd> command on Unix or by the IPCONFIG command on Windows 95 and NT. (Check your manual pages for any options required by your brand of Unix: Sun wants <CODE CLASS="literal">
+ifconfig</code> <CODE CLASS="literal">
+-a</code>). You should see output similar to the following:</p><PRE CLASS="programlisting">
+server% ifconfig -a
+le0: flags=63&lt;UP,BROADCAST,NOTRAILERS,RUNNING &gt;
+ inet 192.168.236.11 netmask ffffff00 broadcast 192.168.236.255
+lo0: flags=49&lt;&amp;lt&gt;UP,LOOPBACK,RUNNING&lt;&amp;gt&gt;
+ inet 127.0.0.1 netmask ff000000</pre><P CLASS="para">
+One of the interfaces will be loopback (in our examples <CODE CLASS="literal">
+lo0</code>), and the other will be the regular IP interface. The flags should show that the interface is running, and Ethernet interfaces will also say they support broadcasts (PPP interfaces don't). The other places to look for IP addresses are <I CLASS="filename">
+/etc/hosts</i> files, Windows <EM CLASS="emphasis">
+HOSTS</em> files, Windows <EM CLASS="emphasis">
+LMHOSTS</em> files, NIS, NIS+ and DNS.</p></div></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-35552">9.2.10 Troubleshooting NetBIOS Names</a></h3><P CLASS="para">Historically, SMB protocols have depended on the NetBIOS name system, also called the LAN Manager name system. This was a simple scheme where each machine had a unique 20-character name and broadcast it on the LAN for everyone to know. With TCP/IP, we tend to use names like <EM CLASS="emphasis">
+client.example.com</em> stored in <I CLASS="filename">
+/etc/hosts</i> files, through DNS or WINS.</p><P CLASS="para">
+The usual mapping to domain names such as <EM CLASS="emphasis">
+server.example.com</em> simply uses the <EM CLASS="emphasis">
+server</em> part as the NetBIOS name and converts it to uppercase. Alas, this doesn't always work, especially if you have a machine with a 21-character name; not everyone uses the same NetBIOS and DNS names. For example, <EM CLASS="emphasis">
+corpvm1</em> along with <EM CLASS="emphasis">
+vm1.corp.com</em> is not unusual.</p><P CLASS="para">
+A machine with a different NetBIOS name and domain name is confusing when you're troubleshooting; we recommend that you try to avoid this wherever possible. NetBIOS names are discoverable with <EM CLASS="emphasis">
+smbclient </em>:</p><UL CLASS="itemizedlist">
+<LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946160">
+</a>If you can list shares on your Samba server with <EM CLASS="emphasis">
+smbclient</em> and a <CODE CLASS="literal">
+-L</code> option (list shares) of <CODE CLASS="replaceable">
+<I>
+short_name_of_server</i></code>, the short name is the NetBIOS name.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946161">
+</a>If you get "Get_Hostbyname: Unknown host name," there is probably a mismatch. Check in the <I CLASS="filename">
+smb.conf</i> file to see if the NetBIOS name is explicitly set.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946162">
+</a>Try again, specifying <CODE CLASS="literal">
+-I</code> and the IP address of the Samba server (e.g., <CODE CLASS="literal">
+smbclient</code> <CODE CLASS="literal">
+-L</code> <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+-I</code> <CODE CLASS="literal">
+192.168.236.86</code>). This overrides the name lookup and forces the packets to go to the IP address. If this works, there was a mismatch.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946163">
+</a>Try with <CODE CLASS="literal">
+-I</code> and the full domain name of the server (e.g., <CODE CLASS="literal">
+smbclient</code> <CODE CLASS="literal">
+-L</code> <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+-I</code> <CODE CLASS="literal">
+server.example.com</code>). This tests the lookup of the domain name, using whatever scheme the Samba server uses (e.g., DNS). If it fails, you have a name service problem. You should reread the section <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8</a> after you finish troubleshooting the NetBIOS names.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946168">
+</a>Try with <CODE CLASS="literal">
+-n</code> (NetBIOS name) and the name you expect to work (e.g., <CODE CLASS="literal">
+smbclient</code> <CODE CLASS="literal">
+-n</code> <CODE CLASS="literal">
+server</code> <CODE CLASS="literal">
+-L</code> <CODE CLASS="literal">
+server-12</code>) but without overriding the IP address through <CODE CLASS="literal">
+-I</code>. If this works, the name you specified with <CODE CLASS="literal">
+-n</code> is the actual NetBIOS name of the server. If you receive "Get-Hostbyname: Unknown host MARY," it's not the right server yet.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-946169">
+</a>If nothing is working so far, repeat the tests specifying <CODE CLASS="literal">
+-U</code> <CODE CLASS="replaceable">
+<I>
+username</i></code> and <CODE CLASS="literal">
+-W</code> <CODE CLASS="replaceable">
+<I>
+workgroup</i></code>, with the username and workgroup in uppercase, to make sure you're not being derailed by a user or workgroup mismatch.</p></li><LI CLASS="listitem">
+<P CLASS="para">
+<A CLASS="listitem" NAME="ch09-pgfId-953522">
+</a>If nothing works still and you had evidence of a name service problem, troubleshoot name service in the section <A CLASS="xref" HREF="ch09_02.html#ch09-23768">
+Section 9.2.8</a>, and then return to NetBIOS name service.</p></li></ul></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_01.html" TITLE="9.1 The Tool Bag">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.1 The Tool Bag" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_03.html" TITLE="9.3 Extra Resources">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: 9.3 Extra Resources" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">9.1 The Tool Bag</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+9.3 Extra Resources</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/ch09_03.html b/docs/htmldocs/using_samba/ch09_03.html
new file mode 100644
index 00000000000..ecaa53ed364
--- /dev/null
+++ b/docs/htmldocs/using_samba/ch09_03.html
@@ -0,0 +1,136 @@
+<HTML>
+<HEAD>
+<TITLE>
+[Chapter 9] 9.3 Extra Resources</title><META NAME="DC.title" CONTENT=""><META NAME="DC.creator" CONTENT=""><META NAME="DC.publisher" CONTENT="O'Reilly &amp; Associates, Inc."><META NAME="DC.date" CONTENT="1999-11-05T21:41:27Z"><META NAME="DC.type" CONTENT="Text.Monograph"><META NAME="DC.format" CONTENT="text/html" SCHEME="MIME"><META NAME="DC.source" CONTENT="" SCHEME="ISBN"><META NAME="DC.language" CONTENT="en-US"><META NAME="generator" CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"></head>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly
+<br>1st Edition November 1999
+<br>1-56592-449-5, Order Number: 4495
+<br>416 pages, $34.95
+</font>
+<p> <a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy</a>
+<p><a href="index.html">Table of Contents</a>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<center>
+<DIV CLASS="htmlnav">
+<TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_02.html" TITLE="9.2 The Fault Tree">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.2 The Fault Tree" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<B>
+<FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">
+<A CLASS="chapter" REL="up" HREF="ch09_01.html" TITLE="9. Troubleshooting Samba">
+Chapter 9<br>
+Troubleshooting Samba</a></font></b></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A. Configuring Samba with SSL" BORDER="0"></a></td></tr></table>&nbsp;<hr noshade size=1></center>
+</div>
+<blockquote>
+<div>
+<H2 CLASS="sect1">
+<A CLASS="title" NAME="ch09-49719">
+9.3 Extra Resources</a></h2><P CLASS="para">At some point during your Samba career, you will want to turn to online or printed resources for news, updates, and aid.</p><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-953071">
+9.3.1 Documentation and FAQs</a></h3><P CLASS="para">It's okay to read the documentation. Really. Nobody can see you, and we won't tell. In fact, Samba ships with a large set of documentation files, and it is well worth the effort to at least browse through them, either in the distribution directory on your computer under <I CLASS="filename">
+/docs</i>, or online at the Samba web site: <a href="http://samba.anu.edu.au/samba/"><I CLASS="filename">http://samba.anu.edu.au/samba/</i></a>. The most current FAQ list, bug information, and distribution locations are located at the web site, with links to all of the Samba manual pages and HOW-TOs.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-946178">
+9.3.2 Samba Newsgroups</a></h3><P CLASS="para">Usenet newsgroups have always been a great place to get advice on just about any topic. In the past few years, though, this vast pool of knowledge has developed something that has made it into an invaluable resource: a memory. Archival and search sites such as DejaNews (<I CLASS="filename"><a href="http://www.dejanews.com">http://www.dejanews.com</i></a>) have made sifting through years of valuable solutions on a topic as simple as a few mouse clicks. </p><P CLASS="para">
+The primary newsgroup for Samba is <EM CLASS="emphasis">
+comp.protocols.smb</em>. This should always be your first stop when there's a problem. More often than not, spending five minutes researching an error here will save hours of frustration while trying to debug something yourself.</p><P CLASS="para">
+When searching a newsgroup, try to be as specific as possible, but not too wordy. Searching on actual error messages is best. If you don't find an answer immediately in the newsgroup, resist the temptation to post a request for help until you've done a bit more work on the problem. You may find that the answer is in a FAQ or one of the many documentation files that ships with Samba, or a solution might become evident when you run one of Samba's diagnostic tools. If nothing works, post a request in <EM CLASS="emphasis">
+comp.protocols.smb</em>, and be as specific as possible about what you have tried and what you are seeing. Include any error messages that appear. It may be several days before you receive help, so be patient and keep trying things while you wait.</p><P CLASS="para">
+Once you post a request for help, keep poking at the problem yourself. Most of us have had the experience of posting a Usenet article containing hundreds of lines of intricate detail, only to solve the problem an hour later after the article has blazed its way across several continents. The rule of thumb goes something like this: the more folks who have read your request, the simpler the solution. Usually this means that once everyone in the Unix community has seen your article, the solution will be something simple like, "Plug the computer into the wall socket."</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-951527">
+9.3.3 Samba Mailing Lists</a></h3><P CLASS="para">The following are mailing lists for support with Samba. See the Samba homepage, <a href="http://www.samba.org/"><I CLASS="filename">http://www.samba.org/</i></a> for information on subscribing and unsubscribing to these mailing lists:</p><DL CLASS="variablelist">
+<DT CLASS="term">
+samba-binaries@samba.org</dt><DD CLASS="listitem">
+<P CLASS="para">
+This mailing list has information on precompiled binaries for the Samba platform.</p></dd><DT CLASS="term">
+samba@samba.org</dt><DD CLASS="listitem">
+<P CLASS="para">
+This mailing list is the place to report suspected bugs in Samba.</p></dd><DT CLASS="term">
+samba-ntdom@samba.org</dt><DD CLASS="listitem">
+<P CLASS="para">
+This mailing list has information on support for domains (particularly Windows NT) with the Samba product.</p></dd><DT CLASS="term">
+samba-technical@samba.org</dt><DD CLASS="listitem">
+<P CLASS="para">
+This mailing list maintains debate about where the future of Samba is headed.</p></dd><DT CLASS="term">
+samba@samba.org</dt><DD CLASS="listitem">
+<P CLASS="para">
+This is the primary Samba mailing list that contains general questions and HOW-TO information on Samba.</p></dd></dl></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-946184">
+9.3.4 Samba Discussion Archives</a></h3><P CLASS="para">There is a search service for the primary Samba mailing list. At the time this book was written, it was listed under "searchable" in the Sources paragraph on the first page of the Samba site and its mirrors, <a href="http://samba.anu.edu.au/listproc/ghindex.html"><I CLASS="filename">http://samba.anu.edu.au/listproc/ghindex.html</i></a>.</p></div><DIV CLASS="sect2">
+<H3 CLASS="sect2">
+<A CLASS="title" NAME="ch09-pgfId-946188">
+9.3.5 Further Reading</a></h3><OL CLASS="orderedlist">
+<LI CLASS="listitem">
+<P CLASS="para">Craig Hunt; <EM CLASS="emphasis">
+TCP/IP Network Administration, 2nd Edition</em>. Sebastopol, CA: O'Reilly and Associates, 1997 (ISBN 1-56592-322-7).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+Hunt, Craig, and Robert Bruce Thompson; <EM CLASS="emphasis">
+Windows NT TCP/IP Network Administration. </em>Sebastopol, CA: O'Reilly and Associates, 1998 (<EM CLASS="emphasis">
+ISBN </em>1-56592-377-4).</p></li><LI CLASS="listitem">
+<P CLASS="para">Albitz, Paul, and Cricket Liu; <EM CLASS="emphasis">
+DNS and Bind, 3rd Edition</em>. Sebastopol, CA: O'Reilly &amp; Associates, 1998 (ISBN 1-56592-512-2).</p></li><LI CLASS="listitem">
+<P CLASS="para">
+Stern, Hal; <EM CLASS="emphasis">
+Managing </em><EM CLASS="emphasis">NFS and NIS</em>. Sebastopol, CA: O'Reilly &amp; Associates, 1991 (ISBN 0-937175-75-7).</p></li></ol></div></div></blockquote>
+<div>
+<center>
+<hr noshade size=1><TABLE WIDTH="515" BORDER="0" CELLSPACING="0" CELLPADDING="0">
+<TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">
+<A CLASS="sect1" HREF="ch09_02.html" TITLE="9.2 The Fault Tree">
+<IMG SRC="gifs/txtpreva.gif" ALT="Previous: 9.2 The Fault Tree" BORDER="0"></a></td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="book" HREF="index.html" TITLE="">
+<IMG SRC="gifs/txthome.gif" ALT="" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+<A CLASS="appendix" HREF="appa_01.html" TITLE="A. Configuring Samba with SSL">
+<IMG SRC="gifs/txtnexta.gif" ALT="Next: A. Configuring Samba with SSL" BORDER="0"></a></td></tr><TR>
+<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="172">9.2 The Fault Tree</td><TD ALIGN="CENTER" VALIGN="TOP" WIDTH="171">
+<A CLASS="index" HREF="inx.html" TITLE="Book Index">
+<IMG SRC="gifs/index.gif" ALT="Book Index" BORDER="0"></a></td><TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="172">
+A. Configuring Samba with SSL</td></tr></table><hr noshade size=1></center>
+</div>
+
+<!-- End of sample chapter -->
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/figs/sam.0101.gif b/docs/htmldocs/using_samba/figs/sam.0101.gif
new file mode 100644
index 00000000000..ce022dd3220
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0101.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0102.gif b/docs/htmldocs/using_samba/figs/sam.0102.gif
new file mode 100644
index 00000000000..2c26743160e
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0102.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0103.gif b/docs/htmldocs/using_samba/figs/sam.0103.gif
new file mode 100644
index 00000000000..480b51bdb24
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0103.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0104.gif b/docs/htmldocs/using_samba/figs/sam.0104.gif
new file mode 100644
index 00000000000..a580bfd9da5
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0104.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0105.gif b/docs/htmldocs/using_samba/figs/sam.0105.gif
new file mode 100644
index 00000000000..45782f6a54d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0105.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0106.gif b/docs/htmldocs/using_samba/figs/sam.0106.gif
new file mode 100644
index 00000000000..7e43f6a8295
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0106.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0107.gif b/docs/htmldocs/using_samba/figs/sam.0107.gif
new file mode 100644
index 00000000000..60f24ce060d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0107.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0108.gif b/docs/htmldocs/using_samba/figs/sam.0108.gif
new file mode 100644
index 00000000000..93b036c7366
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0108.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0109.gif b/docs/htmldocs/using_samba/figs/sam.0109.gif
new file mode 100644
index 00000000000..ec01228ef7c
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0109.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0110.gif b/docs/htmldocs/using_samba/figs/sam.0110.gif
new file mode 100644
index 00000000000..9695cf7c61b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0110.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0111.gif b/docs/htmldocs/using_samba/figs/sam.0111.gif
new file mode 100644
index 00000000000..4dbc2dba41b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0111.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0112.gif b/docs/htmldocs/using_samba/figs/sam.0112.gif
new file mode 100644
index 00000000000..4f559e0d0f0
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0112.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0113.gif b/docs/htmldocs/using_samba/figs/sam.0113.gif
new file mode 100644
index 00000000000..5d8cdaef6b5
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0113.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0114.gif b/docs/htmldocs/using_samba/figs/sam.0114.gif
new file mode 100644
index 00000000000..291e6f0c824
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0114.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0201.gif b/docs/htmldocs/using_samba/figs/sam.0201.gif
new file mode 100644
index 00000000000..e6f97f63015
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0201.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0202.gif b/docs/htmldocs/using_samba/figs/sam.0202.gif
new file mode 100644
index 00000000000..0490c085717
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0202.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0203.gif b/docs/htmldocs/using_samba/figs/sam.0203.gif
new file mode 100644
index 00000000000..a24c4818600
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0203.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0204.gif b/docs/htmldocs/using_samba/figs/sam.0204.gif
new file mode 100644
index 00000000000..e446b1d4f11
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0204.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0301.gif b/docs/htmldocs/using_samba/figs/sam.0301.gif
new file mode 100644
index 00000000000..82306d6cc9b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0301.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0302.gif b/docs/htmldocs/using_samba/figs/sam.0302.gif
new file mode 100644
index 00000000000..0916db72aea
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0302.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0303.gif b/docs/htmldocs/using_samba/figs/sam.0303.gif
new file mode 100644
index 00000000000..18d63dbbb73
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0303.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0304.gif b/docs/htmldocs/using_samba/figs/sam.0304.gif
new file mode 100644
index 00000000000..a0c5eee0992
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0304.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0305.gif b/docs/htmldocs/using_samba/figs/sam.0305.gif
new file mode 100644
index 00000000000..43be04655ab
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0305.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0306.gif b/docs/htmldocs/using_samba/figs/sam.0306.gif
new file mode 100644
index 00000000000..be7609d9439
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0306.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0307.gif b/docs/htmldocs/using_samba/figs/sam.0307.gif
new file mode 100644
index 00000000000..258d3390bc1
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0307.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0308.gif b/docs/htmldocs/using_samba/figs/sam.0308.gif
new file mode 100644
index 00000000000..316643ccfbe
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0308.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0309.gif b/docs/htmldocs/using_samba/figs/sam.0309.gif
new file mode 100644
index 00000000000..4a9d5d762b2
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0309.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0310.gif b/docs/htmldocs/using_samba/figs/sam.0310.gif
new file mode 100644
index 00000000000..37262b91be0
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0310.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0311.gif b/docs/htmldocs/using_samba/figs/sam.0311.gif
new file mode 100644
index 00000000000..c25e96f936f
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0311.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0312.gif b/docs/htmldocs/using_samba/figs/sam.0312.gif
new file mode 100644
index 00000000000..8823f38eb1a
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0312.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0313.gif b/docs/htmldocs/using_samba/figs/sam.0313.gif
new file mode 100644
index 00000000000..981a6849887
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0313.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0314.gif b/docs/htmldocs/using_samba/figs/sam.0314.gif
new file mode 100644
index 00000000000..9a7ed5858e2
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0314.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0315.gif b/docs/htmldocs/using_samba/figs/sam.0315.gif
new file mode 100644
index 00000000000..ed4bcc42209
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0315.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0316.gif b/docs/htmldocs/using_samba/figs/sam.0316.gif
new file mode 100644
index 00000000000..99908ac7d3b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0316.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0317.gif b/docs/htmldocs/using_samba/figs/sam.0317.gif
new file mode 100644
index 00000000000..14899010064
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0317.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0318.gif b/docs/htmldocs/using_samba/figs/sam.0318.gif
new file mode 100644
index 00000000000..263650a2749
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0318.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0319.gif b/docs/htmldocs/using_samba/figs/sam.0319.gif
new file mode 100644
index 00000000000..0d1c934a564
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0319.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0320.gif b/docs/htmldocs/using_samba/figs/sam.0320.gif
new file mode 100644
index 00000000000..061ce27cb10
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0320.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0321.gif b/docs/htmldocs/using_samba/figs/sam.0321.gif
new file mode 100644
index 00000000000..f40fbbedcad
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0321.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0322.gif b/docs/htmldocs/using_samba/figs/sam.0322.gif
new file mode 100644
index 00000000000..f421311dfc2
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0322.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0323.gif b/docs/htmldocs/using_samba/figs/sam.0323.gif
new file mode 100644
index 00000000000..578ffda5524
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0323.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0324.gif b/docs/htmldocs/using_samba/figs/sam.0324.gif
new file mode 100644
index 00000000000..4ab9ceb598f
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0324.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0325.gif b/docs/htmldocs/using_samba/figs/sam.0325.gif
new file mode 100644
index 00000000000..f6da1e74347
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0325.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0326.gif b/docs/htmldocs/using_samba/figs/sam.0326.gif
new file mode 100644
index 00000000000..df6313794d0
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0326.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0327.gif b/docs/htmldocs/using_samba/figs/sam.0327.gif
new file mode 100644
index 00000000000..1e774392154
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0327.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0328.gif b/docs/htmldocs/using_samba/figs/sam.0328.gif
new file mode 100644
index 00000000000..7baa0ef4e6d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0328.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0401.gif b/docs/htmldocs/using_samba/figs/sam.0401.gif
new file mode 100644
index 00000000000..a62d0d5675d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0401.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0402.gif b/docs/htmldocs/using_samba/figs/sam.0402.gif
new file mode 100644
index 00000000000..ecf03ca8c8a
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0402.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0403.gif b/docs/htmldocs/using_samba/figs/sam.0403.gif
new file mode 100644
index 00000000000..755522854a4
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0403.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0404.gif b/docs/htmldocs/using_samba/figs/sam.0404.gif
new file mode 100644
index 00000000000..0d28182e521
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0404.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0405.gif b/docs/htmldocs/using_samba/figs/sam.0405.gif
new file mode 100644
index 00000000000..c7cc9d681b1
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0405.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0406.gif b/docs/htmldocs/using_samba/figs/sam.0406.gif
new file mode 100644
index 00000000000..a4f82804aa0
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0406.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0407.gif b/docs/htmldocs/using_samba/figs/sam.0407.gif
new file mode 100644
index 00000000000..84ca4e87c75
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0407.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0501.gif b/docs/htmldocs/using_samba/figs/sam.0501.gif
new file mode 100644
index 00000000000..dac53c673a1
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0501.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0502.gif b/docs/htmldocs/using_samba/figs/sam.0502.gif
new file mode 100644
index 00000000000..46e282ce31b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0502.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0503.gif b/docs/htmldocs/using_samba/figs/sam.0503.gif
new file mode 100644
index 00000000000..786de36e69f
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0503.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0504.gif b/docs/htmldocs/using_samba/figs/sam.0504.gif
new file mode 100644
index 00000000000..bece7b9e0a5
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0504.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0505.gif b/docs/htmldocs/using_samba/figs/sam.0505.gif
new file mode 100644
index 00000000000..6460e0436d5
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0505.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0506.gif b/docs/htmldocs/using_samba/figs/sam.0506.gif
new file mode 100644
index 00000000000..e7282b02867
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0506.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0507.gif b/docs/htmldocs/using_samba/figs/sam.0507.gif
new file mode 100644
index 00000000000..bc7f2fda9af
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0507.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0508.gif b/docs/htmldocs/using_samba/figs/sam.0508.gif
new file mode 100644
index 00000000000..95b7ad98c4d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0508.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0601.gif b/docs/htmldocs/using_samba/figs/sam.0601.gif
new file mode 100644
index 00000000000..e826dd51415
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0601.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0602.gif b/docs/htmldocs/using_samba/figs/sam.0602.gif
new file mode 100644
index 00000000000..dce39b1c404
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0602.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0603.gif b/docs/htmldocs/using_samba/figs/sam.0603.gif
new file mode 100644
index 00000000000..15ad6f05d7b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0603.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0604.gif b/docs/htmldocs/using_samba/figs/sam.0604.gif
new file mode 100644
index 00000000000..cd9820d00e7
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0604.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0605.gif b/docs/htmldocs/using_samba/figs/sam.0605.gif
new file mode 100644
index 00000000000..db8e9c5e9f6
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0605.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0606.gif b/docs/htmldocs/using_samba/figs/sam.0606.gif
new file mode 100644
index 00000000000..a4c5e577e5a
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0606.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0701.gif b/docs/htmldocs/using_samba/figs/sam.0701.gif
new file mode 100644
index 00000000000..5933bdabbd0
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0701.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0702.gif b/docs/htmldocs/using_samba/figs/sam.0702.gif
new file mode 100644
index 00000000000..c1160e28383
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0702.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0703.gif b/docs/htmldocs/using_samba/figs/sam.0703.gif
new file mode 100644
index 00000000000..653e9b97617
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0703.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0704.gif b/docs/htmldocs/using_samba/figs/sam.0704.gif
new file mode 100644
index 00000000000..78d5a439eae
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0704.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0705.gif b/docs/htmldocs/using_samba/figs/sam.0705.gif
new file mode 100644
index 00000000000..39cee4c8569
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0705.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0706.gif b/docs/htmldocs/using_samba/figs/sam.0706.gif
new file mode 100644
index 00000000000..8725542429c
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0706.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0707.gif b/docs/htmldocs/using_samba/figs/sam.0707.gif
new file mode 100644
index 00000000000..09abcd5e78f
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0707.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0708.gif b/docs/htmldocs/using_samba/figs/sam.0708.gif
new file mode 100644
index 00000000000..bd5466b319b
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0708.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0709.gif b/docs/htmldocs/using_samba/figs/sam.0709.gif
new file mode 100644
index 00000000000..28452fd2322
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0709.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0801.gif b/docs/htmldocs/using_samba/figs/sam.0801.gif
new file mode 100644
index 00000000000..04e9210e54d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0801.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0802.gif b/docs/htmldocs/using_samba/figs/sam.0802.gif
new file mode 100644
index 00000000000..bf1718c93bf
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0802.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0803.gif b/docs/htmldocs/using_samba/figs/sam.0803.gif
new file mode 100644
index 00000000000..bb5739154a5
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0803.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0804.gif b/docs/htmldocs/using_samba/figs/sam.0804.gif
new file mode 100644
index 00000000000..eceb287e629
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0804.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0805.gif b/docs/htmldocs/using_samba/figs/sam.0805.gif
new file mode 100644
index 00000000000..5a599e13453
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0805.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0901.gif b/docs/htmldocs/using_samba/figs/sam.0901.gif
new file mode 100644
index 00000000000..1965600ab92
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0901.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0902.gif b/docs/htmldocs/using_samba/figs/sam.0902.gif
new file mode 100644
index 00000000000..f604d0ed09d
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0902.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0903.gif b/docs/htmldocs/using_samba/figs/sam.0903.gif
new file mode 100644
index 00000000000..1013d453427
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0903.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0904.gif b/docs/htmldocs/using_samba/figs/sam.0904.gif
new file mode 100644
index 00000000000..db13646f3dc
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0904.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.0905.gif b/docs/htmldocs/using_samba/figs/sam.0905.gif
new file mode 100644
index 00000000000..ef8c89bebbb
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.0905.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.aa01.gif b/docs/htmldocs/using_samba/figs/sam.aa01.gif
new file mode 100644
index 00000000000..495b649cd02
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.aa01.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.ab01.gif b/docs/htmldocs/using_samba/figs/sam.ab01.gif
new file mode 100644
index 00000000000..f7379675056
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.ab01.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/figs/sam.ab02.gif b/docs/htmldocs/using_samba/figs/sam.ab02.gif
new file mode 100644
index 00000000000..6090cfd51d2
--- /dev/null
+++ b/docs/htmldocs/using_samba/figs/sam.ab02.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/gifs/index.gif b/docs/htmldocs/using_samba/gifs/index.gif
new file mode 100644
index 00000000000..b45dcd58518
--- /dev/null
+++ b/docs/htmldocs/using_samba/gifs/index.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/gifs/samba.s.gif b/docs/htmldocs/using_samba/gifs/samba.s.gif
new file mode 100644
index 00000000000..4984d0f8f32
--- /dev/null
+++ b/docs/htmldocs/using_samba/gifs/samba.s.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/gifs/txthome.gif b/docs/htmldocs/using_samba/gifs/txthome.gif
new file mode 100644
index 00000000000..5598a0ff938
--- /dev/null
+++ b/docs/htmldocs/using_samba/gifs/txthome.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/gifs/txtnexta.gif b/docs/htmldocs/using_samba/gifs/txtnexta.gif
new file mode 100644
index 00000000000..b6d67311adc
--- /dev/null
+++ b/docs/htmldocs/using_samba/gifs/txtnexta.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/gifs/txtpreva.gif b/docs/htmldocs/using_samba/gifs/txtpreva.gif
new file mode 100644
index 00000000000..2b040b9b518
--- /dev/null
+++ b/docs/htmldocs/using_samba/gifs/txtpreva.gif
Binary files differ
diff --git a/docs/htmldocs/using_samba/index.html b/docs/htmldocs/using_samba/index.html
new file mode 100644
index 00000000000..f1b4ccec6ec
--- /dev/null
+++ b/docs/htmldocs/using_samba/index.html
@@ -0,0 +1,168 @@
+<HTML>
+<HEAD>
+<TITLE></title>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+
+<center>
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
+<tr>
+<td valign="TOP">
+<a href="http://www.oreilly.com/catalog/samba/">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</a>
+</td>
+<td valign="center">
+<H2>Using Samba</H2>
+<font size="-1">
+Robert Eckstein, David Collier-Brown, Peter Kelly<br>
+1st Edition November 1999<br>
+1-56592-449-5, Order Number: 4495<br>
+416 pages, $34.95
+</font>
+<p>
+<a href="http://www.oreilly.com/catalog/samba/">Buy the hardcopy version</a>
+
+</td>
+</tr>
+</table>
+</center>
+
+<hr size=1 noshade>
+<!--sample chapter begins -->
+
+<blockquote>
+<DIV CLASS="toc">
+<H2>
+Table of Contents</h2><P CLASS="toc">
+<a CLASS="chapter" HREF="licenseinfo.html" TITLE="">License Information</a><p>
+<a CLASS="chapter" HREF="this_edition.html" TITLE="">This Edition</a><p>
+<a CLASS="chapter" HREF="ch01_01.html" TITLE="">Chapter 1: <CITE CLASS="chapter">Learning the Samba</cite></a><br>
+ <blockquote>
+ <a CLASS="chapter" HREF="ch01_01.html#s1" TITLE="">Chapter 1.1: <CITE CLASS="chapter">What is Samba?</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_02.html" TITLE="">Chapter 1.2: <CITE CLASS="chapter">What Can Samba Do For Me?</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_03.html" TITLE="">Chapter 1.3: <CITE CLASS="chapter">Getting Familiar with a SMB/CIFS Network</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_04.html" TITLE="">Chapter 1.4: <CITE CLASS="chapter">Microsoft Implementations</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_05.html" TITLE="">Chapter 1.5: <CITE CLASS="chapter">An Overview of the Samba Distribution</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_06.html" TITLE="">Chapter 1.6: <CITE CLASS="chapter">How Can I Get Samba?</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_07.html" TITLE="">Chapter 1.7: <CITE CLASS="chapter">What's New in Samba 2.0?</cite></a><br>
+ <a CLASS="chapter" HREF="ch01_08.html" TITLE="">Chapter 1.8: <CITE CLASS="chapter">And That's Not All...</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch02_01.html" title="">Chapter 2: <CITE CLASS="chapter">Installing Samba on a Unix System</cite></a><br>
+ <blockquote>
+ <a CLASS="chapter" HREF="ch02_01.html#s1" TITLE="">Chapter 2.1: <CITE CLASS="chapter">Downloading the Samba Distribution</cite></a><br>
+ <a CLASS="chapter" HREF="ch02_02.html" TITLE="">Chapter 2.2: <CITE CLASS="chapter">Configuring Samba</cite></a><br>
+ <a CLASS="chapter" HREF="ch02_03.html" TITLE="">Chapter 2.3: <CITE CLASS="chapter">Compiling and Installing Samba</cite></a><br>
+ <a CLASS="chapter" HREF="ch02_04.html" TITLE="">Chapter 2.4: <CITE CLASS="chapter">A Basic Samba Configuration File</cite></a><br>
+ <a CLASS="chapter" HREF="ch02_05.html" TITLE="">Chapter 2.5: <CITE CLASS="chapter">Starting the Samba Daemons</cite></a><br>
+ <a CLASS="chapter" HREF="ch02_06.html" TITLE="">Chapter 2.6: <CITE CLASS="chapter">Testing the Samba Daemons</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch03_01.html" title="">Chapter 3: <CITE CLASS="chapter">Configuring Windows Clients</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch03_01.html#s1" title="">Chapter 3.1: <CITE CLASS="chapter">Setting Up Windows 95/98 Computers</cite></a><br>
+<a CLASS="chapter" HREF="ch03_02.html" title="">Chapter 3.2: <CITE CLASS="chapter">Setting Up Windows NT 4.0 Computers</cite></a><br>
+<a CLASS="chapter" HREF="ch03_03.html" title="">Chapter 3.3: <CITE CLASS="chapter">An Introduction to SMB/CIFS</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch04_01.html" Title="">Chapter 4: <CITE CLASS="chapter">Disk Shares</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch04_01.html#s1" Title="">Chapter 4.1: <CITE CLASS="chapter">Learning the Samba Configuration File</cite></a><br>
+<a CLASS="chapter" HREF="ch04_02.html" Title="">Chapter 4.2: <CITE CLASS="chapter">Special Sections</cite></a><br>
+<a CLASS="chapter" HREF="ch04_03.html" Title="">Chapter 4.3: <CITE CLASS="chapter">Configuration File Options</cite></a><br>
+<a CLASS="chapter" HREF="ch04_04.html" Title="">Chapter 4.4: <CITE CLASS="chapter">Server Configuration</cite></a><br>
+<a CLASS="chapter" HREF="ch04_05.html" Title="">Chapter 4.5: <CITE CLASS="chapter">Disk Share Configuration</cite></a><br>
+<a CLASS="chapter" HREF="ch04_06.html" Title="">Chapter 4.6: <CITE CLASS="chapter">Networking Options with Samba</cite></a><br>
+<a CLASS="chapter" HREF="ch04_07.html" Title="">Chapter 4.7: <CITE CLASS="chapter">Virtual Servers</cite></a><br>
+<a CLASS="chapter" HREF="ch04_08.html" Title="">Chapter 4.8: <CITE CLASS="chapter">Logging Configuration Options</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch05_01.html" title="">Chapter 5: <CITE CLASS="chapter">Browsing and Advanced Disk Shares</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch05_01.html#s1" Title="">Chapter 5.1: <CITE CLASS="chapter">Browsing</cite></a><br>
+<a CLASS="chapter" HREF="ch05_02.html" Title="">Chapter 5.2: <CITE CLASS="chapter">Filesystem Differences</cite></a><br>
+<a CLASS="chapter" HREF="ch05_03.html" Title="">Chapter 5.3: <CITE CLASS="chapter">File Permissions and Attributes on MS-DOS and Unix</cite></a><br>
+<a CLASS="chapter" HREF="ch05_04.html" Title="">Chapter 5.4: <CITE CLASS="chapter">Name Mangling and Case</cite></a><br>
+<a CLASS="chapter" HREF="ch05_05.html" Title="">Chapter 5.5: <CITE CLASS="chapter">Locks and Oplocks</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch06_01.html" title="">Chapter 6: <CITE CLASS="chapter">Users, Security, and Domains</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch06_01.html#s1" Title="">Chapter 6.1: <CITE CLASS="chapter">Users and Groups</cite></a><br>
+<a CLASS="chapter" HREF="ch06_02.html" Title="">Chapter 6.2: <CITE CLASS="chapter">Controlling Access to Shares</cite></a><br>
+<a CLASS="chapter" HREF="ch06_03.html" Title="">Chapter 6.3: <CITE CLASS="chapter">Authentication Security</cite></a><br>
+<a CLASS="chapter" HREF="ch06_04.html" Title="">Chapter 6.4: <CITE CLASS="chapter">Passwords</cite></a><br>
+<a CLASS="chapter" HREF="ch06_05.html" Title="">Chapter 6.5: <CITE CLASS="chapter">Windows Domains</cite></a><br>
+<a CLASS="chapter" HREF="ch06_06.html" Title="">Chapter 6.6: <CITE CLASS="chapter">Logon Scripts</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch07_01.html" Title="">Chapter 7: <CITE CLASS="chapter">Printing and Name Resolution</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch07_01.html#s1" Title="">Chapter 7.1: <CITE CLASS="chapter">Sending Print Jobs to Samba</cite></a><br>
+<a CLASS="chapter" HREF="ch07_02.html" Title="">Chapter 7.2: <CITE CLASS="chapter">Printing to Windows Client Printers</cite></a><br>
+<a CLASS="chapter" HREF="ch07_03.html" Title="">Chapter 7.3: <CITE CLASS="chapter">Name Resolution with Samba</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch08_01.html" title="">Chapter 8: <CITE CLASS="chapter">Additional Samba Information</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch08_01.html#s1" Title="">Chapter 8.1: <CITE CLASS="chapter">Supporting Programmers</cite></a><br>
+<a CLASS="chapter" HREF="ch08_02.html" Title="">Chapter 8.2: <CITE CLASS="chapter">Magic Scripts</cite></a><br>
+<a CLASS="chapter" HREF="ch08_03.html" Title="">Chapter 8.3: <CITE CLASS="chapter">Internationalization</cite></a><br>
+<a CLASS="chapter" HREF="ch08_04.html" Title="">Chapter 8.4: <CITE CLASS="chapter">WinPopup Messages</cite></a><br>
+<a CLASS="chapter" HREF="ch08_05.html" Title="">Chapter 8.5: <CITE CLASS="chapter">Recently Added Options</cite></a><br>
+<a CLASS="chapter" HREF="ch08_06.html" Title="">Chapter 8.6: <CITE CLASS="chapter">Miscellaneous Options</cite></a><br>
+<a CLASS="chapter" HREF="ch08_07.html" Title="">Chapter 8.7: <CITE CLASS="chapter">Backups with smbtar</cite></a><br>
+ </blockquote>
+<a CLASS="chapter" HREF="ch09_01.html" title="">Chapter 9: <CITE CLASS="chapter">Troubleshooting Samba</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="ch09_01.html#s1" Title="">Chapter 9.1: <CITE CLASS="chapter">The Tool Bag</cite></a><br>
+<a CLASS="chapter" HREF="ch09_02.html" Title="">Chapter 9.2: <CITE CLASS="chapter">The Fault Tree</cite></a><br>
+<a CLASS="chapter" HREF="ch09_03.html" Title="">Chapter 9.3: <CITE CLASS="chapter">Extra Resources</cite></a><br>
+ </blockquote>
+
+<a CLASS="appendix" HREF="appa_01.html" title="">Appendix A: <CITE CLASS="appendix">Configuring Samba with SSL</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="appa_01.html#appa-pgfId-986440" Title="">Appendix A.1: <CITE CLASS="chapter">About Certificates</cite></a><br>
+<a CLASS="chapter" HREF="appa_02.html" Title="">Appendix A.2: <CITE CLASS="chapter">Requirements</cite></a><br>
+<a CLASS="chapter" HREF="appa_03.html" Title="">Appendix A.3: <CITE CLASS="chapter">Installing SSLeay</cite></a><br>
+<a CLASS="chapter" HREF="appa_04.html" Title="">Appendix A.4: <CITE CLASS="chapter">Setting Up SSL Proxy</cite></a><br>
+<a CLASS="chapter" HREF="appa_05.html" Title="">Appendix A.5: <CITE CLASS="chapter">SSL Configuration Options</cite></a><br>
+ </blockquote>
+<a CLASS="appendix" HREF="appb_01.html" title="">Appendix B: <CITE CLASS="appendix">Samba Performance Tuning</cite></a><br>
+ <blockquote>
+<a CLASS="chapter" HREF="appb_01.html#appb-47134" Title="">Appendix B.1: <CITE CLASS="chapter">A Simple Benchmark</cite></a><br>
+<a CLASS="chapter" HREF="appb_02.html" Title="">Appendix B.2: <CITE CLASS="chapter">Samba Tuning</cite></a><br>
+<a CLASS="chapter" HREF="appb_03.html" Title="">Appendix B.3: <CITE CLASS="chapter">Sizing Samba Servers</cite></a><br>
+ </blockquote>
+<a CLASS="appendix" HREF="appc_01.html" Title="">Appendix C: <CITE CLASS="appendix">Samba Configuration Option Quick Reference</cite></a><br>
+<p>
+<a CLASS="appendix" HREF="appd_01.html" Title="">Appendix D: <CITE CLASS="appendix">Summary of Samba Daemons and Commands</cite></a><br>
+<p>
+<a CLASS="appendix" HREF="appe_01.html" Title="">Appendix E: <CITE CLASS="appendix">Downloading Samba with CVS</cite></a><br>
+<p>
+<a CLASS="appendix" HREF="appf_01.html" Title="">Appendix F: <CITE CLASS="appendix">Sample Configuration File</cite></a><br>
+<p>
+
+<a HREF="inx.html" Title="">Index</a><br>
+
+</p></div>
+</blockquote>
+
+<!-- End of sample chapter -->
+
+<hr noshade size=1></center>
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+</html>
diff --git a/docs/htmldocs/using_samba/inx.html b/docs/htmldocs/using_samba/inx.html
new file mode 100644
index 00000000000..34207d7a747
--- /dev/null
+++ b/docs/htmldocs/using_samba/inx.html
@@ -0,0 +1,1344 @@
+<html>
+<head>
+<title>Using Samba</title>
+<META NAME="metadata" CONTENT="dublincore.0.1">
+<META NAME="subject" CONTENT="Using Samba">
+<META NAME="title" CONTENT="O'Reilly Catalog Index: Using Samba">
+<META NAME="otheragent" CONTENT="cron job">
+<META NAME="source" CONTENT="internal database">
+<META NAME="publisher" CONTENT="O'Reilly &amp; Associates, Inc.">
+<META NAME="objecttype" CONTENT="catalog index">
+<META NAME="form" CONTENT="html">
+</head>
+<BODY BGCOLOR="#FFFFFF" >
+<table border=0 cellspacing=0 cellpadding=0 width=90%>
+<tr>
+<td>
+<h2>Using Samba</h2>
+<h3>Index</h3>
+
+<PRE>
+</pre>
+<A HREF="#A">[&nbsp;A&nbsp;]</A>,
+<A HREF="#B">[&nbsp;B&nbsp;]</A>,
+<A HREF="#C">[&nbsp;C&nbsp;]</A>,
+<A HREF="#D">[&nbsp;D&nbsp;]</A>,
+<A HREF="#E">[&nbsp;E&nbsp;]</A>,
+<A HREF="#F">[&nbsp;F&nbsp;]</A>,
+<A HREF="#G">[&nbsp;G&nbsp;]</A>,
+<A HREF="#H">[&nbsp;H&nbsp;]</A>,
+<A HREF="#I">[&nbsp;I&nbsp;]</A>,
+<A HREF="#J">[&nbsp;J&nbsp;]</A>,
+<A HREF="#K">[&nbsp;K&nbsp;]</A>,
+<A HREF="#L">[&nbsp;L&nbsp;]</A>,
+<A HREF="#M">[&nbsp;M&nbsp;]</A>,
+<A HREF="#N">[&nbsp;N&nbsp;]</A>,
+<A HREF="#O">[&nbsp;O&nbsp;]</A>,
+<A HREF="#P">[&nbsp;P&nbsp;]</A>,
+<A HREF="#Q">[&nbsp;Q&nbsp;]</A>,
+<A HREF="#R">[&nbsp;R&nbsp;]</A>,
+<A HREF="#S">[&nbsp;S&nbsp;]</A>,
+<A HREF="#T">[&nbsp;T&nbsp;]</A>,
+<A HREF="#U">[&nbsp;U&nbsp;]</A>,
+<A HREF="#V">[&nbsp;V&nbsp;]</A>,
+<A HREF="#W">[&nbsp;W&nbsp;]</A>,
+<A HREF="#Y">[&nbsp;Y&nbsp;]</A>,
+
+
+<BR>&lt;&gt; (angled brackets), 14
+<BR>* (asterisk), 169
+<BR>\ (backslash) in smb.conf file, 85
+<BR>\\ (backslashes, two) in directories, 5
+<BR>: (colon), 6
+<BR>\ (continuation character), 85
+<BR>. (dot), 128, 134
+<BR># (hash mark), 85
+<BR>% (percent sign), 86
+<BR>. (period), 128
+<BR>? (question mark), 135
+<BR>; (semicolon), 85
+<BR>/ (slash character), 129, 134-135
+<BR>/ (slash) in shares, 116
+<BR>_ (underscore) 116
+<BR>* wildcard, 177
+
+<P><A NAME="A"><B>A</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>access-control options (shares), 160-162
+<BR>accessing Samba server, 61
+<BR>accounts, 51-53
+<BR>active connections, option for, 244
+<BR>addresses, networking option for, 106
+<BR>addtosmbpass executable, 176
+<BR>admin users option, 161
+<BR>AFS files, support for, 35
+<BR>aliases
+<BR> &nbsp; &nbsp; &nbsp; multiple, 29
+<BR> &nbsp; &nbsp; &nbsp; for NetBIOS names, 107
+<BR>alid users option, 161
+<BR>announce as option, 123
+<BR>announce version option, 123
+<BR>API (application programming interface), 9
+<BR>archive files, 137
+<BR>authentication, 19, 164-171
+<BR> &nbsp; &nbsp; &nbsp; mechanisms for, 35
+<BR> &nbsp; &nbsp; &nbsp; NT domain, 170
+<BR> &nbsp; &nbsp; &nbsp; share-level option for, 192
+<BR>auto services option, 124
+<BR>automounter, support for, 35
+<BR>awk script, 176
+<P><A NAME="B"><B>B</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>backup browsers
+<BR> &nbsp; &nbsp; &nbsp; local master browser, 22
+<BR> &nbsp; &nbsp; &nbsp; per local master browser, 23
+<BR> &nbsp; &nbsp; &nbsp; maximum number per workgroup, 22
+<BR>backup domain controllers (BDCs), 20
+<BR>backups, with smbtar program, 245-248
+<BR>backwards compatibility
+<BR> &nbsp; &nbsp; &nbsp; elections and, 23
+<BR> &nbsp; &nbsp; &nbsp; for filenames, 143
+<BR> &nbsp; &nbsp; &nbsp; Windows domains and, 20
+<BR>base directory, 40
+<BR>.BAT scripts, 192
+<BR>BDCs (backup domain controllers), 20
+<BR>binary vs. source files, 32
+<BR>bind interfaces only option, 106
+<BR>bindings, 71
+<BR>Bindings tab, 60
+<BR>blocking locks option, 152
+<BR>b-node, 13
+<BR>boolean type, 90
+<BR>bottlenecks, 320-328
+<BR> &nbsp; &nbsp; &nbsp; reducing, 321-326
+<BR> &nbsp; &nbsp; &nbsp; types of, 320
+<BR>broadcast addresses, troubleshooting, 289
+<BR>broadcast registration, 13
+<BR>broadcast resolution, 13, 59
+<BR>broadcasting
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting with tcpdump utility, 255
+<BR> &nbsp; &nbsp; &nbsp; (see also browsing; name resolution)
+<BR>browse lists, 21, 116
+<BR> &nbsp; &nbsp; &nbsp; options for, 124, 127
+<BR> &nbsp; &nbsp; &nbsp; propagation, 24
+<BR> &nbsp; &nbsp; &nbsp; restricting shares from, 115
+<BR>browsing, 21-23, 114-127
+<BR> &nbsp; &nbsp; &nbsp; client-side, testing with net view, 280
+<BR> &nbsp; &nbsp; &nbsp; configuration options for, 122-127
+<BR> &nbsp; &nbsp; &nbsp; elections, 23, 116-119
+<BR> &nbsp; &nbsp; &nbsp; machines, list of, 21
+<BR> &nbsp; &nbsp; &nbsp; options for, list of, 122
+<BR> &nbsp; &nbsp; &nbsp; preventing, 115
+<BR> &nbsp; &nbsp; &nbsp; resources of a specific machine, 21-23
+<BR> &nbsp; &nbsp; &nbsp; server from client, 281
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 275-282
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with smbclient, 276-278
+<BR>bug avoidance options, 240-245
+<BR> &nbsp; &nbsp; &nbsp; list of, 240-241
+<P><A NAME="C"><B>C</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>cache size, new option for (Samba version 2.0), 239
+<BR>cache time (printers), option for, 220
+<BR>capitalization, 84
+<BR>Carnegie Mellon University, 35
+<BR>carriage-returns for scripts, 193
+<BR>case sensitivity
+<BR> &nbsp; &nbsp; &nbsp; hostnames and, 5
+<BR> &nbsp; &nbsp; &nbsp; options for, 146
+<BR> &nbsp; &nbsp; &nbsp; usernames and, 163
+<BR>CD-ROM with this book
+<BR> &nbsp; &nbsp; &nbsp; Samba distribution, 28, 32
+<BR> &nbsp; &nbsp; &nbsp; testing tools, 28
+<BR>certificate authority, 300-303
+<BR>change notification, new option for (Samba version 2.0), 239
+<BR>change notify timeout option, 239
+<BR>Change Windows Password dialog box, 52
+<BR>changes at runtime, 85
+<BR>chat characters for passwords, 178
+<BR>CIFS (Common Internet File System), 3
+<BR> &nbsp; &nbsp; &nbsp; (see also SMB/CIFS protocol)
+<BR>client code page option, 234
+<BR>client users (see users)
+<BR>client variables, 86
+<BR>clients, testing with nmblookup program, 279
+<BR>.CMD scripts, 192
+<BR>code pages, 234
+<BR> &nbsp; &nbsp; &nbsp; multiple, 30
+<BR>coding system option, 235
+<BR>command string, SMB, 75
+<BR>commands for Samba, 366-377
+<BR>commas in values, 84
+<BR>comment option, 99
+<BR>comments in smb.conf (Samba configuration) file, 85
+<BR>compatibility, Samba with Windows NT, 30
+<BR>compilers, 33
+<BR>compiling Samba, 38-41
+<BR> &nbsp; &nbsp; &nbsp; in version 2.0, 29
+<BR>config file option, 91
+<BR>configuration files
+<BR> &nbsp; &nbsp; &nbsp; for individual clients, 253
+<BR> &nbsp; &nbsp; &nbsp; machine-specific, 87
+<BR> &nbsp; &nbsp; &nbsp; sample of, 379-383
+<BR> &nbsp; &nbsp; &nbsp; smb.conf (Samba configuration) file (see smb.conf file)
+<BR>configuration options
+<BR> &nbsp; &nbsp; &nbsp; browsing, 122-127
+<BR> &nbsp; &nbsp; &nbsp; disk share, 97-100
+<BR> &nbsp; &nbsp; &nbsp; format of, 83
+<BR> &nbsp; &nbsp; &nbsp; list of, 329-356
+<BR> &nbsp; &nbsp; &nbsp; server, 94-96
+<BR>configuring disk shares, 96-100
+<BR>configuring DNS (Windows NT), 68
+<BR>configuring Samba, 34-38
+<BR> &nbsp; &nbsp; &nbsp; configuration file
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; creating, 41-45
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testing, 45
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (see also smb.conf (Samba configuration) file)
+<BR> &nbsp; &nbsp; &nbsp; configure script
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GNU, 34
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sample execution, 38
+<BR> &nbsp; &nbsp; &nbsp; options, 34-37
+<BR> &nbsp; &nbsp; &nbsp; performance tuning, 312-328
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; benchmark for, 312, 314
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; other options for, 319-328
+<BR> &nbsp; &nbsp; &nbsp; server, 93-96
+<BR> &nbsp; &nbsp; &nbsp; with SSL, 295-311
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; requirements for, 296
+<BR>configuring TCP/IP networking protocol, 55, 66-71
+<BR>configuring Windows clients, 50-81
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98 computers, 50-63
+<BR> &nbsp; &nbsp; &nbsp; Windows NT 4.0 computers, 63-73
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; basic configuration, 63-67
+<BR>configuring WINS address, 70
+<BR>connected systems, status of, 9
+<BR>connections
+<BR> &nbsp; &nbsp; &nbsp; active, option for, 244
+<BR> &nbsp; &nbsp; &nbsp; current, list of, 370
+<BR> &nbsp; &nbsp; &nbsp; resources, connecting to, 81
+<BR> &nbsp; &nbsp; &nbsp; scripts for, 198
+<BR> &nbsp; &nbsp; &nbsp; SMB, 77
+<BR> &nbsp; &nbsp; &nbsp; testing, 259-263
+<BR> &nbsp; &nbsp; &nbsp; virtual, 78
+<BR>copy option, 92
+<BR>creation masks, 138
+<BR> &nbsp; &nbsp; &nbsp; option for, 140
+<BR>cryptography, private key, 35
+<BR>CVS (Concurrent Versions Systems), 378
+<BR>Cyclic Software, 378
+<P><A NAME="D"><B>D</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>daemons, 82, 359-362
+<BR> &nbsp; &nbsp; &nbsp; killing, 48
+<BR> &nbsp; &nbsp; &nbsp; messages generated by, reading, 8
+<BR> &nbsp; &nbsp; &nbsp; stand-alone, 47
+<BR> &nbsp; &nbsp; &nbsp; starting, 46-48
+<BR> &nbsp; &nbsp; &nbsp; status report, 8
+<BR> &nbsp; &nbsp; &nbsp; testing, 49
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with testparm, 266
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 264-268
+<BR> &nbsp; &nbsp; &nbsp; Unix, 2
+<BR> &nbsp; &nbsp; &nbsp; viewing, 8
+<BR> &nbsp; &nbsp; &nbsp; (see also smbd daemon; nmbd daemon)
+<BR>data transfer protocol, 6
+<BR>datagram service, 10, 16-18
+<BR>deadtime option, 241
+<BR>debug files, 49
+<BR>debug level option, 251, 314
+<BR>debug timestamp option, 112
+<BR>default case option, 146
+<BR>default services, 115
+<BR> &nbsp; &nbsp; &nbsp; option for, 124
+<BR>defending hostnames, 12
+<BR>delays, troubleshooting, 287
+<BR>delete, 142
+<BR>delete readonly option, 139, 142
+<BR>delete veto files option, 135
+<BR>dfree command option, 241
+<BR>DFS, support for, 35
+<BR>DHCP (Dynamic Host Configuration Protocol), 57, 67
+<BR>dialup connection, 53
+<BR>Digital Pathworks clients, option for, 244
+<BR>directories
+<BR> &nbsp; &nbsp; &nbsp; barring users from viewing contents, 130, 133
+<BR> &nbsp; &nbsp; &nbsp; installation, 40
+<BR> &nbsp; &nbsp; &nbsp; permissions, options for, 140
+<BR> &nbsp; &nbsp; &nbsp; for Samba startup file, 363
+<BR> &nbsp; &nbsp; &nbsp; target, 40
+<BR> &nbsp; &nbsp; &nbsp; working, option for, 134
+<BR>directory mask option, 138, 141
+<BR>disabling/enabling features, 34
+<BR>discussion archives for Samba, 293
+<BR>disk quotas, support for, 37
+<BR>disk shares, 4-7, 49, 82-113
+<BR> &nbsp; &nbsp; &nbsp; advanced, 114-154
+<BR> &nbsp; &nbsp; &nbsp; configuring, 96-100
+<BR> &nbsp; &nbsp; &nbsp; creating, 96
+<BR> &nbsp; &nbsp; &nbsp; maximum size of, option for, 242
+<BR> &nbsp; &nbsp; &nbsp; path option, 98
+<BR>disk sync, options for, 245
+<BR>DMB (domain master browser), 119-122
+<BR> &nbsp; &nbsp; &nbsp; option for, 126
+<BR> &nbsp; &nbsp; &nbsp; resource type, 24
+<BR>DNS Configuration tab, 57
+<BR>DNS (Domain Name System), 57
+<BR> &nbsp; &nbsp; &nbsp; configuring, 68
+<BR> &nbsp; &nbsp; &nbsp; as fallback for WINS address, 71
+<BR> &nbsp; &nbsp; &nbsp; names
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NetBIOS names and, 14
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resource types and, 15
+<BR> &nbsp; &nbsp; &nbsp; option for, 228
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 293
+<BR> &nbsp; &nbsp; &nbsp; tab, 68
+<BR>dns proxy option, 228
+<BR>docs directory, 34
+<BR> &nbsp; &nbsp; &nbsp; test utilities, 254
+<BR>documentation for Samba, 291
+<BR> &nbsp; &nbsp; &nbsp; importance of reading, 34
+<BR>domain controllers, 20, 169
+<BR> &nbsp; &nbsp; &nbsp; for Windows 95/98, 18-20
+<BR>domain group map option, 191
+<BR>domain logons, 28, 184
+<BR> &nbsp; &nbsp; &nbsp; configuring Windows 95/98 for, 188
+<BR> &nbsp; &nbsp; &nbsp; configuring Windows NT 4.0 for, 189
+<BR> &nbsp; &nbsp; &nbsp; scripts for, 192-200
+<BR>domain logons option, 190
+<BR>domain master browser (see DMB)
+<BR>domain master option, 126
+<BR>Domain Name System (see DNS)
+<BR>domain user map option, 191
+<BR>domain-level security, 164, 169-171
+<BR>domains, 18-20
+<BR> &nbsp; &nbsp; &nbsp; adding Samba server to Windows NT domain, 171
+<BR> &nbsp; &nbsp; &nbsp; behavior vs. Windows workgroups, 20
+<BR> &nbsp; &nbsp; &nbsp; controllers (see domain controllers)
+<BR> &nbsp; &nbsp; &nbsp; logons (see domain logons)
+<BR> &nbsp; &nbsp; &nbsp; new option for password timeout (Samba version 2.0), 239
+<BR> &nbsp; &nbsp; &nbsp; roles in assumed by Samba, 26
+<BR> &nbsp; &nbsp; &nbsp; Windows, 18, 28, 184-192
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; authentication, 170
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; caution when selecting, 190
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; support for, 28
+<BR>dont descend option, 133
+<BR>DOS file permissions and attributes, 135-143
+<BR>DOS-formatted carriage returns, 193
+<BR>downloads
+<BR> &nbsp; &nbsp; &nbsp; Samba, 32
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obtained using CVS, 378
+<BR> &nbsp; &nbsp; &nbsp; tcpdump utility, 78, 257
+<BR>drive letters, mapping, 5
+<BR>dynamically linked libraries, 33
+<P><A NAME="E"><B>E</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>elections, 23
+<BR> &nbsp; &nbsp; &nbsp; operating system values in, 117
+<BR> &nbsp; &nbsp; &nbsp; order of decisions in, 118
+<BR> &nbsp; &nbsp; &nbsp; role settings in, 117
+<BR> &nbsp; &nbsp; &nbsp; WINS servers and, 26
+<BR>enabling/disabling features, 34
+<BR>encrypt passwords option, 181
+<BR>encrypted passwords, 172
+<BR> &nbsp; &nbsp; &nbsp; Microsoft format, 183
+<BR> &nbsp; &nbsp; &nbsp; option for, 181
+<BR> &nbsp; &nbsp; &nbsp; vs. plaintext passwords, 173
+<BR>Entire Network icon, 4
+<BR>enumerated lists, 91
+<BR>errors
+<BR> &nbsp; &nbsp; &nbsp; searching for, 38
+<BR> &nbsp; &nbsp; &nbsp; syntax, 45
+<BR>/etc/hosts file, 57, 60
+<BR>/etc/inetd.conf configuration files, 48
+<BR> &nbsp; &nbsp; &nbsp; adding SWAT tool to, 41
+<BR>/etc/resolv.conf file, 57
+<BR>/etc/services configuration file, adding SWAT tool to, 41, 48
+<BR>Ethernet adaptor cards, 53, 70
+<BR> &nbsp; &nbsp; &nbsp; linking to TCP/IP networking protocol, 55
+<BR>execute permissions, 47
+<BR>/export/samba/test directory, 42
+<P><A NAME="F"><B>F</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>fake directory create times option, 232
+<BR>fake oplocks option, 153
+<BR>FAQ, Samba, 291
+<BR>fast locking, 36
+<BR>fatal error, option for, 244
+<BR>fault tree, 257-291
+<BR> &nbsp; &nbsp; &nbsp; how to use, 257
+<BR>"File and Printer Sharing for Microsoft Networks", 53, 60, 246
+<BR>file creation masks, 138
+<BR>filenames
+<BR> &nbsp; &nbsp; &nbsp; 8.3 format, 143
+<BR> &nbsp; &nbsp; &nbsp; limitations on, 143
+<BR> &nbsp; &nbsp; &nbsp; representing/resolving, 145
+<BR> &nbsp; &nbsp; &nbsp; Unix, option for, 245
+<BR>files
+<BR> &nbsp; &nbsp; &nbsp; archive, 137
+<BR> &nbsp; &nbsp; &nbsp; attributes, 135-143
+<BR> &nbsp; &nbsp; &nbsp; deleting, option for, 129
+<BR> &nbsp; &nbsp; &nbsp; hidden, 128, 136
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; options for, 134
+<BR> &nbsp; &nbsp; &nbsp; open, option for maximum number of, 243
+<BR> &nbsp; &nbsp; &nbsp; permissions, 135-143
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; options for, 140
+<BR> &nbsp; &nbsp; &nbsp; read-only, 136
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; deleting, 139, 142
+<BR> &nbsp; &nbsp; &nbsp; system, 136
+<BR> &nbsp; &nbsp; &nbsp; in use, status of, 9
+<BR> &nbsp; &nbsp; &nbsp; veto, 129-131
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; option for deleting, 135
+<BR>filesystems
+<BR> &nbsp; &nbsp; &nbsp; differences between, 127-131
+<BR> &nbsp; &nbsp; &nbsp; links and, 130
+<BR> &nbsp; &nbsp; &nbsp; options for, 132-135
+<BR> &nbsp; &nbsp; &nbsp; reporting on by Samba, option for, 242
+<BR> &nbsp; &nbsp; &nbsp; (see also files)
+<BR>fixed user configuration, 196
+<BR>flat namespaces, 14, 25
+<BR>follow symlinks option, 133
+<BR>force create mode option, 141
+<BR>force directory mode option, 141
+<BR>force group option, 139, 141
+<BR>force user option, 139, 141
+<BR>foreign-language characters, 234-236
+<BR>free space on disk, option for, 241
+<BR>fstype option, 242
+<BR>FTP (File Transfer Protocol), 6
+<BR> &nbsp; &nbsp; &nbsp; sites for Samba downloads, 32
+<P><A NAME="G"><B>G</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>gateway field, 68
+<BR>getwd cache option, 134, 320
+<BR>global options, 90
+<BR>[globals] section, 88
+<BR>GNU autoconf, 29
+<BR>GNU configure script, 34
+<BR>GNU General Public License (GPL), 3, 378
+<BR>groups, 155-158
+<BR> &nbsp; &nbsp; &nbsp; administrative privileges for, 159
+<BR> &nbsp; &nbsp; &nbsp; names and types of, 15
+<BR>guest, 162
+<BR>guest access, 159-162
+<BR>guest account option, 162
+<BR>guest ok option, 98
+<BR>guest only option, 162
+<P><A NAME="H"><B>H</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>hangup (HUP) signal, 48
+<BR>header, SMB, 74
+<BR>Hexidecimal byte value
+<BR> &nbsp; &nbsp; &nbsp; for NetBIOS group resource types, 16
+<BR> &nbsp; &nbsp; &nbsp; for NetBIOS unique resource types, 15
+<BR>hidden files, 128, 136
+<BR> &nbsp; &nbsp; &nbsp; options for, 134, 142, 319
+<BR>h-node, 13
+<BR>home directory, user's, 36, 155
+<BR> &nbsp; &nbsp; &nbsp; logon script option for location of, 198
+<BR>homedir map option, 200
+<BR>[homes] share, 89, 157
+<BR>hort preserve case option, 147
+<BR>hostnames
+<BR> &nbsp; &nbsp; &nbsp; case sensitivity and, 5
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; long/short, 286
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lookup, 284
+<BR>hosts
+<BR> &nbsp; &nbsp; &nbsp; files (Windows 95/98), 59
+<BR> &nbsp; &nbsp; &nbsp; files (Windows NT computers), 71
+<BR> &nbsp; &nbsp; &nbsp; networking option for connections, 101, 103, 105
+<BR> &nbsp; &nbsp; &nbsp; subnets and, caution with, 102
+<BR>hosts allow option, 103
+<BR>hosts deny option, 105
+<BR>hosts equiv option, 184
+<BR>how-tos, fault tree, 257-291
+<BR>http, 6
+<BR>HUP (hangup) signal, 48
+<P><A NAME="I"><B>I</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>Identification Changes dialog box (Windows NT), 63
+<BR>Identification tab, 60
+<BR>implementations, Microsoft, 18-27
+<BR>include option, 92
+<BR>inetd daemon, starting other daemons from, 48
+<BR>installing Samba, 31-49
+<BR> &nbsp; &nbsp; &nbsp; common problems, 34
+<BR> &nbsp; &nbsp; &nbsp; installation directories, 40
+<BR> &nbsp; &nbsp; &nbsp; steps in, 31
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final, 41
+<BR> &nbsp; &nbsp; &nbsp; time required, 31
+<BR>installing TCP/IP protocol, 65
+<BR>installing Workstation service, 65
+<BR>interfaces, networking options for, 102
+<BR>interfaces option, 105
+<BR>internationalization, 234-236
+<BR>invalid users option, 161
+<BR>IP address, 288-290
+<BR> &nbsp; &nbsp; &nbsp; setting for Windows NT computers, 67
+<BR>IP Address tab
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98, 57
+<BR> &nbsp; &nbsp; &nbsp; Windows NT, 67
+<BR>IP packet size, tuning, 316
+<P><A NAME="J"><B>J</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>Jacobson, Van, 255
+<P><A NAME="K"><B>K</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>keep-alive packets, option for, 242
+<BR>Kerberos, support for, 35
+<BR>kernel oplocks option, 153
+<P><A NAME="L"><B>L</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>languages, non-European, 30
+<BR>LDAP (Lightweight Directory Access Protocol)
+<BR> &nbsp; &nbsp; &nbsp; replacement for password synchronization, 179
+<BR> &nbsp; &nbsp; &nbsp; support for, 36
+<BR>ldd tool, 33
+<BR>legal agreements covering multi-user functionality, 6
+<BR>Leres, Craig, 255
+<BR>Lightweight Directory Access Protocol (see LDAP)
+<BR>line continuation, 85
+<BR>links, 130
+<BR> &nbsp; &nbsp; &nbsp; option for, 133
+<BR>Linux
+<BR> &nbsp; &nbsp; &nbsp; installing Samba on Linux system, 31
+<BR> &nbsp; &nbsp; &nbsp; submount and, 36
+<BR>lm announce option, 125
+<BR>lm interval option, 125
+<BR>LMHOSTS file, 224
+<BR>load printers option, 222
+<BR>local group map option, 192
+<BR>local master browser, 21, 116-122
+<BR> &nbsp; &nbsp; &nbsp; checking machines for, 118
+<BR> &nbsp; &nbsp; &nbsp; option for, 125
+<BR>local master option, 125
+<BR>local profiles, 194
+<BR>localhost
+<BR> &nbsp; &nbsp; &nbsp; address, 69
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 288
+<BR>localization, 234-236
+<BR>lock directory option, 154
+<BR>locking option, 152
+<BR>locks/locking files, 9, 149-154
+<BR> &nbsp; &nbsp; &nbsp; messaging option for, 237
+<BR> &nbsp; &nbsp; &nbsp; opportunistic locking, 29
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tuning of, 316
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (see also oplocks)
+<BR> &nbsp; &nbsp; &nbsp; options for, 151-154
+<BR> &nbsp; &nbsp; &nbsp; Unix and, 150
+<BR>log files/logging
+<BR> &nbsp; &nbsp; &nbsp; activating/deactivating, 253
+<BR> &nbsp; &nbsp; &nbsp; checking, 108-113
+<BR> &nbsp; &nbsp; &nbsp; configuration options, 108-113
+<BR> &nbsp; &nbsp; &nbsp; in for the first time (Samba), 52
+<BR> &nbsp; &nbsp; &nbsp; levels of
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setting, 251-253
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tuning, 314
+<BR> &nbsp; &nbsp; &nbsp; options for, 199
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 282
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting from, 251-254
+<BR>log level option, 112, 251, 314
+<BR>login dialog box, domain logons
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98, 188
+<BR> &nbsp; &nbsp; &nbsp; Windows NT, 190
+<BR>login parameters, setting, 79
+<BR>logon drive option, 197
+<BR>logon home option, 198
+<BR>logon path option, 197
+<BR>logon script option, 197
+<BR>logon scripts, 192-200
+<BR> &nbsp; &nbsp; &nbsp; options for, 196-198
+<BR>logons (see domain logons)
+<BR>lppause command option, 221
+<BR>lpq cache time option, 220, 319
+<BR>lpq command option, 221
+<BR>lpresume command option, 221
+<BR>lprm command option, 221
+<P><A NAME="M"><B>M</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>machine name, types, 15
+<BR>machine password timeout option, 239
+<BR>magic output option, 233
+<BR>magic script option, 233
+<BR>magic scripts, 233
+<BR>mailing lists
+<BR> &nbsp; &nbsp; &nbsp; posting to, 39
+<BR> &nbsp; &nbsp; &nbsp; for Samba, 292
+<BR>main tree, 40
+<BR>makefiles, 33-34
+<BR>mandatory profiles, 196
+<BR>mangle case option, 148
+<BR>mangled map option, 148
+<BR>mangled names option, 147
+<BR>mangled stack option, 148
+<BR>mangling char option, 148
+<BR>map archive option, 142
+<BR>map hidden option, 142
+<BR>Map Network Drive option, 5, 62
+<BR>map system option, 142
+<BR>mapping
+<BR> &nbsp; &nbsp; &nbsp; files, options for location of, 191
+<BR> &nbsp; &nbsp; &nbsp; network drives, 5
+<BR>masks
+<BR> &nbsp; &nbsp; &nbsp; creation, 138
+<BR> &nbsp; &nbsp; &nbsp; netmasks, 57
+<BR> &nbsp; &nbsp; &nbsp; subnet, 57, 67
+<BR> &nbsp; &nbsp; &nbsp; umasks, 138
+<BR>master browsers (see local master browser; DMB; preferred master browser)
+<BR>max connections option, 161
+<BR>max disk size option, 242
+<BR>max log size option, 112
+<BR>max mux option, 243
+<BR>max open files option, 243
+<BR>max ttl option, 229
+<BR>max wins ttl option, 229
+<BR>max xmit option, 243, 317
+<BR>Maximum Transport Unit (MTU), 316
+<BR>McCanne, Steven, 255
+<BR>measurement forms, 326
+<BR>memory, status of, 9
+<BR>message command option, 238
+<BR>messages
+<BR> &nbsp; &nbsp; &nbsp; from daemons, reading, 8
+<BR> &nbsp; &nbsp; &nbsp; WinPopup, 237
+<BR>Microsoft, 3
+<BR> &nbsp; &nbsp; &nbsp; encryption, 30
+<BR> &nbsp; &nbsp; &nbsp; implementations, 18-27
+<BR>Microsoft Networking Client, 65
+<BR>min print space option, 223
+<BR>min wins ttl option, 229
+<BR>mirror sites for Samba distribution, 28
+<BR>MIT, 35
+<BR>mmap code, 36
+<BR>m-node, 13
+<BR>modem, linking to TCP/IP networking protocol, 55
+<BR>MTU (Maximum Transport Unit), 316
+<BR>multiple code pages, 30
+<BR>multiple subnets, 120
+<BR>multi-user functionality, legal agreements and, 6
+<BR>My Computer (Windows 95/98), 51
+<P><A NAME="N"><B>N</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>name mangling, 143-149
+<BR> &nbsp; &nbsp; &nbsp; options for, 145-149
+<BR> &nbsp; &nbsp; &nbsp; steps in, 143
+<BR>name registration, 10
+<BR>name resolution, 11, 60, 224-229
+<BR> &nbsp; &nbsp; &nbsp; options for, 227-229
+<BR>name resolve order option, 229
+<BR>name services, 10
+<BR> &nbsp; &nbsp; &nbsp; identifying what is in use, 283
+<BR> &nbsp; &nbsp; &nbsp; nmblookup program, 372
+<BR> &nbsp; &nbsp; &nbsp; testing, 258
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 282-288
+<BR>naming
+<BR> &nbsp; &nbsp; &nbsp; machine name, types, 15
+<BR> &nbsp; &nbsp; &nbsp; machines on NetBIOS network, 10-13
+<BR> &nbsp; &nbsp; &nbsp; NT computers, 63
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; caution with, 64
+<BR> &nbsp; &nbsp; &nbsp; TCP/IP networking protocol, setting machine name for, 60
+<BR>NBNS (see NetBIOS, name server)
+<BR>NBT standard, 10
+<BR>NBTSTAT utility, 15
+<BR>Netatalk (Macintosh), support for interoperating with, 37
+<BR>NetBEUI (NetBIOS Extended User Interface), 10, 53
+<BR> &nbsp; &nbsp; &nbsp; Windows NT computers and, 65
+<BR>netbios aliases option, 107
+<BR>NetBIOS name, 14-16
+<BR> &nbsp; &nbsp; &nbsp; option for aliases, 107
+<BR> &nbsp; &nbsp; &nbsp; setting
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Windows 95/98, 61
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Windows NT, 63
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 290
+<BR>netbios name option, 95
+<BR>NetBIOS (Network Basic Input/Output System), 9
+<BR> &nbsp; &nbsp; &nbsp; compared with TCP/IP, 10
+<BR> &nbsp; &nbsp; &nbsp; Extended User Interface (see NetBEUI)
+<BR> &nbsp; &nbsp; &nbsp; multiple servers (see virtual servers)
+<BR> &nbsp; &nbsp; &nbsp; name (see NetBIOS name)
+<BR> &nbsp; &nbsp; &nbsp; name server (NBNS), 11, 25, 58
+<BR> &nbsp; &nbsp; &nbsp; network, naming machines on, 10-13
+<BR> &nbsp; &nbsp; &nbsp; over TCP/IP, 10
+<BR> &nbsp; &nbsp; &nbsp; Unique Resource Types, 15
+<BR>netmasks, 57, 67
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 288
+<BR>network addresses
+<BR> &nbsp; &nbsp; &nbsp; finding, 290
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting, 288-290
+<BR>Network Basic Input/Output System (see NetBIOS)
+<BR>network configuration commands, 192
+<BR>Network dialog box (Windows NT), 63
+<BR>network drives, mapping, 5
+<BR>Network File System
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 293
+<BR>Network File System (NFS), 30
+<BR>Network icon
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98, 53
+<BR> &nbsp; &nbsp; &nbsp; Windows NT, 63
+<BR>network masks (see netmasks)
+<BR>Network Neighborhood icon, 61, 93
+<BR> &nbsp; &nbsp; &nbsp; viewing Samba server, 72
+<BR>Network Neighborhood window, 21-22
+<BR> &nbsp; &nbsp; &nbsp; mapping network drives via, 5
+<BR>networking
+<BR> &nbsp; &nbsp; &nbsp; hardware for, testing, 259
+<BR> &nbsp; &nbsp; &nbsp; network address ranges, 289
+<BR> &nbsp; &nbsp; &nbsp; nmblookup program, testing with, 279
+<BR> &nbsp; &nbsp; &nbsp; options, 101-106
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list of, 103
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; magic script, 233
+<BR> &nbsp; &nbsp; &nbsp; printing on a network, steps in, 201
+<BR> &nbsp; &nbsp; &nbsp; setting up, 53-60
+<BR>newsgroups for Samba, 291
+<BR>NFS (Network File System), 30
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 293
+<BR>nis homedir option, 200
+<BR>NIS/NIS+ protocol, 36, 169
+<BR> &nbsp; &nbsp; &nbsp; how Samba works with, 199
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 293
+<BR>nmbd daemon, 2, 29, 82, 85, 361-362
+<BR> &nbsp; &nbsp; &nbsp; browsing options for, 125
+<BR> &nbsp; &nbsp; &nbsp; killing, 48
+<BR> &nbsp; &nbsp; &nbsp; starting, 46
+<BR>nmblookup program, 372
+<BR> &nbsp; &nbsp; &nbsp; networks, testing with, 279
+<BR>node types, 13
+<BR>non-encrypted passwords, 172
+<BR>non-European languages, 30
+<BR>Novell Networking, 53
+<BR>nt pipe support option, 243
+<BR>nt smb support option, 243
+<BR>null passwords, 183
+<BR>null TID, 74
+<BR>numerical type, 90
+<P><A NAME="O"><B>O</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>.old files, 39
+<BR>ole locking compatibility option, 244
+<BR>Open Source Software (OSS), 3
+<BR>operating systems
+<BR> &nbsp; &nbsp; &nbsp; encrypted/non-encrypted passwords, 172
+<BR> &nbsp; &nbsp; &nbsp; miscellaneous options for, 240
+<BR> &nbsp; &nbsp; &nbsp; values in elections, 117
+<BR>oplock files option, 316
+<BR>oplocks, 149-154
+<BR> &nbsp; &nbsp; &nbsp; break requests, 149
+<BR> &nbsp; &nbsp; &nbsp; messaging option for, 237
+<BR> &nbsp; &nbsp; &nbsp; options for, 151-154
+<BR>oplocks option, 153
+<BR>opportunistic locking, 29
+<BR> &nbsp; &nbsp; &nbsp; tuning, 316
+<BR> &nbsp; &nbsp; &nbsp; (see also oplocks)
+<BR>option names, 84
+<BR>os filetime resolution option, 232
+<BR>os level option, 126
+<BR>OS/2, support for share-level security, 165
+<BR>OSF/1 (Digital Unix), 35
+<P><A NAME="P"><B>P</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>packets
+<BR> &nbsp; &nbsp; &nbsp; headers for, tcpdump utility and, 376
+<BR> &nbsp; &nbsp; &nbsp; maximum size of, option for, 243
+<BR>PAM (pluggable authentication modules), 179
+<BR> &nbsp; &nbsp; &nbsp; support for, 36
+<BR>panic action option, 244
+<BR>passwd chat debug option, 182
+<BR>passwd chat option, 182
+<BR>passwd program option, 182
+<BR>password file, security and, 53
+<BR>password level option, 182
+<BR>Password settings (Windows 95/98), 51
+<BR>passwords, 171-184
+<BR> &nbsp; &nbsp; &nbsp; chat characters for, 178
+<BR> &nbsp; &nbsp; &nbsp; encrypted
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; changing, 176
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; disabling on Windows computers, 173
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vs. non-encrypted, 172, 173
+<BR> &nbsp; &nbsp; &nbsp; null, 183
+<BR> &nbsp; &nbsp; &nbsp; options for, 180-184
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; share-level, 192
+<BR> &nbsp; &nbsp; &nbsp; passwd program, 182
+<BR> &nbsp; &nbsp; &nbsp; smbpasswd program, 374
+<BR> &nbsp; &nbsp; &nbsp; stored by Samba, 172
+<BR> &nbsp; &nbsp; &nbsp; synchronizing, 176-179
+<BR> &nbsp; &nbsp; &nbsp; user-level security and, 168
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98, 51-53
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; changing, 52
+<BR>pathnames
+<BR> &nbsp; &nbsp; &nbsp; option for, 98
+<BR> &nbsp; &nbsp; &nbsp; printer configuration and, 207
+<BR>paths, architecture-specific, 86
+<BR>pdate encrypted option, 183
+<BR>PDC (primary domain controller), 20
+<BR> &nbsp; &nbsp; &nbsp; domain master browser and, 119
+<BR> &nbsp; &nbsp; &nbsp; domain option for, 190
+<BR> &nbsp; &nbsp; &nbsp; domain-level security and, 164
+<BR>PDC (continued)
+<BR> &nbsp; &nbsp; &nbsp; Samba 2.1 and, 186
+<BR> &nbsp; &nbsp; &nbsp; Samba, setting up as, 184
+<BR> &nbsp; &nbsp; &nbsp; sever-level security and, 168
+<BR> &nbsp; &nbsp; &nbsp; trust accounts and, 186
+<BR>performance, 29
+<BR>performance tuning, 312-328
+<BR> &nbsp; &nbsp; &nbsp; benchmark for, 312, 314
+<BR> &nbsp; &nbsp; &nbsp; other options for, 319-328
+<BR> &nbsp; &nbsp; &nbsp; recommended enhancements, 320
+<BR>permissions, 207
+<BR> &nbsp; &nbsp; &nbsp; options for, 140-143
+<BR> &nbsp; &nbsp; &nbsp; for printing, 207
+<BR>plaintext passwords, 173
+<BR>pluggable authentication modules (PAM), 36, 179
+<BR>p-node, 13
+<BR>point-to-point communication, 13
+<BR>point-to-point registration/resolution, 13
+<BR>port not telnet option, 257
+<BR>postexec option, 199
+<BR>postscript option, 221
+<BR>preexec option, 199
+<BR>preferred master browser, 119
+<BR>preferred master option, 126
+<BR>preserve case option, 147
+<BR>preventing browsing, 115
+<BR>primary domain controller (see PDC)
+<BR>primary WINS server, 26
+<BR>print command option, 221
+<BR>print queue, options for, 223
+<BR>print shares, 7-9, 89-90, 204-205
+<BR> &nbsp; &nbsp; &nbsp; created by Samba, 205
+<BR> &nbsp; &nbsp; &nbsp; options for, 222
+<BR> &nbsp; &nbsp; &nbsp; path option, 98
+<BR> &nbsp; &nbsp; &nbsp; setting up on Windows client, 7
+<BR>printable option, 219
+<BR>printcap name option, 223
+<BR>printer capabilities file, 89
+<BR>printer driver file option, 219
+<BR>printer driver location option, 220
+<BR>printer driver option, 219
+<BR>printer option, 219
+<BR>PRINTER$ share, creating, 212
+<BR>printers
+<BR> &nbsp; &nbsp; &nbsp; BSD, 215
+<BR> &nbsp; &nbsp; &nbsp; names
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; caution with, 205
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; checking, 375
+<BR> &nbsp; &nbsp; &nbsp; option for, 219-221
+<BR> &nbsp; &nbsp; &nbsp; sharing (see print shares)
+<BR> &nbsp; &nbsp; &nbsp; System V, 216
+<BR>printing, 201-224
+<BR> &nbsp; &nbsp; &nbsp; commands, 202
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default commands for, 221
+<BR> &nbsp; &nbsp; &nbsp; configuration, minimal, 203-205
+<BR> &nbsp; &nbsp; &nbsp; configuration options, 203-207
+<BR> &nbsp; &nbsp; &nbsp; drivers for, setting up, 210-213
+<BR> &nbsp; &nbsp; &nbsp; on a network, steps in, 201
+<BR> &nbsp; &nbsp; &nbsp; options for, 217-224
+<BR> &nbsp; &nbsp; &nbsp; pathnames used in commands for, 207
+<BR> &nbsp; &nbsp; &nbsp; permissions for, 207
+<BR> &nbsp; &nbsp; &nbsp; print jobs, 204
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spooling with smbprint tool, 213
+<BR> &nbsp; &nbsp; &nbsp; printer definition file, 211
+<BR> &nbsp; &nbsp; &nbsp; resources for information on debugging, 208
+<BR> &nbsp; &nbsp; &nbsp; through Samba, 201-213
+<BR> &nbsp; &nbsp; &nbsp; test for, 206
+<BR> &nbsp; &nbsp; &nbsp; types, 218
+<BR> &nbsp; &nbsp; &nbsp; variables for, 203
+<BR> &nbsp; &nbsp; &nbsp; Windows client printers
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printing to, 213-224
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setting up and testing, 208
+<BR>printing configuration option, 218
+<BR>private directory (Samba distribution), 172
+<BR>private key cryptography, 35
+<BR>privileges, option for, 199
+<BR>processes (see daemons)
+<BR>profiles, 194
+<BR> &nbsp; &nbsp; &nbsp; creating, 53
+<BR> &nbsp; &nbsp; &nbsp; local, 194
+<BR> &nbsp; &nbsp; &nbsp; mandatory, 196
+<BR> &nbsp; &nbsp; &nbsp; roaming, 194-196
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; option for location of, 197
+<BR>programmers, support for, 230-233
+<BR>propagation, browse list, 24
+<BR>Properties button (Windows 95/98), 55
+<BR>protocols
+<BR> &nbsp; &nbsp; &nbsp; routed through a hardware device, 53
+<BR> &nbsp; &nbsp; &nbsp; variant, negotiating, 78
+<BR>Protocols tab, 65-66
+<P><A NAME="Q"><B>Q</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>queuepause command option, 223
+<BR>queueresume command option, 223
+<BR>quotation marks in values, 84
+<P><A NAME="R"><B>R</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>rc.local file, 47
+<BR>read list option, 161
+<BR>read only option, 100
+<BR>read prediction, testing, 318
+<BR>read raw, tuning, 315
+<BR>read size, tuning, 318
+<BR>reading documentation, importance of, 34
+<BR>read-only files, 136
+<BR> &nbsp; &nbsp; &nbsp; deleting, 139, 142
+<BR>read-only partitions, 40
+<BR>read-only/read-write access, 159
+<BR>remote announce option, 127
+<BR>remote browse sync option, 127
+<BR>remote procedure call (RPC), 376
+<BR>representing/resolving filenames, 145
+<BR>resource names, 14
+<BR>resource types, 14
+<BR> &nbsp; &nbsp; &nbsp; for primary domain controller vs. domain master browser, 24
+<BR>resources, connecting to, 81
+<BR>resources for further information, 291-293
+<BR> &nbsp; &nbsp; &nbsp; group attributes, 16
+<BR> &nbsp; &nbsp; &nbsp; NFS (Network File System), 293
+<BR> &nbsp; &nbsp; &nbsp; printers, debugging, 208
+<BR> &nbsp; &nbsp; &nbsp; Samba, 32
+<BR> &nbsp; &nbsp; &nbsp; Solaris servers, 321
+<BR> &nbsp; &nbsp; &nbsp; Windows network configuration commands, 192
+<BR>revalidation of users, 192
+<BR>roaming profiles, 194-196
+<BR> &nbsp; &nbsp; &nbsp; option for location of, 197
+<BR>role settings in elections, 117
+<BR>root postexec option, 199
+<BR>root preexec option, 198
+<BR>root user, 37, 199
+<BR> &nbsp; &nbsp; &nbsp; access, 159
+<BR>routers, TCP/IP configuring and, 68
+<BR>RPC (remote procedure call), 376
+<BR>rpcclient program, 376
+<P><A NAME="S"><B>S</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>SAM (security account manager), 19, 169
+<BR>Samba, 1-9
+<BR> &nbsp; &nbsp; &nbsp; compatibility with Windows NT, 30
+<BR> &nbsp; &nbsp; &nbsp; compiling (see compiling Samba)
+<BR> &nbsp; &nbsp; &nbsp; configuring (see configuring Samba)
+<BR> &nbsp; &nbsp; &nbsp; daemons (see daemons)
+<BR> &nbsp; &nbsp; &nbsp; distribution, xi, 28, 32
+<BR> &nbsp; &nbsp; &nbsp; documentation, importance of reading, 34
+<BR> &nbsp; &nbsp; &nbsp; downloading, 32-34
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; with CVS, 378
+<BR> &nbsp; &nbsp; &nbsp; features/uses, x
+<BR> &nbsp; &nbsp; &nbsp; installing (see installing Samba)
+<BR> &nbsp; &nbsp; &nbsp; logging in for the first time, 52
+<BR> &nbsp; &nbsp; &nbsp; Microsoft encryption and, 30
+<BR> &nbsp; &nbsp; &nbsp; new features file, 34
+<BR> &nbsp; &nbsp; &nbsp; origin of name, 2
+<BR> &nbsp; &nbsp; &nbsp; performance tuning, 312-328
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; benchmark for, 312, 314
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; other options for, 319-328
+<BR> &nbsp; &nbsp; &nbsp; reasons for using, 3
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 291-293
+<BR> &nbsp; &nbsp; &nbsp; roles in Windows domains/workgroups, 26
+<BR> &nbsp; &nbsp; &nbsp; startup file, 363
+<BR> &nbsp; &nbsp; &nbsp; test utilities, 254-257
+<BR> &nbsp; &nbsp; &nbsp; version 2.0, 20, 28
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; character sets, 235
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code pages for, 234
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; coding system parameters, 235
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new options, 238
+<BR> &nbsp; &nbsp; &nbsp; version 2.0.5, xi, 28
+<BR> &nbsp; &nbsp; &nbsp; version 2.1, 20
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PDC functionality and, 186
+<BR> &nbsp; &nbsp; &nbsp; web site, 32, 291
+<BR> &nbsp; &nbsp; &nbsp; WINS server and, 225
+<BR>Samba server
+<BR> &nbsp; &nbsp; &nbsp; accessing, 61
+<BR> &nbsp; &nbsp; &nbsp; connecting to, 71
+<BR> &nbsp; &nbsp; &nbsp; resources offered, 72
+<BR> &nbsp; &nbsp; &nbsp; sizing, 320-328
+<BR> &nbsp; &nbsp; &nbsp; viewing via Network Neighborhood icon, 72
+<BR>Samba Web Administration Tool (see SWAT tool)
+<BR>scripts
+<BR> &nbsp; &nbsp; &nbsp; connection, 198
+<BR> &nbsp; &nbsp; &nbsp; logon, 192-200
+<BR> &nbsp; &nbsp; &nbsp; magic, 233
+<BR> &nbsp; &nbsp; &nbsp; for Samba startup file, 363
+<BR>secondary WINS server, 26
+<BR>sections of smb.conf (Samba configuration) file, 83
+<BR>Secure Sockets Layer protocol (see SSL)
+<BR>security, 35, 164-171
+<BR> &nbsp; &nbsp; &nbsp; domain-level, 169-171
+<BR> &nbsp; &nbsp; &nbsp; levels of, 164
+<BR>security (continued)
+<BR> &nbsp; &nbsp; &nbsp; options for, 164
+<BR> &nbsp; &nbsp; &nbsp; restricting access to shares, 158-163
+<BR> &nbsp; &nbsp; &nbsp; server-level, 168
+<BR> &nbsp; &nbsp; &nbsp; share-level, 164-167
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; options for, 167
+<BR> &nbsp; &nbsp; &nbsp; user-level, 167
+<BR>security account manager (SAM), 19, 169
+<BR>Select Network Protocol dialog box, 65
+<BR>server configuration options, 94-96
+<BR>Server Message Block (see SMB)
+<BR>server string parameter, 95
+<BR>server-level security, 168
+<BR>servers
+<BR> &nbsp; &nbsp; &nbsp; active, list of, 116
+<BR> &nbsp; &nbsp; &nbsp; testing with nmblookup program, 278
+<BR> &nbsp; &nbsp; &nbsp; virtual, 106-108
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; options for, 107
+<BR>service bindings, 71
+<BR>services, 83
+<BR> &nbsp; &nbsp; &nbsp; list of enabled on machine, 45
+<BR> &nbsp; &nbsp; &nbsp; performed by Samba, 2
+<BR> &nbsp; &nbsp; &nbsp; testing low-level, 257-263
+<BR> &nbsp; &nbsp; &nbsp; Workstation, 65
+<BR> &nbsp; &nbsp; &nbsp; (see also shares)
+<BR>Services tab, 65
+<BR>session layer, connection at, 78
+<BR>session parameters, setting, 79
+<BR>session service, 10, 16-18
+<BR>set directory option, 244
+<BR>share modes, 151
+<BR>share options, 90
+<BR>shared directory/resources (see shares)
+<BR>shared resources (see shares)
+<BR>share-level security, 164-167
+<BR> &nbsp; &nbsp; &nbsp; options for, 167
+<BR> &nbsp; &nbsp; &nbsp; printing and guest accounts, 204
+<BR> &nbsp; &nbsp; &nbsp; steps in taken by Samba, 165
+<BR>shares, 30, 83
+<BR> &nbsp; &nbsp; &nbsp; access to
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; controlling, 158-163
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; creating for groups, 157
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; by foreign hosts, option for, 184
+<BR> &nbsp; &nbsp; &nbsp; contents, restricting view of, 115
+<BR> &nbsp; &nbsp; &nbsp; default, 115
+<BR> &nbsp; &nbsp; &nbsp; file, path option for, 98
+<BR> &nbsp; &nbsp; &nbsp; [globals] section, 88
+<BR> &nbsp; &nbsp; &nbsp; option for identifying users allowed access to, 168
+<BR> &nbsp; &nbsp; &nbsp; viewing (see browsing)
+<BR>sharing
+<BR> &nbsp; &nbsp; &nbsp; disks (see disk shares)
+<BR> &nbsp; &nbsp; &nbsp; printers (see print shares)
+<BR>Sharpe, Richard, 74
+<BR>SIGHUP signal, 85
+<BR>sizing Samba servers, 320-328
+<BR>smb passwd file option, 183
+<BR>SMB (Server Message Block), 2, 74-81
+<BR> &nbsp; &nbsp; &nbsp; command string, 75
+<BR> &nbsp; &nbsp; &nbsp; commercial products for, 77
+<BR> &nbsp; &nbsp; &nbsp; deny-mode locks, 151
+<BR> &nbsp; &nbsp; &nbsp; format of, 74
+<BR> &nbsp; &nbsp; &nbsp; header, 75
+<BR> &nbsp; &nbsp; &nbsp; magic scripts, 233
+<BR> &nbsp; &nbsp; &nbsp; making a simple connection, 77
+<BR> &nbsp; &nbsp; &nbsp; maximum number of operations, option for, 243
+<BR> &nbsp; &nbsp; &nbsp; networks, 4
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; usernames and, 162
+<BR> &nbsp; &nbsp; &nbsp; option for NT-specific options, 243
+<BR> &nbsp; &nbsp; &nbsp; password server, 168
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 74
+<BR> &nbsp; &nbsp; &nbsp; seamless operation across networks, 30
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting connections, 268-275
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testing locally, 268
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testing with NET USE, 271-274
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testing with smbclient, 270
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; testing with Windows Explorer, 274-275
+<BR> &nbsp; &nbsp; &nbsp; wrapper support, 34
+<BR>SMB/CIFS protocol, 3
+<BR> &nbsp; &nbsp; &nbsp; filesystems, 34
+<BR> &nbsp; &nbsp; &nbsp; network and, 9-18
+<BR>smbclient program, 49, 364-370
+<BR>smb.conf (Samba configuration) file, 8, 41, 63, 82-93
+<BR> &nbsp; &nbsp; &nbsp; configuring printers, 203
+<BR> &nbsp; &nbsp; &nbsp; creating, 93
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for each client, 253
+<BR> &nbsp; &nbsp; &nbsp; example of, 82
+<BR> &nbsp; &nbsp; &nbsp; modifying for printer drivers, 212
+<BR> &nbsp; &nbsp; &nbsp; options for, 90-93
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; format of, 83
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; supporting programmers, 230-232
+<BR> &nbsp; &nbsp; &nbsp; special sections of, 88-91
+<BR> &nbsp; &nbsp; &nbsp; structure of, 83-86
+<BR> &nbsp; &nbsp; &nbsp; testparm program for, 375
+<BR> &nbsp; &nbsp; &nbsp; variables for, 86-88
+<BR>smbd daemon, 2, 82, 359-360
+<BR> &nbsp; &nbsp; &nbsp; file, 47
+<BR> &nbsp; &nbsp; &nbsp; killing, 48
+<BR> &nbsp; &nbsp; &nbsp; starting, 46
+<BR>smbd server, checking with telnet, 266
+<BR>smbmount, support for, 36
+<BR>smbpasswd file, 172, 174-176
+<BR> &nbsp; &nbsp; &nbsp; adding entries to, 175
+<BR> &nbsp; &nbsp; &nbsp; caution with, 173-174
+<BR> &nbsp; &nbsp; &nbsp; option for location of, 183
+<BR>smbpasswd program, 171, 374
+<BR> &nbsp; &nbsp; &nbsp; changing passwords with, 176
+<BR>smbprint tool, spooling print jobs, 213
+<BR>smbrun option, 244
+<BR>smbsh program, 364
+<BR>smbstatus program, 8, 370
+<BR>smbtar program, 245-248
+<BR> &nbsp; &nbsp; &nbsp; tar operations and, 371
+<BR>smbwrapper client, 30
+<BR>smbwrapper package, 35
+<BR>socket address option, 106
+<BR>socket options configuration options, 314
+<BR>software distribution (see Samba, distribution)
+<BR>source vs. binary files, 32
+<BR>spaces in values, 84
+<BR>special sections, smb.conf (Samba configuration) file, 88-91
+<BR>spelling, caution with, 61
+<BR>spool space, options for, 223
+<BR>square brackets, 83
+<BR>ssl CA certDir option, 308
+<BR>ssl CA certFile option, 308
+<BR>ssl ciphers option, 310
+<BR>ssl client cert option, 309
+<BR>ssl client key option, 309
+<BR>ssl compatibility option, 311
+<BR>ssl hosts option, 307
+<BR>ssl hosts resign option, 307
+<BR>ssl option, 307
+<BR>ssl require clientcert option, 309
+<BR>ssl require servercert option, 310
+<BR>SSL (Secure Sockets Layer) protocol, 30
+<BR> &nbsp; &nbsp; &nbsp; configuration options for, 306-311
+<BR> &nbsp; &nbsp; &nbsp; configuring Samba to use, 300
+<BR> &nbsp; &nbsp; &nbsp; configuring Samba with, 295-311
+<BR> &nbsp; &nbsp; &nbsp; SS Proxy, 296
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setting up, 304
+<BR> &nbsp; &nbsp; &nbsp; SSLeay, 296-304
+<BR> &nbsp; &nbsp; &nbsp; support for, 34, 36
+<BR>ssl server cert option, 308
+<BR>ssl server key option, 308
+<BR>ssl version option, 310
+<BR>stand-alone daemons, 47
+<BR>stat cache option, 239
+<BR>stat cache size option, 239
+<BR>status option, 244
+<BR>status report on Samba, 8
+<BR>strict locking option, 152, 319
+<BR>strict sync option, 245, 319
+<BR>string types, 90
+<BR>strip dot option, 245
+<BR>subnets, 12
+<BR> &nbsp; &nbsp; &nbsp; hosts and, caution with, 102
+<BR> &nbsp; &nbsp; &nbsp; mask, 57, 67
+<BR> &nbsp; &nbsp; &nbsp; multiple spanned by Windows workgroups, 24
+<BR> &nbsp; &nbsp; &nbsp; Windows NT workstations and, 24
+<BR>superuser (see root user)
+<BR>SWAT tool, 29
+<BR> &nbsp; &nbsp; &nbsp; adding to configuration files, 41
+<BR> &nbsp; &nbsp; &nbsp; creating configuration file with, 42
+<BR>sync always option, 245, 319
+<BR>synchronizing
+<BR> &nbsp; &nbsp; &nbsp; passwords, 176-179
+<BR> &nbsp; &nbsp; &nbsp; time, options for, 231
+<BR>syntax errors, 45
+<BR>syslog only option, 113
+<BR>syslog option, 113
+<BR>SYSLOG utility, 110
+<BR> &nbsp; &nbsp; &nbsp; support for, 36
+<BR>system administrator, WINS server and, 26
+<BR>system files, 136
+<BR>System V Unix, 47
+<BR> &nbsp; &nbsp; &nbsp; printer configuration for, 203
+<P><A NAME="T"><B>T</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>tar operations, 371
+<BR>tcpdump utility, 78, 255-257, 376
+<BR> &nbsp; &nbsp; &nbsp; passwords, reading, 172
+<BR>TCP/IP networking protocol, 9
+<BR> &nbsp; &nbsp; &nbsp; adding/configuring, 54
+<BR> &nbsp; &nbsp; &nbsp; checking setup, 53
+<BR> &nbsp; &nbsp; &nbsp; compared with NetBIOS, 10
+<BR> &nbsp; &nbsp; &nbsp; configuring, 66-71
+<BR> &nbsp; &nbsp; &nbsp; installing, 65
+<BR> &nbsp; &nbsp; &nbsp; NetBIOS over, 10
+<BR> &nbsp; &nbsp; &nbsp; receive window, tuning, 317
+<BR> &nbsp; &nbsp; &nbsp; resources for further information, 293
+<BR> &nbsp; &nbsp; &nbsp; TCP, troubleshooting, 263
+<BR>TCP/IP Properties panel (Windows 95/98), 55
+<BR>test parser, 45
+<BR>test share, 42
+<BR>testing
+<BR> &nbsp; &nbsp; &nbsp; configuration file, 45
+<BR> &nbsp; &nbsp; &nbsp; daemons, 49
+<BR> &nbsp; &nbsp; &nbsp; Samba, 41-46
+<BR> &nbsp; &nbsp; &nbsp; smbclient program, 364-370
+<BR> &nbsp; &nbsp; &nbsp; test utilities for Samba, 254-257
+<BR> &nbsp; &nbsp; &nbsp; tools for (CD-ROM with this book), 28
+<BR>testparm program, 375
+<BR>testparm test parser, 45
+<BR>testprns program, 375
+<BR>TID (tree identifier), 74, 78, 80
+<BR>time server option, 231
+<BR>time synchronization, options for, 231
+<BR>time to live (TTL), options for, 229
+<BR>timestamp logs option, 112
+<BR>trace utility, 254
+<BR>trailing dot, option for, 245
+<BR>tree identifier (TID), 74, 78, 80
+<BR>Tridgell, Andrew, 2, 255
+<BR>troubleshooting, 250-291
+<BR> &nbsp; &nbsp; &nbsp; information to have on hand, 257
+<BR> &nbsp; &nbsp; &nbsp; network addresses, 288-290
+<BR> &nbsp; &nbsp; &nbsp; where to start, 250
+<BR>trust accounts, creating, 186
+<BR>TTL (time to live), options for, 229
+<BR>tuning (see performance tuning)
+<P><A NAME="U"><B>U</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>umasks, 138
+<BR>uniform resource locators (URLs), 6
+<BR>Universal Naming Convention (UNC), 5
+<BR>Unix
+<BR> &nbsp; &nbsp; &nbsp; carriage returns, 193
+<BR> &nbsp; &nbsp; &nbsp; daemons, 2
+<BR> &nbsp; &nbsp; &nbsp; file permissions and attributes, 135-143
+<BR> &nbsp; &nbsp; &nbsp; filenames, option for, 245
+<BR> &nbsp; &nbsp; &nbsp; locks and, 150
+<BR> &nbsp; &nbsp; &nbsp; networks, usernames and, 162
+<BR> &nbsp; &nbsp; &nbsp; options
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for messaging, 237
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; miscellaneous, 240
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for print commands, 221
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for system logger, 113
+<BR> &nbsp; &nbsp; &nbsp; password files, 169
+<BR> &nbsp; &nbsp; &nbsp; permissions, share write access and, 159
+<BR> &nbsp; &nbsp; &nbsp; servers, backing up computers from, 246
+<BR> &nbsp; &nbsp; &nbsp; System V, 47
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printer configuration for, 203
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printing and, 29
+<BR> &nbsp; &nbsp; &nbsp; troubleshooting utilities, 254
+<BR> &nbsp; &nbsp; &nbsp; user classifications, 135
+<BR>unix password sync option, 180
+<BR>unix realname option, 133
+<BR>URLs (uniform resource locators), 6
+<BR> &nbsp; &nbsp; &nbsp; distribution, 28
+<BR> &nbsp; &nbsp; &nbsp; Kerberos, 35
+<BR> &nbsp; &nbsp; &nbsp; Samba, 28, 32
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distribution, xi
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; web site, 291
+<BR> &nbsp; &nbsp; &nbsp; SMB (Server Message Block), 74
+<BR>use rhosts option, 184
+<BR>user profiles (Windows 95/98), 50
+<BR>user variables, 86
+<BR>user-level security, 164, 167
+<BR>username level option, 163
+<BR>username map option, 162
+<BR>username option, 167
+<BR>usernames
+<BR> &nbsp; &nbsp; &nbsp; case sensitivity and, 163
+<BR> &nbsp; &nbsp; &nbsp; options for, 162-163
+<BR> &nbsp; &nbsp; &nbsp; SMB vs. Unix networks, 162
+<BR> &nbsp; &nbsp; &nbsp; Windows 95/98, 51-53
+<BR>users, 155-158
+<BR> &nbsp; &nbsp; &nbsp; allowing superuser (root) access to, 159
+<BR> &nbsp; &nbsp; &nbsp; creating, 89
+<BR> &nbsp; &nbsp; &nbsp; domain, semi-automatic deletion, 171
+<BR> &nbsp; &nbsp; &nbsp; home directory, 36
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logon script option for location of, 198
+<BR> &nbsp; &nbsp; &nbsp; invalid, specifying, 158
+<BR> &nbsp; &nbsp; &nbsp; read-only/read-write access, 159
+<BR> &nbsp; &nbsp; &nbsp; setting up, 155
+<BR> &nbsp; &nbsp; &nbsp; share-level option for authentication of, 192
+<BR> &nbsp; &nbsp; &nbsp; shares for, setting up, 157
+<BR>/usr/local/samba file, 40
+<BR>/usr/local/samba/var/log.smb file, 49
+<P><A NAME="V"><B>V</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>valid chars option, 236
+<BR>variables, 86-88
+<BR>veto files, 129-131
+<BR> &nbsp; &nbsp; &nbsp; option for deleting, 135
+<BR>veto files option, 134
+<BR>veto oplock files option, 154
+<BR>viewing daemons, 8
+<BR>virtual connection, 78
+<BR>virtual hosts, 29
+<BR>virtual servers, 106-108
+<BR> &nbsp; &nbsp; &nbsp; options for, 107
+<BR>volume option, 100
+<P><A NAME="W"><B>W</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+<BR>Whistle, 3
+<BR>whitespaces in values, 84
+<BR>wide links option, 134, 319
+<BR>Windows 95/98
+<BR> &nbsp; &nbsp; &nbsp; domain controllers for, 18-20
+<BR> &nbsp; &nbsp; &nbsp; domain logons, configuring, 185
+<BR> &nbsp; &nbsp; &nbsp; domains, 184-192
+<BR> &nbsp; &nbsp; &nbsp; miscellaneous options for, 240
+<BR> &nbsp; &nbsp; &nbsp; multiple users, support for, 50
+<BR> &nbsp; &nbsp; &nbsp; passwords, encrypted, 172
+<BR> &nbsp; &nbsp; &nbsp; printer drivers, installing, 210
+<BR> &nbsp; &nbsp; &nbsp; share-level security, support for, 165
+<BR> &nbsp; &nbsp; &nbsp; WinPopup tool, 237
+<BR>Windows clients
+<BR> &nbsp; &nbsp; &nbsp; configuring, 50-81
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Windows NT 4.0 computers, 63-73
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Windows95/98 computers, 50-63
+<BR> &nbsp; &nbsp; &nbsp; individual configuration files for, 253
+<BR> &nbsp; &nbsp; &nbsp; printers for, setting up and testing, 208
+<BR> &nbsp; &nbsp; &nbsp; role settings in elections, 117
+<BR>Windows Explorer, Map Network Drive option, 5
+<BR>Windows Internet Name Service (see WINS)
+<BR>Windows NT
+<BR> &nbsp; &nbsp; &nbsp; client/server and, 77
+<BR> &nbsp; &nbsp; &nbsp; configuring domain logons, 186
+<BR> &nbsp; &nbsp; &nbsp; domains, 18, 28, 184-192
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; caution when selecting, 190
+<BR> &nbsp; &nbsp; &nbsp; IP address, setting, 67
+<BR> &nbsp; &nbsp; &nbsp; naming, caution with, 63
+<BR> &nbsp; &nbsp; &nbsp; passwords
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; encrypted, 172
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new option for timeout (Samba version 2.0), 239
+<BR> &nbsp; &nbsp; &nbsp; pipes, option for, 243
+<BR> &nbsp; &nbsp; &nbsp; server, domain master browser and, 119
+<BR> &nbsp; &nbsp; &nbsp; SMB, option for, 243
+<BR> &nbsp; &nbsp; &nbsp; user authentication and, 186
+<BR> &nbsp; &nbsp; &nbsp; WINS address and, 70
+<BR>Windows NT Server 4.0, 65
+<BR>Windows NT Server Manager for Domains tool, 171
+<BR>Windows NT Workstation 4.0, 65
+<BR>Windows UNC format, 62
+<BR>Windows workgroups (see workgroups, Windows)
+<BR>WINDOWSHOSTS directory, 71
+<BR>WinPopup tool, 237
+<BR>WINS Address tab (Windows NT panel), 70
+<BR>WINS Configuration tab, 58
+<BR>wins proxy option, 228
+<BR>wins server option, 228
+<BR>wins support option, 228
+<BR>WINS (Windows Internet Name Service), 2, 25, 58
+<BR> &nbsp; &nbsp; &nbsp; address, configuring, 70
+<BR> &nbsp; &nbsp; &nbsp; name resolution and, 224
+<BR> &nbsp; &nbsp; &nbsp; options for, 228
+<BR> &nbsp; &nbsp; &nbsp; server, 44
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; configuring Windows domain logons and, 185
+<BR> &nbsp; &nbsp; &nbsp; servers, 25, 59
+<BR> &nbsp; &nbsp; &nbsp; Windows operating systems and, 26
+<BR> &nbsp; &nbsp; &nbsp; WINS server
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; primary/secondary, 26
+<BR>WINS (Windows Internet Name Service) server
+<BR> &nbsp; &nbsp; &nbsp; setting up Samba as, 226
+<BR> &nbsp; &nbsp; &nbsp; setting up Sambato use, 225
+<BR>Wong, Brian, 321
+<BR>workgroup parameter, 96
+<BR>workgroups, 4
+<BR> &nbsp; &nbsp; &nbsp; roles in assumed by Samba, 26
+<BR> &nbsp; &nbsp; &nbsp; setting, 60
+<BR> &nbsp; &nbsp; &nbsp; Windows
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; behaviors vs. Windows domain, 20
+<BR> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spanning multiple subnets, 24
+<BR>working directory, option for, 134
+<BR>Workstation service, installing, 65
+<BR>wrapper support for SMB (Server Message Block), 34
+<BR>write ahead, tuning, 318
+<BR>write list option, 161
+<BR>write privileges, 40
+<BR>write raw, tuning, 315
+<BR>write size, tuning, 317
+<BR>writeable/write ok option, 100
+<P><A NAME="Y"><B>Y</B><A HREF="inx.html">[&nbsp;Top&nbsp;]</A>
+
+<pre>
+</PRE>
+
+<P>
+<HR NOSHADE SIZE="-1">
+<P>
+Using Samba <a href="index.html">Table of Contents</a>
+<P>
+<CENTER>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/docs/htmldocs/using_samba/licenseinfo.html b/docs/htmldocs/using_samba/licenseinfo.html
new file mode 100644
index 00000000000..7e8962a8325
--- /dev/null
+++ b/docs/htmldocs/using_samba/licenseinfo.html
@@ -0,0 +1,181 @@
+<HTML>
+<HEAD>
+<TITLE>License Info</title>
+</head>
+
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font>
+By Robert Eckstein, David Collier-Brown & Peter Kelly
+<br>1st Edition October 1999 (est.)
+<br>1-56592-449-5, Order Number: 4495
+<br>424 pages (est.), $34.95 (est.)
+</font>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+<!--sample chapter begins -->
+<h2>License Info</h2>
+<p>"Using Samba" may be freely reproduced and distributed in any
+form, in any medium physical or electronic, in whole or in
+part, provided that the terms of this license are adhered to
+and that the reproduction includes this license or a reference
+to it. For a complete reproduction of the book, the reference
+should read:
+<blockquote>
+ Copyright (c) 1999 by O'Reilly & Associates. This book,
+ Using Samba, first edition, was written by Robert Eckstein,
+ David Collier-Brown, and Peter Kelly, and published by
+ O'Reilly & Associates. This material may be distributed only
+ subject to the terms and conditions set forth in the
+ license, which is presently available at
+ <a href="http://www.oreilly.com/catalog/samba/licenseinfo.html">
+ http://www.oreilly.com/catalog/samba/licenseinfo.html</a>.
+</blockquote>
+<p>
+For an excerpt, the reference should read:
+<blockquote>
+ Copyright (c) 1999 by O'Reilly & Associates. This material
+ was taken from the book Using Samba, first edition, written
+ by Robert Eckstein, David Collier-Brown, and Peter Kelly,
+ and published by O'Reilly & Associates. This material may be
+ distributed only subject to the terms and conditions set
+ forth in the license, which is presently available at
+ <a href="http://www.oreilly.com/catalog/samba/licenseinfo.html">
+ http://www.oreilly.com/catalog/samba/licenseinfo.html</a>.
+</blockquote>
+<p>
+Translations must contain similar references in the target
+language. A sample model for a reference in a translation is
+the following:
+<blockquote>
+ Copyright (c) 1999 by [whoever owns the translation]. This
+ is a translation of Using Samba, first edition, written by
+ Robert Eckstein, David Collier-Brown, and Peter Kelly, and
+ published by O'Reilly & Associates. This material may be
+ distributed only subject to the terms and conditions set
+ forth in the license, which is presently available at
+ <a href="http://www.oreilly.com/catalog/samba/licenseinfo.html">
+ http://www.oreilly.com/catalog/samba/licenseinfo.html</a>.
+</blockquote>
+<p>
+Both commercial and noncommercial redistribution of material
+from this book is permitted, but the following restrictions
+apply.
+<ol>
+<li> All copies of any version, including derivative works, must
+ display a prominent notice indicating the original authors
+ of the book and that it was originally developed by
+ O'Reilly & Associates. Any publication as a physical
+ (paper) book shall show the names of the authors and
+ O'Reilly & Associates on the outer surface.
+
+<li> Any changes made must be shared as described below.
+
+<li> No translation can be distributed publicly in print form
+ without approval from O'Reilly & Associates. Any
+ translation, by O'Reilly & Associates or another party,
+ falls under the same conditions as the original version.
+</ol>
+<p>
+MODIFIED VERSIONS. Distribution of any modified version must
+include a prominent notice describing the modifications that
+have been made, and must provide a URL or other sufficient
+information concerning how to obtain the original work.
+O'Reilly & Associates and the Samba Team are not responsible
+for the accuracy of any modifications not incorporated into
+their originally distributed version. The names of the
+original authors, O'Reilly & Associates, or the Samba team may
+not be used to assert or imply endorsement of the resulting
+document unless permission is obtained in advance. Anyone who
+distributes a version of the book with changes to text,
+figures, or any other element must provide the changed version
+in a standard source format to both O'Reilly and the Samba
+team, and must provide them under the same terms as the
+original book.
+<p>
+Mere aggregation of this work, or a portion of the work, with
+other works or programs on the same media shall not cause this
+license to apply to those other works. The aggregate work
+shall contain this license and a notice specifying the
+inclusion of this material.
+<p>
+The copyright will stay in O'Reilly's hands, unless O'Reilly stops
+printing the book. However, the book will be maintained by
+the Samba team. Any changes made by O'Reilly will be given to
+the team, and vice versa.
+<p>
+TRANSLATIONS. In the case of translations, O'Reilly will
+choose when to update and reprint printed versions. If
+O'Reilly lets the translation go out of print for more than 6
+months, the copyright and all other rights go to the Samba
+team.
+<p>
+SEVERABILITY. If any part of this license is found to be
+unenforceable in any jurisdiction, the remaining portions of
+the license remain in force.
+<p>
+NO WARRANTY. This work is licensed and provided "as is"
+without warranty of any kind, express or implied, including,
+but not limited to, the implied warranties of merchantability
+and fitness for a particular purpose or a warranty of
+non-infringement.
+<p>
+GOOD-PRACTICE RECOMMENDATIONS. In addition to the requirements
+of this license, it is requested from and strongly recommended
+of redistributors that:
+<ol>
+ <li> If you are distributing the work on hardcopy or CD-ROM,
+ you provide email notification to the authors of your
+ intent to redistribute at least thirty days before your
+ manuscript or media freeze, to give the authors time to
+ provide updated documents. This notification should
+ describe modifications, if any, made to the document.
+
+ <li> All substantive modifications (including deletions) should
+ be either clearly marked in the document or else described
+ in an attachment to the document.
+
+ <li> While it is not mandatory under this license, it is
+ considered good form to offer a free copy of any hardcopy
+ and CD-ROM expression of this work to its authors and the
+ original software developers.
+
+ <li> Translations should contain this license in the target
+ language.
+</ol>
+
+
+<!-- End of sample chapter -->
+<CENTER>
+<HR SIZE="1" NOSHADE>
+<FONT SIZE="1" FACE="Verdana, Arial, Helvetica">
+<A HREF="http://www.oreilly.com/">
+<B>O'Reilly Home</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/sales/bookstores">
+<B>O'Reilly Bookstores</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/order_new/">
+<B>How to Order</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/contact.html">
+<B>O'Reilly Contacts<BR></B></A>
+<A HREF="http://www.oreilly.com/international/">
+<B>International</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/oreilly/about.html">
+<B>About O'Reilly</B></A> <B> | </B>
+<A HREF="http://www.oreilly.com/affiliates.html">
+<B>Affiliated Companies</B></A><p>
+<EM>&copy; 1999, O'Reilly &amp; Associates, Inc.</EM>
+</FONT>
+</CENTER>
+</BODY>
+
+</html>
diff --git a/docs/htmldocs/using_samba/this_edition.html b/docs/htmldocs/using_samba/this_edition.html
new file mode 100644
index 00000000000..71522ac31e1
--- /dev/null
+++ b/docs/htmldocs/using_samba/this_edition.html
@@ -0,0 +1,48 @@
+<HTML>
+<HEAD>
+<TITLE>This Edition</title>
+</head>
+
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" link="#990000" vlink="#0000CC">
+<table BORDER="0" CELLPADDING="0" CELLSPACING="0" width="90%">
+<tr>
+<td width="25%" valign="TOP">
+<img hspace=10 vspace=10 src="gifs/samba.s.gif"
+alt="Using Samba" align=left valign=top border=0>
+</td>
+<td height="105" valign="TOP">
+<br>
+<H2>Using Samba</H2>
+<font>
+By Robert Eckstein, David Collier-Brown & Peter Kelly
+<br>1st Edition October 1999 (est.)
+<br>1-56592-449-5, Order Number: 4495
+<br>424 pages (est.), $34.95 (est.)
+</font>
+</td>
+</tr>
+</table>
+<hr size=1 noshade>
+
+<blockquote>
+ Copyright (c) 1999 by O'Reilly & Associates. This book,
+ Using Samba, first edition, was written by Robert Eckstein,
+ David Collier-Brown, and Peter Kelly, and published by
+ O'Reilly & Associates. This material may be distributed only
+ subject to the terms and conditions set forth in the
+ license, which is presently available at
+ <a href="http://www.oreilly.com/catalog/samba/licenseinfo.html">
+ http://www.oreilly.com/catalog/samba/licenseinfo.html</a>.
+</blockquote>
+
+<hr size=1 noshade>
+
+<pre>
+This is a modified version of the O'Reilly first edition of
+<i>Using Samba</i>. Some of the modifications were made by <a
+href="mailto:jayts@bigfoot.com">Jay Ts</a> - thanks Jay!
+
+</pre>
+
+</BODY>
+</html>
diff --git a/docs/htmldocs/wbinfo.1.html b/docs/htmldocs/wbinfo.1.html
new file mode 100644
index 00000000000..badeb6961e6
--- /dev/null
+++ b/docs/htmldocs/wbinfo.1.html
@@ -0,0 +1,308 @@
+<HTML
+><HEAD
+><TITLE
+>wbinfo</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="WBINFO"
+>wbinfo</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>wbinfo&nbsp;--&nbsp;Query information from winbind daemon</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>wbinfo</B
+> [-u] [-g] [-n name] [-s sid] [-U uid] [-G gid] [-S sid] [-Y sid] [-t] [-m]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN21"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+>The <B
+CLASS="COMMAND"
+>wbinfo</B
+> program queries and returns information
+ created and used by the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+> winbindd(8)</B
+></A
+> daemon. </P
+><P
+>The <B
+CLASS="COMMAND"
+>winbindd(8)</B
+> daemon must be configured
+ and running for the <B
+CLASS="COMMAND"
+>wbinfo</B
+> program to be able
+ to return information.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN32"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-u</DT
+><DD
+><P
+>This option will list all users available
+ in the Windows NT domain for which the <B
+CLASS="COMMAND"
+>winbindd(8)
+ </B
+> daemon is operating in. Users in all trusted domains
+ will also be listed. Note that this operation does not assign
+ user ids to any users that have not already been seen by
+ <B
+CLASS="COMMAND"
+>winbindd(8)</B
+>.</P
+></DD
+><DT
+>-g</DT
+><DD
+><P
+>This option will list all groups available
+ in the Windows NT domain for which the <B
+CLASS="COMMAND"
+>winbindd(8)
+ </B
+> daemon is operating in. Groups in all trusted domains
+ will also be listed. Note that this operation does not assign
+ group ids to any groups that have not already been seen by
+ <B
+CLASS="COMMAND"
+>winbindd(8)</B
+>. </P
+></DD
+><DT
+>-n name</DT
+><DD
+><P
+>The <TT
+CLASS="PARAMETER"
+><I
+>-n</I
+></TT
+> option
+ queries <B
+CLASS="COMMAND"
+>winbindd(8)</B
+> for the SID
+ associated with the name specified. Domain names can be specified
+ before the user name by using the winbind separator character.
+ For example CWDOM1/Administrator refers to the Administrator
+ user in the domain CWDOM1. If no domain is specified then the
+ domain used is the one specified in the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+>
+ <TT
+CLASS="PARAMETER"
+><I
+>workgroup</I
+></TT
+> parameter. </P
+></DD
+><DT
+>-s sid</DT
+><DD
+><P
+>Use <TT
+CLASS="PARAMETER"
+><I
+>-s</I
+></TT
+> to resolve
+ a SID to a name. This is the inverse of the <TT
+CLASS="PARAMETER"
+><I
+>-n
+ </I
+></TT
+> option above. SIDs must be specified as ASCII strings
+ in the traditional Microsoft format. For example,
+ S-1-5-21-1455342024-3071081365-2475485837-500. </P
+></DD
+><DT
+>-U uid</DT
+><DD
+><P
+>Try to convert a UNIX user id to a Windows NT
+ SID. If the uid specified does not refer to one within
+ the winbind uid range then the operation will fail. </P
+></DD
+><DT
+>-G gid</DT
+><DD
+><P
+>Try to convert a UNIX group id to a Windows
+ NT SID. If the gid specified does not refer to one within
+ the winbind gid range then the operation will fail. </P
+></DD
+><DT
+>-S sid</DT
+><DD
+><P
+>Convert a SID to a UNIX user id. If the SID
+ does not correspond to a UNIX user mapped by <B
+CLASS="COMMAND"
+> winbindd(8)</B
+> then the operation will fail. </P
+></DD
+><DT
+>-Y sid</DT
+><DD
+><P
+>Convert a SID to a UNIX group id. If the SID
+ does not correspond to a UNIX group mapped by <B
+CLASS="COMMAND"
+> winbindd(8)</B
+> then the operation will fail. </P
+></DD
+><DT
+>-t</DT
+><DD
+><P
+>Verify that the workstation trust account
+ created when the Samba server is added to the Windows NT
+ domain is working. </P
+></DD
+><DT
+>-m</DT
+><DD
+><P
+>Produce a list of domains trusted by the
+ Windows NT server <B
+CLASS="COMMAND"
+>winbindd(8)</B
+> contacts
+ when resolving names. This list does not include the Windows
+ NT domain the server is a Primary Domain Controller for.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN88"
+></A
+><H2
+>EXIT STATUS</H2
+><P
+>The wbinfo program returns 0 if the operation
+ succeeded, or 1 if the operation failed. If the <B
+CLASS="COMMAND"
+>winbindd(8)
+ </B
+> daemon is not working <B
+CLASS="COMMAND"
+>wbinfo</B
+> will always return
+ failure. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN93"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN96"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="winbindd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>winbindd(8)</B
+>
+ </A
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN101"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+><B
+CLASS="COMMAND"
+>wbinfo</B
+> and <B
+CLASS="COMMAND"
+>winbindd</B
+>
+ were written by Tim Potter.</P
+><P
+>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/winbind.html b/docs/htmldocs/winbind.html
new file mode 100644
index 00000000000..5148b4bc85f
--- /dev/null
+++ b/docs/htmldocs/winbind.html
@@ -0,0 +1,1312 @@
+<HTML
+><HEAD
+><TITLE
+>Unified Logons between Windows NT and UNIX using Winbind</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="WINBIND"
+>Unified Logons between Windows NT and UNIX using Winbind</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Abstract</A
+></H1
+><P
+>Integration of UNIX and Microsoft Windows NT through
+ a unified logon has been considered a "holy grail" in heterogeneous
+ computing environments for a long time. We present
+ <I
+CLASS="EMPHASIS"
+>winbind</I
+>, a component of the Samba suite
+ of programs as a solution to the unified logon problem. Winbind
+ uses a UNIX implementation
+ of Microsoft RPC calls, Pluggable Authentication Modules, and the Name
+ Service Switch to allow Windows NT domain users to appear and operate
+ as UNIX users on a UNIX machine. This paper describes the winbind
+ system, explaining the functionality it provides, how it is configured,
+ and how it works internally.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN7"
+>Introduction</A
+></H1
+><P
+>It is well known that UNIX and Microsoft Windows NT have
+ different models for representing user and group information and
+ use different technologies for implementing them. This fact has
+ made it difficult to integrate the two systems in a satisfactory
+ manner.</P
+><P
+>One common solution in use today has been to create
+ identically named user accounts on both the UNIX and Windows systems
+ and use the Samba suite of programs to provide file and print services
+ between the two. This solution is far from perfect however, as
+ adding and deleting users on both sets of machines becomes a chore
+ and two sets of passwords are required both of which
+ can lead to synchronization problems between the UNIX and Windows
+ systems and confusion for users.</P
+><P
+>We divide the unified logon problem for UNIX machines into
+ three smaller problems:</P
+><P
+></P
+><UL
+><LI
+><P
+>Obtaining Windows NT user and group information
+ </P
+></LI
+><LI
+><P
+>Authenticating Windows NT users
+ </P
+></LI
+><LI
+><P
+>Password changing for Windows NT users
+ </P
+></LI
+></UL
+><P
+>Ideally, a prospective solution to the unified logon problem
+ would satisfy all the above components without duplication of
+ information on the UNIX machines and without creating additional
+ tasks for the system administrator when maintaining users and
+ groups on either system. The winbind system provides a simple
+ and elegant solution to all three components of the unified logon
+ problem.</P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN20"
+>What Winbind Provides</A
+></H1
+><P
+>Winbind unifies UNIX and Windows NT account management by
+ allowing a UNIX box to become a full member of a NT domain. Once
+ this is done the UNIX box will see NT users and groups as if
+ they were native UNIX users and groups, allowing the NT domain
+ to be used in much the same manner that NIS+ is used within
+ UNIX-only environments.</P
+><P
+>The end result is that whenever any
+ program on the UNIX machine asks the operating system to lookup
+ a user or group name, the query will be resolved by asking the
+ NT domain controller for the specified domain to do the lookup.
+ Because Winbind hooks into the operating system at a low level
+ (via the NSS name resolution modules in the C library) this
+ redirection to the NT domain controller is completely
+ transparent.</P
+><P
+>Users on the UNIX machine can then use NT user and group
+ names as they would use "native" UNIX names. They can chown files
+ so that they are owned by NT domain users or even login to the
+ UNIX machine and run a UNIX X-Window session as a domain user.</P
+><P
+>The only obvious indication that Winbind is being used is
+ that user and group names take the form DOMAIN\user and
+ DOMAIN\group. This is necessary as it allows Winbind to determine
+ that redirection to a domain controller is wanted for a particular
+ lookup and which trusted domain is being referenced.</P
+><P
+>Additionally, Winbind provides an authentication service
+ that hooks into the Pluggable Authentication Modules (PAM) system
+ to provide authentication via a NT domain to any PAM enabled
+ applications. This capability solves the problem of synchronizing
+ passwords between systems since all passwords are stored in a single
+ location (on the domain controller).</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN27"
+>Target Uses</A
+></H2
+><P
+>Winbind is targeted at organizations that have an
+ existing NT based domain infrastructure into which they wish
+ to put UNIX workstations or servers. Winbind will allow these
+ organizations to deploy UNIX workstations without having to
+ maintain a separate account infrastructure. This greatly
+ simplifies the administrative overhead of deploying UNIX
+ workstations into a NT based organization.</P
+><P
+>Another interesting way in which we expect Winbind to
+ be used is as a central part of UNIX based appliances. Appliances
+ that provide file and print services to Microsoft based networks
+ will be able to use Winbind to provide seamless integration of
+ the appliance into the domain.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN31"
+>How Winbind Works</A
+></H1
+><P
+>The winbind system is designed around a client/server
+ architecture. A long running <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+ listens on a UNIX domain socket waiting for requests
+ to arrive. These requests are generated by the NSS and PAM
+ clients and processed sequentially.</P
+><P
+>The technologies used to implement winbind are described
+ in detail below.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN36"
+>Microsoft Remote Procedure Calls</A
+></H2
+><P
+>Over the last two years, efforts have been underway
+ by various Samba Team members to decode various aspects of
+ the Microsoft Remote Procedure Call (MSRPC) system. This
+ system is used for most network related operations between
+ Windows NT machines including remote management, user authentication
+ and print spooling. Although initially this work was done
+ to aid the implementation of Primary Domain Controller (PDC)
+ functionality in Samba, it has also yielded a body of code which
+ can be used for other purposes.</P
+><P
+>Winbind uses various MSRPC calls to enumerate domain users
+ and groups and to obtain detailed information about individual
+ users or groups. Other MSRPC calls can be used to authenticate
+ NT domain users and to change user passwords. By directly querying
+ a Windows PDC for user and group information, winbind maps the
+ NT account information onto UNIX user and group names.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN40"
+>Name Service Switch</A
+></H2
+><P
+>The Name Service Switch, or NSS, is a feature that is
+ present in many UNIX operating systems. It allows system
+ information such as hostnames, mail aliases and user information
+ to be resolved from different sources. For example, a standalone
+ UNIX workstation may resolve system information from a series of
+ flat files stored on the local filesystem. A networked workstation
+ may first attempt to resolve system information from local files,
+ and then consult a NIS database for user information or a DNS server
+ for hostname information.</P
+><P
+>The NSS application programming interface allows winbind
+ to present itself as a source of system information when
+ resolving UNIX usernames and groups. Winbind uses this interface,
+ and information obtained from a Windows NT server using MSRPC
+ calls to provide a new source of account enumeration. Using standard
+ UNIX library calls, one can enumerate the users and groups on
+ a UNIX machine running winbind and see all users and groups in
+ a NT domain plus any trusted domain as though they were local
+ users and groups.</P
+><P
+>The primary control file for NSS is
+ <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>.
+ When a UNIX application makes a request to do a lookup
+ the C library looks in <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+>
+ for a line which matches the service type being requested, for
+ example the "passwd" service type is used when user or group names
+ are looked up. This config line species which implementations
+ of that service should be tried and in what order. If the passwd
+ config line is:</P
+><P
+><B
+CLASS="COMMAND"
+>passwd: files example</B
+></P
+><P
+>then the C library will first load a module called
+ <TT
+CLASS="FILENAME"
+>/lib/libnss_files.so</TT
+> followed by
+ the module <TT
+CLASS="FILENAME"
+>/lib/libnss_example.so</TT
+>. The
+ C library will dynamically load each of these modules in turn
+ and call resolver functions within the modules to try to resolve
+ the request. Once the request is resolved the C library returns the
+ result to the application.</P
+><P
+>This NSS interface provides a very easy way for Winbind
+ to hook into the operating system. All that needs to be done
+ is to put <TT
+CLASS="FILENAME"
+>libnss_winbind.so</TT
+> in <TT
+CLASS="FILENAME"
+>/lib/</TT
+>
+ then add "winbind" into <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> at
+ the appropriate place. The C library will then call Winbind to
+ resolve user and group names.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN56"
+>Pluggable Authentication Modules</A
+></H2
+><P
+>Pluggable Authentication Modules, also known as PAM,
+ is a system for abstracting authentication and authorization
+ technologies. With a PAM module it is possible to specify different
+ authentication methods for different system applications without
+ having to recompile these applications. PAM is also useful
+ for implementing a particular policy for authorization. For example,
+ a system administrator may only allow console logins from users
+ stored in the local password file but only allow users resolved from
+ a NIS database to log in over the network.</P
+><P
+>Winbind uses the authentication management and password
+ management PAM interface to integrate Windows NT users into a
+ UNIX system. This allows Windows NT users to log in to a UNIX
+ machine and be authenticated against a suitable Primary Domain
+ Controller. These users can also change their passwords and have
+ this change take effect directly on the Primary Domain Controller.
+ </P
+><P
+>PAM is configured by providing control files in the directory
+ <TT
+CLASS="FILENAME"
+>/etc/pam.d/</TT
+> for each of the services that
+ require authentication. When an authentication request is made
+ by an application the PAM code in the C library looks up this
+ control file to determine what modules to load to do the
+ authentication check and in what order. This interface makes adding
+ a new authentication service for Winbind very easy, all that needs
+ to be done is that the <TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+> module
+ is copied to <TT
+CLASS="FILENAME"
+>/lib/security/</TT
+> and the PAM
+ control files for relevant services are updated to allow
+ authentication via winbind. See the PAM documentation
+ for more details.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN64"
+>User and Group ID Allocation</A
+></H2
+><P
+>When a user or group is created under Windows NT
+ is it allocated a numerical relative identifier (RID). This is
+ slightly different to UNIX which has a range of numbers that are
+ used to identify users, and the same range in which to identify
+ groups. It is winbind's job to convert RIDs to UNIX id numbers and
+ vice versa. When winbind is configured it is given part of the UNIX
+ user id space and a part of the UNIX group id space in which to
+ store Windows NT users and groups. If a Windows NT user is
+ resolved for the first time, it is allocated the next UNIX id from
+ the range. The same process applies for Windows NT groups. Over
+ time, winbind will have mapped all Windows NT users and groups
+ to UNIX user ids and group ids.</P
+><P
+>The results of this mapping are stored persistently in
+ an ID mapping database held in a tdb database). This ensures that
+ RIDs are mapped to UNIX IDs in a consistent way.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN68"
+>Result Caching</A
+></H2
+><P
+>An active system can generate a lot of user and group
+ name lookups. To reduce the network cost of these lookups winbind
+ uses a caching scheme based on the SAM sequence number supplied
+ by NT domain controllers. User or group information returned
+ by a PDC is cached by winbind along with a sequence number also
+ returned by the PDC. This sequence number is incremented by
+ Windows NT whenever any user or group information is modified. If
+ a cached entry has expired, the sequence number is requested from
+ the PDC and compared against the sequence number of the cached entry.
+ If the sequence numbers do not match, then the cached information
+ is discarded and up to date information is requested directly
+ from the PDC.</P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN71"
+>Installation and Configuration</A
+></H1
+><P
+>Many thanks to John Trostel <A
+HREF="mailto:jtrostel@snapserver.com"
+TARGET="_top"
+>jtrostel@snapserver.com</A
+>
+for providing the HOWTO for this section.</P
+><P
+>This HOWTO describes how to get winbind services up and running
+to control access and authenticate users on your Linux box using
+the winbind services which come with SAMBA 2.2.2.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN76"
+>Introduction</A
+></H2
+><P
+>This HOWTO describes the procedures used to get winbind up and
+running on my RedHat 7.1 system. Winbind is capable of providing access
+and authentication control for Windows Domain users through an NT
+or Win2K PDC for 'regular' services, such as telnet a nd ftp, as
+well for SAMBA services.</P
+><P
+>This HOWTO has been written from a 'RedHat-centric' perspective, so if
+you are using another distribution, you may have to modify the instructions
+somewhat to fit the way your distribution works.</P
+><P
+></P
+><UL
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>Why should I to this?</I
+>
+ </P
+><P
+>This allows the SAMBA administrator to rely on the
+ authentication mechanisms on the NT/Win2K PDC for the authentication
+ of domain members. NT/Win2K users no longer need to have separate
+ accounts on the SAMBA server.
+ </P
+></LI
+><LI
+><P
+> <I
+CLASS="EMPHASIS"
+>Who should be reading this document?</I
+>
+ </P
+><P
+> This HOWTO is designed for system administrators. If you are
+ implementing SAMBA on a file server and wish to (fairly easily)
+ integrate existing NT/Win2K users from your PDC onto the
+ SAMBA server, this HOWTO is for you. That said, I am no NT or PAM
+ expert, so you may find a better or easier way to accomplish
+ these tasks.
+ </P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN89"
+>Requirements</A
+></H2
+><P
+>If you have a samba configuration file that you are currently
+using... <I
+CLASS="EMPHASIS"
+>BACK IT UP!</I
+> If your system already uses PAM,
+<I
+CLASS="EMPHASIS"
+>back up the <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> directory
+contents!</I
+> If you haven't already made a boot disk,
+<I
+CLASS="EMPHASIS"
+>MAKE ONE NOW!</I
+></P
+><P
+>Messing with the pam configuration files can make it nearly impossible
+to log in to yourmachine. That's why you want to be able to boot back
+into your machine in single user mode and restore your
+<TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> back to the original state they were in if
+you get frustrated with the way things are going. ;-)</P
+><P
+>The latest version of SAMBA (version 2.2.2 as of this writing), now
+includes a functioning winbindd daemon. Please refer to the
+<A
+HREF="http://samba.org/"
+TARGET="_top"
+>main SAMBA web page</A
+> or,
+better yet, your closest SAMBA mirror site for instructions on
+downloading the source code.</P
+><P
+>To allow Domain users the ability to access SAMBA shares and
+files, as well as potentially other services provided by your
+SAMBA machine, PAM (pluggable authentication modules) must
+be setup properly on your machine. In order to compile the
+winbind modules, you should have at least the pam libraries resident
+on your system. For recent RedHat systems (7.1, for instance), that
+means <TT
+CLASS="FILENAME"
+>pam-0.74-22</TT
+>. For best results, it is helpful to also
+install the development packages in <TT
+CLASS="FILENAME"
+>pam-devel-0.74-22</TT
+>.</P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN103"
+>Testing Things Out</A
+></H2
+><P
+>Before starting, it is probably best to kill off all the SAMBA
+related daemons running on your server. Kill off all <B
+CLASS="COMMAND"
+>smbd</B
+>,
+<B
+CLASS="COMMAND"
+>nmbd</B
+>, and <B
+CLASS="COMMAND"
+>winbindd</B
+> processes that may
+be running. To use PAM, you will want to make sure that you have the
+standard PAM package (for RedHat) which supplies the <TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+>
+directory structure, including the pam modules are used by pam-aware
+services, several pam libraries, and the <TT
+CLASS="FILENAME"
+>/usr/doc</TT
+>
+and <TT
+CLASS="FILENAME"
+>/usr/man</TT
+> entries for pam. Winbind built better
+in SAMBA if the pam-devel package was also installed. This package includes
+the header files needed to compile pam-aware applications. For instance,
+my RedHat system has both <TT
+CLASS="FILENAME"
+>pam-0.74-22</TT
+> and
+<TT
+CLASS="FILENAME"
+>pam-devel-0.74-22</TT
+> RPMs installed.</P
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN114"
+>Configure and compile SAMBA</A
+></H3
+><P
+>The configuration and compilation of SAMBA is pretty straightforward.
+The first three steps may not be necessary depending upon
+whether or not you have previously built the Samba binaries.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>autoconf</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make clean</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>rm config.cache</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>./configure --with-winbind</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make</B
+>
+<TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make install</B
+></PRE
+></P
+><P
+>This will, by default, install SAMBA in <TT
+CLASS="FILENAME"
+>/usr/local/samba</TT
+>.
+See the main SAMBA documentation if you want to install SAMBA somewhere else.
+It will also build the winbindd executable and libraries. </P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN133"
+>Configure <TT
+CLASS="FILENAME"
+>nsswitch.conf</TT
+> and the
+winbind libraries</A
+></H3
+><P
+>The libraries needed to run the <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+through nsswitch need to be copied to their proper locations, so</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>cp ../samba/source/nsswitch/libnss_winbind.so /lib</B
+></P
+><P
+>I also found it necessary to make the following symbolic link:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>ln -s /lib/libnss_winbind.so /lib/libnss_winbind.so.2</B
+></P
+><P
+>Now, as root you need to edit <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> to
+allow user and group entries to be visible from the <B
+CLASS="COMMAND"
+>winbindd</B
+>
+daemon. My <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file look like
+this after editing:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+> passwd: files winbind
+ shadow: files
+ group: files winbind</PRE
+></P
+><P
+>
+The libraries needed by the winbind daemon will be automatically
+entered into the <B
+CLASS="COMMAND"
+>ldconfig</B
+> cache the next time
+your system reboots, but it
+is faster (and you don't need to reboot) if you do it manually:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/sbin/ldconfig -v | grep winbind</B
+></P
+><P
+>This makes <TT
+CLASS="FILENAME"
+>libnss_winbind</TT
+> available to winbindd
+and echos back a check to you.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN158"
+>Configure smb.conf</A
+></H3
+><P
+>Several parameters are needed in the smb.conf file to control
+the behavior of <B
+CLASS="COMMAND"
+>winbindd</B
+>. Configure
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> These are described in more detail in
+the <A
+HREF="winbindd.8.html"
+TARGET="_top"
+>winbindd(8)</A
+> man page. My
+<TT
+CLASS="FILENAME"
+>smb.conf</TT
+> file was modified to
+include the following entries in the [global] section:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ &#60;...&#62;
+ # separate domain and username with '+', like DOMAIN+username
+ <A
+HREF="winbindd.8.html#WINBINDSEPARATOR"
+TARGET="_top"
+>winbind separator</A
+> = +
+ # use uids from 10000 to 20000 for domain users
+ <A
+HREF="winbindd.8.html#WINBINDUID"
+TARGET="_top"
+>winbind uid</A
+> = 10000-20000
+ # use gids from 10000 to 20000 for domain groups
+ <A
+HREF="winbindd.8.html#WINBINDGID"
+TARGET="_top"
+>winbind gid</A
+> = 10000-20000
+ # allow enumeration of winbind users and groups
+ <A
+HREF="winbindd.8.html#WINBINDENUMUSERS"
+TARGET="_top"
+>winbind enum users</A
+> = yes
+ <A
+HREF="winbindd.8.html#WINBINDENUMGROUP"
+TARGET="_top"
+>winbind enum groups</A
+> = yes
+ # give winbind users a real shell (only needed if they have telnet access)
+ <A
+HREF="winbindd.8.html#TEMPLATEHOMEDIR"
+TARGET="_top"
+>template homedir</A
+> = /home/winnt/%D/%U
+ <A
+HREF="winbindd.8.html#TEMPLATESHELL"
+TARGET="_top"
+>template shell</A
+> = /bin/bash</PRE
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN174"
+>Join the SAMBA server to the PDC domain</A
+></H3
+><P
+>Enter the following command to make the SAMBA server join the
+PDC domain, where <TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+> is the name of
+your Windows domain and <TT
+CLASS="REPLACEABLE"
+><I
+>Administrator</I
+></TT
+> is
+a domain user who has administrative privileges in the domain.</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/smbpasswd -j DOMAIN -r PDC -U Administrator</B
+></P
+><P
+>The proper response to the command should be: "Joined the domain
+<TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+>" where <TT
+CLASS="REPLACEABLE"
+><I
+>DOMAIN</I
+></TT
+>
+is your DOMAIN name.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN185"
+>Start up the winbindd daemon and test it!</A
+></H3
+><P
+>Eventually, you will want to modify your smb startup script to
+automatically invoke the winbindd daemon when the other parts of
+SAMBA start, but it is possible to test out just the winbind
+portion first. To start up winbind services, enter the following
+command as root:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/winbindd</B
+></P
+><P
+>I'm always paranoid and like to make sure the daemon
+is really running...</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>ps -ae | grep winbindd</B
+></P
+><P
+>This command should produce output like this, if the daemon is running</P
+><P
+>3025 ? 00:00:00 winbindd</P
+><P
+>Now... for the real test, try to get some information about the
+users on your PDC</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/wbinfo -u</B
+></P
+><P
+>
+This should echo back a list of users on your Windows users on
+your PDC. For example, I get the following response:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>CEO+Administrator
+CEO+burdell
+CEO+Guest
+CEO+jt-ad
+CEO+krbtgt
+CEO+TsInternetUser</PRE
+></P
+><P
+>Obviously, I have named my domain 'CEO' and my <TT
+CLASS="PARAMETER"
+><I
+>winbindd
+separator</I
+></TT
+> is '+'.</P
+><P
+>You can do the same sort of thing to get group information from
+the PDC:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>/usr/local/samba/bin/wbinfo -g</B
+>
+CEO+Domain Admins
+CEO+Domain Users
+CEO+Domain Guests
+CEO+Domain Computers
+CEO+Domain Controllers
+CEO+Cert Publishers
+CEO+Schema Admins
+CEO+Enterprise Admins
+CEO+Group Policy Creator Owners</PRE
+></P
+><P
+>The function 'getent' can now be used to get unified
+lists of both local and PDC users and groups.
+Try the following command:</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>getent passwd</B
+></P
+><P
+>You should get a list that looks like your <TT
+CLASS="FILENAME"
+>/etc/passwd</TT
+>
+list followed by the domain users with their new uids, gids, home
+directories and default shells.</P
+><P
+>The same thing can be done for groups with the command</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>getent group</B
+></P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN221"
+>Fix the <TT
+CLASS="FILENAME"
+>/etc/rc.d/init.d/smb</TT
+> startup files</A
+></H3
+><P
+>The <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon needs to start up after the
+<B
+CLASS="COMMAND"
+>smbd</B
+> and <B
+CLASS="COMMAND"
+>nmbd</B
+> daemons are running.
+To accomplish this task, you need to modify the <TT
+CLASS="FILENAME"
+>/etc/init.d/smb</TT
+>
+script to add commands to invoke this daemon in the proper sequence. My
+<TT
+CLASS="FILENAME"
+>/etc/init.d/smb</TT
+> file starts up <B
+CLASS="COMMAND"
+>smbd</B
+>,
+<B
+CLASS="COMMAND"
+>nmbd</B
+>, and <B
+CLASS="COMMAND"
+>winbindd</B
+> from the
+<TT
+CLASS="FILENAME"
+>/usr/local/samba/bin</TT
+> directory directly. The 'start'
+function in the script looks like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>start() {
+ KIND="SMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/smbd $SMBDOPTIONS
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/nmbd $NMBDOPTIONS
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Starting $KIND services: "
+ daemon /usr/local/samba/bin/winbindd
+ RETVAL3=$?
+ echo
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] &#38;&#38; touch /var/lock/subsys/smb || \
+ RETVAL=1
+ return $RETVAL
+}</PRE
+></P
+><P
+>The 'stop' function has a corresponding entry to shut down the
+services and look s like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>stop() {
+ KIND="SMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc smbd
+ RETVAL=$?
+ echo
+ KIND="NMB"
+ echo -n $"Shutting down $KIND services: "
+ killproc nmbd
+ RETVAL2=$?
+ echo
+ KIND="Winbind"
+ echo -n $"Shutting down $KIND services: "
+ killproc winbindd
+ RETVAL3=$?
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 -a $RETVAL3 -eq 0 ] &#38;&#38; rm -f /var/lock/subsys/smb
+ echo ""
+ return $RETVAL
+}</PRE
+></P
+><P
+>If you restart the <B
+CLASS="COMMAND"
+>smbd</B
+>, <B
+CLASS="COMMAND"
+>nmbd</B
+>,
+and <B
+CLASS="COMMAND"
+>winbindd</B
+> daemons at this point, you
+should be able to connect to the samba server as a domain member just as
+if you were a local user.</P
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H3
+CLASS="SECT3"
+><A
+NAME="AEN243"
+>Configure Winbind and PAM</A
+></H3
+><P
+>If you have made it this far, you know that winbindd and samba are working
+together. If you want to use winbind to provide authentication for other
+services, keep reading. The pam configuration files need to be altered in
+this step. (Did you remember to make backups of your original
+<TT
+CLASS="FILENAME"
+>/etc/pam.d</TT
+> files? If not, do it now.)</P
+><P
+>You will need a pam module to use winbindd with these other services. This
+module will be compiled in the <TT
+CLASS="FILENAME"
+>../source/nsswitch</TT
+> directory
+by invoking the command</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>make nsswitch/pam_winbind.so</B
+></P
+><P
+>from the <TT
+CLASS="FILENAME"
+>../source</TT
+> directory. The
+<TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+> file should be copied to the location of
+your other pam security modules. On my RedHat system, this was the
+<TT
+CLASS="FILENAME"
+>/lib/security</TT
+> directory.</P
+><P
+><TT
+CLASS="PROMPT"
+>root#</TT
+> <B
+CLASS="COMMAND"
+>cp ../samba/source/nsswitch/pam_winbind.so /lib/security</B
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/samba</TT
+> file does not need to be changed. I
+just left this fileas it was:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_stack.so service=system-auth
+account required /lib/security/pam_stack.so service=system-auth</PRE
+></P
+><P
+>The other services that I modified to allow the use of winbind
+as an authentication service were the normal login on the console (or a terminal
+session), telnet logins, and ftp service. In order to enable these
+services, you may first need to change the entries in
+<TT
+CLASS="FILENAME"
+>/etc/xinetd.d</TT
+> (or <TT
+CLASS="FILENAME"
+>/etc/inetd.conf</TT
+>).
+RedHat 7.1 uses the new xinetd.d structure, in this case you need
+to change the lines in <TT
+CLASS="FILENAME"
+>/etc/xinetd.d/telnet</TT
+>
+and <TT
+CLASS="FILENAME"
+>/etc/xinetd.d/wu-ftp</TT
+> from </P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>enable = no</PRE
+></P
+><P
+>to</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>enable = yes</PRE
+></P
+><P
+>
+For ftp services to work properly, you will also need to either
+have individual directories for the domain users already present on
+the server, or change the home directory template to a general
+directory for all domain users. These can be easily set using
+the <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> global entry
+<B
+CLASS="COMMAND"
+>template homedir</B
+>.</P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/ftp</TT
+> file can be changed
+to allow winbind ftp access in a manner similar to the
+samba file. My <TT
+CLASS="FILENAME"
+>/etc/pam.d/ftp</TT
+> file was
+changed to look like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_shells.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth</PRE
+></P
+><P
+>The <TT
+CLASS="FILENAME"
+>/etc/pam.d/login</TT
+> file can be changed nearly the
+same way. It now looks like this:</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_securetty.so
+auth sufficient /lib/security/pam_winbind.so
+auth sufficient /lib/security/pam_unix.so use_first_pass
+auth required /lib/security/pam_stack.so service=system-auth
+auth required /lib/security/pam_nologin.so
+account sufficient /lib/security/pam_winbind.so
+account required /lib/security/pam_stack.so service=system-auth
+password required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth
+session optional /lib/security/pam_console.so</PRE
+></P
+><P
+>In this case, I added the <B
+CLASS="COMMAND"
+>auth sufficient /lib/security/pam_winbind.so</B
+>
+lines as before, but also added the <B
+CLASS="COMMAND"
+>required pam_securetty.so</B
+>
+above it, to disallow root logins over the network. I also added a
+<B
+CLASS="COMMAND"
+>sufficient /lib/security/pam_unix.so use_first_pass</B
+>
+line after the <B
+CLASS="COMMAND"
+>winbind.so</B
+> line to get rid of annoying
+double prompts for passwords.</P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN290"
+>Limitations</A
+></H1
+><P
+>Winbind has a number of limitations in its current
+ released version that we hope to overcome in future
+ releases:</P
+><P
+></P
+><UL
+><LI
+><P
+>Winbind is currently only available for
+ the Linux operating system, although ports to other operating
+ systems are certainly possible. For such ports to be feasible,
+ we require the C library of the target operating system to
+ support the Name Service Switch and Pluggable Authentication
+ Modules systems. This is becoming more common as NSS and
+ PAM gain support among UNIX vendors.</P
+></LI
+><LI
+><P
+>The mappings of Windows NT RIDs to UNIX ids
+ is not made algorithmically and depends on the order in which
+ unmapped users or groups are seen by winbind. It may be difficult
+ to recover the mappings of rid to UNIX id mapping if the file
+ containing this information is corrupted or destroyed.</P
+></LI
+><LI
+><P
+>Currently the winbind PAM module does not take
+ into account possible workstation and logon time restrictions
+ that may be been set for Windows NT users.</P
+></LI
+></UL
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN300"
+>Conclusion</A
+></H1
+><P
+>The winbind system, through the use of the Name Service
+ Switch, Pluggable Authentication Modules, and appropriate
+ Microsoft RPC calls have allowed us to provide seamless
+ integration of Microsoft Windows NT domain users on a
+ UNIX system. The result is a great reduction in the administrative
+ cost of running a mixed UNIX and NT network.</P
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/winbindd.8.html b/docs/htmldocs/winbindd.8.html
new file mode 100644
index 00000000000..0147861284f
--- /dev/null
+++ b/docs/htmldocs/winbindd.8.html
@@ -0,0 +1,937 @@
+<HTML
+><HEAD
+><TITLE
+>winbindd</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="WINBINDD"
+>winbindd</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>winbindd&nbsp;--&nbsp;Name Service Switch daemon for resolving names
+ from NT servers</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>winbindd</B
+> [-i] [-d &#60;debug level&#62;] [-s &#60;smb config file&#62;]</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN14"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>This program is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+> Samba</A
+> suite.</P
+><P
+><B
+CLASS="COMMAND"
+>winbindd</B
+> is a daemon that provides
+ a service for the Name Service Switch capability that is present
+ in most modern C libraries. The Name Service Switch allows user
+ and system information to be obtained from different databases
+ services such as NIS or DNS. The exact behaviour can be configured
+ throught the <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file.
+ Users and groups are allocated as they are resolved to a range
+ of user and group ids specified by the administrator of the
+ Samba system.</P
+><P
+>The service provided by <B
+CLASS="COMMAND"
+>winbindd</B
+> is called `winbind' and
+ can be used to resolve user and group information from a
+ Windows NT server. The service can also provide authentication
+ services via an associated PAM module. </P
+><P
+> The <TT
+CLASS="FILENAME"
+>pam_winbind</TT
+> module in the 2.2.2 release only
+ supports the <TT
+CLASS="PARAMETER"
+><I
+>auth</I
+></TT
+> and <TT
+CLASS="PARAMETER"
+><I
+>account</I
+></TT
+>
+ module-types. The latter is simply
+ performs a getpwnam() to verify that the system can obtain a uid for the
+ user. If the <TT
+CLASS="FILENAME"
+>libnss_winbind</TT
+> library has been correctly
+ installed, this should always suceed.
+ </P
+><P
+>The following nsswitch databases are implemented by
+ the winbindd service: </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>passwd</DT
+><DD
+><P
+>User information traditionally stored in
+ the <TT
+CLASS="FILENAME"
+>passwd(5)</TT
+> file and used by
+ <B
+CLASS="COMMAND"
+>getpwent(3)</B
+> functions. </P
+></DD
+><DT
+>group</DT
+><DD
+><P
+>Group information traditionally stored in
+ the <TT
+CLASS="FILENAME"
+>group(5)</TT
+> file and used by
+ <B
+CLASS="COMMAND"
+>getgrent(3)</B
+> functions. </P
+></DD
+></DL
+></DIV
+><P
+>For example, the following simple configuration in the
+ <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> file can be used to initially
+ resolve user and group information from <TT
+CLASS="FILENAME"
+>/etc/passwd
+ </TT
+> and <TT
+CLASS="FILENAME"
+>/etc/group</TT
+> and then from the
+ Windows NT server. </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>passwd: files winbind
+group: files winbind
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN48"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>-d debuglevel</DT
+><DD
+><P
+>Sets the debuglevel to an integer between
+ 0 and 100. 0 is for no debugging and 100 is for reams and
+ reams. To submit a bug report to the Samba Team, use debug
+ level 100 (see BUGS.txt). </P
+></DD
+><DT
+>-i</DT
+><DD
+><P
+>Tells <B
+CLASS="COMMAND"
+>winbindd</B
+> to not
+ become a daemon and detach from the current terminal. This
+ option is used by developers when interactive debugging
+ of <B
+CLASS="COMMAND"
+>winbindd</B
+> is required. </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN61"
+></A
+><H2
+>NAME AND ID RESOLUTION</H2
+><P
+>Users and groups on a Windows NT server are assigned
+ a relative id (rid) which is unique for the domain when the
+ user or group is created. To convert the Windows NT user or group
+ into a unix user or group, a mapping between rids and unix user
+ and group ids is required. This is one of the jobs that <B
+CLASS="COMMAND"
+> winbindd</B
+> performs. </P
+><P
+>As winbindd users and groups are resolved from a server, user
+ and group ids are allocated from a specified range. This
+ is done on a first come, first served basis, although all existing
+ users and groups will be mapped as soon as a client performs a user
+ or group enumeration command. The allocated unix ids are stored
+ in a database file under the Samba lock directory and will be
+ remembered. </P
+><P
+>WARNING: The rid to unix id database is the only location
+ where the user and group mappings are stored by winbindd. If this
+ file is deleted or corrupted, there is no way for winbindd to
+ determine which user and group ids correspond to Windows NT user
+ and group rids. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN67"
+></A
+><H2
+>CONFIGURATION</H2
+><P
+>Configuration of the <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+ is done through configuration parameters in the <TT
+CLASS="FILENAME"
+>smb.conf(5)
+ </TT
+> file. All parameters should be specified in the
+ [global] section of smb.conf. </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>winbind separator</DT
+><DD
+><P
+>The winbind separator option allows you
+ to specify how NT domain names and user names are combined
+ into unix user names when presented to users. By default,
+ <B
+CLASS="COMMAND"
+>winbindd</B
+> will use the traditional '\'
+ separator so that the unix user names look like
+ DOMAIN\username. In some cases this separator character may
+ cause problems as the '\' character has special meaning in
+ unix shells. In that case you can use the winbind separator
+ option to specify an alternative separator character. Good
+ alternatives may be '/' (although that conflicts
+ with the unix directory separator) or a '+ 'character.
+ The '+' character appears to be the best choice for 100%
+ compatibility with existing unix utilities, but may be an
+ aesthetically bad choice depending on your taste. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind separator = \ </B
+>
+ </P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind separator = + </B
+></P
+></DD
+><DT
+>winbind uid</DT
+><DD
+><P
+>The winbind uid parameter specifies the
+ range of user ids that are allocated by the winbindd daemon.
+ This range of ids should have no existing local or NIS users
+ within it as strange conflicts can occur otherwise. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind uid = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind uid = 10000-20000</B
+></P
+></DD
+><DT
+>winbind gid</DT
+><DD
+><P
+>The winbind gid parameter specifies the
+ range of group ids that are allocated by the winbindd daemon.
+ This range of group ids should have no existing local or NIS
+ groups within it as strange conflicts can occur otherwise.</P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind gid = &#60;empty string&#62;
+ </B
+></P
+><P
+>Example: <B
+CLASS="COMMAND"
+>winbind gid = 10000-20000
+ </B
+> </P
+></DD
+><DT
+>winbind cache time</DT
+><DD
+><P
+>This parameter specifies the number of
+ seconds the winbindd daemon will cache user and group information
+ before querying a Windows NT server again. When a item in the
+ cache is older than this time winbindd will ask the domain
+ controller for the sequence number of the server's account database.
+ If the sequence number has not changed then the cached item is
+ marked as valid for a further <TT
+CLASS="PARAMETER"
+><I
+>winbind cache time
+ </I
+></TT
+> seconds. Otherwise the item is fetched from the
+ server. This means that as long as the account database is not
+ actively changing winbindd will only have to send one sequence
+ number query packet every <TT
+CLASS="PARAMETER"
+><I
+>winbind cache time
+ </I
+></TT
+> seconds. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind cache time = 15</B
+>
+ </P
+></DD
+><DT
+>winbind enum users</DT
+><DD
+><P
+>On large installations it may be necessary
+ to suppress the enumeration of users through the <B
+CLASS="COMMAND"
+> setpwent()</B
+>, <B
+CLASS="COMMAND"
+>getpwent()</B
+> and
+ <B
+CLASS="COMMAND"
+>endpwent()</B
+> group of system calls. If
+ the <TT
+CLASS="PARAMETER"
+><I
+>winbind enum users</I
+></TT
+> parameter is false,
+ calls to the <B
+CLASS="COMMAND"
+>getpwent</B
+> system call will not
+ return any data. </P
+><P
+><EM
+>Warning:</EM
+> Turning off user enumeration
+ may cause some programs to behave oddly. For example, the <B
+CLASS="COMMAND"
+>finger</B
+>
+ program relies on having access to the full user list when
+ searching for matching usernames. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind enum users = yes </B
+></P
+></DD
+><DT
+>winbind enum groups</DT
+><DD
+><P
+>On large installations it may be necessary
+ to suppress the enumeration of groups through the <B
+CLASS="COMMAND"
+> setgrent()</B
+>, <B
+CLASS="COMMAND"
+>getgrent()</B
+> and
+ <B
+CLASS="COMMAND"
+>endgrent()</B
+> group of system calls. If
+ the <TT
+CLASS="PARAMETER"
+><I
+>winbind enum groups</I
+></TT
+> parameter is
+ false, calls to the <B
+CLASS="COMMAND"
+>getgrent()</B
+> system
+ call will not return any data. </P
+><P
+><EM
+>Warning:</EM
+> Turning off group
+ enumeration may cause some programs to behave oddly.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>winbind enum groups = no </B
+>
+ </P
+></DD
+><DT
+>template homedir</DT
+><DD
+><P
+>When filling out the user information
+ for a Windows NT user, the <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+ uses this parameter to fill in the home directory for that user.
+ If the string <TT
+CLASS="PARAMETER"
+><I
+>%D</I
+></TT
+> is present it is
+ substituted with the user's Windows NT domain name. If the
+ string <TT
+CLASS="PARAMETER"
+><I
+>%U</I
+></TT
+> is present it is substituted
+ with the user's Windows NT user name. </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>template homedir = /home/%D/%U </B
+>
+ </P
+></DD
+><DT
+>template shell</DT
+><DD
+><P
+>When filling out the user information for
+ a Windows NT user, the <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon
+ uses this parameter to fill in the shell for that user.
+ </P
+><P
+>Default: <B
+CLASS="COMMAND"
+>template shell = /bin/false </B
+>
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN149"
+></A
+><H2
+>EXAMPLE SETUP</H2
+><P
+>To setup winbindd for user and group lookups plus
+ authentication from a domain controller use something like the
+ following setup. This was tested on a RedHat 6.2 Linux box. </P
+><P
+>In <TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf</TT
+> put the
+ following:</P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>passwd: files winbind
+group: files winbind
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>In <TT
+CLASS="FILENAME"
+>/etc/pam.d/*</TT
+> replace the
+ <TT
+CLASS="PARAMETER"
+><I
+>auth</I
+></TT
+> lines with something like this: </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>auth required /lib/security/pam_securetty.so
+auth required /lib/security/pam_nologin.so
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_pwdb.so use_first_pass shadow nullok
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Note in particular the use of the <TT
+CLASS="PARAMETER"
+><I
+>sufficient</I
+></TT
+>
+ keyword and the <TT
+CLASS="PARAMETER"
+><I
+>use_first_pass</I
+></TT
+> keyword. </P
+><P
+>Now replace the account lines with this: </P
+><P
+><B
+CLASS="COMMAND"
+>account required /lib/security/pam_winbind.so
+ </B
+></P
+><P
+>The next step is to join the domain. To do that use the
+ <B
+CLASS="COMMAND"
+>smbpasswd</B
+> program like this: </P
+><P
+><B
+CLASS="COMMAND"
+>smbpasswd -j DOMAIN -r PDC -U
+ Administrator</B
+></P
+><P
+>The username after the <TT
+CLASS="PARAMETER"
+><I
+>-U</I
+></TT
+> can be any
+ Domain user that has administrator privileges on the machine.
+ Substitute your domain name for "DOMAIN" and the name of your PDC
+ for "PDC".</P
+><P
+>Next copy <TT
+CLASS="FILENAME"
+>libnss_winbind.so</TT
+> to
+ <TT
+CLASS="FILENAME"
+>/lib</TT
+> and <TT
+CLASS="FILENAME"
+>pam_winbind.so</TT
+>
+ to <TT
+CLASS="FILENAME"
+>/lib/security</TT
+>. A symbolic link needs to be
+ made from <TT
+CLASS="FILENAME"
+>/lib/libnss_winbind.so</TT
+> to
+ <TT
+CLASS="FILENAME"
+>/lib/libnss_winbind.so.2</TT
+>. If you are using an
+ older version of glibc then the target of the link should be
+ <TT
+CLASS="FILENAME"
+>/lib/libnss_winbind.so.1</TT
+>.</P
+><P
+>Finally, setup a <TT
+CLASS="FILENAME"
+>smb.conf</TT
+> containing directives like the
+ following: </P
+><P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>[global]
+ winbind separator = +
+ winbind cache time = 10
+ template shell = /bin/bash
+ template homedir = /home/%D/%U
+ winbind uid = 10000-20000
+ winbind gid = 10000-20000
+ workgroup = DOMAIN
+ security = domain
+ password server = *
+ </PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>Now start winbindd and you should find that your user and
+ group database is expanded to include your NT users and groups,
+ and that you can login to your unix box as a domain user, using
+ the DOMAIN+user syntax for the username. You may wish to use the
+ commands <B
+CLASS="COMMAND"
+>getent passwd</B
+> and <B
+CLASS="COMMAND"
+>getent group
+ </B
+> to confirm the correct operation of winbindd.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN188"
+></A
+><H2
+>NOTES</H2
+><P
+>The following notes are useful when configuring and
+ running <B
+CLASS="COMMAND"
+>winbindd</B
+>: </P
+><P
+><B
+CLASS="COMMAND"
+>nmbd</B
+> must be running on the local machine
+ for <B
+CLASS="COMMAND"
+>winbindd</B
+> to work. <B
+CLASS="COMMAND"
+>winbindd</B
+>
+ queries the list of trusted domains for the Windows NT server
+ on startup and when a SIGHUP is received. Thus, for a running <B
+CLASS="COMMAND"
+> winbindd</B
+> to become aware of new trust relationships between
+ servers, it must be sent a SIGHUP signal. </P
+><P
+>Client processes resolving names through the <B
+CLASS="COMMAND"
+>winbindd</B
+>
+ nsswitch module read an environment variable named <TT
+CLASS="ENVAR"
+> $WINBINDD_DOMAIN</TT
+>. If this variable contains a comma separated
+ list of Windows NT domain names, then winbindd will only resolve users
+ and groups within those Windows NT domains. </P
+><P
+>PAM is really easy to misconfigure. Make sure you know what
+ you are doing when modifying PAM configuration files. It is possible
+ to set up PAM such that you can no longer log into your system. </P
+><P
+>If more than one UNIX machine is running <B
+CLASS="COMMAND"
+>winbindd</B
+>,
+ then in general the user and groups ids allocated by winbindd will not
+ be the same. The user and group ids will only be valid for the local
+ machine.</P
+><P
+>If the the Windows NT RID to UNIX user and group id mapping
+ file is damaged or destroyed then the mappings will be lost. </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN204"
+></A
+><H2
+>SIGNALS</H2
+><P
+>The following signals can be used to manipulate the
+ <B
+CLASS="COMMAND"
+>winbindd</B
+> daemon. </P
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>SIGHUP</DT
+><DD
+><P
+>Reload the <TT
+CLASS="FILENAME"
+>smb.conf(5)</TT
+>
+ file and apply any parameter changes to the running
+ version of winbindd. This signal also clears any cached
+ user and group information. The list of other domains trusted
+ by winbindd is also reloaded. </P
+></DD
+><DT
+>SIGUSR1</DT
+><DD
+><P
+>The SIGUSR1 signal will cause <B
+CLASS="COMMAND"
+> winbindd</B
+> to write status information to the winbind
+ log file including information about the number of user and
+ group ids allocated by <B
+CLASS="COMMAND"
+>winbindd</B
+>.</P
+><P
+>Log files are stored in the filename specified by the
+ log file parameter.</P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN221"
+></A
+><H2
+>FILES</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>/etc/nsswitch.conf(5)</TT
+></DT
+><DD
+><P
+>Name service switch configuration file.</P
+></DD
+><DT
+>/tmp/.winbindd/pipe</DT
+><DD
+><P
+>The UNIX pipe over which clients communicate with
+ the <B
+CLASS="COMMAND"
+>winbindd</B
+> program. For security reasons, the
+ winbind client will only attempt to connect to the winbindd daemon
+ if both the <TT
+CLASS="FILENAME"
+>/tmp/.winbindd</TT
+> directory
+ and <TT
+CLASS="FILENAME"
+>/tmp/.winbindd/pipe</TT
+> file are owned by
+ root. </P
+></DD
+><DT
+>/lib/libnss_winbind.so.X</DT
+><DD
+><P
+>Implementation of name service switch library.
+ </P
+></DD
+><DT
+>$LOCKDIR/winbindd_idmap.tdb</DT
+><DD
+><P
+>Storage for the Windows NT rid to UNIX user/group
+ id mapping. The lock directory is specified when Samba is initially
+ compiled using the <TT
+CLASS="PARAMETER"
+><I
+>--with-lockdir</I
+></TT
+> option.
+ This directory is by default <TT
+CLASS="FILENAME"
+>/usr/local/samba/var/locks
+ </TT
+>. </P
+></DD
+><DT
+>$LOCKDIR/winbindd_cache.tdb</DT
+><DD
+><P
+>Storage for cached user and group information.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN250"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN253"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><TT
+CLASS="FILENAME"
+>nsswitch.conf(5)</TT
+>,
+ <A
+HREF="samba.7.html"
+TARGET="_top"
+>samba(7)</A
+>,
+ <A
+HREF="wbinfo.1.html"
+TARGET="_top"
+>wbinfo(1)</A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN260"
+></A
+><H2
+>AUTHOR</H2
+><P
+>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</P
+><P
+><B
+CLASS="COMMAND"
+>wbinfo</B
+> and <B
+CLASS="COMMAND"
+>winbindd</B
+>
+ were written by Tim Potter.</P
+><P
+>The conversion to DocBook for Samba 2.2 was done
+ by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/manpages/findsmb.1 b/docs/manpages/findsmb.1
new file mode 100644
index 00000000000..23a51a353de
--- /dev/null
+++ b/docs/manpages/findsmb.1
@@ -0,0 +1,90 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "FINDSMB" "1" "06 December 2001" "" ""
+.SH NAME
+findsmb \- list info about machines that respond to SMB name queries on a subnet
+.SH SYNOPSIS
+.sp
+\fBfindsmb\fR [ \fBsubnet broadcast address\fR ]
+.SH "DESCRIPTION"
+.PP
+This perl script is part of the Sambasuite.
+.PP
+\fBfindsmb\fR is a perl script that
+prints out several pieces of information about machines
+on a subnet that respond to SMB name query requests.
+It uses \fB nmblookup(1)\fRto obtain this information.
+.SH "OPTIONS"
+.TP
+\fBsubnet broadcast address\fR
+Without this option, \fBfindsmb
+\fRwill probe the subnet of the machine where
+\fBfindsmb\fR is run. This value is passed
+to \fBnmblookup\fR as part of the
+-B option
+.SH "EXAMPLES"
+.PP
+The output of \fBfindsmb\fR lists the following
+information for all machines that respond to the initial
+\fBnmblookup\fR for any name: IP address, NetBIOS name,
+Workgroup name, operating system, and SMB server version.
+.PP
+There will be a '+' in front of the workgroup name for
+machines that are local master browsers for that workgroup. There
+will be an '*' in front of the workgroup name for
+machines that are the domain master browser for that workgroup.
+Machines that are running Windows, Windows 95 or Windows 98 will
+not show any information about the operating system or server
+version.
+.PP
+The command must be run on a system without \fBnmbd\fRrunning.
+If \fBnmbd\fR is running on the system, you will
+only get the IP address and the DNS name of the machine. To
+get proper responses from Windows 95 and Windows 98 machines,
+the command must be run as root.
+.PP
+For example running \fBfindsmb\fR on a machine
+without \fBnmbd\fR running would yield output similar
+to the following
+.sp
+.nf
+IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION
+---------------------------------------------------------------------
+192.168.35.10 MINESET-TEST1 [DMVENGR]
+192.168.35.55 LINUXBOX *[MYGROUP] [Unix] [Samba 2.0.6]
+192.168.35.56 HERBNT2 [HERB-NT]
+192.168.35.63 GANDALF [MVENGR] [Unix] [Samba 2.0.5a for IRIX]
+192.168.35.65 SAUNA [WORKGROUP] [Unix] [Samba 1.9.18p10]
+192.168.35.71 FROGSTAR [ENGR] [Unix] [Samba 2.0.0 for IRIX]
+192.168.35.78 HERBDHCP1 +[HERB]
+192.168.35.88 SCNT2 +[MVENGR] [Windows NT 4.0] [NT LAN Manager 4.0]
+192.168.35.93 FROGSTAR-PC [MVENGR] [Windows 5.0] [Windows 2000 LAN Manager]
+192.168.35.97 HERBNT1 *[HERB-NT] [Windows NT 4.0] [NT LAN Manager 4.0]
+
+.sp
+.fi
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBnmbd(8)\fR,
+\fBsmbclient(1)
+\fR
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/lmhosts.5 b/docs/manpages/lmhosts.5
new file mode 100644
index 00000000000..eb55aa3104a
--- /dev/null
+++ b/docs/manpages/lmhosts.5
@@ -0,0 +1,92 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "LMHOSTS" "5" "06 December 2001" "" ""
+.SH NAME
+lmhosts \- The Samba NetBIOS hosts file
+.SH SYNOPSIS
+.PP
+\fIlmhosts\fR is the SambaNetBIOS name to IP address mapping file.
+.SH "DESCRIPTION"
+.PP
+This file is part of the Sambasuite.
+.PP
+\fIlmhosts\fR is the \fBSamba
+\fRNetBIOS name to IP address mapping file. It
+is very similar to the \fI/etc/hosts\fR file
+format, except that the hostname component must correspond
+to the NetBIOS naming format.
+.SH "FILE FORMAT"
+.PP
+It is an ASCII file containing one line for NetBIOS name.
+The two fields on each line are separated from each other by
+white space. Any entry beginning with '#' is ignored. Each line
+in the lmhosts file contains the following information :
+.TP 0.2i
+\(bu
+IP Address - in dotted decimal format.
+.TP 0.2i
+\(bu
+NetBIOS Name - This name format is a
+maximum fifteen character host name, with an optional
+trailing '#' character followed by the NetBIOS name type
+as two hexadecimal digits.
+
+If the trailing '#' is omitted then the given IP
+address will be returned for all names that match the given
+name, whatever the NetBIOS name type in the lookup.
+.PP
+An example follows :
+.PP
+.PP
+.sp
+.nf
+#
+# Sample Samba lmhosts file.
+#
+192.9.200.1 TESTPC
+192.9.200.20 NTSERVER#20
+192.9.200.21 SAMBASERVER
+
+.sp
+.fi
+.PP
+.PP
+Contains three IP to NetBIOS name mappings. The first
+and third will be returned for any queries for the names "TESTPC"
+and "SAMBASERVER" respectively, whatever the type component of
+the NetBIOS name requested.
+.PP
+.PP
+The second mapping will be returned only when the "0x20" name
+type for a name "NTSERVER" is queried. Any other name type will not
+be resolved.
+.PP
+.PP
+The default location of the \fIlmhosts\fR file
+is in the same directory as the
+smb.conf(5)>file.
+.PP
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbclient(1)
+\fR
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/make_smbcodepage.1 b/docs/manpages/make_smbcodepage.1
new file mode 100644
index 00000000000..bb53aeb02dd
--- /dev/null
+++ b/docs/manpages/make_smbcodepage.1
@@ -0,0 +1,140 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "MAKE_SMBCODEPAGE" "1" "06 December 2001" "" ""
+.SH NAME
+make_smbcodepage \- construct a codepage file for Samba
+.SH SYNOPSIS
+.sp
+\fBmake_smbcodepage\fR \fBc|d\fR \fBcodepage\fR \fBinputfile\fR \fBoutputfile\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBmake_smbcodepage\fR compiles or de-compiles
+codepage files for use with the internationalization features
+of Samba 2.2
+.SH "OPTIONS"
+.TP
+\fBc|d\fR
+This tells \fBmake_smbcodepage\fR
+if it is compiling (\fIc\fR) a text format code
+page file to binary, or (\fId\fR) de-compiling
+a binary codepage file to text.
+.TP
+\fBcodepage\fR
+This is the codepage we are processing (a
+number, e.g. 850).
+.TP
+\fBinputfile\fR
+This is the input file to process. In
+the \fIc\fR case this will be a text
+codepage definition file such as the ones found in the Samba
+\fIsource/codepages\fR directory. In
+the \fId\fR case this will be the
+binary format codepage definition file normally found in
+the \fIlib/codepages\fR directory in the
+Samba install directory path.
+.TP
+\fBoutputfile\fR
+This is the output file to produce.
+.SH "SAMBA CODEPAGE FILES"
+.PP
+A text Samba codepage definition file is a description
+that tells Samba how to map from upper to lower case for
+characters greater than ascii 127 in the specified DOS code page.
+Note that for certain DOS codepages (437 for example) mapping
+from lower to upper case may be non-symmetrical. For example, in
+code page 437 lower case a acute maps to a plain upper case A
+when going from lower to upper case, but plain upper case A maps
+to plain lower case a when lower casing a character.
+.PP
+A binary Samba codepage definition file is a binary
+representation of the same information, including a value that
+specifies what codepage this file is describing.
+.PP
+As Samba does not yet use UNICODE (current for Samba version 2.2)
+you must specify the client code page that your DOS and Windows
+clients are using if you wish to have case insensitivity done
+correctly for your particular language. The default codepage Samba
+uses is 850 (Western European). Text codepage definition sample files
+are provided in the Samba distribution for codepages 437 (USA), 737 (Greek),
+850 (Western European) 852 (MS-DOS Latin 2), 861 (Icelandic), 866 (Cyrillic),
+932 (Kanji SJIS), 936 (Simplified Chinese), 949 (Hangul) and 950 (Traditional
+Chinese). Users are encouraged to write text codepage definition files for
+their own code pages and donate them to samba@samba.org. All codepage files
+in the Samba \fIsource/codepages\fR directory are
+compiled and installed when a \fB'make install'\fR
+command is issued there.
+.PP
+The client codepage used by the \fBsmbd\fR server
+is configured using the \fBclient code page\fR parameter
+in the \fBsmb.conf\fR file.
+.SH "FILES"
+.PP
+\fBcodepage_def.<codepage>\fR
+.PP
+These are the input (text) codepage files provided in the
+Samba \fIsource/codepages\fR directory.
+.PP
+A text codepage definition file consists of multiple lines
+containing four fields. These fields are:
+.TP 0.2i
+\(bu
+\fBlower\fR: which is the
+(hex) lower case character mapped on this line.
+.TP 0.2i
+\(bu
+\fBupper\fR: which is the (hex)
+upper case character that the lower case character will map to.
+.TP 0.2i
+\(bu
+\fBmap upper to lower\fR which
+is a boolean value (put either True or False here) which tells
+Samba if it is to map the given upper case character to the
+given lower case character when lower casing a filename.
+.TP 0.2i
+\(bu
+\fBmap lower to upper\fR which
+is a boolean value (put either True or False here) which tells
+Samba if it is to map the given lower case character to the
+given upper case character when upper casing a filename.
+.PP
+\fBcodepage.<codepage>\fR - These are the
+output (binary) codepage files produced and placed in the Samba
+destination \fIlib/codepage\fR directory.
+.PP
+.SH "INSTALLATION"
+.PP
+The location of the server and its support files is a
+matter for individual system administrators. The following are
+thus suggestions only.
+.PP
+It is recommended that the \fBmake_smbcodepage
+\fRprogram be installed under the \fI/usr/local/samba
+\fRhierarchy, in a directory readable by all, writeable
+only by root. The program itself should be executable by all. The
+program should NOT be setuid or setgid!
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fR,
+smb.conf(5)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/make_unicodemap.1 b/docs/manpages/make_unicodemap.1
new file mode 100644
index 00000000000..93683c2708e
--- /dev/null
+++ b/docs/manpages/make_unicodemap.1
@@ -0,0 +1,99 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "MAKE_UNICODEMAP" "1" "06 December 2001" "" ""
+.SH NAME
+make_unicodemap \- construct a unicode map file for Samba
+.SH SYNOPSIS
+.sp
+\fBmake_unicodemap\fR \fBcodepage\fR \fBinputfile\fR \fBoutputfile\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Samba
+suite.
+.PP
+\fBmake_unicodemap\fR compiles text unicode map
+files into binary unicode map files for use with the
+internationalization features of Samba 2.2.
+.SH "OPTIONS"
+.TP
+\fBcodepage\fR
+This is the codepage or UNIX character
+set we are processing (a number, e.g. 850).
+.TP
+\fBinputfile\fR
+This is the input file to process. This is a
+text unicode map file such as the ones found in the Samba
+\fIsource/codepages\fR directory.
+.TP
+\fBoutputfile\fR
+This is the binary output file to produce.
+.SH "SAMBA UNICODE MAP FILES"
+.PP
+A text Samba unicode map file is a description that tells Samba
+how to map characters from a specified DOS code page or UNIX character
+set to 16 bit unicode.
+.PP
+A binary Samba unicode map file is a binary representation
+of the same information, including a value that specifies what
+codepage or UNIX character set this file is describing.
+.SH "FILES"
+.PP
+\fICP<codepage>.TXT\fR
+.PP
+These are the input (text) unicode map files provided
+in the Samba \fIsource/codepages\fR
+directory.
+.PP
+A text unicode map file consists of multiple lines
+containing two fields. These fields are :
+.TP 0.2i
+\(bu
+\fIcharacter\fR - which is
+the (hex) character mapped on this line.
+.TP 0.2i
+\(bu
+\fIunicode\fR - which
+is the (hex) 16 bit unicode character that the character
+will map to.
+.PP
+\fIunicode_map.<codepage>\fR - These are
+the output (binary) unicode map files produced and placed in
+the Samba destination \fIlib/codepage\fR
+directory.
+.PP
+.SH "INSTALLATION"
+.PP
+The location of the server and its support files is a matter
+for individual system administrators. The following are thus
+suggestions only.
+.PP
+It is recommended that the \fBmake_unicodemap\fR
+program be installed under the
+\fI$prefix/samba\fR hierarchy,
+in a directory readable by all, writeable only by root. The
+program itself should be executable by all. The program
+should NOT be setuid or setgid!
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fR,
+smb.conf(5)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index e42f194cdee..e7786549a1e 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -1,491 +1,241 @@
-.TH NMBD 8 17/1/1995 nmbd nmbd
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "NMBD" "8" "06 December 2001" "" ""
.SH NAME
-nmbd \- provide netbios nameserver support to clients
+nmbd \- NetBIOS name server to provide NetBIOS over IP naming services to clients
.SH SYNOPSIS
-.B nmbd
-[
-.B -B
-.I broadcast address
-] [
-.B -I
-.I IP address
-] [
-.B -D
-] [
-.B -C comment string
-] [
-.B -G
-.I group name
-] [
-.B -H
-.I netbios hosts file
-] [
-.B -N
-.I netmask
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log basename
-] [
-.B -n
-.I netbios name
-] [
-.B -p
-.I port number
-] [
-.B -s
-.I config file name
-]
-
-.SH DESCRIPTION
+.sp
+\fBnmbd\fR [ \fB-D\fR ] [ \fB-a\fR ] [ \fB-o\fR ] [ \fB-P\fR ] [ \fB-h\fR ] [ \fB-V\fR ] [ \fB-d <debug level>\fR ] [ \fB-H <lmhosts file>\fR ] [ \fB-l <log directory>\fR ] [ \fB-n <primary netbios name>\fR ] [ \fB-p <port number>\fR ] [ \fB-s <configuration file>\fR ]
+.SH "DESCRIPTION"
+.PP
This program is part of the Samba suite.
-
-.B nmbd
-is a server that understands and can reply to netbios
-name service requests, like those produced by LanManager
-clients. It also controls browsing.
-
-LanManager clients, when they start up, may wish to locate a LanManager server.
-That is, they wish to know what IP number a specified host is using.
-
-This program simply listens for such requests, and if its own name is specified
-it will respond with the IP number of the host it is running on. "Its own name"
-is by default the name of the host it is running on, but this can be overriden
-with the
-.B -n
-option (see "OPTIONS" below). Using the
-.B -S
-option (see "OPTIONS" below), it can also be instructed to respond with IP
-information about other hosts, provided they are locatable via the
-gethostbyname() call, or they are in a netbios hosts file.
-
-Nmbd can also be used as a WINS (Windows Internet Name Server)
-server. It will do this automatically by default. What this basically
-means is that it will respond to all name requests that it receives
-that are not broadcasts, as long as it can resolve the name.
-.SH OPTIONS
-.B -B
-
-.RS 3
-On some systems, the server is unable to determine the broadcast address to
-use for name registration requests. If your system has this difficulty, this
-parameter may be used to specify an appropriate broadcast address. The
-address should be given in standard "a.b.c.d" notation.
-
-Only use this parameter if you are sure that the server cannot properly
-determine the proper broadcast address.
-
-The default broadcast address is determined by the server at run time. If it
-encounters difficulty doing so, it makes a guess based on the local IP
-number.
-.RE
-.B -I
-
-.RS 3
-On some systems, the server is unable to determine the correct IP
-address to use. This allows you to override the default choice.
-.RE
-
-.B -D
-
-.RS 3
-If specified, this parameter causes the server to operate as a daemon. That is,
-it detaches itself and runs in the background, fielding requests on the
-appropriate port.
-
-By default, the server will NOT operate as a daemon.
-.RE
-
-.B -C comment string
-
-.RS 3
-This allows you to set the "comment string" that is shown next to the
-machine name in browse listings.
-
-A %v will be replaced with the Samba version number.
-
-A %h will be replaced with the hostname.
-
-It defaults to "Samba %v".
-.RE
-
-.B -G
-
-.RS 3
-This option allows you to specify a netbios group (also known as
-lanmanager domain) that the server should be part of. You may include
-several of these on the command line if you like. Alternatively you
-can use the -H option to load a netbios hosts file containing domain names.
-
-At startup, unless the -R switch has been used, the server will
-attempt to register all group names in the hosts file and on the
-command line (from the -G option).
-
-The server will also respond to queries on this name.
-.RE
-
-.B -H
-
-.RS 3
-It may be useful in some situations to be able to specify a list of
-netbios names for which the server should send a reply if
-queried. This option allows that. The syntax is similar to the
-standard /etc/hosts file format, but has some extensions.
-
-The file contains three columns. Lines beginning with a # are ignored
-as comments. The first column is an IP address, or a hostname. If it
-is a hostname then it is interpreted as the IP address returned by
-gethostbyname() when read. Any IP address of 0.0.0.0 will be
-interpreted as the servers own IP address.
-
-The second column is a netbios name. This is the name that the server
-will respond to. It must be less than 20 characters long.
-
-The third column is optional, and is intended for flags. Currently the
-only flags supported are G, S and M. A G indicates that the name is a
-group (also known as domain) name.
-
-At startup all groups known to the server (either from this file or
-from the -G option) are registered on the network (unless the -R
-option has been selected).
-
-A S or G means that the specified address is a broadcast address of a
-network that you want people to be able to browse you from. Nmbd will
-search for a master browser in that domain and will send host
-announcements to that machine, informing it that the specifed somain
-is available.
-
-A M means that this name is the default netbios name for this
-machine. This has the same affect as specifying the -n option to nmbd.
-
-After startup the server waits for queries, and will answer queries to
-any name known to it. This includes all names in the netbios hosts
-file (if any), it's own name, and any names given with the -G option.
-
-The primary intention of the -H option is to allow a mapping from
-netbios names to internet domain names, and to allow the specification
-of groups that the server should be part of.
-
-.B Example:
-
- # This is a sample netbios hosts file
-
- # DO NOT USE THIS FILE AS-IS
- # YOU MAY INCONVENIENCE THE OWNERS OF THESE IPs
- # if you want to include a name with a space in it then
- # use double quotes.
-
- # first put ourselves in the group LANGROUP
- 0.0.0.0 LANGROUP G
-
- # next add a netbios alias for a faraway host
- arvidsjaur.anu.edu.au ARVIDSJAUR
-
- # finally put in an IP for a hard to find host
- 130.45.3.213 FREDDY
-
- # now we want another subnet to be able to browse
- # us in the workgroup UNIXSERV
- 192.0.2.255 UNIXSERV G
-
-.RE
-
-.B -M
-.I workgroup name
-
-.RS 3
-If this parameter is given, the server will look for a master browser
-for the specified workgroup name, report success or failure, then
-exit. If successful, the IP address of the name located will be
-reported.
-
-If you use the workgroup name "-" then nmbd will search for a master
-browser for any workgroup by using the name __MSBROWSE__.
-
-This option is meant to be used interactively on the command line, not
-as a daemon or in inetd.
-
-.RE
-.B -N
-
-.RS 3
-On some systems, the server is unable to determine the netmask. If
-your system has this difficulty, this parameter may be used to specify
-an appropriate netmask. The mask should be given in standard
-"a.b.c.d" notation.
-
-Only use this parameter if you are sure that the server cannot properly
-determine the proper netmask.
-
-The default netmask is determined by the server at run time. If it
-encounters difficulty doing so, it makes a guess based on the local IP
-number.
-.RE
-
-.B -d
-.I debuglevel
-.RS 3
-
-debuglevel is an integer from 0 to 5.
-
-The default value if this parameter is not specified is zero.
-
-The higher this value, the more detail will be logged to the log files about
-the activities of the server. At level 0, only critical errors and serious
-warnings will be logged. Level 1 is a reasonable level for day to day running
-- it generates a small amount of information about operations carried out.
-
-Levels above 1 will generate considerable amounts of log data, and should
-only be used when investigating a problem. Levels above 3 are designed for
-use only by developers and generate HUGE amounts of log data, most of which
-is extremely cryptic.
-.RE
-
-.B -l
-.I log file
-
-.RS 3
-If specified,
-.I logfile
-specifies a base filename into which operational data from the running server
-will be logged.
-
-The default base name is specified at compile time.
-
-The base name is used to generate actual log file names. For example, if the
-name specified was "log", the following files would be used for log data:
-
-.RS 3
-log.nmb (containing debugging information)
-
-log.nmb.in (containing inbound transaction data)
-
-log.nmb.out (containing outbound transaction data)
-.RE
-
-The log files generated are never removed by the server.
-.RE
-.RE
-
-.B -n
-.I netbios name
-
-.RS 3
-This parameter tells the server what netbios name to respond with when
-queried. The same name is also registered on startup unless the -R
-parameter was specified.
-
-The default netbios name used if this parameter is not specified is the
-name of the host on which the server is running.
-.RE
-
-.B -p
-.I port number
-.RS 3
-
-port number is a positive integer value.
-
-The default value if this parameter is not specified is 137.
-
-This number is the port number that will be used when making connections to
-the server from client software. The standard (well-known) port number for the
-server is 137, hence the default. If you wish to run the server as an ordinary
-user rather than as root, most systems will require you to use a port number
-greater than 1024 - ask your system administrator for help if you are in this
-situation.
-
-Note that the name server uses UDP, not TCP!
-
-This parameter is not normally specified except in the above situation.
-.RE
-.SH FILES
-
-.B /etc/inetd.conf
-
-.RS 3
-If the server is to be run by the inetd meta-daemon, this file must contain
-suitable startup information for the meta-daemon. See the section
-"INSTALLATION" below.
-.RE
-
-.B /etc/rc.d/rc.inet2
-
-.RS 3
-(or whatever initialisation script your system uses)
-
-If running the server as a daemon at startup, this file will need to contain
-an appropriate startup sequence for the server. See the section "Installation"
+.PP
+\fBnmbd\fR is a server that understands
+and can reply to NetBIOS over IP name service requests, like
+those produced by SMB/CIFS clients such as Windows 95/98/ME,
+Windows NT, Windows 2000, and LanManager clients. It also
+participates in the browsing protocols which make up the
+Windows "Network Neighborhood" view.
+.PP
+SMB/CIFS clients, when they start up, may wish to
+locate an SMB/CIFS server. That is, they wish to know what
+IP number a specified host is using.
+.PP
+Amongst other services, \fBnmbd\fR will
+listen for such requests, and if its own NetBIOS name is
+specified it will respond with the IP number of the host it
+is running on. Its "own NetBIOS name" is by
+default the primary DNS name of the host it is running on,
+but this can be overridden with the \fB-n\fR
+option (see OPTIONS below). Thus \fBnmbd\fR will
+reply to broadcast queries for its own name(s). Additional
+names for \fBnmbd\fR to respond on can be set
+via parameters in the \fI smb.conf(5)\fRconfiguration file.
+.PP
+\fBnmbd\fR can also be used as a WINS
+(Windows Internet Name Server) server. What this basically means
+is that it will act as a WINS database server, creating a
+database from name registration requests that it receives and
+replying to queries from clients for these names.
+.PP
+In addition, \fBnmbd\fR can act as a WINS
+proxy, relaying broadcast queries from clients that do
+not understand how to talk the WINS protocol to a WIN
+server.
+.SH "OPTIONS"
+.TP
+\fB-D\fR
+If specified, this parameter causes
+\fBnmbd\fR to operate as a daemon. That is,
+it detaches itself and runs in the background, fielding
+requests on the appropriate port. By default, \fBnmbd\fR
+will operate as a daemon if launched from a command shell.
+nmbd can also be operated from the \fBinetd\fR
+meta-daemon, although this is not recommended.
+.TP
+\fB-a\fR
+If this parameter is specified, each new
+connection will append log messages to the log file.
+This is the default.
+.TP
+\fB-o\fR
+If this parameter is specified, the
+log files will be overwritten when opened. By default,
+\fBsmbd\fR will append entries to the log
+files.
+.TP
+\fB-h\fR
+Prints the help information (usage)
+for \fBnmbd\fR.
+.TP
+\fB-H <filename>\fR
+NetBIOS lmhosts file. The lmhosts
+file is a list of NetBIOS names to IP addresses that
+is loaded by the nmbd server and used via the name
+resolution mechanism name resolve order
+to resolve any NetBIOS name queries needed by the server. Note
+that the contents of this file are \fBNOT\fR
+used by \fBnmbd\fR to answer any name queries.
+Adding a line to this file affects name NetBIOS resolution
+from this host \fBONLY\fR.
+
+The default path to this file is compiled into
+Samba as part of the build process. Common defaults
+are \fI/usr/local/samba/lib/lmhosts\fR,
+\fI/usr/samba/lib/lmhosts\fR or
+\fI/etc/lmhosts\fR. See the \fIlmhosts(5)\fRman page for details on the
+contents of this file.
+.TP
+\fB-V\fR
+Prints the version number for
+\fBnmbd\fR.
+.TP
+\fB-d <debug level>\fR
+debuglevel is an integer
+from 0 to 10. The default value if this parameter is
+not specified is zero.
+
+The higher this value, the more detail will
+be logged to the log files about the activities of the
+server. At level 0, only critical errors and serious
+warnings will be logged. Level 1 is a reasonable level for
+day to day running - it generates a small amount of
+information about operations carried out.
+
+Levels above 1 will generate considerable amounts
+of log data, and should only be used when investigating
+a problem. Levels above 3 are designed for use only by developers
+and generate HUGE amounts of log data, most of which is extremely
+cryptic.
+
+Note that specifying this parameter here will override
+the log level
+parameter in the \fI smb.conf\fRfile.
+.TP
+\fB-l <log directory>\fR
+The -l parameter specifies a directory
+into which the "log.nmbd" log file will be created
+for operational data from the running
+\fBnmbd\fR server.
+
+The default log directory is compiled into Samba
+as part of the build process. Common defaults are \fI /usr/local/samba/var/log.nmb\fR, \fI /usr/samba/var/log.nmb\fR or
+\fI/var/log/log.nmb\fR.
+.TP
+\fB-n <primary NetBIOS name>\fR
+This option allows you to override
+the NetBIOS name that Samba uses for itself. This is identical
+to setting the NetBIOS nameparameter in the
+\fIsmb.conf\fRfile. However, a command
+line setting will take precedence over settings in
+\fIsmb.conf\fR.
+.TP
+\fB-p <UDP port number>\fR
+UDP port number is a positive integer value.
+This option changes the default UDP port number (normally 137)
+that \fBnmbd\fR responds to name queries on. Don't
+use this option unless you are an expert, in which case you
+won't need help!
+.TP
+\fB-s <configuration file>\fR
+The default configuration file name
+is set at build time, typically as \fI /usr/local/samba/lib/smb.conf\fR, but
+this may be changed when Samba is autoconfigured.
+
+The file specified contains the configuration details
+required by the server. See
+\fIsmb.conf(5)\fRfor more information.
+.SH "FILES"
+.TP
+\fB\fI/etc/inetd.conf\fB\fR
+If the server is to be run by the
+\fBinetd\fR meta-daemon, this file
+must contain suitable startup information for the
+meta-daemon. See the section INSTALLATION below.
+.TP
+\fB\fI/etc/rc\fB\fR
+or whatever initialization script your
+system uses).
+
+If running the server as a daemon at startup,
+this file will need to contain an appropriate startup
+sequence for the server. See the section INSTALLATION
below.
-.RE
-
-.B /etc/services
-
-.RS 3
-If running the server via the meta-daemon inetd, this file must contain a
-mapping of service name (eg., netbios-ns) to service port (eg., 137) and
-protocol type (eg., udp). See the section "INSTALLATION" below.
-.RE
-.RE
-
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the server software be installed under the /usr/local
-hierarchy, in a directory readable by all, writeable only by root. The server
-program itself should be executable by all, as users may wish to run the
-server themselves (in which case it will of course run with their privileges).
-The server should NOT be setuid or setgid!
-
-The server log files should be put in a directory readable and writable only
-by root, as the log files may contain sensitive information.
-
-The remaining notes will assume the following:
-
-.RS 3
-nmbd (the server program) installed in /usr/local/smb
-
-log files stored in /var/adm/smblogs
-.RE
-
-The server may be run either as a daemon by users or at startup, or it may
-be run from a meta-daemon such as inetd upon request. If run as a daemon, the
-server will always be ready, so starting sessions will be faster. If run from
-a meta-daemon some memory will be saved and utilities such as the tcpd
-TCP-wrapper may be used for extra security.
-
-When you've decided, continue with either "Running the server as a daemon" or
-"Running the server on request".
-.SH RUNNING THE SERVER AS A DAEMON
-To run the server as a daemon from the command line, simply put the "-D" option
-on the command line. There is no need to place an ampersand at the end of the
-command line - the "-D" option causes the server to detach itself from the
-tty anyway.
-
-Any user can run the server as a daemon (execute permissions permitting, of
-course). This is useful for testing purposes.
-
-To ensure that the server is run as a daemon whenever the machine is started,
-you will need to modify the system startup files. Wherever appropriate (for
-example, in /etc/rc.d/rc.inet2), insert the following line, substituting
-values appropriate to your system:
-
-.RS 3
-/usr/local/smb/nmbd -D -l/var/adm/smblogs/log
-.RE
-
-(The above should appear in your initialisation script as a single line.
-Depending on your terminal characteristics, it may not appear that way in
-this man page. If the above appears as more than one line, please treat any
-newlines or indentation as a single space or TAB character.)
-
-If the options used at compile time are appropriate for your system, all
-parameters except the desired debug level and "-D" may be omitted. See the
-section on "Options" above.
-.SH RUNNING THE SERVER ON REQUEST
-If your system uses a meta-daemon such as inetd, you can arrange to have the
-SMB name server started whenever a process attempts to connect to it. This
-requires several changes to the startup files on the host machine. If you are
-experimenting as an ordinary user rather than as root, you will need the
-assistance of your system administrator to modify the system files.
-
-First, ensure that a port is configured in the file /etc/services. The
-well-known port 137 should be used if possible, though any port may be used.
-
-Ensure that a line similar to the following is in /etc/services:
-
-.RS 3
-netbios-ns 137/udp
-.RE
-
-Note for NIS/YP users: You may need to rebuild the NIS service maps rather
-than alter your local /etc/services file.
-
-Next, put a suitable line in the file /etc/inetd.conf (in the unlikely event
-that you are using a meta-daemon other than inetd, you are on your own). Note
-that the first item in this line matches the service name in /etc/services.
-Substitute appropriate values for your system in this line (see
-.B inetd(8)):
-
-.RS 3
-netbios-ns dgram udp wait root /usr/local/smb/nmbd -l/var/adm/smblogs/log
-.RE
-
-(The above should appear in /etc/inetd.conf as a single line. Depending on
-your terminal characteristics, it may not appear that way in this man page.
-If the above appears as more than one line, please treat any newlines or
-indentation as a single space or TAB character.)
-
-Note that there is no need to specify a port number here, even if you are
-using a non-standard port number.
-.SH TESTING THE INSTALLATION
-If running the server as a daemon, execute it before proceeding. If
-using a meta-daemon, either restart the system or kill and restart the
-meta-daemon. Some versions of inetd will reread their configuration tables if
-they receive a HUP signal.
-
-To test whether the name server is running, start up a client
-.I on a different machine
-and see whether the desired name is now present. Alternatively, run
-the nameserver
-.I on a different machine
-specifying "-L netbiosname", where "netbiosname" is the name you have
-configured the test server to respond with. The command should respond
-with success, and the IP number of the machine using the specified netbios
-name. You may need the -B parameter on some systems. See the README
-file for more information on testing nmbd.
-
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the server has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B inetd(8),
-.B smbd(8),
-.B smb.conf(5),
-.B smbclient(1),
-.B testparm(1),
-.B testprns(1)
-
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the server are logged in the specified log file. The
-log file name is specified at compile time, but may be overridden on the
-command line.
-
-The number and nature of diagnostics available depends on the debug level used
-by the server. If you have problems, set the debug level to 3 and peruse the
-log files.
-
-Most messages are reasonably self-explanatory. Unfortunately, at time of
-creation of this man page the source code is still too fluid to warrant
-describing each and every diagnostic. At this stage your best bet is still
-to grep the source code and inspect the conditions that gave rise to the
-diagnostics you are seeing.
-
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B smb.conf(5) for a full list of contributors and details on how to
-submit bug reports, comments etc.
-
-
-
-
-
+.TP
+\fB\fI/etc/services\fB\fR
+If running the server via the
+meta-daemon \fBinetd\fR, this file
+must contain a mapping of service name (e.g., netbios-ssn)
+to service port (e.g., 139) and protocol type (e.g., tcp).
+See the section INSTALLATION below.
+.TP
+\fB\fI/usr/local/samba/lib/smb.conf\fB\fR
+This is the default location of the
+\fIsmb.conf\fR
+server configuration file. Other common places that systems
+install this file are \fI/usr/samba/lib/smb.conf\fR
+and \fI/etc/smb.conf\fR.
+
+When run as a WINS server (see the
+wins support
+parameter in the \fI smb.conf(5)\fRman page), \fBnmbd\fR
+will store the WINS database in the file \fIwins.dat\fR
+in the \fIvar/locks\fR directory configured under
+wherever Samba was configured to install itself.
+
+If \fBnmbd\fR is acting as a \fB browse master\fR (see the local master
+parameter in the \fI smb.conf(5)\fRman page), \fBnmbd\fR
+will store the browsing database in the file \fIbrowse.dat
+\fRin the \fIvar/locks\fR directory
+configured under wherever Samba was configured to install itself.
+.SH "SIGNALS"
+.PP
+To shut down an \fBnmbd\fR process it is recommended
+that SIGKILL (-9) \fBNOT\fR be used, except as a last
+resort, as this may leave the name database in an inconsistent state.
+The correct way to terminate \fBnmbd\fR is to send it
+a SIGTERM (-15) signal and wait for it to die on its own.
+.PP
+\fBnmbd\fR will accept SIGHUP, which will cause
+it to dump out its namelists into the file \fInamelist.debug
+\fRin the \fI/usr/local/samba/var/locks\fR
+directory (or the \fIvar/locks\fR directory configured
+under wherever Samba was configured to install itself). This will also
+cause \fBnmbd\fR to dump out its server database in
+the \fIlog.nmb\fR file.
+.PP
+The debug log level of nmbd may be raised or lowered using
+\fBsmbcontrol(1)\fR
+(SIGUSR[1|2] signals are no longer used in Samba 2.2). This is
+to allow transient problems to be diagnosed, whilst still running
+at a normally low log level.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBinetd(8)\fR, \fBsmbd(8)\fR,
+\fIsmb.conf(5)\fR
+, \fBsmbclient(1)
+\fR, and the Internet RFC's
+\fIrfc1001.txt\fR, \fIrfc1002.txt\fR.
+In addition the CIFS (formerly SMB) specification is available
+as a link from the Web page
+http://samba.org/cifs/ <URL:http://samba.org/cifs/>.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/nmblookup.1 b/docs/manpages/nmblookup.1
new file mode 100644
index 00000000000..c607a4a72d5
--- /dev/null
+++ b/docs/manpages/nmblookup.1
@@ -0,0 +1,154 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "NMBLOOKUP" "1" "06 December 2001" "" ""
+.SH NAME
+nmblookup \- NetBIOS over TCP/IP client used to lookup NetBIOS names
+.SH SYNOPSIS
+.sp
+\fBnmblookup\fR [ \fB-M\fR ] [ \fB-R\fR ] [ \fB-S\fR ] [ \fB-r\fR ] [ \fB-A\fR ] [ \fB-h\fR ] [ \fB-B <broadcast address>\fR ] [ \fB-U <unicast address>\fR ] [ \fB-d <debug level>\fR ] [ \fB-s <smb config file>\fR ] [ \fB-i <NetBIOS scope>\fR ] [ \fB-T\fR ] \fBname\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBnmblookup\fR is used to query NetBIOS names
+and map them to IP addresses in a network using NetBIOS over TCP/IP
+queries. The options allow the name queries to be directed at a
+particular IP broadcast area or to a particular machine. All queries
+are done over UDP.
+.SH "OPTIONS"
+.TP
+\fB-M\fR
+Searches for a master browser by looking
+up the NetBIOS name \fIname\fR with a
+type of 0x1d. If \fI name\fR is "-" then it does a lookup on the special name
+__MSBROWSE__.
+.TP
+\fB-R\fR
+Set the recursion desired bit in the packet
+to do a recursive lookup. This is used when sending a name
+query to a machine running a WINS server and the user wishes
+to query the names in the WINS server. If this bit is unset
+the normal (broadcast responding) NetBIOS processing code
+on a machine is used instead. See rfc1001, rfc1002 for details.
+.TP
+\fB-S\fR
+Once the name query has returned an IP
+address then do a node status query as well. A node status
+query returns the NetBIOS names registered by a host.
+.TP
+\fB-r\fR
+Try and bind to UDP port 137 to send and receive UDP
+datagrams. The reason for this option is a bug in Windows 95
+where it ignores the source port of the requesting packet
+and only replies to UDP port 137. Unfortunately, on most UNIX
+systems root privilege is needed to bind to this port, and
+in addition, if the nmbd(8)
+daemon is running on this machine it also binds to this port.
+.TP
+\fB-A\fR
+Interpret \fIname\fR as
+an IP Address and do a node status query on this address.
+.TP
+\fB-h\fR
+Print a help (usage) message.
+.TP
+\fB-B <broadcast address>\fR
+Send the query to the given broadcast address. Without
+this option the default behavior of nmblookup is to send the
+query to the broadcast address of the network interfaces as
+either auto-detected or defined in the \fIinterfaces\fR
+parameter of the \fIsmb.conf (5)\fR file.
+.TP
+\fB-U <unicast address>\fR
+Do a unicast query to the specified address or
+host \fIunicast address\fR. This option
+(along with the \fI-R\fR option) is needed to
+query a WINS server.
+.TP
+\fB-d <debuglevel>\fR
+debuglevel is an integer from 0 to 10.
+
+The default value if this parameter is not specified
+is zero.
+
+The higher this value, the more detail will be logged
+about the activities of \fBnmblookup\fR. At level
+0, only critical errors and serious warnings will be logged.
+
+Levels above 1 will generate considerable amounts of
+log data, and should only be used when investigating a problem.
+Levels above 3 are designed for use only by developers and
+generate HUGE amounts of data, most of which is extremely cryptic.
+
+Note that specifying this parameter here will override
+the \fI log level\fRparameter in the \fI smb.conf(5)\fR file.
+.TP
+\fB-s <smb.conf>\fR
+This parameter specifies the pathname to
+the Samba configuration file, smb.conf(5). This file controls all aspects of
+the Samba setup on the machine.
+.TP
+\fB-i <scope>\fR
+This specifies a NetBIOS scope that
+\fBnmblookup\fR will use to communicate with when
+generating NetBIOS names. For details on the use of NetBIOS
+scopes, see rfc1001.txt and rfc1002.txt. NetBIOS scopes are
+\fBvery\fR rarely used, only set this parameter
+if you are the system administrator in charge of all the
+NetBIOS systems you communicate with.
+.TP
+\fB-T\fR
+This causes any IP addresses found in the
+lookup to be looked up via a reverse DNS lookup into a
+DNS name, and printed out before each
+
+\fBIP address .... NetBIOS name\fR
+
+pair that is the normal output.
+.TP
+\fBname\fR
+This is the NetBIOS name being queried. Depending
+upon the previous options this may be a NetBIOS name or IP address.
+If a NetBIOS name then the different name types may be specified
+by appending '#<type>' to the name. This name may also be
+\&'*', which will return all registered names within a broadcast
+area.
+.SH "EXAMPLES"
+.PP
+\fBnmblookup\fR can be used to query
+a WINS server (in the same way \fBnslookup\fR is
+used to query DNS servers). To query a WINS server,
+\fBnmblookup\fR must be called like this:
+.PP
+\fBnmblookup -U server -R 'name'\fR
+.PP
+For example, running :
+.PP
+\fBnmblookup -U samba.org -R 'IRIX#1B'\fR
+.PP
+would query the WINS server samba.org for the domain
+master browser (1B name type) for the IRIX workgroup.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBnmbd(8)\fR,
+samba(7)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/rpcclient.1 b/docs/manpages/rpcclient.1
new file mode 100644
index 00000000000..a29dbe28440
--- /dev/null
+++ b/docs/manpages/rpcclient.1
@@ -0,0 +1,329 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "RPCCLIENT" "1" "06 December 2001" "" ""
+.SH NAME
+rpcclient \- tool for executing client side MS-RPC functions
+.SH SYNOPSIS
+.sp
+\fBrpcclient\fR \fBserver\fR [ \fB-A authfile\fR ] [ \fB-c <command string>\fR ] [ \fB-d debuglevel\fR ] [ \fB-h\fR ] [ \fB-l logfile\fR ] [ \fB-N\fR ] [ \fB-s <smb config file>\fR ] [ \fB-U username[%password]\fR ] [ \fB-W workgroup\fR ] [ \fB-N\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBrpcclient\fR is a utility initially developed
+to test MS-RPC functionality in Samba itself. It has undergone
+several stages of development and stability. Many system administrators
+have now written scripts around it to manage Windows NT clients from
+their UNIX workstation.
+.SH "OPTIONS"
+.TP
+\fBserver\fR
+NetBIOS name of Server to which to connect.
+The server can be any SMB/CIFS server. The name is
+resolved using the \fIname resolve order\fRline from
+\fIsmb.conf(5)\fR.
+.TP
+\fB-A filename\fR
+This option allows
+you to specify a file from which to read the username and
+password used in the connection. The format of the file is
+
+.sp
+.nf
+ username = <value>
+ password = <value>
+ domain = <value>
+
+.sp
+.fi
+
+Make certain that the permissions on the file restrict
+access from unwanted users.
+.TP
+\fB-c 'command string'\fR
+execute semicolon separated commands (listed
+below))
+.TP
+\fB-d debuglevel\fR
+set the debuglevel. Debug level 0 is the lowest
+and 100 being the highest. This should be set to 100 if you are
+planning on submitting a bug report to the Samba team (see \fIBUGS.txt\fR).
+.TP
+\fB-h\fR
+Print a summary of command line options.
+.TP
+\fB-l logbasename\fR
+File name for log/debug files. The extension
+\&'.client' will be appended. The log file is never removed
+by the client.
+.TP
+\fB-N\fR
+instruct \fBrpcclient\fR not to ask
+for a password. By default, \fBrpcclient\fR will prompt
+for a password. See also the \fI-U\fR option.
+.TP
+\fB-s smb.conf\fR
+Specifies the location of the all important
+\fIsmb.conf\fR file.
+.TP
+\fB-U username[%password]\fR
+Sets the SMB username or username and password.
+
+If %password is not specified, the user will be prompted. The
+client will first check the \fBUSER\fR environment variable, then the
+\fBLOGNAME\fR variable and if either exists, the
+string is uppercased. If these environmental variables are not
+found, the username GUEST is used.
+
+A third option is to use a credentials file which
+contains the plaintext of the username and password. This
+option is mainly provided for scripts where the admin doesn't
+desire to pass the credentials on the command line or via environment
+variables. If this method is used, make certain that the permissions
+on the file restrict access from unwanted users. See the
+\fI-A\fR for more details.
+
+Be cautious about including passwords in scripts. Also, on
+many systems the command line of a running process may be seen
+via the \fBps\fR command. To be safe always allow
+\fBrpcclient\fR to prompt for a password and type
+it in directly.
+.TP
+\fB-W domain\fR
+Set the SMB domain of the username. This
+overrides the default domain which is the domain defined in
+smb.conf. If the domain specified is the same as the server's NetBIOS name,
+it causes the client to log on using the server's local SAM (as
+opposed to the Domain SAM).
+.SH "COMMANDS"
+.PP
+\fBLSARPC\fR
+.TP 0.2i
+\(bu
+\fBlsaquery\fR
+.TP 0.2i
+\(bu
+\fBlookupsids\fR - Resolve a list
+of SIDs to usernames.
+.TP 0.2i
+\(bu
+\fBlookupnames\fR - Resolve s list
+of usernames to SIDs.
+.TP 0.2i
+\(bu
+\fBenumtrusts\fR
+.PP
+.PP
+.PP
+\fBSAMR\fR
+.PP
+.TP 0.2i
+\(bu
+\fBqueryuser\fR
+.TP 0.2i
+\(bu
+\fBquerygroup\fR
+.TP 0.2i
+\(bu
+\fBqueryusergroups\fR
+.TP 0.2i
+\(bu
+\fBquerygroupmem\fR
+.TP 0.2i
+\(bu
+\fBqueryaliasmem\fR
+.TP 0.2i
+\(bu
+\fBquerydispinfo\fR
+.TP 0.2i
+\(bu
+\fBquerydominfo\fR
+.TP 0.2i
+\(bu
+\fBenumdomgroups\fR
+.PP
+.PP
+.PP
+\fBSPOOLSS\fR
+.PP
+.TP 0.2i
+\(bu
+\fBadddriver <arch> <config>\fR
+- Execute an AddPrinterDriver() RPC to install the printer driver
+information on the server. Note that the driver files should
+already exist in the directory returned by
+\fBgetdriverdir\fR. Possible values for
+\fIarch\fR are the same as those for
+the \fBgetdriverdir\fR command.
+The \fIconfig\fR parameter is defined as
+follows:
+
+.sp
+.nf
+ Long Printer Name:\\
+ Driver File Name:\\
+ Data File Name:\\
+ Config File Name:\\
+ Help File Name:\\
+ Language Monitor Name:\\
+ Default Data Type:\\
+ Comma Separated list of Files
+
+.sp
+.fi
+
+Any empty fields should be enter as the string "NULL".
+
+Samba does not need to support the concept of Print Monitors
+since these only apply to local printers whose driver can make
+use of a bi-directional link for communication. This field should
+be "NULL". On a remote NT print server, the Print Monitor for a
+driver must already be installed prior to adding the driver or
+else the RPC will fail.
+.TP 0.2i
+\(bu
+\fBaddprinter <printername>
+<sharename> <drivername> <port>\fR
+- Add a printer on the remote server. This printer
+will be automatically shared. Be aware that the printer driver
+must already be installed on the server (see \fBadddriver\fR)
+and the \fIport\fRmust be a valid port name (see
+\fBenumports\fR.
+.TP 0.2i
+\(bu
+\fBdeldriver\fR - Delete the
+specified printer driver for all architectures. This
+does not delete the actual driver files from the server,
+only the entry from the server's list of drivers.
+.TP 0.2i
+\(bu
+\fBenumdata\fR - Enumerate all
+printer setting data stored on the server. On Windows NT clients,
+these values are stored in the registry, while Samba servers
+store them in the printers TDB. This command corresponds
+to the MS Platform SDK GetPrinterData() function (* This
+command is currently unimplemented).
+.TP 0.2i
+\(bu
+\fBenumjobs <printer>\fR
+- List the jobs and status of a given printer.
+This command corresponds to the MS Platform SDK EnumJobs()
+function (* This command is currently unimplemented).
+.TP 0.2i
+\(bu
+\fBenumports [level]\fR
+- Executes an EnumPorts() call using the specified
+info level. Currently only info levels 1 and 2 are supported.
+.TP 0.2i
+\(bu
+\fBenumdrivers [level]\fR
+- Execute an EnumPrinterDrivers() call. This lists the various installed
+printer drivers for all architectures. Refer to the MS Platform SDK
+documentation for more details of the various flags and calling
+options. Currently supported info levels are 1, 2, and 3.
+.TP 0.2i
+\(bu
+\fBenumprinters [level]\fR
+- Execute an EnumPrinters() call. This lists the various installed
+and share printers. Refer to the MS Platform SDK documentation for
+more details of the various flags and calling options. Currently
+supported info levels are 0, 1, and 2.
+.TP 0.2i
+\(bu
+\fBgetdata <printername>\fR
+- Retrieve the data for a given printer setting. See
+the \fBenumdata\fR command for more information.
+This command corresponds to the GetPrinterData() MS Platform
+SDK function (* This command is currently unimplemented).
+.TP 0.2i
+\(bu
+\fBgetdriver <printername>\fR
+- Retrieve the printer driver information (such as driver file,
+config file, dependent files, etc...) for
+the given printer. This command corresponds to the GetPrinterDriver()
+MS Platform SDK function. Currently info level 1, 2, and 3 are supported.
+.TP 0.2i
+\(bu
+\fBgetdriverdir <arch>\fR
+- Execute a GetPrinterDriverDirectory()
+RPC to retreive the SMB share name and subdirectory for
+storing printer driver files for a given architecture. Possible
+values for \fIarch\fR are "Windows 4.0"
+(for Windows 95/98), "Windows NT x86", "Windows NT PowerPC", "Windows
+Alpha_AXP", and "Windows NT R4000".
+.TP 0.2i
+\(bu
+\fBgetprinter <printername>\fR
+- Retrieve the current printer information. This command
+corresponds to the GetPrinter() MS Platform SDK function.
+.TP 0.2i
+\(bu
+\fBopenprinter <printername>\fR
+- Execute an OpenPrinterEx() and ClosePrinter() RPC
+against a given printer.
+.TP 0.2i
+\(bu
+\fBsetdriver <printername> <drivername>\fR
+- Execute a SetPrinter() command to update the printer driver associated
+with an installed printer. The printer driver must already be correctly
+installed on the print server.
+
+See also the \fBenumprinters\fR and
+\fBenumdrivers\fR commands for obtaining a list of
+of installed printers and drivers.
+.PP
+\fBGENERAL OPTIONS\fR
+.PP
+.TP 0.2i
+\(bu
+\fBdebuglevel\fR - Set the current debug level
+used to log information.
+.TP 0.2i
+\(bu
+\fBhelp (?)\fR - Print a listing of all
+known commands or extended help on a particular command.
+.TP 0.2i
+\(bu
+\fBquit (exit)\fR - Exit \fBrpcclient
+\fR\&.
+.SH "BUGS"
+.PP
+\fBrpcclient\fR is designed as a developer testing tool
+and may not be robust in certain areas (such as command line parsing).
+It has been known to generate a core dump upon failures when invalid
+parameters where passed to the interpreter.
+.PP
+From Luke Leighton's original rpcclient man page:
+.PP
+\fB"WARNING!\fR The MSRPC over SMB code has
+been developed from examining Network traces. No documentation is
+available from the original creators (Microsoft) on how MSRPC over
+SMB works, or how the individual MSRPC services work. Microsoft's
+implementation of these services has been demonstrated (and reported)
+to be... a bit flaky in places.
+.PP
+The development of Samba's implementation is also a bit rough,
+and as more of the services are understood, it can even result in
+versions of \fBsmbd(8)\fR and \fBrpcclient(1)\fR
+that are incompatible for some commands or services. Additionally,
+the developers are sending reports to Microsoft, and problems found
+or reported to Microsoft are fixed in Service Packs, which may
+result in incompatibilities."
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of the Samba
+suite.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original rpcclient man page was written by Matthew
+Geddes, Luke Kenneth Casson Leighton, and rewritten by Gerald Carter.
+The conversion to DocBook for Samba 2.2 was done by Gerald
+Carter.
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 0c81f736b6e..ff16ff7c915 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -1,190 +1,141 @@
-.TH SAMBA 7 29/3/95 Samba Samba
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SAMBA" "7" "06 December 2001" "" ""
.SH NAME
-Samba \- a LanManager like fileserver for Unix
+SAMBA \- A Windows SMB/CIFS fileserver for UNIX
.SH SYNOPSIS
-.B Samba
-.SH DESCRIPTION
-The
-.B Samba
-software suite is a collection of programs that implements the SMB
-protocol for unix systems. This protocol is sometimes also referred to
-as the LanManager or Netbios protocol.
-
-.SH COMPONENTS
-
-The Samba suite is made up of several components. Each component is
-described in a separate manual page. It is strongly recommended that
-you read the documentation that comes with Samba and the manual pages
-of those components that you use. If the manual pages aren't clear
-enough then please send me a patch!
-
-The smbd(8) daemon provides the file and print services to SMB clents,
-such as Windows for Workgroups, Windows NT or LanManager. The
-configuration file for this daemon is described in smb.conf(5).
-
-The nmbd(8) daemon provides Netbios nameserving and browsing
-support. It can also be run interactively to query other name service
-daemons.
-
-The smbclient(1) program implements a simple ftp-like client. This is
-useful for accessing SMB shares on other compatible servers (such as
-WfWg), and can also be used to allow a unix box to print to a printer
-attached to any SMB server (such as a PC running WfWg).
-
-The testparm(1) utility allows you to test your smb.conf(5)
-configuration file.
-
-The smbstatus(1) utility allows you to tell who is currently using the
-smbd(8) server.
-
-.SH AVAILABILITY
-
-The Samba software suite is licensed under the Gnu Public License. A
-copy of that license should have come with the package. You are
-encouraged to distribute copies of the Samba suite, but please keep it
-intact.
-
-The latest version of the Samba suite can be obtained via anonymous
-ftp from nimbus.anu.edu.au in the directory pub/tridge/samba/. It is
-also available on several mirror sites worldwide.
-
-You may also find useful information about Samba on the newsgroup
-comp.protocols.smb and the Samba mailing list. Details on how to join
-the mailing list are given in the README file that comes with Samba.
-
-If you have access to a WWW viewer (such as Netscape or Mosaic) then
-you will also find lots of useful information, including back issues
-of the Samba mailing list, at http://lake.canberra.edu.au/pub/samba/
-
-.SH AUTHOR
-
-The main author of the Samba suite is Andrew Tridgell. He may be
-contacted via e-mail at samba-bugs@anu.edu.au.
-
-There have also been an enourmous number of contributors to Samba from
-all over the world. A partial list of these contributors is included
-in the CREDITS section below. The list is, however, badly out of
-date. More up to date info may be obtained from the change-log that
-comes with the Samba source code.
-
-.SH CONTRIBUTIONS
-
-If you wish to contribute to the Samba project, then I suggest you
-join the Samba mailing list.
-
-If you have patches to submit or bugs to report then you may mail them
-directly to samba-bugs@anu.edu.au. Note, however, that due to the
-enourmous popularity of this package I may take some time to repond to
-mail. I prefer patches in "diff -u" format.
-
-.SH CREDITS
-
-Contributors to the project are (in alphabetical order by email address):
-
-(NOTE: This list is very out of date)
-
- Adams, Graham
- (gadams@ddrive.demon.co.uk)
- Allison, Jeremy
- (jeremy@netcom.com)
- Andrus, Ross
- (ross@augie.insci.com)
- Auer, Karl
- (Karl.Auer@anu.edu.au)
- Bogstad, Bill
- (bogstad@cs.jhu.edu)
- Boreham, Bryan
- (Bryan@alex.com)
- Boreham, David
- (davidb@ndl.co.uk)
- Butler, Michael
- (imb@asstdc.scgt.oz.au)
- ???
- (charlie@edina.demon.co.uk)
- Chua, Michael
- (lpc@solomon.technet.sg)
- Cochran, Marc
- (mcochran@wellfleet.com)
- Dey, Martin N
- (mnd@netmgrs.co.uk)
- Errath, Maximilian
- (errath@balu.kfunigraz.ac.at)
- Fisher, Lee
- (leefi@microsoft.com)
- Foderaro, Sean
- (jkf@frisky.Franz.COM)
- Greer, Brad
- (brad@cac.washington.edu)
- Griffith, Michael A
- (grif@cs.ucr.edu)
- Grosen, Mark
- (MDGrosen@spectron.COM)
- ????
- (gunjkoa@dep.sa.gov.au)
- Haapanen, Tom
- (tomh@metrics.com)
- Hench, Mike
- (hench@cae.uwm.edu)
- Horstman, Mark A
- (mh2620@sarek.sbc.com)
- Hudson, Tim
- (tim.hudson@gslmail.mincom.oz.au)
- Hulthen, Erik Magnus
- (magnus@axiom.se)
- ???
- (imb@asstdc.scgt.oz.au)
- Iversen, Per Steinar
- (iversen@dsfys1.fi.uib.no)
- Kaara, Pasi
- (ppk@atk.tpo.fi)
- Karman, Merik
- (merik@blackadder.dsh.oz.au)
- Kiff, Martin
- (mgk@newton.npl.co.uk)
- Kiick, Chris
- (cjkiick@flinx.b11.ingr.com)
- Kukulies, Christoph
- (kuku@acds.physik.rwth-aachen.de)
- ???
- (lance@fox.com)
- Lendecke, Volker
- (lendecke@namu01.gwdg.de)
- ???
- (lonnie@itg.ti.com)
- Mahoney, Paul Thomas
- (ptm@xact1.xact.com)
- Mauelshagen, Heinz
- (mauelsha@ez.da.telekom.de)
- Merrick, Barry G
- (bgm@atml.co.uk)
- Mol, Marcel
- (marcel@fanout.et.tudeflt.nl)
- ???
- (njw@cpsg.com.au)
- ???
- (noses@oink.rhein.de)
- Owens, John
- (john@micros.com)
- Pierson, Jacques
- (pierson@ketje.enet.dec.com)
- Powell, Mark
- (mark@scot1.ucsalf.ac.uk)
- Reiz, Steven
- (sreiz@aie.nl)
- Schlaeger, Joerg
- (joergs@toppoint.de)
- S{rkel{, Vesa
- (vesku@rankki.kcl.fi)
- Tridgell, Andrew
- (samba-bugs@anu.edu.au)
- Troyer, Dean
- (troyer@saifr00.ateng.az.honeywell.com)
- Wakelin, Ross
- (rossw@march.co.uk)
- Wessels, Stefan
- (SWESSELS@dos-lan.cs.up.ac.za)
- Young, Ian A
- (iay@threel.co.uk)
- van der Zwan, Paul
- (paulzn@olivetti.nl)
-
+.sp
+\fBSamba\fR
+.SH "DESCRIPTION"
+.PP
+The Samba software suite is a collection of programs
+that implements the Server Message Block (commonly abbreviated
+as SMB) protocol for UNIX systems. This protocol is sometimes
+also referred to as the Common Internet File System (CIFS),
+LanManager or NetBIOS protocol.
+.TP
+\fBsmbd\fR
+The \fBsmbd \fR
+daemon provides the file and print services to
+SMB clients, such as Windows 95/98, Windows NT, Windows
+for Workgroups or LanManager. The configuration file
+for this daemon is described in \fIsmb.conf\fR
+.TP
+\fBnmbd\fR
+The \fBnmbd\fR
+daemon provides NetBIOS nameserving and browsing
+support. The configuration file for this daemon
+is described in \fIsmb.conf\fR
+.TP
+\fBsmbclient\fR
+The \fBsmbclient\fR
+program implements a simple ftp-like client. This
+is useful for accessing SMB shares on other compatible
+servers (such as Windows NT), and can also be used
+to allow a UNIX box to print to a printer attached to
+any SMB server (such as a PC running Windows NT).
+.TP
+\fBtestparm\fR
+The \fBtestparm\fR
+utility is a simple syntax checker for Samba's
+\fIsmb.conf\fRconfiguration file.
+.TP
+\fBtestprns\fR
+The \fBtestprns\fR
+utility supports testing printer names defined
+in your \fIprintcap>\fR file used
+by Samba.
+.TP
+\fBsmbstatus\fR
+The \fBsmbstatus\fR
+tool provides access to information about the
+current connections to \fBsmbd\fR.
+.TP
+\fBnmblookup\fR
+The \fBnmblookup\fR
+tools allows NetBIOS name queries to be made
+from a UNIX host.
+.TP
+\fBmake_smbcodepage\fR
+The \fBmake_smbcodepage\fR
+utility provides a means of creating SMB code page
+definition files for your \fBsmbd\fR server.
+.TP
+\fBsmbpasswd\fR
+The \fBsmbpasswd\fR
+command is a tool for changing LanMan and Windows NT
+password hashes on Samba and Windows NT servers.
+.SH "COMPONENTS"
+.PP
+The Samba suite is made up of several components. Each
+component is described in a separate manual page. It is strongly
+recommended that you read the documentation that comes with Samba
+and the manual pages of those components that you use. If the
+manual pages aren't clear enough then please send a patch or
+bug report to samba@samba.org <URL:mailto:samba@samba.org>
+.SH "AVAILABILITY"
+.PP
+The Samba software suite is licensed under the
+GNU Public License(GPL). A copy of that license should
+have come with the package in the file COPYING. You are
+encouraged to distribute copies of the Samba suite, but
+please obey the terms of this license.
+.PP
+The latest version of the Samba suite can be
+obtained via anonymous ftp from samba.org in the
+directory pub/samba/. It is also available on several
+mirror sites worldwide.
+.PP
+You may also find useful information about Samba
+on the newsgroup comp.protocol.smb <URL:news:comp.protocols.smb> and the Samba mailing
+list. Details on how to join the mailing list are given in
+the README file that comes with Samba.
+.PP
+If you have access to a WWW viewer (such as Netscape
+or Mosaic) then you will also find lots of useful information,
+including back issues of the Samba mailing list, at
+http://lists.samba.org <URL:http://lists.samba.org/>.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of the
+Samba suite.
+.SH "CONTRIBUTIONS"
+.PP
+If you wish to contribute to the Samba project,
+then I suggest you join the Samba mailing list at
+http://lists.samba.org <URL:http://lists.samba.org/>.
+.PP
+If you have patches to submit or bugs to report
+then you may mail them directly to samba-patches@samba.org.
+Note, however, that due to the enormous popularity of this
+package the Samba Team may take some time to respond to mail. We
+prefer patches in \fBdiff -u\fR format.
+.SH "CONTRIBUTORS"
+.PP
+Contributors to the project are now too numerous
+to mention here but all deserve the thanks of all Samba
+users. To see a full list, look at ftp://samba.org/pub/samba/alpha/change-log <URL:ftp://samba.org/pub/samba/alpha/change-log>
+for the pre-CVS changes and at ftp://samba.org/pub/samba/alpha/cvs.log <URL:ftp://samba.org/pub/samba/alpha/cvs.log>
+for the contributors to Samba post-CVS. CVS is the Open Source
+source code control system used by the Samba Team to develop
+Samba. The project would have been unmanageable without it.
+.PP
+In addition, several commercial organizations now help
+fund the Samba Team with money and equipment. For details see
+the Samba Web pages at http://samba.org/samba/samba-thanks.html.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 933d71ff0c3..9d88615f3f8 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -1,2719 +1,7372 @@
-.TH SMB.CONF 5 11/10/94 smb.conf smb.conf
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMB.CONF" "5" "06 December 2001" "" ""
.SH NAME
-smb.conf \- configuration file for smbd
-.SH SYNOPSIS
-.B smb.conf
-.SH DESCRIPTION
-The
-.B smb.conf
-file is a configuration file for the Samba suite.
-
-.B smb.conf
-contains runtime configuration information for the
-.B smbd
-program. The
-.B smbd
-program provides LanManager-like services to clients
-using the SMB protocol.
-
-.SH FILE FORMAT
-The file consists of sections and parameters. A section begins with the
-name of the section in square brackets and continues until the next
-section begins. Sections contain parameters of the form 'name = value'.
-
-The file is line-based - that is, each newline-terminated line represents
-either a comment, a section name or a parameter.
-
+smb.conf \- The configuration file for the Samba suite
+.SH "SYNOPSIS"
+.PP
+The \fIsmb.conf\fR file is a configuration
+file for the Samba suite. \fIsmb.conf\fR contains
+runtime configuration information for the Samba programs. The
+\fIsmb.conf\fR file is designed to be configured and
+administered by the \fBswat(8)\fR
+program. The complete description of the file format and
+possible parameters held within are here for reference purposes.
+.SH "FILE FORMAT"
+.PP
+The file consists of sections and parameters. A section
+begins with the name of the section in square brackets and continues
+until the next section begins. Sections contain parameters of the
+form
+.PP
+\fIname\fR = \fIvalue
+\fR.PP
+The file is line-based - that is, each newline-terminated
+line represents either a comment, a section name or a parameter.
+.PP
Section and parameter names are not case sensitive.
-
-Only the first equals sign in a parameter is significant. Whitespace before
-or after the first equals sign is discarded. Leading, trailing and internal
-whitespace in section and parameter names is irrelevant. Leading and
-trailing whitespace in a parameter value is discarded. Internal whitespace
-within a parameter value is retained verbatim.
-
-Any line beginning with a semicolon is ignored, as are lines containing
-only whitespace.
-
-Any line ending in a \\ is "continued" on the next line in the
-customary unix fashion.
-
-The values following the equals sign in parameters are all either a string
-(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
-true/false. Case is not significant in boolean values, but is preserved
-in string values. Some items such as create modes are numeric.
-.SH SERVICE DESCRIPTIONS
-Each section in the configuration file describes a service. The section name
-is the service name and the parameters within the section define the service's
-attributes.
-
-There are three special sections, [global], [homes] and [printers], which are
-described under 'special sections'. The following notes apply to ordinary
-service descriptions.
-
-A service consists of a directory to which access is being given plus a
-description of the access rights which are granted to the user of the
-service. Some housekeeping options are also specifiable.
-
-Services are either filespace services (used by the client as an extension of
-their native file systems) or printable services (used by the client to access
-print services on the host running the server).
-
-Services may be guest services, in which case no password is required to
-access them. A specified guest account is used to define access privileges
-in this case.
-
-Services other than guest services will require a password to access
-them. The client provides the username. As many clients only provide
-passwords and not usernames, you may specify a list of usernames to
-check against the password using the "user=" option in the service
-definition.
-
-Note that the access rights granted by the server are masked by the access
-rights granted to the specified or guest user by the host system. The
-server does not grant more access than the host system grants.
-
-The following sample section defines a file space service. The user has write
-access to the path /home/bar. The service is accessed via the service name
-"foo":
-
- [foo]
+.PP
+Only the first equals sign in a parameter is significant.
+Whitespace before or after the first equals sign is discarded.
+Leading, trailing and internal whitespace in section and parameter
+names is irrelevant. Leading and trailing whitespace in a parameter
+value is discarded. Internal whitespace within a parameter value
+is retained verbatim.
+.PP
+Any line beginning with a semicolon (';') or a hash ('#')
+character is ignored, as are lines containing only whitespace.
+.PP
+Any line ending in a '\\' is continued
+on the next line in the customary UNIX fashion.
+.PP
+The values following the equals sign in parameters are all
+either a string (no quotes needed) or a boolean, which may be given
+as yes/no, 0/1 or true/false. Case is not significant in boolean
+values, but is preserved in string values. Some items such as
+create modes are numeric.
+.SH "SECTION DESCRIPTIONS"
+.PP
+Each section in the configuration file (except for the
+[global] section) describes a shared resource (known
+as a "share"). The section name is the name of the
+shared resource and the parameters within the section define
+the shares attributes.
+.PP
+There are three special sections, [global],
+[homes] and [printers], which are
+described under \fBspecial sections\fR. The
+following notes apply to ordinary section descriptions.
+.PP
+A share consists of a directory to which access is being
+given plus a description of the access rights which are granted
+to the user of the service. Some housekeeping options are
+also specifiable.
+.PP
+Sections are either file share services (used by the
+client as an extension of their native file systems) or
+printable services (used by the client to access print services
+on the host running the server).
+.PP
+Sections may be designated \fBguest\fR services,
+in which case no password is required to access them. A specified
+UNIX \fBguest account\fR is used to define access
+privileges in this case.
+.PP
+Sections other than guest services will require a password
+to access them. The client provides the username. As older clients
+only provide passwords and not usernames, you may specify a list
+of usernames to check against the password using the "user ="
+option in the share definition. For modern clients such as
+Windows 95/98/ME/NT/2000, this should not be necessary.
+.PP
+Note that the access rights granted by the server are
+masked by the access rights granted to the specified or guest
+UNIX user by the host system. The server does not grant more
+access than the host system grants.
+.PP
+The following sample section defines a file space share.
+The user has write access to the path \fI/home/bar\fR.
+The share is accessed via the share name "foo":
+.sp
+.nf
+ [foo]
path = /home/bar
- writable = true
-
-The following sample section defines a printable service. The service is
-readonly, but printable. That is, the only write access permitted is via
-calls to open, write to and close a spool file. The 'guest ok' parameter
-means access will be permitted as the default guest user (specified elsewhere):
-
- [aprinter]
+ writeable = true
+
+
+.sp
+.fi
+.PP
+The following sample section defines a printable share.
+The share is readonly, but printable. That is, the only write
+access permitted is via calls to open, write to and close a
+spool file. The \fBguest ok\fR parameter means
+access will be permitted as the default guest user (specified
+elsewhere):
+.sp
+.nf
+ [aprinter]
path = /usr/spool/public
- read only = true
+ writeable = false
printable = true
- public = true
-
-.SH SPECIAL SECTIONS
-
-.SS The [global] section
-.RS 3
-Parameters in this section apply to the server as a whole, or are defaults
-for services which do not specifically define certain items. See the notes
-under 'Parameters' for more information.
+ guest ok = true
+
+
+.sp
+.fi
+.SH "SPECIAL SECTIONS"
+.SS "THE GLOBAL SECTION"
+.PP
+parameters in this section apply to the server
+as a whole, or are defaults for sections which do not
+specifically define certain items. See the notes
+under PARAMETERS for more information.
+.SS "THE HOMES SECTION"
+.PP
+If a section called homes is included in the
+configuration file, services connecting clients to their
+home directories can be created on the fly by the server.
+.PP
+When the connection request is made, the existing
+sections are scanned. If a match is found, it is used. If no
+match is found, the requested section name is treated as a
+user name and looked up in the local password file. If the
+name exists and the correct password has been given, a share is
+created by cloning the [homes] section.
+.PP
+Some modifications are then made to the newly
+created share:
+.TP 0.2i
+\(bu
+The share name is changed from homes to
+the located username.
+.TP 0.2i
+\(bu
+If no path was given, the path is set to
+the user's home directory.
+.PP
+If you decide to use a \fBpath =\fR line
+in your [homes] section then you may find it useful
+to use the %S macro. For example :
+.PP
+.PP
+\fBpath = /data/pchome/%S\fR
+.PP
+.PP
+would be useful if you have different home directories
+for your PCs than for UNIX access.
+.PP
+.PP
+This is a fast and simple way to give a large number
+of clients access to their home directories with a minimum
+of fuss.
+.PP
+.PP
+A similar process occurs if the requested section
+name is "homes", except that the share name is not
+changed to that of the requesting user. This method of using
+the [homes] section works well if different users share
+a client PC.
+.PP
+.PP
+The [homes] section can specify all the parameters
+a normal service section can specify, though some make more sense
+than others. The following is a typical and suitable [homes]
+section:
+.PP
+.sp
+.nf
+ [homes]
+ writeable = yes
+
+
+.sp
+.fi
+.PP
+An important point is that if guest access is specified
+in the [homes] section, all home directories will be
+visible to all clients \fBwithout a password\fR.
+In the very unlikely event that this is actually desirable, it
+would be wise to also specify \fBread only
+access\fR.
+.PP
+.PP
+Note that the \fBbrowseable\fR flag for
+auto home directories will be inherited from the global browseable
+flag, not the [homes] browseable flag. This is useful as
+it means setting \fBbrowseable = no\fR in
+the [homes] section will hide the [homes] share but make
+any auto home directories visible.
+.PP
+.SS "THE PRINTERS SECTION"
+.PP
+This section works like [homes],
+but for printers.
+.PP
+If a [printers] section occurs in the
+configuration file, users are able to connect to any printer
+specified in the local host's printcap file.
+.PP
+When a connection request is made, the existing sections
+are scanned. If a match is found, it is used. If no match is found,
+but a [homes] section exists, it is used as described
+above. Otherwise, the requested section name is treated as a
+printer name and the appropriate printcap file is scanned to see
+if the requested section name is a valid printer share name. If
+a match is found, a new printer share is created by cloning
+the [printers] section.
+.PP
+A few modifications are then made to the newly created
+share:
+.TP 0.2i
+\(bu
+The share name is set to the located printer
+name
+.TP 0.2i
+\(bu
+If no printer name was given, the printer name
+is set to the located printer name
+.TP 0.2i
+\(bu
+If the share does not permit guest access and
+no username was given, the username is set to the located
+printer name.
+.PP
+Note that the [printers] service MUST be
+printable - if you specify otherwise, the server will refuse
+to load the configuration file.
+.PP
+.PP
+Typically the path specified would be that of a
+world-writeable spool directory with the sticky bit set on
+it. A typical [printers] entry would look like
+this:
+.PP
+.sp
+.nf
+ [printers]
+ path = /usr/spool/public
+ guest ok = yes
+ printable = yes
+
+.sp
+.fi
+.PP
+All aliases given for a printer in the printcap file
+are legitimate printer names as far as the server is concerned.
+If your printing subsystem doesn't work like that, you will have
+to set up a pseudo-printcap. This is a file consisting of one or
+more lines like this:
+.PP
+.sp
+.nf
+ alias|alias|alias|alias...
+
+
+.sp
+.fi
+.PP
+Each alias should be an acceptable printer name for
+your printing subsystem. In the [global] section, specify
+the new file as your printcap. The server will then only recognize
+names found in your pseudo-printcap, which of course can contain
+whatever aliases you like. The same technique could be used
+simply to limit access to a subset of your local printers.
+.PP
+.PP
+An alias, by the way, is defined as any component of the
+first entry of a printcap record. Records are separated by newlines,
+components (if there are more than one) are separated by vertical
+bar symbols ('|').
+.PP
+.PP
+NOTE: On SYSV systems which use lpstat to determine what
+printers are defined on the system you may be able to use
+"printcap name = lpstat" to automatically obtain a list
+of printers. See the "printcap name" option
+for more details.
+.PP
+.SH "PARAMETERS"
+.PP
+parameters define the specific attributes of sections.
+.PP
+Some parameters are specific to the [global] section
+(e.g., \fBsecurity\fR). Some parameters are usable
+in all sections (e.g., \fBcreate mode\fR). All others
+are permissible only in normal sections. For the purposes of the
+following descriptions the [homes] and [printers]
+sections will be considered normal. The letter \fBG\fR
+in parentheses indicates that a parameter is specific to the
+[global] section. The letter \fBS\fR
+indicates that a parameter can be specified in a service specific
+section. Note that all \fBS\fR parameters can also be specified in
+the [global] section - in which case they will define
+the default behavior for all services.
+.PP
+parameters are arranged here in alphabetical order - this may
+not create best bedfellows, but at least you can find them! Where
+there are synonyms, the preferred synonym is described, others refer
+to the preferred synonym.
+.SH "VARIABLE SUBSTITUTIONS"
+.PP
+Many of the strings that are settable in the config file
+can take substitutions. For example the option "path =
+/tmp/%u" would be interpreted as "path =
+/tmp/john" if the user connected with the username john.
+.PP
+These substitutions are mostly noted in the descriptions below,
+but there are some general substitutions which apply whenever they
+might be relevant. These are:
+.TP
+\fB%S\fR
+the name of the current service, if any.
+.TP
+\fB%P\fR
+the root directory of the current service,
+if any.
+.TP
+\fB%u\fR
+user name of the current service, if any.
+.TP
+\fB%g\fR
+primary group name of %u.
+.TP
+\fB%U\fR
+session user name (the user name that the client
+wanted, not necessarily the same as the one they got).
+.TP
+\fB%G\fR
+primary group name of %U.
+.TP
+\fB%H\fR
+the home directory of the user given
+by %u.
+.TP
+\fB%v\fR
+the Samba version.
+.TP
+\fB%h\fR
+the Internet hostname that Samba is running
+on.
+.TP
+\fB%m\fR
+the NetBIOS name of the client machine
+(very useful).
+.TP
+\fB%L\fR
+the NetBIOS name of the server. This allows you
+to change your config based on what the client calls you. Your
+server can have a "dual personality".
+.TP
+\fB%M\fR
+the Internet name of the client machine.
+.TP
+\fB%N\fR
+the name of your NIS home directory server.
+This is obtained from your NIS auto.map entry. If you have
+not compiled Samba with the \fB--with-automount\fR
+option then this value will be the same as %L.
+.TP
+\fB%p\fR
+the path of the service's home directory,
+obtained from your NIS auto.map entry. The NIS auto.map entry
+is split up as "%N:%p".
+.TP
+\fB%R\fR
+the selected protocol level after
+protocol negotiation. It can be one of CORE, COREPLUS,
+LANMAN1, LANMAN2 or NT1.
+.TP
+\fB%d\fR
+The process id of the current server
+process.
+.TP
+\fB%a\fR
+the architecture of the remote
+machine. Only some are recognized, and those may not be
+100% reliable. It currently recognizes Samba, WfWg, Win95,
+WinNT and Win2k. Anything else will be known as
+"UNKNOWN". If it gets it wrong then sending a level
+3 log to samba@samba.org
+ <URL:mailto:samba@samba.org> should allow it to be fixed.
+.TP
+\fB%I\fR
+The IP address of the client machine.
+.TP
+\fB%T\fR
+the current date and time.
+.TP
+\fB%$(\fIenvvar\fB)\fR
+The value of the environment variable
+\fIenvar\fR.
+.PP
+There are some quite creative things that can be done
+with these substitutions and other smb.conf options.
+.PP
+.SH "NAME MANGLING"
+.PP
+Samba supports "name mangling" so that DOS and
+Windows clients can use files that don't conform to the 8.3 format.
+It can also be set to adjust the case of 8.3 format filenames.
+.PP
+There are several options that control the way mangling is
+performed, and they are grouped here rather than listed separately.
+For the defaults look at the output of the testparm program.
+.PP
+All of these options can be set separately for each service
+(or globally, of course).
+.PP
+The options are:
+.TP
+\fBmangle case = yes/no\fR
+controls if names that have characters that
+aren't of the "default" case are mangled. For example,
+if this is yes then a name like "Mail" would be mangled.
+Default \fBno\fR.
+.TP
+\fBcase sensitive = yes/no\fR
+controls whether filenames are case sensitive. If
+they aren't then Samba must do a filename search and match on passed
+names. Default \fBno\fR.
+.TP
+\fBdefault case = upper/lower\fR
+controls what the default case is for new
+filenames. Default \fBlower\fR.
+.TP
+\fBpreserve case = yes/no\fR
+controls if new files are created with the
+case that the client passes, or if they are forced to be the
+"default" case. Default \fByes\fR.
+.TP
+\fBshort preserve case = yes/no\fR
+controls if new files which conform to 8.3 syntax,
+that is all in upper case and of suitable length, are created
+upper case, or if they are forced to be the "default"
+case. This option can be use with "preserve case = yes"
+to permit long filenames to retain their case, while short names
+are lowercased. Default \fByes\fR.
+.PP
+By default, Samba 2.2 has the same semantics as a Windows
+NT server, in that it is case insensitive but case preserving.
+.PP
+.SH "NOTE ABOUT USERNAME/PASSWORD VALIDATION"
+.PP
+There are a number of ways in which a user can connect
+to a service. The server uses the following steps in determining
+if it will allow a connection to a specified service. If all the
+steps fail, then the connection request is rejected. However, if one of the
+steps succeeds, then the following steps are not checked.
+.PP
+If the service is marked "guest only = yes" then
+steps 1 to 5 are skipped.
+.IP 1.
+If the client has passed a username/password
+pair and that username/password pair is validated by the UNIX
+system's password programs then the connection is made as that
+username. Note that this includes the
+\\\\server\\service%\fIusername\fR method of passing
+a username.
+.IP 2.
+If the client has previously registered a username
+with the system and now supplies a correct password for that
+username then the connection is allowed.
+.IP 3.
+The client's NetBIOS name and any previously
+used user names are checked against the supplied password, if
+they match then the connection is allowed as the corresponding
+user.
+.IP 4.
+If the client has previously validated a
+username/password pair with the server and the client has passed
+the validation token then that username is used.
+.IP 5.
+If a "user = " field is given in the
+\fIsmb.conf\fR file for the service and the client
+has supplied a password, and that password matches (according to
+the UNIX system's password checking) with one of the usernames
+from the "user =" field then the connection is made as
+the username in the "user =" line. If one
+of the username in the "user =" list begins with a
+\&'@' then that name expands to a list of names in
+the group of the same name.
+.IP 6.
+If the service is a guest service then a
+connection is made as the username given in the "guest
+account =" for the service, irrespective of the
+supplied password.
+.SH "COMPLETE LIST OF GLOBAL PARAMETERS"
+.PP
+Here is a list of all global parameters. See the section of
+each parameter for details. Note that some are synonyms.
+.TP 0.2i
+\(bu
+\fIabort shutdown script\fR
+.TP 0.2i
+\(bu
+\fIadd printer command\fR
+.TP 0.2i
+\(bu
+\fIadd share command\fR
+.TP 0.2i
+\(bu
+\fIadd user script\fR
+.TP 0.2i
+\(bu
+\fIadd machine script\fR
+.TP 0.2i
+\(bu
+\fIallow trusted domains\fR
+.TP 0.2i
+\(bu
+\fIannounce as\fR
+.TP 0.2i
+\(bu
+\fIannounce version\fR
+.TP 0.2i
+\(bu
+\fIauto services\fR
+.TP 0.2i
+\(bu
+\fIbind interfaces only\fR
+.TP 0.2i
+\(bu
+\fIbrowse list\fR
+.TP 0.2i
+\(bu
+\fIchange notify timeout\fR
+.TP 0.2i
+\(bu
+\fIchange share command\fR
+.TP 0.2i
+\(bu
+\fIcharacter set\fR
+.TP 0.2i
+\(bu
+\fIclient code page\fR
+.TP 0.2i
+\(bu
+\fIcode page directory\fR
+.TP 0.2i
+\(bu
+\fIcoding system\fR
+.TP 0.2i
+\(bu
+\fIconfig file\fR
+.TP 0.2i
+\(bu
+\fIdeadtime\fR
+.TP 0.2i
+\(bu
+\fIdebug hires timestamp\fR
+.TP 0.2i
+\(bu
+\fIdebug pid\fR
+.TP 0.2i
+\(bu
+\fIdebug timestamp\fR
+.TP 0.2i
+\(bu
+\fIdebug uid\fR
+.TP 0.2i
+\(bu
+\fIdebuglevel\fR
+.TP 0.2i
+\(bu
+\fIdefault\fR
+.TP 0.2i
+\(bu
+\fIdefault service\fR
+.TP 0.2i
+\(bu
+\fIdelete printer command\fR
+.TP 0.2i
+\(bu
+\fIdelete share command\fR
+.TP 0.2i
+\(bu
+\fIdelete user script\fR
+.TP 0.2i
+\(bu
+\fIdfree command\fR
+.TP 0.2i
+\(bu
+\fIdisable spoolss\fR
+.TP 0.2i
+\(bu
+\fIdns proxy\fR
+.TP 0.2i
+\(bu
+\fIdomain admin group\fR
+.TP 0.2i
+\(bu
+\fIdomain guest group\fR
+.TP 0.2i
+\(bu
+\fIdomain logons\fR
+.TP 0.2i
+\(bu
+\fIdomain master\fR
+.TP 0.2i
+\(bu
+\fIencrypt passwords\fR
+.TP 0.2i
+\(bu
+\fIenhanced browsing\fR
+.TP 0.2i
+\(bu
+\fIenumports command\fR
+.TP 0.2i
+\(bu
+\fIgetwd cache\fR
+.TP 0.2i
+\(bu
+\fIhide local users\fR
+.TP 0.2i
+\(bu
+\fIhide unreadable\fR
+.TP 0.2i
+\(bu
+\fIhomedir map\fR
+.TP 0.2i
+\(bu
+\fIhost msdfs\fR
+.TP 0.2i
+\(bu
+\fIhosts equiv\fR
+.TP 0.2i
+\(bu
+\fIinterfaces\fR
+.TP 0.2i
+\(bu
+\fIkeepalive\fR
+.TP 0.2i
+\(bu
+\fIkernel oplocks\fR
+.TP 0.2i
+\(bu
+\fIlanman auth\fR
+.TP 0.2i
+\(bu
+\fIlarge readwrite\fR
+.TP 0.2i
+\(bu
+\fIldap admin dn\fR
+.TP 0.2i
+\(bu
+\fIldap filter\fR
+.TP 0.2i
+\(bu
+\fIldap port\fR
+.TP 0.2i
+\(bu
+\fIldap server\fR
+.TP 0.2i
+\(bu
+\fIldap ssl\fR
+.TP 0.2i
+\(bu
+\fIldap suffix\fR
+.TP 0.2i
+\(bu
+\fIlm announce\fR
+.TP 0.2i
+\(bu
+\fIlm interval\fR
+.TP 0.2i
+\(bu
+\fIload printers\fR
+.TP 0.2i
+\(bu
+\fIlocal master\fR
+.TP 0.2i
+\(bu
+\fIlock dir\fR
+.TP 0.2i
+\(bu
+\fIlock directory\fR
+.TP 0.2i
+\(bu
+\fIlog file\fR
+.TP 0.2i
+\(bu
+\fIlog level\fR
+.TP 0.2i
+\(bu
+\fIlogon drive\fR
+.TP 0.2i
+\(bu
+\fIlogon home\fR
+.TP 0.2i
+\(bu
+\fIlogon path\fR
+.TP 0.2i
+\(bu
+\fIlogon script\fR
+.TP 0.2i
+\(bu
+\fIlpq cache time\fR
+.TP 0.2i
+\(bu
+\fImachine password timeout\fR
+.TP 0.2i
+\(bu
+\fImangled stack\fR
+.TP 0.2i
+\(bu
+\fImap to guest\fR
+.TP 0.2i
+\(bu
+\fImax disk size\fR
+.TP 0.2i
+\(bu
+\fImax log size\fR
+.TP 0.2i
+\(bu
+\fImax mux\fR
+.TP 0.2i
+\(bu
+\fImax open files\fR
+.TP 0.2i
+\(bu
+\fImax protocol\fR
+.TP 0.2i
+\(bu
+\fImax smbd processes\fR
+.TP 0.2i
+\(bu
+\fImax ttl\fR
+.TP 0.2i
+\(bu
+\fImax wins ttl\fR
+.TP 0.2i
+\(bu
+\fImax xmit\fR
+.TP 0.2i
+\(bu
+\fImessage command\fR
+.TP 0.2i
+\(bu
+\fImin passwd length\fR
+.TP 0.2i
+\(bu
+\fImin password length\fR
+.TP 0.2i
+\(bu
+\fImin protocol\fR
+.TP 0.2i
+\(bu
+\fImin wins ttl\fR
+.TP 0.2i
+\(bu
+\fIname resolve order\fR
+.TP 0.2i
+\(bu
+\fInetbios aliases\fR
+.TP 0.2i
+\(bu
+\fInetbios name\fR
+.TP 0.2i
+\(bu
+\fInetbios scope\fR
+.TP 0.2i
+\(bu
+\fInis homedir\fR
+.TP 0.2i
+\(bu
+\fInt pipe support\fR
+.TP 0.2i
+\(bu
+\fInt smb support\fR
+.TP 0.2i
+\(bu
+\fInull passwords\fR
+.TP 0.2i
+\(bu
+\fIobey pam restrictions\fR
+.TP 0.2i
+\(bu
+\fIoplock break wait time\fR
+.TP 0.2i
+\(bu
+\fIos level\fR
+.TP 0.2i
+\(bu
+\fIos2 driver map\fR
+.TP 0.2i
+\(bu
+\fIpam password change\fR
+.TP 0.2i
+\(bu
+\fIpanic action\fR
+.TP 0.2i
+\(bu
+\fIpasswd chat\fR
+.TP 0.2i
+\(bu
+\fIpasswd chat debug\fR
+.TP 0.2i
+\(bu
+\fIpasswd program\fR
+.TP 0.2i
+\(bu
+\fIpassword level\fR
+.TP 0.2i
+\(bu
+\fIpassword server\fR
+.TP 0.2i
+\(bu
+\fIprefered master\fR
+.TP 0.2i
+\(bu
+\fIpreferred master\fR
+.TP 0.2i
+\(bu
+\fIpreload\fR
+.TP 0.2i
+\(bu
+\fIprintcap\fR
+.TP 0.2i
+\(bu
+\fIprintcap name\fR
+.TP 0.2i
+\(bu
+\fIprinter driver file\fR
+.TP 0.2i
+\(bu
+\fIprotocol\fR
+.TP 0.2i
+\(bu
+\fIread bmpx\fR
+.TP 0.2i
+\(bu
+\fIread raw\fR
+.TP 0.2i
+\(bu
+\fIread size\fR
+.TP 0.2i
+\(bu
+\fIremote announce\fR
+.TP 0.2i
+\(bu
+\fIremote browse sync\fR
+.TP 0.2i
+\(bu
+\fIrestrict anonymous\fR
+.TP 0.2i
+\(bu
+\fIroot\fR
+.TP 0.2i
+\(bu
+\fIroot dir\fR
+.TP 0.2i
+\(bu
+\fIroot directory\fR
+.TP 0.2i
+\(bu
+\fIsecurity\fR
+.TP 0.2i
+\(bu
+\fIserver string\fR
+.TP 0.2i
+\(bu
+\fIshow add printer wizard\fR
+.TP 0.2i
+\(bu
+\fIshutdown script\fR
+.TP 0.2i
+\(bu
+\fIsmb passwd file\fR
+.TP 0.2i
+\(bu
+\fIsocket address\fR
+.TP 0.2i
+\(bu
+\fIsocket options\fR
+.TP 0.2i
+\(bu
+\fIsource environment\fR
+.TP 0.2i
+\(bu
+\fIssl\fR
+.TP 0.2i
+\(bu
+\fIssl CA certDir\fR
+.TP 0.2i
+\(bu
+\fIssl CA certFile\fR
+.TP 0.2i
+\(bu
+\fIssl ciphers\fR
+.TP 0.2i
+\(bu
+\fIssl client cert\fR
+.TP 0.2i
+\(bu
+\fIssl client key\fR
+.TP 0.2i
+\(bu
+\fIssl compatibility\fR
+.TP 0.2i
+\(bu
+\fIssl egd socket\fR
+.TP 0.2i
+\(bu
+\fIssl entropy bytes\fR
+.TP 0.2i
+\(bu
+\fIssl entropy file\fR
+.TP 0.2i
+\(bu
+\fIssl hosts\fR
+.TP 0.2i
+\(bu
+\fIssl hosts resign\fR
+.TP 0.2i
+\(bu
+\fIssl require clientcert\fR
+.TP 0.2i
+\(bu
+\fIssl require servercert\fR
+.TP 0.2i
+\(bu
+\fIssl server cert\fR
+.TP 0.2i
+\(bu
+\fIssl server key\fR
+.TP 0.2i
+\(bu
+\fIssl version\fR
+.TP 0.2i
+\(bu
+\fIstat cache\fR
+.TP 0.2i
+\(bu
+\fIstat cache size\fR
+.TP 0.2i
+\(bu
+\fIstrip dot\fR
+.TP 0.2i
+\(bu
+\fIsyslog\fR
+.TP 0.2i
+\(bu
+\fIsyslog only\fR
+.TP 0.2i
+\(bu
+\fItemplate homedir\fR
+.TP 0.2i
+\(bu
+\fItemplate shell\fR
+.TP 0.2i
+\(bu
+\fItime offset\fR
+.TP 0.2i
+\(bu
+\fItime server\fR
+.TP 0.2i
+\(bu
+\fItimestamp logs\fR
+.TP 0.2i
+\(bu
+\fItotal print jobs\fR
+.TP 0.2i
+\(bu
+\fIunix password sync\fR
+.TP 0.2i
+\(bu
+\fIupdate encrypted\fR
+.TP 0.2i
+\(bu
+\fIuse mmap\fR
+.TP 0.2i
+\(bu
+\fIuse rhosts\fR
+.TP 0.2i
+\(bu
+\fIusername level\fR
+.TP 0.2i
+\(bu
+\fIusername map\fR
+.TP 0.2i
+\(bu
+\fIutmp\fR
+.TP 0.2i
+\(bu
+\fIutmp directory\fR
+.TP 0.2i
+\(bu
+\fIvalid chars\fR
+.TP 0.2i
+\(bu
+\fIwinbind cache time\fR
+.TP 0.2i
+\(bu
+\fIwinbind enum users\fR
+.TP 0.2i
+\(bu
+\fIwinbind enum groups\fR
+.TP 0.2i
+\(bu
+\fIwinbind gid\fR
+.TP 0.2i
+\(bu
+\fIwinbind separator\fR
+.TP 0.2i
+\(bu
+\fIwinbind uid\fR
+.TP 0.2i
+\(bu
+\fIwins hook\fR
+.TP 0.2i
+\(bu
+\fIwins proxy\fR
+.TP 0.2i
+\(bu
+\fIwins server\fR
+.TP 0.2i
+\(bu
+\fIwins support\fR
+.TP 0.2i
+\(bu
+\fIworkgroup\fR
+.TP 0.2i
+\(bu
+\fIwrite raw\fR
+.SH "COMPLETE LIST OF SERVICE PARAMETERS"
+.PP
+Here is a list of all service parameters. See the section on
+each parameter for details. Note that some are synonyms.
+.TP 0.2i
+\(bu
+\fIadmin users\fR
+.TP 0.2i
+\(bu
+\fIallow hosts\fR
+.TP 0.2i
+\(bu
+\fIavailable\fR
+.TP 0.2i
+\(bu
+\fIblocking locks\fR
+.TP 0.2i
+\(bu
+\fIbrowsable\fR
+.TP 0.2i
+\(bu
+\fIbrowseable\fR
+.TP 0.2i
+\(bu
+\fIcase sensitive\fR
+.TP 0.2i
+\(bu
+\fIcasesignames\fR
+.TP 0.2i
+\(bu
+\fIcomment\fR
+.TP 0.2i
+\(bu
+\fIcopy\fR
+.TP 0.2i
+\(bu
+\fIcreate mask\fR
+.TP 0.2i
+\(bu
+\fIcreate mode\fR
+.TP 0.2i
+\(bu
+\fIdefault case\fR
+.TP 0.2i
+\(bu
+\fIdelete readonly\fR
+.TP 0.2i
+\(bu
+\fIdelete veto files\fR
+.TP 0.2i
+\(bu
+\fIdeny hosts\fR
+.TP 0.2i
+\(bu
+\fIdirectory\fR
+.TP 0.2i
+\(bu
+\fIdirectory mask\fR
+.TP 0.2i
+\(bu
+\fIdirectory mode\fR
+.TP 0.2i
+\(bu
+\fIdirectory security mask\fR
+.TP 0.2i
+\(bu
+\fIdont descend\fR
+.TP 0.2i
+\(bu
+\fIdos filemode\fR
+.TP 0.2i
+\(bu
+\fIdos filetime resolution\fR
+.TP 0.2i
+\(bu
+\fIdos filetimes\fR
+.TP 0.2i
+\(bu
+\fIexec\fR
+.TP 0.2i
+\(bu
+\fIfake directory create times\fR
+.TP 0.2i
+\(bu
+\fIfake oplocks\fR
+.TP 0.2i
+\(bu
+\fIfollow symlinks\fR
+.TP 0.2i
+\(bu
+\fIforce create mode\fR
+.TP 0.2i
+\(bu
+\fIforce directory mode\fR
+.TP 0.2i
+\(bu
+\fIforce directory security mode\fR
+.TP 0.2i
+\(bu
+\fIforce group\fR
+.TP 0.2i
+\(bu
+\fIforce security mode\fR
+.TP 0.2i
+\(bu
+\fIforce user\fR
+.TP 0.2i
+\(bu
+\fIfstype\fR
+.TP 0.2i
+\(bu
+\fIgroup\fR
+.TP 0.2i
+\(bu
+\fIguest account\fR
+.TP 0.2i
+\(bu
+\fIguest ok\fR
+.TP 0.2i
+\(bu
+\fIguest only\fR
+.TP 0.2i
+\(bu
+\fIhide dot files\fR
+.TP 0.2i
+\(bu
+\fIhide files\fR
+.TP 0.2i
+\(bu
+\fIhosts allow\fR
+.TP 0.2i
+\(bu
+\fIhosts deny\fR
+.TP 0.2i
+\(bu
+\fIinclude\fR
+.TP 0.2i
+\(bu
+\fIinherit permissions\fR
+.TP 0.2i
+\(bu
+\fIinvalid users\fR
+.TP 0.2i
+\(bu
+\fIlevel2 oplocks\fR
+.TP 0.2i
+\(bu
+\fIlocking\fR
+.TP 0.2i
+\(bu
+\fIlppause command\fR
+.TP 0.2i
+\(bu
+\fIlpq command\fR
+.TP 0.2i
+\(bu
+\fIlpresume command\fR
+.TP 0.2i
+\(bu
+\fIlprm command\fR
+.TP 0.2i
+\(bu
+\fImagic output\fR
+.TP 0.2i
+\(bu
+\fImagic script\fR
+.TP 0.2i
+\(bu
+\fImangle case\fR
+.TP 0.2i
+\(bu
+\fImangled map\fR
+.TP 0.2i
+\(bu
+\fImangled names\fR
+.TP 0.2i
+\(bu
+\fImangling char\fR
+.TP 0.2i
+\(bu
+\fImap archive\fR
+.TP 0.2i
+\(bu
+\fImap hidden\fR
+.TP 0.2i
+\(bu
+\fImap system\fR
+.TP 0.2i
+\(bu
+\fImax connections\fR
+.TP 0.2i
+\(bu
+\fImax print jobs\fR
+.TP 0.2i
+\(bu
+\fImin print space\fR
+.TP 0.2i
+\(bu
+\fImsdfs root\fR
+.TP 0.2i
+\(bu
+\fInt acl support\fR
+.TP 0.2i
+\(bu
+\fIonly guest\fR
+.TP 0.2i
+\(bu
+\fIonly user\fR
+.TP 0.2i
+\(bu
+\fIoplock contention limit\fR
+.TP 0.2i
+\(bu
+\fIoplocks\fR
+.TP 0.2i
+\(bu
+\fIpath\fR
+.TP 0.2i
+\(bu
+\fIposix locking\fR
+.TP 0.2i
+\(bu
+\fIpostexec\fR
+.TP 0.2i
+\(bu
+\fIpostscript\fR
+.TP 0.2i
+\(bu
+\fIpreexec\fR
+.TP 0.2i
+\(bu
+\fIpreexec close\fR
+.TP 0.2i
+\(bu
+\fIpreserve case\fR
+.TP 0.2i
+\(bu
+\fIprint command\fR
+.TP 0.2i
+\(bu
+\fIprint ok\fR
+.TP 0.2i
+\(bu
+\fIprintable\fR
+.TP 0.2i
+\(bu
+\fIprinter\fR
+.TP 0.2i
+\(bu
+\fIprinter admin\fR
+.TP 0.2i
+\(bu
+\fIprinter driver\fR
+.TP 0.2i
+\(bu
+\fIprinter driver location\fR
+.TP 0.2i
+\(bu
+\fIprinter name\fR
+.TP 0.2i
+\(bu
+\fIprinting\fR
+.TP 0.2i
+\(bu
+\fIpublic\fR
+.TP 0.2i
+\(bu
+\fIqueuepause command\fR
+.TP 0.2i
+\(bu
+\fIqueueresume command\fR
+.TP 0.2i
+\(bu
+\fIread list\fR
+.TP 0.2i
+\(bu
+\fIread only\fR
+.TP 0.2i
+\(bu
+\fIroot postexec\fR
+.TP 0.2i
+\(bu
+\fIroot preexec\fR
+.TP 0.2i
+\(bu
+\fIroot preexec close\fR
+.TP 0.2i
+\(bu
+\fIsecurity mask\fR
+.TP 0.2i
+\(bu
+\fIset directory\fR
+.TP 0.2i
+\(bu
+\fIshort preserve case\fR
+.TP 0.2i
+\(bu
+\fIstatus\fR
+.TP 0.2i
+\(bu
+\fIstrict allocate\fR
+.TP 0.2i
+\(bu
+\fIstrict locking\fR
+.TP 0.2i
+\(bu
+\fIstrict sync\fR
+.TP 0.2i
+\(bu
+\fIsync always\fR
+.TP 0.2i
+\(bu
+\fIuse client driver\fR
+.TP 0.2i
+\(bu
+\fIuser\fR
+.TP 0.2i
+\(bu
+\fIusername\fR
+.TP 0.2i
+\(bu
+\fIusers\fR
+.TP 0.2i
+\(bu
+\fIvalid users\fR
+.TP 0.2i
+\(bu
+\fIveto files\fR
+.TP 0.2i
+\(bu
+\fIveto oplock files\fR
+.TP 0.2i
+\(bu
+\fIvfs object\fR
+.TP 0.2i
+\(bu
+\fIvfs options\fR
+.TP 0.2i
+\(bu
+\fIvolume\fR
+.TP 0.2i
+\(bu
+\fIwide links\fR
+.TP 0.2i
+\(bu
+\fIwritable\fR
+.TP 0.2i
+\(bu
+\fIwrite cache size\fR
+.TP 0.2i
+\(bu
+\fIwrite list\fR
+.TP 0.2i
+\(bu
+\fIwrite ok\fR
+.TP 0.2i
+\(bu
+\fIwriteable\fR
+.SH "EXPLANATION OF EACH PARAMETER"
+.TP
+\fBabort shutdown script (G)\fR
+\fBThis parameter only exists in the HEAD cvs branch\fR
+This a full path name to a script called by
+\fBsmbd(8)\fRthat
+should stop a shutdown procedure issued by the \fIshutdown script\fR.
+
+This command will be run as user.
+
+Default: \fBNone\fR.
+
+Example: \fBabort shutdown script = /sbin/shutdown -c\fR
+.TP
+\fBadd printer command (G)\fR
+With the introduction of MS-RPC based printing
+support for Windows NT/2000 clients in Samba 2.2, The MS Add
+Printer Wizard (APW) icon is now also available in the
+"Printers..." folder displayed a share listing. The APW
+allows for printers to be add remotely to a Samba or Windows
+NT/2000 print server.
+
+For a Samba host this means that the printer must be
+physically added to the underlying printing system. The \fIadd
+printer command\fR defines a script to be run which
+will perform the necessary operations for adding the printer
+to the print system and to add the appropriate service definition
+to the \fIsmb.conf\fR file in order that it can be
+shared by \fBsmbd(8)\fR
+.
+
+The \fIadd printer command\fR is
+automatically invoked with the following parameter (in
+order:
+.RS
+.TP 0.2i
+\(bu
+\fIprinter name\fR
+.TP 0.2i
+\(bu
+\fIshare name\fR
+.TP 0.2i
+\(bu
+\fIport name\fR
+.TP 0.2i
+\(bu
+\fIdriver name\fR
+.TP 0.2i
+\(bu
+\fIlocation\fR
+.TP 0.2i
+\(bu
+\fIWindows 9x driver location\fR
.RE
-
-.SS The [homes] section
-.RS 3
-If a section called 'homes' is included in the configuration file, services
-connecting clients to their home directories can be created on the fly by the
-server.
-
-When the connection request is made, the existing services are scanned. If a
-match is found, it is used. If no match is found, the requested service name is
-treated as a user name and looked up in the local passwords file. If the
-name exists and the correct password has been given, a service is created
-by cloning the [homes] section.
-
-Some modifications are then made to the newly created section:
-
-.RS 3
-The service name is changed from 'homes' to the located username
-
-If no path was given, the path is set to the user's home directory.
+.PP
+All parameters are filled in from the PRINTER_INFO_2 structure sent
+by the Windows NT/2000 client with one exception. The "Windows 9x
+driver location" parameter is included for backwards compatibility
+only. The remaining fields in the structure are generated from answers
+to the APW questions.
+.PP
+.PP
+Once the \fIadd printer command\fR has
+been executed, \fBsmbd\fR will reparse the \fI smb.conf\fR to determine if the share defined by the APW
+exists. If the sharename is still invalid, then \fBsmbd
+\fRwill return an ACCESS_DENIED error to the client.
+.PP
+.PP
+See also \fI delete printer command\fR, \fIprinting\fR,
+\fIshow add
+printer wizard\fR
+.PP
+.PP
+Default: \fBnone\fR
+.PP
+.PP
+Example: \fBaddprinter command = /usr/bin/addprinter
+\fR.PP
+.TP
+\fBadd share command (G)\fR
+Samba 2.2.0 introduced the ability to dynamically
+add and delete shares via the Windows NT 4.0 Server Manager. The
+\fIadd share command\fR is used to define an
+external program or script which will add a new service definition
+to \fIsmb.conf\fR. In order to successfully
+execute the \fIadd share command\fR, \fBsmbd\fR
+requires that the administrator be connected using a root account (i.e.
+uid == 0).
+
+When executed, \fBsmbd\fR will automatically invoke the
+\fIadd share command\fR with four parameters.
+.RS
+.TP 0.2i
+\(bu
+\fIconfigFile\fR - the location
+of the global \fIsmb.conf\fR file.
+.TP 0.2i
+\(bu
+\fIshareName\fR - the name of the new
+share.
+.TP 0.2i
+\(bu
+\fIpathName\fR - path to an **existing**
+directory on disk.
+.TP 0.2i
+\(bu
+\fIcomment\fR - comment string to associate
+with the new share.
.RE
-
-If you decide to use a path= line in your [homes] section then you may
-find it useful to use the %S macro. For example path=/data/pchome/%S
-would be useful if you have different home directories for your PCs
-than for unix access.
-
-This is a fast and simple way to give a large number of clients access to
-their home directories with a minimum of fuss.
-
-A similar process occurs if the requested service name is "homes", except that
-the service name is not changed to that of the requesting user. This method
-of using the [homes] section works well if different users share a client PC.
-
-The [homes] section can specify all the parameters a normal service section
-can specify, though some make more sense than others. The following is a
-typical and suitable [homes] section:
-
- [homes]
- writable = yes
-
-An important point:
-
-.RS 3
-If guest access is specified in the [homes] section, all home directories will
-be accessible to all clients
-.B without a password.
-In the very unlikely event
-that this is actually desirable, it would be wise to also specify read only
-access.
+.PP
+This parameter is only used for add file shares. To add printer shares,
+see the \fIadd printer
+command\fR.
+.PP
+.PP
+See also \fIchange share
+command\fR, \fIdelete share
+command\fR.
+.PP
+.PP
+Default: \fBnone\fR
+.PP
+.PP
+Example: \fBadd share command = /usr/local/bin/addshare\fR
+.PP
+.TP
+\fBadd machine script (G)\fR
+This is the full pathname to a script that will
+be run by smbd(8)when a machine is added
+to it's domain using the administrator username and password method.
+
+This option is only required when using sam back-ends tied to the
+Unix uid method of RID calculation such as smbpasswd. This option is only
+available in Samba 3.0.
+
+Default: \fBadd machine script = <empty string>
+\fR
+Example: \fBadd machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
+\fR.TP
+\fBadd user script (G)\fR
+This is the full pathname to a script that will
+be run \fBAS ROOT\fR by smbd(8)
+under special circumstances described below.
+
+Normally, a Samba server requires that UNIX users are
+created for all users accessing files on this server. For sites
+that use Windows NT account databases as their primary user database
+creating these users and keeping the user list in sync with the
+Windows NT PDC is an onerous task. This option allows smbdto create the required UNIX users
+\fBON DEMAND\fR when a user accesses the Samba server.
+
+In order to use this option, smbd
+must be set to \fIsecurity = server\fR or \fI security = domain\fR and \fIadd user script\fR
+must be set to a full pathname for a script that will create a UNIX
+user given one argument of \fI%u\fR, which expands into
+the UNIX user name to create.
+
+When the Windows user attempts to access the Samba server,
+at login (session setup in the SMB protocol) time, smbdcontacts the \fIpassword server\fR and
+attempts to authenticate the given user with the given password. If the
+authentication succeeds then \fBsmbd\fR
+attempts to find a UNIX user in the UNIX password database to map the
+Windows user into. If this lookup fails, and \fIadd user script
+\fRis set then \fBsmbd\fR will
+call the specified script \fBAS ROOT\fR, expanding
+any \fI%u\fR argument to be the user name to create.
+
+If this script successfully creates the user then \fBsmbd
+\fRwill continue on as though the UNIX user
+already existed. In this way, UNIX users are dynamically created to
+match existing Windows NT accounts.
+
+See also \fI security\fR, \fIpassword server\fR,
+\fIdelete user
+script\fR.
+
+Default: \fBadd user script = <empty string>
+\fR
+Example: \fBadd user script = /usr/local/samba/bin/add_user
+%u\fR
+.TP
+\fBadmin users (S)\fR
+This is a list of users who will be granted
+administrative privileges on the share. This means that they
+will do all file operations as the super-user (root).
+
+You should use this option very carefully, as any user in
+this list will be able to do anything they like on the share,
+irrespective of file permissions.
+
+Default: \fBno admin users\fR
+
+Example: \fBadmin users = jason\fR
+.TP
+\fBallow hosts (S)\fR
+Synonym for \fIhosts allow\fR.
+.TP
+\fBallow trusted domains (G)\fR
+This option only takes effect when the \fIsecurity\fR option is set to
+server or domain.
+If it is set to no, then attempts to connect to a resource from
+a domain or workgroup other than the one which smbdis running
+in will fail, even if that domain is trusted by the remote server
+doing the authentication.
+
+This is useful if you only want your Samba server to
+serve resources to users in the domain it is a member of. As
+an example, suppose that there are two domains DOMA and DOMB. DOMB
+is trusted by DOMA, which contains the Samba server. Under normal
+circumstances, a user with an account in DOMB can then access the
+resources of a UNIX account with the same account name on the
+Samba server even if they do not have an account in DOMA. This
+can make implementing a security boundary difficult.
+
+Default: \fBallow trusted domains = yes\fR
+.TP
+\fBannounce as (G)\fR
+This specifies what type of server
+\fBnmbd\fR
+will announce itself as, to a network neighborhood browse
+list. By default this is set to Windows NT. The valid options
+are : "NT Server" (which can also be written as "NT"),
+"NT Workstation", "Win95" or "WfW" meaning Windows NT Server,
+Windows NT Workstation, Windows 95 and Windows for Workgroups
+respectively. Do not change this parameter unless you have a
+specific need to stop Samba appearing as an NT server as this
+may prevent Samba servers from participating as browser servers
+correctly.
+
+Default: \fBannounce as = NT Server\fR
+
+Example: \fBannounce as = Win95\fR
+.TP
+\fBannounce version (G)\fR
+This specifies the major and minor version numbers
+that nmbd will use when announcing itself as a server. The default
+is 4.2. Do not change this parameter unless you have a specific
+need to set a Samba server to be a downlevel server.
+
+Default: \fBannounce version = 4.5\fR
+
+Example: \fBannounce version = 2.0\fR
+.TP
+\fBauto services (G)\fR
+This is a synonym for the \fIpreload\fR.
+.TP
+\fBavailable (S)\fR
+This parameter lets you "turn off" a service. If
+\fIavailable = no\fR, then \fBALL\fR
+attempts to connect to the service will fail. Such failures are
+logged.
+
+Default: \fBavailable = yes\fR
+.TP
+\fBbind interfaces only (G)\fR
+This global parameter allows the Samba admin
+to limit what interfaces on a machine will serve SMB requests. If
+affects file service smbd(8)and
+name service nmbd(8)in slightly
+different ways.
+
+For name service it causes \fBnmbd\fR to bind
+to ports 137 and 138 on the interfaces listed in the interfaces parameter. \fBnmbd
+\fRalso binds to the "all addresses" interface (0.0.0.0)
+on ports 137 and 138 for the purposes of reading broadcast messages.
+If this option is not set then \fBnmbd\fR will service
+name requests on all of these sockets. If \fIbind interfaces
+only\fR is set then \fBnmbd\fR will check the
+source address of any packets coming in on the broadcast sockets
+and discard any that don't match the broadcast addresses of the
+interfaces in the \fIinterfaces\fR parameter list.
+As unicast packets are received on the other sockets it allows
+\fBnmbd\fR to refuse to serve names to machines that
+send packets that arrive through any interfaces not listed in the
+\fIinterfaces\fR list. IP Source address spoofing
+does defeat this simple check, however so it must not be used
+seriously as a security feature for \fBnmbd\fR.
+
+For file service it causes smbd(8)
+to bind only to the interface list given in the interfaces parameter. This restricts the networks that
+\fBsmbd\fR will serve to packets coming in those
+interfaces. Note that you should not use this parameter for machines
+that are serving PPP or other intermittent or non-broadcast network
+interfaces as it will not cope with non-permanent interfaces.
+
+If \fIbind interfaces only\fR is set then
+unless the network address \fB127.0.0.1\fR is added
+to the \fIinterfaces\fR parameter list \fBsmbpasswd(8)\fR
+and \fBswat(8)\fRmay
+not work as expected due to the reasons covered below.
+
+To change a users SMB password, the \fBsmbpasswd\fR
+by default connects to the \fBlocalhost - 127.0.0.1\fR
+address as an SMB client to issue the password change request. If
+\fIbind interfaces only\fR is set then unless the
+network address \fB127.0.0.1\fR is added to the
+\fIinterfaces\fR parameter list then \fB smbpasswd\fR will fail to connect in it's default mode.
+\fBsmbpasswd\fR can be forced to use the primary IP interface
+of the local host by using its \fI-r remote machine\fR
+parameter, with \fIremote machine\fR set
+to the IP name of the primary interface of the local host.
+
+The \fBswat\fR status page tries to connect with
+\fBsmbd\fR and \fBnmbd\fR at the address
+\fB127.0.0.1\fR to determine if they are running.
+Not adding \fB127.0.0.1\fR will cause \fB smbd\fR and \fBnmbd\fR to always show
+"not running" even if they really are. This can prevent \fB swat\fR from starting/stopping/restarting \fBsmbd\fR
+and \fBnmbd\fR.
+
+Default: \fBbind interfaces only = no\fR
+.TP
+\fBblocking locks (S)\fR
+This parameter controls the behavior of smbd(8)when given a request by a client
+to obtain a byte range lock on a region of an open file, and the
+request has a time limit associated with it.
+
+If this parameter is set and the lock range requested
+cannot be immediately satisfied, Samba 2.2 will internally
+queue the lock request, and periodically attempt to obtain
+the lock until the timeout period expires.
+
+If this parameter is set to false, then
+Samba 2.2 will behave as previous versions of Samba would and
+will fail the lock request immediately if the lock range
+cannot be obtained.
+
+Default: \fBblocking locks = yes\fR
+.TP
+\fBbrowsable (S)\fR
+See the \fI browseable\fR.
+.TP
+\fBbrowse list (G)\fR
+This controls whether \fBsmbd(8)\fRwill serve a browse list to
+a client doing a \fBNetServerEnum\fR call. Normally
+set to true. You should never need to change
+this.
+
+Default: \fBbrowse list = yes\fR
+.TP
+\fBbrowseable (S)\fR
+This controls whether this share is seen in
+the list of available shares in a net view and in the browse list.
+
+Default: \fBbrowseable = yes\fR
+.TP
+\fBcase sensitive (S)\fR
+See the discussion in the section NAME MANGLING.
+
+Default: \fBcase sensitive = no\fR
+.TP
+\fBcasesignames (S)\fR
+Synonym for case
+sensitive.
+.TP
+\fBchange notify timeout (G)\fR
+This SMB allows a client to tell a server to
+"watch" a particular directory for any changes and only reply to
+the SMB request when a change has occurred. Such constant scanning of
+a directory is expensive under UNIX, hence an \fBsmbd(8)\fRdaemon only performs such a scan
+on each requested directory once every \fIchange notify
+timeout\fR seconds.
+
+Default: \fBchange notify timeout = 60\fR
+
+Example: \fBchange notify timeout = 300\fR
+
+Would change the scan time to every 5 minutes.
+.TP
+\fBchange share command (G)\fR
+Samba 2.2.0 introduced the ability to dynamically
+add and delete shares via the Windows NT 4.0 Server Manager. The
+\fIchange share command\fR is used to define an
+external program or script which will modify an existing service definition
+in \fIsmb.conf\fR. In order to successfully
+execute the \fIchange share command\fR, \fBsmbd\fR
+requires that the administrator be connected using a root account (i.e.
+uid == 0).
+
+When executed, \fBsmbd\fR will automatically invoke the
+\fIchange share command\fR with four parameters.
+.RS
+.TP 0.2i
+\(bu
+\fIconfigFile\fR - the location
+of the global \fIsmb.conf\fR file.
+.TP 0.2i
+\(bu
+\fIshareName\fR - the name of the new
+share.
+.TP 0.2i
+\(bu
+\fIpathName\fR - path to an **existing**
+directory on disk.
+.TP 0.2i
+\(bu
+\fIcomment\fR - comment string to associate
+with the new share.
.RE
+.PP
+This parameter is only used modify existing file shares definitions. To modify
+printer shares, use the "Printers..." folder as seen when browsing the Samba host.
+.PP
+.PP
+See also \fIadd share
+command\fR, \fIdelete
+share command\fR.
+.PP
+.PP
+Default: \fBnone\fR
+.PP
+.PP
+Example: \fBchange share command = /usr/local/bin/addshare\fR
+.PP
+.TP
+\fBcharacter set (G)\fR
+This allows smbdto map incoming filenames
+from a DOS Code page (see the client
+code page parameter) to several built in UNIX character sets.
+The built in code page translations are:
+.RS
+.TP 0.2i
+\(bu
+ISO8859-1 : Western European
+UNIX character set. The parameter \fIclient code page\fR
+\fBMUST\fR be set to code page 850 if the
+\fIcharacter set\fR parameter is set to
+ISO8859-1 in order for the conversion to the
+UNIX character set to be done correctly.
+.TP 0.2i
+\(bu
+ISO8859-2 : Eastern European
+UNIX character set. The parameter \fIclient code page
+\fR\fBMUST\fR be set to code page 852 if
+the \fI character set\fR parameter is set
+to ISO8859-2 in order for the conversion
+to the UNIX character set to be done correctly.
+.TP 0.2i
+\(bu
+ISO8859-5 : Russian Cyrillic
+UNIX character set. The parameter \fIclient code page
+\fR\fBMUST\fR be set to code page
+866 if the \fIcharacter set \fR parameter is
+set to ISO8859-5 in order for the conversion
+to the UNIX character set to be done correctly.
+.TP 0.2i
+\(bu
+ISO8859-7 : Greek UNIX
+character set. The parameter \fIclient code page
+\fR\fBMUST\fR be set to code page
+737 if the \fIcharacter set\fR parameter is
+set to ISO8859-7 in order for the conversion
+to the UNIX character set to be done correctly.
+.TP 0.2i
+\(bu
+KOI8-R : Alternate mapping
+for Russian Cyrillic UNIX character set. The parameter
+\fIclient code page\fR \fBMUST\fR
+be set to code page 866 if the \fIcharacter set\fR
+parameter is set to KOI8-R in order for the
+conversion to the UNIX character set to be done correctly.
.RE
-
-Note that the browseable flag for auto home directories will be
-inherited from the global browseable flag, not the [homes] browseable
-flag. This is useful as it means setting browseable=no in the [homes]
-section will hide the [homes] service but make any auto home
-directories visible.
-
-.SS The [printers] section
-.RS 3
-This section works like [homes], but for printers.
-
-If a [printers] section occurs in the configuration file, users are able
-to connect to any printer specified in the local host's printcap file.
-
-When a connection request is made, the existing services are scanned. If a
-match is found, it is used. If no match is found, but a [homes] section
-exists, it is used as described above. Otherwise, the requested service name is
-treated as a printer name and the appropriate printcap file is scanned to
-see if the requested service name is a valid printer name. If a match is
-found, a new service is created by cloning the [printers] section.
-
-A few modifications are then made to the newly created section:
-
-.RS 3
-The service name is set to the located printer name
-
-If no printer name was given, the printer name is set to the located printer
-name
-
-If the service does not permit guest access and no username was given, the
-username is set to the located printer name.
+.PP
+\fBBUG\fR. These MSDOS code page to UNIX character
+set mappings should be dynamic, like the loading of MS DOS code pages,
+not static.
+.PP
+.PP
+Normally this parameter is not set, meaning no filename
+translation is done.
+.PP
+.PP
+Default: \fBcharacter set = <empty string>\fR
+.PP
+.PP
+Example: \fBcharacter set = ISO8859-1\fR
+.PP
+.TP
+\fBclient code page (G)\fR
+This parameter specifies the DOS code page
+that the clients accessing Samba are using. To determine what code
+page a Windows or DOS client is using, open a DOS command prompt
+and type the command \fBchcp\fR. This will output
+the code page. The default for USA MS-DOS, Windows 95, and
+Windows NT releases is code page 437. The default for western
+European releases of the above operating systems is code page 850.
+
+This parameter tells smbd(8)
+which of the \fIcodepage.XXX
+\fRfiles to dynamically load on startup. These files,
+described more fully in the manual page \fBmake_smbcodepage(1)\fR, tell \fB smbd\fR how to map lower to upper case characters to provide
+the case insensitivity of filenames that Windows clients expect.
+
+Samba currently ships with the following code page files :
+.RS
+.TP 0.2i
+\(bu
+Code Page 437 - MS-DOS Latin US
+.TP 0.2i
+\(bu
+Code Page 737 - Windows '95 Greek
+.TP 0.2i
+\(bu
+Code Page 850 - MS-DOS Latin 1
+.TP 0.2i
+\(bu
+Code Page 852 - MS-DOS Latin 2
+.TP 0.2i
+\(bu
+Code Page 861 - MS-DOS Icelandic
+.TP 0.2i
+\(bu
+Code Page 866 - MS-DOS Cyrillic
+.TP 0.2i
+\(bu
+Code Page 932 - MS-DOS Japanese SJIS
+.TP 0.2i
+\(bu
+Code Page 936 - MS-DOS Simplified Chinese
+.TP 0.2i
+\(bu
+Code Page 949 - MS-DOS Korean Hangul
+.TP 0.2i
+\(bu
+Code Page 950 - MS-DOS Traditional Chinese
.RE
+.PP
+Thus this parameter may have any of the values 437, 737, 850, 852,
+861, 932, 936, 949, or 950. If you don't find the codepage you need,
+read the comments in one of the other codepage files and the
+\fBmake_smbcodepage(1)\fR man page and write one. Please
+remember to donate it back to the Samba user community.
+.PP
+.PP
+This parameter co-operates with the \fIvalid
+chars\fR parameter in determining what characters are
+valid in filenames and how capitalization is done. If you set both
+this parameter and the \fIvalid chars\fR parameter
+the \fIclient code page\fR parameter
+\fBMUST\fR be set before the \fIvalid
+chars\fR parameter in the \fIsmb.conf\fR
+file. The \fIvalid chars\fR string will then
+augment the character settings in the \fIclient code page\fR
+parameter.
+.PP
+.PP
+If not set, \fIclient code page\fR defaults
+to 850.
+.PP
+.PP
+See also : \fIvalid
+chars\fR, \fIcode page directory\fR
+.PP
+.PP
+Default: \fBclient code page = 850\fR
+.PP
+.PP
+Example: \fBclient code page = 936\fR
+.PP
+.TP
+\fBcode page directory (G)\fR
+Define the location of the various client code page
+files.
-Note that the [printers] service MUST be printable - if you specify otherwise,
-the server will refuse to load the configuration file.
-
-Typically the path specified would be that of a world-writable spool directory
-with the sticky bit set on it. A typical [printers] entry would look like this:
-
- [printers]
- path = /usr/spool/public
- writable = no
- public = yes
- printable = yes
-
-All aliases given for a printer in the printcap file are legitimate printer
-names as far as the server is concerned. If your printing subsystem doesn't
-work like that, you will have to set up a pseudo-printcap. This is a file
-consisting of one or more lines like this:
-
- alias|alias|alias|alias...
-
-Each alias should be an acceptable printer name for your printing
-subsystem. In the [global] section, specify the new file as your printcap.
-The server will then only recognise names found in your pseudo-printcap,
-which of course can contain whatever aliases you like. The same technique
-could be used simply to limit access to a subset of your local printers.
-
-An alias, by the way, is defined as any component of the first entry of a
-printcap record. Records are separated by newlines, components (if there are
-more than one) are separated by vertical bar symbols ("|").
-.SH PARAMETERS
-Parameters define the specific attributes of services.
-
-Some parameters are specific to the [global] section (eg., security).
-Some parameters are usable in all sections (eg., create mode). All others are
-permissible only in normal sections. For the purposes of the following
-descriptions the [homes] and [printers] sections will be considered normal.
-The letter 'G' in parentheses indicates that a parameter is specific to the
-[global] section. The letter 'S' indicates that a parameter can be
-specified in a secvice specific section. Note that all S parameters
-can also be specified in the [global] section - in which case they
-will define the default behaviour for all services.
-
-Parameters are arranged here in alphabetical order - this may not create
-best bedfellows, but at least you can find them! Where there are synonyms,
-the preferred synonym is described, others refer to the preferred synonym.
-
-.SS VARIABLE SUBSTITUTIONS
-
-Many of the strings that are settable in the config file can take
-substitutions. For example the option "path = /tmp/%u" would be
-interpreted as "path = /tmp/john" if the user connected with the
-username john.
-
-These substitutions are mostly noted in the descriptions below, but
-there are some general substitions which apply whenever they might be
-relevant. These are:
-
-%S = the name of the current service, if any
-
-%P = the root directory of the current service, if any
-
-%u = user name of the current service, if any
-
-%g = primary group name of %u
-
-%U = session user name (the user name that the client wanted, not
-necessarily the same as the one they got)
-
-%G = primary group name of %U
-
-%H = the home directory of the user given by %u
-
-%v = the Samba version
-
-%h = the hostname that Samba is running on
-
-%m = the netbios name of the client machine (very useful)
-
-%L = the netbios name of the server. This allows you to change your
-config based on what the client calls you. Your server can have a "dual
-personality".
-
-%M = the internet name of the client machine
-
-%d = The process id of the current server process
-
-%a = the architecture of the remote machine. Only some are recognised,
-and those may not be 100% reliable. It currently recognises Samba,
-WfWg, WinNT and Win95. Anything else will be known as "UNKNOWN". If it
-gets it wrong then sending me a level 3 log should allow me to fix it.
-
-%I = The IP address of the client machine
-
-%T = the current date and time
-
-There are some quite creative things that can be done with these
-substitutions and other smb.conf options.
-
-.SS NAME MANGLING
-
-Samba supports "name mangling" so that Dos and Windows clients can use
-files that don't conform to the 8.3 format. It can also be set to adjust
-the case of 8.3 format filenames.
-
-There are several options that control the way mangling is performed,
-and they are grouped here rather than listed separately. For the
-defaults look at the output of the testparm program.
-
-All of these options can be set separately for each service (or
-globally, of course).
-
-The options are:
-
-"mangle case = yes/no" controls if names that have characters that
-aren't of the "default" case are mangled. For example, if this is yes
-then a name like "Mail" would be mangled. Default no.
-
-"case sensitive = yes/no" controls whether filenames are case
-sensitive. If they aren't then Samba must do a filename search and
-match on passed names. Default no.
-
-"default case = upper/lower" controls what the default case is for new
-filenames. Default lower.
-
-"preserve case = yes/no" controls if new files are created with the
-case that the client passes, or if they are forced to be the "default"
-case. Default no.
-
-"short preserve case = yes/no" controls if new files which conform to 8.3
-syntax, that is all in upper case and of suitable length, are created
-upper case, or if they are forced to be the "default" case. This option can
-be use with "preserve case = yes" to permit long filenames to retain their
-case, while short names are lowered. Default no.
-
-.SS COMPLETE LIST OF GLOBAL PARAMETER
-
-Here is a list of all global parameters. See the section of each
-parameter for details. Note that some are synonyms.
-
-auto services
-
-config file
-
-deadtime
-
-debuglevel
-
-default
-
-default service
-
-dfree command
-
-encrypt passwords
-
-getwd cache
-
-hosts equiv
-
-include
-
-keepalive
-
-lock dir
-
-load printers
-
-lock directory
-
-log file
-
-log level
-
-lpq cache time
-
-mangled stack
-
-max log size
-
-max packet
-
-max xmit
-
-message command
-
-null passwords
-
-os level
-
-packet size
-
-passwd chat
-
-passwd program
-
-password level
-
-password server
-
-preferred master
-
-preload
-
-printing
-
-printcap name
-
-protocol
-
-read bmpx
-
-read prediction
-
-read raw
-
-read size
-
-root
-
-root dir
-
-root directory
-
-security
-
-server string
-
-smbrun
-
-socket options
-
-status
-
-strip dot
-
-time offset
-
-username map
-
-use rhosts
-
-valid chars
-
-workgroup
-
-write raw
-
-.SS COMPLETE LIST OF SERVICE PARAMETER
-
-Here is a list of all service parameters. See the section of each
-parameter for details. Note that some are synonyms.
-
-admin users
-
-allow hosts
-
-alternate permissions
-
-available
-
-browseable
-
-case sensitive
-
-case sig names
-
-copy
-
-create mask
-
-create mode
-
-comment
-
-default case
-
-deny hosts
-
-directory
-
-dont descend
-
-exec
-
-force group
-
-force user
-
-guest account
-
-guest ok
-
-guest only
-
-hide dot files
-
-hosts allow
-
-hosts deny
-
-invalid users
-
-locking
-
-lppause command
-
-lpq command
-
-lpresume command
-
-lprm command
-
-magic output
-
-magic script
-
-mangle case
-
-mangled names
-
-mangling char
-
-map archive
-
-map hidden
-
-map system
-
-max connections
-
-min print space
-
-only guest
-
-only user
-
-path
-
-postexec
-
-postscript
-
-preserve case
-
-print command
-
-print ok
-
-printable
-
-printer
-
-printer name
-
-public
-
-read only
-
-read list
-
-revalidate
-
-root postexec
-
-root preexec
-
-set directory
-
-share modes
-
-short preserve case
-
-strict locking
-
-sync always
-
-user
-
-username
-
-users
-
-valid users
-
-volume
-
-wide links
-
-writable
-
-write ok
-
-writeable
-
-write list
-
-.SS EXPLANATION OF EACH PARAMETER
-.RS 3
-
-.SS admin users (G)
-
-This is a list of users who will be granted administrative privilages
-on the share. This means that they will do all file operations as the
-super-user (root).
-
-You should use this option very carefully, as any user in this list
-will be able to do anything they like on the share, irrespective of
-file permissions.
-
-.B Default:
- no admin users
-
-.B Example:
- admin users = jason
-
-.SS auto services (G)
-This is a list of services that you want to be automatically added to
-the browse lists. This is most useful for homes and printers services
-that would otherwise not be visible.
-
-Note that if you just want all printers in your printcap file loaded
-then the "load printers" option is easier.
-
-.B Default:
- no auto services
-
-.B Example:
- auto services = fred lp colorlp
-
-
-.SS allow hosts (S)
-A synonym for this parameter is 'hosts allow'.
-
-This parameter is a comma delimited set of hosts which are permitted to access
-a services. If specified in the [global] section, matching hosts will be
-allowed access to any service that does not specifically exclude them from
-access. Specific services my have their own list, which override those
-specified in the [global] section.
-
-You can specify the hosts by name or IP number. For example, you could
-restrict access to only the hosts on a Class C subnet with something like
-"allow hosts = 150.203.5.". The full syntax of the list is described in
-the man page
-.B hosts_access(5).
-
-You can also specify hosts by network/netmask pairs and by netgroup
-names if your system supports netgroups. The EXCEPT keyword can also
-be used to limit a wildcard list. The following examples may provide
-some help:
-
-Example 1: allow all IPs in 150.203.*.* except one
-
- hosts allow = 150.203. EXCEPT 150.203.6.66
-
-Example 2: allow hosts that match the given network/netmask
-
- hosts allow = 150.203.15.0/255.255.255.0
-
-Example 3: allow a couple of hosts
-
- hosts allow = lapland, arvidsjaur
-
-Example 4: allow only hosts in netgroup "foonet" or localhost, but
-deny access from one particular host
-
- hosts allow = @foonet, localhost
- hosts deny = pirate
-
-Note that access still requires suitable user-level passwords.
-
-See testparm(1) for a way of testing your host access to see if it
-does what you expect.
-
-.B Default:
- none (ie., all hosts permitted access)
-
-.B Example:
- allow hosts = 150.203.5. myhost.mynet.edu.au
-
-.SS alternate permissions (S)
-
-This option affects the way the "read only" DOS attribute is produced
-for unix files. If this is false then the read only bit is set for
-files on writeable shares which the user cannot write to.
-
-If this is true then it is set for files whos user write bit is not set.
-
-The latter behaviour of useful for when users copy files from each
-others directories, and use a file manager that preserves
-permissions. Without this option they may get annoyed as all copied
-files will have the "read only" bit set.
-
-.B Default:
- alternate permissions = no
-
-.B Example:
- alternate permissions = yes
-
-.SS available (S)
-This parameter lets you 'turn off' a service. If 'available = no', then
-ALL attempts to connect to the service will fail. Such failures are logged.
-
-.B Default:
- available = yes
-
-.B Example:
- available = no
-.SS browseable (S)
-This controls whether this share is seen in the list of available
-shares in a net view and in the browse list.
-
-.B Default:
- browseable = Yes
-
-.B Example:
- browseable = No
-
-.SS case sig names (G)
-See "case sensitive"
-
-.SS comment (S)
-This is a text field that is seen when a client does a net view to
-list what shares are available. It will also be used when browsing is
-fully supported.
-
-.B Default:
- No comment string
-
-.B Example:
- comment = Fred's Files
-
-.SS config file (G)
-
-This allows you to override the config file to use, instead of the
-default (usually smb.conf). There is a chicken and egg problem here as
-this option is set in the config file!
-
-For this reason, if the name of the config file has changed when the
-parameters are loaded then it will reload them from the new config
-file.
-
-This option takes the usual substitutions, which can be very useful.
-
-If thew config file doesn't exist then it won't be loaded (allowing
-you to special case the config files of just a few clients).
-
-.B Example:
- config file = /usr/local/samba/smb.conf.%m
-
-.SS copy (S)
-This parameter allows you to 'clone' service entries. The specified
-service is simply duplicated under the current service's name. Any
-parameters specified in the current section will override those in the
-section being copied.
-
-This feature lets you set up a 'template' service and create similar
-services easily. Note that the service being copied must occur earlier
-in the configuration file than the service doing the copying.
-
-.B Default:
- none
-
-.B Example:
- copy = otherservice
-.SS create mask (S)
-A synonym for this parameter is 'create mode'.
-
-This parameter is the octal modes which are used when converting DOS modes
-to Unix modes.
-
-Note that Samba will or this value with 0700 as you must have at least
-user read, write and execute for Samba to work properly.
-
-.B Default:
- create mask = 0755
-
-.B Example:
- create mask = 0775
-.SS create mode (S)
-See
-.B create mask.
-.SS dead time (G)
-The value of the parameter (a decimal integer) represents the number of
-minutes of inactivity before a connection is considered dead, and it
-is disconnected. The deadtime only takes effect if the number of open files
-is zero.
-
-This is useful to stop a server's resources being exhausted by a large
-number of inactive connections.
-
-Most clients have an auto-reconnect feature when a connection is broken so
-in most cases this parameter should be transparent to users.
-
-Using this parameter with a timeout of a few minutes is recommended
-for most systems.
-
-A deadtime of zero indicates that no auto-disconnection should be performed.
-
-.B Default:
- dead time = 0
-
-.B Example:
- dead time = 15
-.SS debug level (G)
-The value of the parameter (an integer) allows the debug level
-(logging level) to be specified in the smb.conf file. This is to give
-greater flexibility in the configuration of the system.
-
-The default will be the debug level specified on the command line.
-
-.B Example:
- debug level = 3
-.SS default (G)
-See
-.B default service.
-.SS default case (S)
-
-See the section on "NAME MANGLING" Also note the addition of "short
-preserve case"
-
-.SS default service (G)
-A synonym for this parameter is 'default'.
-
-This parameter specifies the name of a service which will be connected to
-if the service actually requested cannot be found. Note that the square
-brackets are NOT given in the parameter value (see example below).
-
-There is no default value for this parameter. If this parameter is not given,
-attempting to connect to a nonexistent service results in an error.
-
-Typically the default service would be a public, read-only service.
-
-Also not that s of 1.9.14 the apparent service name will be changed to
-equal that of the requested service, this is very useful as it allows
-you to use macros like %S to make a wildcard service.
-
-Note also that any _ characters in the name of the service used in the
-default service will get mapped to a /. This allows for interesting
-things.
-
-
-.B Example:
- default service = pub
+See also \fIclient
+code page\fR
+
+Default: \fBcode page directory = ${prefix}/lib/codepages
+\fR
+Example: \fBcode page directory = /usr/share/samba/codepages
+\fR.TP
+\fBcoding system (G)\fR
+This parameter is used to determine how incoming
+Shift-JIS Japanese characters are mapped from the incoming \fIclient code page\fR
+used by the client, into file names in the UNIX filesystem.
+Only useful if \fIclient code page\fR is set to
+932 (Japanese Shift-JIS). The options are :
+.RS
+.TP 0.2i
+\(bu
+SJIS - Shift-JIS. Does no
+conversion of the incoming filename.
+.TP 0.2i
+\(bu
+JIS8, J8BB, J8BH, J8@B,
+J8@J, J8@H - Convert from incoming Shift-JIS to eight
+bit JIS code with different shift-in, shift out codes.
+.TP 0.2i
+\(bu
+JIS7, J7BB, J7BH, J7@B, J7@J,
+J7@H - Convert from incoming Shift-JIS to seven bit
+JIS code with different shift-in, shift out codes.
+.TP 0.2i
+\(bu
+JUNET, JUBB, JUBH, JU@B, JU@J, JU@H
+- Convert from incoming Shift-JIS to JUNET code with different shift-in,
+shift out codes.
+.TP 0.2i
+\(bu
+EUC - Convert an incoming
+Shift-JIS character to EUC code.
+.TP 0.2i
+\(bu
+HEX - Convert an incoming
+Shift-JIS character to a 3 byte hex representation, i.e.
+:AB.
+.TP 0.2i
+\(bu
+CAP - Convert an incoming
+Shift-JIS character to the 3 byte hex representation used by
+the Columbia AppleTalk Program (CAP), i.e. :AB.
+This is used for compatibility between Samba and CAP.
+.RE
+.PP
+Default: \fBcoding system = <empty value>\fR
+.PP
+.TP
+\fBcomment (S)\fR
+This is a text field that is seen next to a share
+when a client does a queries the server, either via the network
+neighborhood or via \fBnet view\fR to list what shares
+are available.
+
+If you want to set the string that is displayed next to the
+machine name then see the \fI server string\fR parameter.
+
+Default: \fBNo comment string\fR
+
+Example: \fBcomment = Fred's Files\fR
+.TP
+\fBconfig file (G)\fR
+This allows you to override the config file
+to use, instead of the default (usually \fIsmb.conf\fR).
+There is a chicken and egg problem here as this option is set
+in the config file!
+
+For this reason, if the name of the config file has changed
+when the parameters are loaded then it will reload them from
+the new config file.
+
+This option takes the usual substitutions, which can
+be very useful.
+
+If the config file doesn't exist then it won't be loaded
+(allowing you to special case the config files of just a few
+clients).
+
+Example: \fBconfig file = /usr/local/samba/lib/smb.conf.%m
+\fR.TP
+\fBcopy (S)\fR
+This parameter allows you to "clone" service
+entries. The specified service is simply duplicated under the
+current service's name. Any parameters specified in the current
+section will override those in the section being copied.
+
+This feature lets you set up a 'template' service and
+create similar services easily. Note that the service being
+copied must occur earlier in the configuration file than the
+service doing the copying.
+
+Default: \fBno value\fR
+
+Example: \fBcopy = otherservice\fR
+.TP
+\fBcreate mask (S)\fR
+A synonym for this parameter is
+\fIcreate mode\fR
+\&.
+
+When a file is created, the necessary permissions are
+calculated according to the mapping from DOS modes to UNIX
+permissions, and the resulting UNIX mode is then bit-wise 'AND'ed
+with this parameter. This parameter may be thought of as a bit-wise
+MASK for the UNIX modes of a file. Any bit \fBnot\fR
+set here will be removed from the modes set on a file when it is
+created.
+
+The default value of this parameter removes the
+\&'group' and 'other' write and execute bits from the UNIX modes.
+
+Following this Samba will bit-wise 'OR' the UNIX mode created
+from this parameter with the value of the \fIforce create mode\fR
+parameter which is set to 000 by default.
+
+This parameter does not affect directory modes. See the
+parameter \fIdirectory mode
+\fRfor details.
+
+See also the \fIforce
+create mode\fR parameter for forcing particular mode
+bits to be set on created files. See also the \fIdirectory mode\fR parameter for masking
+mode bits on created directories. See also the \fIinherit permissions\fR parameter.
+
+Note that this parameter does not apply to permissions
+set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+a mask on access control lists also, they need to set the \fIsecurity mask\fR.
+
+Default: \fBcreate mask = 0744\fR
+
+Example: \fBcreate mask = 0775\fR
+.TP
+\fBcreate mode (S)\fR
+This is a synonym for \fI create mask\fR.
+.TP
+\fBdeadtime (G)\fR
+The value of the parameter (a decimal integer)
+represents the number of minutes of inactivity before a connection
+is considered dead, and it is disconnected. The deadtime only takes
+effect if the number of open files is zero.
+
+This is useful to stop a server's resources being
+exhausted by a large number of inactive connections.
+
+Most clients have an auto-reconnect feature when a
+connection is broken so in most cases this parameter should be
+transparent to users.
+
+Using this parameter with a timeout of a few minutes
+is recommended for most systems.
+
+A deadtime of zero indicates that no auto-disconnection
+should be performed.
+
+Default: \fBdeadtime = 0\fR
+
+Example: \fBdeadtime = 15\fR
+.TP
+\fBdebug hires timestamp (G)\fR
+Sometimes the timestamps in the log messages
+are needed with a resolution of higher that seconds, this
+boolean parameter adds microsecond resolution to the timestamp
+message header when turned on.
+
+Note that the parameter \fI debug timestamp\fR must be on for this to have an
+effect.
+
+Default: \fBdebug hires timestamp = no\fR
+.TP
+\fBdebug pid (G)\fR
+When using only one log file for more then one
+forked smbd-process there may be hard to follow which process
+outputs which message. This boolean parameter is adds the process-id
+to the timestamp message headers in the logfile when turned on.
+
+Note that the parameter \fI debug timestamp\fR must be on for this to have an
+effect.
+
+Default: \fBdebug pid = no\fR
+.TP
+\fBdebug timestamp (G)\fR
+Samba 2.2 debug log messages are timestamped
+by default. If you are running at a high \fIdebug level\fR these timestamps
+can be distracting. This boolean parameter allows timestamping
+to be turned off.
+
+Default: \fBdebug timestamp = yes\fR
+.TP
+\fBdebug uid (G)\fR
+Samba is sometimes run as root and sometime
+run as the connected user, this boolean parameter inserts the
+current euid, egid, uid and gid to the timestamp message headers
+in the log file if turned on.
+
+Note that the parameter \fI debug timestamp\fR must be on for this to have an
+effect.
+
+Default: \fBdebug uid = no\fR
+.TP
+\fBdebuglevel (G)\fR
+Synonym for \fI log level\fR.
+.TP
+\fBdefault (G)\fR
+A synonym for \fI default service\fR.
+.TP
+\fBdefault case (S)\fR
+See the section on NAME MANGLING. Also note the \fIshort preserve case\fR parameter.
+
+Default: \fBdefault case = lower\fR
+.TP
+\fBdefault service (G)\fR
+This parameter specifies the name of a service
+which will be connected to if the service actually requested cannot
+be found. Note that the square brackets are \fBNOT\fR
+given in the parameter value (see example below).
+
+There is no default value for this parameter. If this
+parameter is not given, attempting to connect to a nonexistent
+service results in an error.
+
+Typically the default service would be a \fIguest ok\fR, \fIread-only\fR service.
+
+Also note that the apparent service name will be changed
+to equal that of the requested service, this is very useful as it
+allows you to use macros like \fI%S\fR to make
+a wildcard service.
+
+Note also that any "_" characters in the name of the service
+used in the default service will get mapped to a "/". This allows for
+interesting things.
+
+Example:
+
+.sp
+.nf
+[global]
+ default service = pub
- [pub]
- path = /%S
-
-
-.SS deny hosts (S)
-A synonym for this parameter is 'hosts deny'.
-
-The opposite of 'allow hosts' - hosts listed here are NOT permitted
-access to services unless the specific services have their own lists to
-override this one. Where the lists conflict, the 'allow' list takes precedence.
-
-.B Default:
- none (ie., no hosts specifically excluded)
-
-.B Example:
- deny hosts = 150.203.4. badhost.mynet.edu.au
-.SS dfree command (G)
-The dfree command setting should only be used on systems where a
-problem occurs with the internal disk space calculations. This has
-been known to happen with Ultrix, but may occur with other operating
-systems. The symptom that was seen was an error of "Abort Retry
-Ignore" at the end of each directory listing.
+[pub]
+ path = /%S
+
+.sp
+.fi
+.TP
+\fBdelete printer command (G)\fR
+With the introduction of MS-RPC based printer
+support for Windows NT/2000 clients in Samba 2.2, it is now
+possible to delete printer at run time by issuing the
+DeletePrinter() RPC call.
+
+For a Samba host this means that the printer must be
+physically deleted from underlying printing system. The \fI deleteprinter command\fR defines a script to be run which
+will perform the necessary operations for removing the printer
+from the print system and from \fIsmb.conf\fR.
+
+The \fIdelete printer command\fR is
+automatically called with only one parameter: \fI "printer name"\fR.
+
+Once the \fIdelete printer command\fR has
+been executed, \fBsmbd\fR will reparse the \fI smb.conf\fR to associated printer no longer exists.
+If the sharename is still valid, then \fBsmbd
+\fRwill return an ACCESS_DENIED error to the client.
+
+See also \fI add printer command\fR, \fIprinting\fR,
+\fIshow add
+printer wizard\fR
+
+Default: \fBnone\fR
+
+Example: \fBdeleteprinter command = /usr/bin/removeprinter
+\fR.TP
+\fBdelete readonly (S)\fR
+This parameter allows readonly files to be deleted.
+This is not normal DOS semantics, but is allowed by UNIX.
+
+This option may be useful for running applications such
+as rcs, where UNIX file ownership prevents changing file
+permissions, and DOS semantics prevent deletion of a read only file.
+
+Default: \fBdelete readonly = no\fR
+.TP
+\fBdelete share command (G)\fR
+Samba 2.2.0 introduced the ability to dynamically
+add and delete shares via the Windows NT 4.0 Server Manager. The
+\fIdelete share command\fR is used to define an
+external program or script which will remove an existing service
+definition from \fIsmb.conf\fR. In order to successfully
+execute the \fIdelete share command\fR, \fBsmbd\fR
+requires that the administrator be connected using a root account (i.e.
+uid == 0).
+
+When executed, \fBsmbd\fR will automatically invoke the
+\fIdelete share command\fR with two parameters.
+.RS
+.TP 0.2i
+\(bu
+\fIconfigFile\fR - the location
+of the global \fIsmb.conf\fR file.
+.TP 0.2i
+\(bu
+\fIshareName\fR - the name of
+the existing service.
+.RE
+.PP
+This parameter is only used to remove file shares. To delete printer shares,
+see the \fIdelete printer
+command\fR.
+.PP
+.PP
+See also \fIadd share
+command\fR, \fIchange
+share command\fR.
+.PP
+.PP
+Default: \fBnone\fR
+.PP
+.PP
+Example: \fBdelete share command = /usr/local/bin/delshare\fR
+.PP
+.TP
+\fBdelete user script (G)\fR
+This is the full pathname to a script that will
+be run \fBAS ROOT\fR by \fBsmbd(8)\fRunder special circumstances
+described below.
+
+Normally, a Samba server requires that UNIX users are
+created for all users accessing files on this server. For sites
+that use Windows NT account databases as their primary user database
+creating these users and keeping the user list in sync with the
+Windows NT PDC is an onerous task. This option allows \fB smbd\fR to delete the required UNIX users \fBON
+DEMAND\fR when a user accesses the Samba server and the
+Windows NT user no longer exists.
+
+In order to use this option, \fBsmbd\fR must be
+set to \fIsecurity = domain\fR and \fIdelete
+user script\fR must be set to a full pathname for a script
+that will delete a UNIX user given one argument of \fI%u
+\fR, which expands into the UNIX user name to delete.
+\fBNOTE\fR that this is different to the \fIadd user script\fR
+which will work with the \fIsecurity = server\fR option
+as well as \fIsecurity = domain\fR. The reason for this
+is only when Samba is a domain member does it get the information
+on an attempted user logon that a user no longer exists. In the
+\fIsecurity = server\fR mode a missing user
+is treated the same as an invalid password logon attempt. Deleting
+the user in this circumstance would not be a good idea.
+
+When the Windows user attempts to access the Samba server,
+at \fBlogin\fR (session setup in the SMB protocol)
+time, \fBsmbd\fR contacts the \fIpassword server\fR and attempts to authenticate
+the given user with the given password. If the authentication fails
+with the specific Domain error code meaning that the user no longer
+exists then \fBsmbd\fR attempts to find a UNIX user in
+the UNIX password database that matches the Windows user account. If
+this lookup succeeds, and \fIdelete user script\fR is
+set then \fBsmbd\fR will all the specified script
+\fBAS ROOT\fR, expanding any \fI%u\fR
+argument to be the user name to delete.
+
+This script should delete the given UNIX username. In this way,
+UNIX users are dynamically deleted to match existing Windows NT
+accounts.
+
+See also security = domain,
+\fIpassword server\fR
+, \fIadd user script\fR
+\&.
+
+Default: \fBdelete user script = <empty string>
+\fR
+Example: \fBdelete user script = /usr/local/samba/bin/del_user
+%u\fR
+.TP
+\fBdelete veto files (S)\fR
+This option is used when Samba is attempting to
+delete a directory that contains one or more vetoed directories
+(see the \fIveto files\fR
+option). If this option is set to false (the default) then if a vetoed
+directory contains any non-vetoed files or directories then the
+directory delete will fail. This is usually what you want.
+
+If this option is set to true, then Samba
+will attempt to recursively delete any files and directories within
+the vetoed directory. This can be useful for integration with file
+serving systems such as NetAtalk which create meta-files within
+directories you might normally veto DOS/Windows users from seeing
+(e.g. \fI.AppleDouble\fR)
+
+Setting \fBdelete veto files = yes\fR allows these
+directories to be transparently deleted when the parent directory
+is deleted (so long as the user has permissions to do so).
+
+See also the \fIveto
+files\fR parameter.
+
+Default: \fBdelete veto files = no\fR
+.TP
+\fBdeny hosts (S)\fR
+Synonym for \fIhosts
+deny\fR.
+.TP
+\fBdfree command (G)\fR
+The \fIdfree command\fR setting should
+only be used on systems where a problem occurs with the internal
+disk space calculations. This has been known to happen with Ultrix,
+but may occur with other operating systems. The symptom that was
+seen was an error of "Abort Retry Ignore" at the end of each
+directory listing.
This setting allows the replacement of the internal routines to
calculate the total disk space and amount available with an external
routine. The example below gives a possible script that might fulfill
-this function.
-
-The external program will be passed a single parameter indicating a
-directory in the filesystem being queried. This will typically consist
-of the string "./". The script should return two integers in ascii. The
-first should be the total disk space in blocks, and the second should
-be the number of available blocks. An optional third return value
-can give the block size in bytes. The default blocksize is 1024 bytes.
-
-Note: Your script should NOT be setuid or setgid and should be owned by
-(and writable only by) root!
-
-.B Default:
- By default internal routines for determining the disk capacity
-and remaining space will be used.
-
-.B Example:
- dfree command = /usr/local/smb/dfree
-
- Where the script dfree (which must be made executable) could be
-
- #!/bin/sh
- df $1 | tail -1 | awk '{print $2" "$4}'
-
- or perhaps (on Sys V)
-
- #!/bin/sh
- /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
-
-
- Note that you may have to replace the command names with full
-path names on some systems.
-.SS directory (S)
-See
-.B path.
-.SS dont descend (S)
-There are certain directories on some systems (eg., the /proc tree under
-Linux) that are either not of interest to clients or are infinitely deep
-(recursive). This parameter allows you to specify a comma-delimited list
-of directories that the server should always show as empty.
-
-Note that Samba can be very fussy about the exact format of the "dont
-descend" entries. For example you ma need "./proc" instead of just
-"/proc". Experimentation is the best policy :-)
-
-.B Default:
- none (ie., all directories are OK to descend)
-
-.B Example:
- dont descend = /proc,/dev
-
-.SS encrypt passwords (G)
-
-This boolean controls whether encrypted passwords will be negotiated
-with the cient. Note that this option has no effect if you haven't
-compiled in the necessary des libraries and encryption code. It
-defaults to no.
-
-.SS exec (S)
-
-This is an alias for preexec
-
-
-.SS force group (S)
-This specifies a group name that all connections to this service
-should be made as. This may be useful for sharing files.
-
-.B Default:
- no forced group
-
-.B Example:
- force group = agroup
-
-.SS force user (S)
-This specifies a user name that all connections to this service
-should be made as. This may be useful for sharing files. You should
-also use it carefully as using it incorrectly can cause security
-problems.
-
-This user name only gets used once a connection is established. Thus
-clients still need to connect as a valid user and supply a valid
-password. Once connected, all file operations will be performed as the
-"forced user", not matter what username the client connected as.
-
-.B Default:
- no forced user
-
-.B Example:
- force user = auser
+this function.
+
+The external program will be passed a single parameter indicating
+a directory in the filesystem being queried. This will typically consist
+of the string \fI./\fR. The script should return two
+integers in ASCII. The first should be the total disk space in blocks,
+and the second should be the number of available blocks. An optional
+third return value can give the block size in bytes. The default
+blocksize is 1024 bytes.
+
+Note: Your script should \fBNOT\fR be setuid or
+setgid and should be owned by (and writeable only by) root!
+
+Default: \fBBy default internal routines for
+determining the disk capacity and remaining space will be used.
+\fR
+Example: \fBdfree command = /usr/local/samba/bin/dfree
+\fR
+Where the script dfree (which must be made executable) could be:
+
+.sp
+.nf
+
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+
+.sp
+.fi
+
+or perhaps (on Sys V based systems):
+
+.sp
+.nf
+
+ #!/bin/sh
+ /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
+
+.sp
+.fi
+
+Note that you may have to replace the command names
+with full path names on some systems.
+.TP
+\fBdirectory (S)\fR
+Synonym for \fIpath
+\fR\&.
+.TP
+\fBdirectory mask (S)\fR
+This parameter is the octal modes which are
+used when converting DOS modes to UNIX modes when creating UNIX
+directories.
+
+When a directory is created, the necessary permissions are
+calculated according to the mapping from DOS modes to UNIX permissions,
+and the resulting UNIX mode is then bit-wise 'AND'ed with this
+parameter. This parameter may be thought of as a bit-wise MASK for
+the UNIX modes of a directory. Any bit \fBnot\fR set
+here will be removed from the modes set on a directory when it is
+created.
+
+The default value of this parameter removes the 'group'
+and 'other' write bits from the UNIX mode, allowing only the
+user who owns the directory to modify it.
+
+Following this Samba will bit-wise 'OR' the UNIX mode
+created from this parameter with the value of the \fIforce directory mode
+\fRparameter. This parameter is set to 000 by
+default (i.e. no extra mode bits are added).
+
+Note that this parameter does not apply to permissions
+set by Windows NT/2000 ACL editors. If the administrator wishes to enforce
+a mask on access control lists also, they need to set the \fIdirectory security mask\fR.
+
+See the \fIforce
+directory mode\fR parameter to cause particular mode
+bits to always be set on created directories.
+
+See also the \fIcreate mode
+\fRparameter for masking mode bits on created files,
+and the \fIdirectory
+security mask\fR parameter.
+
+Also refer to the \fI inherit permissions\fR parameter.
+
+Default: \fBdirectory mask = 0755\fR
+
+Example: \fBdirectory mask = 0775\fR
+.TP
+\fBdirectory mode (S)\fR
+Synonym for \fI directory mask\fR
+.TP
+\fBdirectory security mask (S)\fR
+This parameter controls what UNIX permission bits
+can be modified when a Windows NT client is manipulating the UNIX
+permission on a directory using the native NT security dialog
+box.
+
+This parameter is applied as a mask (AND'ed with) to
+the changed permission bits, thus preventing any bits not in
+this mask from being modified. Essentially, zero bits in this
+mask may be treated as a set of bits the user is not allowed
+to change.
+
+If not set explicitly this parameter is set to 0777
+meaning a user is allowed to modify all the user/group/world
+permissions on a directory.
+
+\fBNote\fR that users who can access the
+Samba server through other means can easily bypass this restriction,
+so it is primarily useful for standalone "appliance" systems.
+Administrators of most normal systems will probably want to leave
+it as the default of 0777.
+
+See also the \fI force directory security mode\fR, \fIsecurity mask\fR,
+\fIforce security mode
+\fRparameters.
+
+Default: \fBdirectory security mask = 0777\fR
+
+Example: \fBdirectory security mask = 0700\fR
+.TP
+\fBdisable spoolss (G)\fR
+Enabling this parameter will disables Samba's support
+for the SPOOLSS set of MS-RPC's and will yield identical behavior
+as Samba 2.0.x. Windows NT/2000 clients will downgrade to using
+Lanman style printing commands. Windows 9x/ME will be uneffected by
+the parameter. However, this will also disable the ability to upload
+printer drivers to a Samba server via the Windows NT Add Printer
+Wizard or by using the NT printer properties dialog window. It will
+also disable the capability of Windows NT/2000 clients to download
+print drivers from the Samba host upon demand.
+\fBBe very careful about enabling this parameter.\fR
+
+See also use client driver
+
+Default : \fBdisable spoolss = no\fR
+.TP
+\fBdns proxy (G)\fR
+Specifies that nmbd(8)
+when acting as a WINS server and finding that a NetBIOS name has not
+been registered, should treat the NetBIOS name word-for-word as a DNS
+name and do a lookup with the DNS server for that name on behalf of
+the name-querying client.
+
+Note that the maximum length for a NetBIOS name is 15
+characters, so the DNS name (or DNS alias) can likewise only be
+15 characters, maximum.
+
+\fBnmbd\fR spawns a second copy of itself to do the
+DNS name lookup requests, as doing a name lookup is a blocking
+action.
+
+See also the parameter \fI wins support\fR.
+
+Default: \fBdns proxy = yes\fR
+.TP
+\fBdomain admin group (G)\fR
+This parameter is intended as a temporary solution
+to enable users to be a member of the "Domain Admins" group when
+a Samba host is acting as a PDC. A complete solution will be provided
+by a system for mapping Windows NT/2000 groups onto UNIX groups.
+Please note that this parameter has a somewhat confusing name. It
+accepts a list of usernames and of group names in standard
+\fIsmb.conf\fR notation.
+
+See also \fIdomain
+guest group\fR, \fIdomain
+logons\fR
+
+Default: \fBno domain administrators\fR
+
+Example: \fBdomain admin group = root @wheel\fR
+.TP
+\fBdomain guest group (G)\fR
+This parameter is intended as a temporary solution
+to enable users to be a member of the "Domain Guests" group when
+a Samba host is acting as a PDC. A complete solution will be provided
+by a system for mapping Windows NT/2000 groups onto UNIX groups.
+Please note that this parameter has a somewhat confusing name. It
+accepts a list of usernames and of group names in standard
+\fIsmb.conf\fR notation.
+
+See also \fIdomain
+admin group\fR, \fIdomain
+logons\fR
+
+Default: \fBno domain guests\fR
+
+Example: \fBdomain guest group = nobody @guest\fR
+.TP
+\fBdomain logons (G)\fR
+If set to true, the Samba server will serve
+Windows 95/98 Domain logons for the \fIworkgroup\fR it is in. Samba 2.2 also
+has limited capability to act as a domain controller for Windows
+NT 4 Domains. For more details on setting up this feature see
+the Samba-PDC-HOWTO included in the \fIhtmldocs/\fR
+directory shipped with the source code.
+
+Default: \fBdomain logons = no\fR
+.TP
+\fBdomain master (G)\fR
+Tell \fB nmbd(8)\fRto enable WAN-wide browse list
+collation. Setting this option causes \fBnmbd\fR to
+claim a special domain specific NetBIOS name that identifies
+it as a domain master browser for its given \fIworkgroup\fR. Local master browsers
+in the same \fIworkgroup\fR on broadcast-isolated
+subnets will give this \fBnmbd\fR their local browse lists,
+and then ask \fBsmbd(8)\fR
+for a complete copy of the browse list for the whole wide area
+network. Browser clients will then contact their local master browser,
+and will receive the domain-wide browse list, instead of just the list
+for their broadcast-isolated subnet.
+
+Note that Windows NT Primary Domain Controllers expect to be
+able to claim this \fIworkgroup\fR specific special
+NetBIOS name that identifies them as domain master browsers for
+that \fIworkgroup\fR by default (i.e. there is no
+way to prevent a Windows NT PDC from attempting to do this). This
+means that if this parameter is set and \fBnmbd\fR claims
+the special name for a \fIworkgroup\fR before a Windows
+NT PDC is able to do so then cross subnet browsing will behave
+strangely and may fail.
+
+If \fBdomain logons = yes\fR
+, then the default behavior is to enable the \fIdomain
+master\fR parameter. If \fIdomain logons\fR is
+not enabled (the default setting), then neither will \fIdomain
+master\fR be enabled by default.
+
+Default: \fBdomain master = auto\fR
+.TP
+\fBdont descend (S)\fR
+There are certain directories on some systems
+(e.g., the \fI/proc\fR tree under Linux) that are either not
+of interest to clients or are infinitely deep (recursive). This
+parameter allows you to specify a comma-delimited list of directories
+that the server should always show as empty.
+
+Note that Samba can be very fussy about the exact format
+of the "dont descend" entries. For example you may need \fI ./proc\fR instead of just \fI/proc\fR.
+Experimentation is the best policy :-)
+
+Default: \fBnone (i.e., all directories are OK
+to descend)\fR
+
+Example: \fBdont descend = /proc,/dev\fR
+.TP
+\fBdos filemode (S)\fR
+The default behavior in Samba is to provide
+UNIX-like behavior where only the owner of a file/directory is
+able to change the permissions on it. However, this behavior
+is often confusing to DOS/Windows users. Enabling this parameter
+allows a user who has write access to the file (by whatever
+means) to modify the permissions on it. Note that a user
+belonging to the group owning the file will not be allowed to
+change permissions if the group is only granted read access.
+Ownership of the file/directory is not changed, only the permissions
+are modified.
+
+Default: \fBdos filemode = no\fR
+.TP
+\fBdos filetime resolution (S)\fR
+Under the DOS and Windows FAT filesystem, the finest
+granularity on time resolution is two seconds. Setting this parameter
+for a share causes Samba to round the reported time down to the
+nearest two second boundary when a query call that requires one second
+resolution is made to \fBsmbd(8)\fR
+.
+
+This option is mainly used as a compatibility option for Visual
+C++ when used against Samba shares. If oplocks are enabled on a
+share, Visual C++ uses two different time reading calls to check if a
+file has changed since it was last read. One of these calls uses a
+one-second granularity, the other uses a two second granularity. As
+the two second call rounds any odd second down, then if the file has a
+timestamp of an odd number of seconds then the two timestamps will not
+match and Visual C++ will keep reporting the file has changed. Setting
+this option causes the two timestamps to match, and Visual C++ is
+happy.
+
+Default: \fBdos filetime resolution = no\fR
+.TP
+\fBdos filetimes (S)\fR
+Under DOS and Windows, if a user can write to a
+file they can change the timestamp on it. Under POSIX semantics,
+only the owner of the file or root may change the timestamp. By
+default, Samba runs with POSIX semantics and refuses to change the
+timestamp on a file if the user \fBsmbd\fR is acting
+on behalf of is not the file owner. Setting this option to true allows DOS semantics and smbdwill change the file
+timestamp as DOS requires.
+
+Default: \fBdos filetimes = no\fR
+.TP
+\fBencrypt passwords (G)\fR
+This boolean controls whether encrypted passwords
+will be negotiated with the client. Note that Windows NT 4.0 SP3 and
+above and also Windows 98 will by default expect encrypted passwords
+unless a registry entry is changed. To use encrypted passwords in
+Samba see the file ENCRYPTION.txt in the Samba documentation
+directory \fIdocs/\fR shipped with the source code.
+
+In order for encrypted passwords to work correctly
+\fBsmbd(8)\fRmust either
+have access to a local \fIsmbpasswd(5)
+\fRprogram for information on how to set up
+and maintain this file), or set the security = [server|domain] parameter which
+causes \fBsmbd\fR to authenticate against another
+server.
-.SS guest account (S)
-This is a username which will be used for access to services which are
-specified as 'guest ok' (see below). Whatever privileges this user has
-will be available to any client connecting to the guest
-service. Typically this user will exist in the password file, but will
-not have a valid login. If a username is specified in a given service,
+Default: \fBencrypt passwords = no\fR
+.TP
+\fBenhanced browsing (G)\fR
+This option enables a couple of enhancements to
+cross-subnet browse propagation that have been added in Samba
+but which are not standard in Microsoft implementations.
+
+The first enhancement to browse propagation consists of a regular
+wildcard query to a Samba WINS server for all Domain Master Browsers,
+followed by a browse synchronization with each of the returned
+DMBs. The second enhancement consists of a regular randomised browse
+synchronization with all currently known DMBs.
+
+You may wish to disable this option if you have a problem with empty
+workgroups not disappearing from browse lists. Due to the restrictions
+of the browse protocols these enhancements can cause a empty workgroup
+to stay around forever which can be annoying.
+
+In general you should leave this option enabled as it makes
+cross-subnet browse propagation much more reliable.
+
+Default: \fBenhanced browsing = yes\fR
+.TP
+\fBenumports command (G)\fR
+The concept of a "port" is fairly foreign
+to UNIX hosts. Under Windows NT/2000 print servers, a port
+is associated with a port monitor and generally takes the form of
+a local port (i.e. LPT1:, COM1:, FILE:) or a remote port
+(i.e. LPD Port Monitor, etc...). By default, Samba has only one
+port defined--"Samba Printer Port". Under
+Windows NT/2000, all printers must have a valid port name.
+If you wish to have a list of ports displayed (\fBsmbd
+\fRdoes not use a port name for anything) other than
+the default "Samba Printer Port", you
+can define \fIenumports command\fR to point to
+a program which should generate a list of ports, one per line,
+to standard output. This listing will then be used in response
+to the level 1 and 2 EnumPorts() RPC.
+
+Default: \fBno enumports command\fR
+
+Example: \fBenumports command = /usr/bin/listports
+\fR.TP
+\fBexec (S)\fR
+This is a synonym for \fIpreexec\fR.
+.TP
+\fBfake directory create times (S)\fR
+NTFS and Windows VFAT file systems keep a create
+time for all files and directories. This is not the same as the
+ctime - status change time - that Unix keeps, so Samba by default
+reports the earliest of the various times Unix does keep. Setting
+this parameter for a share causes Samba to always report midnight
+1-1-1980 as the create time for directories.
+
+This option is mainly used as a compatibility option for
+Visual C++ when used against Samba shares. Visual C++ generated
+makefiles have the object directory as a dependency for each object
+file, and a make rule to create the directory. Also, when NMAKE
+compares timestamps it uses the creation time when examining a
+directory. Thus the object directory will be created if it does not
+exist, but once it does exist it will always have an earlier
+timestamp than the object files it contains.
+
+However, Unix time semantics mean that the create time
+reported by Samba will be updated whenever a file is created or
+or deleted in the directory. NMAKE finds all object files in
+the object directory. The timestamp of the last one built is then
+compared to the timestamp of the object directory. If the
+directory's timestamp if newer, then all object files
+will be rebuilt. Enabling this option
+ensures directories always predate their contents and an NMAKE build
+will proceed as expected.
+
+Default: \fBfake directory create times = no\fR
+.TP
+\fBfake oplocks (S)\fR
+Oplocks are the way that SMB clients get permission
+from a server to locally cache file operations. If a server grants
+an oplock (opportunistic lock) then the client is free to assume
+that it is the only one accessing the file and it will aggressively
+cache file data. With some oplock types the client may even cache
+file open/close operations. This can give enormous performance benefits.
+
+When you set \fBfake oplocks = yes\fR, \fBsmbd(8)\fRwill
+always grant oplock requests no matter how many clients are using
+the file.
+
+It is generally much better to use the real \fIoplocks\fR support rather
+than this parameter.
+
+If you enable this option on all read-only shares or
+shares that you know will only be accessed from one client at a
+time such as physically read-only media like CDROMs, you will see
+a big performance improvement on many operations. If you enable
+this option on shares where multiple clients may be accessing the
+files read-write at the same time you can get data corruption. Use
+this option carefully!
+
+Default: \fBfake oplocks = no\fR
+.TP
+\fBfollow symlinks (S)\fR
+This parameter allows the Samba administrator
+to stop \fBsmbd(8)\fR
+from following symbolic links in a particular share. Setting this
+parameter to no prevents any file or directory
+that is a symbolic link from being followed (the user will get an
+error). This option is very useful to stop users from adding a
+symbolic link to \fI/etc/passwd\fR in their home
+directory for instance. However it will slow filename lookups
+down slightly.
+
+This option is enabled (i.e. \fBsmbd\fR will
+follow symbolic links) by default.
+
+Default: \fBfollow symlinks = yes\fR
+.TP
+\fBforce create mode (S)\fR
+This parameter specifies a set of UNIX mode bit
+permissions that will \fBalways\fR be set on a
+file created by Samba. This is done by bitwise 'OR'ing these bits onto
+the mode bits of a file that is being created or having its
+permissions changed. The default for this parameter is (in octal)
+000. The modes in this parameter are bitwise 'OR'ed onto the file
+mode after the mask set in the \fIcreate mask\fR
+parameter is applied.
+
+See also the parameter \fIcreate
+mask\fR for details on masking mode bits on files.
+
+See also the \fIinherit
+permissions\fR parameter.
+
+Default: \fBforce create mode = 000\fR
+
+Example: \fBforce create mode = 0755\fR
+
+would force all created files to have read and execute
+permissions set for 'group' and 'other' as well as the
+read/write/execute bits set for the 'user'.
+.TP
+\fBforce directory mode (S)\fR
+This parameter specifies a set of UNIX mode bit
+permissions that will \fBalways\fR be set on a directory
+created by Samba. This is done by bitwise 'OR'ing these bits onto the
+mode bits of a directory that is being created. The default for this
+parameter is (in octal) 0000 which will not add any extra permission
+bits to a created directory. This operation is done after the mode
+mask in the parameter \fIdirectory mask\fR is
+applied.
+
+See also the parameter \fI directory mask\fR for details on masking mode bits
+on created directories.
+
+See also the \fI inherit permissions\fR parameter.
+
+Default: \fBforce directory mode = 000\fR
+
+Example: \fBforce directory mode = 0755\fR
+
+would force all created directories to have read and execute
+permissions set for 'group' and 'other' as well as the
+read/write/execute bits set for the 'user'.
+.TP
+\fBforce directory security mode (S)\fR
+This parameter controls what UNIX permission bits
+can be modified when a Windows NT client is manipulating the UNIX
+permission on a directory using the native NT security dialog box.
+
+This parameter is applied as a mask (OR'ed with) to the
+changed permission bits, thus forcing any bits in this mask that
+the user may have modified to be on. Essentially, one bits in this
+mask may be treated as a set of bits that, when modifying security
+on a directory, the user has always set to be 'on'.
+
+If not set explicitly this parameter is 000, which
+allows a user to modify all the user/group/world permissions on a
+directory without restrictions.
+
+\fBNote\fR that users who can access the
+Samba server through other means can easily bypass this restriction,
+so it is primarily useful for standalone "appliance" systems.
+Administrators of most normal systems will probably want to leave
+it set as 0000.
+
+See also the \fI directory security mask\fR, \fIsecurity mask\fR,
+\fIforce security mode
+\fRparameters.
+
+Default: \fBforce directory security mode = 0\fR
+
+Example: \fBforce directory security mode = 700\fR
+.TP
+\fBforce group (S)\fR
+This specifies a UNIX group name that will be
+assigned as the default primary group for all users connecting
+to this service. This is useful for sharing files by ensuring
+that all access to files on service will use the named group for
+their permissions checking. Thus, by assigning permissions for this
+group to the files and directories within this service the Samba
+administrator can restrict or allow sharing of these files.
+
+In Samba 2.0.5 and above this parameter has extended
+functionality in the following way. If the group name listed here
+has a '+' character prepended to it then the current user accessing
+the share only has the primary group default assigned to this group
+if they are already assigned as a member of that group. This allows
+an administrator to decide that only users who are already in a
+particular group will create files with group ownership set to that
+group. This gives a finer granularity of ownership assignment. For
+example, the setting \fIforce group = +sys\fR means
+that only users who are already in group sys will have their default
+primary group assigned to sys when accessing this Samba share. All
+other users will retain their ordinary primary group.
+
+If the \fIforce user
+\fRparameter is also set the group specified in
+\fIforce group\fR will override the primary group
+set in \fIforce user\fR.
+
+See also \fIforce
+user\fR.
+
+Default: \fBno forced group\fR
+
+Example: \fBforce group = agroup\fR
+.TP
+\fBforce security mode (S)\fR
+This parameter controls what UNIX permission
+bits can be modified when a Windows NT client is manipulating
+the UNIX permission on a file using the native NT security dialog
+box.
+
+This parameter is applied as a mask (OR'ed with) to the
+changed permission bits, thus forcing any bits in this mask that
+the user may have modified to be on. Essentially, one bits in this
+mask may be treated as a set of bits that, when modifying security
+on a file, the user has always set to be 'on'.
+
+If not set explicitly this parameter is set to 0,
+and allows a user to modify all the user/group/world permissions on a file,
+with no restrictions.
+
+\fBNote\fR that users who can access
+the Samba server through other means can easily bypass this restriction,
+so it is primarily useful for standalone "appliance" systems.
+Administrators of most normal systems will probably want to leave
+this set to 0000.
+
+See also the \fI force directory security mode\fR,
+\fIdirectory security
+mask\fR, \fI security mask\fR parameters.
+
+Default: \fBforce security mode = 0\fR
+
+Example: \fBforce security mode = 700\fR
+.TP
+\fBforce user (S)\fR
+This specifies a UNIX user name that will be
+assigned as the default user for all users connecting to this service.
+This is useful for sharing files. You should also use it carefully
+as using it incorrectly can cause security problems.
+
+This user name only gets used once a connection is established.
+Thus clients still need to connect as a valid user and supply a
+valid password. Once connected, all file operations will be performed
+as the "forced user", no matter what username the client connected
+as. This can be very useful.
+
+In Samba 2.0.5 and above this parameter also causes the
+primary group of the forced user to be used as the primary group
+for all file activity. Prior to 2.0.5 the primary group was left
+as the primary group of the connecting user (this was a bug).
+
+See also \fIforce group
+\fR
+Default: \fBno forced user\fR
+
+Example: \fBforce user = auser\fR
+.TP
+\fBfstype (S)\fR
+This parameter allows the administrator to
+configure the string that specifies the type of filesystem a share
+is using that is reported by \fBsmbd(8)
+\fRwhen a client queries the filesystem type
+for a share. The default type is NTFS for
+compatibility with Windows NT but this can be changed to other
+strings such as Samba or FAT
+if required.
+
+Default: \fBfstype = NTFS\fR
+
+Example: \fBfstype = Samba\fR
+.TP
+\fBgetwd cache (G)\fR
+This is a tuning option. When this is enabled a
+caching algorithm will be used to reduce the time taken for getwd()
+calls. This can have a significant impact on performance, especially
+when the \fIwide links\fR
+parameter is set to false.
+
+Default: \fBgetwd cache = yes\fR
+.TP
+\fBgroup (S)\fR
+Synonym for \fIforce
+group\fR.
+.TP
+\fBguest account (S)\fR
+This is a username which will be used for access
+to services which are specified as \fI guest ok\fR (see below). Whatever privileges this
+user has will be available to any client connecting to the guest service.
+Typically this user will exist in the password file, but will not
+have a valid login. The user account "ftp" is often a good choice
+for this parameter. If a username is specified in a given service,
the specified username overrides this one.
-One some systems the account "nobody" may not be able to print. Use
-another account in this case. You should test this by trying to log in
-as your guest user (perhaps by using the "su -" command) and trying to
-print using lpr.
-
-Note that as of version 1.9 of Samba this option may be set
-differently for each service.
-
-.B Default:
- specified at compile time
-
-.B Example:
- guest account = nobody
-.SS getwd cache (G)
-This is a tuning option. When this is enabled a cacheing algorithm will
-be used to reduce the time taken for getwd() calls. This can have a
-significant impact on performance, especially when widelinks is False.
-
-.B Default:
- getwd cache = No
-
-.B Example:
- getwd cache = Yes
-.SS guest ok (S)
-See
-.B public.
-.SS guest only (S)
-If this parameter is 'yes' for a service, then only guest connections to the
-service are permitted. This parameter will have no affect if "guest ok" or
-"public" is not set for the service.
-
-See the section below on user/password validation for more information about
-this option.
-
-.B Default:
- guest only = no
-
-.B Example:
- guest only = yes
-.SS hide dot files (S)
-This is a boolean parameter that controls whether files starting with
-a dot appear as hidden files.
-
-.B Default:
- hide dot files = yes
-
-.B Example:
- hide dot files = no
-.SS hosts allow (S)
-See
-.B allow hosts.
-.SS hosts deny (S)
-See
-.B deny hosts.
-
-.SS group (S)
-This is an alias for "force group" and is only kept for compatability
-with old versions of Samba. It may be removed in future versions.
-
-.SS hosts equiv (G)
-If this global parameter is a non-null string, it specifies the name of
-a file to read for the names of hosts and users who will be allowed access
-without specifying a password.
-
-This is not be confused with
-.B allow hosts
-which is about hosts access to services and is more useful for guest services.
-.B hosts equiv
-may be useful for NT clients which will not supply passwords to samba.
-
-NOTE: The use of hosts.equiv can be a major security hole. This is
-because you are trusting the PC to supply the correct username. It is
-very easy to get a PC to supply a false username. I recommend that the
-hosts.equiv option be only used if you really know what you are doing,
-or perhaps on a home network where you trust your wife and kids :-)
-
-.B Default
- No host equivalences
-
-.B Example
- hosts equiv = /etc/hosts.equiv
-
-.SS invalid users (S)
-This is a list of users that should not be allowed to login to this
-service. This is really a "paranoid" check to absolutely ensure an
-improper setting does not breach your security.
-
-A name starting with @ is interpreted as a unix group.
-
-The current servicename is substituted for %S. This is useful in the
-[homes] section.
-
-See also "valid users"
-
-.B Default
- No invalid users
-
-.B Example
- invalid users = root fred admin @wheel
-
-.SS include (G)
-
-This allows you to inlcude one config file inside another. the file is
-included literally, as though typed in place.
-
-It takes the standard substitutions, except %u, %P and %S
-
-.SS keep alive (G)
-The value of the parameter (an integer) represents the number of seconds
-between 'keepalive' packets. If this parameter is zero, no keepalive packets
-will be sent. Keepalive packets, if sent, allow the server to tell whether a
-client is still present and responding.
-
-Keepalives should, in general, not be needed if the socket being used
-has the SO_KEEPALIVE attribute set on it (see "socket
-options"). Basically you should only use this option if you strike
-difficulties.
-
-.B Default:
- keep alive = 0
-
-.B Example:
- keep alive = 60
-.SS load printers (G)
-A boolean variable that controls whether all printers in the printcap
-will be loaded for browsing by default.
-
-.B Default:
- load printers = no
-
-.B Example:
- load printers = yes
-
-.SS lock directory (G)
-This options specifies the directory where lock files will be placed.
-The lock files are used to implement the "max connections" option.
-
-.B Default:
- lock directory = /tmp/samba
-
-.B Example:
- lock directory = /usr/local/samba/locks
-.SS locking (S)
-This controls whether or not locking will be performed by the server in
-response to lock requests from the client.
-
-If "locking = no", all lock and unlock requests will appear to succeed and
-all lock queries will indicate that the queried lock is clear.
-
-If "locking = yes", real locking will be performed by the server.
-
-This option may be particularly useful for read-only filesystems which
-do not need locking (such as cdrom drives).
-
-Be careful about disabling locking either globally or in a specific
-service, as lack of locking may result in data corruption.
-
-.B Default:
- locking = yes
-
-.B Example:
- locking = no
-
-.SS log file (G)
-
-This options allows you to override the name of the Samba log file
-(also known as the debug file).
+One some systems the default guest account "nobody" may not
+be able to print. Use another account in this case. You should test
+this by trying to log in as your guest user (perhaps by using the
+\fBsu -\fR command) and trying to print using the
+system print command such as \fBlpr(1)\fR or \fB lp(1)\fR.
+
+Default: \fBspecified at compile time, usually
+"nobody"\fR
+
+Example: \fBguest account = ftp\fR
+.TP
+\fBguest ok (S)\fR
+If this parameter is yes for
+a service, then no password is required to connect to the service.
+Privileges will be those of the \fI guest account\fR.
+
+See the section below on \fI security\fR for more information about this option.
+
+Default: \fBguest ok = no\fR
+.TP
+\fBguest only (S)\fR
+If this parameter is yes for
+a service, then only guest connections to the service are permitted.
+This parameter will have no effect if \fIguest ok\fR is not set for the service.
+
+See the section below on \fI security\fR for more information about this option.
+
+Default: \fBguest only = no\fR
+.TP
+\fBhide dot files (S)\fR
+This is a boolean parameter that controls whether
+files starting with a dot appear as hidden files.
+
+Default: \fBhide dot files = yes\fR
+.TP
+\fBhide files(S)\fR
+This is a list of files or directories that are not
+visible but are accessible. The DOS 'hidden' attribute is applied
+to any files or directories that match.
+
+Each entry in the list must be separated by a '/',
+which allows spaces to be included in the entry. '*'
+and '?' can be used to specify multiple files or directories
+as in DOS wildcards.
+
+Each entry must be a Unix path, not a DOS path and must
+not include the Unix directory separator '/'.
+
+Note that the case sensitivity option is applicable
+in hiding files.
+
+Setting this parameter will affect the performance of Samba,
+as it will be forced to check all files and directories for a match
+as they are scanned.
+
+See also \fIhide
+dot files\fR, \fI veto files\fR and \fIcase sensitive\fR.
+
+Default: \fBno file are hidden\fR
+
+Example: \fBhide files =
+/.*/DesktopFolderDB/TrashFor%m/resource.frk/\fR
+
+The above example is based on files that the Macintosh
+SMB client (DAVE) available from
+Thursby <URL:http://www.thursby.com> creates for internal use, and also still hides
+all files beginning with a dot.
+.TP
+\fBhide local users(G)\fR
+This parameter toggles the hiding of local UNIX
+users (root, wheel, floppy, etc) from remote clients.
+
+Default: \fBhide local users = no\fR
+.TP
+\fBhide unreadable (S)\fR
+This parameter prevents clients from seeing the
+existance of files that cannot be read. Defaults to off.
+
+Default: \fBhide unreadable = no\fR
+.TP
+\fBhomedir map (G)\fR
+If\fInis homedir
+\fRis true, and \fBsmbd(8)\fRis also acting
+as a Win95/98 \fIlogon server\fR then this parameter
+specifies the NIS (or YP) map from which the server for the user's
+home directory should be extracted. At present, only the Sun
+auto.home map format is understood. The form of the map is:
+
+\fBusername server:/some/file/system\fR
+
+and the program will extract the servername from before
+the first ':'. There should probably be a better parsing system
+that copes with different map formats and also Amd (another
+automounter) maps.
+
+\fBNOTE :\fRA working NIS client is required on
+the system for this option to work.
+
+See also \fInis homedir\fR
+, \fIdomain logons\fR
+\&.
+
+Default: \fBhomedir map = <empty string>\fR
+
+Example: \fBhomedir map = amd.homedir\fR
+.TP
+\fBhost msdfs (G)\fR
+This boolean parameter is only available
+if Samba has been configured and compiled with the \fB --with-msdfs\fR option. If set to yes,
+Samba will act as a Dfs server, and allow Dfs-aware clients
+to browse Dfs trees hosted on the server.
+
+See also the \fI msdfs root\fR share level parameter. For
+more information on setting up a Dfs tree on Samba,
+refer to msdfs_setup.html.
+
+Default: \fBhost msdfs = no\fR
+.TP
+\fBhosts allow (S)\fR
+A synonym for this parameter is \fIallow
+hosts\fR.
+
+This parameter is a comma, space, or tab delimited
+set of hosts which are permitted to access a service.
+
+If specified in the [global] section then it will
+apply to all services, regardless of whether the individual
+service has a different setting.
+
+You can specify the hosts by name or IP number. For
+example, you could restrict access to only the hosts on a
+Class C subnet with something like \fBallow hosts = 150.203.5.
+\fR\&. The full syntax of the list is described in the man
+page \fIhosts_access(5)\fR. Note that this man
+page may not be present on your system, so a brief description will
+be given here also.
+
+Note that the localhost address 127.0.0.1 will always
+be allowed access unless specifically denied by a \fIhosts deny\fR option.
+
+You can also specify hosts by network/netmask pairs and
+by netgroup names if your system supports netgroups. The
+\fBEXCEPT\fR keyword can also be used to limit a
+wildcard list. The following examples may provide some help:
+
+Example 1: allow all IPs in 150.203.*.*; except one
+
+\fBhosts allow = 150.203. EXCEPT 150.203.6.66\fR
-This option takes the standard substitutions, allowing you to have
-separate log files for each user or machine.
-
-.B Example:
- log file = /usr/local/samba/log.%m
-
-.SS log level (G)
-see "debug level"
-
-.SS lppause command (S)
-This parameter specifies the command to be executed on the server host in
-order to stop printing or spooling a specific print job.
-
-This command should be a program or script which takes a printer name and
-job number to pause the print job. Currently I don't know of any print
-spooler system that can do this with a simple option, except for the PPR
-system from Trinity College (ppr\-dist.trincoll.edu/pub/ppr). One way
-of implementing this is by using job priorities, where jobs having a too
-low priority wont be sent to the printer. See also the lppause command.
-
-If a %p is given then the printername is put in it's place. A %j is
-replaced with the job number (an integer).
-On HPUX (see printing=hpux), if the -p%p option is added to the lpq
-command, the job will show up with the correct status, i.e. if the job
-priority is lower than the set fence priority it will have the PAUSED
-status, whereas if the priority is equal or higher it will have the
-SPOOLED or PRINTING status.
-
-Note that it is good practice to include the absolute path in the lppause
-command as the PATH may not be available to the server.
-
-.B Default:
- Currently no default value is given to this string
-
-.B Example for HPUX:
- lppause command = /usr/bin/lpalt %p-%j -p0
-
-.SS lpq cache time (G)
-
-This controls how long lpq info will be cached for to prevent the lpq
-command being called too often. A separate cache is kept for each
-variation of the lpq command used by the system, so if you use
-different lpq commands for different users then they won't share cache
-information.
-
-The cache files are stored in /tmp/lpq.xxxx where xxxx is a hash
-of the lpq command in use.
-
-The default is 10 seconds, meaning that the cached results of a
-previous identical lpq command will be used if the cached data is less
-than 10 seconds old. A large value may be advisable if your lpq
-command is very slow.
-
-A value of 0 will disable cacheing completely.
-
-.B Default:
- lpq cache time = 10
-
-.B Example:
- lpq cache time = 30
-
-.SS lpq command (S)
-This parameter specifies the command to be executed on the server host in
-order to obtain "lpq"-style printer status information.
-
-This command should be a program or script which takes a printer name
-as its only parameter and outputs printer status information.
-
-Currently four styles of printer status information are supported;
-BSD, SYSV, AIX and HPUX. This covers most unix systems. You control
-which type is expected using the "printing =" option.
-
-Some clients (notably Windows for Workgroups) may not correctly send the
-connection number for the printer they are requesting status information
-about. To get around this, the server reports on the first printer service
-connected to by the client. This only happens if the connection number sent
-is invalid.
-
-If a %p is given then the printername is put in it's place. Otherwise
-it is placed at the end of the command.
-
-Note that it is good practice to include the absolute path in the lpq
-command as the PATH may not be available to the server.
-
-.B Default:
- depends on the setting of "printing ="
-
-.B Example:
- lpq command = /usr/bin/lpq %p
-
-.SS lpresume command (S)
-This parameter specifies the command to be executed on the server host in
-order to restart or continue printing or spooling a specific print job.
-
-This command should be a program or script which takes a printer name and
-job number to resume the print job. See also the lppause command.
-
-If a %p is given then the printername is put in it's place. A %j is
-replaced with the job number (an integer).
-
-Note that it is good practice to include the absolute path in the lpresume
-command as the PATH may not be available to the server.
-
-.B Default:
- Currently no default value is given to this string
-
-.B Example for HPUX:
- lpresume command = /usr/bin/lpalt %p-%j -p2
-
-.SS lprm command (S)
-This parameter specifies the command to be executed on the server host in
-order to delete a print job.
-
-This command should be a program or script which takes a printer name
-and job number, and deletes the print job.
-
-Currently four styles of printer control are supported; BSD, SYSV, AIX
-and HPUX. This covers most unix systems. You control which type is
-expected using the "printing =" option.
-
-If a %p is given then the printername is put in it's place. A %j is
-replaced with the job number (an integer).
-
-Note that it is good practice to include the absolute path in the lprm
-command as the PATH may not be available to the server.
-
-.B Default:
- depends on the setting of "printing ="
-
-.B Example 1:
- lprm command = /usr/bin/lprm -P%p %j
-
-.B Example 2:
- lprm command = /usr/bin/cancel %p-%j
-
-.SS magic output (S)
-This parameter specifies the name of a file which will contain output
-created by a magic script (see
-.I magic script
-below).
-
-Warning: If two clients use the same magic script in the same directory the
-output file content is undefined.
-.B Default:
- magic output = <magic script name>.out
-
-.B Example:
- magic output = myfile.txt
-.SS magic script (S)
-This parameter specifies the name of a file which, if opened, will be
-executed by the server when the file is closed. This allows a Unix script
-to be sent to the Samba host and executed on behalf of the connected user.
-
-Scripts executed in this way will be deleted upon completion, permissions
-permitting.
-
-If the script generates output, output will be sent to the file specified by
-the
-.I magic output
-parameter (see above).
-
-Note that some shells are unable to interpret scripts containing
-carriage-return-linefeed instead of linefeed as the end-of-line
-marker. Magic scripts must be executable "as is" on the host, which
-for some hosts and some shells will require filtering at the DOS end.
-
-Magic scripts are EXPERIMENTAL and should NOT be relied upon.
-.B Default:
- None. Magic scripts disabled.
-
-.B Example:
- magic script = user.csh
-.SS mangled map (S)
-This is for those who want to directly map UNIX file names which are
-not representable on DOS. The mangling of names is not always what is
-needed. In particular you may have documents with file extensiosn
-that differ between dos and unix. For example, under unix it is common
-to use .html for HTML files, whereas under dos .htm is more commonly
-used.
-
-So to map 'html' to 'htm' you put:
-
- mangled map = (*.html *.htm)
+Example 2: allow hosts that match the given network/netmask
-One very useful case is to remove the annoying ;1 off the ends of
-filenames on some CDROMS (only visible under some unixes). To do this
-use a map of (*;1 *)
+\fBhosts allow = 150.203.15.0/255.255.255.0\fR
-.B default:
- no mangled map
+Example 3: allow a couple of hosts
-.B Example:
- mangled map = (*;1 *)
+\fBhosts allow = lapland, arvidsjaur\fR
-.SS mangle case (S)
+Example 4: allow only hosts in NIS netgroup "foonet", but
+deny access from one particular host
-See the section on "NAME MANGLING"
+\fBhosts allow = @foonet\fR
-.SS mangled names (S)
-This controls whether non-DOS names under Unix should be mapped to
-DOS-compatible names ("mangled") and made visible, or whether non-DOS names
-should simply be ignored.
+\fBhosts deny = pirate\fR
-See the section on "NAME MANGLING" for details on how to control the
-mangling process.
+Note that access still requires suitable user-level passwords.
-If mangling is used then the mangling algorithm is as follows:
+See \fBtestparm(1)\fR
+for a way of testing your host access to see if it does
+what you expect.
+
+Default: \fBnone (i.e., all hosts permitted access)
+\fR
+Example: \fBallow hosts = 150.203.5. myhost.mynet.edu.au
+\fR.TP
+\fBhosts deny (S)\fR
+The opposite of \fIhosts allow\fR
+- hosts listed here are \fBNOT\fR permitted access to
+services unless the specific services have their own lists to override
+this one. Where the lists conflict, the \fIallow\fR
+list takes precedence.
+
+Default: \fBnone (i.e., no hosts specifically excluded)
+\fR
+Example: \fBhosts deny = 150.203.4. badhost.mynet.edu.au
+\fR.TP
+\fBhosts equiv (G)\fR
+If this global parameter is a non-null string,
+it specifies the name of a file to read for the names of hosts
+and users who will be allowed access without specifying a password.
+
+This is not be confused with \fIhosts allow\fR which is about hosts
+access to services and is more useful for guest services. \fI hosts equiv\fR may be useful for NT clients which will
+not supply passwords to Samba.
+
+\fBNOTE :\fR The use of \fIhosts equiv
+\fRcan be a major security hole. This is because you are
+trusting the PC to supply the correct username. It is very easy to
+get a PC to supply a false username. I recommend that the
+\fIhosts equiv\fR option be only used if you really
+know what you are doing, or perhaps on a home network where you trust
+your spouse and kids. And only if you \fBreally\fR trust
+them :-).
+
+Default: \fBno host equivalences\fR
+
+Example: \fBhosts equiv = /etc/hosts.equiv\fR
+.TP
+\fBinclude (G)\fR
+This allows you to include one config file
+inside another. The file is included literally, as though typed
+in place.
+
+It takes the standard substitutions, except \fI%u
+\fR, \fI%P\fR and \fI%S\fR.
+
+Default: \fBno file included\fR
+
+Example: \fBinclude = /usr/local/samba/lib/admin_smb.conf
+\fR.TP
+\fBinherit permissions (S)\fR
+The permissions on new files and directories
+are normally governed by \fI create mask\fR, \fIdirectory mask\fR, \fIforce create mode\fR
+and \fIforce
+directory mode\fR but the boolean inherit
+permissions parameter overrides this.
+
+New directories inherit the mode of the parent directory,
+including bits such as setgid.
+
+New files inherit their read/write bits from the parent
+directory. Their execute bits continue to be determined by
+\fImap archive\fR
+, \fImap hidden\fR
+and \fImap system\fR
+as usual.
+
+Note that the setuid bit is \fBnever\fR set via
+inheritance (the code explicitly prohibits this).
+
+This can be particularly useful on large systems with
+many users, perhaps several thousand, to allow a single [homes]
+share to be used flexibly by each user.
+
+See also \fIcreate mask
+\fR, \fI directory mask\fR, \fIforce create mode\fR and \fIforce directory mode\fR
+\&.
+
+Default: \fBinherit permissions = no\fR
+.TP
+\fBinterfaces (G)\fR
+This option allows you to override the default
+network interfaces list that Samba will use for browsing, name
+registration and other NBT traffic. By default Samba will query
+the kernel for the list of all active interfaces and use any
+interfaces except 127.0.0.1 that are broadcast capable.
+
+The option takes a list of interface strings. Each string
+can be in any of the following forms:
.RS
-- the first (up to) five alphanumeric characters before the rightmost dot of
-the filename are preserved, forced to upper case, and appear as the first (up
-to) five characters of the mangled name.
-
-- a tilde ("~") is appended to the first part of the mangled name, followed
-by a two-character unique sequence, based on the origonal root name
-(i.e., the original filename minus its final extension). The final
-extension is included in the hash calculation only if it contains any upper
-case characters or is longer than three characters.
-
-Note that the character to use may be specified using the "mangling
-char" option, if you don't like ~.
-
-- the first three alphanumeric characters of the final extension are preserved,
-forced to upper case and appear as the extension of the mangled name. The
-final extension is defined as that part of the original filename after the
-rightmost dot. If there are no dots in the filename, the mangled name will
-have no extension (except in the case of hidden files - see below).
-
-- files whose Unix name begins with a dot will be presented as DOS hidden
-files. The mangled name will be created as for other filenames, but with the
-leading dot removed and "___" as its extension regardless of actual original
-extension (that's three underscores).
+.TP 0.2i
+\(bu
+a network interface name (such as eth0).
+This may include shell-like wildcards so eth* will match
+any interface starting with the substring "eth"
+.TP 0.2i
+\(bu
+an IP address. In this case the netmask is
+determined from the list of interfaces obtained from the
+kernel
+.TP 0.2i
+\(bu
+an IP/mask pair.
+.TP 0.2i
+\(bu
+a broadcast/mask pair.
.RE
+.PP
+The "mask" parameters can either be a bit length (such
+as 24 for a C class network) or a full netmask in dotted
+decimal form.
+.PP
+.PP
+The "IP" parameters above can either be a full dotted
+decimal IP address or a hostname which will be looked up via
+the OS's normal hostname resolution mechanisms.
+.PP
+.PP
+For example, the following line:
+.PP
+.PP
+\fBinterfaces = eth0 192.168.2.10/24 192.168.3.10/255.255.255.0
+\fR.PP
+.PP
+would configure three network interfaces corresponding
+to the eth0 device and IP addresses 192.168.2.10 and 192.168.3.10.
+The netmasks of the latter two interfaces would be set to 255.255.255.0.
+.PP
+.PP
+See also \fIbind
+interfaces only\fR.
+.PP
+.PP
+Default: \fBall active interfaces except 127.0.0.1
+that are broadcast capable\fR
+.PP
+.TP
+\fBinvalid users (S)\fR
+This is a list of users that should not be allowed
+to login to this service. This is really a \fBparanoid\fR
+check to absolutely ensure an improper setting does not breach
+your security.
+
+A name starting with a '@' is interpreted as an NIS
+netgroup first (if your system supports NIS), and then as a UNIX
+group if the name was not found in the NIS netgroup database.
+
+A name starting with '+' is interpreted only
+by looking in the UNIX group database. A name starting with
+\&'&' is interpreted only by looking in the NIS netgroup database
+(this requires NIS to be working on your system). The characters
+\&'+' and '&' may be used at the start of the name in either order
+so the value \fI+&group\fR means check the
+UNIX group database, followed by the NIS netgroup database, and
+the value \fI&+group\fR means check the NIS
+netgroup database, followed by the UNIX group database (the
+same as the '@' prefix).
+
+The current servicename is substituted for \fI%S\fR.
+This is useful in the [homes] section.
+
+See also \fIvalid users
+\fR\&.
+
+Default: \fBno invalid users\fR
+
+Example: \fBinvalid users = root fred admin @wheel
+\fR.TP
+\fBkeepalive (G)\fR
+The value of the parameter (an integer) represents
+the number of seconds between \fIkeepalive\fR
+packets. If this parameter is zero, no keepalive packets will be
+sent. Keepalive packets, if sent, allow the server to tell whether
+a client is still present and responding.
+
+Keepalives should, in general, not be needed if the socket
+being used has the SO_KEEPALIVE attribute set on it (see \fIsocket options\fR).
+Basically you should only use this option if you strike difficulties.
+
+Default: \fBkeepalive = 300\fR
+
+Example: \fBkeepalive = 600\fR
+.TP
+\fBkernel oplocks (G)\fR
+For UNIXes that support kernel based \fIoplocks\fR
+(currently only IRIX and the Linux 2.4 kernel), this parameter
+allows the use of them to be turned on or off.
+
+Kernel oplocks support allows Samba \fIoplocks
+\fRto be broken whenever a local UNIX process or NFS operation
+accesses a file that \fBsmbd(8)\fR
+has oplocked. This allows complete data consistency between
+SMB/CIFS, NFS and local file access (and is a \fBvery\fR
+cool feature :-).
+
+This parameter defaults to on, but is translated
+to a no-op on systems that no not have the necessary kernel support.
+You should never need to touch this parameter.
+
+See also the \fIoplocks\fR
+and \fIlevel2 oplocks
+\fRparameters.
+
+Default: \fBkernel oplocks = yes\fR
+.TP
+\fBlanman auth (G)\fR
+This parameter determines whether or not smbdwill
+attempt to authenticate users using the LANMAN password hash.
+If disabled, only clients which support NT password hashes (e.g. Windows
+NT/2000 clients, smbclient, etc... but not Windows 95/98 or the MS DOS
+network client) will be able to connect to the Samba host.
+
+Default : \fBlanman auth = yes\fR
+.TP
+\fBlarge readwrite (G)\fR
+This parameter determines whether or not smbd
+supports the new 64k streaming read and write varient SMB requests introduced
+with Windows 2000. Note that due to Windows 2000 client redirector bugs
+this requires Samba to be running on a 64-bit capable operating system such
+as IRIX, Solaris or a Linux 2.4 kernel. Can improve performance by 10% with
+Windows 2000 clients. Defaults to off. Not as tested as some other Samba
+code paths.
+
+Default : \fBlarge readwrite = no\fR
+.TP
+\fBldap admin dn (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+The \fIldap admin dn\fR defines the Distinguished
+Name (DN) name used by Samba to contact the ldap
+server when retreiving user account information. The \fIldap
+admin dn\fR is used in conjunction with the admin dn password
+stored in the \fIprivate/secrets.tdb\fR file. See the
+\fBsmbpasswd(8)\fRman
+page for more information on how to accmplish this.
+
+Default : \fBnone\fR
+.TP
+\fBldap filter (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+This parameter specifies the RFC 2254 compliant LDAP search filter.
+The default is to match the login name with the uid
+attribute for all entries matching the sambaAccount
+objectclass. Note that this filter should only return one entry.
+
+Default : \fBldap filter = (&(uid=%u)(objectclass=sambaAccount))\fR
+.TP
+\fBldap port (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+This option is used to control the tcp port number used to contact
+the \fIldap server\fR.
+The default is to use the stand LDAP port 389.
+
+Default : \fBldap port = 389\fR
+.TP
+\fBldap server (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+This parameter should contains the FQDN of the ldap directory
+server which should be queried to locate user account information.
+
+Default : \fBldap server = localhost\fR
+.TP
+\fBldap ssl (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+This option is used to define whether or not Samba should
+use SSL when connecting to the \fIldap
+server\fR. This is \fBNOT\fR related to
+Samba SSL support which is enabled by specifying the
+\fB--with-ssl\fR option to the \fIconfigure\fR
+script (see \fIssl\fR).
+
+The \fIldap ssl\fR can be set to one of three values:
+(a) \fBon\fR - Always use SSL when contacting the
+\fIldap server\fR, (b) \fBoff\fR -
+Never use SSL when querying the directory, or (c) \fBstart
+tls\fR - Use the LDAPv3 StartTLS extended operation
+(RFC2830) for communicating with the directory server.
+
+Default : \fBldap ssl = off\fR
+.TP
+\fBldap suffix (G)\fR
+This parameter is only available if Samba has been
+configure to include the \fB--with-ldapsam\fR option
+at compile time. This option should be considered experimental and
+under active development.
+
+Default : \fBnone\fR
+.TP
+\fBlevel2 oplocks (S)\fR
+This parameter controls whether Samba supports
+level2 (read-only) oplocks on a share.
+
+Level2, or read-only oplocks allow Windows NT clients
+that have an oplock on a file to downgrade from a read-write oplock
+to a read-only oplock once a second client opens the file (instead
+of releasing all oplocks on a second open, as in traditional,
+exclusive oplocks). This allows all openers of the file that
+support level2 oplocks to cache the file for read-ahead only (ie.
+they may not cache writes or lock requests) and increases performance
+for many accesses of files that are not commonly written (such as
+application .EXE files).
+
+Once one of the clients which have a read-only oplock
+writes to the file all clients are notified (no reply is needed
+or waited for) and told to break their oplocks to "none" and
+delete any read-ahead caches.
+
+It is recommended that this parameter be turned on
+to speed access to shared executables.
+
+For more discussions on level2 oplocks see the CIFS spec.
+
+Currently, if \fIkernel
+oplocks\fR are supported then level2 oplocks are
+not granted (even if this parameter is set to yes).
+Note also, the \fIoplocks\fR
+parameter must be set to true on this share in order for
+this parameter to have any effect.
+
+See also the \fIoplocks\fR
+and \fIkernel oplocks\fR
+parameters.
+
+Default: \fBlevel2 oplocks = yes\fR
+.TP
+\fBlm announce (G)\fR
+This parameter determines if \fBnmbd(8)\fRwill produce Lanman announce
+broadcasts that are needed by OS/2 clients in order for them to see
+the Samba server in their browse list. This parameter can have three
+values, true, false, or
+auto. The default is auto.
+If set to false Samba will never produce these
+broadcasts. If set to true Samba will produce
+Lanman announce broadcasts at a frequency set by the parameter
+\fIlm interval\fR. If set to auto
+Samba will not send Lanman announce broadcasts by default but will
+listen for them. If it hears such a broadcast on the wire it will
+then start sending them at a frequency set by the parameter
+\fIlm interval\fR.
+
+See also \fIlm interval
+\fR\&.
+
+Default: \fBlm announce = auto\fR
+
+Example: \fBlm announce = yes\fR
+.TP
+\fBlm interval (G)\fR
+If Samba is set to produce Lanman announce
+broadcasts needed by OS/2 clients (see the \fIlm announce\fR parameter) then this
+parameter defines the frequency in seconds with which they will be
+made. If this is set to zero then no Lanman announcements will be
+made despite the setting of the \fIlm announce\fR
+parameter.
+
+See also \fIlm
+announce\fR.
+
+Default: \fBlm interval = 60\fR
+
+Example: \fBlm interval = 120\fR
+.TP
+\fBload printers (G)\fR
+A boolean variable that controls whether all
+printers in the printcap will be loaded for browsing by default.
+See the printers section for
+more details.
+
+Default: \fBload printers = yes\fR
+.TP
+\fBlocal master (G)\fR
+This option allows \fB nmbd(8)\fRto try and become a local master browser
+on a subnet. If set to false then \fB nmbd\fR will not attempt to become a local master browser
+on a subnet and will also lose in all browsing elections. By
+default this value is set to true. Setting this value to true doesn't
+mean that Samba will \fBbecome\fR the local master
+browser on a subnet, just that \fBnmbd\fR will \fB participate\fR in elections for local master browser.
+
+Setting this value to false will cause \fBnmbd\fR
+\fBnever\fR to become a local master browser.
+
+Default: \fBlocal master = yes\fR
+.TP
+\fBlock dir (G)\fR
+Synonym for \fI lock directory\fR.
+.TP
+\fBlock directory (G)\fR
+This option specifies the directory where lock
+files will be placed. The lock files are used to implement the
+\fImax connections\fR
+option.
+
+Default: \fBlock directory = ${prefix}/var/locks\fR
+
+Example: \fBlock directory = /var/run/samba/locks\fR
+.TP
+\fBlocking (S)\fR
+This controls whether or not locking will be
+performed by the server in response to lock requests from the
+client.
+
+If \fBlocking = no\fR, all lock and unlock
+requests will appear to succeed and all lock queries will report
+that the file in question is available for locking.
+
+If \fBlocking = yes\fR, real locking will be performed
+by the server.
+
+This option \fBmay\fR be useful for read-only
+filesystems which \fBmay\fR not need locking (such as
+CDROM drives), although setting this parameter of no
+is not really recommended even in this case.
+
+Be careful about disabling locking either globally or in a
+specific service, as lack of locking may result in data corruption.
+You should never need to set this parameter.
+
+Default: \fBlocking = yes\fR
+.TP
+\fBlog file (G)\fR
+This option allows you to override the name
+of the Samba log file (also known as the debug file).
+
+This option takes the standard substitutions, allowing
+you to have separate log files for each user or machine.
+
+Example: \fBlog file = /usr/local/samba/var/log.%m
+\fR.TP
+\fBlog level (G)\fR
+The value of the parameter (an integer) allows
+the debug level (logging level) to be specified in the
+\fIsmb.conf\fR file. This is to give greater
+flexibility in the configuration of the system.
+
+The default will be the log level specified on
+the command line or level zero if none was specified.
+
+Example: \fBlog level = 3\fR
+.TP
+\fBlogon drive (G)\fR
+This parameter specifies the local path to
+which the home directory will be connected (see \fIlogon home\fR)
+and is only used by NT Workstations.
+
+Note that this option is only useful if Samba is set up as a
+logon server.
+
+Default: \fBlogon drive = z:\fR
+
+Example: \fBlogon drive = h:\fR
+.TP
+\fBlogon home (G)\fR
+This parameter specifies the home directory
+location when a Win95/98 or NT Workstation logs into a Samba PDC.
+It allows you to do
+
+C:\\> \fBNET USE H: /HOME\fR
+
+from a command prompt, for example.
+
+This option takes the standard substitutions, allowing
+you to have separate logon scripts for each user or machine.
+
+This parameter can be used with Win9X workstations to ensure
+that roaming profiles are stored in a subdirectory of the user's
+home directory. This is done in the following way:
+
+\fBlogon home = \\\\%N\\%U\\profile\fR
+
+This tells Samba to return the above string, with
+substitutions made when a client requests the info, generally
+in a NetUserGetInfo request. Win9X clients truncate the info to
+\\\\server\\share when a user does \fBnet use /home\fR
+but use the whole string when dealing with profiles.
+
+Note that in prior versions of Samba, the \fIlogon path\fR was returned rather than
+\fIlogon home\fR. This broke \fBnet use
+/home\fR but allowed profiles outside the home directory.
+The current implementation is correct, and can be used for
+profiles if you use the above trick.
+
+This option is only useful if Samba is set up as a logon
+server.
-The two-digit hash value consists of upper case alphanumeric characters.
-
-This algorithm can cause name collisions only if files in a directory share
-the same first five alphanumeric characters. The probability of such a clash
-is 1/1300.
-
-The name mangling (if enabled) allows a file to be copied between Unix
-directories from DOS while retaining the long Unix filename. Unix files can
-be renamed to a new extension from DOS and will retain the same basename.
-Mangled names do not change between sessions.
-
-.B Default:
- mangled names = yes
-
-.B Example:
- mangled names = no
-.SS mangling char (S)
-This controls what character is used as the "magic" character in name
-mangling. The default is a ~ but this may interfere with some
-software. Use this option to set it to whatever you prefer.
+Default: \fBlogon home = "\\\\%N\\%U"\fR
+
+Example: \fBlogon home = "\\\\remote_smb_server\\%U"\fR
+.TP
+\fBlogon path (G)\fR
+This parameter specifies the home directory
+where roaming profiles (NTuser.dat etc files for Windows NT) are
+stored. Contrary to previous versions of these manual pages, it has
+nothing to do with Win 9X roaming profiles. To find out how to
+handle roaming profiles for Win 9X system, see the \fIlogon home\fR parameter.
+
+This option takes the standard substitutions, allowing you
+to have separate logon scripts for each user or machine. It also
+specifies the directory from which the "Application Data",
+(\fIdesktop\fR, \fIstart menu\fR,
+\fInetwork neighborhood\fR, \fIprograms\fR
+and other folders, and their contents, are loaded and displayed on
+your Windows NT client.
+
+The share and the path must be readable by the user for
+the preferences and directories to be loaded onto the Windows NT
+client. The share must be writeable when the user logs in for the first
+time, in order that the Windows NT client can create the NTuser.dat
+and other directories.
+
+Thereafter, the directories and any of the contents can,
+if required, be made read-only. It is not advisable that the
+NTuser.dat file be made read-only - rename it to NTuser.man to
+achieve the desired effect (a \fBMAN\fRdatory
+profile).
+
+Windows clients can sometimes maintain a connection to
+the [homes] share, even though there is no user logged in.
+Therefore, it is vital that the logon path does not include a
+reference to the homes share (i.e. setting this parameter to
+\\%N\\%U\\profile_path will cause problems).
+
+This option takes the standard substitutions, allowing
+you to have separate logon scripts for each user or machine.
+
+Note that this option is only useful if Samba is set up
+as a logon server.
+
+Default: \fBlogon path = \\\\%N\\%U\\profile\fR
+
+Example: \fBlogon path = \\\\PROFILESERVER\\PROFILE\\%U\fR
+.TP
+\fBlogon script (G)\fR
+This parameter specifies the batch file (.bat) or
+NT command file (.cmd) to be downloaded and run on a machine when
+a user successfully logs in. The file must contain the DOS
+style CR/LF line endings. Using a DOS-style editor to create the
+file is recommended.
+
+The script must be a relative path to the [netlogon]
+service. If the [netlogon] service specifies a \fIpath\fR of \fI/usr/local/samba/netlogon
+\fR, and \fBlogon script = STARTUP.BAT\fR, then
+the file that will be downloaded is:
+
+\fI/usr/local/samba/netlogon/STARTUP.BAT\fR
+
+The contents of the batch file are entirely your choice. A
+suggested command would be to add \fBNET TIME \\\\SERVER /SET
+/YES\fR, to force every machine to synchronize clocks with
+the same time server. Another use would be to add \fBNET USE
+U: \\\\SERVER\\UTILS\fR for commonly used utilities, or \fB NET USE Q: \\\\SERVER\\ISO9001_QA\fR for example.
+
+Note that it is particularly important not to allow write
+access to the [netlogon] share, or to grant users write permission
+on the batch files in a secure environment, as this would allow
+the batch files to be arbitrarily modified and security to be
+breached.
+
+This option takes the standard substitutions, allowing you
+to have separate logon scripts for each user or machine.
+
+This option is only useful if Samba is set up as a logon
+server.
-.B Default:
- mangling char = ~
+Default: \fBno logon script defined\fR
+
+Example: \fBlogon script = scripts\\%U.bat\fR
+.TP
+\fBlppause command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to stop printing or spooling
+a specific print job.
+
+This command should be a program or script which takes
+a printer name and job number to pause the print job. One way
+of implementing this is by using job priorities, where jobs
+having a too low priority won't be sent to the printer.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. A \fI%j\fR is replaced with
+the job number (an integer). On HPUX (see \fIprinting=hpux
+\fR), if the \fI-p%p\fR option is added
+to the lpq command, the job will show up with the correct status, i.e.
+if the job priority is lower than the set fence priority it will
+have the PAUSED status, whereas if the priority is equal or higher it
+will have the SPOOLED or PRINTING status.
+
+Note that it is good practice to include the absolute path
+in the lppause command as the PATH may not be available to the server.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: Currently no default value is given to
+this string, unless the value of the \fIprinting\fR
+parameter is SYSV, in which case the default is :
+
+\fBlp -i %p-%j -H hold\fR
+
+or if the value of the \fIprinting\fR parameter
+is SOFTQ, then the default is:
+
+\fBqstat -s -j%j -h\fR
+
+Example for HPUX: \fBlppause command = /usr/bin/lpalt
+%p-%j -p0\fR
+.TP
+\fBlpq cache time (G)\fR
+This controls how long lpq info will be cached
+for to prevent the \fBlpq\fR command being called too
+often. A separate cache is kept for each variation of the \fB lpq\fR command used by the system, so if you use different
+\fBlpq\fR commands for different users then they won't
+share cache information.
+
+The cache files are stored in \fI/tmp/lpq.xxxx\fR
+where xxxx is a hash of the \fBlpq\fR command in use.
+
+The default is 10 seconds, meaning that the cached results
+of a previous identical \fBlpq\fR command will be used
+if the cached data is less than 10 seconds old. A large value may
+be advisable if your \fBlpq\fR command is very slow.
+
+A value of 0 will disable caching completely.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: \fBlpq cache time = 10\fR
+
+Example: \fBlpq cache time = 30\fR
+.TP
+\fBlpq command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to obtain \fBlpq
+\fR-style printer status information.
+
+This command should be a program or script which
+takes a printer name as its only parameter and outputs printer
+status information.
+
+Currently eight styles of printer status information
+are supported; BSD, AIX, LPRNG, PLP, SYSV, HPUX, QNX and SOFTQ.
+This covers most UNIX systems. You control which type is expected
+using the \fIprinting =\fR option.
+
+Some clients (notably Windows for Workgroups) may not
+correctly send the connection number for the printer they are
+requesting status information about. To get around this, the
+server reports on the first printer service connected to by the
+client. This only happens if the connection number sent is invalid.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. Otherwise it is placed at the end of the
+command.
-.B Example:
- mangling char = ^
+Note that it is good practice to include the absolute path
+in the \fIlpq command\fR as the \fB$PATH
+\fRmay not be available to the server.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: \fBdepends on the setting of \fI printing\fB\fR
+
+Example: \fBlpq command = /usr/bin/lpq -P%p\fR
+.TP
+\fBlpresume command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to restart or continue
+printing or spooling a specific print job.
+
+This command should be a program or script which takes
+a printer name and job number to resume the print job. See
+also the \fIlppause command
+\fRparameter.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. A \fI%j\fR is replaced with
+the job number (an integer).
+
+Note that it is good practice to include the absolute path
+in the \fIlpresume command\fR as the PATH may not
+be available to the server.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: Currently no default value is given
+to this string, unless the value of the \fIprinting\fR
+parameter is SYSV, in which case the default is :
+
+\fBlp -i %p-%j -H resume\fR
+
+or if the value of the \fIprinting\fR parameter
+is SOFTQ, then the default is:
+
+\fBqstat -s -j%j -r\fR
+
+Example for HPUX: \fBlpresume command = /usr/bin/lpalt
+%p-%j -p2\fR
+.TP
+\fBlprm command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to delete a print job.
+
+This command should be a program or script which takes
+a printer name and job number, and deletes the print job.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. A \fI%j\fR is replaced with
+the job number (an integer).
+
+Note that it is good practice to include the absolute
+path in the \fIlprm command\fR as the PATH may not be
+available to the server.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: \fBdepends on the setting of \fIprinting
+\fB\fR
+Example 1: \fBlprm command = /usr/bin/lprm -P%p %j
+\fR
+Example 2: \fBlprm command = /usr/bin/cancel %p-%j
+\fR.TP
+\fBmachine password timeout (G)\fR
+If a Samba server is a member of a Windows
+NT Domain (see the security = domain)
+parameter) then periodically a running smbd(8)process will try and change the MACHINE ACCOUNT
+PASSWORD stored in the TDB called \fIprivate/secrets.tdb
+\fR\&. This parameter specifies how often this password
+will be changed, in seconds. The default is one week (expressed in
+seconds), the same as a Windows NT Domain member server.
+
+See also \fBsmbpasswd(8)
+\fR, and the security = domain) parameter.
+
+Default: \fBmachine password timeout = 604800\fR
+.TP
+\fBmagic output (S)\fR
+This parameter specifies the name of a file
+which will contain output created by a magic script (see the
+\fImagic script\fR
+parameter below).
+
+Warning: If two clients use the same \fImagic script
+\fRin the same directory the output file content
+is undefined.
+
+Default: \fBmagic output = <magic script name>.out
+\fR
+Example: \fBmagic output = myfile.txt\fR
+.TP
+\fBmagic script (S)\fR
+This parameter specifies the name of a file which,
+if opened, will be executed by the server when the file is closed.
+This allows a UNIX script to be sent to the Samba host and
+executed on behalf of the connected user.
+
+Scripts executed in this way will be deleted upon
+completion assuming that the user has the appropriate level
+of privilege and the file permissions allow the deletion.
+
+If the script generates output, output will be sent to
+the file specified by the \fI magic output\fR parameter (see above).
+
+Note that some shells are unable to interpret scripts
+containing CR/LF instead of CR as
+the end-of-line marker. Magic scripts must be executable
+\fBas is\fR on the host, which for some hosts and
+some shells will require filtering at the DOS end.
+
+Magic scripts are \fBEXPERIMENTAL\fR and
+should \fBNOT\fR be relied upon.
+
+Default: \fBNone. Magic scripts disabled.\fR
+
+Example: \fBmagic script = user.csh\fR
+.TP
+\fBmangle case (S)\fR
+See the section on NAME MANGLING
+
+Default: \fBmangle case = no\fR
+.TP
+\fBmangled map (S)\fR
+This is for those who want to directly map UNIX
+file names which cannot be represented on Windows/DOS. The mangling
+of names is not always what is needed. In particular you may have
+documents with file extensions that differ between DOS and UNIX.
+For example, under UNIX it is common to use \fI.html\fR
+for HTML files, whereas under Windows/DOS \fI.htm\fR
+is more commonly used.
+
+So to map \fIhtml\fR to \fIhtm\fR
+you would use:
+
+\fBmangled map = (*.html *.htm)\fR
+
+One very useful case is to remove the annoying \fI;1
+\fRoff the ends of filenames on some CDROMs (only visible
+under some UNIXes). To do this use a map of (*;1 *;).
+
+Default: \fBno mangled map\fR
+
+Example: \fBmangled map = (*;1 *;)\fR
+.TP
+\fBmangled names (S)\fR
+This controls whether non-DOS names under UNIX
+should be mapped to DOS-compatible names ("mangled") and made visible,
+or whether non-DOS names should simply be ignored.
+
+See the section on NAME MANGLING for details on how to control the mangling process.
-.SS max log size (G)
+If mangling is used then the mangling algorithm is as follows:
+.RS
+.TP 0.2i
+\(bu
+The first (up to) five alphanumeric characters
+before the rightmost dot of the filename are preserved, forced
+to upper case, and appear as the first (up to) five characters
+of the mangled name.
+.TP 0.2i
+\(bu
+A tilde "~" is appended to the first part of the mangled
+name, followed by a two-character unique sequence, based on the
+original root name (i.e., the original filename minus its final
+extension). The final extension is included in the hash calculation
+only if it contains any upper case characters or is longer than three
+characters.
-This option (an integer in kilobytes) specifies the max size the log
-file should grow to. Samba periodically checks the size and if it is
-exceeded it will rename the file, adding a .old extension.
+Note that the character to use may be specified using
+the \fImangling char\fR
+option, if you don't like '~'.
+.TP 0.2i
+\(bu
+The first three alphanumeric characters of the final
+extension are preserved, forced to upper case and appear as the
+extension of the mangled name. The final extension is defined as that
+part of the original filename after the rightmost dot. If there are no
+dots in the filename, the mangled name will have no extension (except
+in the case of "hidden files" - see below).
+.TP 0.2i
+\(bu
+Files whose UNIX name begins with a dot will be
+presented as DOS hidden files. The mangled name will be created as
+for other filenames, but with the leading dot removed and "___" as
+its extension regardless of actual original extension (that's three
+underscores).
+.RE
+.PP
+The two-digit hash value consists of upper case
+alphanumeric characters.
+.PP
+.PP
+This algorithm can cause name collisions only if files
+in a directory share the same first five alphanumeric characters.
+The probability of such a clash is 1/1300.
+.PP
+.PP
+The name mangling (if enabled) allows a file to be
+copied between UNIX directories from Windows/DOS while retaining
+the long UNIX filename. UNIX files can be renamed to a new extension
+from Windows/DOS and will retain the same basename. Mangled names
+do not change between sessions.
+.PP
+.PP
+Default: \fBmangled names = yes\fR
+.PP
+.TP
+\fBmangled stack (G)\fR
+This parameter controls the number of mangled names
+that should be cached in the Samba server smbd(8).
+
+This stack is a list of recently mangled base names
+(extensions are only maintained if they are longer than 3 characters
+or contains upper case characters).
+
+The larger this value, the more likely it is that mangled
+names can be successfully converted to correct long UNIX names.
+However, large stack sizes will slow most directory accesses. Smaller
+stacks save memory in the server (each stack element costs 256 bytes).
+
+It is not possible to absolutely guarantee correct long
+filenames, so be prepared for some surprises!
+
+Default: \fBmangled stack = 50\fR
+
+Example: \fBmangled stack = 100\fR
+.TP
+\fBmangling char (S)\fR
+This controls what character is used as
+the \fBmagic\fR character in name mangling. The default is a '~'
+but this may interfere with some software. Use this option to set
+it to whatever you prefer.
+
+Default: \fBmangling char = ~\fR
+
+Example: \fBmangling char = ^\fR
+.TP
+\fBmap archive (S)\fR
+This controls whether the DOS archive attribute
+should be mapped to the UNIX owner execute bit. The DOS archive bit
+is set when a file has been modified since its last backup. One
+motivation for this option it to keep Samba/your PC from making
+any file it touches from becoming executable under UNIX. This can
+be quite annoying for shared source code, documents, etc...
+
+Note that this requires the \fIcreate mask\fR
+parameter to be set such that owner execute bit is not masked out
+(i.e. it must include 100). See the parameter \fIcreate mask\fR for details.
+
+Default: \fBmap archive = yes\fR
+.TP
+\fBmap hidden (S)\fR
+This controls whether DOS style hidden files
+should be mapped to the UNIX world execute bit.
+
+Note that this requires the \fIcreate mask\fR
+to be set such that the world execute bit is not masked out (i.e.
+it must include 001). See the parameter \fIcreate mask\fR for details.
+
+Default: \fBmap hidden = no\fR
+.TP
+\fBmap system (S)\fR
+This controls whether DOS style system files
+should be mapped to the UNIX group execute bit.
+
+Note that this requires the \fIcreate mask\fR
+to be set such that the group execute bit is not masked out (i.e.
+it must include 010). See the parameter \fIcreate mask\fR for details.
+
+Default: \fBmap system = no\fR
+.TP
+\fBmap to guest (G)\fR
+This parameter is only useful in security modes other than \fIsecurity = share\fR
+- i.e. user, server,
+and domain.
+
+This parameter can take three different values, which tell
+smbd(8)what to do with user
+login requests that don't match a valid UNIX user in some way.
+
+The three settings are :
+.RS
+.TP 0.2i
+\(bu
+Never - Means user login
+requests with an invalid password are rejected. This is the
+default.
+.TP 0.2i
+\(bu
+Bad User - Means user
+logins with an invalid password are rejected, unless the username
+does not exist, in which case it is treated as a guest login and
+mapped into the \fI guest account\fR.
+.TP 0.2i
+\(bu
+Bad Password - Means user logins
+with an invalid password are treated as a guest login and mapped
+into the guest account. Note that
+this can cause problems as it means that any user incorrectly typing
+their password will be silently logged on as "guest" - and
+will not know the reason they cannot access files they think
+they should - there will have been no message given to them
+that they got their password wrong. Helpdesk services will
+\fBhate\fR you if you set the \fImap to
+guest\fR parameter this way :-).
+.RE
+.PP
+Note that this parameter is needed to set up "Guest"
+share services when using \fIsecurity\fR modes other than
+share. This is because in these modes the name of the resource being
+requested is \fBnot\fR sent to the server until after
+the server has successfully authenticated the client so the server
+cannot make authentication decisions at the correct time (connection
+to the share) for "Guest" shares.
+.PP
+.PP
+For people familiar with the older Samba releases, this
+parameter maps to the old compile-time setting of the GUEST_SESSSETUP value in local.h.
+.PP
+.PP
+Default: \fBmap to guest = Never\fR
+.PP
+.PP
+Example: \fBmap to guest = Bad User\fR
+.PP
+.TP
+\fBmax connections (S)\fR
+This option allows the number of simultaneous
+connections to a service to be limited. If \fImax connections
+\fRis greater than 0 then connections will be refused if
+this number of connections to the service are already open. A value
+of zero mean an unlimited number of connections may be made.
+
+Record lock files are used to implement this feature. The
+lock files will be stored in the directory specified by the \fIlock directory\fR
+option.
+
+Default: \fBmax connections = 0\fR
+
+Example: \fBmax connections = 10\fR
+.TP
+\fBmax disk size (G)\fR
+This option allows you to put an upper limit
+on the apparent size of disks. If you set this option to 100
+then all shares will appear to be not larger than 100 MB in
+size.
+
+Note that this option does not limit the amount of
+data you can put on the disk. In the above case you could still
+store much more than 100 MB on the disk, but if a client ever asks
+for the amount of free disk space or the total disk size then the
+result will be bounded by the amount specified in \fImax
+disk size\fR.
+
+This option is primarily useful to work around bugs
+in some pieces of software that can't handle very large disks,
+particularly disks over 1GB in size.
+
+A \fImax disk size\fR of 0 means no limit.
+
+Default: \fBmax disk size = 0\fR
+
+Example: \fBmax disk size = 1000\fR
+.TP
+\fBmax log size (G)\fR
+This option (an integer in kilobytes) specifies
+the max size the log file should grow to. Samba periodically checks
+the size and if it is exceeded it will rename the file, adding
+a \fI.old\fR extension.
A size of 0 means no limit.
-.B Default:
- max log size = 5000
-
-.B Example:
- max log size = 1000
-
-.SS max xmit (G)
-
-This option controls the maximum packet size that will be negotiated
-by Samba. The default is 65535, which is the maximum. In some cases
-you may find you get better performance with a smaller value. A value
-below 2048 is likely to cause problems.
-
-.B Default:
- max xmit = 65535
-
-.B Example:
- max xmit = 8192
-
-.SS mangled stack (G)
-This parameter controls the number of mangled names that should be cached in
-the Samba server.
-
-This stack is a list of recently mangled base names (extensions are only
-maintained if they are longer than 3 characters or contains upper case
-characters).
-
-The larger this value, the more likely it is that mangled names can be
-successfully converted to correct long Unix names. However, large stack
-sizes will slow most directory access. Smaller stacks save memory in the
-server (each stack element costs 256 bytes).
-
-It is not possible to absolutely guarantee correct long file names, so
-be prepared for some surprises!
-
-.B Default:
- mangled stack = 50
-
-.B Example:
- mangled stack = 100
-
-.SS map archive (S)
-This controls whether the DOS archive attribute should be mapped to Unix
-execute bits. The DOS archive bit is set when a file has been modified
-since its last backup. One motivation for this option it to keep Samba/your
-PC from making any file it touches from becoming executable under UNIX.
-This can be quite annoying for shared source code, documents, etc...
-
-.B Default:
- map archive = yes
-
-.B Example:
- map archive = no
-
-.SS map hidden (S)
-This controls whether DOS style hidden files should be mapped to Unix
-execute bits.
-
-.B Default:
- map hidden = no
-
-.B Example:
- map hidden = yes
-.SS map system (S)
-This controls whether DOS style system files should be mapped to Unix
-execute bits.
-
-.B Default:
- map system = no
-
-.B Example:
- map system = yes
-.SS max connections (S)
-This option allows the number of simultaneous connections to a
-service to be limited. If "max connections" is greater than 0 then
-connections will be refused if this number of connections to the
-service are already open. A value of zero mean an unlimited number of
-connections may be made.
-
-Record lock files are used to implement this feature. The lock files
-will be stored in the directory specified by the "lock directory" option.
-
-.B Default:
- max connections = 0
-
-.B Example:
- max connections = 10
-.SS only user (S)
-This is a boolean option that controls whether connections with
-usernames not in the user= list will be allowed. By default this
-option is disabled so a client can supply a username to be used by
-the server.
-
-Note that this also means Samba won't try to deduce usernames from the
-service name. This can be annoying for the [homes] section. To get
-around this you could use "user = %S" which means your "user" list
-will be just the service name, which for home directories is the name
-of the user.
-
-.B Default:
- only user = False
-
-.B Example:
- only user = True
-
-.SS message command (G)
-
-This specifies what command to run when the server receives a WinPopup
-style message.
-
-This would normally be a command that would deliver the message
-somehow. How this is to be done is up to your imagination.
-
-What I use is:
-
- message command = csh -c 'xedit %s;rm %s' &
-
-This delivers the message using xedit, then removes it
-afterwards. NOTE THAT IT IS VERY IMPORTANT THAT THIS COMMAND RETURN
-IMMEDIATELY. That's why I have the & on the end. If it doesn't return
-immediately then your PCs may freeze when sending messages (they
-should recover after 30secs, hopefully).
-
-All messages are delivered as the global guest user. The command takes
-the standard substitutions, although %u won't work (%U may be better
+Default: \fBmax log size = 5000\fR
+
+Example: \fBmax log size = 1000\fR
+.TP
+\fBmax mux (G)\fR
+This option controls the maximum number of
+outstanding simultaneous SMB operations that Samba tells the client
+it will allow. You should never need to set this parameter.
+
+Default: \fBmax mux = 50\fR
+.TP
+\fBmax open files (G)\fR
+This parameter limits the maximum number of
+open files that one smbd(8)file
+serving process may have open for a client at any one time. The
+default for this parameter is set very high (10,000) as Samba uses
+only one bit per unopened file.
+
+The limit of the number of open files is usually set
+by the UNIX per-process file descriptor limit rather than
+this parameter so you should never need to touch this parameter.
+
+Default: \fBmax open files = 10000\fR
+.TP
+\fBmax print jobs (S)\fR
+This parameter limits the maximum number of
+jobs allowable in a Samba printer queue at any given moment.
+If this number is exceeded, \fB smbd(8)\fRwill remote "Out of Space" to the client.
+See all \fItotal
+print jobs\fR.
+
+Default: \fBmax print jobs = 1000\fR
+
+Example: \fBmax print jobs = 5000\fR
+.TP
+\fBmax protocol (G)\fR
+The value of the parameter (a string) is the highest
+protocol level that will be supported by the server.
+
+Possible values are :
+.RS
+.TP 0.2i
+\(bu
+CORE: Earliest version. No
+concept of user names.
+.TP 0.2i
+\(bu
+COREPLUS: Slight improvements on
+CORE for efficiency.
+.TP 0.2i
+\(bu
+LANMAN1: First \fB modern\fR version of the protocol. Long filename
+support.
+.TP 0.2i
+\(bu
+LANMAN2: Updates to Lanman1 protocol.
+.TP 0.2i
+\(bu
+NT1: Current up to date version of
+the protocol. Used by Windows NT. Known as CIFS.
+.RE
+.PP
+Normally this option should not be set as the automatic
+negotiation phase in the SMB protocol takes care of choosing
+the appropriate protocol.
+.PP
+.PP
+See also \fImin
+protocol\fR
+.PP
+.PP
+Default: \fBmax protocol = NT1\fR
+.PP
+.PP
+Example: \fBmax protocol = LANMAN1\fR
+.PP
+.TP
+\fBmax smbd processes (G)\fR
+This parameter limits the maximum number of
+\fBsmbd(8)\fR
+processes concurrently running on a system and is intended
+as a stopgap to prevent degrading service to clients in the event
+that the server has insufficient resources to handle more than this
+number of connections. Remember that under normal operating
+conditions, each user will have an smbdassociated with him or her
+to handle connections to all shares from a given host.
+
+Default: \fBmax smbd processes = 0\fR ## no limit
+
+Example: \fBmax smbd processes = 1000\fR
+.TP
+\fBmax ttl (G)\fR
+This option tells nmbd(8)
+what the default 'time to live' of NetBIOS names should be (in seconds)
+when \fBnmbd\fR is requesting a name using either a
+broadcast packet or from a WINS server. You should never need to
+change this parameter. The default is 3 days.
+
+Default: \fBmax ttl = 259200\fR
+.TP
+\fBmax wins ttl (G)\fR
+This option tells nmbd(8)
+when acting as a WINS server ( \fIwins support = yes\fR) what the maximum
+\&'time to live' of NetBIOS names that \fBnmbd\fR
+will grant will be (in seconds). You should never need to change this
+parameter. The default is 6 days (518400 seconds).
+
+See also the \fImin
+wins ttl\fR parameter.
+
+Default: \fBmax wins ttl = 518400\fR
+.TP
+\fBmax xmit (G)\fR
+This option controls the maximum packet size
+that will be negotiated by Samba. The default is 65535, which
+is the maximum. In some cases you may find you get better performance
+with a smaller value. A value below 2048 is likely to cause problems.
+
+Default: \fBmax xmit = 65535\fR
+
+Example: \fBmax xmit = 8192\fR
+.TP
+\fBmessage command (G)\fR
+This specifies what command to run when the
+server receives a WinPopup style message.
+
+This would normally be a command that would
+deliver the message somehow. How this is to be done is
+up to your imagination.
+
+An example is:
+
+\fBmessage command = csh -c 'xedit %s;rm %s' &\fR
+
+This delivers the message using \fBxedit\fR, then
+removes it afterwards. \fBNOTE THAT IT IS VERY IMPORTANT
+THAT THIS COMMAND RETURN IMMEDIATELY\fR. That's why I
+have the '&' on the end. If it doesn't return immediately then
+your PCs may freeze when sending messages (they should recover
+after 30 seconds, hopefully).
+
+All messages are delivered as the global guest user.
+The command takes the standard substitutions, although \fI %u\fR won't work (\fI%U\fR may be better
in this case).
-Apart from the standard substitutions, some additional ones apply. In
-particular:
-
-%s = the filename containing the message
-
-%t = the destination that the message was sent to (probably the server
-name)
-
-%f = who the message is from
-
-You could make this command send mail, or whatever else takes your
-fancy. Please let me know of any really interesting ideas you have.
-
+Apart from the standard substitutions, some additional
+ones apply. In particular:
+.RS
+.TP 0.2i
+\(bu
+\fI%s\fR = the filename containing
+the message.
+.TP 0.2i
+\(bu
+\fI%t\fR = the destination that
+the message was sent to (probably the server name).
+.TP 0.2i
+\(bu
+\fI%f\fR = who the message
+is from.
+.RE
+.PP
+You could make this command send mail, or whatever else
+takes your fancy. Please let us know of any really interesting
+ideas you have.
+.PP
+.PP
Here's a way of sending the messages as mail to root:
-
-message command = /bin/mail -s 'message from %f on %m' root < %s; rm %s
-
-If you don't have a message command then the message won't be
-delivered and Samba will tell the sender there was an
-error. Unfortunately WfWg totally ignores the error code and carries
-on regardless, saying that the message was delivered.
-
-If you want to silently delete it then try "message command = rm %s".
-
-For the really adventurous, try something like this:
-
-message command = csh -c 'csh < %s |& /usr/local/samba/smbclient \\
- -M %m; rm %s' &
-
-this would execute the command as a script on the server, then give
-them the result in a WinPopup message. Note that this could cause a
-loop if you send a message from the server using smbclient! You better
-wrap the above in a script that checks for this :-)
-
-.B Default:
- no message command
-
-.B Example:
- message command = csh -c 'xedit %s;rm %s' &
-
-.SS min print space (S)
-
-This sets the minimum amount of free disk space that must be available
-before a user will be able to spool a print job. It is specified in
-kilobytes. The default is 0, which means no limit.
-
-.B Default:
- min print space = 0
-
-.B Example:
- min print space = 2000
-
-.SS null passwords (G)
-Allow or disallow access to accounts that have null passwords.
-
-.B Default:
- null passwords = no
-
-.B Example:
- null passwords = yes
-
-.SS os level (G)
-This integer value controls what level Samba advertises itself as for
-browse elections. See BROWSING.txt for details.
-
-.SS packet size (G)
-The maximum transmit packet size during a raw read. This option is no
-longer implemented as of version 1.7.00, and is kept only so old
-configuration files do not become invalid.
-
-.SS passwd chat (G)
-This string coontrols the "chat" conversation that takes places
-between smbd and the local password changing program to change the
-users password. The string describes a sequence of response-receive
-pairs that smbd uses to determine what to send to the passwd program
-and what to expect back. If the expected output is not received then
-the password is not changed.
-
-This chat sequence is often quite site specific, deppending on what
-local methods are used for password control (such as NIS+ etc).
-
-The string can contain the macros %o and %n which are substituted for
-the old and new passwords respectively. It can aso contain the
-standard macros \\n \\r \\t and \\s to give line-feed, carriage-return,
-tab and space.
-
-The string can also contain a * which matches any sequence of
-characters.
-
-Double quotes can be used to collect strings with spaces in them into
-a single string.
-
-If the send string in any part of the chat sequence is a fullstop "."
-then no string is sent. Similarly, is the expect string is a fullstop
-then no string is expected.
-
-.B Example:
- passwd chat = "*Enter OLD password*" %o\\n "*Enter NEW password*" %n\\n \\
- "*Reenter NEW password*" %n\\n "*Password changed*"
-
-.B Default:
- passwd chat = *old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*
-
-.SS passwd program (G)
-The name of a program that can be used to set user passwords.
-
-This is only necessary if you have enabled remote password changing at
-compile time. Any occurances of %u will be replaced with the user
-name.
-
-Also note that many passwd programs insist in "reasonable" passwords,
-such as a minimum length, or the inclusion of mixed case chars and
-digits. This can pose a problem as some clients (such as Windows for
-Workgroups) uppercase the password before sending it.
-
-.B Default:
- passwd program = /bin/passwd
-
-.B Example:
- passwd program = /sbin/passwd %u
-
-.SS password level (G)
-Some client/server conbinations have difficulty with mixed-case passwords.
-One offending client is Windows for Workgroups, which for some reason forces
-passwords to upper case when using the LANMAN1 protocol, but leaves them alone
-when using COREPLUS!
-
-This parameter defines the maximum number of characters that may be upper case
-in passwords.
-
-For example, say the password given was "FRED". If
-.B password level
-is set to 1 (one), the following combinations would be tried if "FRED" failed:
-"Fred", "fred", "fRed", "frEd", "freD". If
-.B password level was set to 2 (two), the following combinations would also be
-tried: "FRed", "FrEd", "FreD", "fREd", "fReD", "frED". And so on.
-
-The higher value this parameter is set to the more likely it is that a mixed
-case password will be matched against a single case password. However, you
-should be aware that use of this parameter reduces security and increases the
-time taken to process a new connection.
-
-A value of zero will cause only two attempts to be made - the password as is
-and the password in all-lower case.
-
-If you find the connections are taking too long with this option then
-you probably have a slow crypt() routine. Samba now comes with a fast
-"ufc crypt" that you can select in the Makefile. You should also make
-sure the PASSWORD_LENGTH option is correct for your system in local.h
-and includes.h. On most systems only the first 8 chars of a password
-are significant so PASSWORD_LENGTH should be 8, but on some longer
-passwords are significant. The inlcudes.h file tries to select the
-right length for your system.
-
-.B Default:
- password level = 0
-
-.B Example:
- password level = 4
-
-.SS password server (G)
-
-By specifying the name of another SMB server (such as a WinNT box)
-with this option, and using "security = server" you can get Samba to
-do all it's username/password validation via a remote server.
-
-This options sets the name of the password server to use. It must be a
-netbios name, so if the machines netbios name is different from it's
-internet name then you may have to add it's netbios name to
-/etc/hosts.
-
-The password server much be a machine capable of using the "LM1.2X002"
-or the "LM NT 0.12" protocol, and it must be in user level security
-mode.
-
-NOTE: Using a password server means your unix box (running Samba) is
-only as secure as your password server. DO NOT CHOOSE A PASSWORD
-SERVER THAT YOU DON'T COMPLETELY TRUST.
-
-Never point a Samba server at itself for password serving. This will
-cause a loop and could lock up your Samba server!
-
-The name of the password server takes the standard substitutions, but
-probably the only useful one is %m, which means the Samba server will
-use the incoming client as the password server. If you use this then
-you better trust your clients, and you better restrict them with hosts
-allow!
-
-If you list several hosts in the "password server" option then smbd
-will try each in turn till it finds one that responds. This is useful
-in case your primary server goes down.
-
-.SS path (S)
-A synonym for this parameter is 'directory'.
-
-This parameter specifies a directory to which the user of the service is to
-be given access. In the case of printable services, this is where print data
-will spool prior to being submitted to the host for printing.
-
-For a printable service offering guest access, the service should be readonly
-and the path should be world-writable and have the sticky bit set. This is not
-mandatory of course, but you probably won't get the results you expect if you
-do otherwise.
-
-Any occurances of %u in the path will be replaced with the username
-that the client is connecting as. Any occurances of %m will be
-replaced by the name of the machine they are connecting from. These
-replacements are very useful for setting up pseudo home directories
-for users.
-
-Note that this path will be based on 'root dir' if one was specified.
-.B Default:
- none
-
-.B Example:
- path = /home/fred+
-
-.SS postexec (S)
-
-This option specifies a command to be run whenever the service is
-disconnected. It takes the usual substitutions. The command may be run
-as the root on some systems.
-
-An interesting example may be do unmount server resources:
-
-postexec = /etc/umount /cdrom
-
-See also preexec
-
-.B Default:
- none (no command executed)
-
-.B Example:
- postexec = echo \"%u disconnected from %S from %m (%I)\" >> /tmp/log
-
-.SS postscript (S)
-This parameter forces a printer to interpret the print files as
-postscript. This is done by adding a %! to the start of print output.
-
-This is most useful when you have lots of PCs that persist in putting
-a control-D at the start of print jobs, which then confuses your
-printer.
-
-.B Default:
- postscript = False
-
-.B Example:
- postscript = True
-
-.SS preexec (S)
-
-This option specifies a command to be run whenever the service is
-connected to. It takes the usual substitutions.
-
-An interesting example is to send the users a welcome message every
-time they log in. Maybe a message of the day? Here is an example:
-
-preexec = csh -c 'echo \"Welcome to %S!\" | \
- /usr/local/samba/smbclient -M %m -I %I' &
+.PP
+.PP
+\fBmessage command = /bin/mail -s 'message from %f on
+%m' root < %s; rm %s\fR
+.PP
+.PP
+If you don't have a message command then the message
+won't be delivered and Samba will tell the sender there was
+an error. Unfortunately WfWg totally ignores the error code
+and carries on regardless, saying that the message was delivered.
+.PP
+.PP
+If you want to silently delete it then try:
+.PP
+.PP
+\fBmessage command = rm %s\fR
+.PP
+.PP
+Default: \fBno message command\fR
+.PP
+.PP
+Example: \fBmessage command = csh -c 'xedit %s;
+rm %s' &\fR
+.PP
+.TP
+\fBmin passwd length (G)\fR
+Synonym for \fImin password length\fR.
+.TP
+\fBmin password length (G)\fR
+This option sets the minimum length in characters
+of a plaintext password that \fBsmbd\fR will accept when performing
+UNIX password changing.
+
+See also \fIunix
+password sync\fR, \fIpasswd program\fR and \fIpasswd chat debug\fR
+\&.
+
+Default: \fBmin password length = 5\fR
+.TP
+\fBmin print space (S)\fR
+This sets the minimum amount of free disk
+space that must be available before a user will be able to spool
+a print job. It is specified in kilobytes. The default is 0, which
+means a user can always spool a print job.
+
+See also the \fIprinting
+\fRparameter.
+
+Default: \fBmin print space = 0\fR
+
+Example: \fBmin print space = 2000\fR
+.TP
+\fBmin protocol (G)\fR
+The value of the parameter (a string) is the
+lowest SMB protocol dialect than Samba will support. Please refer
+to the \fImax protocol\fR
+parameter for a list of valid protocol names and a brief description
+of each. You may also wish to refer to the C source code in
+\fIsource/smbd/negprot.c\fR for a listing of known protocol
+dialects supported by clients.
+
+If you are viewing this parameter as a security measure, you should
+also refer to the \fIlanman
+auth\fR parameter. Otherwise, you should never need
+to change this parameter.
+
+Default : \fBmin protocol = CORE\fR
+
+Example : \fBmin protocol = NT1\fR # disable DOS
+clients
+.TP
+\fBmin wins ttl (G)\fR
+This option tells nmbd(8)
+when acting as a WINS server (\fI wins support = yes\fR) what the minimum 'time to live'
+of NetBIOS names that \fBnmbd\fR will grant will be (in
+seconds). You should never need to change this parameter. The default
+is 6 hours (21600 seconds).
+
+Default: \fBmin wins ttl = 21600\fR
+.TP
+\fBmsdfs root (S)\fR
+This boolean parameter is only available if
+Samba is configured and compiled with the \fB --with-msdfs\fR option. If set to yes,
+Samba treats the share as a Dfs root and allows clients to browse
+the distributed file system tree rooted at the share directory.
+Dfs links are specified in the share directory by symbolic
+links of the form \fImsdfs:serverA\\shareA,serverB\\shareB
+\fRand so on. For more information on setting up a Dfs tree
+on Samba, refer to msdfs_setup.html
+.
+
+See also \fIhost msdfs
+\fR
+Default: \fBmsdfs root = no\fR
+.TP
+\fBname resolve order (G)\fR
+This option is used by the programs in the Samba
+suite to determine what naming services to use and in what order
+to resolve host names to IP addresses. The option takes a space
+separated string of name resolution options.
+
+The options are :"lmhosts", "host", "wins" and "bcast". They
+cause names to be resolved as follows :
+.RS
+.TP 0.2i
+\(bu
+lmhosts : Lookup an IP
+address in the Samba lmhosts file. If the line in lmhosts has
+no name type attached to the NetBIOS name (see the lmhosts(5)for details) then
+any name type matches for lookup.
+.TP 0.2i
+\(bu
+host : Do a standard host
+name to IP address resolution, using the system \fI/etc/hosts
+\fR, NIS, or DNS lookups. This method of name resolution
+is operating system depended for instance on IRIX or Solaris this
+may be controlled by the \fI/etc/nsswitch.conf\fR
+file. Note that this method is only used if the NetBIOS name
+type being queried is the 0x20 (server) name type, otherwise
+it is ignored.
+.TP 0.2i
+\(bu
+wins : Query a name with
+the IP address listed in the \fI wins server\fR parameter. If no WINS server has
+been specified this method will be ignored.
+.TP 0.2i
+\(bu
+bcast : Do a broadcast on
+each of the known local interfaces listed in the \fIinterfaces\fR
+parameter. This is the least reliable of the name resolution
+methods as it depends on the target host being on a locally
+connected subnet.
+.RE
+.PP
+Default: \fBname resolve order = lmhosts host wins bcast
+\fR.PP
+.PP
+Example: \fBname resolve order = lmhosts bcast host
+\fR.PP
+.PP
+This will cause the local lmhosts file to be examined
+first, followed by a broadcast attempt, followed by a normal
+system hostname lookup.
+.PP
+.TP
+\fBnetbios aliases (G)\fR
+This is a list of NetBIOS names that nmbd(8)will advertise as additional
+names by which the Samba server is known. This allows one machine
+to appear in browse lists under multiple names. If a machine is
+acting as a browse server or logon server none
+of these names will be advertised as either browse server or logon
+servers, only the primary name of the machine will be advertised
+with these capabilities.
+
+See also \fInetbios
+name\fR.
+
+Default: \fBempty string (no additional names)\fR
+
+Example: \fBnetbios aliases = TEST TEST1 TEST2\fR
+.TP
+\fBnetbios name (G)\fR
+This sets the NetBIOS name by which a Samba
+server is known. By default it is the same as the first component
+of the host's DNS name. If a machine is a browse server or
+logon server this name (or the first component
+of the hosts DNS name) will be the name that these services are
+advertised under.
+
+See also \fInetbios
+aliases\fR.
+
+Default: \fBmachine DNS name\fR
+
+Example: \fBnetbios name = MYNAME\fR
+.TP
+\fBnetbios scope (G)\fR
+This sets the NetBIOS scope that Samba will
+operate under. This should not be set unless every machine
+on your LAN also sets this value.
+.TP
+\fBnis homedir (G)\fR
+Get the home share server from a NIS map. For
+UNIX systems that use an automounter, the user's home directory
+will often be mounted on a workstation on demand from a remote
+server.
+
+When the Samba logon server is not the actual home directory
+server, but is mounting the home directories via NFS then two
+network hops would be required to access the users home directory
+if the logon server told the client to use itself as the SMB server
+for home directories (one over SMB and one over NFS). This can
+be very slow.
+
+This option allows Samba to return the home share as
+being on a different server to the logon server and as
+long as a Samba daemon is running on the home directory server,
+it will be mounted on the Samba client directly from the directory
+server. When Samba is returning the home share to the client, it
+will consult the NIS map specified in \fIhomedir map\fR and return the server
+listed there.
+
+Note that for this option to work there must be a working
+NIS system and the Samba server with this option must also
+be a logon server.
+
+Default: \fBnis homedir = no\fR
+.TP
+\fBnt acl support (S)\fR
+This boolean parameter controls whether
+smbd(8)will attempt to map
+UNIX permissions into Windows NT access control lists.
+This parameter was formally a global parameter in releases
+prior to 2.2.2.
+
+Default: \fBnt acl support = yes\fR
+.TP
+\fBnt pipe support (G)\fR
+This boolean parameter controls whether
+smbd(8)will allow Windows NT
+clients to connect to the NT SMB specific IPC$
+pipes. This is a developer debugging option and can be left
+alone.
+
+Default: \fBnt pipe support = yes\fR
+.TP
+\fBnt smb support (G)\fR
+This boolean parameter controls whether smbd(8)will negotiate NT specific SMB
+support with Windows NT clients. Although this is a developer
+debugging option and should be left alone, benchmarking has discovered
+that Windows NT clients give faster performance with this option
+set to no. This is still being investigated.
+If this option is set to no then Samba offers
+exactly the same SMB calls that versions prior to Samba 2.0 offered.
+This information may be of use if any users are having problems
+with NT SMB support.
+
+You should not need to ever disable this parameter.
+
+Default: \fBnt smb support = yes\fR
+.TP
+\fBnull passwords (G)\fR
+Allow or disallow client access to accounts
+that have null passwords.
+
+See also smbpasswd (5).
+
+Default: \fBnull passwords = no\fR
+.TP
+\fBobey pam restrictions (G)\fR
+When Samba 2.2 is configured to enable PAM support
+(i.e. --with-pam), this parameter will control whether or not Samba
+should obey PAM's account and session management directives. The
+default behavior is to use PAM for clear text authentication only
+and to ignore any account or session management. Note that Samba
+always ignores PAM for authentication in the case of \fIencrypt passwords = yes\fR
+\&. The reason is that PAM modules cannot support the challenge/response
+authentication mechanism needed in the presence of SMB password encryption.
+
+Default: \fBobey pam restrictions = no\fR
+.TP
+\fBonly user (S)\fR
+This is a boolean option that controls whether
+connections with usernames not in the \fIuser\fR
+list will be allowed. By default this option is disabled so that a
+client can supply a username to be used by the server. Enabling
+this parameter will force the server to only user the login
+names from the \fIuser\fR list and is only really
+useful in shave level
+security.
+
+Note that this also means Samba won't try to deduce
+usernames from the service name. This can be annoying for
+the [homes] section. To get around this you could use \fBuser =
+%S\fR which means your \fIuser\fR list
+will be just the service name, which for home directories is the
+name of the user.
+
+See also the \fIuser\fR
+parameter.
+
+Default: \fBonly user = no\fR
+.TP
+\fBonly guest (S)\fR
+A synonym for \fI guest only\fR.
+.TP
+\fBoplock break wait time (G)\fR
+This is a tuning parameter added due to bugs in
+both Windows 9x and WinNT. If Samba responds to a client too
+quickly when that client issues an SMB that can cause an oplock
+break request, then the network client can fail and not respond
+to the break request. This tuning parameter (which is set in milliseconds)
+is the amount of time Samba will wait before sending an oplock break
+request to such (broken) clients.
+
+\fBDO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+AND UNDERSTOOD THE SAMBA OPLOCK CODE\fR.
+
+Default: \fBoplock break wait time = 0\fR
+.TP
+\fBoplock contention limit (S)\fR
+This is a \fBvery\fR advanced
+smbd(8)tuning option to
+improve the efficiency of the granting of oplocks under multiple
+client contention for the same file.
+
+In brief it specifies a number, which causes smbdnot to
+grant an oplock even when requested if the approximate number of
+clients contending for an oplock on the same file goes over this
+limit. This causes \fBsmbd\fR to behave in a similar
+way to Windows NT.
+
+\fBDO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ
+AND UNDERSTOOD THE SAMBA OPLOCK CODE\fR.
+
+Default: \fBoplock contention limit = 2\fR
+.TP
+\fBoplocks (S)\fR
+This boolean option tells \fBsmbd\fR whether to
+issue oplocks (opportunistic locks) to file open requests on this
+share. The oplock code can dramatically (approx. 30% or more) improve
+the speed of access to files on Samba servers. It allows the clients
+to aggressively cache files locally and you may want to disable this
+option for unreliable network environments (it is turned on by
+default in Windows NT Servers). For more information see the file
+\fISpeed.txt\fR in the Samba \fIdocs/\fR
+directory.
+
+Oplocks may be selectively turned off on certain files with a
+share. See the \fI veto oplock files\fR parameter. On some systems
+oplocks are recognized by the underlying operating system. This
+allows data synchronization between all access to oplocked files,
+whether it be via Samba or NFS or a local UNIX process. See the
+\fIkernel oplocks\fR parameter for details.
+
+See also the \fIkernel
+oplocks\fR and \fI level2 oplocks\fR parameters.
+
+Default: \fBoplocks = yes\fR
+.TP
+\fBos level (G)\fR
+This integer value controls what level Samba
+advertises itself as for browse elections. The value of this
+parameter determines whether nmbd(8)
+has a chance of becoming a local master browser for the \fI WORKGROUP\fR in the local broadcast area.
+
+\fBNote :\fRBy default, Samba will win
+a local master browsing election over all Microsoft operating
+systems except a Windows NT 4.0/2000 Domain Controller. This
+means that a misconfigured Samba host can effectively isolate
+a subnet for browsing purposes. See \fIBROWSING.txt
+\fRin the Samba \fIdocs/\fR directory
+for details.
+
+Default: \fBos level = 20\fR
+
+Example: \fBos level = 65 \fR
+.TP
+\fBos2 driver map (G)\fR
+The parameter is used to define the absolute
+path to a file containing a mapping of Windows NT printer driver
+names to OS/2 printer driver names. The format is:
+
+<nt driver name> = <os2 driver
+name>.<device name>
+
+For example, a valid entry using the HP LaserJet 5
+printer driver would appear as \fBHP LaserJet 5L = LASERJET.HP
+LaserJet 5L\fR.
+
+The need for the file is due to the printer driver namespace
+problem described in the Samba
+Printing HOWTO. For more details on OS/2 clients, please
+refer to the OS2-Client-HOWTO
+containing in the Samba documentation.
+
+Default: \fBos2 driver map = <empty string>
+\fR.TP
+\fBpam password change (G)\fR
+With the addition of better PAM support in Samba 2.2,
+this parameter, it is possible to use PAM's password change control
+flag for Samba. If enabled, then PAM will be used for password
+changes when requested by an SMB client instead of the program listed in
+\fIpasswd program\fR.
+It should be possible to enable this without changing your
+\fIpasswd chat\fR
+parameter for most setups.
+
+Default: \fBpam password change = no\fR
+.TP
+\fBpanic action (G)\fR
+This is a Samba developer option that allows a
+system command to be called when either smbd(8)
+crashes. This is usually used to draw attention to the fact that
+a problem occurred.
+
+Default: \fBpanic action = <empty string>\fR
+
+Example: \fBpanic action = "/bin/sleep 90000"\fR
+.TP
+\fBpasswd chat (G)\fR
+This string controls the \fB"chat"\fR
+conversation that takes places between smbdand the local password changing
+program to change the user's password. The string describes a
+sequence of response-receive pairs that smbd(8)uses to determine what to send to the
+\fIpasswd program\fR
+and what to expect back. If the expected output is not
+received then the password is not changed.
+
+This chat sequence is often quite site specific, depending
+on what local methods are used for password control (such as NIS
+etc).
+
+Note that this parameter only is only used if the \fIunix
+password sync\fR parameter is set to yes. This
+sequence is then called \fBAS ROOT\fR when the SMB password
+in the smbpasswd file is being changed, without access to the old
+password cleartext. This means that root must be able to reset the user's password
+without knowing the text of the previous password. In the presence of NIS/YP,
+this means that the passwd program must be
+executed on the NIS master.
+
+The string can contain the macro \fI%n\fR which is substituted
+for the new password. The chat sequence can also contain the standard
+macros \\n, \\r, \\t and \\s to give line-feed,
+carriage-return, tab and space. The chat sequence string can also contain
+a '*' which matches any sequence of characters.
+Double quotes can be used to collect strings with spaces
+in them into a single string.
+
+If the send string in any part of the chat sequence
+is a full stop ".", then no string is sent. Similarly,
+if the expect string is a full stop then no string is expected.
+
+If the \fIpam
+password change\fR parameter is set to true, the chat pairs
+may be matched in any order, and success is determined by the PAM result,
+not any particular output. The \\n macro is ignored for PAM conversions.
+
+See also \fIunix password
+sync\fR, \fI passwd program\fR , \fIpasswd chat debug\fR and \fIpam password change\fR.
+
+Default: \fBpasswd chat = *new*password* %n\\n
+*new*password* %n\\n *changed*\fR
+
+Example: \fBpasswd chat = "*Enter OLD password*" %o\\n
+"*Enter NEW password*" %n\\n "*Reenter NEW password*" %n\\n "*Password
+changed*"\fR
+.TP
+\fBpasswd chat debug (G)\fR
+This boolean specifies if the passwd chat script
+parameter is run in \fBdebug\fR mode. In this mode the
+strings passed to and received from the passwd chat are printed
+in the smbd(8)log with a
+\fIdebug level\fR
+of 100. This is a dangerous option as it will allow plaintext passwords
+to be seen in the \fBsmbd\fR log. It is available to help
+Samba admins debug their \fIpasswd chat\fR scripts
+when calling the \fIpasswd program\fR and should
+be turned off after this has been done. This option has no effect if the
+\fIpam password change\fR
+paramter is set. This parameter is off by default.
+
+See also \fIpasswd chat\fR
+, \fIpam password change\fR
+, \fIpasswd program\fR
+\&.
+
+Default: \fBpasswd chat debug = no\fR
+.TP
+\fBpasswd program (G)\fR
+The name of a program that can be used to set
+UNIX user passwords. Any occurrences of \fI%u\fR
+will be replaced with the user name. The user name is checked for
+existence before calling the password changing program.
+
+Also note that many passwd programs insist in \fBreasonable
+\fRpasswords, such as a minimum length, or the inclusion
+of mixed case chars and digits. This can pose a problem as some clients
+(such as Windows for Workgroups) uppercase the password before sending
+it.
+
+\fBNote\fR that if the \fIunix
+password sync\fR parameter is set to true
+then this program is called \fBAS ROOT\fR
+before the SMB password in the smbpasswd(5)
+file is changed. If this UNIX password change fails, then
+\fBsmbd\fR will fail to change the SMB password also
+(this is by design).
+
+If the \fIunix password sync\fR parameter
+is set this parameter \fBMUST USE ABSOLUTE PATHS\fR
+for \fBALL\fR programs called, and must be examined
+for security implications. Note that by default \fIunix
+password sync\fR is set to false.
+
+See also \fIunix
+password sync\fR.
+
+Default: \fBpasswd program = /bin/passwd\fR
+
+Example: \fBpasswd program = /sbin/npasswd %u\fR
+.TP
+\fBpassword level (G)\fR
+Some client/server combinations have difficulty
+with mixed-case passwords. One offending client is Windows for
+Workgroups, which for some reason forces passwords to upper
+case when using the LANMAN1 protocol, but leaves them alone when
+using COREPLUS! Another problem child is the Windows 95/98
+family of operating systems. These clients upper case clear
+text passwords even when NT LM 0.12 selected by the protocol
+negotiation request/response.
+
+This parameter defines the maximum number of characters
+that may be upper case in passwords.
+
+For example, say the password given was "FRED". If \fI password level\fR is set to 1, the following combinations
+would be tried if "FRED" failed:
+
+"Fred", "fred", "fRed", "frEd","freD"
+
+If \fIpassword level\fR was set to 2,
+the following combinations would also be tried:
+
+"FRed", "FrEd", "FreD", "fREd", "fReD", "frED", ..
+
+And so on.
+
+The higher value this parameter is set to the more likely
+it is that a mixed case password will be matched against a single
+case password. However, you should be aware that use of this
+parameter reduces security and increases the time taken to
+process a new connection.
+
+A value of zero will cause only two attempts to be
+made - the password as is and the password in all-lower case.
+
+Default: \fBpassword level = 0\fR
+
+Example: \fBpassword level = 4\fR
+.TP
+\fBpassword server (G)\fR
+By specifying the name of another SMB server (such
+as a WinNT box) with this option, and using \fBsecurity = domain
+\fRor \fBsecurity = server\fR you can get Samba
+to do all its username/password validation via a remote server.
+
+This option sets the name of the password server to use.
+It must be a NetBIOS name, so if the machine's NetBIOS name is
+different from its Internet name then you may have to add its NetBIOS
+name to the lmhosts file which is stored in the same directory
+as the \fIsmb.conf\fR file.
+
+The name of the password server is looked up using the
+parameter \fIname
+resolve order\fR and so may resolved
+by any method and order described in that parameter.
+
+The password server much be a machine capable of using
+the "LM1.2X002" or the "NT LM 0.12" protocol, and it must be in
+user level security mode.
+
+\fBNOTE:\fR Using a password server
+means your UNIX box (running Samba) is only as secure as your
+password server. \fBDO NOT CHOOSE A PASSWORD SERVER THAT
+YOU DON'T COMPLETELY TRUST\fR.
+
+Never point a Samba server at itself for password
+serving. This will cause a loop and could lock up your Samba
+server!
+
+The name of the password server takes the standard
+substitutions, but probably the only useful one is \fI%m
+\fR, which means the Samba server will use the incoming
+client as the password server. If you use this then you better
+trust your clients, and you had better restrict them with hosts allow!
+
+If the \fIsecurity\fR parameter is set to
+domain, then the list of machines in this
+option must be a list of Primary or Backup Domain controllers for the
+Domain or the character '*', as the Samba server is effectively
+in that domain, and will use cryptographically authenticated RPC calls
+to authenticate the user logging on. The advantage of using \fB security = domain\fR is that if you list several hosts in the
+\fIpassword server\fR option then \fBsmbd
+\fRwill try each in turn till it finds one that responds. This
+is useful in case your primary server goes down.
+
+If the \fIpassword server\fR option is set
+to the character '*', then Samba will attempt to auto-locate the
+Primary or Backup Domain controllers to authenticate against by
+doing a query for the name WORKGROUP<1C>
+and then contacting each server returned in the list of IP
+addresses from the name resolution source.
+
+If the \fIsecurity\fR parameter is
+set to server, then there are different
+restrictions that \fBsecurity = domain\fR doesn't
+suffer from:
+.RS
+.TP 0.2i
+\(bu
+You may list several password servers in
+the \fIpassword server\fR parameter, however if an
+\fBsmbd\fR makes a connection to a password server,
+and then the password server fails, no more users will be able
+to be authenticated from this \fBsmbd\fR. This is a
+restriction of the SMB/CIFS protocol when in \fBsecurity = server
+\fRmode and cannot be fixed in Samba.
+.TP 0.2i
+\(bu
+If you are using a Windows NT server as your
+password server then you will have to ensure that your users
+are able to login from the Samba server, as when in \fB security = server\fR mode the network logon will appear to
+come from there rather than from the users workstation.
+.RE
+.PP
+See also the \fIsecurity
+\fRparameter.
+.PP
+.PP
+Default: \fBpassword server = <empty string>\fR
+.PP
+.PP
+Example: \fBpassword server = NT-PDC, NT-BDC1, NT-BDC2
+\fR.PP
+.PP
+Example: \fBpassword server = *\fR
+.PP
+.TP
+\fBpath (S)\fR
+This parameter specifies a directory to which
+the user of the service is to be given access. In the case of
+printable services, this is where print data will spool prior to
+being submitted to the host for printing.
+
+For a printable service offering guest access, the service
+should be readonly and the path should be world-writeable and
+have the sticky bit set. This is not mandatory of course, but
+you probably won't get the results you expect if you do
+otherwise.
+
+Any occurrences of \fI%u\fR in the path
+will be replaced with the UNIX username that the client is using
+on this connection. Any occurrences of \fI%m\fR
+will be replaced by the NetBIOS name of the machine they are
+connecting from. These replacements are very useful for setting
+up pseudo home directories for users.
+
+Note that this path will be based on \fIroot dir\fR if one was specified.
+
+Default: \fBnone\fR
+
+Example: \fBpath = /home/fred\fR
+.TP
+\fBposix locking (S)\fR
+The \fBsmbd(8)\fR
+daemon maintains an database of file locks obtained by SMB clients.
+The default behavior is to map this internal database to POSIX
+locks. This means that file locks obtained by SMB clients are
+consistent with those seen by POSIX compliant applications accessing
+the files via a non-SMB method (e.g. NFS or local file access).
+You should never need to disable this parameter.
+
+Default: \fBposix locking = yes\fR
+.TP
+\fBpostexec (S)\fR
+This option specifies a command to be run
+whenever the service is disconnected. It takes the usual
+substitutions. The command may be run as the root on some
+systems.
+
+An interesting example may be to unmount server
+resources:
+
+\fBpostexec = /etc/umount /cdrom\fR
+
+See also \fIpreexec\fR
+\&.
+
+Default: \fBnone (no command executed)\fR
+
+Example: \fBpostexec = echo \\"%u disconnected from %S
+from %m (%I)\\" >> /tmp/log\fR
+.TP
+\fBpostscript (S)\fR
+This parameter forces a printer to interpret
+the print files as PostScript. This is done by adding a %!
+to the start of print output.
+
+This is most useful when you have lots of PCs that persist
+in putting a control-D at the start of print jobs, which then
+confuses your printer.
+
+Default: \fBpostscript = no\fR
+.TP
+\fBpreexec (S)\fR
+This option specifies a command to be run whenever
+the service is connected to. It takes the usual substitutions.
+
+An interesting example is to send the users a welcome
+message every time they log in. Maybe a message of the day? Here
+is an example:
+
+\fBpreexec = csh -c 'echo \\"Welcome to %S!\\" |
+/usr/local/samba/bin/smbclient -M %m -I %I' & \fR
Of course, this could get annoying after a while :-)
-See also postexec
-
-.B Default:
- none (no command executed)
-
-.B Example:
- preexec = echo \"%u connected to %S from %m (%I)\" >> /tmp/log
-
-.SS preferred master (G)
-This boolean parameter controls if Samba is a preferred master browser
-for its workgroup. Setting this gives it a slight edge in elections
-and also means it will automatically start an election when it starts
-up.
-
-It is on by default.
-
-.SS preload
-This is an alias for "auto services"
-
-.SS preserve case (S)
-
-This controls if new filenames are created with the case that the
-client passes, or if they are forced to be the "default" case.
-
-.B Default:
- preserve case = no
-
-See the section on "NAME MANGLING" for a fuller discussion.
-
-.SS print command (S)
-After a print job has finished spooling to a service, this command will be
-used via a system() call to process the spool file. Typically the command
-specified will submit the spool file to the host's printing subsystem, but
-there is no requirement that this be the case. The server will not remove the
-spool file, so whatever command you specify should remove the spool file when
-it has been processed, otherwise you will need to manually remove old spool
-files.
-
-The print command is simply a text string. It will be used verbatim,
-with two exceptions: All occurrences of "%s" will be replaced by the
-appropriate spool file name, and all occurrences of "%p" will be
-replaced by the appropriate printer name. The spool file name is
-generated automatically by the server, the printer name is discussed
-below.
-
-The full path name will be used for the filename if %s is not preceded
-by a /. If you don't like this (it can stuff up some lpq output) then
-use %f instead. Any occurances of %f get replaced by the spool
-filename without the full path at the front.
-
-The print command MUST contain at least one occurrence of "%s" or %f -
-the "%p" is optional. At the time a job is submitted, if no printer
-name is supplied the "%p" will be silently removed from the printer
-command.
-
-If specified in the [global] section, the print command given will be used
-for any printable service that does not have its own print command specified.
-
-If there is neither a specified print command for a printable service nor a
-global print command, spool files will be created but not processed and (most
-importantly) not removed.
-
-Note that printing may fail on some unixes from the "nobody"
-account. If this happens then create an alternative guest account that
-can print and set the "guest account" in the [global] section.
-
-You can form quite complex print commands by realising that they are
-just passed to a shell. For example the following will log a print
-job, print the file, then remove it. Note that ; is the usual
-separator for command in shell scripts.
-
-print command = echo Printing %s >> /tmp/print.log; lpr -P %p %s; rm %s
-
-You may have to vary this command considerably depending on how you
-normally print files on your system.
-
-.B Default:
- print command = lpr -r -P %p %s
-
-.B Example:
- print command = /usr/local/samba/myprintscript %p %s
-.SS print ok (S)
-See
-.B printable.
-.SS printable (S)
-A synonym for this parameter is 'print ok'.
-
-If this parameter is 'yes', then clients may open, write to and submit spool
-files on the directory specified for the service.
-
-Note that a printable service will ALWAYS allow writing to the service path
-(user privileges permitting) via the spooling of print data. The 'read only'
-parameter controls only non-printing access to the resource.
-
-.B Default:
- printable = no
-
-.B Example:
- printable = yes
-
-.SS printing (G)
-This parameters controls how printer status information is interpreted
-on your system, and also affects the default values for the "print
-command", "lpq command" and "lprm command".
-
-Currently three printing styles are supported. They are "printing =
-bsd", "printing = sysv", "printing = hpux" and "printing = aix".
-
-To see what the defaults are for the other print commands when using
-these three options use the "testparm" program.
-
-
-.SS printcap name (G)
-This parameter may be used to override the compiled-in default printcap
-name used by the server (usually /etc/printcap). See the discussion of the
-[printers] section above for reasons why you might want to do this.
-
-For those of you without a printcap (say on SysV) you can just create a
-minimal file that looks like a printcap and set "printcap name =" in
-[global] to point at it.
+See also \fIpreexec close
+\fRand \fIpostexec
+\fR\&.
+
+Default: \fBnone (no command executed)\fR
+
+Example: \fBpreexec = echo \\"%u connected to %S from %m
+(%I)\\" >> /tmp/log\fR
+.TP
+\fBpreexec close (S)\fR
+This boolean option controls whether a non-zero
+return code from \fIpreexec
+\fRshould close the service being connected to.
+
+Default: \fBpreexec close = no\fR
+.TP
+\fBpreferred master (G)\fR
+This boolean parameter controls if nmbd(8)is a preferred master browser
+for its workgroup.
+
+If this is set to true, on startup, \fBnmbd\fR
+will force an election, and it will have a slight advantage in
+winning the election. It is recommended that this parameter is
+used in conjunction with \fB\fI domain master\fB = yes\fR, so that \fB nmbd\fR can guarantee becoming a domain master.
+
+Use this option with caution, because if there are several
+hosts (whether Samba servers, Windows 95 or NT) that are preferred
+master browsers on the same subnet, they will each periodically
+and continuously attempt to become the local master browser.
+This will result in unnecessary broadcast traffic and reduced browsing
+capabilities.
+
+See also \fIos level\fR
+\&.
+
+Default: \fBpreferred master = auto\fR
+.TP
+\fBprefered master (G)\fR
+Synonym for \fI preferred master\fR for people who cannot spell :-).
+.TP
+\fBpreload\fR
+This is a list of services that you want to be
+automatically added to the browse lists. This is most useful
+for homes and printers services that would otherwise not be
+visible.
+
+Note that if you just want all printers in your
+printcap file loaded then the \fIload printers\fR option is easier.
+
+Default: \fBno preloaded services\fR
+
+Example: \fBpreload = fred lp colorlp\fR
+.TP
+\fBpreserve case (S)\fR
+This controls if new filenames are created
+with the case that the client passes, or if they are forced to
+be the \fIdefault case
+\fR\&.
+
+Default: \fBpreserve case = yes\fR
+
+See the section on NAME
+MANGLING for a fuller discussion.
+.TP
+\fBprint command (S)\fR
+After a print job has finished spooling to
+a service, this command will be used via a \fBsystem()\fR
+call to process the spool file. Typically the command specified will
+submit the spool file to the host's printing subsystem, but there
+is no requirement that this be the case. The server will not remove
+the spool file, so whatever command you specify should remove the
+spool file when it has been processed, otherwise you will need to
+manually remove old spool files.
+
+The print command is simply a text string. It will be used
+verbatim, with two exceptions: All occurrences of \fI%s
+\fRand \fI%f\fR will be replaced by the
+appropriate spool file name, and all occurrences of \fI%p
+\fRwill be replaced by the appropriate printer name. The
+spool file name is generated automatically by the server. The
+\fI%J\fR macro can be used to access the job
+name as transmitted by the client.
+
+The print command \fBMUST\fR contain at least
+one occurrence of \fI%s\fR or \fI%f
+\fR- the \fI%p\fR is optional. At the time
+a job is submitted, if no printer name is supplied the \fI%p
+\fRwill be silently removed from the printer command.
+
+If specified in the [global] section, the print command given
+will be used for any printable service that does not have its own
+print command specified.
+
+If there is neither a specified print command for a
+printable service nor a global print command, spool files will
+be created but not processed and (most importantly) not removed.
+
+Note that printing may fail on some UNIXes from the
+nobody account. If this happens then create
+an alternative guest account that can print and set the \fIguest account\fR
+in the [global] section.
+
+You can form quite complex print commands by realizing
+that they are just passed to a shell. For example the following
+will log a print job, print the file, then remove it. Note that
+\&';' is the usual separator for command in shell scripts.
+
+\fBprint command = echo Printing %s >>
+/tmp/print.log; lpr -P %p %s; rm %s\fR
+
+You may have to vary this command considerably depending
+on how you normally print files on your system. The default for
+the parameter varies depending on the setting of the \fIprinting\fR parameter.
+
+Default: For \fBprinting = BSD, AIX, QNX, LPRNG
+or PLP :\fR
+
+\fBprint command = lpr -r -P%p %s\fR
+
+For \fBprinting = SYSV or HPUX :\fR
+
+\fBprint command = lp -c -d%p %s; rm %s\fR
+
+For \fBprinting = SOFTQ :\fR
+
+\fBprint command = lp -d%p -s %s; rm %s\fR
+
+Example: \fBprint command = /usr/local/samba/bin/myprintscript
+%p %s\fR
+.TP
+\fBprint ok (S)\fR
+Synonym for \fIprintable\fR.
+.TP
+\fBprintable (S)\fR
+If this parameter is yes, then
+clients may open, write to and submit spool files on the directory
+specified for the service.
+
+Note that a printable service will ALWAYS allow writing
+to the service path (user privileges permitting) via the spooling
+of print data. The \fIwriteable
+\fRparameter controls only non-printing access to
+the resource.
+
+Default: \fBprintable = no\fR
+.TP
+\fBprintcap (G)\fR
+Synonym for \fI printcap name\fR.
+.TP
+\fBprintcap name (G)\fR
+This parameter may be used to override the
+compiled-in default printcap name used by the server (usually \fI /etc/printcap\fR). See the discussion of the [printers] section above for reasons
+why you might want to do this.
+
+On System V systems that use \fBlpstat\fR to
+list available printers you can use \fBprintcap name = lpstat
+\fRto automatically obtain lists of available printers. This
+is the default for systems that define SYSV at configure time in
+Samba (this includes most System V based systems). If \fI printcap name\fR is set to \fBlpstat\fR on
+these systems then Samba will launch \fBlpstat -v\fR and
+attempt to parse the output to obtain a printer list.
A minimal printcap file would look something like this:
-print1|My Printer 1
-print2|My Printer 2
-print3|My Printer 3
-print4|My Printer 4
-print5|My Printer 5
-
-where the | separates aliases of a printer. The fact that the second
-alias has a space in it gives a hint to Samba that it's a comment.
-
-NOTE: Under AIX the default printcap name is "/etc/qconfig". Samba
-will assume the file is in AIX "qconfig" format if the string
-"/qconfig" appears in the printcap filename.
-
-.B Default:
- printcap name = /etc/printcap
-
-.B Example:
- printcap name = /etc/myprintcap
-.SS printer (S)
-A synonym for this parameter is 'printer name'.
-
-This parameter specifies the name of the printer to which print jobs spooled
-through a printable service will be sent.
-
-If specified in the [global] section, the printer name given will be used
-for any printable service that does not have its own printer name specified.
-
-.B Default:
- none (but may be 'lp' on many systems)
-
-.B Example:
- printer name = laserwriter
-.SS printer name (S)
-See
-.B printer.
-.SS protocol (G)
-The value of the parameter (a string) is the highest protocol level that will
-be supported by the server.
-
-Possible values are CORE, COREPLUS, LANMAN1, LANMAN2 and NT1. The relative
-merits of each are discussed in the README file.
-
-.B Default:
- protocol = NT1
-
-.B Example:
- protocol = LANMAN1
-.SS public (S)
-A synonym for this parameter is 'guest ok'.
-
-If this parameter is 'yes' for a service, then no password is required
-to connect to the service. Privileges will be those of the guest
-account.
-
-See the section below on user/password validation for more information about
-this option.
-
-.B Default:
- public = no
-
-.B Example:
- public = yes
-.SS read list (S)
-This is a list of users that are given read-only access to a
-service. If the connecting user is in this list then they will
-not be given write access, no matter what the "read only" option
-is set to. The list can include group names using the @group syntax.
-
-See also the "write list" option
-
-.B Default:
- read list =
-
-.B Example:
- read list = mary, @students
-
-.SS read only (S)
-See
-.B writable
-and
-.B write ok.
-Note that this is an inverted synonym for writable and write ok.
-.SS read prediction (G)
-This options enables or disables the read prediction code used to
-speed up reads from the server. When enabled the server will try to
-pre-read data from the last accessed file that was opened read-only
-while waiting for packets.
-
-.SS Default:
- read prediction = False
-
-.SS Example:
- read prediction = True
-.SS read raw (G)
-This parameter controls whether or not the server will support raw reads when
-transferring data to clients.
-
-If enabled, raw reads allow reads of 65535 bytes in one packet. This
-typically provides a major performance benefit.
-
-However, some clients either negotiate the allowable block size incorrectly
-or are incapable of supporting larger block sizes, and for these clients you
-may need to disable raw reads.
-
-In general this parameter should be viewed as a system tuning tool and left
-severely alone. See also
-.B write raw.
-
-.B Default:
- read raw = yes
-
-.B Example:
- read raw = no
-.SS read size (G)
-
-The option "read size" affects the overlap of disk reads/writes with
-network reads/writes. If the amount of data being transferred in
-several of the SMB commands (currently SMBwrite, SMBwriteX and
-SMBreadbraw) is larger than this value then the server begins writing
-the data before it has received the whole packet from the network, or
-in the case of SMBreadbraw, it begins writing to the network before
-all the data has been read from disk.
-
-This overlapping works best when the speeds of disk and network access
-are similar, having very little effect when the speed of one is much
-greater than the other.
-
-The default value is 2048, but very little experimentation has been
-done yet to determine the optimal value, and it is likely that the best
-value will vary greatly between systems anyway. A value over 65536 is
-pointless and will cause you to allocate memory unnecessarily.
-
-.B Default:
- read size = 2048
-
-.B Example:
- read size = 8192
-
-.SS revalidate (S)
-
-This options controls whether Samba will allow a previously validated
-username/password pair to be used to attach to a share. Thus if you
-connect to \\\\server\\share1 then to \\\\server\\share2 it won't
-automatically allow the client to request connection to the second
-share as the same username as the first without a password.
-
-If "revalidate" is True then the client will be denied automatic
-access as the same username.
-
-.B Default:
- revalidate = False
-
-.B Example:
- revalidate = True
-
-.SS root (G)
-See
-.B root directory.
-.SS root dir (G)
-See
-.B root directory.
-.SS root directory (G)
-Synonyms for this parameter are 'root dir' and 'root'.
-
-The server will chroot() to this directory on startup. This is not
-strictly necessary for secure operation. Even without it the server
-will deny access to files not in one of the service entries. It may
-also check for, and deny access to, soft links to other parts of the
-filesystem, or attempts to use .. in file names to access other
-directories (depending on the setting of the "wide links" parameter).
-
-Adding a "root dir" entry other than "/" adds an extra level of security,
-but at a price. It absolutely ensures that no access is given to files not
-in the sub-tree specified in the "root dir" option, *including* some files
-needed for complete operation of the server. To maintain full operability
-of the server you will need to mirror some system files into the "root dir"
-tree. In particular you will need to mirror /etc/passwd (or a subset of it),
-and any binaries or configuration files needed for printing (if required).
-The set of files that must be mirrored is operating system dependent.
-
-.B Default:
- root directory = /
-
-.B Example:
- root directory = /homes/smb
-.SS security (G)
-This option does affects how clients respond to Samba.
-
-The option sets the "security mode bit" in replies to protocol negotiations
-to turn share level security on or off. Clients decide based on this bit
-whether (and how) to transfer user and password information to the server.
-
-The default is "security=SHARE", mainly because that was the only
-option at one stage.
-
-The alternatives are "security = user" or "security = server".
-
-If your PCs use usernames that are the same as their usernames on the
-unix machine then you will want to use "security = user". If you
-mostly use usernames that don't exist on the unix box then use
-"security = share".
-
-There is a bug in WfWg that may affect your decision. When in user
-level security a WfWg client will totally ignore the password you type
-in the "connect drive" dialog box. This makes it very difficult (if
-not impossible) to connect to a Samba service as anyone except the
-user that you are logged into WfWg as.
-
-If you use "security = server" then Samba will try to validate the
-username/password by passing it to another SMB server, such as an NT
-box. If this fails it will revert to "security = USER".
-
-See the "password server" option for more details.
-
-.B Default:
- security = SHARE
-
-.B Example:
- security = USER
-.SS server string (G)
-This controls what string will show up in the printer comment box in
-print manager and next to the IPC connection in "net view". It can be
-any string that you wish to show to your users.
-
-Note that it DOES NOT affect the string that appears in browse
-lists. That is controlled by a nmbd command line option instead.
-
-A %v will be replaced with the Samba version number.
-
-A %h will be replaced with the hostname.
-
-.B Default:
- server string = Samba %v
-
-.B Example:
- server string = University of GNUs Samba Server
-
-.SS smbrun (G)
-This sets the full path to the smbrun binary. This defaults to the
-value in the Makefile.
-
-You must get this path right for many services to work correctly.
-
-.B Default: taken from Makefile
-
-.B Example:
- smbrun = /usr/local/samba/bin/smbrun
-
-.SS short preserve case (S)
-
-This controls if new short filenames are created with the case that
-the client passes, or if they are forced to be the "default" case.
-
-.B Default:
- short preserve case = no
-
-See the section on "NAME MANGLING" for a fuller discussion.
-
-.SS root preexec (S)
-
-This is the same as preexec except that the command is run as
-root. This is useful for mounting filesystems (such as cdroms) before
-a connection is finalised.
-
-.SS root postexec (S)
-
-This is the same as postexec except that the command is run as
-root. This is useful for unmounting filesystems (such as cdroms) after
-a connection is closed.
-
-.SS set directory (S)
-If 'set directory = no', then users of the service may not use the setdir
-command to change directory.
-
-The setdir comand is only implemented in the Digital Pathworks client. See the
-Pathworks documentation for details.
-.B Default:
- set directory = no
-
-.B Example:
- set directory = yes
-
-.SS share modes (S)
-
-This enables or disables the honouring of the "share modes" during a
-file open. These modes are used by clients to gain exclusive read or
-write access to a file.
-
-These open modes are not directly supported by unix, so they are
-simulated using lock files in the "lock directory". The "lock
-directory" specified in smb.conf must be readable by all users.
-
-The share modes that are enabled by this option are DENY_DOS,
-DENY_ALL, DENY_READ, DENY_WRITE, DENY_NONE and DENY_FCB.
-
-Enabling this option gives full share compatability but may cost a bit
-of processing time on the unix server. They are enabled by default.
-
-.B Default:
- share modes = yes
-
-.B Example:
- share modes = no
-
-.SS socket options (G)
-This option (which can also be invoked with the -O command line
-option) allows you to set socket options to be used when talking with
-the client.
-
-Socket options are controls on the networking layer of the operating
-systems which allow the connection to be tuned.
-
-This option will typically be used to tune your Samba server for
-optimal performance for your local network. There is no way that Samba
-can know what the optimal parameters are for your net, so you must
-experiment and choose them yourself. I strongly suggest you read the
-appropriate documentation for your operating system first (perhaps
-"man setsockopt" will help).
-
-You may find that on some systems Samba will say "Unknown socket
-option" when you supply an option. This means you either mis-typed it
-or you need to add an include file to includes.h for your OS. If the
-latter is the case please send the patch to me
-(samba-bugs@anu.edu.au).
-
-Any of the supported socket options may be combined in any way you
-like, as long as your OS allows it.
-
-This is the list of socket options currently settable using this
-option:
-
- SO_KEEPALIVE
-
- SO_REUSEADDR
-
- SO_BROADCAST
-
- TCP_NODELAY
-
- IPTOS_LOWDELAY
-
- IPTOS_THROUGHPUT
-
- SO_SNDBUF *
-
- SO_RCVBUF *
-
- SO_SNDLOWAT *
-
- SO_RCVLOWAT *
-
-Those marked with a * take an integer argument. The others can
-optionally take a 1 or 0 argument to enable or disable the option, by
-default they will be enabled if you don't specify 1 or 0.
-
-To specify an argument use the syntax SOME_OPTION=VALUE for example
-SO_SNDBUF=8192. Note that you must not have any spaces before or after
-the = sign.
-
-If you are on a local network then a sensible option might be
-
-socket options = IPTOS_LOWDELAY
-
-If you have an almost unloaded local network and you don't mind a lot
-of extra CPU usage in the server then you could try
-
-socket options = IPTOS_LOWDELAY TCP_NODELAY
-
-If you are on a wide area network then perhaps try setting
-IPTOS_THROUGHPUT.
-
-Note that several of the options may cause your Samba server to fail
-completely. Use these options with caution!
-
-.B Default:
- no socket options
-
-.B Example:
- socket options = IPTOS_LOWDELAY
-
-
-
-
-.SS status (G)
-This enables or disables logging of connections to a status file that
-smbstatus can read.
-
-With this disabled smbstatus won't be able to tell you what
-connections are active.
-
-.B Default:
- status = yes
-
-.B Example:
- status = no
-
-.SS strip dot (G)
-This is a boolean that controls whether to strup trailing dots off
-filenames. This helps with some CDROMs that have filenames ending in a
-single dot.
-
-NOTE: This option is now obsolete, and may be removed in future. You
-should use the "mangled map" option instead as it is much more
-general.
-
-.SS strict locking (S)
-This is a boolean that controls the handling of file locking in the
-server. When this is set to yes the server will check every read and
-write access for file locks, and deny access if locks exist. This can
-be slow on some systems.
-
-When strict locking is "no" the server does file lock checks only when
-the client explicitly asks for them.
-
-Well behaved clients always ask for lock checks when it is important,
-so in the vast majority of cases "strict locking = no" is preferable.
-
-.B Default:
- strict locking = no
-
-.B Example:
- strict locking = yes
-
-.SS sync always (S)
-
-This is a boolean parameter that controls whether writes will always
-be written to stable storage before the write call returns. If this is
-false then the server will be guided by the clients request in each
-write call (clients can set a bit indicating that a particular write
-should be synchronous). If this is true then every write will be
-followed by a fsync() call to ensure the data is written to disk.
-
-.B Default:
- sync always = no
-
-.B Example:
- sync always = yes
-
-.SS time offset (G)
-This parameter is a setting in minutes to add to the normal GMT to
-local time conversion. This is useful if you are serving a lot of PCs
-that have incorrect daylight saving time handling.
-
-.B Default:
- time offset = 0
-
-.B Example:
- time offset = 60
-
-.SS user (S)
-See
-.B username.
-.SS username (S)
-A synonym for this parameter is 'user'.
-
-Multiple users may be specified in a comma-delimited list, in which case the
-supplied password will be tested against each username in turn (left to right).
-
-The username= line is needed only when the PC is unable to supply it's own
-username. This is the case for the coreplus protocol or where your
-users have different WfWg usernames to unix usernames. In both these
-cases you may also be better using the \\\\server\\share%user syntax
-instead.
-
-The username= line is not a great solution in many cases as it means Samba
-will try to validate the supplied password against each of the
-usernames in the username= line in turn. This is slow and a bad idea for
-lots of users in case of duplicate passwords. You may get timeouts or
-security breaches using this parameter unwisely.
-
-Samba relies on the underlying unix security. This parameter does not
-restrict who can login, it just offers hints to the Samba server as to
-what usernames might correspond to the supplied password. Users can
-login as whoever they please and they will be able to do no more
-damage than if they started a telnet session. The daemon runs as the
-user that they log in as, so they cannot do anything that user cannot
-do.
-
-To restrict a service to a particular set of users you can use the
-"valid users=" line.
-
-If any of the usernames begin with a @ then the name will be looked up
-in the groups file and will expand to a list of all users in the group
-of that name. Note that searching though a groups file can take quite
-some time, and some clients may time out during the search.
-
-See the section below on username/password validation for more information
-on how this parameter determines access to the services.
-
-.B Default:
- The guest account if a guest service, else the name of the service.
-
-.B Examples:
- username = fred
- username = fred, mary, jack, jane, @users, @pcgroup
-
-.SS username map (G)
-
-This option allows you to to specify a file containing a mapping of
-usernames from the clients to the server. This can be used for several
-purposes. The most common is to map usernames that users use on dos or
-windows machines to those that the unix box uses. The other is to map
-multiple users to a single username so that they can more easily share
-files.
-
-The map file is parsed line by line. Each line should contain a single
-unix username on the left then a '=' followed by a list of usernames
-on the right. The list of usernames on the right may contain names of
-the form @group in which case they will match any unix username in
-that group. The special client name '*' is a wildcard and matches any
-name.
-
-The file is processed on each line by taking the supplied username and
-comparing it with each username on the right hand side of the '='
-signs. If the supplied name matrches any of the names on the right
-hand side then it is replaced with the name on the left. Processing
-then continues with the next line.
-
-If any line begins with a '#' or a ';' then it is ignored
-
-For example to map from he name "admin" or "administrator" to the unix
-name "root" you would use
-
- root = admin administrator
-
-Or to map anyone in the unix group "system" to the unix name "sys" you
-would use
-
- sys = @system
-
-You can have as many mappings as you like in a username map file.
-
-Note that the remapping is applied to all occurances of
-usernames. Thus if you connect to "\\\\server\\fred" and "fred" is
-remapped to "mary" then you will actually be connecting to
-"\\\\server\\mary" and will need to supply a password suitable for
-"mary" not "fred". The only exception to this is the username passwed
-to the "password server" (if you have one). The password server will
-receive whatever username the client supplies without modification.
-
-Also note that no reverse mapping is done. The main effect this has is
-with printing. Users who have been mapped may have trouble deleting
-print jobs as PrintManager under WfWg will think they don't own the
-print job.
-
-.B Default
- no username map
-
-.B Example
- username map = /usr/local/samba/lib/users.map
-
-.SS valid chars (S)
-
-The option allows you to specify additional characters that should be
-considered valid by the server in filenames. This is particularly
-useful for national character sets, such as adding u-umlaut or a-ring.
-
-The option takes a list of characters in either integer or character
-form with spaces between them. If you give two characters with a colon
-between them then it will be taken as an lowercase:uppercase pair.
-
-If you have an editor capable of entering the characters into the
-config file then it is probably easiest to use this method. Otherwise
-you can specify the characters in octal, decimal or hexidecimal form
-using the usual C notation.
-
-For example to add the single character 'Z' to the charset (which is a
-pointless thing to do as it's already there) you could do one of the
-following
-
-valid chars = Z
-valid chars = z:Z
-valid chars = 0132:0172
-
-The last two examples above actually add two characters, and alters
-the uppercase and lowercase mappings appropriately.
-
-.B Default
- Samba defaults to using a reasonable set of valid characters
- for english systems
-
-.B Example
- valid chars = 0345:0305 0366:0326 0344:0304
-
-The above example allows filenames to have the swedish characters in
-them.
-
-.SS valid users (S)
-This is a list of users that should be allowed to login to this
-service. A name starting with @ is interpreted as a unix group.
-
-If this is empty (the default) then any user can login. If a username
-is in both this list and the "invalid users" list then access is
-denied for that user.
-
-The current servicename is substituted for %S. This is useful in the
-[homes] section.
-
-See also "invalid users"
-
-.B Default
- No valid users list. (anyone can login)
-
-.B Example
- valid users = greg, @pcusers
-
-.SS volume (S)
-This allows you to override the volume label returned for a
-share. Useful for CDROMs whos installation programs insist on a
-particular volume label.
-
-The default is the name of the share
-
-.SS wide links (S)
-This parameter controls whether or not links in the Unix file system may be
-followed by the server. Links that point to areas within the directory tree
-exported by the server are always allowed; this parameter controls access
-only to areas that are outside the directory tree being exported.
-
-.B Default:
- wide links = yes
-
-.B Example:
- wide links = no
-
-.SS workgroup (G)
-
-This controls what workgroup your server will appear to be in when
-queried by clients. This can be different to the workgroup specified
-in the nmbd configuration, but it is probably best if you set them to
-the same value.
-
-.B Default:
- set in the Makefile
-
-.B Example:
- workgroup = MYGROUP
+.sp
+.nf
+ print1|My Printer 1
+ print2|My Printer 2
+ print3|My Printer 3
+ print4|My Printer 4
+ print5|My Printer 5
+
+.sp
+.fi
+
+where the '|' separates aliases of a printer. The fact
+that the second alias has a space in it gives a hint to Samba
+that it's a comment.
+
+\fBNOTE\fR: Under AIX the default printcap
+name is \fI/etc/qconfig\fR. Samba will assume the
+file is in AIX \fIqconfig\fR format if the string
+\fIqconfig\fR appears in the printcap filename.
+
+Default: \fBprintcap name = /etc/printcap\fR
+
+Example: \fBprintcap name = /etc/myprintcap\fR
+.TP
+\fBprinter admin (S)\fR
+This is a list of users that can do anything to
+printers via the remote administration interfaces offered by MS-RPC
+(usually using a NT workstation). Note that the root user always
+has admin rights.
+
+Default: \fBprinter admin = <empty string>\fR
+
+Example: \fBprinter admin = admin, @staff\fR
+.TP
+\fBprinter driver (S)\fR
+\fBNote :\fRThis is a deprecated
+parameter and will be removed in the next major release
+following version 2.2. Please see the instructions in
+the Samba 2.2. Printing
+HOWTOfor more information
+on the new method of loading printer drivers onto a Samba server.
+
+This option allows you to control the string
+that clients receive when they ask the server for the printer driver
+associated with a printer. If you are using Windows95 or Windows NT
+then you can use this to automate the setup of printers on your
+system.
+
+You need to set this parameter to the exact string (case
+sensitive) that describes the appropriate printer driver for your
+system. If you don't know the exact string to use then you should
+first try with no \fI printer driver\fR option set and the client will
+give you a list of printer drivers. The appropriate strings are
+shown in a scroll box after you have chosen the printer manufacturer.
+
+See also \fIprinter
+driver file\fR.
+
+Example: \fBprinter driver = HP LaserJet 4L\fR
+.TP
+\fBprinter driver file (G)\fR
+\fBNote :\fRThis is a deprecated
+parameter and will be removed in the next major release
+following version 2.2. Please see the instructions in
+the Samba 2.2. Printing
+HOWTOfor more information
+on the new method of loading printer drivers onto a Samba server.
+
+This parameter tells Samba where the printer driver
+definition file, used when serving drivers to Windows 95 clients, is
+to be found. If this is not set, the default is :
+
+\fISAMBA_INSTALL_DIRECTORY
+/lib/printers.def\fR
+
+This file is created from Windows 95 \fImsprint.inf
+\fRfiles found on the Windows 95 client system. For more
+details on setting up serving of printer drivers to Windows 95
+clients, see the outdated documentation file in the \fIdocs/\fR
+directory, \fIPRINTER_DRIVER.txt\fR.
+
+See also \fI printer driver location\fR.
+
+Default: \fBNone (set in compile).\fR
+
+Example: \fBprinter driver file =
+/usr/local/samba/printers/drivers.def\fR
+.TP
+\fBprinter driver location (S)\fR
+\fBNote :\fRThis is a deprecated
+parameter and will be removed in the next major release
+following version 2.2. Please see the instructions in
+the Samba 2.2. Printing
+HOWTOfor more information
+on the new method of loading printer drivers onto a Samba server.
+
+This parameter tells clients of a particular printer
+share where to find the printer driver files for the automatic
+installation of drivers for Windows 95 machines. If Samba is set up
+to serve printer drivers to Windows 95 machines, this should be set to
+
+\fB\\\\MACHINE\\PRINTER$\fR
+
+Where MACHINE is the NetBIOS name of your Samba server,
+and PRINTER$ is a share you set up for serving printer driver
+files. For more details on setting this up see the outdated documentation
+file in the \fIdocs/\fR directory, \fI PRINTER_DRIVER.txt\fR.
+
+See also \fI printer driver file\fR.
+
+Default: \fBnone\fR
+
+Example: \fBprinter driver location = \\\\MACHINE\\PRINTER$
+\fR.TP
+\fBprinter name (S)\fR
+This parameter specifies the name of the printer
+to which print jobs spooled through a printable service will be sent.
+
+If specified in the [global] section, the printer
+name given will be used for any printable service that does
+not have its own printer name specified.
+
+Default: \fBnone (but may be lp
+on many systems)\fR
+
+Example: \fBprinter name = laserwriter\fR
+.TP
+\fBprinter (S)\fR
+Synonym for \fI printer name\fR.
+.TP
+\fBprinting (S)\fR
+This parameters controls how printer status
+information is interpreted on your system. It also affects the
+default values for the \fIprint command\fR,
+\fIlpq command\fR, \fIlppause command
+\fR, \fIlpresume command\fR, and
+\fIlprm command\fR if specified in the
+[global] section.
+
+Currently nine printing styles are supported. They are
+BSD, AIX,
+LPRNG, PLP,
+SYSV, HPUX,
+QNX, SOFTQ,
+and CUPS.
+
+To see what the defaults are for the other print
+commands when using the various options use the testparm(1)program.
+
+This option can be set on a per printer basis
+
+See also the discussion in the [printers] section.
+.TP
+\fBprotocol (G)\fR
+Synonym for \fImax protocol\fR.
+.TP
+\fBpublic (S)\fR
+Synonym for \fIguest
+ok\fR.
+.TP
+\fBqueuepause command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to pause the printer queue.
+
+This command should be a program or script which takes
+a printer name as its only parameter and stops the printer queue,
+such that no longer jobs are submitted to the printer.
+
+This command is not supported by Windows for Workgroups,
+but can be issued from the Printers window under Windows 95
+and NT.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. Otherwise it is placed at the end of the command.
+
+Note that it is good practice to include the absolute
+path in the command as the PATH may not be available to the
+server.
-.SS write ok (S)
-See
-.B writable
-and
-.B read only.
-.SS writable (S)
-A synonym for this parameter is 'write ok'. An inverted synonym is 'read only'.
-
-If this parameter is 'no', then users of a service may not create or modify
-files in the service's directory.
-
-Note that a printable service ('printable = yes') will ALWAYS allow
-writing to the directory (user privileges permitting), but only via
-spooling operations.
-
-.B Default:
- writable = no
-
-.B Examples:
- read only = no
- writable = yes
- write ok = yes
-.SS write list (S)
-This is a list of users that are given read-write access to a
-service. If the connecting user is in this list then they will be
-given write access, no matter what the "read only" option is set
-to. The list can include group names using the @group syntax.
-
-Note that if a user is in both the read list and the write list then
-they will be given write access.
-
-See also the "read list" option
-
-.B Default:
- write list =
-
-.B Example:
- write list = admin, root, @staff
-
-.SS write raw (G)
-This parameter controls whether or not the server will support raw writes when
-transferring data from clients.
-
-.B Default:
- write raw = yes
-
-.B Example:
- write raw = no
-.SH NOTE ABOUT USERNAME/PASSWORD VALIDATION
-There are a number of ways in which a user can connect to a
-service. The server follows the following steps in determining if it
-will allow a connection to a specified service. If all the steps fail
-then the connection request is rejected. If one of the steps pass then
-the following steps are not checked.
-
-If the service is marked "guest only = yes" then steps 1 to 5 are skipped
-
-Step 1: If the client has passed a username/password pair and that
-username/password pair is validated by the unix systems password
-programs then the connection is made as that username. Note that this
-includes the \\\\server\\service%username method of passing a username.
-
-Step 2: If the client has previously registered a username with the
-system and now supplies a correct password for that username then the
-connection is allowed.
-
-Step 3: The clients netbios name and any previously used user names
-are checked against the supplied password, if they match then the
-connection is allowed as the corresponding user.
-
-Step 4: If the client has previously validated a username/password
-pair with the server and the client has passed the validation token
-then that username is used. This step is skipped if "revalidate = yes"
-for this service.
-
-Step 5: If a "user = " field is given in the smb.conf file for the
-service and the client has supplied a password, and that password
-matches (according to the unix systems password checking) with one of
-the usernames from the user= field then the connection is made as the
-username in the "user=" line. If one of the username in the user= list
-begins with a @ then that name expands to a list of names in the group
-of the same name.
-
-Step 6: If the service is a guest service then a connection is made as
-the username given in the "guest account =" for the service,
-irrespective of the supplied password.
-
-
-.SH WARNINGS
-Although the configuration file permits service names to contain spaces,
-your client software may not. Spaces will be ignored in comparisons anyway,
-so it shouldn't be a problem - but be aware of the possibility.
-
-On a similar note, many clients - especially DOS clients - limit service
-names to eight characters. Smbd has no such limitation, but attempts
-to connect from such clients will fail if they truncate the service names.
-For this reason you should probably keep your service names down to eight
-characters in length.
-
-Use of the [homes] and [printers] special sections make life for an
-administrator easy, but the various combinations of default attributes can be
-tricky. Take extreme care when designing these sections. In particular,
-ensure that the permissions on spool directories are correct.
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the server has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-
-Prior to version 1.5.21 of the Samba suite, the configuration file was
-radically different (more primitive). If you are using a version earlier than
-1.8.05, it is STRONGLY recommended that you upgrade.
-.SH OPTIONS
-Not applicable.
-
-.SH FILES
-Not applicable.
-
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH SEE ALSO
-.B smbd(8),
-.B smbclient(1),
-.B nmbd(8),
-.B testparm(1),
-.B testprns(1),
-.B lpq(1),
-.B hosts_access(5)
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the server are logged in a specified log file. The
-log file name is specified at compile time, but may be overridden on the
-smbd (see smbd(8)) command line.
-
-The number and nature of diagnostics available depends on the debug level used
-by the server. If you have problems, set the debug level to 3 and peruse the
-log files.
-
-Most messages are reasonably self-explanatory. Unfortunately, at time of
-creation of this man page the source code is still too fluid to warrant
-describing each and every diagnostic. At this stage your best bet is still
-to grep the source code and inspect the conditions that gave rise to the
-diagnostics you are seeing.
-
-.SH BUGS
-None known.
-
-Please send bug reports, comments and so on to:
-
-.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
-
-.RS 3
-or to the mailing list
-.RE
+Default: \fBdepends on the setting of \fIprinting
+\fB\fR
+Example: \fBqueuepause command = disable %p\fR
+.TP
+\fBqueueresume command (S)\fR
+This parameter specifies the command to be
+executed on the server host in order to resume the printer queue. It
+is the command to undo the behavior that is caused by the
+previous parameter (\fI queuepause command\fR).
+
+This command should be a program or script which takes
+a printer name as its only parameter and resumes the printer queue,
+such that queued jobs are resubmitted to the printer.
+
+This command is not supported by Windows for Workgroups,
+but can be issued from the Printers window under Windows 95
+and NT.
+
+If a \fI%p\fR is given then the printer name
+is put in its place. Otherwise it is placed at the end of the
+command.
-.B samba@listproc.anu.edu.au
+Note that it is good practice to include the absolute
+path in the command as the PATH may not be available to the
+server.
+Default: \fBdepends on the setting of \fIprinting\fB\fR
+
+Example: \fBqueuepause command = enable %p
+\fR.TP
+\fBread bmpx (G)\fR
+This boolean parameter controls whether smbd(8)will support the "Read
+Block Multiplex" SMB. This is now rarely used and defaults to
+no. You should never need to set this
+parameter.
+
+Default: \fBread bmpx = no\fR
+.TP
+\fBread list (S)\fR
+This is a list of users that are given read-only
+access to a service. If the connecting user is in this list then
+they will not be given write access, no matter what the \fIwriteable\fR
+option is set to. The list can include group names using the
+syntax described in the \fI invalid users\fR parameter.
+
+See also the \fI write list\fR parameter and the \fIinvalid users\fR
+parameter.
+
+Default: \fBread list = <empty string>\fR
+
+Example: \fBread list = mary, @students\fR
+.TP
+\fBread only (S)\fR
+Note that this is an inverted synonym for \fIwriteable\fR.
+.TP
+\fBread raw (G)\fR
+This parameter controls whether or not the server
+will support the raw read SMB requests when transferring data
+to clients.
+
+If enabled, raw reads allow reads of 65535 bytes in
+one packet. This typically provides a major performance benefit.
+
+However, some clients either negotiate the allowable
+block size incorrectly or are incapable of supporting larger block
+sizes, and for these clients you may need to disable raw reads.
+
+In general this parameter should be viewed as a system tuning
+tool and left severely alone. See also \fIwrite raw\fR.
+
+Default: \fBread raw = yes\fR
+.TP
+\fBread size (G)\fR
+The option \fIread size\fR
+affects the overlap of disk reads/writes with network reads/writes.
+If the amount of data being transferred in several of the SMB
+commands (currently SMBwrite, SMBwriteX and SMBreadbraw) is larger
+than this value then the server begins writing the data before it
+has received the whole packet from the network, or in the case of
+SMBreadbraw, it begins writing to the network before all the data
+has been read from disk.
+
+This overlapping works best when the speeds of disk and
+network access are similar, having very little effect when the
+speed of one is much greater than the other.
+
+The default value is 16384, but very little experimentation
+has been done yet to determine the optimal value, and it is likely
+that the best value will vary greatly between systems anyway.
+A value over 65536 is pointless and will cause you to allocate
+memory unnecessarily.
+
+Default: \fBread size = 16384\fR
+
+Example: \fBread size = 8192\fR
+.TP
+\fBremote announce (G)\fR
+This option allows you to setup nmbd(8)to periodically announce itself
+to arbitrary IP addresses with an arbitrary workgroup name.
+
+This is useful if you want your Samba server to appear
+in a remote workgroup for which the normal browse propagation
+rules don't work. The remote workgroup can be anywhere that you
+can send IP packets to.
+
+For example:
+
+\fBremote announce = 192.168.2.255/SERVERS
+192.168.4.255/STAFF\fR
+
+the above line would cause \fBnmbd\fR to announce itself
+to the two given IP addresses using the given workgroup names.
+If you leave out the workgroup name then the one given in
+the \fIworkgroup\fR
+parameter is used instead.
+
+The IP addresses you choose would normally be the broadcast
+addresses of the remote networks, but can also be the IP addresses
+of known browse masters if your network config is that stable.
+
+See the documentation file \fIBROWSING.txt\fR
+in the \fIdocs/\fR directory.
+
+Default: \fBremote announce = <empty string>
+\fR.TP
+\fBremote browse sync (G)\fR
+This option allows you to setup nmbd(8)to periodically request
+synchronization of browse lists with the master browser of a Samba
+server that is on a remote segment. This option will allow you to
+gain browse lists for multiple workgroups across routed networks. This
+is done in a manner that does not work with any non-Samba servers.
+
+This is useful if you want your Samba server and all local
+clients to appear in a remote workgroup for which the normal browse
+propagation rules don't work. The remote workgroup can be anywhere
+that you can send IP packets to.
+
+For example:
+
+\fBremote browse sync = 192.168.2.255 192.168.4.255
+\fR
+the above line would cause \fBnmbd\fR to request
+the master browser on the specified subnets or addresses to
+synchronize their browse lists with the local server.
+
+The IP addresses you choose would normally be the broadcast
+addresses of the remote networks, but can also be the IP addresses
+of known browse masters if your network config is that stable. If
+a machine IP address is given Samba makes NO attempt to validate
+that the remote machine is available, is listening, nor that it
+is in fact the browse master on its segment.
+
+Default: \fBremote browse sync = <empty string>
+\fR.TP
+\fBrestrict anonymous (G)\fR
+This is a boolean parameter. If it is true, then
+anonymous access to the server will be restricted, namely in the
+case where the server is expecting the client to send a username,
+but it doesn't. Setting it to true will force these anonymous
+connections to be denied, and the client will be required to always
+supply a username and password when connecting. Use of this parameter
+is only recommended for homogeneous NT client environments.
+
+This parameter makes the use of macro expansions that rely
+on the username (%U, %G, etc) consistent. NT 4.0
+likes to use anonymous connections when refreshing the share list,
+and this is a way to work around that.
+
+When restrict anonymous is true, all anonymous connections
+are denied no matter what they are for. This can effect the ability
+of a machine to access the Samba Primary Domain Controller to revalidate
+its machine account after someone else has logged on the client
+interactively. The NT client will display a message saying that
+the machine's account in the domain doesn't exist or the password is
+bad. The best way to deal with this is to reboot NT client machines
+between interactive logons, using "Shutdown and Restart", rather
+than "Close all programs and logon as a different user".
+
+Default: \fBrestrict anonymous = no\fR
+.TP
+\fBroot (G)\fR
+Synonym for \fIroot directory"\fR.
+.TP
+\fBroot dir (G)\fR
+Synonym for \fIroot directory"\fR.
+.TP
+\fBroot directory (G)\fR
+The server will \fBchroot()\fR (i.e.
+Change its root directory) to this directory on startup. This is
+not strictly necessary for secure operation. Even without it the
+server will deny access to files not in one of the service entries.
+It may also check for, and deny access to, soft links to other
+parts of the filesystem, or attempts to use ".." in file names
+to access other directories (depending on the setting of the \fIwide links\fR
+parameter).
+
+Adding a \fIroot directory\fR entry other
+than "/" adds an extra level of security, but at a price. It
+absolutely ensures that no access is given to files not in the
+sub-tree specified in the \fIroot directory\fR
+option, \fBincluding\fR some files needed for
+complete operation of the server. To maintain full operability
+of the server you will need to mirror some system files
+into the \fIroot directory\fR tree. In particular
+you will need to mirror \fI/etc/passwd\fR (or a
+subset of it), and any binaries or configuration files needed for
+printing (if required). The set of files that must be mirrored is
+operating system dependent.
+
+Default: \fBroot directory = /\fR
+
+Example: \fBroot directory = /homes/smb\fR
+.TP
+\fBroot postexec (S)\fR
+This is the same as the \fIpostexec\fR
+parameter except that the command is run as root. This
+is useful for unmounting filesystems
+(such as CDROMs) after a connection is closed.
+
+See also \fI postexec\fR.
+
+Default: \fBroot postexec = <empty string>
+\fR.TP
+\fBroot preexec (S)\fR
+This is the same as the \fIpreexec\fR
+parameter except that the command is run as root. This
+is useful for mounting filesystems (such as CDROMs) when a
+connection is opened.
+
+See also \fI preexec\fR and \fIpreexec close\fR.
+
+Default: \fBroot preexec = <empty string>
+\fR.TP
+\fBroot preexec close (S)\fR
+This is the same as the \fIpreexec close
+\fRparameter except that the command is run as root.
+
+See also \fI preexec\fR and \fIpreexec close\fR.
+
+Default: \fBroot preexec close = no\fR
+.TP
+\fBsecurity (G)\fR
+This option affects how clients respond to
+Samba and is one of the most important settings in the \fI smb.conf\fR file.
+
+The option sets the "security mode bit" in replies to
+protocol negotiations with smbd(8)
+to turn share level security on or off. Clients decide
+based on this bit whether (and how) to transfer user and password
+information to the server.
+
+The default is \fBsecurity = user\fR, as this is
+the most common setting needed when talking to Windows 98 and
+Windows NT.
+
+The alternatives are \fBsecurity = share\fR,
+\fBsecurity = server\fR or \fBsecurity = domain
+\fR\&.
+
+In versions of Samba prior to 2.0.0, the default was
+\fBsecurity = share\fR mainly because that was
+the only option at one stage.
+
+There is a bug in WfWg that has relevance to this
+setting. When in user or server level security a WfWg client
+will totally ignore the password you type in the "connect
+drive" dialog box. This makes it very difficult (if not impossible)
+to connect to a Samba service as anyone except the user that
+you are logged into WfWg as.
+
+If your PCs use usernames that are the same as their
+usernames on the UNIX machine then you will want to use
+\fBsecurity = user\fR. If you mostly use usernames
+that don't exist on the UNIX box then use \fBsecurity =
+share\fR.
+
+You should also use \fBsecurity = share\fR if you
+want to mainly setup shares without a password (guest shares). This
+is commonly used for a shared printer server. It is more difficult
+to setup guest shares with \fBsecurity = user\fR, see
+the \fImap to guest\fR
+parameter for details.
+
+It is possible to use \fBsmbd\fR in a \fB hybrid mode\fR where it is offers both user and share
+level security under different \fINetBIOS aliases\fR.
+
+The different settings will now be explained.
+
+\fBSECURITY = SHARE
+\fR
+When clients connect to a share level security server they
+need not log onto the server with a valid username and password before
+attempting to connect to a shared resource (although modern clients
+such as Windows 95/98 and Windows NT will send a logon request with
+a username but no password when talking to a \fBsecurity = share
+\fRserver). Instead, the clients send authentication information
+(passwords) on a per-share basis, at the time they attempt to connect
+to that share.
+
+Note that \fBsmbd\fR \fBALWAYS\fR
+uses a valid UNIX user to act on behalf of the client, even in
+\fBsecurity = share\fR level security.
+
+As clients are not required to send a username to the server
+in share level security, \fBsmbd\fR uses several
+techniques to determine the correct UNIX user to use on behalf
+of the client.
+
+A list of possible UNIX usernames to match with the given
+client password is constructed using the following methods :
+.RS
+.TP 0.2i
+\(bu
+If the \fIguest
+only\fR parameter is set, then all the other
+stages are missed and only the \fIguest account\fR username is checked.
+.TP 0.2i
+\(bu
+Is a username is sent with the share connection
+request, then this username (after mapping - see \fIusername map\fR),
+is added as a potential username.
+.TP 0.2i
+\(bu
+If the client did a previous \fBlogon
+\fRrequest (the SessionSetup SMB call) then the
+username sent in this SMB will be added as a potential username.
+.TP 0.2i
+\(bu
+The name of the service the client requested is
+added as a potential username.
+.TP 0.2i
+\(bu
+The NetBIOS name of the client is added to
+the list as a potential username.
+.TP 0.2i
+\(bu
+Any users on the \fI user\fR list are added as potential usernames.
.RE
-You may also like to subscribe to the announcement channel
+.PP
+If the \fIguest only\fR parameter is
+not set, then this list is then tried with the supplied password.
+The first user for whom the password matches will be used as the
+UNIX user.
+.PP
+.PP
+If the \fIguest only\fR parameter is
+set, or no username can be determined then if the share is marked
+as available to the \fIguest account\fR, then this
+guest user will be used, otherwise access is denied.
+.PP
+.PP
+Note that it can be \fBvery\fR confusing
+in share-level security as to which UNIX username will eventually
+be used in granting access.
+.PP
+.PP
+See also the section NOTE ABOUT USERNAME/PASSWORD VALIDATION.
+.PP
+.PP
+\fBSECURITY = USER
+\fR.PP
+.PP
+This is the default security setting in Samba 2.2.
+With user-level security a client must first "log-on" with a
+valid username and password (which can be mapped using the \fIusername map\fR
+parameter). Encrypted passwords (see the \fIencrypted passwords\fR parameter) can also
+be used in this security mode. Parameters such as \fIuser\fR and \fIguest only\fR if set are then applied and
+may change the UNIX user to use on this connection, but only after
+the user has been successfully authenticated.
+.PP
+.PP
+\fBNote\fR that the name of the resource being
+requested is \fBnot\fR sent to the server until after
+the server has successfully authenticated the client. This is why
+guest shares don't work in user level security without allowing
+the server to automatically map unknown users into the \fIguest account\fR.
+See the \fImap to guest\fR
+parameter for details on doing this.
+.PP
+.PP
+See also the section NOTE ABOUT USERNAME/PASSWORD VALIDATION.
+.PP
+.PP
+\fBSECURITY = SERVER
+\fR.PP
+.PP
+In this mode Samba will try to validate the username/password
+by passing it to another SMB server, such as an NT box. If this
+fails it will revert to \fBsecurity = user\fR, but note
+that if encrypted passwords have been negotiated then Samba cannot
+revert back to checking the UNIX password file, it must have a valid
+\fIsmbpasswd\fR file to check users against. See the
+documentation file in the \fIdocs/\fR directory
+\fIENCRYPTION.txt\fR for details on how to set this
+up.
+.PP
+.PP
+\fBNote\fR that from the client's point of
+view \fBsecurity = server\fR is the same as \fB security = user\fR. It only affects how the server deals
+with the authentication, it does not in any way affect what the
+client sees.
+.PP
+.PP
+\fBNote\fR that the name of the resource being
+requested is \fBnot\fR sent to the server until after
+the server has successfully authenticated the client. This is why
+guest shares don't work in user level security without allowing
+the server to automatically map unknown users into the \fIguest account\fR.
+See the \fImap to guest\fR
+parameter for details on doing this.
+.PP
+.PP
+See also the section NOTE ABOUT USERNAME/PASSWORD VALIDATION.
+.PP
+.PP
+See also the \fIpassword
+server\fR parameter and the \fIencrypted passwords\fR
+parameter.
+.PP
+.PP
+\fBSECURITY = DOMAIN
+\fR.PP
+.PP
+This mode will only work correctly if smbpasswd(8)has been used to add this
+machine into a Windows NT Domain. It expects the \fIencrypted passwords\fR
+parameter to be set to true. In this
+mode Samba will try to validate the username/password by passing
+it to a Windows NT Primary or Backup Domain Controller, in exactly
+the same way that a Windows NT Server would do.
+.PP
+.PP
+\fBNote\fR that a valid UNIX user must still
+exist as well as the account on the Domain Controller to allow
+Samba to have a valid UNIX account to map file access to.
+.PP
+.PP
+\fBNote\fR that from the client's point
+of view \fBsecurity = domain\fR is the same as \fBsecurity = user
+\fR\&. It only affects how the server deals with the authentication,
+it does not in any way affect what the client sees.
+.PP
+.PP
+\fBNote\fR that the name of the resource being
+requested is \fBnot\fR sent to the server until after
+the server has successfully authenticated the client. This is why
+guest shares don't work in user level security without allowing
+the server to automatically map unknown users into the \fIguest account\fR.
+See the \fImap to guest\fR
+parameter for details on doing this.
+.PP
+.PP
+\fBBUG:\fR There is currently a bug in the
+implementation of \fBsecurity = domain\fR with respect
+to multi-byte character set usernames. The communication with a
+Domain Controller must be done in UNICODE and Samba currently
+does not widen multi-byte user names to UNICODE correctly, thus
+a multi-byte username will not be recognized correctly at the
+Domain Controller. This issue will be addressed in a future release.
+.PP
+.PP
+See also the section NOTE ABOUT USERNAME/PASSWORD VALIDATION.
+.PP
+.PP
+See also the \fIpassword
+server\fR parameter and the \fIencrypted passwords\fR
+parameter.
+.PP
+.PP
+Default: \fBsecurity = USER\fR
+.PP
+.PP
+Example: \fBsecurity = DOMAIN\fR
+.PP
+.TP
+\fBsecurity mask (S)\fR
+This parameter controls what UNIX permission
+bits can be modified when a Windows NT client is manipulating
+the UNIX permission on a file using the native NT security
+dialog box.
+
+This parameter is applied as a mask (AND'ed with) to
+the changed permission bits, thus preventing any bits not in
+this mask from being modified. Essentially, zero bits in this
+mask may be treated as a set of bits the user is not allowed
+to change.
+
+If not set explicitly this parameter is 0777, allowing
+a user to modify all the user/group/world permissions on a file.
+
+\fBNote\fR that users who can access the
+Samba server through other means can easily bypass this
+restriction, so it is primarily useful for standalone
+"appliance" systems. Administrators of most normal systems will
+probably want to leave it set to 0777.
+
+See also the \fIforce directory security mode\fR,
+\fIdirectory
+security mask\fR, \fIforce security mode\fR parameters.
+
+Default: \fBsecurity mask = 0777\fR
+
+Example: \fBsecurity mask = 0770\fR
+.TP
+\fBserver string (G)\fR
+This controls what string will show up in the
+printer comment box in print manager and next to the IPC connection
+in \fBnet view\fR. It can be any string that you wish
+to show to your users.
+
+It also sets what will appear in browse lists next
+to the machine name.
+
+A \fI%v\fR will be replaced with the Samba
+version number.
+
+A \fI%h\fR will be replaced with the
+hostname.
+
+Default: \fBserver string = Samba %v\fR
+
+Example: \fBserver string = University of GNUs Samba
+Server\fR
+.TP
+\fBset directory (S)\fR
+If \fBset directory = no\fR, then
+users of the service may not use the setdir command to change
+directory.
+
+The \fBsetdir\fR command is only implemented
+in the Digital Pathworks client. See the Pathworks documentation
+for details.
+
+Default: \fBset directory = no\fR
+.TP
+\fBshort preserve case (S)\fR
+This boolean parameter controls if new files
+which conform to 8.3 syntax, that is all in upper case and of
+suitable length, are created upper case, or if they are forced
+to be the \fIdefault case
+\fR\&. This option can be use with \fBpreserve case = yes\fR
+to permit long filenames to retain their case, while short
+names are lowered.
+
+See the section on NAME MANGLING.
+
+Default: \fBshort preserve case = yes\fR
+.TP
+\fBshow add printer wizard (G)\fR
+With the introduction of MS-RPC based printing support
+for Windows NT/2000 client in Samba 2.2, a "Printers..." folder will
+appear on Samba hosts in the share listing. Normally this folder will
+contain an icon for the MS Add Printer Wizard (APW). However, it is
+possible to disable this feature regardless of the level of privilege
+of the connected user.
+
+Under normal circumstances, the Windows NT/2000 client will
+open a handle on the printer server with OpenPrinterEx() asking for
+Administrator privileges. If the user does not have administrative
+access on the print server (i.e is not root or a member of the
+\fIprinter admin\fR group), the OpenPrinterEx()
+call fails and the client makes another open call with a request for
+a lower privilege level. This should succeed, however the APW
+icon will not be displayed.
+
+Disabling the \fIshow add printer wizard\fR
+parameter will always cause the OpenPrinterEx() on the server
+to fail. Thus the APW icon will never be displayed. \fB Note :\fRThis does not prevent the same user from having
+administrative privilege on an individual printer.
+
+See also \fIaddprinter
+command\fR, \fIdeleteprinter command\fR, \fIprinter admin\fR
+
+Default :\fBshow add printer wizard = yes\fR
+.TP
+\fBshutdown script (G)\fR
+\fBThis parameter only exists in the HEAD cvs branch\fR
+This a full path name to a script called by
+\fBsmbd(8)\fRthat
+should start a shutdown procedure.
+
+This command will be run as the user connected to the
+server.
-.RS 3
-samba-announce@listproc.anu.edu.au
+%m %t %r %f parameters are expanded
+
+\fI%m\fR will be substituted with the
+shutdown message sent to the server.
+
+\fI%t\fR will be substituted with the
+number of seconds to wait before effectively starting the
+shutdown procedure.
+
+\fI%r\fR will be substituted with the
+switch \fB-r\fR. It means reboot after shutdown
+for NT.
+
+\fI%f\fR will be substituted with the
+switch \fB-f\fR. It means force the shutdown
+even if applications do not respond for NT.
+
+Default: \fBNone\fR.
+
+Example: \fBabort shutdown script = /usr/local/samba/sbin/shutdown %m %t %r %f\fR
+
+Shutdown script example:
+.sp
+.nf
+ #!/bin/bash
+
+ $time=0
+ let "time/60"
+ let "time++"
+
+ /sbin/shutdown $3 $4 +$time $1 &
+
+.sp
+.fi
+Shutdown does not return so we need to launch it in background.
+
+See also \fIabort shutdown script\fR.
+.TP
+\fBsmb passwd file (G)\fR
+This option sets the path to the encrypted
+smbpasswd file. By default the path to the smbpasswd file
+is compiled into Samba.
+
+Default: \fBsmb passwd file = ${prefix}/private/smbpasswd
+\fR
+Example: \fBsmb passwd file = /etc/samba/smbpasswd
+\fR.TP
+\fBsocket address (G)\fR
+This option allows you to control what
+address Samba will listen for connections on. This is used to
+support multiple virtual interfaces on the one server, each
+with a different configuration.
+
+By default Samba will accept connections on any
+address.
+
+Example: \fBsocket address = 192.168.2.20\fR
+.TP
+\fBsocket options (G)\fR
+This option allows you to set socket options
+to be used when talking with the client.
+
+Socket options are controls on the networking layer
+of the operating systems which allow the connection to be
+tuned.
+
+This option will typically be used to tune your Samba
+server for optimal performance for your local network. There is
+no way that Samba can know what the optimal parameters are for
+your net, so you must experiment and choose them yourself. We
+strongly suggest you read the appropriate documentation for your
+operating system first (perhaps \fBman setsockopt\fR
+will help).
+
+You may find that on some systems Samba will say
+"Unknown socket option" when you supply an option. This means you
+either incorrectly typed it or you need to add an include file
+to includes.h for your OS. If the latter is the case please
+send the patch to samba@samba.org <URL:mailto:samba@samba.org>.
+
+Any of the supported socket options may be combined
+in any way you like, as long as your OS allows it.
+
+This is the list of socket options currently settable
+using this option:
+.RS
+.TP 0.2i
+\(bu
+SO_KEEPALIVE
+.TP 0.2i
+\(bu
+SO_REUSEADDR
+.TP 0.2i
+\(bu
+SO_BROADCAST
+.TP 0.2i
+\(bu
+TCP_NODELAY
+.TP 0.2i
+\(bu
+IPTOS_LOWDELAY
+.TP 0.2i
+\(bu
+IPTOS_THROUGHPUT
+.TP 0.2i
+\(bu
+SO_SNDBUF *
+.TP 0.2i
+\(bu
+SO_RCVBUF *
+.TP 0.2i
+\(bu
+SO_SNDLOWAT *
+.TP 0.2i
+\(bu
+SO_RCVLOWAT *
.RE
-
-To subscribe to these lists send a message to
-listproc@listproc.anu.edu.au with a body of "subscribe samba Your
-Name" or "subscribe samba-announce Your Name".
-
-Errors or suggestions for improvements to the Samba man pages should be
-mailed to:
-
-.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
+.PP
+Those marked with a \fB'*'\fR take an integer
+argument. The others can optionally take a 1 or 0 argument to enable
+or disable the option, by default they will be enabled if you
+don't specify 1 or 0.
+.PP
+.PP
+To specify an argument use the syntax SOME_OPTION = VALUE
+for example \fBSO_SNDBUF = 8192\fR. Note that you must
+not have any spaces before or after the = sign.
+.PP
+.PP
+If you are on a local network then a sensible option
+might be
+.PP
+.PP
+\fBsocket options = IPTOS_LOWDELAY\fR
+.PP
+.PP
+If you have a local network then you could try:
+.PP
+.PP
+\fBsocket options = IPTOS_LOWDELAY TCP_NODELAY\fR
+.PP
+.PP
+If you are on a wide area network then perhaps try
+setting IPTOS_THROUGHPUT.
+.PP
+.PP
+Note that several of the options may cause your Samba
+server to fail completely. Use these options with caution!
+.PP
+.PP
+Default: \fBsocket options = TCP_NODELAY\fR
+.PP
+.PP
+Example: \fBsocket options = IPTOS_LOWDELAY\fR
+.PP
+.TP
+\fBsource environment (G)\fR
+This parameter causes Samba to set environment
+variables as per the content of the file named.
+
+If the value of this parameter starts with a "|" character
+then Samba will treat that value as a pipe command to open and
+will set the environment variables from the output of the pipe.
+
+The contents of the file or the output of the pipe should
+be formatted as the output of the standard Unix \fBenv(1)
+\fRcommand. This is of the form :
+
+Example environment entry:
+
+\fBSAMBA_NETBIOS_NAME = myhostname\fR
+
+Default: \fBNo default value\fR
+
+Examples: \fBsource environment = |/etc/smb.conf.sh
+\fR
+Example: \fBsource environment =
+/usr/local/smb_env_vars\fR
+.TP
+\fBssl (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This variable enables or disables the entire SSL mode. If
+it is set to no, the SSL-enabled Samba behaves
+exactly like the non-SSL Samba. If set to yes,
+it depends on the variables \fI ssl hosts\fR and \fIssl hosts resign\fR whether an SSL
+connection will be required.
+
+Default: \fBssl = no\fR
+.TP
+\fBssl CA certDir (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This variable defines where to look up the Certification
+Authorities. The given directory should contain one file for
+each CA that Samba will trust. The file name must be the hash
+value over the "Distinguished Name" of the CA. How this directory
+is set up is explained later in this document. All files within the
+directory that don't fit into this naming scheme are ignored. You
+don't need this variable if you don't verify client certificates.
+
+Default: \fBssl CA certDir = /usr/local/ssl/certs
+\fR.TP
+\fBssl CA certFile (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This variable is a second way to define the trusted CAs.
+The certificates of the trusted CAs are collected in one big
+file and this variable points to the file. You will probably
+only use one of the two ways to define your CAs. The first choice is
+preferable if you have many CAs or want to be flexible, the second
+is preferable if you only have one CA and want to keep things
+simple (you won't need to create the hashed file names). You
+don't need this variable if you don't verify client certificates.
+
+Default: \fBssl CA certFile = /usr/local/ssl/certs/trustedCAs.pem
+\fR.TP
+\fBssl ciphers (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This variable defines the ciphers that should be offered
+during SSL negotiation. You should not set this variable unless
+you know what you are doing.
+.TP
+\fBssl client cert (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+The certificate in this file is used by \fBsmbclient(1)\fRif it exists. It's needed
+if the server requires a client certificate.
+
+Default: \fBssl client cert = /usr/local/ssl/certs/smbclient.pem
+\fR.TP
+\fBssl client key (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This is the private key for \fBsmbclient(1)\fR. It's only needed if the
+client should have a certificate.
+
+Default: \fBssl client key = /usr/local/ssl/private/smbclient.pem
+\fR.TP
+\fBssl compatibility (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This variable defines whether OpenSSL should be configured
+for bug compatibility with other SSL implementations. This is
+probably not desirable because currently no clients with SSL
+implementations other than OpenSSL exist.
+
+Default: \fBssl compatibility = no\fR
+.TP
+\fBssl egd socket (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This option is used to define the location of the communiation socket of
+an EGD or PRNGD daemon, from which entropy can be retrieved. This option
+can be used instead of or together with the \fIssl entropy file\fR
+directive. 255 bytes of entropy will be retrieved from the daemon.
+
+Default: \fBnone\fR
+.TP
+\fBssl entropy bytes (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This parameter is used to define the number of bytes which should
+be read from the \fIssl entropy
+file\fR If a -1 is specified, the entire file will
+be read.
+
+Default: \fBssl entropy bytes = 255\fR
+.TP
+\fBssl entropy file (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This parameter is used to specify a file from which processes will
+read "random bytes" on startup. In order to seed the internal pseudo
+random number generator, entropy must be provided. On system with a
+\fI/dev/urandom\fR device file, the processes
+will retrieve its entropy from the kernel. On systems without kernel
+entropy support, a file can be supplied that will be read on startup
+and that will be used to seed the PRNG.
+
+Default: \fBnone\fR
+.TP
+\fBssl hosts (G)\fR
+See \fI ssl hosts resign\fR.
+.TP
+\fBssl hosts resign (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+These two variables define whether Samba will go
+into SSL mode or not. If none of them is defined, Samba will
+allow only SSL connections. If the \fIssl hosts\fR variable lists
+hosts (by IP-address, IP-address range, net group or name),
+only these hosts will be forced into SSL mode. If the \fI ssl hosts resign\fR variable lists hosts, only these
+hosts will \fBNOT\fR be forced into SSL mode. The syntax for these two
+variables is the same as for the \fI hosts allow\fR and \fIhosts deny\fR pair of variables, only
+that the subject of the decision is different: It's not the access
+right but whether SSL is used or not.
+
+The example below requires SSL connections from all hosts
+outside the local net (which is 192.168.*.*).
+
+Default: \fBssl hosts = <empty string>\fR
+
+\fBssl hosts resign = <empty string>\fR
+
+Example: \fBssl hosts resign = 192.168.\fR
+.TP
+\fBssl require clientcert (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+If this variable is set to yes, the
+server will not tolerate connections from clients that don't
+have a valid certificate. The directory/file given in \fIssl CA certDir\fR
+and \fIssl CA certFile
+\fRwill be used to look up the CAs that issued
+the client's certificate. If the certificate can't be verified
+positively, the connection will be terminated. If this variable
+is set to no, clients don't need certificates.
+Contrary to web applications you really \fBshould\fR
+require client certificates. In the web environment the client's
+data is sensitive (credit card numbers) and the server must prove
+to be trustworthy. In a file server environment the server's data
+will be sensitive and the clients must prove to be trustworthy.
+
+Default: \fBssl require clientcert = no\fR
+.TP
+\fBssl require servercert (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+If this variable is set to yes, the
+\fBsmbclient(1)\fR
+will request a certificate from the server. Same as
+\fIssl require
+clientcert\fR for the server.
+
+Default: \fBssl require servercert = no\fR
+.TP
+\fBssl server cert (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This is the file containing the server's certificate.
+The server \fBmust\fR have a certificate. The
+file may also contain the server's private key. See later for
+how certificates and private keys are created.
+
+Default: \fBssl server cert = <empty string>
+\fR.TP
+\fBssl server key (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This file contains the private key of the server. If
+this variable is not defined, the key is looked up in the
+certificate file (it may be appended to the certificate).
+The server \fBmust\fR have a private key
+and the certificate \fBmust\fR
+match this private key.
+
+Default: \fBssl server key = <empty string>
+\fR.TP
+\fBssl version (G)\fR
+This variable is part of SSL-enabled Samba. This
+is only available if the SSL libraries have been compiled on your
+system and the configure option \fB--with-ssl\fR was
+given at configure time.
+
+This enumeration variable defines the versions of the
+SSL protocol that will be used. ssl2or3 allows
+dynamic negotiation of SSL v2 or v3, ssl2 results
+in SSL v2, ssl3 results in SSL v3 and
+tls1 results in TLS v1. TLS (Transport Layer
+Security) is the new standard for SSL.
+
+Default: \fBssl version = "ssl2or3"\fR
+.TP
+\fBstat cache (G)\fR
+This parameter determines if smbd(8)will use a cache in order to
+speed up case insensitive name mappings. You should never need
+to change this parameter.
+
+Default: \fBstat cache = yes\fR
+.TP
+\fBstat cache size (G)\fR
+This parameter determines the number of
+entries in the \fIstat cache\fR. You should
+never need to change this parameter.
+
+Default: \fBstat cache size = 50\fR
+.TP
+\fBstatus (G)\fR
+This enables or disables logging of connections
+to a status file that smbstatus(1)
+can read.
+
+With this disabled \fBsmbstatus\fR won't be able
+to tell you what connections are active. You should never need to
+change this parameter.
+
+Default: \fBstatus = yes\fR
+.TP
+\fBstrict allocate (S)\fR
+This is a boolean that controls the handling of
+disk space allocation in the server. When this is set to yes
+the server will change from UNIX behaviour of not committing real
+disk storage blocks when a file is extended to the Windows behaviour
+of actually forcing the disk system to allocate real storage blocks
+when a file is created or extended to be a given size. In UNIX
+terminology this means that Samba will stop creating sparse files.
+This can be slow on some systems.
+
+When strict allocate is no the server does sparse
+disk block allocation when a file is extended.
+
+Setting this to yes can help Samba return
+out of quota messages on systems that are restricting the disk quota
+of users.
+
+Default: \fBstrict allocate = no\fR
+.TP
+\fBstrict locking (S)\fR
+This is a boolean that controls the handling of
+file locking in the server. When this is set to yes
+the server will check every read and write access for file locks, and
+deny access if locks exist. This can be slow on some systems.
+
+When strict locking is no the server does file
+lock checks only when the client explicitly asks for them.
+
+Well-behaved clients always ask for lock checks when it
+is important, so in the vast majority of cases \fBstrict
+locking = no\fR is preferable.
+
+Default: \fBstrict locking = no\fR
+.TP
+\fBstrict sync (S)\fR
+Many Windows applications (including the Windows
+98 explorer shell) seem to confuse flushing buffer contents to
+disk with doing a sync to disk. Under UNIX, a sync call forces
+the process to be suspended until the kernel has ensured that
+all outstanding data in kernel disk buffers has been safely stored
+onto stable storage. This is very slow and should only be done
+rarely. Setting this parameter to no (the
+default) means that smbdignores the Windows applications requests for
+a sync call. There is only a possibility of losing data if the
+operating system itself that Samba is running on crashes, so there is
+little danger in this default setting. In addition, this fixes many
+performance problems that people have reported with the new Windows98
+explorer shell file copies.
+
+See also the \fIsync
+always>\fR parameter.
+
+Default: \fBstrict sync = no\fR
+.TP
+\fBstrip dot (G)\fR
+This is a boolean that controls whether to
+strip trailing dots off UNIX filenames. This helps with some
+CDROMs that have filenames ending in a single dot.
+
+Default: \fBstrip dot = no\fR
+.TP
+\fBsync always (S)\fR
+This is a boolean parameter that controls
+whether writes will always be written to stable storage before
+the write call returns. If this is false then the server will be
+guided by the client's request in each write call (clients can
+set a bit indicating that a particular write should be synchronous).
+If this is true then every write will be followed by a \fBfsync()
+\fRcall to ensure the data is written to disk. Note that
+the \fIstrict sync\fR parameter must be set to
+yes in order for this parameter to have
+any affect.
+
+See also the \fIstrict
+sync\fR parameter.
+
+Default: \fBsync always = no\fR
+.TP
+\fBsyslog (G)\fR
+This parameter maps how Samba debug messages
+are logged onto the system syslog logging levels. Samba debug
+level zero maps onto syslog LOG_ERR, debug
+level one maps onto LOG_WARNING, debug level
+two maps onto LOG_NOTICE, debug level three
+maps onto LOG_INFO. All higher levels are mapped to LOG_DEBUG.
+
+This parameter sets the threshold for sending messages
+to syslog. Only messages with debug level less than this value
+will be sent to syslog.
+
+Default: \fBsyslog = 1\fR
+.TP
+\fBsyslog only (G)\fR
+If this parameter is set then Samba debug
+messages are logged into the system syslog only, and not to
+the debug log files.
+
+Default: \fBsyslog only = no\fR
+.TP
+\fBtemplate homedir (G)\fR
+When filling out the user information for a Windows NT
+user, the winbindd(8)daemon
+uses this parameter to fill in the home directory for that user.
+If the string \fI%D\fR is present it is substituted
+with the user's Windows NT domain name. If the string \fI%U
+\fRis present it is substituted with the user's Windows
+NT user name.
+
+Default: \fBtemplate homedir = /home/%D/%U\fR
+.TP
+\fBtemplate shell (G)\fR
+When filling out the user information for a Windows NT
+user, the winbindd(8)daemon
+uses this parameter to fill in the login shell for that user.
+
+Default: \fBtemplate shell = /bin/false\fR
+.TP
+\fBtime offset (G)\fR
+This parameter is a setting in minutes to add
+to the normal GMT to local time conversion. This is useful if
+you are serving a lot of PCs that have incorrect daylight
+saving time handling.
+
+Default: \fBtime offset = 0\fR
+
+Example: \fBtime offset = 60\fR
+.TP
+\fBtime server (G)\fR
+This parameter determines if
+nmbd(8)advertises itself as a time server to Windows
+clients.
+
+Default: \fBtime server = no\fR
+.TP
+\fBtimestamp logs (G)\fR
+Synonym for \fI debug timestamp\fR.
+.TP
+\fBtotal print jobs (G)\fR
+This parameter accepts an integer value which defines
+a limit on the maximum number of print jobs that will be accepted
+system wide at any given time. If a print job is submitted
+by a client which will exceed this number, then smbdwill return an
+error indicating that no space is available on the server. The
+default value of 0 means that no such limit exists. This parameter
+can be used to prevent a server from exceeding its capacity and is
+designed as a printing throttle. See also
+\fImax print jobs\fR.
+
+Default: \fBtotal print jobs = 0\fR
+
+Example: \fBtotal print jobs = 5000\fR
+.TP
+\fBunix password sync (G)\fR
+This boolean parameter controls whether Samba
+attempts to synchronize the UNIX password with the SMB password
+when the encrypted SMB password in the smbpasswd file is changed.
+If this is set to true the program specified in the \fIpasswd
+program\fRparameter is called \fBAS ROOT\fR -
+to allow the new UNIX password to be set without access to the
+old UNIX password (as the SMB password change code has no
+access to the old password cleartext, only the new).
+
+See also \fIpasswd
+program\fR, \fI passwd chat\fR.
+
+Default: \fBunix password sync = no\fR
+.TP
+\fBupdate encrypted (G)\fR
+This boolean parameter allows a user logging
+on with a plaintext password to have their encrypted (hashed)
+password in the smbpasswd file to be updated automatically as
+they log on. This option allows a site to migrate from plaintext
+password authentication (users authenticate with plaintext
+password over the wire, and are checked against a UNIX account
+database) to encrypted password authentication (the SMB
+challenge/response authentication mechanism) without forcing
+all users to re-enter their passwords via smbpasswd at the time the
+change is made. This is a convenience option to allow the change over
+to encrypted passwords to be made over a longer period. Once all users
+have encrypted representations of their passwords in the smbpasswd
+file this parameter should be set to no.
+
+In order for this parameter to work correctly the \fIencrypt passwords\fR
+parameter must be set to no when
+this parameter is set to yes.
+
+Note that even when this parameter is set a user
+authenticating to \fBsmbd\fR must still enter a valid
+password in order to connect correctly, and to update their hashed
+(smbpasswd) passwords.
+
+Default: \fBupdate encrypted = no\fR
+.TP
+\fBuse client driver (S)\fR
+This parameter applies only to Windows NT/2000
+clients. It has no affect on Windows 95/98/ME clients. When
+serving a printer to Windows NT/2000 clients without first installing
+a valid printer driver on the Samba host, the client will be required
+to install a local printer driver. From this point on, the client
+will treat the print as a local printer and not a network printer
+connection. This is much the same behavior that will occur
+when \fBdisable spoolss = yes\fR.
+
+The differentiating
+factor is that under normal circumstances, the NT/2000 client will
+attempt to open the network printer using MS-RPC. The problem is that
+because the client considers the printer to be local, it will attempt
+to issue the OpenPrinterEx() call requesting access rights associated
+with the logged on user. If the user possesses local administator rights
+but not root privilegde on the Samba host (often the case), the OpenPrinterEx()
+call will fail. The result is that the client will now display an "Access
+Denied; Unable to connect" message in the printer queue window (even though
+jobs may successfully be printed).
+
+If this parameter is enabled for a printer, then any attempt
+to open the printer with the PRINTER_ACCESS_ADMINISTER right is mapped
+to PRINTER_ACCESS_USE instead. Thus allowing the OpenPrinterEx()
+call to succeed. \fBThis parameter MUST not be able enabled
+on a print share which has valid print driver installed on the Samba
+server.\fR
+
+See also disable spoolss
+
+Default: \fBuse client driver = no\fR
+.TP
+\fBuse mmap (G)\fR
+This global parameter determines if the tdb internals of Samba can
+depend on mmap working correctly on the running system. Samba requires a coherent
+mmap/read-write system memory cache. Currently only HPUX does not have such a
+coherent cache, and so this parameter is set to false by
+default on HPUX. On all other systems this parameter should be left alone. This
+parameter is provided to help the Samba developers track down problems with
+the tdb internal code.
+
+Default: \fBuse mmap = yes\fR
+.TP
+\fBuse rhosts (G)\fR
+If this global parameter is true, it specifies
+that the UNIX user's \fI.rhosts\fR file in their home directory
+will be read to find the names of hosts and users who will be allowed
+access without specifying a password.
+
+\fBNOTE:\fR The use of \fIuse rhosts
+\fRcan be a major security hole. This is because you are
+trusting the PC to supply the correct username. It is very easy to
+get a PC to supply a false username. I recommend that the \fI use rhosts\fR option be only used if you really know what
+you are doing.
+
+Default: \fBuse rhosts = no\fR
+.TP
+\fBuser (S)\fR
+Synonym for \fI username\fR.
+.TP
+\fBusers (S)\fR
+Synonym for \fI username\fR.
+.TP
+\fBusername (S)\fR
+Multiple users may be specified in a comma-delimited
+list, in which case the supplied password will be tested against
+each username in turn (left to right).
+
+The \fIusername\fR line is needed only when
+the PC is unable to supply its own username. This is the case
+for the COREPLUS protocol or where your users have different WfWg
+usernames to UNIX usernames. In both these cases you may also be
+better using the \\\\server\\share%user syntax instead.
+
+The \fIusername\fR line is not a great
+solution in many cases as it means Samba will try to validate
+the supplied password against each of the usernames in the
+\fIusername\fR line in turn. This is slow and
+a bad idea for lots of users in case of duplicate passwords.
+You may get timeouts or security breaches using this parameter
+unwisely.
+
+Samba relies on the underlying UNIX security. This
+parameter does not restrict who can login, it just offers hints
+to the Samba server as to what usernames might correspond to the
+supplied password. Users can login as whoever they please and
+they will be able to do no more damage than if they started a
+telnet session. The daemon runs as the user that they log in as,
+so they cannot do anything that user cannot do.
+
+To restrict a service to a particular set of users you
+can use the \fIvalid users
+\fRparameter.
+
+If any of the usernames begin with a '@' then the name
+will be looked up first in the NIS netgroups list (if Samba
+is compiled with netgroup support), followed by a lookup in
+the UNIX groups database and will expand to a list of all users
+in the group of that name.
+
+If any of the usernames begin with a '+' then the name
+will be looked up only in the UNIX groups database and will
+expand to a list of all users in the group of that name.
+
+If any of the usernames begin with a '&'then the name
+will be looked up only in the NIS netgroups database (if Samba
+is compiled with netgroup support) and will expand to a list
+of all users in the netgroup group of that name.
+
+Note that searching though a groups database can take
+quite some time, and some clients may time out during the
+search.
+
+See the section NOTE ABOUT
+USERNAME/PASSWORD VALIDATION for more information on how
+this parameter determines access to the services.
+
+Default: \fBThe guest account if a guest service,
+else <empty string>.\fR
+
+Examples:\fBusername = fred, mary, jack, jane,
+@users, @pcgroup\fR
+.TP
+\fBusername level (G)\fR
+This option helps Samba to try and 'guess' at
+the real UNIX username, as many DOS clients send an all-uppercase
+username. By default Samba tries all lowercase, followed by the
+username with the first letter capitalized, and fails if the
+username is not found on the UNIX machine.
+
+If this parameter is set to non-zero the behavior changes.
+This parameter is a number that specifies the number of uppercase
+combinations to try while trying to determine the UNIX user name. The
+higher the number the more combinations will be tried, but the slower
+the discovery of usernames will be. Use this parameter when you have
+strange usernames on your UNIX machine, such as AstrangeUser
+\&.
+
+Default: \fBusername level = 0\fR
+
+Example: \fBusername level = 5\fR
+.TP
+\fBusername map (G)\fR
+This option allows you to specify a file containing
+a mapping of usernames from the clients to the server. This can be
+used for several purposes. The most common is to map usernames
+that users use on DOS or Windows machines to those that the UNIX
+box uses. The other is to map multiple users to a single username
+so that they can more easily share files.
+
+The map file is parsed line by line. Each line should
+contain a single UNIX username on the left then a '=' followed
+by a list of usernames on the right. The list of usernames on the
+right may contain names of the form @group in which case they
+will match any UNIX username in that group. The special client
+name '*' is a wildcard and matches any name. Each line of the
+map file may be up to 1023 characters long.
+
+The file is processed on each line by taking the
+supplied username and comparing it with each username on the right
+hand side of the '=' signs. If the supplied name matches any of
+the names on the right hand side then it is replaced with the name
+on the left. Processing then continues with the next line.
+
+If any line begins with a '#' or a ';' then it is
+ignored
+
+If any line begins with an '!' then the processing
+will stop after that line if a mapping was done by the line.
+Otherwise mapping continues with every line being processed.
+Using '!' is most useful when you have a wildcard mapping line
+later in the file.
+
+For example to map from the name admin
+or administrator to the UNIX name root you would use:
+
+\fBroot = admin administrator\fR
+
+Or to map anyone in the UNIX group system
+to the UNIX name sys you would use:
+
+\fBsys = @system\fR
+
+You can have as many mappings as you like in a username
+map file.
+
+If your system supports the NIS NETGROUP option then
+the netgroup database is checked before the \fI/etc/group
+\fRdatabase for matching groups.
+
+You can map Windows usernames that have spaces in them
+by using double quotes around the name. For example:
+
+\fBtridge = "Andrew Tridgell"\fR
+
+would map the windows username "Andrew Tridgell" to the
+unix username "tridge".
+
+The following example would map mary and fred to the
+unix user sys, and map the rest to guest. Note the use of the
+\&'!' to tell Samba to stop processing if it gets a match on
+that line.
+
+.sp
+.nf
+ !sys = mary fred
+ guest = *
+
+.sp
+.fi
+
+Note that the remapping is applied to all occurrences
+of usernames. Thus if you connect to \\\\server\\fred and fred is remapped to mary then you
+will actually be connecting to \\\\server\\mary and will need to
+supply a password suitable for mary not
+fred. The only exception to this is the
+username passed to the \fI password server\fR (if you have one). The password
+server will receive whatever username the client supplies without
+modification.
+
+Also note that no reverse mapping is done. The main effect
+this has is with printing. Users who have been mapped may have
+trouble deleting print jobs as PrintManager under WfWg will think
+they don't own the print job.
+
+Default: \fBno username map\fR
+
+Example: \fBusername map = /usr/local/samba/lib/users.map
+\fR.TP
+\fButmp (G)\fR
+This boolean parameter is only available if
+Samba has been configured and compiled with the option \fB --with-utmp\fR. If set to true then Samba will attempt
+to add utmp or utmpx records (depending on the UNIX system) whenever a
+connection is made to a Samba server. Sites may use this to record the
+user connecting to a Samba share.
+
+See also the \fI utmp directory\fR parameter.
+
+Default: \fButmp = no\fR
+.TP
+\fButmp directory(G)\fR
+This parameter is only available if Samba has
+been configured and compiled with the option \fB --with-utmp\fR. It specifies a directory pathname that is
+used to store the utmp or utmpx files (depending on the UNIX system) that
+record user connections to a Samba server. See also the \fIutmp\fR parameter. By default this is
+not set, meaning the system will use whatever utmp file the
+native system is set to use (usually
+\fI/var/run/utmp\fR on Linux).
+
+Default: \fBno utmp directory\fR
+.TP
+\fBvalid chars (G)\fR
+The option allows you to specify additional
+characters that should be considered valid by the server in
+filenames. This is particularly useful for national character
+sets, such as adding u-umlaut or a-ring.
+
+The option takes a list of characters in either integer
+or character form with spaces between them. If you give two
+characters with a colon between them then it will be taken as
+an lowercase:uppercase pair.
+
+If you have an editor capable of entering the characters
+into the config file then it is probably easiest to use this
+method. Otherwise you can specify the characters in octal,
+decimal or hexadecimal form using the usual C notation.
+
+For example to add the single character 'Z' to the charset
+(which is a pointless thing to do as it's already there) you could
+do one of the following
+
+.sp
+.nf
+ valid chars = Z
+ valid chars = z:Z
+ valid chars = 0132:0172
+
+.sp
+.fi
+
+The last two examples above actually add two characters,
+and alter the uppercase and lowercase mappings appropriately.
+
+Note that you \fBMUST\fR specify this parameter
+after the \fIclient code page\fR parameter if you
+have both set. If \fIclient code page\fR is set after
+the \fIvalid chars\fR parameter the \fIvalid
+chars\fR settings will be overwritten.
+
+See also the \fIclient
+code page\fR parameter.
+
+Default: \fBSamba defaults to using a reasonable set
+of valid characters for English systems\fR
+
+Example: \fBvalid chars = 0345:0305 0366:0326 0344:0304
+\fR
+The above example allows filenames to have the Swedish
+characters in them.
+
+\fBNOTE:\fR It is actually quite difficult to
+correctly produce a \fIvalid chars\fR line for
+a particular system. To automate the process tino@augsburg.net <URL:mailto:tino@augsburg.net> has written
+a package called \fBvalidchars\fR which will automatically
+produce a complete \fIvalid chars\fR line for
+a given client system. Look in the \fIexamples/validchars/
+\fRsubdirectory of your Samba source code distribution
+for this package.
+.TP
+\fBvalid users (S)\fR
+This is a list of users that should be allowed
+to login to this service. Names starting with '@', '+' and '&'
+are interpreted using the same rules as described in the
+\fIinvalid users\fR parameter.
+
+If this is empty (the default) then any user can login.
+If a username is in both this list and the \fIinvalid
+users\fR list then access is denied for that user.
+
+The current servicename is substituted for \fI%S
+\fR\&. This is useful in the [homes] section.
+
+See also \fIinvalid users
+\fR
+Default: \fBNo valid users list (anyone can login)
+\fR
+Example: \fBvalid users = greg, @pcusers\fR
+.TP
+\fBveto files(S)\fR
+This is a list of files and directories that
+are neither visible nor accessible. Each entry in the list must
+be separated by a '/', which allows spaces to be included
+in the entry. '*' and '?' can be used to specify multiple files
+or directories as in DOS wildcards.
+
+Each entry must be a unix path, not a DOS path and
+must \fBnot\fR include the unix directory
+separator '/'.
+
+Note that the \fIcase sensitive\fR option
+is applicable in vetoing files.
+
+One feature of the veto files parameter that it
+is important to be aware of is Samba's behaviour when
+trying to delete a directory. If a directory that is
+to be deleted contains nothing but veto files this
+deletion will \fBfail\fR unless you also set
+the \fIdelete veto files\fR parameter to
+\fIyes\fR.
+
+Setting this parameter will affect the performance
+of Samba, as it will be forced to check all files and directories
+for a match as they are scanned.
+
+See also \fIhide files
+\fRand \fI case sensitive\fR.
+
+Default: \fBNo files or directories are vetoed.
+\fR
+Examples:
+.sp
+.nf
+; Veto any files containing the word Security,
+; any ending in .tmp, and any directory containing the
+; word root.
+veto files = /*Security*/*.tmp/*root*/
+
+; Veto the Apple specific files that a NetAtalk server
+; creates.
+veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/
+.sp
+.fi
+.TP
+\fBveto oplock files (S)\fR
+This parameter is only valid when the \fIoplocks\fR
+parameter is turned on for a share. It allows the Samba administrator
+to selectively turn off the granting of oplocks on selected files that
+match a wildcarded list, similar to the wildcarded list used in the
+\fIveto files\fR
+parameter.
+
+Default: \fBNo files are vetoed for oplock
+grants\fR
+
+You might want to do this on files that you know will
+be heavily contended for by clients. A good example of this
+is in the NetBench SMB benchmark program, which causes heavy
+client contention for files ending in \fI.SEM\fR.
+To cause Samba not to grant oplocks on these files you would use
+the line (either in the [global] section or in the section for
+the particular NetBench share :
+
+Example: \fBveto oplock files = /*.SEM/
+\fR.TP
+\fBvfs object (S)\fR
+This parameter specifies a shared object file that
+is used for Samba VFS I/O operations. By default, normal
+disk I/O operations are used but these can be overloaded
+with a VFS object. The Samba VFS layer is new to Samba 2.2 and
+must be enabled at compile time with --with-vfs.
+
+Default : \fBno value\fR
+.TP
+\fBvfs options (S)\fR
+This parameter allows parameters to be passed
+to the vfs layer at initialization time. The Samba VFS layer
+is new to Samba 2.2 and must be enabled at compile time
+with --with-vfs. See also \fI vfs object\fR.
+
+Default : \fBno value\fR
+.TP
+\fBvolume (S)\fR
+This allows you to override the volume label
+returned for a share. Useful for CDROMs with installation programs
+that insist on a particular volume label.
+
+Default: \fBthe name of the share\fR
+.TP
+\fBwide links (S)\fR
+This parameter controls whether or not links
+in the UNIX file system may be followed by the server. Links
+that point to areas within the directory tree exported by the
+server are always allowed; this parameter controls access only
+to areas that are outside the directory tree being exported.
+
+Note that setting this parameter can have a negative
+effect on your server performance due to the extra system calls
+that Samba has to do in order to perform the link checks.
+
+Default: \fBwide links = yes\fR
+.TP
+\fBwinbind cache time\fR
+This parameter specifies the number of seconds the
+winbindd(8)daemon will cache
+user and group information before querying a Windows NT server
+again.
+
+Default: \fBwinbind cache type = 15\fR
+.TP
+\fBwinbind enum users\fR
+On large installations using
+winbindd(8)it may be
+necessary to suppress the enumeration of users through the
+\fBsetpwent()\fR,
+\fBgetpwent()\fR and
+\fBendpwent()\fR group of system calls. If
+the \fIwinbind enum users\fR parameter is
+false, calls to the \fBgetpwent\fR system call
+will not return any data.
+
+\fBWarning:\fR Turning off user
+enumeration may cause some programs to behave oddly. For
+example, the finger program relies on having access to the
+full user list when searching for matching
+usernames.
+
+Default: \fBwinbind enum users = yes \fR
+.TP
+\fBwinbind enum groups\fR
+On large installations using
+winbindd(8)it may be
+necessary to suppress the enumeration of groups through the
+\fBsetgrent()\fR,
+\fBgetgrent()\fR and
+\fBendgrent()\fR group of system calls. If
+the \fIwinbind enum groups\fR parameter is
+false, calls to the \fBgetgrent()\fR system
+call will not return any data.
+
+\fBWarning:\fR Turning off group
+enumeration may cause some programs to behave oddly.
+
+Default: \fBwinbind enum groups = yes \fR
+.TP
+\fBwinbind gid\fR
+The winbind gid parameter specifies the range of group
+ids that are allocated by the winbindd(8)daemon. This range of group ids should have no
+existing local or NIS groups within it as strange conflicts can
+occur otherwise.
+
+Default: \fBwinbind gid = <empty string>
+\fR
+Example: \fBwinbind gid = 10000-20000\fR
+.TP
+\fBwinbind separator\fR
+This parameter allows an admin to define the character
+used when listing a username of the form of \fIDOMAIN
+\fR\\\fIuser\fR. This parameter
+is only applicable when using the \fIpam_winbind.so\fR
+and \fInss_winbind.so\fR modules for UNIX services.
+
+Example: \fBwinbind separator = \\\fR
+
+Example: \fBwinbind separator = +\fR
+.TP
+\fBwinbind uid\fR
+The winbind gid parameter specifies the range of group
+ids that are allocated by the winbindd(8)daemon. This range of ids should have no
+existing local or NIS users within it as strange conflicts can
+occur otherwise.
+
+Default: \fBwinbind uid = <empty string>
+\fR
+Example: \fBwinbind uid = 10000-20000\fR
+.TP
+\fBwins hook (G)\fR
+When Samba is running as a WINS server this
+allows you to call an external program for all changes to the
+WINS database. The primary use for this option is to allow the
+dynamic update of external name resolution databases such as
+dynamic DNS.
+
+The wins hook parameter specifies the name of a script
+or executable that will be called as follows:
+
+\fBwins_hook operation name nametype ttl IP_list
+\fR.RS
+.TP 0.2i
+\(bu
+The first argument is the operation and is one
+of "add", "delete", or "refresh". In most cases the operation can
+be ignored as the rest of the parameters provide sufficient
+information. Note that "refresh" may sometimes be called when the
+name has not previously been added, in that case it should be treated
+as an add.
+.TP 0.2i
+\(bu
+The second argument is the NetBIOS name. If the
+name is not a legal name then the wins hook is not called.
+Legal names contain only letters, digits, hyphens, underscores
+and periods.
+.TP 0.2i
+\(bu
+The third argument is the NetBIOS name
+type as a 2 digit hexadecimal number.
+.TP 0.2i
+\(bu
+The fourth argument is the TTL (time to live)
+for the name in seconds.
+.TP 0.2i
+\(bu
+The fifth and subsequent arguments are the IP
+addresses currently registered for that name. If this list is
+empty then the name should be deleted.
.RE
-
+.PP
+An example script that calls the BIND dynamic DNS update
+program \fBnsupdate\fR is provided in the examples
+directory of the Samba source code.
+.PP
+.TP
+\fBwins proxy (G)\fR
+This is a boolean that controls if nmbd(8)will respond to broadcast name
+queries on behalf of other hosts. You may need to set this
+to yes for some older clients.
+
+Default: \fBwins proxy = no\fR
+.TP
+\fBwins server (G)\fR
+This specifies the IP address (or DNS name: IP
+address for preference) of the WINS server that nmbd(8)should register with. If you have a WINS server on
+your network then you should set this to the WINS server's IP.
+
+You should point this at your WINS server if you have a
+multi-subnetted network.
+
+\fBNOTE\fR. You need to set up Samba to point
+to a WINS server if you have multiple subnets and wish cross-subnet
+browsing to work correctly.
+
+See the documentation file \fIBROWSING.txt\fR
+in the docs/ directory of your Samba source distribution.
+
+Default: \fBnot enabled\fR
+
+Example: \fBwins server = 192.9.200.1\fR
+.TP
+\fBwins support (G)\fR
+This boolean controls if the
+nmbd(8)process in Samba will act as a WINS server. You should
+not set this to true unless you have a multi-subnetted network and
+you wish a particular \fBnmbd\fR to be your WINS server.
+Note that you should \fBNEVER\fR set this to true
+on more than one machine in your network.
+
+Default: \fBwins support = no\fR
+.TP
+\fBworkgroup (G)\fR
+This controls what workgroup your server will
+appear to be in when queried by clients. Note that this parameter
+also controls the Domain name used with the \fBsecurity = domain\fR
+setting.
+
+Default: \fBset at compile time to WORKGROUP\fR
+
+Example: \fBworkgroup = MYGROUP\fR
+.TP
+\fBwritable (S)\fR
+Synonym for \fI writeable\fR for people who can't spell :-).
+.TP
+\fBwrite cache size (S)\fR
+If this integer parameter is set to non-zero value,
+Samba will create an in-memory cache for each oplocked file
+(it does \fBnot\fR do this for
+non-oplocked files). All writes that the client does not request
+to be flushed directly to disk will be stored in this cache if possible.
+The cache is flushed onto disk when a write comes in whose offset
+would not fit into the cache or when the file is closed by the client.
+Reads for the file are also served from this cache if the data is stored
+within it.
+
+This cache allows Samba to batch client writes into a more
+efficient write size for RAID disks (i.e. writes may be tuned to
+be the RAID stripe size) and can improve performance on systems
+where the disk subsystem is a bottleneck but there is free
+memory for userspace programs.
+
+The integer parameter specifies the size of this cache
+(per oplocked file) in bytes.
+
+Default: \fBwrite cache size = 0\fR
+
+Example: \fBwrite cache size = 262144\fR
+
+for a 256k cache size per file.
+.TP
+\fBwrite list (S)\fR
+This is a list of users that are given read-write
+access to a service. If the connecting user is in this list then
+they will be given write access, no matter what the \fIwriteable\fR
+option is set to. The list can include group names using the
+@group syntax.
+
+Note that if a user is in both the read list and the
+write list then they will be given write access.
+
+See also the \fIread list
+\fRoption.
+
+Default: \fBwrite list = <empty string>
+\fR
+Example: \fBwrite list = admin, root, @staff
+\fR.TP
+\fBwrite ok (S)\fR
+Synonym for \fI writeable\fR.
+.TP
+\fBwrite raw (G)\fR
+This parameter controls whether or not the server
+will support raw write SMB's when transferring data from clients.
+You should never need to change this parameter.
+
+Default: \fBwrite raw = yes\fR
+.TP
+\fBwriteable (S)\fR
+An inverted synonym is \fIread only\fR.
+
+If this parameter is no, then users
+of a service may not create or modify files in the service's
+directory.
+
+Note that a printable service (\fBprintable = yes\fR)
+will \fBALWAYS\fR allow writing to the directory
+(user privileges permitting), but only via spooling operations.
+
+Default: \fBwriteable = no\fR
+.SH "WARNINGS"
+.PP
+Although the configuration file permits service names
+to contain spaces, your client software may not. Spaces will
+be ignored in comparisons anyway, so it shouldn't be a
+problem - but be aware of the possibility.
+.PP
+On a similar note, many clients - especially DOS clients -
+limit service names to eight characters. smbd(8)
+has no such limitation, but attempts to connect from such
+clients will fail if they truncate the service names. For this reason
+you should probably keep your service names down to eight characters
+in length.
+.PP
+Use of the [homes] and [printers] special sections make life
+for an administrator easy, but the various combinations of default
+attributes can be tricky. Take extreme care when designing these
+sections. In particular, ensure that the permissions on spool
+directories are correct.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+samba(7),
+\fBsmbpasswd(8)\fR,
+\fBswat(8)\fR,
+\fBsmbd(8)\fR,
+\fBnmbd(8)\fR,
+\fBsmbclient(1)\fR,
+\fBnmblookup(1)\fR,
+\fBtestparm(1)\fR,
+\fBtestprns(1)\fR
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbcacls.1 b/docs/manpages/smbcacls.1
new file mode 100644
index 00000000000..d2da694a263
--- /dev/null
+++ b/docs/manpages/smbcacls.1
@@ -0,0 +1,191 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBCACLS" "1" "06 December 2001" "" ""
+.SH NAME
+smbcacls \- Set or get ACLs on an NT file or directory names
+.SH SYNOPSIS
+.sp
+\fBsmbcacls\fR \fB//server/share\fR \fBfilename\fR [ \fB-U username\fR ] [ \fB-A acls\fR ] [ \fB-M acls\fR ] [ \fB-D acls\fR ] [ \fB-S acls\fR ] [ \fB-C name\fR ] [ \fB-G name\fR ] [ \fB-n\fR ] [ \fB-h\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+The \fBsmbcacls\fR program manipulates NT Access Control Lists
+(ACLs) on SMB file shares.
+.SH "OPTIONS"
+.PP
+The following options are available to the \fBsmbcacls\fR program.
+The format of ACLs is described in the section ACL FORMAT
+.TP
+\fB-A acls\fR
+Add the ACLs specified to the ACL list. Existing
+access control entries are unchanged.
+.TP
+\fB-M acls\fR
+Modify the mask value (permissions) for the ACLs
+specified on the command line. An error will be printed for each
+ACL specified that was not already present in the ACL list
+.TP
+\fB-D acls\fR
+Delete any ACLs specified on the command line.
+An error will be printed for each ACL specified that was not
+already present in the ACL list.
+.TP
+\fB-S acls\fR
+This command sets the ACLs on the file with
+only the ones specified on the command line. All other ACLs are
+erased. Note that the ACL specified must contain at least a revision,
+type, owner and group for the call to succeed.
+.TP
+\fB-U username\fR
+Specifies a username used to connect to the
+specified service. The username may be of the form "username" in
+which case the user is prompted to enter in a password and the
+workgroup specified in the \fIsmb.conf\fR file is
+used, or "username%password" or "DOMAIN\\username%password" and the
+password and workgroup names are used as provided.
+.TP
+\fB-C name\fR
+The owner of a file or directory can be changed
+to the name given using the \fI-C\fR option.
+The name can be a sid in the form S-1-x-y-z or a name resolved
+against the server specified in the first argument.
+
+This command is a shortcut for -M OWNER:name.
+.TP
+\fB-G name\fR
+The group owner of a file or directory can
+be changed to the name given using the \fI-G\fR
+option. The name can be a sid in the form S-1-x-y-z or a name
+resolved against the server specified n the first argument.
+
+This command is a shortcut for -M GROUP:name.
+.TP
+\fB-n\fR
+This option displays all ACL information in numeric
+format. The default is to convert SIDs to names and ACE types
+and masks to a readable string format.
+.TP
+\fB-h\fR
+Print usage information on the \fBsmbcacls
+\fRprogram.
+.SH "ACL FORMAT"
+.PP
+The format of an ACL is one or more ACL entries separated by
+either commas or newlines. An ACL entry is one of the following:
+.PP
+.sp
+.nf
+
+REVISION:<revision number>
+OWNER:<sid or name>
+GROUP:<sid or name>
+ACL:<sid or name>:<type>/<flags>/<mask>
+
+.sp
+.fi
+.PP
+The revision of the ACL specifies the internal Windows
+NT ACL revision for the security descriptor.
+If not specified it defaults to 1. Using values other than 1 may
+cause strange behaviour.
+.PP
+The owner and group specify the owner and group sids for the
+object. If a SID in the format CWS-1-x-y-z is specified this is used,
+otherwise the name specified is resolved using the server on which
+the file or directory resides.
+.PP
+ACLs specify permissions granted to the SID. This SID again
+can be specified in CWS-1-x-y-z format or as a name in which case
+it is resolved against the server on which the file or directory
+resides. The type, flags and mask values determine the type of
+access granted to the SID.
+.PP
+The type can be either 0 or 1 corresponding to ALLOWED or
+DENIED access to the SID. The flags values are generally
+zero for file ACLs and either 9 or 2 for directory ACLs. Some
+common flags are:
+.TP 0.2i
+\(bu
+#define SEC_ACE_FLAG_OBJECT_INHERIT 0x1
+.TP 0.2i
+\(bu
+#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x2
+.TP 0.2i
+\(bu
+#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x4
+.TP 0.2i
+\(bu
+#define SEC_ACE_FLAG_INHERIT_ONLY 0x8
+.PP
+At present flags can only be specified as decimal or
+hexadecimal values.
+.PP
+.PP
+The mask is a value which expresses the access right
+granted to the SID. It can be given as a decimal or hexadecimal value,
+or by using one of the following text strings which map to the NT
+file permissions of the same name.
+.PP
+.TP 0.2i
+\(bu
+\fBR\fR - Allow read access
+.TP 0.2i
+\(bu
+\fBW\fR - Allow write access
+.TP 0.2i
+\(bu
+\fBX\fR - Execute permission on the object
+.TP 0.2i
+\(bu
+\fBD\fR - Delete the object
+.TP 0.2i
+\(bu
+\fBP\fR - Change permissions
+.TP 0.2i
+\(bu
+\fBO\fR - Take ownership
+.PP
+The following combined permissions can be specified:
+.PP
+.TP 0.2i
+\(bu
+\fBREAD\fR - Equivalent to 'RX'
+permissions
+.TP 0.2i
+\(bu
+\fBCHANGE\fR - Equivalent to 'RXWD' permissions
+.TP 0.2i
+\(bu
+\fBFULL\fR - Equivalent to 'RWXDPO'
+permissions
+.SH "EXIT STATUS"
+.PP
+The \fBsmbcacls\fR program sets the exit status
+depending on the success or otherwise of the operations performed.
+The exit status may be one of the following values.
+.PP
+If the operation succeeded, smbcacls returns and exit
+status of 0. If \fBsmbcacls\fR couldn't connect to the specified server,
+or there was an error getting or setting the ACLs, an exit status
+of 1 is returned. If there was an error parsing any command line
+arguments, an exit status of 2 is returned.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+\fBsmbcacls\fR was written by Andrew Tridgell
+and Tim Potter.
+.PP
+The conversion to DocBook for Samba 2.2 was done
+by Gerald Carter
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index 5590e01296e..4c5ef0b3e4b 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -1,1133 +1,777 @@
-.TH SMBCLIENT 1 17/1/1995 smbclient smbclient
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBCLIENT" "1" "06 December 2001" "" ""
.SH NAME
-smbclient \- ftp-like Lan Manager client program
+smbclient \- ftp-like client to access SMB/CIFS resources on servers
.SH SYNOPSIS
-.B smbclient
-.B servicename
-[
-.B password
-] [
-.B -A
-] [
-.B -E
-] [
-.B -L
-.I host
-] [
-.B -M
-.I host
-] [
-.B -I
-.I IP number
-] [
-.B -N
-] [
-.B -P
-] [
-.B -U
-.I username
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log basename
-] [
-.B -n
-.I netbios name
-] [
-.B -O
-.I socket options
-] [
-.B -p
-.I port number
-.B -T
-.I tar options
-.B -D
-.I initial directory
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B smbclient
-is a client that can 'talk' to a Lan Manager server. It offers
-an interface similar to that of the
-.B ftp
-program (see
-.B ftp(1)). Operations include things like getting files from the
-server to the local machine, putting files from the local machine to
-the server, retrieving directory information from the server and so on.
-
-.SH OPTIONS
-.B servicename
-.RS 3
-.B servicename
-is the name of the service you want to use on the server. A service
-name takes the form
-.B "\\\\\\\\server\\\\service"
-where
-.B server
-is the netbios name of the Lan Manager server offering the desired service and
-.B service
-is the name of the service offered. Thus to connect to the service "printer"
-on the Lan Manager server "lanman", you would use the servicename
-
-.RS 10
-.B "\\\\\\\\lanman\\\\printer"
-.RE
-
-Note that the server name required is NOT necessarily the host name of the
-server! The name required is a Lan Manager server name, which may or may not
-be the same as the hostname of the machine running the server.
-.RE
-
-.B password
-.RS 3
-.B
-password
-is the password required to access the specified service on the
-specified server. If supplied, the
-.B -N
-option (suppress password prompt) is assumed.
-
-There is no default password. If no password is supplied on the command line
-(either here or using the
-.B -U
-option (see below)) and
-.B -N
-is not specified, the client will prompt for a password, even if the desired
-service does not require one. (If prompted for a password and none is
+.sp
+\fBsmbclient\fR \fBservicename\fR [ \fBpassword\fR ] [ \fB-b <buffer size>\fR ] [ \fB-d debuglevel\fR ] [ \fB-D Directory\fR ] [ \fB-U username\fR ] [ \fB-W workgroup\fR ] [ \fB-M <netbios name>\fR ] [ \fB-m maxprotocol\fR ] [ \fB-A authfile\fR ] [ \fB-N\fR ] [ \fB-l logfile\fR ] [ \fB-L <netbios name>\fR ] [ \fB-I destinationIP\fR ] [ \fB-E <terminal code>\fR ] [ \fB-c <command string>\fR ] [ \fB-i scope\fR ] [ \fB-O <socket options>\fR ] [ \fB-p port\fR ] [ \fB-R <name resolve order>\fR ] [ \fB-s <smb config file>\fR ] [ \fB-T<c|x>IXFqgbNan\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBsmbclient\fR is a client that can
+\&'talk' to an SMB/CIFS server. It offers an interface
+similar to that of the ftp program (see \fBftp(1)\fR).
+Operations include things like getting files from the server
+to the local machine, putting files from the local machine to
+the server, retrieving directory information from the server
+and so on.
+.SH "OPTIONS"
+.TP
+\fBservicename\fR
+servicename is the name of the service
+you want to use on the server. A service name takes the form
+\fI//server/service\fR where \fIserver
+\fRis the NetBIOS name of the SMB/CIFS server
+offering the desired service and \fIservice\fR
+is the name of the service offered. Thus to connect to
+the service "printer" on the SMB/CIFS server "smbserver",
+you would use the servicename \fI//smbserver/printer
+\fR
+Note that the server name required is NOT necessarily
+the IP (DNS) host name of the server ! The name required is
+a NetBIOS server name, which may or may not be the
+same as the IP hostname of the machine running the server.
+
+The server name is looked up according to either
+the \fI-R\fR parameter to \fBsmbclient\fR or
+using the name resolve order parameter in the \fIsmb.conf\fR file,
+allowing an administrator to change the order and methods
+by which server names are looked up.
+.TP
+\fBpassword\fR
+The password required to access the specified
+service on the specified server. If this parameter is
+supplied, the \fI-N\fR option (suppress
+password prompt) is assumed.
+
+There is no default password. If no password is supplied
+on the command line (either by using this parameter or adding
+a password to the \fI-U\fR option (see
+below)) and the \fI-N\fR option is not
+specified, the client will prompt for a password, even if
+the desired service does not require one. (If no password is
required, simply press ENTER to provide a null password.)
-Note: Some servers (including OS/2 and Windows for Workgroups) insist
-on an uppercase password. Lowercase or mixed case passwords may be
-rejected by these servers.
+Note: Some servers (including OS/2 and Windows for
+Workgroups) insist on an uppercase password. Lowercase
+or mixed case passwords may be rejected by these servers.
Be cautious about including passwords in scripts.
-.RE
-
-.B -A
-
-.RS 3
-This parameter, if specified, causes the maximum debug level to be selected.
-Be warned that this generates prodigious amounts of debug data. There is also
-a security issue involved, as at the maximum debug level cleartext passwords
-may be written to some log files.
-.RE
-
-.B -L
-
-.RS 3
-This option allows you to look at what services are available on a
-server. You use it as "smbclient -L host" and a list should appear.
-The -I option may be useful if your netbios names don't match your
-tcp/ip host names or if you are trying to reach a host on another
-network. For example:
-
-smbclient -L ftp -I ftp.microsoft.com
-
-will list the shares available on microsofts public server.
-.RE
-
-.B -M
-
-.RS 3
-This options allows you to send messages, using the "WinPopup"
-protocol, to another computer. Once a connection is established you
-then type your message, pressing ^D (control-D) to end.
-
-If the receiving computer is running WinPopup the user will receive
-the message and probably a beep. If they are not running WinPopup the
-message will be lost, and no error message will occur.
-
-The message is also automatically truncated if the message is over
-1600 bytes, as this is the limit of the protocol.
-
-One useful trick is to cat the message through smbclient. For example:
-
-cat mymessage.txt | smbclient -M FRED
-
-will send the message in the file "mymessage.txt" to the machine FRED.
-
-You may also find the -U and -I options useful, as they allow you to
+.TP
+\fB-s smb.conf\fR
+Specifies the location of the all important
+\fIsmb.conf\fR file.
+.TP
+\fB-O socket options\fR
+TCP socket options to set on the client
+socket. See the socket options parameter in the \fI smb.conf (5)\fR manpage for the list of valid
+options.
+.TP
+\fB-R <name resolve order>\fR
+This option is used by the programs in the Samba
+suite to determine what naming services and in what order to resolve
+host names to IP addresses. The option takes a space-separated
+string of different name resolution options.
+
+The options are :"lmhosts", "host", "wins" and "bcast". They
+cause names to be resolved as follows :
+.RS
+.TP 0.2i
+\(bu
+lmhosts : Lookup an IP
+address in the Samba lmhosts file. If the line in lmhosts has
+no name type attached to the NetBIOS name (see the lmhosts(5)for details) then
+any name type matches for lookup.
+.TP 0.2i
+\(bu
+host : Do a standard host
+name to IP address resolution, using the system \fI/etc/hosts
+\fR, NIS, or DNS lookups. This method of name resolution
+is operating system dependent, for instance on IRIX or Solaris this
+may be controlled by the \fI/etc/nsswitch.conf\fR
+file). Note that this method is only used if the NetBIOS name
+type being queried is the 0x20 (server) name type, otherwise
+it is ignored.
+.TP 0.2i
+\(bu
+wins : Query a name with
+the IP address listed in the \fIwins server\fR
+parameter. If no WINS server has
+been specified this method will be ignored.
+.TP 0.2i
+\(bu
+bcast : Do a broadcast on
+each of the known local interfaces listed in the
+\fIinterfaces\fR
+parameter. This is the least reliable of the name resolution
+methods as it depends on the target host being on a locally
+connected subnet.
+.RE
+.PP
+If this parameter is not set then the name resolve order
+defined in the \fIsmb.conf\fR file parameter
+(name resolve order) will be used.
+.PP
+.PP
+The default order is lmhosts, host, wins, bcast and without
+this parameter or any entry in the \fIname resolve order
+\fRparameter of the \fIsmb.conf\fR file the name resolution
+methods will be attempted in this order.
+.PP
+.TP
+\fB-M NetBIOS name\fR
+This options allows you to send messages, using
+the "WinPopup" protocol, to another computer. Once a connection is
+established you then type your message, pressing ^D (control-D) to
+end.
+
+If the receiving computer is running WinPopup the user will
+receive the message and probably a beep. If they are not running
+WinPopup the message will be lost, and no error message will
+occur.
+
+The message is also automatically truncated if the message
+is over 1600 bytes, as this is the limit of the protocol.
+
+One useful trick is to cat the message through
+\fBsmbclient\fR. For example: \fB cat mymessage.txt | smbclient -M FRED \fR will
+send the message in the file \fImymessage.txt\fR
+to the machine FRED.
+
+You may also find the \fI-U\fR and
+\fI-I\fR options useful, as they allow you to
control the FROM and TO parts of the message.
-Samba currently has no way of receiving WinPopup messages.
-
-Note: Copy WinPopup into the startup group on your WfWg PCs if you
-want them to always be able to receive messages.
-.RE
-
-.B -E
-
-.RS 3
-This parameter, if specified, causes the client to write messages to the
-standard error stream (stderr) rather than to the standard output stream.
-
-By default, the client writes messages to standard output - typically the
-user's tty.
-.RE
-
-.B -I
-.I IP number
-
-.RS 3
-.I IP number
-represents the IP number of the server to connect to. It should
-be specified in standard "a.b.c.d" notation.
-
-Normally the client will attempt to locate the specified Lan Manager server
-by looking it up - that is, broadcasting a request for the given server to
-identify itself. Using this parameter will force the client to assume that
-the server is on the machine with the specified IP number.
-
-There is no default for this parameter. If not supplied, it will be determined
-automatically by the client as described above.
-.RE
-
-.B -N
-
-.RS 3
-If specified, this parameter suppresses the normal password prompt from the
-client to the user. This is useful when accessing a service that does not
-require a password.
-
-Unless a password is specified on the command line or this parameter is
-specified, the client will request a password.
-.RE
-
-.B -O
-.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
-
-.RE
-.B -P
-
-.RS 3
-If specified, the service requested will be connected to as a printer service
-rather than as a normal filespace service. Operations such as put and get
-will not be applicable for such a connection.
-
-By default, services will be connected to as NON-printer services.
-.RE
-
-.B -U
-.I username
-
-.RS 3
-.I username
-is the user name that will be used by the client to make a connection,
-assuming your server is running a protocol that allows for usernames.
-
-Some servers are fussy about the case of this name, and some insist
-that it must be a valid netbios name.
-
-If no
-.I username
-is supplied, it will default to an uppercase version of the
-environment variable
-.B USER
-or
-.B LOGNAME
-in that order.
-If no
-.I username
-is supplied and neither environment variable exists the user name will
-be empty.
-
-If the service you are connecting to requires a password, it can be supplied
-using the
-.B -U
-option, by appending a percent symbol ("%") then the password to
-.I username.
-For example, to attach to a service as user "fred" with password "secret", you
-would specify
-.B -U
-.I fred%secret
-on the command line. Note that there are no spaces around the percent symbol.
-
-If you specify the password as part of
-.I username
-then the
-.B -N
-option (suppress password prompt) is assumed.
-
-If you specify the password as a parameter AND as part of
-.I username
-then the password as part of
-.I username
-will take precedence. Putting nothing before or nothing after the percent
-symbol will cause an empty username or an empty password to be used,
-respectively.
-
-Note: Some servers (including OS/2 and Windows for Workgroups) insist
-on an uppercase password. Lowercase or mixed case passwords may be
-rejected by these servers.
-
-Be cautious about including passwords in scripts.
-.RE
-
-.B -d
-.I debuglevel
-.RS 3
-
-debuglevel is an integer from 0 to 5.
-
-The default value if this parameter is not specified is zero.
-
-The higher this value, the more detail will be logged to the log files about
-the activities of the client. At level 0, only critical errors and serious
-warnings will be logged. Level 1 is a reasonable level for day to day running
-- it generates a small amount of information about operations carried out.
-
-Levels above 1 will generate considerable amounts of log data, and should
-only be used when investigating a problem. Levels above 3 are designed for
-use only by developers and generate HUGE amounts of log data, most of which
-is extremely cryptic.
-.RE
-
-.B -l
-.I log basename
-
-.RS 3
-If specified,
-.I log basename
-specifies a base filename into which operational data from the running client
-will be logged.
+See the message command parameter in the \fI smb.conf(5)\fR for a description of how to handle incoming
+WinPopup messages in Samba.
+
+\fBNote\fR: Copy WinPopup into the startup group
+on your WfWg PCs if you want them to always be able to receive
+messages.
+.TP
+\fB-i scope\fR
+This specifies a NetBIOS scope that smbclient will
+use to communicate with when generating NetBIOS names. For details
+on the use of NetBIOS scopes, see \fIrfc1001.txt\fR
+and \fIrfc1002.txt\fR.
+NetBIOS scopes are \fBvery\fR rarely used, only set
+this parameter if you are the system administrator in charge of all
+the NetBIOS systems you communicate with.
+.TP
+\fB-N\fR
+If specified, this parameter suppresses the normal
+password prompt from the client to the user. This is useful when
+accessing a service that does not require a password.
+
+Unless a password is specified on the command line or
+this parameter is specified, the client will request a
+password.
+.TP
+\fB-n NetBIOS name\fR
+By default, the client will use the local
+machine's hostname (in uppercase) as its NetBIOS name. This parameter
+allows you to override the host name and use whatever NetBIOS
+name you wish.
+.TP
+\fB-d debuglevel\fR
+\fIdebuglevel\fR is an integer from 0 to 10, or
+the letter 'A'.
+
+The default value if this parameter is not specified
+is zero.
+
+The higher this value, the more detail will be logged to
+the log files about the activities of the
+client. At level 0, only critical errors and serious warnings will
+be logged. Level 1 is a reasonable level for day to day running -
+it generates a small amount of information about operations
+carried out.
+
+Levels above 1 will generate considerable amounts of log
+data, and should only be used when investigating a problem.
+Levels above 3 are designed for use only by developers and
+generate HUGE amounts of log data, most of which is extremely
+cryptic. If \fIdebuglevel\fR is set to the letter 'A', then \fBall
+\fRdebug messages will be printed. This setting
+is for developers only (and people who \fBreally\fR want
+to know how the code works internally).
+
+Note that specifying this parameter here will override
+the log level parameter in the \fIsmb.conf (5)\fR
+file.
+.TP
+\fB-p port\fR
+This number is the TCP port number that will be used
+when making connections to the server. The standard (well-known)
+TCP port number for an SMB/CIFS server is 139, which is the
+default.
+.TP
+\fB-l logfilename\fR
+If specified, \fIlogfilename\fR specifies a base filename
+into which operational data from the running client will be
+logged.
The default base name is specified at compile time.
-The base name is used to generate actual log file names. For example, if the
-name specified was "log", the following files would be used for log data:
-
-.RS 3
-log.client.debug (containing debugging information)
-
-log.client.in (containing inbound transaction data)
-
-log.client.out (containing outbound transaction data)
-.RE
-
-The log files generated are never removed by the client.
-.RE
-.RE
-
-.B -n
-.I netbios name
-
-.RS 3
-By default, the client will use the local machine's hostname (in
-uppercase) as its netbios name. This parameter allows you to override
-the host name and use whatever netbios name you wish.
-.RE
-
-.B -p
-.I port number
-.RS 3
-
-port number is a positive integer value.
-
-The default value if this parameter is not specified is 139.
-
-This number is the port number that will be used when making connections to
-the server. The standard (well-known) port number for the server is 139,
-hence the default.
-
-This parameter is not normally specified.
-
-.B -T
-.I tar options
-.RS3
-
-where tar options are one or more of c,x,I,X,b,g,N or a; used as:
-.LP
-smbclient
-.B "\\\\\\\\server\\\\share"
-\-TcxIXbgNa
-[
-.IR blocksize
-]
-[
-.IR newer-file
-]
-.IR tarfile
-[
-.IR filenames....
-]
-
-.RS3
-.B c
-Create a tar file on UNIX. Must be followed by the name of a tar file,
-tape device or "-" for standard output. (May be useful to set debugging
-low (-d0)) to avoid corrupting your tar file if using "-"). Mutually
-exclusive with the x flag.
-
-.B x
-Extract (restore) a local tar file back to a share. Unless the -D
-option is given, the tar files will be restored from the top level of
-the share. Must be followed by the name of the tar file, device or "-"
-for standard input. Mutually exclusive with the c flag.
-
-.B I
-Include files and directories. Is the default behaviour when
-.IR filenames
-are specified above. Causes tar files to be included in an extract or create
-(and therefore everything else to be excluded). See example below.
-Filename globbing does not work for included files for extractions (yet).
-
-.B X
-Exclude files and directories. Causes tar files to be excluded from
-an extract or create. See example below.
-Filename globbing does not work for excluded files (yet).
-
-.B b
-Blocksize. Must be followed by a valid (greater than zero) blocksize.
-Causes tar file to be written out in blocksize*TBLOCK (usually 512 byte)
-blocks.
-
-.B g
-Incremental. Only back up files that have the archive bit set. Useful
-only with the c flag.
-
-.B N
-Newer than. Must be followed by the name of a file whose date is
-compared against files found on the share during a create. Only files
-newer than the file specified are backed up to the tar file. Useful
-only with the c flag.
-
-.B a
-Set archive bit. Causes the archive bit to be reset when a file is backed
-up. Useful with the g (and c) flags.
-.LP
-
-.B Examples
-
-smbclient \\\\mypc\\myshare "" -N -Tx backup.tar
-
-Restore from tar file backup.tar into myshare on mypc (no password on share).
-
-smbclient \\\\mypc\\myshare "" -N -TXx backup.tar users/docs
-
-Restore everything except users/docs
-
-smbclient \\\\mypc\\myshare "" -N -Tc backup.tar users/docs
-
-Create a tar file of the files beneath users/docs.
-
-.RE
-
-.B -D
-.I initial directory
-
-.RS3
-
-Change to initial directory before starting. Probably only of any use
-with the tar (\-T) option.
-
-
-.RE
-
-.SH OPERATIONS
-Once the client is running, the user is presented with a prompt, "smb: \\>".
-The backslash ("\\") indicates the current working directory on the server,
-and will change if the current working directory is changed.
-
-The prompt indicates that the client is ready and waiting to carry out a user
-command. Each command is a single word, optionally followed by parameters
-specific to that command. Command and parameters are space-delimited unless
-these notes specifically state otherwise. All commands are case-insensitive.
-Parameters to commands may or may not be case sensitive, depending on the
-command.
-
-You can specify file names which have spaces in them by quoting the
-name with double quotes, for example "a long file name".
-
-Parameters shown in square brackets (eg., "[parameter]") are optional. If not
-given, the command will use suitable defaults. Parameters shown in angle
-brackets (eg., "<parameter>") are required.
-
-Note that all commands operating on the server are actually performed by
-issuing a request to the server. Thus the behaviour may vary from server to
-server, depending on how the server was implemented.
-
-The commands available are given here in alphabetical order.
-
-.B ?
-.RS 3
-.B Parameters:
-.RS 3
-.I [command]
-
-.RE
-.B Description:
-.RS 3
-If
-.I command
-is specified, the
-.B ?
-command will display a brief informative message about the specified command.
-
-If no command is specified, a list of available commands will be displayed.
-.RE
-.RE
-
-.B !
-.RS 3
-.B Parameters:
-.RS 3
-.I [shell command]
-
-.RE
-.B Description:
-.RS 3
-If
-.I shell command
-is specified, the
-.B !
-command will execute a shell locally and run the specified shell command. If
-no command is specified, a shell will be run.
-.RE
-.RE
-
-.B cd
-.RS 3
-.B Parameters:
-.RS 3
-.I [directory name]
-
-.RE
-.B Description:
-.RS 3
-If
-.I directory name
-is specified, the current working directory
-.B on the server
-will be changed to the directory specified. This operation will fail if for
-any reason the specified directory is inaccessible.
-
-If no directory name is specified, the current working directory
-.B on the server
-will be reported.
-.RE
-.RE
-
-.B del
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-The client will request that the server attempt to delete all files matching
-.I mask
-from the current working directory
-.B on the server.
-.RE
-.RE
-
-.B dir
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-A list of the files matching
-.I mask
-in the current working directory
-.B on the server
-will be retrieved from the server and displayed.
-.RE
-.RE
-
-.B exit
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Terminate the connection with the server and exit from the program.
-.RE
-.RE
-
-.B get
-.RS 3
-.B Parameters:
-.RS 3
-.I <remote file name> [local file name]
-
-.RE
-.B Description:
-.RS 3
-Copy the file called
-.I remote file name
-from the server to the machine running the client. If specified, name the
-local copy
-.I local file name.
-Note that all transfers in smbclient are binary. See also the
-.B lowercase
-command.
-.RE
-.RE
-
-.B help
-.RS 3
-.B Parameters:
-.RS 3
-.I [command]
-
-.RE
-.B Description:
-.RS 3
-See the
-.B ?
-command above.
-.RE
-.RE
-
-.B lcd
-.RS 3
-.B Parameters:
-.RS 3
-.I [directory name]
-
-.RE
-.B Description:
-.RS 3
-If
-.I directory name
-is specified, the current working directory
-.B on the local machine
-will be changed to the directory specified. This operation will fail if for
-any reason the specified directory is inaccessible.
-
-If no directory name is specified, the name of the current working directory
-.B on the local machine
-will be reported.
-.RE
-.RE
-
-.B lowercase
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle lowercasing of filenames for the
-.B get
-and
-.B mget
-commands.
-
-When lowercasing is toggled ON, local filenames are converted to lowercase
-when using the
-.B get
-and
-.B mget
-commands. This is often useful when copying (say) MSDOS files from a server,
-because lowercase filenames are the norm on Unix systems.
-.RE
-.RE
-
-.B ls
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B dir
-command above.
-.RE
-.RE
-
-.B mask
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-This command allows the user to set up a mask which will be used during
-recursive operation of the
-.B mget
-and
-.B mput
-commands.
-
-The masks specified to the
-.B mget
-and
-.B mput
-commands act as filters for directories
-rather than files when recursion is toggled ON.
-
-The mask specified with the
-.B mask
-command is necessary to filter files within those directories. For example,
-if the mask specified in an
-.B mget
-command is "source*"
-.I and
-the mask specified with the
-.B mask
-command is "*.c"
-.I and
-recursion is toggled ON, the
-.B mget
-command will retrieve all files matching "*.c" in all directories below
-and including all directories matching "source*" in the current working
-directory.
-
-Note that the value for
-.I mask
-defaults to blank (equivalent to "*") and remains so until the
-.B mask
-command is used to change it. It retains the most recently specified value
-indefinitely. To avoid unexpected results it would be wise to change the
-value of
-.I mask
-back to "*" after using the
-.B mget
-or
-.B mput
-commands.
-.RE
-.RE
-
-.B md
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B mkdir
-command.
-.RE
-.RE
-
-.B mget
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Copy all files matching
-.I mask
-from the server to the machine running the client.
-
-Note that
-.I mask
-is interpreted differently during recursive operation and non-recursive
-operation - refer to the
-.B recurse
-and
-.B mask
-commands for more information. Note that all transfers in smbclient are
-binary. See also the
-.B lowercase
-command.
-.RE
-.RE
-
-.B mkdir
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-Create a new directory
-.B on the server
-(user access privileges permitting) with the specified name.
-.RE
-.RE
-
-.B mput
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Copy all files matching
-.I mask
-in the current working directory
-.B on the local machine
-to the current working directory on the server.
-
-Note that
-.I mask
-is interpreted differently during recursive operation and non-recursive
-operation - refer to the
-.B recurse
-and
-.B mask
-commands for more information. Note that all transfers in smbclient are
-binary.
-.RE
-.RE
-
-.B print
-.RS 3
-.B Parameters:
-.RS 3
-.I <file name>
-
-.RE
-.B Description:
-.RS 3
-Print the specified file
-.B from the local machine
-through a printable service on the server.
-
-See also the
-.B printmode
-command.
-.RE
-.RE
-
-.B printmode
-.RS 3
-.B Parameters:
-.RS 3
-.I <graphics or text>
-
-.RE
-.B Description:
-.RS 3
-Set the print mode to suit either binary data (such as graphical information)
-or text. Subsequent
-.B print
-commands will use the currently set print mode.
-.RE
-.RE
-
-.B prompt
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle prompting for filenames during operation of the
-.B mget
-and
-.B mput
-commands.
-
-When toggled ON, the user will be prompted to confirm the transfer of each
-file during these commands. When toggled OFF, all specified files will be
-transferred without prompting.
-.RE
-.RE
-
-.B put
-.RS 3
-.B Parameters:
-.RS 3
-.I <local file name> [remote file name]
-
-.RE
-.B Description:
-.RS 3
-Copy the file called
-.I local file name
-from the machine running the client to the server. If specified, name the
-remote copy
-.I remote file name.
-Note that all transfers in smbclient are binary. See also the
-.B lowercase
-command.
-.RE
-.RE
-
-.B queue
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Displays the print queue, showing the job id, name, size and current status.
-.RE
-.RE
-
-.B quit
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-See the
-.B exit
-command.
-.RE
-.RE
-
-.B rd
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B rmdir
-command.
-.RE
-.RE
-
-.B recurse
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle directory recursion for the commands
-.B mget
-and
-.B mput
-.
-
-When toggled ON, these commands will process all directories in the source
-directory (ie., the directory they are copying
-.I from
-) and will recurse into any that match the mask specified to the command. Only
-files that match the mask specified using the
-.B mask
-command will be retrieved. See also the
-.mask
-command.
-
-When recursion is toggled OFF, only files from the current working
-directory on the source machine that match the mask specified to the
-.B mget
-or
-.B mput
-commands will be copied, and any mask specified using the
-.B mask
-command will be ignored.
-.RE
-.RE
-
-.B rm
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Remove all files matching
-.I mask
-from the current working directory
-.B on the server.
-.RE
-.RE
-
-.B rmdir
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-Remove the specified directory (user access privileges permitting)
-.B from the server.
-.RE
-.RE
-
-.B tar
-.RS 3
-.B Parameters:
-.RS 3
-.I <c|x>[IXbgNa]
-
-.RE
-.B Description:
-.RS 3
-Performs a tar operation - see -T command line option above. Behaviour
-may be affected by the
-.B tarmode
-command (see below). Using the g (incremental) and N (newer) will affect
-tarmode settings. Note that using the "-" option with tar x may not
-work - use the command line option instead.
-.RE
-.RE
-
-.B blocksize
-.RS 3
-.B Parameters
-.RS 3
-.I <blocksize>
-
-.RE
-.B Description
-.RS 3
-Blocksize. Must be followed by a valid (greater than zero) blocksize.
-Causes tar file to be written out in blocksize*TBLOCK (usually 512 byte)
-blocks.
-.RE
-.RE
-
-.B tarmode
-.RS 3
-.B Parameters
-.RS 3
-.I <full|inc|reset|noreset>
-
-.RE
-.B Description
-.RS 3
-Changes tar's behaviour with regard to archive bits. In full mode,
-tar will back up everything regardless of the archive bit setting (this
-is the default mode). In incremental mode, tar will only back up files
-with the archive bit set. In reset mode, tar will reset the archive bit
-on all files it backs up (implies read/write share).
-.RE
-.RE
-
-.B setmode
-.RS 3
-.B Parameters
-.RS 3
-.I <filename> <perm=[+|-]rsha>
-
-.RE
-.B Description
-.RS 3
-A version of the DOS attrib command to set file permissions. For example,
-
-setmode myfile +r
-
-would make myfile read only.
-.RE
-.RE
-
-.SH NOTES
-Some servers are fussy about the case of supplied usernames, passwords, share
-names (aka service names) and machine names. If you fail to connect try
-giving all parameters in uppercase.
-
-It is often necessary to use the
-.B -n
-option when connecting to some types
-of servers. For example OS/2 LanManager insists on a valid netbios name
-being used, so you need to supply a valid name that would be known to
-the server.
-
-.B smbclient
-supports long file names where the server supports the LANMAN2
-protocol.
-
-.SH FILES
-Not applicable.
-
-.SH ENVIRONMENT VARIABLES
-.B USER
-.RS 3
-The variable USER may contain the username of the person using the client.
-This information is used only if the protocol level is high enough to support
+The base name is used to generate actual log file names.
+For example, if the name specified was "log", the debug file
+would be \fIlog.client\fR.
+
+The log file generated is never removed by the client.
+.TP
+\fB-h\fR
+Print the usage message for the client.
+.TP
+\fB-I IP-address\fR
+\fIIP address\fR is the address of the server to connect to.
+It should be specified in standard "a.b.c.d" notation.
+
+Normally the client would attempt to locate a named
+SMB/CIFS server by looking it up via the NetBIOS name resolution
+mechanism described above in the \fIname resolve order\fR
+parameter above. Using this parameter will force the client
+to assume that the server is on the machine with the specified IP
+address and the NetBIOS name component of the resource being
+connected to will be ignored.
+
+There is no default for this parameter. If not supplied,
+it will be determined automatically by the client as described
+above.
+.TP
+\fB-E\fR
+This parameter causes the client to write messages
+to the standard error stream (stderr) rather than to the standard
+output stream.
+
+By default, the client writes messages to standard output
+- typically the user's tty.
+.TP
+\fB-U username[%pass]\fR
+Sets the SMB username or username and password.
+If %pass is not specified, The user will be prompted. The client
+will first check the \fBUSER\fR environment variable, then the
+\fBLOGNAME\fR variable and if either exists, the
+string is uppercased. Anything in these variables following a '%'
+sign will be treated as the password. If these environment
+variables are not found, the username GUEST
+is used.
+
+If the password is not included in these environment
+variables (using the %pass syntax), \fBsmbclient\fR will look for
+a \fBPASSWD\fR environment variable from which
+to read the password.
+
+A third option is to use a credentials file which
+contains the plaintext of the username and password. This
+option is mainly provided for scripts where the admin doesn't
+wish to pass the credentials on the command line or via environment
+variables. If this method is used, make certain that the permissions
+on the file restrict access from unwanted users. See the
+\fI-A\fR for more details.
+
+Be cautious about including passwords in scripts or in
+the \fBPASSWD\fR environment variable. Also, on
+many systems the command line of a running process may be seen
+via the \fBps\fR command to be safe always allow
+\fBsmbclient\fR to prompt for a password and type
+it in directly.
+.TP
+\fB-A filename\fR
+This option allows
+you to specify a file from which to read the username and
+password used in the connection. The format of the file is
+
+.sp
+.nf
+username = <value>
+password = <value>
+
+.sp
+.fi
+
+Make certain that the permissions on the file restrict
+access from unwanted users.
+.TP
+\fB-L\fR
+This option allows you to look at what services
+are available on a server. You use it as \fBsmbclient -L
+host\fR and a list should appear. The \fI-I
+\fRoption may be useful if your NetBIOS names don't
+match your TCP/IP DNS host names or if you are trying to reach a
+host on another network.
+.TP
+\fB-t terminal code\fR
+This option tells \fBsmbclient\fR how to interpret
+filenames coming from the remote server. Usually Asian language
+multibyte UNIX implementations use different character sets than
+SMB/CIFS servers (\fBEUC\fR instead of \fB SJIS\fR for example). Setting this parameter will let
+\fBsmbclient\fR convert between the UNIX filenames and
+the SMB filenames correctly. This option has not been seriously tested
+and may have some problems.
+
+The terminal codes include CWsjis, CWeuc, CWjis7, CWjis8,
+CWjunet, CWhex, CWcap. This is not a complete list, check the Samba
+source code for the complete list.
+.TP
+\fB-b buffersize\fR
+This option changes the transmit/send buffer
+size when getting or putting a file from/to the server. The default
+is 65520 bytes. Setting this value smaller (to 1200 bytes) has been
+observed to speed up file transfers to and from a Win9x server.
+.TP
+\fB-W WORKGROUP\fR
+Override the default workgroup specified in the
+workgroup parameter of the \fIsmb.conf\fR file
+for this connection. This may be needed to connect to some
+servers.
+.TP
+\fB-T tar options\fR
+smbclient may be used to create \fBtar(1)
+\fRcompatible backups of all the files on an SMB/CIFS
+share. The secondary tar flags that can be given to this option
+are :
+.RS
+.TP 0.2i
+\(bu
+\fIc\fR - Create a tar file on UNIX.
+Must be followed by the name of a tar file, tape device
+or "-" for standard output. If using standard output you must
+turn the log level to its lowest value -d0 to avoid corrupting
+your tar file. This flag is mutually exclusive with the
+\fIx\fR flag.
+.TP 0.2i
+\(bu
+\fIx\fR - Extract (restore) a local
+tar file back to a share. Unless the -D option is given, the tar
+files will be restored from the top level of the share. Must be
+followed by the name of the tar file, device or "-" for standard
+input. Mutually exclusive with the \fIc\fR flag.
+Restored files have their creation times (mtime) set to the
+date saved in the tar file. Directories currently do not get
+their creation dates restored properly.
+.TP 0.2i
+\(bu
+\fII\fR - Include files and directories.
+Is the default behavior when filenames are specified above. Causes
+tar files to be included in an extract or create (and therefore
+everything else to be excluded). See example below. Filename globbing
+works in one of two ways. See r below.
+.TP 0.2i
+\(bu
+\fIX\fR - Exclude files and directories.
+Causes tar files to be excluded from an extract or create. See
+example below. Filename globbing works in one of two ways now.
+See \fIr\fR below.
+.TP 0.2i
+\(bu
+\fIb\fR - Blocksize. Must be followed
+by a valid (greater than zero) blocksize. Causes tar file to be
+written out in blocksize*TBLOCK (usually 512 byte) blocks.
+.TP 0.2i
+\(bu
+\fIg\fR - Incremental. Only back up
+files that have the archive bit set. Useful only with the
+\fIc\fR flag.
+.TP 0.2i
+\(bu
+\fIq\fR - Quiet. Keeps tar from printing
+diagnostics as it works. This is the same as tarmode quiet.
+.TP 0.2i
+\(bu
+\fIr\fR - Regular expression include
+or exclude. Uses regular expression matching for
+excluding or excluding files if compiled with HAVE_REGEX_H.
+However this mode can be very slow. If not compiled with
+HAVE_REGEX_H, does a limited wildcard match on '*' and '?'.
+.TP 0.2i
+\(bu
+\fIN\fR - Newer than. Must be followed
+by the name of a file whose date is compared against files found
+on the share during a create. Only files newer than the file
+specified are backed up to the tar file. Useful only with the
+\fIc\fR flag.
+.TP 0.2i
+\(bu
+\fIa\fR - Set archive bit. Causes the
+archive bit to be reset when a file is backed up. Useful with the
+\fIg\fR and \fIc\fR flags.
+.RE
+.PP
+\fBTar Long File Names\fR
+.PP
+.PP
+\fBsmbclient\fR's tar option now supports long
+file names both on backup and restore. However, the full path
+name of the file must be less than 1024 bytes. Also, when
+a tar archive is created, \fBsmbclient\fR's tar option places all
+files in the archive with relative names, not absolute names.
+.PP
+.PP
+\fBTar Filenames\fR
+.PP
+.PP
+All file names can be given as DOS path names (with '\\'
+as the component separator) or as UNIX path names (with '/' as
+the component separator).
+.PP
+.PP
+\fBExamples\fR
+.PP
+.PP
+Restore from tar file \fIbackup.tar\fR into myshare on mypc
+(no password on share).
+.PP
+.PP
+\fBsmbclient //mypc/yshare "" -N -Tx backup.tar
+\fR.PP
+.PP
+Restore everything except \fIusers/docs\fR
+.PP
+.PP
+\fBsmbclient //mypc/myshare "" -N -TXx backup.tar
+users/docs\fR
+.PP
+.PP
+Create a tar file of the files beneath \fI users/docs\fR.
+.PP
+.PP
+\fBsmbclient //mypc/myshare "" -N -Tc
+backup.tar users/docs \fR
+.PP
+.PP
+Create the same tar file as above, but now use
+a DOS path name.
+.PP
+.PP
+\fBsmbclient //mypc/myshare "" -N -tc backup.tar
+users\\edocs \fR
+.PP
+.PP
+Create a tar file of all the files and directories in
+the share.
+.PP
+.PP
+\fBsmbclient //mypc/myshare "" -N -Tc backup.tar *
+\fR.PP
+.TP
+\fB-D initial directory\fR
+Change to initial directory before starting. Probably
+only of any use with the tar -T option.
+.TP
+\fB-c command string\fR
+command string is a semicolon-separated list of
+commands to be executed instead of prompting from stdin. \fI -N\fR is implied by \fI-c\fR.
+
+This is particularly useful in scripts and for printing stdin
+to the server, e.g. \fB-c 'print -'\fR.
+.SH "OPERATIONS"
+.PP
+Once the client is running, the user is presented with
+a prompt :
+.PP
+smb:\\>
+.PP
+The backslash ("\\") indicates the current working directory
+on the server, and will change if the current working directory
+is changed.
+.PP
+The prompt indicates that the client is ready and waiting to
+carry out a user command. Each command is a single word, optionally
+followed by parameters specific to that command. Command and parameters
+are space-delimited unless these notes specifically
+state otherwise. All commands are case-insensitive. Parameters to
+commands may or may not be case sensitive, depending on the command.
+.PP
+You can specify file names which have spaces in them by quoting
+the name with double quotes, for example "a long file name".
+.PP
+Parameters shown in square brackets (e.g., "[parameter]") are
+optional. If not given, the command will use suitable defaults. Parameters
+shown in angle brackets (e.g., "<parameter>") are required.
+.PP
+Note that all commands operating on the server are actually
+performed by issuing a request to the server. Thus the behavior may
+vary from server to server, depending on how the server was implemented.
+.PP
+The commands available are given here in alphabetical order.
+.TP
+\fB? [command]\fR
+If \fIcommand\fR is specified, the ? command will display
+a brief informative message about the specified command. If no
+command is specified, a list of available commands will
+be displayed.
+.TP
+\fB! [shell command]\fR
+If \fIshell command\fR is specified, the !
+command will execute a shell locally and run the specified shell
+command. If no command is specified, a local shell will be run.
+.TP
+\fBcd [directory name]\fR
+If "directory name" is specified, the current
+working directory on the server will be changed to the directory
+specified. This operation will fail if for any reason the specified
+directory is inaccessible.
+
+If no directory name is specified, the current working
+directory on the server will be reported.
+.TP
+\fBdel <mask>\fR
+The client will request that the server attempt
+to delete all files matching \fImask\fR from the current working
+directory on the server.
+.TP
+\fBdir <mask>\fR
+A list of the files matching \fImask\fR in the current
+working directory on the server will be retrieved from the server
+and displayed.
+.TP
+\fBexit\fR
+Terminate the connection with the server and exit
+from the program.
+.TP
+\fBget <remote file name> [local file name]\fR
+Copy the file called \fIremote file name\fR from
+the server to the machine running the client. If specified, name
+the local copy \fIlocal file name\fR. Note that all transfers in
+\fBsmbclient\fR are binary. See also the
+lowercase command.
+.TP
+\fBhelp [command]\fR
+See the ? command above.
+.TP
+\fBlcd [directory name]\fR
+If \fIdirectory name\fR is specified, the current
+working directory on the local machine will be changed to
+the directory specified. This operation will fail if for any
+reason the specified directory is inaccessible.
+
+If no directory name is specified, the name of the
+current working directory on the local machine will be reported.
+.TP
+\fBlowercase\fR
+Toggle lowercasing of filenames for the get and
+mget commands.
+
+When lowercasing is toggled ON, local filenames are converted
+to lowercase when using the get and mget commands. This is
+often useful when copying (say) MSDOS files from a server, because
+lowercase filenames are the norm on UNIX systems.
+.TP
+\fBls <mask>\fR
+See the dir command above.
+.TP
+\fBmask <mask>\fR
+This command allows the user to set up a mask
+which will be used during recursive operation of the mget and
+mput commands.
+
+The masks specified to the mget and mput commands act as
+filters for directories rather than files when recursion is
+toggled ON.
+
+The mask specified with the mask command is necessary
+to filter files within those directories. For example, if the
+mask specified in an mget command is "source*" and the mask
+specified with the mask command is "*.c" and recursion is
+toggled ON, the mget command will retrieve all files matching
+"*.c" in all directories below and including all directories
+matching "source*" in the current working directory.
+
+Note that the value for mask defaults to blank (equivalent
+to "*") and remains so until the mask command is used to change it.
+It retains the most recently specified value indefinitely. To
+avoid unexpected results it would be wise to change the value of
+mask back to "*" after using the mget or mput commands.
+.TP
+\fBmd <directory name>\fR
+See the mkdir command.
+.TP
+\fBmget <mask>\fR
+Copy all files matching \fImask\fR from the server to
+the machine running the client.
+
+Note that \fImask\fR is interpreted differently during recursive
+operation and non-recursive operation - refer to the recurse and
+mask commands for more information. Note that all transfers in
+\fBsmbclient\fR are binary. See also the lowercase command.
+.TP
+\fBmkdir <directory name>\fR
+Create a new directory on the server (user access
+privileges permitting) with the specified name.
+.TP
+\fBmput <mask>\fR
+Copy all files matching \fImask\fR in the current working
+directory on the local machine to the current working directory on
+the server.
+
+Note that \fImask\fR is interpreted differently during recursive
+operation and non-recursive operation - refer to the recurse and mask
+commands for more information. Note that all transfers in \fBsmbclient\fR
+are binary.
+.TP
+\fBprint <file name>\fR
+Print the specified file from the local machine
+through a printable service on the server.
+
+See also the printmode command.
+.TP
+\fBprintmode <graphics or text>\fR
+Set the print mode to suit either binary data
+(such as graphical information) or text. Subsequent print
+commands will use the currently set print mode.
+.TP
+\fBprompt\fR
+Toggle prompting for filenames during operation
+of the mget and mput commands.
+
+When toggled ON, the user will be prompted to confirm
+the transfer of each file during these commands. When toggled
+OFF, all specified files will be transferred without prompting.
+.TP
+\fBput <local file name> [remote file name]\fR
+Copy the file called \fIlocal file name\fR from the
+machine running the client to the server. If specified,
+name the remote copy \fIremote file name\fR. Note that all transfers
+in \fBsmbclient\fR are binary. See also the lowercase command.
+.TP
+\fBqueue\fR
+Displays the print queue, showing the job id,
+name, size and current status.
+.TP
+\fBquit\fR
+See the exit command.
+.TP
+\fBrd <directory name>\fR
+See the rmdir command.
+.TP
+\fBrecurse\fR
+Toggle directory recursion for the commands mget
+and mput.
+
+When toggled ON, these commands will process all directories
+in the source directory (i.e., the directory they are copying
+from ) and will recurse into any that match the mask specified
+to the command. Only files that match the mask specified using
+the mask command will be retrieved. See also the mask command.
+
+When recursion is toggled OFF, only files from the current
+working directory on the source machine that match the mask specified
+to the mget or mput commands will be copied, and any mask specified
+using the mask command will be ignored.
+.TP
+\fBrm <mask>\fR
+Remove all files matching \fImask\fR from the current
+working directory on the server.
+.TP
+\fBrmdir <directory name>\fR
+Remove the specified directory (user access
+privileges permitting) from the server.
+.TP
+\fBtar <c|x>[IXbgNa]\fR
+Performs a tar operation - see the \fI-T
+\fRcommand line option above. Behavior may be affected
+by the tarmode command (see below). Using g (incremental) and N
+(newer) will affect tarmode settings. Note that using the "-" option
+with tar x may not work - use the command line option instead.
+.TP
+\fBblocksize <blocksize>\fR
+Blocksize. Must be followed by a valid (greater
+than zero) blocksize. Causes tar file to be written out in
+\fIblocksize\fR*TBLOCK (usually 512 byte) blocks.
+.TP
+\fBtarmode <full|inc|reset|noreset>\fR
+Changes tar's behavior with regard to archive
+bits. In full mode, tar will back up everything regardless of the
+archive bit setting (this is the default mode). In incremental mode,
+tar will only back up files with the archive bit set. In reset mode,
+tar will reset the archive bit on all files it backs up (implies
+read/write share).
+.TP
+\fBsetmode <filename> <perm=[+|\\-]rsha>\fR
+A version of the DOS attrib command to set
+file permissions. For example:
+
+\fBsetmode myfile +r \fR
+
+would make myfile read only.
+.SH "NOTES"
+.PP
+Some servers are fussy about the case of supplied usernames,
+passwords, share names (AKA service names) and machine names.
+If you fail to connect try giving all parameters in uppercase.
+.PP
+It is often necessary to use the -n option when connecting
+to some types of servers. For example OS/2 LanManager insists
+on a valid NetBIOS name being used, so you need to supply a valid
+name that would be known to the server.
+.PP
+smbclient supports long file names where the server
+supports the LANMAN2 protocol or above.
+.SH "ENVIRONMENT VARIABLES"
+.PP
+The variable \fBUSER\fR may contain the
+username of the person using the client. This information is
+used only if the protocol level is high enough to support
session-level passwords.
-.RE
-
-.SH INSTALLATION
-The location of the client program is a matter for individual system
-administrators. The following are thus suggestions only.
-
-It is recommended that the client software be installed under the /usr/local
-hierarchy, in a directory readable by all, writeable only by root. The client
-program itself should be executable by all. The client should NOT be setuid
-or setgid!
-
-The client log files should be put in a directory readable and writable only
-by the user.
-
-To test the client, you will need to know the name of a running Lan manager
-server. It is possible to run the smbd (see
-.B smbd(8)) as an ordinary user - running that server as a daemon on a
-user-accessible port (typically any port number over 1024) would
-provide a suitable test server.
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the client software, so it is possible that your version of
-the client has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B smbd(8)
-
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the client are logged in a specified log file. The
-log file name is specified at compile time, but may be overridden on the
-command line.
-
-The number and nature of diagnostics available depends on the debug level used
-by the client. If you have problems, set the debug level to 3 and peruse the
-log files.
-
-Most messages are reasonably self-explanatory. Unfortunately, at time of
-creation of this man page the source code is still too fluid to warrant
-describing each and every diagnostic. At this stage your best bet is still
-to grep the source code and inspect the conditions that gave rise to the
-diagnostics you are seeing.
-
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B smb.conf(5) for a full list of contributors and details on how to
-submit bug reports, comments etc.
+.PP
+The variable \fBPASSWD\fR may contain
+the password of the person using the client. This information is
+used only if the protocol level is high enough to support
+session-level passwords.
+.PP
+The variable \fBLIBSMB_PROG\fR may contain
+the path, executed with system(), which the client should connect
+to instead of connecting to a server. This functionality is primarily
+intended as a development aid, and works best when using a LMHOSTS
+file
+.SH "INSTALLATION"
+.PP
+The location of the client program is a matter for
+individual system administrators. The following are thus
+suggestions only.
+.PP
+It is recommended that the smbclient software be installed
+in the \fI/usr/local/samba/bin/\fR or \fI /usr/samba/bin/\fR directory, this directory readable
+by all, writeable only by root. The client program itself should
+be executable by all. The client should \fBNOT\fR be
+setuid or setgid!
+.PP
+The client log files should be put in a directory readable
+and writeable only by the user.
+.PP
+To test the client, you will need to know the name of a
+running SMB/CIFS server. It is possible to run \fBsmbd(8)
+\fRas an ordinary user - running that server as a daemon
+on a user-accessible port (typically any port number over 1024)
+would provide a suitable test server.
+.SH "DIAGNOSTICS"
+.PP
+Most diagnostics issued by the client are logged in a
+specified log file. The log file name is specified at compile time,
+but may be overridden on the command line.
+.PP
+The number and nature of diagnostics available depends
+on the debug level used by the client. If you have problems,
+set the debug level to 3 and peruse the log files.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbcontrol.1 b/docs/manpages/smbcontrol.1
new file mode 100644
index 00000000000..4b27119673a
--- /dev/null
+++ b/docs/manpages/smbcontrol.1
@@ -0,0 +1,124 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBCONTROL" "1" "06 December 2001" "" ""
+.SH NAME
+smbcontrol \- send messages to smbd or nmbd processes
+.SH SYNOPSIS
+.sp
+\fBsmbcontrol\fR [ \fB-i\fR ]
+.sp
+\fBsmbcontrol\fR [ \fBdestination\fR ] [ \fBmessage-type\fR ] [ \fBparameter\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBsmbcontrol\fR is a very small program, which
+sends messages to an smbd(8)or
+an nmbd(8)daemon running on the
+system.
+.SH "OPTIONS"
+.TP
+\fB-i\fR
+Run interactively. Individual commands
+of the form destination message-type parameters can be entered
+on STDIN. An empty command line or a "q" will quit the
+program.
+.TP
+\fBdestination\fR
+One of \fInmbd\fR
+\fIsmbd\fR or a process ID.
+
+The \fIsmbd\fR destination causes the
+message to "broadcast" to all smbd daemons.
+
+The \fInmbd\fR destination causes the
+message to be sent to the nmbd daemon specified in the
+\fInmbd.pid\fR file.
+
+If a single process ID is given, the message is sent
+to only that process.
+.TP
+\fBmessage-type\fR
+One of: close-share,
+debug,
+force-election, ping
+, profile, debuglevel, profilelevel,
+or printer-notify.
+
+The close-share message-type sends a
+message to smbd which will then close the client connections to
+the named share. Note that this doesn't affect client connections
+to any other shares. This message-type takes an argument of the
+share name for which client connections will be close, or the
+"*" character which will close all currently open shares.
+This message can only be sent to smbd.
+
+The debug message-type allows
+the debug level to be set to the value specified by the
+parameter. This can be sent to any of the destinations.
+
+The force-election message-type can only be
+sent to the nmbd destination. This message
+causes the \fBnmbd\fR daemon to force a new browse
+master election.
+
+The ping message-type sends the
+number of "ping" messages specified by the parameter and waits
+for the same number of reply "pong" messages. This can be sent to
+any of the destinations.
+
+The profile message-type sends a
+message to an smbd to change the profile settings based on the
+parameter. The parameter can be "on" to turn on profile stats
+collection, "off" to turn off profile stats collection, "count"
+to enable only collection of count stats (time stats are
+disabled), and "flush" to zero the current profile stats. This can
+be sent to any of the destinations.
+
+The debuglevel message-type sends
+a "request debug level" message. The current debug level setting
+is returned by a "debuglevel" message. This can be
+sent to any of the destinations.
+
+The profilelevel message-type sends
+a "request profile level" message. The current profile level
+setting is returned by a "profilelevel" message. This can be sent
+to any of the destinations.
+
+The printer-notify message-type sends a
+message to smbd which in turn sends a printer notify message to
+any Windows NT clients connected to a printer. This message-type
+takes an argument of the printer name to send notify messages to.
+This message can only be sent to smbd.
+
+The close-share message-type sends a
+message to smbd which forces smbd to close the share that was
+specified as an argument. This may be useful if you made changes
+to the access controls on the share.
+.TP
+\fBparameters\fR
+any parameters required for the message-type
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBnmbd(8)\fR,
+and \fBsmbd(8)\fR.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbd.8 b/docs/manpages/smbd.8
index bae41b2c479..a01a239e5eb 100644
--- a/docs/manpages/smbd.8
+++ b/docs/manpages/smbd.8
@@ -1,407 +1,491 @@
-.TH SMBD 8 17/1/1995 smbd smbd
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBD" "8" "20 December 2001" "" ""
.SH NAME
-smbd \- provide SMB (aka LanManager) services to clients
+smbd \- server to provide SMB/CIFS services to clients
.SH SYNOPSIS
-.B smbd
-[
-.B -D
-] [
-.B -a
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log file
-] [
-.B -p
-.I port number
-] [
-.B -O
-.I socket options
-] [
-.B -s
-.I configuration file
-]
-.SH DESCRIPTION
+.sp
+\fBsmbd\fR [ \fB-D\fR ] [ \fB-a\fR ] [ \fB-o\fR ] [ \fB-P\fR ] [ \fB-h\fR ] [ \fB-V\fR ] [ \fB-b\fR ] [ \fB-d <debug level>\fR ] [ \fB-l <log directory>\fR ] [ \fB-p <port number>\fR ] [ \fB-O <socket option>\fR ] [ \fB-s <configuration file>\fR ]
+.SH "DESCRIPTION"
+.PP
This program is part of the Samba suite.
-
-.B smbd
-is a server that can provide most SMB services. The
-server provides filespace and printer services to clients using the SMB
-protocol. This is compatible with the LanManager protocol, and can
-service LanManager clients.
-
-An extensive description of the services that the server can provide is given
-in the man page for the configuration file controlling the attributes of those
-services (see
-.B smb.conf(5)). This man page will not describe the services, but
-will concentrate on the administrative aspects of running the server.
-
-Please note that there are significant security implications to running this
-server, and
-.B smb.conf(5) should be regarded as mandatory reading before proceeding with
-installation.
-
-A session is created whenever a client requests one. Each client gets a copy
-of the server for each session. This copy then services all connections made
-by the client during that session. When all connections from its client are
-are closed, the copy of the server for that client terminates.
-
-The configuration file is automatically reloaded if it changes. You
-can force a reload by sending a SIGHUP to the server.
-
-.SH OPTIONS
-.B -D
-
-.RS 3
-If specified, this parameter causes the server to operate as a daemon. That is,
-it detaches itself and runs in the background, fielding requests on the
-appropriate port.
-
-By default, the server will NOT operate as a daemon.
-.RE
-
-.B -a
-
-.RS 3
-If this parameter is specified, the log files will be overwritten with each
-new connection. By default, the log files will be appended to.
-.RE
-
-.B -d
-.I debuglevel
-.RS 3
-
-debuglevel is an integer from 0 to 5.
-
-The default value if this parameter is not specified is zero.
-
-The higher this value, the more detail will be logged to the log files about
-the activities of the server. At level 0, only critical errors and serious
-warnings will be logged. Level 1 is a reasonable level for day to day running
-- it generates a small amount of information about operations carried out.
-
-Levels above 1 will generate considerable amounts of log data, and should
-only be used when investigating a problem. Levels above 3 are designed for
-use only by developers and generate HUGE amounts of log data, most of which
-is extremely cryptic.
-.RE
-
-.B -l
-.I log file
-
-.RS 3
+.PP
+\fBsmbd\fR is the server daemon that
+provides filesharing and printing services to Windows clients.
+The server provides filespace and printer services to
+clients using the SMB (or CIFS) protocol. This is compatible
+with the LanManager protocol, and can service LanManager
+clients. These include MSCLIENT 3.0 for DOS, Windows for
+Workgroups, Windows 95/98/ME, Windows NT, Windows 2000,
+OS/2, DAVE for Macintosh, and smbfs for Linux.
+.PP
+An extensive description of the services that the
+server can provide is given in the man page for the
+configuration file controlling the attributes of those
+services (see \fIsmb.conf(5)
+\fR. This man page will not describe the
+services, but will concentrate on the administrative aspects
+of running the server.
+.PP
+Please note that there are significant security
+implications to running this server, and the \fIsmb.conf(5)\fR
+manpage should be regarded as mandatory reading before
+proceeding with installation.
+.PP
+A session is created whenever a client requests one.
+Each client gets a copy of the server for each session. This
+copy then services all connections made by the client during
+that session. When all connections from its client are closed,
+the copy of the server for that client terminates.
+.PP
+The configuration file, and any files that it includes,
+are automatically reloaded every minute, if they change. You
+can force a reload by sending a SIGHUP to the server. Reloading
+the configuration file will not affect connections to any service
+that is already established. Either the user will have to
+disconnect from the service, or \fBsmbd\fR killed and restarted.
+.SH "OPTIONS"
+.TP
+\fB-D\fR
+If specified, this parameter causes
+the server to operate as a daemon. That is, it detaches
+itself and runs in the background, fielding requests
+on the appropriate port. Operating the server as a
+daemon is the recommended way of running \fBsmbd\fR for
+servers that provide more than casual use file and
+print services. This switch is assumed if \fBsmbd
+\fRis executed on the command line of a shell.
+.TP
+\fB-a\fR
+If this parameter is specified, each new
+connection will append log messages to the log file.
+This is the default.
+.TP
+\fB-o\fR
+If this parameter is specified, the
+log files will be overwritten when opened. By default,
+\fBsmbd\fR will append entries to the log
+files.
+.TP
+\fB-P\fR
+Passive option. Causes \fBsmbd\fR not to
+send any network traffic out. Used for debugging by
+the developers only.
+.TP
+\fB-h\fR
+Prints the help information (usage)
+for \fBsmbd\fR.
+.TP
+\fB-v\fR
+Prints the version number for
+\fBsmbd\fR.
+.TP
+\fB-b\fR
+Prints information about how
+Samba was built.
+.TP
+\fB-d <debug level>\fR
+\fIdebuglevel\fR is an integer
+from 0 to 10. The default value if this parameter is
+not specified is zero.
+
+The higher this value, the more detail will be
+logged to the log files about the activities of the
+server. At level 0, only critical errors and serious
+warnings will be logged. Level 1 is a reasonable level for
+day to day running - it generates a small amount of
+information about operations carried out.
+
+Levels above 1 will generate considerable
+amounts of log data, and should only be used when
+investigating a problem. Levels above 3 are designed for
+use only by developers and generate HUGE amounts of log
+data, most of which is extremely cryptic.
+
+Note that specifying this parameter here will
+override the log
+levelfile.
+.TP
+\fB-l <log directory>\fR
If specified,
-.I logfile
-specifies a base filename into which operational data from the running server
-will be logged.
-
-The default base name is specified at compile time.
-
-The base name is used to generate actual log file names. For example, if the
-name specified was "log", the following files would be used for log data:
-
-.RS 3
-log.debug (containing debugging information)
-
-log.in (containing inbound transaction data)
-
-log.out (containing outbound transaction data)
-.RE
-
-The log files generated are never removed by the server.
-.RE
-
-.B -O
-.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
-
-.RE
-.B -p
-.I port number
-.RS 3
-
-port number is a positive integer value.
-
-The default value if this parameter is not specified is 139.
-
-This number is the port number that will be used when making connections to
-the server from client software. The standard (well-known) port number for the
-server is 139, hence the default. If you wish to run the server as an ordinary
-user rather than as root, most systems will require you to use a port number
-greater than 1024 - ask your system administrator for help if you are in this
-situation.
-
-This parameter is not normally specified except in the above situation.
-.RE
-
-.B -s
-.I configuration file
-
-.RS 3
-The default configuration file name is determined at compile time.
-
-The file specified contains the configuration details required by the server.
-The information in this file includes server-specific information such as
-what printcap file to use, as well as descriptions of all the services that the
-server is to provide. See
-.B smb.conf(5) for more information.
-.RE
-
-.SH FILES
-
-.B /etc/inetd.conf
-
-.RS 3
-If the server is to be run by the inetd meta-daemon, this file must contain
-suitable startup information for the meta-daemon. See the section
-"INSTALLATION" below.
-.RE
-
-.B /etc/rc
-
-.RS 3
-(or whatever initialisation script your system uses)
-
-If running the server as a daemon at startup, this file will need to contain
-an appropriate startup sequence for the server. See the section "INSTALLATION"
+\fIlog directory\fR
+specifies a log directory into which the "log.smbd" log
+file will be created for informational and debug
+messages from the running server. The log
+file generated is never removed by the server although
+its size may be controlled by the max log size
+option in the \fI smb.conf(5)\fRfile.
+
+The default log directory is specified at
+compile time.
+.TP
+\fB-O <socket options>\fR
+See the socket options
+parameter in the \fIsmb.conf(5)
+\fRfile for details.
+.TP
+\fB-p <port number>\fR
+\fIport number\fR is a positive integer
+value. The default value if this parameter is not
+specified is 139.
+
+This number is the port number that will be
+used when making connections to the server from client
+software. The standard (well-known) port number for the
+SMB over TCP is 139, hence the default. If you wish to
+run the server as an ordinary user rather than
+as root, most systems will require you to use a port
+number greater than 1024 - ask your system administrator
+for help if you are in this situation.
+
+In order for the server to be useful by most
+clients, should you configure it on a port other
+than 139, you will require port redirection services
+on port 139, details of which are outlined in rfc1002.txt
+section 4.3.5.
+
+This parameter is not normally specified except
+in the above situation.
+.TP
+\fB-s <configuration file>\fR
+The file specified contains the
+configuration details required by the server. The
+information in this file includes server-specific
+information such as what printcap file to use, as well
+as descriptions of all the services that the server is
+to provide. See \fI smb.conf(5)\fRfor more information.
+The default configuration file name is determined at
+compile time.
+.SH "FILES"
+.TP
+\fB\fI/etc/inetd.conf\fB\fR
+If the server is to be run by the
+\fBinetd\fR meta-daemon, this file
+must contain suitable startup information for the
+meta-daemon. See the section INSTALLATION below.
+.TP
+\fB\fI/etc/rc\fB\fR
+or whatever initialization script your
+system uses).
+
+If running the server as a daemon at startup,
+this file will need to contain an appropriate startup
+sequence for the server. See the section INSTALLATION
below.
-.RE
-
-.B /etc/services
-
-.RS 3
-If running the server via the meta-daemon inetd, this file must contain a
-mapping of service name (eg., netbios-ssn) to service port (eg., 139) and
-protocol type (eg., tcp). See the section "INSTALLATION" below.
-.RE
-
-.B /usr/local/smb/smb.conf
-
-.RS 3
-This file describes all the services the server is to make available to
-clients. See
-.B smb.conf(5) for more information.
-.RE
-.RE
-
-.SH LIMITATIONS
-
-On some systems smbd cannot change uid back to root after a setuid() call.
-Such systems are called "trapdoor" uid systems. If you have such a system,
-you will be unable to connect from a client (such as a PC) as two different
-users at once. Attempts to connect the second user will result in "access
-denied" or similar.
-
-.SH ENVIRONMENT VARIABLES
-
-.B PRINTER
-
-.RS 3
-If no printer name is specified to printable services, most systems will
-use the value of this variable (or "lp" if this variable is not defined)
-as the name of the printer to use. This is not specific to the server,
-however.
-.RE
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the server software be installed under the
-/usr/local hierarchy, in a directory readable by all, writeable only
-by root. The server program itself should be executable by all, as
-users may wish to run the server themselves (in which case it will of
-course run with their privileges). The server should NOT be
-setuid. On some systems it may be worthwhile to make smbd setgid to an
-empty group. This is because some systems may have a security hole where
-daemon processes that become a user can be attached to with a
-debugger. Making the smbd file setgid to an empty group may prevent
-this hole from being exploited. This secrity hole and the suggested
-fix has only been confirmed on Linux at the time this was written. It
-is possible that this hole only exists in Linux, as testing on other
-systems has thus far shown them to be immune.
-
-The server log files should be put in a directory readable and writable only
-by root, as the log files may contain sensitive information.
-
-The configuration file should be placed in a directory readable and writable
-only by root, as the configuration file controls security for the services
-offered by the server. The configuration file can be made readable by all if
-desired, but this is not necessary for correct operation of the server and
-is not recommended. A sample configuration file "smb.conf.sample" is supplied
-with the source to the server - this may be renamed to "smb.conf" and
-modified to suit your needs.
-
+.TP
+\fB\fI/etc/services\fB\fR
+If running the server via the
+meta-daemon \fBinetd\fR, this file
+must contain a mapping of service name (e.g., netbios-ssn)
+to service port (e.g., 139) and protocol type (e.g., tcp).
+See the section INSTALLATION below.
+.TP
+\fB\fI/usr/local/samba/lib/smb.conf\fB\fR
+This is the default location of the
+\fIsmb.conf\fR
+server configuration file. Other common places that systems
+install this file are \fI/usr/samba/lib/smb.conf\fR
+and \fI/etc/smb.conf\fR.
+
+This file describes all the services the server
+is to make available to clients. See \fIsmb.conf(5)\fRfor more information.
+.SH "LIMITATIONS"
+.PP
+On some systems \fBsmbd\fR cannot change uid back
+to root after a setuid() call. Such systems are called
+trapdoor uid systems. If you have such a system,
+you will be unable to connect from a client (such as a PC) as
+two different users at once. Attempts to connect the
+second user will result in access denied or
+similar.
+.SH "ENVIRONMENT VARIABLES"
+.TP
+\fBPRINTER\fR
+If no printer name is specified to
+printable services, most systems will use the value of
+this variable (or lp if this variable is
+not defined) as the name of the printer to use. This
+is not specific to the server, however.
+.SH "INSTALLATION"
+.PP
+The location of the server and its support files
+is a matter for individual system administrators. The following
+are thus suggestions only.
+.PP
+It is recommended that the server software be installed
+under the \fI/usr/local/samba/\fR hierarchy,
+in a directory readable by all, writeable only by root. The server
+program itself should be executable by all, as users may wish to
+run the server themselves (in which case it will of course run
+with their privileges). The server should NOT be setuid. On some
+systems it may be worthwhile to make \fBsmbd\fR setgid to an empty group.
+This is because some systems may have a security hole where daemon
+processes that become a user can be attached to with a debugger.
+Making the \fBsmbd\fR file setgid to an empty group may prevent
+this hole from being exploited. This security hole and the suggested
+fix has only been confirmed on old versions (pre-kernel 2.0) of Linux
+at the time this was written. It is possible that this hole only
+exists in Linux, as testing on other systems has thus far shown them
+to be immune.
+.PP
+The server log files should be put in a directory readable and
+writeable only by root, as the log files may contain sensitive
+information.
+.PP
+The configuration file should be placed in a directory
+readable and writeable only by root, as the configuration file
+controls security for the services offered by the server. The
+configuration file can be made readable by all if desired, but
+this is not necessary for correct operation of the server and is
+not recommended. A sample configuration file \fIsmb.conf.sample
+\fRis supplied with the source to the server - this may
+be renamed to \fIsmb.conf\fR and modified to suit
+your needs.
+.PP
The remaining notes will assume the following:
-
-.RS 3
-smbd (the server program) installed in /usr/local/smb
-
-smb.conf (the configuration file) installed in /usr/local/smb
-
-log files stored in /var/adm/smblogs
-.RE
-
-The server may be run either as a daemon by users or at startup, or it may
-be run from a meta-daemon such as inetd upon request. If run as a daemon, the
-server will always be ready, so starting sessions will be faster. If run from
-a meta-daemon some memory will be saved and utilities such as the tcpd
-TCP-wrapper may be used for extra security.
-
-When you've decided, continue with either "RUNNING THE SERVER AS A DAEMON" or
-"RUNNING THE SERVER ON REQUEST".
-.SH RUNNING THE SERVER AS A DAEMON
-To run the server as a daemon from the command line, simply put the "-D" option
-on the command line. There is no need to place an ampersand at the end of the
-command line - the "-D" option causes the server to detach itself from the
-tty anyway.
-
-Any user can run the server as a daemon (execute permissions permitting, of
-course). This is useful for testing purposes, and may even be useful as a
-temporary substitute for something like ftp. When run this way, however, the
-server will only have the privileges of the user who ran it.
-
-To ensure that the server is run as a daemon whenever the machine is started,
-and to ensure that it runs as root so that it can serve multiple clients, you
-will need to modify the system startup files. Wherever appropriate (for
-example, in /etc/rc), insert the following line, substituting
-port number, log file location, configuration file location and debug level as
-desired:
-
-.RS 3
-/usr/local/smb/smbd -D -l /var/adm/smblogs/log -s /usr/local/smb/smb.conf
-.RE
-
-(The above should appear in your initialisation script as a single line.
-Depending on your terminal characteristics, it may not appear that way in
-this man page. If the above appears as more than one line, please treat any
-newlines or indentation as a single space or TAB character.)
-
-If the options used at compile time are appropriate for your system, all
-parameters except the desired debug level and "-D" may be omitted. See the
-section "OPTIONS" above.
-.SH RUNNING THE SERVER ON REQUEST
-If your system uses a meta-daemon such as inetd, you can arrange to have the
-smbd server started whenever a process attempts to connect to it. This requires
-several changes to the startup files on the host machine. If you are
-experimenting as an ordinary user rather than as root, you will need the
-assistance of your system administrator to modify the system files.
-
-You will probably want to set up the name server
-.B nmbd
-at the same time as
-the smbd - refer to the man page
-.B nmbd(8).
-
-First, ensure that a port is configured in the file /etc/services. The
-well-known port 139 should be used if possible, though any port may be used.
-
-Ensure that a line similar to the following is in /etc/services:
-
-.RS 3
-netbios-ssn 139/tcp
-.RE
-
-Note for NIS/YP users - you may need to rebuild the NIS service maps rather
-than alter your local /etc/services file.
-
-Next, put a suitable line in the file /etc/inetd.conf (in the unlikely event
-that you are using a meta-daemon other than inetd, you are on your own). Note
-that the first item in this line matches the service name in /etc/services.
-Substitute appropriate values for your system in this line (see
-.B inetd(8)):
-
-.RS 3
-netbios-ssn stream tcp nowait root /usr/local/smb/smbd -d1
--l/var/adm/smblogs/log -s/usr/local/smb/smb.conf
-.RE
-
-(The above should appear in /etc/inetd.conf as a single line. Depending on
-your terminal characteristics, it may not appear that way in this man page.
-If the above appears as more than one line, please treat any newlines or
-indentation as a single space or TAB character.)
-
-Note that there is no need to specify a port number here, even if you are
-using a non-standard port number.
-
-Lastly, edit the configuration file to provide suitable services. To start
-with, the following two services should be all you need:
-
-.RS 3
-[homes]
-.RS 3
- writable = yes
-.RE
-
-[printers]
-.RS 3
- writable = no
- printable = yes
- path = /tmp
- public = yes
-.RE
-.RE
-
-This will allow you to connect to your home directory and print to any printer
-supported by the host (user privileges permitting).
-.SH TESTING THE INSTALLATION
-If running the server as a daemon, execute it before proceeding. If
-using a meta-daemon, either restart the system or kill and restart the
-meta-daemon. Some versions of inetd will reread their configuration tables if
-they receive a HUP signal.
-
-If your machine's name is "fred" and your name is "mary", you should now be
-able to connect to the service "\\\\fred\\mary".
-
-To properly test and experiment with the server, we recommend using the
-smbclient program (see
-.B smbclient(1)).
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the server has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B hosts_access(5),
-.B inetd(8),
-.B nmbd(8),
-.B smb.conf(5),
-.B smbclient(1),
-.B testparm(1),
-.B testprns(1)
-
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the server are logged in a specified log file. The
-log file name is specified at compile time, but may be overridden on the
-command line.
-
-The number and nature of diagnostics available depends on the debug level used
-by the server. If you have problems, set the debug level to 3 and peruse the
-log files.
-
-Most messages are reasonably self-explanatory. Unfortunately, at time of
-creation of this man page the source code is still too fluid to warrant
-describing each and every diagnostic. At this stage your best bet is still
-to grep the source code and inspect the conditions that gave rise to the
+.TP 0.2i
+\(bu
+\fBsmbd\fR (the server program)
+installed in \fI/usr/local/samba/bin\fR
+.TP 0.2i
+\(bu
+\fIsmb.conf\fR (the configuration
+file) installed in \fI/usr/local/samba/lib\fR
+.TP 0.2i
+\(bu
+log files stored in \fI/var/adm/smblogs
+\fR.PP
+The server may be run either as a daemon by users
+or at startup, or it may be run from a meta-daemon such as
+\fBinetd\fR upon request. If run as a daemon,
+the server will always be ready, so starting sessions will be
+faster. If run from a meta-daemon some memory will be saved and
+utilities such as the tcpd TCP-wrapper may be used for extra
+security. For serious use as file server it is recommended
+that \fBsmbd\fR be run as a daemon.
+.PP
+.PP
+When you've decided, continue with either
+.PP
+.TP 0.2i
+\(bu
+RUNNING THE SERVER AS A DAEMON or
+.TP 0.2i
+\(bu
+RUNNING THE SERVER ON REQUEST.
+.SH "RUNNING THE SERVER AS A DAEMON"
+.PP
+To run the server as a daemon from the command
+line, simply put the \fB-D\fR option on the
+command line. There is no need to place an ampersand at
+the end of the command line - the \fB-D\fR
+option causes the server to detach itself from the tty
+anyway.
+.PP
+Any user can run the server as a daemon (execute
+permissions permitting, of course). This is useful for
+testing purposes, and may even be useful as a temporary
+substitute for something like ftp. When run this way, however,
+the server will only have the privileges of the user who ran
+it.
+.PP
+To ensure that the server is run as a daemon whenever
+the machine is started, and to ensure that it runs as root
+so that it can serve multiple clients, you will need to modify
+the system startup files. Wherever appropriate (for example, in
+\fI/etc/rc\fR), insert the following line,
+substituting port number, log file location, configuration file
+location and debug level as desired:
+.PP
+\fB/usr/local/samba/bin/smbd -D -l /var/adm/smblogs/log
+-s /usr/local/samba/lib/smb.conf\fR
+.PP
+(The above should appear in your initialization script
+as a single line. Depending on your terminal characteristics,
+it may not appear that way in this man page. If the above appears
+as more than one line, please treat any newlines or indentation
+as a single space or TAB character.)
+.PP
+If the options used at compile time are appropriate for
+your system, all parameters except \fB-D\fR may
+be omitted. See the section OPTIONS above.
+.SH "RUNNING THE SERVER ON REQUEST"
+.PP
+If your system uses a meta-daemon such as \fBinetd
+\fR, you can arrange to have the \fBsmbd\fR server started
+whenever a process attempts to connect to it. This requires several
+changes to the startup files on the host machine. If you are
+experimenting as an ordinary user rather than as root, you will
+need the assistance of your system administrator to modify the
+system files.
+.PP
+You will probably want to set up the NetBIOS name server
+\fBnmbd\fRat
+the same time as \fBsmbd\fR. To do this refer to the
+man page for \fBnmbd(8)\fR
+.
+.PP
+First, ensure that a port is configured in the file
+\fI/etc/services\fR. The well-known port 139
+should be used if possible, though any port may be used.
+.PP
+Ensure that a line similar to the following is in
+\fI/etc/services\fR:
+.PP
+\fBnetbios-ssn 139/tcp\fR
+.PP
+Note for NIS/YP users - you may need to rebuild the
+NIS service maps rather than alter your local \fI/etc/services
+\fRfile.
+.PP
+Next, put a suitable line in the file \fI/etc/inetd.conf
+\fR(in the unlikely event that you are using a meta-daemon
+other than inetd, you are on your own). Note that the first item
+in this line matches the service name in \fI/etc/services
+\fR\&. Substitute appropriate values for your system
+in this line (see \fBinetd(8)\fR):
+.PP
+\fBnetbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd
+-d1 -l/var/adm/smblogs/log -s/usr/local/samba/lib/smb.conf\fR
+.PP
+(The above should appear in \fI/etc/inetd.conf\fR
+as a single line. Depending on your terminal characteristics, it may
+not appear that way in this man page. If the above appears as more
+than one line, please treat any newlines or indentation as a single
+space or TAB character.)
+.PP
+Note that there is no need to specify a port number here,
+even if you are using a non-standard port number.
+.PP
+Lastly, edit the configuration file to provide suitable
+services. To start with, the following two services should be
+all you need:
+.sp
+.nf
+ [homes]
+ writeable = yes
+
+ [printers]
+ writeable = no
+ printable = yes
+ path = /tmp
+ public = yes
+
+
+.sp
+.fi
+.PP
+This will allow you to connect to your home directory
+and print to any printer supported by the host (user privileges
+permitting).
+.SH "PAM INTERACTION"
+.PP
+Samba uses PAM for authentication (when presented with a plaintext
+password), for account checking (is this account disabled?) and for
+session management. The degree too which samba supports PAM is restricted
+by the limitations of the SMB protocol and the
+obey pam restricions
+smb.conf paramater. When this is set, the following restrictions apply:
+.TP 0.2i
+\(bu
+\fBAccount Validation\fR: All acccesses to a
+samba server are checked
+against PAM to see if the account is vaild, not disabled and is permitted to
+login at this time. This also applies to encrypted logins.
+.TP 0.2i
+\(bu
+\fBSession Management\fR: When not using share
+level secuirty, users must pass PAM's session checks before access
+is granted. Note however, that this is bypassed in share level secuirty.
+Note also that some older pam configuration files may need a line
+added for session support.
+.SH "TESTING THE INSTALLATION"
+.PP
+If running the server as a daemon, execute it before
+proceeding. If using a meta-daemon, either restart the system
+or kill and restart the meta-daemon. Some versions of
+\fBinetd\fR will reread their configuration
+tables if they receive a HUP signal.
+.PP
+If your machine's name is \fIfred\fR and your
+name is \fImary\fR, you should now be able to connect
+to the service \fI\\\\fred\\mary\fR.
+.PP
+To properly test and experiment with the server, we
+recommend using the \fBsmbclient\fR program (see
+\fBsmbclient(1)\fR)
+and also going through the steps outlined in the file
+\fIDIAGNOSIS.txt\fR in the \fIdocs/\fR
+directory of your Samba installation.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "DIAGNOSTICS"
+.PP
+Most diagnostics issued by the server are logged
+in a specified log file. The log file name is specified
+at compile time, but may be overridden on the command line.
+.PP
+The number and nature of diagnostics available depends
+on the debug level used by the server. If you have problems, set
+the debug level to 3 and peruse the log files.
+.PP
+Most messages are reasonably self-explanatory. Unfortunately,
+at the time this man page was created, there are too many diagnostics
+available in the source code to warrant describing each and every
+diagnostic. At this stage your best bet is still to grep the
+source code and inspect the conditions that gave rise to the
diagnostics you are seeing.
-
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B smb.conf(5) for a full list of contributors and details on how to
-submit bug reports, comments etc.
+.SH "SIGNALS"
+.PP
+Sending the \fBsmbd\fR a SIGHUP will cause it to
+reload its \fIsmb.conf\fR configuration
+file within a short period of time.
+.PP
+To shut down a user's \fBsmbd\fR process it is recommended
+that \fBSIGKILL (-9)\fR \fBNOT\fR
+be used, except as a last resort, as this may leave the shared
+memory area in an inconsistent state. The safe way to terminate
+an \fBsmbd\fR is to send it a SIGTERM (-15) signal and wait for
+it to die on its own.
+.PP
+The debug log level of \fBsmbd\fR may be raised
+or lowered using \fBsmbcontrol(1)
+\fRprogram (SIGUSR[1|2] signals are no longer used in
+Samba 2.2). This is to allow transient problems to be diagnosed,
+whilst still running at a normally low log level.
+.PP
+Note that as the signal handlers send a debug write,
+they are not re-entrant in \fBsmbd\fR. This you should wait until
+\fBsmbd\fR is in a state of waiting for an incoming SMB before
+issuing them. It is possible to make the signal handlers safe
+by un-blocking the signals before the select call and re-blocking
+them after, however this would affect performance.
+.SH "SEE ALSO"
+.PP
+hosts_access(5), \fBinetd(8)\fR,
+\fBnmbd(8)\fR,
+\fIsmb.conf(5)\fR
+, \fBsmbclient(1)
+\fR, and the Internet RFC's
+\fIrfc1001.txt\fR, \fIrfc1002.txt\fR.
+In addition the CIFS (formerly SMB) specification is available
+as a link from the Web page
+http://samba.org/cifs/ <URL:http://samba.org/cifs/>.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbmnt.8 b/docs/manpages/smbmnt.8
new file mode 100644
index 00000000000..bab134ef54e
--- /dev/null
+++ b/docs/manpages/smbmnt.8
@@ -0,0 +1,63 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBMNT" "8" "06 December 2001" "" ""
+.SH NAME
+smbmnt \- helper utility for mounting SMB filesystems
+.SH SYNOPSIS
+.sp
+\fBsmbmnt\fR \fBmount-point\fR [ \fB-s <share>\fR ] [ \fB-r\fR ] [ \fB-u <uid>\fR ] [ \fB-g <gid>\fR ] [ \fB-f <mask>\fR ] [ \fB-d <mask>\fR ] [ \fB-o <options>\fR ]
+.SH "DESCRIPTION"
+.PP
+\fBsmbmnt\fR is a helper application used
+by the smbmount program to do the actual mounting of SMB shares.
+\fBsmbmnt\fR can be installed setuid root if you want
+normal users to be able to mount their SMB shares.
+.PP
+A setuid smbmnt will only allow mounts on directories owned
+by the user, and that the user has write permission on.
+.PP
+The \fBsmbmnt\fR program is normally invoked
+by \fBsmbmount(8)\fR
+. It should not be invoked directly by users.
+.PP
+smbmount searches the normal PATH for smbmnt. You must ensure
+that the smbmnt version in your path matches the smbmount used.
+.SH "OPTIONS"
+.TP
+\fB-r\fR
+mount the filesystem read-only
+.TP
+\fB-u uid\fR
+specify the uid that the files will
+be owned by
+.TP
+\fB-g gid\fR
+specify the gid that the files will be
+owned by
+.TP
+\fB-f mask\fR
+specify the octal file mask applied
+.TP
+\fB-d mask\fR
+specify the octal directory mask
+applied
+.TP
+\fB-o options\fR
+list of options that are passed as-is to smbfs, if this
+command is run on a 2.4 or higher Linux kernel.
+.SH "AUTHOR"
+.PP
+Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+and others.
+.PP
+The current maintainer of smbfs and the userspace
+tools \fBsmbmount\fR, \fBsmbumount\fR,
+and \fBsmbmnt\fR is Urban Widmark <URL:mailto:urban@teststation.com>.
+The SAMBA Mailing list <URL:mailto:samba@samba.org>
+is the preferred place to ask questions regarding these programs.
+.PP
+The conversion of this manpage for Samba 2.2 was performed
+by Gerald Carter
diff --git a/docs/manpages/smbmount.8 b/docs/manpages/smbmount.8
new file mode 100644
index 00000000000..70a0911887a
--- /dev/null
+++ b/docs/manpages/smbmount.8
@@ -0,0 +1,216 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBMOUNT" "8" "06 December 2001" "" ""
+.SH NAME
+smbmount \- mount an smbfs filesystem
+.SH SYNOPSIS
+.sp
+\fBsmbumount\fR \fBservice\fR \fBmount-point\fR [ \fB-o options\fR ]
+.SH "DESCRIPTION"
+.PP
+\fBsmbmount\fR mounts a Linux SMB filesystem. It
+is usually invoked as \fBmount.smbfs\fR by
+the \fBmount(8)\fR command when using the
+"-t smbfs" option. This command only works in Linux, and the kernel must
+support the smbfs filesystem.
+.PP
+Options to \fBsmbmount\fR are specified as a comma-separated
+list of key=value pairs. It is possible to send options other
+than those listed here, assuming that smbfs supports them. If
+you get mount failures, check your kernel log for errors on
+unknown options.
+.PP
+\fBsmbmount\fR is a daemon. After mounting it keeps running until
+the mounted smbfs is umounted. It will log things that happen
+when in daemon mode using the "machine name" smbmount, so
+typically this output will end up in \fIlog.smbmount\fR. The
+\fBsmbmount\fR process may also be called mount.smbfs.
+.PP
+\fBNOTE:\fR \fBsmbmount\fR
+calls \fBsmbmnt(8)\fR to do the actual mount. You
+must make sure that \fBsmbmnt\fR is in the path so
+that it can be found.
+.SH "OPTIONS"
+.TP
+\fBusername=<arg>\fR
+specifies the username to connect as. If
+this is not given, then the environment variable \fB USER\fR is used. This option can also take the
+form "user%password" or "user/workgroup" or
+"user/workgroup%password" to allow the password and workgroup
+to be specified as part of the username.
+.TP
+\fBpassword=<arg>\fR
+specifies the SMB password. If this
+option is not given then the environment variable
+\fBPASSWD\fR is used. If it can find
+no password \fBsmbmount\fR will prompt
+for a passeword, unless the guest option is
+given.
+
+Note that password which contain the arguement delimiter
+character (i.e. a comma ',') will failed to be parsed correctly
+on the command line. However, the same password defined
+in the PASSWD environment variable or a credentials file (see
+below) will be read correctly.
+.TP
+\fBcredentials=<filename>\fR
+specifies a file that contains a username
+and/or password. The format of the file is:
+
+.sp
+.nf
+ username = <value>
+ password = <value>
+
+.sp
+.fi
+
+This is preferred over having passwords in plaintext in a
+shared file, such as \fI/etc/fstab\fR. Be sure to protect any
+credentials file properly.
+.TP
+\fBnetbiosname=<arg>\fR
+sets the source NetBIOS name. It defaults
+to the local hostname.
+.TP
+\fBuid=<arg>\fR
+sets the uid that will own all files on
+the mounted filesystem.
+It may be specified as either a username or a numeric uid.
+.TP
+\fBgid=<arg>\fR
+sets the gid that will own all files on
+the mounted filesystem.
+It may be specified as either a groupname or a numeric
+gid.
+.TP
+\fBport=<arg>\fR
+sets the remote SMB port number. The default
+is 139.
+.TP
+\fBfmask=<arg>\fR
+sets the file mask. This determines the
+permissions that remote files have in the local filesystem.
+The default is based on the current umask.
+.TP
+\fBdmask=<arg>\fR
+sets the directory mask. This determines the
+permissions that remote directories have in the local filesystem.
+The default is based on the current umask.
+.TP
+\fBdebug=<arg>\fR
+sets the debug level. This is useful for
+tracking down SMB connection problems. A suggested value to
+start with is 4. If set too high there will be a lot of
+output, possibly hiding the useful output.
+.TP
+\fBip=<arg>\fR
+sets the destination host or IP address.
+.TP
+\fBworkgroup=<arg>\fR
+sets the workgroup on the destination
+.TP
+\fBsockopt=<arg>\fR
+sets the TCP socket options. See the \fIsmb.conf
+\fR\fIsocket options\fR option.
+.TP
+\fBscope=<arg>\fR
+sets the NetBIOS scope
+.TP
+\fBguest\fR
+don't prompt for a password
+.TP
+\fBro\fR
+mount read-only
+.TP
+\fBrw\fR
+mount read-write
+.TP
+\fBiocharset=<arg>\fR
+sets the charset used by the Linux side for codepage
+to charset translations (NLS). Argument should be the
+name of a charset, like iso8859-1. (Note: only kernel
+2.4.0 or later)
+.TP
+\fBcodepage=<arg>\fR
+sets the codepage the server uses. See the iocharset
+option. Example value cp850. (Note: only kernel 2.4.0
+or later)
+.TP
+\fBttl=<arg>\fR
+how long a directory listing is cached in milliseconds
+(also affects visibility of file size and date
+changes). A higher value means that changes on the
+server take longer to be noticed but it can give
+better performance on large directories, especially
+over long distances. Default is 1000ms but something
+like 10000ms (10 seconds) is probably more reasonable
+in many cases.
+(Note: only kernel 2.4.2 or later)
+.SH "ENVIRONMENT VARIABLES"
+.PP
+The variable \fBUSER\fR may contain the username of the
+person using the client. This information is used only if the
+protocol level is high enough to support session-level
+passwords. The variable can be used to set both username and
+password by using the format username%password.
+.PP
+The variable \fBPASSWD\fR may contain the password of the
+person using the client. This information is used only if the
+protocol level is high enough to support session-level
+passwords.
+.PP
+The variable \fBPASSWD_FILE\fR may contain the pathname
+of a file to read the password from. A single line of input is
+read and used as the password.
+.SH "BUGS"
+.PP
+Passwords and other options containing , can not be handled.
+For passwords an alternative way of passing them is in a credentials
+file or in the PASSWD environment.
+.PP
+The credentials file does not handle usernames or passwords with
+leading space.
+.PP
+One smbfs bug is important enough to mention here, even if it
+is a bit misplaced:
+.TP 0.2i
+\(bu
+Mounts sometimes stop working. This is usually
+caused by smbmount terminating. Since smbfs needs smbmount to
+reconnect when the server disconnects, the mount will eventually go
+dead. An umount/mount normally fixes this. At least 2 ways to
+trigger this bug are known.
+.PP
+Note that the typical response to a bug report is suggestion
+to try the latest version first. So please try doing that first,
+and always include which versions you use of relevant software
+when reporting bugs (minimum: samba, kernel, distribution)
+.PP
+.SH "SEE ALSO"
+.PP
+Documentation/filesystems/smbfs.txt in the linux kernel
+source tree may contain additional options and information.
+.PP
+FreeBSD also has a smbfs, but it is not related to smbmount
+.PP
+For Solaris, HP-UX and others you may want to look at
+\fBsmbsh(1)\fRor at other
+solutions, such as sharity or perhaps replacing the SMB server with
+a NFS server.
+.SH "AUTHOR"
+.PP
+Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+and others.
+.PP
+The current maintainer of smbfs and the userspace
+tools \fBsmbmount\fR, \fBsmbumount\fR,
+and \fBsmbmnt\fR is Urban Widmark <URL:mailto:urban@teststation.com>.
+The SAMBA Mailing list <URL:mailto:samba@samba.org>
+is the preferred place to ask questions regarding these programs.
+.PP
+The conversion of this manpage for Samba 2.2 was performed
+by Gerald Carter
diff --git a/docs/manpages/smbpasswd.5 b/docs/manpages/smbpasswd.5
new file mode 100644
index 00000000000..b1adf080e7e
--- /dev/null
+++ b/docs/manpages/smbpasswd.5
@@ -0,0 +1,159 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBPASSWD" "5" "06 December 2001" "" ""
+.SH NAME
+smbpasswd \- The Samba encrypted password file
+.SH SYNOPSIS
+.PP
+\fIsmbpasswd\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+smbpasswd is the Samba encrypted password file. It contains
+the username, Unix user id and the SMB hashed passwords of the
+user, as well as account flag information and the time the
+password was last changed. This file format has been evolving with
+Samba and has had several different formats in the past.
+.SH "FILE FORMAT"
+.PP
+The format of the smbpasswd file used by Samba 2.2
+is very similar to the familiar Unix \fIpasswd(5)\fR
+file. It is an ASCII file containing one line for each user. Each field
+ithin each line is separated from the next by a colon. Any entry
+beginning with '#' is ignored. The smbpasswd file contains the
+following information for each user:
+.TP
+\fBname\fR
+This is the user name. It must be a name that
+already exists in the standard UNIX passwd file.
+.TP
+\fBuid\fR
+This is the UNIX uid. It must match the uid
+field for the same user entry in the standard UNIX passwd file.
+If this does not match then Samba will refuse to recognize
+this smbpasswd file entry as being valid for a user.
+.TP
+\fBLanman Password Hash\fR
+This is the LANMAN hash of the user's password,
+encoded as 32 hex digits. The LANMAN hash is created by DES
+encrypting a well known string with the user's password as the
+DES key. This is the same password used by Windows 95/98 machines.
+Note that this password hash is regarded as weak as it is
+vulnerable to dictionary attacks and if two users choose the
+same password this entry will be identical (i.e. the password
+is not "salted" as the UNIX password is). If the user has a
+null password this field will contain the characters "NO PASSWORD"
+as the start of the hex string. If the hex string is equal to
+32 'X' characters then the user's account is marked as
+disabled and the user will not be able to
+log onto the Samba server.
+
+\fBWARNING !!\fR Note that, due to
+the challenge-response nature of the SMB/CIFS authentication
+protocol, anyone with a knowledge of this password hash will
+be able to impersonate the user on the network. For this
+reason these hashes are known as \fBplain text
+equivalents\fR and must \fBNOT\fR be made
+available to anyone but the root user. To protect these passwords
+the smbpasswd file is placed in a directory with read and
+traverse access only to the root user and the smbpasswd file
+itself must be set to be read/write only by root, with no
+other access.
+.TP
+\fBNT Password Hash\fR
+This is the Windows NT hash of the user's
+password, encoded as 32 hex digits. The Windows NT hash is
+created by taking the user's password as represented in
+16-bit, little-endian UNICODE and then applying the MD4
+(internet rfc1321) hashing algorithm to it.
+
+This password hash is considered more secure than
+the LANMAN Password Hash as it preserves the case of the
+password and uses a much higher quality hashing algorithm.
+However, it is still the case that if two users choose the same
+password this entry will be identical (i.e. the password is
+not "salted" as the UNIX password is).
+
+\fBWARNING !!\fR. Note that, due to
+the challenge-response nature of the SMB/CIFS authentication
+protocol, anyone with a knowledge of this password hash will
+be able to impersonate the user on the network. For this
+reason these hashes are known as \fBplain text
+equivalents\fR and must \fBNOT\fR be made
+available to anyone but the root user. To protect these passwords
+the smbpasswd file is placed in a directory with read and
+traverse access only to the root user and the smbpasswd file
+itself must be set to be read/write only by root, with no
+other access.
+.TP
+\fBAccount Flags\fR
+This section contains flags that describe
+the attributes of the users account. In the Samba 2.2 release
+this field is bracketed by '[' and ']' characters and is always
+13 characters in length (including the '[' and ']' characters).
+The contents of this field may be any of the characters.
+.RS
+.TP 0.2i
+\(bu
+\fBU\fR - This means
+this is a "User" account, i.e. an ordinary user. Only User
+and Workstation Trust accounts are currently supported
+in the smbpasswd file.
+.TP 0.2i
+\(bu
+\fBN\fR - This means the
+account has no password (the passwords in the fields LANMAN
+Password Hash and NT Password Hash are ignored). Note that this
+will only allow users to log on with no password if the \fI null passwords\fR parameter is set in the \fIsmb.conf(5)
+\fRconfig file.
+.TP 0.2i
+\(bu
+\fBD\fR - This means the account
+is disabled and no SMB/CIFS logins will be allowed for
+this user.
+.TP 0.2i
+\(bu
+\fBW\fR - This means this account
+is a "Workstation Trust" account. This kind of account is used
+in the Samba PDC code stream to allow Windows NT Workstations
+and Servers to join a Domain hosted by a Samba PDC.
+.RE
+.PP
+Other flags may be added as the code is extended in future.
+The rest of this field space is filled in with spaces.
+.PP
+.TP
+\fBLast Change Time\fR
+This field consists of the time the account was
+last modified. It consists of the characters 'LCT-' (standing for
+"Last Change Time") followed by a numeric encoding of the UNIX time
+in seconds since the epoch (1970) that the last change was made.
+.PP
+All other colon separated fields are ignored at this time.
+.PP
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbpasswd(8)\fR,
+samba(7), and
+the Internet RFC1321 for details on the MD4 algorithm.
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbpasswd.8 b/docs/manpages/smbpasswd.8
new file mode 100644
index 00000000000..8e5be46e318
--- /dev/null
+++ b/docs/manpages/smbpasswd.8
@@ -0,0 +1,313 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBPASSWD" "8" "06 December 2001" "" ""
+.SH NAME
+smbpasswd \- change a user's SMB password
+.SH SYNOPSIS
+.sp
+\fBsmbpasswd\fR [ \fB-a\fR ] [ \fB-x\fR ] [ \fB-d\fR ] [ \fB-e\fR ] [ \fB-D debuglevel\fR ] [ \fB-n\fR ] [ \fB-r <remote machine>\fR ] [ \fB-R <name resolve order>\fR ] [ \fB-m\fR ] [ \fB-j DOMAIN\fR ] [ \fB-U username[%password]\fR ] [ \fB-h\fR ] [ \fB-s\fR ] [ \fB-w pass\fR ] [ \fBusername\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+The smbpasswd program has several different
+functions, depending on whether it is run by the \fBroot\fR
+user or not. When run as a normal user it allows the user to change
+the password used for their SMB sessions on any machines that store
+SMB passwords.
+.PP
+By default (when run with no arguments) it will attempt to
+change the current user's SMB password on the local machine. This is
+similar to the way the \fBpasswd(1)\fR program works.
+\fBsmbpasswd\fR differs from how the passwd program works
+however in that it is not \fBsetuid root\fR but works in
+a client-server mode and communicates with a locally running
+\fBsmbd(8)\fR. As a consequence in order for this to
+succeed the smbd daemon must be running on the local machine. On a
+UNIX machine the encrypted SMB passwords are usually stored in
+the \fIsmbpasswd(5)\fR file.
+.PP
+When run by an ordinary user with no options. smbpasswd
+will prompt them for their old SMB password and then ask them
+for their new password twice, to ensure that the new password
+was typed correctly. No passwords will be echoed on the screen
+whilst being typed. If you have a blank SMB password (specified by
+the string "NO PASSWORD" in the smbpasswd file) then just press
+the <Enter> key when asked for your old password.
+.PP
+smbpasswd can also be used by a normal user to change their
+SMB password on remote machines, such as Windows NT Primary Domain
+Controllers. See the (-r) and -U options below.
+.PP
+When run by root, smbpasswd allows new users to be added
+and deleted in the smbpasswd file, as well as allows changes to
+the attributes of the user in this file to be made. When run by root,
+\fBsmbpasswd\fR accesses the local smbpasswd file
+directly, thus enabling changes to be made even if smbd is not
+running.
+.SH "OPTIONS"
+.TP
+\fB-a\fR
+This option specifies that the username
+following should be added to the local smbpasswd file, with the
+new password typed (type <Enter> for the old password). This
+option is ignored if the username following already exists in
+the smbpasswd file and it is treated like a regular change
+password command. Note that the user to be added must already exist
+in the system password file (usually \fI/etc/passwd\fR)
+else the request to add the user will fail.
+
+This option is only available when running smbpasswd
+as root.
+.TP
+\fB-x\fR
+This option specifies that the username
+following should be deleted from the local smbpasswd file.
+
+This option is only available when running smbpasswd as
+root.
+.TP
+\fB-d\fR
+This option specifies that the username following
+should be disabled in the local smbpasswd
+file. This is done by writing a 'D' flag
+into the account control space in the smbpasswd file. Once this
+is done all attempts to authenticate via SMB using this username
+will fail.
+
+If the smbpasswd file is in the 'old' format (pre-Samba 2.0
+format) there is no space in the user's password entry to write
+this information and so the user is disabled by writing 'X' characters
+into the password space in the smbpasswd file. See \fBsmbpasswd(5)
+\fRfor details on the 'old' and new password file formats.
+
+This option is only available when running smbpasswd as
+root.
+.TP
+\fB-e\fR
+This option specifies that the username following
+should be enabled in the local smbpasswd file,
+if the account was previously disabled. If the account was not
+disabled this option has no effect. Once the account is enabled then
+the user will be able to authenticate via SMB once again.
+
+If the smbpasswd file is in the 'old' format, then \fB smbpasswd\fR will prompt for a new password for this user,
+otherwise the account will be enabled by removing the 'D'
+flag from account control space in the \fI smbpasswd\fR file. See \fBsmbpasswd (5)\fR for
+details on the 'old' and new password file formats.
+
+This option is only available when running smbpasswd as root.
+.TP
+\fB-D debuglevel\fR
+\fIdebuglevel\fR is an integer
+from 0 to 10. The default value if this parameter is not specified
+is zero.
+
+The higher this value, the more detail will be logged to the
+log files about the activities of smbpasswd. At level 0, only
+critical errors and serious warnings will be logged.
+
+Levels above 1 will generate considerable amounts of log
+data, and should only be used when investigating a problem. Levels
+above 3 are designed for use only by developers and generate
+HUGE amounts of log data, most of which is extremely cryptic.
+.TP
+\fB-n\fR
+This option specifies that the username following
+should have their password set to null (i.e. a blank password) in
+the local smbpasswd file. This is done by writing the string "NO
+PASSWORD" as the first part of the first password stored in the
+smbpasswd file.
+
+Note that to allow users to logon to a Samba server once
+the password has been set to "NO PASSWORD" in the smbpasswd
+file the administrator must set the following parameter in the [global]
+section of the \fIsmb.conf\fR file :
+
+\fBnull passwords = yes\fR
+
+This option is only available when running smbpasswd as
+root.
+.TP
+\fB-r remote machine name\fR
+This option allows a user to specify what machine
+they wish to change their password on. Without this parameter
+smbpasswd defaults to the local host. The \fIremote
+machine name\fR is the NetBIOS name of the SMB/CIFS
+server to contact to attempt the password change. This name is
+resolved into an IP address using the standard name resolution
+mechanism in all programs of the Samba suite. See the \fI-R
+name resolve order\fR parameter for details on changing
+this resolving mechanism.
+
+The username whose password is changed is that of the
+current UNIX logged on user. See the \fI-U username\fR
+parameter for details on changing the password for a different
+username.
+
+Note that if changing a Windows NT Domain password the
+remote machine specified must be the Primary Domain Controller for
+the domain (Backup Domain Controllers only have a read-only
+copy of the user account database and will not allow the password
+change).
+
+\fBNote\fR that Windows 95/98 do not have
+a real password database so it is not possible to change passwords
+specifying a Win95/98 machine as remote machine target.
+.TP
+\fB-R name resolve order\fR
+This option allows the user of smbpasswd to determine
+what name resolution services to use when looking up the NetBIOS
+name of the host being connected to.
+
+The options are :"lmhosts", "host", "wins" and "bcast". They cause
+names to be resolved as follows :
+.RS
+.TP 0.2i
+\(bu
+lmhosts : Lookup an IP
+address in the Samba lmhosts file. If the line in lmhosts has
+no name type attached to the NetBIOS name (see the lmhosts(5)for details) then
+any name type matches for lookup.
+.TP 0.2i
+\(bu
+host : Do a standard host
+name to IP address resolution, using the system \fI/etc/hosts
+\fR, NIS, or DNS lookups. This method of name resolution
+is operating system depended for instance on IRIX or Solaris this
+may be controlled by the \fI/etc/nsswitch.conf\fR
+file). Note that this method is only used if the NetBIOS name
+type being queried is the 0x20 (server) name type, otherwise
+it is ignored.
+.TP 0.2i
+\(bu
+wins : Query a name with
+the IP address listed in the \fIwins server\fR
+parameter. If no WINS server has been specified this method
+will be ignored.
+.TP 0.2i
+\(bu
+bcast : Do a broadcast on
+each of the known local interfaces listed in the
+\fIinterfaces\fR parameter. This is the least
+reliable of the name resolution methods as it depends on the
+target host being on a locally connected subnet.
+.RE
+.PP
+The default order is \fBlmhosts, host, wins, bcast\fR
+and without this parameter or any entry in the
+\fIsmb.conf\fR file the name resolution methods will
+be attempted in this order.
+.PP
+.TP
+\fB-m\fR
+This option tells smbpasswd that the account
+being changed is a MACHINE account. Currently this is used
+when Samba is being used as an NT Primary Domain Controller.
+
+This option is only available when running smbpasswd as root.
+.TP
+\fB-j DOMAIN\fR
+This option is used to add a Samba server
+into a Windows NT Domain, as a Domain member capable of authenticating
+user accounts to any Domain Controller in the same way as a Windows
+NT Server. See the \fBsecurity = domain\fR option in
+the \fIsmb.conf(5)\fR man page.
+
+In order to be used in this way, the Administrator for
+the Windows NT Domain must have used the program "Server Manager
+for Domains" to add the primary NetBIOS name of the Samba server
+as a member of the Domain.
+
+After this has been done, to join the Domain invoke \fB smbpasswd\fR with this parameter. smbpasswd will then
+look up the Primary Domain Controller for the Domain (found in
+the \fIsmb.conf\fR file in the parameter
+\fIpassword server\fR and change the machine account
+password used to create the secure Domain communication. This
+password is then stored by smbpasswd in a TDB, writeable only by root,
+called \fIsecrets.tdb\fR
+
+Once this operation has been performed the \fI smb.conf\fR file may be updated to set the \fB security = domain\fR option and all future logins
+to the Samba server will be authenticated to the Windows NT
+PDC.
+
+Note that even though the authentication is being
+done to the PDC all users accessing the Samba server must still
+have a valid UNIX account on that machine.
+
+This option is only available when running smbpasswd as root.
+.TP
+\fB-U username\fR
+This option may only be used in conjunction
+with the \fI-r\fR option. When changing
+a password on a remote machine it allows the user to specify
+the user name on that machine whose password will be changed. It
+is present to allow users who have different user names on
+different systems to change these passwords.
+.TP
+\fB-h\fR
+This option prints the help string for \fB smbpasswd\fR, selecting the correct one for running as root
+or as an ordinary user.
+.TP
+\fB-s\fR
+This option causes smbpasswd to be silent (i.e.
+not issue prompts) and to read its old and new passwords from
+standard input, rather than from \fI/dev/tty\fR
+(like the \fBpasswd(1)\fR program does). This option
+is to aid people writing scripts to drive smbpasswd
+.TP
+\fB-w password\fR
+This parameter is only available is Samba
+has been configured to use the experiemental
+\fB--with-ldapsam\fR option. The \fI-w\fR
+switch is used to specify the password to be used with the
+\fIldap admin
+dn\fR. Note that the password is stored in
+the \fIprivate/secrets.tdb\fR and is keyed off
+of the admin's DN. This means that if the value of \fIldap
+admin dn\fR ever changes, the password will beed to be
+manually updated as well.
+.TP
+\fBusername\fR
+This specifies the username for all of the
+\fBroot only\fR options to operate on. Only root
+can specify this parameter as only root has the permission needed
+to modify attributes directly in the local smbpasswd file.
+.SH "NOTES"
+.PP
+Since \fBsmbpasswd\fR works in client-server
+mode communicating with a local smbd for a non-root user then
+the smbd daemon must be running for this to work. A common problem
+is to add a restriction to the hosts that may access the \fB smbd\fR running on the local machine by specifying a
+\fIallow hosts\fR or \fIdeny hosts\fR
+entry in the \fIsmb.conf\fR file and neglecting to
+allow "localhost" access to the smbd.
+.PP
+In addition, the smbpasswd command is only useful if Samba
+has been set up to use encrypted passwords. See the file
+\fIENCRYPTION.txt\fR in the docs directory for details
+on how to do this.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fIsmbpasswd(5)\fR,
+samba(7)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbrun.1 b/docs/manpages/smbrun.1
deleted file mode 100644
index 1608d3bb345..00000000000
--- a/docs/manpages/smbrun.1
+++ /dev/null
@@ -1,70 +0,0 @@
-.TH SMBRUN 1 17/1/1995 smbrun smbrun
-.SH NAME
-smbrun \- interface program between smbd and external programs
-.SH SYNOPSIS
-.B smbrun
-.I shell-command
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B smbrun
-is a very small 'glue' program, which runs shell commands for
-the
-.B smbd
-daemon (see
-.B smbd(8)).
-
-It first changes to the highest effective user and group ID that it can,
-then runs the command line provided using the system() call. This program is
-necessary to allow some operating systems to run external programs as non-root.
-.SH OPTIONS
-.I shell-command
-
-.RS 3
-The shell command to execute.
-
-The command should have a fully-qualified path.
-.RE
-.SH ENVIRONMENT VARIABLES
-The PATH variable set for the environment in which
-.B smbrun
-is executed will affect what executables are located and executed if a
-fully-qualified path is not given in the command.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the
-.B smbrun
-program be installed under the /usr/local hierarchy, in a directory readable
-by all, writeable only by root. The program should be executable by all.
-The program should NOT be setuid or setgid!
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the program has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B smbd(8),
-.B smb.conf(8)
-.SH DIAGNOSTICS
-If smbrun cannot be located or cannot be executed by
-.B smbd
-then appropriate messages will be found in the smbd logs. Other diagnostics are
-dependent on the shell-command being run. It is advisable for your shell
-commands to issue suitable diagnostics to aid trouble-shooting.
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-This man page was written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B smb.conf(5) for a full list of contributors and details of how to
-submit bug reports, comments etc.
diff --git a/docs/manpages/smbsh.1 b/docs/manpages/smbsh.1
new file mode 100644
index 00000000000..349853bbc7c
--- /dev/null
+++ b/docs/manpages/smbsh.1
@@ -0,0 +1,74 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBSH" "1" "06 December 2001" "" ""
+.SH NAME
+smbsh \- Allows access to Windows NT filesystem using UNIX commands
+.SH SYNOPSIS
+.sp
+\fBsmbsh\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBsmbsh\fR allows you to access an NT filesystem
+using UNIX commands such as \fBls\fR, \fB egrep\fR, and \fBrcp\fR. You must use a
+shell that is dynamically linked in order for \fBsmbsh\fR
+to work correctly.
+.PP
+To use the \fBsmbsh\fR command, execute \fB smbsh\fR from the prompt and enter the username and password
+that authenticates you to the machine running the Windows NT
+operating system.
+.PP
+.sp
+.nf
+ system% \fBsmbsh\fR
+ Username: \fBuser\fR
+ Password: \fBXXXXXXX\fR
+
+.sp
+.fi
+.PP
+Any dynamically linked command you execute from
+this shell will access the \fI/smb\fR directory
+using the smb protocol. For example, the command \fBls /smb
+\fRwill show a list of workgroups. The command
+\fBls /smb/MYGROUP \fR will show all the machines in
+the workgroup MYGROUP. The command
+\fBls /smb/MYGROUP/<machine-name>\fR will show the share
+names for that machine. You could then, for example, use the \fB cd\fR command to change directories, \fBvi\fR to
+edit files, and \fBrcp\fR to copy files.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "BUGS"
+.PP
+\fBsmbsh\fR works by intercepting the standard
+libc calls with the dynamically loaded versions in \fI smbwrapper.o\fR. Not all calls have been "wrapped", so
+some programs may not function correctly under \fBsmbsh
+\fR\&.
+.PP
+Programs which are not dynamically linked cannot make
+use of \fBsmbsh\fR's functionality. Most versions
+of UNIX have a \fBfile\fR command that will
+describe how a program was linked.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fR,
+smb.conf(5)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbspool.8 b/docs/manpages/smbspool.8
new file mode 100644
index 00000000000..864ea348f26
--- /dev/null
+++ b/docs/manpages/smbspool.8
@@ -0,0 +1,102 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBSPOOL" "8" "06 December 2001" "" ""
+.SH NAME
+smbspool \- send print file to an SMB printer
+.SH SYNOPSIS
+.sp
+\fBsmbspool\fR [ \fBjob\fR ] [ \fBuser\fR ] [ \fBtitle\fR ] [ \fBcopies\fR ] [ \fBoptions\fR ] [ \fBfilename\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+smbspool is a very small print spooling program that
+sends a print file to an SMB printer. The command-line arguments
+are position-dependent for compatibility with the Common UNIX
+Printing System, but you can use smbspool with any printing system
+or from a program or script.
+.PP
+\fBDEVICE URI\fR
+.PP
+smbspool specifies the destination using a Uniform Resource
+Identifier ("URI") with a method of "smb". This string can take
+a number of forms:
+.TP 0.2i
+\(bu
+smb://server/printer
+.TP 0.2i
+\(bu
+smb://workgroup/server/printer
+.TP 0.2i
+\(bu
+smb://username:password@server/printer
+.TP 0.2i
+\(bu
+smb://username:password@workgroup/server/printer
+.PP
+smbspool tries to get the URI from argv[0]. If argv[0]
+contains the name of the program then it looks in the \fB DEVICE_URI\fR environment variable.
+.PP
+.PP
+Programs using the \fBexec(2)\fR functions can
+pass the URI in argv[0], while shell scripts must set the
+\fBDEVICE_URI\fR environment variable prior to
+running smbspool.
+.PP
+.SH "OPTIONS"
+.TP 0.2i
+\(bu
+The job argument (argv[1]) contains the
+job ID number and is presently not used by smbspool.
+.TP 0.2i
+\(bu
+The user argument (argv[2]) contains the
+print user's name and is presently not used by smbspool.
+.TP 0.2i
+\(bu
+The title argument (argv[3]) contains the
+job title string and is passed as the remote file name
+when sending the print job.
+.TP 0.2i
+\(bu
+The copies argument (argv[4]) contains
+the number of copies to be printed of the named file. If
+no filename is provided than this argument is not used by
+smbspool.
+.TP 0.2i
+\(bu
+The options argument (argv[5]) contains
+the print options in a single string and is presently
+not used by smbspool.
+.TP 0.2i
+\(bu
+The filename argument (argv[6]) contains the
+name of the file to print. If this argument is not specified
+then the print file is read from the standard input.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fR,
+and samba(7).
+.SH "AUTHOR"
+.PP
+\fBsmbspool\fR was written by Michael Sweet
+at Easy Software Products.
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbstatus.1 b/docs/manpages/smbstatus.1
index 76dc50cbb53..17c1df25e54 100644
--- a/docs/manpages/smbstatus.1
+++ b/docs/manpages/smbstatus.1
@@ -1,52 +1,70 @@
-.TH SMBSTATUS 1 17/1/1995 smbstatus smbstatus
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBSTATUS" "1" "06 December 2001" "" ""
.SH NAME
smbstatus \- report on current Samba connections
.SH SYNOPSIS
-.B smbstatus
-[-d]
-[-s
-.I configuration file
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B smbstatus
-is a very simple program to list the current Samba connections
-
-Just run the program and the output is self explanatory. You can offer
-a configuration filename to override the default. The default is
-CONFIGFILE from the Makefile.
-
-Option
-.I -d
+.sp
+\fBsmbstatus\fR [ \fB-P\fR ] [ \fB-b\fR ] [ \fB-d\fR ] [ \fB-L\fR ] [ \fB-p\fR ] [ \fB-S\fR ] [ \fB-s <configuration file>\fR ] [ \fB-u <username>\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBsmbstatus\fR is a very simple program to
+list the current Samba connections.
+.SH "OPTIONS"
+.TP
+\fB-P\fR
+If samba has been compiled with the
+profiling option, print only the contents of the profiling
+shared memory area.
+.TP
+\fB-b\fR
+gives brief output.
+.TP
+\fB-d\fR
gives verbose output.
-
-.I -p
-print a list of smbd processes and exit. Useful for scripting.
-
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the
-.B smbstatus
-program be installed under the /usr/local hierarchy, in a directory readable
-by all, writeable only by root. The program itself should be executable by all.
-
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the program has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B smb.conf(5),
-.B smbd(8)
-
-See
-.B smb.conf(5) for a full list of contributors and details on how to
-submit bug reports, comments etc.
+.TP
+\fB-L\fR
+causes smbstatus to only list locks.
+.TP
+\fB-p\fR
+print a list of \fBsmbd(8)\fRprocesses and exit.
+Useful for scripting.
+.TP
+\fB-S\fR
+causes smbstatus to only list shares.
+.TP
+\fB-s <configuration file>\fR
+The default configuration file name is
+determined at compile time. The file specified contains the
+configuration details required by the server. See \fIsmb.conf(5)\fR
+for more information.
+.TP
+\fB-u <username>\fR
+selects information relevant to
+\fIusername\fR only.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fRand
+smb.conf(5).
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/smbtar.1 b/docs/manpages/smbtar.1
index 0f1c38c271f..8e70d75fd81 100644
--- a/docs/manpages/smbtar.1
+++ b/docs/manpages/smbtar.1
@@ -1,167 +1,120 @@
-.TH SMBTAR 1 18/2/96 smbtar smbtar
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBTAR" "1" "06 December 2001" "" ""
.SH NAME
-smbtar \- shell script for backing up SMB shares directly to UNIX tape drive
+smbtar \- shell script for backing up SMB/CIFS shares directly to UNIX tape drives
.SH SYNOPSIS
-.B smbtar
-.B \-s
-.I server
-.B [ \-p
-.I password
-.B ]
-.B [ \-x
-.I service
-.B ]
-.B [ \-X ]
-.B [ \-d
-.I directory
-.B ]
-.B [ \-u
-.I user
-.B ]
-.B [ \-t
-.I tape
-.B ]
-.B [ \-b
-.I blocksize
-.B ]
-.B [ \-N
-.I filename
-.B ]
-.B [ \-i ]
-.B [ \-r ]
-.B [ \-l ]
-.B [ \-v ]
-.I filenames...
-
-.SH DESCRIPTION
-This program is an extension to the Samba suite.
-
-.B smbtar
-is a very small shell script on top of smbclient, which dumps SMB
-shares directly to tape.
-
-.SH OPTIONS
-.B \-s
-.I server
-.RS 3
-The PC that the share resides upon.
-.RE
-
-.B \-x
-.I service
-.RS 3
-The share name on the PC to connect to. Default:
-.I backup.
-.RE
-
-.B \-X
-.RS 3
-Exclude mode. Exclude
-.I filenames...
-from tar create or restore.
-.RE
-
-.B \-d
-.I directory
-.RS 3
-Change to initial
-.I directory
-before restoring / backing up files.
-.RE
-
-.B \-v
-.RS 3
+.sp
+\fBsmbtar\fR \fB-s server\fR [ \fB-p password\fR ] [ \fB-x services\fR ] [ \fB-X\fR ] [ \fB-d directory\fR ] [ \fB-u user\fR ] [ \fB-t tape\fR ] [ \fB-t tape\fR ] [ \fB-b blocksize\fR ] [ \fB-N filename\fR ] [ \fB-i\fR ] [ \fB-r\fR ] [ \fB-l loglevel\fR ] [ \fB-v\fR ] \fBfilenames\fR
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBsmbtar\fR is a very small shell script on top
+of \fBsmbclient(1)\fR
+which dumps SMB shares directly to tape.
+.SH "OPTIONS"
+.TP
+\fB-s server\fR
+The SMB/CIFS server that the share resides
+upon.
+.TP
+\fB-x service\fR
+The share name on the server to connect to.
+The default is "backup".
+.TP
+\fB-X\fR
+Exclude mode. Exclude filenames... from tar
+create or restore.
+.TP
+\fB-d directory\fR
+Change to initial \fIdirectory
+\fRbefore restoring / backing up files.
+.TP
+\fB-v\fR
Verbose mode.
-.RE
-
-.B \-p
-.I password
-
-.RS 3
-The password to use to access a share. Default: none
-.RE
-
-.B \-u
-.I user
-.RS 3
-The user id to connect as. Default: UNIX login name.
-.RE
-
-.B \-t
-.I tape
-.RS 3
-Tape device. May be regular file or tape device. Default: Tape environmental
-variable; if not set, a file called
-.I tar.out.
-.RE
-
-.B \-b
-.I blocksize
-.RS 3
-Blocking factor. Defaults to 20. See tar(1) for a fuller explanation.
-.RE
-
-.B \-N
-.I filename
-.RS 3
-Backup only files newer than filename. Could be used (for example) on a log
-file to implement incremental backups.
-.RE
-
-.B \-i
-.RS 3
-Incremental mode; tar files are only backed up if they have the
-archive bit set. The archive bit is reset after each file is read.
-.RE
-
-.B \-r
-.RS 3
-Restore. Files are restored to the share from the tar file.
-.RE
-
-.B \-l
-.RS 3
-Debug level. Corresponds to -d flag on smbclient(1).
-.RE
-
-.SH ENVIRONMENT VARIABLES
-The TAPE variable specifies the default tape device to write to. May
-be overidden with the -t option.
-
-.SH BUGS
-The smbtar script has different options from ordinary tar and tar
-called from smbclient.
-
-.SH CAVEATS
-Sites that are more careful about security may not like the way
-the script handles PC passwords. Backup and restore work on entire shares,
-should work on file lists.
-
-.SH VERSION
-This man page is correct for version 1.9.15p8 of the Samba suite.
-
-.SH SEE ALSO
-.B smbclient
-(8),
-.B smb.conf
-(8)
-.SH DIAGNOSTICS
-See diagnostics for
-.B smbclient
+.TP
+\fB-p password\fR
+The password to use to access a share.
+Default: none
+.TP
+\fB-u user\fR
+The user id to connect as. Default:
+UNIX login name.
+.TP
+\fB-t tape\fR
+Tape device. May be regular file or tape
+device. Default: \fI$TAPE\fR environmental
+variable; if not set, a file called \fItar.out
+\fR\&.
+.TP
+\fB-b blocksize\fR
+Blocking factor. Defaults to 20. See
+\fBtar(1)\fR for a fuller explanation.
+.TP
+\fB-N filename\fR
+Backup only files newer than filename. Could
+be used (for example) on a log file to implement incremental
+backups.
+.TP
+\fB-i\fR
+Incremental mode; tar files are only backed
+up if they have the archive bit set. The archive bit is reset
+after each file is read.
+.TP
+\fB-r\fR
+Restore. Files are restored to the share
+from the tar file.
+.TP
+\fB-l log level\fR
+Log (debug) level. Corresponds to the
+\fI-d\fR flag of \fBsmbclient(1)
+\fR\&.
+.SH "ENVIRONMENT VARIABLES"
+.PP
+The \fI$TAPE\fR variable specifies the
+default tape device to write to. May be overridden
+with the -t option.
+.SH "BUGS"
+.PP
+The \fBsmbtar\fR script has different
+options from ordinary tar and tar called from smbclient.
+.SH "CAVEATS"
+.PP
+Sites that are more careful about security may not like
+the way the script handles PC passwords. Backup and restore work
+on entire shares, should work on file lists. smbtar works best
+with GNU tar and may not work well with other versions.
+.SH "DIAGNOSTICS"
+.PP
+See the \fBDIAGNOSTICS\fR section for the
+\fBsmbclient(1)\fR
command.
-
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-Ricky Poulten (poultenr@logica.co.uk) wrote the tar extension and this
-man page. The smbtar script was heavily rewritten and improved by
-Martin Kraemer <Martin.Kraemer@mch.sni.de>. Many thanks to everyone
-who suggested extensions, improvements, bug fixes, etc.
-
-See
-.B smb.conf
-(5) for a full list of contributors and details of how to submit bug reports,
-comments etc.
-
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBsmbd(8)\fR,
+\fBsmbclient(1)\fR,
+smb.conf(5),
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+Ricky Poulten <URL:mailto:poultenr@logica.co.uk>
+wrote the tar extension and this man page. The \fBsmbtar\fR
+script was heavily rewritten and improved by Martin Kraemer <URL:mailto:Martin.Kraemer@mch.sni.de>. Many
+thanks to everyone who suggested extensions, improvements, bug
+fixes, etc. The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter.
diff --git a/docs/manpages/smbumount.8 b/docs/manpages/smbumount.8
new file mode 100644
index 00000000000..d20826950aa
--- /dev/null
+++ b/docs/manpages/smbumount.8
@@ -0,0 +1,42 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SMBUMOUNT" "8" "06 December 2001" "" ""
+.SH NAME
+smbumount \- smbfs umount for normal users
+.SH SYNOPSIS
+.sp
+\fBsmbumount\fR \fBmount-point\fR
+.SH "DESCRIPTION"
+.PP
+With this program, normal users can unmount smb-filesystems,
+provided that it is suid root. \fBsmbumount\fR has
+been written to give normal Linux users more control over their
+resources. It is safe to install this program suid root, because only
+the user who has mounted a filesystem is allowed to unmount it again.
+For root it is not necessary to use smbumount. The normal umount
+program works perfectly well, but it would certainly be problematic
+to make umount setuid root.
+.SH "OPTIONS"
+.TP
+\fBmount-point\fR
+The directory to unmount.
+.SH "SEE ALSO"
+.PP
+\fBsmbmount(8)\fR
+
+.SH "AUTHOR"
+.PP
+Volker Lendecke, Andrew Tridgell, Michael H. Warfield
+and others.
+.PP
+The current maintainer of smbfs and the userspace
+tools \fBsmbmount\fR, \fBsmbumount\fR,
+and \fBsmbmnt\fR is Urban Widmark <URL:mailto:urban@teststation.com>.
+The SAMBA Mailing list <URL:mailto:samba@samba.org>
+is the preferred place to ask questions regarding these programs.
+.PP
+The conversion of this manpage for Samba 2.2 was performed
+by Gerald Carter
diff --git a/docs/manpages/swat.8 b/docs/manpages/swat.8
new file mode 100644
index 00000000000..5e19f8705ce
--- /dev/null
+++ b/docs/manpages/swat.8
@@ -0,0 +1,140 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "SWAT" "8" "06 December 2001" "" ""
+.SH NAME
+swat \- Samba Web Administration Tool
+.SH SYNOPSIS
+.sp
+\fBswat\fR [ \fB-s <smb config file>\fR ] [ \fB-a\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBswat\fR allows a Samba administrator to
+configure the complex \fI smb.conf(5)\fRfile via a Web browser. In addition,
+a \fBswat\fR configuration page has help links
+to all the configurable options in the \fIsmb.conf\fR file allowing an
+administrator to easily look up the effects of any change.
+.PP
+\fBswat\fR is run from \fBinetd\fR
+.SH "OPTIONS"
+.TP
+\fB-s smb configuration file\fR
+The default configuration file path is
+determined at compile time. The file specified contains
+the configuration details required by the \fBsmbd
+\fRserver. This is the file that \fBswat\fR will modify.
+The information in this file includes server-specific
+information such as what printcap file to use, as well as
+descriptions of all the services that the server is to provide.
+See \fIsmb.conf\fR for more information.
+.TP
+\fB-a\fR
+This option disables authentication and puts
+\fBswat\fR in demo mode. In that mode anyone will be able to modify
+the \fIsmb.conf\fR file.
+
+\fBDo NOT enable this option on a production
+server. \fR
+.SH "INSTALLATION"
+.PP
+After you compile SWAT you need to run \fBmake install
+\fRto install the \fBswat\fR binary
+and the various help files and images. A default install would put
+these in:
+.TP 0.2i
+\(bu
+/usr/local/samba/bin/swat
+.TP 0.2i
+\(bu
+/usr/local/samba/swat/images/*
+.TP 0.2i
+\(bu
+/usr/local/samba/swat/help/*
+.SS "INETD INSTALLATION"
+.PP
+You need to edit your \fI/etc/inetd.conf
+\fRand \fI/etc/services\fR
+to enable SWAT to be launched via \fBinetd\fR.
+.PP
+In \fI/etc/services\fR you need to
+add a line like this:
+.PP
+\fBswat 901/tcp\fR
+.PP
+Note for NIS/YP users - you may need to rebuild the
+NIS service maps rather than alter your local \fI /etc/services\fR file.
+.PP
+the choice of port number isn't really important
+except that it should be less than 1024 and not currently
+used (using a number above 1024 presents an obscure security
+hole depending on the implementation details of your
+\fBinetd\fR daemon).
+.PP
+In \fI/etc/inetd.conf\fR you should
+add a line like this:
+.PP
+\fBswat stream tcp nowait.400 root
+/usr/local/samba/bin/swat swat\fR
+.PP
+One you have edited \fI/etc/services\fR
+and \fI/etc/inetd.conf\fR you need to send a
+HUP signal to inetd. To do this use \fBkill -1 PID
+\fRwhere PID is the process ID of the inetd daemon.
+.SS "LAUNCHING"
+.PP
+To launch SWAT just run your favorite web browser and
+point it at "http://localhost:901/".
+.PP
+Note that you can attach to SWAT from any IP connected
+machine but connecting from a remote machine leaves your
+connection open to password sniffing as passwords will be sent
+in the clear over the wire.
+.SH "FILES"
+.TP
+\fB\fI/etc/inetd.conf\fB\fR
+This file must contain suitable startup
+information for the meta-daemon.
+.TP
+\fB\fI/etc/services\fB\fR
+This file must contain a mapping of service name
+(e.g., swat) to service port (e.g., 901) and protocol type
+(e.g., tcp).
+.TP
+\fB\fI/usr/local/samba/lib/smb.conf\fB\fR
+This is the default location of the \fIsmb.conf(5)
+\fRserver configuration file that swat edits. Other
+common places that systems install this file are \fI /usr/samba/lib/smb.conf\fR and \fI/etc/smb.conf
+\fR\&. This file describes all the services the server
+is to make available to clients.
+.SH "WARNINGS"
+.PP
+\fBswat\fR will rewrite your \fIsmb.conf
+\fRfile. It will rearrange the entries and delete all
+comments, \fIinclude=\fR and \fIcopy="
+\fRoptions. If you have a carefully crafted \fI smb.conf\fR then back it up or don't use swat!
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBinetd(5)\fR,
+\fBsmbd(8)\fR,
+smb.conf(5)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
index 4a0ffcbc489..d9515eddf42 100644
--- a/docs/manpages/testparm.1
+++ b/docs/manpages/testparm.1
@@ -1,104 +1,100 @@
-.TH TESTPARM 1 17/1/1995 testparm testparm
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "TESTPARM" "1" "06 December 2001" "" ""
.SH NAME
-testparm \- check an smbd configuration file for internal correctness
+testparm \- check an smb.conf configuration file for internal correctness
.SH SYNOPSIS
-.B testparm
-[
-.I configfilename
-[
-.I hostname
-.I hostIP
-]
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B testparm
-is a very simple test program to check an
-.B smbd
-configuration
-file for internal correctness. If this program reports no problems, you can use
-the configuration file with confidence that smbd will successfully
-load the configuration file.
-
-Note that this is NOT a guarantee that the services specified in the
-configuration file will be available or will operate as expected.
-
-If the optional host name and host IP address are specified on the
-command line, this test program will run through the service entries
-reporting whether the specified host has access to each service.
-.SH OPTIONS
-.I configfilename
-
-.RS 3
-This is the name of the configuration file to check.
-.RE
-
-.I hostname
-
-.RS 3
-This is the name of the host to check access on.
-
-If this parameter is supplied, the
-.I hostIP
-parameter must also be supplied, or strange things may happen.
-.RE
-
-.I hostIP
-
-.RS 3
-This is the IP number of the host specified in the previous parameter.
-
-This number must be supplied if the
-.I hostname
-parameter is supplied, or strange things may happen.
-.RE
-.SH FILES
-.B smb.conf
-.RS 3
-This is usually the name of the configuration file used by smbd.
-.RE
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the
-.B testparm
-program be installed under the /usr/local hierarchy, in a directory readable
-by all, writeable only by root. The program itself should be executable by all.
-The program should NOT be setuid or setgid!
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the program has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B smb.conf(5),
-.B smbd(8)
-.SH DIAGNOSTICS
-The program will issue a message saying whether the configuration file loaded
-OK or not. This message may be preceded by errors and warnings if the file
-did not load. If the file was loaded OK, the program then dumps all known
-service details to stdout.
-
-If a host name is specified but no host IP number, all bets are off.
-
-Other messages are self-explanatory.
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-The testparm program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
-
-See
-.B samba(7) for a full list of contributors and details on how to
-submit bug reports, comments etc.
+.sp
+\fBtestparm\fR [ \fB-s\fR ] [ \fB-h\fR ] [ \fB-L <servername>\fR ] \fBconfig filename\fR [ \fBhostname hostIP\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBtestparm\fR is a very simple test program
+to check an \fBsmbd\fR configuration file for
+internal correctness. If this program reports no problems, you
+can use the configuration file with confidence that \fBsmbd
+\fRwill successfully load the configuration file.
+.PP
+Note that this is \fBNOT\fR a guarantee that
+the services specified in the configuration file will be
+available or will operate as expected.
+.PP
+If the optional host name and host IP address are
+specified on the command line, this test program will run through
+the service entries reporting whether the specified host
+has access to each service.
+.PP
+If \fBtestparm\fR finds an error in the \fI smb.conf\fR file it returns an exit code of 1 to the calling
+program, else it returns an exit code of 0. This allows shell scripts
+to test the output from \fBtestparm\fR.
+.SH "OPTIONS"
+.TP
+\fB-s\fR
+Without this option, \fBtestparm\fR
+will prompt for a carriage return after printing the service
+names and before dumping the service definitions.
+.TP
+\fB-h\fR
+Print usage message
+.TP
+\fB-L servername\fR
+Sets the value of the %L macro to \fIservername\fR.
+This is useful for testing include files specified with the
+%L macro.
+.TP
+\fBconfigfilename\fR
+This is the name of the configuration file
+to check. If this parameter is not present then the
+default \fIsmb.conf\fR file will be checked.
+.TP
+\fBhostname\fR
+If this parameter and the following are
+specified, then \fBtestparm\fR will examine the \fIhosts
+allow\fR and \fIhosts deny\fR
+parameters in the \fIsmb.conf\fR file to
+determine if the hostname with this IP address would be
+allowed access to the \fBsmbd\fR server. If
+this parameter is supplied, the hostIP parameter must also
+be supplied.
+.TP
+\fBhostIP\fR
+This is the IP address of the host specified
+in the previous parameter. This address must be supplied
+if the hostname parameter is supplied.
+.SH "FILES"
+.TP
+\fB\fIsmb.conf\fB\fR
+This is usually the name of the configuration
+file used by \fBsmbd\fR.
+.SH "DIAGNOSTICS"
+.PP
+The program will issue a message saying whether the
+configuration file loaded OK or not. This message may be preceded by
+errors and warnings if the file did not load. If the file was
+loaded OK, the program then dumps all known service details
+to stdout.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fIsmb.conf(5)\fR,
+\fBsmbd(8)\fR
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/testprns.1 b/docs/manpages/testprns.1
index f1c3d3ef020..fd62ed83861 100644
--- a/docs/manpages/testprns.1
+++ b/docs/manpages/testprns.1
@@ -1,107 +1,90 @@
-.TH TESTPRNS 1 17/1/1995 testprns testprns
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "TESTPRNS" "1" "06 December 2001" "" ""
.SH NAME
testprns \- check printer name for validity with smbd
.SH SYNOPSIS
-.B testprns
-.I printername
-[
-.I printcapname
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B testprns
-is a very simple test program to determine whether a given
-printer name is valid for use in a service to be provided by
-.B smbd.
-
-"Valid" in this context means "can be found in the printcap specified". This
-program is very stupid - so stupid in fact that it would be wisest to always
-specify the printcap file to use.
-.SH OPTIONS
-.I printername
-
-.RS 3
+.sp
+\fBtestprns\fR \fBprintername\fR [ \fBprintcapname\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+\fBtestprns\fR is a very simple test program
+to determine whether a given printer name is valid for use in
+a service to be provided by \fB smbd(8)\fR.
+.PP
+"Valid" in this context means "can be found in the
+printcap specified". This program is very stupid - so stupid in
+fact that it would be wisest to always specify the printcap file
+to use.
+.SH "OPTIONS"
+.TP
+\fBprintername\fR
The printer name to validate.
-Printer names are taken from the first field in each record in the printcap
-file, single printer names and sets of aliases separated by vertical bars
-("|") are recognised. Note that no validation or checking of the printcap
-syntax is done beyond that required to extract the printer name. It may
-be that the print spooling system is more forgiving or less forgiving
-than
-.B testprns
-however if
-.B testprns
-finds the printer then smbd should do as well.
-
-.RE
-
-.I printcapname
-
-.RS 3
-This is the name of the printcap file to search for the given printer name
-in.
-
-If no printcap name is specified,
-.B testprns
-will attempt to scan the printcap file specified at compile time
-(PRINTCAP_NAME).
-.RE
-.SH FILES
-.B /etc/printcap
-.RS 3
-This is usually the default printcap file to scan. See
-.B printcap(5)).
-.RE
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the
-.B testprns
-program be installed under the /usr/local hierarchy, in a directory readable
-by all, writeable only by root. The program should be executable by all.
-The program should NOT be setuid or setgid!
-.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the program has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
-.SH SEE ALSO
-.B printcap(5),
-.B smbd(8),
-.B smbclient(1)
-.SH DIAGNOSTICS
-If a printer is found to be valid, the message "Printer name <printername> is
-valid" will be displayed.
-
-If a printer is found to be invalid, the message "Printer name <printername>
-is not valid" will be displayed.
-
-All messages that would normally be logged during operation of smbd are
-logged by this program to the file
-.I test.log
-in the current directory. The program runs at debuglevel 3, so quite extensive
-logging information is written. The log should be checked carefully for errors
-and warnings.
-
-Other messages are self-explanatory.
-.SH BUGS
-None known.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
-of the Source for this project.
-
-The testprns program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
+Printer names are taken from the first field in each
+record in the printcap file, single printer names and sets
+of aliases separated by vertical bars ("|") are recognized.
+Note that no validation or checking of the printcap syntax is
+done beyond that required to extract the printer name. It may
+be that the print spooling system is more forgiving or less
+forgiving than \fBtestprns\fR. However, if
+\fBtestprns\fR finds the printer then
+\fBsmbd\fR should do so as well.
+.TP
+\fBprintcapname\fR
+This is the name of the printcap file within
+which to search for the given printer name.
-See
-.B samba(7) for a full list of contributors and details of how to
-submit bug reports, comments etc.
+If no printcap name is specified \fBtestprns
+\fRwill attempt to scan the printcap file name
+specified at compile time.
+.SH "FILES"
+.TP
+\fB\fI/etc/printcap\fB\fR
+This is usually the default printcap
+file to scan. See \fIprintcap (5)\fR.
+.SH "DIAGNOSTICS"
+.PP
+If a printer is found to be valid, the message
+"Printer name <printername> is valid" will be
+displayed.
+.PP
+If a printer is found to be invalid, the message
+"Printer name <printername> is not valid" will be
+displayed.
+.PP
+All messages that would normally be logged during
+operation of the Samba daemons are logged by this program to the
+file \fItest.log\fR in the current directory. The
+program runs at debuglevel 3, so quite extensive logging
+information is written. The log should be checked carefully
+for errors and warnings.
+.PP
+Other messages are self-explanatory.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fIprintcap(5)\fR,
+\fBsmbd(8)\fR,
+\fBsmbclient(1)\fR
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+The original Samba man pages were written by Karl Auer.
+The man page sources were converted to YODL format (another
+excellent piece of Open Source software, available at
+ftp://ftp.icce.rug.nl/pub/unix/ <URL:ftp://ftp.icce.rug.nl/pub/unix/>) and updated for the Samba 2.0
+release by Jeremy Allison. The conversion to DocBook for
+Samba 2.2 was done by Gerald Carter
diff --git a/docs/manpages/wbinfo.1 b/docs/manpages/wbinfo.1
new file mode 100644
index 00000000000..63795899c82
--- /dev/null
+++ b/docs/manpages/wbinfo.1
@@ -0,0 +1,110 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "WBINFO" "1" "06 December 2001" "" ""
+.SH NAME
+wbinfo \- Query information from winbind daemon
+.SH SYNOPSIS
+.sp
+\fBwbinfo\fR [ \fB-u\fR ] [ \fB-g\fR ] [ \fB-n name\fR ] [ \fB-s sid\fR ] [ \fB-U uid\fR ] [ \fB-G gid\fR ] [ \fB-S sid\fR ] [ \fB-Y sid\fR ] [ \fB-t\fR ] [ \fB-m\fR ]
+.SH "DESCRIPTION"
+.PP
+This tool is part of the Sambasuite.
+.PP
+The \fBwbinfo\fR program queries and returns information
+created and used by the \fB winbindd(8)\fRdaemon.
+.PP
+The \fBwinbindd(8)\fR daemon must be configured
+and running for the \fBwbinfo\fR program to be able
+to return information.
+.SH "OPTIONS"
+.TP
+\fB-u\fR
+This option will list all users available
+in the Windows NT domain for which the \fBwinbindd(8)
+\fRdaemon is operating in. Users in all trusted domains
+will also be listed. Note that this operation does not assign
+user ids to any users that have not already been seen by
+\fBwinbindd(8)\fR.
+.TP
+\fB-g\fR
+This option will list all groups available
+in the Windows NT domain for which the \fBwinbindd(8)
+\fRdaemon is operating in. Groups in all trusted domains
+will also be listed. Note that this operation does not assign
+group ids to any groups that have not already been seen by
+\fBwinbindd(8)\fR.
+.TP
+\fB-n name\fR
+The \fI-n\fR option
+queries \fBwinbindd(8)\fR for the SID
+associated with the name specified. Domain names can be specified
+before the user name by using the winbind separator character.
+For example CWDOM1/Administrator refers to the Administrator
+user in the domain CWDOM1. If no domain is specified then the
+domain used is the one specified in the \fIsmb.conf\fR
+\fIworkgroup\fR parameter.
+.TP
+\fB-s sid\fR
+Use \fI-s\fR to resolve
+a SID to a name. This is the inverse of the \fI-n
+\fRoption above. SIDs must be specified as ASCII strings
+in the traditional Microsoft format. For example,
+S-1-5-21-1455342024-3071081365-2475485837-500.
+.TP
+\fB-U uid\fR
+Try to convert a UNIX user id to a Windows NT
+SID. If the uid specified does not refer to one within
+the winbind uid range then the operation will fail.
+.TP
+\fB-G gid\fR
+Try to convert a UNIX group id to a Windows
+NT SID. If the gid specified does not refer to one within
+the winbind gid range then the operation will fail.
+.TP
+\fB-S sid\fR
+Convert a SID to a UNIX user id. If the SID
+does not correspond to a UNIX user mapped by \fB winbindd(8)\fR then the operation will fail.
+.TP
+\fB-Y sid\fR
+Convert a SID to a UNIX group id. If the SID
+does not correspond to a UNIX group mapped by \fB winbindd(8)\fR then the operation will fail.
+.TP
+\fB-t\fR
+Verify that the workstation trust account
+created when the Samba server is added to the Windows NT
+domain is working.
+.TP
+\fB-m\fR
+Produce a list of domains trusted by the
+Windows NT server \fBwinbindd(8)\fR contacts
+when resolving names. This list does not include the Windows
+NT domain the server is a Primary Domain Controller for.
+.SH "EXIT STATUS"
+.PP
+The wbinfo program returns 0 if the operation
+succeeded, or 1 if the operation failed. If the \fBwinbindd(8)
+\fRdaemon is not working \fBwbinfo\fR will always return
+failure.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fBwinbindd(8)\fR
+
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+\fBwbinfo\fR and \fBwinbindd\fR
+were written by Tim Potter.
+.PP
+The conversion to DocBook for Samba 2.2 was done
+by Gerald Carter
diff --git a/docs/manpages/winbindd.8 b/docs/manpages/winbindd.8
new file mode 100644
index 00000000000..cfd4fa2fb27
--- /dev/null
+++ b/docs/manpages/winbindd.8
@@ -0,0 +1,381 @@
+.\" This manpage has been automatically generated by docbook2man-spec
+.\" from a DocBook document. docbook2man-spec can be found at:
+.\" <http://shell.ipoline.com/~elmert/hacks/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "WINBINDD" "8" "06 December 2001" "" ""
+.SH NAME
+winbindd \- Name Service Switch daemon for resolving names from NT servers
+.SH SYNOPSIS
+.sp
+\fBwinbindd\fR [ \fB-i\fR ] [ \fB-d <debug level>\fR ] [ \fB-s <smb config file>\fR ]
+.SH "DESCRIPTION"
+.PP
+This program is part of the Sambasuite.
+.PP
+\fBwinbindd\fR is a daemon that provides
+a service for the Name Service Switch capability that is present
+in most modern C libraries. The Name Service Switch allows user
+and system information to be obtained from different databases
+services such as NIS or DNS. The exact behaviour can be configured
+throught the \fI/etc/nsswitch.conf\fR file.
+Users and groups are allocated as they are resolved to a range
+of user and group ids specified by the administrator of the
+Samba system.
+.PP
+The service provided by \fBwinbindd\fR is called `winbind' and
+can be used to resolve user and group information from a
+Windows NT server. The service can also provide authentication
+services via an associated PAM module.
+.PP
+The \fIpam_winbind\fR module in the 2.2.2 release only
+supports the \fIauth\fR and \fIaccount\fR
+module-types. The latter is simply
+performs a getpwnam() to verify that the system can obtain a uid for the
+user. If the \fIlibnss_winbind\fR library has been correctly
+installed, this should always suceed.
+.PP
+The following nsswitch databases are implemented by
+the winbindd service:
+.TP
+\fBpasswd\fR
+User information traditionally stored in
+the \fIpasswd(5)\fR file and used by
+\fBgetpwent(3)\fR functions.
+.TP
+\fBgroup\fR
+Group information traditionally stored in
+the \fIgroup(5)\fR file and used by
+\fBgetgrent(3)\fR functions.
+.PP
+For example, the following simple configuration in the
+\fI/etc/nsswitch.conf\fR file can be used to initially
+resolve user and group information from \fI/etc/passwd
+\fRand \fI/etc/group\fR and then from the
+Windows NT server.
+.PP
+.PP
+.sp
+.nf
+passwd: files winbind
+group: files winbind
+
+.sp
+.fi
+.PP
+.SH "OPTIONS"
+.TP
+\fB-d debuglevel\fR
+Sets the debuglevel to an integer between
+0 and 100. 0 is for no debugging and 100 is for reams and
+reams. To submit a bug report to the Samba Team, use debug
+level 100 (see BUGS.txt).
+.TP
+\fB-i\fR
+Tells \fBwinbindd\fR to not
+become a daemon and detach from the current terminal. This
+option is used by developers when interactive debugging
+of \fBwinbindd\fR is required.
+.SH "NAME AND ID RESOLUTION"
+.PP
+Users and groups on a Windows NT server are assigned
+a relative id (rid) which is unique for the domain when the
+user or group is created. To convert the Windows NT user or group
+into a unix user or group, a mapping between rids and unix user
+and group ids is required. This is one of the jobs that \fB winbindd\fR performs.
+.PP
+As winbindd users and groups are resolved from a server, user
+and group ids are allocated from a specified range. This
+is done on a first come, first served basis, although all existing
+users and groups will be mapped as soon as a client performs a user
+or group enumeration command. The allocated unix ids are stored
+in a database file under the Samba lock directory and will be
+remembered.
+.PP
+WARNING: The rid to unix id database is the only location
+where the user and group mappings are stored by winbindd. If this
+file is deleted or corrupted, there is no way for winbindd to
+determine which user and group ids correspond to Windows NT user
+and group rids.
+.SH "CONFIGURATION"
+.PP
+Configuration of the \fBwinbindd\fR daemon
+is done through configuration parameters in the \fIsmb.conf(5)
+\fRfile. All parameters should be specified in the
+[global] section of smb.conf.
+.TP
+\fBwinbind separator\fR
+The winbind separator option allows you
+to specify how NT domain names and user names are combined
+into unix user names when presented to users. By default,
+\fBwinbindd\fR will use the traditional '\\'
+separator so that the unix user names look like
+DOMAIN\\username. In some cases this separator character may
+cause problems as the '\\' character has special meaning in
+unix shells. In that case you can use the winbind separator
+option to specify an alternative separator character. Good
+alternatives may be '/' (although that conflicts
+with the unix directory separator) or a '+ 'character.
+The '+' character appears to be the best choice for 100%
+compatibility with existing unix utilities, but may be an
+aesthetically bad choice depending on your taste.
+
+Default: \fBwinbind separator = \\ \fR
+
+Example: \fBwinbind separator = + \fR
+.TP
+\fBwinbind uid\fR
+The winbind uid parameter specifies the
+range of user ids that are allocated by the winbindd daemon.
+This range of ids should have no existing local or NIS users
+within it as strange conflicts can occur otherwise.
+
+Default: \fBwinbind uid = <empty string>
+\fR
+Example: \fBwinbind uid = 10000-20000\fR
+.TP
+\fBwinbind gid\fR
+The winbind gid parameter specifies the
+range of group ids that are allocated by the winbindd daemon.
+This range of group ids should have no existing local or NIS
+groups within it as strange conflicts can occur otherwise.
+
+Default: \fBwinbind gid = <empty string>
+\fR
+Example: \fBwinbind gid = 10000-20000
+\fR.TP
+\fBwinbind cache time\fR
+This parameter specifies the number of
+seconds the winbindd daemon will cache user and group information
+before querying a Windows NT server again. When a item in the
+cache is older than this time winbindd will ask the domain
+controller for the sequence number of the server's account database.
+If the sequence number has not changed then the cached item is
+marked as valid for a further \fIwinbind cache time
+\fRseconds. Otherwise the item is fetched from the
+server. This means that as long as the account database is not
+actively changing winbindd will only have to send one sequence
+number query packet every \fIwinbind cache time
+\fRseconds.
+
+Default: \fBwinbind cache time = 15\fR
+.TP
+\fBwinbind enum users\fR
+On large installations it may be necessary
+to suppress the enumeration of users through the \fB setpwent()\fR, \fBgetpwent()\fR and
+\fBendpwent()\fR group of system calls. If
+the \fIwinbind enum users\fR parameter is false,
+calls to the \fBgetpwent\fR system call will not
+return any data.
+
+\fBWarning:\fR Turning off user enumeration
+may cause some programs to behave oddly. For example, the \fBfinger\fR
+program relies on having access to the full user list when
+searching for matching usernames.
+
+Default: \fBwinbind enum users = yes \fR
+.TP
+\fBwinbind enum groups\fR
+On large installations it may be necessary
+to suppress the enumeration of groups through the \fB setgrent()\fR, \fBgetgrent()\fR and
+\fBendgrent()\fR group of system calls. If
+the \fIwinbind enum groups\fR parameter is
+false, calls to the \fBgetgrent()\fR system
+call will not return any data.
+
+\fBWarning:\fR Turning off group
+enumeration may cause some programs to behave oddly.
+
+Default: \fBwinbind enum groups = no \fR
+.TP
+\fBtemplate homedir\fR
+When filling out the user information
+for a Windows NT user, the \fBwinbindd\fR daemon
+uses this parameter to fill in the home directory for that user.
+If the string \fI%D\fR is present it is
+substituted with the user's Windows NT domain name. If the
+string \fI%U\fR is present it is substituted
+with the user's Windows NT user name.
+
+Default: \fBtemplate homedir = /home/%D/%U \fR
+.TP
+\fBtemplate shell\fR
+When filling out the user information for
+a Windows NT user, the \fBwinbindd\fR daemon
+uses this parameter to fill in the shell for that user.
+
+Default: \fBtemplate shell = /bin/false \fR
+.SH "EXAMPLE SETUP"
+.PP
+To setup winbindd for user and group lookups plus
+authentication from a domain controller use something like the
+following setup. This was tested on a RedHat 6.2 Linux box.
+.PP
+In \fI/etc/nsswitch.conf\fR put the
+following:
+.PP
+.sp
+.nf
+passwd: files winbind
+group: files winbind
+
+.sp
+.fi
+.PP
+In \fI/etc/pam.d/*\fR replace the
+\fIauth\fR lines with something like this:
+.PP
+.sp
+.nf
+auth required /lib/security/pam_securetty.so
+auth required /lib/security/pam_nologin.so
+auth sufficient /lib/security/pam_winbind.so
+auth required /lib/security/pam_pwdb.so use_first_pass shadow nullok
+
+.sp
+.fi
+.PP
+Note in particular the use of the \fIsufficient\fR
+keyword and the \fIuse_first_pass\fR keyword.
+.PP
+Now replace the account lines with this:
+.PP
+\fBaccount required /lib/security/pam_winbind.so
+\fR.PP
+The next step is to join the domain. To do that use the
+\fBsmbpasswd\fR program like this:
+.PP
+\fBsmbpasswd -j DOMAIN -r PDC -U
+Administrator\fR
+.PP
+The username after the \fI-U\fR can be any
+Domain user that has administrator privileges on the machine.
+Substitute your domain name for "DOMAIN" and the name of your PDC
+for "PDC".
+.PP
+Next copy \fIlibnss_winbind.so\fR to
+\fI/lib\fR and \fIpam_winbind.so\fR
+to \fI/lib/security\fR. A symbolic link needs to be
+made from \fI/lib/libnss_winbind.so\fR to
+\fI/lib/libnss_winbind.so.2\fR. If you are using an
+older version of glibc then the target of the link should be
+\fI/lib/libnss_winbind.so.1\fR.
+.PP
+Finally, setup a \fIsmb.conf\fR containing directives like the
+following:
+.PP
+.sp
+.nf
+[global]
+ winbind separator = +
+ winbind cache time = 10
+ template shell = /bin/bash
+ template homedir = /home/%D/%U
+ winbind uid = 10000-20000
+ winbind gid = 10000-20000
+ workgroup = DOMAIN
+ security = domain
+ password server = *
+
+.sp
+.fi
+.PP
+Now start winbindd and you should find that your user and
+group database is expanded to include your NT users and groups,
+and that you can login to your unix box as a domain user, using
+the DOMAIN+user syntax for the username. You may wish to use the
+commands \fBgetent passwd\fR and \fBgetent group
+\fRto confirm the correct operation of winbindd.
+.SH "NOTES"
+.PP
+The following notes are useful when configuring and
+running \fBwinbindd\fR:
+.PP
+\fBnmbd\fR must be running on the local machine
+for \fBwinbindd\fR to work. \fBwinbindd\fR
+queries the list of trusted domains for the Windows NT server
+on startup and when a SIGHUP is received. Thus, for a running \fB winbindd\fR to become aware of new trust relationships between
+servers, it must be sent a SIGHUP signal.
+.PP
+Client processes resolving names through the \fBwinbindd\fR
+nsswitch module read an environment variable named \fB $WINBINDD_DOMAIN\fR. If this variable contains a comma separated
+list of Windows NT domain names, then winbindd will only resolve users
+and groups within those Windows NT domains.
+.PP
+PAM is really easy to misconfigure. Make sure you know what
+you are doing when modifying PAM configuration files. It is possible
+to set up PAM such that you can no longer log into your system.
+.PP
+If more than one UNIX machine is running \fBwinbindd\fR,
+then in general the user and groups ids allocated by winbindd will not
+be the same. The user and group ids will only be valid for the local
+machine.
+.PP
+If the the Windows NT RID to UNIX user and group id mapping
+file is damaged or destroyed then the mappings will be lost.
+.SH "SIGNALS"
+.PP
+The following signals can be used to manipulate the
+\fBwinbindd\fR daemon.
+.TP
+\fBSIGHUP\fR
+Reload the \fIsmb.conf(5)\fR
+file and apply any parameter changes to the running
+version of winbindd. This signal also clears any cached
+user and group information. The list of other domains trusted
+by winbindd is also reloaded.
+.TP
+\fBSIGUSR1\fR
+The SIGUSR1 signal will cause \fB winbindd\fR to write status information to the winbind
+log file including information about the number of user and
+group ids allocated by \fBwinbindd\fR.
+
+Log files are stored in the filename specified by the
+log file parameter.
+.SH "FILES"
+.TP
+\fB\fI/etc/nsswitch.conf(5)\fB\fR
+Name service switch configuration file.
+.TP
+\fB/tmp/.winbindd/pipe\fR
+The UNIX pipe over which clients communicate with
+the \fBwinbindd\fR program. For security reasons, the
+winbind client will only attempt to connect to the winbindd daemon
+if both the \fI/tmp/.winbindd\fR directory
+and \fI/tmp/.winbindd/pipe\fR file are owned by
+root.
+.TP
+\fB/lib/libnss_winbind.so.X\fR
+Implementation of name service switch library.
+.TP
+\fB$LOCKDIR/winbindd_idmap.tdb\fR
+Storage for the Windows NT rid to UNIX user/group
+id mapping. The lock directory is specified when Samba is initially
+compiled using the \fI--with-lockdir\fR option.
+This directory is by default \fI/usr/local/samba/var/locks
+\fR\&.
+.TP
+\fB$LOCKDIR/winbindd_cache.tdb\fR
+Storage for cached user and group information.
+.SH "VERSION"
+.PP
+This man page is correct for version 2.2 of
+the Samba suite.
+.SH "SEE ALSO"
+.PP
+\fInsswitch.conf(5)\fR,
+samba(7),
+wbinfo(1),
+smb.conf(5)
+.SH "AUTHOR"
+.PP
+The original Samba software and related utilities
+were created by Andrew Tridgell. Samba is now developed
+by the Samba Team as an Open Source project similar
+to the way the Linux kernel is developed.
+.PP
+\fBwbinfo\fR and \fBwinbindd\fR
+were written by Tim Potter.
+.PP
+The conversion to DocBook for Samba 2.2 was done
+by Gerald Carter
diff --git a/docs/samba.lsm b/docs/samba.lsm
deleted file mode 100644
index 503ba1ec94b..00000000000
--- a/docs/samba.lsm
+++ /dev/null
@@ -1,26 +0,0 @@
-Begin2
-Title = Samba
-Version = 1.8.0
-Desc1 = Samba is a SMB based file and print server for unix. It
-Desc2 = provides access to unix file and print services from
-Desc3 = SMB compatible clients such as WinNT, WfWg, OS/2
-Desc4 = and Pathworks. It also includes a ftp-style unix client
-Desc5 = and a netbios nameserver.
-Author = Andrew Tridgell
-AuthorEmail = samba-bugs@anu.edu.au
-Maintainer = Andrew Tridgell
-MaintEmail = samba-bugs@anu.edu.au
-Site1 = nimbus.anu.edu.au
-Path1 = pub/tridge/samba/
-File1 = samba-latest.tar.gz
-FileSize1 = 200K
-Required1 = Ansi-C compiler and a TCP/IP network.
-CopyPolicy1 = GNU Public License
-Keywords = LanManager, SMB, Networking
-Comment1 = To join the Samba mailing list send mail to
-Comment2 = listproc@listproc.anu.edu.au with a body of
-Comment3 = "subscribe samba Your Name"
-Entered = October 1994
-EnteredBy = Andrew Tridgell
-End
-
diff --git a/docs/textdocs/ADS-HOWTO.txt b/docs/textdocs/ADS-HOWTO.txt
new file mode 100644
index 00000000000..7a066c69ecf
--- /dev/null
+++ b/docs/textdocs/ADS-HOWTO.txt
@@ -0,0 +1,142 @@
+Samba 3.0 prealpha guide to Kerberos authentication
+---------------------------------------------------
+
+Andrew Tridgell
+tridge@samba.org
+
+This is a VERY ROUGH guide to setting up the current (November 2001)
+pre-alpha version of Samba 3.0 with kerberos authentication against a
+Windows2000 KDC. The procedures listed here are likely to change as
+the code develops.
+
+Pieces you need before you begin:
+
+- a Windows 2000 server
+- the latest CVS source code for Samba. See http://cvs.samba.org/ for how to
+ fetch this.
+- the MIT kerberos development libraries (either install from the
+ above sources or use a package). Under debian you need "libkrb5-dev"
+ and "krb5-user". The heimdal libraries will not work.
+- the OpenLDAP development libraries.
+
+On RedHat this means you should have at least:
+
+krb5-workstation (for kinit)
+krb5-libs (for linking with)
+krb5-devel (because you are compiling from source)
+
+in addition to the standard development environment.
+
+Note that these are not standard on a RedHat install, and you may need
+to get them off CD2.
+
+Also check that you have the latest copy of this HOWTO. It is
+available from http://samba.org/ftp/tridge/kerberos/HOWTO
+
+Step 1: Compile Samba
+
+ If your kerberos libraries are in a non-standard location then
+ remember to add the configure option --with-krb5=DIR.
+
+ After you run configure make sure that include/config.h contains
+ lines like this:
+
+ #define HAVE_KRB5 1
+ #define HAVE_LDAP 1
+
+ If it doesn't then configure did not find your krb5 libraries or
+ your ldap libraries. Look in config.log to figure out why and fix
+ it.
+
+ Then compile and install Samba as usual. You must use at least the
+ following 3 options in smb.conf:
+
+ realm = YOUR.KERBEROS.REALM
+ ads server = your.kerberos.server
+ security = ADS
+ encrypt passwords = yes
+
+ Strictly speaking, you can omit the realm name and you can use an IP
+ address for the ads server. In that case Samba will auto-detect these.
+
+ You do *not* need a smbpasswd file, although it won't do any harm
+ and if you have one then Samba will be able to fall back to normal
+ password security for older clients. I expect that the above
+ required options will change soon when we get better active
+ directory integration.
+
+
+Step 2: Setup your /etc/krb5.conf
+
+ The minimal configuration for krb5.conf is:
+
+ [realms]
+ YOUR.KERBEROS.REALM = {
+ kdc = your.kerberos.server
+ }
+
+
+ Test your config by doing a "kinit USERNAME@REALM" and making sure that
+ your password is accepted by the Win2000 KDC.
+
+ NOTE: The realm must be uppercase.
+
+ You also must ensure that you can do a reverse DNS lookup on the IP
+ address of your KDC. Also, the name that this reverse lookup maps to
+ must either be the netbios name of the KDC (ie. the hostname with no
+ domain attached) or it can alternatively be the netbios name
+ followed by the realm.
+
+ The easiest way to ensure you get this right is to add a /etc/hosts
+ entry mapping the IP address of your KDC to its netbios name. If you
+ don't get this right then you will get a "local error" when you try
+ to join the realm.
+
+* If all you want is kerberos support in smbclient then you can skip
+* straight to step 5 now. Step 3 is only needed if you want kerberos
+* support in smbd.
+
+
+Step 3: Create the computer account
+
+ Do a "kinit" as a user that has authority to change arbitrary
+ passwords on the KDC ("Administrator" is a good choice). Then as a
+ user that has write permission on the Samba private directory
+ (usually root) run:
+
+ net ads join
+
+ Possible errors:
+ - "bash: kinit: command not found":
+ - kinit is in the krb5-workstation RPM on RedHat systems, and is
+ in /usr/kerberos/bin, so it won't be in the path until
+ you log in again (or open a new terminal)
+ - "ADS support not compiled in"
+ - Samba must be reconfigured (remove config.cache) and
+ recompiled (make clean all install) after the kerberos libs
+ and headers are installed.
+
+
+Step 4: Test your server setup
+
+ On a Windows 2000 client try "net use * \\server\share". You should
+ be logged in with kerberos without needing to know a password. If
+ this fails then run "klist tickets". Did you get a ticket for the
+ server? Does it have an encoding type of DES-CBC-MD5 ?
+
+Step 5: Testing with smbclient
+
+ On your Samba server try to login to a Win2000 server or your Samba
+ server using smbclient and kerberos. Use smbclient as usual, but
+ specify the -k option to choose kerberos authentication.
+
+
+--------
+
+NOTES:
+ - must change administrator password at least once after DC install,
+ to create the right encoding types
+
+ - w2k doesn't seem to create the _kerberos._udp and _ldap._tcp in
+ their defaults DNS setup. Maybe fixed in service packs?
+
diff --git a/docs/textdocs/Application_Serving.txt b/docs/textdocs/Application_Serving.txt
new file mode 100644
index 00000000000..6a61a99d7e0
--- /dev/null
+++ b/docs/textdocs/Application_Serving.txt
@@ -0,0 +1,56 @@
+Contributed: January 7, 1997
+Updated: March 24, 1998
+Contributor: John H Terpstra <samba@samba.org>
+ Copyright (C) 1997 - John H Terpstra
+Status: Current
+
+Subject: Using a Samba share as an administrative share for MS Office, etc.
+==============================================================================
+
+Problem:
+========
+Microsoft Office products can be installed as an administrative installation
+from which the application can either be run off the administratively installed
+product that resides on a shared resource, or from which that product can be
+installed onto workstation clients.
+
+The general mechanism for implementing an adminstrative installation involves
+running:
+ X:\setup /A, where X is the drive letter of either CDROM or floppy
+
+This installation process will NOT install the product for use per se, but
+rather results in unpacking of the compressed distribution files into a target
+shared folder. For this process you need write privilidge to the share and it
+is desirable to enable file locking and share mode operation during this
+process.
+
+Subsequent installation of MS Office from this share will FAIL unless certain
+precautions are taken. This failure will be caused by share mode operation
+which will prevent the MS Office installation process from re-opening various
+dynamic link library files and will cause sporadic file not found problems.
+
+Solution:
+=========
+1. As soon as the administrative installation (unpacking) has completed
+ set the following parameters on the share containing it:
+ [MSOP95]
+ path = /where_you_put_it
+ comment = Your comment
+ volume = "The_CD_ROM_Label"
+ read only = yes
+ available = yes
+ share modes = no
+ locking = no
+ browseable = yes
+ public = yes
+
+2. Now you are ready to run the setup program from the Microsoft Windows
+workstation as follows:-
+ \\"Server_Name"\MSOP95\msoffice\setup
+
+MS Office Sharing - Please note:
+================================
+
+Workgroup Templates should be stored on an ordinary writable or read-only share
+but USER templates MUST be stored on a writable share _OR_ on the users' local
+machine.
diff --git a/docs/textdocs/BROWSING-Config.txt b/docs/textdocs/BROWSING-Config.txt
new file mode 100644
index 00000000000..ba0f399f48d
--- /dev/null
+++ b/docs/textdocs/BROWSING-Config.txt
@@ -0,0 +1,215 @@
+Date: July 5, 1998
+Contributor: John H Terpstra <jht@samba.org>
+
+Subject: Cross Subnet Browsing / Cross Workgroup Browsing
+===============================================================================
+
+OVERVIEW:
+=========
+
+This document should be read in conjunction with BROWSING.txt and may
+be taken as the fast track guide to implementing browsing across subnets
+and / or across workgroups (or domains). WINS is the best tool for resolution
+of NetBIOS names to IP addesses. WINS is NOT involved in browse list handling
+except by way of name to address mapping.
+
+
+DISCUSSION:
+===========
+
+Firstly, all MS Windows networking is based on SMB (Server Message
+Block) based messaging. SMB messaging is implemented using NetBIOS. Samba
+implements NetBIOS by encapsulating it over TCP/IP. MS Windows products can
+do likewise. NetBIOS based networking uses broadcast messaging to affect
+browse list management. When running NetBIOS over TCP/IP this uses UDP
+based messaging. UDP messages can be broadcast or unicast.
+
+Normally, only unicast UDP messaging can be forwarded by routers. The
+"remote announce" parameter to smb.conf helps to project browse announcements
+to remote network segments via unicast UDP. Similarly, the "remote browse sync"
+parameter of smb.conf implements browse list collation using unicast UDP.
+
+Secondly, in those networks where Samba is the only SMB server technology
+wherever possible nmbd should be configured on one (1) machine as the WINS
+server. This makes it easy to manage the browsing environment. If each network
+segment is configured with it's own Samba WINS server, then the only way to
+get cross segment browsing to work is by using the "remote announce" and
+the "remote browse sync" parameters to your smb.conf file.
+
+If only one WINS server is used then the use of the "remote announce" and the
+"remote browse sync" parameters should NOT be necessary.
+
+Samba WINS does not support MS-WINS replication. This means that when setting up
+Samba as a WINS server there must only be one nmbd configured as a WINS server
+on the network. Some sites have used multiple Samba WINS servers for redundancy
+(one server per subnet) and then used "remote browse sync" and "remote announce"
+to affect browse list collation across all segments. Note that this means
+clients will only resolve local names, and must be configured to use DNS to
+resolve names on other subnets in order to resolve the IP addresses of the
+servers they can see on other subnets. This setup is not recommended, but is
+mentioned as a practical consideration (ie: an 'if all else fails' scenario).
+
+Lastly, take note that browse lists are a collection of unreliable broadcast
+messages that are repeated at intervals of not more than 15 minutes. This means
+that it will take time to establish a browse list and it can take up to 45
+minutes to stabilise, particularly across network segments.
+
+
+A) Use of the "Remote Announce" parameter
+------------------------------------------
+The "remote announce" parameter of smb.conf can be used to forcibly ensure
+that all the NetBIOS names on a network get announced to a remote network.
+The syntax of the "remote announce" parameter is:
+
+ remote announce = a.b.c.d [e.f.g.h] ...
+_or_
+ remote announce = a.b.c.d/WORKGROUP [e.f.g.h/WORKGROUP] ...
+
+where:
+ a.b.c.d: is either the LMB (Local Master Browser) IP address
+ e.f.g.h: or the broadcst address of the remote network.
+ ie: the LMB is at 192.168.1.10, or the address
+ could be given as 192.168.1.255 where the netmask
+ is assumed to be 24 bits (255.255.255.0).
+ When the remote announcement is made to the broadcast
+ address of the remote network every host will receive
+ our announcements. This is noisy and therefore
+ undesirable but may be necessary if we do NOT know
+ the IP address of the remote LMB.
+
+ WORKGROUP: is optional and can be either our own workgroup
+ or that of the remote network. If you use the
+ workgroup name of the remote network then our
+ NetBIOS machine names will end up looking like
+ they belong to that workgroup, this may cause
+ name resolution problems and should be avoided.
+
+
+B) Use of the "Remote Browse Sync" parameter
+--------------------------------------------
+
+The "remote browse sync" parameter of smb.conf is used to announce to
+another LMB that it must synchronise it's NetBIOS name list with our
+Samba LMB. It works ONLY if the Samba server that has this option is
+simultaneously the LMB on it's network segment.
+
+The syntax of the "remote browse sync" parameter is:
+
+ remote browse sync = a.b.c.d
+
+where:
+ a.b.c.d: is either the IP address of the remote LMB or else
+ is the network broadcast address of the remote segment.
+
+
+C) Use of WINS
+--------------
+
+Use of WINS (either Samba WINS _or_ MS Windows NT Server WINS) is highly
+recommended. Every NetBIOS machine registers it's name together with a
+name_type value for each of of several types of service it has available.
+eg: It registers it's name directly as a unique (the type 0x03) name.
+It also registers it's name if it is running the lanmanager compatible
+server service (used to make shares and printers available to other users)
+by registering the server (the type 0x20) name.
+
+All NetBIOS names are up to 15 characters in length. The name_type variable
+is added to the end of the name - thus creating a 16 character name. Any
+name that is shorter than 15 characters is padded with spaces to the 15th
+character. ie: All NetBIOS names are 16 characters long (including the
+name_type information).
+
+WINS can store these 16 character names as they get registered. A client
+that wants to log onto the network can ask the WINS server for a list
+of all names that have registered the NetLogon service name_type. This saves
+broadcast traffic and greatly expedites logon processing. Since broadcast
+name resolution can not be used across network segments this type of
+information can only be provided via WINS _or_ via statically configured
+"lmhosts" files that must reside on all clients in the absence of WINS.
+
+WINS also serves the purpose of forcing browse list synchronisation by all
+LMB's. LMB's must synchronise their browse list with the DMB (domain master
+browser) and WINS helps the LMB to identify it's DMB. By definition this
+will work only within a single workgroup. Note that the domain master browser
+has NOTHING to do with what is referred to as an MS Windows NT Domain. The
+later is a reference to a security environment while the DMB refers to the
+master controller for browse list information only.
+
+Use of WINS will work correctly only if EVERY client TCP/IP protocol stack
+has been configured to use the WINS server/s. Any client that has not been
+configured to use the WINS server will continue to use only broadcast based
+name registration so that WINS may NEVER get to know about it. In any case,
+machines that have not registered with a WINS server will fail name to address
+lookup attempts by other clients and will therefore cause workstation access
+errors.
+
+To configure Samba as a WINS server just add "wins support = yes" to the
+smb.conf file [globals] section.
+
+To configure Samba to register with a WINS server just add
+"wins server = a.b.c.d" to your smb.conf file [globals] section.
+
+DO NOT EVER use both "wins support = yes" together with "wins server = a.b.c.d"
+particularly not using it's own IP address.
+
+
+D) Do NOT use more than one (1) protocol on MS Windows machines
+---------------------------------------------------------------
+
+A very common cause of browsing problems results from installing more than
+one protocol on an MS Windows machine.
+
+Every NetBIOS machine take part in a process of electing the LMB (and DMB)
+every 15 minutes. A set of election criteria is used to determine the order
+of precidence for winning this election process. A machine running Samba or
+Windows NT will be biased so that the most suitable machine will predictably
+win and thus retain it's role.
+
+The election process is "fought out" so to speak over every NetBIOS network
+interface. In the case of a Windows 9x machine that has both TCP/IP and IPX
+installed and has NetBIOS enabled over both protocols the election will be
+decided over both protocols. As often happens, if the Windows 9x machine is
+the only one with both protocols then the LMB may be won on the NetBIOS
+interface over the IPX protocol. Samba will then lose the LMB role as Windows
+9x will insist it knows who the LMB is. Samba will then cease to function
+as an LMB and thus browse list operation on all TCP/IP only machines will
+fail.
+
+The safest rule of all to follow it this - USE ONLY ONE PROTOCOL!
+
+
+E) Name Resolution Order
+========================
+
+Resolution of NetBIOS names to IP addresses can take place using a number
+of methods. The only ones that can provide NetBIOS name_type information
+are:
+ WINS: the best tool!
+ LMHOSTS: is static and hard to maintain.
+ Broadcast: uses UDP and can not resolve names across
+ remote segments.
+
+Alternative means of name resolution includes:
+ /etc/hosts: is static, hard to maintain, and lacks name_type info.
+ DNS: is a good choice but lacks essential name_type info.
+
+Many sites want to restrict DNS lookups and want to avoid broadcast name
+resolution traffic. The "name resolve order" parameter is of great help here.
+The syntax of the "name resolve order" parameter is:
+
+ name resolve order = wins lmhosts bcast host
+_or_
+ name resolve order = wins lmhosts (eliminates bcast and host)
+
+the default is:
+ name resolve order = host lmhost wins bcast
+
+where:
+ "host" refers the the native methods used by the Unix system
+ to implement the gethostbyname() function call. This is normally
+ controlled by:
+ /etc/host.conf
+ /etc/nsswitch.conf
+ /etc/resolv.conf
+
+===============================================================================
diff --git a/docs/textdocs/BROWSING.txt b/docs/textdocs/BROWSING.txt
index 8a09d2274fb..ad12d4c7220 100644
--- a/docs/textdocs/BROWSING.txt
+++ b/docs/textdocs/BROWSING.txt
@@ -1,60 +1,66 @@
-BROWSING
-========
-
-Samba now fully supports browsing. The browsing is supported by nmbd
-and is also controlled by options in the smb.conf file (see
-smb.conf(5)).
+Author/s: Many (Thanks to Luke, Jeremy, Andrew, etc.)
+Updated: July 5, 1998
+Status: Current - For VERY Advanced Users ONLY
-Samba can act as a browse master for a workgroup, but currently cannot
-act as a domain controller. The ability to be a domain controller will
-be added in a later version.
-
-To get browsing to work you need to run nmbd as usual, but will need
-to use the "workgroup" option in smb.conf to control what workgroup
-Samba becomes a part of.
+Summary: This describes how to configure Samba for improved browsing.
+=====================================================================
-The -G option is most useful for simple setups where Samba is browsable
-in only one workgroup. In more complex cases the lmhosts file is
-better.
+OVERVIEW:
+=========
+SMB networking provides a mechanism by which clients can access a list
+of machines that are available within the network. This list is called
+the browse list and is heavily used by all SMB clients. Configuration
+of SMB browsing has been problematic for some Samba users, hence this
+document.
-Be very careful setting up your lmhosts file. An incorrectly setup
-lmhosts file can have disasterous results for your net!
+Browsing will NOT work if name resolution from NetBIOS names to IP
+addresses does not function correctly. Use of a WINS server is highly
+recommended to aid the resolution of NetBIOS (SMB) names to IP addresses.
+WINS allows remote segment clients to obtain NetBIOS name_type information
+that can NOT be provided by any other means of name resolution.
-A simple lmhosts file might be:
+=====================================================================
-# This is a simple lmhosts file
-#
-# This is a host alias. Anyone querying this name
-# will get the specified IP
-192.0.2.17 SMBDATA
-#
-# first put ourselves in workgroup MYGROUP using
-# our own net address
-0.0.0.0 MYGROUP G
+BROWSING
+========
+Samba now fully supports browsing. The browsing is supported by nmbd
+and is also controlled by options in the smb.conf file (see smb.conf(5)).
+
+Samba can act as a local browse master for a workgroup and the ability
+for samba to support domain logons and scripts is now available. See
+DOMAIN.txt for more information on domain logons.
+
+Samba can also act as a domain master browser for a workgroup. This
+means that it will collate lists from local browse masters into a
+wide area network server list. In order for browse clients to
+resolve the names they may find in this list, it is recommended that
+both samba and your clients use a WINS server.
+
+Note that you should NOT set Samba to be the domain master for a
+workgroup that has the same name as an NT Domain: on each wide area
+network, you must only ever have one domain master browser per workgroup,
+regardless of whether it is NT, Samba or any other type of domain master
+that is providing this service.
+
+[Note that nmbd can be configured as a WINS server, but it is not
+necessary to specifically use samba as your WINS server. NTAS can
+be configured as your WINS server. In a mixed NT server and
+samba environment on a Wide Area Network, it is recommended that
+you use the NT server's WINS server capabilities. In a samba-only
+environment, it is recommended that you use one and only one nmbd
+as your WINS server].
-Note in the above that I overrode what workgroup Samba is in using the
-G flag. Also note that the 0.0.0.0 address is used, which will be
-automatically replaced with the broadcast address for groups, and with
-the local IP address for other entries.
+To get browsing to work you need to run nmbd as usual, but will need
+to use the "workgroup" option in smb.conf to control what workgroup
+Samba becomes a part of.
Samba also has a useful option for a Samba server to offer itself for
-browsing on another subnet.
-
-This works by the lmhosts file specifying a broadcast address on the
-other network to use to find a browse master for the workgroup.
-
-For example if you wanted yourself to appear in the workgroup STAFF on
-the network which has a broadcast of 192.0.3.255 then this entry would
-do the trick:
-
-# put ourselves in the STAFF workgroup on the other subnet
-192.0.3.255 STAFF G
-
-Notice the G at the end! It is very important you include this as this
-entry without the G could cause a broadcast storm!
+browsing on another subnet. It is recommended that this option is only
+used for 'unusual' purposes: announcements over the internet, for
+example. See "remote announce" in the smb.conf man page.
If something doesn't work then hopefully the log.nmb file will
-help you track down the problem. Try a debug level of 2 or 3 for
+help you track down the problem. Try a debug level of 2 or 3 for
finding problems.
Note that if it doesn't work for you, then you should still be able to
@@ -62,84 +68,487 @@ type the server name as \\SERVER in filemanager then hit enter and
filemanager should display the list of available shares.
Some people find browsing fails because they don't have the global
-"guest account" set to a valid account. Remember that the IPC$
+"guest account" set to a valid account. Remember that the IPC$
connection that lists the shares is done as guest, and thus you must
have a valid guest account.
Also, a lot of people are getting bitten by the problem of too many
-parameters on the command line of nmbd in inetd.conf. This trick is to
+parameters on the command line of nmbd in inetd.conf. This trick is to
not use spaces between the option and the parameter (eg: -d2 instead
-of -d 2), and to not use the -B and -N options. New versions of nmbd
+of -d 2), and to not use the -B and -N options. New versions of nmbd
are now far more likely to correctly find your broadcast and network
-addess, so in most cases these aren't needed.
+address, so in most cases these aren't needed.
The other big problem people have is that their broadcast address,
-netmask or IP address is wrong (specified with the -B, -N and -I
-options to nmbd).
+netmask or IP address is wrong (specified with the "interfaces" option
+in smb.conf)
+
+
+BROWSING ACROSS SUBNETS
+=======================
+
+With the release of Samba 1.9.17(alpha1 and above) Samba has been
+updated to enable it to support the replication of browse lists
+across subnet boundaries. New code and options have been added to
+achieve this. This section describes how to set this feature up
+in different settings.
+
+To see browse lists that span TCP/IP subnets (ie. networks separated
+by routers that don't pass broadcast traffic) you must set up at least
+one WINS server. The WINS server acts as a DNS for NetBIOS names, allowing
+NetBIOS name to IP address translation to be done by doing a direct
+query of the WINS server. This is done via a directed UDP packet on
+port 137 to the WINS server machine. The reason for a WINS server is
+that by default, all NetBIOS name to IP address translation is done
+by broadcasts from the querying machine. This means that machines
+on one subnet will not be able to resolve the names of machines on
+another subnet without using a WINS server.
+
+Remember, for browsing across subnets to work correctly, all machines,
+be they Windows 95, Windows NT, or Samba servers must have the IP address
+of a WINS server given to them by a DHCP server, or by manual configuration
+(for Win95 and WinNT, this is in the TCP/IP Properties, under Network
+settings) for Samba this is in the smb.conf file.
+
+How does cross subnet browsing work ?
+=====================================
+
+Cross subnet browsing is a complicated dance, containing multiple
+moving parts. It has taken Microsoft several years to get the code
+that achieves this correct, and Samba lags behind in some areas.
+However, with the 1.9.17 release, Samba is capable of cross subnet
+browsing when configured correctly.
+
+Consider a network set up as follows :
+
+ (DMB)
+ N1_A N1_B N1_C N1_D N1_E
+ | | | | |
+ -------------------------------------------------------
+ | subnet 1 |
+ +---+ +---+
+ |R1 | Router 1 Router 2 |R2 |
+ +---+ +---+
+ | |
+ | subnet 2 subnet 3 |
+ -------------------------- ------------------------------------
+ | | | | | | | |
+ N2_A N2_B N2_C N2_D N3_A N3_B N3_C N3_D
+ (WINS)
+
+Consisting of 3 subnets (1, 2, 3) conneted by two routers
+(R1, R2) - these do not pass broadcasts. Subnet 1 has 5 machines
+on it, subnet 2 has 4 machines, subnet 3 has 4 machines. Assume
+for the moment that all these machines are configured to be in the
+same workgroup (for simplicities sake). Machine N1_C on subnet 1
+is configured as Domain Master Browser (ie. it will collate the
+browse lists for the workgroup). Machine N2_D is configured as
+WINS server and all the other machines are configured to register
+their NetBIOS names with it.
+
+As all these machines are booted up, elections for master browsers
+will take place on each of the three subnets. Assume that machine
+N1_C wins on subnet 1, N2_B wins on subnet 2, and N3_D wins on
+subnet 3 - these machines are known as local master browsers for
+their particular subnet. N1_C has an advantage in winning as the
+local master browser on subnet 1 as it is set up as Domain Master
+Browser.
+
+On each of the three networks, machines that are configured to
+offer sharing services will broadcast that they are offering
+these services. The local master browser on each subnet will
+receive these broadcasts and keep a record of the fact that
+the machine is offering a service. This list of records is
+the basis of the browse list. For this case, assume that
+all the machines are configured to offer services so all machines
+will be on the browse list.
+
+For each network, the local master browser on that network is
+considered 'authoritative' for all the names it receives via
+local broadcast. This is because a machine seen by the local
+master browser via a local broadcast must be on the same
+network as the local master browser and thus is a 'trusted'
+and 'verifiable' resource. Machines on other networks that
+the local master browsers learn about when collating their
+browse lists have not been directly seen - these records are
+called 'non-authoritative'.
+
+At this point the browse lists look as follows (these are
+the machines you would see in your network neighborhood if
+you looked in it on a particular network right now).
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+
+Note that at this point all the subnets are separate, no
+machine is seen across any of the subnets.
+
+Now examine subnet 2. As soon as N2_B has become the local
+master browser it looks for a Domain master browser to synchronize
+its browse list with. It does this by querying the WINS server
+(N2_D) for the IP address associated with the NetBIOS name
+WORKGROUP<1B>. This name was registerd by the Domain master
+browser (N1_C) with the WINS server as soon as it was booted.
+
+Once N2_B knows the address of the Domain master browser it
+tells it that is the local master browser for subnet 2 by
+sending a MasterAnnouncement packet as a UDP port 138 packet.
+It then synchronizes with it by doing a NetServerEnum2 call. This
+tells the Domain Master Browser to send it all the server
+names it knows about. Once the domain master browser receives
+the MasterAnnouncement packet it schedules a synchronization
+request to the sender of that packet. After both synchronizations
+are done the browse lists look like :
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+
+Servers with a (*) after them are non-authoritative names.
+
+At this point users looking in their network neighborhood on
+subnets 1 or 2 will see all the servers on both, users on
+subnet 3 will still only see the servers on their own subnet.
+
+The same sequence of events that occured for N2_B now occurs
+for the local master browser on subnet 3 (N3_D). When it
+synchronizes browse lists with the domain master browser (N1_A)
+it gets both the server entries on subnet 1, and those on
+subnet 2. After N3_D has synchronized with N1_C and vica-versa
+the browse lists look like.
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*),
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*),
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Servers with a (*) after them are non-authoritative names.
+
+At this point users looking in their network neighborhood on
+subnets 1 or 3 will see all the servers on all sunbets, users on
+subnet 2 will still only see the servers on subnets 1 and 2, but not 3.
+
+Finally, the local master browser for subnet 2 (N2_B) will sync again
+with the domain master browser (N1_C) and will recieve the missing
+server entries. Finally - and as a steady state (if no machines
+are removed or shut off) the browse lists will look like :
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*),
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*),
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Servers with a (*) after them are non-authoritative names.
+
+Synchronizations between the domain master browser and local
+master browsers will continue to occur, but this should be a
+steady state situation.
+
+If either router R1 or R2 fails the following will occur:
+
+1) Names of computers on each side of the inaccessible network fragments
+will be maintained for as long as 36 minutes, in the network neighbourhood
+lists.
+
+2) Attempts to connect to these inaccessible computers will fail, but the
+names will not be removed from the network neighbourhood lists.
+
+3) If one of the fragments is cut off from the WINS server, it will only
+be able to access servers on its local subnet, by using subnet-isolated
+broadcast NetBIOS name resolution. The effects are similar to that of
+losing access to a DNS server.
+
+Setting up a WINS server
+========================
+
+Either a Samba machine or a Windows NT Server machine may be set up
+as a WINS server. To set a Samba machine to be a WINS server you must
+add the following option to the smb.conf file on the selected machine :
+in the [globals] section add the line
+
+ wins support = yes
+
+Versions of Samba previous to 1.9.17 had this parameter default to
+yes. If you have any older versions of Samba on your network it is
+strongly suggested you upgrade to 1.9.17 or above, or at the very
+least set the parameter to 'no' on all these machines.
+
+Machines with "wins support = yes" will keep a list of all NetBIOS
+names registered with them, acting as a DNS for NetBIOS names.
+
+You should set up only ONE wins server. Do NOT set the
+"wins support = yes" option on more than one Samba server.
+
+To set up a Windows NT Server as a WINS server you need to set up
+the WINS service - see your NT documentation for details. Note that
+Windows NT WINS Servers can replicate to each other, allowing more
+than one to be set up in a complex subnet environment. As Microsoft
+refuse to document these replication protocols Samba cannot currently
+participate in these replications. It is possible in the future that
+a Samba->Samba WINS replication protocol may be defined, in which
+case more than one Samba machine could be set up as a WINS server
+but currently only one Samba server should have the "wins support = yes"
+parameter set.
+
+After the WINS server has been configured you must ensure that all
+machines participating on the network are configured with the address
+of this WINS server. If your WINS server is a Samba machine, fill in
+the Samba machine IP address in the "Primary WINS Server" field of
+the "Control Panel->Network->Protocols->TCP->WINS Server" dialogs
+in Windows 95 or Windows NT. To tell a Samba server the IP address
+of the WINS server add the following line to the [global] section of
+all smb.conf files :
+
+ wins server = <name or IP address>
+
+where <name or IP address> is either the DNS name of the WINS server
+machine or its IP address.
+
+Note that this line MUST NOT BE SET in the smb.conf file of the Samba
+server acting as the WINS server itself. If you set both the
+"wins support = yes" option and the "wins server = <name>" option then
+nmbd will fail to start.
+
+There are two possible scenarios for setting up cross subnet browsing.
+The first details setting up cross subnet browsing on a network containing
+Windows 95, Samba and Windows NT machines that are not configured as
+part of a Windows NT Domain. The second details setting up cross subnet
+browsing on networks that contain NT Domains.
+
+Setting up Browsing in a WORKGROUP
+==================================
+
+To set up cross subnet browsing on a network containing machines
+in up to be in a WORKGROUP, not an NT Domain you need to set up one
+Samba server to be the Domain Master Browser (note that this is *NOT*
+the same as a Primary Domain Controller, although in an NT Domain the
+same machine plays both roles). The role of a Domain master browser is
+to collate the browse lists from local master browsers on all the
+subnets that have a machine participating in the workgroup. Without
+one machine configured as a domain master browser each subnet would
+be an isolated workgroup, unable to see any machines on any other
+subnet. It is the presense of a domain master browser that makes
+cross subnet browsing possible for a workgroup.
+
+In an WORKGROUP environment the domain master browser must be a
+Samba server, and there must only be one domain master browser per
+workgroup name. To set up a Samba server as a domain master browser,
+set the following option in the [global] section of the smb.conf file :
+
+ domain master = yes
+
+The domain master browser should also preferrably be the local master
+browser for its own subnet. In order to achieve this set the following
+options in the [global] section of the smb.conf file :
+
+ domain master = yes
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+The domain master browser may be the same machine as the WINS
+server, if you require.
+
+Next, you should ensure that each of the subnets contains a
+machine that can act as a local master browser for the
+workgroup. Any NT machine should be able to do this, as will
+Windows 95 machines (although these tend to get rebooted more
+often, so it's not such a good idea to use these). To make a
+Samba server a local master browser set the following
+options in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+Do not do this for more than one Samba server on each subnet,
+or they will war with each other over which is to be the local
+master browser.
+
+The "local master" parameter allows Samba to act as a local master
+browser. The "preferred master" causes nmbd to force a browser
+election on startup and the "os level" parameter sets Samba high
+enough so that it should win any browser elections.
+
+If you have an NT machine on the subnet that you wish to
+be the local master browser then you can disable Samba from
+becoming a local master browser by setting the following
+options in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = no
+ preferred master = no
+ os level = 0
+
+Setting up Browsing in a DOMAIN
+===============================
+
+If you are adding Samba servers to a Windows NT Domain then
+you must not set up a Samba server as a domain master browser.
+By default, a Windows NT Primary Domain Controller for a Domain
+name is also the Domain master browser for that name, and many
+things will break if a Samba server registers the Domain master
+browser NetBIOS name (DOMAIN<1B>) with WINS instead of the PDC.
+
+For subnets other than the one containing the Windows NT PDC
+you may set up Samba servers as local master browsers as
+described. To make a Samba server a local master browser set
+the following options in the [global] section of the smb.conf
+file :
+
+ domain master = no
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+If you wish to have a Samba server fight the election with machines
+on the same subnet you may set the "os level" parameter to lower
+levels. By doing this you can tune the order of machines that
+will become local master browsers if they are running. For
+more details on this see the section "FORCING SAMBA TO BE THE MASTER"
+below.
+
+If you have Windows NT machines that are members of the domain
+on all subnets, and you are sure they will always be running then
+you can disable Samba from taking part in browser elections and
+ever becoming a local master browser by setting following options
+in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = no
+ preferred master = no
+ os level = 0
FORCING SAMBA TO BE THE MASTER
==============================
Who becomes the "master browser" is determined by an election process
-using broadcasts. Each election packet contains a number of parameters
+using broadcasts. Each election packet contains a number of parameters
which determine what precedence (bias) a host should have in the
-election. By default Samba uses a very low precedence and thus loses
+election. By default Samba uses a very low precedence and thus loses
elections to just about anyone else.
If you want Samba to win elections then just set the "os level" global
-option in smb.conf to a higher number. It defaults to 0. Using 33
+option in smb.conf to a higher number. It defaults to 0. Using 34
would make it win all elections over every other system (except other
samba systems!)
-A "os level" of 2 would make it beat WfWg and Win95, but not NTAS. A
+A "os level" of 2 would make it beat WfWg and Win95, but not NTAS. A
NTAS domain controller uses level 32.
The maximum os level is 255
+If you want samba to force an election on startup, then set the
+"preferred master" global option in smb.conf to "yes". Samba will
+then have a slight advantage over other potential master browsers
+that are not preferred master browsers. Use this parameter with
+care, as if you have two hosts (whether they are windows 95 or NT or
+samba) on the same local subnet both set with "preferred master" to
+"yes", then periodically and continually they will force an election
+in order to become the local master browser.
+
+If you want samba to be a "domain master browser", then it is
+recommended that you also set "preferred master" to "yes", because
+samba will not become a domain master browser for the whole of your
+LAN or WAN if it is not also a local master browser on its own
+broadcast isolated subnet.
+
+It is possible to configure two samba servers to attempt to become
+the domain master browser for a domain. The first server that comes
+up will be the domain master browser. All other samba servers will
+attempt to become the domain master browser every 5 minutes. They
+will find that another samba server is already the domain master
+browser and will fail. This provides automatic redundancy, should
+the current domain master browser fail.
+
+
MAKING SAMBA THE DOMAIN MASTER
==============================
The domain master is responsible for collating the browse lists of
-multiple subnets so that browsing can occur between subnets. You can
+multiple subnets so that browsing can occur between subnets. You can
make samba act as the domain master by setting "domain master = yes"
-in smb.conf. By default it will not be a domain master.
+in smb.conf. By default it will not be a domain master.
+
+Note that you should NOT set Samba to be the domain master for a
+workgroup that has the same name as an NT Domain.
When samba is the domain master and the master browser it will listen
-for master announcements from other subnets and then contact them to
-synchronise browse lists.
+for master announcements (made roughly every twelve minutes) from local
+master browsers on other subnets and then contact them to synchronise
+browse lists.
If you want samba to be the domain master then I suggest you also set
-the "os level" high enough to make sure it wins elections.
+the "os level" high enough to make sure it wins elections, and set
+"preferred master" to "yes", to get samba to force an election on
+startup.
-NOTIFYING THE DOMAIN CONTROLLER
-===============================
+Note that all your servers (including samba) and clients should be
+using a WINS server to resolve NetBIOS names. If your clients are only
+using broadcasting to resolve NetBIOS names, then two things will occur:
-If you have a domain controller for the domain which Samba is a part
-of then you should add the line "domain controller = address" to
-smb.conf. "address" can either be a name available via DNS or a IP
-address or a broadcast address. If it is a broadcast address then
-Samba will look for a domain controller on that network.
+a) your local master browsers will be unable to find a domain master
+ browser, as it will only be looking on the local subnet.
-When Samba is the master browser it will regularly contact the domain
-controller to synchronise browse lists.
+b) if a client happens to get hold of a domain-wide browse list, and
+ a user attempts to access a host in that list, it will be unable to
+ resolve the NetBIOS name of that host.
+If, however, both samba and your clients are using a WINS server, then:
+
+a) your local master browsers will contact the WINS server and, as long as
+ samba has registered that it is a domain master browser with the WINS
+ server, your local master browser will receive samba's ip address
+ as its domain master browser.
+
+b) when a client receives a domain-wide browse list, and a user attempts
+ to access a host in that list, it will contact the WINS server to
+ resolve the NetBIOS name of that host. as long as that host has
+ registered its NetBIOS name with the same WINS server, the user will
+ be able to see that host.
NOTE ABOUT BROADCAST ADDRESSES
==============================
If your network uses a "0" based broadcast address (for example if it
-ends in a 0) then you will strike problems. Windows for Workgroups
+ends in a 0) then you will strike problems. Windows for Workgroups
does not seem to support a 0's broadcast and you will probably find
that browsing and name lookups won't work.
-You have a few options:
-
-1) change to a 1's broadcast on your unix server. These often end in
-.255 (check with your local network guru for details)
-2) set the nmbd broadcast to a 1's based address on the command line using
-the -B option. This only works if your network setup listens on both
-0s and 1s based broadcasts. The -B option can only control what
-address it sends to, not what it listens on.
+MULTIPLE INTERFACES
+===================
+Samba now supports machines with multiple network interfaces. If you
+have multiple interfaces then you will need to use the "interfaces"
+option in smb.conf to configure them. See smb.conf(5) for details.
diff --git a/docs/textdocs/BUGS.txt b/docs/textdocs/BUGS.txt
index e0fd6951477..247998c6c7a 100644
--- a/docs/textdocs/BUGS.txt
+++ b/docs/textdocs/BUGS.txt
@@ -1,31 +1,31 @@
-This file describes how to report Samba bugs.
+Contributor: Samba Team
+Updated: June 27, 1997
->> The email address for bug reports is samba-bugs@anu.edu.au <<
-
-(NOTE: This mail may not be in place yet. If you have troubles with it
-then use samba-bugs@arvidsjaur.anu.edu.au)
+Subject: This file describes how to report Samba bugs.
+============================================================================
+>> The email address for bug reports is samba@samba.org <<
Please take the time to read this file before you submit a bug
-report. Also, please see if it has changed between releases, as I
-may be changing the bug reporting mechanism sometime soon.
+report. Also, please see if it has changed between releases, as we
+may be changing the bug reporting mechanism at some time.
Please also do as much as you can yourself to help track down the
-bug. I only develop Samba in my spare time and I receive far more mail
-about it than I can possibly answer, so you have a much higher chance
-of an answer and a fix if you send me a "developer friendly" bug
-report that lets me fix it fast.
+bug. Samba is maintained by a dedicated group of people who volunteer
+their time, skills and efforts. We receive far more mail about it than
+we can possibly answer, so you have a much higher chance of an answer
+and a fix if you send us a "developer friendly" bug report that lets
+us fix it fast.
Do not assume that if you post the bug to the comp.protocols.smb
-newsgroup that I will read it. I do read all postings to the samba
-mailing list (see the README). If you suspect that your problem is not
-a bug but a configuration problem then it is better to send it to the
-Samba mailing list, as there are (at last count) 1900 other users on
+newsgroup or the mailing list that we will read it. If you suspect that your
+problem is not a bug but a configuration problem then it is better to send
+it to the Samba mailing list, as there are (at last count) 5000 other users on
that list that may be able to help you.
You may also like to look though the recent mailing list archives,
which are conveniently accessible on the Samba web pages
-at http://lake.canberra.edu.au/pub/samba/
+at http://samba.org/samba/
GENERAL INFO
@@ -36,6 +36,8 @@ errors. Look in your log files for obvious messages that tell you that
you've misconfigured something and run testparm to test your config
file for correct syntax.
+Have you run through DIAGNOSIS.txt? This is very important.
+
If you include part of a log file with your bug report then be sure to
annotate it with exactly what you were doing on the client at the
time, and exactly what the results were.
@@ -54,6 +56,7 @@ To set the debug level use "log level =" in your smb.conf. You may
also find it useful to set the log level higher for just one machine
and keep separate logs for each machine. To do this use:
+log level = 10
log file = /usr/local/samba/lib/log.%m
include = /usr/local/samba/lib/smb.conf.%m
@@ -63,6 +66,15 @@ put any smb.conf commands you want, for example "log level=" may be
useful. This also allows you to experiment with different security
systems, protocol levels etc on just one machine.
+The smb.conf entry "log level =" is synonymous with the entry
+"debuglevel =" that has been used in older versions of Samba and
+is being retained for backwards compatibility of smb.conf files.
+
+As the "log level =" value is increased you will record a significantly
+increasing level of debugging information. For most debugging operations
+you may not need a setting higher than 3. Nearly all bugs can be tracked
+at a setting of 10, but be prepared for a VERY large volume of log data.
+
INTERNAL ERRORs
---------------
@@ -115,7 +127,7 @@ where it occurred.
PATCHES
-------
-The best sort of bug report is one that includes a fix! If you send me
+The best sort of bug report is one that includes a fix! If you send us
patches please use "diff -u" format if your version of diff supports
it, otherwise use "diff -c4". Make sure your do the diff against a
clean version of the source and let me know exactly what version you
diff --git a/docs/textdocs/DHCP-Server-Configuration.txt b/docs/textdocs/DHCP-Server-Configuration.txt
new file mode 100644
index 00000000000..499706955fb
--- /dev/null
+++ b/docs/textdocs/DHCP-Server-Configuration.txt
@@ -0,0 +1,240 @@
+Subject: DHCP Server Configuration for SMB Clients
+Date: March 1, 1998
+Updated: May 15, 2001
+Contributor: John H Terpstra <jht@samba.org>
+Support: This is an unsupported document. Refer to documentation that is
+ supplied with the ISC DHCP Server. Do NOT email the contributor
+ for ANY assistance.
+===============================================================================
+
+Background:
+===========
+
+We wish to help those folks who wish to use the ISC DHCP Server and provide
+sample configuration settings. Most operating systems today come ship with
+the ISC DHCP Server. ISC DHCP is available from:
+ ftp://ftp.isc.org/isc/dhcp
+
+Incorrect configuration of MS Windows clients (Windows9X, Windows ME, Windows
+NT/2000) will lead to problems with browsing and with general network
+operation. Windows 9X/ME users often report problems where the TCP/IP and related
+network settings will inadvertantly become reset at machine start-up resulting
+in loss of configuration settings. This results in increased maintenance
+overheads as well as serious user frustration.
+
+In recent times users on one mailing list incorrectly attributed the cause of
+network operating problems to incorrect configuration of Samba.
+
+One user insisted that the only way to provent Windows95 from periodically
+performing a full system reset and hardware detection process on start-up was
+to install the NetBEUI protocol in addition to TCP/IP. This assertion is not
+correct.
+
+In the first place, there is NO need for NetBEUI. All Microsoft Windows clients
+natively run NetBIOS over TCP/IP, and that is the only protocol that is
+recognised by Samba. Installation of NetBEUI and/or NetBIOS over IPX will
+cause problems with browse list operation on most networks. Even Windows NT
+networks experience these problems when incorrectly configured Windows95
+systems share the same name space. It is important that only those protocols
+that are strictly needed for site specific reasons should EVER be installed.
+
+Secondly, and totally against common opinion, DHCP is NOT an evil design but is
+an extension of the BOOTP protocol that has been in use in Unix environments
+for many years without any of the melt-down problems that some sensationalists
+would have us believe can be experienced with DHCP. In fact, DHCP in covered by
+rfc1541 and is a very safe method of keeping an MS Windows desktop environment
+under control and for ensuring stable network operation.
+
+Please note that MS Windows systems as of MS Windows NT 3.1 and MS Windows 95
+store all network configuration settings a registry. There are a few reports
+from MS Windows network administrators that warrant mention here. It would appear
+that when one sets certain MS TCP/IP protocol settings (either directly or via
+DHCP) that these do get written to the registry. Even though a subsequent
+change of setting may occur the old value may persist in the registry. This
+has been known to create serious networking problems.
+
+An example of this occurs when a manual TCP/IP environment is configured to
+include a NetBIOS Scope. In this event, when the administrator then changes the
+configuration of the MS TCP/IP protocol stack, without first deleting the
+current settings, by simply checking the box to configure the MS TCP/IP stack
+via DHCP then the NetBIOS Scope that is still persistent in the registry WILL be
+applied to the resulting DHCP offered settings UNLESS the DHCP server also sets
+a NetBIOS Scope. It may therefore be prudent to forcibly apply a NULL NetBIOS
+Scope from your DHCP server. The can be done in the dhcpd.conf file with the
+parameter:
+ option netbios-scope "";
+
+While it is true that the Microsoft DHCP server that comes with Windows NT
+Server provides only a sub-set of rfc1533 functionality this is hardly an issue
+in those sites that already have a large investment and commitment to Unix
+systems and technologies. The current state of the art of the DHCP Server
+specification in covered in rfc2132.
+
+This document aims to provide enough background information so that the
+majority of site can without too much hardship get the Internet Software
+Consortium's (ISC) DHCP Server into operation. The key benefits of using DHCP
+includes:
+
+1) Automated IP Address space management and maximised re-use of available IP
+Addresses,
+
+2) Automated control of MS Windows client TCP/IP network configuration,
+
+3) Automatic recovery from start-up and run-time problems with Windows95.
+
+
+
+Client Configuration for SMB Networking:
+========================================
+SMB network clients need to be configured so that all standard TCP/IP name to
+address resolution works correctly. Once this has been achieved the SMB
+environment provides additional tools and services that act as helper agents in
+the translation of SMB (NetBIOS) names to their appropriate IP Addresses. One
+such helper agent is the NetBIOS Name Server (NBNS) or as Microsoft called it
+in their Windows NT Server implementation WINS (Windows Internet Name Server).
+
+A client needs to be configured so that it has a unique Machine (Computer)
+Name.
+
+This can be done, but needs a few NT registry hacks and you need to be able to
+speak UNICODE, which is of course no problem for a True Wizzard(tm) :)
+Instructions on how to do this (including a small util for less capable
+Wizzards) can be found at
+
+ http://www.unixtools.org/~nneul/sw/nt/dhcp-netbios-hostname.html
+
+
+All remaining TCP/IP networking parameters can be assigned via DHCP. These include:
+
+a) IP Address,
+b) Netmask,
+c) Gateway (Router) Address,
+d) DNS Domain Name,
+e) DNS Server addresses,
+f) WINS (NBNS) Server addresses,
+g) IP Forwarding,
+h) Timezone offset,
+i) Node Type,
+j) NetBIOS Scope
+
+Other assignments can be made from a DHCP server too, but the above cover the
+major needs.
+
+Note: IF ever an entry has has been made to the NetBIOS Scope field of the
+TCP/IP configuration panel on an MS Windows machine, and it has then been
+committed, then that setting may become persistent. In such a c ase it is better
+to configure the DHCP server with a NetBIOS Scope consisting of an empty string
+(ie: A NULL scope).
+
+
+DHCP Server Installation:
+=========================
+It is assumed that you will have obtained a copy of the GPL'd ISC DHCP server
+source files from ftp://ftp.isc.org/isc/dhcp, it is also assumed that you have
+compiled the sources and have installed the binary files.
+
+The following simply serves to provide sample configuration files to enable
+dhcpd to operate. The sample files assume that your site is configured to use
+private IP network address space using the Class B range of 172.16.1.0 -
+172.16.1.255 and is using a netmask of 255.255.255.0 (ie:24 bits). It is
+assumed that your router to the outside world is at 172.16.1.254 and that your
+Internet Domain Name is bestnet.com.au. The IP Address range 172.16.1.100 to
+172.16.1.240 has been set aside as your dynamically allocated range. In
+addition, bestnet.com.au have two print servers that need to obtain settings
+via BOOTP. The machine linux.bestnet.com.au has IP address 172.16.1.1 and is
+you primary Samba server with WINS support enabled by adding the parameter to
+the /etc/smb.conf file: [globals] wins support = yes. The dhcp lease time will
+be set to 20 hours.
+
+Configuration Files:
+====================
+Before dhcpd will run you need to install a file that speifies the
+configuration settings, and another that holds the database of issued IP
+addresses. On many systems these are stored in the /etc directory on the Unix
+system.
+
+Example /etc/dhcpd.conf:
+========================
+server-identifier linux.bestnet.com.au;
+
+subnet 172.16.1.0 netmask 255.255.255.0 {
+ range 172.16.1.100 172.16.1.240;
+ default-lease-time 72000;
+ max-lease-time 144000;
+ option subnet-mask 255.255.255.0;
+ option broadcast-address 172.16.1.255;
+ option routers 172.16.1.254;
+ option domain-name-servers 172.16.1.1, 172.16.1.2;
+ option domain-name "bestnet.com.au";
+ option time-offset 39600;
+ option ip-forwarding off;
+ option netbios-name-servers 172.16.0.1, 172.16.0.1;
+ option netbios-dd-server 172.16.0.1;
+ option netbios-node-type 8;
+ option netbios-scope "";
+}
+
+; Note: The above netbios-scope is purposely an empty (NULL) string.
+
+group {
+ next-server 172.16.1.10;
+ option subnet-mask 255.255.255.0;
+ option domain-name "bestnet.com.au";
+ option domain-name-servers 172.16.1.1, 172.16.0.2;
+ option netbios-name-servers 172.16.0.1, 172.16.0.1;
+ option netbios-dd-server 172.16.0.1;
+ option netbios-node-type 8;
+ option netbios-scope "SomeCrazyScope";
+ option routers 172.16.1.240;
+ option time-offset 39600;
+ host lexmark1 {
+ hardware ethernet 06:07:08:09:0a:0b;
+ fixed-address 172.16.1.245;
+ }
+ host epson4 {
+ hardware ethernet 01:02:03:04:05:06;
+ fixed-address 172.16.1.242;
+ }
+}
+
+
+Creating the /etc/dhcpd.leases file:
+====================================
+At a Unix shell create an empty dhcpd.leases file in the /etc directory.
+You can do this by typing: cp /dev/null /etc/dhcpd.leases
+
+
+Setting up a route table for all-ones addresses:
+================================================
+Quoting from the README file that comes with the ISC DHCPD Server:
+
+ BROADCAST
+
+In order for dhcpd to work correctly with picky DHCP clients (e.g.,
+Windows 95), it must be able to send packets with an IP destination
+address of 255.255.255.255. Unfortunately, Linux insists on changing
+255.255.255.255 into the local subnet broadcast address (here, that's
+192.5.5.223). This results in a DHCP protocol violation, and while
+many DHCP clients don't notice the problem, some (e.g., all Microsoft
+DHCP clients) do. Clients that have this problem will appear not to
+see DHCPOFFER messages from the server.
+
+It is possible to work around this problem on some versions of Linux
+by creating a host route from your network interface address to
+255.255.255.255. The command you need to use to do this on Linux
+varies from version to version. The easiest version is:
+
+ route add -host 255.255.255.255 dev eth0
+
+On some older Linux systems, you will get an error if you try to do
+this. On those systems, try adding the following entry to your
+/etc/hosts file:
+
+255.255.255.255 all-ones
+
+Then, try:
+
+ route add -host all-ones dev eth0
+
+
+For more information please refer to the ISC DHCPD Server documentation.
diff --git a/docs/textdocs/DIAGNOSIS.txt b/docs/textdocs/DIAGNOSIS.txt
index 6681bdc4bcb..2816610a9cb 100644
--- a/docs/textdocs/DIAGNOSIS.txt
+++ b/docs/textdocs/DIAGNOSIS.txt
@@ -1,5 +1,8 @@
-DIAGNOSING YOUR SAMBA SERVER
-============================
+Contributor: Andrew Tridgell
+Updated: November 1, 1999
+
+Subject: DIAGNOSING YOUR SAMBA SERVER
+===========================================================================
This file contains a list of tests you can perform to validate your
Samba server. It also tells you what the likely cause of the problem
@@ -10,9 +13,6 @@ You should do ALL the tests, in the order shown. I have tried to
carefully choose them so later tests only use capabilities verified in
the earlier tests.
-I would welcome additions to this set of tests. Please mail them to
-samba-bugs@anu.edu.au
-
If you send me an email saying "it doesn't work" and you have not
followed this test procedure then you should not be surprised if I
ignore your email.
@@ -22,11 +22,14 @@ ASSUMPTIONS
-----------
In all of the tests I assume you have a Samba server called BIGSERVER
-and a PC called ACLIENT. I also assume the PC is running windows for
-workgroups with a recent copy of the microsoft tcp/ip stack. The
-procedure is similar for other types of clients.
+and a PC called ACLIENT both in workgroup TESTGROUP. I also assume the
+PC is running windows for workgroups with a recent copy of the
+microsoft tcp/ip stack. Alternatively, your PC may be running Windows
+95 or Windows NT (Workstation or Server).
+
+The procedure is similar for other types of clients.
-I also assume you know the name of a available share in your
+I also assume you know the name of an available share in your
smb.conf. I will assume this share is called "tmp". You can add a
"tmp" share like by adding the following to smb.conf:
@@ -36,15 +39,28 @@ smb.conf. I will assume this share is called "tmp". You can add a
read only = yes
-THESE TESTS ASSUME VERSION 1.9.15 OR LATER OF THE SAMBA SUITE. SOME
+THESE TESTS ASSUME VERSION 2.0.6 OR LATER OF THE SAMBA SUITE. SOME
COMMANDS SHOWN DID NOT EXIST IN EARLIER VERSIONS
+Please pay attention to the error messages you receive. If any error message
+reports that your server is being unfriendly you should first check that you
+IP name resolution is correctly set up. eg: Make sure your /etc/resolv.conf
+file points to name servers that really do exist.
+
+Also, if you do not have DNS server access for name resolution please check
+that the settings for your smb.conf file results in "dns proxy = no". The
+best way to check this is with "testparm smb.conf"
+
TEST 1:
-------
-run the command "testparm". If it reports any errors then your
-smb.conf configuration file is faulty.
+In the directory in which you store your smb.conf file, run the command
+"testparm smb.conf". If it reports any errors then your smb.conf
+configuration file is faulty.
+
+Note: Your smb.conf file may be located in: /etc
+ Or in: /usr/local/samba/lib
TEST 2:
@@ -60,13 +76,18 @@ run ping.
If you get a message saying "host not found" or similar then your DNS
software or /etc/hosts file is not correctly setup. It is possible to
run samba without DNS entries for the server and client, but I assume
-you do have correct entries for the remainder of these tests.
+you do have correct entries for the remainder of these tests.
+
+Another reason why ping might fail is if your host is running firewall
+software. You will need to relax the rules to let in the workstation
+in question, perhaps by allowing access from another subnet (on Linux
+this is done via the ipfwadm program.)
TEST 3:
-------
-run the command "smbclient -L BIGSERVER -U%" on the unix box. You
+Run the command "smbclient -L BIGSERVER" on the unix box. You
should get a list of available shares back.
If you get a error message containing the string "Bad password" then
@@ -76,26 +97,57 @@ valid. Check what your guest account is using "testparm" and
temporarily remove any "hosts allow", "hosts deny", "valid users" or
"invalid users" lines.
-If you get a "connection refused" response then the smbd server could
-not be run. If you installed it in inetd.conf then you probably edited
+If you get a "connection refused" response then the smbd server may
+not be running. If you installed it in inetd.conf then you probably edited
that file incorrectly. If you installed it as a daemon then check that
it is running, and check that the netbios-ssn port is in a LISTEN
state using "netstat -a".
If you get a "session request failed" then the server refused the
-connection. If it says "your server software is being unfriendly" then
+connection. If it says "Your server software is being unfriendly" then
its probably because you have invalid command line parameters to smbd,
or a similar fatal problem with the initial startup of smbd. Also
-check your config file for syntax errors with "testparm".
+check your config file (smb.conf) for syntax errors with "testparm"
+and that the various directories where samba keeps its log and lock
+files exist.
+
+There are a number of reasons for which smbd may refuse or decline
+a session request. The most common of these involve one or more of
+the following smb.conf file entries:
+ hosts deny = ALL
+ hosts allow = xxx.xxx.xxx.xxx/yy
+ bind interfaces only = Yes
+
+In the above, no allowance has been made for any session requests that
+will automatically translate to the loopback adaptor address 127.0.0.1.
+To solve this problem change these lines to:
+ hosts deny = ALL
+ hosts allow = xxx.xxx.xxx.xxx/yy 127.
+Do NOT use the "bind interfaces only" parameter where you may wish to
+use the samba password change facility, or where smbclient may need to
+access local service for name resolution or for local resource
+connections. (Note: the "bind interfaces only" parameter deficiency
+where it will not allow connections to the loopback address will be
+fixed soon).
+
+Another common cause of these two errors is having something already running
+on port 139, such as Samba (ie: smbd is running from inetd already) or
+something like Digital's Pathworks. Check your inetd.conf file before trying
+to start smbd as a daemon, it can avoid a lot of frustration!
+
+And yet another possible cause for failure of TEST 3 is when the subnet mask
+and / or broadcast address settings are incorrect. Please check that the
+network interface IP Address / Broadcast Address / Subnet Mask settings are
+correct and that Samba has correctly noted these in the log.nmb file.
TEST 4:
-------
-run the command "nmblookup -B BIGSERVER __SAMBA__". You should get the
+Run the command "nmblookup -B BIGSERVER __SAMBA__". You should get the
IP address of your Samba server back.
If you don't then nmbd is incorrectly installed. Check your inetd.conf
-if yu run it from there, or that the daemon is running and listening
+if you run it from there, or that the daemon is running and listening
to udp port 137.
One common problem is that many inetd implementations can't take many
@@ -103,6 +155,7 @@ parameters on the command line. If this is the case then create a
one-line script that contains the right parameters and run that from
inetd.
+
TEST 5:
-------
@@ -110,14 +163,16 @@ run the command "nmblookup -B ACLIENT '*'"
You should get the PCs IP address back. If you don't then the client
software on the PC isn't installed correctly, or isn't started, or you
-got the name of the PC wrong. Note that you probably won't get a "node
-status response" from the PC due to a bug in the microsoft netbios
-nameserver implementation (it responds to the wrong port number).
+got the name of the PC wrong.
+
+If ACLIENT doesn't resolve via DNS then use the IP address of the
+client in the above test.
+
TEST 6:
-------
-run the command "nmblookup -d 2 '*'"
+Run the command "nmblookup -d 2 '*'"
This time we are trying the same as the previous test but are trying
it via a broadcast to the default broadcast address. A number of
@@ -128,33 +183,29 @@ hosts.
If this doesn't give a similar result to the previous test then
nmblookup isn't correctly getting your broadcast address through its
-automatic mechanism. In this case you should experiment with the -B
-option which allows you to manually specify the broadcast address,
-overriding the automatic detection. You should try different broadcast
-addresses until your find the one that works. It will most likely be
-something like a.b.c.255 as microsoft tcpip stacks only listen on 1's
-based broadcast addresses. If you get stuck then ask your local
-networking guru for help (and show them this paragraph).
-
-If you find you do need the -B option (ie. the automatic detection
-doesn't work) then you should add the -B option with the right
-broadcast address for your network to the command line of nmbd in
-inetd.conf or in the script you use to start nmbd as a daemon. Once
-you do this go back to the "nmblookup __SAMBA__ -B BIGSERVER" test to
-make sure you have it running properly.
+automatic mechanism. In this case you should experiment use the
+"interfaces" option in smb.conf to manually configure your IP
+address, broadcast and netmask.
If your PC and server aren't on the same subnet then you will need to
use the -B option to set the broadcast address to the that of the PCs
subnet.
+This test will probably fail if your subnet mask and broadcast address are
+not correct. (Refer to TEST 3 notes above).
+
TEST 7:
-------
-run the command "smbclient '\\BIGSERVER\TMP'". You should then be
+Run the command "smbclient //BIGSERVER/TMP". You should then be
prompted for a password. You should use the password of the account
you are logged into the unix box with. If you want to test with
-another account then add the -U <accountname> option to the command
-line.
+another account then add the -U <accountname> option to the end of
+the command line. eg: smbclient //bigserver/tmp -Ujohndoe
+
+Note: It is possible to specify the password along with the username
+as follows:
+ smbclient //bigserver/tmp -Ujohndoe%secret
Once you enter the password you should get the "smb>" prompt. If you
don't then look at the error message. If it says "invalid network
@@ -168,6 +219,8 @@ compile in support for them in smbd
- you have a mixed case password and you haven't enabled the "password
level" option at a high enough level
- the "path =" line in smb.conf is incorrect. Check it with testparm
+- you enabled password encryption but didn't create the SMB encrypted
+password file
Once connected you should be able to use the commands "dir" "get"
"put" etc. Type "help <command>" for instructions. You should
@@ -199,11 +252,22 @@ same fixes apply as they did for the "smbclient -L" test above. In
particular, make sure your "hosts allow" line is correct (see the man
pages)
+Also, do not overlook that fact that when the workstation requests the
+connection to the samba server it will attempt to connect using the
+name with which you logged onto your Windows machine. You need to make
+sure that an account exists on your Samba server with that exact same
+name and password.
+
+If you get "specified computer is not receiving requests" or similar
+it probably means that the host is not contactable via tcp services.
+Check to see if the host is running tcp wrappers, and if so add an entry in
+the hosts.allow file for your client (or subnet, etc.)
+
TEST 9:
--------
-run the command "net use x: \\BIGSERVER\TMP". You should be prompted
+Run the command "net use x: \\BIGSERVER\TMP". You should be prompted
for a password then you should get a "command completed successfully"
message. If not then your PC software is incorrectly installed or your
smb.conf is incorrect. make sure your "hosts allow" and other config
@@ -215,23 +279,43 @@ USERNAME" to the [tmp] section of smb.conf where "USERNAME" is the
username corresponding to the password you typed. If you find this
fixes things you may need the username mapping option.
-
TEST 10:
--------
+Run the command "nmblookup -M TESTGROUP" where TESTGROUP is the name
+of the workgroup that your Samba server and Windows PCs belong to. You
+should get back the IP address of the master browser for that
+workgroup.
+
+If you don't then the election process has failed. Wait a minute to
+see if it is just being slow then try again. If it still fails after
+that then look at the browsing options you have set in smb.conf. Make
+sure you have "preferred master = yes" to ensure that an election is
+held at startup.
+
+TEST 11:
+--------
+
From file manager try to browse the server. Your samba server should
appear in the browse list of your local workgroup (or the one you
-specified in the Makefile). You should be able to double click on the
-name of the server and get a list of shares. If you get a "invalid
+specified in smb.conf). You should be able to double click on the name
+of the server and get a list of shares. If you get a "invalid
password" error when you do then you are probably running WinNT and it
is refusing to browse a server that has no encrypted password
-capability and is in user level security mode.
+capability and is in user level security mode. In this case either set
+"security = server" AND "password server = Windows_NT_Machine" in your
+smb.conf file, or enable encrypted passwords AFTER compiling in support
+for encrypted passwords (refer to the Makefile).
Still having troubles?
----------------------
Try the mailing list or newsgroup, or use the tcpdump-smb utility to
-sniff the problem.
+sniff the problem. The official samba mailing list can be reached at
+samba@samba.org. To find out more about samba and how to
+subscribe to the mailing list check out the samba web page at
+ http://samba.org/samba
+Also look at the other docs in the Samba package!
diff --git a/docs/textdocs/DOMAIN.txt b/docs/textdocs/DOMAIN.txt
deleted file mode 100644
index 31e19675fae..00000000000
--- a/docs/textdocs/DOMAIN.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-Samba now supports domain logons and network logon scripts. The
-support is still experimental, but it seems to work.
-
-The support is also not complete. Samba does not yet support the
-sharing of the SAM database with other systems yet, or remote
-administration. Support for these kind of things should be added
-sometime in the future.
-
-The domain support only works for WfWg and Win95 clients. Support for
-NT and OS/2 clients is still being worked on.
-
-Using these features you can make your clients verify their logon via
-the Samba server and make clients run a batch file when they logon to
-the network. The latter is particularly useful.
-
-To use domain logons you need to do the following:
-
-1) Setup nmbd and smbd and configure the smb.conf so that Samba is
-acting as the master browser. See INSTALL.txt and BROWSING.txt for
-details.
-
-2) create a share called [netlogon] in your smb.conf. This share should
-be readable by all users, and probably should not be writeable. This
-share will hold your network logon scripts.
-
-For example I have used:
-
- [netlogon]
- path = /data/dos/netlogon
- writeable = no
- guest ok = yes
-
-
-3) in the [global] section of smb.conf set the following:
-
- domain logons = yes
- logon script = %U.bat
-
-the choice of batch file is, of course, up to you. The above would
-give each user a separate batch file as the %U will be changed to
-their username automatically. The other standard % macros may also be
-used. You can make the btch files come from a subdirectory by using
-soemthing like:
-
- logon script = scripts\%U.bat
-
-4) create the batch files to be run when the user logs in. If the batch
-file doesn't exist then no batch file will be run.
-
-In the batch files you need to be careful to use DOS style cr/lf line
-endings. If you don't then DOS may get confused. I suggest you use a
-DOS editor to remotely edit the files if you don't know how to produce
-DOS style files under unix.
-
-5) Use smbclient with the -U option for some users to make sure that
-the \\server\NETLOGON share is available, the batch files are visible
-and they are readable by the users.
-
-6) you will probabaly find that your clients automatically mount the
-\\SERVER\NETLOGON share as drive z: while logging in. You can put some
-useful programs there to execute from the batch files.
-
-
-NOTE: You must be using "security = user" or "security = server" for
-domain logons to work correctly. Share level security won't work
-correctly.
-
-
diff --git a/docs/textdocs/ENCRYPTION.txt b/docs/textdocs/ENCRYPTION.txt
deleted file mode 100644
index 046b473e9a1..00000000000
--- a/docs/textdocs/ENCRYPTION.txt
+++ /dev/null
@@ -1,333 +0,0 @@
- LanManager / Samba Password Encryption.
- ---------------------------------------
-
-With the development of LanManager compatible password encryption for
-Samba, it is now able to validate user connections in exactly the same
-way as a LanManager or Windows NT server.
-
-This document describes how the SMB password encryption algorithm
-works and what issues there are in choosing whether you want to use
-it. You should read it carefully, especially the part about security
-and the "PROS and CONS" section.
-
-How does it work ?
-------------------
-
- LanManager encryption is somewhat similar to UNIX password
-encryption. The server uses a file containing a hashed value of a
-users password. This is created by taking the users paintext
-password, capitalising it, and either truncating to 14 bytes (or
-padding to 14 bytes with null bytes). This 14 byte value is used as
-two 56 bit DES keys to encrypt a 'magic' eight byte value, forming a
-16 byte value which is stored by the server and client. Let this value
-be known as the *hashed password*.
-
-When a client (LanManager, Windows for WorkGroups, Windows 95 or
-Windows NT) wishes to mount a Samba drive (or use a Samba resource) it
-first requests a connection and negotiates the protocol that the client
-and server will use. In the reply to this request the Samba server
-generates and appends an 8 byte, random value - this is stored in the
-Samba server after the reply is sent and is known as the *challenge*.
-
-The challenge is different for every client connection.
-
-The client then uses the hashed password (16 byte value described
-above), appended with 5 null bytes, as three 56 bit DES keys, each of
-which is used to encrypt the challenge 8 byte value, forming a 24 byte
-value known as the *response*.
-
-In the SMB call SMBsessionsetupX (when user level security is
-selected) or the call SMBtconX (when share level security is selected)
-the 24 byte response is returned by the client to the Samba server.
-
-The Samba server then reproduces the above calculation, using it's own
-stored value of the 16 byte hashed password (read from the smbpasswd
-file - described later) and the challenge value that it kept from the
-negotiate protocol reply. It then checks to see if the 24 byte value it
-calculates matches the 24 byte value returned to it from the client.
-
-If these values match exactly, then the client knew the correct
-password (or the 16 byte hashed value - see security note below) and
-is this allowed access. If not then the client did not know the
-correct password and is denied access.
-
-Note that the Samba server never knows or stores the cleartext of the
-users password - just the 16 byte hashed function derived from it. Also
-note that the cleartext password or 16 byte hashed value are never
-transmitted over the network - thus increasing security.
-
-IMPORTANT NOTE ABOUT SECURITY
------------------------------
-
-The unix and SMB password encryption techniques seem similar on the
-surface. This similarity is, however, only skin deep. The unix scheme
-typically sends clear text passwords over the nextwork when logging
-in. This is bad. The SMB encryption scheme never sends the cleartext
-password over the network but it does store the 16 byte hashed value
-on disk. This is also bad. Why? Because the 16 byte hashed value is a
-"password equivalent". You cannot derive the users password from it,
-but it could potentially be used in a modified client to gain access
-to a server. This would require considerable technical knowledge on
-behalf of the attacker but is perfectly possible. You should thus
-treat the smbpasswd file as though it contained the cleartext
-passwords of all your users. Its contents must be kept secret, and the
-file should be protected accordingly.
-
-Ideally we would like a password scheme which neither requires plain
-text passwords on the net or on disk. Unfortunately this is not
-available as Samba is stuck with being compatible with other SMB
-systems (WinNT, WfWg, Win95 etc).
-
-
-PROS AND CONS
--------------
-
-There are advantages and disadvantages to both schemes.
-
-Advantages of SMB Encryption:
------------------------------
-
-- plain text passwords are not passed across the network. Someone using
-a network sniffer cannot just record passwords going to the SMB server.
-
-- WinNT doesn't like talking to a server that isn't using SMB
-encrypted passwords. It will refuse to browse the server if the server
-is also in user level security mode. It will insist on promting the
-user for the password on each connection, which is very annoying. The
-only things you can do to stop this is to use SMB encryption.
-
-Advantages of non-encrypted passwords:
---------------------------------------
-
-- plain text passwords are not kept on disk.
-
-- uses same password file as other unix services such as login and
-ftp
-
-- you are probably already using other services (such as telnet and
-ftp) which send plain text passwords over the net, so not sending them
-for SMB isn't such a big deal.
-
-- the SMB encryption code in Samba is new and has only had limited
-testing. We have tried hard to make it secure but in any new
-implementation of a password scheme there is the possability of an
-error.
-
-
-The smbpasswd file.
--------------------
-
- In order for Samba to participate in the above protocol it must
-be able to look up the 16 byte hashed value given a user name.
-Unfortunately, as the UNIX password value is also a one way hash
-function (ie. it is impossible to retrieve the cleartext of the users
-password given the UNIX hash of it) then a separate password file
-containing this 16 byte value must be kept. To minimise problems with
-these two password files, getting out of sync, the UNIX /etc/passwd and
-the smbpasswd file, a utility, mksmbpasswd.sh, is provided to generate
-a smbpasswd file from a UNIX /etc/passwd file.
-
-To generate the smbpasswd file from your /etc/passwd file use the
-following command :-
-
-cat /etc/passwd | mksmbpasswd.sh >/usr/local/samba/private/smbpasswd
-
-If you are running on a system that uses NIS, use
-
-ypcat passwd | mksmbpasswd.sh >/usr/local/samba/private/smbpasswd
-
-The mksmbpasswd.sh program is found in the Samba source directory. By
-default, the smbpasswd file is stored in :-
-
-/usr/local/samba/private/smbpasswd
-
-The owner of the /usr/local/samba/private directory should be set to
-root, and the permissions on it should be set to :-
-
-r-x------
-
-The command
-
-chmod 500 /usr/local/samba/private
-
-will do the trick. Likewise, the smbpasswd file inside the private
-directory should be owned by root and the permissions on is should be
-set to
-
-rw-------
-
-by the command :-
-
-chmod 600 smbpasswd.
-
-The format of the smbpasswd file is
-
-username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
-
-Although only the username, uid, and XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-sections are significant and are looked at in the Samba code.
-
-It is *VITALLY* important that there by 32 'X' characters between the
-two ':' characters - the smbpasswd and Samba code will fail to validate
-any entries that do not have 32 characters between ':' characters.
-
-When the password file is created all users have password entries
-consisting of 32 'X' characters. By default this disallows any access
-as this user. When a user has a password set, the 'X' characters change
-to 32 ascii hexadecimal digits (0-9, A-F). These are an ascii
-representation of the 16 byte hashed value of a users password.
-
-To set a user to have no password (not recommended), edit the file
-using vi, and replace the first 11 characters with the asci text
-
-NO PASSWORD
-
-Eg. To clear the password for user bob, his smbpasswd file entry would
-look like :
-
-bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:Bob's full name:/bobhome:/bobshell
-
-If you are allowing users to use the smbpasswd command to set their own
-passwords, you may want to give users NO PASSWORD initially so they do
-not have to enter a previous password when changing to their new
-password (not recommended).
-
-Note : This file should be protected very carefully. Anyone with
-access to this file can (with enough knowledge of the protocols) gain
-access to your SMB server. The file is thus more sensitive than a
-normal unix /etc/passwd file.
-
-The smbpasswd Command.
-----------------------
-
- The smbpasswd command maintains the 32 byte password field in
-the smbpasswd file. If you wish to make it similar to the unix passwd
-or yppasswd programs, install it in /usr/local/samba/bin (or your main
-Samba binary directory) and make it setuid root.
-
-Note that if you do not do this then the root user will have to set all
-users passwords.
-
-To set up smbpasswd as setuid root, change to the Samba binary install
-directory and then type (as root) :
-
-chown root smbpasswd
-chmod 4555 smbpasswd
-
-If smbpasswd is installed as setuid root then you would use it as
-follows.
-
-smbpasswd
-Old SMB password: <type old alue here - just hit return if there is NO PASSWORD>
-New SMB Password: < type new value >
-Repeat New SMB Password: < re-type new value >
-
-If the old value does not match the current value stored for that user,
-or the two new values do not match each other, then the password will
-not be changed.
-
-If invoked by an ordinary user it will only allow the user to change
-his or her own Samba password.
-
-If run by the root user smbpasswd may take an optional argument,
-specifying the user name whose SMB password you wish to change. Note
-that when run as root smbpasswd does not prompt for or check the old
-password value, thus allowing root to set passwords for users who have
-forgotten their passwords.
-
-smbpasswd is designed to work in the same way and be familiar to UNIX
-users who use the passwd or yppasswd commands.
-
-NOTE. As smbpasswd is designed to be installed as setuid root I would
-appreciate it if everyone examined the source code to look for
-potential security flaws. A setuid program, if not written properly can
-be an open door to a system cracker. Please help make this program
-secure by reporting all problems to me (the author, Jeremy Allison).
-
-My email address is :-
-
-jra@vantive.com
-
-Setting up Samba to support LanManager Encryption.
---------------------------------------------------
-
-This is a very brief description on how to setup samba to support
-password encryption. More complete instructions will probably be added
-later.
-
-1) get and compile the libdes libraries. the source is available from
-nimbus.anu.edu.au in pub/tridge/libdes/libdes.tar.92-10-13.gz
-
-2) enable the encryption stuff in the Samba makefile, making sure you
-point it to the libdes library and include file (it needs des.h)
-The entries you need to uncomment are the four lines after the comment :-
-
-# This is for SMB encrypted (lanman) passwords.
-
-Note that you may have to change the variable DES_BASE to
-point at the place where you installed the DES library.
-
-3) compile and install samba as usual
-
-4) f your system can't compile the module getsmbpass.c then remove the
--DSMBGETPASS define from the Makefile.
-
-5) enable encrypted passwords in smb.conf by adding the line
-"encrypt passwords = yes" in the [global] section
-
-6) create the initial smbpasswd password file in the place you
-specified in the Makefile. A simple way to do this based on your
-existing Makefile (assuming it is in a reasonably standard format) is
-like this:
-
-cat /etc/passwd | mksmbpasswd.sh > /usr/local/samba/private/smbpasswd
-
-Change ownership of private and smbpasswd to root.
-
-chown -R root /usr/local/samba/private
-
-Set the correct permissions on /usr/local/samba/private
-
-chmod 500 /usr/local/samba/private
-
-Set the correct permissions on /usr/local/samba/private/smbpasswd
-
-chmod 600 /usr/local/samba/private/smbpasswd
-
-note that the mksmbpasswd.sh script is in the samba source directory.
-
-If this fails then you will find that you will need entries that look
-like this:
-
-# SMB password file.
-tridge:148:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Andrew Tridgell:/home/tridge:/bin/tcsh
-
-note that the uid and username fields must be right. Also, you must get
-the number of X's right (there should be 32).
-
-If you wish, install the smbpasswd program as suid root.
-
-chown root /usr/local/samba/bin/smbpasswd
-chmod 4555 /usr/local/samba/bin/smbpasswd
-
-7) set the passwords for users using the smbpasswd command. For
-example, as root you could do "smbpasswd tridge"
-
-8) try it out!
-
-Note that you can test things using smbclient, as it also now supports
-encryption.
-
-NOTE TO USA Sites that Mirror Samba
------------------------------------
-
-The DES library is considered a munition in the USA. Under US Law it is
-illegal to export this software, or to put it in a freely available ftp
-site.
-
-Please do not mirror the DES directory from the site on nimbus.anu.edu.au
-
-Thank you,
-
-Jeremy Allison.
-
diff --git a/docs/textdocs/Faxing.txt b/docs/textdocs/Faxing.txt
new file mode 100644
index 00000000000..0703d75cc35
--- /dev/null
+++ b/docs/textdocs/Faxing.txt
@@ -0,0 +1,220 @@
+Contributor: Gerhard Zuber <zuber@berlin.snafu.de>
+Date: August 5th 1997.
+Status: Current
+
+Subject: F A X I N G with S A M B A
+==========================================================================
+
+This text describes how to turn your SAMBA-server into a fax-server
+for any environment, especially for Windows.
+ Author: Gerhard Zuber <zuber@berlin.snafu.de>
+ Version: 1.4
+ Date: 04. Aug. 1997
+
+Requirements:
+ UNIX box (Linux preferred) with SAMBA and a faxmodem
+ ghostscript package
+ mgetty+sendfax package
+ pbm package (portable bitmap tools)
+
+FTP sites:
+ sunsite.unc.edu:/pub/Linux/system/Serial/mgetty+sendfax*
+ tsx-11.mit.edu:/pub/linux/sources/sbin/mgetty+sendfax
+ ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/mgetty1.1.6-May05.tar.gz
+
+ pbm10dec91.tgz
+ ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/pbm10dec91.tgz
+ sunsite.unc.edu: ..../apps/graphics/convert/pbmplus-10dec91-bin.tar.gz
+ ftp.gwdg.de/pub/linux/grafik/pbmplus.src.tar.Z (this is 10dec91 source)
+ or ??? pbm10dec91.tgz pbmplus10dec91.tgz
+
+
+making mgetty+sendfax running:
+==============================
+
+ go to source tree: /usr/src/mgetty+sendfax
+ cp policy.h-dist policy.h
+
+ change your settings: valid tty ports, modem initstring, Station-Id
+
+#define MODEM_INIT_STRING "AT &F S0=0 &D3 &K3 &C1\\\\N2"
+
+#define FAX_STATION_ID "49 30 12345678"
+
+#define FAX_MODEM_TTYS "ttyS1:ttyS2:ttyS3"
+
+ Modem initstring is for rockwell based modems
+ if you want to use mgetty+sendfax as PPP-dialin-server,
+ define AUTO_PPP in Makefile:
+
+CFLAGS=-O2 -Wall -pipe -DAUTO_PPP
+
+ compile it and install the package.
+ edit your /etc/inittab and let mgetty running on your preferred
+ ports:
+
+s3:45:respawn:/usr/local/sbin/mgetty ttyS2 vt100
+
+ now issue a
+ kill -HUP 1
+ and enjoy with the lightning LEDs on your modem
+ your now are ready to receive faxes !
+
+
+ if you want a PPP dialin-server, edit
+ /usr/local/etc/mgetty+sendfax/login.config
+
+/AutoPPP/ - ppp /usr/sbin/pppd auth debug passive modem
+
+
+ Note: this package automatically decides between a fax call and
+ a modem call. In case of modem call you get a login prompt !
+
+Tools for printing faxes:
+=========================
+
+ your incomed faxes are in:
+ /var/spool/fax/incoming
+
+ print it with:
+
+ for i in *
+ do
+ g3cat $i | g3tolj | lpr -P hp
+ done
+
+ in case of low resolution use instead:
+
+ g3cat $i | g3tolj -aspect 2 | lpr -P hp
+
+
+ g3cat is in the tools-section, g3tolj is in the contrib-section
+ for printing to HP lasers.
+
+ If you want to produce files for displaying and printing with Windows, use
+ some tools from the pbm-package like follow
+
+ g3cat $i | g3topbm - | ppmtopcx - >$i.pcx
+
+ and view it with your favourite Windows tool (maybe paintbrush)
+
+
+Now making the fax-server:
+===========================
+
+ fetch the file
+ mgetty+sendfax/frontends/winword/faxfilter
+
+ and place it in
+
+ /usr/local/etc/mgetty+sendfax/
+
+ prepare your faxspool file as mentioned in this file
+ edit fax/faxspool.in and reinstall or change the final
+ /usr/local/bin/faxspool too.
+
+ if [ "$user" = "root" -o "$user" = "fax" -o \
+ "$user" = "lp" -o "$user" = "daemon" -o "$user" = "bin" ]
+
+ find the first line and change the second.
+
+ make sure you have pbmtext (from the pbm-package). This is
+ needed for creating the small header line on each page.
+ Notes on pbmplus:
+ Some peoples had problems with precompiled binaries (especially
+ at linux) with a shared lib libgr.so.x.x. The better way is
+ to fetch the source and compile it. One needs only pbmtext for
+ generating the small line on top of each page /faxheader). Install
+ only the individual programs you need. If you install the full
+ package then install pbmplus first and then mgetty+sendfax, because
+ this package has some changed programs by itself (but not pbmtext).
+
+ make sure your ghostscript is functional. You need fonts !
+ I prefer these from the OS/2 disks
+
+ prepare your faxheader
+ /usr/local/etc/mgetty+sendfax/faxheader
+
+ edit your /etc/printcap file:
+
+# FAX
+lp3|fax:\
+ :lp=/dev/null:\
+ :sd=/usr/spool/lp3:\
+ :if=/usr/local/etc/mgetty+sendfax/faxfilter:sh:sf:mx#0:\
+ :lf=/usr/spool/lp3/fax-log:
+
+
+
+
+ edit your /usr/local/samba/lib/smb.conf
+
+ so you have a smb based printer named "fax"
+
+
+The final step:
+===============
+
+ Now you have a printer called "fax" which can be used via
+ TCP/IP-printing (lpd-system) or via SAMBA (windows printing).
+
+ On every system you are able to produce postscript-files you
+ are ready to fax.
+
+ On Windows 3.1 95 and NT:
+
+ Install a printer wich produces postscript output,
+ e.g. apple laserwriter
+
+ connect the "fax" to your printer
+
+
+ Now write your first fax. Use your favourite wordprocessor,
+ write, winword, notepad or whatever you want, and start
+ with the headerpage.
+
+ Usually each fax has a header page. It carries your name,
+ your address, your phone/fax-number.
+
+ It carries also the recipient, his address and his *** fax
+ number ***. Now here is the trick:
+
+ Use the text:
+ Fax-Nr: 123456789
+ as the recipients fax-number. Make sure this text does not
+ occur in regular text ! Make sure this text is not broken
+ by formatting information, e.g. format it as a single entity.
+ (Windows Write and Win95 Wordpad are functional, maybe newer
+ versions of Winword are breaking formatting information).
+
+ The trick is that postscript output is human readable and
+ the faxfilter program scans the text for this pattern and
+ uses the found number as the fax-destination-number.
+
+ Now print your fax through the fax-printer and it will be
+ queued for later transmission. Use faxrunq for sending the
+ queue out.
+
+ Notes of SAMBA smb.conf:
+ Simply use fall through from the samba printer to the unix
+ printer. Sample:
+
+
+ printcap name = /etc/printcap
+ print command = /usr/bin/lpr -r -P %p %s
+ lpq command = /usr/bin/lpq -P %p
+ lprm command = /usr/bin/lprm -P %p %j
+
+
+[fax]
+ comment = FAX (mgetty+sendfax)
+ path = /tmp
+ printable = yes
+ public = yes
+ writable = no
+ create mode = 0700
+ browseable = yes
+ guest ok = no
+
+
+
diff --git a/docs/textdocs/GOTCHAS.txt b/docs/textdocs/GOTCHAS.txt
new file mode 100644
index 00000000000..bc5c6dae853
--- /dev/null
+++ b/docs/textdocs/GOTCHAS.txt
@@ -0,0 +1,68 @@
+This file lists Gotchas to watch out for:
+=========================================================================
+Item Number: 1.0
+Description: Problem Detecting Interfaces
+Symptom: Workstations do NOT see Samba server in Browse List
+OS: RedHat - Rembrandt Beta 2
+Platform: Intel
+Date: August 16, 1996
+Submitted By: John H Terpstra
+Details:
+ By default RedHat Rembrandt-II during installation adds an
+ entry to /etc/hosts as follows:-
+ 127.0.0.1 loopback "hostname"."domainname"
+
+ This causes Samba to loop back onto the loopback interface.
+ The result is that Samba fails to communicate correctly with
+ the world and therefor may fail to correctly negotiate who
+ is the master browse list holder and who is the master browser.
+
+Corrective Action: Delete the entry after the word loopback
+ in the line starting 127.0.0.1
+=========================================================================
+Item Number: 2.0
+Description: Problems with MS Windows NT Server network logon service
+Symptom: Loss of Domain Logon Services and failed Windows NT / 95
+ logon attempts.
+OS: All Unix systems with Windows NT Domain Control environments.
+Platform: All
+Date: February 1, 1997
+Submitted By: John H Terpstra
+Details:
+ Samba is configured for Domain logon control in a network
+ where a Windows NT Domain Primary Controller is running.
+
+ Case 1:
+ The Windows NT Server is shut down, then restarted. Then
+ the Samba server is reconfigured so that it NO LONGER offers
+ Domain logon services. Windows NT and 95 workstations can no
+ longer log onto the domain. Ouch!!!
+
+ Case 2:
+ The Windows NT Server which is running the Network logon
+ Service is shut down and restarted while Samba is a domain
+ controller offering the Domain LogOn service. Windows NT
+ Workstation and Server can no longer log onto the network.
+
+ Cause:
+ Windows NT checks at start up to see if any domain logon
+ controllers are already running within the domain. It finds
+ Samba claiming to offer the service and therefore does NOT
+ start its Network Logon Service.
+
+ Windows NT needs the Windows NT network logon service to gain
+ from its Domain controller's SAM database the security
+ identifier for the user loging on.
+
+Work-around: Stop the Samba nmbd and smbd processes, then on the Windows
+ NT Primary Domain Controller start the Network Logon Service.
+ Now restart the Samba nmbd and smbd services.
+
+ Better still: DO NOT CONFIGURE SAMBA AS THE NETWORK LOGON
+ SERVER, DO NOT SET SAMBA TO BE THE DOMAIN MASTER, DO NOT
+ SET SAMBA TO OS LEVEL GREATER THAN 0.
+
+ ie: Let Windows NT Server be the Domain Logon server, the
+ domain master browser and do NOT interfere with any aspect
+ of Microsoft Windows NT Domain Control.
+=========================================================================
diff --git a/docs/textdocs/GROUP-MAPPING-HOWTO.txt b/docs/textdocs/GROUP-MAPPING-HOWTO.txt
new file mode 100644
index 00000000000..6bd29656af8
--- /dev/null
+++ b/docs/textdocs/GROUP-MAPPING-HOWTO.txt
@@ -0,0 +1,78 @@
+Samba 3.0 prealpha guide to group mapping
+---------------------------------------------------
+
+Jean François Micouleau (jfm@samba.org)
+
+Starting with Samba 3.0 alpha 2, a new group mapping function is available. The
+current method (likely to change) to manage the groups is a new command called
+smbgroupedit.
+
+The first immediate reason to use the group mapping on a PDC, is that
+the 'domain admin group' of smb.conf is now gone. This parameter was
+used to give the listed users local admin rights on their
+workstations. It was some magic stuff that simply worked but didn't
+scale very well for complex setups.
+
+Let me explain how it works on NT/W2K, to have this magic fade away.
+When installing NT/W2K on a computer, the installer program creates some users
+and groups. Notably the 'Administrators' group, and gives to that group some
+privileges like the ability to change the date and time or to kill any process
+(or close too) running on the local machine. The 'Administrator' user is a
+member of the 'Administrators' group, and thus 'inherit' the 'Administrators'
+group privileges. If a 'joe' user is created and become a member of the
+'Administrator' group, 'joe' has exactly the same rights as 'Administrator'.
+
+When a NT/W2K machine is joined to a domain, during that phase, the "Domain
+Administrators' group of the PDC is added to the 'Administrators' group of the
+workstation. Every members of the 'Domain Administrators' group 'inherit' the
+rights of the 'Administrators' group when logging on the workstation.
+
+
+You are now wondering how to make some of your samba PDC users members of the
+'Domain Administrators' ? That's really easy.
+
+1) create a unix group (usually in /etc/group), let's call it domadm
+2) add to this group the users that must be Administrators. For example if you
+want joe,john and mary, your entry in /etc/group will look like:
+
+ domadm:x:502:joe,john,mary
+
+3) map this domadm group to the 'domain admins' group:
+
+3.1) lists all the mapped groups by running: smbgroupedit -v
+ you will get a list looking like the one below.
+
+NT group (SID) -> Unix group
+System Operators (S-1-5-32-549) -> -1
+Replicators (S-1-5-32-552) -> -1
+Guests (S-1-5-32-546) -> -1
+Power Users (S-1-5-32-547) -> -1
+Print Operators (S-1-5-32-550) -> -1
+Administrators (S-1-5-32-544) -> -1
+Account Operators (S-1-5-32-548) -> -1
+Backup Operators (S-1-5-32-551) -> -1
+Users (S-1-5-32-545) -> -1
+Domain Admins (S-1-5-21-1108995562-3116817432-1375597819-512) -> -1
+Domain Guests (S-1-5-21-1108995562-3116817432-1375597819-514) -> -1
+Domain Users (S-1-5-21-1108995562-3116817432-1375597819-513) -> -1
+
+3.2) map the unix domadm group to the NT 'Domain Admins' group, by running the
+command:
+
+ smbgroupedit -c S-1-5-21-1108995562-3116817432-1375597819-512 -u domadm
+
+warning: don't copy and paste this sample, the Domain Admins SID (the
+S-1-5-21-...-512) is different for every PDC.
+
+you're set, joe, john and mary are domain administrators !
+
+
+
+Like the Domain Admins group, you can map any arbitrary Unix group to any NT
+group. You can also make any Unix group a domain group. For example, on a domain
+member machine (an NT/W2K or a samba server running winbind), you would like to
+give access to a certain directory to some users who are member of a group on
+your samba PDC. Flag that group as a domain group by running:
+
+ smbgroupedit -a unixgroup -td
+
diff --git a/docs/textdocs/HINTS.txt b/docs/textdocs/HINTS.txt
index 953650bdd3e..75114557fe8 100644
--- a/docs/textdocs/HINTS.txt
+++ b/docs/textdocs/HINTS.txt
@@ -1,3 +1,10 @@
+Contributor: Many
+Updated: Not for a long time!
+
+Subject: A collection of hints
+Status: May be useful information but NOT current
+===============================================================================
+
Here are some random hints that you may find useful. These really
should be incorporated in the main docs someday.
@@ -40,7 +47,7 @@ Jim barry has written an excellent drag-and-drop cr/lf converter for
windows. Just drag your file onto the icon and it converts the file.
Get it from
-ftp://nimbus.anu.edu.au/pub/tridge/samba/contributed/fixcrlf.zip
+ftp://samba.org/pub/samba/contributed/fixcrlf.zip
----------------------
HINT: Use the "username map" option
diff --git a/docs/textdocs/INSTALL.sambatar b/docs/textdocs/INSTALL.sambatar
index 388e2a3eb6f..413f54d3c65 100644
--- a/docs/textdocs/INSTALL.sambatar
+++ b/docs/textdocs/INSTALL.sambatar
@@ -1,3 +1,9 @@
+Contributor: Ricky Poulten <poultenr@logica.co.uk>
+Date: Unknown
+Status: Current
+
+Subject: Using smbtar
+=============================================================================
Please see the readme and the man page for general info.
diff --git a/docs/textdocs/Imprints.txt b/docs/textdocs/Imprints.txt
new file mode 100644
index 00000000000..4ea9782bd38
--- /dev/null
+++ b/docs/textdocs/Imprints.txt
@@ -0,0 +1,47 @@
+==================================================================
+
+
+Imprints (Installation Manager of Printer driver
+Retreival and Installation for Samba) is a project to
+implement a UNIX equivalent of the Windows NT APW.
+It has been taken on in part by the Samba Team, VA Linux
+Systems and Hewlett-Packard. The Imprints toolset seeks
+to provide central repository for users and administrators
+to locate, download, and install all variations Window
+95/98/NT printer drivers on Samba print servers.
+
+The server portion of Imprints is composed of a database
+server which contains information and locations of various
+printer driver packages. This server can be queried over
+standard HTTP get requests and should therefore be available
+to most administrators behind firewalls. The server's
+database consists of records containing data about each
+known printer driver package. For example, each driver
+record contains a URL from which the Imprints installation
+client can download the package as well as a public key which
+can be used to verify the package's integrity.
+
+Once downloaded, the installation client will attempt to
+install the printer driver on the defined remote server
+using the username and password provided by the administrator.
+If the username/password pair can be authenticated by the
+remote server (and has the appropriate authorization), then
+the printer driver(s) is (are) installed and the new Printer
+is created.
+
+From Samba's point of view, the process of creating a new
+printer via the Imprints installation client is identical to
+that of using the Windows NT APW. In fact, Imprints utilizes
+Samba's rpcclient and smbclient tools to issue the same MS-RPC
+and file copy operations as an NT client. This means that
+Imprints can also be used to install printers on remote Windows
+NT print servers.
+
+For more information on Imprints, visit the project homepage
+at
+
+ http://imprints.sourceforge.net/.
+
+
+
+
diff --git a/docs/textdocs/Macintosh_Clients.txt b/docs/textdocs/Macintosh_Clients.txt
new file mode 100644
index 00000000000..dfac97e1aa2
--- /dev/null
+++ b/docs/textdocs/Macintosh_Clients.txt
@@ -0,0 +1,23 @@
+> Are there any Macintosh clients for Samba?
+
+Yes. Thursby now have a CIFS Client / Server called DAVE - see
+http://www.thursby.com/
+
+They test it against Windows 95, Windows NT and samba for
+compatibility issues. At the time of writing, DAVE was at version
+1.0.1. The 1.0.0 to 1.0.1 update is available as a free download from
+the Thursby web site (the speed of finder copies has been greatly
+enhanced, and there are bug-fixes included).
+
+Alternatives - There are two free implementations of AppleTalk for
+several kinds of UNIX machnes, and several more commercial ones.
+These products allow you to run file services and print services
+natively to Macintosh users, with no additional support required on
+the Macintosh. The two free omplementations are Netatalk,
+http://www.umich.edu/~rsug/netatalk/, and CAP,
+http://www.cs.mu.oz.au/appletalk/atalk.html. What Samba offers MS
+Windows users, these packages offer to Macs. For more info on these
+packages, Samba, and Linux (and other UNIX-based systems) see
+http://www.eats.com/linux_mac_win.html
+
+
diff --git a/docs/textdocs/NetBIOS.txt b/docs/textdocs/NetBIOS.txt
new file mode 100644
index 00000000000..ca0dcc84b72
--- /dev/null
+++ b/docs/textdocs/NetBIOS.txt
@@ -0,0 +1,152 @@
+Contributor: lkcl - samba@samba.org
+ Copyright 1997 Luke Kenneth Casson Leighton
+Date: March 1997
+Status: Current
+Updated: 12jun97
+
+Subject: Definition of NetBIOS Protocol and Name Resolution Modes
+=============================================================================
+
+=======
+NETBIOS
+=======
+
+NetBIOS runs over the following tranports: TCP/IP; NetBEUI and IPX/SPX.
+Samba only uses NetBIOS over TCP/IP. For details on the TCP/IP NetBIOS
+Session Service NetBIOS Datagram Service, and NetBIOS Names, see
+rfc1001.txt and rfc1002.txt.
+
+NetBEUI is a raw NetBIOS frame protocol implementation that allows NetBIOS
+datagrams to be sent out over the 'wire' embedded within LLC frames.
+NetBEUI is not required when using NetBIOS over TCP/IP protocols and it
+is preferable NOT to install NetBEUI if it can be avoided.
+
+IPX/SPX is also not required when using NetBIOS over TCP/IP, and it is
+preferable NOT to install the IPX/SPX transport unless you are using Novell
+servers. At the very least, it is recommended that you do not install
+'NetBIOS over IPX/SPX'.
+
+[When installing Windows 95, you will find that NetBEUI and IPX/SPX are
+installed as the default protocols. This is because they are the simplest
+to manage: no Windows 95 user-configuration is required].
+
+
+NetBIOS applications (such as samba) offer their services (for example,
+SMB file and print sharing) on a NetBIOS name. They must claim this name
+on the network before doing so. The NetBIOS session service will then
+accept connections on the application's behalf (on the NetBIOS name
+claimed by the application). A NetBIOS session between the application
+and the client can then commence.
+
+NetBIOS names consist of 15 characters plus a 'type' character. This is
+similar, in concept, to an IP address and a TCP port number, respectively.
+A NetBIOS-aware application on a host will offer different services under
+different NetBIOS name types, just as a host will offer different TCP/IP
+services on different port numbers.
+
+NetBIOS names must be claimed on a network, and must be defended. The use
+of NetBIOS names is most suitable on a single subnet; a Local Area Network
+or a Wide Area Network.
+
+NetBIOS names are either UNIQUE or GROUP. Only one application can claim a
+UNIQUE NetBIOS name on a network.
+
+There are two kinds of NetBIOS Name resolution: Broadcast and Point-to-Point.
+
+
+=================
+BROADCAST NetBIOS
+=================
+
+Clients can claim names, and therefore offer services on successfully claimed
+names, on their broadcast-isolated subnet. One way to get NetBIOS services
+(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
+SMB file/print sharing: see cifs4.txt) working on a LAN or WAN is to make
+your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
+
+This, however, is not recommended. If you have a large LAN or WAN, you will
+find that some of your hosts spend 95 percent of their time dealing with
+broadcast traffic. [If you have IPX/SPX on your LAN or WAN, you will find
+that this is already happening: a packet analyzer will show, roughly
+every twelve minutes, great swathes of broadcast traffic!].
+
+
+============
+NBNS NetBIOS
+============
+
+rfc1001.txt describes, amongst other things, the implementation and use
+of, a 'NetBIOS Name Service'. NT/AS offers 'Windows Internet Name Service'
+which is fully rfc1001/2 compliant, but has had to take specific action
+with certain NetBIOS names in order to make it useful. (for example, it
+deals with the registration of <1c> <1d> <1e> names all in different ways.
+I recommend the reading of the Microsoft WINS Server Help files for full
+details).
+
+Samba also offers WINS server capabilities. Samba does not interact
+with NT/AS (WINS replication), so if you have a mixed NT server and
+Samba server environment, it is recommended that you use the NT server's
+WINS capabilities, instead of samba's WINS server capabilities.
+
+The use of a WINS server cuts down on broadcast network traffic for
+NetBIOS name resolution. It has the effect of pulling all the broadcast
+isolated subnets together into a single NetBIOS scope, across your LAN
+or WAN, while avoiding the use of TCP/IP broadcast packets.
+
+When you have a WINS server on your LAN, WINS clients will be able to
+contact the WINS server to resolve NetBIOS names. Note that only those
+WINS clients that have registered with the same WINS server will be
+visible. The WINS server _can_ have static NetBIOS entries added to its
+database (usually for security reasons you might want to consider putting
+your domain controllers or other important servers as static entries,
+but you should not rely on this as your sole means of security), but for
+the most part, NetBIOS names are registered dynamically.
+
+[It is important to mention that samba's browsing capabilities (as a WINS
+client) must have access to a WINS server. if you are using samba also
+as a WINS server, then it will have a direct short-cut into the WINS
+database.
+
+This provides some confusion for lots of people, and is worth mentioning
+here: a Browse Server is NOT a WINS Server, even if these services are
+implemented in the same application. A Browse Server _needs_ a WINS server
+because a Browse Server is a WINS client, which is _not_ the same thing].
+
+Clients can claim names, and therefore offer services on successfully claimed
+names, on their broadcast-isolated subnet. One way to get NetBIOS services
+(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
+SMB file/print sharing: see cifs6.txt) working on a LAN or WAN is to make
+your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
+You will find, however, if you do this on a large LAN or a WAN, that your
+network is completely swamped by NetBIOS and browsing packets, which is why
+WINS was developed to minimise the necessity of broadcast traffic.
+
+WINS Clients therefore claim names from the WINS server. If the WINS
+server allows them to register a name, the client's NetBIOS session service
+can then offer services on this name. Other WINS clients will then
+contact the WINS server to resolve a NetBIOS name.
+
+
+=======================
+Samba WINS Capabilities
+=======================
+
+To configure samba as a WINS server, you must add "wins support = yes" to
+the [global] section of your smb.conf file. This will enable WINS server
+capabilities in nmbd.
+
+To configure samba as a WINS client, you must add "wins server = x.x.x.x"
+to the [global] section of your smb.conf file, where x.x.x.x is the TCP/IP
+address of your WINS server. The browsing capabilities in nmbd will then
+register (and resolve) WAN-wide NetBIOS names with this WINS server.
+
+Note that if samba has "wins support = yes", then the browsing capabilities
+will _not_ use the "wins server" option to resolve NetBIOS names: it will
+go directly to the internal WINS database for NetBIOS name resolution. It
+is therefore invalid to have both "wins support = yes" and
+"wins server = x.x.x.x". Note, in particular, that if you configure the
+"wins server" parameter to be the ip address of your samba server itself
+(as might one intuitively think), that you will run into difficulties.
+Do not use both parameters!
+
+
diff --git a/docs/textdocs/PROFILES.txt b/docs/textdocs/PROFILES.txt
new file mode 100644
index 00000000000..1b9cf4213e3
--- /dev/null
+++ b/docs/textdocs/PROFILES.txt
@@ -0,0 +1,385 @@
+Contributors: Bruce Cook <BC3-AU@bigfoot.com>
+ Copyright (C) 1998 Bruce Cook
+
+ John Terpstra <samba@samba.org>
+ Copyright (C) 1998 John H. Terpstra
+
+ Wolfgang Ratzka <ratzka@hrz.uni-marburg.de>
+ Copyright (C) 1998 Wolfgang Ratzka
+
+Created: April 11, 1998
+Updated: April 11, 1998
+
+Subject: User Profiles
+===========================================================================
+
+From BC3-AU@bigfoot.com Sat Apr 11 13:36:05 1998
+Date: Sat, 11 Apr 1998 17:13:49 +1000
+From: Bruce Cook <BC3-AU@bigfoot.com>
+To: Multiple recipients of list <samba-ntdom@samba.org>
+Subject: RE: A question about NT Domains
+
+Luke Kenneth Casson Leighton writes:
+ > On Fri, 10 Apr 1998, Jean-Francois Micouleau wrote:
+ >
+ > > On Fri, 10 Apr 1998, Luke Kenneth Casson Leighton wrote:
+ > >
+ > > > ah, then i need to explain better. two or more users have identical
+ > > > profiles. say only one user installs a program which adds additional keys
+ > > > into the registry. those keys, as i understand it, will *not* be removed
+ > > > from HKEY_LOCAL_USER when subsequent users log in.
+ > >
+ > > under W95 or NT ?
+ >
+ > my experience is with Win95, but i expect the same for NT, and have been
+ > told that it is so by someone who runs NT admin training courses.
+ >
+ > > and why do you want to have one profile shared between multiples users ?
+ >
+ > you don't. how did you get that impression? i said multiple users with
+ > identical profiles, not multiple users sharing one profile.
+
+In my experience with both Win95 and NT, is that the HKEY_LOCAL_USER information
+is stored in USER.dat or NTuser.DAT for NT. ALL of this branch is in this file
+and there is no overlap between any two users (Unless you have '95 set up
+to use a single common profile).
+
+[** lkcl: see jht's message for conditions under which an overlap can occur **]
+
+The HKEY_LOCAL_MACHINE branch is machine based, and shared by all users of that
+machine.
+
+
+[And now for a whole stack of caveats]
+
+1. User start menu paths are not stored in the registry (obviously) they're
+ a directory structure that located by settings in HKEY_LOCAL_USER.
+
+ If you want start menues / desktop / favorites to be individual to a user
+ you must set up your user registry so these can be located individually.
+ The easiest tool to manage this is the policy editor.
+
+2. When you log onto 'Doze 95, it has to find the user registry.
+
+
+ If you have specified a common profile, a "default user" USER.DAT is used.
+
+ If you have specified individualised profiles, then USER.DAT will be found
+ by the following formula:
+
+ 1. if NET USE x: /HOME was used at startup, try for x:\USER.DAT (where
+ x: is any drive letter from A to Z.
+ if no USER.DAT is found go to step 3
+
+ 2. if no home is specified in a mapping,
+ ...\windows\profiles\username\USER.DAT is used. If no USER.DAT exists
+ go to step 3.
+
+ 3. If neither of the previous two found a USER.DAT, then it will use
+ a prototype USER.DAT which it will later save to the above specified
+ path when the user logs out.
+
+ The interesting thing here is that the prototype USER.DAT used here
+ is actually a copy of the last USER.DAT used on this machine. (This
+ may be the effect that the original poster is seeing)
+
+ 4. As discussed above the start menu and desktop are specified in the
+ registry contained within USER.DAT. When a new USER.DAT is created
+ from a prototype, new directories are created for the start menu and
+ desktop ACCORDING TO HOW THE COPIED PROTOTYPE DEFINES THEM.
+
+ So if the prototype USER.DAT says that start menu is in H:\Start Menu
+ but programs folder is C:\windows\start menu\programs, then the
+ H:\start menu will be created, and the existing machine programs
+ folder used.
+
+ This means that is is important when creating roving profiles to get
+ your prototype USER.DAT and general user directory structure set up
+ exactly as you want it, and then make a copy of it that you know will
+ be safe from modification. When creating a new user you then copy
+ this prototype into the new user area, so that the new user doesn't
+ just inherit what the previous user had.
+
+
+3. When you log onto 'Doze NT, it has to find the user registry.
+
+
+ NT is easier to see what's going on, but follows much the same rules as
+ '95. The big difference being that 'NT gets its profile location from
+ the login server when it's logged in. (On an NT system have a look at user
+ manager/user/profile - you will see that you can specify the user profile
+ path) Under NT3.51 this profile path was a path to NTuser.DAT, on 4.0 this
+ seems to be a path to a directory structure (haven't played with many NT4
+ servers)
+
+ I'm not sure how this works in samba, as I haven't yet tried the NT_DOM stuff
+ yet (Luke: I assume you have a keyword for this?)
+
+[lkcl: nt workstations should look in exactly the same places for things on
+ samba or other SMB servers as they do on an NT server, as long as that
+ SMB server looks like NT. if anyone finds that something fails, alert
+ us on samba@samba.org and we'll look into it].
+
+ When an NT system find a user without a NTuser.DAT, it copies from a
+ prototype that it stores especially for this purpose, so while unlike '95
+ the user doesn't get whatever happened last on the machine, the user will
+ get a fairly minimalist configuration.
+
+[[jht:
+When a Win95 machine logs onto a Windows NT Domain the Win95 machine looks
+for the presence of a file called Config.Pol in the following location:
+ \\"Authenticating Server"\NETLOGON
+It reads this file and uses it to ammend both the desktop environment as well
+as the file %WinDir%\Profiles\%USERNAME%\User.DAT. As with Windows NT, on log
+out this file gets written back to the profile server into the %USERNAME%
+directory in the profile share.
+
+It is thus possible to share a common desktop profile between Windows NT and
+Windows 9x.
+:jht]]
+
+
+4. There are a *LOT* of reasons that the 'doze machine might not find USER.DAT
+ and therefore default to a prototype.
+
+ 1. Can't execute logon script & therefore no /HOME mapping (Most common)
+ .Make sure the script exists
+ .that you have your logon script set right
+ .Netlogon share must exist
+ .Protection/ownership of the script and share
+
+ 2. no /HOME mapping in the logon script
+
+ 3. no home path specified in /etc/smb.conf (Or no home mapping set
+ up for that user in NT's user manager)
+
+ 4. Protection/ownership of the user directory
+
+ 5. protection/ownership of USER.DAT
+
+ 6. basic networking problems
+ .Is the networking available (Test it by manually mapping
+ to both the user share and netlogon share)
+ .Was the networking working during logon ?
+
+ 7. Has it defaulted to a prototype, and then had you map the home
+ directory afterwards ? - This will result in the bad prototype
+ being written into the users home, and them being stuck with it,
+ (Just replace USER.DAT again)
+
+
+5. Interesting NOTE
+
+ When '95 is performing the logon script, the HKEY_LOCAL_USERS has
+ NOT been mapped from the USER.DAT. What has been mapped at this stage
+ is the prototype registry (last one used).
+
+ I assume the reason for this is that '95 is waiting for the logon
+ script to complete so that it can identify where the user's home
+ directory is.
+
+ If at this point you attempt to do anything that uses the USER registry,
+ (installing something for example or reading something from the user
+ registry) you will actually be operating on the machine stored prototype
+ profile not the user profile. This means that nothing will realy
+ happen to the user setup (No menu items, no settings etc).
+
+ To get around this you can name a process in the "run once" entries in
+ the HKEY_LOCAL_MACHINE branch, and these "run once" processes will be
+ executed once the USER.DAT is loaded, and all the user directories are
+ accessible.
+
+
+To sum up:
+
+ NET USE H: /HOME
+ is the key to getting your user profiles loaded from a server.
+ NET USE H: \\server\homes
+ Won't get it right without a lot of stuffing about.
+
+ Windoze '95 goes through a lot to bring you your user profile and
+ if anything goes wrong during this process, it will drop back to
+ using whatever profile was last used on the machine.
+
+
+From samba@aquasoft.com.au Sat Apr 11 13:48:54 1998
+Date: Sat, 11 Apr 1998 09:34:08 +1000
+From: Samba Bugs <samba@aquasoft.com.au>
+To: Multiple recipients of list <samba-ntdom@samba.org>
+Subject: Re: A question about NT Domains
+
+Just for the sake of completeness I thought I'd add a bit to this.
+Let's be clear about which files affect registry changes (or contents).
+
+Under NT, open a command prompt interface:
+cd %SystemRoot%\System32\config
+dir
+
+The standard registry files are:
+ Default - all component default settings
+ System - all HKLM\System entries
+ Software - all HKLM\Software entries
+ Security - Domain/Machine releated User Rights & Privs.
+ SAM - the Security Access Manager database (ie:Passwords etc.)
+
+[[jht:
+The SAM and Security files are the only files that get synchronised between
+Windows NT Domain Controllers.
+:jht]]
+
+These are used by EVERYTHING!!
+
+When a user logs in the following files get checked:
+ 1) \\"Authenticating Server"\NETLOGON\NTConfig.Pol
+ 2) %SystemRoot%\Profiles\Policies\NTConfig.Pol
+ this one is a copy of the last NTConfig.Pol downloaded
+ from (1) above - if available.
+ 3) %SystemRoot%\Policies\%UserName%\NTUser.DAT
+
+[[jht:
+The System Policy Editor on Windows NT can be used to create both the
+Windows 95 "Config.Pol" file, as well as the Windows NT "NTConfig.Pol"
+file. To create the Windows 95 policy file you MUST load the Windows 95
+policy template BEFORE creating the Config.Pol file.
+:jht]]
+
+The later, is first obtained from a profile server if the User_Init_Info
+passed from the Domain Logon Server specifies use of a roaming profile.
+If item (3) does NOT exist and/or NO default profile is available one gets
+created from the system default settings PLUS the last loaded file at item
+(2) above.
+
+The HKCU is always unique to the currently logged in user, BUT if the
+currently logged in user is using a shared profile that has NOT been made
+exclusive then on logout the HKCU will be written over the top of the
+source files. That is why Mandatory profiles are essential when sharing a
+roaming profile.
+
+On Sat, 11 Apr 1998, Wolfgang Ratzka wrote:
+
+> Luke Kenneth Casson Leighton wrote:
+>
+> > my experience is with Win95, but i expect the same for NT, and have been
+> > told that it is so by someone who runs NT admin training courses.
+>
+> On NT it is quite definitely not so. HKCU will always be loaded completely from
+> the user's NTuser.dat file and unloaded again after logout.
+> In fact HKCU is not a proper registry hive but a symbolic reference to the subkey of
+> HKEY_USERS that corresponds to the current user. If more than one user
+> is active on an NT machine (on plain vanilla NT this *is* possible if you have
+> services running as a non-system user; on WinFrame or Hydra multiple users
+> can be logged in) you will see several subkeys of HKU that correspond to
+> the active users and don't interfere with each other.
+>
+> Of course some settings that a user can change do not go into the HKCU hive
+> but into HKLM, most notably the screen resolution and the number of colours
+> (you can use policies to prevent user's from changing these).
+> Some applications put information that should go into HKCU into HKLM instead.
+> (Hall of Shame: Netscape Communicator, Microsoft Office 97 [User dictionaries!]...).
+> Others just use plain good old INI files in their program directory or even
+> in \WINNT\SYSTEM32. Those changes will not be user specific but machine
+> specific and those programs will cause trouble, when one tries to run them
+> on WinFrame or Hydra... :-).
+>
+> Summarizing:
+>
+> Q: Will the next user inherit a previous user's additions
+> to the HKCU registry hive?
+> A: Quite definitely not.
+
+Correct.
+
+>
+> Q: Can a user foul up the configuration for the next user?
+> A: Quite definitely yes!
+
+See above. Yes, but not if correctly configured.
+
+>
+> Q: Is this discussion out of place on the samba-ntdom list?
+> A: Errr....
+
+Errr... Really? I think it is. Do we, or do we not, want to help people to
+gain stable and dependable use of samba?
+
+> --
+> Wolfgang Ratzka (dialing in from home)
+
+Cheers,
+John H Terpstra (Also from home!!!!)
+
+=============================================================================
+Further notes by Bruce Cook
+
+Date: Sun, 12 Apr 1998 14:12:22 +1000
+From: Bruce Cook <BC3-AU@bigfoot.com>
+Subject: Re: Win95 / NT Profiles (was: RE: A question about NT Domains)
+
+Ah yes I knew there was something I forgot.
+here it is for completeness.
+
+=============================================================================
+
+When a user logs into a specific machine for the first time, they will be
+told that they've never logged into the machine, and would they like to
+store the user setting for future use.
+
+If the user answers NO, they will be nagged about this every time they
+log into the machine until they say YES. (How about it MS, could we
+possible do something about this feature?)
+
+When the user answers YES, thereafter upon logging out of the machine,
+a copy of the user's profile is also written onto the machines local disk
+for later use.
+
+When a user logs into a machine where his/her profile has previously been
+saved, a comparison is made between the date of the profile copy kept on
+the machine, and the date of the profile stored on the server. In theory
+the server date should be later or the same.
+
+If the local machine date is later than the server date, the client
+machine will tell you the the settings on the local machine are more
+recent than those of the server, and would you like to user them instead.
+
+This occurs for a couple of reasons:
+ 1. Server not available when the user logs out
+ 2. Date mismatch between the server and the client
+ (I always use NET TIME \\server /SET /YES in my logon scripts)
+
+
+Logging in with NO server available.
+
+In some cases a client will want to log into a network with no server
+available. (Portables away from the office, or a dead server)
+
+This can only happen if the administrator has NOT set the machine to
+give access only upon password verification from the server.
+(If the admin has done this, it can be circumvented by restarting
+ the machine in safe mode, and running poledit, or regedit and
+ disabling that feature)
+
+If you are able to log in while the server is unavailable, you have
+two choices
+ 1. Log in as a user that previously stored a profile
+ (The password won't have to match unless the machine
+ is set up to store passwords)
+
+ 2. log in as the default user (bit the cancel button or escape key)
+
+If you choose to use your profile stored on the local machine, there are
+several things you should be wary of:
+ 1. the profile stored on the machine will be a copy of the last
+ profile used when you logged into THAT machine. You may get
+ quite an old profile.
+ 2. When you log out, that local profile is garunteed to be later
+ than the one on the server, and if the server is available, or
+ you later log into that machine when the server is available
+ you could overwrite the good server profile with a bogus profile.
+
+
+Technique note:
+ I set portable computers up so that they don't use roaming profiles,
+ rather they have a single profile kept on the machine. This means
+ that a user has the same desktop look an feel regardless of where
+ they are. This follows the philosophy that laptops tend to be used
+ by only one person.
diff --git a/docs/textdocs/Passwords.txt b/docs/textdocs/Passwords.txt
index e06876fecae..25d4c816f05 100644
--- a/docs/textdocs/Passwords.txt
+++ b/docs/textdocs/Passwords.txt
@@ -1,5 +1,9 @@
-NOTE ABOUT PASSWORDS
-====================
+Contributor: Unknown
+Date: Updated April 19th 1999.
+Status: Current
+
+Subject: NOTE ABOUT PASSWORDS
+=============================================================================
Unix systems use a wide variety of methods for checking the validity
of a password. This is primarily controlled with the Makefile defines
@@ -30,10 +34,10 @@ Unix password checking method you are using. Note that the AFS code is
only written and tested for AFS 3.3 and later.
-SECURITY = SERVER
-=================
+SECURITY = SERVER or DOMAIN
+===========================
-Samba can use a remote server to do it's username/password
+Samba can use a remote server to do its username/password
validation. This allows you to have one central machine (for example a
NT box) control the passwords for the Unix box.
diff --git a/docs/textdocs/Printing.txt b/docs/textdocs/Printing.txt
new file mode 100644
index 00000000000..b47120eaba9
--- /dev/null
+++ b/docs/textdocs/Printing.txt
@@ -0,0 +1,255 @@
+Contributor: Unknown <samba@samba.org>
+Revised by: Patrick Powell <papowell@lprng.org>
+Date: August 11, 2000
+Status: Current
+
+Subject: Dubugging Printing Problems
+=============================================================================
+
+This is a short description of how to debug printing problems with
+Samba. This describes how to debug problems with printing from a SMB
+client to a Samba server, not the other way around. For the reverse
+see the examples/printing directory.
+
+Please send enhancements to this file to samba@samba.org
+
+Ok, so you want to print to a Samba server from your PC. The first
+thing you need to understand is that Samba does not actually do any
+printing itself, it just acts as a middleman between your PC client
+and your Unix printing subsystem. Samba receives the file from the PC
+then passes the file to a external "print command". What print command
+you use is up to you.
+
+The whole things is controlled using options in smb.conf. The most
+relevant options (which you should look up in the smb.conf man page)
+are:
+ [global]
+ print command - send a file to a spooler
+ lpq command - get spool queue status
+ lprm command - remove a job
+ [printers]
+ path = /var/spool/lpd/samba
+
+The following are nice to know about:
+
+ queuepause command - stop a printer or print queue
+ queueresume command - start a printer or print queue
+
+Example:
+ print command = /usr/bin/lpr -r -P%p %s
+ lpq command = /usr/bin/lpq -P%p %s
+ lprm command = /usr/bin/lprm -P%p %j
+ queuepause command = /usr/sbin/lpc -P%p stop
+ queuepause command = /usr/sbin/lpc -P%p start
+
+Samba should set reasonable defaults for these depending on your
+system type, but it isn't clairvoyant. It is not uncommon that you
+have to tweak these for local conditions. The commands should
+always have fully specified pathnames, as the smdb may not have
+the correct PATH values.
+
+When you send a job to Samba to be printed, it will make a temporary
+copy of it in the directory specified in the [printers] section.
+and it should be periodically cleaned out. The lpr -r option
+requests that the temporary copy be removed after printing; If
+printing fails then you might find leftover files in this directory,
+and it should be periodically cleaned out. Samba used the lpq
+command to determine the "job number" assigned to your print job
+by the spooler.
+
+The %<letter> are "macros" that get dynamically replaced with appropriate
+values when they are used. The %s gets replaced with the name of the spool
+file that Samba creates and the %p gets replaced with the name of the
+printer. The %j gets replaced with the "job number" which comes from
+the lpq output.
+
+DEBUGGING PRINTER PROBLEMS
+
+One way to debug printing problems is to start by replacing these
+command with shell scripts that record the arguments and the contents
+of the print file. A simple example of this kind of things might
+be:
+
+ print command = /tmp/saveprint %p %s
+
+ #!/bin/saveprint
+ # we make sure that we are the right user
+ /usr/bin/id -p >/tmp/tmp.print
+ # we run the command and save the error messages
+ # replace the command with the one appropriate for your system
+ /usr/bin/lpr -r -P$1 $2 2>>&/tmp/tmp.print
+
+Then you print a file and try removing it. You may find that the
+print queue needs to be stopped in order to see the queue status
+and remove the job:
+
+h4: {42} % echo hi >/tmp/hi
+h4: {43} % smbclient //localhost/lw4
+added interface ip=10.0.0.4 bcast=10.0.0.255 nmask=255.255.255.0
+Password:
+Domain=[ASTART] OS=[Unix] Server=[Samba 2.0.7]
+smb: \> print /tmp/hi
+putting file /tmp/hi as hi-17534 (0.0 kb/s) (average 0.0 kb/s)
+smb: \> queue
+1049 3 hi-17534
+smb: \> cancel 1049
+Error cancelling job 1049 : code 0
+smb: \> cancel 1049
+Job 1049 cancelled
+smb: \> queue
+smb: \> exit
+
+The 'code 0' indicates that the job was removed. The comment
+by the smbclient is a bit misleading on this.
+You can observe the command output and then and look at the
+/tmp/tmp.print file to see what the results are. You can quickly
+find out if the problem is with your printing system. Often people
+have problems with their /etc/printcap file or permissions on
+various print queues.
+
+WHAT PRINTERS DO I HAVE
+
+You can use the 'testprns' program to check to see if the printer
+name you are using is recognized by Samba. For example, you can
+use:
+
+ testprns printer /etc/printcap
+
+Samba can get its printcap information from a file or from a program.
+You can try the following to see the format of the extracted
+information:
+
+ testprns -a printer /etc/printcap
+
+ testprns -a printer '|/bin/cat printcap'
+
+SETTING UP PRINTCAP AND PRINT SERVERS
+
+You may need to set up some printcaps for your Samba system to use.
+It is strongly recommended that you use the facilities provided by
+the print spooler to set up queues and printcap information.
+
+Samba requires either a printcap or program to deliver printcap
+information. This printcap information has the format:
+
+ name|alias1|alias2...:option=value:...
+
+For almost all printing systems, the printer 'name' must be composed
+only of alphanumeric or underscore '_' characters. Some systems also
+allow hyphens ('-') as well. An alias is an alternative name for the
+printer, and an alias with a space in it is used as a 'comment'
+about the printer. The printcap format optionally uses a \ at the end of lines
+to extend the printcap to multiple lines.
+
+
+Here are some examples of printcap files:
+
+pr just printer name
+pr|alias printer name and alias
+pr|My Printer printer name, alias used as comment
+pr:sh:\ Same as pr:sh:cm= testing
+ :cm= \
+ testing
+pr:sh Same as pr:sh:cm= testing
+ :cm= testing
+
+Samba reads the printcap information when first started. If you make
+changes in the printcap information, then you must do the following:
+
+a) make sure that the print spooler is aware of these changes.
+ The LPRng system uses the 'lpc reread' command to do this.
+
+b) make sure that the spool queues, etc., exist and have the
+ correct permissions. The LPRng system uses the 'checkpc -f'
+ command to do this.
+
+c) You now should send a SIGHUP signal to the smbd server to have
+ it reread the printcap information.
+
+JOB SENT, NO OUTPUT
+
+This is the most frustrating part of printing. You may have sent the
+job, verified that the job was forwarded, set up a wrapper around
+the command to send the file, but there was no output from the printer.
+
+First, check to make sure that the job REALLY is getting to the
+right print queue. If you are using a BSD or LPRng print spooler,
+you can temporarily stop the printing of jobs. Jobs can still be
+submitted, but they will not be printed. Use:
+
+ lpc -Pprinter stop
+
+Now submit a print job and then use 'lpq -Pprinter' to see if the
+job is in the print queue. If it is not in the print queue then
+you will have to find out why it is not being accepted for printing.
+
+Next, you may want to check to see what the format of the job really
+was. With the assistance of the system administrator you can view
+the submitted jobs files. You may be surprised to find that these
+are not in what you would expect to call a printable format.
+You can use the UNIX 'file' utitily to determine what the job
+format actually is:
+
+ cd /var/spool/lpd/printer # spool directory of print jobs
+ ls # find job files
+ file dfA001myhost
+
+You should make sure that your printer supports this format OR that
+your system administrator has installed a 'print filter' that will
+convert the file to a format appropriate for your printer.
+
+JOB SENT, STRANGE OUTPUT
+
+Once you have the job printing, you can then start worrying about
+making it print nicely.
+
+The most common problem is extra pages of output: banner pages
+OR blank pages at the end.
+
+If you are getting banner pages, check and make sure that the
+printcap option or printer option is configured for no banners.
+If you have a printcap, this is the :sh (suppress header or banner
+page) option. You should have the following in your printer.
+
+ printer: ... :sh
+
+If you have this option and are still getting banner pages, there
+is a strong chance that your printer is generating them for you
+automatically. You should make sure that banner printing is disabled
+for the printer. This usually requires using the printer setup software
+or procedures supplied by the printer manufacturer.
+
+If you get an extra page of output, this could be due to problems
+with your job format, or if you are generating PostScript jobs,
+incorrect setting on your printer driver on the MicroSoft client.
+For example, under Win95 there is a option:
+
+ Printers|Printer Name|(Right Click)Properties|Postscript|Advanced|
+
+that allows you to choose if a Ctrl-D is appended to all jobs.
+This is a very bad thing to do, as most spooling systems will
+automatically add a ^D to the end of the job if it is detected as
+PostScript. The multiple ^D may cause an additional page of output.
+
+RAW POSTSCRIPT PRINTED
+
+This is a problem that is usually caused by either the print spooling
+system putting information at the start of the print job that makes
+the printer think the job is a text file, or your printer simply
+does not support PostScript. You may need to enable 'Automatic
+Format Detection' on your printer.
+
+ADVANCED PRINTING
+
+Note that you can do some pretty magic things by using your
+imagination with the "print command" option and some shell scripts.
+Doing print accounting is easy by passing the %U option to a print
+command shell script. You could even make the print command detect
+the type of output and its size and send it to an appropriate
+printer.
+
+DEBUGGING
+
+If the above debug tips don't help, then maybe you need to bring in
+the bug guns, system tracing. See Tracing.txt in this directory.
+-----------------------------------------------------------------------------
diff --git a/docs/textdocs/README.DCEDFS b/docs/textdocs/README.DCEDFS
index f84b84bb686..da9bb2197da 100644
--- a/docs/textdocs/README.DCEDFS
+++ b/docs/textdocs/README.DCEDFS
@@ -1,9 +1,8 @@
-=============================================================================
-
- Basic DCE/DFS Support for SAMBA 1.9.13
-
- Jim Doyle <doyle@oec.com> 06-02-95
+Contributor: Jim Doyle <doyle@oec.com>
+Date: 06-02-95
+Status: Current but needs updating
+Subject: Basic DCE/DFS Support for SAMBA 1.9.13
=============================================================================
Functionality:
diff --git a/docs/textdocs/README.NOW b/docs/textdocs/README.NOW
new file mode 100644
index 00000000000..1184a9d057f
--- /dev/null
+++ b/docs/textdocs/README.NOW
@@ -0,0 +1,8 @@
+The files in the directory have either yet to
+converted into SGML/DocBook format or are outdated.
+To create ASCII versions of the documentation
+in the ../htmldocs/ directory, run
+
+ $ lynx -dump file.html > file.txt
+
+
diff --git a/docs/textdocs/README.jis b/docs/textdocs/README.jis
index 2ac6716a6f6..50ff0cced74 100644
--- a/docs/textdocs/README.jis
+++ b/docs/textdocs/README.jis
@@ -14,6 +14,10 @@
$B$rL\E*$H$7$F$$$^$9!#$=$N$?$a!"F|K\8lBP1~$O!"I,MW:G>.8B$7$+9T$J$C$F$*$j$^$;$s!#(B
+ $BF|K\8lBP1~$7$?(B samba $B$rMxMQ$9$k$?$a$K$O!"%3%s%Q%$%k$9$k;~$K!"I,$:!"(BKANJI $B$NDj5A$rDI(B
+ $B2C$7$F$/$@$5$$!#$3$N%*%W%7%g%s$r;XDj$7$F$$$J$$>l9g$O!"F|K\8l$N%U%!%$%kL>$r@5$7$/07(B
+ $B$&$3$H$O$G$-$^$;$s!#!J%3%s%Q%$%k$K$D$$$F$O!"2<5-(B 3. $B$r;2>H$7$F2<$5$$!K(B
+
2. $BMxMQJ}K!(B
(1) $BDI2C$7$?%Q%i%a!<%?(B
@@ -34,6 +38,12 @@
$B$N(B16$B?J?t$rB3$1$k7A<0$K$J$j$^$9!#(B
$B$3$3$G!"(B':' $B$rB>$NJ8;z$KJQ99$7$?$$>l9g$O!"(Bhex $B$N8e$m$K$=$NJ8;z$r;XDj$7$^$9!#(B
$BNc$($P!"(B@$B$rJQ$o$j$K;H$$$?$$>l9g$O!"(B'hex@'$B$N$h$&$K;XDj$7$^$9!#(B
+ cap: 7 bits $B$N(B ASCII $B%3!<%I0J30$N%3!<%I$r0J2<$N7A<0$GI=$9J}<0$H$$$&E@$G$O(B
+ hex$B$HF1MM$G$9$,!"(BCAP (The Columbia AppleTalk Package)$B$H8_49@-$r;}$DJQ49(B
+ $BJ}<0$H$J$C$F$$$^$9!#(Bhex$B$H$N0c$$$O(B0x80$B0J>e$N%3!<%I$N$_(B':80'$B$N$h$&$KJQ49(B
+ $B$5$l!"$=$NB>$O(BASCII$B%3!<%I$G8=$5$l$^$9!#(B
+ $BNc$($P!"(B'$B%*%U%#%9(B'$B$H$$$&L>A0$O!"(B':83I:83t:83B:83X'$B$H$J$j$^$9!#(B
+
JIS $B%3!<%I$K$D$$$F$O!"0J2<$NI=$r;2>H$7$F2<$5$$!#(B
$B(#(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(!(!(!(!(!($(B
$B(";XDj(B $B("4A;z3+;O("4A;z=*N;("%+%J3+;O("%+%J=*N;("1Q?t3+;O("Hw9M(B $B("(B
@@ -90,6 +100,8 @@
$B%$%kL>$O!"(BEUC $B%3!<%I$K$J$j$^$9!#$3$3$G;XDj$7$?%3!<%I7O$O!"%5!<%P5Z$S%/%i%$%"%s%H(B
$B%W%m%0%i%`$N%G%U%)%k%H$KCM$J$j$^$9!#(B
+ $B>0!"%*%W%7%g%sCf$N(B \ $B$d(B " $B$bK:$l$:$K;XDj$7$F2<$5$$!#(B
+
3. $B@)8B;v9`(B
(1) $B4A;z%3!<%I(B
@@ -104,21 +116,34 @@
$B$A$c$s$H$7$?%9%Z%C%/$,$h$/$o$+$i$J$+$C$?$N$G$9$,!"0l1~!"(BDOS/V $B$NF0:n$HF1$8F0:n$r9T$J(B
$B$&$h$&$K$J$C$F$$$^$9!#(B
+(4) $B%m%s%0%U%!%$%kL>$K$D$$$F(B
+ Windows NT/95 $B$G$O!"%m%s%0%U%!%$%kL>$,07$($^$9!#%m%s%0%U%!%$%kL>$r(B 8.3 $B%U%)!<%^%C%H(B
+ $B$G07$&$?$a$K!"(Bmangling $B$7$F$$$^$9$,!"$3$NJ}K!$O!"(BNT $B$d(B 95 $B$,9T$J$C$F$$$k(B mangling $B$H(B
+ $B$O0[$J$j$^$9$N$GCm0U$7$F2<$5$$!#(B
+
4. $B>c32Ey$N%l%]!<%H$K$D$$$F(B
$BF|K\8l$N%U%!%$%kL>$K4X$7$F!"J8;z2=$1Ey$N>c32$,$"$l$P!";d$K%l%]!<%H$7$FD:$1$l$P9,$$$G(B
$B$9!#$?$@$7!"%*%j%8%J%k$+$i$NLdBjE@$d<ALd$K$D$$$F$O!"%*%j%8%J%k$N:n<T$XD>@\Ld$$9g$o$;$k(B
$B$+!"$b$7$/$O%a!<%j%s%0%j%9%H$J$I$X%l%]!<%H$9$k$h$&$K$7$F2<$5$$!#(B
+$B%l%]!<%H$5$l$k>l9g!"MxMQ$5$l$F$$$k4D6-(B(UNIX $B5Z$S(B PC $BB&$N(BOS$B$J$I(B)$B$H$G$-$^$7$?$i@_Dj%U%!(B
+$B%$%k$d%m%0$J$I$rE:IU$7$FD:$1$k$H9,$$$G$9!#(B
+
5. $B$=$NB>(B
- hex $B7A<0$NJQ49J}K!$O!"(B
+ $B%3!<%IJQ49$O0J2<$NJ}!9$,:n$i$l$?%W%m%0%i%`$rMxMQ$7$F$$$^$9!#(B
- $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ hex $B7A<0(B $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ cap $B7A<0(B $BI%ED(B $BF;O:(B (michiro@po.iijnet.or.jp)(michiro@dms.toppan.co.jp)$B;a(B
- $B$,:n$i$l$?%3!<%I$rMxMQ$7$F$$$^$9!#(B
+ $B$=$NB>!"$?$/$5$s$NJ}!9$+$i$$$m$$$m$H8f65<($$$?$@$-$"$j$,$H$&$4$6$$$^$7$?!#:#8e$H$b$h(B
+$B$m$7$/$*4j$$CW$7$^$9!#(B
1994$BG/(B10$B7n(B28$BF|(B $BBh#1HG(B
1995$BG/(B 8$B7n(B16$BF|(B $BBh#2HG(B
+1995$BG/(B11$B7n(B24$BF|(B $BBh#3HG(B
+1996$BG/(B 5$B7n(B13$BF|(B $BBh#4HG(B
+
$BF#ED(B $B?r(B fujita@ainix.isac.co.jp
diff --git a/docs/textdocs/README.sambatar b/docs/textdocs/README.sambatar
index 26829952eb6..af7250c2a49 100644
--- a/docs/textdocs/README.sambatar
+++ b/docs/textdocs/README.sambatar
@@ -1,3 +1,11 @@
+Contributor/s: Martin.Kraemer <Martin.Kraemer@mch.sni.de>
+ and Ricky Poulten (ricky@logcam.co.uk)
+Date: Unknown - circa 1994
+Status: Obsoleted - smbtar has been a stable part of Samba
+ since samba-1.9.13
+
+Subject: Sambatar (now smbtar)
+=============================================================================
This is version 1.4 of my small extension to samba that allows PC shares
to be backed up directly to a UNIX tape. It only has been tested under
diff --git a/docs/textdocs/Recent-FAQs.txt b/docs/textdocs/Recent-FAQs.txt
new file mode 100644
index 00000000000..feed1278277
--- /dev/null
+++ b/docs/textdocs/Recent-FAQs.txt
@@ -0,0 +1,286 @@
+Contributor: Samba-bugs@samba.org
+Date: July 5, 1998
+Status: Current
+
+=============================================================================
+Subject: Recent FAQ answers to common questions / problems
+=============================================================================
+Contents: NetWkstaUserLogon
+ Not listening for calling name
+ System Error 1240
+ Trapdoor UID
+ User Access Control
+ Using NT to Browse Samba Shares
+ setup.exe and 16 bit programs
+ smbclient -N
+
+NetWkstaUserLogon
+=================
+FAQ answer about the new password server code:
+
+In 1.9.18 you can disable the NetWkstaUserLogon call at compile time
+in local.h and from 1.9.18p3 you can now disable it from an option in
+your smb.conf.
+
+The password server behaviour changed because we discovered that bugs
+in some NT servers allowed anyone to login with no password if they
+chose an account name that did not exist on the password server. The
+NT password server was saying "yes, it's OK to login" even when the
+account didn't exist at all! Adding the NetWkstaUserLogon call fixed
+the problem, and follows the "recommended" method that MS have
+recently documented for pass through authentication.
+
+The problem now is that some NT servers (in particular NT
+workstation?) don't support the NetWkstaUserLogon call. The call also
+doesn't work for accounts in trust relationships.
+
+The eventual solution for this will be to replace the password server
+code in Samba with NT domain code as that is developed. For now you
+have the choice of compiling Samba either with or without the
+NetWkstaUserLogon call in the password server code.
+
+In 1.9.18p3 the following was added (copied from the 1.9.18p3 release
+notes):
+
+In the [global] section of smb.conf :
+
+networkstation user login
+
+This code (submitted by Rob Nielsen) allows the code many people
+were having problems with that queries an NT password server to
+be turned off at runtime rather than compile time. Please see the
+documentation in the smb.conf manual page for details. This is a
+security option - it must only be turned off after checks have been
+made to ensure that your NT password server does not suffer from the
+bug this code was meant to protect against !
+
+In 1.9.18 you can enable/disable this call in local.h. In 1.9.17p5
+you could apply the following patch. Applying this patch will make
+the password server code behave like the code in earlier versions
+of Samba. If you do this then please ensure that you test to see
+that users are prevented from logging in if they give a bogus
+username/password. You may have a NT server that is affected by the
+bug that this code is designed to avoid.
+
+
+--- password.c 1997/10/21 10:09:28 1.25.2.4
++++ password.c 1997/12/31 06:43:06
+@@ -1619,6 +1619,7 @@
+ }
+
+
++#if 0
+ if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) {
+ DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost));
+ cli_tdis(&cli);
+@@ -1638,6 +1639,7 @@
+ cli_tdis(&cli);
+ return False;
+ }
++#endif
+
+ DEBUG(3,("password server %s accepted the password\n", cli.desthost));
+===============================================================================
+
+Not listening for calling name
+==============================
+
+> Session request failed (131,129) with myname=HOBBES destname=CALVIN
+> Not listening for calling name
+
+If you get this when talking to a Samba box then it means that your
+global "hosts allow" or "hosts deny" settings are causing the Samba
+server to refuse the connection.
+
+Look carefully at your "hosts allow" and "hosts deny" lines in the
+global section of smb.conf.
+
+It can also be a problem with reverse DNS lookups not functioning
+correctly, leading to the remote host identity not being able to
+be confirmed, but that is less likely.
+===============================================================================
+
+System Error 1240
+=================
+System error 1240 means that the client is refusing to talk
+to a non-encrypting server. Microsoft changed WinNT in service
+pack 3 to refuse to connect to servers that do not support
+SMB password encryption.
+
+There are two main solutions:
+
+1) enable SMB password encryption in Samba. See ENCRYPTION.txt in the
+Samba docs
+
+2) disable this new behaviour in NT. See WinNT.txt in the
+Samba docs
+===============================================================================
+
+Trapdoor UID
+============
+> Log message "you appear to have a trapdoor uid system"
+
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.
+
+It might also mean that your OS has a trapdoor uid/gid system :-)
+
+This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.
+
+The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.
+
+Complain to your OS vendor and ask them to fix their system.
+
+Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!
+===============================================================================
+
+User Access Control
+===================
+> In windows when i set up a share in "user mode" i get the message:
+> "You cannot view the list of users at this time. Please try again later."
+>
+> I know you have lists of users for access and aliasing purposes, but i
+> have read nothing to support the idea that these lists control the Domain
+> Users List...
+
+Samba does NOT at this time support user mode access control for Window 9x
+of for NT. This is a priority item and requires full implementation of the NT SMB
+protocol calls. Samba-1.9.19 will go into alpha in about 2 months time and will
+have a more full implementation of the NT SMB protocols to support Domain Client
+interoperability. When we can see that this has been succesful we wil then implement
+the NT SMB Server components. This will probably be released as Samba-2.0
+
+Samba-1.9.18p5 is scheduled to go out within 14 days. This will close off the 1.9.18
+branch and then opens the way to progress 1.9.19.
+
+I hope this answers your concerns adequately.
+===============================================================================
+
+Using NT to Browse Samba Shares
+===============================
+> WIN-NT workstations (nt4.0, service pack 3)
+> samba with
+> security = user
+> encrypt passwords = yes
+> guest account = guest
+>
+> start the explorer on a win-nt workstation and select network. I find
+> my unix server running samba, but I can not see the list of shares
+> unless I am a user, who is known in the smbpasswd of the unix machine.
+> The guest account "guest" exists on my unix machine. For testing I even
+> made him a regular user with a password.
+>
+> With my network monitor I can see, that the win-nt workstation uses the
+> current login, to connect to IPC$ on the samba server
+> (for example "administrator"), not the guest account.
+
+This is exactly how Windows NT works. You MUST have a valid account on the Windows
+NT box you are trying to see the resource list on. If your currently logged in
+account details do NOT match an account on the NT machine you are trying to access
+then you will be presented with a logon box for that machine. When you enter the
+name of an account on that machine / domain, together with a valid password then
+the resource list is made available. If the account details are not correct then
+no resource list is shown.
+
+Samba follows the behaviour of Windows NT exactly.
+
+Warning:Warning:Warning:
+========================
+Samba can be compiled with the GUEST_SESSION_SETUP option at 0,1 or 2.
+The default is 0. If this is set to 1 or 2 then Windows NT machines that DO NOT
+have an account on the Samba server will see the resource list. The down side of this
+is that legitimate users may then be refused access to their legitimate resources.
+Setting this option creates serious security holes. DO NOT DO IT. Samba has the
+value of this option set at 0 - NOT WITHOUT REASON!!!!
+
+******> Warning:Warning:Warning: ****> Do not tamper with this setting!!!
+===============================================================================
+
+setup.exe and 16 bit programs
+=============================
+Running 16 bit programs from Windows NT on a Samba mapped drive
+---------------------------------------------------------------
+
+The Windows NT redirector has a bug when running against a
+Samba or Windows 95 mapped drive and attempting to run a
+16 bit executable.
+
+The problem occurs when the pathname to a 16 bit executable
+contains a non 8.3 filename complient directory component,
+Windows NT will fail to load the program and complain it
+cannot find the path to the program.
+
+It can be verified that this is a bug in Windows NT and
+not Samba as the same problem can be reproduced exactly
+when attempting to run the same program with the same
+pathname from a Windows 95 server (ie. the problem still
+exists even with no Samba server involved).
+
+Microsoft have been made aware of this problem, it is
+unknown if they regard it as serious enough to provide
+a fix for this.
+
+One of the reasons this problem is reported frequently
+is that InstallShield setup.exe executables are frequently
+written as 16 bit programs, and so hit this problem.
+
+As a workaround, you may create (on a Samba server at
+least) a symbolic link with an 8.3 complient name to
+the non 8.3 complient directory name, and then the 16
+bit program will run. Alternatively, use the 8.3
+complient mangled name to specify the path to run
+the binary.
+
+This will be fixed when Samba adds the NT-specific
+SMB calls (currently targeted for the next major
+Samba release), as once the NT SMB calls are used
+this problem no longer occurs (which is why the
+problem doesn't occur when running against a drive
+mapped to a Windows NT server).
+
+Regards,
+
+ Jeremy Allison.
+ Samba Team.
+===============================================================================
+
+smbclient -N
+============
+> When getting the list of shares available on a host using the command
+> smbclient -N -L <server>
+> the program always prompts for the password if the server is a Samba server.
+> It also ignores the "-N" argument when querying some (but not all) of our
+> NT servers.
+
+No, it does not ignore -N, it is just that your server rejected the
+null password in the connection, so smbclient prompts for a password
+to try again.
+
+To get the behaviour that you probably want use
+ smbclient -L host -U%
+
+this will set both the username and password to null, which is
+an anonymous login for SMB. Using -N would only set the password
+to null, and this is not accepted as an anonymous login for most
+SMB servers.
+===============================================================================
+
diff --git a/docs/textdocs/RoutedNetworks.txt b/docs/textdocs/RoutedNetworks.txt
new file mode 100644
index 00000000000..fb55f9f9bf0
--- /dev/null
+++ b/docs/textdocs/RoutedNetworks.txt
@@ -0,0 +1,63 @@
+#NOFNR Flag in LMHosts to Communicate Across Routers
+
+ Last reviewed: May 5, 1997
+ Article ID: Q103765
+ The information in this article applies to:
+
+ Microsoft Windows NT operating system version 3.1
+ Microsoft Windows NT Advanced Server version 3.1
+
+ SUMMARY
+
+ Some of the LAN Manager for UNIX and Pathworks servers may have
+problems in communicating across routers with
+ Windows NT workstations. The use of #NOFNR flag in the LMHosts
+file solves the problem.
+
+ MORE INFORMATION
+
+ When you are communicating with a server across a router in a IP
+routed environment, the LMHosts file is used to
+ resolve Workstation name-to-IP address mapping. The LMHosts
+entry for a remote machine name provides the IP
+ address for the remote machine. In Lan Manager 2.x, providing
+the LMHosts entry eliminates the need to do a Name
+ Query broadcast to the local domain and instead a TCP session is
+established with the remote machine. Windows NT
+ performs the same function in a different way.
+
+ When an LMHosts entry exists for a remote server, Windows NT
+will not send a Name Query broadcast to the local
+ subnet and instead send a directed Name Query to the remote
+server. If the remote server does not respond to the Name
+ Query, further communications (TCP SYN, and so on) will not take
+place. This was done to eliminate the performance
+ issues when trying to connect to a remote machine when it was
+not available (down).
+
+ Some of the older LAN Manager for UNIX and DEC Pathworks servers
+do not respond to directed Name Queries sent
+ by Windows NT. In that case, the users will see an error 53
+(Path not found), even though they have specified the
+ LMHosts entries correctly. A new LMHosts flag #NOFNR was added
+to solve this problem. By specifying the
+ #NOFNR flag on the same line where the name resolution
+information for the server is provided, the directed Name
+ Query can be avoided. For example:
+
+ 130.20.1.1 mylmxserver #PRE #NOFNR
+
+
+ Note that this will only apply to mylmxserver and not to any
+other entries in the LMHosts file. To set
+ a global flag, an entry could be added in the registry. To
+completely remove any directed Name
+ Queries sent from a Windows NT machine, create the following
+value in
+
+HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Nbt\Parameters:
+
+ NoDirectedFNR REG_DWORD 1
+
+
+ This will cause the directed Name Queries to not go out for any
diff --git a/docs/textdocs/SCO.txt b/docs/textdocs/SCO.txt
index 1b3801471f7..7c01aa57c6c 100644
--- a/docs/textdocs/SCO.txt
+++ b/docs/textdocs/SCO.txt
@@ -1,4 +1,11 @@
-There is an annoying TCPIP bug in SCO Unix. This causes orruption when
+Contributor: Geza Makay <makayg@math.u-szeged.hu>
+Date: Unknown
+Status: Obsolete - Dates to SCO Unix v3.2.4 approx.
+
+Subject: TCP/IP Bug in SCO Unix
+============================================================================
+
+There is an annoying TCPIP bug in SCO Unix. This causes corruption when
transferring files with Samba.
Geza Makay (makayg@math.u-szeged.hu) sends this information:
diff --git a/docs/textdocs/SMBTAR.notes b/docs/textdocs/SMBTAR.notes
index a23cbf2b325..679d776f56c 100644
--- a/docs/textdocs/SMBTAR.notes
+++ b/docs/textdocs/SMBTAR.notes
@@ -1,3 +1,9 @@
+Contributor: Unknown
+Date: 1994
+Status: Mostly Current - refer man page
+
+Subject: Smbtar
+============================================================================
Intro
-----
@@ -37,4 +43,4 @@ newer filename
into its own with sambatar. This causes tar (or get, mget, etc) to
only copy files newer than the specified file name. Could be used
against the previous nights (or whatever) log file to implement incremental
-backups. \ No newline at end of file
+backups.
diff --git a/docs/textdocs/Samba-OpenSSL.txt b/docs/textdocs/Samba-OpenSSL.txt
new file mode 100644
index 00000000000..e1b54b1a032
--- /dev/null
+++ b/docs/textdocs/Samba-OpenSSL.txt
@@ -0,0 +1,405 @@
+Contributor: Christian Starkjohann <cs@obdev.at>
+Date: May 29, 1998
+Status:
+
+Comment: Updated by Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+Date: July 16, 2001
+
+Subject: Compiling and using samba with SSL support
+============================================================================
+
+What is SSL and SSLeay/OpenSSL?
+===============================
+SSL (Secure Socket Layer) is a protocol for encrypted and authenticated data
+transport. It is used by secure web servers for shopping malls, telebanking
+and things like that.
+
+SSLeay is a free implementation of the SSL protocol. The successor of it is
+OpenSSL, available from
+
+ http://www.openssl.org/
+
+The current version while these lines are written is 0.9.6b. In some countries
+encryption is plagued by legal problems, even though things have relaxed a
+lot in the last years.
+
+To compile samba with SSL support, you must first compile and install OpenSSL.
+At least version 0.9.5 of OpenSSL is required. Version 0.9.6b is the latest
+version and is strongly recommended.
+OpenSSL consists of a library (which can be linked to other applications like
+samba) and several utility programs needed for key generation, certification
+etc. OpenSSL installs to /usr/local/ssl/ by default.
+
+
+Compiling samba with OpenSSL
+============================
+1. Get and install OpenSSL. The rest of this documentation assumes that you
+ have installed it at the default location, which is /usr/local/ssl/.
+2. Call "configure" with the "--with-ssl" flag. If OpenSSL is not installed in
+ the default directory, you can use the "--with-sslinc" and "--with-ssllib"
+ flags to specify the location.
+3. Compile and install as usual.
+
+
+Configuring SSL in samba
+========================
+Before you configure SSL, you should know the basics of cryptography and how
+SSL relates to all of this. A basic introduction can be found further down in
+this document. The following variables in the "[global]" section of the
+configuration file are used to configure SSL:
+
+ssl = yes
+ This variable enables or disables the entire SSL mode. If it is set to
+ "no", the SSL enabled samba behaves exactly like the non-SSL samba. If set
+ to "yes", it depends on the variables "ssl hosts" and "ssl hosts resign"
+ whether an SSL connection will be required.
+ssl hosts =
+ssl hosts resign = 192.168.
+ These two variables define whether samba will go into SSL mode or not. If
+ none of them is defined, samba will allow only SSL connections. If the
+ "ssl hosts" variable lists hosts (by IP-address, IP-address range, net
+ group or name), only these hosts will be forced into SSL mode. If the
+ "ssl hosts resign" variable lists hosts, only these hosts will NOT be
+ forced into SSL mode. The syntax for these two variables is the same as
+ for the "hosts allow" and "hosts deny" pair of variables, only that the
+ subject of the decision is different: It's not the access right but
+ whether SSL is used or not. See the man page of smb.conf (section about
+ "allow hosts") for details. The above example requires SSL connections
+ from all hosts outside the local net (which is 192.168.*.*).
+ssl CA certDir = /usr/local/ssl/certs
+ This variable defines where to look up the Certification Autorities. The
+ given directory should contain one file for each CA that samba will trust.
+ The file name must be the hash value over the "Distinguished Name" of the
+ CA. How this directory is set up is explained later in this document. All
+ files within the directory that don't fit into this naming scheme are
+ ignored. You don't need this variable if you don't verify client
+ certificates.
+ssl CA certFile = /usr/local/ssl/certs/trustedCAs.pem
+ This variable is a second way to define the trusted CAs. The certificates
+ of the trusted CAs are collected in one big file and this variable points
+ to the file. You will probably only use one of the two ways to define your
+ CAs. The first choice is preferable if you have many CAs or want to be
+ flexible, the second is perferable if you only have one CA and want to
+ keep things simple (you won't need to create the hashed file names). You
+ don't need this variable if you don't verify client certificates.
+ssl server cert = /usr/local/ssl/certs/samba.pem
+ This is the file containing the server's certificate. The server _must_
+ have a certificate. The file may also contain the server's private key.
+ See later for how certificates and private keys are created.
+ssl server key = /usr/local/ssl/private/samba.pem
+ This file contains the private key of the server. If this variable is not
+ defined, the key is looked up in the certificate file (it may be appended
+ to the certificate). The server _must_ have a private key and the
+ certificate _must_ match this private key.
+ssl client cert = /usr/local/ssl/certs/smbclient.pem
+ The certificate in this file is used by smbclient if it exists. It's needed
+ if the server requires a client certificate.
+ssl client key = /usr/local/ssl/private/smbclient.pem
+ This is the private key for smbclient. It's only needed if the client
+ should have a certificate.
+ssl require clientcert = yes
+ If this variable is set to "yes", the server will not tolerate connections
+ from clients that don't have a valid certificate. The directory/file
+ given in "ssl CA certDir" and "ssl CA certFile" will be used to look up
+ the CAs that issued the client's certificate. If the certificate can't be
+ verified positively, the connection will be terminated.
+ If this variable is set to "no", clients don't need certificates. Contrary
+ to web applications you really _should_ require client certificates. In
+ the web environment the client's data is sensitive (credit card numbers)
+ and the server must prove to be trustworthy. In a file server environment
+ the server's data will be sensitive and the clients must prove to be
+ trustworthy.
+ssl require servercert = yes
+ If this variable is set to "yes", the smbclient will request a certificate
+ from the server. Same as "ssl require clientcert" for the server.
+ssl ciphers = ???
+ This variable defines the ciphers that should be offered during SSL
+ negotiation. You should not set this variable unless you know what you do.
+ssl version = ssl2or3
+ This enumeration variable defines the versions of the SSL protocol that
+ will be used. "ssl2or3" allows dynamic negotiation of SSL v2 or v3, "ssl2"
+ results SSL v2, "ssl3" results in SSL v3 and "tls1" results in TLS v1. TLS
+ (Transport Layer Security) is the (proposed?) new standard for SSL. The
+ default value is "ssl2or3".
+ssl compatibility = no
+ This variable defines whether SSLeay should be configured for bug
+ compatibility with other SSL implementations. This is probably not
+ desirable because currently no clients with SSL implementations other than
+ SSLeay exist.
+ssl entropy file =
+ Specifies a file from which processes will read "random bytes" on startup.
+ In order to seed the internal pseudo random number generator, entropy
+ must be provided. On system with a /dev/urandom device file, the processes
+ will retrieve its entropy from the kernel. On systems without kernel
+ entropy support, a file can be supplied that will be read on startup
+ and that will be used to seed the PRNG.
+ssl entropy bytes = 256
+ Number of bytes that will be read from entropy file. If -1 is given, the
+ complete file will be read.
+ssl egd socket =
+ Location of the communiation socket of an EGD or PRNGD daemon, from which
+ entropy can be retrieved. This option can be used instead of or together
+ with the "ssl entropy file" directive. 255bytes of entropy will be
+ retrieved from the daemon.
+
+
+Running samba with OpenSSL
+==========================
+Samba is started as usual. The daemon will ask for the private key's pass
+phrase before it goes to background if the private key has been encrypted.
+If you start smbd from inetd, this won't work. Therefore you must not encrypt
+your private key if you run smbd from inetd.
+
+Windows clients will try to connect to the SSL enabled samba daemon and they
+will fail. This can fill your log with failed SSL negotiation messages. To
+avoid this, you can either not run nmbd (if all clients use DNS to look up
+the server), which will leave the Windows machine unaware of the server, or
+list all (local) Windows machines in the "ssl hosts resign" variable.
+
+
+About certificates
+==================
+Secure samba servers will not be set up for public use as it is the case with
+secure web servers. Most installations will probably use it for distributed
+offices that use parts of the internet for their intranet, for access to a
+web server that's physically hosted by the provider or simply for teleworking.
+All these applications work with a known group of users that can easily agree
+on a certification authority. The CA can be operated by the company and the
+policy for issuing certificates can be determined by the company. If samba is
+configured to verify client certificates, it (currently) only verifies
+whether a valid certificate exists. It does not verify any of the data within
+the certificate (although it prints some of the data to the log file).
+
+
+Which clients are available that support SSL?
+=============================================
+Currently there are only smbclient which is part of the samba package and
+Sharity. Shariy versions newer than 0.14 in the beta branch and 1.01 in the
+main branch can be compiled with SSLeay. Sharity is a CIFS/SMB client
+implementation for Unix. It is a commercial product, but it is available in
+source code and the demo-mode allows access to the first three layers of the
+mounted directory hierarchy. Licenses for universities and students are free.
+Sharity is available at
+
+ http://www.obdev.at/Products/Sharity.html
+
+
+
+###########################################################################
+Basics about Cryptography and SSL(eay)
+###########################################################################
+
+There are many good introductions to cryptography. I assume that the reader
+is familiar with the words "encryption", "digital signature" and RSA. If you
+don't know these terms, please read the cryptography FAQ part 6 and 7, which
+is posted to the usenet newsgroup sci.crypt. It is also available from
+
+ ftp://rtfm.mit.edu/pub/usenet/news.answers/cryptography-faq
+and
+ http://www.cis.ohio-state.edu/hypertext/faq/usenet/cryptography-faq
+
+I'll concentrate on the questions specific to SSL and samba here.
+
+
+What is a certificate?
+======================
+A certificate is issued by an issuer, usually a "Certification Authority"
+(CA), who confirms something by issuing the certificate. The subject of this
+confirmation depends on the CA's policy. CAs for secure web servers (used for
+shopping malls etc.) usually only attest that the given public key belongs the
+the given domain name. Company-wide CAs might attest that you are an employee
+of the company, that you have permissions to use a server or whatever.
+
+
+What is an X.509 certificate technically?
+=========================================
+Technically, the certificate is a block of data signed by the certificate
+issuer (the CA). The relevant fields are:
+ - unique identifier (name) of the certificate issuer
+ - time range during that the certificate is valid
+ - unique identifier (name) of the certified subject
+ - public key of the certified subject
+ - the issuer's signature over all of the above
+If this certificate should be verified, the verifier must have a table of the
+names and public keys of trusted CAs. For simplicity, these tables are lists
+of certificates issued by the respective CAs for themselves (self-signed
+certificates).
+
+
+What are the implications of this certificate structure?
+========================================================
+ - Because the certificate contains the subject's public key, the
+ certificate and the private key together are all that's needed to encrypt
+ and decrypt.
+ - To verify certificates, you need the certificates of all CAs you trust.
+ - The simplest form of a dummy-certificate is one that's signed by the
+ subject itself.
+ - A CA is needed. The client can't simply issue local certificates for
+ servers it trusts because the server determines which certificate it
+ presents.
+
+
+
+###########################################################################
+Setting up files and directories for OpenSSL
+###########################################################################
+
+The first thing you should do is to change your PATH environment variable to
+include the bin directory of OpenSSL. E.g.:
+
+ PATH=$PATH:/usr/local/ssl/bin
+
+If your system's kernel supports a /dev/urandom device, all OpenSSL operations
+will automatically retrieve its entropy from it. If your system does not
+support /dev/urandom, you may install an EGD/PRNGD daemon for entropy
+supply or can generate seed from reading files (that should contain information
+unpredictable/unknown to attackers). Use the "-rand" option to the openssl
+commands to specify the entropy source (if /dev/urandom is not available).
+
+OpenSSL additionally keeps random seed in the $HOME/.rnd file. You can
+initialize this file using:
+
+ openssl rand -rand /tmp/rfile.txt > $HOME/.rnd
+ rm -f /tmp/rfile.txt # nobody must know!!
+
+or
+
+ openssl rand -rand /path/to/egd-socket > $HOME/.rnd
+
+How to create a keypair
+=======================
+This is done with 'genrsa' for RSA keys and 'gendsa' for DSA keys. For an RSA
+key with 1024 bits which is written to the file "key.pem" type:
+
+ openssl genrsa -des3 -rand /path/to/source 1024 > key.pem
+
+You will be asked for a pass phrase to protect this key. If you don't want to
+protect your private key with a pass phrase, just omit the parameter "-des3".
+If you want a different key size, replace the parameter "1024". You really
+should use a pass phrase.
+
+If you want to remove the pass phrase from a key use:
+
+ openssl rsa -in key.pem -out newkey.pem
+
+And to add or change a pass phrase:
+
+ openssl rsa -des3 -in key.pem -out newkey.pem
+
+
+How to create a dummy certificate
+=================================
+If you still have your keypair in the file "key.pem", the command
+
+ openssl req -new -x509 -key key.pem -out cert.pem
+
+will write a self-signed dummy certificate to the file "cert.pem". This can
+be used for testing or if only encryption and no certification is needed.
+Please bear in mind that encryption without authentication (certification)
+can never be secure. It's open to (at least) "man-in-the-middle" attacks.
+
+
+How to create a certificate signing request
+===========================================
+You must not simply send your keypair to the CA for signing because it
+contains the private key which _must_ be kept secret. A signing request
+consists of your public key and some additional information you want to have
+bound to that key by the certificate. If you operate a secure web server,
+this additional information will (among other things) contain the URL of
+your server in the field "Common Name". The certificate signing request is
+created from the keypair with the following command (assuming that the key
+pair is still in "key.pem"):
+
+ openssl req -new -key key.pem -out csr.pem
+
+This command will ask you for the information which must be included in the
+certificate and will write the signing request to the file "csr.pem". This
+signing request is all the CA needs for signing, at least technically. Most
+CAs will demand bureaucratic material and money, too.
+
+
+How to set up a Certification Authority (CA)
+============================================
+Being a certification authority requires a database that holds the CA's
+keypair, the CA's certificate, a list of all signed certificates and other
+information. This database is kept in a directory hierarchy below a
+configurable starting point. The starting point must be configured in the
+ssleay.conf file. This file is at /usr/local/ssl/lib/ssleay.conf if you have
+not changed the default installation path.
+
+The first thing you should do is to edit this file according to your needs.
+Let's assume that you want to hold the CA's database at the directory
+"/usr/local/ssl/CA". Change the variable "dir" in section "CA_default" to
+this path. You may also want to edit the default settings for some variables,
+but the values given should be OK. This path is also contained in the shell
+script CA.sh, which should be at "/usr/local/ssl/bin/CA.sh". Change the path
+in the shell script:
+
+ CATOP=/usr/local/ssl/CA
+ CAKEY=./cakey.pem # relative to $CATOP/
+ CACERT=./cacert.pem # relative to $CATOP/private/
+
+Then create the directory "/usr/local/ssl/CA" and make it writable for the
+user that operates the CA. You should also initialize SSLeay as CA user (set
+up the random number generator). Now you should call the shell script CA.sh
+to set up the initial database:
+
+ CA.sh -newca
+
+This command will ask you whether you want to use an existing certificate or
+create one. Just press enter to create a new key pair and certificate. You
+will be asked the usual questions for certificates: the country, state, city,
+"Common Name", etc. Enter the appropriate values for the CA. When CA.sh
+finishes, it has set up a bunch of directories and files. A CA must publish
+it's certificate, which is in the file "/usr/local/ssl/CA/cacert.pem".
+
+
+How to sign a certificate request
+=================================
+After setting up the CA stuff, you can start signing certificate requests.
+Make sure that the SSLeay utilities know where the configuration file is.
+The default is compiled in, if you don't use the default location, add the
+parameter "-config <cfg-file>". Make also sure that the configuration file
+contains the correct path to the CA database. If all this is set up properly,
+you can sign the request in the file "csr.pem" with the command:
+
+ openssl ca -policy policy_anything -days 365 -infiles csr.pem >cert.pem
+
+The resulting certificate (and additional information) will be in "cert.pem".
+If you want the certificate to be valid for a period different from 365 days,
+simply change the "-days" parameter.
+
+
+How to install a new CA certificate
+===================================
+Whereever a certificate must be checked, the CA's certificate must be
+available. Let's take the common case where the client verifies the server's
+certificate. The case where the server verfies the client's certificate works
+the same way. The client receives the server's certificate, which contains
+the "Distinguished Name" of the CA. To verify whether the signature in this
+certificate is OK, it must look up the public key of that CA. Therefore each
+client must hold a database of CAs, indexed by CA name. This database is best
+kept in a directory where each file contains the certificate of one CA and is
+named after the hashvalue (checksum) of the CA's name. This section describes
+how such a database is managed technically. Whether or not to install (and
+thereby trust) a CA is a totally different matter.
+
+The client must know the directory of the CA database. This can be configured.
+There may also be a configuration option to set up a CA database file which
+contains all CA certs in one file. Let's assume that the CA database is kept
+in the directory "/usr/local/ssl/certs". The following example assumes that
+the CA's certificate is in the file "cacert.pem" and the CA is known as
+"myCA". To install the certificate, do the following:
+
+ cp cacert.pem /usr/local/ssl/cers/myCA.pem
+ cd /usr/local/ssl/certs
+ ln -s myCA.pem `openssl x509 -noout -hash < myCA.pem`.0
+
+The last command creates a link from the hashed name to the real file.
+
+From now on all certificates signed by the myCA authority will be accepted by
+clients that use the directory "/usr/local/ssl/certs/" as their CA certificate
+database.
+
+
+
diff --git a/docs/textdocs/Speed.txt b/docs/textdocs/Speed.txt
index 5dfd70323b1..b82db8f8f4d 100644
--- a/docs/textdocs/Speed.txt
+++ b/docs/textdocs/Speed.txt
@@ -1,8 +1,8 @@
-This file tries to outline the ways to improve the speed of a Samba server.
-Andrew Tridgell
-January 1995
+Subject: Samba performance issues
+============================================================================
+This file tries to outline the ways to improve the speed of a Samba server.
COMPARISONS
-----------
@@ -30,6 +30,62 @@ hardware Samba should certainly be competitive in speed with other
systems.
+OPLOCKS
+-------
+
+Oplocks are the way that SMB clients get permission from a server to
+locally cache file operations. If a server grants an oplock
+(opportunistic lock) then the client is free to assume that it is the
+only one accessing the file and it will agressively cache file
+data. With some oplock types the client may even cache file open/close
+operations. This can give enormous performance benefits.
+
+With the release of Samba 1.9.18 we now correctly support opportunistic
+locks. This is turned on by default, and can be turned off on a share-
+by-share basis by setting the parameter :
+
+oplocks = False
+
+We recommend that you leave oplocks on however, as current benchmark
+tests with NetBench seem to give approximately a 30% improvement in
+speed with them on. This is on average however, and the actual
+improvement seen can be orders of magnitude greater, depending on
+what the client redirector is doing.
+
+Previous to Samba 1.9.18 there was a 'fake oplocks' option. This
+option has been left in the code for backwards compatibility reasons
+but it's use is now deprecated. A short summary of what the old
+code did follows.
+
+LEVEL2 OPLOCKS
+--------------
+
+With Samba 2.0.5 a new capability - level2 (read only) oplocks is
+supported (although the option is off by default - see the smb.conf
+man page for details). Turning on level2 oplocks (on a share-by-share basis)
+by setting the parameter :
+
+level2 oplocks = true
+
+should speed concurrent access to files that are not commonly written
+to, such as application serving shares (ie. shares that contain common
+.EXE files - such as a Microsoft Office share) as it allows clients to
+read-ahread cache copies of these files.
+
+Old 'fake oplocks' option - deprecated.
+---------------------------------------
+
+Samba can also fake oplocks, by granting a oplock whenever a client
+asks for one. This is controlled using the smb.conf option "fake
+oplocks". If you set "fake oplocks = yes" then you are telling the
+client that it may agressively cache the file data for all opens.
+
+Enabling 'fake oplocks' on all read-only shares or shares that you know
+will only be accessed from one client at a time you will see a big
+performance improvement on many operations. If you enable this option
+on shares where multiple clients may be accessing the files read-write
+at the same time you can get data corruption.
+
SOCKET OPTIONS
--------------
@@ -80,7 +136,10 @@ MAX XMIT
At startup the client and server negotiate a "maximum transmit" size,
which limits the size of nearly all SMB commands. You can set the
maximum size that Samba will negotiate using the "max xmit = " option
-in smb.conf.
+in smb.conf. Note that this is the maximum size of SMB request that
+Samba will accept, but not the maximum size that the *client* will accept.
+The client maximum receive size is sent to Samba by the client and Samba
+honours this limit.
It defaults to 65536 bytes (the maximum), but it is possible that some
clients may perform better with a smaller transmit unit. Trying values
@@ -111,7 +170,20 @@ no". This will gain you a lot in opening and closing files but will
mean that (in some cases) the system won't force a second user of a
file to open the file read-only if the first has it open
read-write. For many applications that do their own locking this
-doesn't matter, but for some it may.
+doesn't matter, but for some it may. Most Windows applications
+depend heavily on "share modes" working correctly and it is
+recommended that the Samba share mode support be left at the
+default of "on".
+
+The share mode code in Samba has been re-written in the 1.9.17
+release following tests with the Ziff-Davis NetBench PC Benchmarking
+tool. It is now believed that Samba 1.9.17 implements share modes
+similarly to Windows NT.
+
+NOTE: In the most recent versions of Samba there is an option to use
+shared memory via mmap() to implement the share modes. This makes
+things much faster. See the Makefile for how to enable this.
+
LOG LEVEL
---------
@@ -187,7 +259,7 @@ Samba supports reading files via memory mapping them. One some
machines this can give a large boost to performance, on others it
makes not difference at all, and on some it may reduce performance.
-To enable you you have to recompile Samba with the -DUSE_MMAP=1 option
+To enable you you have to recompile Samba with the -DUSE_MMAP option
on the FLAGS line of the Makefile.
Note that memory mapping is only used on files opened read only, and
@@ -239,6 +311,7 @@ person even reported a speed drop of a factor of 30 when he went from
It probably depends a lot on your hardware, and the type of unix box
you have at the other end of the link.
+
MY RESULTS
----------
@@ -263,10 +336,3 @@ smbclient running on another linux box. Maybe I'll add those results
here someday ...
-COMMENTS
---------
-
-If you've read this far then please give me some feedback! Which of
-the above suggestions worked for you?
-
-Mail the samba mailing list or samba-bugs@anu.edu.au
diff --git a/docs/textdocs/Speed2.txt b/docs/textdocs/Speed2.txt
new file mode 100644
index 00000000000..a8c3e7381fd
--- /dev/null
+++ b/docs/textdocs/Speed2.txt
@@ -0,0 +1,57 @@
+Contributor: Paul Cochrane <paulc@dth.scot.nhs.uk>
+Organization: Dundee Limb Fitting Centre
+Date: Fri, 10 Apr 1998
+Subject: Samba SPEED.TXT comment
+=============================================================================
+
+This might be relevant to Client Tuning. I have been trying various methods
+of getting win95 to talk to Samba quicker. The results I have come up with
+are:
+
+1. Install the W2setup.exe file from www.microsoft.com. This is an
+update for the winsock stack and utilities which improve performance.
+
+2. Configure the win95 TCPIP registry settings to give better
+perfomance. I use a program called MTUSPEED.exe which I got off the
+net. There are various other utilities of this type freely available.
+The setting which give the best performance for me are:
+
+(a) MaxMTU Remove
+(b) RWIN Remove
+(c) MTUAutoDiscover Disable
+(d) MTUBlackHoleDetect Disable
+(e) Time To Live Enabled
+(f) Time To Live - HOPS 32
+(g) NDI Cache Size 0
+
+3. I tried virtually all of the items mentioned in the document and
+the only one which made a difference to me was the socket options. It
+turned out I was better off without any!!!!!
+
+In terms of overall speed of transfer, between various win95 clients
+and a DX2-66 20MB server with a crappy NE2000 compatible and old IDE
+drive (Kernel 2.0.30). The transfer rate was reasonable for 10 baseT.
+
+The figures are: Put Get
+P166 client 3Com card: 420-440kB/s 500-520kB/s
+P100 client 3Com card: 390-410kB/s 490-510kB/s
+DX4-75 client NE2000: 370-380kB/s 330-350kB/s
+
+I based these test on transfer two files a 4.5MB text file and a 15MB
+textfile. The results arn't bad considering the hardware Samba is
+running on. It's a crap machine!!!!
+
+The updates mentioned in 1 and 2 brought up the transfer rates from
+just over 100kB/s in some clients.
+
+A new client is a P333 connected via a 100MB/s card and hub. The
+transfer rates from this were good: 450-500kB/s on put and 600+kB/s
+on get.
+
+Looking at standard FTP throughput, Samba is a bit slower (100kB/s
+upwards). I suppose there is more going on in the samba protocol, but
+if it could get up to the rate of FTP the perfomance would be quite
+staggering.
+
+Paul Cochrane
+
diff --git a/docs/textdocs/Support.txt b/docs/textdocs/Support.txt
deleted file mode 100644
index d71bdaf7b3e..00000000000
--- a/docs/textdocs/Support.txt
+++ /dev/null
@@ -1,376 +0,0 @@
-The Samba Consultants List
-==========================
-
-This is a list of people who are prepared to install and support Samba.
-Note that in most countries nobody should admit to "supplying" Samba, since
-there is then an implied warranty with possibly onerous legal obligations.
-Just downloading and installing it isn't supply in this sense, but advertising
-"run our Samba for best results" may be so.
-
-Being on this list does not imply any sort of endorsement by anyone, it is just
-provided in the hope that it will be useful.
-
-If you want to be added to the list, or want your entry modified then
-contact the address below. They are currently listed in the
-order that they were received. If it gets too big we may organise it
-by region. Please make sure to include a header line giving the region
-and country, eg CANBERRA - AUSTRALIA.
-
-You can contact the maintainers at samba-bugs@anu.edu.au
-
-
-------------------------------------------------------------------------------
-BRISBANE - AUSTRALIA
-
-Brett Worth
-Select Computer Technology - Brisbane
-431 Logan Road
-Stones Corner QLD 4120
-E-Mail: brett@sct.com.au
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
-
-Paul Blackman (ictinus@lake.canberra.edu.au, Ph. 06 2012518) is
-available for consultation. Paul's Samba background is with
-Solaris 2.3/4 and WFWG/Win95 machines. Paul is also the maintainer
-of the SAMBA Web Pages.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-READING - ENGLAND
-
-Philip Hands | E-Mail: info@hands.com
-Philip Hands Computing Ltd. | Tel: +44 1734 476287 Fax: 1734 474655
-Unit 1, Cherry Close, Caversham, Reading RG4 8UP UK
-
-Samba experience: SVR4,SVR3.2 & Linux <--> WfWg, W3.1, OS2 and MS-LanMan
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-ILLONOIS - USA
-
-Information One, Inc.
-736 Hinman Ave, Suite 2W
-Evanston, IL 60202
-708-328-9137 708-328-0117 FAX
-info@info1.com
-
-Providing custom Internet and networking solutions.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-Olympic Peninsula Consulting; 1241 Lansing Ave W., Bremerton, WA 98312-4343
-telephone 1+ 360 792 6938; mailto:opc@aa.net; http://www.aa.net/~opc;
-Unix Systems and TCP/IP Network design, programming, and administration.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-SolutionS R Us has been in business for 3+ years providing viable 3rd
-party support in system/network administration. With our own Linux
-distribution which we're constantly improving to make it the best and
-using it to provide total solutions for companies which are open to
-using Linux.
-
-Mauro DePalma <mauro@sru.com>
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-BIELEFELD - GERMANY
-
-I am located in Bielefeld/Germany and have been doing Unix consultancy
-work for the past 8 years throughout Germany and the rest of Europe. I
-can be contacted by email at <jpm@mens.de> or via phone at +49 521
-9225922 or telefax at +49 521 9225924.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
-
-Ben Elliston
-Faculty of Information Sciences and Engineering
-University of Canberra AUSTRALIA
-E-mail: ben@ise.canberra.edu.au (Uni)
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-PALERMO - ITALY
-
-Francesco Cardinale
-E-Mail: cardinal@palermo.italtel.it
-Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-
-John Terpstra - Aquasoft (jht@aquasoft.com.au)
-Business: +612 524 4040
-Home: +612 540 3154
-Shoephone: +612 414 334422 (aka 0414 334422)
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-ONTARIO - CANADA
-
-Strata Software Limited, Kanata Ontario CANADA
-Tel: +1 (613) 591-1922 Fax: +1 (613) 591-3485
-Email: sales@strataware.com WWW: http://www.strataware.com/
-
-Strata Software Limited is a software development and consulting group
-specializing in data communications (TCP/IP and OSI), X.400, X.500 and
-LDAP, and X.509-based security. We have Samba experience with Windows NT,
-Windows 95, and Windows for Workgroups clients with Linux, Unixware
-(SVR4), and HP-UX servers.
-------------------------------------------------------------------------------
-
------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-
-We are a Unix & Windows developer with a consulting & support component.
-In business since 1981 with experience on Sun, hp, sgi, IBM rs6000 plus
-Windows, NT and Win95, Using Samba since September 94.
-CodeSmiths, 22 Darley Road, MANLY 2095 NSW; 977 1979; fax: 977 2116
-philm@esi.com.au (Australia; New South Wales; SYDNEY; North East)
------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-EDINBUGH - SCOTLAND
-
-Charlie Hussey email charlie@edina.demon.co.uk
-Edina Software Limited tel 0131 657 1129
-4 James Street fax 0131 669 9092
-Edinburgh EH15 2DS
-
-SAMBA experience: SCO UNIX <=> WfWg
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-LONDON - ENGLAND
-
-Mark H. Preston,
-Network Analyst, | Email : mpreston@sghms.ac.uk
-Computer Unit, | Tel : +44 (0)181 725-5434
-St. George's Hospital Med School, | Fax : +44 (0)181 725-3583
-London SW17 ORE. | WWW : http://www.sghms.ac.uk
-
-Samba Experience:
-Server: Solaris 2.3 & 2.4, Irix 5.2 & 5.3
-Client: WinNT, Win95, WfWg, Win3.1, Ms-LanMan, DHCP support
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-
-Pacific ESI has used and installed Samba since 1.6 on a range
-of machines running SunOS, BSD/OS, SCO/UNIX, HP/UX, and Solaris,
-and WfWG and Windows95. The largest system worked on to date
-involved an Australia wide network of machines with PCs and SUNs
-at the various nodes. The in-house testing site is a wide area
-network with three sites, remotely connected with PPP and with
-SUN servers at each site to all of which are connected several
-PCs running mainly WfWG.
-
-Stefan Kjellberg Pacific Engineering Systems
-International
-info@eram.esi.com.au Voice:+61-2-9063377
-... Fax:+61-2-9063468
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-CHANTILLY - USA
-
-Intelligent Decisions, Inc.
-ATTN: Richard Bullington
-14121 Parke Long Ct. #104
-Chantilly, VA 22021
-U.S.A.
-(703) 803-8070
-rbullington@intdec.com
-
-Samba experience: Linux, DEC ULTRIX <=> WFWG 3.11, Windows NT 3.5
-Specializing in World Wide Web related UNIX-to-PC connectivity.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-FORT COLLINS, CO - USA
-
-Granite Computing Solutions
-ATTN: Brian Grossman
-Box 270103
-Fort Collins, CO 80527-0103
-U.S.A.
-(970) 225-2370
-granite@fortnet.org
-
-Information services, including WfWG, NT, Apple <=> Unix interoperability.
-
-Our standard advertisement says:
-
-> Unix workstations, servers and custom systems <
->> WWW and Unix education <<
->>> Enterprise and departmental computing solutions <<<
->>> Backup & restore <<<
->> Software forensics <<
-> Data translation <
-------------------------------------------------------------------------------
-
-----------------------------------------------------------
-Adelaide, Australia
-
-NS Computer Software and Services P/L
-PO Box 86
-Ingle Farm
-SA 5098
-
-Contact: Richard Sharpe
- Ph: +61-8-281-0063 (08-281-0063) AH
- FAX:+61-8-250-2080 (08-250-2080)
-
-Experience with: ULTRIX, Digital UNIX, SunOS, WfW 3.11, Win95, WNT 3.51
-
-----------------------------------------------------------
-
-----------------------------------------------------------
-TECTONIC LIMITED
-WESTWOOD
-78 LOUGHBOROUGH ROAD
-QUORN
-LEICESTERSHIRE
-LE12 8DX
-
-TELEPHONE 01509-620922
-FAX 01509-620933
-
-CONTACT DAVID ROBINSON
-
-WE ARE UNIX ORIENTATED BUT ALSO SPECIALISE IN PC TO UNIX COMMUNICATIONS, WE
-KNOW AND UNDERSTAND PC-NFS, (HENCE OUR INTEREST IN SAMBA).
-WE SUPPORT SUNOS, SOLARIS 1.X AND 2.X, HP-UX 9.0 AND 10.0, OSF (or DEC UNIX,
-whichever you prefer), WinNT, WfWG and Win95.
-
-WE ARE ALREADY TALKING TO A COUPLE OF VERY LARGE SAMBA USERS HERE IN THE UK.
-WE WOULD LIKE TO SUPPORT THEM (AND MANY MORE), WOULD YOU PLEASE CONTACT ME ON:
-david@tectonic.demon.co.uk
-----------------------------------------------------------
-
-----------------------------------------------------------
-MIAMI, FL - USA
-
-Swaney & Associates, Inc.
-ATTN: Stephen Swaney
- 2543 Lincoln Avenue
- Miami, Florida 33133
- U.S.A
- (305) 860-0570
-
-Specializing in:
- High Availability system & networks
- UNIX to PC connectivity
- Market Data systems
- Messaging Systems (Sendmail & Microsoft Exchange)
-----------------------------------------------------------
-
-------------------------------------------------------------------------------
-NEW JERSEY - USA
-
-William J. Maggio
-LAN & Computer Integrators, Inc.
-242 Old New Brunswick Road Email: bmaggio@lci.com
-Suite 440 Voice: 908-981-1991
-Piscataway, NJ 08855 Fax : 908-981-1858
-
- Specializing in Internet connectivity and security, Sun integration and
- high speed, enterprise network design and deployment.
-------------------------------------------------------------------------------
-
-FAREHAM - ENGLAND
-
-High Field Technology Ltd
-Little Park Farm Road, Segensworth West,
-Fareham, Hants PO15 5SJ, UK.
-sales@hft.co.uk tel +44 148 957 0111 fax +44 148 957 0555
-
-Company skills: Real time hardware and software systems
-
-Samba experience: BSD/OS, Linux, LynxOS <==> WFWG, NT
-
-------------------------------------------------------------------------------
-
------------------------------------------------------------------------
-QUEBEC - CANADA
-
-Dataden Computer Systems
-Attn: Danny Arseneau
-arseneau@parkmed.com
-895 2nd Avenue
-Ile Bizard, Quebec
-Canada, H9C 1K3
-Tel: (514)891-2293
-Fax: (514)696-0848
-
-Dataden is company that specializes in Unix--TCP/IP networking.
-We have over 15 years of experience. We have been installing,
-configuring and maintaining Samba for clients for 1-1/2 years now. We
-have samba installations on Linx, SunOS and DEC OSF. Our biggest site
-has 4 Suns and 3 Linux servers running Samba which are serving a network
-of about 50 PC's running WFWg and Win95.
------------------------------------------------------------------------
-
------------------------------------------------------------------------
-CALIFORNIA - USA
-
-Ron Halstead
-Open Systems Consulting
-3098-4 Lakemont Drive
-San Ramon, CA 94583 (San Francisco Bay Area)
-(510) 735-7529
-halstead@ix.netcom.com
------------------------------------------------------------------------
-
-
------------------------------------------------------------------------
-MELBOURNE - AUSTRALIA
-
-Michael Ciavarella
-Cybersoruce Pty Ltd.
-8/140 Queen Street
-Melbourne VIC 3000
-Phone: +61-3-9642-5997
-Fax: +61-3-9642-5998
-Email: mikec@cyber.com.au
-WWW: http://www.cyber.com.au
-
-Cybersource specialises in TCP/IP network integration and Open Systems
-administration. Cybersource is an Australian-owned and operated
-company, with clients including some of Australia's largest financial,
-petrochemical and state government organisations.
------------------------------------------------------------------------
-
------------------------------------------------------------------------
-SOUTHERN CALIFORNIA - USA
-
-Michael St. Laurent
-Serving Los Angeles and Orange Counties. Please contact via email.
-rowl@earthlink.net
-Michael St. Laurent
-Hartwell Corporation
-------------------------------------------------------------------------------
-WASHINGTON DC METRO - USA
-
-Asset Software, Inc. has been running Samba since the 1.6 release on various
-platforms, including SunOS 4.x, Solaris 2.x, IRIX 4.x and 5.x, Linux 1.1x,
-1.2x, and 1.3x, and BSD UNIX 4.3 and above. We specialize in small office
-network solutions and provide services to enhance a small office's
-operations. Primarily a custom software operation, our vast knowledge of
-Windows, DOS, Unix, Windows NT, MacOS, and OS/2 enable us to provide quality
-technical assistance to the small office environment at a reasonable price.
-Our upcoming multi-mailbox mail client, IQ Mail, enables users with more
-than one mailbox to send and retrieve their mail from a single, consistent
-mail client running in Windows.
-
-David J. Fenwick Asset Software, Inc.
-President djf@assetsw.com
-------------------------------------------------------------------------------
-
diff --git a/docs/textdocs/Tracing.txt b/docs/textdocs/Tracing.txt
new file mode 100644
index 00000000000..fd65045abdb
--- /dev/null
+++ b/docs/textdocs/Tracing.txt
@@ -0,0 +1,93 @@
+Contributor: Andrew Tridgell <samba@samba.org>
+Date: Old
+Status: Questionable
+
+Subject: How to trace samba system calls for debugging purposes
+=============================================================================
+
+This file describes how to do a system call trace on Samba to work out
+what its doing wrong. This is not for the faint of heart, but if you
+are reading this then you are probably desperate.
+
+Actually its not as bad as the the above makes it sound, just don't
+expect the output to be very pretty :-)
+
+Ok, down to business. One of the big advantages of unix systems is
+that they nearly all come with a system trace utility that allows you
+to monitor all system calls that a program is making. This is
+extremely using for debugging and also helps when trying to work out
+why something is slower than you expect. You can use system tracing
+without any special compilation options.
+
+The system trace utility is called different things on different
+systems. On Linux systems its called strace. Under SunOS 4 its called
+trace. Under SVR4 style systems (including solaris) its called
+truss. Under many BSD systems its called ktrace.
+
+The first thing you should do is read the man page for your native
+system call tracer. In the discussion below I'll assume its called
+strace as strace is the only portable system tracer (its available for
+free for many unix types) and its also got some of the nicest
+features.
+
+Next, try using strace on some simple commands. For example, "strace
+ls" or "strace echo hello".
+
+You'll notice that it produces a LOT of output. It is showing you the
+arguments to every system call that the program makes and the
+result. Very little happens in a program without a system call so you
+get lots of output. You'll also find that it produces a lot of
+"preamble" stuff showing the loading of shared libraries etc. Ignore
+this (unless its going wrong!)
+
+For example, the only line that really matters in the "strace echo
+hello" output is:
+
+write(1, "hello\n", 6) = 6
+
+all the rest is just setting up to run the program.
+
+Ok, now you're famialiar with strace. To use it on Samba you need to
+strace the running smbd daemon. The way I tend ot use it is to first
+login from my Windows PC to the Samba server, then use smbstatus to
+find which process ID that client is attached to, then as root I do
+"strace -p PID" to attach to that process. I normally redirect the
+stderr output from this command to a file for later perusal. For
+example, if I'm using a csh style shell:
+
+ strace -f -p 3872 >& strace.out
+
+or with a sh style shell:
+
+ strace -f -p 3872 > strace.out 2>&1
+
+Note the "-f" option. This is only available on some systems, and
+allows you to trace not just the current process, but any children it
+forks. This is great for finding printing problems caused by the
+"print command" being wrong.
+
+Once you are attached you then can do whatever it is on the client
+that is causing problems and you will capture all the system calls
+that smbd makes.
+
+So how do you interpret the results? Generally I search thorugh the
+output for strings that I know will appear when the problem
+happens. For example, if I am having touble with permissions on a file
+I would search for that files name in the strace output and look at
+the surrounding lines. Another trick is to match up file descriptor
+numbers and "follow" what happens to an open file until it is closed.
+
+Beyond this you will have to use your initiative. To give you an idea
+of wehat you are looking for here is a piece of strace output that
+shows that /dev/null is not world writeable, which causes printing to
+fail with Samba:
+
+[pid 28268] open("/dev/null", O_RDWR) = -1 EACCES (Permission denied)
+[pid 28268] open("/dev/null", O_WRONLY) = -1 EACCES (Permission denied)
+
+the process is trying to first open /dev/null read-write then
+read-only. Both fail. This means /dev/null has incorrect permissions.
+
+Have fun!
+
+(please send updates/fixes to this file to samba@samba.org)
diff --git a/docs/textdocs/UNIX-SMB.txt b/docs/textdocs/UNIX-SMB.txt
index b2c064215cf..c3d7643cbcb 100644
--- a/docs/textdocs/UNIX-SMB.txt
+++ b/docs/textdocs/UNIX-SMB.txt
@@ -1,3 +1,9 @@
+Contributor: Andrew Tridgell <samba@samba.org>
+Date: April 1995
+
+Subject: Discussion of NetBIOS in a Unix World
+============================================================================
+
This is a short document that describes some of the issues that
confront a SMB implementation on unix, and how Samba copes with
them. They may help people who are looking at unix<->PC
@@ -6,9 +12,6 @@ interoperability.
It was written to help out a person who was writing a paper on unix to
PC connectivity.
-Andrew Tridgell
-April 1995
-
Usernames
=========
@@ -85,19 +88,17 @@ passwords they are in trouble.
Samba can try to cope with this by either using the "password level"
option which causes Samba to try the offered password with up to the
specified number of case changes, or by using the "password server"
-option which allows Samba to do it's validation via another machine
+option which allows Samba to do its validation via another machine
(typically a WinNT server).
-Samba also doesn't support the password encryption method used by SMB
-clients. This is because the spec isn't sufficiently detailed for an
-implementation (although Jeremy Allison is working on it, to try and
-work it out). Also, there is a fundamental problem with what we
-understand so far in the algorithm, as it seems that the server would
-need to store somewhere on disk a reversibly encrypted (effectively
-plaintext) copy of the users password in order to use the
-algorithm. This goes against the unix policy that "even the super-user
-doesn't know your password" which comes from the use of a one-way hash
-function.
+Samba supports the password encryption method used by SMB
+clients. Note that the use of password encryption in Microsoft
+networking leads to password hashes that are "plain text equivalent".
+This means that it is *VERY* important to ensure that the Samba
+smbpasswd file containing these password hashes is only readable
+by the root user. See the documentation ENCRYPTION.txt for more
+details.
+
Locking
=======
@@ -127,7 +128,7 @@ The second major problem is the "opportunistic locking" requested by
some clients. If a client requests opportunistic locking then it is
asking the server to notify it if anyone else tries to do something on
the same file, at which time the client will say if it is willing to
-give up it's lock. Unix has no simple way of implementing
+give up its lock. Unix has no simple way of implementing
opportunistic locking, and currently Samba has no support for it.
Deny Modes
@@ -140,10 +141,12 @@ allowed by anyone else who tries to use the file at the same time. If
DENY_READ is placed on the file, for example, then any attempt to open
the file for reading should fail.
-Unix has no equivalent notion. To implement these Samba uses lock
+Unix has no equivalent notion. To implement this Samba uses either lock
files based on the files inode and placed in a separate lock
-directory. These are clumsy and consume processing and file resources,
-so they are optional and off by default.
+directory or a shared memory implementation. The lock file method
+is clumsy and consumes processing and file resources,
+the shared memory implementation is vastly prefered and is turned on
+by default for those systems that support it.
Trapdoor UIDs
=============
@@ -155,6 +158,9 @@ within the one process. On some unixes (such as SCO) this is not
possible. This means that on those unixes the client is restricted to
a single uid.
+Note that you can also get the "trapdoor uid" message for other
+reasons. Please see the FAQ for details.
+
Port numbers
============
@@ -216,5 +222,10 @@ this protocol level much easier.
There is also a problem with the SMB specications. SMB is a X/Open
spec, but the X/Open book is far from ideal, and fails to cover many
-important issues, leaving much to the imagination.
+important issues, leaving much to the imagination. Microsoft recently
+renamed the SMB protocol CIFS (Common Internet File System) and have
+published new specifications. These are far superior to the old
+X/Open documents but there are still undocumented calls and features.
+This specification is actively being worked on by a CIFS developers
+mailing list hosted by Microsft.
diff --git a/docs/textdocs/UNIX_SECURITY.txt b/docs/textdocs/UNIX_SECURITY.txt
new file mode 100644
index 00000000000..d6a0a01acc5
--- /dev/null
+++ b/docs/textdocs/UNIX_SECURITY.txt
@@ -0,0 +1,54 @@
+Contributor: John H Terpstra <jht@samba.org>
+Date: July 5, 1998
+Status: Current
+
+Subject: SETTING UNIX FILE SYSTEM SECURITY
+===============================================================================
+The following excerpt from a bug report demonstrates the need to
+understand Unix file system security and to manage it correctly.
+
+Quote:
+======
+> We are unable to keep individual users from mapping to any other user's
+> home directory once they have supplied a valid password! They only need
+> to enter their own password. I have not found *any* method that I can
+> use to configure samba to enforce that only a user may map their own
+> home directory.
+>
+> User xyzzy can map his home directory. Once mapped user xyzzy can also map
+> *anyone* elses home directory!
+
+ANSWER:
+=======
+This is not a security flaw, it is by design. Samba allows
+users to have *exactly* the same access to the UNIX filesystem
+as they would if they were logged onto the UNIX box, except
+that it only allows such views onto the file system as are
+allowed by the defined shares.
+
+This means that if your UNIX home directories are set up
+such that one user can happily cd into another users
+directory and do an ls, the UNIX security solution is to
+change the UNIX file permissions on the users home directories
+such that the cd and ls would be denied.
+
+Samba tries very had not to second guess the UNIX administrators
+security policies, and trusts the UNIX admin to set
+the policies and permissions he or she desires.
+
+Samba does allow the setup you require when you have set the
+"only user = yes" option on the share, is that you have not set the
+valid users list for the share.
+
+Note that only user works in conjunction with the users= list,
+so to get the behavior you require, add the line :
+
+users = %S
+
+this is equivalent to:
+
+valid users = %S
+
+to the definition of the [homes] share, as recommended in
+the smb.conf man page.
+
diff --git a/docs/textdocs/Win95.txt b/docs/textdocs/Win95.txt
new file mode 100644
index 00000000000..69330c512d4
--- /dev/null
+++ b/docs/textdocs/Win95.txt
@@ -0,0 +1,74 @@
+Copyright (C) 1997 - Samba-Team
+Contributed Date: August 20, 1997
+Last Update: August 20, 1997
+
+Subject: Windows 95 and Samba Interoperability
+===============================================================================
+
+Password Handling:
+------------------
+Microsoft periodically release updates to all their operating systems. Some of
+these are welcomed while others cause us to change the way we do things. Few
+people like change, particularly if the change is unexpected. The best advice
+always is to read the documentation provided BEFORE applying an update.
+
+One of the recent Win95 updates (VRDRUPD.EXE) disables plain text (also called
+clear text) password authentication. The effects of this updates are desirable
+where MS Windows NT is providing the password authentication service. This
+update is most undesirable where Samba must provide the authentication service
+unless Samba has been specifically configured to use encrypted passwords _AND_
+has been linked with the libdes library.
+
+If the above conditions have not been complied with, and you are using Samba,
+then Windows 95 clients will NOT be able to authenticate to a Samba server.
+
+To re-enable plain text password capabilities AFTER applying this update
+you must create a new value in the Windows 95 registry.
+
+Either foillow the following procedure or just double click on the
+file Win95_PlainPassword.reg for an easier way to do this.
+
+Procedure:
+1) Launch the Registry Editor as follows:
+ Click on: /Start/Run
+ Type "regedit" and press enter.
+
+2) Double click on: HKEY_LOCAL_MACHINE
+
+3) Locate the following Key:
+ /HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/VxD/VNETSUP
+
+4) From the menu bar select Edit/New/DWORD Value
+
+5) Rename the entry from "New Value #1" to:
+ EnablePlainTextPassword
+
+6) Press Enter, then double click on the new entry.
+ A dialog box will pop up and enable you to set a value.
+ You must set this value to 1.
+
+-------------------------------------------------------------------------------
+
+Windows 95 Updates:
+-------------------
+When using Windows 95 OEM SR2 the following updates are recommended where Samba
+is being used. Please NOTE that the above change will affect you once these
+updates have been installed.
+
+There are more updates than the ones mentioned here. You are referred to the
+Microsoft Web site for all currently available updates to your specific version
+of Windows 95.
+
+Kernel Update: KRNLUPD.EXE
+Ping Fix: PINGUPD.EXE
+RPC Update: RPCRTUPD.EXE
+TCP/IP Update: VIPUPD.EXE
+Redirector Update: VRDRUPD.EXE
+
+Also, if using MS OutLook it is desirable to install the OLEUPD.EXE fix. This
+fix may stop your machine from hanging for an extended period when exiting
+OutLook and you may also notice a significant speedup when accessing network
+neighborhood services.
+
+-------------------------------------------------------------------------------
+The above password information was provided by: Jochen Huppertz <jhu@nrh.de>
diff --git a/docs/textdocs/WinNT.txt b/docs/textdocs/WinNT.txt
index b57abb7742e..5c72fb08aa7 100644
--- a/docs/textdocs/WinNT.txt
+++ b/docs/textdocs/WinNT.txt
@@ -1,6 +1,17 @@
-There are some particular issues with Samba and Windows NT
+Contributors: Various
+ Password Section - Copyright (C) 1997 - John H Terpstra
+ Printing Section - Copyright (C) 1997 - Matthew Harrell
+ Priting Info - Copyright (C) 1997 - Frank Varnavas
+Updated: October 16, 1997
+Status: Current
-=====================================================================
+Subject: Samba and Windows NT Password Handling
+=============================================================================
+
+There are some particular issues with Samba and Windows NT.
+
+Passwords:
+==========
One of the most annoying problems with WinNT is that NT refuses to
connect to a server that is in user level security mode and that
doesn't support password encryption unless it first prompts the user
@@ -8,21 +19,34 @@ for a password.
This means even if you have the same password on the NT box and the
Samba server you will get prompted for a password. Entering the
-correct password will get you connected.
+correct password will get you connected only if Windows NT can
+communicate with Samba using a compatible mode of password security.
+
+All versions of Windows NT prior to 4.0 Service Pack 3 could negotiate
+plain text (clear text) passwords. Windows NT 4.0 Service Pack 3 changed
+this default behaviour so it now will only handle encrypted passwords.
+The following registry entry change will re-enable clear text password
+handling:
+
+Run regedt32.exe and locate the hive key entry:
+HKEY_LOCAL_MACHINE\system\CurrentControlSet\Services\Rdr\Parameters\
+
+Add the following value:
+ EnablePlainTextPassword:REG_DWORD=1
+
+Alternatively, use the NT4_PlainPassword.reg file in this directory (either
+by double clicking on it, or run regedt32.exe and select "Import Registry
+File" from the "Registry" Menu).
The other major ramification of this feature of NT is that it can't
browse a user level non-encrypted server unless it already has a
connection open. This is because there is no spot for a password
prompt in the browser window. It works fine if you already have a
drive mounted (for example, one auto mounted on startup).
-
-Samba should support encrypted passwords soon, which will solve this
-problem.
=====================================================================
-
-
-=====================================================================
+Printing:
+=========
When you mount a printer using the print manager in NT you may find
the following info from Matthew Harrell <harrell@leech.nrl.navy.mil>
useful:
@@ -49,8 +73,32 @@ time for the NT machine to get verification that the printer queue
actually exists.
I hope this helped in some way...
------------
+
=====================================================================
+Printing Info:
+--------------
+
+From: Frank Varnavas <varnavas@ny.ubs.com>
+Subject: RE: Samba as a print server
+
+When an NT client attempts to connect to a printer on a non-NT print
+server the attempt is failed with an error, something like:
+
+ "You have insufficient access to your computer to perform the
+ operation because a driver needs to be installed"
+
+This is because domain users must have 'Power User' status on the
+desktop to connect to printers on a non-NT print server.
+This error occurs regardless of whether the driver in question is
+already installed or not. What it really means is that the server is
+a non-NT server and the client does not have permission to create
+printers locally. Apparently when a connection to a non-NT print
+server is made the printer is defined locally. Such an action can be
+performed by either a local administrator or a Power User.
+Unfortunately there is no way to limit the powers of a Power User, nor
+is there any way to grant the Printer Creation right to another group.
+This permission policy is documented in PSS database WINNT, ID Q101874
+Frank Varnavas (varnavas@ny.ubs.com)
diff --git a/docs/textdocs/cifsntdomain.txt b/docs/textdocs/cifsntdomain.txt
new file mode 100644
index 00000000000..643b8957c9f
--- /dev/null
+++ b/docs/textdocs/cifsntdomain.txt
@@ -0,0 +1,1498 @@
+NT Domain Authentication
+------------------------
+
+Authors: - Luke Kenneth Casson Leighton (lkcl@switchboard.net)
+-------- - Paul Ashton (paul@argo.demon.co.uk)
+ - Duncan Stansfield (duncans@sco.com)
+
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+ Copyright (C) 1997 Paul Ashton
+ Copyright (C) 1997 Duncan Stansfield
+
+Version: 0.024 (01Nov97)
+--------
+
+Distribution: Unlimited and encouraged, for the purposes of implementation
+------------- and comments. Feedback welcomed by the authors.
+
+Liability: Absolutely none accepted implicitly or explicitly, direct
+---------- or consequentially, for use, abuse, misuse, lack of use,
+ misunderstandings, mistakes, omissions, mis-information for
+ anything in or not in, related to or not related to, or
+ pertaining to this document, or anything else that a lawyer
+ can think of or not think of.
+
+Warning: Please bear in mind that an incorrect implementation of this
+-------- protocol can cause NT workstation to fail irrevocably, for
+ which the authors accept no liability (see above). Please
+ contact your vendor if you have any problems.
+
+Sources: - Packet Traces from Netmonitor (Service Pack 1 and above)
+-------- - Paul Ashton and Luke Leighton's other "NT Domain" doc.
+ - CIFS documentation - cifs6.txt
+ - CIFS documentation - cifsrap2.txt
+
+Original: http://mailhost.cb1.com/~lkcl/cifsntdomain.txt.
+--------- (Controlled copy maintained by lkcl@switchboard.net)
+
+Credits: - Paul Ashton: loads of work with Net Monitor;
+-------- understanding the NT authentication system;
+ reference implementation of the NT domain support on which
+ this document is originally based.
+ - Duncan Stansfield: low-level analysis of MSRPC Pipes.
+ - Linus Nordberg: producing c-code from Paul's crypto spec.
+ - Windows Sourcer development team
+
+
+Contents:
+---------
+
+ 1) Introduction
+
+ 2) Structures and notes
+
+ 2.1) Notes
+ 2.3) Enumerations
+ 2.3) Structures
+
+ 3) Transact Named Pipe Header/Tail
+
+ 3.1) MSRPC Pipes
+ 3.2) Header
+ 3.3) Tail
+
+ 4) NTLSA Transact Named Pipe
+
+ 4.1) LSA Open Policy
+ 4.2) LSA Query Info Policy
+ 4.3) LSA Enumerate Trusted Domains
+ 4.4) LSA Open Secret
+ 4.5) LSA Close
+ 4.6) LSA Lookup SIDS
+ 4.7) LSA Lookup Names
+
+ 5) NETLOGON rpc Transact Named Pipe
+
+ 5.1) LSA Request Challenge
+ 5.2) LSA Authenticate 2
+ 5.3) LSA Server Password Set
+ 5.4) LSA SAM Logon
+ 5.5) LSA SAM Logoff
+
+ 6) \\MAILSLOT\NET\NTLOGON
+
+ 6.1) Query for PDC
+ 6.2) SAM Logon
+
+ 7) SRVSVC Transact Named Pipe
+
+ 7.1) Net Share Enum
+ 7.2) Net Server Get Info
+
+
+Appendix:
+---------
+
+ A1) Cryptographic side of NT Domain Authentication
+
+ A1.1) Definitions
+ A1.2) Protocol
+ A1.3) Comments
+
+ A2) SIDs and RIDs
+
+ A2.1) Well-known SIDs
+
+ A2.1.1) Universal well-known SIDs
+ A2.1.2) NT well-known SIDs
+
+ A2.2) Well-known RIDS
+
+ A2.2.1) Well-known RID users
+ A2.2.2) Well-known RID groups
+ A2.2.3) Well-known RID aliases
+
+
+
+1) Introduction
+---------------
+
+
+This document contains information to provide an NT workstation with login
+services, without the need for an NT server.
+
+It should be possible to select a domain instead of a workgroup (in the NT
+workstation's TCP/IP settings) and after the obligatory reboot, type in a
+username, password, select a domain and successfully log in. I would
+appreciate any feedback on your experiences with this process, and any
+comments, corrections and additions to this document.
+
+
+The packets described here can be easily derived from (and are probably
+better understood using) Netmon.exe. You will need to use the version
+of Netmon that matches your system, in order to correctly decode the
+NETLOGON, lsarpc and srvsvc Transact pipes. This document is derived from
+NT Service Pack 1 and its corresponding version of Netmon. It is intended
+that an annotated packet trace be produced, which will likely be more
+instructive than this document.
+
+Also needed, to fully implement NT Domain Login Services, is the
+document describing the cryptographic part of the NT authentication.
+This document is available from comp.protocols.smb; from the ntsecurity.net
+digest and from the samba digest, amongst other sources.
+
+A copy is available from:
+
+http://ntbugtraq.rc.on.ca/SCRIPTS/WA.EXE?A2=ind9708&L=ntbugtraq&O=A&P=2935
+http://mailhost.cb1.com/~lkcl/crypt.html
+
+
+A c-code implementation, provided by Linus Nordberg <linus@incolumitas.se>
+of this protocol is available from:
+
+http://samba.org/cgi-bin/mfs/01/digest/1997/97aug/0391.html
+http://mailhost.cb1.com/~lkcl/crypt.txt
+
+
+Also used to provide debugging information is the Check Build version of
+NT workstation, and enabling full debugging in NETLOGON. This is
+achieved by setting the following REG_SZ registry key to 0x1ffffff:
+
+HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters
+
+- Incorrect direct editing of the registry can cause your machine to fail.
+ Then again, so can incorrect implementation of this protocol.
+ See "Liability:" above.
+
+
+Bear in mind that each packet over-the-wire will have its origin in an
+API call. Therefore, there are likely to be structures, enumerations
+and defines that are usefully documented elsewhere.
+
+
+This document is by no means complete or authoritative. Missing sections
+include, but are not limited to:
+
+- the meaning (and use by NT) of SIDs and RIDs.
+
+- mappings of RIDs to usernames (and vice-versa).
+
+- what a User ID is and what a Group ID is.
+
+- the exact meaning/definition of various magic constants or enumerations.
+
+- the reply error code and use of that error code when a workstation
+ becomes a member of a domain (to be described later). Failure to
+ return this error code will make the workstation report that it is
+ already a member of the domain.
+
+- the cryptographic side of the NetrServerPasswordSet command, which would
+ allow the workstation to change its password. This password is used to
+ generate the long-term session key. [It is possible to reject this
+ command, and keep the default workstation password].
+
+
+2) Notes and Structures
+-----------------------
+
+
+2.1) Notes
+----------
+
+- In the SMB Transact pipes, some "Structures", described here, appear to be
+ 4-byte aligned with the SMB header, at their start. Exactly which
+ "Structures" need aligning is not precisely known or documented.
+
+- In the UDP NTLOGON Mailslots, some "Structures", described here, appear to be
+ 2-byte aligned with the start of the mailslot, at their start.
+
+- Domain SID is of the format S-revision-version-auth1-auth2...authN.
+ e.g S-1-5-123-456-789-123-456. the 5 could be a sub-revision.
+
+- any undocumented buffer pointers must be non-zero if the string buffer it
+ refers to contains characters. exactly what value they should be is unknown.
+ 0x0000 0002 seems to do the trick to indicate that the buffer exists. a
+ NULL buffer pointer indicates that the string buffer is of zero length.
+ If the buffer pointer is NULL, then it is suspected that the structure it
+ refers to is NOT put into (or taken out of) the SMB data stream. This is
+ empirically derived from, for example, the LSA SAM Logon response packet,
+ where if the buffer pointer is NULL, the user information is not inserted
+ into the data stream. Exactly what happens with an array of buffer pointers
+ is not known, although an educated guess can be made.
+
+- an array of structures (a container) appears to have a count and a pointer.
+ if the count is zero, the pointer is also zero. no further data is put
+ into or taken out of the SMB data stream. if the count is non-zero, then
+ the pointer is also non-zero. immediately following the pointer is the
+ count again, followed by an array of container sub-structures. the count
+ appears a third time after the last sub-structure.
+
+
+2.2) Enumerations
+-----------------
+
+- MSRPC Header type. command number in the msrpc packet header
+
+ MSRPC_Request: 0x00
+ MSRPC_Response: 0x02
+ MSRPC_Bind: 0x0B
+ MSRPC_BindAck: 0x0C
+
+- MSRPC Packet info. the meaning of these flags is undocumented
+
+ FirstFrag: 0x01
+ LastFrag: 0x02
+ NotaFrag: 0x04
+ RecRespond: 0x08
+ NoMultiplex: 0x10
+ NotForIdemp: 0x20
+ NotforBcast: 0x40
+ NoUuid: 0x80
+
+
+2.3) Structures
+---------------
+
+- sizeof VOID* is 32 bits.
+
+- sizeof char is 8 bits.
+
+- UTIME is 32 bits, indicating time in seconds since 01jan1970. documented
+ in cifs6.txt (section 3.5 page, page 30).
+
+- NTTIME is 64 bits. documented in cifs6.txt (section 3.5 page, page 30).
+
+- DOM_SID (domain SID structure) :
+
+ UINT32 num of sub-authorities in domain SID
+ UINT8 SID revision number
+ UINT8 num of sub-authorities in domain SID
+ UINT8[6] 6 bytes for domain SID - Identifier Authority.
+ UINT16[n_subauths] domain SID sub-authorities
+
+ Note: the domain SID is documented elsewhere.
+
+- STR (string) :
+
+ char[] null-terminated string of ascii characters.
+
+- UNIHDR (unicode string header) :
+
+ UINT16 length of unicode string
+ UINT16 max length of unicode string
+ UINT32 4 - undocumented.
+
+- UNIHDR2 (unicode string header plus buffer pointer) :
+
+ UNIHDR unicode string header
+ VOID* undocumented buffer pointer
+
+- UNISTR (unicode string) :
+
+ UINT16[] null-terminated string of unicode characters.
+
+- NAME (length-indicated unicode string) :
+
+ UINT32 length of unicode string
+ UINT16[] null-terminated string of unicode characters.
+
+- UNISTR2 (aligned unicode string) :
+
+ UINT8[] padding to get unicode string 4-byte aligned
+ with the start of the SMB header.
+ UINT32 max length of unicode string
+ UINT32 0 - undocumented
+ UINT32 length of unicode string
+ UINT16[] string of uncode characters.
+
+- OBJ_ATTR (object attributes) :
+
+ UINT32 0x18 - length (in bytes) including the length field.
+ VOID* 0 - root directory (pointer)
+ VOID* 0 - object name (pointer)
+ UINT32 0 - attributes (undocumented)
+ VOID* 0 - security descriptior (pointer)
+ UINT32 0 - security quality of service
+
+- POL_HND (LSA policy handle) :
+
+ char[20] policy handle
+
+- DOM_SID2 (domain SID structure, SIDS stored in unicode) :
+
+ UINT32 5 - SID type
+ UINT32 0 - undocumented
+ UNIHDR2 domain SID unicode string header
+ UNISTR domain SID unicode string
+
+ Note: there is a conflict between the unicode string header and the
+ unicode string itself as to which to use to indicate string
+ length. this will need to be resolved.
+
+ Note: the SID type indicates, for example, an alias; a well-known group etc.
+ this is documented somewhere.
+
+- DOM_RID (domain RID structure) :
+
+ UINT32 5 - well-known SID. 1 - user SID (see ShowACLs)
+ UINT32 5 - undocumented
+ UINT32 domain RID
+ UINT32 0 - domain index out of above reference domains
+
+
+- LOG_INFO (server, account, client structure) :
+
+ Note: logon server name starts with two '\' characters and is upper case.
+
+ Note: account name is the logon client name from the LSA Request Challenge,
+ with a $ on the end of it, in upper case.
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ UNISTR2 account name unicode string
+ UINT16 sec_chan - security channel type
+ UNISTR2 logon client machine unicode string
+
+- CLNT_SRV (server, client names structure) :
+
+ Note: logon server name starts with two '\' characters and is upper case.
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ VOID* undocumented buffer pointer
+ UNISTR2 logon client machine unicode string
+
+- CREDS (credentials + time stamp)
+
+ char[8] credentials
+ UTIME time stamp
+
+- CLNT_INFO2 (server, client structure, client credentials) :
+
+ Note: whenever this structure appears in a request, you must take a copy
+ of the client-calculated credentials received, because they will be
+ used in subsequent credential checks. the presumed intention is to
+ maintain an authenticated request/response trail.
+
+ CLNT_SRV client and server names
+ UINT8[] ???? padding, for 4-byte alignment with SMB header.
+ VOID* pointer to client credentials.
+ CREDS client-calculated credentials + client time
+
+- CLNT_INFO (server, account, client structure, client credentials) :
+
+ Note: whenever this structure appears in a request, you must take a copy
+ of the client-calculated credentials received, because they will be
+ used in subsequent credential checks. the presumed intention is to
+ maintain an authenticated request/response trail.
+
+ LOG_INFO logon account info
+ CREDS client-calculated credentials + client time
+
+- ID_INFO_1 (id info structure, auth level 1) :
+
+ VOID* ptr_id_info_1
+ UNIHDR domain name unicode header
+ UINT32 param control
+ UINT64 logon ID
+ UNIHDR user name unicode header
+ UNIHDR workgroup name unicode header
+ char[16] arc4 LM OWF Password
+ char[16] arc4 NT OWF Password
+ UNISTR2 domain name unicode string
+ UNISTR2 user name unicode string
+ UNISTR2 workstation name unicode string
+
+- SAM_INFO (sam logon/logoff id info structure) :
+
+ Note: presumably, the return credentials is supposedly for the server to
+ verify that the credential chain hasn't been compromised.
+
+ CLNT_INFO2 client identification/authentication info
+ VOID* pointer to return credentials.
+ CRED return credentials - ignored.
+ UINT16 logon level
+ UINT16 switch value
+
+ switch (switch_value)
+ case 1:
+ {
+ ID_INFO_1 id_info_1;
+ }
+
+- GID (group id info) :
+
+ UINT32 group id
+ UINT32 user attributes (only used by NT 3.1 and 3.51)
+
+- DOM_REF (domain reference info) :
+
+ VOID* undocumented buffer pointer.
+ UINT32 num referenced domains?
+ VOID* undocumented domain name buffer pointer.
+ UINT32 32 - max number of entries
+ UINT32 4 - num referenced domains?
+
+ UNIHDR2 domain name unicode string header
+ UNIHDR2[num_ref_doms-1] referenced domain unicode string headers
+
+ UNISTR domain name unicode string
+ DOM_SID[num_ref_doms] referenced domain SIDs
+
+- DOM_INFO (domain info, levels 3 and 5 are the same)) :
+
+ UINT8[] ??? padding to get 4-byte alignment with start of SMB header
+ UINT16 domain name string length * 2
+ UINT16 domain name string length * 2
+ VOID* undocumented domain name string buffer pointer
+ VOID* undocumented domain SID string buffer pointer
+ UNISTR2 domain name (unicode string)
+ DOM_SID domain SID
+
+- USER_INFO (user logon info) :
+
+ Note: it would be nice to know what the 16 byte user session key is for.
+
+ NTTIME logon time
+ NTTIME logoff time
+ NTTIME kickoff time
+ NTTIME password last set time
+ NTTIME password can change time
+ NTTIME password must change time
+
+ UNIHDR username unicode string header
+ UNIHDR user's full name unicode string header
+ UNIHDR logon script unicode string header
+ UNIHDR profile path unicode string header
+ UNIHDR home directory unicode string header
+ UNIHDR home directory drive unicode string header
+
+ UINT16 logon count
+ UINT16 bad password count
+
+ UINT32 User ID
+ UINT32 Group ID
+ UINT32 num groups
+ VOID* undocumented buffer pointer to groups.
+
+ UINT32 user flags
+ char[16] user session key
+
+ UNIHDR logon server unicode string header
+ UNIHDR logon domain unicode string header
+ VOID* undocumented logon domain id pointer
+ char[40] 40 undocumented padding bytes. future expansion?
+
+ UINT32 0 - num_other_sids?
+ VOID* NULL - undocumented pointer to other domain SIDs.
+
+ UNISTR2 username unicode string
+ UNISTR2 user's full name unicode string
+ UNISTR2 logon script unicode string
+ UNISTR2 profile path unicode string
+ UNISTR2 home directory unicode string
+ UNISTR2 home directory drive unicode string
+
+ UINT32 num groups
+ GID[num_groups] group info
+
+ UNISTR2 logon server unicode string
+ UNISTR2 logon domain unicode string
+
+ DOM_SID domain SID
+ DOM_SID[num_sids] other domain SIDs?
+
+- SH_INFO_1_PTR (pointers to level 1 share info strings):
+
+Note: see cifsrap2.txt section5, page 10.
+
+ 0 for shi1_type indicates a Disk.
+ 1 for shi1_type indicates a Print Queue.
+ 2 for shi1_type indicates a Device.
+ 3 for shi1_type indicates an IPC pipe.
+ 0x8000 0000 (top bit set in shi1_type) indicates a hidden share.
+
+ VOID* shi1_netname - pointer to net name
+ UINT32 shi1_type - type of share. 0 - undocumented.
+ VOID* shi1_remark - pointer to comment.
+
+- SH_INFO_1_STR (level 1 share info strings) :
+
+ UNISTR2 shi1_netname - unicode string of net name
+ UNISTR2 shi1_remark - unicode string of comment.
+
+- SHARE_INFO_1_CTR :
+
+ share container with 0 entries:
+
+ UINT32 0 - EntriesRead
+ UINT32 0 - Buffer
+
+ share container with > 0 entries:
+
+ UINT32 EntriesRead
+ UINT32 non-zero - Buffer
+ UINT32 EntriesRead
+
+ SH_INFO_1_PTR[EntriesRead] share entry pointers
+ SH_INFO_1_STR[EntriesRead] share entry strings
+
+ UINT8[] padding to get unicode string 4-byte
+ aligned with start of the SMB header.
+ UINT32 EntriesRead
+ UINT32 0 - padding
+
+- SERVER_INFO_101 :
+
+Note: see cifs6.txt section 6.4 - the fields described therein will be
+ of assistance here. for example, the type listed below is the
+ same as fServerType, which is described in 6.4.1.
+
+ SV_TYPE_WORKSTATION 0x00000001 All workstations
+ SV_TYPE_SERVER 0x00000002 All servers
+ SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ server
+ SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ service
+ SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ SV_TYPE_NOVELL 0x00000080 Novell servers
+ SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ SV_TYPE_NT 0x00001000 NT server
+ SV_TYPE_WFW 0x00002000 Server running Windows for
+
+ SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ service
+ SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ "local"
+ SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszServer
+ and pszDomain parameters must be
+ NULL.
+
+ UINT32 500 - platform_id
+ VOID* pointer to name
+ UINT32 5 - major version
+ UINT32 4 - minor version
+ UINT32 type (SV_TYPE_... bit field)
+ VOID* pointer to comment
+
+ UNISTR2 sv101_name - unicode string of server name
+ UNISTR2 sv_101_comment - unicode string of server comment.
+
+ UINT8[] padding to get unicode string 4-byte
+ aligned with start of the SMB header.
+
+
+
+3) MSRPC over Transact Named Pipe
+---------------------------------
+
+For details on the SMB Transact Named Pipe, see cifs6.txt
+
+
+3.1) MSRPC Pipes
+----------------
+
+The MSRPC is conducted over an SMB Transact Pipe with a name of "\PIPE\".
+You must first obtain a 16 bit file handle, by sending a SMBopenX with the
+pipe name "\PIPE\srvsvc" for example. You can then perform an SMB Trans,
+and must carry out an SMBclose on the file handle once you are finished.
+
+Trans Requests must be sent with two setup UINT16s, no UINT16 params (none
+known about), and UINT8 data parameters sufficient to contain the MSRPC
+header, and MSRPC data. The first UINT16 setup parameter must be either
+0x0026 to indicate an RPC, or 0x0001 to indicate Set Named Pipe Handle
+state. The second UINT16 parameter must be the file handle for the pipe,
+obtained above.
+
+The Data section for an API Command of 0x0026 (RPC pipe) in the Trans
+Request is the RPC Header, followed by the RPC Data. The Data section for
+an API Command of 0x0001 (Set Named Pipe Handle state) is two bytes. The
+only value seen for these two bytes is 0x00 0x43.
+
+
+MSRPC Responses are sent as response data inside standard SMB Trans
+responses, with the MSRPC Header, MSRPC Data and MSRPC tail.
+
+
+It is suspected that the Trans Requests will need to be at least 2-byte
+aligned (probably 4-byte). This is standard practice for SMBs. It is also
+independent of the observed 4-byte alignments with the start of the MSRPC
+header, including the 4-byte alignment between the MSRPC header and the
+MSRPC data.
+
+
+First, an SMBtconX connection is made to the IPC$ share. The connection
+must be made using encrypted passwords, not clear-text. Then, an SMBopenX
+is made on the pipe. Then, a Set Named Pipe Handle State must be sent,
+after which the pipe is ready to accept API commands. Lastly, and SMBclose
+is sent.
+
+
+To be resolved:
+
+ lkcl/01nov97 there appear to be two additional bytes after the null-
+ terminated \PIPE\ name for the RPC pipe. Values seen so far are
+ listed below:
+
+ initial SMBopenX request: RPC API command 0x26 params:
+
+ "\\PIPE\\lsarpc" 0x65 0x63; 0x72 0x70; 0x44 0x65;
+ "\\PIPE\\srvsvc" 0x73 0x76; 0x4E 0x00; 0x5C 0x43;
+
+
+3.2) Header
+-----------
+
+[section to be rewritten, following receipt of work by Duncan Stansfield]
+
+
+Interesting note: if you set packed data representation to 0x0100 0000
+then all 4-byte and 2-byte word ordering is turned around!
+
+The start of each of the NTLSA and NETLOGON named pipes begins with:
+
+00 UINT8 5 - RPC major version
+01 UINT8 0 - RPC minor version
+02 UINT8 2 - RPC response packet
+03 UINT8 3 - (FirstFrag bit-wise or with LastFrag)
+04 UINT32 0x1000 0000 - packed data representation
+08 UINT16 fragment length - data size (bytes) inc header and tail.
+0A UINT16 0 - authentication length
+0C UINT32 call identifier. matches 12th UINT32 of incoming RPC data.
+10 UINT32 allocation hint - data size (bytes) minus header and tail.
+14 UINT16 0 - presentation context identifier
+16 UINT8 0 - cancel count
+17 UINT8 in replies: 0 - reserved; in requests: opnum - see #defines.
+18 ...... start of data (goes on for allocation_hint bytes)
+
+
+RPC_Packet for request, response, bind and bind acknowledgement.
+{
+
+ UINT8 versionmaj # reply same as request (0x05)
+ UINT8 versionmin # reply same as request (0x00)
+ UINT8 type # one of the MSRPC_Type enums
+ UINT8 flags # reply same as request (0x00 for Bind, 0x03 for Request)
+ UINT32 representation # reply same as request (0x00000010)
+ UINT16 fraglength # the length of the data section of the SMB trans packet
+ UINT16 authlength
+ UINT32 callid # call identifier. (e.g. 0x00149594)
+
+ * stub USE TvPacket # the remainder of the packet depending on the "type"
+}
+
+
+# the interfaces are numbered. as yet I haven't seen more than one interface
+# used on the same pipe name
+# srvsvc
+# abstract (0x4B324FC8, 0x01D31670, 0x475A7812, 0x88E16EBF, 0x00000003)
+# transfer (0x8A885D04, 0x11C91CEB, 0x0008E89F, 0x6048102B, 0x00000002)
+RPC_Iface RW
+{
+ UINT8 byte[16] # 16 bytes of number
+ UINT32 version # the interface number
+}
+
+
+# the remainder of the packet after the header if "type" was Bind
+# in the response header, "type" should be BindAck
+RPC_ReqBind RW
+{
+ UINT16 maxtsize # maximum transmission fragment size (0x1630)
+ UINT16 maxrsize # max receive fragment size (0x1630)
+ UINT32 assocgid # associated group id (0x0)
+ UINT32 numelements # the number of elements (0x1)
+ UINT16 contextid # presentation context identifier (0x0)
+ UINT8 numsyntaxes # the number of syntaxes (has always been 1?)(0x1)
+ UINT8[] # 4-byte alignment padding, against SMB header
+
+ * abstractint USE RPC_Iface # num and vers. of interface client is using
+ * transferint USE RPC_Iface # num and vers. of interface to use for replies
+}
+
+
+RPC_Address RW
+{
+ UINT16 length # length of the string including null terminator
+ * port USE string # the string above in single byte, null terminated form
+}
+
+
+# the response to place after the header in the reply packet
+RPC_ResBind RW
+{
+ UINT16 maxtsize # same as request
+ UINT16 maxrsize # same as request
+ UINT32 assocgid # zero
+
+ * secondaddr USE RPC_Address # the address string, as described earlier
+
+ UINT8[] # 4-byte alignment padding, against SMB header
+
+ UINT8 numresults # the number of results (0x01)
+
+ UINT8[] # 4-byte alignment padding, against SMB header
+ UINT16 result # result (0x00 = accept)
+ UINT16 reason # reason (0x00 = no reason specified)
+
+ * transfersyntax USE RPC_Iface # the transfer syntax from the request
+}
+
+
+# the remainder of the packet after the header for every other other
+# request
+RPC_ReqNorm RW
+{
+ UINT32 allochint # the size of the stub data in bytes
+ UINT16 prescontext # presentation context identifier (0x0)
+ UINT16 opnum # operation number (0x15)
+
+ * stub USE TvPacket # a packet dependent on the pipe name
+ # (probably the interface) and the op number)
+}
+
+
+# response to a request
+RPC_ResNorm RW
+{
+ UINT32 allochint # size of the stub data in bytes
+ UINT16 prescontext # presentation context identifier (same as request)
+ UINT8 cancelcount # cancel count? (0x0)
+ UINT8 reserved # 0 - one byte padding
+
+ * stub USE TvPacket # the remainder of the reply
+}
+
+
+3.3) Tail
+---------
+
+The end of each of the NTLSA and NETLOGON named pipes ends with:
+
+ ...... end of data
+ UINT32 return code
+
+
+
+3.4 RPC Bind / Bind Ack
+-----------------------
+
+RPC Binds are the process of associating an RPC pipe (e.g \PIPE\lsarpc)
+with a "transfer syntax" (see RPC_Iface structure). The purpose for doing
+this is unknown.
+
+Note: The RPC_ResBind SMB Transact request is sent with two uint16 setup
+ parameters. The first is 0x0026; the second is the file handle
+ returned by the SMBopenX Transact response.
+
+Note: The RPC_ResBind members maxtsize, maxrsize and assocgid are the
+ same in the response as the same members in the RPC_ReqBind. The
+ RPC_ResBind member transfersyntax is the same in the response as
+ the
+
+Note: The RPC_ResBind response member secondaddr contains the name
+ of what is presumed to be the service behind the RPC pipe. The
+ mapping identified so far is:
+
+ initial SMBopenX request: RPC_ResBind response:
+
+ "\\PIPE\\srvsvc" "\\PIPE\\ntsvcs"
+ "\\PIPE\\samr" "\\PIPE\\lsass"
+ "\\PIPE\\lsarpc" "\\PIPE\\lsass"
+ "\\PIPE\\wkssvc" "\\PIPE\\wksvcs"
+ "\\PIPE\\NETLOGON" "\\PIPE\\NETLOGON"
+
+Note: The RPC_Packet fraglength member in both the Bind Request and Bind
+ Acknowledgment must contain the length of the entire RPC data,
+ including the RPC_Packet header.
+
+Request:
+
+ RPC_Packet
+ RPC_ReqBind
+
+Response:
+
+ RPC_Packet
+ RPC_ResBind
+
+
+
+4) NTLSA Transact Named Pipe
+----------------------------
+
+The sequence of actions taken on this pipe are:
+
+- Establish a connection to the IPC$ share (SMBtconX). use encrypted passwords.
+- Open an RPC Pipe with the name "\\PIPE\\lsarpc". Store the file handle.
+- Using the file handle, send a Set Named Pipe Handle state to 0x4300.
+- Send an LSA Open Policy request. Store the Policy Handle.
+- Using the Policy Handle, send LSA Query Info Policy requests, etc.
+- Using the Policy Handle, send an LSA Close.
+- Close the IPC$ share.
+
+
+Defines for this pipe, identifying the query are:
+
+- LSA Open Policy: 0x2c
+- LSA Query Info Policy: 0x07
+- LSA Enumerate Trusted Domains: 0x0d
+- LSA Open Secret: 0xff
+- LSA Lookup SIDs: 0xfe
+- LSA Lookup Names: 0xfd
+- LSA Close: 0x00
+
+
+4.1) LSA Open Policy
+--------------------
+
+Note: The policy handle can be anything you like.
+
+Request:
+
+ VOID* buffer pointer
+ UNISTR2 server name - unicode string starting with two '\'s
+ OBJ_ATTR object attributes
+ UINT32 1 - desired access
+
+Response:
+
+ POL_HND LSA policy handle
+
+ return 0 - indicates success
+
+
+4.2) LSA Query Info Policy
+--------------------------
+
+Note: The info class in response must be the same as that in the request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT16 info class (also a policy handle?)
+
+Response:
+
+ VOID* undocumented buffer pointer
+ UINT16 info class (same as info class in request).
+
+ switch (info class)
+ case 3:
+ case 5:
+ {
+ DOM_INFO domain info, levels 3 and 5 (are the same).
+ }
+
+ return 0 - indicates success
+
+
+4.3) LSA Enumerate Trusted Domains
+----------------------------------
+
+Request:
+
+ no extra data
+
+Response:
+
+ UINT32 0 - enumeration context
+ UINT32 0 - entries read
+ UINT32 0 - trust information
+
+ return 0x8000 001a - "no trusted domains" success code
+
+
+4.4) LSA Open Secret
+--------------------
+
+Request:
+
+ no extra data
+
+Response:
+
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+
+ return 0x0C00 0034 - "no such secret" success code
+
+
+4.5) LSA Close
+--------------
+
+Request:
+
+ POL_HND policy handle to be closed
+
+Response:
+
+ POL_HND 0s - closed policy handle (all zeros)
+
+ return 0 - indicates success
+
+
+4.6) LSA Lookup SIDS
+--------------------
+
+Note: num_entries in response must be same as num_entries in request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT32 num_entries
+ VOID* undocumented domain SID buffer pointer
+ VOID* undocumented domain name buffer pointer
+ VOID*[num_entries] undocumented domain SID pointers to be looked up.
+ DOM_SID[num_entries] domain SIDs to be looked up.
+ char[16] completely undocumented 16 bytes.
+
+Response:
+
+ DOM_REF domain reference response
+
+ UINT32 num_entries (listed above)
+ VOID* undocumented buffer pointer
+
+ UINT32 num_entries (listed above)
+ DOM_SID2[num_entries] domain SIDs (from Request, listed above).
+
+ UINT32 num_entries (listed above)
+
+ return 0 - indicates success
+
+
+4.7) LSA Lookup Names
+---------------------
+
+Note: num_entries in response must be same as num_entries in request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT32 num_entries
+ UINT32 num_entries
+ VOID* undocumented domain SID buffer pointer
+ VOID* undocumented domain name buffer pointer
+ NAME[num_entries] names to be looked up.
+ char[] undocumented bytes - falsely translated SID structure?
+
+Response:
+
+ DOM_REF domain reference response
+
+ UINT32 num_entries (listed above)
+ VOID* undocumented buffer pointer
+
+ UINT32 num_entries (listed above)
+ DOM_RID[num_entries] domain SIDs (from Request, listed above).
+
+ UINT32 num_entries (listed above)
+
+ return 0 - indicates success
+
+
+
+5) NETLOGON rpc Transact Named Pipe
+-----------------------------------
+
+The sequence of actions taken on this pipe are:
+
+- Establish a connection to the IPC$ share (SMBtconX). use encrypted passwords.
+- Open an RPC Pipe with the name "\\PIPE\\NETLOGON". Store the file handle.
+- Using the file handle, send a Set Named Pipe Handle state to 0x4300.
+- Create Client Challenge. Send LSA Request Challenge. Store Server Challenge.
+- Calculate Session Key. Send an LSA Auth 2 Challenge. Store Auth2 Challenge.
+- Calc/Verify Client Creds. Send LSA Srv PW Set. Calc/Verify Server Creds.
+- Calc/Verify Client Creds. Send LSA SAM Logon . Calc/Verify Server Creds.
+- Calc/Verify Client Creds. Send LSA SAM Logoff. Calc/Verify Server Creds.
+- Close the IPC$ share.
+
+
+Defines for this pipe, identifying the query are:
+
+- LSA Request Challenge: 0x04
+- LSA Server Password Set: 0x06
+- LSA SAM Logon: 0x02
+- LSA SAM Logoff: 0x03
+- LSA Auth 2: 0x0f
+- LSA Logon Control: 0x0e
+
+
+5.1) LSA Request Challenge
+--------------------------
+
+Note: logon server name starts with two '\' characters and is upper case.
+
+Note: logon client is the machine, not the user.
+
+Note: the initial LanManager password hash, against which the challenge
+ is issued, is the machine name itself (lower case). there will be
+ calls issued (LSA Server Password Set) which will change this, later.
+ refusing these calls allows you to always deal with the same password
+ (i.e the LM# of the machine name in lower case).
+
+Request:
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ UNISTR2 logon client unicode string
+ char[8] client challenge
+
+Response:
+
+ char[8] server challenge
+
+ return 0 - indicates success
+
+
+
+5.2) LSA Authenticate 2
+-----------------------
+
+Note: in between request and response, calculate the client credentials,
+ and check them against the client-calculated credentials (this
+ process uses the previously received client credentials).
+
+Note: neg_flags in the response is the same as that in the request.
+
+Note: you must take a copy of the client-calculated credentials received
+ here, because they will be used in subsequent authentication packets.
+
+Request:
+
+ LOG_INFO client identification info
+
+ char[8] client-calculated credentials
+ UINT8[] padding to 4-byte align with start of SMB header.
+ UINT32 neg_flags - negotiated flags (usual value is 0x0000 01ff)
+
+Response:
+
+ char[8] server credentials.
+ UINT32 neg_flags - same as neg_flags in request.
+
+ return 0 - indicates success. failure value unknown.
+
+
+5.3) LSA Server Password Set
+----------------------------
+
+Note: the new password is suspected to be a DES encryption using the old
+ password to generate the key.
+
+Note: in between request and response, calculate the client credentials,
+ and check them against the client-calculated credentials (this
+ process uses the previously received client credentials).
+
+Note: the server credentials are constructed from the client-calculated
+ credentials and the client time + 1 second.
+
+Note: you must take a copy of the client-calculated credentials received
+ here, because they will be used in subsequent authentication packets.
+
+Request:
+
+ CLNT_INFO client identification/authentication info
+ char[] new password - undocumented.
+
+Response:
+
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ return 0 - indicates success; 0xC000 006a indicates failure
+
+
+5.4) LSA SAM Logon
+------------------
+
+Note: valid_user is True iff the username and password hash are valid for
+ the requested domain.
+
+Request:
+
+ SAM_INFO sam_id structure
+
+Response:
+
+ VOID* undocumented buffer pointer
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ if (valid_user)
+ {
+ UINT16 3 - switch value indicating USER_INFO structure.
+ VOID* non-zero - pointer to USER_INFO structure
+ USER_INFO user logon information
+
+ UINT32 1 - Authoritative response; 0 - Non-Auth?
+
+ return 0 - indicates success
+ }
+ else
+ {
+ UINT16 0 - switch value. value to indicate no user presumed.
+ VOID* 0x0000 0000 - indicates no USER_INFO structure.
+
+ UINT32 1 - Authoritative response; 0 - Non-Auth?
+
+ return 0xC000 0064 - NT_STATUS_NO_SUCH_USER.
+ }
+
+
+5.5) LSA SAM Logoff
+--------------------
+
+Note: presumably, the SAM_INFO structure is validated, and a (currently
+ undocumented) error code returned if the Logoff is invalid.
+
+Request:
+
+ SAM_INFO sam_id structure
+
+Response:
+
+ VOID* undocumented buffer pointer
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ return 0 - indicates success. undocumented failure indication.
+
+
+6) \\MAILSLOT\NET\NTLOGON
+-------------------------
+
+Note: mailslots will contain a response mailslot, to which the response
+ should be sent. the target NetBIOS name is REQUEST_NAME<20>, where
+ REQUEST_NAME is the name of the machine that sent the request.
+
+
+6.1) Query for PDC
+------------------
+
+Note: NTversion, LMNTtoken, LM20token in response are the same as those
+ given in the request.
+
+Request:
+
+ UINT16 0x0007 - Query for PDC
+ STR machine name
+ STR response mailslot
+ UINT8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+Response:
+
+ UINT16 0x000A - Respose to Query for PDC
+ STR machine name (in uppercase)
+ UINT8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ UNISTR domain name
+ UINT32 NTversion (same as received in request)
+ UINT16 LMNTtoken (same as received in request)
+ UINT16 LM20token (same as received in request)
+
+
+6.2) SAM Logon
+--------------
+
+Note: machine name in response is preceded by two '\' characters.
+
+Note: NTversion, LMNTtoken, LM20token in response are the same as those
+ given in the request.
+
+Note: user name in the response is presumably the same as that in the request.
+
+Request:
+
+ UINT16 0x0012 - SAM Logon
+ UINT16 request count
+ UNISTR machine name
+ UNISTR user name
+ STR response mailslot
+ UINT32 alloweable account
+ UINT32 domain SID size
+ char[sid_size] domain SID, of sid_size bytes.
+ UINT8[] ???? padding to 4? 2? -byte align with start of mailslot.
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+Response:
+
+ UINT16 0x0013 - Response to SAM Logon
+ UNISTR machine name
+ UNISTR user name - workstation trust account
+ UNISTR domain name
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+
+
+7) SRVSVC Transact Named Pipe
+-----------------------------
+
+
+Defines for this pipe, identifying the query are:
+
+- Net Share Enum : 0x0f
+- Net Server Get Info : 0x15
+
+
+7.1) Net Share Enum
+------------------
+
+Note: share level and switch value in the response are presumably the
+ same as those in the request.
+
+Note: cifsrap2.txt (section 5) may be of limited assistance here.
+
+Request:
+
+ VOID* pointer (to server name?)
+ UNISTR2 server name
+
+ UINT8[] padding to get unicode string 4-byte aligned
+ with the start of the SMB header.
+
+ UINT32 share level
+ UINT32 switch value
+
+ VOID* pointer to SHARE_INFO_1_CTR
+ SHARE_INFO_1_CTR share info with 0 entries
+
+ UINT32 preferred maximum length (0xffff ffff)
+
+Response:
+
+ UINT32 share level
+ UINT32 switch value
+
+ VOID* pointer to SHARE_INFO_1_CTR
+ SHARE_INFO_1_CTR share info (only added if share info ptr is non-zero)
+
+ return 0 - indicates success
+
+
+7.2) Net Server Get Info
+------------------
+
+Note: level is the same value as in the request.
+
+Request:
+
+ UNISTR2 server name
+ UINT32 switch level
+
+Response:
+
+ UINT32 switch level
+ VOID* pointer to SERVER_INFO_101
+
+ SERVER_INFO_101 server info (only added if server info ptr is non-zero)
+
+ return 0 - indicates success
+
+
+
+Appendix
+--------
+
+A1) Cryptographic side of NT Domain Authentication
+--------------------------------------------------
+
+
+A1.1) Definitions
+-----------------
+
+Add(A1,A2): Intel byte ordered addition of corresponding 4 byte words
+in arrays A1 and A2
+
+E(K,D): DES ECB encryption of 8 byte data D using 7 byte key K
+
+lmowf(): Lan man hash
+
+ntowf(): NT hash
+
+PW: md4(machine_password) == md4(lsadump $machine.acc) ==
+pwdump(machine$) (initially) == md4(lmowf(unicode(machine)))
+
+ARC4(K,Lk,D,Ld): ARC4 encryption of data D of length Ld with key K of
+length Lk
+
+v[m..n(,l)]: subset of v from bytes m to n, optionally padded with
+zeroes to length l
+
+Cred(K,D): E(K[7..7,7],E(K[0..6],D)) computes a credential
+
+Time(): 4 byte current time
+
+Cc,Cs: 8 byte client and server challenges Rc,Rs: 8 byte client and
+server credentials
+
+
+A1.2) Protocol
+--------------
+
+C->S ReqChal,Cc S->C Cs
+
+C & S compute session key Ks = E(PW[9..15],E(PW[0..6],Add(Cc,Cs)))
+
+C: Rc = Cred(Ks,Cc) C->S Authenticate,Rc S: Rs = Cred(Ks,Cs),
+assert(Rc == Cred(Ks,Cc)) S->C Rs C: assert(Rs == Cred(Ks,Cs))
+
+On joining the domain the client will optionally attempt to change its
+password and the domain controller may refuse to update it depending
+on registry settings. This will also occur weekly afterwards.
+
+C: Tc = Time(), Rc' = Cred(Ks,Rc+Tc) C->S ServerPasswordSet,Rc',Tc,
+arc4(Ks[0..7,16],lmowf(randompassword()) C: Rc = Cred(Ks,Rc+Tc+1) S:
+assert(Rc' == Cred(Ks,Rc+Tc)), Ts = Time() S: Rs' = Cred(Ks,Rs+Tc+1)
+S->C Rs',Ts C: assert(Rs' == Cred(Ks,Rs+Tc+1)) S: Rs = Rs'
+
+User: U with password P wishes to login to the domain (incidental data
+such as workstation and domain omitted)
+
+C: Tc = Time(), Rc' = Cred(Ks,Rc+Tc) C->S NetLogonSamLogon,Rc',Tc,U,
+arc4(Ks[0..7,16],16,ntowf(P),16), arc4(Ks[0..7,16],16,lmowf(P),16) S:
+assert(Rc' == Cred(Ks,Rc+Tc)) assert(passwords match those in SAM) S:
+Ts = Time()
+
+S->C Cred(Ks,Cred(Ks,Rc+Tc+1)),userinfo(logon script,UID,SIDs,etc) C:
+assert(Rs == Cred(Ks,Cred(Rc+Tc+1)) C: Rc = Cred(Ks,Rc+Tc+1)
+
+
+A1.3) Comments
+--------------
+
+On first joining the domain the session key could be computed by
+anyone listening in on the network as the machine password has a well
+known value. Until the machine is rebooted it will use this session
+key to encrypt NT and LM one way functions of passwords which are
+password equivalents. Any user who logs in before the machine has been
+rebooted a second time will have their password equivalent exposed. Of
+course the new machine password is exposed at this time anyway.
+
+None of the returned user info such as logon script, profile path and
+SIDs *appear* to be protected by anything other than the TCP checksum.
+
+The server time stamps appear to be ignored.
+
+The client sends a ReturnAuthenticator in the SamLogon request which I
+can't find a use for. However its time is used as the timestamp
+returned by the server.
+
+The password OWFs should NOT be sent over the network reversibly
+encrypted. They should be sent using ARC4(Ks,md4(owf)) with the server
+computing the same function using the owf values in the SAM.
+
+
+A2) SIDs and RIDs
+-----------------
+
+SIDs and RIDs are well documented elsewhere.
+
+A SID is an NT Security ID (see DOM_SID structure). They are of the form:
+
+ S-revision-NN-SubAuth1-SubAuth2-SubAuth3...
+ S-revision-0xNNNNNNNNNNNN-SubAuth1-SubAuth2-SubAuth3...
+
+currently, the SID revision is 1.
+The Sub-Authorities are known as Relative IDs (RIDs).
+
+
+A2.1) Well-known SIDs
+---------------------
+
+
+A2.1.1) Universal well-known SIDs
+---------------------------------
+
+ Null SID S-1-0-0
+ World S-1-1-0
+ Local S-1-2-0
+ Creator Owner ID S-1-3-0
+ Creator Group ID S-1-3-1
+ Creator Owner Server ID S-1-3-2
+ Creator Group Server ID S-1-3-3
+
+ (Non-unique IDs) S-1-4
+
+
+A2.1.2) NT well-known SIDs
+--------------------------
+
+ NT Authority S-1-5
+ Dialup S-1-5-1
+
+ Network S-1-5-2
+ Batch S-1-5-3
+ Interactive S-1-5-4
+ Service S-1-5-6
+ AnonymousLogon S-1-5-7 (aka null logon session)
+ Proxy S-1-5-8
+ ServerLogon S-1-5-8 (aka domain controller account)
+
+ (Logon IDs) S-1-5-5-X-Y
+
+ (NT non-unique IDs) S-1-5-0x15-...
+
+ (Built-in domain) s-1-5-0x20
+
+
+
+A2.2) Well-known RIDS
+---------------------
+
+A RID is a sub-authority value, as part of either a SID, or in the case
+of Group RIDs, part of the DOM_GID structure, in the USER_INFO_1
+structure, in the LSA SAM Logon response.
+
+
+A2.2.1) Well-known RID users
+----------------------------
+
+ DOMAIN_USER_RID_ADMIN 0x0000 01F4
+ DOMAIN_USER_RID_GUEST 0x0000 01F5
+
+
+
+A2.2.2) Well-known RID groups
+----------------------------
+
+ DOMAIN_GROUP_RID_ADMINS 0x0000 0200
+ DOMAIN_GROUP_RID_USERS 0x0000 0201
+ DOMAIN_GROUP_RID_GUESTS 0x0000 0202
+
+
+
+A2.2.3) Well-known RID aliases
+------------------------------
+
+ DOMAIN_ALIAS_RID_ADMINS 0x0000 0220
+ DOMAIN_ALIAS_RID_USERS 0x0000 0221
+ DOMAIN_ALIAS_RID_GUESTS 0x0000 0222
+ DOMAIN_ALIAS_RID_POWER_USERS 0x0000 0223
+
+ DOMAIN_ALIAS_RID_ACCOUNT_OPS 0x0000 0224
+ DOMAIN_ALIAS_RID_SYSTEM_OPS 0x0000 0225
+ DOMAIN_ALIAS_RID_PRINT_OPS 0x0000 0226
+ DOMAIN_ALIAS_RID_BACKUP_OPS 0x0000 0227
+
+ DOMAIN_ALIAS_RID_REPLICATOR 0x0000 0228
+
+
diff --git a/docs/textdocs/kurs.pdf b/docs/textdocs/kurs.pdf
new file mode 100644
index 00000000000..0846227020d
--- /dev/null
+++ b/docs/textdocs/kurs.pdf
Binary files differ
diff --git a/docs/textdocs/kurs.tex b/docs/textdocs/kurs.tex
new file mode 100644
index 00000000000..6f5a24098e5
--- /dev/null
+++ b/docs/textdocs/kurs.tex
@@ -0,0 +1,2460 @@
+\documentclass{scrartcl}
+\usepackage{pslatex}
+\usepackage[dvips,colorlinks=true,
+ pdfauthor={Volker Lendecke, Service Network GmbH},
+ pdftitle={Kursskript Samba},
+ pdfsubject={Samba},
+ pdfkeywords={samba,training}
+ ]{hyperref}
+\usepackage[T1]{fontenc}
+\usepackage{german}
+\usepackage{pstricks}
+\usepackage[dvips]{epsfig}
+\newcommand{\prog}{\texttt}
+\newcommand{\param}{\texttt}
+\newcommand{\datei}{\texttt}
+\newcommand{\nbname}{\texttt}
+\newcommand{\todo}{\texttt}
+\newcommand{\defin}{\emph}
+\hyphenation{Net-BIOS}
+
+\usepackage{fancyheadings}
+\pagestyle{fancyplain}
+\lhead{}
+\rhead{\thepage}
+\rfoot{\copyright{} 1999, 2000, Volker Lendecke (http://www.sernet.de/vl/)}
+\cfoot{}
+
+\begin{document}
+
+\title{Kursskript\\[\baselineskip]
+ \epsfig{file=logo.ps,width=6cm}}
+
+\author{Volker Lendecke\\
+Samba Team\\
+Service Network GmbH\\
+G"ottingen\\
+http://samba.SerNet.DE/}
+
+\date{\today}
+
+\maketitle
+\thispagestyle{empty}
+
+\begin{quote}
+ Dieses Dokument ist eine Mitschrift des Sambakurses der Service
+ Network GmbH in G"ottingen. Es gibt einen guten "Uberblick "uber den
+ Kurs und kann gleichzeitig als generelle Einf"uhrung in NetBIOS und
+ Samba dienen.
+\end{quote}
+
+\break
+
+\tableofcontents
+
+\break
+
+\section{Einf"uhrung}
+
+Samba -- Was ist das?
+
+Kurz gesagt l"a"st Samba jeden Unixrechner in der Netzwerkumgebung von
+Windows NT erscheinen. Au"serdem lassen sich mit Samba Datei- und
+Druckfreigaben erstellen. Das hei"st, unter Unix vorhandener
+Plattenplatz kann ganz normal unter Windows genutzt werden, und unter
+Unix vorhandene Drucker kann man als Netzwerkdrucker unter Windows
+ansteuern. Dar"uber hinaus bietet Samba viele Dienste, die sonst nur
+von Windows NT geleistet werden. Dazu geh"oren:
+
+\begin{description}
+
+\item[WINS Server] Mit Samba kann sehr einfach ein WINS Server
+ eingerichtet werden.
+
+\item[Computersuchdienst] Samba als sehr stabiler Server kann alle
+ Aufgaben des Computersuchdienstes "ubernehmen. Die in Windowsumgebungen
+ oft nicht sehr vorhersagbare Netzwerkumgebung kann so etwas
+ stabiler gemacht werden.
+
+\item[Logon Server] F"ur Windows 95/98 ist Samba Logon-Server, kann
+ also die Dom"anenanmeldung f"ur diese Systeme "ubernehmen.
+
+\item[PDC] Die Funktionalit"at des Primary Domain Controller ist in
+ einer noch nicht freigegebenen Version implementiert, ist jedoch
+ schon in vielen Installationen im produktiven Einsatz.
+
+\item[Diagnosewerkzeuge] Samba bietet eine Reihe von kleinen, aber
+sehr effektiven Werkzeugen, die die oft m"uhselige Suche nach Fehlern
+im Netz vereinfachen k"onnen.
+
+\end{description}
+
+Samba bietet gegen"uber den bekannten Implementationen des
+SMB-Protokolls einige Vorteile. Teilweise sind diese Vorteile von Unix
+geerbt, teilweise sind sie in der Architektur von Samba begr"undet.
+
+\begin{description}
+
+\item[Entfernte Administration] Der gr"o"ste Vorteil von Samba in
+ gr"o"seren Umgebungen ist die M"oglichkeit, die gesamte
+ Administration von der Kommandozeile aus durchzuf"uhren. Damit
+ bekommt man gegen"uber grafischen Oberfl"achen sehr viel bessere
+ M"oglichkeiten, von entfernten Standorten aus zu administrieren.
+ Werkzeuge wie PC Anywhere sind hier deutlich weniger flexibel.
+
+ Zus"atzlich bietet Samba die M"oglichkeit der grafischen
+ Administration "uber einen Webbrowser. Auch hier ist es unerheblich,
+ wo sich Administrator und Server befinden.
+
+\item[Zentrale Konfiguration] Die gesamte Konfiguration von Samba
+ befindet sich in einer einzigen Datei und ist nicht "uber viele
+ Dialogfelder verteilt. Das erleichtert die Administration erheblich.
+ So l"a"st sich eine funktionierende Konfiguration sehr einfach
+ sichern und wieder einspielen.
+
+\item[Stabilit"at] Samba erbt von Unix eine hohe Stabilit"at.
+ Unixrechner sind daf"ur ausgelegt, "uber Monate hinweg durchzulaufen
+ und leisten dies auch. Samba als weiterer Proze"s profitiert von
+ dieser hohen Verf"ugbarkeit. Die modulare Struktur von Unix l"a"st
+ es dar"uber hinaus zu, da"s der Serverdienst Samba unabh"angig von
+ allen anderen Systemprozessen eigenst"andig neu gestartet werden
+ kann, sofern hier ein Problem vorliegen sollte.
+
+ Samba hat eine Architektur, die die Stabilit"at weiter f"ordert.
+ F"ur jede Clientverbindung wird ein eigener Proze"s gestartet.
+ Verursacht also ein Client ein Problem auf Serverseite, dann wird
+ nur dieser Client in Mitleidenschaft gezogen. Eventuell
+ st"urzt dieser eine Proze"s ab, die anderen werden jedoch
+ nicht gest"ort.
+
+\item[Skalierbarkeit] Samba kann von dem vielzitierten kleinen 386er
+ unter Linux bis hin zu den gr"o"sten heute verf"ugbaren Maschinen
+ jede Hardware optimal ausnutzen. Die Architektur von Samba
+ erm"oglicht es, da"s auch Multiprozessormaschinen optimal
+ ausgelastet werden. Multiprozessormaschinen k"onnen alle Prozessoren dann
+ besch"aftigen, wenn es viele unabh"angige Prozesse im System gibt.
+ Samba erstellt f"ur jeden Client einen Proze"s, der auf einem
+ eigenen Prozessor ablaufen kann.
+
+\item[Flexibilit"at] Samba bietet eine riesige Anzahl von
+ Konfigurationsoptionen, die zun"achst einmal "uberw"altigend wirkt.
+ Im Laufe des Kurses wird sich herausstellen, da"s f"ur das
+ Funktionieren von Samba nur sehr wenige Optionen wirklich notwendig
+ sind. Die meisten Optionen werden nur f"ur Spezialf"alle ben"otigt.
+ Durch ein sehr flexibles Schema von Makroersetzungen ist mit Samba
+ sehr viel mehr m"oglich als mit NT. Als Beispiel sei genannt, da"s
+ man sehr einfach einen Sambaserver unter zwei verschiedenen Namen in
+ der Netzwerkumgebung erscheinen lassen kann, und beide virtuelle
+ Server unterschiedlich konfigurieren kann. Zu Testzwecken ist es
+ sogar m"oglich,
+ zwei unterschiedliche Versionen gleichzeitig auf einer Maschine
+ laufen zu lassen.
+
+\end{description}
+
+\section{NetBIOS}
+
+Sobald Windowsrechner Dateisysteme austauschen, sich gegenseitig in
+der Netzwerkumgebung sehen oder Drucker freigeben, funktioniert die
+Kommunikation "uber NetBIOS\footnote{Dies ist in reinen Windows 2000
+ Umgebungen nicht mehr richtig. Microsoft hat die NetBIOS-Ebene
+ abgeschafft, Windows 2000 kommuniziert direkt "uber TCP. Aus
+ Kompatibilit"atsgr"unden kann Windows 2000 jedoch noch "uber NetBIOS
+ kommunizieren.}. NetBIOS ist eine reine
+Softwareschnittstelle zur Kommunikation von Rechnern. Mit dieser
+Schnittstelle werden Programmen unterschiedliche Dienste zur
+Kommunikation zur Verf"ugung gestellt. NetBIOS wurde entworfen, um in
+kleinen, lokalen Netzen Kommunikation zu erm"oglichen. Dabei lag der
+Schwerpunkt des Entwurfs auf der Einfachheit der Anwendung. Auf
+Skalierbarkeit und die Andwendung in Weitverkehrsnetzen wurde beim
+Design nicht geachtet.
+
+Die Kommunikation mit NetBIOS wurde in drei Teilbereiche aufgeteilt,
+den Namensdienst, den Datagramm- und den Sitzungsdienst.
+
+\begin{description}
+
+\item[Namensdienst:] Im Rahmen des Namensdienstes sind die Rechner in
+ der Lage, sich gegenseitig im Netz zu identifizieren. Es sei an
+ dieser Stelle betont, da"s der NetBIOS-Namensdienst nichts mit der
+ Anzeige in der Netzwerkumgebung zu tun hat. Der Computersuchdienst,
+ der f"ur die Netzwerkumgebung zust"andig ist, h"angt jedoch sehr
+ stark von einem korrekt funktionierenden Namensdienst ab.
+
+\item[Datagrammdienst:] Betrachtet man die Rechnerkommunikation auf
+ dem Netz, so sieht man, da"s die versendeten Daten in einzelne
+ Pakete aufgeteilt werden.
+ Diese einzelnen Pakete werden dann vom Netz nach bestem Bem"uhen an
+ einen Zielrechner ausgeliefert. Geht ein Paket verloren, kann man
+ nichts machen, man bekommt unter Umst"anden nicht einmal eine
+ Benachrichtigung dar"uber, da"s etwas nicht stimmt. Aufeinander
+ folgende Pakete k"onnen in vertauschter Reihenfolge beim Empf"anger
+ ankommen. Es kann sogar sein, da"s Pakete auf dem Weg dupliziert
+ werden, also mehrfach ankommen. Diese Unzuverl"assigkeit des Netzes
+ wird durch den Datagrammdienst an die Benutzerprogramme
+ weitergegeben. Der Datagrammdienst hat jedoch nicht nur Nachteile.
+ Zwei Vorteile sind der geringe Aufwand, mit dem Pakete verschickt
+ werden k"onnen, und die M"oglichkeit, ein Datagramm an mehrere
+ Rechner gleichzeitig zu verschicken. Die Applikation mu"s selbst
+ entscheiden, wie sie mit der Unzuverl"assigkeit des Dienstes
+ klarkommt.
+
+\item[Sitzungsdienst:] Die Unzuverl"assigkeit des Netzes ist f"ur
+bestimmte Applikationen wie Dateitransfer oder Terminalanwendungen
+nicht akzeptabel. Wenn man eine Datei "ubertr"agt, m"ochte man sicher
+sein, da"s die Datei komplett und korrekt "ubertragen wurde. F"ur
+diese h"oheren Anforderungen wurde der Sitzungsdienst entworfen. Zwei
+Rechner vereinbaren eine NetBIOS-Sitzung. Die Daten, die "uber diese
+Verbindung "ubertragen werden, kommen auf jeden Fall an, und zwar in
+der richtigen Reihenfolge. K"onnen Daten einmal nicht "ubertragen
+werden, so erh"alt die versendende Applikation eine Fehlermeldung. Die
+Applikation kann nun versuchen, die abgebrochene Sitzung neu
+aufzubauen. Dieser Zuverl"assigkeit steht ein erh"ohter Aufwand beim
+Sitzungsauf- und -abbau gegen"uber.
+
+\end{description}
+
+Zwei Rechner, die kommunizieren wollen, m"ussen sich zun"achst gegenseitig
+identifizieren. NetBIOS sieht hierf"ur bis zu 16 Zeichen lange Namen
+vor. Jede Applikation kann f"ur sich beliebig viele Namen reservieren
+und unter einem dieser Namen Verbindungen aufbauen und Daten austauschen.
+Diese Reservierung von Namen gilt sowohl f"ur Server, die vom Netz aus
+erreichbar sein m"ussen, als auch f"ur Clients, die Server im Netz
+erreichen wollen, da Server wissen m"ussen, wohin die Antworten
+gehen m"ussen.
+
+Zwei Anwendungen wollen nun per NetBIOS miteinander kommunizieren.
+Dazu mu"s zun"achst der Server seine Bereitschaft kundtun,
+Verbindungen entgegenzunehmen. Dazu meldet er sich im Netz mit seinem
+Namen an. Diese Anmeldung geschieht per Broadcast, so da"s alle im
+Netz mith"oren k"onnen. Jeder Rechner ist frei, beliebige Namen im
+Netz f"ur sich zu beanspruchen, sofern diese noch nicht belegt
+sind\footnote{Mit dieser Freiheit ergeben sich viele M"oglicheiten,
+ von einem beliebigen Rechner aus ein Windows-Netz bis zur
+ Unbenutzbarkeit zu st"oren. Man mu"s nur bestimmte, f"ur den PDC
+ vorgesehene Namen zum richtigen Zeitpunkt reservieren.}. Eine
+Reservierung geschieht also, indem ein Rechner per Broadcast
+ank"undigt, da"s er unter einem bestimmten Namen erreichbar ist. Dann
+wartet er auf Protest. Beklagt sich niemand, schickt er eine zweite
+Reservierung und wartet wieder. Nach der dritten Reservierung ist der
+Rechner ausreichend sicher, da"s kein anderer den Namen bereits f"ur
+sich eingenommen hat, und sieht ihn als f"ur sich reserviert an.
+
+Wenn nun ein Client mit einem Server reden m"ochte, dann mu"s er sich
+wie der Server einen eindeutigen Namen ausdenken und im Netz
+reservieren. Das Verfahren dazu ist identisch. Zus"atzlich mu"s der
+Client jedoch die MAC-Adresse des Servers herausbekommen. Die
+Mechanismen, wie dies geschieht, h"angen davon ab, wie NetBIOS
+implementiert ist.
+
+NetBIOS kann mit unterschiedlichen Protokollen implementiert werden.
+NetBEUI, IPX und TCP/IP sind drei heute verwendete Protokolle, wobei
+f"ur Neuinstallation TCP/IP das bevorzugte Protokoll sein sollte.
+Der Ablauf der Namensaufl"osung soll an einem
+Beispiel verdeutlicht werden.
+
+Auf einem Client soll eine Verbindung zu dem Server \nbname{samba}
+aufgebaut werden. Direkt erreicht man dies, indem man in der Taskleiste
+Start $\rightarrow$ Ausf"uhren $\rightarrow$ \verb|\\samba| eingibt.
+Im folgenden werden die unterschiedlichen Verfahren betrachtet, mit
+denen ein Rechner die MAC-Adresse des Servers herausbekommt.
+
+\begin{description}
+
+\item[NetBEUI:]
+
+ \textbf{"`Samba"'$\,\Rightarrow\,$MAC-Adresse}
+
+ Bei diesem Protokoll findet der Client den Server ausschlie"slich
+ "uber Broadcasts. Er verschickt per Broadcast eine Anfrage, wer sich
+ f"ur den gesuchten Namen verantwortlich f"uhlt. Der Rechner, der
+ diesen Namen tats"achlich als Server reserviert hat, wird aufgrund
+ dieser Anfrage seine eigene MAC-Adresse aus dem ROM seiner
+ Netzwerkkarte auslesen und entsprechend antworten. Daraufhin kann
+ der Client dann die Verbindung aufbauen. "Uber NetBEUI k"onnen also
+ nur Rechner miteinander reden, die in der gleichen Broadcastdom"ane
+ liegen. Sobald Router zum Einsatz kommen sollen, kann reines NetBEUI
+ nicht mehr verwendet werden, da dann der Server, der kontaktiert
+ werden soll, von der Namensanfrage nichts mehr mitbekommt, also auch
+ nicht antworten kann.
+
+\item[IPX]
+
+ \textbf{"`Samba"'$\,\Rightarrow\,$IPX-Knotenadresse
+ $\,\Rightarrow\,$MAC-Adresse}
+
+ Bei IPX liegt zwischen Servernamen und der MAC-Adresse die
+ IPX-Knotenadresse. Diese enth"alt eine 4 Byte lange Netzwerknummer
+ und die 6 Byte lange MAC-Adresse des Rechners. Die Knotenadresse
+ wird anhand des NetBIOS-Namens wie bei NetBEUI per Broadcast im
+ lokalen Netz gesucht. Damit w"aren Rechner hinter Routern nicht
+ erreichbar, da die Namensanfrage nicht zu ihnen durchdringt.
+ IPX-Router erkennen diese Namensanfragen und leiten sie per
+ Broadcast in s"amtliche angeschlossenen Netze weiter, so da"s die
+ Anfrage jedes Teilnetz erreicht.
+
+ Jede Anfrage l"ost einen Broadcast in jedem angeschlossenen Subnetz
+ aus. Einige IPX-Router speichern eine Namenstabelle und k"onnen so
+ viele Anfragen selbst beantworten, so da"s die Broadcastlast
+ reduziert wird.
+
+\item[TCP/IP]
+
+ \textbf{"`Samba"'$\,\Rightarrow\,$IP-Adresse$\,\Rightarrow\,
+ $MAC-Adresse}
+
+ Bei TCP/IP mu"s der Client die IP-Adresse des Servers herausfinden.
+ Dies geschieht wie bei den anderen Protokollen per Broadcast im
+ lokalen Netz. IP-Router k"onnen nicht angewiesen werden, die
+ Anfragen per Broadcast in alle angeschlossenen Netze weiterzuleiten.
+ Aus diesem Grund gibt es hier andere Mechanismen, die im folgenden
+ beschrieben werden.
+
+ Nachdem die IP-Adresse herausgefunden wurde, kommen die bekannten
+ Mechanismen von IP zum tragen. Befindet sich der Rechner im eigenen
+ Subnetz, wird direkt eine ARP-Anfrage nach der MAC-Adresse
+ ausgel"ost. Andernfalls wird der entsprechende Router anhand der
+ Routingtabelle herausgefunden und dann dessen MAC-Adresse per ARP
+ festgestellt.
+
+\end{description}
+
+Die Protokolle ordnen sich folgenderma"sen ein:
+
+\begin{figure}[ht]
+\[\begin{pspicture}(12,6)
+\psframe(3,0)(9,1)
+\rput(6,0.5){Hardware}
+\psframe(3,1)(5,3)
+\rput(4,2){TCP/IP}
+\psframe(5,1)(7,3)
+\rput(6,2){NetBEUI}
+\psframe(7,1)(9,2)
+\rput(8,1.5){IPX}
+\psframe(7,2)(9,3)
+\rput(8,2.5){NWLink}
+\psframe(3,3)(9,4)
+\rput(6,3.5){{\bfseries NetBIOS}}
+\psframe(0,4)(2,5)
+\rput(1,4.5){ping}
+\psline(0,4)(3,3)
+\psline(2,4)(5,3)
+\psframe(10,3)(12,4)
+\rput(11,3.5){NWClient}
+\psline(7,2)(10,3)
+\psline(9,2)(12,3)
+\psframe(3,4)(6,5)
+\rput(4.5,4.5){SMB}
+\psframe(3,5)(6,6)
+\rput(4.5,5.5){Datei, Druck}
+\psframe(6,4)(9,6)
+\rput(7.5,5.5){Andere}
+\rput(7.5,5){NetBIOS-}
+\rput(7.5,4.5){Anwendungen}
+\end{pspicture}\]
+\caption{Protokollstapel}
+\label{protokollstapel}
+\end{figure}
+
+In dieser Grafik steht das Programm \prog{ping} f"ur beliebige
+Programme, die direkt auf TCP/IP aufsetzen. Dies gilt beispielsweise
+f"ur alle WWW-Browser und f"ur die Programme \prog{telnet} und
+\prog{ftp}.
+
+Man kann festhalten, da"s NetBEUI hier das einzige Protokoll ist, das
+nicht "uber Routergrenzen hinweg verwendbar ist. Sowohl IPX als auch
+IP sind f"ur den Einsatz in Weitverkehrsnetzen entworfen worden und
+k"onnen folglich mit Routern umgehen.
+
+Samba ist ausschlie"slich in der Lage, NetBIOS "uber TCP/IP zu
+benutzen. Daher werden die anderen Protokolle ab hier ignoriert.
+
+\section{Bestandteile von Samba}
+
+Das Programmpaket Samba besteht aus mehreren Programmen, von denen
+einige der Serverseite und andere der Clientseite zugeordnet werden
+k"onnen.
+
+Die Servertools:
+
+\begin{description}
+
+\item[smbd] ist der zentrale Serverproze"s, der f"ur die eigentlichen
+ Datei- und Druckdienste zust"andig ist. Sie werden mehrere
+ \prog{smbd}s im System finden. Einer dieser Prozesse lauscht auf dem
+ TCP-Port 139, und nimmt neue Verbindungen entgegen. Jede neue
+ Verbindung st"o"st einen neuen Proze"s \prog{smbd} an. Wenn Sie
+ einen Client vom Sambaserver trennen wollen, m"ussen Sie nur mit
+ \prog{smbstatus} die Proze"snummer des zust"andigen \prog{smbd}
+ erfragen, und diesen einen Proze"s t"oten.
+
+ Samba ist im Hauptspeicherverbrauch recht sparsam. Jeder
+ \emph{aktive} Client ben"otigt etwa 1 MB Hauptspeicher auf dem
+ Server. Clients, die gerade nicht aktiv Dateien mit dem Sambaserver
+ austauschen, ben"otigen praktisch "uberhaupt keine Resourcen. Viel
+ Hauptspeicher kann von Samba selbstverst"andlich gut als Cache
+ genutzt werden.
+
+\item[nmbd] ist f"ur die NetBIOS Namens- und Datagrammdienste
+ zust"andig. Dieser Proze"s reserviert beim Start von Samba die
+ entsprechenden NetBIOS-Namen, er ist WINS-Server und f"ur den
+ Computersuchdienst zust"andig.
+
+\item[testparm] Mit diesem Programm kann man die \datei{smb.conf} auf
+ syntaktische Korrektheit pr"ufen. Das Programm liest die
+ Konfigurationsdatei ein und gibt Fehlermeldungen aus, sofern es
+ unbekannte Parameter findet.
+
+\item[smbpasswd] wird zur Pflege der verschl"usselten Pa"sw"orter auf
+ Serverseite verwendet. Wie dies funktioniert, wird im Kapitel
+ \ref{passwoerter} erkl"art.
+
+\end{description}
+
+Die Clients:
+
+\begin{description}
+
+\item[smbclient:] Mit dem Programm \prog{smbclient} kann man auf
+ Freigaben von NT-Rechnern zugreifen. Man kann auf von NT zur
+ Verf"ugung gestellten Druckern drucken und man kann NT-Freigaben in
+ tar-Dateien sichern. Weiterhin wird mit \prog{smbclient} die Liste
+ der Server im Netz erfragt, analog zu der Netzwerkumgebung unter
+ Windows.
+
+\item[nmblookup] ist ein Diagnosewerkzeug f"ur die
+ NetBIOS-Namensaufl"osung. Wenn zwei Computer mit Windows sich
+ nicht finden k"onnen, kann man mit \prog{nmblookup} deren Versuche,
+ sich gegenseitig zu finden, genau nachstellen. Ebenso k"onnen
+ WINS-Server befragt werden und ein NetBIOS Node Status abgefragt
+ werden. Das entsprechende Programm auf Seiten von Windows ist das
+ Kommandozeilenprogramm \prog{nbtstat}.
+
+\end{description}
+
+Auf der Serverseite finden sich noch weitere Komponenten:
+
+\begin{description}
+
+\item[smb.conf:] Die zentrale Konfigurationsdatei von Samba. Ist Samba
+ als fester Systembestandteil installiert, findet sie sich in der
+ Regel unter \datei{/etc/smb.conf}. Ist Samba selbst compiliert,
+ liegt sie h"aufig unter \datei{/usr/local/samba/lib/smb.conf}.
+
+\item[/var/lock/samba:] Samba ben"otigt ein Verzeichnis, in dem es
+ tempor"are Lockdateien und Datenbanken ablegen kann. Wird Samba ohne
+ besondere Optionen selbst compiliert, liegt dies Verzeichnis unter
+ \datei{/usr/local/samba/var}.
+
+\item[/etc/smbpasswd] ist die Pa"swortdatenbank von Samba, sofern mit
+ verschl"usselten Pa"s\-w"ortern gearbeitet wird.
+ \datei{/usr/local/samba/private/} ist das Standardverzeichnis f"ur
+ diese Datei.
+
+\end{description}
+
+\section{NetBIOS-Konfiguration mit Samba}
+
+Als erstes soll eine minimale Konfiguration von Samba erreicht werden,
+mit der jeder Rechner in der Netzwerkumgebung zu sehen ist. Dazu
+sollte die Datei \datei{smb.conf} folgenderma"sen aussehen:
+
+\begin{verbatim}
+[global]
+workgroup = arbeitsgruppe
+interfaces = <IP-Adresse>/<Netzmaske>
+\end{verbatim}
+
+\label{aufbau-smb.conf}
+Der grunds"atzliche Aufbau der \datei{smb.conf} gleicht dem Aufbau der
+.INI-Dateien von Windows 3. Die Datei ist in mehrere Abschnitte
+unterteilt, die jeweils durch einen Abschnittsnamen eingeleitet
+werden. Dieser Abschnittsname selbst wird in eckige Klammern gesetzt.
+Der Inhalt jedes Abschnitts besteht nun aus Parameterzuweisungen. Im
+Beispiel gibt es nur den Abschnitt \param{global}. In diesem werden
+Festlegungen getroffen, die den Server als ganzes betreffen. Wenn
+sp"ater Freigaben erstellt werden, geschieht dies durch Anlegen von
+weiteren Abschnitten.
+
+Mit dem Parameter \param{workgroup =} wird die Arbeitsgruppe
+festgelegt, in der sich der Server befinden soll.
+
+Der Parameter \label{interfaces}\param{interfaces =} ist einer der
+wichtigsten Parameter der Sambakonfiguration. Er ist deshalb so
+wichtig, weil damit das Funktionieren des NetBIOS-Systems innerhalb
+von Samba garantiert wird. Sp"ater wird deutlich werden, da"s gro"se
+Teile der Kommunikation auf Broadcasts basieren. \prog{ifconfig
+ <interface>} unter Unix, oder unter Linux speziell \prog{ifconfig
+ eth0} gibt sowohl die IP-Adresse der Ethernetkarte als auch die dort
+gesetzte Broadcastadresse als Ausgabe. Der Parameter \param{interfaces
+ =} weist Samba an, diese und keine andere Schnittstelle zu nutzen.
+Dar"uberhinaus ist Samba nun in der Lage, die Broadcastadresse, die
+auf dieser Schnittstelle g"ultig ist, zu bestimmen. Theoretisch
+k"onnte man die Broadcastadresse selbst"andig herausfinden, aber es
+gibt keinen portablen Weg, dies "uber Systemgrenzen hinweg zu tun. Das
+sicherste ist, Samba direkt "uber die Broadcastadresse zu informieren.
+
+Mit diesen beiden Einstellungen wird man direkt den Sambarechner in
+der Netzwerkumgebung sehen. Zur Vereinfachung sollten noch zwei
+weitere Parameter gesetzt werden, die sp"ater erkl"art werden. Die
+vollst"andige \datei{smb.conf} sieht also folgenderma"sen
+aus:\footnote{Auf einem der Rechner sollte zus"atzlich \param{os level
+ = 67} und \param{preferred master = yes} im Abschnitt
+ \param{[global]} der /etc/smb.conf gesetzt sein.}
+
+\begin{verbatim}
+[global]
+workgroup = arbeitsgruppe
+interfaces = <IP-Adresse>/<Netzmaske>
+security = share
+encrypt passwords = yes
+\end{verbatim}
+
+Mit dieser Konfiguration kann Samba gestartet werden. Unter SuSE Linux
+geschieht dies mit dem Aufruf:
+
+\begin{verbatim}
+rcsmb start
+\end{verbatim}
+
+Damit Samba beim n"achsten Hochfahren automatisch gestartet wird,
+sollte die Variable \texttt{START\_SMB} in der Datei
+\datei{/etc/rc.config} auf \texttt{yes} gesetzt werden. Es mu"s
+letztlich nur erreicht werden, da"s sowohl der \prog{nmbd} als auch
+der \prog{smbd} mit dem Parameter \texttt{-D} gestartet werden.
+
+Es ist denkbar, den Aufruf beider Programme durch den \prog{inetd}
+durchf"uhren zu lassen. Bei Samba ist dies jedoch nicht sinnvoll.
+Insbesondere der \prog{nmbd} mu"s auf jeden Fall beim Start des
+Systems hochfahren, da dieser im NetBIOS-System Namen f"ur sich
+reservieren mu"s. W"urde er erst bei der ersten Anfrage gestartet,
+h"atten Windowsrechner keine M"oglichkeit, den Sambarechner zu finden.
+Au"serdem wird sich der \prog{nmbd} nicht wieder beenden, sobald er
+einmal gestartet wurde. Der \prog{smbd} k"onnte durch den \prog{inetd}
+gestartet werden. Jedoch ist der Resourcenbedarf nicht so hoch, da"s
+die erh"ohte Startzeit damit gerechtfertigt werden k"onnte.
+
+Nachdem alle Sambaserver gestartet wurden, sollten diese in der
+Netzwerkumgebung der beteiligten Windowsrechner erscheinen.
+
+\section{Namensaufl"osung per Broadcast}
+
+Mit \prog{nmblookup} kann man direkt eine NetBIOS-Namensanfrage
+ausl"osen.
+
+\begin{quote}
+\begin{small}\begin{verbatim}
+vlendec@server:/home/vlendec> nmblookup server
+querying server on 192.168.1.255
+192.168.1.3 server<00>
+vlendec@linux:/home/vlendec>
+\end{verbatim}\end{small}
+\end{quote}
+
+An diesem Beispiel wird deutlich, wie die NetBIOS-Namensaufl"osung
+normalerweise arbeitet. Es wird ein Paket an der Adresse 192.168.1.255
+versendet, die Broadcastadresse im lokalen Subnetz. Um
+NetBIOS-Namensanfragen zu erm"oglichen, mu"s Samba in der Lage sein,
+die Broadcastadresse herauszufinden, an die das Paket geschickt werden
+soll. \prog{nmblookup} entnimmt diese Adresse der Zeile
+\param{interfaces =} der \datei{smb.conf}. F"ur Tests kann man
+\prog{nmblookup} mit dem Parameter -B anweisen, die Anfragen an eine
+andere Broadcastadresse zu versenden.
+
+\begin{quote}
+\begin{small}\begin{verbatim}
+vlendec@server:/home/vlendec> nmblookup -B 192.168.1.31 server
+querying server on 192.168.1.31
+name_query failed to find name server
+vlendec@linux:/home/vlendec>
+\end{verbatim}\end{small}
+\end{quote}
+
+In diesem Beispiel wurde die Broadcastadresse auf 192.168.1.31
+gesetzt. Diese Broadcastadresse gilt in Subnetz 192.168.1.0/27. Jedoch
+f"uhlte sich der \prog{nmbd}, der f"ur diesen Namen verantwortlich
+ist, nicht angesprochen. Folglich hat er nicht auf diese Namensanfrage
+geantwortet.
+
+Unter Windows kann man die Namensanfrage so isoliert nicht ausl"osen,
+man mu"s eine Verbindung aufbauen. Windows unterh"alt einen Cache, in
+dem erfolgreiche Anfragen zwischengespeichert werden. Diesen kann man
+sich mit \prog{nbtstat -c} anzeigen und mit \prog{nbtstat -R} l"oschen.
+Man kann eine Anfrage erzwingen, indem man mit leerem Namenscache eine
+Verbindung aufbaut, beispielsweise durch ein \prog{net view
+ \symbol{'134}\symbol{'134}samba}.
+
+Die Fehlermeldung, wenn eine NetBIOS-Namensanfrage fehlschl"agt,
+lautet im GUI: "`Der Netzwerkpfad wurde nicht gefunden"'. Auf der
+Kommandozeile kommt noch die Fehlermeldung 53 dazu.
+
+Mit \prog{nmblookup} kann man sich zus"atzlich die von einem Rechner
+reservierten Namen ausgeben lassen. Die entsprechende Operation nennt
+sich \defin{Node Status Request} und wird durch den Parameter \prog{-A
+ <IP-Adresse>} ausgel"ost. Die Ausgabe eines solchen Node Status
+Request zeigt, da"s ein Rechner f"ur sich nicht nur einen einzigen
+Namen reserviert, sondern gleich mehrere.
+
+Zun"achst gibt es die Einzelnamen, zum Beispiel den Computernamen
+selbst. F"ur diese gilt die Regel, da"s sie nur ein einziges Mal im
+gesamten Netz auftauchen d"urfen. Sie werden reserviert und stehen dem
+entsprechenden Rechner dann exklusiv zur Verf"ugung. Daneben gibt es
+die Gruppennamen, die im Node Status Request durch \texttt{<GROUP>}
+markiert sind. Diese kann es mehrfach im Netz geben. Die Gruppennamen
+sind insbesondere als Ziele f"ur NetBIOS-Datagramme interessant.
+Beispielsweise reserviert jeder Teilnehmer an einer Arbeitsgruppe den
+NetBIOS-Gruppennamen \nbname{arbeitsgruppe<00>}. Damit kann ein
+Rechner mit einem einzigen verschickten Datagramm an diesen Namen
+s"amtliche Rechner in dieser Arbeitsgruppe erreichen.
+
+Zus"atzlich f"allt auf, da"s beispielsweise der Computername selbst
+als Einzelnamen mehrfach reserviert ist. Hier kommen die
+unterschiedlichen Namenstypen ins Spiel. Das 16. Byte eines
+NetBIOS-Namens ist f"ur ein Typfeld reserviert. So sind
+unterschiedliche Anwendungen auf einem Rechner in der Lage, sich Namen
+zu reservieren, ohne sich gegenseitig zu st"oren.
+
+Zun"achst die Einzelnamen, die h"aufig auftauchen:
+
+\begin{description}
+
+\item[computername$<$00$>$] Hiermit tut der Rechner einfach seine
+Existenz kund. Wenn ein Rechner auf Resourcen anderer Rechner zugreift,
+wird als Clientname dieser Name benutzt.
+
+\item[computername$<$20$>$] Dieser Name wird f"ur den Serverdienst
+reserviert. Wenn ein Rechner als Datei- oder Druckserver angesprochen
+werden soll, dann wird eine Verbindung zu diesem NetBIOS-Namen aufgebaut.
+
+\item[computername$<$03$>$] Unter diesem Namen meldet sich der
+Nachrichtendienst des Rechners an. Kurze Meldungen, die unter Windows
+NT mit dem Kommando \prog{net send} abgesetzt werden, und unter
+Windows 95 mit dem Programm Winpopup verschickt werden, kann der
+Rechner damit empfangen und am Bildschirm anzeigen.
+
+\item[arbeitsgruppe$<$1d$>$] Dieser Rechner ist der sogenannte
+ \defin{Lokale Master Browser}, der die Liste s"amtlicher Rechner in
+ der Netzwerkumgebung pflegt.
+
+\item[arbeitsgruppe$<$1b$>$] Dieser Rechner ist der \defin{Domain
+ Master Browser}, der "uber Subnetzgrenzen hinweg f"ur die
+ Netzwerkumgebung zust"andig ist.
+
+\end{description}
+
+Einige Gruppennamen werden ebenfalls reserviert:
+
+\begin{description}
+
+\item[arbeitsgruppe$<$00$>$] Ein Rechner verk"undet hiermit seine
+ Zugeh"origkeit zu einer Arbeitsgruppe. Beispielsweise k"onnen
+ Winpopup-Meldungen an eine ganze Arbeitsgruppe versendet werden.
+ Dies geschieht per Datagramm an diesen Namen.
+
+\item[arbeitsgruppe$<$1e$>$] Wahlen zum Lokalen Master Browser werden
+ "uber diesen Namen abgewickelt. Siehe hierzu Kapitel \ref{netzwerkumgebung}.
+
+\end{description}
+
+\section{Netzwerkumgebung}
+\label{netzwerkumgebung}
+
+Die \defin{Netzwerkumgebung} ist einer der instabileren Aspekte von
+Windows. Hiermit kann man sich, sofern alles funktioniert, alle
+Rechner in einer Arbeitsgruppe anzeigen lassen. Dabei dauert es
+mitunter geraume Zeit, bis ein Rechner in einer Anzeige erscheint, und
+es dauert unter Umst"anden noch l"anger, bis er wieder verschwindet.
+
+Eine naive Implementation k"onnte funktionieren, indem jeder Rechner,
+der Serverdienste anbietet, dieses regelm"a"sig per Broadcast im Netz
+mitteilt. Ein solches Vorgehen hat jedoch mehrere Nachteile. Erstens
+w"urde die Last im Netz mit jedem zus"atzlichen Rechner stark
+ansteigen. Zweitens mu"s jeder Rechner, der die Netzwerkumgebung anzeigen
+will, relativ komplexe Software laufen lassen. Und drittens scheitert dieses
+Schema auf jeden Fall an Subnetzgrenzen, die f"ur Broadcasts eine
+Grenze darstellen. Aus diesen Gr"unden ist man einen anderen Weg
+gegangen.
+
+Der \defin{Lokale Master Browser} (im folgenden auch LMB genannt) ist
+ein Rechner, der im Netz die Netzwerkumgebung pflegt. Dieser Rechner
+wird nirgendwo zentral bestimmt, sondern er wird gew"ahlt. Diese Wahl
+findet immer dann statt, wenn einer der beteiligten Rechner
+feststellt, da"s es im Moment keinen solchen Lokalen Master Browser
+gibt. Beispielsweise kann der Explorer von Windows eine solche Wahl
+ansto"sen. Wenn Windows 95 die geschwenkte Taschenlampe anzeigt, wird
+der LMB gesucht. Ist keiner vorhanden, wird eine Wahl angesto"sen.
+
+Die Wahl erfolgt mit Datagrammen an den Gruppennamen
+\nbname{arbeitsgruppe<1e>}. Ein Rechner verschickt ein Datagramm an
+diesen Namen. Jeder Rechner, der diesen Namen reserviert hat, h"ort
+dieses Datagramm und entscheidet, wie er selbst vorgehen soll. In dem
+Datagramm sind verschiedene Kriterien zur Wahl enthalten,
+beispielsweise das Betriebssystem des versendenden Rechners.
+
+Empf"angt beispielsweise eine Windows NT Workstation ein Paket von
+einem Windows NT Server, so entscheidet sie, da"s sie die Wahl
+verloren hat. Damit wird sie selbst nicht mehr aktiv. Kommt dieses
+Paket jedoch von einem Windows 95 Rechner, so h"alt sie sich selbst
+f"ur geeigneter, den Lokalen Master Browser zu "ubernehmen. Dann wird
+sie selbst ein solches Wahlpaket mit ihren Parametern versenden. Der
+Windows 95 Rechner empf"angt dies, und sieht, da"s er verloren hat.
+Auf diese Weise schaukelt sich die Wahl hoch, bis der "`beste"'
+Rechner die Wahl gewinnt.
+
+Wenn es nun mehrere Windows NT Workstations im Netz g"abe, dann
+w"are die Wahl unentschieden. An dieser Stelle kommt die \emph{Uptime}
+der Rechner ins Spiel. Der Rechner, der am l"angsten l"auft, gewinnt
+die Wahl. Nun kann es sein, da"s nach einem Stromausfall zwei Rechner
+genau die gleiche Uptime haben. Dann kommt als letztes und eindeutiges
+Entscheidungskriterium der NetBIOS-Name des Rechners zum Zug. Der
+alphabetisch vorne stehende Rechner gewinnt. Mit diesen drei Kriterien
+ist eine eindeutige Wahl gesichert.
+
+Samba ordnet sich in der Standardeinstellung zwischen Windows 95 und
+Windows NT ein, das hei"st, gegen Windows 95 gewinnt Samba die Wahl,
+"uberl"a"st jedoch Windows NT Rechnern den Lokalen Master Browser.
+
+Drei Parameter in der \datei{smb.conf} bestimmen das Verhalten von
+Samba in der Wahl zum Lokalen Master Browser:
+
+\begin{description}
+
+\item[\param{os level}] Damit wird die Einordnung von Samba in die
+ unterschiedlichen Betriebssysteme geregelt. Diese haben f"ur die
+ Betriebssystemstufe folgende Werte:
+
+\[\begin{tabular}{|l|r|}
+\hline
+Windows for Workgroups & 0 \\
+\hline
+Windows 95/98 & 1 \\
+\hline
+Windows NT Workstation & 16 \\
+\hline
+Windows NT Server & 32 \\
+\hline
+\end{tabular}\]
+
+Diese Werte sind nicht als fest anzusehen. Wenn ein neues Service Pack
+f"ur ein Betriebssystem herausgegeben wird, ist es m"oglich, da"s in
+der Software f"ur den Lokalen Master Browser Fehler bereinigt wurden.
+Dann ist es sinnvoll, da"s diese neue Software die Rolle des LMB
+"ubernimmt. Der einfachste Weg ist, den \param{os level} einfach
+hochzusetzen. Samba hat hier einen Vorgabewert von 20.
+
+Der Parameter \param{os level} kann Werte von 0 bis 255 annehmen.
+Setzt man ihn auf 255, wird nach einer erfolgreichen Wahl niemand mehr
+Local Master Browser werden k"onnen.
+
+\item[\param{local master}] M"ochte man auf keinen Fall den LMB auf
+ einem Sambarechner haben, so setzt man den Parameter \param{local
+ master = no}. Dann nimmt Samba an keiner Wahl teil.
+
+\item[\param{preferred master}] Mit der Standardeinstellung
+ \param{preferred master = no} sucht Samba beim Start nach
+ einem LMB. Findet er einen, meldet er sich dort. Findet er keinen
+ LMB, bleibt Samba passiv. Jemand anders mu"s eine Wahl ansto"sen.
+ Wenn dann eine Wahl stattfindet, nimmt Samba teil und ordnet sich
+ anhand seines \param{os level} ein. Wenn man sichergehen m"ochte,
+ da"s Samba auf jeden Fall nach dem Start den LMB "ubernimmt, dann
+ mu"s man den \param{os level} hoch genug setzen, und den Parameter
+ \param{preferred master = yes} setzen. Damit wird Samba beim Start
+ des \prog{nmbd} auf jeden Fall eine Wahl ansto"sen und sie dann
+ unter Umst"anden gewinnen.
+
+\end{description}
+
+Mit den Einstellungen
+
+\begin{verbatim}
+[global]
+os level = 66
+preferred master = yes
+\end{verbatim}
+
+\noindent
+kann man sicher sein, da"s der Sambarechner immer den LMB innehat. Es
+sei denn, ein anderer Administrator von Samba kommt auf die Idee,
+einen noch h"oheren Wert f"ur den \param{os level} zu benutzen.
+
+Ein Primary Domain Controller kann unter Umst"anden erheblich gest"ort
+werden, wenn er in seinem Subnetz nicht der LMB ist.
+
+\section{NetBIOS "uber Subnetzgrenzen}
+
+\newcommand{\computer}[2]{%
+ \rput[t](0,0){%
+ \begin{pspicture}(2,2)
+ \psframe(0,0.5)(2,1.5)
+ \psline(1,1.5)(1,2)
+ \rput(1,1){\texttt{#1}}
+ \rput[b](1,0.2){{\footnotesize IP: #2}}
+ \end{pspicture}}}
+\newcommand{\network}[1]{%
+ \rput[l](0,0){%
+ \begin{pspicture}(#1,0.6)
+ \psline(0,0)(0,0.6)
+ \psline(0,0.3)(#1,0.3)
+ \psline(#1,0)(#1,0.6)
+ \end{pspicture}}}
+\newcommand{\routednet}{%
+\rput[lb](0,0){%
+\begin{pspicture}(10,5.5)
+\rput(0,5){\network{7}}
+\rput(2,5){\computer{WKS}{192.168.1.5}}
+\rput(3,2){\network{7}}
+\rput(8,2){\computer{SERVER}{192.168.2.8}}
+\rput(5.5,3.75){\psframe(-1,-0.25)(1,0.25)}
+\rput(5.5,3.75){{\footnotesize 192.168.1.1}}
+\rput(5.5,3.25){\psframe(-1,-0.25)(1,0.25)}
+\rput(5.5,3.25){{\footnotesize 192.168.2.1}}
+\psline(5.5,4)(5.5,5)
+\psline(5.5,2)(5.5,3)
+\end{pspicture}}}
+
+Wird die Namensreservierung und -aufl"osung ausschlie"slich per
+Broadcast durchgef"uhrt, kann man Rechner, die hinter Routern liegen,
+nicht erreichen. Broadcasts verbleiben in den Subnetzen, in denen sie
+ausgesendet wurden.
+
+\begin{figure}[ht]\[
+\begin{pspicture}(10,6)
+\rput(0,0){\routednet}
+\psline{<-}(0,5.5)(2.7,5.5)
+\psline{->}(4.3,5.5)(7,5.5)
+\rput(3.5,5.5){\texttt{SERVER?}}
+\end{pspicture}\]
+\caption{Namensanfrage per Broadcast}
+\label{broadcastanfrage}
+\end{figure}
+
+In der dargestellten Situation sind zwei Netze "uber einen Router
+verbunden. Jeder der beiden Rechner reserviert seinen Namen in dem ihm
+zugeordneten Subnetz. Die Workstation \nbname{WKS} schickt ihre
+Reservierungen per Broadcast an 192.168.1.255, und der Server
+\nbname{SERVER} wird seinen Namen auf 192.168.2.255 reservieren. Der
+Router zwischen beiden bekommt diese Reservierungen zwar mit, wird sie
+aber nicht in das jeweils andere Subnetz weiterleiten. Wenn nun
+\nbname{WKS} ihren Server \nbname{SERVER} sucht, geschieht dies
+ebenfalls per Broadcast an 192.168.1.255. Diese Anfrage bleibt wie
+dargestellt im oberen Subnetz und erreicht \nbname{SERVER} gar nicht,
+so da"s dieser auch nicht antworten kann.
+
+Der einfachste Weg, die Namensaufl"osung "uber Subnetzgrenzen hinweg
+zu realisieren, geht "uber eine statische Tabelle. Unter Windows
+liegt diese in der Datei \datei{LMHOSTS}. Sie liegt abh"angig von der
+Windowsversion in unterschiedlichen Verzeichnissen und l"a"st sich am
+einfachsten mit der Suchfunktion des Desktops finden. Diese Datei ist
+"ahnlich aufgebaut wie die Datei \datei{/etc/hosts} unter Unix. Ein
+Beispieleintrag ist der folgende:
+
+\verb|192.168.1.5 samba|
+
+Die Eintr"age in der \datei{LMHOSTS} k"onnen durch den Zusatz
+\texttt{\#PRE} erg"anzt werden. Dieser Zusatz legt fest, in welcher
+Reihenfolge die Namensaufl"osung vorgenommen wird. Ist kein
+\texttt{\#PRE} vorhanden, so wird zun"achst eine konventionelle
+Namensaufl"osung per Broadcast versucht. Erst, wenn diese
+fehlschl"agt, wird in der \datei{LMHOSTS} nachgeschaut. Ist der Zusatz
+vorhanden, so wird ohne Namensaufl"osung direkt der Wert in der
+\datei{LMHOSTS} verwendet.
+
+Die zweite M"oglichkeit, das Problem zu l"osen, ist eine zentrale
+Datei \datei{LMHOSTS}. Dazu gibt es den WINS-Server. Ein solcher Server
+ist ein Rechner, bei dem sich jede Applikation im Netz mit ihren Namen
+anmeldet. Die IP-Adresse dieses Servers mu"s jedem Rechner mitgeteilt
+werden. Bei Windows geschieht dies in den Eigenschaften des TCP/IP
+Protokolls im Reiter WINS-Adresse. Setzt man DHCP-Server ein, kann man
+ebenfalls den WINS-Server festlegen. Samba bekommt die Adresse mit dem
+Parameter \param{wins server = <ip-adresse>} im Abschnitt
+\param{[global]} der \datei{smb.conf} mitgeteilt. Sobald ein Client
+die IP-Adresse des WINS Servers kennt, ist es v"ollig gleichg"ultig,
+ob sich dieser im gleichen Subnetz befindet oder nicht.
+
+Die Namensreservierung erfolgt nicht mehr per Broadcast, sondern mit
+einem gerichteten UDP-Paket an den WINS-Server. Gerichtete Pakete
+leitet der Router wie jedes andere Paket an den WINS-Server weiter.
+Dieser sieht in seiner Tabelle nach, ob der Name bereits reserviert
+ist. Ist das nicht der Fall, so wird er spontan eine Best"atigung der
+Reservierung zur"uckschicken. Diese Reservierung gilt nun f"ur eine
+bestimmte Zeit und mu"s rechtzeitig erneuert werden.
+
+Ist der Name bereits reserviert, wird der WINS-Server den bisherigen
+Besitzer befragen, ob er den Namen noch ben"otigt. Bekommt er keine
+Antwort, wird er dem neuen Besitzer ebenfalls eine Best"atigung
+schicken. M"ochte der alte Besitzer den Namen noch verwenden, so wird
+der Anfragende eine Ablehnung der Reservierung erhalten. Diese
+Nachfrage ist notwendig, um einem abgest"urzten Rechner das spontane
+Booten zu erm"oglichen, da bei einem Absturz keine Freigabe der
+Namensreservierung erfolgen kann.
+
+Die Namensanfrage, die in Abbildung \ref{broadcastanfrage} den Server
+nicht erreichte, weil der Router keine Broadcasts weitergibt, wird nun
+direkt an den WINS-Server gerichtet, der in seiner Tabelle nachsehen
+kann.
+
+\begin{figure}[ht]\[
+\begin{pspicture}(10,6)
+\rput(0,0){\routednet}
+\rput(4,2){\computer{WINS}{192.168.2.5}}
+\psline[linestyle=dashed,linearc=0.25]
+ {->}(2.5,4.5)(3.2,4.9)(5.3,4.9)(5.3,2)(4.5,1.5)
+\rput(3.5,5.8){\texttt{SERVER?}}
+\end{pspicture}\]
+\caption{WINS-Anfrage}
+\end{figure}
+
+Samba kann ganz normal als WINS-Server konfiguriert werden, indem der
+Parameter \param{wins support = yes} gesetzt wird. Ist diese Parameter
+gesetzt, kann Samba nach einem Neustart bei allen Clients und allen
+sonstigen Servern als WINS-Server eingetragen werden. Werden diese
+dann neu gestartet, melden sie sich beim WINS Server an.
+
+Wenn nun ein Rechner mit Samba als WINS Server konfiguriert ist, und
+sich die anderen Rechner dort anmelden, werden diese in der Datei
+\datei{/var/lock/samba/wins.dat} abgelegt. Der \prog{nmbd} pflegt
+diese Datei dynamisch, je nach Reservierungen und Abmeldungen. Die
+Datei \datei{wins.dat} wird in regelm"a"sigen Abst"anden geschrieben.
+Wenn es notwendig sein sollte, den wirklich aktuellen Stand
+unabh"angig von diesem Zeitintervall zu erhalten, so kann man dem
+\prog{nmbd} das \prog{HANGUP}-Signal durch den Befehl \prog{killall
+-HUP nmbd} senden. Au"serdem wird die \datei{wins.dat} beim Beenden
+des \prog{nmbd} geschrieben.
+
+Diese Datenbank wird auf Festplatte gehalten, damit die Daten einen
+Neustart von Samba "uberleben. Jeder Rechner, der einen Namen f"ur
+sich reserviert hat, hat diese Reservierung f"ur einen bestimmten
+Zeitraum ausgesprochen. Wenn Samba jetzt neu gestartet werden sollte,
+und dadurch die Datenbank verloren ginge, w"are der gesamte
+NetBIOS-Namensraum nicht mehr verf"ugbar. Au"serdem kann ein WINS
+Server die angeschlossenen Clients weder von sich aus finden, noch sie
+darum bitten, sich erneut zu registrieren. Daher ist die WINS
+Datenbank "uber Neustarts von Samba hinaus zu erhalten.
+
+Die Anfrage, die die Workstation \nbname{WKS} absetzt, wird nun nicht
+mehr per Broadcast gestellt, sondern mit einem gerichteten Paket an
+den WINS-Server, bei dem sich alle Rechner angemeldet haben.
+
+%\[\setlength{\unitlength}{1mm}
+%\begin{picture}(100,60)(0,20)
+%\put(0,0){\routednet}
+%\put(30,75){\makebox(0,0)[l]{{\ttfamily\bfseries SERVER?}}}
+%\curve(17,65, 20,72, 29,75)
+%\tagcurve(40,75, 50,75, 57,65, 57,45, 45,38, 40,30, 30,20)
+%\put(50,45){\circle*{1}}
+%\put(40,40){\computer{WINS}{192.168.2.5}}
+%\end{picture}\]
+
+WINS hat gegen"uber der broadcastbasierten Namensreservierung einige
+Vorteile. Namensreservierung per Broadcast erfolgt durch Wartezeiten.
+Es wird die Reservierung angek"undigt, es wird gewartet, die
+Reservierung wird erneut angek"undigt, und es wird wieder gewartet.
+Dieses Spiel wiederholt sich mehrfach, bis der Rechner sicher sein
+kann, da"s ein eventueller Vorbesitzer des Namens genug Zeit hatte,
+sich zu beklagen. Beim Einsatz von WINS entfallen diese Wartezeiten,
+da hier ein einziger Rechner s"amtliche reservierte Namen registriert
+und in seiner Tabelle nachschauen kann. Daher ist die Reservierung per
+NetBIOS deutlich schneller, und auch weniger netzbelastend. Selbst
+wenn man also nur ein einziges Subnetz hat, sollte man zur Reduzierung
+der Netzlast den Einsatz eines WINS-Servers in Erw"agung ziehen.
+
+Zus"atzlich sei hier angemerkt, da"s es netzwerkweit nur einen
+einzigen WINS-Server geben darf. Selbst wenn es unterschiedliche
+Arbeitsgruppen oder Dom"anen gibt, darf es nicht mehr als einen
+WINS-Server geben. Setzt man mehrere WINS-Server ein, hat man getrennte
+Namensr"aume. Rechner im einen Namensraum k"onnen mit Rechnern, die
+an einem anderen WINS-Server angeschlossen sind, nicht kommunizieren.
+Es kann trotzdem zu Kollisionen kommen, da Windowsrechner bestimmte
+Namen unabh"angig von WINS-Einstellungen ausschlie"slich per Broadcast
+reservieren. Unter Windows NT kann man mehrere WINS-Server einsetzen,
+die sich gegenseitig abstimmen. Diese WINS-Server treten gegen"uber
+den Clients als ein einziger Server auf, unabh"angig von ihrer Anzahl.
+
+Die Abfrage eines WINS Servers durch \prog{nmblookup} erfolgt
+beispielhaft folgenderma"sen:
+
+\begin{verbatim}
+nmblookup -R -U 192.168.1.5 samba
+\end{verbatim}
+
+Hiermit wird der WINS Server, der auf dem Rechner 192.168.1.5 liegt,
+nach dem Namen \nbname{samba} befragt.
+
+Samba kennt zwei zus"atzliche Funktionen, die es im Zusammenhang mit
+WINS interessant machen. Einerseits kann Samba als WINS Proxy
+eingerichtet werden, indem \param{wins proxy = yes} gesetzt wird. Ist
+diese Einstellung aktiv, dann wird Samba s"amtliche Reservierungen und
+Anfragen, die es aus dem lokalen Netz per Broadcast erh"alt, an den
+mit \prog{wins server =} konfigurierten WINS Server weiterleiten.
+Damit kann man einen Samba-Server in ein Subnetz stellen. S"amtliche
+Rechner in diesem Netz werden nun beim WINS angemeldet, und nutzen
+diesen auch. Dies ist auch dann der Fall, wenn sie entweder selbst
+keinen WINS Server ansprechen k"onnen oder nicht daf"ur konfiguriert
+sind. Man sollte jedoch in jedem Fall eine echte Konfiguration des
+WINS Servers auf dem Client vorziehen. Ein WINS Proxy kann nur eine
+Behelfsl"osung sein, da man sich damit auf einen weiteren
+Rechner verl"a"st.
+
+Unter Windows kann man statische Eintr"age im WINS vornehmen. Dies
+geht so direkt unter Samba nicht. Man mu"s hierzu den Parameter
+\param{dns proxy = yes} auf dem WINS Server setzen. Empf"angt der WINS
+Server nun eine Anfrage, die er nicht aus seiner Datenbank beantworten
+kann, wird er eine ganz normale Unix-Hostnamenanfrage machen.
+Typischerweise wird er in der \datei{/etc/hosts} nachschauen und
+danach dann das DNS anhand der Konfiguration in der Datei
+\datei{/etc/resolv.conf} befragen. Damit ist es durch einen Eintrag
+auf dem WINS Server m"oglich, den gesamten DNS-Namensraum auch in der
+NetBIOS-Namenswelt zur Verf"ugung zu stellen.
+
+\section{Netzwerkumgebung "uber Subnetzgrenzen}
+
+So, wie die Netzwerkumgebung in Abschnitt \ref{netzwerkumgebung}
+betrachtet wurde, funktioniert sie nur in einem einzigen lokalen
+Netz. Die Wahl zum lokalen Master Browser funktioniert per Datagramm,
+das an den Namen \nbname{arbeitsgruppe<1e>} gesendet
+wird. \nbname{arbeitsgruppe<1e>} ist ein Gruppenname, der von mehreren
+Rechnern reserviert sein kann. Das hei"st, da"s ein Datagramm an
+diesen Namen mehrere Rechner erreichen mu"s. Dies geschieht bei
+NetBIOS "uber TCP/IP mit einem UDP-Paket an die Broadcastadresse im
+lokalen Netz. Allein hieraus ergibt sich, da"s es pro Arbeitsgruppe in
+jedem Subnetz einen eigenen LMB geben mu"s. Jeder LMB bekommt aus
+seinem Subnetz die Informationen "uber vorhandene Server.
+
+Um diese Einschr"ankung zu umgehen, gibt es den Domain Master Browser
+(DMB). Der DMB ist ein Rechner, der die Serverlisten von allen LMBs
+einsammelt und auf Anforderung wieder herausgibt. Dabei sitzt der DMB
+nur passiv da und wartet darauf, da"s sich ein LMB mit ihm
+synchronisieren will. Es ist Aufgabe der LMBs, sich regelm"a"sig
+danach zu erkundigen, wo der DMB sitzt, und mit diesem dann die
+Serverlisten abzugleichen.
+
+Die Vorg"ange werden am deutlichsten, wenn man ein Beispiel
+betrachtet. Dieses Beispiel ist im wesentlichen der
+Originaldokumentation von Samba aus der Datei \datei{BROWSING.txt}
+entnommen.
+
+\newcommand{\minicomputer}[1]{%
+\begin{picture}(10,9)(5,9)
+\put(0,0){\framebox(10,5){{\ttfamily #1}}}
+\put(5,5){\line(0,1){4}}
+\end{picture}}
+\newcommand{\mininetz}[1]{%
+\begin{picture}(62,12)
+\put(10,10){\minicomputer{N#1A}}
+\put(25,10){\minicomputer{N#1B}}
+\put(40,10){\minicomputer{N#1C}}
+\put(55,10){\minicomputer{N#1D}}
+\put(3,10){\line(1,0){59}}
+\put(3,8){\line(0,1){4}}
+\put(62,8){\line(0,1){4}}
+\end{picture}}
+
+\begin{figure}[ht]
+\[\setlength{\unitlength}{1.1mm}
+\begin{picture}(120,60)(0,5)
+\put(0,20){\mininetz{1}}
+\put(25,19){\makebox(0,0){\textit{{\small DMB,LMB}}}}
+\put(30,50){\mininetz{2}}
+\put(85,49){\makebox(0,0){\textit{{\small WINS}}}}
+\put(55,49){\makebox(0,0){\textit{{\small LMB}}}}
+\put(50,5){\mininetz{3}}
+\put(105,4){\makebox(0,0){\textit{{\small LMB}}}}
+\put(48,48){\minicomputer{R1}}
+\put(48,48){\line(0,1){12}}
+\put(48,39){\line(0,-1){9}}
+\put(77,48){\minicomputer{R2}}
+\put(77,48){\line(0,1){12}}
+\put(77,39){\line(0,-1){24}}
+\end{picture}\]
+\caption{Domain Master Browser}
+\end{figure}
+
+Dieses Netz besteht aus 3 Subnetzen (1,2,3), die durch 2 Router (R1
+und R2) verbunden sind. Die Router lassen keine Broadcasts durch. Alle
+Subnetze bestehen aus jeweils 4 Maschinen. Nehmen wir der Einfachheit
+halber an, da"s alle Maschinen in der gleichen Arbeitsgruppe
+konfiguriert sind. Rechner \nbname{N1B} im Subnetz 1 ist als Domain
+Master Browser konfiguriert. Das hei"st, da"s er die Browseliste f"ur
+die ganze Arbeitsgruppe aufsammelt. Rechner \nbname{N2D} ist als WINS
+Server konfiguriert und alle anderen Maschinen registrieren ihre
+NetBIOS Namen dort.
+
+Wenn alle diese Maschinen gebootet werden, werden in jedem der drei
+Subnetze Wahlen um einen Local Master Browser abgehalten. Nehmen wir
+an, im Subnetz 1 gewinnt \nbname{N1C}, im Subnetz 2 gewinnt
+\nbname{N2B} und im Subnetz 3 gewinnt \nbname{N3D}. Diese Maschinen
+sind als Local Master Browser in ihrem Subnetz bekannt. Im Subnetz 1
+liegen der LMB und der DMB auf der gleichen Maschine, was nicht der
+Fall sein mu"s. Diese beiden Rollen sind vollst"andig unabh"angig
+voneinander.
+
+Alle Maschinen, die Serverdienste anzubieten haben, k"undigen dies per
+Broadcast auf ihrem Subnetz an. Der Local Master Browser in jedem
+Subnetz empf"angt diese Broadcasts und tr"agt alle Server in einer
+Liste ein. Diese Liste von Eintr"agen ist die Basis f"ur die
+Browseliste. In unserem Fall nehmen wir an, da"s alle Maschinen
+Serverdienste anbieten, das hei"st, da"s alle Maschinen in der Liste
+erscheinen.
+
+F"ur jedes Subnetz wird der Local Master Browser als
+\emph{ma"sgeblich} angesehen, und zwar f"ur alle Namen, die er per
+lokalem Broadcast empf"angt. Broadcasts verlassen das Subnetz nicht,
+und die Broadcasts im lokalen Subnetz werden als ma"sgeblich
+angesehen. Daher wird dem Local Master Browser bei diesen Servern
+geglaubt. Rechner, die sich in anderen Subnetzen befinden, und "uber
+die der Local Master Browser von anderen Local Master Browsern
+informiert wurde, werden als nicht ma"sgeblich angesehen.
+
+An diesem Punkt sieht die Browse Liste folgenderma"sen aus: (dies sind
+die Maschinen, die Sie in Ihrer Netzwerkumgebung sehen w"urden, wenn
+Sie sie in einem bestimmten Subnetz ansehen)
+
+\vspace{\baselineskip}
+\[\begin{tabular}{|c|c|l|}
+\hline
+Netz & LMB & Liste \\ \hline \hline
+1 & \nbname{N1C} & \nbname{N1A}, \nbname{N1B}, \nbname{N1C}, \nbname{N1D}\\
+\hline
+2 & \nbname{N2B} & \nbname{N2A}, \nbname{N2B}, \nbname{N2C}, \nbname{N2D}\\
+\hline
+3 & \nbname{N3D} & \nbname{N3A}, \nbname{N3B}, \nbname{N3C}, \nbname{N3D}\\
+\hline
+\end{tabular}\]
+\vspace{\baselineskip}
+
+An diesem Punkt sind alle Subnetze vollst"andig separat, keine
+Maschine wird in anderen Subnetzen gesehen. Die
+Microsoft-Dokumentation spricht davon, da"s die Arbeitsgruppen in den
+Subnetzen getrennt sind.
+
+Sehen wir uns nun Subnetz 2 an. Sobald \nbname{N2B} der Local Master
+Browser geworden ist, sucht er den Domain Master Browser, um mit ihm
+die Browse Listen zu synchronisieren. Dies tut er, indem er den WINS
+Server (\nbname{N2D}) nach der IP-Adresse fragt, die zum NetBIOS-Namen
+\nbname{arbeitsgruppe<1B>} geh"ort. Diesen Namen hat der Domain Master
+Browser (\nbname{N1C}) beim WINS Server f"ur sich beim booten
+registriert.
+
+\nbname{N2B} kennt nun den Domain Master Browser. Er k"undigt sich als
+Local Master Browser f"ur Subnetz 2 bei ihm an. Dann synchronisiert
+\nbname{N2B} sich mit \nbname{N2D}, indem er einen
+NetServerEnum2-Aufruf abschickt. Der Domain Master Browser schickt
+alle Server, die er kennt, zur"uck. Sobald der Domain Master Browser
+die Ank"undigung von \nbname{N2B} als Lokaler Master Browser erhalten
+hat, wird auch er sich mit dem Local Master Browser
+synchronisieren. Nachdem beide Synchronisationen stattgefunden haben,
+sehen die Browse Listen so aus:
+
+\vspace{\baselineskip}
+\[\begin{tabular}{|c|c|l|}
+\hline
+Netz & LMB & Liste \\ \hline \hline
+1 & \nbname{N1C} & \nbname{N1A}, \nbname{N1B}, \nbname{N1C}, \nbname{N1D}\\
+ & & \nbname{N2A*}, \nbname{N2B*}, \nbname{N2C*}, \nbname{N2D*}\\
+\hline
+2 & \nbname{N2B} & \nbname{N2A}, \nbname{N2B}, \nbname{N2C}, \nbname{N2D}\\
+& & \nbname{N1A*}, \nbname{N1B*}, \nbname{N1C*}, \nbname{N1D*}\\
+\hline
+3 & \nbname{N3D} & \nbname{N3A}, \nbname{N3B}, \nbname{N3C}, \nbname{N3D}\\
+\hline
+\end{tabular}\]
+\vspace{\baselineskip}
+
+Die mit * bezeichneten Eintr"age werden als nicht ma"sgeblich
+angesehen, da sie von anderen Master Browsern erhalten wurden. F"ur
+den Client macht dies jedoch keinen Unterschied. Nur der LMB darf
+diese Eintr"age selbstverst"andlich beim n"achsten Abgleich nicht an
+den DMB als seine eigenen zur"uckmelden.
+
+Zu diesem Zeitpunkt werden Benutzer in den Subnetzen 1 und 2, die die
+Netzwerkumgebung ansehen, die Server in beiden Subnetzen sehen,
+Benutzer im Subnetz 3 sehen immer noch nur die Server in ihrem eigenen
+Subnetz.
+
+Der lokale Master Browser im Subnetz 3 (\nbname{N3D}) macht nun exakt
+das gleiche wie \nbname{N2B}. Wenn er die Browse Listen mit dem Domain
+Master Browser (\nbname{N1B}) abgeglichen hat, bekommt er sowohl die
+Server in Subnetz 1, als auch die im Subnetz 2. Nachdem sich
+\nbname{N3D} mit \nbname{N1C} synchronisiert hat und umgekehrt, sehen
+die Browse Listen folgenderma"sen aus:
+
+\vspace{\baselineskip}
+\[\begin{tabular}{|c|c|l|}
+\hline
+Netz & LMB & Liste \\ \hline \hline
+1 & \nbname{N1C} & \nbname{N1A}, \nbname{N1B}, \nbname{N1C}, \nbname{N1D}\\
+ & & \nbname{N2A*}, \nbname{N2B*}, \nbname{N2C*}, \nbname{N2D*}\\
+ & & \nbname{N3A*}, \nbname{N3B*}, \nbname{N3C*}, \nbname{N3D*}\\
+\hline
+2 & \nbname{N2B} & \nbname{N2A}, \nbname{N2B}, \nbname{N2C}, \nbname{N2D}\\
+ & & \nbname{N1A*}, \nbname{N1B*}, \nbname{N1C*}, \nbname{N1D*}\\
+\hline
+3 & \nbname{N3D} & \nbname{N3A}, \nbname{N3B}, \nbname{N3C}, \nbname{N3D}\\
+ & & \nbname{N1A*}, \nbname{N1B*}, \nbname{N1C*}, \nbname{N1D*}\\
+ & & \nbname{N2A*}, \nbname{N2B*}, \nbname{N2C*}, \nbname{N2D*}\\
+\hline
+\end{tabular}\]
+\vspace{\baselineskip}
+
+Jetzt sehen Benutzer in den Subnetzen 1 und 3 alle Server in allen
+Subnetzen, Benutzer im Subnetz 2 sehen jedoch immer noch nur die
+Server von Subnetz 1 und 2, nicht jedoch die im Subnetz 3.
+
+Zum guten Schlu"s wird sich der lokale Master Browser im Subnetz 2
+(\nbname{N2B}) erneut mit dem Domain Master Browser abstimmen, und die
+fehlenden Servereintr"age bekommen. Endlich sehen die Browse Listen
+als stabiler Zustand so aus:
+
+\vspace{\baselineskip}
+\[\begin{tabular}{|c|c|l|}
+\hline
+Netz & LMB & Liste \\ \hline \hline
+1 & \nbname{N1C} & \nbname{N1A}, \nbname{N1B}, \nbname{N1C}, \nbname{N1D}\\
+ & & \nbname{N2A*}, \nbname{N2B*}, \nbname{N2C*}, \nbname{N2D*}\\
+ & & \nbname{N3A*}, \nbname{N3B*}, \nbname{N3C*}, \nbname{N3D*}\\
+\hline
+2 & \nbname{N2B} & \nbname{N2A}, \nbname{N2B}, \nbname{N2C}, \nbname{N2D}\\
+ & & \nbname{N1A*}, \nbname{N1B*}, \nbname{N1C*}, \nbname{N1D*}\\
+ & & \nbname{N3A*}, \nbname{N3B*}, \nbname{N3C*}, \nbname{N3D*}\\
+\hline
+3 & \nbname{N3D} & \nbname{N3A}, \nbname{N3B}, \nbname{N3C}, \nbname{N3D}\\
+ & & \nbname{N1A*}, \nbname{N1B*}, \nbname{N1C*}, \nbname{N1D*}\\
+ & & \nbname{N2A*}, \nbname{N2B*}, \nbname{N2C*}, \nbname{N2D*}\\
+\hline
+\end{tabular}\]
+\vspace{\baselineskip}
+
+Synchronisationen zwischen dem Domain Master Browser und den Lokalen
+Master Browsern wird weiterhin auftreten, aber dies sollte den
+stabilen Zustand nur best"atigen.
+
+Wenn Router R1 oder R2 ausfallen, wird das folgende passieren:
+
+\begin{enumerate}
+\item Namen der Computer auf beiden Seiten der nicht mehr erreichbaren
+Subnetze werden f"ur 36 Minuten weiter in den Browse Listen gehalten,
+so da"s sie in der Netzwerkumgebung weiterhin erscheinen.
+
+\item Versuche, Verbindungen zu diesen Rechnern aufzubauen, werden
+scheitern, aber die Namen werden nicht von den Browse Listen entfernt
+werden.
+
+\item Wenn ein Subnetz vom WINS Server getrennt wird, wird es nur noch
+auf die lokalen Server zugreifen k"onnen, deren Namen mit lokaler
+Broadcast NetBIOS-Namensaufl"osung aufgel"ost werden k"onnen. Das ist
+vergleichbar mit der Situation, keinen Zugriff auf einen DNS Server
+mehr zu haben.
+\end{enumerate}
+
+\section{Einfache Freigaben}
+
+Der grunds"atzliche Aufbau der Datei \datei{smb.conf} wurde bereits
+auf Seite (\pageref{aufbau-smb.conf}) erw"ahnt. Bis zu diesem Punkt
+hat sich s"amtliche Konfiguration im Abschnitt \texttt{[global]}
+abgespielt, der globale Servereinstellungen beinhaltet. Wenn der
+Sambarechner nicht nur im Netz gesehen werden soll, sondern auch
+sinnvolle Dinge tun soll, mu"s man Freigaben zur Verf"ugung stellen.
+Dies tut man, indem man einfach einen neuen Abschnitt beginnt, dessen
+Name gerade nicht \texttt{[global]} ist. Um eine Freigabe vollst"andig
+zu machen, mu"s man mit dem Parameter \texttt{path} angeben, welches
+Verzeichnis man freigeben m"ochte. Eine f"ur alle Zugriffe offene
+Freigabe des Verzeichnisses \datei{/cdrom} erreicht man mit folgender
+\datei{smb.conf}:
+
+\begin{verbatim}
+[global]
+workgroup = arbeitsgruppe
+interfaces = <IP-Adresse>/<Netzmaske>
+security = share
+encrypt passwords = yes
+
+[cd]
+path = /cdrom
+guest ok = yes
+\end{verbatim}
+
+\noindent
+Damit entsteht auf dem Server eine Freigabe namens \texttt{CD}, die
+das Verzeichnis \datei{/cdrom} im Netz f"ur alle zum Lesen zur
+Verf"ugung stellt.
+
+\textbf{Achtung:}
+Es findet hier \emph{keine} "Uberpr"ufung der Zugriffsrechte statt. Um
+diese "Uberpr"ufung zu erm"oglichen, sollte zun"achst einmal der
+Aufbau einer Verbindung zu einer Freigabe genauer beleuchtet werden.
+
+\section{SMB-Sitzungen}
+
+Wird am Client eine Verbindung zu einer Freigabe auf einem SMB-Server
+aufgebaut, so m"ussen mehrere Schritte durchlaufen werden.
+
+\subsection*{NetBIOS-Namensaufl"osung}
+
+Zu einem Rechnernamen mu"s eine IP-Adresse herausgefunden werden. Dies
+wurde in den letzten Abschnitten eingehend behandelt.
+
+\subsection*{TCP-Verbindung}
+
+Wenn die IP-Adresse klar ist, wird eine TCP-Verbindung zu Port 139 des
+Servers aufgebaut. Um vorhandene TCP-Verbindungen anzuzeigen, gibt es
+sowohl auf Unix- als auch auf Windowsrechnern das Werkzeug
+\prog{netstat}.
+
+\subsection*{NetBIOS-Sitzung}
+
+Auf einem Serverrechner arbeiten unter Umst"anden mehrere
+Applikationen, die Namen f"ur sich reserviert haben. Diese sind alle
+unter der IP-Adresse des Rechners und dem TCP-Protokoll auf Port 139
+erreichbar. Anhand des TCP-Verbindungsaufbaus ist nicht klar, welche
+Serverapplikation angesprochen werden soll. Die Unterscheidung wird
+durch den Servernamen getroffen, der in der TCP-Verbindung als erstes
+"ubertragen wird.
+
+Da"s der Servername "ubertragen wird, kann man ganz einfach mit Hilfe
+des Programms \prog{smbclient} sehen. Man versucht, sich die Liste der
+Freigaben eines realen Windowsrechners geben zu lassen, indem man
+folgendes aufruft:
+
+\verb|smbclient -L smallwin|
+
+Damit wird zun"achst eine NetBIOS-Namensanfrage ausgel"ost, und dann
+eine Verbindung zum entsprechenden Server ausgel"ost. \prog{smbclient}
+hat jedoch die M"oglichkeit, einen Server unter einem anderen Namen
+anzusprechen, indem man
+
+\verb|smbclient -L test -I ip-adresse|
+
+\noindent
+eingibt. \prog{smbclient} wird zun"achst versuchen, eine Verbindung
+zum NetBIOS-Namen \texttt{test} aufzubauen, und zwar ohne da"s eine
+NetBIOS-Namensanfrage ausgel"ost wird. Stattdessen wird die angegebene
+IP-Adresse auf Port 139 direkt angesprochen, und der Name
+\texttt{test} als Servername angegeben. Windows merkt, da"s das nicht
+stimmen kann und verweigert den Verbindungsaufbau mit einer
+Fehlermeldung. Erst im zweiten Versuch wird es \prog{smbclient}
+gelingen, eine Verbindung aufzubauen, da diese Verbindung zum
+allgemeinen Namen \texttt{*smbserver}\footnote{Das Protokoll wurde als
+Antwort auf das WebNFS von SUN in Common Internet File System umbenannt.
+Im Gegensatz zur Firma SUN, die tats"achlich das NFS-Protokoll verbessert
+hat, hat sich Microsoft die Arbeit einfacher gemacht. Der Name
+\texttt{*SMBSERVER} ist der einzige echte Unterschied, den CIFS von
+seinem Urvater SMB unterscheidet. Mit Windows 2000 werden diese
+NetBIOS-Namen beim Verbindungsaufbau gar komplett unterschlagen.
+Daf"ur ist es aber notwendig, einen weiteren Port zu reservieren, und
+zwar Port 445.} aufgebaut wird.
+
+Auch der Clientname wird in der Verbindung "ubergeben. Dies testet man
+am besten mit
+
+\verb|smbclient //win/c\$ -n blafasel|
+
+\noindent und schaut sich
+die Verbindungstabelle auf der Windowsmaschine mit \verb|nbtstat -s|
+an.
+
+Mit dem "ubergebenen Servernamen kann man sehr nette Tricks anstellen.
+Man stelle sich vor, da"s einige Freigaben nur f"ur bestimmte
+Clientrechner sichtbar sein sollen. Dies ist mit Bordmitteln von Samba
+so nicht m"oglich. Man kann zwar mit dem Parameter \param{browseable}
+festlegen, ob bestimmte Freigaben in der Netzwerkumgebung erscheinen.
+Dieser Parameter hat aber zwei Nachteile. Erstens sind die Freigaben nur
+unsichtbar geworden, darauf zugreifen kann man immer noch. Zweitens kann man
+Freigaben nur f"ur alle Rechner verstecken oder freigeben.
+
+Samba bietet die Option, unter zwei oder mehreren verschiedenen Namen
+in der Netzwerkumgebung zu erscheinen. Mit dem Parameter
+\param{netbios name} gibt man einen Namen f"ur den Server an.
+Zus"atzliche Namen kann man mit \param{netbios aliases} vergeben. Mit
+
+\begin{verbatim}
+netbios name = fichte
+netbios aliases = birke eiche kiefer buche
+\end{verbatim}
+
+\noindent
+handelt man sich einen ganzen Wald in der Netzwerkumgebung ein. Klickt
+man auf die einzelnen Server, sieht man "uberall die gleichen
+Freigaben und Zugriffsrechte. Nun kann man f"ur jeden dieser
+virtuellen Rechner eine eigene Konfigurationsdatei anlegen.
+Beispielsweise kann man sie \datei{/etc/smb.conf.birke},
+\datei{/etc/smb.conf.eiche} und so weiter nennen. Die Datei
+\datei{/etc/smb.conf} ist f"ur den Rechner \nbname{fichte} zust"andig
+und enth"alt neben den Einstellungen f"ur \nbname{fichte} den
+Parameter
+
+\param{config file = /etc/smb.conf.\%L}
+
+\noindent Dabei steht
+\param{\%L} f"ur den Servernamen, unter dem Samba angesprochen wird.
+Wenn es eine passende Datei gibt, dann bewirkt der Parameter
+\param{config file}, da"s die komplette Konfiguration neu eingelesen
+wird. Existiert keine passende Datei, so wird der Parameter einfach
+ignoriert. Um nun den Zugriff nur f"ur einzelne Clients zu erlauben,
+kann bei den einzelnen virtuellen Servern mit den Parametern
+\param{hosts allow} und \param{hosts deny} der Zugriff geregelt
+werden.
+
+\subsection*{Negotiate Protocol}
+
+Die NetBIOS-Sitzung ist nun aufgebaut, und es k"onnen Daten
+"ubermittelt werden. Innerhalb dieser NetBIOS-Sitzung wird eine
+SMB-Sitzung schrittweise aufgebaut. SMB ist ein Protokoll, bei dem im
+Prinzip der Client jede Aktion durch eine Anfrage anst"o"st, und der
+Server diese beantwortet\footnote{Im Prinzip deshalb, da mit Oplocks
+ auch der Server von sich aus aktiv werden kann.}.
+
+SMB (Server Message Block) ist ein gewachsenes Protokoll. Es ist mit
+den F"ahigkeiten der Betriebssysteme gewachsen, die damit arbeiten.
+Zun"achst ist es entstanden, um die Dateisystemaufrufe der MS-DOS
+Systemschnittstelle INT 0x21 auf das Netz zu verlagern. Mit einer
+gewissen Weitsicht hat man jedoch vorausgesehen, da"s die Entwicklung
+nicht bei MS-DOS stehen bleiben w"urde, sondern sich die
+Dateisystemaufrufe "andern w"urden. Man hat im Protokoll also eine
+M"oglichkeit vorgesehen, mit der unterschiedliche Protokollvarianten
+ausgehandelt werden k"onnen. Die unterschiedlichen Protokolle
+orientieren sich immer an den F"ahigkeiten der jeweiligen
+Betriebssysteme. Beispielsweise wurde mit dem LAN Manager, der eine
+Benutzerverwaltung besitzt, das Konzept des Benutzers im Protokoll
+aufgenommen. OS/2 hat ein recht weitgehendes Konzept der
+Druckerverwaltung, das entsprechend mit Protokollerweiterungen bedacht
+wurde. Sogar f"ur XENIX gibt es einen eigenen Protokolldialekt, der
+das Unix-Zugriffsrechtekonzept im SMB-Protokoll abbildet. Diese
+Protokollvariante beherrscht nur leider kein moderner Client. Mit
+Ausnahme des ausgestorbenen XENIX-Dialektes lassen sich die Protokolle
+gut in eine Hierarchie einordnen. Sp"atere Protokolle beherrschen alle
+Aspekte der vorherigen Varianten.
+
+Die erste Anfrage, die der Client an den Server schickt, ist ein
+\defin{Negotiate Protocol Request}. In dieser Anfrage schickt der
+Client an den Server eine Liste der Protokollvarianten, die er
+beherrscht. Der Server w"ahlt nun aus dieser Liste der Protokolle eins
+aus, und schickt eine entsprechende Antwort zur"uck. Die verschiedenen
+Protokolle bauen aufeinander auf. Daher kann man mit dem Parameter
+\param{protocol} das h"ochste Protokoll festlegen, mit dem Samba
+arbeiten soll.
+
+In der Antwort auf diese erste Anfrage werden zwei weitere
+Einstellungen verschickt, die Teile des weiteren Ablaufs festlegen.
+
+Der Server entscheidet, ob er die Zugriffssteuerung auf Benutzer- oder
+auf Freigabeebene regeln m"ochte. Damit wird festgelegt, zu welchem
+Zeitpunkt der Benutzer ein Pa"swort liefern mu"s. Entweder kann es
+beim direkt folgenden \defin{Session Setup} erfolgen, oder erst beim
+\defin{Tree Connect} danach.
+
+Der Parameter \param{security} legt fest, welche Art der
+Zugriffssteuerung gew"ahlt wurde. Mit \param{security = share} wird
+die Freigabeebene eingestellt, \param{security = user} legt die
+Clients auf die Benutzerebene fest.
+
+Sichtbar wird diese Unterscheidung in der Windowswelt nur bei Windows
+95 und Windows 98. Diese Betriebssysteme beherrschen zun"achst einmal
+nur die Zugriffssteuerung auf Freigabeebene, da sie nicht "uber eine
+Benutzerdatenbank verf"ugen. Es ist nicht m"oglich, einzelnen
+Benutzern den Zugriff auf Freigaben zu gew"ahren oder zu
+verweigern. Um trotzdem benutzerbasiert Zugriffssteuerung zu
+erm"oglichen, mu"s ein Server angegeben werden, der f"ur Windows die
+Benutzerdatenbank pflegt. Damit k"onnen Pa"sw"orter benutzerbasiert
+"uberpr"uft werden.
+
+Weiterhin gibt der Server dem Client vor, ob Klartextpa"sw"orter
+verwendet werden sollen, oder ob die Pa"sw"orter verschl"usselt
+werden. Wenn der Server festlegt, da"s verschl"usselte Pa"sw"orter
+verwendet werden, wird zus"atzlich die Herausforderung f"ur das
+\defin{Challenge Response} Verfahren mitgeschickt.
+
+Die Entscheidung "uber Klartextpa"sw"orter mu"s also getroffen werden,
+ohne da"s der Server den Benutzernamen, der sich anmelden will,
+kennt. Es ist also nicht m"oglich, f"ur einige Benutzer
+Klartextpa"sw"orter und f"ur andere Benutzer verschl"usselte
+Pa"sw"orter zu verwenden.
+
+\subsection*{Session Setup}
+
+Nachdem die Protokollversion ausgehandelt ist, wird vom Client ein
+\defin{Session Setup} verschickt. In diesem Session Setup schickt der
+Client seinen Benutzernamen an den Server. Sofern dieser
+\param{security = user} verlangt hat, wird an dieser Stelle das
+Pa"swort mitgeschickt. Damit ist der Server in der Lage, die
+Identit"at des Benutzers festzustellen. Wenn \param{security = share}
+vereinbart wurde, dann ignoriert der Server ein hier eventuell
+mitgeschicktes Pa"swort.
+
+\subsection*{Tree Connect}
+
+Als letztes legt der Client fest, welche Freigabe er ansprechen will.
+Der entsprechende Aufruf hei"st \defin{Tree Connect}. Sofern
+\param{security = share} vereinbart wurde, wird an dieser Stelle das
+Pa"swort "uberpr"uft. Der Benutzername kann in diesem Fall nicht zur
+Zugriffsregelung verwendet werden. Dieser wurde unter Umst"anden gar
+nicht "ubermittelt, da der Client den Session Setup komplett auslassen
+darf. Andererseits hat er bei einem durchgef"uhrten Session Setup kein
+Pa"swort angeben m"ussen, anhand dessen die Identit"at des Benutzers
+zweifelsfrei h"atte festgestellt werden k"onnen.
+
+\section{Zugriffsrechte}
+
+Bei Windows NT kann man mit zwei unterschiedlichen Mechanismen Rechte
+vergeben. An einer Freigabe kann man "uber Schreib- und Lesezugriff
+entscheiden. Innerhalb des Dateisystems kann man detailiert Rechte
+vergeben.
+
+Ist bei Samba \param{security = user} gesetzt, so hat der Server die
+M"oglichkeit, anhand des angemeldeten Benutzers Zugriffsrechte zu
+vergeben oder zu verweigern. Wenn bez"uglich der Zugriffsrechte bei
+einer Freigabe nichts gesagt wird, hat jeder korrekt angemeldete
+Benutzer Leserecht. Man kann auch Gastbenutzern Leserecht geben, indem
+man \param{guest ok = yes} setzt.
+
+Mit den Optionen zur Rechtevergabe an Freigaben hat man die
+M"oglichkeit, einzelnen Benutzern und ganzen Unixgruppen Rechte zu
+geben oder zu nehmen. Die M"oglichkeiten sind hier deutlich weitergehend
+als die Semantik, die Unix mit den Rechtemasken f"ur den
+Dateibesitzer, die besitzende Gruppe und den Rest der Welt bereit
+stellt. Von den m"oglichen Anwendungen sollen hier drei h"aufig
+ben"otigte F"alle dargestellt werden.
+
+\begin{itemize}
+\item {\bf \emph{Alle} Benutzer haben gleichen Zugriff}
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+\end{verbatim}
+
+Bei dieser Freigabe bekommen alle Benutzer, die sich mit Namen und
+Pa"swort am Server angemeldet haben, \emph{Leserecht} auf die
+Freigabe. Schreibrecht vergibt man, indem man den Parameter
+\param{writeable = yes} setzt:
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+writeable = yes
+\end{verbatim}
+
+\item {\bf \emph{Einige} Benutzer haben gleichen Zugriff}
+
+Will man den Zugriff auf einige Benutzer einschr"anken, erstellt man
+eine Liste \param{valid users} auf:
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+valid users = mueller, meier
+\end{verbatim}
+
+Zu dieser Freigabe haben die Benutzer mueller und meier
+Lesezugriff. Sollen diese Benutzer Schreibzugriff bekommen, so ist wie
+im vorangegangenen Beispiel der Parameter \param{writeable = yes} zu
+setzen:
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+valid users = mueller, meier
+writeable = yes
+\end{verbatim}
+
+F"ur den Parameter \param{valid users} spielt der Benutzer root keine
+besondere Rolle. Das hei"st, da"s er auf die Freigabe \param{projekt}
+keinen Zugriff hat. Soll er Zugriff bekommen, mu"s man ihn wie jeden
+anderen Benutzer in die Liste \param{valid users} mit aufnehmen.
+
+Der Parameter \param{valid users} gibt die M"oglichkeit, ganze
+Unixgruppen in den Zugriff mit aufzunehmen. Um dies zu erreichen, mu"s
+man das at-Zeichen voranstellen:
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+valid users = root, @users
+writeable = yes
+\end{verbatim}
+
+Mit dieser Einstellung haben alle Benutzer, die in der Unixgruppe
+users sind, Schreibzugriff auf die Freigabe. Zus"atzlich kann der
+Benutzer root schreiben.
+
+\item {\bf Einige Benutzer haben Leserecht, andere Schreibrecht}
+
+Will man differenziert Rechte vergeben, so mu"s man s"amtliche
+Benutzer, die "uberhaupt Zugriff auf die Freigabe bekommen sollen, in
+die Liste \param{valid users} aufnehmen, und mit \param{writeable =
+no} nur Leserechte vergeben. Die Benutzer, die "uber diese
+Standardeinstellung hinaus Schreibrecht bekommen sollen, m"ussen in
+die \param{write list} aufgenommen werden.
+
+\begin{verbatim}
+[projekt]
+path = /data/projekt
+valid users = @users, @admins
+writeable = no
+write list = @admins
+\end{verbatim}
+
+Mit diesen Einstellungen haben die Benutzer der Gruppe users
+Leserecht, und die Benutzer der Gruppe admins haben Schreibrecht.
+
+\end{itemize}
+
+\section{Unix-Zugriffsrechte}
+
+Unter Windows NT gibt es zwei M"oglichkeiten, Zugriff auf Dateien zu
+gew"ahren. "Uber eine Freigabe kann ein Lese- oder ein Schreibrecht
+vergeben werden. Im zweiten Schritt k"onnen dann "uber eine
+Rechtevergabe im Dateisystem weitere Rechte vergeben werden. Samba
+regelt die Zugriffskontrolle ebenfalls in zwei Schritten. Die
+freigabebezogenen Rechte werden "uber Parameter wie \param{valid
+users} und \param{write ok} geregelt. Die Zugriffsrechte innerhalb des
+Dateisystems regelt Samba nicht selbst, sondern verl"a"st sich
+hierf"ur auf das darunterliegende Betriebssystem Unix.
+
+Zwischen Unix und DOS bestehen gro"se Unterschiede. DOS und alle seine
+Nachfolger sind Einzelbenutzersysteme, Unix ist von Anfang an als
+Multiusersystem entworfen worden. Diese Unterschiede werden besonders
+deutlich, wenn man die Attribute betrachtet, die auf Dateien vergeben
+werden. DOS kennt vier Attribute:
+
+\begin{description}
+\item[Read-Only] Der Inhalt dieser Datei kann nur gelesen, aber nicht
+geschrieben werden. Die Datei kann nicht gel"oscht werden.
+\item[System] Diese Datei ist f"ur spezielle Betriebssystemzwecke
+vorgesehen.
+\item[Hidden] Diese Datei wird mit dem Kommando 'DIR' nicht angezeigt.
+\item[Archiv] Das Archivbit wird bei jedem Schreibzugriff gesetzt.
+Backupprogrammen ist es freigestellt, dieses Bit zur"uckzusetzen.
+Damit kann eine inkrementelle Sicherung erm"oglicht werden.
+\end{description}
+
+Diese Bits k"onnen vom Benutzer frei gesetzt und wieder zur"uckgesetzt
+werden. Sie bieten also keinen echten Zugriffsschutz, sondern nur eine
+gewisse Sicherung gegen Fehlbedienung.
+
+Unix f"uhrt mit jeder Datei einen Satz von Zugriffsrechten mit. Diese
+sind aufgeteilt in 3 Gruppen von Benutzern: Der Dateibesitzer, die
+besitzende Gruppe und alle anderen. Jeder Gruppe k"onnen 3
+Rechte zugeteilt werden: Lesen, Schreiben und ausf"uhren.
+
+Unter DOS werden Ausf"uhrungsrechte nicht verwendet. Sie stehen f"ur
+Samba zur Verf"ugung, um die DOS-Attribute im Unix-Dateisystem
+abzubilden. Das Schreibschutzbit unter DOS hat mit dem Schreibrecht
+des Dateibesitzers unter Unix eine Entsprechung. Bis auf die Umsetzung
+des Schreibschutzbits kann die Umsetzung der Attribute unter Samba mit
+den entsprechenden Parametern \param{map <xxx>} gesteuert werden,
+wobei das Archivbit ohne Zusatzangabe umgesetzt wird, die anderen
+beiden Attribute nicht. Die Attributumsetzung erfolgt anhand der
+folgenden Tabelle:
+
+\[ \begin{tabular}{|l|l|c|l|l|}
+\hline
+DOS-Attribut & Unix-Recht & Maske & Parameter & Standard \\
+\hline\hline
+Schreibschutz & Schreibrecht Besitzer & 200 & - & immer \\
+\hline
+Archiv & Ausf"uhrung Besitzer & 100 & \param{map archive} & \param{yes} \\
+\hline
+System & Ausf"uhrung Gruppe & 010 & \param{map system} & \param{no} \\
+\hline
+Versteckt & Ausf"uhrung Andere & 001 & \param{map hidden} & \param{no} \\
+\hline
+\end{tabular} \]
+
+Samba mu"s nun diese beiden Dateiattribute ineinander "uberf"uhren.
+Samba mu"s neu erstellten Dateien Unixrechte zuordnen. Wird eine
+Datei neu erstellt, dann gibt der Client dem Server die DOS-Attribute
+mit, mit der er die Datei erstellt haben m"ochte. Daraus formt Samba
+einen Satz von Unix-Zugriffsrechten. Diese Rechte werden vom Parameter
+\param{create mask} eingeschr"ankt. Die Standardvorgabe f"ur die
+\param{create mask} ist gleich \param{744}, was der Rechtemaske
+\param{rwxr--r--} entspricht. Der Dateieigent"umer hat Schreib- und
+Leserecht, alle anderen haben reines Leserecht. Samba schr"ankt die
+Rechte ein, indem der gew"unschte Satz an Rechten mit einer logischen
+UND-Operation mit der \param{create mask} verkn"upft wird. Nur die
+Rechte, die in der \param{create mask} gesetzt sind, k"onnen
+m"oglicherweise in der neu erzeugten Datei auftauchen. In einem
+weiteren Schritt setzt Samba explizit gew"unschte Zugriffsrechte
+anhand des Parameters \param{force create mode}, dessen Standardwert
+auf \param{000} steht. Dies geschieht durch eine ODER-Verkn"upfung mit
+diesem Wert.
+
+Diese Zusammenh"ange werden an einem Beispiel deutlicher. Es kann
+gew"unscht sein, da"s auf neu erstellten Dateien nur der
+Dateibesitzer und die Gruppe Leserecht haben sollen. Der Rest der Welt
+soll diese Dateien nicht lesen k"onnen. Das wird dadurch erreicht,
+da"s man die \param{create mask = 740} setzt, also das Leserecht f"ur
+den Rest der Welt ausmaskiert. Es kann dar"uber hinaus gew"unscht
+sein, da"s die besitztende Gruppe ein Schreibrecht einger"aumt
+bekommt. Das kann man durch \param{force create mode = 020} erreichen.
+Tabellarisch dargestellt hei"st dies:
+
+\[ \begin{tabular}{|l|l||c|l|}
+\hline
+Wunsch & & & \texttt{rw-r-{}-r-{}-} \\
+\hline
+create mask & 740 & UND & \texttt{rw-r-{}-{}-{}-{}-} \\
+\hline
+\hline
+& & & \texttt{rw-r-{}-{}-{}-{}-} \\
+\hline
+force create mode & 020 & ODER & \texttt{-{}-{}-{}-w-{}-{}-{}-} \\
+\hline
+\hline
+Ergebnis & & & \texttt{rw-rw-{}-{}-{}-} \\
+\hline
+\end{tabular} \]
+
+Die Ausf"uhrungsrechte auf Dateien werden unter DOS nicht verwendet,
+sie k"onnen also verwendet werden, um DOS-Attribute im
+Unix-Dateisystem abzulegen. Ausf"uhrungsrechte auf Dateiverzeichnissen
+wirken sich jedoch auf das Verhalten von Samba aus, da durch sie der
+Zugriff zu den Verzeichnissen geregelt wird. Daher kann es
+w"unschenswert sein, da"s die Rechtezuweisung auf Dateien und
+Verzeichnissen unterschiedlich geregelt wird. Die Parameter
+\param{create mask} und \param{force create mode} wirken daher nur auf
+neu angelegte Dateien. F"ur Verzeichnisse sind die Parameter
+\param{directory mask} und \param{force directory mode}
+verantwortlich. Der Vorgabewert f"ur \param{directory mask} ist
+hierbei \param{755}, um den Zutritt f"ur die Gruppe und den Rest der
+Welt zu erm"oglichen, die Vorgabe f"ur \param{force directory mode}
+besetzt mit dem Wert \param{000} kein zus"atzliches Recht.
+
+\section{Beispiel: Projektverzeichnisse}
+
+Folgendes Problem stellt sich bei der Migration von Novell zu Samba
+recht h"aufig. Unter Novell kann man anhand von
+Gruppenzugeh"origkeiten den Zugriff auf Verzeichnisse regeln. Dies ist
+unter Samba anhand von Unixrechten ebenfalls m"oglich. Was Unix leider
+nicht zur Verf"ugung stellt, ist die M"oglichkeit, Verzeichnisse vor
+Benutzern zu verstecken. Ein Benutzer sieht grunds"atzlich alle
+Verzeichnisse, bekommt aber bei vielen dieser Verzeichnisse die
+Meldung, da"s der Zugriff verweigert wurde. Wenn es jetzt anhand der
+Gruppenzugeh"origkeit des Benutzers m"oglich w"are, nur die
+Verzeichnisse anzuzeigen, auf die er tats"achlich Zugriff hat,
+k"onnten die Verzeichnisse deutlich "ubersichtlicher werden.
+
+Die Flexibilit"at von Samba erm"oglicht es, diese von Unix
+vorgegeben Beschr"ankung zu umgehen, und zwar unter Benutzung von
+Skripten, die vor dem Verbinden mit einer Freigabe ausgef"uhrt werden.
+
+Folgendes Szenario wird vorausgesetzt: Jeder Benutzer ist in mehrere
+Gruppen eingeteilt, die jeweils Projekte, Arbeitsgruppen oder
+Abteilungen darstellen k"onnen. Jede dieser Gruppen hat unter
+\datei{/data/groups} ein eigenes Verzeichnis, auf das sie schreiben
+darf. Die einzelnen Verzeichnisse haben das Set Group ID Bit gesetzt,
+damit die neu angelegten Dateien den jeweiligen Gruppen angeh"oren.
+
+Als Beispiel gebe es die drei Gruppen \param{edv}, \param{fibu} und
+\param{verkauf}. Das Gruppenverzeichnis \datei{/data/groups} sieht
+folgenderma"sen aus:
+
+{\small\begin{verbatim}
+root@server:/data/groups> ls -l
+total 12
+drwxrws--- 2 root edv 4096 Jan 31 06:43 edv
+drwxrws--- 2 root fibu 4096 Jan 31 06:43 fibu
+drwxrws--- 2 root verkauf 4096 Jan 31 06:43 verkauf
+root@server:/data/groups>
+\end{verbatim}
+}
+
+Die korrekten Rechte erreicht man unter Unix durch:
+
+{\small\begin{verbatim}
+root@server:/root> mkdir /data/groups/edv
+root@server:/root> chgrp edv /data/groups/edv
+root@server:/root> chmod 2770 /data/groups/edv
+\end{verbatim}
+}
+
+Eine Freigabe, die jedem Benutzer anhand seiner Rechte hierauf Zugriff
+gew"ahrt, kann folgenderma"sen aussehen:
+
+{\small\begin{verbatim}
+[allgroups]
+path = /data/groups
+writeable = yes
+create mode = 740
+directory mode = 750
+force create mode = 020
+force directory mode = 020
+\end{verbatim}
+}
+
+Zu beachten ist hier, da"s keine zus"atzlichen Einschr"ankungen anhand
+von \param{valid users} notwendig sind, da der Zugriff durch die
+Unixrechte beschr"ankt ist. Die Parameter \param{create mask} und
+\param{directory mask} sind nicht strikt notwendig, da bereits auf der
+Ebene \datei{/data/share} die Benutzer abgewiesen werden. Die
+Parameter \datei{force create mode} und \param{force directory mode}
+sind hingegen notwendig, da ohne sie neu angelegte Dateien nicht die
+notwendigen Gruppenschreibrechte erhalten w"urden, die zum gemeinsamen
+Zugriff notwendig sind.
+
+Diese Freigabe erf"ullt funktional genau die Anforderungen, da"s
+jeder in die Verzeichnisse schreiben darf, f"ur die er die
+Gruppenmitgliedschaft hat. Der Nachteil an diesem Verfahren ist, da"s
+er alle anderen Verzeichnisse sieht, was bei gro"sen Servern mit
+vielen Gruppen recht un"ubersichtlich werden kann.
+
+Die preexec-Skripte von Samba erm"oglichen die "ubersichtliche
+Darstellung der Gruppenstruktur. Ein preexec-Skript wird ausgef"uhrt,
+bevor der Benutzer tats"achlich mit der Freigabe verbunden wird.
+
+{\small\begin{verbatim}
+[gruppen]
+path = /data/users/%U
+root preexec = /usr/local/bin/mklinks %U
+writeable = yes
+\end{verbatim}
+}
+
+Die Datei \datei{mklinks} hat folgenden Inhalt:
+
+{\small\begin{verbatim}
+#!/bin/sh
+umask 022
+cd /data/users
+rm -rf "$1"
+mkdir "$1"
+cd "$1"
+for i in `groups $1`
+do
+ ln -s /data/groups/$i .
+done
+\end{verbatim}
+}
+
+Beim Verbinden an die Freigabe wird das Verzeichnis
+\datei{/data/users/username} frisch erstellt, das anhand der
+Gruppenzugeh"origkeit des Benutzers eine Liste von symbolischen
+Links erstellt, die auf die eigentlichen Gruppenverzeichnisse
+verweisen. Damit bekommt er nur die Verzeichnisse im Explorer
+angezeigt, auf die er tats"achlich Zugriff hat. Durch die Angabe
+\param{path = /data/users/\%U} ist zudem sichergestellt, da"s die
+Freigabe f"ur alle Benutzer gleich hei"st, aber f"ur jeden
+Benutzer auf ein eigenes Verzeichnis verweist. Das Skript wird in
+diesem Beispiel als \param{root preexec} ausgef"uhrt, um den
+Verwaltungsaufwand beim Anlegen neuer Benutzer zu minimieren. Mit
+einem reinen \param{preexec} ohne Rootrechte w"are es notwendig,
+f"ur jeden Benutzer unterhalb von \param{/data/users} ein eigenes
+Verzeichnis mit den notwendigen Rechten anzulegen. Alternativ
+k"onnte man das Verzeichnis mit der Gruppenliste im
+Heimatverzeichnis des Benutzers anlegen, wobei dabei Zweifel
+bez"uglich der "Ubersichtlichkeit angebracht sind. Ein weiteres
+Argument, das Skript unter Rootrechten auszuf"uhren, ist die
+Betriebssicherheit. Ohne dies w"are es dem Benutzer m"oglich, sich
+vollst"andig von einem Gruppenverzeichnis auszuschlie"sen indem er
+das gesamte Verzeichnis inklusive symbolischem Link l"oscht. Mit
+der dargestellten Version geh"ort das Verzeichnis mit den
+symbolischen Links dem Benutzer root, und Fehlbedienungen in
+dieser Ebene sind ausgschlossen.
+
+Wenn man die Freigabe \param{[allgroups]} auf \param{[browseable =
+ no]} setzt, so hat man maximale "Ubersichtlichkeit bei vollem
+Zugriff auf s"amtliche Gruppenverzeichnisse durch den Administrator
+gegeben.
+
+"Andern sich die Gruppenzugeh"origkeiten eines Benutzers, so kann
+er einfach durch ein Neuverbinden an die Freigabe die neue Sicht auf
+die Verzeichnisstruktur bekommen. Dieses Neuverbinden kann erzwungen
+werden, indem der richtige Serverprozess get"otet wird. Dieser kann
+anhand des Programms \prog{smbstatus} leicht herausgefunden werden.
+
+\section{Pa"sw"orter}
+\label{passwoerter}
+
+Protokolle der IP-Welt wie telnet, ftp und pop3 "ubertragen die
+Pa"sw"orter zur Benutzerauthentifizierung im Klartext. Damit kann
+jeder, der den Netzverkehr abh"oren kann, s"amtliche Pa"sw"orter
+mitschreiben. Daf"ur existieren fertige Programme, die Benutzernamen
+und dazugeh"orige Pa"sw"orter ausgeben. In der Unixwelt wurde dies
+zun"achst nicht als problematisch angesehen, da zum Zugriff auf das
+Netz Administratorrechte oder physikalischer Zugriff zum Netz
+notwendig sind. Beides war historisch oft nicht gegeben, so da"s das
+Risiko als relativ gering eingesch"atzt wurde. Mit dem Aufkommen von
+DOS und Ethernet hat jeder Benutzer Administratorrechte, kann also den
+Netzverkehr mitschneiden.
+
+Benutzerauthentifizierung mu"s vor allem eins leisten: Der Benutzer
+mu"s beweisen, da"s er sein Pa"swort kennt. Ein
+Authentifizierungsprotokoll kann es dabei erm"oglichen, da"s das
+Pa"swort nicht "ubertragen werden mu"s.
+
+Im SMB-Protokoll wird zur Authentifizierung ein Challenge-Response
+Verfahren eingesetzt. Der Server verschickt an den Client eine
+Zufallszahl, die sogenannte Herausforderung. Der Client kennt das
+Benutzerpa"swort, und verschl"usselt die Herausforderung mit dem
+Pa"swort als Schl"ussel. Diesen verschl"usselten Wert verschickt der
+Client anstelle des Pa"sworts. Der Server kennt das Benutzerpa"swort
+ebenfalls, und kann den versch"usselten Wert entschl"usseln. Entsteht
+bei der Entschl"usselung wieder die Herausforderung, so hat der
+Benutzer die Herausforderung offensichtlich mit dem korrekten Pa"swort
+verschl"usselt. Kommt etwas anderes heraus, war das Pa"swort nicht
+richtig.
+
+\begin{figure}\[
+\begin{pspicture}(11.5,6.5)
+%\psgrid[subgriddiv=1,griddots=10]
+\psframe(11.5,6.5)
+\psline(3,6.5)(3,0)
+\psline(7,6.5)(7,0)
+\psframe[fillstyle=solid,fillcolor=lightgray](3,0)(7,6.5)
+\rput(2,6){{\sffamily\bfseries Client}}
+\rput(5,6){{\sffamily\bfseries Zuh"orer}}
+\rput(8,6){{\sffamily\bfseries Server}}
+\psline(0,5.7)(11.5,5.7)
+
+\psline{->}(2.5,5)(7.5,5)
+\rput(5,5.2){Negotiate Protocol}
+
+\rput[lB](8,4.5){H: Herausforderung}
+\psline{->}(7.5,4.5)(2.5,4.5)
+\rput(5,4.3){{\bfseries H}}
+
+\psline{->}(2.5,3)(7.5,3)
+\rput(5,3.2){Session Setup}
+\rput(5,2.8){{\bfseries Username, PW(H)}}
+\rput[lB](0.3,3.9){Herausforderung}
+\rput[lB](0.3,3.5){Username}
+\rput[lB](0.3,3.1){Pa"swort}
+
+\rput[lB](8,2.9){Username}
+\rput[lB](8.2,2.5){$\Rightarrow$ Pa"swort}
+\rput[lB](8.2,2.1){entschl"ussle PW(H)}
+
+\pscurve{->}(5.8,2.7)(8,1.8)(9.5,1.8)(10,2)
+\rput[tl](9.8,1.9){$\Rightarrow$ H}
+
+\pscurve{<->}(10.5,1.6)(10.8,1.5)(11.3,2)(11,3)(8.3,4.4)
+\rput[t](10.8,1.4){=?}
+
+\psline{->}(7.5,0.8)(2.5,0.8)
+\rput(5,0.6){{\bfseries Ok?}}
+\end{pspicture}\]
+\caption{Challenge-Response Verfahren}
+\end{figure}
+
+Ein Zuh"orer verf"ugt
+"uber die Herausforderung und den verschl"usselten Wert. Mit
+diesen beiden Werten k"onnte er einen Known Plaintext Angriff gegen
+die Verschl"usselung starten. Das hei"st, es mu"s ein
+Verschl"uselungsalgorithmus gew"ahlt werden, der gegen einen solchen
+Angriff immun ist. Er kann keine Replay Attacke starten, da er bei
+jedem neuen Verbindungsaubau eine neue Herausforderung bekommt, die er
+verschl"ussen mu"s.
+
+Windows NT verh"alt sich diesbez"uglich vern"unftig. Windows 95 denkt
+sich jedoch nur alle 15 Minuten eine neue Herausforderung aus. Das
+hei"st, da"s jemand nur einen Verbindungsaufbau mitschneiden mu"s, und
+sich sofort danach mit der gleichen Benutzerkennung bei der gleichen
+Maschine anmelden kann. Man kann sich
+fast sicher darauf verlassen, die gleiche Herausforderung zu
+bekommen, und mit der mitgeschnittenen Antwort Zugriff zu erhalten.
+Dies gilt selbstverst"andlich nur f"ur die Zugriffe, bei denen Windows
+95 als Server benutzt wird. Und wer tut das schon?
+
+Dieses Verfahren setzt voraus, da"s der Server "uber das
+Benutzerpa"swort im Klartext verf"ugt. Unter Unix tut er das nicht,
+sondern der Server kennt nur eine zerhackte Version des Pa"swortes,
+den Wert aus der Datei \datei{/etc/shadow}.
+
+Eine Hashfunktion, wie sie unter Unix eingesetzt wird, hat drei
+Eigenschaften.
+
+\begin{enumerate}
+
+\item Sie ist leicht zu berechnen. Dies ist notwendig, damit die
+Pa"swort"uberpr"ufung nicht zu lange dauert.
+
+\item Sie ist nur sehr schwer umkehrbar. Das hei"st, aus dem zerhackten
+Pa"swort
+ist das Klartextpa"swort nicht berechenbar. Als Beispiel f"ur eine
+solche Einwegfunktion soll hier die Multiplikation
+herhalten. 98453*34761=3422324733 ist relativ einfach zu
+berechnen. Da"s die Zahl 3422324733 aus den beiden Ursprungszahlen
+entstanden ist, ist schon sehr viel schwieriger herauszufinden. Es
+gibt Verfahren, mit denen der R"uckweg ausgeschlossen ist\footnote{Wie
+"uberall in der Kryptographie gilt dies auch nur so lange, bis jemand
+den R"uckweg gefunden hat.}.
+
+Mit dieser Eigenschaft war es zu rechtfertigen, da"s in den fr"uhen
+Tagen von Unix die Hashwerte der Pa"sw"orter f"ur alle Benutzer lesbar
+waren, da niemand daraus etwas ableiten konnte. Mit dem "Uberflu"s an
+Rechenleistung kann man aber sogenannte crack-Programme verwenden, die
+die erste Eigenschaft der Hashfunktion ausnutzen: Sie probieren
+einfach tausende von Pa"sw"ortern pro Sekunde aus. Schlechte
+Pa"sw"orter k"onnen so sehr schnell gefunden werden. Daher hat man die
+Pa"sw"orter in die nicht allgemein lesbare Datei \datei{/etc/shadow}
+ausgelagert.
+
+\item Zwei verschiedene Pa"sw"orter f"uhren zu zwei verschiedenen
+Hashwerten. Damit kann das Loginprogramm ausreichend sicher sein, da"s
+ein korrekter Hashwert aus dem korrekten Pa"swort entstanden ist.
+
+\end{enumerate}
+
+Authentifizierung unter Unix setzt voraus, da"s der Client dem Server
+das Klartextpa"swort pr"asentiert. Der Server kann daraus den Hashwert
+berechnen, und mit dem gespeicherten Wert vergleichen. Leider verf"ugt
+er nicht "uber das Klartextpa"swort des Benutzers, um das
+Challenge-Response Verfahren durchf"uhren zu k"onnen. Daher mu"s unter
+Samba f"ur die Pa"swortversch"usselung eine zweite Pa"swortdatenbank
+gepflegt werden, die Datei \datei{smbpasswd}.
+
+Auch in der Datei \datei{smbpasswd} stehen keine
+Klartextpa"sw"orter. Bevor die Herausforderung mit dem Pa"swort
+verschl"usselt wird, wird das Pa"swort unter Windows ebenfalls durch
+eine Hashfunktion geschickt. Von dieser Hashfunktion gibt es zwei
+Varianten, die beide nicht mit den unter Unix verwendeten Funktionen
+"ubereinstimmen. Das hei"st, da"s man mit den dort enthaltenen Werten
+so direkt nicht mehr anfangen kann als mit den Werten aus der Datei
+\datei{/etc/shadow} unter Unix, denn wenn man sie als Pa"swort
+eingeben w"urde, w"urde Windows sofort wieder den Hash darauf anwenden,
+und einen anderen, also falschen Wert daraus errechnen. Das Programm
+\prog{smbclient} mu"s diese Operation ebenfalls durchf"uhren, nur hat
+man hierzu den Quellcode und kann die entsprechenden Stellen
+auskommentieren. So hat man die M"oglichkeit, sich anhand der Werte in
+der \datei{smbpasswd} ohne Einsatz von crack bei einem NT-Rechner
+anzumelden.
+
+Alles nicht dramatisch, sagt Microsoft. Das "Aquivalent zur Datei
+\datei{smbpasswd} liegt unter NT verschl"usselt vor. Diese
+Verschl"usselung mu"s jedoch reversibel sein, um das
+Challenge-Response Verfahren durchf"uhren zu k"onnen. Ein Teil der
+Sicherheitsargumentation liegt darin, da"s dieses
+Verschl"usselungsverfahren nicht offengelegt wurde. Das Verfahren war
+solange geheim, bis Jeremy Allison das Programm \prog{pwdump}
+ver"offentlicht hat. Dieses Programm extrahiert aus der
+Benutzerdatenbank von NT eine Datei, die direkt als \datei{smbpasswd}
+verwendet werden kann\footnote{Allerdings nur f"ur Samba 1.9, zu 2.0
+ hin wurde das Format ge"andert. Es gibt in Samba 2.0 aber ein
+ Konvertierungsskript.}.
+
+Das hei"st, der Administrator unter NT verf"ugt direkt "uber die
+Pa"sw"orter aller Benutzer oder zumindest "uber etwas Gleichwertiges.
+Damit hat er automatisch die M"oglichkeit, sich bei fremden Systemen
+anzumelden, sofern dort das Pa"swort gleich ist. Bei Unix kann sich
+der Administrator zwar in die Identit"at jedes Benutzers versetzen.
+Dies bleibt aber auf das lokale System beschr"ankt, da er das Pa"swort
+des Benutzers nicht kennt.
+
+Sollte ein neugieriger Administrator einmal an den tats"achlichen
+Pa"sw"orten seiner Benutzer interessiert sein, dann macht NT es ihm
+deutlich einfacher als Unix dies tut. Unix verwendet sogenannte
+versalzene Pa"sw"orter. Wenn ein Pa"swort ge"andert wird, dann wird
+ein Zufallswert berechnet, dem Pa"swort hinzugef"ugt und dann die
+Hashfunktion durchgef"uhrt. Der Zufallswert wird der Datei
+\datei{/etc/shadow} im Klartext hinzugef"ugt, damit die "Uberpr"ufung
+die gleichen Operationen durchf"uhren kann. So kann man keine Tabelle
+von Pa"sw"ortern und den zugeh"origen Hashwerten anlegen. Man kann
+auch nicht erkennen, wenn zwei Benutzer das gleiche Pa"swort
+verwenden. Windows NT verwendet dieses Verfahren nicht.
+
+Aus Kompatibilit"atsgr"unden mu"s NT auch noch zus"atzlich einen sehr
+schlechten Hashwert mitf"uhren. Bei alten Windowsversionen konnte das
+Pa"swort bis zu 14 Zeichen lang sein. War es k"urzer, wurde es mit
+Leerzeichen aufgef"ullt. Dann wurde mit den ersten 7 Zeichen ein
+Hashwert berechnet, und dann mit den zweiten 7 Zeichen. Das hei"st, es
+sind sofort alle Pa"sw"orter erkennbar, die weniger als 7 Zeichen
+haben, da die zweite H"alfte des Hashwertes immer gleich ist.
+
+\section{Druckfreigaben}
+
+Um Drucker unter Samba zur Verf"ugung zu stellen, m"ussen diese von
+Unix aus ansprechbar sein. Unter Linux mit einem BSD-kompatiblen
+Drucksystem geschieht dies durch Eintr"age in der Datei
+\datei{/etc/printcap}. Alle Drucker, die dort definiert sind, kann man
+als Netzwerkdrucker f"ur Windowsclients freigeben.
+
+Unter Linux ist die Frage der Druckertreiber noch nicht
+zufriedenstellend gel"ost. Druckertreiber unter Windows w"urde man
+unter Linux nicht als solche bezeichnen. In der Linuxwelt sind Treiber
+Softwaremodule, die direkt Hardware wie Netzwerkkarten oder den
+parallelen Port ansprechen. Druckertreiber im Sinne von Windows sind
+unter Linux sogenannte Filter, die Druckdaten in ein f"ur den Drucker
+akzeptables Format aufbereiten. Das einheitliche Druckformat unter
+Linux ist Postscript, das mit dem Programm Ghostscript in viele
+druckereigene Formate umgewandelt werden kann. Druckertreiber unter
+Windows gehen vom Windows Metafile-Format aus, und wandeln dies
+entsprechend um. Das Windows Metafile-Format enth"alt Aufrufe an die
+Graphische Komponente von Windows, das GDI.
+
+Wenn man einen Drucker, der "uber Unix angesprochen wird, von Windows
+aus nutzen m"ochte, mu"s man planen, wo die Aufbereitung in das
+druckereigene Format geschehen soll. Zwei Wege sind denkbar.
+
+\begin{itemize}
+\item Auf den Arbeitspl"atzen wird ein generischer Postscripttreiber
+ installiert. Die Clients m"ussen nicht wissen, welches Druckermodell
+ sich hinter einer Freigabe verbirgt. Die Umwandlung findet auf dem
+ Druckerserver mittels \prog{ghostscript} statt.
+\item Der Druckertreiber reicht die Daten weiter, ohne sie weiter zu
+ behandeln. Auf den Arbeitspl"atzen werden f"ur jeden Netzdrucker die
+ korrekten Treiber installiert.
+\end{itemize}
+
+Beide Wege haben Vor- und Nachteile. Im ersten Fall hat man weniger
+Aufwand mit der Administration auf Clientseite. Man mu"s den korrekten
+"`Druckertreiber"' nur einmal definieren, am Druckerserver. Beim
+zweiten Weg kann man die bessere Unterst"utzung der Druckerhersteller
+f"ur die Windowsplattformen nutzen. Druckertreiber f"ur Windows bieten
+in der Regel die M"oglichkeit, Sonderfunktionen wie die Auswahl des
+Papierschachtes zu nutzen. Dieser erh"ohte Komfort zieht jedoch nach
+sich, da"s auf jedem Client der korrekte Druckertreiber installiert
+ist.
+
+Nutzt eine Windows NT Workstation einen Drucker, der von einem Windows
+NT Server freigegeben wurde, so gibt es noch die M"oglichkeit, die
+Druckaufbereitung komplett vom NT Server vornehmen zu lassen, und
+trotzdem s"amtliche Komfortfunktionen auf der Workstation zu nutzen.
+Dazu mu"s auf der Workstation kein Druckertreiber installiert sein.
+Diese sogenannten EMF-Druckerwarteschlangen kann Samba zur Zeit nicht
+exportieren. Samba wird dies voraussichtlich auch nicht so schnell
+erm"oglichen, da hierf"ur gro"se Teile von Windows, n"amlich das GDI,
+auf Sambaseite implementiert werden m"u"ste.
+
+Eine Druckfreigabe wird genau wie eine Dateifreigabe in einem eigenen
+Abschnitt erstellt, wobei f"ur die Druckfunktion drei Optionen
+notwendig sind:
+
+\begin{verbatim}
+[deskjet]
+printable = yes
+printer = lp
+path = /tmp
+\end{verbatim}
+
+Zu einer Druckfreigabe wird die Definition durch die Angabe
+\param{printable = yes}.
+
+Mit der Option \param{printer =} wird festgelegt, welche
+Druckerwarteschlange unter Unix angesprochen werden soll. Dieser
+Drucker mu"s das Format verstehen, das vom Windowsdruckertreiber
+geliefert wird. Also sollte hier entweder Postscript angenommen
+werden, oder die Daten sollten per sogenannter Raw-Queue direkt ohne
+Umwandlung an den Drucker weitergeleitet werden.
+
+Die Option \param{path =} legt einen Spoolbereich fest. Ein Druckjob,
+den ein Windowsrechner an Samba schickt, mu"s zun"achst in einer Datei
+abgespeichert werden. Wenn diese Datei geschlossen wird, teilt der
+Client dem Server mit, da"s diese nun zum Drucker geschickt werden
+soll. Samba realisiert dies, indem das Programm \prog{lpr} mit der
+Druckdatei als Argument aufgerufen wird. Samba mu"s also f"ur sich die
+M"oglichkeit haben, Druckjobs in Dateien zu speichern, bevor sie an
+den \prog{lpd} "ubergeben werden. Dies sollte nicht das
+Spoolverzeichnis sein, das der \prog{lpd} selbst f"ur den Drucker
+vorsieht.
+
+\section{Samba als Logon-Server}
+
+Wenn sich in einem Netz Windows 95/98 Clients befinden, kann es
+w"unschenswert sein, da"s sich die Benutzer dieser Arbeitspl"atze nur
+mit einem Pa"swort anmelden k"onnen, das zentral auf einem Server
+vorgehalten wird. Dazu mu"s der entsprechende Server spezielle Aufrufe
+von Clients entgegennehmen und korrekt beantworten. In der reinen
+Windowswelt ist dazu ein Windows NT Server notwendig, der als
+sogenannter Primary Domain Controller (PDC) installiert ist. Samba ist
+ebenfalls in der Lage, dies zu tun. Dazu ist im Abschnitt
+\param{[global]} der Parameter \param{domain logons = yes} zu setzen.
+Die Implementation, die Microsoft gew"ahlt hat, um Dom"anenanmeldungen
+zu erm"oglichen, erzwingt zus"atzlich, da"s der Domain Master Browser
+auf dem gleichen Rechner liegt wie der Logon Server. Das hei"st, man
+ben"otigt f"ur Dom"anenanmeldungen die folgenden Parameter:
+
+\begin{verbatim}
+[global]
+workgroup = samba
+domain logons = yes
+domain master = yes
+\end{verbatim}
+
+Hat man diese Parameter gesetzt, kann man in den Eigenschaften des
+Clients f"ur Microsoft-Netzwerke einstellen, da"s der Client sich an
+der Dom"ane \texttt{samba} anmelden soll. Hat man verschl"usselte
+Pa"sw"orter (Siehe Abschnitt \ref{passwoerter}) aktiviert, kann man
+vom Client aus sein SMB-Pa"swort "andern, indem man das entsprechende
+Kontrollfeld in der Systemsteuerung von Windows benutzt.
+
+\section{Windows NT Dom"anen}
+
+Die Dom"anenanmeldung unter Windows 95/98 ist eine relativ einfache
+Sache, da es sich dabei praktisch nur um eine "Uberpr"ufung der
+Benutzerpa"sw"orter handelt. So etwas wie Benutzer kennt Windows 95
+praktisch nicht, jeder Benutzer hat vollen Zugriff auf das gesamte
+System. Erst mit Windows NT hat Microsoft den Schritt hin zu einem
+Betriebssystem gemacht, das Benutzerkonten und Zugriffsrechte
+verwalten kann. Damit sind sie sehr viel weiter gegangen, als Unix
+dies getan hatte. Um das Konzept der Windows NT Dom"ane zu
+verdeutlichen, soll hier zun"achst auf das Konzept des Benutzers unter
+Windows und unter Unix eingegangen werden.
+
+Unter Unix besteht ein Benutzer im wesentlichen aus einer numerischen
+Userid, und nicht mehr. Das Programm \prog{login} mu"s beim Anmelden
+des Benutzers anhand seines Namens herausfinden, welche numerische
+Userid er hat. Dazu sieht es in der Datei \datei{/etc/passwd} nach.
+Mit der Datei \datei{/etc/shadow} pr"uft \prog{login} das Pa"swort.
+Ist es korrekt, wird in die gefundene Userid umgeschaltet und die
+Loginshell des Benutzers gestartet. Nach diesem Vorgang ist es Unix
+v"ollig egal, wie der Benutzer hei"st, das einzige, was interessiert,
+ist der numerische Wert. Damit h"angt an jedem Proze"s eine endeutige
+Identifikation der Rechte, die er hat.
+
+Unter Unix ist es so, da"s Userids nur auf dem Rechner gelten, auf dem
+sie zugeordnet wurden. Es gibt keine M"oglichkeit, Rechte von einem
+Rechner auf den n"achsten zu "ubernehmen oder global Benutzer
+zuzuordnen. Die einzige M"oglichkeit, die man zu Vereinheitlichung
+hat, ist der Austausch der jeweils auf einem Rechner geltenden
+Tabellen "uber verschiedene Rechner hinweg. Genau das tut NIS oder
+Yellow Pages. Die Benutzerdatenbank wird verteilt, gilt aber auf jedem
+Rechner rein lokal.
+
+Unter NT sieht das sehr "ahnlich aus, nur da"s hier der Benutzer nicht
+durch eine kleine Zahl, sondern durch einen Security Identifier SID
+repr"asentiert wird. Ein solcher SID ist mehrteilig. Der erste Teil
+dieses SID beinhaltet eine Kennung der Benutzerdatenbank, zu der
+dieser Benutzer geh"ort. Ein solcher SID ist 96 Bit lang und Microsoft
+behauptet, da"s dieser Wert zuf"allig genug gew"ahlt ist, da"s es
+keine zwei Benutzerdatenbanken geben kann, die die gleiche SID haben.
+Der zweite Teil besteht aus einem sogenannten Relative Identifier RID,
+der den Benutzer innerhalb der Dom"ane eindeutig identifiziert. Die
+Kennung f"ur die Dom"ane besteht aus 3 32-Bit Zahlen, die zusammen 96
+Bit ergeben.
+
+Unter Windows NT hat nun jeder Rechner eine eigene Benutzerdatenbank,
+genau wie unter Unix. Da aber jede Benutzerdatenbank eindeutig
+identifiziert ist, kann es keine zwei Benutzer mit gleicher Userid
+geben. Der Relative Identifier mag gleich sein, der Identifier f"ur
+die Benutzerdatenbank unterscheidet sich aber auf jeden Fall.
+
+Microsoft unterscheidet verschiedene Netzwerkmodelle. Das Peer-To-Peer
+Netz ist das Modell, das auch Unix zugrunde liegt. Hier hat jeder
+beteiligte Rechner eine eigene Benutzerdatenbank, eigene Pa"sw"orter
+und eigene Rechtezuordnungen. Das Dom"anenmodell ist das Modell, das
+sich signifikant von Unix unterscheidet. Mit dem Dom"anenmodell wird
+eine Workstation in die Lage versetzt, mehr als eine Benutzerdatenbank
+zu benutzen. Neben der eigenen Benutzerdatenbank, die jede Workstation
+hat, kann sie eine Benutzerdatenbank von einem anderen Rechner
+importieren. In einer Windows NT Dom"ane gibt es einen Rechner, der
+seine eigene Benutzerdatenbank anderen zur Verf"ugung stellt, den
+sogenannten Primary Domain Controller. Dieser reserviert f"ur sich
+spezielle NetBIOS-Namen, um sich den Workstations als Logonserver
+anzubieten. Eine Workstation befragt den Primary Domain Controller
+nach allen relevanten Daten zu den Benutzern, die sich bei ihr
+anmelden wollen, und die Rechte auf der Workstation wahrnehmen
+k"onnen.
+
+Die Kommunikation zwischen der Workstation und dem Primary Domain
+Controller l"auft verschl"usselt ab. Um eine solche Verschl"usselung
+zu erm"oglichen, mu"s ein gemeinsamer Schl"ussel vereinbart werden. Um
+sich "uber einen Schl"ussel einig zu werden, gibt es spezialisierte
+Protokolle, wie beispielsweise der Diffie-Hellmann
+Schl"usselaustausch. Um jeglichen Problemen mit Patenten oder
+Exportrestriktionen zu umgehen, ist Microsoft einen anderen Weg
+gegangen. Beim Schl"usselaustausch geht es im wesentlichen darum,
+sich "uber ein gemeinsames Geheimnis einig zu werden. Um ein
+gemeinsames Geheimnis zu wahren und zu pr"ufen, kennt Microsoft
+bereits eine Gruppe von Protokollen: Die Protokolle zum Pr"ufen und
+Austauschen von Benutzerpa"sw"ortern. Genau diese Protokolle werden
+verwendet, um die Kommunikation zwischen PDC und Workstation zu
+sichern. Daher mu"s jede Workstation explizit in die Dom"ane
+aufgenommen werden.
+
+Bei Samba ist es so, da"s es zu jedem Benutzer, der ein Pa"swort in
+der \datei{/etc/smb.conf} hat, einen Benutzer im System geben mu"s.
+Der zu einer Workstation geh"orende Benutzer mu"s den NetBIOS-Namen
+der Workstation, erg"anzt um ein \$-Zeichen, haben. Man ben"otigt also
+zwei Schritte, um eine Workstation in die Dom"ane aufzunehmen. Im
+ersten Schritt wird der Unixbenutzer angelegt. Dies geschieht in
+vielen Linuxsystemen mit dem Kommando \texttt{useradd -m $<$user$>$}.
+Der angelegte Benutzer ben"otigt im Unixsystem weder ein Pa"swort noch
+ein Heimatverzeichnis. Er ist notwendig, da die Workstation in der
+Dom"ane eine eigene SID bekommt, die aus der Unix userid berechnet
+wird. Dann mu"s die Workstation ein Pa"swort in der
+\datei{/etc/smbpasswd} bekommen, und zwar mit dem Befehl
+\texttt{smbpasswd -a -m name}. Ein Beispiel sieht folgenderma"sen aus:
+
+\begin{verbatim}
+root@erde: useradd -m wks\$
+root@erde: smbpasswd -a -m wks
+\end{verbatim}
+
+Man beachte, da"s beim Befehl \texttt{useradd} ein Dollarzeichen,
+maskiert durch den Backslash, hinzugef"ugt wurde. Der Befehl
+\prog{smbpasswd} f"ugt diesen bei Verwendung des Parameters \prog{-m}
+selbst hinzu.
+
+\section{Samba als Dom"anenmitglied}
+
+Mit dem Parameter \param{security} kann man den Zeitpunkt steuern, zu
+dem das Benutzerpa"swort gepr"uft wird. \param{security = share} legt
+fest, da"s die Pr"ufung beim Tree Connect stattfindet, das hei"st,
+wenn die Freigabe angesprochen wird. Ist \param{security = user}
+angegeben, wird das Pa"swort bereits einen Schritt vorher, also beim
+Session Setup gepr"uft. Bei \param{security = user} wird also die
+Kombination von Benutzer und Pa"swort gepr"uft bei \param{security =
+ share} die Kombination Freigabe und Pa"swort.
+
+Der Parameter \param{security} kann noch zwei weitere Werte annehmen:
+\param{server} und \param{domain}. Bei beiden Einstellungen verh"alt
+sich Samba gegen"uber dem Client genau wie bei \param{security =
+ user}, der Benutzer mu"s sich unter seinem Namen beim Server
+authentifizieren. Die Unterschiede liegen in der Art und Weise, wie
+das Pa"swort "uberpr"uft wird.
+
+\begin{itemize}
+\item \param{security = user}: Die "Uberpr"ufung findet anhand einer
+ lokalen Datenbank statt. Werden Klartextpa"sw"orter verwendet
+ (\param{encrypt passwords = no}), so wird die lokale
+ Unix-Pa"swortdatenbank in \datei{/etc/passwd}, \datei{/etc/shadow}
+ oder die entsprechende NIS-Tabelle herangezogen. Bei
+ verschl"usselten Pa"sw"ortern mit wird die Samba-eigene
+ Pa"swortdatenbank in der Datei \datei{smbpasswd} zur "Uberpr"ufung
+ herangezogen.
+\item \param{security = server}: Bei dieser Einstellung bekommt der
+ Sambaserver vom Client einen Benutzernamen und ein Pa"swort
+ pr"asentiert. Er versucht daraufhin, sich mit diesem Pa"swort bei
+ einem weiteren Server anzumelden. Funktioniert dies, hat der
+ Benutzer sein Pa"swort offensichtlich richtig eingegeben. Schl"agt
+ dies fehl, wird auch dem Client des Sambaservers der Fehler
+ mitgeteilt und der Zugriff verweigert. Der Pa"swortserver, der zur
+ "Uberpr"ufung herangezogen wird, mu"s mit seinem NetBIOS-Namen im
+ Parameter \param{password server} angegeben werden.
+\item \param{security = domain}: Auch hierbei wird die "Uberpr"ufung
+ einem Pa"swortserver "uberlassen. Dieser mu"s jedoch ein Primary
+ Domain Controller sein, der den Sambaserver in die Dom"ane
+ aufgenommen hat. Der Hauptvorteil gegen"uber \param{security =
+ server} besteht in einer deutlich reduzierten Last auf dem
+ Pa"swortserver und einer verschl"usselten Kommunikation zwischen
+ Samba und Pa"swortserver.
+\end{itemize}
+
+Um einen Windowsrechner dazu zu bringen, f"ur einen Sambaserver die
+Pa"swort"uberpr"ufung zu "ubernehmen, mu"s man nur \param{security =
+ server} und den \param{password server} passend setzen. Dabei
+"ubernimmt der Server ausschlie"slich die "Uberpr"ufung der
+Pa"s\-w"orter. Bei verschl"usselten Pa"sw"ortern k"onnen Benutzer nur
+dann in die \datei{smbpasswd} aufgenommen werden, wenn sie in der
+Unix-Benutzerdatenbank existieren. Genau so verh"alt es sich bei
+\param{security = server}. Benutzer k"onnen auf Samba nur dann
+zugreifen, wenn sie als normale Unixbenutzer existieren.
+
+\param{security = server} ist nicht die optimale L"osung f"ur die
+"Uberpr"ufung von Pa"sw"ortern durch einen weiteren Rechner.
+
+Um die Vorteile der Dom"anenmitgliedschaft zu nutzen, ist etwas mehr
+Aufwand notwendig. Mitglied einer Dom"ane zu sein hei"st, mit dem
+Primary Domain Controller "uber einen verschl"usselten Kanal
+kommunizieren zu k"onnen. Diese Verschl"usselung wird verwendet, um
+Benutzerinformationen verdeckt austauschen zu k"onnen. Als
+Verschl"usselungsverfahren kommt ein symmetrisches oder auch secret
+key Verfahren zum Einsatz. Um ein symmetrisches Verfahren anwenden zu
+k"onnen, m"ussen sich beide Partner "uber ein gemeinsames Geheimnis,
+den \emph{secret key} einig sein. Ein solches gemeinsames Geheimnis
+mu"s regelm"a"sig ge"andert werden, um einer gro"sen Klasse von
+kryptographischen Angriffen auszuweichen. Eine solche "Anderung darf
+selbstverst"andlich nicht abgeh"ort werden k"onnen, da ein Zuh"orer
+damit die gesamte Kommunikation abh"oren kann. F"ur die "Anderung
+eines Geheimnisses gab es bereits vor der Implementation des
+Dom"anenprotokolls ein fertiges Protokoll, das man direkt verwenden
+konnte: Die M"oglichkeit, Benutzerpa"sw"orter "uber das Netz zu
+"andern, war mir einem gesicherten Protokoll implementiert. Um dieses
+Protokoll zur verschl"usselten Kommunikation zwischen einer
+Workstation oder einem Mitgliedsserver und dem Dom"anencontroller
+nutzen zu k"onnen, mu"s es f"ur jedes Dom"anenmitglied ein
+Benutzerkonto geben. Genau dies wird auf dem Dom"anencontroller
+erstellt, wenn man eine Workstation oder einen Server mit dem
+Servermanager in die Dom"ane aufnimmt. Betritt man danach mit der
+Workstation die Dom"ane, wird als erstes das Pa"swort des
+Computerkontos ge"andert.
+
+Um einen Sambaserver in eine Dom"ane aufzunehmen, sind zwei Schritte
+notwendig.
+
+\begin{itemize}
+\item Auf dem Server mu"s der Sambaserver mit seinem NetBIOS-Namen in
+ die Dom"ane aufgenommen werden.
+\item Der Sambaserver selbst mu"s dar"uber informiert werden, da"s er
+ sich in der Dom"ane befindet, und er mu"s sein Pa"swort "andern.
+ Dies geschieht mit dem Befehl
+
+\verb|smbpasswd -j DOM -r PDC|
+
+Dabei steht \texttt{DOM} f"ur die Dom"ane, die betreten wird. Mit
+\texttt{PDC} wird der NetBIOS-Name des Dom"anencontrollers der Dom"ane
+benannt.
+\end{itemize}
+
+Mit diesem Kommando wird das Maschinenpa"swort auf dem PDC auf einen
+neuen, zuf"alligen Wert ge"andert. Dieses neue Maschinenpa"swort f"ur
+den Samba Server wird in einer Datei im gleichen Verzeichnis wie die
+Datei \texttt{smbpasswd} abgespeichert und hat folgenden Namen:
+
+\verb|<NT DOMAENENNAME>.<Samba Servername>.mac|
+
+Die Endung .mac steht f"ur \emph{Machine ACcount} Pa"swortdatei. Im obigen
+Beispiel w"urde die Datei also \texttt{DOM.SERV1.mac} hei"sen.
+
+Diese Datei wird von root erstellt und ist f"ur keinen anderen
+Benutzer lesbar. Sie ist der Schl"ussel zu Ihrer Dom"anensicherheit
+und sollte genau so vorsichtig behandelt werden wie die Datei
+\texttt{/etc/shadow}.
+
+Nach diesen beiden Schritten kann man mit \param{security = domain},
+\param{password server = PDC BDC1 BDC2} und \param{encrypt passwords =
+ yes} die Pa"swort"uberpr"ufung an einen der Dom"anencontroller
+delegieren. Dies sind die Prim"aren und Backup Dom"anencontroller, die
+Samba der Reihe nach kontaktieren wird, um Benutzer zu
+authentifizieren. Samba wird sie in der aufgef"uhrten Reihenfolge
+ansprechen. Sie k"onnen also die Reihenfolge ver"andern, um eine
+g"unstigere Lastverteilung zu erreichen. Eine weitere Option ist die
+Angabe \param{password server = *}. Damit sucht Samba mit den
+Standardmethoden\footnote{Windows NT findet einen Dom"anencontroller,
+ indem der NetBIOS-Name \nbname{DOMAIN<1C>} gesucht wird.} von
+Windows NT nach einem Dom"anencontroller und befragt die Server, die
+es bei dieser Anfrage herausbekommen hat.
+
+Warum ist \param{security = domain} besser als \param{security =
+ server}?
+
+Der Vorteil der Dom"anensicherheit ist, da"s Samba die
+Authentifizierung "uber einen gesicherten RPC Kanal schickt, genau wie
+ein Windows NT Server es tun w"urde. Das hei"st, da"s Samba nun genau
+wie ein Windows NT Server an einer Vertrauensstellung teilnehmen kann.
+Das hei"st, Sie k"onnen einen Samba Server in eine Resourcendom"ane
+aufnehmen, und Sie k"onnen die Authentifizierung via Resourcen PDC vom
+PDC der Benutzerdom"ane vornehmen lassen.
+
+Zus"atzlich mu"s in der Einstellung \texttt{security = server} der
+Samba D"amon eine Verbindung zum Authentifizierungsserver w"ahrend
+seiner gesamten Laufzeit offenhalten. Dies kann die Anzahl der offenen
+Verbindungen auf einem Windows NT Server in die H"ohe treiben, so da"s
+dieser keine Verbindungen mehr annimmt. Mit \texttt{security = domain}
+verbinden sich die Samba D"amonen nur so lange mit dem PDC, wie es
+f"ur die Benutzerauthentifizierung notwendig ist. Danach wird die
+Verbindung wieder abgebaut, so da"s die Verbindungen wieder
+anderweitig verwendbar sind.
+
+Und nicht zuletzt bekommt der Samba Server als Teil der Antwort auf
+die Authentifizierungsanforderung Informationen "uber den Security
+Identifier, die Gruppenzuordnungen und andere Informationen "uber den
+Benutzer. All diese Informationen werden Samba zuk"unftig erlauben, in
+einem sogenannten Appliance Modus zu laufen. In diesem Modus wird
+kein manuell angelegter Unixbenutzer mehr notwendig sein. Samba wird Unix
+Benutzer und Gruppen aus der Authentifizierungsantwort des PDC
+erzeugen. Damit wird Samba wirklich ein Plug and Play Mitglied einer
+Dom"ane.
+
+Dieser Appliance Modus kann heute schon ann"ahernd erreicht werden,
+indem bei Samba der Parameter \param{add user script} angegeben wird.
+In diesem Parameter wird ein Unixprogramm angegeben, das dynamisch
+einen Unixbenutzer erzeugen mu"s, nachdem ein Pa"swortserver die
+Korrektheit eines Pa"sworts best"atigt hat. Ein Beispiel kann sein:
+
+\verb|add user script = /usr/bin/useradd -m %U|
+
+Damit wird einfach ein Benutzer hinzugef"ugt, wenn er noch nicht
+existiert, aber der PDC das Pa"swort best"atigt hat.
+
+\end{document}
+
diff --git a/docs/textdocs/logo.ps b/docs/textdocs/logo.ps
new file mode 100644
index 00000000000..4fa39aef368
--- /dev/null
+++ b/docs/textdocs/logo.ps
@@ -0,0 +1,344 @@
+%!PS-Adobe-3.0
+%%Pages: (atend)
+%%BoundingBox: 0 261 683 580
+%.....................................
+%%Creator: Aladdin Ghostscript 601 (pswrite)
+%%CreationDate: 2000/08/03 14:15:29
+%%DocumentData: Clean7Bit
+%%EndComments
+%%BeginProlog
+% This copyright applies to everything between here and the %%EndProlog:
+% Copyright (C) 2000 Aladdin Enterprises, Menlo Park, CA. All rights reserved.
+%%BeginResource: procset GS_pswrite_ProcSet
+/GS_pswrite_ProcSet 80 dict dup begin
+/!{bind def}bind def/#{load def}!/N/counttomark #
+/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!
+/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}!
+/w/setlinewidth #/J/setlinecap #
+/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat #
+/m/moveto #/l/lineto #/c/rcurveto #/h{p closepath}!/H{P closepath}!
+/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!
+/re{4 -2 roll m exch dup lx exch ly neg lx h}!
+/^{3 index neg 3 index neg}!
+/P{N 0 gt{N -2 roll moveto p}if}!
+/p{N 2 idiv{N -2 roll rlineto}repeat}!
+/f{P fill}!/f*{P eofill}!/s{H stroke}!/S{P stroke}!
+/q/gsave #/Q/grestore #/rf{re fill}!
+/Y{initclip P clip newpath}!/Y*{initclip P eoclip newpath}!/rY{re Y}!
+/|={pop exch 4 1 roll 3 array astore cvx exch 1 index def exec}!
+/|{exch string readstring |=}!
+/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!
+/@/currentfile #/${+ @ |}!
+/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!
+/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!
+/|X{exch string readhexstring |=}!/$X{+ @ |X}!
+/@X{{currentfile ( ) readhexstring pop}}!
+/PS{1 index where{pop cvx exec pop pop}{pop/setpage where
+{pop pageparams 3{exch pop}repeat setpage}{pop pop}ifelse}ifelse}!
+end def
+%%EndResource
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+/pagesave save def GS_pswrite_ProcSet begin
+612 792 /letter PS
+0.1 0.1 scale
+480 0 translate
+%%EndPageSetup
+mark
+75 w
+4 M
+255 15 0 rG
+481.48 4361.14 m
+-66 41.75 -145.25 62.64 -237.74 62.64 c
+-24.49 0 -47.76 -3.02 -69.76 -9 c
+-31.49 -8.49 -46.23 -21.97 -44.23 -40.43 c
+1.99 -16.99 28.47 -38.2 79.51 -63.66 c
+78.49 -38.96 125.74 -63.66 141.74 -74.15 c
+51.97 -33.95 79.98 -69.9 83.99 -107.81 c
+7 -64.92 -39.99 -117.36 -141.01 -157.3 c
+-90.5 -35.94 -199.74 -53.9 -327.74 -53.9 c
+-89.01 0 -168.99 7.23 -239.97 21.71 c
+-90.53 18.45 -137.02 39.43 -139.51 62.9 c
+-0.53 3.48 -0.03 6.97 1.49 10.49 c
+45 140.04 p
+74 -54.26 149.24 -81.39 225.76 -81.39 c
+36.97 0 54.23 12.21 51.74 36.68 c
+-3.52 30.41 -24.76 58.85 -63.75 85.31 c
+-20.51 12.95 -56.78 36.91 -108.75 71.84 c
+-43.51 29.91 -65.24 65.83 -65.24 107.75 c
+0 75.32 60.73 130.69 182.26 166.11 c
+84.49 24.44 182.72 36.68 294.72 36.68 c
+119.48 0 224.24 -16.81 314.24 -50.42 c
+17.25 -164.09 h
+S
+1304.6 4343.04 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.5 -60.29 -92.26 -90.44 -140.25 -90.44 c
+-35.01 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.25 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.5 -73.24 h
+1108.1 4573.78 m
+-132.51 0 -249.26 -30.5 -350.24 -91.5 c
+-120 -72.5 -180 -170.77 -180 -294.75 c
+0 -13.51 0.73 -27.51 2.25 -42.01 c
+7.97 -76.5 42.98 -134.24 105 -173.24 c
+53.49 -34.01 120.99 -51 202.5 -51 c
+149.01 0 267.75 57.86 356.25 173.61 c
+-51.76 -164.24 426 0 195.76 626.25 p
+-169.51 11.25 -404.76 16.88 -705.76 16.88 c
+h
+S
+5755.04 4343.04 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.5 -60.29 -92.26 -90.44 -140.25 -90.44 c
+-35 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.25 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.5 -73.24 h
+5558.54 4573.78 m
+-132.5 0 -249.25 -30.5 -350.24 -91.5 c
+-120 -72.5 -180 -170.77 -180 -294.75 c
+0 -13.51 0.73 -27.51 2.26 -42.01 c
+7.96 -76.5 42.97 -134.24 105 -173.24 c
+53.49 -34.01 120.99 -51 202.5 -51 c
+149 0 267.74 57.86 356.25 173.61 c
+-51.77 -164.24 426 0 195.77 626.25 p
+-169.52 11.25 -404.77 16.88 -705.77 16.88 c
+h
+S
+4670.96 5042.19 -297.33 668.31 -574.48 -685.34 202.89 3.96 -315.84 -1098.47 436.49 0 23.24 59.24 P
+50.5 -49.51 136.75 -74.24 258.75 -74.24 c
+132.01 0 247.99 31.94 348.01 95.83 c
+115.49 73.89 173.26 173.21 173.26 298.01 c
+0 13.95 -0.76 28.19 -2.25 42.66 c
+-15.5 147.74 -141.01 221.63 -376.5 221.63 c
+-63.01 0 -138.77 -10.64 -227.25 -31.88 c
+123.99 490.32 227.02 9.97 h
+4464.7 4260.71 m
+-48.01 -126.3 -109.01 -189.43 -182.99 -189.43 c
+-26.51 0 -49.01 3.69 -67.52 11.13 c
+-11.02 5.45 -22 10.9 -32.99 16.35 c
+16.49 45.32 p
+35.98 100.05 70.49 166.67 103.51 199.87 c
+28.01 28.21 68 42.33 120 42.33 c
+90.76 0 -47.26 -125.57 h
+S
+3637.84 4406.7 m
+-12.01 112.61 -97.53 168.95 -256.52 168.95 c
+-199.51 0 -348.49 -20.01 -446.98 -60 c
+-56.52 39.99 -147.02 60 -271.5 60 c
+-204.52 0 -428.26 -5.77 -671.25 -17.25 c
+-196.5 -627.75 436.5 0 23.26 62.26 p
+73.48 195 138.72 313.74 195.74 356.25 c
+32.98 24.99 77.48 37.5 133.5 37.5 c
+-19.02 -46.52 -33.25 -85.52 -42.75 -117.01 c
+-107.25 -339 442.5 0 24 62.26 p
+45.46 115.99 77.22 192.74 95.24 230.24 c
+30.49 62.49 60.23 104.51 89.24 126.01 c
+32.99 24.99 77.49 37.5 133.5 37.5 c
+-19.01 -46.52 -33.25 -85.52 -42.74 -117.01 c
+-292.57 -917.2 -223.62 3.05 297.33 -668.31 543.98 656.81 -177.09 2.42 295.99 923.64 p
+16 50.53 21.97 96.09 17.99 136.64 c
+h
+S
+K
+457.11 4402.39 m
+-66 41.75 -145.25 62.64 -237.74 62.64 c
+-24.49 0 -47.76 -3.02 -69.76 -9 c
+-31.49 -8.49 -46.23 -21.97 -44.23 -40.43 c
+1.99 -16.99 28.47 -38.2 79.51 -63.66 c
+78.49 -38.96 125.74 -63.66 141.74 -74.15 c
+51.97 -33.95 79.98 -69.9 83.99 -107.81 c
+7 -64.92 -39.99 -117.36 -141.01 -157.3 c
+-90.5 -35.94 -199.74 -53.9 -327.74 -53.9 c
+-89.01 0 -168.99 7.23 -239.97 21.71 c
+-90.53 18.45 -137.02 39.43 -139.51 62.9 c
+-0.53 3.48 -0.03 6.97 1.49 10.49 c
+45 140.04 p
+74 -54.26 149.24 -81.39 225.76 -81.39 c
+36.97 0 54.23 12.21 51.74 36.68 c
+-3.52 30.41 -24.76 58.85 -63.75 85.31 c
+-20.51 12.95 -56.78 36.91 -108.75 71.84 c
+-43.51 29.91 -65.24 65.83 -65.24 107.75 c
+0 75.32 60.73 130.69 182.26 166.11 c
+84.49 24.44 182.72 36.68 294.72 36.68 c
+119.48 0 224.24 -16.81 314.24 -50.42 c
+17.25 -164.09 p f
+45 w
+0 255 r6
+457.11 4402.39 m
+-66 41.75 -145.25 62.64 -237.74 62.64 c
+-24.49 0 -47.76 -3.02 -69.76 -9 c
+-31.49 -8.49 -46.23 -21.97 -44.23 -40.43 c
+1.99 -16.99 28.47 -38.2 79.51 -63.66 c
+78.49 -38.96 125.74 -63.66 141.74 -74.15 c
+51.97 -33.95 79.98 -69.9 83.99 -107.81 c
+7 -64.92 -39.99 -117.36 -141.01 -157.3 c
+-90.5 -35.94 -199.74 -53.9 -327.74 -53.9 c
+-89.01 0 -168.99 7.23 -239.97 21.71 c
+-90.53 18.45 -137.02 39.43 -139.51 62.9 c
+-0.53 3.48 -0.03 6.97 1.49 10.49 c
+45 140.04 p
+74 -54.26 149.24 -81.39 225.76 -81.39 c
+36.97 0 54.23 12.21 51.74 36.68 c
+-3.52 30.41 -24.76 58.85 -63.75 85.31 c
+-20.51 12.95 -56.78 36.91 -108.75 71.84 c
+-43.51 29.91 -65.24 65.83 -65.24 107.75 c
+0 75.32 60.73 130.69 182.26 166.11 c
+84.49 24.44 182.72 36.68 294.72 36.68 c
+119.48 0 224.24 -16.81 314.24 -50.42 c
+17.25 -164.09 h
+S
+13 16 255 rG
+1280.22 4384.29 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.5 -60.29 -92.25 -90.44 -140.24 -90.44 c
+-35.01 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.24 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.51 -73.24 h
+1083.73 4615.03 m
+-132.51 0 -249.26 -30.5 -350.25 -91.5 c
+-120 -72.5 -180 -170.77 -180 -294.75 c
+0 -13.51 0.73 -27.51 2.25 -42.01 c
+7.97 -76.5 42.98 -134.24 105 -173.24 c
+53.49 -34.01 120.99 -51 202.5 -51 c
+149 0 267.74 57.86 356.25 173.61 c
+-51.77 -164.24 426.01 0 195.76 626.25 p
+-169.51 11.25 -404.77 16.88 -705.76 16.88 c
+f
+0 255 r6
+1280.22 4384.29 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.5 -60.29 -92.25 -90.44 -140.24 -90.44 c
+-35.01 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.24 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.51 -73.24 h
+1083.73 4615.03 m
+-132.51 0 -249.26 -30.5 -350.25 -91.5 c
+-120 -72.5 -180 -170.77 -180 -294.75 c
+0 -13.51 0.73 -27.51 2.25 -42.01 c
+7.97 -76.5 42.98 -134.24 105 -173.24 c
+53.49 -34.01 120.99 -51 202.5 -51 c
+149 0 267.74 57.86 356.25 173.61 c
+-51.77 -164.24 426.01 0 195.76 626.25 p
+-169.51 11.25 -404.77 16.88 -705.76 16.88 c
+h
+S
+13 16 255 rG
+5730.66 4384.29 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.49 -60.29 -92.25 -90.44 -140.24 -90.44 c
+-35.01 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.25 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.51 -73.24 h
+5534.17 4615.03 m
+-132.51 0 -249.26 -30.5 -350.24 -91.5 c
+-120.01 -72.5 -180.01 -170.77 -180.01 -294.75 c
+0 -13.51 0.74 -27.51 2.26 -42.01 c
+7.97 -76.5 42.98 -134.24 105 -173.24 c
+53.5 -34.01 121 -51 202.5 -51 c
+149.01 0 267.75 57.86 356.25 173.61 c
+-51.77 -164.24 426.01 0 195.76 626.25 p
+-169.51 11.25 -404.76 16.88 -705.76 16.88 c
+f
+0 255 r6
+5730.66 4384.29 m
+-22.5 -58.8 -50.01 -109.87 -82.5 -153.2 c
+-45.49 -60.29 -92.25 -90.44 -140.24 -90.44 c
+-35.01 0 -52.5 23.91 -52.5 71.75 c
+0 38.85 12.25 82.94 36.74 132.27 c
+37.5 75.24 91.23 112.86 161.25 112.86 c
+105.76 0 -28.51 -73.24 h
+5534.17 4615.03 m
+-132.51 0 -249.26 -30.5 -350.24 -91.5 c
+-120.01 -72.5 -180.01 -170.77 -180.01 -294.75 c
+0 -13.51 0.74 -27.51 2.26 -42.01 c
+7.97 -76.5 42.98 -134.24 105 -173.24 c
+53.5 -34.01 121 -51 202.5 -51 c
+149.01 0 267.75 57.86 356.25 173.61 c
+-51.77 -164.24 426.01 0 195.76 626.25 p
+-169.51 11.25 -404.76 16.88 -705.76 16.88 c
+h
+S
+K
+4646.58 5083.44 -297.33 668.31 -574.48 -685.34 202.9 3.96 -315.85 -1098.47 436.5 0 23.23 59.24 P
+50.51 -49.51 136.76 -74.24 258.75 -74.24 c
+132.01 0 248 31.94 348.02 95.83 c
+115.48 73.89 173.26 173.21 173.26 298.01 c
+0 13.95 -0.76 28.19 -2.26 42.66 c
+-15.5 147.74 -141 221.63 -376.49 221.63 c
+-63.02 0 -138.78 -10.64 -227.26 -31.88 c
+123.99 490.32 227.02 9.97 h
+4440.33 4301.96 m
+-48.02 -126.3 -109.01 -189.43 -182.99 -189.43 c
+-26.51 0 -49.01 3.69 -67.53 11.13 c
+-11.01 5.45 -22 10.9 -32.99 16.35 c
+16.5 45.32 p
+35.97 100.05 70.48 166.67 103.5 199.87 c
+28.01 28.21 68 42.33 120 42.33 c
+90.77 0 -47.26 -125.57 p f
+0 255 r6
+4646.58 5083.44 -297.33 668.31 -574.48 -685.34 202.9 3.96 -315.85 -1098.47 436.5 0 23.23 59.24 P
+50.51 -49.51 136.76 -74.24 258.75 -74.24 c
+132.01 0 248 31.94 348.02 95.83 c
+115.48 73.89 173.26 173.21 173.26 298.01 c
+0 13.95 -0.76 28.19 -2.26 42.66 c
+-15.5 147.74 -141 221.63 -376.49 221.63 c
+-63.02 0 -138.78 -10.64 -227.26 -31.88 c
+123.99 490.32 227.02 9.97 h
+4440.33 4301.96 m
+-48.02 -126.3 -109.01 -189.43 -182.99 -189.43 c
+-26.51 0 -49.01 3.69 -67.53 11.13 c
+-11.01 5.45 -22 10.9 -32.99 16.35 c
+16.5 45.32 p
+35.97 100.05 70.48 166.67 103.5 199.87 c
+28.01 28.21 68 42.33 120 42.33 c
+90.77 0 -47.26 -125.57 h
+S
+K
+3613.46 4447.95 m
+-12.01 112.61 -97.53 168.95 -256.52 168.95 c
+-199.51 0 -348.49 -20.01 -446.98 -60 c
+-56.51 39.99 -147.01 60 -271.5 60 c
+-204.52 0 -428.26 -5.77 -671.25 -17.25 c
+-196.49 -627.75 436.49 0 23.27 62.26 p
+73.47 195 138.72 313.74 195.73 356.25 c
+32.99 24.99 77.49 37.5 133.5 37.5 c
+-19.01 -46.52 -33.25 -85.52 -42.74 -117.01 c
+-107.26 -339 442.5 0 24 62.26 p
+45.47 115.99 77.22 192.74 95.24 230.24 c
+30.5 62.49 60.24 104.51 89.24 126.01 c
+32.99 24.99 77.49 37.5 133.51 37.5 c
+-19.02 -46.52 -33.25 -85.52 -42.75 -117.01 c
+-292.57 -917.2 -223.62 3.05 297.33 -668.31 543.99 656.81 -177.1 2.42 296 923.64 p
+15.99 50.53 21.97 96.09 17.98 136.64 c
+f
+0 255 r6
+3613.46 4447.95 m
+-12.01 112.61 -97.53 168.95 -256.52 168.95 c
+-199.51 0 -348.49 -20.01 -446.98 -60 c
+-56.51 39.99 -147.01 60 -271.5 60 c
+-204.52 0 -428.26 -5.77 -671.25 -17.25 c
+-196.49 -627.75 436.49 0 23.27 62.26 p
+73.47 195 138.72 313.74 195.73 356.25 c
+32.99 24.99 77.49 37.5 133.5 37.5 c
+-19.01 -46.52 -33.25 -85.52 -42.74 -117.01 c
+-107.26 -339 442.5 0 24 62.26 p
+45.47 115.99 77.22 192.74 95.24 230.24 c
+30.5 62.49 60.24 104.51 89.24 126.01 c
+32.99 24.99 77.49 37.5 133.51 37.5 c
+-19.02 -46.52 -33.25 -85.52 -42.75 -117.01 c
+-292.57 -917.2 -223.62 3.05 297.33 -668.31 543.99 656.81 -177.1 2.42 296 923.64 p
+15.99 50.53 21.97 96.09 17.98 136.64 c
+h
+S
+cleartomark end showpage pagesave restore
+%%PageTrailer
+%%Trailer
+%%Pages: 1
+%%EOF
diff --git a/docs/textdocs/outdated/NTDOMAIN.txt b/docs/textdocs/outdated/NTDOMAIN.txt
new file mode 100644
index 00000000000..8408acb979a
--- /dev/null
+++ b/docs/textdocs/outdated/NTDOMAIN.txt
@@ -0,0 +1,51 @@
+!==
+!== NTDOMAIN.txt for Samba release 2.0.4 18 May 1999
+!==
+Contributor: Luke Kenneth Casson Leighton (samba-bugs@samba.org)
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+Created: October 20, 1997
+Updated: February 25, 1999 (Jerry Carter)
+
+Subject: NT Domain Logons
+===========================================================================
+
+As of 1.9.18alpha1, Samba supports logins for NT 3.51 and 4.0 Workstations,
+without the need, use or intervention of NT Server. This document describes
+how to set this up. Over the continued development of the 1.9.18alpha
+series, this process (and therefore this document) should become simpler.
+
+One useful thing to do is to get this version of Samba up and running
+with Win95 profiles, as you would for the current stable version of
+Samba (currently at 1.9.17p4), and is fully documented. You will need
+to set up encrypted passwords. Even if you don't have any Win95 machines,
+using your Samba Server to store the profile for one of your NT Workstation
+users is a good test that you have 1.9.18alpha1 correctly configured *prior*
+to attempting NT Domain Logons.
+
+The support is still experimental, so should be used at your own risk.
+
+NT is not as robust as you might have been led to believe: during the
+development of the Domain Logon Support, one person reported having to
+reinstall NT from scratch: their workstation had become totally unuseable.
+
+[further reports on ntsec@iss.net by independent administrators showing
+ similar symptoms lead us to believe that the SAM database file may be
+ corruptible. this _is_ recoverable (or, at least the machine is accessible),
+ by deleting the SAM file, under which circumstances all user account details
+ are lost, but at least the Administrator can log in with a blank password.
+ this is *not* possible except if the NT system is installed in a FAT
+ partition.]
+
+This *has* been reported to the NTBUGTRAQ@LISTSERV.NTBUGTRAQ.COM digest.
+
+==========================================================================
+Please note that Samba 2.0 does not **officially** support domain logons
+for Windows NT clients. Of course, domain logon support for Windows 9x
+clients is complete and official. These are two different issues.
+
+Samba's capability to act as a Primary Domain Controller for Windows NT
+domains is not advertised as it is not completed yet. For more information
+regarding how to obtain the latest development (HEAD branch) source code
+and what features are available, please refer to the NT Domain FAQ on-line
+at the Samba web site under the documentation page.
+
diff --git a/docs/textdocs/outdated/PRINTER_DRIVER.txt b/docs/textdocs/outdated/PRINTER_DRIVER.txt
new file mode 100644
index 00000000000..5bf82e0cfe4
--- /dev/null
+++ b/docs/textdocs/outdated/PRINTER_DRIVER.txt
@@ -0,0 +1,240 @@
+!==
+!== PRINTER_DRIVER.txt for Samba release 2.0.4 18 May 1999
+!==
+==========================================================================
+ Supporting the famous PRINTER$ share
+
+ Jean-Francois.Micouleau@utc.fr, 10/26/97
+ modified by herb@sgi.com 1/2/98
+
+===========================================================================
+
+Disclaimer:
+
+ This ONLY works with Windows 95
+ It does NOT work with Windows NT 4
+
+
+Goal:
+
+ When you click on a samba shared printer, you can now install the driver
+ automatically onto the Windows 95 machine, as you would from an NT server.
+
+How To:
+
+ It's a three step config.
+
+ First, create a new directory, where you will put the driver files, and
+ make a share in smb.conf pointing to it.
+
+ Example:
+
+ [printer$]
+ path=/usr/local/samba/printer
+ public=yes
+ writable=no
+ browseable=yes
+
+ Second, you have to build the list of drivers required for a specific
+ printer. This is the most complicated thing to do. Get the files
+ 'msprint.inf' and 'msprint2.inf' from Windows 95, the easiest way is to
+ grab them from a working Windows 95 computer. They are usually located
+ in 'c:\windows\inf'. Look in them for the printer you have. Run the new
+ program 'make_printerdef' with the file name and the printer name as
+ parameters. If you have drivers for an unsupported or updated printer,
+ first install these drivers on an Windows 95 system. There will be a
+ file created in your inf directory named 'oem?.inf' (where the ? is some
+ number). Use this file instead of msprint.inf.
+
+ Example: (from the /usr/local/samba/lib directory)
+
+ make_printerdef msprint.inf "Apple LaserWriter" >> printers.def
+
+ The program will print out a list of required files to stderr.
+ Copy all the files listed into the directory you created in step 1.
+ If you have "preserve case = yes" make sure your files names match
+ EXACTLY the names listed.
+
+ Third, you need to add 2 new parameters in smb.conf. One is in the
+ [global] section, called 'printer driver file' pointing to the printer
+ description file you just created, and the other in each printer share,
+ called 'printer driver location' pointing to where the client will get
+ the drivers. Don't forget to set correctly the printer driver parameter
+ to the Windows printer name.
+
+ Example:
+
+ [global]
+ printer driver file=/usr/local/samba/lib/printers.def
+
+ [lp]
+ comment = My old printer laser
+ browseable = yes
+ printable = yes
+ public = yes
+ writable = no
+ create mode = 0700
+ printer driver=Apple LaserWriter
+ printer driver location=\\%h\PRINTER$
+
+ %h will expand to the computer name, and PRINTER$ is the name of the
+ share created in step one.
+
+
+If it doesn't work for you, don't send flame ! It worked for me. In case of
+trouble don't hesitate to send me a mail with your smb.conf file and
+printers.def
+
+
+******* added by herb@sgi.com
+
+For those of you who like to know the details, and in case I have guessed
+wrong on some of the fields - The following is the format of the entries
+in the printers.def file: (entries are 1 single line - they are split here
+for readability)
+
+<Long Printer Name>:<Driver File Name>:<Data File Name>:<Help File Name>:
+<Language Monitor Name>:<Default Data Type>:<Comma Separated list of Files>
+
+The <Help File Name> and the <Language Monitor Name> can be empty.
+If no <Driver File Name> or <Data File Name> are specified in the inf file,
+these will default to the section name for the printer.
+
+The following is an excerpt from the MSPRINT2.INF file on a WIN95 machine.
+I have deleted all but the entries relating to installing a driver for the
+"QMS ColorScript 100 Model 30" printer. Using this "file" I'll try to
+explain how the printers.def file is created.
+
+make_printerdef is run with the first argument being the name of this
+file (MSPRINT2.INF in this case) and the second argument being the
+name of the printer ("QMS ColorScript 100 Model 30" in this case).
+
+The printer name is first found in the "Model section" to obtain the
+name of the "Installer Section" (this is the name after the equal sign).
+We ignore the alternate name.
+
+The "Installer Section" contains entries for "CopyFiles" and "DataSection".
+The "CopyFiles" line gives a list of all the required files for this
+printer. If the name begins with an @ it is the name of a file (after
+you strip off the @), otherwise it is the name of a "Copy Section" which
+in turn is a list of files required. This printer has one file listed
+"QCS30503.SPD" and two sections "COLOR_QMS_100_30" and "PSCRIPT". The
+"COLOR_QMS_100_30" section is listed in the "[DestinationDirs]" as
+having a value of 23. This means that all files listed in this section
+should go into the "color" subdirectory. The list of files to copy for
+this printer is thus:
+
+QCS30503.SPD,color\QMS10030.ICM,PSCRIPT.DRV,PSCRIPT.HLP,PSCRIPT.INI,
+TESTPS.TXT,APPLE380.SPD,FONTS.MFM,ICONLIB.DLL,PSMON.DLL
+
+From the "Data Section" we obtain values for "DriverFile", "HelpFile",
+and "LanguageMonitor". The % around the value for "LanguageMonitor"
+indicates that it is a string that can be localized so its actual value
+is obtained from the "[Strings]" section. The "Data Section" could also
+have contained an entry for "DefaultDataType".
+
+Using the information we have obtained we can now construct the entry
+for the printers.def file.
+
+<Long Printer Name> -> QMS ColorScript 100 Model 30 (name given
+ on the command line)
+<Driver File Name> -> PSCRIPT.DRV (given in Data Section)
+<Data File Name> -> QCS30503.SPD (defaults to Install Section name)
+<Help File Name> -> PSCRIPT.HLP (given in Data Section)
+<Language Monitor Name> -> PostScript Language Monitor (given in Data Section)
+<Default Data Type> -> RAW (default if not specified)
+
+
+So.... the enty (actually one line but split here for readability) would
+be:
+
+QMS ColorScript 100 Model 30:PSCRIPT.DRV:QCS30503.SPD:
+PSCRIPT.HLP:PostScript Language Monitor:RAW:
+QCS30503.SPD,color\QMS10030.ICM,PSCRIPT.DRV,PSCRIPT.HLP,PSCRIPT.INI,
+TESTPS.TXT,APPLE380.SPD,FONTS.MFM,ICONLIB.DLL,PSMON.DLL
+
+---------------------- Info from MSPRINT2.INF ------------------------
+;
+; The Manufacturer section lists all of the manufacturers that we will
+; display in the Dialog box
+
+[Manufacturer]
+"QMS"
+
+
+;
+; Model sections. Each section here corresponds with an entry listed in the
+; [Manufacturer] section, above. The models will be displayed in the order
+; that they appear in the INF file.
+;
+; Each model lists a variation of its own name as a compatible ID. This
+; is done primarily as an optimization during upgrade.
+;
+[QMS]
+"QMS ColorScript 100 Model 30" = QCS30503.SPD,QMS_ColorScript_100_Model_30
+
+
+;
+; Installer Sections
+;
+; These sections control file installation, and reference all files that
+; need to be copied. The section name will be assumed to be the driver
+; file, unless there is an explicit DriverFile section listed.
+;
+[QCS30503.SPD]
+CopyFiles=@QCS30503.SPD,COLOR_QMS_100_30,PSCRIPT
+DataSection=PSCRIPT_DATA
+
+; Copy Sections
+;
+; Lists of files that are actually copied. These sections are referenced
+; from the installer sections, above. Only create a section if it contains
+; two or more files (if we only copy a single file, identify it in the
+; installer section, using the @filename notation) or if it's a color
+; profile (since the DestinationDirs can only handle sections, and not
+; individual files).
+;
+[COLOR_QMS_100_30]
+QMS10030.ICM
+
+[PSCRIPT]
+PSCRIPT.DRV
+PSCRIPT.HLP
+PSCRIPT.INI
+TESTPS.TXT
+APPLE380.SPD
+FONTS.MFM
+ICONLIB.DLL
+PSMON.DLL
+
+
+;
+; Data Sections
+;
+; These sections contain data that is shared between devices.
+;
+[PSCRIPT_DATA]
+DriverFile=PSCRIPT.DRV
+HelpFile=PSCRIPT.HLP
+LanguageMonitor=%PS_MONITOR%
+
+
+;
+; Color profiles go to the colors directory. All other files go to the
+; system directory
+;
+
+[DestinationDirs]
+DefaultDestDir=11
+COLOR_QMS_100_30=23
+COLOR_TEKTRONIX_200I=23
+COLOR_TEKTRONIX_III_PXI=23
+
+
+;
+; Localizable Strings
+;
+[Strings]
+MS="Microsoft"
+PS_MONITOR="PostScript Language Monitor,PSMON.DLL"
+
diff --git a/docs/textdocs/PROJECTS b/docs/textdocs/outdated/PROJECTS
index cf903f2c6dd..3008bea430d 100644
--- a/docs/textdocs/PROJECTS
+++ b/docs/textdocs/outdated/PROJECTS
@@ -14,35 +14,37 @@ then please let me know! Also, if you are listed below and you have
any corrections or updates then please let me know.
Email contact:
-samba-bugs@anu.edu.au
+samba-bugs@samba.org
========================================================================
Documentation and FAQ
Docs and FAQ files for the Samba suite of software.
-Contact Karl.Auer@anu.edu.au
+Contact samba-bugs@samba.org with the diffs. These are urgently
+required.
-Mark Preston is now working on a set of formatted docs for Samba.
-Contact mpreston@sghms.ac.uk
+The FAQ is being added to on an ad hoc basis, see the web pages for info.
-Docs are currently up to date with version, 1.7.07. FAQ being added to
-as questions arise.
+Mark Preston was working on a set of formatted docs for Samba. Is this
+still happening? Contact mpreston@sghms.ac.uk
-Status last updated 27th September 1994
+Status last updated 2nd October 1996
========================================================================
========================================================================
Netbeui support
-This aims to produce patches so that Samba can be used with clients
+This aimed to produce patches so that Samba can be used with clients
that do not have TCP/IP. It will try to remain as portable as possible.
-
-Contact Brian.Onn@Canada.Sun.COM (Brian Onn)
-
-The project is just startup up.
-
-Status last updated 4th October 1994
+Contact Brian.Onn@Canada.Sun.COM (Brian Onn) Unfortunately it died, and
+although a lot of people have expressed interest nobody has come forward
+to do it. The Novell port (see Samba web pages) includes NetBEUI
+functionality in a proprietrary library which should still be helpful as
+we have the interfaces. Alan Cox (a.cox@li.org) has the information
+required to write the state machine if someone is going to do the work.
+
+Status last updated 2nd October 1996
========================================================================
========================================================================
@@ -52,21 +54,11 @@ A mountable smb filesystem for Linux using the userfs userspace filesystem
Contact lendecke@namu01.gwdg.de (Volker Lendecke)
-Currently this is at version 0.2. It works but is really only for
-people with some knowledge and experience of Linux kernel hacking.
-
-Status last updated 23rd August 1994
-========================================================================
-
-========================================================================
-Nmbd
-
-Aims to produce a complete rfc1001/1002 implementation. The current
-nmbd is a partial implementation.
-
-Contact Fabrice Cetre (cetre@ifhpserv.insa-lyon.fr)
+This works really well, and is measurably more efficient than commercial
+client software. It is now part of the Linux kernel. Long filename support
+is in use.
-Status last updated 23rd August 1994
+Status last updated June 1997
========================================================================
========================================================================
diff --git a/docs/textdocs/security_level.txt b/docs/textdocs/security_level.txt
new file mode 100644
index 00000000000..f4e0df7139c
--- /dev/null
+++ b/docs/textdocs/security_level.txt
@@ -0,0 +1,100 @@
+Contributor: Andrew Tridgell
+Updated: June 27, 1997
+Status: Current
+
+Subject: Description of SMB security levels.
+===========================================================================
+
+Samba supports the following options to the global smb.conf parameter
+"security =":
+ share, user, server
+
+Note: Samba-2.0.0 now adds the "domain" security mode. Please refer to
+the smb.conf man page for usage information and to the document
+docs/textdocs/DOMAIN_MEMBER.txt for further background details.
+
+Of the above, "security = server" means that Samba reports to clients that
+it is running in "user mode" but actually passes off all authentication
+requests to another "user mode" server. This requires an additional
+parameter "password server =" that points to the real authentication server.
+That real authentication server can be another Samba server or can be a
+Windows NT server, the later natively capable of encrypted password support.
+
+Below is a more complete description of security levels.
+===========================================================================
+
+A SMB server tells the client at startup what "security level" it is
+running. There are two options "share level" and "user level". Which
+of these two the client receives affects the way the client then tries
+to authenticate itself. It does not directly affect (to any great
+extent) the way the Samba server does security. I know this is
+strange, but it fits in with the client/server approach of SMB. In SMB
+everything is initiated and controlled by the client, and the server
+can only tell the client what is available and whether an action is
+allowed.
+
+I'll describe user level security first, as its simpler. In user level
+security the client will send a "session setup" command directly after
+the protocol negotiation. This contains a username and password. The
+server can either accept or reject that username/password
+combination. Note that at this stage the server has no idea what
+share the client will eventually try to connect to, so it can't base
+the "accept/reject" on anything other than:
+
+- the username/password
+- the machine that the client is coming from
+
+If the server accepts the username/password then the client expects to
+be able to mount any share (using a "tree connection") without
+specifying a password. It expects that all access rights will be as
+the username/password specified in the "session setup".
+
+It is also possible for a client to send multiple "session setup"
+requests. When the server responds it gives the client a "uid" to use
+as an authentication tag for that username/password. The client can
+maintain multiple authentication contexts in this way (WinDD is an
+example of an application that does this)
+
+
+Ok, now for share level security. In share level security the client
+authenticates itself separately for each share. It will send a
+password along with each "tree connection" (share mount). It does not
+explicitly send a username with this operation. The client is
+expecting a password to be associated with each share, independent of
+the user. This means that samba has to work out what username the
+client probably wants to use. It is never explicitly sent the
+username. Some commercial SMB servers such as NT actually associate
+passwords directly with shares in share level security, but samba
+always uses the unix authentication scheme where it is a
+username/password that is authenticated, not a "share/password".
+
+Many clients send a "session setup" even if the server is in share
+level security. They normally send a valid username but no
+password. Samba records this username in a list of "possible
+usernames". When the client then does a "tree connection" it also adds
+to this list the name of the share they try to connect to (useful for
+home directories) and any users listed in the "user =" smb.conf
+line. The password is then checked in turn against these "possible
+usernames". If a match is found then the client is authenticated as
+that user.
+
+Finally "server level" security. In server level security the samba
+server reports to the client that it is in user level security. The
+client then does a "session setup" as described earlier. The samba
+server takes the username/password that the client sends and attempts
+to login to the "password server" by sending exactly the same
+username/password that it got from the client. If that server is in
+user level security and accepts the password then samba accepts the
+clients connection. This allows the samba server to use another SMB
+server as the "password server".
+
+You should also note that at the very start of all this, where the
+server tells the client what security level it is in, it also tells
+the client if it supports encryption. If it does then it supplies the
+client with a random "cryptkey". The client will then send all
+passwords in encrypted form. You have to compile samba with encryption
+enabled to support this feature, and you have to maintain a separate
+smbpasswd file with SMB style encrypted passwords. It is
+cryptographically impossible to translate from unix style encryption
+to SMB style encryption, although there are some fairly simple management
+schemes by which the two could be kept in sync.
diff --git a/docs/yodldocs/README-NOW b/docs/yodldocs/README-NOW
new file mode 100644
index 00000000000..592d38c1351
--- /dev/null
+++ b/docs/yodldocs/README-NOW
@@ -0,0 +1,14 @@
+!==
+!== Notice of change of documentation format
+!==
+
+Samba is no longer using yodl as the source markup
+language for our documentation. As of release 2.2.0,
+we are using DocBook V4.1 exclusively (assuming you are not
+counting the ASCII files yet to be converted).
+
+Please see ../docbook/docbook.txt for more information
+on this.
+
+jerry carter
+SAMBA Team
diff --git a/examples/README b/examples/README
index 3e58e0faf1c..ba47cf912f7 100644
--- a/examples/README
+++ b/examples/README
@@ -1,6 +1,11 @@
-This directory contains example config files for Samba. If you have an
-interesting config file, then please send it in for inclusion in the
-package.
+Copyright(C) Samba-Team 1993-1997
+
+This directory contains example config files and related material for
+Samba.
+
+At a minimum please refer to the smb.conf.default file for current
+information regarding global and share parameter settings.
+
+Send additions to: samba-bugs@samba.org
-Send it to: Andrew.Tridgell@anu.edu.au
diff --git a/examples/VFS/.cvsignore b/examples/VFS/.cvsignore
new file mode 100644
index 00000000000..0b0923a496a
--- /dev/null
+++ b/examples/VFS/.cvsignore
@@ -0,0 +1,2 @@
+.libs
+*.so
diff --git a/examples/VFS/Makefile b/examples/VFS/Makefile
new file mode 100644
index 00000000000..581e1a06fb5
--- /dev/null
+++ b/examples/VFS/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for samba-vfs examples
+#
+# $Id: Makefile,v 1.4 2000/11/06 20:01:03 jra Exp $
+#
+
+# Variables
+
+CC = gcc
+LIBTOOL = libtool
+
+SAMBA_SRC = ../../source
+SAMBA_INCL = ../../source/include
+UBIQX_SRC = ../../source/ubiqx
+SMBWR_SRC = ../../source/smbwrapper
+CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -Wall -g
+VFS_OBJS = audit.so skel.so
+
+# Default target
+
+default: $(VFS_OBJS)
+
+# Pattern rules
+
+%.so: %.lo
+ $(LIBTOOL) $(CC) -shared -o $@ $< $(LDFLAGS)
+
+%.lo: %.c
+ $(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+# Misc targets
+
+clean:
+ rm -rf .libs
+ rm -f core *~ *% *.bak \
+ $(VFS_OBJS) $(VFS_OBJS:.so=.o) $(VFS_OBJS:.so=.lo)
diff --git a/examples/VFS/README b/examples/VFS/README
new file mode 100644
index 00000000000..c2f39f9727d
--- /dev/null
+++ b/examples/VFS/README
@@ -0,0 +1,35 @@
+README for Samba Virtual File System (VFS) Examples
+===================================================
+
+This directory contains some sample code to demonstrate VFS
+construction. The following VFS modules are given:
+
+ skel
+ A skeleton VFS module. When used, this module simply
+ passes all requests back to the disk functions (i.e it
+ operates as a passthrough filter). It should be
+ useful as a starting point for developing new VFS
+ modules.
+
+ audit
+ A simple module to audit file access to the syslog
+ facility. The following operations are logged: share
+ connect/disconnect, directory opens/create/remove,
+ file open/close/rename/unlink/chmod.
+
+The libtool program, available from your favourite GNU software
+archive, is required to compile these programs.
+
+To use the VFS modules, create a share similar to the one below. The
+important parameter is the 'vfs object' parameter which must point to
+the exact pathname of the shared library object.
+
+ [audit]
+ comment = Audited /data directory
+ path = /data
+ vfs object = /path/to/audit.so
+ writeable = yes
+ browseable = yes
+
+Further documentation on writing VFS modules for Samba can be found in
+docs directory of the Samba source distribution.
diff --git a/examples/VFS/audit.c b/examples/VFS/audit.c
new file mode 100644
index 00000000000..7fbcb97837e
--- /dev/null
+++ b/examples/VFS/audit.c
@@ -0,0 +1,196 @@
+/*
+ * Auditing VFS module for samba. Log selected file operations to syslog
+ * facility.
+ *
+ * Copyright (C) Tim Potter, 1999-2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <syslog.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <includes.h>
+#include <vfs.h>
+
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_USER
+#endif
+
+#ifndef SYSLOG_PRIORITY
+#define SYSLOG_PRIORITY LOG_NOTICE
+#endif
+
+static struct vfs_ops default_vfs_ops;
+
+/* Implementation of vfs_ops. Pass everything on to the default
+ operation but log event first. */
+
+static int audit_connect(struct connection_struct *conn, const char *svc,
+ const char *user)
+{
+ syslog(SYSLOG_PRIORITY, "connect to service %s by user %s\n",
+ svc, user);
+
+ return 0; /* Success */
+}
+
+static void audit_disconnect(struct connection_struct *conn)
+{
+ syslog(SYSLOG_PRIORITY, "disconnected\n");
+}
+
+static DIR *audit_opendir(struct connection_struct *conn, const char *fname)
+{
+ DIR *result = default_vfs_ops.opendir(conn, fname);
+
+ syslog(SYSLOG_PRIORITY, "opendir %s %s%s\n",
+ fname,
+ (result == NULL) ? "failed: " : "",
+ (result == NULL) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_mkdir(struct connection_struct *conn, const char *path,
+ mode_t mode)
+{
+ int result = default_vfs_ops.mkdir(conn, path, mode);
+
+ syslog(SYSLOG_PRIORITY, "mkdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_rmdir(struct connection_struct *conn, const char *path)
+{
+ int result = default_vfs_ops.rmdir(conn, path);
+
+ syslog(SYSLOG_PRIORITY, "rmdir %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_open(struct connection_struct *conn, const char *fname,
+ int flags, mode_t mode)
+{
+ int result = default_vfs_ops.open(conn, fname, flags, mode);
+
+ syslog(SYSLOG_PRIORITY, "open %s (fd %d) %s%s%s\n",
+ fname, result,
+ ((flags & O_WRONLY) || (flags & O_RDWR)) ? "for writing " : "",
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_close(struct files_struct *fsp, int fd)
+{
+ int result = default_vfs_ops.close(fsp, fd);
+
+ syslog(SYSLOG_PRIORITY, "close fd %d %s%s\n",
+ fd,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_rename(struct connection_struct *conn, const char *old,
+ const char *new)
+{
+ int result = default_vfs_ops.rename(conn, old, new);
+
+ syslog(SYSLOG_PRIORITY, "rename %s -> %s %s%s\n",
+ old, new,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_unlink(struct connection_struct *conn, const char *path)
+{
+ int result = default_vfs_ops.unlink(conn, path);
+
+ syslog(SYSLOG_PRIORITY, "unlink %s %s%s\n",
+ path,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+static int audit_chmod(struct connection_struct *conn, const char *path,
+ mode_t mode)
+{
+ int result = default_vfs_ops.chmod(conn, path, mode);
+
+ syslog(SYSLOG_PRIORITY, "chmod %s mode 0x%x %s%s\n",
+ path, mode,
+ (result < 0) ? "failed: " : "",
+ (result < 0) ? strerror(errno) : "");
+
+ return result;
+}
+
+/* VFS initialisation function. Return initialised vfs_ops structure
+ back to SAMBA. */
+
+struct vfs_ops *vfs_init(int *vfs_version, struct vfs_ops *ops)
+{
+ *vfs_version = SMB_VFS_INTERFACE_VERSION;
+
+ openlog("smbd_audit", LOG_PID, SYSLOG_FACILITY);
+ syslog(SYSLOG_PRIORITY, "initialised\n");
+
+ /* Save a copy of the default ops */
+
+ default_vfs_ops = *ops;
+
+ /* Override our ones */
+
+ ops->connect = audit_connect;
+ ops->disconnect = audit_disconnect;
+ ops->opendir = audit_opendir;
+ ops->mkdir = audit_mkdir;
+ ops->rmdir = audit_rmdir;
+ ops->open = audit_open;
+ ops->close = audit_close;
+ ops->rename = audit_rename;
+ ops->unlink = audit_unlink;
+ ops->chmod = audit_chmod;
+
+ return(ops);
+}
diff --git a/examples/VFS/block/Makefile b/examples/VFS/block/Makefile
new file mode 100644
index 00000000000..dcc7c077936
--- /dev/null
+++ b/examples/VFS/block/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for samba-vfs examples
+#
+#
+
+# Variables
+
+CC = gcc
+LIBTOOL = libtool
+
+SAMBA_SRC = /usr/local/src/samba/samba-2.2.0-ron/source
+SAMBA_INCL = ${SAMBA_SRC}/include
+UBIQX_SRC = ${SAMBA_SRC}/ubiqx
+SMBWR_SRC = ${SAMBA_SRC}/smbwrapper
+CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -Wall -g -D_LARGEFILE63_SOURCE -D_GNU_SOURCE -fno-builtin
+
+
+VFS_OBJS = block.so
+
+# Default target
+
+default: $(VFS_OBJS)
+
+# Pattern rules
+
+%.so: %.lo
+ $(LIBTOOL) $(CC) -shared -o $@ $< $(LDFLAGS)
+
+%.lo: %.c
+ $(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+# Misc targets
+
+clean:
+ rm -rf .libs
+ rm -f core *~ *% *.bak \
+ $(VFS_OBJS) $(VFS_OBJS:.so=.o) $(VFS_OBJS:.so=.lo)
diff --git a/examples/VFS/block/block.c b/examples/VFS/block/block.c
new file mode 100644
index 00000000000..3c4f736e849
--- /dev/null
+++ b/examples/VFS/block/block.c
@@ -0,0 +1,546 @@
+/*
+ *
+ * Block access from links to dev mount points specified in PARAMCONF file
+ *
+ * Copyright (C) Ronald Kuetemeier, 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <syslog.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+
+#include <includes.h>
+#include <vfs.h>
+
+
+
+DIR *block_opendir(struct connection_struct *conn, char *fname);
+int block_connect(struct connection_struct *conn, char *service, char *user);
+void block_disconnect(struct connection_struct *conn);
+
+
+/* VFS operations */
+
+
+extern struct vfs_ops default_vfs_ops; /* For passthrough operation */
+
+struct vfs_ops execute_vfs_ops = {
+
+ /* Disk operations */
+
+ block_connect,
+ block_disconnect,
+ NULL, /* disk free */
+
+ /* Directory operations */
+
+ block_opendir,
+ NULL, /* readdir */
+ NULL,
+ NULL,
+ NULL, /* closedir */
+
+ /* File operations */
+
+ NULL,
+ NULL,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* lseek */
+ NULL,
+ NULL, /* fsync */
+ NULL, /* stat */
+ NULL, /* fstat */
+ NULL, /* lstat */
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* chown */
+ NULL,
+ NULL, /* chdir */
+ NULL, /* getwd */
+ NULL, /* utime */
+ NULL, /* ftruncate */
+ NULL, /* lock */
+ NULL, /* fget_nt_acl */
+ NULL, /* get_nt_acl */
+ NULL, /* fset_nt_acl */
+ NULL, /* set_nt_acl */
+ NULL,
+ NULL
+};
+
+
+#ifndef PARAMCONF
+#define PARAMCONF "/etc/samba-block.conf"
+#endif
+
+extern BOOL pm_process(char *FileName, BOOL (*sfunc)(char *), BOOL(*pfunc)(char * , char *));
+
+//functions
+
+BOOL enter_pblock_mount(char *dir);
+BOOL get_section(char *sect);
+BOOL get_parameter_value(char *param, char *value);
+BOOL load_param(void);
+BOOL search(struct stat *stat_buf);
+BOOL dir_search(char *link, char *dir);
+BOOL enter_pblock_dir(char *dir);
+
+
+
+typedef struct block_dir
+{
+ dev_t st_dev;
+ int str_len;
+ char *dir_name;
+ struct block_dir *next;
+} block_dir;
+
+
+static char *params[] = {"mount_point","dir_name"};
+enum { MOUNT_POINT , DIR_NAME };
+
+static struct block_dir *pblock_mountp = NULL;
+static struct block_dir *pblock_dir = NULL;
+
+
+
+/*
+ * Load the conf file into a table
+ */
+
+BOOL load_param(void)
+{
+
+ if ((pm_process(PARAMCONF,&get_section,&get_parameter_value)) == TRUE)
+ {
+ return TRUE;
+
+ }
+ return FALSE;
+}
+
+
+
+/*
+ * Enter the key and data into the list
+ *
+ */
+
+BOOL enter_pblock_mount(char *dir)
+{
+ struct stat stat_buf;
+ static struct block_dir *tmp_pblock;
+
+
+ if((stat(dir,&stat_buf)) != 0)
+ {
+ return FALSE;
+ }
+
+ if(pblock_mountp == NULL)
+ {
+ pblock_mountp = calloc(1, sizeof(block_dir));
+ if( pblock_mountp == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = pblock_mountp;
+ tmp_pblock->next = NULL;
+
+ }else
+ {
+ tmp_pblock->next = calloc(1, sizeof(block_dir));
+ if(tmp_pblock->next == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ tmp_pblock->next = NULL;
+
+ }
+
+
+ tmp_pblock->st_dev = stat_buf.st_dev;
+ tmp_pblock->dir_name = strdup(dir);
+
+
+ return TRUE;
+
+}
+
+
+/*
+ * Enter the key and data into the list
+ *
+ */
+
+BOOL enter_pblock_dir(char *dir)
+{
+ static struct block_dir *tmp_pblock;
+
+
+ if(pblock_dir == NULL)
+ {
+ pblock_dir = calloc(1, sizeof(block_dir));
+ if( pblock_dir == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = pblock_dir;
+ tmp_pblock->next = NULL;
+
+ }else
+ {
+ tmp_pblock->next = calloc(1, sizeof(block_dir));
+ if(tmp_pblock->next == NULL)
+ {
+ return FALSE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ tmp_pblock->next = NULL;
+
+ }
+
+
+ tmp_pblock->dir_name = strdup(dir);
+ tmp_pblock->str_len = strlen(dir);
+
+
+ return TRUE;
+
+}
+
+
+
+
+/*
+ * Function callback for config section names
+ */
+
+BOOL get_section(char *sect)
+{
+ return TRUE;
+}
+
+
+
+/*
+ * Function callback for config parameter value pairs
+ *
+ */
+
+BOOL get_parameter_value(char *param, char *value)
+{
+ int i = 0, maxargs = sizeof(params) / sizeof(char *);
+
+
+ for( i= 0; i < maxargs; i++)
+ {
+ if (strcmp(param,params[i]) == 0)
+ {
+ switch(i)
+ {
+ case MOUNT_POINT :
+ enter_pblock_mount(value);
+ break;
+ case DIR_NAME :
+ enter_pblock_dir(value);
+ break;
+ default :
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+/* VFS initialisation function. Return initialised vfs_ops structure
+ back to SAMBA. */
+
+struct vfs_ops *vfs_init(int *vfs_version)
+{
+ *vfs_version = SMB_VFS_INTERFACE_VERSION;
+
+ return(&execute_vfs_ops);
+}
+
+
+/*
+ * VFS connect and param file loading
+ */
+
+int block_connect(struct connection_struct *conn, char *service, char *user)
+{
+ if((load_param()) == FALSE)
+ {
+
+ return -1;
+
+ }
+
+ DEBUG(0,("%s connecting \n",conn->user));
+
+ return (default_vfs_ops.connect(conn, service,user));
+}
+
+/*
+ * Free allocated structures and disconnect
+ *
+ */
+
+
+void block_disconnect(struct connection_struct *conn)
+{
+
+ struct block_dir *tmp_pblock = (pblock_mountp == NULL ? pblock_dir : pblock_mountp);
+ struct block_dir *free_pblock = NULL;
+
+ while(tmp_pblock != NULL)
+ {
+ free(tmp_pblock->dir_name);
+ free_pblock = tmp_pblock;
+ tmp_pblock = tmp_pblock->next;
+ free(free_pblock);
+
+ if(tmp_pblock == NULL && pblock_dir != NULL)
+ {
+ tmp_pblock = (pblock_mountp == NULL ? pblock_dir : NULL);
+ pblock_dir = NULL;
+
+ }
+
+ }
+
+
+
+ default_vfs_ops.disconnect(conn);
+}
+
+/*
+ * VFS opendir
+ */
+
+DIR *block_opendir(struct connection_struct *conn, char *fname)
+{
+
+ char *dir_name = NULL;
+ struct stat stat_buf;
+
+ dir_name = alloca((strlen(conn->origpath) + strlen(fname) + 2) * sizeof(char));
+
+ pstrcpy(dir_name,conn->origpath);
+ pstrcat(dir_name, "/");
+ strncat(dir_name, fname, strcspn(fname,"/"));
+
+ if((lstat(dir_name,&stat_buf)) == 0)
+ {
+ if((S_ISLNK(stat_buf.st_mode)) == 1)
+ {
+ stat(dir_name,&stat_buf);
+ if((search(&stat_buf) || dir_search(dir_name, fname) ) == TRUE)
+ {
+ DEBUG(0,("%s used link to blocked dir: %s \n", conn->user, dir_name));
+ errno = EACCES;
+ return NULL;
+ }
+ }
+ }
+
+ return (default_vfs_ops.opendir(conn, fname));
+}
+
+
+/*
+ * Find mount point to block in list
+ */
+
+BOOL search(struct stat *stat_buf)
+{
+ struct block_dir *tmp_pblock = pblock_mountp;
+
+ while(tmp_pblock != NULL)
+ {
+
+ if(tmp_pblock->st_dev == stat_buf->st_dev)
+ {
+ return TRUE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ }
+
+ return FALSE;
+
+}
+
+/*
+ * Find dir in list to block id the starting point is link from a share
+ */
+
+BOOL dir_search(char *link, char *dir)
+{
+ char buf[PATH_MAX +1], *ext_path;
+ int len = 0;
+ struct block_dir *tmp_pblock = pblock_dir;
+
+ if((len = readlink(link,buf,sizeof(buf))) == -1)
+ {
+ return TRUE;
+
+ }else
+ {
+ buf[len] = '\0';
+ }
+
+
+ if((ext_path = strchr(dir,'/')) != NULL)
+ {
+ pstrcat(buf,&ext_path[1]);
+ len = strlen(buf);
+ }
+
+ while(tmp_pblock != NULL)
+ {
+ if(len < tmp_pblock->str_len)
+ {
+ tmp_pblock = tmp_pblock->next;
+ continue;
+ }
+
+ if((strstr(buf,tmp_pblock->dir_name)) != NULL)
+ {
+ return TRUE;
+ }
+ tmp_pblock = tmp_pblock->next;
+ }
+
+
+ return FALSE;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/VFS/block/samba-block.conf b/examples/VFS/block/samba-block.conf
new file mode 100644
index 00000000000..7a137980b73
--- /dev/null
+++ b/examples/VFS/block/samba-block.conf
@@ -0,0 +1,6 @@
+[ blocked ]
+mount_point = /
+mount_point = /boot
+mount_point = /proc
+dir_name = /usr/local/src/samba
+dir_name = /usr/bin
diff --git a/examples/VFS/block/smb.conf b/examples/VFS/block/smb.conf
new file mode 100644
index 00000000000..368155f1f83
--- /dev/null
+++ b/examples/VFS/block/smb.conf
@@ -0,0 +1,13 @@
+[homes]
+ comment = Home Directories
+ vfs object = /usr/local/samba/lib/block.so
+ browseable = yes
+ writable = yes
+
+
+
+
+
+
+
+
diff --git a/examples/VFS/skel.c b/examples/VFS/skel.c
new file mode 100644
index 00000000000..9bb84fe2b1c
--- /dev/null
+++ b/examples/VFS/skel.c
@@ -0,0 +1,297 @@
+/*
+ * Skeleton VFS module. Implements passthrough operation of all VFS
+ * calls to disk functions.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include <includes.h>
+#include <vfs.h>
+
+/* Function prototypes */
+
+ /* Disk operations */
+
+ int skel_connect(struct connection_struct *conn, char *service, char *user); void skel_disconnect(struct connection_struct *conn);
+ SMB_BIG_UINT skel_disk_free(struct connection_struct *conn, char *path, BOOL small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+
+ /* Directory operations */
+
+ DIR *skel_opendir(struct connection_struct *conn, char *fname);
+ struct dirent *skel_readdir(struct connection_struct *conn, DIR *dirp);
+ int skel_mkdir(struct connection_struct *conn, char *path, mode_t mode);
+ int skel_rmdir(struct connection_struct *conn, char *path);
+ int skel_closedir(struct connection_struct *conn, DIR *dir);
+
+ /* File operations */
+
+ int skel_open(struct connection_struct *conn, char *fname, int flags, mode_t mode);
+ int skel_close(struct files_struct *fsp, int fd);
+ ssize_t skel_read(struct files_struct *fsp, int fd, char *data, size_t n);
+ ssize_t skel_write(struct files_struct *fsp, int fd, char *data, size_t n);
+ SMB_OFF_T skel_lseek(struct files_struct *fsp, int filedes, SMB_OFF_T offset, int whence);
+ int skel_rename(struct connection_struct *conn, char *old, char *new);
+ int skel_fsync(struct files_struct *fsp, int fd);
+ int skel_stat(struct connection_struct *conn, char *fname, SMB_STRUCT_STAT *sbuf);
+ int skel_fstat(struct files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf);
+ int skel_lstat(struct connection_struct *conn, char *path, SMB_STRUCT_STAT *sbuf);
+ int skel_unlink(struct connection_struct *conn, char *path);
+ int skel_chmod(struct connection_struct *conn, char *path, mode_t mode);
+ int skel_chown(struct connection_struct *conn, char *path, uid_t uid, gid_t gid);
+ int skel_chdir(struct connection_struct *conn, char *path);
+ char *skel_getwd(struct connection_struct *conn, char *buf);
+ int skel_utime(struct connection_struct *conn, char *path, struct utimbuf *times);
+ int skel_ftruncate(struct files_struct *fsp, int fd, SMB_OFF_T offset);
+ BOOL skel_lock(struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+
+ /* NT file access control list operations */
+
+ size_t skel_fget_nt_acl(struct files_struct *fsp, int fd, struct security_descriptor_info **ppdesc);
+ size_t skel_get_nt_acl(struct files_struct *fsp, char *name, struct security_descriptor_info **ppdesc);
+ BOOL skel_fset_nt_acl(struct files_struct *fsp, int fd, uint32 security_info_sent, struct security_descriptor_info *psd);
+ BOOL skel_set_nt_acl(struct files_struct *fsp, char *name, uint32 security_info_sent, struct security_descriptor_info *psd);
+
+
+/* VFS operations structure */
+
+struct vfs_ops skel_ops = {
+
+ /* Disk operations */
+
+ skel_connect,
+ skel_disconnect,
+ skel_disk_free,
+
+ /* Directory operations */
+
+ skel_opendir,
+ skel_readdir,
+ skel_mkdir,
+ skel_rmdir,
+ skel_closedir,
+
+ /* File operations */
+
+ skel_open,
+ skel_close,
+ skel_read,
+ skel_write,
+ skel_lseek,
+ skel_rename,
+ skel_fsync,
+ skel_stat,
+ skel_fstat,
+ skel_lstat,
+ skel_unlink,
+ skel_chmod,
+ skel_chown,
+ skel_chdir,
+ skel_getwd,
+ skel_utime,
+ skel_ftruncate,
+ skel_lock,
+
+ /* NT File ACL operations */
+
+ skel_fget_nt_acl,
+ skel_get_nt_acl,
+ skel_fset_nt_acl,
+ skel_set_nt_acl
+};
+
+/* VFS initialisation - return vfs_ops function pointer structure */
+
+struct vfs_ops *vfs_init(int *vfs_version)
+{
+ *vfs_version = SMB_VFS_INTERFACE_VERSION;
+ return(&skel_ops);
+}
+
+/* Implementation of VFS functions. Insert your useful stuff here */
+
+extern struct vfs_ops default_vfs_ops; /* For passthrough operation */
+
+int skel_connect(struct connection_struct *conn, char *service, char *user)
+{
+ return default_vfs_ops.connect(conn, service, user);
+}
+
+void skel_disconnect(struct connection_struct *conn)
+{
+ default_vfs_ops.disconnect(conn);
+}
+
+SMB_BIG_UINT skel_disk_free(struct connection_struct *conn, char *path,
+ BOOL small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ return default_vfs_ops.disk_free(conn, path, small_query, bsize,
+ dfree, dsize);
+}
+
+DIR *skel_opendir(struct connection_struct *conn, char *fname)
+{
+ return default_vfs_ops.opendir(conn, fname);
+}
+
+struct dirent *skel_readdir(struct connection_struct *conn, DIR *dirp)
+{
+ return default_vfs_ops.readdir(conn, dirp);
+}
+
+int skel_mkdir(struct connection_struct *conn, char *path, mode_t mode)
+{
+ return default_vfs_ops.mkdir(conn, path, mode);
+}
+
+int skel_rmdir(struct connection_struct *conn, char *path)
+{
+ return default_vfs_ops.rmdir(conn, path);
+}
+
+int skel_closedir(struct connection_struct *conn, DIR *dir)
+{
+ return default_vfs_ops.closedir(conn, dir);
+}
+
+int skel_open(struct connection_struct *conn, char *fname, int flags, mode_t mode)
+{
+ return default_vfs_ops.open(conn, fname, flags, mode);
+}
+
+int skel_close(struct files_struct *fsp, int fd)
+{
+ return default_vfs_ops.close(fsp, fd);
+}
+
+ssize_t skel_read(struct files_struct *fsp, int fd, char *data, size_t n)
+{
+ return default_vfs_ops.read(fsp, fd, data, n);
+}
+
+ssize_t skel_write(struct files_struct *fsp, int fd, char *data, size_t n)
+{
+ return default_vfs_ops.write(fsp, fd, data, n);
+}
+
+SMB_OFF_T skel_lseek(struct files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
+{
+ return default_vfs_ops.lseek(fsp, filedes, offset, whence);
+}
+
+int skel_rename(struct connection_struct *conn, char *old, char *new)
+{
+ return default_vfs_ops.rename(conn, old, new);
+}
+
+int skel_fsync(struct files_struct *fsp, int fd)
+{
+ return default_vfs_ops.fsync(fsp, fd);
+}
+
+int skel_stat(struct connection_struct *conn, char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ return default_vfs_ops.stat(conn, fname, sbuf);
+}
+
+int skel_fstat(struct files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
+{
+ return default_vfs_ops.fstat(fsp, fd, sbuf);
+}
+
+int skel_lstat(struct connection_struct *conn, char *path, SMB_STRUCT_STAT *sbuf)
+{
+ return default_vfs_ops.lstat(conn, path, sbuf);
+}
+
+int skel_unlink(struct connection_struct *conn, char *path)
+{
+ return default_vfs_ops.unlink(conn, path);
+}
+
+int skel_chmod(struct connection_struct *conn, char *path, mode_t mode)
+{
+ return default_vfs_ops.chmod(conn, path, mode);
+}
+
+int skel_chown(struct connection_struct *conn, char *path, uid_t uid, gid_t gid)
+{
+ return default_vfs_ops.chown(conn, path, uid, gid);
+}
+
+int skel_chdir(struct connection_struct *conn, char *path)
+{
+ return default_vfs_ops.chdir(conn, path);
+}
+
+char *skel_getwd(struct connection_struct *conn, char *buf)
+{
+ return default_vfs_ops.getwd(conn, buf);
+}
+
+int skel_utime(struct connection_struct *conn, char *path, struct utimbuf *times)
+{
+ return default_vfs_ops.utime(conn, path, times);
+}
+
+int skel_ftruncate(struct files_struct *fsp, int fd, SMB_OFF_T offset)
+{
+ return default_vfs_ops.ftruncate(fsp, fd, offset);
+}
+
+BOOL skel_lock(struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ return default_vfs_ops.lock(fsp, fd, op, offset, count, type);
+}
+
+size_t skel_fget_nt_acl(struct files_struct *fsp, int fd, struct security_descriptor_info **ppdesc)
+{
+ return default_vfs_ops.fget_nt_acl(fsp, fd, ppdesc);
+}
+
+size_t skel_get_nt_acl(struct files_struct *fsp, char *name, struct security_descriptor_info **ppdesc)
+{
+ return default_vfs_ops.get_nt_acl(fsp, name, ppdesc);
+}
+
+BOOL skel_fset_nt_acl(struct files_struct *fsp, int fd, uint32 security_info_sent, struct security_descriptor_info *psd)
+{
+ return default_vfs_ops.fset_nt_acl(fsp, fd, security_info_sent, psd);
+}
+
+BOOL skel_set_nt_acl(struct files_struct *fsp, char *name, uint32 security_info_sent, struct security_descriptor_info *psd)
+{
+ return default_vfs_ops.set_nt_acl(fsp, name, security_info_sent, psd);
+}
+
diff --git a/examples/appliance/Makefile b/examples/appliance/Makefile
new file mode 100644
index 00000000000..c49451add86
--- /dev/null
+++ b/examples/appliance/Makefile
@@ -0,0 +1,68 @@
+PREFIX=/usr/local/samba
+CONFIGOPTS=--with-pam --prefix=$(PREFIX) --with-smbmount
+
+
+all: headb tngb
+
+config:
+ (cd head/source; CFLAGS="-Wall -O2 -g" ./configure $(CONFIGOPTS))
+ (cd tng; CFLAGS="-Wall -O2 -g" ./configure $(CONFIGOPTS) --enable-shared=no)
+
+headb:
+ (cd head/source; make)
+
+tngb:
+ (cd tng; make bin/samedit bin/winbindd nsswitch)
+
+clean:
+ (cd head/source; make clean)
+ (cd tng; make clean)
+
+proto:
+ (cd head/source; make proto)
+ (cd tng; make proto)
+
+distclean:
+ (cd head/source; make clean; rm -f config.cache; rm -f Makefile)
+ (cd tng; make clean; rm -f config.cache; rm -f Makefile)
+
+install: installhead installtng
+
+installbin: installheadbin installtng
+
+installhead:
+ (cd head/source; make install)
+
+installheadbin:
+ (cd head/source; make installbin)
+
+installtng: tngb
+ (cd tng; \
+ rm -f $(PREFIX)/bin/samedit $(PREFIX)/bin/winbindd; \
+ cp bin/samedit bin/winbindd $(PREFIX)/bin; \
+ rm -f /lib/libnss_winbind.so.2 /lib/security/pam_winbind.so; \
+ cp nsswitch/libnss_winbind.so /lib/libnss_winbind.so.2; \
+ cp nsswitch/pam_winbind.so /lib/security/)
+
+stop:
+ -killall winbindd smbd nmbd
+
+start:
+ $(PREFIX)/bin/smbd
+ $(PREFIX)/bin/nmbd
+ $(PREFIX)/bin/winbindd
+
+restart: stop start
+
+updatehead:
+ (cd head; cvs -z9 update -d)
+
+updatetng:
+ (cd tng; cvs -z9 update -d)
+
+update: updatehead updatetng
+
+checkout:
+ -mkdir head tng
+ (cd head ; cvs -z9 co samba; mv samba head)
+ (cd head ; cvs -z9 co -r SAMBA_TNG samba/source; mv source tng)
diff --git a/examples/appliance/README b/examples/appliance/README
new file mode 100644
index 00000000000..3c9028fd89a
--- /dev/null
+++ b/examples/appliance/README
@@ -0,0 +1,52 @@
+This directory provides build tools for building a Samba based domain
+appliance.
+
+A appliance is a box that gets its username and group database from a
+domain controller, and does its authentication via a domain
+controller. Right now this is only supported by combining two CVS
+branches of Samba, which is what the files in this directory do.
+
+SETUP
+-----
+
+To setup an appliance do the following:
+
+1) build and install Samba using the .spec file or Makefile in this
+ directory.
+
+2) setup winbindd by following the directions in the winbindd man
+ page.
+
+3) test winbindd, validating that domain users and groups are visible
+ and that domain authentication works, both using unix tools and
+ smbclient.
+
+for appliance printing support also do this:
+
+4) create a print$ share with write permission for print
+ administrators.
+
+4) create the "nt printer driver" directory (by default
+ /usr/local/samba/lib/ntprinters) and make it writable by print
+ adminisrators.
+
+5) populate your /etc/printcap printer database
+
+6) add printers using the NT "add printer wizard" in the Printers
+ network folder.
+
+
+PACKAGING
+---------
+
+- Checkout the Samba CVS head branch into a directory call
+ samba-appliance-0.2/head
+
+- Checkout the source subdirectory of the Samba CVS SAMBA_TNG branch
+ into a directory call samba-appliance-0.2/tng
+
+- Copy Makefile and smb.conf-appliance to samba-appliance-0.2/
+
+- run build.sh
+
+That should build source and binary RPMs in /usr/src/redhat/{RPMS,SRPMS}
diff --git a/examples/appliance/appliance.spec b/examples/appliance/appliance.spec
new file mode 100644
index 00000000000..6fb631b4e2f
--- /dev/null
+++ b/examples/appliance/appliance.spec
@@ -0,0 +1,389 @@
+Summary: Samba SMB client and server
+Name: samba-appliance
+Version: 0.2
+Release: 1
+Copyright: GNU GPL version 2
+Group: Networking
+Source: %{name}-%{version}-src.tar.gz
+Packager: John H Terpstra [Samba-Team] <jht@samba.org>
+Requires: pam >= 0.64
+Prereq: chkconfig fileutils
+BuildRoot: /var/tmp/samba
+Provides: winbind
+
+%define prefix /usr/local/samba
+
+%define tng_build_dir $RPM_BUILD_DIR/%{name}-%{version}/tng
+%define head_build_dir $RPM_BUILD_DIR/%{name}-%{version}/head
+
+%description
+Samba provides an SMB server which can be used to provide
+network services to SMB (sometimes called "Lan Manager")
+clients, including various versions of MS Windows, OS/2,
+and other Linux machines. Samba also provides some SMB
+clients, which complement the built-in SMB filesystem
+in Linux. Samba uses NetBIOS over TCP/IP (NetBT) protocols
+and does NOT need NetBEUI (Microsoft Raw NetBIOS frame)
+protocol.
+
+Samba-2 features an almost working NT Domain Control
+capability and includes the new SWAT (Samba Web Administration
+Tool) that allows samba's smb.conf file to be remotely managed
+using your favourite web browser. For the time being this is
+being enabled on TCP port 901 via inetd.
+
+Please refer to the WHATSNEW.txt document for fixup information.
+This binary release includes encrypted password support.
+Please read the smb.conf file and ENCRYPTION.txt in the
+docs directory for implementation details.
+
+NOTE: Red Hat Linux 5.X Uses PAM which has integrated support
+for Shadow passwords. Do NOT recompile with the SHADOW_PWD option
+enabled. Red Hat Linux has built in support for quotas in PAM.
+
+%changelog
+* Mon Jun 5 2000 Tim Potter <tpot@samba.org>
+ - Modified to use prefix=/usr/local/samba everywhere
+
+* Sat Nov 29 1999 Matthew Vanecek <mev0003@unt.edu>
+ - Added a Prefix and changed "/usr" to "%{prefix}"
+
+* Sat Nov 11 1999 Tridge <tridge@linuxcare.com>
+ - changed from mount.smb to mount.smbfs
+
+* Sat Oct 9 1999 Tridge <tridge@linuxcare.com>
+ - removed smbwrapper
+ - added smbmnt and smbmount
+
+* Sun Apr 25 1999 John H Terpstra <jht@samba.org>
+ - added smbsh.1 man page
+
+* Fri Mar 26 1999 Andrew Tridgell <tridge@samba.org>
+ - added --with-pam as pam is no longer used by default
+
+* Sat Jan 27 1999 Jeremy Allison <jra@samba.org>
+ - Removed smbrun binary and tidied up some loose ends
+
+* Sun Oct 25 1998 John H Terpstra <jht@samba.org>
+ - Added parameters to /config to ensure smb.conf, lmhosts,
+ and smbusers never gets over-written.
+
+* Sat Oct 24 1998 John H Terpstra <jht@samba.org>
+ - removed README.smbsh file from docs area
+
+* Mon Oct 05 1998 John H Terpstra <jht@samba.org>
+ - Added rpcclient to binaries list
+ - Added smbwrapper stuff
+
+* Fri Aug 21 1998 John H Terpstra <jht@samba.org>
+ - Updated for Samba version 2.0 building
+
+* Tue Jul 07 1998 Erik Troan <ewt@redhat.com>
+ - updated postun triggerscript to check $0
+ - clear /etc/codepages from %preun instead of %postun
+
+* Sat Jul 04 1998 John H Terpstra <jht@samba.org>
+ - fixed codepage preservation during update via -Uvh
+
+* Mon Jun 08 1998 Erik Troan <ewt@redhat.com>
+ - made the %postun script a tad less agressive; no reason to remove
+ the logs or lock file
+ - the %postun and %preun should only exectute if this is the final
+ removal
+ - migrated %triggerpostun from Red Hat's samba package to work around
+ packaging problems in some Red Hat samba releases
+
+* Sun Apr 26 1998 John H Terpstra <jht@samba.org>
+ - Tidy up for early alpha releases
+ - added findsmb from SGI packaging
+
+* Thu Apr 09 1998 John H Terpstra <jht@samba.org>
+ - Updated spec file
+ - Included new codepage.936
+
+* Sat Mar 20 1998 John H Terpstra <jht@samba.org>
+ - Added swat facility
+
+* Sat Jan 24 1998 John H Terpstra <jht@samba.org>
+ - Many optimisations (some suggested by Manoj Kasichainula <manojk@io.com>
+ - Use of chkconfig in place of individual symlinks to /etc/rc.d/init/smb
+ - Compounded make line
+ - Updated smb.init restart mechanism
+ - Use compound mkdir -p line instead of individual calls to mkdir
+ - Fixed smb.conf file path for log files
+ - Fixed smb.conf file path for incoming smb print spool directory
+ - Added a number of options to smb.conf file
+ - Added smbadduser command (missed from all previous RPMs) - Doooh!
+ - Added smbuser file and smb.conf file updates for username map
+
+%prep
+%setup
+
+%build
+make config
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+
+# Install stuff for tng
+
+mkdir -p $RPM_BUILD_ROOT%{prefix}/bin
+mkdir -p $RPM_BUILD_ROOT/lib/security
+cp %{tng_build_dir}/bin/samedit $RPM_BUILD_ROOT%{prefix}/bin
+cp %{tng_build_dir}/bin/winbindd $RPM_BUILD_ROOT%{prefix}/bin
+cp %{tng_build_dir}/nsswitch/libnss_winbind.so $RPM_BUILD_ROOT/lib
+cp %{tng_build_dir}/nsswitch/pam_winbind.so $RPM_BUILD_ROOT/lib/security
+
+# Install stuff for head
+
+mkdir -p $RPM_BUILD_ROOT%{prefix}/lib/codepages/src
+mkdir -p $RPM_BUILD_ROOT/etc/{logrotate.d,pam.d}
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/{init.d,rc0.d,rc1.d,rc2.d,rc3.d,rc5.d,rc6.d}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/bin
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/{images,help,include}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/man/{man1,man5,man7,man8}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/var/locks
+mkdir -p $RPM_BUILD_ROOT%{prefix}/private
+
+# Install standard binary files
+for i in nmblookup smbclient smbspool smbpasswd smbstatus testparm testprns \
+ make_smbcodepage make_printerdef
+do
+install -m755 -s %{head_build_dir}/source/bin/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+for i in addtosmbpass mksmbpasswd.sh smbtar
+do
+install -m755 %{head_build_dir}/source/script/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat smbmount smbmnt smbumount
+do
+install -m755 -s %{head_build_dir}/source/bin/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+
+# we need a symlink for mount to recognise the smb filesystem type
+#ln -sf %{prefix}/bin/smbmount $RPM_BUILD_ROOT%{prefix}/bin/mount.smbfs
+
+# Install level 1 man pages
+for i in smbclient.1 smbrun.1 smbstatus.1 smbtar.1 testparm.1 testprns.1 make_smbcodepage.1 nmblookup.1
+do
+install -m644 %{head_build_dir}/docs/manpages/$i $RPM_BUILD_ROOT%{prefix}/man/man1
+done
+
+# Install codepage source files
+for i in 437 737 850 852 861 866 932 936 949 950
+do
+install -m644 %{head_build_dir}/source/codepages/codepage_def.$i $RPM_BUILD_ROOT%{prefix}/lib/codepages/src
+done
+
+# Install SWAT helper files
+for i in %{head_build_dir}/swat/help/*.html %{head_build_dir}/docs/htmldocs/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/help
+done
+for i in %{head_build_dir}/swat/images/*.gif
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/images
+done
+for i in %{head_build_dir}/swat/include/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/include
+done
+
+# Install the miscellany
+install -m644 %{head_build_dir}/swat/README $RPM_BUILD_ROOT%{prefix}/share/swat
+install -m644 %{head_build_dir}/docs/manpages/smb.conf.5 $RPM_BUILD_ROOT%{prefix}/man/man5
+install -m644 %{head_build_dir}/docs/manpages/lmhosts.5 $RPM_BUILD_ROOT%{prefix}/man/man5
+install -m644 %{head_build_dir}/docs/manpages/smbpasswd.5 $RPM_BUILD_ROOT%{prefix}/man/man5
+install -m644 %{head_build_dir}/docs/manpages/samba.7 $RPM_BUILD_ROOT%{prefix}/man/man7
+install -m644 %{head_build_dir}/docs/manpages/smbd.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/nmbd.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/swat.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/smbmnt.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/smbmount.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/smbpasswd.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 %{head_build_dir}/docs/manpages/smbspool.8 $RPM_BUILD_ROOT%{prefix}/man/man8
+install -m644 $RPM_BUILD_DIR/%{name}-%{version}/smb.conf-appliance $RPM_BUILD_ROOT%{prefix}/lib/smb.conf
+install -m644 %{head_build_dir}/packaging/RedHat/smbusers $RPM_BUILD_ROOT/etc/smbusers
+install -m755 %{head_build_dir}/packaging/RedHat/smbprint $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 %{head_build_dir}/packaging/RedHat/findsmb $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 %{head_build_dir}/packaging/RedHat/smbadduser $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 %{head_build_dir}/packaging/RedHat/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb
+install -m755 %{head_build_dir}/packaging/RedHat/smb.init $RPM_BUILD_ROOT%{prefix}/bin/samba
+install -m644 %{head_build_dir}/packaging/RedHat/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba
+install -m644 %{head_build_dir}/packaging/RedHat/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba
+echo 127.0.0.1 localhost > $RPM_BUILD_ROOT/etc/lmhosts
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+#/sbin/chkconfig --add smb
+
+# Build codepage load files
+for i in 437 737 850 852 861 866 932 936 949 950
+do
+%{prefix}/bin/make_smbcodepage c $i %{prefix}/lib/codepages/src/codepage_def.$i %{prefix}/lib/codepages/codepage.$i
+done
+
+# Add swat entry to /etc/services if not already there
+if !( grep ^[:space:]*swat /etc/services > /dev/null ) then
+ echo 'swat 901/tcp # Add swat service used via inetd' >> /etc/services
+fi
+
+# Add swat entry to /etc/inetd.conf if needed
+if !( grep ^[:space:]*swat /etc/inetd.conf > /dev/null ) then
+ echo 'swat stream tcp nowait.400 root %{prefix}/sbin/swat swat' >> /etc/inetd.conf
+killall -1 inetd || :
+fi
+
+%preun
+if [ $1 = 0 ] ; then
+ /sbin/chkconfig --del smb
+
+ for n in %{prefix}/lib/codepages/*; do
+ if [ $n != %{prefix}/lib/codepages/src ]; then
+ rm -rf $n
+ fi
+ done
+ # We want to remove the browse.dat and wins.dat files so they can not interfer with a new version of samba!
+ if [ -e %{prefix}/var/locks/browse.dat ]; then
+ rm -f %{prefix}/var/locks/browse.dat
+ fi
+ if [ -e %{prefix}/var/locks/wins.dat ]; then
+ rm -f %{prefix}/var/locks/wins.dat
+ fi
+fi
+
+%postun
+# Only delete remnants of samba if this is the final deletion.
+if [ $1 = 0 ] ; then
+ if [ -x /etc/pam.d/samba ]; then
+ rm -f /etc/pam.d/samba
+ fi
+ if [ -e /var/log/samba ]; then
+ rm -rf /var/log/samba
+ fi
+ if [ -e /var/lock/samba ]; then
+ rm -rf /var/lock/samba
+ fi
+
+ # Remove swat entries from /etc/inetd.conf and /etc/services
+ cd /etc
+ tmpfile=/etc/tmp.$$
+ sed -e '/^[:space:]*swat.*$/d' /etc/inetd.conf > $tmpfile
+ mv $tmpfile inetd.conf
+ sed -e '/^[:space:]*swat.*$/d' /etc/services > $tmpfile
+ mv $tmpfile services
+fi
+
+%triggerpostun -- samba < samba-2.0.0
+if [ $0 != 0 ]; then
+ /sbin/chkconfig --add smb
+fi
+
+
+%files
+%doc %{head_build_dir}/README %{head_build_dir}/COPYING
+%doc %{head_build_dir}/Manifest %{head_build_dir}/Read-Manifest-Now
+%doc %{head_build_dir}/WHATSNEW.txt %{head_build_dir}/Roadmap
+%doc %{head_build_dir}/docs
+%doc %{head_build_dir}/swat/README
+%doc %{head_build_dir}/examples
+%attr(-,root,root) %{prefix}/bin/smbd
+%attr(-,root,root) %{prefix}/bin/nmbd
+%attr(-,root,root) %{prefix}/bin/swat
+%attr(-,root,root) %{prefix}/bin/smbmnt
+%attr(-,root,root) %{prefix}/bin/smbmount
+%attr(-,root,root) %{prefix}/bin/smbumount
+%attr(0750,root,root) %{prefix}/bin/samba
+%attr(-,root,root) %{prefix}/bin/addtosmbpass
+%attr(-,root,root) %{prefix}/bin/mksmbpasswd.sh
+%attr(-,root,root) %{prefix}/bin/smbclient
+%attr(-,root,root) %{prefix}/bin/smbspool
+%attr(-,root,root) %{prefix}/bin/testparm
+%attr(-,root,root) %{prefix}/bin/testprns
+%attr(-,root,root) %{prefix}/bin/findsmb
+%attr(-,root,root) %{prefix}/bin/smbstatus
+%attr(-,root,root) %{prefix}/bin/nmblookup
+%attr(-,root,root) %{prefix}/bin/make_smbcodepage
+%attr(-,root,root) %{prefix}/bin/make_printerdef
+%attr(-,root,root) %{prefix}/bin/smbpasswd
+%attr(-,root,root) %{prefix}/bin/smbtar
+%attr(-,root,root) %{prefix}/bin/smbprint
+%attr(-,root,root) %{prefix}/bin/smbadduser
+%attr(-,root,root) %{prefix}/share/swat/help/welcome.html
+%attr(-,root,root) %{prefix}/share/swat/help/DOMAIN_MEMBER.html
+%attr(-,root,root) %{prefix}/share/swat/help/NT_Security.html
+%attr(-,root,root) %{prefix}/share/swat/help/lmhosts.5.html
+%attr(-,root,root) %{prefix}/share/swat/help/make_smbcodepage.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/nmbd.8.html
+%attr(-,root,root) %{prefix}/share/swat/help/nmblookup.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/samba.7.html
+%attr(-,root,root) %{prefix}/share/swat/help/smb.conf.5.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbclient.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbspool.8.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbd.8.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbpasswd.5.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbpasswd.8.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbrun.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbstatus.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/smbtar.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/swat.8.html
+%attr(-,root,root) %{prefix}/share/swat/help/testparm.1.html
+%attr(-,root,root) %{prefix}/share/swat/help/testprns.1.html
+%attr(-,root,root) %{prefix}/share/swat/images/globals.gif
+%attr(-,root,root) %{prefix}/share/swat/images/home.gif
+%attr(-,root,root) %{prefix}/share/swat/images/passwd.gif
+%attr(-,root,root) %{prefix}/share/swat/images/printers.gif
+%attr(-,root,root) %{prefix}/share/swat/images/shares.gif
+%attr(-,root,root) %{prefix}/share/swat/images/samba.gif
+%attr(-,root,root) %{prefix}/share/swat/images/status.gif
+%attr(-,root,root) %{prefix}/share/swat/images/viewconfig.gif
+%attr(-,root,root) %{prefix}/share/swat/include/header.html
+%attr(-,root,root) %{prefix}/share/swat/include/footer.html
+%attr(-,root,root) %config(noreplace) /etc/lmhosts
+%attr(-,root,root) %config(noreplace) %{prefix}/lib/smb.conf
+%attr(-,root,root) %config(noreplace) /etc/smbusers
+%attr(-,root,root) /etc/rc.d/init.d/smb
+%attr(-,root,root) /etc/logrotate.d/samba
+%attr(-,root,root) /etc/pam.d/samba
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.437
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.737
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.850
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.852
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.861
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.866
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.932
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.936
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.949
+%attr(-,root,root) %{prefix}/lib/codepages/src/codepage_def.950
+%attr(-,root,root) %{prefix}/man/man1/smbstatus.1
+%attr(-,root,root) %{prefix}/man/man1/smbclient.1
+%attr(-,root,root) %{prefix}/man/man1/make_smbcodepage.1
+%attr(-,root,root) %{prefix}/man/man1/smbrun.1
+%attr(-,root,root) %{prefix}/man/man1/smbtar.1
+%attr(-,root,root) %{prefix}/man/man1/testparm.1
+%attr(-,root,root) %{prefix}/man/man1/testprns.1
+%attr(-,root,root) %{prefix}/man/man1/nmblookup.1
+%attr(-,root,root) %{prefix}/man/man5/smb.conf.5
+%attr(-,root,root) %{prefix}/man/man5/lmhosts.5
+%attr(-,root,root) %{prefix}/man/man5/smbpasswd.5
+%attr(-,root,root) %{prefix}/man/man7/samba.7
+%attr(-,root,root) %{prefix}/man/man8/smbd.8
+%attr(-,root,root) %{prefix}/man/man8/nmbd.8
+%attr(-,root,root) %{prefix}/man/man8/smbpasswd.8
+%attr(-,root,root) %{prefix}/man/man8/swat.8
+%attr(-,root,root) %{prefix}/man/man8/smbmnt.8
+%attr(-,root,root) %{prefix}/man/man8/smbmount.8
+%attr(-,root,root) %{prefix}/man/man8/smbspool.8
+%attr(-,root,root) %dir %{prefix}/lib/codepages
+%attr(-,root,root) %dir %{prefix}/lib/codepages/src
+%attr(-,root,root) %dir %{prefix}/var/locks
+%attr(-,root,root) %dir %{prefix}/private
+%attr(-,root,root) %{prefix}/bin/winbindd
+%attr(-,root,root) %{prefix}/bin/samedit
+%attr(-,root,root) /lib/libnss_winbind.so
+%attr(-,root,root) /lib/security/pam_winbind.so
diff --git a/examples/appliance/build.sh b/examples/appliance/build.sh
new file mode 100755
index 00000000000..ad7a4eb5fb3
--- /dev/null
+++ b/examples/appliance/build.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+tar --exclude=CVS -czf /usr/src/redhat/SOURCES/samba-appliance-0.2-src.tar.gz samba-appliance-0.2
+rpm -ba appliance.spec
diff --git a/examples/appliance/smb.conf-appliance b/examples/appliance/smb.conf-appliance
new file mode 100644
index 00000000000..a3c62256c5a
--- /dev/null
+++ b/examples/appliance/smb.conf-appliance
@@ -0,0 +1,8 @@
+[global]
+ workgroup = DOMAIN
+ security = domain
+ encrypt passwords = true
+ stat cache = false
+ winbind uid = 10000-20000
+ winbind gid = 10000-20000
+ password server = PDC
diff --git a/examples/autofs/auto.a b/examples/autofs/auto.a
new file mode 100644
index 00000000000..0fa8f4efc30
--- /dev/null
+++ b/examples/autofs/auto.a
@@ -0,0 +1,15 @@
+# automount points below /a
+
+# This is an automounter map and it has the following format
+# key [ -mount-options-separated-by-comma ] location
+# Details may be found in the autofs(5) manpage
+
+# nfs servers
+valepp -fstype=nfs,rsize=8192,wsize=8192 valepp:/
+galaun -fstype=nfs,rsize=8192,wsize=8192 galaun:/
+
+# smb-servers
+supra_andreas -fstype=smb,username=andreas,password=foo ://supra/aheinrich
+supra_cspiel -fstype=smb,username=cspiel ://supra/cspiel
+phonon_andreas -fstype=smb,username=andreas ://phonon/andreas
+helium_cspiel -fstype=smb,username=cspiel ://helium/cspiel
diff --git a/examples/libsmbclient/Makefile b/examples/libsmbclient/Makefile
new file mode 100644
index 00000000000..8c1def8a162
--- /dev/null
+++ b/examples/libsmbclient/Makefile
@@ -0,0 +1,25 @@
+#
+CC = gcc
+
+SAMBA_INCL = ../../source/include
+
+CFLAGS = -I$(SAMBA_INCL)
+
+LDFLAGS = -L/usr/lib
+
+all: testsmbc tree
+
+testsmbc: testsmbc.o
+ @echo Linking testsmbc
+ @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lsmbclient
+
+testsmbc-static: testsmbc.o
+ @echo Linking testsmbc
+ @$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< -lsmbclient -ldl -lnsl
+
+tree: tree.o
+ @echo Linking tree
+ @$(CC) `gtk-config --cflags` $(CFLAGS) $(LDFLAGS) -o $@ `gtk-config --libs` -lsmbclient $<
+
+clean:
+ @rm -f *.o *~
diff --git a/examples/libsmbclient/README b/examples/libsmbclient/README
new file mode 100644
index 00000000000..d9a9f829174
--- /dev/null
+++ b/examples/libsmbclient/README
@@ -0,0 +1,8 @@
+Some simple example programs for libsmbclient ...
+
+testsmbc.c is kinda broken as it has many hardcoded bits in it
+
+tree.c is an example of how you might do some of these things with GTK+
+It needs lots of work but shows you some ways to use libsmbclient.
+
+Richard Sharpe, 17-May-2001 ...
diff --git a/examples/libsmbclient/testsmbc.c b/examples/libsmbclient/testsmbc.c
new file mode 100644
index 00000000000..7aae9d85616
--- /dev/null
+++ b/examples/libsmbclient/testsmbc.c
@@ -0,0 +1,456 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library test program
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libsmbclient.h>
+
+void auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+ char temp[128];
+
+ fprintf(stdout, "Need password for //%s/%s\n", server, share);
+
+ fprintf(stdout, "Enter workgroup: [%s] ", workgroup);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(workgroup, temp, wgmaxlen - 1);
+
+ fprintf(stdout, "Enter username: [%s] ", username);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(username, temp, unmaxlen - 1);
+
+ fprintf(stdout, "Enter password: [%s] ", password);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(password, temp, pwmaxlen - 1);
+
+}
+
+int global_id = 0;
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+ global_id = pji->id;
+
+}
+
+int main(int argc, char *argv[])
+{
+ int err, fd, dh1, dh2, dh3, dsize, dirc;
+ const char *file = "smb://samba/public/testfile.txt";
+ const char *file2 = "smb://samba/public/testfile2.txt";
+ char buff[256];
+ char dirbuf[512];
+ char *dirp;
+ struct stat st1, st2;
+
+ err = smbc_init(auth_fn, 10); /* Initialize things */
+
+ if (err < 0) {
+
+ fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno));
+
+ }
+
+ if (argc > 1) {
+
+ /* Try to list the print jobs ... */
+
+ if (smbc_list_print_jobs("smb://samba/pclp", print_list_fn) < 0) {
+
+ fprintf(stderr, "Could not list print jobs: %s, %d\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete the last job listed */
+
+ if (global_id > 0) {
+
+ fprintf(stdout, "Trying to delete print job %u\n", global_id);
+
+ if (smbc_unlink_print_job("smb://samba/pclp", global_id) < 0) {
+
+ fprintf(stderr, "Failed to unlink job id %u, %s, %u\n", global_id,
+ strerror(errno), errno);
+
+ exit(1);
+
+ }
+
+ }
+
+ /* Try to print a file ... */
+
+ if (smbc_print_file("smb://samba/public/testfile2.txt", "smb://samba/pclp") < 0) {
+
+ fprintf(stderr, "Failed to print job: %s %u\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete argv[1] as a file ... */
+
+ if (smbc_unlink(argv[1]) < 0) {
+
+ fprintf(stderr, "Could not unlink: %s, %s, %d\n",
+ argv[1], strerror(errno), errno);
+
+ exit(0);
+
+ }
+
+ if ((dh1 = smbc_opendir("smb://"))<1) {
+
+ fprintf(stderr, "Could not open directory: smb://: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh2 = smbc_opendir("smb://sambanet")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://sambanet: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh3 = smbc_opendir("smb://samba")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://samba: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Directory handles: %u, %u, %u\n", dh1, dh2, dh3);
+
+ /* Now, list those directories, but in funny ways ... */
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh1, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh2, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "\nDirectory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh3, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "\nDir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ (char *)dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ exit(1);
+
+ }
+
+ /* For now, open a file on a server that is hard coded ... later will
+ * read from the command line ...
+ */
+
+ fd = smbc_open(file, O_RDWR | O_CREAT | O_TRUNC, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ /* Now, write some date to the file ... */
+
+ bzero(buff, sizeof(buff));
+ strcpy(buff, "Some test data for the moment ...");
+
+ err = smbc_write(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "writing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Wrote %d bytes to file: %s\n", sizeof(buff), buff);
+
+ /* Now, seek the file back to offset 0 */
+
+ err = smbc_lseek(fd, SEEK_SET, 0);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Seeking file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Completed lseek on file: %s\n", file);
+
+ /* Now, read the file contents back ... */
+
+ err = smbc_read(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "Reading file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Read file: %s\n", buff); /* Should check the contents */
+
+ fprintf(stdout, "Now fstat'ing file: %s\n", file);
+
+ err = smbc_fstat(fd, &st1);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Fstat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+
+ /* Now, close the file ... */
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+
+ }
+
+ /* Now, rename the file ... */
+
+ err = smbc_rename(file, file2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Renaming file: %s to %s: %s\n", file, file2, strerror(errno));
+
+ }
+
+ fprintf(stdout, "Renamed file %s to %s\n", file, file2);
+
+ /* Now, create a file and delete it ... */
+
+ fprintf(stdout, "Now, creating file: %s so we can delete it.\n", file);
+
+ fd = smbc_open(file, O_RDWR | O_CREAT, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, delete the file ... */
+
+ fprintf(stdout, "File %s created, now deleting ...\n", file);
+
+ err = smbc_unlink(file);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Deleting file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, stat the file, file 2 ... */
+
+ fprintf(stdout, "Now stat'ing file: %s\n", file);
+
+ err = smbc_stat(file2, &st2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Stat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Stat'ed file: %s. Size = %d, mode = %04X\n", file2,
+ (int)st2.st_size, st2.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st2.st_atime));
+ fprintf(stdout, "Earlier stat: %s, Size = %d, mode = %04X\n", file,
+ (int)st1.st_size, st1.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st1.st_atime));
+
+ /* Now, make a directory ... */
+
+ fprintf(stdout, "Making directory smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 0666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ if (errno == EEXIST) { /* Try to delete the directory */
+
+ fprintf(stdout, "Trying to delete directory: smb://samba/public/make-dir\n");
+
+ if (smbc_rmdir("smb://samba/public/make-dir") < 0) { /* Error */
+
+ fprintf(stderr, "Error removing directory: smb://samba/public/make-dir: %s\n", strerror(errno));
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Making directory: smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ fprintf(stderr, "I give up!\n");
+
+ exit(1);
+
+ }
+
+ }
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Made dir: make-dir\n");
+ return 0;
+}
diff --git a/examples/libsmbclient/tree.c b/examples/libsmbclient/tree.c
new file mode 100644
index 00000000000..da60236e601
--- /dev/null
+++ b/examples/libsmbclient/tree.c
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client GTK+ tree-based application
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* example-gtk+ application, ripped off from the gtk+ tree.c sample */
+
+#include <stdio.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include "libsmbclient.h"
+
+static GtkWidget *clist;
+
+struct tree_data {
+
+ guint32 type; /* Type of tree item, an SMBC_TYPE */
+ char name[256]; /* May need to change this later */
+
+};
+
+void error_message(gchar *message) {
+
+ GtkWidget *dialog, *label, *okay_button;
+
+ /* Create the widgets */
+
+ dialog = gtk_dialog_new();
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ label = gtk_label_new (message);
+ okay_button = gtk_button_new_with_label("Okay");
+
+ /* Ensure that the dialog box is destroyed when the user clicks ok. */
+
+ gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ okay_button);
+
+ /* Add the label, and show everything we've added to the dialog. */
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+ label);
+ gtk_widget_show_all (dialog);
+}
+
+/*
+ * We are given a widget, and we want to retrieve its URL so we
+ * can do a directory listing.
+ *
+ * We walk back up the tree, picking up pieces until we hit a server or
+ * workgroup type and return a path from there
+ */
+
+static char path_string[1024];
+
+char *get_path(GtkWidget *item)
+{
+ GtkWidget *p = item;
+ struct tree_data *pd;
+ char *comps[1024]; /* We keep pointers to the components here */
+ int i = 0, j, level,type;
+
+ /* Walk back up the tree, getting the private data */
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Pick up this item's component info */
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item));
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) {
+
+ /* Find the parent and extract the data etc ... */
+
+ p = GTK_WIDGET(p->parent);
+ p = GTK_WIDGET(GTK_TREE(p)->tree_owner);
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p));
+
+ level = GTK_TREE(item->parent)->level;
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ }
+
+ /*
+ * Got a list of comps now, should check that we did not hit a workgroup
+ * when we got other things as well ... Later
+ *
+ * Now, build the path
+ */
+
+ snprintf(path_string, sizeof(path_string), "smb:/");
+
+ for (j = i - 1; j >= 0; j--) {
+
+ strncat(path_string, "/", sizeof(path_string) - strlen(path_string));
+ strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string));
+
+ }
+
+ fprintf(stdout, "Path string = %s\n", path_string);
+
+ return path_string;
+
+}
+
+struct tree_data *make_tree_data(guint32 type, const char *name)
+{
+ struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data));
+
+ if (p) {
+
+ p->type = type;
+ strncpy(p->name, name, sizeof(p->name));
+
+ }
+
+ return p;
+
+}
+
+/* Note that this is called every time the user clicks on an item,
+ whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+ GtkWidget *subtree)
+{
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+ struct stat st1;
+ char path[1024], path1[1024];
+
+ g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+
+ /* Now, figure out what it is, and display it in the clist ... */
+
+ gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */
+
+ /* Now, get the private data for the subtree */
+
+ strncpy(path, get_path(child), 1024);
+
+ if ((dh = smbc_opendir(path)) < 0) { /* Handle error */
+
+ g_print("cb_select_child: Could not open dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) {
+
+ g_print("cb_select_child: Could not read dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ gchar col1[128], col2[128], col3[128], col4[128];
+ gchar *rowdata[4] = {col1, col2, col3, col4};
+
+ dirlen = dirp->dirlen;
+
+ /* Format each of the items ... */
+
+ strncpy(col1, dirp->name, 128);
+
+ col2[0] = col3[0] = col4[0] = (char)0;
+
+ switch (dirp->smbc_type) {
+
+ case SMBC_WORKGROUP:
+
+ break;
+
+ case SMBC_SERVER:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_FILE_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_PRINTER_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+ break;
+
+ case SMBC_COMMS_SHARE:
+
+ break;
+
+ case SMBC_IPC_SHARE:
+
+ break;
+
+ case SMBC_DIR:
+ case SMBC_FILE:
+
+ /* Get stats on the file/dir and see what we have */
+
+ if ((strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") != 0)) {
+
+ strncpy(path1, path, sizeof(path1));
+ strncat(path1, "/", sizeof(path) - strlen(path));
+ strncat(path1, dirp->name, sizeof(path) - strlen(path));
+
+ if (smbc_stat(path1, &st1) < 0) {
+
+ if (errno != EBUSY) {
+
+ g_print("cb_select_child: Could not stat file %s, %s\n", path1,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+ else {
+
+ strncpy(col2, "Device or resource busy", sizeof(col2));
+
+ }
+ }
+ else {
+ /* Now format each of the relevant things ... */
+
+ snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)",
+ (st1.st_mode&S_IRUSR?'r':'-'),
+ (st1.st_mode&S_IWUSR?'w':'-'),
+ (st1.st_mode&S_IXUSR?'x':'-'),
+ (st1.st_mode&S_IRGRP?'r':'-'),
+ (st1.st_mode&S_IWGRP?'w':'-'),
+ (st1.st_mode&S_IXGRP?'x':'-'),
+ (st1.st_mode&S_IROTH?'r':'-'),
+ (st1.st_mode&S_IWOTH?'w':'-'),
+ (st1.st_mode&S_IXOTH?'x':'-'),
+ st1.st_mode);
+ snprintf(col3, sizeof(col3), "%u", st1.st_size);
+ snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime));
+ }
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ gtk_clist_append(GTK_CLIST(clist), rowdata);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+}
+
+/* Note that this is never called */
+static void cb_unselect_child( GtkWidget *root_tree,
+ GtkWidget *child,
+ GtkWidget *subtree )
+{
+ g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+}
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal( GtkWidget *item,
+ gchar *signame )
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen, level;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ /* Get the text of the label */
+ gtk_label_get (label, &name);
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Get the level of the tree which the item is in */
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+ char server[128];
+
+ if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item),
+ strerror(errno));
+
+ snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ if (!my_data) {
+
+ g_print("Could not allocate space for tree_data: %s\n",
+ dirp->name);
+
+ gtk_main_quit();
+ return;
+
+ }
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ if (dirp->smbc_type != SMBC_FILE &&
+ dirp->smbc_type != SMBC_IPC_SHARE &&
+ (strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") !=0)){
+
+ subtree = gtk_tree_new();
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else if (strncmp(signame, "collapse", 8) == 0) {
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+}
+
+static void cb_selection_changed( GtkWidget *tree )
+{
+ GList *i;
+
+ g_print ("selection_change called for tree %p\n", tree);
+ g_print ("selected objects are:\n");
+
+ i = GTK_TREE_SELECTION(tree);
+ while (i){
+ gchar *name;
+ GtkLabel *label;
+ GtkWidget *item;
+
+ /* Get a GtkWidget pointer from the list node */
+ item = GTK_WIDGET (i->data);
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("\t%s on level %d\n", name, GTK_TREE
+ (item->parent)->level);
+ i = i->next;
+ }
+}
+
+/*
+ * Expand or collapse the whole network ...
+ */
+static void cb_wholenet(GtkWidget *item, gchar *signame)
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+
+ if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */
+
+ g_print("cb_wholenet: Could not open dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+
+ g_print("cb_wholenet: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else { /* Must be collapse ... FIXME ... */
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+
+ }
+
+}
+
+/* Should put up a dialog box to ask the user for username and password */
+
+static void
+auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+
+ strncpy(username, "test", unmaxlen);
+ strncpy(password, "test", pwmaxlen);
+
+}
+
+static char *col_titles[] = {
+ "Name", "Attributes", "Size", "Modification Date",
+};
+
+int main( int argc,
+ char *argv[] )
+{
+ GtkWidget *window, *scrolled_win, *scrolled_win2, *tree;
+ GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane;
+ gint err, dh;
+ gint i;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ gtk_init (&argc, &argv);
+
+ /* Init the smbclient library */
+
+ err = smbc_init(auth_fn, 10);
+
+ /* Print an error response ... */
+
+ if (err < 0) {
+
+ fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* a generic toplevel window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(window, "main browser window");
+ gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+ gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser");
+ gtk_widget_set_usize(GTK_WIDGET(window), 750, -1);
+ gtk_container_set_border_width (GTK_CONTAINER(window), 5);
+
+ gtk_widget_show (window);
+
+ /* A container for the two panes ... */
+
+ main_hbox = gtk_hbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_hbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_hbox);
+
+ gtk_widget_show(main_hbox);
+
+ l_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
+ r_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size);
+ gtk_container_add(GTK_CONTAINER(main_hbox), l_pane);
+ gtk_widget_show(l_pane);
+
+ /* A generic scrolled window */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win, 150, 200);
+ gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win);
+ gtk_widget_show (scrolled_win);
+
+ /* Another generic scrolled window */
+ scrolled_win2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win2, 150, 200);
+ gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2);
+ gtk_widget_show (scrolled_win2);
+
+ /* Create the root tree */
+ tree = gtk_tree_new();
+ g_print ("root tree is %p\n", tree);
+ /* connect all GtkTree:: signals */
+ gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+ GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+ /* Add it to the scrolled window */
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
+ tree);
+ /* Set the selection mode */
+ gtk_tree_set_selection_mode (GTK_TREE(tree),
+ GTK_SELECTION_MULTIPLE);
+ /* Show it */
+ gtk_widget_show (tree);
+
+ /* Now, create a clist and attach it to the second pane */
+
+ clist = gtk_clist_new_with_titles(4, col_titles);
+
+ gtk_container_add (GTK_CONTAINER(scrolled_win2), clist);
+
+ gtk_widget_show(clist);
+
+ /* Now, build the top level display ... */
+
+ if ((dh = smbc_opendir("smb:///")) < 0) {
+
+ fprintf(stderr, "Could not list default workgroup: smb:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Create a tree item for Whole Network */
+
+ item = gtk_tree_item_new_with_label ("Whole Network");
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_wholenet), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_wholenet), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ subtree = gtk_tree_new(); /* A subtree for Whole Network */
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ /* Now, get the items in smb:/// and add them to the tree */
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* Handle the error */
+
+ fprintf(stderr, "Could not read directory for smbc:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Dir len: %u\n", err);
+
+ while (err > 0) { /* Extract each entry and make a sub-tree */
+ struct tree_data *my_data;
+ int dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ item = gtk_tree_item_new_with_label(dirp->name);
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh); /* FIXME, check for error :-) */
+
+ /* Show the window and loop endlessly */
+ gtk_main();
+ return 0;
+}
+/* example-end */
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
index b018f3dcce9..7f77d07d00c 100644
--- a/examples/misc/extra_smbstatus
+++ b/examples/misc/extra_smbstatus
@@ -10,28 +10,31 @@ added things at source level, script was quick&easy.
if ($1 == "-p") then
smbstatus -p |sort -u
else if ($1 == "-c") then
- echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique
-smbd processes running.
+ echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique smbd processes running.
else if ($1 == "-l") then
- echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z
-|grep -c :` >>$2
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z |grep -c :` >>$2
+else if ($1 == "-cs") then
+ echo There are `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` concurrent connections to share: $2
+else if ($1 == "-csl") then
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` >>$3
else
- smbstatus |sort +3 -4 -u
+ echo "'smbstat -c' ==> Count unique smbd processes."
+ echo "'smbstat -p' ==> List unique smbd processes."
+ echo "'smbstat -l logfile' ==> Append a log entry for the number of"
+ echo " concurrent and unique processes to logfile."
+ echo "'smbstat -cs sharename'"
+ echo " ==> Count processes connected to sharename (assumed unique)"
+ echo "'smbstat -csl sharename logfile'"
+ echo " ==> Append a log entry for the number of concurrent"
+ echo " processes connected to sharename (assumed unique)"
endif
******
-The '-p' option was just to show unique PIDs.
+Run this script from cron eg.
-The more important ones are the '-c' and '-l' options '-c' just counts
-the number of unique smbd's, While '-l' logs this count with date and
-time to a log file specified on the command line. I'm using '-l' at
-the moment with cron to give me an idea of usage/max connections etc.
-I was also thinking of doing a log for individual/specified services.
+0,5,10,15,20,25,30,35,40,50,55 * * * * /usr/local/samba/bin/smbstat -l /usr/local/samba/var/smbdcount.log
-The default (last) option was to show unique PIDs with user names.
-Unfortunately this still lists all file locks etc. This would be
-better with a 'no locked files' option from smbstatus (or is there one
-that I didn't see)
+and you get a good idea of usage over time.
Cheers,
~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~
@@ -43,5 +46,5 @@ Cheers,
| | "Spend a little love and get high"
_/ \_ | - Lenny Kravitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-~~~~ SAMBA Web Pages: http://samba.canberra.edu.au/pub/samba/samba.html ~~~~~
+~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.org/samba/ ~~~~~~~~~~~~~~
diff --git a/examples/misc/swat.pl b/examples/misc/swat.pl
new file mode 100644
index 00000000000..f6414b63497
--- /dev/null
+++ b/examples/misc/swat.pl
@@ -0,0 +1,122 @@
+#! /usr/bin/perl5
+##
+## This is a simple script written by Herb Lewis @ SGI <herb@samba.org>
+## for reporting which parameters are supported by loadparm.c but
+## not by SWAT I just thought it looked fun and might be of interest to others
+## --jerry@samba.org
+##
+## Here is a little info on the usage and output format so you don't have
+## to dig through the code to understand what is printed.
+##
+## Useage: swat.pl [path_to_loadparm.c]
+##
+## The output consists of 4 columns of information
+## Option Name, Global Page, Share Page, Printer Page
+## The section separaters will also be printed (preceded by 16 *) to show
+## which options are grouped in the various sections.
+##
+## If the option name is preceded by an * it means this is a deprecated option.
+## If the option name is preceded by 5 spaces it means this is an alias for the
+## previous option.
+##
+## Under the Global Page, Share Page, and Printer Page columns there will be
+## one of 3 entries, BASIC, ADVANCED, or no. "BASIC" indicates this option will
+## show in the Basic View of that page in SWAT. "ADVANCED" indicates this
+## option will show in the Advanced View of that page in SWAT. "No" indicates
+## that this option is not available on that page in SWAT.
+##
+## Under the Global Page column, if an entry begins with an * it indicates that
+## this is actually specified in Samba as a "service parameter" not a "global
+## parameter" but you can set a default value for this on the Global Page in
+## SWAT.
+##
+## --herb@samba.org
+
+$lastone = "nothing";
+
+if (@ARGV[0]) {
+ $filename = @ARGV[0];
+} else {
+ $filename = "/usr3/samba20/samba/source/param/loadparm.c";
+}
+
+open (INFILE,$filename) || die "unable to open $filename\n";
+while (not eof(INFILE))
+{
+ $_ = <INFILE>;
+ last if ( /^static struct parm_struct parm_table/) ;
+}
+print "Option Name Global Page Share Page Printer Page\n";
+print "---------------------------------------------------------------------";
+while (not eof(INFILE))
+{
+ $_ = <INFILE>;
+ last if (/};/);
+ @fields = split(/,/,$_);
+ next if not ($fields[0] =~ /^.*{"/);
+ $fields[0] =~ s/.*{"//;
+ $fields[0] =~ s/"//;
+ if ($fields[3] eq $lastone) {
+ print " $fields[0]\n";
+ next;
+ }
+ $lastone = $fields[3];
+ $fields[2] =~ s/^\s+//;
+ $fields[2] =~ s/\s+$//;
+ $fields[2] =~ s/}.*$//;
+ $fields[6] =~ s/^\s+//;
+ $fields[6] =~ s/\s+$//;
+ $fields[6] =~ s/}.*$//;
+ if ($fields[2] =~ /P_SEPARATOR/) {
+ print "\n****************$fields[0]\n";
+ next;
+ }
+ else {
+ if ($fields[6] =~ /FLAG_DEPRECATED/) {
+ print "*$fields[0]".' 'x(31-length($fields[0]));
+ }
+ else {
+ print "$fields[0]".' 'x(32-length($fields[0]));
+ }
+ }
+ if (($fields[2] =~ /P_GLOBAL/) || ($fields[6] =~ /FLAG_GLOBAL/)) {
+ if ($fields[6] =~ /FLAG_GLOBAL/) {
+ print "*";
+ }
+ else {
+ print " ";
+ }
+ if ($fields[6] =~ /FLAG_BASIC/) {
+ print "BASIC ";
+ }
+ else {
+ print "ADVANCED ";
+ }
+ }
+ else {
+ print " no ";
+ }
+ if ($fields[6] =~ /FLAG_SHARE/) {
+ if ($fields[6] =~ /FLAG_BASIC/) {
+ print "BASIC ";
+ }
+ else {
+ print "ADVANCED ";
+ }
+ }
+ else {
+ print "no ";
+ }
+ if ($fields[6] =~ /FLAG_PRINT/) {
+ if ($fields[6] =~ /FLAG_BASIC/) {
+ print "BASIC";
+ }
+ else {
+ print "ADVANCED";
+ }
+ }
+ else {
+ print "no";
+ }
+ print "\n";
+}
diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl
index fc3dc2e2c05..9303658ce14 100644
--- a/examples/misc/wall.perl
+++ b/examples/misc/wall.perl
@@ -6,40 +6,64 @@
#@(#) ...using "smbclient -M" message to winpopup service.
#@(#) Default usage is to message every connected PC.
#@(#) Alternate usage is to message every pc on the argument list.
-#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
+#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
#
+# Cleanup and corrections by
+# Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+# Message to send can be now also fed (quietly) from stdin; a pipe will do.
#=============================================================================
-$smbstatus = "/usr/local/bin/smbstatus";
-$smbclient = "/usr/local/bin/smbclient";
-print STDOUT "\nEnter message for Samba clients of this host\n";
-print STDOUT "(terminated with single '.' or end of file):\n";
+$smbstatus = "/usr/local/bin/smbstatus";
+$smbshout = "/usr/local/bin/smbclient -M";
-while ( <STDIN> ) {
- /^\.$/ && last;
- push(@message, $_);
+if (@ARGV) {
+ @clients = @ARGV;
+ undef @ARGV;
}
+else { # no clients specified explicitly
+ open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n";
+ while(<PCLIST>) {
+ last if /^Locked files:/;
+ split(' ', $_, 6);
+ # do not accept this line if less then six fields
+ next unless $_[5];
+ # if you have A LOT of clients you may speed things up by
+ # checking pid - no need to look further if this pid was already
+ # seen; left as an exercise :-)
+ $client = $_[4];
+ next unless $client =~ /^\w+\./; # expect 'dot' in a client name
+ next if grep($_ eq $client, @clients); # we want this name once
+ push(@clients, $client);
+ }
+ close(PCLIST);
+}
+
+if (-t) {
+ print <<'EOT';
-if ( $ARGV[0] ne "" ) {
- $debug && print STDOUT "Was given args: \n\t @ARGV\n";
- foreach $client ( @ARGV ) {
- $pcclient{$client} = $client;
- }
-} else {
- open( PCLIST, "$smbstatus | /bin/awk '/^[a-z]/ {print $5}' | /bin/sort | /bin/uniq|");
- while ( <PCLIST> ) {
- /^[a-z]+[a-z0-9A-Z-_]+.+/ || next;
- ($share, $user, $group, $pid, $client, @junk) = split;
- $pcclient{$client} = $client;
- }
- close(PCLIST);
+Enter message for Samba clients of this host
+(terminated with single '.' or end of file):
+EOT
+
+ while (<>) {
+ last if /^\.$/;
+ push(@message, $_);
+ }
+}
+else { # keep quiet and read message from stdin
+ @message = <>;
}
-foreach $pc ( keys(%pcclient) ) {
- print STDOUT "Sending message ";
- $debug && print STDOUT " <@message> \n";
- print STDOUT "To <$pc>\n";
- open(SENDMSG,"|$smbclient -M $pc") || next;
+foreach(@clients) {
+## print "To $_:\n";
+ if (open(SENDMSG,"|$smbshout $_")) {
print SENDMSG @message;
close(SENDMSG);
+ }
+ else {
+ warn "Cannot notify $_ with $smbshout:\n$!\n";
+ }
}
+
+exit 0;
+
diff --git a/examples/printer-accounting/README b/examples/printer-accounting/README
new file mode 100644
index 00000000000..b7ab42acb96
--- /dev/null
+++ b/examples/printer-accounting/README
@@ -0,0 +1,63 @@
+These are just a few examples of what you can do for printer accounting;
+they are really just hacks to show a manager how may pages were being
+printed out on his new hp5n :)
+
+acct-all will run acct-sum and read the log files to generate some
+stats.
+
+Here is a sample output of the raw stats :
+
+1996-06-10.15:02:15 pkelly master.fcp.oypi.com 538 0
+1996-06-10.15:06:40 pkelly master.fcp.oypi.com 537 0
+1996-06-10.15:32:12 ted master.fcp.oypi.com 547 0
+1996-06-11.09:06:15 violet master.fcp.oypi.com 2667 0
+1996-06-11.09:48:02 violet master.fcp.oypi.com 66304 5
+1996-06-11.09:50:04 violet master.fcp.oypi.com 116975 9
+1996-06-11.09:57:20 violet master.fcp.oypi.com 3013 1
+1996-06-11.10:13:17 pkelly master.fcp.oypi.com 3407 1
+1996-06-11.12:37:06 craig master.fcp.oypi.com 13639 2
+1996-06-11.12:42:23 pkelly master.fcp.oypi.com 13639 2
+1996-06-11.12:45:11 marlene master.fcp.oypi.com 515 0
+1996-06-11.14:17:10 lucie master.fcp.oypi.com 1405 1
+1996-06-11.14:36:03 laura master.fcp.oypi.com 45486 5
+1996-06-11.15:08:21 violet master.fcp.oypi.com 1923 1
+1996-06-11.15:09:42 laura master.fcp.oypi.com 4821 1
+1996-06-11.15:12:28 laura master.fcp.oypi.com 46277 5
+1996-06-11.15:19:38 violet master.fcp.oypi.com 3503 1
+1996-06-11.15:21:49 lucie master.fcp.oypi.com 493 0
+1996-06-11.15:43:36 al master.fcp.oypi.com 3067 1
+
+And the output after the acct-sum is done on a full set of files
+in /var/log/lp/*
+
+master[1072] /var/log/lp$ /etc/conf/acct-all
+
+Sun Jul 21 23:03:16 EDT 1996
+
+Pages are approximate ...
+
+User Jobs Pages Size
+al 1 1 2 KB
+craig 1 2 13 KB
+jack 68 235 1995 KB
+laura 88 328 3050 KB
+lucie 221 379 3529 KB
+marlene 12 151 1539 KB
+melanie 83 365 3691 KB
+michelle 68 219 1987 KB
+mike 2 10 81 KB
+neil 111 225 2753 KB
+operator 44 137 1132 KB
+pkelly 368 984 11154 KB
+root 8 0 29 KB
+ted 158 257 2337 KB
+tony 244 368 2455 KB
+violet 419 1002 10072 KB
+
+
+Printer Jobs Pages
+hp2p 3 4
+hp5 915 2135
+lp 978 2524
+
+<pkelly@ets.net>
diff --git a/examples/printer-accounting/acct-all b/examples/printer-accounting/acct-all
new file mode 100644
index 00000000000..dc8f175b3cb
--- /dev/null
+++ b/examples/printer-accounting/acct-all
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo ""
+date
+echo ""
+echo "Pages are approximate ..."
+echo ""
+/etc/conf/acct-sum /var/log/lp/*
+echo ""
diff --git a/examples/printer-accounting/acct-sum b/examples/printer-accounting/acct-sum
new file mode 100644
index 00000000000..ffbfc8d8801
--- /dev/null
+++ b/examples/printer-accounting/acct-sum
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+while (<>) {
+ ($date, $user, $machine, $size, $pages) = split(' ');
+
+ $Printer{$ARGV}++;
+ $PrinterPages{$ARGV} += $pages;
+
+ $Jobs{$user}++;
+ $Size{$user}+= $size;
+ $Pages{$user}+= $pages;
+}
+
+printf "%-15s %5s %8s %8s\n", qw(User Jobs Pages Size);
+foreach $user (sort keys %Jobs) {
+ printf "%-15s %5d %8d %8d \KB\n",
+ $user, $Jobs{$user}, $Pages{$user}, $Size{$user}/1024;
+}
+
+
+print "\n\n";
+printf "%-15s %5s %8s %8s\n", qw(Printer Jobs Pages);
+foreach $prn (sort keys %Printer) {
+ ($name = $prn) =~ s=.*/==;
+ printf "%-15s %5d %8d\n",
+ $name, $Printer{$prn}, $PrinterPages{$prn};
+}
+
+
diff --git a/examples/printer-accounting/hp5-redir b/examples/printer-accounting/hp5-redir
new file mode 100644
index 00000000000..ea1299068a3
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# With redirection to another valid /etc/printcap entry
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+# send to the real printer now.
+open(P, "|lpr -Pmgmt0") || die "Can't print to hp5-real ($!)\n";
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print P $buf;
+ # this is ugly, but it gives the approx in pages. We
+ # don't print graphics, so ... There must be a better way :)
+ $cnt += ($buf =~ /^L/g);
+}
+close(P);
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/lp-acct b/examples/printer-accounting/lp-acct
new file mode 100644
index 00000000000..91a3def08f8
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# Regular, with no redirection
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print $buf;
+ $cnt += ($buf =~ /^L/g);
+}
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/printcap b/examples/printer-accounting/printcap
new file mode 100644
index 00000000000..976005a097c
--- /dev/null
+++ b/examples/printer-accounting/printcap
@@ -0,0 +1,22 @@
+# HP5N - Accounting entry
+#
+# This file calls the filter, hp5-redir to do the numbers and then
+# is redirected to the real entry, mgmt0, which is a remote HP5N
+# on the LAN with it's own IP number.
+#
+hp5:lp=/dev/lp1:\
+ :sd=/usr/spool/lpd/hp5-acct:\
+ :lf=/var/log/lp-err:\
+ :af=/var/log/lp/hp5:\
+ :if=/usr/local/bin/lp/hp5-redir:\
+ :sh:sf:\
+ :mx#0:
+
+# HP5N - Real printer location
+mgmt0:\
+ :rm=hp5.fcp.oypi.com:\
+ :rp=hp5.fcp.oypi.com:\
+ :sd=/usr/spool/lpd/mgmt0:\
+ :sh:sf:\
+ :mx#0:
+
diff --git a/examples/printing/smbprint b/examples/printing/smbprint
index a80d60ce4fa..5a00a2a8aa8 100755
--- a/examples/printing/smbprint
+++ b/examples/printing/smbprint
@@ -1,4 +1,4 @@
-#!/bin/sh -x
+#!/bin/sh
# This script is an input filter for printcap printing on a unix machine. It
# uses the smbclient program to print the file to the specified smb-based
@@ -20,6 +20,11 @@
# so that the server, service, and password can be read from
# a /usr/var/spool/lpd/PRINTNAME/.config file.
#
+# Script further modified by Richard Sharpe to fix some things.
+# Get rid of the -x on the first line, and add parameters
+#
+# -t now causes translate to be used when sending files
+#
# In order for this to work the /etc/printcap entry must include an
# accounting file (af=...):
#
@@ -53,7 +58,8 @@ logfile=/tmp/smb-print.log
# Extract the directory name from the file name.
# Concat this with /.config to get the config file.
#
-eval acct_file=\$$#
+TRANS=0
+eval acct_file=\${$#}
spool_dir=`dirname $acct_file`
config_file=$spool_dir/.config
@@ -63,6 +69,16 @@ config_file=$spool_dir/.config
# password
eval `cat $config_file`
+while getopts t c; do
+ case $c in
+ t)
+ TRANS=1
+ ;;
+
+ '?') # Bad parameters, ignore it ...
+ ;;
+ esac
+done
#
# Some debugging help, change the >> to > if you want to same space.
#
@@ -71,7 +87,9 @@ echo "server $server, service $service" >> $logfile
(
# NOTE You may wish to add the line `echo translate' if you want automatic
# CR/LF translation when printing.
-# echo translate
+ if [ $TRANS -eq 1 ]; then
+ echo translate
+ fi
echo "print -"
cat
) | /usr/local/samba/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/examples/simple/smb.conf b/examples/simple/smb.conf
index cdf65b337f7..786bf49057c 100644
--- a/examples/simple/smb.conf
+++ b/examples/simple/smb.conf
@@ -80,11 +80,13 @@
writable = no
create mode = 0700
-; you might also want this one
+; you might also want this one, notice that it is read only so as not to give
+; people without an account write access.
+;
; [tmp]
; comment = Temporary file space
; path = /tmp
-; read only = no
+; read only = yes
; public = yes
;
diff --git a/examples/smb.conf.default b/examples/smb.conf.default
new file mode 100644
index 00000000000..c25b2dc6281
--- /dev/null
+++ b/examples/smb.conf.default
@@ -0,0 +1,252 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name, eg: REDHAT4
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# If you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ load printers = yes
+
+# you may wish to override the location of the printcap file
+; printcap name = /etc/printcap
+
+# on SystemV system setting printcap name to lpstat should allow
+# you to automatically obtain a printer list from the SystemV spool
+# system
+; printcap name = lpstat
+
+# It should not be necessary to specify the print system type unless
+# it is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /usr/local/samba/var/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /usr/local/samba/lib/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+# You may want to add the following on a Linux system:
+# SO_RCVBUF=8192 SO_SNDBUF=8192
+ socket options = TCP_NODELAY
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /usr/local/samba/lib/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /usr/local/samba/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /usr/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; writable = yes
+; printable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %U option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/examples/svr4-startup/README b/examples/svr4-startup/README
new file mode 100644
index 00000000000..8ed9f744770
--- /dev/null
+++ b/examples/svr4-startup/README
@@ -0,0 +1,24 @@
+Hi and thanks for this great software.
+
+Solaris (and other sysv) machines have a standardized way of
+starting and shutting down services (you may well know that already).
+
+Here's a piece of code one could place under /etc/init.d
+and create appropriate link from, say
+
+ /etc/rc2.d/S99samba.server
+
+to make smbd start and stop automatically with system bootups and
+shutdowns. Each one should edit the lines containing the
+daemon calls to agree with his/her installation (the code below
+works with the defaults) and workgroup setup (we use the -G and -n
+options).
+
+
+I hope this will be of use --- at least it is for me.
+
+Yours,
+
+Timo Knuutila
+knuutila@cs.utu.fi
+
diff --git a/examples/svr4-startup/samba.server b/examples/svr4-startup/samba.server
new file mode 100755
index 00000000000..0a47fdb10ce
--- /dev/null
+++ b/examples/svr4-startup/samba.server
@@ -0,0 +1,38 @@
+#!/bin/sh
+#ident "@(#)samba.server 1.0 96/06/19 TK" /* SVr4.0 1.1.13.1*/
+#
+# Please send info on modifications to knuutila@cs.utu.fi
+#
+# This file should have uid root, gid sys and chmod 744
+#
+if [ ! -d /usr/bin ]
+then # /usr not mounted
+ exit
+fi
+
+killproc() { # kill the named process(es)
+ pid=`/usr/bin/ps -e |
+ /usr/bin/grep -w $1 |
+ /usr/bin/sed -e 's/^ *//' -e 's/ .*//'`
+ [ "$pid" != "" ] && kill $pid
+}
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+'start')
+#
+# Edit these lines to suit your installation (paths, workgroup, host)
+#
+ /opt/samba/bin/smbd -D -s/opt/samba/smb.conf
+ /opt/samba/bin/nmbd -D -l/opt/samba/log -s/opt/samba/smb.conf
+ ;;
+'stop')
+ killproc nmbd
+ killproc smbd
+ ;;
+*)
+ echo "Usage: /etc/init.d/samba.server { start | stop }"
+ ;;
+esac
diff --git a/examples/thoralf/smb.conf b/examples/thoralf/smb.conf
new file mode 100644
index 00000000000..f9f147474a8
--- /dev/null
+++ b/examples/thoralf/smb.conf
@@ -0,0 +1,152 @@
+; Configuration file for smbd (Samba 1.9.15p8)
+; created by Thoralf Freitag. Send comments to:
+; <Thoralf.Freitag@remserv.rz.fhtw-berlin.de> or
+; <Thoralf.Freitag@t-online.de>
+; last edit 24.04.1995 01:11
+;
+;
+
+[global]
+
+ protocol = NT1
+ ;long filenames for win95
+ mangle case = yes
+ ;lower and upper letters
+ mangled names = yes
+ default case = lower
+ case sensitive = no
+ preserve case = yes
+ short preserve case = yes
+
+ printing = bsd
+ printcap name = /etc/printcap
+ lpq cache time = 0
+ workgroup = WORKGROUP
+ admin users = su
+ ;su is allowed to do all !!!
+ guest account = ftp
+ ;guest is same as user ftp
+ default service = reference
+ ;is possibly helpful to browsing under win 95
+ os level = 2
+ log file = /var/adm/log.smb
+ max log size = 10
+ debug level = 1
+ share modes = yes
+ lock directory = /var/adm
+
+[JP_360_raw]
+ comment = Networkprinter queue for Olivetti JP 360 (untreated RAW format)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = samba
+ ;samba is an alias name for an raw_printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_mono]
+ comment = Networkprinter queue for Olivetti JP 360 Mono (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp
+ ;lp means the standard printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_color]
+ comment = Networkprinter queue for Olivetti JP 360 Color (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp4
+ ;my printer need this to print with his color cartridge
+ ;--> the lpd is drive to the printer as an color printer
+ path = /samba/tmp
+ create mode = 0700
+
+[tmp]
+ comment = the garbage dump
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/tmp
+ create mask = 0777
+
+[transfer]
+ comment = the market place
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/transfer
+ create mask = 0777
+
+[homes]
+ comment = home directories
+ browseable = no
+ ;ONLY the home-dirs are visible, not the service itself
+ available = yes
+ guest ok = no
+ read only = no
+ printable = no
+ create mode = 0700
+
+[install]
+ comment = all of the many install files
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/install
+ create mode = 0755
+
+[doc-help]
+ comment = documentations, helpfiles, FAQ's
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/doc
+ create mode = 0755
+
+[cd_rom_2]
+ comment = the CD in the CD-ROM drive on PANDORA
+ browsable = yes
+ available = yes
+ public = yes
+ writable = no
+ printable = no
+ path = /cdrom
+
+[reference]
+ ;the default, if invalid accesses
+ comment = PANDORA: Samba LAN manager
+ browsable = yes
+ ;only as an hint
+ available = no
+ ;however no access possible
+ public = yes
+ writable = no
+ printable = no
+ path = /samba/tmp
+
diff --git a/examples/validchars/msdos70.out b/examples/validchars/msdos70.out
new file mode 100644
index 00000000000..a722b83604f
--- /dev/null
+++ b/examples/validchars/msdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: 237
+235: ok
+234: ok
+233: ok
+232: ok
+231: 232
+230: ok
+229: ok
+228: 229
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: 73
+212: ok
+211: ok
+210: ok
+209: ok
+208: 209
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: 199
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 233
+162: 224
+161: 214
+160: 181
+159: ok
+158: ok
+157: ok
+156: ok
+155: 157
+154: ok
+153: ok
+152: length 0
+151: 235
+150: 234
+149: 227
+148: 153
+147: 226
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 222
+140: 215
+139: 216
+138: 212
+137: 211
+136: 210
+135: 128
+134: 143
+133: 183
+132: 142
+131: 182
+130: 144
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: open unlink 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 73:213 213:73 73:73 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 130:144 145:146 148:153 129:154 156 155:157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 160:181 131:182 133:183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198:199 200 201 202 203 204 205 206 207 208:209 136:210 137:211 138:212 161:214 140:215 139:216 217 218 219 220 221 141:222 223 162:224 225 147:226 149:227 228:229 230 231:232 163:233 150:234 151:235 236:237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/nwdos70.out b/examples/validchars/nwdos70.out
new file mode 100644
index 00000000000..b0dbf628531
--- /dev/null
+++ b/examples/validchars/nwdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: ok
+235: ok
+234: ok
+233: ok
+232: ok
+231: ok
+230: ok
+229: ok
+228: ok
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: ok
+212: ok
+211: ok
+210: ok
+209: ok
+208: ok
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: ok
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 85
+162: 79
+161: 73
+160: 65
+159: ok
+158: ok
+157: ok
+156: ok
+155: ok
+154: ok
+153: ok
+152: 89
+151: 85
+150: 85
+149: 79
+148: 153
+147: 79
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 73
+140: 73
+139: 73
+138: 69
+137: 69
+136: 69
+135: 128
+134: 143
+133: 65
+132: 142
+131: 65
+130: 69
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: length 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 69:130 130:69 69:69 65:131 131:65 65:65 65:133 133:65 65:65 69:136 136:69 69:69 69:137 137:69 69:69 69:138 138:69 69:69 73:139 139:73 73:73 73:140 140:73 73:73 73:141 141:73 73:73 79:147 147:79 79:79 79:149 149:79 79:79 85:150 150:85 85:85 85:151 151:85 85:85 89:152 152:89 89:89 65:160 160:65 65:65 73:161 161:73 73:73 79:162 162:79 79:79 85:163 163:85 85:85 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 144 145:146 148:153 129:154 155 156 157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/readme b/examples/validchars/readme
new file mode 100644
index 00000000000..6487fbd766a
--- /dev/null
+++ b/examples/validchars/readme
@@ -0,0 +1,101 @@
+Note: All files in this directory are DOS formatted (CRLF line terminator).
+
+!!! VIRUS WARNING !!! I do not know if VALIDCHR.COM is virus free !!!
+I think that my system is virus free here because I do not run any games
+or other copied software. I only run Shareware/Freeware etc. from CD-ROMs
+or from registered disks, however I do not use viral scanners because
+I have not registered any (I consider `having no sex' is better than
+`testing for AIDS on a regular basis', if you know what I mean).
+
+This is VALIDCHR, a little DOS program I wrote to create
+an apropriate `valid chars =' config parameter.
+It is freeware and is thought to be distributed freely with Samba.
+
+WARNING:
+ Your SMB driver may use another character map as the one VALIDCHR
+ sees. The only way you can tell this is that some file names fail.
+ Under Win95 everything is fine, though.
+
+Usage:
+ c:
+ mkdir junk_dir
+ cd junk_dir
+ a:validchr > a:output.log
+ cd ..
+ rmdir junk_dir
+
+Siedeffects:
+ Files named *.TST may be deleted.
+
+Verification:
+ For diagnostic purpose you can run VALIDCHR on a Samba mounted drive.
+ Then you can use unix diff to compare the output of the network and
+ the hard drive. These two outputs usually differ! However there
+ should be few differences. I get following on Win95 (c: visa e:)
+ 104c104
+ < 152: length 0
+ ---
+ > 152: 95
+ (diff line for `valid chars =' deleted because it's uninteresting)
+ You can see, `y diaresis' can be mapped on the network drive while
+ it cannot be mapped on the hard drive. Everything else is identical.
+ However this gives a hint that one can improve the mapping.
+
+Bugs:
+ Yes, probably some.
+
+
+VALIDCHR must be run on the system which character mapping should be probed.
+It must be run on the hard drive for this. VALIDCHR ALTERS THE CURRENT
+DIRECTORY AND REMOVES SOME FILES, SO ALWAYS RUN IT IN A junk DIRECTORY !!!
+You should redirect the output of VALIDCHR. At the end of the output is a
+line like
+ valid chars = x:y y:x x:x ... a:b c ...
+which is suitable for your smb.conf file. (you should remove the DOS CR
+character, because DOS uses CRLF while Unix uses LF only.)
+
+Note that some mappings at the beginning of the `valid chars =' line like
+A:B B:A B:B
+might look a little bit strange to you, however sometimes character A
+has to be mapped to character B independently of a default mapping
+to uppercase or lowercase while character B must not be touched. I found
+this out the hard way ... Consider it a crude workaround, because Samba
+lacks the possibility to map characters in one direction only!
+
+VALIDCHR usually issues one warning for character 32.
+You may ignore these and any other warnings.
+
+VALIDCHR does not test for character NUL (this is the directory end marker).
+
+validchr.c is the source code to validchr.com
+ You may do anything with the source code (copy, change, sell, burn)
+validchr.com is a Borland C compiled binary.
+ Beware, it may contain a virus (if my system contains one).
+nwdos70.out is the output of an VALIDCHR-run under Novell DOS 7.0
+ while no codepage (no display.sys) was active.
+msdos70.out is the output of an VALIDCHR-run under MS-DOS 7.0 (Win95 DOS)
+ while codepage 850 was active.
+
+I have no other MS-DOS systems at home currently.
+(I have access to MS-DOS 3.0, 3.2, 3.3, 5.0 and 6.22, however I have no time
+ to run VALIDCHR there)
+
+Some words to the output
+(for people not fammiliar with programming language C):
+
+probed_char: [text] mapped_char
+
+probed_char is the character probed to be written to disk
+text may be empty or contain:
+ open File could not be opened.
+ close File could not be closed (should not happen)
+ length File name was shortened (usually occurs on SPC)
+ unlink File cannot be unlinked (usually when open fails)
+mapped_char is the character which is used by MS-DOS in the directory
+ This is usually the uppercase character.
+ The mapped character is 0 if something failed (you may say
+ that the character is not supported)
+
+The last line in the output is documented in the smb.conf manual page ;)
+
+tino@augsburg.net
diff --git a/examples/validchars/validchr.c b/examples/validchars/validchr.c
new file mode 100644
index 00000000000..415546cb841
--- /dev/null
+++ b/examples/validchars/validchr.c
@@ -0,0 +1,123 @@
+/* by tino@augsburg.net
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <dirent.h>
+
+unsigned char
+test(void)
+{
+ DIR *dir;
+ struct dirent *dp;
+ unsigned char c;
+
+ if ((dir=opendir("."))==0)
+ {
+ perror("open .");
+ return 0;
+ }
+ c = 0;
+ while ((dp=readdir(dir))!=0)
+ {
+ size_t len;
+
+ len = strlen(dp->d_name);
+ if (len<4)
+ continue;
+ if (strcmp(dp->d_name+len-4, ".TST"))
+ continue;
+ if (len!=5)
+ {
+ fprintf(stderr, "warning: %s\n", dp->d_name);
+ printf(" length");
+ continue;
+ }
+ if (c)
+ printf(" double%d\n", c);
+ c = dp->d_name[0];
+ }
+ if (closedir(dir))
+ perror("close .");
+ return c;
+}
+
+int
+main(void)
+{
+ char name[256];
+ unsigned char map[256], upper[256], lower[256];
+ int i, j, c;
+ FILE *fd;
+
+ if (test())
+ {
+ printf("There are *.TST files, please remove\n");
+ return 0;
+ }
+ for (i=0; ++i<256; )
+ {
+ lower[i] = i;
+ upper[i] = 0;
+ }
+ for (i=256; --i; )
+ {
+ map[i] = i;
+ strcpy(name, "..TST");
+ name[0] = i;
+ printf("%d:", i);
+ if ((fd=fopen(name, "w"))==0)
+ printf(" open");
+ else
+ fclose(fd);
+ c = test();
+ if (unlink(name))
+ printf(" unlink");
+ if (c==i)
+ printf(" ok");
+ else
+ printf(" %d", c);
+ printf("\n");
+ if (c!=i)
+ {
+ upper[c]++;
+ lower[c] = i;
+ }
+ map[i] = c;
+ }
+
+ /* Uppercase characters are detected above on:
+ * The character is mapped to itself and there is a
+ * character which maps to it.
+ * Lowercase characters are the lowest character pointing to another one.
+ * Else it is a one way character.
+ *
+ * For this reason we have to process the list
+ * 1) for 'one way' characters
+ * 'one way' is something which is no upper and no lower character.
+ * This is an awful, crude and ugly hack due to missing Samba support.
+ * 2) for true uppercase/lowercase characters
+ * 3) for standalone characters
+ * Note that there might be characters which do not fall into 1 to 3.
+ */
+ printf("\n valid chars =");
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]!=i && lower[map[i]]!=i)
+ {
+ if (!upper[i])
+ printf(" %d:%d %d:%d %d:%d", /*1*/
+ map[i], i, i, map[i], map[i], map[i]);
+ else
+ fprintf(stderr, "ignoring map %d->%d because of %d->%d\n",
+ lower[i], i, i, map[i]);
+ }
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]==i)
+ if (upper[i])
+ printf(" %d:%d", lower[i], i); /*2*/
+ else
+ printf(" %d", i); /*3*/
+ printf("\n");
+ return 0;
+}
diff --git a/examples/validchars/validchr.com b/examples/validchars/validchr.com
new file mode 100644
index 00000000000..a5dbb39bedf
--- /dev/null
+++ b/examples/validchars/validchr.com
@@ -0,0 +1,77 @@
+ŒÊ.‰–´0Í!‹.‹,ŽÚ£é Œç ‰ã ‰.ÿ è]¡ã ŽÀ3À‹Ø‹ø¹ÿüò®ãaC&8uö€Í€÷Ù‰á ¹ÓãƒÃƒãø‰å ŒÚ+ê‹>º#ÿs¿‰>º#Ç>'r(>R#r"±ÓïG;ïrƒ>º#tƒ>R#u¿;ïw‹ýëéã‹ßÚ‰÷ ‰û ¡ç +ØŽÀ´JWÍ!_ÓçúŽÒ‹çû3À.Ž–¿î&¹>'+Ïüóªƒ>$#vG€>é r@w€>ê r7¸X»Í!r*´g‹$#Í!r ´H»Í!r@£ÿ HŽÀ´IÍ!r
+¸X»Í!séb´Í‰í ‰ï
+Àt ¸@ŽÀ»p&Æ3í.Ž–¾è&¿î&è©ÿ6ß ÿ6Ý ÿ6Û èóPèy.Ž–VW¾î&¿î&èÊ_^ÃËì´LŠFÍ!¹ºŸ é¸5Í!‰Ë ŒÍ ¸5Í!‰Ï ŒÑ ¸5Í!‰Ó ŒÕ ¸5Í!‰× ŒÙ ¸%ŒÊŽÚº{Í!ø%ÅË Í!¸%ÅÏ Í!¸%ÅÓ Í!¸%Å× Í!ø‹×‹Þ;ßt&€?ÿt&ŠO2í;Ès‹Á‹ÓƒÃëã;×t‹Ú&€?&Æÿt&ÿ_ëÄ&ÿWë½Ã´‹×‹Þ;ßt&€?ÿt &8gr&Šg‹ÓƒÃëå;×t‹Ú&€?&Æÿt&ÿ_ëÇ&ÿWëÀô@»Í!ùº­ .Ž–èêÿ¸PèPU‹ìƒìVW¸!Pè6Y‰Fþ Àu ¸!PèƒY°é‰ÆFýë]VèúY‹øƒÿsëO¸ !P‹ÆÇüÿPèYY Àtë8ƒÿtV¸!P¸"Pèƃĸ!PèmYë€~ýtŠFý´P¸%!PèWYYŠˆFýÿvþètY‹ð Àu–ÿvþè›Y Àt¸0!PèûYŠFýétÿ_^‹å]ÃU‹ììèCÿ
+Àt ¸8!PèY3ÀéaÇFþë†úû‹^þØŠFþˆ†úü‹^þØÆÿFþ‹Fþ=|ÛÇFþéƆúý‹^þØŠFþˆ¸^!P†úþPèêYYŠFþˆ†úþÿvþ¸d!Pè¨YY¸h!P†úþPèÊYY‰Fú Àu ¸j!PèŠëÿvúèYè§þ´‰Fü†úþPèJY Àt¸p!PèeY‹Fü;Fþu
+¸x!PèUYë ÿvü¸|!PèHYY¸€!Pè?Y‹Fü;Fþt†úü‹^üØþ†úû‹^üØŠFþˆ†úý‹^þØŠFüˆÿNþté2ÿ¸‚!PèYÇFþéÒ†úý‹^þØ€?uéÁ†úý‹^þØŠ´;Fþu鬆úý‹^þØŠ´–úû‹؊´;Fþu鋆úü‹^þØŠ´ ÀuJ†úý‹^þØŠ´P†úý‹^þØŠ´P†úý‹^þØŠ´Pÿvþÿvþ†úý‹^þØŠ´P¸”!PèZƒÄë0†úý‹^þØŠ´Pÿvþÿvþ†úû‹^þØŠ´P¸§!P¸"PèwƒÄ ÿFþ‹Fþ=}é ÿÇFþëW†úý‹^þØ€?tI†úý‹^þØŠ´;Fþu7†úü‹^þØ€?tÿvþ†úû‹^þØŠ´P¸Î!PèʃÄë ÿvþ¸Õ!Pè»YYÿFþ‹Fþ=|ž¸Ù!é•ý‹å]ÃU‹ìƒ>Ü! u¸ë‹Ü!Ñã‹F‰‡î&ÿÜ!3À]ÃU‹ì´C2À‹VÍ!r ‹^‰3ÀëPè?]ÃU‹ì´C°‹V‹NÍ!r3ÀëPè$]ÃU‹ì´/Í!S´‹VÍ!´N‹N‹VÍ!œY“´ZÍ!Qr3ÀëSèñ]ÃU‹ì´/Í!S´‹VÍ!´OÍ!œY“´ZÍ!Qr3ÀëSèÄ]ÃÃU‹ìV‹v öuëÿÜ!‹Ü!Ñãÿ—î&ƒ>Ü!uëè¯úÿÞ!èûè¸úƒ~u öuÿà!ÿâ!ÿvè¡úY^]ÂU‹ì3ÀPPÿvè¦ÿ]ÃU‹ì¸P3ÀPÿvè”ÿ]Ã3ÀP¸P3ÀPè…ÿøPP3ÀPèyÿÃU‹ìV‹v ö|ƒþX~¾W‰6T#Š„V#˜‹ðë ÷Þƒþ0éÇT#ÿÿ‰6ë ¸ÿÿ^]ÂU‹ìV‹vVè¼ÿ‹Æ^]ÂU‹ì¸D‹^Í!’%€]ÃU‹ìƒì"VW‹~
+‹^ƒû$wX€ûrS‹F ‹N É}€~t Æ-G÷Ù÷؃ÙvÞã‘+Ò÷ó‘÷óˆFã ëñ+Ò÷óˆF ÀuõNÞ÷ÙÎüNŠ,
+s:ëFªâï°ª‹F
+_^‹å]Â U‹ì3ÀPÿvÿv¸
+P°P°aPèjÿ]ÂU‹ì‹^Ñã§&#ÿý´BŠF
+‹^‹N‹VÍ!rëPèäþ™]ÃU‹ìV‹v‹V öu¾.'ÿv Òu¸°#ë‹ÂPVèÖYYPèÿ¸´#PVèÕYY‹Æ^]ÂU‹ìƒìVW‹v‹~V3ÀPƒ=ÿu¸ë¸‹Pèžÿ‹ðFþPVèTýYY Àt׋Æ_^‹å]º;$#s+‹ÚÑãLJ&#‹Ú±ÓãƇè!ÿ‹ÂÓàä!‹ÚÓ㉇ò!B;$#rÕ è!˜PètþY Àu&æ!ÿý¸P÷æ!t¸ë3ÀP3ÀP¸ä!PèZƒÄ ø!˜Pè@þY Àu&ö!ÿý¸P÷ö!t¸ë3ÀP3ÀP¸ô!Pè&ƒÄÃU‹ì´A‹VÍ!r3ÀëPè´ý]ÊÆèŠÂÔ†àè†à'@'ªÃU‹ìì–VWÇFîÇFìPÇFêëFW¹ÿÿ2Àò®÷ÑI_Ã6ˆGþNìu/SQR†jÿ+ø†jÿPWÿvÿV
+ ÀuÇFêÇFìP~î¾jÿZY[Ãü¾jÿ‰~ü‹~ü‹v¬
+Àt<%t6ˆGþNìîè¬ÿëééÚ‰vð¬<%tç‰~ü3ɉNò‰NþˆNõÇFøÿÿÇFöÿÿë¬2ä‹Ð‹Ø€ë €û`sŠŸÃ#ƒûvéÑã.ÿ§û郀ýwøƒNþëЀýwíƒNþëÅ€ýwâ€~õ+tˆVõ뵃fþßëƒNþ µ맀ýwM÷Fþu)ƒNþµë“é8‹~6‹ƒF€ýs Ày÷؃Nþ‰Føµéoÿ€ýu׉FöþÅébÿ€ýsʵÿFöéUÿ’,0˜€ýwµ‡Fø À|ÑÑà‹ÐÑàÑàÂFøé3ÿ€ýu›‡Fö ÀtµÑà‹ÐÑàÑàÂFöéÿƒNþéeÿNþƒfþïéYÿ·ë
+·³éÚÆFõˆVû3ÒˆVú‹~6‹ë·
+ÆFúˆVû‹~6‹™GG‰v÷Fþt6‹GG‰~~» Àu Òuƒ~öu 6Æ‹ÇëƒNþRPWŠÇ˜PŠFúPSèÝû‹Vö Ò}éòéýˆVû‰v~º‹^6ÿ7CC‰^÷Fþ t6‹CC‰^è˜ý°:ªZèý6ÆÆFúƒfþûNº+ù‡Ï‹Vö;Ñ‹Ñ韉vˆVû‹~6‹ƒF~»2ä6‰¹é‰vˆVû‹~÷Fþ u 6‹=ƒF ÿë 6Ä=ƒFŒÀ Çu¿¼#èPý;Növ‹Nöé…‰vˆVû‹~‹Nö É}¹WQ^»SR¸#FþP‹Fþ©t ¸ƒF
+ëƒF¸Pèò~»÷Fþt‹Vø Ò~èòü&€=-uI+Ñ~‰Vò&€=-t ŠFõ
+ÀtO&ˆƒ~ò~
+‹Nö É}ÿNòèÀü‹÷‹~ü‹^ø¸#Fþ=uŠfû€üou ƒ~òÇFòë€üxt€üXuƒNþ@KKƒnò}ÇFòNò÷Fþu ë° èyüK;Ùö÷Fþ@t °0èhüŠFûèbü‹Vò Ò~'+Ê+Ú&Š<-t< t<+u&¬èCüIK‡Êã°0è8üâù‡Êã+Ù&¬6ˆGþNìè+üâð Û~ ‹Ë° èüâùéUü‰v‹~÷Fþ u 6‹=ƒFë6Ä=ƒF¸P*FìFî&‰÷FþtGG&Çéü‹vð‹~ü°%èÉû¬
+Àuø€~ìP}èÄûƒ~êt¸ÿÿë‹Fî_^‹å]Â^ H “ S Á Î   | A  # '   M ð  ËËËn t U‹ìVW‹~ÿvè‰Y‹ð@PÿvWè ƒÄ‹ÇÆ_^]ÃU‹ì‹F‹Ôê;Âs£ó 3Àë Çë ¸ÿÿ]ÃU‹ì‹F‹Vó ƒÒ‹È ÒuÁr
+;Ìs‡ó ë Çë ¸ÿÿ]ÃU‹ìÿvè¤ÿY]ÃU‹ì‹F™RPè·ÿYY]ú$$ëº)$¹´@»Í!¹'º.$´@Í!é£óU‹ì‹V´DŠF‹^‹N
+Í!r ƒ~u‹ÂëëPèø]ÃVW‹ô‹\ƒër;X$tèBëè_^Ã9V$t#‹wöt‰6X$ë ;6V$t ‹ÞèT‹G£X$ë ‹Þ3À£V$£X$£Z$Sèöþ[Ãÿ;V$t‹w‹¨u‰‹?û‰u‹Þëè2‹?û‹¨tË÷ð‰\‹ß‹;ßt‰>Z$‹w‰u‰|ÃÇZ$Ë6Z$ öt‹|‰\‰]‰‰wÉZ$‰_‰_ÃVW‹ô‹D ÀtRr6%þÿ=s¸ƒ>V$t‹Z$ Ût ‹Ó9s‹_;Úuõèfë!èŠëèë3Àë‹ðƒÆ97séèkÿÿ‹Ã_^ÃP3ÀPPè6þ[[%t 3ÒRPè(þ[[XP3ÛSPèþ[[=ÿÿt‹Ø‰V$‰X$X@‰ƒÃ‹ÃÃ[3ÀÃP3ÛSPèöý[[=ÿÿt‹Ø¡X$‰G‰X$X@‰ƒÃ‹ÃÃX3ÀÃ)‹ó7‹þø@‰‰\‰uƒÆ‹ÆËìSPQPèÿ[‹Ø Àtü‹ø‹vþ‹ ƒÆVƒéÑéó¥‰Fþè$þ[‹^þƒÄ˃Â;Ñw5‹Ñ;X$u‰ÿÃSPèKý[[ë‹ûø‰]+Ð)‹÷ò‰|B‰‹Ë‹ßè7þ‹ÙƒÃÃVWU‹ì‹^‹F
+ Àt7 Ût-ƒë‹I‹ÐƒÂƒâþƒúsº;Êr wƒÃëè‡ÿëèOÿ‹Ãë PèeþëSèý3À[]_^Ãÿ&à&U‹ì‹N´CŠF‹VÍ!r‘ëPèyõ]ÃU‹ì‹V;$#r ¸Pèdõë‹ÚÑãLJ&#RèY]ÃU‹ì´>‹^Í!r ÑãLJ&#3ÀëPè5õ]ÃU‹ìVWÿvèØ Y‹øPèàýY‹ð Àu
+Çë 3ÀëpÿvVè” YY‹ÇO Àt‹ß€8:t€8\t
+€8/t¸\$ë¸a$PVè YY¸/Pè˜ýY‹ø Àu Çë VëW¸PVèÔóƒÄ Àt Vè¥üYWè üY뙉u+ÆE-ÆE.Ý‹Ç_^]ÃU‹ìV‹v€|.ÝuV¸Pÿt+è˜óƒÄÆD-^]ÃU‹ìV‹v€|.Ýt
+Çë 3ÀëŠD-˜ Àu VèžóY ÀuëÆD-‹Æ^]ÃU‹ìV‹v öt€|.Ýt Çë ¸ÿÿëÆD.ÿt+èüYVè üY3À^]ÃU‹ìVW‹~¾ÿÿ ÿtd9}u_ƒ}tƒ=} WèVY ÀuK÷EtÿuèÐûY€}| ŠE˜PèWþY‹ðÇEÇEÇÆEÿƒ} t3ÀPPÿu èÈôPèÝõYÇE ‹Æ_^]ÃU‹ìVW‹~ ÿuènëf9}t¸ÿÿë^ƒ=|)÷Eu
+‹Ç9E
+uFÇ‹Ç9E
+u8‹E‰E
+ë0ë.‹E@‹ð)5P‹E‰E
+PŠE˜Pè
+ƒÄ;Æt ÷EuƒMëŸ3À_^]ÃU‹ìƒìVWÇFþ‹>$#¾ä!ë÷DtVèbÿYÿFþƒÆ‹ÇO Àuç‹Fþ_^‹å]ÃU‹ìƒìVW‹vÇFþ‹ÞFŠŠÁ<ruº¿ë €ùwuºë€ùau º ÇFþ€¿ë3ÀëiŠ F€ù+t€<+u€ùtt€ùbu€ù+uŠ ƒâüƒÊÇFþ€¿€ùtuÊ@ë€ùbuÊ€ë¡N#%À Ћ©€tƒÏ@Çà! ‹^‰‹^‹Fþ‰‹Ç_^‹å]ÂU‹ìƒìV‹v
+ÿvFþPFüPè4ÿ‰D Àt €|}'ÿvü‹Fþ FPÿv苃ĈD
+À} ÆDÿÇD3ÀëAŠD˜Pè'òY ÀtL¸P÷Dt¸ë3ÀP3ÀPVèƒÄ ÀtVè›ýYëÂÇD ‹Æ^‹å]ÂV¾ä!€||¡$#±Óàä!‹ÖƒÆ;Âwç€||3Àë‹Æ^ÃU‹ìèÏÿ‹Ð Àu3Àë Rÿvÿv3ÀPè$ÿ]ÃU‹ì¸×PÿvÿvFPè¤ó]ÃU‹ìVW‹vƒ<}
+‹TB‹úë ‹™3Â+‹Ћø÷D@u,‹L
+ƒ<}ë I‹Ù€?
+uG‹ÂJ Àuðë‹ÙA€?
+uG‹ÂJ Àuð‹Ç_^]ÂU‹ìVW‹v‹~
+Vè7ýY Àt¸ÿÿëGƒÿuƒ<~ Vè|ÿ™)FVd_þÇ‹D‰D
+WÿvÿvŠD˜Pè‰ñƒÄƒúÿu
+=ÿÿu¸ÿÿë3À_^]ÃU‹ìƒìV‹v¸P3À3ÒPRŠD˜PèUñƒÄ‰Vþ‰Füƒúÿu=ÿÿu鄃<}tŠD˜Ñà‹Ø÷‡&#tW¸P3À3ÒPRŠD˜PèñƒÄ‰Vú‰Føƒúÿu=ÿÿtP3ÀPÿvþÿvüŠD˜PèôðƒÄƒúÿu =ÿÿuºÿÿ¸ÿÿë*‹Fú‹Vø‰Fþ‰VüVèþ™FüVþë Vèþ™)FüVþ‹Vþ‹Fü^‹å]ÃU‹ìVW‹~‹v‹NÑéüó¥s¤‹F_^]ÃU‹ì‹N´<‹VÍ!rëPè†ï]ÂU‹ì‹^+É+Ò´@Í!]ÂU‹ìƒìVW‹v‹~÷ÆÀu¡N#%À ð3ÀPÿvè¹ùYY‰Fþ÷Ætx#>P#‹Ç©€u¸Pè.ïƒ~þÿu#ƒ>T#t
+ÿ6T#èïéí÷Ç€t3À븉Fþë ÷Æt7¸PPëÜ÷Æðtÿv3ÀPèOÿ‹ø À}éµWèŒùYëÿvÿvþè6ÿ‹ø À}léœVÿvèYY‹ø À|Z3ÀPWè~öYY‰Fü©€tÎ ÷Æ€t%ÿ P¸PWè[öƒÄë
+÷ÆtWèþþ÷Fþt÷Æt÷Æðt¸PPÿvèÐøƒÄ ÿ|/÷Æt¸ë3À‹Öâÿø ÐR÷Fþt3Àë¸Z ЋßÑ㉗&#‹Ç_^‹å]ÃU‹ìƒì°‹N÷Áu
+°÷Áu°‹V±ð"N
+Á´=Í!r‰Fþ‹F%ÿ¸ €‹^þÑ㉇&#‹FþëPèÛí‹å]ÃU‹ì¡ë ;Æ$}ƒ>ë | ‹ë Ñã‹—f$ëºÃ&Rÿv¸Ñ&P¸"PèTüƒÄ]ÃU‹ì¸×P¸ô!PÿvFPèòï]ÃU‹ìV‹vÿ VŠF˜PèYY^]ÃU‹ìVW‹~ŠF¢<'ƒ=ÿ}:ÿ‹]
+ÿE
+ˆ÷Eué÷€><'
+t
+€><' téæWèžùY ÀuéÚ¸ÿÿéÙéÑ÷Eu÷EuƒMëãMƒ}tEƒ=t WèeùY ÀuÊ‹E÷؉‹]
+ÿE
+ <'ˆ÷Eu鈀><'
+t€><' uzWè2ùY Àtqë•ëmŠE˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè–íƒÄ€><'
+u÷E@u¸P¸Ú&PŠE˜PèOƒÄ=u¸P¸<'PŠE˜Pè7ƒÄ=t
+÷Eué=ÿ <'´_^]ÃU‹ì¸ô!PÿvèÌþYY]ÃU‹ìƒìVW‹~‹F‰Fþ÷Et)ëW‹^ÿFŠ˜Pè þYY=ÿÿu3ÀéY‹FÿN ÀuÜéI÷E@uéãƒ}uéš‹E;FsQƒ=t Wè=øY ÀuÅŠE˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè¥ìƒÄÿvÿvŠE˜PènƒÄ;Fuéâë…éÝ‹F|ƒ=u
+¸ÿÿ+E‰ë WèÛ÷Y Àté`ÿÿvÿvÿu
+è¦ûƒÄ‹F‰‹FE
+霊E˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè!ìƒÄÿvÿvŠE˜PèêƒÄ;Ftaéÿë\ƒ}t=ë/ÿ}‹]
+ÿE
+‹vÿFŠˆ´ëW‹^ÿFŠPèVýYY=ÿÿuéÊþ‹FÿN ÀuÇëÿvÿvŠE˜P膃Ä;Fté¥þ‹Fþ_^‹å]ÂU‹ìVW‹v‹~
+9tu ƒ~ÿÿv¸ÿÿ馃>Þ&uþô!uÇÞ&ëƒ>Ü&u þä!uÇÜ&ƒ<t¸P3À3ÒPRVèjùƒÄ÷Dtÿtè,òYƒdóÇD‹Æ‰D‰D
+ƒ~t> ÿv:ÇÞ!B ƒ~uWèÌòY‰F ÀuéuÿƒLëélÿ‹F‰D
+‰D‰|ƒ~uƒL3À_^]ÃU‹ìVWü‹~‹×2À¹ÿÿò®uÿ‹~¹ÿÿò®÷Ñ+ù‡÷÷Æt¤IÑéó¥s¤’_^]ÃU‹ìVWŒØŽÀü3À‹Ø‹~‹÷2À¹ÿÿò®÷Ñ‹þ‹vó¦ŠDÿŠ]ÿ+Ã_^]ÃU‹ìVWü‹~‹÷2À¹ÿÿò®÷Ñ‹~ó¤‹F_^]ÃU‹ìWŒØŽÀ‹~3Àü¹ÿÿò®‘÷ÐH_]ÃU‹ììˆVW‹~‹v;>$#r
+¸Pèééá‹F@=s3ÀéÓ‹ßÑã÷‡&#t¸P3À3ÒPRWèåéƒÄ‹ßÑã÷‡&#@uÿvVW訃Ä霋ßÑã§&#ÿý‰vú‹F‰FþëMÿNþ‹^úÿFúŠˆFý<
+uÆ FŠFýˆF†xÿ‹Ö+Ðú€|'+ðVPWè[ƒÄ‹Ð;Ætƒúÿu¸ÿÿë=‹F+Fþë1¶xÿƒ~þu©†xÿ+ð‹Æ Àv!V†xÿPWè ƒÄ‹Ð;ÆtƒúÿtÅ‹FÂ+Æë‹F_^‹å]ÃU‹ì‹^Ñã÷‡&#t¸Pë´@‹^‹N‹VÍ!rP‹^Ñã&#XëPèøç]ÃVW3ÿ¾ä!;>$#s÷DtVèÌóYƒÆG;>$#rê_^ÃVW¿¾ä!ë÷DtVè"ôYOƒÆ ÿuì_^ÃBorland C++ - Copyright 1991 Borland Intl.Divide error
+Abnormal program termination
+>'>'.open ..TSTwarning: %s
+ length double%d
+close .There are *.TST files, please remove
+..TST%d:w open unlink ok %d
+
+ valid chars = %d:%d %d:%d %d:%dignoring map %d->%d because of %d->%d
+ %d:%d %d
+‰‰‰ ä!
+ô!"C"B$"```  @ÿÿ),(((((),(((),#,*((((**#(#%(TMP.$$$(null)  
+
+   print scanf : floating point formats not linked
+\*.**.*È$Ð$è$%%%%7%G%\%n%‹%Ÿ%®%Â%Ï%Ð%ß%&&#&4&E&W&i&j&k&l&m&n&o&p&q&r&s&&’&¦&¸&¹&º&»&¼&½&¾&¿&À&Á&Â&0Error 0Invalid function numberNo such file or directoryPath not foundToo many open filesPermission deniedBad file numberMemory arena trashedNot enough memoryInvalid memory block addressInvalid environmentInvalid formatInvalid access codeInvalid dataNo such deviceAttempted to remove current directoryNot same deviceNo more filesInvalid argumentArg list too bigExec format errorCross-device linkMath argumentResult too largeFile already existsPossible deadlockUnknown error%s: %s
diff --git a/packaging/Caldera/OpenLinux/.cvsignore b/packaging/Caldera/OpenLinux/.cvsignore
new file mode 100644
index 00000000000..062afa2b04f
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/.cvsignore
@@ -0,0 +1,6 @@
+convertsmbpasswd.perl
+make_smbpasswd.perl
+makerpms.sh
+samba2.spec
+samba2.spec-lsb
+samba3.spec
diff --git a/packaging/Caldera/OpenLinux/README.Public b/packaging/Caldera/OpenLinux/README.Public
new file mode 100644
index 00000000000..00f41f37382
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/README.Public
@@ -0,0 +1,9 @@
+This directory is exported to any windows computer, if the daemon
+"SMB server processes (samba)" is started and the distributed
+configuration is used. So be careful about any data you put into
+this directory.
+
+The default configuration restricts the access rights to read only
+access.
+
+2000-03-13, Klaus Singvogel, Caldera (Deutschland) GmbH.
diff --git a/packaging/Caldera/OpenLinux/README.home b/packaging/Caldera/OpenLinux/README.home
new file mode 100644
index 00000000000..5a893eb0e12
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/README.home
@@ -0,0 +1,15 @@
+This directory $HOME/Samba is exported to any windows computer, if
+the daemon "SMB server processes (samba)" is started and the distributed
+configuration is used. So be careful about the data you put into this
+directory.
+
+Note: Only the user of this account can connect to this share. The
+shares name is equal to the users Linux account, e.g.
+\\your_linuxmachine\\your_linuxaccount
+
+If you want to have the files public accessible use the public browseable
+share instead. It's currently /srv/samba/Public, but have a look at file
+/etc/samba.d/smb.conf to get the latest name.
+
+
+2000-03-13, Klaus Singvogel, Caldera (Deutschland) GmbH.
diff --git a/packaging/Caldera/OpenLinux/README.profiles b/packaging/Caldera/OpenLinux/README.profiles
new file mode 100644
index 00000000000..b629e10966b
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/README.profiles
@@ -0,0 +1,10 @@
+This directory is used to store the roaming Profiles of your Windows
+users. For more information install the package samba-doc and read the
+file /usr/share/doc/packages/samba-2.0.7/docs/textdocs/DOMAIN.txt
+
+The default configuration sets the access rights to read/write for
+anyone. If you see a problem in this, disable the Profiles support in
+your samba configuration: either edit file /etc/samba.d/smb.conf or
+use swat (http://localhost:901/).
+
+2000-03-13, Klaus Singvogel, Caldera (Deutschland) GmbH.
diff --git a/packaging/Caldera/OpenLinux/findsmb b/packaging/Caldera/OpenLinux/findsmb
new file mode 100755
index 00000000000..986c2481779
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/findsmb
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/Caldera/OpenLinux/makerpms.sh.tmpl b/packaging/Caldera/OpenLinux/makerpms.sh.tmpl
new file mode 100644
index 00000000000..e7ba1d96230
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/makerpms.sh.tmpl
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Copyright (C) 1998 John H Terpstra, 2000 Klaus Singvogel
+#
+SPECDIR=${SPECDIR:-/usr/src/OpenLinux/SPECS}
+SRCDIR=${SRCDIR:-/usr/src/OpenLinux/SOURCES}
+USERID=`id -u`
+GRPID=`id -g`
+devel=0;
+old=0;
+
+# Do some argument parsing...
+if [ z$1 = z"devel" ]; then
+ devel=1;
+ shift
+fi
+if [ z$1 = z"old" ]; then
+ old=1;
+ shift
+fi
+
+# Start preparing the packages...
+if [ $devel -ne 0 ]; then
+ ( cd ../../../.. ; chown -R ${USERID}.${GRPID} samba; mv samba samba-PVERSION )
+ ( cd ../../../.. ; tar czvf ${SRCDIR}/samba-PVERSION.tar.gz samba-PVERSION; mv samba-PVERSION samba )
+else
+ ( cd ../../../.. ; chown -R ${USERID}.${GRPID} samba-PVERSION )
+ ( cd ../../../.. ; tar czvf ${SRCDIR}/samba-PVERSION.tar.gz samba-PVERSION )
+fi
+
+cp -af *.spec *.spec-lsb $SPECDIR
+for src in *.patch; do
+ trg=`echo $src | sed 's;xxxxxx;PVERSION;'`
+ cp -a $src $SRCDIR/$trg
+done
+
+# Start building the package
+cd $SPECDIR
+if [ $old -eq 0 ]; then
+mv -f samba2.spec samba2.spec-nonlsb
+ln -f samba2.spec-lsb samba2.spec
+fi
+rpm -ba -v samba2.spec
diff --git a/packaging/Caldera/OpenLinux/samba-3.0.0.pre-install.patch b/packaging/Caldera/OpenLinux/samba-3.0.0.pre-install.patch
new file mode 100644
index 00000000000..f6571a2763e
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba-3.0.0.pre-install.patch
@@ -0,0 +1,12 @@
+--- samba/source/script/installbin.sh.orig Mon Dec 13 14:27:43 1999
++++ samba/source/script/installbin.sh Fri Jun 16 15:06:13 2000
+@@ -34,7 +34,8 @@
+
+ # this is a special case, mount needs this in a specific location
+ if [ $p2 = smbmount ]; then
+- ln -sf $BINDIR/$p2 /sbin/mount.smbfs
++ cp -p $BINDIR/$p2 /sbin/mount.smbfs
++ ln -s /sbin/mount.smbfs $BINDIR/$p2
+ fi
+ done
+
diff --git a/packaging/Caldera/OpenLinux/samba.daemon b/packaging/Caldera/OpenLinux/samba.daemon
new file mode 100644
index 00000000000..96683702f5d
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba.daemon
@@ -0,0 +1,6 @@
+IDENT=samba
+DESCRIPTIVE="SMB server processes (samba)"
+CONFIGURED="no"
+ONBOOT="no"
+OPTIONS_SMB="-D"
+OPTIONS_NMB="-D"
diff --git a/packaging/Caldera/OpenLinux/samba.init b/packaging/Caldera/OpenLinux/samba.init
new file mode 100755
index 00000000000..1b830a1da3d
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba.init
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# description: Starts and stops the Samba smbd and nmbd daemons
+# used to provide SMB network services.
+
+NAME_S=smbd
+DAEMON_S=/usr/sbin/$NAME_S
+NAME_N=nmbd
+DAEMON_N=/usr/sbin/$NAME_N
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# See how we were called.
+case "$1" in
+ start)
+ [ -e $SVIlock ] && exit 1
+ [ ${NETWORKING} = "no" ] && exit 2
+ [ -x $DAEMON_S -a -x $DAEMON_N ] || exit 2
+
+ #[ "$CONFIGURED" != "no" -a "$CONFIGURED" != "false" ] || {
+ SVIemptyConfig /etc/samba.d/smb.conf && {
+ echo "$DESCRIPTIVE: not configured! Skipped..."
+ exit 2
+ }
+
+ echo -n "Starting $IDENT: "
+ ssd -S -n $NAME_S -x $DAEMON_S -- $OPTIONS_SMB
+ ssd -S -n $NAME_N -x $DAEMON_N -- $OPTIONS_NMB
+
+ echo "."
+ touch $SVIlock
+ ;;
+
+ stop)
+ [ -e $SVIlock ] || exit 0
+
+ echo -n "Stopping $IDENT: "
+ ssd -K -p /var/lock/samba.d/$NAME_N.pid -n $NAME_N #-x $DAEMON_N
+ ssd -K -p /var/lock/samba.d/$NAME_S.pid -n $NAME_S #-x $DAEMON_S
+
+ echo "."
+ rm -f $SVIlock
+ ;;
+
+ restart)
+ echo -n "Restarting $IDENT: "
+ $0 stop
+ $0 start
+ exit $?
+ ;;
+
+ *)
+ echo "Usage: $SVIscript {start|restart|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/packaging/Caldera/OpenLinux/samba.init-lsb b/packaging/Caldera/OpenLinux/samba.init-lsb
new file mode 100755
index 00000000000..f14eef648fa
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba.init-lsb
@@ -0,0 +1,108 @@
+#!/bin/bash
+#
+#
+### BEGIN INIT INFO
+# Provides: $samba
+# Required-Start: $network
+# Required-Stop: $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Description: samba
+# Starts and stops the Samba smbd and nmbd daemons
+# used to provide SMB network services.
+### END INIT INFO
+#
+# Written by Miquel van Smoorenburg <miquels@drinkel.ow.org>.
+# Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+# Modified for OpenLinux by Raymund Will <ray@caldera.de>
+# Adapted for samba by Klaus Singvogel <klaus@caldera.de>
+
+NAME_S=smbd
+DAEMON_S=/usr/sbin/$NAME_S
+NAME_N=nmbd
+DAEMON_N=/usr/sbin/$NAME_N
+
+# Source function library (and set vital variables).
+. @SVIdir@/functions
+
+status() {
+ [ -e $1 ] || return 3; # lock / pid file doesn't exist, seems to be stopped
+
+ i=`cat "$1"`
+ state=`egrep '^State' /proc/$i/status 2>/dev/null| sed 's#.* \(.\).*#\1#'`
+ if [ x$state = x -o x$state = xZ ]; then
+ return 2 # no such process (or zombie) --> dead
+ fi
+ return 0 # seems to be up and running
+}
+
+case "$1" in
+ start)
+ [ ! -e $SVIlock ] || exit 0
+ [ -x $DAEMON_S -a -x $DAEMON_N ] || exit 5
+ SVIemptyConfig /etc/samba.d/smb.conf && exit 6
+
+ echo -n "Starting $SVIsubsys services: "
+ ssd -S -n $NAME_S -x $DAEMON_S -- $OPTIONS_SMB
+ ssd -S -n $NAME_N -x $DAEMON_N -- $OPTIONS_NMB
+ ret=$?
+
+ echo "."
+ touch $SVIlock
+ ;;
+
+ stop)
+ [ -e $SVIlock ] || exit 0
+
+ echo -n "Stopping $SVIsubsys services: "
+ ssd -K -p /var/lock/samba.d/$NAME_N.pid -n $NAME_N #-x $DAEMON_N
+ ssd -K -p /var/lock/samba.d/$NAME_S.pid -n $NAME_S #-x $DAEMON_S
+
+ ret=$?
+
+ echo "."
+ rm -f $SVIlock
+ ;;
+
+ force-reload)
+ [ -e $SVIlock ] || exit 0
+ $0 restart
+ ret=$?
+ ;;
+
+ reload)
+ echo -n "Reloading $SVIsubsys service configuration: "
+ # nmbd has no config file to reload
+ ssd -K --signal 1 -p /var/lock/samba.d/$NAME_S.pid -n $NAME_S #-x $DAEMON_S
+ ret=$?
+ echo "."
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ret=$?
+ ;;
+
+ status)
+ echo -n "Checking status of $SVIsubsys service: "
+ status /var/lock/samba.d/$NAME_N.pid
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo -n "$NAME_N "
+ status /var/lock/samba.d/$NAME_S.pid
+ ret=$?
+ [ $ret -eq 0 ] && echo -n "$NAME_S"
+ fi
+ echo "."
+ ;;
+
+ *)
+ echo "Usage: $SVIscript {start|stop|restart|force-reload|reload|status}"
+ ret=2
+ ;;
+
+esac
+
+exit $ret
+
diff --git a/packaging/Caldera/OpenLinux/samba.logrotate b/packaging/Caldera/OpenLinux/samba.logrotate
new file mode 100644
index 00000000000..46611f83d8f
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba.logrotate
@@ -0,0 +1,12 @@
+/var/log/samba.d/nmbd {
+ postrotate
+ /usr/bin/killall -HUP nmbd
+ endscript
+}
+
+/var/log/samba.d/smbd {
+ postrotate
+ /usr/bin/killall -HUP smbd
+ endscript
+}
+
diff --git a/packaging/Caldera/OpenLinux/samba.pam b/packaging/Caldera/OpenLinux/samba.pam
new file mode 100644
index 00000000000..225ab724ec9
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba.pam
@@ -0,0 +1,11 @@
+#%PAM-1.0
+#[For version 1.0 syntax, the above header is optional]
+#
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_pwdb.so nullok nodelay # shadow audit
+# auth required /lib/security/pam_smbpass.so nodelay
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_pwdb.so # shadow md5
+#password required /lib/security/pam_smbpass.so nodelay smbconf=/etc/samba.d/smb.conf
diff --git a/packaging/Caldera/OpenLinux/samba2.spec-lsb.tmpl b/packaging/Caldera/OpenLinux/samba2.spec-lsb.tmpl
new file mode 100644
index 00000000000..7a2b921dd58
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba2.spec-lsb.tmpl
@@ -0,0 +1,506 @@
+%define Version PVERSION
+%define date PRELEASE
+%define Vendor Caldera
+%define Dist OpenLinux
+%define EtcSamba /etc/samba.d
+%define LSBservedir /srv/samba
+
+Name : samba
+Version : %{Version}
+Release : %{date}
+Group : Server/Network
+
+Summary : Samba SMB client and server.
+Summary(de) : Samba SMB Client und Server.
+Summary(es) : Cliente y servidor SMB Samba.
+Summary(fr) : Client et serveur SMB Samba.
+Summary(it) : Client e server SMB.
+Summary(pt) : Cliente e servidor SMB Samba.
+
+Copyright : Andrew Tridgell, John H Terpstra; GPL Version 2
+Packager : Klaus Singvogel <klaus@caldera.de>
+#Icon : Caldera-daemon.gif
+URL : http://samba.org/samba
+
+Requires : libpam >= 0.66, SysVinit-scripts >= 1.04-6
+
+
+BuildRoot : /tmp/%{Name}-%{Version}
+
+Source: ftp://ftp.samba.org/pub/samba/%{Name}-%{Version}.tar.gz
+#Patch0: %{Name}-%{Version}-smbmount.patch
+#Patch1: %{Name}-%{Version}-install.patch
+#Patch2: %{Name}-%{Version}-smbconf.patch
+
+%Package doc
+Group : Server/Network
+
+Summary : Documentation on SAMBA.
+Summary(de) : Die Dokumentation für Samba.
+Summary(es) : Documentation de SAMBA.
+Summary(fr) : Documentation pour Samba.
+Summary(it) : Documentazione su SAMBA.
+Summary(pt) : Documentação sobre o SAMBA.
+
+%Package -n smbfs
+Group : System/Network
+
+Summary : Mount and unmount commands for SMB filesystems (smbfs).
+Summary(de) : Mount und unmount für SMB-Dateisysteme (smbfs).
+Summary(es) : Comandos de montaje y desmontaje de sistemas de ficheros SMB (smbfs).
+Summary(fr) : Commandes pour le montage et le démontage des systèmes de fichiers SMB (smbfs).
+Summary(it) : Comandi per montare e smontare i file system SMB (smbfs).
+Summary(pt) : Comandos mount e unmount para o sistema de ficheiros SMB (smbfs).
+
+%Package -n swat
+Group : Administration/Network
+Requires : setup >= 2.0-2, tcp_wrappers, netkit-base >= 0.17-5
+
+Summary : Samba Web Administration Tool.
+Summary(de) : Das Samba Web Administrationstool.
+Summary(es) : Utilidad de administración Samba.
+Summary(fr) : Outil d'administration Internet pour Samba.
+Summary(it) : Strumento per l'amministrazione di Samba via Web.
+Summary(pt) : Ferramenta Web de administração de Samba (Samba Web Administration Tool).
+
+
+%Description
+Samba provides an SMB server which can be used to provide network
+services to SMB (sometimes called "Lan Manager") clients, including
+various versions of MS Windows, OS/2, and other Linux machines.
+
+%Description -l de
+Samba stellt einen SMB Server zur Verfügung, mit dem Netzwerkdienste für SMB
+(auch "Lan Manager" genannt) Clients bereitgestellt werden können. Dies
+schließt verschiedene Versionen von MS Windows, OS/2 und andere Linux
+Maschinen ein.
+
+%Description -l es
+Samba dispone de un servidor SMB que puede utilizarse para proporcionar
+servicios de red a clientes SMB (a veces conocido como "Lan Manager"),
+incluyendo varias versiones de MS Windows, OS/2 y otras máquinas Linux.
+
+%Description -l fr
+Samba fournit un serveur SMB qui peut être utilisé pour fournir des services
+de réseau aux clients SMB (parfois appelés "Lan Manager"), comportant
+diverses versions de MS Windows, OS/2 et d'autres machines Linux.
+
+%Description -l it
+Samba fornisce un server SMB che può essere usato per fornire servizi
+di rete a client SMB (talvolta chiamato "Lan Manager"), comprese varie
+versioni di MS Windows, OS/2 e altre macchine Linux.
+
+%Description -l pt
+O Samba fornece um servidor de SMB que pode ser usado para fornecer serviços de
+rede aos clientes de SMB (denominado por vezes como "Lan Manager"), incluindo
+várias versões do Windows, OS/2 e outras máquinas Linux.
+
+%Description doc
+This package contains extensive SAMBA documentation, including a FAQ,
+comprehensive usage documentation, and a number of examples.
+
+%Description -l de doc
+Dieses Paket enthält eine ausführliche SAMBA Dokumentation, inklusive
+einer FAQ, umfassender Gebrauchsdokumentation und einer Reihe von
+Beispielen.
+
+%Description -l es doc
+Este paquete contiene una extensa documentación sobre SAMBA, incluyendo
+FAQ (Preguntas de Uso Frecuente), documentación sobre el uso y algunos
+ejemplos.
+
+%Description -l fr doc
+Ce paquetage contient une documentation complète sur Samba, y compris
+une FAQ détaillée de son utilisation et un certain nombre d'exemples.
+
+%Description -l it doc
+Questo pacchetto contiene la documentazione su SAMBA tra cui una FAQ
+una esaustiva documentazione d'uso e un certo numero di esempi.
+
+%Description -l pt doc
+Este pacote contém alguma documentação extensa sobre o SAMBA, incluindo a FAQ,
+alguma documentação compreensiva sobre a utilização e alguns exemplos.
+
+%Description -n smbfs
+This package includes the tools necessary to mount filesystems from
+SMB servers.
+
+%Description -l de -n smbfs
+Dieses Paket enthält die nötigen Tools, um Dateisysteme von SMB-Servern
+zu mounten.
+
+%Description -l es -n smbfs
+este paqeute incluye las herramientas necesarias para montar sistemas de
+ficheros de servidores SMB.
+
+%Description -l fr -n smbfs
+Ce paquetage contient les outils nécessaires pour monter des systèmes
+de fichiers sur des serveurs SMB.
+
+%Description -l it -n smbfs
+Questo pacchetto contiene gli strumenti necessari per montare filesystem
+da server SMB.
+
+%Description -l pt -n smbfs
+Este pacote contém as ferramentas necessárias para montar sistema de
+ficheiros de servidores SMB.
+
+%Description -n swat
+SWAT allows a Samba administrator to configure the complex smb.conf
+file via a Web browser. It also provides links to all the configurable
+options in the smb.conf file allowing an administrator to easily look
+up the effects of any change.
+
+%Description -l de -n swat
+Mit SWAT kann ein Samba-Administrator die komplexe smb.conf
+Datei mit Hilfe eines Web-Browsers konfigurieren. Es stellt auch Links zu
+allen konfigurierbaren Optionen in der smb.conf Datei bereit, wodurch ein
+Administrator die Auswirkungen einer Änderung leicht nachvollziehen kann.
+
+%Description -l es -n swat
+SWAT permite a un administrador de Samba configurar el complejo fichero
+smb.conf mediante una navegador web. También proporciona enlaces a todas las
+opciones configurables en el fichero smb.conf, permitiendo al administrador
+comprobar fácilmente los efectos de cualquier cambio.
+
+%Description -l fr -n swat
+SWAT permet à un administrateur Samba de configurer le fichier smb.conf
+complexe via un navigateur Web. Il fournit également des liens d'aide pour
+toutes les options configurables dans le fichier smb.conf permettant à un
+administrateur de consulter aisément les effets d'une modification.
+
+%Description -l it -n swat
+SWAT permette ad un amministratore Samba di configurare il complesso file
+smb.conf attraverso un browser Web. SWAT ha anche dei link di aiuto per
+tutte le opzioni di configurazione del file smb.conf.
+
+%Description -l pt -n swat
+O SWAT permite a um administrador de Samba configurar o complexo ficheiro
+smb.conf através de uma interface Web. Fornece também referências para
+todas as opções configuraveis no smb.conf, permitindo a um admnistrador
+verificar rapidamente o efeite de qualquer alteração.
+
+
+%Prep
+%setup
+#%patch0 -p1
+#%patch1 -p1
+#%patch2 -p1
+
+# instead of patch (to help configuration) ... ;^)
+%{fixUP} -vbT source/Makefile.in -e '
+ s:we don.t use sbindir because we want:if you want : +
+ s:(the previous releases of Samba):$1, please use: +
+ s:(SBINDIR\s*=\s*\@)b:# ./configure --sbindir=\\\$(BINDIR)\n${1}sb: +
+ s:/log\.(\S+):/log/samba.d/${1}d: +
+ s:(PASSWD_PROGRAM\s*=\s*)(/bin):$1/usr$2:
+'
+# s:^(LIBS\s*=):AUTH_$1: +
+# s:((CLIENT|CUPS|NMBD|SMBD|SWAT|RPCCLIENT|SMBPASSWD|STATUS|TESTPRNS|TESTPARM)_OBJ\) )(\$\(LDF):$1\$(AUTH_LIBS) $3:
+
+for i in {cvs.,change-}log; do [ ! -f ../$i ] || mv ../$i source; done
+
+mv swat/help/welcome.html docs
+%{fixUP} -vT docs -e '
+ s:/usr/local/samba/bin/(smb(client|run)):/usr/bin/$1:g +
+ s:/usr/local/samba/bin/((s|n)mbd|swat|smbstatus):/usr/sbin/$1:g +
+ s:/usr/local/samba/var/locks:/var/lock/samba.d: +
+ s:/usr/local/samba/(var|lib)/log:/var/log/samba.d/smb: +
+ s:/usr/local/samba/swat:/usr/share/samba/swat:g +
+ s:/usr/local/samba/lib:%{EtcSamba}:g +
+ s:/usr/local/samba/printers:/var/spool/samba:g +
+ s:/usr/local/samba/private/smbpasswd:/usr/bin/smbpasswd:g +
+ s:/usr/local/samba/netlogon:%{LSBservedir}/netlogon:g;
+'
+mv docs/welcome.html swat/help
+for i in docs/*/smb.conf.5*; do
+ %{fixUP} -vT $i -e '
+ s:users\.map:smbusers:g +
+ s:SAMBA_INSTALL_DIRECTORY/lib:%{EtcSamba}: +
+ s:None \(set in compile\)\.:(see above).: +
+ s:/usr/local/:/usr/:g;
+ '
+done
+%{fixUP} -vT docs/textdocs/Faxing.txt -e '
+ s:/usr/local/etc/:/etc/: +
+ s:/usr/local/:/usr/:;
+'
+# ENCRYPTION.txt is gone.
+%{fixUP} -vT docs/docbook/projdoc/ENCRYPTION.sgml -e '
+ s:/usr/local/samba/private:%{EtcSamba}:g +
+ s:mksmbpasswd.sh:mksmbpasswd:g +
+ s:the Samba source directory:/usr/bin:;
+'
+
+%{fixUP} -vT docs/htmldocs/make_smbcodepage.1.html -e '
+ s:/usr/local/samba:/usr/bin/:g;
+'
+for i in htmldocs/DOMAIN_MEMBER.html htmldocs/Samba-HOWTO-Collection.html \
+ htmldocs/samba-pdc-faq.html htmldocs/samba-pdc-howto.html \
+ htmldocs/smbclient.1.html htmldocs/smbd.8.html \
+ docbook/projdoc/DOMAIN_MEMBER.sgml docbook/projdoc/DOMAIN_MEMBER.sgml \
+ docbook/faq/samba-pdc-faq.sgml docbook/howto/samba-pdc-howto.sgml \
+ docbook/manpages/smbclient.1.sgml docbook/manpages/smbd.8.sgml \
+ docbook/projdoc/ENCRYPTION.sgml manpages/smbclient.1 manpages/smbd.8 ; do
+%{fixUP} -vT docs/$i -e '
+ s:/usr/local/samba/private/FOREST.SLEEPY.SID:/var/lock/samba.d/FOREST.SLEEPY.SID: +
+ s:/usr/local/samba/private:/usr/bin:g +
+ s:/usr/local/samba/bin:/usr/bin:g +
+ s:/usr/local/sbin:/usr/sbin:g +
+ s:/usr/local/src/samba:/usr/src/samba:g ;'
+done
+%{fixUP} -vT docs/docbook/manpages/make_smbcodepage.1.sgml -e '
+ s:/usr/local/samba:/usr/bin:g ;
+'
+%{fixUP} -vT docs/htmldocs/samba-pdc-faq.html -e '
+ s:/usr/local/src:/usr/src:g ;
+'
+# End of DirtyHack(TM)
+
+
+%Build
+cd source
+autoreconf
+
+CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="-s" ./configure \
+ --with-fhs \
+ --prefix='$(DESTDIR)/usr' \
+ --localstatedir='$(DESTDIR)/var' \
+ --libdir='$(DESTDIR)%{EtcSamba}' \
+ --with-privatedir='$(LIBDIR)' \
+ --with-lockdir='$(DESTDIR)/var/lock/samba.d' \
+ --with-swatdir='$(DESTDIR)/usr/share/swat' \
+ --with-sambabook='$(DESTDIR)/usr/share/swat/using_samba' \
+ --with-configdir='$(DESTDIR)'%{EtcSamba} \
+ --with-codepagedir='$(DESTDIR)'/usr/share/samba/codepages \
+ --without-smbwrapper \
+ --with-smbmount \
+ --with-pam \
+ --with-pam_smbpass \
+ --with-netatalk \
+ --with-quotas \
+ --with-utmp \
+ --with-syslog
+
+make LOGFILEBASE=/var/log/samba.d all nsswitch/libnss_wins.so debug2html bin/smbspool
+
+
+%Install
+%{mkDESTDIR}
+VVS=packaging/%{Vendor}/%{Dist}
+
+mkdir -p $DESTDIR/etc/{{logrotate,pam}.d,sysconfig/daemons}
+mkdir -p $DESTDIR/var/{lo{ck,g}/samba.d,spool/samba}
+mkdir -p $DESTDIR/usr/share/swat/using_samba/{gifs,figs}
+mkdir -p $DESTDIR/lib/security
+mkdir -p $DESTDIR/%{LSBservedir}/{netlogon,profiles,Public}
+mkdir -p $DESTDIR/etc/skel/Samba
+mkdir -p $DESTDIR/usr/share/samba/codepages/src $DESTDIR/sbin
+mkdir -p $DESTDIR/%{SVIdir}
+
+make LOGFILEBASE=/var/log/samba.d -C source install
+
+strip $DESTDIR/usr/bin/smb{mnt,umount}
+#mv $DESTDIR/usr/bin/{make,add,conv}* $DESTDIR/usr/bin
+
+cp -p source/codepages/codepage_def.??? $DESTDIR/usr/share/samba/codepages/src
+
+# Install the nsswitch library extension file
+install -m 755 source/nsswitch/libnss_wins.so $DESTDIR/lib/libnss_wins.so.2.0
+# Make link for wins resolver
+ln -s libnss_wins.so.2.0 $DESTDIR/lib/libnss_wins.so.2
+ln -s libnss_wins.so.2.0 $DESTDIR/lib/libnss_wins.so
+
+# install -m 755 source/nsswitch/libnss_winbind.so $DESTDIR/lib/libnss_winbind.so.2.0
+# # Make link for winbind resolver
+# ln -s libnss_winbind.so.2.0 $DESTDIR/lib/libnss_winbind.so.2
+# ln -s libnss_winbind.so.2.0 $DESTDIR/lib/libnss_winbind.so
+
+# install -m 755 source/nsswitch/pam_winbind.so $DESTDIR/lib/security
+
+# install -m 755 source/bin/wbinfo $DESTDIR/usr/bin
+
+install -m 755 source/bin/debug2html $DESTDIR/usr/sbin/debug2html
+
+#lsb: cp -p $VVS/samba.init $DESTDIR/etc/rc.d/init.d/samba
+ln -s /etc/rc.d/init.d/samba $DESTDIR/usr/sbin
+
+cp -p $VVS/smb.conf.sample $DESTDIR%{EtcSamba}/smb.conf.sample
+cp -p $VVS/smb.conf $DESTDIR%{EtcSamba}/smb.conf
+cp -p $VVS/smbusers $DESTDIR%{EtcSamba}
+cp -p $VVS/smbprint $DESTDIR/usr/bin
+#cp -p $VVS/smbadduser.perl $DESTDIR/usr/bin/smbadduser
+#cp -p $VVS/make_smbpasswd.perl $DESTDIR/usr/bin/make_smbpasswd
+#cp -p $VVS/convertsmbpasswd.perl $DESTDIR/usr/bin/convertsmbpasswd
+#cp -p $VVS/updatesmbpasswd.perl $DESTDIR/usr/bin/updatesmbpasswd
+cp -p $VVS/findsmb $DESTDIR/usr/bin
+cp -p $VVS/samba.daemon $DESTDIR/etc/sysconfig/daemons/samba
+cp -p $VVS/samba.pam $DESTDIR/etc/pam.d/samba
+cp -p $VVS/samba.logrotate $DESTDIR/etc/logrotate.d/samba
+cp -p $VVS/README.home $DESTDIR/etc/skel/Samba/README.txt
+cp -p $VVS/README.Public $DESTDIR/%{LSBservedir}/Public/README.txt
+cp -p $VVS/README.profiles $DESTDIR/%{LSBservedir}/profiles/README.txt
+
+# Add PAM smbpass facility
+mv $DESTDIR/usr/bin/pam_smbpass.so $DESTDIR/lib/security
+
+install -m 755 $VVS/samba.init-lsb $DESTDIR/%{SVIdir}/%{Name}
+
+for f in testparm testprns; do
+ ln -s $f $DESTDIR/usr/bin/smb$f
+ ln -s $f.1 $DESTDIR/usr/man/man1/smb$f.1
+done
+#ln -s make_smbcodepage $DESTDIR/usr/bin/mksmbcodepage
+#ln -s make_smbpasswd $DESTDIR/usr/bin/mksmbpasswd
+#ln -sf convert_smbpasswd $DESTDIR/usr/bin/convertsmbpasswd
+ln -s ../usr/bin/smbmnt $DESTDIR/sbin/mount.smbfs
+
+
+cat <<-'EoH' > $DESTDIR%{EtcSamba}/lmhosts
+ 127.0.0.1 localhost
+EoH
+
+# lsb has new way of inetd configuration
+mkdir -p $DESTDIR%{NKinetdir}
+cat <<EoI >$DESTDIR%{NKinetdir}/swat
+swat stream tcp nowait.400 root /usr/sbin/tcpd swat
+EoI
+
+# -------------------- Documentation -------------------------------
+DOCD="$DESTDIR/%{_defaultdocdir}/samba-%{Version}"; mkdir -p $DOCD
+ln -sf ../Copyrights/GPL-2.0 $DOCD/COPYING
+#cp -p README README-smbmount Manifest Read-Manifest-Now $DOCD
+cp -p README Manifest Read-Manifest-Now $DOCD
+cp -p WHATSNEW.txt Roadmap $DOCD
+cp -a docs examples $DOCD
+
+mv $DOCD/docs/htmldocs/wfw_slip.htm $DOCD/docs/wfw_slip.html
+
+rm -rf $DOCD/docs/{htmldocs,manpages,yodldocs}
+rm -rf $DOCD/examples/{svr4-startup,printing}
+rm -rf $DOCD/CVS $DOCD/*/CVS $DOCD/*/*/CVS $DOCD/*/*/*/CVS
+
+cp -p swat/README $DOCD/README.swat
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba/gifs
+done
+
+# -------------------- Fixing final pathes -------------------------------
+
+%{fixUP} -T $DESTDIR/%{SVIdir} -e 's:\@SVIdir\@:%{SVIdir}:'
+%{fixUP} -vT $DOCD/examples -e 's:/usr/local/bin/:/usr/bin/:g;'
+%{fixUP} -vT $DESTDIR/%{EtcSamba} -e 's:\@samba_home\@:%{LSBservedir}:'
+
+%{fixManPages}
+
+%{mkLists} -c samba
+cat << 'EOF' | %{mkLists} -d samba
+Samba base
+%{LSBservedir} config-IGNORED
+^/(etc|var|home|tmp) config-IGNORED
+swat swat
+%{_defaultdocdir}/samba-[^/]+/$ base
+%{_defaultdocdir}/samba- doc
+tmp IGNORED
+man IGNORED
+lib/security IGNORED
+/src/$ IGNORED
+/usr/private/$ IGNORED
+@default@
+EOF
+cat << 'EOF' | %{mkLists} -f -a samba
+\.old$ IGNORED
+Samba/README.txt base
+^/etc config-IGNORED
+%{_defaultdocdir}/samba-[^/]+/(COPYING|README$) base
+libnss_wins.* base
+pam_smbpass.so base
+%{_defaultdocdir}/samba-[^/]+/(COPYING|README$) base
+%{_defaultdocdir}/samba- doc
+smb(mount|mnt|umount) smbfs
+mount.smbfs smbfs
+swat swat
+@default@
+EOF
+
+
+%Clean
+%{rmDESTDIR}
+
+
+%Post
+/usr/lib/LSB/init-install %{Name}
+
+
+%Post -n swat
+%{NKinetdReload}
+perl -pi -e '$s=1 if /^swat/;
+ print "swat:ALL EXCEPT 127.0.0.1\n" if eof && ! $s' /etc/hosts.deny
+
+
+%PostUn
+test "$1" = "0" || exit 0
+/usr/lib/LSB/init-remove %{Name}
+# We want to remove the browse.dat and wins.dat files so they can not
+# interfer with a new version of samba!
+rm -f /var/lock/samba/browse.dat
+rm -f /var/lock/samba/{brlock,connections,locking,messages}.tdb
+if [ -e /var/lock/samba.d/namelist.debug ]; then
+ rm -f /var/lock/samba.d/namelist.debug
+fi
+rm -f /var/lock/samba/unexpected.tdb
+rm -f /var/lock/samba/{smbd,nmbd}.pid
+
+# Note: We MUST keep:
+# winbindd_*, sshare_info*, printing*, ntdrivers*
+
+
+%PostUn -n swat
+#$no lsb: lisa --inetd disable swat $1
+test "$1" = "0" || exit 0
+%{SVIdir}/inet reload
+[ -x /usr/sbin/swat ]||perl -ni -e '/^swat\s*\:/||print' /etc/hosts.deny
+
+
+%Files -f files-samba-base
+%defattr(-,root,root)
+%config %attr(0755,root,root) %{SVIdir}/samba
+%config %attr(644,root,root) /etc/sysconfig/daemons/samba
+%config %attr(644,root,root) /etc/pam.d/samba
+%config %attr(644,root,root) /etc/logrotate.d/samba
+%config %attr(-,root,root) %{EtcSamba}
+%dir %attr(755,root,root) /var/lock/samba.d
+%dir %attr(755,root,root) /var/log/samba.d
+%dir %attr(1777,root,root) /var/spool/samba
+%dir %attr(755,root,root) %{LSBservedir}
+%dir %attr(755,root,root) %{LSBservedir}/netlogon
+%dir %attr(755,root,root) %{LSBservedir}/profiles
+%dir %attr(755,root,root) %{LSBservedir}/Public
+
+
+%Files doc -f files-samba-doc
+%defattr(-,root,root)
+
+
+%Files -n smbfs -f files-samba-smbfs
+%defattr(-,root,root)
+
+
+%Files -n swat -f files-samba-swat
+%defattr(-,root,root)
+%config %attr(644,root,root) %{NKinetdir}/swat
+
+%ChangeLog
+* Mon Jan 01 1997 ...
+$Id: samba2.spec-lsb.tmpl,v 1.3 2001/06/01 12:33:16 jerry Exp $
diff --git a/packaging/Caldera/OpenLinux/samba2.spec.tmpl b/packaging/Caldera/OpenLinux/samba2.spec.tmpl
new file mode 100644
index 00000000000..738b8c41e3d
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba2.spec.tmpl
@@ -0,0 +1,484 @@
+%define Version PVERSION
+%define date PRELEASE
+%define Vendor Caldera
+%define Dist OpenLinux
+%define EtcSamba /etc/samba.d
+%define _defaultdocdir /usr/doc
+%define LSBservedir /srv/samba
+
+Name : samba
+Version : %{Version}
+Release : %{date}
+Group : Server/Network
+
+Summary : Samba SMB client and server.
+Summary(de) : Samba SMB Client und Server.
+Summary(es) : Cliente y servidor SMB Samba.
+Summary(fr) : Client et serveur SMB Samba.
+Summary(it) : Client e server SMB.
+Summary(pt) : Cliente e servidor SMB Samba.
+
+Copyright : Andrew Tridgell, John H Terpstra; GPL Version 2
+Packager : Klaus Singvogel <klaus@caldera.de>
+#Icon : Caldera-daemon.gif
+URL : http://samba.org/samba
+
+Requires : libpam >= 0.66, SysVinit-scripts >= 1.04-6
+
+
+BuildRoot : /tmp/%{Name}-%{Version}
+
+Source: ftp://ftp.samba.org/pub/samba/%{Name}-%{Version}.tar.gz
+#Patch0: %{Name}-%{Version}-smbmount.patch
+#Patch1: %{Name}-%{Version}-install.patch
+#Patch2: %{Name}-%{Version}-smbconf.patch
+
+
+%Package doc
+Group : Server/Network
+
+Summary : Documentation on SAMBA.
+Summary(de) : Die Dokumentation für Samba.
+Summary(es) : Documentation de SAMBA.
+Summary(fr) : Documentation pour Samba.
+Summary(it) : Documentazione su SAMBA.
+Summary(pt) : Documentação sobre o SAMBA.
+
+
+%Package -n smbfs
+Group : System/Network
+
+Summary : Mount and unmount commands for SMB filesystems (smbfs).
+Summary(de) : Mount und unmount für SMB-Dateisysteme (smbfs).
+Summary(es) : Comandos de montaje y desmontaje de sistemas de ficheros SMB (smbfs).
+Summary(fr) : Commandes pour le montage et le démontage des systèmes de fichiers SMB (smbfs).
+Summary(it) : Comandi per montare e smontare i file system SMB (smbfs).
+Summary(pt) : Comandos mount e unmount para o sistema de ficheiros SMB (smbfs).
+
+
+
+%Package -n swat
+Group : Administration/Network
+Requires : setup >= 2.0-2, tcp_wrappers
+
+Summary : Samba Web Administration Tool.
+Summary(de) : Das Samba Web Administrationstool.
+Summary(es) : Utilidad de administración Samba.
+Summary(fr) : Outil d'administration Internet pour Samba.
+Summary(it) : Strumento per l'amministrazione di Samba via Web.
+Summary(pt) : Ferramenta Web de administração de Samba (Samba Web Administration Tool).
+
+
+%Description
+Samba provides an SMB server which can be used to provide network
+services to SMB (sometimes called "Lan Manager") clients, including
+various versions of MS Windows, OS/2, and other Linux machines.
+
+%Description -l de
+Samba stellt einen SMB Server zur Verfügung, mit dem Netzwerkdienste für SMB
+(auch "Lan Manager" genannt) Clients bereitgestellt werden können. Dies
+schließt verschiedene Versionen von MS Windows, OS/2 und andere Linux
+Maschinen ein.
+
+%Description -l es
+Samba dispone de un servidor SMB que puede utilizarse para proporcionar
+servicios de red a clientes SMB (a veces conocido como "Lan Manager"),
+incluyendo varias versiones de MS Windows, OS/2 y otras máquinas Linux.
+
+%Description -l fr
+Samba fournit un serveur SMB qui peut être utilisé pour fournir des services
+de réseau aux clients SMB (parfois appelés "Lan Manager"), comportant
+diverses versions de MS Windows, OS/2 et d'autres machines Linux.
+
+%Description -l it
+Samba fornisce un server SMB che può essere usato per fornire servizi
+di rete a client SMB (talvolta chiamato "Lan Manager"), comprese varie
+versioni di MS Windows, OS/2 e altre macchine Linux.
+
+%Description -l pt
+O Samba fornece um servidor de SMB que pode ser usado para fornecer serviços de
+rede aos clientes de SMB (denominado por vezes como "Lan Manager"), incluindo
+várias versões do Windows, OS/2 e outras máquinas Linux.
+
+%Description doc
+This package contains extensive SAMBA documentation, including a FAQ,
+comprehensive usage documentation, and a number of examples.
+
+%Description -l de doc
+Dieses Paket enthält eine ausführliche SAMBA Dokumentation, inklusive
+einer FAQ, umfassender Gebrauchsdokumentation und einer Reihe von
+Beispielen.
+
+%Description -l es doc
+Este paquete contiene una extensa documentación sobre SAMBA, incluyendo
+FAQ (Preguntas de Uso Frecuente), documentación sobre el uso y algunos
+ejemplos.
+
+%Description -l fr doc
+Ce paquetage contient une documentation complète sur Samba, y compris
+une FAQ détaillée de son utilisation et un certain nombre d'exemples.
+
+%Description -l it doc
+Questo pacchetto contiene la documentazione su SAMBA tra cui una FAQ
+una esaustiva documentazione d'uso e un certo numero di esempi.
+
+%Description -l pt doc
+Este pacote contém alguma documentação extensa sobre o SAMBA, incluindo a FAQ,
+alguma documentação compreensiva sobre a utilização e alguns exemplos.
+
+%Description -n smbfs
+This package includes the tools necessary to mount filesystems from
+SMB servers.
+
+%Description -l de -n smbfs
+Dieses Paket enthält die nötigen Tools, um Dateisysteme von SMB-Servern
+zu mounten.
+
+%Description -l es -n smbfs
+este paqeute incluye las herramientas necesarias para montar sistemas de
+ficheros de servidores SMB.
+
+%Description -l fr -n smbfs
+Ce paquetage contient les outils nécessaires pour monter des systèmes
+de fichiers sur des serveurs SMB.
+
+%Description -l it -n smbfs
+Questo pacchetto contiene gli strumenti necessari per montare filesystem
+da server SMB.
+
+%Description -l pt -n smbfs
+Este pacote contém as ferramentas necessárias para montar sistema de
+ficheiros de servidores SMB.
+
+%Description -n swat
+SWAT allows a Samba administrator to configure the complex smb.conf
+file via a Web browser. It also provides links to all the configurable
+options in the smb.conf file allowing an administrator to easily look
+up the effects of any change.
+
+%Description -l de -n swat
+Mit SWAT kann ein Samba-Administrator die komplexe smb.conf
+Datei mit Hilfe eines Web-Browsers konfigurieren. Es stellt auch Links zu
+allen konfigurierbaren Optionen in der smb.conf Datei bereit, wodurch ein
+Administrator die Auswirkungen einer Änderung leicht nachvollziehen kann.
+
+%Description -l es -n swat
+SWAT permite a un administrador de Samba configurar el complejo fichero
+smb.conf mediante una navegador web. También proporciona enlaces a todas las
+opciones configurables en el fichero smb.conf, permitiendo al administrador
+comprobar fácilmente los efectos de cualquier cambio.
+
+%Description -l fr -n swat
+SWAT permet à un administrateur Samba de configurer le fichier smb.conf
+complexe via un navigateur Web. Il fournit également des liens d'aide pour
+toutes les options configurables dans le fichier smb.conf permettant à un
+administrateur de consulter aisément les effets d'une modification.
+
+%Description -l it -n swat
+SWAT permette ad un amministratore Samba di configurare il complesso file
+smb.conf attraverso un browser Web. SWAT ha anche dei link di aiuto per
+tutte le opzioni di configurazione del file smb.conf.
+
+%Description -l pt -n swat
+O SWAT permite a um administrador de Samba configurar o complexo ficheiro
+smb.conf através de uma interface Web. Fornece também referências para
+todas as opções configuraveis no smb.conf, permitindo a um admnistrador
+verificar rapidamente o efeite de qualquer alteração.
+
+
+%Prep
+%setup
+#%patch0 -p1
+#%patch1 -p1
+#%patch2 -p1
+
+# instead of patch (to help configuration) ... ;^)
+%{fixUP} -vbT source/Makefile.in -e '
+ s:we don.t use sbindir because we want:if you want : +
+ s:(the previous releases of Samba):$1, please use: +
+ s:(SBINDIR\s*=\s*\@)b:# ./configure --sbindir=\\\$(BINDIR)\n${1}sb: +
+ s:/log\.(\S+):/log/samba.d/${1}d: +
+ s:(PASSWD_PROGRAM\s*=\s*)(/bin):$1/usr$2:
+'
+# s:^(LIBS\s*=):AUTH_$1: +
+# s:((CLIENT|CUPS|NMBD|SMBD|SWAT|RPCCLIENT|SMBPASSWD|STATUS|TESTPRNS|TESTPARM)_OBJ\) )(\$\(LDF):$1\$(AUTH_LIBS) $3:
+
+for i in {cvs.,change-}log; do [ ! -f ../$i ] || mv ../$i source; done
+
+mv swat/help/welcome.html docs
+%{fixUP} -vT docs -e '
+ s:/usr/local/samba/bin/(smb(client|run)):/usr/bin/$1:g +
+ s:/usr/local/samba/bin/((s|n)mbd|swat|smbstatus):/usr/sbin/$1:g +
+ s:/usr/local/samba/var/locks:/var/lock/samba.d: +
+ s:/usr/local/samba/(var|lib)/log:/var/log/samba.d/smb: +
+ s:/usr/local/samba/swat:/usr/share/samba/swat:g +
+ s:/usr/local/samba/lib:%{EtcSamba}:g +
+ s:/usr/local/samba/printers:/var/spool/samba:g +
+ s:/usr/local/samba/private/smbpasswd:/usr/bin/smbpasswd:g +
+ s:/usr/local/samba/netlogon:%{LSBservedir}/netlogon:g;
+'
+mv docs/welcome.html swat/help
+for i in docs/*/smb.conf.5*; do
+ %{fixUP} -vT $i -e '
+ s:users\.map:smbusers:g +
+ s:SAMBA_INSTALL_DIRECTORY/lib:%{EtcSamba}: +
+ s:None \(set in compile\)\.:(see above).: +
+ s:/usr/local/:/usr/:g;
+ '
+done
+%{fixUP} -vT docs/textdocs/Faxing.txt -e '
+ s:/usr/local/etc/:/etc/: +
+ s:/usr/local/:/usr/:;
+'
+%{fixUP} -vT docs/docbook/projdoc/ENCRYPTION.sgml -e '
+ s:/usr/local/samba/private:%{EtcSamba}:g +
+ s:mksmbpasswd.sh:mksmbpasswd:g +
+ s:the Samba source directory:/usr/bin:;
+'
+%{fixUP} -vT docs/htmldocs/make_smbcodepage.1.html -e '
+ s:/usr/local/samba:/usr/bin/:g;
+'
+for i in htmldocs/DOMAIN_MEMBER.html htmldocs/Samba-HOWTO-Collection.html \
+ htmldocs/samba-pdc-faq.html htmldocs/samba-pdc-howto.html \
+ htmldocs/smbclient.1.html htmldocs/smbd.8.html \
+ docbook/projdoc/DOMAIN_MEMBER.sgml htmldocs/DOMAIN_MEMBER.html \
+ docbook/faq/samba-pdc-faq.sgml docbook/howto/samba-pdc-howto.sgml \
+ docbook/manpages/smbclient.1.sgml docbook/manpages/smbd.8.sgml \
+ docbook/projdoc/ENCRYPTION.sgml manpages/smbclient.1 manpages/smbd.8 ; do
+%{fixUP} -vT docs/$i -e '
+ s:/usr/local/samba/private/FOREST.SLEEPY.SID:/var/lock/samba.d/FOREST.SLEEPY.SID: +
+ s:/usr/local/samba/private:/usr/bin:g +
+ s:/usr/local/samba/bin:/usr/bin:g +
+ s:/usr/local/sbin:/usr/sbin:g +
+ s:/usr/local/src/samba:/usr/src/samba:g ;'
+done
+%{fixUP} -vT docs/docbook/manpages/make_smbcodepage.1.sgml -e '
+ s:/usr/local/samba:/usr/bin:g ;
+'
+%{fixUP} -vT docs/htmldocs/samba-pdc-faq.html -e '
+ s:/usr/local/src:/usr/src:g ;
+'
+# End of DirtyHack(TM)
+
+
+%Build
+cd source
+autoreconf
+
+CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="-s" ./configure \
+ --prefix='$(DESTDIR)/usr' \
+ --localstatedir='$(DESTDIR)/var' \
+ --libdir='$(DESTDIR)%{EtcSamba}' \
+ --with-privatedir='$(LIBDIR)' \
+ --with-lockdir='$(DESTDIR)/var/lock/samba.d' \
+ --with-swatdir='$(DESTDIR)/usr/share/swat' \
+ --with-swatdir='$(DESTDIR)/usr/share/swat' \
+ --with-sambabook='$(DESTDIR)/usr/share/swat/using_samba' \
+ --with-configdir='$(DESTDIR)'%{EtcSamba} \
+ --with-codepagedir='$(DESTDIR)'/usr/share/samba/codepages \
+ --without-smbwrapper \
+ --with-smbmount \
+ --with-pam \
+ --with-pam_smbpass \
+ --with-netatalk \
+ --with-quotas \
+ --with-syslog \
+ --with-utmp
+
+make LOGFILEBASE=/var/log/samba.d all
+make LOGFILEBASE=/var/log/samba.d nsswitch/libnss_wins.so
+make LOGFILEBASE=/var/log/samba.d smbfilter debug2html
+make LOGFILEBASE=/var/log/samba.d bin/smbspool
+
+
+%Install
+%{mkDESTDIR}
+VVS=packaging/%{Vendor}/%{Dist}
+
+mkdir -p $DESTDIR/etc/{{rc.d/init,logrotate,pam}.d,sysconfig/daemons,skel/Samba}
+mkdir -p $DESTDIR/var/{lo{ck,g}/samba.d,spool/samba}
+mkdir -p $DESTDIR/usr/share/swat/using_samba/{gifs,figs}
+mkdir -p $DESTDIR/lib/security
+mkdir -p $DESTDIR/%{LSBservedir}/{netlogon,profiles,Public}
+mkdir -p $DESTDIR/usr/share/samba/codepages/src $DESTDIR/sbin
+
+make -C source install
+make LOGFILEBASE=/var/log/samba.d -C source install
+
+strip $DESTDIR/usr/bin/smb{mnt,umount}
+#mv $DESTDIR/usr/bin/{make,add,conv}* $DESTDIR/usr/sbin
+
+cp -p source/codepages/codepage_def.??? $DESTDIR/usr/share/samba/codepages/src
+
+# Install the nsswitch library extension file
+install -m 755 source/nsswitch/libnss_wins.so $DESTDIR/lib/libnss_wins.so.2.0
+# Make link for wins resolver
+ln -s libnss_wins.so.2.0 $DESTDIR/lib/libnss_wins.so.2
+ln -s libnss_wins.so.2.0 $DESTDIR/lib/libnss_wins.so
+
+# install -m 755 source/nsswitch/libnss_winbind.so $DESTDIR/lib/libnss_winbind.so.2.0
+# # Make link for winbind resolver
+# ln -s libnss_winbind.so.2.0 $DESTDIR/lib/libnss_winbind.so.2
+# ln -s libnss_winbind.so.2.0 $DESTDIR/lib/libnss_winbind.so
+
+# install -m 755 source/nsswitch/pam_winbind.so $DESTDIR/lib/security
+
+# install -m 755 source/bin/wbinfo $DESTDIR/usr/bin
+
+for f in debug2html smbfilter smbspool; do
+ install -m 755 source/bin/$f $DESTDIR/usr/sbin/$f
+done
+
+cp -p $VVS/samba.init $DESTDIR/etc/rc.d/init.d/samba
+ln -s /etc/rc.d/init.d/samba $DESTDIR/usr/sbin
+
+cp -p $VVS/smb.conf.sample $DESTDIR%{EtcSamba}/smb.conf.sample
+cp -p $VVS/smb.conf $DESTDIR%{EtcSamba}/smb.conf
+cp -p $VVS/smbusers $DESTDIR%{EtcSamba}
+cp -p $VVS/smbprint $DESTDIR/usr/bin
+#cp -p $VVS/smbadduser.perl $DESTDIR/usr/bin/smbadduser
+#cp -p $VVS/make_smbpasswd.perl $DESTDIR/usr/bin/make_smbpasswd
+#cp -p $VVS/convertsmbpasswd.perl $DESTDIR/usr/bin/convertsmbpasswd
+#cp -p $VVS/updatesmbpasswd.perl $DESTDIR/usr/bin/updatesmbpasswd
+cp -p $VVS/findsmb $DESTDIR/usr/bin
+cp -p $VVS/samba.daemon $DESTDIR/etc/sysconfig/daemons/samba
+cp -p $VVS/samba.pam $DESTDIR/etc/pam.d/samba
+cp -p $VVS/samba.logrotate $DESTDIR/etc/logrotate.d/samba
+cp -p $VVS/README.home $DESTDIR/etc/skel/Samba/README.txt
+cp -p $VVS/README.Public $DESTDIR/%{LSBservedir}/Public/README.txt
+cp -p $VVS/README.profiles $DESTDIR/%{LSBservedir}/profiles/README.txt
+
+# Add PAM smbpass facility
+mv $DESTDIR/usr/bin/pam_smbpass.so $DESTDIR/lib/security
+
+for f in testparm testprns; do
+ ln -s $f $DESTDIR/usr/bin/smb$f
+ ln -s $f.1 $DESTDIR/usr/man/man1/smb$f.1
+done
+ln -s make_smbcodepage $DESTDIR/usr/bin/mksmbcodepage
+#ln -s make_smbpasswd $DESTDIR/usr/bin/mksmbpasswd
+#ln -sf convert_smbpasswd $DESTDIR/usr/bin/convertsmbpasswd
+ln -s ../usr/bin/smbmnt $DESTDIR/sbin/mount.smbfs
+
+cat <<-'EoH' > $DESTDIR%{EtcSamba}/lmhosts
+ 127.0.0.1 localhost
+EoH
+
+
+DOCD="$DESTDIR/%{_defaultdocdir}/samba-%{Version}"; mkdir -p $DOCD
+ln -sf ../Copyrights/GPL-2.0 $DOCD/COPYING
+cp -p README README-smbmount Manifest Read-Manifest-Now $DOCD
+cp -p WHATSNEW.txt Roadmap $DOCD
+cp -a docs examples $DOCD
+
+mv $DOCD/docs/htmldocs/wfw_slip.htm $DOCD/docs/wfw_slip.html
+
+rm -rf $DOCD/docs/{htmldocs,manpages,yodldocs}
+rm -rf $DOCD/examples/{svr4-startup,printing}
+rm -rf $DOCD/CVS $DOCD/*/CVS $DOCD/*/*/CVS $DOCD/*/*/*/CVS
+
+cp -p swat/README $DOCD/README.swat
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif
+do
+install -m644 $i $DESTDIR/usr/share/swat/using_samba/gifs
+done
+
+%{fixUP} -vT $DOCD/examples -e 's:/usr/local/bin/:/usr/bin/:g;'
+%{fixUP} -vT $DESTDIR/etc/samba.d -e 's:\@samba_home\@:%{LSBservedir}:'
+
+%{fixManPages}
+
+%{mkLists} -c samba
+cat << 'EOF' | %{mkLists} -d samba
+Samba base
+%{LSBservedir} config-IGNORED
+^/(etc|var|home|tmp) config-IGNORED
+swat swat
+%{_defaultdocdir}/samba-[^/]+/$ base
+%{_defaultdocdir}/samba- doc
+tmp IGNORED
+man IGNORED
+@default@
+EOF
+cat << 'EOF' | %{mkLists} -f -a samba
+\.old$ IGNORED
+Samba/README.txt base
+^/etc config-IGNORED
+%{_defaultdocdir}/samba-[^/]+/(COPYING|README$) base
+libnss_wins.so base
+%{_defaultdocdir}/samba-[^/]+/(COPYING|README$) base
+%{_defaultdocdir}/samba- doc
+smb(mount|mnt|umount) smbfs
+mount.smbfs smbfs
+swat swat
+@default@
+EOF
+
+
+%Clean
+%{rmDESTDIR}
+
+
+%Post
+lisa --SysV-init install samba S91 3:4:5 K09 0:1:2:6
+
+
+%Post -n swat
+lisa --inetd install swat stream tcp nowait.400 root /usr/sbin/tcpd swat
+perl -pi -e '$s=1 if /^swat/;
+ print "swat:ALL EXCEPT 127.0.0.1\n" if eof && ! $s' /etc/hosts.deny
+
+
+%PostUn
+lisa --SysV-init remove samba $1
+# We want to remove the browse.dat and wins.dat files so they can not
+# interfer with a new version of samba!
+rm -f /var/lock/samba/{browse,wins}.dat
+
+
+%PostUn -n swat
+lisa --inetd disable swat $1
+[ -x /usr/sbin/swat ]||perl -ni -e '/^swat\s*\:/||print' /etc/hosts.deny
+
+
+%Files -f files-samba-base
+%defattr(-,root,root)
+%config %attr(755,root,root) /etc/rc.d/init.d/samba
+%config %attr(644,root,root) /etc/sysconfig/daemons/samba
+%config %attr(644,root,root) /etc/pam.d/samba
+%config %attr(644,root,root) /etc/logrotate.d/samba
+%config %attr(-,root,root) %{EtcSamba}
+%dir %attr(755,root,root) /var/lock/samba.d
+%dir %attr(755,root,root) /var/log/samba.d
+%dir %attr(1777,root,root) /var/spool/samba
+%dir %attr(755,root,root) %{LSBservedir}
+%dir %attr(755,root,root) %{LSBservedir}/netlogon
+%dir %attr(755,root,root) %{LSBservedir}/profiles
+%dir %attr(755,root,root) %{LSBservedir}/Public
+
+
+%Files doc -f files-samba-doc
+%defattr(-,root,root)
+
+
+%Files -n smbfs -f files-samba-smbfs
+%defattr(-,root,root)
+
+
+%Files -n swat -f files-samba-swat
+%defattr(-,root,root)
+
+
+%ChangeLog
+* Mon Jan 01 1997 ...
+$Id: samba2.spec.tmpl,v 1.3 2001/06/01 12:33:16 jerry Exp $
diff --git a/packaging/Caldera/OpenLinux/samba3.spec.tmpl b/packaging/Caldera/OpenLinux/samba3.spec.tmpl
new file mode 100644
index 00000000000..ab4e48649b9
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/samba3.spec.tmpl
@@ -0,0 +1,314 @@
+%define Version PVERSION
+%define date PRELEASE
+%define Vendor Caldera
+%define Dist OpenLinux
+%define EtcSamba /etc/samba.d
+
+Name : samba
+Version : %{Version}
+Release : %{date}
+Group : Server/Network
+
+Summary : Samba SMB client and server.
+
+Copyright : Andrew Tridgell, John H Terpstra; GPL Version 2
+Packager : Klaus Singvogel <klaus@caldera.de>
+Icon : Caldera-daemon.gif
+URL : http://samba.org/samba
+
+Requires : libpam >= 0.66, SysVinit-scripts >= 1.04-6
+
+
+BuildRoot : /tmp/%{Name}-%{Version}
+
+Source: ftp://ftp.samba.org/pub/samba/%{Name}-%{Version}%{date}.tar.gz
+#Patch0: %{Name}-%{Version}-smbmount.patch
+Patch1: %{Name}-%{Version}-install.patch
+#Patch2: %{Name}-%{Version}-smbconf.patch
+
+
+%Package doc
+Group : Server/Network
+
+Summary : Documentation on SAMBA.
+
+
+%Package -n smbfs
+Group : System/Network
+
+Summary : Mount and unmount commands for SMB filesystems (smbfs).
+
+
+%Package -n swat
+Group : Administration/Network
+Requires : setup >= 2.0-2, tcp_wrappers
+
+Summary : Samba Web Administration Tool.
+Samba provides an SMB server which can be used to provide
+network services to SMB (sometimes called "Lan Manager")
+clients, including various versions of MS Windows, OS/2,
+and other Linux machines. Samba also provides some SMB
+clients, which complement the built-in SMB filesystem
+in Linux. Samba uses NetBIOS over TCP/IP (NetBT) protocols
+and does NOT need NetBEUI (Microsoft Raw NetBIOS frame)
+protocol.
+
+Samba-2.2 features working NT Domain Control capability and
+includes the SWAT (Samba Web Administration Tool) that
+allows samba's smb.conf file to be remotely managed using your
+favourite web browser. For the time being this is being
+enabled on TCP port 901 via inetd.
+
+Users are advised to use Samba-2.2 as a Windows NT4
+Domain Controller only on networks that do NOT have a Windows
+NT Domain Controller. This release does NOT as yet have
+Backup Domain control ability.
+
+Please refer to the WHATSNEW.txt document for fixup information.
+This binary release includes encrypted password support.
+
+Please read the smb.conf file and ENCRYPTION.txt in the
+docs directory for implementation details.
+
+%Description
+
+NOTE: Caldera OpenLinux uses PAM which has integrated support
+for Shadow passwordsand for quotas. Do NOT recompile with the
+SHADOW_PWD option enabled.
+
+%Description doc
+Documentation on SAMBA.
+
+
+%Description -n smbfs
+This package includes the tools necessary to mount filesystems from
+SMB servers.
+
+Smbmount and smbumount are an interface to the SMB filesystem. Smbfs is
+a filesystem which understands the SMB protocol. This is the protocol
+Windows for Workgroups, Windows NT or Lan Manager use to talk to each
+other. It was inspired by samba, the program by Andrew Tridgell that
+turns any unix site into a file server for DOS or Windows clients. See
+http://samba.org/samba for this interesting program suite and lots of
+more information on SMB and NetBIOS over TCP/IP. There you also find
+explanation for conceps like NetBIOS name or share.
+
+
+%Description -n swat
+swat allows a Samba administrator to configure the complex smb.conf
+file via a Web browser. In addition, a swat configuration page has
+help links to all the configurable options in the smb.conf file
+allowing an administrator to easily look up the effects of any change.
+
+
+%Prep
+%setup -n samba
+#%%patch0 -p1
+%patch1 -p1
+#%patch2 -p1
+
+# instead of patch (to help configuration) ... ;^)
+%{fixUP} -vbT source/Makefile.in -e '
+ s:we don.t use sbindir because we want:if you want : +
+ s:(the previous releases of Samba):$1, please use: +
+ s:(SBINDIR\s*=\s*\@)b:# ./configure --sbindir=\\\$(BINDIR)\n${1}sb: +
+ s:/log\.(\S+):/log/samba.d/${1}d: +
+ s:(PASSWD_PROGRAM\s*=\s*)(/bin):$1/usr$2: +
+ s:^(LIBS\s*=):AUTH_$1: +
+ s:((SMBD|SWAT|RPCCLIENT|SMBPASSWD)_OBJ\) )(\$\(LDF):$1\$(AUTH_LIBS) $3:
+'
+
+for i in {cvs.,change-}log; do [ ! -f ../$i ] || mv ../$i source; done
+
+mv swat/help/welcome.html docs
+%{fixUP} -vT docs -e '
+ s:/usr/local/samba/bin/(smb(client|run)):/usr/bin/$1:g +
+ s:/usr/local/samba/bin/((s|n)mbd|swat):/usr/sbin/$1:g +
+ s:/usr/local/samba/var/locks:/var/lock/samba.d: +
+ s:/usr/local/samba/(var|lib)/log:/var/log/samba.d/smb: +
+ s:/usr/local/samba/swat:/usr/share/samba/swat:g +
+ s:/usr/local/samba/lib:%{EtcSamba}:g;
+'
+mv docs/welcome.html swat/help
+for i in docs/*/smb.conf.5*; do
+ %{fixUP} -vT $i -e '
+ s:users\.map:smbusers:g +
+ s:SAMBA_INSTALL_DIRECTORY/lib:%{EtcSamba}: +
+ s:None \(set in compile\)\.:(see above).: +
+ s:/usr/local/:/usr/:g;
+ '
+done
+%{fixUP} -vT docs/textdocs/Faxing.txt -e '
+ s:/usr/local/etc/:/etc/: +
+ s:/usr/local/:/usr/:;
+'
+%{fixUP} -vT docs/textdocs/ENCRYPTION.txt -e '
+ s:/usr/local/samba/private:%{EtcSamba}:g +
+ s:mksmbpasswd.sh:mksmbpasswd:g +
+ s:the Samba source directory:/usr/bin:;
+'
+# End of DirtyHack(TM)
+
+
+%Build
+cd source
+autoreconf
+
+CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="-s" ./configure \
+ --prefix='$(DESTDIR)/usr' \
+ --localstatedir='$(DESTDIR)/var' \
+ --libdir='$(DESTDIR)%{EtcSamba}' \
+ --with-privatedir='$(LIBDIR)' \
+ --with-lockdir='$(DESTDIR)/var/lock/samba.d' \
+ --with-swatdir='$(DESTDIR)/usr/share/swat' \
+ --with-smbmount --with-pam --without-smbwrapper \
+ --with-utmp --with-quotas --with-vfs --with-msdfs \
+ --with-profile --with-syslog --with-utmp --with-netatalk \
+ --with-sambabook=$(DESTDIR)/usr/share/swat/using_samba
+
+make all nsswitch/libnss_wins.so
+
+
+%Install
+%{mkDESTDIR}
+VVS=packaging/%{Vendor}/%{Dist}
+
+mkdir -p $DESTDIR/etc/{{rc.d/init,logrotate,pam}.d,sysconfig/daemons}
+mkdir -p $DESTDIR/var/{lo{ck,g}/samba.d,spool/samba}
+mkdir -p $DESTDIR/usr/{share,swat/using_samba}
+mkdir -p $DESTDIR/home/samba $DESTDIR%{EtcSamba}/codepages/src $DESTDIR/sbin
+
+make -C source install
+
+strip $DESTDIR/usr/bin/smb{mount,mnt,umount}
+mv $DESTDIR/usr/bin/{make,add,conv}* $DESTDIR/usr/sbin
+
+#cp -p source/codepages/codepage_def.??? $DESTDIR%{EtcSamba}/codepages/src
+
+# Install the nsswitch library extension file
+cp -p source/nsswitch/libnss_wins.so $DESTDIR/lib
+# Make link for wins resolver
+cd $DESTDIR/lib
+ln -s libnss_wins.so libnss_wins.so.2
+cd $RPM_BUILD_DIR
+
+cp -p $VVS/samba.init $DESTDIR/etc/rc.d/init.d/samba
+ln -s /etc/rc.d/init.d/samba $DESTDIR/usr/sbin
+
+cp -p $VVS/smb.conf.sample $DESTDIR%{EtcSamba}/smb.conf.sample
+#cp -p $VVS/smb.conf.sample $DESTDIR%{EtcSamba}/smb.conf
+cp -p $VVS/smbusers $DESTDIR%{EtcSamba}
+cp -p $VVS/smbprint $DESTDIR/usr/bin
+cp -p $VVS/smbadduser.perl $DESTDIR/usr/sbin/smbadduser
+cp -p $VVS/make_smbpasswd.perl $DESTDIR/usr/sbin/make_smbpasswd
+cp -p $VVS/convertsmbpasswd.perl $DESTDIR/usr/sbin/convertsmbpasswd
+cp -p $VVS/updatesmbpasswd.perl $DESTDIR/usr/sbin/updatesmbpasswd
+cp -p $VVS/findsmb $DESTDIR/usr/sbin
+cp -p $VVS/samba.daemon $DESTDIR/etc/sysconfig/daemons/samba
+cp -p $VVS/samba.pam $DESTDIR/etc/pam.d/samba
+cp -p $VVS/samba.logrotate $DESTDIR/etc/logrotate.d/samba
+
+for f in testparm testprns; do
+ ln -s $f $DESTDIR/usr/bin/smb$f
+ ln -s $f.1 $DESTDIR/usr/man/man1/smb$f.1
+done
+ln -s make_smbcodepage $DESTDIR/usr/sbin/mksmbcodepage
+ln -s make_smbpasswd $DESTDIR/usr/sbin/mksmbpasswd
+ln -sf convert_smbpasswd $DESTDIR/usr/sbin/convertsmbpasswd
+
+cat <<-'EoH' > $DESTDIR%{EtcSamba}/lmhosts
+ 127.0.0.1 localhost
+EoH
+
+
+DOCD="$DESTDIR/%{_defaultdocdir}/samba-%{Version}"; mkdir -p $DOCD
+ln -sf ../Copyrights/GPL-2.0 $DOCD/COPYING
+cp -p README Manifest Read-Manifest-Now WHATSNEW.txt Roadmap $DOCD
+cp -a docs examples $DOCD
+
+mv $DOCD/docs/htmldocs/wfw_slip.htm $DOCD/docs/wfw_slip.html
+
+rm -rf $DOCD/docs/{htmldocs,manpages,yodldocs}
+rm -rf $DOCD/examples/{svr4-startup,printing}
+
+cp -p swat/README $DOCD/README.swat
+
+%{fixUP} -vT $DOCD/examples -e 's:/usr/local/bin/:/usr/bin/:g;'
+
+%{fixManPages}
+
+%{mkLists} -c samba
+cat << 'EOF' | %{mkLists} -d samba
+^/(etc|var|home) config-IGNORED
+swat swat
+/usr/doc/samba-[^/]+/$ base
+/doc/samba- doc
+@default@
+EOF
+cat << 'EOF' | %{mkLists} -f -a samba
+^/etc config-IGNORED
+/doc/samba-[^/]+/(COPYING|README$) base
+/doc/samba- doc
+smb(mount|mnt|umount) smbfs
+mount.smbfs smbfs
+swat swat
+@default@
+EOF
+
+
+%Clean
+%{rmDESTDIR}
+
+
+%Post
+lisa --SysV-init install samba S91 3:4:5 K09 0:1:2:6
+
+
+%Post -n swat
+lisa --inetd install swat stream tcp nowait.400 root /usr/sbin/tcpd swat
+perl -pi -e '$s=1 if /^swat/;
+ print "swat:ALL EXCEPT 127.0.0.1\n" if eof && ! $s' /etc/hosts.deny
+
+
+%PostUn
+lisa --SysV-init remove samba $1
+# We want to remove the browse.dat and wins.dat files so they can not
+# interfer with a new version of samba!
+rm -f /var/lock/samba/{browse,wins}.dat
+
+
+%PostUn -n swat
+lisa --inetd disable swat $1
+[ -x /usr/sbin/swat ]||perl -ni -e '/^swat\s*\:/||print' /etc/hosts.deny
+
+
+%Files -f files-samba-base
+%defattr(-,root,root)
+%config %attr(755,root,root) /etc/rc.d/init.d/samba
+%config %attr(644,root,root) /etc/sysconfig/daemons/samba
+%config %attr(644,root,root) /etc/pam.d/samba
+%config %attr(644,root,root) /etc/logrotate.d/samba
+%config %attr(-,root,root) %{EtcSamba}
+%config %attr(755,root,root) /home/samba
+
+%dir %attr(755,root,root) /var/lock/samba.d
+%dir %attr(755,root,root) /var/log/samba.d
+%dir %attr(1777,root,root) /var/spool/samba
+#%dir %attr(775,root,nobody) /home/samba
+
+
+%Files doc -f files-samba-doc
+%defattr(-,root,root)
+
+
+%Files -n smbfs -f files-samba-smbfs
+%defattr(-,root,root)
+
+
+%Files -n swat -f files-samba-swat
+%defattr(-,root,root)
+
+
+%ChangeLog
+* Mon Jan 01 1997 ...
+
diff --git a/packaging/Caldera/OpenLinux/smb.conf b/packaging/Caldera/OpenLinux/smb.conf
new file mode 100644
index 00000000000..e62c7bf1e4c
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/smb.conf
@@ -0,0 +1,51 @@
+# Samba config file created using SWAT
+# from localhost (127.0.0.1)
+
+# Global parameters
+[global]
+ workgroup = MYGROUP
+ server string = Samba Server on Caldera OpenLinux
+ encrypt passwords = Yes
+ username map = /etc/samba.d/smbusers
+ password level = 8
+ username level = 8
+ log file = /var/log/samba.d/smb.%m
+ max log size = 200
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+ logon path = \\%L\Profiles\%U
+ dns proxy = No
+ printing = cups
+
+[homes]
+ comment = Home Directories
+ path = %H/Samba
+ username = %S
+ valid users = %S
+ writeable = Yes
+ create mask = 0750
+ only user = Yes
+ browseable = No
+
+[netlogon]
+ comment = Samba Network Logon Service
+ path = @samba_home@/netlogon
+ guest ok = Yes
+ share modes = No
+
+[profiles]
+ path = @samba_home@/profiles
+ writeable = Yes
+ guest ok = Yes
+ browseable = No
+
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ create mask = 0700
+ printable = Yes
+ browseable = No
+
+[public]
+ comment = Public Stuff
+ path = @samba_home@/Public
+ write list = @users
diff --git a/packaging/Caldera/OpenLinux/smb.conf.sample b/packaging/Caldera/OpenLinux/smb.conf.sample
new file mode 100644
index 00000000000..cec5a8a8b22
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/smb.conf.sample
@@ -0,0 +1,315 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server on Caldera OpenLinux
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# If you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ load printers = yes
+
+# you may wish to override the location of the printcap file
+; printcap name = /etc/printcap
+
+# It should not be necessary to specify the print system type unless
+# it is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+ printing = cups
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba.d/smb.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 200
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+ password level = 8
+ username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+ encrypt passwords = yes
+ smb passwd file = /etc/samba.d/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+ username map = /etc/samba.d/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/samba.d/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+ os level = 20
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+ logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+; this gives access to a 'Public' sub-directory in each user's home...
+; (it is named 'public' as it is intended to be used by other sharing
+; technologies (like NetWare, appletalk) too and may get disclosed due
+; to weak protocols! -- hmm, are there less secure protocols than NFS? :)
+ path = %H/Samba
+ valid users = %S
+ users = %S
+ only user = yes
+ browseable = no
+ writable = yes
+ create mask = 0750
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+[netlogon]
+ comment = Samba Network Logon Service
+ path = @samba_home@/netlogon
+ guest ok = yes
+ writable = no
+ share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+[profiles]
+ path = @samba_home@/profiles
+ writeable = yes
+ browseable = no
+ guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+ create mask = 0700
+
+# A publicly accessible directory, but read only, except for people in
+# the "users" group
+[public]
+ comment = Public Stuff
+ path = @samba_home@/public
+ browseable = yes
+ read only = yes
+ public = no
+ printable = no
+; writable = yes
+# access may be controlled by these options
+; read list = user1, user2, @group
+; valid users = user1, user3
+; write list = @users
+
+# Other examples.
+#
+# This one is useful for people to share files, BUT
+# access to '/tmp' or '/var/tmp' should *not* be given lightly,
+# as this can (still) pose a security threat!
+# Better use a dedicate sub-directory to /(var/)tmp or something
+# like a [public] share!
+[tmp]
+ comment = Temporary file space
+ path = /tmp
+ browseable = yes
+ read only = yes
+ public = no
+ printable = no
+
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Caldera/OpenLinux/smbadduser.perl b/packaging/Caldera/OpenLinux/smbadduser.perl
new file mode 100755
index 00000000000..61bec2320d9
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/smbadduser.perl
@@ -0,0 +1,146 @@
+#!/usr/bin/perl -w
+#
+# smbadduser - Written by Mike Zakharoff
+# perl-rewrite by Raymund Will
+#
+
+$smbpasswd = "/etc/samba.d/smbpasswd";
+$user_map = "/etc/samba.d/smbusers";
+#
+# Set to site specific passwd command
+#
+$passwd = "cat /etc/passwd |";
+#$passwd = "niscat passwd.org_dir |";
+if ( -e "/var/run/ypbind.pid" ) {
+ $passwd = "(cat /etc/passwd; ypcat passwd ) |";
+}
+
+$line = "-" x 58;
+if ($#ARGV < 0) {
+ print <<EoM;
+$line
+Written: Mike Zakharoff email: michael.j.zakharoff\@boeing.com
+
+ 1) Updates $smbpasswd
+ 2) Updates $user_map
+ 3) Executes smbpasswd for each new user
+
+smbadduser unixid[:ntid] unixid[:ntid] ...
+
+Example: smbadduser zak:zakharoffm jdoe johns:smithj
+$line
+EoM
+ exit 1;
+}
+
+# get valid UNIX-Ids (later skip missing)
+%U = ();
+{
+ my $X = "X" x 32;
+ my @t = ();
+
+ open( IN, $passwd) || die( "ERROR: open($passwd): $!\n");
+ while ( <IN> ) {
+ next unless (/^[A-Za-z0-9_]+:/);
+ @t = split(/:/);
+ $U{$t[0]} = join( ":", ($t[0], $t[2], $X, $X, $t[4], $t[5], $t[6]));
+ }
+ close( IN);
+}
+# get all smb passwords (later skip already existent)
+%S = ();
+$Cs = "";
+if ( -r $smbpasswd ) {
+ open( IN, $smbpasswd) || die( "ERROR: open($smbpasswd): $!\n");
+ while ( <IN> ) {
+ if ( /^\#/ ) {
+ $Cs .= $_; next;
+ } elsif ( ! /^([A-Za-z0-9_]+):/ ) {
+ chop; print STDERR "ERROR: $_: invalid smbpasswd entry!\n"; next;
+ }
+ $S{$1} = $_;
+ }
+ close( IN);
+}
+# get all map entries
+%M = ();
+$Cm = "";
+if ( -r $user_map ) {
+ open( IN, $user_map) || die( "ERROR: open($user_map): $!\n");
+ while ( <IN> ) {
+ if ( /^\#/ ) {
+ $Cm .= $_; next;
+ } elsif ( ! /^([A-Za-z0-9_]+)\s*=\s*(\S.+\S)\s*/ ) {
+ chop; print STDERR "ERROR: $_: invalid user-map entry!\n"; next;
+ }
+ $M{$1} = $2;
+ }
+ close( IN);
+}
+# check parameter syntax
+%N = ();
+{
+ foreach ( @ARGV ) {
+ my ( $u, $s, @R) = split(/:/);
+ if ( $#R >= 0 ) {
+ print STDERR "ERROR: $_: Must use unixid[:ntid] SKIPPING...\n";
+ next;
+ }
+ $s = $u unless ( defined( $s) );
+ if ( ! exists( $U{$u}) ) {
+ print STDERR "ERROR: $u: Not in passwd database SKIPPING...\n";
+ next;
+ }
+ if ( exists( $S{$u}) ) {
+ print STDERR "ERROR: $u: Already in smbpasswd database SKIPPING...\n";
+ next;
+ }
+ print "Adding: $u to $smbpasswd\n";
+ $S{$u} = $U{$u};
+ if ( $u ne $s ) {
+ if ( exists( $M{$u}) ) {
+ if ( $M{$u} !~ /\b$s\b/ ) {
+ print "Adding: $s to $u in $user_map\n";
+ $M{$u} .= " $s";
+ }
+ } else {
+ print "Mapping: $s to $u in $user_map\n";
+ $M{$u} = $s;
+ }
+ }
+ $N{$u} = $s;
+ }
+}
+# rewrite $smbpasswd
+{
+ open( OUT, "> $smbpasswd.new") || die( "ERROR: open($smbpasswd.new): $!\n");
+ $Cs = "#\n# SMB password file.\n#\n" unless ( $Cs );
+ print OUT $Cs;
+ foreach ( sort( keys( %S)) ) {
+ print OUT $S{$_};
+ }
+ close( OUT);
+ rename( $smbpasswd, $smbpasswd . "-");
+ rename( $smbpasswd . ".new", $smbpasswd) || die;
+}
+# rewrite $user_map
+{
+ open( OUT, "> $user_map.new") || die( "ERROR: open($user_map.new): $!\n");
+ $Cm = "# Unix_name = SMB_name1 SMB_name2 ...\n" unless ( $Cm );
+ print OUT $Cm;
+ foreach ( sort( keys( %M)) ) {
+ print OUT "$_ = $M{$_}\n";
+ }
+ close( OUT);
+ rename( $user_map, $user_map . "-");
+ rename( $user_map . ".new", $user_map) || die;
+}
+# call 'smbpasswd' for each new
+{
+ foreach ( sort( keys( %N)) ) {
+ print $line . "\n";
+ print "ENTER password for $_\n";
+ system( "smbpasswd $_");
+ }
+}
+
diff --git a/packaging/Caldera/OpenLinux/smbprint b/packaging/Caldera/OpenLinux/smbprint
new file mode 100755
index 00000000000..5d66aa13774
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to save space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "//$server/$service" $password -U $server -N -P >> $logfile 2>&1
diff --git a/packaging/Caldera/OpenLinux/smbusers b/packaging/Caldera/OpenLinux/smbusers
new file mode 100644
index 00000000000..ae3389f53f8
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nobody = guest pcguest smbguest
diff --git a/packaging/Caldera/OpenLinux/updatesmbpasswd.perl b/packaging/Caldera/OpenLinux/updatesmbpasswd.perl
new file mode 100755
index 00000000000..60f572b4905
--- /dev/null
+++ b/packaging/Caldera/OpenLinux/updatesmbpasswd.perl
@@ -0,0 +1,10 @@
+#!/usr/bin/perl -w
+while ( <> ) {
+ print;
+ @V = split(/:/);
+ $_ = $V[3];
+ if ( $V[0] !~ /^\#/ && !(/^[0-9A-F]{32}$/ || /^X{32}$/ || /^\*{32}$/) ) {
+ $V[3] = "X" x 32;
+ }
+ print( join( ':', @V));
+}
diff --git a/packaging/Caldera/OpenServer/Clean b/packaging/Caldera/OpenServer/Clean
new file mode 100755
index 00000000000..fe4eed25270
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Clean
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# Cleanup after having configured, compiled, installed and packaged.
+# Careful - running this script attempts to restore this hierarchy to
+# freshly unpacked source
+#
+# Invoke as "./Clean -n" to get this script to tell you what it would do
+# without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+[ -d dist ] && $V rm -rf dist
+[ -f ../../../source/Makefile ] && {
+ $V cd ../../../source
+ $V rm -f bin/locktest bin/masktest bin/smbsh bin/debug2html \
+ bin/locktest2 bin/smbfilter bin/smbtorture
+ $V make clean
+ $V make distclean
+ $V rm -f mout*
+}
diff --git a/packaging/Caldera/OpenServer/Compile b/packaging/Caldera/OpenServer/Compile
new file mode 100755
index 00000000000..cba414ec743
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Compile
@@ -0,0 +1,48 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+CC="gcc -I/usr/local/include -L/usr/local/lib"
+CFLAGS="-O3 -I/usr/local/include -L/usr/local/lib"
+CXX="g++"
+CXXFLAGS="-O3 -I/usr/local/include/stl -I/usr/local/include -L/usr/local/lib"
+RANLIB=true
+MAKE=/usr/local/bin/make
+if [ "$V" = "echo" ]
+then
+ echo "exporting the following shell variables:"
+ echo "CC=$CC"
+ echo "CXX=$CXX"
+ echo "RANLIB=$RANLIB"
+ echo "MAKE=$MAKE"
+ echo "CFLAGS=$CFLAGS"
+ echo "CXXFLAGS=$CXXFLAGS"
+else
+ export CC CXX RANLIB MAKE CFLAGS CXXFLAGS
+fi
+
+if [ "$V" = "echo" ]
+then
+ echo "cd ../../../source"
+ echo "rm -f mout-1 mout-2 mout-3 mout-4"
+ echo "make all 2>&1 | tee mout-1"
+ echo "make smbfilter smbtorture debug2html 2>&1 | tee mout-2"
+ echo "make bin/smbspool smbwrapper bin/wbinfo 2>&1 | tee mout-3"
+ echo "make masktest locktest locktest2 2>&1 | tee mout-3"
+else
+ cd ../../../source
+ rm -f mout-1 mout-2 mout-3 mout-4
+ make all 2>&1 | tee mout-1
+ make smbfilter smbtorture debug2html 2>&1 | tee mout-2
+ make bin/smbspool smbwrapper bin/wbinfo 2>&1 | tee mout-3
+ make masktest locktest locktest2 2>&1 | tee mout-3
+fi
+#
+# Not building :
+# nsswitch - no <nss.h>
+# rpctorture - improper use of client_info struct, dunno
diff --git a/packaging/Caldera/OpenServer/Configure b/packaging/Caldera/OpenServer/Configure
new file mode 100755
index 00000000000..65a4f1186fa
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Configure
@@ -0,0 +1,73 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+CC="gcc -I/usr/local/include -L/usr/local/lib"
+CFLAGS="-O3 -I/usr/local/include -L/usr/local/lib"
+CXX="g++"
+CXXFLAGS="-O3 -I/usr/local/include/stl -I/usr/local/include -L/usr/local/lib"
+RANLIB=true
+MAKE=/usr/local/bin/make
+PREFIX=/usr/local/samba
+if [ "$V" = "echo" ]
+then
+ echo "exporting the following shell variables:"
+ echo "CC=$CC"
+ echo "CXX=$CXX"
+ echo "RANLIB=$RANLIB"
+ echo "MAKE=$MAKE"
+ echo "CFLAGS=$CFLAGS"
+ echo "CXXFLAGS=$CXXFLAGS"
+ echo "PREFIX=$PREFIX"
+else
+ export CC CXX RANLIB MAKE CFLAGS CXXFLAGS PREFIX
+fi
+
+cd ../../../source
+[ -f mout-config ] && {
+ if [ "$V" = "echo" ]
+ then
+ echo "mv mout-config mout-config$$"
+ else
+ mv mout-config mout-config$$
+ fi
+}
+if [ "$V" = "echo" ]
+then
+ echo "./configure \
+ --prefix=${PREFIX} \
+ --with-profile \
+ --with-syslog \
+ --with-utmp \
+ --with-vfs \
+ --with-msdfs \
+ --with-netatalk \
+ --with-sambabook=${PREFIX}/swat/using_samba \
+ 2>&1 | tee mout-config"
+else
+ ./configure \
+ --prefix=${PREFIX} \
+ --with-profile \
+ --with-syslog \
+ --with-utmp \
+ --with-vfs \
+ --with-msdfs \
+ --with-netatalk \
+ --with-sambabook=${PREFIX}/swat/using_samba \
+ 2>&1 | tee mout-config
+fi
+
+cat >> include/config.h <<EOF
+#ifdef HAVE_LONGLONG
+#undef HAVE_LONGLONG
+#endif
+EOF
+
+sed -e "s/nobody/nouser/" include/local.h > /tmp/nouser$$
+cp /tmp/nouser$$ include/local.h
+rm -f /tmp/nouser$$
diff --git a/packaging/Caldera/OpenServer/Install b/packaging/Caldera/OpenServer/Install
new file mode 100755
index 00000000000..ab27b6f67fa
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Install
@@ -0,0 +1,156 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+# Make sure we pick up the install binary from /usr/local/bin
+# rather than /etc/install
+PATH=/usr/local/bin:$PATH
+export PATH
+
+PREFIX=/usr/local/samba
+HERE=`pwd`
+PKGDIR=packaging/Caldera/OpenServer
+
+BUILD_ROOT=${HERE}/dist
+BLDFIX=${BUILD_ROOT}/${PREFIX}
+$V rm -rf $BUILD_ROOT
+$V mkdir -p $BUILD_ROOT/etc/init.d
+$V mkdir -p ${BLDFIX}/bin
+$V mkdir -p ${BLDFIX}/sbin
+$V mkdir -p ${BLDFIX}/swat/using_samba/gifs
+$V mkdir -p ${BLDFIX}/swat/using_samba/figs
+$V mkdir -p ${BLDFIX}/swat/images
+$V mkdir -p ${BLDFIX}/swat/help
+$V mkdir -p ${BLDFIX}/swat/include
+$V mkdir -p ${BLDFIX}/man/man.1
+$V mkdir -p ${BLDFIX}/man/man.5
+$V mkdir -p ${BLDFIX}/man/man.7
+$V mkdir -p ${BLDFIX}/man/man.8
+$V mkdir -p ${BLDFIX}/var/locks
+$V mkdir -p ${BLDFIX}/lib/codepages/src
+
+# Copy into the dist tree the custom data files
+for i in Clean Install MakeSSO Packem Remove cdmt.config
+do
+ $V cp pkg/$i ${BUILD_ROOT}
+done
+for i in cntl input
+do
+ $V rm -rf ${BUILD_ROOT}/$i
+ $V cp -r pkg/$i ${BUILD_ROOT}/$i
+done
+
+cd ../../..
+
+# Install standard binary files
+for i in nmblookup smbclient smbpasswd smbstatus testparm testprns \
+ make_smbcodepage make_unicodemap make_printerdef rpcclient smbspool \
+ smbsh
+do
+$V install -m755 -s source/bin/$i ${BLDFIX}/bin
+done
+for i in mksmbpasswd.sh smbtar
+do
+$V install -m755 source/script/$i ${BLDFIX}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat debug2html smbtorture smbfilter locktest2 masktest
+do
+$V install -m755 -s source/bin/$i ${BLDFIX}/sbin
+done
+
+
+# Install level 1 man pages
+for i in *.1
+do
+$V install -m644 docs/manpages/$i ${BLDFIX}/man/man.1
+done
+
+# Install codepage source files
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+$V install -m644 source/codepages/codepage_def.$i ${BLDFIX}/lib/codepages/src
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+$V install -m644 source/codepages/CP$i.TXT ${BLDFIX}/lib/codepages/src
+done
+
+# Install SWAT helper files
+for i in swat/help/*.html docs/htmldocs/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/help
+done
+for i in swat/images/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/images
+done
+for i in swat/include/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/include
+done
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba/gifs
+done
+
+# Install the miscellany
+$V install -m644 swat/README ${BLDFIX}/swat
+$V install -m644 docs/manpages/smb.conf.5 ${BLDFIX}/man/man.5
+$V install -m644 docs/manpages/lmhosts.5 ${BLDFIX}/man/man.5
+$V install -m644 docs/manpages/smbpasswd.5 ${BLDFIX}/man/man.5
+$V install -m644 docs/manpages/samba.7 ${BLDFIX}/man/man.7
+$V install -m644 docs/manpages/smbd.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/nmbd.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/smbpasswd.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/swat.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/smbmount.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/smbmnt.8 ${BLDFIX}/man/man.8
+$V install -m644 docs/manpages/smbumount.8 ${BLDFIX}/man/man.8
+$V install -m644 ${PKGDIR}/smb.conf ${BLDFIX}/lib/smb.conf
+$V install -m644 ${PKGDIR}/smbusers $BUILD_ROOT/etc/smbusers
+$V install -m755 ${PKGDIR}/smbprint ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/findsmb ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/smbadduser ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/smb.init $BUILD_ROOT/etc/init.d/samba
+
+# The following is now done in the postinstall script
+#
+# if [ "$V" = "echo" ]
+# then
+# echo "echo 127.0.0.1 localhost > $BUILD_ROOT/etc/lmhosts"
+# else
+# echo 127.0.0.1 localhost > $BUILD_ROOT/etc/lmhosts
+# fi
+#
+# Build codepage load files
+# $V cd ${BLDFIX}/lib/codepages
+# for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+# do
+# $V ${PREFIX}/bin/make_smbcodepage c $i \
+# ${BLDFIX}/lib/codepages/src/codepage_def.$i \
+# ${BLDFIX}/lib/codepages/codepage.$i
+# done
+# for i in 437 737 850 852 861 866 932 936 949 950 \
+# ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+# do
+# $V ${PREFIX}/bin/make_unicodemap $i \
+# ${BLDFIX}/lib/codepages/src/CP$i.TXT \
+# ${BLDFIX}/lib/codepages/unicode_map.$i
+# done
diff --git a/packaging/Caldera/OpenServer/Makevol b/packaging/Caldera/OpenServer/Makevol
new file mode 100755
index 00000000000..dc57b246ef5
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Makevol
@@ -0,0 +1,10 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+./Configure $*
+./Compile $*
+./Install $*
+./Package $*
diff --git a/packaging/Caldera/OpenServer/Package b/packaging/Caldera/OpenServer/Package
new file mode 100755
index 00000000000..c954e55e1e8
--- /dev/null
+++ b/packaging/Caldera/OpenServer/Package
@@ -0,0 +1,13 @@
+#!/bin/ksh
+#
+# Now create the actual custom installable media images
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+$V cd dist
+$V ./MakeSSO
diff --git a/packaging/Caldera/OpenServer/README b/packaging/Caldera/OpenServer/README
new file mode 100644
index 00000000000..794bf546049
--- /dev/null
+++ b/packaging/Caldera/OpenServer/README
@@ -0,0 +1,44 @@
+Preparation Date: April 13, 2001
+Preparer: Ronald Joe Record <rr@sco.com>
+
+Instructions: Preparing Samba Packages for SCO OpenServer
+===============================================================
+
+We provide support only for current versions of SCO OpenServer
+
+The file samba-2.2-osr5.patch is a patch file suitable for use
+with the patch command as follows:
+
+ # cd ../../../source
+ # patch -p 0 -i ../packaging/Caldera/OpenServer/samba-2.2-osr5.patch
+
+The files modified by this patch are:
+ utils/torture.c
+ utils/locktest.c
+ utils/locktest2.c
+
+This patch should only be necessary until these changes are accepted
+back into the 2.2 source tree. Until then, this patch must be applied
+prior to building Samba 2.2 on SCO OpenServer 5.
+
+To produce the custom installable media images simply type (in this directory):
+ # ./Makevol
+
+The resultant samba media images should reside in the ./dist subdirectory.
+To install from the media images, issue the command (as root):
+
+ # cd dist
+ # ./Install
+
+Alternately, each of the steps in building the media images may be performed
+individually by invoking each of the following:
+
+ # ./Configure
+ # ./Compile
+ # ./Install
+ # ./Package
+
+If files are added or deleted from the SCO OpenServer Samba distribution then
+the prototype file in the pkg directory should be appropriately modified.
+The files in the pkg subdirectory were initially created using the mkpkg
+package from SCO Skunkware (see http://www.sco.com/skunkware).
diff --git a/packaging/Caldera/OpenServer/findsmb b/packaging/Caldera/OpenServer/findsmb
new file mode 100755
index 00000000000..bb91c784b89
--- /dev/null
+++ b/packaging/Caldera/OpenServer/findsmb
@@ -0,0 +1,141 @@
+#!/usr/local/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/local/samba/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/Caldera/OpenServer/pkg/Clean b/packaging/Caldera/OpenServer/pkg/Clean
new file mode 100755
index 00000000000..fa68f18118c
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/Clean
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm -rf archives sso usr
diff --git a/packaging/Caldera/OpenServer/pkg/Install b/packaging/Caldera/OpenServer/pkg/Install
new file mode 100755
index 00000000000..ef0f61f33e1
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/Install
@@ -0,0 +1 @@
+custom -p SKUNK2000:Samba -i -z `pwd`/archives/FLOPPY
diff --git a/packaging/Caldera/OpenServer/pkg/MakeSSO b/packaging/Caldera/OpenServer/pkg/MakeSSO
new file mode 100755
index 00000000000..538aaf58f77
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/MakeSSO
@@ -0,0 +1,25 @@
+:
+# MakeSSO
+#
+
+rm -rf archives sso
+
+ CDMT_DIR=`pwd`; export CDMT_DIR
+ Samba_DIR=`pwd`; export Samba_DIR
+ cdmtParse
+ if test $? != 0
+ then
+ exit 1
+ fi
+
+ cdmtCompress
+ if test $? != 0
+ then
+ exit 1
+ fi
+
+ cdmtArchive
+ if test $? != 0
+ then
+ exit 1
+ fi
diff --git a/packaging/Caldera/OpenServer/pkg/Packem b/packaging/Caldera/OpenServer/pkg/Packem
new file mode 100755
index 00000000000..a1b67e972d9
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/Packem
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+P=`pwd`
+PKGTAR=`basename $P`-VOLS.tar
+PKGDIST=`basename $P`-dist.tar.gz
+
+DIRS=usr
+[ -d etc ] && DIRS="etc usr"
+cd archives/FLOPPY
+tar cf ../../$PKGTAR VOL*
+cd ../..
+tar cf - $DIRS | /usr/local/bin/gzip -9 > $PKGDIST
+[ -f $PKGTAR ] && rm -rf archives
+[ -f $PKGDIST ] && rm -rf $DIRS
+rm -rf sso
diff --git a/packaging/Caldera/OpenServer/pkg/Remove b/packaging/Caldera/OpenServer/pkg/Remove
new file mode 100755
index 00000000000..ea6102ac38a
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/Remove
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# Generic command-line Software Manger (custom) removal from
+# media images. Based on the installation script by Phil Hollenback
+# (philiph@sco.com) and Ron Record (rr@sco.com)
+#
+
+# Set this to be the full pathname to the directory
+# where your media images are:
+VDIR=`pwd`/archives/FLOPPY
+VOLS=$VDIR/VOL.000.000
+
+component=`grep "component" < $VOLS | head -1 | cut -d= -f2 | cut -d: -f1`
+package=`grep "component" < $VOLS | head -1 | cut -d= -f2 | cut -d: -f2`
+
+custom -p $component:$package -r
diff --git a/packaging/Caldera/OpenServer/pkg/cdmt.config b/packaging/Caldera/OpenServer/pkg/cdmt.config
new file mode 100644
index 00000000000..e11c1961f22
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/cdmt.config
@@ -0,0 +1,34 @@
+MACROS:
+
+DEFAULT_EXEC_MODE = 0755
+
+DEFAULT_FILE_MODE = 0644
+DEFAULT_FILE_OWNER = bin
+DEFAULT_FILE_GROUP = bin
+
+DEFAULT_DIR_MODE = 0755
+DEFAULT_DIR_OWNER = bin
+DEFAULT_DIR_GROUP = bin
+
+DEFAULT_FIFO_MODE = 0644
+DEFAULT_FIFO_OWNER = bin
+DEFAULT_FIFO_GROUP = bin
+
+DEFAULT_DISTTREEROOT_SHARED = $CDMT_DIR
+DEFAULT_DISTTREEROOT_CLIENT = $CDMT_DIR
+
+CONFIG:
+ removeFiles = FALSE
+ removalPrompt = FALSE
+ archiveMedia = FLOPPY
+ compress = TRUE
+ ssoDir = sso
+
+FLOPPY_MEDIA:
+ device = /dev/rfd0
+ volumeSize = 8000
+ distVendor = SCO
+ distVersion = 2.2
+ distCode = SKUNK2000
+ paperLabel = "SCO Skunkware Samba 2.2"
+
diff --git a/packaging/Caldera/OpenServer/pkg/cntl/ccs b/packaging/Caldera/OpenServer/pkg/cntl/ccs
new file mode 100755
index 00000000000..0cb22490e47
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/cntl/ccs
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# Postinstallscript written by Ron Record (rr@sco.com)
+#
+
+scriptname="$0"
+step="$1"
+keywords="$2"
+pkglist="$3"
+
+# Source in the standard functions library, ccsSetup.sh
+. ccsSetup.sh
+
+ccs_return_value=0
+
+SPOOL=/var/spool/samba
+SVCS=/etc/services
+INET=/etc/inetd.conf
+LMHOST=/etc/lmhosts
+PREFIX=/usr/local/samba
+
+#
+# Create /var/spool/samba, create an initial /etc/lmhosts, build the
+# codepages and setup swat to be run out of inetd on port 901
+#
+PostExport()
+{
+ [ -d $SPOOL ] || {
+ mkdir -p $SPOOL
+ chmod 1777 $SPOOL
+ }
+ if [ -f $LMHOST ]
+ then
+ grep localhost $LMHOST > /dev/null || {
+ echo 127.0.0.1 localhost >> $LMHOST
+ }
+ else
+ echo 127.0.0.1 localhost > $LMHOST
+ fi
+
+ cd ${PREFIX}/lib/codepages
+ for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+ do
+ ${PREFIX}/bin/make_smbcodepage c $i \
+ ${PREFIX}/lib/codepages/src/codepage_def.$i \
+ ${PREFIX}/lib/codepages/codepage.$i
+ done
+ for i in 437 737 850 852 861 866 932 936 949 950 \
+ ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+ do
+ ${PREFIX}/bin/make_unicodemap $i \
+ ${PREFIX}/lib/codepages/src/CP$i.TXT \
+ ${PREFIX}/lib/codepages/unicode_map.$i
+ done
+
+ grep swat $SVCS > /dev/null || {
+ echo "swat 901/tcp # Samba Web Administration Tool " >> $SVCS
+ }
+
+ grep swat $INET > /dev/null || {
+ echo "swat stream tcp nowait root /usr/local/samba/bin/swat swat " >> $INET
+ }
+
+ kill -1 `ps -e | grep inetd | awk ' { print $1 } '`
+}
+
+DisableStop()
+{
+ /etc/init.d/samba disable > /dev/null 2>&1
+ /etc/init.d/samba stop > /dev/null 2>&1
+}
+
+#
+# Remove /var/spool/samba and delete inetd entries for swat
+#
+PostUnexport()
+{
+ [ -d $SPOOL ] && {
+ rm -rf $SPOOL
+ }
+
+ grep swat $SVCS > /dev/null && {
+ B=`basename $SVCS`
+ T=$B$$
+ grep -v swat $SVCS > /tmp/$T
+ cp /tmp/$T $SVCS
+ rm -f /tmp/$T
+ }
+
+ grep swat $INET > /dev/null || {
+ B=`basename $INET`
+ T=$B$$
+ grep -v swat $INET > /tmp/$T
+ cp /tmp/$T $INET
+ rm -f /tmp/$T
+ }
+
+ kill -1 `ps -e | grep inetd | awk ' { print $1 } '`
+}
+
+case "$step" in
+ POST_EXPORT) PostExport ;;
+ PRE_UNEXPORT) DisableStop ;;
+ POST_UNEXPORT) PostUnexport ;;
+esac
+
+exit $ccs_return_value
+
diff --git a/packaging/Caldera/OpenServer/pkg/input/Samba.cmpnt b/packaging/Caldera/OpenServer/pkg/input/Samba.cmpnt
new file mode 100644
index 00000000000..245f6d12ce8
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/input/Samba.cmpnt
@@ -0,0 +1,25 @@
+
+COMP:SKUNK2000:Samba:
+description = "Samba - A Windows SMB/CIFS fileserver for UNIX"
+version = 2.2
+subpackages = Samba
+required = Samba
+dependencies =
+distTreeRootSHARED = $Samba_DIR
+distTreeRootCLIENT = $Samba_DIR
+pkgFiles = $Samba_DIR/input/Samba.pkg
+
+FILE_DEFAULT:
+mode = $DEFAULT_FILE_MODE
+owner = $DEFAULT_FILE_OWNER
+group = $DEFAULT_FILE_GROUP
+
+DIR_DEFAULT:
+mode = $DEFAULT_DIR_MODE
+owner = $DEFAULT_DIR_OWNER
+group = $DEFAULT_DIR_GROUP
+
+FIFO_DEFAULT:
+mode = $DEFAULT_FIFO_MODE
+owner = $DEFAULT_FIFO_OWNER
+group = $DEFAULT_FIFO_GROUP
diff --git a/packaging/Caldera/OpenServer/pkg/input/Samba.pkg b/packaging/Caldera/OpenServer/pkg/input/Samba.pkg
new file mode 100644
index 00000000000..ea76e74a610
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/input/Samba.pkg
@@ -0,0 +1,1905 @@
+
+PKG:Control:
+description = "Control package"
+dependencies =
+distTreeRootSHARED = $Samba_DIR
+distTreeRootCLIENT = $Samba_DIR
+
+DIR:Control:SHARED:cntl:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Control:SHARED:cntl/ccs:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+PKG:Samba:
+description = "Samba - A Windows SMB/CIFS fileserver for UNIX"
+dependencies =
+distTreeRootSHARED = $Samba_DIR
+distTreeRootCLIENT = $Samba_DIR
+
+DIR:Samba:SHARED:etc:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:etc/init.d:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:etc/init.d/samba:
+mode = 0755
+owner = root
+group = sys
+flags =
+exportPath = /etc/init.d/samba
+
+FILE:Samba:SHARED:etc/smbusers:
+mode = 0644
+owner = root
+group = sys
+flags =
+exportPath = /etc/smbusers
+
+DIR:Samba:SHARED:usr:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba:
+mode = 0755
+owner = root
+group = sys
+flags =
+exportPath = /usr/local/samba
+
+DIR:Samba:SHARED:usr/local/samba/bin:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/nmblookup:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbclient:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbpasswd:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbstatus:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/testparm:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/testprns:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/make_smbcodepage:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/make_unicodemap:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/make_printerdef:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/rpcclient:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbspool:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbsh:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/mksmbpasswd.sh:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbtar:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbprint:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/findsmb:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/bin/smbadduser:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/sbin:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/smbd:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/nmbd:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/swat:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/debug2html:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/smbtorture:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/smbfilter:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/locktest2:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/sbin/masktest:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/using_samba:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/using_samba/gifs:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/gifs/index.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/gifs/samba.s.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/gifs/txthome.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/gifs/txtnexta.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/gifs/txtpreva.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/using_samba/figs:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0101.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0102.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0103.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0104.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0105.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0106.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0107.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0108.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0109.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0110.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0111.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0112.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0113.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0114.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0201.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0202.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0203.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0204.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0301.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0302.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0303.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0304.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0305.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0306.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0307.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0308.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0309.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0310.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0311.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0312.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0313.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0314.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0315.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0316.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0317.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0318.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0319.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0320.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0321.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0322.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0323.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0324.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0325.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0326.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0327.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0328.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0401.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0402.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0403.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0404.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0405.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0406.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0407.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0501.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0502.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0503.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0504.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0505.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0506.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0507.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0508.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0601.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0602.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0603.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0604.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0605.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0606.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0701.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0702.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0703.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0704.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0705.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0706.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0707.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0708.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0709.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0801.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0802.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0803.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0804.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0805.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0901.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0902.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0903.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0904.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.0905.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.aa01.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.ab01.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/figs/sam.ab02.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appa_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appa_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appa_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appa_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appa_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appb_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appb_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appb_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appc_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appd_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appe_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/appf_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_06.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_07.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch01_08.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch02_06.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch03_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch03_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch03_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_06.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_07.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch04_08.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch05_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch05_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch05_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch05_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch05_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch06_06.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch07_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch07_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch07_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_04.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_05.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_06.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch08_07.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch09_01.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch09_02.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/ch09_03.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/index.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/inx.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/licenseinfo.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/using_samba/this_edition.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/images:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/globals.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/home.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/passwd.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/printers.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/samba.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/shares.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/status.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/images/viewconfig.gif:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/help:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/welcome.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/DOMAIN_MEMBER.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/NT_Security.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/OS2-Client-HOWTO.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/Samba-HOWTO-Collection.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/UNIX_INSTALL.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/findsmb.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/lmhosts.5.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/make_smbcodepage.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/msdfs_setup.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/nmbd.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/nmblookup.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/printer_driver2.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/rpcclient.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/samba-pdc-faq.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/samba-pdc-howto.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/samba.7.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smb.conf.5.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbcacls.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbclient.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbcontrol.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbd.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbmnt.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbmount.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbpasswd.5.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbpasswd.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbrun.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbsh.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbspool.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbstatus.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbtar.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/smbumount.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/swat.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/testparm.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/testprns.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/wbinfo.1.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/winbind.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/help/winbindd.8.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/swat/include:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/include/footer.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/include/header.html:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/swat/README:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/man:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/man/man.1:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/findsmb.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/make_smbcodepage.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/make_unicodemap.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/nmblookup.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/rpcclient.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbcacls.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbclient.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbcontrol.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbrun.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbsh.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbstatus.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/smbtar.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/testparm.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/testprns.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.1/wbinfo.1:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/man/man.5:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.5/smb.conf.5:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.5/lmhosts.5:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.5/smbpasswd.5:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/man/man.7:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.7/samba.7:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/man/man.8:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/smbd.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/nmbd.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/smbpasswd.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/swat.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/smbmount.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/smbmnt.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/man/man.8/smbumount.8:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/var:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/var/locks:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/lib:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/lib/codepages:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+DIR:Samba:SHARED:usr/local/samba/lib/codepages/src:
+mode = 0755
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.437:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.737:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.775:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.850:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.852:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.861:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.866:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.932:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.936:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.949:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.950:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/codepage_def.1251:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP437.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP737.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP850.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP852.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP861.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP866.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP932.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP936.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP949.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CP950.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CPISO8859-1.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CPISO8859-2.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CPISO8859-5.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CPISO8859-7.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/codepages/src/CPKOI8-R.TXT:
+mode = 0644
+owner = root
+group = sys
+flags =
+
+FILE:Samba:SHARED:usr/local/samba/lib/smb.conf:
+mode = 0644
+owner = root
+group = sys
+flags =
diff --git a/packaging/Caldera/OpenServer/pkg/input/Samba.prd b/packaging/Caldera/OpenServer/pkg/input/Samba.prd
new file mode 100644
index 00000000000..e31c8bfe8e8
--- /dev/null
+++ b/packaging/Caldera/OpenServer/pkg/input/Samba.prd
@@ -0,0 +1,6 @@
+PROD:SKUNK2000:Samba:
+description = "Samba - A Windows SMB/CIFS fileserver for UNIX"
+version = 2.2
+packages = SKUNK2000:Samba
+required = SKUNK2000:Samba
+cmpntFiles = Samba.cmpnt
diff --git a/packaging/Caldera/OpenServer/samba-2.2-osr5.patch b/packaging/Caldera/OpenServer/samba-2.2-osr5.patch
new file mode 100644
index 00000000000..fb71d9298b4
--- /dev/null
+++ b/packaging/Caldera/OpenServer/samba-2.2-osr5.patch
@@ -0,0 +1,29 @@
+--- utils/torture.c.00 Fri Mar 30 13:53:26 2001
++++ utils/torture.c Fri Apr 13 15:06:04 2001
+@@ -2703,7 +2703,11 @@
+
+ dbf = stdout;
+
++#if defined(_SCO_DS) /* SCO OpenServer */
++ setvbuf(stdout, NULL, _IONBF, 0);
++#else
+ setbuffer(stdout, NULL, 0);
++#endif
+
+ charset_initialise();
+
+--- utils/locktest.c.00 Fri Sep 29 13:18:14 2000
++++ utils/locktest.c Fri Apr 13 17:54:11 2001
+@@ -384,8 +384,12 @@
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
++#if defined(_SCO_DS) /* OpenServer */
++ recorded[n].len = 1;
++#else
+ recorded[n].len = 1 +
+ random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
++#endif
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ recorded[n].r1 = random() % 100;
diff --git a/packaging/Caldera/OpenServer/smb.conf b/packaging/Caldera/OpenServer/smb.conf
new file mode 100644
index 00000000000..717c4efb174
--- /dev/null
+++ b/packaging/Caldera/OpenServer/smb.conf
@@ -0,0 +1,291 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = lpstat
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+ printing = sysv
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nouser" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /usr/local/samba/var/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; writable = yes
+; printable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Caldera/OpenServer/smb.init b/packaging/Caldera/OpenServer/smb.init
new file mode 100755
index 00000000000..ce6c6fa4b38
--- /dev/null
+++ b/packaging/Caldera/OpenServer/smb.init
@@ -0,0 +1,76 @@
+#!/bin/sh
+#ident "@(#)samba.server 1.0 96/06/19 TK" /* SVr4.0 1.1.13.1*/
+#
+# Please send info on modifications to knuutila@cs.utu.fi
+#
+# This file should have uid root, gid sys and chmod 744
+#
+# Modified 17-Jul-99 by Ron Record (rr@sco.com) for use in SCO Skunkware
+#
+
+SAMBADIR=/usr/local/samba
+RCSCRIPT=/etc/rc2.d/S99samba
+
+if [ ! -d /usr/bin ]
+then # /usr not mounted
+ exit
+fi
+
+killproc() { # kill the named process(es)
+ if [ -f $SAMBADIR/var/locks/$1.pid ]
+ then
+ kill `cat $SAMBADIR/var/locks/$1.pid`
+ else
+ pid=`/usr/bin/ps -e |
+ /usr/bin/grep $1 |
+ /usr/bin/sed -e 's/^ *//' -e 's/ .*//'`
+ [ "$pid" != "" ] && kill $pid
+ fi
+}
+
+start() {
+#
+# Edit these lines to suit your installation (paths, workgroup, host)
+#
+ $SAMBADIR/sbin/smbd -D -s $SAMBADIR/lib/smb.conf
+ $SAMBADIR/sbin/nmbd -D -s $SAMBADIR/lib/smb.conf
+}
+
+stop() {
+ killproc nmbd
+ killproc smbd
+}
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+'start')
+ start
+ ;;
+'stop')
+ stop
+ ;;
+'restart')
+ stop
+ start
+ ;;
+'enable')
+ if [ -h $RCSCRIPT ] ; then
+ echo "Samba is already enabled."
+ else
+ echo "Enabling Samba ... \c"
+ rm -f $RCSCRIPT
+ ln -s /etc/init.d/samba $RCSCRIPT
+ echo "Done"
+ fi
+ ;;
+'disable')
+ echo "Disabling Samba ... \c"
+ rm -f $RCSCRIPT
+ echo "Done"
+ ;;
+*)
+ echo "Usage: /etc/init.d/samba { start | stop | restart | enable | disable }"
+ ;;
+esac
diff --git a/packaging/Caldera/OpenServer/smbadduser b/packaging/Caldera/OpenServer/smbadduser
new file mode 100755
index 00000000000..2f38bf28f1a
--- /dev/null
+++ b/packaging/Caldera/OpenServer/smbadduser
@@ -0,0 +1,73 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+unalias *
+set path = ($path)
+
+set smbpasswd = /etc/smbpasswd
+set user_map = /etc/smbusers
+#
+# Set to site specific passwd command
+#
+set passwd = "cat /etc/passwd"
+#set passwd = "niscat passwd.org_dir"
+#set passwd = "ypcat passwd"
+
+set line = "----------------------------------------------------------"
+if ($#argv == 0) then
+ echo $line
+ echo "Written: Mike Zakharoff email: michael.j.zakharoff@boeing.com"
+ echo ""
+ echo " 1) Updates $smbpasswd"
+ echo " 2) Updates $user_map"
+ echo " 3) Executes smbpasswd for each new user"
+ echo ""
+ echo "smbadduser unixid:ntid unixid:ntid ..."
+ echo ""
+ echo "Example: smbadduser zak:zakharoffm johns:smithj"
+ echo $line
+ exit 1
+endif
+
+touch $smbpasswd $user_map
+set new = ()
+foreach one ($argv)
+ echo $one | grep ':' >& /dev/null
+ if ($status != 0) then
+ echo "ERROR: Must use unixid:ntid like -> zak:zakharoffm"
+ continue
+ endif
+ set unix = `echo $one | awk -F: '{print $1}'`
+ set ntid = `echo $one | awk -F: '{print $2}'`
+
+ set usr = `eval $passwd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#usr != 1) then
+ echo "ERROR: $unix Not in passwd database SKIPPING..."
+ continue
+ endif
+ set tmp = `cat $smbpasswd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#tmp != 0) then
+ echo "ERROR: $unix is already in $smbpasswd SKIPPING..."
+ continue
+ endif
+
+ echo "Adding: $unix to $smbpasswd"
+ eval $passwd | \
+ awk -F: '$1==USR { \
+ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }' USR=$unix >> $smbpasswd
+ if ($unix != $ntid) then
+ echo "Adding: {$unix = $ntid} to $user_map"
+ echo "$unix = $ntid" >> $user_map
+ endif
+ set new = ($new $unix)
+end
+
+#
+# Enter password for new users
+#
+foreach one ($new)
+ echo $line
+ echo "ENTER password for $one"
+ smbpasswd $one
+end
diff --git a/packaging/Caldera/OpenServer/smbprint b/packaging/Caldera/OpenServer/smbprint
new file mode 100755
index 00000000000..ec083eede62
--- /dev/null
+++ b/packaging/Caldera/OpenServer/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to same space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/packaging/Caldera/OpenServer/smbusers b/packaging/Caldera/OpenServer/smbusers
new file mode 100644
index 00000000000..08f611826ab
--- /dev/null
+++ b/packaging/Caldera/OpenServer/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nouser = guest pcguest smbguest
diff --git a/packaging/Caldera/UnixWare/Clean b/packaging/Caldera/UnixWare/Clean
new file mode 100755
index 00000000000..fe4eed25270
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Clean
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# Cleanup after having configured, compiled, installed and packaged.
+# Careful - running this script attempts to restore this hierarchy to
+# freshly unpacked source
+#
+# Invoke as "./Clean -n" to get this script to tell you what it would do
+# without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+[ -d dist ] && $V rm -rf dist
+[ -f ../../../source/Makefile ] && {
+ $V cd ../../../source
+ $V rm -f bin/locktest bin/masktest bin/smbsh bin/debug2html \
+ bin/locktest2 bin/smbfilter bin/smbtorture
+ $V make clean
+ $V make distclean
+ $V rm -f mout*
+}
diff --git a/packaging/Caldera/UnixWare/Compile b/packaging/Caldera/UnixWare/Compile
new file mode 100755
index 00000000000..2867e4d5ad5
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Compile
@@ -0,0 +1,52 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+CC="cc -Kthread -Kalloca -I/usr/local/include -L/usr/local/lib"
+CPP="$CC -E"
+CFLAGS="-Xa -Dasm=__asm -DANSICPP -O3"
+LDFLAGS="-L/usr/local/lib"
+CXX="CC -I/usr/local/include"
+CXXFLAGS="-O3 -I/usr/local/include/stl -L/usr/local/lib"
+RANLIB=true
+MAKE=/usr/local/bin/make
+if [ "$V" = "echo" ]
+then
+ echo "exporting the following shell variables:"
+ echo "CC=$CC"
+ echo "CPP=$CPP"
+ echo "CXX=$CXX"
+ echo "RANLIB=$RANLIB"
+ echo "MAKE=$MAKE"
+ echo "CFLAGS=$CFLAGS"
+ echo "CXXFLAGS=$CXXFLAGS"
+ echo "LDFLAGS=$LDFLAGS"
+else
+ export CC CPP CXX RANLIB MAKE CFLAGS CXXFLAGS LDFLAGS
+fi
+
+if [ "$V" = "echo" ]
+then
+ echo "cd ../../../source"
+ echo "rm -f mout-1 mout-2 mout-3 mout-4"
+ echo "make all 2>&1 | tee mout-1"
+ echo "make smbfilter smbtorture debug2html 2>&1 | tee mout-2"
+ echo "make bin/smbspool smbwrapper bin/wbinfo 2>&1 | tee mout-3"
+ echo "make masktest locktest locktest2 2>&1 | tee mout-3"
+else
+ cd ../../../source
+ rm -f mout-1 mout-2 mout-3 mout-4
+ make all 2>&1 | tee mout-1
+ make smbfilter smbtorture debug2html 2>&1 | tee mout-2
+ make bin/smbspool smbwrapper bin/wbinfo 2>&1 | tee mout-3
+ make masktest locktest locktest2 2>&1 | tee mout-3
+fi
+#
+# Not building :
+# nsswitch - no <nss.h>
+# rpctorture - improper use of client_info struct, dunno
diff --git a/packaging/Caldera/UnixWare/Configure b/packaging/Caldera/UnixWare/Configure
new file mode 100755
index 00000000000..e5a7fbba4dc
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Configure
@@ -0,0 +1,67 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+CC="cc -Kthread -Kalloca -I/usr/local/include -L/usr/local/lib"
+CPP="$CC -E"
+CFLAGS="-Xa -Dasm=__asm -DANSICPP -O3"
+LDFLAGS="-L/usr/local/lib"
+CXX="CC -I/usr/local/include"
+CXXFLAGS="-O3 -I/usr/local/include/stl -L/usr/local/lib"
+RANLIB=true
+MAKE=/usr/local/bin/make
+PREFIX=/usr/local/samba
+if [ "$V" = "echo" ]
+then
+ echo "exporting the following shell variables:"
+ echo "CC=$CC"
+ echo "CPP=$CPP"
+ echo "CXX=$CXX"
+ echo "RANLIB=$RANLIB"
+ echo "MAKE=$MAKE"
+ echo "CFLAGS=$CFLAGS"
+ echo "CXXFLAGS=$CXXFLAGS"
+ echo "LDFLAGS=$LDFLAGS"
+ echo "PREFIX=$PREFIX"
+else
+ export CC CPP CXX RANLIB MAKE CFLAGS CXXFLAGS LDFLAGS PREFIX
+fi
+
+cd ../../../source
+[ -f mout-config ] && {
+ if [ "$V" = "echo" ]
+ then
+ echo "mv mout-config mout-config$$"
+ else
+ mv mout-config mout-config$$
+ fi
+}
+if [ "$V" = "echo" ]
+then
+ echo "./configure \
+ --prefix=${PREFIX} \
+ --with-profile \
+ --with-syslog \
+ --with-utmp \
+ --with-vfs \
+ --with-msdfs \
+ --with-netatalk \
+ --with-sambabook=${PREFIX}/swat/using_samba \
+ 2>&1 | tee mout-config"
+else
+ ./configure \
+ --prefix=${PREFIX} \
+ --with-profile \
+ --with-syslog \
+ --with-utmp \
+ --with-vfs \
+ --with-msdfs \
+ --with-netatalk \
+ --with-sambabook=${PREFIX}/swat/using_samba \
+ 2>&1 | tee mout-config
+fi
diff --git a/packaging/Caldera/UnixWare/Install b/packaging/Caldera/UnixWare/Install
new file mode 100755
index 00000000000..3fffc37d25a
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Install
@@ -0,0 +1,146 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+PREFIX=/usr/local/samba
+HERE=`pwd`
+PKGDIR=packaging/Caldera/UnixWare
+
+BUILD_ROOT=${HERE}/dist
+BLDFIX=${BUILD_ROOT}/${PREFIX}
+$V rm -rf $BUILD_ROOT
+$V mkdir -p $BUILD_ROOT/etc/init.d
+$V mkdir -p ${BLDFIX}/bin
+$V mkdir -p ${BLDFIX}/sbin
+$V mkdir -p ${BLDFIX}/swat/using_samba/gifs
+$V mkdir -p ${BLDFIX}/swat/using_samba/figs
+$V mkdir -p ${BLDFIX}/swat/images
+$V mkdir -p ${BLDFIX}/swat/help
+$V mkdir -p ${BLDFIX}/swat/include
+$V mkdir -p ${BLDFIX}/man/man1
+$V mkdir -p ${BLDFIX}/man/man5
+$V mkdir -p ${BLDFIX}/man/man7
+$V mkdir -p ${BLDFIX}/man/man8
+$V mkdir -p ${BLDFIX}/var/locks
+$V mkdir -p ${BLDFIX}/lib/codepages/src
+
+# Copy into the dist tree the pkg data files
+for i in pkg/*
+do
+ [ -f $i ] && $V cp $i ${BUILD_ROOT}
+done
+
+cd ../../..
+
+# Install standard binary files
+for i in nmblookup smbclient smbpasswd smbstatus testparm testprns \
+ make_smbcodepage make_unicodemap make_printerdef rpcclient smbspool \
+ smbsh smbwrapper.so
+do
+$V install -m755 -s source/bin/$i ${BLDFIX}/bin
+done
+for i in mksmbpasswd.sh smbtar
+do
+$V install -m755 source/script/$i ${BLDFIX}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat debug2html smbtorture smbfilter locktest2 masktest
+do
+$V install -m755 -s source/bin/$i ${BLDFIX}/sbin
+done
+
+
+# Install level 1 man pages
+for i in *.1
+do
+$V install -m644 docs/manpages/$i ${BLDFIX}/man/man1
+done
+
+# Install codepage source files
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+$V install -m644 source/codepages/codepage_def.$i ${BLDFIX}/lib/codepages/src
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+$V install -m644 source/codepages/CP$i.TXT ${BLDFIX}/lib/codepages/src
+done
+
+# Install SWAT helper files
+for i in swat/help/*.html docs/htmldocs/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/help
+done
+for i in swat/images/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/images
+done
+for i in swat/include/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/include
+done
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif
+do
+$V install -m644 $i ${BLDFIX}/swat/using_samba/gifs
+done
+
+# Install the miscellany
+$V install -m644 swat/README ${BLDFIX}/swat
+$V install -m644 docs/manpages/smb.conf.5 ${BLDFIX}/man/man5
+$V install -m644 docs/manpages/lmhosts.5 ${BLDFIX}/man/man5
+$V install -m644 docs/manpages/smbpasswd.5 ${BLDFIX}/man/man5
+$V install -m644 docs/manpages/samba.7 ${BLDFIX}/man/man7
+$V install -m644 docs/manpages/smbd.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/nmbd.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/smbpasswd.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/swat.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/smbmount.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/smbmnt.8 ${BLDFIX}/man/man8
+$V install -m644 docs/manpages/smbumount.8 ${BLDFIX}/man/man8
+$V install -m644 ${PKGDIR}/smb.conf ${BLDFIX}/lib/smb.conf
+$V install -m644 ${PKGDIR}/smbusers $BUILD_ROOT/etc/smbusers
+$V install -m755 ${PKGDIR}/smbprint ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/findsmb ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/smbadduser ${BLDFIX}/bin
+$V install -m755 ${PKGDIR}/smb.init $BUILD_ROOT/etc/init.d/samba
+
+# The following is now done in the postinstall script
+#
+# if [ "$V" = "echo" ]
+# then
+# echo "echo 127.0.0.1 localhost > $BUILD_ROOT/etc/lmhosts"
+# else
+# echo 127.0.0.1 localhost > $BUILD_ROOT/etc/lmhosts
+# fi
+#
+# Build codepage load files
+# $V cd ${BLDFIX}/lib/codepages
+# for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+# do
+# $V ${PREFIX}/bin/make_smbcodepage c $i \
+# ${BLDFIX}/lib/codepages/src/codepage_def.$i \
+# ${BLDFIX}/lib/codepages/codepage.$i
+# done
+# for i in 437 737 850 852 861 866 932 936 949 950 \
+# ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+# do
+# $V ${PREFIX}/bin/make_unicodemap $i \
+# ${BLDFIX}/lib/codepages/src/CP$i.TXT \
+# ${BLDFIX}/lib/codepages/unicode_map.$i
+# done
diff --git a/packaging/Caldera/UnixWare/Makepkg b/packaging/Caldera/UnixWare/Makepkg
new file mode 100755
index 00000000000..dc57b246ef5
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Makepkg
@@ -0,0 +1,10 @@
+#!/bin/ksh
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+./Configure $*
+./Compile $*
+./Install $*
+./Package $*
diff --git a/packaging/Caldera/UnixWare/Package b/packaging/Caldera/UnixWare/Package
new file mode 100755
index 00000000000..f225b8eb7ea
--- /dev/null
+++ b/packaging/Caldera/UnixWare/Package
@@ -0,0 +1,40 @@
+#!/bin/ksh
+#
+# Now create the actual pkgadd installable datastream
+#
+# invoke with -n as the first argument to get this script to tell
+# you what it would do without doing anything
+#
+
+V=
+[ "$1" = "-n" ] && V=echo
+
+$V cd dist
+PKGNAME=samba
+PKGBLD=`pwd`
+[ "$V" = "echo" ] && PKGBLD=$PKGBLD/dist
+
+PKGCOMPRESS="-c"
+#PKGBLOCKLIM=2876
+PKGBLOCKLIM=6200
+
+##############################################################################
+#
+# make filesystem-type package in directory ./$PKGNAME/
+# (source files reside in ./root)
+#
+# don't use PKGBLOCKLIM for now
+#
+$V pkgmk -o $PKGCOMPRESS -d $PKGBLD -r $PKGBLD
+#pkgmk -o $PKGCOMPRESS -l $PKGBLOCKLIM -d $PKGBLD -r $PKGBLD
+#pkgmk -o $PKGCOMPRESS -l $PKGBLOCKLIM -d $PKGBLD -r $PKGBLD/root
+
+#
+# make $PKGNAME.pkg datastream-type package
+#
+$V pkgtrans -s $PKGBLD $PKGBLD/$PKGNAME.pkg $PKGNAME
+
+#
+# remove filesystem-type package
+#
+#rm -rf $PKGBLD/$PKGNAME
diff --git a/packaging/Caldera/UnixWare/README b/packaging/Caldera/UnixWare/README
new file mode 100644
index 00000000000..74f8dc53d5d
--- /dev/null
+++ b/packaging/Caldera/UnixWare/README
@@ -0,0 +1,54 @@
+Preparation Date: December 28, 2000
+Preparer: Ronald Joe Record <rr@sco.com>
+
+Instructions: Preparing Samba Packages for UnixWare
+===============================================================
+
+We provide support only for current versions of UnixWare.
+
+The file samba-2.2-uw7.patch is a patch file suitable for use
+with the patch command as follows:
+
+ # cd ../../../source
+ # patch -p 0 -i ../packaging/Caldera/UnixWare/samba-2.2-uw7.patch
+
+The files modified by this patch are:
+ smbwrapper/smbw.c
+ tdb/tdb.c
+ utils/torture.c
+ utils/locktest.c
+ utils/locktest2.c
+ utils/masktest.c
+ utils/smbcacls.c
+ ltconfig
+ configure.in
+
+This patch should only be necessary until these changes are accepted
+back into the 2.2 source tree. Until then, this patch must be applied
+prior to building Samba 2.2 on UnixWare 7. After applying the patch it
+is then necessary to run autoconf again and regenerate the configure file:
+
+ # cd ../../../source
+ # autoconf
+
+To produce the pkgadd installable datastream simply type (in this directory):
+ # ./Makepkg
+
+The resultant samba.pkg should reside in the ./dist subdirectory.
+To install from this pkgadd datastream, issue the command (as root):
+
+ # cd dist
+ # pkgadd -d `pwd`/samba.pkg all
+
+Alternately, each of the steps in building the datastream may be performed
+individually by invoking each of the following:
+
+ # ./Configure
+ # ./Compile
+ # ./Install
+ # ./Package
+
+If files are added or deleted from the UnixWare Samba distribution then
+the prototype file in the pkg directory should be appropriately modified.
+The files in the pkg subdirectory were initially created using the mkpkg
+package from SCO Skunkware (see http://www.sco.com/skunkware).
diff --git a/packaging/Caldera/UnixWare/findsmb b/packaging/Caldera/UnixWare/findsmb
new file mode 100755
index 00000000000..bb91c784b89
--- /dev/null
+++ b/packaging/Caldera/UnixWare/findsmb
@@ -0,0 +1,141 @@
+#!/usr/local/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/local/samba/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/Caldera/UnixWare/pkg/admin b/packaging/Caldera/UnixWare/pkg/admin
new file mode 100644
index 00000000000..fe2438c770c
--- /dev/null
+++ b/packaging/Caldera/UnixWare/pkg/admin
@@ -0,0 +1 @@
+basedir=ask
diff --git a/packaging/Caldera/UnixWare/pkg/pkginfo b/packaging/Caldera/UnixWare/pkg/pkginfo
new file mode 100644
index 00000000000..c4d8bff0bb9
--- /dev/null
+++ b/packaging/Caldera/UnixWare/pkg/pkginfo
@@ -0,0 +1,10 @@
+PKG="samba"
+NAME="Samba - A Windows SMB/CIFS fileserver for UNIX"
+VERSION="2.2"
+VENDOR="SCO"
+HOTLINE="1-800-SCO-UNIX"
+EMAIL="rr@sco.com"
+CATEGORY="skunkware"
+CLASSES="samba"
+ARCH="i386"
+BASEDIR=/
diff --git a/packaging/Caldera/UnixWare/pkg/postinstall b/packaging/Caldera/UnixWare/pkg/postinstall
new file mode 100755
index 00000000000..4e202ae3543
--- /dev/null
+++ b/packaging/Caldera/UnixWare/pkg/postinstall
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Create /var/spool/samba, setup swat to be run out of inetd on port 901,
+# initialize the lmhosts file and create the codepage load files
+#
+# Written 10-Aug-1999 by Ronald Joe Record (rr@sco.com)
+#
+
+SPOOL=/var/spool/samba
+SVCS=/etc/services
+INET=/etc/inetd.conf
+PREFIX=/usr/local/samba
+LMHOST=/etc/lmhosts
+
+[ -d $SPOOL ] || {
+ mkdir -p $SPOOL
+ chmod 1777 $SPOOL
+}
+
+grep swat $SVCS > /dev/null || {
+ echo "swat 901/tcp # Samba Web Administration Tool " >> $SVCS
+}
+
+grep swat $INET > /dev/null || {
+ echo "swat stream tcp nowait root /usr/local/samba/bin/swat swat " >> $INET
+}
+
+if [ -f $LMHOST ]
+then
+ grep localhost $LMHOST > /dev/null || {
+ echo 127.0.0.1 localhost >> $LMHOST
+ }
+else
+ echo 127.0.0.1 localhost > $LMHOST
+fi
+
+#
+# Build codepage load files
+#
+
+cd ${PREFIX}/lib/codepages
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+ ${PREFIX}/bin/make_smbcodepage c $i \
+ ${PREFIX}/lib/codepages/src/codepage_def.$i \
+ ${PREFIX}/lib/codepages/codepage.$i
+done
+for i in 437 737 850 852 861 866 932 936 949 950 \
+ ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+ ${PREFIX}/bin/make_unicodemap $i \
+ ${PREFIX}/lib/codepages/src/CP$i.TXT \
+ ${PREFIX}/lib/codepages/unicode_map.$i
+done
+
+kill -1 `ps -e | grep inetd | awk ' { print $1 } '`
diff --git a/packaging/Caldera/UnixWare/pkg/postremove b/packaging/Caldera/UnixWare/pkg/postremove
new file mode 100755
index 00000000000..dc81d6fa85f
--- /dev/null
+++ b/packaging/Caldera/UnixWare/pkg/postremove
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Remove /var/spool/samba and delete inetd entries for swat
+#
+
+SPOOL=/var/spool/samba
+SVCS=/etc/services
+INET=/etc/inetd.conf
+
+[ -d $SPOOL ] && {
+ rm -rf $SPOOL
+}
+
+grep swat $SVCS > /dev/null && {
+ B=`basename $SVCS`
+ T=$B$$
+ grep -v swat $SVCS > /tmp/$T
+ cp /tmp/$T $SVCS
+ rm -f /tmp/$T
+}
+
+grep swat $INET > /dev/null || {
+ B=`basename $INET`
+ T=$B$$
+ grep -v swat $INET > /tmp/$T
+ cp /tmp/$T $INET
+ rm -f /tmp/$T
+}
+
+kill -1 `ps -e | grep inetd | awk ' { print $1 } '`
diff --git a/packaging/Caldera/UnixWare/pkg/prototype b/packaging/Caldera/UnixWare/pkg/prototype
new file mode 100644
index 00000000000..13a64b6feb1
--- /dev/null
+++ b/packaging/Caldera/UnixWare/pkg/prototype
@@ -0,0 +1,310 @@
+i admin=admin
+i pkginfo=pkginfo
+i postinstall=postinstall
+i postremove=postremove
+
+d samba etc 0755 root sys
+d samba etc/init.d 0755 root sys
+f samba etc/init.d/samba 0755 root sys
+f samba etc/smbusers 0644 root sys
+d samba usr 0755 root sys
+d samba usr/local 0755 root sys
+d samba usr/local/samba 0755 root sys
+d samba usr/local/samba/bin 0755 root sys
+f samba usr/local/samba/bin/nmblookup 0755 root sys
+f samba usr/local/samba/bin/smbclient 0755 root sys
+f samba usr/local/samba/bin/smbpasswd 0755 root sys
+f samba usr/local/samba/bin/smbstatus 0755 root sys
+f samba usr/local/samba/bin/testparm 0755 root sys
+f samba usr/local/samba/bin/testprns 0755 root sys
+f samba usr/local/samba/bin/make_smbcodepage 0755 root sys
+f samba usr/local/samba/bin/make_unicodemap 0755 root sys
+f samba usr/local/samba/bin/make_printerdef 0755 root sys
+f samba usr/local/samba/bin/rpcclient 0755 root sys
+f samba usr/local/samba/bin/smbspool 0755 root sys
+f samba usr/local/samba/bin/smbsh 0755 root sys
+f samba usr/local/samba/bin/smbwrapper.so 0755 root sys
+f samba usr/local/samba/bin/mksmbpasswd.sh 0755 root sys
+f samba usr/local/samba/bin/smbtar 0755 root sys
+f samba usr/local/samba/bin/smbprint 0755 root sys
+f samba usr/local/samba/bin/findsmb 0755 root sys
+f samba usr/local/samba/bin/smbadduser 0755 root sys
+d samba usr/local/samba/sbin 0755 root sys
+f samba usr/local/samba/sbin/smbd 0755 root sys
+f samba usr/local/samba/sbin/nmbd 0755 root sys
+f samba usr/local/samba/sbin/swat 0755 root sys
+f samba usr/local/samba/sbin/debug2html 0755 root sys
+f samba usr/local/samba/sbin/smbtorture 0755 root sys
+f samba usr/local/samba/sbin/smbfilter 0755 root sys
+f samba usr/local/samba/sbin/locktest2 0755 root sys
+f samba usr/local/samba/sbin/masktest 0755 root sys
+d samba usr/local/samba/swat 0755 root sys
+d samba usr/local/samba/swat/using_samba 0755 root sys
+d samba usr/local/samba/swat/using_samba/gifs 0755 root sys
+f samba usr/local/samba/swat/using_samba/gifs/index.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/gifs/samba.s.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/gifs/txthome.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/gifs/txtnexta.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/gifs/txtpreva.gif 0644 root sys
+d samba usr/local/samba/swat/using_samba/figs 0755 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0101.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0102.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0103.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0104.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0105.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0106.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0107.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0108.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0109.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0110.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0111.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0112.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0113.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0114.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0201.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0202.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0203.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0204.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0301.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0302.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0303.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0304.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0305.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0306.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0307.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0308.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0309.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0310.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0311.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0312.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0313.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0314.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0315.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0316.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0317.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0318.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0319.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0320.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0321.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0322.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0323.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0324.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0325.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0326.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0327.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0328.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0401.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0402.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0403.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0404.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0405.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0406.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0407.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0501.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0502.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0503.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0504.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0505.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0506.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0507.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0508.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0601.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0602.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0603.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0604.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0605.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0606.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0701.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0702.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0703.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0704.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0705.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0706.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0707.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0708.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0709.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0801.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0802.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0803.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0804.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0805.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0901.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0902.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0903.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0904.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.0905.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.aa01.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.ab01.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/figs/sam.ab02.gif 0644 root sys
+f samba usr/local/samba/swat/using_samba/appa_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appa_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appa_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appa_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appa_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appb_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appb_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appb_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appc_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appd_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appe_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/appf_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_06.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_07.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch01_08.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch02_06.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch03_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch03_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch03_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_06.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_07.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch04_08.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch05_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch05_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch05_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch05_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch05_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch06_06.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch07_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch07_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch07_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_04.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_05.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_06.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch08_07.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch09_01.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch09_02.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/ch09_03.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/index.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/inx.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/licenseinfo.html 0644 root sys
+f samba usr/local/samba/swat/using_samba/this_edition.html 0644 root sys
+d samba usr/local/samba/swat/images 0755 root sys
+f samba usr/local/samba/swat/images/globals.gif 0644 root sys
+f samba usr/local/samba/swat/images/home.gif 0644 root sys
+f samba usr/local/samba/swat/images/passwd.gif 0644 root sys
+f samba usr/local/samba/swat/images/printers.gif 0644 root sys
+f samba usr/local/samba/swat/images/samba.gif 0644 root sys
+f samba usr/local/samba/swat/images/shares.gif 0644 root sys
+f samba usr/local/samba/swat/images/status.gif 0644 root sys
+f samba usr/local/samba/swat/images/viewconfig.gif 0644 root sys
+d samba usr/local/samba/swat/help 0755 root sys
+f samba usr/local/samba/swat/help/welcome.html 0644 root sys
+f samba usr/local/samba/swat/help/DOMAIN_MEMBER.html 0644 root sys
+f samba usr/local/samba/swat/help/NT_Security.html 0644 root sys
+f samba usr/local/samba/swat/help/findsmb.1.html 0644 root sys
+f samba usr/local/samba/swat/help/lmhosts.5.html 0644 root sys
+f samba usr/local/samba/swat/help/make_smbcodepage.1.html 0644 root sys
+f samba usr/local/samba/swat/help/nmbd.8.html 0644 root sys
+f samba usr/local/samba/swat/help/nmblookup.1.html 0644 root sys
+f samba usr/local/samba/swat/help/rpcclient.1.html 0644 root sys
+f samba usr/local/samba/swat/help/samba-pdc-faq.html 0644 root sys
+f samba usr/local/samba/swat/help/samba-pdc-howto.html 0644 root sys
+f samba usr/local/samba/swat/help/samba.7.html 0644 root sys
+f samba usr/local/samba/swat/help/smb.conf.5.html 0644 root sys
+f samba usr/local/samba/swat/help/smbclient.1.html 0644 root sys
+f samba usr/local/samba/swat/help/smbcontrol.1.html 0644 root sys
+f samba usr/local/samba/swat/help/smbd.8.html 0644 root sys
+f samba usr/local/samba/swat/help/smbpasswd.5.html 0644 root sys
+f samba usr/local/samba/swat/help/smbpasswd.8.html 0644 root sys
+f samba usr/local/samba/swat/help/smbrun.1.html 0644 root sys
+f samba usr/local/samba/swat/help/smbsh.1.html 0644 root sys
+f samba usr/local/samba/swat/help/smbspool.8.html 0644 root sys
+f samba usr/local/samba/swat/help/smbstatus.1.html 0644 root sys
+f samba usr/local/samba/swat/help/smbtar.1.html 0644 root sys
+f samba usr/local/samba/swat/help/swat.8.html 0644 root sys
+f samba usr/local/samba/swat/help/testparm.1.html 0644 root sys
+f samba usr/local/samba/swat/help/testprns.1.html 0644 root sys
+f samba usr/local/samba/swat/help/wbinfo.1.html 0644 root sys
+f samba usr/local/samba/swat/help/winbindd.8.html 0644 root sys
+d samba usr/local/samba/swat/include 0755 root sys
+f samba usr/local/samba/swat/include/footer.html 0644 root sys
+f samba usr/local/samba/swat/include/header.html 0644 root sys
+f samba usr/local/samba/swat/README 0644 root sys
+d samba usr/local/samba/man 0755 root sys
+d samba usr/local/samba/man/man1 0755 root sys
+f samba usr/local/samba/man/man1/findsmb.1 0644 root sys
+f samba usr/local/samba/man/man1/make_smbcodepage.1 0644 root sys
+f samba usr/local/samba/man/man1/make_unicodemap.1 0644 root sys
+f samba usr/local/samba/man/man1/nmblookup.1 0644 root sys
+f samba usr/local/samba/man/man1/smbclient.1 0644 root sys
+f samba usr/local/samba/man/man1/smbcontrol.1 0644 root sys
+f samba usr/local/samba/man/man1/smbrun.1 0644 root sys
+f samba usr/local/samba/man/man1/smbsh.1 0644 root sys
+f samba usr/local/samba/man/man1/smbstatus.1 0644 root sys
+f samba usr/local/samba/man/man1/smbtar.1 0644 root sys
+f samba usr/local/samba/man/man1/testparm.1 0644 root sys
+f samba usr/local/samba/man/man1/testprns.1 0644 root sys
+f samba usr/local/samba/man/man1/wbinfo.1 0644 root sys
+d samba usr/local/samba/man/man5 0755 root sys
+f samba usr/local/samba/man/man5/smb.conf.5 0644 root sys
+f samba usr/local/samba/man/man5/lmhosts.5 0644 root sys
+f samba usr/local/samba/man/man5/smbpasswd.5 0644 root sys
+d samba usr/local/samba/man/man7 0755 root sys
+f samba usr/local/samba/man/man7/samba.7 0644 root sys
+d samba usr/local/samba/man/man8 0755 root sys
+f samba usr/local/samba/man/man8/smbd.8 0644 root sys
+f samba usr/local/samba/man/man8/nmbd.8 0644 root sys
+f samba usr/local/samba/man/man8/smbpasswd.8 0644 root sys
+f samba usr/local/samba/man/man8/swat.8 0644 root sys
+f samba usr/local/samba/man/man8/smbmount.8 0644 root sys
+f samba usr/local/samba/man/man8/smbmnt.8 0644 root sys
+f samba usr/local/samba/man/man8/smbumount.8 0644 root sys
+d samba usr/local/samba/var 0755 root sys
+d samba usr/local/samba/var/locks 0755 root sys
+d samba usr/local/samba/lib 0755 root sys
+d samba usr/local/samba/lib/codepages 0755 root sys
+d samba usr/local/samba/lib/codepages/src 0755 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.437 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.737 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.775 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.850 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.852 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.861 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.866 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.932 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.936 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.949 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.950 0644 root sys
+f samba usr/local/samba/lib/codepages/src/codepage_def.1251 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP437.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP737.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP850.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP852.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP861.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP866.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP932.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP936.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP949.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CP950.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CPISO8859-1.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CPISO8859-2.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CPISO8859-5.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CPISO8859-7.TXT 0644 root sys
+f samba usr/local/samba/lib/codepages/src/CPKOI8-R.TXT 0644 root sys
+f samba usr/local/samba/lib/smb.conf 0644 root sys
+d samba usr/local/man 0755 root sys
+d samba usr/local/man/html 0755 root sys
+s samba usr/local/man/html/samba=/usr/local/samba/swat/using_samba
diff --git a/packaging/Caldera/UnixWare/samba-2.2-uw7-prototype.patch b/packaging/Caldera/UnixWare/samba-2.2-uw7-prototype.patch
new file mode 100644
index 00000000000..7678379b063
--- /dev/null
+++ b/packaging/Caldera/UnixWare/samba-2.2-uw7-prototype.patch
@@ -0,0 +1,11 @@
+--- packaging/Caldera/UnixWare/pkg/prototype.00 Tue Jan 9 05:40:47 2001
++++ packaging/Caldera/UnixWare/pkg/prototype Fri Apr 13 14:44:33 2001
+@@ -220,7 +220,7 @@
+ f samba usr/local/samba/swat/help/make_smbcodepage.1.html 0644 root sys
+ f samba usr/local/samba/swat/help/nmbd.8.html 0644 root sys
+ f samba usr/local/samba/swat/help/nmblookup.1.html 0644 root sys
+-f samba usr/local/samba/swat/help/rpcclient.8.html 0644 root sys
++f samba usr/local/samba/swat/help/rpcclient.1.html 0644 root sys
+ f samba usr/local/samba/swat/help/samba-pdc-faq.html 0644 root sys
+ f samba usr/local/samba/swat/help/samba-pdc-howto.html 0644 root sys
+ f samba usr/local/samba/swat/help/samba.7.html 0644 root sys
diff --git a/packaging/Caldera/UnixWare/samba-2.2-uw7.patch b/packaging/Caldera/UnixWare/samba-2.2-uw7.patch
new file mode 100644
index 00000000000..c4412e542ee
--- /dev/null
+++ b/packaging/Caldera/UnixWare/samba-2.2-uw7.patch
@@ -0,0 +1,200 @@
+--- smbwrapper/smbw.c.orig Mon Jan 8 12:37:48 2001
++++ smbwrapper/smbw.c Fri Apr 13 13:09:00 2001
+@@ -22,6 +22,11 @@
+ #include "includes.h"
+ #include "realcalls.h"
+
++#if defined(__USLC__) && defined(HAVE_SYS_ACL_H)
++#define GETACL ACL_GET
++#define GETACLCNT ACL_CNT
++#endif
++
+ pstring smbw_cwd;
+
+ static struct smbw_file *smbw_files;
+@@ -1462,7 +1467,11 @@
+ /*****************************************************
+ say no to acls
+ *******************************************************/
++#if defined(__USLC__)
++ int smbw_acl(const char *pathp, int cmd, int nentries, void *aclbufp)
++#else
+ int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
++#endif
+ {
+ if (cmd == GETACL || cmd == GETACLCNT) return 0;
+ errno = ENOSYS;
+@@ -1474,7 +1483,11 @@
+ /*****************************************************
+ say no to acls
+ *******************************************************/
++#if defined(__USLC__)
++ int smbw_facl(int fd, int cmd, int nentries, void *aclbufp)
++#else
+ int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
++#endif
+ {
+ if (cmd == GETACL || cmd == GETACLCNT) return 0;
+ errno = ENOSYS;
+--- tdb/tdb.c.orig Fri Apr 13 05:58:34 2001
++++ tdb/tdb.c Fri Apr 13 13:34:18 2001
+@@ -856,7 +856,11 @@
+ {
+ TDB_DATA key, dbuf;
+ struct list_struct rec;
++#if defined(__USLC__)
++ struct tdb_traverse_lock tl = { (struct tdb_traverse_lock *)0, 0, 0 };
++#else
+ struct tdb_traverse_lock tl = { NULL, 0, 0 };
++#endif
+ int ret, count = 0;
+
+ /* This was in the initializaton, above, but the IRIX compiler
+--- utils/torture.c.orig Fri Mar 30 13:53:26 2001
++++ utils/torture.c Fri Apr 13 13:09:01 2001
+@@ -2703,7 +2703,11 @@
+
+ dbf = stdout;
+
++#if defined(__USLC__)
++ setbuf(stdout, NULL);
++#else
+ setbuffer(stdout, NULL, 0);
++#endif
+
+ charset_initialise();
+
+--- utils/locktest.c.orig Fri Sep 29 13:18:14 2000
++++ utils/locktest.c Fri Apr 13 13:09:01 2001
+@@ -34,7 +34,7 @@
+
+ #define FILENAME "\\locktest.dat"
+ #define LOCKRANGE 1000
+-#define LOCKBASE 0;
++#define LOCKBASE 0
+
+ /*
+ #define LOCKBASE (0x40000000 - 50)
+@@ -59,6 +59,7 @@
+ char needed;
+ };
+
++#ifndef __USLC__
+ static struct record preset[] = {
+ #if 0
+ {36, 5, 0, 0, 0, 8, 1},
+@@ -67,6 +68,7 @@
+ {99, 11, 0, 0, 7, 1, 1},
+ #endif
+ };
++#endif /* __USLC__) */
+
+ static struct record *recorded;
+
+@@ -378,20 +380,23 @@
+ recorded = (struct record *)malloc(sizeof(*recorded) * numops);
+
+ for (n=0; n<numops; n++) {
++#ifndef __USLC__
+ if (n < sizeof(preset) / sizeof(preset[0])) {
+ recorded[n] = preset[n];
+ } else {
++#endif
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
+- recorded[n].len = 1 +
+- random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
++ recorded[n].len = 1 + random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ recorded[n].r1 = random() % 100;
+ recorded[n].r2 = random() % 100;
+ recorded[n].needed = True;
++#ifndef __USLC__
+ }
++#endif
+ }
+
+ reconnect(cli, fnum, share);
+@@ -484,7 +489,11 @@
+ int seed, server;
+ static pstring servicesf = CONFIGFILE;
+
++#if defined(__USLC__)
++ setvbuf(stdout,NULL,_IOLBF,0); /* line buffered */
++#else
+ setlinebuf(stdout);
++#endif
+
+ dbf = stderr;
+
+--- utils/locktest2.c.orig Tue Jun 13 08:47:44 2000
++++ utils/locktest2.c Fri Apr 13 13:09:01 2001
+@@ -540,7 +540,11 @@
+ int seed;
+ static pstring servicesf = CONFIGFILE;
+
++#if defined(__USLC__)
++ setvbuf(stdout,NULL,_IOLBF,0); /* line buffered */
++#else
+ setlinebuf(stdout);
++#endif
+
+ dbf = stderr;
+
+--- utils/masktest.c.orig Fri May 26 17:28:02 2000
++++ utils/masktest.c Fri Apr 13 13:09:01 2001
+@@ -310,7 +310,11 @@
+ int seed;
+ static pstring servicesf = CONFIGFILE;
+
++#if defined(__USLC__)
++ setvbuf(stdout,NULL,_IOLBF,0); /* line buffered */
++#else
+ setlinebuf(stdout);
++#endif
+
+ dbf = stderr;
+
+--- utils/smbcacls.c.orig Thu Apr 12 21:09:39 2001
++++ utils/smbcacls.c Fri Apr 13 13:09:01 2001
+@@ -824,7 +824,11 @@
+
+ ctx=talloc_init();
+
++#if defined(__USLC__)
++ setvbuf(stdout,NULL,_IOLBF,0); /* line buffered */
++#else
+ setlinebuf(stdout);
++#endif
+
+ dbf = stderr;
+
+--- ltconfig.orig Mon Mar 13 15:20:00 2000
++++ ltconfig Fri Apr 13 13:09:01 2001
+@@ -1482,9 +1482,9 @@
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts'
++ archive_cmds='$LD -G${allow_undefined_flag} -h $rpath/$soname -o $lib $libobjs $deplibs $linkopts'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp'
++ $LD -G${allow_undefined_flag} -M $lib.exp -h $rpath/$soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp'
+ hardcode_libdir_flag_spec=
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+--- configure.in.orig Fri Apr 13 11:33:18 2001
++++ configure.in Fri Apr 13 13:09:01 2001
+@@ -727,6 +727,10 @@
+ *sysv5*)
+ if [ test "$GCC" != yes ]; then
+ AC_DEFINE(HAVE_MEMSET)
++ PICFLAG="-KPIC"
++ ac_cv_prog_cc_fpic=no
++ ac_cv_prog_cc_Kpic=no
++ ac_cv_prog_cc_KPIC=yes
+ fi
+ LDSHFLAGS="-G"
+ ;;
diff --git a/packaging/Caldera/UnixWare/smb.conf b/packaging/Caldera/UnixWare/smb.conf
new file mode 100644
index 00000000000..e3b3ae9e693
--- /dev/null
+++ b/packaging/Caldera/UnixWare/smb.conf
@@ -0,0 +1,291 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = lpstat
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+ printing = sysv
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /usr/local/samba/var/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; writable = yes
+; printable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Caldera/UnixWare/smb.init b/packaging/Caldera/UnixWare/smb.init
new file mode 100755
index 00000000000..ce6c6fa4b38
--- /dev/null
+++ b/packaging/Caldera/UnixWare/smb.init
@@ -0,0 +1,76 @@
+#!/bin/sh
+#ident "@(#)samba.server 1.0 96/06/19 TK" /* SVr4.0 1.1.13.1*/
+#
+# Please send info on modifications to knuutila@cs.utu.fi
+#
+# This file should have uid root, gid sys and chmod 744
+#
+# Modified 17-Jul-99 by Ron Record (rr@sco.com) for use in SCO Skunkware
+#
+
+SAMBADIR=/usr/local/samba
+RCSCRIPT=/etc/rc2.d/S99samba
+
+if [ ! -d /usr/bin ]
+then # /usr not mounted
+ exit
+fi
+
+killproc() { # kill the named process(es)
+ if [ -f $SAMBADIR/var/locks/$1.pid ]
+ then
+ kill `cat $SAMBADIR/var/locks/$1.pid`
+ else
+ pid=`/usr/bin/ps -e |
+ /usr/bin/grep $1 |
+ /usr/bin/sed -e 's/^ *//' -e 's/ .*//'`
+ [ "$pid" != "" ] && kill $pid
+ fi
+}
+
+start() {
+#
+# Edit these lines to suit your installation (paths, workgroup, host)
+#
+ $SAMBADIR/sbin/smbd -D -s $SAMBADIR/lib/smb.conf
+ $SAMBADIR/sbin/nmbd -D -s $SAMBADIR/lib/smb.conf
+}
+
+stop() {
+ killproc nmbd
+ killproc smbd
+}
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+'start')
+ start
+ ;;
+'stop')
+ stop
+ ;;
+'restart')
+ stop
+ start
+ ;;
+'enable')
+ if [ -h $RCSCRIPT ] ; then
+ echo "Samba is already enabled."
+ else
+ echo "Enabling Samba ... \c"
+ rm -f $RCSCRIPT
+ ln -s /etc/init.d/samba $RCSCRIPT
+ echo "Done"
+ fi
+ ;;
+'disable')
+ echo "Disabling Samba ... \c"
+ rm -f $RCSCRIPT
+ echo "Done"
+ ;;
+*)
+ echo "Usage: /etc/init.d/samba { start | stop | restart | enable | disable }"
+ ;;
+esac
diff --git a/packaging/Caldera/UnixWare/smbadduser b/packaging/Caldera/UnixWare/smbadduser
new file mode 100755
index 00000000000..2f38bf28f1a
--- /dev/null
+++ b/packaging/Caldera/UnixWare/smbadduser
@@ -0,0 +1,73 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+unalias *
+set path = ($path)
+
+set smbpasswd = /etc/smbpasswd
+set user_map = /etc/smbusers
+#
+# Set to site specific passwd command
+#
+set passwd = "cat /etc/passwd"
+#set passwd = "niscat passwd.org_dir"
+#set passwd = "ypcat passwd"
+
+set line = "----------------------------------------------------------"
+if ($#argv == 0) then
+ echo $line
+ echo "Written: Mike Zakharoff email: michael.j.zakharoff@boeing.com"
+ echo ""
+ echo " 1) Updates $smbpasswd"
+ echo " 2) Updates $user_map"
+ echo " 3) Executes smbpasswd for each new user"
+ echo ""
+ echo "smbadduser unixid:ntid unixid:ntid ..."
+ echo ""
+ echo "Example: smbadduser zak:zakharoffm johns:smithj"
+ echo $line
+ exit 1
+endif
+
+touch $smbpasswd $user_map
+set new = ()
+foreach one ($argv)
+ echo $one | grep ':' >& /dev/null
+ if ($status != 0) then
+ echo "ERROR: Must use unixid:ntid like -> zak:zakharoffm"
+ continue
+ endif
+ set unix = `echo $one | awk -F: '{print $1}'`
+ set ntid = `echo $one | awk -F: '{print $2}'`
+
+ set usr = `eval $passwd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#usr != 1) then
+ echo "ERROR: $unix Not in passwd database SKIPPING..."
+ continue
+ endif
+ set tmp = `cat $smbpasswd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#tmp != 0) then
+ echo "ERROR: $unix is already in $smbpasswd SKIPPING..."
+ continue
+ endif
+
+ echo "Adding: $unix to $smbpasswd"
+ eval $passwd | \
+ awk -F: '$1==USR { \
+ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }' USR=$unix >> $smbpasswd
+ if ($unix != $ntid) then
+ echo "Adding: {$unix = $ntid} to $user_map"
+ echo "$unix = $ntid" >> $user_map
+ endif
+ set new = ($new $unix)
+end
+
+#
+# Enter password for new users
+#
+foreach one ($new)
+ echo $line
+ echo "ENTER password for $one"
+ smbpasswd $one
+end
diff --git a/packaging/Caldera/UnixWare/smbprint b/packaging/Caldera/UnixWare/smbprint
new file mode 100755
index 00000000000..ec083eede62
--- /dev/null
+++ b/packaging/Caldera/UnixWare/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to same space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/packaging/Caldera/UnixWare/smbusers b/packaging/Caldera/UnixWare/smbusers
new file mode 100644
index 00000000000..ae3389f53f8
--- /dev/null
+++ b/packaging/Caldera/UnixWare/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nobody = guest pcguest smbguest
diff --git a/packaging/Digital/Instructions b/packaging/Digital/Instructions
new file mode 100644
index 00000000000..f764ad350dd
--- /dev/null
+++ b/packaging/Digital/Instructions
@@ -0,0 +1,55 @@
+Copyright (C) 1997-1998 John H Terpstra
+E-mail: jht@samba.org
+
+Subject: Installation Instructions for Digital Unix v4.0
+--------------------------------------------------------
+
+1) cd /
+2) tar xvf [path-to-]/install.tar
+3) cd /usr/local/samba/lib
+4) vi smb.conf
+
+Now modify smb.conf to reflect your site needs.
+
+5) samba start
+
+To stop samba:
+
+ samba stop
+
+You could install samba to run from the system start-up scripts
+(recommended) by running ./setup.sh
+
+Start / Stop Samba as follows:-
+
+ samba [start | stop]
+
+
+Subject: Encrypted password support
+-----------------------------------
+
+Encrypted password support is quite distinct from Digital Enhanced
+Security Mode operation of the Unix system. Encrypted passwords
+applies to the SMB connections serviced by this machine, not to
+local user logons. Local user logons are services by the security
+system chosen by your system administrator.
+
+Digital Unix knows of either BASIC or ENHANCED security mode
+operation. BASIC mode uses the traditional /etc/passwd database
+containing Unix crypted passwords. ENHANCED mode uses a TCB database.
+Samba-1.9.18p10 has been modified so that if OSF1_ENH_SEC is defined
+at compile time then a password check will be made first using ENHANCED
+mode and if that fails then it will try BASIC mode. This is the case
+for this binary distribution - you need not recompile. In other
+words: this binary distribution will work with either security mode.
+
+To enable SMB encrypted password support do the following:
+
+1) Put /usr/local/samba/bin in your PATH
+2) Edit /usr/local/samba/lib/smb.conf and uncomment the
+ line "encrypt passwd = yes"
+3) Execute: smbpasswd -a "username" "password"
+
+The above will create your /usr/local/samba/private/smbpasswd file
+in which will be the NT and LanMAN hashed passwords.
+
diff --git a/packaging/Digital/PackageDate b/packaging/Digital/PackageDate
new file mode 100644
index 00000000000..360e4148aa0
--- /dev/null
+++ b/packaging/Digital/PackageDate
@@ -0,0 +1 @@
+November 14, 1998, Australia/Sydney
diff --git a/packaging/Digital/Packager b/packaging/Digital/Packager
new file mode 100644
index 00000000000..75252978dc1
--- /dev/null
+++ b/packaging/Digital/Packager
@@ -0,0 +1,2 @@
+Date: November 14, 1998
+Packager: John H Terpstra <jht@samba.org>
diff --git a/packaging/Digital/Packaging-instructions b/packaging/Digital/Packaging-instructions
new file mode 100644
index 00000000000..77eafd312f5
--- /dev/null
+++ b/packaging/Digital/Packaging-instructions
@@ -0,0 +1,14 @@
+The package building files should be located in a directory
+called: samba-2.0.0
+
+Step Directions
+==== ============================================
+1. Copy the samba distribution tarball into the packaging directory
+2. Make sure you have a installed on your system the GNU gzip/gunzip files
+3. Edit "package-prep" script as required
+4. Run "package-prep"
+
+If all goes well, you should now have a usable distribution package.
+
+Note: Update the Instructions file as required.
+
diff --git a/packaging/Digital/package-prep b/packaging/Digital/package-prep
new file mode 100755
index 00000000000..2daee8b69ef
--- /dev/null
+++ b/packaging/Digital/package-prep
@@ -0,0 +1,30 @@
+tar xvf skeleton.tar
+NOWDIR=`pwd`;
+( cd /usr/local;
+ if [ -x man ]; then mv man man.orig; fi
+ if [ -x samba ]; then mv samba samba.orig; fi
+ ln -sf $NOWDIR/usr/local/man man;
+ ln -sf $NOWDIR/usr/local/samba samba; )
+gunzip samba-2.0.0.tar.gz
+tar xvf samba-2.0.0.tar
+cd samba-2.0.0/source
+./configure
+make
+make install
+cd $NOWDIR/usr/local/samba
+cp -pr man ../
+rm -rf man
+cd $NOWDIR
+tar cvf install.tar usr var
+cd samba-2.0.0/source
+rm -f ../source/bin/*
+make clean
+cd ../..
+tar cvf samba-2.0.0.tar samba-2.0.0
+rm -rf samba-2.0.0
+rm -rf usr var
+cd ..
+find samba-2.0.0 -print | cpio -o > samba-2.0.0-OSF1-v4.0-beta5.cpio
+gzip samba-2.0.0-OSF1-v4.0-beta5.cpio
+cd samba-2.0.0
+tar xvf install.tar
diff --git a/packaging/Digital/samba.init b/packaging/Digital/samba.init
new file mode 100755
index 00000000000..6a742440890
--- /dev/null
+++ b/packaging/Digital/samba.init
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+if [ ! -d /usr/bin ]; then
+ echo "The /usr file system is not mounted."
+ exit 1
+fi
+
+killproc() {
+ pid=`/bin/ps ax | grep -w $1 | sed -e 's/^ *//' -e 's/ .*//'`
+ echo "Stopping $1 now."
+ [ "$pid" != "" ] && kill -15 $pid
+ echo $pid
+}
+
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+ 'start')
+ echo "Starting Samba"
+ /usr/local/samba/bin/smbd
+ /usr/local/samba/bin/nmbd
+ echo "Done."
+ ;;
+ 'stop')
+ killproc smbd
+ killproc nmbd
+ ;;
+ *)
+ echo "Usage: /sbin/init.d/samba.init [ start | stop ]"
+ ;;
+esac
+exit 0
diff --git a/packaging/Digital/setup.sh b/packaging/Digital/setup.sh
new file mode 100755
index 00000000000..81b04878bb1
--- /dev/null
+++ b/packaging/Digital/setup.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+echo "Setting up for SWAT - The Samba Web Administration Tool"
+
+echo 'swat 901/tcp' >> /etc/services
+uniq /etc/services /tmp/tempserv
+cp /tmp/tempserv /etc/services
+rm /tmp/tempserv
+echo 'swat stream tcp nowait.400 root /usr/local/samba/bin/swat swat' >> /etc/inetd.conf
+uniq /etc/inetd.conf /tmp/tempinetd
+cp /tmp/tempinetd /etc/inetd.conf
+rm /tmp/tempinetd
+echo "Creating Symbolic Links for Start up Scripts"
+cp -f samba.init /sbin/init.d
+chown bin.bin /sbin/init.d/samba.init
+chmod 750 /sbin/init.d/samba.init
+ln -sf /sbin/init.d/samba.init /sbin/rc0.d/K01samba
+ln -sf /sbin/init.d/samba.init /sbin/rc2.d/K91samba
+ln -sf /sbin/init.d/samba.init /sbin/rc3.d/S91samba
+echo "Done. Now settting up samba command"
+ln /sbin/init.d/samba.init /sbin/samba
+echo "Done."
+echo "To start / stop samba:"
+echo " execute: samba [start | stop]
diff --git a/packaging/Digital/skeleton.tar b/packaging/Digital/skeleton.tar
new file mode 100644
index 00000000000..92598d0c5e7
--- /dev/null
+++ b/packaging/Digital/skeleton.tar
Binary files differ
diff --git a/packaging/Example/Instructions b/packaging/Example/Instructions
new file mode 100644
index 00000000000..02ffa7b6a8c
--- /dev/null
+++ b/packaging/Example/Instructions
@@ -0,0 +1,41 @@
+Copyright (C) 1997-1998 Samba-Team
+E-mail: samba-binaries@samba.org
+
+Subject: Installation Instructions for SuperNewOS X.X
+--------------------------------------------------------
+
+1) cd /
+2) tar xvf [path-to-samba-package]/install.tar
+3) cd /usr/local/samba/lib
+4) vi smb.conf
+
+Now modify smb.conf to reflect your site needs.
+
+5) samba start
+
+To stop samba:
+
+ samba stop
+
+You could install samba to run from the system start-up scripts
+(recommended) by running ./setup.sh
+
+Start / Stop Samba as follows:-
+
+ samba [start | stop]
+
+
+Subject: New Users Must Read This
+-----------------------------------
+Above ALL else, read the smb.conf man pages _AND_ all text documentation.
+
+To enable SMB encrypted password support do the following:
+
+1) Put /usr/local/samba/bin in your PATH
+2) Edit /usr/local/samba/lib/smb.conf and uncomment the
+ line "encrypt passwd = yes"
+3) Execute: smbpasswd -a "username" "password"
+
+The above will create your /usr/local/samba/private/smbpasswd file
+in which will be the NT and LanMAN hashed passwords.
+
diff --git a/packaging/Example/PackageDate b/packaging/Example/PackageDate
new file mode 100644
index 00000000000..95cbb0972bf
--- /dev/null
+++ b/packaging/Example/PackageDate
@@ -0,0 +1 @@
+# Month, WeekDay, Date, Year, PreparerCity, Country
diff --git a/packaging/Example/Packager b/packaging/Example/Packager
new file mode 100644
index 00000000000..f5db3f8c303
--- /dev/null
+++ b/packaging/Example/Packager
@@ -0,0 +1 @@
+Packager: John Doe <doej@somewhere.org>
diff --git a/packaging/Example/Packaging-instructions b/packaging/Example/Packaging-instructions
new file mode 100644
index 00000000000..b598fd68b15
--- /dev/null
+++ b/packaging/Example/Packaging-instructions
@@ -0,0 +1,16 @@
+The package building files should be located in a
+directory called: samba-X.X.X
+
+Where X.X.X is the version ID.
+
+Step Directions
+==== ============================================
+1. Copy the samba distribution tarball into the packaging directory
+2. Make sure you have a installed on your system the GNU gzip/gunzip files
+3. Edit "package-prep" script as required
+4. Run "package-prep"
+
+If all goes well, you should now have a usable distribution package.
+
+Note: Update the Instructions file as required.
+
diff --git a/packaging/Example/package-prep b/packaging/Example/package-prep
new file mode 100755
index 00000000000..e8f5089a865
--- /dev/null
+++ b/packaging/Example/package-prep
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Extract the skeleton directory structure into which samba will be installed.
+tar xvf skeleton.tar
+
+# Now link the skeleton directory structure into the final install tree.
+( cd /usr/local;
+ mv man man.orig;
+ mv samba samba.orig;
+ NOWDIR=`pwd`;
+ ln -sf $NOWDIR/usr/local/man man;
+ ln -sf $NOWDIR/usr/local/samba samba; )
+
+# Unpack the master source tarball
+gunzip samba-X.X.X.tar.gz
+tar xvf samba-X.X.X.tar
+
+# Now build the binary files
+cd samba-X.X.X/source
+./configure
+make
+make install
+
+# Install into the packaging tree that full reflects the final install tree
+cd $NOWDIR/usr/local/samba
+cp -pr man ../
+rm -rf man
+cd $NOWDIR
+
+# Create the package tarball
+tar cvf install.tar usr var
+
+# Clean up original sources preserving all configured files
+# Note: This will allow installers to check build options
+cd samba-X.X.X/source
+rm -f ../source/bin/*
+make clean
+cd ../..
+tar cvf samba-X.X.X.tar samba-X.X.X
+rm -rf samba-X.X.X
+rm -rf usr var
+cd ..
+tar cvf samba-X.X.X-OS-Version-CPU.tar samba-X.X.X
+gzip samba-X.X.X-OS-Version-CPU.tar
+
+# We now have the distribution package, now restore our runtime system
+cd samba-X.X.X
+tar xcf install.tar
+
+# Please test operation before shipping the binary distribution package
+# to the samba-team.
diff --git a/packaging/Example/samba.init b/packaging/Example/samba.init
new file mode 100755
index 00000000000..c1d605cda06
--- /dev/null
+++ b/packaging/Example/samba.init
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+if [ ! -d /usr/bin ]; then
+ echo "The /usr file system is not mounted."
+ exit 1
+fi
+
+killproc() {
+ pid=`/bin/ps ax | grep -w $1 | sed -e 's/^ *//' -e 's/ .*//'`
+ echo "Stopping $1 now."
+ [ "$pid" != "" ] && kill -15 $pid
+ echo $pid
+}
+
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+ 'start')
+ echo "Starting Samba"
+ /usr/local/samba/sbin/smbd
+ /usr/local/samba/sbin/nmbd
+ echo "Done."
+ ;;
+ 'stop')
+ killproc smbd
+ killproc nmbd
+ ;;
+ *)
+ echo "Usage: /sbin/init.d/samba.init [ start | stop ]"
+ ;;
+esac
+exit 0
diff --git a/packaging/Example/setup.sh b/packaging/Example/setup.sh
new file mode 100755
index 00000000000..994b16d5ef0
--- /dev/null
+++ b/packaging/Example/setup.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Note: This file MUST be edited to suit the target OS environment.
+#
+
+echo "Setting up for SWAT - The Samba Web Administration Tool"
+
+echo 'swat 901/tcp' >> /etc/services
+uniq /etc/services /tmp/tempserv
+cp /tmp/tempserv /etc/services
+rm /tmp/tempserv
+echo 'swat stream tcp nowait.400 root /usr/local/samba/bin/swat swat' >> /etc/inetd.conf
+uniq /etc/inetd.conf /tmp/tempinetd
+cp /tmp/tempinetd /etc/inetd.conf
+rm /tmp/tempinetd
+echo "Creating Symbolic Links for Start up Scripts"
+cp -f samba.init /sbin/init.d
+chown bin.bin /sbin/init.d/samba.init
+chmod 750 /sbin/init.d/samba.init
+ln -sf /sbin/init.d/samba.init /sbin/rc0.d/K01samba
+ln -sf /sbin/init.d/samba.init /sbin/rc2.d/K91samba
+ln -sf /sbin/init.d/samba.init /sbin/rc3.d/S91samba
+echo "Done. Now settting up samba command"
+ln /sbin/init.d/samba.init /sbin/samba
+echo "Done."
+echo "To start / stop samba:"
+echo " execute: samba [start | stop]
diff --git a/packaging/Example/skeleton.tar b/packaging/Example/skeleton.tar
new file mode 100644
index 00000000000..92598d0c5e7
--- /dev/null
+++ b/packaging/Example/skeleton.tar
Binary files differ
diff --git a/packaging/LSB/README b/packaging/LSB/README
new file mode 100644
index 00000000000..4ff0b99d769
--- /dev/null
+++ b/packaging/LSB/README
@@ -0,0 +1,6 @@
+README.lsb - 1 July 2001
+------------------------
+
+The files in this directory allow you to build an LSB-compliant
+version of SAMBA using the RPM software and the LSB development
+environment.
diff --git a/packaging/LSB/lsb-samba.spec b/packaging/LSB/lsb-samba.spec
new file mode 100644
index 00000000000..516eaa430eb
--- /dev/null
+++ b/packaging/LSB/lsb-samba.spec
@@ -0,0 +1,100 @@
+#
+# "$Id: lsb-samba.spec,v 1.2 2001/07/03 01:01:12 jra Exp $"
+#
+# Linux Standards Based RPM "spec" file for SAMBA.
+#
+
+Summary: SAMBA
+Name: lsb-samba
+Version: 2.2.1
+Release: 0
+Copyright: GPL
+Group: System Environment/Daemons
+Source: ftp://ftp.samba.org/pub/samba/samba-%{version}.tar.gz
+Url: http://www.samba.org
+Packager: Michael Sweet <mike@easysw.com>
+Vendor: SAMBA Team
+
+# Require the "lsb" package, which guarantees LSB compliance.
+Requires: lsb
+
+# use BuildRoot so as not to disturb the version already installed
+BuildRoot: /var/tmp/%{name}-root
+
+%description
+
+%prep
+%setup
+
+%build
+export LDFLAGS="-L/usr/lib/lsb --dynamic-linker=/lib/ld-lsb.so.1"
+
+./configure --with-fhs --prefix=/usr --sysconfdir=/etc \
+ --sharedstatedir=/var --datadir=/usr/share \
+ --with-configdir=/etc/samba \
+ --with-swatdir=/usr/share/samba/swat
+
+# If we got this far, all prerequisite libraries must be here.
+make
+
+%install
+# Make sure the RPM_BUILD_ROOT directory exists.
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+make \
+ BASEDIR=$RPM_BUILD_ROOT/usr \
+ BINDIR=$RPM_BUILD_ROOT/usr/bin \
+ CODEPAGEDIR=$RPM_BUILD_ROOT/usr/share/samba/codepages \
+ CONFIGDIR=$RPM_BUILD_ROOT/etc/samba \
+ INCLUDEDIR=$RPM_BUILD_ROOT/usr/include \
+ LIBDIR=$RPM_BUILD_ROOT/usr/lib \
+ LOCKDIR=$RPM_BUILD_ROOT/var/lock/samba \
+ LOGFILEBASE=$RPM_BUILD_ROOT/var/log/samba \
+ MANDIR=$RPM_BUILD_ROOT/usr/share/man \
+ SBINDIR=$RPM_BUILD_ROOT/usr/sbin \
+ SWATDIR=$RPM_BUILD_ROOT/usr/share/samba/swat \
+ VARDIR=$RPM_BUILD_ROOT/var \
+ install
+
+mkdir -p $RPM_BUILD_ROOT/etc/init.d
+install -m 700 packaging/LSB/samba.sh /etc/init.d/samba
+
+mkdir -p $RPM_BUILD_ROOT/etc/samba
+install -m 644 packaging/LSB/smb.conf /etc/samba
+
+mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
+install -m 644 packaging/LSB/samba.xinetd /etc/xinetd.d/samba
+
+%post
+/usr/lib/lsb/install_initd /etc/init.d/samba
+
+%preun
+/usr/lib/lsb/remove_initd /etc/init.d/samba
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%dir /etc/init.d
+/etc/init.d/samba
+%dir /etc/samba
+%config(noreplace) /etc/samba/smb.conf
+%dir /etc/samba/private
+%dir /etc/xinetd.d
+%config(noreplace) /etc/xinetd.d/samba
+%dir /usr/bin
+/usr/bin/*
+%dir /usr/sbin
+/usr/sbin/*
+%dir /usr/share/man
+/usr/share/man/*
+%dir /usr/share/samba
+/usr/share/samba/*
+%dir /var/lock/samba
+%dir /var/log/samba
+
+#
+# End of "$Id: lsb-samba.spec,v 1.2 2001/07/03 01:01:12 jra Exp $".
+#
diff --git a/packaging/LSB/samba.sh b/packaging/LSB/samba.sh
new file mode 100755
index 00000000000..99fa1b0117d
--- /dev/null
+++ b/packaging/LSB/samba.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# "$Id: samba.sh,v 1.2 2001/07/03 01:01:12 jra Exp $"
+#
+# SAMBA startup (init) script for LSB-compliant systems.
+#
+# Provides: smbd nmbd
+# Required-Start: 3 5
+# Required-Stop: 0 2 1 6
+# Default-Start: 3 5
+# Default-Stop: 0 2 1 6
+# Description: Starts and stops the SAMBA smbd and nmbd daemons \
+# used to provide SMB network services.
+#
+
+# Source LSB function library.
+. /lib/lsb/init-functions
+
+# Check that smb.conf exists.
+if test ! -f /etc/samba/smb.conf; then
+ log_failure_msg "The smb.conf file does not exist."
+ exit 6
+fi
+
+# Make sure that smbd and nmbd exist...
+if test ! -f /usr/sbin/nmbd -o ! -f /usr/sbin/smbd; then
+ log_failure_msg "The nmbd and/or smbd daemons are not installed."
+ exit 5
+fi
+
+# See how we were called.
+case "$1" in
+ start)
+ start_daemon nmbd -D
+ start_daemon smbd -D
+ log_success_msg "Started SMB services."
+ ;;
+
+ stop)
+ killproc smbd
+ killproc nmbd
+ log_success_msg "Shutdown SMB services."
+ ;;
+
+ reload)
+ # smbd and nmbd automatically re-read the smb.conf file...
+ log_success_msg "Reload not necessary with SAMBA."
+ ;;
+
+ status)
+ if test -z "`pidofproc smbd`"; then
+ log_success_msg "smbd is not running."
+ else
+ log_success_msg "smbd is running."
+ fi
+ if test -z "`pidofproc nmbd`"; then
+ log_success_msg "nmbd is not running."
+ else
+ log_success_msg "nmbd is running."
+ fi
+ ;;
+
+
+ restart | force-reload)
+ $0 stop
+ $0 start
+ ;;
+
+ *)
+ echo "Usage: smb {start|stop|reload|force-reload|restart|status}"
+ exit 1
+ ;;
+esac
+
+# Return "success"
+exit 0
+
+#
+# End of "$Id: samba.sh,v 1.2 2001/07/03 01:01:12 jra Exp $".
+#
diff --git a/packaging/LSB/samba.xinetd b/packaging/LSB/samba.xinetd
new file mode 100644
index 00000000000..8c38b354218
--- /dev/null
+++ b/packaging/LSB/samba.xinetd
@@ -0,0 +1,15 @@
+# default: off
+# description: SWAT is the Samba Web Admin Tool. Use swat \
+# to configure your Samba server. To use SWAT, \
+# connect to port 901 with your favorite web browser.
+service swat
+{
+ port = 901
+ socket_type = stream
+ wait = no
+ only_from = localhost
+ user = root
+ server = /usr/sbin/swat
+ log_on_failure += USERID
+ disable = yes
+}
diff --git a/packaging/LSB/smb.conf b/packaging/LSB/smb.conf
new file mode 100644
index 00000000000..71ff9463884
--- /dev/null
+++ b/packaging/LSB/smb.conf
@@ -0,0 +1,290 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not made any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = /etc/printcap
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/samba/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/samba/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/samba/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; read only = yes
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Mandrake/.cvsignore b/packaging/Mandrake/.cvsignore
new file mode 100644
index 00000000000..ffcc2e7e5ee
--- /dev/null
+++ b/packaging/Mandrake/.cvsignore
@@ -0,0 +1,2 @@
+makerpms.sh
+samba2.spec
diff --git a/packaging/Mandrake/README b/packaging/Mandrake/README
new file mode 100644
index 00000000000..1c5bb30edc0
--- /dev/null
+++ b/packaging/Mandrake/README
@@ -0,0 +1,11 @@
+Preparation Date: Sat Apr 14 2001
+Preparer: John H Terpstra <jht@samba.org>
+
+Instructions: Preparing Samba Packages for Mandrake Linux 7.2
+===============================================================
+
+We provide support only for current versions of Mandrake Linux.
+
+To produce the RPMS simply type:
+ sh makerpms.sh
+
diff --git a/packaging/Mandrake/empty.patch b/packaging/Mandrake/empty.patch
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/packaging/Mandrake/empty.patch
diff --git a/packaging/Mandrake/findsmb b/packaging/Mandrake/findsmb
new file mode 100755
index 00000000000..986c2481779
--- /dev/null
+++ b/packaging/Mandrake/findsmb
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/Mandrake/makerpms.sh.tmpl b/packaging/Mandrake/makerpms.sh.tmpl
new file mode 100644
index 00000000000..c4ad9c6b581
--- /dev/null
+++ b/packaging/Mandrake/makerpms.sh.tmpl
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Copyright (C) 1998 John H Terpstra, 1999 K Spoon
+#
+SPECDIR=/usr/src/RPM/SPECS
+SRCDIR=/usr/src/RPM/SOURCES
+USERID=`id -u`
+GRPID=`id -g`
+VERSION='PVERSION'
+
+( cd ../../.. ; mv samba samba-$VERSION; chown -R ${USERID}.${GRPID} ${SRCDIR}/samba-$VERSION )
+( cd ../../.. ; tar --exclude=CVS -czvf ${SRCDIR}/samba-$VERSION.tar.gz samba-$VERSION )
+( cd ../../.. ; mv samba-$VERSION samba )
+cp -a *.spec $SPECDIR
+cp -a *.patch smb.* samba.log $SRCDIR
+cd $SPECDIR
+rpm -ba -v samba2.spec
diff --git a/packaging/Mandrake/samba.log b/packaging/Mandrake/samba.log
new file mode 100644
index 00000000000..7dc1667bafe
--- /dev/null
+++ b/packaging/Mandrake/samba.log
@@ -0,0 +1,15 @@
+/var/log/samba/log.nmbd {
+ notifempty
+ missingok
+ postrotate
+ /usr/bin/killall -HUP nmbd
+ endscript
+}
+
+/var/log/samba/log.smbd {
+ notifempty
+ missingok
+ postrotate
+ /usr/bin/killall -HUP smbd
+ endscript
+}
diff --git a/packaging/Mandrake/samba.pamd b/packaging/Mandrake/samba.pamd
new file mode 100644
index 00000000000..30912de1726
--- /dev/null
+++ b/packaging/Mandrake/samba.pamd
@@ -0,0 +1,5 @@
+#%PAM-1.0
+auth required /lib/security/pam_nologin.so
+auth required /lib/security/pam_stack.so service=system-auth
+account required /lib/security/pam_stack.so service=system-auth
+session required /lib/security/pam_stack.so service=system-auth
diff --git a/packaging/Mandrake/samba.xinetd b/packaging/Mandrake/samba.xinetd
new file mode 100644
index 00000000000..a6dea1f7405
--- /dev/null
+++ b/packaging/Mandrake/samba.xinetd
@@ -0,0 +1,15 @@
+# default: on
+# description: SWAT is the Samba Web Admin Tool. Use swat \
+# to configure your Samba server. To use SWAT, \
+# connect to port 901 with your favorite web browser.
+service swat
+{
+ port = 901
+ socket_type = stream
+ wait = no
+ only_from = localhost
+ user = root
+ server = /usr/sbin/swat
+ log_on_failure += USERID
+ disable = no
+}
diff --git a/packaging/Mandrake/samba2.spec.tmpl b/packaging/Mandrake/samba2.spec.tmpl
new file mode 100644
index 00000000000..5bc92535f80
--- /dev/null
+++ b/packaging/Mandrake/samba2.spec.tmpl
@@ -0,0 +1,300 @@
+Summary: Samba SMB client and server
+Name: samba
+Version: PVERSION
+Release: PRELEASE
+Copyright: GNU GPL version 2
+Group: Networking
+Source: ftp://samba.org/pub/samba/samba-%{version}.tar.gz
+Packager: Gerald (Jerry) Carter [Samba-Team] <jerry@samba.org>
+Requires: pam >= 0.72 kernel >= 2.2.1 glibc >= 2.1.2
+Prereq: chkconfig fileutils
+BuildRoot: /var/tmp/samba
+Prefix: /usr
+
+%description
+Samba provides an SMB server which can be used to provide
+network services to SMB (sometimes called "Lan Manager")
+clients, including various versions of MS Windows, OS/2,
+and other Linux machines. Samba also provides some SMB
+clients, which complement the built-in SMB filesystem
+in Linux. Samba uses NetBIOS over TCP/IP (NetBT) protocols
+and does NOT need NetBEUI (Microsoft Raw NetBIOS frame)
+protocol.
+
+Samba-2.2 features working NT Domain Control capability and
+includes the SWAT (Samba Web Administration Tool) that
+allows samba's smb.conf file to be remotely managed using your
+favourite web browser. For the time being this is being
+enabled on TCP port 901 via inetd.
+
+Users are advised to use Samba-2.2 as a Windows NT4
+Domain Controller only on networks that do NOT have a Windows
+NT Domain Controller. This release does NOT as yet have
+Backup Domain control ability.
+
+Please refer to the WHATSNEW.txt document for fixup information.
+This binary release includes encrypted password support.
+
+Please read the smb.conf file and ENCRYPTION.txt in the
+docs directory for implementation details.
+
+%changelog
+* Mon May 21 2001 Gerald (Jerry) Carter <jerry@samba.org>
+ - removed docs/htmldocs and docs/manpages from /usr/share/docs
+ These het installed in /usr/share/swat already
+ - Fix for codepages and src not getting installed in the RPM
+ - Fixed minor typos
+
+* Mon Apr 23 2001 Gerald (Jerry) Carter <jerry@samba.org>
+ - Added a few bug fixes to release the first Mandrake RPMS
+
+* Sat Apr 14 2001 John H Terpstra <jht@samba.org>
+ - Added official samba-team support for Mandrakesoft
+ - We get a lot of requests for this!
+
+%prep
+%setup
+
+%build
+cd source
+
+%ifarch ia64
+libtoolize --copy --force # get it to recognize IA-64
+autoconf
+autoheader
+EXTRA="-D_LARGEFILE64_SOURCE"
+%endif
+
+NUMCPU=`grep processor /proc/cpuinfo | wc -l`
+
+CFLAGS="$RPM_OPT_FLAGS $EXTRA" ./configure \
+ --prefix=%{prefix} \
+ --with-fhs \
+ --libdir=/etc/samba \
+ --localstatedir=/var \
+ --with-codepagedir=%{prefix}/share/samba/codepages \
+ --with-configdir=/etc/samba \
+ --with-lockdir=/var/lock/samba \
+ --with-swatdir=%{prefix}/share/swat \
+ --with-quotas \
+ --with-smbmount \
+ --with-pam \
+ --with-pam_smbpass \
+ --with-syslog \
+ --with-utmp \
+ --with-netatalk \
+ --with-sambabook=%{prefix}/share/swat/using_samba
+
+make -j${NUMCPU} proto
+make -j${NUMCPU} all smbfilter nsswitch/libnss_wins.so debug2html
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/etc/{logrotate.d,pam.d,samba,xinetd.d}
+mkdir -p $RPM_BUILD_ROOT/etc/samba/security
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+mkdir -p $RPM_BUILD_ROOT/lib/security
+mkdir -p $RPM_BUILD_ROOT%{prefix}/{bin,sbin}
+mkdir -p $RPM_BUILD_ROOT/home/samba
+mkdir -p $RPM_BUILD_ROOT/sbin
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/{images,help,include}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/samba/codepages/src
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/{figs,gifs}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/man/{man1,man5,man7,man8}
+mkdir -p $RPM_BUILD_ROOT/var/lock/samba
+mkdir -p $RPM_BUILD_ROOT/var/log/samba
+mkdir -p $RPM_BUILD_ROOT/var/spool/samba
+
+# Install standard binary files
+for i in nmblookup smbclient smbpasswd smbstatus testparm testprns \
+ make_smbcodepage make_unicodemap make_printerdef rpcclient smbspool \
+ smbmount smbumount smbmnt
+do
+ install -m755 -s source/bin/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+for i in smbtar
+do
+ install -m755 source/script/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat debug2html smbfilter
+do
+ install -m755 -s source/bin/$i $RPM_BUILD_ROOT%{prefix}/sbin
+done
+
+# we need a symlink for mount to recognise the smb and smbfs filesystem types
+ln -sf %{prefix}/bin/smbmount $RPM_BUILD_ROOT/sbin/mount.smbfs
+ln -sf %{prefix}/bin/smbmount $RPM_BUILD_ROOT/sbin/mount.smb
+
+# Install codepage source files
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251; do
+ install -m644 source/codepages/codepage_def.$i $RPM_BUILD_ROOT%{prefix}/share/samba/codepages/src
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R; do
+ install -m644 source/codepages/CP$i.TXT $RPM_BUILD_ROOT%{prefix}/share/samba/codepages/src
+done
+
+# Install the nsswitch library extenstion file
+install -m755 source/nsswitch/libnss_wins.so $RPM_BUILD_ROOT/lib
+# Make link for wins resolver
+( cd $RPM_BUILD_ROOT/lib; ln -s libnss_wins.so libnss_wins.so.2; )
+
+# PAM Authentication file
+install -m755 source/bin/pam_smbpass.so $RPM_BUILD_ROOT/lib/security
+
+# Install SWAT helper files
+for i in swat/help/*.html docs/htmldocs/*.html; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/help
+done
+for i in swat/images/*.gif; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/images
+done
+for i in swat/include/*.html; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/include
+done
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif; do
+ install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/gifs
+done
+
+# Install the miscellany
+install -m644 swat/README $RPM_BUILD_ROOT%{prefix}/share/swat
+# Install level 1 man pages
+for i in *.1; do
+ install -m644 docs/manpages/$i $RPM_BUILD_ROOT%{prefix}/share/man/man1
+done
+install -m644 docs/manpages/smb.conf.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+install -m644 docs/manpages/lmhosts.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+install -m644 docs/manpages/smbpasswd.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+
+install -m644 docs/manpages/samba.7 $RPM_BUILD_ROOT%{prefix}/share/man/man7
+
+install -m644 docs/manpages/smbd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/nmbd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbpasswd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/swat.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbmount.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbmnt.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbumount.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbspool.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+
+install -m644 swat/README $RPM_BUILD_ROOT%{prefix}/share/swat
+
+install -m644 packaging/Mandrake/smb.con* $RPM_BUILD_ROOT/etc/samba/
+install -m644 packaging/Mandrake/smbusers $RPM_BUILD_ROOT/etc/samba/smbusers
+install -m755 packaging/Mandrake/smbprint $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/Mandrake/findsmb $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/Mandrake/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb
+install -m755 packaging/Mandrake/smb.init $RPM_BUILD_ROOT%{prefix}/sbin/samba
+install -m644 packaging/Mandrake/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba
+install -m644 packaging/Mandrake/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba
+install -m644 packaging/Mandrake/samba.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/swat
+echo 127.0.0.1 localhost > $RPM_BUILD_ROOT/etc/samba/lmhosts
+
+##
+## remove these directories so they don't get installed twice
+##
+/bin/rm -rf docs/htmldocs
+/bin/rm -rf docs/manpages
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/chkconfig --add smb
+/sbin/chkconfig smb off
+
+# Build codepage load files
+cd %{prefix}/share/samba/codepages
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+%{prefix}/bin/make_smbcodepage c $i %{prefix}/share/samba/codepages/src/codepage_def.$i %{prefix}/share/samba/codepages/codepage.$i
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+%{prefix}/bin/make_unicodemap $i %{prefix}/share/samba/codepages/src/CP$i.TXT %{prefix}/share/samba/codepages/unicode_map.$i
+done
+
+# Add swat entry to /etc/services if not already there
+if !( grep ^[:space:]*swat /etc/services > /dev/null ) then
+ echo 'swat 901/tcp # Add swat service used via inetd' >> /etc/services
+fi
+
+%preun
+if [ $1 = 0 ] ; then
+ /sbin/chkconfig --del smb
+
+ # We want to remove the browse.dat file
+ if [ -e /var/lock/samba/browse.dat ]; then
+ rm -f /var/lock/samba/browse.dat
+ fi
+fi
+
+%postun
+# Only delete remnants of samba if this is the final deletion.
+if [ $1 = 0 ] ; then
+ if [ -x /etc/pam.d/samba ]; then
+ rm -f /etc/pam.d/samba
+ fi
+ if [ -e /var/log/samba ]; then
+ rm -rf /var/log/samba
+ fi
+ if [ -e /var/lock/samba ]; then
+ rm -rf /var/lock/samba
+ fi
+
+ # Remove swat entries from /etc/inetd.conf and /etc/services
+ cd /etc
+ tmpfile=/etc/tmp.$$
+ sed -e '/^[:space:]*swat.*$/d' /etc/services > $tmpfile
+ mv $tmpfile services
+fi
+
+%triggerpostun -- samba < samba-2.0.0
+if [ $0 != 0 ]; then
+ /sbin/chkconfig --add smb
+fi
+
+%files
+%doc README COPYING Manifest Read-Manifest-Now
+%doc WHATSNEW.txt Roadmap
+%doc docs
+%doc swat/README
+%doc examples
+%attr(-,root,root) %{prefix}/sbin/*
+%attr(-,root,root) /sbin/*
+%attr(-,root,root) %{prefix}/bin/*
+%attr(755,root,root) /lib/*
+%attr(-,root,root) %{prefix}/share/swat/help/*
+%attr(-,root,root) %{prefix}/share/swat/images/*
+%attr(-,root,root) %{prefix}/share/swat/include/*
+%attr(-,root,root) %{prefix}/share/swat/using_samba/*
+%attr(-,root,root) %config(noreplace) /etc/samba/lmhosts
+%attr(-,root,root) %config(noreplace) /etc/samba/smb.conf
+%attr(-,root,root) %config(noreplace) /etc/samba/smbusers
+%attr(-,root,root) /etc/rc.d/init.d/smb
+%attr(-,root,root) /etc/logrotate.d/samba
+%attr(-,root,root) %config(noreplace) /etc/pam.d/samba
+%attr(-,root,root) %{prefix}/share/man/man1/*
+%attr(-,root,root) %{prefix}/share/man/man5/*
+%attr(-,root,root) %{prefix}/share/man/man7/*
+%attr(-,root,root) %{prefix}/share/man/man8/*
+%attr(-,root,root) %dir /etc/samba/
+%attr(-,root,root) %dir /usr/share/samba/codepages/*
+%attr(-,root,root) %dir /usr/share/samba/codepages/src/*
+%attr(-,root,root) %dir /var/lock/samba
+%attr(-,root,root) %dir /var/log/samba
+%attr(1777,root,root) %dir /var/spool/samba
+
+
+
diff --git a/packaging/Mandrake/smb.conf b/packaging/Mandrake/smb.conf
new file mode 100644
index 00000000000..a14e90ec16b
--- /dev/null
+++ b/packaging/Mandrake/smb.conf
@@ -0,0 +1,320 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not made any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MDKGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server %v
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# Enabling internationalization:
+# you can match a Windows code page with a UNIX character set.
+# Windows: 437 (US), 737 (GREEK), 850 (Latin1 - Western European),
+# 852 (Eastern Eu.), 861 (Icelandic), 932 (Cyrillic - Russian),
+# 936 (Japanese - Shift-JIS), 936 (Simpl. Chinese), 949 (Korean Hangul),
+# 950 (Trad. Chin.).
+# UNIX: ISO8859-1 (Western European), ISO8859-2 (Eastern Eu.),
+# ISO8859-5 (Russian Cyrillic), KOI8-R (Alt-Russ. Cyril.)
+# This is an example for french users:
+; client code page = 850
+; character set = ISO8859-1
+
+
+# CHANGES TO ENABLE PRINTING ON ALL CUPS PRINTERS IN THE NETWORK
+# (as cups is now used in linux-mandrake 7.2 by default)
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = lpstat
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx, cups
+ printing = cups
+
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/samba/private/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /var/lib/samba/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+#Uncomment the following 2 lines if you would like your login scripts to
+#be created dynamically by ntlogon (check that you have it in the correct
+#locationn (the default of the ntlogon rpm available in contribs)
+;root preexec = /usr/bin/ntlogon -u %U -g %G -o %a -d /var/lib/samba/netlogon
+;root postexec = rm -f /var/lib/samba/netlogon/%U.bat
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /var/lib/samba/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a CUPS print system there is no need to
+# specifically define each individual printer.
+# You must configure the samba printers with the appropriate Windows
+# drivers on your Windows clients. On the Samba server no filtering is
+# done. If you wish that the server provides the driver and the clients
+# send PostScript ("Generic PostScript Printer" under Windows), you have
+# to swap the 'print command' line below with the commented one.
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# to allow user 'guest account' to print.
+ guest ok = yes
+ writable = no
+ printable = yes
+ create mode = 0700
+# =====================================
+# print command: see above for details.
+# =====================================
+ print command = lpr-cups -P %p -o raw %s -r # using client side printer drivers.
+; print command = lpr-cups -P %p %s # using cups own drivers (use generic PostScript on clients).
+ lpq command = lpstat -o %p
+ lprm command = cancel %p-%j
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba/public
+; public = yes
+; writable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Mandrake/smb.init b/packaging/Mandrake/smb.init
new file mode 100755
index 00000000000..8855f04efba
--- /dev/null
+++ b/packaging/Mandrake/smb.init
@@ -0,0 +1,93 @@
+#!/bin/sh
+#
+# chkconfig: - 91 35
+# description: Starts and stops the Samba smbd and nmbd daemons \
+# used to provide SMB network services.
+
+# Source function library.
+if [ -f /etc/init.d/functions ] ; then
+ . /etc/init.d/functions
+elif [ -f /etc/rc.d/init.d/functions ] ; then
+ . /etc/rc.d/init.d/functions
+else
+ exit 0
+fi
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+# Check that smb.conf exists.
+[ -f /etc/samba/smb.conf ] || exit 0
+
+RETVAL=0
+
+
+start() {
+ echo -n "Starting SMB services: "
+ daemon smbd -D
+ RETVAL=$?
+ echo
+ echo -n "Starting NMB services: "
+ daemon nmbd -D
+ RETVAL2=$?
+ echo
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 ] && touch /var/lock/subsys/smb || \
+ RETVAL=1
+ return $RETVAL
+}
+stop() {
+ echo -n "Shutting down SMB services: "
+ killproc smbd
+ RETVAL=$?
+ echo
+ echo -n "Shutting down NMB services: "
+ killproc nmbd
+ RETVAL2=$?
+ [ $RETVAL -eq 0 -a $RETVAL2 -eq 0 ] && rm -f /var/lock/subsys/smb
+ echo ""
+ return $RETVAL
+}
+restart() {
+ stop
+ start
+}
+reload() {
+ echo -n "Reloading smb.conf file: "
+ killproc smbd -HUP
+ RETVAL=$?
+ echo
+ return $RETVAL
+}
+mdkstatus() {
+ status smbd
+ status nmbd
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reload)
+ reload
+ ;;
+ status)
+ mdkstatus
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/smb ] && restart || :
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|status|condrestart}"
+ exit 1
+esac
+
+exit $?
diff --git a/packaging/Mandrake/smbprint b/packaging/Mandrake/smbprint
new file mode 100755
index 00000000000..0d07c9c7833
--- /dev/null
+++ b/packaging/Mandrake/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to same space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "//$server/$service" $password -U $server -N -P >> $logfile
diff --git a/packaging/Mandrake/smbusers b/packaging/Mandrake/smbusers
new file mode 100644
index 00000000000..ae3389f53f8
--- /dev/null
+++ b/packaging/Mandrake/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nobody = guest pcguest smbguest
diff --git a/packaging/PHT/TurboLinux/.cvsignore b/packaging/PHT/TurboLinux/.cvsignore
new file mode 100644
index 00000000000..0238ed8cae6
--- /dev/null
+++ b/packaging/PHT/TurboLinux/.cvsignore
@@ -0,0 +1,3 @@
+makefile-path.patch
+makerpms.sh
+samba2.spec
diff --git a/packaging/PHT/TurboLinux/README b/packaging/PHT/TurboLinux/README
new file mode 100644
index 00000000000..867ff01811b
--- /dev/null
+++ b/packaging/PHT/TurboLinux/README
@@ -0,0 +1,11 @@
+Preparation Date: October 25, 1998
+Preparer: John H Terpstra <jht@samba.org>
+
+Instructions: Preparing Samba Packages for TurboLinux
+===============================================================
+
+We provide support only for current versions of TurboLinux.
+
+To produce the RPMS simply type:
+ sh makerpms.sh
+
diff --git a/packaging/PHT/TurboLinux/findsmb b/packaging/PHT/TurboLinux/findsmb
new file mode 100755
index 00000000000..986c2481779
--- /dev/null
+++ b/packaging/PHT/TurboLinux/findsmb
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/PHT/TurboLinux/makerpms.sh.tmpl b/packaging/PHT/TurboLinux/makerpms.sh.tmpl
new file mode 100644
index 00000000000..c389bf1a68a
--- /dev/null
+++ b/packaging/PHT/TurboLinux/makerpms.sh.tmpl
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright (C) 1998 John H Terpstra, 1999 K Spoon
+#
+SPECDIR=/usr/src/turbo/SPECS
+SRCDIR=/usr/src/turbo/SOURCES
+USERID=`id -u`
+GRPID=`id -g`
+
+( cd ../../../.. ; chown -R ${USERID}.${GRPID} ${SRCDIR}/samba-PVERSION )
+( cd ../../../.. ; tar czvf ${SRCDIR}/samba-PVERSION.tar.gz samba-PVERSION )
+cp -a *.spec $SPECDIR
+cp -a *.patch smb.* samba.log $SRCDIR
+cd $SPECDIR
+rpm -ba -v samba2.spec
diff --git a/packaging/PHT/TurboLinux/samba.log b/packaging/PHT/TurboLinux/samba.log
new file mode 100644
index 00000000000..c5f2a5b45bc
--- /dev/null
+++ b/packaging/PHT/TurboLinux/samba.log
@@ -0,0 +1,11 @@
+/var/log/samba/log.nmb {
+ postrotate
+ /usr/bin/killall -HUP nmbd
+ endrotate
+}
+
+/var/log/samba/log.smb {
+ postrotate
+ /usr/bin/killall -HUP smbd
+ endrotate
+}
diff --git a/packaging/PHT/TurboLinux/samba.pamd b/packaging/PHT/TurboLinux/samba.pamd
new file mode 100644
index 00000000000..225ab724ec9
--- /dev/null
+++ b/packaging/PHT/TurboLinux/samba.pamd
@@ -0,0 +1,11 @@
+#%PAM-1.0
+#[For version 1.0 syntax, the above header is optional]
+#
+# The PAM configuration file for the `samba' service
+#
+auth required /lib/security/pam_pwdb.so nullok nodelay # shadow audit
+# auth required /lib/security/pam_smbpass.so nodelay
+account required /lib/security/pam_pwdb.so audit nodelay
+session required /lib/security/pam_pwdb.so nodelay
+password required /lib/security/pam_pwdb.so # shadow md5
+#password required /lib/security/pam_smbpass.so nodelay smbconf=/etc/samba.d/smb.conf
diff --git a/packaging/PHT/TurboLinux/samba2.spec.tmpl b/packaging/PHT/TurboLinux/samba2.spec.tmpl
new file mode 100644
index 00000000000..0633f62a7e7
--- /dev/null
+++ b/packaging/PHT/TurboLinux/samba2.spec.tmpl
@@ -0,0 +1,502 @@
+Summary: Samba SMB client and server
+Name: samba
+Version: PVERSION
+Release: PRELEASE
+Copyright: GNU GPL version 2
+Group: Networking
+Source: ftp://samba.org/pub/samba/samba-PVERSION.tar.gz
+Patch: smbw.patch
+Requires: pam >= 0.64 kernel >= 2.2.1 glibc >= 2.1.2
+Prereq: chkconfig fileutils
+BuildRoot: /var/tmp/samba
+Prefix: /usr
+
+%package debugtools
+Version: PVERSION
+Release: PRELEASE
+Group: Networking
+Summary: Programs to debug Samba and to test SMB client integrity
+
+%package -n smbfs
+Version: PVERSION
+Release: PRELEASE
+Group: Utilities/File
+Summary: Programs to mount SMB shares.
+
+%description
+Samba provides an SMB server which can be used to provide
+network services to SMB (sometimes called "Lan Manager")
+clients, including various versions of MS Windows, OS/2,
+and other Linux machines. Samba also provides some SMB
+clients, which complement the built-in SMB filesystem
+in Linux. Samba uses NetBIOS over TCP/IP (NetBT) protocols
+and does NOT need NetBEUI (Microsoft Raw NetBIOS frame)
+protocol.
+
+Samba-2.2 features working NT Domain Control capability and
+includes the SWAT (Samba Web Administration Tool) that
+allows samba's smb.conf file to be remotely managed using your
+favourite web browser. For the time being this is being
+enabled on TCP port 901 via inetd.
+
+Users are advised to use Samba-2.2 as a Windows NT4
+Domain Controller only on networks that do NOT have a Windows
+NT Domain Controller. This release does NOT as yet have
+Backup Domain control ability.
+
+Please refer to the WHATSNEW.txt document for fixup information.
+This binary release includes encrypted password support.
+
+Please read the smb.conf file and ENCRYPTION.txt in the
+docs directory for implementation details.
+
+NOTE: TurboLinux uses PAM which has integrated support
+for Shadow passwords and quotas. Do NOT recompile with the
+SHADOW_PWD option enabled.
+
+
+%description -n smbfs
+This package includes the tools necessary to mount filesystems from
+SMB servers.
+
+Smbmount and smbumount are an interface to the SMB filesystem. Smbfs is
+a filesystem which understands the SMB protocol. This is the protocol
+Windows for Workgroups, Windows NT or Lan Manager use to talk to each
+other. It was inspired by samba, the program by Andrew Tridgell that
+turns any unix site into a file server for DOS or Windows clients. See
+http://samba.org/samba for this interesting program suite and lots of
+more information on SMB and NetBIOS over TCP/IP. There you also find
+explanation for conceps like NetBIOS name or share.
+
+%changelog
+* Tue Mar 27 2001 John H Terpstra <jht@samba.org>
+- Fixes to make 2.2 compile
+
+* Sat Nov 04 2000 John H Terpstra <jht@samba.org>
+- Put Symlink for libnss_wins.so back into main install section
+
+* Fri Nov 3 2000 Uros Prestor <uros@turbolinux.com>
+- ported to IA-64
+
+* Mon Oct 09 2000 John H Terpstra <jht@turbolinux.com>
+- Started move to Samba-2.2.0
+- Added nsswitch wins support
+
+* Mon May 29 2000 John H Terpstra <jht@turbolinux.com>
+- moved linkage of libnss_wins.so.2 to %post
+- added removal step to %postun
+
+* Fri Apr 14 2000 John H Terpstra <jht@turbolinux.com>
+- Added unicode pages
+
+* Sat Apr 08 2000 John H Terpsta <jht@turbolinux.com>
+- Added nsswitch stuff
+- Fixed some typos
+- Changed hard link for smbmount to symlink
+
+* Sun Apr 02 2000 John H Terpstra <jht@turbolinux.com>
+- Updated for samba-2.0.7
+- Added codepages 775 1251
+- Added configure options "--with-profile --with-utmp
+ --with-netatalk --with-sambabook=/usr/share/swat/using_samba"
+- added using_samba book
+
+* Fri Oct 29 1999 Kelley Spoon <kspoon@turbolinux.com>
+- get rid of the rc?.d directories
+- -j flags for make command to (hopefully) speed up on
+ SMP systems
+- discoverd that John had already made the changes I
+ was going to do...
+- Wait! He forgot to move the man pages into /usr/share!
+ Cool... I get to do something substantial.
+
+* Sun Oct 16 1999 John H Terspstra <jht@turbolinux.com>
+- changed mount.smb to link to smbmount
+- removed smbwrappers as it is broken with glibc-2.1.x
+
+* Sun May 09 1999 John H Terpstra <jht@samba.org>
+- Added smbtorture et al.
+
+* Wed Mar 10 1999 Scott Stone <sstone@turbolinux.com>
+- This package now builds smbfs stuff
+- Added xinetd autosetup in the post install section
+- (todo: add remove of xinetd stuff in postuninstall section)
+
+* Sun Feb 28 1999 Jeremy Allison <jra@samba.org>
+ - Removed smbrun binary and tidied up some loose ends
+
+* Sun Oct 25 1998 John H Terpstra <jht@samba.org>
+ - Added modifier to /config specifier so that smb.conf,
+ lmhosts and smbusers never get lost
+
+* Sat Oct 24 1998 John H Terpstra <jht@samba.org>
+ - removed README.smbsh file from docs area
+
+* Mon Oct 05 1998 John H Terpstra <jht@samba.org>
+ - Added rpcclient to binaries list
+ - Added smbwrapper stuff
+
+* Fri Aug 21 1998 John H Terpstra <jht@samba.org>
+ - Updated for Samba version 2.0 building
+
+* Tue Jul 07 1998 Erik Troan <ewt@redhat.com>
+ - updated postun triggerscript to check $0
+ - clear /etc/codepages from %preun instead of %postun
+
+* Sat Jul 04 1998 John H Terpstra <jht@samba.org>
+ - fixed codepage preservation during update via -Uvh
+
+* Mon Jun 08 1998 Erik Troan <ewt@redhat.com>
+ - made the %postun script a tad less agressive; no reason to remove
+ the logs or lock file
+ - the %postun and %preun should only exectute if this is the final
+ removal
+ - migrated %triggerpostun from Red Hat's samba package to work around
+ packaging problems in some Red Hat samba releases
+
+* Sun Apr 26 1998 John H Terpstra <jht@samba.org>
+ - Tidy up for early alpha releases
+ - added findsmb from SGI packaging
+
+* Thu Apr 09 1998 John H Terpstra <jht@samba.org>
+ - Updated spec file
+ - Included new codepage.936
+
+* Sat Mar 20 1998 John H Terpstra <jht@samba.org>
+ - Added swat facility
+
+* Sat Jan 24 1998 John H Terpstra <jht@samba.org>
+ - Many optimisations (some suggested by Manoj Kasichainula <manojk@io.com>
+ - Use of chkconfig in place of individual symlinks to /etc/rc.d/init/smb
+ - Compounded make line
+ - Updated smb.init restart mechanism
+ - Use compound mkdir -p line instead of individual calls to mkdir
+ - Fixed smb.conf file path for log files
+ - Fixed smb.conf file path for incoming smb print spool directory
+ - Added a number of options to smb.conf file
+ - Added smbadduser command (missed from all previous RPMs) - Doooh!
+ - Added smbuser file and smb.conf file updates for username map
+
+%prep
+%setup
+%patch -p1
+
+
+%build
+cd source
+
+%ifarch ia64
+libtoolize --copy --force # get it to recognize IA-64
+%endif
+
+autoconf
+autoheader
+NUMCPU=`grep processor /proc/cpuinfo | wc -l`
+CFLAGS="$RPM_OPT_FLAGS $EXTRA" ./configure \
+ --prefix=%{prefix} \
+ --libdir=/etc/samba \
+ --with-lockdir=/var/lock/samba \
+ --with-privatedir=/etc \
+ --with-swatdir=%{prefix}/share/swat \
+ --with-quotas \
+ --with-smbmount \
+ --with-pam \
+ --with-pam_smbpass \
+ --with-profile \
+ --with-syslog \
+ --with-utmp \
+ --with-netatalk \
+ --with-sambabook=%{prefix}/share/swat/using_samba
+
+make -j${NUMCPU} all smbfilter nsswitch/libnss_wins.so
+make -j${NUMCPU} debug2html
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/sbin
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/samba/codepages/src
+mkdir -p $RPM_BUILD_ROOT/etc/samba
+mkdir -p $RPM_BUILD_ROOT/etc/{logrotate.d,pam.d}
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+mkdir -p $RPM_BUILD_ROOT/lib
+mkdir -p $RPM_BUILD_ROOT/home/samba
+mkdir -p $RPM_BUILD_ROOT%{prefix}/{bin,sbin}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/{gifs,figs}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/{images,help,include}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/man/{man1,man5,man7,man8}
+mkdir -p $RPM_BUILD_ROOT/var/lock/samba
+mkdir -p $RPM_BUILD_ROOT/var/log/samba
+mkdir -p $RPM_BUILD_ROOT/var/spool/samba
+
+# Install standard binary files
+for i in nmblookup smbclient smbpasswd smbstatus testparm testprns \
+ make_smbcodepage make_unicodemap make_printerdef rpcclient smbspool
+do
+install -m755 -s source/bin/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+for i in mksmbpasswd.sh smbtar
+do
+install -m755 source/script/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat smbmount smbumount smbmnt debug2html smbfilter
+do
+install -m755 -s source/bin/$i $RPM_BUILD_ROOT/usr/sbin
+done
+
+
+# Install level 1 man pages
+for i in *.1
+do
+install -m644 docs/manpages/$i $RPM_BUILD_ROOT%{prefix}/share/man/man1
+done
+
+# Install codepage source files
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+install -m644 source/codepages/codepage_def.$i $RPM_BUILD_ROOT%{prefix}/samba/codepages/src
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+install -m644 source/codepages/CP$i.TXT $RPM_BUILD_ROO%{prefix}/samba/codepages/src
+done
+
+# Install the nsswitch library extension file
+install -m755 source/nsswitch/libnss_wins.so $RPM_BUILD_ROOT/lib
+# Make link for wins resolver
+( cd $RPM_BUILD_ROOT/lib; ln -s libnss_wins.so libnss_wins.so.2; )
+
+# Install PAM pam_smbpass.so
+install -m644 source/bin/pam_smbpass.so $RPM_BUILD_ROOT/lib/security
+
+# Install SWAT helper files
+for i in swat/help/*.html docs/htmldocs/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/help
+done
+for i in swat/images/*.gif
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/images
+done
+for i in swat/include/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/include
+done
+
+# This is the O'Reily Samba Book - on-line
+for i in docs/htmldocs/using_samba/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba
+done
+for i in docs/htmldocs/using_samba/figs/*.gif
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/figs
+done
+for i in docs/htmldocs/using_samba/gifs/*.gif
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/gifs
+done
+
+# Install the miscellany
+install -m644 swat/README $RPM_BUILD_ROOT%{prefix}/share/swat
+install -m644 docs/manpages/smb.conf.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+install -m644 docs/manpages/lmhosts.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+install -m644 docs/manpages/smbpasswd.5 $RPM_BUILD_ROOT%{prefix}/share/man/man5
+install -m644 docs/manpages/samba.7 $RPM_BUILD_ROOT%{prefix}/share/man/man7
+install -m644 docs/manpages/smbd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/nmbd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbpasswd.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/swat.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbmount.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbmnt.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 docs/manpages/smbumount.8 $RPM_BUILD_ROOT%{prefix}/share/man/man8
+install -m644 packaging/PHT/TurboLinux/smb.conf $RPM_BUILD_ROOT/etc/samba/smb.conf
+install -m644 packaging/PHT/TurboLinux/smbusers $RPM_BUILD_ROOT/etc/samba/smbusers
+install -m755 packaging/PHT/TurboLinux/smbprint $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/PHT/TurboLinux/findsmb $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/PHT/TurboLinux/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb
+install -m755 packaging/PHT/TurboLinux/smb.init $RPM_BUILD_ROOT%{prefix}/sbin/samba
+install -m644 packaging/PHT/TurboLinux/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba
+install -m644 packaging/PHT/TurboLinux/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba
+echo 127.0.0.1 localhost > $RPM_BUILD_ROOT/etc/lmhosts
+
+# Link smbmount to /sbin/mount.smb and /sbin/mount.smbfs
+ln -sf %{prefix}/sbin/smbmount $RPM_BUILD_ROOT/sbin/mount.smb
+ln -sf %{prefix}/sbin/smbmount $RPM_BUILD_ROOT/sbin/mount.smbfs
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/chkconfig --add smb
+/sbin/chkconfig smb off
+
+# Build codepage load files
+cd %{prefix}/share/samba
+for i in 437 737 775 850 852 861 866 932 936 949 950 1251
+do
+%{prefix}/bin/make_smbcodepage c $i %{prefix}/share/samba/codepages/src/codepage_def.$i %{prefix}/share/samba/codepages/codepage.$i
+done
+for i in 437 737 850 852 861 866 932 936 949 950 ISO8859-1 ISO8859-2 ISO8859-5 ISO8859-7 KOI8-R
+do
+%{prefix}/bin/make_unicodemap $i %{prefix}/share/samba/codepages/src/CP$i.TXT %{prefix}/share/samba/codepages/unicode_map.$i
+done
+
+# Add swat entry to /etc/services if not already there
+if !( grep ^[:space:]*swat /etc/services > /dev/null ) then
+ echo 'swat 901/tcp # Add swat service used via inetd' >> /etc/services
+fi
+
+# Add swat entry to /etc/inetd.conf if needed
+if !( grep ^[:space:]*swat /etc/inetd.conf > /dev/null ) then
+ echo '#swat stream tcp nowait.400 root %{prefix}/sbin/swat swat' >> /etc/inetd.conf
+ killall -1 inetd || :
+fi
+
+# Now create the xinetd.conf file from our inetd.conf file, back up orig first.
+if [ -f /etc/xinetd.conf ]; then
+ mv /etc/xinetd.conf /etc/xinetd.conf.presamba
+ /usr/sbin/itox --daemon_dir /usr/sbin < /etc/inetd.conf > /etc/xinetd.conf
+fi
+
+
+%preun
+if [ $1 = 0 ] ; then
+ /sbin/chkconfig --del smb
+
+ for n in %{prefix}/share/samba/codepages/*; do
+ if [ $n != %{prefix}/share/samba/codepages/src ]; then
+ rm -rf $n
+ fi
+ done
+ # We want to remove the browse.dat and wins.dat files so they can not interfer with a new version of samba!
+ if [ -e /var/lock/samba/browse.dat ]; then
+ rm -f /var/lock/samba/browse.dat
+ fi
+ if [ -e /var/lock/samba/wins.dat ]; then
+ rm -f /var/lock/samba/wins.dat
+ fi
+fi
+
+%postun
+# Only delete remnants of samba if this is the final deletion.
+if [ $1 = 0 ] ; then
+ if [ -x /etc/pam.d/samba ]; then
+ rm -f /etc/pam.d/samba
+ fi
+ if [ -e /var/log/samba ]; then
+ rm -rf /var/log/samba
+ fi
+
+# Note: We MUST keep:
+# winbindd_*, sshare_info*, printing*, ntdrivers*
+
+ if [ -x /var/lock/samba ]; then
+ rm -f /var/lock/samba/browse.dat
+ rm -f /var/lock/samba/{brlock,connections,locking,messages}.tdb
+ if [ -e /var/lock/samba.d/namelist.debug ]; then
+ rm -f /var/lock/samba.d/namelist.debug
+ fi
+ rm -f /var/lock/samba/unexpected.tdb
+ rm -f /var/lock/samba/{smbd,nmbd}.pid
+ fi
+
+ # Remove swat entries from /etc/inetd.conf and /etc/services
+ cd /etc
+ tmpfile=/etc/tmp.$$
+ sed -e '/^[:space:]*swat.*$/d' /etc/inetd.conf > $tmpfile
+ mv $tmpfile inetd.conf
+ sed -e '/#swat.*$/d' /etc/inetd.conf > $tmpfile
+ mv $tmpfile inetd.conf
+ sed -e '/^[:space:]*swat.*$/d' /etc/services > $tmpfile
+ mv $tmpfile services
+
+ # Recreate xinetd.conf file from /etc/inetd.conf
+ mv /etc/xinetd.conf /etc/xinetd.conf.samba
+ /usr/sbin/itox --daemon_dir /usr/sbin < /etc/inetd.conf > /etc/xinetd.conf
+fi
+
+
+%triggerpostun -- samba < samba-2.0.0
+if [ $0 != 0 ]; then
+ /sbin/chkconfig --add smb
+fi
+
+
+%files
+%doc README COPYING Manifest Read-Manifest-Now
+%doc WHATSNEW.txt Roadmap
+%doc docs
+%doc swat/README
+%doc examples
+%attr(-,root,root) %{prefix}/sbin/smbd
+%attr(-,root,root) %{prefix}/sbin/nmbd
+%attr(-,root,root) %{prefix}/sbin/swat
+%attr(-,root,root) %{prefix}/sbin/debug2html
+%attr(0750,root,root) %{prefix}/sbin/samba
+%attr(-,root,root) %{prefix}/bin/smbclient
+%attr(-,root,root) %{prefix}/bin/rpcclient
+%attr(-,root,root) %{prefix}/bin/testparm
+%attr(-,root,root) %{prefix}/bin/testprns
+%attr(-,root,root) %{prefix}/bin/findsmb
+%attr(-,root,root) %{prefix}/bin/smbstatus
+%attr(-,root,root) %{prefix}/bin/nmblookup
+%attr(-,root,root) %{prefix}/bin/make_smbcodepage
+%attr(-,root,root) %{prefix}/bin/make_unicodemap
+%attr(-,root,root) %{prefix}/bin/make_printerdef
+%attr(-,root,root) %{prefix}/bin/smbpasswd
+%attr(-,root,root) %{prefix}/bin/smbtar
+%attr(-,root,root) %{prefix}/bin/smbprint
+%attr(-,root,root) %{prefix}/bin/smbspool
+%attr(-,root,root) %{prefix}/bin/smbadduser
+%attr(755,root,root) /lib/libnss_wins.s*
+%attr(755,root,root) /lib/security/pam_smbpass.so
+%attr(-,root,root) %{prefix}/share/swat/help/*
+%attr(-,root,root) %{prefix}/share/swat/images/*
+%attr(-,root,root) %{prefix}/share/swat/include/header.html
+%attr(-,root,root) %{prefix}/share/swat/include/footer.html
+%attr(-,root,root) %{prefix}/share/swat/using_samba/*
+%attr(-,root,root) %config(noreplace) /etc/samba/lmhosts
+%attr(-,root,root) %config(noreplace) /etc/samba/smb.conf
+%attr(-,root,root) %config(noreplace) /etc/samba/smbusers
+%attr(-,root,root) /etc/rc.d/init.d/smb
+%attr(-,root,root) /etc/logrotate.d/samba
+%attr(-,root,root) /etc/pam.d/samba
+%attr(-,root,root) %{prefix}/share/samba/codepages/src/codepage_def.*
+%attr(-,root,root) %{prefix}/share/samba/codepages/src/CP*
+# %attr(-,root,root) %{prefix}/share/man/man1/smbsh.1
+%attr(-,root,root) %{prefix}/share/man/man1/make_smbcodepage.1
+%attr(-,root,root) %{prefix}/share/man/man1/make_unicodemap.1
+%attr(-,root,root) %{prefix}/share/man/man1/nmblookup.1
+%attr(-,root,root) %{prefix}/share/man/man1/smbclient.1
+%attr(-,root,root) %{prefix}/share/man/man1/smbrun.1
+%attr(-,root,root) %{prefix}/share/man/man1/smbstatus.1
+%attr(-,root,root) %{prefix}/share/man/man1/smbtar.1
+%attr(-,root,root) %{prefix}/share/man/man1/testparm.1
+%attr(-,root,root) %{prefix}/share/man/man1/testprns.1
+%attr(-,root,root) %{prefix}/share/man/man5/lmhosts.5
+%attr(-,root,root) %{prefix}/share/man/man5/smb.conf.5
+%attr(-,root,root) %{prefix}/share/man/man5/smbpasswd.5
+%attr(-,root,root) %{prefix}/share/man/man7/samba.7
+%attr(-,root,root) %{prefix}/share/man/man8/nmbd.8
+%attr(-,root,root) %{prefix}/share/man/man8/smbd.8
+%attr(-,root,root) %{prefix}/share/man/man8/smbpasswd.8
+%attr(-,root,root) %{prefix}/share/man/man8/swat.8
+%attr(-,root,nobody) %dir /home/samba
+%attr(-,root,root) %dir %{prefix}/share/samba/codepages
+%attr(-,root,root) %dir %{prefix}/share/samba/codepages/src
+%attr(-,root,root) %dir /var/lock/samba
+%attr(-,root,root) %dir /var/log/samba
+%attr(1777,root,root) %dir /var/spool/samba
+
+%files -n smbfs
+%attr(-,root,root) %{prefix}/sbin/smbmount
+%attr(-,root,root) %{prefix}/sbin/smbumount
+%attr(-,root,root) %{prefix}/sbin/smbmnt
+%attr(-,root,root) /sbin/mount.smb
+%attr(-,root,root) /sbin/mount.smbfs
+%attr(-,root,root) %{prefix}/share/man/man8/smbmnt.8
+%attr(-,root,root) %{prefix}/share/man/man8/smbmount.8
+%attr(-,root,root) %{prefix}/share/man/man8/smbumount.8
diff --git a/packaging/PHT/TurboLinux/smb.conf b/packaging/PHT/TurboLinux/smb.conf
new file mode 100644
index 00000000000..e07d15c93ef
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smb.conf
@@ -0,0 +1,291 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = /etc/printcap
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; writable = yes
+; printable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/PHT/TurboLinux/smb.init b/packaging/PHT/TurboLinux/smb.init
new file mode 100755
index 00000000000..6529977d236
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smb.init
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# chkconfig: 345 91 35
+# description: Starts and stops the Samba smbd and nmbd daemons \
+# used to provide SMB network services.
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+# Check that smb.conf exists.
+[ -f /etc/smb.conf ] || exit 0
+
+# See how we were called.
+case "$1" in
+ start)
+ echo -n "Starting SMB services: "
+ daemon smbd -D
+ daemon nmbd -D
+ echo
+ touch /var/lock/subsys/smb
+ ;;
+ stop)
+ echo -n "Shutting down SMB services: "
+ killproc smbd
+ killproc nmbd
+ rm -f /var/lock/subsys/smb
+ echo ""
+ ;;
+ status)
+ status smbd
+ status nmbd
+ ;;
+ restart)
+ echo -n "Restarting SMB services: "
+ $0 stop
+ $0 start
+ echo "done."
+ ;;
+ *)
+ echo "Usage: smb {start|stop|restart|status}"
+ exit 1
+esac
+
diff --git a/packaging/PHT/TurboLinux/smbadduser b/packaging/PHT/TurboLinux/smbadduser
new file mode 100755
index 00000000000..2f38bf28f1a
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smbadduser
@@ -0,0 +1,73 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+unalias *
+set path = ($path)
+
+set smbpasswd = /etc/smbpasswd
+set user_map = /etc/smbusers
+#
+# Set to site specific passwd command
+#
+set passwd = "cat /etc/passwd"
+#set passwd = "niscat passwd.org_dir"
+#set passwd = "ypcat passwd"
+
+set line = "----------------------------------------------------------"
+if ($#argv == 0) then
+ echo $line
+ echo "Written: Mike Zakharoff email: michael.j.zakharoff@boeing.com"
+ echo ""
+ echo " 1) Updates $smbpasswd"
+ echo " 2) Updates $user_map"
+ echo " 3) Executes smbpasswd for each new user"
+ echo ""
+ echo "smbadduser unixid:ntid unixid:ntid ..."
+ echo ""
+ echo "Example: smbadduser zak:zakharoffm johns:smithj"
+ echo $line
+ exit 1
+endif
+
+touch $smbpasswd $user_map
+set new = ()
+foreach one ($argv)
+ echo $one | grep ':' >& /dev/null
+ if ($status != 0) then
+ echo "ERROR: Must use unixid:ntid like -> zak:zakharoffm"
+ continue
+ endif
+ set unix = `echo $one | awk -F: '{print $1}'`
+ set ntid = `echo $one | awk -F: '{print $2}'`
+
+ set usr = `eval $passwd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#usr != 1) then
+ echo "ERROR: $unix Not in passwd database SKIPPING..."
+ continue
+ endif
+ set tmp = `cat $smbpasswd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#tmp != 0) then
+ echo "ERROR: $unix is already in $smbpasswd SKIPPING..."
+ continue
+ endif
+
+ echo "Adding: $unix to $smbpasswd"
+ eval $passwd | \
+ awk -F: '$1==USR { \
+ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }' USR=$unix >> $smbpasswd
+ if ($unix != $ntid) then
+ echo "Adding: {$unix = $ntid} to $user_map"
+ echo "$unix = $ntid" >> $user_map
+ endif
+ set new = ($new $unix)
+end
+
+#
+# Enter password for new users
+#
+foreach one ($new)
+ echo $line
+ echo "ENTER password for $one"
+ smbpasswd $one
+end
diff --git a/packaging/PHT/TurboLinux/smbprint b/packaging/PHT/TurboLinux/smbprint
new file mode 100755
index 00000000000..ec083eede62
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to same space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/packaging/PHT/TurboLinux/smbusers b/packaging/PHT/TurboLinux/smbusers
new file mode 100644
index 00000000000..ae3389f53f8
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nobody = guest pcguest smbguest
diff --git a/packaging/PHT/TurboLinux/smbw.patch b/packaging/PHT/TurboLinux/smbw.patch
new file mode 100644
index 00000000000..0abbfdf73f6
--- /dev/null
+++ b/packaging/PHT/TurboLinux/smbw.patch
@@ -0,0 +1,10 @@
+--- samba-2.0.0/source/smbwrapper/smbsh.in.orig Mon Oct 5 22:37:01 1998
++++ samba-2.0.0/source/smbwrapper/smbsh.in Mon Oct 5 22:37:51 1998
+@@ -1,6 +1,6 @@
+ #! /bin/sh
+
+-SMBW_LIBDIR=${SMBW_LIBDIR-@builddir@/smbwrapper}
++SMBW_LIBDIR=${SMBW_LIBDIR-/usr/bin}
+
+ if [ ! -f ${SMBW_LIBDIR}/smbwrapper.so ]; then
+ echo You need to set LIBDIR in smbsh
diff --git a/packaging/README b/packaging/README
new file mode 100644
index 00000000000..ce651377907
--- /dev/null
+++ b/packaging/README
@@ -0,0 +1,38 @@
+Copyright (C) 1997-1998 Samba-Team
+Date: November 16, 1998
+Updates: First Release - 19970819
+ 19981116
+===============================================================================
+
+Note:
+=====
+This directory is a public repository for platform specific files including
+build files for binary package distributions for specific operating systems
+as well as for source file distribution packages for those systems.
+
+The Example directory should be used as a guide for preparation of binary
+packages for distribution via the official samba ftp sites.
+
+The files contained here are intended for use only by those wishing to build
+distribution packages and are NOT considered suitable material for anyone who
+wants to just install Samba from the pristine source files contained under
+the ~/source directory.
+
+All contributions / modifications / additions / etc. to the packaging files
+should be sent to samba-patches@samba.org with the subject marked:
+ PACKAGING: [add|mod|contrib] Your subject.
+
+Should you, or anyone you know of, have package build instructions and/or files
+that may be of use to the wider community of Samba users please mail the above
+account with subject: PACKAGING: [avail] OS xxxxxxxxxx
+where xxxxxxxxxx is the operating system platform that may be contributed.
+
+We will contact the person who is offering to contribute package build details
+to ensure that their contribution can be included in the official Samba sources.
+
+In the event that anyone wishes to contribute package build information please
+indicate in your response how we may access a suitable system to ensure our
+ability to keep the binary distribution itself current with the released source.
+
+The future of cooperatively developed software such as Samba depends on the
+willingness of all partners to share the fruit of their labours.
diff --git a/packaging/README.UnixWare b/packaging/README.UnixWare
new file mode 100644
index 00000000000..a4b08954ecc
--- /dev/null
+++ b/packaging/README.UnixWare
@@ -0,0 +1,6 @@
+Date: January 9, 2001
+Maintainer: John H Terpstra
+Subject: UnixWare Packaging Files
+Modifications: Initial release 20010109
+
+Note: The packaging build files for UnixWare are located under ~samba/packaging/Caldera/UnixWare.
diff --git a/packaging/RedHat/.cvsignore b/packaging/RedHat/.cvsignore
new file mode 100644
index 00000000000..4ce9d934e6e
--- /dev/null
+++ b/packaging/RedHat/.cvsignore
@@ -0,0 +1,6 @@
+makefile-path.patch
+makerpms.sh
+samba2.spec
+smbadduser
+smbw.patch
+samba2.rpm?.spec \ No newline at end of file
diff --git a/packaging/RedHat/README b/packaging/RedHat/README
new file mode 100644
index 00000000000..210248fa35a
--- /dev/null
+++ b/packaging/RedHat/README
@@ -0,0 +1,11 @@
+Preparation Date: Fri Aug 21, 1998
+Preparer: John H Terpstra <jht@samba.org>
+
+Instructions: Preparing Samba Packages for Red Hat Linux 5.X
+===============================================================
+
+We provide support only for current versions of Red Hat Linux.
+
+To produce the RPMS simply type:
+ sh makerpms.sh
+
diff --git a/packaging/RedHat/findsmb b/packaging/RedHat/findsmb
new file mode 100755
index 00000000000..986c2481779
--- /dev/null
+++ b/packaging/RedHat/findsmb
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/RedHat/makerpms.sh.tmpl b/packaging/RedHat/makerpms.sh.tmpl
new file mode 100644
index 00000000000..44b89a45ec8
--- /dev/null
+++ b/packaging/RedHat/makerpms.sh.tmpl
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright (C) John H Terpstra 1998
+# Updated for RPM 3 by Jochen Wiedmann, joe@ispsoft.de
+# Changed for a generic tar file rebuild by abartlet@pcug.org.au
+USERID=`id -u`
+GRPID=`id -g`
+VERSION='PVERSION'
+
+rm -f ../../samba2.*.spec
+
+case `rpm --version | awk '{print $3}'` in
+ 2.*)
+ sed -e "s/MANDIR_MACRO/\%\{prefix\}\/man/g" < samba2.spec > samba2.rpm2.spec
+ cp samba2.rpm2.spec ../../
+ ;;
+ 3.*)
+ sed -e "s/MANDIR_MACRO/\%\{prefix\}\/man/g" < samba2.spec > samba2.rpm3.spec
+ cp samba2.rpm3.spec ../../
+ ;;
+ 4.*)
+ sed -e "s/MANDIR_MACRO/\%\{_mandir\}/g" < samba2.spec > samba2.rpm4.spec
+ cp samba2.rpm4.spec ../../
+ ;;
+ *)
+ echo "Unknown RPM version: `rpm --version`"
+ exit 1
+ ;;
+esac
+
+( cd ../../source; if [ -f Makefile ]; then make distclean; fi )
+( cd ../../.. ; chown -R ${USERID}.${GRPID} samba-${VERSION} )
+( cd ../../.. ; tar --exclude=CVS -czvf samba-${VERSION}.tar.gz samba-${VERSION}/samba2.*.spec samba-${VERSION} )
+
+rpm -ta -v ../../../samba-${VERSION}.tar.gz
+
+
+
+
diff --git a/packaging/RedHat/samba.log b/packaging/RedHat/samba.log
new file mode 100644
index 00000000000..4b244099c4f
--- /dev/null
+++ b/packaging/RedHat/samba.log
@@ -0,0 +1,11 @@
+/var/log/samba/log.nmbd {
+ postrotate
+ /usr/bin/killall -HUP nmbd
+ endscript
+}
+
+/var/log/samba/log.smbd {
+ postrotate
+ /usr/bin/killall -HUP smbd
+ endscript
+}
diff --git a/packaging/RedHat/samba.pamd b/packaging/RedHat/samba.pamd
new file mode 100644
index 00000000000..1b4a93fb19e
--- /dev/null
+++ b/packaging/RedHat/samba.pamd
@@ -0,0 +1,4 @@
+auth required /lib/security/pam_pwdb.so nullok shadow
+account required /lib/security/pam_pwdb.so
+session required /lib/security/pam_pwdb.so
+password required /lib/security/pam_pwdb.so
diff --git a/packaging/RedHat/samba.pamd.stack b/packaging/RedHat/samba.pamd.stack
new file mode 100644
index 00000000000..6a948f92cbd
--- /dev/null
+++ b/packaging/RedHat/samba.pamd.stack
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth required pam_nologin.so
+auth required pam_stack.so service=system-auth
+account required pam_stack.so service=system-auth
+session required pam_stack.so service=system-auth
+password required pam_stack.so service=system-auth
diff --git a/packaging/RedHat/samba.xinetd b/packaging/RedHat/samba.xinetd
new file mode 100644
index 00000000000..8c38b354218
--- /dev/null
+++ b/packaging/RedHat/samba.xinetd
@@ -0,0 +1,15 @@
+# default: off
+# description: SWAT is the Samba Web Admin Tool. Use swat \
+# to configure your Samba server. To use SWAT, \
+# connect to port 901 with your favorite web browser.
+service swat
+{
+ port = 901
+ socket_type = stream
+ wait = no
+ only_from = localhost
+ user = root
+ server = /usr/sbin/swat
+ log_on_failure += USERID
+ disable = yes
+}
diff --git a/packaging/RedHat/samba2.spec.tmpl b/packaging/RedHat/samba2.spec.tmpl
new file mode 100644
index 00000000000..c99b9123825
--- /dev/null
+++ b/packaging/RedHat/samba2.spec.tmpl
@@ -0,0 +1,458 @@
+Summary: Samba SMB client and server
+Name: samba
+Version: PVERSION
+Release: PRELEASE
+Copyright: GNU GPL version 2
+Group: Networking
+Source: ftp://samba.org/pub/samba/samba-%{version}.tar.gz
+Packager: John H Terpstra [Samba-Team] <jht@samba.org>
+Requires: pam >= 0.72 kernel >= 2.2.1 glibc >= 2.1.2
+Prereq: chkconfig fileutils
+BuildRoot: /var/tmp/samba
+Prefix: /usr
+
+%description
+Samba provides an SMB server which can be used to provide
+network services to SMB (sometimes called "Lan Manager")
+clients, including various versions of MS Windows, OS/2,
+and other Linux machines. Samba also provides some SMB
+clients, which complement the built-in SMB filesystem
+in Linux. Samba uses NetBIOS over TCP/IP (NetBT) protocols
+and does NOT need NetBEUI (Microsoft Raw NetBIOS frame)
+protocol.
+
+Samba-2.2 features working NT Domain Control capability and
+includes the SWAT (Samba Web Administration Tool) that
+allows samba's smb.conf file to be remotely managed using your
+favourite web browser. For the time being this is being
+enabled on TCP port 901 via inetd.
+
+Users are advised to use Samba-2.2 as a Windows NT4
+Domain Controller only on networks that do NOT have a Windows
+NT Domain Controller. This release does NOT as yet have
+Backup Domain control ability.
+
+Please refer to the WHATSNEW.txt document for fixup information.
+This binary release includes encrypted password support.
+
+Please read the smb.conf file and ENCRYPTION.txt in the
+docs directory for implementation details.
+
+NOTE: Red Hat Linux uses PAM which has integrated support
+for Shadow passwords and quotas. Do NOT recompile with the
+SHADOW_PWD option enabled
+
+%changelog
+* Mon Aug 1 2001 Tim Potter <tpot@samba.org>
+ - Install winbind daemon, client programs, nss and pam libraries
+ - Removed codepage stuff so spec file works with current HEAD branch
+
+* Sat Mar 31 2001 Andrew Bartlett <abartlet@pcug.org.au>
+ - Changed prefix/share/man for _mandir/share/man
+ - Changed this for a sed macro MANDIR_MACRO
+ - This allows us to build both RH7 (RPM4)
+ and older versions from same specfile.
+ - Made makerpms.sh use the rpm -ta command rather
+ than attempting to devine the correct location to
+ put the file. Also removes some /tmp symlink games.
+ - Allows build on RPM4
+ - Increased PAM requirements to allow us to use
+ system-auth (this pam is in 6.x errata at least)
+
+* Tue Mar 27 2001 John H Terpstra <jht@samba.org>
+ - Fixed typos introduced by Sum Wun.
+ - Build for Red Hat 7.x
+
+* Sun Nov 12 2000 John H Terpstra <jht@samba.org>
+ - Updated for Samba-2.2 releases
+ - Added libnss_wins.so stuff
+ - Added compile-time options
+
+* Sat Nov 29 1999 Matthew Vanecek <mev0003@unt.edu>
+ - Added a Prefix and changed "/usr" to "%{prefix}"
+
+* Sat Nov 11 1999 Tridge <tridge@linuxcare.com>
+ - changed from mount.smb to mount.smbfs
+
+* Sat Oct 9 1999 Tridge <tridge@linuxcare.com>
+ - removed smbwrapper
+ - added smbmnt and smbmount
+
+* Sun Apr 25 1999 John H Terpstra <jht@samba.org>
+ - added smbsh.1 man page
+
+* Fri Mar 26 1999 Andrew Tridgell <tridge@samba.org>
+ - added --with-pam as pam is no longer used by default
+
+* Sat Jan 27 1999 Jeremy Allison <jra@samba.org>
+ - Removed smbrun binary and tidied up some loose ends
+
+* Sun Oct 25 1998 John H Terpstra <jht@samba.org>
+ - Added parameters to /config to ensure smb.conf, lmhosts,
+ and smbusers never gets over-written.
+
+* Sat Oct 24 1998 John H Terpstra <jht@samba.org>
+ - removed README.smbsh file from docs area
+
+* Mon Oct 05 1998 John H Terpstra <jht@samba.org>
+ - Added rpcclient to binaries list
+ - Added smbwrapper stuff
+
+* Fri Aug 21 1998 John H Terpstra <jht@samba.org>
+ - Updated for Samba version 2.0 building
+
+* Tue Jul 07 1998 Erik Troan <ewt@redhat.com>
+ - updated postun triggerscript to check $0
+ - clear /etc/codepages from %preun instead of %postun
+
+* Sat Jul 04 1998 John H Terpstra <jht@samba.org>
+ - fixed codepage preservation during update via -Uvh
+
+* Mon Jun 08 1998 Erik Troan <ewt@redhat.com>
+ - made the %postun script a tad less agressive; no reason to remove
+ the logs or lock file
+ - the %postun and %preun should only exectute if this is the final
+ removal
+ - migrated %triggerpostun from Red Hat's samba package to work around
+ packaging problems in some Red Hat samba releases
+
+* Sun Apr 26 1998 John H Terpstra <jht@samba.org>
+ - Tidy up for early alpha releases
+ - added findsmb from SGI packaging
+
+* Thu Apr 09 1998 John H Terpstra <jht@samba.org>
+ - Updated spec file
+ - Included new codepage.936
+
+* Sat Mar 20 1998 John H Terpstra <jht@samba.org>
+ - Added swat facility
+
+* Sat Jan 24 1998 John H Terpstra <jht@samba.org>
+ - Many optimisations (some suggested by Manoj Kasichainula <manojk@io.com>
+ - Use of chkconfig in place of individual symlinks to /etc/rc.d/init/smb
+ - Compounded make line
+ - Updated smb.init restart mechanism
+ - Use compound mkdir -p line instead of individual calls to mkdir
+ - Fixed smb.conf file path for log files
+ - Fixed smb.conf file path for incoming smb print spool directory
+ - Added a number of options to smb.conf file
+ - Added smbuser file and smb.conf file updates for username map
+
+%prep
+%setup
+
+%build
+cd source
+
+%ifarch ia64
+libtoolize --copy --force # get it to recognize IA-64
+autoheader
+autoconf
+EXTRA="-D_LARGEFILE64_SOURCE"
+%endif
+NUMCPU=`grep processor /proc/cpuinfo | wc -l`
+CFLAGS="$RPM_OPT_FLAGS $EXTRA" ./configure \
+ --prefix=%{prefix} \
+ --localstatedir=/var \
+ --with-configdir=/etc/samba \
+ --with-privatedir=/etc/samba \
+ --with-fhs \
+ --with-quotas \
+ --with-smbmount \
+ --with-pam \
+ --with-syslog \
+ --with-utmp \
+ --with-netatalk \
+ --with-sambabook=%{prefix}/share/swat/using_samba \
+ --with-swatdir=%{prefix}/share/swat
+make -j${NUMCPU} proto
+make -j${NUMCPU} all nsswitch/libnss_wins.so
+make -j${NUMCPU} debug2html
+make -j${NUMCPU} bin/smbspool
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/sbin
+mkdir -p $RPM_BUILD_ROOT/etc/samba
+mkdir -p $RPM_BUILD_ROOT/etc/{logrotate.d,pam.d,samba}
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+mkdir -p $RPM_BUILD_ROOT%{prefix}/{bin,sbin}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/{images,help,include,using_samba}
+mkdir -p $RPM_BUILD_ROOT%{prefix}/share/swat/using_samba/{figs,gifs}
+mkdir -p $RPM_BUILD_ROOTMANDIR_MACRO
+mkdir -p $RPM_BUILD_ROOT/var/lock/samba
+mkdir -p $RPM_BUILD_ROOT/var/log/samba
+mkdir -p $RPM_BUILD_ROOT/var/spool/samba
+mkdir -p $RPM_BUILD_ROOT/lib/security
+
+# Install standard binary files
+for i in nmblookup smbclient smbpasswd smbstatus testparm testprns \
+ make_printerdef rpcclient smbspool smbcacls smbcontrol wbinfo
+do
+install -m755 source/bin/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+for i in mksmbpasswd.sh smbtar
+do
+install -m755 source/script/$i $RPM_BUILD_ROOT%{prefix}/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat smbmount smbumount smbmnt debug2html winbindd
+do
+install -m755 source/bin/$i $RPM_BUILD_ROOT%{prefix}/sbin
+done
+
+# we need a symlink for mount to recognise the smb and smbfs filesystem types
+ln -sf %{prefix}/sbin/smbmount $RPM_BUILD_ROOT/sbin/mount.smbfs
+ln -sf %{prefix}/sbin/smbmount $RPM_BUILD_ROOT/sbin/mount.smb
+
+# This allows us to get away without duplicating code that
+# sombody else can maintain for us.
+cd source
+make LIBDIR=$RPM_BUILD_ROOT/etc/samba \
+ BINDIR=$RPM_BUILD_ROOT%{prefix}/bin \
+ MANDIR=$RPM_BUILD_ROOTMANDIR_MACRO \
+ SWATDIR=$RPM_BUILD_ROOT/usr/share/swat \
+ SAMBABOOK=$RPM_BUILD_ROOT/usr/share/swat/using_samba \
+ installman installswat
+cd ..
+
+# Install the nsswitch library extension file
+install -m755 source/nsswitch/libnss_wins.so $RPM_BUILD_ROOT/lib
+
+# Make link for wins resolver
+( cd $RPM_BUILD_ROOT/lib; ln -s libnss_wins.so libnss_wins.so.2; )
+
+# Install winbind shared libraries
+install -m755 source/nsswitch/libnss_winbind.so $RPM_BUILD_ROOT/lib
+install -m755 source/nsswitch/pam_winbind.so $RPM_BUILD_ROOT/lib/security
+
+# Install SWAT helper files
+for i in swat/help/*.html docs/htmldocs/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/help
+done
+for i in swat/images/*.gif
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/images
+done
+for i in swat/include/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT%{prefix}/share/swat/include
+done
+
+# Install the miscellany
+install -m644 swat/README $RPM_BUILD_ROOT%{prefix}/share/swat
+install -m755 packaging/RedHat/smbprint $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/RedHat/findsmb $RPM_BUILD_ROOT%{prefix}/bin
+install -m755 packaging/RedHat/smb.init $RPM_BUILD_ROOT/etc/rc.d/init.d/smb
+install -m755 packaging/RedHat/smb.init $RPM_BUILD_ROOT%{prefix}/sbin/samba
+install -m644 packaging/RedHat/samba.log $RPM_BUILD_ROOT/etc/logrotate.d/samba
+install -m644 packaging/RedHat/smb.conf $RPM_BUILD_ROOT/etc/samba/smb.conf
+install -m644 packaging/RedHat/smbusers $RPM_BUILD_ROOT/etc/samba/smbusers
+install -m644 packaging/RedHat/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba
+install -m644 packaging/RedHat/samba.pamd.stack $RPM_BUILD_ROOT/etc/samba/samba.stack
+install -m644 packaging/RedHat/samba.xinetd $RPM_BUILD_ROOT/etc/samba/samba.xinetd
+echo 127.0.0.1 localhost > $RPM_BUILD_ROOT/etc/samba/lmhosts
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/chkconfig --add smb
+/sbin/chkconfig smb off
+
+echo "Looking for old /etc/smb.conf..."
+if [ -f /etc/smb.conf ]; then
+ echo "Moving old /etc/smb.conf to /etc/samba/smb.conf"
+ mv /etc/smb.conf /etc/samba/smb.conf
+fi
+
+echo "Looking for old /etc/smbusers..."
+if [ -f /etc/smbusers ]; then
+ echo "Moving old /etc/smbusers to /etc/samba/smbusers"
+ mv /etc/smbusers /etc/samba/smbusers
+fi
+
+echo "Looking for old /etc/lmhosts..."
+if [ -f /etc/lmhosts ]; then
+ echo "Moving old /etc/lmhosts to /etc/samba/lmhosts"
+ mv /etc/lmhosts /etc/samba/lmhosts
+fi
+
+echo "Looking for old /etc/MACHINE.SID..."
+if [ -f /etc/MACHINE.SID ]; then
+ echo "Moving old /etc/MACHINE.SID to /etc/samba/MACHINE.SID"
+ mv /etc/MACHINE.SID /etc/samba/MACHINE.SID
+fi
+
+echo "Looking for old /etc/smbpasswd..."
+if [ -f /etc/smbpasswd ]; then
+ echo "Moving old /etc/smbpasswd to /etc/samba/smbpasswd"
+ mv /etc/smbpasswd /etc/samba/smbpasswd
+fi
+
+# Add swat entry to /etc/services if not already there.
+if !( grep ^[:space:]*swat /etc/services > /dev/null ) then
+ echo 'swat 901/tcp # Add swat service used via inetd' >> /etc/services
+fi
+
+# Add swat entry to /etc/inetd.conf if needed.
+if [ -f /etc/inetd.conf ]; then
+ if !( grep ^[:space:]*swat /etc/inetd.conf > /dev/null ) then
+ echo 'swat stream tcp nowait.400 root %{prefix}/sbin/swat swat' >> /etc/inetd.conf
+ killall -1 inetd || :
+ fi
+fi
+
+# Add swat entry to xinetd.d if needed.
+if [ -d $RPM_BUILD_ROOT/etc/xinetd.d -a ! -f /etc/xinetd.d/swat ]; then
+ mv /etc/samba/samba.xinetd /etc/xinetd.d/swat
+else
+ rm -f /etc/samba/samba.xinetd
+fi
+
+# Install the correct version of the samba pam file, depending on pam version.
+if [ -f /lib/security/pam_stack.so ]; then
+ echo "Installing stack version of /etc/pam.d/samba..."
+ mv /etc/samba/samba.stack /etc/pam.d/samba
+else
+ echo "Installing non-stack version of /etc/pam.d/samba..."
+ rm -f /etc/samba/samba.stack
+fi
+
+# Create winbind nss client symlink
+
+ln -s /lib/libnss_winbind.so /lib/libnss_winbind.so.2
+
+%preun
+if [ $1 = 0 ] ; then
+ /sbin/chkconfig --del smb
+
+ # We want to remove the browse.dat and wins.dat files so they can not interfer with a new version of samba!
+ if [ -e /var/lock/samba/browse.dat ]; then
+ rm -f /var/lock/samba/browse.dat
+ fi
+ if [ -e /var/lock/samba/wins.dat ]; then
+ rm -f /var/lock/samba/wins.dat
+ fi
+
+ # Remove the transient tdb files.
+ if [ -e /var/lock/samba/brlock.tdb ]; then
+ rm -f /var/lock/samba/brlock.tdb
+ fi
+
+ if [ -e /var/lock/samba/unexpected.tdb ]; then
+ rm -f /var/lock/samba/unexpected.tdb
+ fi
+
+ if [ -e /var/lock/samba/connections.tdb ]; then
+ rm -f /var/lock/samba/connections.tdb
+ fi
+
+ if [ -e /var/lock/samba/locking.tdb ]; then
+ rm -f /var/lock/samba/locking.tdb
+ fi
+
+ if [ -e /var/lock/samba/messages.tdb ]; then
+ rm -f /var/lock/samba/messages.tdb
+ fi
+
+ # Remove winbind nss client symlink
+
+ if [ -L /lib/libnss_winbind.so.2 ]; then
+ rm -f /lib/libnss_winbind.so.2
+ fi
+fi
+
+%postun
+# Only delete remnants of samba if this is the final deletion.
+if [ $1 = 0 ] ; then
+ if [ -x /etc/pam.d/samba ]; then
+ rm -f /etc/pam.d/samba
+ fi
+ if [ -e /var/log/samba ]; then
+ rm -rf /var/log/samba
+ fi
+
+ # Remove swat entries from /etc/inetd.conf and /etc/services
+ cd /etc
+ tmpfile=/etc/tmp.$$
+ if [ -f /etc/inetd.conf ]; then
+ # preserve inetd.conf permissions.
+ cp -p /etc/inetd.conf $tmpfile
+ sed -e '/^[:space:]*swat.*$/d' /etc/inetd.conf > $tmpfile
+ mv $tmpfile inetd.conf
+ fi
+ # preserve services permissions.
+ cp -p /etc/services $tmpfile
+ sed -e '/^[:space:]*swat.*$/d' /etc/services > $tmpfile
+ mv $tmpfile /etc/services
+
+ # Remove swat entry from /etc/xinetd.d
+ if [ -f /etc/xinetd.d/swat ]; then
+ rm -r /etc/xinetd.d/swat
+ fi
+fi
+
+%triggerpostun -- samba < samba-2.0.0
+if [ $0 != 0 ]; then
+ /sbin/chkconfig --add smb
+fi
+
+%files
+%doc README COPYING Manifest Read-Manifest-Now
+%doc WHATSNEW.txt Roadmap
+%doc docs
+%doc swat/README
+%doc examples
+%attr(-,root,root) %{prefix}/sbin/smbd
+%attr(-,root,root) %{prefix}/sbin/nmbd
+%attr(-,root,root) %{prefix}/sbin/swat
+%attr(-,root,root) %{prefix}/sbin/smbmnt
+%attr(-,root,root) %{prefix}/sbin/smbmount
+%attr(-,root,root) %{prefix}/sbin/smbumount
+%attr(-,root,root) %{prefix}/sbin/winbindd
+%attr(-,root,root) /sbin/mount.smbfs
+%attr(-,root,root) /sbin/mount.smb
+%attr(-,root,root) %{prefix}/bin/mksmbpasswd.sh
+%attr(-,root,root) %{prefix}/bin/smbclient
+%attr(-,root,root) %{prefix}/bin/smbspool
+%attr(-,root,root) %{prefix}/bin/rpcclient
+%attr(-,root,root) %{prefix}/bin/testparm
+%attr(-,root,root) %{prefix}/bin/testprns
+%attr(-,root,root) %{prefix}/bin/findsmb
+%attr(-,root,root) %{prefix}/bin/smbstatus
+%attr(-,root,root) %{prefix}/bin/nmblookup
+%attr(-,root,root) %{prefix}/bin/make_printerdef
+%attr(-,root,root) %{prefix}/bin/smbpasswd
+%attr(-,root,root) %{prefix}/bin/smbtar
+%attr(-,root,root) %{prefix}/bin/smbprint
+%attr(-,root,root) %{prefix}/bin/smbcontrol
+%attr(-,root,root) %{prefix}/bin/smbcacls
+%attr(-,root,root) %{prefix}/bin/wbinfo
+%attr(755,root,root) /lib/libnss_wins.s*
+%attr(-,root,root) %{prefix}/share/swat/help/*
+%attr(-,root,root) %{prefix}/share/swat/images/*
+%attr(-,root,root) %{prefix}/share/swat/include/header.html
+%attr(-,root,root) %{prefix}/share/swat/include/footer.html
+%attr(-,root,root) %{prefix}/share/swat/using_samba/*
+%attr(-,root,root) %config(noreplace) /etc/samba/lmhosts
+%attr(-,root,root) %config(noreplace) /etc/samba/smb.conf
+%attr(-,root,root) %config(noreplace) /etc/samba/smbusers
+%attr(-,root,root) /etc/samba/samba.stack
+%attr(-,root,root) /etc/samba/samba.xinetd
+%attr(-,root,root) /etc/rc.d/init.d/smb
+%attr(-,root,root) /etc/logrotate.d/samba
+%attr(-,root,root) %config(noreplace) /etc/pam.d/samba
+%attr(-,root,root) MANDIR_MACRO/man1/*
+%attr(-,root,root) MANDIR_MACRO/man5/*
+%attr(-,root,root) MANDIR_MACRO/man7/*
+%attr(-,root,root) MANDIR_MACRO/man8/*
+%attr(755,root,root) %dir /var/lock/samba
+%attr(-,root,root) %dir /var/log/samba
+%attr(1777,root,root) %dir /var/spool/samba
+%attr(-,root,root) /lib/libnss_winbind.so
+%attr(-,root,root) /lib/security/pam_winbind.so
diff --git a/packaging/RedHat/smb.conf b/packaging/RedHat/smb.conf
new file mode 100644
index 00000000000..71ff9463884
--- /dev/null
+++ b/packaging/RedHat/smb.conf
@@ -0,0 +1,290 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not made any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = /etc/printcap
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/samba/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/samba/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/samba/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; read only = yes
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/RedHat/smb.init b/packaging/RedHat/smb.init
new file mode 100755
index 00000000000..260439281a3
--- /dev/null
+++ b/packaging/RedHat/smb.init
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# chkconfig: 345 91 35
+# description: Starts and stops the Samba smbd and nmbd daemons \
+# used to provide SMB network services.
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+# Check that smb.conf exists.
+[ -f /etc/samba/smb.conf ] || exit 0
+
+# See how we were called.
+case "$1" in
+ start)
+ echo -n "Starting SMB services: "
+ daemon smbd -D
+ daemon nmbd -D
+ echo
+ touch /var/lock/subsys/smb
+ ;;
+ stop)
+ echo -n "Shutting down SMB services: "
+ killproc smbd
+ killproc nmbd
+ rm -f /var/lock/subsys/smb
+ echo ""
+ ;;
+ status)
+ status smbd
+ status nmbd
+ ;;
+ restart)
+ echo -n "Restarting SMB services: "
+ $0 stop
+ $0 start
+ echo "done."
+ ;;
+ *)
+ echo "Usage: smb {start|stop|restart|status}"
+ exit 1
+esac
+
diff --git a/packaging/RedHat/smbprint b/packaging/RedHat/smbprint
new file mode 100755
index 00000000000..ec083eede62
--- /dev/null
+++ b/packaging/RedHat/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script is an input filter for printcap printing on a unix machine. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+# For example you could have a printcap entry like this
+#
+# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
+#
+# which would create a unix printer called "smb" that will print via this
+# script. You will need to create the spool directory /usr/spool/smb with
+# appropriate permissions and ownerships for your system.
+
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+
+#
+# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
+# so that the server, service, and password can be read from
+# a /var/spool/lpd/PRINTNAME/.config file.
+#
+# In order for this to work the /etc/printcap entry must include an
+# accounting file (af=...):
+#
+# cdcolour:\
+# :cm=CD IBM Colorjet on 6th:\
+# :sd=/var/spool/lpd/cdcolour:\
+# :af=/var/spool/lpd/cdcolour/acct:\
+# :if=/usr/local/etc/smbprint:\
+# :mx=0:\
+# :lp=/dev/null:
+#
+# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
+# server=PC_SERVER
+# service=PR_SHARENAME
+# password="password"
+#
+# E.g.
+# server=PAULS_PC
+# service=CJET_371
+# password=""
+
+#
+# Debugging log file, change to /dev/null if you like.
+#
+# logfile=/tmp/smb-print.log
+logfile=/dev/null
+
+
+#
+# The last parameter to the filter is the accounting file name.
+# Extract the directory name from the file name.
+# Concat this with /.config to get the config file.
+#
+eval acct_file=\${$#}
+spool_dir=`dirname $acct_file`
+config_file=$spool_dir/.config
+
+# Should read the following variables set in the config file:
+# server
+# service
+# password
+eval `cat $config_file`
+
+#
+# Some debugging help, change the >> to > if you want to same space.
+#
+echo "server $server, service $service" >> $logfile
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+# echo translate
+ echo "print -"
+ cat
+) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/packaging/RedHat/smbusers b/packaging/RedHat/smbusers
new file mode 100644
index 00000000000..ae3389f53f8
--- /dev/null
+++ b/packaging/RedHat/smbusers
@@ -0,0 +1,3 @@
+# Unix_name = SMB_name1 SMB_name2 ...
+root = administrator admin
+nobody = guest pcguest smbguest
diff --git a/packaging/SGI/.cvsignore b/packaging/SGI/.cvsignore
new file mode 100644
index 00000000000..7b74def5aea
--- /dev/null
+++ b/packaging/SGI/.cvsignore
@@ -0,0 +1,8 @@
+bins
+catman
+html
+codepages
+swat
+Makefile
+samba.idb
+samba.spec
diff --git a/packaging/SGI/README b/packaging/SGI/README
new file mode 100644
index 00000000000..f13164af4a7
--- /dev/null
+++ b/packaging/SGI/README
@@ -0,0 +1,44 @@
+This directory contains sample files for using Samba on an IRIX
+system. These were taken from a system running IRIX 6.2. The
+client machines were running Win95 and connected via the Ethernet
+using TCP/IP and DNS. Consult the Samba documentation for tips
+on configuring Samba "properly"; this smb.conf file is very simple.
+Consult the Microsoft help/documentation to understand how to
+configure the networking support on the PC clients (Win95, WfW,
+etc.).
+
+This distribution is configured so that various Samba configuration,
+binary, and log files are placed in the /usr/samba file hierarchy.
+Man pages are placed in the /usr/share/catman/u_man hierarchy.
+
+The version number of the distribution is a 10 digit number that
+is created from the samba version number. Each section of the samba
+version number forms 2 digits of the version number (with leading
+zeros if necessary). The alpha versions add 00 and 2 digits for
+the alpha number. The first release adds 0100. Patch releases add
+2 digits for the patch level plus 1 and 00.
+
+samba version 1.9.18alpha9 would become 0109180009
+samba version 1.9.18 would become 0109180100
+samba version 1.9.18p9 would become 0109181000
+
+You can enable all printers on your system to be used by samba
+by running the script /usr/samba/mkprintcap.sh
+
+This distribution automatically configures samba to run as deamons
+by the script /etc/init.d/samba and the file /etc/config/samba
+(used by chkconfig). If you would prefer to have samba started by
+inetd you can run the script /usr/samba/inetd.sh.
+
+To create a Samba distribution you must have the Documenter's WorkBench
+package installed to format the manual pages. In addition you need
+to have the Software Packager software (inst_dev) installed to
+generate the inst images, and Perl to generate the spec and idb files.
+
+From /usr/samba/packaging/SGI directory run the mkrelease.sh script.
+There is one optional argument which is the major release number of the
+OS version (4, 5, or 6) you desire. If no number is specified it defaults
+to 6. This script uses Perl to generate the Makefile with the proper
+defines and the packaging files samba.spec and samba.idb. The binary
+package files will be placed in ./bins
+
diff --git a/packaging/SGI/findsmb b/packaging/SGI/findsmb
new file mode 100755
index 00000000000..a48ec592e80
--- /dev/null
+++ b/packaging/SGI/findsmb
@@ -0,0 +1,141 @@
+#!/bin/perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [subnet broadcast address]
+#
+# with no agrument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+
+$SAMBABIN = "/usr/samba/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d option and broadcast address
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } else {
+ if ($_) {
+ $BCAST = "-B $_";
+ }
+ }
+}
+
+sub ipsort # do numeric sort on last field of IP address
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*'|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+
+print "\nIP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+# find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup -r -A $ip|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+# get the first <00> name
+
+ @name = grep(/<00> - /,@nmblookup);
+ $_ = @name[0];
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ /(\S+)/;
+ $name = $1;
+ }
+
+# do an smbclient command on the netbios name.
+
+ open(SMB,"$SAMBABIN/smbclient -N -L $name -I $ip -U% |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+# look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/.*Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+# for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ /(\S+)/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+
+# see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+# line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+# try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
+
diff --git a/packaging/SGI/idb.pl b/packaging/SGI/idb.pl
new file mode 100755
index 00000000000..66cb3fa5584
--- /dev/null
+++ b/packaging/SGI/idb.pl
@@ -0,0 +1,374 @@
+#!/usr/bin/perl
+require "pwd.pl" || die "Required pwd.pl not found";
+
+# This perl script automatically generates the idb file
+
+$PKG = 'samba';
+$SRCDIR = '../..';
+$SRCPFX = '.';
+
+&initpwd;
+$curdir = $ENV{"PWD"};
+
+if ($PKG eq "samba_irix") {
+ open(BOOKS,"IDB.books") || die "Unable to open IDB.books file\n";
+ @books = sort idbsort <BOOKS>;
+ close BOOKS;
+}
+
+# We don't want the files listed in .cvsignore in the source tree
+open(IGNORES,"$SRCDIR/source/.cvsignore") || die "Unable to open .cvsignore file\n";
+while (<IGNORES>) {
+ chop;
+ next if /cvs\.log/;
+ $ignores{$_}++;
+}
+close IGNORES;
+
+# We don't want the files listed in .cvsignore in the source/include tree
+open(IGNORES,"$SRCDIR/source/include/.cvsignore") || die "Unable to open include/.cvsignore file\n";
+while (<IGNORES>) {
+ chop;
+ $ignores{$_}++;
+}
+close IGNORES;
+
+# get the names of all the binary files to be installed
+open(MAKEFILE,"$SRCDIR/source/Makefile") || die "Unable to open Makefile\n";
+@makefile = <MAKEFILE>;
+@winbind_progs = grep(/^WINBIND_PROGS /,@makefile);
+@winbind_sprogs = grep(/^WINBIND_SPROGS /,@makefile);
+@winbind_lprogs = grep(/^WINBIND_LPROGS /,@makefile);
+@winbind_pam_progs = grep(/^WINBIND_PAM_PROGS /,@makefile);
+@sprogs = grep(/^SPROGS /,@makefile);
+@progs1 = grep(/^PROGS1 /,@makefile);
+@progs2 = grep(/^PROGS2 /,@makefile);
+@mprogs = grep(/^MPROGS /,@makefile);
+@progs = grep(/^PROGS /,@makefile);
+@scripts = grep(/^SCRIPTS /,@makefile);
+@codepagelist = grep(/^CODEPAGELIST/,@makefile);
+close MAKEFILE;
+
+if (@winbind_progs) {
+ @winbind_progs[0] =~ s/^.*\=//;
+ @winbind_progs = split(' ',@winbind_progs[0]);
+}
+if (@winbind_sprogs) {
+ @winbind_sprogs[0] =~ s/^.*\=//;
+ @winbind_sprogs = split(' ',@winbind_sprogs[0]);
+}
+if (@winbind_lprogs) {
+ @winbind_lprogs[0] =~ s/^.*\=//;
+ @winbind_lprogs = split(' ',@winbind_lprogs[0]);
+}
+if (@winbind_pam_progs) {
+ @winbind_pam_progs[0] =~ s/^.*\=//;
+ @winbind_pam_progs = split(' ',@winbind_pam_progs[0]);
+}
+if (@sprogs) {
+ @sprogs[0] =~ s/^.*\=//;
+ @sprogs[0] =~ s/\$\(\S+\)\s//g;
+ @sprogs = split(' ',@sprogs[0]);
+}
+if (@progs) {
+ @progs[0] =~ s/^.*\=//;
+ @progs[0] =~ s/\$\(\S+\)\s//g;
+ @progs = split(' ',@progs[0]);
+}
+if (@mprogs) {
+ @mprogs[0] =~ s/^.*\=//;
+ @mprogs = split(' ',@mprogs[0]);
+}
+if (@progs1) {
+ @progs1[0] =~ s/^.*\=//;
+ @progs1 = split(' ',@progs1[0]);
+}
+if (@progs2) {
+ @progs2[0] =~ s/^.*\=//;
+ @progs2 = split(' ',@progs2[0]);
+}
+if (@scripts) {
+ @scripts[0] =~ s/^.*\=//;
+ @scripts[0] =~ s/\$\(srcdir\)\///g;
+ @scripts = split(' ',@scripts[0]);
+}
+
+# we need to create codepages for the package
+@codepagelist[0] =~ s/^.*\=//;
+chdir "$SRCDIR/source";
+system("chmod +x ./script/installcp.sh");
+system("./script/installcp.sh . . ../packaging/SGI/codepages ./bin @codepagelist[0]");
+chdir $curdir;
+opendir(DIR,"$SRCDIR/packaging/SGI/codepages") || die "Can't open codepages directory";
+@codepage = sort readdir(DIR);
+closedir(DIR);
+
+# install the swat files
+chdir "$SRCDIR/source";
+system("chmod +x ./script/installswat.sh");
+system("./script/installswat.sh ../packaging/SGI/swat ./ ../packaging/SGI/swat/using_samba");
+system("cp -f ../swat/README ../packaging/SGI/swat");
+chdir $curdir;
+
+# add my local files to the list of binaries to install
+@bins = sort byfilename (@sprogs,@progs,@progs1,@progs2,@mprogs,@scripts,@winbind_progs,@winbind_sprogs,("/findsmb","/sambalp","/smbprint"));
+@nsswitch = sort byfilename (@winbind_lprogs,@winbind_pam_progs);
+
+# get a complete list of all files in the tree
+chdir "$SRCDIR/";
+&dodir('.');
+chdir $curdir;
+
+# the files installed in docs include all the original files in docs plus all
+# the "*.doc" files from the source tree
+@docs = sort byfilename grep (!/^docs\/$/ & (/^source\/.*\.doc$/ | /^docs\//),@allfiles);
+@docs = grep(!/htmldocs\/using_samba/, @docs);
+@docs = grep(!/docbook/, @docs);
+
+@swatfiles = sort grep(/^packaging\/SGI\/swat/, @allfiles);
+@catman = sort grep(/^packaging\/SGI\/catman/ & !/\/$/, @allfiles);
+@catman = sort bydirnum @catman;
+
+# strip out all the generated directories and the "*.o" files from the source
+# release
+@allfiles = grep(!/^.*\.o$/ & !/^.*\.po$/ & !/^.*\.po32$/ & !/^source\/bin/ & !/^packaging\/SGI\/bins/ & !/^packaging\/SGI\/catman/ & !/^packaging\/SGI\/html/ & !/^packaging\/SGI\/codepages/ & !/^packaging\/SGI\/swat/, @allfiles);
+
+open(IDB,"> $curdir/$PKG.idb") || die "Unable to open $PKG.idb for output\n";
+
+print IDB "f 0644 root sys etc/config/samba $SRCPFX/packaging/SGI/samba.config $PKG.sw.base config(update)\n";
+print IDB "f 0755 root sys etc/init.d/samba $SRCPFX/packaging/SGI/samba.rc $PKG.sw.base\n";
+print IDB "l 0000 root sys etc/rc0.d/K39samba $SRCPFX/packaging/SGI $PKG.sw.base symval(../init.d/samba)\n";
+print IDB "l 0000 root sys etc/rc2.d/S81samba $SRCPFX/packaging/SGI $PKG.sw.base symval(../init.d/samba)\n";
+
+if ($PKG eq "samba_irix") {
+ print IDB "d 0755 root sys usr/relnotes/samba_irix $SRCPFX/packaging/SGI $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba_irix/TC build/TC $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba_irix/ch1.z build/ch1.z $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba_irix/ch2.z build/ch2.z $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba_irix/ch3.z build/ch3.z $PKG.man.relnotes\n";
+}
+else {
+ @copyfile = grep (/^COPY/,@allfiles);
+ print IDB "d 0755 root sys usr/relnotes/samba $SRCPFX/packaging/SGI $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba/@copyfile[0] $SRCPFX/@copyfile[0] $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba/legal_notice.html $SRCPFX/packaging/SGI/legal_notice.html $PKG.man.relnotes\n";
+ print IDB "f 0644 root sys usr/relnotes/samba/samba-relnotes.html $SRCPFX/packaging/SGI/relnotes.html $PKG.man.relnotes\n";
+}
+
+print IDB "d 0755 root sys usr/samba $SRCPFX/packaging/SGI $PKG.sw.base\n";
+
+print IDB "d 0755 root sys usr/samba/bin $SRCPFX/packaging/SGI $PKG.sw.base\n";
+while(@bins) {
+ $nextfile = shift @bins;
+ ($filename = $nextfile) =~ s/^.*\///;;
+
+ if (index($nextfile,'$')) {
+ if ($filename eq "smbpasswd") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/source/$nextfile $PKG.sw.base \n";
+ }
+ elsif ($filename eq "findsmb") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/packaging/SGI/$filename $PKG.sw.base\n";
+ }
+ elsif ($filename eq "swat") {
+ print IDB "f 4755 root sys usr/samba/bin/$filename $SRCPFX/source/$nextfile $PKG.sw.base preop(\"chroot \$rbase /etc/init.d/samba stop\") exitop(\"chroot \$rbase /usr/samba/scripts/startswat.sh\") removeop(\"chroot \$rbase /sbin/cp /etc/inetd.conf /etc/inetd.conf.O ; chroot \$rbase /sbin/sed -e '/^swat/D' -e '/^#SWAT/D' /etc/inetd.conf.O >/etc/inetd.conf; /etc/killall -HUP inetd || true\")\n";
+ }
+ elsif ($filename eq "sambalp") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/packaging/SGI/$filename $PKG.sw.base \n";
+ }
+ elsif ($filename eq "smbprint") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/packaging/SGI/$filename $PKG.sw.base\n";
+ }
+ elsif ($filename eq "smbd") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/source/$nextfile $PKG.sw.base \n";
+ print IDB "f 0755 root sys usr/samba/bin/$filename.noquota $SRCPFX/source/$nextfile.noquota $PKG.sw.base \n";
+ print IDB "f 0755 root sys usr/samba/bin/$filename.profile $SRCPFX/source/$nextfile.profile $PKG.sw.base \n";
+ }
+ elsif ($filename eq "nmbd") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/source/$nextfile $PKG.sw.base \n";
+ print IDB "f 0755 root sys usr/samba/bin/$filename.profile $SRCPFX/source/$nextfile.profile $PKG.sw.base \n";
+ }
+ else {
+ print IDB "f 0755 root sys usr/samba/bin/$filename $SRCPFX/source/$nextfile $PKG.sw.base \n";
+ }
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/docs $SRCPFX/docs $PKG.man.doc\n";
+while (@docs) {
+ $nextfile = shift @docs;
+ next if ($nextfile eq "CVS");
+ ($junk,$file) = split(/\//,$nextfile,2);
+ if (grep(/\/$/,$nextfile)) {
+ $file =~ s/\/$//;
+ $nextfile =~ s/\/$//;
+ print IDB "d 0755 root sys usr/samba/docs/$file $SRCPFX/$nextfile $PKG.man.doc\n";
+ }
+ else {
+ print IDB "f 0644 root sys usr/samba/docs/$file $SRCPFX/$nextfile $PKG.man.doc\n";
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/lib $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 root sys usr/samba/lib/codepages $SRCPFX/packaging/SGI $PKG.sw.base\n";
+while (@codepage) {
+ $nextpage = shift @codepage;
+ print IDB "f 0644 root sys usr/samba/lib/codepages/$nextpage $SRCPFX/packaging/SGI/codepages/$nextpage $PKG.sw.base nostrip \n";
+}
+print IDB "f 0644 root sys usr/samba/lib/smb.conf $SRCPFX/packaging/SGI/smb.conf $PKG.sw.base config(suggest)\n";
+
+if (@nsswitch) {
+ print IDB "d 0644 root sys usr/samba/nsswitch $SRCPFX/packaging/SGI $PKG.sw.base\n";
+ while(@nsswitch) {
+ $nextfile = shift @nsswitch;
+ ($filename = $nextfile) =~ s/^.*\///;;
+ print IDB "f 0755 root sys usr/samba/nsswitch/$filename $SRCPFX/source/$nextfile $PKG.sw.base \n";
+ }
+}
+
+print IDB "d 0755 lp sys usr/samba/printer $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 lp sys usr/samba/printer/W32ALPHA $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 lp sys usr/samba/printer/W32MIPS $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 lp sys usr/samba/printer/W32PPC $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 lp sys usr/samba/printer/W32X86 $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 lp sys usr/samba/printer/WIN40 $SRCPFX/packaging/SGI $PKG.sw.base\n";
+
+print IDB "d 0644 root sys usr/samba/private $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "f 0600 root sys usr/samba/private/smbpasswd $SRCPFX/packaging/SGI/smbpasswd $PKG.sw.base config(suggest)\n";
+
+print IDB "d 0755 root sys usr/samba/scripts $SRCPFX/packaging/SGI $PKG.src.samba\n";
+print IDB "f 0755 root sys usr/samba/scripts/inetd.sh $SRCPFX/packaging/SGI/inetd.sh $PKG.sw.base\n";
+print IDB "f 0755 root sys usr/samba/scripts/inst.msg $SRCPFX/packaging/SGI/inst.msg $PKG.sw.base exitop(\"chroot \$rbase /usr/samba/scripts/inst.msg\")\n";
+print IDB "f 0755 root sys usr/samba/scripts/mkprintcap.sh $SRCPFX/packaging/SGI/mkprintcap.sh $PKG.sw.base\n";
+print IDB "f 0755 root sys usr/samba/scripts/removeswat.sh $SRCPFX/packaging/SGI/removeswat.sh $PKG.sw.base\n";
+print IDB "f 0755 root sys usr/samba/scripts/startswat.sh $SRCPFX/packaging/SGI/startswat.sh $PKG.sw.base\n";
+
+print IDB "d 0755 root sys usr/samba/src $SRCPFX/packaging/SGI $PKG.src.samba\n";
+@sorted = sort(@allfiles);
+while (@sorted) {
+ $nextfile = shift @sorted;
+ ($file = $nextfile) =~ s/^.*\///;
+ next if grep(/packaging\/SGI/& (/Makefile/ | /samba\.spec/ | /samba\.idb/),$nextfile);
+ next if grep(/source/,$nextfile) && ($ignores{$file});
+ next if ($nextfile eq "CVS");
+ if (grep(/\/$/,$nextfile)) {
+ $nextfile =~ s/\/$//;
+ print IDB "d 0755 root sys usr/samba/src/$nextfile $SRCPFX/$nextfile $PKG.src.samba\n";
+ }
+ else {
+ if (grep((/\.sh$/ | /configure$/ | /configure\.developer/ | /config\.guess/ | /config\.sub/ | /\.pl$/ | /mkman$/ | /pcp\/Install/ | /pcp\/Remove/),$nextfile)) {
+ print IDB "f 0755 root sys usr/samba/src/$nextfile $SRCPFX/$nextfile $PKG.src.samba\n";
+ }
+ else {
+ print IDB "f 0644 root sys usr/samba/src/$nextfile $SRCPFX/$nextfile $PKG.src.samba\n";
+ }
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/swat $SRCPFX/packaging/SGI/swat $PKG.sw.base\n";
+while (@swatfiles) {
+ $nextfile = shift @swatfiles;
+ ($file = $nextfile) =~ s/^packaging\/SGI\/swat\///;
+ next if !$file;
+ if (grep(/\/$/,$file)) {
+ $file =~ s/\/$//;
+ print IDB "d 0755 root sys usr/samba/swat/$file $SRCPFX/packaging/SGI/swat/$file $PKG.sw.base\n";
+ }
+ else {
+ print IDB "f 0444 root sys usr/samba/swat/$file $SRCPFX/packaging/SGI/swat/$file $PKG.sw.base\n";
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/var $SRCPFX/packaging/SGI $PKG.sw.base\n";
+print IDB "d 0755 root sys usr/samba/var/locks $SRCPFX/packaging/SGI $PKG.sw.base\n";
+
+if ($PKG eq "samba_irix") {
+ while(@books) {
+ $nextfile = shift @books;
+ print IDB $nextfile;
+ }
+}
+
+print IDB "d 0755 root sys usr/share/catman/u_man $SRCPFX/packaging/SGI $PKG.man.manpages\n";
+$olddirnum = "0";
+while (@catman) {
+ $nextfile = shift @catman;
+ ($file = $nextfile) =~ s/^packaging\/SGI\/catman\///;
+ ($dirnum = $file) =~ s/^[\D]*//;
+ $dirnum =~ s/\.z//;
+ if ($dirnum ne $olddirnum) {
+ print IDB "d 0755 root sys usr/share/catman/u_man/cat$dirnum $SRCPFX/packaging/SGI $PKG.man.manpages\n";
+ $olddirnum = $dirnum;
+ }
+ print IDB "f 0664 root sys usr/share/catman/u_man/cat$dirnum/$file $SRCPFX/$nextfile $PKG.man.manpages\n";
+}
+print IDB "d 01777 lp sys var/spool/samba $SRCPFX/packaging/SGI $PKG.sw.base\n";
+
+close IDB;
+print "\n\n$PKG.idb file has been created\n";
+
+sub dodir {
+ local($dir, $nlink) = @_;
+ local($dev,$ino,$mode,$subcount);
+
+ ($dev,$ino,$mode,$nlink) = stat('.') unless $nlink;
+
+ opendir(DIR,'.') || die "Can't open current directory";
+ local(@filenames) = sort readdir(DIR);
+ closedir(DIR);
+
+ if ($nlink ==2) { # This dir has no subdirectories.
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ $this = substr($dir,2)."/$_";
+ push(@allfiles,$this);
+ }
+ }
+ else {
+ $subcount = $nlink -2;
+ for (@filenames) {
+ next if $_ eq '.';
+ next if $_ eq '..';
+ next if $_ eq 'CVS';
+ ($dev,$ino,$mode,$nlink) = lstat($_);
+ $name = "$dir/$_";
+ $this = substr($name,2);
+ $this .= '/' if -d;
+ push(@allfiles,$this);
+ next if $subcount == 0; # seen all the subdirs?
+
+ next unless -d _;
+
+ chdir $_ || die "Can't cd to $name";
+ &dodir($name,$nlink);
+ chdir '..';
+ --$subcount;
+ }
+ }
+}
+
+sub byfilename {
+ ($f0,$f1) = split(/\//,$a,2);
+ ($f0,$f2) = split(/\//,$b,2);
+ $f1 cmp $f2;
+}
+
+sub bydirnum {
+ ($f1 = $a) =~ s/^.*\///;
+ ($f2 = $b) =~ s/^.*\///;
+ ($dir1 = $a) =~ s/^[\D]*//;
+ ($dir2 = $b) =~ s/^[\D]*//;
+ if (!($dir1 <=> $dir2)) {
+ $f1 cmp $f2;
+ }
+ else {
+ $dir1 <=> $dir2;
+ }
+}
+
+sub idbsort {
+ ($f0,$f1,$f2,$f3) = split(/ /,$a,4);
+ ($f0,$f1,$f2,$f4) = split(/ /,$b,4);
+ $f3 cmp $f4;
+}
+
diff --git a/packaging/SGI/inetd.sh b/packaging/SGI/inetd.sh
new file mode 100755
index 00000000000..1d403978aec
--- /dev/null
+++ b/packaging/SGI/inetd.sh
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# kill any running samba processes
+#
+/etc/killall smbd nmbd
+chkconfig samba off
+
+#
+# add SAMBA deamons to inetd.conf
+#
+cp /etc/inetd.conf /etc/inetd.conf.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/inetd.conf.O -o ! -w /etc/inetd.conf ]; then exit 1; fi
+
+sed -e "/^netbios/D" -e "/^#SAMBA/D" /etc/inetd.conf.O > /etc/inetd.conf
+echo '#SAMBA services' >> /etc/inetd.conf
+echo netbios-ssn stream tcp nowait root /usr/samba/bin/smbd smbd >> /etc/inetd.conf
+echo netbios-ns dgram udp wait root /usr/samba/bin/nmbd nmbd -S >> /etc/inetd.conf
+
+#
+# add SAMBA service ports to /etc/services
+#
+cp /etc/services /etc/services.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/services.O -o ! -w /etc/services ]; then exit 1; fi
+
+sed -e "/^netbios/D" -e "/^#SAMBA/D" /etc/services.O > /etc/services
+echo '#SAMBA services' >> /etc/services
+echo 'netbios-ns 137/udp # SAMBA' >> /etc/services
+echo 'netbios-ssn 139/tcp # SAMBA' >> /etc/services
+
+#
+# restart inetd to start SAMBA
+#
+/etc/killall -HUP inetd
diff --git a/packaging/SGI/inst.msg b/packaging/SGI/inst.msg
new file mode 100755
index 00000000000..4d8bab389cb
--- /dev/null
+++ b/packaging/SGI/inst.msg
@@ -0,0 +1,31 @@
+#! /bin/sh
+
+echo
+echo
+echo Samba has been installed on your system.
+echo
+echo Your /etc/services and /etc/inetd.conf files have
+echo been modified to automatically start the
+echo Samba Web Administration Tool \(SWAT\) when you
+echo connect with a web browser to
+echo
+echo http://`hostname`:901
+echo
+echo The original versions of /etc/services and
+echo /etc/inetd.conf were saved with a .O extension.
+echo
+echo If you do not wish SWAT to be enabled you may
+echo run the script /usr/samba/scripts/removeswat.sh
+echo which will remove the entries from /etc/services
+echo and /etc/inetd.conf
+echo
+echo Please review your configuration settings by
+echo connecting to SWAT or editing the file
+echo /usr/samba/lib/smb.conf and then starting
+echo the smbd and nmbd daemons to complete the
+echo installation. You may start the daemons from
+echo the SWAT "Status" page or by executing the
+echo following command as root.
+echo
+echo /etc/init.d/samba start
+echo
diff --git a/packaging/SGI/legal_notice.html b/packaging/SGI/legal_notice.html
new file mode 100644
index 00000000000..fdb76456289
--- /dev/null
+++ b/packaging/SGI/legal_notice.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<HTML VERSION="2.0">
+<HEAD>
+<TITLE>Silicon Graphics Freeware Legal Notice</TITLE>
+</HEAD>
+
+<BODY>
+<H1><A NAME="LEGAL">Silicon Graphics Freeware Legal Notice</A></H1>
+<HR>
+Copyright 1995, Silicon Graphics, Inc. -- ALL RIGHTS RESERVED
+<P>
+You may copy, modify, use and distribute this software, (i)
+provided that you include the entirety of this reservation of
+rights notice in all such copies, and (ii) you comply with any
+additional or different obligations and/or use restrictions
+specified by any third party owner or supplier of the software
+in other notices that may be included with the software.
+
+<P>
+SGI DISCLAIMS ALL WARRANTIES WITH RESPECT TO THIS SOFTWARE,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION,
+ALL WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE OR NONINFRINGEMENT. SGI SHALL NOT BE LIABLE FOR ANY
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING,
+WITHOUT LIMITATION, LOST REVENUES, LOST PROFITS, OR LOSS OF
+PROSPECTIVE ECONOMIC ADVANTAGE, RESULTING FROM THE USE OR MISUSE
+OF THIS SOFTWARE.
+
+<P>
+U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+
+<P>
+
+Use, duplication or disclosure by the Government is subject to
+restrictions as set forth in FAR 52.227.19(c)(2) or subparagraph
+(c)(1)(ii) of the Rights in Technical Data and Computer Software
+clause at DFARS 252.227-7013 and/or in similar or successor
+clauses in the FAR, or the DOD or NASA FAR Supplement.
+Unpublished - rights reserved under the Copyright Laws of United
+States. Contractor/manufacturer is Silicon Graphics, Inc., 2011
+N. Shoreline Blvd. Mountain View, CA 94039-7311.
+
+<H3><A NAME="SUPPORT">Product Support</A></H3>
+
+<P>
+Freeware products are not supported by Silicon Graphics or any
+of its support providers. The software contained in this package
+is made available through the generous efforts of their authors.
+Although they are interested in your feedback, they are under no
+obligation to address bugs, enhancements, or answer questions.
+
+</BODY>
+</HTML>
diff --git a/packaging/SGI/mkman b/packaging/SGI/mkman
new file mode 100755
index 00000000000..a39ed9fdd0c
--- /dev/null
+++ b/packaging/SGI/mkman
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ ! -d catman ]; then
+ mkdir catman
+fi
+
+
+FILES="*.?"
+
+cd ../../docs/manpages
+for FILE in $FILES ; do
+ if [ "$FILE" = "smbmnt.8" ]; then continue; fi;
+ if [ "$FILE" = "smbmount.8" -o "$FILE" = "smbumount.8" ]; then continue; fi;
+ if [ "$FILE" = "smbrun.1" ]; then continue; fi;
+ neqn $FILE | tbl | nroff -man > ../../packaging/SGI/catman/`basename $FILE`
+ pack -f ../../packaging/SGI/catman/`basename $FILE`
+done
+cd ../../packaging/SGI
diff --git a/packaging/SGI/mkprintcap.sh b/packaging/SGI/mkprintcap.sh
new file mode 100755
index 00000000000..f610e757f06
--- /dev/null
+++ b/packaging/SGI/mkprintcap.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+#
+# create printcap file
+#
+if [ -r /usr/samba/printcap ]
+then
+ cp /usr/samba/printcap /usr/samba/printcap.O
+fi
+
+echo "#" > /usr/samba/printcap
+echo "# Samba printcap file" >> /usr/samba/printcap
+echo "# Alias names are separated by |, any name with spaces is taken as a comment" >> /usr/samba/printcap
+echo "#" >> /usr/samba/printcap
+lpstat -a | sed -e "s/ .*//" >> /usr/samba/printcap
+
diff --git a/packaging/SGI/mkrelease.sh b/packaging/SGI/mkrelease.sh
new file mode 100755
index 00000000000..a85a64569bc
--- /dev/null
+++ b/packaging/SGI/mkrelease.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+
+# This file goes through all the necessary steps to build a release package.
+# syntax:
+# mkrelease.sh [clean]
+#
+# You can specify clean to do a make clean before building. Make clean
+# will also run configure and generate the required Makefile.
+#
+# You can specify which targets to build. If targets are specified, the
+# specified targets will be built but inst packages will not be generated.
+
+doclean=""
+SGI_ABI=-n32
+ISA=-mips3
+CC=cc
+
+if [ ! -f ../../source/Makefile ]; then
+ doclean="clean"
+fi
+
+if [ "$1" = "clean" ]; then
+ doclean=$1
+ shift
+fi
+
+export SGI_ABI ISA CC
+
+if [ "$doclean" = "clean" ]; then
+ cd ../../source
+ if [ -f Makefile ]; then
+ make distclean
+ fi
+ cd ../packaging/SGI
+ rm -rf bins catman html codepages swat samba.idb samba.spec
+fi
+
+# create the catman versions of the manual pages
+#
+if [ "$doclean" = "clean" ]; then
+ echo Making manual pages
+ ./mkman
+ errstat=$?
+ if [ $errstat -ne 0 ]; then
+ echo "Error $errstat making manual pages\n";
+ exit $errstat;
+ fi
+fi
+
+cd ../../source
+if [ "$doclean" = "clean" ]; then
+ echo Create SGI specific Makefile
+ ./configure --prefix=/usr/samba --sbindir='${exec_prefix}/bin' --mandir=/usr/share/catman --with-acl-support
+ errstat=$?
+ if [ $errstat -ne 0 ]; then
+ echo "Error $errstat creating Makefile\n";
+ exit $errstat;
+ fi
+fi
+
+
+# build the sources
+#
+echo Making binaries
+
+make clean
+make headers
+make -P "CFLAGS=-O -g3 -D WITH_PROFILE" bin/smbd bin/nmbd
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat building profile sources\n";
+ exit $errstat;
+fi
+mv bin/smbd bin/smbd.profile
+mv bin/nmbd bin/nmbd.profile
+
+make clean
+make -P "CFLAGS=-O -g3 -D QUOTAOBJS=smbd/noquotas.o" bin/smbd
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat building noquota sources\n";
+ exit $errstat;
+fi
+mv bin/smbd bin/smbd.noquota
+
+make -P "CFLAGS=-O -g3" all
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat building sources\n";
+ exit $errstat;
+fi
+
+cd ../packaging/SGI
+
+#
+# Don't generate packages if targets were specified
+#
+if [ "$1" != "" ]; then
+ exit 0;
+fi
+
+# generate the packages
+#
+echo Generating Inst Packages
+./spec.pl # create the samba.spec file
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat creating samba.spec\n";
+ exit $errstat;
+fi
+
+./idb.pl # create the samba.idb file
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat creating samba.idb\n";
+ exit $errstat;
+fi
+
+if [ ! -d bins ]; then
+ mkdir bins
+fi
+
+# do the packaging
+/usr/sbin/gendist -rbase / -sbase ../.. -idb samba.idb -spec samba.spec -dist ./bins -all
+
diff --git a/packaging/SGI/printcap b/packaging/SGI/printcap
new file mode 100644
index 00000000000..b67b9cb167c
--- /dev/null
+++ b/packaging/SGI/printcap
@@ -0,0 +1,5 @@
+#
+# Sample printcap file
+# Alias names are separated by |, any name with spaces is taken as a comment
+#
+lp4js|lp12|LaserJet on the third floor by the coffee machine
diff --git a/packaging/SGI/relnotes.html b/packaging/SGI/relnotes.html
new file mode 100644
index 00000000000..afcf5796776
--- /dev/null
+++ b/packaging/SGI/relnotes.html
@@ -0,0 +1,233 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>Samba Release Notes</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Samba Release Notes</H1>
+
+<P>
+<HR></P>
+
+<H2>Table of Contents</H2>
+
+<MENU>
+<LI><B><A HREF="#WHATIS">What is Samba?</A></B> </LI>
+
+<LI><B><A HREF="#Support">Support Policy</A> </B></LI>
+
+<LI><B><A HREF="#Installation">Installation Information</A> </B></LI>
+
+<LI><B><A HREF="legal_notice.html">Silicon
+Graphics Legal Notice</A> </B></LI>
+
+<LI><B><A HREF="#AUTHORNOTES">Author's Notice(s)</A> </B></LI>
+
+<LI><B><A HREF="#Documentation">Documentation Information</A> </B></LI>
+</MENU>
+
+<P>
+<HR></P>
+
+<H2><A NAME="WHATIS"></A>What is Samba?</H2>
+
+<P>Samba is an SMB client and server for Unix. It makes it possible for
+client machines running Windows 95 and Windows for Workgroups to access
+files and/or print services on a Unix system. Samba includes an SMB server
+to provide LanManager-style file and print services to PCs, a Netbios (RFC10001/1002)
+name server, and an FTP-like client application for accessing PC resources
+from Unix. </P>
+
+<P>To make Samba work you'll need to configure your server host to run
+<B>smbd</B> and <B>nmbd</B> whenever you connect to a certain Internet
+port from the client machine. <B>Smbd</B> and <B>nmbd</B> can be started
+either as daemons or from inetd.</P>
+
+<P>By default <B>smbd</B> and <B>nmbd</B> are started as daemons by the
+file <I>/etc/init.d/samba</I> in conjunction with the chkconfig variable
+samba being set to on. If you set chkconfig samba off then the deamons
+will not be automatically started on reboot. In this case you must type
+the following at a shell prompt to start samba after a reboot: </P>
+
+<PRE><B> chkconfig samba on
+ /etc/init.d/samba start</B>
+</PRE>
+
+<P>If you make changes to your configuration files, <B>smbd</B> and <B>nmbd</B>
+may be restarted by typing the following at a shell prompt: </P>
+
+<PRE><B> /etc/init.d/samba start</B>
+</PRE>
+
+<P><B>smbd</B> and <B>nmbd</B> may be killed by typing the following at
+a shell prompt: </P>
+
+<PRE><B> /etc/init.d/samba stop</B>
+</PRE>
+
+<P>To have <B>smbd</B> and <B>nmbd</B> started by inetd you can execute
+the shell script <I>/usr/samba/inetd.sh</I> to automatically configure
+the various files and start the processes. This shell script first kills
+any running <B>smbd</B> and <B>nmbd</B> processes. It then removes any
+existing entries for &quot;netbios*&quot; from <I>/etc/inetd.conf</I> and
+adds the following lines </P>
+
+<PRE><B> netbios-ssn stream tcp nowait root /usr/samba/bin/smbd smbd
+ netbios-ns dgram udp wait root /usr/samba/bin/nmbd nmbd -S</B>
+</PRE>
+
+<P>It then removes any existing entries for &quot;netbios*&quot; from <I>/etc/services</I>
+and adds the following lines </P>
+
+<PRE><B> netbios-ns 137/udp # SAMBA
+ netbios-ssn 139/tcp # SAMBA</B>
+</PRE>
+
+<P><I>Inetd</I> is then restarted by executing:</P>
+
+<PRE><B> /etc/killall -HUP inetd</B>
+</PRE>
+
+<P>If you make changes to your configuration files, <B>smbd</B> and <B>nmbd</B>
+may be restarted by typing the following at a shell prompt: </P>
+
+<PRE><B> /etc/killall smbd nmbd
+ /etc/killall -HUP inetd</B>
+</PRE>
+
+<H3><A NAME="AUTHORNOTES"></A>Author's Notice(s):</H3>
+
+<P>The author of this product is: Andrew Tridgell </P>
+
+<P>Samba is distributed freely under the <A HREF="COPYING">GNU
+public license</A>. </P>
+
+<H3><A NAME="Support"></A>Support:</H3>
+
+<P>The software in this package is considered unsupported by Silicon Graphics.
+Neither the authors or Silicon Graphics are compelled to help resolve problems
+you may encounter in the installation, setup, or execution of this software.
+To be more to the point, if you call us with an issue regarding products
+in the Freeware package, we'll have to gracefully terminate the call. The
+<A HREF="http://samba.org/pub/samba/">
+Samba Web Page</A> has a listing of companies and individuals that offer
+commercial support for a fee.
+</P>
+
+<H2><A NAME="Installation"></A>Installation Information</H2>
+
+<P>Samba includes these subsystems: </P>
+
+<TABLE>
+<TR>
+<TD ALIGN=LEFT><B>samba.sw.base</B> (<I>default</I>)</TD>
+
+<TD>Execution environment for Samba.</TD>
+</TR>
+
+<TR>
+<TD ALIGN=left><B>samba.man.manpages</B>(<I>default</I>)</TD>
+
+<TD>Samba's online manual pages (preformatted).</TD>
+</TR>
+
+<TR>
+<TD ALIGN=LEFT VALIGN=TOP><B>samba.man.doc</B> (<I>default</I>)</TD>
+
+<TD>Samba documentation: hints on installation and configuration, an FAQ
+(Frequently Asked Questions), help in diagnosing problems, etc..</TD>
+</TR>
+
+<TR>
+<TD ALIGN=left><B>samba.man.relnotes</B> (<I>default</I>) </TD>
+
+<TD>Samba online release notes.</TD>
+</TR>
+
+<TR>
+<TD ALIGN=LEFT VALIGN=TOP><B>samba.src.samba</B> </TD>
+
+<TD>The Samba software distribution from which this product was
+built (including the packaging/SGI directory which will allow this distribution
+to be rebuilt).</TD>
+</TR>
+</TABLE>
+
+<H3>Installation Method</H3>
+
+<P>All of the subsystems for Samba can be installed using IRIX. You do
+not need to use the miniroot. Refer to the <I>Software Installation Administrator's
+Guide</I> for complete installation instructions. </P>
+
+<H3>Prerequisites</H3>
+
+<P>Your workstation must be running IRIX 5.3 or later in order to use this
+product. </P>
+
+<H3>Configuration Files</H3>
+
+<P>Because configuration files often contain modifications, inst treats
+them specially during the installation process. If they have not been modified,
+inst removes the old file and installs the new version during software
+updates. For configuration files that have been modified, the new version
+is installed and the old version is renamed by adding the suffix .O (for
+older) to the name. The no-suffix version contains changes that are required
+for compatibility with the rest of the newly installed software, that increase
+functionality, or that fix bugs. You should use diff(1) or gdiff(1) to
+compare the two versions of the files and transfer information that you
+recognize as machine or site-specific from the .O version to the no-suffix
+version. </P>
+
+<DL>
+<DT><B>/usr/samba/lib/smb.conf</B> </DT>
+
+<DD>Configuration definitions for the <B>smbd</B> program; the SMB server
+process. The default configuration sets up password-based access to home
+directories on a machine as well as open access to to all printers and
+/tmp. The workgroup is set by default to &quot;workgroup&quot;. It is highly
+recommended that administrators review the content of this file when installing
+Samba for the first time.</DD>
+
+<DT><B>/usr/samba/printcap</B> </DT>
+
+<DD>A file that specifies the available printers on a system. It is included
+as an example; administrators may want to replace it or override the reference
+to it in the <B>smb.conf</B> file. The script <B>/usr/samba/mkprintcap.sh</B>
+was used by inst to create a printcap file that contains all printers on
+your system. You may wish to remove some printers or add a comment to each
+printer name to describe its location.</DD>
+</DL>
+
+<H2><A NAME="Documentation"></A>Documentation Information</H2>
+
+<P>Preformatted manual pages are installed by default as are the contents
+of the <B>docs</B> directory from the Samba distribution; consult <I>samba</I>(7)
+for an introduction. </P>
+
+<P>There is a mailing list for discussion of Samba. To subscribe send mail
+to <A HREF="mailto:listproc@samba.org">listproc@samba.org</A>
+with a body of &quot;subscribe samba Your Name&quot; </P>
+
+<P>To send mail to everyone on the list mail to <A HREF="mailto:samba@samba.org">samba@samba.org</A>.
+</P>
+
+<P>There is also an announcement mailing list where new versions are announced.
+To subscribe send mail to <A HREF="mailto:listproc@samba.org">listproc@samba.org</A>
+with a body of &quot;subscribe samba-announce Your Name&quot;. All announcements
+also go to the samba list. </P>
+
+<P>You might also like to look at the Usenet news group <A HREF="news:comp.protocols.smb">comp.protocols.smb</A>
+as it often contains lots of useful info and is frequented by lots of Samba
+users. The newsgroup was initially setup by people on the Samba mailing
+list. It is not, however, exclusive to Samba, it is a forum for discussing
+the SMB protocol (which Samba implements). </P>
+
+<P>A Samba WWW site has been setup with lots of useful info. Connect to:
+<A HREF="http://samba.org/pub/samba/">http://samba.org/pub/samba/</A>.
+It is maintained by Paul Blackman (thanks Paul!). You can contact him at
+<A HREF="mailto:ictinus@lake.canberra.edu.au">ictinus@lake.canberra.edu.au</A>.
+</P>
+
+</BODY>
+</HTML>
diff --git a/packaging/SGI/removeswat.sh b/packaging/SGI/removeswat.sh
new file mode 100755
index 00000000000..7a4745345be
--- /dev/null
+++ b/packaging/SGI/removeswat.sh
@@ -0,0 +1,25 @@
+#! /bin/sh
+#
+# remove SWAT deamon from inetd.conf
+#
+cp /etc/inetd.conf /etc/inetd.conf.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/inetd.conf.O -o ! -w /etc/inetd.conf ]; then exit 1; fi
+
+sed -e "/^swat/D" -e "/^#SWAT/D" /etc/inetd.conf.O > /etc/inetd.conf
+
+#
+# remove SWAT service port from /etc/services
+#
+cp /etc/services /etc/services.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/services.O -o ! -w /etc/services ]; then exit 1; fi
+
+sed -e "/^swat/D" -e "/^#SWAT/D" /etc/services.O > /etc/services
+
+#
+# restart inetd to reread config files
+#
+/etc/killall -HUP inetd
diff --git a/packaging/SGI/samba.config b/packaging/SGI/samba.config
new file mode 100644
index 00000000000..b3d86404ab5
--- /dev/null
+++ b/packaging/SGI/samba.config
@@ -0,0 +1 @@
+on
diff --git a/packaging/SGI/samba.rc b/packaging/SGI/samba.rc
new file mode 100644
index 00000000000..bc0f90ee77f
--- /dev/null
+++ b/packaging/SGI/samba.rc
@@ -0,0 +1,43 @@
+#! /bin/sh
+
+#
+# Samba server control
+#
+
+IS_ON=/etc/chkconfig
+KILLALL=/sbin/killall
+
+SAMBAD=/usr/samba/bin/smbd
+#SAMBA_OPTS=-d2
+NMBD=/usr/samba/bin/nmbd
+#NMBD_OPTS=-d1
+
+if test ! -x $IS_ON ; then
+ IS_ON=true
+fi
+
+if $IS_ON verbose ; then
+ ECHO=echo
+else # For a quiet startup and shutdown
+ ECHO=:
+fi
+
+case $1 in
+'start')
+ if $IS_ON samba && test -x $SAMBAD; then
+ $KILLALL -15 smbd nmbd
+ $ECHO "Samba:\c"
+ $SAMBAD $SAMBA_OPTS -D; $ECHO " smbd\c"
+ $NMBD $NMBD_OPTS -D; $ECHO " nmbd\c"
+ $ECHO "."
+ fi
+ ;;
+'stop')
+ $ECHO "Stopping Samba Servers."
+ $KILLALL -15 smbd nmbd
+ exit 0
+ ;;
+*)
+ echo "usage: /etc/init.d/samba {start|stop}"
+ ;;
+esac
diff --git a/packaging/SGI/sambalp b/packaging/SGI/sambalp
new file mode 100644
index 00000000000..61e62215c91
--- /dev/null
+++ b/packaging/SGI/sambalp
@@ -0,0 +1,157 @@
+#!/bin/perl
+#
+# Hacked by Alan Stebbens <aks@sgi.com> to setuid to the username if
+# valid on this system. Written as a secure Perl script. To enable,
+#
+# chown root /usr/samba/bin/sambalp
+# chmod u+s,+x /usr/samba/bin/sambalp
+#
+# If setuidshells is not enabled on your system, you must also do this:
+#
+# systune -i
+# nosuidshells = 0
+# y
+# quit
+#
+# reboot
+#
+# This script will still work as a normal user; it will not try
+# to setuid in this case.
+#
+# If the "$PSFIX" variable is set below...
+#
+# Workaround Win95 printer driver/Impressario bug by removing
+# the PS check for available virtual memory. Note that this
+# bug appears to be in all Win95 print drivers that generate
+# PostScript; but is for certain there with a QMS-PS 810 (the
+# printer type I configure on the Win95-side for printing with
+# Samba).
+#
+# the perl script fixes 3 different bugs.
+# 1. remove the JCL statements added by some HP printer drivers to the
+# beginning of the postscript output.
+# 2. Fix a bug in output from word files with long filenames. A non-printing
+# character added to the end of the title comment by word is
+# removed.
+# 3. The VM fix described above.
+#
+#
+# Modified for Perl4 compatibility.
+#
+
+$PROG = "sambalp";
+
+$PSFIX = 1; # set to 0 if you don't want to run
+ # the "psfix" portion
+
+# Untaint the PATH variable
+@PATH = split(' ',<<EOF);
+ /usr/sbin /usr/bsd /sbin /usr/bin /bin /usr/lib /usr/local/bin
+EOF
+$ENV{'PATH'} = join(':',@PATH);
+
+if ($#ARGV < 3) {
+ print STDERR "usage: $PROG printer file user system\n";
+ exit;
+}
+
+$printer = $ARGV[0];
+$file = $ARGV[1];
+$user = $ARGV[2];
+$system = $ARGV[3];
+
+open(LPSTAT,"/usr/bin/lpstat -t|") || die("Can't get printer list.\n");
+@printers = ();
+while (<LPSTAT>) {
+ next unless /^printer (\w+)/;
+ push(@printers,$1);
+}
+close LPSTAT;
+# Create a hash list
+@printers{@printers} = @printers;
+
+# Untaint the printer name
+if (defined($prtname = $printers{$printer})) {
+ $printer = $prtname;
+} else {
+ die("Unknown printer: \"$printer\"\n");
+}
+
+if ($> == 0) { # are we root?
+ # yes -- then perform a taint checks and possibly do a suid check
+
+ # Untaint the file and system names (pretend to filter them)
+ $file = $file =~ /^(.*)/ ? $1 : die("Bad file: $file\n");
+ $system = $system =~ /^(.*)/ ? $1 : die("Bad system: $system\n");
+
+ # Get the valid users
+ setpwent;
+ %users = ();
+ while (@pwe = getpwent()) {
+ $uids{$pwe[0]} = $pwe[2];
+ $users{$pwe[2]} = $pwe[0];
+ }
+ endpwent();
+
+ # Check out the user -- if the user is a real user on this system,
+ # then become that user so that the printer header page looks right
+ # otherwise, remain as the default user (probably "nobody").
+
+ if (defined($uid = $uids{$user})) {
+
+ # before we change UID, we must ensure that the file is still
+ # readable after the UID change.
+ chown($uid, 9, $file); # make the file owned by the user
+
+ # Now, go ahead and become the user
+ $name = $users{$uid};
+ $> = $uid; # become the user
+ $< = $uid;
+ } else { # do untaint filtering
+ $name = $user =~ /^(\w+)/ ? $1 : die("Bad user: $user\n");
+ }
+} else { # otherwise, just be me
+ $name = $user; # whomever that is
+}
+
+$lpcommand = "/usr/bin/lp -c -d$printer -t'$name on $system'";
+
+# This code is from the original "psfix" but it has been completely
+# rewritten for speed.
+
+if ($PSFIX) { # are we running a "psfix"?
+ open(FILE, $file) || die("Can't read $file: $!\n");
+ open(LP, "|$lpcommand -") || die("Can't open pipe to \"lp\": $!\n");
+ select(LP);
+ while (<FILE>) { #
+ $_ =~ s/^\004//; # strip any ctrl-d's
+ if (/^\e%/) { # get rid of any non-postscript commands
+ while (<FILE>) { # remove text until next %!PS
+ s/^\001M//; # lenmark driver prefixes Ctrl-A M to %!PS
+ last if /^%!PS/;
+ }
+ last if eof(FILE);
+ } elsif (/^%%Title:/) { # fix bug in long titles from MS Word
+ s/.\r$/\r/; # remove trailing character on the title
+ } elsif (/^\/VM\?/) { # remove VM test
+ print "/VM? { pop } bind def\r\n";
+ while (<FILE>) { last if /def\r/; }
+ next; # don't print
+ }
+ print;
+ }
+ close FILE;
+ close LP;
+} else { # we're not running psfix?
+ system("$lpcommand $file");
+}
+
+if ($file =~ m(^/)) {
+ # $file is a fully specified path
+ # Remove the file only if it lives in a directory ending in /tmp.
+ unlink($file) if ($file =~ m(/tmp/[^/]+$));
+} else {
+ # $file is NOT a fully specified path
+ # Remove the file only if current directory ends in /tmp.
+ unlink($file) if (`pwd` =~ m(/tmp$));
+}
diff --git a/packaging/SGI/smb.conf b/packaging/SGI/smb.conf
new file mode 100644
index 00000000000..3448226faa3
--- /dev/null
+++ b/packaging/SGI/smb.conf
@@ -0,0 +1,124 @@
+; Configuration file for smbd.
+; ============================================================================
+; For the format of this file and comprehensive descriptions of all the
+; configuration option, please refer to the man page for smb.conf(5).
+
+; This is a sample configuration for IRIX 6.x systems
+;
+; The following configuration should suit most systems for basic usage and
+; initial testing. It gives all clients access to their home directories and
+; /usr/tmp and allows access to all printers returned by lpstat.
+;
+[global]
+ comment = Samba %v
+ workgroup = workgroup
+ printing = sysv
+;
+; The default for printcap name is lpstat which will export all printers.
+; If you want to limit the printers that are visible to clients, you can
+; use a printcap file. The script mkprintcap.sh will create a printcap
+; file that contains all your printers. Edit this file to only contain the
+; printers that you wish to be visible. Names longer than 15 characters
+; in the printcap file will not be visible to clients.
+;
+; printcap name = /usr/samba/printcap
+ printcap name = lpstat
+;
+; If you are using Impressario 1.x then you'll want to use the
+; sambalp script provided with this package. It works around
+; a problem in the PostScript generated by the standard Windows
+; drivers--there is a check to verify sufficient virtual memory
+; is available in the printer to print the job, but this fails
+; under Impressario because of a bug in Impressario 1.x. The sambalp
+; script strips out the vmstatus check. BTW, when using this
+; setup to print be sure to configure a Windows printer driver
+; that generates PostScript--QMS-PS 810 is one that should work
+; with the sambalp script. This version of sambalp (if installed
+; as a setuid script - see the comments at the beginning of the
+; script) will setuid to the username if valid on the system. This
+; makes the banner pages print the proper username. You can disable
+; the PostScript fixes by changing a variable in sambalp.
+;
+ print command = /usr/samba/bin/sambalp %p %s %U %m
+; print command = /usr/bin/lp -c -d%p -t"%U on machine %m" %s ; rm %s
+
+; clear the default lppause and lpresume commands since these are not
+; supported in IRIX
+ lppause command =
+ lpresume command =
+
+ load printers = yes
+ guest account = nobody
+ browseable = yes
+
+; this tells Samba to use a separate log file for each machine
+; that connects - default is single file named /usr/samba/var/log.smb
+; log file = /usr/samba/var/log.%m
+
+; Set a max size for log files in Kb
+ max log size = 50
+
+; You will need a world readable lock directory
+; if you want to support the file sharing modes for multiple users
+; of the same files
+ locking = yes
+ lock directory = /usr/samba/var/locks
+
+ security = user
+
+; You need to test to see if this makes a difference on your system
+ socket options = TCP_NODELAY
+
+; Set the os level to > 32 if there is no NT server for your workgroup
+ os level = 0
+ preferred master = no
+ domain master = no
+ local master = no
+ wins support = no
+ wins server =
+
+ preserve case = yes
+ short preserve case = yes
+
+; These are the settings required for IRIX password sync
+ passwd program = /usr/bin/passwd %u
+ passwd chat = *ew*password:* %n\n *e-enter*new*password:* %n\n
+
+; Uncomment the following if you wish to use encrypted passwords.
+; encrypt passwords = yes
+
+; Uncomment the following if you wish to sync unix and smbpasswd
+; unix password sync = yes
+
+; Printer admin account to allow uploading printer drivers
+ printer admin = lp
+
+[homes]
+ comment = Home Directories
+ browseable = no
+ writeable = yes
+
+; Share for printer drivers for automatic driver download
+;
+[print$]
+ comment = printer driver directory
+ path = /usr/samba/printer
+ guest ok = yes
+ browseable = yes
+ read only = yes
+ write list = lp
+
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+ printable = yes
+ guest ok = yes
+ writeable = no
+ create mask = 0700
+
+[tmp]
+ comment = Temporary file space
+ path = /usr/tmp
+ writeable = yes
+ guest ok = yes
diff --git a/packaging/SGI/smbpasswd b/packaging/SGI/smbpasswd
new file mode 100644
index 00000000000..8e7ab34cadd
--- /dev/null
+++ b/packaging/SGI/smbpasswd
@@ -0,0 +1 @@
+# Samba SMB password file
diff --git a/packaging/SGI/smbprint b/packaging/SGI/smbprint
new file mode 100644
index 00000000000..07923a42b1e
--- /dev/null
+++ b/packaging/SGI/smbprint
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# @(#) smbprint.sysv version 1.0 Ross Wakelin <r.wakelin@march.co.uk>
+#
+# Version 1.0 13 January 1995
+# modified from the original smbprint (bsd) script
+#
+# this script is a System 5 printer interface script. It uses the smbclient
+# program to print the file to the specified smb-based server and service.
+#
+# To add this to your lp system, modify the server and service variables
+# and then execute the following command (as root):
+#
+# lpadmin -punixprintername -v/dev/null -i/usr/samba/bin/smbprint
+#
+# where unixprintername is the name that the printer will be known as
+# on your unix box.
+#
+# the script smbprint will be copied into your printer administration
+# directory (/usr/spool/lp) as a new interface (interface/unixprintername)
+# Then you have to execute the following commands:
+#
+# enable unixprintername
+# accept unixprintername
+#
+# This script will then be called by the lp service to print the files.
+# This script will have 6 or more parameters passed to it by the lp service.
+# The first five will contain details of the print job, who queued it etc,
+# while parameters 6 onwards are a list of files to print. We just
+# cat these to the samba client.
+#
+# clear out the unwanted parameters
+
+shift;shift;shift;shift;shift
+
+# now the argument list is just the files to print
+
+# Set these to the server and service you wish to print to
+# In this example I have a PC called "admin" that has a printer
+# exported called "hplj2" with no password.
+#
+server=admin
+service=hplj2
+password=""
+
+# NOTE: The line `echo translate' provides automatic CR/LF translation
+# when printing.
+(
+ echo translate
+ echo "print -"
+ cat $*
+) | /usr/samba/bin/smbclient "//$server/$service" $password -N > /dev/null
+exit $?
+
diff --git a/packaging/SGI/spec.pl b/packaging/SGI/spec.pl
new file mode 100755
index 00000000000..4541eb04ec3
--- /dev/null
+++ b/packaging/SGI/spec.pl
@@ -0,0 +1,91 @@
+#!/usr/bin/perl
+
+# This perl script generates the samba.spec file based on the version
+# information in the version.h file in the source tree
+
+open (VER,'../../source/include/version.h') || die "Unable to open version.h\n";
+($_ = <VER>) =~ s/"//g;
+close (VER);
+@foo = split(' ');
+splice(@foo,0,2);
+$_ = $foo[0];
+
+# create the package name
+$vername = " id \"Samba Version ".$_."\"\n";
+
+$patch = 0;
+#create the subsystem version numbers
+if (/alpha/) {
+ $_ =~ s/alpha/.00./;
+}
+elsif (/-HEAD/) {
+ $_ =~ s/-HEAD/.01/;
+ $_ .= '.99';
+}
+elsif (/pre-/) {
+ $_ =~ s/pre-//;
+ $_ .= '.00';
+}
+elsif (/p/) {
+ $_ =~ s/p/./;
+ $_ .= '.00';
+ $patch = 1;
+}
+else {
+ $_ .='.01.00';
+}
+
+($v1,$v2,$v3,$v4,$v5) = split('\.');
+$v4 = $v4 + $patch;
+$vernum = sprintf(" version %02d%02d%02d%02d%02d\n",$v1,$v2,$v3,$v4,$v5);
+
+# generate the samba.spec file
+open(SPEC,">samba.spec") || die "Unable to open samba.spec for output\n";
+print SPEC "product samba\n";
+print SPEC $vername;
+print SPEC " image sw\n";
+print SPEC " id \"Samba Execution Environment\"\n";
+print SPEC $vernum;
+print SPEC " order 0\n";
+print SPEC " subsys base default\n";
+print SPEC " id \"Samba Execution Environment\"\n";
+print SPEC " replaces fw_samba.sw.base 0 9999999999\n";
+print SPEC " replaces fw_samba.sw.samba 0 9999999999\n";
+print SPEC " exp samba.sw.base\n";
+print SPEC " endsubsys\n";
+print SPEC " endimage\n";
+print SPEC " image man\n";
+print SPEC " id \"Samba Online Documentation\"\n";
+print SPEC $vernum;
+print SPEC " order 1\n";
+print SPEC " subsys manpages default\n";
+print SPEC " id \"Samba Man Page\"\n";
+print SPEC " replaces fw_samba.man.manpages 0 9999999999\n";
+print SPEC " replaces fw_samba.man.samba 0 9999999999\n";
+print SPEC " exp samba.man.manpages\n";
+print SPEC " endsubsys\n";
+print SPEC " subsys doc default\n";
+print SPEC " id \"Samba Documentation\"\n";
+print SPEC " replaces fw_samba.man.doc 0 9999999999\n";
+print SPEC " exp samba.man.doc\n";
+print SPEC " endsubsys\n";
+print SPEC " subsys relnotes default\n";
+print SPEC " id \"Samba Release Notes\"\n";
+print SPEC " replaces fw_samba.man.relnotes 0 9999999999\n";
+print SPEC " exp samba.man.relnotes\n";
+print SPEC " endsubsys\n";
+print SPEC " endimage\n";
+print SPEC " image src\n";
+print SPEC " id \"Samba Source Code\"\n";
+print SPEC $vernum;
+print SPEC " order 2\n";
+print SPEC " subsys samba\n";
+print SPEC " id \"Samba Source Code\"\n";
+print SPEC " replaces fw_samba.src.samba 0 9999999999\n";
+print SPEC " exp samba.src.samba\n";
+print SPEC " endsubsys\n";
+print SPEC " endimage\n";
+print SPEC "endproduct\n";
+close SPEC || die "Error on close of samba.spec\n";
+
+print "\nsamba.spec file has been created\n\n";
diff --git a/packaging/SGI/startswat.sh b/packaging/SGI/startswat.sh
new file mode 100755
index 00000000000..2a0333020fb
--- /dev/null
+++ b/packaging/SGI/startswat.sh
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# add SWAT deamon to inetd.conf
+#
+cp /etc/inetd.conf /etc/inetd.conf.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/inetd.conf.O -o ! -w /etc/inetd.conf ]; then exit 1; fi
+
+sed -e "/^swat/D" -e "/^#SWAT/D" /etc/inetd.conf.O > /etc/inetd.conf
+echo '#SWAT services' >> /etc/inetd.conf
+echo swat stream tcp nowait root /usr/samba/bin/swat swat >> /etc/inetd.conf
+
+#
+# add SWAT service port to /etc/services
+#
+cp /etc/services /etc/services.O
+
+if [ $? -ne 0 ]; then exit 1; fi
+if [ ! -r /etc/services.O -o ! -w /etc/services ]; then exit 1; fi
+
+sed -e "/^swat/D" -e "/^#SWAT/D" /etc/services.O > /etc/services
+echo '#SWAT services' >> /etc/services
+echo 'swat 901/tcp # SWAT' >> /etc/services
+
+#
+# restart inetd to start SWAT
+#
+/etc/killall -HUP inetd
diff --git a/packaging/Solaris/README b/packaging/Solaris/README
new file mode 100644
index 00000000000..b918cf91732
--- /dev/null
+++ b/packaging/Solaris/README
@@ -0,0 +1,18 @@
+
+INSTRUCTIONS: Preparing Samba packages for Solaris
+
+To produce a package:
+
+* Build the binaries (by running ./configure; make; in the source directory)
+* Type sh makepkg.sh
+
+The package will be created in the /tmp directory.
+
+By default, the package will be built to install samba in /usr/local
+To change the default, modify the INSTALL_BASE variable in makepkg.sh
+This is after you have configured samba with a --prefix option of the
+alternate samba location and then created the binaries.
+
+Shirish Kalele <kalele@samba.org>
+Date: 2000.01.12
+
diff --git a/packaging/Solaris/copyright b/packaging/Solaris/copyright
new file mode 100644
index 00000000000..1792668d174
--- /dev/null
+++ b/packaging/Solaris/copyright
@@ -0,0 +1 @@
+Copyright (C) 2001 Samba Team
diff --git a/packaging/Solaris/i.swat b/packaging/Solaris/i.swat
new file mode 100644
index 00000000000..047f0e17200
--- /dev/null
+++ b/packaging/Solaris/i.swat
@@ -0,0 +1,44 @@
+while read src dest
+do
+ sed -e '/^swat.*swat$/d' $dest >/tmp/$$swat || exit 2
+ cat $src >>/tmp/$$swat || exit 2
+
+ # Use cp;rm instead of mv because $dest might be a symlink
+ cp -f /tmp/$$swat $dest || exit 2
+ rm -f /tmp/$$swat
+done
+
+if [ "$1" = ENDOFCLASS ]
+then
+
+ # If local install, restart inetd
+ if [ -z "${PKG_INSTALL_ROOT}" ]
+ then
+ TARGET=`hostname`
+ kill -HUP `ps -e -o pid,comm | grep inetd | awk '{print $1}'`
+ else
+ TARGET="<servername>"
+ fi
+
+ cat <<EOF
+The Samba Web Administration Tool (SWAT) has been installed on your system.
+You can connect to it from a web browser on TCP port 901 at
+http://${TARGET}:901/.
+
+If you use NIS/NIS+, check the ${PKG_INSTALL_ROOT}/etc/nsswitch.conf file
+to verify that the local services file is being used as a backend for the
+services database, or you won't be able to connect to the Samba Admin Tool.
+
+EOF
+
+ if [ ! -z "$PKG_INSTALL_ROOT" ]
+ then
+ CAT <<EOF
+The SWAT settings will not take effect till you send a hangup (HUP) signal
+to inetd on the target system.
+
+EOF
+ fi
+
+fi
+
diff --git a/packaging/Solaris/inetd.conf.master b/packaging/Solaris/inetd.conf.master
new file mode 100644
index 00000000000..b11fb7c3db2
--- /dev/null
+++ b/packaging/Solaris/inetd.conf.master
@@ -0,0 +1 @@
+swat stream tcp nowait.400 root __BASEDIR__/samba/bin/swat swat
diff --git a/packaging/Solaris/makepkg.sh b/packaging/Solaris/makepkg.sh
new file mode 100755
index 00000000000..b57e182e4a3
--- /dev/null
+++ b/packaging/Solaris/makepkg.sh
@@ -0,0 +1,185 @@
+#!/bin/sh
+#
+# Copyright (C) Shirish A Kalele 2000
+#
+# Builds a Samba package from the samba distribution.
+# By default, the package will be built to install samba in /usr/local
+# Change the INSTALL_BASE variable to change this: will modify the pkginfo
+# and samba.server files to point to the new INSTALL_BASE
+#
+INSTALL_BASE=/usr/local
+
+add_dynamic_entries()
+{
+ # First build the codepages and append codepage entries to prototype
+ echo "#\n# Codepages \n#"
+ echo d none samba/lib/codepages 0755 root other
+
+ CODEPAGELIST="437 737 850 852 861 932 866 949 950 936"
+ # Check if make_smbcodepage exists
+ if [ ! -f $DISTR_BASE/source/bin/make_smbcodepage ]; then
+ echo "Could not find $DISTR_BASE/source/bin/make_smbcodepage to generate codepages.\n\
+ Please create the binaries before packaging." >&2
+ exit 1
+ fi
+
+ for p in $CODEPAGELIST; do
+ $DISTR_BASE/source/bin/make_smbcodepage c $p $DISTR_BASE/source/codepages/codepage_def.$p $DISTR_BASE/source/codepages/codepage.$p
+ echo f none samba/lib/codepages/codepage.$p=source/codepages/codepage.$p 0644 root other
+ done
+
+ # Create unicode maps
+ if [ ! -f $DISTR_BASE/source/bin/make_unicodemap ]; then
+ echo "Missing $DISTR_BASE/source/bin/make_unicodemap. Aborting." >&2
+ exit 1
+ fi
+
+ # Pull in all the unicode map files from source/codepages/CP*.TXT
+ list=`find $DISTR_BASE/source/codepages -name "CP*.TXT" | sed 's|^.*CP\(.*\)\.TXT|\1|'`
+ for umap in $list
+ do
+ $DISTR_BASE/source/bin/make_unicodemap $umap $DISTR_BASE/source/codepages/CP$umap.TXT $DISTR_BASE/source/codepages/unicode_map.$umap
+ echo f none samba/lib/codepages/unicode_map.$umap=source/codepages/unicode_map.$umap 0644 root other
+ done
+
+ # Add the binaries, docs and SWAT files
+
+ echo "#\n# Binaries \n#"
+ cd $DISTR_BASE/source/bin
+ for binfile in *
+ do
+ if [ -f $binfile ]; then
+ echo f none samba/bin/$binfile=source/bin/$binfile 0755 root other
+ fi
+ done
+
+ # Add the scripts to bin/
+ echo "#\n# Scripts \n#"
+ cd $DISTR_BASE/source/script
+ for shfile in *
+ do
+ if [ -f $shfile ]; then
+ echo f none samba/bin/$shfile=source/script/$shfile 0755 root other
+ fi
+ done
+
+ # Add the manpages
+ echo "#\n# man pages \n#"
+ echo d none /usr ? ? ?
+ echo d none /usr/share ? ? ?
+ echo d none /usr/share/man ? ? ?
+
+ # Create directories for man page sections if nonexistent
+ cd $DISTR_BASE/docs/manpages
+ for i in 1 2 3 4 5 6 7 8 9
+ do
+ manpages=`ls *.$i 2>/dev/null`
+ if [ $? -eq 0 ]
+ then
+ echo d none /usr/share/man/man$i ? ? ?
+ for manpage in $manpages
+ do
+ echo f none /usr/share/man/man${i}/${manpage}=docs/manpages/$manpage 0644 root other
+ done
+ fi
+ done
+
+ echo "#\n# HTML documentation \n#"
+ cd $DISTR_BASE
+ list=`find docs/htmldocs -type d | grep -v "/CVS$"`
+ for docdir in $list
+ do
+ if [ -d $docdir ]; then
+ echo d none samba/$docdir 0755 root other
+ fi
+ done
+
+ list=`find docs/htmldocs -type f | grep -v /CVS/`
+ for htmldoc in $list
+ do
+ if [ -f $htmldoc ]; then
+ echo f none samba/$htmldoc=$htmldoc 0644 root other
+ fi
+ done
+
+ # Create a symbolic link to the Samba book in docs/ for beginners
+ echo 's none samba/docs/samba_book=htmldocs/using_samba'
+
+ echo "#\n# Text Docs \n#"
+ echo d none samba/docs/textdocs 0755 root other
+ cd $DISTR_BASE/docs/textdocs
+ for textdoc in *
+ do
+ if [ -f $textdoc ]; then
+ echo f none samba/docs/textdocs/$textdoc=docs/textdocs/$textdoc 0644 root other
+ fi
+ done
+ echo "#\n# SWAT \n#"
+ cd $DISTR_BASE
+ list=`find swat -type d | grep -v "/CVS$"`
+ for i in $list
+ do
+ echo "d none samba/$i 0755 root other"
+ done
+ list=`find swat -type f | grep -v /CVS/`
+ for i in $list
+ do
+ echo "f none samba/$i=$i 0644 root other"
+ done
+ echo "#\n# HTML documentation for SWAT\n#"
+ cd $DISTR_BASE/docs/htmldocs
+ for htmldoc in *
+ do
+ if [ -f $htmldoc ]; then
+ echo f none samba/swat/help/$htmldoc=docs/htmldocs/$htmldoc 0644 root other
+ fi
+ done
+
+ echo "#\n# Using Samba Book files for SWAT\n#"
+ cd $DISTR_BASE/docs/htmldocs
+
+# set up a symbolic link instead of duplicating the book tree
+ echo 's none samba/swat/using_samba=../docs/htmldocs/using_samba'
+
+}
+
+if [ $# = 0 ]
+then
+ # Try to guess the distribution base..
+ CURR_DIR=`pwd`
+ DISTR_BASE=`echo $CURR_DIR | sed 's|\(.*\)/packaging.*|\1|'`
+ echo "Assuming Samba distribution is rooted at $DISTR_BASE.."
+else
+ DISTR_BASE=$1
+fi
+
+#
+if [ ! -d $DISTR_BASE ]; then
+ echo "Source build directory $DISTR_BASE does not exist."
+ exit 1
+fi
+
+# Set up the prototype file from prototype.master
+if [ -f prototype ]; then
+ rm prototype
+fi
+
+# Setup version from version.h
+VERSION=`sed 's/#define VERSION \"\(.*\)\"$/\1/' ../../source/include/version.h`
+sed -e "s|__VERSION__|$VERSION|" -e "s|__ARCH__|`uname -p`|" -e "s|__BASEDIR__|$INSTALL_BASE|g" pkginfo.master >pkginfo
+
+sed -e "s|__BASEDIR__|$INSTALL_BASE|g" inetd.conf.master >inetd.conf
+sed -e "s|__BASEDIR__|$INSTALL_BASE|g" samba.server.master >samba.server
+
+cp prototype.master prototype
+
+# Add the dynamic part to the prototype file
+(add_dynamic_entries >> prototype)
+
+# Create the package
+pkgmk -o -d /tmp -b $DISTR_BASE -f prototype
+if [ $? = 0 ]
+then
+ pkgtrans /tmp samba.pkg samba
+fi
+echo The samba package is in /tmp
diff --git a/packaging/Solaris/pkg-specs/pkginfo b/packaging/Solaris/pkg-specs/pkginfo
new file mode 100644
index 00000000000..d195f177e90
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/pkginfo
@@ -0,0 +1,12 @@
+PKG=samba
+NAME=SMB based file/printer sharing
+ARCH=sparc
+VERSION=2.0.6
+CATEGORY=system
+VENDOR=Samba Group
+DESC=File and printer sharing for NT workstations
+HOTLINE=Please contact your local UNIX support group
+EMAIL=samba@samba.org
+CLASSES=none
+BASEDIR=/usr/local
+INTONLY=1
diff --git a/packaging/Solaris/pkginfo.master b/packaging/Solaris/pkginfo.master
new file mode 100644
index 00000000000..33e7cdb471d
--- /dev/null
+++ b/packaging/Solaris/pkginfo.master
@@ -0,0 +1,12 @@
+PKG=samba
+NAME=SMB based file/printer sharing
+ARCH=__ARCH__
+VERSION=__VERSION__
+CATEGORY=system
+VENDOR=Samba Team
+DESC=File and printer sharing for Windows workstations
+HOTLINE=Please contact your local UNIX support group
+EMAIL=samba@samba.org
+CLASSES=none
+BASEDIR=__BASEDIR__
+INTONLY=1
diff --git a/packaging/Solaris/postinstall b/packaging/Solaris/postinstall
new file mode 100644
index 00000000000..0b7f40a85d0
--- /dev/null
+++ b/packaging/Solaris/postinstall
@@ -0,0 +1,21 @@
+cat <<EOF
+___________________________________________________________________________
+
+INSTALLATION COMPLETE.
+
+All files comprising the Samba Server have been installed.
+
+You can configure Samba by creating a configuration file at
+${BASEDIR}/samba/lib/smb.conf. For details on configuration,
+refer to the Samba man pages under ${PKG_INSTALL_ROOT}/usr/share/man
+and the documentation at ${BASEDIR}/samba/docs.
+
+BEGINNERS:
+Beginners can also refer to the excellent "Using Samba" book published
+by O'Reilly and Associates and officially supported by the Samba Team.
+This book is supplied with this package and can be accessed at
+${BASEDIR}/samba/docs/samba_book/index.html
+___________________________________________________________________________
+
+EOF
+
diff --git a/packaging/Solaris/preremove b/packaging/Solaris/preremove
new file mode 100644
index 00000000000..28e8d75c298
--- /dev/null
+++ b/packaging/Solaris/preremove
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# If this is a local deinstall, stop samba
+if [ -z "$PKG_INSTALL_ROOT" ]
+then
+ SMBD=`ps -e -o pid,comm | grep smbd | awk '{print $1}'`
+ NMBD=`ps -e -o pid,comm | grep nmbd | awk '{print $1}'`
+ [ ! -z "$SMBD" ] && kill $SMBD
+ [ ! -z "$NMBD" ] && kill $NMBD
+ sleep 2
+fi
+
diff --git a/packaging/Solaris/prototype.master b/packaging/Solaris/prototype.master
new file mode 100644
index 00000000000..bfcb3e00492
--- /dev/null
+++ b/packaging/Solaris/prototype.master
@@ -0,0 +1,52 @@
+#
+# The static master prototype file for the Samba package.
+# For files that can't be dynamically added to the prototype file at
+# package build time
+#
+# Information files.
+#
+i pkginfo=./pkginfo
+i copyright=./copyright
+i request=./request
+i checkinstall
+i preremove=./preremove
+i postinstall=./postinstall
+i i.swat=./i.swat
+i r.swat=./r.swat
+#
+# Stuff that goes into the system areas of the filesystem.
+#
+d none /etc ? ? ?
+d initscript /etc/init.d ? ? ?
+f initscript /etc/init.d/samba.server=packaging/Solaris/samba.server 0744 root sys
+d initscript /etc/rc3.d ? ? ?
+s initscript /etc/rc3.d/S99samba.server=../init.d/samba.server
+#
+# Stuff to set up SWAT
+#
+d swat /etc/inet ? ? ?
+e swat /etc/inet/services=packaging/Solaris/services ? ? ?
+e swat /etc/inet/inetd.conf=packaging/Solaris/inetd.conf ? ? ?
+#
+# Create the samba subtree. (Usually /usr/local/samba )
+#
+d none samba 0755 root other
+d none samba/var 0755 root other
+d none samba/bin 0755 root other
+d none samba/lib 0755 root other
+d none samba/docs 0755 root other
+#
+# Stuff that goes into lib
+#
+f none samba/lib/smb.conf.example=examples/smb.conf.default 0644 root other
+d none samba/lib/regeditscripts 0755 root other
+f none samba/lib/regeditscripts/NT4_PlainPassword.reg=docs/NT4_PlainPassword.reg 0444 root other
+f none samba/lib/regeditscripts/Win95_PlainPassword.reg=docs/Win95_PlainPassword.reg 0444 root other
+f none samba/lib/regeditscripts/Win98_PlainPassword.reg=docs/Win98_PlainPassword.reg 0444 root other
+f none samba/lib/regeditscripts/Win2000_PlainPassword.reg=docs/Win2000_PlainPassword.reg 0444 root other
+#
+# Random files
+f none samba/docs/Samba-HOWTO-Collection.pdf=docs/Samba-HOWTO-Collection.pdf 0644 root other
+#
+# Static part of prototype file ends.
+#
diff --git a/packaging/Solaris/r.swat b/packaging/Solaris/r.swat
new file mode 100644
index 00000000000..11c776646da
--- /dev/null
+++ b/packaging/Solaris/r.swat
@@ -0,0 +1,16 @@
+while read dest
+do
+ sed -e '/^swat.*swat$/d' $dest >/tmp/$$swat || exit 2
+ # Use cp;rm; instead of mv because $dest might be a symlink
+ cp -f /tmp/$$swat $dest || exit 2
+ rm -f /tmp/$$swat
+done
+
+if [ "$1" = ENDOFCLASS ]
+then
+ if [ -z "$PKG_INSTALL_ROOT" ]
+ then
+ kill -HUP `ps -e -o pid,comm | grep inetd | awk '{print $1}'`
+ fi
+fi
+
diff --git a/packaging/Solaris/request b/packaging/Solaris/request
new file mode 100644
index 00000000000..59cdd0ab22a
--- /dev/null
+++ b/packaging/Solaris/request
@@ -0,0 +1,17 @@
+trap 'exit 3' 15
+
+VALSTR=/usr/sadm/bin/valstr
+
+resp=`ckyorn -d y -p "Do you wish to have Samba start whenever the system boots up? (default:y) " -Q`
+$VALSTR -r "^[yY]" $resp
+[ $? -eq 0 ] && CLASSES="$CLASSES initscript"
+
+resp=`ckyorn -d y -p "Do you wish to set up the Samba Web Admin Tool (SWAT)? (default:y) " -Q`
+$VALSTR -r "^[yY]" $resp
+[ $? -eq 0 ] && CLASSES="$CLASSES swat"
+
+cat >$1 <<!
+CLASSES=$CLASSES
+!
+exit 0
+
diff --git a/packaging/Solaris/samba.server.master b/packaging/Solaris/samba.server.master
new file mode 100755
index 00000000000..6de77780b34
--- /dev/null
+++ b/packaging/Solaris/samba.server.master
@@ -0,0 +1,48 @@
+#!/bin/sh
+#ident "@(#)samba.server 1.0 96/06/19 TK" /* SVr4.0 1.1.13.1*/
+#
+# Please send info on modifications to knuutila@cs.utu.fi
+#
+# This file should have uid root, gid sys and chmod 744
+#
+if [ ! -d /usr/bin ]
+then # /usr not mounted
+ exit
+fi
+
+killproc() { # kill the named process(es)
+ pid=`/usr/bin/ps -e |
+ /usr/bin/grep -w $1 |
+ /usr/bin/sed -e 's/^ *//' -e 's/ .*//'`
+ [ "$pid" != "" ] && kill $pid
+}
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+'start')
+#
+# Edit these lines to suit your installation (paths, workgroup, host)
+#
+ BASE=__BASEDIR__/samba
+ $BASE/bin/smbd -D -s$BASE/lib/smb.conf
+ $BASE/bin/nmbd -D -s$BASE/lib/smb.conf
+ ;;
+'stop')
+ killproc nmbd
+ killproc smbd
+ ;;
+
+'restart')
+ killproc nmbd
+ killproc smbd
+ BASE=/usr/local/samba
+ $BASE/bin/smbd -D -s$BASE/lib/smb.conf
+ $BASE/bin/nmbd -D -l$BASE/var/log -s$BASE/lib/smb.conf
+ ;;
+
+*)
+ echo "Usage: /etc/init.d/samba.server { start | stop | restart }"
+ ;;
+esac
diff --git a/packaging/Solaris/services b/packaging/Solaris/services
new file mode 100644
index 00000000000..fc691200c8d
--- /dev/null
+++ b/packaging/Solaris/services
@@ -0,0 +1 @@
+swat 901/tcp # Samba Web Admin Tool - swat
diff --git a/packaging/SuSE/5.2/samba-1.9.18p5.dif b/packaging/SuSE/5.2/samba-1.9.18p5.dif
new file mode 100644
index 00000000000..39b13f010de
--- /dev/null
+++ b/packaging/SuSE/5.2/samba-1.9.18p5.dif
@@ -0,0 +1,234 @@
+--- Makefile.Linux
++++ Makefile.Linux 1998/05/06 15:58:42
+@@ -0,0 +1,35 @@
++#
++#
++# Makefile.Linux to integrate package into source tree of S.u.S.E.-Linux
++#
++# Copyright (C) 1996 S.u.S.E. GmbH Fuerth, Germany.
++#
++# Please send bug-fixes or comments to feedback@suse.de.
++#
++# Author: Florian La Roche <florian@suse.de>
++# Volker Lendecke <vl@suse.de>
++#
++#
++
++doc=/usr/doc/packages/samba
++
++compile:
++ make -C source
++
++install:
++ make install -C source
++ mkdir -p $(doc)
++ cp -a docs/* $(doc)
++ rm -rf $(doc)/*.[0-9]
++ cp -R examples $(doc)
++ chmod 644 `find $(doc) -type f`
++ chmod 755 `find $(doc) -type d`
++ install -m 644 smb.conf /etc/smb.conf
++ install rc /sbin/init.d/smb
++ install -m 755 source/mksmbpasswd.sh /usr/bin/mksmbpasswd.sh
++ ln -sf ../smb /sbin/init.d/rc2.d/S20smb
++ ln -sf ../smb /sbin/init.d/rc2.d/K20smb
++ ln -sf ../smb /sbin/init.d/rc3.d/S20smb
++ ln -sf ../smb /sbin/init.d/rc3.d/K20smb
++ mkdir -p /var/adm/fillup-templates
++ cp rc.config.samba /var/adm/fillup-templates
+--- doinst.sh
++++ doinst.sh 1998/05/06 15:54:52
+@@ -0,0 +1,15 @@
++#
++# install/doinst.sh - to be done after extraction
++#
++# Copyright (c) 1997 S.u.S.E. GmbH Fuerth, Germany.
++#
++#
++echo "Updating etc/rc.config..."
++if [ -x bin/fillup ] ; then
++ bin/fillup -q -d = etc/rc.config var/adm/fillup-templates/rc.config.samba
++else
++ echo "ERROR: fillup not found. This should not happen. Please compare"
++ echo "etc/rc.config and var/adm/fillup-templates/rc.config.samba and"
++ echo "update by hand."
++fi
++
+--- rc
++++ rc 1998/05/06 15:54:52
+@@ -0,0 +1,32 @@
++#! /bin/sh
++# Copyright (c) 1996 StarDivision GmbH. All rights reserved.
++# Copyright (c) 1996 S.u.S.E. Gmbh Fuerth, Germany. All rights reserved.
++#
++# Author: Bastian Epting, StarDivision GmbH <be@stardivision.de>
++# Florian La Roche, <florian@suse.de>
++# Volker Lendecke, <vl@suse.de>
++#
++
++. /etc/rc.config
++
++test "$START_SMB" = "yes" || exit 0
++
++case "$1" in
++ start)
++ echo -n "Starting SMB services."
++ /usr/sbin/nmbd -D
++ /usr/sbin/smbd -D
++ echo
++ ;;
++ stop)
++ echo -n "Shutting down SMB services."
++ killproc -TERM /usr/sbin/nmbd
++ killproc -TERM /usr/sbin/smbd
++ echo
++ ;;
++ *)
++ echo "Usage: $0 {start|stop}"
++ exit 1
++esac
++
++exit 0
+--- rc.config.samba
++++ rc.config.samba 1998/05/06 15:54:52
+@@ -0,0 +1,5 @@
++#
++# start samba? ("yes" or "no")
++# Windows 95 / NT - File- and Printservices
++#
++START_SMB="no"
+--- smb.conf
++++ smb.conf 1998/05/06 15:54:52
+@@ -0,0 +1,48 @@
++[global]
++ workgroup = arbeitsgruppe
++ guest account = nobody
++ keep alive = 30
++ os level = 2
++ security = user
++ printing = bsd
++ printcap name = /etc/printcap
++ load printers = yes
++
++; Please uncomment the following entry and replace the
++; ip number and netmask with the correct numbers for
++; your ethernet interface.
++; interfaces = 192.168.1.1/255.255.255.0
++
++; If you want Samba to act as a wins server, please set
++; 'wins support = yes'
++ wins support = no
++
++; If you want Samba to use an existing wins server,
++; please uncomment the following line and replace
++; the dummy with the wins server's ip number.
++; wins server = 192.168.1.1
++
++[homes]
++ comment = Heimatverzeichnis
++ browseable = no
++ read only = no
++ create mode = 0750
++
++; The following share gives all users access to the Server's CD drive,
++; assuming it is mounted under /cd. To enable this share, please remove
++; the semicolons before the lines
++;
++; [cdrom]
++; comment = Linux CD-ROM
++; path = /cd
++; read only = yes
++; locking = no
++
++[printers]
++ comment = All Printers
++ browseable = no
++ printable = yes
++ public = no
++ read only = yes
++ create mode = 0700
++ directory = /tmp
+--- source/Makefile
++++ source/Makefile 1998/05/06 15:54:52
+@@ -5,11 +5,11 @@
+ ###########################################################################
+
+ # The base directory for all samba files
+-BASEDIR = /usr/local/samba
++BASEDIR = /usr
+
+ # The base manpages directory to put the man pages in
+ # Note: $(MANDIR)/man1, $(MANDIR)/man5 and $(MANDIR)/man8 must exist.
+-MANDIR = /usr/local/man
++MANDIR = /usr/man
+
+ # The directories to put things in. If you use multiple
+ # architectures or share the samba binaries across NFS then
+@@ -18,16 +18,16 @@
+ # normally only applies to nmbd and smbd
+ # SBINDIR implies a secure binary directory
+ BINDIR = $(BASEDIR)/bin
+-SBINDIR = $(BASEDIR)/bin
+-LIBDIR = $(BASEDIR)/lib
+-VARDIR = $(BASEDIR)/var
++SBINDIR = $(BASEDIR)/sbin
++LIBDIR = $(BASEDIR)/lib/samba
++VARDIR = /var/log
+
+ # The permissions to give the executables
+ INSTALLPERMS = 0755
+
+ # Add any optimisation or debugging flags here
+ # add -DSYSLOG for syslog support
+-FLAGS1 = -O
++FLAGS1 = -O2
+ LIBS1 =
+
+ # You will need to use a ANSI C compiler. This means under SunOS 4 you can't
+@@ -47,15 +47,15 @@
+ # or in smb.conf (see smb.conf(5))
+ SMBLOGFILE = $(VARDIR)/log.smb
+ NMBLOGFILE = $(VARDIR)/log.nmb
+-CONFIGFILE = $(LIBDIR)/smb.conf
+-LMHOSTSFILE = $(LIBDIR)/lmhosts
+-DRIVERFILE = $(LIBDIR)/printers.def
++CONFIGFILE = /etc/smb.conf
++LMHOSTSFILE = /etc/lmhosts
++DRIVERFILE = /etc/printers.def
+ SMB_PASSWD = $(BINDIR)/smbpasswd
+-SMB_PASSWD_FILE = $(BASEDIR)/private/smbpasswd
+-WEB_ROOT = $(BASEDIR)
++SMB_PASSWD_FILE = /etc/smbpasswd
++WEB_ROOT = /etc
+
+ # the directory where lock files go
+-LOCKDIR = $(VARDIR)/locks
++LOCKDIR = /var/lock
+
+ # The directory where code page definition files go
+ CODEPAGEDIR = $(LIBDIR)/codepages
+@@ -206,7 +206,7 @@
+ # contributed by Andrew.Tridgell@anu.edu.au
+ # add -DLINUX_BIGCRYPT is you have shadow passwords but don't have the
+ # right libraries and includes
+-# FLAGSM = -DLINUX -DSHADOW_PWD -DFAST_SHARE_MODES
++FLAGSM = -DLINUX -DSHADOW_PWD -DFAST_SHARE_MODES
+ # LIBSM = -lshadow
+
+ # Use this for Linux without shadow passwords or for any Linux
+--- source/includes.h
++++ source/includes.h 1998/05/06 15:54:52
+@@ -244,13 +244,6 @@
+ #define USE_SETFS
+ #endif
+ #endif
+-#ifdef SHADOW_PWD
+-#if _LINUX_C_LIB_VERSION_MAJOR < 5
+-#ifndef crypt
+-#define crypt pw_encrypt
+-#endif
+-#endif
+-#endif
+ #endif
+
+ #ifdef SUNOS4
diff --git a/packaging/SuSE/5.2/samba.spec b/packaging/SuSE/5.2/samba.spec
new file mode 100644
index 00000000000..5f20875c9ea
--- /dev/null
+++ b/packaging/SuSE/5.2/samba.spec
@@ -0,0 +1,119 @@
+#
+# spec file for package samba (Version 1.9.18p1)
+#
+# Copyright (c) 1997 S.u.S.E. GmbH Fuerth, Germany.
+#
+# please send bugfixes or comments to feedback@suse.de.
+#
+
+Vendor: S.u.S.E. GmbH, Fuerth, Germany
+Distribution: S.u.S.E. Linux 5.1 (i386)
+Name: samba
+Release: 1
+Copyright: 1992-98 Andrew Tridgell, Karl Auer, Jeremy Allison
+Group:
+Provides: samba smbfs
+Requires:
+Conflicts:
+Autoreqprov: on
+Packager: feedback@suse.de
+
+Version: 1.9.18p5
+Summary: Samba is a file server for Unix, similar to LanManager.
+Source: samba-1.9.18p5.tar.gz
+Source1: smbfs-2.0.2.tar.gz
+Patch: samba-1.9.18p5.dif
+Patch1: smbfs-2.0.2.dif
+%prep
+%setup
+%patch
+%setup -T -n smbfs-2.0.2 -b1
+%patch -P 1
+%build
+cd ../samba-1.9.18p5
+make -f Makefile.Linux compile
+cd ../smbfs-2.0.2
+make -f Makefile.Linux compile
+%install
+cd ../samba-1.9.18p5
+make -f Makefile.Linux install
+cd ../smbfs-2.0.2
+make -f Makefile.Linux install
+Check
+%post
+echo "Updating etc/rc.config..."
+if [ -x bin/fillup ] ; then
+ bin/fillup -q -d = etc/rc.config var/adm/fillup-templates/rc.config.samba
+else
+ echo "ERROR: fillup not found. This should not happen. Please compare"
+ echo "etc/rc.config and var/adm/fillup-templates/rc.config.samba and"
+ echo "update by hand."
+fi
+%files
+%docdir /usr/doc/packages/samba
+/usr/doc/packages/samba
+%config /etc/smb.conf
+/usr/lib/samba/codepages
+/sbin/init.d/rc2.d/K20smb
+/sbin/init.d/rc2.d/S20smb
+/sbin/init.d/rc3.d/K20smb
+/sbin/init.d/rc3.d/S20smb
+%config /sbin/init.d/smb
+/usr/bin/addtosmbpass
+/usr/bin/mksmbpasswd.sh
+/usr/bin/make_printerdef
+/usr/bin/make_smbcodepage
+/usr/bin/nmblookup
+/usr/bin/smbclient
+/usr/bin/smbmount
+/usr/bin/smbpasswd
+/usr/bin/smbstatus
+/usr/bin/smbtar
+/usr/bin/smbumount
+/usr/bin/testparm
+/usr/bin/testprns
+%doc /usr/man/man1/smbclient.1.gz
+%doc /usr/man/man1/smbrun.1.gz
+%doc /usr/man/man1/smbstatus.1.gz
+%doc /usr/man/man1/smbtar.1.gz
+%doc /usr/man/man1/testparm.1.gz
+%doc /usr/man/man1/testprns.1.gz
+%doc /usr/man/man1/make_smbcodepage.1.gz
+%doc /usr/man/man5/smb.conf.5.gz
+%doc /usr/man/man7/samba.7.gz
+%doc /usr/man/man8/nmbd.8.gz
+%doc /usr/man/man8/smbd.8.gz
+%doc /usr/man/man8/smbmount.8.gz
+%doc /usr/man/man8/smbumount.8.gz
+%doc /usr/man/man8/smbmnt.8.gz
+%doc /usr/man/man8/smbpasswd.8.gz
+/usr/sbin/nmbd
+/usr/sbin/smbd
+/var/adm/fillup-templates/rc.config.samba
+%description
+Samba is a suite of programs which work together to allow clients to
+access Unix filespace and printers via the SMB protocol (Seerver Message
+Block).
+CAUTION: The samba daemons are started by the init script
+/sbin/init.d/samba, not by inetd. The entries for /usr/sbin/smbd
+and /usr/sbin/nmbd must be commented out in /etc/inetd.conf.
+In practice, this means that you can redirect disks and printers to
+Unix disks and printers from LAN Manager clients, Windows for
+Workgroups 3.11 clients, Windows'95 clients, Windows NT clients
+and OS/2 clients. There is
+also a Unix client program supplied as part of the suite which allows
+Unix users to use an ftp-like interface to access filespace and
+printers on any other SMB server.
+Samba includes the following programs (in summary):
+* smbd, the SMB server. This handles actual connections from clients.
+* nmbd, the Netbios name server, which helps clients locate servers.
+* smbclient, the Unix-hosted client program.
+* testprns, a program to test server access to printers.
+* testparm, a program to test the Samba configuration file for correctness.
+* smb.conf, the Samba configuration file.
+* smbprint, a sample script to allow a Unix host to use smbclient
+to print to an SMB server.
+The suite is supplied with full source and is GPLed.
+This package expects its config file under /etc/smb.conf .
+Documentation: /usr/doc/packages/samba
+
diff --git a/packaging/SuSE/7.1/samba-2.2.0-alpha0.dif b/packaging/SuSE/7.1/samba-2.2.0-alpha0.dif
new file mode 100644
index 00000000000..75bfdf18c66
--- /dev/null
+++ b/packaging/SuSE/7.1/samba-2.2.0-alpha0.dif
@@ -0,0 +1,224 @@
+--- lmhosts
++++ lmhosts 2000/08/28 07:32:33
+@@ -0,0 +1,8 @@
++# This file provides the same function that the
++# lmhosts file does for Windows.
++# It provides another way to map netbios names to ip addresses.
++# See the section on 'name resolve order' in the manual page to
++# smb.conf for more information.
++
++# Sample entry:
++# 192.168.1.1 samba
+--- mount.smbfs
++++ mount.smbfs 2000/08/28 07:32:55
+@@ -0,0 +1,14 @@
++#!/bin/sh
++#
++# Copyright (c) 1999 SuSE GmbH Nuernberg, Germany. All rights reserved.
++#
++# Author: Carsten Hoeger <choeger@suse.de>
++#
++# /sbin/mount.smbfs
++#
++# I'm called by the mount-command and smbmount want's to get
++# called by me, so lets do it.
++#
++# P.S.: This is a very very raw solution and I don't know, if this
++# is intentionally.
++smbmount "$@"
+--- rc
++++ rc 2000/08/28 07:32:33
+@@ -0,0 +1,53 @@
++#! /bin/sh
++# Copyright (c) 1996 StarDivision GmbH. All rights reserved.
++# Copyright (c) 1996 S.u.S.E. Gmbh Fuerth, Germany. All rights reserved.
++#
++# Author: Bastian Epting, StarDivision GmbH <be@stardivision.de>
++# Florian La Roche, <florian@suse.de>
++# Volker Lendecke, <vl@suse.de>
++#
++
++. /etc/rc.config
++
++# Determine the base and follow a runlevel link name.
++base=${0##*/}
++link=${base#*[SK][0-9][0-9]}
++
++# Force execution if not called by a runlevel directory.
++test $link = $base && START_SMB=yes
++test "$START_SMB" = "yes" || exit 0
++
++# The echo return value for success (defined in /etc/rc.config).
++return=$rc_done
++case "$1" in
++ start)
++ echo -n "Starting SMB services:"
++ startproc /usr/sbin/nmbd -D || return=$rc_failed
++ startproc /usr/sbin/smbd -D || return=$rc_failed
++ echo -e "$return"
++ ;;
++ stop)
++ echo -n "Shutting down SMB services:"
++ killproc -TERM /usr/sbin/nmbd || return=$rc_failed
++ killproc -TERM /usr/sbin/smbd || return=$rc_failed
++ echo -e "$return"
++ ;;
++ restart|reload)
++ echo -n "Reloading SMB services:"
++ killproc -HUP /usr/sbin/nmbd || return=$rc_failed
++ killproc -HUP /usr/sbin/smbd || return=$rc_failed
++ echo -e "$return"
++ ;;
++ status)
++ echo -n "Checking for service smb: "
++ checkproc /usr/sbin/nmbd && echo -n "OK " || echo -n "No process "
++ checkproc /usr/sbin/smbd && echo "OK " || echo "No process"
++ ;;
++ *)
++ echo "Usage: $0 {start|stop|restart|reload|status}"
++ exit 1
++esac
++
++# Inform the caller not only verbosely and set an exit status.
++test "$return" = "$rc_done" || exit 1
++exit 0
+--- rc.config.samba
++++ rc.config.samba 2000/08/28 07:32:33
+@@ -0,0 +1,5 @@
++#
++# start samba? ("yes" or "no")
++# Windows 95 / NT - File- and Printservices
++#
++START_SMB="no"
+--- smb.conf
++++ smb.conf 2000/08/28 07:32:33
+@@ -0,0 +1,80 @@
++;
++; /etc/smb.conf
++;
++; Copyright (c) 1999 SuSE GmbH Nuernberg, Germany.
++;
++[global]
++ workgroup = arbeitsgruppe
++ guest account = nobody
++ keep alive = 30
++ os level = 2
++ kernel oplocks = false
++ security = user
++
++; Uncomment the following, if you want to use an existing
++; NT-Server to authenticate users, but don't forget that
++; you also have to create them locally!!!
++; security = server
++; password server = 192.168.1.10
++; encrypt passwords = yes
++
++ printing = bsd
++ printcap name = /etc/printcap
++ load printers = yes
++
++ socket options = TCP_NODELAY
++
++ map to guest = Bad User
++
++; Uncomment this, if you want to integrate your server
++; into an existing net e.g. with NT-WS to prevent nettraffic
++; local master = no
++
++; Please uncomment the following entry and replace the
++; ip number and netmask with the correct numbers for
++; your ethernet interface.
++; interfaces = 192.168.1.1/255.255.255.0
++
++; If you want Samba to act as a wins server, please set
++; 'wins support = yes'
++ wins support = no
++
++; If you want Samba to use an existing wins server,
++; please uncomment the following line and replace
++; the dummy with the wins server's ip number.
++; wins server = 192.168.1.1
++
++; Do you wan't samba to act as a logon-server for
++; your windows 95/98 clients, so uncomment the
++; following:
++; logon script =%U.bat
++; domain logons = yes
++; domain master = yes
++; [netlogon]
++; path = /netlogon
++
++
++[homes]
++ comment = Heimatverzeichnis
++ browseable = no
++ read only = no
++ create mode = 0750
++
++; The following share gives all users access to the Server's CD drive,
++; assuming it is mounted under /cd. To enable this share, please remove
++; the semicolons before the lines
++;
++; [cdrom]
++; comment = Linux CD-ROM
++; path = /cdrom
++; read only = yes
++; locking = no
++
++[printers]
++ comment = All Printers
++ browseable = no
++ printable = yes
++ public = no
++ read only = yes
++ create mode = 0700
++ directory = /tmp
+--- smbfs
++++ smbfs 2000/08/28 07:32:33
+@@ -0,0 +1,40 @@
++#! /bin/bash
++# Copyright (c) 1996 SuSE GmbH Nuernberg, Germany. All rights reserved.
++#
++# Author: Thomas Fehr <fehr@suse.de>, 1999
++#
++# /sbin/init.d/smbfs
++#
++
++smbfs=no
++if [ `cat /proc/mounts | grep " smbfs " | wc -l` -gt 0 ]
++then
++ smbfs=yes
++fi
++
++return=$rc_done
++case "$1" in
++ start|reload)
++ ;;
++ stop)
++ if [ "$smbfs" = "yes" ]
++ then
++ echo -n "Remove SMB File System"
++ #
++ # Unmount in background because during long timeouts
++ #
++ umount -at smbfs &
++ sleep 2
++ echo -e "$return"
++ fi
++ ;;
++ restart)
++ $0 stop && $0 start || return=$rc_failed
++ ;;
++ status)
++ ;;
++ *)
++ echo "Usage: $0 {start|stop|status|reload|restart}"
++ exit 1
++esac
++exit 0
+--- smbpasswd
++++ smbpasswd 2000/08/28 07:32:33
+@@ -0,0 +1,3 @@
++# Sample smbpasswd file.
++# To use this, set 'encrypt passwords = yes' in the [global]-section
++# of /etc/smb.conf
diff --git a/packaging/SuSE/7.1/samba.pamd b/packaging/SuSE/7.1/samba.pamd
new file mode 100644
index 00000000000..d9e7088bea3
--- /dev/null
+++ b/packaging/SuSE/7.1/samba.pamd
@@ -0,0 +1,3 @@
+#%PAM-1.0
+auth required /lib/security/pam_unix.so
+account required /lib/security/pam_unix.so
diff --git a/packaging/SuSE/7.1/samba.spec b/packaging/SuSE/7.1/samba.spec
new file mode 100644
index 00000000000..60d8099edbf
--- /dev/null
+++ b/packaging/SuSE/7.1/samba.spec
@@ -0,0 +1,381 @@
+#
+# spec file for package samba (Version 2.0.7)
+#
+# Copyright (c) 2000 SuSE GmbH Nuernberg, Germany.
+#
+# please send bugfixes or comments to feedback@suse.de.
+#
+
+# neededforbuild automake openldap
+# usedforbuild aaa_base aaa_dir autoconf automake base bash bindutil binutils bison bzip compress cpio cracklib devs diff ext2fs file fileutil find flex gawk gcc gdbm gettext gpm gppshare groff gzip kbd less libc libtool libz lx_suse make mktemp modules ncurses net_tool netcfg nkita nkitb nssv1 openldap pam patch perl pgp ps rcs rpm sendmail sh_utils shadow shlibs strace syslogd sysvinit texinfo textutil timezone unzip util vim xdevel xf86 xshared
+
+Vendor: SuSE GmbH, Nuernberg, Germany
+Distribution: SuSE Linux 7.1a (i386)
+Name: samba
+Release: 0
+Packager: feedback@suse.de
+
+Copyright: 1992-95 Andrew Tridgell, Karl Auer, Jeremy Allison
+Group: Networking/Daemons
+Url: http://www.samba.org
+Provides: samba smbfs
+Requires: smbclnt
+Autoreqprov: on
+Version: 2.2
+Summary: An SMB file server for Unix
+Source: samba-2.2.0-alpha0.tar.gz
+Source1: samba.pamd
+Patch: samba-2.2.0-alpha0.dif
+%package -n smbclnt
+Summary: Samba client utilities
+Autoreqprov: on
+Group: Networking
+%prep
+%setup -n samba-2.2.0-alpha0
+%patch
+
+%build
+cd source
+%{?suse_update_config:%{suse_update_config -f}}
+LIBS=-lnsl \
+./configure --prefix=/usr --libdir=/etc \
+ --with-privatedir=/etc --localstatedir=/var/log \
+ --with-smbmount --with-pam \
+ --mandir=%{_mandir} \
+ --with-swatdir=/usr/lib/samba/swat \
+ --with-sambabook=/usr/lib/samba/swat/using_samba
+cd ..
+make LOCKDIR=/var/lock/samba SBINDIR=/usr/sbin \
+ CODEPAGEDIR=/usr/lib/samba/codepages -C source
+
+%install
+mkdir -p /usr/lib/samba
+make install LOCKDIR=/var/lock/samba SBINDIR=/usr/sbin \
+ CODEPAGEDIR=/usr/lib/samba/codepages -C source
+# cleanup docs
+rm -rf docs/*.[0-9]
+chmod 644 `find docs examples -type f`
+chmod 755 `find docs examples -type d`
+#utility scripts
+mkdir -p /usr/lib/samba/scripts
+cp -a source/script/* /usr/lib/samba/scripts
+# configuration files
+install -m 644 smb.conf /etc/smb.conf
+install -m 644 lmhosts /etc/lmhosts
+install -m 600 smbpasswd -o root -g root /etc/smbpasswd
+install -d 755 /etc/pam.d
+install -m 644 $RPM_SOURCE_DIR/samba.pamd /etc/pam.d/samba
+install -m 755 mount.smbfs /sbin/mount.smbfs
+# start script
+install rc /sbin/init.d/smb
+ln -sf ../smb /sbin/init.d/rc2.d/S20smb
+ln -sf ../smb /sbin/init.d/rc2.d/K20smb
+ln -sf ../smb /sbin/init.d/rc3.d/S20smb
+ln -sf ../smb /sbin/init.d/rc3.d/K20smb
+ln -sf ../../sbin/init.d/smb /usr/sbin/rcsmb
+install smbfs /sbin/init.d/smbfs
+ln -sf ../smbfs /sbin/init.d/rc2.d/S21smbfs
+ln -sf ../smbfs /sbin/init.d/rc2.d/K19smbfs
+ln -sf ../smbfs /sbin/init.d/rc3.d/S21smbfs
+ln -sf ../smbfs /sbin/init.d/rc3.d/K19smbfs
+ln -sf ../../sbin/init.d/smbfs /usr/sbin/rcsmbfs
+# rc.config fragment
+mkdir -p /var/adm/fillup-templates
+cp rc.config.samba /var/adm/fillup-templates
+%{?suse_check}
+
+%post
+echo "Updating etc/rc.config..."
+if [ -x bin/fillup ] ; then
+ bin/fillup -q -d = etc/rc.config var/adm/fillup-templates/rc.config.samba
+else
+ echo "ERROR: fillup not found. This should not happen. Please compare"
+ echo "etc/rc.config and var/adm/fillup-templates/rc.config.samba and"
+ echo "update by hand."
+fi
+if grep -q '^[#[:space:]]*swat' etc/inetd.conf ; then
+ echo /etc/inetd.conf is up to date
+else
+ echo updating inetd.conf
+ cat >> etc/inetd.conf << EOF
+# swat is the Samba Web Administration Tool
+swat stream tcp nowait.400 root /usr/sbin/swat swat
+EOF
+fi
+if grep -q '^swat' etc/services ; then
+ echo /etc/services is up to date
+else
+ echo updating services
+ cat >> etc/services << EOF
+swat 901/tcp # swat is the Samba Web Administration Tool
+EOF
+fi
+mkdir -p var/adm/notify/messages
+cat << EOF > var/adm/notify/messages/samba-notify
+Achtung!
+========
+Die Syntax des smbmount Kommandos hat sich geaendert!
+smbmount kann nicht mehr direkt aufgerufen werden. Es wird von einem
+Shellscript /sbin/mount.smbfs aufgerufen, welches wiederum von mount
+aufgerufen wird.
+Hier ein Beispielaufruf:
+mount -t smbfs -o username=uname,password=passwd //smbserv/share /destination
+*****************************************************************************
+Attention!
+==========
+The syntax of smbmount has changed!
+smbmount can not be called direct anymore. It will be called by a shell
+script /sbin/mount.smbfs, which will be called by mount.
+A sample call to smbfs:
+mount -t smbfs -o username=uname,password=passwd //smbserv/share /destination
+EOF
+
+%files
+%config(noreplace) /etc/smb.conf
+%config(noreplace) /etc/lmhosts
+%config(noreplace) /etc/smbpasswd
+%config /etc/pam.d/samba
+/usr/lib/samba
+/sbin/init.d/rc2.d/K20smb
+/sbin/init.d/rc2.d/S20smb
+/sbin/init.d/rc3.d/K20smb
+/sbin/init.d/rc3.d/S20smb
+%config /sbin/init.d/smb
+/usr/bin/addtosmbpass
+/usr/bin/convert_smbpasswd
+/usr/bin/make_printerdef
+/usr/bin/make_smbcodepage
+/usr/bin/make_unicodemap
+/usr/bin/smbpasswd
+/usr/bin/smbstatus
+/usr/bin/testparm
+/usr/bin/testprns
+%doc docs/* examples
+%doc %{_mandir}/man1/make_smbcodepage.1.gz
+%doc %{_mandir}/man1/make_unicodemap.1.gz
+%doc %{_mandir}/man1/smbrun.1.gz
+%doc %{_mandir}/man1/smbsh.1.gz
+%doc %{_mandir}/man1/smbstatus.1.gz
+%doc %{_mandir}/man1/testparm.1.gz
+%doc %{_mandir}/man1/testprns.1.gz
+%doc %{_mandir}/man5/lmhosts.5.gz
+%doc %{_mandir}/man5/smb.conf.5.gz
+%doc %{_mandir}/man5/smbpasswd.5.gz
+%doc %{_mandir}/man7/samba.7.gz
+%doc %{_mandir}/man8/nmbd.8.gz
+%doc %{_mandir}/man8/smbd.8.gz
+%doc %{_mandir}/man8/smbpasswd.8.gz
+%doc %{_mandir}/man8/swat.8.gz
+/usr/sbin/nmbd
+/usr/sbin/rcsmb
+/usr/sbin/smbd
+/usr/sbin/swat
+/var/adm/fillup-templates/rc.config.samba
+
+%files -n smbclnt
+/sbin/init.d/rc2.d/K19smbfs
+/sbin/init.d/rc2.d/S21smbfs
+/sbin/init.d/rc3.d/K19smbfs
+/sbin/init.d/rc3.d/S21smbfs
+%config /sbin/init.d/smbfs
+/usr/sbin/rcsmbfs
+/sbin/mount.smbfs
+/usr/bin/nmblookup
+/usr/bin/rpcclient
+/usr/bin/smbclient
+/usr/bin/smbmnt
+/usr/bin/smbmount
+/usr/bin/smbumount
+/usr/bin/smbspool
+/usr/bin/smbtar
+%doc %{_mandir}/man1/nmblookup.1.gz
+%doc %{_mandir}/man1/smbclient.1.gz
+%doc %{_mandir}/man1/smbtar.1.gz
+%doc %{_mandir}/man8/smbmnt.8.gz
+%doc %{_mandir}/man8/smbmount.8.gz
+%doc %{_mandir}/man8/smbspool.8.gz
+%doc %{_mandir}/man8/smbumount.8.gz
+
+%description
+Samba is a suite of programs which work together to allow clients to
+access Unix filespace and printers via the SMB protocol (Server Message
+Block).
+In practice, this means that you can redirect disks and printers to
+Unix disks and printers from LAN Manager clients, Windows for
+Workgroups 3.11 clients, Windows'95 clients, Windows NT clients
+and OS/2 clients. There is
+also a Unix client program supplied as part of the suite which allows
+Unix users to use an ftp-like interface to access filespace and
+printers on any other SMB server.
+Samba includes the following programs (in summary):
+* smbd, the SMB server. This handles actual connections from clients.
+* nmbd, the Netbios name server, which helps clients locate servers.
+* smbclient, the Unix-hosted client program.
+* smbrun, a little 'glue' program to help the server run external
+programs.
+* testprns, a program to test server access to printers.
+* testparm, a program to test the Samba configuration file for correctness.
+* smb.conf, the Samba configuration file.
+* smbprint, a sample script to allow a Unix host to use smbclient
+to print to an SMB server.
+The suite is supplied with full source and is GPLed.
+This package expects its config file under /etc/smb.conf .
+
+Authors:
+--------
+ Andrew Tridgell <Andrew.Tridgell@anu.edu.au>
+ Karl Auer <Karl.Auer@anu.edu.au>
+ Jeremy Allison <jeremy@netcom.com>
+
+SuSE series: n
+
+
+%description -n smbclnt
+This package contains all programs, that are needed to act as a samba
+client. This includes also smbmount, of course.
+
+Authors:
+--------
+ Andrew Tridgell <Andrew.Tridgell@anu.edu.au>
+ Karl Auer <Karl.Auer@anu.edu.au>
+ Jeremy Allison <jeremy@netcom.com>
+
+SuSE series: n
+
+
+%changelog -n samba
+* Mon Aug 28 2000 - choeger@suse.de
+- changed $* to "$@" in mount.smbfs to make it also
+ possible to mount shares with spaces
+* Mon Jul 31 2000 - choeger@suse.de
+- improvement for rcsmb
+- fix for spec-file to compile with NIS netgroups
+* Thu Jul 20 2000 - choeger@suse.de
+- added smbfs initscript that has been removed
+ by an error
+* Tue Jul 11 2000 - choeger@suse.de
+- split package into client and server parts
+ client package name: smbclnt
+* Wed Apr 26 2000 - choeger@suse.de
+- new version, 2.0.7
+* Thu Apr 06 2000 - ro@suse.de
+- removed pam,cracklib from neededforbuild: build handles this
+* Wed Apr 05 2000 - bk@suse.de
+- s390 team added config.{sub,guess} update macro for s390
+* Mon Mar 27 2000 - choeger@suse.de
+- fixed bug in specfile
+ the multilined configure call missed a "" :-(
+* Thu Mar 09 2000 - choeger@suse.de
+- fixed typo in specfile
+* Wed Mar 01 2000 - choeger@suse.de
+- added %{_mandir}
+* Tue Feb 08 2000 - choeger@suse.de
+- removed /sbin/init.d/smbfs because it is no longer needed
+* Mon Jan 03 2000 - choeger@suse.de
+- bugfix for ipc.c
+ to make roaming profiles work again.
+* Tue Nov 30 1999 - choeger@suse.de
+- changed kernel oplocks = off to
+ kernel oplocks = false
+* Tue Nov 16 1999 - choeger@suse.de
+- added kernel oplocks = off in smb.conf
+* Fri Nov 12 1999 - choeger@suse.de
+- new version, 2.0.6
+* Fri Nov 05 1999 - choeger@suse.de
+- Fix for the smbmount lost-connection problem
+ _seems_ to work...
+* Fri Oct 29 1999 - choeger@suse.de
+- removed comment sign in /etc/inetd.conf for swat
+* Mon Sep 13 1999 - bs@suse.de
+- ran old prepare_spec on spec file to switch to new prepare_spec.
+* Tue Aug 10 1999 - fehr@suse.de
+- set execute permissions for mksmbpasswd.sh and changesmbpasswd.sh
+* Thu Jul 29 1999 - fehr@suse.de
+- fixed typo in /sbin/init.d/smbfs
+* Thu Jul 22 1999 - fehr@suse.de
+- changed to new version 2.0.5a
+* Wed Jul 21 1999 - fehr@suse.de
+- changed to new version 2.0.5
+* Tue Jul 20 1999 - fehr@suse.de
+- install /sbin/init.d/smbfs
+- changed to new version 2.0.5pre4
+* Mon Jul 19 1999 - fehr@suse.de
+- add /sbin/init.d/smbfs
+- changed to new version 2.0.5pre3
+* Fri Jul 02 1999 - fehr@suse.de
+- removed "umount -a -t smbfs" from start sscript
+* Tue Jun 22 1999 - kukuk@suse.de
+- 2.0.4b changed default values, enable PAM again
+* Fri Jun 18 1999 - kukuk@suse.de
+- changed to new version 2.0.4b
+* Mon Jun 14 1999 - kukuk@suse.de
+- Enable PAM, add samba.pamd
+* Mon May 03 1999 - fehr@suse.de
+- add umount -a -t smbfs to shutdown sequence of samba
+* Thu Mar 11 1999 - ro@suse.de
+- smbmount: define NR_OPEN to 1024 if undefined (GLIBC-2.1)
+* Wed Mar 10 1999 - choeger@suse.de
+- some enhancements for smb.conf
+* Wed Mar 10 1999 - choeger@suse.de
+- new version 2.0.3 and smbmount now seems to work
+* Tue Mar 09 1999 - ro@suse.de
+- use samba-2.0.2 for STABLE
+- use smbfs-2.1 with kernel 2.2.2
+* Sun Feb 28 1999 - ro@suse.de
+- for glibc-2.1 strncat uses strcat for one subcase, so don't
+ redefine strcat to "ERROR" for glibc-2.1
+* Mon Feb 15 1999 - fehr@suse.de
+- fix for umount problem from Volker
+* Tue Feb 09 1999 - fehr@suse.de
+- changed to version 2.0.2 of samba
+* Fri Jan 15 1999 - bs@suse.de
+- replaced /sbin/init.d/smb with newer style version (again)
+* Fri Jan 15 1999 - fehr@suse.de
+- switched to new version 2.0.0
+* Wed Jan 13 1999 - bs@suse.de
+- fixed entry in inetd.conf
+* Wed Jan 13 1999 - bs@suse.de
+- replaced /sbin/init.d/smb with newer style version
+* Mon Jan 11 1999 - vl@suse.de
+- make 2.0.0beta5 package of samba
+* Mon Aug 24 1998 - vl@suse.de
+- changed to version 1.9.18p10
+* Mon Jun 29 1998 - vl@suse.de
+- changed to version 1.9.18p8
+* Mon Apr 20 1998 - vl@suse.de
+- changed to version 1.9.18p4
+* Thu Feb 19 1998 - vl@suse.de
+- changed to version 1.9.18p3
+* Tue Feb 03 1998 - vl@suse.de
+- changed to version 1.9.18p2
+- fixed some problems in spec-file, some files were missing :-(
+- fixed smbfs-2.0.2/Makefile.Linux
+* Tue Jan 13 1998 - vl@suse.de
+- changed to version 1.9.18p1
+* Fri Jan 09 1998 - vl@suse.de
+- changed to version 1.9.18
+* Tue Dec 02 1997 - bs@suse.de
+- disable samba by default in /etc/rc.config
+* Mon Oct 06 1997 - fehr@suse.de
+- package prepared for automatic building
+* Mon Sep 29 1997 - fehr@suse.de
+- updated to version 1.9.17p2 due to security hole.
+* Wed Jul 16 1997 - fehr@suse.de
+- add fillup-template for rc.config and install it in doinst.sh
+* Fri Jun 27 1997 - bs@suse.de
+- update to smbfs-2.0.2, due to security hole.
+* Tue Jun 17 1997 - fehr@suse.de
+- changed init-skript to recognize entry START_SMB of rc.config
+* Mon Jun 02 1997 - vl@suse.de
+- update to version 1.9.16p11
+- Starting Samba from /sbin/init.d, not from inetd.conf
+* Sun Feb 02 1997 - vl@suse.de
+- update to version 1.9.16p10
+- Adapted /etc/smb.conf.sample to 4.4.1 manual
+* Thu Jan 02 1997 - florian@suse.de
+- update to version 1.9.16p9
+- configuration file is now /etc/smb.conf
+- smbd and nmbd are now in /usr/sbin
+- added start-script /sbin/init.d/smb and entry in /etc/rc.config
+* Thu Jan 02 1997 - florian@suse.de
+- Update auf neue Version 1.9.16p6.
diff --git a/packaging/bin/update-pkginfo b/packaging/bin/update-pkginfo
new file mode 100755
index 00000000000..8432173cc88
--- /dev/null
+++ b/packaging/bin/update-pkginfo
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+VERSION=$1
+RELEASE=$2
+
+if [ $# -ne 2 ]; then
+ echo Usage: update-pkginfo VERSION RELEASE
+ exit 1
+fi
+
+for f in */*/*.tmpl; do
+ f2=`echo $f | sed s/.tmpl//g`
+ echo $f2
+ sed -e s/PVERSION/$VERSION/g -e s/PRELEASE/$RELEASE/g < $f > $f2
+done
+for f in */*.tmpl; do
+ f2=`echo $f | sed s/.tmpl//g`
+ echo $f2
+ sed -e s/PVERSION/$VERSION/g -e s/PRELEASE/$RELEASE/g < $f > $f2
+done
diff --git a/pcp/Install b/pcp/Install
new file mode 100755
index 00000000000..c2087fc01e3
--- /dev/null
+++ b/pcp/Install
@@ -0,0 +1,64 @@
+#! /bin/sh
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+# Install the samba PMDA and/or PMNS
+#
+
+# source the PCP configuration environment variables
+. /etc/pcp.env
+
+# Get the common procedures and variable assignments
+#
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+# The name of the PMDA
+#
+iam=samba
+
+# override interactive dialog from pmdaproc.sh
+#
+__choose_mode()
+{
+ echo "Installing the \"$iam\" Performance Metrics Domain Agent (PMDA) ..."
+ echo
+}
+
+# Using libpcp_pmda.so.2 and PMDA_INTERFACE_2
+#
+pmda_interface=2
+
+# Do it
+#
+pmdaSetup
+pmdaInstall
+
+exit 0
diff --git a/pcp/Makefile b/pcp/Makefile
new file mode 100644
index 00000000000..e01731b2565
--- /dev/null
+++ b/pcp/Makefile
@@ -0,0 +1,69 @@
+#!make
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+SHELL = sh
+
+include /etc/pcp.conf
+
+IAM = samba
+CFILES = $(IAM).c
+
+LIBTARGET = pmda_$(IAM).so
+CMDTARGET = pmda$(IAM)
+TARGETS = $(LIBTARGET) $(CMDTARGET)
+
+DEBUG = -DDEBUG
+CFLAGS = $(DEBUG)
+LDOPTS =
+LDLIBS = -lpcp_pmda -lpcp
+DSOOPTS = -shared
+LDIRT = metrics.h so_locations *.log help.dir help.pag *.pmda_$(IAM).so
+
+INSTALL = install
+CC = cc
+
+default: $(TARGETS)
+
+install: default
+
+$(CMDTARGET): profile.h metrics.h $(CFILES)
+ $(CC) $(CFLAGS) $(CFILES) $(LDOPTS) $(LDLIBS) -o $@
+
+$(LIBTARGET): profile.h metrics.h $(CFILES)
+ $(CC) $(CFLAGS) $(DSOOPTS) $(LDOPTS) $(CFILES) $(LDLIBS) -o $@
+
+metrics.h: profile.h mkheader.pl
+ ./mkheader.pl
+
+clobber clean:
+ rm -f $(LDIRT) $(TARGETS)
diff --git a/pcp/README b/pcp/README
new file mode 100644
index 00000000000..97d8125a53e
--- /dev/null
+++ b/pcp/README
@@ -0,0 +1,94 @@
+samba PMDA
+===========
+
+This PMDA is a sample that illustrates how a simple samba monitor
+PMDA might be constructed, using a shared memory segment to transfer
+information about transaction activity from the smb daemon.
+
+Note:
+ This PMDA may be remade from source and hence requires
+ a C compiler and Perl to be installed.
+
+ Uses of make(1) may fail (without removing or clobbering files)
+ if the C compiler cannot be found. This is most likely to
+ happen when running the PMDA ./Install script.
+
+ The only remedial action is to install the C compiler, or
+ hand-craft changes to the Makefile.
+
+Metrics
+=======
+
+The file ./help contains descriptions for all of the metrics exported
+by this PMDA.
+
+Once the PMDA has been installed, the following command will list all
+the available metrics and their explanatory "help" text:
+
+ $ pminfo -fT samba
+
+Installation
+============
+
+ + # mkdir /var/pcp/pmdas/samba
+ + # cp * /var/pcp/pmdas/samba
+ + # cp ../source/include/profile.h /var/pcp/pmdas/samba
+ + # cd /var/pcp/pmdas/samba
+
+ + Check that there is no clash in the Performance Metrics Domain
+ defined in ./domain.h and the other PMDAs currently in use
+ (/etc/pmcd.conf). If there is, edit ./domain.h to choose another
+ domain number.
+
+ + If you are not installing on an IRIX system, edit samba.c and
+ comment out the
+
+ #define IRIX 1
+
+ + Then simply use
+
+ # ./Install
+
+ + Alternatively, to install just the Performance Metrics Name Space
+ for the samba metrics on the local system, but not the samba PMDA
+ (presumably because the local system is running PCP 1.x and you
+ wish to connect to a remote system where PCP 2.0 and the samba PMDA
+ is running), make sure the Performance Metrics Domain defined in
+ ./domain.h matches the domain chosen for the samba PMDA on the
+ remote system (check the second field in the corresponding line of
+ the pmcd.conf file on the remote system - located in /etc on IRIX
+ and /var/pcp/config/pmcd on Linux), then
+
+ # ./Install -N
+
+De-installation
+===============
+
+ + Simply use
+
+ # cd /var/pcp/pmdas/samba
+ # ./Remove
+
+ + If you also want to remove the sources use
+
+ # cd /
+ # rm -rf /var/pcp/pmdas/samba
+
+Making something happen
+=======================
+
+The application "smbd" updates the shared memory segment to add
+profile information about smbd. By default updating is disabled.
+To start updating of the shared memory segment you need to run the
+smbcontrol command to turn on profiling for one or more smbd processes
+(see the man page for smbcontrol).
+
+
+
+Troubleshooting
+===============
+
+ + After installing or restarting the agent, the PMCD log file
+ (pmcd.log) and the PMDA log file (samba.log) should be checked
+ for any warnings or errors. These logs are located in
+ /var/log/pcp/pmcd on Linux and /var/adm/pcplog on IRIX.
diff --git a/pcp/Remove b/pcp/Remove
new file mode 100755
index 00000000000..3f7434d2553
--- /dev/null
+++ b/pcp/Remove
@@ -0,0 +1,52 @@
+#! /bin/sh
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+# Remove the samba PMDA
+#
+
+# source the PCP configuration environment variables
+. /etc/pcp.env
+
+# Get the common procedures and variable assignments
+#
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+# The name of the PMDA
+#
+iam=samba
+
+# Do it
+#
+pmdaSetup
+pmdaRemove
+
+exit 0
diff --git a/pcp/domain.h b/pcp/domain.h
new file mode 100644
index 00000000000..3cf0bc6ce97
--- /dev/null
+++ b/pcp/domain.h
@@ -0,0 +1,4 @@
+/*
+ * built from /var/pcp/pmns/stdpmid
+ */
+#define SAMBA 123
diff --git a/pcp/help b/pcp/help
new file mode 100644
index 00000000000..dc3b02f03bd
--- /dev/null
+++ b/pcp/help
@@ -0,0 +1,77 @@
+#
+# samba PMDA help file in the ASCII format
+#
+# lines beginning with a # are ignored
+# lines beginning @ introduce a new entry of the form
+# @ metric_name oneline-text
+# help test goes
+# here over multiple lines
+# ...
+#
+# the metric_name is decoded against the default PMNS -- as a special case,
+# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an
+# instance domain identification, and the text describes the instance domain
+#
+# blank lines before the @ line are ignored
+#
+
+@ SAMBA.0 Count and Time Instance Domain
+Contains count and time information for system calls and smb transactions.
+Counts shows the number of times each transaction was called. Times
+indicates the time spent in each transaction.
+
+@ SAMBA.1 Byte Instance Domain
+This domain contains instances for the number of bytes transferred
+using the read and write system call.
+
+@ samba.counts Count of calls to this function
+
+@ samba.times Time required to complete call
+
+@ samba.bytes Number of bytes processed by this call
+
+@ samba.smbd.smb_count Count of SMB packets processed
+
+@ samba.smbd.uid_changes Count of times effective uid changed
+
+@ samba.statcache.lookups Number of lookups in stat cache
+
+@ samba.statcache.misses Number of times stat cache lookup missed
+
+@ samba.statcache.hits Number of times stat cache lookup hit
+
+@ samba.writecache.num_caches Number of write caches available
+
+@ samba.writecache.allocated_caches Number of write caches allocated
+
+@ samba.writecache.read_hits Number of times read request found in write cache
+
+@ samba.writecache.total_writes Number of writes to write cache
+
+@ samba.writecache.init_writes Number of initial writes to write cache
+
+@ samba.writecache.abutted_writes
+
+@ samba.writecache.perfect_writes
+
+@ samba.writecache.direct_writes
+
+@ samba.writecache.non_oplock_writes
+
+@ samba.writecache.seek_flush
+
+@ samba.writecache.read_flush
+
+@ samba.writecache.write_flush
+
+@ samba.writecache.readraw_flush
+
+@ samba.writecache.oplock_rel_flush
+
+@ samba.writecache.close_flush
+
+@ samba.writecache.sync_flush
+
+@ samba.writecache.size_change_flush
+
+@ samba.bytes cumulative number of bytes read or written
diff --git a/pcp/mkheader.pl b/pcp/mkheader.pl
new file mode 100755
index 00000000000..ad069c544a8
--- /dev/null
+++ b/pcp/mkheader.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+
+
+open(PROFILE,"profile.h") || die "Unable to open profile.h\n";
+@profile = <PROFILE>;
+close PROFILE;
+
+open(METRICS,"> metrics.h") || die "Unable to open metrics.h for output\n";
+
+print METRICS "#define COUNT_TIME_INDOM 0\n";
+print METRICS "#define BYTE_INDOM 1\n\n";
+print METRICS "#define FIELD_OFF(x) (unsigned)\&(((struct profile_stats *)NULL)->x)\n\n";
+print METRICS "typedef struct {\n";
+print METRICS "\tchar *name;\n";
+print METRICS "\tunsigned offset;\n";
+print METRICS "} samba_instance;\n\n";
+
+@instnames = grep(/unsigned .*_time;/,@profile);
+foreach $instnames (@instnames) {
+ chomp $instnames;
+ $instnames =~ s/^.*unsigned (.*)_time.*$/$1/;
+}
+
+print METRICS "static samba_instance samba_counts[] = {";
+$first = 1;
+foreach $1 (@instnames) {
+ if ($first == 1) {
+ $first = 0;
+ print METRICS "\n";
+ } else {
+ print METRICS ",\n";
+ }
+ print METRICS "\t{\"$1\", FIELD_OFF($1_count)}";
+}
+print METRICS "\n};\n\n";
+print METRICS "static samba_instance samba_times[] = {";
+$first = 1;
+foreach $1 (@instnames) {
+ if ($first == 1) {
+ $first = 0;
+ print METRICS "\n";
+ } else {
+ print METRICS ",\n";
+ }
+ print METRICS "\t{\"$1\", FIELD_OFF($1_time)}";
+}
+print METRICS "\n};\n\n";
+print METRICS "static samba_instance samba_bytes[] = {";
+@instnames = grep(/unsigned .*_bytes;/,@profile);
+$first = 1;
+foreach $_ (@instnames) {
+ if ($first == 1) {
+ $first = 0;
+ print METRICS "\n";
+ } else {
+ print METRICS ",\n";
+ }
+ /^.*unsigned (.*)_bytes.*$/;
+ print METRICS "\t{\"$1\", FIELD_OFF($1_bytes)}";
+}
+print METRICS "\n};\n";
+
+close METRICS
diff --git a/pcp/pmns b/pcp/pmns
new file mode 100644
index 00000000000..1f3dd3934ee
--- /dev/null
+++ b/pcp/pmns
@@ -0,0 +1,45 @@
+/*
+ * Metrics for samba PMDA
+ *
+ */
+
+samba {
+ smbd
+ statcache
+ writecache
+ counts SAMBA:3:0
+ times SAMBA:4:0
+ bytes SAMBA:5:0
+}
+
+samba.smbd {
+ smb_count SAMBA:0:0
+ uid_changes SAMBA:0:1
+}
+
+samba.statcache {
+ lookups SAMBA:1:0
+ misses SAMBA:1:1
+ hits SAMBA:1:2
+}
+
+samba.writecache {
+ num_caches SAMBA:2:0
+ allocated_caches SAMBA:2:1
+ read_hits SAMBA:2:2
+ total_writes SAMBA:2:3
+ init_writes SAMBA:2:4
+ abutted_writes SAMBA:2:5
+ perfect_writes SAMBA:2:6
+ direct_writes SAMBA:2:7
+ non_oplock_writes SAMBA:2:8
+ seek_flush SAMBA:2:9
+ read_flush SAMBA:2:10
+ write_flush SAMBA:2:11
+ readraw_flush SAMBA:2:12
+ oplock_rel_flush SAMBA:2:13
+ close_flush SAMBA:2:14
+ sync_flush SAMBA:2:15
+ size_change_flush SAMBA:2:16
+}
+
diff --git a/pcp/root b/pcp/root
new file mode 100644
index 00000000000..d5137bc7ddd
--- /dev/null
+++ b/pcp/root
@@ -0,0 +1,10 @@
+/*
+ * fake "root" for validating the local PMNS subtree
+ */
+
+#include "/var/pcp/pmns/stdpmid"
+
+root { samba }
+
+#include "pmns"
+
diff --git a/pcp/samba.c b/pcp/samba.c
new file mode 100644
index 00000000000..07a6ce2e169
--- /dev/null
+++ b/pcp/samba.c
@@ -0,0 +1,390 @@
+/*
+ * Samba, configurable PMDA
+ *
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+typedef int BOOL;
+
+#define IRIX 1
+
+#include <stdio.h>
+#include <sys/shm.h>
+#include <pcp/pmapi.h>
+#ifdef IRIX
+#include <pcp/impl.h>
+#endif
+#include <pcp/pmda.h>
+#include "domain.h"
+#include "profile.h"
+#include "metrics.h"
+
+static pmdaInstid *counttime = NULL;
+static pmdaInstid *bytes = NULL;
+
+/*
+ * List of instance domains
+ */
+
+static pmdaIndom indomtab[] = {
+ {COUNT_TIME_INDOM,0,NULL},
+ {BYTE_INDOM,0,NULL}
+};
+/*
+ * all metrics supported in this PMDA - one table entry for each
+ */
+
+static pmdaMetric metrictab[] = {
+/* smbd.smb_count */
+ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* smbd.uid_changes */
+ { NULL, { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* statcache.lookups */
+ { NULL, { PMDA_PMID(1,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* statcache.misses */
+ { NULL, { PMDA_PMID(1,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* statcache.hits */
+ { NULL, { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.num_caches */
+ { NULL, { PMDA_PMID(2,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.allocated_caches */
+ { NULL, { PMDA_PMID(2,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.read_hits */
+ { NULL, { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.total_writes */
+ { NULL, { PMDA_PMID(2,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.init_writes */
+ { NULL, { PMDA_PMID(2,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.abutted_writes */
+ { NULL, { PMDA_PMID(2,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.perfect_writes */
+ { NULL, { PMDA_PMID(2,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.direct_writes */
+ { NULL, { PMDA_PMID(2,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.non_oplock_writes */
+ { NULL, { PMDA_PMID(2,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.seek_flush */
+ { NULL, { PMDA_PMID(2,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.read_flush */
+ { NULL, { PMDA_PMID(2,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.write_flush */
+ { NULL, { PMDA_PMID(2,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.readraw_flush */
+ { NULL, { PMDA_PMID(2,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.oplock_rel_flush */
+ { NULL, { PMDA_PMID(2,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.close_flush */
+ { NULL, { PMDA_PMID(2,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.sync_flush */
+ { NULL, { PMDA_PMID(2,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* writecache.size_change_flush */
+ { NULL, { PMDA_PMID(2,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* counts instance domain */
+ { NULL, { PMDA_PMID(3,0), PM_TYPE_U32, COUNT_TIME_INDOM, PM_SEM_COUNTER,
+ { 0,0,1,0,0,PM_COUNT_ONE} }, },
+/* times instance domain */
+ { NULL, { PMDA_PMID(4,0), PM_TYPE_U32, COUNT_TIME_INDOM, PM_SEM_COUNTER,
+ { 0,1,0,0,PM_TIME_USEC,0} }, },
+/* bytes instance domain */
+ { NULL, { PMDA_PMID(5,0), PM_TYPE_U32, BYTE_INDOM, PM_SEM_COUNTER,
+ { 1,0,0,PM_SPACE_BYTE,0,0} }, }
+
+};
+
+extern int errno;
+struct profile_stats *stats;
+struct profile_header *shmheader;
+int shmid = -1;
+
+
+int
+samba_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
+{
+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid);
+
+
+ if (inst != PM_IN_NULL && mdesc->m_desc.indom == PM_INDOM_NULL)
+ return PM_ERR_INST;
+
+ if (idp->cluster == 0) {
+ switch (idp->item) {
+ case 0: /* smbd.smb_count */
+ atom->ul = stats->smb_count;
+ break;
+ case 1: /* smb.uid_changes */
+ atom->ul = stats->uid_changes;
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ }
+ else if (idp->cluster == 1) { /* statcache */
+ switch (idp->item) {
+ case 0: /* statcache.lookups */
+ atom->ul = stats->statcache_lookups;
+ break;
+ case 1: /* statcache.misses */
+ atom->ul = stats->statcache_misses;
+ break;
+ case 2: /* statcache.hits */
+ atom->ul = stats->statcache_hits;
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ }
+ else if (idp->cluster == 2) { /* writecache */
+ switch (idp->item) {
+ case 0: /* writecache.num_caches */
+ atom->ul = stats->writecache_num_write_caches;
+ break;
+ case 1: /* writecache.allocated_caches */
+ atom->ul = stats->writecache_allocated_write_caches;
+ break;
+ case 2: /* writecache.read_hits */
+ atom->ul = stats->writecache_read_hits;
+ break;
+ case 3: /* writecache.total_writes */
+ atom->ul = stats->writecache_total_writes;
+ break;
+ case 4: /* writecache.init_writes */
+ atom->ul = stats->writecache_init_writes;
+ break;
+ case 5: /* writecache.abutted_writes */
+ atom->ul = stats->writecache_abutted_writes;
+ break;
+ case 6: /* writecache.perfect_writes */
+ atom->ul = stats->writecache_num_perfect_writes;
+ break;
+ case 7: /* writecache.direct_writes */
+ atom->ul = stats->writecache_direct_writes;
+ break;
+ case 8: /* writecache.non_oplock_writes */
+ atom->ul = stats->writecache_non_oplock_writes;
+ break;
+ case 9: /* writecache.seek_flush */
+ atom->ul = stats->writecache_flushed_writes[SEEK_FLUSH];
+ break;
+ case 10: /* writecache.read_flush */
+ atom->ul = stats->writecache_flushed_writes[READ_FLUSH];
+ break;
+ case 11: /* writecache.write_flush */
+ atom->ul = stats->writecache_flushed_writes[WRITE_FLUSH];
+ break;
+ case 12: /* writecache.readraw_flush */
+ atom->ul = stats->writecache_flushed_writes[READRAW_FLUSH];
+ break;
+ case 13: /* writecache.oplock_rel_flush */
+ atom->ul = stats->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH];
+ break;
+ case 14: /* writecache.close_flush */
+ atom->ul = stats->writecache_flushed_writes[CLOSE_FLUSH];
+ break;
+ case 15: /* writecache.sync_flush */
+ atom->ul = stats->writecache_flushed_writes[SYNC_FLUSH];
+ break;
+ case 16: /* writecache.size_change_flush */
+ atom->ul = stats->writecache_flushed_writes[SIZECHANGE_FLUSH];
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ }
+ else if (idp->cluster == 3) { /* counts */
+ if (idp->item == 0) {
+ if (inst < indomtab[COUNT_TIME_INDOM].it_numinst) {
+ unsigned *p;
+
+ p = (unsigned *)((unsigned)stats + samba_counts[inst].offset);
+ atom->ul = *p;
+ }
+ else
+ return PM_ERR_INST;
+ }
+ else
+ return PM_ERR_PMID;
+ }
+ else if (idp->cluster == 4) { /* times */
+ if (idp->item == 0) {
+ if (inst < indomtab[COUNT_TIME_INDOM].it_numinst) {
+ unsigned *p;
+
+ p = (unsigned *)((unsigned)stats + samba_times[inst].offset);
+ atom->ul = *p;
+ }
+ else
+ return PM_ERR_INST;
+ }
+ else
+ return PM_ERR_PMID;
+ }
+ else if (idp->cluster == 5) { /* bytes */
+ if (idp->item == 0) {
+ if (inst < indomtab[BYTE_INDOM].it_numinst) {
+ unsigned *p;
+
+ p = (unsigned *)((unsigned)stats + samba_bytes[inst].offset);
+ atom->ul = *p;
+ }
+ else
+ return PM_ERR_INST;
+ }
+ else
+ return PM_ERR_PMID;
+ }
+ else
+ return PM_ERR_PMID;
+ return 0;
+}
+
+
+void
+samba_init(pmdaInterface *dp)
+{
+ int inst_count, i;
+
+ if (dp->status != 0)
+ return;
+
+ if ((shmid = shmget(PROF_SHMEM_KEY, 0, 0)) == -1) {
+ fprintf(stderr, "shmid: %s\n", strerror(errno));
+ fprintf(stderr, "samba not compiled with profile support or not running\n");
+ exit(1);
+ }
+ shmheader = (struct profile_header *)shmat(shmid, NULL, SHM_RDONLY);
+ if ((int)shmheader == -1) {
+ fprintf(stderr, "shmat: %s\n", strerror(errno));
+ exit(1);
+ }
+
+/*
+ * Initialize lists of instances
+ */
+
+ inst_count = sizeof(samba_counts)/sizeof(samba_counts[0]);
+ counttime = (pmdaInstid *)malloc(inst_count * sizeof(pmdaInstid));
+ if (counttime == NULL) {
+ __pmNoMem("count&time",inst_count * sizeof(pmdaInstid),PM_FATAL_ERR);
+ /* NOTREACHED*/
+ }
+ for (i = 0; i < inst_count; i++) {
+ counttime[i].i_inst = i;
+ counttime[i].i_name = samba_counts[i].name;
+ }
+ indomtab[COUNT_TIME_INDOM].it_numinst = inst_count;
+ indomtab[COUNT_TIME_INDOM].it_set = counttime;
+
+ inst_count = sizeof(samba_bytes)/sizeof(samba_bytes[0]);
+ bytes = (pmdaInstid *)malloc(inst_count * sizeof(pmdaInstid));
+ if (bytes == NULL) {
+ __pmNoMem("bytes",inst_count * sizeof(pmdaInstid),PM_FATAL_ERR);
+ /* NOTREACHED*/
+ }
+ for (i = 0; i < inst_count; i++) {
+ bytes[i].i_inst = i;
+ bytes[i].i_name = samba_bytes[i].name;
+ }
+ indomtab[BYTE_INDOM].it_numinst = inst_count;
+ indomtab[BYTE_INDOM].it_set = bytes;
+
+
+ pmdaSetFetchCallBack(dp, samba_fetchCallBack);
+ pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]),
+ metrictab, sizeof(metrictab)/sizeof(metrictab[0]));
+
+ /* validate the data */
+ if (!shmheader) /* not mapped yet */
+ fprintf(stderr, "samba_init: shmem not mapped\n");
+ else if (shmheader->prof_shm_magic != PROF_SHM_MAGIC)
+ fprintf(stderr, "samba_init: bad magic\n");
+ else if (shmheader->prof_shm_version != PROF_SHM_VERSION)
+ fprintf(stderr, "samba_init: bad version %X\n",
+ shmheader->prof_shm_version);
+ else {
+ stats = &shmheader->stats;
+ return; /* looks OK */
+ }
+ exit(1);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int err = 0;
+ char *p;
+ pmdaInterface dispatch;
+
+ for (p = pmProgname = argv[0]; *p; p++)
+ if (*p == '/') pmProgname = p+1;
+
+ pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, SAMBA,
+ "samba.log", "/var/pcp/pmdas/samba/help");
+
+ if (pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err) != EOF) {
+ fprintf(stderr, "Usage: %s [options]\n\n\
+Options:\n\
+ -d domain use domain (numeric) for metrics domain of PMDA\n\
+ -l logfile write log into logfile rather than using default log name\n",
+ pmProgname);
+ exit(1);
+ }
+
+ pmdaOpenLog(&dispatch);
+ samba_init(&dispatch);
+ pmdaConnect(&dispatch);
+ pmdaMain(&dispatch);
+
+ exit(0);
+ /*NOTREACHED*/
+}
diff --git a/source/.cvsignore b/source/.cvsignore
new file mode 100644
index 00000000000..64f71dd86e2
--- /dev/null
+++ b/source/.cvsignore
@@ -0,0 +1,17 @@
+.headers.stamp
+.proto.stamp
+ID
+ID
+Makefile
+bin
+config.cache
+config.log
+config.status
+cvs.log
+dox
+libtool
+so_locations
+testdir
+testtmp
+*.po
+*.po32
diff --git a/source/CodingSuggestions b/source/CodingSuggestions
new file mode 100644
index 00000000000..48c51281f52
--- /dev/null
+++ b/source/CodingSuggestions
@@ -0,0 +1,143 @@
+/**
+
+@page CodingSuggestions Coding suggestions
+
+So you want to add code to Samba ...
+
+One of the daunting tasks facing a programmer attempting to write code for
+Samba is understanding the various coding conventions used by those most
+active in the project. These conventions were mostly unwritten and helped
+improve either the portability, stability or consistency of the code. This
+document will attempt to document a few of the more important coding
+practices used at this time on the Samba project. The coding practices are
+expected to change slightly over time, and even to grow as more is learned
+about obscure portability considerations. Two existing documents
+samba/source/internals.doc and samba/source/architecture.doc provide
+additional information.
+
+The loosely related question of coding style is very personal and this
+document does not attempt to address that subject, except to say that I
+have observed that eight character tabs seem to be preferred in Samba
+source. If you are interested in the topic of coding style, two oft-quoted
+documents are:
+
+ http://lxr.linux.no/source/Documentation/CodingStyle
+ http://www.fsf.org/prep/standards_toc.html
+
+but note that coding style in Samba varies due to the many different
+programmers who have contributed.
+
+Following are some considerations you should use when adding new code to
+Samba. First and foremost remember that:
+
+Portability is a primary consideration in adding function, as is network
+compatability with de facto, existing, real world CIFS/SMB implementations.
+There are lots of platforms that Samba builds on so use caution when adding
+a call to a library function that is not invoked in existing Samba code.
+Also note that there are many quite different SMB/CIFS clients that Samba
+tries to support, not all of which follow the SNIA CIFS Technical Reference
+(or the earlier Microsoft reference documents or the X/Open book on the SMB
+Standard) perfectly.
+
+Here are some other suggestions:
+
+1) use d_printf instead of printf for display text
+ reason: enable auto-substitution of translated language text
+
+2) use SAFE_FREE instead of free
+ reason: reduce traps due to null pointers
+
+3) don't use bzero use memset, or ZERO_STRUCT and ZERO_STRUCTP macros
+ reason: not POSIX
+
+4) don't use strcpy and strlen (use safe_* equivalents)
+ reason: to avoid traps due to buffer overruns
+
+5) don't use getopt_long, use popt functions instead
+ reason: portability
+
+6) explicitly add const qualifiers on parm passing in functions where parm
+ is input only (somewhat controversial but const can be #defined away)
+
+8) discourage use of threads
+ reason: portability (also see architecture.doc)
+
+9) don't explicitly include new header files in C files - new h files
+ should be included by adding them once to includes.h
+ reason: consistency
+
+10) don't explicitly extern functions (they are autogenerated by
+ "make proto" into proto.h)
+ reason: consistency
+
+11) use endian safe macros when unpacking SMBs (see byteorder.h and
+ internals.doc)
+ reason: not everyone uses Intel
+
+12) Note Unicode implications of charset handling (see internals.doc). See
+ pull_* and push_* and convert_string functions.
+ reason: Internationalization
+
+13) Don't assume English only
+ reason: See above
+
+14) Try to avoid using in/out parameters (functions that return data which
+ overwrites input parameters)
+ reason: Can cause stability problems
+
+15) Ensure copyright notices are correct, don't append Tridge's name to code
+ that he didn't write. If you did not write the code, make sure that it
+ can coexist with the rest of the Samba GPLed code.
+
+16) Consider usage of DATA_BLOBs for length specified byte-data.
+ reason: stability
+
+17) Take advantage of tdbs for database like function
+ reason: consistency
+
+18) Don't access the SAM_ACCOUNT structure directly, they should be accessed
+ via pdb_get...() and pdb_set...() functions.
+ reason: stability, consistency
+
+19) Don't check a password directly against the passdb, always use the
+ check_password() interface.
+ reason: long term pluggability
+
+20) Try to use asprintf rather than pstrings and fstrings where possible
+
+21) Use normal C comments / * instead of C++ comments // like
+ this. Although the C++ comment format is part of the C99
+ standard, some older vendor C compilers do not accept it.
+
+22) Try to write documentation for API functions and structures
+ explaining the point of the code, the way it should be used, and
+ any special conditions or results. Mark these with a double-star
+ comment start / ** so that they can be picked up by Doxygen, as in
+ this file.
+
+23) Keep the scope narrow. This means making functions/variables
+ static whenever possible. We don't want our namespace
+ polluted. Each module should have a minimal number of externally
+ visible functions or variables.
+
+24) Use function pointers to keep knowledge about particular pieces of
+ code isolated in one place. We don't want a particular piece of
+ functionality to be spread out across lots of places - that makes
+ for fragile, hand to maintain code. Instead, design an interface
+ and use tables containing function pointers to implement specific
+ functionality. This is particularly important for command
+ interpreters.
+
+25) Think carefully about what it will be like for someone else to add
+ to and maintain your code. If it would be hard for someone else to
+ maintain then do it another way.
+
+The suggestions above are simply that, suggestions, but the information may
+help in reducing the routine rework done on new code. The preceeding list
+is expected to change routinely as new support routines and macros are
+added.
+
+Written by Steve French, with contributions from Simo Sorce, Andrew
+Bartlett, Tim Potter and Martin Pool.
+
+**/
diff --git a/source/Doxyfile b/source/Doxyfile
new file mode 100644
index 00000000000..327f94fa243
--- /dev/null
+++ b/source/Doxyfile
@@ -0,0 +1,170 @@
+# Doxyfile 0.1
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = Samba
+PROJECT_NUMBER = HEAD
+OUTPUT_DIRECTORY = dox
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH = *source
+INTERNAL_DOCS = YES
+CLASS_DIAGRAMS = YES
+SOURCE_BROWSER = YES
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = NO
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = YES
+VERBATIM_HEADERS = YES
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = YES
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES = YES
+REFERENCED_RELATION = YES
+REFERENCED_BY_RELATION = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = NO
+WARN_IF_UNDOCUMENTED = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . \
+ CodingSuggestions mainpage.dox
+FILE_PATTERNS = *.c \
+ *.h \
+ *.idl
+RECURSIVE = YES
+EXCLUDE = include/includes.h \
+ include/proto.h
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 1
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YE
+GENERATE_HTMLHELP = NO
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 3
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = YES
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = NO
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/source/Makefile.in b/source/Makefile.in
new file mode 100644
index 00000000000..da1eb419f53
--- /dev/null
+++ b/source/Makefile.in
@@ -0,0 +1,899 @@
+##########################################################################
+# Makefile.in for Samba - rewritten for autoconf support
+# Copyright Andrew Tridgell 1992-1998
+# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+###########################################################################
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+
+LIBS=@LIBS@
+CC=@CC@
+SHLD=@SHLD@
+CFLAGS=@CFLAGS@
+CPPFLAGS=@CPPFLAGS@
+LDFLAGS=@LDFLAGS@
+LDSHFLAGS=@LDSHFLAGS@ @LDFLAGS@
+AWK=@AWK@
+
+TERMLDFLAGS=@TERMLDFLAGS@
+TERMLIBS=@TERMLIBS@
+
+LINK=$(CC) $(FLAGS) $(LDFLAGS)
+
+INSTALLCMD=@INSTALL@
+
+VPATH=@srcdir@
+srcdir=@srcdir@
+builddir=@builddir@
+SHELL=/bin/sh
+
+# XXX: Perhaps this should be @SHELL@ instead -- apparently autoconf
+# will search for a POSIX-compliant shell, and that might not be
+# /bin/sh on some platforms. I guess it's not a big problem -- mbp
+
+# See the autoconf manual "Installation Directory Variables" for a
+# discussion of thesubtle use of these variables.
+
+BASEDIR= @prefix@
+BINDIR = @bindir@
+# sbindir is mapped to bindir when compiling SAMBA in 2.0.x compatibility mode.
+SBINDIR = @sbindir@
+LIBDIR = @libdir@
+VARDIR = @localstatedir@
+MANDIR = @mandir@
+
+# The permissions to give the executables
+INSTALLPERMS = 0755
+
+# set these to where to find various files
+# These can be overridden by command line switches (see smbd(8))
+# or in smb.conf (see smb.conf(5))
+LOGFILEBASE = $(VARDIR)
+CONFIGFILE = $(LIBDIR)/smb.conf
+LMHOSTSFILE = $(LIBDIR)/lmhosts
+DRIVERFILE = $(LIBDIR)/printers.def
+# This is where smbpasswd et al go
+PRIVATEDIR = @privatedir@
+
+SMB_PASSWD_FILE = $(PRIVATEDIR)/smbpasswd
+PRIVATE_DIR = $(PRIVATEDIR)
+
+# This is where SWAT images and help files go
+SWATDIR = @swatdir@
+
+# the directory where lock files go
+LOCKDIR = @lockdir@
+
+# man pages language(s)
+man_langs = "@manlangs@"
+
+FLAGS1 = $(CFLAGS) @FLAGS1@ -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -I$(srcdir)/smbwrapper $(CPPFLAGS) -I. -I$(srcdir)
+FLAGS2 =
+FLAGS3 =
+FLAGS4 =
+FLAGS5 = $(FLAGS1) $(FLAGS2) $(FLAGS3) $(FLAGS4)
+FLAGS = $(ISA) $(FLAGS5)
+FLAGS32 = $(ISA32) $(FLAGS5)
+
+PASSWD_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\" -DPRIVATE_DIR=\"$(PRIVATE_DIR)\"
+PATH_FLAGS1 = -DCONFIGFILE=\"$(CONFIGFILE)\" -DSBINDIR=\"$(SBINDIR)\"
+PATH_FLAGS2 = $(PATH_FLAGS1) -DBINDIR=\"$(BINDIR)\" -DDRIVERFILE=\"$(DRIVERFILE)\"
+PATH_FLAGS3 = $(PATH_FLAGS2) -DLMHOSTSFILE=\"$(LMHOSTSFILE)\"
+PATH_FLAGS4 = $(PATH_FLAGS3) -DSWATDIR=\"$(SWATDIR)\" -DLOCKDIR=\"$(LOCKDIR)\"
+PATH_FLAGS5 = $(PATH_FLAGS4) -DLIBDIR=\"$(LIBDIR)\" -DLOGFILEBASE=\"$(LOGFILEBASE)\"
+PATH_FLAGS = $(PATH_FLAGS5) $(PASSWD_FLAGS)
+
+WINBIND_PROGS = @WINBIND_TARGETS@
+WINBIND_SPROGS = @WINBIND_STARGETS@
+WINBIND_PAM_PROGS = @WINBIND_PAM_TARGETS@
+WINBIND_LPROGS = @WINBIND_LTARGETS@
+
+SPROGS = bin/smbd bin/nmbd bin/swat @WINBIND_STARGETS@
+PROGS1 = bin/smbclient bin/net bin/smbspool bin/testparm bin/testprns bin/smbstatus bin/smbcontrol bin/smbtree @RUNPROG@ @WINBIND_TARGETS@
+PROGS2 = bin/smbpasswd bin/rpcclient bin/smbcacls @WRAP@ @WRAP32@ @PAM_MOD@
+MPROGS = @MPROGS@
+LPROGS = $(WINBIND_PAM_PROGS) $(WINBIND_LPROGS)
+
+PROGS = $(PROGS1) $(PROGS2) $(MPROGS) bin/nmblookup bin/pdbedit bin/smbgroupedit
+TORTURE_PROGS = bin/smbtorture bin/msgtest bin/masktest bin/locktest bin/locktest2
+SHLIBS = libsmbclient
+
+SCRIPTS = $(srcdir)/script/smbtar $(srcdir)/script/addtosmbpass $(srcdir)/script/convert_smbpasswd
+
+QUOTAOBJS=@QUOTAOBJS@
+
+######################################################################
+# object file lists
+######################################################################
+
+TDB_OBJ = tdb/tdb.o tdb/spinlock.o tdb/tdbutil.o
+
+LIB_OBJ = lib/charcnv.o lib/debug.o lib/fault.o \
+ lib/getsmbpass.o lib/interface.o lib/md4.o \
+ lib/interfaces.o lib/pidfile.o lib/replace.o \
+ lib/signal.o lib/system.o lib/time.o \
+ lib/ufc.o lib/genrand.o lib/username.o lib/util_getent.o lib/access.o lib/smbrun.o \
+ lib/bitmap.o lib/crc32.o lib/snprintf.o lib/dprintf.o lib/xfile.o lib/wins_srv.o \
+ lib/util_str.o lib/util_sid.o \
+ lib/util_unistr.o lib/util_file.o \
+ lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
+ lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
+ lib/ms_fnmatch.o lib/select.o lib/error.o lib/messages.o \
+ lib/md5.o lib/hmacmd5.o lib/iconv.o lib/smbpasswd.o \
+ nsswitch/wb_client.o nsswitch/wb_common.o \
+ intl/lang_tdb.o lib/account_pol.o $(TDB_OBJ)
+
+READLINE_OBJ = lib/readline.o
+
+UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
+ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o ubiqx/debugparse.o
+
+PARAM_OBJ = param/loadparm.o param/params.o dynconfig.o
+
+LIBADS_OBJ = libads/ldap.o libads/sasl.o libads/krb5_setpw.o libads/kerberos.o \
+ libads/ads_struct.o passdb/secrets.o libads/util.o
+
+LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
+ libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
+ libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \
+ libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \
+ libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \
+ libsmb/namequery.o libsmb/nmblib.o libsmb/clistr.o \
+ libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o \
+ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
+ libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
+ libsmb/passchange.o libsmb/unexpected.o $(RPC_PARSE_OBJ1) \
+ $(LIBADS_OBJ)
+
+LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
+ libsmb/cli_netlogon.o libsmb/cli_srvsvc.o libsmb/cli_dfs.o \
+ libsmb/cli_reg.o libsmb/trust_passwd.o\
+ rpc_client/cli_pipe.o libsmb/cli_pipe_util.o
+
+LIBMSRPC_PICOBJ = $(LIBMSRPC_OBJ:.o=.po)
+
+RPC_SERVER_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o \
+ rpc_server/srv_lsa_hnd.o rpc_server/srv_netlog.o rpc_server/srv_netlog_nt.o \
+ rpc_server/srv_pipe_hnd.o rpc_server/srv_reg.o rpc_server/srv_reg_nt.o \
+ rpc_server/srv_samr.o rpc_server/srv_samr_nt.o rpc_server/srv_srvsvc.o rpc_server/srv_srvsvc_nt.o \
+ rpc_server/srv_util.o rpc_server/srv_wkssvc.o rpc_server/srv_wkssvc_nt.o \
+ rpc_server/srv_pipe.o rpc_server/srv_dfs.o rpc_server/srv_dfs_nt.o \
+ rpc_server/srv_spoolss.o rpc_server/srv_spoolss_nt.o
+
+# this includes only the low level parse code, not stuff
+# that requires knowledge of security contexts
+RPC_PARSE_OBJ1 = rpc_parse/parse_prs.o rpc_parse/parse_sec.o \
+ rpc_parse/parse_misc.o
+
+RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_net.o \
+ rpc_parse/parse_reg.o rpc_parse/parse_rpc.o \
+ rpc_parse/parse_samr.o rpc_parse/parse_srv.o \
+ rpc_parse/parse_wks.o \
+ rpc_parse/parse_spoolss.o rpc_parse/parse_dfs.o
+
+
+RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
+ rpc_client/cli_login.o \
+ rpc_client/cli_spoolss_notify.o
+
+LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
+
+PASSDB_OBJ = passdb/passdb.o \
+ passdb/machine_sid.o passdb/pdb_smbpasswd.o \
+ passdb/pdb_tdb.o passdb/pdb_ldap.o \
+ passdb/pdb_nisplus.o
+
+GROUPDB_OBJ = groupdb/mapping.o
+
+# passdb/smbpass.o passdb/ldap.o passdb/nispass.o
+
+PROFILE_OBJ = profile/profile.o
+
+OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
+
+NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o
+
+PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
+
+AUTH_OBJ = auth/auth.o auth/auth_sam.o auth/auth_server.o auth/auth_domain.o \
+ auth/auth_rhosts.o auth/auth_unix.o auth/auth_util.o auth/auth_winbind.o \
+ auth/auth_info.o auth/auth_builtin.o $(PLAINTEXT_AUTH_OBJ)
+
+
+SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
+ smbd/utmp.o smbd/session.o \
+ smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \
+ smbd/ipc.o smbd/lanman.o smbd/mangle.o smbd/negprot.o \
+ smbd/message.o smbd/nttrans.o smbd/pipes.o \
+ smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \
+ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \
+ smbd/blocking.o smbd/sec_ctx.o \
+ smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \
+ smbd/posix_acls.o lib/sysacls.o \
+ smbd/process.o smbd/service.o smbd/error.o \
+ printing/printfsp.o lib/util_seaccess.o smbd/srvstr.o \
+ smbd/build_options.o \
+ rpc_client/cli_trust.o \
+ rpc_client/cli_netlogon.o \
+ rpc_client/cli_login.o \
+ rpc_client/cli_spoolss_notify.o
+
+
+PRINTING_OBJ = printing/pcap.o printing/print_svid.o \
+ printing/print_cups.o printing/print_generic.o \
+ printing/lpq_parse.o printing/load.o
+
+PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o
+
+MSDFS_OBJ = msdfs/msdfs.o
+
+SMBD_OBJ = $(SMBD_OBJ1) $(MSDFS_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+ $(RPC_SERVER_OBJ) $(RPC_PARSE_OBJ) \
+ $(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) \
+ $(LIB_OBJ) $(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ) \
+ $(NOTIFY_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) $(LIBMSRPC_OBJ)
+
+
+NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
+ nmbd/nmbd_become_lmb.o nmbd/nmbd_browserdb.o \
+ nmbd/nmbd_browsesync.o nmbd/nmbd_elections.o \
+ nmbd/nmbd_incomingdgrams.o nmbd/nmbd_incomingrequests.o \
+ nmbd/nmbd_lmhosts.o nmbd/nmbd_logonnames.o nmbd/nmbd_mynames.o \
+ nmbd/nmbd_namelistdb.o nmbd/nmbd_namequery.o \
+ nmbd/nmbd_nameregister.o nmbd/nmbd_namerelease.o \
+ nmbd/nmbd_nodestatus.o nmbd/nmbd_packets.o \
+ nmbd/nmbd_processlogon.o nmbd/nmbd_responserecordsdb.o \
+ nmbd/nmbd_sendannounce.o nmbd/nmbd_serverlistdb.o \
+ nmbd/nmbd_subnetdb.o nmbd/nmbd_winsproxy.o nmbd/nmbd_winsserver.o \
+ nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o
+
+NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+ $(PROFILE_OBJ) $(LIB_OBJ)
+
+SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
+ web/swat.o web/neg_lang.o $(PRINTING_OBJ) $(LIBSMB_OBJ) $(LOCKING_OBJ) \
+ $(PARAM_OBJ) $(PASSDB_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ) $(GROUPDB_OBJ) $(PLAINTEXT_AUTH_OBJ) \
+ smbwrapper/shared.o
+
+SMBSH_OBJ = smbwrapper/smbsh.o smbwrapper/shared.o \
+ $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+MAKE_PRINTERDEF_OBJ = utils/make_printerdef.o $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+STATUS_OBJ = utils/status.o $(LOCKING_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ)
+
+SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ)
+
+SMBTREE_OBJ = utils/smbtree.o $(LOCKING_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(LIBSMB_OBJ)
+
+TESTPARM_OBJ = utils/testparm.o \
+ $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+TESTPRNS_OBJ = utils/testprns.o $(PARAM_OBJ) $(PRINTING_OBJ) $(UBIQX_OBJ) \
+ $(LIB_OBJ)
+
+SMBPASSWD_OBJ = utils/smbpasswd.o $(PARAM_OBJ) \
+ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ)\
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+PDBEDIT_OBJ = utils/pdbedit.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ) $(GROUPDB_OBJ)
+
+SMBGROUPEDIT_OBJ = utils/smbgroupedit.o $(GROUPDB_OBJ) $(PARAM_OBJ) \
+ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+RPCCLIENT_OBJ1 = rpcclient/rpcclient.o rpcclient/cmd_lsarpc.o \
+ rpcclient/cmd_samr.o rpcclient/cmd_spoolss.o \
+ rpcclient/cmd_netlogon.o rpcclient/cmd_srvsvc.o \
+ rpcclient/cmd_dfs.o rpcclient/cmd_reg.o \
+ rpc_client/cli_login.o rpc_client/cli_netlogon.o \
+ rpcclient/display_sec.o
+
+RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(LIBMSRPC_OBJ) \
+ $(READLINE_OBJ) $(GROUPDB_OBJ)
+
+SAMSYNC_OBJ1 = rpcclient/samsync.o rpc_client/cli_netlogon.o rpcclient/display_sec.o
+
+SAMSYNC_OBJ = $(SAMSYNC_OBJ1) \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(LIBMSRPC_OBJ) \
+ $(GROUPDB_OBJ)
+
+PAM_WINBIND_OBJ = nsswitch/pam_winbind.po nsswitch/wb_common.po lib/snprintf.o
+
+SMBW_OBJ = smbwrapper/smbw.o \
+ smbwrapper/smbw_dir.o smbwrapper/smbw_stat.o \
+ smbwrapper/realcalls.o smbwrapper/shared.o \
+ smbwrapper/smbw_cache.o \
+ $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+SMBWRAPPER_OBJ = $(SMBW_OBJ) smbwrapper/wrapped.o
+
+LIBSMBCLIENT_OBJ = libsmb/libsmbclient.o $(LIB_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
+
+CLIENT_OBJ = client/client.o client/clitar.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(READLINE_OBJ)
+
+NET_OBJ = utils/net.o utils/net_ads.o \
+ utils/net_rap.o utils/net_rpc.o \
+ utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \
+ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) \
+ $(GROUPDB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+
+CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+MOUNT_OBJ = client/smbmount.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+MNT_OBJ = client/smbmnt.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+UMOUNT_OBJ = client/smbumount.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) \
+ $(LIBSMB_OBJ) $(LIB_OBJ)
+
+SMBTORTURE_OBJ = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
+ torture/denytest.o \
+ $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+MASKTEST_OBJ = torture/masktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+MSGTEST_OBJ = torture/msgtest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+LOCKTEST_OBJ = torture/locktest.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+NSSTEST_OBJ = torture/nsstest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+LOCKTEST2_OBJ = torture/locktest2.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+SMBCACLS_OBJ = utils/smbcacls.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) \
+ $(LIBMSRPC_OBJ) $(GROUPDB_OBJ)
+
+TALLOCTORT_OBJ = lib/talloctort.o $(LIB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
+
+RPCTORTURE_OBJ = torture/rpctorture.o \
+ rpcclient/display.o \
+ rpcclient/cmd_lsarpc.o \
+ rpcclient/cmd_wkssvc.o \
+ rpcclient/cmd_samr.o \
+ rpcclient/cmd_srvsvc.o \
+ rpcclient/cmd_netlogon.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ)
+
+DEBUG2HTML_OBJ = utils/debug2html.o ubiqx/debugparse.o
+
+SMBFILTER_OBJ = utils/smbfilter.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+PROTO_OBJ = $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) \
+ $(SMBWRAPPER_OBJ) $(SMBTORTURE_OBJ) $(RPCCLIENT_OBJ1) \
+ $(LIBMSRPC_OBJ) $(RPC_CLIENT_OBJ) $(AUTH_OBJ) $(NET_OBJ)
+
+NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
+NSS_OBJ = $(NSS_OBJ_0:.o=.po)
+
+PICOBJS = $(SMBWRAPPER_OBJ:.o=.po)
+PICOBJS32 = $(SMBWRAPPER_OBJ:.o=.po32)
+LIBSMBCLIENT_PICOBJS = $(LIBSMBCLIENT_OBJ:.o=.po)
+
+PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
+ pam_smbpass/pam_smb_acct.o pam_smbpass/support.o \
+ lib/debug.o lib/util_sid.o lib/messages.o lib/util_str.o \
+ lib/wins_srv.o lib/substitute.o lib/select.o lib/util.o \
+ nsswitch/wb_client.o nsswitch/wb_common.o \
+ lib/system.o lib/util_file.o \
+ lib/genrand.o lib/username.o lib/util_getent.o lib/charcnv.o lib/time.o \
+ lib/md4.o lib/util_unistr.o lib/signal.o lib/talloc.o \
+ lib/ms_fnmatch.o lib/util_sock.o lib/smbrun.o \
+ lib/util_sec.o lib/snprintf.o \
+ ubiqx/ubi_sLinkList.o libsmb/smbencrypt.o libsmb/smbdes.o \
+ $(PARAM_OBJ) $(TDB_OBJ) $(PASSDB_OBJ)
+
+PAM_SMBPASS_PICOOBJ = $(PAM_SMBPASS_OBJ_0:.o=.po)
+
+NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
+NSS_OBJ = $(NSS_OBJ_0:.o=.po)
+
+WINBINDD_OBJ1 = \
+ nsswitch/winbindd.o \
+ nsswitch/winbindd_user.o \
+ nsswitch/winbindd_group.o \
+ nsswitch/winbindd_idmap.o \
+ nsswitch/winbindd_util.o \
+ nsswitch/winbindd_cache.o \
+ nsswitch/winbindd_pam.o \
+ nsswitch/winbindd_sid.o \
+ nsswitch/winbindd_misc.o \
+ nsswitch/winbindd_cm.o \
+ nsswitch/winbindd_rpc.o \
+ nsswitch/winbindd_ads.o
+
+NECESSARY_BECAUSE_SAMBA_DEPENDENCIES_ARE_SO_BROKEN_OBJ = \
+ rpc_client/cli_netlogon.o rpc_client/cli_login.o \
+ auth/auth_util.o
+
+WINBINDD_OBJ = \
+ $(WINBINDD_OBJ1) $(NOPROTO_OBJ) $(PASSDB_OBJ) \
+ $(LIBNMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) \
+ $(GROUPDB_OBJ) $(PROFILE_OBJ) \
+ $(NECESSARY_BECAUSE_SAMBA_DEPENDENCIES_ARE_SO_BROKEN_OBJ)
+
+WBINFO_OBJ = nsswitch/wbinfo.o libsmb/smbencrypt.o libsmb/smbdes.o \
+ passdb/secrets.o
+
+WINBIND_NSS_OBJ = nsswitch/winbind_nss.o nsswitch/wb_common.o
+
+WINBIND_NSS_PICOBJS = $(WINBIND_NSS_OBJ:.o=.po)
+
+POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
+ popt/popthelp.o popt/poptparse.o
+
+######################################################################
+# now the rules...
+######################################################################
+all : SHOWFLAGS include/proto.h include/build_env.h $(SPROGS) $(PROGS) $(WINBIND_PROGS) $(WINBIND_SPROGS) $(LPROGS) $(SHLIBS)
+
+pam_smbpass : SHOWFLAGS bin/pam_smbpass.@SHLIBEXT@
+
+smbwrapper : SHOWFLAGS bin/smbsh bin/smbwrapper.@SHLIBEXT@ @WRAP32@
+
+torture : SHOWFLAGS $(TORTURE_PROGS)
+
+smbtorture : SHOWFLAGS bin/smbtorture
+
+masktest : SHOWFLAGS bin/masktest
+
+msgtest : SHOWFLAGS bin/msgtest
+
+locktest : SHOWFLAGS bin/locktest
+
+smbcacls : SHOWFLAGS bin/smbcacls
+
+locktest2 : SHOWFLAGS bin/locktest2
+
+rpctorture : SHOWFLAGS bin/rpctorture
+
+debug2html : SHOWFLAGS bin/debug2html
+
+smbfilter : SHOWFLAGS bin/smbfilter
+
+talloctort : SHOWFLAGS bin/talloctort
+
+nsswitch : SHOWFLAGS $(WINBIND_PROGS) $(WINBIND_SPROGS) $(LPROGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .po32 .lo
+
+SHOWFLAGS:
+ @echo "Using FLAGS = $(FLAGS)"
+ @echo " FLAGS32 = $(FLAGS32)"
+ @echo " LIBS = $(LIBS)"
+ @echo " LDSHFLAGS = $(LDSHFLAGS)"
+ @echo " LDFLAGS = $(LDFLAGS)"
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c
+ @$(CC) -I. -I$(srcdir) $(FLAGS) -c $< \
+ -o $@
+@BROKEN_CC@ -mv `echo $@ | sed 's%^.*/%%g'` $@
+
+# These dependencies are only approximately correct: we want to make
+# sure Samba's paths are updated if ./configure is re-run. Really it
+# would be nice if "make prefix=/opt/samba all" also rebuilt things,
+# but since we also require "make install prefix=/opt/samba" *not* to
+# rebuild it's a bit hard.
+
+dynconfig.o: dynconfig.c Makefile
+ @echo Compiling $*.c
+ @$(CC) $(FLAGS) $(PATH_FLAGS) -c $< -o $@
+
+dynconfig.po: dynconfig.c Makefile
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c with @PICFLAG@
+ @$(CC) -I. -I$(srcdir) $(FLAGS) $(PATH_FLAGS) @PICFLAG@ -c $< -o $*.@PICSUFFIX@
+@BROKEN_CC@ -mv `echo $@ | sed -e 's%^.*/%%g' -e 's%\.po$$%.o%'` $@
+@POBAD_CC@ @mv $*.po.o $@
+
+.c.po:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c with @PICFLAG@
+ @$(CC) -I. -I$(srcdir) $(FLAGS) @PICFLAG@ -c $< -o $*.@PICSUFFIX@
+@BROKEN_CC@ -mv `echo $@ | sed -e 's%^.*/%%g' -e 's%\.po$$%.o%'` $@
+@POBAD_CC@ @mv $*.po.o $@
+
+# this is for IRIX
+.c.po32:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c with @PICFLAG@ and -32
+ @$(CC) -32 -I. -I$(srcdir) $(FLAGS32) $(PATH_FLAGS) @PICFLAG@ -c $< \
+ -o $*.po32.o
+@BROKEN_CC@ -mv `echo $@ | sed -e 's%^.*/%%g' -e 's%\.po32$$%.o%'` $@.o
+ @mv $*.po32.o $@
+
+bin/.dummy:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then :; else \
+ dir=bin $(MAKEDIR); fi
+ @: >> $@ || : > $@ # what a fancy emoticon!
+
+bin/smbd: $(SMBD_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/nmbd: $(NMBD_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NMBD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/swat: $(SWAT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SWAT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/rpcclient: $(RPCCLIENT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(RPCCLIENT_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(TERMLIBS) $(LIBS)
+
+bin/samsync: $(SAMSYNC_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SAMSYNC_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbclient: $(CLIENT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CLIENT_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(TERMLIBS) $(LIBS)
+
+bin/net: $(NET_OBJ) bin/.dummy @BUILD_POPT@
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NET_OBJ) $(LDFLAGS) $(LIBS) @BUILD_POPT@
+
+bin/smbspool: $(CUPS_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(CUPS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbmount: $(MOUNT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MOUNT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbmnt: $(MNT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MNT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbumount: $(UMOUNT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(UMOUNT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/testparm: $(TESTPARM_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(TESTPARM_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/testprns: $(TESTPRNS_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(TESTPRNS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbstatus: $(STATUS_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(STATUS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbcontrol: $(SMBCONTROL_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBCONTROL_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbtree: $(SMBTREE_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBTREE_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbpasswd: $(SMBPASSWD_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBPASSWD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/pdbedit: $(PDBEDIT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(PDBEDIT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbgroupedit: $(SMBGROUPEDIT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBGROUPEDIT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/nmblookup: $(NMBLOOKUP_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NMBLOOKUP_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/make_printerdef: $(MAKE_PRINTERDEF_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MAKE_PRINTERDEF_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbtorture: $(SMBTORTURE_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBTORTURE_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/talloctort: $(TALLOCTORT_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(TALLOCTORT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/masktest: $(MASKTEST_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MASKTEST_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/msgtest: $(MSGTEST_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(MSGTEST_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbcacls: $(SMBCACLS_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBCACLS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/locktest: $(LOCKTEST_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/nsstest: $(NSSTEST_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NSSTEST_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/locktest2: $(LOCKTEST2_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(LOCKTEST2_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/rpctorture: $(RPCTORTURE_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(RPCTORTURE_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/debug2html: $(DEBUG2HTML_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(DEBUG2HTML_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbfilter: $(SMBFILTER_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBFILTER_OBJ) $(LDFLAGS) $(LIBS)
+
+
+bin/smbw_sample: $(SMBW_OBJ) utils/smbw_sample.o bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBW_OBJ) utils/smbw_sample.o $(LDFLAGS) $(LIBS)
+
+bin/smbwrapper.@SHLIBEXT@: $(PICOBJS)
+ @echo Linking shared library $@
+ @$(LINK) $(LDSHFLAGS) -o $@ $(PICOBJS) $(LIBS)
+
+bin/smbwrapper.32.@SHLIBEXT@: $(PICOBJS32)
+ @echo Linking shared library $@
+ @$(LINK) -32 $(LDSHFLAGS) -o $@ $(PICOBJS32) $(LIBS)
+
+bin/libsmbclient.@SHLIBEXT@: $(LIBSMBCLIENT_PICOBJS)
+ echo Linking libsmbclient shared library $@
+ $(SHLD) $(LDSHFLAGS) -o $@ $(LIBSMBCLIENT_PICOBJS) $(LIBS)
+
+bin/libsmbclient.a: $(LIBSMBCLIENT_PICOBJS)
+ @echo Linking libsmbclient non-shared library $@
+ -$(AR) -rc $@ $(LIBSMBCLIENT_PICOBJS)
+
+libsmbclient: bin/libsmbclient.a @LIBSMBCLIENT_SHARED@
+
+bin/smbsh: $(SMBSH_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SMBSH_OBJ) $(LDFLAGS) $(LIBS)
+
+nsswitch/libnss_wins.so: $(NSS_OBJ)
+ @echo "Linking $@"
+ @$(LINK) $(LDSHFLAGS) -o $@ $(NSS_OBJ) -lc
+
+bin/winbindd: $(WINBINDD_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(LINK) -o $@ $(WINBINDD_OBJ) $(LIBS)
+
+nsswitch/libnss_winbind.so: $(WINBIND_NSS_PICOBJS)
+ @echo "Linking $@"
+ @$(LINK) $(LDSHFLAGS) -o $@ $(WINBIND_NSS_PICOBJS)
+
+nsswitch/pam_winbind.so: $(PAM_WINBIND_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(LINK) $(LDSHFLAGS) -o $@ $(PAM_WINBIND_OBJ)
+
+bin/wbinfo: $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) \
+ $(UBIQX_OBJ) @BUILD_POPT@ bin/.dummy
+ @echo Linking $@
+ @$(LINK) -o $@ $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(NOPROTO_OBJ) \
+ $(UBIQX_OBJ) $(LIBS) @BUILD_POPT@
+
+bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ)
+ @echo "Linking shared library $@"
+ $(LINK) $(LDSHFLAGS) -symbolic -o $@ $(PAM_SMBPASS_PICOOBJ) -lpam $(LIBS) -lc
+
+bin/libmsrpc.a: $(LIBMSRPC_PICOBJ)
+ -$(AR) -rc $@ $(LIBMSRPC_PICOBJ)
+
+bin/spamsync: rpcclient/samsync.o bin/libmsrpc.a
+ @$(LINK) -o $@ rpcclient/samsync.o bin/libmsrpc.a \
+ $(UBIQX_OBJ) $(LIBS)
+
+install: installbin installman installscripts installswat
+
+installdirs:
+ -$(SHELL) $(srcdir)/install-sh -d -m $(INSTALLPERMS) \
+ $(BASEDIR) $(SBINDIR) $(BINDIR) $(LIBDIR) $(VARDIR)
+
+installservers: all installdirs
+ @$(SHELL) $(srcdir)/script/installbin.sh $(INSTALLPERMS) $(BASEDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(SPROGS)
+
+installbin: all installdirs
+ @$(SHELL) $(srcdir)/script/installbin.sh $(INSTALLPERMS) $(BASEDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(SPROGS)
+ @$(SHELL) $(srcdir)/script/installbin.sh $(INSTALLPERMS) $(BASEDIR) $(BINDIR) $(LIBDIR) $(VARDIR) $(PROGS)
+
+installscripts: installdirs
+ @$(SHELL) $(srcdir)/script/installscripts.sh $(INSTALLPERMS) $(BINDIR) $(SCRIPTS)
+
+installswat: installdirs
+ @$(SHELL) $(srcdir)/script/installswat.sh $(SWATDIR) $(srcdir)
+
+installclientlib:
+ -$(INSTALLCMD) bin/libsmbclient.so $(LIBDIR)
+ -$(INSTALLCMD) -d ${prefix}/include
+ -$(INSTALLCMD) include/libsmbclient.h ${prefix}/include
+
+# revert to the previously installed version
+revert:
+ @$(SHELL) $(srcdir)/script/revert.sh $(SBINDIR) $(SPROGS)
+ @$(SHELL) $(srcdir)/script/revert.sh $(BINDIR) $(PROGS) $(SCRIPTS)
+
+installman:
+ @$(SHELL) $(srcdir)/script/installman.sh $(MANDIR) $(srcdir) $(man_langs) "@ROFF@"
+
+.PHONY: showlayout
+
+showlayout:
+ @echo "Samba will be installed into:"
+ @echo " basedir: $(BASEDIR)"
+ @echo " bindir: $(BINDIR)"
+ @echo " sbindir: $(SBINDIR)"
+ @echo " libdir: $(LIBDIR)"
+ @echo " vardir: $(VARDIR)"
+ @echo " mandir: $(MANDIR)"
+
+
+uninstall: uninstallman uninstallbin uninstallscripts
+
+uninstallman:
+ @$(SHELL) $(srcdir)/script/uninstallman.sh $(MANDIR) $(srcdir) $(man_langs)
+
+uninstallbin:
+ @$(SHELL) $(srcdir)/script/uninstallbin.sh $(INSTALLPERMS) $(BASEDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(SPROGS)
+ @$(SHELL) $(srcdir)/script/uninstallbin.sh $(INSTALLPERMS) $(BASEDIR) $(BINDIR) $(LIBDIR) $(VARDIR) $(PROGS)
+
+uninstallscripts:
+ @$(SHELL) $(srcdir)/script/uninstallscripts.sh $(INSTALLPERMS) $(BINDIR) $(SCRIPTS)
+
+clean: delheaders
+ -rm -f core */*~ *~ */*.o */*.po */*.po32 */*.@SHLIBEXT@ $(PROGS) $(SPROGS) .headers.stamp
+
+winbindd_proto:
+ @cd $(srcdir) && $(SHELL) script/mkproto.sh $(AWK) \
+ -h _WINBINDD_PROTO_H_ nsswitch/winbindd_proto.h \
+ $(WINBINDD_OBJ1)
+
+delheaders:
+ @/bin/rm -f $(srcdir)/include/proto.h $(srcdir)/include/build_env.h
+ @/bin/rm -f include/proto.h include/build_env.h
+
+# we want our generated headers to be rebuilt if they don't exist, but not rebuilt every time
+.headers.stamp:
+ @[ -f $@ ] || touch $@
+
+$(PROTO_OBJ) : .headers.stamp
+
+include/proto.h:
+ @echo rebuilding include/proto.h
+ @cd $(srcdir) && $(AWK) -f script/mkproto.awk `echo $(PROTO_OBJ) | tr ' ' '\n' | sed -e 's/\.o/\.c/g' | sort -u | egrep -v 'ubiqx/|wrapped'` > $(builddir)/include/proto.h
+
+include/build_env.h:
+ @echo rebuilding include/build_env.h
+ @cd $(srcdir) && $(SHELL) script/build_env.sh $(srcdir) $(builddir) $(CC) > $(builddir)/include/build_env.h
+
+headers: delheaders include/proto.h include/build_env.h .headers.stamp
+
+proto: headers winbindd_proto
+
+etags:
+ etags `find $(srcdir) -name "*.[ch]" | grep -v /CVS/`
+
+ctags:
+ ctags `find $(srcdir) -name "*.[ch]" | grep -v /CVS/`
+
+realclean: clean
+ -rm -f config.log $(PROGS) $(SPROGS) bin/.dummy
+ -rmdir bin
+
+distclean: realclean
+ -rm -f include/config.h Makefile
+ -rm -f config.status config.cache so_locations
+ -rm -rf .deps
+
+#
+# This target is for documenation updators. It regenerates
+# the man pages and HTML docs from the YODL source files.
+# In order for this target to work YODL must be installed
+# and working on your system. JRA.
+yodldocs:
+ @$(SHELL) $(srcdir)/script/makeyodldocs.sh $(srcdir)
+
+# this target is really just for my use. It only works on a limited
+# range of machines and is used to produce a list of potentially
+# dead (ie. unused) functions in the code. (tridge)
+finddead:
+ nm */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
+ nm */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
+ comm -13 nmused.txt nmfns.txt
+
+
+# when configure.in is updated, reconfigure
+$(srcdir)/configure: $(srcdir)/configure.in
+ @echo "WARNING: you need to rerun autoconf"
+
+config.status: $(srcdir)/configure
+ @echo "WARNING: you need to run configure"
+
+Makefile: $(srcdir)/Makefile.in config.status
+ @echo "WARNING: you need to run ./config.status"
+
+test_prefix=/tmp/test-samba
+# Run regression suite using the external "satyr" framework
+check:
+ @echo "** Sorry, samba self-test without installation does not work "
+ @echo "** yet. Please try specifying a scratch directory to"
+ @echo "** ./configure --prefix DIR"
+ @echo "** then run \"make install installcheck\""
+ exit 1
+
+# -rm -rf $(test_prefix)/lib
+# mkdir $(test_prefix)/lib -p ./testdir
+# PATH=$(builddir)/bin:$(PATH) \
+# SATYR_SUITEDIR=../testsuite/build_farm/ prefix=$(test_prefix) \
+# testdir=./testdir $(SHELL) satyr
+
+# Run regression suite on the installed version.
+
+# `installcheck'
+# Perform installation tests (if any). The user must build and
+# install the program before running the tests. You should not
+# assume that `$(bindir)' is in the search path.
+
+dangerous-installcheck:
+ mkdir -p $(BASEDIR)/lib
+ mkdir -p $(BASEDIR)/var
+ PATH=$(BINDIR):$(SBINDIR):$(PATH) \
+ SATYR_DISCOURAGE=1 \
+ SATYR_SUITEDIR=../testsuite/satyr/ prefix=$(BASEDIR) \
+ LIBSMB_PROG=$(SBINDIR)/smbd \
+ testdir=./testdir $(SHELL) satyr
+
diff --git a/source/acconfig.h b/source/acconfig.h
new file mode 100644
index 00000000000..ebe015c637a
--- /dev/null
+++ b/source/acconfig.h
@@ -0,0 +1,186 @@
+#undef HAVE_VOLATILE
+#undef HAVE_BROKEN_READDIR
+#undef HAVE_C99_VSNPRINTF
+#undef HAVE_ERRNO_DECL
+#undef HAVE_LONGLONG
+#undef HAVE_OFF64_T
+#undef HAVE_REMSH
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UTIMBUF
+#undef HAVE_SIG_ATOMIC_T_TYPE
+#undef HAVE_SOCKLEN_T_TYPE
+#undef ssize_t
+#undef ino_t
+#undef ssize_t
+#undef loff_t
+#undef offset_t
+#undef aclent_t
+#undef wchar_t
+#undef HAVE_CONNECT
+#undef HAVE_SHORT_INO_T
+#undef WITH_SMBWRAPPER
+#undef WITH_AFS
+#undef WITH_DFS
+#undef SUNOS5
+#undef SUNOS4
+#undef LINUX
+#undef AIX
+#undef BSD
+#undef IRIX
+#undef IRIX6
+#undef HPUX
+#undef QNX
+#undef SCO
+#undef OSF1
+#undef NEXT2
+#undef RELIANTUNIX
+#undef HAVE_MMAP
+#undef HAVE_FCNTL_LOCK
+#undef HAVE_FTRUNCATE_EXTEND
+#undef FTRUNCATE_NEEDS_ROOT
+#undef HAVE_TRAPDOOR_UID
+#undef HAVE_ROOT
+#undef HAVE_GETTIMEOFDAY_TZ
+#undef HAVE_SOCK_SIN_LEN
+#undef STAT_READ_FILSYS
+#undef STAT_STATFS2_BSIZE
+#undef STAT_STATFS2_FSIZE
+#undef STAT_STATFS2_FS_DATA
+#undef STAT_STATFS3_OSF1
+#undef STAT_STATFS4
+#undef STAT_STATVFS
+#undef STAT_STATVFS64
+#undef HAVE_IFACE_AIX
+#undef HAVE_IFACE_IFCONF
+#undef HAVE_IFACE_IFREQ
+#undef HAVE_CRYPT
+#undef HAVE_PUTPRPWNAM
+#undef HAVE_SET_AUTH_PARAMETERS
+#undef WITH_SYSLOG
+#undef WITH_PROFILE
+#undef WITH_SSL
+#undef SSL_DIR
+#undef WITH_LDAP
+#undef WITH_NISPLUS
+#undef WITH_TDBPWD
+#undef WITH_PAM
+#undef WITH_NISPLUS_HOME
+#undef WITH_AUTOMOUNT
+#undef WITH_SMBMOUNT
+#undef WITH_QUOTAS
+#undef WITH_WINBIND
+#undef HAVE_BROKEN_GETGROUPS
+#undef REPLACE_GETPASS
+#undef REPLACE_INET_NTOA
+#undef HAVE_FILE_MACRO
+#undef HAVE_FUNCTION_MACRO
+#undef HAVE_SETRESUID_DECL
+#undef HAVE_SETRESUID
+#undef WITH_NETATALK
+#undef WITH_UTMP
+#undef WITH_MSDFS
+#undef WITH_LIBICONV
+#undef HAVE_INO64_T
+#undef HAVE_STRUCT_FLOCK64
+#undef SIZEOF_INO_T
+#undef SIZEOF_OFF_T
+#undef STAT_STATVFS64
+#undef HAVE_LIBREADLINE
+#undef HAVE_KERNEL_SHARE_MODES
+#undef HAVE_KERNEL_OPLOCKS_IRIX
+#undef HAVE_KERNEL_OPLOCKS_LINUX
+#undef HAVE_KERNEL_CHANGE_NOTIFY
+#undef HAVE_IRIX_SPECIFIC_CAPABILITIES
+#undef HAVE_INT16_FROM_RPC_RPC_H
+#undef HAVE_UINT16_FROM_RPC_RPC_H
+#undef HAVE_INT32_FROM_RPC_RPC_H
+#undef HAVE_UINT32_FROM_RPC_RPC_H
+#undef KRB4_AUTH
+#undef KRB5_AUTH
+#undef KRB4_DIR
+#undef KRB5_DIR
+#undef SEEKDIR_RETURNS_VOID
+#undef HAVE_DIRENT_D_OFF
+#undef HAVE_GETSPNAM
+#undef HAVE_BIGCRYPT
+#undef HAVE_GETPRPWNAM
+#undef HAVE_FSTAT64
+#undef HAVE_LSTAT64
+#undef HAVE_STAT64
+#undef HAVE_SETRESGID
+#undef HAVE_SETRESGID_DECL
+#undef HAVE_SHADOW_H
+#undef HAVE_CUPS
+#undef HAVE_MEMSET
+#undef HAVE_STRCASECMP
+#undef HAVE_STRUCT_DIRENT64
+#undef HAVE_TRUNCATED_SALT
+#undef BROKEN_NISPLUS_INCLUDE_FILES
+#undef HAVE_RPC_AUTH_ERROR_CONFLICT
+#undef HAVE_EXPLICIT_LARGEFILE_SUPPORT
+#undef USE_BOTH_CRYPT_CALLS
+#undef HAVE_BROKEN_FCNTL64_LOCKS
+#undef HAVE_SECURE_MKSTEMP
+#undef HAVE_FNMATCH
+#undef USE_SETEUID
+#undef USE_SETRESUID
+#undef USE_SETREUID
+#undef USE_SETUIDX
+#undef HAVE_LIBDL
+#undef SYSCONF_SC_NGROUPS_MAX
+#undef HAVE_UT_UT_NAME
+#undef HAVE_UT_UT_USER
+#undef HAVE_UT_UT_ID
+#undef HAVE_UT_UT_HOST
+#undef HAVE_UT_UT_TIME
+#undef HAVE_UT_UT_TV
+#undef HAVE_UT_UT_TYPE
+#undef HAVE_UT_UT_PID
+#undef HAVE_UT_UT_EXIT
+#undef HAVE_UT_UT_ADDR
+#undef HAVE_UX_UT_SYSLEN
+#undef PUTUTLINE_RETURNS_UTMP
+#undef COMPILER_SUPPORTS_LL
+#undef HAVE_YP_GET_DEFAULT_DOMAIN
+#undef USE_SPINLOCKS
+#undef SPARC_SPINLOCKS
+#undef INTEL_SPINLOCKS
+#undef MIPS_SPINLOCKS
+#undef POWERPC_SPINLOCKS
+#undef HAVE_POSIX_ACLS
+#undef HAVE_ACL_GET_PERM_NP
+#undef HAVE_UNIXWARE_ACLS
+#undef HAVE_SOLARIS_ACLS
+#undef HAVE_HPUX_ACLS
+#undef HAVE_IRIX_ACLS
+#undef HAVE_AIX_ACLS
+#undef HAVE_TRU64_ACLS
+#undef HAVE_NO_ACLS
+#undef HAVE_LIBPAM
+#undef HAVE_ASPRINTF_DECL
+#undef HAVE_VASPRINTF_DECL
+#undef HAVE_SNPRINTF_DECL
+#undef HAVE_VSNPRINTF_DECL
+#undef HAVE_NATIVE_ICONV
+#undef HAVE_UNIXSOCKET
+#undef MMAP_BLACKLIST
+#undef HAVE_IMMEDIATE_STRUCTURES
+#undef HAVE_CUPS
+#undef WITH_LDAP_SAM
+#undef WITH_NISPLUS_SAM
+#undef WITH_SMBPASSWD_SAM
+#undef WITH_TDB_SAM
+#undef LINUX_QUOTAS_1
+#undef LINUX_QUOTAS_2
+#undef PACKAGE
+#undef VERSION
+#undef HAVE_LC_MESSAGES
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_STPCPY
+#undef I18N_SWAT
+#undef I18N_DEFAULT_PREF_LANG
+#undef HAVE_KRB5
+#undef BROKEN_REDHAT_7_SYSTEM_HEADERS
+#undef HAVE_LDAP
diff --git a/source/aclocal.m4 b/source/aclocal.m4
new file mode 100644
index 00000000000..caf5ab461b9
--- /dev/null
+++ b/source/aclocal.m4
@@ -0,0 +1,932 @@
+dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
+dnl if the cache file is inconsistent with the current host,
+dnl target and build system types, execute CMD or print a default
+dnl error message.
+AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
+ AC_REQUIRE([AC_CANONICAL_SYSTEM])
+ AC_MSG_CHECKING([config.cache system type])
+ if { test x"${ac_cv_host_system_type+set}" = x"set" &&
+ test x"$ac_cv_host_system_type" != x"$host"; } ||
+ { test x"${ac_cv_build_system_type+set}" = x"set" &&
+ test x"$ac_cv_build_system_type" != x"$build"; } ||
+ { test x"${ac_cv_target_system_type+set}" = x"set" &&
+ test x"$ac_cv_target_system_type" != x"$target"; }; then
+ AC_MSG_RESULT([different])
+ ifelse($#, 1, [$1],
+ [AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
+ else
+ AC_MSG_RESULT([same])
+ fi
+ ac_cv_host_system_type="$host"
+ ac_cv_build_system_type="$build"
+ ac_cv_target_system_type="$target"
+])
+
+
+dnl test whether dirent has a d_off member
+AC_DEFUN(AC_DIRENT_D_OFF,
+[AC_CACHE_CHECK([for d_off in dirent], ac_cv_dirent_d_off,
+[AC_TRY_COMPILE([
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>], [struct dirent d; d.d_off;],
+ac_cv_dirent_d_off=yes, ac_cv_dirent_d_off=no)])
+if test $ac_cv_dirent_d_off = yes; then
+ AC_DEFINE(HAVE_DIRENT_D_OFF)
+fi
+])
+
+
+dnl AC_PROG_CC_FLAG(flag)
+AC_DEFUN(AC_PROG_CC_FLAG,
+[AC_CACHE_CHECK(whether ${CC-cc} accepts -$1, ac_cv_prog_cc_$1,
+[echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -$1 -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_$1=yes
+else
+ ac_cv_prog_cc_$1=no
+fi
+rm -f conftest*
+])])
+
+dnl see if a declaration exists for a function or variable
+dnl defines HAVE_function_DECL if it exists
+dnl AC_HAVE_DECL(var, includes)
+AC_DEFUN(AC_HAVE_DECL,
+[
+ AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[
+ AC_TRY_COMPILE([$2],[int i = (int)$1],
+ ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)])
+ if test x"$ac_cv_have_$1_decl" = x"yes"; then
+ AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL])
+ fi
+])
+
+
+dnl check for a function in a library, but don't
+dnl keep adding the same library to the LIBS variable.
+dnl AC_LIBTESTFUNC(lib,func)
+AC_DEFUN(AC_LIBTESTFUNC,
+[case "$LIBS" in
+ *-l$1*) AC_CHECK_FUNCS($2) ;;
+ *) AC_CHECK_LIB($1, $2)
+ AC_CHECK_FUNCS($2)
+ ;;
+ esac
+])
+
+dnl Define an AC_DEFINE with ifndef guard.
+dnl AC_N_DEFINE(VARIABLE [, VALUE])
+define(AC_N_DEFINE,
+[cat >> confdefs.h <<\EOF
+[#ifndef] $1
+[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1)
+[#endif]
+EOF
+])
+
+dnl Add an #include
+dnl AC_ADD_INCLUDE(VARIABLE)
+define(AC_ADD_INCLUDE,
+[cat >> confdefs.h <<\EOF
+[#include] $1
+EOF
+])
+
+## libtool.m4 - Configure libtool for the target system. -*-Shell-script-*-
+## Copyright (C) 1996-1999 Free Software Foundation, Inc.
+## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+##
+## As a special exception to the GNU General Public License, if you
+## distribute this file as part of a program that contains a
+## configuration script generated by Autoconf, you may include it under
+## the same distribution terms that you use for the rest of that program.
+
+# serial 40 AC_PROG_LIBTOOL
+AC_DEFUN(AC_PROG_LIBTOOL,
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+
+# Save cache, so that ltconfig can load it
+AC_CACHE_SAVE
+
+# Actually configure libtool. ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
+LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \
+DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
+$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \
+|| AC_MSG_ERROR([libtool configure failed])
+
+# Reload cache, that may have been modified by ltconfig
+AC_CACHE_LOAD
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Redirect the config.log output again, so that the ltconfig log is not
+# clobbered by the next message.
+exec 5>>./config.log
+])
+
+# Macro to add for using GNU gettext.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 5
+
+AC_DEFUN(AM_WITH_NLS,
+ [AC_MSG_CHECKING([whether NLS is requested])
+ dnl Default is enabled NLS
+ AC_ARG_ENABLE(nls,
+ [ --disable-nls do not use Native Language Support],
+ USE_NLS=$enableval, USE_NLS=yes)
+ AC_MSG_RESULT($USE_NLS)
+ AC_SUBST(USE_NLS)
+
+ USE_INCLUDED_LIBINTL=no
+
+ dnl If we use NLS figure out what method
+ if test "$USE_NLS" = "yes"; then
+ AC_DEFINE(ENABLE_NLS)
+# AC_MSG_CHECKING([whether included gettext is requested])
+# AC_ARG_WITH(included-gettext,
+# [ --with-included-gettext use the GNU gettext library included here],
+# nls_cv_force_use_gnu_gettext=$withval,
+# nls_cv_force_use_gnu_gettext=no)
+# AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
+
+ dnl ad-hoc fix to prevent configure from detecting
+ dnl gettext on the system. use included-gettext as default.(rkawa)
+ nls_cv_force_use_gnu_gettext="yes"
+
+ nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+ if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+ dnl User does not insist on using GNU NLS library. Figure out what
+ dnl to use. If gettext or catgets are available (in this order) we
+ dnl use this. Else we have to fall back to GNU NLS library.
+ dnl catgets is only used if permitted by option --with-catgets.
+ nls_cv_header_intl=
+ nls_cv_header_libgt=
+ CATOBJEXT=NONE
+
+ AC_CHECK_HEADER(libintl.h,
+ [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc,
+ [AC_TRY_LINK([#include <libintl.h>], [return (int) gettext ("")],
+ gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)])
+
+ if test "$gt_cv_func_gettext_libc" != "yes"; then
+ AC_CHECK_LIB(intl, bindtextdomain,
+ [AC_CACHE_CHECK([for gettext in libintl],
+ gt_cv_func_gettext_libintl,
+ [AC_CHECK_LIB(intl, gettext,
+ gt_cv_func_gettext_libintl=yes,
+ gt_cv_func_gettext_libintl=no)],
+ gt_cv_func_gettext_libintl=no)])
+ fi
+
+ if test "$gt_cv_func_gettext_libc" = "yes" \
+ || test "$gt_cv_func_gettext_libintl" = "yes"; then
+ AC_DEFINE(HAVE_GETTEXT)
+ AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl
+ if test "$MSGFMT" != "no"; then
+ AC_CHECK_FUNCS(dcgettext)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ AC_TRY_LINK(, [extern int _nl_msg_cat_cntr;
+ return _nl_msg_cat_cntr],
+ [CATOBJEXT=.gmo
+ DATADIRNAME=share],
+ [CATOBJEXT=.mo
+ DATADIRNAME=lib])
+ INSTOBJEXT=.mo
+ fi
+ fi
+ ])
+
+ if test "$CATOBJEXT" = "NONE"; then
+# AC_MSG_CHECKING([whether catgets can be used])
+# AC_ARG_WITH(catgets,
+# [ --with-catgets use catgets functions if available],
+# nls_cv_use_catgets=$withval, nls_cv_use_catgets=no)
+# AC_MSG_RESULT($nls_cv_use_catgets)
+
+ dnl ad-hoc fix to prevent configure to detect catgets library.
+ dnl (rkawa)
+ nls_cv_use_catgets="no"
+
+ if test "$nls_cv_use_catgets" = "yes"; then
+ dnl No gettext in C library. Try catgets next.
+ AC_CHECK_LIB(i, main)
+ AC_CHECK_FUNC(catgets,
+ [AC_DEFINE(HAVE_CATGETS)
+ INTLOBJS="\$(CATOBJS)"
+ AC_PATH_PROG(GENCAT, gencat, no)dnl
+ if test "$GENCAT" != "no"; then
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, no)
+ if test "$GMSGFMT" = "no"; then
+ AM_PATH_PROG_WITH_TEST(GMSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)
+ fi
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ USE_INCLUDED_LIBINTL=yes
+ CATOBJEXT=.cat
+ INSTOBJEXT=.cat
+ DATADIRNAME=lib
+ INTLDEPS='$(top_builddir)/intl/libintl.a'
+ INTLLIBS=$INTLDEPS
+ LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+ nls_cv_header_intl=intl/libintl.h
+ nls_cv_header_libgt=intl/libgettext.h
+ fi])
+ fi
+ fi
+
+ if test "$CATOBJEXT" = "NONE"; then
+ dnl Neither gettext nor catgets in included in the C library.
+ dnl Fall back on GNU gettext library.
+ nls_cv_use_gnu_gettext=yes
+ fi
+ fi
+
+ if test "$nls_cv_use_gnu_gettext" = "yes"; then
+ dnl Mark actions used to generate GNU NLS library.
+ INTLOBJS="\$(GETTOBJS)"
+ AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt)
+ AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+ AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+ [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+ AC_SUBST(MSGFMT)
+ USE_INCLUDED_LIBINTL=yes
+ CATOBJEXT=.gmo
+ INSTOBJEXT=.mo
+ DATADIRNAME=share
+ INTLDEPS='$(top_builddir)/intl/libintl.a'
+ INTLLIBS=$INTLDEPS
+ LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+ nls_cv_header_intl=intl/libintl.h
+ nls_cv_header_libgt=intl/libgettext.h
+ fi
+
+ dnl Test whether we really found GNU xgettext.
+ if test "$XGETTEXT" != ":"; then
+ dnl If it is no GNU xgettext we define it as : so that the
+ dnl Makefiles still can work.
+ if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+ : ;
+ else
+ AC_MSG_RESULT(
+ [found xgettext program is not GNU xgettext; ignore it])
+ XGETTEXT=":"
+ fi
+ fi
+
+ # We need to process the po/ directory.
+ POSUB=po
+ else
+ DATADIRNAME=share
+ nls_cv_header_intl=intl/libintl.h
+ nls_cv_header_libgt=intl/libgettext.h
+ fi
+
+ dnl the next line has been modified by rkawa to avoid
+ dnl misconfiguration of intl/libintl.h symlink.
+ rm -f intl/libintl.h
+
+ AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
+ AC_OUTPUT_COMMANDS(
+ [case "$CONFIG_FILES" in *po/Makefile.in*)
+ sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+ esac])
+
+
+ # If this is used in GNU gettext we have to set USE_NLS to `yes'
+ # because some of the sources are only built for this goal.
+ if test "$PACKAGE" = gettext; then
+ USE_NLS=yes
+ USE_INCLUDED_LIBINTL=yes
+ fi
+
+ dnl These rules are solely for the distribution goal. While doing this
+ dnl we only have to keep exactly one list of the available catalogs
+ dnl in configure.in.
+ for lang in $ALL_LINGUAS; do
+ GMOFILES="$GMOFILES $lang.gmo"
+ POFILES="$POFILES $lang.po"
+ done
+
+ dnl Make all variables we use known to autoconf.
+ AC_SUBST(USE_INCLUDED_LIBINTL)
+ AC_SUBST(CATALOGS)
+ AC_SUBST(CATOBJEXT)
+ AC_SUBST(DATADIRNAME)
+ AC_SUBST(GMOFILES)
+ AC_SUBST(INSTOBJEXT)
+ AC_SUBST(INTLDEPS)
+ AC_SUBST(INTLLIBS)
+ AC_SUBST(INTLOBJS)
+ AC_SUBST(POFILES)
+ AC_SUBST(POSUB)
+ ])
+
+AC_DEFUN(AM_GNU_GETTEXT,
+ [AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+ AC_REQUIRE([AC_PROG_CC])dnl
+ AC_REQUIRE([AC_PROG_RANLIB])dnl
+ AC_REQUIRE([AC_ISC_POSIX])dnl
+ AC_REQUIRE([AC_HEADER_STDC])dnl
+ AC_REQUIRE([AC_C_CONST])dnl
+ AC_REQUIRE([AC_C_INLINE])dnl
+ AC_REQUIRE([AC_TYPE_OFF_T])dnl
+ AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+ AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+ AC_REQUIRE([AC_FUNC_MMAP])dnl
+
+ AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \
+unistd.h sys/param.h])
+ AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \
+strdup __argz_count __argz_stringify __argz_next])
+
+ if test "${ac_cv_func_stpcpy+set}" != "set"; then
+ AC_CHECK_FUNCS(stpcpy)
+ fi
+ if test "${ac_cv_func_stpcpy}" = "yes"; then
+ AC_DEFINE(HAVE_STPCPY)
+ fi
+
+ AM_LC_MESSAGES
+ AM_WITH_NLS
+
+
+ if test "x$CATOBJEXT" != "x"; then
+ if test "x$ALL_LINGUAS" = "x"; then
+ LINGUAS=
+ else
+ AC_MSG_CHECKING(for catalogs to be installed)
+ NEW_LINGUAS=
+ for lang in ${LINGUAS=$ALL_LINGUAS}; do
+ case "$ALL_LINGUAS" in
+ *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;;
+ esac
+ done
+ LINGUAS=$NEW_LINGUAS
+ AC_MSG_RESULT($LINGUAS)
+ fi
+
+ dnl Construct list of names of catalog files to be constructed.
+ if test -n "$LINGUAS"; then
+ for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+ fi
+ fi
+
+ dnl The reference to <locale.h> in the installed <libintl.h> file
+ dnl must be resolved because we cannot expect the users of this
+ dnl to define HAVE_LOCALE_H.
+ if test $ac_cv_header_locale_h = yes; then
+ INCLUDE_LOCALE_H="#include <locale.h>"
+ else
+ INCLUDE_LOCALE_H="\
+/* The system does not provide the header <locale.h>. Take care yourself. */"
+ fi
+ AC_SUBST(INCLUDE_LOCALE_H)
+ dnl Determine which catalog format we have (if any is needed)
+ dnl For now we know about two different formats:
+ dnl Linux libc-5 and the normal X/Open format
+ test -d intl || mkdir intl
+ if test "$CATOBJEXT" = ".cat"; then
+ AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen)
+
+ dnl Transform the SED scripts while copying because some dumb SEDs
+ dnl cannot handle comments.
+ sed -e '/^#/d' $srcdir/intl/$msgformat-msg.sed > intl/po2msg.sed
+
+ dnl To avoid XPG incompatible SED to be used, .msg files of
+ dnl x/open format are included to the archive, rather than
+ dnl compiled in the installation. If the system uses linux libc5
+ dnl format, then x/open files are removed and the sed script
+ dnl creates the files of the correct format. (rkawa)
+ if test "$msgformat" = "linux"; then
+ rm -f $srcdir/po/*.msg
+ fi
+ fi
+ dnl po2tbl.sed is always needed.
+ sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \
+ $srcdir/intl/po2tbl.sed.in > intl/po2tbl.sed
+
+ dnl In the intl/Makefile.in we have a special dependency which makes
+ dnl only sense for gettext. We comment this out for non-gettext
+ dnl packages.
+ if test "$PACKAGE" = "gettext"; then
+ GT_NO="#NO#"
+ GT_YES=
+ else
+ GT_NO=
+ GT_YES="#YES#"
+ fi
+ AC_SUBST(GT_NO)
+ AC_SUBST(GT_YES)
+
+ dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly
+ dnl find the mkinstalldirs script in another subdir but ($top_srcdir).
+ dnl Try to locate is.
+ MKINSTALLDIRS=
+ if test -n "$ac_aux_dir"; then
+ MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs"
+ fi
+ if test -z "$MKINSTALLDIRS"; then
+ MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+ fi
+ AC_SUBST(MKINSTALLDIRS)
+
+ dnl *** For now the libtool support in intl/Makefile is not for real.
+ l=
+ AC_SUBST(l)
+
+ dnl Generate list of files to be processed by xgettext which will
+ dnl be included in po/Makefile.
+ test -d po || mkdir po
+ if test "x$srcdir" != "x."; then
+ if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then
+ posrcprefix="$srcdir/"
+ else
+ posrcprefix="../$srcdir/"
+ fi
+ else
+ posrcprefix="../"
+ fi
+ rm -f po/POTFILES
+ sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+ < $srcdir/po/POTFILES.in > po/POTFILES
+ ])
+
+# Check whether LC_MESSAGES is available in <locale.h>.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+AC_DEFUN(AM_LC_MESSAGES,
+ [if test $ac_cv_header_locale_h = yes; then
+ AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES,
+ [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+ am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)])
+ if test $am_cv_val_LC_MESSAGES = yes; then
+ AC_DEFINE(HAVE_LC_MESSAGES)
+ fi
+ fi])
+
+# Search path for a program which passes the given test.
+# Ulrich Drepper <drepper@cygnus.com>, 1996.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN(AM_PATH_PROG_WITH_TEST,
+[# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+ /*)
+ ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in ifelse([$5], , $PATH, [$5]); do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if [$3]; then
+ ac_cv_path_$1="$ac_dir/$ac_word"
+ break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+ ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test -n "[$]$1"; then
+ AC_MSG_RESULT([$]$1)
+else
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
+
+
+AC_DEFUN(AC_LIBTOOL_SETUP,
+[AC_PREREQ(2.13)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_RANLIB])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+dnl
+
+case "$target" in
+NONE) lt_target="$host" ;;
+*) lt_target="$target" ;;
+esac
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags="--cache-file=$cache_file"
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN],
+[libtool_flags="$libtool_flags --enable-dlopen"])
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[libtool_flags="$libtool_flags --enable-win32-dll"])
+AC_ARG_ENABLE(libtool-lock,
+ [ --disable-libtool-lock avoid locking (might break parallel builds)])
+test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
+test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$lt_target" in
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case "`/usr/bin/file conftest.o`" in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+
+ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw*)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+])
+esac
+])
+
+# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
+AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
+
+# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
+AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
+
+# AC_ENABLE_SHARED - implement the --enable-shared flag
+# Usage: AC_ENABLE_SHARED[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN(AC_ENABLE_SHARED, [dnl
+define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
+])
+
+# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
+AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)])
+
+# AC_ENABLE_STATIC - implement the --enable-static flag
+# Usage: AC_ENABLE_STATIC[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN(AC_ENABLE_STATIC, [dnl
+define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
+])
+
+# AC_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)])
+
+
+# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
+# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
+# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
+# `yes'.
+AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl
+define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(fast-install,
+changequote(<<, >>)dnl
+<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
+changequote([, ])dnl
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_fast_install=yes ;;
+no) enable_fast_install=no ;;
+*)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+ for pkg in $enableval; do
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac],
+enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
+])
+
+# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install
+AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)])
+
+# AC_PROG_LD - find the path to the GNU or non-GNU linker
+AC_DEFUN(AC_PROG_LD,
+[AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by GCC])
+ ac_prog=`($CC -print-prog-name=ld) 2>&5`
+ case "$ac_prog" in
+ # Accept absolute paths.
+changequote(,)dnl
+ [\\/]* | [A-Za-z]:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+changequote([,])dnl
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(ac_cv_path_LD,
+[if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ ac_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+ test "$with_gnu_ld" != no && break
+ else
+ test "$with_gnu_ld" != yes && break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+else
+ ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])
+
+AC_DEFUN(AC_PROG_LD_GNU,
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+ ac_cv_prog_gnu_ld=yes
+else
+ ac_cv_prog_gnu_ld=no
+fi])
+])
+
+# AC_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN(AC_PROG_NM,
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(ac_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ ac_cv_path_NM="$NM"
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+ ac_cv_path_NM="$ac_dir/nm -B"
+ break
+ elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+ ac_cv_path_NM="$ac_dir/nm -p"
+ break
+ else
+ ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+fi])
+NM="$ac_cv_path_NM"
+AC_MSG_RESULT([$NM])
+])
+
+# AC_CHECK_LIBM - check for math library
+AC_DEFUN(AC_CHECK_LIBM,
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case "$lt_target" in
+*-*-beos* | *-*-cygwin*)
+ # These system don't have libm
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, main, LIBM="-lm")
+ ;;
+esac
+])
+
+# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl convenience library, adds --enable-ltdl-convenience to
+# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
+# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
+# to be `${top_builddir}/libltdl'. Make sure you start DIR with
+# '${top_builddir}/' (note the single quotes!) if your package is not
+# flat, and, if you're not using automake, define top_builddir as
+# appropriate in the Makefiles.
+AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ case "$enable_ltdl_convenience" in
+ no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+ "") enable_ltdl_convenience=yes
+ ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+ esac
+ LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la
+ INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
+])
+
+# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
+# the libltdl installable library, and adds --enable-ltdl-install to
+# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
+# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
+# to be `${top_builddir}/libltdl'. Make sure you start DIR with
+# '${top_builddir}/' (note the single quotes!) if your package is not
+# flat, and, if you're not using automake, define top_builddir as
+# appropriate in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ AC_CHECK_LIB(ltdl, main,
+ [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+ [if test x"$enable_ltdl_install" = xno; then
+ AC_MSG_WARN([libltdl not installed, but installation disabled])
+ else
+ enable_ltdl_install=yes
+ fi
+ ])
+ if test x"$enable_ltdl_install" = x"yes"; then
+ ac_configure_args="$ac_configure_args --enable-ltdl-install"
+ LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la
+ INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
+ else
+ ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+ LIBLTDL="-lltdl"
+ INCLTDL=
+ fi
+])
+
+dnl old names
+AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl
+AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl
+AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl
+AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl
+AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl
+AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl
+AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl
+
+dnl This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])dnl
diff --git a/source/aparser/Makefile b/source/aparser/Makefile
new file mode 100644
index 00000000000..953743b234d
--- /dev/null
+++ b/source/aparser/Makefile
@@ -0,0 +1,17 @@
+CFLAGS=-Wall -g
+CC=gcc
+
+OBJ = vluke.o parser.o
+AWKPROGS=dump.awk harness.awk header.awk parsefn.awk main.awk parsetree.awk template.awk util.awk
+
+all: test.h vluke
+
+test.h : $(AWKPROGS)
+ igawk -f main.awk srvsvc.struct
+
+vluke: test.h $(OBJ)
+ $(CC) $(CFLAGS) -o vluke $(OBJ)
+
+clean:
+ rm -f *.o test.h prs_*.[ch]
+
diff --git a/source/aparser/build b/source/aparser/build
new file mode 100755
index 00000000000..4cdf2901f80
--- /dev/null
+++ b/source/aparser/build
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+file=$1
+
+if ! igawk -f main.awk $file; then
+ echo parse failed;
+ exit 1;
+fi
+
+echo compiling vluke
+gcc -Wall -g -o vluke parser.c vluke.c util.c
+echo done.
+
diff --git a/source/aparser/cifs.struct b/source/aparser/cifs.struct
new file mode 100644
index 00000000000..202f0d7e619
--- /dev/null
+++ b/source/aparser/cifs.struct
@@ -0,0 +1,1029 @@
+module cifs
+
+option autoalign False
+
+
+#define BOOL uint32
+#define UCHAR uint8
+#define WCHAR uint16
+#define USHORT uint16
+#define LONG uint32
+#define ULONG uint32
+#define DWORD uint32
+#define SMB_TIME uint16
+#define SMB_DATE uint16
+
+typedef struct {
+ ULONG low;
+ LONG high;
+} TIME;
+
+typedef struct {
+ ULONG low;
+ ULONG high;
+} hyper;
+
+typedef struct {
+ uint8 cmd;
+ uint8 reserved;
+ uint16 offset;
+} ANDX_INFO;
+
+
+typedef struct {
+ uint8 tag2;
+ STRING protocol;
+} BUF2;
+
+typedef struct {
+ uint16 bcount;
+ BUF2 protocol[*];
+} Q_NEGPROT_0;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 0 Q_NEGPROT_0 q0;
+ }
+} Q_NEGPROT;
+
+typedef struct {
+ USHORT DialectIndex; /* Index of selected dialect */
+ USHORT SecurityMode; /* Security mode: */
+ /* bit 0: 0 = share, 1 = user */
+ /* bit 1: 1 = use challenge/response */
+ /* authentication */
+ USHORT MaxBufferSize; /* Max transmit buffer size (>= 1024) */
+ USHORT MaxMpxCount; /* Max pending multiplexed requests */
+ USHORT MaxNumberVcs; /* Max VCs between client and server */
+ USHORT RawMode; /* Raw modes supported: */
+ /* bit 0: 1 = Read Raw supported */
+ /* bit 1: 1 = Write Raw supported */
+ ULONG SessionKey; /* Unique token identifying this session */
+ SMB_TIME ServerTime; /* Current time at server */
+ SMB_DATE ServerDate; /* Current date at server */
+ USHORT ServerTimeZone; /* Current time zone at server */
+ USHORT ChallengeLength; /* Length of Challenge; MBZ if not LM2.1
+ /* dialect or later */
+ USHORT Reserved; /* MBZ */
+ USHORT ByteCount; /* Count of data bytes */
+ UCHAR Challenge[ChallengeLength]; /* The challenge */
+ STRING PrimaryDomain; /* The server's primary domain */
+
+} R_NEGPROT_12;
+
+typedef struct {
+ USHORT DialectIndex; /*Index of selected dialect */
+ UCHAR SecurityMode; /*Security mode: */
+ /* bit 0: 0 = share, 1 = user */
+ /* bit 1: 1 = use challenge/response */
+ /* authentication */
+ /* bit 2: 1 = Security Signatures (SMB integrity */
+ /* check) enabled */
+ /* bit 3: 1 = Security Signatures (SMB integrity */
+ /* check) required */
+ USHORT MaxMpxCount; /*Max pending outstanding requests */
+ USHORT MaxNumberVcs; /*Max VCs between client and server */
+ ULONG MaxBufferSize; /*Max transmit buffer size */
+ ULONG MaxRawSize; /*Maximum raw buffer size */
+ ULONG SessionKey; /*Unique token identifying this session */
+ ULONG Capabilities; /*Server capabilities */
+ ULONG SystemTimeLow; /*System (UTC) time of the server (low). */
+ ULONG SystemTimeHigh; /*System (UTC) time of the server (high). */
+ USHORT ServerTimeZone;/*Time zone of server (minutes from UTC) */
+ UCHAR SecurityBlobLength;/*Length of SecurityBlob */
+
+ USHORT bcount; /*Count of data bytes */
+ /*UCHAR GUID[16]; A globally unique identifier assigned to the */
+ /* server; present only when */
+ /* CAP_EXTENDED_SECURITY is on in the */
+ /* Capabilities field. */
+ UCHAR SecurityBlob[SecurityBlobLength]; /*Opaque Security Blob associated with the */
+ /* security package if CAP_EXTENDED_SECURITY is */
+ /* on in the Capabilities field; else challenge */
+ /* for CIFS challenge/response authentication. */
+ STRING OemDomainName[+]; /*The name of the domain (in OEM chars); not */
+ /* present if CAP_EXTENDED_SECURITY is on in the */
+ /* Capabilities field */
+} R_NEGPROT_17;
+
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 17 R_NEGPROT_17 r17;
+ }
+} R_NEGPROT;
+
+typedef struct {
+ uint8 wcount;
+ uint16 vwv[wcount];
+ uint16 bcount;
+ uint8 none[bcount];
+} Q_TDIS;
+
+typedef struct {
+ uint8 wcount;
+ uint16 vwv[wcount];
+ uint16 bcount;
+ uint8 none[bcount];
+} R_TDIS;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 bcount;
+ uint8 none[bcount];
+} R_ULOGOFF_ANDX_2;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 2 R_ULOGOFF_ANDX_2 q2;
+ }
+} R_ULOGOFF_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 bcount;
+ uint8 none[bcount];
+} Q_ULOGOFF_ANDX_2;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 2 Q_ULOGOFF_ANDX_2 q2;
+ }
+} Q_ULOGOFF_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 bufsize;
+ uint16 max_mpx;
+ uint16 vc;
+ ULONG sess_key;
+ uint16 pwlen;
+ ULONG reserved;
+
+ uint16 bcount;
+ uint8 password[pwlen];
+ STRING domain;
+ STRING os;
+ STRING server;
+
+} Q_SESSION_SETUP_ANDX_10;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 bufsize;
+ uint16 max_mpx;
+ uint16 vc;
+ ULONG sess_key;
+ uint16 pwlen;
+ uint16 upwlen;
+ ULONG capabilities;
+ ULONG reserved;
+
+ uint16 bcount;
+ uint8 password[pwlen];
+ uint8 upassword[upwlen];
+ STRING user;
+ STRING domain;
+ STRING os;
+ STRING server;
+
+} Q_SESSION_SETUP_ANDX_13;
+
+typedef struct _Q_SESSION_SETUP_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 10 Q_SESSION_SETUP_ANDX_10 q10;
+ case 13 Q_SESSION_SETUP_ANDX_13 q13;
+ }
+} Q_SESSION_SETUP_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 vwv2;
+ uint16 passlen;
+ uint16 bcount;
+ uint8 password[passlen];
+ STRING path;
+ STRING device;
+} Q_TCON_ANDX_4;
+
+typedef struct _Q_TCON_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 4 Q_TCON_ANDX_4 q4;
+ }
+} Q_TCON_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 vwv2;
+ uint16 bcount;
+ STRING share;
+} R_TCON_ANDX_3;
+
+typedef struct _R_TCON_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 3 R_TCON_ANDX_3 q3;
+ }
+} R_TCON_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint16 action;
+
+ uint16 count;
+ STRING os;
+ STRING server;
+ STRING domain;
+} R_SESSION_SETUP_ANDX_10;
+
+typedef struct _R_SESSION_SETUP_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 3 R_SESSION_SETUP_ANDX_10 r3;
+ }
+} R_SESSION_SETUP_ANDX;
+
+
+typedef struct _R_CLOSE {
+ uint8 wcount;
+ uint16 count;
+ uint8 none[count];
+
+} R_CLOSE;
+
+typedef struct _Q_CLOSE {
+ uint8 wcount;
+ uint16 fnum;
+ uint32 vwv1;
+
+ uint16 count;
+ uint8 none[count];
+
+} Q_CLOSE;
+
+typedef struct {
+ uint16 dsize;
+ uint16 bsizehi;
+ uint16 bsizelo;
+ uint16 avail;
+ uint16 vwv4;
+
+ uint16 bcount;
+ uint8 none[bcount];
+
+} R_DSKATTR_5;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 5 R_DSKATTR_5 r5;
+ }
+} R_DSKATTR;
+
+typedef struct {
+ uint16 count;
+ uint8 none[count];
+
+} Q_DSKATTR_0;
+
+typedef struct _Q_DSKATTR {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 0 Q_DSKATTR_0 q1;
+ }
+
+} Q_DSKATTR;
+
+typedef struct {
+ ANDX_INFO andx;
+
+ uint16 bcount;
+ uint8 none[bcount];
+
+} R_LOCKING_2;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 2 R_LOCKING_2 r2;
+ }
+} R_LOCKING_ANDX;
+
+/* XXXX must do a switch on bit 0x10 to do large locks XXXX */
+/* LockType Flag Name Value Description */
+
+#define LOCKING_ANDX_SHARED_LOCK 0x01 /* Read-only lock */
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02 /* Oplock break notification */
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 /* Change lock type */
+#define LOCKING_ANDX_CANCEL_LOCK 0x08 /* Cancel outstanding request */
+#define LOCKING_ANDX_LARGE_FILES 0x10 /* Large file locking format */
+
+typedef struct {
+ USHORT Pid; /* PID of process "owning" lock */
+ ULONG Offset; /* Offset to bytes to [un]lock */
+ ULONG Length; /* Number of bytes to [un]lock */
+} LOCKING_ANDX_RANGE_SHORT;
+
+typedef struct {
+ USHORT Pid; /* PID of process "owning" lock */
+ .align4 0;
+ ULONG OffsetHigh; /* Offset to bytes to [un]lock (high) */
+ ULONG OffsetLow; /* Offset to bytes to [un]lock (low) */
+ ULONG LengthHigh; /* Number of bytes to [un]lock (high) */
+ ULONG LengthLow; /* Number of bytes to [un]lock (low) */
+
+} LOCKING_ANDX_RANGE_LARGE;
+
+/* typedef struct { */
+ /* union ctr[LockType&0x10] { */
+ /* case 0 LOCKING_ANDX_RANGE_SHORT ls; */
+ /* case 0x10 LOCKING_ANDX_RANGE_LARGE ll; */
+ /* } */
+/* } LOCKING_ANDX_RANGE; */
+
+typedef struct {
+ ANDX_INFO andx;
+
+ USHORT Fid; /* File handle */
+ UCHAR LockType; /* See LockType table below */
+ UCHAR OplockLevel; /* The new oplock level */
+ ULONG Timeout; /* Milliseconds to wait for unlock */
+ USHORT NumberOfUnlocks; /* Num. unlock range structs following */
+ USHORT NumberOfLocks; /* Num. lock range structs following */
+
+ USHORT ByteCount; /* Count of data bytes */
+ LOCKING_ANDX_RANGE_SHORT Unlocks[NumberOfUnlocks]; /* Unlock ranges */
+ LOCKING_ANDX_RANGE_SHORT Locks[NumberOfLocks]; /* Lock ranges */
+
+} Q_LOCKING_8;
+
+typedef struct _Q_LOCKING {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 8 Q_LOCKING_8 q8;
+ }
+
+} Q_LOCKING_ANDX;
+
+
+typedef struct {
+ uint16 bcount;
+ uint8 protocols[bcount];
+
+} R_UNLINK_0;
+
+typedef struct {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 0 R_UNLINK_0 r0;
+ }
+} R_UNLINK;
+
+typedef struct {
+ uint16 dirtype;
+
+ uint16 count;
+ uint8 fname[count];
+
+} Q_UNLINK_1;
+
+typedef struct _Q_UNLINK {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 1 Q_UNLINK_1 q1;
+ }
+
+} Q_UNLINK;
+
+typedef struct _R_OPEN_ANDX{
+ uint8 wcount;
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint16 fmode;
+ uint32 mtime;
+ uint32 size;
+ uint16 rmode;
+ uint16 vwv9;
+ uint16 vwv10;
+ uint16 smb_action;
+ uint16 vwv12;
+ uint16 vwv13;
+ uint16 vwv14;
+
+ uint16 count;
+ uint8 none[count];
+
+} R_OPEN_ANDX;
+
+typedef struct _Q_OPEN_ANDX{
+ uint8 wcount;
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint16 fmode;
+ uint32 mtime;
+ uint32 size;
+ uint16 rmode;
+ uint16 vwv9;
+ uint16 vwv10;
+ uint16 smb_action;
+ uint16 vwv12;
+ uint16 vwv13;
+ uint16 vwv14;
+
+ uint16 count;
+ uint8 fname[count];
+
+} Q_OPEN_ANDX;
+
+typedef struct _R_READ_ANDX {
+ uint8 wcount;
+ ANDX_INFO andx;
+ uint16 vwv2;
+ uint16 vwv3;
+ uint16 vwv4;
+ uint16 nread;
+ uint16 offset;
+ uint16 vwv7;
+ uint16 vwv8;
+ uint16 vwv9;
+ uint16 vwv10;
+ uint16 vwv11;
+
+ uint16 count;
+ uint8 data[count];
+
+} R_READ_ANDX;
+
+typedef struct _Q_READ_ANDX_10 {
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint32 startpos;
+ uint16 smb_maxcnt;
+ uint16 smb_mincnt;
+ uint16 vwv7;
+ uint16 vwv8;
+ uint16 vwv9;
+
+ uint16 count;
+ uint8 none[count];
+
+} Q_READ_ANDX_10;
+
+typedef struct _Q_READ_ANDX_12 {
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint32 startpos;
+ uint16 smb_maxcnt;
+ uint16 smb_mincnt;
+ uint16 vwv7;
+ uint16 vwv8;
+ uint16 vwv9;
+ uint32 startposhi;
+
+ uint16 count;
+ uint8 none[count];
+
+} Q_READ_ANDX_12;
+
+typedef struct _Q_READ_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 10 Q_READ_ANDX_10 q10;
+ case 12 Q_READ_ANDX_12 q12;
+ }
+} Q_READ_ANDX;
+
+typedef struct _R_WRITE_ANDX {
+ uint8 wcount;
+ ANDX_INFO andx;
+ uint16 nwritten;
+ uint16 vwv3;
+ uint16 vwv4;
+ uint16 vwv5;
+
+ uint16 count;
+ uint8 none[count];
+
+} R_WRITE_ANDX;
+
+typedef struct _Q_WRITE_ANDX_12 {
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint32 startpos;
+ uint16 vwv5;
+ uint16 vwv6;
+ uint16 write_through;
+ uint16 vwv8;
+ uint16 vwv9;
+ uint16 numtowrite;
+ uint16 smb_doff;
+
+ uint16 count;
+ uint8 data[count];
+
+} Q_WRITE_ANDX_12;
+
+typedef struct _Q_WRITE_ANDX_14 {
+ ANDX_INFO andx;
+ uint16 fnum;
+ uint32 startpos;
+ uint16 vwv5;
+ uint16 vwv6;
+ uint16 write_through;
+ uint16 vwv8;
+ uint16 vwv9;
+ uint16 numtowrite;
+ uint16 smb_doff;
+ uint32 startposhi;
+
+ uint16 count;
+ uint8 data[count];
+
+} Q_WRITE_ANDX_14;
+
+typedef struct _Q_WRITE_ANDX {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 12 Q_WRITE_ANDX_12 q12;
+ case 14 Q_WRITE_ANDX_14 q14;
+ }
+} Q_WRITE_ANDX;
+
+
+
+typedef struct _Q_NTTRANS_19 {
+ UCHAR MaxSetupCount; /* Max setup words to return */
+ USHORT Reserved;
+ ULONG TotalParameterCount; /* Total parameter bytes being sent */
+ ULONG TotalDataCount; /* Total data bytes being sent */
+ ULONG MaxParameterCount; /* Max parameter bytes to return */
+ ULONG MaxDataCount; /* Max data bytes to return */
+ ULONG ParameterCount; /* Parameter bytes sent this buffer */
+ ULONG ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ ULONG DataCount; /* Data bytes sent this buffer */
+ ULONG DataOffset; /* Offset (from header start) to data */
+ UCHAR SetupCount; /* Count of setup words */
+ USHORT Function; /* The transaction function code */
+ UCHAR Buffer[1];
+ USHORT Setup[SetupCount]; /* Setup words */
+ USHORT ByteCount; /* Count of data bytes */
+ .align4 0;
+ UCHAR Parameters[ParameterCount];/* Parameter bytes */
+ .align4 0;
+ UCHAR Data[DataCount]; /* Data bytes */
+
+} Q_NTTRANS_19;
+
+typedef struct _Q_NTTRANS {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 19 Q_NTTRANS_19 q19;
+ }
+} Q_NTTRANS;
+
+typedef struct _R_NTTRANS_18 {
+ UCHAR Reserved[3];
+ ULONG TotalParameterCount; /* Total parameter bytes being sent */
+ ULONG TotalDataCount; /* Total data bytes being sent */
+ ULONG ParameterCount; /* Parameter bytes sent this buffer */
+ ULONG ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ ULONG ParameterDisplacement; /* Specifies the offset from the start */
+ /* of the overall parameter block to */
+ /* the parameter bytes that are */
+ /* contained in this message */
+ ULONG DataCount; /* Data bytes sent this buffer */
+ ULONG DataOffset; /* Offset (from header start) to data */
+ ULONG DataDisplacement; /* Specifies the offset from the start */
+ /* of the overall data block to the */
+ /* data bytes that are contained in */
+ /* this message. */
+ UCHAR SetupCount; /* Count of setup words */
+ USHORT Setup[SetupCount]; /* Setup words */
+ USHORT ByteCount; /* Count of data bytes */
+ .align4 0;
+ UCHAR Parameters[ParameterCount]; /* Parameter bytes */
+ .align4 0;
+ UCHAR Data[DataCount]; /* Data bytes */
+} R_NTTRANS_18;
+
+typedef struct _R_NTTRANS {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 18 R_NTTRANS_18 q18;
+ }
+ .align4 2;
+} R_NTTRANS;
+
+/*Setup[0] Transaction2 Value Description */
+/*Subcommand Code */
+/*=============================== ===== ============================= */
+
+#define TRANS2_OPEN2 0x00 /* Create file with extended attributes */
+#define TRANS2_FIND_FIRST2 0x01 /* Begin search for files */
+#define TRANS2_FIND_NEXT2 0x02 /* Resume search for files */
+#define TRANS2_QUERY_FS_INFO 0x03 /* Get file system information
+#define TRANS2_RESERVED4 0x04 /* Reserved */
+#define TRANS2_QUERY_PATH_INFO 0x05 /* Get information about a named file or directory */
+#define TRANS2_SET_PATH_INFO 0x06 /* Set information about a named file or directory */
+#define TRANS2_QUERY_FILE_INFO 0x07 /* Get information about a handle */
+#define TRANS2_SET_FILE_INFO 0x08 /* Set information by handle */
+#define TRANS2_FSCTL 0x09 /* Not implemented by NT server */
+#define TRANS2_IOCTL2 0x0A /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_FIRST 0x0B /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_NEXT 0x0C /* Not implemented by NT server */
+#define TRANS2_CREATE_DIRECTORY 0x0D /* Create directory with extended attributes */
+#define TRANS2_SESSION_SETUP 0x0E /* Session setup with extended security information */
+#define TRANS2_GET_DFS_REFERRAL 0x10 /* Get a DFS referral */
+#define TRANS2_REPORT_DFS_INCONSISTENCY 0x11 /* Report a DFS knowledge inconsistency */
+
+typedef struct {
+ USHORT InformationLevel; /* Level of information requested */
+} TRANS2_QUERY_FS_INFO_STRUCT;
+
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EA_SIZE 2
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+
+
+typedef struct {
+ hyper CreationTime;
+ hyper LastAccessTime;
+ hyper LastWriteTime;
+ hyper ChangeTime;
+ USHORT Attributes;
+ .align4 0;
+} SMB_QUERY_FILE_BASIC_INFO_STRUCT;
+
+
+typedef struct {
+ ULONG fs_atr;
+ LONG max_len_filename;
+ ULONG length;
+ uint8 fs[length];
+ .align4 2;
+} SMB_QUERY_FS_ATTRIBUTE_INFO_STRUCT;
+
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_PRSISTENT_ACLS 0x00000004
+#define FILE_FILE_COMPRESSION 0x00000008
+#define FILE_VOLUME_QUOTAS 0x00000010
+#define FILE_DEVICE_IS_MOUNTED 0x00000020
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+
+typedef struct {
+ USHORT Fid;
+ USHORT InformationLevel;
+ USHORT Reserved;
+ .align4 0;
+
+ union ctr[InformationLevel] {
+ case 0x101 SMB_QUERY_FILE_BASIC_INFO_STRUCT t101;
+ }
+
+} TRANS2_SET_FILE_INFO_STRUCT;
+
+typedef struct {
+ USHORT InformationLevel; /* Level of information requested */
+ ULONG Reserved; /* Must be zero */
+ STRING FileName; /* File or directory name */
+} TRANS2_QUERY_PATH_INFO_STRUCT;
+
+typedef struct {
+ USHORT SearchAttributes;
+ USHORT SearchCount;
+ USHORT Flags;
+ USHORT InformationLevel;
+ ULONG SearchStorageType;
+ STRING FileName;
+} TRANS2_FIND_FIRST2_STRUCT;
+
+typedef struct _Q_TRANS2_15 {
+ USHORT TotalParameterCount; /* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT MaxParameterCount; /* Max parameter bytes to return */
+ USHORT MaxDataCount; /* Max data bytes to return */
+ UCHAR MaxSetupCount; /* Max setup words to return */
+ UCHAR Reserved;
+ USHORT Flags; /* Additional information: */
+ /* bit 0 - also disconnect TID in TID */
+ ULONG Timeout;
+ USHORT Reserved2;
+ USHORT ParameterCount; /* Parameter bytes sent this buffer */
+ USHORT ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from header start) to data */
+ UCHAR SetupCount; /* Count of setup words */
+ UCHAR Reserved3; /* Reserved (pad above to word) */
+ USHORT Setup[SetupCount]; /* Setup words (# = SetupWordCount) */
+ USHORT ByteCount; /* Count of data bytes */
+ .align4 0;
+ union ctr[Setup[0]] {
+ case 1 TRANS2_FIND_FIRST2_STRUCT t1;
+ case 3 TRANS2_QUERY_FS_INFO_STRUCT t3;
+ case 5 TRANS2_QUERY_PATH_INFO_STRUCT t5;
+ case 8 TRANS2_SET_FILE_INFO_STRUCT t8;
+ }
+
+} Q_TRANS2_15;
+
+typedef struct _Q_TRANS2 {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 15 Q_TRANS2_15 q15;
+ }
+} Q_TRANS2;
+
+typedef struct {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ hyper CreationTime;
+ hyper LastAccessTime;
+ hyper LastWriteTime;
+ hyper ChangeTime;
+ hyper EndOfFile;
+ hyper AllocationSize;
+ ULONG ExtFileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ UCHAR ShortNameLength;
+ UCHAR Reserved;
+ uint8 ShortName[24];
+ UCHAR FileName[FileNameLength];
+ .align4 2;
+} SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
+
+typedef struct {
+ .align2 0;
+} R_TRANS2_D0;
+
+typedef struct {
+ .align4 2;
+} R_TRANS2_P0;
+
+typedef struct {
+ USHORT Reserved;
+} R_TRANS2_P2;
+
+typedef struct {
+ USHORT Sid; /* Search handle */
+ USHORT SearchCount; /* Number of entries returned */
+ USHORT EndOfSearch; /* Was last entry returned? */
+ USHORT EaErrorOffset; /* Offset into EA list if EA error */
+ USHORT LastNameOffset; /* Offset into data to file name of last */
+ /* entry, if server needs it to resume */
+ /* search; else 0 */
+ .align4 2;
+ SMB_FIND_FILE_BOTH_DIRECTORY_INFO i104[SearchCount];
+} R_TRANS2_FIND_FIRST2_STRUCT;
+
+typedef struct {
+ SMB_QUERY_FILE_BASIC_INFO_STRUCT i101;
+ .align4 2;
+} R_TRANS2_FILE_BASIC_STRUCT;
+
+typedef struct _R_TRANS2_10 {
+ USHORT TotalParameterCount;/* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT Reserved2;
+ USHORT ParameterCount; /* Parameter bytes sent this buffer */
+ USHORT ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ USHORT ParameterDisplacement; /* Specifies the offset from the start */
+ /* of the overall parameter block to */
+ /* the parameter bytes that are */
+ /* contained in this message */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from header start) to data */
+ USHORT DataDisplacement; /* Specifies the offset from the start */
+ /* of the overall data block to the */
+ /* data bytes that are contained in */
+ /* this message. */
+ UCHAR SetupCount; /* Count of setup words */
+ UCHAR Reserved3; /* Reserved (pad above to word) */
+ USHORT Setup[SetupCount]; /* Setup words */
+ USHORT ByteCount; /* Count of data bytes */
+ .align4 2;
+ union pctr[ParameterCount] {
+ case 0 R_TRANS2_P0 p0;
+ case 2 R_TRANS2_P2 p2;
+ case 10 R_TRANS2_FIND_FIRST2_STRUCT r10;
+ }
+ union dctr[DataCount] {
+ case 0 R_TRANS2_D0 d0;
+ case 0x24 R_TRANS2_FILE_BASIC_STRUCT r24;
+ case 0x14 SMB_QUERY_FS_ATTRIBUTE_INFO_STRUCT r14;
+ }
+} R_TRANS2_10;
+
+typedef struct {
+ USHORT ByteCount; /* Count of data bytes */
+} R_TRANS2_0;
+
+typedef struct _R_TRANS2 {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 0 R_TRANS2_0 q0;
+ case 10 R_TRANS2_10 q10;
+ }
+} R_TRANS2;
+
+typedef struct _Q_TRANS_16 {
+ USHORT TotalParameterCount; /* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT MaxParameterCount; /* Max parameter bytes to return */
+ USHORT MaxDataCount; /* Max data bytes to return */
+ UCHAR MaxSetupCount; /* Max setup words to return */
+ UCHAR Reserved;
+ USHORT Flags; /* Additional information: */
+ /* bit 0 - also disconnect TID in TID */
+ ULONG Timeout;
+ USHORT Reserved2;
+ USHORT ParameterCount; /* Parameter bytes sent this buffer */
+ USHORT ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from header start) to data */
+ UCHAR SetupCount; /* Count of setup words */
+ UCHAR Reserved3; /* Reserved (pad above to word) */
+ USHORT Setup[SetupCount]; /* Setup words (# = SetupWordCount) */
+ USHORT ByteCount; /* Count of data bytes */
+ STRING Name; /* Must be NULL */
+ .align4 0;
+ UCHAR Parameters[ParameterCount];/* Parameter bytes (# = ParameterCount) */
+ .align4 0;
+ UCHAR Data[DataCount]; /* Data bytes (# = DataCount) */
+
+} Q_TRANS_16;
+
+typedef struct _Q_TRANS {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 16 Q_TRANS_16 q16;
+ }
+} Q_TRANS;
+
+typedef struct _R_TRANS_10 {
+ USHORT TotalParameterCount;/* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT Reserved2;
+ USHORT ParameterCount; /* Parameter bytes sent this buffer */
+ USHORT ParameterOffset; /* Offset (from header start) to */
+ /* Parameters */
+ USHORT ParameterDisplacement; /* Specifies the offset from the start */
+ /* of the overall parameter block to */
+ /* the parameter bytes that are */
+ /* contained in this message */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from header start) to data */
+ USHORT DataDisplacement; /* Specifies the offset from the start */
+ /* of the overall data block to the */
+ /* data bytes that are contained in */
+ /* this message. */
+ UCHAR SetupCount; /* Count of setup words */
+ UCHAR Reserved3; /* Reserved (pad above to word) */
+ USHORT Setup[SetupCount]; /* Setup words */
+ USHORT ByteCount; /* Count of data bytes */
+ .align4 0;
+ UCHAR Parameters[ParameterCount];/* Parameter bytes */
+ .align4 0;
+ UCHAR Data[DataCount]; /* Data bytes */
+} R_TRANS_10;
+
+typedef struct _R_TRANS {
+ uint8 wcount;
+ union ctr[wcount] {
+ case 10 R_TRANS_10 q10;
+ }
+} R_TRANS;
+
+typedef struct _Q_NT_CREATE_ANDX_24 {
+ ANDX_INFO andx;
+ uint8 reserved;
+ uint16 name_len;
+ ULONG flags;
+ ULONG rootfid;
+ ULONG access;
+ hyper allocsize;
+ ULONG attribs;
+ ULONG sharing;
+ ULONG creat_disp;
+ ULONG creat_options;
+ ULONG impersonation;
+ uint8 sec_flags;
+
+ uint16 count;
+ uint8 name[name_len];
+
+} Q_NTCREATE_ANDX_24;
+
+typedef struct _Q_NTCREATE_ANDX{
+ uint8 wcount;
+ union ctr[wcount] {
+ case 24 Q_NTCREATE_ANDX_24 q24;
+ }
+} Q_NTCREATE_ANDX;
+
+typedef struct {
+ ANDX_INFO andx;
+ uint8 oplock_level;
+ uint16 fid;
+ ULONG action;
+ TIME create_time;
+ TIME access_time;
+ TIME write_time;
+ TIME change_time;
+ ULONG ext_attribs;
+ hyper allocsize;
+ hyper size;
+ uint16 type;
+ uint16 state;
+ uint8 directory;
+
+ uint16 count;
+ uint8 none[count];
+
+} R_NTCREATE_ANDX_34;
+
+typedef struct _R_NTCREATE_ANDX{
+ uint8 wcount;
+ union ctr[wcount] {
+ case 34 R_NTCREATE_ANDX_34 q34;
+ }
+} R_NTCREATE_ANDX;
+
+typedef struct {
+ ULONG smbhdr;
+ uint8 com;
+ uint8 rcls;
+ uint8 reh;
+ uint16 err;
+ uint8 flg;
+ uint16 flg2;
+ uint16 reserved;
+ uint8 SecuritySignature[8];
+ uint16 pad;
+ uint16 tid;
+ uint16 pid;
+ uint16 uid;
+ uint16 mid;
+} SMB_HDR;
+
+typedef struct _R_SMB {
+ ULONG nbhdr;
+ SMB_HDR hdr;
+ union ctr[hdr.com] {
+ case 4 R_CLOSE r4;
+ case 6 R_UNLINK r6;
+ case 36 R_LOCKING_ANDX r36;
+ case 37 R_TRANS r37;
+ case 45 R_OPEN_ANDX r45;
+ case 46 R_READ_ANDX r46;
+ case 47 R_WRITE_ANDX r47;
+ case 50 R_TRANS2 q50;
+ case 113 R_TDIS r113;
+ case 114 R_NEGPROT r114;
+ case 115 R_SESSION_SETUP_ANDX r115;
+ case 116 R_ULOGOFF_ANDX r116;
+ case 117 R_TCON_ANDX r117;
+ case 128 R_DSKATTR r128;
+ case 160 R_NTTRANS r160;
+ case 162 R_NTCREATE_ANDX r162;
+ }
+} R_SMB;
+
+typedef struct _Q_SMB {
+ ULONG nbhdr;
+ SMB_HDR hdr;
+ union ctr[hdr.com] {
+ case 4 Q_CLOSE q4;
+ case 6 Q_UNLINK q6;
+ case 36 Q_LOCKING_ANDX q36;
+ case 37 Q_TRANS q37;
+ case 45 Q_OPEN_ANDX q45;
+ case 46 Q_READ_ANDX q46;
+ case 47 Q_WRITE_ANDX q47;
+ case 50 Q_TRANS2 q50;
+ case 113 Q_TDIS q113;
+ case 114 Q_NEGPROT q114;
+ case 115 Q_SESSION_SETUP_ANDX q115;
+ case 116 Q_ULOGOFF_ANDX q116;
+ case 117 Q_TCON_ANDX q117;
+ case 128 Q_DSKATTR q128;
+ case 160 Q_NTTRANS q160;
+ case 162 Q_NTCREATE_ANDX q162;
+ }
+} Q_SMB;
+
diff --git a/source/aparser/dump.awk b/source/aparser/dump.awk
new file mode 100644
index 00000000000..11bfb107e46
--- /dev/null
+++ b/source/aparser/dump.awk
@@ -0,0 +1,70 @@
+# dump the current parse tree
+
+
+function element_string(elnum,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ if (elements[elnum, "ptr"]=="1") elem="*"elem;
+ if (elements[elnum, "array_len"]!="")
+ elem=elem"["elements[elnum, "array_len"]"]";
+ if (elements[elnum, "switch"]!="")
+ elem=elem"["elements[elnum, "switch"]"]";
+ return elem;
+}
+
+function dump_element(f, elnum,
+ LOCAL, elem, type)
+{
+ type = elements[elnum, "type"];
+ case = elements[elnum, "case"];
+ elem = element_string(elnum);
+ if (case != "") {
+ xprintf(f,"\t\tcase %d %s %s;\n", case, type, elem);
+ } else {
+ xprintf(f,"\t%s %s;\n", type, elem);
+ }
+}
+
+function dump_union(f, elnum,
+ LOCAL, i)
+{
+ xprintf(f,"\tunion %s {\n", element_string(elnum));
+ for (i=0;i<unions[elnum, "num_elems"];i++) {
+ dump_element(f, unions[elnum, i]);
+ }
+ xprintf(f,"\t}\n");
+}
+
+function dump_elem(f, struct_num, elem_num,
+ LOCAL, enum)
+{
+ elnum = structs[struct_num, elem_num];
+
+ if (elements[elnum, "type"] == "union") {
+ dump_union(f, elnum);
+ } else {
+ dump_element(f, elnum);
+ }
+}
+
+function dump_structs(f, NIL,
+ LOCAL, i, j)
+{
+ xprintf(f,"/* dump of parsed structures */\n\n\n");
+
+ for (i=0;i < num_options;i++) {
+ xprintf(f,"option %s %s\n", options[i, "name"], options[i, "value"]);
+ }
+ xprintf(f,"\n\n");
+
+ for (i=0;i < num_structs;i++) {
+ xprintf(f,"/* structure %d */\n", i);
+ xprintf(f,"struct %s {\n", structs[i, "name"]);
+ for (j=0;j<structs[i, "num_elems"];j++) {
+ dump_elem(f, i, j);
+ }
+ xprintf(f,"};\n\n");
+ }
+ xprintf(f,"/* end dump */\n\n");
+}
diff --git a/source/aparser/harness.awk b/source/aparser/harness.awk
new file mode 100644
index 00000000000..6c4c35c40f2
--- /dev/null
+++ b/source/aparser/harness.awk
@@ -0,0 +1,17 @@
+function produce_harness(f,
+ LOCAL, v, struct_num, i)
+{
+ struct_num=structs[test];
+
+ v["MODULE"]=module;
+
+ print_template(f, "harness_start.tpl", v);
+
+ for (i=0;i<num_structs;i++) {
+ v["TEST"] = structs[i, "name"];
+ print_template(f, "harness.tpl", v);
+ }
+
+ print_template(f, "harness_end.tpl", v);
+}
+
diff --git a/source/aparser/header.awk b/source/aparser/header.awk
new file mode 100644
index 00000000000..ba7117436b8
--- /dev/null
+++ b/source/aparser/header.awk
@@ -0,0 +1,80 @@
+# produce a header file for a parsed struct file
+
+function header_elstring(elnum,
+ LOCAL, elem)
+{
+ array_len = elements[elnum, "array_len"];
+ elem=elements[elnum, "elem"];
+ if (elements[elnum, "ptr"]=="1") elem="*"elem;
+ if (array_len!="") {
+ if (is_constant(array_len) == 1) {
+ elem=elem"["array_len"]";
+ } else {
+ elem="*"elem;
+ }
+ }
+ return elem;
+}
+
+function header_element(f, elnum,
+ LOCAL, type)
+{
+ type=elements[elnum, "type"];
+ if (substr(type,1,1) == ".") return;
+ xprintf(f,"\t%s %s;\n", type, header_elstring(elnum));
+}
+
+function header_union(f, elnum,
+ LOCAL, i)
+{
+ xprintf(f,"\tunion {\n");
+ for (i=0;i<unions[elnum, "num_elems"];i++) {
+ header_element(f, unions[elnum, i]);
+ }
+ xprintf(f,"\t} %s;\n", header_elstring(elnum));
+}
+
+function header_elem(f, elnum)
+{
+
+ if (elements[elnum, "type"] == "union") {
+ header_union(f, elnum);
+ } else {
+ header_element(f, elnum);
+ }
+}
+
+function header_struct(f, struct_num,
+ LOCAL, i)
+{
+ xprintf(f,"/* structure %s */\n",
+ structs[struct_num, "name"]);
+ xprintf(f,"typedef struct {\n");
+ for (i=0;i < structs[struct_num, "num_elems"];i++) {
+ header_elem(f, structs[struct_num, i]);
+ }
+ xprintf(f,"} %s;\n\n\n", structs[struct_num, "name"]);
+}
+
+
+function produce_headers(f, NIL,
+ LOCAL, i)
+{
+ xprintf(f,"/* auto-generated headers for %s */\n\n\n", module);
+ xprintf(f,"#ifndef _%s_\n", module);
+ xprintf(f,"#define _%s_\n", module);
+
+ xprintf(f,"\n\n");
+ for (i=0;i < num_options;i++) {
+ xprintf(f,"#define OPTION_%s %s\n",
+ options[i, "name"], options[i, "value"]);
+ }
+ xprintf(f,"\n\n");
+
+ for (i=0;i < num_structs;i++) {
+ header_struct(f, i);
+ }
+ xprintf(f,"/* end auto-generated headers */\n\n");
+ xprintf(f,"#endif /* _%s_ */\n", module);
+}
+
diff --git a/source/aparser/main.awk b/source/aparser/main.awk
new file mode 100644
index 00000000000..4969f2217a2
--- /dev/null
+++ b/source/aparser/main.awk
@@ -0,0 +1,25 @@
+# the main program
+
+@include dump.awk
+@include header.awk
+@include util.awk
+@include template.awk
+#@include parsefn.awk
+@include parserel.awk
+@include harness.awk
+@include parsetree.awk
+@include token.awk
+
+END {
+ dump_structs("dump.out");
+ printf("Producing headers...\n");
+ produce_headers("prs_"module".h");
+# printf("Producing parsers...\n");
+# produce_parsers("prs_"module".c", "mod_"module".c");
+ printf("Producing relative parsers...\n");
+ produce_relative("prs_"module".c");
+ printf("Producing harness...\n");
+ produce_harness("test.h");
+ printf("Done.\n");
+ exit 0;
+}
diff --git a/source/aparser/parsefn.awk b/source/aparser/parsefn.awk
new file mode 100644
index 00000000000..2bebd765e66
--- /dev/null
+++ b/source/aparser/parsefn.awk
@@ -0,0 +1,271 @@
+# build parse functions for a parsed struct file
+
+function elem_name(v, elem)
+{
+ return v["UNION"]elem;
+}
+
+function parse_array(f, v, elnum, flags,
+ LOCAL, type, elem, array_len)
+{
+ type = elements[elnum, "type"];
+ elem = elements[elnum, "elem"];
+ array_len = elements[elnum, "array_len"];
+ v["ELEM"] = elem_name(v, elem);
+ v["TYPE"] = type;
+ v["FLAGS"] = flags;
+ v["ARRAY_LEN"] = array_len;
+
+ if (array_len=="+") {
+ print_template(f,"prs_array_optional.tpl", v);
+ return;
+ }
+
+ if (array_len=="*") {
+ print_template(f,"prs_array_remainder.tpl", v);
+ return;
+ }
+
+ if (type == "wchar" || type == "uint16") {
+ if (match(array_len,"[0-9]") == 1) {
+ print_template(f, "prs_wstring_fixed.tpl", v);
+ } else {
+ print_template(f, "prs_wstring.tpl", v);
+ }
+ } else if (type == "uint8") {
+ if (match(array_len,"[0-9]") == 1) {
+ print_template(f, "prs_uint8s_fixed.tpl", v);
+ } else {
+ print_template(f, "prs_uint8s.tpl", v);
+ }
+ } else {
+ print_template(f, "prs_array.tpl", v);
+ }
+}
+
+
+function parse_element(f, v, elnum, flags,
+ LOCAL, type, elem)
+{
+ if (elements[elnum,"nowire"] != "") {
+ return;
+ }
+ type = elements[elnum, "type"];
+ if (substr(type,1,1) == ".") return;
+ elem = elements[elnum, "elem"];
+ if (elements[elnum,"ptr"] == "") {
+ v["PTR"] = "\\&";
+ } else {
+ v["PTR"] = " ";
+ }
+ v["ELEM"] = elem_name(v, elem);
+ v["TYPE"] = type;
+ v["FLAGS"] = flags;
+ print_template(f, "prs_element.tpl", v);
+}
+
+function parse_union(f, v, elnum, flags,
+ LOCAL, i)
+{
+ v["UNION"] = elements[elnum, "elem"];
+ v["SWITCH"] = elements[elnum, "switch"];
+
+ if (elements[elnum, "ptr"] == "1") {
+ v["UNION"] = v["UNION"]"->";
+ } else {
+ v["UNION"] = v["UNION"]".";
+ }
+
+ print_template(f, "union_start.tpl", v);
+ for (i=0;i<unions[elnum, "num_elems"];i++) {
+ v["CASE"] = elements[unions[elnum, i], "case"];
+ print_template(f, "prs_case.tpl", v);
+ if (elements[elnum, "ptr"] == "1") {
+ parse_scalars(f, v, unions[elnum, i], "PARSE_SCALARS");
+ parse_buffers(f, v, unions[elnum, i], "PARSE_BUFFERS");
+ } else {
+ if (flags == "PARSE_SCALARS") {
+ parse_scalars(f, v, unions[elnum, i], flags);
+ } else {
+ parse_buffers(f, v, unions[elnum, i], flags);
+ }
+ }
+ print_template(f, "prs_break.tpl", v);
+ }
+ v["UNION"] = "";
+
+ print_template(f, "union_end.tpl", v);
+}
+
+function parse_scalar(f, v, elnum, flags)
+{
+ if (elements[elnum, "type"] == "union") {
+ parse_union(f, v, elnum, flags);
+ } else if (elements[elnum, "array_len"]!="") {
+ parse_array(f, v, elnum, flags);
+ } else {
+ parse_element(f, v, elnum, flags);
+ }
+}
+
+function parse_align2(f, v, elnum, flags,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ v["OFFSET"] = elem_name(v, elem);
+ print_template(f, "prs_align2.tpl", v);
+}
+
+function parse_align4(f, v, elnum, flags,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ v["OFFSET"] = elem_name(v, elem);
+ print_template(f, "prs_align4.tpl", v);
+}
+
+function parse_pointer(f, v, elnum, flags,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ v["ELEM"] = elem_name(v, elem);
+ v["FLAGS"] = flags;
+ print_template(f, "prs_pointer.tpl", v);
+}
+
+function parse_scalar_fn(m, v, elnum,
+ LOCAL, elem, type)
+{
+ elem = elements[elnum, "elem"];
+ type = elements[elnum, "type"]
+ xprintf(m, "%s %s", type, elem_name(v, elem));
+ if (type == "union") {
+ } else if (elements[elnum, "array_len"]!="") {
+ } else {
+ }
+}
+
+function parse_pointer_fn(f, v, elnum, flags,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ v["ELEM"] = elem_name(v, elem);
+ v["FLAGS"] = flags;
+ xprintf(m, "%s\n", v["ELEM"]);
+}
+
+function parse_scalars_fn(m, v, elnum, flags)
+{
+ if (elements[elnum, "type"] == ".align2") {
+ }
+ else if (elements[elnum, "type"] == ".align4") {
+ }
+ else if (elements[elnum, "ptr"] == "1") {
+ parse_pointer_fn(m, v, elnum, flags);
+ } else {
+ parse_scalar_fn(m, v, elnum, flags);
+ }
+}
+
+function parse_scalars(f, v, elnum, flags)
+{
+ if (elements[elnum, "type"] == ".align2") {
+ parse_align2(f, v, elnum, flags);
+ }
+ else if (elements[elnum, "type"] == ".align4") {
+ parse_align4(f, v, elnum, flags);
+ }
+ else if (elements[elnum, "ptr"] == "1") {
+ parse_pointer(f, v, elnum, flags);
+ } else {
+ parse_scalar(f, v, elnum, flags);
+ }
+}
+
+function parse_buffers(f, v, elnum, flags,
+ LOCAL, elem, type)
+{
+ elem = elements[elnum, "elem"];
+ type = elements[elnum, "type"];
+ v["ELEM"] = elem_name(v, elem);
+ if (elements[elnum, "type"] == ".align2") {
+ }
+ else if (elements[elnum, "type"] == ".align4") {
+ } else if (elements[elnum, "ptr"] == "1") {
+ print_template(f, "ifptr_start.tpl", v);
+ parse_scalar(f, v, elnum, "PARSE_SCALARS|PARSE_BUFFERS");
+ print_template(f, "ifptr_end.tpl", v);
+ } else {
+ parse_scalar(f, v, elnum, flags);
+ }
+}
+
+function struct_parser(f, m, v, struct_num,
+ LOCAL, i, n1, f1, num_elems)
+{
+ f1 = -1;
+ num_elems = structs[struct_num, "num_elems"];
+ v["STRUCTNAME"] = structs[struct_num, "name"];
+ v["FUNCNAME"] = "io_" v["STRUCTNAME"];
+ print_template(f, "fn_start.tpl", v);
+
+ for (n1=0;n1<num_elems;n1++) {
+ if (elements[structs[struct_num, n1], "type"] == ".trailer") {
+ f1 = n1;
+ break;
+ }
+ }
+
+ # first all the structure pointers, scalars and arrays
+ for (i=0;i<n1;i++) {
+ parse_scalars(f, v, structs[struct_num, i], "PARSE_SCALARS");
+ }
+
+ print_template(f, "fn_mid.tpl", v);
+
+ # now the buffers
+ for (i=0;i<n1;i++) {
+ parse_buffers(f, v, structs[struct_num, i], "PARSE_BUFFERS");
+ }
+
+ # and any trailers
+ for (i=n1;i<num_elems;i++) {
+ parse_scalars(f, v, structs[struct_num, i], "PARSE_SCALARS");
+ parse_buffers(f, v, structs[struct_num, i], "PARSE_BUFFERS");
+ }
+
+ if (i > 0) {
+ print_template(f, "fn_end.tpl", v);
+ }
+ else {
+ print_template(f, "fn_end0.tpl", v);
+ }
+
+ if (f1 == -1)
+ return;
+
+ xprintf(m, "void fn_%s(\n", v["STRUCTNAME"]);
+
+ for (i=f1+1;i<num_elems;i++) {
+ parse_scalars_fn(m, v, structs[struct_num, i]);
+ if (i != num_elems-1)
+ xprintf(m, ", \n");
+
+ }
+
+ xprintf(m, ")\n{\n}\n");
+}
+
+function produce_parsers(f, m,
+ LOCAL, v, i)
+{
+ v["MODULE"]=module;
+
+ print_template(f, "module_start.tpl", v);
+
+ for (i=0;i < num_structs;i++) {
+ struct_parser(f, m, v, i);
+ }
+
+ print_template(f, "module_end.tpl", v);
+}
diff --git a/source/aparser/parser.c b/source/aparser/parser.c
new file mode 100644
index 00000000000..0c7153e1fb7
--- /dev/null
+++ b/source/aparser/parser.c
@@ -0,0 +1,471 @@
+#include "parser.h"
+
+/*******************************************************************
+ Attempt, if needed, to grow a data buffer.
+ Also depends on the data stream mode (io).
+ ********************************************************************/
+
+BOOL io_grow(io_struct *ps, uint32 extra_space)
+{
+ uint32 new_size;
+ char *new_data;
+
+ ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
+
+ if(ps->data_offset + extra_space <= ps->buffer_size)
+ return True;
+
+ /*
+ * We cannot grow the buffer if we're not reading
+ * into the io_struct, or if we don't own the memory.
+ */
+
+ if(UNMARSHALLING(ps) || !ps->is_dynamic) {
+ DEBUG(0,("io_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+ (unsigned int)extra_space));
+ return False;
+ }
+
+ /*
+ * Decide how much extra space we really need.
+ */
+
+ extra_space -= (ps->buffer_size - ps->data_offset);
+ if(ps->buffer_size == 0) {
+ new_size = extra_space;
+
+ if((new_data = malloc(new_size)) == NULL) {
+ DEBUG(0,("io_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
+ return False;
+ }
+ memset(new_data, '\0', new_size );
+ } else {
+ /*
+ * If the current buffer size is bigger than the space needed, just
+ * double it, else add extra_space.
+ */
+ new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);
+
+ if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+ DEBUG(0,("io_grow: Realloc failure for size %u.\n",
+ (unsigned int)new_size));
+ return False;
+ }
+ }
+ ps->buffer_size = new_size;
+ ps->data_p = new_data;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Ensure we can read/write to a given offset.
+ ********************************************************************/
+
+char *io_mem_get(io_struct *ps, uint32 extra_size)
+{
+ if(UNMARSHALLING(ps)) {
+ /*
+ * If reading, ensure that we can read the requested size item.
+ */
+ if (ps->data_offset + extra_size > ps->buffer_size) {
+ DEBUG(0,("io_mem_get: reading data of size %u would overrun buffer.\n",
+ (unsigned int)extra_size ));
+ return NULL;
+ }
+ } else {
+ /*
+ * Writing - grow the buffer if needed.
+ */
+ if(!io_grow(ps, extra_size))
+ return False;
+ }
+ return &ps->data_p[ps->data_offset];
+}
+
+/*******************************************************************
+ Initialise a parse structure - malloc the data if requested.
+ ********************************************************************/
+
+BOOL io_init(io_struct *ps, uint32 size, BOOL io)
+{
+ ZERO_STRUCTP(ps);
+ ps->io = io;
+ ps->bigendian_data = False;
+ ps->is_dynamic = False;
+ ps->data_offset = 0;
+ ps->buffer_size = 0;
+ ps->data_p = NULL;
+
+ if (size != 0) {
+ ps->buffer_size = size;
+ if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
+ DEBUG(0,("io_init: malloc fail for %u bytes.\n", (unsigned int)size));
+ return False;
+ }
+ ps->is_dynamic = True; /* We own this memory. */
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ debug output for parsing info.
+
+ XXXX side-effect of this function is to increase the debug depth XXXX
+
+ ********************************************************************/
+void io_debug(io_struct *ps, int depth, char *desc, char *fn_name)
+{
+ DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
+}
+
+/*******************************************************************
+ Align a the data_len to a multiple of align bytes - filling with
+ zeros.
+ ********************************************************************/
+
+BOOL io_align2(io_struct *ps, int offset)
+{
+ uint32 mod = (ps->data_offset + offset) & (2-1);
+
+ if (mod != 0) {
+ uint32 extra_space = (2 - mod);
+ if(!io_grow(ps, extra_space))
+ return False;
+ memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+ ps->data_offset += extra_space;
+ }
+
+ return True;
+}
+
+BOOL io_align4(io_struct *ps, int offset)
+{
+ uint32 mod = (ps->data_offset + offset) & (4-1);
+
+ if (mod != 0) {
+ uint32 extra_space = (4 - mod);
+ if(!io_grow(ps, extra_space))
+ return False;
+ memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+ ps->data_offset += extra_space;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Align a the data_len to a multiple of align bytes - filling with
+ zeros.
+ ********************************************************************/
+
+BOOL io_align(io_struct *ps, int align)
+{
+ uint32 mod;
+
+ if (!ps->autoalign) return True;
+
+ mod = ps->data_offset & (align-1);
+
+ if (align != 0 && mod != 0) {
+ uint32 extra_space = (align - mod);
+ if(!io_grow(ps, extra_space))
+ return False;
+ memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+ ps->data_offset += extra_space;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ read from a socket into memory.
+ ********************************************************************/
+BOOL io_read(io_struct *ps, int fd, size_t len, int timeout)
+{
+ BOOL ok;
+ size_t prev_size = ps->buffer_size;
+ if (!io_grow(ps, len))
+ {
+ return False;
+ }
+
+ if (timeout > 0)
+ {
+ ok = (read(fd, &ps->data_p[prev_size], len) == len);
+ }
+ else
+ {
+ ok = (read(fd, &ps->data_p[prev_size], len) == len);
+ }
+ return ok;
+}
+
+
+/*******************************************************************
+ do IO on a uint32.
+ ********************************************************************/
+BOOL io_uint32(char *name, io_struct *ps, int depth, uint32 *data32, unsigned flags)
+{
+ char *q;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ if (!io_align(ps, 4)) return False;
+
+ q = io_mem_get(ps, sizeof(uint32));
+ if (q == NULL) return False;
+
+ DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data32)
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+/*******************************************************************
+ do IO on a uint16.
+ ********************************************************************/
+BOOL io_uint16(char *name, io_struct *ps, int depth, uint16 *data16, unsigned flags)
+{
+ char *q;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ if (!io_align(ps, 2)) return False;
+
+ q = io_mem_get(ps, sizeof(uint16));
+ if (q == NULL) return False;
+
+ DBG_RW_SVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data16)
+ ps->data_offset += sizeof(uint16);
+
+ return True;
+}
+
+/*******************************************************************
+ do IO on a uint8.
+ ********************************************************************/
+BOOL io_uint8(char *name, io_struct *ps, int depth, uint8 *data8, unsigned flags)
+{
+ char *q;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ q = io_mem_get(ps, sizeof(uint8));
+ if (q == NULL) return False;
+
+ DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data8)
+ ps->data_offset += sizeof(uint8);
+
+ return True;
+}
+
+/*******************************************************************
+ do IO on a pointer
+ ********************************************************************/
+BOOL io_pointer(char *desc, io_struct *ps, int depth, void **p, unsigned flags)
+{
+ uint32 v;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ v = (*p) ? 0xdeadbeef : 0;
+ if (!io_uint32(desc, ps, depth, &v, flags)) return False;
+ *p = (void *) (v ? 0xdeadbeef : 0);
+ return True;
+}
+
+/*******************************************************************
+ Stream a null-terminated string.
+ ********************************************************************/
+BOOL io_SMBSTR(char *name, io_struct *ps, int depth, char **str, unsigned flags)
+{
+ char *q;
+ uint8 *start;
+ int i;
+ size_t len;
+ int start_offset = ps->data_offset;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ if (UNMARSHALLING(ps)) {
+ *str = io_mem_get(ps, 0);
+ if (*str == NULL)
+ return False;
+ len = strlen(*str);
+ ps->data_offset += len + 1;
+ }
+ else
+ {
+ len = strlen(*str)+1;
+ start = (uint8*)q;
+
+ for(i = 0; i < len; i++) {
+ q = io_mem_get(ps, 1);
+ if (q == NULL)
+ return False;
+
+ RW_CVAL(ps->io, q, (*str)[i],0);
+ ps->data_offset++;
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth),
+ start_offset, name, *str));
+ return True;
+}
+
+/******************************************************************
+ do IO on a byte array
+ ********************************************************************/
+BOOL io_uint8s(char *name, io_struct *ps, int depth, uint8 **data8s, int len, unsigned flags)
+{
+ char *q;
+ size_t num_bytes = len * sizeof(uint8);
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ q = io_mem_get(ps, num_bytes);
+ if (q == NULL) return False;
+
+ if (MARSHALLING(ps))
+ {
+ DBG_RW_PCVAL(True, name, depth, ps->data_offset, ps->io, q, *data8s, len)
+ }
+ else
+ {
+ *data8s = q;
+ dump_data(depth+5, *data8s, num_bytes);
+ }
+ ps->data_offset += num_bytes;
+
+ return True;
+}
+/******************************************************************
+ do IO on a fixed-size byte array
+ ********************************************************************/
+BOOL io_uint8s_fixed(char *name, io_struct *ps, int depth, uint8 *data8s, int len, unsigned flags)
+{
+ char *q;
+ size_t num_bytes = len * sizeof(uint8);
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ q = io_mem_get(ps, num_bytes);
+ if (q == NULL) return False;
+
+ DBG_RW_PCVAL(True, name, depth, ps->data_offset, ps->io, q, data8s, len)
+ ps->data_offset += num_bytes;
+
+ return True;
+}
+
+
+/******************************************************************
+ do IO on an io (eh?? :)
+ ********************************************************************/
+BOOL io_io_struct(char *name, io_struct *ps, int depth, io_struct *io, unsigned flags)
+{
+ char *q;
+ uint16 len;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ q = io_mem_get(ps, sizeof(uint16));
+ if (q == NULL) return False;
+
+ /* length first */
+ if (MARSHALLING(ps))
+ {
+ len = io->data_offset;
+ }
+ if (!io_uint16("len", ps, depth+1, &len, flags))
+ {
+ return False;
+ }
+ if (UNMARSHALLING(ps))
+ {
+ if (!io_init(io, len, UNMARSHALL))
+ {
+ return False;
+ }
+ }
+
+ /* now data */
+ q = io_mem_get(ps, len * sizeof(uint8));
+ if (q == NULL) return False;
+
+ if (MARSHALLING(ps))
+ {
+ DBG_RW_PCVAL(False, name, depth+1, ps->data_offset, ps->io, q, io->data_p, len)
+ }
+ else
+ {
+ io->data_p = q;
+ dump_data(depth+5, q, len);
+ }
+ ps->data_offset += len;
+
+ return True;
+}
+
+/******************************************************************
+ do IO on a unicode array
+ ********************************************************************/
+BOOL io_wstring(char *name, io_struct *ps, int depth, uint16 *data16s, int len, unsigned flags)
+{
+ char *q;
+
+ if (!(flags & PARSE_SCALARS)) return True;
+
+ if (!io_align(ps, 2)) return False;
+
+ q = io_mem_get(ps, len * sizeof(uint16));
+ if (q == NULL) return False;
+
+ DBG_RW_PSVAL(True, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data16s, len)
+ ps->data_offset += (len * sizeof(uint16));
+
+ return True;
+}
+
+
+/******************************************************************
+allocate some memory for a parse structure
+ ********************************************************************/
+void io_free(io_struct *ps)
+{
+ if (ps->is_dynamic && ps->data_p)
+ {
+ free(ps->data_p);
+ ps->data_p = NULL;
+ }
+}
+
+/******************************************************************
+allocate some memory for a parse structure
+ ********************************************************************/
+BOOL io_alloc(char *name, io_struct *ps, void **ptr, unsigned size)
+{
+ (*ptr) = (void *)malloc(size);
+ if (*ptr) return True;
+ return False;
+}
+
+/******************************************************************
+realloc some memory for a parse structure
+ ********************************************************************/
+BOOL io_realloc(char *name, io_struct *ps, void **ptr, unsigned size)
+{
+ BOOL ret = True;
+ void *tp;
+
+ tp = (void *)Realloc(*ptr, size);
+ if (tp) *ptr = tp;
+ else ret = False;
+ return ret;
+}
+
diff --git a/source/aparser/parser.h b/source/aparser/parser.h
new file mode 100644
index 00000000000..319aeb5d138
--- /dev/null
+++ b/source/aparser/parser.h
@@ -0,0 +1,103 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../include/byteorder.h"
+
+#define PARSE_SCALARS (1<<0)
+#define PARSE_BUFFERS (1<<1)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#define DEBUG(lvl, str) printf str;
+#define DEBUGADD(lvl, str) printf str;
+
+#define MARSHALL 0
+#define UNMARSHALL 1
+
+#define MARSHALLING(ps) (!(ps)->io)
+#define UNMARSHALLING(ps) ((ps)->io)
+
+typedef int BOOL;
+typedef unsigned char uint8;
+typedef unsigned char uchar;
+typedef unsigned short uint16;
+typedef unsigned short wchar;
+typedef unsigned uint32;
+typedef char *SMBSTR;
+
+/* a null terminated unicode string */
+typedef uint16 ZUSTRING;
+
+#ifndef _PSTRING
+
+#define PSTRING_LEN 1024
+#define FSTRING_LEN 128
+
+typedef char pstring[PSTRING_LEN];
+typedef char fstring[FSTRING_LEN];
+
+#define _PSTRING
+
+#endif
+#define False 0
+#define True 1
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+
+#define MAX_UNISTRLEN 256
+#define MAX_STRINGLEN 256
+#define MAX_BUFFERLEN 512
+
+typedef struct _io_struct
+{
+ BOOL io; /* parsing in or out of data stream */
+ /*
+ * If the (incoming) data is big-endian. On output we are
+ * always little-endian.
+ */
+ BOOL bigendian_data;
+ BOOL is_dynamic; /* Do we own this memory or not ? */
+ BOOL autoalign; /* should we auto-align all elements? */
+ uint32 data_offset; /* Current working offset into data. */
+ uint32 buffer_size; /* Current size of the buffer. */
+ uint32 grow_size; /* size requested via io_grow() calls */
+ char *data_p; /* The buffer itself. */
+} io_struct;
+
+
+char *io_mem_get(io_struct *ps, uint32 extra_size);
+BOOL io_init(io_struct *ps, uint32 size, BOOL io);
+void io_debug(io_struct *ps, int depth, char *desc, char *fn_name);
+BOOL io_align(io_struct *ps, int align);
+BOOL io_align4(io_struct *ps, int align);
+BOOL io_align2(io_struct *ps, int align);
+BOOL io_read(io_struct *ps, int fd, size_t len, int timeout);
+void dump_data(int level,char *buf1,int len);
+BOOL io_alloc(char *name, io_struct *ps, void **ptr, unsigned size);
+BOOL io_uint32(char *name, io_struct *ps, int depth, uint32 *data32, unsigned flags);
+BOOL io_uint16(char *name, io_struct *ps, int depth, uint16 *data16, unsigned flags);
+BOOL io_uint8(char *name, io_struct *ps, int depth, uint8 *data8, unsigned flags);
+BOOL io_pointer(char *desc, io_struct *ps, int depth, void **p, unsigned flags);
+BOOL io_SMBSTR(char *name, io_struct *ps, int depth, char **str, unsigned flags);
+BOOL io_io_struct(char *name, io_struct *ps, int depth, io_struct *io, unsigned flags);
+BOOL io_wstring(char *name, io_struct *ps, int depth, uint16 *data16s, int len, unsigned flags);
+BOOL io_uint8s_fixed(char *name, io_struct *ps, int depth, uint8 *data8s, int len, unsigned flags);
+BOOL io_uint8s(char *name, io_struct *ps, int depth, uint8 **data8s, int len, unsigned flags);
+
+char *tab_depth(int depth);
+void *Realloc(void *p,size_t size);
+void dump_data(int level,char *buf1,int len);
+void print_asc(int level, uchar const *buf, int len);
+BOOL io_ZUSTRING(char *name, io_struct *ps, int depth, uint16 **ustr, unsigned flags);
+size_t strlen_w(void *src);
+
diff --git a/source/aparser/parserel.awk b/source/aparser/parserel.awk
new file mode 100644
index 00000000000..6d80f0607e4
--- /dev/null
+++ b/source/aparser/parserel.awk
@@ -0,0 +1,213 @@
+# build parse functions for a parsed struct file
+
+function elem_name(v, elem)
+{
+ return v["UNION"]elem;
+}
+
+function parse_array(f, v, elnum, flags,
+ LOCAL, type, elem, array_len)
+{
+ type = elements[elnum, "type"];
+ elem = elements[elnum, "elem"];
+ array_len = elements[elnum, "array_len"];
+ v["ELEM"] = elem_name(v, elem);
+ v["TYPE"] = type;
+ v["FLAGS"] = flags;
+ v["ARRAY_LEN"] = array_len;
+
+ if (array_len=="+") {
+ print_template(f,"prs_array_optional.tpl", v);
+ return;
+ }
+
+ if (array_len=="&") {
+ print_template(f,"prs_array_null.tpl", v);
+ return;
+ }
+
+ if (array_len=="*") {
+ print_template(f,"prs_array_remainder.tpl", v);
+ return;
+ }
+
+ if (type == "wchar" || type == "uint16") {
+ if (match(array_len,"[0-9]") == 1) {
+ print_template(f, "prs_wstring_fixed.tpl", v);
+ } else {
+ print_template(f, "prs_wstring.tpl", v);
+ }
+ } else if (type == "uint8") {
+ if (match(array_len,"[0-9]") == 1) {
+ print_template(f, "prs_uint8s_fixed.tpl", v);
+ } else {
+ print_template(f, "prs_uint8s.tpl", v);
+ }
+ } else {
+ print_template(f, "prs_array.tpl", v);
+ }
+}
+
+
+function parse_element(f, v, elnum, flags,
+ LOCAL, type, elem)
+{
+ if (elements[elnum,"nowire"] != "") {
+ return;
+ }
+ type = elements[elnum, "type"];
+ if (substr(type,1,1) == ".") return;
+ elem = elements[elnum, "elem"];
+ if (elements[elnum,"ptr"] == "") {
+ v["PTR"] = "\\&";
+ } else {
+ v["PTR"] = " ";
+ }
+ v["ELEM"] = elem_name(v, elem);
+ v["TYPE"] = type;
+ v["FLAGS"] = flags;
+ print_template(f, "prs_element.tpl", v);
+}
+
+function parse_union(f, v, elnum, flags,
+ LOCAL, i)
+{
+ v["UNION"] = elements[elnum, "elem"];
+ v["SWITCH"] = elements[elnum, "switch"];
+
+ if (elements[elnum, "ptr"] == "1") {
+ v["UNION"] = v["UNION"]"->";
+ } else {
+ v["UNION"] = v["UNION"]".";
+ }
+
+ print_template(f, "union_start.tpl", v);
+ for (i=0;i<unions[elnum, "num_elems"];i++) {
+ v["CASE"] = elements[unions[elnum, i], "case"];
+ print_template(f, "prs_case.tpl", v);
+ if (elements[elnum, "ptr"] == "1") {
+ parse_scalars(f, v, unions[elnum, i], "PARSE_SCALARS");
+ parse_buffers(f, v, unions[elnum, i], "PARSE_BUFFERS");
+ } else {
+ if (flags == "PARSE_SCALARS") {
+ parse_scalars(f, v, unions[elnum, i], flags);
+ } else {
+ parse_buffers(f, v, unions[elnum, i], flags);
+ }
+ }
+ print_template(f, "prs_break.tpl", v);
+ }
+ v["UNION"] = "";
+
+ print_template(f, "union_end.tpl", v);
+}
+
+function parse_scalar(f, v, elnum, flags)
+{
+ if (elements[elnum, "type"] == "union") {
+ parse_union(f, v, elnum, flags);
+ } else if (elements[elnum, "array_len"]!="") {
+ parse_array(f, v, elnum, flags);
+ } else {
+ parse_element(f, v, elnum, flags);
+ }
+}
+
+function parse_pointer(f, v, elnum, flags,
+ LOCAL, elem)
+{
+ elem = elements[elnum, "elem"];
+ v["ELEM"] = elem_name(v, elem);
+ v["FLAGS"] = flags;
+ print_template(f, "prs_pointer.tpl", v);
+}
+
+function parse_scalars(f, v, elnum, flags)
+{
+ if (elements[elnum, "ptr"] == "1") {
+ parse_pointer(f, v, elnum, flags);
+ } else {
+ parse_scalar(f, v, elnum, flags);
+ }
+}
+
+function parse_buffers(f, v, elnum, flags,
+ LOCAL, elem, type)
+{
+ elem = elements[elnum, "elem"];
+ type = elements[elnum, "type"];
+ v["ELEM"] = elem_name(v, elem);
+ if (elements[elnum, "ptr"] == "1") {
+ print_template(f, "ifptr_start.tpl", v);
+ parse_scalar(f, v, elnum, "PARSE_SCALARS|PARSE_BUFFERS");
+ print_template(f, "ifptr_end.tpl", v);
+ } else {
+ parse_scalar(f, v, elnum, flags);
+ }
+}
+
+function struct_immediate(f, v, struct_num,
+ LOCAL, i, n1, num_elems)
+{
+ num_elems = structs[struct_num, "num_elems"];
+ v["STRUCTNAME"] = structs[struct_num, "name"];
+ v["FUNCNAME"] = "io_" v["STRUCTNAME"];
+
+ print_template(f, "fn_i_start.tpl", v);
+
+ for (i=0;i<num_elems;i++) {
+ parse_scalars(f, v, structs[struct_num, i], "PARSE_SCALARS");
+ parse_buffers(f, v, structs[struct_num, i], "PARSE_BUFFERS");
+ }
+
+ print_template(f, "fn_i_end.tpl", v);
+}
+
+
+function struct_recursive(f, v, struct_num,
+ LOCAL, i, n1, num_elems)
+{
+ num_elems = structs[struct_num, "num_elems"];
+ v["STRUCTNAME"] = structs[struct_num, "name"];
+ v["FUNCNAME"] = "io_" v["STRUCTNAME"];
+
+ print_template(f, "fn_start.tpl", v);
+
+# first all the structure pointers, scalars and arrays
+ for (i=0;i<num_elems;i++) {
+ parse_scalars(f, v, structs[struct_num, i], "PARSE_SCALARS");
+ }
+
+ print_template(f, "fn_mid.tpl", v);
+
+# now the buffers
+ for (i=0;i<num_elems;i++) {
+ parse_buffers(f, v, structs[struct_num, i], "PARSE_BUFFERS");
+ }
+
+ print_template(f, "fn_end.tpl", v);
+}
+
+function struct_parser(f, v, struct_num,
+ LOCAL, i, n1, num_elems)
+{
+ if (structs[struct_num, "recurse"] == "True") {
+ struct_recursive(f, v, struct_num);
+ } else {
+ struct_immediate(f, v, struct_num);
+ }
+}
+
+function produce_relative(f,
+ LOCAL, v, i)
+{
+ v["MODULE"]=module;
+
+ print_template(f, "module_start.tpl", v);
+
+ for (i=0;i < num_structs;i++) {
+ struct_parser(f, v, i);
+ }
+
+ print_template(f, "module_end.tpl", v);
+}
diff --git a/source/aparser/parsetree.awk b/source/aparser/parsetree.awk
new file mode 100644
index 00000000000..80587a01116
--- /dev/null
+++ b/source/aparser/parsetree.awk
@@ -0,0 +1,224 @@
+# build the parse tree for a struct file
+
+function find_structure(name,
+ LOCAL, i)
+{
+ for (i=0;i<num_structs;i++) {
+ if (structs[i, "name"] == name) return i;
+ }
+ return "-1";
+}
+
+function start_module(name)
+{
+ module=name;
+ num_structs=0;
+ num_elements=0;
+ num_unions=0;
+ num_tests=0;
+ num_options=0;
+}
+
+function set_option(name, value)
+{
+ options[name] = value;
+ options[num_options, "name"] = name;
+ options[num_options, "value"] = value;
+ num_options++;
+}
+
+function parse_define(def1, def2,
+ LOCAL, type, i)
+{
+ defines[def1]=def2;
+}
+
+function start_struct(name)
+{
+ current_struct=num_structs;
+ structs[name]=current_struct;
+ structs[current_struct, "name"]=name;
+ structs[current_struct, "num_elems"]=0;
+ structs[current_struct, "num_unions"]=0;
+ structs[current_struct, "recurse"] = options["recurse"];
+}
+
+function end_struct(name)
+{
+ if (name!="") structs[num_structs, "name"]=name;
+ printf("struct %s with %d elements\n",
+ structs[num_structs, "name"],
+ structs[num_structs, "num_elems"]);
+ num_structs++;
+ current_struct="";
+}
+
+function add_element(type, elem, case,
+ LOCAL, elem_num, i, v)
+{
+ while (defines[type]!="") {
+ type=defines[type];
+ }
+ elem_num=num_elements;
+
+ if (substr(elem, 1, 1) == ".") {
+ elem=substr(elem, 2);
+ elements[elem_num, "nowire"]=1;
+ }
+
+ if (substr(elem, 1, 1) == "*") {
+ elem=substr(elem, 2);
+ elements[elem_num, "ptr"]=1;
+ }
+
+ i=match(elem,"[[]");
+ if (i != 0) {
+ v = substr(elem, i+1, length(elem)-i-1);
+ elem=substr(elem, 1, i-1);
+ if (type=="union") {
+ elements[elem_num, "switch"] = v;
+ } else {
+ elements[elem_num, "array_len"] = v;
+ }
+ }
+
+ elements[elem_num, "type"] = type;
+ elements[elem_num, "elem"] = elem;
+ elements[elem_num, "case"] = case;
+
+ num_elements++;
+ return elem_num;
+}
+
+function add_struct_elem(type, elem, case,
+ LOCAL, elem_num)
+{
+ elem_num=structs[current_struct, "num_elems"];
+ structs[current_struct, elem_num] = add_element(type, elem, case);
+ structs[current_struct, "num_elems"]++;
+ return structs[current_struct, elem_num];
+}
+
+function start_union(elem)
+{
+ current_union = add_struct_elem("union", elem);
+ unions[current_union, "num_elems"] = 0;
+}
+
+function start_union_notencap(switch)
+{
+ add_struct_elem("uint32", "switch_"switch);
+ start_union("UNKNOWN[switch_"switch"]");
+}
+
+function start_union_encap(struct, type, switch, union)
+{
+ start_struct(struct);
+ add_struct_elem(type, switch);
+ add_struct_elem(type, "switch_"switch);
+ start_union(union"[switch_"switch"]");
+ encap_union="1";
+}
+
+function parse_case(case, type, elem,
+ LOCAL, elem_num)
+{
+ split(case, a, "[:]");
+ case = a[1];
+ elem_num = unions[current_union, "num_elems"];
+ unions[current_union, elem_num] = add_element(type, elem, case);
+ unions[current_union, "num_elems"]++;
+}
+
+function end_union(name)
+{
+ if (name!="") {
+ elements[current_union, "elem"] = name;
+ }
+ current_union="";
+ if (encap_union=="1") {
+ end_struct(name);
+ encap_union="0";
+ }
+}
+
+function delete_element(struct, elnum,
+ LOCAL, i)
+{
+ for (i=elnum;i<structs[struct,"num_elems"]-1;i++) {
+ structs[struct, i] = structs[struct, i+1];
+ }
+ structs[struct, "num_elems"]--;
+}
+
+function copy_struct(from, to,
+ LOCAL, i)
+{
+ for (i=0;i<structs[from,"num_elems"];i++) {
+ structs[to, i] = structs[from, i];
+ }
+ structs[to, "name"] = structs[from, "name"];
+ structs[to, "num_elems"] = structs[from, "num_elems"];
+ structs[to, "num_unions"] = structs[from, "num_unions"];
+}
+
+function add_sizeis_array(count, type, elem)
+{
+ copy_struct(current_struct, current_struct+1);
+ elem=substr(elem,2);
+ start_struct("array_"current_struct"_"elem);
+ add_struct_elem("uint32", count);
+ add_struct_elem(type, elem"["count"]");
+ end_struct("");
+ current_struct=num_structs;
+ add_struct_elem("array_"current_struct-1"_"elem, "*"elem"_ptr");
+}
+
+
+function start_function(type, fname)
+{
+ start_struct(fname);
+ structs[current_struct, "recurse"] = "False";
+}
+
+function end_function(LOCAL, i)
+{
+ copy_struct(num_structs, num_structs+1);
+ structs[num_structs, "name"] = "Q_"structs[num_structs, "name"];
+ for (i=0;i<structs[num_structs, "num_elems"];i++) {
+ if (match(elements[structs[num_structs, i], "properties"], "in") == 0) {
+ delete_element(num_structs, i);
+ i--;
+ }
+ }
+ end_struct();
+ current_struct=num_structs;
+ structs[num_structs, "name"] = "R_"structs[num_structs, "name"];
+ for (i=0;i<structs[num_structs, "num_elems"];i++) {
+ if (match(elements[structs[num_structs, i], "properties"], "out") == 0) {
+ delete_element(num_structs, i);
+ i--;
+ }
+ }
+ if (return_result!="void")
+ add_function_param("[out]", return_result, "status");
+ end_struct();
+}
+
+function add_function_param(properties, type, elem,
+ LOCAL, elnum, len)
+{
+ len=length(type);
+ if (substr(type, len) == "*") {
+ type=substr(type, 1, len-1);
+ elem="*"elem;
+ }
+ if (substr(elem,1,1) == "*" &&
+ (match(properties,"in") == 0 ||
+ find_structure(type) != "-1")) {
+ elem=substr(elem, 2);
+ }
+ elnum = add_struct_elem(type, elem);
+ elements[elnum, "properties"] = properties;
+}
+
diff --git a/source/aparser/spool.struct b/source/aparser/spool.struct
new file mode 100644
index 00000000000..1563ba5be07
--- /dev/null
+++ b/source/aparser/spool.struct
@@ -0,0 +1,90 @@
+module spool
+
+struct BUFFER5 {
+ uint32 buf_len;
+ uint16 buffer[buf_len];
+};
+
+struct BUFFERP {
+ uint32 buf_len;
+ BUFFER5 *buf;
+};
+
+struct UNISTR2 {
+ uint32 max_len;
+ uint32 undoc;
+ uint32 str_len;
+ uint16 buffer[str_len];
+};
+
+struct LPWSTR {
+ UNISTR2 *str;
+};
+
+struct VERSION {
+ uint32 version;
+ uint32 build;
+ uint32 osversion;
+};
+
+struct NTTIME {
+ uint32 low;
+ uint32 high;
+};
+
+struct DWORD {
+ uint32 x;
+};
+
+struct PRINTER_DRIVER_INFO_LEVEL_3 {
+ DWORD cversion;
+ LPWSTR name;
+ LPWSTR environment;
+ LPWSTR driverpath;
+ LPWSTR datafile;
+ LPWSTR configfile;
+ LPWSTR helpfile;
+ LPWSTR monitorname;
+ LPWSTR defaultdatatype;
+ BUFFERP dependentfiles;
+};
+
+struct PRINTER_DRIVER_INFO_LEVEL_6 {
+ DWORD dummy1;
+ DWORD version;
+ LPWSTR name;
+ LPWSTR environment;
+ LPWSTR driverpath;
+ LPWSTR datafile;
+ LPWSTR configfile;
+ LPWSTR helpfile;
+ LPWSTR monitorname;
+ LPWSTR defaultdatatype;
+ BUFFERP dependentfiles;
+ BUFFERP previousnames;
+ NTTIME driverdate;
+ VERSION driverversion;
+ LPWSTR mfgname;
+ LPWSTR oemurl;
+ LPWSTR hardwareid;
+ LPWSTR provider;
+};
+
+
+struct PRINTER_DRIVER_INFO {
+ uint32 level;
+ union *info[level] {
+ case 3 PRINTER_DRIVER_INFO_LEVEL_3 info_3;
+ case 6 PRINTER_DRIVER_INFO_LEVEL_6 info_6;
+ }
+};
+
+
+struct R_GETPRINTERDATA {
+ uint32 type;
+ uint32 size;
+ uint8 *data;
+ uint32 needed;
+ uint32 status;
+};
+
diff --git a/source/aparser/spool_io_printer_driver_info_level_3.prs b/source/aparser/spool_io_printer_driver_info_level_3.prs
new file mode 100644
index 00000000000..baa32ef7c7b
--- /dev/null
+++ b/source/aparser/spool_io_printer_driver_info_level_3.prs
Binary files differ
diff --git a/source/aparser/spool_io_printer_driver_info_level_6.prs b/source/aparser/spool_io_printer_driver_info_level_6.prs
new file mode 100644
index 00000000000..3c5a47e7a3c
--- /dev/null
+++ b/source/aparser/spool_io_printer_driver_info_level_6.prs
Binary files differ
diff --git a/source/aparser/srvsvc.struct b/source/aparser/srvsvc.struct
new file mode 100644
index 00000000000..aa40c8f15e4
--- /dev/null
+++ b/source/aparser/srvsvc.struct
@@ -0,0 +1,184 @@
+module srvsvc
+
+typedef uint32 LONG;
+typedef uint32 *ENUM_HND;
+
+typedef struct _UNISTR2 {
+ uint32 max_len;
+ uint32 undoc;
+ uint32 str_len;
+ wchar buffer[str_len];
+} UNISTR2;
+
+typedef UNISTR2 *LPWSTR;
+
+/* function 8 */
+struct CONN_INFO_0 {
+ uint32 id; /* connection id. */
+};
+
+struct CONN_INFO_1 {
+ uint32 id;
+ uint32 type;
+ uint32 num_opens;
+ uint32 num_users;
+ uint32 open_time;
+ LPWSTR usr_name;
+ LPWSTR net_name;
+};
+
+struct CONN_ENUM_CTR {
+ uint32 level;
+ uint32 level2;
+ uint32 num_entries;
+ uint32 num_entries2;
+ union *info[level] {
+ case 0 CONN_INFO_0 info0[num_entries];
+ case 1 CONN_INFO_1 info1[num_entries];
+ }
+};
+
+struct SRV_R_NET_CONN_ENUM {
+ .trailer;
+ CONN_ENUM_CTR ctr;
+ uint32 num_entries;
+ ENUM_HND handle;
+ uint32 status2;
+};
+
+struct SRV_Q_NET_CONN_ENUM {
+ .trailer;
+ LPWSTR dest_srv;
+ LPWSTR qual_srv;
+ uint32 level;
+ uint32 level2;
+ CONN_ENUM_CTR *ctr;
+ uint32 max_len;
+ ENUM_HND handle;
+};
+
+/* function 9 */
+struct FILE_INFO_3 {
+ uint32 id; /* file index */
+ uint32 perms; /* file permissions. don't know what format */
+ uint32 num_locks; /* file locks */
+ LPWSTR path_name; /* file name */
+ LPWSTR user_name; /* file owner */
+};
+
+struct SRV_FILE_INFO_CTR {
+ uint32 level;
+ uint32 num_entries;
+ uint32 dummy;
+ union *file[level] {
+ case 3 FILE_INFO_3 info3[num_entries];
+ }
+};
+
+struct SRV_Q_NET_FILE_ENUM {
+ .trailer;
+ LPWSTR srv_name;
+ LPWSTR qual_name;
+ uint32 dummy;
+ uint32 level;
+ SRV_FILE_INFO_CTR ctr;
+ uint32 *status;
+ uint32 preferred_len;
+ ENUM_HND enum_hnd;
+};
+
+
+struct SRV_R_NET_FILE_ENUM {
+ .trailer;
+ uint32 level;
+ uint32 dummy;
+ SRV_FILE_INFO_CTR *ctr;
+ uint32 total_entries; /* total number of files */
+ ENUM_HND enum_hnd;
+ uint32 status; /* return status */
+};
+
+
+/* function 15 */
+struct SRV_SHARE_INFO_1 {
+ LPWSTR uni_netname;
+ uint32 type;
+ LPWSTR uni_remark;
+};
+
+struct SRV_SHARE_INFO_2 {
+ LPWSTR uni_netname;
+ uint32 type;
+ LPWSTR uni_remark;
+ uint32 perms;
+ uint32 max_uses;
+ uint32 num_uses;
+ LPWSTR path;
+ LPWSTR passwd;
+};
+
+struct SRV_R_NET_SHARE_ENUM {
+ uint32 level;
+ uint32 level2;
+ uint32 *ret_count;
+ uint32 num_entries;
+ union *info[level] {
+ case 1 SRV_SHARE_INFO_1 info1[num_entries];
+ case 2 SRV_SHARE_INFO_2 info2[num_entries];
+ }
+ .trailer;
+ uint32 count;
+ ENUM_HND handle;
+ uint32 status;
+};
+
+
+
+/* function 21 */
+struct SERVER_INFO_100 {
+ uint32 dwPlatformID;
+ LPWSTR pszName;
+};
+
+struct SERVER_INFO_101 {
+ uint32 dwPlatformID;
+ LPWSTR pszName;
+ uint32 dwVerMajor;
+ uint32 dwVerMinor;
+ uint32 dwType;
+ LPWSTR pszComment;
+};
+
+struct SERVER_INFO_102 {
+ uint32 dwPlatformID;
+ LPWSTR pszName;
+ uint32 dwVerMajor;
+ uint32 dwVerMinor;
+ uint32 dwType;
+ LPWSTR pszComment;
+ uint32 dwUsers;
+ uint32 lDisc;
+ uint32 bHidden;
+ uint32 dwAnnounce;
+ uint32 dwAnnDelta;
+ uint32 dwLicenses;
+ LPWSTR pszUserPath;
+};
+
+struct SRV_R_NET_SERVER_INFO {
+ .trailer;
+ uint32 level;
+ union *info[level] {
+ case 100 SERVER_INFO_100 sv100;
+ case 101 SERVER_INFO_101 sv101;
+ case 102 SERVER_INFO_102 sv102;
+ }
+ uint32 status;
+};
+
+struct SRV_Q_NET_SERVER_INFO {
+ .trailer;
+ LPWSTR server;
+ uint32 level;
+};
+
diff --git a/source/aparser/srvsvc2.struct b/source/aparser/srvsvc2.struct
new file mode 100644
index 00000000000..362d121e378
--- /dev/null
+++ b/source/aparser/srvsvc2.struct
@@ -0,0 +1,655 @@
+module srvsvc
+
+option autoalign True
+option relative False
+option recurse True
+option foo blah
+
+#define BOOL uint32
+#define LONG uint32
+#define DWORD uint32
+#define STATUS uint32
+
+typedef struct _UNISTR2 {
+ uint32 max_len;
+ uint32 undoc;
+ uint32 str_len;
+ wchar buffer[str_len];
+} UNISTR2;
+
+struct LPWSTR {
+ UNISTR2 *str;
+};
+
+
+
+ /* -- CHARACTER DEVICE INFORMATION -- */
+
+ typedef struct _CHARDEV_INFO_0 {
+ LPWSTR pszName;
+ } CHARDEV_INFO_0;
+
+ typedef struct _CHARDEV_INFO_1 {
+ LPWSTR pszName;
+ DWORD dwStatus;
+ LPWSTR pszUser;
+ DWORD dwTime;
+ } CHARDEV_INFO_1;
+
+ typedef union _CHARDEV_INFO switch (DWORD dwLevel) ctr {
+ case 1: CHARDEV_INFO_0 *ci0;
+ case 2: CHARDEV_INFO_1 *ci1;
+ } CHARDEV_INFO;
+
+ typedef struct _CHARDEV_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CHARDEV_INFO_0 *ci0;
+ } CHARDEV_ENUM_0;
+
+ typedef struct _CHARDEV_ENUM_1 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CHARDEV_INFO_1 *ci1;
+ } CHARDEV_ENUM_1;
+
+ typedef struct _CHARDEV_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] CHARDEV_ENUM_0 *ce0;
+ [case(1)] CHARDEV_ENUM_1 *ce1;
+ } ctr;
+ } CHARDEV_ENUM;
+
+ STATUS NetrCharDevEnum( /* Function 0x00 */
+ [in,unique] LPWSTR pszServer,
+ [in,out] CHARDEV_ENUM* pCharDevEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrCharDevGetInfo( /* Function 0x01 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszDevice,
+ [in] DWORD dwLevel,
+ [out] CHARDEV_INFO* pCharDevInfo
+ );
+
+ STATUS NetrCharDevControl( /* Function 0x02 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszDevice,
+ [in] DWORD dwOpcode
+ );
+
+ /* -- CHARACTER DEVICE QUEUE INFORMATION -- */
+
+ typedef struct _CHARDEVQ_INFO_0 {
+ LPWSTR pszName;
+ } CHARDEVQ_INFO_0;
+
+ typedef struct _CHARDEVQ_INFO_1 {
+ LPWSTR pszName;
+ DWORD dwPriority;
+ LPWSTR pszDevices;
+ DWORD dwNumUsers;
+ DWORD dwNumAhead;
+ } CHARDEVQ_INFO_1;
+
+ typedef union _CHARDEVQ_INFO switch (DWORD dwLevel) ctr {
+ case 1: CHARDEVQ_INFO_0 *ci0;
+ case 2: CHARDEVQ_INFO_1 *ci1;
+ } CHARDEVQ_INFO;
+
+ typedef struct _CHARDEVQ_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CHARDEVQ_INFO_0 *ci0;
+ } CHARDEVQ_ENUM_0;
+
+ typedef struct _CHARDEVQ_ENUM_1 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CHARDEVQ_INFO_1 *ci1;
+ } CHARDEVQ_ENUM_1;
+
+ typedef struct _CHARDEVQ_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] CHARDEVQ_ENUM_0 *ce0;
+ [case(1)] CHARDEVQ_ENUM_1 *ce1;
+ } ctr;
+ } CHARDEVQ_ENUM;
+
+ STATUS NetrCharDevQEnum( /* Function 0x03 */
+ [in,unique] LPWSTR pszServer,
+ [in,unique] LPWSTR pszUser,
+ [in,out] CHARDEVQ_ENUM* pCharDevQEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrCharDevQGetInfo( /* Function 0x04 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszQueue,
+ [in,ref] LPWSTR pszUser,
+ [in] DWORD dwLevel,
+ [out] CHARDEVQ_INFO* pCharDevQInfo
+ );
+
+ STATUS NetrCharDevQSetInfo( /* Function 0x05 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszQueue,
+ [in] DWORD dwLevel,
+ [in] CHARDEVQ_INFO* pCharDevQInfo,
+ [in,out] DWORD* dwParmError
+ );
+
+ STATUS NetrCharDevQPurge( /* Function 0x06 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszQueue
+ );
+
+ STATUS NetrCharDevQPurgeSelf( /* Function 0x07 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszQueue,
+ [in,ref] LPWSTR pszComputer
+ );
+
+ /* -- CONNECTION INFORMATION -- */
+
+ typedef struct _CONNECTION_INFO_0 {
+ DWORD dwConnID;
+ } CONNECTION_INFO_0;
+
+ typedef struct _CONNECTION_INFO_1 {
+ DWORD dwConnID;
+ DWORD dwType;
+ DWORD dwNumOpens;
+ DWORD dwNumUsers;
+ DWORD dwTime;
+ LPWSTR pszUser;
+ LPWSTR pszShare;
+ } CONNECTION_INFO_1;
+
+ typedef struct _CONNECTION_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CONNECTION_INFO_0 *ci0;
+ } CONNECTION_ENUM_0;
+
+ typedef struct _CONNECTION_ENUM_1 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] CONNECTION_INFO_1 *ci1;
+ } CONNECTION_ENUM_1;
+
+ typedef struct _CONNECTION_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] CONNECTION_ENUM_0 *ce0;
+ [case(1)] CONNECTION_ENUM_1 *ce1;
+ } ctr;
+ } CONNECTION_ENUM;
+
+ STATUS NetrConnectionEnum( /* Function 0x08 */
+ [in,unique] LPWSTR pszServer,
+ [in,unique] LPWSTR pszClient,
+ [in,out] CONNECTION_ENUM* pConnectionEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ /* -- FILE INFORMATION -- */
+
+ typedef struct _FILE_INFO_2 {
+ DWORD dwFileID;
+ } FILE_INFO_2;
+
+ typedef struct _FILE_INFO_3 {
+ DWORD dwFileID;
+ DWORD dwPermissions;
+ DWORD dwNumLocks;
+ LPWSTR pszPath;
+ LPWSTR pszUser;
+ } FILE_INFO_3;
+
+ typedef union _FILE_INFO switch (DWORD dwLevel) ctr {
+ case 2: FILE_INFO_2 *fi2;
+ case 3: FILE_INFO_3 *fi3;
+ } FILE_INFO;
+
+ typedef struct _FILE_ENUM_2 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] FILE_INFO_2 *fi2;
+ } FILE_ENUM_2;
+
+ typedef struct _FILE_ENUM_3 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] FILE_INFO_3 *fi3;
+ } FILE_ENUM_3;
+
+ typedef struct _FILE_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(2)] FILE_ENUM_2 *fe2;
+ [case(3)] FILE_ENUM_3 *fe3;
+ } ctr;
+ } FILE_ENUM;
+
+ STATUS NetrFileEnum( /* Function 0x09 */
+ [in,unique] LPWSTR pszServer,
+ [in,unique] LPWSTR pszBasePath,
+ [in,unique] LPWSTR pszUser,
+ [in,out] FILE_ENUM* pFileEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrFileGetInfo( /* Function 0x0A */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwFileID,
+ [in] DWORD dwLevel,
+ [out] FILE_INFO* pFileInfo
+ );
+
+ STATUS NetrFileClose( /* Function 0x0B */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwFileID
+ );
+
+ /* -- SESSION INFORMATION -- */
+
+ typedef struct _SESSION_INFO_0 {
+ LPWSTR pszClient;
+ } SESSION_INFO_0;
+
+ typedef struct _SESSION_INFO_1 {
+ LPWSTR pszClient;
+ LPWSTR pszUser;
+ DWORD dwOpens;
+ DWORD dwTime;
+ DWORD dwIdleTime;
+ DWORD dwUserFlags;
+ } SESSION_INFO_1;
+
+ typedef struct _SESSION_INFO_2 {
+ LPWSTR pszClient;
+ LPWSTR pszUser;
+ DWORD dwOpens;
+ DWORD dwTime;
+ DWORD dwIdleTime;
+ DWORD dwUserFlags;
+ LPWSTR pszClientType;
+ } SESSION_INFO_2;
+
+ typedef struct _SESSION_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SESSION_INFO_0 *si0;
+ } SESSION_ENUM_0;
+
+ typedef struct _SESSION_ENUM_1 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SESSION_INFO_1 *si1;
+ } SESSION_ENUM_1;
+
+ typedef struct _SESSION_ENUM_2 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SESSION_INFO_2 *si2;
+ } SESSION_ENUM_2;
+
+ typedef struct _SESSION_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] SESSION_ENUM_0 *se0;
+ [case(1)] SESSION_ENUM_1 *se1;
+ [case(2)] SESSION_ENUM_2 *se2;
+ } ctr;
+ } SESSION_ENUM;
+
+ STATUS NetrSessionEnum( /* Function 0x0C */
+ [in,unique] LPWSTR pszServer,
+ [in,unique] LPWSTR pszClient,
+ [in,unique] LPWSTR pszUser,
+ [in,out] SESSION_ENUM* pFileEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrSessionDel( /* Function 0x0D */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszClient,
+ [in,ref] LPWSTR pszUser
+ );
+
+ /* -- SHARE INFORMATION -- */
+
+ typedef struct _SHARE_INFO_0 {
+ LPWSTR pszName;
+ } SHARE_INFO_0;
+
+ typedef struct _SHARE_INFO_1 {
+ LPWSTR pszName;
+ DWORD dwType;
+ LPWSTR pszComment;
+ } SHARE_INFO_1;
+
+ typedef struct _SHARE_INFO_2 {
+ LPWSTR pszName;
+ DWORD dwType;
+ LPWSTR pszComment;
+ DWORD dwPermissions;
+ DWORD dwMaxUses;
+ DWORD dwCurrentUses;
+ LPWSTR pszPath;
+ LPWSTR pszPasswd;
+ } SHARE_INFO_2;
+
+ typedef union _SHARE_INFO switch (DWORD dwLevel) ctr {
+ case 0: SHARE_INFO_0 *si0;
+ case 1: SHARE_INFO_1 *si1;
+ case 2: SHARE_INFO_2 *si2;
+ } SHARE_INFO;
+
+ typedef struct _SHARE_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SHARE_INFO_0 *si0;
+ } SHARE_ENUM_0;
+
+ typedef struct _SHARE_ENUM_1 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SHARE_INFO_1 *si1;
+ } SHARE_ENUM_1;
+
+ typedef struct _SHARE_ENUM_2 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] SHARE_INFO_2 *si2;
+ } SHARE_ENUM_2;
+
+ typedef struct _SHARE_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] SHARE_ENUM_0 *se0;
+ [case(1)] SHARE_ENUM_1 *se1;
+ [case(2)] SHARE_ENUM_2 *se2;
+ } ctr;
+ } SHARE_ENUM;
+
+ STATUS NetrShareAdd( /* Function 0x0E */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [out] SHARE_INFO* pShareInfo,
+ [in,out] DWORD* dwParmError
+ );
+
+ STATUS NetrShareEnum( /* Function 0x0F */
+ [in,unique] LPWSTR pszServer,
+ [in,out] SHARE_ENUM* pShareEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrShareGetInfo( /* Function 0x10 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszShare,
+ [in] DWORD dwLevel,
+ [out] SHARE_INFO* pShareInfo
+ );
+
+ STATUS NetrShareSetInfo( /* Function 0x11 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszShare,
+ [in] DWORD dwLevel,
+ [in] SHARE_INFO* pShareInfo,
+ [in] DWORD dwReserved
+ );
+
+ STATUS NetrShareDel( /* Function 0x12 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszShare,
+ [in] DWORD dwReserved
+ );
+
+ STATUS NetrShareDelSticky( /* Function 0x13 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszShare,
+ [in] DWORD dwReserved
+ );
+
+ STATUS NetrShareCheck( /* Function 0x14 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszDevice,
+ [out] DWORD* dwType
+ );
+
+ /* --- SERVER INFORMATION --- */
+
+ typedef struct _SERVER_INFO_100 {
+ DWORD dwPlatformID;
+ LPWSTR pszName;
+ } SERVER_INFO_100;
+
+ typedef struct _SERVER_INFO_101 {
+ DWORD dwPlatformID;
+ LPWSTR pszName;
+ DWORD dwVerMajor;
+ DWORD dwVerMinor;
+ DWORD dwType;
+ LPWSTR pszComment;
+ } SERVER_INFO_101;
+
+ typedef struct _SERVER_INFO_102 {
+ DWORD dwPlatformID;
+ LPWSTR pszName;
+ DWORD dwVerMajor;
+ DWORD dwVerMinor;
+ DWORD dwType;
+ LPWSTR pszComment;
+ DWORD dwUsers;
+ LONG lDisc;
+ BOOL bHidden;
+ DWORD dwAnnounce;
+ DWORD dwAnnDelta;
+ DWORD dwLicenses;
+ LPWSTR pszUserPath;
+ } SERVER_INFO_102;
+
+ typedef union _SERVER_INFO switch (DWORD dwLevel) ctr {
+ case 100: SERVER_INFO_100 *sv100;
+ case 101: SERVER_INFO_101 *sv101;
+ case 102: SERVER_INFO_102 *sv102;
+ } SERVER_INFO;
+
+ STATUS NetrServerGetInfo( /* Function 0x15 */
+ [in,unique] LPWSTR pszServerName,
+ [in] DWORD dwLevel,
+ [out] SERVER_INFO* pServerInfo
+ );
+
+ STATUS NetrServerSetInfo( /* Function 0x16 */
+ [in,unique] LPWSTR pszServerName,
+ [in] DWORD dwLevel,
+ [in] SERVER_INFO* pServerInfo,
+ [in] DWORD dwReserved
+ );
+
+ typedef struct _DISK_INFO {
+ LPWSTR pszName;
+ } DISK_INFO;
+
+ typedef struct _DISK_ENUM {
+ DWORD dwEntries;
+ [size_is(dwEntries)] DISK_INFO *di;
+ } DISK_ENUM;
+
+ STATUS NetrServerDiskEnum( /* Function 0x17 */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [in,out] DISK_ENUM* pDiskEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ typedef struct _STAT_SERVER {
+ DWORD dwStart;
+ DWORD dwFOpens;
+ DWORD dwDevOpens;
+ DWORD dwJobsQueued;
+ DWORD dwSOpens;
+ DWORD dwSTimedOut;
+ DWORD dwSErrors;
+ DWORD dwPWErrors;
+ DWORD dwPermErrors;
+ DWORD dwSysErrors;
+ DWORD dwBytesSentLow;
+ DWORD dwBytesSentHigh;
+ DWORD dwBytesRcvdLow;
+ DWORD dwBytesRcvdHigh;
+ DWORD dwAVResponse;
+ DWORD dwReqBufNeed;
+ DWORD dwBigBufNeed;
+ } STAT_SERVER;
+
+ STATUS NetrServerStatisticsGet( /* Function 0x18 */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [in] DWORD dwOptions,
+ [out] STAT_SERVER* pStatServer
+ );
+
+ typedef struct _TRANSPORT_INFO_0 {
+ LPWSTR pszName;
+ } TRANSPORT_INFO_0;
+
+ typedef union _TRANSPORT_INFO switch (DWORD dwLevel) ctr {
+ case 0: TRANSPORT_INFO_0 *ti0;
+ } TRANSPORT_INFO;
+
+ typedef struct _TRANSPORT_ENUM_0 {
+ DWORD dwEntries;
+ [size_is(dwEntries)] TRANSPORT_INFO_0 *ti0;
+ } TRANSPORT_ENUM_0;
+
+ typedef struct _TRANSPORT_ENUM {
+ DWORD dwLevel;
+ [switch_is(dwLevel)] union {
+ [case(0)] TRANSPORT_ENUM_0 *te0;
+ } ctr;
+ } TRANSPORT_ENUM;
+
+ STATUS NetrServerTransportAdd( /* Function 0x19 */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [out] TRANSPORT_INFO* pTransportInfo
+ );
+
+ STATUS NetrServerTransportEnum( /* Function 0x1a */
+ [in,unique] LPWSTR pszServer,
+ [in,out] TRANSPORT_ENUM* pTransportEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrServerTransportDel( /* Function 0x1b */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [out] TRANSPORT_INFO* pTransportInfo
+ );
+
+ typedef struct _TIME_OF_DAY {
+ DWORD dwElapsedTime;
+ DWORD dwMsecs;
+ DWORD dwHours;
+ DWORD dwMins;
+ DWORD dwSecs;
+ DWORD dwHunds;
+ LONG lTimeZone;
+ DWORD dwInterval;
+ DWORD dwDay;
+ DWORD dwMonth;
+ DWORD dwYear;
+ DWORD dwWeekday;
+ } TIME_OF_DAY;
+
+ STATUS NetrRemoteTOD( /* Function 0x1c */
+ [in,unique] LPWSTR pszServer,
+ [out] TIME_OF_DAY* pTOD
+ );
+
+ STATUS NetrServerSetServiceBits( /* Function 0x1d */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD hServiceStatus, /* ?? */
+ [in] DWORD dwServiceBits,
+ [in] BOOL bSetBitsOn,
+ [in] BOOL bUpdateImmediately
+ );
+
+ /* --- PATH INFORMATION --- */
+
+ STATUS NetprPathType( /* Function 0x1e */
+ void /* Not known */
+ );
+
+ STATUS NetprPathCanonicalize( /* Function 0x1f */
+ void /* Not known */
+ );
+
+ STATUS NetprPathCompare( /* Function 0x20 */
+ void /* Not known */
+ );
+
+ STATUS NetprNameValidate( /* Function 0x21 */
+ void /* Not known */
+ );
+
+ STATUS NetprNameCanonicalize( /* Function 0x22 */
+ void /* Not known */
+ );
+
+ STATUS NetprNameCompare( /* Function 0x23 */
+ void /* Not known */
+ );
+
+ /* --- LATER ADDITIONS --- */
+
+ STATUS NetrShareEnumSticky( /* Function 0x24 */
+ [in,unique] LPWSTR pszServer,
+ [in,out] SHARE_ENUM* pShareEnum,
+ [in] DWORD dwMaxLen,
+ [out] DWORD* dwEntries,
+ [in,out] DWORD* hResume
+ );
+
+ STATUS NetrShareDelStart( /* Function 0x25 */
+ [in,unique] LPWSTR pszServer,
+ [in,ref] LPWSTR pszShare,
+ [in] DWORD dwReserved /* ? */
+ );
+
+ STATUS NetrShareDelCommit( /* Function 0x26 */
+ [in,unique] LPWSTR pszServer
+ );
+
+ STATUS NetrpGetFileSecurity( /* Function 0x27 */
+ void /* Not known */
+ );
+
+ STATUS NetrpSetFileSecurity( /* Function 0x28 */
+ void /* Not known */
+ );
+
+ STATUS NetrServerTransportAddEx( /* Function 0x29 */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD dwLevel,
+ [out] TRANSPORT_INFO* pTransportInfo
+ );
+
+ STATUS NetrServerSetServiceBitsEx( /* Function 0x30 */
+ [in,unique] LPWSTR pszServer,
+ [in] DWORD hServiceStatus, /* ?? */
+ [in] DWORD dwServiceBits,
+ [in] BOOL bSetBitsOn,
+ [in] BOOL bUpdateImmediately
+ );
+
diff --git a/source/aparser/template.awk b/source/aparser/template.awk
new file mode 100644
index 00000000000..20157008354
--- /dev/null
+++ b/source/aparser/template.awk
@@ -0,0 +1,18 @@
+# template file handling
+
+function print_template(f, tplname, v,
+ LOCAL, i, pat, line)
+{
+ tplname="templates/"tplname;
+ if (numlines(tplname) <= 0) fatal("no template "tplname);
+ while ((getline line < tplname) > 0) {
+ while ((i = match(line,"@[a-zA-Z_]*@")) != 0) {
+ pat=substr(line,i+1,RLENGTH-2);
+ if (v[pat] == "") fatal("no value for "pat" in "tplname);
+ gsub("@"pat"@", v[pat], line);
+ }
+
+ xprintf(f, "%s\n", line);
+ }
+ close(tplname);
+}
diff --git a/source/aparser/templates/fn_end.tpl b/source/aparser/templates/fn_end.tpl
new file mode 100644
index 00000000000..2275ec4e33c
--- /dev/null
+++ b/source/aparser/templates/fn_end.tpl
@@ -0,0 +1,13 @@
+
+end:
+ /* the parse is OK */
+ return True;
+
+fail:
+ if (UNMARSHALLING(ps)) {
+ ZERO_STRUCTP(il);
+ }
+ return False;
+} /* @FUNCNAME@ */
+
+
diff --git a/source/aparser/templates/fn_end0.tpl b/source/aparser/templates/fn_end0.tpl
new file mode 100644
index 00000000000..6e49a10f538
--- /dev/null
+++ b/source/aparser/templates/fn_end0.tpl
@@ -0,0 +1,8 @@
+
+end:
+ /* the parse is OK */
+ return True;
+
+} /* @FUNCNAME@ */
+
+
diff --git a/source/aparser/templates/fn_i_end.tpl b/source/aparser/templates/fn_i_end.tpl
new file mode 100644
index 00000000000..9de61decb38
--- /dev/null
+++ b/source/aparser/templates/fn_i_end.tpl
@@ -0,0 +1,12 @@
+
+ /* the parse is OK */
+ return True;
+
+fail:
+ if (UNMARSHALLING(ps)) {
+ ZERO_STRUCTP(il);
+ }
+ return False;
+} /* @FUNCNAME@ */
+
+
diff --git a/source/aparser/templates/fn_i_start.tpl b/source/aparser/templates/fn_i_start.tpl
new file mode 100644
index 00000000000..3979d78e7db
--- /dev/null
+++ b/source/aparser/templates/fn_i_start.tpl
@@ -0,0 +1,15 @@
+/*******************************************************************
+parse a @STRUCTNAME@ structure
+********************************************************************/
+BOOL @FUNCNAME@(char *desc, io_struct *ps, int depth,
+ @STRUCTNAME@ *il, unsigned flags)
+{
+ io_debug(ps, depth, desc, "@FUNCNAME@");
+ depth++;
+
+#if 0
+ if (UNMARSHALLING(ps)) {
+ ZERO_STRUCTP(il);
+ }
+#endif
+ /* parse the scalars */
diff --git a/source/aparser/templates/fn_mid.tpl b/source/aparser/templates/fn_mid.tpl
new file mode 100644
index 00000000000..b81de92a5bd
--- /dev/null
+++ b/source/aparser/templates/fn_mid.tpl
@@ -0,0 +1,6 @@
+
+buffers:
+ if (!(flags & PARSE_BUFFERS)) goto end;
+
+ /* now parse the buffers */
+
diff --git a/source/aparser/templates/fn_start.tpl b/source/aparser/templates/fn_start.tpl
new file mode 100644
index 00000000000..a5d58767a6c
--- /dev/null
+++ b/source/aparser/templates/fn_start.tpl
@@ -0,0 +1,17 @@
+/*******************************************************************
+parse a @STRUCTNAME@ structure
+********************************************************************/
+BOOL @FUNCNAME@(char *desc, io_struct *ps, int depth,
+ @STRUCTNAME@ *il, unsigned flags)
+{
+ io_debug(ps, depth, desc, "@FUNCNAME@");
+ depth++;
+
+ if (!(flags & PARSE_SCALARS)) goto buffers;
+
+#if 0
+ if (UNMARSHALLING(ps)) {
+ ZERO_STRUCTP(il);
+ }
+#endif
+ /* parse the scalars */
diff --git a/source/aparser/templates/harness.tpl b/source/aparser/templates/harness.tpl
new file mode 100644
index 00000000000..27c33c0adc1
--- /dev/null
+++ b/source/aparser/templates/harness.tpl
@@ -0,0 +1,5 @@
+
+ if (strcmp(test,"@TEST@")==0) {
+ @TEST@ il;
+ ret = io_@TEST@("@TEST@", ps, 0, &il, flags);
+ } else
diff --git a/source/aparser/templates/harness_end.tpl b/source/aparser/templates/harness_end.tpl
new file mode 100644
index 00000000000..1e15faec167
--- /dev/null
+++ b/source/aparser/templates/harness_end.tpl
@@ -0,0 +1,7 @@
+ {
+ printf("structure %s not found\n", test);
+ ret = False;
+ }
+
+ return ret;
+}
diff --git a/source/aparser/templates/harness_start.tpl b/source/aparser/templates/harness_start.tpl
new file mode 100644
index 00000000000..beba6fc12de
--- /dev/null
+++ b/source/aparser/templates/harness_start.tpl
@@ -0,0 +1,7 @@
+#include "prs_@MODULE@.c"
+
+static BOOL run_test(char *test, io_struct *ps, int flags)
+{
+ BOOL ret;
+
+
diff --git a/source/aparser/templates/ifptr_end.tpl b/source/aparser/templates/ifptr_end.tpl
new file mode 100644
index 00000000000..990635cf453
--- /dev/null
+++ b/source/aparser/templates/ifptr_end.tpl
@@ -0,0 +1 @@
+ }
diff --git a/source/aparser/templates/ifptr_start.tpl b/source/aparser/templates/ifptr_start.tpl
new file mode 100644
index 00000000000..228b84bac93
--- /dev/null
+++ b/source/aparser/templates/ifptr_start.tpl
@@ -0,0 +1,2 @@
+ if (il->@ELEM@) {
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@)))) goto fail;
diff --git a/source/aparser/templates/module_end.tpl b/source/aparser/templates/module_end.tpl
new file mode 100644
index 00000000000..661f7edb95d
--- /dev/null
+++ b/source/aparser/templates/module_end.tpl
@@ -0,0 +1,3 @@
+
+
+/* end auto-generated structure parsers for @MODULE@ */
diff --git a/source/aparser/templates/module_start.tpl b/source/aparser/templates/module_start.tpl
new file mode 100644
index 00000000000..ac6a3c9d98d
--- /dev/null
+++ b/source/aparser/templates/module_start.tpl
@@ -0,0 +1,5 @@
+/* auto-generated structure parsers for @MODULE@
+ generated by aparser
+*/
+#include "prs_@MODULE@.h"
+
diff --git a/source/aparser/templates/prs_.align.tpl b/source/aparser/templates/prs_.align.tpl
new file mode 100644
index 00000000000..25816a23b34
--- /dev/null
+++ b/source/aparser/templates/prs_.align.tpl
@@ -0,0 +1 @@
+ if(!io_align(ps)) goto fail;
diff --git a/source/aparser/templates/prs_align2.tpl b/source/aparser/templates/prs_align2.tpl
new file mode 100644
index 00000000000..54c569b547b
--- /dev/null
+++ b/source/aparser/templates/prs_align2.tpl
@@ -0,0 +1 @@
+ if (!io_align2(ps, @OFFSET@)) goto fail;
diff --git a/source/aparser/templates/prs_align4.tpl b/source/aparser/templates/prs_align4.tpl
new file mode 100644
index 00000000000..702fab13243
--- /dev/null
+++ b/source/aparser/templates/prs_align4.tpl
@@ -0,0 +1 @@
+ if (!io_align4(ps, @OFFSET@)) goto fail;
diff --git a/source/aparser/templates/prs_array.tpl b/source/aparser/templates/prs_array.tpl
new file mode 100644
index 00000000000..4bd6a26c99c
--- /dev/null
+++ b/source/aparser/templates/prs_array.tpl
@@ -0,0 +1,8 @@
+ if ((@FLAGS@ & PARSE_SCALARS) &&
+ !io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@))*(il->@ARRAY_LEN@))) goto fail;
+ {
+ int i;
+ for (i=0;i<il->@ARRAY_LEN@;i++) {
+ if (!io_@TYPE@("@ELEM@...", ps, depth+1, &il->@ELEM@[i], @FLAGS@)) goto fail;
+ }
+ }
diff --git a/source/aparser/templates/prs_array_optional.tpl b/source/aparser/templates/prs_array_optional.tpl
new file mode 100644
index 00000000000..38bd32861f7
--- /dev/null
+++ b/source/aparser/templates/prs_array_optional.tpl
@@ -0,0 +1,5 @@
+ if ((MARSHALLING(ps) && il->@ELEM@) ||
+ ps->data_offset < ps->buffer_size) {
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@)))) goto fail;
+ if (!io_@TYPE@("@ELEM@...", ps, depth+1, il->@ELEM@, @FLAGS@)) goto fail;
+ }
diff --git a/source/aparser/templates/prs_array_remainder.tpl b/source/aparser/templates/prs_array_remainder.tpl
new file mode 100644
index 00000000000..c8b1e2ab5af
--- /dev/null
+++ b/source/aparser/templates/prs_array_remainder.tpl
@@ -0,0 +1,17 @@
+ if (UNMARSHALLING(ps))
+ {
+ int i;
+ for (i=0;ps->data_offset < ps->buffer_size;i++) {
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@))*(i+1))) goto fail;
+ if (!io_@TYPE@("@ELEM@...", ps, depth+1, &il->@ELEM@[i], @FLAGS@)) goto fail;
+ }
+ }
+ else
+ {
+ int i = -1;
+ /* HACK ALERT! */
+ do {
+ i++;
+ if (!io_@TYPE@("@ELEM@...", ps, depth+1, &il->@ELEM@[i], @FLAGS@)) goto fail;
+ } while (il->@ELEM@[i].tag2 != 0);
+ }
diff --git a/source/aparser/templates/prs_break.tpl b/source/aparser/templates/prs_break.tpl
new file mode 100644
index 00000000000..eb540f7be84
--- /dev/null
+++ b/source/aparser/templates/prs_break.tpl
@@ -0,0 +1 @@
+ break;
diff --git a/source/aparser/templates/prs_case.tpl b/source/aparser/templates/prs_case.tpl
new file mode 100644
index 00000000000..06c1bd3ae6e
--- /dev/null
+++ b/source/aparser/templates/prs_case.tpl
@@ -0,0 +1 @@
+ case @CASE@:
diff --git a/source/aparser/templates/prs_case_end.tpl b/source/aparser/templates/prs_case_end.tpl
new file mode 100644
index 00000000000..eb540f7be84
--- /dev/null
+++ b/source/aparser/templates/prs_case_end.tpl
@@ -0,0 +1 @@
+ break;
diff --git a/source/aparser/templates/prs_element.tpl b/source/aparser/templates/prs_element.tpl
new file mode 100644
index 00000000000..e8bf5180cec
--- /dev/null
+++ b/source/aparser/templates/prs_element.tpl
@@ -0,0 +1 @@
+ if (!io_@TYPE@("@ELEM@", ps, depth+1, @PTR@il->@ELEM@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/prs_pointer.tpl b/source/aparser/templates/prs_pointer.tpl
new file mode 100644
index 00000000000..4ebcf19d834
--- /dev/null
+++ b/source/aparser/templates/prs_pointer.tpl
@@ -0,0 +1,2 @@
+ if (!io_pointer("@ELEM@_ptr", ps, depth+1,
+ (void **)&il->@ELEM@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/prs_struct.tpl b/source/aparser/templates/prs_struct.tpl
new file mode 100644
index 00000000000..ab8246db8e7
--- /dev/null
+++ b/source/aparser/templates/prs_struct.tpl
@@ -0,0 +1 @@
+ if (!@MODULE@_io_@TYPE@("@ELEM@", &il->@ELEM@, ps, depth+1)) goto fail;
diff --git a/source/aparser/templates/prs_struct_alloc.tpl b/source/aparser/templates/prs_struct_alloc.tpl
new file mode 100644
index 00000000000..9eae5c92fca
--- /dev/null
+++ b/source/aparser/templates/prs_struct_alloc.tpl
@@ -0,0 +1 @@
+ if (!@MODULE@_io_@TYPE@_alloc("@ELEM@", &il->@ELEM@, ps, depth+1)) goto fail;
diff --git a/source/aparser/templates/prs_uint16.tpl b/source/aparser/templates/prs_uint16.tpl
new file mode 100644
index 00000000000..b40d6d4216f
--- /dev/null
+++ b/source/aparser/templates/prs_uint16.tpl
@@ -0,0 +1 @@
+ if (!io_uint16("@ELEM@", ps, depth+1, &il->@ELEM@)) goto fail;
diff --git a/source/aparser/templates/prs_uint32.tpl b/source/aparser/templates/prs_uint32.tpl
new file mode 100644
index 00000000000..eb76715d28b
--- /dev/null
+++ b/source/aparser/templates/prs_uint32.tpl
@@ -0,0 +1 @@
+ if (!io_uint32("@ELEM@", ps, depth+1, &il->@ELEM@)) goto fail;
diff --git a/source/aparser/templates/prs_uint8s.tpl b/source/aparser/templates/prs_uint8s.tpl
new file mode 100644
index 00000000000..967162213f4
--- /dev/null
+++ b/source/aparser/templates/prs_uint8s.tpl
@@ -0,0 +1,2 @@
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@))*(il->@ARRAY_LEN@))) goto fail;
+ if (!io_uint8s("@ELEM@", ps, depth+1, &il->@ELEM@, il->@ARRAY_LEN@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/prs_uint8s_fixed.tpl b/source/aparser/templates/prs_uint8s_fixed.tpl
new file mode 100644
index 00000000000..26597f419f3
--- /dev/null
+++ b/source/aparser/templates/prs_uint8s_fixed.tpl
@@ -0,0 +1 @@
+ if (!io_uint8s_fixed("@ELEM@", ps, depth+1, il->@ELEM@, @ARRAY_LEN@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/prs_wstring.tpl b/source/aparser/templates/prs_wstring.tpl
new file mode 100644
index 00000000000..4de46f093c8
--- /dev/null
+++ b/source/aparser/templates/prs_wstring.tpl
@@ -0,0 +1,2 @@
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@))*(il->@ARRAY_LEN@))) goto fail;
+ if (!io_wstring("@ELEM@", ps, depth+1, il->@ELEM@, il->@ARRAY_LEN@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/prs_wstring_fixed.tpl b/source/aparser/templates/prs_wstring_fixed.tpl
new file mode 100644
index 00000000000..e33f7c3d5d2
--- /dev/null
+++ b/source/aparser/templates/prs_wstring_fixed.tpl
@@ -0,0 +1,2 @@
+ if (!io_alloc("@ELEM@", ps, (void **)&il->@ELEM@, sizeof(*(il->@ELEM@))*(@ARRAY_LEN@))) goto fail;
+ if (!io_wstring("@ELEM@", ps, depth+1, il->@ELEM@, @ARRAY_LEN@, @FLAGS@)) goto fail;
diff --git a/source/aparser/templates/union_end.tpl b/source/aparser/templates/union_end.tpl
new file mode 100644
index 00000000000..511adbcf602
--- /dev/null
+++ b/source/aparser/templates/union_end.tpl
@@ -0,0 +1,5 @@
+ default:
+ DEBUG(5,("No handler for case %d in @FUNCNAME@\n",
+ (int)il->@SWITCH@));
+ goto fail;
+ }
diff --git a/source/aparser/templates/union_start.tpl b/source/aparser/templates/union_start.tpl
new file mode 100644
index 00000000000..aa052be6972
--- /dev/null
+++ b/source/aparser/templates/union_start.tpl
@@ -0,0 +1 @@
+ switch (il->@SWITCH@) {
diff --git a/source/aparser/token.awk b/source/aparser/token.awk
new file mode 100644
index 00000000000..fb2982f0777
--- /dev/null
+++ b/source/aparser/token.awk
@@ -0,0 +1,180 @@
+# tokenise the input file
+
+function parse_error(msg) {
+ printf("PARSE ERROR: %s\nLine "NR" : "$0"\n", msg);
+ exit 1;
+}
+
+# ignore multi-line C comments.
+{
+ if (t = index($0, "/*")) {
+ if (t > 1)
+ tmp = substr($0, 1, t - 1)
+ else
+ tmp = ""
+ u = index(substr($0, t + 2), "*/")
+ while (u == 0) {
+ getline
+ t = -1
+ u = index($0, "*/")
+ }
+ if (u <= length($0) - 2)
+ $0 = tmp substr($0, t + u + 3)
+ else
+ $0 = tmp
+ }
+}
+
+# ignore blank lines
+/^[ \t]*$/ {
+ next;
+}
+
+/^\#define.*/ {
+ split($0,a,"[ \t;]*");
+ parse_define(a[2], a[3]);
+ next;
+}
+
+# ignore comments
+/^[ \t]*\#/ {
+ next;
+}
+
+/^[ \t]*module/ {
+ {if (module!="") parse_error("you can only specify one module name");}
+ start_module($2);
+ next;
+}
+
+{if (module=="") parse_error("you must specify the module name first");}
+
+/^[ \t]*option/ {
+ set_option($2, $3);
+ next;
+}
+
+/^[ \t]*typedef struct.*\{/ {
+ {if (current_struct!="") parse_error("you cannot have nested structures");}
+ start_struct($3);
+ next;
+}
+
+/^[ \t]*struct.*\{/ {
+ {if (current_struct!="") parse_error("you cannot have nested structures");}
+ start_struct($2);
+ next;
+}
+
+/^[ \t]*typedef union.*\{/ {
+ {if (current_struct!="") parse_error("this cannot appear inside a structure");}
+ split($0,a,"[ \t;()]*");
+ start_union_encap(a[4], a[6], a[7], a[8]);
+ next;
+}
+
+/^[ \t]*void.*\(/ {
+ {if (current_struct!="") parse_error("you cannot have nested structures");}
+ split($0,a,"[ \t;()]*");
+ start_function(a[2], a[3]);
+ return_result="void";
+ next;
+}
+
+/^[ \t]*STATUS.*\(|^[ \t]*void.*\(/ {
+ {if (current_struct!="") parse_error("you cannot have nested structures");}
+ split($0,a,"[ \t;()]*");
+ start_function(a[2], a[3]);
+ return_result="STATUS";
+ next;
+}
+
+{if (current_struct=="") parse_error("this must appear inside a structure");}
+
+/^[ \t]*union.*\{/ {
+ {if (current_union!="") parse_error("you cannot have nested unions");}
+ start_union($2);
+ next;
+}
+
+/^[ \t]*\[switch_is.*union.*\{/ {
+ {if (current_union!="") parse_error("you cannot have nested unions");}
+ split($0,a,"[ \t;()]*");
+ start_union_notencap(a[3]);
+ next;
+}
+
+/^[ \t]*case.*;/ {
+ {if (current_union=="") parse_error("this must appear inide a union");}
+ split($0,a,"[ \t;]*");
+ parse_case(a[3],a[4],a[5]);
+ next;
+}
+
+/^[ \t]*\[case(.*)\].*;/ {
+ {if (current_union=="") parse_error("this must appear inide a union");}
+ split($0,a,"[ \t;()[\]]*");
+ parse_case(a[6],a[8],a[9]);
+ next;
+}
+
+/^[ \t]*\}$/ {
+ {if (current_union=="") parse_error("this must appear inside a union");}
+ end_union("");
+ next;
+}
+
+/^[ \t]*\} .*;/ {
+ if (current_union!="") {
+ split($2,a,"[ \t;]*");
+ end_union(a[1]);
+ next;
+ }
+}
+
+{if (current_union!="") parse_error("this cannot appear inside a union");}
+
+/^[ \t]*\};/ {
+ end_struct("");
+ next;
+}
+
+/^[ \t]*\} .*;/ {
+ split($2,a,"[ \t;]*");
+ end_struct(a[1]);
+ next;
+}
+
+/^[ \t]*\);/ {
+ end_function();
+ return_result="";
+ next;
+}
+
+/^.*size_is.*\*.*;/ {
+ split($0,a,"[ \t;()]*");
+ add_sizeis_array(a[3], a[5], a[6]);
+ next;
+}
+
+/^.*;/ {
+ split($0,a,"[ \t;]*");
+ add_struct_elem(a[2], a[3]);
+ next;
+}
+
+/^[\t ]*void/ {
+ next;
+}
+
+/^[ \t]*\[.*\].*/ {
+ split($0,a,"[ \t;]*");
+ split(a[4], b, "[,]");
+ add_function_param(a[2], a[3], b[1]);
+ next;
+}
+
+{
+ parse_error("Unknown construct.");
+}
+
diff --git a/source/aparser/util.awk b/source/aparser/util.awk
new file mode 100644
index 00000000000..6c5594da688
--- /dev/null
+++ b/source/aparser/util.awk
@@ -0,0 +1,39 @@
+function isaptr(elem)
+{
+ if (substr(elem, 1, 1) == "*") {
+ return 1;
+ }
+ return 0;
+}
+
+function noptr(elem)
+{
+ if (!isaptr(elem)) return elem;
+ return substr(elem, 2);
+}
+
+function xprintf(f, fmt, v1, v2, v3, v4, v5, v6, v7)
+{
+ printf(fmt, v1, v2, v3, v4, v5, v6) > f;
+}
+
+function fatal(why)
+{
+ printf("FATAL: %s\n", why);
+ exit 1;
+}
+
+function numlines(fname,
+ LOCAL, line, count)
+{
+ count=0;
+ while ((getline line < fname) > 0) count++;
+ close(fname);
+ return count;
+}
+
+# return 1 if the string is a constant
+function is_constant(s)
+{
+ return match(s,"^[0-9]+$");
+}
diff --git a/source/aparser/util.c b/source/aparser/util.c
new file mode 100644
index 00000000000..ffa84dbfabc
--- /dev/null
+++ b/source/aparser/util.c
@@ -0,0 +1,112 @@
+#include "parser.h"
+
+
+/*******************************************************************
+ Count the number of characters (not bytes) in a unicode string.
+********************************************************************/
+size_t strlen_w(void *src)
+{
+ size_t len;
+
+ for (len = 0; SVAL(src, len*2); len++) ;
+
+ return len;
+}
+
+/****************************************************************************
+expand a pointer to be a particular size
+****************************************************************************/
+void *Realloc(void *p,size_t size)
+{
+ void *ret=NULL;
+
+ if (size == 0) {
+ if (p) free(p);
+ DEBUG(5,("Realloc asked for 0 bytes\n"));
+ return NULL;
+ }
+
+ if (!p)
+ ret = (void *)malloc(size);
+ else
+ ret = (void *)realloc(p,size);
+
+ if (!ret)
+ DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size));
+
+ return(ret);
+}
+
+
+char *tab_depth(int depth)
+{
+ static pstring spaces;
+ memset(spaces, ' ', depth * 4);
+ spaces[depth * 4] = 0;
+ return spaces;
+}
+
+void print_asc(int level, uchar const *buf, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ {
+ DEBUGADD(level, ("%c", isprint(buf[i]) ? buf[i] : '.'));
+ }
+}
+
+void dump_data(int level, char *buf1, int len)
+{
+ uchar const *buf = (uchar const *)buf1;
+ int i = 0;
+ if (buf == NULL)
+ {
+ DEBUG(level, ("dump_data: NULL, len=%d\n", len));
+ return;
+ }
+ if (len < 0)
+ return;
+ if (len == 0)
+ {
+ DEBUG(level, ("\n"));
+ return;
+ }
+
+ DEBUG(level, ("[%03X] ", i));
+ for (i = 0; i < len;)
+ {
+ DEBUGADD(level, ("%02X ", (int)buf[i]));
+ i++;
+ if (i % 8 == 0)
+ DEBUGADD(level, (" "));
+ if (i % 16 == 0)
+ {
+ print_asc(level, &buf[i - 16], 8);
+ DEBUGADD(level, (" "));
+ print_asc(level, &buf[i - 8], 8);
+ DEBUGADD(level, ("\n"));
+ if (i < len)
+ DEBUGADD(level, ("[%03X] ", i));
+ }
+ }
+
+ if (i % 16 != 0) /* finish off a non-16-char-length row */
+ {
+ int n;
+
+ n = 16 - (i % 16);
+ DEBUGADD(level, (" "));
+ if (n > 8)
+ DEBUGADD(level, (" "));
+ while (n--)
+ DEBUGADD(level, (" "));
+
+ n = MIN(8, i % 16);
+ print_asc(level, &buf[i - (i % 16)], n);
+ DEBUGADD(level, (" "));
+ n = (i % 16) - n;
+ if (n > 0)
+ print_asc(level, &buf[i - n], n);
+ DEBUGADD(level, ("\n"));
+ }
+}
diff --git a/source/aparser/vluke.c b/source/aparser/vluke.c
new file mode 100644
index 00000000000..d3868f2753e
--- /dev/null
+++ b/source/aparser/vluke.c
@@ -0,0 +1,41 @@
+#include "parser.h"
+#include "test.h"
+
+int main(int argc, char *argv[])
+{
+ BOOL ret;
+ char *fname, *test;
+ int fd;
+ struct stat st;
+ io_struct ps;
+
+ if (argc < 3) {
+ printf("usage: vluke <structure> <file>\n");
+ exit(1);
+ }
+
+ test = argv[1];
+ fname = argv[2];
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) {
+ perror(fname);
+ exit(1);
+ }
+ fstat(fd, &st);
+
+ io_init(&ps, 0, MARSHALL);
+ ps.is_dynamic=True;
+ io_read(&ps, fd, st.st_size, 0);
+ ps.data_offset = 0;
+ ps.buffer_size = ps.grow_size;
+ ps.io = UNMARSHALL;
+ ps.autoalign = OPTION_autoalign;
+ ret = run_test(test, &ps, PARSE_SCALARS|PARSE_BUFFERS);
+ printf("\nret=%s\n", ret?"OK":"Bad");
+ printf("Trailer is %d bytes\n\n", ps.grow_size - ps.data_offset);
+ if (ps.grow_size - ps.data_offset > 0) {
+ dump_data(0, ps.data_p + ps.data_offset, ps.grow_size - ps.data_offset);
+ }
+ return !ret;
+}
diff --git a/source/architecture.doc b/source/architecture.doc
new file mode 100644
index 00000000000..eb29792bea0
--- /dev/null
+++ b/source/architecture.doc
@@ -0,0 +1,134 @@
+Samba Architecture
+------------------
+
+First preliminary version Dan Shearer Nov 97
+Quickly scrabbled together from odd bits of mail and memory. Please update.
+
+This document gives a general overview of how Samba works
+internally. The Samba Team has tried to come up with a model which is
+the best possible compromise between elegance, portability, security
+and the constraints imposed by the very messy SMB and CIFS
+protocol.
+
+It also tries to answer some of the frequently asked questions such as:
+
+ * Is Samba secure when running on Unix? The xyz platform?
+ What about the root priveliges issue?
+
+ * Pros and cons of multithreading in various parts of Samba
+
+ * Why not have a separate process for name resolution, WINS,
+ and browsing?
+
+
+Multithreading and Samba
+------------------------
+
+People sometimes tout threads as a uniformly good thing. They are very
+nice in their place but are quite inappropriate for smbd. nmbd is
+another matter, and multi-threading it would be very nice.
+
+The short version is that smbd is not multithreaded, and alternative
+servers that take this approach under Unix (such as Syntax, at the
+time of writing) suffer tremendous performance penalties and are less
+robust. nmbd is not threaded either, but this is because it is not
+possible to do it while keeping code consistent and portable across 35
+or more platforms. (This drawback also applies to threading smbd.)
+
+The longer versions is that there are very good reasons for not making
+smbd multi-threaded. Multi-threading would actually make Samba much
+slower, less scalable, less portable and much less robust. The fact
+that we use a separate process for each connection is one of Samba's
+biggest advantages.
+
+Threading smbd
+--------------
+
+A few problems that would arise from a threaded smbd are:
+
+0) It's not only to create threads instead of processes, but you
+ must care about all variables if they have to be thread specific
+ (currently they would be global).
+
+1) if one thread dies (eg. a seg fault) then all threads die. We can
+immediately throw robustness out the window.
+
+2) many of the system calls we make are blocking. Non-blocking
+equivalents of many calls are either not available or are awkward (and
+slow) to use. So while we block in one thread all clients are
+waiting. Imagine if one share is a slow NFS filesystem and the others
+are fast, we will end up slowing all clients to the speed of NFS.
+
+3) you can't run as a different uid in different threads. This means
+we would have to switch uid/gid on _every_ SMB packet. It would be
+horrendously slow.
+
+4) the per process file descriptor limit would mean that we could only
+support a limited number of clients.
+
+5) we couldn't use the system locking calls as the locking context of
+fcntl() is a process, not a thread.
+
+Threading nmbd
+--------------
+
+This would be ideal, but gets sunk by portability requirements.
+
+Andrew tried to write a test threads library for nmbd that used only
+ansi-C constructs (using setjmp and longjmp). Unfortunately some OSes
+defeat this by restricting longjmp to calling addresses that are
+shallower than the current address on the stack (apparently AIX does
+this). This makes a truly portable threads library impossible. So to
+support all our current platforms we would have to code nmbd both with
+and without threads, and as the real aim of threads is to make the
+code clearer we would not have gained anything. (it is a myth that
+threads make things faster. threading is like recursion, it can make
+things clear but the same thing can always be done faster by some
+other method)
+
+Chris tried to spec out a general design that would abstract threading
+vs separate processes (vs other methods?) and make them accessible
+through some general API. This doesn't work because of the data
+sharing requirements of the protocol (packets in the future depending
+on packets now, etc.) At least, the code would work but would be very
+clumsy, and besides the fork() type model would never work on Unix. (Is there an OS that it would work on, for nmbd?)
+
+A fork() is cheap, but not nearly cheap enough to do on every UDP
+packet that arrives. Having a pool of processes is possible but is
+nasty to program cleanly due to the enormous amount of shared data (in
+complex structures) between the processes. We can't rely on each
+platform having a shared memory system.
+
+nbmd Design
+-----------
+
+Originally Andrew used recursion to simulate a multi-threaded
+environment, which use the stack enormously and made for really
+confusing debugging sessions. Luke Leighton rewrote it to use a
+queuing system that keeps state information on each packet. The
+first version used a single structure which was used by all the
+pending states. As the initialisation of this structure was
+done by adding arguments, as the functionality developed, it got
+pretty messy. So, it was replaced with a higher-order function
+and a pointer to a user-defined memory block. This suddenly
+made things much simpler: large numbers of functions could be
+made static, and modularised. This is the same principle as used
+in NT's kernel, and achieves the same effect as threads, but in
+a single process.
+
+Then Jeremy rewrote nmbd. The packet data in nmbd isn't what's on the
+wire. It's a nice format that is very amenable to processing but still
+keeps the idea of a distinct packet. See "struct packet_struct" in
+nameserv.h. It has all the detail but none of the on-the-wire
+mess. This makes it ideal for using in disk or memory-based databases
+for browsing and WINS support.
+
+nmbd now consists of a series of modules. It...
+
+
+Samba Design and Security
+-------------------------
+
+Why Isn't nmbd Multiple Daemons?
+--------------------------------
+
diff --git a/source/auth/auth.c b/source/auth/auth.c
new file mode 100644
index 00000000000..710b5f27fbf
--- /dev/null
+++ b/source/auth/auth.c
@@ -0,0 +1,272 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Check user is in correct domain if required
+****************************************************************************/
+
+static BOOL check_domain_match(char *user, char *domain)
+{
+ /*
+ * If we aren't serving to trusted domains, we must make sure that
+ * the validation request comes from an account in the same domain
+ * as the Samba server
+ */
+
+ if (!lp_allow_trusted_domains() &&
+ !(strequal("", domain) ||
+ strequal(lp_workgroup(), domain) ||
+ is_netbios_alias_or_name(domain))) {
+ DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
+ return False;
+ } else {
+ return True;
+ }
+}
+
+/****************************************************************************
+ Check a users password, as given in the user-info struct and return various
+ interesting details in the server_info struct.
+
+ This functions does NOT need to be in a become_root()/unbecome_root() pair
+ as it makes the calls itself when needed.
+
+ The return value takes precedence over the contents of the server_info
+ struct. When the return is other than NT_STATUS_NOPROBLEMO the contents
+ of that structure is undefined.
+
+****************************************************************************/
+
+NTSTATUS check_password(const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ const char *pdb_username;
+ auth_methods *auth_method;
+
+ if (!user_info || !auth_info || !server_info) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ DEBUG(3, ("check_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n",
+ user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
+
+ DEBUG(3, ("check_password: mapped user is: [%s]\\[%s]@[%s]\n",
+ user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
+ if (auth_info->challenge_set_by) {
+ DEBUG(10, ("auth_info challenge created by %s\n", auth_info->challenge_set_by));
+ }
+ DEBUG(10, ("challenge is: \n"));
+ dump_data(5, (auth_info)->challenge.data, (auth_info)->challenge.length);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("user_info has passwords of length %d and %d\n",
+ user_info->lm_resp.length, user_info->nt_resp.length));
+ DEBUG(100, ("lm:\n"));
+ dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
+ DEBUG(100, ("nt:\n"));
+ dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
+#endif
+
+ for (auth_method = auth_info->auth_method_list;auth_method; auth_method = auth_method->next)
+ {
+ nt_status = auth_method->auth(auth_method->private_data, user_info, auth_info, server_info);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3, ("check_password: %s authentication for user [%s] suceeded\n",
+ auth_method->name, user_info->smb_name.str));
+ } else {
+ DEBUG(5, ("check_password: %s authentication for user [%s] FAILED with error %s\n",
+ auth_method->name, user_info->smb_name.str, get_nt_error_msg(nt_status)));
+ }
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ break;
+ }
+ }
+
+ /* This needs to be sorted: If it doesn't match, what should we do? */
+ if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+
+ /* This is one of the few places the *relies* (rather than just sets defaults
+ on the value of lp_security(). This needs to change. A new paramater
+ perhaps? */
+ if (lp_security() >= SEC_SERVER) {
+ smb_user_control(user_info, *server_info, nt_status);
+ }
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ pdb_username = pdb_get_username((*server_info)->sam_account);
+ if (!(*server_info)->guest) {
+ /* We might not be root if we are an RPC call */
+ become_root();
+ nt_status = smb_pam_accountcheck(pdb_username);
+ unbecome_root();
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n",
+ pdb_username));
+ } else {
+ DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n",
+ pdb_username, get_nt_error_msg(nt_status)));
+ }
+ }
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG((*server_info)->guest ? 5 : 2,
+ ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n",
+ (*server_info)->guest ? "guest " : "",
+ user_info->smb_name.str,
+ user_info->internal_username.str,
+ pdb_username));
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n",
+ user_info->smb_name.str, user_info->internal_username.str,
+ get_nt_error_msg(nt_status)));
+ ZERO_STRUCTP(server_info);
+ }
+ return nt_status;
+
+}
+
+/****************************************************************************
+ Squash an NT_STATUS return in line with requirements for unauthenticated
+ connections. (session setups in particular)
+****************************************************************************/
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status)
+{
+ if NT_STATUS_IS_OK(nt_status) {
+ return nt_status;
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+ } else {
+ return nt_status;
+ }
+}
+
+
+
+/****************************************************************************
+ COMPATABILITY INTERFACES:
+ ***************************************************************************/
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+static NTSTATUS pass_check_smb(char *smb_name,
+ char *domain,
+ DATA_BLOB lm_pwd,
+ DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext_password,
+ BOOL encrypted)
+
+{
+ NTSTATUS nt_status;
+ auth_usersupplied_info *user_info = NULL;
+ extern auth_authsupplied_info *negprot_global_auth_info;
+ auth_serversupplied_info *server_info = NULL;
+ if (encrypted) {
+ make_user_info_for_reply_enc(&user_info, smb_name,
+ domain,
+ lm_pwd,
+ nt_pwd,
+ plaintext_password);
+ nt_status = check_password(user_info, negprot_global_auth_info, &server_info);
+ } else {
+ auth_authsupplied_info *plaintext_auth_info = NULL;
+ DATA_BLOB chal;
+ if (!make_auth_info_subsystem(&plaintext_auth_info)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ chal = auth_get_challenge(plaintext_auth_info);
+
+ if (!make_user_info_for_reply(&user_info,
+ smb_name, domain, chal.data,
+ plaintext_password)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = check_password(user_info, plaintext_auth_info, &server_info);
+
+ data_blob_free(&chal);
+ free_auth_info(&plaintext_auth_info);
+ }
+ free_user_info(&user_info);
+ free_server_info(&server_info);
+ return nt_status;
+}
+
+/****************************************************************************
+check if a username/password pair is OK either via the system password
+database or the encrypted SMB password database
+return True if the password is correct, False otherwise
+****************************************************************************/
+BOOL password_ok(char *smb_name, DATA_BLOB password_blob)
+{
+
+ DATA_BLOB null_password = data_blob(NULL, 0);
+ extern BOOL global_encrypted_passwords_negotiated;
+ BOOL encrypted = (global_encrypted_passwords_negotiated && password_blob.length == 24);
+
+ if (encrypted) {
+ /*
+ * The password could be either NTLM or plain LM. Try NTLM first,
+ * but fall-through as required.
+ * NTLMv2 makes no sense here.
+ */
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) {
+ return True;
+ }
+
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) {
+ return True;
+ }
+ } else {
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+
diff --git a/source/auth/auth_builtin.c b/source/auth/auth_builtin.c
new file mode 100644
index 00000000000..2bba36f754d
--- /dev/null
+++ b/source/auth/auth_builtin.c
@@ -0,0 +1,90 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ Generic authenticaion types
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Check for a guest logon (username = "") and if so create the required
+ structure.
+****************************************************************************/
+
+static NTSTATUS check_guest_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+
+ if (!(user_info->internal_username.str
+ && *user_info->internal_username.str)) {
+ if (make_server_info_guest(server_info)) {
+ nt_status = NT_STATUS_OK;
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ return nt_status;
+}
+
+BOOL auth_init_guest(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_guest_security;
+ return True;
+}
+
+/****************************************************************************
+ Return an error based on username
+****************************************************************************/
+
+static NTSTATUS check_name_to_ntstatus_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status;
+ fstring user;
+ long error_num;
+ fstrcpy(user, user_info->smb_name.str);
+ strlower(user);
+ error_num = strtoul(user, NULL, 16);
+
+ DEBUG(5,("Error for user %s was %lx\n", user, error_num));
+
+ nt_status = NT_STATUS(error_num);
+
+ return nt_status;
+}
+
+BOOL auth_init_name_to_ntstatus(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_name_to_ntstatus_security;
+ return True;
+}
+
diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c
new file mode 100644
index 00000000000..a5e90aff39a
--- /dev/null
+++ b/source/auth/auth_domain.c
@@ -0,0 +1,498 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ Authenticate against a remote domain
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+BOOL global_machine_password_needs_changing = False;
+
+extern pstring global_myname;
+extern userdom_struct current_user_info;
+
+/***********************************************************************
+ Connect to a remote machine for domain security authentication
+ given a name or IP address.
+ ***********************************************************************/
+
+static BOOL connect_to_domain_password_server(struct cli_state *pcli,
+ char *server, unsigned char *trust_passwd)
+{
+ struct in_addr dest_ip;
+ fstring remote_machine;
+ NTSTATUS result;
+
+ if (cli_initialise(pcli) == NULL) {
+ DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if (is_ipaddress(server)) {
+ struct in_addr to_ip;
+
+ /* we shouldn't have 255.255.255.255 forthe IP address of
+ a password server anyways */
+ if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
+ DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
+ return False;
+ }
+
+ if (!name_status_find("*", 0x20, 0x20, to_ip, remote_machine)) {
+ DEBUG(0, ("connect_to_domain_password_server: Can't "
+ "resolve name for IP %s\n", server));
+ return False;
+ }
+ } else {
+ fstrcpy(remote_machine, server);
+ }
+
+ standard_sub_basic(current_user_info.smb_name, remote_machine);
+ strupper(remote_machine);
+
+ if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
+ DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_connect(pcli, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
+session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ return False;
+ }
+
+ pcli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(pcli)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (pcli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!(pcli->sec_mode & 1)) {
+ DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * We now have an anonymous connection to IPC$ on the domain password server.
+ */
+
+ /*
+ * Even if the connect succeeds we need to setup the netlogon
+ * pipe here. We do this as we may just have changed the domain
+ * account password on the PDC and yet we may be talking to
+ * a BDC that doesn't have this replicated yet. In this case
+ * a successful connect to a DC needs to take the netlogon connect
+ * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
+ */
+
+ if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ result = cli_nt_setup_creds(pcli, trust_passwd);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
+%s. Error was : %s.\n", remote_machine, get_nt_error_msg(result)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return(False);
+ }
+
+ return True;
+}
+
+/***********************************************************************
+ Utility function to attempt a connection to an IP address of a DC.
+************************************************************************/
+
+static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip,
+ unsigned char *trust_passwd)
+{
+ fstring dc_name;
+
+ /*
+ * Ignore addresses we have already tried.
+ */
+
+ if (is_zero_ip(*ip))
+ return False;
+
+ if (!lookup_dc_name(global_myname, lp_workgroup(), ip, dc_name))
+ return False;
+
+ return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
+}
+
+/***********************************************************************
+ We have been asked to dynamcially determine the IP addresses of
+ the PDC and BDC's for this DOMAIN, and query them in turn.
+************************************************************************/
+static BOOL find_connect_pdc(struct cli_state *pcli,
+ unsigned char *trust_passwd,
+ time_t last_change_time)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+ BOOL connected_ok = False;
+ time_t time_now = time(NULL);
+ BOOL use_pdc_only = False;
+
+ /*
+ * If the time the machine password has changed
+ * was less than an hour ago then we need to contact
+ * the PDC only, as we cannot be sure domain replication
+ * has yet taken place. Bug found by Gerald (way to go
+ * Gerald !). JRA.
+ */
+
+ if (time_now - last_change_time < 3600)
+ use_pdc_only = True;
+
+ if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
+ return False;
+
+ /*
+ * Firstly try and contact a PDC/BDC who has the same
+ * network address as any of our interfaces.
+ */
+ for(i = 0; i < count; i++) {
+ if(!is_local_net(ip_list[i]))
+ continue;
+
+ if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ break;
+
+ zero_ip(&ip_list[i]); /* Tried and failed. */
+ }
+
+ /*
+ * Secondly try and contact a random PDC/BDC.
+ */
+ if(!connected_ok) {
+ i = (sys_random() % count);
+
+ if (!(connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ zero_ip(&ip_list[i]); /* Tried and failed. */
+ }
+
+ /*
+ * Finally go through the IP list in turn, ignoring any addresses
+ * we have already tried.
+ */
+ if(!connected_ok) {
+ /*
+ * Try and connect to any of the other IP addresses in the PDC/BDC list.
+ * Note that from a WINS server the #1 IP address is the PDC.
+ */
+ for(i = 0; i < count; i++) {
+ if((connected_ok = attempt_connect_to_dc(pcli, &ip_list[i], trust_passwd)))
+ break;
+ }
+ }
+
+ SAFE_FREE(ip_list);
+
+
+ return connected_ok;
+}
+
+/***********************************************************************
+ Do the same as security=server, but using NT Domain calls and a session
+ key from the machine password. If the server parameter is specified
+ use it, otherwise figure out a server from the 'password server' param.
+************************************************************************/
+
+static NTSTATUS domain_client_validate(const auth_usersupplied_info *user_info,
+ uchar chal[8],
+ auth_serversupplied_info **server_info,
+ char *server, unsigned char *trust_passwd,
+ time_t last_change_time)
+{
+ fstring remote_machine;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 info3;
+ struct cli_state cli;
+ uint32 smb_uid_low;
+ BOOL connected_ok = False;
+ NTSTATUS status;
+ struct passwd *pass;
+
+ /*
+ * At this point, smb_apasswd points to the lanman response to
+ * the challenge in local_challenge, and smb_ntpasswd points to
+ * the NT response to the challenge in local_challenge. Ship
+ * these over the secure channel to a domain controller and
+ * see if they were valid.
+ */
+
+ ZERO_STRUCT(cli);
+
+ while (!connected_ok &&
+ next_token(&server,remote_machine,LIST_SEP,sizeof(remote_machine))) {
+ if(strequal(remote_machine, "*")) {
+ connected_ok = find_connect_pdc(&cli, trust_passwd, last_change_time);
+ } else {
+ connected_ok = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
+ }
+ }
+
+ if (!connected_ok) {
+ DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
+ cli_shutdown(&cli);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* We really don't care what LUID we give the user. */
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ ZERO_STRUCT(info3);
+
+ /*
+ * If this call succeeds, we now have lots of info about the user
+ * in the info3 structure.
+ */
+
+ status = cli_nt_login_network(&cli, user_info, chal, smb_uid_low,
+ &ctr, &info3);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("domain_client_validate: unable to validate password "
+ "for user %s in domain %s to Domain controller %s. "
+ "Error was %s.\n", user_info->smb_name.str,
+ user_info->domain.str, cli.srv_name_slash,
+ get_nt_error_msg(status)));
+ } else {
+ char *dom_user;
+
+ /* Check DOMAIN\username first to catch winbind users, then
+ just the username for local users. */
+
+ asprintf(&dom_user, "%s%s%s", user_info->domain.str,
+ lp_winbind_separator(),
+ user_info->internal_username.str);
+
+ if (!(pass = Get_Pwnam(dom_user)))
+ pass = Get_Pwnam(user_info->internal_username.str);
+
+ free(dom_user);
+
+ if (pass) {
+ make_server_info_pw(server_info, pass);
+ if (!server_info) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ /* Store the user group information in the server_info returned to the caller. */
+
+ if (NT_STATUS_IS_OK(status) && (info3.num_groups2 != 0)) {
+ DOM_SID domain_sid;
+ int i;
+ NT_USER_TOKEN *ptok;
+ auth_serversupplied_info *pserver_info = *server_info;
+
+ if ((pserver_info->ptok = malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
+ DEBUG(0, ("domain_client_validate: out of memory allocating rid group membership\n"));
+ status = NT_STATUS_NO_MEMORY;
+ free_server_info(server_info);
+ goto done;
+ }
+
+ ptok = pserver_info->ptok;
+ ptok->num_sids = (size_t)info3.num_groups2;
+
+ if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
+ DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
+ status = NT_STATUS_NO_MEMORY;
+ free_server_info(server_info);
+ goto done;
+ }
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n"));
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ free_server_info(server_info);
+ goto done;
+ }
+
+ for (i = 0; i < ptok->num_sids; i++) {
+ sid_copy(&ptok->user_sids[i], &domain_sid);
+ sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid);
+ }
+ }
+
+#if 0
+ /*
+ * We don't actually need to do this - plus it fails currently with
+ * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
+ * send here. JRA.
+ */
+
+ if (NT_STATUS_IS_OK(status)) {
+ if(cli_nt_logoff(&cli, &ctr) == False) {
+ DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+ status = NT_STATUS_LOGON_FAILURE;
+ }
+ }
+#endif /* 0 */
+
+ done:
+
+ /* Note - once the cli stream is shutdown the mem_ctx used
+ to allocate the other_sids and gids structures has been deleted - so
+ these pointers are no longer valid..... */
+
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return status;
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
+
+static NTSTATUS check_ntdomain_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ char *p, *pserver;
+ unsigned char trust_passwd[16];
+ time_t last_change_time;
+
+ if (!user_info || !server_info || !auth_info) {
+ DEBUG(1,("check_ntdomain_security: Critical variables not present. Failing.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /*
+ * Check that the requested domain is not our own machine name.
+ * If it is, we should never check the PDC here, we use our own local
+ * password file.
+ */
+
+ if(is_netbios_alias_or_name(user_info->domain.str)) {
+ DEBUG(3,("check_ntdomain_security: Requested domain was for this machine.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ become_root();
+
+ /*
+ * Get the machine account password for our primary domain
+ */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time))
+ {
+ DEBUG(0, ("check_domain_security: could not fetch trust account password for domain %s\n", lp_workgroup()));
+ unbecome_root();
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ unbecome_root();
+
+ /* Test if machine password is expired and need to be changed */
+ if (time(NULL) > last_change_time + lp_machine_password_timeout())
+ {
+ global_machine_password_needs_changing = True;
+ }
+
+ /*
+ * Treat each name in the 'password server =' line as a potential
+ * PDC/BDC. Contact each in turn and try and authenticate.
+ */
+
+ pserver = lp_passwordserver();
+ if (! *pserver) pserver = "*";
+ p = pserver;
+
+ nt_status = domain_client_validate(user_info, (uchar *)auth_info->challenge.data,server_info,
+ p, trust_passwd, last_change_time);
+
+ return nt_status;
+}
+
+BOOL auth_init_ntdomain(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_ntdomain_security;
+ return True;
+}
diff --git a/source/auth/auth_info.c b/source/auth/auth_info.c
new file mode 100644
index 00000000000..cc13d5a8b95
--- /dev/null
+++ b/source/auth/auth_info.c
@@ -0,0 +1,291 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ Authentication utility functions
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+const struct auth_init_function builtin_auth_init_functions[] = {
+ { "guest", auth_init_guest },
+ { "rhosts", auth_init_rhosts },
+ { "hostsequiv", auth_init_hostsequiv },
+ { "sam", auth_init_sam },
+ { "samstrict", auth_init_samstrict },
+ { "unix", auth_init_unix },
+ { "smbserver", auth_init_smbserver },
+ { "ntdomain", auth_init_ntdomain },
+ { "winbind", auth_init_winbind },
+#ifdef DEVELOPER
+ { "name_to_ntstatus", auth_init_name_to_ntstatus },
+#endif
+ { NULL, NULL}
+};
+
+/***************************************************************************
+ Make a auth_info struct
+***************************************************************************/
+
+static BOOL make_auth_info(auth_authsupplied_info **auth_info)
+{
+ *auth_info = malloc(sizeof(**auth_info));
+ if (!*auth_info) {
+ DEBUG(0,("make_auth_info: malloc failed!\n"));
+ return False;
+ }
+ ZERO_STRUCTP(*auth_info);
+
+ return True;
+}
+
+/***************************************************************************
+ Make a auth_info struct with a specified list.
+***************************************************************************/
+
+BOOL make_auth_info_list(auth_authsupplied_info **auth_info, auth_methods *list)
+{
+ if (!make_auth_info(auth_info)) {
+ return False;
+ }
+
+ (*auth_info)->auth_method_list = list;
+
+ return True;
+}
+
+/***************************************************************************
+ Make a auth_info struct for the auth subsystem
+***************************************************************************/
+
+static BOOL make_auth_info_text_list(auth_authsupplied_info **auth_info, char **text_list)
+{
+ auth_methods *list = NULL;
+ auth_methods *t = NULL;
+ auth_methods *tmp;
+ int i;
+
+ if (!text_list) {
+ DEBUG(2,("No auth method list!?\n"));
+ return False;
+ }
+
+ for (;*text_list; text_list++)
+ {
+ DEBUG(5,("Attempting to find an auth method to match %s\n", *text_list));
+ for (i = 0; builtin_auth_init_functions[i].name; i++)
+ {
+ if (strequal(builtin_auth_init_functions[i].name, *text_list))
+ {
+ DEBUG(5,("Found auth method %s (at pos %d)\n", *text_list, i));
+ if (builtin_auth_init_functions[i].init(&t)) {
+ DEBUG(5,("auth method %s has a valid init\n", *text_list));
+ t->name = builtin_auth_init_functions[i].name;
+ DLIST_ADD_END(list, t, tmp);
+ } else {
+ DEBUG(5,("auth method %s DOES NOT have a valid init\n", *text_list));
+ }
+ break;
+ }
+ }
+ }
+
+ make_auth_info_list(auth_info, list);
+
+ return True;
+}
+
+/***************************************************************************
+ Make a auth_info struct for the auth subsystem
+***************************************************************************/
+
+BOOL make_auth_info_subsystem(auth_authsupplied_info **auth_info)
+{
+ char **auth_method_list = NULL;
+
+ if (lp_auth_methods() && !lp_list_copy(&auth_method_list, lp_auth_methods())) {
+ return False;
+ }
+
+ if (auth_method_list == NULL) {
+ switch (lp_security())
+ {
+ case SEC_DOMAIN:
+ DEBUG(5,("Making default auth method list for security=domain\n"));
+ auth_method_list = lp_list_make("guest samstrict ntdomain");
+ break;
+ case SEC_SERVER:
+ DEBUG(5,("Making default auth method list for security=server\n"));
+ auth_method_list = lp_list_make("guest samstrict smbserver");
+ break;
+ case SEC_USER:
+ if (lp_encrypted_passwords()) {
+ DEBUG(5,("Making default auth method list for security=user, encrypt passwords = yes\n"));
+ auth_method_list = lp_list_make("guest sam");
+ } else {
+ DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
+ auth_method_list = lp_list_make("guest unix");
+ }
+ break;
+ case SEC_SHARE:
+ if (lp_encrypted_passwords()) {
+ DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
+ auth_method_list = lp_list_make("guest sam");
+ } else {
+ DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
+ auth_method_list = lp_list_make("guest unix");
+ }
+ break;
+ case SEC_ADS:
+ DEBUG(5,("Making default auth method list for security=ADS\n"));
+ auth_method_list = lp_list_make("guest samstrict ads ntdomain");
+ break;
+ default:
+ DEBUG(5,("Unknown auth method!\n"));
+ return False;
+ }
+ } else {
+ DEBUG(5,("Using specified auth order\n"));
+ }
+
+ if (!make_auth_info_text_list(auth_info, auth_method_list)) {
+ lp_list_free(&auth_method_list);
+ return False;
+ }
+
+ lp_list_free(&auth_method_list);
+ return True;
+}
+
+/***************************************************************************
+ Make a auth_info struct with a random challenge
+***************************************************************************/
+
+BOOL make_auth_info_random(auth_authsupplied_info **auth_info)
+{
+ uchar chal[8];
+ if (!make_auth_info_subsystem(auth_info)) {
+ return False;
+ }
+
+ generate_random_buffer(chal, sizeof(chal), False);
+ (*auth_info)->challenge = data_blob(chal, sizeof(chal));
+
+ (*auth_info)->challenge_set_by = "random";
+
+ return True;
+}
+
+/***************************************************************************
+ Make a auth_info struct with a fixed challenge
+***************************************************************************/
+
+BOOL make_auth_info_fixed(auth_authsupplied_info **auth_info, uchar chal[8])
+{
+ if (!make_auth_info_subsystem(auth_info)) {
+ return False;
+ }
+
+ (*auth_info)->challenge = data_blob(chal, 8);
+ return True;
+}
+
+/***************************************************************************
+ Clear out a auth_info struct that has been allocated
+***************************************************************************/
+
+void free_auth_info(auth_authsupplied_info **auth_info)
+{
+ auth_methods *list;
+ if (*auth_info != NULL) {
+ list = (*auth_info)->auth_method_list;
+ while (list) {
+ auth_methods *old_head = list;
+ if (list->free_private_data) {
+ list->free_private_data(&(list->private_data));
+ }
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
+
+ data_blob_free(&(*auth_info)->challenge);
+ ZERO_STRUCT(**auth_info);
+ }
+ SAFE_FREE(*auth_info);
+}
+
+/****************************************************************************
+ Try to get a challenge out of the various authenticaion modules.
+ It is up to the caller to free it.
+****************************************************************************/
+
+DATA_BLOB auth_get_challenge(auth_authsupplied_info *auth_info)
+{
+ DATA_BLOB challenge = data_blob(NULL, 0);
+ char *challenge_set_by = NULL;
+ auth_methods *auth_method;
+
+ if (auth_info->challenge.length) {
+ DEBUG(5, ("auth_get_challenge: returning previous challenge (normal)\n"));
+ return data_blob(auth_info->challenge.data, auth_info->challenge.length);
+ }
+
+ for (auth_method = auth_info->auth_method_list; auth_method; auth_method = auth_method->next)
+ {
+ if (auth_method->get_chal) {
+ DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
+ if (challenge_set_by) {
+ DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authenticaion method %s has already specified a challenge. Challenge by %s ignored.\n",
+ challenge_set_by, auth_method->name));
+ } else {
+ challenge = auth_method->get_chal(&auth_method->private_data, auth_info);
+ if (challenge.length) {
+ DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name));
+ auth_info->challenge = challenge;
+ challenge_set_by = auth_method->name;
+ auth_info->challenge_set_method = auth_method;
+ } else {
+ DEBUG(3, ("auth_get_challenge: getting challenge from authenticaion method %s FAILED.\n",
+ auth_method->name));
+ }
+ }
+ } else {
+ DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
+ }
+ }
+
+ if (!challenge_set_by) {
+ uchar chal[8];
+
+ generate_random_buffer(chal, sizeof(chal), False);
+ auth_info->challenge = data_blob(chal, sizeof(chal));
+
+ challenge_set_by = "random";
+ }
+
+ DEBUG(5, ("auth_info challenge created by %s\n", challenge_set_by));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, auth_info->challenge.data, (auth_info)->challenge.length);
+
+ SMB_ASSERT(auth_info->challenge.length == 8);
+
+ auth_info->challenge_set_by=challenge_set_by;
+
+ return data_blob(auth_info->challenge.data, auth_info->challenge.length);
+}
+
+
diff --git a/source/auth/auth_rhosts.c b/source/auth/auth_rhosts.c
new file mode 100644
index 00000000000..2605f0770a2
--- /dev/null
+++ b/source/auth/auth_rhosts.c
@@ -0,0 +1,228 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Main SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Read the a hosts.equiv or .rhosts file and check if it
+ allows this user from this machine.
+****************************************************************************/
+
+static BOOL check_user_equiv(const char *user, const char *remote, const char *equiv_file)
+{
+ int plus_allowed = 1;
+ char *file_host;
+ char *file_user;
+ char **lines = file_lines_load(equiv_file, NULL);
+ int i;
+
+ DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
+ if (! lines) return False;
+ for (i=0; lines[i]; i++) {
+ char *buf = lines[i];
+ trim_string(buf," "," ");
+
+ if (buf[0] != '#' && buf[0] != '\n')
+ {
+ BOOL is_group = False;
+ int plus = 1;
+ char *bp = buf;
+ if (strcmp(buf, "NO_PLUS\n") == 0)
+ {
+ DEBUG(6, ("check_user_equiv NO_PLUS\n"));
+ plus_allowed = 0;
+ }
+ else {
+ if (buf[0] == '+')
+ {
+ bp++;
+ if (*bp == '\n' && plus_allowed)
+ {
+ /* a bare plus means everbody allowed */
+ DEBUG(6, ("check_user_equiv everybody allowed\n"));
+ file_lines_free(lines);
+ return True;
+ }
+ }
+ else if (buf[0] == '-')
+ {
+ bp++;
+ plus = 0;
+ }
+ if (*bp == '@')
+ {
+ is_group = True;
+ bp++;
+ }
+ file_host = strtok(bp, " \t\n");
+ file_user = strtok(NULL, " \t\n");
+ DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
+ file_user ? file_user : "(null)" ));
+ if (file_host && *file_host)
+ {
+ BOOL host_ok = False;
+
+#if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
+ if (is_group)
+ {
+ static char *mydomain = NULL;
+ if (!mydomain)
+ yp_get_default_domain(&mydomain);
+ if (mydomain && innetgr(file_host,remote,user,mydomain))
+ host_ok = True;
+ }
+#else
+ if (is_group)
+ {
+ DEBUG(1,("Netgroups not configured\n"));
+ continue;
+ }
+#endif
+
+ /* is it this host */
+ /* the fact that remote has come from a call of gethostbyaddr
+ * means that it may have the fully qualified domain name
+ * so we could look up the file version to get it into
+ * a canonical form, but I would rather just type it
+ * in full in the equiv file
+ */
+ if (!host_ok && !is_group && strequal(remote, file_host))
+ host_ok = True;
+
+ if (!host_ok)
+ continue;
+
+ /* is it this user */
+ if (file_user == 0 || strequal(user, file_user))
+ {
+ DEBUG(5, ("check_user_equiv matched %s%s %s\n",
+ (plus ? "+" : "-"), file_host,
+ (file_user ? file_user : "")));
+ file_lines_free(lines);
+ return (plus ? True : False);
+ }
+ }
+ }
+ }
+ }
+ file_lines_free(lines);
+ return False;
+}
+
+
+/****************************************************************************
+check for a possible hosts equiv or rhosts entry for the user
+****************************************************************************/
+
+static BOOL check_hosts_equiv(struct passwd *pass)
+{
+ char *fname = NULL;
+
+ if (!pass)
+ return(False);
+
+ fname = lp_hosts_equiv();
+
+ /* note: don't allow hosts.equiv on root */
+ if (fname && *fname && (pass->pw_uid != 0)) {
+ if (check_user_equiv(pass->pw_name,client_name(),fname))
+ return(True);
+ }
+
+ return(False);
+}
+
+
+/****************************************************************************
+ Check for a valid .rhosts/hosts.equiv entry for this user
+****************************************************************************/
+
+static NTSTATUS check_hostsequiv_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
+
+ if (pass) {
+ if (check_hosts_equiv(pass)) {
+ nt_status = NT_STATUS_OK;
+ make_server_info_pw(server_info, pass);
+ }
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+
+ return nt_status;
+}
+
+
+/****************************************************************************
+ Check for a valid .rhosts/hosts.equiv entry for this user
+****************************************************************************/
+
+static NTSTATUS check_rhosts_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
+ pstring rhostsfile;
+
+ if (pass) {
+ char *home = pass->pw_dir;
+ if (home) {
+ slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
+ become_root();
+ if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) {
+ nt_status = NT_STATUS_OK;
+ make_server_info_pw(server_info, pass);
+ }
+ unbecome_root();
+ }
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+
+ return nt_status;
+}
+
+BOOL auth_init_hostsequiv(auth_methods **auth_method)
+{
+
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+ (*auth_method)->auth = check_hostsequiv_security;
+ return True;
+}
+
+BOOL auth_init_rhosts(auth_methods **auth_method)
+{
+
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+ (*auth_method)->auth = check_rhosts_security;
+ return True;
+}
diff --git a/source/auth/auth_sam.c b/source/auth/auth_sam.c
new file mode 100644
index 00000000000..d899006cf8b
--- /dev/null
+++ b/source/auth/auth_sam.c
@@ -0,0 +1,447 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+core of smb password checking routine.
+****************************************************************************/
+static BOOL smb_pwd_check_ntlmv1(DATA_BLOB nt_response,
+ const uchar *part_passwd,
+ DATA_BLOB sec_blob,
+ uint8 user_sess_key[16])
+{
+ /* Finish the encryption of part_passwd. */
+ uchar p24[24];
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return False;
+ }
+
+ if (sec_blob.length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%d)\n", sec_blob.length));
+ return False;
+ }
+
+ if (nt_response.length != 24) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response.length));
+ return False;
+ }
+
+ SMBOWFencrypt(part_passwd, sec_blob.data, p24);
+ if (user_sess_key != NULL)
+ {
+ SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
+ }
+
+
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |"));
+ dump_data(100, part_passwd, 16);
+ DEBUG(100,("Password from client was |"));
+ dump_data(100, nt_response.data, nt_response.length);
+ DEBUG(100,("Given challenge was |"));
+ dump_data(100, sec_blob.data, sec_blob.length);
+ DEBUG(100,("Value from encryption was |"));
+ dump_data(100, p24, 24);
+#endif
+ return (memcmp(p24, nt_response.data, 24) == 0);
+}
+
+/****************************************************************************
+core of smb password checking routine.
+****************************************************************************/
+static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response,
+ const uchar *part_passwd,
+ const DATA_BLOB sec_blob,
+ const char *user, const char *domain,
+ uint8 user_sess_key[16])
+{
+ /* Finish the encryption of part_passwd. */
+ uchar kr[16];
+ uchar value_from_encryption[16];
+ uchar client_response[16];
+ DATA_BLOB client_key_data;
+
+ if (part_passwd == NULL)
+ {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always False */
+ return False;
+ }
+
+ if (ntv2_response.length < 16) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy... */
+ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%d)\n",
+ ntv2_response.length));
+ return False;
+ }
+
+ client_key_data = data_blob(ntv2_response.data+16, ntv2_response.length-16);
+ memcpy(client_response, ntv2_response.data, sizeof(client_response));
+
+ ntv2_owf_gen(part_passwd, user, domain, kr);
+ SMBOWFencrypt_ntv2(kr, sec_blob, client_key_data, (char *)value_from_encryption);
+ if (user_sess_key != NULL)
+ {
+ SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |"));
+ dump_data(100, part_passwd, 16);
+ DEBUG(100,("Password from client was |"));
+ dump_data(100, ntv2_response.data, ntv2_response.length);
+ DEBUG(100,("Variable data from client was |"));
+ dump_data(100, client_key_data.data, client_key_data.length);
+ DEBUG(100,("Given challenge was |"));
+ dump_data(100, sec_blob.data, sec_blob.length);
+ DEBUG(100,("Value from encryption was |"));
+ dump_data(100, value_from_encryption, 16);
+#endif
+ data_blob_clear_free(&client_key_data);
+ return (memcmp(value_from_encryption, client_response, 16) == 0);
+}
+
+
+/****************************************************************************
+ Do a specific test for an smb password being correct, given a smb_password and
+ the lanman and NT responses.
+****************************************************************************/
+static NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ uint8 user_sess_key[16])
+{
+ uint16 acct_ctrl;
+ const uint8 *nt_pw, *lm_pw;
+ uint32 ntlmssp_flags;
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+ if (acct_ctrl & ACB_PWNOTREQ)
+ {
+ if (lp_null_passwords())
+ {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass)));
+ return(NT_STATUS_OK);
+ }
+ else
+ {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass)));
+ return(NT_STATUS_LOGON_FAILURE);
+ }
+ }
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ lm_pw = pdb_get_lanman_passwd(sampass);
+
+ ntlmssp_flags = user_info->ntlmssp_flags;
+
+ if (nt_pw == NULL) {
+ DEBUG(3,("smb_password_ok: NO NT password stored for user %s.\n",
+ pdb_get_username(sampass)));
+ /* No return, we want to check the LM hash below in this case */
+ ntlmssp_flags &= (~(NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_NTLM2));
+ }
+
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("smb_password_ok: Checking NTLMv2 password\n"));
+ if (smb_pwd_check_ntlmv2( user_info->nt_resp,
+ nt_pw, auth_info->challenge,
+ user_info->smb_name.str,
+ user_info->client_domain.str,
+ user_sess_key))
+ {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("smb_password_ok: NTLMv2 password check failed\n"));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM) {
+ if (lp_ntlm_auth()) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(user_info->nt_resp,
+ nt_pw, auth_info->challenge,
+ user_sess_key))
+ {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("smb_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(2,("smb_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
+ /* No return, we want to check the LM hash below in this case */
+ }
+ }
+
+ if (lm_pw == NULL) {
+ DEBUG(3,("smb_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass)));
+ ntlmssp_flags &= (~NTLMSSP_NEGOTIATE_OEM);
+ }
+
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_OEM) {
+
+ if (user_info->lm_resp.length != 24) {
+ DEBUG(2,("smb_password_ok: invalid LanMan password length (%d) for user %s\n",
+ user_info->nt_resp.length, pdb_get_username(sampass)));
+ }
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("smb_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ DEBUG(4,("smb_password_ok: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(user_info->lm_resp,
+ lm_pw, auth_info->challenge,
+ user_sess_key))
+ {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(4,("smb_password_ok: LM password check failed for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+
+ /* Should not be reached, but if they send nothing... */
+ DEBUG(3,("smb_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+/****************************************************************************
+ Do a specific test for a SAM_ACCOUNT being vaild for this connection
+ (ie not disabled, expired and the like).
+****************************************************************************/
+static NTSTATUS sam_account_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info)
+{
+ uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
+ char *workstation_list;
+ time_t kickoff_time;
+
+ DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
+
+ /* Quit if the account was disabled. */
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(1,("Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ /* Test account expire time */
+
+ kickoff_time = pdb_get_kickoff_time(sampass);
+ if (kickoff_time != 0 && time(NULL) > kickoff_time) {
+ DEBUG(1,("Account for user '%s' has expried.\n", pdb_get_username(sampass)));
+ DEBUG(3,("Account expired at '%ld' unix time.\n", (long)kickoff_time));
+ return NT_STATUS_ACCOUNT_EXPIRED;
+ }
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) {
+ time_t must_change_time = pdb_get_pass_must_change_time(sampass);
+ time_t last_set_time = pdb_get_pass_last_set_time(sampass);
+
+ /* check for immediate expiry "must change at next logon" */
+ if (must_change_time == 0 && last_set_time != 0) {
+ DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
+ return NT_STATUS_PASSWORD_MUST_CHANGE;
+ }
+
+ /* check for expired password */
+ if (must_change_time < time(NULL) && must_change_time != 0) {
+ DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
+ DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time));
+ return NT_STATUS_PASSWORD_EXPIRED;
+ }
+ }
+
+ /* Test workstation. Workstation list is comma separated. */
+
+ workstation_list = strdup(pdb_get_workstations(sampass));
+
+ if (!workstation_list) return NT_STATUS_NO_MEMORY;
+
+ if (*workstation_list) {
+ BOOL invalid_ws = True;
+ char *s = workstation_list;
+
+ fstring tok;
+
+ while (next_token(&s, tok, ",", sizeof(tok))) {
+ DEBUG(10,("checking for workstation match %s and %s (len=%d)\n",
+ tok, user_info->wksta_name.str, user_info->wksta_name.len));
+ if(strequal(tok, user_info->wksta_name.str)) {
+ invalid_ws = False;
+ break;
+ }
+ }
+
+ SAFE_FREE(workstation_list);
+ if (invalid_ws)
+ return NT_STATUS_INVALID_WORKSTATION;
+ } else {
+ SAFE_FREE(workstation_list);
+ }
+
+ if (acct_ctrl & ACB_DOMTRUST) {
+ DEBUG(2,("session_trust_account: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
+ }
+
+ if (acct_ctrl & ACB_SVRTRUST) {
+ DEBUG(2,("session_trust_account: Server trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
+ }
+
+ if (acct_ctrl & ACB_WSTRUST) {
+ DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
+ return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash supplied in the user_info structure
+return an NT_STATUS constant.
+****************************************************************************/
+
+static NTSTATUS check_sam_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ SAM_ACCOUNT *sampass=NULL;
+ BOOL ret;
+ NTSTATUS nt_status;
+ uint8 user_sess_key[16];
+ const uint8* lm_hash;
+
+ if (!user_info || !auth_info) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (!pdb_init_sam(&sampass)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get the account information */
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
+ unbecome_root();
+
+ if (ret == False)
+ {
+ DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ nt_status = sam_password_ok(sampass, user_info, auth_info, user_sess_key);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ pdb_free_sam(&sampass);
+ return nt_status;
+ }
+
+ nt_status = sam_account_ok(sampass, user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ pdb_free_sam(&sampass);
+ return nt_status;
+ }
+
+ if (!make_server_info_sam(server_info, sampass)) {
+ DEBUG(0,("failed to malloc memory for server_info\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
+ if (lm_hash) {
+ memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
+ }
+
+ memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
+
+ return nt_status;
+}
+
+BOOL auth_init_sam(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_sam_security;
+ return True;
+}
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash supplied in the user_info structure
+return an NT_STATUS constant.
+****************************************************************************/
+
+static NTSTATUS check_samstrict_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+
+ if (!user_info || !auth_info) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* If we are a domain member, we must not
+ attempt to check the password locally,
+ unless it is one of our aliases. */
+
+ if (!is_netbios_alias_or_name(user_info->domain.str)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ return check_sam_security(my_private_data, user_info, auth_info, server_info);
+}
+
+BOOL auth_init_samstrict(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_samstrict_security;
+ return True;
+}
+
diff --git a/source/auth/auth_server.c b/source/auth/auth_server.c
new file mode 100644
index 00000000000..7e43d529d27
--- /dev/null
+++ b/source/auth/auth_server.c
@@ -0,0 +1,365 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Authenticate to a remote server
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern userdom_struct current_user_info;
+
+/****************************************************************************
+ Support for server level security.
+****************************************************************************/
+
+static struct cli_state *server_cryptkey(void)
+{
+ struct cli_state *cli = NULL;
+ fstring desthost;
+ struct in_addr dest_ip;
+ char *p, *pserver;
+ BOOL connected_ok = False;
+
+ if (!(cli = cli_initialise(cli)))
+ return NULL;
+
+ /* security = server just can't function with spnego */
+ cli->use_spnego = False;
+
+ pserver = strdup(lp_passwordserver());
+ p = pserver;
+
+ while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
+ standard_sub_basic(current_user_info.smb_name, desthost);
+ strupper(desthost);
+
+ if(!resolve_name( desthost, &dest_ip, 0x20)) {
+ DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
+ continue;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
+ continue;
+ }
+
+ if (cli_connect(cli, desthost, &dest_ip)) {
+ DEBUG(3,("connected to password server %s\n",desthost));
+ connected_ok = True;
+ break;
+ }
+ }
+
+ SAFE_FREE(pserver);
+
+ if (!connected_ok) {
+ DEBUG(0,("password server not available\n"));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip))
+ return NULL;
+
+ if (strequal(desthost,myhostname())) {
+ exit_server("Password server loop!");
+ }
+
+ DEBUG(3,("got session\n"));
+
+ if (!cli_negprot(cli)) {
+ DEBUG(1,("%s rejected the negprot\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN2 ||
+ !(cli->sec_mode & 1)) {
+ DEBUG(1,("%s isn't in user level security mode\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ DEBUG(3,("password server OK\n"));
+
+ return cli;
+}
+
+/****************************************************************************
+ Clean up our allocated cli.
+****************************************************************************/
+
+static void free_server_private_data(void **private_data_pointer)
+{
+ struct cli_state **cli = (struct cli_state **)private_data_pointer;
+ if (*cli && (*cli)->initialised) {
+ cli_shutdown(*cli);
+ }
+}
+
+/****************************************************************************
+ Send a 'keepalive' packet down the cli pipe.
+****************************************************************************/
+
+static void send_server_keepalive(void **private_data_pointer)
+{
+ struct cli_state **cli = (struct cli_state **)private_data_pointer;
+
+ /* also send a keepalive to the password server if its still
+ connected */
+ if (cli && *cli && (*cli)->initialised) {
+ if (!send_keepalive((*cli)->fd)) {
+ DEBUG( 2, ( "password server keepalive failed.\n"));
+ cli_shutdown(*cli);
+ }
+ }
+}
+
+/****************************************************************************
+ Get the challenge out of a password server.
+****************************************************************************/
+
+static DATA_BLOB auth_get_challenge_server(void **my_private_data, const struct authsupplied_info *auth_info)
+{
+ struct cli_state *cli = server_cryptkey();
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+
+ if ((cli->sec_mode & 2) == 0) {
+ /* We can't work with unencrypted password servers
+ unless 'encrypt passwords = no' */
+ DEBUG(5,("make_auth_info_server: Server is unencrypted, no challenge available..\n"));
+
+ /* However, it is still a perfectly fine connection
+ to pass that unencrypted password over */
+ *my_private_data = (void *)cli;
+ return data_blob(NULL, 0);
+
+ } else if (cli->secblob.length < 8) {
+ /* We can't do much if we don't get a full challenge */
+ DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n"));
+ cli_shutdown(cli);
+ return data_blob(NULL, 0);
+ }
+
+ *my_private_data = (void *)cli;
+
+ return data_blob(cli->secblob.data,8);
+ } else {
+ return data_blob(NULL, 0);
+ }
+}
+
+
+/****************************************************************************
+ Check for a valid username and password in security=server mode.
+ - Validate a password with the password server.
+****************************************************************************/
+
+static NTSTATUS check_smbserver_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ struct cli_state *cli;
+ static unsigned char badpass[24];
+ static fstring baduser;
+ static BOOL tested_password_server = False;
+ static BOOL bad_password_server = False;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ BOOL locally_made_cli = False;
+
+ /*
+ * Check that the requested domain is not our own machine name.
+ * If it is, we should never check the PDC here, we use our own local
+ * password file.
+ */
+
+ if(is_netbios_alias_or_name(user_info->domain.str)) {
+ DEBUG(3,("check_smbserver_security: Requested domain was for this machine.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ cli = my_private_data;
+
+ if (cli) {
+ } else {
+ cli = server_cryptkey();
+ locally_made_cli = True;
+ }
+
+ if (!cli || !cli->initialised) {
+ DEBUG(1,("password server is not connected (cli not initilised)\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if ((cli->sec_mode & 2) == 0) {
+ if (user_info->encrypted) {
+ DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ } else {
+ if (memcmp(cli->secblob.data, auth_info->challenge.data, 8) != 0) {
+ DEBUG(1,("the challenge that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ if(badpass[0] == 0)
+ memset(badpass, 0x1f, sizeof(badpass));
+
+ if((user_info->nt_resp.length == sizeof(badpass)) &&
+ !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
+ /*
+ * Very unlikely, our random bad password is the same as the users
+ * password.
+ */
+ memset(badpass, badpass[0]+1, sizeof(badpass));
+ }
+
+ if(baduser[0] == 0) {
+ fstrcpy(baduser, INVALID_USER_PREFIX);
+ fstrcat(baduser, global_myname);
+ }
+
+ /*
+ * Attempt a session setup with a totally incorrect password.
+ * If this succeeds with the guest bit *NOT* set then the password
+ * server is broken and is not correctly setting the guest bit. We
+ * need to detect this as some versions of NT4.x are broken. JRA.
+ */
+
+ /* I sure as hell hope that there arn't servers out there that take
+ * NTLMv2 and have this bug, as we don't test for that...
+ * - abartlet@samba.org
+ */
+
+ if ((!tested_password_server) && (lp_paranoid_server_security())) {
+ if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass),
+ (char *)badpass, sizeof(badpass), user_info->domain.str)) {
+
+ /*
+ * We connected to the password server so we
+ * can say we've tested it.
+ */
+ tested_password_server = True;
+
+ if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
+ DEBUG(0,("server_validate: password server %s allows users as non-guest \
+with a bad password.\n", cli->desthost));
+ DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
+use this machine as the password server.\n"));
+ cli_ulogoff(cli);
+
+ /*
+ * Password server has the bug.
+ */
+ bad_password_server = True;
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ cli_ulogoff(cli);
+ }
+ } else {
+
+ /*
+ * We have already tested the password server.
+ * Fail immediately if it has the bug.
+ */
+
+ if(bad_password_server) {
+ DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
+with a bad password.\n", cli->desthost));
+ DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
+use this machine as the password server.\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ /*
+ * Now we know the password server will correctly set the guest bit, or is
+ * not guest enabled, we can try with the real password.
+ */
+
+ if (!user_info->encrypted) {
+ /* Plaintext available */
+ if (!cli_session_setup(cli, user_info->smb_name.str,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length,
+ NULL, 0,
+ user_info->domain.str)) {
+ DEBUG(1,("password server %s rejected the password\n", cli->desthost));
+ /* Make this cli_nt_error() when the conversion is in */
+ nt_status = cli_nt_error(cli);
+ } else {
+ nt_status = NT_STATUS_OK;
+ }
+ } else {
+ if (!cli_session_setup(cli, user_info->smb_name.str,
+ (char *)user_info->lm_resp.data,
+ user_info->lm_resp.length,
+ (char *)user_info->nt_resp.data,
+ user_info->nt_resp.length,
+ user_info->domain.str)) {
+ DEBUG(1,("password server %s rejected the password\n", cli->desthost));
+ /* Make this cli_nt_error() when the conversion is in */
+ nt_status = cli_nt_error(cli);
+ } else {
+ nt_status = NT_STATUS_OK;
+ }
+ }
+
+ /* if logged in as guest then reject */
+ if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
+ DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+
+ cli_ulogoff(cli);
+
+ if NT_STATUS_IS_OK(nt_status) {
+ struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
+ if (pass) {
+ if (!make_server_info_pw(server_info, pass)) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ if (locally_made_cli) {
+ cli_shutdown(cli);
+ }
+
+ return(nt_status);
+}
+
+BOOL auth_init_smbserver(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+ (*auth_method)->auth = check_smbserver_security;
+ (*auth_method)->get_chal = auth_get_challenge_server;
+ (*auth_method)->send_keepalive = send_server_keepalive;
+ (*auth_method)->free_private_data = free_server_private_data;
+ return True;
+}
diff --git a/source/auth/auth_unix.c b/source/auth/auth_unix.c
new file mode 100644
index 00000000000..d134ce6909c
--- /dev/null
+++ b/source/auth/auth_unix.c
@@ -0,0 +1,125 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+update the encrypted smbpasswd file from the plaintext username and password
+
+this ugly hack needs to die, but not quite yet...
+*****************************************************************************/
+static BOOL update_smbpassword_file(char *user, char *password)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if(ret == False) {
+ DEBUG(0,("pdb_getsampwnam returned NULL\n"));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ /*
+ * Remove the account disabled flag - we are updating the
+ * users password from a login.
+ */
+ if (!pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED)) {
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (sampass, password)) {
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ /* Now write it into the file. */
+ become_root();
+
+ /* Here, the override flag is True, because we want to ignore the
+ XXXXXXX'd out password */
+ ret = pdb_update_sam_account (sampass, True);
+
+ unbecome_root();
+
+ if (ret) {
+ DEBUG(3,("pdb_update_sam_account returned %d\n",ret));
+ }
+
+ memset(password, '\0', strlen(password));
+
+ pdb_free_sam(&sampass);
+ return ret;
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password
+in PLAIN TEXT
+****************************************************************************/
+
+NTSTATUS check_unix_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ NTSTATUS nt_status;
+ struct passwd *pass = NULL;
+
+ become_root();
+ pass = Get_Pwnam(user_info->internal_username.str);
+
+ nt_status = pass_check(pass,
+ pass ? pass->pw_name : user_info->internal_username.str,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length-1,
+ lp_update_encrypted() ?
+ update_smbpassword_file : NULL,
+ True);
+
+ unbecome_root();
+
+ if NT_STATUS_IS_OK(nt_status) {
+ if (pass) {
+ make_server_info_pw(server_info, pass);
+ } else {
+ /* we need to do somthing more useful here */
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ return nt_status;
+}
+
+BOOL auth_init_unix(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+ (*auth_method)->auth = check_unix_security;
+ return True;
+}
diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c
new file mode 100644
index 00000000000..3e480b4fd18
--- /dev/null
+++ b/source/auth/auth_util.c
@@ -0,0 +1,750 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Authentication utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern fstring remote_machine;
+extern pstring global_myname;
+
+/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(const char *unix_user, const char *homedir)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ if (! *add_script)
+ return -1;
+ all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
+ if (homedir)
+ all_string_sub(add_script, "%H", homedir, sizeof(pstring));
+ ret = smbrun(add_script,NULL);
+ DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+int smb_delete_user(char *unix_user)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluser_script());
+ if (! *del_script)
+ return -1;
+ all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
+ ret = smbrun(del_script,NULL);
+ DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Add and Delete UNIX users on demand, based on NTSTATUS codes.
+****************************************************************************/
+
+void smb_user_control(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info, NTSTATUS nt_status)
+{
+ struct passwd *pwd=NULL;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+
+ if (!(server_info->sam_fill_level & SAM_FILL_UNIX)) {
+
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ */
+
+ if(lp_adduser_script() && !(pwd = Get_Pwnam(user_info->internal_username.str))) {
+ smb_create_user(user_info->internal_username.str, NULL);
+ }
+ } else {
+ if(lp_adduser_script()) {
+ SMB_STRUCT_STAT st;
+ const char *home_dir = pdb_get_homedir(server_info->sam_account);
+ /*
+ * Also call smb_create_user if the users
+ * home directory doesn't exist. Used with
+ * winbindd to allow the script to create
+ * the home directory for a user mapped
+ * with winbindd.
+ */
+
+ if (home_dir &&
+ (sys_stat(home_dir, &st) == -1) && (errno == ENOENT)) {
+ smb_create_user(user_info->internal_username.str, home_dir);
+ }
+ }
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
+ /*
+ * User failed to validate ok against Domain controller.
+ * If the failure was "user doesn't exist" and admin
+ * wants us to try and delete that UNIX user on the fly,
+ * do so.
+ */
+ if (lp_deluser_script()) {
+ smb_delete_user(user_info->internal_username.str);
+ }
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+static BOOL make_user_info(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *internal_username,
+ const char *client_domain,
+ const char *domain,
+ const char *wksta_name,
+ DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext,
+ uint32 ntlmssp_flags, BOOL encrypted)
+{
+
+ DEBUG(5,("attempting to make a user_info for %s (%s)\n", internal_username, smb_name));
+
+ *user_info = malloc(sizeof(**user_info));
+ if (!user_info) {
+ DEBUG(0,("malloc failed for user_info (size %d)\n", sizeof(*user_info)));
+ return False;
+ }
+
+ ZERO_STRUCTP(*user_info);
+
+ DEBUG(5,("makeing strings for %s's user_info struct\n", internal_username));
+
+ (*user_info)->smb_name.str = strdup(smb_name);
+ if ((*user_info)->smb_name.str) {
+ (*user_info)->smb_name.len = strlen(smb_name);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->internal_username.str = strdup(internal_username);
+ if ((*user_info)->internal_username.str) {
+ (*user_info)->internal_username.len = strlen(internal_username);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->domain.str = strdup(domain);
+ if ((*user_info)->domain.str) {
+ (*user_info)->domain.len = strlen(domain);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->client_domain.str = strdup(client_domain);
+ if ((*user_info)->client_domain.str) {
+ (*user_info)->client_domain.len = strlen(client_domain);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->wksta_name.str = strdup(wksta_name);
+ if ((*user_info)->wksta_name.str) {
+ (*user_info)->wksta_name.len = strlen(wksta_name);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ DEBUG(5,("makeing blobs for %s's user_info struct\n", internal_username));
+
+ (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length);
+ (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length);
+ (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length);
+
+ (*user_info)->encrypted = encrypted;
+ (*user_info)->ntlmssp_flags = ntlmssp_flags;
+
+ DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , internal_username, smb_name));
+
+ return True;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure after appropriate mapping.
+****************************************************************************/
+
+BOOL make_user_info_map(auth_usersupplied_info **user_info,
+ const char *smb_name,
+ const char *client_domain,
+ const char *wksta_name,
+ DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext,
+ uint32 ntlmssp_flags, BOOL encrypted)
+{
+ const char *domain;
+ fstring internal_username;
+ fstrcpy(internal_username, smb_name);
+ map_username(internal_username);
+
+ if (lp_allow_trusted_domains()) {
+ char *user;
+ /* the client could have given us a workstation name
+ or other crap for the workgroup - we really need a
+ way of telling if this domain name is one of our
+ trusted domain names
+
+ The way I do it here is by checking if the fully
+ qualified username exists. This is rather reliant
+ on winbind, but until we have a better method this
+ will have to do
+ */
+ asprintf(&user, "%s%s%s",
+ client_domain, lp_winbind_separator(),
+ smb_name);
+ if (Get_Pwnam(user) != NULL) {
+ domain = client_domain;
+ } else {
+ domain = lp_workgroup();
+ }
+ free(user);
+ } else {
+ domain = lp_workgroup();
+ }
+
+ return make_user_info(user_info,
+ smb_name, internal_username,
+ client_domain, domain,
+ wksta_name,
+ lm_pwd, nt_pwd,
+ plaintext,
+ ntlmssp_flags, encrypted);
+
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrypt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char *wksta_name,
+ uchar *lm_network_pwd, int lm_pwd_len,
+ uchar *nt_network_pwd, int nt_pwd_len)
+{
+ BOOL ret;
+ DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
+ DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ uint32 ntlmssp_flags = 0;
+
+ if (lm_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ if (nt_pwd_len == 24) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+ } else if (nt_pwd_len != 0) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ ret = make_user_info_map(user_info,
+ smb_name, client_domain,
+ wksta_name,
+ lm_blob, nt_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&lm_blob);
+ data_blob_free(&nt_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrypt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char *wksta_name,
+ char chal[8],
+ uchar lm_interactive_pwd[16],
+ uchar nt_interactive_pwd[16],
+ uchar *dc_sess_key)
+{
+ char lm_pwd[16];
+ char nt_pwd[16];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ unsigned char key[16];
+ uint32 ntlmssp_flags = 0;
+
+ ZERO_STRUCT(key);
+ memcpy(key, dc_sess_key, 8);
+
+ if (lm_interactive_pwd) memcpy(lm_pwd, lm_interactive_pwd, sizeof(lm_pwd));
+ if (nt_interactive_pwd) memcpy(nt_pwd, nt_interactive_pwd, sizeof(nt_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("key:"));
+ dump_data(100, (char *)key, sizeof(key));
+
+ DEBUG(100,("lm owf password:"));
+ dump_data(100, lm_pwd, sizeof(lm_pwd));
+
+ DEBUG(100,("nt owf password:"));
+ dump_data(100, nt_pwd, sizeof(nt_pwd));
+#endif
+
+ SamOEMhash((uchar *)lm_pwd, key, sizeof(lm_pwd));
+ SamOEMhash((uchar *)nt_pwd, key, sizeof(nt_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decrypt of lm owf password:"));
+ dump_data(100, lm_pwd, sizeof(lm_pwd));
+
+ DEBUG(100,("decrypt of nt owf password:"));
+ dump_data(100, nt_pwd, sizeof(nt_pwd));
+#endif
+
+ SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response);
+ SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response);
+
+ /* Password info parinoia */
+ ZERO_STRUCT(lm_pwd);
+ ZERO_STRUCT(nt_pwd);
+ ZERO_STRUCT(key);
+
+ {
+ BOOL ret;
+ DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
+ DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+
+ if (lm_interactive_pwd)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ if (nt_interactive_pwd)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+
+ ret = make_user_info_map(user_info,
+ smb_name, client_domain,
+ wksta_name,
+ local_lm_blob,
+ local_nt_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ return ret;
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info_winbind(auth_usersupplied_info **user_info,
+ const char *username,
+ const char *domain,
+ const char *password,
+ char chal[8] /* Give winbind back the challenge we used */
+ )
+{
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+ DATA_BLOB plaintext_blob;
+ uint32 ntlmssp_flags = 0;
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n"));
+
+ generate_random_buffer(chal, 8, False);
+
+ if (*password) {
+ SMBencrypt( (const uchar *)password, chal, local_lm_response);
+
+ /* This encrypts the lm_pwd field, which actually contains
+ the password rather than the nt_pwd field because that
+ contains nothing */
+
+ /* WATCH OUT. This doesn't work if the incoming password is
+ incorrectly cased. We might want to add a check here
+ and only do an LM in that case */
+
+ SMBNTencrypt((const uchar *)password, chal, local_nt_response);
+
+ local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
+ local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
+ plaintext_blob = data_blob(password, strlen(password)+1);
+ if ((!local_lm_blob.data) || (!local_nt_blob.data)|| (!plaintext_blob.data)) {
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ data_blob_clear_free(&plaintext_blob);
+ return False;
+ }
+ ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM;
+ } else {
+ local_lm_blob = data_blob(NULL, 0);
+ local_nt_blob = data_blob(NULL, 0);
+ plaintext_blob = data_blob(NULL, 0);
+ }
+
+ {
+ BOOL ret;
+
+ ret = make_user_info(user_info,
+ username, username,
+ domain, domain,
+ global_myname,
+ local_lm_blob,
+ local_nt_blob,
+ plaintext_blob,
+ ntlmssp_flags, False);
+
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ data_blob_clear_free(&plaintext_blob);
+ return ret;
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrypt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ uchar *lm_network_pwd, int lm_pwd_len,
+ uchar *nt_network_pwd, int nt_pwd_len)
+{
+ BOOL ret;
+ DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
+ DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ uint32 ntlmssp_flags = 0;
+
+ if (lm_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ if (nt_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+
+ ret = make_user_info(user_info,
+ smb_name, smb_name,
+ client_domain, client_domain,
+ global_myname,
+ lm_blob, nt_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&lm_blob);
+ data_blob_free(&nt_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info_for_reply(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char chal[8],
+ DATA_BLOB plaintext_password)
+{
+
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+ BOOL ret = False;
+ uint32 ntlmssp_flags = 0;
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted format.\n"));
+
+ if (plaintext_password.data) {
+ unsigned char local_lm_response[24];
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(10,("Unencrypted password (len %d):\n",plaintext_password.length));
+ dump_data(100, plaintext_password.data, plaintext_password.length);
+#endif
+
+ SMBencrypt( (const uchar *)plaintext_password.data, chal, local_lm_response);
+ local_lm_blob = data_blob(local_lm_response, 24);
+
+ /* We can't do an NT hash here, as the password needs to be
+ case insensitive */
+ local_nt_blob = data_blob(NULL, 0);
+
+ ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM;
+ } else {
+ local_lm_blob = data_blob(NULL, 0);
+ local_nt_blob = data_blob(NULL, 0);
+ }
+
+ ret = make_user_info_map(user_info, smb_name,
+ client_domain,
+ remote_machine,
+ local_lm_blob,
+ local_nt_blob,
+ plaintext_password,
+ ntlmssp_flags, False);
+
+ data_blob_free(&local_lm_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info_for_reply_enc(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ DATA_BLOB lm_resp, DATA_BLOB nt_resp,
+ DATA_BLOB plaintext_password)
+{
+ uint32 ntlmssp_flags = 0;
+
+ DATA_BLOB no_plaintext_blob = data_blob(NULL, 0);
+
+ if (lm_resp.length == 24) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ }
+ if (nt_resp.length == 0) {
+ } else if (nt_resp.length == 24) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+ } else {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ return make_user_info_map(user_info, smb_name,
+ client_domain,
+ remote_machine,
+ lm_resp,
+ nt_resp,
+ no_plaintext_blob,
+ ntlmssp_flags, True);
+}
+
+/****************************************************************************
+ Create a guest user_info blob, for anonymous authenticaion.
+****************************************************************************/
+
+BOOL make_user_info_guest(auth_usersupplied_info **user_info)
+{
+ DATA_BLOB lm_blob = data_blob(NULL, 0);
+ DATA_BLOB nt_blob = data_blob(NULL, 0);
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ uint32 ntlmssp_flags = 0;
+
+ return make_user_info(user_info,
+ "","",
+ "","",
+ "",
+ nt_blob, lm_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+}
+
+/***************************************************************************
+ Make a user_info struct
+***************************************************************************/
+
+BOOL make_server_info(auth_serversupplied_info **server_info)
+{
+ *server_info = malloc(sizeof(**server_info));
+ if (!*server_info) {
+ DEBUG(0,("make_server_info: malloc failed!\n"));
+ return False;
+ }
+ ZERO_STRUCTP(*server_info);
+ return True;
+}
+
+/***************************************************************************
+ Make (and fill) a user_info struct from a SAM_ACCOUNT
+***************************************************************************/
+
+BOOL make_server_info_sam(auth_serversupplied_info **server_info, SAM_ACCOUNT *sampass)
+{
+ if (!make_server_info(server_info)) {
+ return False;
+ }
+
+ (*server_info)->sam_fill_level = SAM_FILL_ALL;
+ (*server_info)->sam_account = sampass;
+
+ DEBUG(5,("make_server_info_sam: made server info for user %s\n",
+ pdb_get_username((*server_info)->sam_account)));
+ return True;
+}
+
+/***************************************************************************
+ Make (and fill) a user_info struct from a 'struct passwd' by conversion
+ to a SAM_ACCOUNT
+***************************************************************************/
+
+BOOL make_server_info_pw(auth_serversupplied_info **server_info, const struct passwd *pwd)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ if (!pdb_init_sam_pw(&sampass, pwd)) {
+ return False;
+ }
+ return make_server_info_sam(server_info, sampass);
+}
+
+/***************************************************************************
+ Free a user_info struct
+***************************************************************************/
+
+void free_user_info(auth_usersupplied_info **user_info)
+{
+ DEBUG(5,("attempting to free (and zero) a user_info structure\n"));
+ if (*user_info != NULL) {
+ if ((*user_info)->smb_name.str) {
+ DEBUG(10,("structure was created for %s\n", (*user_info)->smb_name.str));
+ }
+ SAFE_FREE((*user_info)->smb_name.str);
+ SAFE_FREE((*user_info)->internal_username.str);
+ SAFE_FREE((*user_info)->client_domain.str);
+ SAFE_FREE((*user_info)->domain.str);
+ SAFE_FREE((*user_info)->wksta_name.str);
+ data_blob_free(&(*user_info)->lm_resp);
+ data_blob_free(&(*user_info)->nt_resp);
+ SAFE_FREE((*user_info)->interactive_password);
+ data_blob_clear_free(&(*user_info)->plaintext_password);
+ ZERO_STRUCT(**user_info);
+ }
+ SAFE_FREE(*user_info);
+}
+
+/***************************************************************************
+ Clear out a server_info struct that has been allocated
+***************************************************************************/
+
+void free_server_info(auth_serversupplied_info **server_info)
+{
+ if (*server_info != NULL) {
+ pdb_free_sam(&(*server_info)->sam_account);
+
+ /* call pam_end here, unless we know we are keeping it */
+ delete_nt_token( &(*server_info)->ptok );
+ ZERO_STRUCT(**server_info);
+ }
+ SAFE_FREE(*server_info);
+}
+
+/***************************************************************************
+ Make a server_info struct for a guest user
+***************************************************************************/
+
+BOOL make_server_info_guest(auth_serversupplied_info **server_info)
+{
+ struct passwd *pass = sys_getpwnam(lp_guestaccount());
+
+ if (pass) {
+ if (!make_server_info_pw(server_info, pass)) {
+ return False;
+ }
+ (*server_info)->guest = True;
+ return True;
+ }
+ DEBUG(0,("make_server_info_guest: sys_getpwnam() failed on guest account!\n"));
+ return False;
+}
+
+/***************************************************************************
+ Make an auth_methods struct
+***************************************************************************/
+
+BOOL make_auth_methods(auth_methods **auth_method)
+{
+ *auth_method = malloc(sizeof(**auth_method));
+ if (!*auth_method) {
+ DEBUG(0,("make_auth_method: malloc failed!\n"));
+ return False;
+ }
+ ZERO_STRUCTP(*auth_method);
+
+ return True;
+}
+
+/****************************************************************************
+ Delete a SID token.
+****************************************************************************/
+
+void delete_nt_token(NT_USER_TOKEN **pptoken)
+{
+ if (*pptoken) {
+ NT_USER_TOKEN *ptoken = *pptoken;
+ SAFE_FREE( ptoken->user_sids );
+ ZERO_STRUCTP(ptoken);
+ }
+ SAFE_FREE(*pptoken);
+}
+
+/****************************************************************************
+ Duplicate a SID token.
+****************************************************************************/
+
+NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken)
+{
+ NT_USER_TOKEN *token;
+
+ if (!ptoken)
+ return NULL;
+
+ if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL)
+ return NULL;
+
+ ZERO_STRUCTP(token);
+
+ if ((token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids )) == NULL) {
+ SAFE_FREE(token);
+ return NULL;
+ }
+
+ token->num_sids = ptoken->num_sids;
+
+ return token;
+}
diff --git a/source/auth/auth_winbind.c b/source/auth/auth_winbind.c
new file mode 100644
index 00000000000..9ca87fe0ddc
--- /dev/null
+++ b/source/auth/auth_winbind.c
@@ -0,0 +1,111 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind authentication mechnism
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Prototypes from common.h */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+
+/* Authenticate a user with a challenge/response */
+
+static NTSTATUS check_winbind_security(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const auth_authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ struct passwd *pw;
+ NTSTATUS nt_status;
+
+ if (!user_info) {
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (!auth_info) {
+ DEBUG(3,("Password for user %s cannot be checked because we have no auth_info to get the challenge from.\n",
+ user_info->internal_username.str));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ snprintf(request.data.auth_crap.user, sizeof(request.data.auth_crap.user),
+ "%s\\%s", user_info->domain.str, user_info->smb_name.str);
+
+ memcpy(request.data.auth_crap.chal, auth_info->challenge.data, sizeof(request.data.auth_crap.chal));
+
+ request.data.auth_crap.lm_resp_len = MIN(user_info->lm_resp.length,
+ sizeof(request.data.auth_crap.lm_resp));
+ request.data.auth_crap.nt_resp_len = MIN(user_info->nt_resp.length,
+ sizeof(request.data.auth_crap.nt_resp));
+
+ memcpy(request.data.auth_crap.lm_resp, user_info->lm_resp.data,
+ sizeof(request.data.auth_crap.lm_resp_len));
+ memcpy(request.data.auth_crap.nt_resp, user_info->nt_resp.data,
+ request.data.auth_crap.lm_resp_len);
+
+ result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
+
+ if (result == NSS_STATUS_SUCCESS) {
+
+ pw = Get_Pwnam(user_info->internal_username.str);
+
+ if (pw) {
+ if (make_server_info_pw(server_info, pw)) {
+ nt_status = NT_STATUS_OK;
+ } else {
+ nt_status = NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ } else {
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+
+ return nt_status;
+}
+
+BOOL auth_init_winbind(auth_methods **auth_method)
+{
+ if (!make_auth_methods(auth_method)) {
+ return False;
+ }
+
+ (*auth_method)->auth = check_winbind_security;
+ return True;
+}
+
+
+
+
diff --git a/source/auth/pampass.c b/source/auth/pampass.c
new file mode 100644
index 00000000000..018eae3a07e
--- /dev/null
+++ b/source/auth/pampass.c
@@ -0,0 +1,892 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+ PAM Password checking
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) John H Terpsta 1999-2001
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * This module provides PAM based functions for validation of
+ * username/password pairs, account managment, session and access control.
+ * Note: SMB password checking is done in smbpass.c
+ */
+
+#include "includes.h"
+
+#ifdef WITH_PAM
+
+/*******************************************************************
+ * Handle PAM authentication
+ * - Access, Authentication, Session, Password
+ * Note: See PAM Documentation and refer to local system PAM implementation
+ * which determines what actions/limitations/allowances become affected.
+ *********************************************************************/
+
+#include <security/pam_appl.h>
+
+/*
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
+ */
+
+struct smb_pam_userdata {
+ const char *PAM_username;
+ const char *PAM_password;
+ const char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
+
+/*
+ * Macros to help make life easy
+ */
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
+static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
+{
+
+ if( pam_error != PAM_SUCCESS) {
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
+
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ char *msg, int dbglvl,
+ NTSTATUS *nt_status)
+{
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (NT_STATUS_IS_OK(*nt_status)) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
+/*
+ * PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ memset(reply, '\0', sizeof(struct pam_response) * num_msg);
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static void special_char_sub(char *buf)
+{
+ all_string_sub(buf, "\\n", "", 0);
+ all_string_sub(buf, "\\r", "", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass)
+{
+ pstring_sub(buf, "%u", username);
+ all_string_sub(buf, "%o", oldpass, sizeof(fstring));
+ all_string_sub(buf, "%n", newpass, sizeof(fstring));
+}
+
+
+struct chat_struct {
+ struct chat_struct *next, *prev;
+ fstring prompt;
+ fstring reply;
+};
+
+/**************************************************************
+ Create a linked list containing chat data.
+***************************************************************/
+
+static struct chat_struct *make_pw_chat(char *p)
+{
+ fstring prompt;
+ fstring reply;
+ struct chat_struct *list = NULL;
+ struct chat_struct *t;
+ struct chat_struct *tmp;
+
+ while (1) {
+ t = (struct chat_struct *)malloc(sizeof(*t));
+ if (!t) {
+ DEBUG(0,("make_pw_chat: malloc failed!\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(list, t, tmp);
+
+ if (!next_token(&p, prompt, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(prompt,"."))
+ fstrcpy(prompt,"*");
+
+ special_char_sub(prompt);
+ fstrcpy(t->prompt, prompt);
+ strlower(t->prompt);
+ trim_string(t->prompt, " ", " ");
+
+ if (!next_token(&p, reply, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(reply,"."))
+ fstrcpy(reply,"");
+
+ special_char_sub(reply);
+ fstrcpy(t->reply, reply);
+ strlower(t->reply);
+ trim_string(t->reply, " ", " ");
+
+ }
+ return list;
+}
+
+static void free_pw_chat(struct chat_struct *list)
+{
+ while (list) {
+ struct chat_struct *old_head = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
+}
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring current_prompt;
+ fstring current_reply;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+ struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());
+ struct chat_struct *t;
+ BOOL found;
+ *resp = NULL;
+
+ DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ if (pw_chat == NULL)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) {
+ DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ for (replies = 0; replies < num_msg; replies++) {
+ found = False;
+ DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));
+#endif
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));
+#endif
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ free_pw_chat(pw_chat);
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ SAFE_FREE(pconv->appdata_ptr);
+
+ SAFE_FREE(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,
+ const char *passwd, const char *newpass)
+{
+ struct pam_conv *pconv = (struct pam_conv *)malloc(sizeof(struct pam_conv));
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)malloc(sizeof(struct smb_pam_userdata));
+
+ if (pconv == NULL || udp == NULL) {
+ SAFE_FREE(pconv);
+ SAFE_FREE(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
+
+/*
+ * PAM Closing out cleanup handler
+ */
+
+static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
+{
+ int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
+
+ if( pamh != NULL ) {
+ pam_error = pam_end(pamh, 0);
+ if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
+ return True;
+ }
+ }
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
+ return False;
+}
+
+/*
+ * Start PAM authentication for specified account
+ */
+
+static BOOL smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv)
+{
+ int pam_error;
+ const char *our_rhost;
+
+ *pamh = (pam_handle_t *)NULL;
+
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
+
+ pam_error = pam_start("samba", user, pconv, pamh);
+ if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+
+ if (rhost == NULL) {
+ our_rhost = client_name();
+ if (strequal(rhost,"UNKNOWN"))
+ our_rhost = client_addr();
+ } else {
+ our_rhost = rhost;
+ }
+
+#ifdef PAM_RHOST
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", our_rhost));
+ pam_error = pam_set_item(*pamh, PAM_RHOST, our_rhost);
+ if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+#ifdef PAM_TTY
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
+ pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
+ if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
+ return True;
+}
+
+/*
+ * PAM Authentication Handler
+ */
+static NTSTATUS smb_pam_auth(pam_handle_t *pamh, char *user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+
+ /*
+ * To enable debugging set in /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ */
+
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
+ switch( pam_error ){
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+ nt_status = NT_STATUS_WRONG_PASSWORD;
+ break;
+ case PAM_CRED_INSUFFICIENT:
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
+ break;
+ case PAM_AUTHINFO_UNAVAIL:
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_MAXTRIES:
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
+ break;
+ case PAM_ABORT:
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Account Handler
+ */
+static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
+ switch( pam_error ) {
+ case PAM_AUTHTOK_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_ACCT_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ nt_status = NT_STATUS_ACCOUNT_EXPIRED;
+ break;
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_NO_TOKEN;
+
+ /*
+ * This will allow samba to aquire a kerberos token. And, when
+ * exporting an AFS cell, be able to /write/ to this cell.
+ */
+
+ DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
+ pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
+ switch( pam_error ) {
+ case PAM_CRED_UNAVAIL:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ case PAM_CRED_EXPIRED:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_CRED_ERR:
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Internal Session Handler
+ */
+static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
+{
+ int pam_error;
+
+#ifdef PAM_TTY
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
+ pam_error = pam_set_item(pamh, PAM_TTY, tty);
+ if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+ return False;
+#endif
+
+ if (flag) {
+ pam_error = pam_open_session(pamh, PAM_SILENT);
+ if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+ return False;
+ } else {
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
+ if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+ return False;
+ }
+ return (True);
+}
+
+/*
+ * Internal PAM Password Changer.
+ */
+
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+
+ /* This doesn't seem to be defined on Solaris. JRA */
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+#endif
+
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Account handler
+ */
+
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_OK;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user)))
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+NTSTATUS smb_pam_passcheck(char * user, char * password)
+{
+ pam_handle_t *pamh = NULL;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
+
+ /*
+ * Note we can't ignore PAM here as this is the only
+ * way of doing auths on plaintext passwords when
+ * compiled --with-pam.
+ */
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_setcred(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+BOOL smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+#else
+
+/* If PAM not used, no PAM restrictions on accounts. */
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ return NT_STATUS_OK;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ return True;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_close_session(char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
+#endif /* WITH_PAM */
diff --git a/source/auth/pass_check.c b/source/auth/pass_check.c
new file mode 100644
index 00000000000..77839e4bb0c
--- /dev/null
+++ b/source/auth/pass_check.c
@@ -0,0 +1,776 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password checking
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this module is for checking a username/password against a system
+ password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+/* these are kept here to keep the string_combinations function simple */
+static fstring this_user;
+#if !defined(WITH_PAM)
+static fstring this_salt;
+static fstring this_crypted;
+#endif
+
+#ifdef WITH_AFS
+
+#include <afs/stds.h>
+#include <afs/kautils.h>
+
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static BOOL afs_auth(char *user, char *password)
+{
+ long password_expires = 0;
+ char *reason;
+
+ /* For versions of AFS prior to 3.3, this routine has few arguments, */
+ /* but since I can't find the old documentation... :-) */
+ setpag();
+ if (ka_UserAuthenticateGeneral
+ (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
+ (char *)0, /* cell */
+ password, 0, /* lifetime, default */
+ &password_expires, /*days 'til it expires */
+ 0, /* spare 2 */
+ &reason) == 0)
+ {
+ return (True);
+ }
+ DEBUG(1,
+ ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
+ return (False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+#include <dce/dce_error.h>
+#include <dce/sec_login.h>
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+ - Server credentials may expire
+ - Client credential cache files have wrong owner
+ - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static BOOL dfs_auth(char *user, char *password)
+{
+ error_status_t err;
+ int err2;
+ int prterr;
+ signed32 expire_time, current_time;
+ boolean32 password_reset;
+ struct passwd *pw;
+ sec_passwd_rec_t passwd_rec;
+ sec_login_auth_src_t auth_src = sec_login_auth_src_network;
+ unsigned char dce_errstr[dce_c_error_string_len];
+ gid_t egid;
+
+ if (dcelogin_atmost_once)
+ return (False);
+
+#ifdef HAVE_CRYPT
+ /*
+ * We only go for a DCE login context if the given password
+ * matches that stored in the local password file..
+ * Assumes local passwd file is kept in sync w/ DCE RGY!
+ */
+
+ if (strcmp((char *)crypt(password, this_salt), this_crypted))
+ {
+ return (False);
+ }
+#endif
+
+ sec_login_get_current_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ time(&current_time);
+
+ if (expire_time < (current_time + 60))
+ {
+ struct passwd *pw;
+ sec_passwd_rec_t *key;
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_refresh_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't refresh identity. %s\n",
+ dce_errstr));
+
+ return (False);
+ }
+
+ sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
+ (unsigned char *)pw->pw_name,
+ sec_c_key_version_none,
+ (void **)&key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get key for %s. %s\n",
+ pw->pw_name, dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_valid_and_cert_ident(my_dce_sec_context, key,
+ &password_reset, &auth_src,
+ &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE can't validate and certify identity for %s. %s\n",
+ pw->pw_name, dce_errstr));
+ }
+
+ sec_key_mgmt_free_key(key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't free key.\n", dce_errstr));
+ }
+ }
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ return (False);
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ /*
+ * NB. I'd like to change these to call something like change_to_user()
+ * instead but currently we don't have a connection
+ * context to become the correct user. This is already
+ * fairly platform specific code however, so I think
+ * this should be ok. I have added code to go
+ * back to being root on error though. JRA.
+ */
+
+ egid = getegid();
+
+ set_effective_gid(pw->pw_gid);
+ set_effective_uid(pw->pw_uid);
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ passwd_rec.version_number = sec_passwd_c_version_none;
+ passwd_rec.pepper = NULL;
+ passwd_rec.key.key_type = sec_passwd_plain;
+ passwd_rec.key.tagged_union.plain = (idl_char *) password;
+
+ sec_login_validate_identity(my_dce_sec_context,
+ &passwd_rec, &password_reset,
+ &auth_src, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE Identity Validation failed for principal %s: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
+ goto err;
+ }
+
+ if (auth_src != sec_login_auth_src_network)
+ {
+ DEBUG(0, ("DCE context has no network credentials.\n"));
+ }
+
+ sec_login_set_context(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE login failed for principal %s, cant set context: %s\n",
+ user, dce_errstr));
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
+ user, sys_getpid()));
+
+ DEBUG(3, ("DCE principal: %s\n"
+ " uid: %d\n"
+ " gid: %d\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid));
+ DEBUG(3, (" info: %s\n"
+ " dir: %s\n"
+ " shell: %s\n",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell));
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+ goto err;
+ }
+
+ set_effective_uid(0);
+ set_effective_gid(0);
+
+ DEBUG(0,
+ ("DCE context expires: %s", asctime(localtime(&expire_time))));
+
+ dcelogin_atmost_once = 1;
+ return (True);
+
+ err:
+
+ /* Go back to root, JRA. */
+ set_effective_uid(0);
+ set_effective_gid(egid);
+ return (False);
+}
+
+void dfs_unlogin(void)
+{
+ error_status_t err;
+ int err2;
+ unsigned char dce_errstr[dce_c_error_string_len];
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE purge login context failed for server instance %d: %s\n",
+ sys_getpid(), dce_errstr));
+ }
+}
+#endif
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+static int linux_bigcrypt(char *password, char *salt1, char *crypted)
+{
+#define LINUX_PASSWORD_SEG_CHARS 8
+ char salt[3];
+ int i;
+
+ StrnCpy(salt, salt1, 2);
+ crypted += 2;
+
+ for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
+ char *p = crypt(password, salt) + 2;
+ if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
+ return (0);
+ password += LINUX_PASSWORD_SEG_CHARS;
+ crypted += strlen(p);
+ }
+
+ return (1);
+}
+#endif
+
+#ifdef OSF1_ENH_SEC
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+static char *osf1_bigcrypt(char *password, char *salt1)
+{
+ static char result[AUTH_MAX_PASSWD_LENGTH] = "";
+ char *p1;
+ char *p2 = password;
+ char salt[3];
+ int i;
+ int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
+ if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
+ parts++;
+
+ StrnCpy(salt, salt1, 2);
+ StrnCpy(result, salt1, 2);
+ result[2] = '\0';
+
+ for (i = 0; i < parts; i++) {
+ p1 = crypt(p2, salt);
+ strncat(result, p1 + 2,
+ AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
+ StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
+ p2 += AUTH_CLEARTEXT_SEG_CHARS;
+ }
+
+ return (result);
+}
+#endif
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (char *),
+ int N)
+{
+ int len = strlen(s);
+ int i;
+ NTSTATUS nt_status;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len, PASSWORD_LENGTH);
+#endif
+
+ if (N <= 0 || offset >= len)
+ return (fn(s));
+
+ for (i = offset; i < (len - (N - 1)); i++) {
+ char c = s[i];
+ if (!islower(c))
+ continue;
+ s[i] = toupper(c);
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
+ return (nt_status);
+ }
+ s[i] = c;
+ }
+ return (NT_STATUS_WRONG_PASSWORD);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (char *), int N)
+{
+ int n;
+ NTSTATUS nt_status;
+ for (n = 1; n <= N; n++)
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
+ return nt_status;
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static NTSTATUS password_check(char *password)
+{
+#ifdef WITH_PAM
+ return smb_pam_passcheck(this_user, password);
+#else
+
+ BOOL ret;
+
+#ifdef WITH_AFS
+ if (afs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_AFS */
+
+#ifdef WITH_DFS
+ if (dfs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_DFS */
+
+#ifdef OSF1_ENH_SEC
+
+ ret = (strcmp(osf1_bigcrypt(password, this_salt),
+ this_crypted) == 0);
+ if (!ret) {
+ DEBUG(2,
+ ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ }
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* OSF1_ENH_SEC */
+
+#ifdef ULTRIX_AUTH
+ ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* ULTRIX_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+ ret = (linux_bigcrypt(password, this_salt, this_crypted));
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* LINUX_BIGCRYPT */
+
+#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
+
+ /*
+ * Some systems have bigcrypt in the C library but might not
+ * actually use it for the password hashes (HPUX 10.20) is
+ * a noteable example. So we try bigcrypt first, followed
+ * by crypt.
+ */
+
+ if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
+ return NT_STATUS_OK;
+ else
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+
+#ifdef HAVE_BIGCRYPT
+ ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_BIGCRYPT */
+
+#ifndef HAVE_CRYPT
+ DEBUG(1, ("Warning - no crypt available\n"));
+ return NT_STATUS_LOGON_FAILURE;
+#else /* HAVE_CRYPT */
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_CRYPT */
+#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+#endif /* WITH_PAM || KRB4_AUTH || KRB5_AUTH */
+}
+
+
+
+/****************************************************************************
+CHECK if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file
+return NT_STATUS_OK on correct match, appropriate error otherwise
+****************************************************************************/
+
+NTSTATUS pass_check(struct passwd *pass, char *user, char *password,
+ int pwlen, BOOL (*fn) (char *, char *), BOOL run_cracker)
+{
+ pstring pass2;
+ int level = lp_passwordlevel();
+
+ NTSTATUS nt_status;
+ if (password)
+ password[pwlen] = 0;
+
+#if DEBUG_PASSWORD
+ DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
+#endif
+
+ if (!password)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (((!*password) || (!pwlen)) && !lp_null_passwords())
+ return NT_STATUS_LOGON_FAILURE;
+
+#if defined(WITH_PAM)
+
+ /*
+ * If we're using PAM we want to short-circuit all the
+ * checks below and dive straight into the PAM code.
+ */
+
+ fstrcpy(this_user, user);
+
+ DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
+
+#else /* Not using PAM or Kerebos */
+
+ DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
+
+ if (!pass) {
+ DEBUG(3, ("Couldn't find user %s\n", user));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+#ifdef HAVE_GETSPNAM
+ {
+ struct spwd *spass;
+
+ /* many shadow systems require you to be root to get
+ the password, in most cases this should already be
+ the case when this function is called, except
+ perhaps for IPC password changing requests */
+
+ spass = getspnam(pass->pw_name);
+ if (spass && spass->sp_pwdp)
+ pstrcpy(pass->pw_passwd, spass->sp_pwdp);
+ }
+#elif defined(IA_UINFO)
+ {
+ /* Need to get password with SVR4.2's ia_ functions
+ instead of get{sp,pw}ent functions. Required by
+ UnixWare 2.x, tested on version
+ 2.1. (tangent@cyberport.com) */
+ uinfo_t uinfo;
+ if (ia_openinfo(pass->pw_name, &uinfo) != -1)
+ ia_get_logpwd(uinfo, &(pass->pw_passwd));
+ }
+#endif
+
+#ifdef HAVE_GETPRPWNAM
+ {
+ struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
+ if (pr_pw && pr_pw->ufld.fd_encrypt)
+ pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
+ }
+#endif
+
+#ifdef OSF1_ENH_SEC
+ {
+ struct pr_passwd *mypasswd;
+ DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
+ user));
+ mypasswd = getprpwnam(user);
+ if (mypasswd) {
+ fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
+ fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
+ } else {
+ DEBUG(5,
+ ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
+ user));
+ }
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ {
+ AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+ if (ap) {
+ fstrcpy(pass->pw_passwd, ap->a_password);
+ endauthent();
+ }
+ }
+#endif
+
+ /* extract relevant info */
+ fstrcpy(this_salt, pass->pw_passwd);
+
+#if defined(HAVE_TRUNCATED_SALT)
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ this_salt[2] = 0;
+#endif
+
+ fstrcpy(this_crypted, pass->pw_passwd);
+
+ if (!*this_crypted) {
+ if (!lp_null_passwords()) {
+ DEBUG(2, ("Disallowing %s with null password\n",
+ this_user));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ if (!*password) {
+ DEBUG(3,
+ ("Allowing access to %s with null password\n",
+ this_user));
+ return NT_STATUS_OK;
+ }
+ }
+
+#endif /* defined(WITH_PAM) */
+
+ /* try it as it came to us */
+ nt_status = password_check(password);
+ if NT_STATUS_IS_OK(nt_status) {
+ if (fn) {
+ fn(user, password);
+ }
+ return (nt_status);
+ } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+ return (nt_status);
+ }
+
+ if (!run_cracker) {
+ return (nt_status);
+ }
+
+ /* if the password was given to us with mixed case then we don't
+ * need to proceed as we know it hasn't been case modified by the
+ * client */
+ if (strhasupper(password) && strhaslower(password)) {
+ return nt_status;
+ }
+
+ /* make a copy of it */
+ StrnCpy(pass2, password, sizeof(pstring) - 1);
+
+ /* try all lowercase if it's currently all uppercase */
+ if (strhasupper(password)) {
+ strlower(password);
+ if NT_STATUS_IS_OK(nt_status = password_check(password)) {
+ if (fn)
+ fn(user, password);
+ return (nt_status);
+ }
+ }
+
+ /* give up? */
+ if (level < 1) {
+ /* restore it */
+ fstrcpy(password, pass2);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower(password);
+
+
+ if NT_STATUS_IS_OK(nt_status = string_combinations(password, password_check, level)) {
+ if (fn)
+ fn(user, password);
+ return nt_status;
+ }
+
+ /* restore it */
+ fstrcpy(password, pass2);
+
+ return NT_STATUS_WRONG_PASSWORD;
+}
diff --git a/source/bin/.cvsignore b/source/bin/.cvsignore
new file mode 100644
index 00000000000..fe08cb63f84
--- /dev/null
+++ b/source/bin/.cvsignore
@@ -0,0 +1,36 @@
+.dummy
+.libs
+locktest
+locktest2
+make_printerdef
+make_smbcodepage
+make_unicodemap
+masktest
+msgtest
+net
+nmbd
+nmblookup
+pdbedit
+rpcclient
+samsync
+smbcacls
+smbcacls
+smbclient
+smbcontrol
+smbd
+smbgroupedit
+smbmnt
+smbmount
+smbpasswd
+smbsh
+smbspool
+smbstatus
+smbtorture
+smbtree
+smbumount
+swat
+talloctort
+testparm
+testprns
+wbinfo
+winbindd
diff --git a/source/change-log b/source/change-log
index e120ac6f02a..1f7798b541f 100644
--- a/source/change-log
+++ b/source/change-log
@@ -1,10 +1,13 @@
-Change Log for Samba
+SUPERCEDED Change Log for Samba
+^^^^^^^^^^
Unless otherwise attributed, all changes were made by
-Andrew.Tridgell@anu.edu.au
+Andrew.Tridgell@anu.edu.au. All bugs to samba-bugs@samba.org.
NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
1.5.00 announced to mailing list
@@ -1793,6 +1796,9 @@ NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
- Linux quota patch from xeno@mix.hsv.no
- try to work around NT passlen2 problem in session setup
- released alpha1
+
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
==========
@@ -1869,4 +1875,4 @@ lpd stuff:
Tony Aiuto (tony@ics.com)
make max disk size local
- \ No newline at end of file
+
diff --git a/source/client/.cvsignore b/source/client/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/client/.cvsignore
diff --git a/source/client/client.c b/source/client/client.c
index 504cb5a0bb4..a5654a0eafb 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -1,8 +1,9 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
+ Version 3.0.
SMB client
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,36 +20,39 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
+#define NO_SYSLOG
#include "includes.h"
-#include "nameserv.h"
#ifndef REGISTER
#define REGISTER 0
#endif
+const char prog_name[] = "smbclient";
+
+struct cli_state *cli;
+extern BOOL in_client;
+static int port = 0;
pstring cur_dir = "\\";
pstring cd_path = "";
-pstring service="";
-pstring desthost="";
-pstring myname = "";
-pstring password = "";
-pstring username="";
-pstring workgroup=WORKGROUP;
-BOOL got_pass = False;
-BOOL connect_as_printer = False;
-BOOL connect_as_ipc = False;
-extern struct in_addr bcast_ip;
-static BOOL got_bcast=False;
-
-char cryptkey[8];
-BOOL doencrypt=False;
-
+static pstring service;
+static pstring desthost;
+extern pstring global_myname;
+static pstring password;
+static pstring username;
+static pstring workgroup;
+static char *cmdstr;
+static BOOL got_pass;
+static int io_bufsize = 64512;
+static BOOL use_kerberos;
+
+static int name_type = 0x20;
+static int max_protocol = PROTOCOL_NT1;
extern pstring user_socket_options;
+static int process_tok(fstring tok);
+static int cmd_help(void);
+
/* 30 second timeout on most commands */
#define CLIENT_TIMEOUT (30*1000)
#define SHORT_TIMEOUT (5*1000)
@@ -56,65 +60,35 @@ extern pstring user_socket_options;
/* value for unused fid field in trans2 secondary request */
#define FID_UNUSED (0xFFFF)
-int name_type = 0x20;
-
-int max_protocol = PROTOCOL_NT1;
-
-
time_t newer_than = 0;
int archive_level = 0;
-extern struct in_addr myip;
-
-extern pstring debugf;
-extern int DEBUGLEVEL;
-
BOOL translation = False;
+static BOOL have_ip;
+
/* clitar bits insert */
-extern void cmd_tar();
-extern void cmd_block();
-extern void cmd_tarmode();
-extern void cmd_setmode();
extern int blocksize;
extern BOOL tar_inc;
extern BOOL tar_reset;
-extern int process_tar();
-extern int tar_parseargs();
/* clitar bits end */
-int cnum = 0;
-int pid = 0;
-int gid = 0;
-int uid = 0;
-int mid = 0;
-int myumask = 0755;
-
-int max_xmit = BUFFER_SIZE;
-
-extern pstring scope;
+mode_t myumask = 0755;
BOOL prompt = True;
int printmode = 1;
-BOOL recurse = False;
+static BOOL recurse = False;
BOOL lowercase = False;
-BOOL have_ip = False;
-
struct in_addr dest_ip;
#define SEPARATORS " \t\n\r"
BOOL abort_mget = True;
-extern int Protocol;
-
-BOOL readbraw_supported = False;
-BOOL writebraw_supported = False;
-
pstring fileselection = "";
extern file_info def_finfo;
@@ -125,269 +99,114 @@ int get_total_time_ms = 0;
int put_total_size = 0;
int put_total_time_ms = 0;
-
-extern int Client;
+/* totals globals */
+static double dir_total;
#define USENMB
-#ifdef KANJI
-extern int coding_system;
-#define CNV_LANG(s) (coding_system == DOSV_CODE?s:dos_to_unix(s, False))
-#define CNV_INPUT(s) (coding_system == DOSV_CODE?s:unix_to_dos(s, True))
-static BOOL
-setup_term_code (char *code)
-{
- int new;
- new = interpret_coding_system (code, UNKNOWN_CODE);
- if (new != UNKNOWN_CODE) {
- coding_system = new;
- return True;
- }
- return False;
-}
-#else
-#define CNV_LANG(s) dos2unix_format(s,False)
-#define CNV_INPUT(s) unix2dos_format(s,True)
-#endif
-
-static void send_logout(void );
-BOOL reopen_connection(char *inbuf,char *outbuf);
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static BOOL call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,
- int *rprcnt,int *rdrcnt,char *param,char *data,
- char **rparam,char **rdata);
-static BOOL send_trans_request(char *outbuf,int trans,
- char *name,int fid,int flags,
- char *data,char *param,uint16 *setup,
- int ldata,int lparam,int lsetup,
- int mdata,int mparam,int msetup);
-
-
-/****************************************************************************
-setup basics in a outgoing packet
-****************************************************************************/
-void setup_pkt(char *outbuf)
-{
- SSVAL(outbuf,smb_pid,pid);
- SSVAL(outbuf,smb_uid,uid);
- SSVAL(outbuf,smb_mid,mid);
- if (Protocol > PROTOCOL_CORE)
- {
- SCVAL(outbuf,smb_flg,0x8);
- SSVAL(outbuf,smb_flg2,0x1);
- }
-}
-
/****************************************************************************
write to a local file with CR/LF->LF translation if appropriate. return the
number taken from the buffer. This may not equal the number written.
****************************************************************************/
static int writefile(int f, char *b, int n)
{
- int i;
+ int i;
- if (!translation)
- return(write(f,b,n));
-
- i = 0;
- while (i < n)
- {
- if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
- {
- b++;i++;
+ if (!translation) {
+ return write(f,b,n);
}
- if (write(f, b, 1) != 1)
- {
- break;
+
+ i = 0;
+ while (i < n) {
+ if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
+ b++;i++;
+ }
+ if (write(f, b, 1) != 1) {
+ break;
+ }
+ b++;
+ i++;
}
- b++;
- i++;
- }
- return(i);
+ return(i);
}
/****************************************************************************
read from a file with LF->CR/LF translation if appropriate. return the
number read. read approx n bytes.
****************************************************************************/
-static int readfile(char *b, int size, int n, FILE *f)
+static int readfile(char *b, int n, XFILE *f)
{
- int i;
- int c;
+ int i;
+ int c;
- if (!translation || (size != 1))
- return(fread(b,size,n,f));
+ if (!translation)
+ return x_fread(b,1,n,f);
- i = 0;
- while (i < n)
- {
- if ((c = getc(f)) == EOF)
- {
- break;
- }
+ i = 0;
+ while (i < (n - 1) && (i < BUFFER_SIZE)) {
+ if ((c = x_getc(f)) == EOF) {
+ break;
+ }
- if (c == '\n') /* change all LFs to CR/LF */
- {
- b[i++] = '\r';
- n++;
- }
+ if (c == '\n') { /* change all LFs to CR/LF */
+ b[i++] = '\r';
+ }
- b[i++] = c;
- }
+ b[i++] = c;
+ }
- return(i);
+ return(i);
}
/****************************************************************************
-read from a file with print translation. return the number read. read approx n
-bytes.
-****************************************************************************/
-static int printread(FILE *f,char *b,int n)
-{
- int i;
-
- i = readfile(b,1, n-1,f);
-#if FORMFEED
- if (feof(f) && i>0)
- b[i++] = '\014';
-#endif
-
- return(i);
-}
-
-/****************************************************************************
-check for existance of a dir
-****************************************************************************/
-static BOOL chkpath(char *path,BOOL report)
-{
- fstring path2;
- pstring inbuf,outbuf;
- char *p;
-
- strcpy(path2,path);
- trim_string(path2,NULL,"\\");
- if (!*path2) *path2 = '\\';
-
- bzero(outbuf,smb_size);
- set_message(outbuf,0,4 + strlen(path2),True);
- SCVAL(outbuf,smb_com,SMBchkpth);
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,path2);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (report && CVAL(inbuf,smb_rcls) != 0)
- DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
-
- return(CVAL(inbuf,smb_rcls) == 0);
-}
-
-
-/****************************************************************************
send a message
****************************************************************************/
-static void send_message(char *inbuf,char *outbuf)
+static void send_message(void)
{
- int total_len = 0;
-
- char *p;
- int grp_id;
-
- /* send a SMBsendstrt command */
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBsendstrt;
- SSVAL(outbuf,smb_tid,cnum);
+ int total_len = 0;
+ int grp_id;
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,username);
- p = skip_string(p,1);
- *p++ = 4;
- strcpy(p,desthost);
- p = skip_string(p,1);
-
- set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
-
- send_smb(Client,outbuf);
-
+ if (!cli_message_start(cli, desthost, username, &grp_id)) {
+ d_printf("message start: %s\n", cli_errstr(cli));
+ return;
+ }
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
- {
- printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
- return;
- }
- grp_id = SVAL(inbuf,smb_vwv0);
+ d_printf("Connected. Type your message, ending it with a Control-D\n");
- printf("Connected. Type your message, ending it with a Control-D\n");
+ while (!feof(stdin) && total_len < 1600) {
+ int maxlen = MIN(1600 - total_len,127);
+ pstring msg;
+ int l=0;
+ int c;
- while (!feof(stdin) && total_len < 1600)
- {
- int maxlen = MIN(1600 - total_len,127);
- pstring msg;
- int l=0;
- int c;
+ ZERO_ARRAY(msg);
- bzero(msg,smb_size);
+ for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
+ if (c == '\n')
+ msg[l++] = '\r';
+ msg[l] = c;
+ }
- for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
- {
- if (c == '\n')
- msg[l++] = '\r';
- msg[l] = c;
+ if (!cli_message_text(cli, msg, l, grp_id)) {
+ d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
+ return;
+ }
+
+ total_len += l;
}
- CVAL(outbuf,smb_com) = SMBsendtxt;
-
- set_message(outbuf,1,l+3,True);
-
- SSVAL(outbuf,smb_vwv0,grp_id);
-
- p = smb_buf(outbuf);
- *p = 1;
- SSVAL(p,1,l);
- memcpy(p+3,msg,l);
-
- send_smb(Client,outbuf);
-
+ if (total_len >= 1600)
+ d_printf("the message was truncated to 1600 bytes\n");
+ else
+ d_printf("sent %d bytes\n",total_len);
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
- {
- printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
- return;
+ if (!cli_message_end(cli, grp_id)) {
+ d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
+ return;
}
-
- total_len += l;
- }
-
- if (total_len >= 1600)
- printf("the message was truncated to 1600 bytes ");
- else
- printf("sent %d bytes ",total_len);
-
- printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
-
- CVAL(outbuf,smb_com) = SMBsendend;
- set_message(outbuf,1,0,False);
- SSVAL(outbuf,smb_vwv0,grp_id);
-
- send_smb(Client,outbuf);
-
-
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
- {
- printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
- return;
- }
}
@@ -395,1137 +214,572 @@ static void send_message(char *inbuf,char *outbuf)
/****************************************************************************
check the space on a device
****************************************************************************/
-static void do_dskattr(void)
+static int do_dskattr(void)
{
- pstring inbuf,outbuf;
-
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBdskattr;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ int total, bsize, avail;
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ if (!cli_dskattr(cli, &bsize, &total, &avail)) {
+ d_printf("Error in dskattr: %s\n",cli_errstr(cli));
+ return 1;
+ }
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));
+ d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
+ total, bsize, avail);
- DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
- SVAL(inbuf,smb_vwv0),
- SVAL(inbuf,smb_vwv1)*SVAL(inbuf,smb_vwv2),
- SVAL(inbuf,smb_vwv3)));
+ return 0;
}
/****************************************************************************
show cd/pwd
****************************************************************************/
-static void cmd_pwd(void)
+static int cmd_pwd(void)
{
- DEBUG(0,("Current directory is %s",CNV_LANG(service)));
- DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
+ d_printf("Current directory is %s",service);
+ d_printf("%s\n",cur_dir);
+ return 0;
}
/****************************************************************************
change directory - inner section
****************************************************************************/
-static void do_cd(char *newdir)
+static int do_cd(char *newdir)
{
- char *p = newdir;
- pstring saved_dir;
- pstring dname;
+ char *p = newdir;
+ pstring saved_dir;
+ pstring dname;
- /* Save the current directory in case the
- new directory is invalid */
- strcpy(saved_dir, cur_dir);
- if (*p == '\\')
- strcpy(cur_dir,p);
- else
- strcat(cur_dir,p);
- if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
- strcat(cur_dir, "\\");
- }
- dos_clean_name(cur_dir);
- strcpy(dname,cur_dir);
- strcat(cur_dir,"\\");
- dos_clean_name(cur_dir);
-
- if (!strequal(cur_dir,"\\"))
- if (!chkpath(dname,True))
- strcpy(cur_dir,saved_dir);
-
- strcpy(cd_path,cur_dir);
+ dos_format(newdir);
+
+ /* Save the current directory in case the
+ new directory is invalid */
+ pstrcpy(saved_dir, cur_dir);
+ if (*p == '\\')
+ pstrcpy(cur_dir,p);
+ else
+ pstrcat(cur_dir,p);
+ if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
+ pstrcat(cur_dir, "\\");
+ }
+ dos_clean_name(cur_dir);
+ pstrcpy(dname,cur_dir);
+ pstrcat(cur_dir,"\\");
+ dos_clean_name(cur_dir);
+
+ if (!strequal(cur_dir,"\\")) {
+ if (!cli_chkpath(cli, dname)) {
+ d_printf("cd %s: %s\n", dname, cli_errstr(cli));
+ pstrcpy(cur_dir,saved_dir);
+ }
+ }
+
+ pstrcpy(cd_path,cur_dir);
+
+ return 0;
}
/****************************************************************************
change directory
****************************************************************************/
-static void cmd_cd(char *inbuf,char *outbuf)
+static int cmd_cd(void)
{
- fstring buf;
-
- if (next_token(NULL,buf,NULL))
- do_cd(buf);
- else
- DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
-}
+ fstring buf;
+ int rc = 0;
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
+ rc = do_cd(buf);
+ else
+ d_printf("Current directory is %s\n",cur_dir);
-/****************************************************************************
- display info about a file
- ****************************************************************************/
-static void display_finfo(file_info *finfo)
-{
- time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
- DEBUG(0,(" %-30s%7.7s%10d %s",
- CNV_LANG(finfo->name),
- attrib_string(finfo->mode),
- finfo->size,
- asctime(LocalTime(&t,GMT_TO_LOCAL))));
+ return rc;
}
-/****************************************************************************
- do a directory listing, calling fn on each file found
- ****************************************************************************/
-void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
- DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
- if (Protocol >= PROTOCOL_LANMAN2)
- {
- if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
- return;
- }
-
- expand_mask(Mask,False);
- do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
- return;
-}
/*******************************************************************
decide if a file should be operated on
********************************************************************/
static BOOL do_this_one(file_info *finfo)
{
- if (finfo->mode & aDIR) return(True);
+ if (finfo->mode & aDIR) return(True);
- if (newer_than && finfo->mtime < newer_than)
- return(False);
+ if (*fileselection &&
+ !mask_match(finfo->name,fileselection,False)) {
+ DEBUG(3,("match_match %s failed\n", finfo->name));
+ return False;
+ }
- if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
- return(False);
+ if (newer_than && finfo->mtime < newer_than) {
+ DEBUG(3,("newer_than %s failed\n", finfo->name));
+ return(False);
+ }
- return(True);
+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
+ DEBUG(3,("archive %s failed\n", finfo->name));
+ return(False);
+ }
+
+ return(True);
}
/****************************************************************************
-interpret a short filename structure
-The length of the structure is returned
-****************************************************************************/
-static int interpret_short_filename(char *p,file_info *finfo)
+ display info about a file
+ ****************************************************************************/
+static void display_finfo(file_info *finfo)
{
- finfo->mode = CVAL(p,21);
-
- /* this date is converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date(p+22);
- finfo->mtime = finfo->atime = finfo->ctime;
- finfo->size = IVAL(p,26);
- strcpy(finfo->name,p+30);
-
- return(DIR_STRUCT_SIZE);
+ if (do_this_one(finfo)) {
+ time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
+ d_printf(" %-30s%7.7s %8.0f %s",
+ finfo->name,
+ attrib_string(finfo->mode),
+ (double)finfo->size,
+ asctime(LocalTime(&t)));
+ dir_total += finfo->size;
+ }
}
+
/****************************************************************************
-interpret a long filename structure - this is mostly guesses at the moment
-The length of the structure is returned
-The structure of a long filename depends on the info level. 260 is used
-by NT and 2 is used by OS/2
-****************************************************************************/
-static int interpret_long_filename(int level,char *p,file_info *finfo)
+ accumulate size of a file
+ ****************************************************************************/
+static void do_du(file_info *finfo)
{
- if (finfo)
- memcpy(finfo,&def_finfo,sizeof(*finfo));
-
- switch (level)
- {
- case 1: /* OS/2 understands this */
- if (finfo)
- {
- /* these dates are converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date2(p+4);
- finfo->atime = make_unix_date2(p+8);
- finfo->mtime = make_unix_date2(p+12);
- finfo->size = IVAL(p,16);
- finfo->mode = CVAL(p,24);
- strcpy(finfo->name,p+27);
+ if (do_this_one(finfo)) {
+ dir_total += finfo->size;
}
- return(28 + CVAL(p,26));
+}
- case 2: /* this is what OS/2 uses mostly */
- if (finfo)
- {
- /* these dates are converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date2(p+4);
- finfo->atime = make_unix_date2(p+8);
- finfo->mtime = make_unix_date2(p+12);
- finfo->size = IVAL(p,16);
- finfo->mode = CVAL(p,24);
- strcpy(finfo->name,p+31);
- }
- return(32 + CVAL(p,30));
+static BOOL do_list_recurse;
+static BOOL do_list_dirs;
+static char *do_list_queue = 0;
+static long do_list_queue_size = 0;
+static long do_list_queue_start = 0;
+static long do_list_queue_end = 0;
+static void (*do_list_fn)(file_info *);
- /* levels 3 and 4 are untested */
- case 3:
- if (finfo)
- {
- /* these dates are probably like the other ones */
- finfo->ctime = make_unix_date2(p+8);
- finfo->atime = make_unix_date2(p+12);
- finfo->mtime = make_unix_date2(p+16);
- finfo->size = IVAL(p,20);
- finfo->mode = CVAL(p,28);
- strcpy(finfo->name,p+33);
+/****************************************************************************
+functions for do_list_queue
+ ****************************************************************************/
+
+/*
+ * The do_list_queue is a NUL-separated list of strings stored in a
+ * char*. Since this is a FIFO, we keep track of the beginning and
+ * ending locations of the data in the queue. When we overflow, we
+ * double the size of the char*. When the start of the data passes
+ * the midpoint, we move everything back. This is logically more
+ * complex than a linked list, but easier from a memory management
+ * angle. In any memory error condition, do_list_queue is reset.
+ * Functions check to ensure that do_list_queue is non-NULL before
+ * accessing it.
+ */
+static void reset_do_list_queue(void)
+{
+ SAFE_FREE(do_list_queue);
+ do_list_queue_size = 0;
+ do_list_queue_start = 0;
+ do_list_queue_end = 0;
+}
+
+static void init_do_list_queue(void)
+{
+ reset_do_list_queue();
+ do_list_queue_size = 1024;
+ do_list_queue = malloc(do_list_queue_size);
+ if (do_list_queue == 0) {
+ d_printf("malloc fail for size %d\n",
+ (int)do_list_queue_size);
+ reset_do_list_queue();
+ } else {
+ memset(do_list_queue, 0, do_list_queue_size);
}
- return(SVAL(p,4)+4);
+}
- case 4:
- if (finfo)
+static void adjust_do_list_queue(void)
+{
+ /*
+ * If the starting point of the queue is more than half way through,
+ * move everything toward the beginning.
+ */
+ if (do_list_queue && (do_list_queue_start == do_list_queue_end))
{
- /* these dates are probably like the other ones */
- finfo->ctime = make_unix_date2(p+8);
- finfo->atime = make_unix_date2(p+12);
- finfo->mtime = make_unix_date2(p+16);
- finfo->size = IVAL(p,20);
- finfo->mode = CVAL(p,28);
- strcpy(finfo->name,p+37);
+ DEBUG(4,("do_list_queue is empty\n"));
+ do_list_queue_start = do_list_queue_end = 0;
+ *do_list_queue = '\0';
}
- return(SVAL(p,4)+4);
-
- case 260: /* NT uses this, but also accepts 2 */
- if (finfo)
+ else if (do_list_queue_start > (do_list_queue_size / 2))
{
- int ret = SVAL(p,0);
- int namelen;
- p += 4; /* next entry offset */
- p += 4; /* fileindex */
-
- /* these dates appear to arrive in a weird way. It seems to
- be localtime plus the serverzone given in the initial
- connect. This is GMT when DST is not in effect and one
- hour from GMT otherwise. Can this really be right??
-
- I suppose this could be called kludge-GMT. Is is the GMT
- you get by using the current DST setting on a different
- localtime. It will be cheap to calculate, I suppose, as
- no DST tables will be needed */
-
- finfo->ctime = interpret_long_date(p); p += 8;
- finfo->atime = interpret_long_date(p); p += 8;
- finfo->mtime = interpret_long_date(p); p += 8; p += 8;
- finfo->size = IVAL(p,0); p += 8;
- p += 8; /* alloc size */
- finfo->mode = CVAL(p,0); p += 4;
- namelen = IVAL(p,0); p += 4;
- p += 4; /* EA size */
- p += 2; /* short name len? */
- p += 24; /* short name? */
- StrnCpy(finfo->name,p,namelen);
- return(ret);
+ DEBUG(4,("sliding do_list_queue backward\n"));
+ memmove(do_list_queue,
+ do_list_queue + do_list_queue_start,
+ do_list_queue_end - do_list_queue_start);
+ do_list_queue_end -= do_list_queue_start;
+ do_list_queue_start = 0;
}
- return(SVAL(p,0));
- }
-
- DEBUG(1,("Unknown long filename format %d\n",level));
- return(SVAL(p,0));
+
}
-
-
-
-/****************************************************************************
- act on the files in a dir listing
- ****************************************************************************/
-static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
+static void add_to_do_list_queue(const char* entry)
{
-
- if (!((finfo->mode & aDIR) == 0 && *fileselection &&
- !mask_match(finfo->name,fileselection,False,False)) &&
- !(recurse_dir && (strequal(finfo->name,".") ||
- strequal(finfo->name,".."))))
- {
- if (recurse_dir && (finfo->mode & aDIR))
+ char *dlq;
+ long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
+ while (new_end > do_list_queue_size)
{
- pstring mask2;
- pstring sav_dir;
- strcpy(sav_dir,cur_dir);
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
- strcpy(mask2,cur_dir);
-
- if (!fn)
- DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
-
- strcat(mask2,"*");
-
- if (longdir)
- do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);
- else
- do_dir(inbuf,outbuf,mask2,attribute,fn,True);
-
- strcpy(cur_dir,sav_dir);
+ do_list_queue_size *= 2;
+ DEBUG(4,("enlarging do_list_queue to %d\n",
+ (int)do_list_queue_size));
+ dlq = Realloc(do_list_queue, do_list_queue_size);
+ if (! dlq) {
+ d_printf("failure enlarging do_list_queue to %d bytes\n",
+ (int)do_list_queue_size);
+ reset_do_list_queue();
+ }
+ else
+ {
+ do_list_queue = dlq;
+ memset(do_list_queue + do_list_queue_size / 2,
+ 0, do_list_queue_size / 2);
+ }
}
- else
+ if (do_list_queue)
{
- if (fn && do_this_one(finfo))
- fn(finfo);
+ pstrcpy(do_list_queue + do_list_queue_end, entry);
+ do_list_queue_end = new_end;
+ DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
+ entry, (int)do_list_queue_start, (int)do_list_queue_end));
}
- }
}
-
-/****************************************************************************
- do a directory listing, calling fn on each file found
- ****************************************************************************/
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
+static char *do_list_queue_head(void)
{
- char *p;
- int received = 0;
- BOOL first = True;
- char status[21];
- int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
- int num_received = 0;
- int i;
- char *dirlist = NULL;
- pstring mask;
- file_info finfo;
-
- finfo = def_finfo;
-
- bzero(status,21);
-
- strcpy(mask,Mask);
-
- while (1)
- {
- bzero(outbuf,smb_size);
- if (first)
- set_message(outbuf,2,5 + strlen(mask),True);
- else
- set_message(outbuf,2,5 + 21,True);
-
-#if FFIRST
- if (Protocol >= PROTOCOL_LANMAN1)
- CVAL(outbuf,smb_com) = SMBffirst;
- else
-#endif
- CVAL(outbuf,smb_com) = SMBsearch;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ return do_list_queue + do_list_queue_start;
+}
- SSVAL(outbuf,smb_vwv0,num_asked);
- SSVAL(outbuf,smb_vwv1,attribute);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- if (first)
- strcpy(p,mask);
- else
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- if (first)
- SSVAL(p,0,0);
- else
+static void remove_do_list_queue_head(void)
+{
+ if (do_list_queue_end > do_list_queue_start)
{
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
+ do_list_queue_start += strlen(do_list_queue_head()) + 1;
+ adjust_do_list_queue();
+ DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
+ (int)do_list_queue_start, (int)do_list_queue_end));
}
+}
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- received = SVAL(inbuf,smb_vwv0);
-
- DEBUG(5,("dir received %d\n",received));
-
- DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
-
- if (received <= 0) break;
-
- first = False;
-
- dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
-
- if (!dirlist)
- return 0;
-
- p = smb_buf(inbuf) + 3;
-
- memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
- p,received*DIR_STRUCT_SIZE);
-
- memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
-
- num_received += received;
-
- if (CVAL(inbuf,smb_rcls) != 0) break;
- }
-
-#if FFIRST
- if (!first && Protocol >= PROTOCOL_LANMAN1)
- {
- bzero(outbuf,smb_size);
- CVAL(outbuf,smb_com) = SMBfclose;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
- }
-#endif
-
- if (!fn)
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- display_finfo(&finfo);
- }
-
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
- }
-
- if (dirlist) free(dirlist);
- return(num_received);
+static int do_list_queue_empty(void)
+{
+ return (! (do_list_queue && *do_list_queue));
}
/****************************************************************************
- receive a SMB trans or trans2 response allocating the necessary memory
+a helper for do_list
****************************************************************************/
-static BOOL receive_trans_response(char *inbuf,int trans,
- int *data_len,int *param_len,
- char **data,char **param)
+static void do_list_helper(file_info *f, const char *mask, void *state)
{
- int total_data=0;
- int total_param=0;
- int this_data,this_param;
-
- *data_len = *param_len = 0;
-
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
- show_msg(inbuf);
-
- /* sanity check */
- if (CVAL(inbuf,smb_com) != trans)
- {
- DEBUG(0,("Expected %s response, got command 0x%02x\n",
- trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
- return(False);
- }
- if (CVAL(inbuf,smb_rcls) != 0)
- return(False);
-
- /* parse out the lengths */
- total_data = SVAL(inbuf,smb_tdrcnt);
- total_param = SVAL(inbuf,smb_tprcnt);
-
- /* allocate it */
- *data = Realloc(*data,total_data);
- *param = Realloc(*param,total_param);
-
- while (1)
- {
- this_data = SVAL(inbuf,smb_drcnt);
- this_param = SVAL(inbuf,smb_prcnt);
- if (this_data)
- memcpy(*data + SVAL(inbuf,smb_drdisp),
- smb_base(inbuf) + SVAL(inbuf,smb_droff),
- this_data);
- if (this_param)
- memcpy(*param + SVAL(inbuf,smb_prdisp),
- smb_base(inbuf) + SVAL(inbuf,smb_proff),
- this_param);
- *data_len += this_data;
- *param_len += this_param;
-
- /* parse out the total lengths again - they can shrink! */
- total_data = SVAL(inbuf,smb_tdrcnt);
- total_param = SVAL(inbuf,smb_tprcnt);
-
- if (total_data <= *data_len && total_param <= *param_len)
- break;
-
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
- show_msg(inbuf);
-
- /* sanity check */
- if (CVAL(inbuf,smb_com) != trans)
- {
- DEBUG(0,("Expected %s response, got command 0x%02x\n",
- trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
- return(False);
+ if (f->mode & aDIR) {
+ if (do_list_dirs && do_this_one(f)) {
+ do_list_fn(f);
+ }
+ if (do_list_recurse &&
+ !strequal(f->name,".") &&
+ !strequal(f->name,"..")) {
+ pstring mask2;
+ char *p;
+
+ pstrcpy(mask2, mask);
+ p = strrchr_m(mask2,'\\');
+ if (!p) return;
+ p[1] = 0;
+ pstrcat(mask2, f->name);
+ pstrcat(mask2,"\\*");
+ add_to_do_list_queue(mask2);
+ }
+ return;
+ }
+
+ if (do_this_one(f)) {
+ do_list_fn(f);
}
- if (CVAL(inbuf,smb_rcls) != 0)
- return(False);
- }
-
- return(True);
}
+
/****************************************************************************
- do a directory listing, calling fn on each file found. Use the TRANSACT2
- call for long filenames
+a wrapper around cli_list that adds recursion
****************************************************************************/
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
+void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
{
- int max_matches = 512;
- int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
- char *p;
- pstring mask;
- file_info finfo;
- int i;
- char *dirlist = NULL;
- int dirlist_len = 0;
- int total_received = 0;
- BOOL First = True;
- char *resp_data=NULL;
- char *resp_param=NULL;
- int resp_data_len = 0;
- int resp_param_len=0;
-
- int ff_resume_key = 0;
- int ff_searchcount=0;
- int ff_eos=0;
- int ff_lastname=0;
- int ff_dir_handle=0;
- int loop_count = 0;
-
- uint16 setup;
- pstring param;
-
- strcpy(mask,Mask);
-
- while (ff_eos == 0)
- {
- loop_count++;
- if (loop_count > 200)
- {
- DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
- break;
- }
+ static int in_do_list = 0;
- if (First)
+ if (in_do_list && rec)
{
- setup = TRANSACT2_FINDFIRST;
- SSVAL(param,0,attribute); /* attribute */
- SSVAL(param,2,max_matches); /* max count */
- SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
- SSVAL(param,6,info_level);
- SIVAL(param,8,0);
- strcpy(param+12,mask);
+ fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
+ exit(1);
}
- else
- {
- setup = TRANSACT2_FINDNEXT;
- SSVAL(param,0,ff_dir_handle);
- SSVAL(param,2,max_matches); /* max count */
- SSVAL(param,4,info_level);
- SIVAL(param,6,ff_resume_key); /* ff_resume_key */
- SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
- strcpy(param+12,mask);
-
- DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
- ff_dir_handle,ff_resume_key,ff_lastname,mask));
- }
- /* ??? original code added 1 pad byte after param */
- send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
- NULL,param,&setup,
- 0,12+strlen(mask)+1,1,
- BUFFER_SIZE,10,0);
+ in_do_list = 1;
- if (!receive_trans_response(inbuf,SMBtrans2,
- &resp_data_len,&resp_param_len,
- &resp_data,&resp_param))
- {
- DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
- break;
- }
+ do_list_recurse = rec;
+ do_list_dirs = dirs;
+ do_list_fn = fn;
- /* parse out some important return info */
- p = resp_param;
- if (First)
+ if (rec)
{
- ff_dir_handle = SVAL(p,0);
- ff_searchcount = SVAL(p,2);
- ff_eos = SVAL(p,4);
- ff_lastname = SVAL(p,8);
+ init_do_list_queue();
+ add_to_do_list_queue(mask);
+
+ while (! do_list_queue_empty())
+ {
+ /*
+ * Need to copy head so that it doesn't become
+ * invalid inside the call to cli_list. This
+ * would happen if the list were expanded
+ * during the call.
+ * Fix from E. Jay Berkenbilt (ejb@ql.org)
+ */
+ pstring head;
+ pstrcpy(head, do_list_queue_head());
+ cli_list(cli, head, attribute, do_list_helper, NULL);
+ remove_do_list_queue_head();
+ if ((! do_list_queue_empty()) && (fn == display_finfo))
+ {
+ char* next_file = do_list_queue_head();
+ char* save_ch = 0;
+ if ((strlen(next_file) >= 2) &&
+ (next_file[strlen(next_file) - 1] == '*') &&
+ (next_file[strlen(next_file) - 2] == '\\'))
+ {
+ save_ch = next_file +
+ strlen(next_file) - 2;
+ *save_ch = '\0';
+ }
+ d_printf("\n%s\n",next_file);
+ if (save_ch)
+ {
+ *save_ch = '\\';
+ }
+ }
+ }
}
- else
+ else
{
- ff_searchcount = SVAL(p,0);
- ff_eos = SVAL(p,2);
- ff_lastname = SVAL(p,6);
+ if (cli_list(cli, mask, attribute, do_list_helper, NULL) == -1)
+ {
+ d_printf("%s listing %s\n", cli_errstr(cli), mask);
+ }
}
- if (ff_searchcount == 0)
- break;
-
- /* point to the data bytes */
- p = resp_data;
+ in_do_list = 0;
+ reset_do_list_queue();
+}
- /* we might need the lastname for continuations */
- if (ff_lastname > 0)
- {
- switch(info_level)
- {
- case 260:
- ff_resume_key =0;
- StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
- /* strcpy(mask,p+ff_lastname+94); */
- break;
- case 1:
- strcpy(mask,p + ff_lastname + 1);
- ff_resume_key = 0;
- break;
- }
+/****************************************************************************
+ get a directory listing
+ ****************************************************************************/
+static int cmd_dir(void)
+{
+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+ pstring mask;
+ fstring buf;
+ char *p=buf;
+ int rc;
+
+ dir_total = 0;
+ pstrcpy(mask,cur_dir);
+ if(mask[strlen(mask)-1]!='\\')
+ pstrcat(mask,"\\");
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ dos_format(p);
+ if (*p == '\\')
+ pstrcpy(mask,p);
+ else
+ pstrcat(mask,p);
}
- else
- strcpy(mask,"");
-
- /* and add them to the dirlist pool */
- dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
-
- if (!dirlist)
- {
- DEBUG(0,("Failed to expand dirlist\n"));
- break;
+ else {
+ pstrcat(mask,"*");
}
- /* put in a length for the last entry, to ensure we can chain entries
- into the next packet */
- {
- char *p2;
- for (p2=p,i=0;i<(ff_searchcount-1);i++)
- p2 += interpret_long_filename(info_level,p2,NULL);
- SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
- }
-
- /* grab the data for later use */
- memcpy(dirlist+dirlist_len,p,resp_data_len);
- dirlist_len += resp_data_len;
-
- total_received += ff_searchcount;
-
- if (resp_data) free(resp_data); resp_data = NULL;
- if (resp_param) free(resp_param); resp_param = NULL;
-
- DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
- ff_searchcount,ff_eos,ff_resume_key));
-
- First = False;
- }
-
- if (!fn)
- for (p=dirlist,i=0;i<total_received;i++)
- {
- p += interpret_long_filename(info_level,p,&finfo);
- display_finfo(&finfo);
- }
-
- for (p=dirlist,i=0;i<total_received;i++)
- {
- p += interpret_long_filename(info_level,p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
- }
-
- /* free up the dirlist buffer */
- if (dirlist) free(dirlist);
- return(total_received);
+ do_list(mask, attribute, display_finfo, recurse, True);
+
+ rc = do_dskattr();
+
+ DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
+
+ return rc;
}
/****************************************************************************
get a directory listing
****************************************************************************/
-static void cmd_dir(char *inbuf,char *outbuf)
+static int cmd_du(void)
{
- int attribute = aDIR | aSYSTEM | aHIDDEN;
- pstring mask;
- fstring buf;
- char *p=buf;
-
- strcpy(mask,cur_dir);
- if(mask[strlen(mask)-1]!='\\')
- strcat(mask,"\\");
-
- if (next_token(NULL,buf,NULL))
- {
- if (*p == '\\')
- strcpy(mask,p);
- else
- strcat(mask,p);
- }
- else {
- strcat(mask,"*");
- }
-
- do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
-
- do_dskattr();
-}
+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+ pstring mask;
+ fstring buf;
+ char *p=buf;
+ int rc;
+
+ dir_total = 0;
+ pstrcpy(mask,cur_dir);
+ if(mask[strlen(mask)-1]!='\\')
+ pstrcat(mask,"\\");
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ dos_format(p);
+ if (*p == '\\')
+ pstrcpy(mask,p);
+ else
+ pstrcat(mask,p);
+ } else {
+ pstrcat(mask,"*");
+ }
+ do_list(mask, attribute, do_du, recurse, True);
+
+ rc = do_dskattr();
+
+ d_printf("Total number of bytes: %.0f\n", dir_total);
+
+ return rc;
+}
/****************************************************************************
get a file from rname to lname
****************************************************************************/
-static void do_get(char *rname,char *lname,file_info *finfo1)
+static int do_get(char *rname,char *lname)
{
- int handle=0,fnum;
- uint32 nread=0;
- char *p;
- BOOL newhandle = False;
- char *inbuf,*outbuf;
- file_info finfo;
- BOOL close_done = False;
- BOOL ignore_close_error = False;
- char *dataptr=NULL;
- int datalen=0;
-
- struct timeval tp_start;
- GetTimeOfDay(&tp_start);
-
- if (finfo1)
- finfo = *finfo1;
- else
- finfo = def_finfo;
-
- if (lowercase)
- strlower(lname);
-
-
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return;
- }
-
- bzero(outbuf,smb_size);
- set_message(outbuf,15,1 + strlen(rname),True);
-
- CVAL(outbuf,smb_com) = SMBopenX;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv2,1);
- SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
- SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
- SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
- SSVAL(outbuf,smb_vwv8,1);
-
- p = smb_buf(outbuf);
- strcpy(p,rname);
- p = skip_string(p,1);
-
- /* do a chained openX with a readX? */
-#if 1
- if (finfo.size > 0)
- {
- DEBUG(3,("Chaining readX wth openX\n"));
- SSVAL(outbuf,smb_vwv0,SMBreadX);
- SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
- bzero(p,200);
- p -= smb_wct;
- SSVAL(p,smb_wct,10);
- SSVAL(p,smb_vwv0,0xFF);
- SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
- SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
- smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
- }
-#endif
-
- if(!strcmp(lname,"-"))
- handle = fileno(stdout);
- else
- {
- handle = creat(lname,0644);
- newhandle = True;
- }
- if (handle < 0)
- {
- DEBUG(0,("Error opening local file %s\n",lname));
- free(inbuf);free(outbuf);
- return;
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- if (CVAL(inbuf,smb_rcls) == ERRSRV &&
- SVAL(inbuf,smb_err) == ERRnoresource &&
- reopen_connection(inbuf,outbuf))
- {
- do_get(rname,lname,finfo1);
- return;
+ int handle=0,fnum;
+ BOOL newhandle = False;
+ char *data;
+ struct timeval tp_start;
+ int read_size = io_bufsize;
+ uint16 attr;
+ size_t size;
+ off_t nread = 0;
+ int rc = 0;
+
+ GetTimeOfDay(&tp_start);
+
+ if (lowercase) {
+ strlower(lname);
}
- DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
- if(newhandle)
- close(handle);
- free(inbuf);free(outbuf);
- return;
- }
-
- strcpy(finfo.name,rname);
-
- if (!finfo1)
- {
- finfo.mode = SVAL(inbuf,smb_vwv3);
- /* these times arrive as LOCAL time, using the DST offset
- corresponding to that time, we convert them to GMT */
- finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
- finfo.atime = finfo.ctime = finfo.mtime;
- finfo.size = IVAL(inbuf,smb_vwv6);
- }
-
- DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
-
- fnum = SVAL(inbuf,smb_vwv2);
-
- /* we might have got some data from a chained readX */
- if (SVAL(inbuf,smb_vwv0) == SMBreadX)
- {
- p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
- datalen = SVAL(p,smb_vwv5);
- dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
- }
- else
- {
- dataptr = NULL;
- datalen = 0;
- }
-
-
- DEBUG(2,("getting file %s of size %d bytes as %s ",
- CNV_LANG(finfo.name),
- finfo.size,
- lname));
-
- while (nread < finfo.size && !close_done)
- {
- int method = -1;
- static BOOL can_chain_close = True;
-
- p=NULL;
-
- DEBUG(3,("nread=%d max_xmit=%d fsize=%d\n",nread,max_xmit,finfo.size));
- /* 3 possible read types. readbraw if a large block is required.
- readX + close if not much left and read if neither is supported */
+ fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
+
+ if (fnum == -1) {
+ d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
+ return 1;
+ }
- /* we might have already read some data from a chained readX */
- if (dataptr && datalen>0)
- method=3;
+ if(!strcmp(lname,"-")) {
+ handle = fileno(stdout);
+ } else {
+ handle = sys_open(lname,O_WRONLY|O_CREAT|O_TRUNC,0644);
+ newhandle = True;
+ }
+ if (handle < 0) {
+ d_printf("Error opening local file %s\n",lname);
+ return 1;
+ }
- /* if we can finish now then readX+close */
- if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
- ((finfo.size - nread) <
- (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
- method = 0;
- /* if we support readraw then use that */
- if (method<0 && readbraw_supported)
- method = 1;
+ if (!cli_qfileinfo(cli, fnum,
+ &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
+ !cli_getattrE(cli, fnum,
+ &attr, &size, NULL, NULL, NULL)) {
+ d_printf("getattrib: %s\n",cli_errstr(cli));
+ return 1;
+ }
- /* if we can then use readX */
- if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
- method = 2;
+ DEBUG(2,("getting file %s of size %.0f as %s ",
+ lname, (double)size, lname));
- switch (method)
- {
- /* use readX */
- case 0:
- case 2:
- if (method == 0)
- close_done = True;
-
- /* use readX + close */
- bzero(outbuf,smb_size);
- set_message(outbuf,10,0,True);
- CVAL(outbuf,smb_com) = SMBreadX;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- if (close_done)
- {
- CVAL(outbuf,smb_vwv0) = SMBclose;
- SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
- }
- else
- CVAL(outbuf,smb_vwv0) = 0xFF;
-
- SSVAL(outbuf,smb_vwv2,fnum);
- SIVAL(outbuf,smb_vwv3,nread);
- SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
- SSVAL(outbuf,smb_vwv6,0);
- SIVAL(outbuf,smb_vwv7,0);
- SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
-
- if (close_done)
- {
- p = smb_buf(outbuf);
- bzero(p,9);
-
- CVAL(p,0) = 3;
- SSVAL(p,1,fnum);
- SIVALS(p,3,-1);
-
- /* now set the total packet length */
- smb_setlen(outbuf,smb_len(outbuf)+9);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
- break;
- }
-
- if (close_done &&
- SVAL(inbuf,smb_vwv0) != SMBclose)
- {
- /* NOTE: WfWg sometimes just ignores the chained
- command! This seems to break the spec? */
- DEBUG(3,("Rejected chained close?\n"));
- close_done = False;
- can_chain_close = False;
- ignore_close_error = True;
- }
-
- datalen = SVAL(inbuf,smb_vwv5);
- dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
- break;
-
- /* use readbraw */
- case 1:
- {
- static int readbraw_size = BUFFER_SIZE;
-
- extern int Client;
- bzero(outbuf,smb_size);
- set_message(outbuf,8,0,True);
- CVAL(outbuf,smb_com) = SMBreadbraw;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
- SSVAL(outbuf,smb_vwv0,fnum);
- SIVAL(outbuf,smb_vwv1,nread);
- SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
- SSVAL(outbuf,smb_vwv4,0);
- SIVALS(outbuf,smb_vwv5,-1);
- send_smb(Client,outbuf);
-
- /* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
- DEBUG(0,("Failed to read length in readbraw\n"));
- exit(1);
- }
-
- /* Even though this is not an smb message, smb_len
- returns the generic length of an smb message */
- datalen = smb_len(inbuf);
-
- if (datalen == 0)
- {
- /* we got a readbraw error */
- DEBUG(4,("readbraw error - reducing size\n"));
- readbraw_size = (readbraw_size * 9) / 10;
-
- if (readbraw_size < max_xmit)
- {
- DEBUG(0,("disabling readbraw\n"));
- readbraw_supported = False;
- }
-
- dataptr=NULL;
- continue;
- }
-
- if(read_data(Client,inbuf,datalen) != datalen) {
- DEBUG(0,("Failed to read data in readbraw\n"));
- exit(1);
- }
- dataptr = inbuf;
- }
- break;
-
- case 3:
- /* we've already read some data with a chained readX */
- break;
-
- default:
- /* use plain read */
- bzero(outbuf,smb_size);
- set_message(outbuf,5,0,True);
- CVAL(outbuf,smb_com) = SMBread;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
- SIVAL(outbuf,smb_vwv2,nread);
- SSVAL(outbuf,smb_vwv4,finfo.size - nread);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
- break;
- }
-
- datalen = SVAL(inbuf,smb_vwv0);
- dataptr = smb_buf(inbuf) + 3;
- break;
+ if(!(data = (char *)malloc(read_size))) {
+ d_printf("malloc fail for size %d\n", read_size);
+ cli_close(cli, fnum);
+ return 1;
}
+
+ while (1) {
+ int n = cli_read(cli, fnum, data, nread, read_size);
+
+ if (n <= 0) break;
- if (writefile(handle,dataptr,datalen) != datalen)
- {
- DEBUG(0,("Error writing local file\n"));
- break;
- }
+ if (writefile(handle,data, n) != n) {
+ d_printf("Error writing local file\n");
+ rc = 1;
+ break;
+ }
- nread += datalen;
- if (datalen == 0)
- {
- DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
- break;
+ nread += n;
}
- dataptr=NULL;
- datalen=0;
- }
+ if (nread < size) {
+ DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
+ rname, (long)nread));
+ rc = 1;
+ }
+ SAFE_FREE(data);
+
+ if (!cli_close(cli, fnum)) {
+ d_printf("Error %s closing remote file\n",cli_errstr(cli));
+ rc = 1;
+ }
+
+ if (newhandle) {
+ close(handle);
+ }
+
+ if (archive_level >= 2 && (attr & aARCH)) {
+ cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
+ }
- if (!close_done)
- {
- bzero(outbuf,smb_size);
- set_message(outbuf,3,0,True);
- CVAL(outbuf,smb_com) = SMBclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SIVALS(outbuf,smb_vwv1,-1);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
{
- DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
- if(newhandle)
- close(handle);
- free(inbuf);free(outbuf);
- return;
+ struct timeval tp_end;
+ int this_time;
+
+ GetTimeOfDay(&tp_end);
+ this_time =
+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
+ get_total_time_ms += this_time;
+ get_total_size += nread;
+
+ DEBUG(2,("(%3.1f kb/s) (average %3.1f kb/s)\n",
+ nread / (1.024*this_time + 1.0e-4),
+ get_total_size / (1.024*get_total_time_ms)));
}
- }
-
- if(newhandle)
- close(handle);
-
- if (archive_level >= 2 && (finfo.mode & aARCH)) {
- bzero(outbuf,smb_size);
- set_message(outbuf,8,strlen(rname)+4,True);
- CVAL(outbuf,smb_com) = SMBsetatr;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
- SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
- SIVALS(outbuf,smb_vwv1,0);
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,rname);
- p += strlen(p)+1;
- *p++ = 4;
- *p = 0;
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
- }
-
- {
- struct timeval tp_end;
- int this_time;
-
- GetTimeOfDay(&tp_end);
- this_time =
- (tp_end.tv_sec - tp_start.tv_sec)*1000 +
- (tp_end.tv_usec - tp_start.tv_usec)/1000;
- get_total_time_ms += this_time;
- get_total_size += finfo.size;
-
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
- finfo.size / (1.024*this_time + 1.0e-4),
- get_total_size / (1.024*get_total_time_ms)));
- }
-
- free(inbuf);free(outbuf);
+
+ return rc;
}
/****************************************************************************
get a file
****************************************************************************/
-static void cmd_get(void)
+static int cmd_get(void)
{
- pstring lname;
- pstring rname;
- char *p;
-
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
-
- p = rname + strlen(rname);
-
- if (!next_token(NULL,p,NULL)) {
- DEBUG(0,("get <filename>\n"));
- return;
- }
- strcpy(lname,p);
- dos_clean_name(rname);
-
- next_token(NULL,lname,NULL);
+ pstring lname;
+ pstring rname;
+ char *p;
- do_get(rname,lname,NULL);
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,"\\");
+
+ p = rname + strlen(rname);
+
+ if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
+ d_printf("get <filename>\n");
+ return 1;
+ }
+ pstrcpy(lname,p);
+ dos_clean_name(rname);
+
+ next_token_nr(NULL,lname,NULL,sizeof(lname));
+
+ return do_get(rname, lname);
}
@@ -1534,110 +788,105 @@ static void cmd_get(void)
****************************************************************************/
static void do_mget(file_info *finfo)
{
- pstring rname;
- pstring quest;
-
- if (strequal(finfo->name,".") || strequal(finfo->name,".."))
- return;
-
- if (abort_mget)
- {
- DEBUG(0,("mget aborted\n"));
- return;
- }
+ pstring rname;
+ pstring quest;
+ pstring saved_curdir;
+ pstring mget_mask;
- if (finfo->mode & aDIR)
- sprintf(quest,"Get directory %s? ",CNV_LANG(finfo->name));
- else
- sprintf(quest,"Get file %s? ",CNV_LANG(finfo->name));
+ if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+ return;
- if (prompt && !yesno(quest)) return;
+ if (abort_mget) {
+ d_printf("mget aborted\n");
+ return;
+ }
- if (finfo->mode & aDIR)
- {
- pstring saved_curdir;
- pstring mget_mask;
- char *inbuf,*outbuf;
+ if (finfo->mode & aDIR)
+ slprintf(quest,sizeof(pstring)-1,
+ "Get directory %s? ",finfo->name);
+ else
+ slprintf(quest,sizeof(pstring)-1,
+ "Get file %s? ",finfo->name);
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ if (prompt && !yesno(quest)) return;
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return;
+ if (!(finfo->mode & aDIR)) {
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,finfo->name);
+ do_get(rname,finfo->name);
+ return;
}
- strcpy(saved_curdir,cur_dir);
+ /* handle directories */
+ pstrcpy(saved_curdir,cur_dir);
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
+ pstrcat(cur_dir,finfo->name);
+ pstrcat(cur_dir,"\\");
- unix_format(finfo->name);
- {
+ unix_format(finfo->name);
if (lowercase)
- strlower(finfo->name);
-
+ strlower(finfo->name);
+
if (!directory_exist(finfo->name,NULL) &&
- sys_mkdir(finfo->name,0777) != 0)
- {
- DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
- strcpy(cur_dir,saved_curdir);
- free(inbuf);free(outbuf);
- return;
- }
-
- if (sys_chdir(finfo->name) != 0)
- {
- DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
- strcpy(cur_dir,saved_curdir);
- free(inbuf);free(outbuf);
- return;
- }
- }
-
- strcpy(mget_mask,cur_dir);
- strcat(mget_mask,"*");
-
- do_dir((char *)inbuf,(char *)outbuf,
- mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False);
- chdir("..");
- strcpy(cur_dir,saved_curdir);
- free(inbuf);free(outbuf);
- }
- else
- {
- strcpy(rname,cur_dir);
- strcat(rname,finfo->name);
- do_get(rname,finfo->name,finfo);
- }
+ mkdir(finfo->name,0777) != 0) {
+ d_printf("failed to create directory %s\n",finfo->name);
+ pstrcpy(cur_dir,saved_curdir);
+ return;
+ }
+
+ if (chdir(finfo->name) != 0) {
+ d_printf("failed to chdir to directory %s\n",finfo->name);
+ pstrcpy(cur_dir,saved_curdir);
+ return;
+ }
+
+ pstrcpy(mget_mask,cur_dir);
+ pstrcat(mget_mask,"*");
+
+ do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True);
+ chdir("..");
+ pstrcpy(cur_dir,saved_curdir);
}
+
/****************************************************************************
view the file using the pager
****************************************************************************/
-static void cmd_more(void)
+static int cmd_more(void)
{
- fstring rname,lname,tmpname,pager_cmd;
- char *pager;
-
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
- sprintf(tmpname,"/tmp/smbmore.%d",getpid());
- strcpy(lname,tmpname);
-
- if (!next_token(NULL,rname+strlen(rname),NULL)) {
- DEBUG(0,("more <filename>\n"));
- return;
- }
- dos_clean_name(rname);
-
- do_get(rname,lname,NULL);
-
- pager=getenv("PAGER");
- sprintf(pager_cmd,"%s %s",(pager? pager:PAGER), tmpname);
- system(pager_cmd);
- unlink(tmpname);
+ fstring rname,lname,pager_cmd;
+ char *pager;
+ int fd;
+ int rc = 0;
+
+ fstrcpy(rname,cur_dir);
+ fstrcat(rname,"\\");
+
+ slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
+ fd = smb_mkstemp(lname);
+ if (fd == -1) {
+ d_printf("failed to create temporary file for more\n");
+ return 1;
+ }
+ close(fd);
+
+ if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
+ d_printf("more <filename>\n");
+ unlink(lname);
+ return 1;
+ }
+ dos_clean_name(rname);
+
+ rc = do_get(rname,lname);
+
+ pager=getenv("PAGER");
+
+ slprintf(pager_cmd,sizeof(pager_cmd)-1,
+ "%s %s",(pager? pager:PAGER), lname);
+ system(pager_cmd);
+ unlink(lname);
+
+ return rc;
}
@@ -1645,1060 +894,760 @@ static void cmd_more(void)
/****************************************************************************
do a mget command
****************************************************************************/
-static void cmd_mget(char *inbuf,char *outbuf)
+static int cmd_mget(void)
{
- int attribute = aSYSTEM | aHIDDEN;
- pstring mget_mask;
- fstring buf;
- char *p=buf;
-
- *mget_mask = 0;
-
- if (recurse)
- attribute |= aDIR;
-
- abort_mget = False;
-
- while (next_token(NULL,p,NULL))
- {
- strcpy(mget_mask,cur_dir);
- if(mget_mask[strlen(mget_mask)-1]!='\\')
- strcat(mget_mask,"\\");
-
- if (*p == '\\')
- strcpy(mget_mask,p);
- else
- strcat(mget_mask,p);
- do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
- }
-
- if (! *mget_mask)
- {
- strcpy(mget_mask,cur_dir);
- if(mget_mask[strlen(mget_mask)-1]!='\\')
- strcat(mget_mask,"\\");
- strcat(mget_mask,"*");
- do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
- }
+ uint16 attribute = aSYSTEM | aHIDDEN;
+ pstring mget_mask;
+ fstring buf;
+ char *p=buf;
+
+ *mget_mask = 0;
+
+ if (recurse)
+ attribute |= aDIR;
+
+ abort_mget = False;
+
+ while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
+ pstrcpy(mget_mask,cur_dir);
+ if(mget_mask[strlen(mget_mask)-1]!='\\')
+ pstrcat(mget_mask,"\\");
+
+ if (*p == '\\')
+ pstrcpy(mget_mask,p);
+ else
+ pstrcat(mget_mask,p);
+ do_list(mget_mask, attribute,do_mget,False,True);
+ }
+
+ if (!*mget_mask) {
+ pstrcpy(mget_mask,cur_dir);
+ if(mget_mask[strlen(mget_mask)-1]!='\\')
+ pstrcat(mget_mask,"\\");
+ pstrcat(mget_mask,"*");
+ do_list(mget_mask, attribute,do_mget,False,True);
+ }
+
+ return 0;
}
+
/****************************************************************************
make a directory of name "name"
****************************************************************************/
static BOOL do_mkdir(char *name)
{
- char *p;
- char *inbuf,*outbuf;
-
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return False;
- }
-
- bzero(outbuf,smb_size);
- set_message(outbuf,0,2 + strlen(name),True);
-
- CVAL(outbuf,smb_com) = SMBmkdir;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ if (!cli_mkdir(cli, name)) {
+ d_printf("%s making remote directory %s\n",
+ cli_errstr(cli),name);
+ return(False);
+ }
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,name);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s making remote directory %s\n",
- smb_errstr(inbuf),CNV_LANG(name)));
+ return(True);
+}
- free(inbuf);free(outbuf);
- return(False);
- }
+/****************************************************************************
+show 8.3 name of a file
+****************************************************************************/
+static BOOL do_altname(char *name)
+{
+ fstring altname;
+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+ d_printf("%s getting alt name for %s\n",
+ cli_errstr(cli),name);
+ return(False);
+ }
+ d_printf("%s\n", altname);
- free(inbuf);free(outbuf);
- return(True);
+ return(True);
}
/****************************************************************************
- make a directory
- ****************************************************************************/
-static void cmd_mkdir(char *inbuf,char *outbuf)
+ Exit client.
+****************************************************************************/
+static int cmd_quit(void)
{
- pstring mask;
- fstring buf;
- char *p=buf;
-
- strcpy(mask,cur_dir);
-
- if (!next_token(NULL,p,NULL))
- {
- if (!recurse)
- DEBUG(0,("mkdir <dirname>\n"));
- return;
- }
- strcat(mask,p);
-
- if (recurse)
- {
- pstring ddir;
- pstring ddir2;
- *ddir2 = 0;
-
- strcpy(ddir,mask);
- trim_string(ddir,".",NULL);
- p = strtok(ddir,"/\\");
- while (p)
- {
- strcat(ddir2,p);
- if (!chkpath(ddir2,False))
- {
- do_mkdir(ddir2);
- }
- strcat(ddir2,"\\");
- p = strtok(NULL,"/\\");
- }
- }
- else
- do_mkdir(mask);
+ cli_shutdown(cli);
+ exit(0);
+ /* NOTREACHED */
+ return 0;
}
-/*******************************************************************
- write to a file using writebraw
- ********************************************************************/
-static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
+/****************************************************************************
+ make a directory
+ ****************************************************************************/
+static int cmd_mkdir(void)
{
- extern int Client;
- pstring inbuf;
-
- bzero(outbuf,smb_size);
- bzero(inbuf,smb_size);
- set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
-
- CVAL(outbuf,smb_com) = SMBwritebraw;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,n);
- SIVAL(outbuf,smb_vwv3,pos);
- SSVAL(outbuf,smb_vwv7,1);
-
- send_smb(Client,outbuf);
+ pstring mask;
+ fstring buf;
+ char *p=buf;
- if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
- return(0);
-
- _smb_setlen(buf-4,n); /* HACK! XXXX */
+ pstrcpy(mask,cur_dir);
- if (write_socket(Client,buf-4,n+4) != n+4)
- return(0);
+ if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
+ if (!recurse)
+ d_printf("mkdir <dirname>\n");
+ return 1;
+ }
+ pstrcat(mask,p);
- if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(0,("Error writing remote file (2)\n"));
- return(0);
- }
- return(SVAL(inbuf,smb_vwv0));
+ if (recurse) {
+ pstring ddir;
+ pstring ddir2;
+ *ddir2 = 0;
+
+ pstrcpy(ddir,mask);
+ trim_string(ddir,".",NULL);
+ p = strtok(ddir,"/\\");
+ while (p) {
+ pstrcat(ddir2,p);
+ if (!cli_chkpath(cli, ddir2)) {
+ do_mkdir(ddir2);
+ }
+ pstrcat(ddir2,"\\");
+ p = strtok(NULL,"/\\");
+ }
+ } else {
+ do_mkdir(mask);
+ }
+
+ return 0;
}
-
-/*******************************************************************
- write to a file
- ********************************************************************/
-static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
+/****************************************************************************
+ show alt name
+ ****************************************************************************/
+static int cmd_altname(void)
{
- pstring inbuf;
-
- if (writebraw_supported && n > (max_xmit-200))
- return(smb_writeraw(outbuf,fnum,pos,buf,n));
-
- bzero(outbuf,smb_size);
- bzero(inbuf,smb_size);
- set_message(outbuf,5,n + 3,True);
-
- CVAL(outbuf,smb_com) = SMBwrite;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,n);
- SIVAL(outbuf,smb_vwv2,pos);
- SSVAL(outbuf,smb_vwv4,0);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,n);
+ pstring name;
+ fstring buf;
+ char *p=buf;
+
+ pstrcpy(name,cur_dir);
- memcpy(smb_buf(outbuf)+3,buf,n);
+ if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
+ d_printf("altname <file>\n");
+ return 1;
+ }
+ pstrcat(name,p);
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ do_altname(name);
- if (CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
- return(0);
- }
- return(SVAL(inbuf,smb_vwv0));
+ return 0;
}
-
/****************************************************************************
put a single file
****************************************************************************/
-static void do_put(char *rname,char *lname,file_info *finfo)
-{
- int fnum;
- FILE *f;
- int nread=0;
- char *p;
- char *inbuf,*outbuf;
- time_t close_time = finfo->mtime;
- char *buf=NULL;
- static int maxwrite=0;
-
- struct timeval tp_start;
- GetTimeOfDay(&tp_start);
-
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return;
- }
-
- bzero(outbuf,smb_size);
- set_message(outbuf,3,2 + strlen(rname),True);
-
- if (finfo->mtime == 0 || finfo->mtime == -1)
- finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
-
- CVAL(outbuf,smb_com) = SMBcreate;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,finfo->mode);
- put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,rname);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
+static int do_put(char *rname,char *lname)
+{
+ int fnum;
+ XFILE *f;
+ int nread=0;
+ char *buf=NULL;
+ int maxwrite=io_bufsize;
+ int rc = 0;
+
+ struct timeval tp_start;
+ GetTimeOfDay(&tp_start);
- free(inbuf);free(outbuf);if (buf) free(buf);
- return;
- }
+ fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+
+ if (fnum == -1) {
+ d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
+ return 1;
+ }
- f = fopen(lname,"r");
+ /* allow files to be piped into smbclient
+ jdblair 24.jun.98 */
+ if (!strcmp(lname, "-")) {
+ f = x_stdin;
+ /* size of file is not known */
+ } else {
+ f = x_fopen(lname,O_RDONLY, 0);
+ }
- if (!f)
- {
- DEBUG(0,("Error opening local file %s\n",lname));
- free(inbuf);free(outbuf);
- return;
- }
+ if (!f) {
+ d_printf("Error opening local file %s\n",lname);
+ return 1;
+ }
- fnum = SVAL(inbuf,smb_vwv0);
- if (finfo->size < 0)
- finfo->size = file_size(lname);
-
- DEBUG(1,("putting file %s of size %d bytes as %s ",lname,finfo->size,CNV_LANG(rname)));
+ DEBUG(1,("putting file %s as %s ",lname,
+ rname));
- if (!maxwrite)
- maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
+ buf = (char *)malloc(maxwrite);
+ if (!buf) {
+ d_printf("ERROR: Not enough memory!\n");
+ return 1;
+ }
+ while (!x_feof(f)) {
+ int n = maxwrite;
+ int ret;
- while (nread < finfo->size)
- {
- int n = maxwrite;
- int ret;
+ if ((n = readfile(buf,n,f)) < 1) {
+ if((n == 0) && x_feof(f))
+ break; /* Empty local file. */
- n = MIN(n,finfo->size - nread);
+ d_printf("Error reading local file: %s\n", strerror(errno));
+ rc = 1;
+ break;
+ }
- buf = (char *)Realloc(buf,n+4);
-
- fseek(f,nread,SEEK_SET);
- if ((n = readfile(buf+4,1,n,f)) < 1)
- {
- DEBUG(0,("Error reading local file\n"));
- break;
- }
+ ret = cli_write(cli, fnum, 0, buf, nread, n);
- ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
+ if (n != ret) {
+ d_printf("Error writing file: %s\n", cli_errstr(cli));
+ rc = 1;
+ break;
+ }
- if (n != ret) {
- if (!maxwrite) {
- DEBUG(0,("Error writing file\n"));
- break;
- } else {
- maxwrite /= 2;
- continue;
+ nread += n;
}
- }
-
- nread += n;
- }
-
+ if (!cli_close(cli, fnum)) {
+ d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
+ x_fclose(f);
+ SAFE_FREE(buf);
+ return 1;
+ }
- bzero(outbuf,smb_size);
- set_message(outbuf,3,0,True);
- CVAL(outbuf,smb_com) = SMBclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- put_dos_date3(outbuf,smb_vwv1,close_time);
+
+ x_fclose(f);
+ SAFE_FREE(buf);
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
- fclose(f);
- free(inbuf);free(outbuf);
- if (buf) free(buf);
- return;
- }
+ {
+ struct timeval tp_end;
+ int this_time;
+
+ GetTimeOfDay(&tp_end);
+ this_time =
+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
+ put_total_time_ms += this_time;
+ put_total_size += nread;
+
+ DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
+ nread / (1.024*this_time + 1.0e-4),
+ put_total_size / (1.024*put_total_time_ms)));
+ }
-
- fclose(f);
- free(inbuf);free(outbuf);
- if (buf) free(buf);
-
- {
- struct timeval tp_end;
- int this_time;
-
- GetTimeOfDay(&tp_end);
- this_time =
- (tp_end.tv_sec - tp_start.tv_sec)*1000 +
- (tp_end.tv_usec - tp_start.tv_usec)/1000;
- put_total_time_ms += this_time;
- put_total_size += finfo->size;
-
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
- finfo->size / (1.024*this_time + 1.0e-4),
- put_total_size / (1.024*put_total_time_ms)));
- }
-}
+ if (f == x_stdin) {
+ cli_shutdown(cli);
+ exit(0);
+ }
+
+ return rc;
+}
/****************************************************************************
put a file
****************************************************************************/
-static void cmd_put(void)
+static int cmd_put(void)
{
- pstring lname;
- pstring rname;
- fstring buf;
- char *p=buf;
- file_info finfo;
- finfo = def_finfo;
-
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
-
+ pstring lname;
+ pstring rname;
+ fstring buf;
+ char *p=buf;
+
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,"\\");
- if (!next_token(NULL,p,NULL))
- {
- DEBUG(0,("put <filename>\n"));
- return;
- }
- strcpy(lname,p);
+ if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
+ d_printf("put <filename>\n");
+ return 1;
+ }
+ pstrcpy(lname,p);
- if (next_token(NULL,p,NULL))
- strcat(rname,p);
- else
- strcat(rname,lname);
-
- dos_clean_name(rname);
-
- {
- struct stat st;
- if (!file_exist(lname,&st)) {
- DEBUG(0,("%s does not exist\n",lname));
- return;
- }
- finfo.mtime = st.st_mtime;
- }
-
- do_put(rname,lname,&finfo);
+ if (next_token_nr(NULL,p,NULL,sizeof(buf)))
+ pstrcat(rname,p);
+ else
+ pstrcat(rname,lname);
+
+ dos_clean_name(rname);
+
+ {
+ SMB_STRUCT_STAT st;
+ /* allow '-' to represent stdin
+ jdblair, 24.jun.98 */
+ if (!file_exist(lname,&st) &&
+ (strcmp(lname,"-"))) {
+ d_printf("%s does not exist\n",lname);
+ return 1;
+ }
+ }
+
+ return do_put(rname,lname);
+}
+
+/*************************************
+ File list structure
+*************************************/
+
+static struct file_list {
+ struct file_list *prev, *next;
+ char *file_path;
+ BOOL isdir;
+} *file_list;
+
+/****************************************************************************
+ Free a file_list structure
+****************************************************************************/
+
+static void free_file_list (struct file_list * list)
+{
+ struct file_list *tmp;
+
+ while (list)
+ {
+ tmp = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(tmp->file_path);
+ SAFE_FREE(tmp);
+ }
}
/****************************************************************************
seek in a directory/file list until you get something that doesn't start with
the specified name
****************************************************************************/
-static BOOL seek_list(FILE *f,char *name)
+static BOOL seek_list(struct file_list *list, char *name)
{
- pstring s;
- while (!feof(f))
- {
- if (fscanf(f,"%s",s) != 1) return(False);
- trim_string(s,"./",NULL);
- if (strncmp(s,name,strlen(name)) != 0)
- {
- strcpy(name,s);
- return(True);
+ while (list) {
+ trim_string(list->file_path,"./","\n");
+ if (strncmp(list->file_path, name, strlen(name)) != 0) {
+ return(True);
+ }
+ list = list->next;
}
- }
- return(False);
+ return(False);
}
-
/****************************************************************************
set the file selection mask
****************************************************************************/
-static void cmd_select(void)
+static int cmd_select(void)
{
- strcpy(fileselection,"");
- next_token(NULL,fileselection,NULL);
+ pstrcpy(fileselection,"");
+ next_token_nr(NULL,fileselection,NULL,sizeof(fileselection));
+
+ return 0;
}
+/****************************************************************************
+ Recursive file matching function act as find
+ match must be always set to True when calling this function
+****************************************************************************/
+static int file_find(struct file_list **list, const char *directory,
+ const char *expression, BOOL match)
+{
+ DIR *dir;
+ struct file_list *entry;
+ struct stat statbuf;
+ int ret;
+ char *path;
+ BOOL isdir;
+ char *dname;
+
+ dir = opendir(directory);
+ if (!dir) return -1;
+
+ while ((dname = readdirname(dir))) {
+ if (!strcmp("..", dname)) continue;
+ if (!strcmp(".", dname)) continue;
+
+ if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
+ continue;
+ }
+
+ isdir = False;
+ if (!match || !gen_fnmatch(expression, dname)) {
+ if (recurse) {
+ ret = stat(path, &statbuf);
+ if (ret == 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ isdir = True;
+ ret = file_find(list, path, expression, False);
+ }
+ } else {
+ d_printf("file_find: cannot stat file %s\n", path);
+ }
+
+ if (ret == -1) {
+ SAFE_FREE(path);
+ closedir(dir);
+ return -1;
+ }
+ }
+ entry = (struct file_list *) malloc(sizeof (struct file_list));
+ if (!entry) {
+ d_printf("Out of memory in file_find\n");
+ closedir(dir);
+ return -1;
+ }
+ entry->file_path = path;
+ entry->isdir = isdir;
+ DLIST_ADD(*list, entry);
+ } else {
+ SAFE_FREE(path);
+ }
+ }
+
+ closedir(dir);
+ return 0;
+}
/****************************************************************************
mput some files
****************************************************************************/
-static void cmd_mput(void)
+static int cmd_mput(void)
{
- pstring lname;
- pstring rname;
- file_info finfo;
- fstring buf;
- char *p=buf;
-
- finfo = def_finfo;
-
-
- while (next_token(NULL,p,NULL))
- {
- struct stat st;
- pstring cmd;
- pstring tmpname;
- FILE *f;
-
- sprintf(tmpname,"/tmp/ls.smb.%d",(int)getpid());
- if (recurse)
- sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
- else
- sprintf(cmd,"/bin/ls %s > %s",p,tmpname);
- system(cmd);
-
- f = fopen(tmpname,"r");
- if (!f) continue;
-
- while (!feof(f))
- {
- pstring quest;
-
- if (fscanf(f,"%s",lname) != 1) break;
- trim_string(lname,"./",NULL);
-
- again1:
+ fstring buf;
+ char *p=buf;
+
+ while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
+ int ret;
+ struct file_list *temp_list;
+ char *quest, *lname, *rname;
+
+ file_list = NULL;
- /* check if it's a directory */
- if (directory_exist(lname,&st))
- {
- if (!recurse) continue;
- sprintf(quest,"Put directory %s? ",lname);
- if (prompt && !yesno(quest))
- {
- strcat(lname,"/");
- if (!seek_list(f,lname))
- break;
- goto again1;
+ ret = file_find(&file_list, ".", p, True);
+ if (ret) {
+ free_file_list(file_list);
+ continue;
}
-
- strcpy(rname,cur_dir);
- strcat(rname,lname);
- if (!do_mkdir(rname))
- {
- strcat(lname,"/");
- if (!seek_list(f,lname))
- break;
- goto again1;
+
+ quest = NULL;
+ lname = NULL;
+ rname = NULL;
+
+ for (temp_list = file_list; temp_list;
+ temp_list = temp_list->next) {
+
+ SAFE_FREE(lname);
+ if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
+ continue;
+ trim_string(lname, "./", "/");
+
+ /* check if it's a directory */
+ if (temp_list->isdir) {
+ /* if (!recurse) continue; */
+
+ SAFE_FREE(quest);
+ asprintf(&quest, "Put directory %s? ", lname);
+ if (prompt && !yesno(quest)) { /* No */
+ /* Skip the directory */
+ lname[strlen(lname)-1] = '/';
+ if (!seek_list(temp_list, lname))
+ break;
+ } else { /* Yes */
+ SAFE_FREE(rname);
+ asprintf(&rname, "%s%s", cur_dir, lname);
+ dos_format(rname);
+ if (!cli_chkpath(cli, rname) &&
+ !do_mkdir(rname)) {
+ DEBUG (0, ("Unable to make dir, skipping..."));
+ /* Skip the directory */
+ lname[strlen(lname)-1] = '/';
+ if (!seek_list(temp_list, lname))
+ break;
+ }
+ }
+ continue;
+ } else {
+ SAFE_FREE(quest);
+ asprintf(&quest,"Put file %s? ", lname);
+ if (prompt && !yesno(quest)) /* No */
+ continue;
+
+ /* Yes */
+ SAFE_FREE(rname);
+ asprintf(&rname, "%s%s", cur_dir, lname);
+ }
+
+ dos_format(rname);
+
+ do_put(rname, lname);
}
-
- continue;
- }
- else
- {
- sprintf(quest,"Put file %s? ",lname);
- if (prompt && !yesno(quest)) continue;
-
- strcpy(rname,cur_dir);
- strcat(rname,lname);
- }
- dos_format(rname);
-
- /* null size so do_put knows to ignore it */
- finfo.size = -1;
-
- /* set the date on the file */
- finfo.mtime = st.st_mtime;
-
- do_put(rname,lname,&finfo);
+ free_file_list(file_list);
+ SAFE_FREE(quest);
+ SAFE_FREE(lname);
+ SAFE_FREE(rname);
}
- fclose(f);
- unlink(tmpname);
- }
-}
-/****************************************************************************
- cancel a print job
- ****************************************************************************/
-static void do_cancel(int job)
-{
- char *rparam = NULL;
- char *rdata = NULL;
- char *p;
- int rdrcnt,rprcnt;
- pstring param;
-
- bzero(param,sizeof(param));
-
- p = param;
- SSVAL(p,0,81); /* api number */
- p += 2;
- strcpy(p,"W");
- p = skip_string(p,1);
- strcpy(p,"");
- p = skip_string(p,1);
- SSVAL(p,0,job);
- p += 2;
-
- if (call_api(PTR_DIFF(p,param),0,
- 6,1000,
- &rprcnt,&rdrcnt,
- param,NULL,
- &rparam,&rdata))
- {
- int res = SVAL(rparam,0);
-
- if (!res)
- printf("Job %d cancelled\n",job);
- else
- printf("Error %d calcelling job %d\n",res,job);
- return;
- }
- else
- printf("Server refused cancel request\n");
-
- if (rparam) free(rparam);
- if (rdata) free(rdata);
-
- return;
+ return 0;
}
/****************************************************************************
cancel a print job
****************************************************************************/
-static void cmd_cancel(char *inbuf,char *outbuf )
+static int do_cancel(int job)
{
- fstring buf;
- int job;
-
- if (!connect_as_printer)
- {
- DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
- DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
- }
-
- if (!next_token(NULL,buf,NULL)) {
- printf("cancel <jobid> ...\n");
- return;
- }
- do {
- job = atoi(buf);
- do_cancel(job);
- } while (next_token(NULL,buf,NULL));
+ if (cli_printjob_del(cli, job)) {
+ d_printf("Job %d cancelled\n",job);
+ return 0;
+ } else {
+ d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
+ return 1;
+ }
}
/****************************************************************************
- get info on a file
+ cancel a print job
****************************************************************************/
-static void cmd_stat(char *inbuf,char *outbuf)
+static int cmd_cancel(void)
{
- fstring buf;
- pstring param;
- char *resp_data=NULL;
- char *resp_param=NULL;
- int resp_data_len = 0;
- int resp_param_len=0;
- char *p;
- uint16 setup = TRANSACT2_QPATHINFO;
-
- if (!next_token(NULL,buf,NULL)) {
- printf("stat <file>\n");
- return;
- }
-
- bzero(param,6);
- SSVAL(param,0,4); /* level */
- p = param+6;
- strcpy(p,cur_dir);
- strcat(p,buf);
-
- send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
- NULL,param,&setup,
- 0,6 + strlen(p)+1,1,
- BUFFER_SIZE,2,0);
-
- receive_trans_response(inbuf,SMBtrans2,
- &resp_data_len,&resp_param_len,
- &resp_data,&resp_param);
-
- if (resp_data) free(resp_data); resp_data = NULL;
- if (resp_param) free(resp_param); resp_param = NULL;
+ fstring buf;
+ int job;
+
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ d_printf("cancel <jobid> ...\n");
+ return 1;
+ }
+ do {
+ job = atoi(buf);
+ do_cancel(job);
+ } while (next_token_nr(NULL,buf,NULL,sizeof(buf)));
+
+ return 0;
}
/****************************************************************************
print a file
****************************************************************************/
-static void cmd_print(char *inbuf,char *outbuf )
+static int cmd_print(void)
{
- int fnum;
- FILE *f = NULL;
- uint32 nread=0;
- pstring lname;
- pstring rname;
- char *p;
-
- if (!connect_as_printer)
- {
- DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
- DEBUG(0,("Trying to print without -P may fail\n"));
- }
-
- if (!next_token(NULL,lname,NULL))
- {
- DEBUG(0,("print <filename>\n"));
- return;
- }
-
- strcpy(rname,lname);
- p = strrchr(rname,'/');
- if (p)
- {
- pstring tname;
- strcpy(tname,p+1);
- strcpy(rname,tname);
- }
-
- if ((int)strlen(rname) > 14)
- rname[14] = 0;
-
- if (strequal(lname,"-"))
- {
- f = stdin;
- strcpy(rname,"stdin");
- }
-
- dos_clean_name(rname);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,2,2 + strlen(rname),True);
-
- CVAL(outbuf,smb_com) = SMBsplopen;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0);
- SSVAL(outbuf,smb_vwv1,printmode);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,rname);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
- return;
- }
-
- if (!f)
- f = fopen(lname,"r");
- if (!f)
- {
- DEBUG(0,("Error opening local file %s\n",lname));
- return;
- }
+ pstring lname;
+ pstring rname;
+ char *p;
-
- fnum = SVAL(inbuf,smb_vwv0);
-
- DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
-
- while (!feof(f))
- {
- int n;
-
- bzero(outbuf,smb_size);
- set_message(outbuf,1,3,True);
-
- /* for some strange reason the OS/2 print server can't handle large
- packets when printing. weird */
- n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
-
- if (translation)
- n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
- else
- n = readfile(smb_buf(outbuf)+3,1,n,f);
- if (n <= 0)
- {
- DEBUG(0,("read gave %d\n",n));
- break;
+ if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) {
+ d_printf("print <filename>\n");
+ return 1;
}
- smb_setlen(outbuf,smb_len(outbuf) + n);
-
- CVAL(outbuf,smb_com) = SMBsplwr;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,n+3);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,n);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
- break;
+ pstrcpy(rname,lname);
+ p = strrchr_m(rname,'/');
+ if (p) {
+ slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid());
}
- nread += n;
- }
-
- DEBUG(2,("%d bytes printed\n",nread));
+ if (strequal(lname,"-")) {
+ slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
+ }
- bzero(outbuf,smb_size);
- set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBsplclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ return do_put(rname, lname);
+}
- SSVAL(outbuf,smb_vwv0,fnum);
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
- if (f != stdin)
- fclose(f);
- return;
- }
-
- if (f != stdin)
- fclose(f);
+/****************************************************************************
+ show a print queue entry
+****************************************************************************/
+static void queue_fn(struct print_job_info *p)
+{
+ d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
}
/****************************************************************************
-print a file
+ show a print queue
****************************************************************************/
-static void cmd_queue(char *inbuf,char *outbuf )
+static int cmd_queue(void)
{
- int count;
- char *p;
-
- bzero(outbuf,smb_size);
- set_message(outbuf,2,0,True);
-
- CVAL(outbuf,smb_com) = SMBsplretq;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
- SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
- return;
- }
-
- count = SVAL(inbuf,smb_vwv0);
- p = smb_buf(inbuf) + 3;
- if (count <= 0)
- {
- DEBUG(0,("No entries in the print queue\n"));
- return;
- }
-
- {
- char status[20];
-
- DEBUG(0,("Job Name Size Status\n"));
-
- while (count--)
- {
- switch (CVAL(p,4))
- {
- case 0x01: sprintf(status,"held or stopped"); break;
- case 0x02: sprintf(status,"printing"); break;
- case 0x03: sprintf(status,"awaiting print"); break;
- case 0x04: sprintf(status,"in intercept"); break;
- case 0x05: sprintf(status,"file had error"); break;
- case 0x06: sprintf(status,"printer error"); break;
- default: sprintf(status,"unknown"); break;
- }
-
- DEBUG(0,("%-6d %-16.16s %-9d %s\n",
- SVAL(p,5),p+12,IVAL(p,7),status));
- p += 28;
- }
- }
-
+ cli_print_queue(cli, queue_fn);
+
+ return 0;
}
-
/****************************************************************************
delete some files
****************************************************************************/
static void do_del(file_info *finfo)
{
- char *p;
- char *inbuf,*outbuf;
- pstring mask;
+ pstring mask;
- strcpy(mask,cur_dir);
- strcat(mask,finfo->name);
+ pstrcpy(mask,cur_dir);
+ pstrcat(mask,finfo->name);
- if (finfo->mode & aDIR)
- return;
+ if (finfo->mode & aDIR)
+ return;
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return;
- }
-
- bzero(outbuf,smb_size);
- set_message(outbuf,1,2 + strlen(mask),True);
-
- CVAL(outbuf,smb_com) = SMBunlink;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ if (!cli_unlink(cli, mask)) {
+ d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask);
+ }
+}
- SSVAL(outbuf,smb_vwv0,0);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,mask);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
+/****************************************************************************
+delete some files
+****************************************************************************/
+static int cmd_del(void)
+{
+ pstring mask;
+ fstring buf;
+ uint16 attribute = aSYSTEM | aHIDDEN;
- free(inbuf);free(outbuf);
-
+ if (recurse)
+ attribute |= aDIR;
+
+ pstrcpy(mask,cur_dir);
+
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ d_printf("del <filename>\n");
+ return 1;
+ }
+ pstrcat(mask,buf);
+
+ do_list(mask, attribute,do_del,False,False);
+
+ return 0;
}
/****************************************************************************
-delete some files
****************************************************************************/
-static void cmd_del(char *inbuf,char *outbuf )
+static int cmd_open(void)
{
- pstring mask;
- fstring buf;
- int attribute = aSYSTEM | aHIDDEN;
+ pstring mask;
+ fstring buf;
+
+ pstrcpy(mask,cur_dir);
+
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ d_printf("open <filename>\n");
+ return 1;
+ }
+ pstrcat(mask,buf);
- if (recurse)
- attribute |= aDIR;
-
- strcpy(mask,cur_dir);
-
- if (!next_token(NULL,buf,NULL))
- {
- DEBUG(0,("del <filename>\n"));
- return;
- }
- strcat(mask,buf);
-
- do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False);
+ cli_open(cli, mask, O_RDWR, DENY_ALL);
+
+ return 0;
}
/****************************************************************************
remove a directory
****************************************************************************/
-static void cmd_rmdir(char *inbuf,char *outbuf )
+static int cmd_rmdir(void)
{
- pstring mask;
- fstring buf;
- char *p;
+ pstring mask;
+ fstring buf;
- strcpy(mask,cur_dir);
-
- if (!next_token(NULL,buf,NULL))
- {
- DEBUG(0,("rmdir <dirname>\n"));
- return;
- }
- strcat(mask,buf);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,0,2 + strlen(mask),True);
-
- CVAL(outbuf,smb_com) = SMBrmdir;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ pstrcpy(mask,cur_dir);
+
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ d_printf("rmdir <dirname>\n");
+ return 1;
+ }
+ pstrcat(mask,buf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,mask);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
- return;
- }
-
+ if (!cli_rmdir(cli, mask)) {
+ d_printf("%s removing remote directory file %s\n",
+ cli_errstr(cli),mask);
+ }
+
+ return 0;
}
/****************************************************************************
rename some files
****************************************************************************/
-static void cmd_rename(char *inbuf,char *outbuf )
+static int cmd_rename(void)
{
- pstring src,dest;
- fstring buf,buf2;
- char *p;
-
- strcpy(src,cur_dir);
- strcpy(dest,cur_dir);
-
- if (!next_token(NULL,buf,NULL) || !next_token(NULL,buf2,NULL))
- {
- DEBUG(0,("rename <src> <dest>\n"));
- return;
- }
- strcat(src,buf);
- strcat(dest,buf2);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
-
- CVAL(outbuf,smb_com) = SMBmv;
- SSVAL(outbuf,smb_tid,cnum);
- SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,src);
- p = skip_string(p,1);
- *p++ = 4;
- strcpy(p,dest);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
- return;
- }
+ pstring src,dest;
+ fstring buf,buf2;
+ pstrcpy(src,cur_dir);
+ pstrcpy(dest,cur_dir);
+
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) ||
+ !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
+ d_printf("rename <src> <dest>\n");
+ return 1;
+ }
+
+ pstrcat(src,buf);
+ pstrcat(dest,buf2);
+
+ if (!cli_rename(cli, src, dest)) {
+ d_printf("%s renaming files\n",cli_errstr(cli));
+ return 1;
+ }
+
+ return 0;
}
/****************************************************************************
toggle the prompt flag
****************************************************************************/
-static void cmd_prompt(void)
+static int cmd_prompt(void)
{
- prompt = !prompt;
- DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
+ prompt = !prompt;
+ DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
+
+ return 1;
}
/****************************************************************************
set the newer than time
****************************************************************************/
-static void cmd_newer(void)
+static int cmd_newer(void)
{
- fstring buf;
- BOOL ok;
- struct stat sbuf;
-
- ok = next_token(NULL,buf,NULL);
- if (ok && (sys_stat(buf,&sbuf) == 0))
- {
- newer_than = sbuf.st_mtime;
- DEBUG(1,("Getting files newer than %s",
- asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
- }
- else
- newer_than = 0;
-
- if (ok && newer_than == 0)
- DEBUG(0,("Error setting newer-than time\n"));
+ fstring buf;
+ BOOL ok;
+ SMB_STRUCT_STAT sbuf;
+
+ ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
+ if (ok && (sys_stat(buf,&sbuf) == 0)) {
+ newer_than = sbuf.st_mtime;
+ DEBUG(1,("Getting files newer than %s",
+ asctime(LocalTime(&newer_than))));
+ } else {
+ newer_than = 0;
+ }
+
+ if (ok && newer_than == 0) {
+ d_printf("Error setting newer-than time\n");
+ return 1;
+ }
+
+ return 0;
}
/****************************************************************************
set the archive level
****************************************************************************/
-static void cmd_archive(void)
+static int cmd_archive(void)
{
- fstring buf;
+ fstring buf;
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ archive_level = atoi(buf);
+ } else
+ d_printf("Archive level is %d\n",archive_level);
- if (next_token(NULL,buf,NULL)) {
- archive_level = atoi(buf);
- } else
- DEBUG(0,("Archive level is %d\n",archive_level));
+ return 0;
}
/****************************************************************************
toggle the lowercaseflag
****************************************************************************/
-static void cmd_lowercase(void)
+static int cmd_lowercase(void)
{
- lowercase = !lowercase;
- DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
+ lowercase = !lowercase;
+ DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
+
+ return 0;
}
@@ -2707,1020 +1656,211 @@ static void cmd_lowercase(void)
/****************************************************************************
toggle the recurse flag
****************************************************************************/
-static void cmd_recurse(void)
+static int cmd_recurse(void)
{
- recurse = !recurse;
- DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
-}
+ recurse = !recurse;
+ DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
-/****************************************************************************
-toggle the translate flag
-****************************************************************************/
-static void cmd_translate(void)
-{
- translation = !translation;
- DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
- translation?"on":"off"));
-}
-
-
-/****************************************************************************
-do a printmode command
-****************************************************************************/
-static void cmd_printmode(void)
-{
- fstring buf;
- fstring mode;
-
- if (next_token(NULL,buf,NULL))
- {
- if (strequal(buf,"text"))
- printmode = 0;
- else
- {
- if (strequal(buf,"graphics"))
- printmode = 1;
- else
- printmode = atoi(buf);
- }
- }
-
- switch(printmode)
- {
- case 0:
- strcpy(mode,"text");
- break;
- case 1:
- strcpy(mode,"graphics");
- break;
- default:
- sprintf(mode,"%d",printmode);
- break;
- }
-
- DEBUG(2,("the printmode is now %s\n",mode));
+ return 0;
}
/****************************************************************************
-do the lcd command
+toggle the translate flag
****************************************************************************/
-static void cmd_lcd(void)
+static int cmd_translate(void)
{
- fstring buf;
- pstring d;
+ translation = !translation;
+ DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
+ translation?"on":"off"));
- if (next_token(NULL,buf,NULL))
- sys_chdir(buf);
- DEBUG(2,("the local directory is now %s\n",GetWd(d)));
-}
-
-
-/****************************************************************************
-send a session request
-****************************************************************************/
-static BOOL send_session_request(char *inbuf,char *outbuf)
-{
- fstring dest;
- char *p;
- int len = 4;
- /* send a session request (RFC 8002) */
-
- strcpy(dest,desthost);
- p = strchr(dest,'.');
- if (p) *p = 0;
-
- /* put in the destination name */
- p = outbuf+len;
- name_mangle(dest,p,name_type);
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(myname,p,0);
- len += name_len(p);
-
- /* setup the packet length */
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(Client,outbuf);
- DEBUG(5,("Sent session request\n"));
-
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,0) == 0x84) /* C. Hoch 9/14/95 Start */
- {
- /* For information, here is the response structure.
- * We do the byte-twiddling to for portability.
- struct RetargetResponse{
- unsigned char type;
- unsigned char flags;
- int16 length;
- int32 ip_addr;
- int16 port;
- };
- */
- extern int Client;
- int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
- /* SESSION RETARGET */
- putip((char *)&dest_ip,inbuf+4);
-
- close_sockets();
- Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (Client == -1)
- return False;
-
- DEBUG(3,("Retargeted\n"));
-
- set_socket_options(Client,user_socket_options);
-
- /* Try again */
- return send_session_request(inbuf,outbuf);
- } /* C. Hoch 9/14/95 End */
-
-
- if (CVAL(inbuf,0) != 0x82)
- {
- int ecode = CVAL(inbuf,4);
- DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
- CVAL(inbuf,0),ecode,myname,desthost));
- switch (ecode)
- {
- case 0x80:
- DEBUG(0,("Not listening on called name\n"));
- DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
- DEBUG(0,("You may find the -I option useful for this\n"));
- break;
- case 0x81:
- DEBUG(0,("Not listening for calling name\n"));
- DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
- DEBUG(0,("You may find the -n option useful for this\n"));
- break;
- case 0x82:
- DEBUG(0,("Called name not present\n"));
- DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
- DEBUG(0,("You may find the -I option useful for this\n"));
- break;
- case 0x83:
- DEBUG(0,("Called name present, but insufficient resources\n"));
- DEBUG(0,("Perhaps you should try again later?\n"));
- break;
- default:
- DEBUG(0,("Unspecified error 0x%X\n",ecode));
- DEBUG(0,("Your server software is being unfriendly\n"));
- break;
- }
- return(False);
- }
- return(True);
+ return 0;
}
/****************************************************************************
-send a login command
+do a printmode command
****************************************************************************/
-static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup)
-{
- BOOL was_null = (!inbuf && !outbuf);
- int sesskey=0;
- time_t servertime = 0;
- extern int serverzone;
- int sec_mode=0;
- int crypt_len;
- int max_vcs=0;
- struct {
- int prot;
- char *name;
- }
- prots[] =
- {
- {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
- {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
- {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
- {PROTOCOL_LANMAN1,"LANMAN1.0"},
- {PROTOCOL_LANMAN2,"LM1.2X002"},
- {PROTOCOL_LANMAN2,"Samba"},
- {PROTOCOL_NT1,"NT LM 0.12"},
- {PROTOCOL_NT1,"NT LANMAN 1.0"},
- {-1,NULL}
- };
- char *pass = NULL;
- pstring dev;
- char *p;
- int numprots;
-
- if (was_null)
- {
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- }
-
-#if AJT
- if (strstr(service,"IPC$")) connect_as_ipc = True;
-#endif
-
- strcpy(dev,"A:");
- if (connect_as_printer)
- strcpy(dev,"LPT1:");
- if (connect_as_ipc)
- strcpy(dev,"IPC");
-
-
- if (start_session && !send_session_request(inbuf,outbuf))
- {
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
- bzero(outbuf,smb_size);
-
- /* setup the protocol strings */
- {
- int plength;
-
- for (plength=0,numprots=0;
- prots[numprots].name && prots[numprots].prot<=max_protocol;
- numprots++)
- plength += strlen(prots[numprots].name)+2;
-
- set_message(outbuf,0,plength,True);
-
- p = smb_buf(outbuf);
- for (numprots=0;
- prots[numprots].name && prots[numprots].prot<=max_protocol;
- numprots++)
- {
- *p++ = 2;
- strcpy(p,prots[numprots].name);
- p += strlen(p) + 1;
- }
- }
-
- CVAL(outbuf,smb_com) = SMBnegprot;
- setup_pkt(outbuf);
-
- CVAL(smb_buf(outbuf),0) = 2;
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- show_msg(inbuf);
-
- if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
- {
- DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
- myname,desthost,smb_errstr(inbuf)));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
- Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
-
-
- if (Protocol < PROTOCOL_NT1) {
- sec_mode = SVAL(inbuf,smb_vwv1);
- max_xmit = SVAL(inbuf,smb_vwv2);
- sesskey = IVAL(inbuf,smb_vwv6);
- serverzone = SVALS(inbuf,smb_vwv10)*60;
- /* this time is converted to GMT by make_unix_date */
- servertime = make_unix_date(inbuf+smb_vwv8);
- if (Protocol >= PROTOCOL_COREPLUS) {
- readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
- writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
- }
- crypt_len = smb_buflen(inbuf);
- memcpy(cryptkey,smb_buf(inbuf),8);
- DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
- max_vcs = SVAL(inbuf,smb_vwv4);
- DEBUG(3,("max vcs %d\n",max_vcs));
- DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
- } else {
- /* NT protocol */
- sec_mode = CVAL(inbuf,smb_vwv1);
- max_xmit = IVAL(inbuf,smb_vwv3+1);
- sesskey = IVAL(inbuf,smb_vwv7+1);
- serverzone = SVALS(inbuf,smb_vwv15+1)*60;
- /* this time arrives in real GMT */
- servertime = interpret_long_date(inbuf+smb_vwv11+1);
- crypt_len = CVAL(inbuf,smb_vwv16+1);
- memcpy(cryptkey,smb_buf(inbuf),8);
- if (IVAL(inbuf,smb_vwv9+1) & 1)
- readbraw_supported = writebraw_supported = True;
- DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
- max_vcs = SVAL(inbuf,smb_vwv2+1);
- DEBUG(3,("max vcs %d\n",max_vcs));
- DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
- DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
- }
-
- DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
- DEBUG(3,("max xmt %d\n",max_xmit));
- DEBUG(3,("Got %d byte crypt key\n",crypt_len));
- DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
-
- doencrypt = ((sec_mode & 2) != 0);
-
- if (servertime) {
- static BOOL done_time = False;
- if (!done_time) {
- DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
- asctime(LocalTime(&servertime,GMT_TO_LOCAL)),
- -(double)(serverzone/3600.0)));
- done_time = True;
- }
- }
-
- get_pass:
-
- if (got_pass)
- pass = password;
- else
- pass = (char *)getpass("Password: ");
-
- if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
- {
- fstring pword;
- int passlen = strlen(pass)+1;
- strcpy(pword,pass);
-
-#ifdef SMB_PASSWD
- if (doencrypt && *pass) {
- DEBUG(3,("Using encrypted passwords\n"));
- passlen = 24;
- SMBencrypt(pass,cryptkey,pword);
- }
-#else
- doencrypt = False;
-#endif
-
- /* if in share level security then don't send a password now */
- if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;}
-
- /* send a session setup command */
- bzero(outbuf,smb_size);
-
- if (Protocol < PROTOCOL_NT1) {
- set_message(outbuf,10,1 + strlen(username) + passlen,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
- setup_pkt(outbuf);
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,max_xmit);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,max_vcs-1);
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,passlen);
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen);
- p += passlen;
- strcpy(p,username);
- } else {
- if (!doencrypt) passlen--;
- /* for Win95 */
- set_message(outbuf,13,0,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
- setup_pkt(outbuf);
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,getpid());
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,passlen);
- SSVAL(outbuf,smb_vwv8,0);
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
- strcpy(p,username);p = skip_string(p,1);
- strcpy(p,workgroup);p = skip_string(p,1);
- strcpy(p,"Unix");p = skip_string(p,1);
- strcpy(p,"Samba");p = skip_string(p,1);
- set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- show_msg(inbuf);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- if (! *pass &&
- ((CVAL(inbuf,smb_rcls) == ERRDOS &&
- SVAL(inbuf,smb_err) == ERRnoaccess) ||
- (CVAL(inbuf,smb_rcls) == ERRSRV &&
- SVAL(inbuf,smb_err) == ERRbadpw)))
- {
- got_pass = False;
- DEBUG(3,("resending login\n"));
- goto get_pass;
- }
-
- DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n",
- username,myname,desthost,smb_errstr(inbuf)));
- DEBUG(0,("You might find the -U, -W or -n options useful\n"));
- DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
- DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
- if (Protocol >= PROTOCOL_NT1) {
- char *domain,*os,*lanman;
- p = smb_buf(inbuf);
- os = p;
- lanman = skip_string(os,1);
- domain = skip_string(lanman,1);
- if (*domain || *os || *lanman)
- DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
- }
-
- /* use the returned uid from now on */
- if (SVAL(inbuf,smb_uid) != uid)
- DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
- SVAL(inbuf,smb_uid),uid));
- uid = SVAL(inbuf,smb_uid);
- }
-
- /* now we've got a connection - send a tcon message */
- bzero(outbuf,smb_size);
-
- if (strncmp(service,"\\\\",2) != 0)
- {
- DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
- DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
- }
-
-
- again2:
-
- {
- int passlen = strlen(pass)+1;
- fstring pword;
- strcpy(pword,pass);
-
-#ifdef SMB_PASSWD
- if (doencrypt && *pass) {
- passlen=24;
- SMBencrypt(pass,cryptkey,pword);
- }
-#endif
-
- /* if in user level security then don't send a password now */
- if ((sec_mode & 1)) {
- strcpy(pword, ""); passlen=1;
- }
-
- set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,passlen);
-
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen);
- p += passlen;
- strcpy(p,service);
- p = skip_string(p,1);
- strcpy(p,dev);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- /* trying again with a blank password */
- if (CVAL(inbuf,smb_rcls) != 0 &&
- (int)strlen(pass) > 0 &&
- !doencrypt &&
- Protocol >= PROTOCOL_LANMAN1)
- {
- DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
- strcpy(pass,"");
- goto again2;
- }
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
- DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
- DEBUG(0,("Some servers insist that these be in uppercase\n"));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
+static int cmd_printmode(void)
+{
+ fstring buf;
+ fstring mode;
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ if (strequal(buf,"text")) {
+ printmode = 0;
+ } else {
+ if (strequal(buf,"graphics"))
+ printmode = 1;
+ else
+ printmode = atoi(buf);
+ }
}
- return(False);
- }
-
- max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
- if (max_xmit <= 0)
- max_xmit = BUFFER_SIZE - 4;
-
- cnum = SVAL(inbuf,smb_tid);
-
- DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
+ switch(printmode)
+ {
+ case 0:
+ fstrcpy(mode,"text");
+ break;
+ case 1:
+ fstrcpy(mode,"graphics");
+ break;
+ default:
+ slprintf(mode,sizeof(mode)-1,"%d",printmode);
+ break;
+ }
+
+ DEBUG(2,("the printmode is now %s\n",mode));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return True;
+ return 0;
}
-
/****************************************************************************
-send a logout command
+do the lcd command
****************************************************************************/
-static void send_logout(void )
+static int cmd_lcd(void)
{
- pstring inbuf,outbuf;
-
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBtdis;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,SHORT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
- }
+ fstring buf;
+ pstring d;
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
+ chdir(buf);
+ DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
-
-#ifdef STATS
- stats_report();
-#endif
- exit(0);
+ return 0;
}
-
-
/****************************************************************************
-call a remote api
+list a share name
****************************************************************************/
-static BOOL call_api(int prcnt,int drcnt,
- int mprcnt,int mdrcnt,
- int *rprcnt,int *rdrcnt,
- char *param,char *data,
- char **rparam,char **rdata)
+static void browse_fn(const char *name, uint32 m,
+ const char *comment, void *state)
{
- static char *inbuf=NULL;
- static char *outbuf=NULL;
-
- if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ fstring typestr;
- send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
- data,param,NULL,
- drcnt,prcnt,0,
- mdrcnt,mprcnt,0);
+ *typestr=0;
- return (receive_trans_response(inbuf,SMBtrans,
- rdrcnt,rprcnt,
- rdata,rparam));
+ switch (m)
+ {
+ case STYPE_DISKTREE:
+ fstrcpy(typestr,"Disk"); break;
+ case STYPE_PRINTQ:
+ fstrcpy(typestr,"Printer"); break;
+ case STYPE_DEVICE:
+ fstrcpy(typestr,"Device"); break;
+ case STYPE_IPC:
+ fstrcpy(typestr,"IPC"); break;
+ }
+ d_printf("\t%-15.15s%-10.10s%s\n",
+ name,typestr,comment);
}
-/****************************************************************************
- send a SMB trans or trans2 request
- ****************************************************************************/
-static BOOL send_trans_request(char *outbuf,int trans,
- char *name,int fid,int flags,
- char *data,char *param,uint16 *setup,
- int ldata,int lparam,int lsetup,
- int mdata,int mparam,int msetup)
-{
- int i;
- int this_ldata,this_lparam;
- int tot_data=0,tot_param=0;
- char *outdata,*outparam;
- pstring inbuf;
- char *p;
-
- this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
- this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
-
- bzero(outbuf,smb_size);
- set_message(outbuf,14+lsetup,0,True);
- CVAL(outbuf,smb_com) = trans;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
- outdata = outparam+this_lparam;
-
- /* primary request */
- SSVAL(outbuf,smb_tpscnt,lparam); /* tpscnt */
- SSVAL(outbuf,smb_tdscnt,ldata); /* tdscnt */
- SSVAL(outbuf,smb_mprcnt,mparam); /* mprcnt */
- SSVAL(outbuf,smb_mdrcnt,mdata); /* mdrcnt */
- SCVAL(outbuf,smb_msrcnt,msetup); /* msrcnt */
- SSVAL(outbuf,smb_flags,flags); /* flags */
- SIVAL(outbuf,smb_timeout,0); /* timeout */
- SSVAL(outbuf,smb_pscnt,this_lparam); /* pscnt */
- SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
- SSVAL(outbuf,smb_dscnt,this_ldata); /* dscnt */
- SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
- SCVAL(outbuf,smb_suwcnt,lsetup); /* suwcnt */
- for (i=0;i<lsetup;i++) /* setup[] */
- SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
- p = smb_buf(outbuf);
- if (trans==SMBtrans)
- strcpy(p,name); /* name[] */
- else
- {
- *p++ = 0; /* put in a null smb_name */
- *p++ = 'D'; *p++ = ' '; /* this was added because OS/2 does it */
- }
- if (this_lparam) /* param[] */
- memcpy(outparam,param,this_lparam);
- if (this_ldata) /* data[] */
- memcpy(outdata,data,this_ldata);
- set_message(outbuf,14+lsetup, /* wcnt, bcc */
- PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
-
- show_msg(outbuf);
- send_smb(Client,outbuf);
-
- if (this_ldata < ldata || this_lparam < lparam)
- {
- /* receive interim response */
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s request failed (%s)\n",
- trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
- return(False);
- }
-
- tot_data = this_ldata;
- tot_param = this_lparam;
-
- while (tot_data < ldata || tot_param < lparam)
- {
- this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
- this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
-
- set_message(outbuf,trans==SMBtrans?8:9,0,True);
- CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
-
- outparam = smb_buf(outbuf);
- outdata = outparam+this_lparam;
-
- /* secondary request */
- SSVAL(outbuf,smb_tpscnt,lparam); /* tpscnt */
- SSVAL(outbuf,smb_tdscnt,ldata); /* tdscnt */
- SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
- SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
- SSVAL(outbuf,smb_spsdisp,tot_param); /* psdisp */
- SSVAL(outbuf,smb_sdscnt,this_ldata); /* dscnt */
- SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
- SSVAL(outbuf,smb_sdsdisp,tot_data); /* dsdisp */
- if (trans==SMBtrans2)
- SSVAL(outbuf,smb_sfid,fid); /* fid */
- if (this_lparam) /* param[] */
- memcpy(outparam,param,this_lparam);
- if (this_ldata) /* data[] */
- memcpy(outdata,data,this_ldata);
- set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
- PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
-
- show_msg(outbuf);
- send_smb(Client,outbuf);
-
- tot_data += this_ldata;
- tot_param += this_lparam;
- }
- }
-
- return(True);
-}
/****************************************************************************
try and browse available connections on a host
****************************************************************************/
static BOOL browse_host(BOOL sort)
{
-#ifdef NOSTRCASECMP
-#define strcasecmp StrCaseCmp
-#endif
- extern int strcasecmp();
-
- char *rparam = NULL;
- char *rdata = NULL;
- char *p;
- int rdrcnt,rprcnt;
- pstring param;
- int count = -1;
-
- /* now send a SMBtrans command with api RNetShareEnum */
- p = param;
- SSVAL(p,0,0); /* api number */
- p += 2;
- strcpy(p,"WrLeh");
- p = skip_string(p,1);
- strcpy(p,"B13BWz");
- p = skip_string(p,1);
- SSVAL(p,0,1);
- SSVAL(p,2,BUFFER_SIZE);
- p += 4;
-
- if (call_api(PTR_DIFF(p,param),0,
- 1024,BUFFER_SIZE,
- &rprcnt,&rdrcnt,
- param,NULL,
- &rparam,&rdata))
- {
- int res = SVAL(rparam,0);
- int converter=SVAL(rparam,2);
- int i;
- BOOL long_share_name=False;
-
- if (res == 0)
- {
- count=SVAL(rparam,4);
- p = rdata;
-
- if (count > 0)
- {
- printf("\n\tSharename Type Comment\n");
- printf("\t--------- ---- -------\n");
- }
-
- if (sort)
- qsort(p,count,20,QSORT_CAST strcasecmp);
-
- for (i=0;i<count;i++)
- {
- char *sname = p;
- int type = SVAL(p,14);
- int comment_offset = IVAL(p,16) & 0xFFFF;
- fstring typestr;
- *typestr=0;
-
- switch (type)
- {
- case STYPE_DISKTREE:
- strcpy(typestr,"Disk"); break;
- case STYPE_PRINTQ:
- strcpy(typestr,"Printer"); break;
- case STYPE_DEVICE:
- strcpy(typestr,"Device"); break;
- case STYPE_IPC:
- strcpy(typestr,"IPC"); break;
- }
+ int ret;
- printf("\t%-15.15s%-10.10s%s\n",
- sname,
- typestr,
- comment_offset?rdata+comment_offset-converter:"");
-
- if (strlen(sname)>8) long_share_name=True;
-
- p += 20;
- }
-
- if (long_share_name) {
- printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
- }
- }
- }
-
- if (rparam) free(rparam);
- if (rdata) free(rdata);
+ d_printf("\n\tSharename Type Comment\n");
+ d_printf("\t--------- ---- -------\n");
- return(count>0);
-}
+ if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
+ d_printf("Error returning browse list: %s\n", cli_errstr(cli));
+ return (ret != -1);
+}
/****************************************************************************
-get some server info
+list a server name
****************************************************************************/
-static void server_info()
+static void server_fn(const char *name, uint32 m,
+ const char *comment, void *state)
{
- char *rparam = NULL;
- char *rdata = NULL;
- char *p;
- int rdrcnt,rprcnt;
- pstring param;
-
- bzero(param,sizeof(param));
-
- p = param;
- SSVAL(p,0,63); /* api number */
- p += 2;
- strcpy(p,"WrLh");
- p = skip_string(p,1);
- strcpy(p,"zzzBBzz");
- p = skip_string(p,1);
- SSVAL(p,0,10); /* level 10 */
- SSVAL(p,2,1000);
- p += 6;
-
- if (call_api(PTR_DIFF(p,param),0,
- 6,1000,
- &rprcnt,&rdrcnt,
- param,NULL,
- &rparam,&rdata))
- {
- int res = SVAL(rparam,0);
- int converter=SVAL(rparam,2);
-
- if (res == 0)
- {
- p = rdata;
-
- printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
- rdata+SVAL(p,0)-converter,
- rdata+SVAL(p,4)-converter,
- rdata+SVAL(p,8)-converter,
- rdata+SVAL(p,14)-converter);
- }
- }
-
- if (rparam) free(rparam);
- if (rdata) free(rdata);
-
- return;
+ d_printf("\t%-16.16s %s\n", name, comment);
}
-
/****************************************************************************
try and browse available connections on a host
****************************************************************************/
-static BOOL list_servers()
+static BOOL list_servers(char *wk_grp)
{
- char *rparam = NULL;
- char *rdata = NULL;
- int rdrcnt,rprcnt;
- char *p;
- pstring param;
- int uLevel = 1;
- int count = 0;
-
- /* now send a SMBtrans command with api ServerEnum? */
- p = param;
- SSVAL(p,0,0x68); /* api number */
- p += 2;
- strcpy(p,"WrLehDO");
- p = skip_string(p,1);
-
- strcpy(p,"B16BBDz");
-#if 0
- strcpy(p,getenv("XX_STR2"));
-#endif
-
- p = skip_string(p,1);
- SSVAL(p,0,uLevel);
- SSVAL(p,2,0x2000); /* buf length */
- p += 4;
-
- SIVAL(p,0,SV_TYPE_ALL);
-
- if (call_api(PTR_DIFF(p+4,param),0,
- 8,10000,
- &rprcnt,&rdrcnt,
- param,NULL,
- &rparam,&rdata))
- {
- int res = SVAL(rparam,0);
- int converter=SVAL(rparam,2);
- int i;
-
- if (res == 0) {
- char *p2 = rdata;
- count=SVAL(rparam,4);
-
- if (count > 0) {
- printf("\n\nThis machine has a browse list:\n");
- printf("\n\tServer Comment\n");
- printf("\t--------- -------\n");
- }
+ if (!cli->server_domain) return False;
- for (i=0;i<count;i++) {
- char *sname = p2;
- int comment_offset = IVAL(p2,22) & 0xFFFF;
- printf("\t%-16.16s %s\n",
- sname,
- comment_offset?rdata+comment_offset-converter:"");
-
- p2 += 26;
- }
- }
- }
-
- if (rparam) {free(rparam); rparam = NULL;}
- if (rdata) {free(rdata); rdata = NULL;}
-
- SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
-
- if (call_api(PTR_DIFF(p+4,param),0,
- 8,10000,
- &rprcnt,&rdrcnt,
- param,NULL,
- &rparam,&rdata))
- {
- int res = SVAL(rparam,0);
- int converter=SVAL(rparam,2);
- int i;
-
- if (res == 0) {
- char *p2 = rdata;
- count=SVAL(rparam,4);
-
- if (count > 0) {
- printf("\n\nThis machine has a workgroup list:\n");
- printf("\n\tWorkgroup Master\n");
- printf("\t--------- -------\n");
- }
-
- for (i=0;i<count;i++) {
- char *sname = p2;
- int comment_offset = IVAL(p2,22) & 0xFFFF;
- printf("\t%-16.16s %s\n",
- sname,
- comment_offset?rdata+comment_offset-converter:"");
-
- p2 += 26;
- }
- }
- }
+ d_printf("\n\tServer Comment\n");
+ d_printf("\t--------- -------\n");
- if (rparam) free(rparam);
- if (rdata) free(rdata);
-
- return(count>0);
-}
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn, NULL);
+ d_printf("\n\tWorkgroup Master\n");
+ d_printf("\t--------- -------\n");
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM, server_fn, NULL);
+ return True;
+}
+/* Some constants for completing filename arguments */
-void cmd_help();
+#define COMPL_NONE 0 /* No completions */
+#define COMPL_REMOTE 1 /* Complete remote filename */
+#define COMPL_LOCAL 2 /* Complete local filename */
-/* This defines the commands supported by this client */
+/* This defines the commands supported by this client.
+ * NOTE: The "!" must be the last one in the list because it's fn pointer
+ * field is NULL, and NULL in that field is used in process_tok()
+ * (below) to indicate the end of the list. crh
+ */
struct
{
char *name;
- void (*fn)();
+ int (*fn)(void);
char *description;
+ char compl_args[2]; /* Completion argument info */
} commands[] =
{
- {"ls",cmd_dir,"<mask> list the contents of the current directory"},
- {"dir",cmd_dir,"<mask> list the contents of the current directory"},
- {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
- {"cd",cmd_cd,"[directory] change/report the remote directory"},
- {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
- {"get",cmd_get,"<remote name> [local name] get a file"},
- {"mget",cmd_mget,"<mask> get all the matching files"},
- {"put",cmd_put,"<local name> [remote name] put a file"},
- {"mput",cmd_mput,"<mask> put all matching files"},
- {"rename",cmd_rename,"<src> <dest> rename some files"},
- {"more",cmd_more,"<remote name> view a remote file with your pager"},
- {"mask",cmd_select,"<mask> mask all filenames against this"},
- {"del",cmd_del,"<mask> delete all matching files"},
- {"rm",cmd_del,"<mask> delete all matching files"},
- {"mkdir",cmd_mkdir,"<directory> make a directory"},
- {"md",cmd_mkdir,"<directory> make a directory"},
- {"rmdir",cmd_rmdir,"<directory> remove a directory"},
- {"rd",cmd_rmdir,"<directory> remove a directory"},
- {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},
- {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},
- {"translate",cmd_translate,"toggle text translation for printing"},
- {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},
- {"print",cmd_print,"<file name> print a file"},
- {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
- {"queue",cmd_queue,"show the print queue"},
- {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
- {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
- {"quit",send_logout,"logoff the server"},
- {"q",send_logout,"logoff the server"},
- {"exit",send_logout,"logoff the server"},
- {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
- {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit"},
- {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
- {"blocksize",cmd_block,"blocksize <number> (default 20)" },
- {"tarmode",cmd_tarmode,
- "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
- {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
- {"help",cmd_help,"[command] give help on a command"},
- {"?",cmd_help,"[command] give help on a command"},
- {"!",NULL,"run a shell command on the local system"},
- {"",NULL,NULL}
+ {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
+ {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
+ {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+ {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
+ {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+ {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
+ {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
+ {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
+ {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
+ {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
+ {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
+ {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
+ {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
+ {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
+ {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
+ {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
+ {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
+ {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+ {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
+ {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
+ {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
+ {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
+ {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+ {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
+ {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
};
@@ -3730,805 +1870,872 @@ struct
******************************************************************/
static int process_tok(fstring tok)
{
- int i = 0, matches = 0;
- int cmd=0;
- int tok_len = strlen(tok);
-
- while (commands[i].fn != NULL)
- {
- if (strequal(commands[i].name,tok))
- {
- matches = 1;
- cmd = i;
- break;
- }
- else if (strnequal(commands[i].name, tok, tok_len+1))
- {
- matches++;
- cmd = i;
+ int i = 0, matches = 0;
+ int cmd=0;
+ int tok_len = strlen(tok);
+
+ while (commands[i].fn != NULL) {
+ if (strequal(commands[i].name,tok)) {
+ matches = 1;
+ cmd = i;
+ break;
+ } else if (strnequal(commands[i].name, tok, tok_len)) {
+ matches++;
+ cmd = i;
+ }
+ i++;
}
- i++;
- }
- if (matches == 0)
- return(-1);
- else if (matches == 1)
- return(cmd);
- else
- return(-2);
+ if (matches == 0)
+ return(-1);
+ else if (matches == 1)
+ return(cmd);
+ else
+ return(-2);
}
/****************************************************************************
help
****************************************************************************/
-void cmd_help(void)
+static int cmd_help(void)
{
- int i=0,j;
- fstring buf;
-
- if (next_token(NULL,buf,NULL))
- {
- if ((i = process_tok(buf)) >= 0)
- DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
- }
- else
- while (commands[i].description)
- {
- for (j=0; commands[i].description && (j<5); j++) {
- DEBUG(0,("%-15s",commands[i].name));
- i++;
+ int i=0,j;
+ fstring buf;
+
+ if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+ if ((i = process_tok(buf)) >= 0)
+ d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
+ } else {
+ while (commands[i].description) {
+ for (j=0; commands[i].description && (j<5); j++) {
+ d_printf("%-15s",commands[i].name);
+ i++;
+ }
+ d_printf("\n");
+ }
}
- DEBUG(0,("\n"));
- }
+ return 0;
}
/****************************************************************************
-open the client sockets
+process a -c command string
****************************************************************************/
-static BOOL open_sockets(int port )
+static int process_command_string(char *cmd)
{
- static int last_port;
- char *host;
- pstring service2;
- extern int Client;
-#ifdef USENMB
- BOOL failed = True;
-#endif
+ pstring line;
+ char *ptr;
+ int rc = 0;
- if (port == 0) port=last_port;
- last_port=port;
-
- strupper(service);
-
- if (*desthost)
- {
- host = desthost;
- }
- else
- {
- strcpy(service2,service);
- host = strtok(service2,"\\/");
- if (!host) {
- DEBUG(0,("Badly formed host name\n"));
- return(False);
- }
- strcpy(desthost,host);
- }
-
- DEBUG(3,("Opening sockets\n"));
-
- if (*myname == 0)
- {
- get_myname(myname,NULL);
- strupper(myname);
- }
-
- if (!have_ip)
- {
- struct hostent *hp;
-
- if ((hp = Get_Hostbyname(host))) {
- putip((char *)&dest_ip,(char *)hp->h_addr);
- failed = False;
- } else {
-#ifdef USENMB
- /* Try and resolve the name with the netbios server */
- int bcast;
- pstring hs;
- struct in_addr ip1, ip2;
+ while (cmd[0] != '\0') {
+ char *p;
+ fstring tok;
+ int i;
+
+ if ((p = strchr_m(cmd, ';')) == 0) {
+ strncpy(line, cmd, 999);
+ line[1000] = '\0';
+ cmd += strlen(cmd);
+ } else {
+ if (p - cmd > 999) p = cmd + 999;
+ strncpy(line, cmd, p - cmd);
+ line[p - cmd] = '\0';
+ cmd = p + 1;
+ }
+
+ /* and get the first part of the command */
+ ptr = line;
+ if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
+
+ if ((i = process_tok(tok)) >= 0) {
+ rc = commands[i].fn();
+ } else if (i == -2) {
+ d_printf("%s: command abbreviation ambiguous\n",tok);
+ } else {
+ d_printf("%s: command not found\n",tok);
+ }
+ }
- if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
- set_socket_options (bcast, "SO_BROADCAST");
+ return rc;
+}
+
+/****************************************************************************
+handle completion of commands for readline
+****************************************************************************/
+static char **completion_fn(char *text, int start, int end)
+{
+#define MAX_COMPLETIONS 100
+ char **matches;
+ int i, count=0;
- if (!got_bcast && get_myname(hs, &ip1)) {
- get_broadcast(&ip1, &bcast_ip, &ip2);
- }
+ /* for words not at the start of the line fallback to filename completion */
+ if (start) return NULL;
- if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
- failed = False;
- }
- close (bcast);
+ matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
+ if (!matches) return NULL;
+
+ matches[count++] = strdup(text);
+ if (!matches[0]) return NULL;
+
+ for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
+ if (strncmp(text, commands[i].name, strlen(text)) == 0) {
+ matches[count] = strdup(commands[i].name);
+ if (!matches[count]) return NULL;
+ count++;
+ }
}
-#endif
- if (failed) {
- DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
- return False;
+
+ if (count == 2) {
+ SAFE_FREE(matches[0]);
+ matches[0] = strdup(matches[1]);
}
- }
- }
+ matches[count] = NULL;
+ return matches;
+}
- Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (Client == -1)
- return False;
- DEBUG(3,("Connected\n"));
-
- set_socket_options(Client,user_socket_options);
-
- return True;
+/****************************************************************************
+make sure we swallow keepalives during idle time
+****************************************************************************/
+static void readline_callback(void)
+{
+ fd_set fds;
+ struct timeval timeout;
+ static time_t last_t;
+ time_t t;
+
+ t = time(NULL);
+
+ if (t - last_t < 5) return;
+
+ last_t = t;
+
+ again:
+ FD_ZERO(&fds);
+ FD_SET(cli->fd,&fds);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ sys_select_intr(cli->fd+1,&fds,&timeout);
+
+ /* We deliberately use receive_smb instead of
+ client_receive_smb as we want to receive
+ session keepalives and then drop them here.
+ */
+ if (FD_ISSET(cli->fd,&fds)) {
+ receive_smb(cli->fd,cli->inbuf,0);
+ goto again;
+ }
+
+ cli_chkpath(cli, "\\");
}
+
/****************************************************************************
-wait for keyboard activity, swallowing network packets
+process commands on stdin
****************************************************************************/
-#ifdef CLIX
-static char wait_keyboard(char *buffer)
-#else
-static void wait_keyboard(char *buffer)
-#endif
+static void process_stdin(void)
{
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
-#ifdef CLIX
- int delay = 0;
-#endif
-
- while (1)
- {
- extern int Client;
- FD_ZERO(&fds);
- FD_SET(Client,&fds);
-#ifndef CLIX
- FD_SET(fileno(stdin),&fds);
-#endif
+ char *ptr;
- timeout.tv_sec = 20;
- timeout.tv_usec = 0;
-#ifdef CLIX
- timeout.tv_sec = 0;
-#endif
- selrtn = sys_select(&fds,&timeout);
-
-#ifndef CLIX
- if (FD_ISSET(fileno(stdin),&fds))
- return;
-#else
- {
- char ch;
- int f_flags;
- int readret;
-
- f_flags = fcntl(fileno(stdin), F_GETFL, 0);
- fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
- readret = read_data( fileno(stdin), &ch, 1);
- fcntl(fileno(stdin), F_SETFL, f_flags);
- if (readret == -1)
- {
- if (errno != EAGAIN)
- {
- /* should crash here */
- DEBUG(1,("readchar stdin failed\n"));
- }
- }
- else if (readret != 0)
- {
- return ch;
- }
- }
-#endif
- if (FD_ISSET(Client,&fds))
- receive_smb(Client,buffer,0);
+ while (1) {
+ fstring tok;
+ fstring the_prompt;
+ char *cline;
+ pstring line;
+ int i;
+
+ /* display a prompt */
+ slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
+ cline = smb_readline(the_prompt, readline_callback, completion_fn);
+
+ if (!cline) break;
+
+ pstrcpy(line, cline);
+
+ /* special case - first char is ! */
+ if (*line == '!') {
+ system(line + 1);
+ continue;
+ }
-#ifdef CLIX
- delay++;
- if (delay > 100000)
- {
- delay = 0;
- chkpath("\\",False);
+ /* and get the first part of the command */
+ ptr = line;
+ if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
+
+ if ((i = process_tok(tok)) >= 0) {
+ commands[i].fn();
+ } else if (i == -2) {
+ d_printf("%s: command abbreviation ambiguous\n",tok);
+ } else {
+ d_printf("%s: command not found\n",tok);
+ }
}
-#else
- chkpath("\\",False);
-#endif
- }
}
-/****************************************************************************
-close and open the connection again
-****************************************************************************/
-BOOL reopen_connection(char *inbuf,char *outbuf)
+/*****************************************************
+return a connection to a server
+*******************************************************/
+struct cli_state *do_connect(const char *server, const char *share)
{
- static int open_count=0;
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ const char *server_n;
+ struct in_addr ip;
+ fstring servicename;
+ char *sharename;
+
+ /* make a copy so we don't modify the global string 'service' */
+ safe_strcpy(servicename, share, sizeof(servicename)-1);
+ sharename = servicename;
+ if (*sharename == '\\') {
+ server = sharename+2;
+ sharename = strchr_m(server,'\\');
+ if (!sharename) return NULL;
+ *sharename = 0;
+ sharename++;
+ }
- open_count++;
+ server_n = server;
+
+ zero_ip(&ip);
- if (open_count>5) return(False);
+ make_nmb_name(&calling, global_myname, 0x0);
+ make_nmb_name(&called , server, name_type);
- DEBUG(1,("Trying to re-open connection\n"));
+ again:
+ zero_ip(&ip);
+ if (have_ip) ip = dest_ip;
- set_message(outbuf,0,0,True);
- SCVAL(outbuf,smb_com,SMBtdis);
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) ||
+ !cli_connect(c, server_n, &ip)) {
+ d_printf("Connection to %s failed\n", server_n);
+ return NULL;
+ }
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,SHORT_TIMEOUT);
+ c->protocol = max_protocol;
+ c->use_kerberos = use_kerberos;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ char *p;
+ d_printf("session request to %s failed (%s)\n",
+ called.name, cli_errstr(c));
+ cli_shutdown(c);
+ if ((p=strchr_m(called.name, '.'))) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ d_printf("protocol negotiation failed\n");
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ /* if a password was not supplied then try again with a null username */
+ if (password[0] || !username[0] || use_kerberos ||
+ !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
+ d_printf("session setup failed: %s\n", cli_errstr(c));
+ cli_shutdown(c);
+ return NULL;
+ }
+ d_printf("Anonymous login successful\n");
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type){
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, sharename, "?????",
+ password, strlen(password)+1)) {
+ d_printf("tree connect failed: %s\n", cli_errstr(c));
+ cli_shutdown(c);
+ return NULL;
+ }
- close_sockets();
- if (!open_sockets(0)) return(False);
+ DEBUG(4,(" tconx ok\n"));
- return(send_login(inbuf,outbuf,True,True));
+ return c;
}
+
/****************************************************************************
process commands from the client
****************************************************************************/
-BOOL process(char *base_directory)
+static int process(char *base_directory)
{
- extern FILE *dbf;
- pstring line;
+ int rc = 0;
- char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ cli = do_connect(desthost, service);
+ if (!cli) {
+ return 1;
+ }
- if ((InBuffer == NULL) || (OutBuffer == NULL))
- return(False);
+ if (*base_directory) do_cd(base_directory);
+
+ if (cmdstr) {
+ rc = process_command_string(cmdstr);
+ } else {
+ process_stdin();
+ }
- bzero(OutBuffer,smb_size);
-
- if (!send_login(InBuffer,OutBuffer,True,True))
- return(False);
+ cli_shutdown(cli);
+ return rc;
+}
- if (*base_directory) do_cd(base_directory);
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(char *pname)
+{
+ d_printf("Usage: %s service <password> [options]", pname);
+
+ d_printf("\nVersion %s\n",VERSION);
+ d_printf("\t-s smb.conf pathname to smb.conf file\n");
+ d_printf("\t-O socket_options socket options to use\n");
+ d_printf("\t-R name resolve order use these name resolution services only\n");
+ d_printf("\t-M host send a winpopup message to the host\n");
+ d_printf("\t-i scope use this NetBIOS scope\n");
+ d_printf("\t-N don't ask for a password\n");
+ d_printf("\t-n netbios name. Use this name as my netbios name\n");
+ d_printf("\t-d debuglevel set the debuglevel\n");
+ d_printf("\t-P connect to service as a printer\n");
+ d_printf("\t-p port connect to the specified port\n");
+ d_printf("\t-l log basename. Basename for log/debug files\n");
+ d_printf("\t-h Print this help message.\n");
+ d_printf("\t-I dest IP use this IP to connect to\n");
+ d_printf("\t-E write messages to stderr instead of stdout\n");
+ d_printf("\t-k use kerberos (active directory) authentication\n");
+ d_printf("\t-U username set the network username\n");
+ d_printf("\t-L host get a list of shares available on a host\n");
+ d_printf("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n");
+ d_printf("\t-m max protocol set the max protocol level\n");
+ d_printf("\t-A filename get the credentials from a file\n");
+ d_printf("\t-W workgroup set the workgroup name\n");
+ d_printf("\t-T<c|x>IXFqgbNan command line tar\n");
+ d_printf("\t-D directory start from directory\n");
+ d_printf("\t-c command string execute semicolon separated commands\n");
+ d_printf("\t-b xmit/send buffer changes the transmit/send buffer (default: 65520)\n");
+ d_printf("\n");
+}
+
+
+/****************************************************************************
+get a password from a a file or file descriptor
+exit on failure
+****************************************************************************/
+static void get_password_file(void)
+{
+ int fd = -1;
+ char *p;
+ BOOL close_it = False;
+ pstring spec;
+ char pass[128];
+
+ if ((p = getenv("PASSWD_FD")) != NULL) {
+ pstrcpy(spec, "descriptor ");
+ pstrcat(spec, p);
+ sscanf(p, "%d", &fd);
+ close_it = False;
+ } else if ((p = getenv("PASSWD_FILE")) != NULL) {
+ fd = sys_open(p, O_RDONLY, 0);
+ pstrcpy(spec, p);
+ if (fd < 0) {
+ fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
+ spec, strerror(errno));
+ exit(1);
+ }
+ close_it = True;
+ }
- while (!feof(stdin))
- {
- fstring tok;
- int i;
+ for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
+ p && p - pass < sizeof(pass);) {
+ switch (read(fd, p, 1)) {
+ case 1:
+ if (*p != '\n' && *p != '\0') {
+ *++p = '\0'; /* advance p, and null-terminate pass */
+ break;
+ }
+ case 0:
+ if (p - pass) {
+ *p = '\0'; /* null-terminate it, just in case... */
+ p = NULL; /* then force the loop condition to become false */
+ break;
+ } else {
+ fprintf(stderr, "Error reading password from file %s: %s\n",
+ spec, "empty password\n");
+ exit(1);
+ }
+
+ default:
+ fprintf(stderr, "Error reading password from file %s: %s\n",
+ spec, strerror(errno));
+ exit(1);
+ }
+ }
+ pstrcpy(password, pass);
+ if (close_it)
+ close(fd);
+}
- bzero(OutBuffer,smb_size);
- /* display a prompt */
- DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
- fflush(dbf);
-#ifdef CLIX
- line[0] = wait_keyboard(InBuffer);
- /* this might not be such a good idea... */
- if ( line[0] == EOF)
- break;
-#else
- wait_keyboard(InBuffer);
-#endif
-
- /* and get a response */
-#ifdef CLIX
- fgets( &line[1],999, stdin);
-#else
- if (!fgets(line,1000,stdin))
- break;
-#endif
+/****************************************************************************
+handle a -L query
+****************************************************************************/
+static int do_host_query(char *query_host)
+{
+ cli = do_connect(query_host, "IPC$");
+ if (!cli)
+ return 1;
- /* input language code to internal one */
- CNV_INPUT (line);
+ browse_host(True);
+ list_servers(workgroup);
- /* special case - first char is ! */
- if (*line == '!')
- {
- system(line + 1);
- continue;
- }
-
- /* and get the first part of the command */
- {
- char *ptr = line;
- if (!next_token(&ptr,tok,NULL)) continue;
- }
-
- if ((i = process_tok(tok)) >= 0)
- commands[i].fn(InBuffer,OutBuffer);
- else if (i == -2)
- DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
- else
- DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
- }
-
- send_logout();
- return(True);
+ cli_shutdown(cli);
+
+ return(0);
}
/****************************************************************************
-usage on the program
+handle a tar operation
****************************************************************************/
-void usage(char *pname)
+static int do_tar_op(char *base_directory)
{
- DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
- pname));
+ int ret;
+ cli = do_connect(desthost, service);
+ if (!cli)
+ return 1;
-#ifdef KANJI
- DEBUG(0,("[-t termcode] "));
-#endif /* KANJI */
+ recurse=True;
- DEBUG(0,("\nVersion %s\n",VERSION));
- DEBUG(0,("\t-p port listen on the specified port\n"));
- DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
- DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
- DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
- DEBUG(0,("\t-N don't ask for a password\n"));
- DEBUG(0,("\t-P connect to service as a printer\n"));
- DEBUG(0,("\t-M host send a winpopup message to the host\n"));
- DEBUG(0,("\t-m max protocol set the max protocol level\n"));
- DEBUG(0,("\t-L host get a list of shares available on a host\n"));
- DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
- DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
- DEBUG(0,("\t-U username set the network username\n"));
- DEBUG(0,("\t-W workgroup set the workgroup name\n"));
-#ifdef KANJI
- DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
-#endif /* KANJI */
- DEBUG(0,("\t-T<c|x>IXgbNa command line tar\n"));
- DEBUG(0,("\t-D directory start from directory\n"));
- DEBUG(0,("\n"));
-}
+ if (*base_directory) do_cd(base_directory);
+
+ ret=process_tar();
+ cli_shutdown(cli);
+ return(ret);
+}
/****************************************************************************
- main program
+handle a message operation
****************************************************************************/
-int main(int argc,char *argv[])
+static int do_message_op(void)
{
- fstring base_directory;
- char *pname = argv[0];
- int port = 139;
- int opt;
- extern FILE *dbf;
- extern char *optarg;
- extern int optind;
- pstring query_host;
- BOOL message = False;
- extern char tar_type;
-
- *query_host = 0;
- *base_directory = 0;
-
- DEBUGLEVEL = 2;
-
- setup_logging(pname,True);
-
- TimeInit();
- charset_initialise();
-
- pid = getpid();
- uid = getuid();
- gid = getgid();
- mid = pid + 100;
- myumask = umask(0);
- umask(myumask);
-
- if (getenv("USER"))
- {
- strcpy(username,getenv("USER"));
- strupper(username);
- }
-
- if (*username == 0 && getenv("LOGNAME"))
- {
- strcpy(username,getenv("LOGNAME"));
- strupper(username);
- }
-
- if (argc < 2)
- {
- usage(pname);
- exit(1);
- }
-
- if (*argv[1] != '-')
- {
+ struct in_addr ip;
+ struct nmb_name called, calling;
- strcpy(service,argv[1]);
- argc--;
- argv++;
+ zero_ip(&ip);
- if (count_chars(service,'\\') < 3)
- {
- usage(pname);
- printf("\n%s: Not enough '\\' characters in service\n",service);
- exit(1);
- }
+ make_nmb_name(&calling, global_myname, 0x0);
+ make_nmb_name(&called , desthost, name_type);
-/*
- if (count_chars(service,'\\') > 3)
- {
- usage(pname);
- printf("\n%s: Too many '\\' characters in service\n",service);
- exit(1);
- }
- */
+ zero_ip(&ip);
+ if (have_ip) ip = dest_ip;
- if (argc > 1 && (*argv[1] != '-'))
- {
- got_pass = True;
- strcpy(password,argv[1]);
- memset(argv[1],'X',strlen(argv[1]));
- argc--;
- argv++;
+ if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) || !cli_connect(cli, desthost, &ip)) {
+ d_printf("Connection to %s failed\n", desthost);
+ return 1;
}
- }
-#ifdef KANJI
- setup_term_code (KANJI);
- while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:")) != EOF)
-#else
- while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:m:W:T:D:")) != EOF)
-#endif /* KANJI */
- switch (opt)
- {
- case 'm':
- max_protocol = interpret_protocol(optarg,max_protocol);
- break;
- case 'O':
- strcpy(user_socket_options,optarg);
- break;
- case 'M':
- name_type = 3;
- strcpy(desthost,optarg);
- strupper(desthost);
- message = True;
- break;
- case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
- break;
- case 'D':
- strcpy(base_directory,optarg);
- break;
- case 'T':
- if (!tar_parseargs(argc, argv, optarg, optind)) {
- usage(pname);
- exit(1);
- }
- break;
- case 'i':
- strcpy(scope,optarg);
- break;
- case 'L':
- got_pass = True;
- strcpy(query_host,optarg);
- break;
- case 'U':
- {
- char *p;
- strcpy(username,optarg);
- if ((p=strchr(username,'%')))
- {
- *p = 0;
- strcpy(password,p+1);
- got_pass = True;
- memset(strchr(optarg,'%')+1,'X',strlen(password));
- }
+ if (!cli_session_request(cli, &calling, &called)) {
+ d_printf("session request failed\n");
+ cli_shutdown(cli);
+ return 1;
}
-
- break;
- case 'W':
- strcpy(workgroup,optarg);
- break;
- case 'E':
- dbf = stderr;
- break;
- case 'I':
- {
- dest_ip = *interpret_addr2(optarg);
- if (zero_ip(dest_ip)) exit(1);
- have_ip = True;
- }
- break;
- case 'n':
- strcpy(myname,optarg);
- break;
- case 'N':
- got_pass = True;
- break;
- case 'P':
- connect_as_printer = True;
- break;
- case 'd':
- if (*optarg == 'A')
- DEBUGLEVEL = 10000;
- else
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'l':
- sprintf(debugf,"%s.client",optarg);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'h':
- usage(pname);
- exit(0);
- break;
+
+ send_message();
+ cli_shutdown(cli);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ fstring base_directory;
+ char *pname = argv[0];
+ int opt;
+ extern char *optarg;
+ extern int optind;
+ int old_debug;
+ pstring query_host;
+ BOOL message = False;
+ extern char tar_type;
+ pstring term_code;
+ pstring new_name_resolve_order;
+ pstring logfile;
+ char *p;
+ int rc = 0;
+
#ifdef KANJI
- case 't':
- if (!setup_term_code (optarg)) {
- DEBUG(0, ("%s: unknown terminal code name\n", optarg));
- usage (pname);
- exit (1);
- }
- break;
+ pstrcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
#endif /* KANJI */
- default:
- usage(pname);
- exit(1);
- }
- if (!tar_type && !*query_host && !*service && !message)
- {
- usage(pname);
- exit(1);
- }
+ *query_host = 0;
+ *base_directory = 0;
+ *new_name_resolve_order = 0;
- DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
+ DEBUGLEVEL = 2;
+
+ setup_logging(pname,True);
+
+ /*
+ * If the -E option is given, be careful not to clobber stdout
+ * before processing the options. 28.Feb.99, richard@hacom.nl.
+ * Also pre-parse the -s option to get the service file name.
+ */
+
+ for (opt = 1; opt < argc; opt++) {
+ if (strcmp(argv[opt], "-E") == 0)
+ dbf = x_stderr;
+ else if(strncmp(argv[opt], "-s", 2) == 0) {
+ if(argv[opt][2] != '\0')
+ pstrcpy(dyn_CONFIGFILE, &argv[opt][2]);
+ else if(argv[opt+1] != NULL) {
+ /*
+ * At least one more arg left.
+ */
+ pstrcpy(dyn_CONFIGFILE, argv[opt+1]);
+ } else {
+ usage(pname);
+ exit(1);
+ }
+ }
+ }
- get_myname(*myname?NULL:myname,&myip);
- strupper(myname);
+ in_client = True; /* Make sure that we tell lp_load we are */
- if (tar_type) {
- recurse=True;
+ old_debug = DEBUGLEVEL;
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
+ prog_name, dyn_CONFIGFILE);
+ }
+ DEBUGLEVEL = old_debug;
+
+#ifdef WITH_SSL
+ sslutil_init(0);
+#endif
- if (open_sockets(port)) {
- char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- int ret;
+ pstrcpy(workgroup,lp_workgroup());
- if ((InBuffer == NULL) || (OutBuffer == NULL))
- return(1);
+ load_interfaces();
+ myumask = umask(0);
+ umask(myumask);
- bzero(OutBuffer,smb_size);
- if (!send_login(InBuffer,OutBuffer,True,True))
- return(False);
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
- if (*base_directory) do_cd(base_directory);
+ /* modification to support userid%passwd syntax in the USER var
+ 25.Aug.97, jdblair@uab.edu */
- ret=process_tar(InBuffer, OutBuffer);
-
- send_logout();
- close_sockets();
- return(ret);
- } else
- return(1);
- }
-
- if (*query_host)
- {
- int ret = 0;
- sprintf(service,"\\\\%s\\IPC$",query_host);
- strupper(service);
- connect_as_ipc = True;
- if (open_sockets(port))
- {
-#if 0
- *username = 0;
-#endif
- if (!send_login(NULL,NULL,True,True))
- return(1);
-
- server_info();
- if (!browse_host(True)) {
- sleep(1);
- browse_host(True);
- }
- if (!list_servers()) {
- sleep(1);
- list_servers();
- }
-
- send_logout();
- close_sockets();
+ if ((p=strchr_m(username,'%'))) {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
+ }
+ strupper(username);
}
- return(ret);
- }
+ /* modification to support PASSWD environmental var
+ 25.Aug.97, jdblair@uab.edu */
+ if (getenv("PASSWD")) {
+ pstrcpy(password,getenv("PASSWD"));
+ got_pass = True;
+ }
- if (message)
- {
- int ret = 0;
- if (open_sockets(port))
- {
- pstring inbuf,outbuf;
- bzero(outbuf,smb_size);
- if (!send_session_request(inbuf,outbuf))
- return(1);
+ if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
+ get_password_file();
+ got_pass = True;
+ }
- send_message(inbuf,outbuf);
+ if (*username == 0 && getenv("LOGNAME")) {
+ pstrcpy(username,getenv("LOGNAME"));
+ strupper(username);
+ }
- close_sockets();
+ if (*username == 0) {
+ pstrcpy(username,"GUEST");
}
- return(ret);
- }
+ if (argc < 2) {
+ usage(pname);
+ exit(1);
+ }
+
+ if (*argv[1] != '-') {
+ pstrcpy(service,argv[1]);
+ /* Convert any '/' characters in the service name to '\' characters */
+ string_replace( service, '/','\\');
+ argc--;
+ argv++;
+
+ if (count_chars(service,'\\') < 3) {
+ usage(pname);
+ d_printf("\n%s: Not enough '\\' characters in service\n",service);
+ exit(1);
+ }
- if (open_sockets(port))
- {
- if (!process(base_directory))
- {
- close_sockets();
- return(1);
+ if (argc > 1 && (*argv[1] != '-')) {
+ got_pass = True;
+ pstrcpy(password,argv[1]);
+ memset(argv[1],'X',strlen(argv[1]));
+ argc--;
+ argv++;
+ }
}
- close_sockets();
- }
- else
- return(1);
- return(0);
-}
+ while ((opt =
+ getopt(argc, argv,"s:O:R:M:i:Nn:d:Pp:l:hI:EU:L:t:m:W:T:D:c:b:A:k")) != EOF) {
+ switch (opt) {
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ case 'O':
+ pstrcpy(user_socket_options,optarg);
+ break;
+ case 'R':
+ pstrcpy(new_name_resolve_order, optarg);
+ break;
+ case 'M':
+ name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
+ pstrcpy(desthost,optarg);
+ message = True;
+ break;
+ case 'i':
+ {
+ extern pstring global_scope;
+ pstrcpy(global_scope,optarg);
+ strupper(global_scope);
+ }
+ break;
+ case 'N':
+ got_pass = True;
+ break;
+ case 'n':
+ pstrcpy(global_myname,optarg);
+ break;
+ case 'd':
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'P':
+ /* not needed anymore */
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'l':
+ slprintf(logfile,sizeof(logfile)-1, "%s.client",optarg);
+ lp_set_logfile(logfile);
+ break;
+ case 'h':
+ usage(pname);
+ exit(0);
+ break;
+ case 'I':
+ {
+ dest_ip = *interpret_addr2(optarg);
+ if (is_zero_ip(dest_ip))
+ exit(1);
+ have_ip = True;
+ }
+ break;
+ case 'E':
+ display_set_stderr();
+ dbf = x_stderr;
+ break;
+ case 'U':
+ {
+ char *lp;
+ pstrcpy(username,optarg);
+ if ((lp=strchr_m(username,'%'))) {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr_m(optarg,'%')+1,'X',strlen(password));
+ }
+ }
+ break;
+
+ case 'A':
+ {
+ XFILE *auth;
+ fstring buf;
+ uint16 len = 0;
+ char *ptr, *val, *param;
+
+ if ((auth=x_fopen(optarg, O_RDONLY, 0)) == NULL)
+ {
+ /* fail if we can't open the credentials file */
+ d_printf("ERROR: Unable to open credentials file!\n");
+ exit (-1);
+ }
+
+ while (!x_feof(auth))
+ {
+ /* get a line from the file */
+ if (!x_fgets(buf, sizeof(buf), auth))
+ continue;
+ len = strlen(buf);
+
+ if ((len) && (buf[len-1]=='\n'))
+ {
+ buf[len-1] = '\0';
+ len--;
+ }
+ if (len == 0)
+ continue;
+
+ /* break up the line into parameter & value.
+ will need to eat a little whitespace possibly */
+ param = buf;
+ if (!(ptr = strchr_m (buf, '=')))
+ continue;
+ val = ptr+1;
+ *ptr = '\0';
+
+ /* eat leading white space */
+ while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
+ val++;
+
+ if (strwicmp("password", param) == 0)
+ {
+ pstrcpy(password, val);
+ got_pass = True;
+ }
+ else if (strwicmp("username", param) == 0)
+ pstrcpy(username, val);
+ else if (strwicmp("domain", param) == 0)
+ pstrcpy(workgroup,val);
+ memset(buf, 0, sizeof(buf));
+ }
+ x_fclose(auth);
+ }
+ break;
+
+ case 'L':
+ p = optarg;
+ while(*p == '\\' || *p == '/')
+ p++;
+ pstrcpy(query_host,p);
+ break;
+ case 't':
+ pstrcpy(term_code, optarg);
+ break;
+ case 'm':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'W':
+ pstrcpy(workgroup,optarg);
+ break;
+ case 'T':
+ if (!tar_parseargs(argc, argv, optarg, optind)) {
+ usage(pname);
+ exit(1);
+ }
+ break;
+ case 'D':
+ pstrcpy(base_directory,optarg);
+ break;
+ case 'c':
+ cmdstr = optarg;
+ break;
+ case 'b':
+ io_bufsize = MAX(1, atoi(optarg));
+ break;
+ case 'k':
+#ifdef HAVE_KRB5
+ use_kerberos = True;
+ got_pass = True;
+#else
+ d_printf("No kerberos support compiled in\n");
+ exit(1);
+#endif
+ break;
+ default:
+ usage(pname);
+ exit(1);
+ }
+ }
+ get_myname((*global_myname)?NULL:global_myname);
-/* error code stuff - put together by Merik Karman
- merik@blackadder.dsh.oz.au */
+ if(*new_name_resolve_order)
+ lp_set_name_resolve_order(new_name_resolve_order);
-typedef struct
-{
- char *name;
- int code;
- char *message;
-} err_code_struct;
-
-/* Dos Error Messages */
-err_code_struct dos_msgs[] = {
- {"ERRbadfunc",1,"Invalid function."},
- {"ERRbadfile",2,"File not found."},
- {"ERRbadpath",3,"Directory invalid."},
- {"ERRnofids",4,"No file descriptors available"},
- {"ERRnoaccess",5,"Access denied."},
- {"ERRbadfid",6,"Invalid file handle."},
- {"ERRbadmcb",7,"Memory control blocks destroyed."},
- {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
- {"ERRbadmem",9,"Invalid memory block address."},
- {"ERRbadenv",10,"Invalid environment."},
- {"ERRbadformat",11,"Invalid format."},
- {"ERRbadaccess",12,"Invalid open mode."},
- {"ERRbaddata",13,"Invalid data."},
- {"ERR",14,"reserved."},
- {"ERRbaddrive",15,"Invalid drive specified."},
- {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."},
- {"ERRdiffdevice",17,"Not same device."},
- {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
- {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
- {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
- {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."},
- {"ERRbadpipe",230,"Pipe invalid."},
- {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
- {"ERRpipeclosing",232,"Pipe close in progress."},
- {"ERRnotconnected",233,"No process on other end of pipe."},
- {"ERRmoredata",234,"There is more data to be returned."},
- {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
- {NULL,-1,NULL}};
-
-/* Server Error Messages */
-err_code_struct server_msgs[] = {
- {"ERRerror",1,"Non-specific error code."},
- {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
- {"ERRbadtype",3,"reserved."},
- {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
- {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
- {"ERRinvnetname",6,"Invalid network name in tree connect."},
- {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
- {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
- {"ERRqtoobig",50,"Print queue full -- no space."},
- {"ERRqeof",51,"EOF on print queue dump."},
- {"ERRinvpfid",52,"Invalid print file FID."},
- {"ERRsmbcmd",64,"The server did not recognize the command received."},
- {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
- {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."},
- {"ERRreserved",68,"reserved."},
- {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
- {"ERRreserved",70,"reserved."},
- {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
- {"ERRpaused",81,"Server is paused."},
- {"ERRmsgoff",82,"Not receiving messages."},
- {"ERRnoroom",83,"No room to buffer message."},
- {"ERRrmuns",87,"Too many remote user names."},
- {"ERRtimeout",88,"Operation timed out."},
- {"ERRnoresource",89,"No resources currently available for request."},
- {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
- {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
- {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
- {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
- {"ERRcontmpx",252,"Continue in MPX mode."},
- {"ERRreserved",253,"reserved."},
- {"ERRreserved",254,"reserved."},
- {"ERRnosupport",0xFFFF,"Function not supported."},
- {NULL,-1,NULL}};
-
-/* Hard Error Messages */
-err_code_struct hard_msgs[] = {
- {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
- {"ERRbadunit",20,"Unknown unit."},
- {"ERRnotready",21,"Drive not ready."},
- {"ERRbadcmd",22,"Unknown command."},
- {"ERRdata",23,"Data error (CRC)."},
- {"ERRbadreq",24,"Bad request structure length."},
- {"ERRseek",25 ,"Seek error."},
- {"ERRbadmedia",26,"Unknown media type."},
- {"ERRbadsector",27,"Sector not found."},
- {"ERRnopaper",28,"Printer out of paper."},
- {"ERRwrite",29,"Write fault."},
- {"ERRread",30,"Read fault."},
- {"ERRgeneral",31,"General failure."},
- {"ERRbadshare",32,"A open conflicts with an existing open."},
- {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
- {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
- {"ERRFCBUnavail",35,"No FCBs are available to process request."},
- {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
- {NULL,-1,NULL}};
+ if (!tar_type && !*query_host && !*service && !message) {
+ usage(pname);
+ exit(1);
+ }
+ DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
-struct
-{
- int code;
- char *class;
- err_code_struct *err_msgs;
-} err_classes[] = {
- {0,"SUCCESS",NULL},
- {0x01,"ERRDOS",dos_msgs},
- {0x02,"ERRSRV",server_msgs},
- {0x03,"ERRHRD",hard_msgs},
- {0x04,"ERRXOS",NULL},
- {0xE1,"ERRRMX1",NULL},
- {0xE2,"ERRRMX2",NULL},
- {0xE3,"ERRRMX3",NULL},
- {0xFF,"ERRCMD",NULL},
- {-1,NULL,NULL}};
+ if (tar_type) {
+ if (cmdstr)
+ process_command_string(cmdstr);
+ return do_tar_op(base_directory);
+ }
+ if ((p=strchr_m(query_host,'#'))) {
+ *p = 0;
+ p++;
+ sscanf(p, "%x", &name_type);
+ }
+
+ if (*query_host) {
+ return do_host_query(query_host);
+ }
-/****************************************************************************
-return a SMB error string from a SMB buffer
-****************************************************************************/
-char *smb_errstr(char *inbuf)
-{
- static pstring ret;
- int class = CVAL(inbuf,smb_rcls);
- int num = SVAL(inbuf,smb_err);
- int i,j;
-
- for (i=0;err_classes[i].class;i++)
- if (err_classes[i].code == class)
- {
- if (err_classes[i].err_msgs)
- {
- err_code_struct *err = err_classes[i].err_msgs;
- for (j=0;err[j].name;j++)
- if (num == err[j].code)
- {
- if (DEBUGLEVEL > 0)
- sprintf(ret,"%s - %s (%s)",err_classes[i].class,
- err[j].name,err[j].message);
- else
- sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
- return ret;
- }
- }
+ if (message) {
+ return do_message_op();
+ }
+
+ if (process(base_directory)) {
+ return 1;
+ }
- sprintf(ret,"%s - %d",err_classes[i].class,num);
- return ret;
- }
-
- sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
- return(ret);
+ return rc;
}
diff --git a/source/client/clitar.c b/source/client/clitar.c
index 1433ec59412..64b035a89ec 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -2,7 +2,8 @@
Unix SMB/Netbios implementation.
Version 1.9.
Tar Extensions
- Copyright (C) Ricky Poulten 1995
+ Copyright (C) Ricky Poulten 1995-1998
+ Copyright (C) Richard Sharpe 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,100 +19,181 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* The following changes developed by Richard Sharpe for Canon Information
+ Systems Research Australia (CISRA)
+
+ 1. Restore can now restore files with long file names
+ 2. Save now saves directory information so that we can restore
+ directory creation times
+ 3. tar now accepts both UNIX path names and DOS path names. I prefer
+ those lovely /'s to those UGLY \'s :-)
+ 4. the files to exclude can be specified as a regular expression by adding
+ an r flag to the other tar flags. Eg:
+
+ -TcrX file.tar "*.(obj|exe)"
+
+ will skip all .obj and .exe files
+*/
#include "includes.h"
#include "clitar.h"
-extern void setup_pkt(char *outbuf);
-extern BOOL reopen_connection(char *inbuf,char *outbuf);
-extern void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
+static int clipfind(char **aret, int ret, char *tok);
+
+typedef struct file_info_struct file_info2;
-int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+struct file_info_struct
+{
+ size_t size;
+ uint16 mode;
+ int uid;
+ int gid;
+ /* These times are normally kept in GMT */
+ time_t mtime;
+ time_t atime;
+ time_t ctime;
+ char *name; /* This is dynamically allocate */
+
+ file_info2 *next, *prev; /* Used in the stack ... */
+
+};
+
+typedef struct
+{
+ file_info2 *top;
+ int items;
-extern BOOL recurse;
+} stack;
+
+stack dir_stack = {NULL, 0}; /* Want an empty stack */
#define SEPARATORS " \t\n\r"
-extern int DEBUGLEVEL;
-extern int Client;
+extern struct cli_state *cli;
/* These defines are for the do_setrattr routine, to indicate
* setting and reseting of file attributes in the function call */
#define ATTRSET 1
#define ATTRRESET 0
-static int attribute = aDIR | aSYSTEM | aHIDDEN;
+static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
#ifndef CLIENT_TIMEOUT
#define CLIENT_TIMEOUT (30*1000)
#endif
-static char *tarbuf;
+static char *tarbuf, *buffer_p;
static int tp, ntarf, tbufsiz;
+static double ttarf;
/* Incremental mode */
BOOL tar_inc=False;
/* Reset archive bit */
BOOL tar_reset=False;
/* Include / exclude mode (true=include, false=exclude) */
BOOL tar_excl=True;
+/* use regular expressions for search on file names */
+BOOL tar_re_search=False;
+#ifdef HAVE_REGEX_H
+regex_t *preg;
+#endif
+/* Do not dump anything, just calculate sizes */
+BOOL dry_run=False;
+/* Dump files with System attribute */
+BOOL tar_system=True;
+/* Dump files with Hidden attribute */
+BOOL tar_hidden=True;
+/* Be noisy - make a catalogue */
+BOOL tar_noisy=True;
+BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
+
char tar_type='\0';
static char **cliplist=NULL;
static int clipn=0;
+static BOOL must_free_cliplist = False;
extern file_info def_finfo;
extern BOOL lowercase;
-extern int cnum;
+extern uint16 cnum;
extern BOOL readbraw_supported;
extern int max_xmit;
extern pstring cur_dir;
extern int get_total_time_ms;
extern int get_total_size;
-extern int Protocol;
int blocksize=20;
int tarhandle;
-static void writetarheader();
-static void do_atar();
-static void do_tar();
-static void oct_it();
-static void fixtarname();
-static int dotarbuf();
-static void dozerobuf();
-static void dotareof();
-static void initarbuf();
-static int do_setrattr();
-void cmd_tar();
-int process_tar();
-char **toktocliplist();
-int clipfind();
+static void writetarheader(int f, char *aname, int size, time_t mtime,
+ char *amode, unsigned char ftype);
+static void do_atar(char *rname,char *lname,file_info *finfo1);
+static void do_tar(file_info *finfo);
+static void oct_it(long value, int ndgs, char *p);
+static void fixtarname(char *tptr, char *fp, int l);
+static int dotarbuf(int f, char *b, int n);
+static void dozerobuf(int f, int n);
+static void dotareof(int f);
+static void initarbuf(void);
+
/* restore functions */
-static long readtarheader();
-static long unoct();
-static void do_tarput();
-static void unfixtarname();
+static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
+static long unoct(char *p, int ndgs);
+static void do_tarput(void);
+static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
/*
* tar specific utitlities
*/
+/*******************************************************************
+Create a string of size size+1 (for the null)
+*******************************************************************/
+static char *string_create_s(int size)
+{
+ char *tmp;
+
+ tmp = (char *)malloc(size+1);
+
+ if (tmp == NULL) {
+
+ DEBUG(0, ("Out of memory in string_create_s\n"));
+
+ }
+
+ return(tmp);
+
+}
+
/****************************************************************************
Write a tar header to buffer
****************************************************************************/
static void writetarheader(int f, char *aname, int size, time_t mtime,
- char *amode)
+ char *amode, unsigned char ftype)
{
union hblock hb;
int i, chk, l;
char *jp;
+ DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
+
memset(hb.dummy, 0, sizeof(hb.dummy));
l=strlen(aname);
- if (l >= NAMSIZ)
- {
- DEBUG(0, ("tar file %s name length exceeds NAMSIZ\n", aname));
- }
+ if (l >= NAMSIZ - 1) {
+ /* write a GNU tar style long header */
+ char *b;
+ b = (char *)malloc(l+TBLOCK+100);
+ if (!b) {
+ DEBUG(0,("out of memory\n"));
+ exit(1);
+ }
+ writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
+ memset(b, 0, l+TBLOCK+100);
+ fixtarname(b, aname, l);
+ i = strlen(b)+1;
+ DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
+ dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
+ SAFE_FREE(b);
+ }
/* use l + 1 to do the null too */
fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
@@ -122,14 +204,14 @@ static void writetarheader(int f, char *aname, int size, time_t mtime,
/* write out a "standard" tar format header */
hb.dbuf.name[NAMSIZ-1]='\0';
- strcpy(hb.dbuf.mode, amode);
+ safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
oct_it(0L, 8, hb.dbuf.uid);
oct_it(0L, 8, hb.dbuf.gid);
oct_it((long) size, 13, hb.dbuf.size);
oct_it((long) mtime, 13, hb.dbuf.mtime);
memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
- hb.dbuf.linkflag='0';
memset(hb.dbuf.linkname, 0, NAMSIZ);
+ hb.dbuf.linkflag=ftype;
for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
@@ -142,7 +224,7 @@ static void writetarheader(int f, char *aname, int size, time_t mtime,
/****************************************************************************
Read a tar header into a hblock structure, and validate
***************************************************************************/
-static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
+static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
{
long chk, fchk;
int i;
@@ -167,29 +249,44 @@ static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
- DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
+ DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
chk, fchk, hb->dbuf.chksum));
if (fchk != chk)
{
- DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
+ DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
+ dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
return -1;
}
- strcpy(finfo->name, prefix);
+ if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
+
+ DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
+ return(-1);
+
+ }
+
+ safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
/* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
- strlen(hb->dbuf.name) + 1);
+ strlen(hb->dbuf.name) + 1, True);
-/* can't handle links at present */
- if (hb->dbuf.linkflag != '0') {
+ /* can't handle some links at present */
+ if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
if (hb->dbuf.linkflag == 0) {
DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
finfo->name));
} else {
- DEBUG(0, ("this tar file appears to contain some kind of link - ignoring\n"));
- return -2;
+ if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
+ /* Do nothing here at the moment. do_tarput will handle this
+ as long as the longlink gets back to it, as it has to advance
+ the buffer pointer, etc */
+
+ } else {
+ DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
+ return -2;
+ }
}
}
@@ -222,6 +319,9 @@ static int dotarbuf(int f, char *b, int n)
{
int fail=1, writ=n;
+ if (dry_run) {
+ return writ;
+ }
/* This routine and the next one should be the only ones that do write()s */
if (tp + n >= tbufsiz)
{
@@ -250,7 +350,7 @@ static int dotarbuf(int f, char *b, int n)
}
/****************************************************************************
-Write a zeros to buffer / tape
+Write zeros to buffer / tape
****************************************************************************/
static void dozerobuf(int f, int n)
{
@@ -258,9 +358,13 @@ static void dozerobuf(int f, int n)
* used to round files to nearest block
* and to do tar EOFs */
+ if (dry_run)
+ return;
+
if (n+tp >= tbufsiz)
{
memset(tarbuf+tp, 0, tbufsiz-tp);
+
write(f, tarbuf, tbufsiz);
memset(tarbuf, 0, (tp+=n-tbufsiz));
}
@@ -274,14 +378,14 @@ static void dozerobuf(int f, int n)
/****************************************************************************
Malloc tape buffer
****************************************************************************/
-static void initarbuf()
+static void initarbuf(void)
{
/* initialize tar buffer */
tbufsiz=blocksize*TBLOCK;
- tarbuf=malloc(tbufsiz);
+ tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
- /* reset tar buffer pointer and tar file counter */
- tp=0; ntarf=0;
+ /* reset tar buffer pointer and tar file counter and total dumped */
+ tp=0; ntarf=0; ttarf=0;
}
/****************************************************************************
@@ -289,13 +393,16 @@ Write two zero blocks at end of file
****************************************************************************/
static void dotareof(int f)
{
- struct stat stbuf;
+ SMB_STRUCT_STAT stbuf;
/* Two zero blocks at end of file, write out full buffer */
+ if (dry_run)
+ return;
+
(void) dozerobuf(f, TBLOCK);
(void) dozerobuf(f, TBLOCK);
- if (fstat(f, &stbuf) == -1)
+ if (sys_fstat(f, &stbuf) == -1)
{
DEBUG(0, ("Couldn't stat file handle\n"));
return;
@@ -311,37 +418,18 @@ static void dotareof(int f)
****************************************************************************/
static void fixtarname(char *tptr, char *fp, int l)
{
- /* add a '.' to start of file name, convert from ugly dos \'s in path
- * to lovely unix /'s :-} */
-
- *tptr++='.';
-#ifdef KANJI
- while (l > 0) {
- if (is_shift_jis (*fp)) {
- *tptr++ = *fp++;
- *tptr++ = *fp++;
- l -= 2;
- } else if (is_kana (*fp)) {
- *tptr++ = *fp++;
- l--;
- } else if (*fp == '\\') {
- *tptr++ = '/';
- fp++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
- }
- }
-#else
- while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
-#endif
+ /* add a '.' to start of file name, convert from ugly dos \'s in path
+ * to lovely unix /'s :-} */
+ *tptr++='.';
+
+ safe_strcpy(tptr, fp, l);
+ string_replace(tptr, '\\', '/');
}
/****************************************************************************
Convert from decimal to octal string
****************************************************************************/
-static void oct_it (register long value, register int ndgs, register char *p)
+static void oct_it (long value, int ndgs, char *p)
{
/* Converts long to octal string, pads with leading zeros */
@@ -371,7 +459,7 @@ static long unoct(char *p, int ndgs)
while (--ndgs)
{
- if (isdigit(*p))
+ if (isdigit((int)*p))
value = (value << 3) | (long) (*p - '0');
p++;
@@ -381,10 +469,14 @@ static long unoct(char *p, int ndgs)
}
/****************************************************************************
-Compare two strings in a slash insensitive way
+Compare two strings in a slash insensitive way, allowing s1 to match s2
+if s1 is an "initial" string (up to directory marker). Thus, if s2 is
+a file in any subdirectory of s1, declare a match.
***************************************************************************/
-int strslashcmp(const char *s1, const char *s2)
+static int strslashcmp(char *s1, char *s2)
{
+ char *s1_0=s1;
+
while(*s1 && *s2 &&
(*s1 == *s2
|| tolower(*s1) == tolower(*s2)
@@ -393,296 +485,52 @@ int strslashcmp(const char *s1, const char *s2)
s1++; s2++;
}
- return *s1-*s2;
-}
-
-/*
- * general smb utility functions
- */
-/****************************************************************************
-Set DOS file attributes
-***************************************************************************/
-static int do_setrattr(char *fname, int attr, int setit)
-{
- /*
- * First get the existing attribs from existing file
+ /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
+ string of s2.
*/
- char *inbuf,*outbuf;
- char *p;
- pstring name;
- int fattr;
-
- strcpy(name,fname);
- strcpy(fname,"\\");
- strcat(fname,name);
-
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return False;
- }
-
- /* send an smb getatr message */
-
- memset(outbuf,0,smb_size);
- set_message(outbuf,0,2 + strlen(fname),True);
- CVAL(outbuf,smb_com) = SMBgetatr;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,fname);
- p += (strlen(fname)+1);
-
- *p++ = 4;
- *p++ = 0;
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
- else
- {
- DEBUG(5,("\nattr 0x%X time %d size %d\n",
- (int)CVAL(inbuf,smb_vwv0),
- SVAL(inbuf,smb_vwv1),
- SVAL(inbuf,smb_vwv3)));
- }
-
- fattr=CVAL(inbuf,smb_vwv0);
+ if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
- /* combine found attributes with bits to be set or reset */
+ /* ignore trailing slash on s1 */
+ if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
- attr=setit ? (fattr | attr) : (fattr & ~attr);
+ /* check for s1 is an "initial" string of s2 */
+ if (*s2 == '/' || *s2 == '\\') return 0;
- /* now try and set attributes by sending smb reset message */
-
- /* clear out buffer and start again */
- memset(outbuf,0,smb_size);
- set_message(outbuf,8,4 + strlen(fname),True);
- CVAL(outbuf,smb_com) = SMBsetatr;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,attr);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,fname);
- p += (strlen(fname)+1);
-
- *p++ = 4;
- *p++ = 0;
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s setting attributes on file %s\n",
- smb_errstr(inbuf), fname));
- free(inbuf);free(outbuf);
- return(False);
- }
-
- free(inbuf);free(outbuf);
- return(True);
+ return *s1-*s2;
}
-/****************************************************************************
-Create a file on a share
-***************************************************************************/
-static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
-{
- char *p;
- /* *must* be called with buffer ready malloc'ed */
- /* open remote file */
-
- memset(outbuf,0,smb_size);
- set_message(outbuf,3,2 + strlen(finfo.name),True);
- CVAL(outbuf,smb_com) = SMBcreate;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,finfo.mode);
- put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,finfo.name);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
- finfo.name));
- return 0;
- }
-
- *fnum = SVAL(inbuf,smb_vwv0);
- return True;
-}
/****************************************************************************
-Write a file to a share
-***************************************************************************/
-static BOOL smbwrite(int fnum, int n, int low, int high, int left,
- char *bufferp, char *inbuf, char *outbuf)
-{
- /* *must* be called with buffer ready malloc'ed */
-
- memset(outbuf,0,smb_size);
- set_message(outbuf,5,n + 3,True);
-
- memcpy(smb_buf(outbuf)+3, bufferp, n);
-
- set_message(outbuf,5,n + 3, False);
- CVAL(outbuf,smb_com) = SMBwrite;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,n);
- SIVAL(outbuf,smb_vwv2,low);
- SSVAL(outbuf,smb_vwv4,left);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,n);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
- return False;
- }
-
- if (n != SVAL(inbuf,smb_vwv0))
- {
- DEBUG(0,("Error: only wrote %d bytes out of %d\n",
- SVAL(inbuf,smb_vwv0), n));
- return False;
- }
-
- return True;
-}
-
-/****************************************************************************
-Close a file on a share
+Ensure a remote path exists (make if necessary)
***************************************************************************/
-static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
+static BOOL ensurepath(char *fname)
{
/* *must* be called with buffer ready malloc'ed */
+ /* ensures path exists */
- memset(outbuf,0,smb_size);
- set_message(outbuf,3,0,True);
- CVAL(outbuf,smb_com) = SMBclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
-
- DEBUG(3,("Setting date to %s (0x%X)",
- asctime(LocalTime(&finfo.mtime,GMT_TO_LOCAL)),
- finfo.mtime));
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
- finfo.name));
- return False;
- }
-
- return True;
-}
-
-/****************************************************************************
-Verify existence of path on share
-***************************************************************************/
-static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
-{
- char *p;
-
- memset(outbuf,0,smb_size);
- set_message(outbuf,0,4 + strlen(fname),True);
- CVAL(outbuf,smb_com) = SMBchkpth;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,fname);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
-
- return(CVAL(inbuf,smb_rcls) == 0);
-}
+ char *partpath, *ffname;
+ char *p=fname, *basehack;
-/****************************************************************************
-Make a directory on share
-***************************************************************************/
-static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
-{
- /* *must* be called with buffer ready malloc'ed */
- char *p;
+ DEBUG(5, ( "Ensurepath called with: %s\n", fname));
- memset(outbuf,0,smb_size);
- set_message(outbuf,0,2 + strlen(fname),True);
-
- CVAL(outbuf,smb_com) = SMBmkdir;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- strcpy(p,fname);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("%s making remote directory %s\n",
- smb_errstr(inbuf),fname));
- return(False);
- }
+ partpath = string_create_s(strlen(fname));
+ ffname = string_create_s(strlen(fname));
- return(True);
-}
+ if ((partpath == NULL) || (ffname == NULL)){
-/****************************************************************************
-Ensure a remote path exists (make if necessary)
-***************************************************************************/
-static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
-{
- /* *must* be called with buffer ready malloc'ed */
- /* ensures path exists */
+ DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
+ return(False);
- pstring partpath, ffname;
- char *p=fname, *basehack;
+ }
*partpath = 0;
/* fname copied to ffname so can strtok */
- strcpy(ffname, fname);
+ safe_strcpy(ffname, fname, strlen(fname));
/* do a `basename' on ffname, so don't try and make file name directory */
- if ((basehack=strrchr(ffname, '\\')) == NULL)
+ if ((basehack=strrchr_m(ffname, '\\')) == NULL)
return True;
else
*basehack='\0';
@@ -691,10 +539,10 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
while (p)
{
- strcat(partpath, p);
+ safe_strcat(partpath, p, strlen(fname) + 1);
- if (!smbchkpath(partpath, inbuf, outbuf)) {
- if (!smbmkdir(partpath, inbuf, outbuf))
+ if (!cli_chkpath(cli, partpath)) {
+ if (!cli_mkdir(cli, partpath))
{
DEBUG(0, ("Error mkdirhiering\n"));
return False;
@@ -704,16 +552,48 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
}
- strcat(partpath, "\\");
+ safe_strcat(partpath, "\\", strlen(fname) + 1);
p = strtok(NULL,"/\\");
}
return True;
}
-/*
- * smbclient functions
- */
+static int padit(char *buf, int bufsize, int padsize)
+{
+ int berr= 0;
+ int bytestowrite;
+
+ DEBUG(5, ("Padding with %d zeros\n", padsize));
+ memset(buf, 0, bufsize);
+ while( !berr && padsize > 0 ) {
+ bytestowrite= MIN(bufsize, padsize);
+ berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
+ padsize -= bytestowrite;
+ }
+
+ return berr;
+}
+
+
+static void do_setrattr(char *name, uint16 attr, int set)
+{
+ uint16 oldattr;
+
+ if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
+
+ if (set == ATTRSET) {
+ attr |= oldattr;
+ } else {
+ attr = oldattr & ~attr;
+ }
+
+ if (!cli_setatr(cli, name, attr, 0)) {
+ DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
+ }
+}
+
+
/****************************************************************************
append one remote file to the tar file
***************************************************************************/
@@ -721,356 +601,154 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
{
int fnum;
uint32 nread=0;
- char *p;
- char *inbuf,*outbuf;
- file_info finfo;
+ char ftype;
+ file_info2 finfo;
BOOL close_done = False;
BOOL shallitime=True;
- BOOL ignore_close_error = False;
- char *dataptr=NULL;
+ char data[65520];
+ int read_size = 65520;
int datalen=0;
struct timeval tp_start;
GetTimeOfDay(&tp_start);
- if (finfo1)
- finfo = *finfo1;
- else
- finfo = def_finfo;
+ ftype = '0'; /* An ordinary file ... */
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ if (finfo1) {
+ finfo.size = finfo1 -> size;
+ finfo.mode = finfo1 -> mode;
+ finfo.uid = finfo1 -> uid;
+ finfo.gid = finfo1 -> gid;
+ finfo.mtime = finfo1 -> mtime;
+ finfo.atime = finfo1 -> atime;
+ finfo.ctime = finfo1 -> ctime;
+ }
+ else {
+ finfo.size = def_finfo.size;
+ finfo.mode = def_finfo.mode;
+ finfo.uid = def_finfo.uid;
+ finfo.gid = def_finfo.gid;
+ finfo.mtime = def_finfo.mtime;
+ finfo.atime = def_finfo.atime;
+ finfo.ctime = def_finfo.ctime;
+ }
- if (!inbuf || !outbuf)
+ if (dry_run)
{
- DEBUG(0,("out of memory\n"));
+ DEBUG(3,("skipping file %s of size %d bytes\n",
+ finfo.name,
+ (int)finfo.size));
+ shallitime=0;
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+ ntarf++;
return;
}
- memset(outbuf,0,smb_size);
- set_message(outbuf,15,1 + strlen(rname),True);
-
- CVAL(outbuf,smb_com) = SMBopenX;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv2,1);
- SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
- SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
- SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
- SSVAL(outbuf,smb_vwv8,1);
-
- p = smb_buf(outbuf);
- strcpy(p,rname);
- p = skip_string(p,1);
+ fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
dos_clean_name(rname);
- /* do a chained openX with a readX? */
- if (finfo.size > 0)
- {
- SSVAL(outbuf,smb_vwv0,SMBreadX);
- SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
- memset(p,0,200);
- p -= smb_wct;
- SSVAL(p,smb_wct,10);
- SSVAL(p,smb_vwv0,0xFF);
- SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
- SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
- smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- if (CVAL(inbuf,smb_rcls) == ERRSRV &&
- SVAL(inbuf,smb_err) == ERRnoresource &&
- reopen_connection(inbuf,outbuf))
- {
- do_atar(rname,lname,finfo1);
- free(inbuf);free(outbuf);
+ if (fnum == -1) {
+ DEBUG(0,("%s opening remote file %s (%s)\n",
+ cli_errstr(cli),rname, cur_dir));
return;
- }
+ }
- DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
- free(inbuf);free(outbuf);
- return;
- }
+ finfo.name = string_create_s(strlen(rname));
+ if (finfo.name == NULL) {
+ DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
+ return;
+ }
- strcpy(finfo.name,rname);
- if (!finfo1)
- {
- finfo.mode = SVAL(inbuf,smb_vwv3);
- finfo.size = IVAL(inbuf,smb_vwv4);
- finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
- finfo.atime = finfo.ctime = finfo.mtime;
- }
+ safe_strcpy(finfo.name,rname, strlen(rname));
+ if (!finfo1) {
+ if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
+ DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
+ return;
+ }
+ finfo.ctime = finfo.mtime;
+ }
DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
- fnum = SVAL(inbuf,smb_vwv2);
-
if (tar_inc && !(finfo.mode & aARCH))
{
DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
shallitime=0;
}
+ else if (!tar_system && (finfo.mode & aSYSTEM))
+ {
+ DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
+ shallitime=0;
+ }
+ else if (!tar_hidden && (finfo.mode & aHIDDEN))
+ {
+ DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
+ shallitime=0;
+ }
else
{
- if (SVAL(inbuf,smb_vwv0) == SMBreadX)
- {
- p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
- datalen = SVAL(p,smb_vwv5);
- dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
- }
- else
- {
- dataptr = NULL;
- datalen = 0;
- }
-
- DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
+ DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
finfo.name,
- finfo.size,
+ (int)finfo.size,
lname));
/* write a tar header, don't bother with mode - just set to 100644 */
- writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0");
-
- while (nread < finfo.size && !close_done)
- {
- int method = -1;
- static BOOL can_chain_close=True;
+ writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
- p=NULL;
-
- DEBUG(3,("nread=%d\n",nread));
-
- /* 3 possible read types. readbraw if a large block is required.
- readX + close if not much left and read if neither is supported */
-
- /* we might have already read some data from a chained readX */
- if (dataptr && datalen>0)
- method=3;
-
- /* if we can finish now then readX+close */
- if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
- ((finfo.size - nread) <
- (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
- method = 0;
-
- /* if we support readraw then use that */
- if (method<0 && readbraw_supported)
- method = 1;
-
- /* if we can then use readX */
- if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
- method = 2;
-
-
- switch (method)
- {
- /* use readX */
- case 0:
- case 2:
- if (method == 0)
- close_done = True;
+ while (nread < finfo.size && !close_done) {
- /* use readX + close */
- memset(outbuf,0,smb_size);
- set_message(outbuf,10,0,True);
- CVAL(outbuf,smb_com) = SMBreadX;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- if (close_done)
- {
- CVAL(outbuf,smb_vwv0) = SMBclose;
- SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
- }
- else
- CVAL(outbuf,smb_vwv0) = 0xFF;
-
-
- SSVAL(outbuf,smb_vwv2,fnum);
- SIVAL(outbuf,smb_vwv3,nread);
- SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
- SSVAL(outbuf,smb_vwv6,0);
- SIVAL(outbuf,smb_vwv7,0);
- SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
-
- if (close_done)
- {
- p = smb_buf(outbuf);
- memset(p,0,9);
-
- CVAL(p,0) = 3;
- SSVAL(p,1,fnum);
- SIVALS(p,3,-1);
-
- /* now set the total packet length */
- smb_setlen(outbuf,smb_len(outbuf)+9);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
- break;
- }
-
- if (close_done &&
- SVAL(inbuf,smb_vwv0) != SMBclose)
- {
- /* NOTE: WfWg sometimes just ignores the chained
- command! This seems to break the spec? */
- DEBUG(3,("Rejected chained close?\n"));
- close_done = False;
- can_chain_close = False;
- ignore_close_error = True;
- }
+ DEBUG(3,("nread=%d\n",nread));
- datalen = SVAL(inbuf,smb_vwv5);
- dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
- break;
+ datalen = cli_read(cli, fnum, data, nread, read_size);
+ if (datalen == -1) {
+ DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
+ break;
+ }
- /* use readbraw */
- case 1:
- {
- static int readbraw_size = 0xFFFF;
-
- extern int Client;
- memset(outbuf,0,smb_size);
- set_message(outbuf,8,0,True);
- CVAL(outbuf,smb_com) = SMBreadbraw;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
- SSVAL(outbuf,smb_vwv0,fnum);
- SIVAL(outbuf,smb_vwv1,nread);
- SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
- SSVAL(outbuf,smb_vwv4,0);
- SIVALS(outbuf,smb_vwv5,-1);
- send_smb(Client,outbuf);
-
- /* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
- DEBUG(0,("Failed to read length in readbraw\n"));
- exit(1);
- }
-
- /* Even though this is not an smb message, smb_len
- returns the generic length of an smb message */
- datalen = smb_len(inbuf);
-
- if (datalen == 0)
- {
- /* we got a readbraw error */
- DEBUG(4,("readbraw error - reducing size\n"));
- readbraw_size = (readbraw_size * 9) / 10;
-
- if (readbraw_size < max_xmit)
- {
- DEBUG(0,("disabling readbraw\n"));
- readbraw_supported = False;
- }
-
- dataptr=NULL;
- continue;
+ nread += datalen;
+
+ /* if file size has increased since we made file size query, truncate
+ read so tar header for this file will be correct.
+ */
+
+ if (nread > finfo.size) {
+ datalen -= nread - finfo.size;
+ DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
}
- if(read_data(Client,inbuf,datalen) != datalen) {
- DEBUG(0,("Failed to read data in readbraw\n"));
- exit(1);
- }
- dataptr = inbuf;
+ /* add received bits of file to buffer - dotarbuf will
+ * write out in 512 byte intervals */
+ if (dotarbuf(tarhandle,data,datalen) != datalen) {
+ DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
+ break;
}
- break;
-
- case 3:
- /* we've already read some data with a chained readX */
- break;
-
- default:
- /* use plain read */
- memset(outbuf,0,smb_size);
- set_message(outbuf,5,0,True);
- CVAL(outbuf,smb_com) = SMBread;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
- SIVAL(outbuf,smb_vwv2,nread);
- SSVAL(outbuf,smb_vwv4,finfo.size - nread);
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
- break;
- }
-
- datalen = SVAL(inbuf,smb_vwv0);
- dataptr = smb_buf(inbuf) + 3;
- break;
- }
-
-
- /* add received bits of file to buffer - dotarbuf will
- * write out in 512 byte intervals */
- if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
- {
- DEBUG(0,("Error writing local file\n"));
- break;
- }
-
- nread += datalen;
- if (datalen == 0)
- {
- DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
- break;
- }
-
- dataptr=NULL;
- datalen=0;
- }
-
+ if (datalen == 0) {
+ DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
+ break;
+ }
+
+ datalen=0;
+ }
+
+ /* pad tar file with zero's if we couldn't get entire file */
+ if (nread < finfo.size) {
+ DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
+ if (padit(data, sizeof(data), finfo.size - nread))
+ DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
+ }
+
/* round tar file to nearest block */
if (finfo.size % TBLOCK)
dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
ntarf++;
}
- if (!close_done)
- {
- memset(outbuf,0,smb_size);
- set_message(outbuf,3,0,True);
- CVAL(outbuf,smb_com) = SMBclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SIVALS(outbuf,smb_vwv1,-1);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
- free(inbuf);free(outbuf);
- return;
- }
- }
+ cli_close(cli, fnum);
if (shallitime)
{
@@ -1078,7 +756,8 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
int this_time;
/* if shallitime is true then we didn't skip */
- if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
+ if (tar_reset && !dry_run)
+ (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
GetTimeOfDay(&tp_end);
this_time =
@@ -1087,13 +766,18 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
get_total_time_ms += this_time;
get_total_size += finfo.size;
+ if (tar_noisy)
+ {
+ DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
+ (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
+ finfo.name));
+ }
+
/* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
finfo.size / MAX(0.001, (1.024*this_time)),
get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
}
-
- free(inbuf);free(outbuf);
}
/****************************************************************************
@@ -1103,25 +787,29 @@ static void do_tar(file_info *finfo)
{
pstring rname;
- if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+ if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
return;
/* Is it on the exclude list ? */
if (!tar_excl && clipn) {
pstring exclaim;
- strcpy(exclaim, cur_dir);
+ DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
+
+ safe_strcpy(exclaim, cur_dir, sizeof(pstring));
*(exclaim+strlen(exclaim)-1)='\0';
- if (clipfind(cliplist, clipn, exclaim)) {
- DEBUG(3,("Skipping directory %s\n", exclaim));
- return;
- }
+ safe_strcat(exclaim, "\\", sizeof(pstring));
+ safe_strcat(exclaim, finfo->name, sizeof(exclaim));
- strcat(exclaim, "\\");
- strcat(exclaim, finfo->name);
+ DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
- if (clipfind(cliplist, clipn, exclaim)) {
+ if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
+#ifdef HAVE_REGEX_H
+ (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
+#else
+ (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
+#endif
DEBUG(3,("Skipping file %s\n", exclaim));
return;
}
@@ -1131,36 +819,33 @@ static void do_tar(file_info *finfo)
{
pstring saved_curdir;
pstring mtar_mask;
- char *inbuf,*outbuf;
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
- return;
- }
+ DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
- strcpy(saved_curdir,cur_dir);
+ safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
+ safe_strcat(cur_dir,"\\", sizeof(cur_dir));
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
+ DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
/* write a tar directory, don't bother with mode - just set it to
* 40755 */
- writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0");
- strcpy(mtar_mask,cur_dir);
- strcat(mtar_mask,"*");
-
- do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse);
- strcpy(cur_dir,saved_curdir);
- free(inbuf);free(outbuf);
+ writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
+ if (tar_noisy) {
+ DEBUG(0,(" directory %s\n", cur_dir));
+ }
+ ntarf++; /* Make sure we have a file on there */
+ safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
+ safe_strcat(mtar_mask,"*", sizeof(pstring));
+ DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
+ do_list(mtar_mask, attribute, do_tar, False, True);
+ safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
}
else
{
- strcpy(rname,cur_dir);
- strcat(rname,finfo->name);
+ safe_strcpy(rname,cur_dir, sizeof(pstring));
+ safe_strcat(rname,finfo->name, sizeof(pstring));
do_atar(rname,finfo->name,finfo);
}
}
@@ -1168,227 +853,423 @@ static void do_tar(file_info *finfo)
/****************************************************************************
Convert from UNIX to DOS file names
***************************************************************************/
-static void unfixtarname(char *tptr, char *fp, int l)
+static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
{
- /* remove '.' from start of file name, convert from unix /'s to
- * dos \'s in path. Kill any absolute path names.
- */
+ /* remove '.' from start of file name, convert from unix /'s to
+ * dos \'s in path. Kill any absolute path names. But only if first!
+ */
- if (*fp == '.') fp++;
- if (*fp == '\\' || *fp == '/') fp++;
-
-#ifdef KANJI
- while (l > 0) {
- if (is_shift_jis (*fp)) {
- *tptr++ = *fp++;
- *tptr++ = *fp++;
- l -= 2;
- } else if (is_kana (*fp)) {
- *tptr++ = *fp++;
- l--;
- } else if (*fp == '/') {
- *tptr++ = '\\';
- fp++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
+ DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
+
+ if (first) {
+ if (*fp == '.') {
+ fp++;
+ l--;
+ }
+ if (*fp == '\\' || *fp == '/') {
+ fp++;
+ l--;
+ }
+ }
+
+ safe_strcpy(tptr, fp, l);
+ string_replace(tptr, '/', '\\');
+}
+
+
+/****************************************************************************
+Move to the next block in the buffer, which may mean read in another set of
+blocks. FIXME, we should allow more than one block to be skipped.
+****************************************************************************/
+static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
+{
+ int bufread, total = 0;
+
+ DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
+ *bufferp += TBLOCK;
+ total = TBLOCK;
+
+ if (*bufferp >= (ltarbuf + bufsiz)) {
+
+ DEBUG(5, ("Reading more data into ltarbuf ...\n"));
+
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where read can return short if coming from
+ * a pipe.
+ */
+
+ bufread = read(tarhandle, ltarbuf, bufsiz);
+ total = bufread;
+
+ while (total < bufsiz) {
+ if (bufread < 0) { /* An error, return false */
+ return (total > 0 ? -2 : bufread);
+ }
+ if (bufread == 0) {
+ if (total <= 0) {
+ return -2;
+ }
+ break;
+ }
+ bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
+ total += bufread;
}
+
+ DEBUG(5, ("Total bytes read ... %i\n", total));
+
+ *bufferp = ltarbuf;
+
}
-#else
- while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
-#endif
+
+ return(total);
+
}
-static void do_tarput()
+/* Skip a file, even if it includes a long file name? */
+static int skip_file(int skipsize)
{
- file_info finfo;
- int nread=0, bufread;
- char *inbuf,*outbuf;
- int fsize=0;
- int fnum;
+ int dsize = skipsize;
+
+ DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
+
+ /* FIXME, we should skip more than one block at a time */
+
+ while (dsize > 0) {
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return(False);
+
+ }
+
+ dsize -= TBLOCK;
+
+ }
+
+ return(True);
+}
+
+/*************************************************************
+ Get a file from the tar file and store it.
+ When this is called, tarbuf already contains the first
+ file block. This is a bit broken & needs fixing.
+**************************************************************/
+
+static int get_file(file_info2 finfo)
+{
+ int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
+
+ DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
+
+ if (ensurepath(finfo.name) &&
+ (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
+ DEBUG(0, ("abandoning restore\n"));
+ return(False);
+ }
+
+ /* read the blocks from the tar file and write to the remote file */
+
+ rsize = finfo.size; /* This is how much to write */
+
+ while (rsize > 0) {
+
+ /* We can only write up to the end of the buffer */
+
+ dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
+ dsize = MIN(dsize, rsize); /* Should be only what is left */
+ DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
+
+ if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
+ DEBUG(0, ("Error writing remote file\n"));
+ return 0;
+ }
+
+ rsize -= dsize;
+ pos += dsize;
+
+ /* Now figure out how much to move in the buffer */
+
+ /* FIXME, we should skip more than one block at a time */
+
+ /* First, skip any initial part of the part written that is left over */
+ /* from the end of the first TBLOCK */
+
+ if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
+
+ dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
+ bpos = 0;
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return False;
+
+ }
+
+ }
+
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
+ * If the file being extracted is an exact multiple of
+ * TBLOCK bytes then we don't want to extract the next
+ * block from the tarfile here, as it will be done in
+ * the caller of get_file().
+ */
+
+ while (((rsize != 0) && (dsize >= TBLOCK)) ||
+ ((rsize == 0) && (dsize > TBLOCK))) {
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return False;
+ }
+
+ dsize -= TBLOCK;
+ }
+
+ bpos = dsize;
+
+ }
+
+ /* Now close the file ... */
+
+ if (!cli_close(cli, fnum)) {
+ DEBUG(0, ("Error closing remote file\n"));
+ return(False);
+ }
+
+ /* Now we update the creation date ... */
+
+ DEBUG(5, ("Updating creation date on %s\n", finfo.name));
+
+ if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
+ if (tar_real_noisy) {
+ DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
+ /*return(False); */ /* Ignore, as Win95 does not allow changes */
+ }
+ }
+
+ ntarf++;
+
+ DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
+
+ return(True);
+}
+
+/* Create a directory. We just ensure that the path exists and return as there
+ is no file associated with a directory
+*/
+static int get_dir(file_info2 finfo)
+{
+
+ DEBUG(0, ("restore directory %s\n", finfo.name));
+
+ if (!ensurepath(finfo.name)) {
+
+ DEBUG(0, ("Problems creating directory\n"));
+ return(False);
+
+ }
+
+ ntarf++;
+ return(True);
+
+}
+/* Get a file with a long file name ... first file has file name, next file
+ has the data. We only want the long file name, as the loop in do_tarput
+ will deal with the rest.
+*/
+static char * get_longfilename(file_info2 finfo)
+{
+ int namesize = finfo.size + strlen(cur_dir) + 2;
+ char *longname = malloc(namesize);
+ int offset = 0, left = finfo.size;
+ BOOL first = True;
+
+ DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
+ DEBUG(5, ("Len = %d\n", (int)finfo.size));
+
+ if (longname == NULL) {
+
+ DEBUG(0, ("could not allocate buffer of size %d for longname\n",
+ (int)(finfo.size + strlen(cur_dir) + 2)));
+ return(NULL);
+ }
+
+ /* First, add cur_dir to the long file name */
+
+ if (strlen(cur_dir) > 0) {
+ strncpy(longname, cur_dir, namesize);
+ offset = strlen(cur_dir);
+ }
+
+ /* Loop through the blocks picking up the name */
+
+ while (left > 0) {
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+ return(NULL);
+
+ }
+
+ unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
+ DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
+
+ offset += TBLOCK;
+ left -= TBLOCK;
+
+ }
+
+ return(longname);
+
+}
+
+static void do_tarput(void)
+{
+ file_info2 finfo;
struct timeval tp_start;
- BOOL tskip=False; /* We'll take each file as it comes */
+ char *longfilename = NULL, linkflag;
+ int skip = False;
GetTimeOfDay(&tp_start);
-
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-
- if (!inbuf || !outbuf)
- {
- DEBUG(0,("out of memory\n"));
+
+ DEBUG(5, ("RJS do_tarput called ...\n"));
+
+ buffer_p = tarbuf + tbufsiz; /* init this to force first read */
+
+ /* Now read through those files ... */
+
+ while (True) {
+
+ /* Get us to the next block, or the first block first time around */
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+
+ DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+
return;
+
}
-
- /*
- * Must read in tbufsiz dollops
- */
- /* These should be the only reads in clitar.c */
- while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
- char *bufferp, *endofbuffer;
- int chunk;
+ DEBUG(5, ("Reading the next header ...\n"));
- /* Code to handle a short read.
- * We always need a TBLOCK full of stuff
- */
- if (bufread % TBLOCK) {
- int lchunk=TBLOCK-(bufread % TBLOCK);
- int lread;
+ switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
+
+ case -2: /* Hmm, not good, but not fatal */
+ DEBUG(0, ("Skipping %s...\n", finfo.name));
+ if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
+ !skip_file(finfo.size)) {
- /* It's a shorty - a short read that is */
- DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
+ DEBUG(0, ("Short file, bailing out...\n"));
+ return;
- while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
- bufread+=lread;
- if (!(lchunk-=lread)) break;
}
- /* If we've reached EOF then that must be a short file */
- if (lread<=0) break;
+ break;
+
+ case -1:
+ DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
+ return;
+
+ case 0: /* chksum is zero - looks like an EOF */
+ DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
+ return; /* Hmmm, bad here ... */
+
+ default:
+ /* No action */
+
+ break;
+
}
- bufferp=tarbuf;
- endofbuffer=tarbuf+bufread;
+ /* Now, do we have a long file name? */
+
+ if (longfilename != NULL) {
+
+ SAFE_FREE(finfo.name); /* Free the space already allocated */
+ finfo.name = longfilename;
+ longfilename = NULL;
- if (tskip) {
- if (fsize<bufread) {
- tskip=False;
- bufferp+=fsize;
- fsize=0;
- } else {
- if (fsize==bufread) tskip=False;
- fsize-=bufread;
- continue;
- }
}
- do {
- if (!fsize)
- {
- switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
- {
- case -2: /* something dodgy but not fatal about this */
- DEBUG(0, ("skipping %s...\n", finfo.name));
- bufferp+=TBLOCK; /* header - like a link */
- continue;
- case -1:
- DEBUG(0, ("abandoning restore\n"));
- free(inbuf); free(outbuf);
- return;
- case 0: /* chksum is zero - we assume that one all zero
- *header block will do for eof */
- DEBUG(0,
- ("total of %d tar files restored to share\n", ntarf));
- free(inbuf); free(outbuf);
- return;
- default:
- break;
- }
-
- tskip=clipn
- && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
- if (tskip) {
- bufferp+=TBLOCK;
- if (finfo.mode & aDIR)
- continue;
- else if ((fsize=finfo.size) % TBLOCK) {
- fsize+=TBLOCK-(fsize%TBLOCK);
- }
- if (fsize<endofbuffer-bufferp) {
- bufferp+=fsize;
- fsize=0;
- continue;
- } else {
- fsize-=endofbuffer-bufferp;
- break;
- }
- }
+ /* Well, now we have a header, process the file ... */
- if (finfo.mode & aDIR)
- {
- if (!smbchkpath(finfo.name, inbuf, outbuf)
- && !smbmkdir(finfo.name, inbuf, outbuf))
- {
- DEBUG(0, ("abandoning restore\n"));
- free(inbuf); free(outbuf);
- return;
- }
- else
- {
- bufferp+=TBLOCK;
- continue;
- }
- }
-
- fsize=finfo.size;
-
- if (ensurepath(finfo.name, inbuf, outbuf)
- && !smbcreat(finfo, &fnum, inbuf, outbuf))
- {
- DEBUG(0, ("abandoning restore\n"));
- free(inbuf);free(outbuf);
- return;
- }
-
- DEBUG(0,("restore tar file %s of size %d bytes\n",
- finfo.name,finfo.size));
-
- nread=0;
- if ((bufferp+=TBLOCK) >= endofbuffer) break;
- } /* if (!fsize) */
-
- /* write out the file in chunk sized chunks - don't
- * go past end of buffer though */
- chunk=(fsize-nread < endofbuffer - bufferp)
- ? fsize - nread : endofbuffer - bufferp;
-
- while (chunk > 0) {
- int minichunk=MIN(chunk, max_xmit-200);
-
- if (!smbwrite(fnum, /* file descriptor */
- minichunk, /* n */
- nread, /* offset low */
- 0, /* offset high - not implemented */
- fsize-nread, /* left - only hint to server */
- bufferp,
- inbuf,
- outbuf))
- {
- DEBUG(0, ("Error writing remote file\n"));
- free(inbuf); free(outbuf);
- return;
- }
- DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
-
- bufferp+=minichunk; nread+=minichunk;
- chunk-=minichunk;
+ /* Should we skip the file? We have the long name as well here */
+
+ skip = clipn &&
+ ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
+#ifdef HAVE_REGEX_H
+ || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
+#else
+ || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
+#endif
+
+ DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
+
+ if (skip) {
+
+ skip_file(finfo.size);
+ continue;
+
+ }
+
+ /* We only get this far if we should process the file */
+ linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
+
+ switch (linkflag) {
+
+ case '0': /* Should use symbolic names--FIXME */
+
+ /*
+ * Skip to the next block first, so we can get the file, FIXME, should
+ * be in get_file ...
+ * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where file size in tarfile is zero.
+ */
+
+ if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ DEBUG(0, ("Short file, bailing out...\n"));
+ return;
}
-
- if (nread>=fsize)
- {
- if (!smbshut(finfo, fnum, inbuf, outbuf))
- {
- DEBUG(0, ("Error closing remote file\n"));
- free(inbuf);free(outbuf);
- return;
- }
- if (fsize % TBLOCK) bufferp+=TBLOCK - (fsize % TBLOCK);
- DEBUG(5, ("bufferp is now %d (psn=%d)\n",
- (long) bufferp, (long)(bufferp - tarbuf)));
- ntarf++;
- fsize=0;
- }
- } while (bufferp < endofbuffer);
+ if (!get_file(finfo)) {
+ DEBUG(0, ("Abandoning restore\n"));
+ return;
+
+ }
+ break;
+
+ case '5':
+ if (!get_dir(finfo)) {
+ DEBUG(0, ("Abandoning restore \n"));
+ return;
+ }
+ break;
+
+ case 'L':
+ longfilename = get_longfilename(finfo);
+ if (!longfilename) {
+ DEBUG(0, ("abandoning restore\n"));
+ return;
+
+ }
+ DEBUG(5, ("Long file name: %s\n", longfilename));
+ break;
+
+ default:
+ skip_file(finfo.size); /* Don't handle these yet */
+ break;
+
+ }
+
}
- DEBUG(0, ("premature eof on tar file ?\n"));
- DEBUG(0,("total of %d tar files restored to share\n", ntarf));
- free(inbuf); free(outbuf);
}
+
/*
* samba interactive commands
*/
@@ -1396,36 +1277,38 @@ static void do_tarput()
/****************************************************************************
Blocksize command
***************************************************************************/
-void cmd_block(void)
+int cmd_block(void)
{
fstring buf;
int block;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0, ("blocksize <n>\n"));
- return;
+ return 1;
}
block=atoi(buf);
if (block < 0 || block > 65535)
{
DEBUG(0, ("blocksize out of range"));
- return;
+ return 1;
}
blocksize=block;
DEBUG(2,("blocksize is now %d\n", blocksize));
+
+ return 0;
}
/****************************************************************************
command to set incremental / reset mode
***************************************************************************/
-void cmd_tarmode(void)
+int cmd_tarmode(void)
{
fstring buf;
- while (next_token(NULL,buf,NULL)) {
+ while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
if (strequal(buf, "full"))
tar_inc=False;
else if (strequal(buf, "inc"))
@@ -1434,37 +1317,54 @@ void cmd_tarmode(void)
tar_reset=True;
else if (strequal(buf, "noreset"))
tar_reset=False;
+ else if (strequal(buf, "system"))
+ tar_system=True;
+ else if (strequal(buf, "nosystem"))
+ tar_system=False;
+ else if (strequal(buf, "hidden"))
+ tar_hidden=True;
+ else if (strequal(buf, "nohidden"))
+ tar_hidden=False;
+ else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
+ tar_noisy=True;
+ else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
+ tar_noisy=False;
else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
}
- DEBUG(0, ("tarmode is now %s, %s\n",
+ DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
tar_inc ? "incremental" : "full",
- tar_reset ? "reset" : "noreset"));
+ tar_system ? "system" : "nosystem",
+ tar_hidden ? "hidden" : "nohidden",
+ tar_reset ? "reset" : "noreset",
+ tar_noisy ? "verbose" : "quiet"));
+
+ return 0;
}
/****************************************************************************
Feeble attrib command
***************************************************************************/
-void cmd_setmode(void)
+int cmd_setmode(void)
{
char *q;
fstring buf;
pstring fname;
- int attra[2];
+ uint16 attra[2];
int direct=1;
attra[0] = attra[1] = 0;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
- DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
- return;
+ DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
+ return 1;
}
- strcpy(fname, cur_dir);
- strcat(fname, buf);
+ safe_strcpy(fname, cur_dir, sizeof(pstring));
+ safe_strcat(fname, buf, sizeof(pstring));
- while (next_token(NULL,buf,NULL)) {
+ while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
q=buf;
while(*q)
@@ -1482,55 +1382,64 @@ void cmd_setmode(void)
case 'a': attra[direct]|=aARCH;
break;
default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
- return;
+ return 1;
}
}
if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
{
- DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
- return;
+ DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
+ return 1;
}
-DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
- (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
- (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
+ DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+ do_setrattr(fname, attra[ATTRSET], ATTRSET);
+ do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
+
+ return 0;
}
/****************************************************************************
Principal command for creating / extracting
***************************************************************************/
-void cmd_tar(char *inbuf, char *outbuf)
+int cmd_tar(void)
{
fstring buf;
char **argl;
int argcl;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
- DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
- return;
+ DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
+ return 1;
}
argl=toktocliplist(&argcl, NULL);
if (!tar_parseargs(argcl, argl, buf, 0))
- return;
+ return 1;
- process_tar(inbuf, outbuf);
+ process_tar();
- free(argl);
+ SAFE_FREE(argl);
+
+ return 0;
}
/****************************************************************************
Command line (option) version
***************************************************************************/
-int process_tar(char *inbuf, char *outbuf)
+int process_tar(void)
{
initarbuf();
switch(tar_type) {
case 'x':
+
+#if 0
+ do_tarput2();
+#else
do_tarput();
- free(tarbuf);
+#endif
+ SAFE_FREE(tarbuf);
close(tarhandle);
break;
case 'r':
@@ -1540,67 +1449,82 @@ int process_tar(char *inbuf, char *outbuf)
pstring tarmac;
for (i=0; i<clipn; i++) {
- DEBUG(0,("arg %d = %s\n", i, cliplist[i]));
+ DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
*(cliplist[i]+strlen(cliplist[i])-1)='\0';
}
- if (strrchr(cliplist[i], '\\')) {
+ if (strrchr_m(cliplist[i], '\\')) {
pstring saved_dir;
- strcpy(saved_dir, cur_dir);
+ safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
if (*cliplist[i]=='\\') {
- strcpy(tarmac, cliplist[i]);
+ safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
} else {
- strcpy(tarmac, cur_dir);
- strcat(tarmac, cliplist[i]);
+ safe_strcpy(tarmac, cur_dir, sizeof(pstring));
+ safe_strcat(tarmac, cliplist[i], sizeof(pstring));
}
- strcpy(cur_dir, tarmac);
- *(strrchr(cur_dir, '\\')+1)='\0';
+ safe_strcpy(cur_dir, tarmac, sizeof(pstring));
+ *(strrchr_m(cur_dir, '\\')+1)='\0';
- do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
- strcpy(cur_dir,saved_dir);
+ DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
+ do_list(tarmac,attribute,do_tar, False, True);
+ safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
} else {
- strcpy(tarmac, cur_dir);
- strcat(tarmac, cliplist[i]);
- do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
+ safe_strcpy(tarmac, cur_dir, sizeof(pstring));
+ safe_strcat(tarmac, cliplist[i], sizeof(pstring));
+ DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
+ do_list(tarmac,attribute,do_tar, False, True);
}
}
} else {
pstring mask;
- strcpy(mask,cur_dir);
- strcat(mask,"\\*");
- do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse);
+ safe_strcpy(mask,cur_dir, sizeof(pstring));
+ DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
+ safe_strcat(mask,"\\*", sizeof(pstring));
+ do_list(mask,attribute,do_tar,False, True);
}
if (ntarf) dotareof(tarhandle);
close(tarhandle);
- free(tarbuf);
+ SAFE_FREE(tarbuf);
- DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
+ DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
+ DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
break;
}
+ if (must_free_cliplist) {
+ int i;
+ for (i = 0; i < clipn; ++i) {
+ SAFE_FREE(cliplist[i]);
+ }
+ SAFE_FREE(cliplist);
+ cliplist = NULL;
+ clipn = 0;
+ must_free_cliplist = False;
+ }
+
return(0);
}
/****************************************************************************
Find a token (filename) in a clip list
***************************************************************************/
-int clipfind(char **aret, int ret, char *tok)
+static int clipfind(char **aret, int ret, char *tok)
{
if (aret==NULL) return 0;
/* ignore leading slashes or dots in token */
- while(strchr("/\\.", *tok)) tok++;
+ while(strchr_m("/\\.", *tok)) tok++;
while(ret--) {
char *pkey=*aret++;
/* ignore leading slashes or dots in list */
- while(strchr("/\\.", *pkey)) pkey++;
+ while(strchr_m("/\\.", *pkey)) pkey++;
if (!strslashcmp(pkey, tok)) return 1;
}
@@ -1609,6 +1533,114 @@ int clipfind(char **aret, int ret, char *tok)
}
/****************************************************************************
+Read list of files to include from the file and initialize cliplist
+accordingly.
+***************************************************************************/
+static int read_inclusion_file(char *filename)
+{
+ XFILE *inclusion = NULL;
+ char buf[MAXPATHLEN + 1];
+ char *inclusion_buffer = NULL;
+ int inclusion_buffer_size = 0;
+ int inclusion_buffer_sofar = 0;
+ char *p;
+ char *tmpstr;
+ int i;
+ int error = 0;
+
+ clipn = 0;
+ buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
+ if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
+ /* XXX It would be better to include a reason for failure, but without
+ * autoconf, it's hard to use strerror, sys_errlist, etc.
+ */
+ DEBUG(0,("Unable to open inclusion file %s\n", filename));
+ return 0;
+ }
+
+ while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
+ if (inclusion_buffer == NULL) {
+ inclusion_buffer_size = 1024;
+ if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
+ DEBUG(0,("failure allocating buffer to read inclusion file\n"));
+ error = 1;
+ break;
+ }
+ }
+
+ if (buf[strlen(buf)-1] == '\n') {
+ buf[strlen(buf)-1] = '\0';
+ }
+
+ if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
+ char *ib;
+ inclusion_buffer_size *= 2;
+ ib = Realloc(inclusion_buffer,inclusion_buffer_size);
+ if (! ib) {
+ DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
+ inclusion_buffer_size));
+ error = 1;
+ break;
+ }
+ else inclusion_buffer = ib;
+ }
+
+ safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
+ inclusion_buffer_sofar += strlen(buf) + 1;
+ clipn++;
+ }
+ x_fclose(inclusion);
+
+ if (! error) {
+ /* Allocate an array of clipn + 1 char*'s for cliplist */
+ cliplist = malloc((clipn + 1) * sizeof(char *));
+ if (cliplist == NULL) {
+ DEBUG(0,("failure allocating memory for cliplist\n"));
+ error = 1;
+ } else {
+ cliplist[clipn] = NULL;
+ p = inclusion_buffer;
+ for (i = 0; (! error) && (i < clipn); i++) {
+ /* set current item to NULL so array will be null-terminated even if
+ * malloc fails below. */
+ cliplist[i] = NULL;
+ if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
+ DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
+ error = 1;
+ } else {
+ unfixtarname(tmpstr, p, strlen(p) + 1, True);
+ cliplist[i] = tmpstr;
+ if ((p = strchr_m(p, '\000')) == NULL) {
+ DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
+ abort();
+ }
+ }
+ ++p;
+ }
+ must_free_cliplist = True;
+ }
+ }
+
+ SAFE_FREE(inclusion_buffer);
+ if (error) {
+ if (cliplist) {
+ char **pp;
+ /* We know cliplist is always null-terminated */
+ for (pp = cliplist; *pp; ++pp) {
+ SAFE_FREE(*pp);
+ }
+ SAFE_FREE(cliplist);
+ cliplist = NULL;
+ must_free_cliplist = False;
+ }
+ return 0;
+ }
+
+ /* cliplist and its elements are freed at the end of process_tar. */
+ return 1;
+}
+
+/****************************************************************************
Parse tar arguments. Sets tar_type, tar_excl, etc.
***************************************************************************/
int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
@@ -1620,6 +1652,7 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
*/
tar_type='\0';
tar_excl=True;
+ dry_run=False;
while (*Optarg)
switch(*Optarg++) {
@@ -1649,13 +1682,13 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
DEBUG(0,("Option N must be followed by valid file name\n"));
return 0;
} else {
- struct stat stbuf;
+ SMB_STRUCT_STAT stbuf;
extern time_t newer_than;
if (sys_stat(argv[Optind], &stbuf) == 0) {
newer_than = stbuf.st_mtime;
DEBUG(1,("Getting files newer than %s",
- asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
+ asctime(LocalTime(&newer_than))));
Optind++;
} else {
DEBUG(0,("Error setting newer-than time\n"));
@@ -1666,20 +1699,43 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
case 'a':
tar_reset=True;
break;
+ case 'q':
+ tar_noisy=False;
+ break;
case 'I':
if (tar_clipfl) {
- DEBUG(0,("Only one of I,X must be specified\n"));
+ DEBUG(0,("Only one of I,X,F must be specified\n"));
return 0;
}
tar_clipfl='I';
break;
case 'X':
if (tar_clipfl) {
- DEBUG(0,("Only one of I,X must be specified\n"));
+ DEBUG(0,("Only one of I,X,F must be specified\n"));
return 0;
}
tar_clipfl='X';
break;
+ case 'F':
+ if (tar_clipfl) {
+ DEBUG(0,("Only one of I,X,F must be specified\n"));
+ return 0;
+ }
+ tar_clipfl='F';
+ break;
+ case 'r':
+ DEBUG(0, ("tar_re_search set\n"));
+ tar_re_search = True;
+ break;
+ case 'n':
+ if (tar_type == 'c') {
+ DEBUG(0, ("dry_run set\n"));
+ dry_run = True;
+ } else {
+ DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
+ return 0;
+ }
+ break;
default:
DEBUG(0,("Unknown tar option\n"));
return 0;
@@ -1690,21 +1746,105 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
return 0;
}
+ /* tar_excl is true if cliplist lists files to be included.
+ * Both 'I' and 'F' mean include. */
+ tar_excl=tar_clipfl!='X';
+
+ if (tar_clipfl=='F') {
+ if (argc-Optind-1 != 1) {
+ DEBUG(0,("Option F must be followed by exactly one filename.\n"));
+ return 0;
+ }
+ if (! read_inclusion_file(argv[Optind+1])) {
+ return 0;
+ }
+ } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
+ char *tmpstr;
+ char **tmplist;
+ int clipcount;
+
+ cliplist=argv+Optind+1;
+ clipn=argc-Optind-1;
+ clipcount = clipn;
+
+ if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
+ DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
+ clipn)
+ );
+ return 0;
+ }
+
+ for (clipcount = 0; clipcount < clipn; clipcount++) {
+
+ DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
+
+ if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
+ DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
+ clipcount)
+ );
+ return 0;
+ }
+ unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
+ tmplist[clipcount] = tmpstr;
+ DEBUG(5, ("Processed an item, %s\n", tmpstr));
+
+ DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
+ }
+ cliplist = tmplist;
+ must_free_cliplist = True;
+ }
+
+ if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
+#ifdef HAVE_REGEX_H
+ int errcode;
+
+ if ((preg = (regex_t *)malloc(65536)) == NULL) {
+
+ DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
+ return;
+
+ }
+
+ if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
+ char errstr[1024];
+ size_t errlen;
+
+ errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
+
+ DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
+ return;
+
+ }
+#endif
+
+ clipn=argc-Optind-1;
+ cliplist=argv+Optind+1;
+
+ }
+
if (Optind>=argc || !strcmp(argv[Optind], "-")) {
/* Sets tar handle to either 0 or 1, as appropriate */
tarhandle=(tar_type=='c');
+ /*
+ * Make sure that dbf points to stderr if we are using stdout for
+ * tar output
+ */
+ if (tarhandle == 1)
+ dbf = x_stderr;
} else {
- tar_excl=tar_clipfl!='X';
-
- if (Optind+1<argc) {
- cliplist=argv+Optind+1;
- clipn=argc-Optind-1;
- }
-
- if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
- || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
+ if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
+ {
+ if (!dry_run) {
+ DEBUG(0,("Output is /dev/null, assuming dry_run"));
+ dry_run = True;
+ }
+ tarhandle=-1;
+ } else
+ if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
+ || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0))
{
- DEBUG(0,("Error opening local file %s\n",argv[Optind]));
+ DEBUG(0,("Error opening local file %s - %s\n",
+ argv[Optind], strerror(errno)));
return(0);
}
}
diff --git a/source/client/smbmnt.c b/source/client/smbmnt.c
new file mode 100644
index 00000000000..36248987b1e
--- /dev/null
+++ b/source/client/smbmnt.c
@@ -0,0 +1,306 @@
+/*
+ * smbmnt.c
+ *
+ * Copyright (C) 1995-1998 by Paal-Kr. Engstad and Volker Lendecke
+ * extensively modified by Tridge
+ *
+ */
+
+#include "includes.h"
+
+#include <mntent.h>
+#include <sys/utsname.h>
+
+#include <asm/types.h>
+#include <asm/posix_types.h>
+#include <linux/smb.h>
+#include <linux/smb_mount.h>
+#include <asm/unistd.h>
+
+#ifndef MS_MGC_VAL
+/* This may look strange but MS_MGC_VAL is what we are looking for and
+ is what we need from <linux/fs.h> under libc systems and is
+ provided in standard includes on glibc systems. So... We
+ switch on what we need... */
+#include <linux/fs.h>
+#endif
+
+static uid_t mount_uid;
+static gid_t mount_gid;
+static int mount_ro;
+static unsigned mount_fmask;
+static unsigned mount_dmask;
+static int user_mount;
+static char *options;
+
+static void
+help(void)
+{
+ printf("\n");
+ printf("Usage: smbmnt mount-point [options]\n");
+ printf("Version %s\n\n",VERSION);
+ printf("-s share share name on server\n"
+ "-r mount read-only\n"
+ "-u uid mount as uid\n"
+ "-g gid mount as gid\n"
+ "-f mask permission mask for files\n"
+ "-d mask permission mask for directories\n"
+ "-o options name=value, list of options\n"
+ "-h print this help text\n");
+}
+
+static int
+parse_args(int argc, char *argv[], struct smb_mount_data *data, char **share)
+{
+ int opt;
+
+ while ((opt = getopt (argc, argv, "s:u:g:rf:d:o:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 's':
+ *share = optarg;
+ break;
+ case 'u':
+ if (!user_mount) {
+ mount_uid = strtol(optarg, NULL, 0);
+ }
+ break;
+ case 'g':
+ if (!user_mount) {
+ mount_gid = strtol(optarg, NULL, 0);
+ }
+ break;
+ case 'r':
+ mount_ro = 1;
+ break;
+ case 'f':
+ mount_fmask = strtol(optarg, NULL, 8);
+ break;
+ case 'd':
+ mount_dmask = strtol(optarg, NULL, 8);
+ break;
+ case 'o':
+ options = optarg;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return 0;
+
+}
+
+static char *
+fullpath(const char *p)
+{
+ char path[MAXPATHLEN];
+
+ if (strlen(p) > MAXPATHLEN-1) {
+ return NULL;
+ }
+
+ if (realpath(p, path) == NULL) {
+ fprintf(stderr,"Failed to find real path for mount point\n");
+ exit(1);
+ }
+ return strdup(path);
+}
+
+/* Check whether user is allowed to mount on the specified mount point. If it's
+ OK then we change into that directory - this prevents race conditions */
+static int mount_ok(char *mount_point)
+{
+ SMB_STRUCT_STAT st;
+
+ if (chdir(mount_point) != 0) {
+ return -1;
+ }
+
+ if (sys_stat(".", &st) != 0) {
+ return -1;
+ }
+
+ 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;
+}
+
+/* Tries to mount using the appropriate format. For 2.2 the struct,
+ for 2.4 the ascii version. */
+static int
+do_mount(char *share_name, unsigned int flags, struct smb_mount_data *data)
+{
+ pstring opts;
+ struct utsname uts;
+ char *release, *major, *minor;
+ char *data1, *data2;
+
+ uname(&uts);
+ release = uts.release;
+ major = strsep(&release, ".");
+ minor = strsep(&release, ".");
+ if (major && minor && atoi(major) == 2 && atoi(minor) < 4) {
+ /* < 2.4, assume struct */
+ data1 = (char *) data;
+ data2 = opts;
+ } else {
+ /* >= 2.4, assume ascii but fall back on struct */
+ data1 = opts;
+ data2 = (char *) data;
+ }
+
+ slprintf(opts, sizeof(opts)-1,
+ "version=7,uid=%d,gid=%d,file_mode=0%o,dir_mode=0%o,%s",
+ data->uid, data->gid, data->file_mode, data->dir_mode,options);
+ if (mount(share_name, ".", "smbfs", flags, data1) == 0)
+ return 0;
+ return mount(share_name, ".", "smbfs", flags, data2);
+}
+
+ int main(int argc, char *argv[])
+{
+ char *mount_point, *share_name = NULL;
+ FILE *mtab;
+ int fd;
+ unsigned int flags;
+ struct smb_mount_data data;
+ struct mntent ment;
+
+ memset(&data, 0, sizeof(struct smb_mount_data));
+
+ if (argc < 2) {
+ help();
+ exit(1);
+ }
+
+ if (argv[1][0] == '-') {
+ help();
+ exit(1);
+ }
+
+ if (getuid() != 0) {
+ user_mount = 1;
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "smbmnt must be installed suid root for direct user mounts (%d,%d)\n", getuid(), geteuid());
+ exit(1);
+ }
+
+ mount_uid = getuid();
+ mount_gid = getgid();
+ mount_fmask = umask(0);
+ umask(mount_fmask);
+ mount_fmask = ~mount_fmask;
+
+ mount_point = fullpath(argv[1]);
+
+ argv += 1;
+ argc -= 1;
+
+ if (mount_ok(mount_point) != 0) {
+ fprintf(stderr, "cannot mount on %s: %s\n",
+ mount_point, strerror(errno));
+ exit(1);
+ }
+
+ data.version = SMB_MOUNT_VERSION;
+
+ /* getuid() gives us the real uid, who may umount the fs */
+ data.mounted_uid = getuid();
+
+ if (parse_args(argc, argv, &data, &share_name) != 0) {
+ help();
+ return -1;
+ }
+
+ data.uid = mount_uid;
+ data.gid = mount_gid;
+ data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_fmask;
+ data.dir_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_dmask;
+
+ if (mount_dmask == 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;
+ }
+
+ flags = MS_MGC_VAL;
+
+ if (mount_ro) flags |= MS_RDONLY;
+
+ if (do_mount(share_name, flags, &data) < 0) {
+ switch (errno) {
+ case ENODEV:
+ fprintf(stderr, "ERROR: smbfs filesystem not supported by the kernel\n");
+ break;
+ default:
+ perror("mount error");
+ }
+ fprintf(stderr, "Please refer to the smbmnt(8) manual page\n");
+ return -1;
+ }
+
+ ment.mnt_fsname = share_name ? share_name : "none";
+ ment.mnt_dir = mount_point;
+ ment.mnt_type = "smbfs";
+ ment.mnt_opts = "";
+ ment.mnt_freq = 0;
+ ment.mnt_passno= 0;
+
+ mount_point = ment.mnt_dir;
+
+ if (mount_point == NULL)
+ {
+ fprintf(stderr, "Mount point too long\n");
+ return -1;
+ }
+
+ 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/source/client/smbmount.c b/source/client/smbmount.c
new file mode 100644
index 00000000000..2b5617ceb5c
--- /dev/null
+++ b/source/client/smbmount.c
@@ -0,0 +1,881 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0.
+ SMBFS mount program
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#include <mntent.h>
+#include <asm/types.h>
+#include <linux/smb_fs.h>
+
+extern BOOL in_client;
+extern pstring user_socket_options;
+extern BOOL append_log;
+extern fstring remote_machine;
+
+static pstring credentials;
+static pstring my_netbios_name;
+static pstring password;
+static pstring username;
+static pstring workgroup;
+static pstring mpoint;
+static pstring service;
+static pstring options;
+
+static struct in_addr dest_ip;
+static BOOL have_ip;
+static int smb_port = 0;
+static BOOL got_pass;
+static uid_t mount_uid;
+static gid_t mount_gid;
+static int mount_ro;
+static unsigned mount_fmask;
+static unsigned mount_dmask;
+
+static void usage(void);
+
+static void exit_parent(int sig)
+{
+ /* parent simply exits when child says go... */
+ exit(0);
+}
+
+static void daemonize(void)
+{
+ int j, status;
+ pid_t child_pid;
+
+ signal( SIGTERM, exit_parent );
+
+ if ((child_pid = sys_fork()) < 0) {
+ DEBUG(0,("could not fork\n"));
+ }
+
+ if (child_pid > 0) {
+ while( 1 ) {
+ j = waitpid( child_pid, &status, 0 );
+ if( j < 0 ) {
+ if( EINTR == errno ) {
+ continue;
+ }
+ status = errno;
+ }
+ break;
+ }
+ /* If we get here - the child exited with some error status */
+ exit(status);
+ }
+
+ signal( SIGTERM, SIG_DFL );
+ chdir("/");
+}
+
+static void close_our_files(int client_fd)
+{
+ int i;
+ struct rlimit limits;
+
+ getrlimit(RLIMIT_NOFILE,&limits);
+ for (i = 0; i< limits.rlim_max; i++) {
+ if (i == client_fd)
+ continue;
+ close(i);
+ }
+}
+
+static void usr1_handler(int x)
+{
+ return;
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct cli_state *do_connection(char *the_service)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ struct in_addr ip;
+ pstring server;
+ char *share;
+
+ if (the_service[0] != '\\' || the_service[1] != '\\') {
+ usage();
+ exit(1);
+ }
+
+ pstrcpy(server, the_service+2);
+ share = strchr_m(server,'\\');
+ if (!share) {
+ usage();
+ exit(1);
+ }
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ make_nmb_name(&calling, my_netbios_name, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_ip(&ip);
+ if (have_ip) ip = dest_ip;
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) != smb_port) ||
+ !cli_connect(c, server_n, &ip)) {
+ DEBUG(0,("%d: Connection to %s failed\n", getpid(), server_n));
+ if (c) {
+ cli_shutdown(c);
+ }
+ return NULL;
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ char *p;
+ DEBUG(0,("%d: session request to %s failed (%s)\n",
+ getpid(), called.name, cli_errstr(c)));
+ cli_shutdown(c);
+ if ((p=strchr_m(called.name, '.'))) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,("%d: session request ok\n", getpid()));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("%d: protocol negotiation failed\n", getpid()));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ /* This should be right for current smbfs. Future versions will support
+ large files as well as unicode and oplocks. */
+ c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
+ CAP_NT_FIND | CAP_STATUS32 | CAP_LEVEL_II_OPLOCKS);
+ c->force_dos_errors = True;
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ /* if a password was not supplied then try again with a
+ null username */
+ if (password[0] || !username[0] ||
+ !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
+ DEBUG(0,("%d: session setup failed: %s\n",
+ getpid(), cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+ DEBUG(0,("Anonymous login successful\n"));
+ }
+
+ DEBUG(4,("%d: session setup ok\n", getpid()));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("%d: tree connect failed: %s\n",
+ getpid(), cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,("%d: tconx ok\n", getpid()));
+
+ got_pass = True;
+
+ return c;
+}
+
+
+/****************************************************************************
+unmount smbfs (this is a bailout routine to clean up if a reconnect fails)
+ Code blatently stolen from smbumount.c
+ -mhw-
+****************************************************************************/
+static void smb_umount(char *mount_point)
+{
+ int fd;
+ struct mntent *mnt;
+ FILE* mtab;
+ FILE* new_mtab;
+
+ /* Programmers Note:
+ This routine only gets called to the scene of a disaster
+ to shoot the survivors... A connection that was working
+ has now apparently failed. We have an active mount point
+ (presumably) that we need to dump. If we get errors along
+ the way - make some noise, but we are already turning out
+ the lights to exit anyways...
+ */
+ if (umount(mount_point) != 0) {
+ DEBUG(0,("%d: Could not umount %s: %s\n",
+ getpid(), mount_point, strerror(errno)));
+ return;
+ }
+
+ if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
+ DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", getpid()));
+ return;
+ }
+
+ close(fd);
+
+ if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
+ DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
+ getpid(), strerror(errno)));
+ return;
+ }
+
+#define MOUNTED_TMP MOUNTED".tmp"
+
+ if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
+ DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
+ getpid(), strerror(errno)));
+ endmntent(mtab);
+ return;
+ }
+
+ while ((mnt = getmntent(mtab)) != NULL) {
+ if (strcmp(mnt->mnt_dir, mount_point) != 0) {
+ addmntent(new_mtab, mnt);
+ }
+ }
+
+ endmntent(mtab);
+
+ if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+ DEBUG(0,("%d: Error changing mode of %s: %s\n",
+ getpid(), MOUNTED_TMP, strerror(errno)));
+ return;
+ }
+
+ endmntent(new_mtab);
+
+ if (rename(MOUNTED_TMP, MOUNTED) < 0) {
+ DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
+ getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
+ return;
+ }
+
+ if (unlink(MOUNTED"~") == -1) {
+ DEBUG(0,("%d: Can't remove "MOUNTED"~", getpid()));
+ return;
+ }
+}
+
+
+/*
+ * Call the smbfs ioctl to install a connection socket,
+ * then wait for a signal to reconnect. Note that we do
+ * not exit after open_sockets() or send_login() errors,
+ * as the smbfs mount would then have no way to recover.
+ */
+static void send_fs_socket(char *the_service, char *mount_point, struct cli_state *c)
+{
+ int fd, closed = 0, res = 1;
+ pid_t parentpid = getppid();
+ struct smb_conn_opt conn_options;
+
+ memset(&conn_options, 0, sizeof(conn_options));
+
+ while (1) {
+ if ((fd = open(mount_point, O_RDONLY)) < 0) {
+ DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
+ getpid(), mount_point));
+ break;
+ }
+
+ conn_options.fd = c->fd;
+ conn_options.protocol = c->protocol;
+ conn_options.case_handling = SMB_CASE_DEFAULT;
+ conn_options.max_xmit = c->max_xmit;
+ conn_options.server_uid = c->vuid;
+ conn_options.tid = c->cnum;
+ conn_options.secmode = c->sec_mode;
+ conn_options.rawmode = 0;
+ conn_options.sesskey = c->sesskey;
+ conn_options.maxraw = 0;
+ conn_options.capabilities = c->capabilities;
+ conn_options.serverzone = c->serverzone/60;
+
+ res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
+ if (res != 0) {
+ DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
+ getpid(), res));
+ close(fd);
+ break;
+ }
+
+ if (parentpid) {
+ /* Ok... We are going to kill the parent. Now
+ is the time to break the process group... */
+ setsid();
+ /* Send a signal to the parent to terminate */
+ kill(parentpid, SIGTERM);
+ parentpid = 0;
+ }
+
+ close(fd);
+
+ /* This looks wierd but we are only closing the userspace
+ side, the connection has already been passed to smbfs and
+ it has increased the usage count on the socket.
+
+ If we don't do this we will "leak" sockets and memory on
+ each reconnection we have to make. */
+ cli_shutdown(c);
+ c = NULL;
+
+ if (!closed) {
+ /* redirect stdout & stderr since we can't know that
+ the library functions we use are using DEBUG. */
+ if ( (fd = open("/dev/null", O_WRONLY)) < 0)
+ DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
+ close_our_files(fd);
+ if (fd >= 0) {
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
+ }
+
+ /* here we are no longer interactive */
+ pstrcpy(remote_machine, "smbmount"); /* sneaky ... */
+ setup_logging("mount.smbfs", False);
+ append_log = True;
+ reopen_logs();
+ DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, getpid()));
+
+ closed = 1;
+ }
+
+ /* Wait for a signal from smbfs ... but don't continue
+ until we actually get a new connection. */
+ while (!c) {
+ CatchSignal(SIGUSR1, &usr1_handler);
+ pause();
+ DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", getpid()));
+ c = do_connection(the_service);
+ }
+ }
+
+ smb_umount(mount_point);
+ DEBUG(2,("mount.smbfs[%d]: exit\n", getpid()));
+ exit(1);
+}
+
+
+/**
+ * Mount a smbfs
+ **/
+static void init_mount(void)
+{
+ char mount_point[MAXPATHLEN+1];
+ pstring tmp;
+ pstring svc2;
+ struct cli_state *c;
+ char *args[20];
+ int i, status;
+
+ if (realpath(mpoint, mount_point) == NULL) {
+ fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
+ return;
+ }
+
+
+ c = do_connection(service);
+ if (!c) {
+ fprintf(stderr,"SMB connection failed\n");
+ exit(1);
+ }
+
+ /*
+ Set up to return as a daemon child and wait in the parent
+ until the child say it's ready...
+ */
+ daemonize();
+
+ pstrcpy(svc2, service);
+ string_replace(svc2, '\\','/');
+ string_replace(svc2, ' ','_');
+
+ memset(args, 0, sizeof(args[0])*20);
+
+ i=0;
+ args[i++] = "smbmnt";
+
+ args[i++] = mount_point;
+ args[i++] = "-s";
+ args[i++] = svc2;
+
+ if (mount_ro) {
+ args[i++] = "-r";
+ }
+ if (mount_uid) {
+ slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
+ args[i++] = "-u";
+ args[i++] = smb_xstrdup(tmp);
+ }
+ if (mount_gid) {
+ slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
+ args[i++] = "-g";
+ args[i++] = smb_xstrdup(tmp);
+ }
+ if (mount_fmask) {
+ slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
+ args[i++] = "-f";
+ args[i++] = smb_xstrdup(tmp);
+ }
+ if (mount_dmask) {
+ slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
+ args[i++] = "-d";
+ args[i++] = smb_xstrdup(tmp);
+ }
+ if (options) {
+ args[i++] = "-o";
+ args[i++] = options;
+ }
+
+ if (sys_fork() == 0) {
+ char *smbmnt_path;
+
+ asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
+
+ if (file_exist(smbmnt_path, NULL)) {
+ execv(smbmnt_path, args);
+ fprintf(stderr,
+ "smbfs/init_mount: execv of %s failed. Error was %s.",
+ smbmnt_path, strerror(errno));
+ } else {
+ execvp("smbmnt", args);
+ fprintf(stderr,
+ "smbfs/init_mount: execv of %s failed. Error was %s.",
+ "smbmnt", strerror(errno));
+ }
+ free(smbmnt_path);
+ exit(1);
+ }
+
+ if (waitpid(-1, &status, 0) == -1) {
+ fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
+ /* FIXME: do some proper error handling */
+ exit(1);
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+ fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
+ /* FIXME: do some proper error handling */
+ exit(1);
+ }
+
+ /* Ok... This is the rubicon for that mount point... At any point
+ after this, if the connections fail and can not be reconstructed
+ for any reason, we will have to unmount the mount point. There
+ is no exit from the next call...
+ */
+ send_fs_socket(service, mount_point, c);
+}
+
+
+/****************************************************************************
+get a password from a a file or file descriptor
+exit on failure (from smbclient, move to libsmb or shared .c file?)
+****************************************************************************/
+static void get_password_file(void)
+{
+ int fd = -1;
+ char *p;
+ BOOL close_it = False;
+ pstring spec;
+ char pass[128];
+
+ if ((p = getenv("PASSWD_FD")) != NULL) {
+ pstrcpy(spec, "descriptor ");
+ pstrcat(spec, p);
+ sscanf(p, "%d", &fd);
+ close_it = False;
+ } else if ((p = getenv("PASSWD_FILE")) != NULL) {
+ fd = sys_open(p, O_RDONLY, 0);
+ pstrcpy(spec, p);
+ if (fd < 0) {
+ fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
+ spec, strerror(errno));
+ exit(1);
+ }
+ close_it = True;
+ }
+
+ for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
+ p && p - pass < sizeof(pass);) {
+ switch (read(fd, p, 1)) {
+ case 1:
+ if (*p != '\n' && *p != '\0') {
+ *++p = '\0'; /* advance p, and null-terminate pass */
+ break;
+ }
+ case 0:
+ if (p - pass) {
+ *p = '\0'; /* null-terminate it, just in case... */
+ p = NULL; /* then force the loop condition to become false */
+ break;
+ } else {
+ fprintf(stderr, "Error reading password from file %s: %s\n",
+ spec, "empty password\n");
+ exit(1);
+ }
+
+ default:
+ fprintf(stderr, "Error reading password from file %s: %s\n",
+ spec, strerror(errno));
+ exit(1);
+ }
+ }
+ pstrcpy(password, pass);
+ if (close_it)
+ close(fd);
+}
+
+/****************************************************************************
+get username and password from a credentials file
+exit on failure (from smbclient, move to libsmb or shared .c file?)
+****************************************************************************/
+static void read_credentials_file(char *filename)
+{
+ FILE *auth;
+ fstring buf;
+ uint16 len = 0;
+ char *ptr, *val, *param;
+
+ if ((auth=sys_fopen(filename, "r")) == NULL)
+ {
+ /* fail if we can't open the credentials file */
+ DEBUG(0,("ERROR: Unable to open credentials file!\n"));
+ exit (-1);
+ }
+
+ while (!feof(auth))
+ {
+ /* get a line from the file */
+ if (!fgets (buf, sizeof(buf), auth))
+ continue;
+ len = strlen(buf);
+
+ if ((len) && (buf[len-1]=='\n'))
+ {
+ buf[len-1] = '\0';
+ len--;
+ }
+ if (len == 0)
+ continue;
+
+ /* break up the line into parameter & value.
+ will need to eat a little whitespace possibly */
+ param = buf;
+ if (!(ptr = strchr (buf, '=')))
+ continue;
+ val = ptr+1;
+ *ptr = '\0';
+
+ /* eat leading white space */
+ while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
+ val++;
+
+ if (strwicmp("password", param) == 0)
+ {
+ pstrcpy(password, val);
+ got_pass = True;
+ }
+ else if (strwicmp("username", param) == 0)
+ pstrcpy(username, val);
+
+ memset(buf, 0, sizeof(buf));
+ }
+ fclose(auth);
+}
+
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(void)
+{
+ printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
+
+ printf("Version %s\n\n",VERSION);
+
+ printf(
+"Options:\n\
+ username=<arg> SMB username\n\
+ password=<arg> SMB password\n\
+ credentials=<filename> file with username/password\n\
+ netbiosname=<arg> source NetBIOS name\n\
+ uid=<arg> mount uid or username\n\
+ gid=<arg> mount gid or groupname\n\
+ port=<arg> remote SMB port number\n\
+ fmask=<arg> file umask\n\
+ dmask=<arg> directory umask\n\
+ debug=<arg> debug level\n\
+ ip=<arg> destination host or IP address\n\
+ workgroup=<arg> workgroup on destination\n\
+ sockopt=<arg> TCP socket options\n\
+ scope=<arg> NetBIOS scope\n\
+ iocharset=<arg> Linux charset (iso8859-1, utf8)\n\
+ codepage=<arg> server codepage (cp850)\n\
+ ttl=<arg> dircache time to live\n\
+ guest don't prompt for a password\n\
+ ro mount read-only\n\
+ rw mount read-write\n\
+\n\
+This command is designed to be run from within /bin/mount by giving\n\
+the option '-t smbfs'. For example:\n\
+ mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
+");
+}
+
+
+/****************************************************************************
+ Argument parsing for mount.smbfs interface
+ mount will call us like this:
+ mount.smbfs device mountpoint -o <options>
+
+ <options> is never empty, containing at least rw or ro
+ ****************************************************************************/
+static void parse_mount_smb(int argc, char **argv)
+{
+ int opt;
+ char *opts;
+ char *opteq;
+ extern char *optarg;
+ int val;
+ extern pstring global_scope;
+ char *p;
+
+ if (argc < 2 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ pstrcpy(service, argv[1]);
+ pstrcpy(mpoint, argv[2]);
+
+ /* Convert any '/' characters in the service name to
+ '\' characters */
+ string_replace(service, '/','\\');
+ argc -= 2;
+ argv += 2;
+
+ opt = getopt(argc, argv, "o:");
+ if(opt != 'o') {
+ return;
+ }
+
+ options[0] = 0;
+ p = options;
+
+ /*
+ * option parsing from nfsmount.c (util-linux-2.9u)
+ */
+ for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
+ DEBUG(3, ("opts: %s\n", opts));
+ if ((opteq = strchr_m(opts, '='))) {
+ val = atoi(opteq + 1);
+ *opteq = '\0';
+
+ if (!strcmp(opts, "username") ||
+ !strcmp(opts, "logon")) {
+ char *lp;
+ pstrcpy(username,opteq+1);
+ if ((lp=strchr_m(username,'%'))) {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
+ }
+ if ((lp=strchr_m(username,'/'))) {
+ *lp = 0;
+ pstrcpy(workgroup,lp+1);
+ }
+ } else if(!strcmp(opts, "passwd") ||
+ !strcmp(opts, "password")) {
+ pstrcpy(password,opteq+1);
+ got_pass = True;
+ memset(opteq+1,'X',strlen(password));
+ } else if(!strcmp(opts, "credentials")) {
+ pstrcpy(credentials,opteq+1);
+ } else if(!strcmp(opts, "netbiosname")) {
+ pstrcpy(my_netbios_name,opteq+1);
+ } else if(!strcmp(opts, "uid")) {
+ mount_uid = nametouid(opteq+1);
+ } else if(!strcmp(opts, "gid")) {
+ mount_gid = nametogid(opteq+1);
+ } else if(!strcmp(opts, "port")) {
+ smb_port = val;
+ } else if(!strcmp(opts, "fmask")) {
+ mount_fmask = strtol(opteq+1, NULL, 8);
+ } else if(!strcmp(opts, "dmask")) {
+ mount_dmask = strtol(opteq+1, NULL, 8);
+ } else if(!strcmp(opts, "debug")) {
+ DEBUGLEVEL = val;
+ } else if(!strcmp(opts, "ip")) {
+ dest_ip = *interpret_addr2(opteq+1);
+ if (is_zero_ip(dest_ip)) {
+ fprintf(stderr,"Can't resolve address %s\n", opteq+1);
+ exit(1);
+ }
+ have_ip = True;
+ } else if(!strcmp(opts, "workgroup")) {
+ pstrcpy(workgroup,opteq+1);
+ } else if(!strcmp(opts, "sockopt")) {
+ pstrcpy(user_socket_options,opteq+1);
+ } else if(!strcmp(opts, "scope")) {
+ pstrcpy(global_scope,opteq+1);
+ } else {
+ slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
+ p += strlen(p);
+ }
+ } else {
+ val = 1;
+ if(!strcmp(opts, "nocaps")) {
+ fprintf(stderr, "Unhandled option: %s\n", opteq+1);
+ exit(1);
+ } else if(!strcmp(opts, "guest")) {
+ *password = '\0';
+ got_pass = True;
+ } else if(!strcmp(opts, "rw")) {
+ mount_ro = 0;
+ } else if(!strcmp(opts, "ro")) {
+ mount_ro = 1;
+ } else {
+ strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
+ p += strlen(opts);
+ *p++ = ',';
+ *p = 0;
+ }
+ }
+ }
+
+ if (!*service) {
+ usage();
+ exit(1);
+ }
+
+ if (p != options) {
+ *(p-1) = 0; /* remove trailing , */
+ DEBUG(3,("passthrough options '%s'\n", options));
+ }
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ char *p;
+
+ DEBUGLEVEL = 1;
+
+ /* here we are interactive, even if run from autofs */
+ setup_logging("mount.smbfs",True);
+
+#if 0 /* JRA - Urban says not needed ? */
+ /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
+ is to not announce any unicode capabilities as current smbfs does
+ not support it. */
+ p = getenv("CLI_FORCE_ASCII");
+ if (p && !strcmp(p, "false"))
+ unsetenv("CLI_FORCE_ASCII");
+ else
+ setenv("CLI_FORCE_ASCII", "true", 1);
+#endif
+
+ in_client = True; /* Make sure that we tell lp_load we are */
+
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
+
+ if ((p=strchr_m(username,'%'))) {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
+ }
+ strupper(username);
+ }
+
+ if (getenv("PASSWD")) {
+ pstrcpy(password,getenv("PASSWD"));
+ got_pass = True;
+ }
+
+ if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
+ get_password_file();
+ got_pass = True;
+ }
+
+ if (*username == 0 && getenv("LOGNAME")) {
+ pstrcpy(username,getenv("LOGNAME"));
+ }
+
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ dyn_CONFIGFILE);
+ }
+
+ parse_mount_smb(argc, argv);
+
+ if (*credentials != 0) {
+ read_credentials_file(credentials);
+ }
+
+ DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
+
+ if (*workgroup == 0) {
+ pstrcpy(workgroup,lp_workgroup());
+ }
+
+ load_interfaces();
+ if (!*my_netbios_name) {
+ pstrcpy(my_netbios_name, myhostname());
+ }
+ strupper(my_netbios_name);
+
+ init_mount();
+ return 0;
+}
diff --git a/source/client/smbspool.c b/source/client/smbspool.c
new file mode 100644
index 00000000000..3e583e855e9
--- /dev/null
+++ b/source/client/smbspool.c
@@ -0,0 +1,413 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0.
+ SMB backend for the Common UNIX Printing System ("CUPS")
+ Copyright 1999 by Easy Software Products
+ Copyright Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*
+ * Globals...
+ */
+
+extern BOOL in_client; /* Boolean for client library */
+
+
+/*
+ * Local functions...
+ */
+
+static void list_devices(void);
+static struct cli_state *smb_connect(char *, char *, char *, char *, char *);
+static int smb_print(struct cli_state *, char *, FILE *);
+
+
+/*
+ * 'main()' - Main entry for SMB backend.
+ */
+
+ int /* O - Exit status */
+ main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int copies; /* Number of copies */
+ char uri[1024], /* URI */
+ *sep, /* Pointer to separator */
+ *username, /* Username */
+ *password, /* Password */
+ *workgroup, /* Workgroup */
+ *server, /* Server name */
+ *printer; /* Printer name */
+ FILE *fp; /* File to print */
+ int status=0; /* Status of LPD job */
+ struct cli_state *cli; /* SMB interface */
+
+ /* we expect the URI in argv[0]. Detect the case where it is in argv[1] and cope */
+ if (argc > 2 && strncmp(argv[0],"smb://", 6) && !strncmp(argv[1],"smb://", 6)) {
+ argv++;
+ argc--;
+ }
+
+ if (argc == 1)
+ {
+ /*
+ * NEW! In CUPS 1.1 the backends are run with no arguments to list the
+ * available devices. These can be devices served by this backend
+ * or any other backends (i.e. you can have an SNMP backend that
+ * is only used to enumerate the available network printers... :)
+ */
+
+ list_devices();
+ return (0);
+ }
+
+ if (argc < 6 || argc > 7)
+ {
+ fprintf(stderr, "Usage: %s [DEVICE_URI] job-id user title copies options [file]\n",
+ argv[0]);
+ fputs(" The DEVICE_URI environment variable can also contain the\n", stderr);
+ fputs(" destination printer:\n", stderr);
+ fputs("\n", stderr);
+ fputs(" smb://[username:password@][workgroup/]server/printer\n", stderr);
+ return (1);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, print data from stdin...
+ */
+
+ if (argc == 6)
+ {
+ /*
+ * Print from Copy stdin to a temporary file...
+ */
+
+ fp = stdin;
+ copies = 1;
+ }
+ else if ((fp = fopen(argv[6], "rb")) == NULL)
+ {
+ perror("ERROR: Unable to open print file");
+ return (1);
+ }
+ else
+ copies = atoi(argv[4]);
+
+ /*
+ * Find the URI...
+ */
+
+ if (strncmp(argv[0], "smb://", 6) == 0)
+ strncpy(uri, argv[0], sizeof(uri) - 1);
+ else if (getenv("DEVICE_URI") != NULL)
+ strncpy(uri, getenv("DEVICE_URI"), sizeof(uri) - 1);
+ else
+ {
+ fputs("ERROR: No device URI found in argv[0] or DEVICE_URI environment variable!\n", stderr);
+ return (1);
+ }
+
+ uri[sizeof(uri) - 1] = '\0';
+
+ /*
+ * Extract the destination from the URI...
+ */
+
+ if ((sep = strrchr_m(uri, '@')) != NULL)
+ {
+ username = uri + 6;
+ *sep++ = '\0';
+
+ server = sep;
+
+ /*
+ * Extract password as needed...
+ */
+
+ if ((password = strchr_m(username, ':')) != NULL)
+ *password++ = '\0';
+ else
+ password = "";
+ }
+ else
+ {
+ username = "";
+ password = "";
+ server = uri + 6;
+ }
+
+ if ((sep = strchr_m(server, '/')) == NULL)
+ {
+ fputs("ERROR: Bad URI - need printer name!\n", stderr);
+ return (1);
+ }
+
+ *sep++ = '\0';
+ printer = sep;
+
+ if ((sep = strchr_m(printer, '/')) != NULL)
+ {
+ /*
+ * Convert to smb://[username:password@]workgroup/server/printer...
+ */
+
+ *sep++ = '\0';
+
+ workgroup = server;
+ server = printer;
+ printer = sep;
+ }
+ else
+ workgroup = NULL;
+
+ /*
+ * Setup the SAMBA server state...
+ */
+
+ setup_logging("smbspool", True);
+
+ in_client = True; /* Make sure that we tell lp_load we are */
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False))
+ {
+ fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
+ return (1);
+ }
+
+ if (workgroup == NULL)
+ workgroup = lp_workgroup();
+
+ load_interfaces();
+
+ do
+ {
+ if ((cli = smb_connect(workgroup, server, printer, username, password)) == NULL)
+ {
+ if (getenv("CLASS") == NULL)
+ {
+ perror("ERROR: Unable to connect to SAMBA host, will retry in 60 seconds...");
+ sleep (60);
+ }
+ else
+ {
+ perror("ERROR: Unable to connect to SAMBA host, trying next printer...");
+ return (1);
+ }
+ }
+ }
+ while (cli == NULL);
+
+ /*
+ * Now that we are connected to the server, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ CatchSignal(SIGTERM, SIG_IGN);
+
+ /*
+ * Queue the job...
+ */
+
+ for (i = 0; i < copies; i ++)
+ if ((status = smb_print(cli, argv[3] /* title */, fp)) != 0)
+ break;
+
+ cli_shutdown(cli);
+
+ /*
+ * Return the queue status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'list_devices()' - List the available printers seen on the network...
+ */
+
+static void
+list_devices(void)
+{
+ /*
+ * Eventually, search the local workgroup for available hosts and printers.
+ */
+
+ puts("network smb \"Unknown\" \"Windows Printer via SAMBA\"");
+}
+
+
+/*
+ * 'smb_connect()' - Return a connection to a server.
+ */
+
+static struct cli_state * /* O - SMB connection */
+smb_connect(char *workgroup, /* I - Workgroup */
+ char *server, /* I - Server */
+ char *share, /* I - Printer */
+ char *username, /* I - Username */
+ char *password) /* I - Password */
+{
+ struct cli_state *c; /* New connection */
+ struct nmb_name called, /* NMB name of server */
+ calling; /* NMB name of client */
+ struct in_addr ip; /* IP address of server */
+ pstring myname; /* Client name */
+
+
+ /*
+ * Get the names and addresses of the client and server...
+ */
+
+ get_myname(myname);
+
+ zero_ip(&ip);
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called, server, 0x20);
+
+ /*
+ * Open a new connection to the SMB server...
+ */
+
+ if ((c = cli_initialise(NULL)) == NULL)
+ {
+ fputs("ERROR: cli_initialize() failed...\n", stderr);
+ return (NULL);
+ }
+
+ if (!cli_connect(c, server, &ip))
+ {
+ fputs("ERROR: cli_connect() failed...\n", stderr);
+ return (NULL);
+ }
+
+ if (!cli_session_request(c, &calling, &called))
+ {
+ fputs("ERROR: cli_session_request() failed...\n", stderr);
+ return (NULL);
+ }
+
+ if (!cli_negprot(c))
+ {
+ fputs("ERROR: SMB protocol negotiation failed\n", stderr);
+ cli_shutdown(c);
+ return (NULL);
+ }
+
+ /*
+ * Do password stuff...
+ */
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup))
+ {
+ fprintf(stderr, "ERROR: SMB session setup failed: %s\n", cli_errstr(c));
+ return (NULL);
+ }
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1))
+ {
+ fprintf(stderr, "ERROR: SMB tree connect failed: %s\n", cli_errstr(c));
+ cli_shutdown(c);
+ return (NULL);
+ }
+
+ /*
+ * Return the new connection...
+ */
+
+ return (c);
+}
+
+
+/*
+ * 'smb_print()' - Queue a job for printing using the SMB protocol.
+ */
+
+static int /* O - 0 = success, non-0 = failure */
+smb_print(struct cli_state *cli, /* I - SMB connection */
+ char *title, /* I - Title/job name */
+ FILE *fp) /* I - File to print */
+{
+ int fnum; /* File number */
+ int nbytes, /* Number of bytes read */
+ tbytes; /* Total bytes read */
+ char buffer[8192], /* Buffer for copy */
+ *ptr; /* Pointer into tile */
+
+
+ /*
+ * Sanitize the title...
+ */
+
+ for (ptr = title; *ptr; ptr ++)
+ if (!isalnum((int)*ptr) && !isspace((int)*ptr))
+ *ptr = '_';
+
+ /*
+ * Open the printer device...
+ */
+
+ if ((fnum = cli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE)) == -1)
+ {
+ fprintf(stderr, "ERROR: %s opening remote file %s\n",
+ cli_errstr(cli), title);
+ return (1);
+ }
+
+ /*
+ * Copy the file to the printer...
+ */
+
+ if (fp != stdin)
+ rewind(fp);
+
+ tbytes = 0;
+
+ while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+ {
+ if (cli_write(cli, fnum, 0, buffer, tbytes, nbytes) != nbytes)
+ {
+ fprintf(stderr, "ERROR: Error writing file: %s\n", cli_errstr(cli));
+ break;
+ }
+
+ tbytes += nbytes;
+ }
+
+ if (!cli_close(cli, fnum))
+ {
+ fprintf(stderr, "ERROR: %s closing remote file %s\n",
+ cli_errstr(cli), title);
+ return (1);
+ }
+ else
+ return (0);
+}
diff --git a/source/client/smbumount.c b/source/client/smbumount.c
new file mode 100644
index 00000000000..983ad44fa0f
--- /dev/null
+++ b/source/client/smbumount.c
@@ -0,0 +1,185 @@
+/*
+ * smbumount.c
+ *
+ * Copyright (C) 1995-1998 by Volker Lendecke
+ *
+ */
+
+#include "includes.h"
+
+#include <mntent.h>
+
+#include <asm/types.h>
+#include <asm/posix_types.h>
+#include <linux/smb.h>
+#include <linux/smb_mount.h>
+#include <linux/smb_fs.h>
+
+/* This is a (hopefully) temporary hack due to the fact that
+ sizeof( uid_t ) != sizeof( __kernel_uid_t ) under glibc.
+ This may change in the future and smb.h may get fixed in the
+ future. In the mean time, it's ugly hack time - get over it.
+*/
+#undef SMB_IOC_GETMOUNTUID
+#define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_uid_t)
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0400000
+#endif
+
+static void
+usage(void)
+{
+ printf("usage: smbumount mountpoint\n");
+}
+
+static int
+umount_ok(const char *mount_point)
+{
+ /* we set O_NOFOLLOW to prevent users playing games with symlinks to
+ umount filesystems they don't own */
+ int fid = open(mount_point, O_RDONLY|O_NOFOLLOW, 0);
+ __kernel_uid_t mount_uid;
+
+ if (fid == -1) {
+ fprintf(stderr, "Could not open %s: %s\n",
+ mount_point, strerror(errno));
+ return -1;
+ }
+
+ if (ioctl(fid, SMB_IOC_GETMOUNTUID, &mount_uid) != 0) {
+ fprintf(stderr, "%s probably not smb-filesystem\n",
+ mount_point);
+ return -1;
+ }
+
+ if ((getuid() != 0)
+ && (mount_uid != getuid())) {
+ fprintf(stderr, "You are not allowed to umount %s\n",
+ mount_point);
+ return -1;
+ }
+
+ close(fid);
+ return 0;
+}
+
+/* Make a canonical pathname from PATH. Returns a freshly malloced string.
+ It is up the *caller* to ensure that the PATH is sensible. i.e.
+ canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
+ is not a legal pathname for ``/dev/fd0'' Anything we cannot parse
+ we return unmodified. */
+static char *
+canonicalize (char *path)
+{
+ char *canonical = malloc (PATH_MAX + 1);
+
+ if (!canonical) {
+ fprintf(stderr, "Error! Not enough memory!\n");
+ return NULL;
+ }
+
+ if (strlen(path) > PATH_MAX) {
+ fprintf(stderr, "Mount point string too long\n");
+ return NULL;
+ }
+
+ if (path == NULL)
+ return NULL;
+
+ if (realpath (path, canonical))
+ return canonical;
+
+ pstrcpy (canonical, path);
+ return canonical;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int fd;
+ char* mount_point;
+ struct mntent *mnt;
+ FILE* mtab;
+ FILE* new_mtab;
+
+ if (argc != 2) {
+ usage();
+ exit(1);
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "smbumount must be installed suid root\n");
+ exit(1);
+ }
+
+ mount_point = canonicalize(argv[1]);
+
+ if (mount_point == NULL)
+ {
+ exit(1);
+ }
+
+ if (umount_ok(mount_point) != 0) {
+ exit(1);
+ }
+
+ if (umount(mount_point) != 0) {
+ fprintf(stderr, "Could not umount %s: %s\n",
+ mount_point, strerror(errno));
+ exit(1);
+ }
+
+ 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, "r")) == NULL) {
+ fprintf(stderr, "Can't open " MOUNTED ": %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+#define MOUNTED_TMP MOUNTED".tmp"
+
+ if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
+ fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
+ strerror(errno));
+ endmntent(mtab);
+ return 1;
+ }
+
+ while ((mnt = getmntent(mtab)) != NULL) {
+ if (strcmp(mnt->mnt_dir, mount_point) != 0) {
+ addmntent(new_mtab, mnt);
+ }
+ }
+
+ endmntent(mtab);
+
+ if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+ fprintf(stderr, "Error changing mode of %s: %s\n",
+ MOUNTED_TMP, strerror(errno));
+ exit(1);
+ }
+
+ endmntent(new_mtab);
+
+ if (rename(MOUNTED_TMP, MOUNTED) < 0) {
+ fprintf(stderr, "Cannot rename %s to %s: %s\n",
+ MOUNTED, MOUNTED_TMP, strerror(errno));
+ exit(1);
+ }
+
+ if (unlink(MOUNTED"~") == -1)
+ {
+ fprintf(stderr, "Can't remove "MOUNTED"~");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/source/client/testsmbc.c b/source/client/testsmbc.c
new file mode 100644
index 00000000000..7aae9d85616
--- /dev/null
+++ b/source/client/testsmbc.c
@@ -0,0 +1,456 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library test program
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libsmbclient.h>
+
+void auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+ char temp[128];
+
+ fprintf(stdout, "Need password for //%s/%s\n", server, share);
+
+ fprintf(stdout, "Enter workgroup: [%s] ", workgroup);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(workgroup, temp, wgmaxlen - 1);
+
+ fprintf(stdout, "Enter username: [%s] ", username);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(username, temp, unmaxlen - 1);
+
+ fprintf(stdout, "Enter password: [%s] ", password);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(password, temp, pwmaxlen - 1);
+
+}
+
+int global_id = 0;
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+ global_id = pji->id;
+
+}
+
+int main(int argc, char *argv[])
+{
+ int err, fd, dh1, dh2, dh3, dsize, dirc;
+ const char *file = "smb://samba/public/testfile.txt";
+ const char *file2 = "smb://samba/public/testfile2.txt";
+ char buff[256];
+ char dirbuf[512];
+ char *dirp;
+ struct stat st1, st2;
+
+ err = smbc_init(auth_fn, 10); /* Initialize things */
+
+ if (err < 0) {
+
+ fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno));
+
+ }
+
+ if (argc > 1) {
+
+ /* Try to list the print jobs ... */
+
+ if (smbc_list_print_jobs("smb://samba/pclp", print_list_fn) < 0) {
+
+ fprintf(stderr, "Could not list print jobs: %s, %d\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete the last job listed */
+
+ if (global_id > 0) {
+
+ fprintf(stdout, "Trying to delete print job %u\n", global_id);
+
+ if (smbc_unlink_print_job("smb://samba/pclp", global_id) < 0) {
+
+ fprintf(stderr, "Failed to unlink job id %u, %s, %u\n", global_id,
+ strerror(errno), errno);
+
+ exit(1);
+
+ }
+
+ }
+
+ /* Try to print a file ... */
+
+ if (smbc_print_file("smb://samba/public/testfile2.txt", "smb://samba/pclp") < 0) {
+
+ fprintf(stderr, "Failed to print job: %s %u\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete argv[1] as a file ... */
+
+ if (smbc_unlink(argv[1]) < 0) {
+
+ fprintf(stderr, "Could not unlink: %s, %s, %d\n",
+ argv[1], strerror(errno), errno);
+
+ exit(0);
+
+ }
+
+ if ((dh1 = smbc_opendir("smb://"))<1) {
+
+ fprintf(stderr, "Could not open directory: smb://: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh2 = smbc_opendir("smb://sambanet")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://sambanet: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh3 = smbc_opendir("smb://samba")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://samba: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Directory handles: %u, %u, %u\n", dh1, dh2, dh3);
+
+ /* Now, list those directories, but in funny ways ... */
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh1, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh2, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "\nDirectory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh3, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "\nDir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ (char *)dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ exit(1);
+
+ }
+
+ /* For now, open a file on a server that is hard coded ... later will
+ * read from the command line ...
+ */
+
+ fd = smbc_open(file, O_RDWR | O_CREAT | O_TRUNC, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ /* Now, write some date to the file ... */
+
+ bzero(buff, sizeof(buff));
+ strcpy(buff, "Some test data for the moment ...");
+
+ err = smbc_write(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "writing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Wrote %d bytes to file: %s\n", sizeof(buff), buff);
+
+ /* Now, seek the file back to offset 0 */
+
+ err = smbc_lseek(fd, SEEK_SET, 0);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Seeking file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Completed lseek on file: %s\n", file);
+
+ /* Now, read the file contents back ... */
+
+ err = smbc_read(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "Reading file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Read file: %s\n", buff); /* Should check the contents */
+
+ fprintf(stdout, "Now fstat'ing file: %s\n", file);
+
+ err = smbc_fstat(fd, &st1);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Fstat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+
+ /* Now, close the file ... */
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+
+ }
+
+ /* Now, rename the file ... */
+
+ err = smbc_rename(file, file2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Renaming file: %s to %s: %s\n", file, file2, strerror(errno));
+
+ }
+
+ fprintf(stdout, "Renamed file %s to %s\n", file, file2);
+
+ /* Now, create a file and delete it ... */
+
+ fprintf(stdout, "Now, creating file: %s so we can delete it.\n", file);
+
+ fd = smbc_open(file, O_RDWR | O_CREAT, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, delete the file ... */
+
+ fprintf(stdout, "File %s created, now deleting ...\n", file);
+
+ err = smbc_unlink(file);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Deleting file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, stat the file, file 2 ... */
+
+ fprintf(stdout, "Now stat'ing file: %s\n", file);
+
+ err = smbc_stat(file2, &st2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Stat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Stat'ed file: %s. Size = %d, mode = %04X\n", file2,
+ (int)st2.st_size, st2.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st2.st_atime));
+ fprintf(stdout, "Earlier stat: %s, Size = %d, mode = %04X\n", file,
+ (int)st1.st_size, st1.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st1.st_atime));
+
+ /* Now, make a directory ... */
+
+ fprintf(stdout, "Making directory smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 0666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ if (errno == EEXIST) { /* Try to delete the directory */
+
+ fprintf(stdout, "Trying to delete directory: smb://samba/public/make-dir\n");
+
+ if (smbc_rmdir("smb://samba/public/make-dir") < 0) { /* Error */
+
+ fprintf(stderr, "Error removing directory: smb://samba/public/make-dir: %s\n", strerror(errno));
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Making directory: smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ fprintf(stderr, "I give up!\n");
+
+ exit(1);
+
+ }
+
+ }
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Made dir: make-dir\n");
+ return 0;
+}
diff --git a/source/client/tree.c b/source/client/tree.c
new file mode 100644
index 00000000000..d4f286ef563
--- /dev/null
+++ b/source/client/tree.c
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client GTK+ tree-based application
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* example-gtk+ application, ripped off from the gtk+ tree.c sample */
+
+#include <stdio.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include "libsmbclient.h"
+
+static GtkWidget *clist;
+
+struct tree_data {
+
+ guint32 type; /* Type of tree item, an SMBC_TYPE */
+ char name[256]; /* May need to change this later */
+
+};
+
+void error_message(gchar *message) {
+
+ GtkWidget *dialog, *label, *okay_button;
+
+ /* Create the widgets */
+
+ dialog = gtk_dialog_new();
+ gtk_window_set_modal(GTK_WINDOW(dialog), True);
+ label = gtk_label_new (message);
+ okay_button = gtk_button_new_with_label("Okay");
+
+ /* Ensure that the dialog box is destroyed when the user clicks ok. */
+
+ gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ okay_button);
+
+ /* Add the label, and show everything we've added to the dialog. */
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+ label);
+ gtk_widget_show_all (dialog);
+}
+
+/*
+ * We are given a widget, and we want to retrieve its URL so we
+ * can do a directory listing.
+ *
+ * We walk back up the tree, picking up pieces until we hit a server or
+ * workgroup type and return a path from there
+ */
+
+static char path_string[1024];
+
+char *get_path(GtkWidget *item)
+{
+ GtkWidget *p = item;
+ struct tree_data *pd;
+ char *comps[1024]; /* We keep pointers to the components here */
+ int i = 0, j, level,type;
+
+ /* Walk back up the tree, getting the private data */
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Pick up this item's component info */
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item));
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) {
+
+ /* Find the parent and extract the data etc ... */
+
+ p = GTK_WIDGET(p->parent);
+ p = GTK_WIDGET(GTK_TREE(p)->tree_owner);
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p));
+
+ level = GTK_TREE(item->parent)->level;
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ }
+
+ /*
+ * Got a list of comps now, should check that we did not hit a workgroup
+ * when we got other things as well ... Later
+ *
+ * Now, build the path
+ */
+
+ snprintf(path_string, sizeof(path_string), "smb:/");
+
+ for (j = i - 1; j >= 0; j--) {
+
+ strncat(path_string, "/", sizeof(path_string) - strlen(path_string));
+ strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string));
+
+ }
+
+ fprintf(stdout, "Path string = %s\n", path_string);
+
+ return path_string;
+
+}
+
+struct tree_data *make_tree_data(guint32 type, const char *name)
+{
+ struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data));
+
+ if (p) {
+
+ p->type = type;
+ strncpy(p->name, name, sizeof(p->name));
+
+ }
+
+ return p;
+
+}
+
+/* Note that this is called every time the user clicks on an item,
+ whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+ GtkWidget *subtree)
+{
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+ struct stat st1;
+ char path[1024], path1[1024];
+
+ g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+
+ /* Now, figure out what it is, and display it in the clist ... */
+
+ gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */
+
+ /* Now, get the private data for the subtree */
+
+ strncpy(path, get_path(child), 1024);
+
+ if ((dh = smbc_opendir(path)) < 0) { /* Handle error */
+
+ g_print("cb_select_child: Could not open dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) {
+
+ g_print("cb_select_child: Could not read dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ gchar col1[128], col2[128], col3[128], col4[128];
+ gchar *rowdata[4] = {col1, col2, col3, col4};
+
+ dirlen = dirp->dirlen;
+
+ /* Format each of the items ... */
+
+ strncpy(col1, dirp->name, 128);
+
+ col2[0] = col3[0] = col4[0] = (char)0;
+
+ switch (dirp->smbc_type) {
+
+ case SMBC_WORKGROUP:
+
+ break;
+
+ case SMBC_SERVER:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_FILE_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_PRINTER_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+ break;
+
+ case SMBC_COMMS_SHARE:
+
+ break;
+
+ case SMBC_IPC_SHARE:
+
+ break;
+
+ case SMBC_DIR:
+ case SMBC_FILE:
+
+ /* Get stats on the file/dir and see what we have */
+
+ if ((strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") != 0)) {
+
+ strncpy(path1, path, sizeof(path1));
+ strncat(path1, "/", sizeof(path) - strlen(path));
+ strncat(path1, dirp->name, sizeof(path) - strlen(path));
+
+ if (smbc_stat(path1, &st1) < 0) {
+
+ if (errno != EBUSY) {
+
+ g_print("cb_select_child: Could not stat file %s, %s\n", path1,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+ else {
+
+ strncpy(col2, "Device or resource busy", sizeof(col2));
+
+ }
+ }
+ else {
+ /* Now format each of the relevant things ... */
+
+ snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)",
+ (st1.st_mode&S_IRUSR?'r':'-'),
+ (st1.st_mode&S_IWUSR?'w':'-'),
+ (st1.st_mode&S_IXUSR?'x':'-'),
+ (st1.st_mode&S_IRGRP?'r':'-'),
+ (st1.st_mode&S_IWGRP?'w':'-'),
+ (st1.st_mode&S_IXGRP?'x':'-'),
+ (st1.st_mode&S_IROTH?'r':'-'),
+ (st1.st_mode&S_IWOTH?'w':'-'),
+ (st1.st_mode&S_IXOTH?'x':'-'),
+ st1.st_mode);
+ snprintf(col3, sizeof(col3), "%u", st1.st_size);
+ snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime));
+ }
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ gtk_clist_append(GTK_CLIST(clist), rowdata);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+}
+
+/* Note that this is never called */
+static void cb_unselect_child( GtkWidget *root_tree,
+ GtkWidget *child,
+ GtkWidget *subtree )
+{
+ g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+}
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal( GtkWidget *item,
+ gchar *signame )
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen, level;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ /* Get the text of the label */
+ gtk_label_get (label, &name);
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Get the level of the tree which the item is in */
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+ char server[128];
+
+ if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item),
+ strerror(errno));
+
+ slprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ slprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ if (!my_data) {
+
+ g_print("Could not allocate space for tree_data: %s\n",
+ dirp->name);
+
+ gtk_main_quit();
+ return;
+
+ }
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ if (dirp->smbc_type != SMBC_FILE &&
+ dirp->smbc_type != SMBC_IPC_SHARE &&
+ (strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") !=0)){
+
+ subtree = gtk_tree_new();
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else if (strncmp(signame, "collapse", 8) == 0) {
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+}
+
+static void cb_selection_changed( GtkWidget *tree )
+{
+ GList *i;
+
+ g_print ("selection_change called for tree %p\n", tree);
+ g_print ("selected objects are:\n");
+
+ i = GTK_TREE_SELECTION(tree);
+ while (i){
+ gchar *name;
+ GtkLabel *label;
+ GtkWidget *item;
+
+ /* Get a GtkWidget pointer from the list node */
+ item = GTK_WIDGET (i->data);
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("\t%s on level %d\n", name, GTK_TREE
+ (item->parent)->level);
+ i = i->next;
+ }
+}
+
+/*
+ * Expand or collapse the whole network ...
+ */
+static void cb_wholenet(GtkWidget *item, gchar *signame)
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+
+ if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */
+
+ g_print("cb_wholenet: Could not open dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+
+ g_print("cb_wholenet: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else { /* Must be collapse ... FIXME ... */
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+
+ }
+
+}
+
+/* Should put up a dialog box to ask the user for username and password */
+
+static void
+auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+
+ strncpy(username, "test", unmaxlen);
+ strncpy(password, "test", pwmaxlen);
+
+}
+
+static char *col_titles[] = {
+ "Name", "Attributes", "Size", "Modification Date",
+};
+
+int main( int argc,
+ char *argv[] )
+{
+ GtkWidget *window, *scrolled_win, *scrolled_win2, *tree;
+ GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane;
+ gint err, dh;
+ gint i;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ gtk_init (&argc, &argv);
+
+ /* Init the smbclient library */
+
+ err = smbc_init(auth_fn, 10);
+
+ /* Print an error response ... */
+
+ if (err < 0) {
+
+ fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* a generic toplevel window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(window, "main browser window");
+ gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+ gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser");
+ gtk_widget_set_usize(GTK_WIDGET(window), 750, -1);
+ gtk_container_set_border_width (GTK_CONTAINER(window), 5);
+
+ gtk_widget_show (window);
+
+ /* A container for the two panes ... */
+
+ main_hbox = gtk_hbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_hbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_hbox);
+
+ gtk_widget_show(main_hbox);
+
+ l_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
+ r_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size);
+ gtk_container_add(GTK_CONTAINER(main_hbox), l_pane);
+ gtk_widget_show(l_pane);
+
+ /* A generic scrolled window */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win, 150, 200);
+ gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win);
+ gtk_widget_show (scrolled_win);
+
+ /* Another generic scrolled window */
+ scrolled_win2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win2, 150, 200);
+ gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2);
+ gtk_widget_show (scrolled_win2);
+
+ /* Create the root tree */
+ tree = gtk_tree_new();
+ g_print ("root tree is %p\n", tree);
+ /* connect all GtkTree:: signals */
+ gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+ GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+ /* Add it to the scrolled window */
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
+ tree);
+ /* Set the selection mode */
+ gtk_tree_set_selection_mode (GTK_TREE(tree),
+ GTK_SELECTION_MULTIPLE);
+ /* Show it */
+ gtk_widget_show (tree);
+
+ /* Now, create a clist and attach it to the second pane */
+
+ clist = gtk_clist_new_with_titles(4, col_titles);
+
+ gtk_container_add (GTK_CONTAINER(scrolled_win2), clist);
+
+ gtk_widget_show(clist);
+
+ /* Now, build the top level display ... */
+
+ if ((dh = smbc_opendir("smb:///")) < 0) {
+
+ fprintf(stderr, "Could not list default workgroup: smb:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Create a tree item for Whole Network */
+
+ item = gtk_tree_item_new_with_label ("Whole Network");
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_wholenet), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_wholenet), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ subtree = gtk_tree_new(); /* A subtree for Whole Network */
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ /* Now, get the items in smb:/// and add them to the tree */
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* Handle the error */
+
+ fprintf(stderr, "Could not read directory for smbc:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Dir len: %u\n", err);
+
+ while (err > 0) { /* Extract each entry and make a sub-tree */
+ struct tree_data *my_data;
+ int dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ item = gtk_tree_item_new_with_label(dirp->name);
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh); /* FIXME, check for error :-) */
+
+ /* Show the window and loop endlessly */
+ gtk_main();
+ return 0;
+}
+/* example-end */
diff --git a/source/codepages/.cvsignore b/source/codepages/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/codepages/.cvsignore
diff --git a/source/codepages/lowcase.dat b/source/codepages/lowcase.dat
new file mode 100644
index 00000000000..62b6e2e952b
--- /dev/null
+++ b/source/codepages/lowcase.dat
Binary files differ
diff --git a/source/codepages/upcase.dat b/source/codepages/upcase.dat
new file mode 100644
index 00000000000..bb6f9beb4e3
--- /dev/null
+++ b/source/codepages/upcase.dat
Binary files differ
diff --git a/source/codepages/valid.dat b/source/codepages/valid.dat
new file mode 100644
index 00000000000..78c14b33f0f
--- /dev/null
+++ b/source/codepages/valid.dat
Binary files differ
diff --git a/source/config.guess b/source/config.guess
new file mode 100755
index 00000000000..bcdc0742b73
--- /dev/null
+++ b/source/config.guess
@@ -0,0 +1,1308 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-11-26'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int dummy(){}" > $dummy.c ;
+ for c in cc gcc c89 ; do
+ ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+ if test $? = 0 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ rm -f $dummy.c $dummy.o $dummy.rel ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ # Determine the machine/vendor (is the vendor relevant).
+ case "${UNAME_MACHINE}" in
+ amiga) machine=m68k-unknown ;;
+ arm32) machine=arm-unknown ;;
+ atari*) machine=m68k-atari ;;
+ sun3*) machine=m68k-sun ;;
+ mac68k) machine=m68k-apple ;;
+ macppc) machine=powerpc-apple ;;
+ hp3[0-9][05]) machine=m68k-hp ;;
+ ibmrt|romp-ibm) machine=romp-ibm ;;
+ sparc*) machine=`uname -p`-unknown ;;
+ *) machine=${UNAME_MACHINE}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE}" in
+ i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ 2-1307)
+ UNAME_MACHINE="alphaev68"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ fi ;;
+ esac
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3D:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in
+ big) echo mips-unknown-linux-gnu && exit 0 ;;
+ little) echo mipsel-unknown-linux-gnu && exit 0 ;;
+ esac
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_targets=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-pc-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-pc-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[GKLNPTVW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/config.sub b/source/config.sub
new file mode 100755
index 00000000000..2476310dff3
--- /dev/null
+++ b/source/config.sub
@@ -0,0 +1,1421 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-12-03'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dsp16xx \
+ | fr30 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el | mips64vr4300 \
+ | mips64vr4300el | mips64vr5000 | mips64vr5000el \
+ | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \
+ | mipsisa32 \
+ | mn10200 | mn10300 \
+ | ns16k | ns32k \
+ | openrisc \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[34] | sh[34]eb | shbe | shle \
+ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alphapca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c54x-* \
+ | clipper-* | cray2-* | cydra-* \
+ | d10v-* | d30v-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | m32r-* \
+ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
+ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \
+ | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \
+ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [cjt]90)
+ basic_machine=${basic_machine}-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i686-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=t3e-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ windows32)
+ basic_machine=i386-pc
+ os=-windows32-msvcrt
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh3eb | sh4eb)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ c4x*)
+ basic_machine=c4x-none
+ os=-coff
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto*)
+ os=-nto-qnx
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/configure b/source/configure
new file mode 100755
index 00000000000..8182324f0a5
--- /dev/null
+++ b/source/configure
@@ -0,0 +1,13773 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/usr/local/samba
+ac_help="$ac_help
+ --enable-debug turn on debugging [default=no]"
+ac_help="$ac_help
+ --enable-developer turn on developer warnings and debugging [default=no]"
+ac_help="$ac_help
+ --enable-dmalloc enable heap debugging [default=no]"
+ac_help="$ac_help
+ --with-readline[=DIR] Look for readline include/libs in DIR (default=auto) "
+ac_help="$ac_help
+ --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto) "
+ac_help="$ac_help
+ --with-smbwrapper Include SMB wrapper support (default=no) "
+ac_help="$ac_help
+ --with-afs Include AFS clear-text auth support (default=no) "
+ac_help="$ac_help
+ --with-dce-dfs Include DCE/DFS clear-text auth support (default=no)"
+ac_help="$ac_help
+ --with-krb5=base-dir Locate Kerberos 5 support (default=/usr)"
+ac_help="$ac_help
+ --with-automount Include AUTOMOUNT support (default=no)"
+ac_help="$ac_help
+ --with-smbmount Include SMBMOUNT (Linux only) support (default=no)"
+ac_help="$ac_help
+ --with-pam Include PAM support (default=no)"
+ac_help="$ac_help
+ --with-pam_smbpass Build a PAM module to allow other applications to use our smbpasswd file (default=no)"
+ac_help="$ac_help
+ --with-tdbsam Include experimental TDB SAM support (default=no)"
+ac_help="$ac_help
+ --with-ldapsam Include experimental LDAP SAM support (default=no)"
+ac_help="$ac_help
+ --with-nisplussam Include NISPLUS SAM support (default=no)"
+ac_help="$ac_help
+ --with-nisplus-home Include NISPLUS_HOME support (default=no)"
+ac_help="$ac_help
+ --with-ssl Include SSL support (default=no)
+ --with-sslinc=DIR Where the SSL includes are (defaults to /usr/local/ssl/include)
+ --with-ssllib=DIR Where the SSL libraries are (defaults to /usr/local/ssl/lib)"
+ac_help="$ac_help
+ --with-syslog Include experimental SYSLOG support (default=no)"
+ac_help="$ac_help
+ --with-profiling-data Include gathering source code profile information (default=no)"
+ac_help="$ac_help
+ --with-quotas Include experimental disk-quota support (default=no)"
+ac_help="$ac_help
+ --with-utmp Include experimental utmp accounting (default=no)"
+ac_help="$ac_help
+ --with-privatedir=DIR Where to put smbpasswd ($ac_default_prefix/private)"
+ac_help="$ac_help
+ --with-lockdir=DIR Where to put lock files ($ac_default_prefix/var/locks)"
+ac_help="$ac_help
+ --with-swatdir=DIR Where to put SWAT files ($ac_default_prefix/swat)"
+ac_help="$ac_help
+ --with-manpages-langs={en,ja,pl} Choose man pages' language(s). (en)"
+ac_help="$ac_help
+ --with-spinlocks Use spin locks instead of fcntl locks (default=no) "
+ac_help="$ac_help
+ --with-acl-support Include ACL support (default=no)"
+ac_help="$ac_help
+ --with-winbind Build winbind (default, if supported by OS)"
+ac_help="$ac_help
+ --with-included-popt use bundled popt library, not from system"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=include/includes.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+# we want to be compatibe with older versions of Samba
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# compile with optimisation and without debugging by default
+CFLAGS="-O ${CFLAGS}"
+
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval="$enable_debug"
+ if eval "test x$enable_debug = xyes"; then
+ CFLAGS="${CFLAGS} -g"
+ fi
+fi
+
+
+# Check whether --enable-developer or --disable-developer was given.
+if test "${enable_developer+set}" = set; then
+ enableval="$enable_developer"
+ if eval "test x$enable_developer = xyes"; then
+ CFLAGS="${CFLAGS} -g -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -DDEBUG_PASSWORD -DDEVELOPER"
+ fi
+fi
+
+
+# Check whether --enable-dmalloc or --disable-dmalloc was given.
+if test "${enable_dmalloc+set}" = set; then
+ enableval="$enable_dmalloc"
+ :
+fi
+
+
+if test "x$enable_dmalloc" = xyes
+then
+ cat >> confdefs.h <<\EOF
+#define ENABLE_DMALLOC 1
+EOF
+
+ LIBS="$LIBS -ldmalloc"
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:647: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:677: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:728: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:760: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 771 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:776: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:802: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:807: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:816: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:835: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:897: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:954: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+ echo "$ac_t""$AWK" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:985: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+ grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+ echo "$ac_t""yes" 1>&6
+ ISC=yes # If later tests want to check for ISC.
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+else
+ echo "$ac_t""no" 1>&6
+ ISC=
+fi
+
+
+if test "x$CC" != xcc; then
+ echo $ac_n "checking whether $CC and cc understand -c and -o together""... $ac_c" 1>&6
+echo "configure:1008: checking whether $CC and cc understand -c and -o together" >&5
+else
+ echo $ac_n "checking whether cc understands -c and -o together""... $ac_c" 1>&6
+echo "configure:1011: checking whether cc understands -c and -o together" >&5
+fi
+set dummy $CC; ac_cc="`echo $2 |
+ sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`"
+if eval "test \"`echo '$''{'ac_cv_prog_cc_${ac_cc}_c_o'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'foo(){}' > conftest.c
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='${CC-cc} -c conftest.c -o conftest.o 1>&5'
+if { (eval echo configure:1023: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } &&
+ test -f conftest.o && { (eval echo configure:1024: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+then
+ eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+ if test "x$CC" != xcc; then
+ # Test first that cc exists at all.
+ if { ac_try='cc -c conftest.c 1>&5'; { (eval echo configure:1029: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+ ac_try='cc -c conftest.c -o conftest.o 1>&5'
+ if { (eval echo configure:1031: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } &&
+ test -f conftest.o && { (eval echo configure:1032: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+ then
+ # cc works too.
+ :
+ else
+ # cc exists but doesn't like -o.
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+ fi
+ fi
+ fi
+else
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+ cat >> confdefs.h <<\EOF
+#define NO_MINUS_C_MINUS_O 1
+EOF
+
+fi
+
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then
+ BROKEN_CC=
+else
+ BROKEN_CC=#
+fi
+
+
+echo $ac_n "checking that the C compiler understands volatile""... $ac_c" 1>&6
+echo "configure:1066: checking that the C compiler understands volatile" >&5
+if eval "test \"`echo '$''{'samba_cv_volatile'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 1072 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int main() {
+volatile int i = 0
+; return 0; }
+EOF
+if { (eval echo configure:1079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_volatile=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_volatile=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_volatile" 1>&6
+if test x"$samba_cv_volatile" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_VOLATILE 1
+EOF
+
+fi
+
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:1128: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:1149: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:1167: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+ case "$host_os" in
+ *irix6*) cat >> confdefs.h <<\EOF
+#include <standards.h>
+EOF
+
+ ;;
+esac
+
+
+
+ echo $ac_n "checking config.cache system type""... $ac_c" 1>&6
+echo "configure:1201: checking config.cache system type" >&5
+ if { test x"${ac_cv_host_system_type+set}" = x"set" &&
+ test x"$ac_cv_host_system_type" != x"$host"; } ||
+ { test x"${ac_cv_build_system_type+set}" = x"set" &&
+ test x"$ac_cv_build_system_type" != x"$build"; } ||
+ { test x"${ac_cv_target_system_type+set}" = x"set" &&
+ test x"$ac_cv_target_system_type" != x"$target"; }; then
+ echo "$ac_t""different" 1>&6
+ { echo "configure: error: "you must remove config.cache and restart configure"" 1>&2; exit 1; }
+ else
+ echo "$ac_t""same" 1>&6
+ fi
+ ac_cv_host_system_type="$host"
+ ac_cv_build_system_type="$build"
+ ac_cv_target_system_type="$target"
+
+
+#
+# Config CPPFLAG settings for strange OS's that must be set
+# before other tests.
+#
+case "$host_os" in
+# Try to work out if this is the native HPUX compiler that uses the -Ae flag.
+ *hpux*)
+ echo $ac_n "checking whether ${CC-cc} accepts -Ae""... $ac_c" 1>&6
+echo "configure:1226: checking whether ${CC-cc} accepts -Ae" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_Ae'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -Ae -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_Ae=yes
+else
+ ac_cv_prog_cc_Ae=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_Ae" 1>&6
+ # mmap on HPUX is completely broken...
+ cat >> confdefs.h <<\EOF
+#define MMAP_BLACKLIST 1
+EOF
+
+ if test $ac_cv_prog_cc_Ae = yes; then
+ CPPFLAGS="$CPPFLAGS -Ae"
+ fi
+#
+# Defines needed for HPUX support.
+# HPUX has bigcrypt but (sometimes?) doesn't use it for
+# password hashing - hence the USE_BOTH_CRYPT_CALLS define.
+#
+ case `uname -r` in
+ *9*|*10*)
+ CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_POSIX_SOURCE"
+ cat >> confdefs.h <<\EOF
+#define USE_BOTH_CRYPT_CALLS 1
+EOF
+
+ ;;
+ *11*)
+ CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_POSIX_SOURCE -D_LARGEFILE64_SOURCE"
+ cat >> confdefs.h <<\EOF
+#define USE_BOTH_CRYPT_CALLS 1
+EOF
+
+ ;;
+ esac
+ ;;
+#
+# AIX4.x doesn't even admit to having large
+# files *at all* unless the -D_LARGE_FILE or -D_LARGE_FILE_API flags are set.
+#
+ *aix4*)
+ echo "$ac_t""enabling large file support" 1>&6
+ CPPFLAGS="$CPPFLAGS -D_LARGE_FILES"
+ ;;
+#
+# Defines needed for Solaris 2.6/2.7 aka 7.0 to make it admit
+# to the existance of large files..
+# Note that -D_LARGEFILE64_SOURCE is different from the Sun
+# recommendations on large file support, however it makes the
+# compile work using gcc 2.7 and 2.8, whereas using the Sun
+# recommendation makes the compile fail on gcc2.7. JRA.
+#
+ *solaris*)
+ case `uname -r` in
+ 5.0*|5.1*|5.2*|5.3*|5.5*)
+ echo "$ac_t""no large file support" 1>&6
+ ;;
+ 5.*)
+ echo "$ac_t""enabling large file support" 1>&6
+ if test "$ac_cv_prog_gcc" = yes; then
+ ${CC-cc} -v >conftest.c 2>&1
+ ac_cv_gcc_compiler_version_number=`grep 'gcc version' conftest.c`
+ rm -fr conftest.c
+ case "$ac_cv_gcc_compiler_version_number" in
+ *"gcc version 2.6"*|*"gcc version 2.7"*)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE"
+ ;;
+ *)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ ;;
+ esac
+ else
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ fi
+ ;;
+ esac
+ ;;
+#
+# Tests needed for SINIX large file support.
+#
+ *sysv4*)
+ if test $host = mips-sni-sysv4 ; then
+ echo $ac_n "checking for LFS support""... $ac_c" 1>&6
+echo "configure:1318: checking for LFS support" >&5
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ if test "$cross_compiling" = yes; then
+ SINIX_LFS_SUPPORT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1325 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}
+EOF
+if { (eval echo configure:1337: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ SINIX_LFS_SUPPORT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ SINIX_LFS_SUPPORT=no
+fi
+rm -fr conftest*
+fi
+
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$SINIX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ CFLAGS="`getconf LFS64_CFLAGS` $CFLAGS"
+ LDFLAGS="`getconf LFS64_LDFLAGS` $LDFLAGS"
+ LIBS="`getconf LFS64_LIBS` $LIBS"
+ fi
+ echo "$ac_t""$SINIX_LFS_SUPPORT" 1>&6
+ fi
+ ;;
+
+# Tests for linux LFS support. Need kernel 2.4 and glibc2.2 or greater support.
+#
+ *linux*)
+ echo $ac_n "checking for LFS support""... $ac_c" 1>&6
+echo "configure:1364: checking for LFS support" >&5
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ if test "$cross_compiling" = yes; then
+ LINUX_LFS_SUPPORT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1371 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+#include <sys/utsname.h>
+main() {
+#if _LFS64_LARGEFILE == 1
+ struct utsname uts;
+ char *release;
+ int major, minor;
+
+ /* Ensure this is glibc 2.2 or higher */
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+ int libc_major = __GLIBC__;
+ int libc_minor = __GLIBC_MINOR__;
+
+ if (libc_major < 2)
+ exit(1);
+ if (libc_minor < 2)
+ exit(1);
+#endif
+
+ /* Ensure this is kernel 2.4 or higher */
+
+ uname(&uts);
+ release = uts.release;
+ major = atoi(strsep(&release, "."));
+ minor = atoi(strsep(&release, "."));
+
+ if (major > 2 || (major == 2 && minor > 3))
+ exit(0);
+ exit(1);
+#else
+ exit(1);
+#endif
+}
+
+EOF
+if { (eval echo configure:1409: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ LINUX_LFS_SUPPORT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ LINUX_LFS_SUPPORT=no
+fi
+rm -fr conftest*
+fi
+
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$LINUX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ fi
+ echo "$ac_t""$LINUX_LFS_SUPPORT" 1>&6
+ ;;
+
+ *hurd*)
+ echo $ac_n "checking for LFS support""... $ac_c" 1>&6
+echo "configure:1430: checking for LFS support" >&5
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ if test "$cross_compiling" = yes; then
+ GLIBC_LFS_SUPPORT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1437 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}
+EOF
+if { (eval echo configure:1449: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ GLIBC_LFS_SUPPORT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ GLIBC_LFS_SUPPORT=no
+fi
+rm -fr conftest*
+fi
+
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$GLIBC_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ fi
+ echo "$ac_t""$GLIBC_LFS_SUPPORT" 1>&6
+ ;;
+
+esac
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:1471: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat > conftest.$ac_ext <<EOF
+#line 1478 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:1485: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+ inline | yes) ;;
+ no) cat >> confdefs.h <<\EOF
+#define inline
+EOF
+ ;;
+ *) cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1511: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1526 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1532: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1543 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1549: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1560 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1566: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1591: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1596 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1604: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1621 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1639 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1660 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1671: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1699: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1704 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1712: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1737: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1745 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1756: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1778: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1786 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1797: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1820: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1825 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1834: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1855: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1860 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1876: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+for ac_hdr in arpa/inet.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1900: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1905 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1910: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in unistd.h utime.h grp.h sys/id.h limits.h memory.h net/if.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1940: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1945 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1950: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in compat.h rpc/rpc.h rpcsvc/nis.h rpcsvc/yp_prot.h rpcsvc/ypclnt.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1980: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1985 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/mode.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2020: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2025 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2030: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2060: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2065 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2070: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2100: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2105 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2110: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2140: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2145 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2150: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in security/pam_modules.h security/_pam_macros.h ldap.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2180: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2185 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2190: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+#
+# HPUX has a bug in that including shadow.h causes a re-definition of MAXINT.
+# This causes configure to fail to detect it. Check for shadow separately on HPUX.
+#
+case "$host_os" in
+ *hpux*)
+ cat > conftest.$ac_ext <<EOF
+#line 2224 "configure"
+#include "confdefs.h"
+#include <shadow.h>
+int main() {
+struct spwd testme
+; return 0; }
+EOF
+if { (eval echo configure:2231: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_shadow_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_shadow_h=no
+fi
+rm -f conftest*
+ if test x"$ac_cv_header_shadow_h" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SHADOW_H 1
+EOF
+
+ fi
+ ;;
+esac
+for ac_hdr in shadow.h netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2253: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2258 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2263: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in nss.h nss_common.h ns_api.h sys/security.h security/pam_appl.h security/pam_modules.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2293: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2298 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in stropts.h poll.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2333: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2338 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2343: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/capability.h syscall.h sys/syscall.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2373: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2378 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2383: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/acl.h sys/cdefs.h glob.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2413: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2418 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2423: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# For experimental utmp support (lastlog on some BSD-like systems)
+for ac_hdr in utmp.h utmpx.h lastlog.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2455: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2460 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2465: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# For quotas on Veritas VxFS filesystems
+for ac_hdr in sys/fs/vx_quota.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2497: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2502 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2507: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# For quotas on Linux XFS filesystems
+for ac_hdr in linux/xqm.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2539: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2544 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2549: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking size of int""... $ac_c" 1>&6
+echo "configure:2577: checking size of int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_sizeof_int=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2585 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(int));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2597: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_int=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+EOF
+
+
+echo $ac_n "checking size of long""... $ac_c" 1>&6
+echo "configure:2617: checking size of long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_sizeof_long=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2625 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(long));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2637: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_long=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+EOF
+
+
+echo $ac_n "checking size of short""... $ac_c" 1>&6
+echo "configure:2657: checking size of short" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_sizeof_short=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2665 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(short));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2677: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_short=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_short=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_short" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+EOF
+
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:2698: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2703 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:2752: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:2773: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat > conftest.$ac_ext <<EOF
+#line 2780 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:2787: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+ inline | yes) ;;
+ no) cat >> confdefs.h <<\EOF
+#define inline
+EOF
+ ;;
+ *) cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:2813: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 2820 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2831: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 2835 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2846: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_bigendian=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2866 "configure"
+#include "confdefs.h"
+main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:2879: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_bigendian=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+ cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6
+echo "configure:2903: checking whether char is unsigned" >&5
+if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$GCC" = yes; then
+ # GCC predefines this symbol on systems where it applies.
+cat > conftest.$ac_ext <<EOF
+#line 2910 "configure"
+#include "confdefs.h"
+#ifdef __CHAR_UNSIGNED__
+ yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_c_char_unsigned=yes
+else
+ rm -rf conftest*
+ ac_cv_c_char_unsigned=no
+fi
+rm -f conftest*
+
+else
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2932 "configure"
+#include "confdefs.h"
+/* volatile prevents gcc2 from optimizing the test away on sparcs. */
+#if !defined(__STDC__) || __STDC__ != 1
+#define volatile
+#endif
+main() {
+ volatile char c = 255; exit(c < 0);
+}
+EOF
+if { (eval echo configure:2942: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_char_unsigned=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_char_unsigned=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_char_unsigned" 1>&6
+if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then
+ cat >> confdefs.h <<\EOF
+#define __CHAR_UNSIGNED__ 1
+EOF
+
+fi
+
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2967: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2972 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2989: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:3008: checking for uid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3013 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "uid_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_uid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+if test $ac_cv_type_uid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:3042: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3047 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_mode_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+ cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:3075: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3080 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:3108: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3113 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:3141: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3146 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
+echo "configure:3174: checking for st_rdev in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3179 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if { (eval echo configure:3187: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6
+if test $ac_cv_struct_st_rdev = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+echo $ac_n "checking for d_off in dirent""... $ac_c" 1>&6
+echo "configure:3208: checking for d_off in dirent" >&5
+if eval "test \"`echo '$''{'ac_cv_dirent_d_off'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3213 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+int main() {
+struct dirent d; d.d_off;
+; return 0; }
+EOF
+if { (eval echo configure:3223: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_dirent_d_off=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_dirent_d_off=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_dirent_d_off" 1>&6
+if test $ac_cv_dirent_d_off = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_DIRENT_D_OFF 1
+EOF
+
+fi
+
+echo $ac_n "checking for ino_t""... $ac_c" 1>&6
+echo "configure:3244: checking for ino_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ino_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3249 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])ino_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ino_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ino_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ino_t" 1>&6
+if test $ac_cv_type_ino_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ino_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for loff_t""... $ac_c" 1>&6
+echo "configure:3277: checking for loff_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_loff_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3282 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])loff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_loff_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_loff_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_loff_t" 1>&6
+if test $ac_cv_type_loff_t = no; then
+ cat >> confdefs.h <<\EOF
+#define loff_t off_t
+EOF
+
+fi
+
+echo $ac_n "checking for offset_t""... $ac_c" 1>&6
+echo "configure:3310: checking for offset_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_offset_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3315 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])offset_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_offset_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_offset_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_offset_t" 1>&6
+if test $ac_cv_type_offset_t = no; then
+ cat >> confdefs.h <<\EOF
+#define offset_t loff_t
+EOF
+
+fi
+
+echo $ac_n "checking for ssize_t""... $ac_c" 1>&6
+echo "configure:3343: checking for ssize_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3348 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ssize_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ssize_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ssize_t" 1>&6
+if test $ac_cv_type_ssize_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ssize_t int
+EOF
+
+fi
+
+echo $ac_n "checking for wchar_t""... $ac_c" 1>&6
+echo "configure:3376: checking for wchar_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_wchar_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3381 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])wchar_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_wchar_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_wchar_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_wchar_t" 1>&6
+if test $ac_cv_type_wchar_t = no; then
+ cat >> confdefs.h <<\EOF
+#define wchar_t unsigned short
+EOF
+
+fi
+
+
+############################################
+# for cups support we need libcups, and a handful of header files
+
+echo $ac_n "checking for httpConnect in -lcups""... $ac_c" 1>&6
+echo "configure:3413: checking for httpConnect in -lcups" >&5
+ac_lib_var=`echo cups'_'httpConnect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcups $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3421 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char httpConnect();
+
+int main() {
+httpConnect()
+; return 0; }
+EOF
+if { (eval echo configure:3432: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo cups | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lcups $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# I wonder if there is a nicer way of doing this?
+
+if test x"$ac_cv_lib_cups_httpConnect" = x"yes"; then
+ for ac_hdr in cups/cups.h cups/language.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3467: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3472 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3477: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ if test x"$ac_cv_header_cups_cups_h" = x"yes"; then
+ if test x"$ac_cv_header_cups_language_h" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_CUPS 1
+EOF
+
+ fi
+ fi
+fi
+
+############################################
+# we need libdl for PAM and the new VFS code
+echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "configure:3516: checking for dlopen in -ldl" >&5
+ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3524 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo configure:3535: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldl";
+ cat >> confdefs.h <<\EOF
+#define HAVE_LIBDL 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+############################################
+# check if the compiler can do immediate structures
+echo $ac_n "checking for immediate structures""... $ac_c" 1>&6
+echo "configure:3563: checking for immediate structures" >&5
+if eval "test \"`echo '$''{'samba_cv_immediate_structures'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3569 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+int main() {
+
+ #define X_FOOBAR(x) ((FOOBAR) { x })
+ typedef struct {unsigned x;} FOOBAR;
+ FOOBAR f = X_FOOBAR(1);
+
+; return 0; }
+EOF
+if { (eval echo configure:3581: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_immediate_structures=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_immediate_structures=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_immediate_structures" 1>&6
+if test x"$samba_cv_immediate_structures" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_IMMEDIATE_STRUCTURES 1
+EOF
+
+fi
+
+############################################
+# check for unix domain sockets
+echo $ac_n "checking for unix domain sockets""... $ac_c" 1>&6
+echo "configure:3604: checking for unix domain sockets" >&5
+if eval "test \"`echo '$''{'samba_cv_unixsocket'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3610 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+int main() {
+
+ struct sockaddr_un sunaddr;
+ sunaddr.sun_family = AF_UNIX;
+
+; return 0; }
+EOF
+if { (eval echo configure:3625: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_unixsocket=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_unixsocket=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_unixsocket" 1>&6
+if test x"$samba_cv_unixsocket" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UNIXSOCKET 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for socklen_t type""... $ac_c" 1>&6
+echo "configure:3647: checking for socklen_t type" >&5
+if eval "test \"`echo '$''{'samba_cv_socklen_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3653 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>
+int main() {
+socklen_t i = 0
+; return 0; }
+EOF
+if { (eval echo configure:3666: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_socklen_t=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_socklen_t=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_socklen_t" 1>&6
+if test x"$samba_cv_socklen_t" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKLEN_T_TYPE 1
+EOF
+
+fi
+
+echo $ac_n "checking for sig_atomic_t type""... $ac_c" 1>&6
+echo "configure:3687: checking for sig_atomic_t type" >&5
+if eval "test \"`echo '$''{'samba_cv_sig_atomic_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3693 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>
+int main() {
+sig_atomic_t i = 0
+; return 0; }
+EOF
+if { (eval echo configure:3706: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_sig_atomic_t=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_sig_atomic_t=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_sig_atomic_t" 1>&6
+if test x"$samba_cv_sig_atomic_t" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SIG_ATOMIC_T_TYPE 1
+EOF
+
+fi
+
+# stupid headers have the functions but no declaration. grrrr.
+
+ echo $ac_n "checking for errno declaration""... $ac_c" 1>&6
+echo "configure:3729: checking for errno declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_errno_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3735 "configure"
+#include "confdefs.h"
+#include <errno.h>
+int main() {
+int i = (int)errno
+; return 0; }
+EOF
+if { (eval echo configure:3742: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_errno_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_errno_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_errno_decl" 1>&6
+ if test x"$ac_cv_have_errno_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ERRNO_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for setresuid declaration""... $ac_c" 1>&6
+echo "configure:3764: checking for setresuid declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_setresuid_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3770 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+int main() {
+int i = (int)setresuid
+; return 0; }
+EOF
+if { (eval echo configure:3777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_setresuid_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_setresuid_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_setresuid_decl" 1>&6
+ if test x"$ac_cv_have_setresuid_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SETRESUID_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for setresgid declaration""... $ac_c" 1>&6
+echo "configure:3799: checking for setresgid declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_setresgid_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3805 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+int main() {
+int i = (int)setresgid
+; return 0; }
+EOF
+if { (eval echo configure:3812: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_setresgid_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_setresgid_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_setresgid_decl" 1>&6
+ if test x"$ac_cv_have_setresgid_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SETRESGID_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for asprintf declaration""... $ac_c" 1>&6
+echo "configure:3834: checking for asprintf declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_asprintf_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3840 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+int i = (int)asprintf
+; return 0; }
+EOF
+if { (eval echo configure:3847: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_asprintf_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_asprintf_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_asprintf_decl" 1>&6
+ if test x"$ac_cv_have_asprintf_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ASPRINTF_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for vasprintf declaration""... $ac_c" 1>&6
+echo "configure:3869: checking for vasprintf declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_vasprintf_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3875 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+int i = (int)vasprintf
+; return 0; }
+EOF
+if { (eval echo configure:3882: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_vasprintf_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_vasprintf_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_vasprintf_decl" 1>&6
+ if test x"$ac_cv_have_vasprintf_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_VASPRINTF_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for vsnprintf declaration""... $ac_c" 1>&6
+echo "configure:3904: checking for vsnprintf declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_vsnprintf_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3910 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+int i = (int)vsnprintf
+; return 0; }
+EOF
+if { (eval echo configure:3917: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_vsnprintf_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_vsnprintf_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_vsnprintf_decl" 1>&6
+ if test x"$ac_cv_have_vsnprintf_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_VSNPRINTF_DECL 1
+EOF
+
+ fi
+
+
+ echo $ac_n "checking for snprintf declaration""... $ac_c" 1>&6
+echo "configure:3939: checking for snprintf declaration" >&5
+if eval "test \"`echo '$''{'ac_cv_have_snprintf_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3945 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+int i = (int)snprintf
+; return 0; }
+EOF
+if { (eval echo configure:3952: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_have_snprintf_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_have_snprintf_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_have_snprintf_decl" 1>&6
+ if test x"$ac_cv_have_snprintf_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SNPRINTF_DECL 1
+EOF
+
+ fi
+
+
+# and glibc has setresuid under linux but the function does
+# nothing until kernel 2.1.44! very dumb.
+echo $ac_n "checking for real setresuid""... $ac_c" 1>&6
+echo "configure:3976: checking for real setresuid" >&5
+if eval "test \"`echo '$''{'samba_cv_have_setresuid'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ if test "$cross_compiling" = yes; then
+ samba_cv_have_setresuid=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3985 "configure"
+#include "confdefs.h"
+#include <errno.h>
+main() { setresuid(1,1,1); setresuid(2,2,2); exit(errno==EPERM?0:1);}
+EOF
+if { (eval echo configure:3990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_have_setresuid=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_have_setresuid=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_have_setresuid" 1>&6
+if test x"$samba_cv_have_setresuid" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SETRESUID 1
+EOF
+
+fi
+
+# Do the same check for setresguid...
+#
+echo $ac_n "checking for real setresgid""... $ac_c" 1>&6
+echo "configure:4015: checking for real setresgid" >&5
+if eval "test \"`echo '$''{'samba_cv_have_setresgid'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ if test "$cross_compiling" = yes; then
+ samba_cv_have_setresgid=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4024 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+#include <errno.h>
+main() { errno = 0; setresgid(1,1,1); exit(errno != 0 ? (errno==EPERM ? 0 : 1) : 0);}
+EOF
+if { (eval echo configure:4030: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_have_setresgid=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_have_setresgid=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_have_setresgid" 1>&6
+if test x"$samba_cv_have_setresgid" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SETRESGID 1
+EOF
+
+fi
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:4053: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_memcmp_clean=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4061 "configure"
+#include "confdefs.h"
+
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:4071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_memcmp_clean=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+
+###############################################
+# test for where we get crypt() from
+for ac_func in crypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4094: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4099 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4122: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test x"$ac_cv_func_crypt" = x"no"; then
+ echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:4148: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcrypt $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4156 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:4167: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lcrypt";
+ cat >> confdefs.h <<\EOF
+#define HAVE_CRYPT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+###############################################
+# Readline included by default unless explicitly asked not to
+test "${with_readline+set}" != "set" && with_readline=yes
+
+# test for where we get readline() from
+echo $ac_n "checking whether to use readline""... $ac_c" 1>&6
+echo "configure:4200: checking whether to use readline" >&5
+# Check whether --with-readline or --without-readline was given.
+if test "${with_readline+set}" = set; then
+ withval="$with_readline"
+ case "$with_readline" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+
+ for ac_hdr in readline.h history.h readline/readline.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4212: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4217 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ for ac_hdr in readline/history.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4252: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4257 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4262: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+ for ac_hdr in readline.h readline/readline.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4293: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4298 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+ for termlib in ncurses curses termcap terminfo termlib; do
+ echo $ac_n "checking for tgetent in -l${termlib}""... $ac_c" 1>&6
+echo "configure:4326: checking for tgetent in -l${termlib}" >&5
+ac_lib_var=`echo ${termlib}'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-l${termlib} $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4334 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:4345: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ TERMLIBS="-l${termlib}"; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ done
+ echo $ac_n "checking for rl_callback_handler_install in -lreadline""... $ac_c" 1>&6
+echo "configure:4367: checking for rl_callback_handler_install in -lreadline" >&5
+ac_lib_var=`echo readline'_'rl_callback_handler_install | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lreadline $TERMLIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4375 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char rl_callback_handler_install();
+
+int main() {
+rl_callback_handler_install()
+; return 0; }
+EOF
+if { (eval echo configure:4386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ TERMLIBS="-lreadline $TERMLIBS"
+ cat >> confdefs.h <<\EOF
+#define HAVE_LIBREADLINE 1
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&6
+TERMLIBS=
+fi
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+
+ # Needed for AC_CHECK_HEADERS and AC_CHECK_LIB to look at
+ # alternate readline path
+ _ldflags=${LDFLAGS}
+ _cppflags=${CPPFLAGS}
+
+ # Add additional search path
+ LDFLAGS="-L$with_readline/lib $LDFLAGS"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+
+ for ac_hdr in readline.h history.h readline/readline.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4437: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4442 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4447: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ for ac_hdr in readline/history.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4477: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4482 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4487: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+ for ac_hdr in readline.h readline/readline.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4518: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4523 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4528: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+ for termlib in ncurses curses termcap terminfo termlib; do
+ echo $ac_n "checking for tgetent in -l${termlib}""... $ac_c" 1>&6
+echo "configure:4551: checking for tgetent in -l${termlib}" >&5
+ac_lib_var=`echo ${termlib}'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-l${termlib} $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4559 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:4570: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ TERMLIBS="-l${termlib}"; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ done
+ echo $ac_n "checking for rl_callback_handler_install in -lreadline""... $ac_c" 1>&6
+echo "configure:4592: checking for rl_callback_handler_install in -lreadline" >&5
+ac_lib_var=`echo readline'_'rl_callback_handler_install | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lreadline $TERMLIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4600 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char rl_callback_handler_install();
+
+int main() {
+rl_callback_handler_install()
+; return 0; }
+EOF
+if { (eval echo configure:4611: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ TERMLDFLAGS="-L$with_readline/lib"
+ TERMCPPFLAGS="-I$with_readline/include"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+ TERMLIBS="-lreadline $TERMLIBS"
+ cat >> confdefs.h <<\EOF
+#define HAVE_LIBREADLINE 1
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&6
+TERMLIBS= CPPFLAGS=$_cppflags
+fi
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+ LDFLAGS=$_ldflags
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+
+# The readline API changed slightly from readline3 to readline4, so
+# code will generate warnings on one of them unless we have a few
+# special cases.
+echo $ac_n "checking for rl_completion_matches in -lreadline""... $ac_c" 1>&6
+echo "configure:4661: checking for rl_completion_matches in -lreadline" >&5
+ac_lib_var=`echo readline'_'rl_completion_matches | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lreadline $TERMLIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4669 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char rl_completion_matches();
+
+int main() {
+rl_completion_matches()
+; return 0; }
+EOF
+if { (eval echo configure:4680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_NEW_LIBREADLINE 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# The following test taken from the cvs sources
+# If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
+# The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
+# libsocket.so which has a bad implementation of gethostbyname (it
+# only looks in /etc/hosts), so we only look for -lsocket if we need
+# it.
+for ac_func in connect
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4713: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4718 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4741: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test x"$ac_cv_func_connect" = x"no"; then
+ case "$LIBS" in
+ *-lnsl*) ;;
+ *) echo $ac_n "checking for printf in -lnsl_s""... $ac_c" 1>&6
+echo "configure:4769: checking for printf in -lnsl_s" >&5
+ac_lib_var=`echo nsl_s'_'printf | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl_s $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4777 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char printf();
+
+int main() {
+printf()
+; return 0; }
+EOF
+if { (eval echo configure:4788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo nsl_s | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lnsl_s $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ case "$LIBS" in
+ *-lnsl*) ;;
+ *) echo $ac_n "checking for printf in -lnsl""... $ac_c" 1>&6
+echo "configure:4819: checking for printf in -lnsl" >&5
+ac_lib_var=`echo nsl'_'printf | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4827 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char printf();
+
+int main() {
+printf()
+; return 0; }
+EOF
+if { (eval echo configure:4838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lnsl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ case "$LIBS" in
+ *-lsocket*) ;;
+ *) echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6
+echo "configure:4869: checking for connect in -lsocket" >&5
+ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4877 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+connect()
+; return 0; }
+EOF
+if { (eval echo configure:4888: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ case "$LIBS" in
+ *-linet*) ;;
+ *) echo $ac_n "checking for connect in -linet""... $ac_c" 1>&6
+echo "configure:4919: checking for connect in -linet" >&5
+ac_lib_var=`echo inet'_'connect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-linet $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4927 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+connect()
+; return 0; }
+EOF
+if { (eval echo configure:4938: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo inet | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-linet $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ if test x"$ac_cv_lib_socket_connect" = x"yes" ||
+ test x"$ac_cv_lib_inet_connect" = x"yes"; then
+ # ac_cv_func_connect=yes
+ # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
+ cat >> confdefs.h <<\EOF
+#define HAVE_CONNECT 1
+EOF
+
+ fi
+fi
+
+###############################################
+# test for where we get get_yp_default_domain() from
+for ac_func in yp_get_default_domain
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4982: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4987 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5010: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test x"$ac_cv_func_yp_get_default_domain" = x"no"; then
+ echo $ac_n "checking for yp_get_default_domain in -lnsl""... $ac_c" 1>&6
+echo "configure:5036: checking for yp_get_default_domain in -lnsl" >&5
+ac_lib_var=`echo nsl'_'yp_get_default_domain | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5044 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char yp_get_default_domain();
+
+int main() {
+yp_get_default_domain()
+; return 0; }
+EOF
+if { (eval echo configure:5055: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lnsl";
+ cat >> confdefs.h <<\EOF
+#define HAVE_YP_GET_DEFAULT_DOMAIN 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+# Check if we have execl, if not we need to compile smbrun.
+for ac_func in execl
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5085: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5090 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test x"$ac_cv_func_execl" = x"no"; then
+ RUNPROG="bin/smbrun"
+else
+ RUNPROG=""
+fi
+
+for ac_func in waitpid getcwd strdup strtoul strerror chown fchown chmod fchmod chroot
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5146: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5151 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5174: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in fstat strchr utime utimes getrlimit fsync bzero memset strlcpy strlcat
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5201: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5206 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5229: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in memmove vsnprintf snprintf asprintf vasprintf setsid glob strpbrk pipe crypt16 getauthuid
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5256: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5261 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in strftime sigprocmask sigblock sigaction sigset innetgr setnetgrent getnetgrent endnetgrent
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5311: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5316 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5339: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in initgroups select poll rdchk getgrnam getgrent pathconf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5366: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5371 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5394: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in setpriv setgidx setuidx setgroups sysconf mktime rename ftruncate stat64 fstat64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5421: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5426 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5449: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in lstat64 fopen64 atexit grantpt dup2 lseek64 ftruncate64 readdir64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5476: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5481 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5504: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in fseek64 fseeko64 ftell64 ftello64 setluid getpwanam setlinebuf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5531: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5536 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in srandom random srand rand setenv usleep strcasecmp fcvt fcvtl symlink readlink
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5586: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5591 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5614: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in syslog vsyslog
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5641: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5646 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5669: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+# setbuffer is needed for smbtorture
+for ac_func in setbuffer
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5697: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5702 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# syscall() is needed for smbwrapper.
+for ac_func in syscall
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5754: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5759 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5782: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_func in _dup _dup2 _opendir _readdir _seekdir _telldir _closedir
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5810: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5815 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in __dup __dup2 __opendir __readdir __seekdir __telldir __closedir
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5865: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5870 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5893: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in __getcwd _getcwd
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5920: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5925 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5948: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in __xstat __fxstat __lxstat
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5975: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5980 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in _stat _lstat _fstat __stat __lstat __fstat
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6030: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6035 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6058: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in _acl __acl _facl __facl _open __open _chdir __chdir
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6085: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6090 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in _close __close _fchdir __fchdir _fcntl __fcntl
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6140: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6145 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in getdents _getdents __getdents _lseek __lseek _read __read
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6195: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6200 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6223: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in _write __write _fork __fork
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6250: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6255 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6278: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in _stat64 __stat64 _fstat64 __fstat64 _lstat64 __lstat64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6305: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6310 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6333: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in __sys_llseek llseek _llseek __llseek readdir64 _readdir64 __readdir64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6360: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6365 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6388: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in pread _pread __pread pread64 _pread64 __pread64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6415: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6420 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6443: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in pwrite _pwrite __pwrite pwrite64 _pwrite64 __pwrite64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6470: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6475 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6498: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in open64 _open64 __open64 creat64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6525: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6530 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6553: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+#
+# stat64 family may need <sys/stat.h> on some systems, notably ReliantUNIX
+#
+
+if test x$ac_cv_func_stat64 = xno ; then
+ echo $ac_n "checking for stat64 in <sys/stat.h>""... $ac_c" 1>&6
+echo "configure:6584: checking for stat64 in <sys/stat.h>" >&5
+ cat > conftest.$ac_ext <<EOF
+#line 6586 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+
+int main() {
+struct stat64 st64; exit(stat64(".",&st64));
+; return 0; }
+EOF
+if { (eval echo configure:6598: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_stat64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ echo "$ac_t""$ac_cv_func_stat64" 1>&6
+ if test x$ac_cv_func_stat64 = xyes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STAT64 1
+EOF
+
+ fi
+fi
+
+if test x$ac_cv_func_lstat64 = xno ; then
+ echo $ac_n "checking for lstat64 in <sys/stat.h>""... $ac_c" 1>&6
+echo "configure:6617: checking for lstat64 in <sys/stat.h>" >&5
+ cat > conftest.$ac_ext <<EOF
+#line 6619 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+
+int main() {
+struct stat64 st64; exit(lstat64(".",&st64));
+; return 0; }
+EOF
+if { (eval echo configure:6631: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_lstat64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ echo "$ac_t""$ac_cv_func_lstat64" 1>&6
+ if test x$ac_cv_func_lstat64 = xyes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LSTAT64 1
+EOF
+
+ fi
+fi
+
+if test x$ac_cv_func_fstat64 = xno ; then
+ echo $ac_n "checking for fstat64 in <sys/stat.h>""... $ac_c" 1>&6
+echo "configure:6650: checking for fstat64 in <sys/stat.h>" >&5
+ cat > conftest.$ac_ext <<EOF
+#line 6652 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+
+int main() {
+struct stat64 st64; exit(fstat64(0,&st64));
+; return 0; }
+EOF
+if { (eval echo configure:6664: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_fstat64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ echo "$ac_t""$ac_cv_func_fstat64" 1>&6
+ if test x$ac_cv_func_fstat64 = xyes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FSTAT64 1
+EOF
+
+ fi
+fi
+
+#####################################
+# we might need the resolv library on some systems
+echo $ac_n "checking for dn_expand in -lresolv""... $ac_c" 1>&6
+echo "configure:6684: checking for dn_expand in -lresolv" >&5
+ac_lib_var=`echo resolv'_'dn_expand | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lresolv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 6692 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dn_expand();
+
+int main() {
+dn_expand()
+; return 0; }
+EOF
+if { (eval echo configure:6703: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lresolv $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+#
+# Check for the functions putprpwnam, set_auth_parameters,
+# getspnam, bigcrypt and getprpwnam in -lsec and -lsecurity
+# Needed for OSF1 and HPUX.
+#
+
+case "$LIBS" in
+ *-lsecurity*) for ac_func in putprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6741: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6746 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for putprpwnam in -lsecurity""... $ac_c" 1>&6
+echo "configure:6794: checking for putprpwnam in -lsecurity" >&5
+ac_lib_var=`echo security'_'putprpwnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsecurity $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 6802 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char putprpwnam();
+
+int main() {
+putprpwnam()
+; return 0; }
+EOF
+if { (eval echo configure:6813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsecurity $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in putprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6843: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6848 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6871: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+case "$LIBS" in
+ *-lsec*) for ac_func in putprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6902: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6907 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for putprpwnam in -lsec""... $ac_c" 1>&6
+echo "configure:6955: checking for putprpwnam in -lsec" >&5
+ac_lib_var=`echo sec'_'putprpwnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsec $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 6963 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char putprpwnam();
+
+int main() {
+putprpwnam()
+; return 0; }
+EOF
+if { (eval echo configure:6974: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo sec | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsec $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in putprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7004: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7009 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+case "$LIBS" in
+ *-lsecurity*) for ac_func in set_auth_parameters
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7064: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7069 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7092: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for set_auth_parameters in -lsecurity""... $ac_c" 1>&6
+echo "configure:7117: checking for set_auth_parameters in -lsecurity" >&5
+ac_lib_var=`echo security'_'set_auth_parameters | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsecurity $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7125 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char set_auth_parameters();
+
+int main() {
+set_auth_parameters()
+; return 0; }
+EOF
+if { (eval echo configure:7136: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsecurity $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in set_auth_parameters
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7166: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7171 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7194: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+case "$LIBS" in
+ *-lsec*) for ac_func in set_auth_parameters
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7225: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7230 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7253: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for set_auth_parameters in -lsec""... $ac_c" 1>&6
+echo "configure:7278: checking for set_auth_parameters in -lsec" >&5
+ac_lib_var=`echo sec'_'set_auth_parameters | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsec $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7286 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char set_auth_parameters();
+
+int main() {
+set_auth_parameters()
+; return 0; }
+EOF
+if { (eval echo configure:7297: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo sec | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsec $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in set_auth_parameters
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7327: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7332 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+# UnixWare 7.x has its getspnam in -lgen
+case "$LIBS" in
+ *-lgen*) for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7388: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7393 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7416: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for getspnam in -lgen""... $ac_c" 1>&6
+echo "configure:7441: checking for getspnam in -lgen" >&5
+ac_lib_var=`echo gen'_'getspnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lgen $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7449 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getspnam();
+
+int main() {
+getspnam()
+; return 0; }
+EOF
+if { (eval echo configure:7460: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo gen | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lgen $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7490: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7495 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7518: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+case "$LIBS" in
+ *-lsecurity*) for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7550: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7555 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7578: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for getspnam in -lsecurity""... $ac_c" 1>&6
+echo "configure:7603: checking for getspnam in -lsecurity" >&5
+ac_lib_var=`echo security'_'getspnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsecurity $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7611 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getspnam();
+
+int main() {
+getspnam()
+; return 0; }
+EOF
+if { (eval echo configure:7622: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsecurity $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7652: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7657 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+case "$LIBS" in
+ *-lsec*) for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7711: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7716 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7739: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for getspnam in -lsec""... $ac_c" 1>&6
+echo "configure:7764: checking for getspnam in -lsec" >&5
+ac_lib_var=`echo sec'_'getspnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsec $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7772 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getspnam();
+
+int main() {
+getspnam()
+; return 0; }
+EOF
+if { (eval echo configure:7783: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo sec | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsec $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7813: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7818 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7841: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+case "$LIBS" in
+ *-lsecurity*) for ac_func in bigcrypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7873: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7878 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7901: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for bigcrypt in -lsecurity""... $ac_c" 1>&6
+echo "configure:7926: checking for bigcrypt in -lsecurity" >&5
+ac_lib_var=`echo security'_'bigcrypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsecurity $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7934 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char bigcrypt();
+
+int main() {
+bigcrypt()
+; return 0; }
+EOF
+if { (eval echo configure:7945: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsecurity $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in bigcrypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7975: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 7980 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+case "$LIBS" in
+ *-lsec*) for ac_func in bigcrypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8034: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8039 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for bigcrypt in -lsec""... $ac_c" 1>&6
+echo "configure:8087: checking for bigcrypt in -lsec" >&5
+ac_lib_var=`echo sec'_'bigcrypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsec $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8095 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char bigcrypt();
+
+int main() {
+bigcrypt()
+; return 0; }
+EOF
+if { (eval echo configure:8106: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo sec | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsec $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in bigcrypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8136: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8141 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8164: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+case "$LIBS" in
+ *-lsecurity*) for ac_func in getprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8196: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8201 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8224: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for getprpwnam in -lsecurity""... $ac_c" 1>&6
+echo "configure:8249: checking for getprpwnam in -lsecurity" >&5
+ac_lib_var=`echo security'_'getprpwnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsecurity $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8257 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getprpwnam();
+
+int main() {
+getprpwnam()
+; return 0; }
+EOF
+if { (eval echo configure:8268: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsecurity $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in getprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8298: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8303 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8326: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+case "$LIBS" in
+ *-lsec*) for ac_func in getprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8357: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8362 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8385: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+ ;;
+ *) echo $ac_n "checking for getprpwnam in -lsec""... $ac_c" 1>&6
+echo "configure:8410: checking for getprpwnam in -lsec" >&5
+ac_lib_var=`echo sec'_'getprpwnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsec $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8418 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getprpwnam();
+
+int main() {
+getprpwnam()
+; return 0; }
+EOF
+if { (eval echo configure:8429: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo sec | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsec $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ for ac_func in getprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:8459: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8464 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ ;;
+ esac
+
+
+# this bit needs to be modified for each OS that is suported by
+# smbwrapper. You need to specify how to created a shared library and
+# how to compile C code to produce PIC object files
+
+# these are the defaults, good for lots of systems
+HOST_OS="$host_os"
+LDSHFLAGS="-shared"
+SHLD="\${CC}"
+PICFLAG=""
+PICSUFFIX="po"
+POBAD_CC="#"
+SHLIBEXT="so"
+# Assume non-shared by default and override below
+BLDSHARED="false"
+echo $ac_n "checking ability to build shared libraries""... $ac_c" 1>&6
+echo "configure:8530: checking ability to build shared libraries" >&5
+
+# and these are for particular systems
+case "$host_os" in
+ *linux*) cat >> confdefs.h <<\EOF
+#define LINUX 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ PICFLAG="-fPIC"
+ ;;
+ *solaris*) cat >> confdefs.h <<\EOF
+#define SUNOS5 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-h \$@ -G"
+ if test "${ac_cv_prog_CC}" = "gcc"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ POBAD_CC=""
+ PICSUFFIX="po.o"
+ fi
+ ;;
+ *sunos*) cat >> confdefs.h <<\EOF
+#define SUNOS4 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-h,\$@ -G"
+ PICFLAG="-KPIC" # Is this correct for SunOS
+ ;;
+ *bsd*) BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-fPIC"
+ ;;
+ *irix*) cat >> confdefs.h <<\EOF
+#define IRIX 1
+EOF
+
+ case "$host_os" in
+ *irix6*) cat >> confdefs.h <<\EOF
+#define IRIX6 1
+EOF
+
+ ;;
+ esac
+ ATTEMPT_WRAP32_BUILD=yes
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ if test "${ac_cv_prog_CC}" = "gcc"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ fi
+ ;;
+ *aix*) cat >> confdefs.h <<\EOF
+#define AIX 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-bexpall,-bM:SRE,-bnoentry"
+ PICFLAG="-O2 -qmaxmem=6000"
+ ;;
+ *hpux*) cat >> confdefs.h <<\EOF
+#define HPUX 1
+EOF
+
+ SHLIBEXT="sl"
+ # Use special PIC flags for the native HP-UX compiler.
+ if test $ac_cv_prog_cc_Ae = yes; then
+ #BLDSHARED="true"
+ LDSHFLAGS="-b -z +h \$@"
+ PICFLAG="+z"
+ fi
+ ;;
+ *qnx*) cat >> confdefs.h <<\EOF
+#define QNX 1
+EOF
+;;
+ *osf*) cat >> confdefs.h <<\EOF
+#define OSF1 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-fPIC"
+ ;;
+ *sco*) cat >> confdefs.h <<\EOF
+#define SCO 1
+EOF
+;;
+ *unixware*) cat >> confdefs.h <<\EOF
+#define UNIXWARE 1
+EOF
+
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-KPIC"
+ ;;
+ *next2*) cat >> confdefs.h <<\EOF
+#define NEXT2 1
+EOF
+;;
+ *dgux*) # Extract the first word of "groff", so it can be a program name with args.
+set dummy groff; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:8639: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_ROFF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$ROFF"; then
+ ac_cv_prog_ROFF="$ROFF" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_ROFF="groff -etpsR -Tascii -man"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+ROFF="$ac_cv_prog_ROFF"
+if test -n "$ROFF"; then
+ echo "$ac_t""$ROFF" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+;;
+ *sysv4*)
+ case "$host" in
+ *-univel-*) if test "$GCC" != yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MEMSET 1
+EOF
+
+ fi
+ LDSHFLAGS="-G"
+ ;;
+ *mips-sni-sysv4*) cat >> confdefs.h <<\EOF
+#define RELIANTUNIX 1
+EOF
+;;
+ esac
+ ;;
+ *sysv5*)
+ if test "$GCC" != yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MEMSET 1
+EOF
+
+ fi
+ LDSHFLAGS="-G"
+ ;;
+esac
+echo "$ac_t""$BLDSHARED" 1>&6
+echo $ac_n "checking linker flags for shared libraries""... $ac_c" 1>&6
+echo "configure:8693: checking linker flags for shared libraries" >&5
+echo "$ac_t""$LDSHFLAGS" 1>&6
+echo $ac_n "checking compiler flags for position-independent code""... $ac_c" 1>&6
+echo "configure:8696: checking compiler flags for position-independent code" >&5
+echo "$ac_t""$PICFLAGS" 1>&6
+
+# this updates our target list if we can build shared libs
+if test $BLDSHARED = true; then
+ LIBSMBCLIENT_SHARED=bin/libsmbclient.$SHLIBEXT
+else
+ LIBSMBCLIENT_SHARED=
+fi
+
+################
+
+echo $ac_n "checking for long long""... $ac_c" 1>&6
+echo "configure:8709: checking for long long" >&5
+if eval "test \"`echo '$''{'samba_cv_have_longlong'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_have_longlong=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8718 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }
+EOF
+if { (eval echo configure:8723: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_have_longlong=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_have_longlong=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_have_longlong" 1>&6
+if test x"$samba_cv_have_longlong" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LONGLONG 1
+EOF
+
+fi
+
+#
+# Check if the compiler supports the LL prefix on long long integers.
+# AIX needs this.
+
+echo $ac_n "checking for LL suffix on long long integers""... $ac_c" 1>&6
+echo "configure:8750: checking for LL suffix on long long integers" >&5
+if eval "test \"`echo '$''{'samba_cv_compiler_supports_ll'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 8756 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+long long i = 0x8000000000LL
+; return 0; }
+EOF
+if { (eval echo configure:8763: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_compiler_supports_ll=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_compiler_supports_ll=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_compiler_supports_ll" 1>&6
+if test x"$samba_cv_compiler_supports_ll" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define COMPILER_SUPPORTS_LL 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for 64 bit off_t""... $ac_c" 1>&6
+echo "configure:8785: checking for 64 bit off_t" >&5
+if eval "test \"`echo '$''{'samba_cv_SIZEOF_OFF_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_SIZEOF_OFF_T=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8794 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(off_t) == 8) ? 0 : 1); }
+EOF
+if { (eval echo configure:8800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_SIZEOF_OFF_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_SIZEOF_OFF_T=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_SIZEOF_OFF_T" 1>&6
+if test x"$samba_cv_SIZEOF_OFF_T" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define SIZEOF_OFF_T 8
+EOF
+
+fi
+
+echo $ac_n "checking for off64_t""... $ac_c" 1>&6
+echo "configure:8823: checking for off64_t" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_OFF64_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_OFF64_T=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8832 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }
+EOF
+if { (eval echo configure:8842: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_OFF64_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_OFF64_T=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_OFF64_T" 1>&6
+if test x"$samba_cv_HAVE_OFF64_T" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OFF64_T 1
+EOF
+
+fi
+
+echo $ac_n "checking for 64 bit ino_t""... $ac_c" 1>&6
+echo "configure:8865: checking for 64 bit ino_t" >&5
+if eval "test \"`echo '$''{'samba_cv_SIZEOF_INO_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_SIZEOF_INO_T=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8874 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(ino_t) == 8) ? 0 : 1); }
+EOF
+if { (eval echo configure:8880: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_SIZEOF_INO_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_SIZEOF_INO_T=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_SIZEOF_INO_T" 1>&6
+if test x"$samba_cv_SIZEOF_INO_T" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define SIZEOF_INO_T 8
+EOF
+
+fi
+
+echo $ac_n "checking for ino64_t""... $ac_c" 1>&6
+echo "configure:8903: checking for ino64_t" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_INO64_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_INO64_T=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8912 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; ino64_t s; if (sizeof(ino_t) == sizeof(ino64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }
+EOF
+if { (eval echo configure:8922: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_INO64_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_INO64_T=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_INO64_T" 1>&6
+if test x"$samba_cv_HAVE_INO64_T" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_INO64_T 1
+EOF
+
+fi
+
+echo $ac_n "checking for struct dirent64""... $ac_c" 1>&6
+echo "configure:8945: checking for struct dirent64" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_STRUCT_DIRENT64'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 8951 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <dirent.h>
+int main() {
+struct dirent64 de;
+; return 0; }
+EOF
+if { (eval echo configure:8963: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_STRUCT_DIRENT64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_STRUCT_DIRENT64=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_STRUCT_DIRENT64" 1>&6
+if test x"$samba_cv_HAVE_STRUCT_DIRENT64" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_DIRENT64 1
+EOF
+
+fi
+
+echo $ac_n "checking for unsigned char""... $ac_c" 1>&6
+echo "configure:8984: checking for unsigned char" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UNSIGNED_CHAR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_UNSIGNED_CHAR=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 8993 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main() { char c; c=250; exit((c > 0)?0:1); }
+EOF
+if { (eval echo configure:8998: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_UNSIGNED_CHAR=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_UNSIGNED_CHAR=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UNSIGNED_CHAR" 1>&6
+if test x"$samba_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UNSIGNED_CHAR 1
+EOF
+
+fi
+
+echo $ac_n "checking for sin_len in sock""... $ac_c" 1>&6
+echo "configure:9021: checking for sin_len in sock" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_SOCK_SIN_LEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9027 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main() {
+struct sockaddr_in sock; sock.sin_len = sizeof(sock);
+; return 0; }
+EOF
+if { (eval echo configure:9036: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_SOCK_SIN_LEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_SOCK_SIN_LEN=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_SOCK_SIN_LEN" 1>&6
+if test x"$samba_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCK_SIN_LEN 1
+EOF
+
+fi
+
+echo $ac_n "checking whether seekdir returns void""... $ac_c" 1>&6
+echo "configure:9057: checking whether seekdir returns void" >&5
+if eval "test \"`echo '$''{'samba_cv_SEEKDIR_RETURNS_VOID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9063 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <dirent.h>
+void seekdir(DIR *d, long loc) { return; }
+int main() {
+return 0;
+; return 0; }
+EOF
+if { (eval echo configure:9072: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_SEEKDIR_RETURNS_VOID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_SEEKDIR_RETURNS_VOID=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_SEEKDIR_RETURNS_VOID" 1>&6
+if test x"$samba_cv_SEEKDIR_RETURNS_VOID" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define SEEKDIR_RETURNS_VOID 1
+EOF
+
+fi
+
+echo $ac_n "checking for __FILE__ macro""... $ac_c" 1>&6
+echo "configure:9093: checking for __FILE__ macro" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_FILE_MACRO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9099 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+printf("%s\n", __FILE__);
+; return 0; }
+EOF
+if { (eval echo configure:9106: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_FILE_MACRO=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_FILE_MACRO=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_FILE_MACRO" 1>&6
+if test x"$samba_cv_HAVE_FILE_MACRO" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FILE_MACRO 1
+EOF
+
+fi
+
+echo $ac_n "checking for __FUNCTION__ macro""... $ac_c" 1>&6
+echo "configure:9127: checking for __FUNCTION__ macro" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_FUNCTION_MACRO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9133 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+printf("%s\n", __FUNCTION__);
+; return 0; }
+EOF
+if { (eval echo configure:9140: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_FUNCTION_MACRO=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_FUNCTION_MACRO=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_FUNCTION_MACRO" 1>&6
+if test x"$samba_cv_HAVE_FUNCTION_MACRO" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FUNCTION_MACRO 1
+EOF
+
+fi
+
+echo $ac_n "checking if gettimeofday takes tz argument""... $ac_c" 1>&6
+echo "configure:9161: checking if gettimeofday takes tz argument" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_GETTIMEOFDAY_TZ'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9170 "configure"
+#include "confdefs.h"
+
+#include <sys/time.h>
+#include <unistd.h>
+main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}
+EOF
+if { (eval echo configure:9177: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_GETTIMEOFDAY_TZ" 1>&6
+if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GETTIMEOFDAY_TZ 1
+EOF
+
+fi
+
+echo $ac_n "checking for C99 vsnprintf""... $ac_c" 1>&6
+echo "configure:9200: checking for C99 vsnprintf" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_C99_VSNPRINTF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_C99_VSNPRINTF=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9209 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <stdarg.h>
+void foo(const char *format, ...) {
+ va_list ap;
+ int len;
+ char buf[5];
+
+ va_start(ap, format);
+ len = vsnprintf(0, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(1);
+
+ if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
+
+ exit(0);
+}
+main() { foo("hello"); }
+
+EOF
+if { (eval echo configure:9231: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_C99_VSNPRINTF=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_C99_VSNPRINTF=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_C99_VSNPRINTF" 1>&6
+if test x"$samba_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_C99_VSNPRINTF 1
+EOF
+
+fi
+
+echo $ac_n "checking for broken readdir""... $ac_c" 1>&6
+echo "configure:9254: checking for broken readdir" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_BROKEN_READDIR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_BROKEN_READDIR=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9263 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <dirent.h>
+main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
+if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
+di->d_name[0] == 0) exit(0); exit(1);}
+EOF
+if { (eval echo configure:9271: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_BROKEN_READDIR=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_BROKEN_READDIR=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_BROKEN_READDIR" 1>&6
+if test x"$samba_cv_HAVE_BROKEN_READDIR" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_BROKEN_READDIR 1
+EOF
+
+fi
+
+echo $ac_n "checking for utimbuf""... $ac_c" 1>&6
+echo "configure:9294: checking for utimbuf" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UTIMBUF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9300 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utime.h>
+int main() {
+struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));
+; return 0; }
+EOF
+if { (eval echo configure:9308: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UTIMBUF=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UTIMBUF=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UTIMBUF" 1>&6
+if test x"$samba_cv_HAVE_UTIMBUF" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UTIMBUF 1
+EOF
+
+fi
+
+
+for ac_func in pututline pututxline updwtmp updwtmpx getutmpx
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:9332: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9337 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:9360: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for ut_name in utmp""... $ac_c" 1>&6
+echo "configure:9386: checking for ut_name in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_NAME'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9392 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_name[0] = 'a';
+; return 0; }
+EOF
+if { (eval echo configure:9400: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_NAME=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_NAME=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_NAME" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_NAME" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_NAME 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_user in utmp""... $ac_c" 1>&6
+echo "configure:9421: checking for ut_user in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_USER'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9427 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_user[0] = 'a';
+; return 0; }
+EOF
+if { (eval echo configure:9435: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_USER=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_USER=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_USER" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_USER" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_USER 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_id in utmp""... $ac_c" 1>&6
+echo "configure:9456: checking for ut_id in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_ID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9462 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_id[0] = 'a';
+; return 0; }
+EOF
+if { (eval echo configure:9470: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_ID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_ID=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_ID" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_ID" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_ID 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_host in utmp""... $ac_c" 1>&6
+echo "configure:9491: checking for ut_host in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_HOST'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9497 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_host[0] = 'a';
+; return 0; }
+EOF
+if { (eval echo configure:9505: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_HOST=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_HOST=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_HOST" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_HOST" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_HOST 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_time in utmp""... $ac_c" 1>&6
+echo "configure:9526: checking for ut_time in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_TIME'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9532 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; time_t t; ut.ut_time = t;
+; return 0; }
+EOF
+if { (eval echo configure:9540: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TIME=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TIME=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_TIME" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_TIME" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_tv in utmp""... $ac_c" 1>&6
+echo "configure:9561: checking for ut_tv in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_TV'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9567 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; struct timeval tv; ut.ut_tv = tv;
+; return 0; }
+EOF
+if { (eval echo configure:9575: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TV=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TV=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_TV" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_TV" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_TV 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_type in utmp""... $ac_c" 1>&6
+echo "configure:9596: checking for ut_type in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_TYPE'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9602 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_type = 0;
+; return 0; }
+EOF
+if { (eval echo configure:9610: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TYPE=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_TYPE=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_TYPE" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_TYPE" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_TYPE 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_pid in utmp""... $ac_c" 1>&6
+echo "configure:9631: checking for ut_pid in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_PID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9637 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_pid = 0;
+; return 0; }
+EOF
+if { (eval echo configure:9645: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_PID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_PID=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_PID" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_PID" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_PID 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_exit in utmp""... $ac_c" 1>&6
+echo "configure:9666: checking for ut_exit in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_EXIT'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9672 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_exit.e_exit = 0;
+; return 0; }
+EOF
+if { (eval echo configure:9680: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_EXIT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_EXIT=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_EXIT" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_EXIT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_EXIT 1
+EOF
+
+fi
+
+echo $ac_n "checking for ut_addr in utmp""... $ac_c" 1>&6
+echo "configure:9701: checking for ut_addr in utmp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UT_UT_ADDR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9707 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp ut; ut.ut_addr = 0;
+; return 0; }
+EOF
+if { (eval echo configure:9715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_ADDR=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UT_UT_ADDR=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UT_UT_ADDR" 1>&6
+if test x"$samba_cv_HAVE_UT_UT_ADDR" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UT_UT_ADDR 1
+EOF
+
+fi
+
+if test x$ac_cv_func_pututline = xyes ; then
+ echo $ac_n "checking whether pututline returns pointer""... $ac_c" 1>&6
+echo "configure:9737: checking whether pututline returns pointer" >&5
+if eval "test \"`echo '$''{'samba_cv_PUTUTLINE_RETURNS_UTMP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 9743 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmp.h>
+int main() {
+struct utmp utarg; struct utmp *utreturn; utreturn = pututline(&utarg);
+; return 0; }
+EOF
+if { (eval echo configure:9751: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_PUTUTLINE_RETURNS_UTMP=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_PUTUTLINE_RETURNS_UTMP=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_PUTUTLINE_RETURNS_UTMP" 1>&6
+ if test x"$samba_cv_PUTUTLINE_RETURNS_UTMP" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define PUTUTLINE_RETURNS_UTMP 1
+EOF
+
+ fi
+fi
+
+echo $ac_n "checking for ut_syslen in utmpx""... $ac_c" 1>&6
+echo "configure:9773: checking for ut_syslen in utmpx" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UX_UT_SYSLEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 9779 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <utmpx.h>
+int main() {
+struct utmpx ux; ux.ut_syslen = 0;
+; return 0; }
+EOF
+if { (eval echo configure:9787: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UX_UT_SYSLEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UX_UT_SYSLEN=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UX_UT_SYSLEN" 1>&6
+if test x"$samba_cv_HAVE_UX_UT_SYSLEN" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UX_UT_SYSLEN 1
+EOF
+
+fi
+
+
+#################################################
+# check for libiconv support
+echo $ac_n "checking whether to use libiconv""... $ac_c" 1>&6
+echo "configure:9811: checking whether to use libiconv" >&5
+# Check whether --with-libiconv or --without-libiconv was given.
+if test "${with_libiconv+set}" = set; then
+ withval="$with_libiconv"
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ CFLAGS="$CFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ echo $ac_n "checking for iconv_open in -liconv""... $ac_c" 1>&6
+echo "configure:9824: checking for iconv_open in -liconv" >&5
+ac_lib_var=`echo iconv'_'iconv_open | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-liconv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 9832 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char iconv_open();
+
+int main() {
+iconv_open()
+; return 0; }
+EOF
+if { (eval echo configure:9843: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo iconv | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-liconv $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ cat >> confdefs.h <<EOF
+#define WITH_LIBICONV "${withval}"
+EOF
+
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+############
+# check for iconv in libc
+echo $ac_n "checking for working iconv""... $ac_c" 1>&6
+echo "configure:9886: checking for working iconv" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_NATIVE_ICONV'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_NATIVE_ICONV=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9895 "configure"
+#include "confdefs.h"
+
+#include <iconv.h>
+main() {
+ iconv_t cd = iconv_open("ASCII", "UCS-2LE");
+ if (cd == 0 || cd == (iconv_t)-1) return -1;
+ return 0;
+}
+
+EOF
+if { (eval echo configure:9906: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_NATIVE_ICONV=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_NATIVE_ICONV=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_NATIVE_ICONV" 1>&6
+if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_NATIVE_ICONV 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for Linux kernel oplocks""... $ac_c" 1>&6
+echo "configure:9930: checking for Linux kernel oplocks" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_KERNEL_OPLOCKS_LINUX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9939 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+main() {
+ int fd = open("/dev/null", O_RDONLY);
+ return fcntl(fd, F_GETLEASE, 0) == -1;
+}
+
+EOF
+if { (eval echo configure:9953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" 1>&6
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_KERNEL_OPLOCKS_LINUX 1
+EOF
+
+fi
+
+echo $ac_n "checking for kernel change notify support""... $ac_c" 1>&6
+echo "configure:9976: checking for kernel change notify support" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_KERNEL_CHANGE_NOTIFY'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 9985 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+main() {
+ exit(fcntl(open("/tmp", O_RDONLY), F_NOTIFY, 0) == -1 ? 1 : 0);
+}
+
+EOF
+if { (eval echo configure:9999: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" 1>&6
+if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_KERNEL_CHANGE_NOTIFY 1
+EOF
+
+fi
+
+echo $ac_n "checking for kernel share modes""... $ac_c" 1>&6
+echo "configure:10022: checking for kernel share modes" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_KERNEL_SHARE_MODES'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_KERNEL_SHARE_MODES=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10031 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/file.h>
+#ifndef LOCK_MAND
+#define LOCK_MAND 32
+#define LOCK_READ 64
+#endif
+main() {
+ exit(flock(open("/dev/null", O_RDWR), LOCK_MAND|LOCK_READ) != 0);
+}
+
+EOF
+if { (eval echo configure:10047: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_KERNEL_SHARE_MODES=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_KERNEL_SHARE_MODES=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_KERNEL_SHARE_MODES" 1>&6
+if test x"$samba_cv_HAVE_KERNEL_SHARE_MODES" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_KERNEL_SHARE_MODES 1
+EOF
+
+fi
+
+
+
+
+echo $ac_n "checking for IRIX kernel oplock type definitions""... $ac_c" 1>&6
+echo "configure:10073: checking for IRIX kernel oplock type definitions" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_KERNEL_OPLOCKS_IRIX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10079 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <fcntl.h>
+int main() {
+oplock_stat_t t; t.os_state = OP_REVOKE; t.os_dev = 1; t.os_ino = 1;
+; return 0; }
+EOF
+if { (eval echo configure:10087: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_KERNEL_OPLOCKS_IRIX" 1>&6
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_IRIX" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_KERNEL_OPLOCKS_IRIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for irix specific capabilities""... $ac_c" 1>&6
+echo "configure:10108: checking for irix specific capabilities" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10117 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/capability.h>
+main() {
+ cap_t cap;
+ if ((cap = cap_get_proc()) == NULL)
+ exit(1);
+ cap->cap_effective |= CAP_NETWORK_MGT;
+ cap->cap_inheritable |= CAP_NETWORK_MGT;
+ cap_set_proc(cap);
+ exit(0);
+}
+
+EOF
+if { (eval echo configure:10132: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES" 1>&6
+if test x"$samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_IRIX_SPECIFIC_CAPABILITIES 1
+EOF
+
+fi
+
+#
+# Check for int16, uint16, int32 and uint32 in rpc/types.h included from rpc/rpc.h
+# This is *really* broken but some systems (DEC OSF1) do this.... JRA.
+#
+
+echo $ac_n "checking for int16 typedef included by rpc/rpc.h""... $ac_c" 1>&6
+echo "configure:10160: checking for int16 typedef included by rpc/rpc.h" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_INT16_FROM_RPC_RPC_H'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10166 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif
+int main() {
+int16 testvar;
+; return 0; }
+EOF
+if { (eval echo configure:10176: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_INT16_FROM_RPC_RPC_H=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_INT16_FROM_RPC_RPC_H=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_INT16_FROM_RPC_RPC_H" 1>&6
+if test x"$samba_cv_HAVE_INT16_FROM_RPC_RPC_H" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_INT16_FROM_RPC_RPC_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for uint16 typedef included by rpc/rpc.h""... $ac_c" 1>&6
+echo "configure:10197: checking for uint16 typedef included by rpc/rpc.h" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UINT16_FROM_RPC_RPC_H'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10203 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif
+int main() {
+uint16 testvar;
+; return 0; }
+EOF
+if { (eval echo configure:10213: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UINT16_FROM_RPC_RPC_H" 1>&6
+if test x"$samba_cv_HAVE_UINT16_FROM_RPC_RPC_H" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UINT16_FROM_RPC_RPC_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for int32 typedef included by rpc/rpc.h""... $ac_c" 1>&6
+echo "configure:10234: checking for int32 typedef included by rpc/rpc.h" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_INT32_FROM_RPC_RPC_H'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10240 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif
+int main() {
+int32 testvar;
+; return 0; }
+EOF
+if { (eval echo configure:10250: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_INT32_FROM_RPC_RPC_H=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_INT32_FROM_RPC_RPC_H=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_INT32_FROM_RPC_RPC_H" 1>&6
+if test x"$samba_cv_HAVE_INT32_FROM_RPC_RPC_H" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_INT32_FROM_RPC_RPC_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for uint32 typedef included by rpc/rpc.h""... $ac_c" 1>&6
+echo "configure:10271: checking for uint32 typedef included by rpc/rpc.h" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UINT32_FROM_RPC_RPC_H'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10277 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif
+int main() {
+uint32 testvar;
+; return 0; }
+EOF
+if { (eval echo configure:10287: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UINT32_FROM_RPC_RPC_H" 1>&6
+if test x"$samba_cv_HAVE_UINT32_FROM_RPC_RPC_H" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UINT32_FROM_RPC_RPC_H 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for conflicting AUTH_ERROR define in rpc/rpc.h""... $ac_c" 1>&6
+echo "configure:10309: checking for conflicting AUTH_ERROR define in rpc/rpc.h" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 10315 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#endif /* HAVE_SYS_SECURITY_H */
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif
+int main() {
+int testvar;
+; return 0; }
+EOF
+if { (eval echo configure:10329: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=yes
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT" 1>&6
+if test x"$samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_RPC_AUTH_ERROR_CONFLICT 1
+EOF
+
+fi
+
+echo $ac_n "checking for test routines""... $ac_c" 1>&6
+echo "configure:10350: checking for test routines" >&5
+if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot run when cross-compiling" 1>&2
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10355 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/trivial.c"
+EOF
+if { (eval echo configure:10359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ { echo "configure: error: cant find test code. Aborting config" 1>&2; exit 1; }
+fi
+rm -fr conftest*
+fi
+
+
+echo $ac_n "checking for ftruncate extend""... $ac_c" 1>&6
+echo "configure:10373: checking for ftruncate extend" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_FTRUNCATE_EXTEND'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_FTRUNCATE_EXTEND=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10382 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/ftruncate.c"
+EOF
+if { (eval echo configure:10386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_FTRUNCATE_EXTEND=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_FTRUNCATE_EXTEND=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_FTRUNCATE_EXTEND" 1>&6
+if test x"$samba_cv_HAVE_FTRUNCATE_EXTEND" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FTRUNCATE_EXTEND 1
+EOF
+
+fi
+
+echo $ac_n "checking for AF_LOCAL socket support""... $ac_c" 1>&6
+echo "configure:10409: checking for AF_LOCAL socket support" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_WORKING_AF_LOCAL'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_WORKING_AF_LOCAL=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10418 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/unixsock.c"
+EOF
+if { (eval echo configure:10422: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_WORKING_AF_LOCAL=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_WORKING_AF_LOCAL=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_WORKING_AF_LOCAL" 1>&6
+if test x"$samba_cv_HAVE_WORKING_AF_LOCAL" != xno
+then
+ cat >> confdefs.h <<\EOF
+#define HAVE_WORKING_AF_LOCAL 1
+EOF
+
+fi
+
+echo $ac_n "checking for broken getgroups""... $ac_c" 1>&6
+echo "configure:10446: checking for broken getgroups" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_BROKEN_GETGROUPS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_BROKEN_GETGROUPS=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10455 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/getgroups.c"
+EOF
+if { (eval echo configure:10459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_BROKEN_GETGROUPS=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_BROKEN_GETGROUPS=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_BROKEN_GETGROUPS" 1>&6
+if test x"$samba_cv_HAVE_BROKEN_GETGROUPS" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_BROKEN_GETGROUPS 1
+EOF
+
+fi
+
+echo $ac_n "checking whether getpass should be replaced""... $ac_c" 1>&6
+echo "configure:10482: checking whether getpass should be replaced" >&5
+if eval "test \"`echo '$''{'samba_cv_REPLACE_GETPASS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I${srcdir-.}/ -I${srcdir-.}/include -I${srcdir-.}/ubiqx -I${srcdir-.}/smbwrapper"
+cat > conftest.$ac_ext <<EOF
+#line 10490 "configure"
+#include "confdefs.h"
+
+#define REPLACE_GETPASS 1
+#define NO_CONFIG_H 1
+#define main dont_declare_main
+#include "${srcdir-.}/lib/getsmbpass.c"
+#undef main
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:10503: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_REPLACE_GETPASS=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_REPLACE_GETPASS=no
+fi
+rm -f conftest*
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+fi
+
+echo "$ac_t""$samba_cv_REPLACE_GETPASS" 1>&6
+if test x"$samba_cv_REPLACE_GETPASS" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define REPLACE_GETPASS 1
+EOF
+
+fi
+
+echo $ac_n "checking for broken inet_ntoa""... $ac_c" 1>&6
+echo "configure:10526: checking for broken inet_ntoa" >&5
+if eval "test \"`echo '$''{'samba_cv_REPLACE_INET_NTOA'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_REPLACE_INET_NTOA=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10535 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+main() { struct in_addr ip; ip.s_addr = 0x12345678;
+if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
+ strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); }
+exit(1);}
+EOF
+if { (eval echo configure:10549: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_REPLACE_INET_NTOA=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_REPLACE_INET_NTOA=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_REPLACE_INET_NTOA" 1>&6
+if test x"$samba_cv_REPLACE_INET_NTOA" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define REPLACE_INET_NTOA 1
+EOF
+
+fi
+
+echo $ac_n "checking for secure mkstemp""... $ac_c" 1>&6
+echo "configure:10572: checking for secure mkstemp" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_SECURE_MKSTEMP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_SECURE_MKSTEMP=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10581 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() {
+ struct stat st;
+ char tpl[20]="/tmp/test.XXXXXX";
+ int fd = mkstemp(tpl);
+ if (fd == -1) exit(1);
+ unlink(tpl);
+ if (fstat(fd, &st) != 0) exit(1);
+ if ((st.st_mode & 0777) != 0600) exit(1);
+ exit(0);
+}
+EOF
+if { (eval echo configure:10598: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_SECURE_MKSTEMP=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_SECURE_MKSTEMP=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_SECURE_MKSTEMP" 1>&6
+if test x"$samba_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SECURE_MKSTEMP 1
+EOF
+
+fi
+
+echo $ac_n "checking for sysconf(_SC_NGROUPS_MAX)""... $ac_c" 1>&6
+echo "configure:10621: checking for sysconf(_SC_NGROUPS_MAX)" >&5
+if eval "test \"`echo '$''{'samba_cv_SYSCONF_SC_NGROUPS_MAX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_SYSCONF_SC_NGROUPS_MAX=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10630 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+main() { exit(sysconf(_SC_NGROUPS_MAX) == -1 ? 1 : 0); }
+EOF
+if { (eval echo configure:10635: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_SYSCONF_SC_NGROUPS_MAX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_SYSCONF_SC_NGROUPS_MAX=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_SYSCONF_SC_NGROUPS_MAX" 1>&6
+if test x"$samba_cv_SYSCONF_SC_NGROUPS_MAX" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define SYSCONF_SC_NGROUPS_MAX 1
+EOF
+
+fi
+
+echo $ac_n "checking for root""... $ac_c" 1>&6
+echo "configure:10658: checking for root" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_ROOT'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_ROOT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10667 "configure"
+#include "confdefs.h"
+main() { exit(getuid() != 0); }
+EOF
+if { (eval echo configure:10671: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_ROOT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_ROOT=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_ROOT" 1>&6
+if test x"$samba_cv_HAVE_ROOT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ROOT 1
+EOF
+
+else
+ echo "configure: warning: running as non-root will disable some tests" 1>&2
+fi
+
+##################
+# look for a method of finding the list of network interfaces
+iface=no;
+echo $ac_n "checking for iface AIX""... $ac_c" 1>&6
+echo "configure:10699: checking for iface AIX" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_IFACE_AIX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_IFACE_AIX=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10708 "configure"
+#include "confdefs.h"
+
+#define HAVE_IFACE_AIX 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"
+EOF
+if { (eval echo configure:10716: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_IFACE_AIX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_IFACE_AIX=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_IFACE_AIX" 1>&6
+if test x"$samba_cv_HAVE_IFACE_AIX" = x"yes"; then
+ iface=yes;cat >> confdefs.h <<\EOF
+#define HAVE_IFACE_AIX 1
+EOF
+
+fi
+
+if test $iface = no; then
+echo $ac_n "checking for iface ifconf""... $ac_c" 1>&6
+echo "configure:10740: checking for iface ifconf" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_IFACE_IFCONF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_IFACE_IFCONF=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10749 "configure"
+#include "confdefs.h"
+
+#define HAVE_IFACE_IFCONF 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"
+EOF
+if { (eval echo configure:10757: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_IFACE_IFCONF=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_IFACE_IFCONF=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_IFACE_IFCONF" 1>&6
+if test x"$samba_cv_HAVE_IFACE_IFCONF" = x"yes"; then
+ iface=yes;cat >> confdefs.h <<\EOF
+#define HAVE_IFACE_IFCONF 1
+EOF
+
+fi
+fi
+
+if test $iface = no; then
+echo $ac_n "checking for iface ifreq""... $ac_c" 1>&6
+echo "configure:10782: checking for iface ifreq" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_IFACE_IFREQ'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_IFACE_IFREQ=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10791 "configure"
+#include "confdefs.h"
+
+#define HAVE_IFACE_IFREQ 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"
+EOF
+if { (eval echo configure:10799: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_IFACE_IFREQ=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_IFACE_IFREQ=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_IFACE_IFREQ" 1>&6
+if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then
+ iface=yes;cat >> confdefs.h <<\EOF
+#define HAVE_IFACE_IFREQ 1
+EOF
+
+fi
+fi
+
+
+################################################
+# look for a method of setting the effective uid
+seteuid=no;
+if test $seteuid = no; then
+echo $ac_n "checking for setresuid""... $ac_c" 1>&6
+echo "configure:10828: checking for setresuid" >&5
+if eval "test \"`echo '$''{'samba_cv_USE_SETRESUID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_USE_SETRESUID=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10837 "configure"
+#include "confdefs.h"
+
+#define AUTOCONF_TEST 1
+#define USE_SETRESUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"
+EOF
+if { (eval echo configure:10845: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_USE_SETRESUID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_USE_SETRESUID=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_USE_SETRESUID" 1>&6
+if test x"$samba_cv_USE_SETRESUID" = x"yes"; then
+ seteuid=yes;cat >> confdefs.h <<\EOF
+#define USE_SETRESUID 1
+EOF
+
+fi
+fi
+
+
+if test $seteuid = no; then
+echo $ac_n "checking for setreuid""... $ac_c" 1>&6
+echo "configure:10871: checking for setreuid" >&5
+if eval "test \"`echo '$''{'samba_cv_USE_SETREUID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_USE_SETREUID=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10880 "configure"
+#include "confdefs.h"
+
+#define AUTOCONF_TEST 1
+#define USE_SETREUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"
+EOF
+if { (eval echo configure:10888: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_USE_SETREUID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_USE_SETREUID=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_USE_SETREUID" 1>&6
+if test x"$samba_cv_USE_SETREUID" = x"yes"; then
+ seteuid=yes;cat >> confdefs.h <<\EOF
+#define USE_SETREUID 1
+EOF
+
+fi
+fi
+
+if test $seteuid = no; then
+echo $ac_n "checking for seteuid""... $ac_c" 1>&6
+echo "configure:10913: checking for seteuid" >&5
+if eval "test \"`echo '$''{'samba_cv_USE_SETEUID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_USE_SETEUID=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10922 "configure"
+#include "confdefs.h"
+
+#define AUTOCONF_TEST 1
+#define USE_SETEUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"
+EOF
+if { (eval echo configure:10930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_USE_SETEUID=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_USE_SETEUID=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_USE_SETEUID" 1>&6
+if test x"$samba_cv_USE_SETEUID" = x"yes"; then
+ seteuid=yes;cat >> confdefs.h <<\EOF
+#define USE_SETEUID 1
+EOF
+
+fi
+fi
+
+if test $seteuid = no; then
+echo $ac_n "checking for setuidx""... $ac_c" 1>&6
+echo "configure:10955: checking for setuidx" >&5
+if eval "test \"`echo '$''{'samba_cv_USE_SETUIDX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_USE_SETUIDX=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 10964 "configure"
+#include "confdefs.h"
+
+#define AUTOCONF_TEST 1
+#define USE_SETUIDX 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"
+EOF
+if { (eval echo configure:10972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_USE_SETUIDX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_USE_SETUIDX=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_USE_SETUIDX" 1>&6
+if test x"$samba_cv_USE_SETUIDX" = x"yes"; then
+ seteuid=yes;cat >> confdefs.h <<\EOF
+#define USE_SETUIDX 1
+EOF
+
+fi
+fi
+
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:10997: checking for working mmap" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_MMAP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_MMAP=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11006 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/shared_mmap.c"
+EOF
+if { (eval echo configure:11010: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_MMAP=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_MMAP=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_MMAP" 1>&6
+if test x"$samba_cv_HAVE_MMAP" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+echo $ac_n "checking for ftruncate needs root""... $ac_c" 1>&6
+echo "configure:11033: checking for ftruncate needs root" >&5
+if eval "test \"`echo '$''{'samba_cv_FTRUNCATE_NEEDS_ROOT'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_FTRUNCATE_NEEDS_ROOT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11042 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/ftruncroot.c"
+EOF
+if { (eval echo configure:11046: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_FTRUNCATE_NEEDS_ROOT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_FTRUNCATE_NEEDS_ROOT=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_FTRUNCATE_NEEDS_ROOT" 1>&6
+if test x"$samba_cv_FTRUNCATE_NEEDS_ROOT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define FTRUNCATE_NEEDS_ROOT 1
+EOF
+
+fi
+
+echo $ac_n "checking for fcntl locking""... $ac_c" 1>&6
+echo "configure:11069: checking for fcntl locking" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_FCNTL_LOCK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_FCNTL_LOCK=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11078 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/fcntl_lock.c"
+EOF
+if { (eval echo configure:11082: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_FCNTL_LOCK=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_FCNTL_LOCK=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_FCNTL_LOCK" 1>&6
+if test x"$samba_cv_HAVE_FCNTL_LOCK" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FCNTL_LOCK 1
+EOF
+
+fi
+
+echo $ac_n "checking for broken (glibc2.1/x86) 64 bit fcntl locking""... $ac_c" 1>&6
+echo "configure:11105: checking for broken (glibc2.1/x86) 64 bit fcntl locking" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_BROKEN_FCNTL64_LOCKS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11114 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/fcntl_lock64.c"
+EOF
+if { (eval echo configure:11118: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_BROKEN_FCNTL64_LOCKS" 1>&6
+if test x"$samba_cv_HAVE_BROKEN_FCNTL64_LOCKS" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_BROKEN_FCNTL64_LOCKS 1
+EOF
+
+
+else
+
+
+ echo $ac_n "checking for 64 bit fcntl locking""... $ac_c" 1>&6
+echo "configure:11143: checking for 64 bit fcntl locking" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_STRUCT_FLOCK64'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_STRUCT_FLOCK64=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11152 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+main() { struct flock64 fl64;
+#if defined(F_SETLKW64) && defined(F_SETLK64) && defined(F_GETLK64)
+exit(0);
+#else
+exit(1);
+#endif
+}
+EOF
+if { (eval echo configure:11176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_STRUCT_FLOCK64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_STRUCT_FLOCK64=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_STRUCT_FLOCK64" 1>&6
+
+ if test x"$samba_cv_HAVE_STRUCT_FLOCK64" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_FLOCK64 1
+EOF
+
+ fi
+fi
+
+
+case "$host_os" in
+*linux*)
+echo $ac_n "checking for broken RedHat 7.2 system header files""... $ac_c" 1>&6
+echo "configure:11204: checking for broken RedHat 7.2 system header files" >&5
+if eval "test \"`echo '$''{'samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 11210 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:11224: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" 1>&6
+if test x"$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define BROKEN_REDHAT_7_SYSTEM_HEADERS 1
+EOF
+
+fi
+;;
+esac
+
+echo $ac_n "checking for broken nisplus include files""... $ac_c" 1>&6
+echo "configure:11247: checking for broken nisplus include files" >&5
+if eval "test \"`echo '$''{'samba_cv_BROKEN_NISPLUS_INCLUDE_FILES'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 11253 "configure"
+#include "confdefs.h"
+#include <sys/acl.h>
+#if defined(HAVE_RPCSVC_NIS_H)
+#include <rpcsvc/nis.h>
+#endif
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:11263: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=yes
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_BROKEN_NISPLUS_INCLUDE_FILES" 1>&6
+if test x"$samba_cv_BROKEN_NISPLUS_INCLUDE_FILES" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define BROKEN_NISPLUS_INCLUDE_FILES 1
+EOF
+
+fi
+
+
+#################################################
+# check for smbwrapper support
+echo $ac_n "checking whether to use smbwrapper""... $ac_c" 1>&6
+echo "configure:11287: checking whether to use smbwrapper" >&5
+# Check whether --with-smbwrapper or --without-smbwrapper was given.
+if test "${with_smbwrapper+set}" = set; then
+ withval="$with_smbwrapper"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SMBWRAPPER 1
+EOF
+
+ WRAP="bin/smbsh bin/smbwrapper.$SHLIBEXT"
+
+ if test x$ATTEMPT_WRAP32_BUILD = x; then
+ WRAP32=""
+ else
+ WRAP32=bin/smbwrapper.32.$SHLIBEXT
+ fi
+
+# Conditions under which smbwrapper should not be built.
+
+ if test x$PICFLAG = x; then
+ echo No support for PIC code - disabling smbwrapper and smbsh
+ WRAP=""
+ WRAP32=""
+ elif test x$ac_cv_func_syscall = xno; then
+ echo "$ac_t""No syscall() -- disabling smbwrapper and smbsh" 1>&6
+ WRAP=""
+ WRAP32=""
+ fi
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for AFS clear-text auth support
+echo $ac_n "checking whether to use AFS clear-text auth""... $ac_c" 1>&6
+echo "configure:11331: checking whether to use AFS clear-text auth" >&5
+# Check whether --with-afs or --without-afs was given.
+if test "${with_afs+set}" = set; then
+ withval="$with_afs"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_AFS 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+#################################################
+# check for the DFS clear-text auth system
+echo $ac_n "checking whether to use DFS clear-text auth""... $ac_c" 1>&6
+echo "configure:11357: checking whether to use DFS clear-text auth" >&5
+# Check whether --with-dfs or --without-dfs was given.
+if test "${with_dfs+set}" = set; then
+ withval="$with_dfs"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_DFS 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+#################################################
+# see if this box has the RedHat location for kerberos
+echo $ac_n "checking for /usr/kerberos""... $ac_c" 1>&6
+echo "configure:11383: checking for /usr/kerberos" >&5
+if test -d /usr/kerberos; then
+ LDFLAGS="$LDFLAGS -L/usr/kerberos/lib"
+ CFLAGS="$CFLAGS -I/usr/kerberos/include"
+ CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include"
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+#################################################
+# check for location of Kerberos 5 install
+echo $ac_n "checking for kerberos 5 install path""... $ac_c" 1>&6
+echo "configure:11396: checking for kerberos 5 install path" >&5
+# Check whether --with-krb5 or --without-krb5 was given.
+if test "${with_krb5+set}" = set; then
+ withval="$with_krb5"
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lkrb5"
+ CFLAGS="$CFLAGS -I$withval/include"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+# now check for krb5.h. Some systems have the libraries without the headers!
+# note that this check is done here to allow for different kerberos
+# include paths
+for ac_hdr in krb5.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:11425: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11430 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:11435: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# now check for gssapi headers. This is also done here to allow for
+# different kerberos include paths
+for ac_hdr in gssapi/gssapi_generic.h gssapi/gssapi.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:11468: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11473 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:11478: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+##################################################################
+# we might need the k5crypto and com_err libraries on some systems
+echo $ac_n "checking for _et_list in -lcom_err""... $ac_c" 1>&6
+echo "configure:11508: checking for _et_list in -lcom_err" >&5
+ac_lib_var=`echo com_err'_'_et_list | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcom_err $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11516 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _et_list();
+
+int main() {
+_et_list()
+; return 0; }
+EOF
+if { (eval echo configure:11527: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lcom_err"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for krb5_encrypt_data in -lk5crypto""... $ac_c" 1>&6
+echo "configure:11548: checking for krb5_encrypt_data in -lk5crypto" >&5
+ac_lib_var=`echo k5crypto'_'krb5_encrypt_data | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lk5crypto $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11556 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb5_encrypt_data();
+
+int main() {
+krb5_encrypt_data()
+; return 0; }
+EOF
+if { (eval echo configure:11567: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lk5crypto"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for gss_import_name in -lgssapi_krb5""... $ac_c" 1>&6
+echo "configure:11588: checking for gss_import_name in -lgssapi_krb5" >&5
+ac_lib_var=`echo gssapi_krb5'_'gss_import_name | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lgssapi_krb5 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11596 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gss_import_name();
+
+int main() {
+gss_import_name()
+; return 0; }
+EOF
+if { (eval echo configure:11607: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lgssapi_krb5"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+########################################################
+# now see if we can find the krb5 libs in standard paths
+# or as specified above
+echo $ac_n "checking for krb5_mk_req_extended in -lkrb5""... $ac_c" 1>&6
+echo "configure:11633: checking for krb5_mk_req_extended in -lkrb5" >&5
+ac_lib_var=`echo krb5'_'krb5_mk_req_extended | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lkrb5 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11641 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char krb5_mk_req_extended();
+
+int main() {
+krb5_mk_req_extended()
+; return 0; }
+EOF
+if { (eval echo configure:11652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lkrb5";
+ cat >> confdefs.h <<\EOF
+#define HAVE_KRB5 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+##################################################################
+# we might need the lber lib on some systems. To avoid link errors
+# this test must be before the libldap test
+echo $ac_n "checking for ber_scanf in -llber""... $ac_c" 1>&6
+echo "configure:11682: checking for ber_scanf in -llber" >&5
+ac_lib_var=`echo lber'_'ber_scanf | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-llber $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11690 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char ber_scanf();
+
+int main() {
+ber_scanf()
+; return 0; }
+EOF
+if { (eval echo configure:11701: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -llber"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+########################################################
+# now see if we can find the ldap libs in standard paths
+if test x$have_ldap != xyes; then
+echo $ac_n "checking for ldap_open in -lldap""... $ac_c" 1>&6
+echo "configure:11726: checking for ldap_open in -lldap" >&5
+ac_lib_var=`echo ldap'_'ldap_open | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lldap $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11734 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char ldap_open();
+
+int main() {
+ldap_open()
+; return 0; }
+EOF
+if { (eval echo configure:11745: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lldap";
+ cat >> confdefs.h <<\EOF
+#define HAVE_LDAP 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+#################################################
+# check for automount support
+echo $ac_n "checking whether to use AUTOMOUNT""... $ac_c" 1>&6
+echo "configure:11775: checking whether to use AUTOMOUNT" >&5
+# Check whether --with-automount or --without-automount was given.
+if test "${with_automount+set}" = set; then
+ withval="$with_automount"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_AUTOMOUNT 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for smbmount support
+echo $ac_n "checking whether to use SMBMOUNT""... $ac_c" 1>&6
+echo "configure:11800: checking whether to use SMBMOUNT" >&5
+# Check whether --with-smbmount or --without-smbmount was given.
+if test "${with_smbmount+set}" = set; then
+ withval="$with_smbmount"
+ case "$withval" in
+ yes)
+ case "$host_os" in
+ *linux*)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SMBMOUNT 1
+EOF
+
+ MPROGS="bin/smbmount bin/smbmnt bin/smbumount"
+ ;;
+ *)
+ { echo "configure: error: not on a linux system!" 1>&2; exit 1; }
+ ;;
+ esac
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ MPROGS=
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+ MPROGS=
+
+fi
+
+
+
+#################################################
+# check for a PAM clear-text auth, accounts, password and session support
+with_pam_for_crypt=no
+echo $ac_n "checking whether to use PAM""... $ac_c" 1>&6
+echo "configure:11837: checking whether to use PAM" >&5
+# Check whether --with-pam or --without-pam was given.
+if test "${with_pam+set}" = set; then
+ withval="$with_pam"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_PAM 1
+EOF
+
+ LIBS="$LIBS -lpam"
+ with_pam_for_crypt=yes
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+# we can't build a pam module if we don't have pam.
+echo $ac_n "checking for pam_get_data in -lpam""... $ac_c" 1>&6
+echo "configure:11863: checking for pam_get_data in -lpam" >&5
+ac_lib_var=`echo pam'_'pam_get_data | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lpam $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 11871 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_get_data();
+
+int main() {
+pam_get_data()
+; return 0; }
+EOF
+if { (eval echo configure:11882: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_LIBPAM 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+#################################################
+# check for pam_smbpass support
+echo $ac_n "checking whether to use pam_smbpass""... $ac_c" 1>&6
+echo "configure:11909: checking whether to use pam_smbpass" >&5
+# Check whether --with-pam_smbpass or --without-pam_smbpass was given.
+if test "${with_pam_smbpass+set}" = set; then
+ withval="$with_pam_smbpass"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+
+# Conditions under which pam_smbpass should not be built.
+
+ if test x$PICFLAG = x; then
+ echo "$ac_t""No support for PIC code - disabling pam_smbpass" 1>&6
+ PAM_MOD=""
+ elif test x$ac_cv_lib_pam_pam_get_data = xno; then
+ echo "$ac_t""No libpam found -- disabling pam_smbpass" 1>&6
+ PAM_MOD=""
+ else
+ PAM_MOD="bin/pam_smbpass.so"
+ fi
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+###############################################
+# test for where we get crypt() from, but only
+# if not using PAM
+if test $with_pam_for_crypt = no; then
+for ac_func in crypt
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:11947: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 11952 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:11975: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test x"$ac_cv_func_crypt" = x"no"; then
+ echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:12001: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcrypt $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 12009 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:12020: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lcrypt";
+ cat >> confdefs.h <<\EOF
+#define HAVE_CRYPT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+fi
+
+##
+## moved after the check for -lcrypt in order to
+## ensure that the necessary libraries are included
+## check checking for truncated salt. Wrapped by the
+## $with_pam_for_crypt variable as above --jerry
+##
+if test $with_pam_for_crypt = no; then
+echo $ac_n "checking for a crypt that needs truncated salt""... $ac_c" 1>&6
+echo "configure:12055: checking for a crypt that needs truncated salt" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_TRUNCATED_SALT'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_TRUNCATED_SALT=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12064 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/crypttest.c"
+EOF
+if { (eval echo configure:12068: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_TRUNCATED_SALT=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_TRUNCATED_SALT=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_TRUNCATED_SALT" 1>&6
+if test x"$samba_cv_HAVE_TRUNCATED_SALT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TRUNCATED_SALT 1
+EOF
+
+fi
+fi
+
+
+
+########################################################################################
+##
+## TESTS FOR SAM BACKENDS. KEEP THESE GROUPED TOGETHER
+##
+########################################################################################
+
+## set the with_smbpasswd_sam as the default
+with_smbpasswd_sam=yes
+
+
+#################################################
+# check for a TDB password database
+echo $ac_n "checking whether to use TDB SAM database""... $ac_c" 1>&6
+echo "configure:12106: checking whether to use TDB SAM database" >&5
+# Check whether --with-tdbsam or --without-tdbsam was given.
+if test "${with_tdbsam+set}" = set; then
+ withval="$with_tdbsam"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_TDB_SAM 1
+EOF
+
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for a LDAP password database
+echo $ac_n "checking whether to use LDAP SAM database""... $ac_c" 1>&6
+echo "configure:12132: checking whether to use LDAP SAM database" >&5
+# Check whether --with-ldapsam or --without-ldapsam was given.
+if test "${with_ldapsam+set}" = set; then
+ withval="$with_ldapsam"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_LDAP_SAM 1
+EOF
+
+ LIBS="-lldap -llber $LIBS"
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for a NISPLUS password database
+echo $ac_n "checking whether to use NISPLUS SAM database""... $ac_c" 1>&6
+echo "configure:12159: checking whether to use NISPLUS SAM database" >&5
+# Check whether --with-nisplussam or --without-nisplussam was given.
+if test "${with_nisplussam+set}" = set; then
+ withval="$with_nisplussam"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_NISPLUS_SAM 1
+EOF
+
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+################################################
+# This test should come last because the
+# smbpasswd SAM is only used if another format
+# has not been defined
+echo $ac_n "checking whether to use traditional smbpasswd file""... $ac_c" 1>&6
+echo "configure:12187: checking whether to use traditional smbpasswd file" >&5
+if test $with_smbpasswd_sam = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SMBPASSWD_SAM 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+########################################################################################
+##
+## END OF TESTS FOR SAM BACKENDS.
+##
+########################################################################################
+
+#################################################
+# check for a NISPLUS_HOME support
+echo $ac_n "checking whether to use NISPLUS_HOME""... $ac_c" 1>&6
+echo "configure:12207: checking whether to use NISPLUS_HOME" >&5
+# Check whether --with-nisplus-home or --without-nisplus-home was given.
+if test "${with_nisplus_home+set}" = set; then
+ withval="$with_nisplus_home"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_NISPLUS_HOME 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for the secure socket layer
+echo $ac_n "checking whether to use SSL""... $ac_c" 1>&6
+echo "configure:12232: checking whether to use SSL" >&5
+# Check whether --with-ssl or --without-ssl was given.
+if test "${with_ssl+set}" = set; then
+ withval="$with_ssl"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SSL 1
+EOF
+
+ withval="/usr/local/ssl" # default
+
+ if test "${with_sslinc+set}" = set; then
+
+ withval="$with_sslinc"
+ case "$withval" in
+ yes|no)
+ echo "configure: warning: --with-sslinc called without argument - will use default" 1>&w
+ CFLAGS="-I/usr/local/ssl/include $CFLAGS"
+ ;;
+ * )
+ CFLAGS="-I${withval} $CFLAGS"
+ ;;
+ esac
+
+ else
+
+ CFLAGS="-I/usr/local/ssl/include $CFLAGS"
+
+ fi
+
+ if test "${with_ssllib+set}" = set; then
+
+ withval="$with_ssllib"
+ case "$withval" in
+ yes|no)
+ echo "configure: warning: --with-ssllib called without argument - will use default" 1>&w
+ LDFLAGS="-L/usr/local/ssl/lib $LDFLAGS"
+ ;;
+ * )
+ LDFLAGS="-L${withval}/lib $LDFLAGS"
+ ;;
+ esac
+
+ else
+
+ LDFLAGS="-L/usr/local/ssl/lib $LDFLAGS"
+
+ fi
+
+ LIBS="-lssl -lcrypto $LIBS"
+
+# if test ! -d ${withval}; then
+# echo "configure: error: called with --with-ssl, but ssl base directory ${withval} does not exist or is not a directory. Aborting config" 1>&2
+# exit 1
+# fi
+
+ CFLAGS="-DHAVE_CRYPT_DECL $CFLAGS" # Damn, SSLeay defines its own
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for syslog logging
+echo $ac_n "checking whether to use syslog logging""... $ac_c" 1>&6
+echo "configure:12306: checking whether to use syslog logging" >&5
+# Check whether --with-syslog or --without-syslog was given.
+if test "${with_syslog+set}" = set; then
+ withval="$with_syslog"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SYSLOG 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for a shared memory profiling support
+echo $ac_n "checking whether to use profiling""... $ac_c" 1>&6
+echo "configure:12331: checking whether to use profiling" >&5
+# Check whether --with-profiling-data or --without-profiling-data was given.
+if test "${with_profiling_data+set}" = set; then
+ withval="$with_profiling_data"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_PROFILE 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+#################################################
+# check for experimental disk-quotas support
+QUOTAOBJS=smbd/noquotas.o
+
+echo $ac_n "checking whether to support disk-quotas""... $ac_c" 1>&6
+echo "configure:12359: checking whether to support disk-quotas" >&5
+# Check whether --with-quotas or --without-quotas was given.
+if test "${with_quotas+set}" = set; then
+ withval="$with_quotas"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ case "$host_os" in
+ *linux*)
+ # Check for kernel 2.4.x quota braindamage...
+ echo $ac_n "checking for linux 2.4.x quota braindamage..""... $ac_c" 1>&6
+echo "configure:12370: checking for linux 2.4.x quota braindamage.." >&5
+if eval "test \"`echo '$''{'samba_cv_linux_2_4_quota_braindamage'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 12376 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <linux/quota.h>
+#include <mntent.h>
+#include <linux/unistd.h>
+int main() {
+struct mem_dqblk D;
+; return 0; }
+EOF
+if { (eval echo configure:12388: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_linux_2_4_quota_braindamage=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_linux_2_4_quota_braindamage=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_linux_2_4_quota_braindamage" 1>&6
+if test x"$samba_cv_linux_2_4_quota_braindamage" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define LINUX_QUOTAS_2 1
+EOF
+
+else
+ cat >> confdefs.h <<\EOF
+#define LINUX_QUOTAS_1 1
+EOF
+
+fi
+ ;;
+ *)
+ ;;
+ esac
+ QUOTAOBJS=smbd/quotas.o
+ cat >> confdefs.h <<\EOF
+#define WITH_QUOTAS 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+#################################################
+# check for experimental utmp accounting
+
+echo $ac_n "checking whether to support utmp accounting""... $ac_c" 1>&6
+echo "configure:12437: checking whether to support utmp accounting" >&5
+# Check whether --with-utmp or --without-utmp was given.
+if test "${with_utmp+set}" = set; then
+ withval="$with_utmp"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_UTMP 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# set private directory location
+# Check whether --with-privatedir or --without-privatedir was given.
+if test "${with_privatedir+set}" = set; then
+ withval="$with_privatedir"
+ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ echo "configure: warning: --with-privatedir called without argument - will use default" 1>&2
+ privatedir='${prefix}/private'
+ ;;
+ * )
+ privatedir="$withval"
+ ;;
+ esac
+
+else
+ privatedir='${prefix}/private'
+
+
+fi
+
+
+#################################################
+# set lock directory location
+# Check whether --with-lockdir or --without-lockdir was given.
+if test "${with_lockdir+set}" = set; then
+ withval="$with_lockdir"
+ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ echo "configure: warning: --with-lockdir called without argument - will use default" 1>&2
+ lockdir='$(VARDIR)/locks'
+ ;;
+ * )
+ lockdir="$withval"
+ ;;
+ esac
+
+else
+ lockdir='$(VARDIR)/locks'
+
+
+fi
+
+
+#################################################
+# set SWAT directory location
+# Check whether --with-swatdir or --without-swatdir was given.
+if test "${with_swatdir+set}" = set; then
+ withval="$with_swatdir"
+ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ echo "configure: warning: --with-swatdir called without argument - will use default" 1>&2
+ swatdir='${prefix}/swat'
+ ;;
+ * )
+ swatdir="$withval"
+ ;;
+ esac
+
+else
+ swatdir='${prefix}/swat'
+
+
+fi
+
+
+#################################################
+# choose native language(s) of man pages
+echo $ac_n "checking chosen man pages' language(s)""... $ac_c" 1>&6
+echo "configure:12537: checking chosen man pages' language(s)" >&5
+# Check whether --with-manpages-langs or --without-manpages-langs was given.
+if test "${with_manpages_langs+set}" = set; then
+ withval="$with_manpages_langs"
+ case "$withval" in
+ yes|no)
+ echo "configure: warning: --with-manpages-langs called without argument - will use default" 1>&2
+ manlangs="en"
+ ;;
+ *)
+ manlangs="$withval"
+ ;;
+ esac
+
+ echo "$ac_t""$manlangs" 1>&6
+ manlangs=`echo $manlangs | sed "s/,/ /"` # replacing commas with spaces to produce a list
+
+else
+ manlangs="en"
+ echo "$ac_t""$manlangs" 1>&6
+
+
+fi
+
+
+#################################################
+# these tests are taken from the GNU fileutils package
+echo "checking how to get filesystem space usage" 1>&6
+echo "configure:12565: checking how to get filesystem space usage" >&5
+space=no
+
+# Test for statvfs64.
+if test $space = no; then
+ # SVR4
+ echo $ac_n "checking statvfs64 function (SVR4)""... $ac_c" 1>&6
+echo "configure:12572: checking statvfs64 function (SVR4)" >&5
+if eval "test \"`echo '$''{'fu_cv_sys_stat_statvfs64'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_statvfs64=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12580 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ main ()
+ {
+ struct statvfs64 fsd;
+ exit (statvfs64 (".", &fsd));
+ }
+EOF
+if { (eval echo configure:12594: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_statvfs64=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_statvfs64=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$fu_cv_sys_stat_statvfs64" 1>&6
+ if test $fu_cv_sys_stat_statvfs64 = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATVFS64 1
+EOF
+
+ fi
+fi
+
+# Perform only the link test since it seems there are no variants of the
+# statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs)
+# because that got a false positive on SCO OSR5. Adding the declaration
+# of a `struct statvfs' causes this test to fail (as it should) on such
+# systems. That system is reported to work fine with STAT_STATFS4 which
+# is what it gets when this test fails.
+if test $space = no; then
+ # SVR4
+ echo $ac_n "checking statvfs function (SVR4)""... $ac_c" 1>&6
+echo "configure:12627: checking statvfs function (SVR4)" >&5
+if eval "test \"`echo '$''{'fu_cv_sys_stat_statvfs'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12632 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/statvfs.h>
+int main() {
+struct statvfs fsd; statvfs (0, &fsd);
+; return 0; }
+EOF
+if { (eval echo configure:12640: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ fu_cv_sys_stat_statvfs=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ fu_cv_sys_stat_statvfs=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$fu_cv_sys_stat_statvfs" 1>&6
+ if test $fu_cv_sys_stat_statvfs = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATVFS 1
+EOF
+
+ fi
+fi
+
+if test $space = no; then
+ # DEC Alpha running OSF/1
+ echo $ac_n "checking for 3-argument statfs function (DEC OSF/1)""... $ac_c" 1>&6
+echo "configure:12665: checking for 3-argument statfs function (DEC OSF/1)" >&5
+ if eval "test \"`echo '$''{'fu_cv_sys_stat_statfs3_osf1'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_statfs3_osf1=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12673 "configure"
+#include "confdefs.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_fsize = 0;
+ exit (statfs (".", &fsd, sizeof (struct statfs)));
+ }
+EOF
+if { (eval echo configure:12686: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_statfs3_osf1=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_statfs3_osf1=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+ echo "$ac_t""$fu_cv_sys_stat_statfs3_osf1" 1>&6
+ if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATFS3_OSF1 1
+EOF
+
+ fi
+fi
+
+if test $space = no; then
+# AIX
+ echo $ac_n "checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)""... $ac_c" 1>&6
+echo "configure:12713: checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)" >&5
+ if eval "test \"`echo '$''{'fu_cv_sys_stat_statfs2_bsize'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_statfs2_bsize=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12721 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_bsize = 0;
+ exit (statfs (".", &fsd));
+ }
+EOF
+if { (eval echo configure:12740: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_statfs2_bsize=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_statfs2_bsize=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+ echo "$ac_t""$fu_cv_sys_stat_statfs2_bsize" 1>&6
+ if test $fu_cv_sys_stat_statfs2_bsize = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATFS2_BSIZE 1
+EOF
+
+ fi
+fi
+
+if test $space = no; then
+# SVR3
+ echo $ac_n "checking for four-argument statfs (AIX-3.2.5, SVR3)""... $ac_c" 1>&6
+echo "configure:12767: checking for four-argument statfs (AIX-3.2.5, SVR3)" >&5
+ if eval "test \"`echo '$''{'fu_cv_sys_stat_statfs4'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_statfs4=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12775 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/statfs.h>
+ main ()
+ {
+ struct statfs fsd;
+ exit (statfs (".", &fsd, sizeof fsd, 0));
+ }
+EOF
+if { (eval echo configure:12785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_statfs4=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_statfs4=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+ echo "$ac_t""$fu_cv_sys_stat_statfs4" 1>&6
+ if test $fu_cv_sys_stat_statfs4 = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATFS4 1
+EOF
+
+ fi
+fi
+
+if test $space = no; then
+# 4.4BSD and NetBSD
+ echo $ac_n "checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)""... $ac_c" 1>&6
+echo "configure:12812: checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)" >&5
+ if eval "test \"`echo '$''{'fu_cv_sys_stat_statfs2_fsize'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_statfs2_fsize=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12820 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_fsize = 0;
+ exit (statfs (".", &fsd));
+ }
+EOF
+if { (eval echo configure:12836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_statfs2_fsize=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_statfs2_fsize=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+ echo "$ac_t""$fu_cv_sys_stat_statfs2_fsize" 1>&6
+ if test $fu_cv_sys_stat_statfs2_fsize = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATFS2_FSIZE 1
+EOF
+
+ fi
+fi
+
+if test $space = no; then
+ # Ultrix
+ echo $ac_n "checking for two-argument statfs with struct fs_data (Ultrix)""... $ac_c" 1>&6
+echo "configure:12863: checking for two-argument statfs with struct fs_data (Ultrix)" >&5
+ if eval "test \"`echo '$''{'fu_cv_sys_stat_fs_data'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ fu_cv_sys_stat_fs_data=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 12871 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_FS_TYPES_H
+#include <sys/fs_types.h>
+#endif
+ main ()
+ {
+ struct fs_data fsd;
+ /* Ultrix's statfs returns 1 for success,
+ 0 for not mounted, -1 for failure. */
+ exit (statfs (".", &fsd) != 1);
+ }
+EOF
+if { (eval echo configure:12891: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ fu_cv_sys_stat_fs_data=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ fu_cv_sys_stat_fs_data=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+ echo "$ac_t""$fu_cv_sys_stat_fs_data" 1>&6
+ if test $fu_cv_sys_stat_fs_data = yes; then
+ space=yes
+ cat >> confdefs.h <<\EOF
+#define STAT_STATFS2_FS_DATA 1
+EOF
+
+ fi
+fi
+
+#
+# As a gating factor for large file support, in order to
+# use <4GB files we must have the following minimal support
+# available.
+# long long, and a 64 bit off_t or off64_t.
+# If we don't have all of these then disable large
+# file support.
+#
+echo $ac_n "checking if large file support can be enabled""... $ac_c" 1>&6
+echo "configure:12924: checking if large file support can be enabled" >&5
+cat > conftest.$ac_ext <<EOF
+#line 12926 "configure"
+#include "confdefs.h"
+
+#if defined(HAVE_LONGLONG) && (defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8)))
+#include <sys/types.h>
+#else
+__COMPILE_ERROR_
+#endif
+
+int main() {
+int i
+; return 0; }
+EOF
+if { (eval echo configure:12939: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=no
+fi
+rm -f conftest*
+if test x"$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_EXPLICIT_LARGEFILE_SUPPORT 1
+EOF
+
+fi
+echo "$ac_t""$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT" 1>&6
+
+# Check whether --with-spinlocks or --without-spinlocks was given.
+if test "${with_spinlocks+set}" = set; then
+ withval="$with_spinlocks"
+ :
+fi
+
+if test "x$with_spinlocks" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define USE_SPINLOCKS 1
+EOF
+
+
+ case "$host_cpu" in
+ sparc)
+ cat >> confdefs.h <<\EOF
+#define SPARC_SPINLOCKS 1
+EOF
+
+ ;;
+
+ i386|i486|i586|i686)
+ cat >> confdefs.h <<\EOF
+#define INTEL_SPINLOCKS 1
+EOF
+
+ ;;
+
+ mips)
+ cat >> confdefs.h <<\EOF
+#define MIPS_SPINLOCKS 1
+EOF
+
+ ;;
+
+ powerpc)
+ cat >> confdefs.h <<\EOF
+#define POWERPC_SPINLOCKS 1
+EOF
+
+ ;;
+ esac
+fi
+
+#################################################
+# check for ACL support
+
+echo $ac_n "checking whether to support ACLs""... $ac_c" 1>&6
+echo "configure:13004: checking whether to support ACLs" >&5
+# Check whether --with-acl-support or --without-acl-support was given.
+if test "${with_acl_support+set}" = set; then
+ withval="$with_acl_support"
+ case "$withval" in
+ yes)
+
+ case "$host_os" in
+ *sysv5*)
+ echo "$ac_t""Using UnixWare ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_UNIXWARE_ACLS 1
+EOF
+
+ ;;
+ *solaris*)
+ echo "$ac_t""Using solaris ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOLARIS_ACLS 1
+EOF
+
+ ;;
+ *hpux*)
+ echo "$ac_t""Using HPUX ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_HPUX_ACLS 1
+EOF
+
+ ;;
+ *irix*)
+ echo "$ac_t""Using IRIX ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_IRIX_ACLS 1
+EOF
+
+ ;;
+ *aix*)
+ echo "$ac_t""Using AIX ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_AIX_ACLS 1
+EOF
+
+ ;;
+ *osf*)
+ echo "$ac_t""Using Tru64 ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_TRU64_ACLS 1
+EOF
+
+ LIBS="$LIBS -lpacl"
+ ;;
+ *)
+ echo $ac_n "checking for acl_get_file in -lacl""... $ac_c" 1>&6
+echo "configure:13057: checking for acl_get_file in -lacl" >&5
+ac_lib_var=`echo acl'_'acl_get_file | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lacl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 13065 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char acl_get_file();
+
+int main() {
+acl_get_file()
+; return 0; }
+EOF
+if { (eval echo configure:13076: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo acl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lacl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ echo $ac_n "checking for ACL support""... $ac_c" 1>&6
+echo "configure:13104: checking for ACL support" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_POSIX_ACLS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 13110 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+int main() {
+ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);
+; return 0; }
+EOF
+if { (eval echo configure:13118: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ samba_cv_HAVE_POSIX_ACLS=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_POSIX_ACLS=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_POSIX_ACLS" 1>&6
+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
+ echo "$ac_t""Using posix ACLs" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_POSIX_ACLS 1
+EOF
+
+ echo $ac_n "checking for acl_get_perm_np""... $ac_c" 1>&6
+echo "configure:13138: checking for acl_get_perm_np" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_ACL_GET_PERM_NP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 13144 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/acl.h>
+int main() {
+ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);
+; return 0; }
+EOF
+if { (eval echo configure:13152: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ samba_cv_HAVE_ACL_GET_PERM_NP=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_ACL_GET_PERM_NP=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_ACL_GET_PERM_NP" 1>&6
+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ACL_GET_PERM_NP 1
+EOF
+
+ fi
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_NO_ACLS 1
+EOF
+
+ ;;
+ esac
+else
+ cat >> confdefs.h <<\EOF
+#define HAVE_NO_ACLS 1
+EOF
+
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# Check whether winbind is supported on this platform. If so we need to
+# build and install client programs (WINBIND_TARGETS), sbin programs
+# (WINBIND_STARGETS) and shared libraries (WINBIND_LTARGETS).
+
+echo $ac_n "checking whether to build winbind""... $ac_c" 1>&6
+echo "configure:13199: checking whether to build winbind" >&5
+
+# Initially, the value of $host_os decides whether winbind is supported
+
+case "$host_os" in
+ *linux*|*solaris*)
+ HAVE_WINBIND=yes
+ ;;
+ *)
+ HAVE_WINBIND=no
+ winbind_no_reason=", unsupported on $host_os"
+ ;;
+esac
+
+# Check the setting of --with-winbindd
+
+# Check whether --with-winbind or --without-winbind was given.
+if test "${with_winbind+set}" = set; then
+ withval="$with_winbind"
+
+ case "$withval" in
+ yes)
+ HAVE_WINBIND=yes
+ ;;
+ no)
+ HAVE_WINBIND=no
+ winbind_reason=""
+ ;;
+ esac
+fi
+
+
+# We need unix domain sockets for winbind
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+ if test x"$samba_cv_unixsocket" = x"no"; then
+ winbind_no_reason=", no unix domain socket support on $host_os"
+ HAVE_WINBIND=no
+ fi
+fi
+
+# Display test results
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+
+ echo "$ac_t""yes" 1>&6
+
+ WINBIND_TARGETS="bin/wbinfo"
+ WINBIND_STARGETS="bin/winbindd"
+ WINBIND_LTARGETS="nsswitch/libnss_winbind.so"
+ case "$with_pam" in
+ yes)
+ WINBIND_PAM_TARGETS="nsswitch/pam_winbind.so"
+ ;;
+ esac
+else
+ echo "$ac_t""no$winbind_no_reason" 1>&6
+
+ WINBIND_TARGETS=""
+ WINBIND_STARGETS=""
+ WINBIND_LTARGETS=""
+ WINBIND_PAM_PROGS=""
+fi
+
+# Substitution time!
+
+
+
+
+
+
+#################################################
+# Check to see if we should use the included popt
+
+# Check whether --with-included-popt or --without-included-popt was given.
+if test "${with_included_popt+set}" = set; then
+ withval="$with_included_popt"
+
+ case "$withval" in
+ yes)
+ INCLUDED_POPT=yes
+ ;;
+ no)
+ INCLUDED_POPT=no
+ ;;
+ esac
+fi
+
+if test x"$INCLUDED_POPT" != x"yes"; then
+ echo $ac_n "checking for poptGetContext in -lpopt""... $ac_c" 1>&6
+echo "configure:13289: checking for poptGetContext in -lpopt" >&5
+ac_lib_var=`echo popt'_'poptGetContext | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lpopt $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 13297 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char poptGetContext();
+
+int main() {
+poptGetContext()
+; return 0; }
+EOF
+if { (eval echo configure:13308: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ INCLUDED_POPT=no
+else
+ echo "$ac_t""no" 1>&6
+INCLUDED_POPT=yes
+fi
+
+fi
+
+echo $ac_n "checking whether to use included popt""... $ac_c" 1>&6
+echo "configure:13332: checking whether to use included popt" >&5
+if test x"$INCLUDED_POPT" = x"yes"; then
+ echo "$ac_t""$srcdir/popt" 1>&6
+ BUILD_POPT='$(POPT_OBJS)'
+ FLAGS1="-I$srcdir/popt"
+else
+ echo "$ac_t""no" 1>&6
+ LIBS="$LIBS -lpopt"
+fi
+
+
+
+#################################################
+# final configure stuff
+
+echo "checking configure summary"
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 13352 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/summary.c"
+EOF
+if { (eval echo configure:13356: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ echo "configure OK";
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ { echo "configure: error: summary failure. Aborting config" 1>&2; exit 1; }
+fi
+rm -fr conftest*
+fi
+
+
+builddir=`pwd`
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "include/stamp-h Makefile include/config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@RUNPROG@%$RUNPROG%g
+s%@MPROGS@%$MPROGS%g
+s%@LDSHFLAGS@%$LDSHFLAGS%g
+s%@SHLD@%$SHLD%g
+s%@HOST_OS@%$HOST_OS%g
+s%@PAM_MOD@%$PAM_MOD%g
+s%@WRAP@%$WRAP%g
+s%@WRAP32@%$WRAP32%g
+s%@PICFLAG@%$PICFLAG%g
+s%@PICSUFFIX@%$PICSUFFIX%g
+s%@POBAD_CC@%$POBAD_CC%g
+s%@SHLIBEXT@%$SHLIBEXT%g
+s%@LIBSMBCLIENT_SHARED@%$LIBSMBCLIENT_SHARED%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@AWK@%$AWK%g
+s%@BROKEN_CC@%$BROKEN_CC%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@TERMLIBS@%$TERMLIBS%g
+s%@TERMLDFLAGS@%$TERMLDFLAGS%g
+s%@ROFF@%$ROFF%g
+s%@QUOTAOBJS@%$QUOTAOBJS%g
+s%@privatedir@%$privatedir%g
+s%@lockdir@%$lockdir%g
+s%@swatdir@%$swatdir%g
+s%@manlangs@%$manlangs%g
+s%@WINBIND_TARGETS@%$WINBIND_TARGETS%g
+s%@WINBIND_STARGETS@%$WINBIND_STARGETS%g
+s%@WINBIND_LTARGETS@%$WINBIND_LTARGETS%g
+s%@WINBIND_PAM_TARGETS@%$WINBIND_PAM_TARGETS%g
+s%@BUILD_POPT@%$BUILD_POPT%g
+s%@FLAGS1@%$FLAGS1%g
+s%@builddir@%$builddir%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"include/stamp-h Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="include/config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/source/configure.developer b/source/configure.developer
new file mode 100755
index 00000000000..0409a750615
--- /dev/null
+++ b/source/configure.developer
@@ -0,0 +1,2 @@
+#!/bin/sh
+`dirname $0`/configure --enable-developer $*
diff --git a/source/configure.in b/source/configure.in
new file mode 100644
index 00000000000..48057c15a5b
--- /dev/null
+++ b/source/configure.in
@@ -0,0 +1,2583 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(include/includes.h)
+AC_CONFIG_HEADER(include/config.h)
+# we want to be compatibe with older versions of Samba
+AC_PREFIX_DEFAULT(/usr/local/samba)
+
+dnl Unique-to-Samba variables we'll be playing with.
+AC_SUBST(SHELL)
+AC_SUBST(RUNPROG)
+AC_SUBST(MPROGS)
+AC_SUBST(LDSHFLAGS)
+AC_SUBST(SHLD)
+AC_SUBST(HOST_OS)
+AC_SUBST(PAM_MOD)
+AC_SUBST(WRAP)
+AC_SUBST(WRAP32)
+AC_SUBST(PICFLAG)
+AC_SUBST(PICSUFFIX)
+AC_SUBST(POBAD_CC)
+AC_SUBST(SHLIBEXT)
+AC_SUBST(LIBSMBCLIENT_SHARED)
+
+# compile with optimisation and without debugging by default
+CFLAGS="-O ${CFLAGS}"
+
+AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]],
+ [if eval "test x$enable_debug = xyes"; then
+ CFLAGS="${CFLAGS} -g"
+ fi])
+
+AC_ARG_ENABLE(developer, [ --enable-developer turn on developer warnings and debugging [default=no]],
+ [if eval "test x$enable_developer = xyes"; then
+ CFLAGS="${CFLAGS} -g -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -DDEBUG_PASSWORD -DDEVELOPER"
+ fi])
+
+AC_ARG_ENABLE(dmalloc, [ --enable-dmalloc enable heap debugging [default=no]])
+
+if test "x$enable_dmalloc" = xyes
+then
+ AC_DEFINE(ENABLE_DMALLOC, 1, [Define to turn on dmalloc debugging])
+ LIBS="$LIBS -ldmalloc"
+fi
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_AWK
+
+dnl needed before AC_TRY_COMPILE
+AC_ISC_POSIX
+
+dnl Check if C compiler understands -c and -o at the same time
+AC_PROG_CC_C_O
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = no"; then
+ BROKEN_CC=
+else
+ BROKEN_CC=#
+fi
+AC_SUBST(BROKEN_CC)
+
+dnl Check if the C compiler understands volatile (it should, being ANSI).
+AC_CACHE_CHECK([that the C compiler understands volatile],samba_cv_volatile, [
+ AC_TRY_COMPILE([#include <sys/types.h>],[volatile int i = 0],
+ samba_cv_volatile=yes,samba_cv_volatile=no)])
+if test x"$samba_cv_volatile" = x"yes"; then
+ AC_DEFINE(HAVE_VOLATILE)
+fi
+
+
+AC_CANONICAL_SYSTEM
+
+dnl Add #include for broken IRIX header files
+ case "$host_os" in
+ *irix6*) AC_ADD_INCLUDE(<standards.h>)
+ ;;
+esac
+
+AC_VALIDATE_CACHE_SYSTEM_TYPE
+
+#
+# Config CPPFLAG settings for strange OS's that must be set
+# before other tests.
+#
+case "$host_os" in
+# Try to work out if this is the native HPUX compiler that uses the -Ae flag.
+ *hpux*)
+ AC_PROG_CC_FLAG(Ae)
+ # mmap on HPUX is completely broken...
+ AC_DEFINE(MMAP_BLACKLIST)
+ if test $ac_cv_prog_cc_Ae = yes; then
+ CPPFLAGS="$CPPFLAGS -Ae"
+ fi
+#
+# Defines needed for HPUX support.
+# HPUX has bigcrypt but (sometimes?) doesn't use it for
+# password hashing - hence the USE_BOTH_CRYPT_CALLS define.
+#
+ case `uname -r` in
+ *9*|*10*)
+ CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_POSIX_SOURCE"
+ AC_DEFINE(USE_BOTH_CRYPT_CALLS)
+ ;;
+ *11*)
+ CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_POSIX_SOURCE -D_LARGEFILE64_SOURCE"
+ AC_DEFINE(USE_BOTH_CRYPT_CALLS)
+ ;;
+ esac
+ ;;
+#
+# AIX4.x doesn't even admit to having large
+# files *at all* unless the -D_LARGE_FILE or -D_LARGE_FILE_API flags are set.
+#
+ *aix4*)
+ AC_MSG_RESULT([enabling large file support])
+ CPPFLAGS="$CPPFLAGS -D_LARGE_FILES"
+ ;;
+#
+# Defines needed for Solaris 2.6/2.7 aka 7.0 to make it admit
+# to the existance of large files..
+# Note that -D_LARGEFILE64_SOURCE is different from the Sun
+# recommendations on large file support, however it makes the
+# compile work using gcc 2.7 and 2.8, whereas using the Sun
+# recommendation makes the compile fail on gcc2.7. JRA.
+#
+ *solaris*)
+ case `uname -r` in
+ 5.0*|5.1*|5.2*|5.3*|5.5*)
+ AC_MSG_RESULT([no large file support])
+ ;;
+ 5.*)
+ AC_MSG_RESULT([enabling large file support])
+ if test "$ac_cv_prog_gcc" = yes; then
+ ${CC-cc} -v >conftest.c 2>&1
+ ac_cv_gcc_compiler_version_number=`grep 'gcc version' conftest.c`
+ rm -fr conftest.c
+ case "$ac_cv_gcc_compiler_version_number" in
+ *"gcc version 2.6"*|*"gcc version 2.7"*)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE"
+ ;;
+ *)
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ ;;
+ esac
+ else
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ fi
+ ;;
+ esac
+ ;;
+#
+# Tests needed for SINIX large file support.
+#
+ *sysv4*)
+ if test $host = mips-sni-sysv4 ; then
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}], [SINIX_LFS_SUPPORT=yes], [SINIX_LFS_SUPPORT=no], [SINIX_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$SINIX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE $CPPFLAGS"
+ CFLAGS="`getconf LFS64_CFLAGS` $CFLAGS"
+ LDFLAGS="`getconf LFS64_LDFLAGS` $LDFLAGS"
+ LIBS="`getconf LFS64_LIBS` $LIBS"
+ fi
+ AC_MSG_RESULT([$SINIX_LFS_SUPPORT])
+ fi
+ ;;
+
+# Tests for linux LFS support. Need kernel 2.4 and glibc2.2 or greater support.
+#
+ *linux*)
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+#include <sys/utsname.h>
+main() {
+#if _LFS64_LARGEFILE == 1
+ struct utsname uts;
+ char *release;
+ int major, minor;
+
+ /* Ensure this is glibc 2.2 or higher */
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+ int libc_major = __GLIBC__;
+ int libc_minor = __GLIBC_MINOR__;
+
+ if (libc_major < 2)
+ exit(1);
+ if (libc_minor < 2)
+ exit(1);
+#endif
+
+ /* Ensure this is kernel 2.4 or higher */
+
+ uname(&uts);
+ release = uts.release;
+ major = atoi(strsep(&release, "."));
+ minor = atoi(strsep(&release, "."));
+
+ if (major > 2 || (major == 2 && minor > 3))
+ exit(0);
+ exit(1);
+#else
+ exit(1);
+#endif
+}
+], [LINUX_LFS_SUPPORT=yes], [LINUX_LFS_SUPPORT=no], [LINUX_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$LINUX_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $CPPFLAGS"
+ fi
+ AC_MSG_RESULT([$LINUX_LFS_SUPPORT])
+ ;;
+
+ *hurd*)
+ AC_MSG_CHECKING([for LFS support])
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ AC_TRY_RUN([
+#include <unistd.h>
+main () {
+#if _LFS64_LARGEFILE == 1
+exit(0);
+#else
+exit(1);
+#endif
+}], [GLIBC_LFS_SUPPORT=yes], [GLIBC_LFS_SUPPORT=no], [GLIBC_LFS_SUPPORT=cross])
+ CPPFLAGS="$old_CPPFLAGS"
+ if test x$GLIBC_LFS_SUPPORT = xyes ; then
+ CPPFLAGS="-D_LARGEFILE64_SOURCE -D_GNU_SOURCE $CPPFLAGS"
+ fi
+ AC_MSG_RESULT([$GLIBC_LFS_SUPPORT])
+ ;;
+
+esac
+
+AC_INLINE
+AC_HEADER_STDC
+AC_HEADER_DIRENT
+AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(arpa/inet.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h)
+AC_CHECK_HEADERS(unistd.h utime.h grp.h sys/id.h limits.h memory.h net/if.h)
+AC_CHECK_HEADERS(compat.h rpc/rpc.h rpcsvc/nis.h rpcsvc/yp_prot.h rpcsvc/ypclnt.h)
+AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/mode.h)
+AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h)
+AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h)
+AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h)
+AC_CHECK_HEADERS(security/pam_modules.h security/_pam_macros.h ldap.h)
+
+#
+# HPUX has a bug in that including shadow.h causes a re-definition of MAXINT.
+# This causes configure to fail to detect it. Check for shadow separately on HPUX.
+#
+case "$host_os" in
+ *hpux*)
+ AC_TRY_COMPILE([#include <shadow.h>],[struct spwd testme],
+ ac_cv_header_shadow_h=yes,ac_cv_header_shadow_h=no)
+ if test x"$ac_cv_header_shadow_h" = x"yes"; then
+ AC_DEFINE(HAVE_SHADOW_H)
+ fi
+ ;;
+esac
+AC_CHECK_HEADERS(shadow.h netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
+AC_CHECK_HEADERS(nss.h nss_common.h ns_api.h sys/security.h security/pam_appl.h security/pam_modules.h)
+AC_CHECK_HEADERS(stropts.h poll.h)
+AC_CHECK_HEADERS(sys/capability.h syscall.h sys/syscall.h)
+AC_CHECK_HEADERS(sys/acl.h sys/cdefs.h glob.h)
+
+# For experimental utmp support (lastlog on some BSD-like systems)
+AC_CHECK_HEADERS(utmp.h utmpx.h lastlog.h)
+
+# For quotas on Veritas VxFS filesystems
+AC_CHECK_HEADERS(sys/fs/vx_quota.h)
+
+# For quotas on Linux XFS filesystems
+AC_CHECK_HEADERS(linux/xqm.h)
+
+AC_CHECK_SIZEOF(int,cross)
+AC_CHECK_SIZEOF(long,cross)
+AC_CHECK_SIZEOF(short,cross)
+
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+AC_C_CHAR_UNSIGNED
+
+AC_TYPE_SIGNAL
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_PID_T
+AC_STRUCT_ST_RDEV
+AC_DIRENT_D_OFF
+AC_CHECK_TYPE(ino_t,unsigned)
+AC_CHECK_TYPE(loff_t,off_t)
+AC_CHECK_TYPE(offset_t,loff_t)
+AC_CHECK_TYPE(ssize_t, int)
+AC_CHECK_TYPE(wchar_t, unsigned short)
+
+############################################
+# for cups support we need libcups, and a handful of header files
+
+AC_CHECK_LIB(cups,httpConnect)
+
+# I wonder if there is a nicer way of doing this?
+
+if test x"$ac_cv_lib_cups_httpConnect" = x"yes"; then
+ AC_CHECK_HEADERS(cups/cups.h cups/language.h)
+ if test x"$ac_cv_header_cups_cups_h" = x"yes"; then
+ if test x"$ac_cv_header_cups_language_h" = x"yes"; then
+ AC_DEFINE(HAVE_CUPS)
+ fi
+ fi
+fi
+
+############################################
+# we need libdl for PAM and the new VFS code
+AC_CHECK_LIB(dl, dlopen, [LIBS="$LIBS -ldl";
+ AC_DEFINE(HAVE_LIBDL)])
+
+############################################
+# check if the compiler can do immediate structures
+AC_CACHE_CHECK([for immediate structures],samba_cv_immediate_structures, [
+ AC_TRY_COMPILE([
+#include <stdio.h>],
+[
+ #define X_FOOBAR(x) ((FOOBAR) { x })
+ typedef struct {unsigned x;} FOOBAR;
+ FOOBAR f = X_FOOBAR(1);
+],
+ samba_cv_immediate_structures=yes,samba_cv_immediate_structures=no)])
+if test x"$samba_cv_immediate_structures" = x"yes"; then
+ AC_DEFINE(HAVE_IMMEDIATE_STRUCTURES)
+fi
+
+############################################
+# check for unix domain sockets
+AC_CACHE_CHECK([for unix domain sockets],samba_cv_unixsocket, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>],
+[
+ struct sockaddr_un sunaddr;
+ sunaddr.sun_family = AF_UNIX;
+],
+ samba_cv_unixsocket=yes,samba_cv_unixsocket=no)])
+if test x"$samba_cv_unixsocket" = x"yes"; then
+ AC_DEFINE(HAVE_UNIXSOCKET)
+fi
+
+
+AC_CACHE_CHECK([for socklen_t type],samba_cv_socklen_t, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <sys/socket.h>],[socklen_t i = 0],
+ samba_cv_socklen_t=yes,samba_cv_socklen_t=no)])
+if test x"$samba_cv_socklen_t" = x"yes"; then
+ AC_DEFINE(HAVE_SOCKLEN_T_TYPE)
+fi
+
+AC_CACHE_CHECK([for sig_atomic_t type],samba_cv_sig_atomic_t, [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <signal.h>],[sig_atomic_t i = 0],
+ samba_cv_sig_atomic_t=yes,samba_cv_sig_atomic_t=no)])
+if test x"$samba_cv_sig_atomic_t" = x"yes"; then
+ AC_DEFINE(HAVE_SIG_ATOMIC_T_TYPE)
+fi
+
+# stupid headers have the functions but no declaration. grrrr.
+AC_HAVE_DECL(errno, [#include <errno.h>])
+AC_HAVE_DECL(setresuid, [#include <unistd.h>])
+AC_HAVE_DECL(setresgid, [#include <unistd.h>])
+AC_HAVE_DECL(asprintf, [#include <stdio.h>])
+AC_HAVE_DECL(vasprintf, [#include <stdio.h>])
+AC_HAVE_DECL(vsnprintf, [#include <stdio.h>])
+AC_HAVE_DECL(snprintf, [#include <stdio.h>])
+
+# and glibc has setresuid under linux but the function does
+# nothing until kernel 2.1.44! very dumb.
+AC_CACHE_CHECK([for real setresuid],samba_cv_have_setresuid,[
+ AC_TRY_RUN([#include <errno.h>
+main() { setresuid(1,1,1); setresuid(2,2,2); exit(errno==EPERM?0:1);}],
+ samba_cv_have_setresuid=yes,samba_cv_have_setresuid=no,samba_cv_have_setresuid=cross)])
+if test x"$samba_cv_have_setresuid" = x"yes"; then
+ AC_DEFINE(HAVE_SETRESUID)
+fi
+
+# Do the same check for setresguid...
+#
+AC_CACHE_CHECK([for real setresgid],samba_cv_have_setresgid,[
+ AC_TRY_RUN([#include <unistd.h>
+#include <errno.h>
+main() { errno = 0; setresgid(1,1,1); exit(errno != 0 ? (errno==EPERM ? 0 : 1) : 0);}],
+ samba_cv_have_setresgid=yes,samba_cv_have_setresgid=no,samba_cv_have_setresgid=cross)])
+if test x"$samba_cv_have_setresgid" = x"yes"; then
+ AC_DEFINE(HAVE_SETRESGID)
+fi
+
+AC_FUNC_MEMCMP
+
+###############################################
+# test for where we get crypt() from
+AC_CHECK_FUNCS(crypt)
+if test x"$ac_cv_func_crypt" = x"no"; then
+ AC_CHECK_LIB(crypt, crypt, [LIBS="$LIBS -lcrypt";
+ AC_DEFINE(HAVE_CRYPT)])
+fi
+
+
+###############################################
+# Readline included by default unless explicitly asked not to
+test "${with_readline+set}" != "set" && with_readline=yes
+
+# test for where we get readline() from
+AC_MSG_CHECKING(whether to use readline)
+AC_ARG_WITH(readline,
+[ --with-readline[=DIR] Look for readline include/libs in DIR (default=auto) ],
+[ case "$with_readline" in
+ yes)
+ AC_MSG_RESULT(yes)
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE)
+ break], [TERMLIBS=], $TERMLIBS)])
+ ;;
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+
+ # Needed for AC_CHECK_HEADERS and AC_CHECK_LIB to look at
+ # alternate readline path
+ _ldflags=${LDFLAGS}
+ _cppflags=${CPPFLAGS}
+
+ # Add additional search path
+ LDFLAGS="-L$with_readline/lib $LDFLAGS"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLDFLAGS="-L$with_readline/lib"
+ TERMCPPFLAGS="-I$with_readline/include"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+ TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE)
+ break], [TERMLIBS= CPPFLAGS=$_cppflags], $TERMLIBS)])
+
+ LDFLAGS=$_ldflags
+ ;;
+ esac],
+ AC_MSG_RESULT(no)
+)
+AC_SUBST(TERMLIBS)
+AC_SUBST(TERMLDFLAGS)
+
+# The readline API changed slightly from readline3 to readline4, so
+# code will generate warnings on one of them unless we have a few
+# special cases.
+AC_CHECK_LIB(readline, rl_completion_matches,
+ [AC_DEFINE(HAVE_NEW_LIBREADLINE, 1,
+ [Do we have rl_completion_matches?])],
+ [],
+ [$TERMLIBS])
+
+# The following test taken from the cvs sources
+# If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
+# The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
+# libsocket.so which has a bad implementation of gethostbyname (it
+# only looks in /etc/hosts), so we only look for -lsocket if we need
+# it.
+AC_CHECK_FUNCS(connect)
+if test x"$ac_cv_func_connect" = x"no"; then
+ case "$LIBS" in
+ *-lnsl*) ;;
+ *) AC_CHECK_LIB(nsl_s, printf) ;;
+ esac
+ case "$LIBS" in
+ *-lnsl*) ;;
+ *) AC_CHECK_LIB(nsl, printf) ;;
+ esac
+ case "$LIBS" in
+ *-lsocket*) ;;
+ *) AC_CHECK_LIB(socket, connect) ;;
+ esac
+ case "$LIBS" in
+ *-linet*) ;;
+ *) AC_CHECK_LIB(inet, connect) ;;
+ esac
+ dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
+ dnl has been cached.
+ if test x"$ac_cv_lib_socket_connect" = x"yes" ||
+ test x"$ac_cv_lib_inet_connect" = x"yes"; then
+ # ac_cv_func_connect=yes
+ # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
+ AC_DEFINE(HAVE_CONNECT)
+ fi
+fi
+
+###############################################
+# test for where we get get_yp_default_domain() from
+AC_CHECK_FUNCS(yp_get_default_domain)
+if test x"$ac_cv_func_yp_get_default_domain" = x"no"; then
+ AC_CHECK_LIB(nsl, yp_get_default_domain, [LIBS="$LIBS -lnsl";
+ AC_DEFINE(HAVE_YP_GET_DEFAULT_DOMAIN)])
+fi
+
+# Check if we have execl, if not we need to compile smbrun.
+AC_CHECK_FUNCS(execl)
+if test x"$ac_cv_func_execl" = x"no"; then
+ RUNPROG="bin/smbrun"
+else
+ RUNPROG=""
+fi
+
+AC_CHECK_FUNCS(waitpid getcwd strdup strtoul strerror chown fchown chmod fchmod chroot)
+AC_CHECK_FUNCS(fstat strchr utime utimes getrlimit fsync bzero memset strlcpy strlcat)
+AC_CHECK_FUNCS(memmove vsnprintf snprintf asprintf vasprintf setsid glob strpbrk pipe crypt16 getauthuid)
+AC_CHECK_FUNCS(strftime sigprocmask sigblock sigaction sigset innetgr setnetgrent getnetgrent endnetgrent)
+AC_CHECK_FUNCS(initgroups select poll rdchk getgrnam getgrent pathconf)
+AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf mktime rename ftruncate stat64 fstat64)
+AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt dup2 lseek64 ftruncate64 readdir64)
+AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid getpwanam setlinebuf)
+AC_CHECK_FUNCS(srandom random srand rand setenv usleep strcasecmp fcvt fcvtl symlink readlink)
+AC_CHECK_FUNCS(syslog vsyslog)
+# setbuffer is needed for smbtorture
+AC_CHECK_FUNCS(setbuffer)
+
+# syscall() is needed for smbwrapper.
+AC_CHECK_FUNCS(syscall)
+
+AC_CHECK_FUNCS(_dup _dup2 _opendir _readdir _seekdir _telldir _closedir)
+AC_CHECK_FUNCS(__dup __dup2 __opendir __readdir __seekdir __telldir __closedir)
+AC_CHECK_FUNCS(__getcwd _getcwd)
+AC_CHECK_FUNCS(__xstat __fxstat __lxstat)
+AC_CHECK_FUNCS(_stat _lstat _fstat __stat __lstat __fstat)
+AC_CHECK_FUNCS(_acl __acl _facl __facl _open __open _chdir __chdir)
+AC_CHECK_FUNCS(_close __close _fchdir __fchdir _fcntl __fcntl)
+AC_CHECK_FUNCS(getdents _getdents __getdents _lseek __lseek _read __read)
+AC_CHECK_FUNCS(_write __write _fork __fork)
+AC_CHECK_FUNCS(_stat64 __stat64 _fstat64 __fstat64 _lstat64 __lstat64)
+AC_CHECK_FUNCS(__sys_llseek llseek _llseek __llseek readdir64 _readdir64 __readdir64)
+AC_CHECK_FUNCS(pread _pread __pread pread64 _pread64 __pread64)
+AC_CHECK_FUNCS(pwrite _pwrite __pwrite pwrite64 _pwrite64 __pwrite64)
+AC_CHECK_FUNCS(open64 _open64 __open64 creat64)
+
+#
+# stat64 family may need <sys/stat.h> on some systems, notably ReliantUNIX
+#
+
+if test x$ac_cv_func_stat64 = xno ; then
+ AC_MSG_CHECKING([for stat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(stat64(".",&st64));], [ac_cv_func_stat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_stat64])
+ if test x$ac_cv_func_stat64 = xyes ; then
+ AC_DEFINE(HAVE_STAT64)
+ fi
+fi
+
+if test x$ac_cv_func_lstat64 = xno ; then
+ AC_MSG_CHECKING([for lstat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(lstat64(".",&st64));], [ac_cv_func_lstat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_lstat64])
+ if test x$ac_cv_func_lstat64 = xyes ; then
+ AC_DEFINE(HAVE_LSTAT64)
+ fi
+fi
+
+if test x$ac_cv_func_fstat64 = xno ; then
+ AC_MSG_CHECKING([for fstat64 in <sys/stat.h>])
+ AC_TRY_LINK([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+], [struct stat64 st64; exit(fstat64(0,&st64));], [ac_cv_func_fstat64=yes])
+ AC_MSG_RESULT([$ac_cv_func_fstat64])
+ if test x$ac_cv_func_fstat64 = xyes ; then
+ AC_DEFINE(HAVE_FSTAT64)
+ fi
+fi
+
+#####################################
+# we might need the resolv library on some systems
+AC_CHECK_LIB(resolv, dn_expand)
+
+#
+# Check for the functions putprpwnam, set_auth_parameters,
+# getspnam, bigcrypt and getprpwnam in -lsec and -lsecurity
+# Needed for OSF1 and HPUX.
+#
+
+AC_LIBTESTFUNC(security, putprpwnam)
+AC_LIBTESTFUNC(sec, putprpwnam)
+
+AC_LIBTESTFUNC(security, set_auth_parameters)
+AC_LIBTESTFUNC(sec, set_auth_parameters)
+
+# UnixWare 7.x has its getspnam in -lgen
+AC_LIBTESTFUNC(gen, getspnam)
+
+AC_LIBTESTFUNC(security, getspnam)
+AC_LIBTESTFUNC(sec, getspnam)
+
+AC_LIBTESTFUNC(security, bigcrypt)
+AC_LIBTESTFUNC(sec, bigcrypt)
+
+AC_LIBTESTFUNC(security, getprpwnam)
+AC_LIBTESTFUNC(sec, getprpwnam)
+
+# this bit needs to be modified for each OS that is suported by
+# smbwrapper. You need to specify how to created a shared library and
+# how to compile C code to produce PIC object files
+
+# these are the defaults, good for lots of systems
+HOST_OS="$host_os"
+LDSHFLAGS="-shared"
+SHLD="\${CC}"
+PICFLAG=""
+PICSUFFIX="po"
+POBAD_CC="#"
+SHLIBEXT="so"
+# Assume non-shared by default and override below
+BLDSHARED="false"
+AC_MSG_CHECKING([ability to build shared libraries])
+
+# and these are for particular systems
+case "$host_os" in
+ *linux*) AC_DEFINE(LINUX)
+ BLDSHARED="true"
+ LDSHFLAGS="-shared"
+ PICFLAG="-fPIC"
+ ;;
+ *solaris*) AC_DEFINE(SUNOS5)
+ BLDSHARED="true"
+ LDSHFLAGS="-h \$@ -G"
+ if test "${ac_cv_prog_CC}" = "gcc"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ POBAD_CC=""
+ PICSUFFIX="po.o"
+ fi
+ ;;
+ *sunos*) AC_DEFINE(SUNOS4)
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-h,\$@ -G"
+ PICFLAG="-KPIC" # Is this correct for SunOS
+ ;;
+ *bsd*) BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-fPIC"
+ ;;
+ *irix*) AC_DEFINE(IRIX)
+ case "$host_os" in
+ *irix6*) AC_DEFINE(IRIX6)
+ ;;
+ esac
+ ATTEMPT_WRAP32_BUILD=yes
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ if test "${ac_cv_prog_CC}" = "gcc"; then
+ PICFLAG="-fPIC"
+ else
+ PICFLAG="-KPIC"
+ fi
+ ;;
+ *aix*) AC_DEFINE(AIX)
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-bexpall,-bM:SRE,-bnoentry"
+ PICFLAG="-O2 -qmaxmem=6000"
+ ;;
+ *hpux*) AC_DEFINE(HPUX)
+ SHLIBEXT="sl"
+ # Use special PIC flags for the native HP-UX compiler.
+ if test $ac_cv_prog_cc_Ae = yes; then
+ #BLDSHARED="true"
+ LDSHFLAGS="-b -z +h \$@"
+ PICFLAG="+z"
+ fi
+ ;;
+ *qnx*) AC_DEFINE(QNX);;
+ *osf*) AC_DEFINE(OSF1)
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-fPIC"
+ ;;
+ *sco*) AC_DEFINE(SCO);;
+ *unixware*) AC_DEFINE(UNIXWARE)
+ BLDSHARED="true"
+ LDSHFLAGS="-Wl,-soname,\$@ -shared"
+ PICFLAG="-KPIC"
+ ;;
+ *next2*) AC_DEFINE(NEXT2);;
+ *dgux*) AC_CHECK_PROG( ROFF, groff, [groff -etpsR -Tascii -man]);;
+ *sysv4*)
+ case "$host" in
+ *-univel-*) if [ test "$GCC" != yes ]; then
+ AC_DEFINE(HAVE_MEMSET)
+ fi
+ LDSHFLAGS="-G"
+ ;;
+ *mips-sni-sysv4*) AC_DEFINE(RELIANTUNIX);;
+ esac
+ ;;
+ *sysv5*)
+ if [ test "$GCC" != yes ]; then
+ AC_DEFINE(HAVE_MEMSET)
+ fi
+ LDSHFLAGS="-G"
+ ;;
+esac
+AC_MSG_RESULT($BLDSHARED)
+AC_MSG_CHECKING([linker flags for shared libraries])
+AC_MSG_RESULT([$LDSHFLAGS])
+AC_MSG_CHECKING([compiler flags for position-independent code])
+AC_MSG_RESULT([$PICFLAGS])
+
+# this updates our target list if we can build shared libs
+if test $BLDSHARED = true; then
+ LIBSMBCLIENT_SHARED=bin/libsmbclient.$SHLIBEXT
+else
+ LIBSMBCLIENT_SHARED=
+fi
+
+################
+
+AC_CACHE_CHECK([for long long],samba_cv_have_longlong,[
+AC_TRY_RUN([#include <stdio.h>
+main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }],
+samba_cv_have_longlong=yes,samba_cv_have_longlong=no,samba_cv_have_longlong=cross)])
+if test x"$samba_cv_have_longlong" = x"yes"; then
+ AC_DEFINE(HAVE_LONGLONG)
+fi
+
+#
+# Check if the compiler supports the LL prefix on long long integers.
+# AIX needs this.
+
+AC_CACHE_CHECK([for LL suffix on long long integers],samba_cv_compiler_supports_ll, [
+ AC_TRY_COMPILE([#include <stdio.h>],[long long i = 0x8000000000LL],
+ samba_cv_compiler_supports_ll=yes,samba_cv_compiler_supports_ll=no)])
+if test x"$samba_cv_compiler_supports_ll" = x"yes"; then
+ AC_DEFINE(COMPILER_SUPPORTS_LL)
+fi
+
+
+AC_CACHE_CHECK([for 64 bit off_t],samba_cv_SIZEOF_OFF_T,[
+AC_TRY_RUN([#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(off_t) == 8) ? 0 : 1); }],
+samba_cv_SIZEOF_OFF_T=yes,samba_cv_SIZEOF_OFF_T=no,samba_cv_SIZEOF_OFF_T=cross)])
+if test x"$samba_cv_SIZEOF_OFF_T" = x"yes"; then
+ AC_DEFINE(SIZEOF_OFF_T,8)
+fi
+
+AC_CACHE_CHECK([for off64_t],samba_cv_HAVE_OFF64_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
+samba_cv_HAVE_OFF64_T=yes,samba_cv_HAVE_OFF64_T=no,samba_cv_HAVE_OFF64_T=cross)])
+if test x"$samba_cv_HAVE_OFF64_T" = x"yes"; then
+ AC_DEFINE(HAVE_OFF64_T)
+fi
+
+AC_CACHE_CHECK([for 64 bit ino_t],samba_cv_SIZEOF_INO_T,[
+AC_TRY_RUN([#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(ino_t) == 8) ? 0 : 1); }],
+samba_cv_SIZEOF_INO_T=yes,samba_cv_SIZEOF_INO_T=no,samba_cv_SIZEOF_INO_T=cross)])
+if test x"$samba_cv_SIZEOF_INO_T" = x"yes"; then
+ AC_DEFINE(SIZEOF_INO_T,8)
+fi
+
+AC_CACHE_CHECK([for ino64_t],samba_cv_HAVE_INO64_T,[
+AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+main() { struct stat64 st; ino64_t s; if (sizeof(ino_t) == sizeof(ino64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
+samba_cv_HAVE_INO64_T=yes,samba_cv_HAVE_INO64_T=no,samba_cv_HAVE_INO64_T=cross)])
+if test x"$samba_cv_HAVE_INO64_T" = x"yes"; then
+ AC_DEFINE(HAVE_INO64_T)
+fi
+
+AC_CACHE_CHECK([for struct dirent64],samba_cv_HAVE_STRUCT_DIRENT64,[
+AC_TRY_COMPILE([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <dirent.h>],
+[struct dirent64 de;],
+samba_cv_HAVE_STRUCT_DIRENT64=yes,samba_cv_HAVE_STRUCT_DIRENT64=no)])
+if test x"$samba_cv_HAVE_STRUCT_DIRENT64" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_DIRENT64)
+fi
+
+AC_CACHE_CHECK([for unsigned char],samba_cv_HAVE_UNSIGNED_CHAR,[
+AC_TRY_RUN([#include <stdio.h>
+main() { char c; c=250; exit((c > 0)?0:1); }],
+samba_cv_HAVE_UNSIGNED_CHAR=yes,samba_cv_HAVE_UNSIGNED_CHAR=no,samba_cv_HAVE_UNSIGNED_CHAR=cross)])
+if test x"$samba_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then
+ AC_DEFINE(HAVE_UNSIGNED_CHAR)
+fi
+
+AC_CACHE_CHECK([for sin_len in sock],samba_cv_HAVE_SOCK_SIN_LEN,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[struct sockaddr_in sock; sock.sin_len = sizeof(sock);],
+samba_cv_HAVE_SOCK_SIN_LEN=yes,samba_cv_HAVE_SOCK_SIN_LEN=no)])
+if test x"$samba_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then
+ AC_DEFINE(HAVE_SOCK_SIN_LEN)
+fi
+
+AC_CACHE_CHECK([whether seekdir returns void],samba_cv_SEEKDIR_RETURNS_VOID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <dirent.h>
+void seekdir(DIR *d, long loc) { return; }],[return 0;],
+samba_cv_SEEKDIR_RETURNS_VOID=yes,samba_cv_SEEKDIR_RETURNS_VOID=no)])
+if test x"$samba_cv_SEEKDIR_RETURNS_VOID" = x"yes"; then
+ AC_DEFINE(SEEKDIR_RETURNS_VOID)
+fi
+
+AC_CACHE_CHECK([for __FILE__ macro],samba_cv_HAVE_FILE_MACRO,[
+AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __FILE__);],
+samba_cv_HAVE_FILE_MACRO=yes,samba_cv_HAVE_FILE_MACRO=no)])
+if test x"$samba_cv_HAVE_FILE_MACRO" = x"yes"; then
+ AC_DEFINE(HAVE_FILE_MACRO)
+fi
+
+AC_CACHE_CHECK([for __FUNCTION__ macro],samba_cv_HAVE_FUNCTION_MACRO,[
+AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __FUNCTION__);],
+samba_cv_HAVE_FUNCTION_MACRO=yes,samba_cv_HAVE_FUNCTION_MACRO=no)])
+if test x"$samba_cv_HAVE_FUNCTION_MACRO" = x"yes"; then
+ AC_DEFINE(HAVE_FUNCTION_MACRO)
+fi
+
+AC_CACHE_CHECK([if gettimeofday takes tz argument],samba_cv_HAVE_GETTIMEOFDAY_TZ,[
+AC_TRY_RUN([
+#include <sys/time.h>
+#include <unistd.h>
+main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,samba_cv_HAVE_GETTIMEOFDAY_TZ=no,samba_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
+if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
+ AC_DEFINE(HAVE_GETTIMEOFDAY_TZ)
+fi
+
+AC_CACHE_CHECK([for C99 vsnprintf],samba_cv_HAVE_C99_VSNPRINTF,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <stdarg.h>
+void foo(const char *format, ...) {
+ va_list ap;
+ int len;
+ char buf[5];
+
+ va_start(ap, format);
+ len = vsnprintf(0, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(1);
+
+ if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
+
+ exit(0);
+}
+main() { foo("hello"); }
+],
+samba_cv_HAVE_C99_VSNPRINTF=yes,samba_cv_HAVE_C99_VSNPRINTF=no,samba_cv_HAVE_C99_VSNPRINTF=cross)])
+if test x"$samba_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+ AC_DEFINE(HAVE_C99_VSNPRINTF)
+fi
+
+AC_CACHE_CHECK([for broken readdir],samba_cv_HAVE_BROKEN_READDIR,[
+AC_TRY_RUN([#include <sys/types.h>
+#include <dirent.h>
+main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
+if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
+di->d_name[0] == 0) exit(0); exit(1);} ],
+samba_cv_HAVE_BROKEN_READDIR=yes,samba_cv_HAVE_BROKEN_READDIR=no,samba_cv_HAVE_BROKEN_READDIR=cross)])
+if test x"$samba_cv_HAVE_BROKEN_READDIR" = x"yes"; then
+ AC_DEFINE(HAVE_BROKEN_READDIR)
+fi
+
+AC_CACHE_CHECK([for utimbuf],samba_cv_HAVE_UTIMBUF,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utime.h>],
+[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
+samba_cv_HAVE_UTIMBUF=yes,samba_cv_HAVE_UTIMBUF=no,samba_cv_HAVE_UTIMBUF=cross)])
+if test x"$samba_cv_HAVE_UTIMBUF" = x"yes"; then
+ AC_DEFINE(HAVE_UTIMBUF)
+fi
+
+dnl utmp and utmpx come in many flavours
+dnl We need to check for many of them
+dnl But we don't need to do each and every one, because our code uses
+dnl mostly just the utmp (not utmpx) fields.
+
+AC_CHECK_FUNCS(pututline pututxline updwtmp updwtmpx getutmpx)
+
+AC_CACHE_CHECK([for ut_name in utmp],samba_cv_HAVE_UT_UT_NAME,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_name[0] = 'a';],
+samba_cv_HAVE_UT_UT_NAME=yes,samba_cv_HAVE_UT_UT_NAME=no,samba_cv_HAVE_UT_UT_NAME=cross)])
+if test x"$samba_cv_HAVE_UT_UT_NAME" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_NAME)
+fi
+
+AC_CACHE_CHECK([for ut_user in utmp],samba_cv_HAVE_UT_UT_USER,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_user[0] = 'a';],
+samba_cv_HAVE_UT_UT_USER=yes,samba_cv_HAVE_UT_UT_USER=no,samba_cv_HAVE_UT_UT_USER=cross)])
+if test x"$samba_cv_HAVE_UT_UT_USER" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_USER)
+fi
+
+AC_CACHE_CHECK([for ut_id in utmp],samba_cv_HAVE_UT_UT_ID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_id[0] = 'a';],
+samba_cv_HAVE_UT_UT_ID=yes,samba_cv_HAVE_UT_UT_ID=no,samba_cv_HAVE_UT_UT_ID=cross)])
+if test x"$samba_cv_HAVE_UT_UT_ID" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_ID)
+fi
+
+AC_CACHE_CHECK([for ut_host in utmp],samba_cv_HAVE_UT_UT_HOST,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_host[0] = 'a';],
+samba_cv_HAVE_UT_UT_HOST=yes,samba_cv_HAVE_UT_UT_HOST=no,samba_cv_HAVE_UT_UT_HOST=cross)])
+if test x"$samba_cv_HAVE_UT_UT_HOST" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_HOST)
+fi
+
+AC_CACHE_CHECK([for ut_time in utmp],samba_cv_HAVE_UT_UT_TIME,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; time_t t; ut.ut_time = t;],
+samba_cv_HAVE_UT_UT_TIME=yes,samba_cv_HAVE_UT_UT_TIME=no,samba_cv_HAVE_UT_UT_TIME=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TIME" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TIME)
+fi
+
+AC_CACHE_CHECK([for ut_tv in utmp],samba_cv_HAVE_UT_UT_TV,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; struct timeval tv; ut.ut_tv = tv;],
+samba_cv_HAVE_UT_UT_TV=yes,samba_cv_HAVE_UT_UT_TV=no,samba_cv_HAVE_UT_UT_TV=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TV" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TV)
+fi
+
+AC_CACHE_CHECK([for ut_type in utmp],samba_cv_HAVE_UT_UT_TYPE,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_type = 0;],
+samba_cv_HAVE_UT_UT_TYPE=yes,samba_cv_HAVE_UT_UT_TYPE=no,samba_cv_HAVE_UT_UT_TYPE=cross)])
+if test x"$samba_cv_HAVE_UT_UT_TYPE" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_TYPE)
+fi
+
+AC_CACHE_CHECK([for ut_pid in utmp],samba_cv_HAVE_UT_UT_PID,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_pid = 0;],
+samba_cv_HAVE_UT_UT_PID=yes,samba_cv_HAVE_UT_UT_PID=no,samba_cv_HAVE_UT_UT_PID=cross)])
+if test x"$samba_cv_HAVE_UT_UT_PID" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_PID)
+fi
+
+AC_CACHE_CHECK([for ut_exit in utmp],samba_cv_HAVE_UT_UT_EXIT,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_exit.e_exit = 0;],
+samba_cv_HAVE_UT_UT_EXIT=yes,samba_cv_HAVE_UT_UT_EXIT=no,samba_cv_HAVE_UT_UT_EXIT=cross)])
+if test x"$samba_cv_HAVE_UT_UT_EXIT" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_EXIT)
+fi
+
+AC_CACHE_CHECK([for ut_addr in utmp],samba_cv_HAVE_UT_UT_ADDR,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_addr = 0;],
+samba_cv_HAVE_UT_UT_ADDR=yes,samba_cv_HAVE_UT_UT_ADDR=no,samba_cv_HAVE_UT_UT_ADDR=cross)])
+if test x"$samba_cv_HAVE_UT_UT_ADDR" = x"yes"; then
+ AC_DEFINE(HAVE_UT_UT_ADDR)
+fi
+
+if test x$ac_cv_func_pututline = xyes ; then
+ AC_CACHE_CHECK([whether pututline returns pointer],samba_cv_PUTUTLINE_RETURNS_UTMP,[
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmp.h>],
+ [struct utmp utarg; struct utmp *utreturn; utreturn = pututline(&utarg);],
+ samba_cv_PUTUTLINE_RETURNS_UTMP=yes,samba_cv_PUTUTLINE_RETURNS_UTMP=no)])
+ if test x"$samba_cv_PUTUTLINE_RETURNS_UTMP" = x"yes"; then
+ AC_DEFINE(PUTUTLINE_RETURNS_UTMP)
+ fi
+fi
+
+AC_CACHE_CHECK([for ut_syslen in utmpx],samba_cv_HAVE_UX_UT_SYSLEN,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <utmpx.h>],
+[struct utmpx ux; ux.ut_syslen = 0;],
+samba_cv_HAVE_UX_UT_SYSLEN=yes,samba_cv_HAVE_UX_UT_SYSLEN=no,samba_cv_HAVE_UX_UT_SYSLEN=cross)])
+if test x"$samba_cv_HAVE_UX_UT_SYSLEN" = x"yes"; then
+ AC_DEFINE(HAVE_UX_UT_SYSLEN)
+fi
+
+
+#################################################
+# check for libiconv support
+AC_MSG_CHECKING(whether to use libiconv)
+AC_ARG_WITH(libiconv,
+[ --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto) ],
+[ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ CFLAGS="$CFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ AC_CHECK_LIB(iconv, iconv_open)
+ AC_DEFINE_UNQUOTED(WITH_LIBICONV, "${withval}")
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+############
+# check for iconv in libc
+AC_CACHE_CHECK([for working iconv],samba_cv_HAVE_NATIVE_ICONV,[
+AC_TRY_RUN([
+#include <iconv.h>
+main() {
+ iconv_t cd = iconv_open("ASCII", "UCS-2LE");
+ if (cd == 0 || cd == (iconv_t)-1) return -1;
+ return 0;
+}
+],
+samba_cv_HAVE_NATIVE_ICONV=yes,samba_cv_HAVE_NATIVE_ICONV=no,samba_cv_HAVE_NATIVE_ICONV=cross)])
+if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"yes"; then
+ AC_DEFINE(HAVE_NATIVE_ICONV)
+fi
+
+
+AC_CACHE_CHECK([for Linux kernel oplocks],samba_cv_HAVE_KERNEL_OPLOCKS_LINUX,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+main() {
+ int fd = open("/dev/null", O_RDONLY);
+ return fcntl(fd, F_GETLEASE, 0) == -1;
+}
+],
+samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=yes,samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=no,samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=cross)])
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_LINUX" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_OPLOCKS_LINUX)
+fi
+
+AC_CACHE_CHECK([for kernel change notify support],samba_cv_HAVE_KERNEL_CHANGE_NOTIFY,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+main() {
+ exit(fcntl(open("/tmp", O_RDONLY), F_NOTIFY, 0) == -1 ? 1 : 0);
+}
+],
+samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=yes,samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=no,samba_cv_HAVE_KERNEL_CHANGE_NOTIFY=cross)])
+if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_CHANGE_NOTIFY)
+fi
+
+AC_CACHE_CHECK([for kernel share modes],samba_cv_HAVE_KERNEL_SHARE_MODES,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/file.h>
+#ifndef LOCK_MAND
+#define LOCK_MAND 32
+#define LOCK_READ 64
+#endif
+main() {
+ exit(flock(open("/dev/null", O_RDWR), LOCK_MAND|LOCK_READ) != 0);
+}
+],
+samba_cv_HAVE_KERNEL_SHARE_MODES=yes,samba_cv_HAVE_KERNEL_SHARE_MODES=no,samba_cv_HAVE_KERNEL_SHARE_MODES=cross)])
+if test x"$samba_cv_HAVE_KERNEL_SHARE_MODES" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_SHARE_MODES)
+fi
+
+
+
+
+AC_CACHE_CHECK([for IRIX kernel oplock type definitions],samba_cv_HAVE_KERNEL_OPLOCKS_IRIX,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <fcntl.h>],
+[oplock_stat_t t; t.os_state = OP_REVOKE; t.os_dev = 1; t.os_ino = 1;],
+samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=yes,samba_cv_HAVE_KERNEL_OPLOCKS_IRIX=no)])
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS_IRIX" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_OPLOCKS_IRIX)
+fi
+
+AC_CACHE_CHECK([for irix specific capabilities],samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES,[
+AC_TRY_RUN([#include <sys/types.h>
+#include <sys/capability.h>
+main() {
+ cap_t cap;
+ if ((cap = cap_get_proc()) == NULL)
+ exit(1);
+ cap->cap_effective |= CAP_NETWORK_MGT;
+ cap->cap_inheritable |= CAP_NETWORK_MGT;
+ cap_set_proc(cap);
+ exit(0);
+}
+],
+samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=yes,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=no,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=cross)])
+if test x"$samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES" = x"yes"; then
+ AC_DEFINE(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+fi
+
+#
+# Check for int16, uint16, int32 and uint32 in rpc/types.h included from rpc/rpc.h
+# This is *really* broken but some systems (DEC OSF1) do this.... JRA.
+#
+
+AC_CACHE_CHECK([for int16 typedef included by rpc/rpc.h],samba_cv_HAVE_INT16_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int16 testvar;],
+samba_cv_HAVE_INT16_FROM_RPC_RPC_H=yes,samba_cv_HAVE_INT16_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_INT16_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_INT16_FROM_RPC_RPC_H)
+fi
+
+AC_CACHE_CHECK([for uint16 typedef included by rpc/rpc.h],samba_cv_HAVE_UINT16_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[uint16 testvar;],
+samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=yes,samba_cv_HAVE_UINT16_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_UINT16_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_UINT16_FROM_RPC_RPC_H)
+fi
+
+AC_CACHE_CHECK([for int32 typedef included by rpc/rpc.h],samba_cv_HAVE_INT32_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int32 testvar;],
+samba_cv_HAVE_INT32_FROM_RPC_RPC_H=yes,samba_cv_HAVE_INT32_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_INT32_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_INT32_FROM_RPC_RPC_H)
+fi
+
+AC_CACHE_CHECK([for uint32 typedef included by rpc/rpc.h],samba_cv_HAVE_UINT32_FROM_RPC_RPC_H,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[uint32 testvar;],
+samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=yes,samba_cv_HAVE_UINT32_FROM_RPC_RPC_H=no)])
+if test x"$samba_cv_HAVE_UINT32_FROM_RPC_RPC_H" = x"yes"; then
+ AC_DEFINE(HAVE_UINT32_FROM_RPC_RPC_H)
+fi
+
+dnl
+dnl Some systems (SCO) have a problem including
+dnl <prot.h> and <rpc/rpc.h> due to AUTH_ERROR being defined
+dnl as a #define in <prot.h> and as part of an enum
+dnl in <rpc/rpc.h>.
+dnl
+
+AC_CACHE_CHECK([for conflicting AUTH_ERROR define in rpc/rpc.h],samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT,[
+AC_TRY_COMPILE([#include <sys/types.h>
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#endif /* HAVE_SYS_SECURITY_H */
+#if defined(HAVE_RPC_RPC_H)
+#include <rpc/rpc.h>
+#endif],
+[int testvar;],
+samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=no,samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT=yes)])
+if test x"$samba_cv_HAVE_RPC_AUTH_ERROR_CONFLICT" = x"yes"; then
+ AC_DEFINE(HAVE_RPC_AUTH_ERROR_CONFLICT)
+fi
+
+AC_MSG_CHECKING([for test routines])
+AC_TRY_RUN([#include "${srcdir-.}/tests/trivial.c"],
+ AC_MSG_RESULT(yes),
+ AC_MSG_ERROR([cant find test code. Aborting config]),
+ AC_MSG_WARN([cannot run when cross-compiling]))
+
+AC_CACHE_CHECK([for ftruncate extend],samba_cv_HAVE_FTRUNCATE_EXTEND,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/ftruncate.c"],
+ samba_cv_HAVE_FTRUNCATE_EXTEND=yes,samba_cv_HAVE_FTRUNCATE_EXTEND=no,samba_cv_HAVE_FTRUNCATE_EXTEND=cross)])
+if test x"$samba_cv_HAVE_FTRUNCATE_EXTEND" = x"yes"; then
+ AC_DEFINE(HAVE_FTRUNCATE_EXTEND)
+fi
+
+AC_CACHE_CHECK([for AF_LOCAL socket support], samba_cv_HAVE_WORKING_AF_LOCAL, [
+AC_TRY_RUN([#include "${srcdir-.}/tests/unixsock.c"],
+ samba_cv_HAVE_WORKING_AF_LOCAL=yes,
+ samba_cv_HAVE_WORKING_AF_LOCAL=no,
+ samba_cv_HAVE_WORKING_AF_LOCAL=cross)])
+if test x"$samba_cv_HAVE_WORKING_AF_LOCAL" != xno
+then
+ AC_DEFINE(HAVE_WORKING_AF_LOCAL, 1, [Define if you have working AF_LOCAL sockets])
+fi
+
+AC_CACHE_CHECK([for broken getgroups],samba_cv_HAVE_BROKEN_GETGROUPS,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/getgroups.c"],
+ samba_cv_HAVE_BROKEN_GETGROUPS=yes,samba_cv_HAVE_BROKEN_GETGROUPS=no,samba_cv_HAVE_BROKEN_GETGROUPS=cross)])
+if test x"$samba_cv_HAVE_BROKEN_GETGROUPS" = x"yes"; then
+ AC_DEFINE(HAVE_BROKEN_GETGROUPS)
+fi
+
+AC_CACHE_CHECK([whether getpass should be replaced],samba_cv_REPLACE_GETPASS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -I${srcdir-.}/ -I${srcdir-.}/include -I${srcdir-.}/ubiqx -I${srcdir-.}/smbwrapper"
+AC_TRY_COMPILE([
+#define REPLACE_GETPASS 1
+#define NO_CONFIG_H 1
+#define main dont_declare_main
+#include "${srcdir-.}/lib/getsmbpass.c"
+#undef main
+],[],samba_cv_REPLACE_GETPASS=yes,samba_cv_REPLACE_GETPASS=no)
+CPPFLAGS="$SAVE_CPPFLAGS"
+])
+if test x"$samba_cv_REPLACE_GETPASS" = x"yes"; then
+ AC_DEFINE(REPLACE_GETPASS)
+fi
+
+AC_CACHE_CHECK([for broken inet_ntoa],samba_cv_REPLACE_INET_NTOA,[
+AC_TRY_RUN([
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+main() { struct in_addr ip; ip.s_addr = 0x12345678;
+if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
+ strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); }
+exit(1);}],
+ samba_cv_REPLACE_INET_NTOA=yes,samba_cv_REPLACE_INET_NTOA=no,samba_cv_REPLACE_INET_NTOA=cross)])
+if test x"$samba_cv_REPLACE_INET_NTOA" = x"yes"; then
+ AC_DEFINE(REPLACE_INET_NTOA)
+fi
+
+AC_CACHE_CHECK([for secure mkstemp],samba_cv_HAVE_SECURE_MKSTEMP,[
+AC_TRY_RUN([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+main() {
+ struct stat st;
+ char tpl[20]="/tmp/test.XXXXXX";
+ int fd = mkstemp(tpl);
+ if (fd == -1) exit(1);
+ unlink(tpl);
+ if (fstat(fd, &st) != 0) exit(1);
+ if ((st.st_mode & 0777) != 0600) exit(1);
+ exit(0);
+}],
+samba_cv_HAVE_SECURE_MKSTEMP=yes,
+samba_cv_HAVE_SECURE_MKSTEMP=no,
+samba_cv_HAVE_SECURE_MKSTEMP=cross)])
+if test x"$samba_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
+ AC_DEFINE(HAVE_SECURE_MKSTEMP)
+fi
+
+AC_CACHE_CHECK([for sysconf(_SC_NGROUPS_MAX)],samba_cv_SYSCONF_SC_NGROUPS_MAX,[
+AC_TRY_RUN([#include <unistd.h>
+main() { exit(sysconf(_SC_NGROUPS_MAX) == -1 ? 1 : 0); }],
+samba_cv_SYSCONF_SC_NGROUPS_MAX=yes,samba_cv_SYSCONF_SC_NGROUPS_MAX=no,samba_cv_SYSCONF_SC_NGROUPS_MAX=cross)])
+if test x"$samba_cv_SYSCONF_SC_NGROUPS_MAX" = x"yes"; then
+ AC_DEFINE(SYSCONF_SC_NGROUPS_MAX)
+fi
+
+AC_CACHE_CHECK([for root],samba_cv_HAVE_ROOT,[
+AC_TRY_RUN([main() { exit(getuid() != 0); }],
+ samba_cv_HAVE_ROOT=yes,samba_cv_HAVE_ROOT=no,samba_cv_HAVE_ROOT=cross)])
+if test x"$samba_cv_HAVE_ROOT" = x"yes"; then
+ AC_DEFINE(HAVE_ROOT)
+else
+ AC_MSG_WARN(running as non-root will disable some tests)
+fi
+
+##################
+# look for a method of finding the list of network interfaces
+iface=no;
+AC_CACHE_CHECK([for iface AIX],samba_cv_HAVE_IFACE_AIX,[
+AC_TRY_RUN([
+#define HAVE_IFACE_AIX 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"],
+ samba_cv_HAVE_IFACE_AIX=yes,samba_cv_HAVE_IFACE_AIX=no,samba_cv_HAVE_IFACE_AIX=cross)])
+if test x"$samba_cv_HAVE_IFACE_AIX" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_AIX)
+fi
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifconf],samba_cv_HAVE_IFACE_IFCONF,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFCONF 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"],
+ samba_cv_HAVE_IFACE_IFCONF=yes,samba_cv_HAVE_IFACE_IFCONF=no,samba_cv_HAVE_IFACE_IFCONF=cross)])
+if test x"$samba_cv_HAVE_IFACE_IFCONF" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF)
+fi
+fi
+
+if test $iface = no; then
+AC_CACHE_CHECK([for iface ifreq],samba_cv_HAVE_IFACE_IFREQ,[
+AC_TRY_RUN([
+#define HAVE_IFACE_IFREQ 1
+#define AUTOCONF_TEST 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/interfaces.c"],
+ samba_cv_HAVE_IFACE_IFREQ=yes,samba_cv_HAVE_IFACE_IFREQ=no,samba_cv_HAVE_IFACE_IFREQ=cross)])
+if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then
+ iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ)
+fi
+fi
+
+
+################################################
+# look for a method of setting the effective uid
+seteuid=no;
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setresuid],samba_cv_USE_SETRESUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETRESUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETRESUID=yes,samba_cv_USE_SETRESUID=no,samba_cv_USE_SETRESUID=cross)])
+if test x"$samba_cv_USE_SETRESUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETRESUID)
+fi
+fi
+
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setreuid],samba_cv_USE_SETREUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETREUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETREUID=yes,samba_cv_USE_SETREUID=no,samba_cv_USE_SETREUID=cross)])
+if test x"$samba_cv_USE_SETREUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETREUID)
+fi
+fi
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for seteuid],samba_cv_USE_SETEUID,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETEUID 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETEUID=yes,samba_cv_USE_SETEUID=no,samba_cv_USE_SETEUID=cross)])
+if test x"$samba_cv_USE_SETEUID" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETEUID)
+fi
+fi
+
+if test $seteuid = no; then
+AC_CACHE_CHECK([for setuidx],samba_cv_USE_SETUIDX,[
+AC_TRY_RUN([
+#define AUTOCONF_TEST 1
+#define USE_SETUIDX 1
+#include "confdefs.h"
+#include "${srcdir-.}/lib/util_sec.c"],
+ samba_cv_USE_SETUIDX=yes,samba_cv_USE_SETUIDX=no,samba_cv_USE_SETUIDX=cross)])
+if test x"$samba_cv_USE_SETUIDX" = x"yes"; then
+ seteuid=yes;AC_DEFINE(USE_SETUIDX)
+fi
+fi
+
+
+AC_CACHE_CHECK([for working mmap],samba_cv_HAVE_MMAP,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/shared_mmap.c"],
+ samba_cv_HAVE_MMAP=yes,samba_cv_HAVE_MMAP=no,samba_cv_HAVE_MMAP=cross)])
+if test x"$samba_cv_HAVE_MMAP" = x"yes"; then
+ AC_DEFINE(HAVE_MMAP)
+fi
+
+AC_CACHE_CHECK([for ftruncate needs root],samba_cv_FTRUNCATE_NEEDS_ROOT,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/ftruncroot.c"],
+ samba_cv_FTRUNCATE_NEEDS_ROOT=yes,samba_cv_FTRUNCATE_NEEDS_ROOT=no,samba_cv_FTRUNCATE_NEEDS_ROOT=cross)])
+if test x"$samba_cv_FTRUNCATE_NEEDS_ROOT" = x"yes"; then
+ AC_DEFINE(FTRUNCATE_NEEDS_ROOT)
+fi
+
+AC_CACHE_CHECK([for fcntl locking],samba_cv_HAVE_FCNTL_LOCK,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/fcntl_lock.c"],
+ samba_cv_HAVE_FCNTL_LOCK=yes,samba_cv_HAVE_FCNTL_LOCK=no,samba_cv_HAVE_FCNTL_LOCK=cross)])
+if test x"$samba_cv_HAVE_FCNTL_LOCK" = x"yes"; then
+ AC_DEFINE(HAVE_FCNTL_LOCK)
+fi
+
+AC_CACHE_CHECK([for broken (glibc2.1/x86) 64 bit fcntl locking],samba_cv_HAVE_BROKEN_FCNTL64_LOCKS,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/fcntl_lock64.c"],
+ samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=yes,samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=no,samba_cv_HAVE_BROKEN_FCNTL64_LOCKS=cross)])
+if test x"$samba_cv_HAVE_BROKEN_FCNTL64_LOCKS" = x"yes"; then
+ AC_DEFINE(HAVE_BROKEN_FCNTL64_LOCKS)
+
+else
+
+dnl
+dnl Don't check for 64 bit fcntl locking if we know that the
+dnl glibc2.1 broken check has succeeded.
+dnl
+
+ AC_CACHE_CHECK([for 64 bit fcntl locking],samba_cv_HAVE_STRUCT_FLOCK64,[
+ AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+main() { struct flock64 fl64;
+#if defined(F_SETLKW64) && defined(F_SETLK64) && defined(F_GETLK64)
+exit(0);
+#else
+exit(1);
+#endif
+}],
+ samba_cv_HAVE_STRUCT_FLOCK64=yes,samba_cv_HAVE_STRUCT_FLOCK64=no,samba_cv_HAVE_STRUCT_FLOCK64=cross)])
+
+ if test x"$samba_cv_HAVE_STRUCT_FLOCK64" = x"yes"; then
+ AC_DEFINE(HAVE_STRUCT_FLOCK64)
+ fi
+fi
+
+
+case "$host_os" in
+*linux*)
+AC_CACHE_CHECK([for broken RedHat 7.2 system header files],samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[
+AC_TRY_COMPILE([
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+],[int i;],
+ samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no,samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes)])
+if test x"$samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then
+ AC_DEFINE(BROKEN_REDHAT_7_SYSTEM_HEADERS)
+fi
+;;
+esac
+
+AC_CACHE_CHECK([for broken nisplus include files],samba_cv_BROKEN_NISPLUS_INCLUDE_FILES,[
+AC_TRY_COMPILE([#include <sys/acl.h>
+#if defined(HAVE_RPCSVC_NIS_H)
+#include <rpcsvc/nis.h>
+#endif],
+[int i;],
+samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=no,samba_cv_BROKEN_NISPLUS_INCLUDE_FILES=yes)])
+if test x"$samba_cv_BROKEN_NISPLUS_INCLUDE_FILES" = x"yes"; then
+ AC_DEFINE(BROKEN_NISPLUS_INCLUDE_FILES)
+fi
+
+
+#################################################
+# check for smbwrapper support
+AC_MSG_CHECKING(whether to use smbwrapper)
+AC_ARG_WITH(smbwrapper,
+[ --with-smbwrapper Include SMB wrapper support (default=no) ],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SMBWRAPPER)
+ WRAP="bin/smbsh bin/smbwrapper.$SHLIBEXT"
+
+ if test x$ATTEMPT_WRAP32_BUILD = x; then
+ WRAP32=""
+ else
+ WRAP32=bin/smbwrapper.32.$SHLIBEXT
+ fi
+
+# Conditions under which smbwrapper should not be built.
+
+ if test x$PICFLAG = x; then
+ echo No support for PIC code - disabling smbwrapper and smbsh
+ WRAP=""
+ WRAP32=""
+ elif test x$ac_cv_func_syscall = xno; then
+ AC_MSG_RESULT([No syscall() -- disabling smbwrapper and smbsh])
+ WRAP=""
+ WRAP32=""
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for AFS clear-text auth support
+AC_MSG_CHECKING(whether to use AFS clear-text auth)
+AC_ARG_WITH(afs,
+[ --with-afs Include AFS clear-text auth support (default=no) ],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_AFS)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+#################################################
+# check for the DFS clear-text auth system
+AC_MSG_CHECKING(whether to use DFS clear-text auth)
+AC_ARG_WITH(dfs,
+[ --with-dce-dfs Include DCE/DFS clear-text auth support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_DFS)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+#################################################
+# see if this box has the RedHat location for kerberos
+AC_MSG_CHECKING(for /usr/kerberos)
+if test -d /usr/kerberos; then
+ LDFLAGS="$LDFLAGS -L/usr/kerberos/lib"
+ CFLAGS="$CFLAGS -I/usr/kerberos/include"
+ CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include"
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+#################################################
+# check for location of Kerberos 5 install
+AC_MSG_CHECKING(for kerberos 5 install path)
+AC_ARG_WITH(krb5,
+[ --with-krb5=base-dir Locate Kerberos 5 support (default=/usr)],
+[ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ LIBS="$LIBS -lkrb5"
+ CFLAGS="$CFLAGS -I$withval/include"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+# now check for krb5.h. Some systems have the libraries without the headers!
+# note that this check is done here to allow for different kerberos
+# include paths
+AC_CHECK_HEADERS(krb5.h)
+
+# now check for gssapi headers. This is also done here to allow for
+# different kerberos include paths
+AC_CHECK_HEADERS(gssapi/gssapi_generic.h gssapi/gssapi.h)
+
+##################################################################
+# we might need the k5crypto and com_err libraries on some systems
+AC_CHECK_LIB(com_err, _et_list, [LIBS="$LIBS -lcom_err"])
+AC_CHECK_LIB(k5crypto, krb5_encrypt_data, [LIBS="$LIBS -lk5crypto"])
+AC_CHECK_LIB(gssapi_krb5, gss_import_name, [LIBS="$LIBS -lgssapi_krb5"])
+
+
+########################################################
+# now see if we can find the krb5 libs in standard paths
+# or as specified above
+AC_CHECK_LIB(krb5, krb5_mk_req_extended, [LIBS="$LIBS -lkrb5";
+ AC_DEFINE(HAVE_KRB5)])
+
+
+##################################################################
+# we might need the lber lib on some systems. To avoid link errors
+# this test must be before the libldap test
+AC_CHECK_LIB(lber, ber_scanf, [LIBS="$LIBS -llber"])
+
+########################################################
+# now see if we can find the ldap libs in standard paths
+if test x$have_ldap != xyes; then
+AC_CHECK_LIB(ldap, ldap_open, [LIBS="$LIBS -lldap";
+ AC_DEFINE(HAVE_LDAP)])
+fi
+
+
+#################################################
+# check for automount support
+AC_MSG_CHECKING(whether to use AUTOMOUNT)
+AC_ARG_WITH(automount,
+[ --with-automount Include AUTOMOUNT support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_AUTOMOUNT)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for smbmount support
+AC_MSG_CHECKING(whether to use SMBMOUNT)
+AC_ARG_WITH(smbmount,
+[ --with-smbmount Include SMBMOUNT (Linux only) support (default=no)],
+[ case "$withval" in
+ yes)
+ case "$host_os" in
+ *linux*)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SMBMOUNT)
+ MPROGS="bin/smbmount bin/smbmnt bin/smbumount"
+ ;;
+ *)
+ AC_MSG_ERROR(not on a linux system!)
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ MPROGS=
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+ MPROGS=
+)
+
+
+#################################################
+# check for a PAM clear-text auth, accounts, password and session support
+with_pam_for_crypt=no
+AC_MSG_CHECKING(whether to use PAM)
+AC_ARG_WITH(pam,
+[ --with-pam Include PAM support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_PAM)
+ LIBS="$LIBS -lpam"
+ with_pam_for_crypt=yes
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+# we can't build a pam module if we don't have pam.
+AC_CHECK_LIB(pam, pam_get_data, [AC_DEFINE(HAVE_LIBPAM)])
+
+#################################################
+# check for pam_smbpass support
+AC_MSG_CHECKING(whether to use pam_smbpass)
+AC_ARG_WITH(pam_smbpass,
+[ --with-pam_smbpass Build a PAM module to allow other applications to use our smbpasswd file (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+
+# Conditions under which pam_smbpass should not be built.
+
+ if test x$PICFLAG = x; then
+ AC_MSG_RESULT([No support for PIC code - disabling pam_smbpass])
+ PAM_MOD=""
+ elif test x$ac_cv_lib_pam_pam_get_data = xno; then
+ AC_MSG_RESULT([No libpam found -- disabling pam_smbpass])
+ PAM_MOD=""
+ else
+ PAM_MOD="bin/pam_smbpass.so"
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+###############################################
+# test for where we get crypt() from, but only
+# if not using PAM
+if test $with_pam_for_crypt = no; then
+AC_CHECK_FUNCS(crypt)
+if test x"$ac_cv_func_crypt" = x"no"; then
+ AC_CHECK_LIB(crypt, crypt, [LIBS="$LIBS -lcrypt";
+ AC_DEFINE(HAVE_CRYPT)])
+fi
+fi
+
+##
+## moved after the check for -lcrypt in order to
+## ensure that the necessary libraries are included
+## check checking for truncated salt. Wrapped by the
+## $with_pam_for_crypt variable as above --jerry
+##
+if test $with_pam_for_crypt = no; then
+AC_CACHE_CHECK([for a crypt that needs truncated salt],samba_cv_HAVE_TRUNCATED_SALT,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/crypttest.c"],
+ samba_cv_HAVE_TRUNCATED_SALT=no,samba_cv_HAVE_TRUNCATED_SALT=yes,samba_cv_HAVE_TRUNCATED_SALT=cross)])
+if test x"$samba_cv_HAVE_TRUNCATED_SALT" = x"yes"; then
+ AC_DEFINE(HAVE_TRUNCATED_SALT)
+fi
+fi
+
+
+
+########################################################################################
+##
+## TESTS FOR SAM BACKENDS. KEEP THESE GROUPED TOGETHER
+##
+########################################################################################
+
+## set the with_smbpasswd_sam as the default
+with_smbpasswd_sam=yes
+
+
+#################################################
+# check for a TDB password database
+AC_MSG_CHECKING(whether to use TDB SAM database)
+AC_ARG_WITH(tdbsam,
+[ --with-tdbsam Include experimental TDB SAM support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_TDB_SAM)
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for a LDAP password database
+AC_MSG_CHECKING(whether to use LDAP SAM database)
+AC_ARG_WITH(ldapsam,
+[ --with-ldapsam Include experimental LDAP SAM support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_LDAP_SAM)
+ LIBS="-lldap -llber $LIBS"
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for a NISPLUS password database
+AC_MSG_CHECKING(whether to use NISPLUS SAM database)
+AC_ARG_WITH(nisplussam,
+[ --with-nisplussam Include NISPLUS SAM support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_NISPLUS_SAM)
+ with_smbpasswd_sam=no
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+################################################
+# This test should come last because the
+# smbpasswd SAM is only used if another format
+# has not been defined
+AC_MSG_CHECKING(whether to use traditional smbpasswd file)
+if test $with_smbpasswd_sam = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SMBPASSWD_SAM)
+else
+ AC_MSG_RESULT(no)
+fi
+
+########################################################################################
+##
+## END OF TESTS FOR SAM BACKENDS.
+##
+########################################################################################
+
+#################################################
+# check for a NISPLUS_HOME support
+AC_MSG_CHECKING(whether to use NISPLUS_HOME)
+AC_ARG_WITH(nisplus-home,
+[ --with-nisplus-home Include NISPLUS_HOME support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_NISPLUS_HOME)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for the secure socket layer
+AC_MSG_CHECKING(whether to use SSL)
+AC_ARG_WITH(ssl,
+[ --with-ssl Include SSL support (default=no)
+ --with-sslinc=DIR Where the SSL includes are (defaults to /usr/local/ssl/include)
+ --with-ssllib=DIR Where the SSL libraries are (defaults to /usr/local/ssl/lib)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SSL)
+ withval="/usr/local/ssl" # default
+
+ if test "${with_sslinc+set}" = set; then
+
+ withval="$with_sslinc"
+ case "$withval" in
+ yes|no)
+ echo "configure: warning: --with-sslinc called without argument - will use default" 1>&w
+ CFLAGS="-I/usr/local/ssl/include $CFLAGS"
+ ;;
+ * )
+ CFLAGS="-I${withval} $CFLAGS"
+ ;;
+ esac
+
+ else
+
+ CFLAGS="-I/usr/local/ssl/include $CFLAGS"
+
+ fi
+
+ if test "${with_ssllib+set}" = set; then
+
+ withval="$with_ssllib"
+ case "$withval" in
+ yes|no)
+ echo "configure: warning: --with-ssllib called without argument - will use default" 1>&w
+ LDFLAGS="-L/usr/local/ssl/lib $LDFLAGS"
+ ;;
+ * )
+ LDFLAGS="-L${withval}/lib $LDFLAGS"
+ ;;
+ esac
+
+ else
+
+ LDFLAGS="-L/usr/local/ssl/lib $LDFLAGS"
+
+ fi
+
+ LIBS="-lssl -lcrypto $LIBS"
+
+# if test ! -d ${withval}; then
+# echo "configure: error: called with --with-ssl, but ssl base directory ${withval} does not exist or is not a directory. Aborting config" 1>&2
+# exit 1
+# fi
+
+ CFLAGS="-DHAVE_CRYPT_DECL $CFLAGS" # Damn, SSLeay defines its own
+
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for syslog logging
+AC_MSG_CHECKING(whether to use syslog logging)
+AC_ARG_WITH(syslog,
+[ --with-syslog Include experimental SYSLOG support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SYSLOG)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for a shared memory profiling support
+AC_MSG_CHECKING(whether to use profiling)
+AC_ARG_WITH(profiling-data,
+[ --with-profiling-data Include gathering source code profile information (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_PROFILE)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+#################################################
+# check for experimental disk-quotas support
+QUOTAOBJS=smbd/noquotas.o
+
+AC_MSG_CHECKING(whether to support disk-quotas)
+AC_ARG_WITH(quotas,
+[ --with-quotas Include experimental disk-quota support (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ case "$host_os" in
+ *linux*)
+ # Check for kernel 2.4.x quota braindamage...
+ AC_CACHE_CHECK([for linux 2.4.x quota braindamage..],samba_cv_linux_2_4_quota_braindamage, [
+ AC_TRY_COMPILE([#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <linux/quota.h>
+#include <mntent.h>
+#include <linux/unistd.h>],[struct mem_dqblk D;],
+ samba_cv_linux_2_4_quota_braindamage=yes,samba_cv_linux_2_4_quota_braindamage=no)])
+if test x"$samba_cv_linux_2_4_quota_braindamage" = x"yes"; then
+ AC_DEFINE(LINUX_QUOTAS_2)
+else
+ AC_DEFINE(LINUX_QUOTAS_1)
+fi
+ ;;
+ *)
+ ;;
+ esac
+ QUOTAOBJS=smbd/quotas.o
+ AC_DEFINE(WITH_QUOTAS)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+AC_SUBST(QUOTAOBJS)
+
+#################################################
+# check for experimental utmp accounting
+
+AC_MSG_CHECKING(whether to support utmp accounting)
+AC_ARG_WITH(utmp,
+[ --with-utmp Include experimental utmp accounting (default=no)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_UTMP)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# set private directory location
+AC_ARG_WITH(privatedir,
+[ --with-privatedir=DIR Where to put smbpasswd ($ac_default_prefix/private)],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-privatedir called without argument - will use default])
+ privatedir='${prefix}/private'
+ ;;
+ * )
+ privatedir="$withval"
+ ;;
+ esac
+ AC_SUBST(privatedir)],
+ [privatedir='${prefix}/private'
+ AC_SUBST(privatedir)]
+)
+
+#################################################
+# set lock directory location
+AC_ARG_WITH(lockdir,
+[ --with-lockdir=DIR Where to put lock files ($ac_default_prefix/var/locks)],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody calls it without argument
+ #
+ AC_MSG_WARN([--with-lockdir called without argument - will use default])
+ lockdir='$(VARDIR)/locks'
+ ;;
+ * )
+ lockdir="$withval"
+ ;;
+ esac
+ AC_SUBST(lockdir)],
+ [lockdir='$(VARDIR)/locks'
+ AC_SUBST(lockdir)]
+)
+
+#################################################
+# set SWAT directory location
+AC_ARG_WITH(swatdir,
+[ --with-swatdir=DIR Where to put SWAT files ($ac_default_prefix/swat)],
+[ case "$withval" in
+ yes|no)
+ #
+ # Just in case anybody does it
+ #
+ AC_MSG_WARN([--with-swatdir called without argument - will use default])
+ swatdir='${prefix}/swat'
+ ;;
+ * )
+ swatdir="$withval"
+ ;;
+ esac
+ AC_SUBST(swatdir)],
+ [swatdir='${prefix}/swat'
+ AC_SUBST(swatdir)]
+)
+
+#################################################
+# choose native language(s) of man pages
+AC_MSG_CHECKING(chosen man pages' language(s))
+AC_ARG_WITH(manpages-langs,
+[ --with-manpages-langs={en,ja,pl} Choose man pages' language(s). (en)],
+[ case "$withval" in
+ yes|no)
+ AC_MSG_WARN(--with-manpages-langs called without argument - will use default)
+ manlangs="en"
+ ;;
+ *)
+ manlangs="$withval"
+ ;;
+ esac
+
+ AC_MSG_RESULT($manlangs)
+ manlangs=`echo $manlangs | sed "s/,/ /"` # replacing commas with spaces to produce a list
+ AC_SUBST(manlangs)],
+
+ [manlangs="en"
+ AC_MSG_RESULT($manlangs)
+ AC_SUBST(manlangs)]
+)
+
+#################################################
+# these tests are taken from the GNU fileutils package
+AC_CHECKING(how to get filesystem space usage)
+space=no
+
+# Test for statvfs64.
+if test $space = no; then
+ # SVR4
+ AC_CACHE_CHECK([statvfs64 function (SVR4)], fu_cv_sys_stat_statvfs64,
+ [AC_TRY_RUN([
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ main ()
+ {
+ struct statvfs64 fsd;
+ exit (statvfs64 (".", &fsd));
+ }],
+ fu_cv_sys_stat_statvfs64=yes,
+ fu_cv_sys_stat_statvfs64=no,
+ fu_cv_sys_stat_statvfs64=cross)])
+ if test $fu_cv_sys_stat_statvfs64 = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATVFS64)
+ fi
+fi
+
+# Perform only the link test since it seems there are no variants of the
+# statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs)
+# because that got a false positive on SCO OSR5. Adding the declaration
+# of a `struct statvfs' causes this test to fail (as it should) on such
+# systems. That system is reported to work fine with STAT_STATFS4 which
+# is what it gets when this test fails.
+if test $space = no; then
+ # SVR4
+ AC_CACHE_CHECK([statvfs function (SVR4)], fu_cv_sys_stat_statvfs,
+ [AC_TRY_LINK([#include <sys/types.h>
+#include <sys/statvfs.h>],
+ [struct statvfs fsd; statvfs (0, &fsd);],
+ fu_cv_sys_stat_statvfs=yes,
+ fu_cv_sys_stat_statvfs=no)])
+ if test $fu_cv_sys_stat_statvfs = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATVFS)
+ fi
+fi
+
+if test $space = no; then
+ # DEC Alpha running OSF/1
+ AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)])
+ AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1,
+ [AC_TRY_RUN([
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_fsize = 0;
+ exit (statfs (".", &fsd, sizeof (struct statfs)));
+ }],
+ fu_cv_sys_stat_statfs3_osf1=yes,
+ fu_cv_sys_stat_statfs3_osf1=no,
+ fu_cv_sys_stat_statfs3_osf1=no)])
+ AC_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1)
+ if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATFS3_OSF1)
+ fi
+fi
+
+if test $space = no; then
+# AIX
+ AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl
+member (AIX, 4.3BSD)])
+ AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize,
+ [AC_TRY_RUN([
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_bsize = 0;
+ exit (statfs (".", &fsd));
+ }],
+ fu_cv_sys_stat_statfs2_bsize=yes,
+ fu_cv_sys_stat_statfs2_bsize=no,
+ fu_cv_sys_stat_statfs2_bsize=no)])
+ AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize)
+ if test $fu_cv_sys_stat_statfs2_bsize = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATFS2_BSIZE)
+ fi
+fi
+
+if test $space = no; then
+# SVR3
+ AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)])
+ AC_CACHE_VAL(fu_cv_sys_stat_statfs4,
+ [AC_TRY_RUN([#include <sys/types.h>
+#include <sys/statfs.h>
+ main ()
+ {
+ struct statfs fsd;
+ exit (statfs (".", &fsd, sizeof fsd, 0));
+ }],
+ fu_cv_sys_stat_statfs4=yes,
+ fu_cv_sys_stat_statfs4=no,
+ fu_cv_sys_stat_statfs4=no)])
+ AC_MSG_RESULT($fu_cv_sys_stat_statfs4)
+ if test $fu_cv_sys_stat_statfs4 = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATFS4)
+ fi
+fi
+
+if test $space = no; then
+# 4.4BSD and NetBSD
+ AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl
+member (4.4BSD and NetBSD)])
+ AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize,
+ [AC_TRY_RUN([#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+ main ()
+ {
+ struct statfs fsd;
+ fsd.f_fsize = 0;
+ exit (statfs (".", &fsd));
+ }],
+ fu_cv_sys_stat_statfs2_fsize=yes,
+ fu_cv_sys_stat_statfs2_fsize=no,
+ fu_cv_sys_stat_statfs2_fsize=no)])
+ AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize)
+ if test $fu_cv_sys_stat_statfs2_fsize = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATFS2_FSIZE)
+ fi
+fi
+
+if test $space = no; then
+ # Ultrix
+ AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)])
+ AC_CACHE_VAL(fu_cv_sys_stat_fs_data,
+ [AC_TRY_RUN([#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_FS_TYPES_H
+#include <sys/fs_types.h>
+#endif
+ main ()
+ {
+ struct fs_data fsd;
+ /* Ultrix's statfs returns 1 for success,
+ 0 for not mounted, -1 for failure. */
+ exit (statfs (".", &fsd) != 1);
+ }],
+ fu_cv_sys_stat_fs_data=yes,
+ fu_cv_sys_stat_fs_data=no,
+ fu_cv_sys_stat_fs_data=no)])
+ AC_MSG_RESULT($fu_cv_sys_stat_fs_data)
+ if test $fu_cv_sys_stat_fs_data = yes; then
+ space=yes
+ AC_DEFINE(STAT_STATFS2_FS_DATA)
+ fi
+fi
+
+#
+# As a gating factor for large file support, in order to
+# use <4GB files we must have the following minimal support
+# available.
+# long long, and a 64 bit off_t or off64_t.
+# If we don't have all of these then disable large
+# file support.
+#
+AC_MSG_CHECKING([if large file support can be enabled])
+AC_TRY_COMPILE([
+#if defined(HAVE_LONGLONG) && (defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8)))
+#include <sys/types.h>
+#else
+__COMPILE_ERROR_
+#endif
+],
+[int i],
+samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=yes,samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=no)
+if test x"$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT" = x"yes"; then
+ AC_DEFINE(HAVE_EXPLICIT_LARGEFILE_SUPPORT)
+fi
+AC_MSG_RESULT([$samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT])
+
+AC_ARG_WITH(spinlocks,
+[ --with-spinlocks Use spin locks instead of fcntl locks (default=no) ])
+if test "x$with_spinlocks" = "xyes"; then
+ AC_DEFINE(USE_SPINLOCKS)
+
+ case "$host_cpu" in
+ sparc)
+ AC_DEFINE(SPARC_SPINLOCKS)
+ ;;
+
+ i386|i486|i586|i686)
+ AC_DEFINE(INTEL_SPINLOCKS)
+ ;;
+
+ mips)
+ AC_DEFINE(MIPS_SPINLOCKS)
+ ;;
+
+ powerpc)
+ AC_DEFINE(POWERPC_SPINLOCKS)
+ ;;
+ esac
+fi
+
+#################################################
+# check for ACL support
+
+AC_MSG_CHECKING(whether to support ACLs)
+AC_ARG_WITH(acl-support,
+[ --with-acl-support Include ACL support (default=no)],
+[ case "$withval" in
+ yes)
+
+ case "$host_os" in
+ *sysv5*)
+ AC_MSG_RESULT(Using UnixWare ACLs)
+ AC_DEFINE(HAVE_UNIXWARE_ACLS)
+ ;;
+ *solaris*)
+ AC_MSG_RESULT(Using solaris ACLs)
+ AC_DEFINE(HAVE_SOLARIS_ACLS)
+ ;;
+ *hpux*)
+ AC_MSG_RESULT(Using HPUX ACLs)
+ AC_DEFINE(HAVE_HPUX_ACLS)
+ ;;
+ *irix*)
+ AC_MSG_RESULT(Using IRIX ACLs)
+ AC_DEFINE(HAVE_IRIX_ACLS)
+ ;;
+ *aix*)
+ AC_MSG_RESULT(Using AIX ACLs)
+ AC_DEFINE(HAVE_AIX_ACLS)
+ ;;
+ *osf*)
+ AC_MSG_RESULT(Using Tru64 ACLs)
+ AC_DEFINE(HAVE_TRU64_ACLS)
+ LIBS="$LIBS -lpacl"
+ ;;
+ *)
+ AC_CHECK_LIB(acl,acl_get_file)
+ AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
+ AC_TRY_LINK([#include <sys/types.h>
+#include <sys/acl.h>],
+[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
+samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
+ AC_MSG_RESULT(Using posix ACLs)
+ AC_DEFINE(HAVE_POSIX_ACLS)
+ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
+ AC_TRY_LINK([#include <sys/types.h>
+#include <sys/acl.h>],
+[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
+samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
+ AC_DEFINE(HAVE_ACL_GET_PERM_NP)
+ fi
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ AC_DEFINE(HAVE_NO_ACLS)
+ ;;
+ esac ],
+ AC_DEFINE(HAVE_NO_ACLS)
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# Check whether winbind is supported on this platform. If so we need to
+# build and install client programs (WINBIND_TARGETS), sbin programs
+# (WINBIND_STARGETS) and shared libraries (WINBIND_LTARGETS).
+
+AC_MSG_CHECKING(whether to build winbind)
+
+# Initially, the value of $host_os decides whether winbind is supported
+
+case "$host_os" in
+ *linux*|*solaris*)
+ HAVE_WINBIND=yes
+ ;;
+ *)
+ HAVE_WINBIND=no
+ winbind_no_reason=", unsupported on $host_os"
+ ;;
+esac
+
+# Check the setting of --with-winbindd
+
+AC_ARG_WITH(winbind,
+[ --with-winbind Build winbind (default, if supported by OS)],
+[
+ case "$withval" in
+ yes)
+ HAVE_WINBIND=yes
+ ;;
+ no)
+ HAVE_WINBIND=no
+ winbind_reason=""
+ ;;
+ esac ],
+)
+
+# We need unix domain sockets for winbind
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+ if test x"$samba_cv_unixsocket" = x"no"; then
+ winbind_no_reason=", no unix domain socket support on $host_os"
+ HAVE_WINBIND=no
+ fi
+fi
+
+# Display test results
+
+if test x"$HAVE_WINBIND" = x"yes"; then
+
+ AC_MSG_RESULT(yes)
+
+ WINBIND_TARGETS="bin/wbinfo"
+ WINBIND_STARGETS="bin/winbindd"
+ WINBIND_LTARGETS="nsswitch/libnss_winbind.so"
+ case "$with_pam" in
+ yes)
+ WINBIND_PAM_TARGETS="nsswitch/pam_winbind.so"
+ ;;
+ esac
+else
+ AC_MSG_RESULT(no$winbind_no_reason)
+
+ WINBIND_TARGETS=""
+ WINBIND_STARGETS=""
+ WINBIND_LTARGETS=""
+ WINBIND_PAM_PROGS=""
+fi
+
+# Substitution time!
+
+AC_SUBST(WINBIND_TARGETS)
+AC_SUBST(WINBIND_STARGETS)
+AC_SUBST(WINBIND_LTARGETS)
+AC_SUBST(WINBIND_PAM_TARGETS)
+
+#################################################
+# Check to see if we should use the included popt
+
+AC_ARG_WITH(included-popt,
+[ --with-included-popt use bundled popt library, not from system],
+[
+ case "$withval" in
+ yes)
+ INCLUDED_POPT=yes
+ ;;
+ no)
+ INCLUDED_POPT=no
+ ;;
+ esac ],
+)
+if test x"$INCLUDED_POPT" != x"yes"; then
+ AC_CHECK_LIB(popt, poptGetContext,
+ INCLUDED_POPT=no, INCLUDED_POPT=yes)
+fi
+
+AC_MSG_CHECKING(whether to use included popt)
+if test x"$INCLUDED_POPT" = x"yes"; then
+ AC_MSG_RESULT($srcdir/popt)
+ BUILD_POPT='$(POPT_OBJS)'
+ FLAGS1="-I$srcdir/popt"
+else
+ AC_MSG_RESULT(no)
+ LIBS="$LIBS -lpopt"
+fi
+AC_SUBST(BUILD_POPT)
+AC_SUBST(FLAGS1)
+
+#################################################
+# final configure stuff
+
+echo "checking configure summary"
+AC_TRY_RUN([#include "${srcdir-.}/tests/summary.c"],
+ echo "configure OK";,
+ AC_MSG_ERROR([summary failure. Aborting config]),:)
+
+builddir=`pwd`
+AC_SUBST(builddir)
+
+AC_OUTPUT(include/stamp-h Makefile)
diff --git a/source/configure.nodebug.developer b/source/configure.nodebug.developer
new file mode 100755
index 00000000000..65e21b4bdf4
--- /dev/null
+++ b/source/configure.nodebug.developer
@@ -0,0 +1,3 @@
+#!/bin/sh
+CFLAGS="-Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -DDEBUG_PASSWORD"; export CFLAGS
+./configure $*
diff --git a/source/dynconfig.c b/source/dynconfig.c
new file mode 100644
index 00000000000..a9055715c97
--- /dev/null
+++ b/source/dynconfig.c
@@ -0,0 +1,73 @@
+/*
+ Unix SMB/Netbios implementation.
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * @file dynconfig.c
+ *
+ * @brief Global configurations, initialized to configured defaults.
+ *
+ * This file should be the only file that depends on path
+ * configuration (--prefix, etc), so that if ./configure is re-run,
+ * all programs will be appropriately updated. Everything else in
+ * Samba should import extern variables from here, rather than relying
+ * on preprocessor macros.
+ *
+ * Eventually some of these may become even more variable, so that
+ * they can for example consistently be set across the whole of Samba
+ * by command-line parameters, config file entries, or environment
+ * variables.
+ *
+ * @todo Perhaps eventually these should be merged into the parameter
+ * table? There's kind of a chicken-and-egg situation there...
+ **/
+
+char const *dyn_SBINDIR = SBINDIR,
+ *dyn_BINDIR = BINDIR,
+ *dyn_SWATDIR = SWATDIR;
+
+pstring dyn_CONFIGFILE = CONFIGFILE; /**< Location of smb.conf file. **/
+
+/** Log file directory. **/
+pstring dyn_LOGFILEBASE = LOGFILEBASE;
+
+/** Statically configured LanMan hosts. **/
+pstring dyn_LMHOSTSFILE = LMHOSTSFILE;
+
+/**
+ * @brief Samba library directory.
+ *
+ * @sa lib_path() to get the path to a file inside the LIBDIR.
+ **/
+pstring dyn_LIBDIR = LIBDIR;
+
+/**
+ * @brief Directory holding lock files.
+ *
+ * Not writable, but used to set a default in the parameter table.
+ **/
+const pstring dyn_LOCKDIR = LOCKDIR;
+
+const pstring dyn_DRIVERFILE = DRIVERFILE;
+
+const pstring dyn_SMB_PASSWD_FILE = SMB_PASSWD_FILE;
+const pstring dyn_PRIVATE_DIR = PRIVATE_DIR;
+
+
diff --git a/source/groupdb/aliasdb.c b/source/groupdb/aliasdb.c
new file mode 100644
index 00000000000..62513b2e33d
--- /dev/null
+++ b/source/groupdb/aliasdb.c
@@ -0,0 +1,386 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pasesword and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1996-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mases Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern fstring global_sam_name;
+
+/*
+ * NOTE. All these functions are abstracted into a structure
+ * that points to the correct function for the selected database. JRA.
+ */
+
+static struct aliasdb_ops *aldb_ops;
+
+/***************************************************************
+ Initialise the alias db operations.
+***************************************************************/
+
+BOOL initialise_alias_db(void)
+{
+ if (aldb_ops)
+ {
+ return True;
+ }
+
+#ifdef WITH_NISPLUS
+ aldb_ops = nisplus_initialise_alias_db();
+#elif defined(WITH_LDAP)
+ aldb_ops = ldap_initialise_alias_db();
+#else
+ aldb_ops = file_initialise_alias_db();
+#endif
+
+ return (aldb_ops != NULL);
+}
+
+/*
+ * Functions that return/manipulate a LOCAL_GRP.
+ */
+
+/************************************************************************
+ Utility function to search alias database by gid: the LOCAL_GRP
+ structure does not have a gid member, so we have to convert here
+ from gid to alias rid.
+*************************************************************************/
+LOCAL_GRP *iterate_getaliasgid(gid_t gid, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ return iterate_getaliasrid(pwdb_gid_to_alias_rid(gid), mem, num_mem);
+}
+
+/************************************************************************
+ Utility function to search alias database by rid. use this if your database
+ does not have search facilities.
+*************************************************************************/
+LOCAL_GRP *iterate_getaliasrid(uint32 rid, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ LOCAL_GRP *als = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by rid: 0x%x\n", rid));
+
+ /* Open the alias database file - not for update. */
+ fp = startaliasent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open alias database.\n"));
+ return NULL;
+ }
+
+ while ((als = getaliasent(fp, mem, num_mem)) != NULL && als->rid != rid)
+ {
+ }
+
+ if (als != NULL)
+ {
+ DEBUG(10, ("found alias %s by rid: 0x%x\n", als->name, rid));
+ }
+
+ endaliasent(fp);
+ return als;
+}
+
+/************************************************************************
+ Utility function to search alias database by name. use this if your database
+ does not have search facilities.
+*************************************************************************/
+LOCAL_GRP *iterate_getaliasnam(char *name, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ LOCAL_GRP *als = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the alias database file - not for update. */
+ fp = startaliasent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open alias database.\n"));
+ return NULL;
+ }
+
+ while ((als = getaliasent(fp, mem, num_mem)) != NULL && !strequal(als->name, name))
+ {
+ }
+
+ if (als != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endaliasent(fp);
+ return als;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomainalias list.
+ *************************************************************************/
+BOOL add_domain_alias(LOCAL_GRP **alss, int *num_alss, LOCAL_GRP *als)
+{
+ LOCAL_GRP *talss;
+
+ if (alss == NULL || num_alss == NULL || als == NULL)
+ return False;
+
+ talss = Realloc((*alss), ((*num_alss)+1) * sizeof(LOCAL_GRP));
+ if (talss == NULL) {
+ SAFE_FREE(*alss);
+ return False;
+ } else
+ (*alss) = talss;
+
+ DEBUG(10,("adding alias %s(%s)\n", als->name, als->comment));
+
+ fstrcpy((*alss)[(*num_alss)].name , als->name);
+ fstrcpy((*alss)[(*num_alss)].comment, als->comment);
+ (*alss)[(*num_alss)].rid = als->rid;
+
+ (*num_alss)++;
+
+ return True;
+}
+
+/*************************************************************************
+ checks to see if a user is a member of a domain alias
+ *************************************************************************/
+static BOOL user_is_member(char *user_name, LOCAL_GRP_MEMBER *mem, int num_mem)
+{
+ int i;
+ pstring name;
+ slprintf(name, sizeof(name)-1, "\\%s\\%s", global_sam_name, user_name);
+
+ for (i = 0; i < num_mem; i++)
+ {
+ DEBUG(10,("searching against user %s...\n", mem[i].name));
+ if (strequal(mem[i].name, name))
+ {
+ DEBUG(10,("searching for user %s: found\n", name));
+ return True;
+ }
+ }
+ DEBUG(10,("searching for user %s: not found\n", name));
+ return False;
+}
+
+/*************************************************************************
+ gets an array of aliases that a user is in. use this if your database
+ does not have search facilities
+ *************************************************************************/
+BOOL iterate_getuseraliasnam(char *user_name, LOCAL_GRP **alss, int *num_alss)
+{
+ LOCAL_GRP *als;
+ LOCAL_GRP_MEMBER *mem = NULL;
+ int num_mem = 0;
+ void *fp = NULL;
+
+ DEBUG(10, ("search for useralias by name: %s\n", user_name));
+
+ if (user_name == NULL || als == NULL || num_alss == NULL)
+ {
+ return False;
+ }
+
+ (*alss) = NULL;
+ (*num_alss) = 0;
+
+ /* Open the alias database file - not for update. */
+ fp = startaliasent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open alias database.\n"));
+ return False;
+ }
+
+ /* iterate through all aliases. search members for required user */
+ while ((als = getaliasent(fp, &mem, &num_mem)) != NULL)
+ {
+ DEBUG(5,("alias name %s members: %d\n", als->name, num_mem));
+ if (num_mem != 0 && mem != NULL)
+ {
+ BOOL ret = True;
+ if (user_is_member(user_name, mem, num_mem))
+ {
+ ret = add_domain_alias(alss, num_alss, als);
+ }
+
+ SAFE_FREE(mem);
+ num_mem = 0;
+
+ if (!ret)
+ {
+ (*num_alss) = 0;
+ break;
+ }
+ }
+ }
+
+ if ((*num_alss) != 0)
+ {
+ DEBUG(10, ("found %d user aliases:\n", (*num_alss)));
+ }
+
+ endaliasent(fp);
+ return True;
+}
+
+/*************************************************************************
+ gets an array of aliases that a user is in. use this if your database
+ does not have search facilities
+ *************************************************************************/
+BOOL enumdomaliases(LOCAL_GRP **alss, int *num_alss)
+{
+ LOCAL_GRP *als;
+ void *fp = NULL;
+
+ DEBUG(10, ("enum user aliases\n"));
+
+ if (als == NULL || num_alss == NULL)
+ {
+ return False;
+ }
+
+ (*alss) = NULL;
+ (*num_alss) = 0;
+
+ /* Open the alias database file - not for update. */
+ fp = startaliasent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open alias database.\n"));
+ return False;
+ }
+
+ /* iterate through all aliases. */
+ while ((als = getaliasent(fp, NULL, NULL)) != NULL)
+ {
+ if (!add_domain_alias(alss, num_alss, als))
+ {
+ DEBUG(0,("unable to add alias while enumerating\n"));
+ return False;
+ }
+ }
+
+ if ((*num_alss) != 0)
+ {
+ DEBUG(10, ("found %d user aliases:\n", (*num_alss)));
+ }
+
+ endaliasent(fp);
+ return True;
+}
+
+/***************************************************************
+ Start to enumerate the alias database list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+void *startaliasent(BOOL update)
+{
+ return aldb_ops->startaliasent(update);
+}
+
+/***************************************************************
+ End enumeration of the alias database list.
+****************************************************************/
+
+void endaliasent(void *vp)
+{
+ aldb_ops->endaliasent(vp);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the alias database list.
+ *************************************************************************/
+
+LOCAL_GRP *getaliasent(void *vp, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ return aldb_ops->getaliasent(vp, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to add an entry to the alias database file.
+*************************************************************************/
+
+BOOL add_alias_entry(LOCAL_GRP *newals)
+{
+ return aldb_ops->add_alias_entry(newals);
+}
+
+/************************************************************************
+ Routine to search the alias database file for an entry matching the aliasname.
+ and then replace the entry.
+************************************************************************/
+
+BOOL mod_alias_entry(LOCAL_GRP* als)
+{
+ return aldb_ops->mod_alias_entry(als);
+}
+
+/************************************************************************
+ Routine to search alias database by name.
+*************************************************************************/
+
+LOCAL_GRP *getaliasnam(char *name, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ return aldb_ops->getaliasnam(name, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to search alias database by alias rid.
+*************************************************************************/
+
+LOCAL_GRP *getaliasrid(uint32 alias_rid, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ return aldb_ops->getaliasrid(alias_rid, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to search alias database by gid.
+*************************************************************************/
+
+LOCAL_GRP *getaliasgid(gid_t gid, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ return aldb_ops->getaliasgid(gid, mem, num_mem);
+}
+
+/*************************************************************************
+ gets an array of aliases that a user is in.
+ *************************************************************************/
+BOOL getuseraliasnam(char *user_name, LOCAL_GRP **als, int *num_alss)
+{
+ return aldb_ops->getuseraliasnam(user_name, als, num_alss);
+}
+
+/*************************************************************
+ initialises a LOCAL_GRP.
+ **************************************************************/
+
+void aldb_init_als(LOCAL_GRP *als)
+{
+ if (als == NULL) return;
+ ZERO_STRUCTP(als);
+}
+
diff --git a/source/groupdb/aliasfile.c b/source/groupdb/aliasfile.c
new file mode 100644
index 00000000000..21c8a1a5001
--- /dev/null
+++ b/source/groupdb/aliasfile.c
@@ -0,0 +1,289 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef USE_SMBPASS_DB
+
+static int al_file_lock_depth = 0;
+
+static char s_readbuf[1024];
+
+/***************************************************************
+ Start to enumerate the aliasdb list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+static void *startalsfilepwent(BOOL update)
+{
+ return startfilepwent(lp_smb_alias_file(),
+ s_readbuf, sizeof(s_readbuf),
+ &al_file_lock_depth, update);
+}
+
+/***************************************************************
+ End enumeration of the aliasdb list.
+****************************************************************/
+
+static void endalsfilepwent(void *vp)
+{
+ endfilepwent(vp, &al_file_lock_depth);
+}
+
+/*************************************************************************
+ Return the current position in the aliasdb list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+static SMB_BIG_UINT getalsfilepwpos(void *vp)
+{
+ return getfilepwpos(vp);
+}
+
+/*************************************************************************
+ Set the current position in the aliasdb list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+static BOOL setalsfilepwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return setfilepwpos(vp, tok);
+}
+
+static BOOL make_alias_line(char *p, int max_len,
+ LOCAL_GRP *als,
+ LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ int i;
+ int len;
+ len = slprintf(p, max_len-1, "%s:%s:%d:", als->name, als->comment, als->rid);
+
+ if (len == -1)
+ {
+ DEBUG(0,("make_alias_line: cannot create entry\n"));
+ return False;
+ }
+
+ p += len;
+ max_len -= len;
+
+ if (mem == NULL || num_mem == NULL)
+ {
+ return True;
+ }
+
+ for (i = 0; i < (*num_mem); i++)
+ {
+ len = strlen((*mem)[i].name);
+ p = safe_strcpy(p, (*mem)[i].name, max_len);
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("make_alias_line: out of space for aliases!\n"));
+ return False;
+ }
+
+ max_len -= len;
+
+ if (i != (*num_mem)-1)
+ {
+ *p = ',';
+ p++;
+ max_len--;
+ }
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomainalias list.
+ *************************************************************************/
+static char *get_alias_members(char *p, int *num_mem, LOCAL_GRP_MEMBER **members)
+{
+ fstring name;
+
+ if (num_mem == NULL || members == NULL)
+ return NULL;
+
+ (*num_mem) = 0;
+ (*members) = NULL;
+
+ while (next_token(&p, name, ",", sizeof(fstring))) {
+ LOCAL_GRP_MEMBER *mbrs;
+ DOM_SID sid;
+ uint8 type;
+
+ if (lookup_sid(name, &sid, &type)) {
+ mbrs = Realloc((*members), ((*num_mem)+1) * sizeof(LOCAL_GRP_MEMBER));
+ (*num_mem)++;
+ } else {
+ DEBUG(0,("alias database: could not resolve alias named %s\n", name));
+ continue;
+ }
+ if (mbrs == NULL) {
+ SAFE_FREE(*members);
+ return NULL;
+ } else
+ (*members) = mbrs;
+
+ fstrcpy((*members)[(*num_mem)-1].name, name);
+ (*members)[(*num_mem)-1].sid_use = type;
+ sid_copy(&(*members)[(*num_mem)-1].sid, &sid);
+ }
+ return p;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomainalias list.
+ *************************************************************************/
+static LOCAL_GRP *getalsfilepwent(void *vp, LOCAL_GRP_MEMBER **mem, int *num_mem)
+{
+ /* Static buffers we will return. */
+ static LOCAL_GRP al_buf;
+
+ int gidval;
+
+ pstring linebuf;
+ char *p;
+ size_t linebuf_len;
+
+ aldb_init_als(&al_buf);
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0)
+ {
+ /* get alias name */
+
+ p = strncpyn(al_buf.name, linebuf, sizeof(al_buf.name), ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getalsfilepwent: malformed alias entry (no :)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* get alias comment */
+
+ p = strncpyn(al_buf.comment, p, sizeof(al_buf.comment), ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getalsfilepwent: malformed alias entry (no :)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* Get alias gid. */
+
+ p = Atoic(p, &gidval, ":");
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("getalsfilepwent: malformed alias entry (no : after uid)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* now get the user's aliases. there are a maximum of 32 */
+
+ if (mem != NULL && num_mem != NULL)
+ {
+ (*mem) = NULL;
+ (*num_mem) = 0;
+
+ p = get_alias_members(p, num_mem, mem);
+ if (p == NULL)
+ {
+ DEBUG(0, ("getalsfilepwent: malformed alias entry (no : after members)\n"));
+ }
+ }
+
+ /* ok, set up the static data structure and return it */
+
+ al_buf.rid = pwdb_gid_to_alias_rid((gid_t)gidval);
+
+ make_alias_line(linebuf, sizeof(linebuf), &al_buf, mem, num_mem);
+ DEBUG(10,("line: '%s'\n", linebuf));
+
+ return &al_buf;
+ }
+
+ DEBUG(5,("getalsfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Routine to add an entry to the aliasdb file.
+*************************************************************************/
+
+static BOOL add_alsfileals_entry(LOCAL_GRP *newals)
+{
+ DEBUG(0, ("add_alsfileals_entry: NOT IMPLEMENTED\n"));
+ return False;
+}
+
+/************************************************************************
+ Routine to search the aliasdb file for an entry matching the aliasname.
+ and then modify its alias entry. We can't use the startalspwent()/
+ getalspwent()/endalspwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out alias or NO PASS
+************************************************************************/
+
+static BOOL mod_alsfileals_entry(LOCAL_GRP* als)
+{
+ DEBUG(0, ("mod_alsfileals_entry: NOT IMPLEMENTED\n"));
+ return False;
+}
+
+
+static struct aliasdb_ops file_ops =
+{
+ startalsfilepwent,
+ endalsfilepwent,
+ getalsfilepwpos,
+ setalsfilepwpos,
+
+ iterate_getaliasnam, /* In aliasdb.c */
+ iterate_getaliasgid, /* In aliasdb.c */
+ iterate_getaliasrid, /* In aliasdb.c */
+ getalsfilepwent,
+
+ add_alsfileals_entry,
+ mod_alsfileals_entry,
+
+ iterate_getuseraliasnam /* in aliasdb.c */
+};
+
+struct aliasdb_ops *file_initialise_alias_db(void)
+{
+ return &file_ops;
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void als_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* USE_SMBPASS_DB */
diff --git a/source/groupdb/groupdb.c b/source/groupdb/groupdb.c
new file mode 100644
index 00000000000..69b4137472f
--- /dev/null
+++ b/source/groupdb/groupdb.c
@@ -0,0 +1,382 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * NOTE. All these functions are abstracted into a structure
+ * that points to the correct function for the selected database. JRA.
+ */
+
+static struct groupdb_ops *gpdb_ops;
+
+/***************************************************************
+ Initialise the group db operations.
+***************************************************************/
+
+BOOL initialise_group_db(void)
+{
+ if (gpdb_ops)
+ {
+ return True;
+ }
+
+#ifdef WITH_NISPLUS
+ gpdb_ops = nisplus_initialise_group_db();
+#elif defined(WITH_LDAP)
+ gpdb_ops = ldap_initialise_group_db();
+#else
+ gpdb_ops = file_initialise_group_db();
+#endif
+
+ return (gpdb_ops != NULL);
+}
+
+/*
+ * Functions that return/manipulate a DOMAIN_GRP.
+ */
+
+/************************************************************************
+ Utility function to search group database by gid: the DOMAIN_GRP
+ structure does not have a gid member, so we have to convert here
+ from gid to group rid.
+*************************************************************************/
+DOMAIN_GRP *iterate_getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ return iterate_getgrouprid(pwdb_gid_to_group_rid(gid), mem, num_mem);
+}
+
+/************************************************************************
+ Utility function to search group database by rid. use this if your database
+ does not have search facilities.
+*************************************************************************/
+DOMAIN_GRP *iterate_getgrouprid(uint32 rid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ DOMAIN_GRP *grp = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by rid: 0x%x\n", rid));
+
+ /* Open the group database file - not for update. */
+ fp = startgroupent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open group database.\n"));
+ return NULL;
+ }
+
+ while ((grp = getgroupent(fp, mem, num_mem)) != NULL && grp->rid != rid)
+ {
+ }
+
+ if (grp != NULL)
+ {
+ DEBUG(10, ("found group %s by rid: 0x%x\n", grp->name, rid));
+ }
+
+ endgroupent(fp);
+ return grp;
+}
+
+/************************************************************************
+ Utility function to search group database by name. use this if your database
+ does not have search facilities.
+*************************************************************************/
+DOMAIN_GRP *iterate_getgroupnam(char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ DOMAIN_GRP *grp = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the group database file - not for update. */
+ fp = startgroupent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open group database.\n"));
+ return NULL;
+ }
+
+ while ((grp = getgroupent(fp, mem, num_mem)) != NULL && !strequal(grp->name, name))
+ {
+ }
+
+ if (grp != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endgroupent(fp);
+ return grp;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomaingroup list.
+ *************************************************************************/
+BOOL add_domain_group(DOMAIN_GRP **grps, int *num_grps, DOMAIN_GRP *grp)
+{
+ DOMAIN_GRP *tgrps;
+
+ if (grps == NULL || num_grps == NULL || grp == NULL)
+ return False;
+
+ tgrps = Realloc((*grps), ((*num_grps)+1) * sizeof(DOMAIN_GRP));
+ if (tgrps == NULL) {
+ SAFE_FREE(*grps);
+ return False;
+ } else
+ (*grps) = tgrps;
+
+ DEBUG(10,("adding group %s(%s)\n", grp->name, grp->comment));
+
+ fstrcpy((*grps)[(*num_grps)].name , grp->name);
+ fstrcpy((*grps)[(*num_grps)].comment, grp->comment);
+ (*grps)[(*num_grps)].attr = grp->attr;
+ (*grps)[(*num_grps)].rid = grp->rid ;
+
+ (*num_grps)++;
+
+ return True;
+}
+
+/*************************************************************************
+ checks to see if a user is a member of a domain group
+ *************************************************************************/
+static BOOL user_is_member(char *user_name, DOMAIN_GRP_MEMBER *mem, int num_mem)
+{
+ int i;
+ for (i = 0; i < num_mem; i++)
+ {
+ DEBUG(10,("searching against user %s...\n", mem[i].name));
+ if (strequal(mem[i].name, user_name))
+ {
+ DEBUG(10,("searching for user %s: found\n", user_name));
+ return True;
+ }
+ }
+ DEBUG(10,("searching for user %s: not found\n", user_name));
+ return False;
+}
+
+/*************************************************************************
+ gets an array of groups that a user is in. use this if your database
+ does not have search facilities
+ *************************************************************************/
+BOOL iterate_getusergroupsnam(char *user_name, DOMAIN_GRP **grps, int *num_grps)
+{
+ DOMAIN_GRP *grp;
+ DOMAIN_GRP_MEMBER *mem = NULL;
+ int num_mem = 0;
+ void *fp = NULL;
+
+ DEBUG(10, ("search for usergroups by name: %s\n", user_name));
+
+ if (user_name == NULL || grp == NULL || num_grps == NULL)
+ {
+ return False;
+ }
+
+ (*grps) = NULL;
+ (*num_grps) = 0;
+
+ /* Open the group database file - not for update. */
+ fp = startgroupent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open group database.\n"));
+ return False;
+ }
+
+ /* iterate through all groups. search members for required user */
+ while ((grp = getgroupent(fp, &mem, &num_mem)) != NULL)
+ {
+ DEBUG(5,("group name %s members: %d\n", grp->name, num_mem));
+ if (num_mem != 0 && mem != NULL)
+ {
+ BOOL ret = True;
+ if (user_is_member(user_name, mem, num_mem))
+ {
+ ret = add_domain_group(grps, num_grps, grp);
+ }
+
+ SAFE_FREE(mem);
+ num_mem = 0;
+
+ if (!ret)
+ {
+ (*num_grps) = 0;
+ break;
+ }
+ }
+ }
+
+ if ((*num_grps) != 0)
+ {
+ DEBUG(10, ("found %d user groups:\n", (*num_grps)));
+ }
+
+ endgroupent(fp);
+ return True;
+}
+
+/*************************************************************************
+ gets an array of groups that a user is in. use this if your database
+ does not have search facilities
+ *************************************************************************/
+BOOL enumdomgroups(DOMAIN_GRP **grps, int *num_grps)
+{
+ DOMAIN_GRP *grp;
+ void *fp = NULL;
+
+ DEBUG(10, ("enum user groups\n"));
+
+ if (grp == NULL || num_grps == NULL)
+ {
+ return False;
+ }
+
+ (*grps) = NULL;
+ (*num_grps) = 0;
+
+ /* Open the group database file - not for update. */
+ fp = startgroupent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open group database.\n"));
+ return False;
+ }
+
+ /* iterate through all groups. */
+ while ((grp = getgroupent(fp, NULL, NULL)) != NULL)
+ {
+ if (!add_domain_group(grps, num_grps, grp))
+ {
+ DEBUG(0,("unable to add group while enumerating\n"));
+ return False;
+ }
+ }
+
+ if ((*num_grps) != 0)
+ {
+ DEBUG(10, ("found %d user groups:\n", (*num_grps)));
+ }
+
+ endgroupent(fp);
+ return True;
+}
+
+/***************************************************************
+ Start to enumerate the group database list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+void *startgroupent(BOOL update)
+{
+ return gpdb_ops->startgroupent(update);
+}
+
+/***************************************************************
+ End enumeration of the group database list.
+****************************************************************/
+
+void endgroupent(void *vp)
+{
+ gpdb_ops->endgroupent(vp);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the group database list.
+ *************************************************************************/
+
+DOMAIN_GRP *getgroupent(void *vp, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ return gpdb_ops->getgroupent(vp, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to add an entry to the group database file.
+*************************************************************************/
+
+BOOL add_group_entry(DOMAIN_GRP *newgrp)
+{
+ return gpdb_ops->add_group_entry(newgrp);
+}
+
+/************************************************************************
+ Routine to search the group database file for an entry matching the groupname.
+ and then replace the entry.
+************************************************************************/
+
+BOOL mod_group_entry(DOMAIN_GRP* grp)
+{
+ return gpdb_ops->mod_group_entry(grp);
+}
+
+/************************************************************************
+ Routine to search group database by name.
+*************************************************************************/
+
+DOMAIN_GRP *getgroupnam(char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ return gpdb_ops->getgroupnam(name, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to search group database by group rid.
+*************************************************************************/
+
+DOMAIN_GRP *getgrouprid(uint32 group_rid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ return gpdb_ops->getgrouprid(group_rid, mem, num_mem);
+}
+
+/************************************************************************
+ Routine to search group database by gid.
+*************************************************************************/
+
+DOMAIN_GRP *getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ return gpdb_ops->getgroupgid(gid, mem, num_mem);
+}
+
+/*************************************************************************
+ gets an array of groups that a user is in.
+ *************************************************************************/
+BOOL getusergroupsnam(char *user_name, DOMAIN_GRP **grp, int *num_grps)
+{
+ return gpdb_ops->getusergroupsnam(user_name, grp, num_grps);
+}
+
+/*************************************************************
+ initialises a DOMAIN_GRP.
+ **************************************************************/
+
+void gpdb_init_grp(DOMAIN_GRP *grp)
+{
+ if (grp == NULL) return;
+ ZERO_STRUCTP(grp);
+}
+
diff --git a/source/groupdb/groupfile.c b/source/groupdb/groupfile.c
new file mode 100644
index 00000000000..557ae92530f
--- /dev/null
+++ b/source/groupdb/groupfile.c
@@ -0,0 +1,284 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef USE_SMBPASS_DB
+
+static int gp_file_lock_depth = 0;
+
+static char s_readbuf[1024];
+
+/***************************************************************
+ Start to enumerate the grppasswd list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+static void *startgrpfilepwent(BOOL update)
+{
+ return startfilepwent(lp_smb_group_file(),
+ s_readbuf, sizeof(s_readbuf),
+ &gp_file_lock_depth, update);
+}
+
+/***************************************************************
+ End enumeration of the grppasswd list.
+****************************************************************/
+
+static void endgrpfilepwent(void *vp)
+{
+ endfilepwent(vp, &gp_file_lock_depth);
+}
+
+/*************************************************************************
+ Return the current position in the grppasswd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+static SMB_BIG_UINT getgrpfilepwpos(void *vp)
+{
+ return getfilepwpos(vp);
+}
+
+/*************************************************************************
+ Set the current position in the grppasswd list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+static BOOL setgrpfilepwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return setfilepwpos(vp, tok);
+}
+
+static BOOL make_group_line(char *p, int max_len,
+ DOMAIN_GRP *grp,
+ DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ int i;
+ int len;
+ len = slprintf(p, max_len-1, "%s:%s:%d:", grp->name, grp->comment, grp->rid);
+
+ if (len == -1)
+ {
+ DEBUG(0,("make_group_line: cannot create entry\n"));
+ return False;
+ }
+
+ p += len;
+ max_len -= len;
+
+ if (mem == NULL || num_mem == NULL)
+ {
+ return True;
+ }
+
+ for (i = 0; i < (*num_mem); i++)
+ {
+ len = strlen((*mem)[i].name);
+ p = safe_strcpy(p, (*mem)[i].name, max_len);
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("make_group_line: out of space for groups!\n"));
+ return False;
+ }
+
+ max_len -= len;
+
+ if (i != (*num_mem)-1)
+ {
+ *p = ',';
+ p++;
+ max_len--;
+ }
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomaingroup list.
+ *************************************************************************/
+static char *get_group_members(char *p, int *num_mem, DOMAIN_GRP_MEMBER **members)
+{
+ fstring name;
+
+ if (num_mem == NULL || members == NULL)
+ {
+ return NULL;
+ }
+
+ (*num_mem) = 0;
+ (*members) = NULL;
+
+ while (next_token(&p, name, ",", sizeof(fstring)))
+ {
+ DOMAIN_GRP_MEMBER *mbrs;
+
+ mbrs = Realloc((*members), ((*num_mem)+1) * sizeof(DOMAIN_GRP_MEMBER));
+ if (mbrs == NULL) {
+ SAFE_FREE(*members);
+ return NULL;
+ }
+ else (*members) = mbrs;
+ fstrcpy((*members)[(*num_mem)].name, name);
+ (*members)[(*num_mem)].attr = 0x07;
+ (*num_mem)++;
+ }
+ return p;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbdomaingroup list.
+ *************************************************************************/
+static DOMAIN_GRP *getgrpfilepwent(void *vp, DOMAIN_GRP_MEMBER **mem, int *num_mem)
+{
+ /* Static buffers we will return. */
+ static DOMAIN_GRP gp_buf;
+
+ int gidval;
+
+ pstring linebuf;
+ char *p;
+ size_t linebuf_len;
+
+ gpdb_init_grp(&gp_buf);
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0)
+ {
+ /* get group name */
+
+ p = strncpyn(gp_buf.name, linebuf, sizeof(gp_buf.name), ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getgrpfilepwent: malformed group entry (no :)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* get group comment */
+
+ p = strncpyn(gp_buf.comment, p, sizeof(gp_buf.comment), ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getgrpfilepwent: malformed group entry (no :)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* Get group gid. */
+
+ p = Atoic(p, &gidval, ":");
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("getgrpfilepwent: malformed group entry (no : after uid)\n"));
+ continue;
+ }
+
+ /* Go past ':' */
+ p++;
+
+ /* now get the user's groups. there are a maximum of 32 */
+
+ if (mem != NULL && num_mem != NULL)
+ {
+ (*mem) = NULL;
+ (*num_mem) = 0;
+
+ p = get_group_members(p, num_mem, mem);
+ if (p == NULL)
+ {
+ DEBUG(0, ("getgrpfilepwent: malformed group entry (no : after members)\n"));
+ }
+ }
+
+ /* ok, set up the static data structure and return it */
+
+ gp_buf.rid = pwdb_gid_to_group_rid((gid_t)gidval);
+ gp_buf.attr = 0x07;
+
+ make_group_line(linebuf, sizeof(linebuf), &gp_buf, mem, num_mem);
+ DEBUG(10,("line: '%s'\n", linebuf));
+
+ return &gp_buf;
+ }
+
+ DEBUG(5,("getgrpfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Routine to add an entry to the grppasswd file.
+*************************************************************************/
+
+static BOOL add_grpfilegrp_entry(DOMAIN_GRP *newgrp)
+{
+ DEBUG(0, ("add_grpfilegrp_entry: NOT IMPLEMENTED\n"));
+ return False;
+}
+
+/************************************************************************
+ Routine to search the grppasswd file for an entry matching the groupname.
+ and then modify its group entry. We can't use the startgrppwent()/
+ getgrppwent()/endgrppwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out group or NO PASS
+************************************************************************/
+
+static BOOL mod_grpfilegrp_entry(DOMAIN_GRP* grp)
+{
+ DEBUG(0, ("mod_grpfilegrp_entry: NOT IMPLEMENTED\n"));
+ return False;
+}
+
+
+static struct groupdb_ops file_ops =
+{
+ startgrpfilepwent,
+ endgrpfilepwent,
+ getgrpfilepwpos,
+ setgrpfilepwpos,
+
+ iterate_getgroupnam, /* In groupdb.c */
+ iterate_getgroupgid, /* In groupdb.c */
+ iterate_getgrouprid, /* In groupdb.c */
+ getgrpfilepwent,
+
+ add_grpfilegrp_entry,
+ mod_grpfilegrp_entry,
+
+ iterate_getusergroupsnam /* in groupdb.c */
+};
+
+struct groupdb_ops *file_initialise_group_db(void)
+{
+ return &file_ops;
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void grppass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* USE_SMBPASS_DB */
diff --git a/source/groupdb/mapping.c b/source/groupdb/mapping.c
new file mode 100644
index 00000000000..06fc30ad476
--- /dev/null
+++ b/source/groupdb/mapping.c
@@ -0,0 +1,1173 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern DOM_SID global_sam_sid;
+
+static TDB_CONTEXT *tdb; /* used for driver files */
+
+#define DATABASE_VERSION 1
+#define GROUP_PREFIX "UNIXGROUP/"
+
+PRIVS privs[] = {
+ {SE_PRIV_NONE, "no_privs", "No privilege" }, /* this one MUST be first */
+ {SE_PRIV_ADD_MACHINES, "SeMachineAccountPrivilege", "Add workstations to the domain" },
+ {SE_PRIV_SEC_PRIV, "SeSecurityPrivilege", "Manage the audit logs" },
+ {SE_PRIV_TAKE_OWNER, "SeTakeOwnershipPrivilege", "Take ownership of file" },
+ {SE_PRIV_ADD_USERS, "SaAddUsers", "Add users to the domain - Samba" },
+ {SE_PRIV_PRINT_OPERATOR, "SaPrintOp", "Add or remove printers - Samba" },
+ {SE_PRIV_ALL, "SaAllPrivs", "all privileges" }
+};
+/*
+PRIVS privs[] = {
+ { 2, "SeCreateTokenPrivilege" },
+ { 3, "SeAssignPrimaryTokenPrivilege" },
+ { 4, "SeLockMemoryPrivilege" },
+ { 5, "SeIncreaseQuotaPrivilege" },
+ { 6, "SeMachineAccountPrivilege" },
+ { 7, "SeTcbPrivilege" },
+ { 8, "SeSecurityPrivilege" },
+ { 9, "SeTakeOwnershipPrivilege" },
+ { 10, "SeLoadDriverPrivilege" },
+ { 11, "SeSystemProfilePrivilege" },
+ { 12, "SeSystemtimePrivilege" },
+ { 13, "SeProfileSingleProcessPrivilege" },
+ { 14, "SeIncreaseBasePriorityPrivilege" },
+ { 15, "SeCreatePagefilePrivilege" },
+ { 16, "SeCreatePermanentPrivilege" },
+ { 17, "SeBackupPrivilege" },
+ { 18, "SeRestorePrivilege" },
+ { 19, "SeShutdownPrivilege" },
+ { 20, "SeDebugPrivilege" },
+ { 21, "SeAuditPrivilege" },
+ { 22, "SeSystemEnvironmentPrivilege" },
+ { 23, "SeChangeNotifyPrivilege" },
+ { 24, "SeRemoteShutdownPrivilege" },
+ { 25, "SeUndockPrivilege" },
+ { 26, "SeSyncAgentPrivilege" },
+ { 27, "SeEnableDelegationPrivilege" },
+};
+*/
+
+ /*
+ * Those are not really privileges like the other ones.
+ * They are handled in a special case and called
+ * system privileges.
+ *
+ * SeNetworkLogonRight
+ * SeUnsolicitedInputPrivilege
+ * SeBatchLogonRight
+ * SeServiceLogonRight
+ * SeInteractiveLogonRight
+ * SeDenyInteractiveLogonRight
+ * SeDenyNetworkLogonRight
+ * SeDenyBatchLogonRight
+ * SeDenyBatchLogonRight
+ */
+
+#if 0
+/****************************************************************************
+check if the user has the required privilege.
+****************************************************************************/
+static BOOL se_priv_access_check(NT_USER_TOKEN *token, uint32 privilege)
+{
+ /* no token, no privilege */
+ if (token==NULL)
+ return False;
+
+ if ((token->privilege & privilege)==privilege)
+ return True;
+
+ return False;
+}
+#endif
+
+/****************************************************************************
+dump the mapping group mapping to a text file
+****************************************************************************/
+char *decode_sid_name_use(fstring group, enum SID_NAME_USE name_use)
+{
+ static fstring group_type;
+
+ switch(name_use) {
+ case SID_NAME_USER:
+ fstrcpy(group_type,"User");
+ break;
+ case SID_NAME_DOM_GRP:
+ fstrcpy(group_type,"Domain group");
+ break;
+ case SID_NAME_DOMAIN:
+ fstrcpy(group_type,"Domain");
+ break;
+ case SID_NAME_ALIAS:
+ fstrcpy(group_type,"Local group");
+ break;
+ case SID_NAME_WKN_GRP:
+ fstrcpy(group_type,"Builtin group");
+ break;
+ case SID_NAME_DELETED:
+ fstrcpy(group_type,"Deleted");
+ break;
+ case SID_NAME_INVALID:
+ fstrcpy(group_type,"Invalid");
+ break;
+ case SID_NAME_UNKNOWN:
+ default:
+ fstrcpy(group_type,"Unknown type");
+ break;
+ }
+
+ fstrcpy(group, group_type);
+ return group_type;
+}
+
+/****************************************************************************
+open the group mapping tdb
+****************************************************************************/
+BOOL init_group_mapping(void)
+{
+ static pid_t local_pid;
+ char *vstring = "INFO/version";
+
+ if (tdb && local_pid == sys_getpid()) return True;
+ tdb = tdb_open_log(lock_path("group_mapping.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb) {
+ DEBUG(0,("Failed to open group mapping database\n"));
+ return False;
+ }
+
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb, vstring);
+ if (tdb_fetch_int(tdb, vstring) != DATABASE_VERSION) {
+ tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
+ tdb_store_int(tdb, vstring, DATABASE_VERSION);
+ }
+ tdb_unlock_bystring(tdb, vstring);
+
+ /* write a list of default groups */
+ if(!default_group_mapping())
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+BOOL add_mapping_entry(GROUP_MAP *map, int flag)
+{
+ TDB_DATA kbuf, dbuf;
+ pstring key, buf;
+ fstring string_sid="";
+ int len;
+ int i;
+ PRIVILEGE_SET *set;
+
+ init_group_mapping();
+
+ sid_to_string(string_sid, &map->sid);
+
+ len = tdb_pack(buf, sizeof(buf), "ddffd",
+ map->gid, map->sid_name_use, map->nt_name, map->comment, map->systemaccount);
+
+ /* write the privilege list in the TDB database */
+
+ set=&map->priv_set;
+ len += tdb_pack(buf+len, sizeof(buf)-len, "d", set->count);
+ for (i=0; i<set->count; i++)
+ len += tdb_pack(buf+len, sizeof(buf)-len, "ddd",
+ set->set[i].luid.low, set->set[i].luid.high, set->set[i].attr);
+
+ if (len > sizeof(buf))
+ return False;
+
+ slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
+
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+ dbuf.dsize = len;
+ dbuf.dptr = buf;
+ if (tdb_store(tdb, kbuf, dbuf, flag) != 0) return False;
+
+ return True;
+}
+
+/****************************************************************************
+initialise first time the mapping list
+****************************************************************************/
+BOOL add_initial_entry(gid_t gid, fstring sid, enum SID_NAME_USE sid_name_use,
+ fstring nt_name, fstring comment, PRIVILEGE_SET priv_set, uint32 systemaccount)
+{
+ GROUP_MAP map;
+
+ map.gid=gid;
+ string_to_sid(&map.sid, sid);
+ map.sid_name_use=sid_name_use;
+ fstrcpy(map.nt_name, nt_name);
+ fstrcpy(map.comment, comment);
+ map.systemaccount=systemaccount;
+
+ map.priv_set.count=priv_set.count;
+ map.priv_set.set=priv_set.set;
+
+ add_mapping_entry(&map, TDB_INSERT);
+
+ return True;
+}
+
+/****************************************************************************
+initialise a privilege list
+****************************************************************************/
+void init_privilege(PRIVILEGE_SET *priv_set)
+{
+ priv_set->count=0;
+ priv_set->control=0;
+ priv_set->set=NULL;
+}
+
+/****************************************************************************
+free a privilege list
+****************************************************************************/
+BOOL free_privilege(PRIVILEGE_SET *priv_set)
+{
+ if (priv_set->count==0) {
+ DEBUG(100,("free_privilege: count=0, nothing to clear ?\n"));
+ return False;
+ }
+
+ if (priv_set->set==NULL) {
+ DEBUG(0,("free_privilege: list ptr is NULL, very strange !\n"));
+ return False;
+ }
+
+ safe_free(priv_set->set);
+ priv_set->count=0;
+ priv_set->control=0;
+ priv_set->set=NULL;
+
+ return True;
+}
+
+/****************************************************************************
+add a privilege to a privilege array
+****************************************************************************/
+BOOL add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+{
+ LUID_ATTR *new_set;
+
+ /* check if the privilege is not already in the list */
+ if (check_priv_in_privilege(priv_set, set))
+ return False;
+
+ /* we can allocate memory to add the new privilege */
+
+ new_set=(LUID_ATTR *)Realloc(priv_set->set, (priv_set->count+1)*(sizeof(LUID_ATTR)));
+ if (new_set==NULL) {
+ DEBUG(0,("add_privilege: could not Realloc memory to add a new privilege\n"));
+ return False;
+ }
+
+ new_set[priv_set->count].luid.high=set.luid.high;
+ new_set[priv_set->count].luid.low=set.luid.low;
+ new_set[priv_set->count].attr=set.attr;
+
+ priv_set->count++;
+ priv_set->set=new_set;
+
+ return True;
+}
+
+/****************************************************************************
+add all the privileges to a privilege array
+****************************************************************************/
+BOOL add_all_privilege(PRIVILEGE_SET *priv_set)
+{
+ LUID_ATTR set;
+
+ set.attr=0;
+ set.luid.high=0;
+
+ set.luid.low=SE_PRIV_ADD_USERS;
+ add_privilege(priv_set, set);
+
+ set.luid.low=SE_PRIV_ADD_MACHINES;
+ add_privilege(priv_set, set);
+
+ set.luid.low=SE_PRIV_PRINT_OPERATOR;
+ add_privilege(priv_set, set);
+
+ return True;
+}
+
+/****************************************************************************
+check if the privilege list is empty
+****************************************************************************/
+BOOL check_empty_privilege(PRIVILEGE_SET *priv_set)
+{
+
+ if (priv_set->count!=0)
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+check if the privilege is in the privilege list
+****************************************************************************/
+BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+{
+ int i;
+
+ /* if the list is empty, obviously we can't have it */
+ if (check_empty_privilege(priv_set))
+ return False;
+
+ for (i=0; i<priv_set->count; i++) {
+ LUID_ATTR *cur_set;
+
+ cur_set=&priv_set->set[i];
+ /* check only the low and high part. Checking the attr field has no meaning */
+ if( (cur_set->luid.low==set.luid.low) && (cur_set->luid.high==set.luid.high) )
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+remove a privilege to a privilege array
+****************************************************************************/
+BOOL remove_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+{
+ LUID_ATTR *new_set;
+ LUID_ATTR *old_set;
+ int i,j;
+
+ /* check if the privilege is in the list */
+ if (!check_priv_in_privilege(priv_set, set))
+ return False;
+
+ /* special case if it's the only privilege in the list */
+ if (priv_set->count==1) {
+ free_privilege(priv_set);
+ init_privilege(priv_set);
+
+ return True;
+ }
+
+ /*
+ * the privilege is there, create a new list,
+ * and copy the other privileges
+ */
+
+ old_set=priv_set->set;
+
+ new_set=(LUID_ATTR *)malloc((priv_set->count-1)*(sizeof(LUID_ATTR)));
+ if (new_set==NULL) {
+ DEBUG(0,("remove_privilege: could not malloc memory for new privilege list\n"));
+ return False;
+ }
+
+ for (i=0, j=0; i<priv_set->count; i++) {
+ if ((old_set[i].luid.low==set.luid.low) &&
+ (old_set[i].luid.high==set.luid.high)) {
+ continue;
+ }
+
+ new_set[j].luid.low=old_set[i].luid.low;
+ new_set[j].luid.high=old_set[i].luid.high;
+ new_set[j].attr=old_set[i].attr;
+
+ j++;
+ }
+
+ if (j!=priv_set->count-1) {
+ DEBUG(0,("remove_privilege: mismatch ! difference is not -1\n"));
+ DEBUGADD(0,("old count:%d, new count:%d\n", priv_set->count, j));
+ safe_free(new_set);
+ return False;
+ }
+
+ /* ok everything is fine */
+
+ priv_set->count--;
+ priv_set->set=new_set;
+
+ safe_free(old_set);
+
+ return True;
+}
+
+/****************************************************************************
+initialise first time the mapping list
+****************************************************************************/
+BOOL default_group_mapping(void)
+{
+ DOM_SID sid_admins;
+ DOM_SID sid_users;
+ DOM_SID sid_guests;
+ fstring str_admins;
+ fstring str_users;
+ fstring str_guests;
+ LUID_ATTR set;
+
+ PRIVILEGE_SET privilege_none;
+ PRIVILEGE_SET privilege_all;
+ PRIVILEGE_SET privilege_print_op;
+
+ init_privilege(&privilege_none);
+ init_privilege(&privilege_all);
+ init_privilege(&privilege_print_op);
+
+ set.attr=0;
+ set.luid.high=0;
+ set.luid.low=SE_PRIV_PRINT_OPERATOR;
+ add_privilege(&privilege_print_op, set);
+
+ add_all_privilege(&privilege_all);
+
+ /* Add the Wellknown groups */
+
+ add_initial_entry(-1, "S-1-5-32-544", SID_NAME_ALIAS, "Administrators", "", privilege_all, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+ add_initial_entry(-1, "S-1-5-32-545", SID_NAME_ALIAS, "Users", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+ add_initial_entry(-1, "S-1-5-32-546", SID_NAME_ALIAS, "Guests", "", privilege_none, PR_ACCESS_FROM_NETWORK);
+ add_initial_entry(-1, "S-1-5-32-547", SID_NAME_ALIAS, "Power Users", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+
+ add_initial_entry(-1, "S-1-5-32-548", SID_NAME_ALIAS, "Account Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+ add_initial_entry(-1, "S-1-5-32-549", SID_NAME_ALIAS, "System Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+ add_initial_entry(-1, "S-1-5-32-550", SID_NAME_ALIAS, "Print Operators", "", privilege_print_op, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+ add_initial_entry(-1, "S-1-5-32-551", SID_NAME_ALIAS, "Backup Operators", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+
+ add_initial_entry(-1, "S-1-5-32-552", SID_NAME_ALIAS, "Replicators", "", privilege_none, PR_ACCESS_FROM_NETWORK);
+
+ /* Add the defaults domain groups */
+
+ sid_copy(&sid_admins, &global_sam_sid);
+ sid_append_rid(&sid_admins, DOMAIN_GROUP_RID_ADMINS);
+ sid_to_string(str_admins, &sid_admins);
+ add_initial_entry(-1, str_admins, SID_NAME_DOM_GRP, "Domain Admins", "", privilege_all, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+
+ sid_copy(&sid_users, &global_sam_sid);
+ sid_append_rid(&sid_users, DOMAIN_GROUP_RID_USERS);
+ sid_to_string(str_users, &sid_users);
+ add_initial_entry(-1, str_users, SID_NAME_DOM_GRP, "Domain Users", "", privilege_none, PR_ACCESS_FROM_NETWORK|PR_LOG_ON_LOCALLY);
+
+ sid_copy(&sid_guests, &global_sam_sid);
+ sid_append_rid(&sid_guests, DOMAIN_GROUP_RID_GUESTS);
+ sid_to_string(str_guests, &sid_guests);
+ add_initial_entry(-1, str_guests, SID_NAME_DOM_GRP, "Domain Guests", "", privilege_none, PR_ACCESS_FROM_NETWORK);
+
+ return True;
+}
+
+
+/****************************************************************************
+return the sid and the type of the unix group
+****************************************************************************/
+BOOL get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
+{
+ TDB_DATA kbuf, dbuf;
+ pstring key;
+ fstring string_sid;
+ int ret;
+ int i;
+ PRIVILEGE_SET *set;
+
+ init_group_mapping();
+
+ /* the key is the SID, retrieving is direct */
+
+ sid_to_string(string_sid, &sid);
+ slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr) return False;
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
+ &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
+
+ set=&map->priv_set;
+ init_privilege(set);
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
+
+ DEBUG(10,("get_group_map_from_sid: %d privileges\n", map->priv_set.count));
+
+ set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
+ if (set->set==NULL) {
+ DEBUG(0,("get_group_map_from_sid: could not allocate memory for privileges\n"));
+ return False;
+ }
+
+ for (i=0; i<set->count; i++)
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd",
+ &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
+
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize) {
+ DEBUG(0,("get_group_map_from_sid: group mapping TDB corrupted ?\n"));
+ free_privilege(set);
+ return False;
+ }
+
+ /* we don't want the privileges */
+ if (with_priv==MAPPING_WITHOUT_PRIV)
+ free_privilege(set);
+
+ sid_copy(&map->sid, &sid);
+
+ return True;
+}
+
+
+/****************************************************************************
+return the sid and the type of the unix group
+****************************************************************************/
+BOOL get_group_map_from_gid(gid_t gid, GROUP_MAP *map, BOOL with_priv)
+{
+ TDB_DATA kbuf, dbuf, newkey;
+ fstring string_sid;
+ int ret;
+ int i;
+ PRIVILEGE_SET *set;
+
+ init_group_mapping();
+
+ /* we need to enumerate the TDB to find the GID */
+
+ for (kbuf = tdb_firstkey(tdb);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr) continue;
+
+ fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
+
+ string_to_sid(&map->sid, string_sid);
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
+ &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
+
+ set=&map->priv_set;
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
+
+ set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
+ if (set->set==NULL) {
+ DEBUG(0,("get_group_map_from_gid: could not allocate memory for privileges\n"));
+ return False;
+ }
+
+ for (i=0; i<set->count; i++)
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd",
+ &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
+
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize){
+ free_privilege(set);
+ continue;
+ }
+
+ if (gid==map->gid) {
+ if (!with_priv)
+ free_privilege(&map->priv_set);
+ return True;
+ }
+
+ free_privilege(set);
+ }
+
+ return False;
+}
+
+/****************************************************************************
+return the sid and the type of the unix group
+****************************************************************************/
+BOOL get_group_map_from_ntname(char *name, GROUP_MAP *map, BOOL with_priv)
+{
+ TDB_DATA kbuf, dbuf, newkey;
+ fstring string_sid;
+ int ret;
+ int i;
+ PRIVILEGE_SET *set;
+
+ init_group_mapping();
+
+ /* we need to enumerate the TDB to find the name */
+
+ for (kbuf = tdb_firstkey(tdb);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0) continue;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr) continue;
+
+ fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
+
+ string_to_sid(&map->sid, string_sid);
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
+ &map->gid, &map->sid_name_use, &map->nt_name, &map->comment, &map->systemaccount);
+
+ set=&map->priv_set;
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
+
+ set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
+ if (set->set==NULL) {
+ DEBUG(0,("get_group_map_from_ntname: could not allocate memory for privileges\n"));
+ return False;
+ }
+
+ for (i=0; i<set->count; i++)
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd",
+ &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
+
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize) {
+ free_privilege(set);
+ continue;
+ }
+
+ if (StrCaseCmp(name, map->nt_name)==0) {
+ if (!with_priv)
+ free_privilege(&map->priv_set);
+ return True;
+ }
+
+ free_privilege(set);
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ remove a group mapping entry
+****************************************************************************/
+BOOL group_map_remove(DOM_SID sid)
+{
+ TDB_DATA kbuf, dbuf;
+ pstring key;
+ fstring string_sid;
+
+ init_group_mapping();
+
+ /* the key is the SID, retrieving is direct */
+
+ sid_to_string(string_sid, &sid);
+ slprintf(key, sizeof(key), "%s%s", GROUP_PREFIX, string_sid);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr) return False;
+
+ SAFE_FREE(dbuf.dptr);
+
+ if(tdb_delete(tdb, kbuf) != TDB_SUCCESS)
+ return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+enumerate the group mapping
+****************************************************************************/
+BOOL enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
+ int *num_entries, BOOL unix_only, BOOL with_priv)
+{
+ TDB_DATA kbuf, dbuf, newkey;
+ fstring string_sid;
+ fstring group_type;
+ GROUP_MAP map;
+ GROUP_MAP *mapt;
+ int ret;
+ int entries=0;
+ int i;
+ PRIVILEGE_SET *set;
+
+ init_group_mapping();
+
+ *num_entries=0;
+ *rmap=NULL;
+
+ for (kbuf = tdb_firstkey(tdb);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ if (strncmp(kbuf.dptr, GROUP_PREFIX, strlen(GROUP_PREFIX)) != 0)
+ continue;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr)
+ continue;
+
+ fstrcpy(string_sid, kbuf.dptr+strlen(GROUP_PREFIX));
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddffd",
+ &map.gid, &map.sid_name_use, &map.nt_name, &map.comment, &map.systemaccount);
+
+ set=&map.priv_set;
+ init_privilege(set);
+
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "d", &set->count);
+
+ if (set->count!=0) {
+ set->set=(LUID_ATTR *)malloc(set->count*sizeof(LUID_ATTR));
+ if (set->set==NULL) {
+ DEBUG(0,("enum_group_mapping: could not allocate memory for privileges\n"));
+ return False;
+ }
+ }
+
+ for (i=0; i<set->count; i++)
+ ret += tdb_unpack(dbuf.dptr+ret, dbuf.dsize-ret, "ddd",
+ &(set->set[i].luid.low), &(set->set[i].luid.high), &(set->set[i].attr));
+
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize) {
+ DEBUG(11,("enum_group_mapping: error in memory size\n"));
+ free_privilege(set);
+ continue;
+ }
+
+ /* list only the type or everything if UNKNOWN */
+ if (sid_name_use!=SID_NAME_UNKNOWN && sid_name_use!=map.sid_name_use) {
+ DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
+ free_privilege(set);
+ continue;
+ }
+
+ if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
+ DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
+ free_privilege(set);
+ continue;
+ }
+
+ string_to_sid(&map.sid, string_sid);
+
+ decode_sid_name_use(group_type, map.sid_name_use);
+ DEBUG(11,("enum_group_mapping: returning group %s of type %s\n", map.nt_name ,group_type));
+
+ mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
+ if (!mapt) {
+ DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
+ SAFE_FREE(*rmap);
+ free_privilege(set);
+ return False;
+ }
+ else
+ (*rmap) = mapt;
+
+ mapt[entries].gid = map.gid;
+ sid_copy( &mapt[entries].sid, &map.sid);
+ mapt[entries].sid_name_use = map.sid_name_use;
+ fstrcpy(mapt[entries].nt_name, map.nt_name);
+ fstrcpy(mapt[entries].comment, map.comment);
+ mapt[entries].systemaccount=map.systemaccount;
+ mapt[entries].priv_set.count=set->count;
+ mapt[entries].priv_set.control=set->control;
+ mapt[entries].priv_set.set=set->set;
+ if (!with_priv)
+ free_privilege(&(mapt[entries].priv_set));
+
+ entries++;
+ }
+
+ *num_entries=entries;
+ return True;
+}
+
+
+/****************************************************************************
+convert a privilege string to a privilege array
+****************************************************************************/
+void convert_priv_from_text(PRIVILEGE_SET *se_priv, char *privilege)
+{
+ pstring tok;
+ char *p = privilege;
+ int i;
+ LUID_ATTR set;
+
+ /* By default no privilege */
+ init_privilege(se_priv);
+
+ if (privilege==NULL)
+ return;
+
+ while(next_token(&p, tok, " ", sizeof(tok)) ) {
+ for (i=0; i<=PRIV_ALL_INDEX; i++) {
+ if (StrCaseCmp(privs[i].priv, tok)==0) {
+ set.attr=0;
+ set.luid.high=0;
+ set.luid.low=privs[i].se_priv;
+ add_privilege(se_priv, set);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+convert a privilege array to a privilege string
+****************************************************************************/
+void convert_priv_to_text(PRIVILEGE_SET *se_priv, char *privilege)
+{
+ int i,j;
+
+ if (privilege==NULL)
+ return;
+
+ ZERO_STRUCTP(privilege);
+
+ if (check_empty_privilege(se_priv)) {
+ fstrcat(privilege, "No privilege");
+ return;
+ }
+
+ for(i=0; i<se_priv->count; i++) {
+ j=1;
+ while (privs[j].se_priv!=se_priv->set[i].luid.low && j<=PRIV_ALL_INDEX) {
+ j++;
+ }
+
+ fstrcat(privilege, privs[j].priv);
+ fstrcat(privilege, " ");
+ }
+}
+
+
+/*
+ *
+ * High level functions
+ * better to use them than the lower ones.
+ *
+ * we are checking if the group is in the mapping file
+ * and if the group is an existing unix group
+ *
+ */
+
+/* get a domain group from it's SID */
+
+BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
+{
+ struct group *grp;
+
+ DEBUG(10, ("get_domain_group_from_sid\n"));
+
+ /* if the group is NOT in the database, it CAN NOT be a domain group */
+ if(!get_group_map_from_sid(sid, map, with_priv))
+ return False;
+
+ DEBUG(10, ("get_domain_group_from_sid: SID found in the TDB\n"));
+
+ /* if it's not a domain group, continue */
+ if (map->sid_name_use!=SID_NAME_DOM_GRP) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: SID is a domain group\n"));
+
+ if (map->gid==-1) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: SID is mapped to gid:%d\n",map->gid));
+
+ if ( (grp=getgrgid(map->gid)) == NULL) {
+ DEBUG(10, ("get_domain_group_from_sid: gid DOESN'T exist in UNIX security\n"));
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ DEBUG(10, ("get_domain_group_from_sid: gid exists in UNIX security\n"));
+
+ return True;
+}
+
+
+/* get a local (alias) group from it's SID */
+
+BOOL get_local_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
+{
+ struct group *grp;
+
+ /* The group is in the mapping table */
+ if(get_group_map_from_sid(sid, map, with_priv)) {
+ if (map->sid_name_use!=SID_NAME_ALIAS) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ if (map->gid==-1) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ if ( (grp=getgrgid(map->gid)) == NULL) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+ } else {
+ /* the group isn't in the mapping table.
+ * make one based on the unix information */
+ uint32 alias_rid;
+
+ sid_peek_rid(&sid, &alias_rid);
+ map->gid=pdb_group_rid_to_gid(alias_rid);
+
+ if ((grp=getgrgid(map->gid)) == NULL)
+ return False;
+
+ map->sid_name_use=SID_NAME_ALIAS;
+ map->systemaccount=PR_ACCESS_FROM_NETWORK;
+
+ fstrcpy(map->nt_name, grp->gr_name);
+ fstrcpy(map->comment, "Local Unix Group");
+
+ init_privilege(&map->priv_set);
+
+ sid_copy(&map->sid, &sid);
+ }
+
+ return True;
+}
+
+/* get a builtin group from it's SID */
+
+BOOL get_builtin_group_from_sid(DOM_SID sid, GROUP_MAP *map, BOOL with_priv)
+{
+ struct group *grp;
+
+ if(!get_group_map_from_sid(sid, map, with_priv))
+ return False;
+
+ if (map->sid_name_use!=SID_NAME_WKN_GRP) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ if (map->gid==-1) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ if ( (grp=getgrgid(map->gid)) == NULL) {
+ if (with_priv)
+ free_privilege(&map->priv_set);
+ return False;
+ }
+
+ return True;
+}
+
+
+
+/****************************************************************************
+Returns a GROUP_MAP struct based on the gid.
+****************************************************************************/
+BOOL get_group_from_gid(gid_t gid, GROUP_MAP *map, BOOL with_priv)
+{
+ struct group *grp;
+
+ if ( (grp=getgrgid(gid)) == NULL)
+ return False;
+
+ /*
+ * make a group map from scratch if doesn't exist.
+ */
+ if (!get_group_map_from_gid(gid, map, with_priv)) {
+ map->gid=gid;
+ map->sid_name_use=SID_NAME_ALIAS;
+ map->systemaccount=PR_ACCESS_FROM_NETWORK;
+ init_privilege(&map->priv_set);
+
+ /* interim solution until we have a last RID allocated */
+
+ sid_copy(&map->sid, &global_sam_sid);
+ sid_append_rid(&map->sid, pdb_gid_to_group_rid(gid));
+
+ fstrcpy(map->nt_name, grp->gr_name);
+ fstrcpy(map->comment, "Local Unix Group");
+ }
+
+ return True;
+}
+
+
+
+
+/****************************************************************************
+ Get the member users of a group and
+ all the users who have that group as primary.
+
+ give back an array of uid
+ return the grand number of users
+
+
+ TODO: sort the list and remove duplicate. JFM.
+
+****************************************************************************/
+
+BOOL get_uid_list_of_group(gid_t gid, uid_t **uid, int *num_uids)
+{
+ struct group *grp;
+ struct passwd *pwd;
+ int i=0;
+ char *gr;
+ uid_t *u;
+
+ *num_uids = 0;
+ *uid=NULL;
+
+ if ( (grp=getgrgid(gid)) == NULL)
+ return False;
+
+ gr = grp->gr_mem[0];
+ DEBUG(10, ("getting members\n"));
+
+ while (gr && (*gr != (char)'\0')) {
+ u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
+ if (!u) {
+ DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
+ return False;
+ }
+ else (*uid) = u;
+
+ if( (pwd=getpwnam(gr)) !=NULL) {
+ (*uid)[*num_uids]=pwd->pw_uid;
+ (*num_uids)++;
+ }
+ gr = grp->gr_mem[++i];
+ }
+ DEBUG(10, ("got [%d] members\n", *num_uids));
+
+ setpwent();
+ while ((pwd=getpwent()) != NULL) {
+ if (pwd->pw_gid==gid) {
+ u = Realloc((*uid), sizeof(uid_t)*(*num_uids+1));
+ if (!u) {
+ DEBUG(0,("get_uid_list_of_group: unable to enlarge uid list!\n"));
+ return False;
+ }
+ else (*uid) = u;
+ (*uid)[*num_uids]=pwd->pw_uid;
+
+ (*num_uids)++;
+ }
+ }
+ endpwent();
+ DEBUG(10, ("got primary groups, members: [%d]\n", *num_uids));
+
+ return True;
+}
+
+/****************************************************************************
+ Create a UNIX group on demand.
+****************************************************************************/
+
+int smb_create_group(char *unix_group)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_addgroup_script());
+ if (! *add_script) return -1;
+ pstring_sub(add_script, "%g", unix_group);
+ ret = smbrun(add_script,NULL);
+ DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX group on demand.
+****************************************************************************/
+
+int smb_delete_group(char *unix_group)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_delgroup_script());
+ if (! *del_script) return -1;
+ pstring_sub(del_script, "%g", unix_group);
+ ret = smbrun(del_script,NULL);
+ DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Create a UNIX group on demand.
+****************************************************************************/
+
+int smb_add_user_group(char *unix_group, char *unix_user)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_addusertogroup_script());
+ if (! *add_script) return -1;
+ pstring_sub(add_script, "%g", unix_group);
+ pstring_sub(add_script, "%u", unix_user);
+ ret = smbrun(add_script,NULL);
+ DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX group on demand.
+****************************************************************************/
+
+int smb_delete_user_group(char *unix_group, char *unix_user)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluserfromgroup_script());
+ if (! *del_script) return -1;
+ pstring_sub(del_script, "%g", unix_group);
+ pstring_sub(del_script, "%u", unix_user);
+ ret = smbrun(del_script,NULL);
+ DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+
+
diff --git a/source/include/.cvsignore b/source/include/.cvsignore
new file mode 100644
index 00000000000..b07cf4c2c43
--- /dev/null
+++ b/source/include/.cvsignore
@@ -0,0 +1,4 @@
+build_env.h
+config.h
+stamp-h
+proto.h
diff --git a/source/include/MacExtensions.h b/source/include/MacExtensions.h
new file mode 100644
index 00000000000..1c57690ba47
--- /dev/null
+++ b/source/include/MacExtensions.h
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) John H Terpstra 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef _MAC_EXTENSIONS_H
+#define _MAC_EXTENSIONS_H
+
+/* Folder that holds the stream info */
+#define STREAM_FOLDER ".streams"
+#define STREAM_FOLDER_SLASH ".streams/"
+
+/* Common Streams Names*/
+#define DefaultStreamTestLen 6
+#define DefaultStreamTest ":$DATA"
+#define AFPDATA_STREAM "::$DATA"
+#define AFPINFO_STREAM ":AFP_AfpInfo:$DATA"
+#define AFPRESOURCE_STREAM ":AFP_Resource:$DATA"
+#define AFPCOMMENTS_STREAM ":Comments:$DATA"
+#define AFPDESKTOP_STREAM ":AFP_DeskTop:$DATA"
+#define AFPIDINDEX_STREAM ":AFP_IdIndex:$DATA"
+
+/*
+** NT's AFP_AfpInfo stream structure
+*/
+#define APF_INFO_SIZE 0x3c
+#define AFP_Signature 0x41465000
+#define AFP_Version 0x00000100
+#define AFP_BackupTime 0x00000080
+#define AFP_FinderSize 32
+/*
+** Orginal AFP_AfpInfo stream used by NT
+** We needed a way to store the create date so SAMBA
+** AFP_AfpInfo adds for bytes to this structrure
+** and call's it _SambaAfpInfo
+*/
+typedef struct _AfpInfo
+{
+ uint32 afpi_Signature; /* Must be *(PDWORD)"AFP" */
+ uint32 afpi_Version; /* Must be 0x00010000 */
+ uint32 afpi_Reserved1;
+ uint32 afpi_BackupTime; /* Backup time for the file/dir */
+ unsigned char afpi_FinderInfo[AFP_FinderSize]; /* Finder Info (32 bytes) */
+ unsigned char afpi_ProDosInfo[6]; /* ProDos Info (6 bytes) # */
+ unsigned char afpi_Reserved2[6];
+} AfpInfo;
+
+typedef struct _SambaAfpInfo
+{
+ AfpInfo afp;
+ unsigned long createtime;
+} SambaAfpInfo;
+
+/*
+** On SAMBA this structrue is followed by 4 bytes that store the create
+** date of the file or folder asociated with it.
+*/
+
+/*
+** These extentions are only supported with the NT LM 0.12 Dialect. These extentions
+** will be process on a share by share bases.
+*/
+
+/*
+** Trans2_Query_FS_Information Call is used by the MacCIFS extentions for three reasons.
+** First to see if the remote server share supports the basic Macintosh CIFS extentions.
+** Second to return some basic need information about the share to the Macintosh.
+** Third to see if this share support any other Macintosh extentions.
+**
+** We will be using infromation levels that are betwwen 0x300 and 0x399 for all Macintosh
+** extentions calls. The first of these will be the SMB_MAC_QUERY_FS_INFO level which
+** will allow the server to return the MacQueryFSInfo structure. All feilds are Little
+** Endian unless other wise specified.
+*/
+#define SMB_MAC_QUERY_FS_INFO 0x301
+
+
+
+/*
+** The server will return folder access control in the Trans2_Find_First2
+** and Trans2_Find_Next2 message described later in this document.
+*/
+#define SUPPORT_MAC_ACCESS_CNTRL 0x0010
+/*
+** The server supports setting/getting comments using the mechanism in this
+** document instead of using the NTFS format described in the Introduction.
+*/
+#define SUPPORT_MAC_GETSETCOMMENTS 0x0020
+/*
+** The Server supports setting and getting Macintosh desktop database information
+** using the mechanism in this document.
+*/
+#define SUPPORT_MAC_DESKTOPDB_CALLS 0x0040
+/*
+** The server will return a unique id for files and directories in the
+** Trans2_Find_First2 and Trans2_Find_Next2 message described later in this document.
+*/
+#define SUPPORT_MAC_UNIQUE_IDS 0x0080
+/*
+** The server will return this flag telling the client that the server does
+** not support streams or the Macintosh extensions. The rest of this message
+** will be ignored by the client.
+*/
+#define NO_STREAMS_OR_MAC_SUPPORT 0x0100
+
+/*
+** We will be adding a new info level to the Trans2_Find_First2 and Trans2_Find_Next2.
+** This info level will be SMB_MAC_FIND_BOTH_HFS_INFO and will support the server
+** return additional information need by the Macintosh. All fields are Little
+** Endian unless other wise specified.
+*/
+
+#define SMB_MAC_FIND_BOTH_HFS_INFO 0x302
+
+enum {
+ ownerRead = 0x0400,
+ ownerWrite = 0x0200,
+ ownerSearch = 0x0100,
+ groupRead = 0x0040,
+ groupWrite = 0x0020,
+ groupSearch = 0x0010,
+ otherRead = 0x0004,
+ otherWrite = 0x0002,
+ otherSearch = 0x0001,
+ Owner = 0x0800
+};
+
+
+/*
+** We will be adding a new info level to the Trans2_Set_Path_Information.
+** This info level will be SMB_MAC_SET_FINDER_INFO and will support the client
+** setting information on the server need by the Macintosh. All fields are Little
+** Endian unless other wise specified.
+*/
+
+#define SMB_MAC_SET_FINDER_INFO 0x303
+
+enum {
+ SetCreateDate = 0x01, /* If this is set then set the create date of the file/folder */
+ SetModDate = 0x02, /* If this is set then set the modify date of the file/folder */
+ SetFLAttrib = 0x04, /* If this is set then set the Macintosh lock bit of the file/folder */
+ FndrInfo1 = 0x08, /* If this is set then set the first 16 bytes of finder info */
+ FndrInfo2 = 0x10, /* If this is set then set the second 16 bytes of finder info */
+ SetHidden = 0x20 /* We are either setting or unsetting the hidden bit */
+};
+
+
+/*
+** We will be adding some new info level to the Trans2_Set_Path_Information and Trans2_Query_Path_Information.
+** These info levels will allow the client to add, get, and remove desktop inforamtion from the
+** server. How the server stores this information is up to them.
+*/
+
+/*
+** We need to be able to store an application name and its creator in a database. We send a
+** Trans2_Set_Path_Information call with the full path of the application in the path field.
+** We will send an info level that represents adding an application name and creator to the database.
+** We will pass the File Creator in the data message.
+**
+** The server should just respond with no error or an error.
+*/
+#define SMB_MAC_DT_ADD_APPL 0x304
+
+/*
+** We need to be able to remove an application name and its creator from a database. We send a
+** Trans2_Set_Path_Information call with the full path of the application in the path field.
+** We will send an info level that represents removing an application name and creator from the database.
+** We will pass the File Creator in the data message.
+**
+** The server should just respond with no error or an error.
+*/
+#define SMB_MAC_DT_REMOVE_APPL 0x305
+
+
+/*
+** We need to be able to get an application name and its creator from a database. We send a
+** Trans2_Query_Path_Information call in which the name field is just ignore.
+** We will send an info level that represents getting an application name with a structure that
+** contains the File Creator and index. Were index has the following meaning.
+** Index = 0; Get the application path from the database with the most current date.
+** Index > 0; Use the index to find the application path from the database.
+** e.g. index of 5 means get the fifth entry of this application name in the database.
+** if not entry return an error.
+**
+** The server returns with a structure that contains the full path to the appication and
+** its creator's date.
+*/
+#define SMB_MAC_DT_GET_APPL 0x306
+
+
+/*
+** We need to be able to get an icon from a database. We send a Trans2_Query_Path_Information call in
+** which the path name is ignore. We will send an info level that represents getting an icon with a structure
+** that contains the Requested size of the icon, the Icon type, File Creator, and File Type.
+**
+** The server returns with a structure that contains the actual size of the icon
+** (must be less than requested length) and the icon bit map.
+*/
+#define SMB_MAC_DT_GET_ICON 0x307
+
+
+/*
+** We need to be able to get an icon from a database. We send a Trans2_Query_Path_Information call in
+** which the path name is ignore. We will send an info level that represents getting an icon with a structure
+** that contains the index and File Creator. The index allows the client to make repeated calls to the server
+** gathering all icon stored by this file creator.
+**
+**
+** The server returns with a structure that contains the actual size of the icon
+** (must be less than requested length) and the icon bit map, File Type, and Icon Type.
+*/
+#define SMB_MAC_DT_GET_ICON_INFO 0x308
+
+
+
+/*
+** We need to be able to add an icon to a database. We send a Trans2_Set_Path_Information call in
+** which the path name is ignore. We will send an info level that represents setting an icon with a structure
+** that contains the icon data, icon size, icon type, the file type, and file creator.
+**
+**
+** The server returns only that the call was succesfull or not.
+*/
+#define SMB_MAC_DT_ADD_ICON 0x309
+
+#endif /* _MAC_EXTENSIONS_H */
+
+/* _MAC_EXTENSIONS_H */
+
diff --git a/source/include/ads.h b/source/include/ads.h
new file mode 100644
index 00000000000..884f2aa6ef7
--- /dev/null
+++ b/source/include/ads.h
@@ -0,0 +1,64 @@
+/*
+ header for ads (active directory) library routines
+
+ basically this is a wrapper around ldap
+*/
+
+typedef struct {
+ void *ld;
+ char *realm;
+ char *ldap_server;
+ char *ldap_server_name;
+ char *kdc_server;
+ int ldap_port;
+ char *bind_path;
+ time_t last_attempt;
+ char *password;
+ char *user_name;
+ char *server_realm;
+} ADS_STRUCT;
+
+/* there are 4 possible types of errors the ads subsystem can produce */
+enum ads_error_type {ADS_ERROR_KRB5, ADS_ERROR_GSS,
+ ADS_ERROR_LDAP, ADS_ERROR_SYSTEM};
+
+typedef struct {
+ enum ads_error_type error_type;
+ int rc;
+ /* For error_type = ADS_ERROR_GSS minor_status describe GSS API error */
+ /* Where rc represents major_status of GSS API error */
+ int minor_status;
+} ADS_STATUS;
+
+/* macros to simplify error returning */
+#define ADS_ERROR(rc) ads_build_error(ADS_ERROR_LDAP, rc, 0);
+#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc, 0);
+#define ADS_ERROR_KRB5(rc) ads_build_error(ADS_ERROR_KRB5, rc, 0);
+#define ADS_ERROR_GSS(rc, minor) ads_build_error(ADS_ERROR_GSS, rc, minor);
+
+#define ADS_ERR_OK(status) ((status).rc == 0)
+#define ADS_SUCCESS ADS_ERROR(0)
+
+/* time between reconnect attempts */
+#define ADS_RECONNECT_TIME 5
+
+/* timeout on searches */
+#define ADS_SEARCH_TIMEOUT 10
+
+#define UF_DONT_EXPIRE_PASSWD 0x10000
+#define UF_MNS_LOGON_ACCOUNT 0x20000
+#define UF_SMARTCARD_REQUIRED 0x40000
+#define UF_TRUSTED_FOR_DELEGATION 0x80000
+#define UF_NOT_DELEGATED 0x100000
+#define UF_USE_DES_KEY_ONLY 0x200000
+#define UF_DONT_REQUIRE_PREAUTH 0x400000
+
+#define UF_TEMP_DUPLICATE_ACCOUNT 0x0100
+#define UF_NORMAL_ACCOUNT 0x0200
+#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x0800
+#define UF_WORKSTATION_TRUST_ACCOUNT 0x1000
+#define UF_SERVER_TRUST_ACCOUNT 0x2000
+
+/* account types */
+#define ATYPE_GROUP 0x10000000
+#define ATYPE_USER 0x30000000
diff --git a/source/include/asn1.h b/source/include/asn1.h
new file mode 100644
index 00000000000..ae3cd22dde9
--- /dev/null
+++ b/source/include/asn1.h
@@ -0,0 +1,54 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ simple ASN1 code
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+struct nesting {
+ off_t start;
+ size_t taglen; /* for parsing */
+ struct nesting *next;
+};
+
+typedef struct {
+ uint8 *data;
+ size_t length;
+ off_t ofs;
+ struct nesting *nesting;
+ BOOL has_error;
+} ASN1_DATA;
+
+
+#define ASN1_APPLICATION(x) ((x)+0x60)
+#define ASN1_SEQUENCE(x) ((x)+0x30)
+#define ASN1_CONTEXT(x) ((x)+0xa0)
+#define ASN1_GENERAL_STRING 0x1b
+#define ASN1_OCTET_STRING 0x4
+#define ASN1_OID 0x6
+#define ASN1_BOOLEAN 0x1
+#define ASN1_INTEGER 0x2
+#define ASN1_ENUMERATED 0xa
+
+#define ASN1_MAX_OIDS 20
+
+/* some well known object IDs */
+#define OID_SPNEGO "1 3 6 1 5 5 2"
+#define OID_NTLMSSP "1 3 6 1 4 1 311 2 2 10"
+#define OID_KERBEROS5_OLD "1 2 840 48018 1 2 2"
+#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
diff --git a/source/include/auth.h b/source/include/auth.h
new file mode 100644
index 00000000000..270b8d388ab
--- /dev/null
+++ b/source/include/auth.h
@@ -0,0 +1,135 @@
+#ifndef _SMBAUTH_H_
+#define _SMBAUTH_H_
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ Standardised Authentication types
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* AUTH_STR - string */
+typedef struct normal_string
+{
+ int len;
+ char *str;
+} AUTH_STR;
+
+/* AUTH_UNISTR - unicode string or buffer */
+typedef struct unicode_string
+{
+ int len;
+ uchar *unistr;
+} AUTH_UNISTR;
+
+typedef struct interactive_password
+{
+ OWF_INFO lm_owf; /* LM OWF Password */
+ OWF_INFO nt_owf; /* NT OWF Password */
+} auth_interactive_password;
+
+typedef struct usersupplied_info
+{
+
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ auth_interactive_password * interactive_password;
+ DATA_BLOB plaintext_password;
+
+ BOOL encrypted;
+
+ uint32 ntlmssp_flags;
+
+ AUTH_STR client_domain; /* domain name string */
+ AUTH_STR domain; /* domain name after mapping */
+ AUTH_STR internal_username; /* username after mapping */
+ AUTH_STR smb_name; /* username before mapping */
+ AUTH_STR wksta_name; /* workstation name (netbios calling name) unicode string */
+
+} auth_usersupplied_info;
+
+#define SAM_FILL_NAME 0x01
+#define SAM_FILL_INFO3 0x02
+#define SAM_FILL_SAM 0x04
+#define SAM_FILL_UNIX 0x08
+#define SAM_FILL_ALL (SAM_FILL_NAME | SAM_FILL_INFO3 | SAM_FILL_SAM | SAM_FILL_UNIX)
+
+typedef struct serversupplied_info
+{
+ BOOL guest;
+
+ /* This groups info is needed for when we become_user() for this uid */
+ int n_groups;
+ gid_t *groups;
+
+ /* NT group information taken from the info3 structure */
+
+ NT_USER_TOKEN *ptok;
+
+ uchar session_key[16];
+
+ uint8 first_8_lm_hash[8];
+
+ uint32 sam_fill_level; /* How far is this structure filled? */
+
+ SAM_ACCOUNT *sam_account;
+
+ void *pam_handle;
+
+} auth_serversupplied_info;
+
+typedef struct authsupplied_info {
+ DATA_BLOB challenge;
+
+ /* Who set this up in the first place? */
+ char *challenge_set_by; \
+
+ struct auth_methods *challenge_set_method;
+ /* What order are the various methods in? Try to stop it changing under us */
+ struct auth_methods *auth_method_list;
+} auth_authsupplied_info;
+
+typedef struct auth_methods
+{
+ struct auth_methods *prev, *next;
+ char *name; /* What name got this module */
+
+ NTSTATUS (*auth)(void *my_private_data,
+ const auth_usersupplied_info *user_info,
+ const struct authsupplied_info *auth_info,
+ auth_serversupplied_info **server_info);
+
+ DATA_BLOB (*get_chal)(void **my_private_data, const struct authsupplied_info *auth_info);
+
+ /* Used to keep tabs on things like the cli for SMB server authentication */
+ void *private_data;
+
+ /* Function to clean up the above arbitary structure */
+ void (*free_private_data)(void **private_data);
+
+ /* Function to send a keepalive message on the above structure */
+ void (*send_keepalive)(void **private_data);
+
+} auth_methods;
+
+typedef struct auth_init_function {
+ char *name;
+ /* Function to create a member of the authmethods list */
+ BOOL (*init)(struct auth_methods **auth_method);
+} auth_init_function;
+
+
+#endif /* _SMBAUTH_H_ */
diff --git a/source/include/byteorder.h b/source/include/byteorder.h
index 899cd6c4991..e6cce73cebf 100644
--- a/source/include/byteorder.h
+++ b/source/include/byteorder.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB Byte handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,9 +19,79 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
/*
This file implements macros for machine independent short and
int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16 that is in the local machines byte order, and you
+want to do it with only the assumption that uint16 is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16 value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16 xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
*/
#undef CAREFUL_ALIGNMENT
@@ -42,6 +112,7 @@
#if CAREFUL_ALIGNMENT
+
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
@@ -52,29 +123,45 @@
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
-#else
+
+#else /* CAREFUL_ALIGNMENT */
+
/* this handles things for architectures like the 386 that can handle
alignment errors */
/*
WARNING: This section is dependent on the length of int16 and int32
being correct
*/
+
+/* get single value from an SMB buffer */
#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+
+/* store single value in an SMB buffer */
#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
-#endif
+#endif /* CAREFUL_ALIGNMENT */
/* now the reverse routines - these are used in nmb packets (mostly) */
#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
+
+/* Alignment macros. */
+#define ALIGN4(p,base) ((p) + ((4 - (PTR_DIFF((p), (base)) & 3)) & 3))
+#define ALIGN2(p,base) ((p) + ((2 - (PTR_DIFF((p), (base)) & 1)) & 1))
+
+#endif /* _BYTEORDER_H */
diff --git a/source/include/charset.h b/source/include/charset.h
index 7091732223a..3221349f4a8 100644
--- a/source/include/charset.h
+++ b/source/include/charset.h
@@ -1,8 +1,8 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
- Character set handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Version 3.0
+ charset defines
+ Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,43 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef CHARSET_C
-
-extern char *dos_char_map;
-extern char *upper_char_map;
-extern char *lower_char_map;
-extern void add_char_string(char *s);
-extern void charset_initialise(void);
-
-#ifdef toupper
-#undef toupper
-#endif
-
-#ifdef tolower
-#undef tolower
-#endif
-
-#ifdef isupper
-#undef isupper
-#endif
-
-#ifdef islower
-#undef islower
-#endif
-
-#ifdef isdoschar
-#undef isdoschar
-#endif
-
-#ifdef isspace
-#undef isspace
-#endif
-
-#define toupper(c) upper_char_map[(char)(c)]
-#define tolower(c) lower_char_map[(char)(c)]
-#define isupper(c) (((char)(c)) != tolower(c))
-#define islower(c) (((char)(c)) != toupper(c))
-#define isdoschar(c) (dos_char_map[(char)(c)] != 0)
-#define isspace(c) ((c)==' ' || (c) == '\t')
-#endif
+/* this defines the charset types used in samba */
+typedef enum {CH_UCS2=0, CH_UNIX=1, CH_DISPLAY=2, CH_DOS=3} charset_t;
+#define NUM_CHARSETS 4
diff --git a/source/include/client.h b/source/include/client.h
new file mode 100644
index 00000000000..fde001813d3
--- /dev/null
+++ b/source/include/client.h
@@ -0,0 +1,147 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Jeremy Allison 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+/* the client asks for a smaller buffer to save ram and also to get more
+ overlap on the wire. This size gives us a nice read/write size, which
+ will be a multiple of the page size on almost any system */
+#define CLI_BUFFER_SIZE (0xFFFF)
+
+
+/*
+ * These definitions depend on smb.h
+ */
+
+typedef struct file_info
+{
+ SMB_OFF_T size;
+ uint16 mode;
+ uid_t uid;
+ gid_t gid;
+ /* these times are normally kept in GMT */
+ time_t mtime;
+ time_t atime;
+ time_t ctime;
+ pstring name;
+ char short_name[13*3]; /* the *3 is to cope with multi-byte */
+} file_info;
+
+struct print_job_info
+{
+ uint16 id;
+ uint16 priority;
+ size_t size;
+ fstring user;
+ fstring name;
+ time_t t;
+};
+
+struct cli_state {
+ int port;
+ int fd;
+ uint16 cnum;
+ uint16 pid;
+ uint16 mid;
+ uint16 vuid;
+ int protocol;
+ int sec_mode;
+ int rap_error;
+ int privileges;
+
+ fstring eff_name;
+ fstring desthost;
+ fstring user_name;
+ fstring domain;
+
+ /*
+ * The following strings are the
+ * ones returned by the server if
+ * the protocol > NT1.
+ */
+ fstring server_type;
+ fstring server_os;
+ fstring server_domain;
+
+ fstring share;
+ fstring dev;
+ struct nmb_name called;
+ struct nmb_name calling;
+ fstring full_dest_host_name;
+ struct in_addr dest_ip;
+
+ struct pwd_info pwd;
+ DATA_BLOB secblob; /* cryptkey or negTokenInit */
+ uint32 sesskey;
+ int serverzone;
+ uint32 servertime;
+ int readbraw_supported;
+ int writebraw_supported;
+ int timeout; /* in milliseconds. */
+ int max_xmit;
+ int max_mux;
+ char *outbuf;
+ char *inbuf;
+ int bufsize;
+ int initialised;
+ int win95;
+ uint32 capabilities;
+
+ TALLOC_CTX *mem_ctx;
+
+ /*
+ * Only used in NT domain calls.
+ */
+
+ uint16 nt_pipe_fnum; /* Pipe handle. */
+ unsigned char sess_key[16]; /* Current session key. */
+ unsigned char ntlmssp_hash[258]; /* ntlmssp data. */
+ uint32 ntlmssp_cli_flgs; /* ntlmssp client flags */
+ uint32 ntlmssp_srv_flgs; /* ntlmssp server flags */
+ uint32 ntlmssp_seq_num; /* ntlmssp sequence number */
+ DOM_CRED clnt_cred; /* Client credential. */
+ fstring mach_acct; /* MYNAME$. */
+ fstring srv_name_slash; /* \\remote server. */
+ fstring clnt_name_slash; /* \\local client. */
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+ vuser_key key;
+ uint32 ntlmssp_flags;
+ BOOL use_kerberos;
+ BOOL use_spnego;
+
+ BOOL use_oplocks; /* should we use oplocks? */
+ BOOL use_level_II_oplocks; /* should we use level II oplocks? */
+
+ /* a oplock break request handler */
+ BOOL (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level);
+
+ BOOL force_dos_errors;
+
+ /* was this structure allocated by cli_initialise? If so, then
+ free in cli_shutdown() */
+ BOOL allocated;
+};
+
+#endif /* _CLIENT_H */
diff --git a/source/include/clitar.h b/source/include/clitar.h
index 2305fceeec7..ad76191fb75 100644
--- a/source/include/clitar.h
+++ b/source/include/clitar.h
@@ -1,3 +1,26 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 3.0
+ * clitar file format
+ * Copyright (C) Andrew Tridgell 2000
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CLITAR_H
+#define _CLITAR_H
#define TBLOCK 512
#define NAMSIZ 100
@@ -15,3 +38,5 @@ union hblock {
char linkname[NAMSIZ];
} dbuf;
};
+
+#endif /* _CLITAR_H */
diff --git a/source/include/config.h.in b/source/include/config.h.in
new file mode 100644
index 00000000000..1c22c0b5e59
--- /dev/null
+++ b/source/include/config.h.in
@@ -0,0 +1,1093 @@
+/* include/config.h.in. Generated automatically from configure.in by autoheader 2.13. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if type char is unsigned and you are not using gcc. */
+#ifndef __CHAR_UNSIGNED__
+#undef __CHAR_UNSIGNED__
+#endif
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define if your struct stat has st_rdev. */
+#undef HAVE_ST_RDEV
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define as __inline if that's what the C compiler calls it. */
+#undef inline
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if you need to in order for stat and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+#undef HAVE_VOLATILE
+#undef HAVE_BROKEN_READDIR
+#undef HAVE_C99_VSNPRINTF
+#undef HAVE_ERRNO_DECL
+#undef HAVE_LONGLONG
+#undef HAVE_OFF64_T
+#undef HAVE_REMSH
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UTIMBUF
+#undef HAVE_SIG_ATOMIC_T_TYPE
+#undef HAVE_SOCKLEN_T_TYPE
+#undef ssize_t
+#undef ino_t
+#undef ssize_t
+#undef loff_t
+#undef offset_t
+#undef aclent_t
+#undef wchar_t
+#undef HAVE_CONNECT
+#undef HAVE_SHORT_INO_T
+#undef WITH_SMBWRAPPER
+#undef WITH_AFS
+#undef WITH_DFS
+#undef SUNOS5
+#undef SUNOS4
+#undef LINUX
+#undef AIX
+#undef BSD
+#undef IRIX
+#undef IRIX6
+#undef HPUX
+#undef QNX
+#undef SCO
+#undef OSF1
+#undef NEXT2
+#undef RELIANTUNIX
+#undef HAVE_MMAP
+#undef HAVE_FCNTL_LOCK
+#undef HAVE_FTRUNCATE_EXTEND
+#undef FTRUNCATE_NEEDS_ROOT
+#undef HAVE_TRAPDOOR_UID
+#undef HAVE_ROOT
+#undef HAVE_GETTIMEOFDAY_TZ
+#undef HAVE_SOCK_SIN_LEN
+#undef STAT_READ_FILSYS
+#undef STAT_STATFS2_BSIZE
+#undef STAT_STATFS2_FSIZE
+#undef STAT_STATFS2_FS_DATA
+#undef STAT_STATFS3_OSF1
+#undef STAT_STATFS4
+#undef STAT_STATVFS
+#undef STAT_STATVFS64
+#undef HAVE_IFACE_AIX
+#undef HAVE_IFACE_IFCONF
+#undef HAVE_IFACE_IFREQ
+#undef HAVE_CRYPT
+#undef HAVE_PUTPRPWNAM
+#undef HAVE_SET_AUTH_PARAMETERS
+#undef WITH_SYSLOG
+#undef WITH_PROFILE
+#undef WITH_SSL
+#undef SSL_DIR
+#undef WITH_LDAP
+#undef WITH_NISPLUS
+#undef WITH_TDBPWD
+#undef WITH_PAM
+#undef WITH_NISPLUS_HOME
+#undef WITH_AUTOMOUNT
+#undef WITH_SMBMOUNT
+#undef WITH_QUOTAS
+#undef WITH_WINBIND
+#undef HAVE_BROKEN_GETGROUPS
+#undef REPLACE_GETPASS
+#undef REPLACE_INET_NTOA
+#undef HAVE_FILE_MACRO
+#undef HAVE_FUNCTION_MACRO
+#undef HAVE_SETRESUID_DECL
+#undef HAVE_SETRESUID
+#undef WITH_NETATALK
+#undef WITH_UTMP
+#undef WITH_MSDFS
+#undef WITH_LIBICONV
+#undef HAVE_INO64_T
+#undef HAVE_STRUCT_FLOCK64
+#undef SIZEOF_INO_T
+#undef SIZEOF_OFF_T
+#undef STAT_STATVFS64
+#undef HAVE_LIBREADLINE
+#undef HAVE_KERNEL_SHARE_MODES
+#undef HAVE_KERNEL_OPLOCKS_IRIX
+#undef HAVE_KERNEL_OPLOCKS_LINUX
+#undef HAVE_KERNEL_CHANGE_NOTIFY
+#undef HAVE_IRIX_SPECIFIC_CAPABILITIES
+#undef HAVE_INT16_FROM_RPC_RPC_H
+#undef HAVE_UINT16_FROM_RPC_RPC_H
+#undef HAVE_INT32_FROM_RPC_RPC_H
+#undef HAVE_UINT32_FROM_RPC_RPC_H
+#undef KRB4_AUTH
+#undef KRB5_AUTH
+#undef KRB4_DIR
+#undef KRB5_DIR
+#undef SEEKDIR_RETURNS_VOID
+#undef HAVE_DIRENT_D_OFF
+#undef HAVE_GETSPNAM
+#undef HAVE_BIGCRYPT
+#undef HAVE_GETPRPWNAM
+#undef HAVE_FSTAT64
+#undef HAVE_LSTAT64
+#undef HAVE_STAT64
+#undef HAVE_SETRESGID
+#undef HAVE_SETRESGID_DECL
+#undef HAVE_SHADOW_H
+#undef HAVE_CUPS
+#undef HAVE_MEMSET
+#undef HAVE_STRCASECMP
+#undef HAVE_STRUCT_DIRENT64
+#undef HAVE_TRUNCATED_SALT
+#undef BROKEN_NISPLUS_INCLUDE_FILES
+#undef HAVE_RPC_AUTH_ERROR_CONFLICT
+#undef HAVE_EXPLICIT_LARGEFILE_SUPPORT
+#undef USE_BOTH_CRYPT_CALLS
+#undef HAVE_BROKEN_FCNTL64_LOCKS
+#undef HAVE_SECURE_MKSTEMP
+#undef HAVE_FNMATCH
+#undef USE_SETEUID
+#undef USE_SETRESUID
+#undef USE_SETREUID
+#undef USE_SETUIDX
+#undef HAVE_LIBDL
+#undef SYSCONF_SC_NGROUPS_MAX
+#undef HAVE_UT_UT_NAME
+#undef HAVE_UT_UT_USER
+#undef HAVE_UT_UT_ID
+#undef HAVE_UT_UT_HOST
+#undef HAVE_UT_UT_TIME
+#undef HAVE_UT_UT_TV
+#undef HAVE_UT_UT_TYPE
+#undef HAVE_UT_UT_PID
+#undef HAVE_UT_UT_EXIT
+#undef HAVE_UT_UT_ADDR
+#undef HAVE_UX_UT_SYSLEN
+#undef PUTUTLINE_RETURNS_UTMP
+#undef COMPILER_SUPPORTS_LL
+#undef HAVE_YP_GET_DEFAULT_DOMAIN
+#undef USE_SPINLOCKS
+#undef SPARC_SPINLOCKS
+#undef INTEL_SPINLOCKS
+#undef MIPS_SPINLOCKS
+#undef POWERPC_SPINLOCKS
+#undef HAVE_POSIX_ACLS
+#undef HAVE_ACL_GET_PERM_NP
+#undef HAVE_UNIXWARE_ACLS
+#undef HAVE_SOLARIS_ACLS
+#undef HAVE_HPUX_ACLS
+#undef HAVE_IRIX_ACLS
+#undef HAVE_AIX_ACLS
+#undef HAVE_TRU64_ACLS
+#undef HAVE_NO_ACLS
+#undef HAVE_LIBPAM
+#undef HAVE_ASPRINTF_DECL
+#undef HAVE_VASPRINTF_DECL
+#undef HAVE_SNPRINTF_DECL
+#undef HAVE_VSNPRINTF_DECL
+#undef HAVE_NATIVE_ICONV
+#undef HAVE_UNIXSOCKET
+#undef MMAP_BLACKLIST
+#undef HAVE_IMMEDIATE_STRUCTURES
+#undef HAVE_CUPS
+#undef WITH_LDAP_SAM
+#undef WITH_NISPLUS_SAM
+#undef WITH_SMBPASSWD_SAM
+#undef WITH_TDB_SAM
+#undef LINUX_QUOTAS_1
+#undef LINUX_QUOTAS_2
+#undef PACKAGE
+#undef VERSION
+#undef HAVE_LC_MESSAGES
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_STPCPY
+#undef I18N_SWAT
+#undef I18N_DEFAULT_PREF_LANG
+#undef HAVE_KRB5
+#undef BROKEN_REDHAT_7_SYSTEM_HEADERS
+#undef HAVE_LDAP
+
+/* The number of bytes in a int. */
+#undef SIZEOF_INT
+
+/* The number of bytes in a long. */
+#undef SIZEOF_LONG
+
+/* The number of bytes in a short. */
+#undef SIZEOF_SHORT
+
+/* Define if you have the __acl function. */
+#undef HAVE___ACL
+
+/* Define if you have the __chdir function. */
+#undef HAVE___CHDIR
+
+/* Define if you have the __close function. */
+#undef HAVE___CLOSE
+
+/* Define if you have the __closedir function. */
+#undef HAVE___CLOSEDIR
+
+/* Define if you have the __dup function. */
+#undef HAVE___DUP
+
+/* Define if you have the __dup2 function. */
+#undef HAVE___DUP2
+
+/* Define if you have the __facl function. */
+#undef HAVE___FACL
+
+/* Define if you have the __fchdir function. */
+#undef HAVE___FCHDIR
+
+/* Define if you have the __fcntl function. */
+#undef HAVE___FCNTL
+
+/* Define if you have the __fork function. */
+#undef HAVE___FORK
+
+/* Define if you have the __fstat function. */
+#undef HAVE___FSTAT
+
+/* Define if you have the __fstat64 function. */
+#undef HAVE___FSTAT64
+
+/* Define if you have the __fxstat function. */
+#undef HAVE___FXSTAT
+
+/* Define if you have the __getcwd function. */
+#undef HAVE___GETCWD
+
+/* Define if you have the __getdents function. */
+#undef HAVE___GETDENTS
+
+/* Define if you have the __llseek function. */
+#undef HAVE___LLSEEK
+
+/* Define if you have the __lseek function. */
+#undef HAVE___LSEEK
+
+/* Define if you have the __lstat function. */
+#undef HAVE___LSTAT
+
+/* Define if you have the __lstat64 function. */
+#undef HAVE___LSTAT64
+
+/* Define if you have the __lxstat function. */
+#undef HAVE___LXSTAT
+
+/* Define if you have the __open function. */
+#undef HAVE___OPEN
+
+/* Define if you have the __open64 function. */
+#undef HAVE___OPEN64
+
+/* Define if you have the __opendir function. */
+#undef HAVE___OPENDIR
+
+/* Define if you have the __pread function. */
+#undef HAVE___PREAD
+
+/* Define if you have the __pread64 function. */
+#undef HAVE___PREAD64
+
+/* Define if you have the __pwrite function. */
+#undef HAVE___PWRITE
+
+/* Define if you have the __pwrite64 function. */
+#undef HAVE___PWRITE64
+
+/* Define if you have the __read function. */
+#undef HAVE___READ
+
+/* Define if you have the __readdir function. */
+#undef HAVE___READDIR
+
+/* Define if you have the __readdir64 function. */
+#undef HAVE___READDIR64
+
+/* Define if you have the __seekdir function. */
+#undef HAVE___SEEKDIR
+
+/* Define if you have the __stat function. */
+#undef HAVE___STAT
+
+/* Define if you have the __stat64 function. */
+#undef HAVE___STAT64
+
+/* Define if you have the __sys_llseek function. */
+#undef HAVE___SYS_LLSEEK
+
+/* Define if you have the __telldir function. */
+#undef HAVE___TELLDIR
+
+/* Define if you have the __write function. */
+#undef HAVE___WRITE
+
+/* Define if you have the __xstat function. */
+#undef HAVE___XSTAT
+
+/* Define if you have the _acl function. */
+#undef HAVE__ACL
+
+/* Define if you have the _chdir function. */
+#undef HAVE__CHDIR
+
+/* Define if you have the _close function. */
+#undef HAVE__CLOSE
+
+/* Define if you have the _closedir function. */
+#undef HAVE__CLOSEDIR
+
+/* Define if you have the _dup function. */
+#undef HAVE__DUP
+
+/* Define if you have the _dup2 function. */
+#undef HAVE__DUP2
+
+/* Define if you have the _facl function. */
+#undef HAVE__FACL
+
+/* Define if you have the _fchdir function. */
+#undef HAVE__FCHDIR
+
+/* Define if you have the _fcntl function. */
+#undef HAVE__FCNTL
+
+/* Define if you have the _fork function. */
+#undef HAVE__FORK
+
+/* Define if you have the _fstat function. */
+#undef HAVE__FSTAT
+
+/* Define if you have the _fstat64 function. */
+#undef HAVE__FSTAT64
+
+/* Define if you have the _getcwd function. */
+#undef HAVE__GETCWD
+
+/* Define if you have the _getdents function. */
+#undef HAVE__GETDENTS
+
+/* Define if you have the _llseek function. */
+#undef HAVE__LLSEEK
+
+/* Define if you have the _lseek function. */
+#undef HAVE__LSEEK
+
+/* Define if you have the _lstat function. */
+#undef HAVE__LSTAT
+
+/* Define if you have the _lstat64 function. */
+#undef HAVE__LSTAT64
+
+/* Define if you have the _open function. */
+#undef HAVE__OPEN
+
+/* Define if you have the _open64 function. */
+#undef HAVE__OPEN64
+
+/* Define if you have the _opendir function. */
+#undef HAVE__OPENDIR
+
+/* Define if you have the _pread function. */
+#undef HAVE__PREAD
+
+/* Define if you have the _pread64 function. */
+#undef HAVE__PREAD64
+
+/* Define if you have the _pwrite function. */
+#undef HAVE__PWRITE
+
+/* Define if you have the _pwrite64 function. */
+#undef HAVE__PWRITE64
+
+/* Define if you have the _read function. */
+#undef HAVE__READ
+
+/* Define if you have the _readdir function. */
+#undef HAVE__READDIR
+
+/* Define if you have the _readdir64 function. */
+#undef HAVE__READDIR64
+
+/* Define if you have the _seekdir function. */
+#undef HAVE__SEEKDIR
+
+/* Define if you have the _stat function. */
+#undef HAVE__STAT
+
+/* Define if you have the _stat64 function. */
+#undef HAVE__STAT64
+
+/* Define if you have the _telldir function. */
+#undef HAVE__TELLDIR
+
+/* Define if you have the _write function. */
+#undef HAVE__WRITE
+
+/* Define if you have the asprintf function. */
+#undef HAVE_ASPRINTF
+
+/* Define if you have the atexit function. */
+#undef HAVE_ATEXIT
+
+/* Define if you have the bigcrypt function. */
+#undef HAVE_BIGCRYPT
+
+/* Define if you have the bzero function. */
+#undef HAVE_BZERO
+
+/* Define if you have the chmod function. */
+#undef HAVE_CHMOD
+
+/* Define if you have the chown function. */
+#undef HAVE_CHOWN
+
+/* Define if you have the chroot function. */
+#undef HAVE_CHROOT
+
+/* Define if you have the connect function. */
+#undef HAVE_CONNECT
+
+/* Define if you have the creat64 function. */
+#undef HAVE_CREAT64
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if you have the crypt16 function. */
+#undef HAVE_CRYPT16
+
+/* Define if you have the dup2 function. */
+#undef HAVE_DUP2
+
+/* Define if you have the endnetgrent function. */
+#undef HAVE_ENDNETGRENT
+
+/* Define if you have the execl function. */
+#undef HAVE_EXECL
+
+/* Define if you have the fchmod function. */
+#undef HAVE_FCHMOD
+
+/* Define if you have the fchown function. */
+#undef HAVE_FCHOWN
+
+/* Define if you have the fcvt function. */
+#undef HAVE_FCVT
+
+/* Define if you have the fcvtl function. */
+#undef HAVE_FCVTL
+
+/* Define if you have the fopen64 function. */
+#undef HAVE_FOPEN64
+
+/* Define if you have the fseek64 function. */
+#undef HAVE_FSEEK64
+
+/* Define if you have the fseeko64 function. */
+#undef HAVE_FSEEKO64
+
+/* Define if you have the fstat function. */
+#undef HAVE_FSTAT
+
+/* Define if you have the fstat64 function. */
+#undef HAVE_FSTAT64
+
+/* Define if you have the fsync function. */
+#undef HAVE_FSYNC
+
+/* Define if you have the ftell64 function. */
+#undef HAVE_FTELL64
+
+/* Define if you have the ftello64 function. */
+#undef HAVE_FTELLO64
+
+/* Define if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the ftruncate64 function. */
+#undef HAVE_FTRUNCATE64
+
+/* Define if you have the getauthuid function. */
+#undef HAVE_GETAUTHUID
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the getdents function. */
+#undef HAVE_GETDENTS
+
+/* Define if you have the getgrent function. */
+#undef HAVE_GETGRENT
+
+/* Define if you have the getgrnam function. */
+#undef HAVE_GETGRNAM
+
+/* Define if you have the getnetgrent function. */
+#undef HAVE_GETNETGRENT
+
+/* Define if you have the getprpwnam function. */
+#undef HAVE_GETPRPWNAM
+
+/* Define if you have the getpwanam function. */
+#undef HAVE_GETPWANAM
+
+/* Define if you have the getrlimit function. */
+#undef HAVE_GETRLIMIT
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if you have the getutmpx function. */
+#undef HAVE_GETUTMPX
+
+/* Define if you have the glob function. */
+#undef HAVE_GLOB
+
+/* Define if you have the grantpt function. */
+#undef HAVE_GRANTPT
+
+/* Define if you have the initgroups function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the innetgr function. */
+#undef HAVE_INNETGR
+
+/* Define if you have the llseek function. */
+#undef HAVE_LLSEEK
+
+/* Define if you have the lseek64 function. */
+#undef HAVE_LSEEK64
+
+/* Define if you have the lstat64 function. */
+#undef HAVE_LSTAT64
+
+/* Define if you have the memmove function. */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function. */
+#undef HAVE_MEMSET
+
+/* Define if you have the mktime function. */
+#undef HAVE_MKTIME
+
+/* Define if you have the open64 function. */
+#undef HAVE_OPEN64
+
+/* Define if you have the pathconf function. */
+#undef HAVE_PATHCONF
+
+/* Define if you have the pipe function. */
+#undef HAVE_PIPE
+
+/* Define if you have the poll function. */
+#undef HAVE_POLL
+
+/* Define if you have the pread function. */
+#undef HAVE_PREAD
+
+/* Define if you have the pread64 function. */
+#undef HAVE_PREAD64
+
+/* Define if you have the putprpwnam function. */
+#undef HAVE_PUTPRPWNAM
+
+/* Define if you have the pututline function. */
+#undef HAVE_PUTUTLINE
+
+/* Define if you have the pututxline function. */
+#undef HAVE_PUTUTXLINE
+
+/* Define if you have the pwrite function. */
+#undef HAVE_PWRITE
+
+/* Define if you have the pwrite64 function. */
+#undef HAVE_PWRITE64
+
+/* Define if you have the rand function. */
+#undef HAVE_RAND
+
+/* Define if you have the random function. */
+#undef HAVE_RANDOM
+
+/* Define if you have the rdchk function. */
+#undef HAVE_RDCHK
+
+/* Define if you have the readdir64 function. */
+#undef HAVE_READDIR64
+
+/* Define if you have the readlink function. */
+#undef HAVE_READLINK
+
+/* Define if you have the rename function. */
+#undef HAVE_RENAME
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the set_auth_parameters function. */
+#undef HAVE_SET_AUTH_PARAMETERS
+
+/* Define if you have the setbuffer function. */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the setgidx function. */
+#undef HAVE_SETGIDX
+
+/* Define if you have the setgroups function. */
+#undef HAVE_SETGROUPS
+
+/* Define if you have the setlinebuf function. */
+#undef HAVE_SETLINEBUF
+
+/* Define if you have the setluid function. */
+#undef HAVE_SETLUID
+
+/* Define if you have the setnetgrent function. */
+#undef HAVE_SETNETGRENT
+
+/* Define if you have the setpriv function. */
+#undef HAVE_SETPRIV
+
+/* Define if you have the setsid function. */
+#undef HAVE_SETSID
+
+/* Define if you have the setuidx function. */
+#undef HAVE_SETUIDX
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sigblock function. */
+#undef HAVE_SIGBLOCK
+
+/* Define if you have the sigprocmask function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define if you have the sigset function. */
+#undef HAVE_SIGSET
+
+/* Define if you have the snprintf function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the srand function. */
+#undef HAVE_SRAND
+
+/* Define if you have the srandom function. */
+#undef HAVE_SRANDOM
+
+/* Define if you have the stat64 function. */
+#undef HAVE_STAT64
+
+/* Define if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function. */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strlcat function. */
+#undef HAVE_STRLCAT
+
+/* Define if you have the strlcpy function. */
+#undef HAVE_STRLCPY
+
+/* Define if you have the strpbrk function. */
+#undef HAVE_STRPBRK
+
+/* Define if you have the strtoul function. */
+#undef HAVE_STRTOUL
+
+/* Define if you have the symlink function. */
+#undef HAVE_SYMLINK
+
+/* Define if you have the syscall function. */
+#undef HAVE_SYSCALL
+
+/* Define if you have the sysconf function. */
+#undef HAVE_SYSCONF
+
+/* Define if you have the syslog function. */
+#undef HAVE_SYSLOG
+
+/* Define if you have the updwtmp function. */
+#undef HAVE_UPDWTMP
+
+/* Define if you have the updwtmpx function. */
+#undef HAVE_UPDWTMPX
+
+/* Define if you have the usleep function. */
+#undef HAVE_USLEEP
+
+/* Define if you have the utime function. */
+#undef HAVE_UTIME
+
+/* Define if you have the utimes function. */
+#undef HAVE_UTIMES
+
+/* Define if you have the vasprintf function. */
+#undef HAVE_VASPRINTF
+
+/* Define if you have the vsnprintf function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if you have the vsyslog function. */
+#undef HAVE_VSYSLOG
+
+/* Define if you have the waitpid function. */
+#undef HAVE_WAITPID
+
+/* Define if you have the yp_get_default_domain function. */
+#undef HAVE_YP_GET_DEFAULT_DOMAIN
+
+/* Define if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define if you have the <compat.h> header file. */
+#undef HAVE_COMPAT_H
+
+/* Define if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define if you have the <cups/cups.h> header file. */
+#undef HAVE_CUPS_CUPS_H
+
+/* Define if you have the <cups/language.h> header file. */
+#undef HAVE_CUPS_LANGUAGE_H
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
+/* Define if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define if you have the <history.h> header file. */
+#undef HAVE_HISTORY_H
+
+/* Define if you have the <krb5.h> header file. */
+#undef HAVE_KRB5_H
+
+/* Define if you have the <lastlog.h> header file. */
+#undef HAVE_LASTLOG_H
+
+/* Define if you have the <ldap.h> header file. */
+#undef HAVE_LDAP_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <linux/xqm.h> header file. */
+#undef HAVE_LINUX_XQM_H
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the <netinet/in_ip.h> header file. */
+#undef HAVE_NETINET_IN_IP_H
+
+/* Define if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define if you have the <netinet/ip.h> header file. */
+#undef HAVE_NETINET_IP_H
+
+/* Define if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define if you have the <ns_api.h> header file. */
+#undef HAVE_NS_API_H
+
+/* Define if you have the <nss.h> header file. */
+#undef HAVE_NSS_H
+
+/* Define if you have the <nss_common.h> header file. */
+#undef HAVE_NSS_COMMON_H
+
+/* Define if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define if you have the <readline.h> header file. */
+#undef HAVE_READLINE_H
+
+/* Define if you have the <readline/history.h> header file. */
+#undef HAVE_READLINE_HISTORY_H
+
+/* Define if you have the <readline/readline.h> header file. */
+#undef HAVE_READLINE_READLINE_H
+
+/* Define if you have the <rpc/rpc.h> header file. */
+#undef HAVE_RPC_RPC_H
+
+/* Define if you have the <rpcsvc/nis.h> header file. */
+#undef HAVE_RPCSVC_NIS_H
+
+/* Define if you have the <rpcsvc/yp_prot.h> header file. */
+#undef HAVE_RPCSVC_YP_PROT_H
+
+/* Define if you have the <rpcsvc/ypclnt.h> header file. */
+#undef HAVE_RPCSVC_YPCLNT_H
+
+/* Define if you have the <security/_pam_macros.h> header file. */
+#undef HAVE_SECURITY__PAM_MACROS_H
+
+/* Define if you have the <security/pam_appl.h> header file. */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define if you have the <security/pam_modules.h> header file. */
+#undef HAVE_SECURITY_PAM_MODULES_H
+
+/* Define if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define if you have the <sys/acl.h> header file. */
+#undef HAVE_SYS_ACL_H
+
+/* Define if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
+/* Define if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/dustat.h> header file. */
+#undef HAVE_SYS_DUSTAT_H
+
+/* Define if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define if you have the <sys/filsys.h> header file. */
+#undef HAVE_SYS_FILSYS_H
+
+/* Define if you have the <sys/fs/s5param.h> header file. */
+#undef HAVE_SYS_FS_S5PARAM_H
+
+/* Define if you have the <sys/fs/vx_quota.h> header file. */
+#undef HAVE_SYS_FS_VX_QUOTA_H
+
+/* Define if you have the <sys/id.h> header file. */
+#undef HAVE_SYS_ID_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define if you have the <sys/mode.h> header file. */
+#undef HAVE_SYS_MODE_H
+
+/* Define if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/priv.h> header file. */
+#undef HAVE_SYS_PRIV_H
+
+/* Define if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/security.h> header file. */
+#undef HAVE_SYS_SECURITY_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/shm.h> header file. */
+#undef HAVE_SYS_SHM_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/statfs.h> header file. */
+#undef HAVE_SYS_STATFS_H
+
+/* Define if you have the <sys/statvfs.h> header file. */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/unistd.h> header file. */
+#undef HAVE_SYS_UNISTD_H
+
+/* Define if you have the <sys/vfs.h> header file. */
+#undef HAVE_SYS_VFS_H
+
+/* Define if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have the <syscall.h> header file. */
+#undef HAVE_SYSCALL_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define if you have the <utmp.h> header file. */
+#undef HAVE_UTMP_H
+
+/* Define if you have the <utmpx.h> header file. */
+#undef HAVE_UTMPX_H
+
+/* Define if you have the acl library (-lacl). */
+#undef HAVE_LIBACL
+
+/* Define if you have the cups library (-lcups). */
+#undef HAVE_LIBCUPS
+
+/* Define if you have the gen library (-lgen). */
+#undef HAVE_LIBGEN
+
+/* Define if you have the iconv library (-liconv). */
+#undef HAVE_LIBICONV
+
+/* Define if you have the inet library (-linet). */
+#undef HAVE_LIBINET
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the nsl_s library (-lnsl_s). */
+#undef HAVE_LIBNSL_S
+
+/* Define if you have the resolv library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the sec library (-lsec). */
+#undef HAVE_LIBSEC
+
+/* Define if you have the security library (-lsecurity). */
+#undef HAVE_LIBSECURITY
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to turn on dmalloc debugging */
+#undef ENABLE_DMALLOC
+
+/* Do we have rl_completion_matches? */
+#undef HAVE_NEW_LIBREADLINE
+
+/* Define if you have working AF_LOCAL sockets */
+#undef HAVE_WORKING_AF_LOCAL
+
diff --git a/source/include/debug.h b/source/include/debug.h
new file mode 100644
index 00000000000..37eaed2b124
--- /dev/null
+++ b/source/include/debug.h
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB debug stuff
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) John H Terpstra 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+/* -------------------------------------------------------------------------- **
+ * Debugging code. See also debug.c
+ */
+
+/* mkproto.awk has trouble with ifdef'd function definitions (it ignores
+ * the #ifdef directive and will read both definitions, thus creating two
+ * diffferent prototype declarations), so we must do these by hand.
+ */
+/* I know the __attribute__ stuff is ugly, but it does ensure we get the
+ arguemnts to DEBUG() right. We have got them wrong too often in the
+ past.
+ */
+int Debug1( char *, ... ) PRINTF_ATTRIBUTE(1,2);
+BOOL dbgtext( char *, ... ) PRINTF_ATTRIBUTE(1,2);
+
+extern XFILE *dbf;
+
+/* If we have these macros, we can add additional info to the header. */
+#ifdef HAVE_FILE_MACRO
+#define FILE_MACRO (__FILE__)
+#else
+#define FILE_MACRO ("")
+#endif
+
+#ifdef HAVE_FUNCTION_MACRO
+#define FUNCTION_MACRO (__FUNCTION__)
+#else
+#define FUNCTION_MACRO ("")
+#endif
+
+/*
+ * Redefine DEBUGLEVEL because so we don't have to change every source file
+ * that *unnecessarily* references it. Source files neeed not extern reference
+ * DEBUGLEVEL, as it's extern in includes.h (which all source files include).
+ * Eventually, all these references should be removed, and all references to
+ * DEBUGLEVEL should be references to DEBUGLEVEL_CLASS[DBGC_ALL]. This could
+ * still be through a macro still called DEBUGLEVEL. This cannot be done now
+ * because some references would expand incorrectly.
+ */
+#define DEBUGLEVEL *debug_level
+
+
+/*
+ * Define all new debug classes here. A class is represented by an entry in
+ * the DEBUGLEVEL_CLASS array. Index zero of this arrray is equivalent to the
+ * old DEBUGLEVEL. Any source file that does NOT add the following lines:
+ *
+ * #undef DBGC_CLASS
+ * #define DBGC_CLASS DBGC_<your class name here>
+ *
+ * at the start of the file (after #include "includes.h") will default to
+ * using index zero, so it will behaive just like it always has.
+ */
+#define DBGC_CLASS 0 /* override as shown above */
+#define DBGC_ALL 0 /* index equivalent to DEBUGLEVEL */
+
+#define DBGC_TDB 1
+#define DBGC_PRINTDRIVERS 2
+#define DBGC_LANMAN 3
+#define DBGC_SMB 4
+#define DBGC_RPC 5
+#define DBGC_RPC_HDR 6
+#define DBGC_BDC 7
+
+#define DBGC_LAST 8 /* MUST be last class value + 1 */
+
+extern int DEBUGLEVEL_CLASS[DBGC_LAST];
+extern BOOL DEBUGLEVEL_CLASS_ISSET[DBGC_LAST];
+
+struct debuglevel_message {
+ int debuglevel_class[DBGC_LAST];
+ BOOL debuglevel_class_isset[DBGC_LAST];
+};
+
+/* Debugging macros
+ *
+ * DEBUGLVL()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Returns True if the debug level was <= DEBUGLEVEL.
+ *
+ * Example: if( DEBUGLVL( 2 ) ) dbgtext( "Some text.\n" );
+ *
+ * DEBUGLVLC()
+ * If the 'macro specified' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Returns True if the debug level was <= DEBUGLEVEL.
+ *
+ * Example: if( DEBUGLVLC( DBGC_TDB, 2 ) ) dbgtext( "Some text.\n" );
+ *
+ * DEBUG()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUG( 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGC()
+ * If the 'macro specified' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synomym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUGC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGADD(), DEBUGADDC()
+ * Same as DEBUG() and DEBUGC() except the text is appended to the previous
+ * DEBUG(), DEBUGC(), DEBUGADD(), DEBUGADDC() with out another interviening
+ * header.
+ *
+ * Example: DEBUGADD( 2, ("Some text and a value %d.\n", value) );
+ * DEBUGADDC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * Note: If the debug class has not be redeined (see above) then the optimizer
+ * will remove the extra conditional test.
+ */
+
+#define DEBUGLVL( level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) ) )
+
+
+#define DEBUGLVLC( dbgc_class, level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) ) )
+
+
+#define DEBUG( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) )) \
+ && (dbgtext body) )
+
+#define DEBUGC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) )) \
+ && (dbgtext body) )
+
+#define DEBUGADD( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ DBGC_CLASS ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ DBGC_CLASS ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbgtext body) )
+
+#define DEBUGADDC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ ((DEBUGLEVEL_CLASS[ dbgc_class ] >= (level))|| \
+ (!DEBUGLEVEL_CLASS_ISSET[ dbgc_class ] && \
+ DEBUGLEVEL_CLASS[ DBGC_ALL ] >= (level)) ) \
+ && (dbgtext body) )
+
+#endif
diff --git a/source/include/dlinklist.h b/source/include/dlinklist.h
new file mode 100644
index 00000000000..cf75404c561
--- /dev/null
+++ b/source/include/dlinklist.h
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ some simple double linked list macros
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+
+/* hook into the front of the list */
+#define DLIST_ADD(list, p) \
+{ \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+}
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define DLIST_REMOVE(list, p) \
+{ \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+}
+
+/* promote an element to the top of the list */
+#define DLIST_PROMOTE(list, p) \
+{ \
+ DLIST_REMOVE(list, p) \
+ DLIST_ADD(list, p) \
+}
+
+/* hook into the end of the list - needs a tmp pointer */
+#define DLIST_ADD_END(list, p, tmp) \
+{ \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ for ((tmp) = (list); (tmp)->next; (tmp) = (tmp)->next) ; \
+ (tmp)->next = (p); \
+ (p)->next = NULL; \
+ (p)->prev = (tmp); \
+ } \
+}
+
+/* demote an element to the top of the list, needs a tmp pointer */
+#define DLIST_DEMOTE(list, p, tmp) \
+{ \
+ DLIST_REMOVE(list, p) \
+ DLIST_ADD_END(list, p, tmp) \
+}
diff --git a/source/include/doserr.h b/source/include/doserr.h
new file mode 100644
index 00000000000..d55f21be346
--- /dev/null
+++ b/source/include/doserr.h
@@ -0,0 +1,186 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ DOS error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DOSERR_H
+#define _DOSERR_H
+
+/* Error classes */
+
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRDOS error class */
+#define ERRsuccess 0 /* No error */
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRbadshare 32 /* Share mode on file conflict with open mode */
+#define ERRlock 33 /* Lock request conflicts with existing lock */
+#define ERRunsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */
+#define ERRnosuchshare 67 /* You specified an invalid share name */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRinvalidparam 87
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRinsufficientbuffer 122
+#define ERRinvalidname 123 /* Invalid name */
+#define ERRunknownlevel 124
+#define ERRnotlocked 158 /* This region is not locked by this locking context. */
+#define ERRrename 183
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERRnomoreitems 259
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
+#define ERReasnotsupported 282 /* Extended attributes */
+#define ERRlogonfailure 1326 /* Unknown username or bad password */
+#define ERRbuftoosmall 2123
+#define ERRunknownipc 2142
+#define ERRnosuchprintjob 2151
+
+/* here's a special one from observing NT */
+#define ERRnoipc 66 /* don't support ipc */
+
+/* These errors seem to be only returned by the NT printer driver system */
+
+#define ERRunknownprinterdriver 1797 /* ERROR_UNKNOWN_PRINTER_DRIVER */
+#define ERRinvalidprintername 1801 /* ERROR_INVALID_PRINTER_NAME */
+#define ERRprinteralreadyexists 1802 /* ERROR_PRINTER_ALREADY_EXISTS */
+#define ERRinvaliddatatype 1804 /* ERROR_INVALID_DATATYPE */
+#define ERRinvalidenvironment 1805 /* ERROR_INVALID_ENVIRONMENT */
+#define ERRprinterdriverinuse 3001 /* ERROR_PRINTER_DRIVER_IN_USE */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+#define ERRunknownsmb 22 /* from NT 3.5 response */
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+
+/* these are win32 error codes. There are only a few places where
+ these matter for Samba, primarily in the NT printing code */
+#define WERR_OK W_ERROR(0)
+#define WERR_BADFILE W_ERROR(2)
+#define WERR_ACCESS_DENIED W_ERROR(5)
+#define WERR_BADFID W_ERROR(6)
+#define WERR_BADFUNC W_ERROR(1)
+#define WERR_INSUFFICIENT_BUFFER W_ERROR(122)
+#define WERR_NO_SUCH_SHARE W_ERROR(67)
+#define WERR_INVALID_PARAM W_ERROR(87)
+#define WERR_NOT_SUPPORTED W_ERROR(50)
+#define WERR_BAD_PASSWORD W_ERROR(86)
+#define WERR_NOMEM W_ERROR(8)
+#define WERR_INVALID_NAME W_ERROR(123)
+#define WERR_UNKNOWN_LEVEL W_ERROR(124)
+#define WERR_NO_MORE_ITEMS W_ERROR(259)
+#define WERR_MORE_DATA W_ERROR(234)
+#define WERR_UNKNOWN_PRINTER_DRIVER W_ERROR(1797)
+#define WERR_INVALID_PRINTER_NAME W_ERROR(1801)
+#define WERR_PRINTER_ALREADY_EXISTS W_ERROR(1802)
+#define WERR_INVALID_DATATYPE W_ERROR(1804)
+#define WERR_INVALID_ENVIRONMENT W_ERROR(1805)
+#define WERR_BUF_TOO_SMALL W_ERROR(2123)
+#define WERR_JOB_NOT_FOUND W_ERROR(2151)
+#define WERR_DEST_NOT_FOUND W_ERROR(2152)
+#define WERR_PRINTER_DRIVER_IN_USE W_ERROR(3001)
+#define WERR_STATUS_MORE_ENTRIES W_ERROR(0x0105)
+
+/* DFS errors */
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#define WERR_DFS_NO_SUCH_VOL W_ERROR(NERR_BASE+562)
+#define WERR_DFS_NO_SUCH_SHARE W_ERROR(NERR_BASE+565)
+#define WERR_DFS_NO_SUCH_SERVER W_ERROR(NERR_BASE+573)
+#define WERR_DFS_INTERNAL_ERROR W_ERROR(NERR_BASE+590)
+#define WERR_DFS_CANT_CREATE_JUNCT W_ERROR(NERR_BASE+569)
+
+#endif /* _DOSERR_H */
diff --git a/source/include/dynconfig.h b/source/include/dynconfig.h
new file mode 100644
index 00000000000..5ce858f1c4a
--- /dev/null
+++ b/source/include/dynconfig.h
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/Netbios implementation.
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ * @file dynconfig.h
+ *
+ * @brief Exported global configurations.
+ **/
+
+extern char const *dyn_SBINDIR,
+ *dyn_BINDIR,
+ *dyn_SWATDIR;
+
+extern pstring dyn_CONFIGFILE;
+extern pstring dyn_LOGFILEBASE, dyn_LMHOSTSFILE;
+extern pstring dyn_LIBDIR;
+extern const pstring dyn_LOCKDIR;
+extern const pstring dyn_DRIVERFILE;
+extern const pstring dyn_SMB_PASSWD_FILE;
+extern const pstring dyn_PRIVATE_DIR;
diff --git a/source/include/hash.h b/source/include/hash.h
new file mode 100644
index 00000000000..80a1aaae50e
--- /dev/null
+++ b/source/include/hash.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Copyright (C) Ying Chen 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _HASH_H_
+#define _HASH_H_
+
+#define MAX_HASH_TABLE_SIZE 16384
+#define HASH_TABLE_INCREMENT 2
+
+typedef int (*compare_function)(char *, char *);
+typedef int (*hash_function)(int, char *);
+
+/*
+ * lru_link: links the node to the LRU list.
+ * hash_elem: the pointer to the element that is tied onto the link.
+ */
+typedef struct lru_node {
+ ubi_dlNode lru_link;
+ void *hash_elem;
+} lru_node;
+
+/*
+ * bucket_link: link the hash element to the bucket chain that it belongs to.
+ * lru_link: this element ties the hash element to the lru list.
+ * bucket: a pointer to the hash bucket that this element belongs to.
+ * value: a pointer to the hash element content. It can be anything.
+ * key: stores the string key. The hash_element is always allocated with
+ * more memory space than the structure shown below to accomodate the space
+ * used for the whole string. But the memory is always appended at the
+ * end of the structure, so keep "key" at the end of the structure.
+ * Don't move it.
+ */
+typedef struct hash_element {
+ ubi_dlNode bucket_link;
+ lru_node lru_link;
+ ubi_dlList *bucket;
+ void *value;
+ char key[1];
+} hash_element;
+
+/*
+ * buckets: a list of buckets, implemented as a dLinkList.
+ * lru_chain: the lru list of all the hash elements.
+ * num_elements: the # of elements in the hash table.
+ * size: the hash table size.
+ * comp_func: the compare function used during hash key comparisons.
+ */
+
+typedef struct hash_table {
+ ubi_dlList *buckets;
+ ubi_dlList lru_chain;
+ int num_elements;
+ int size;
+ compare_function comp_func;
+} hash_table;
+
+#endif /* _HASH_H_ */
diff --git a/source/include/hmacmd5.h b/source/include/hmacmd5.h
new file mode 100644
index 00000000000..adb52058a89
--- /dev/null
+++ b/source/include/hmacmd5.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Interface header: Scheduler service
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+ Copyright (C) Andrew Tridgell 1992-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _HMAC_MD5_H
+
+typedef struct
+{
+ struct MD5Context ctx;
+ uchar k_ipad[65];
+ uchar k_opad[65];
+
+} HMACMD5Context;
+
+#endif /* _HMAC_MD5_H */
diff --git a/source/include/includes.h b/source/include/includes.h
index cc2bbbfad7c..92ac462e1b1 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -4,7 +4,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Machine customisation and include handling
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,1135 +20,1083 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*
- This file does all the #includes's. This makes it easier to
- port to a new unix. Hopefully a port will only have to edit the Makefile
- and add a section for the new unix below.
-*/
+#ifndef NO_CONFIG_H /* for some tests */
+#include "config.h"
+#endif
-/* the first OS dependent section is to setup what includes will be used.
- the main OS dependent section comes later on
-*/
+#include "local.h"
-#ifdef ALTOS
-#define NO_UTIMEH
+#ifdef AIX
+#define DEFAULT_PRINTING PRINT_AIX
+#define PRINTCAP_NAME "/etc/qconfig"
#endif
-#ifdef MIPS
-#define POSIX_H
-#define NO_UTIMEH
+#ifdef HPUX
+#define DEFAULT_PRINTING PRINT_HPUX
#endif
-#ifdef sun386
-#define NO_UTIMEH
+#ifdef QNX
+#define DEFAULT_PRINTING PRINT_QNX
#endif
-#ifdef NEXT2
-#define NO_UTIMEH
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
#endif
-#ifdef NEXT3_0
-#define NO_UTIMEH
-#define NO_UNISTDH
+#ifdef LINUX
+#ifndef DEFAULT_PRINTING
+#define DEFAULT_PRINTING PRINT_BSD
#endif
-
-#ifdef APOLLO
-#define NO_UTIMEH
-#define NO_SYSMOUNTH
-#define NO_UNISTDH
+#ifndef PRINTCAP_NAME
+#define PRINTCAP_NAME "/etc/printcap"
#endif
-
-#ifdef AIX
-#define NO_SYSMOUNTH
#endif
-#ifdef M88K_R3
-#define SVR3H
-#define NO_RESOURCEH
+#ifdef __GNUC__
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
#endif
-#ifdef DNIX
-#define NO_SYSMOUNTH
-#define NO_NETIFH
-#define NO_RESOURCEH
-#define PRIME_NMBD 0
-#define NO_SETGROUPS
+#ifdef RELIANTUNIX
+/*
+ * <unistd.h> has to be included before any other to get
+ * large file support on Reliant UNIX. Yes, it's broken :-).
+ */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
+#endif /* RELIANTUNIX */
+#include <sys/types.h>
-#ifdef ISC
-#define SYSSTREAMH
-#define NO_RESOURCEH
-#endif
-
-#ifdef QNX
-#define NO_RESOURCEH
-#define NO_SYSMOUNTH
-#define USE_MMAP 1
-#ifdef __386__
- #define __i386__
-#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
#endif
-
-#ifdef NEWS42
-#define NO_UTIMEH
-#define NO_STRFTIME
-#define NO_UTIMBUF
-#define REPLACE_MKTIME
-#define NO_TM_NAME
#endif
-#ifdef OS2
-#define NO_SYSMOUNTH
-#define NO_NETIFH
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
#endif
-#ifdef LYNX
-#define NO_SYSMOUNTH
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
+#include <stdio.h>
+#include <stddef.h>
-#if (defined(SHADOW_PWD)||defined(OSF1_ENH_SEC)||defined(SecureWare)||defined(PWDAUTH))
-#define PASSWORD_LENGTH 16
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
#endif
-/* here is the general includes section - with some ifdefs generated
- by the previous section
-*/
-#include "local.h"
-#include <stdio.h>
-#ifdef POSIX_STDLIBH
-#include <posix/stdlib.h>
-#else
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
-#include <ctype.h>
-#include <time.h>
-#ifndef NO_UTIMEH
-#include <utime.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
#endif
-#include <sys/types.h>
-#ifdef SVR3H
-#include <sys/statfs.h>
-#include <sys/stream.h>
-#include <netinet/types.h>
-#include <netinet/ether.h>
-#include <netinet/ip_if.h>
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
#endif
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <stddef.h>
-#ifdef POSIX_H
-#include <posix/utime.h>
-#include <bsd/sys/time.h>
-#include <bsd/netinet/in.h>
-#else
-#include <sys/time.h>
-#include <netinet/in.h>
-#endif
-#include <netdb.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <grp.h>
-#ifndef NO_RESOURCEH
-#include <sys/resource.h>
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#elif HAVE_SYSCALL_H
+#include <syscall.h>
#endif
-#ifndef NO_SYSMOUNTH
-#include <sys/mount.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
#endif
-#include <pwd.h>
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
#endif
-#ifndef NO_UNISTDH
-#include <unistd.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
#endif
-#include <sys/wait.h>
-#ifdef SYSSTREAMH
-#include <sys/stream.h>
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
#endif
-#ifndef NO_NETIFH
-#ifdef POSIX_H
-#include <bsd/net/if.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
#else
-#include <net/if.h>
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
#endif
#endif
-#if USE_MMAP
-#include <sys/mman.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
#endif
-#if defined(GETPWANAM)
-#include <sys/types.h>
-#include <sys/label.h>
-#include <sys/audit.h>
-#include <pwdadj.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
#endif
-#if defined(SHADOW_PWD) && !defined(NETBSD) && !defined(CONVEX)
-#include <shadow.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
#endif
-/* this might be different on different systems */
-#ifdef QUOTAS
-#ifdef LINUX
-#ifdef __KERNEL__
-#undef __KERNEL__
-#include <sys/quota.h>
-#define __KERNEL__
-#else
-#include <sys/quota.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
#endif
-#include <mntent.h>
-#else
-#include <sys/quota.h>
-#ifndef CRAY
-#include <devnm.h>
-#else
-#include <mntent.h>
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
#endif
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
#endif
-
-#ifdef SYSLOG
-#include <syslog.h>
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
#endif
+#include <errno.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
-/***************************************************************************
-Here come some platform specific sections
-***************************************************************************/
-
-
-#ifdef LINUX
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/vfs.h>
-#include <netinet/in.h>
-#ifndef NO_ASMSIGNALH
-#include <asm/signal.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
#endif
-#define SIGNAL_CAST (__sighandler_t)
-#define USE_GETCWD
-#define USE_SETSID
-#define HAVE_BZERO
-#define HAVE_MEMMOVE
-#ifdef SHADOW_PWD
-#ifndef crypt
-#define crypt pw_encrypt
+
+#ifdef HAVE_SYS_MODE_H
+/* apparently AIX needs this for S_ISLNK */
+#ifndef S_ISLNK
+#include <sys/mode.h>
#endif
#endif
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
#endif
-#ifdef SUNOS4
-#define SIGNAL_CAST (void (*)(int))
-#include <netinet/tcp.h>
-#include <dirent.h>
-#include <sys/acct.h>
-#include <sys/vfs.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <signal.h>
-/* #include <termios.h> */
-#ifdef sun386
-#define NO_STRFTIME
-#define NO_UTIMBUF
-#define mktime timelocal
-typedef unsigned short mode_t;
+#include <pwd.h>
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
#else
-#include <utime.h>
-#define NO_STRERROR
-#endif
-#define REPLACE_GETPASS
-#define BSD_TERMIO
+#include <varargs.h>
#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/file.h>
-#ifdef SUNOS5
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/acct.h>
-#include <sys/statfs.h>
-#include <sys/statvfs.h>
-#include <sys/filio.h>
-#include <sys/sockio.h>
-#include <netinet/in_systm.h>
+#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
-#include <netinet/ip.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <rpcsvc/ypclnt.h>
-#include <crypt.h>
-#include <termios.h>
-extern int gettimeofday (struct timeval *, void *);
-extern int gethostname (char *name, int namelen);
-extern int innetgr (const char *, const char *, const char *, const char *);
-#define USE_SETVBUF
-#define SIGNAL_CAST (void (*)(int))
-#ifndef SYSV
-#define SYSV
-#endif
-#define USE_WAITPID
-#define REPLACE_STRLEN
-#define USE_STATVFS
-#define USE_GETCWD
-#define USE_SETSID
-#define REPLACE_GETPASS
#endif
+/*
+ * The next three defines are needed to access the IPTOS_* options
+ * on some systems.
+ */
-#ifdef ULTRIX
-#include <strings.h>
-#include <nfs/nfs_clnt.h>
-#include <nfs/vfs.h>
-#include <netinet/tcp.h>
-#ifdef ULTRIX_AUTH
-#include <auth.h>
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
#endif
-char *getwd(char *);
-#define NOSTRDUP
-#ifdef __STDC__
-#define SIGNAL_CAST (void(*)(int))
+
+#ifdef HAVE_NETINET_IN_IP_H
+#include <netinet/in_ip.h>
#endif
-#define USE_DIRECT
+
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
#endif
-#ifdef SGI
-#include <netinet/tcp.h>
-#include <sys/statfs.h>
-#include <string.h>
-#include <signal.h>
-#ifndef SYSV
-#define SYSV
+#if defined(HAVE_TERMIOS_H)
+/* POSIX terminal handling. */
+#include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <termio.h>
+#elif defined(HAVE_SYS_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <sys/termio.h>
#endif
-#define SIGNAL_CAST (void (*)())
-#define STATFS4
-#define USE_WAITPID
-#define USE_DIRECT
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
#endif
-#ifdef SGI5
-#include <netinet/tcp.h>
-#include <sys/statvfs.h>
-#include <string.h>
-#include <signal.h>
-#include <dirent.h>
-#define USE_WAITPID
-#define NETGROUP
-#ifndef SYSV
-#define SYSV
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
#endif
-#define SIGNAL_CAST (void (*)())
-#define USE_STATVFS
-#define USE_WAITPID
+
+
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
-#ifdef MIPS
-#include <bsd/net/soioctl.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/statfs.h>
-#include <sys/wait.h>
-#include <sys/termio.h>
-#define SIGNAL_CAST (void (*)())
-typedef int mode_t;
-extern struct group *getgrnam();
-extern struct passwd *getpwnam();
-#define STATFS4
-#define NO_STRERROR
-#define REPLACE_STRSTR
-#endif /* MIPS */
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_SYS_FS_S5PARAM_H
+#include <sys/fs/s5param.h>
+#endif
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+#include <sys/filsys.h>
+#endif
-#ifdef DGUX
-#include <string.h>
-#include <dirent.h>
-#include <sys/statfs.h>
-#include <sys/statvfs.h>
-#include <fcntl.h>
-#include <termios.h>
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)(int))
-#define STATFS4
-#define USE_GETCWD
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
#endif
+#ifdef HAVE_DUSTAT_H
+#include <sys/dustat.h>
+#endif
-#ifdef SVR4
-#include <string.h>
-#include <sys/dir.h>
-#include <dirent.h>
-#include <sys/statfs.h>
+#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
-#include <sys/vfs.h>
-#include <sys/filio.h>
-#include <fcntl.h>
-#include <sys/sockio.h>
-#include <netinet/tcp.h>
-#include <stropts.h>
-#include <termios.h>
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)(int))
-#define USE_STATVFS
-#define USE_GETCWD
-#define USE_SETSID
#endif
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
-#ifdef OSF1
-#include <termios.h>
-#include <strings.h>
-#include <dirent.h>
-char *getwd(char *);
-char *mktemp(char *); /* No standard include */
-#include <netinet/in.h>
-#include <arpa/inet.h> /* both for inet_ntoa */
-#define SIGNAL_CAST ( void (*) (int) )
-#define STATFS3
-#define USE_F_FSIZE
-#include <netinet/tcp.h>
-#ifdef OSF1_ENH_SEC
-#include <pwd.h>
-#include <sys/types.h>
+#ifdef HAVE_GETPWANAM
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+
+#ifdef HAVE_SYS_SECURITY_H
#include <sys/security.h>
#include <prot.h>
-#include <unistd.h>
#define PASSWORD_LENGTH 16
-#define NEED_AUTH_PARAMETERS
-#endif /* OSF1_ENH_SEC */
+#endif /* HAVE_SYS_SECURITY_H */
+
+#ifdef HAVE_COMPAT_H
+#include <compat.h>
#endif
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
-#ifdef CLIX
-#include <dirent.h>
-#define SIGNAL_CAST (void (*)())
-#include <sys/fcntl.h>
-#include <sys/statfs.h>
-#include <string.h>
-#define NO_EID
-#define USE_WAITPID
-#define STATFS4
-#define NO_FSYNC
-#define USE_GETCWD
-#define USE_SETSID
-#define REPLACE_GETPASS
-#define NO_GETRLIMIT
-#endif /* CLIX */
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H)
+#define _I386_STATFS_H
+#define BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
-#ifdef BSDI
-#include <string.h>
-#include <netinet/tcp.h>
-#define SIGNAL_CAST (void (*)())
-#define USE_DIRECT
+#include <sys/capability.h>
+
+#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#undef _I386_STATFS_H
+#undef BROKEN_REDHAT_7_STATFS_WORKAROUND
#endif
+#endif
-#ifdef NETBSD
-#include <strings.h>
-#include <netinet/tcp.h>
-/* you may not need this */
-#define NO_GETSPNAM
-#define SIGNAL_CAST (void (*)())
-#define USE_DIRECT
-#define REPLACE_INNETGR
-#endif
+#if defined(HAVE_RPC_RPC_H)
+/*
+ * Check for AUTH_ERROR define conflict with rpc/rpc.h in prot.h.
+ */
+#if defined(HAVE_SYS_SECURITY_H) && defined(HAVE_RPC_AUTH_ERROR_CONFLICT)
+#undef AUTH_ERROR
+#endif
+#include <rpc/rpc.h>
+#endif
+#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined(HAVE_SETNETGRENT) && defined(HAVE_ENDNETGRENT) && defined(HAVE_GETNETGRENT)
+#define HAVE_NETGROUP 1
+#endif
+#if defined (HAVE_NETGROUP)
+#if defined(HAVE_RPCSVC_YP_PROT_H)
+#include <rpcsvc/yp_prot.h>
+#endif
+#if defined(HAVE_RPCSVC_YPCLNT_H)
+#include <rpcsvc/ypclnt.h>
+#endif
+#endif /* HAVE_NETGROUP */
-#ifdef FreeBSD
-#include <strings.h>
-#include <netinet/tcp.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#define SIGNAL_CAST (void (*)())
-#define USE_DIRECT
-#define REPLACE_INNETGR
-#endif
+#if defined(HAVE_SYS_IPC_H)
+#include <sys/ipc.h>
+#endif /* HAVE_SYS_IPC_H */
+#if defined(HAVE_SYS_SHM_H)
+#include <sys/shm.h>
+#endif /* HAVE_SYS_SHM_H */
+#ifdef HAVE_NATIVE_ICONV
+#include <iconv.h>
+#endif
-#ifdef AIX
-#include <strings.h>
-#include <sys/dir.h>
-#include <sys/select.h>
-#include <dirent.h>
-#include <sys/statfs.h>
-#include <sys/vfs.h>
-#include <sys/id.h>
-#include <sys/priv.h>
-#include <netinet/tcp.h>
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)())
-#define DEFAULT_PRINTING PRINT_AIX
+#if HAVE_KRB5_H
+#include <krb5.h>
+#else
+#undef HAVE_KRB5
#endif
+#if HAVE_LDAP_H
+#include <ldap.h>
+#else
+#undef HAVE_LDAP
+#endif
-#ifdef HPUX
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/vfs.h>
-#include <sys/types.h>
-#include <sys/termios.h>
-#include <netinet/tcp.h>
-#ifdef HPUX_10_TRUSTED
-#include <hpsecurity.h>
-#include <prot.h>
-#define NEED_AUTH_PARAMETERS
-#endif
-#define SIGNAL_CAST (void (*)(__harg))
-#define SELECT_CAST (int *)
-#define SYSV
-#define USE_WAITPID
-#define WAIT3_CAST2 (int *)
-#define USE_GETCWD
-#define USE_SETSID
-#define USE_SETRES
-#define DEFAULT_PRINTING PRINT_HPUX
-#define SIGCLD_IGNORE
+#if HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#else
+#undef HAVE_KRB5
#endif
+#if HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#else
+#undef HAVE_KRB5
+#endif
-#ifdef SEQUENT
-#include <signal.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/statfs.h>
-#include <sys/stat.h>
-#include <sys/buf.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <fcntl.h>
-#define SIGNAL_CAST (void (*)(int))
-#define USE_WAITPID
-#define USE_GETCWD
-#define NO_EID
-#define STATFS4
-#define USE_DIRECT
+/* we support ADS if we have krb5 and ldap libs */
+#if defined(HAVE_KRB5) && defined(HAVE_LDAP)
+#define HAVE_ADS
#endif
-#ifdef NEXT2
-#include <sys/types.h>
-#include <strings.h>
-#include <dirent.h>
-#include <sys/vfs.h>
-#define bzero(b,len) memset(b,0,len)
-#define mode_t int
-#define NO_UTIMBUF
-#include <libc.h>
-#define NOSTRDUP
-#define USE_DIRECT
-#define USE_WAITPID
-#endif
+/*
+ * Define VOLATILE if needed.
+ */
+#if defined(HAVE_VOLATILE)
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
-#ifdef NEXT3_0
-#include <strings.h>
-#include <sys/dir.h>
-#include <sys/vfs.h>
-#define bzero(b,len) memset(b,0,len)
-#define NO_UTIMBUF
-#include <libc.h>
-#define NOSTRDUP
-#define USE_DIRECT
-#define mode_t int
-#define GID_TYPE int
-#define gid_t int
-#define SIGNAL_CAST (void (*)(int))
-#define WAIT3_CAST1 (union wait *)
-#define HAVE_GMTOFF
+/*
+ * Define additional missing types
+ */
+#ifndef HAVE_SIG_ATOMIC_T_TYPE
+typedef int sig_atomic_t;
#endif
+#ifndef HAVE_SOCKLEN_T_TYPE
+typedef int socklen_t;
+#endif
-#ifdef APOLLO
-#include <string.h>
-#include <fcntl.h>
-#include <sys/statfs.h>
-#define NO_UTIMBUF
-#define USE_DIRECT
-#define USE_GETCWD
-#define SIGNAL_CAST (void (*)())
-#define HAVE_FCNTL_LOCK 0
-#define HAVE_GETTIMEOFDAY
-#define STATFS4
+#ifndef uchar
+#define uchar unsigned char
#endif
+#ifdef HAVE_UNSIGNED_CHAR
+#define schar signed char
+#else
+#define schar char
+#endif
+/*
+ Samba needs type definitions for int16, int32, uint16 and uint32.
-#ifdef SCO
-#include <sys/netinet/tcp.h>
-#include <sys/netinet/in_systm.h>
-#include <sys/netinet/ip.h>
-#include <dirent.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/statfs.h>
-#include <sys/stropts.h>
-#include <limits.h>
-#ifdef EVEREST
-#include <unistd.h>
+ Normally these are signed and unsigned 16 and 32 bit integers, but
+ they actually only need to be at least 16 and 32 bits
+ respectively. Thus if your word size is 8 bytes just defining them
+ as signed and unsigned int will work.
+*/
+
+#ifndef uint8
+#define uint8 unsigned char
#endif
-#ifdef NETGROUP
-#include <rpcsvc/ypclnt.h>
+
+#if !defined(int16) && !defined(HAVE_INT16_FROM_RPC_RPC_H)
+#if (SIZEOF_SHORT == 4)
+#define int16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define int16 short
+#endif /* SIZEOF_SHORT != 4 */
#endif
-#ifdef SecureWare
-#include <sys/security.h>
-#include <sys/audit.h>
-#include <prot.h>
-#define crypt bigcrypt
-#endif
-#ifndef EVEREST
- #define ftruncate(f,l) syscall(0x0a28,f,l)
-#endif
-#define SIGNAL_CAST (void (*)(int))
-#define USE_WAITPID
-#define USE_GETCWD
-#define USE_SETSID
-#ifdef SCO3_2_2
-#define NO_EID
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int16 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
+#if (SIZEOF_SHORT == 4)
+#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define uint16 unsigned short
+#endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#if !defined(int32) && !defined(HAVE_INT32_FROM_RPC_RPC_H)
+#if (SIZEOF_INT == 4)
+#define int32 int
+#elif (SIZEOF_LONG == 4)
+#define int32 long
+#elif (SIZEOF_SHORT == 4)
+#define int32 short
#else
-#ifndef EVEREST
-#define USE_IFREQ
+/* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+#define int32 int
#endif
#endif
-#define STATFS4
-#define NO_FSYNC
-#ifndef EVEREST
-#define NO_INITGROUPS
+
+/*
+ * Note we duplicate the size tests in the unsigned
+ * case as int32 may be a typedef from rpc/rpc.h
+ */
+
+#if !defined(uint32) && !defined(HAVE_UINT32_FROM_RPC_RPC_H)
+#if (SIZEOF_INT == 4)
+#define uint32 unsigned int
+#elif (SIZEOF_LONG == 4)
+#define uint32 unsigned long
+#elif (SIZEOF_SHORT == 4)
+#define uint32 unsigned short
+#else
+/* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+#define uint32 unsigned
#endif
-#define HAVE_PATHCONF
-#define NO_GETRLIMIT
#endif
+/*
+ * Types for devices, inodes and offsets.
+ */
+
+#ifndef SMB_DEV_T
+#define SMB_DEV_T dev_t
+#endif
+/*
+ * Setup the correctly sized inode type.
+ */
-/* Definitions for RiscIX */
-#ifdef RiscIX
-#define SIGNAL_CAST (void (*)(int))
-#include <sys/dirent.h>
-#include <sys/acct.h>
-#include <sys/vfs.h>
-#include <string.h>
-#include <utime.h>
-#include <signal.h>
-#define HAVE_GETTIMEOFDAY
-#define NOSTRCASECMP
-#define NOSTRDUP
+#ifndef SMB_INO_T
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_INO64_T)
+# define SMB_INO_T ino64_t
+# else
+# define SMB_INO_T ino_t
+# endif
#endif
+#ifndef LARGE_SMB_INO_T
+# if (defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_INO64_T)) || (defined(SIZEOF_INO_T) && (SIZEOF_INO_T == 8))
+# define LARGE_SMB_INO_T 1
+# endif
+#endif
+#ifdef LARGE_SMB_INO_T
+#define SINO_T(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#else
+#define SINO_T(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#endif
-#ifdef ISC
-#include <net/errno.h>
-#include <string.h>
-#include <sys/dir.h>
-#include <dirent.h>
-#include <sys/statfs.h>
-#include <fcntl.h>
-#include <sys/sioctl.h>
-#include <stropts.h>
-#include <limits.h>
-#include <netinet/tcp.h>
-#define FIONREAD FIORDCHK
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)(int))
-#define USE_GETCWD
-#define USE_SETSID
-#define USE_IFREQ
-#define NO_FTRUNCATE
-#define STATFS4
-#define NO_FSYNC
+#ifndef SMB_OFF_T
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T)
+# define SMB_OFF_T off64_t
+# else
+# define SMB_OFF_T off_t
+# endif
#endif
+/* this should really be a 64 bit type if possible */
+#define br_off SMB_BIG_UINT
+#define SMB_OFF_T_BITS (sizeof(SMB_OFF_T)*8)
-#ifdef AUX
-#include <fstab.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/vfs.h>
-#include <fcntl.h>
-#include <termios.h>
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)(int))
-char *strdup (char *);
-#define USE_GETCWD
-#endif
+/*
+ * Set the define that tells us if we can do 64 bit
+ * NT SMB calls.
+ */
+#ifndef LARGE_SMB_OFF_T
+# if (defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T)) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8))
+# define LARGE_SMB_OFF_T 1
+# endif
+#endif
-#ifdef M88K_R3
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <termios.h>
-#define STATFS4
-#define SYSV
-#define USE_WAITPID
-#define SIGNAL_CAST (void (*)(int))
-char *strdup (char *);
-#define USE_GETCWD
-#define NO_FSYNC
-#define NO_EID
+#ifdef LARGE_SMB_OFF_T
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#define SOFF_T_R(p, ofs, v) (SIVAL(p,(ofs)+4,(v)&0xFFFFFFFF), SIVAL(p,ofs,(v)>>32))
+#else
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#define SOFF_T_R(p, ofs, v) (SIVAL(p,(ofs)+4,v),SIVAL(p,ofs,0))
#endif
+/*
+ * Type for stat structure.
+ */
-#ifdef DNIX
-#include <dirent.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/statfs.h>
-#include <sys/stropts.h>
-#define NO_GET_BROADCAST
-#define USE_WAITPID
-#define USE_GETCWD
-#define USE_SETSID
-#define STATFS4
-#define NO_EID
-#define PF_INET AF_INET
-#define NO_STRERROR
-#define ftruncate(f,l) chsize(f,l)
-#endif /* DNIX */
-
-#ifdef CONVEX
-#define SIGNAL_CAST (void (*)(int))
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/vfs.h>
-#include <fcntl.h>
-#define DONT_REINSTALL_SIG
-#define USE_SIGBLOCK
-#define USE_WAITPID
-#define SIGNAL_CAST (_SigFunc_Ptr_t)
-#define NO_GETSPNAM
-#define HAVE_MEMMOVE
-extern char *mktemp(char *);
-extern int fsync(int);
-extern int seteuid(uid_t);
-extern int setgroups(int, int *);
-extern int initgroups(char *, int);
-extern int statfs(char *, struct statfs *);
-extern int setegid(gid_t);
-extern int getopt(int, char *const *, const char *);
-extern int chroot(char *);
-extern int gettimeofday(struct timeval *, struct timezone *);
-extern int gethostname(char *, int);
-extern char *crypt(char *, char *);
-extern char *getpass(char *);
-#endif
-
-
-#ifdef CRAY
-#define MAXPATHLEN 1024
-#include <dirent.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/statfs.h>
-#define SIGNAL_CAST (void (*)(int))
-#define SIGCLD_IGNORE
-#define HAVE_FCNTL_LOCK 1
-#define USE_SETSID
-#define STATFS4
+#ifndef SMB_STRUCT_STAT
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STAT64) && defined(HAVE_OFF64_T)
+# define SMB_STRUCT_STAT struct stat64
+# else
+# define SMB_STRUCT_STAT struct stat
+# endif
#endif
+/*
+ * Type for dirent structure.
+ */
-#ifdef ALTOS
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/fcntl.h>
-#include <sys/statfs.h>
-#define const
-#define uid_t int
-#define gid_t int
-#define mode_t int
-#define ptrdiff_t int
-#define HAVE_GETGRNAM 0
-#define NO_EID
-#define NO_FSYNC
-#define NO_FTRUNCATE
-#define NO_GETRLIMIT
-#define NO_INITGROUPS
-#define NO_SELECT
-#define NO_SETGROUPS
-#define NO_STRERROR
-#define NO_STRFTIME
-#define NO_TM_NAME
-#define NO_UTIMEH
-#define NOSTRCASECMP
-#define REPLACE_MKTIME
-#define REPLACE_RENAME
-#define REPLACE_STRSTR
-#define STATFS4
-#define USE_GETCWD
+#ifndef SMB_STRUCT_DIRENT
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_DIRENT64)
+# define SMB_STRUCT_DIRENT struct dirent64
+# else
+# define SMB_STRUCT_DIRENT struct dirent
+# endif
#endif
-#ifdef QNX
-#define STATFS4
-#include <sys/statfs.h>
-#include <sys/select.h>
-#include <signal.h>
-#include <sys/dir.h>
-#define SIGNAL_CAST (void (*)())
-#define USE_WAITPID
-#define NO_INITGROUPS
-#define NO_SETGROUPS
-#define HAVE_TIMEZONE
-#define USE_GETCWD
-#define USE_SETSID
-#define HAVE_FCNTL_LOCK 1
-#define DEFAULT_PRINTING PRINT_QNX
+/*
+ * Defines for 64 bit fcntl locks.
+ */
+
+#ifndef SMB_STRUCT_FLOCK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_STRUCT_FLOCK struct flock64
+# else
+# define SMB_STRUCT_FLOCK struct flock
+# endif
#endif
+#ifndef SMB_F_SETLKW
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLKW F_SETLKW64
+# else
+# define SMB_F_SETLKW F_SETLKW
+# endif
+#endif
-#ifdef NEWS42
-#include <string.h>
-#include <dirent.h>
-#include <sys/vfs.h>
-#include <sys/timeb.h>
-typedef int mode_t;
+#ifndef SMB_F_SETLK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLK F_SETLK64
+# else
+# define SMB_F_SETLK F_SETLK
+# endif
#endif
-#ifdef OS2
-#include <dirent.h>
-#include <sys/statfs.h>
-#include <string.h>
-#include <limits.h>
-#define SIGNAL_CAST (void (*)())
-#define HAVE_FCNTL_LOCK 0
-#define USE_WAITPID
-#define NO_GET_BROADCAST
-#define NO_EID
-#define NO_SETGROUPS
-#define NO_INITGROUPS
-#define NO_CRYPT
-#define NO_STATFS
-#define NO_CHROOT
-#define NO_CHOWN
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
-#endif
-
-
-#ifdef LYNX
-#define SIGNAL_CAST (void (*)())
-#define WAIT3_CAST1 (union wait *)
-#define STATFS4
-#include <fcntl.h>
-#include <resource.h>
-#include <stat.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/statfs.h>
-#define USE_GETCWD
-#define USE_GETSID
+#ifndef SMB_F_GETLK
+# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_GETLK F_GETLK64
+# else
+# define SMB_F_GETLK F_GETLK
+# endif
#endif
+#if defined(HAVE_LONGLONG)
+#define SMB_BIG_UINT unsigned long long
+#define SMB_BIG_INT long long
+#define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#else
+#define SMB_BIG_UINT unsigned long
+#define SMB_BIG_INT long
+#define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#endif
-/*******************************************************************
-end of the platform specific sections
-********************************************************************/
+#define SMB_BIG_UINT_BITS (sizeof(SMB_BIG_UINT)*8)
-#ifdef SecureWare
-#define NEED_AUTH_PARAMETERS
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
-#ifdef REPLACE_GETPASS
-extern char *getsmbpass(char *);
-#define getpass(s) getsmbpass(s)
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
-#ifdef REPLACE_INNETGR
-#define innetgr(group,host,user,dom) InNetGr(group,host,user,dom)
+#ifndef HAVE_STRERROR
+extern char *sys_errlist[];
+#define strerror(i) sys_errlist[i]
#endif
-#ifndef FD_SETSIZE
-#define FD_SETSIZE 255
+#ifndef HAVE_ERRNO_DECL
+extern int errno;
#endif
-#ifndef MAXINT
-#define MAXINT ((((unsigned)1)<<(sizeof(int)*8-1))-1)
+#ifdef HAVE_BROKEN_GETGROUPS
+#define GID_T int
+#else
+#define GID_T gid_t
#endif
-#ifndef __STDC__
-#define const
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32 /* Guess... */
+#endif
+
+/* Lists, trees, caching, database... */
+#include "xfile.h"
+#include "intl.h"
+#include "ubi_sLinkList.h"
+#include "ubi_dLinkList.h"
+#include "dlinklist.h"
+#include "../tdb/tdb.h"
+#include "../tdb/spinlock.h"
+#include "talloc.h"
+#include "ads.h"
+#include "interfaces.h"
+#include "hash.h"
+#include "trans2.h"
+#include "nterr.h"
+#include "secrets.h"
+#include "messages.h"
+#include "util_list.h"
+#include "charset.h"
+#include "dynconfig.h"
+
+#include "util_getent.h"
+
+#ifndef UBI_BINTREE_H
+#include "ubi_Cache.h"
+#endif /* UBI_BINTREE_H */
+
+#include "debugparse.h"
+
+#include "version.h"
+#include "smb.h"
+#include "smbw.h"
+#include "nameserv.h"
+
+#include "byteorder.h"
+
+#include "ntdomain.h"
+
+#include "msdfs.h"
+
+#include "smbprofile.h"
+
+#include "mapping.h"
+
+#include "rap.h"
+
+#include "md5.h"
+#include "hmacmd5.h"
+
+#include "auth.h"
+
+#include "session.h"
+
+#include "asn1.h"
+
+#include "popt.h"
+
+#ifndef MAXCODEPAGELINES
+#define MAXCODEPAGELINES 256
#endif
-/* Now for some other grungy stuff */
-#ifdef NO_GETSPNAM
-struct spwd { /* fake shadow password structure */
- char *sp_pwdp;
+/*
+ * Type for wide character dirent structure.
+ * Only d_name is defined by POSIX.
+ */
+
+typedef struct smb_wdirent {
+ wpstring d_name;
+} SMB_STRUCT_WDIRENT;
+
+/*
+ * Type for wide character passwd structure.
+ */
+
+typedef struct smb_wpasswd {
+ wfstring pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ wpstring pw_gecos;
+ wpstring pw_dir;
+ wpstring pw_shell;
+} SMB_STRUCT_WPASSWD;
+
+/* used in net.c */
+struct functable {
+ char *funcname;
+ int (*fn)(int argc, const char **argv);
};
-#endif
-#ifndef HAVE_BZERO
-#ifndef bzero
-#define bzero(p,s) memset(p,0,s)
-#endif
-#endif
-#ifndef HAVE_MEMMOVE
-#ifndef memmove
-#define memmove(d,s,n) MemMove(d,s,n)
-#endif
-#endif
+/* Defines for wisXXX functions. */
+#define UNI_UPPER 0x1
+#define UNI_LOWER 0x2
+#define UNI_DIGIT 0x4
+#define UNI_XDIGIT 0x8
+#define UNI_SPACE 0x10
-#ifdef USE_DIRECT
-#include <sys/dir.h>
-#endif
+#include "nsswitch/nss.h"
+
+/***** automatically generated prototypes *****/
+#include "proto.h"
-/* some unixes have ENOTTY instead of TIOCNOTTY */
-#ifndef TIOCNOTTY
-#ifdef ENOTTY
-#define TIOCNOTTY ENOTTY
+/* String routines */
+
+#include "safe_string.h"
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
#endif
-#ifndef SIGHUP
-#define SIGHUP 1
+/* this guess needs to be improved (tridge) */
+#if (defined(STAT_STATVFS) || defined(STAT_STATVFS64)) && !defined(SYSV)
+#define SYSV 1
#endif
-/* if undefined then use bsd or sysv printing */
#ifndef DEFAULT_PRINTING
-#ifdef SYSV
+#ifdef HAVE_CUPS
+#define DEFAULT_PRINTING PRINT_CUPS
+#define PRINTCAP_NAME "cups"
+#elif defined(SYSV)
#define DEFAULT_PRINTING PRINT_SYSV
+#define PRINTCAP_NAME "lpstat"
#else
#define DEFAULT_PRINTING PRINT_BSD
+#define PRINTCAP_NAME "/etc/printcap"
#endif
#endif
+#ifndef PRINTCAP_NAME
+#define PRINTCAP_NAME "/etc/printcap"
+#endif
-#ifdef AFS_AUTH
-#include <afs/stds.h>
-#include <afs/kautils.h>
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
#endif
-#ifdef DFS_AUTH
-#include <dce/dce_error.h>
-#include <dce/sec_login.h>
+#ifndef MAP_FILE
+#define MAP_FILE 0
#endif
-#ifdef NO_UTIMBUF
-struct utimbuf {
- time_t actime;
- time_t modtime;
-};
+#if (!defined(WITH_NISPLUS) && !defined(WITH_LDAP) && !defined(WITH_TDB_SAM))
+#define USE_SMBPASS_DB 1
#endif
-#ifdef NO_STRERROR
-#ifndef strerror
-extern char *sys_errlist[];
-#define strerror(i) sys_errlist[i]
+#if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS)
+#define OSF1_ENH_SEC 1
+#endif
+
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
#endif
#endif
-#ifndef perror
-#define perror(m) printf("%s: %s\n",m,strerror(errno))
+/* what is the longest significant password available on your system?
+ Knowing this speeds up password searches a lot */
+#ifndef PASSWORD_LENGTH
+#define PASSWORD_LENGTH 8
#endif
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 255
+#ifdef REPLACE_INET_NTOA
+#define inet_ntoa rep_inet_ntoa
#endif
-#include "version.h"
-#include "smb.h"
-#include "byteorder.h"
-#ifdef SMB_PASSWD
-#include "smbpass.h"
+#ifndef HAVE_PIPE
+#define SYNC_DNS 1
#endif
-#include "kanji.h"
-#include "charset.h"
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
-#ifndef S_IFREG
-#define S_IFREG 0100000
+#ifndef SEEK_SET
+#define SEEK_SET 0
#endif
-#ifndef S_ISREG
-#define S_ISREG(x) ((S_IFREG & x)!=0)
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
#endif
-#ifndef S_ISDIR
-#define S_ISDIR(x) ((S_IFDIR & x)!=0)
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
#endif
-#ifdef UFC_CRYPT
+#ifndef HAVE_CRYPT
#define crypt ufc_crypt
#endif
-#ifdef REPLACE_STRLEN
-#define strlen(s) Strlen(s)
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
-#ifdef REPLACE_STRSTR
-#define strstr(s,p) Strstr(s,p)
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
#endif
-#ifdef REPLACE_MKTIME
-#define mktime(t) Mktime(t)
+#ifdef HAVE_LIBREADLINE
+# ifdef HAVE_READLINE_READLINE_H
+# include <readline/readline.h>
+# ifdef HAVE_READLINE_HISTORY_H
+# include <readline/history.h>
+# endif
+# else
+# ifdef HAVE_READLINE_H
+# include <readline.h>
+# ifdef HAVE_HISTORY_H
+# include <history.h>
+# endif
+# else
+# undef HAVE_LIBREADLINE
+# endif
+# endif
#endif
-#ifndef NGROUPS_MAX
-#define NGROUPS_MAX 128
+#ifndef HAVE_STRDUP
+char *strdup(const char *s);
#endif
-#ifndef EDQUOT
-#define EDQUOT ENOSPC
+#ifndef HAVE_MEMMOVE
+void *memmove(void *dest,const void *src,int size);
#endif
-#ifndef HAVE_GETGRNAM
-#define HAVE_GETGRNAM 1
+#ifndef HAVE_INITGROUPS
+int initgroups(char *name,gid_t id);
#endif
-#ifndef SOL_TCP
-#define SOL_TCP 6
+#ifndef HAVE_RENAME
+int rename(const char *zfrom, const char *zto);
#endif
-/* default to using ftruncate workaround as this is safer than assuming
-it works and getting lots of bug reports */
-#ifndef FTRUNCATE_CAN_EXTEND
-#define FTRUNCATE_CAN_EXTEND 0
+#ifndef HAVE_MKTIME
+time_t mktime(struct tm *t);
#endif
-/* maybe this unix doesn't separate RD and WR locks? */
-#ifndef F_RDLCK
-#define F_RDLCK F_WRLCK
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *d, const char *s, size_t bufsize);
#endif
-#ifndef ENOTSOCK
-#define ENOTSOCK EINVAL
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
-#ifndef SIGCLD
-#define SIGCLD SIGCHLD
-#endif
+#ifndef HAVE_FTRUNCATE
+int ftruncate(int f,long l);
+#endif
-#ifndef HAVE_FCNTL_LOCK
-#define HAVE_FCNTL_LOCK 1
+#ifndef HAVE_STRTOUL
+unsigned long strtoul(const char *nptr, char **endptr, int base);
#endif
-#ifndef WAIT3_CAST2
-#define WAIT3_CAST2 (struct rusage *)
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESUID_DECL))
+/* stupid glibc */
+int setresuid(uid_t ruid, uid_t euid, uid_t suid);
+#endif
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL))
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+#endif
+#ifndef HAVE_VASPRINTF_DECL
+int vasprintf(char **ptr, const char *format, va_list ap);
#endif
-#ifndef WAIT3_CAST1
-#define WAIT3_CAST1 (int *)
+#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET)
+#define bzero(a,b) memset((a),'\0',(b))
#endif
-#ifndef QSORT_CAST
-#define QSORT_CAST (int (*)())
+#ifdef REPLACE_GETPASS
+#define getpass(prompt) getsmbpass((prompt))
#endif
-/* this is a rough check to see if this machine has a lstat() call.
- it is not guaranteed to work */
-#if !(defined(S_ISLNK) || defined(S_IFLNK))
-#define lstat stat
+/*
+ * Some older systems seem not to have MAXHOSTNAMELEN
+ * defined.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 254
#endif
-/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
-#ifndef errno
-extern int errno;
-#endif
+/* yuck, I'd like a better way of doing this */
+#define DIRP_SIZE (256 + 32)
+/*
+ * glibc on linux doesn't seem to have MSG_WAITALL
+ * defined. I think the kernel has it though..
+ */
-#ifdef NO_EID
-#define geteuid() getuid()
-#define getegid() getgid()
-#define seteuid(x) setuid(x)
-#define setegid(x) setgid(x)
+#ifndef MSG_WAITALL
+#define MSG_WAITALL 0
#endif
+/* default socket options. Dave Miller thinks we should default to TCP_NODELAY
+ given the socket IO pattern that Samba uses */
+#ifdef TCP_NODELAY
+#define DEFAULT_SOCKET_OPTIONS "TCP_NODELAY"
+#else
+#define DEFAULT_SOCKET_OPTIONS ""
+#endif
-#if (HAVE_FCNTL_LOCK == 0)
-/* since there is no locking available, system includes */
-/* for DomainOS 10.4 do not contain any of the following */
-/* #define's. So, to satisfy the compiler, add these */
-/* #define's, although they arn't really necessary. */
-#define F_GETLK 0
-#define F_SETLK 0
-#define F_WRLCK 0
-#define F_UNLCK 0
-#endif /* HAVE_FCNTL_LOCK == 0 */
+/* Load header file for libdl stuff */
-#ifdef NOSTRCASECMP
-#define strcasecmp(s1,s2) StrCaseCmp(s1,s2)
-#define strncasecmp(s1,s2,n) StrnCaseCmp(s1,s2,n)
+#ifdef HAVE_LIBDL
+#include <dlfcn.h>
#endif
-#ifndef strcpy
-#define strcpy(dest,src) StrCpy(dest,src)
+/* dmalloc -- free heap debugger (dmalloc.org). This should be near
+ * the *bottom* of include files so as not to conflict. */
+#ifdef DMALLOC
+# include <dmalloc.h>
#endif
-/* possibly wrap the malloc calls */
-#if WRAP_MALLOC
+/* Some POSIX definitions for those without */
+
+#ifndef S_IFDIR
+#define S_IFDIR 0x4000
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR)
+#endif
+#ifndef S_IRWXU
+#define S_IRWXU 00700 /* read, write, execute: owner */
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 00400 /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200 /* write permission: owner */
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100 /* execute permission: owner */
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG 00070 /* read, write, execute: group */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040 /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020 /* write permission: group */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010 /* execute permission: group */
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 00007 /* read, write, execute: other */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004 /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002 /* write permission: other */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001 /* execute permission: other */
+#endif
-/* undo the old malloc def if necessary */
-#ifdef malloc
-#define xx_old_malloc malloc
-#undef malloc
+/* NetBSD doesn't have these */
+#ifndef SHM_R
+#define SHM_R 0400
#endif
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
+#ifndef SHM_W
+#define SHM_W 0200
+#endif
-/* undo the old realloc def if necessary */
-#ifdef realloc
-#define xx_old_realloc realloc
-#undef realloc
+#if HAVE_KERNEL_SHARE_MODES
+#ifndef LOCK_MAND
+#define LOCK_MAND 32 /* This is a mandatory flock */
+#define LOCK_READ 64 /* ... Which allows concurrent read operations */
+#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
+#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
+#endif
#endif
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
+extern int DEBUGLEVEL;
-/* undo the old free def if necessary */
-#ifdef free
-#define xx_old_free free
-#undef free
-#endif
+#define MAX_SEC_CTX_DEPTH 8 /* Maximum number of security contexts */
-#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
-/* and the malloc prototypes */
-void *malloc_wrapped(int,char *,int);
-void *realloc_wrapped(void *,int,char *,int);
-void free_wrapped(void *,char *,int);
+#ifdef GLIBC_HACK_FCNTL64
+/* this is a gross hack. 64 bit locking is completely screwed up on
+ i386 Linux in glibc 2.1.95 (which ships with RedHat 7.0). This hack
+ "fixes" the problem with the current 2.4.0test kernels
+*/
+#define fcntl fcntl64
+#undef F_SETLKW
+#undef F_SETLK
+#define F_SETLK 13
+#define F_SETLKW 14
+#endif
+
+/* Needed for sys_dlopen/sys_dlsym/sys_dlclose */
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
#endif
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
-#if WRAP_MEMCPY
-/* undo the old memcpy def if necessary */
-#ifdef memcpy
-#define xx_old_memcpy memcpy
-#undef memcpy
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
#endif
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+/* needed for some systems without iconv. Doesn't really matter
+ what error code we use */
+#ifndef EILSEQ
+#define EILSEQ EIO
#endif
+/* add varargs prototypes with printf checking */
+int fdprintf(int , const char *, ...) PRINTF_ATTRIBUTE(2,3);
+int d_printf(const char *, ...) PRINTF_ATTRIBUTE(1,2);
+int d_fprintf(FILE *f, const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#ifndef HAVE_SNPRINTF_DECL
+int snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+#ifndef HAVE_ASPRINTF_DECL
+int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
#endif
+
+/* we used to use these fns, but now we have good replacements
+ for snprintf and vsnprintf */
+#define slprintf snprintf
+#define vslprintf vsnprintf
+
+#endif /* _INCLUDES_H */
+
diff --git a/source/include/interfaces.h b/source/include/interfaces.h
new file mode 100644
index 00000000000..3b786f1ebcb
--- /dev/null
+++ b/source/include/interfaces.h
@@ -0,0 +1,12 @@
+/*
+ This structure is used by lib/interfaces.c to return the list of network
+ interfaces on the machine
+*/
+
+#define MAX_INTERFACES 128
+
+struct iface_struct {
+ char name[16];
+ struct in_addr ip;
+ struct in_addr netmask;
+};
diff --git a/source/include/intl.h b/source/include/intl.h
new file mode 100644
index 00000000000..6bde64f0908
--- /dev/null
+++ b/source/include/intl.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ internationalisation headers
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/* ideally we would have a static mapping, but that precludes
+ dynamic loading. This is a reasonable compromise */
+#define _(x) lang_msg_rotate(x)
diff --git a/source/include/kanji.h b/source/include/kanji.h
deleted file mode 100644
index 4f18305c637..00000000000
--- a/source/include/kanji.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Adding for Japanese language by <fujita@ainix.isac.co.jp> 1994.9.5
- and extend coding system to EUC/SJIS/JIS/HEX at 1994.10.11
- and add all jis codes sequence at 1995.8.16
- Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp>
-*/
-#ifndef _KANJI_H_
-#define _KANJI_H_
-
-#ifdef KANJI
-
-/* FOR SHIFT JIS CODE */
-#define is_shift_jis(c) \
- ((0x81 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0x9f) \
- || (0xe0 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xef))
-#define is_shift_jis2(c) \
- (0x40 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xfc \
- && ((unsigned char) (c)) != 0x7f)
-#define is_kana(c) ((0xa0 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xdf))
-
-#ifdef _KANJI_C_
-/* FOR EUC CODE */
-#define euc_kana (0x8e)
-#define is_euc_kana(c) (((unsigned char) (c)) == euc_kana)
-#define is_euc(c) (0xa0 < ((unsigned char) (c)) && ((unsigned char) (c)) < 0xff)
-
-/* FOR JIS CODE */
-/* default jis third shift code, use for output */
-#ifndef JIS_KSO
-#define JIS_KSO 'B'
-#endif
-#ifndef JIS_KSI
-#define JIS_KSI 'J'
-#endif
-/* in: \E$B or \E$@ */
-/* out: \E(J or \E(B or \E(H */
-#define jis_esc (0x1b)
-#define jis_so (0x0e)
-#define jis_so1 ('$')
-#define jis_so2 ('B')
-#define jis_si (0x0f)
-#define jis_si1 ('(')
-#define jis_si2 ('J')
-#define is_esc(c) (((unsigned char) (c)) == jis_esc)
-#define is_so1(c) (((unsigned char) (c)) == jis_so1)
-#define is_so2(c) (((unsigned char) (c)) == jis_so2 || ((unsigned char) (c)) == '@')
-#define is_si1(c) (((unsigned char) (c)) == jis_si1)
-#define is_si2(c) (((unsigned char) (c)) == jis_si2 || ((unsigned char) (c)) == 'B' \
- || ((unsigned char) (c)) == 'H')
-#define is_so(c) (((unsigned char) (c)) == jis_so)
-#define is_si(c) (((unsigned char) (c)) == jis_si)
-#define junet_kana1 ('(')
-#define junet_kana2 ('I')
-#define is_juk1(c) (((unsigned char) (c)) == junet_kana1)
-#define is_juk2(c) (((unsigned char) (c)) == junet_kana2)
-
-#define _KJ_ROMAN (0)
-#define _KJ_KANJI (1)
-#define _KJ_KANA (2)
-
-/* FOR HEX */
-#define HEXTAG ':'
-#define hex2bin(x) \
- ( ((int) '0' <= ((int) (x)) && ((int) (x)) <= (int)'9')? \
- (((int) (x))-(int)'0'): \
- ((int) 'a'<= ((int) (x)) && ((int) (x))<= (int) 'f')? \
- (((int) (x)) - (int)'a'+10): \
- (((int) (x)) - (int)'A'+10) )
-#define bin2hex(x) \
- ( (((int) (x)) >= 10)? (((int) (x))-10 + (int) 'a'): (((int) (x)) + (int) '0') )
-
-#else /* not _KANJI_C_ */
-
-extern char* (*_dos_to_unix) (const char *str, BOOL overwrite);
-extern char* (*_unix_to_dos) (const char *str, BOOL overwrite);
-
-#define unix_to_dos (*_unix_to_dos)
-#define dos_to_unix (*_dos_to_unix)
-
-extern char *sj_strtok (char *s1, const char *s2);
-extern char *sj_strchr (const char *s, int c);
-extern char *sj_strrchr (const char *s, int c);
-extern char *sj_strstr (const char *s1, const char *s2);
-
-#define strchr sj_strchr
-#define strrchr sj_strrchr
-#define strstr sj_strstr
-#define strtok sj_strtok
-
-#endif /* _KANJI_C_ */
-
-#define UNKNOWN_CODE (-1)
-#define SJIS_CODE (0)
-#define EUC_CODE (1)
-#define JIS7_CODE (2)
-#define JIS8_CODE (3)
-#define JUNET_CODE (4)
-#define HEX_CODE (5)
-#define CAP_CODE (6)
-#define DOSV_CODE SJIS_CODE
-
-int interpret_coding_system (char *str, int def);
-
-#else
-
-#define unix_to_dos(x,y) (x)
-#define dos_to_unix(x,y) (x)
-
-#endif /* not KANJI */
-
-#endif /* _KANJI_H_ */
diff --git a/source/include/libsmbclient.h b/source/include/libsmbclient.h
new file mode 100644
index 00000000000..98701b2693e
--- /dev/null
+++ b/source/include/libsmbclient.h
@@ -0,0 +1,791 @@
+/*=====================================================================
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library API definitions
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ =====================================================================*/
+
+#ifndef SMBCLIENT_H_INCLUDED
+#define SMBCLIENT_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/* The following are special comments to instruct DOXYGEN (automated
+ * documentation tool:
+*/
+/** \defgroup libsmbclient
+*/
+/** \defgroup structure Data Structures Type and Constants
+* \ingroup libsmbclient
+* Data structures, types, and constants
+*/
+/** \defgroup file File Functions
+* \ingroup libsmbclient
+* Functions used to access individual file contents
+*/
+/** \defgroup directory Directory Functions
+* \ingroup libsmbclient
+* Functions used to access directory entries
+*/
+/** \defgroup attribute Attributes Functions
+* \ingroup libsmbclient
+* Functions used to view or change file and directory attributes
+*/
+/** \defgroup print Print Functions
+* \ingroup libsmbclient
+* Functions used to access printing functionality
+*/
+/** \defgroup attribute Miscellaneous Functions
+* \ingroup libsmbclient
+* Functions that don't fit in to other categories
+*/
+/*-------------------------------------------------------------------*/
+
+/* Make sure we have the following includes for now ... */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define SMBC_MAX_NAME 1023
+#define SMBC_WORKGROUP 1
+#define SMBC_SERVER 2
+#define SMBC_FILE_SHARE 3
+#define SMBC_PRINTER_SHARE 4
+#define SMBC_COMMS_SHARE 5
+#define SMBC_IPC_SHARE 6
+#define SMBC_DIR 7
+#define SMBC_FILE 8
+#define SMBC_LINK 9
+
+#define SMBC_FILE_MODE (S_IFREG | 0444)
+#define SMBC_DIR_MODE (S_IFDIR | 0555)
+
+#define SMBC_MAX_FD 10000
+
+
+/**@ingroup structure
+ * Structure that represents a directory entry.
+ *
+ */
+struct smbc_dirent
+{
+ /** Type of entity.
+ SMBC_WORKGROUP=1,
+ SMBC_SERVER=2,
+ SMBC_FILE_SHARE=3,
+ SMBC_PRINTER_SHARE=4,
+ SMBC_COMMS_SHARE=5,
+ SMBC_IPC_SHARE=6,
+ SMBC_DIR=7,
+ SMBC_FILE=8,
+ SMBC_LINK=9,*/
+ uint smbc_type;
+
+ /** Length of this smbc_dirent in bytes
+ */
+ uint dirlen;
+ /** The length of the comment string in bytes (includes null
+ * terminator)
+ */
+ uint commentlen;
+ /** Points to the null terminated comment string
+ */
+ char *comment;
+ /** The length of the name string in bytes (includes null
+ * terminator)
+ */
+ uint namelen;
+ /** Points to the null terminated name string
+ */
+ char name[1];
+};
+
+
+#ifndef _CLIENT_H
+typedef unsigned short uint16;
+
+/**@ingroup structure
+ * Structure that represents a print job.
+ *
+ */
+struct print_job_info
+{
+ /** numeric ID of the print job
+ */
+ uint16 id;
+
+ /** represents print job priority (lower numbers mean higher priority)
+ */
+ uint16 priority;
+
+ /** Size of the print job
+ */
+ size_t size;
+
+ /** Name of the user that owns the print job
+ */
+ char user[128];
+
+ /** Name of the print job. This will have no name if an anonymous print
+ * file was opened. Ie smb://server/printer
+ */
+ char name[128];
+
+ /** Time the print job was spooled
+ */
+ time_t t;
+};
+#endif
+
+
+/**@ingroup structure
+ * Authentication callback function type.
+ *
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * @param srv Server being authenticated to
+ *
+ * @param shr Share being authenticated to
+ *
+ * @param wg Pointer to buffer containing a "hint" for the
+ * workgroup to be authenticated. Should be filled in
+ * with the correct workgroup if the hint is wrong.
+ *
+ * @param wglen The size of the workgroup buffer in bytes
+ *
+ * @param un Pointer to buffer containing a "hint" for the
+ * user name to be use for authentication. Should be
+ * filled in with the correct workgroup if the hint is
+ * wrong.
+ *
+ * @param unlen The size of the username buffer in bytes
+ *
+ * @param pw Pointer to buffer containing to which password
+ * copied
+ *
+ * @param pwlen The size of the password buffer in bytes
+ *
+ */
+typedef void (*smbc_get_auth_data_fn)(const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen);
+
+
+/**@ingroup structure
+ * Print job info callback function type.
+ *
+ * @param i pointer to print job information structure
+ *
+ */
+typedef void (*smbc_get_print_job_info)(struct print_job_info *i);
+
+
+/**@ingroup misc
+ * Initialize the samba client library.
+ *
+ * Must be called before using any of the smbclient API function
+ *
+ * @param fn The function that will be called to obtaion
+ * authentication credentials.
+ *
+ * @param debug Allows caller to set the debug level. Can be
+ * changed in smb.conf file. Allows caller to set
+ * debugging if no smb.conf.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - ENOENT The smb.conf file would not load
+ *
+ */
+int smbc_init(smbc_get_auth_data_fn fn, int debug);
+
+
+/**@ingroup file
+ * Open a file on an SMB server.
+ *
+ * @param furl The smb url of the file to be opened.
+ *
+ * @param flags Is one of O_RDONLY, O_WRONLY or O_RDWR which
+ * request opening the file read-only,write-only
+ * or read/write. flags may also be bitwise-or'd with
+ * one or more of the following:
+ * O_CREAT - If the file does not exist it will be
+ * created.
+ * O_EXCL - When used with O_CREAT, if the file
+ * already exists it is an error and the open will
+ * fail.
+ * O_TRUNC - If the file already exists it will be
+ * truncated.
+ * O_APPEND The file is opened in append mode
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * Not currently use, but there for future use.
+ * We will map this to SYSTEM, HIDDEN, etc bits
+ * that reverses the mapping that smbc_fstat does.
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENODEV The requested share does not exist
+ * - ENOTDIR A file on the path is not a directory
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ *
+ * @see smbc_creat()
+ *
+ * @note This call uses an underlying routine that may create
+ * a new connection to the server specified in the URL.
+ * If the credentials supplied in the URL, or via the
+ * auth_fn in the smbc_init call, fail, this call will
+ * try again with an empty username and password. This
+ * often gets mapped to the guest account on some machines.
+ */
+int smbc_open(const char *furl, int flags, mode_t mode);
+
+
+/**@ingroup file
+ * Create a file on an SMB server.
+ *
+ * Same as calling smbc_open() with flags = O_CREAT|O_WRONLY|O_TRUNC
+ *
+ * @param furl The smb url of the file to be created
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * NOTE, the above is not true. We are dealing with
+ * an SMB server, which has no concept of a umask!
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ * - ENODEV The requested share does not exist.
+ * @see smbc_open()
+ *
+ */
+int smbc_creat(const char *furl, mode_t mode);
+
+
+/**@ingroup file
+ * Read from a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes read, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_write()
+ *
+ */
+ssize_t smbc_read(int fd, void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Write to a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes written, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory.
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_read()
+ *
+ */
+ssize_t smbc_write(int fd, void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Seek to a specific location in a file.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param offset Offset in bytes from whence
+ *
+ * @param whence A location in the file:
+ * - SEEK_SET The offset is set to offset bytes from
+ * the beginning of the file
+ * - SEEK_CUR The offset is set to current location
+ * plus offset bytes.
+ * - SEEK_END The offset is set to the size of the
+ * file plus offset bytes.
+ *
+ * @return Upon successful completion, lseek returns the
+ * resulting offset location as measured in bytes
+ * from the beginning of the file. Otherwise, a value
+ * of (off_t)-1 is returned and errno is set to
+ * indicate the error:
+ * - EBADF Fildes is not an open file descriptor.
+ * - EINVAL Whence is not a proper value or smbc_init
+ * not called.
+ *
+ * @todo Are all the whence values really supported?
+ *
+ * @todo Are errno values complete and correct?
+ */
+off_t smbc_lseek(int fd, off_t offset, int whence);
+
+
+/**@ingroup file
+ * Close an open file handle.
+ *
+ * @param fd The file handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF fd isn't a valid open file descriptor
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_open(), smbc_creat()
+ */
+int smbc_close(int fd);
+
+
+/**@ingroup directory
+ * Unlink (delete) a file or directory.
+ *
+ * @param furl The smb url of the file to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname is not allowed or one
+ * of the directories in pathname did not allow
+ * search (execute) permission
+ * - ENOENT A directory component in pathname does
+ * not exist
+ * - EINVAL NULL was passed in the file param or
+ * smbc_init not called.
+ * - EACCES You do not have access to the file
+ * - ENOMEM Insufficient kernel memory was available
+ *
+ * @see smbc_rmdir()s
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_unlink(const char *furl);
+
+
+/**@ingroup directory
+ * Rename or move a file or directory.
+ *
+ * @param ourl The original smb url (source url) of file or
+ * directory to be moved
+ *
+ * @param nurl The new smb url (destination url) of the file
+ * or directory after the move. Currently nurl must
+ * be on the same share as ourl.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EISDIR nurl is an existing directory, but ourl is
+ * not a directory.
+ * - EEXIST nurl is a non-empty directory,
+ * i.e., contains entries other than "." and ".."
+ * - EINVAL The new url contained a path prefix
+ * of the old, or, more generally, an attempt was
+ * made to make a directory a subdirectory of itself
+ * or smbc_init not called.
+ * - ENOTDIR A component used as a directory in ourl
+ * or nurl path is not, in fact, a directory. Or,
+ * ourl is a directory, and newpath exists but is not
+ * a directory.
+ * - EACCES or EPERM Write access to the directory
+ * containing ourl or nurl is not allowed for the
+ * process's effective uid, or one of the
+ * directories in ourl or nurl did not allow search
+ * (execute) permission, or ourl was a directory
+ * and did not allow write permission.
+ * - ENOENT A directory component in ourl or nurl
+ * does not exist.
+ * - EXDEV Rename across shares not supported.
+ * - ENOMEM Insufficient kernel memory was available.
+ * - EEXIST The target file, nurl, already exists.
+ *
+ *
+ * @todo Are we going to support copying when urls are not on the same
+ * share? I say no... NOTE. I agree for the moment.
+ *
+ */
+int smbc_rename(const char *ourl, const char *nurl);
+
+
+/**@ingroup directory
+ * Open a directory used to obtain directory entries.
+ *
+ * @param durl The smb url of the directory to open
+ *
+ * @return Valid directory handle. < 0 on error with errno set:
+ * - EACCES Permission denied.
+ * - EINVAL A NULL file/URL was passed, or the URL would
+ * not parse, or was of incorrect form or smbc_init not
+ * called.
+ * - ENOENT durl does not exist, or name is an
+ * - ENOMEM Insufficient memory to complete the
+ * operation.
+ * - ENOTDIR name is not a directory.
+ * - EPERM the workgroup could not be found.
+ * - ENODEV the workgroup or server could not be found.
+ *
+ * @see smbc_getdents(), smbc_readdir(), smbc_closedir()
+ *
+ */
+int smbc_opendir(const char *durl);
+
+
+/**@ingroup directory
+ * Close a directory handle opened by smbc_opendir().
+ *
+ * @param dh Directory handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF dh is an invalid directory handle
+ *
+ * @see smbc_opendir()
+ */
+int smbc_closedir(int dh);
+
+
+/**@ingroup directory
+ * Get multiple directory entries.
+ *
+ * smbc_getdents() reads as many dirent structures from the an open
+ * directory handle into a specified memory area as will fit.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @param dirp pointer to buffer that will receive the directory
+ * entries.
+ *
+ * @param count The size of the dirp buffer in bytes
+ *
+ * @returns If any dirents returned, return will indicate the
+ * total size. If there were no more dirents available,
+ * 0 is returned. < 0 indicates an error.
+ * - EBADF Invalid directory handle
+ * - EINVAL Result buffer is too small or smbc_init
+ * not called.
+ * - ENOENT No such directory.
+ * @see , smbc_dirent, smbc_readdir(), smbc_open()
+ *
+ * @todo Are errno values complete and correct?
+ *
+ * @todo Add example code so people know how to parse buffers.
+ */
+int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count);
+
+
+/**@ingroup directory
+ * Get a single directory entry.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return A pointer to a smbc_dirent structure, or NULL if an
+ * error occurs or end-of-directory is reached:
+ * - EBADF Invalid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_dirent, smbc_getdents(), smbc_open()
+ */
+struct smbc_dirent* smbc_readdir(unsigned int dh);
+
+
+/**@ingroup directory
+ * Get the current directory offset.
+ *
+ * smbc_telldir() may be used in conjunction with smbc_readdir() and
+ * smbc_lseekdir().
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return The current location in the directory stream or -1
+ * if an error occur. The current location is not
+ * an offset. Becuase of the implementation, it is a
+ * handle that allows the library to find the entry
+ * later.
+ * - EBADF dh is not a valid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ * - ENOTDIR if dh is not a directory
+ *
+ * @see smbc_readdir()
+ *
+ */
+off_t smbc_telldir(int dh);
+
+
+/**@ingroup directory
+ * lseek on directories.
+ *
+ * smbc_lseekdir() may be used in conjunction with smbc_readdir() and
+ * smbc_telldir(). (rewind by smbc_lseekdir(fd, NULL))
+ *
+ * @param fd Valid directory as returned by smbc_opendir()
+ *
+ * @param offset The offset (as returned by smbc_telldir). Can be
+ * NULL, in which case we will rewind
+ *
+ * @return 0 on success, -1 on failure
+ * - EBADF dh is not a valid directory handle
+ * - ENOTDIR if dh is not a directory
+ * - EINVAL offset did not refer to a valid dirent or
+ * smbc_init not called.
+ *
+ * @see smbc_telldir()
+ *
+ *
+ * @todo In what does the reture and errno values mean?
+ */
+int smbc_lseekdir(int fd, off_t offset);
+
+/**@ingroup directory
+ * Create a directory.
+ *
+ * @param durl The url of the directory to create
+ *
+ * @param mode Specifies the permissions to use. It is modified
+ * by the process's umask in the usual way: the
+ * permissions of the created file are (mode & ~umask).
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EEXIST directory url already exists
+ * - EACCES The parent directory does not allow write
+ * permission to the process, or one of the directories
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - EINVAL NULL durl passed or smbc_init not called.
+ * - ENOMEM Insufficient memory was available.
+ *
+ * @see smbc_rmdir()
+ *
+ */
+int smbc_mkdir(const char *durl, mode_t mode);
+
+
+/**@ingroup directory
+ * Remove a directory.
+ *
+ * @param durl The smb url of the directory to remove
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname was not allowed.
+ * - EINVAL durl is NULL or smbc_init not called.
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - ENOTEMPTY directory contains entries.
+ * - ENOMEM Insufficient kernel memory was available.
+ *
+ * @see smbc_mkdir(), smbc_unlink()
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_rmdir(const char *durl);
+
+
+/**@ingroup attribute
+ * Get information about a file or directory.
+ *
+ * @param url The smb url to get information for
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOENT A component of the path file_name does not
+ * exist.
+ * - EINVAL a NULL url was passed or smbc_init not called.
+ * - EACCES Permission denied.
+ * - ENOMEM Out of memory
+ * - ENOTDIR The target dir, url, is not a directory.
+ *
+ * @see Unix stat()
+ *
+ */
+int smbc_stat(const char *url, struct stat *st);
+
+
+/**@ingroup attribute
+ * Get file information via an file descriptor.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return EBADF filedes is bad.
+ * - EACCES Permission denied.
+ * - EBADF fd is not a valid file descriptor
+ * - EINVAL Problems occurred in the underlying routines
+ * or smbc_init not called.
+ * - ENOMEM Out of memory
+ *
+ * @see smbc_stat(), Unix stat()
+ *
+ */
+int smbc_fstat(int fd, struct stat *st);
+
+
+/**@ingroup attribue
+ * Change the ownership of a file or directory.
+ *
+ * @param url The smb url of the file or directory to change
+ * ownership of.
+ *
+ * @param owner I have no idea?
+ *
+ * @param group I have not idea?
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EPERM The effective UID does not match the owner
+ * of the file, and is not zero; or the owner or group
+ * were specified incorrectly.
+ * - ENOENT The file does not exist.
+ * - ENOMEM Insufficient was available.
+ * - ENOENT file or directory does not exist
+ *
+ * @todo Are we actually going to be able to implement this function
+ *
+ * @todo How do we abstract owner and group uid and gid?
+ *
+ */
+int smbc_chown(const char *url, uid_t owner, gid_t group);
+
+
+/**@ingroup attribute
+ * Change the permissions of a file.
+ *
+ * @param url The smb url of the file or directory to change
+ * permissions of
+ *
+ * @param mode The permissions to set:
+ * - Put good explaination of permissions here!
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EPERM The effective UID does not match the owner
+ * of the file, and is not zero
+ * - ENOENT The file does not exist.
+ * - ENOMEM Insufficient was available.
+ * - ENOENT file or directory does not exist
+ *
+ * @todo Actually implement this fuction?
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_chmod(const char *url, mode_t mode);
+
+
+/**@ingroup print
+ * Print a file given the name in fname. It would be a URL ...
+ *
+ * @param fname The URL of a file on a remote SMB server that the
+ * caller wants printed
+ *
+ * @param printq The URL of the print share to print the file to.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ *
+ * - EINVAL fname or printq was NULL or smbc_init not
+ * not called.
+ * and errors returned by smbc_open
+ *
+ */
+int smbc_print_file(const char *fname, const char *printq);
+
+/**@ingroup print
+ * Open a print file that can be written to by other calls. This simply
+ * does an smbc_open call after checking if there is a file name on the
+ * URI. If not, a temporary name is added ...
+ *
+ * @param fname The URL of the print share to print to?
+ *
+ * @returns A file handle for the print file if successful.
+ * Returns -1 if an error ocurred and errno has the values
+ * - EINVAL fname was NULL or smbc_init not called.
+ * - all errors returned by smbc_open
+ *
+ */
+int smbc_open_print_job(const char *fname);
+
+/**@ingroup print
+ * List the print jobs on a print share, for the moment, pass a callback
+ *
+ * @param purl The url of the print share to list the jobs of
+ *
+ * @param fn Callback function the receives printjob info
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ * - EACCES ???
+ */
+int smbc_list_print_jobs(const char *purl, smbc_get_print_job_info fn);
+
+/**@ingroup print
+ * Delete a print job
+ *
+ * @param purl Url of the print share
+ *
+ * @param id The id of the job to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ *
+ * @todo what errno values are possible here?
+ */
+int smbc_unlink_print_job(const char *purl, int id);
+
+
+#endif /* SMBCLIENT_H_INCLUDED */
diff --git a/source/include/local.h b/source/include/local.h
index 2775453e150..da9fee05642 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -1,7 +1,24 @@
+/* Copyright (C) 1995-1998 Samba-Team */
+/* Copyright (C) 1998 John H Terpstra <jht@aquasoft.com.au> */
+
/* local definitions for file server */
#ifndef _LOCAL_H
#define _LOCAL_H
+/* The default workgroup - usually overridden in smb.conf */
+#ifndef WORKGROUP
+#define WORKGROUP "WORKGROUP"
+#endif
+
+/* the maximum debug level to compile into the code. This assumes a good
+ optimising compiler that can remove unused code
+ for embedded or low-memory systems set this to a value like 2 to get
+ only important messages. This gives *much* smaller binaries
+*/
+#ifndef MAX_DEBUG_LEVEL
+#define MAX_DEBUG_LEVEL 1000
+#endif
+
/* This defines the section name in the configuration file that will contain */
/* global parameters - that is, parameters relating to the whole server, not */
/* just services. This name is then reserved, and may not be used as a */
@@ -17,57 +34,56 @@
refer to the special "printers" service */
#define PRINTERS_NAME "printers"
-/* This defines the name of the printcap file. It is MOST UNLIKELY that
- this will change BUT! Specifying a file with the format of a printcap
- file but containing only a subset of the printers actually in your real
- printcap file is a quick-n-dirty way to allow dynamic access to a subset
- of available printers.
-*/
-#define PRINTCAP_NAME "/etc/printcap"
-
-/* set these to define the limits of the server. NOTE These are on a
- per-client basis. Thus any one machine can't connect to more than
- MAX_CONNECTIONS services, but any number of machines may connect at
- one time. */
-#define MAX_CONNECTIONS 127
-#define MAX_OPEN_FILES 100
-
-/* the max number of connections that the smbstatus program will show */
-#define MAXSTATUS 1000
+/* Yves Gaige <yvesg@hptnodur.grenoble.hp.com> requested this set this */
+/* to a maximum of 8 if old smb clients break because of long printer names. */
+#define MAXPRINTERLEN 15
/* max number of directories open at once */
/* note that with the new directory code this no longer requires a
file handle per directory, but large numbers do use more memory */
-#define MAXDIR 64
+#define MAX_OPEN_DIRECTORIES 256
+
+/* max number of directory handles */
+/* As this now uses the bitmap code this can be
+ quite large. */
+#define MAX_DIRECTORY_HANDLES 2048
+
+/* maximum number of file caches per smbd */
+#define MAX_WRITE_CACHES 10
+
+/* define what facility to use for syslog */
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_DAEMON
+#endif
+
+/*
+ * Default number of maximum open files per smbd. This is
+ * also limited by the maximum available file descriptors
+ * per process and can also be set in smb.conf as "max open files"
+ * in the [global] section.
+ */
+
+#ifndef MAX_OPEN_FILES
+#define MAX_OPEN_FILES 10000
+#endif
+
+/* the max number of simultanous connections to the server by all clients */
+#define MAXSTATUS 100000
#define WORDMAX 0xFFFF
+/* the maximum password length before we declare a likely attack */
+#define MAX_PASS_LEN 200
/* separators for lists */
#define LIST_SEP " \t,;:\n\r"
-#ifndef LOCKDIR
-#define LOCKDIR "/tmp/samba"
-#endif
+/* wchar separators for lists */
+#define LIST_SEP_W wchar_list_sep
/* this is where browse lists are kept in the lock dir */
#define SERVER_LIST "browse.dat"
-/* the print command on the server, %s is replaced with the filename */
-/* note that the -r removes the file after printing - you'll run out */
-/* of disk pretty quickly if you don't. This command is only used as */
-/* the default - it can be overridden in the configuration file. */
-#define PRINT_COMMAND "lpr -r %s"
-
-/* the lpq command on the server. the printername is passed as an argument */
-#ifndef LPQ_COMMAND
-#define LPQ_COMMAND "lpq -P"
-#endif
-
-/* shall guest entries in printer queues get changed to user entries,
- so they can be deleted using the windows print manager? */
-#define LPQ_GUEST_TO_USER
-
/* shall filenames with illegal chars in them get mangled in long
filename listings? */
#define MANGLE_LONG_FILENAMES
@@ -79,43 +95,18 @@
/* the size of the directory cache */
#define DIRCACHESIZE 20
-/* what type of filesystem do we want this to show up as in a NT file
- manager window? */
-#define FSTYPE_STRING "Samba"
-
-/* we have two time standards - local and GMT. This will try to sort them out.
- */
-
-#define LOCAL_TO_GMT 1
-#define GMT_TO_LOCAL (-1)
+/* what default type of filesystem do we want this to show up as in a
+ NT file manager window? */
+#define FSTYPE_STRING "NTFS"
-/* do you want smbd to send a 1 byte packet to nmbd to trigger it to start
- when smbd starts? */
-#ifndef PRIME_NMBD
-#define PRIME_NMBD 1
+/* the default guest account - normally set in the Makefile or smb.conf */
+#ifndef GUEST_ACCOUNT
+#define GUEST_ACCOUNT "nobody"
#endif
-/* do you want session setups at user level security with a invalid
- password to be rejected or allowed in as guest? WinNT rejects them
- but it can be a pain as it means "net view" needs to use a password
-
- You have 3 choices:
-
- GUEST_SESSSETUP = 0 means session setups with an invalid password
- are rejected.
-
- GUEST_SESSSETUP = 1 means session setups with an invalid password
- are rejected, unless the username does not exist, in which case it
- is treated as a guest login
-
- GUEST_SESSSETUP = 2 means session setups with an invalid password
- are treated as a guest login
-
- Note that GUEST_SESSSETUP only has an effect in user or server
- level security.
- */
-#ifndef GUEST_SESSSETUP
-#define GUEST_SESSSETUP 0
+/* user to test password server with as invalid in security=server mode. */
+#ifndef INVALID_USER_PREFIX
+#define INVALID_USER_PREFIX "sambatest"
#endif
/* the default pager to use for the client "more" command. Users can
@@ -130,18 +121,19 @@
/* the following control timings of various actions. Don't change
them unless you know what you are doing. These are all in seconds */
#define DEFAULT_SMBD_TIMEOUT (60*60*24*7)
-#define SMBD_RELOAD_CHECK (10)
-#define SHARE_MODES_CHECK (10)
-#define SHARE_MODES_CLEAN (300)
+#define SMBD_RELOAD_CHECK (180)
#define IDLE_CLOSED_TIMEOUT (60)
#define DPTR_IDLE_TIMEOUT (120)
-#define SMBD_SELECT_LOOP (10)
+#define SMBD_SELECT_TIMEOUT (60)
+#define SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS (10)
#define NMBD_SELECT_LOOP (10)
#define BROWSE_INTERVAL (60)
#define REGISTRATION_INTERVAL (10*60)
#define NMBD_INETD_TIMEOUT (120)
#define NMBD_MAX_TTL (24*60*60)
#define LPQ_LOCK_TIMEOUT (5)
+#define NMBD_INTERFACES_RELOAD (120)
+#define NMBD_UNEXPECTED_TIMEOUT (15)
/* the following are in milliseconds */
#define LOCK_RETRY_TIMEOUT (100)
@@ -151,17 +143,57 @@
accessible to root */
#define DUMP_CORE 1
-/* what is the longest significant password available on your system?
- Knowing this speeds up password searches a lot */
-#ifndef PASSWORD_LENGTH
-#define PASSWORD_LENGTH 8
-#endif
+/* shall we support browse requests via a FIFO to nmbd? */
+#define ENABLE_FIFO 1
-#define SMB_ALIGNMENT 1
+/* how long (in miliseconds) to wait for a socket connect to happen */
+#define LONG_CONNECT_TIMEOUT 30000
+#define SHORT_CONNECT_TIMEOUT 5000
+/* the default netbios keepalive timeout */
+#define DEFAULT_KEEPALIVE 300
-/* shall we support browse requests via a FIFO to nmbd? */
-#define ENABLE_FIFO 1
+/* the directory to sit in when idle */
+/* #define IDLE_DIR "/" */
+
+/* Timout (in seconds) to wait for an oplock break
+ message to return from the client. */
+
+#define OPLOCK_BREAK_TIMEOUT 30
+
+/* Timout (in seconds) to add to the oplock break timeout
+ to wait for the smbd to smbd message to return. */
+
+#define OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR 2
+
+/* the read preciction code has been disabled until some problems with
+ it are worked out */
+#define USE_READ_PREDICTION 0
+
+/* name of directory that netatalk uses to store macintosh resource forks */
+#define APPLEDOUBLE ".AppleDouble/"
+
+/*
+ * Default passwd chat script.
+ */
+
+#define DEFAULT_PASSWD_CHAT "*new*password* %n\\n *new*password* %n\\n *changed*"
+
+/* Minimum length of allowed password when changing UNIX password. */
+#define MINPASSWDLENGTH 5
+
+/* maximum ID number used for session control. This cannot be larger
+ than 62*62 for the current code */
+#define MAX_SESSION_ID 3000
+
+#ifndef SESSION_TEMPLATE
+#define SESSION_TEMPLATE "smb/%d"
+#endif
+
+/* the maximum age in seconds of a password. Should be a lp_ parameter */
+#define MAX_PASSWORD_AGE (21*24*60*60)
+/* Allocation roundup. */
+#define SMB_ROUNDUP_ALLOCATION_SIZE 0x100000
#endif
diff --git a/source/include/mapping.h b/source/include/mapping.h
new file mode 100644
index 00000000000..9b46989ccb7
--- /dev/null
+++ b/source/include/mapping.h
@@ -0,0 +1,61 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define PRIV_ALL_INDEX 5
+
+#define SE_PRIV_NONE 0x0000
+#define SE_PRIV_ADD_MACHINES 0x0006
+#define SE_PRIV_SEC_PRIV 0x0008
+#define SE_PRIV_TAKE_OWNER 0x0009
+#define SE_PRIV_ADD_USERS 0xff01
+#define SE_PRIV_PRINT_OPERATOR 0xff03
+#define SE_PRIV_ALL 0xffff
+
+#define ENUM_ONLY_MAPPED True
+#define ENUM_ALL_MAPPED False
+
+#define MAPPING_WITH_PRIV True
+#define MAPPING_WITHOUT_PRIV False
+
+#define PR_NONE 0x0000
+#define PR_LOG_ON_LOCALLY 0x0001
+#define PR_ACCESS_FROM_NETWORK 0x0002
+#define PR_LOG_ON_BATCH_JOB 0x0004
+#define PR_LOG_ON_SERVICE 0x0010
+
+
+typedef struct _GROUP_MAP {
+ gid_t gid;
+ DOM_SID sid;
+ enum SID_NAME_USE sid_name_use;
+ fstring nt_name;
+ fstring comment;
+ uint32 systemaccount;
+ PRIVILEGE_SET priv_set;
+} GROUP_MAP;
+
+typedef struct _PRIVS {
+ uint32 se_priv;
+ char *priv;
+ char *description;
+} PRIVS;
+
diff --git a/source/include/md5.h b/source/include/md5.h
new file mode 100644
index 00000000000..dc2f2dd207f
--- /dev/null
+++ b/source/include/md5.h
@@ -0,0 +1,25 @@
+#ifndef MD5_H
+#define MD5_H
+#ifndef HEADER_MD5_H
+/* Try to avoid clashes with OpenSSL */
+#define HEADER_MD5_H
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/source/include/messages.h b/source/include/messages.h
new file mode 100644
index 00000000000..dfbc4862117
--- /dev/null
+++ b/source/include/messages.h
@@ -0,0 +1,48 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ messages.c header
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _MESSAGES_H_
+#define _MESSAGES_H_
+
+/* general messages */
+#define MSG_DEBUG 1
+#define MSG_PING 2
+#define MSG_PONG 3
+#define MSG_PROFILE 4
+#define MSG_REQ_DEBUGLEVEL 5
+#define MSG_DEBUGLEVEL 6
+#define MSG_REQ_PROFILELEVEL 7
+#define MSG_PROFILELEVEL 8
+
+/* nmbd messages */
+#define MSG_FORCE_ELECTION 1001
+
+/* rpc messages */
+#define MSG_PRINTER_NOTIFY 2001
+#define MSG_PRINTER_UPDATE 2002
+
+/* smbd messages */
+#define MSG_SMB_CONF_UPDATED 3001
+#define MSG_SMB_FORCE_TDIS 3002
+#define MSG_SMB_SAM_SYNC 3003
+#define MSG_SMB_SAM_REPL 3004
+
+#endif
diff --git a/source/include/msdfs.h b/source/include/msdfs.h
new file mode 100644
index 00000000000..df2ea5a6e4a
--- /dev/null
+++ b/source/include/msdfs.h
@@ -0,0 +1,78 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ MSDfs services for Samba
+ Copyright (C) Shirish Kalele 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _MSDFS_H
+#define _MSDFS_H
+
+#define REFERRAL_TTL 600
+
+/* Flags used in trans2 Get Referral reply */
+#define DFSREF_REFERRAL_SERVER 0x1
+#define DFSREF_STORAGE_SERVER 0x2
+
+/* Referral sizes */
+#define VERSION2_REFERRAL_SIZE 0x16
+#define VERSION3_REFERRAL_SIZE 0x22
+#define REFERRAL_HEADER_SIZE 0x08
+
+/* Maximum number of referrals for each Dfs volume */
+#define MAX_REFERRAL_COUNT 256
+
+struct referral
+{
+ pstring alternate_path; /* contains the path referred */
+ uint32 proximity;
+ uint32 ttl; /* how long should client cache referral */
+};
+
+struct junction_map
+{
+ pstring service_name;
+ pstring volume_name;
+ int referral_count;
+ struct referral* referral_list;
+};
+
+struct dfs_path
+{
+ pstring hostname;
+ pstring servicename;
+ pstring volumename;
+ pstring restofthepath;
+};
+
+#define RESOLVE_DFSPATH(name, conn, inbuf, outbuf) \
+{ if(((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES)) && \
+ dfs_redirect(name,conn)) \
+ return ERROR_NT(NT_STATUS_PATH_NOT_COVERED); }
+
+#define RESOLVE_FINDFIRST_DFSPATH(name, conn, inbuf, outbuf) \
+{ if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) || \
+ get_remote_arch()==RA_WIN95) \
+ if(dfs_findfirst_redirect(directory,conn)) \
+ return ERROR_NT(NT_STATUS_PATH_NOT_COVERED); }
+
+#define init_dfsroot(conn, inbuf, outbuf) \
+{ if(lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) \
+ SSVAL(outbuf, smb_vwv2, SMB_SHARE_IN_DFS | SMB_SUPPORT_SEARCH_BITS); \
+}
+
+#endif /* _MSDFS_H */
diff --git a/source/include/nameserv.h b/source/include/nameserv.h
index 168dd4ba866..ff777fd1ca7 100644
--- a/source/include/nameserv.h
+++ b/source/include/nameserv.h
@@ -1,8 +1,10 @@
+#ifndef _NAMESERV_H_
+#define _NAMESERV_H_
/*
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios header - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,59 +22,396 @@
*/
-#define MAX_DGRAM_SIZE 576
+#define PERMANENT_TTL 0
+
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 1
+
+#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
-#define NMB_PORT 137
-#define DGRAM_PORT 138
-#define SMB_PORT 139
+/*********************************************************
+ Types of reply packet.
+**********************************************************/
+
+enum netbios_reply_type_code { NMB_QUERY, NMB_STATUS, NMB_REG, NMB_REG_REFRESH,
+ NMB_REL, NMB_WAIT_ACK, NMB_MULTIHOMED_REG,
+ WINS_REG, WINS_QUERY };
+
+/* From rfc1002, 4.2.1.2 */
+/* Question types. */
+#define QUESTION_TYPE_NB_QUERY 0x20
+#define QUESTION_TYPE_NB_STATUS 0x21
+
+/* Question class */
+#define QUESTION_CLASS_IN 0x1
+
+/* Opcode definitions */
+#define NMB_NAME_QUERY_OPCODE 0x0
+#define NMB_NAME_REG_OPCODE 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_NAME_RELEASE_OPCODE 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WACK_OPCODE 0x07 /* see rfc1002.txt 4.2.16 */
+/* Ambiguity in rfc1002 about which of these is correct. */
+/* WinNT uses 8 by default but can be made to use 9. */
+#define NMB_NAME_REFRESH_OPCODE_8 0x08 /* see rfc1002.txt 4.2.4 */
+#define NMB_NAME_REFRESH_OPCODE_9 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_NAME_MULTIHOMED_REG_OPCODE 0x0F /* Invented by Microsoft. */
+
+/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
+
+/* Resource record types. rfc1002 4.2.1.3 */
+#define RR_TYPE_A 0x1
+#define RR_TYPE_NS 0x2
+#define RR_TYPE_NULL 0xA
+#define RR_TYPE_NB 0x20
+#define RR_TYPE_NBSTAT 0x21
+
+/* Resource record class. */
+#define RR_CLASS_IN 0x1
+
+/* NetBIOS flags */
+#define NB_GROUP 0x80
+#define NB_PERM 0x02
+#define NB_ACTIVE 0x04
+#define NB_CONFL 0x08
+#define NB_DEREG 0x10
+#define NB_BFLAG 0x00 /* Broadcast node type. */
+#define NB_PFLAG 0x20 /* Point-to-point node type. */
+#define NB_MFLAG 0x40 /* Mixed bcast & p-p node type. */
+#define NB_HFLAG 0x60 /* Microsoft 'hybrid' node type. */
+#define NB_NODETYPEMASK 0x60
+/* Mask applied to outgoing NetBIOS flags. */
+#define NB_FLGMSK 0xE0
+
+/* NetBIOS flag identifier. */
+#define NAME_GROUP(p) ((p)->data.nb_flags & NB_GROUP)
+#define NAME_BFLAG(p) (((p)->data.nb_flags & NB_NODETYPEMASK) == NB_BFLAG)
+#define NAME_PFLAG(p) (((p)->data.nb_flags & NB_NODETYPEMASK) == NB_PFLAG)
+#define NAME_MFLAG(p) (((p)->data.nb_flags & NB_NODETYPEMASK) == NB_MFLAG)
+#define NAME_HFLAG(p) (((p)->data.nb_flags & NB_NODETYPEMASK) == NB_HFLAG)
+
+/* Samba name state for a name in a namelist. */
+#define NAME_IS_ACTIVE(p) ((p)->data.nb_flags & NB_ACTIVE)
+#define NAME_IN_CONFLICT(p) ((p)->data.nb_flags & NB_CONFL)
+#define NAME_IS_DEREGISTERING(p) ((p)->data.nb_flags & NB_DEREG)
+
+/* Error codes for NetBIOS requests. */
+#define FMT_ERR 0x1 /* Packet format error. */
+#define SRV_ERR 0x2 /* Internal server error. */
+#define NAM_ERR 0x3 /* Name does not exist. */
+#define IMP_ERR 0x4 /* Request not implemented. */
+#define RFS_ERR 0x5 /* Request refused. */
+#define ACT_ERR 0x6 /* Active error - name owned by another host. */
+#define CFT_ERR 0x7 /* Name in conflict error. */
+
+#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
+
+/* Workgroup state identifiers. */
+#define AM_POTENTIAL_MASTER_BROWSER(work) ((work)->mst_state == MST_POTENTIAL)
+#define AM_LOCAL_MASTER_BROWSER(work) ((work)->mst_state == MST_BROWSER)
+#define AM_DOMAIN_MASTER_BROWSER(work) ((work)->dom_state == DOMAIN_MST)
+#define AM_DOMAIN_MEMBER(work) ((work)->log_state == LOGON_SRV)
-enum name_source {LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
+/* Microsoft browser NetBIOS name. */
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+
+/* Mail slots. */
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
+#define NT_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NTLOGON"
+#define LANMAN_MAILSLOT "\\MAILSLOT\\LANMAN"
+
+/* Samba definitions for find_name_on_subnet(). */
+#define FIND_ANY_NAME 0
+#define FIND_SELF_NAME 1
+
+/*
+ * The different name types that can be in namelists.
+ *
+ * SELF_NAME should only be on the broadcast and unicast subnets.
+ * LMHOSTS_NAME should only be in the remote_broadcast_subnet.
+ * REGISTER_NAME, DNS_NAME, DNSFAIL_NAME should only be in the wins_server_subnet.
+ * WINS_PROXY_NAME should only be on the broadcast subnets.
+ * PERMANENT_NAME can be on all subnets except remote_broadcast_subnet.
+ *
+ */
+
+enum name_source {LMHOSTS_NAME, REGISTER_NAME, SELF_NAME, DNS_NAME,
+ DNSFAIL_NAME, PERMANENT_NAME, WINS_PROXY_NAME};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
-/* a netbios name structure */
-struct nmb_name {
- char name[17];
- char scope[64];
- int name_type;
+enum master_state
+{
+ MST_NONE,
+ MST_POTENTIAL,
+ MST_BACKUP,
+ MST_MSB,
+ MST_BROWSER,
+ MST_UNBECOMING_MASTER
};
-/* this is the structure used for the local netbios name list */
-struct name_record
+enum domain_state
{
- struct name_record *next;
- struct name_record *prev;
- struct nmb_name name;
- time_t death_time;
- struct in_addr ip;
- BOOL unique;
- enum name_source source;
+ DOMAIN_NONE,
+ DOMAIN_WAIT,
+ DOMAIN_MST
};
-/* this is used by the list of domains */
-struct domain_record
+enum logon_state
{
- struct domain_record *next;
- struct domain_record *prev;
- fstring name;
- time_t lastannounce_time;
- int announce_interval;
- struct in_addr bcast_ip;
+ LOGON_NONE,
+ LOGON_WAIT,
+ LOGON_SRV
};
-/* this is used to hold the list of servers in my domain */
+struct subnet_record;
+
+struct nmb_data
+{
+ uint16 nb_flags; /* Netbios flags. */
+ int num_ips; /* Number of ip entries. */
+ struct in_addr *ip; /* The ip list for this name. */
+
+ enum name_source source; /* Where the name came from. */
+
+ time_t death_time; /* The time the record must be removed (do not remove if 0). */
+ time_t refresh_time; /* The time the record should be refreshed. */
+};
+
+/* This structure represents an entry in a local netbios name list. */
+struct name_record
+ {
+ ubi_trNode node[1];
+ struct subnet_record *subnet;
+ struct nmb_name name; /* The netbios name. */
+ struct nmb_data data; /* The netbios data. */
+ };
+
+/* Browser cache for synchronising browse lists. */
+struct browse_cache_record
+ {
+ ubi_dlNode node[1];
+ pstring lmb_name;
+ pstring work_group;
+ struct in_addr ip;
+ time_t sync_time;
+ time_t death_time; /* The time the record must be removed. */
+ };
+
+/* This is used to hold the list of servers in my domain, and is
+ contained within lists of domains. */
+
struct server_record
{
struct server_record *next;
struct server_record *prev;
- fstring name;
- fstring comment;
- uint32 servertype;
+
+ struct subnet_record *subnet;
+
+ struct server_info_struct serv;
+ time_t death_time;
+};
+
+/* A workgroup structure. It contains a list of servers. */
+struct work_record
+{
+ struct work_record *next;
+ struct work_record *prev;
+
+ struct subnet_record *subnet;
+
+ struct server_record *serverlist;
+
+ /* Stage of development from non-local-master up to local-master browser. */
+ enum master_state mst_state;
+
+ /* Stage of development from non-domain-master to domain-master browser. */
+ enum domain_state dom_state;
+
+ /* Stage of development from non-logon-server to logon server. */
+ enum logon_state log_state;
+
+ /* Work group info. */
+ fstring work_group;
+ int token; /* Used when communicating with backup browsers. */
+ fstring local_master_browser_name; /* Current local master browser. */
+
+ /* Announce info. */
+ time_t lastannounce_time;
+ int announce_interval;
+ BOOL needannounce;
+
+ /* Timeout time for this workgroup. 0 means permanent. */
time_t death_time;
+
+ /* Election info */
+ BOOL RunningElection;
+ BOOL needelection;
+ int ElectionCount;
+ uint32 ElectionCriterion;
+
+ /* Domain master browser info. Used for efficient syncs. */
+ struct nmb_name dmb_name;
+ struct in_addr dmb_addr;
+};
+
+/* typedefs needed to define copy & free functions for userdata. */
+struct userdata_struct;
+
+typedef struct userdata_struct * (*userdata_copy_fn)(struct userdata_struct *);
+typedef void (*userdata_free_fn)(struct userdata_struct *);
+
+/* Structure to define any userdata passed around. */
+
+struct userdata_struct {
+ userdata_copy_fn copy_fn;
+ userdata_free_fn free_fn;
+ unsigned int userdata_len;
+ char data[16]; /* 16 is to ensure alignment/padding on all systems */
};
-/* a resource record */
+struct response_record;
+struct packet_struct;
+struct res_rec;
+
+/* typedef to define the function called when this response packet comes in. */
+typedef void (*response_function)(struct subnet_record *, struct response_record *,
+ struct packet_struct *);
+
+/* typedef to define the function called when this response record times out. */
+typedef void (*timeout_response_function)(struct subnet_record *,
+ struct response_record *);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is successful. */
+typedef void (*success_function)(struct subnet_record *, struct userdata_struct *, ...);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is unsuccessful. */
+typedef void (*fail_function)(struct subnet_record *, struct response_record *, ...);
+
+/* List of typedefs for success and fail functions of the different query
+ types. Used to catch any compile time prototype errors. */
+
+typedef void (*register_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16,
+ int,
+ struct in_addr);
+typedef void (*register_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*release_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr);
+typedef void (*release_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*refresh_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16,
+ int,
+ struct in_addr);
+typedef void (*refresh_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*query_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr,
+ struct res_rec *answers);
+
+typedef void (*query_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *,
+ int);
+
+typedef void (*node_status_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct res_rec *,
+ struct in_addr);
+typedef void (*node_status_fail_function)( struct subnet_record *,
+ struct response_record *);
+
+/* Initiated name queries are recorded in this list to track any responses. */
+
+struct response_record
+{
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16 response_id;
+
+ /* Callbacks for packets received or not. */
+ response_function resp_fn;
+ timeout_response_function timeout_fn;
+
+ /* Callbacks for the request succeeding or not. */
+ success_function success_fn;
+ fail_function fail_fn;
+
+ struct packet_struct *packet;
+
+ struct userdata_struct *userdata;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+
+ /* Recursion protection. */
+ BOOL in_expiration_processing;
+};
+
+/* A subnet structure. It contains a list of workgroups and netbios names. */
+
+/*
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. These do NOT interact with other subnet records'
+ netbios names.
+*/
+
+enum subnet_type {
+ NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
+ UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
+ REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
+ WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
+};
+
+struct subnet_record
+{
+ struct subnet_record *next;
+ struct subnet_record *prev;
+
+ char *subnet_name; /* For Debug identification. */
+ enum subnet_type type; /* To catagorize the subnet. */
+
+ struct work_record *workgrouplist; /* List of workgroups. */
+ ubi_trRoot namelist[1]; /* List of netbios names. */
+ struct response_record *responselist; /* List of responses expected. */
+
+ BOOL namelist_changed;
+ BOOL work_changed;
+
+ struct in_addr bcast_ip;
+ struct in_addr mask_ip;
+ struct in_addr myip;
+ int nmb_sock; /* socket to listen for unicast 137. */
+ int dgram_sock; /* socket to listen for unicast 138. */
+};
+
+/* A resource record. */
struct res_rec {
struct nmb_name rr_name;
int rr_type;
@@ -82,7 +421,7 @@ struct res_rec {
char rdata[MAX_DGRAM_SIZE];
};
-/* define a nmb packet. */
+/* An nmb packet. */
struct nmb_packet
{
struct {
@@ -114,8 +453,18 @@ struct nmb_packet
struct res_rec *additional;
};
+/* msg_type field options - from rfc1002. */
+
+#define DGRAM_UNIQUE 0x10
+#define DGRAM_GROUP 0x11
+#define DGRAM_BROADCAST 0x12
+#define DGRAM_ERROR 0x13
+#define DGRAM_QUERY_REQUEST 0x14
+#define DGRAM_POSITIVE_QUERY_RESPONSE 0x15
+#define DGRAM_NEGATIVE_QUERT_RESPONSE 0x16
+
+/* A datagram - this normally contains SMB data in the data[] array. */
-/* a datagram - this normally contains SMB data in the data[] array */
struct dgram_packet {
struct {
int msg_type;
@@ -136,12 +485,14 @@ struct dgram_packet {
char data[MAX_DGRAM_SIZE];
};
-/* define a structure used to queue packets. this will be a linked
- list of nmb packets */
+/* Define a structure used to queue packets. This will be a linked
+ list of nmb packets. */
+
struct packet_struct
{
struct packet_struct *next;
struct packet_struct *prev;
+ BOOL locked;
struct in_addr ip;
int port;
int fd;
@@ -153,32 +504,70 @@ struct packet_struct
} packet;
};
+/* NETLOGON opcodes */
-/* this defines a list of network interfaces */
-struct net_interface {
- struct net_interface *next;
- struct in_addr ip;
- struct in_addr bcast;
- struct in_addr netmask;
-};
+#define QUERYFORPDC 7 /* Query for PDC. */
+#define SAM_UAS_CHANGE 10 /* Announce change to UAS or SAM. */
+#define QUERYFORPDC_R 12 /* Response to Query for PDC. */
+#define SAMLOGON 18
+#define SAMLOGON_R 19
+#define SAMLOGON_UNK_R 21
+
+/* Ids for netbios packet types. */
+
+#define ANN_HostAnnouncement 1
+#define ANN_AnnouncementRequest 2
+#define ANN_Election 8
+#define ANN_GetBackupListReq 9
+#define ANN_GetBackupListResp 10
+#define ANN_BecomeBackup 11
+#define ANN_DomainAnnouncement 12
+#define ANN_MasterAnnouncement 13
+#define ANN_ResetBrowserState 14
+#define ANN_LocalMasterAnnouncement 15
+
+
+/* Broadcast packet announcement intervals, in minutes. */
+
+/* Attempt to add domain logon and domain master names. */
+#define CHECK_TIME_ADD_DOM_NAMES 5
+
+/* Search for master browsers of workgroups samba knows about,
+ except default. */
+#define CHECK_TIME_MST_BROWSE 5
+
+/* Request backup browser announcements from other servers. */
+#define CHECK_TIME_ANNOUNCE_BACKUP 15
+
+/* Request host announcements from other servers: min and max of interval. */
+#define CHECK_TIME_MIN_HOST_ANNCE 3
+#define CHECK_TIME_MAX_HOST_ANNCE 12
+
+/* Announce as master to WINS server and any Primary Domain Controllers. */
+#define CHECK_TIME_MST_ANNOUNCE 15
+
+/* Time between syncs from domain master browser to local master browsers. */
+#define CHECK_TIME_DMB_TO_LMB_SYNC 15
+
+/* Do all remote announcements this often. */
+#define REMOTE_ANNOUNCE_INTERVAL 180
+
+/* what is the maximum period between name refreshes. Note that this only
+ affects non-permanent self names (in seconds) */
+#define MAX_REFRESH_TIME (60*20)
+
+/* Macro's to enumerate subnets either with or without
+ the UNICAST subnet. */
+
+extern struct subnet_record *subnetlist;
+extern struct subnet_record *unicast_subnet;
+extern struct subnet_record *wins_server_subnet;
+extern struct subnet_record *remote_broadcast_subnet;
+#define FIRST_SUBNET subnetlist
+#define NEXT_SUBNET_EXCLUDING_UNICAST(x) ((x)->next)
+#define NEXT_SUBNET_INCLUDING_UNICAST(x) (get_next_subnet_maybe_unicast((x)))
-/* prototypes */
-void free_nmb_packet(struct nmb_packet *nmb);
-void free_packet(struct packet_struct *packet);
-struct packet_struct *read_packet(int fd,enum packet_type packet_type);
-BOOL send_packet(struct packet_struct *p);
-struct packet_struct *receive_packet(int fd,enum packet_type type,int timeout);
-void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)());
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)());
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip);
-char *namestr(struct nmb_name *n);
+/* To be removed. */
+enum state_type { TEST };
+#endif /* _NAMESERV_H_ */
diff --git a/source/include/nt_printing.h b/source/include/nt_printing.h
new file mode 100644
index 00000000000..61abc1a31bc
--- /dev/null
+++ b/source/include/nt_printing.h
@@ -0,0 +1,335 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Jean Francois Micouleau 1998-2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef NT_PRINTING_H_
+#define NT_PRINTING_H_
+
+#define ORIENTATION 0x00000001L
+#define PAPERSIZE 0x00000002L
+#define PAPERLENGTH 0x00000004L
+#define PAPERWIDTH 0x00000008L
+#define SCALE 0x00000010L
+#define COPIES 0x00000100L
+#define DEFAULTSOURCE 0x00000200L
+#define PRINTQUALITY 0x00000400L
+#define COLOR 0x00000800L
+#define DUPLEX 0x00001000L
+#define YRESOLUTION 0x00002000L
+#define TTOPTION 0x00004000L
+#define COLLATE 0x00008000L
+#define FORMNAME 0x00010000L
+#define LOGPIXELS 0x00020000L
+#define BITSPERPEL 0x00040000L
+#define PELSWIDTH 0x00080000L
+#define PELSHEIGHT 0x00100000L
+#define DISPLAYFLAGS 0x00200000L
+#define DISPLAYFREQUENCY 0x00400000L
+#define PANNINGWIDTH 0x00800000L
+#define PANNINGHEIGHT 0x01000000L
+
+#define ORIENT_PORTRAIT 1
+#define ORIENT_LANDSCAPE 2
+
+#define PAPER_FIRST PAPER_LETTER
+#define PAPER_LETTER 1 /* Letter 8 1/2 x 11 in */
+#define PAPER_LETTERSMALL 2 /* Letter Small 8 1/2 x 11 in */
+#define PAPER_TABLOID 3 /* Tabloid 11 x 17 in */
+#define PAPER_LEDGER 4 /* Ledger 17 x 11 in */
+#define PAPER_LEGAL 5 /* Legal 8 1/2 x 14 in */
+#define PAPER_STATEMENT 6 /* Statement 5 1/2 x 8 1/2 in */
+#define PAPER_EXECUTIVE 7 /* Executive 7 1/4 x 10 1/2 in */
+#define PAPER_A3 8 /* A3 297 x 420 mm */
+#define PAPER_A4 9 /* A4 210 x 297 mm */
+#define PAPER_A4SMALL 10 /* A4 Small 210 x 297 mm */
+#define PAPER_A5 11 /* A5 148 x 210 mm */
+#define PAPER_B4 12 /* B4 (JIS) 250 x 354 */
+#define PAPER_B5 13 /* B5 (JIS) 182 x 257 mm */
+#define PAPER_FOLIO 14 /* Folio 8 1/2 x 13 in */
+#define PAPER_QUARTO 15 /* Quarto 215 x 275 mm */
+#define PAPER_10X14 16 /* 10x14 in */
+#define PAPER_11X17 17 /* 11x17 in */
+#define PAPER_NOTE 18 /* Note 8 1/2 x 11 in */
+#define PAPER_ENV_9 19 /* Envelope #9 3 7/8 x 8 7/8 */
+#define PAPER_ENV_10 20 /* Envelope #10 4 1/8 x 9 1/2 */
+#define PAPER_ENV_11 21 /* Envelope #11 4 1/2 x 10 3/8 */
+#define PAPER_ENV_12 22 /* Envelope #12 4 \276 x 11 */
+#define PAPER_ENV_14 23 /* Envelope #14 5 x 11 1/2 */
+#define PAPER_CSHEET 24 /* C size sheet */
+#define PAPER_DSHEET 25 /* D size sheet */
+#define PAPER_ESHEET 26 /* E size sheet */
+#define PAPER_ENV_DL 27 /* Envelope DL 110 x 220mm */
+#define PAPER_ENV_C5 28 /* Envelope C5 162 x 229 mm */
+#define PAPER_ENV_C3 29 /* Envelope C3 324 x 458 mm */
+#define PAPER_ENV_C4 30 /* Envelope C4 229 x 324 mm */
+#define PAPER_ENV_C6 31 /* Envelope C6 114 x 162 mm */
+#define PAPER_ENV_C65 32 /* Envelope C65 114 x 229 mm */
+#define PAPER_ENV_B4 33 /* Envelope B4 250 x 353 mm */
+#define PAPER_ENV_B5 34 /* Envelope B5 176 x 250 mm */
+#define PAPER_ENV_B6 35 /* Envelope B6 176 x 125 mm */
+#define PAPER_ENV_ITALY 36 /* Envelope 110 x 230 mm */
+#define PAPER_ENV_MONARCH 37 /* Envelope Monarch 3.875 x 7.5 in */
+#define PAPER_ENV_PERSONAL 38 /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */
+#define PAPER_FANFOLD_US 39 /* US Std Fanfold 14 7/8 x 11 in */
+#define PAPER_FANFOLD_STD_GERMAN 40 /* German Std Fanfold 8 1/2 x 12 in */
+#define PAPER_FANFOLD_LGL_GERMAN 41 /* German Legal Fanfold 8 1/2 x 13 in */
+
+#define PAPER_LAST PAPER_FANFOLD_LGL_GERMAN
+#define PAPER_USER 256
+
+#define BIN_FIRST BIN_UPPER
+#define BIN_UPPER 1
+#define BIN_ONLYONE 1
+#define BIN_LOWER 2
+#define BIN_MIDDLE 3
+#define BIN_MANUAL 4
+#define BIN_ENVELOPE 5
+#define BIN_ENVMANUAL 6
+#define BIN_AUTO 7
+#define BIN_TRACTOR 8
+#define BIN_SMALLFMT 9
+#define BIN_LARGEFMT 10
+#define BIN_LARGECAPACITY 11
+#define BIN_CASSETTE 14
+#define BIN_FORMSOURCE 15
+#define BIN_LAST BIN_FORMSOURCE
+
+#define BIN_USER 256 /* device specific bins start here */
+
+#define RES_DRAFT (-1)
+#define RES_LOW (-2)
+#define RES_MEDIUM (-3)
+#define RES_HIGH (-4)
+
+#define COLOR_MONOCHROME 1
+#define COLOR_COLOR 2
+
+#define DUP_SIMPLEX 1
+#define DUP_VERTICAL 2
+#define DUP_HORIZONTAL 3
+
+#define TT_BITMAP 1 /* print TT fonts as graphics */
+#define TT_DOWNLOAD 2 /* download TT fonts as soft fonts */
+#define TT_SUBDEV 3 /* substitute device fonts for TT fonts */
+
+#define COLLATE_FALSE 0
+#define COLLATE_TRUE 1
+
+typedef struct nt_printer_driver_info_level_3
+{
+ uint32 cversion;
+
+ fstring name;
+ fstring environment;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring monitorname;
+ fstring defaultdatatype;
+ fstring *dependentfiles;
+} NT_PRINTER_DRIVER_INFO_LEVEL_3;
+
+/* SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure */
+typedef struct {
+ uint32 version;
+ fstring name;
+ fstring environment;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring monitorname;
+ fstring defaultdatatype;
+ fstring mfgname;
+ fstring oemurl;
+ fstring hardwareid;
+ fstring provider;
+ fstring *dependentfiles;
+ fstring *previousnames;
+} NT_PRINTER_DRIVER_INFO_LEVEL_6;
+
+
+typedef struct nt_printer_driver_info_level
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3;
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *info_6;
+} NT_PRINTER_DRIVER_INFO_LEVEL;
+
+typedef struct nt_printer_param
+{
+ fstring value;
+ uint32 type;
+ uint8 *data;
+ int data_len;
+ struct nt_printer_param *next;
+} NT_PRINTER_PARAM;
+
+typedef struct ntdevicemode
+{
+ fstring devicename;
+ fstring formname;
+
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ uint16 driverextra;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ uint16 logpixels;
+
+ uint32 fields;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ uint8 *private;
+} NT_DEVICEMODE;
+
+typedef struct nt_printer_info_level_2
+{
+ uint32 attributes;
+ uint32 priority;
+ uint32 default_priority;
+ uint32 starttime;
+ uint32 untiltime;
+ WERROR status;
+ uint32 cjobs;
+ uint32 averageppm;
+ fstring servername;
+ fstring printername;
+ fstring sharename;
+ fstring portname;
+ fstring drivername;
+ pstring comment;
+ fstring location;
+ NT_DEVICEMODE *devmode;
+ fstring sepfile;
+ fstring printprocessor;
+ fstring datatype;
+ fstring parameters;
+ NT_PRINTER_PARAM *specific;
+ SEC_DESC_BUF *secdesc_buf;
+ /* not used but ... and how ??? */
+ uint32 changeid;
+ uint32 c_setprinter;
+ uint32 setuptime;
+} NT_PRINTER_INFO_LEVEL_2;
+
+typedef struct nt_printer_info_level
+{
+ NT_PRINTER_INFO_LEVEL_2 *info_2;
+} NT_PRINTER_INFO_LEVEL;
+
+typedef struct
+{
+ fstring name;
+ uint32 flag;
+ uint32 width;
+ uint32 length;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+} nt_forms_struct;
+
+/*
+typedef struct _form
+{
+ uint32 flags;
+ uint32 name_ptr;
+ uint32 size_x;
+ uint32 size_y;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ UNISTR2 name;
+} FORM;
+*/
+
+#ifndef SAMBA_PRINTER_PORT_NAME
+#define SAMBA_PRINTER_PORT_NAME "Samba Printer Port"
+#endif
+
+/* DOS header format */
+#define DOS_HEADER_SIZE 64
+#define DOS_HEADER_MAGIC_OFFSET 0
+#define DOS_HEADER_MAGIC 0x5A4D
+#define DOS_HEADER_LFANEW_OFFSET 60
+
+/* New Executable format (Win or OS/2 1.x segmented) */
+#define NE_HEADER_SIZE 64
+#define NE_HEADER_SIGNATURE_OFFSET 0
+#define NE_HEADER_SIGNATURE 0x454E
+#define NE_HEADER_TARGET_OS_OFFSET 54
+#define NE_HEADER_TARGOS_WIN 0x02
+#define NE_HEADER_MINOR_VER_OFFSET 62
+#define NE_HEADER_MAJOR_VER_OFFSET 63
+
+/* Portable Executable format */
+#define PE_HEADER_SIZE 248
+#define PE_HEADER_SIGNATURE_OFFSET 0
+#define PE_HEADER_SIGNATURE 0x00004550
+#define PE_HEADER_MACHINE_OFFSET 4
+#define PE_HEADER_MACHINE_I386 0x14c
+#define PE_HEADER_NUMBER_OF_SECTIONS 6
+#define PE_HEADER_MAJOR_OS_VER_OFFSET 64
+#define PE_HEADER_MINOR_OS_VER_OFFSET 66
+#define PE_HEADER_MAJOR_IMG_VER_OFFSET 68
+#define PE_HEADER_MINOR_IMG_VER_OFFSET 70
+#define PE_HEADER_MAJOR_SS_VER_OFFSET 72
+#define PE_HEADER_MINOR_SS_VER_OFFSET 74
+#define PE_HEADER_SECT_HEADER_SIZE 40
+#define PE_HEADER_SECT_NAME_OFFSET 0
+#define PE_HEADER_SECT_SIZE_DATA_OFFSET 16
+#define PE_HEADER_SECT_PTR_DATA_OFFSET 20
+
+/* Microsoft file version format */
+#define VS_SIGNATURE "VS_VERSION_INFO"
+#define VS_MAGIC_VALUE 0xfeef04bd
+#define VS_MAJOR_OFFSET 8
+#define VS_MINOR_OFFSET 12
+#define VS_VERSION_INFO_UNICODE_SIZE (sizeof(VS_SIGNATURE)*2+4+VS_MINOR_OFFSET+4) /* not true size! */
+#define VS_VERSION_INFO_SIZE (sizeof(VS_SIGNATURE)+4+VS_MINOR_OFFSET+4) /* not true size! */
+#define VS_NE_BUF_SIZE 4096 /* Must be > 2*VS_VERSION_INFO_SIZE */
+
+#endif /* NT_PRINTING_H_ */
diff --git a/source/include/ntdomain.h b/source/include/ntdomain.h
new file mode 100644
index 00000000000..8718b9dc5fb
--- /dev/null
+++ b/source/include/ntdomain.h
@@ -0,0 +1,288 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _NT_DOMAIN_H /* _NT_DOMAIN_H */
+#define _NT_DOMAIN_H
+
+/* dce/rpc support */
+#include "rpc_dce.h"
+
+/* miscellaneous structures / defines */
+#include "rpc_misc.h"
+
+#include "rpc_creds.h"
+
+#include "talloc.h"
+
+/*
+ * A bunch of stuff that was put into smb.h
+ * in the NTDOM branch - it didn't belong there.
+ */
+
+typedef struct _prs_struct
+{
+ BOOL io; /* parsing in or out of data stream */
+ /*
+ * If the (incoming) data is big-endian. On output we are
+ * always little-endian.
+ */
+ BOOL bigendian_data;
+ uint8 align; /* data alignment */
+ BOOL is_dynamic; /* Do we own this memory or not ? */
+ uint32 data_offset; /* Current working offset into data. */
+ uint32 buffer_size; /* Current allocated size of the buffer. */
+ uint32 grow_size; /* size requested via prs_grow() calls */
+ char *data_p; /* The buffer itself. */
+ TALLOC_CTX *mem_ctx; /* When unmarshalling, use this.... */
+} prs_struct;
+
+/*
+ * Defines for io member of prs_struct.
+ */
+
+#define MARSHALL 0
+#define UNMARSHALL 1
+
+#define MARSHALLING(ps) (!(ps)->io)
+#define UNMARSHALLING(ps) ((ps)->io)
+
+#define RPC_BIG_ENDIAN 1
+#define RPC_LITTLE_ENDIAN 0
+
+#define RPC_PARSE_ALIGN 4
+
+typedef struct _output_data {
+ /*
+ * Raw RPC output data. This does not include RPC headers or footers.
+ */
+ prs_struct rdata;
+
+ /* The amount of data sent from the current rdata struct. */
+ uint32 data_sent_length;
+
+ /*
+ * The current PDU being returned. This inclues
+ * headers, data and authentication footer.
+ */
+ unsigned char current_pdu[MAX_PDU_FRAG_LEN];
+
+ /* The amount of data in the current_pdu buffer. */
+ uint32 current_pdu_len;
+
+ /* The amount of data sent from the current PDU. */
+ uint32 current_pdu_sent;
+} output_data;
+
+typedef struct _input_data {
+ /*
+ * This is the current incoming pdu. The data here
+ * is collected via multiple writes until a complete
+ * pdu is seen, then the data is copied into the in_data
+ * structure. The maximum size of this is 0x1630 (MAX_PDU_FRAG_LEN).
+ */
+ unsigned char current_in_pdu[MAX_PDU_FRAG_LEN];
+
+ /*
+ * The amount of data needed to complete the in_pdu.
+ * If this is zero, then we are at the start of a new
+ * pdu.
+ */
+ uint32 pdu_needed_len;
+
+ /*
+ * The amount of data received so far in the in_pdu.
+ * If this is zero, then we are at the start of a new
+ * pdu.
+ */
+ uint32 pdu_received_len;
+
+ /*
+ * This is the collection of input data with all
+ * the rpc headers and auth footers removed.
+ * The maximum length of this (1Mb) is strictly enforced.
+ */
+ prs_struct data;
+} input_data;
+
+/*
+ * Handle database - stored per pipe.
+ */
+
+struct policy
+{
+ struct policy *next, *prev;
+
+ POLICY_HND pol_hnd;
+
+ void *data_ptr;
+ void (*free_fn)(void *);
+
+};
+
+struct handle_list {
+ struct policy *Policy; /* List of policies. */
+ size_t count; /* Current number of handles. */
+ size_t pipe_ref_count; /* Number of pipe handles referring to this list. */
+};
+
+/* Domain controller authentication protocol info */
+struct dcinfo
+{
+ DOM_CHAL clnt_chal; /* Initial challenge received from client */
+ DOM_CHAL srv_chal; /* Initial server challenge */
+ DOM_CRED clnt_cred; /* Last client credential */
+ DOM_CRED srv_cred; /* Last server credential */
+
+ uchar sess_key[8]; /* Session key */
+ uchar md4pw[16]; /* md4(machine password) */
+
+ fstring mach_acct; /* Machine name we've authenticated. */
+};
+
+typedef struct pipes_struct
+{
+ struct pipes_struct *next, *prev;
+ int pnum;
+ connection_struct *conn;
+ uint16 vuid; /* points to the unauthenticated user that opened this pipe. */
+ BOOL open; /* open connection */
+ uint16 device_state;
+ uint16 priority;
+ fstring name;
+ fstring pipe_srv_name;
+
+ RPC_HDR hdr; /* Incoming RPC header. */
+ RPC_HDR_REQ hdr_req; /* Incoming request header. */
+
+ uint32 ntlmssp_chal_flags; /* Client challenge flags. */
+ BOOL ntlmssp_auth_requested; /* If the client wanted authenticated rpc. */
+ BOOL ntlmssp_auth_validated; /* If the client *got* authenticated rpc. */
+ unsigned char challenge[8];
+ unsigned char ntlmssp_hash[258];
+ uint32 ntlmssp_seq_num;
+ struct dcinfo dc; /* Keeps the creds data. */
+
+ /*
+ * Windows user info.
+ */
+ fstring user_name;
+ fstring domain;
+ fstring wks;
+
+ /*
+ * Unix user name and credentials.
+ */
+
+ fstring pipe_user_name;
+ struct current_user pipe_user;
+
+ /*
+ * Set to true when an RPC bind has been done on this pipe.
+ */
+
+ BOOL pipe_bound;
+
+ /*
+ * Set to true when we should return fault PDU's for everything.
+ */
+
+ BOOL fault_state;
+
+ /*
+ * Set to RPC_BIG_ENDIAN when dealing with big-endian PDU's
+ */
+
+ BOOL endian;
+
+ /*
+ * Struct to deal with multiple pdu inputs.
+ */
+
+ input_data in_data;
+
+ /*
+ * Struct to deal with multiple pdu outputs.
+ */
+
+ output_data out_data;
+
+ /* When replying to an SMBtrans, this is the maximum amount of
+ data that can be sent in the initial reply. */
+ int max_trans_reply;
+
+ /* talloc context to use when allocating memory on this pipe. */
+ TALLOC_CTX *mem_ctx;
+
+ /* handle database to use on this pipe. */
+ struct handle_list *pipe_handles;
+
+} pipes_struct;
+
+struct api_struct
+{
+ char *name;
+ uint8 opnum;
+ BOOL (*fn) (pipes_struct *);
+};
+
+typedef struct
+{
+ uint32 rid;
+ char *name;
+
+} rid_name;
+
+struct acct_info
+{
+ fstring acct_name; /* account name */
+ fstring acct_desc; /* account name */
+ uint32 rid; /* domain-relative RID */
+};
+
+/*
+ * higher order functions for use with msrpc client code
+ */
+
+#define PRINT_INFO_FN(fn)\
+ void (*fn)(const char*, uint32, uint32, void *const *const)
+#define JOB_INFO_FN(fn)\
+ void (*fn)(const char*, const char*, uint32, uint32, void *const *const)
+
+/* end higher order functions */
+
+
+/* security descriptor structures */
+#include "rpc_secdes.h"
+
+/* different dce/rpc pipes */
+#include "rpc_lsa.h"
+#include "rpc_netlogon.h"
+#include "rpc_reg.h"
+#include "rpc_samr.h"
+#include "rpc_srvsvc.h"
+#include "rpc_wkssvc.h"
+#include "rpc_spoolss.h"
+#include "rpc_dfs.h"
+#include "sids.h"
+
+#endif /* _NT_DOMAIN_H */
diff --git a/source/include/nterr.h b/source/include/nterr.h
new file mode 100644
index 00000000000..69b5d7981de
--- /dev/null
+++ b/source/include/nterr.h
@@ -0,0 +1,563 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _NTERR_H
+#define _NTERR_H
+
+/* Win32 Status codes. */
+
+#define STATUS_BUFFER_OVERFLOW NT_STATUS(0x80000005)
+#define NT_STATUS_NO_MORE_ENTRIES NT_STATUS(0x8000001a)
+
+#define STATUS_MORE_ENTRIES NT_STATUS(0x0105)
+#define ERROR_INVALID_PARAMETER NT_STATUS(0x0057)
+#define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a)
+#define STATUS_1804 NT_STATUS(0x070c)
+#define STATUS_NOTIFY_ENUM_DIR NT_STATUS(0x010c)
+
+/* Win32 Error codes extracted using a loop in smbclient then printing a
+ netmon sniff to a file. */
+
+/*
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | NT_STATUS_NOPROBLEMO |
+ | |
+ | |
+ | 4 September |
+ | |
+ | 2001 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+*/
+
+#define NT_STATUS_OK NT_STATUS(0x0000)
+#define NT_STATUS_UNSUCCESSFUL NT_STATUS(0xC0000000 | 0x0001)
+#define NT_STATUS_NOT_IMPLEMENTED NT_STATUS(0xC0000000 | 0x0002)
+#define NT_STATUS_INVALID_INFO_CLASS NT_STATUS(0xC0000000 | 0x0003)
+#define NT_STATUS_INFO_LENGTH_MISMATCH NT_STATUS(0xC0000000 | 0x0004)
+#define NT_STATUS_ACCESS_VIOLATION NT_STATUS(0xC0000000 | 0x0005)
+#define NT_STATUS_IN_PAGE_ERROR NT_STATUS(0xC0000000 | 0x0006)
+#define NT_STATUS_PAGEFILE_QUOTA NT_STATUS(0xC0000000 | 0x0007)
+#define NT_STATUS_INVALID_HANDLE NT_STATUS(0xC0000000 | 0x0008)
+#define NT_STATUS_BAD_INITIAL_STACK NT_STATUS(0xC0000000 | 0x0009)
+#define NT_STATUS_BAD_INITIAL_PC NT_STATUS(0xC0000000 | 0x000a)
+#define NT_STATUS_INVALID_CID NT_STATUS(0xC0000000 | 0x000b)
+#define NT_STATUS_TIMER_NOT_CANCELED NT_STATUS(0xC0000000 | 0x000c)
+#define NT_STATUS_INVALID_PARAMETER NT_STATUS(0xC0000000 | 0x000d)
+#define NT_STATUS_NO_SUCH_DEVICE NT_STATUS(0xC0000000 | 0x000e)
+#define NT_STATUS_NO_SUCH_FILE NT_STATUS(0xC0000000 | 0x000f)
+#define NT_STATUS_INVALID_DEVICE_REQUEST NT_STATUS(0xC0000000 | 0x0010)
+#define NT_STATUS_END_OF_FILE NT_STATUS(0xC0000000 | 0x0011)
+#define NT_STATUS_WRONG_VOLUME NT_STATUS(0xC0000000 | 0x0012)
+#define NT_STATUS_NO_MEDIA_IN_DEVICE NT_STATUS(0xC0000000 | 0x0013)
+#define NT_STATUS_UNRECOGNIZED_MEDIA NT_STATUS(0xC0000000 | 0x0014)
+#define NT_STATUS_NONEXISTENT_SECTOR NT_STATUS(0xC0000000 | 0x0015)
+#define NT_STATUS_MORE_PROCESSING_REQUIRED NT_STATUS(0xC0000000 | 0x0016)
+#define NT_STATUS_NO_MEMORY NT_STATUS(0xC0000000 | 0x0017)
+#define NT_STATUS_CONFLICTING_ADDRESSES NT_STATUS(0xC0000000 | 0x0018)
+#define NT_STATUS_NOT_MAPPED_VIEW NT_STATUS(0xC0000000 | 0x0019)
+#define NT_STATUS_UNABLE_TO_FREE_VM NT_STATUS(0xC0000000 | 0x001a)
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION NT_STATUS(0xC0000000 | 0x001b)
+#define NT_STATUS_INVALID_SYSTEM_SERVICE NT_STATUS(0xC0000000 | 0x001c)
+#define NT_STATUS_ILLEGAL_INSTRUCTION NT_STATUS(0xC0000000 | 0x001d)
+#define NT_STATUS_INVALID_LOCK_SEQUENCE NT_STATUS(0xC0000000 | 0x001e)
+#define NT_STATUS_INVALID_VIEW_SIZE NT_STATUS(0xC0000000 | 0x001f)
+#define NT_STATUS_INVALID_FILE_FOR_SECTION NT_STATUS(0xC0000000 | 0x0020)
+#define NT_STATUS_ALREADY_COMMITTED NT_STATUS(0xC0000000 | 0x0021)
+#define NT_STATUS_ACCESS_DENIED NT_STATUS(0xC0000000 | 0x0022)
+#define NT_STATUS_BUFFER_TOO_SMALL NT_STATUS(0xC0000000 | 0x0023)
+#define NT_STATUS_OBJECT_TYPE_MISMATCH NT_STATUS(0xC0000000 | 0x0024)
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION NT_STATUS(0xC0000000 | 0x0025)
+#define NT_STATUS_INVALID_DISPOSITION NT_STATUS(0xC0000000 | 0x0026)
+#define NT_STATUS_UNWIND NT_STATUS(0xC0000000 | 0x0027)
+#define NT_STATUS_BAD_STACK NT_STATUS(0xC0000000 | 0x0028)
+#define NT_STATUS_INVALID_UNWIND_TARGET NT_STATUS(0xC0000000 | 0x0029)
+#define NT_STATUS_NOT_LOCKED NT_STATUS(0xC0000000 | 0x002a)
+#define NT_STATUS_PARITY_ERROR NT_STATUS(0xC0000000 | 0x002b)
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM NT_STATUS(0xC0000000 | 0x002c)
+#define NT_STATUS_NOT_COMMITTED NT_STATUS(0xC0000000 | 0x002d)
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES NT_STATUS(0xC0000000 | 0x002e)
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG NT_STATUS(0xC0000000 | 0x002f)
+#define NT_STATUS_INVALID_PARAMETER_MIX NT_STATUS(0xC0000000 | 0x0030)
+#define NT_STATUS_INVALID_QUOTA_LOWER NT_STATUS(0xC0000000 | 0x0031)
+#define NT_STATUS_DISK_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0032)
+#define NT_STATUS_OBJECT_NAME_INVALID NT_STATUS(0xC0000000 | 0x0033)
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND NT_STATUS(0xC0000000 | 0x0034)
+#define NT_STATUS_OBJECT_NAME_COLLISION NT_STATUS(0xC0000000 | 0x0035)
+#define NT_STATUS_HANDLE_NOT_WAITABLE NT_STATUS(0xC0000000 | 0x0036)
+#define NT_STATUS_PORT_DISCONNECTED NT_STATUS(0xC0000000 | 0x0037)
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED NT_STATUS(0xC0000000 | 0x0038)
+#define NT_STATUS_OBJECT_PATH_INVALID NT_STATUS(0xC0000000 | 0x0039)
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND NT_STATUS(0xC0000000 | 0x003a)
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD NT_STATUS(0xC0000000 | 0x003b)
+#define NT_STATUS_DATA_OVERRUN NT_STATUS(0xC0000000 | 0x003c)
+#define NT_STATUS_DATA_LATE_ERROR NT_STATUS(0xC0000000 | 0x003d)
+#define NT_STATUS_DATA_ERROR NT_STATUS(0xC0000000 | 0x003e)
+#define NT_STATUS_CRC_ERROR NT_STATUS(0xC0000000 | 0x003f)
+#define NT_STATUS_SECTION_TOO_BIG NT_STATUS(0xC0000000 | 0x0040)
+#define NT_STATUS_PORT_CONNECTION_REFUSED NT_STATUS(0xC0000000 | 0x0041)
+#define NT_STATUS_INVALID_PORT_HANDLE NT_STATUS(0xC0000000 | 0x0042)
+#define NT_STATUS_SHARING_VIOLATION NT_STATUS(0xC0000000 | 0x0043)
+#define NT_STATUS_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x0044)
+#define NT_STATUS_INVALID_PAGE_PROTECTION NT_STATUS(0xC0000000 | 0x0045)
+#define NT_STATUS_MUTANT_NOT_OWNED NT_STATUS(0xC0000000 | 0x0046)
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x0047)
+#define NT_STATUS_PORT_ALREADY_SET NT_STATUS(0xC0000000 | 0x0048)
+#define NT_STATUS_SECTION_NOT_IMAGE NT_STATUS(0xC0000000 | 0x0049)
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED NT_STATUS(0xC0000000 | 0x004a)
+#define NT_STATUS_THREAD_IS_TERMINATING NT_STATUS(0xC0000000 | 0x004b)
+#define NT_STATUS_BAD_WORKING_SET_LIMIT NT_STATUS(0xC0000000 | 0x004c)
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP NT_STATUS(0xC0000000 | 0x004d)
+#define NT_STATUS_SECTION_PROTECTION NT_STATUS(0xC0000000 | 0x004e)
+#define NT_STATUS_EAS_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x004f)
+#define NT_STATUS_EA_TOO_LARGE NT_STATUS(0xC0000000 | 0x0050)
+#define NT_STATUS_NONEXISTENT_EA_ENTRY NT_STATUS(0xC0000000 | 0x0051)
+#define NT_STATUS_NO_EAS_ON_FILE NT_STATUS(0xC0000000 | 0x0052)
+#define NT_STATUS_EA_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0053)
+#define NT_STATUS_FILE_LOCK_CONFLICT NT_STATUS(0xC0000000 | 0x0054)
+#define NT_STATUS_LOCK_NOT_GRANTED NT_STATUS(0xC0000000 | 0x0055)
+#define NT_STATUS_DELETE_PENDING NT_STATUS(0xC0000000 | 0x0056)
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x0057)
+#define NT_STATUS_UNKNOWN_REVISION NT_STATUS(0xC0000000 | 0x0058)
+#define NT_STATUS_REVISION_MISMATCH NT_STATUS(0xC0000000 | 0x0059)
+#define NT_STATUS_INVALID_OWNER NT_STATUS(0xC0000000 | 0x005a)
+#define NT_STATUS_INVALID_PRIMARY_GROUP NT_STATUS(0xC0000000 | 0x005b)
+#define NT_STATUS_NO_IMPERSONATION_TOKEN NT_STATUS(0xC0000000 | 0x005c)
+#define NT_STATUS_CANT_DISABLE_MANDATORY NT_STATUS(0xC0000000 | 0x005d)
+#define NT_STATUS_NO_LOGON_SERVERS NT_STATUS(0xC0000000 | 0x005e)
+#define NT_STATUS_NO_SUCH_LOGON_SESSION NT_STATUS(0xC0000000 | 0x005f)
+#define NT_STATUS_NO_SUCH_PRIVILEGE NT_STATUS(0xC0000000 | 0x0060)
+#define NT_STATUS_PRIVILEGE_NOT_HELD NT_STATUS(0xC0000000 | 0x0061)
+#define NT_STATUS_INVALID_ACCOUNT_NAME NT_STATUS(0xC0000000 | 0x0062)
+#define NT_STATUS_USER_EXISTS NT_STATUS(0xC0000000 | 0x0063)
+#define NT_STATUS_NO_SUCH_USER NT_STATUS(0xC0000000 | 0x0064)
+#define NT_STATUS_GROUP_EXISTS NT_STATUS(0xC0000000 | 0x0065)
+#define NT_STATUS_NO_SUCH_GROUP NT_STATUS(0xC0000000 | 0x0066)
+#define NT_STATUS_MEMBER_IN_GROUP NT_STATUS(0xC0000000 | 0x0067)
+#define NT_STATUS_MEMBER_NOT_IN_GROUP NT_STATUS(0xC0000000 | 0x0068)
+#define NT_STATUS_LAST_ADMIN NT_STATUS(0xC0000000 | 0x0069)
+#define NT_STATUS_WRONG_PASSWORD NT_STATUS(0xC0000000 | 0x006a)
+#define NT_STATUS_ILL_FORMED_PASSWORD NT_STATUS(0xC0000000 | 0x006b)
+#define NT_STATUS_PASSWORD_RESTRICTION NT_STATUS(0xC0000000 | 0x006c)
+#define NT_STATUS_LOGON_FAILURE NT_STATUS(0xC0000000 | 0x006d)
+#define NT_STATUS_ACCOUNT_RESTRICTION NT_STATUS(0xC0000000 | 0x006e)
+#define NT_STATUS_INVALID_LOGON_HOURS NT_STATUS(0xC0000000 | 0x006f)
+#define NT_STATUS_INVALID_WORKSTATION NT_STATUS(0xC0000000 | 0x0070)
+#define NT_STATUS_PASSWORD_EXPIRED NT_STATUS(0xC0000000 | 0x0071)
+#define NT_STATUS_ACCOUNT_DISABLED NT_STATUS(0xC0000000 | 0x0072)
+#define NT_STATUS_NONE_MAPPED NT_STATUS(0xC0000000 | 0x0073)
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED NT_STATUS(0xC0000000 | 0x0074)
+#define NT_STATUS_LUIDS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0075)
+#define NT_STATUS_INVALID_SUB_AUTHORITY NT_STATUS(0xC0000000 | 0x0076)
+#define NT_STATUS_INVALID_ACL NT_STATUS(0xC0000000 | 0x0077)
+#define NT_STATUS_INVALID_SID NT_STATUS(0xC0000000 | 0x0078)
+#define NT_STATUS_INVALID_SECURITY_DESCR NT_STATUS(0xC0000000 | 0x0079)
+#define NT_STATUS_PROCEDURE_NOT_FOUND NT_STATUS(0xC0000000 | 0x007a)
+#define NT_STATUS_INVALID_IMAGE_FORMAT NT_STATUS(0xC0000000 | 0x007b)
+#define NT_STATUS_NO_TOKEN NT_STATUS(0xC0000000 | 0x007c)
+#define NT_STATUS_BAD_INHERITANCE_ACL NT_STATUS(0xC0000000 | 0x007d)
+#define NT_STATUS_RANGE_NOT_LOCKED NT_STATUS(0xC0000000 | 0x007e)
+#define NT_STATUS_DISK_FULL NT_STATUS(0xC0000000 | 0x007f)
+#define NT_STATUS_SERVER_DISABLED NT_STATUS(0xC0000000 | 0x0080)
+#define NT_STATUS_SERVER_NOT_DISABLED NT_STATUS(0xC0000000 | 0x0081)
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED NT_STATUS(0xC0000000 | 0x0082)
+#define NT_STATUS_GUIDS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0083)
+#define NT_STATUS_INVALID_ID_AUTHORITY NT_STATUS(0xC0000000 | 0x0084)
+#define NT_STATUS_AGENTS_EXHAUSTED NT_STATUS(0xC0000000 | 0x0085)
+#define NT_STATUS_INVALID_VOLUME_LABEL NT_STATUS(0xC0000000 | 0x0086)
+#define NT_STATUS_SECTION_NOT_EXTENDED NT_STATUS(0xC0000000 | 0x0087)
+#define NT_STATUS_NOT_MAPPED_DATA NT_STATUS(0xC0000000 | 0x0088)
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND NT_STATUS(0xC0000000 | 0x0089)
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND NT_STATUS(0xC0000000 | 0x008a)
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND NT_STATUS(0xC0000000 | 0x008b)
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED NT_STATUS(0xC0000000 | 0x008c)
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND NT_STATUS(0xC0000000 | 0x008d)
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO NT_STATUS(0xC0000000 | 0x008e)
+#define NT_STATUS_FLOAT_INEXACT_RESULT NT_STATUS(0xC0000000 | 0x008f)
+#define NT_STATUS_FLOAT_INVALID_OPERATION NT_STATUS(0xC0000000 | 0x0090)
+#define NT_STATUS_FLOAT_OVERFLOW NT_STATUS(0xC0000000 | 0x0091)
+#define NT_STATUS_FLOAT_STACK_CHECK NT_STATUS(0xC0000000 | 0x0092)
+#define NT_STATUS_FLOAT_UNDERFLOW NT_STATUS(0xC0000000 | 0x0093)
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO NT_STATUS(0xC0000000 | 0x0094)
+#define NT_STATUS_INTEGER_OVERFLOW NT_STATUS(0xC0000000 | 0x0095)
+#define NT_STATUS_PRIVILEGED_INSTRUCTION NT_STATUS(0xC0000000 | 0x0096)
+#define NT_STATUS_TOO_MANY_PAGING_FILES NT_STATUS(0xC0000000 | 0x0097)
+#define NT_STATUS_FILE_INVALID NT_STATUS(0xC0000000 | 0x0098)
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED NT_STATUS(0xC0000000 | 0x0099)
+#define NT_STATUS_INSUFFICIENT_RESOURCES NT_STATUS(0xC0000000 | 0x009a)
+#define NT_STATUS_DFS_EXIT_PATH_FOUND NT_STATUS(0xC0000000 | 0x009b)
+#define NT_STATUS_DEVICE_DATA_ERROR NT_STATUS(0xC0000000 | 0x009c)
+#define NT_STATUS_DEVICE_NOT_CONNECTED NT_STATUS(0xC0000000 | 0x009d)
+#define NT_STATUS_DEVICE_POWER_FAILURE NT_STATUS(0xC0000000 | 0x009e)
+#define NT_STATUS_FREE_VM_NOT_AT_BASE NT_STATUS(0xC0000000 | 0x009f)
+#define NT_STATUS_MEMORY_NOT_ALLOCATED NT_STATUS(0xC0000000 | 0x00a0)
+#define NT_STATUS_WORKING_SET_QUOTA NT_STATUS(0xC0000000 | 0x00a1)
+#define NT_STATUS_MEDIA_WRITE_PROTECTED NT_STATUS(0xC0000000 | 0x00a2)
+#define NT_STATUS_DEVICE_NOT_READY NT_STATUS(0xC0000000 | 0x00a3)
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES NT_STATUS(0xC0000000 | 0x00a4)
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL NT_STATUS(0xC0000000 | 0x00a5)
+#define NT_STATUS_CANT_OPEN_ANONYMOUS NT_STATUS(0xC0000000 | 0x00a6)
+#define NT_STATUS_BAD_VALIDATION_CLASS NT_STATUS(0xC0000000 | 0x00a7)
+#define NT_STATUS_BAD_TOKEN_TYPE NT_STATUS(0xC0000000 | 0x00a8)
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD NT_STATUS(0xC0000000 | 0x00a9)
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT NT_STATUS(0xC0000000 | 0x00aa)
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x00ab)
+#define NT_STATUS_PIPE_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x00ac)
+#define NT_STATUS_INVALID_PIPE_STATE NT_STATUS(0xC0000000 | 0x00ad)
+#define NT_STATUS_PIPE_BUSY NT_STATUS(0xC0000000 | 0x00ae)
+#define NT_STATUS_ILLEGAL_FUNCTION NT_STATUS(0xC0000000 | 0x00af)
+#define NT_STATUS_PIPE_DISCONNECTED NT_STATUS(0xC0000000 | 0x00b0)
+#define NT_STATUS_PIPE_CLOSING NT_STATUS(0xC0000000 | 0x00b1)
+#define NT_STATUS_PIPE_CONNECTED NT_STATUS(0xC0000000 | 0x00b2)
+#define NT_STATUS_PIPE_LISTENING NT_STATUS(0xC0000000 | 0x00b3)
+#define NT_STATUS_INVALID_READ_MODE NT_STATUS(0xC0000000 | 0x00b4)
+#define NT_STATUS_IO_TIMEOUT NT_STATUS(0xC0000000 | 0x00b5)
+#define NT_STATUS_FILE_FORCED_CLOSED NT_STATUS(0xC0000000 | 0x00b6)
+#define NT_STATUS_PROFILING_NOT_STARTED NT_STATUS(0xC0000000 | 0x00b7)
+#define NT_STATUS_PROFILING_NOT_STOPPED NT_STATUS(0xC0000000 | 0x00b8)
+#define NT_STATUS_COULD_NOT_INTERPRET NT_STATUS(0xC0000000 | 0x00b9)
+#define NT_STATUS_FILE_IS_A_DIRECTORY NT_STATUS(0xC0000000 | 0x00ba)
+#define NT_STATUS_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x00bb)
+#define NT_STATUS_REMOTE_NOT_LISTENING NT_STATUS(0xC0000000 | 0x00bc)
+#define NT_STATUS_DUPLICATE_NAME NT_STATUS(0xC0000000 | 0x00bd)
+#define NT_STATUS_BAD_NETWORK_PATH NT_STATUS(0xC0000000 | 0x00be)
+#define NT_STATUS_NETWORK_BUSY NT_STATUS(0xC0000000 | 0x00bf)
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST NT_STATUS(0xC0000000 | 0x00c0)
+#define NT_STATUS_TOO_MANY_COMMANDS NT_STATUS(0xC0000000 | 0x00c1)
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR NT_STATUS(0xC0000000 | 0x00c2)
+#define NT_STATUS_INVALID_NETWORK_RESPONSE NT_STATUS(0xC0000000 | 0x00c3)
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR NT_STATUS(0xC0000000 | 0x00c4)
+#define NT_STATUS_BAD_REMOTE_ADAPTER NT_STATUS(0xC0000000 | 0x00c5)
+#define NT_STATUS_PRINT_QUEUE_FULL NT_STATUS(0xC0000000 | 0x00c6)
+#define NT_STATUS_NO_SPOOL_SPACE NT_STATUS(0xC0000000 | 0x00c7)
+#define NT_STATUS_PRINT_CANCELLED NT_STATUS(0xC0000000 | 0x00c8)
+#define NT_STATUS_NETWORK_NAME_DELETED NT_STATUS(0xC0000000 | 0x00c9)
+#define NT_STATUS_NETWORK_ACCESS_DENIED NT_STATUS(0xC0000000 | 0x00ca)
+#define NT_STATUS_BAD_DEVICE_TYPE NT_STATUS(0xC0000000 | 0x00cb)
+#define NT_STATUS_BAD_NETWORK_NAME NT_STATUS(0xC0000000 | 0x00cc)
+#define NT_STATUS_TOO_MANY_NAMES NT_STATUS(0xC0000000 | 0x00cd)
+#define NT_STATUS_TOO_MANY_SESSIONS NT_STATUS(0xC0000000 | 0x00ce)
+#define NT_STATUS_SHARING_PAUSED NT_STATUS(0xC0000000 | 0x00cf)
+#define NT_STATUS_REQUEST_NOT_ACCEPTED NT_STATUS(0xC0000000 | 0x00d0)
+#define NT_STATUS_REDIRECTOR_PAUSED NT_STATUS(0xC0000000 | 0x00d1)
+#define NT_STATUS_NET_WRITE_FAULT NT_STATUS(0xC0000000 | 0x00d2)
+#define NT_STATUS_PROFILING_AT_LIMIT NT_STATUS(0xC0000000 | 0x00d3)
+#define NT_STATUS_NOT_SAME_DEVICE NT_STATUS(0xC0000000 | 0x00d4)
+#define NT_STATUS_FILE_RENAMED NT_STATUS(0xC0000000 | 0x00d5)
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED NT_STATUS(0xC0000000 | 0x00d6)
+#define NT_STATUS_NO_SECURITY_ON_OBJECT NT_STATUS(0xC0000000 | 0x00d7)
+#define NT_STATUS_CANT_WAIT NT_STATUS(0xC0000000 | 0x00d8)
+#define NT_STATUS_PIPE_EMPTY NT_STATUS(0xC0000000 | 0x00d9)
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO NT_STATUS(0xC0000000 | 0x00da)
+#define NT_STATUS_CANT_TERMINATE_SELF NT_STATUS(0xC0000000 | 0x00db)
+#define NT_STATUS_INVALID_SERVER_STATE NT_STATUS(0xC0000000 | 0x00dc)
+#define NT_STATUS_INVALID_DOMAIN_STATE NT_STATUS(0xC0000000 | 0x00dd)
+#define NT_STATUS_INVALID_DOMAIN_ROLE NT_STATUS(0xC0000000 | 0x00de)
+#define NT_STATUS_NO_SUCH_DOMAIN NT_STATUS(0xC0000000 | 0x00df)
+#define NT_STATUS_DOMAIN_EXISTS NT_STATUS(0xC0000000 | 0x00e0)
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x00e1)
+#define NT_STATUS_OPLOCK_NOT_GRANTED NT_STATUS(0xC0000000 | 0x00e2)
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL NT_STATUS(0xC0000000 | 0x00e3)
+#define NT_STATUS_INTERNAL_DB_CORRUPTION NT_STATUS(0xC0000000 | 0x00e4)
+#define NT_STATUS_INTERNAL_ERROR NT_STATUS(0xC0000000 | 0x00e5)
+#define NT_STATUS_GENERIC_NOT_MAPPED NT_STATUS(0xC0000000 | 0x00e6)
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT NT_STATUS(0xC0000000 | 0x00e7)
+#define NT_STATUS_INVALID_USER_BUFFER NT_STATUS(0xC0000000 | 0x00e8)
+#define NT_STATUS_UNEXPECTED_IO_ERROR NT_STATUS(0xC0000000 | 0x00e9)
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR NT_STATUS(0xC0000000 | 0x00ea)
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR NT_STATUS(0xC0000000 | 0x00eb)
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR NT_STATUS(0xC0000000 | 0x00ec)
+#define NT_STATUS_NOT_LOGON_PROCESS NT_STATUS(0xC0000000 | 0x00ed)
+#define NT_STATUS_LOGON_SESSION_EXISTS NT_STATUS(0xC0000000 | 0x00ee)
+#define NT_STATUS_INVALID_PARAMETER_1 NT_STATUS(0xC0000000 | 0x00ef)
+#define NT_STATUS_INVALID_PARAMETER_2 NT_STATUS(0xC0000000 | 0x00f0)
+#define NT_STATUS_INVALID_PARAMETER_3 NT_STATUS(0xC0000000 | 0x00f1)
+#define NT_STATUS_INVALID_PARAMETER_4 NT_STATUS(0xC0000000 | 0x00f2)
+#define NT_STATUS_INVALID_PARAMETER_5 NT_STATUS(0xC0000000 | 0x00f3)
+#define NT_STATUS_INVALID_PARAMETER_6 NT_STATUS(0xC0000000 | 0x00f4)
+#define NT_STATUS_INVALID_PARAMETER_7 NT_STATUS(0xC0000000 | 0x00f5)
+#define NT_STATUS_INVALID_PARAMETER_8 NT_STATUS(0xC0000000 | 0x00f6)
+#define NT_STATUS_INVALID_PARAMETER_9 NT_STATUS(0xC0000000 | 0x00f7)
+#define NT_STATUS_INVALID_PARAMETER_10 NT_STATUS(0xC0000000 | 0x00f8)
+#define NT_STATUS_INVALID_PARAMETER_11 NT_STATUS(0xC0000000 | 0x00f9)
+#define NT_STATUS_INVALID_PARAMETER_12 NT_STATUS(0xC0000000 | 0x00fa)
+#define NT_STATUS_REDIRECTOR_NOT_STARTED NT_STATUS(0xC0000000 | 0x00fb)
+#define NT_STATUS_REDIRECTOR_STARTED NT_STATUS(0xC0000000 | 0x00fc)
+#define NT_STATUS_STACK_OVERFLOW NT_STATUS(0xC0000000 | 0x00fd)
+#define NT_STATUS_NO_SUCH_PACKAGE NT_STATUS(0xC0000000 | 0x00fe)
+#define NT_STATUS_BAD_FUNCTION_TABLE NT_STATUS(0xC0000000 | 0x00ff)
+#define NT_STATUS_DIRECTORY_NOT_EMPTY NT_STATUS(0xC0000000 | 0x0101)
+#define NT_STATUS_FILE_CORRUPT_ERROR NT_STATUS(0xC0000000 | 0x0102)
+#define NT_STATUS_NOT_A_DIRECTORY NT_STATUS(0xC0000000 | 0x0103)
+#define NT_STATUS_BAD_LOGON_SESSION_STATE NT_STATUS(0xC0000000 | 0x0104)
+#define NT_STATUS_LOGON_SESSION_COLLISION NT_STATUS(0xC0000000 | 0x0105)
+#define NT_STATUS_NAME_TOO_LONG NT_STATUS(0xC0000000 | 0x0106)
+#define NT_STATUS_FILES_OPEN NT_STATUS(0xC0000000 | 0x0107)
+#define NT_STATUS_CONNECTION_IN_USE NT_STATUS(0xC0000000 | 0x0108)
+#define NT_STATUS_MESSAGE_NOT_FOUND NT_STATUS(0xC0000000 | 0x0109)
+#define NT_STATUS_PROCESS_IS_TERMINATING NT_STATUS(0xC0000000 | 0x010a)
+#define NT_STATUS_INVALID_LOGON_TYPE NT_STATUS(0xC0000000 | 0x010b)
+#define NT_STATUS_NO_GUID_TRANSLATION NT_STATUS(0xC0000000 | 0x010c)
+#define NT_STATUS_CANNOT_IMPERSONATE NT_STATUS(0xC0000000 | 0x010d)
+#define NT_STATUS_IMAGE_ALREADY_LOADED NT_STATUS(0xC0000000 | 0x010e)
+#define NT_STATUS_ABIOS_NOT_PRESENT NT_STATUS(0xC0000000 | 0x010f)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST NT_STATUS(0xC0000000 | 0x0110)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED NT_STATUS(0xC0000000 | 0x0111)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER NT_STATUS(0xC0000000 | 0x0112)
+#define NT_STATUS_ABIOS_INVALID_COMMAND NT_STATUS(0xC0000000 | 0x0113)
+#define NT_STATUS_ABIOS_INVALID_LID NT_STATUS(0xC0000000 | 0x0114)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x0115)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR NT_STATUS(0xC0000000 | 0x0116)
+#define NT_STATUS_NO_LDT NT_STATUS(0xC0000000 | 0x0117)
+#define NT_STATUS_INVALID_LDT_SIZE NT_STATUS(0xC0000000 | 0x0118)
+#define NT_STATUS_INVALID_LDT_OFFSET NT_STATUS(0xC0000000 | 0x0119)
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR NT_STATUS(0xC0000000 | 0x011a)
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT NT_STATUS(0xC0000000 | 0x011b)
+#define NT_STATUS_RXACT_INVALID_STATE NT_STATUS(0xC0000000 | 0x011c)
+#define NT_STATUS_RXACT_COMMIT_FAILURE NT_STATUS(0xC0000000 | 0x011d)
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO NT_STATUS(0xC0000000 | 0x011e)
+#define NT_STATUS_TOO_MANY_OPENED_FILES NT_STATUS(0xC0000000 | 0x011f)
+#define NT_STATUS_CANCELLED NT_STATUS(0xC0000000 | 0x0120)
+#define NT_STATUS_CANNOT_DELETE NT_STATUS(0xC0000000 | 0x0121)
+#define NT_STATUS_INVALID_COMPUTER_NAME NT_STATUS(0xC0000000 | 0x0122)
+#define NT_STATUS_FILE_DELETED NT_STATUS(0xC0000000 | 0x0123)
+#define NT_STATUS_SPECIAL_ACCOUNT NT_STATUS(0xC0000000 | 0x0124)
+#define NT_STATUS_SPECIAL_GROUP NT_STATUS(0xC0000000 | 0x0125)
+#define NT_STATUS_SPECIAL_USER NT_STATUS(0xC0000000 | 0x0126)
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP NT_STATUS(0xC0000000 | 0x0127)
+#define NT_STATUS_FILE_CLOSED NT_STATUS(0xC0000000 | 0x0128)
+#define NT_STATUS_TOO_MANY_THREADS NT_STATUS(0xC0000000 | 0x0129)
+#define NT_STATUS_THREAD_NOT_IN_PROCESS NT_STATUS(0xC0000000 | 0x012a)
+#define NT_STATUS_TOKEN_ALREADY_IN_USE NT_STATUS(0xC0000000 | 0x012b)
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x012c)
+#define NT_STATUS_COMMITMENT_LIMIT NT_STATUS(0xC0000000 | 0x012d)
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT NT_STATUS(0xC0000000 | 0x012e)
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ NT_STATUS(0xC0000000 | 0x012f)
+#define NT_STATUS_INVALID_IMAGE_PROTECT NT_STATUS(0xC0000000 | 0x0130)
+#define NT_STATUS_INVALID_IMAGE_WIN_16 NT_STATUS(0xC0000000 | 0x0131)
+#define NT_STATUS_LOGON_SERVER_CONFLICT NT_STATUS(0xC0000000 | 0x0132)
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC NT_STATUS(0xC0000000 | 0x0133)
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED NT_STATUS(0xC0000000 | 0x0134)
+#define NT_STATUS_DLL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0135)
+#define NT_STATUS_OPEN_FAILED NT_STATUS(0xC0000000 | 0x0136)
+#define NT_STATUS_IO_PRIVILEGE_FAILED NT_STATUS(0xC0000000 | 0x0137)
+#define NT_STATUS_ORDINAL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0138)
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND NT_STATUS(0xC0000000 | 0x0139)
+#define NT_STATUS_CONTROL_C_EXIT NT_STATUS(0xC0000000 | 0x013a)
+#define NT_STATUS_LOCAL_DISCONNECT NT_STATUS(0xC0000000 | 0x013b)
+#define NT_STATUS_REMOTE_DISCONNECT NT_STATUS(0xC0000000 | 0x013c)
+#define NT_STATUS_REMOTE_RESOURCES NT_STATUS(0xC0000000 | 0x013d)
+#define NT_STATUS_LINK_FAILED NT_STATUS(0xC0000000 | 0x013e)
+#define NT_STATUS_LINK_TIMEOUT NT_STATUS(0xC0000000 | 0x013f)
+#define NT_STATUS_INVALID_CONNECTION NT_STATUS(0xC0000000 | 0x0140)
+#define NT_STATUS_INVALID_ADDRESS NT_STATUS(0xC0000000 | 0x0141)
+#define NT_STATUS_DLL_INIT_FAILED NT_STATUS(0xC0000000 | 0x0142)
+#define NT_STATUS_MISSING_SYSTEMFILE NT_STATUS(0xC0000000 | 0x0143)
+#define NT_STATUS_UNHANDLED_EXCEPTION NT_STATUS(0xC0000000 | 0x0144)
+#define NT_STATUS_APP_INIT_FAILURE NT_STATUS(0xC0000000 | 0x0145)
+#define NT_STATUS_PAGEFILE_CREATE_FAILED NT_STATUS(0xC0000000 | 0x0146)
+#define NT_STATUS_NO_PAGEFILE NT_STATUS(0xC0000000 | 0x0147)
+#define NT_STATUS_INVALID_LEVEL NT_STATUS(0xC0000000 | 0x0148)
+#define NT_STATUS_WRONG_PASSWORD_CORE NT_STATUS(0xC0000000 | 0x0149)
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT NT_STATUS(0xC0000000 | 0x014a)
+#define NT_STATUS_PIPE_BROKEN NT_STATUS(0xC0000000 | 0x014b)
+#define NT_STATUS_REGISTRY_CORRUPT NT_STATUS(0xC0000000 | 0x014c)
+#define NT_STATUS_REGISTRY_IO_FAILED NT_STATUS(0xC0000000 | 0x014d)
+#define NT_STATUS_NO_EVENT_PAIR NT_STATUS(0xC0000000 | 0x014e)
+#define NT_STATUS_UNRECOGNIZED_VOLUME NT_STATUS(0xC0000000 | 0x014f)
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED NT_STATUS(0xC0000000 | 0x0150)
+#define NT_STATUS_NO_SUCH_ALIAS NT_STATUS(0xC0000000 | 0x0151)
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS NT_STATUS(0xC0000000 | 0x0152)
+#define NT_STATUS_MEMBER_IN_ALIAS NT_STATUS(0xC0000000 | 0x0153)
+#define NT_STATUS_ALIAS_EXISTS NT_STATUS(0xC0000000 | 0x0154)
+#define NT_STATUS_LOGON_NOT_GRANTED NT_STATUS(0xC0000000 | 0x0155)
+#define NT_STATUS_TOO_MANY_SECRETS NT_STATUS(0xC0000000 | 0x0156)
+#define NT_STATUS_SECRET_TOO_LONG NT_STATUS(0xC0000000 | 0x0157)
+#define NT_STATUS_INTERNAL_DB_ERROR NT_STATUS(0xC0000000 | 0x0158)
+#define NT_STATUS_FULLSCREEN_MODE NT_STATUS(0xC0000000 | 0x0159)
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS NT_STATUS(0xC0000000 | 0x015a)
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED NT_STATUS(0xC0000000 | 0x015b)
+#define NT_STATUS_NOT_REGISTRY_FILE NT_STATUS(0xC0000000 | 0x015c)
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED NT_STATUS(0xC0000000 | 0x015d)
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR NT_STATUS(0xC0000000 | 0x015e)
+#define NT_STATUS_FT_MISSING_MEMBER NT_STATUS(0xC0000000 | 0x015f)
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY NT_STATUS(0xC0000000 | 0x0160)
+#define NT_STATUS_ILLEGAL_CHARACTER NT_STATUS(0xC0000000 | 0x0161)
+#define NT_STATUS_UNMAPPABLE_CHARACTER NT_STATUS(0xC0000000 | 0x0162)
+#define NT_STATUS_UNDEFINED_CHARACTER NT_STATUS(0xC0000000 | 0x0163)
+#define NT_STATUS_FLOPPY_VOLUME NT_STATUS(0xC0000000 | 0x0164)
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND NT_STATUS(0xC0000000 | 0x0165)
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER NT_STATUS(0xC0000000 | 0x0166)
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR NT_STATUS(0xC0000000 | 0x0167)
+#define NT_STATUS_FLOPPY_BAD_REGISTERS NT_STATUS(0xC0000000 | 0x0168)
+#define NT_STATUS_DISK_RECALIBRATE_FAILED NT_STATUS(0xC0000000 | 0x0169)
+#define NT_STATUS_DISK_OPERATION_FAILED NT_STATUS(0xC0000000 | 0x016a)
+#define NT_STATUS_DISK_RESET_FAILED NT_STATUS(0xC0000000 | 0x016b)
+#define NT_STATUS_SHARED_IRQ_BUSY NT_STATUS(0xC0000000 | 0x016c)
+#define NT_STATUS_FT_ORPHANING NT_STATUS(0xC0000000 | 0x016d)
+#define NT_STATUS_PARTITION_FAILURE NT_STATUS(0xC0000000 | 0x0172)
+#define NT_STATUS_INVALID_BLOCK_LENGTH NT_STATUS(0xC0000000 | 0x0173)
+#define NT_STATUS_DEVICE_NOT_PARTITIONED NT_STATUS(0xC0000000 | 0x0174)
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA NT_STATUS(0xC0000000 | 0x0175)
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA NT_STATUS(0xC0000000 | 0x0176)
+#define NT_STATUS_EOM_OVERFLOW NT_STATUS(0xC0000000 | 0x0177)
+#define NT_STATUS_NO_MEDIA NT_STATUS(0xC0000000 | 0x0178)
+#define NT_STATUS_NO_SUCH_MEMBER NT_STATUS(0xC0000000 | 0x017a)
+#define NT_STATUS_INVALID_MEMBER NT_STATUS(0xC0000000 | 0x017b)
+#define NT_STATUS_KEY_DELETED NT_STATUS(0xC0000000 | 0x017c)
+#define NT_STATUS_NO_LOG_SPACE NT_STATUS(0xC0000000 | 0x017d)
+#define NT_STATUS_TOO_MANY_SIDS NT_STATUS(0xC0000000 | 0x017e)
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED NT_STATUS(0xC0000000 | 0x017f)
+#define NT_STATUS_KEY_HAS_CHILDREN NT_STATUS(0xC0000000 | 0x0180)
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE NT_STATUS(0xC0000000 | 0x0181)
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR NT_STATUS(0xC0000000 | 0x0182)
+#define NT_STATUS_DRIVER_INTERNAL_ERROR NT_STATUS(0xC0000000 | 0x0183)
+#define NT_STATUS_INVALID_DEVICE_STATE NT_STATUS(0xC0000000 | 0x0184)
+#define NT_STATUS_IO_DEVICE_ERROR NT_STATUS(0xC0000000 | 0x0185)
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x0186)
+#define NT_STATUS_BACKUP_CONTROLLER NT_STATUS(0xC0000000 | 0x0187)
+#define NT_STATUS_LOG_FILE_FULL NT_STATUS(0xC0000000 | 0x0188)
+#define NT_STATUS_TOO_LATE NT_STATUS(0xC0000000 | 0x0189)
+#define NT_STATUS_NO_TRUST_LSA_SECRET NT_STATUS(0xC0000000 | 0x018a)
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT NT_STATUS(0xC0000000 | 0x018b)
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE NT_STATUS(0xC0000000 | 0x018c)
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE NT_STATUS(0xC0000000 | 0x018d)
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT NT_STATUS(0xC0000000 | 0x018e)
+#define NT_STATUS_EVENTLOG_CANT_START NT_STATUS(0xC0000000 | 0x018f)
+#define NT_STATUS_TRUST_FAILURE NT_STATUS(0xC0000000 | 0x0190)
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED NT_STATUS(0xC0000000 | 0x0191)
+#define NT_STATUS_NETLOGON_NOT_STARTED NT_STATUS(0xC0000000 | 0x0192)
+#define NT_STATUS_ACCOUNT_EXPIRED NT_STATUS(0xC0000000 | 0x0193)
+#define NT_STATUS_POSSIBLE_DEADLOCK NT_STATUS(0xC0000000 | 0x0194)
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT NT_STATUS(0xC0000000 | 0x0195)
+#define NT_STATUS_REMOTE_SESSION_LIMIT NT_STATUS(0xC0000000 | 0x0196)
+#define NT_STATUS_EVENTLOG_FILE_CHANGED NT_STATUS(0xC0000000 | 0x0197)
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x0198)
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x0199)
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT NT_STATUS(0xC0000000 | 0x019a)
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT NT_STATUS(0xC0000000 | 0x019b)
+#define NT_STATUS_FS_DRIVER_REQUIRED NT_STATUS(0xC0000000 | 0x019c)
+#define NT_STATUS_NO_USER_SESSION_KEY NT_STATUS(0xC0000000 | 0x0202)
+#define NT_STATUS_USER_SESSION_DELETED NT_STATUS(0xC0000000 | 0x0203)
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND NT_STATUS(0xC0000000 | 0x0204)
+#define NT_STATUS_INSUFF_SERVER_RESOURCES NT_STATUS(0xC0000000 | 0x0205)
+#define NT_STATUS_INVALID_BUFFER_SIZE NT_STATUS(0xC0000000 | 0x0206)
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT NT_STATUS(0xC0000000 | 0x0207)
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD NT_STATUS(0xC0000000 | 0x0208)
+#define NT_STATUS_TOO_MANY_ADDRESSES NT_STATUS(0xC0000000 | 0x0209)
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS NT_STATUS(0xC0000000 | 0x020a)
+#define NT_STATUS_ADDRESS_CLOSED NT_STATUS(0xC0000000 | 0x020b)
+#define NT_STATUS_CONNECTION_DISCONNECTED NT_STATUS(0xC0000000 | 0x020c)
+#define NT_STATUS_CONNECTION_RESET NT_STATUS(0xC0000000 | 0x020d)
+#define NT_STATUS_TOO_MANY_NODES NT_STATUS(0xC0000000 | 0x020e)
+#define NT_STATUS_TRANSACTION_ABORTED NT_STATUS(0xC0000000 | 0x020f)
+#define NT_STATUS_TRANSACTION_TIMED_OUT NT_STATUS(0xC0000000 | 0x0210)
+#define NT_STATUS_TRANSACTION_NO_RELEASE NT_STATUS(0xC0000000 | 0x0211)
+#define NT_STATUS_TRANSACTION_NO_MATCH NT_STATUS(0xC0000000 | 0x0212)
+#define NT_STATUS_TRANSACTION_RESPONDED NT_STATUS(0xC0000000 | 0x0213)
+#define NT_STATUS_TRANSACTION_INVALID_ID NT_STATUS(0xC0000000 | 0x0214)
+#define NT_STATUS_TRANSACTION_INVALID_TYPE NT_STATUS(0xC0000000 | 0x0215)
+#define NT_STATUS_NOT_SERVER_SESSION NT_STATUS(0xC0000000 | 0x0216)
+#define NT_STATUS_NOT_CLIENT_SESSION NT_STATUS(0xC0000000 | 0x0217)
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE NT_STATUS(0xC0000000 | 0x0218)
+#define NT_STATUS_DEBUG_ATTACH_FAILED NT_STATUS(0xC0000000 | 0x0219)
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED NT_STATUS(0xC0000000 | 0x021a)
+#define NT_STATUS_DATA_NOT_ACCEPTED NT_STATUS(0xC0000000 | 0x021b)
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND NT_STATUS(0xC0000000 | 0x021c)
+#define NT_STATUS_VDM_HARD_ERROR NT_STATUS(0xC0000000 | 0x021d)
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT NT_STATUS(0xC0000000 | 0x021e)
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH NT_STATUS(0xC0000000 | 0x021f)
+#define NT_STATUS_MAPPED_ALIGNMENT NT_STATUS(0xC0000000 | 0x0220)
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH NT_STATUS(0xC0000000 | 0x0221)
+#define NT_STATUS_LOST_WRITEBEHIND_DATA NT_STATUS(0xC0000000 | 0x0222)
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID NT_STATUS(0xC0000000 | 0x0223)
+#define NT_STATUS_PASSWORD_MUST_CHANGE NT_STATUS(0xC0000000 | 0x0224)
+#define NT_STATUS_NOT_FOUND NT_STATUS(0xC0000000 | 0x0225)
+#define NT_STATUS_NOT_TINY_STREAM NT_STATUS(0xC0000000 | 0x0226)
+#define NT_STATUS_RECOVERY_FAILURE NT_STATUS(0xC0000000 | 0x0227)
+#define NT_STATUS_STACK_OVERFLOW_READ NT_STATUS(0xC0000000 | 0x0228)
+#define NT_STATUS_FAIL_CHECK NT_STATUS(0xC0000000 | 0x0229)
+#define NT_STATUS_DUPLICATE_OBJECTID NT_STATUS(0xC0000000 | 0x022a)
+#define NT_STATUS_OBJECTID_EXISTS NT_STATUS(0xC0000000 | 0x022b)
+#define NT_STATUS_CONVERT_TO_LARGE NT_STATUS(0xC0000000 | 0x022c)
+#define NT_STATUS_RETRY NT_STATUS(0xC0000000 | 0x022d)
+#define NT_STATUS_FOUND_OUT_OF_SCOPE NT_STATUS(0xC0000000 | 0x022e)
+#define NT_STATUS_ALLOCATE_BUCKET NT_STATUS(0xC0000000 | 0x022f)
+#define NT_STATUS_PROPSET_NOT_FOUND NT_STATUS(0xC0000000 | 0x0230)
+#define NT_STATUS_MARSHALL_OVERFLOW NT_STATUS(0xC0000000 | 0x0231)
+#define NT_STATUS_INVALID_VARIANT NT_STATUS(0xC0000000 | 0x0232)
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND NT_STATUS(0xC0000000 | 0x0233)
+#define NT_STATUS_ACCOUNT_LOCKED_OUT NT_STATUS(0xC0000000 | 0x0234)
+#define NT_STATUS_HANDLE_NOT_CLOSABLE NT_STATUS(0xC0000000 | 0x0235)
+#define NT_STATUS_CONNECTION_REFUSED NT_STATUS(0xC0000000 | 0x0236)
+#define NT_STATUS_GRACEFUL_DISCONNECT NT_STATUS(0xC0000000 | 0x0237)
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED NT_STATUS(0xC0000000 | 0x0238)
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED NT_STATUS(0xC0000000 | 0x0239)
+#define NT_STATUS_CONNECTION_INVALID NT_STATUS(0xC0000000 | 0x023a)
+#define NT_STATUS_CONNECTION_ACTIVE NT_STATUS(0xC0000000 | 0x023b)
+#define NT_STATUS_NETWORK_UNREACHABLE NT_STATUS(0xC0000000 | 0x023c)
+#define NT_STATUS_HOST_UNREACHABLE NT_STATUS(0xC0000000 | 0x023d)
+#define NT_STATUS_PROTOCOL_UNREACHABLE NT_STATUS(0xC0000000 | 0x023e)
+#define NT_STATUS_PORT_UNREACHABLE NT_STATUS(0xC0000000 | 0x023f)
+#define NT_STATUS_REQUEST_ABORTED NT_STATUS(0xC0000000 | 0x0240)
+#define NT_STATUS_CONNECTION_ABORTED NT_STATUS(0xC0000000 | 0x0241)
+#define NT_STATUS_BAD_COMPRESSION_BUFFER NT_STATUS(0xC0000000 | 0x0242)
+#define NT_STATUS_USER_MAPPED_FILE NT_STATUS(0xC0000000 | 0x0243)
+#define NT_STATUS_AUDIT_FAILED NT_STATUS(0xC0000000 | 0x0244)
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET NT_STATUS(0xC0000000 | 0x0245)
+#define NT_STATUS_CONNECTION_COUNT_LIMIT NT_STATUS(0xC0000000 | 0x0246)
+#define NT_STATUS_LOGIN_TIME_RESTRICTION NT_STATUS(0xC0000000 | 0x0247)
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION NT_STATUS(0xC0000000 | 0x0248)
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH NT_STATUS(0xC0000000 | 0x0249)
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO NT_STATUS(0xC0000000 | 0x0250)
+#define NT_STATUS_BAD_DLL_ENTRYPOINT NT_STATUS(0xC0000000 | 0x0251)
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT NT_STATUS(0xC0000000 | 0x0252)
+#define NT_STATUS_LPC_REPLY_LOST NT_STATUS(0xC0000000 | 0x0253)
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 NT_STATUS(0xC0000000 | 0x0254)
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 NT_STATUS(0xC0000000 | 0x0255)
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT NT_STATUS(0xC0000000 | 0x0256)
+#define NT_STATUS_PATH_NOT_COVERED NT_STATUS(0xC0000000 | 0x0257)
+#define NT_STATUS_NO_CALLBACK_ACTIVE NT_STATUS(0xC0000000 | 0x0258)
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED NT_STATUS(0xC0000000 | 0x0259)
+#define NT_STATUS_PWD_TOO_SHORT NT_STATUS(0xC0000000 | 0x025a)
+#define NT_STATUS_PWD_TOO_RECENT NT_STATUS(0xC0000000 | 0x025b)
+#define NT_STATUS_PWD_HISTORY_CONFLICT NT_STATUS(0xC0000000 | 0x025c)
+#define NT_STATUS_PLUGPLAY_NO_DEVICE NT_STATUS(0xC0000000 | 0x025e)
+#define NT_STATUS_UNSUPPORTED_COMPRESSION NT_STATUS(0xC0000000 | 0x025f)
+#define NT_STATUS_INVALID_HW_PROFILE NT_STATUS(0xC0000000 | 0x0260)
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH NT_STATUS(0xC0000000 | 0x0261)
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND NT_STATUS(0xC0000000 | 0x0262)
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND NT_STATUS(0xC0000000 | 0x0263)
+#define NT_STATUS_RESOURCE_NOT_OWNED NT_STATUS(0xC0000000 | 0x0264)
+#define NT_STATUS_TOO_MANY_LINKS NT_STATUS(0xC0000000 | 0x0265)
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT NT_STATUS(0xC0000000 | 0x0266)
+#define NT_STATUS_FILE_IS_OFFLINE NT_STATUS(0xC0000000 | 0x0267)
+#define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE) /* scheduler */
+
+#endif /* _NTERR_H */
diff --git a/source/include/passdb.h b/source/include/passdb.h
new file mode 100644
index 00000000000..8836bad3e27
--- /dev/null
+++ b/source/include/passdb.h
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ passdb structures and parameters
+ Copyright (C) Gerald Carter 2001
+ Copyright (C) Luke Kenneth Casson Leighton 1998 - 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _PASSDB_H
+#define _PASSDB_H
+
+/*
+ * This next constant specifies the version number of the VFS interface
+ * this smbd will load. Increment this if *ANY* changes are made to the
+ * passdb_ops below.
+ */
+
+#define SMB_PASSDB_MAJOR_VERSION 1
+#define SMB_PASSDB_MINOR_VERSION 0
+
+/* passdb operations structure */
+struct passdb_ops {
+
+ /* Iteration Functions*/
+ BOOL (*setsampwent) (BOOL update);
+ void (*endsampwent) (void);
+ SAM_ACCOUNT* (*getsampwent) (void);
+
+ /* Lookup Functions */
+ SAM_ACCOUNT* (*getsampwuid) (uid_t uid);
+ SAM_ACCOUNT* (*getsampwrid) (uint32 rid);
+ SAM_ACOCUNT* (*getsampwnam) (char* username);
+
+ /* Modify the SAM database */
+ BOOL (*update_sam_account) (SAM_ACCOUNT* sampass, BOOL override);
+ BOOL (*delete_sam_account) (char* username);
+ BOOL (*add_sam_account) (SAM_ACCOUNT* sampass);
+
+ /* authenticate a user */
+ SAM_ACCOUNT* (*logon_user) (char* username, char* domain, char* lm_pw,
+ int lm_pw_len, char* nt_pw, int nt_pw_len, char* clear_pass);
+};
+
+
+
+#define SMB_UIDMAP_MAJOR_VERSION 1
+#define SMB_UIDMAP_MINOR_VERSION 0
+
+typedef enum sid_type {SID_USER_TYPE, SID_GROUP_TYPE} SMB_SID_T
+
+/* uid mapping structure */
+struct uidmap_ops {
+
+ /* From NT to UNIX */
+ int (*sid_to_id) (DOM_SID* sid, SMB_SID_T type);
+
+ /* From UNIX to NT */
+ DOM_SID* (*id_to_sid) (int id, SMB_SID_T type);
+
+};
+
+
+#endif /* _PASSDB_H */
diff --git a/source/include/printing.h b/source/include/printing.h
new file mode 100644
index 00000000000..ee0b25d63fd
--- /dev/null
+++ b/source/include/printing.h
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing definitions
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ This file defines the low-level printing system interfaces used by the
+ SAMBA printing subsystem.
+*/
+
+/* Information for print jobs */
+struct printjob {
+ pid_t pid; /* which process launched the job */
+ int sysjob; /* the system (lp) job number */
+ int fd; /* file descriptor of open file if open */
+ time_t starttime; /* when the job started spooling */
+ int status; /* the status of this job */
+ size_t size; /* the size of the job so far */
+ BOOL spooled; /* has it been sent to the spooler yet? */
+ BOOL smbjob; /* set if the job is a SMB job */
+ fstring filename; /* the filename used to spool the file */
+ fstring jobname; /* the job name given to us by the client */
+ fstring user; /* the user who started the job */
+ fstring qname; /* name of the print queue the job was sent to */
+};
+
+/* Information for print interfaces */
+struct printif
+{
+ int (*queue_get)(int snum, print_queue_struct **q,
+ print_status_struct *status);
+ int (*queue_pause)(int snum);
+ int (*queue_resume)(int snum);
+ int (*job_delete)(int snum, struct printjob *pjob);
+ int (*job_pause)(int snum, struct printjob *pjob);
+ int (*job_resume)(int snum, struct printjob *pjob);
+ int (*job_submit)(int snum, struct printjob *pjob);
+};
+
+extern struct printif generic_printif;
+
+#ifdef HAVE_CUPS
+extern struct printif cups_printif;
+#endif /* HAVE_CUPS */
+
+#define PRINT_MAX_JOBID 10000
+#define UNIX_JOB_START PRINT_MAX_JOBID
+#define NEXT_JOBID(j) ((j+1) % PRINT_MAX_JOBID > 0 ? (j+1) % PRINT_MAX_JOBID : 1)
+
+#define PRINT_SPOOL_PREFIX "smbprn."
+#define PRINT_DATABASE_VERSION 2
diff --git a/source/include/rap.h b/source/include/rap.h
new file mode 100755
index 00000000000..24b70251b77
--- /dev/null
+++ b/source/include/rap.h
@@ -0,0 +1,508 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ RAP (SMB Remote Procedure Calls) defines and structures
+ Copyright (C) Steve French 2001 (sfrench@us.ibm.com)
+ Copyright (C) Jim McDonough 2001 (jmcd@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RAP_H_
+#define _RAP_H_
+
+/*****************************************************/
+/* */
+/* Additional RAP functionality */
+/* */
+/* RAP is the original SMB RPC, documented */
+/* by Microsoft and X/Open in the 1990s and */
+/* supported by most SMB/CIFS servers although */
+/* it is unlikely that any one implementation */
+/* supports all RAP command codes since some */
+/* are quite obsolete and a few are specific */
+/* to a particular network operating system */
+/* */
+/* Although it has largely been replaced */
+/* for complex remote admistration and management */
+/* (of servers) by the relatively newer */
+/* DCE/RPC based remote API (which better handles */
+/* large >64K data structures), there are many */
+/* important administrative and resource location */
+/* tasks and user tasks (e.g. password change) */
+/* that are performed via RAP. */
+/* */
+/* Although a few of the RAP calls are implemented */
+/* in the Samba client library already (clirap.c) */
+/* the new ones are in clirap2.c for easy patching */
+/* and integration and a corresponding header */
+/* file, rap.h, has been created. */
+/* */
+/* This is based on data from the CIFS spec */
+/* and the LAN Server and LAN Manager */
+/* Programming Reference books and published */
+/* RAP document and CIFS forum postings and */
+/* lots of trial and error. Additional */
+/* background information is available from the */
+/* X/Open reference book in their PC Interworking */
+/* series "IPC for SMB" and also from the */
+/* interoperability documentation in */
+/* ftp://ftp.microsoft.com/developr/drg/cifs */
+/* */
+/* Function names changed from API_ (as they are */
+/* in the CIFS specification to RAP_ in order */
+/* to avoid confusion with other API calls */
+/* sent via DCE RPC */
+/* */
+/*****************************************************/
+
+/*****************************************************/
+/* */
+/* Although without pound defines (of this header) */
+/* cifsrap.c already includes support for: */
+/* */
+/* WshareEnum (API number 0, level 1) */
+/* NetServerEnum2 (API num 104, level 1) */
+/* WWkstaUserLogon (132) */
+/* SamOEMchgPasswordUser2_P (214) */
+/* */
+/* and cifsprint.c already includes support for: */
+/* */
+/* WPrintJobEnum (API num 76, level 2) */
+/* WPrintJobDel (API num 81) */
+/* */
+/*****************************************************/
+
+#define RAP_WshareEnum 0
+#define RAP_WshareGetInfo 1
+#define RAP_WshareSetInfo 2
+#define RAP_WshareAdd 3
+#define RAP_WshareDel 4
+#define RAP_NetShareCheck 5
+#define RAP_WsessionEnum 6
+#define RAP_WsessionGetInfo 7
+#define RAP_WsessionDel 8
+#define RAP_WconnectionEnum 9
+#define RAP_WfileEnum 10
+#define RAP_WfileGetInfo 11
+#define RAP_WfileClose 12
+#define RAP_WserverGetInfo 13
+#define RAP_WserverSetInfo 14
+#define RAP_WserverDiskEnum 15
+#define RAP_WserverAdminCommand 16
+#define RAP_NetAuditOpen 17
+#define RAP_WauditClear 18
+#define RAP_NetErrorLogOpen 19
+#define RAP_WerrorLogClear 20
+#define RAP_NetCharDevEnum 21
+#define RAP_NetCharDevGetInfo 22
+#define RAP_WCharDevControl 23
+#define RAP_NetCharDevQEnum 24
+#define RAP_NetCharDevQGetInfo 25
+#define RAP_WCharDevQSetInfo 26
+#define RAP_WCharDevQPurge 27
+#define RAP_WCharDevQPurgeSelf 28
+#define RAP_WMessageNameEnum 29
+#define RAP_WMessageNameGetInfo 30
+#define RAP_WMessageNameAdd 31
+#define RAP_WMessageNameDel 32
+#define RAP_WMessageNameFwd 33
+#define RAP_WMessageNameUnFwd 34
+#define RAP_WMessageBufferSend 35
+#define RAP_WMessageFileSend 36
+#define RAP_WMessageLogFileSet 37
+#define RAP_WMessageLogFileGet 38
+#define RAP_WServiceEnum 39
+#define RAP_WServiceInstall 40
+#define RAP_WServiceControl 41
+#define RAP_WAccessEnum 42
+#define RAP_WAccessGetInfo 43
+#define RAP_WAccessSetInfo 44
+#define RAP_WAccessAdd 45
+#define RAP_WAccessDel 46
+#define RAP_WGroupEnum 47
+#define RAP_WGroupAdd 48
+#define RAP_WGroupDel 49
+#define RAP_WGroupAddUser 50
+#define RAP_WGroupDelUser 51
+#define RAP_WGroupGetUsers 52
+#define RAP_WUserEnum 53
+#define RAP_WUserAdd 54
+#define RAP_WUserDel 55
+#define RAP_WUserGetInfo 56
+#define RAP_WUserSetInfo 57
+#define RAP_WUserPasswordSet 58
+#define RAP_WUserGetGroups 59
+#define RAP_WWkstaSetUID 62
+#define RAP_WWkstaGetInfo 63
+#define RAP_WWkstaSetInfo 64
+#define RAP_WUseEnum 65
+#define RAP_WUseAdd 66
+#define RAP_WUseDel 67
+#define RAP_WUseGetInfo 68
+#define RAP_WPrintQEnum 69
+#define RAP_WPrintQGetInfo 70
+#define RAP_WPrintQSetInfo 71
+#define RAP_WPrintQAdd 72
+#define RAP_WPrintQDel 73
+#define RAP_WPrintQPause 74
+#define RAP_WPrintQContinue 75
+#define RAP_WPrintJobEnum 76
+#define RAP_WPrintJobGetInfo 77
+#define RAP_WPrintJobSetInfo_OLD 78
+#define RAP_WPrintJobDel 81
+#define RAP_WPrintJobPause 82
+#define RAP_WPrintJobContinue 83
+#define RAP_WPrintDestEnum 84
+#define RAP_WPrintDestGetInfo 85
+#define RAP_WPrintDestControl 86
+#define RAP_WProfileSave 87
+#define RAP_WProfileLoad 88
+#define RAP_WStatisticsGet 89
+#define RAP_WStatisticsClear 90
+#define RAP_NetRemoteTOD 91
+#define RAP_WNetBiosEnum 92
+#define RAP_WNetBiosGetInfo 93
+#define RAP_NetServerEnum 94
+#define RAP_I_NetServerEnum 95
+#define RAP_WServiceGetInfo 96
+#define RAP_WPrintQPurge 103
+#define RAP_NetServerEnum2 104
+#define RAP_WAccessGetUserPerms 105
+#define RAP_WGroupGetInfo 106
+#define RAP_WGroupSetInfo 107
+#define RAP_WGroupSetUsers 108
+#define RAP_WUserSetGroups 109
+#define RAP_WUserModalsGet 110
+#define RAP_WUserModalsSet 111
+#define RAP_WFileEnum2 112
+#define RAP_WUserAdd2 113
+#define RAP_WUserSetInfo2 114
+#define RAP_WUserPasswordSet2 115
+#define RAP_I_NetServerEnum2 116
+#define RAP_WConfigGet2 117
+#define RAP_WConfigGetAll2 118
+#define RAP_WGetDCName 119
+#define RAP_NetHandleGetInfo 120
+#define RAP_NetHandleSetInfo 121
+#define RAP_WStatisticsGet2 122
+#define RAP_WBuildGetInfo 123
+#define RAP_WFileGetInfo2 124
+#define RAP_WFileClose2 125
+#define RAP_WNetServerReqChallenge 126
+#define RAP_WNetServerAuthenticate 127
+#define RAP_WNetServerPasswordSet 128
+#define RAP_WNetAccountDeltas 129
+#define RAP_WNetAccountSync 130
+#define RAP_WUserEnum2 131
+#define RAP_WWkstaUserLogon 132
+#define RAP_WWkstaUserLogoff 133
+#define RAP_WLogonEnum 134
+#define RAP_WErrorLogRead 135
+#define RAP_NetPathType 136
+#define RAP_NetPathCanonicalize 137
+#define RAP_NetPathCompare 138
+#define RAP_NetNameValidate 139
+#define RAP_NetNameCanonicalize 140
+#define RAP_NetNameCompare 141
+#define RAP_WAuditRead 142
+#define RAP_WPrintDestAdd 143
+#define RAP_WPrintDestSetInfo 144
+#define RAP_WPrintDestDel 145
+#define RAP_WUserValidate2 146
+#define RAP_WPrintJobSetInfo 147
+#define RAP_TI_NetServerDiskEnum 148
+#define RAP_TI_NetServerDiskGetInfo 149
+#define RAP_TI_FTVerifyMirror 150
+#define RAP_TI_FTAbortVerify 151
+#define RAP_TI_FTGetInfo 152
+#define RAP_TI_FTSetInfo 153
+#define RAP_TI_FTLockDisk 154
+#define RAP_TI_FTFixError 155
+#define RAP_TI_FTAbortFix 156
+#define RAP_TI_FTDiagnoseError 157
+#define RAP_TI_FTGetDriveStats 158
+#define RAP_TI_FTErrorGetInfo 160
+#define RAP_NetAccessCheck 163
+#define RAP_NetAlertRaise 164
+#define RAP_NetAlertStart 165
+#define RAP_NetAlertStop 166
+#define RAP_NetAuditWrite 167
+#define RAP_NetIRemoteAPI 168
+#define RAP_NetServiceStatus 169
+#define RAP_NetServerRegister 170
+#define RAP_NetServerDeregister 171
+#define RAP_NetSessionEntryMake 172
+#define RAP_NetSessionEntryClear 173
+#define RAP_NetSessionEntryGetInfo 174
+#define RAP_NetSessionEntrySetInfo 175
+#define RAP_NetConnectionEntryMake 176
+#define RAP_NetConnectionEntryClear 177
+#define RAP_NetConnectionEntrySetInfo 178
+#define RAP_NetConnectionEntryGetInfo 179
+#define RAP_NetFileEntryMake 180
+#define RAP_NetFileEntryClear 181
+#define RAP_NetFileEntrySetInfo 182
+#define RAP_NetFileEntryGetInfo 183
+#define RAP_AltSrvMessageBufferSend 184
+#define RAP_AltSrvMessageFileSend 185
+#define RAP_wI_NetRplWkstaEnum 186
+#define RAP_wI_NetRplWkstaGetInfo 187
+#define RAP_wI_NetRplWkstaSetInfo 188
+#define RAP_wI_NetRplWkstaAdd 189
+#define RAP_wI_NetRplWkstaDel 190
+#define RAP_wI_NetRplProfileEnum 191
+#define RAP_wI_NetRplProfileGetInfo 192
+#define RAP_wI_NetRplProfileSetInfo 193
+#define RAP_wI_NetRplProfileAdd 194
+#define RAP_wI_NetRplProfileDel 195
+#define RAP_wI_NetRplProfileClone 196
+#define RAP_wI_NetRplBaseProfileEnum 197
+#define RAP_WIServerSetInfo 201
+#define RAP_WPrintDriverEnum 205
+#define RAP_WPrintQProcessorEnum 206
+#define RAP_WPrintPortEnum 207
+#define RAP_WNetWriteUpdateLog 208
+#define RAP_WNetAccountUpdate 209
+#define RAP_WNetAccountConfirmUpdate 210
+#define RAP_WConfigSet 211
+#define RAP_WAccountsReplicate 212
+#define RAP_SamOEMChgPasswordUser2_P 214
+#define RAP_NetServerEnum3 215
+#define RAP_WprintDriverGetInfo 250
+#define RAP_WprintDriverSetInfo 251
+#define RAP_WaliasAdd 252
+#define RAP_WaliasDel 253
+#define RAP_WaliasGetInfo 254
+#define RAP_WaliasSetInfo 255
+#define RAP_WaliasEnum 256
+#define RAP_WuserGetLogonAsn 257
+#define RAP_WuserSetLogonAsn 258
+#define RAP_WuserGetAppSel 259
+#define RAP_WuserSetAppSel 260
+#define RAP_WappAdd 261
+#define RAP_WappDel 262
+#define RAP_WappGetInfo 263
+#define RAP_WappSetInfo 264
+#define RAP_WappEnum 265
+#define RAP_WUserDCDBInit 266
+#define RAP_WDASDAdd 267
+#define RAP_WDASDDel 268
+#define RAP_WDASDGetInfo 269
+#define RAP_WDASDSetInfo 270
+#define RAP_WDASDEnum 271
+#define RAP_WDASDCheck 272
+#define RAP_WDASDCtl 273
+#define RAP_WuserRemoteLogonCheck 274
+#define RAP_WUserPasswordSet3 275
+#define RAP_WCreateRIPLMachine 276
+#define RAP_WDeleteRIPLMachine 277
+#define RAP_WGetRIPLMachineInfo 278
+#define RAP_WSetRIPLMachineInfo 279
+#define RAP_WEnumRIPLMachine 280
+#define RAP_I_ShareAdd 281
+#define RAP_AliasEnum 282
+#define RAP_WaccessApply 283
+#define RAP_WPrt16Query 284
+#define RAP_WPrt16Set 285
+#define RAP_WUserDel100 286
+#define RAP_WUserRemoteLogonCheck2 287
+#define RAP_WRemoteTODSet 294
+#define RAP_WprintJobMoveAll 295
+#define RAP_W16AppParmAdd 296
+#define RAP_W16AppParmDel 297
+#define RAP_W16AppParmGet 298
+#define RAP_W16AppParmSet 299
+#define RAP_W16RIPLMachineCreate 300
+#define RAP_W16RIPLMachineGetInfo 301
+#define RAP_W16RIPLMachineSetInfo 302
+#define RAP_W16RIPLMachineEnum 303
+#define RAP_W16RIPLMachineListParmEnum 304
+#define RAP_W16RIPLMachClassGetInfo 305
+#define RAP_W16RIPLMachClassEnum 306
+#define RAP_W16RIPLMachClassCreate 307
+#define RAP_W16RIPLMachClassSetInfo 308
+#define RAP_W16RIPLMachClassDelete 309
+#define RAP_W16RIPLMachClassLPEnum 310
+#define RAP_W16RIPLMachineDelete 311
+#define RAP_W16WSLevelGetInfo 312
+#define RAP_WserverNameAdd 313
+#define RAP_WserverNameDel 314
+#define RAP_WserverNameEnum 315
+#define RAP_I_WDASDEnum 316
+#define RAP_WDASDEnumTerminate 317
+#define RAP_WDASDSetInfo2 318
+#define MAX_API 318
+
+
+/* Parameter description strings for RAP calls */
+/* Names are defined name for RAP call with _REQ */
+/* appended to end. */
+
+#define RAP_WFileEnum2_REQ "zzWrLehb8g8"
+#define RAP_WFileGetInfo2_REQ "DWrLh"
+#define RAP_WFileClose2_REQ "D"
+
+#define RAP_NetGroupEnum_REQ "WrLeh"
+#define RAP_NetGroupAdd_REQ "WsT"
+#define RAP_NetGroupDel_REQ "z"
+#define RAP_NetGroupAddUser_REQ "zz"
+#define RAP_NetGroupDelUser_REQ "zz"
+#define RAP_NetGroupGetUsers_REQ "zWrLeh"
+#define RAP_NetGroupSetUsers_REQ "zWsTW"
+
+#define RAP_NetUserAdd2_REQ "WsTWW"
+#define RAP_NetUserEnum_REQ "WrLeh"
+#define RAP_NetUserEnum2_REQ "WrLDieh"
+#define RAP_NetUserGetGroups_REQ "zWrLeh"
+#define RAP_NetUserSetGroups_REQ "zWsTW"
+#define RAP_NetUserPasswordSet_REQ "zb16b16w"
+#define RAP_NetUserPasswordSet2_REQ "zb16b16WW"
+#define RAP_SAMOEMChgPasswordUser2_REQ "B516B16"
+#define RAP_NetUserValidate2_REQ "Wb62WWrLhWW"
+
+#define RAP_NetServerEnum2_REQ "WrLehDz"
+#define RAP_WserverGetInfo_REQ "WrLh"
+#define RAP_NetWkstatGetInfo "WrLh"
+
+#define RAP_WShareAdd_REQ "WsT"
+#define RAP_WShareEnum_REQ "WrLeh"
+#define RAP_WShareDel_REQ "zW"
+#define RAP_WWkstaGetInfo_REQ "WrLh"
+
+#define RAP_NetPrintQEnum_REQ "WrLeh"
+#define RAP_NetPrintQGetInfo_REQ "zWrLh"
+
+#define RAP_NetServerAdminCommand_REQ "zhrLeh"
+#define RAP_NetServiceEnum_REQ "WrLeh"
+#define RAP_NetServiceControl_REQ "zWWrL"
+#define RAP_NetServiceInstall_REQ "zF88sg88T"
+#define RAP_NetServiceGetInfo_REQ "zWrLh"
+#define RAP_NetSessionEnum_REQ "WrLeh"
+#define RAP_NetSessionGetInfo_REQ "zWrLh"
+#define RAP_NetSessionDel_REQ "zW"
+
+#define RAP_NetConnectionEnum_REQ "zWrLeh"
+
+#define RAP_NetWkstaUserLogoff_REQ "zzWb38WrLh"
+
+/* Description strings for returned data in RAP calls */
+/* I use all caps here in part to avoid accidental */
+/* name collisions */
+
+#define RAP_FILE_INFO_L2 "D"
+#define RAP_FILE_INFO_L3 "DWWzz"
+
+#define RAP_GROUP_INFO_L0 "B21"
+#define RAP_GROUP_INFO_L1 "B21Bz"
+#define RAP_GROUP_USERS_INFO_0 "B21"
+#define RAP_GROUP_USERS_INFO_1 "B21BN"
+
+#define RAP_USER_INFO_L0 "B21"
+#define RAP_USER_INFO_L1 "B21BB16DWzzWz"
+
+#define RAP_SERVER_INFO_L0 "B16"
+#define RAP_SERVER_INFO_L1 "B16BBDz"
+#define RAP_SERVER_INFO_L2 "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz"
+#define RAP_SERVER_INFO_L3 "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWzDWz"
+#define RAP_SERVICE_INFO_L0 "B16"
+#define RAP_SERVICE_INFO_L2 "B16WDWB64"
+#define RAP_SHARE_INFO_L0 "B13"
+#define RAP_SHARE_INFO_L1 "B13BWz"
+#define RAP_SHARE_INFO_L2 "B13BWzWWWzB9B"
+
+#define RAP_PRINTQ_INFO_L2 "B13BWWWzzzzzWN"
+#define RAP_SMB_PRINT_JOB_L1 "WB21BB16B10zWWzDDz"
+
+#define RAP_SESSION_INFO_L2 "zzWWWDDDz"
+#define RAP_CONNECTION_INFO_L1 "WWWWDzz"
+
+#define RAP_USER_LOGOFF_INFO_L1 "WDW"
+
+#define RAP_WKSTA_INFO_L1 "WDzzzzBBDWDWWWWWWWWWWWWWWWWWWWzzWzzW"
+#define RAP_WKSTA_INFO_L10 "zzzBBzz"
+
+/* BB explicit packing would help in structs below */
+
+/* sizes of fixed-length fields, including null terminator */
+#define RAP_GROUPNAME_LEN 21
+#define RAP_USERNAME_LEN 21
+#define RAP_SHARENAME_LEN 13
+#define RAP_UPASSWD_LEN 16 /* user password */
+#define RAP_SPASSWD_LEN 9 /* share password */
+#define RAP_MACHNAME_LEN 16
+#define RAP_SRVCNAME_LEN 16
+#define RAP_SRVCCMNT_LEN 64
+#define RAP_DATATYPE_LEN 10
+
+
+typedef struct rap_group_info_1
+{
+ char group_name[RAP_GROUPNAME_LEN];
+ char reserved1;
+ char * comment;
+} RAP_GROUP_INFO_1;
+
+typedef struct rap_user_info_1
+{
+ char user_name[RAP_USERNAME_LEN];
+ char reserved1;
+ char passwrd[RAP_UPASSWD_LEN];
+ uint32 pwage;
+ uint16 priv;
+ char * home_dir;
+ char * comment;
+ uint16 userflags;
+ char * logon_script;
+} RAP_USER_INFO_1;
+
+typedef struct rap_service_info_2
+{
+ char service_name[RAP_SRVCNAME_LEN];
+ uint16 status;
+ uint32 installcode;
+ uint16 process_num;
+ char * comment;
+} RAP_SERVICE_INFO_2;
+
+
+typedef struct rap_share_info_0
+{
+ char share_name[RAP_SHARENAME_LEN];
+} RAP_SHARE_INFO_0;
+
+typedef struct rap_share_info_1
+{
+ char share_name[RAP_SHARENAME_LEN];
+ char reserved1;
+ uint16 share_type;
+ char * comment;
+} RAP_SHARE_INFO_1;
+
+typedef struct rap_share_info_2
+{
+ char share_name[RAP_SHARENAME_LEN];
+ char reserved1;
+ uint16 share_type;
+ char * comment;
+ uint16 perms;
+ uint16 maximum_users;
+ uint16 active_users;
+ char * path;
+ char password[RAP_SPASSWD_LEN];
+ char reserved2;
+} RAP_SHARE_INFO_2;
+
+#endif /* _RAP_H_ */
diff --git a/source/include/rpc_brs.h b/source/include/rpc_brs.h
new file mode 100644
index 00000000000..99ba8f2dd07
--- /dev/null
+++ b/source/include/rpc_brs.h
@@ -0,0 +1,81 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_BRS_H /* _RPC_BRS_H */
+#define _RPC_BRS_H
+
+
+/* brssvc pipe */
+#define BRS_QUERY_INFO 0x02
+
+
+/* BRS_Q_QUERY_INFO - probably a capabilities request */
+typedef struct q_brs_query_info_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* unicode server name starting with '\\' */
+
+ uint16 switch_value1; /* info level 100 (0x64) */
+ /* align */
+ uint16 switch_value2; /* info level 100 (0x64) */
+
+ uint32 ptr;
+ uint32 pad1;
+ uint32 pad2;
+
+} BRS_Q_QUERY_INFO;
+
+
+/* BRS_INFO_100 - level 100 info */
+typedef struct brs_info_100_info
+{
+ uint32 pad1;
+ uint32 ptr2;
+ uint32 pad2;
+ uint32 pad3;
+
+} BRS_INFO_100;
+
+
+/* BRS_R_QUERY_INFO - probably a capabilities request */
+typedef struct r_brs_query_info_info
+{
+ uint16 switch_value1; /* 100 (0x64) - switch value */
+ /* align */
+ uint16 switch_value2; /* info level 100 (0x64) */
+
+ /* for now, only level 100 is supported. this should be an enum container */
+ uint32 ptr_1; /* pointer 1 */
+
+ union
+ {
+ BRS_INFO_100 *brs100; /* browser info level 100 */
+ void *id;
+
+ } info;
+
+ NTSTATUS status; /* return status */
+
+} BRS_R_QUERY_INFO;
+
+#endif /* _RPC_BRS_H */
+
diff --git a/source/include/rpc_client.h b/source/include/rpc_client.h
new file mode 100644
index 00000000000..270545c2a3f
--- /dev/null
+++ b/source/include/rpc_client.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Elrond 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_CLIENT_H
+#define _RPC_CLIENT_H
+
+#if 0 /* JERRY */
+#include "rpc_client_proto.h"
+#endif
+
+#endif /* _RPC_CLIENT_H */
diff --git a/source/include/rpc_creds.h b/source/include/rpc_creds.h
new file mode 100644
index 00000000000..0ab508ffe70
--- /dev/null
+++ b/source/include/rpc_creds.h
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _RPC_CREDS_H /* _RPC_CREDS_H */
+#define _RPC_CREDS_H
+
+typedef struct ntuser_creds
+{
+ fstring user_name;
+ fstring domain;
+ struct pwd_info pwd;
+
+ uint32 ntlmssp_flags;
+
+} CREDS_NT;
+
+typedef struct unixuser_creds
+{
+ fstring user_name;
+ fstring requested_name;
+ fstring real_name;
+ BOOL guest;
+
+} CREDS_UNIX;
+
+typedef struct unixsec_creds
+{
+ uint32 uid;
+ uint32 gid;
+ int num_grps;
+ uint32 *grps;
+
+} CREDS_UNIX_SEC;
+
+typedef struct ntsec_creds
+{
+ DOM_SID sid;
+ uint32 num_grps;
+ uint32 *grp_rids;
+
+} CREDS_NT_SEC;
+
+typedef struct user_creds
+{
+ BOOL reuse;
+
+ uint32 ptr_ntc;
+ uint32 ptr_uxc;
+ uint32 ptr_nts;
+ uint32 ptr_uxs;
+ uint32 ptr_ssk;
+
+ CREDS_NT ntc;
+ CREDS_UNIX uxc;
+
+ CREDS_NT_SEC nts;
+ CREDS_UNIX_SEC uxs;
+
+ uchar usr_sess_key[16];
+
+} CREDS_HYBRID;
+
+typedef struct cred_command
+{
+ uint16 version;
+ uint16 command;
+ uint32 pid; /* unique process id */
+
+ fstring name;
+
+ uint32 ptr_creds;
+ CREDS_HYBRID *cred;
+
+} CREDS_CMD;
+
+#endif /* _RPC_CREDS_H */
+
diff --git a/source/include/rpc_dce.h b/source/include/rpc_dce.h
new file mode 100644
index 00000000000..f9ebaae0b81
--- /dev/null
+++ b/source/include/rpc_dce.h
@@ -0,0 +1,345 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DCE_RPC_H /* _DCE_RPC_H */
+#define _DCE_RPC_H
+
+#include "rpc_misc.h" /* this only pulls in STRHDR */
+
+
+/* DCE/RPC packet types */
+
+enum RPC_PKT_TYPE
+{
+ RPC_REQUEST = 0x00,
+ RPC_RESPONSE = 0x02,
+ RPC_FAULT = 0x03,
+ RPC_BIND = 0x0B,
+ RPC_BINDACK = 0x0C,
+ RPC_BINDNACK = 0x0D,
+ RPC_ALTCONT = 0x0E,
+ RPC_ALTCONTRESP = 0x0F,
+ RPC_BINDRESP = 0x10 /* not the real name! this is undocumented! */
+};
+
+/* DCE/RPC flags */
+#define RPC_FLG_FIRST 0x01
+#define RPC_FLG_LAST 0x02
+#define RPC_FLG_NOCALL 0x20
+
+/* NTLMSSP message types */
+enum NTLM_MESSAGE_TYPE
+{
+ NTLMSSP_NEGOTIATE = 1,
+ NTLMSSP_CHALLENGE = 2,
+ NTLMSSP_AUTH = 3,
+ NTLMSSP_UNKNOWN = 4
+};
+
+/* NTLMSSP negotiation flags */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
+#define NTLMSSP_NEGOTIATE_OEM 0x00000002
+#define NTLMSSP_REQUEST_TARGET 0x00000004
+#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
+#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
+#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
+#define NTLMSSP_NEGOTIATE_00001000 0x00001000
+#define NTLMSSP_NEGOTIATE_00002000 0x00002000
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
+#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
+#define NTLMSSP_NEGOTIATE_128 0x20000000
+#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000
+
+#define SMBD_NTLMSSP_NEG_FLAGS 0x000082b1
+
+/* NTLMSSP signature version */
+#define NTLMSSP_SIGN_VERSION 0x01
+
+/* NTLMSSP auth type and level. */
+#define NTLMSSP_AUTH_TYPE 0xa
+#define NTLMSSP_AUTH_LEVEL 0x6
+
+/* Maximum PDU fragment size. */
+#define MAX_PDU_FRAG_LEN 0x1630
+
+/*
+ * Actual structure of a DCE UUID
+ */
+
+typedef struct rpc_uuid
+{
+ uint32 time_low;
+ uint16 time_mid;
+ uint16 time_hi_and_version;
+ uint8 remaining[8];
+} RPC_UUID;
+
+#define RPC_UUID_LEN 16
+
+/* RPC_IFACE */
+typedef struct rpc_iface_info
+{
+ RPC_UUID uuid; /* 16 bytes of rpc interface identification */
+ uint32 version; /* the interface version number */
+
+} RPC_IFACE;
+
+#define RPC_IFACE_LEN (RPC_UUID_LEN + 4)
+
+struct pipe_id_info
+{
+ /* the names appear not to matter: the syntaxes _do_ matter */
+
+ char *client_pipe;
+ RPC_IFACE abstr_syntax; /* this one is the abstract syntax id */
+
+ char *server_pipe; /* this one is the secondary syntax name */
+ RPC_IFACE trans_syntax; /* this one is the primary syntax id */
+};
+
+/* RPC_HDR - dce rpc header */
+typedef struct rpc_hdr_info
+{
+ uint8 major; /* 5 - RPC major version */
+ uint8 minor; /* 0 - RPC minor version */
+ uint8 pkt_type; /* RPC_PKT_TYPE - RPC response packet */
+ uint8 flags; /* DCE/RPC flags */
+ uint8 pack_type[4]; /* 0x1000 0000 - little-endian packed data representation */
+ uint16 frag_len; /* fragment length - data size (bytes) inc header and tail. */
+ uint16 auth_len; /* 0 - authentication length */
+ uint32 call_id; /* call identifier. matches 12th uint32 of incoming RPC data. */
+
+} RPC_HDR;
+
+#define RPC_HEADER_LEN 16
+
+/* RPC_HDR_REQ - ms request rpc header */
+typedef struct rpc_hdr_req_info
+{
+ uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */
+ uint16 context_id; /* 0 - presentation context identifier */
+ uint16 opnum; /* opnum */
+
+} RPC_HDR_REQ;
+
+#define RPC_HDR_REQ_LEN 8
+
+/* RPC_HDR_RESP - ms response rpc header */
+typedef struct rpc_hdr_resp_info
+{
+ uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */
+ uint16 context_id; /* 0 - presentation context identifier */
+ uint8 cancel_count; /* 0 - cancel count */
+ uint8 reserved; /* 0 - reserved. */
+
+} RPC_HDR_RESP;
+
+#define RPC_HDR_RESP_LEN 8
+
+/* RPC_HDR_FAULT - fault rpc header */
+typedef struct rpc_hdr_fault_info
+{
+ NTSTATUS status;
+ uint32 reserved; /* 0x0000 0000 */
+} RPC_HDR_FAULT;
+
+#define RPC_HDR_FAULT_LEN 8
+
+/* this seems to be the same string name depending on the name of the pipe,
+ * but is more likely to be linked to the interface name
+ * "srvsvc", "\\PIPE\\ntsvcs"
+ * "samr", "\\PIPE\\lsass"
+ * "wkssvc", "\\PIPE\\wksvcs"
+ * "NETLOGON", "\\PIPE\\NETLOGON"
+ */
+/* RPC_ADDR_STR */
+typedef struct rpc_addr_info
+{
+ uint16 len; /* length of the string including null terminator */
+ fstring str; /* the string above in single byte, null terminated form */
+
+} RPC_ADDR_STR;
+
+/* RPC_HDR_BBA */
+typedef struct rpc_hdr_bba_info
+{
+ uint16 max_tsize; /* maximum transmission fragment size (0x1630) */
+ uint16 max_rsize; /* max receive fragment size (0x1630) */
+ uint32 assoc_gid; /* associated group id (0x0) */
+
+} RPC_HDR_BBA;
+
+#define RPC_HDR_BBA_LEN 8
+
+/* RPC_HDR_AUTHA */
+typedef struct rpc_hdr_autha_info
+{
+ uint16 max_tsize; /* maximum transmission fragment size (0x1630) */
+ uint16 max_rsize; /* max receive fragment size (0x1630) */
+
+ uint8 auth_type; /* 0x0a */
+ uint8 auth_level; /* 0x06 */
+ uint8 stub_type_len; /* don't know */
+ uint8 padding; /* padding */
+
+ uint32 unknown; /* 0x0014a0c0 */
+
+} RPC_HDR_AUTHA;
+
+#define RPC_HDR_AUTHA_LEN 12
+
+/* RPC_HDR_AUTH */
+typedef struct rpc_hdr_auth_info
+{
+ uint8 auth_type; /* 0x0a */
+ uint8 auth_level; /* 0x06 */
+ uint8 stub_type_len; /* don't know */
+ uint8 padding; /* padding */
+
+ uint32 unknown; /* pointer */
+
+} RPC_HDR_AUTH;
+
+#define RPC_HDR_AUTH_LEN 8
+
+/* RPC_BIND_REQ - ms req bind */
+typedef struct rpc_bind_req_info
+{
+ RPC_HDR_BBA bba;
+
+ uint32 num_elements; /* the number of elements (0x1) */
+ uint16 context_id; /* presentation context identifier (0x0) */
+ uint8 num_syntaxes; /* the number of syntaxes (has always been 1?)(0x1) */
+
+ RPC_IFACE abstract; /* num and vers. of interface client is using */
+ RPC_IFACE transfer; /* num and vers. of interface to use for replies */
+
+} RPC_HDR_RB;
+
+/*
+ * The following length is 8 bytes RPC_HDR_BBA_LEN, 8 bytes internals
+ * (with 3 bytes padding), + 2 x RPC_IFACE_LEN bytes for RPC_IFACE structs.
+ */
+
+#define RPC_HDR_RB_LEN (RPC_HDR_BBA_LEN + 8 + (2*RPC_IFACE_LEN))
+
+/* RPC_RESULTS - can only cope with one reason, right now... */
+typedef struct rpc_results_info
+{
+/* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint8 num_results; /* the number of results (0x01) */
+
+/* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint16 result; /* result (0x00 = accept) */
+ uint16 reason; /* reason (0x00 = no reason specified) */
+
+} RPC_RESULTS;
+
+/* RPC_HDR_BA */
+typedef struct rpc_hdr_ba_info
+{
+ RPC_HDR_BBA bba;
+
+ RPC_ADDR_STR addr ; /* the secondary address string, as described earlier */
+ RPC_RESULTS res ; /* results and reasons */
+ RPC_IFACE transfer; /* the transfer syntax from the request */
+
+} RPC_HDR_BA;
+
+/* RPC_AUTH_VERIFIER */
+typedef struct rpc_auth_verif_info
+{
+ fstring signature; /* "NTLMSSP" */
+ uint32 msg_type; /* NTLMSSP_MESSAGE_TYPE (1,2,3) */
+
+} RPC_AUTH_VERIFIER;
+
+/* this is TEMPORARILY coded up as a specific structure */
+/* this structure comes after the bind request */
+/* RPC_AUTH_NTLMSSP_NEG */
+typedef struct rpc_auth_ntlmssp_neg_info
+{
+ uint32 neg_flgs; /* 0x0000 b2b3 */
+
+ STRHDR hdr_myname; /* offset is against START of this structure */
+ STRHDR hdr_domain; /* offset is against START of this structure */
+
+ fstring myname; /* calling workstation's name */
+ fstring domain; /* calling workstations's domain */
+
+} RPC_AUTH_NTLMSSP_NEG;
+
+/* this is TEMPORARILY coded up as a specific structure */
+/* this structure comes after the bind acknowledgement */
+/* RPC_AUTH_NTLMSSP_CHAL */
+typedef struct rpc_auth_ntlmssp_chal_info
+{
+ uint32 unknown_1; /* 0x0000 0000 */
+ uint32 unknown_2; /* 0x0000 0028 */
+ uint32 neg_flags; /* 0x0000 82b1 */
+
+ uint8 challenge[8]; /* ntlm challenge */
+ uint8 reserved [8]; /* zeros */
+
+} RPC_AUTH_NTLMSSP_CHAL;
+
+
+/* RPC_AUTH_NTLMSSP_RESP */
+typedef struct rpc_auth_ntlmssp_resp_info
+{
+ STRHDR hdr_lm_resp; /* 24 byte response */
+ STRHDR hdr_nt_resp; /* 24 byte response */
+ STRHDR hdr_domain;
+ STRHDR hdr_usr;
+ STRHDR hdr_wks;
+ STRHDR hdr_sess_key; /* NULL unless negotiated */
+ uint32 neg_flags; /* 0x0000 82b1 */
+
+ fstring sess_key;
+ fstring wks;
+ fstring user;
+ fstring domain;
+ fstring nt_resp;
+ fstring lm_resp;
+
+} RPC_AUTH_NTLMSSP_RESP;
+
+/* attached to the end of encrypted rpc requests and responses */
+/* RPC_AUTH_NTLMSSP_CHK */
+typedef struct rpc_auth_ntlmssp_chk_info
+{
+ uint32 ver; /* 0x0000 0001 */
+ uint32 reserved;
+ uint32 crc32; /* checksum using 0xEDB8 8320 as a polynomial */
+ uint32 seq_num;
+
+} RPC_AUTH_NTLMSSP_CHK;
+
+#define RPC_AUTH_NTLMSSP_CHK_LEN 16
+
+
+#endif /* _DCE_RPC_H */
diff --git a/source/include/rpc_dfs.h b/source/include/rpc_dfs.h
new file mode 100644
index 00000000000..5222d6b3565
--- /dev/null
+++ b/source/include/rpc_dfs.h
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 2000
+ Copyright (C) Shirish Kalele 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_DFS_H
+#define _RPC_DFS_H
+
+/* NETDFS pipe: calls */
+#define DFS_EXIST 0x00
+#define DFS_ADD 0x01
+#define DFS_REMOVE 0x02
+#define DFS_GET_INFO 0x04
+#define DFS_ENUM 0x05
+
+/* dfsadd flags */
+#define DFSFLAG_ADD_VOLUME 0x00000001
+#define DFSFLAG_RESTORE_VOLUME 0x00000002
+
+typedef struct dfs_q_dfs_exist
+{
+ uint32 dummy;
+}
+DFS_Q_DFS_EXIST;
+
+/* status == 1 if dfs exists. */
+typedef struct dfs_r_dfs_exist
+{
+ uint32 status; /* Not a WERROR or NTSTATUS code */
+}
+DFS_R_DFS_EXIST;
+
+typedef struct dfs_q_dfs_add
+{
+ uint32 ptr_DfsEntryPath;
+ UNISTR2 DfsEntryPath;
+ uint32 ptr_ServerName;
+ UNISTR2 ServerName;
+ uint32 ptr_ShareName;
+ UNISTR2 ShareName;
+ uint32 ptr_Comment;
+ UNISTR2 Comment;
+ uint32 Flags;
+}
+DFS_Q_DFS_ADD;
+
+typedef struct dfs_r_dfs_add
+{
+ WERROR status;
+}
+DFS_R_DFS_ADD;
+
+/********************************************/
+typedef struct dfs_q_dfs_remove
+{
+ UNISTR2 DfsEntryPath;
+ uint32 ptr_ServerName;
+ UNISTR2 ServerName;
+ uint32 ptr_ShareName;
+ UNISTR2 ShareName;
+}
+DFS_Q_DFS_REMOVE;
+
+typedef struct dfs_r_dfs_remove
+{
+ WERROR status;
+}
+DFS_R_DFS_REMOVE;
+
+/********************************************/
+typedef struct dfs_info_1
+{
+ uint32 ptr_entrypath;
+ UNISTR2 entrypath;
+}
+DFS_INFO_1;
+
+typedef struct dfs_info_2
+{
+ uint32 ptr_entrypath;
+ UNISTR2 entrypath;
+ uint32 ptr_comment;
+ UNISTR2 comment;
+ uint32 state;
+ uint32 num_storages;
+}
+DFS_INFO_2;
+
+typedef struct dfs_storage_info
+{
+ uint32 state;
+ uint32 ptr_servername;
+ UNISTR2 servername;
+ uint32 ptr_sharename;
+ UNISTR2 sharename;
+}
+DFS_STORAGE_INFO;
+
+typedef struct dfs_info_3
+{
+ uint32 ptr_entrypath;
+ UNISTR2 entrypath;
+ uint32 ptr_comment;
+ UNISTR2 comment;
+ uint32 state;
+ uint32 num_storages;
+ uint32 ptr_storages;
+ uint32 num_storage_infos;
+ DFS_STORAGE_INFO* storages;
+}
+DFS_INFO_3;
+
+typedef struct dfs_info_ctr
+{
+
+ uint32 switch_value;
+ uint32 num_entries;
+ uint32 ptr_dfs_ctr; /* pointer to dfs info union */
+ union
+ {
+ DFS_INFO_1 *info1;
+ DFS_INFO_2 *info2;
+ DFS_INFO_3 *info3;
+ } dfs;
+}
+DFS_INFO_CTR;
+
+typedef struct dfs_q_dfs_get_info
+{
+ UNISTR2 uni_path;
+
+ uint32 ptr_server;
+ UNISTR2 uni_server;
+
+ uint32 ptr_share;
+ UNISTR2 uni_share;
+
+ uint32 level;
+}
+DFS_Q_DFS_GET_INFO;
+
+typedef struct dfs_r_dfs_get_info
+{
+ uint32 level;
+ uint32 ptr_ctr;
+ DFS_INFO_CTR ctr;
+ WERROR status;
+}
+DFS_R_DFS_GET_INFO;
+
+typedef struct dfs_q_dfs_enum
+{
+ uint32 level;
+ uint32 maxpreflen;
+ uint32 ptr_buffer;
+ uint32 level2;
+ uint32 ptr_num_entries;
+ uint32 num_entries;
+ uint32 ptr_num_entries2;
+ uint32 num_entries2;
+ ENUM_HND reshnd;
+}
+DFS_Q_DFS_ENUM;
+
+typedef struct dfs_r_dfs_enum
+{
+ DFS_INFO_CTR *ctr;
+ uint32 ptr_buffer;
+ uint32 level;
+ uint32 level2;
+ uint32 ptr_num_entries;
+ uint32 num_entries;
+ uint32 ptr_num_entries2;
+ uint32 num_entries2;
+ ENUM_HND reshnd;
+ WERROR status;
+}
+DFS_R_DFS_ENUM;
+
+#endif
diff --git a/source/include/rpc_lsa.h b/source/include/rpc_lsa.h
new file mode 100644
index 00000000000..4f72aa13161
--- /dev/null
+++ b/source/include/rpc_lsa.h
@@ -0,0 +1,675 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_LSA_H /* _RPC_LSA_H */
+#define _RPC_LSA_H
+
+#include "rpc_misc.h"
+
+enum SID_NAME_USE
+{
+ SID_NAME_USE_NONE = 0,/* NOTUSED */
+ SID_NAME_USER = 1, /* user */
+ SID_NAME_DOM_GRP = 2, /* domain group */
+ SID_NAME_DOMAIN = 3, /* domain: don't know what this is */
+ SID_NAME_ALIAS = 4, /* local group */
+ SID_NAME_WKN_GRP = 5, /* well-known group */
+ SID_NAME_DELETED = 6, /* deleted account: needed for c2 rating */
+ SID_NAME_INVALID = 7, /* invalid account */
+ SID_NAME_UNKNOWN = 8 /* oops. */
+};
+
+/* Opcodes available on this pipe */
+
+#define LSA_CLOSE 0x00
+#define LSA_DELETE 0x01
+#define LSA_ENUM_PRIVS 0x02
+#define LSA_QUERYSECOBJ 0x03
+#define LSA_SETSECOBJ 0x04
+#define LSA_CHANGEPASSWORD 0x05
+#define LSA_OPENPOLICY 0x06
+#define LSA_QUERYINFOPOLICY 0x07
+#define LSA_SETINFOPOLICY 0x08
+#define LSA_CLEARAUDITLOG 0x09
+#define LSA_CREATEACCOUNT 0x0a
+#define LSA_ENUM_ACCOUNTS 0x0b
+#define LSA_CREATETRUSTDOM 0x0c
+#define LSA_ENUMTRUSTDOM 0x0d
+#define LSA_LOOKUPNAMES 0x0e
+#define LSA_LOOKUPSIDS 0x0f
+#define LSA_CREATESECRET 0x10
+#define LSA_OPENACCOUNT 0x11
+#define LSA_ENUMPRIVSACCOUNT 0x12
+#define LSA_ADDPRIVS 0x13
+#define LSA_REMOVEPRIVS 0x14
+#define LSA_GETQUOTAS 0x15
+#define LSA_SETQUOTAS 0x16
+#define LSA_GETSYSTEMACCOUNT 0x17
+#define LSA_SETSYSTEMACCOUNT 0x18
+#define LSA_OPENTRUSTDOM 0x19
+#define LSA_QUERYTRUSTDOM 0x1a
+#define LSA_SETINFOTRUSTDOM 0x1b
+#define LSA_OPENSECRET 0x1c
+#define LSA_SETSECRET 0x1d
+#define LSA_QUERYSECRET 0x1e
+#define LSA_LOOKUPPRIVVALUE 0x1f
+#define LSA_LOOKUPPRIVNAME 0x20
+#define LSA_PRIV_GET_DISPNAME 0x21
+#define LSA_DELETEOBJECT 0x22
+#define LSA_ENUMACCTWITHRIGHT 0x23
+#define LSA_ENUMACCTRIGHTS 0x24
+#define LSA_ADDACCTRIGHTS 0x25
+#define LSA_REMOVEACCTRIGHTS 0x26
+#define LSA_QUERYTRUSTDOMINFO 0x27
+#define LSA_SETTRUSTDOMINFO 0x28
+#define LSA_DELETETRUSTDOM 0x29
+#define LSA_STOREPRIVDATA 0x2a
+#define LSA_RETRPRIVDATA 0x2b
+#define LSA_OPENPOLICY2 0x2c
+#define LSA_UNK_GET_CONNUSER 0x2d /* LsaGetConnectedCredentials ? */
+
+/* XXXX these are here to get a compile! */
+#define LSA_LOOKUPRIDS 0xFD
+
+#define LSA_MAX_GROUPS 96
+#define LSA_MAX_SIDS 128
+
+/* DOM_QUERY - info class 3 and 5 LSA Query response */
+typedef struct dom_query_info
+{
+ uint16 uni_dom_max_len; /* domain name string length * 2 */
+ uint16 uni_dom_str_len; /* domain name string length * 2 */
+ uint32 buffer_dom_name; /* undocumented domain name string buffer pointer */
+ uint32 buffer_dom_sid; /* undocumented domain SID string buffer pointer */
+ UNISTR2 uni_domain_name; /* domain name (unicode string) */
+ DOM_SID2 dom_sid; /* domain SID */
+
+} DOM_QUERY;
+
+/* level 5 is same as level 3. we hope. */
+typedef DOM_QUERY DOM_QUERY_3;
+typedef DOM_QUERY DOM_QUERY_5;
+
+/* level 2 is auditing settings */
+typedef struct dom_query_2
+{
+ uint32 auditing_enabled;
+ uint32 count1; /* usualy 7, at least on nt4sp4 */
+ uint32 count2; /* the same */
+ uint32 *auditsettings;
+} DOM_QUERY_2;
+
+/* level 6 is server role information */
+typedef struct dom_query_6
+{
+ uint16 server_role; /* 2=backup, 3=primary */
+} DOM_QUERY_6;
+
+typedef struct seq_qos_info
+{
+ uint32 len; /* 12 */
+ uint16 sec_imp_level; /* 0x02 - impersonation level */
+ uint8 sec_ctxt_mode; /* 0x01 - context tracking mode */
+ uint8 effective_only; /* 0x00 - effective only */
+
+} LSA_SEC_QOS;
+
+typedef struct obj_attr_info
+{
+ uint32 len; /* 0x18 - length (in bytes) inc. the length field. */
+ uint32 ptr_root_dir; /* 0 - root directory (pointer) */
+ uint32 ptr_obj_name; /* 0 - object name (pointer) */
+ uint32 attributes; /* 0 - attributes (undocumented) */
+ uint32 ptr_sec_desc; /* 0 - security descriptior (pointer) */
+ uint32 ptr_sec_qos; /* security quality of service */
+ LSA_SEC_QOS *sec_qos;
+
+} LSA_OBJ_ATTR;
+
+/* LSA_Q_OPEN_POL - LSA Query Open Policy */
+typedef struct lsa_q_open_pol_info
+{
+ uint32 ptr; /* undocumented buffer pointer */
+ uint16 system_name; /* 0x5c - system name */
+ LSA_OBJ_ATTR attr ; /* object attributes */
+
+ uint32 des_access; /* desired access attributes */
+
+} LSA_Q_OPEN_POL;
+
+/* LSA_R_OPEN_POL - response to LSA Open Policy */
+typedef struct lsa_r_open_pol_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return code */
+
+} LSA_R_OPEN_POL;
+
+/* LSA_Q_OPEN_POL2 - LSA Query Open Policy */
+typedef struct lsa_q_open_pol2_info
+{
+ uint32 ptr; /* undocumented buffer pointer */
+ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+ LSA_OBJ_ATTR attr ; /* object attributes */
+
+ uint32 des_access; /* desired access attributes */
+
+} LSA_Q_OPEN_POL2;
+
+/* LSA_R_OPEN_POL2 - response to LSA Open Policy */
+typedef struct lsa_r_open_pol2_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return code */
+
+} LSA_R_OPEN_POL2;
+
+
+#define POLICY_VIEW_LOCAL_INFORMATION 0x00000001
+#define POLICY_VIEW_AUDIT_INFORMATION 0x00000002
+#define POLICY_GET_PRIVATE_INFORMATION 0x00000004
+#define POLICY_TRUST_ADMIN 0x00000008
+#define POLICY_CREATE_ACCOUNT 0x00000010
+#define POLICY_CREATE_SECRET 0x00000020
+#define POLICY_CREATE_PRIVILEGE 0x00000040
+#define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080
+#define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100
+#define POLICY_AUDIT_LOG_ADMIN 0x00000200
+#define POLICY_SERVER_ADMIN 0x00000400
+#define POLICY_LOOKUP_NAMES 0x00000800
+
+#define POLICY_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED_ACCESS |\
+ POLICY_VIEW_LOCAL_INFORMATION |\
+ POLICY_VIEW_AUDIT_INFORMATION |\
+ POLICY_GET_PRIVATE_INFORMATION |\
+ POLICY_TRUST_ADMIN |\
+ POLICY_CREATE_ACCOUNT |\
+ POLICY_CREATE_SECRET |\
+ POLICY_CREATE_PRIVILEGE |\
+ POLICY_SET_DEFAULT_QUOTA_LIMITS |\
+ POLICY_SET_AUDIT_REQUIREMENTS |\
+ POLICY_AUDIT_LOG_ADMIN |\
+ POLICY_SERVER_ADMIN |\
+ POLICY_LOOKUP_NAMES )
+
+
+#define POLICY_READ ( STANDARD_RIGHTS_READ_ACCESS |\
+ POLICY_VIEW_AUDIT_INFORMATION |\
+ POLICY_GET_PRIVATE_INFORMATION)
+
+#define POLICY_WRITE ( STANDARD_RIGHTS_WRITE_ACCESS |\
+ POLICY_TRUST_ADMIN |\
+ POLICY_CREATE_ACCOUNT |\
+ POLICY_CREATE_SECRET |\
+ POLICY_CREATE_PRIVILEGE |\
+ POLICY_SET_DEFAULT_QUOTA_LIMITS |\
+ POLICY_SET_AUDIT_REQUIREMENTS |\
+ POLICY_AUDIT_LOG_ADMIN |\
+ POLICY_SERVER_ADMIN)
+
+#define POLICY_EXECUTE ( STANDARD_RIGHTS_EXECUTE_ACCESS |\
+ POLICY_VIEW_LOCAL_INFORMATION |\
+ POLICY_LOOKUP_NAMES )
+
+/* LSA_Q_QUERY_SEC_OBJ - LSA query security */
+typedef struct lsa_query_sec_obj_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 sec_info;
+
+} LSA_Q_QUERY_SEC_OBJ;
+
+/* LSA_R_QUERY_SEC_OBJ - probably an open */
+typedef struct r_lsa_query_sec_obj_info
+{
+ uint32 ptr;
+ SEC_DESC_BUF *buf;
+
+ NTSTATUS status; /* return status */
+
+} LSA_R_QUERY_SEC_OBJ;
+
+/* LSA_Q_QUERY_INFO - LSA query info policy */
+typedef struct lsa_query_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint16 info_class; /* info class */
+
+} LSA_Q_QUERY_INFO;
+
+/* LSA_INFO_UNION */
+typedef union lsa_info_union
+{
+ DOM_QUERY_2 id2;
+ DOM_QUERY_3 id3;
+ DOM_QUERY_5 id5;
+ DOM_QUERY_6 id6;
+} LSA_INFO_UNION;
+
+/* LSA_R_QUERY_INFO - response to LSA query info policy */
+typedef struct lsa_r_query_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+ uint16 info_class; /* info class (same as info class in request) */
+
+ LSA_INFO_UNION dom;
+
+ NTSTATUS status; /* return code */
+
+} LSA_R_QUERY_INFO;
+
+/* LSA_Q_ENUM_TRUST_DOM - LSA enumerate trusted domains */
+typedef struct lsa_enum_trust_dom_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 enum_context; /* enumeration context handle */
+ uint32 preferred_len; /* preferred maximum length */
+
+} LSA_Q_ENUM_TRUST_DOM;
+
+/* LSA_R_ENUM_TRUST_DOM - response to LSA enumerate trusted domains */
+typedef struct lsa_r_enum_trust_dom_info
+{
+ uint32 enum_context; /* enumeration context handle */
+ uint32 num_domains; /* number of domains */
+ uint32 ptr_enum_domains; /* buffer pointer to num domains */
+
+ /* this lot is only added if ptr_enum_domains is non-NULL */
+ uint32 num_domains2; /* number of domains */
+ UNIHDR2 *hdr_domain_name;
+ UNISTR2 *uni_domain_name;
+ DOM_SID2 *domain_sid;
+
+ NTSTATUS status; /* return code */
+
+} LSA_R_ENUM_TRUST_DOM;
+
+/* LSA_Q_CLOSE */
+typedef struct lsa_q_close_info
+{
+ POLICY_HND pol; /* policy handle */
+
+} LSA_Q_CLOSE;
+
+/* LSA_R_CLOSE */
+typedef struct lsa_r_close_info
+{
+ POLICY_HND pol; /* policy handle. should be all zeros. */
+
+ NTSTATUS status; /* return code */
+
+} LSA_R_CLOSE;
+
+
+#define MAX_REF_DOMAINS 32
+
+/* DOM_TRUST_HDR */
+typedef struct dom_trust_hdr
+{
+ UNIHDR hdr_dom_name; /* referenced domain unicode string headers */
+ uint32 ptr_dom_sid;
+
+} DOM_TRUST_HDR;
+
+/* DOM_TRUST_INFO */
+typedef struct dom_trust_info
+{
+ UNISTR2 uni_dom_name; /* domain name unicode string */
+ DOM_SID2 ref_dom ; /* referenced domain SID */
+
+} DOM_TRUST_INFO;
+
+/* DOM_R_REF */
+typedef struct dom_ref_info
+{
+ uint32 num_ref_doms_1; /* num referenced domains */
+ uint32 ptr_ref_dom; /* pointer to referenced domains */
+ uint32 max_entries; /* 32 - max number of entries */
+ uint32 num_ref_doms_2; /* num referenced domains */
+
+ DOM_TRUST_HDR hdr_ref_dom[MAX_REF_DOMAINS]; /* referenced domains */
+ DOM_TRUST_INFO ref_dom [MAX_REF_DOMAINS]; /* referenced domains */
+
+} DOM_R_REF;
+
+/* the domain_idx points to a SID associated with the name */
+
+/* LSA_TRANS_NAME - translated name */
+typedef struct lsa_trans_name_info
+{
+ uint16 sid_name_use; /* value is 5 for a well-known group; 2 for a domain group; 1 for a user... */
+ UNIHDR hdr_name;
+ uint32 domain_idx; /* index into DOM_R_REF array of SIDs */
+
+} LSA_TRANS_NAME;
+
+#define MAX_LOOKUP_SIDS 30
+
+/* LSA_TRANS_NAME_ENUM - LSA Translated Name Enumeration container */
+typedef struct lsa_trans_name_enum_info
+{
+ uint32 num_entries;
+ uint32 ptr_trans_names;
+ uint32 num_entries2;
+
+ LSA_TRANS_NAME *name; /* translated names */
+ UNISTR2 *uni_name;
+
+} LSA_TRANS_NAME_ENUM;
+
+/* LSA_SID_ENUM - LSA SID enumeration container */
+typedef struct lsa_sid_enum_info
+{
+ uint32 num_entries;
+ uint32 ptr_sid_enum;
+ uint32 num_entries2;
+
+ uint32 *ptr_sid; /* domain SID pointers to be looked up. */
+ DOM_SID2 *sid; /* domain SIDs to be looked up. */
+
+} LSA_SID_ENUM;
+
+/* LSA_Q_LOOKUP_SIDS - LSA Lookup SIDs */
+typedef struct lsa_q_lookup_sids
+{
+ POLICY_HND pol; /* policy handle */
+ LSA_SID_ENUM sids;
+ LSA_TRANS_NAME_ENUM names;
+ LOOKUP_LEVEL level;
+ uint32 mapped_count;
+
+} LSA_Q_LOOKUP_SIDS;
+
+/* LSA_R_LOOKUP_SIDS - response to LSA Lookup SIDs */
+typedef struct lsa_r_lookup_sids
+{
+ uint32 ptr_dom_ref;
+ DOM_R_REF *dom_ref; /* domain reference info */
+
+ LSA_TRANS_NAME_ENUM *names;
+ uint32 mapped_count;
+
+ NTSTATUS status; /* return code */
+
+} LSA_R_LOOKUP_SIDS;
+
+/* LSA_Q_LOOKUP_NAMES - LSA Lookup NAMEs */
+typedef struct lsa_q_lookup_names
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 num_entries;
+ uint32 num_entries2;
+ UNIHDR *hdr_name; /* name buffer pointers */
+ UNISTR2 *uni_name; /* names to be looked up */
+
+ uint32 num_trans_entries;
+ uint32 ptr_trans_sids; /* undocumented domain SID buffer pointer */
+ uint32 lookup_level;
+ uint32 mapped_count;
+
+} LSA_Q_LOOKUP_NAMES;
+
+/* LSA_R_LOOKUP_NAMES - response to LSA Lookup NAMEs by name */
+typedef struct lsa_r_lookup_names
+{
+ uint32 ptr_dom_ref;
+ DOM_R_REF *dom_ref; /* domain reference info */
+
+ uint32 num_entries;
+ uint32 ptr_entries;
+ uint32 num_entries2;
+ DOM_RID2 *dom_rid; /* domain RIDs being looked up */
+
+ uint32 mapped_count;
+
+ NTSTATUS status; /* return code */
+} LSA_R_LOOKUP_NAMES;
+
+/* This is probably a policy handle but at the moment we
+ never read it - so use a dummy struct. */
+
+typedef struct lsa_q_open_secret
+{
+ uint32 dummy;
+} LSA_Q_OPEN_SECRET;
+
+/* We always return "not found" at present - so just marshal the minimum. */
+
+typedef struct lsa_r_open_secret
+{
+ uint32 dummy1;
+ uint32 dummy2;
+ uint32 dummy3;
+ uint32 dummy4;
+ NTSTATUS status;
+} LSA_R_OPEN_SECRET;
+
+typedef struct lsa_enum_priv_entry
+{
+ UNIHDR hdr_name;
+ uint32 luid_low;
+ uint32 luid_high;
+ UNISTR2 name;
+
+} LSA_PRIV_ENTRY;
+
+/* LSA_Q_ENUM_PRIVS - LSA enum privileges */
+typedef struct lsa_q_enum_privs
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 enum_context;
+ uint32 pref_max_length;
+} LSA_Q_ENUM_PRIVS;
+
+typedef struct lsa_r_enum_privs
+{
+ uint32 enum_context;
+ uint32 count;
+ uint32 ptr;
+ uint32 count1;
+
+ LSA_PRIV_ENTRY *privs;
+
+ NTSTATUS status;
+} LSA_R_ENUM_PRIVS;
+
+/* LSA_Q_PRIV_GET_DISPNAME - LSA get privilege display name */
+typedef struct lsa_q_priv_get_dispname
+{
+ POLICY_HND pol; /* policy handle */
+ UNIHDR hdr_name;
+ UNISTR2 name;
+ uint16 lang_id;
+ uint16 lang_id_sys;
+} LSA_Q_PRIV_GET_DISPNAME;
+
+typedef struct lsa_r_priv_get_dispname
+{
+ uint32 ptr_info;
+ UNIHDR hdr_desc;
+ UNISTR2 desc;
+ /* Don't align ! */
+ uint16 lang_id;
+ /* align */
+ NTSTATUS status;
+} LSA_R_PRIV_GET_DISPNAME;
+
+/* LSA_Q_ENUM_ACCOUNTS */
+typedef struct lsa_q_enum_accounts
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 enum_context;
+ uint32 pref_max_length;
+} LSA_Q_ENUM_ACCOUNTS;
+
+/* LSA_R_ENUM_ACCOUNTS */
+typedef struct lsa_r_enum_accounts
+{
+ uint32 enum_context;
+ LSA_SID_ENUM sids;
+ NTSTATUS status;
+} LSA_R_ENUM_ACCOUNTS;
+
+/* LSA_Q_UNK_GET_CONNUSER - gets username\domain of connected user
+ called when "Take Ownership" is clicked -SK */
+typedef struct lsa_q_unk_get_connuser
+{
+ uint32 ptr_srvname;
+ UNISTR2 uni2_srvname;
+ uint32 unk1; /* 3 unknown uint32's are seen right after uni2_srvname */
+ uint32 unk2; /* unk2 appears to be a ptr, unk1 = unk3 = 0 usually */
+ uint32 unk3;
+} LSA_Q_UNK_GET_CONNUSER;
+
+/* LSA_R_UNK_GET_CONNUSER */
+typedef struct lsa_r_unk_get_connuser
+{
+ uint32 ptr_user_name;
+ UNIHDR hdr_user_name;
+ UNISTR2 uni2_user_name;
+
+ uint32 unk1;
+
+ uint32 ptr_dom_name;
+ UNIHDR hdr_dom_name;
+ UNISTR2 uni2_dom_name;
+
+ NTSTATUS status;
+} LSA_R_UNK_GET_CONNUSER;
+
+
+typedef struct lsa_q_openaccount
+{
+ POLICY_HND pol; /* policy handle */
+ DOM_SID2 sid;
+ uint32 access; /* desired access */
+} LSA_Q_OPENACCOUNT;
+
+typedef struct lsa_r_openaccount
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status;
+} LSA_R_OPENACCOUNT;
+
+typedef struct lsa_q_enumprivsaccount
+{
+ POLICY_HND pol; /* policy handle */
+} LSA_Q_ENUMPRIVSACCOUNT;
+
+
+typedef struct LUID
+{
+ uint32 low;
+ uint32 high;
+} LUID;
+
+typedef struct LUID_ATTR
+{
+ LUID luid;
+ uint32 attr;
+} LUID_ATTR ;
+
+typedef struct privilege_set
+{
+ uint32 count;
+ uint32 control;
+ LUID_ATTR *set;
+} PRIVILEGE_SET;
+
+typedef struct lsa_r_enumprivsaccount
+{
+ uint32 ptr;
+ uint32 count;
+ PRIVILEGE_SET set;
+ NTSTATUS status;
+} LSA_R_ENUMPRIVSACCOUNT;
+
+typedef struct lsa_q_getsystemaccount
+{
+ POLICY_HND pol; /* policy handle */
+} LSA_Q_GETSYSTEMACCOUNT;
+
+typedef struct lsa_r_getsystemaccount
+{
+ uint32 access;
+ NTSTATUS status;
+} LSA_R_GETSYSTEMACCOUNT;
+
+
+typedef struct lsa_q_setsystemaccount
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 access;
+} LSA_Q_SETSYSTEMACCOUNT;
+
+typedef struct lsa_r_setsystemaccount
+{
+ NTSTATUS status;
+} LSA_R_SETSYSTEMACCOUNT;
+
+
+typedef struct lsa_q_lookupprivvalue
+{
+ POLICY_HND pol; /* policy handle */
+ UNIHDR hdr_right;
+ UNISTR2 uni2_right;
+} LSA_Q_LOOKUPPRIVVALUE;
+
+typedef struct lsa_r_lookupprivvalue
+{
+ LUID luid;
+ NTSTATUS status;
+} LSA_R_LOOKUPPRIVVALUE;
+
+
+typedef struct lsa_q_addprivs
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 count;
+ PRIVILEGE_SET set;
+} LSA_Q_ADDPRIVS;
+
+typedef struct lsa_r_addprivs
+{
+ NTSTATUS status;
+} LSA_R_ADDPRIVS;
+
+
+typedef struct lsa_q_removeprivs
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 allrights;
+ uint32 ptr;
+ uint32 count;
+ PRIVILEGE_SET set;
+} LSA_Q_REMOVEPRIVS;
+
+typedef struct lsa_r_removeprivs
+{
+ NTSTATUS status;
+} LSA_R_REMOVEPRIVS;
+
+
+#endif /* _RPC_LSA_H */
+
+
diff --git a/source/include/rpc_misc.h b/source/include/rpc_misc.h
new file mode 100644
index 00000000000..558c28459e3
--- /dev/null
+++ b/source/include/rpc_misc.h
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "ntdomain.h"
+#include "rpc_dce.h"
+
+#ifndef _RPC_MISC_H /* _RPC_MISC_H */
+#define _RPC_MISC_H
+
+
+
+/* well-known RIDs - Relative IDs */
+
+/* RIDs - Well-known users ... */
+#define DOMAIN_USER_RID_ADMIN (0x000001F4L)
+#define DOMAIN_USER_RID_GUEST (0x000001F5L)
+
+/* RIDs - well-known groups ... */
+#define DOMAIN_GROUP_RID_ADMINS (0x00000200L)
+#define DOMAIN_GROUP_RID_USERS (0x00000201L)
+#define DOMAIN_GROUP_RID_GUESTS (0x00000202L)
+
+/* RIDs - well-known aliases ... */
+#define BUILTIN_ALIAS_RID_ADMINS (0x00000220L)
+#define BUILTIN_ALIAS_RID_USERS (0x00000221L)
+#define BUILTIN_ALIAS_RID_GUESTS (0x00000222L)
+#define BUILTIN_ALIAS_RID_POWER_USERS (0x00000223L)
+
+#define BUILTIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L)
+#define BUILTIN_ALIAS_RID_SYSTEM_OPS (0x00000225L)
+#define BUILTIN_ALIAS_RID_PRINT_OPS (0x00000226L)
+#define BUILTIN_ALIAS_RID_BACKUP_OPS (0x00000227L)
+
+#define BUILTIN_ALIAS_RID_REPLICATOR (0x00000228L)
+
+/*
+ * Masks for mappings between unix uid and gid types and
+ * NT RIDS.
+ */
+
+/* Take the bottom bit. */
+#define RID_TYPE_MASK 1
+#define RID_MULTIPLIER 2
+
+/* The two common types. */
+#define USER_RID_TYPE 0
+#define GROUP_RID_TYPE 1
+
+/* ENUM_HND */
+typedef struct enum_hnd_info
+{
+ uint32 ptr_hnd; /* pointer to enumeration handle */
+ uint32 handle; /* enumeration handle */
+
+} ENUM_HND;
+
+/* LOOKUP_LEVEL - switch value */
+typedef struct lookup_level_info
+{
+ uint16 value;
+
+} LOOKUP_LEVEL;
+
+/* DOM_SID2 - security id */
+typedef struct sid_info_2
+{
+ uint32 num_auths; /* length, bytes, including length of len :-) */
+
+ DOM_SID sid;
+
+} DOM_SID2;
+
+/* STRHDR - string header */
+typedef struct header_info
+{
+ uint16 str_str_len;
+ uint16 str_max_len;
+ uint32 buffer; /* non-zero */
+
+} STRHDR;
+
+/* UNIHDR - unicode string header */
+typedef struct unihdr_info
+{
+ uint16 uni_str_len;
+ uint16 uni_max_len;
+ uint32 buffer; /* usually has a value of 4 */
+
+} UNIHDR;
+
+/* UNIHDR2 - unicode string header and undocumented buffer */
+typedef struct unihdr2_info
+{
+ UNIHDR unihdr;
+ uint32 buffer; /* 32 bit buffer pointer */
+
+} UNIHDR2;
+
+/* clueless as to what maximum length should be */
+#define MAX_UNISTRLEN 256
+#define MAX_STRINGLEN 256
+#define MAX_BUFFERLEN 512
+
+/* UNISTR - unicode string size and buffer */
+typedef struct unistr_info
+{
+ /* unicode characters. ***MUST*** be little-endian. ***MUST*** be null-terminated */
+ uint16 *buffer;
+} UNISTR;
+
+/* BUFHDR - buffer header */
+typedef struct bufhdr_info
+{
+ uint32 buf_max_len;
+ uint32 buf_len;
+
+} BUFHDR;
+
+/* BUFFER2 - unicode string, size (in uint8 ascii chars) and buffer */
+/* pathetic. some stupid team of \PIPE\winreg writers got the concept */
+/* of a unicode string different from the other \PIPE\ writers */
+typedef struct buffer2_info
+{
+ uint32 buf_max_len;
+ uint32 undoc;
+ uint32 buf_len;
+ /* unicode characters. ***MUST*** be little-endian. **NOT** necessarily null-terminated */
+ uint16 *buffer;
+
+} BUFFER2;
+
+/* BUFFER3 */
+typedef struct buffer3_info
+{
+ uint32 buf_max_len;
+ uint8 *buffer; /* Data */
+ uint32 buf_len;
+
+} BUFFER3;
+
+/* BUFFER5 */
+typedef struct buffer5_info
+{
+ uint32 buf_len;
+ uint16 *buffer; /* data */
+} BUFFER5;
+
+/* UNISTR2 - unicode string size (in uint16 unicode chars) and buffer */
+typedef struct unistr2_info
+{
+ uint32 uni_max_len;
+ uint32 undoc;
+ uint32 uni_str_len;
+ /* unicode characters. ***MUST*** be little-endian.
+ **must** be null-terminated and the uni_str_len should include
+ the NULL character */
+ uint16 *buffer;
+
+} UNISTR2;
+
+/* STRING2 - string size (in uint8 chars) and buffer */
+typedef struct string2_info
+{
+ uint32 str_max_len;
+ uint32 undoc;
+ uint32 str_str_len;
+ uint8 *buffer; /* uint8 characters. **NOT** necessarily null-terminated */
+
+} STRING2;
+
+/* UNISTR3 - XXXX not sure about this structure */
+typedef struct unistr3_info
+{
+ uint32 uni_str_len;
+ UNISTR str;
+
+} UNISTR3;
+
+
+/* DOM_RID2 - domain RID structure for ntlsa pipe */
+typedef struct domrid2_info
+{
+ uint8 type; /* value is SID_NAME_USE enum */
+ uint32 rid;
+ uint32 rid_idx; /* referenced domain index */
+
+} DOM_RID2;
+
+/* DOM_RID3 - domain RID structure for samr pipe */
+typedef struct domrid3_info
+{
+ uint32 rid; /* domain-relative (to a SID) id */
+ uint32 type1; /* value is 0x1 */
+ uint32 ptr_type; /* undocumented pointer */
+ uint32 type2; /* value is 0x1 */
+ uint32 unk; /* value is 0x2 */
+
+} DOM_RID3;
+
+/* DOM_RID4 - rid + user attributes */
+typedef struct domrid4_info
+{
+ uint32 unknown;
+ uint16 attr;
+ uint32 rid; /* user RID */
+
+} DOM_RID4;
+
+/* DOM_CLNT_SRV - client / server names */
+typedef struct clnt_srv_info
+{
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ uint32 undoc_buffer2; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_comp_name; /* client machine name */
+
+} DOM_CLNT_SRV;
+
+/* DOM_LOG_INFO - login info */
+typedef struct log_info
+{
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ UNISTR2 uni_acct_name; /* account name */
+ uint16 sec_chan; /* secure channel type */
+ UNISTR2 uni_comp_name; /* client machine name */
+
+} DOM_LOG_INFO;
+
+/* DOM_CHAL - challenge info */
+typedef struct chal_info
+{
+ uchar data[8]; /* credentials */
+} DOM_CHAL;
+
+/* DOM_CREDs - timestamped client or server credentials */
+typedef struct cred_info
+{
+ DOM_CHAL challenge; /* credentials */
+ UTIME timestamp; /* credential time-stamp */
+} DOM_CRED;
+
+/* DOM_CLNT_INFO - client info */
+typedef struct clnt_info
+{
+ DOM_LOG_INFO login;
+ DOM_CRED cred;
+
+} DOM_CLNT_INFO;
+
+/* DOM_CLNT_INFO2 - client info */
+typedef struct clnt_info2
+{
+ DOM_CLNT_SRV login;
+ uint32 ptr_cred;
+ DOM_CRED cred;
+
+} DOM_CLNT_INFO2;
+
+/* DOM_LOGON_ID - logon id */
+typedef struct logon_info
+{
+ uint32 low;
+ uint32 high;
+
+} DOM_LOGON_ID;
+
+/* OWF INFO */
+typedef struct owf_info
+{
+ uint8 data[16];
+
+} OWF_INFO;
+
+
+/* DOM_GID - group id + user attributes */
+typedef struct gid_info
+{
+ uint32 g_rid; /* a group RID */
+ uint32 attr;
+
+} DOM_GID;
+
+/* POLICY_HND */
+typedef struct lsa_policy_info
+{
+ uint32 data1;
+ uint32 data2;
+ uint16 data3;
+ uint16 data4;
+ uint8 data5[8];
+} POLICY_HND;
+
+/*
+ * A client connection's state, pipe name,
+ * user credentials, etc...
+ */
+typedef struct _cli_auth_fns cli_auth_fns;
+struct user_creds;
+struct cli_connection {
+
+ char *srv_name;
+ char *pipe_name;
+ struct user_creds usr_creds;
+
+ struct cli_state *pCli_state;
+
+ cli_auth_fns *auth;
+
+ void *auth_info;
+ void *auth_creds;
+};
+
+
+/*
+ * Associate a POLICY_HND with a cli_connection
+ */
+typedef struct rpc_hnd_node {
+
+ POLICY_HND hnd;
+ struct cli_connection *cli;
+
+} RPC_HND_NODE;
+
+typedef struct uint64_s
+{
+ uint32 low;
+ uint32 high;
+} UINT64_S;
+
+/* BUFHDR2 - another buffer header, with info level */
+typedef struct bufhdr2_info
+{
+ uint32 info_level;
+ uint32 length; /* uint8 chars */
+ uint32 buffer;
+
+}
+BUFHDR2;
+
+/* BUFFER4 - simple length and buffer */
+typedef struct buffer4_info
+{
+ uint32 buf_len;
+ uint8 buffer[MAX_BUFFERLEN];
+
+}
+BUFFER4;
+
+
+#endif /* _RPC_MISC_H */
diff --git a/source/include/rpc_netlogon.h b/source/include/rpc_netlogon.h
new file mode 100644
index 00000000000..e221db271f2
--- /dev/null
+++ b/source/include/rpc_netlogon.h
@@ -0,0 +1,906 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_NETLOGON_H /* _RPC_NETLOGON_H */
+#define _RPC_NETLOGON_H
+
+
+/* NETLOGON pipe */
+#define NET_SAMLOGON 0x02
+#define NET_SAMLOGOFF 0x03
+#define NET_REQCHAL 0x04
+#define NET_AUTH 0x05
+#define NET_SRVPWSET 0x06
+#define NET_SAM_DELTAS 0x07
+#define NET_LOGON_CTRL 0x0c
+#define NET_AUTH2 0x0f
+#define NET_LOGON_CTRL2 0x0e
+#define NET_SAM_SYNC 0x10
+#define NET_TRUST_DOM_LIST 0x13
+
+/* Secure Channel types. used in NetrServerAuthenticate negotiation */
+#define SEC_CHAN_WKSTA 2
+#define SEC_CHAN_DOMAIN 4
+#define SEC_CHAN_BDC 6
+
+/* Returned delta types */
+#define SAM_DELTA_DOMAIN_INFO 0x01 /* Domain */
+#define SAM_DELTA_GROUP_INFO 0x02 /* Domain groups */
+#define SAM_DELTA_ACCOUNT_INFO 0x05 /* Users */
+#define SAM_DELTA_GROUP_MEM 0x08 /* Group membership */
+#define SAM_DELTA_ALIAS_INFO 0x09 /* Local groups */
+#define SAM_DELTA_ALIAS_MEM 0x0C /* Local group membership */
+#define SAM_DELTA_DOM_INFO 0x0D /* Privilige stuff */
+#define SAM_DELTA_UNK0E_INFO 0x0e /* Privilige stuff */
+#define SAM_DELTA_PRIVS_INFO 0x10 /* Privilige stuff */
+#define SAM_DELTA_UNK12_INFO 0x12 /* Privilige stuff */
+#define SAM_DELTA_SAM_STAMP 0x16 /* Some kind of journal record? */
+
+/* SAM database types */
+#define SAM_DATABASE_DOMAIN 0x00 /* Domain users and groups */
+#define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */
+#define SAM_DATABASE_PRIVS 0x02 /* Priviliges? */
+
+#if 0
+/* I think this is correct - it's what gets parsed on the wire. JRA. */
+/* NET_USER_INFO_2 */
+typedef struct net_user_info_2
+{
+ uint32 ptr_user_info;
+
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* username unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home directory drive unicode string header */
+
+ uint16 logon_count; /* logon count */
+ uint16 bad_pw_count; /* bad password count */
+
+ uint32 user_id; /* User ID */
+ uint32 group_id; /* Group ID */
+ uint32 num_groups; /* num groups */
+ uint32 buffer_groups; /* undocumented buffer pointer to groups. */
+ uint32 user_flgs; /* user flags */
+
+ uint8 user_sess_key[16]; /* unused user session key */
+
+ UNIHDR hdr_logon_srv; /* logon server unicode string header */
+ UNIHDR hdr_logon_dom; /* logon domain unicode string header */
+
+ uint32 buffer_dom_id; /* undocumented logon domain id pointer */
+ uint8 padding[40]; /* unused padding bytes. expansion room */
+
+ UNISTR2 uni_user_name; /* username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+
+ uint32 num_groups2; /* num groups */
+ DOM_GID *gids; /* group info */
+
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_dom; /* logon domain unicode string */
+
+ DOM_SID2 dom_sid; /* domain SID */
+
+ uint32 num_other_groups; /* other groups */
+ DOM_GID *other_gids; /* group info */
+ DOM_SID2 *other_sids; /* undocumented - domain SIDs */
+
+} NET_USER_INFO_2;
+#endif
+
+/* NET_USER_INFO_3 */
+typedef struct net_user_info_3
+{
+ uint32 ptr_user_info;
+
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* username unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home directory drive unicode string header */
+
+ uint16 logon_count; /* logon count */
+ uint16 bad_pw_count; /* bad password count */
+
+ uint32 user_rid; /* User RID */
+ uint32 group_rid; /* Group RID */
+
+ uint32 num_groups; /* num groups */
+ uint32 buffer_groups; /* undocumented buffer pointer to groups. */
+ uint32 user_flgs; /* user flags */
+
+ uint8 user_sess_key[16]; /* unused user session key */
+
+ UNIHDR hdr_logon_srv; /* logon server unicode string header */
+ UNIHDR hdr_logon_dom; /* logon domain unicode string header */
+
+ uint32 buffer_dom_id; /* undocumented logon domain id pointer */
+ uint8 padding[40]; /* unused padding bytes. expansion room */
+
+ uint32 num_other_sids; /* 0 - num_sids */
+ uint32 buffer_other_sids; /* NULL - undocumented pointer to SIDs. */
+
+ UNISTR2 uni_user_name; /* username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+
+ uint32 num_groups2; /* num groups */
+ DOM_GID *gids; /* group info */
+
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_dom; /* logon domain unicode string */
+
+ DOM_SID2 dom_sid; /* domain SID */
+
+ uint32 num_other_groups; /* other groups */
+ DOM_GID *other_gids; /* group info */
+ DOM_SID2 *other_sids; /* undocumented - domain SIDs */
+
+} NET_USER_INFO_3;
+
+
+/* NETLOGON_INFO_1 - pdc status info, i presume */
+typedef struct netlogon_1_info
+{
+ uint32 flags; /* 0x0 - undocumented */
+ uint32 pdc_status; /* 0x0 - undocumented */
+
+} NETLOGON_INFO_1;
+
+/* NETLOGON_INFO_2 - pdc status info, plus trusted domain info */
+typedef struct netlogon_2_info
+{
+ uint32 flags; /* 0x0 - undocumented */
+ uint32 pdc_status; /* 0x0 - undocumented */
+ uint32 ptr_trusted_dc_name; /* pointer to trusted domain controller name */
+ uint32 tc_status; /* 0x051f - ERROR_NO_LOGON_SERVERS */
+ UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */
+
+} NETLOGON_INFO_2;
+
+/* NETLOGON_INFO_3 - logon status info, i presume */
+typedef struct netlogon_3_info
+{
+ uint32 flags; /* 0x0 - undocumented */
+ uint32 logon_attempts; /* number of logon attempts */
+ uint32 reserved_1; /* 0x0 - undocumented */
+ uint32 reserved_2; /* 0x0 - undocumented */
+ uint32 reserved_3; /* 0x0 - undocumented */
+ uint32 reserved_4; /* 0x0 - undocumented */
+ uint32 reserved_5; /* 0x0 - undocumented */
+
+} NETLOGON_INFO_3;
+
+/********************************************************
+ Logon Control Query
+
+ This is generated by a nltest /bdc_query:DOMAIN
+
+ query_level 0x1, function_code 0x1
+
+ ********************************************************/
+
+/* NET_Q_LOGON_CTRL - LSA Netr Logon Control */
+
+typedef struct net_q_logon_ctrl_info
+{
+ uint32 ptr;
+ UNISTR2 uni_server_name;
+ uint32 function_code;
+ uint32 query_level;
+} NET_Q_LOGON_CTRL;
+
+/* NET_R_LOGON_CTRL - LSA Netr Logon Control */
+
+typedef struct net_r_logon_ctrl_info
+{
+ uint32 switch_value;
+ uint32 ptr;
+
+ union {
+ NETLOGON_INFO_1 info1;
+ } logon;
+
+ NTSTATUS status;
+} NET_R_LOGON_CTRL;
+
+/********************************************************
+ Logon Control2 Query
+
+ query_level 0x1 - pdc status
+ query_level 0x3 - number of logon attempts.
+
+ ********************************************************/
+
+/* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */
+typedef struct net_q_logon_ctrl2_info
+{
+ uint32 ptr; /* undocumented buffer pointer */
+ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+
+ uint32 function_code; /* 0x1 */
+ uint32 query_level; /* 0x1, 0x3 */
+ uint32 switch_value; /* 0x1 */
+
+} NET_Q_LOGON_CTRL2;
+
+/*******************************************************
+ Logon Control Response
+
+ switch_value is same as query_level in request
+ *******************************************************/
+
+/* NET_R_LOGON_CTRL2 - response to LSA Logon Control2 */
+typedef struct net_r_logon_ctrl2_info
+{
+ uint32 switch_value; /* 0x1, 0x3 */
+ uint32 ptr;
+
+ union
+ {
+ NETLOGON_INFO_1 info1;
+ NETLOGON_INFO_2 info2;
+ NETLOGON_INFO_3 info3;
+
+ } logon;
+
+ NTSTATUS status; /* return code */
+
+} NET_R_LOGON_CTRL2;
+
+/* NET_Q_TRUST_DOM_LIST - LSA Query Trusted Domains */
+typedef struct net_q_trust_dom_info
+{
+ uint32 ptr; /* undocumented buffer pointer */
+ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+
+} NET_Q_TRUST_DOM_LIST;
+
+#define MAX_TRUST_DOMS 1
+
+/* NET_R_TRUST_DOM_LIST - response to LSA Trusted Domains */
+typedef struct net_r_trust_dom_info
+{
+ UNISTR2 uni_trust_dom_name[MAX_TRUST_DOMS];
+
+ NTSTATUS status; /* return code */
+
+} NET_R_TRUST_DOM_LIST;
+
+
+/* NEG_FLAGS */
+typedef struct neg_flags_info
+{
+ uint32 neg_flags; /* negotiated flags */
+
+} NEG_FLAGS;
+
+
+/* NET_Q_REQ_CHAL */
+typedef struct net_q_req_chal_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_clnt; /* logon client unicode string */
+ DOM_CHAL clnt_chal; /* client challenge */
+
+} NET_Q_REQ_CHAL;
+
+
+/* NET_R_REQ_CHAL */
+typedef struct net_r_req_chal_info
+{
+ DOM_CHAL srv_chal; /* server challenge */
+ NTSTATUS status; /* return code */
+} NET_R_REQ_CHAL;
+
+/* NET_Q_AUTH */
+typedef struct net_q_auth_info
+{
+ DOM_LOG_INFO clnt_id; /* client identification info */
+ DOM_CHAL clnt_chal; /* client-calculated credentials */
+} NET_Q_AUTH;
+
+/* NET_R_AUTH */
+typedef struct net_r_auth_info
+{
+ DOM_CHAL srv_chal; /* server-calculated credentials */
+ NTSTATUS status; /* return code */
+} NET_R_AUTH;
+
+/* NET_Q_AUTH_2 */
+typedef struct net_q_auth2_info
+{
+ DOM_LOG_INFO clnt_id; /* client identification info */
+ DOM_CHAL clnt_chal; /* client-calculated credentials */
+
+ NEG_FLAGS clnt_flgs; /* usually 0x0000 01ff */
+
+} NET_Q_AUTH_2;
+
+
+/* NET_R_AUTH_2 */
+typedef struct net_r_auth2_info
+{
+ DOM_CHAL srv_chal; /* server-calculated credentials */
+ NEG_FLAGS srv_flgs; /* usually 0x0000 01ff */
+ NTSTATUS status; /* return code */
+} NET_R_AUTH_2;
+
+
+/* NET_Q_SRV_PWSET */
+typedef struct net_q_srv_pwset_info
+{
+ DOM_CLNT_INFO clnt_id; /* client identification/authentication info */
+ uint8 pwd[16]; /* new password - undocumented. */
+
+} NET_Q_SRV_PWSET;
+
+/* NET_R_SRV_PWSET */
+typedef struct net_r_srv_pwset_info
+{
+ DOM_CRED srv_cred; /* server-calculated credentials */
+
+ NTSTATUS status; /* return code */
+
+} NET_R_SRV_PWSET;
+
+/* NET_ID_INFO_2 */
+typedef struct net_network_info_2
+{
+ uint32 ptr_id_info2; /* pointer to id_info_2 */
+ UNIHDR hdr_domain_name; /* domain name unicode header */
+ uint32 param_ctrl; /* param control (0x2) */
+ DOM_LOGON_ID logon_id; /* logon ID */
+ UNIHDR hdr_user_name; /* user name unicode header */
+ UNIHDR hdr_wksta_name; /* workstation name unicode header */
+ uint8 lm_chal[8]; /* lan manager 8 byte challenge */
+ STRHDR hdr_nt_chal_resp; /* nt challenge response */
+ STRHDR hdr_lm_chal_resp; /* lm challenge response */
+
+ UNISTR2 uni_domain_name; /* domain name unicode string */
+ UNISTR2 uni_user_name; /* user name unicode string */
+ UNISTR2 uni_wksta_name; /* workgroup name unicode string */
+ STRING2 nt_chal_resp; /* nt challenge response */
+ STRING2 lm_chal_resp; /* lm challenge response */
+
+} NET_ID_INFO_2;
+
+/* NET_ID_INFO_1 */
+typedef struct id_info_1
+{
+ uint32 ptr_id_info1; /* pointer to id_info_1 */
+ UNIHDR hdr_domain_name; /* domain name unicode header */
+ uint32 param_ctrl; /* param control */
+ DOM_LOGON_ID logon_id; /* logon ID */
+ UNIHDR hdr_user_name; /* user name unicode header */
+ UNIHDR hdr_wksta_name; /* workstation name unicode header */
+ OWF_INFO lm_owf; /* LM OWF Password */
+ OWF_INFO nt_owf; /* NT OWF Password */
+ UNISTR2 uni_domain_name; /* domain name unicode string */
+ UNISTR2 uni_user_name; /* user name unicode string */
+ UNISTR2 uni_wksta_name; /* workgroup name unicode string */
+
+} NET_ID_INFO_1;
+
+#define INTERACTIVE_LOGON_TYPE 1
+#define NET_LOGON_TYPE 2
+
+/* NET_ID_INFO_CTR */
+typedef struct net_id_info_ctr_info
+{
+ uint16 switch_value;
+
+ union
+ {
+ NET_ID_INFO_1 id1; /* auth-level 1 - interactive user login */
+ NET_ID_INFO_2 id2; /* auth-level 2 - workstation referred login */
+
+ } auth;
+
+} NET_ID_INFO_CTR;
+
+/* SAM_INFO - sam logon/off id structure */
+typedef struct sam_info
+{
+ DOM_CLNT_INFO2 client;
+ uint32 ptr_rtn_cred; /* pointer to return credentials */
+ DOM_CRED rtn_cred; /* return credentials */
+ uint16 logon_level;
+ NET_ID_INFO_CTR *ctr;
+
+} DOM_SAM_INFO;
+
+/* NET_Q_SAM_LOGON */
+typedef struct net_q_sam_logon_info
+{
+ DOM_SAM_INFO sam_id;
+ uint16 validation_level;
+
+} NET_Q_SAM_LOGON;
+
+/* NET_R_SAM_LOGON */
+typedef struct net_r_sam_logon_info
+{
+ uint32 buffer_creds; /* undocumented buffer pointer */
+ DOM_CRED srv_creds; /* server credentials. server time stamp appears to be ignored. */
+
+ uint16 switch_value; /* 3 - indicates type of USER INFO */
+ NET_USER_INFO_3 *user;
+
+ uint32 auth_resp; /* 1 - Authoritative response; 0 - Non-Auth? */
+
+ NTSTATUS status; /* return code */
+
+} NET_R_SAM_LOGON;
+
+
+/* NET_Q_SAM_LOGOFF */
+typedef struct net_q_sam_logoff_info
+{
+ DOM_SAM_INFO sam_id;
+
+} NET_Q_SAM_LOGOFF;
+
+/* NET_R_SAM_LOGOFF */
+typedef struct net_r_sam_logoff_info
+{
+ uint32 buffer_creds; /* undocumented buffer pointer */
+ DOM_CRED srv_creds; /* server credentials. server time stamp appears to be ignored. */
+
+ NTSTATUS status; /* return code */
+
+} NET_R_SAM_LOGOFF;
+
+/* NET_Q_SAM_SYNC */
+typedef struct net_q_sam_sync_info
+{
+ UNISTR2 uni_srv_name; /* \\PDC */
+ UNISTR2 uni_cli_name; /* BDC */
+ DOM_CRED cli_creds;
+ DOM_CRED ret_creds;
+
+ uint32 database_id;
+ uint32 restart_state;
+ uint32 sync_context;
+
+ uint32 max_size; /* preferred maximum length */
+
+} NET_Q_SAM_SYNC;
+
+/* SAM_DELTA_HDR */
+typedef struct sam_delta_hdr_info
+{
+ uint16 type; /* type of structure attached */
+ uint16 type2;
+ uint32 target_rid;
+
+ uint32 type3;
+ uint32 ptr_delta;
+
+} SAM_DELTA_HDR;
+
+/* SAM_DOMAIN_INFO (0x1) */
+typedef struct sam_domain_info_info
+{
+ UNIHDR hdr_dom_name;
+ UNIHDR hdr_oem_info;
+
+ UINT64_S force_logoff;
+ uint16 min_pwd_len;
+ uint16 pwd_history_len;
+ UINT64_S max_pwd_age;
+ UINT64_S min_pwd_age;
+ UINT64_S dom_mod_count;
+ NTTIME creation_time;
+
+ BUFHDR2 hdr_sec_desc; /* security descriptor */
+ UNIHDR hdr_unknown;
+ uint8 reserved[40];
+
+ UNISTR2 uni_dom_name;
+ UNISTR2 buf_oem_info; /* never seen */
+
+ BUFFER4 buf_sec_desc;
+ UNISTR2 buf_unknown;
+
+} SAM_DOMAIN_INFO;
+
+/* SAM_GROUP_INFO (0x2) */
+typedef struct sam_group_info_info
+{
+ UNIHDR hdr_grp_name;
+ DOM_GID gid;
+ UNIHDR hdr_grp_desc;
+ BUFHDR2 hdr_sec_desc; /* security descriptor */
+ uint8 reserved[48];
+
+ UNISTR2 uni_grp_name;
+ UNISTR2 uni_grp_desc;
+ BUFFER4 buf_sec_desc;
+
+} SAM_GROUP_INFO;
+
+/* SAM_PWD */
+typedef struct sam_passwd_info
+{
+ /* this structure probably contains password history */
+ /* this is probably a count of lm/nt pairs */
+ uint32 unk_0; /* 0x0000 0002 */
+
+ UNIHDR hdr_lm_pwd;
+ uint8 buf_lm_pwd[16];
+
+ UNIHDR hdr_nt_pwd;
+ uint8 buf_nt_pwd[16];
+
+ UNIHDR hdr_empty_lm;
+ UNIHDR hdr_empty_nt;
+
+} SAM_PWD;
+
+/* SAM_ACCOUNT_INFO (0x5) */
+typedef struct sam_account_info_info
+{
+ UNIHDR hdr_acct_name;
+ UNIHDR hdr_full_name;
+
+ uint32 user_rid;
+ uint32 group_rid;
+
+ UNIHDR hdr_home_dir;
+ UNIHDR hdr_dir_drive;
+ UNIHDR hdr_logon_script;
+ UNIHDR hdr_acct_desc;
+ UNIHDR hdr_workstations;
+
+ NTTIME logon_time;
+ NTTIME logoff_time;
+
+ uint32 logon_divs; /* 0xA8 */
+ uint32 ptr_logon_hrs;
+
+ uint16 bad_pwd_count;
+ uint16 logon_count;
+ NTTIME pwd_last_set_time;
+ NTTIME acct_expiry_time;
+
+ uint32 acb_info;
+ uint8 nt_pwd[16];
+ uint8 lm_pwd[16];
+ uint8 nt_pwd_present;
+ uint8 lm_pwd_present;
+ uint8 pwd_expired;
+
+ UNIHDR hdr_comment;
+ UNIHDR hdr_parameters;
+ uint16 country;
+ uint16 codepage;
+
+ BUFHDR2 hdr_sec_desc; /* security descriptor */
+
+ UNIHDR hdr_profile;
+ UNIHDR hdr_reserved[3]; /* space for more strings */
+ uint32 dw_reserved[4]; /* space for more data - first two seem to
+ be an NTTIME */
+
+ UNISTR2 uni_acct_name;
+ UNISTR2 uni_full_name;
+ UNISTR2 uni_home_dir;
+ UNISTR2 uni_dir_drive;
+ UNISTR2 uni_logon_script;
+ UNISTR2 uni_acct_desc;
+ UNISTR2 uni_workstations;
+
+ uint32 unknown1; /* 0x4EC */
+ uint32 unknown2; /* 0 */
+
+ BUFFER4 buf_logon_hrs;
+ UNISTR2 uni_comment;
+ UNISTR2 uni_parameters;
+ SAM_PWD pass;
+ BUFFER4 buf_sec_desc;
+ UNISTR2 uni_profile;
+
+} SAM_ACCOUNT_INFO;
+
+/* SAM_GROUP_MEM_INFO (0x8) */
+typedef struct sam_group_mem_info_info
+{
+ uint32 ptr_rids;
+ uint32 ptr_attribs;
+ uint32 num_members;
+ uint8 unknown[16];
+
+ uint32 num_members2;
+ uint32 *rids;
+
+ uint32 num_members3;
+ uint32 *attribs;
+
+} SAM_GROUP_MEM_INFO;
+
+/* SAM_ALIAS_INFO (0x9) */
+typedef struct sam_alias_info_info
+{
+ UNIHDR hdr_als_name;
+ uint32 als_rid;
+ BUFHDR2 hdr_sec_desc; /* security descriptor */
+ UNIHDR hdr_als_desc;
+ uint8 reserved[40];
+
+ UNISTR2 uni_als_name;
+ BUFFER4 buf_sec_desc;
+ UNISTR2 uni_als_desc;
+
+} SAM_ALIAS_INFO;
+
+/* SAM_ALIAS_MEM_INFO (0xC) */
+typedef struct sam_alias_mem_info_info
+{
+ uint32 num_members;
+ uint32 ptr_members;
+ uint8 unknown[16];
+
+ uint32 num_sids;
+ uint32 *ptr_sids;
+ DOM_SID2 *sids;
+
+} SAM_ALIAS_MEM_INFO;
+
+
+/* SAM_DELTA_DOM (0x0D) */
+typedef struct
+{
+ uint32 unknown1; /* 0x5000 */
+ uint32 unknown2; /* 0 */
+ uint32 unknown3; /* 0 */
+ uint32 unknown4; /* 0 */
+ uint32 count1;
+ uint32 ptr1;
+ uint16 count2;
+ uint16 count3;
+ uint32 ptr2;
+ uint32 ptr3;
+
+ uint32 unknown4b; /* 0x02000000 */
+ uint32 unknown5; /* 0x00100000 */
+ uint32 unknown6; /* 0x00010000 */
+ uint32 unknown7; /* 0x0f000000 */
+ uint32 unknown8; /* 0 */
+ uint32 unknown9; /* 0 */
+ uint32 unknown10; /* 0 */
+ uint32 unknown11; /* 0x3c*/
+ uint32 unknown12; /* 0*/
+
+ uint32 unknown13; /* a7080110 */
+ uint32 unknown14; /* 01bfb0dd */
+ uint32 unknown15; /* 0f */
+ uint32 unknown16; /* 68 */
+ uint32 unknown17; /* 00169000 */
+
+ uint32 count4;
+ uint32 unknown18; /* 0 times count4 */
+
+ uint32 unknown19; /* 8 */
+
+ uint32 unknown20; /* 0x04 times count1 */
+
+ uint32 ptr4;
+
+ UNISTR2 domain_name;
+ DOM_SID2 domain_sid;
+
+} SAM_DELTA_DOM;
+
+/* SAM_DELTA_UNK0E (0x0e) */
+typedef struct
+{
+ uint32 buf_size;
+ SEC_DESC *sec_desc;
+ DOM_SID2 sid;
+ UNIHDR hdr_domain;
+
+ uint32 unknown0;
+ uint32 unknown1;
+ uint32 unknown2;
+
+ uint32 buf_size2;
+ uint32 ptr;
+
+ uint32 unknown3;
+ UNISTR2 domain;
+
+} SAM_DELTA_UNK0E;
+
+/* SAM_DELTA_PRIVS (0x10) */
+typedef struct
+{
+ uint32 buf_size;
+ SEC_DESC *sec_desc;
+ DOM_SID2 sid;
+
+ uint32 priv_count;
+ uint32 reserved1; /* 0x0 */
+
+ uint32 ptr1;
+ uint32 ptr2;
+
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ uint32 unknown9;
+
+ uint32 buf_size2;
+ uint32 ptr3;
+ uint32 unknown10; /* 48 bytes 0x0*/
+
+ uint32 attribute_count;
+ uint32 *attributes;
+
+ uint32 privlist_count;
+ UNIHDR *hdr_privslist;
+ UNISTR2 *uni_privslist;
+
+
+} SAM_DELTA_PRIVS;
+
+/* SAM_DELTA_UNK12 (0x12) */
+typedef struct
+{
+ uint32 buf_size;
+ SEC_DESC *sec_desc;
+ UNISTR2 secret;
+
+ uint32 count1;
+ uint32 count2;
+ uint32 ptr;
+ NTTIME time1;
+ uint32 count3;
+ uint32 count4;
+ uint32 ptr2;
+ NTTIME time2;
+ uint32 unknow1;
+
+ uint32 buf_size2;
+ uint32 ptr3;
+ uint32 unknow2; /* 0x0 12 times */
+
+ uint32 chal_len;
+ uint32 reserved1; /* 0 */
+ uint32 chal_len2;
+ uint8 chal[16];
+
+ uint32 key_len;
+ uint32 reserved2; /* 0 */
+ uint32 key_len2;
+ uint8 key[8];
+
+ uint32 buf_size3;
+ SEC_DESC *sec_desc2;
+
+} SAM_DELTA_UNK12;
+
+/* SAM_DELTA_STAMP (0x16) */
+typedef struct
+{
+ uint32 seqnum;
+ uint32 dom_mod_count_ptr;
+ UINT64_S dom_mod_count; /* domain mod count at last sync */
+} SAM_DELTA_STAMP;
+
+typedef union sam_delta_ctr_info
+{
+ SAM_DOMAIN_INFO domain_info ;
+ SAM_GROUP_INFO group_info ;
+ SAM_ACCOUNT_INFO account_info;
+ SAM_GROUP_MEM_INFO grp_mem_info;
+ SAM_ALIAS_INFO alias_info ;
+ SAM_ALIAS_MEM_INFO als_mem_info;
+ SAM_DELTA_DOM dom_info;
+ SAM_DELTA_PRIVS privs_info;
+ SAM_DELTA_STAMP stamp;
+ SAM_DELTA_UNK0E unk0e_info;
+ SAM_DELTA_UNK12 unk12_info;
+} SAM_DELTA_CTR;
+
+/* NET_R_SAM_SYNC */
+typedef struct net_r_sam_sync_info
+{
+ DOM_CRED srv_creds;
+
+ uint32 sync_context;
+
+ uint32 ptr_deltas;
+ uint32 num_deltas;
+ uint32 ptr_deltas2;
+ uint32 num_deltas2;
+
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+
+ NTSTATUS status;
+} NET_R_SAM_SYNC;
+
+/* NET_Q_SAM_DELTAS */
+typedef struct net_q_sam_deltas_info
+{
+ UNISTR2 uni_srv_name;
+ UNISTR2 uni_cli_name;
+ DOM_CRED cli_creds;
+ DOM_CRED ret_creds;
+
+ uint32 database_id;
+ UINT64_S dom_mod_count; /* domain mod count at last sync */
+
+ uint32 max_size; /* preferred maximum length */
+
+} NET_Q_SAM_DELTAS;
+
+/* NET_R_SAM_DELTAS */
+typedef struct net_r_sam_deltas_info
+{
+ DOM_CRED srv_creds;
+
+ UINT64_S dom_mod_count; /* new domain mod count */
+
+ uint32 ptr_deltas;
+ uint32 num_deltas;
+ uint32 num_deltas2;
+
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+
+ NTSTATUS status;
+} NET_R_SAM_DELTAS;
+
+#endif /* _RPC_NETLOGON_H */
diff --git a/source/include/rpc_parse.h b/source/include/rpc_parse.h
new file mode 100644
index 00000000000..5a302b1af33
--- /dev/null
+++ b/source/include/rpc_parse.h
@@ -0,0 +1,31 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Elrond 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_PARSE_H
+#define _RPC_PARSE_H
+
+/* different dce/rpc pipes */
+#include "rpc_reg.h"
+#include "rpc_brs.h"
+
+#endif /* _RPC_PARSE_H */
diff --git a/source/include/rpc_reg.h b/source/include/rpc_reg.h
new file mode 100644
index 00000000000..bc2c3824df3
--- /dev/null
+++ b/source/include/rpc_reg.h
@@ -0,0 +1,549 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_REG_H /* _RPC_REG_H */
+#define _RPC_REG_H
+
+
+/* winreg pipe defines */
+#define REG_OPEN_HKCR 0x00
+#define _REG_UNK_01 0x01
+#define REG_OPEN_HKLM 0x02
+#define _REG_UNK_03 0x03
+#define REG_OPEN_HKU 0x04
+#define REG_CLOSE 0x05
+#define REG_CREATE_KEY 0x06
+#define REG_DELETE_KEY 0x07
+#define REG_DELETE_VALUE 0x08
+#define REG_ENUM_KEY 0x09
+#define REG_ENUM_VALUE 0x0a
+#define REG_FLUSH_KEY 0x0b
+#define REG_GET_KEY_SEC 0x0c
+#define _REG_UNK_0D 0x0d
+#define _REG_UNK_0E 0x0e
+#define REG_OPEN_ENTRY 0x0f
+#define REG_QUERY_KEY 0x10
+#define REG_INFO 0x11
+#define _REG_UNK_12 0x12
+#define _REG_UNK_13 0x13
+#define _REG_UNK_14 0x14
+#define REG_SET_KEY_SEC 0x15
+#define REG_CREATE_VALUE 0x16
+#define _REG_UNK_17 0x17
+#define REG_SHUTDOWN 0x18
+#define REG_ABORT_SHUTDOWN 0x19
+#define REG_UNK_1A 0x1a
+
+#define HKEY_CLASSES_ROOT 0x80000000
+#define HKEY_CURRENT_USER 0x80000001
+#define HKEY_LOCAL_MACHINE 0x80000002
+#define HKEY_USERS 0x80000003
+
+/* Registry data types */
+
+#define REG_NONE 0
+#define REG_SZ 1
+#define REG_EXPAND_SZ 2
+#define REG_BINARY 3
+#define REG_DWORD 4
+#define REG_DWORD_LE 4 /* DWORD, little endian */
+#define REG_DWORD_BE 5 /* DWORD, big endian */
+#define REG_LINK 6
+#define REG_MULTI_SZ 7
+#define REG_RESOURCE_LIST 8
+#define REG_FULL_RESOURCE_DESCRIPTOR 9
+#define REG_RESOURCE_REQUIREMENTS_LIST 10
+
+/* REG_Q_OPEN_HKCR */
+typedef struct q_reg_open_hkcr_info
+{
+ uint32 ptr;
+ uint16 unknown_0; /* 0x5428 - 16 bit unknown */
+ uint16 unknown_1; /* random. changes */
+ uint32 level; /* 0x0000 0002 - 32 bit unknown */
+
+} REG_Q_OPEN_HKCR ;
+
+/* REG_R_OPEN_HKCR */
+typedef struct r_reg_open_hkcr_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} REG_R_OPEN_HKCR;
+
+
+/* REG_Q_OPEN_HKLM */
+typedef struct q_reg_open_hklm_info
+{
+ uint32 ptr;
+ uint16 unknown_0; /* 0xE084 - 16 bit unknown */
+ uint16 unknown_1; /* random. changes */
+ uint32 access_mask; /* 0x0000 0002 - 32 bit unknown */
+
+}
+REG_Q_OPEN_HKLM;
+
+/* REG_R_OPEN_HKLM */
+typedef struct r_reg_open_hklm_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+}
+REG_R_OPEN_HKLM;
+
+
+/* REG_Q_OPEN_HKU */
+typedef struct q_reg_open_hku_info
+{
+ uint32 ptr;
+ uint16 unknown_0; /* 0xE084 - 16 bit unknown */
+ uint16 unknown_1; /* random. changes */
+ uint32 level; /* 0x0000 0002 - 32 bit unknown */
+
+} REG_Q_OPEN_HKU;
+
+/* REG_R_OPEN_HKU */
+typedef struct r_reg_open_hku_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} REG_R_OPEN_HKU;
+
+
+/* REG_Q_FLUSH_KEY */
+typedef struct q_reg_open_flush_key_info
+{
+ POLICY_HND pol; /* policy handle */
+
+} REG_Q_FLUSH_KEY;
+
+/* REG_R_FLUSH_KEY */
+typedef struct r_reg_open_flush_key_info
+{
+ NTSTATUS status; /* return status */
+
+} REG_R_FLUSH_KEY;
+
+
+/* REG_Q_SET_KEY_SEC */
+typedef struct q_reg_set_key_sec_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 sec_info; /* xxxx_SECURITY_INFORMATION */
+
+ uint32 ptr; /* pointer */
+ BUFHDR hdr_sec; /* header for security data */
+ SEC_DESC_BUF *data; /* security data */
+
+} REG_Q_SET_KEY_SEC;
+
+/* REG_R_SET_KEY_SEC */
+typedef struct r_reg_set_key_sec_info
+{
+ NTSTATUS status;
+
+} REG_R_SET_KEY_SEC;
+
+
+/* REG_Q_GET_KEY_SEC */
+typedef struct q_reg_get_key_sec_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 sec_info; /* xxxx_SECURITY_INFORMATION */
+
+ uint32 ptr; /* pointer */
+ BUFHDR hdr_sec; /* header for security data */
+ SEC_DESC_BUF *data; /* security data */
+
+} REG_Q_GET_KEY_SEC;
+
+/* REG_R_GET_KEY_SEC */
+typedef struct r_reg_get_key_sec_info
+{
+ uint32 sec_info; /* xxxx_SECURITY_INFORMATION */
+
+ uint32 ptr; /* pointer */
+ BUFHDR hdr_sec; /* header for security data */
+ SEC_DESC_BUF *data; /* security data */
+
+ NTSTATUS status;
+
+} REG_R_GET_KEY_SEC;
+
+/* REG_Q_CREATE_VALUE */
+typedef struct q_reg_create_value_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ UNIHDR hdr_name; /* name of value */
+ UNISTR2 uni_name;
+
+ uint32 type; /* 1 = UNISTR, 3 = BYTES, 4 = DWORD, 7 = MULTI_UNISTR */
+
+ BUFFER3 *buf_value; /* value, in byte buffer */
+
+} REG_Q_CREATE_VALUE;
+
+/* REG_R_CREATE_VALUE */
+typedef struct r_reg_create_value_info
+{
+ NTSTATUS status; /* return status */
+
+} REG_R_CREATE_VALUE;
+
+/* REG_Q_ENUM_VALUE */
+typedef struct q_reg_query_value_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 val_index; /* index */
+
+ UNIHDR hdr_name; /* name of value */
+ UNISTR2 uni_name;
+
+ uint32 ptr_type; /* pointer */
+ uint32 type; /* 1 = UNISTR, 3 = BYTES, 4 = DWORD, 7 = MULTI_UNISTR */
+
+ uint32 ptr_value; /* pointer */
+ BUFFER2 buf_value; /* value, in byte buffer */
+
+ uint32 ptr1; /* pointer */
+ uint32 len_value1; /* */
+
+ uint32 ptr2; /* pointer */
+ uint32 len_value2; /* */
+
+} REG_Q_ENUM_VALUE;
+
+/* REG_R_ENUM_VALUE */
+typedef struct r_reg_enum_value_info
+{
+ UNIHDR hdr_name; /* name of value */
+ UNISTR2 uni_name;
+
+ uint32 ptr_type; /* pointer */
+ uint32 type; /* 1 = UNISTR, 3 = BYTES, 4 = DWORD, 7 = MULTI_UNISTR */
+
+ uint32 ptr_value; /* pointer */
+ BUFFER2 *buf_value; /* value, in byte buffer */
+
+ uint32 ptr1; /* pointer */
+ uint32 len_value1; /* */
+
+ uint32 ptr2; /* pointer */
+ uint32 len_value2; /* */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_ENUM_VALUE;
+
+/* REG_Q_CREATE_KEY */
+typedef struct q_reg_create_key_info
+{
+ POLICY_HND pnt_pol; /* parent key policy handle */
+
+ UNIHDR hdr_name;
+ UNISTR2 uni_name;
+
+ UNIHDR hdr_class;
+ UNISTR2 uni_class;
+
+ uint32 reserved; /* 0x0000 0000 */
+ SEC_ACCESS sam_access; /* access rights flags, see rpc_secdes.h */
+
+ uint32 ptr1;
+ uint32 sec_info; /* xxxx_SECURITY_INFORMATION */
+
+ uint32 ptr2; /* pointer */
+ BUFHDR hdr_sec; /* header for security data */
+ uint32 ptr3; /* pointer */
+ SEC_DESC_BUF *data;
+
+ uint32 unknown_2; /* 0x0000 0000 */
+
+} REG_Q_CREATE_KEY;
+
+/* REG_R_CREATE_KEY */
+typedef struct r_reg_create_key_info
+{
+ POLICY_HND key_pol; /* policy handle */
+ uint32 unknown; /* 0x0000 0000 */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_CREATE_KEY;
+
+/* REG_Q_DELETE_KEY */
+typedef struct q_reg_delete_key_info
+{
+ POLICY_HND pnt_pol; /* parent key policy handle */
+
+ UNIHDR hdr_name;
+ UNISTR2 uni_name;
+} REG_Q_DELETE_KEY;
+
+/* REG_R_DELETE_KEY */
+typedef struct r_reg_delete_key_info
+{
+ POLICY_HND key_pol; /* policy handle */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_DELETE_KEY;
+
+/* REG_Q_DELETE_VALUE */
+typedef struct q_reg_delete_val_info
+{
+ POLICY_HND pnt_pol; /* parent key policy handle */
+
+ UNIHDR hdr_name;
+ UNISTR2 uni_name;
+
+} REG_Q_DELETE_VALUE;
+
+/* REG_R_DELETE_VALUE */
+typedef struct r_reg_delete_val_info
+{
+ POLICY_HND key_pol; /* policy handle */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_DELETE_VALUE;
+
+/* REG_Q_QUERY_KEY */
+typedef struct q_reg_query_info
+{
+ POLICY_HND pol; /* policy handle */
+ UNIHDR hdr_class;
+ UNISTR2 uni_class;
+
+} REG_Q_QUERY_KEY;
+
+/* REG_R_QUERY_KEY */
+typedef struct r_reg_query_key_info
+{
+ UNIHDR hdr_class;
+ UNISTR2 uni_class;
+
+ uint32 num_subkeys;
+ uint32 max_subkeylen;
+ uint32 max_subkeysize; /* 0x0000 0000 */
+ uint32 num_values;
+ uint32 max_valnamelen;
+ uint32 max_valbufsize;
+ uint32 sec_desc; /* 0x0000 0078 */
+ NTTIME mod_time; /* modified time */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_QUERY_KEY;
+
+
+/* REG_Q_UNK_1A */
+typedef struct q_reg_unk_1a_info
+{
+ POLICY_HND pol; /* policy handle */
+
+} REG_Q_UNK_1A;
+
+/* REG_R_UNK_1A */
+typedef struct r_reg_unk_1a_info
+{
+ uint32 unknown; /* 0x0500 0000 */
+ NTSTATUS status; /* return status */
+
+} REG_R_UNK_1A;
+
+
+/* REG_Q_CLOSE */
+typedef struct reg_q_close_info
+{
+ POLICY_HND pol; /* policy handle */
+
+} REG_Q_CLOSE;
+
+/* REG_R_CLOSE */
+typedef struct reg_r_close_info
+{
+ POLICY_HND pol; /* policy handle. should be all zeros. */
+
+ NTSTATUS status; /* return code */
+
+} REG_R_CLOSE;
+
+
+/* REG_Q_ENUM_KEY */
+typedef struct q_reg_enum_value_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 key_index;
+
+ uint16 key_name_len; /* 0x0000 */
+ uint16 unknown_1; /* 0x0414 */
+
+ uint32 ptr1; /* pointer */
+ uint32 unknown_2; /* 0x0000 020A */
+ uint8 pad1[8]; /* padding - zeros */
+
+ uint32 ptr2; /* pointer */
+ uint8 pad2[8]; /* padding - zeros */
+
+ uint32 ptr3; /* pointer */
+ NTTIME time; /* current time? */
+
+} REG_Q_ENUM_KEY;
+
+/* REG_R_ENUM_KEY */
+typedef struct r_reg_enum_key_info
+{
+ uint16 key_name_len; /* number of bytes in key name */
+ uint16 unknown_1; /* 0x0414 - matches with query unknown_1 */
+
+ uint32 ptr1; /* pointer */
+ uint32 unknown_2; /* 0x0000 020A */
+ uint32 unknown_3; /* 0x0000 0000 */
+
+ UNISTR3 key_name;
+
+ uint32 ptr2; /* pointer */
+ uint8 pad2[8]; /* padding - zeros */
+
+ uint32 ptr3; /* pointer */
+ NTTIME time; /* current time? */
+
+ NTSTATUS status; /* return status */
+
+} REG_R_ENUM_KEY;
+
+
+/* REG_Q_INFO */
+typedef struct q_reg_info_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ UNIHDR hdr_type; /* unicode product type header */
+ UNISTR2 uni_type; /* unicode product type - "ProductType" */
+
+ uint32 ptr_reserved; /* pointer */
+
+ uint32 ptr_buf; /* the next three fields follow if ptr_buf != 0 */
+ uint32 ptr_bufsize;
+ uint32 bufsize;
+ uint32 buf_unk;
+
+ uint32 unk1;
+ uint32 ptr_buflen;
+ uint32 buflen;
+
+ uint32 ptr_buflen2;
+ uint32 buflen2;
+
+} REG_Q_INFO;
+
+/* REG_R_INFO */
+typedef struct r_reg_info_info
+{
+ uint32 ptr_type; /* key type pointer */
+ uint32 type; /* key datatype */
+
+ uint32 ptr_uni_val; /* key value pointer */
+ BUFFER2 *uni_val; /* key value */
+
+ uint32 ptr_max_len;
+ uint32 buf_max_len;
+
+ uint32 ptr_len;
+ uint32 buf_len;
+
+ NTSTATUS status; /* return status */
+
+} REG_R_INFO;
+
+
+/* REG_Q_OPEN_ENTRY */
+typedef struct q_reg_open_entry_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ UNIHDR hdr_name; /* unicode registry string header */
+ UNISTR2 uni_name; /* unicode registry string name */
+
+ uint32 unknown_0; /* 32 bit unknown - 0x0000 0000 */
+ uint32 unknown_1; /* 32 bit unknown - 0x0200 0000 */
+
+} REG_Q_OPEN_ENTRY;
+
+
+
+/* REG_R_OPEN_ENTRY */
+typedef struct r_reg_open_entry_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} REG_R_OPEN_ENTRY;
+
+/* REG_Q_SHUTDOWN */
+typedef struct q_reg_shutdown_info
+{
+ uint32 ptr_0;
+ uint32 ptr_1;
+ uint32 ptr_2;
+ UNIHDR hdr_msg; /* shutdown message */
+ UNISTR2 uni_msg; /* seconds */
+ uint32 timeout; /* seconds */
+ uint16 flags;
+
+} REG_Q_SHUTDOWN;
+
+/* REG_R_SHUTDOWN */
+typedef struct r_reg_shutdown_info
+{
+ NTSTATUS status; /* return status */
+
+} REG_R_SHUTDOWN;
+
+/* REG_Q_ABORT_SHUTDOWN */
+typedef struct q_reg_abort_shutdown_info
+{
+ uint32 ptr_server;
+ uint16 server;
+
+} REG_Q_ABORT_SHUTDOWN;
+
+/* REG_R_ABORT_SHUTDOWN */
+typedef struct r_reg_abort_shutdown_info
+{
+ NTSTATUS status; /* return status */
+
+} REG_R_ABORT_SHUTDOWN;
+
+
+#endif /* _RPC_REG_H */
+
diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h
new file mode 100644
index 00000000000..43ee342ed33
--- /dev/null
+++ b/source/include/rpc_samr.h
@@ -0,0 +1,1808 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1997-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_SAMR_H /* _RPC_SAMR_H */
+#define _RPC_SAMR_H
+
+
+#include "rpc_misc.h"
+
+
+/*******************************************************************
+ the following information comes from a QuickView on samsrv.dll,
+ and gives an idea of exactly what is needed:
+
+x SamrAddMemberToAlias
+x SamrAddMemberToGroup
+SamrAddMultipleMembersToAlias
+x SamrChangePasswordUser
+x SamrCloseHandle
+x SamrConnect
+x SamrCreateAliasInDomain
+x SamrCreateGroupInDomain
+x SamrCreateUserInDomain
+? SamrDeleteAlias
+SamrDeleteGroup
+x SamrDeleteUser
+x SamrEnumerateAliasesInDomain
+SamrEnumerateDomainsInSamServer
+x SamrEnumerateGroupsInDomain
+x SamrEnumerateUsersInDomain
+SamrGetUserDomainPasswordInformation
+SamrLookupDomainInSamServer
+? SamrLookupIdsInDomain
+x SamrLookupNamesInDomain
+x SamrOpenAlias
+x SamrOpenDomain
+x SamrOpenGroup
+x SamrOpenUser
+x SamrQueryDisplayInformation
+x SamrQueryInformationAlias
+SamrQueryInformationDomain
+? SamrQueryInformationUser
+x SamrQuerySecurityObject
+SamrRemoveMemberFromAlias
+SamrRemoveMemberFromForiegnDomain
+SamrRemoveMemberFromGroup
+SamrRemoveMultipleMembersFromAlias
+x SamrSetInformationAlias
+SamrSetInformationDomain
+x SamrSetInformationGroup
+x SamrSetInformationUser
+SamrSetMemberAttributesOfGroup
+SamrSetSecurityObject
+SamrShutdownSamServer
+SamrTestPrivateFunctionsDomain
+SamrTestPrivateFunctionsUser
+
+********************************************************************/
+
+#define SAMR_CONNECT_ANON 0x00
+#define SAMR_CLOSE_HND 0x01
+#define SAMR_UNKNOWN_2 0x02 /* set sec object? */
+#define SAMR_QUERY_SEC_OBJECT 0x03
+
+#define SAMR_UNKNOWN_4 0x04 /* profile info? */
+#define SAMR_LOOKUP_DOMAIN 0x05
+#define SAMR_ENUM_DOMAINS 0x06
+#define SAMR_OPEN_DOMAIN 0x07
+#define SAMR_QUERY_DOMAIN_INFO 0x08
+#define SAMR_SET_DOMAIN_INFO 0x09
+
+#define SAMR_CREATE_DOM_GROUP 0x0a
+#define SAMR_ENUM_DOM_GROUPS 0x0b
+#define SAMR_ENUM_DOM_USERS 0x0d
+#define SAMR_CREATE_DOM_ALIAS 0x0e
+#define SAMR_ENUM_DOM_ALIASES 0x0f
+#define SAMR_QUERY_USERALIASES 0x10
+
+#define SAMR_LOOKUP_NAMES 0x11
+#define SAMR_LOOKUP_RIDS 0x12
+
+#define SAMR_OPEN_GROUP 0x13
+#define SAMR_QUERY_GROUPINFO 0x14
+#define SAMR_SET_GROUPINFO 0x15
+#define SAMR_ADD_GROUPMEM 0x16
+#define SAMR_DELETE_DOM_GROUP 0x17
+#define SAMR_DEL_GROUPMEM 0x18
+#define SAMR_QUERY_GROUPMEM 0x19
+#define SAMR_UNKNOWN_1A 0x1a
+
+#define SAMR_OPEN_ALIAS 0x1b
+#define SAMR_QUERY_ALIASINFO 0x1c
+#define SAMR_SET_ALIASINFO 0x1d
+#define SAMR_DELETE_DOM_ALIAS 0x1e
+#define SAMR_ADD_ALIASMEM 0x1f
+#define SAMR_DEL_ALIASMEM 0x20
+#define SAMR_QUERY_ALIASMEM 0x21
+
+#define SAMR_OPEN_USER 0x22
+#define SAMR_DELETE_DOM_USER 0x23
+#define SAMR_QUERY_USERINFO 0x24
+#define SAMR_SET_USERINFO2 0x25
+#define SAMR_QUERY_USERGROUPS 0x27
+
+#define SAMR_QUERY_DISPINFO 0x28
+#define SAMR_UNKNOWN_29 0x29
+#define SAMR_UNKNOWN_2a 0x2a
+#define SAMR_UNKNOWN_2b 0x2b
+#define SAMR_GET_USRDOM_PWINFO 0x2c
+#define SAMR_UNKNOWN_2D 0x2d
+#define SAMR_UNKNOWN_2E 0x2e /* looks like an alias for SAMR_QUERY_DOMAIN_INFO */
+#define SAMR_UNKNOWN_2f 0x2f
+#define SAMR_QUERY_DISPINFO3 0x30 /* Alias for SAMR_QUERY_DISPINFO
+ with info level 3 */
+#define SAMR_UNKNOWN_31 0x31
+#define SAMR_CREATE_USER 0x32
+#define SAMR_QUERY_DISPINFO4 0x33 /* Alias for SAMR_QUERY_DISPINFO
+ with info level 4 */
+#define SAMR_ADDMULTI_ALIASMEM 0x34
+
+#define SAMR_UNKNOWN_35 0x35
+#define SAMR_UNKNOWN_36 0x36
+#define SAMR_CHGPASSWD_USER 0x37
+#define SAMR_GET_DOM_PWINFO 0x38
+#define SAMR_CONNECT 0x39
+#define SAMR_SET_USERINFO 0x3A
+
+
+
+typedef struct logon_hours_info
+{
+ uint32 len; /* normally 21 bytes */
+ uint8 hours[32];
+
+} LOGON_HRS;
+
+/* SAM_USER_INFO_23 */
+typedef struct sam_user_info_23
+{
+ /* TIMES MAY NOT IN RIGHT ORDER!!!! */
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* NULL - user name unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home drive unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_acct_desc ; /* user description */
+ UNIHDR hdr_workstations; /* comma-separated workstations user can log in from */
+ UNIHDR hdr_unknown_str ; /* don't know what this is, yet. */
+ UNIHDR hdr_munged_dial ; /* munged path name and dial-back tel number */
+
+ uint8 lm_pwd[16]; /* lm user passwords */
+ uint8 nt_pwd[16]; /* nt user passwords */
+
+ uint32 user_rid; /* Primary User ID */
+ uint32 group_rid; /* Primary Group ID */
+
+ uint32 acb_info; /* account info (ACB_xxxx bit-mask) */
+
+ uint32 unknown_3; /* 0x09f8 27fa */
+
+ uint16 logon_divs; /* 0x0000 00a8 which is 168 which is num hrs in a week */
+ /* uint8 pad[2] */
+ uint32 ptr_logon_hrs; /* pointer to logon hours */
+
+ uint8 padding1[8];
+
+ uint32 unknown_5; /* 0x0001 0000 */
+
+ uint8 pass[516];
+
+ UNISTR2 uni_user_name; /* NULL - username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_acct_desc ; /* user description unicode string */
+ UNISTR2 uni_workstations; /* login from workstations unicode string */
+ UNISTR2 uni_unknown_str ; /* don't know what this is, yet. */
+ UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel no */
+
+ uint32 unknown_6; /* 0x0000 04ec */
+ uint32 padding4;
+
+ LOGON_HRS logon_hrs;
+
+} SAM_USER_INFO_23;
+
+/* SAM_USER_INFO_24 */
+typedef struct sam_user_info_24
+{
+ uint8 pass[516];
+ uint16 pw_len;
+} SAM_USER_INFO_24;
+
+/*
+ * NB. This structure is *definately* incorrect. It's my best guess
+ * currently for W2K SP2. The password field is encrypted in a different
+ * way than normal... And there are definately other problems. JRA.
+ */
+
+/* SAM_USER_INFO_25 */
+typedef struct sam_user_info_25
+{
+ /* TIMES MAY NOT IN RIGHT ORDER!!!! */
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* NULL - user name unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home drive unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_acct_desc ; /* user description */
+ UNIHDR hdr_workstations; /* comma-separated workstations user can log in from */
+ UNIHDR hdr_unknown_str ; /* don't know what this is, yet. */
+ UNIHDR hdr_munged_dial ; /* munged path name and dial-back tel number */
+
+ uint8 lm_pwd[16]; /* lm user passwords */
+ uint8 nt_pwd[16]; /* nt user passwords */
+
+ uint32 user_rid; /* Primary User ID */
+ uint32 group_rid; /* Primary Group ID */
+
+ uint32 acb_info; /* account info (ACB_xxxx bit-mask) */
+
+ uint32 unknown_6[6];
+
+ uint8 pass[532];
+
+ UNISTR2 uni_user_name; /* NULL - username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_acct_desc ; /* user description unicode string */
+ UNISTR2 uni_workstations; /* login from workstations unicode string */
+ UNISTR2 uni_unknown_str ; /* don't know what this is, yet. */
+ UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel no */
+} SAM_USER_INFO_25;
+
+
+/* SAM_USER_INFO_21 */
+typedef struct sam_user_info_21
+{
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* username unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home drive unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_acct_desc ; /* user description */
+ UNIHDR hdr_workstations; /* comma-separated workstations user can log in from */
+ UNIHDR hdr_unknown_str ; /* don't know what this is, yet. */
+ UNIHDR hdr_munged_dial ; /* munged path name and dial-back tel number */
+
+ uint8 lm_pwd[16]; /* lm user passwords */
+ uint8 nt_pwd[16]; /* nt user passwords */
+
+ uint32 user_rid; /* Primary User ID */
+ uint32 group_rid; /* Primary Group ID */
+
+ uint32 acb_info; /* account info (ACB_xxxx bit-mask) */
+
+ uint32 unknown_3; /* 0x00ff ffff */
+
+ uint16 logon_divs; /* 0x0000 00a8 which is 168 which is num hrs in a week */
+ /* uint8 pad[2] */
+ uint32 ptr_logon_hrs; /* unknown pointer */
+
+ uint32 unknown_5; /* 0x0002 0000 */
+
+ uint8 padding1[8];
+
+ UNISTR2 uni_user_name; /* username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_acct_desc ; /* user description unicode string */
+ UNISTR2 uni_workstations; /* login from workstations unicode string */
+ UNISTR2 uni_unknown_str ; /* don't know what this is, yet. */
+ UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel number */
+
+ uint32 unknown_6; /* 0x0000 04ec */
+ uint32 padding4;
+
+ LOGON_HRS logon_hrs;
+
+} SAM_USER_INFO_21;
+
+
+/* SAM_USER_INFO_20 */
+typedef struct sam_user_info_20
+{
+ UNIHDR hdr_munged_dial ; /* munged path name and dial-back tel number */
+
+ UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel number */
+
+} SAM_USER_INFO_20;
+
+/* SAM_USER_INFO_12 */
+typedef struct sam_user_info_12
+{
+ uint8 lm_pwd[16]; /* lm user passwords */
+ uint8 nt_pwd[16]; /* nt user passwords */
+
+ uint8 lm_pwd_active;
+ uint8 nt_pwd_active;
+
+} SAM_USER_INFO_12;
+
+/* SAM_USER_INFO_11 */
+typedef struct sam_user_info_11
+{
+ uint8 padding_0[16]; /* 0 - padding 16 bytes */
+ NTTIME expiry; /* expiry time or something? */
+ uint8 padding_1[24]; /* 0 - padding 24 bytes */
+
+ UNIHDR hdr_mach_acct; /* unicode header for machine account */
+ uint32 padding_2; /* 0 - padding 4 bytes */
+
+ uint32 ptr_1; /* pointer */
+ uint8 padding_3[32]; /* 0 - padding 32 bytes */
+ uint32 padding_4; /* 0 - padding 4 bytes */
+
+ uint32 ptr_2; /* pointer */
+ uint32 padding_5; /* 0 - padding 4 bytes */
+
+ uint32 ptr_3; /* pointer */
+ uint8 padding_6[32]; /* 0 - padding 32 bytes */
+
+ uint32 rid_user; /* user RID */
+ uint32 rid_group; /* group RID */
+
+ uint16 acct_ctrl; /* 0080 - ACB_XXXX */
+ uint16 unknown_3; /* 16 bit padding */
+
+ uint16 unknown_4; /* 0x003f - 16 bit unknown */
+ uint16 unknown_5; /* 0x003c - 16 bit unknown */
+
+ uint8 padding_7[16]; /* 0 - padding 16 bytes */
+ uint32 padding_8; /* 0 - padding 4 bytes */
+
+ UNISTR2 uni_mach_acct; /* unicode string for machine account */
+
+ uint8 padding_9[48]; /* 0 - padding 48 bytes */
+
+} SAM_USER_INFO_11;
+
+
+/* SAM_USER_INFO_10 */
+typedef struct sam_user_info_10
+{
+ uint32 acb_info;
+
+} SAM_USER_INFO_10;
+
+
+
+/* SAMR_Q_CLOSE_HND - probably a policy handle close */
+typedef struct q_samr_close_hnd_info
+{
+ POLICY_HND pol; /* policy handle */
+
+} SAMR_Q_CLOSE_HND;
+
+
+/* SAMR_R_CLOSE_HND - probably a policy handle close */
+typedef struct r_samr_close_hnd_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_CLOSE_HND;
+
+
+/****************************************************************************
+SAMR_Q_GET_USRDOM_PWINFO - a "set user info" occurs just after this
+*****************************************************************************/
+
+/* SAMR_Q_GET_USRDOM_PWINFO */
+typedef struct q_samr_usrdom_pwinfo_info
+{
+ POLICY_HND user_pol; /* policy handle */
+
+} SAMR_Q_GET_USRDOM_PWINFO;
+
+
+/****************************************************************************
+SAMR_R_GET_USRDOM_PWINFO - a "set user info" occurs just after this
+*****************************************************************************/
+
+/* SAMR_R_GET_USRDOM_PWINFO */
+typedef struct r_samr_usrdom_pwinfo_info
+{
+ uint16 unknown_0; /* 0000 */
+ uint16 unknown_1; /* 0x0016 or 0x0015 */
+ uint32 unknown_2; /* 0x0000 0000 */
+ NTSTATUS status;
+
+} SAMR_R_GET_USRDOM_PWINFO;
+
+
+/****************************************************************************
+SAMR_Q_QUERY_SEC_OBJ - info level 4. returns SIDs.
+*****************************************************************************/
+
+/* SAMR_Q_QUERY_SEC_OBJ - probably get domain info... */
+typedef struct q_samr_query_sec_obj_info
+{
+ POLICY_HND user_pol; /* policy handle */
+ uint32 sec_info; /* xxxx_SECURITY_INFORMATION 0x0000 0004 */
+
+} SAMR_Q_QUERY_SEC_OBJ;
+
+/* SAMR_R_QUERY_SEC_OBJ - probably an open */
+typedef struct r_samr_query_sec_obj_info
+{
+ uint32 ptr;
+ SEC_DESC_BUF *buf;
+
+ NTSTATUS status; /* return status */
+
+} SAMR_R_QUERY_SEC_OBJ;
+
+
+/****************************************************************************
+SAMR_Q_QUERY_DOMAIN_INFO - probably a query on domain group info.
+*****************************************************************************/
+
+/* SAMR_Q_QUERY_DOMAIN_INFO - */
+typedef struct q_samr_query_domain_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint16 switch_value; /* 0x0002, 0x0001 */
+
+} SAMR_Q_QUERY_DOMAIN_INFO;
+
+typedef struct sam_unknown_info_3_info
+{
+ NTTIME logout;
+ /* 0x8000 0000 */ /* DON'T forcibly disconnect remote users from server when logon hours expire*/
+
+ /* 0x0000 0000 */ /* forcibly disconnect remote users from server when logon hours expire*/
+
+} SAM_UNK_INFO_3;
+
+typedef struct sam_unknown_info_6_info
+{
+ uint32 unknown_0; /* 0x0000 0000 */
+
+ uint32 ptr_0; /* pointer to unknown structure */
+ uint8 padding[12]; /* 12 bytes zeros */
+
+} SAM_UNK_INFO_6;
+
+typedef struct sam_unknown_info_7_info
+{
+ uint16 unknown_0; /* 0x0003 */
+
+} SAM_UNK_INFO_7;
+
+typedef struct sam_unknown_info_12_inf
+{
+ NTTIME duration;
+ NTTIME reset_count;
+ uint16 bad_attempt_lockout;
+
+} SAM_UNK_INFO_12;
+
+typedef struct sam_unknown_info_5_inf
+{
+ UNIHDR hdr_server; /* server name unicode header */
+ UNISTR2 uni_server; /* server name unicode string */
+
+} SAM_UNK_INFO_5;
+
+typedef struct sam_unknown_info_2_inf
+{
+ uint32 unknown_0; /* 0x0000 0000 */
+ uint32 unknown_1; /* 0x8000 0000 */
+ uint32 unknown_2; /* 0x0000 0000 */
+
+ uint32 ptr_0; /* pointer to unknown structure */
+ UNIHDR hdr_domain; /* domain name unicode header */
+ UNIHDR hdr_server; /* server name unicode header */
+
+ /* put all the data in here, at the moment, including what the above
+ pointer is referring to
+ */
+
+ uint32 seq_num; /* some sort of incrementing sequence number? */
+ uint32 unknown_3; /* 0x0000 0000 */
+
+ uint32 unknown_4; /* 0x0000 0001 */
+ uint32 unknown_5; /* 0x0000 0003 */
+ uint32 unknown_6; /* 0x0000 0001 */
+ uint32 num_domain_usrs; /* number of users in domain */
+ uint32 num_domain_grps; /* number of domain groups in domain */
+ uint32 num_local_grps; /* number of local groups in domain */
+
+ uint8 padding[12]; /* 12 bytes zeros */
+
+ UNISTR2 uni_domain; /* domain name unicode string */
+ UNISTR2 uni_server; /* server name unicode string */
+
+} SAM_UNK_INFO_2;
+
+typedef struct sam_unknown_info_1_inf
+{
+ uint16 min_length_password;
+ uint16 password_history;
+ uint32 flag;
+ NTTIME expire;
+ NTTIME min_passwordage;
+
+} SAM_UNK_INFO_1;
+
+
+typedef struct sam_unknown_ctr_info
+{
+ union
+ {
+ SAM_UNK_INFO_1 inf1;
+ SAM_UNK_INFO_2 inf2;
+ SAM_UNK_INFO_3 inf3;
+ SAM_UNK_INFO_5 inf5;
+ SAM_UNK_INFO_6 inf6;
+ SAM_UNK_INFO_7 inf7;
+ SAM_UNK_INFO_12 inf12;
+
+ } info;
+
+} SAM_UNK_CTR;
+
+
+/* SAMR_R_QUERY_DOMAIN_INFO - */
+typedef struct r_samr_query_domain_info
+{
+ uint32 ptr_0;
+ uint16 switch_value; /* same as in query */
+
+ SAM_UNK_CTR *ctr;
+
+ NTSTATUS status; /* return status */
+
+} SAMR_R_QUERY_DOMAIN_INFO;
+
+
+/* SAMR_Q_LOOKUP_DOMAIN - obtain SID for a local domain */
+typedef struct q_samr_lookup_domain_info
+{
+ POLICY_HND connect_pol;
+
+ UNIHDR hdr_domain;
+ UNISTR2 uni_domain;
+
+} SAMR_Q_LOOKUP_DOMAIN;
+
+
+/* SAMR_R_LOOKUP_DOMAIN */
+typedef struct r_samr_lookup_domain_info
+{
+ uint32 ptr_sid;
+ DOM_SID2 dom_sid;
+
+ NTSTATUS status;
+
+} SAMR_R_LOOKUP_DOMAIN;
+
+
+/****************************************************************************
+SAMR_Q_OPEN_DOMAIN - unknown_0 values seen associated with SIDs:
+
+0x0000 03f1 and a specific domain sid - S-1-5-21-44c01ca6-797e5c3d-33f83fd0
+0x0000 0200 and a specific domain sid - S-1-5-21-44c01ca6-797e5c3d-33f83fd0
+*****************************************************************************/
+
+/* SAMR_Q_OPEN_DOMAIN */
+typedef struct q_samr_open_domain_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 flags; /* 0x2000 0000; 0x0000 0211; 0x0000 0280; 0x0000 0200 - flags? */
+ DOM_SID2 dom_sid; /* domain SID */
+
+} SAMR_Q_OPEN_DOMAIN;
+
+
+/* SAMR_R_OPEN_DOMAIN - probably an open */
+typedef struct r_samr_open_domain_info
+{
+ POLICY_HND domain_pol; /* policy handle associated with the SID */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_OPEN_DOMAIN;
+
+#define MAX_SAM_ENTRIES 50
+
+typedef struct samr_entry_info
+{
+ uint32 rid;
+ UNIHDR hdr_name;
+
+} SAM_ENTRY;
+
+
+/* SAMR_Q_ENUM_DOMAINS - SAM rids and names */
+typedef struct q_samr_enum_domains_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 start_idx; /* enumeration handle */
+ uint32 max_size; /* 0x0000 ffff */
+
+} SAMR_Q_ENUM_DOMAINS;
+
+/* SAMR_R_ENUM_DOMAINS - SAM rids and Domain names */
+typedef struct r_samr_enum_domains_info
+{
+ uint32 next_idx; /* next starting index required for enum */
+ uint32 ptr_entries1;
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_dom_name;
+
+ uint32 num_entries4;
+
+ NTSTATUS status;
+
+} SAMR_R_ENUM_DOMAINS;
+
+/* SAMR_Q_ENUM_DOM_USERS - SAM rids and names */
+typedef struct q_samr_enum_dom_users_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 start_idx; /* number of values (0 indicates unlimited?) */
+ uint16 acb_mask; /* 0x0000 indicates all */
+ uint16 unknown_1; /* 0x0000 */
+
+ uint32 max_size; /* 0x0000 ffff */
+
+} SAMR_Q_ENUM_DOM_USERS;
+
+
+/* SAMR_R_ENUM_DOM_USERS - SAM rids and names */
+typedef struct r_samr_enum_dom_users_info
+{
+ uint32 next_idx; /* next starting index required for enum */
+ uint32 ptr_entries1;
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_acct_name;
+
+ uint32 num_entries4;
+
+ NTSTATUS status;
+
+} SAMR_R_ENUM_DOM_USERS;
+
+
+/* SAMR_Q_ENUM_DOM_GROUPS - SAM rids and names */
+typedef struct q_samr_enum_dom_groups_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ /* this is possibly an enumeration context handle... */
+ uint32 start_idx; /* 0x0000 0000 */
+
+ uint32 max_size; /* 0x0000 ffff */
+
+} SAMR_Q_ENUM_DOM_GROUPS;
+
+
+/* SAMR_R_ENUM_DOM_GROUPS - SAM rids and names */
+typedef struct r_samr_enum_dom_groups_info
+{
+ uint32 next_idx;
+ uint32 ptr_entries1;
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_grp_name;
+
+ uint32 num_entries4;
+
+ NTSTATUS status;
+
+} SAMR_R_ENUM_DOM_GROUPS;
+
+
+/* SAMR_Q_ENUM_DOM_ALIASES - SAM rids and names */
+typedef struct q_samr_enum_dom_aliases_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ /* this is possibly an enumeration context handle... */
+ uint32 start_idx; /* 0x0000 0000 */
+
+ uint32 max_size; /* 0x0000 ffff */
+
+} SAMR_Q_ENUM_DOM_ALIASES;
+
+
+/* SAMR_R_ENUM_DOM_ALIASES - SAM rids and names */
+typedef struct r_samr_enum_dom_aliases_info
+{
+ uint32 next_idx;
+ uint32 ptr_entries1;
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_grp_name;
+
+ uint32 num_entries4;
+
+ NTSTATUS status;
+
+} SAMR_R_ENUM_DOM_ALIASES;
+
+
+/* -- Level 1 Display Info - User Information -- */
+
+typedef struct samr_entry_info1
+{
+ uint32 user_idx;
+
+ uint32 rid_user;
+ uint16 acb_info;
+ uint16 pad;
+
+ UNIHDR hdr_acct_name;
+ UNIHDR hdr_user_name;
+ UNIHDR hdr_user_desc;
+
+} SAM_ENTRY1;
+
+typedef struct samr_str_entry_info1
+{
+ UNISTR2 uni_acct_name;
+ UNISTR2 uni_full_name;
+ UNISTR2 uni_acct_desc;
+
+} SAM_STR1;
+
+typedef struct sam_entry_info_1
+{
+ SAM_ENTRY1 *sam;
+ SAM_STR1 *str;
+
+} SAM_DISPINFO_1;
+
+
+/* -- Level 2 Display Info - Trust Account Information -- */
+
+typedef struct samr_entry_info2
+{
+ uint32 user_idx;
+
+ uint32 rid_user;
+ uint16 acb_info;
+ uint16 pad;
+
+ UNIHDR hdr_srv_name;
+ UNIHDR hdr_srv_desc;
+
+} SAM_ENTRY2;
+
+typedef struct samr_str_entry_info2
+{
+ UNISTR2 uni_srv_name;
+ UNISTR2 uni_srv_desc;
+
+} SAM_STR2;
+
+typedef struct sam_entry_info_2
+{
+ SAM_ENTRY2 *sam;
+ SAM_STR2 *str;
+
+} SAM_DISPINFO_2;
+
+
+/* -- Level 3 Display Info - Domain Group Information -- */
+
+typedef struct samr_entry_info3
+{
+ uint32 grp_idx;
+
+ uint32 rid_grp;
+ uint32 attr; /* SE_GROUP_xxx, usually 7 */
+
+ UNIHDR hdr_grp_name;
+ UNIHDR hdr_grp_desc;
+
+} SAM_ENTRY3;
+
+typedef struct samr_str_entry_info3
+{
+ UNISTR2 uni_grp_name;
+ UNISTR2 uni_grp_desc;
+
+} SAM_STR3;
+
+typedef struct sam_entry_info_3
+{
+ SAM_ENTRY3 *sam;
+ SAM_STR3 *str;
+
+} SAM_DISPINFO_3;
+
+
+/* -- Level 4 Display Info - User List (ASCII) -- */
+
+typedef struct samr_entry_info4
+{
+ uint32 user_idx;
+ STRHDR hdr_acct_name;
+
+} SAM_ENTRY4;
+
+typedef struct samr_str_entry_info4
+{
+ STRING2 acct_name;
+
+} SAM_STR4;
+
+typedef struct sam_entry_info_4
+{
+ SAM_ENTRY4 *sam;
+ SAM_STR4 *str;
+
+} SAM_DISPINFO_4;
+
+
+/* -- Level 5 Display Info - Group List (ASCII) -- */
+
+typedef struct samr_entry_info5
+{
+ uint32 grp_idx;
+ STRHDR hdr_grp_name;
+
+} SAM_ENTRY5;
+
+typedef struct samr_str_entry_info5
+{
+ STRING2 grp_name;
+
+} SAM_STR5;
+
+typedef struct sam_entry_info_5
+{
+ SAM_ENTRY5 *sam;
+ SAM_STR5 *str;
+
+} SAM_DISPINFO_5;
+
+
+typedef struct sam_dispinfo_ctr_info
+{
+ union
+ {
+ SAM_DISPINFO_1 *info1; /* users/names/descriptions */
+ SAM_DISPINFO_2 *info2; /* trust accounts */
+ SAM_DISPINFO_3 *info3; /* domain groups/descriptions */
+ SAM_DISPINFO_4 *info4; /* user list (ASCII) - used by Win95 */
+ SAM_DISPINFO_5 *info5; /* group list (ASCII) */
+ void *info; /* allows assignment without typecasting, */
+
+ } sam;
+
+} SAM_DISPINFO_CTR;
+
+
+/* SAMR_Q_QUERY_DISPINFO - SAM rids, names and descriptions */
+typedef struct q_samr_query_disp_info
+{
+ POLICY_HND domain_pol;
+
+ uint16 switch_level; /* see SAM_DISPINFO_CTR above */
+ /* align */
+
+ uint32 start_idx; /* start enumeration index */
+ uint32 max_entries; /* maximum number of entries to return */
+ uint32 max_size; /* recommended data size; if exceeded server
+ should return STATUS_MORE_ENTRIES */
+
+} SAMR_Q_QUERY_DISPINFO;
+
+
+/* SAMR_R_QUERY_DISPINFO */
+typedef struct r_samr_query_dispinfo_info
+{
+ uint32 total_size; /* total data size for all matching entries
+ (0 = uncalculated) */
+ uint32 data_size; /* actual data size returned = size of SAM_ENTRY
+ structures + total length of strings */
+
+ uint16 switch_level; /* see SAM_DISPINFO_CTR above */
+ /* align */
+
+ uint32 num_entries; /* number of entries returned */
+ uint32 ptr_entries;
+ uint32 num_entries2;
+
+ SAM_DISPINFO_CTR *ctr;
+
+ NTSTATUS status;
+
+} SAMR_R_QUERY_DISPINFO;
+
+
+/* SAMR_Q_DELETE_DOM_GROUP - delete domain group */
+typedef struct q_samr_delete_dom_group_info
+{
+ POLICY_HND group_pol; /* policy handle */
+
+} SAMR_Q_DELETE_DOM_GROUP;
+
+
+/* SAMR_R_DELETE_DOM_GROUP - delete domain group */
+typedef struct r_samr_delete_dom_group_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_DELETE_DOM_GROUP;
+
+
+/* SAMR_Q_CREATE_DOM_GROUP - SAM create group */
+typedef struct q_samr_create_dom_group_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ UNIHDR hdr_acct_desc;
+ UNISTR2 uni_acct_desc;
+
+ uint32 access_mask;
+
+} SAMR_Q_CREATE_DOM_GROUP;
+
+/* SAMR_R_CREATE_DOM_GROUP - SAM create group */
+typedef struct r_samr_create_dom_group_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 rid;
+ NTSTATUS status;
+
+} SAMR_R_CREATE_DOM_GROUP;
+
+/* SAMR_Q_QUERY_GROUPINFO - SAM Group Info */
+typedef struct q_samr_query_group_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint16 switch_level; /* 0x0001 seen */
+
+} SAMR_Q_QUERY_GROUPINFO;
+
+typedef struct samr_group_info1
+{
+ UNIHDR hdr_acct_name;
+
+ uint32 unknown_1; /* 0x0000 0003 - number of group members? */
+ uint32 num_members; /* 0x0000 0001 - number of group members? */
+
+ UNIHDR hdr_acct_desc;
+
+ UNISTR2 uni_acct_name;
+ UNISTR2 uni_acct_desc;
+
+} GROUP_INFO1;
+
+typedef struct samr_group_info3
+{
+ uint32 unknown_1; /* 0x0000 0003 - number of group members? */
+
+} GROUP_INFO3;
+
+typedef struct samr_group_info4
+{
+ UNIHDR hdr_acct_desc;
+ UNISTR2 uni_acct_desc;
+
+} GROUP_INFO4;
+
+/* GROUP_INFO_CTR */
+typedef struct group_info_ctr
+{
+ uint16 switch_value1;
+
+ union
+ {
+ GROUP_INFO1 info1;
+ GROUP_INFO3 info3;
+ GROUP_INFO4 info4;
+
+ } group;
+
+} GROUP_INFO_CTR;
+
+/* SAMR_R_QUERY_GROUPINFO - SAM Group Info */
+typedef struct r_samr_query_groupinfo_info
+{
+ uint32 ptr;
+ GROUP_INFO_CTR *ctr;
+
+ NTSTATUS status;
+
+} SAMR_R_QUERY_GROUPINFO;
+
+
+/* SAMR_Q_SET_GROUPINFO - SAM Group Info */
+typedef struct q_samr_set_group_info
+{
+ POLICY_HND pol; /* policy handle */
+ GROUP_INFO_CTR *ctr;
+
+} SAMR_Q_SET_GROUPINFO;
+
+/* SAMR_R_SET_GROUPINFO - SAM Group Info */
+typedef struct r_samr_set_group_info
+{
+ NTSTATUS status;
+
+} SAMR_R_SET_GROUPINFO;
+
+
+/* SAMR_Q_DELETE_DOM_ALIAS - delete domain alias */
+typedef struct q_samr_delete_dom_alias_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+} SAMR_Q_DELETE_DOM_ALIAS;
+
+
+/* SAMR_R_DELETE_DOM_ALIAS - delete domain alias */
+typedef struct r_samr_delete_dom_alias_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_DELETE_DOM_ALIAS;
+
+
+/* SAMR_Q_CREATE_DOM_ALIAS - SAM create alias */
+typedef struct q_samr_create_dom_alias_info
+{
+ POLICY_HND dom_pol; /* policy handle */
+
+ UNIHDR hdr_acct_desc;
+ UNISTR2 uni_acct_desc;
+
+ uint32 access_mask; /* 0x001f000f */
+
+} SAMR_Q_CREATE_DOM_ALIAS;
+
+/* SAMR_R_CREATE_DOM_ALIAS - SAM create alias */
+typedef struct r_samr_create_dom_alias_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+ uint32 rid;
+ NTSTATUS status;
+
+} SAMR_R_CREATE_DOM_ALIAS;
+
+/* SAMR_Q_QUERY_ALIASINFO - SAM Alias Info */
+typedef struct q_samr_query_alias_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint16 switch_level; /* 0x0003 seen */
+
+} SAMR_Q_QUERY_ALIASINFO;
+
+typedef struct samr_alias_info1
+{
+ UNIHDR hdr_acct_name;
+ UNIHDR hdr_acct_desc;
+ uint32 num_member;
+ UNISTR2 uni_acct_name;
+ UNISTR2 uni_acct_desc;
+
+} ALIAS_INFO1;
+
+typedef struct samr_alias_info3
+{
+ UNIHDR hdr_acct_desc;
+ UNISTR2 uni_acct_desc;
+
+} ALIAS_INFO3;
+
+/* ALIAS_INFO_CTR */
+typedef struct alias_info_ctr
+{
+ uint16 switch_value1;
+ uint16 switch_value2;
+
+ union
+ {
+ ALIAS_INFO1 info1;
+ ALIAS_INFO3 info3;
+
+ } alias;
+
+} ALIAS_INFO_CTR;
+
+/* SAMR_R_QUERY_ALIASINFO - SAM alias info */
+typedef struct r_samr_query_aliasinfo_info
+{
+ uint32 ptr;
+ ALIAS_INFO_CTR ctr;
+
+ NTSTATUS status;
+
+} SAMR_R_QUERY_ALIASINFO;
+
+
+/* SAMR_Q_SET_ALIASINFO - SAM Alias Info */
+typedef struct q_samr_set_alias_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+ ALIAS_INFO_CTR ctr;
+
+} SAMR_Q_SET_ALIASINFO;
+
+/* SAMR_R_SET_ALIASINFO - SAM alias info */
+typedef struct r_samr_set_aliasinfo_info
+{
+ NTSTATUS status;
+
+} SAMR_R_SET_ALIASINFO;
+
+
+/* SAMR_Q_QUERY_USERGROUPS - */
+typedef struct q_samr_query_usergroup_info
+{
+ POLICY_HND pol; /* policy handle associated with unknown id */
+
+} SAMR_Q_QUERY_USERGROUPS;
+
+/* SAMR_R_QUERY_USERGROUPS - probably a get sam info */
+typedef struct r_samr_query_usergroup_info
+{
+ uint32 ptr_0; /* pointer */
+ uint32 num_entries; /* number of RID groups */
+ uint32 ptr_1; /* pointer */
+ uint32 num_entries2; /* number of RID groups */
+
+ DOM_GID *gid; /* group info */
+
+ NTSTATUS status; /* return status */
+
+} SAMR_R_QUERY_USERGROUPS;
+
+/* SAM_USERINFO_CTR - sam user info */
+typedef struct sam_userinfo_ctr_info
+{
+ uint16 switch_value;
+
+ union
+ {
+ SAM_USER_INFO_10 *id10; /* auth-level 0x10 */
+ SAM_USER_INFO_11 *id11; /* auth-level 0x11 */
+ SAM_USER_INFO_12 *id12; /* auth-level 0x12 */
+ SAM_USER_INFO_20 *id20; /* auth-level 20 */
+ SAM_USER_INFO_21 *id21; /* auth-level 21 */
+ SAM_USER_INFO_23 *id23; /* auth-level 0x17 */
+ SAM_USER_INFO_24 *id24; /* auth-level 0x18 */
+ SAM_USER_INFO_25 *id25; /* auth-level 0x19 */
+ void* id; /* to make typecasting easy */
+
+ } info;
+
+} SAM_USERINFO_CTR;
+
+
+/* SAMR_Q_SET_USERINFO2 - set sam info */
+typedef struct q_samr_set_user_info2
+{
+ POLICY_HND pol; /* policy handle associated with user */
+ uint16 switch_value; /* 0x0010 */
+
+ SAM_USERINFO_CTR *ctr;
+
+} SAMR_Q_SET_USERINFO2;
+
+/* SAMR_R_SET_USERINFO2 - set sam info */
+typedef struct r_samr_set_user_info2
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_SET_USERINFO2;
+
+/* SAMR_Q_SET_USERINFO - set sam info */
+typedef struct q_samr_set_user_info
+{
+ POLICY_HND pol; /* policy handle associated with user */
+ uint16 switch_value;
+ SAM_USERINFO_CTR *ctr;
+
+} SAMR_Q_SET_USERINFO;
+
+/* SAMR_R_SET_USERINFO - set sam info */
+typedef struct r_samr_set_user_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_SET_USERINFO;
+
+
+/* SAMR_Q_QUERY_USERINFO - probably a get sam info */
+typedef struct q_samr_query_user_info
+{
+ POLICY_HND pol; /* policy handle associated with unknown id */
+ uint16 switch_value; /* 0x0015, 0x0011 or 0x0010 - 16 bit unknown */
+
+} SAMR_Q_QUERY_USERINFO;
+
+/* SAMR_R_QUERY_USERINFO - probably a get sam info */
+typedef struct r_samr_query_user_info
+{
+ uint32 ptr; /* pointer */
+ SAM_USERINFO_CTR *ctr;
+
+ NTSTATUS status; /* return status */
+
+} SAMR_R_QUERY_USERINFO;
+
+
+/****************************************************************************
+SAMR_Q_QUERY_USERALIASES - do a conversion from name to RID.
+
+the policy handle allocated by an "samr open secret" call is associated
+with a SID. this policy handle is what is queried here, *not* the SID
+itself. the response to the lookup rids is relative to this SID.
+*****************************************************************************/
+/* SAMR_Q_QUERY_USERALIASES */
+typedef struct q_samr_query_useraliases_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_sids1; /* number of rids being looked up */
+ uint32 ptr; /* buffer pointer */
+ uint32 num_sids2; /* number of rids being looked up */
+
+ uint32 *ptr_sid; /* pointers to sids to be looked up */
+ DOM_SID2 *sid ; /* sids to be looked up. */
+
+} SAMR_Q_QUERY_USERALIASES;
+
+
+/* SAMR_R_QUERY_USERALIASES */
+typedef struct r_samr_query_useraliases_info
+{
+ uint32 num_entries;
+ uint32 ptr; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ uint32 *rid; /* domain RIDs being looked up */
+
+ NTSTATUS status; /* return code */
+
+} SAMR_R_QUERY_USERALIASES;
+
+
+/****************************************************************************
+SAMR_Q_LOOKUP_NAMES - do a conversion from Names to RIDs+types.
+*****************************************************************************/
+/* SAMR_Q_LOOKUP_NAMES */
+typedef struct q_samr_lookup_names_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_names1; /* number of names being looked up */
+ uint32 flags; /* 0x0000 03e8 - unknown */
+ uint32 ptr; /* 0x0000 0000 - 32 bit unknown */
+ uint32 num_names2; /* number of names being looked up */
+
+ UNIHDR *hdr_name; /* unicode account name header */
+ UNISTR2 *uni_name; /* unicode account name string */
+
+} SAMR_Q_LOOKUP_NAMES;
+
+
+/* SAMR_R_LOOKUP_NAMES */
+typedef struct r_samr_lookup_names_info
+{
+ uint32 num_rids1; /* number of aliases being looked up */
+ uint32 ptr_rids; /* pointer to aliases */
+ uint32 num_rids2; /* number of aliases being looked up */
+
+ uint32 *rids; /* rids */
+
+ uint32 num_types1; /* number of users in aliases being looked up */
+ uint32 ptr_types; /* pointer to users in aliases */
+ uint32 num_types2; /* number of users in aliases being looked up */
+
+ uint32 *types; /* SID_ENUM type */
+
+ NTSTATUS status; /* return code */
+
+} SAMR_R_LOOKUP_NAMES;
+
+
+/****************************************************************************
+SAMR_Q_LOOKUP_RIDS - do a conversion from RID groups to something.
+
+called to resolve domain RID groups.
+*****************************************************************************/
+/* SAMR_Q_LOOKUP_RIDS */
+typedef struct q_samr_lookup_rids_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_rids1; /* number of rids being looked up */
+ uint32 flags; /* 0x0000 03e8 - unknown */
+ uint32 ptr; /* 0x0000 0000 - 32 bit unknown */
+ uint32 num_rids2; /* number of rids being looked up */
+
+ uint32 *rid; /* domain RIDs being looked up */
+
+} SAMR_Q_LOOKUP_RIDS;
+
+
+/****************************************************************************
+SAMR_R_LOOKUP_RIDS - do a conversion from group RID to names
+
+*****************************************************************************/
+/* SAMR_R_LOOKUP_RIDS */
+typedef struct r_samr_lookup_rids_info
+{
+ uint32 num_names1; /* number of aliases being looked up */
+ uint32 ptr_names; /* pointer to aliases */
+ uint32 num_names2; /* number of aliases being looked up */
+
+ UNIHDR *hdr_name; /* unicode account name header */
+ UNISTR2 *uni_name; /* unicode account name string */
+
+ uint32 num_types1; /* number of users in aliases being looked up */
+ uint32 ptr_types; /* pointer to users in aliases */
+ uint32 num_types2; /* number of users in aliases being looked up */
+
+ uint32 *type; /* SID_ENUM type */
+
+ NTSTATUS status;
+
+} SAMR_R_LOOKUP_RIDS;
+
+
+/* SAMR_Q_OPEN_USER - probably an open */
+typedef struct q_samr_open_user_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint32 access_mask; /* 32 bit unknown - 0x02011b */
+ uint32 user_rid; /* user RID */
+
+} SAMR_Q_OPEN_USER;
+
+
+/* SAMR_R_OPEN_USER - probably an open */
+typedef struct r_samr_open_user_info
+{
+ POLICY_HND user_pol; /* policy handle associated with unknown id */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_OPEN_USER;
+
+
+/* SAMR_Q_CREATE_USER - probably a create */
+typedef struct q_samr_create_user_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+
+ UNIHDR hdr_name; /* unicode account name header */
+ UNISTR2 uni_name; /* unicode account name */
+
+ uint32 acb_info; /* account control info */
+ uint32 access_mask; /* 0xe005 00b0 */
+
+} SAMR_Q_CREATE_USER;
+
+
+/* SAMR_R_CREATE_USER - probably a create */
+typedef struct r_samr_create_user_info
+{
+ POLICY_HND user_pol; /* policy handle associated with user */
+
+ uint32 unknown_0; /* 0x0007 03ff */
+ uint32 user_rid; /* user RID */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_CREATE_USER;
+
+
+/* SAMR_Q_DELETE_DOM_USER - delete domain user */
+typedef struct q_samr_delete_dom_user_info
+{
+ POLICY_HND user_pol; /* policy handle */
+
+} SAMR_Q_DELETE_DOM_USER;
+
+
+/* SAMR_R_DELETE_DOM_USER - delete domain user */
+typedef struct r_samr_delete_dom_user_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_DELETE_DOM_USER;
+
+
+/* SAMR_Q_QUERY_GROUPMEM - query group members */
+typedef struct q_samr_query_groupmem_info
+{
+ POLICY_HND group_pol; /* policy handle */
+
+} SAMR_Q_QUERY_GROUPMEM;
+
+
+/* SAMR_R_QUERY_GROUPMEM - query group members */
+typedef struct r_samr_query_groupmem_info
+{
+ uint32 ptr;
+ uint32 num_entries;
+
+ uint32 ptr_rids;
+ uint32 ptr_attrs;
+
+ uint32 num_rids;
+ uint32 *rid;
+
+ uint32 num_attrs;
+ uint32 *attr;
+
+ NTSTATUS status;
+
+} SAMR_R_QUERY_GROUPMEM;
+
+
+/* SAMR_Q_DEL_GROUPMEM - probably an del group member */
+typedef struct q_samr_del_group_mem_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 rid; /* rid */
+
+} SAMR_Q_DEL_GROUPMEM;
+
+
+/* SAMR_R_DEL_GROUPMEM - probably an del group member */
+typedef struct r_samr_del_group_mem_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_DEL_GROUPMEM;
+
+
+/* SAMR_Q_ADD_GROUPMEM - probably an add group member */
+typedef struct q_samr_add_group_mem_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 rid; /* rid */
+ uint32 unknown; /* 0x0000 0005 */
+
+} SAMR_Q_ADD_GROUPMEM;
+
+
+/* SAMR_R_ADD_GROUPMEM - probably an add group member */
+typedef struct r_samr_add_group_mem_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_ADD_GROUPMEM;
+
+
+/* SAMR_Q_OPEN_GROUP - probably an open */
+typedef struct q_samr_open_group_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint32 access_mask; /* 0x0000 0001, 0x0000 0003, 0x0000 001f */
+ uint32 rid_group; /* rid */
+
+} SAMR_Q_OPEN_GROUP;
+
+
+/* SAMR_R_OPEN_GROUP - probably an open */
+typedef struct r_samr_open_group_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_OPEN_GROUP;
+
+
+/* SAMR_Q_QUERY_ALIASMEM - query alias members */
+typedef struct q_samr_query_aliasmem_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+} SAMR_Q_QUERY_ALIASMEM;
+
+
+/* SAMR_R_QUERY_ALIASMEM - query alias members */
+typedef struct r_samr_query_aliasmem_info
+{
+ uint32 num_sids;
+ uint32 ptr;
+ uint32 num_sids1;
+
+ DOM_SID2 *sid;
+
+ NTSTATUS status;
+
+} SAMR_R_QUERY_ALIASMEM;
+
+
+/* SAMR_Q_ADD_ALIASMEM - add alias member */
+typedef struct q_samr_add_alias_mem_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+ DOM_SID2 sid; /* member sid to be added to the alias */
+
+} SAMR_Q_ADD_ALIASMEM;
+
+
+/* SAMR_R_ADD_ALIASMEM - add alias member */
+typedef struct r_samr_add_alias_mem_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_ADD_ALIASMEM;
+
+
+/* SAMR_Q_DEL_ALIASMEM - add an add alias member */
+typedef struct q_samr_del_alias_mem_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+ DOM_SID2 sid; /* member sid to be added to alias */
+
+} SAMR_Q_DEL_ALIASMEM;
+
+
+/* SAMR_R_DEL_ALIASMEM - delete alias member */
+typedef struct r_samr_del_alias_mem_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_DEL_ALIASMEM;
+
+
+
+/* SAMR_Q_OPEN_ALIAS - probably an open */
+typedef struct q_samr_open_alias_info
+{
+ POLICY_HND dom_pol;
+
+ uint32 access_mask;
+ uint32 rid_alias;
+
+} SAMR_Q_OPEN_ALIAS;
+
+
+/* SAMR_R_OPEN_ALIAS - probably an open */
+typedef struct r_samr_open_alias_info
+{
+ POLICY_HND pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_OPEN_ALIAS;
+
+
+/* SAMR_Q_CONNECT_ANON - probably an open */
+typedef struct q_samr_connect_anon_info
+{
+ uint32 ptr; /* ptr? */
+ uint16 unknown_0; /* 0x005c */
+ uint16 unknown_1; /* 0x0001 */
+ uint32 access_mask;
+
+} SAMR_Q_CONNECT_ANON;
+
+/* SAMR_R_CONNECT_ANON - probably an open */
+typedef struct r_samr_connect_anon_info
+{
+ POLICY_HND connect_pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_CONNECT_ANON;
+
+/* SAMR_Q_CONNECT - probably an open */
+typedef struct q_samr_connect_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* unicode server name starting with '\\' */
+
+ uint32 access_mask;
+
+} SAMR_Q_CONNECT;
+
+
+/* SAMR_R_CONNECT - probably an open */
+typedef struct r_samr_connect_info
+{
+ POLICY_HND connect_pol; /* policy handle */
+ NTSTATUS status; /* return status */
+
+} SAMR_R_CONNECT;
+
+/* SAMR_Q_GET_DOM_PWINFO */
+typedef struct q_samr_get_dom_pwinfo
+{
+ uint32 ptr;
+ UNIHDR hdr_srv_name;
+ UNISTR2 uni_srv_name;
+
+} SAMR_Q_GET_DOM_PWINFO;
+
+/* SAMR_R_GET_DOM_PWINFO */
+typedef struct r_samr_get_dom_pwinfo
+{
+ uint16 unk_0;
+ uint16 unk_1;
+ uint16 unk_2;
+ NTSTATUS status;
+
+} SAMR_R_GET_DOM_PWINFO;
+
+/* SAMR_ENC_PASSWD */
+typedef struct enc_passwd_info
+{
+ uint32 ptr;
+ uint8 pass[516];
+
+} SAMR_ENC_PASSWD;
+
+/* SAMR_ENC_HASH */
+typedef struct enc_hash_info
+{
+ uint32 ptr;
+ uint8 hash[16];
+
+} SAMR_ENC_HASH;
+
+/* SAMR_Q_CHGPASSWD_USER */
+typedef struct q_samr_chgpasswd_user_info
+{
+ uint32 ptr_0;
+
+ UNIHDR hdr_dest_host; /* server name unicode header */
+ UNISTR2 uni_dest_host; /* server name unicode string */
+
+ UNIHDR hdr_user_name; /* username unicode string header */
+ UNISTR2 uni_user_name; /* username unicode string */
+
+ SAMR_ENC_PASSWD nt_newpass;
+ SAMR_ENC_HASH nt_oldhash;
+
+ uint32 unknown; /* 0x0000 0001 */
+
+ SAMR_ENC_PASSWD lm_newpass;
+ SAMR_ENC_HASH lm_oldhash;
+
+} SAMR_Q_CHGPASSWD_USER;
+
+/* SAMR_R_CHGPASSWD_USER */
+typedef struct r_samr_chgpasswd_user_info
+{
+ NTSTATUS status; /* 0 == OK, C000006A (NT_STATUS_WRONG_PASSWORD) */
+
+} SAMR_R_CHGPASSWD_USER;
+
+
+/* SAMR_Q_UNKNOWN_2D */
+typedef struct q_samr_unknown_2d_info
+{
+ POLICY_HND dom_pol; /* policy handle */
+ DOM_SID2 sid; /* SID */
+
+} SAMR_Q_UNKNOWN_2D;
+
+
+/* SAMR_R_UNKNOWN_2D - probably an open */
+typedef struct r_samr_unknown_2d_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_UNKNOWN_2D;
+
+
+
+/* these are from the old rpc_samr.h - they are needed while the merge
+ is still going on */
+#define MAX_SAM_SIDS 15
+
+/* DOM_SID3 - security id */
+typedef struct sid_info_3
+{
+ uint16 len; /* length, bytes, including length of len :-) */
+ /* uint8 pad[2]; */
+
+ DOM_SID sid;
+
+} DOM_SID3;
+
+/* SAMR_Q_UNKNOWN_2E */
+typedef struct q_samr_unknown_2e_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint16 switch_value;
+
+} SAMR_Q_UNKNOWN_2E;
+
+/* SAMR_R_UNKNOWN_2E */
+typedef struct r_samr_unknown_2e_info
+{
+ uint32 ptr_0;
+ uint16 switch_value;
+ SAM_UNK_CTR *ctr;
+ NTSTATUS status; /* return status */
+
+} SAMR_R_UNKNOWN_2E;
+
+/* SAMR_Q_SET_DOMAIN_INFO */
+typedef struct q_samr_set_domain_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint16 switch_value0;
+ uint16 switch_value;
+ SAM_UNK_CTR *ctr;
+
+} SAMR_Q_SET_DOMAIN_INFO;
+
+/* SAMR_R_SET_DOMAIN_INFO */
+typedef struct r_samr_set_domain_info
+{
+ NTSTATUS status; /* return status */
+
+} SAMR_R_SET_DOMAIN_INFO;
+
+
+#endif /* _RPC_SAMR_H */
+
diff --git a/source/include/rpc_secdes.h b/source/include/rpc_secdes.h
new file mode 100644
index 00000000000..259c1567675
--- /dev/null
+++ b/source/include/rpc_secdes.h
@@ -0,0 +1,175 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_SECDES_H /* _RPC_SECDES_H */
+#define _RPC_SECDES_H
+
+#define SEC_RIGHTS_QUERY_VALUE 0x00000001
+#define SEC_RIGHTS_SET_VALUE 0x00000002
+#define SEC_RIGHTS_CREATE_SUBKEY 0x00000004
+#define SEC_RIGHTS_ENUM_SUBKEYS 0x00000008
+#define SEC_RIGHTS_NOTIFY 0x00000010
+#define SEC_RIGHTS_CREATE_LINK 0x00000020
+
+#define SEC_RIGHTS_READ 0x00020019
+#define SEC_RIGHTS_FULL_CONTROL 0x000f003f
+#define SEC_RIGHTS_MAXIMUM_ALLOWED 0x02000000
+
+#define SEC_ACE_TYPE_ACCESS_ALLOWED 0x0
+#define SEC_ACE_TYPE_ACCESS_DENIED 0x1
+#define SEC_ACE_TYPE_SYSTEM_AUDIT 0x2
+#define SEC_ACE_TYPE_SYSTEM_ALARM 0x3
+
+#define SEC_ACE_FLAG_OBJECT_INHERIT 0x1
+#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x2
+#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x4
+#define SEC_ACE_FLAG_INHERIT_ONLY 0x8
+#define SEC_ACE_FLAG_INHERITED_ACE 0x10 /* New for Windows 2000 */
+#define SEC_ACE_FLAG_VALID_INHERIT 0xf
+#define SEC_ACE_FLAG_SUCCESSFUL_ACCESS 0x40
+#define SEC_ACE_FLAG_FAILED_ACCESS 0x80
+
+#define SEC_DESC_OWNER_DEFAULTED 0x0001
+#define SEC_DESC_GROUP_DEFAULTED 0x0002
+#define SEC_DESC_DACL_PRESENT 0x0004
+#define SEC_DESC_DACL_DEFAULTED 0x0008
+#define SEC_DESC_SACL_PRESENT 0x0010
+#define SEC_DESC_SACL_DEFAULTED 0x0020
+/*
+ * New Windows 2000 bits.
+ */
+#define SE_DESC_DACL_AUTO_INHERIT_REQ 0x0100
+#define SE_DESC_SACL_AUTO_INHERIT_REQ 0x0200
+#define SE_DESC_DACL_AUTO_INHERITED 0x0400
+#define SE_DESC_SACL_AUTO_INHERITED 0x0800
+#define SE_DESC_DACL_PROTECTED 0x1000
+#define SE_DESC_SACL_PROTECTED 0x2000
+
+#define SEC_DESC_SELF_RELATIVE 0x8000
+
+/* security information */
+
+#define OWNER_SECURITY_INFORMATION 0x00000001
+#define GROUP_SECURITY_INFORMATION 0x00000002
+#define DACL_SECURITY_INFORMATION 0x00000004
+#define SACL_SECURITY_INFORMATION 0x00000008
+
+#define ALL_SECURITY_INFORMATION (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|\
+ DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION)
+
+#ifndef _SEC_ACCESS
+/* SEC_ACCESS */
+typedef struct security_info_info
+{
+ uint32 mask;
+
+} SEC_ACCESS;
+#define _SEC_ACCESS
+#endif
+
+#ifndef _SEC_ACE
+/* SEC_ACE */
+typedef struct security_ace_info
+{
+ uint8 type; /* xxxx_xxxx_ACE_TYPE - e.g allowed / denied etc */
+ uint8 flags; /* xxxx_INHERIT_xxxx - e.g OBJECT_INHERIT_ACE */
+ uint16 size;
+
+ SEC_ACCESS info;
+ DOM_SID trustee;
+
+} SEC_ACE;
+#define _SEC_ACE
+#endif
+
+#ifndef ACL_REVISION
+#define ACL_REVISION 0x3
+#endif
+
+#ifndef NT4_ACL_REVISION
+#define NT4_ACL_REVISION 0x2
+#endif
+
+#ifndef _SEC_ACL
+/* SEC_ACL */
+typedef struct security_acl_info
+{
+ uint16 revision; /* 0x0003 */
+ uint16 size; /* size in bytes of the entire ACL structure */
+ uint32 num_aces; /* number of Access Control Entries */
+
+ SEC_ACE *ace;
+
+} SEC_ACL;
+#define _SEC_ACL
+#endif
+
+#ifndef SEC_DESC_REVISION
+#define SEC_DESC_REVISION 0x1
+#endif
+
+#ifndef _SEC_DESC
+/* SEC_DESC */
+typedef struct security_descriptor_info
+{
+ uint16 revision; /* 0x0001 */
+ uint16 type; /* SEC_DESC_xxxx flags */
+
+ uint32 off_owner_sid; /* offset to owner sid */
+ uint32 off_grp_sid ; /* offset to group sid */
+ uint32 off_sacl ; /* offset to system list of permissions */
+ uint32 off_dacl ; /* offset to list of permissions */
+
+ SEC_ACL *dacl; /* user ACL */
+ SEC_ACL *sacl; /* system ACL */
+ DOM_SID *owner_sid;
+ DOM_SID *grp_sid;
+
+} SEC_DESC;
+#define _SEC_DESC
+#endif
+
+#ifndef _SEC_DESC_BUF
+/* SEC_DESC_BUF */
+typedef struct sec_desc_buf_info
+{
+ uint32 max_len;
+ uint32 ptr;
+ uint32 len;
+
+ SEC_DESC *sec;
+
+} SEC_DESC_BUF;
+#define _SEC_DESC_BUF
+#endif
+
+/* A type to describe the mapping of generic access rights to object
+ specific access rights. */
+
+typedef struct generic_mapping {
+ uint32 generic_read;
+ uint32 generic_write;
+ uint32 generic_execute;
+ uint32 generic_all;
+} GENERIC_MAPPING;
+
+#endif /* _RPC_SECDES_H */
diff --git a/source/include/rpc_spoolss.h b/source/include/rpc_spoolss.h
new file mode 100755
index 00000000000..bd9de92dcb7
--- /dev/null
+++ b/source/include/rpc_spoolss.h
@@ -0,0 +1,1987 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ Copyright (C) Jean Francois Micouleau 1998-2000,
+ Copyright (C) Tim Potter 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_SPOOLSS_H /* _RPC_SPOOLSS_H */
+#define _RPC_SPOOLSS_H
+
+#define INTEGER 1
+#define STRING 2
+
+/* spoolss pipe: this are the calls which are not implemented ...
+#define SPOOLSS_OPENPRINTER 0x01
+#define SPOOLSS_GETPRINTERDRIVER 0x0b
+#define SPOOLSS_READPRINTER 0x16
+#define SPOOLSS_WAITFORPRINTERCHANGE 0x1c
+#define SPOOLSS_ADDPORT 0x25
+#define SPOOLSS_CONFIGUREPORT 0x26
+#define SPOOLSS_DELETEPORT 0x27
+#define SPOOLSS_CREATEPRINTERIC 0x28
+#define SPOOLSS_PLAYGDISCRIPTONPRINTERIC 0x29
+#define SPOOLSS_DELETEPRINTERIC 0x2a
+#define SPOOLSS_ADDPRINTERCONNECTION 0x2b
+#define SPOOLSS_DELETEPRINTERCONNECTION 0x2c
+#define SPOOLSS_PRINTERMESSAGEBOX 0x2d
+#define SPOOLSS_ADDMONITOR 0x2e
+#define SPOOLSS_DELETEMONITOR 0x2f
+#define SPOOLSS_DELETEPRINTPROCESSOR 0x30
+#define SPOOLSS_ADDPRINTPROVIDOR 0x31
+#define SPOOLSS_DELETEPRINTPROVIDOR 0x32
+#define SPOOLSS_RESETPRINTER 0x34
+#define SPOOLSS_FINDFIRSTPRINTERCHANGENOTIFICATION 0x36
+#define SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION 0x37
+#define SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD 0x39
+#define SPOOLSS_ROUTERREPLYPRINTER 0x3b
+#define SPOOLSS_ADDPORTEX 0x3d
+#define SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION0x3e
+#define SPOOLSS_SPOOLERINIT 0x3f
+#define SPOOLSS_RESETPRINTEREX 0x40
+#define SPOOLSS_ROUTERREFRESHPRINTERCHANGENOTIFICATION 0x42
+#define SPOOLSS_DELETEPRINTERDATAEX 0x51
+#define SPOOLSS_DELETEPRINTERDRIVEREX 0x54
+#define SPOOLSS_ADDPRINTERDRIVEREX 0x59
+*/
+
+/* those are implemented */
+#define SPOOLSS_ENUMPRINTERS 0x00
+#define SPOOLSS_SETJOB 0x02
+#define SPOOLSS_GETJOB 0x03
+#define SPOOLSS_ENUMJOBS 0x04
+#define SPOOLSS_ADDPRINTER 0x05
+#define SPOOLSS_DELETEPRINTER 0x06
+#define SPOOLSS_SETPRINTER 0x07
+#define SPOOLSS_GETPRINTER 0x08
+#define SPOOLSS_ADDPRINTERDRIVER 0x09
+#define SPOOLSS_ENUMPRINTERDRIVERS 0x0a
+#define SPOOLSS_GETPRINTERDRIVERDIRECTORY 0x0c
+#define SPOOLSS_DELETEPRINTERDRIVER 0x0d
+#define SPOOLSS_ADDPRINTPROCESSOR 0x0e
+#define SPOOLSS_ENUMPRINTPROCESSORS 0x0f
+#define SPOOLSS_GETPRINTPROCESSORDIRECTORY 0x10
+#define SPOOLSS_STARTDOCPRINTER 0x11
+#define SPOOLSS_STARTPAGEPRINTER 0x12
+#define SPOOLSS_WRITEPRINTER 0x13
+#define SPOOLSS_ENDPAGEPRINTER 0x14
+#define SPOOLSS_ABORTPRINTER 0x15
+#define SPOOLSS_ENDDOCPRINTER 0x17
+#define SPOOLSS_ADDJOB 0x18
+#define SPOOLSS_SCHEDULEJOB 0x19
+#define SPOOLSS_GETPRINTERDATA 0x1a
+#define SPOOLSS_SETPRINTERDATA 0x1b
+#define SPOOLSS_CLOSEPRINTER 0x1d
+#define SPOOLSS_ADDFORM 0x1e
+#define SPOOLSS_DELETEFORM 0x1f
+#define SPOOLSS_GETFORM 0x20
+#define SPOOLSS_SETFORM 0x21
+#define SPOOLSS_ENUMFORMS 0x22
+#define SPOOLSS_ENUMPORTS 0x23
+#define SPOOLSS_ENUMMONITORS 0x24
+#define SPOOLSS_ENUMPRINTPROCDATATYPES 0x33
+#define SPOOLSS_GETPRINTERDRIVER2 0x35
+/* find close printer notification */
+#define SPOOLSS_FCPN 0x38
+#define SPOOLSS_REPLYOPENPRINTER 0x3a
+#define SPOOLSS_REPLYCLOSEPRINTER 0x3c
+/* remote find first printer change notifyEx */
+#define SPOOLSS_RFFPCNEX 0x41
+/*SPOOLSS_ROUTERREFRESHPRINTERCHANGENOTIFICATION */
+#define SPOOLSS_RRPCN 0x42
+/* remote find next printer change notifyEx */
+#define SPOOLSS_RFNPCNEX 0x43
+#define SPOOLSS_OPENPRINTEREX 0x45
+#define SPOOLSS_ADDPRINTEREX 0x46
+#define SPOOLSS_ENUMPRINTERDATA 0x48
+#define SPOOLSS_DELETEPRINTERDATA 0x49
+#define SPOOLSS_SETPRINTERDATAEX 0x4d
+#define SPOOLSS_GETPRINTERDATAEX 0x4e
+#define SPOOLSS_ENUMPRINTERDATAEX 0x4f
+#define SPOOLSS_ENUMPRINTERKEY 0x50
+
+
+#define PRINTER_CONTROL_UNPAUSE 0x00000000
+#define PRINTER_CONTROL_PAUSE 0x00000001
+#define PRINTER_CONTROL_RESUME 0x00000002
+#define PRINTER_CONTROL_PURGE 0x00000003
+#define PRINTER_CONTROL_SET_STATUS 0x00000004
+
+#define PRINTER_STATUS_PAUSED 0x00000001
+#define PRINTER_STATUS_ERROR 0x00000002
+#define PRINTER_STATUS_PENDING_DELETION 0x00000004
+#define PRINTER_STATUS_PAPER_JAM 0x00000008
+
+#define PRINTER_STATUS_PAPER_OUT 0x00000010
+#define PRINTER_STATUS_MANUAL_FEED 0x00000020
+#define PRINTER_STATUS_PAPER_PROBLEM 0x00000040
+#define PRINTER_STATUS_OFFLINE 0x00000080
+
+#define PRINTER_STATUS_IO_ACTIVE 0x00000100
+#define PRINTER_STATUS_BUSY 0x00000200
+#define PRINTER_STATUS_PRINTING 0x00000400
+#define PRINTER_STATUS_OUTPUT_BIN_FULL 0x00000800
+
+#define PRINTER_STATUS_NOT_AVAILABLE 0x00001000
+#define PRINTER_STATUS_WAITING 0x00002000
+#define PRINTER_STATUS_PROCESSING 0x00004000
+#define PRINTER_STATUS_INITIALIZING 0x00008000
+
+#define PRINTER_STATUS_WARMING_UP 0x00010000
+#define PRINTER_STATUS_TONER_LOW 0x00020000
+#define PRINTER_STATUS_NO_TONER 0x00040000
+#define PRINTER_STATUS_PAGE_PUNT 0x00080000
+
+#define PRINTER_STATUS_USER_INTERVENTION 0x00100000
+#define PRINTER_STATUS_OUT_OF_MEMORY 0x00200000
+#define PRINTER_STATUS_DOOR_OPEN 0x00400000
+#define PRINTER_STATUS_SERVER_UNKNOWN 0x00800000
+
+#define PRINTER_STATUS_POWER_SAVE 0x01000000
+
+#define SERVER_ACCESS_ADMINISTER 0x00000001
+#define SERVER_ACCESS_ENUMERATE 0x00000002
+#define PRINTER_ACCESS_ADMINISTER 0x00000004
+#define PRINTER_ACCESS_USE 0x00000008
+#define JOB_ACCESS_ADMINISTER 0x00000010
+
+/* JOB status codes. */
+
+#define JOB_STATUS_PAUSED 0x001
+#define JOB_STATUS_ERROR 0x002
+#define JOB_STATUS_DELETING 0x004
+#define JOB_STATUS_SPOOLING 0x008
+#define JOB_STATUS_PRINTING 0x010
+#define JOB_STATUS_OFFLINE 0x020
+#define JOB_STATUS_PAPEROUT 0x040
+#define JOB_STATUS_PRINTED 0x080
+#define JOB_STATUS_DELETED 0x100
+#define JOB_STATUS_BLOCKED 0x200
+#define JOB_STATUS_USER_INTERVENTION 0x400
+
+/* ACE masks for the various print permissions */
+
+#define PRINTER_ACE_FULL_CONTROL GENERIC_ALL_ACCESS
+#define PRINTER_ACE_MANAGE_DOCUMENTS READ_CONTROL_ACCESS
+#define PRINTER_ACE_PRINT \
+ (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS)
+
+/* Access rights for print servers */
+#define SERVER_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE
+#define SERVER_READ STANDARD_RIGHTS_READ_ACCESS|SERVER_ACCESS_ENUMERATE
+#define SERVER_WRITE STANDARD_RIGHTS_WRITE_ACCESS|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE
+#define SERVER_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|SERVER_ACCESS_ENUMERATE
+
+/* Access rights for printers */
+#define PRINTER_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE
+#define PRINTER_READ STANDARD_RIGHTS_READ_ACCESS|PRINTER_ACCESS_USE
+#define PRINTER_WRITE STANDARD_RIGHTS_WRITE_ACCESS|PRINTER_ACCESS_USE
+#define PRINTER_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|PRINTER_ACCESS_USE
+
+/* Access rights for jobs */
+#define JOB_ALL_ACCESS STANDARD_RIGHTS_REQUIRED_ACCESS|JOB_ACCESS_ADMINISTER
+#define JOB_READ STANDARD_RIGHTS_READ_ACCESS|JOB_ACCESS_ADMINISTER
+#define JOB_WRITE STANDARD_RIGHTS_WRITE_ACCESS|JOB_ACCESS_ADMINISTER
+#define JOB_EXECUTE STANDARD_RIGHTS_EXECUTE_ACCESS|JOB_ACCESS_ADMINISTER
+
+#define ONE_VALUE 1
+#define TWO_VALUE 2
+#define POINTER 3
+
+#define PRINTER_NOTIFY_TYPE 0x00
+#define JOB_NOTIFY_TYPE 0x01
+
+#define MAX_PRINTER_NOTIFY 26
+#define MAX_JOB_NOTIFY 24
+
+#define MAX_NOTIFY_TYPE_FOR_NOW 26
+
+#define PRINTER_NOTIFY_SERVER_NAME 0x00
+#define PRINTER_NOTIFY_PRINTER_NAME 0x01
+#define PRINTER_NOTIFY_SHARE_NAME 0x02
+#define PRINTER_NOTIFY_PORT_NAME 0x03
+#define PRINTER_NOTIFY_DRIVER_NAME 0x04
+#define PRINTER_NOTIFY_COMMENT 0x05
+#define PRINTER_NOTIFY_LOCATION 0x06
+#define PRINTER_NOTIFY_DEVMODE 0x07
+#define PRINTER_NOTIFY_SEPFILE 0x08
+#define PRINTER_NOTIFY_PRINT_PROCESSOR 0x09
+#define PRINTER_NOTIFY_PARAMETERS 0x0A
+#define PRINTER_NOTIFY_DATATYPE 0x0B
+#define PRINTER_NOTIFY_SECURITY_DESCRIPTOR 0x0C
+#define PRINTER_NOTIFY_ATTRIBUTES 0x0D
+#define PRINTER_NOTIFY_PRIORITY 0x0E
+#define PRINTER_NOTIFY_DEFAULT_PRIORITY 0x0F
+#define PRINTER_NOTIFY_START_TIME 0x10
+#define PRINTER_NOTIFY_UNTIL_TIME 0x11
+#define PRINTER_NOTIFY_STATUS 0x12
+#define PRINTER_NOTIFY_STATUS_STRING 0x13
+#define PRINTER_NOTIFY_CJOBS 0x14
+#define PRINTER_NOTIFY_AVERAGE_PPM 0x15
+#define PRINTER_NOTIFY_TOTAL_PAGES 0x16
+#define PRINTER_NOTIFY_PAGES_PRINTED 0x17
+#define PRINTER_NOTIFY_TOTAL_BYTES 0x18
+#define PRINTER_NOTIFY_BYTES_PRINTED 0x19
+
+#define JOB_NOTIFY_PRINTER_NAME 0x00
+#define JOB_NOTIFY_MACHINE_NAME 0x01
+#define JOB_NOTIFY_PORT_NAME 0x02
+#define JOB_NOTIFY_USER_NAME 0x03
+#define JOB_NOTIFY_NOTIFY_NAME 0x04
+#define JOB_NOTIFY_DATATYPE 0x05
+#define JOB_NOTIFY_PRINT_PROCESSOR 0x06
+#define JOB_NOTIFY_PARAMETERS 0x07
+#define JOB_NOTIFY_DRIVER_NAME 0x08
+#define JOB_NOTIFY_DEVMODE 0x09
+#define JOB_NOTIFY_STATUS 0x0A
+#define JOB_NOTIFY_STATUS_STRING 0x0B
+#define JOB_NOTIFY_SECURITY_DESCRIPTOR 0x0C
+#define JOB_NOTIFY_DOCUMENT 0x0D
+#define JOB_NOTIFY_PRIORITY 0x0E
+#define JOB_NOTIFY_POSITION 0x0F
+#define JOB_NOTIFY_SUBMITTED 0x10
+#define JOB_NOTIFY_START_TIME 0x11
+#define JOB_NOTIFY_UNTIL_TIME 0x12
+#define JOB_NOTIFY_TIME 0x13
+#define JOB_NOTIFY_TOTAL_PAGES 0x14
+#define JOB_NOTIFY_PAGES_PRINTED 0x15
+#define JOB_NOTIFY_TOTAL_BYTES 0x16
+#define JOB_NOTIFY_BYTES_PRINTED 0x17
+
+#define PRINTER_CHANGE_ADD_PRINTER 0x00000001
+#define PRINTER_CHANGE_SET_PRINTER 0x00000002
+#define PRINTER_CHANGE_DELETE_PRINTER 0x00000004
+#define PRINTER_CHANGE_FAILED_CONNECTION_PRINTER 0x00000008
+#define PRINTER_CHANGE_PRINTER (PRINTER_CHANGE_ADD_PRINTER | \
+ PRINTER_CHANGE_SET_PRINTER | \
+ PRINTER_CHANGE_DELETE_PRINTER | \
+ PRINTER_CHANGE_FAILED_CONNECTION_PRINTER )
+
+#define PRINTER_CHANGE_ADD_JOB 0x00000100
+#define PRINTER_CHANGE_SET_JOB 0x00000200
+#define PRINTER_CHANGE_DELETE_JOB 0x00000400
+#define PRINTER_CHANGE_WRITE_JOB 0x00000800
+#define PRINTER_CHANGE_JOB (PRINTER_CHANGE_ADD_JOB | \
+ PRINTER_CHANGE_SET_JOB | \
+ PRINTER_CHANGE_DELETE_JOB | \
+ PRINTER_CHANGE_WRITE_JOB )
+
+#define PRINTER_CHANGE_ADD_FORM 0x00010000
+#define PRINTER_CHANGE_SET_FORM 0x00020000
+#define PRINTER_CHANGE_DELETE_FORM 0x00040000
+#define PRINTER_CHANGE_FORM (PRINTER_CHANGE_ADD_FORM | \
+ PRINTER_CHANGE_SET_FORM | \
+ PRINTER_CHANGE_DELETE_FORM )
+
+#define PRINTER_CHANGE_ADD_PORT 0x00100000
+#define PRINTER_CHANGE_CONFIGURE_PORT 0x00200000
+#define PRINTER_CHANGE_DELETE_PORT 0x00400000
+#define PRINTER_CHANGE_PORT (PRINTER_CHANGE_ADD_PORT | \
+ PRINTER_CHANGE_CONFIGURE_PORT | \
+ PRINTER_CHANGE_DELETE_PORT )
+
+#define PRINTER_CHANGE_ADD_PRINT_PROCESSOR 0x01000000
+#define PRINTER_CHANGE_DELETE_PRINT_PROCESSOR 0x04000000
+#define PRINTER_CHANGE_PRINT_PROCESSOR (PRINTER_CHANGE_ADD_PRINT_PROCESSOR | \
+ PRINTER_CHANGE_DELETE_PRINT_PROCESSOR )
+
+#define PRINTER_CHANGE_ADD_PRINTER_DRIVER 0x10000000
+#define PRINTER_CHANGE_SET_PRINTER_DRIVER 0x20000000
+#define PRINTER_CHANGE_DELETE_PRINTER_DRIVER 0x40000000
+#define PRINTER_CHANGE_PRINTER_DRIVER (PRINTER_CHANGE_ADD_PRINTER_DRIVER | \
+ PRINTER_CHANGE_SET_PRINTER_DRIVER | \
+ PRINTER_CHANGE_DELETE_PRINTER_DRIVER )
+
+#define PRINTER_CHANGE_TIMEOUT 0x80000000
+#define PRINTER_CHANGE_ALL (PRINTER_CHANGE_JOB | \
+ PRINTER_CHANGE_FORM | \
+ PRINTER_CHANGE_PORT | \
+ PRINTER_CHANGE_PRINT_PROCESSOR | \
+ PRINTER_CHANGE_PRINTER_DRIVER )
+
+#define PRINTER_NOTIFY_INFO_DISCARDED 0x1
+
+/*
+ * The printer attributes.
+ * I #defined all of them (grabbed form MSDN)
+ * I'm only using:
+ * ( SHARED | NETWORK | RAW_ONLY )
+ * RAW_ONLY _MUST_ be present otherwise NT will send an EMF file
+ */
+
+#define PRINTER_ATTRIBUTE_QUEUED 0x00000001
+#define PRINTER_ATTRIBUTE_DIRECT 0x00000002
+#define PRINTER_ATTRIBUTE_DEFAULT 0x00000004
+#define PRINTER_ATTRIBUTE_SHARED 0x00000008
+
+#define PRINTER_ATTRIBUTE_NETWORK 0x00000010
+#define PRINTER_ATTRIBUTE_HIDDEN 0x00000020
+#define PRINTER_ATTRIBUTE_LOCAL 0x00000040
+#define PRINTER_ATTRIBUTE_ENABLE_DEVQ 0x00000080
+
+#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS 0x00000100
+#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST 0x00000200
+#define PRINTER_ATTRIBUTE_WORK_OFFLINE 0x00000400
+#define PRINTER_ATTRIBUTE_ENABLE_BIDI 0x00000800
+
+#define PRINTER_ATTRIBUTE_RAW_ONLY 0x00001000
+
+#define NO_PRIORITY 0
+#define MAX_PRIORITY 99
+#define MIN_PRIORITY 1
+#define DEF_PRIORITY 1
+
+/* the flags of the query */
+#define PRINTER_ENUM_DEFAULT 0x00000001
+#define PRINTER_ENUM_LOCAL 0x00000002
+#define PRINTER_ENUM_CONNECTIONS 0x00000004
+#define PRINTER_ENUM_FAVORITE 0x00000004
+#define PRINTER_ENUM_NAME 0x00000008
+#define PRINTER_ENUM_REMOTE 0x00000010
+#define PRINTER_ENUM_SHARED 0x00000020
+#define PRINTER_ENUM_NETWORK 0x00000040
+
+/* the flags of each printers */
+#define PRINTER_ENUM_UNKNOWN_8 0x00000008
+#define PRINTER_ENUM_EXPAND 0x00004000
+#define PRINTER_ENUM_CONTAINER 0x00008000
+#define PRINTER_ENUM_ICONMASK 0x00ff0000
+#define PRINTER_ENUM_ICON1 0x00010000
+#define PRINTER_ENUM_ICON2 0x00020000
+#define PRINTER_ENUM_ICON3 0x00040000
+#define PRINTER_ENUM_ICON4 0x00080000
+#define PRINTER_ENUM_ICON5 0x00100000
+#define PRINTER_ENUM_ICON6 0x00200000
+#define PRINTER_ENUM_ICON7 0x00400000
+#define PRINTER_ENUM_ICON8 0x00800000
+
+/* this struct is undocumented */
+/* thanks to the ddk ... */
+typedef struct spool_user_1
+{
+ uint32 size; /* length of user_name & client_name + 2? */
+ uint32 client_name_ptr;
+ uint32 user_name_ptr;
+ uint32 build;
+ uint32 major;
+ uint32 minor;
+ uint32 processor;
+ UNISTR2 client_name;
+ UNISTR2 user_name;
+}
+SPOOL_USER_1;
+
+typedef struct spool_user_ctr_info
+{
+ uint32 level;
+ uint32 ptr;
+ SPOOL_USER_1 user1;
+}
+SPOOL_USER_CTR;
+
+typedef struct devicemode
+{
+ UNISTR devicename;
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ uint16 driverextra;
+ uint32 fields;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ UNISTR formname;
+ uint16 logpixels;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ uint8 *private;
+}
+DEVICEMODE;
+
+typedef struct _devmode_cont
+{
+ uint32 size;
+ uint32 devmode_ptr;
+ DEVICEMODE *devmode;
+}
+DEVMODE_CTR;
+
+typedef struct _printer_default
+{
+ uint32 datatype_ptr;
+ UNISTR2 datatype;
+ DEVMODE_CTR devmode_cont;
+ uint32 access_required;
+}
+PRINTER_DEFAULT;
+
+/* SPOOL_Q_OPEN_PRINTER_EX request to open a printer */
+typedef struct spool_q_open_printer_ex
+{
+ uint32 printername_ptr;
+ UNISTR2 printername;
+ PRINTER_DEFAULT printer_default;
+ uint32 user_switch;
+ SPOOL_USER_CTR user_ctr;
+}
+SPOOL_Q_OPEN_PRINTER_EX;
+
+/* SPOOL_R_OPEN_PRINTER_EX reply to an open printer */
+typedef struct spool_r_open_printer_ex
+{
+ POLICY_HND handle; /* handle used along all transactions (20*uint8) */
+ WERROR status;
+}
+SPOOL_R_OPEN_PRINTER_EX;
+
+typedef struct spool_notify_option_type
+{
+ uint16 type;
+ uint16 reserved0;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 count;
+ uint32 fields_ptr;
+ uint32 count2;
+ uint16 fields[MAX_NOTIFY_TYPE_FOR_NOW];
+}
+SPOOL_NOTIFY_OPTION_TYPE;
+
+typedef struct spool_notify_option_type_ctr
+{
+ uint32 count;
+ SPOOL_NOTIFY_OPTION_TYPE *type;
+}
+SPOOL_NOTIFY_OPTION_TYPE_CTR;
+
+
+
+typedef struct s_header_type
+{
+ uint32 type;
+ union
+ {
+ uint32 value;
+ UNISTR string;
+ }
+ data;
+}
+HEADER_TYPE;
+
+typedef struct new_buffer
+{
+ uint32 ptr;
+ uint32 size;
+ prs_struct prs;
+ uint32 struct_start;
+ uint32 string_at_end;
+}
+NEW_BUFFER;
+
+typedef struct spool_q_getprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 valuename;
+ uint32 size;
+}
+SPOOL_Q_GETPRINTERDATA;
+
+typedef struct spool_r_getprinterdata
+{
+ uint32 type;
+ uint32 size;
+ uint8 *data;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDATA;
+
+typedef struct spool_q_deleteprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 valuename;
+}
+SPOOL_Q_DELETEPRINTERDATA;
+
+typedef struct spool_r_deleteprinterdata
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDATA;
+
+typedef struct spool_q_closeprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_CLOSEPRINTER;
+
+typedef struct spool_r_closeprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_CLOSEPRINTER;
+
+typedef struct spool_q_startpageprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_STARTPAGEPRINTER;
+
+typedef struct spool_r_startpageprinter
+{
+ WERROR status;
+}
+SPOOL_R_STARTPAGEPRINTER;
+
+typedef struct spool_q_endpageprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_ENDPAGEPRINTER;
+
+typedef struct spool_r_endpageprinter
+{
+ WERROR status;
+}
+SPOOL_R_ENDPAGEPRINTER;
+
+
+typedef struct spool_q_deleteprinterdriver
+{
+ uint32 server_ptr;
+ UNISTR2 server;
+ UNISTR2 arch;
+ UNISTR2 driver;
+}
+SPOOL_Q_DELETEPRINTERDRIVER;
+
+typedef struct spool_r_deleteprinterdriver
+{
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTERDRIVER;
+
+
+typedef struct spool_doc_info_1
+{
+ uint32 p_docname;
+ uint32 p_outputfile;
+ uint32 p_datatype;
+ UNISTR2 docname;
+ UNISTR2 outputfile;
+ UNISTR2 datatype;
+}
+DOC_INFO_1;
+
+typedef struct spool_doc_info
+{
+ uint32 switch_value;
+ DOC_INFO_1 doc_info_1;
+}
+DOC_INFO;
+
+typedef struct spool_doc_info_container
+{
+ uint32 level;
+ DOC_INFO docinfo;
+}
+DOC_INFO_CONTAINER;
+
+typedef struct spool_q_startdocprinter
+{
+ POLICY_HND handle;
+ DOC_INFO_CONTAINER doc_info_container;
+}
+SPOOL_Q_STARTDOCPRINTER;
+
+typedef struct spool_r_startdocprinter
+{
+ uint32 jobid;
+ WERROR status;
+}
+SPOOL_R_STARTDOCPRINTER;
+
+typedef struct spool_q_enddocprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_ENDDOCPRINTER;
+
+typedef struct spool_r_enddocprinter
+{
+ WERROR status;
+}
+SPOOL_R_ENDDOCPRINTER;
+
+typedef struct spool_q_writeprinter
+{
+ POLICY_HND handle;
+ uint32 buffer_size;
+ uint8 *buffer;
+ uint32 buffer_size2;
+}
+SPOOL_Q_WRITEPRINTER;
+
+typedef struct spool_r_writeprinter
+{
+ uint32 buffer_written;
+ WERROR status;
+}
+SPOOL_R_WRITEPRINTER;
+
+typedef struct spool_notify_option
+{
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ uint32 option_type_ptr;
+ SPOOL_NOTIFY_OPTION_TYPE_CTR ctr;
+}
+SPOOL_NOTIFY_OPTION;
+
+typedef struct spool_notify_info_data
+{
+ uint16 type;
+ uint16 field;
+ uint32 reserved;
+ uint32 id;
+ union
+ {
+ uint32 value[2];
+ struct
+ {
+ uint32 length;
+ uint16 *string;
+ }
+ data;
+ }
+ notify_data;
+ uint32 size;
+ BOOL enc_type;
+} SPOOL_NOTIFY_INFO_DATA;
+
+typedef struct spool_notify_info
+{
+ uint32 version;
+ uint32 flags;
+ uint32 count;
+ SPOOL_NOTIFY_INFO_DATA *data;
+}
+SPOOL_NOTIFY_INFO;
+
+/* If the struct name looks obscure, yes it is ! */
+/* RemoteFindFirstPrinterChangeNotificationEx query struct */
+typedef struct spoolss_q_rffpcnex
+{
+ POLICY_HND handle;
+ uint32 flags;
+ uint32 options;
+ uint32 localmachine_ptr;
+ UNISTR2 localmachine;
+ uint32 printerlocal;
+ uint32 option_ptr;
+ SPOOL_NOTIFY_OPTION *option;
+}
+SPOOL_Q_RFFPCNEX;
+
+typedef struct spool_r_rffpcnex
+{
+ WERROR status;
+}
+SPOOL_R_RFFPCNEX;
+
+/* Remote Find Next Printer Change Notify Ex */
+typedef struct spool_q_rfnpcnex
+{
+ POLICY_HND handle;
+ uint32 change;
+ uint32 option_ptr;
+ SPOOL_NOTIFY_OPTION *option;
+}
+SPOOL_Q_RFNPCNEX;
+
+typedef struct spool_r_rfnpcnex
+{
+ uint32 info_ptr;
+ SPOOL_NOTIFY_INFO info;
+ WERROR status;
+}
+SPOOL_R_RFNPCNEX;
+
+/* Find Close Printer Notify */
+typedef struct spool_q_fcpn
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_FCPN;
+
+typedef struct spool_r_fcpn
+{
+ WERROR status;
+}
+SPOOL_R_FCPN;
+
+
+typedef struct printer_info_0
+{
+ UNISTR printername;
+ UNISTR servername;
+ uint32 cjobs;
+ uint32 total_jobs;
+ uint32 total_bytes;
+
+ uint16 year;
+ uint16 month;
+ uint16 dayofweek;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 milliseconds;
+
+ uint32 global_counter;
+ uint32 total_pages;
+
+ uint16 major_version;
+ uint16 build_version;
+
+ uint32 unknown7;
+ uint32 unknown8;
+ uint32 unknown9;
+ uint32 session_counter;
+ uint32 unknown11;
+ uint32 printer_errors;
+ uint32 unknown13;
+ uint32 unknown14;
+ uint32 unknown15;
+ uint32 unknown16;
+ uint32 change_id;
+ uint32 unknown18;
+ uint32 status;
+ uint32 unknown20;
+ uint32 c_setprinter;
+
+ uint16 unknown22;
+ uint16 unknown23;
+ uint16 unknown24;
+ uint16 unknown25;
+ uint16 unknown26;
+ uint16 unknown27;
+ uint16 unknown28;
+ uint16 unknown29;
+} PRINTER_INFO_0;
+
+typedef struct printer_info_1
+{
+ uint32 flags;
+ UNISTR description;
+ UNISTR name;
+ UNISTR comment;
+}
+PRINTER_INFO_1;
+
+typedef struct printer_info_2
+{
+ UNISTR servername;
+ UNISTR printername;
+ UNISTR sharename;
+ UNISTR portname;
+ UNISTR drivername;
+ UNISTR comment;
+ UNISTR location;
+ DEVICEMODE *devmode;
+ UNISTR sepfile;
+ UNISTR printprocessor;
+ UNISTR datatype;
+ UNISTR parameters;
+ SEC_DESC *secdesc;
+ uint32 attributes;
+ uint32 priority;
+ uint32 defaultpriority;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 status;
+ uint32 cjobs;
+ uint32 averageppm;
+}
+PRINTER_INFO_2;
+
+typedef struct printer_info_3
+{
+ uint32 flags;
+ SEC_DESC *secdesc;
+}
+PRINTER_INFO_3;
+
+typedef struct spool_q_enumprinters
+{
+ uint32 flags;
+ uint32 servername_ptr;
+ UNISTR2 servername;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTERS;
+
+typedef struct printer_info_ctr_info
+{
+ PRINTER_INFO_0 *printers_0;
+ PRINTER_INFO_1 *printers_1;
+ PRINTER_INFO_2 *printers_2;
+ PRINTER_INFO_3 *printers_3;
+}
+PRINTER_INFO_CTR;
+
+typedef struct spool_r_enumprinters
+{
+ NEW_BUFFER *buffer;
+ uint32 needed; /* bytes needed */
+ uint32 returned; /* number of printers */
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERS;
+
+
+typedef struct spool_q_getprinter
+{
+ POLICY_HND handle;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTER;
+
+typedef struct printer_info_info
+{
+ union
+ {
+ PRINTER_INFO_0 *info0;
+ PRINTER_INFO_1 *info1;
+ PRINTER_INFO_2 *info2;
+ void *info;
+ } printer;
+} PRINTER_INFO;
+
+typedef struct spool_r_getprinter
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+} SPOOL_R_GETPRINTER;
+
+typedef struct driver_info_1
+{
+ UNISTR name;
+} DRIVER_INFO_1;
+
+typedef struct driver_info_2
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+} DRIVER_INFO_2;
+
+typedef struct driver_info_3
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+ UNISTR helpfile;
+ uint16 *dependentfiles;
+ UNISTR monitorname;
+ UNISTR defaultdatatype;
+}
+DRIVER_INFO_3;
+
+typedef struct driver_info_6
+{
+ uint32 version;
+ UNISTR name;
+ UNISTR architecture;
+ UNISTR driverpath;
+ UNISTR datafile;
+ UNISTR configfile;
+ UNISTR helpfile;
+ uint16 *dependentfiles;
+ UNISTR monitorname;
+ UNISTR defaultdatatype;
+ uint16* previousdrivernames;
+ NTTIME driver_date;
+ uint32 padding;
+ uint32 driver_version_low;
+ uint32 driver_version_high;
+ UNISTR mfgname;
+ UNISTR oem_url;
+ UNISTR hardware_id;
+ UNISTR provider;
+}
+DRIVER_INFO_6;
+
+typedef struct driver_info_info
+{
+ DRIVER_INFO_1 *info1;
+ DRIVER_INFO_2 *info2;
+ DRIVER_INFO_3 *info3;
+ DRIVER_INFO_6 *info6;
+}
+PRINTER_DRIVER_CTR;
+
+typedef struct spool_q_getprinterdriver2
+{
+ POLICY_HND handle;
+ uint32 architecture_ptr;
+ UNISTR2 architecture;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+ uint32 clientmajorversion;
+ uint32 clientminorversion;
+}
+SPOOL_Q_GETPRINTERDRIVER2;
+
+typedef struct spool_r_getprinterdriver2
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 servermajorversion;
+ uint32 serverminorversion;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDRIVER2;
+
+
+typedef struct add_jobinfo_1
+{
+ UNISTR path;
+ uint32 job_number;
+}
+ADD_JOBINFO_1;
+
+
+typedef struct spool_q_addjob
+{
+ POLICY_HND handle;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ADDJOB;
+
+typedef struct spool_r_addjob
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_ADDJOB;
+
+/*
+ * I'm really wondering how many different time formats
+ * I will have to cope with
+ *
+ * JFM, 09/13/98 In a mad mood ;-(
+*/
+typedef struct systemtime
+{
+ uint16 year;
+ uint16 month;
+ uint16 dayofweek;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 milliseconds;
+}
+SYSTEMTIME;
+
+typedef struct s_job_info_1
+{
+ uint32 jobid;
+ UNISTR printername;
+ UNISTR machinename;
+ UNISTR username;
+ UNISTR document;
+ UNISTR datatype;
+ UNISTR text_status;
+ uint32 status;
+ uint32 priority;
+ uint32 position;
+ uint32 totalpages;
+ uint32 pagesprinted;
+ SYSTEMTIME submitted;
+}
+JOB_INFO_1;
+
+typedef struct s_job_info_2
+{
+ uint32 jobid;
+ UNISTR printername;
+ UNISTR machinename;
+ UNISTR username;
+ UNISTR document;
+ UNISTR notifyname;
+ UNISTR datatype;
+ UNISTR printprocessor;
+ UNISTR parameters;
+ UNISTR drivername;
+ DEVICEMODE *devmode;
+ UNISTR text_status;
+/* SEC_DESC sec_desc;*/
+ uint32 status;
+ uint32 priority;
+ uint32 position;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 totalpages;
+ uint32 size;
+ SYSTEMTIME submitted;
+ uint32 timeelapsed;
+ uint32 pagesprinted;
+}
+JOB_INFO_2;
+
+typedef struct spool_q_enumjobs
+{
+ POLICY_HND handle;
+ uint32 firstjob;
+ uint32 numofjobs;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMJOBS;
+
+typedef struct job_info_ctr_info
+{
+ union
+ {
+ JOB_INFO_1 **job_info_1;
+ JOB_INFO_2 **job_info_2;
+ void *info;
+ } job;
+
+} JOB_INFO_CTR;
+
+typedef struct spool_r_enumjobs
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMJOBS;
+
+typedef struct spool_q_schedulejob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+}
+SPOOL_Q_SCHEDULEJOB;
+
+typedef struct spool_r_schedulejob
+{
+ WERROR status;
+}
+SPOOL_R_SCHEDULEJOB;
+
+typedef struct s_port_info_1
+{
+ UNISTR port_name;
+}
+PORT_INFO_1;
+
+typedef struct s_port_info_2
+{
+ UNISTR port_name;
+ UNISTR monitor_name;
+ UNISTR description;
+ uint32 port_type;
+ uint32 reserved;
+}
+PORT_INFO_2;
+
+typedef struct spool_q_enumports
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPORTS;
+
+typedef struct port_info_ctr_info
+{
+ union
+ {
+ PORT_INFO_1 *info_1;
+ PORT_INFO_2 *info_2;
+ }
+ port;
+
+}
+PORT_INFO_CTR;
+
+typedef struct spool_r_enumports
+{
+ NEW_BUFFER *buffer;
+ uint32 needed; /* bytes needed */
+ uint32 returned; /* number of printers */
+ WERROR status;
+}
+SPOOL_R_ENUMPORTS;
+
+#define JOB_CONTROL_PAUSE 1
+#define JOB_CONTROL_RESUME 2
+#define JOB_CONTROL_CANCEL 3
+#define JOB_CONTROL_RESTART 4
+#define JOB_CONTROL_DELETE 5
+
+typedef struct job_info_info
+{
+ union
+ {
+ JOB_INFO_1 job_info_1;
+ JOB_INFO_2 job_info_2;
+ }
+ job;
+
+}
+JOB_INFO;
+
+typedef struct spool_q_setjob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+ uint32 level;
+ JOB_INFO ctr;
+ uint32 command;
+
+}
+SPOOL_Q_SETJOB;
+
+typedef struct spool_r_setjob
+{
+ WERROR status;
+
+}
+SPOOL_R_SETJOB;
+
+typedef struct spool_q_enumprinterdrivers
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTERDRIVERS;
+
+typedef struct spool_r_enumprinterdrivers
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDRIVERS;
+
+typedef struct spool_form_1
+{
+ uint32 flag;
+ UNISTR name;
+ uint32 width;
+ uint32 length;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+}
+FORM_1;
+
+typedef struct spool_q_enumforms
+{
+ POLICY_HND handle;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMFORMS;
+
+typedef struct spool_r_enumforms
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 numofforms;
+ WERROR status;
+}
+SPOOL_R_ENUMFORMS;
+
+typedef struct spool_q_getform
+{
+ POLICY_HND handle;
+ UNISTR2 formname;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETFORM;
+
+typedef struct spool_r_getform
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETFORM;
+
+typedef struct spool_printer_info_level_1
+{
+ uint32 flags;
+ uint32 description_ptr;
+ uint32 name_ptr;
+ uint32 comment_ptr;
+ UNISTR2 description;
+ UNISTR2 name;
+ UNISTR2 comment;
+} SPOOL_PRINTER_INFO_LEVEL_1;
+
+typedef struct spool_printer_info_level_2
+{
+ uint32 servername_ptr;
+ uint32 printername_ptr;
+ uint32 sharename_ptr;
+ uint32 portname_ptr;
+ uint32 drivername_ptr;
+ uint32 comment_ptr;
+ uint32 location_ptr;
+ uint32 devmode_ptr;
+ uint32 sepfile_ptr;
+ uint32 printprocessor_ptr;
+ uint32 datatype_ptr;
+ uint32 parameters_ptr;
+ uint32 secdesc_ptr;
+ uint32 attributes;
+ uint32 priority;
+ uint32 default_priority;
+ uint32 starttime;
+ uint32 untiltime;
+ WERROR status;
+ uint32 cjobs;
+ uint32 averageppm;
+ UNISTR2 servername;
+ UNISTR2 printername;
+ UNISTR2 sharename;
+ UNISTR2 portname;
+ UNISTR2 drivername;
+ UNISTR2 comment;
+ UNISTR2 location;
+ UNISTR2 sepfile;
+ UNISTR2 printprocessor;
+ UNISTR2 datatype;
+ UNISTR2 parameters;
+ SEC_DESC_BUF *secdesc;
+}
+SPOOL_PRINTER_INFO_LEVEL_2;
+
+typedef struct spool_printer_info_level_3
+{
+ uint32 secdesc_ptr;
+}
+SPOOL_PRINTER_INFO_LEVEL_3;
+
+typedef struct spool_printer_info_level
+{
+ uint32 level;
+ uint32 info_ptr;
+ SPOOL_PRINTER_INFO_LEVEL_1 *info_1;
+ SPOOL_PRINTER_INFO_LEVEL_2 *info_2;
+ SPOOL_PRINTER_INFO_LEVEL_3 *info_3;
+}
+SPOOL_PRINTER_INFO_LEVEL;
+
+typedef struct spool_printer_driver_info_level_3
+{
+ uint32 cversion;
+ uint32 name_ptr;
+ uint32 environment_ptr;
+ uint32 driverpath_ptr;
+ uint32 datafile_ptr;
+ uint32 configfile_ptr;
+ uint32 helpfile_ptr;
+ uint32 monitorname_ptr;
+ uint32 defaultdatatype_ptr;
+ uint32 dependentfilessize;
+ uint32 dependentfiles_ptr;
+
+ UNISTR2 name;
+ UNISTR2 environment;
+ UNISTR2 driverpath;
+ UNISTR2 datafile;
+ UNISTR2 configfile;
+ UNISTR2 helpfile;
+ UNISTR2 monitorname;
+ UNISTR2 defaultdatatype;
+ BUFFER5 dependentfiles;
+
+}
+SPOOL_PRINTER_DRIVER_INFO_LEVEL_3;
+
+/* SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure */
+typedef struct {
+ uint32 version;
+ uint32 name_ptr;
+ uint32 environment_ptr;
+ uint32 driverpath_ptr;
+ uint32 datafile_ptr;
+ uint32 configfile_ptr;
+ uint32 helpfile_ptr;
+ uint32 monitorname_ptr;
+ uint32 defaultdatatype_ptr;
+ uint32 dependentfiles_len;
+ uint32 dependentfiles_ptr;
+ uint32 previousnames_len;
+ uint32 previousnames_ptr;
+ NTTIME driverdate;
+ UINT64_S driverversion;
+ uint32 dummy4;
+ uint32 mfgname_ptr;
+ uint32 oemurl_ptr;
+ uint32 hardwareid_ptr;
+ uint32 provider_ptr;
+ UNISTR2 name;
+ UNISTR2 environment;
+ UNISTR2 driverpath;
+ UNISTR2 datafile;
+ UNISTR2 configfile;
+ UNISTR2 helpfile;
+ UNISTR2 monitorname;
+ UNISTR2 defaultdatatype;
+ BUFFER5 dependentfiles;
+ BUFFER5 previousnames;
+ UNISTR2 mfgname;
+ UNISTR2 oemurl;
+ UNISTR2 hardwareid;
+ UNISTR2 provider;
+} SPOOL_PRINTER_DRIVER_INFO_LEVEL_6;
+
+
+typedef struct spool_printer_driver_info_level
+{
+ uint32 level;
+ uint32 ptr;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *info_3;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *info_6;
+}
+SPOOL_PRINTER_DRIVER_INFO_LEVEL;
+
+
+/* this struct is undocumented */
+/* thanks to the ddk ... */
+typedef struct spool_user_level_1
+{
+ uint32 size;
+ uint32 client_name_ptr;
+ uint32 user_name_ptr;
+ uint32 build;
+ uint32 major;
+ uint32 minor;
+ uint32 processor;
+ UNISTR2 client_name;
+ UNISTR2 user_name;
+}
+SPOOL_USER_LEVEL_1;
+
+typedef struct spool_user_level
+{
+ SPOOL_USER_LEVEL_1 *user_level_1;
+}
+SPOOL_USER_LEVEL;
+
+typedef struct spool_q_setprinter
+{
+ POLICY_HND handle;
+ uint32 level;
+ SPOOL_PRINTER_INFO_LEVEL info;
+ SEC_DESC_BUF *secdesc_ctr;
+ DEVMODE_CTR devmode_ctr;
+
+ uint32 command;
+
+}
+SPOOL_Q_SETPRINTER;
+
+typedef struct spool_r_setprinter
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTER;
+
+typedef struct spool_q_addprinter
+{
+ UNISTR2 server_name;
+ uint32 level;
+ SPOOL_PRINTER_INFO_LEVEL info;
+ uint32 unk0;
+ uint32 unk1;
+ uint32 unk2;
+ uint32 unk3;
+ uint32 user_level;
+ SPOOL_USER_LEVEL user;
+}
+SPOOL_Q_ADDPRINTER;
+
+typedef struct spool_r_addprinter
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTER;
+
+typedef struct spool_q_deleteprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_DELETEPRINTER;
+
+typedef struct spool_r_deleteprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_DELETEPRINTER;
+
+typedef struct spool_q_abortprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_ABORTPRINTER;
+
+typedef struct spool_r_abortprinter
+{
+ WERROR status;
+}
+SPOOL_R_ABORTPRINTER;
+
+
+typedef struct spool_q_addprinterex
+{
+ uint32 server_name_ptr;
+ UNISTR2 server_name;
+ uint32 level;
+ SPOOL_PRINTER_INFO_LEVEL info;
+ uint32 unk0;
+ uint32 unk1;
+ uint32 unk2;
+ uint32 unk3;
+ uint32 user_switch;
+ SPOOL_USER_CTR user_ctr;
+}
+SPOOL_Q_ADDPRINTEREX;
+
+typedef struct spool_r_addprinterex
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_ADDPRINTEREX;
+
+
+typedef struct spool_q_addprinterdriver
+{
+ uint32 server_name_ptr;
+ UNISTR2 server_name;
+ uint32 level;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL info;
+}
+SPOOL_Q_ADDPRINTERDRIVER;
+
+typedef struct spool_r_addprinterdriver
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTERDRIVER;
+
+
+typedef struct driver_directory_1
+{
+ UNISTR name;
+}
+DRIVER_DIRECTORY_1;
+
+typedef struct driver_info_ctr_info
+{
+ DRIVER_DIRECTORY_1 *info1;
+}
+DRIVER_DIRECTORY_CTR;
+
+typedef struct spool_q_getprinterdriverdirectory
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTERDRIVERDIR;
+
+typedef struct spool_r_getprinterdriverdirectory
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDRIVERDIR;
+
+typedef struct spool_q_addprintprocessor
+{
+ uint32 server_ptr;
+ UNISTR2 server;
+ UNISTR2 environment;
+ UNISTR2 path;
+ UNISTR2 name;
+}
+SPOOL_Q_ADDPRINTPROCESSOR;
+
+typedef struct spool_r_addprintprocessor
+{
+ WERROR status;
+}
+SPOOL_R_ADDPRINTPROCESSOR;
+
+
+typedef struct spool_q_enumprintprocessors
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 environment_ptr;
+ UNISTR2 environment;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTPROCESSORS;
+
+typedef struct printprocessor_1
+{
+ UNISTR name;
+}
+PRINTPROCESSOR_1;
+
+typedef struct spool_r_enumprintprocessors
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTPROCESSORS;
+
+typedef struct spool_q_enumprintprocdatatypes
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 processor_ptr;
+ UNISTR2 processor;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTPROCDATATYPES;
+
+typedef struct ppdatatype_1
+{
+ UNISTR name;
+}
+PRINTPROCDATATYPE_1;
+
+typedef struct spool_r_enumprintprocdatatypes
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTPROCDATATYPES;
+
+typedef struct printmonitor_1
+{
+ UNISTR name;
+}
+PRINTMONITOR_1;
+
+typedef struct printmonitor_2
+{
+ UNISTR name;
+ UNISTR environment;
+ UNISTR dll_name;
+}
+PRINTMONITOR_2;
+
+typedef struct spool_q_enumprintmonitors
+{
+ uint32 name_ptr;
+ UNISTR2 name;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_ENUMPRINTMONITORS;
+
+typedef struct spool_r_enumprintmonitors
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTMONITORS;
+
+
+typedef struct spool_q_enumprinterdata
+{
+ POLICY_HND handle;
+ uint32 index;
+ uint32 valuesize;
+ uint32 datasize;
+}
+SPOOL_Q_ENUMPRINTERDATA;
+
+typedef struct spool_r_enumprinterdata
+{
+ uint32 valuesize;
+ uint16 *value;
+ uint32 realvaluesize;
+ uint32 type;
+ uint32 datasize;
+ uint8 *data;
+ uint32 realdatasize;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDATA;
+
+typedef struct spool_q_setprinterdata
+{
+ POLICY_HND handle;
+ UNISTR2 value;
+ uint32 type;
+ uint32 max_len;
+ uint8 *data;
+ uint32 real_len;
+ uint32 numeric_data;
+}
+SPOOL_Q_SETPRINTERDATA;
+
+typedef struct spool_r_setprinterdata
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTERDATA;
+
+typedef struct _form
+{
+ uint32 flags;
+ uint32 name_ptr;
+ uint32 size_x;
+ uint32 size_y;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ UNISTR2 name;
+}
+FORM;
+
+typedef struct spool_q_addform
+{
+ POLICY_HND handle;
+ uint32 level;
+ uint32 level2;
+ FORM form;
+}
+SPOOL_Q_ADDFORM;
+
+typedef struct spool_r_addform
+{
+ WERROR status;
+}
+SPOOL_R_ADDFORM;
+
+typedef struct spool_q_setform
+{
+ POLICY_HND handle;
+ UNISTR2 name;
+ uint32 level;
+ uint32 level2;
+ FORM form;
+}
+SPOOL_Q_SETFORM;
+
+typedef struct spool_r_setform
+{
+ WERROR status;
+}
+SPOOL_R_SETFORM;
+
+typedef struct spool_q_deleteform
+{
+ POLICY_HND handle;
+ UNISTR2 name;
+}
+SPOOL_Q_DELETEFORM;
+
+typedef struct spool_r_deleteform
+{
+ WERROR status;
+}
+SPOOL_R_DELETEFORM;
+
+typedef struct spool_q_getjob
+{
+ POLICY_HND handle;
+ uint32 jobid;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETJOB;
+
+typedef struct pjob_info_info
+{
+ union
+ {
+ JOB_INFO_1 *job_info_1;
+ JOB_INFO_2 *job_info_2;
+ void *info;
+ }
+ job;
+
+}
+PJOB_INFO;
+
+typedef struct spool_r_getjob
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETJOB;
+
+typedef struct spool_q_replyopenprinter
+{
+ UNISTR2 string;
+ uint32 printer;
+ uint32 type;
+ uint32 unknown0;
+ uint32 unknown1;
+}
+SPOOL_Q_REPLYOPENPRINTER;
+
+typedef struct spool_r_replyopenprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_REPLYOPENPRINTER;
+
+typedef struct spool_q_replycloseprinter
+{
+ POLICY_HND handle;
+}
+SPOOL_Q_REPLYCLOSEPRINTER;
+
+typedef struct spool_r_replycloseprinter
+{
+ POLICY_HND handle;
+ WERROR status;
+}
+SPOOL_R_REPLYCLOSEPRINTER;
+
+typedef struct spool_q_rrpcn
+{
+ POLICY_HND handle;
+ uint32 change_low;
+ uint32 change_high;
+ uint32 unknown0;
+ uint32 unknown1;
+ uint32 info_ptr;
+ SPOOL_NOTIFY_INFO info;
+}
+SPOOL_Q_REPLY_RRPCN;
+
+typedef struct spool_r_rrpcn
+{
+ uint32 unknown0;
+ WERROR status;
+}
+SPOOL_R_REPLY_RRPCN;
+
+typedef struct spool_q_getprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 keyname;
+ UNISTR2 valuename;
+ uint32 size;
+}
+SPOOL_Q_GETPRINTERDATAEX;
+
+typedef struct spool_r_getprinterdataex
+{
+ uint32 type;
+ uint32 size;
+ uint8 *data;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTERDATAEX;
+
+typedef struct spool_q_setprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ UNISTR2 value;
+ uint32 type;
+ uint32 max_len;
+ uint8 *data;
+ uint32 real_len;
+ uint32 numeric_data;
+}
+SPOOL_Q_SETPRINTERDATAEX;
+
+typedef struct spool_r_setprinterdataex
+{
+ WERROR status;
+}
+SPOOL_R_SETPRINTERDATAEX;
+
+
+typedef struct spool_q_enumprinterkey
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ uint32 size;
+}
+SPOOL_Q_ENUMPRINTERKEY;
+
+typedef struct spool_r_enumprinterkey
+{
+ BUFFER5 keys;
+ uint32 needed; /* in bytes */
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERKEY;
+
+typedef struct printer_enum_values
+{
+ UNISTR valuename;
+ uint32 value_len;
+ uint32 type;
+ uint8 *data;
+ uint32 data_len;
+
+}
+PRINTER_ENUM_VALUES;
+
+typedef struct printer_enum_values_ctr
+{
+ uint32 size;
+ uint32 size_of_array;
+ PRINTER_ENUM_VALUES *values;
+}
+PRINTER_ENUM_VALUES_CTR;
+
+typedef struct spool_q_enumprinterdataex
+{
+ POLICY_HND handle;
+ UNISTR2 key;
+ uint32 size;
+}
+SPOOL_Q_ENUMPRINTERDATAEX;
+
+typedef struct spool_r_enumprinterdataex
+{
+ PRINTER_ENUM_VALUES_CTR ctr;
+ uint32 needed;
+ uint32 returned;
+ WERROR status;
+}
+SPOOL_R_ENUMPRINTERDATAEX;
+
+typedef struct printprocessor_directory_1
+{
+ UNISTR name;
+}
+PRINTPROCESSOR_DIRECTORY_1;
+
+typedef struct spool_q_getprintprocessordirectory
+{
+ UNISTR2 name;
+ UNISTR2 environment;
+ uint32 level;
+ NEW_BUFFER *buffer;
+ uint32 offered;
+}
+SPOOL_Q_GETPRINTPROCESSORDIRECTORY;
+
+typedef struct spool_r_getprintprocessordirectory
+{
+ NEW_BUFFER *buffer;
+ uint32 needed;
+ WERROR status;
+}
+SPOOL_R_GETPRINTPROCESSORDIRECTORY;
+
+#define PRINTER_DRIVER_VERSION 2
+#define PRINTER_DRIVER_ARCHITECTURE "Windows NT x86"
+
+#endif /* _RPC_SPOOLSS_H */
+
diff --git a/source/include/rpc_srvsvc.h b/source/include/rpc_srvsvc.h
new file mode 100644
index 00000000000..651c0b97673
--- /dev/null
+++ b/source/include/rpc_srvsvc.h
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_SRVSVC_H /* _RPC_SRVSVC_H */
+#define _RPC_SRVSVC_H
+
+
+/* srvsvc pipe */
+#define SRV_NETCONNENUM 0x08
+#define SRV_NETFILEENUM 0x09
+#define SRV_NETSESSENUM 0x0c
+#define SRV_NET_SHARE_ADD 0x0e
+#define SRV_NETSHAREENUM_ALL 0x0f
+#define SRV_NET_SHARE_GET_INFO 0x10
+#define SRV_NET_SHARE_SET_INFO 0x11
+#define SRV_NET_SHARE_DEL 0x12
+#define SRV_NET_SRV_GET_INFO 0x15
+#define SRV_NET_SRV_SET_INFO 0x16
+#define SRV_NET_DISK_ENUM 0x17
+#define SRV_NET_REMOTE_TOD 0x1c
+#define SRV_NET_NAME_VALIDATE 0x21
+#define SRV_NETSHAREENUM 0x24
+#define SRV_NETFILEQUERYSECDESC 0x27
+#define SRV_NETFILESETSECDESC 0x28
+
+#define MAX_SERVER_DISK_ENTRIES 15
+
+typedef struct disk_info {
+ uint32 unknown;
+ UNISTR3 disk_name;
+} DISK_INFO;
+
+typedef struct disk_enum_container {
+ uint32 level;
+ uint32 entries_read;
+ uint32 unknown;
+ uint32 disk_info_ptr;
+ DISK_INFO disk_info[MAX_SERVER_DISK_ENTRIES];
+} DISK_ENUM_CONTAINER;
+
+typedef struct net_srv_disk_enum {
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* server name */
+
+ DISK_ENUM_CONTAINER disk_enum_ctr;
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+ uint32 total_entries; /* total number of entries */
+ ENUM_HND enum_hnd;
+ NTSTATUS status; /* return status */
+} SRV_Q_NET_DISK_ENUM, SRV_R_NET_DISK_ENUM;
+
+typedef struct net_name_validate {
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+ UNISTR2 uni_name; /*name to validate*/
+ uint32 type;
+ uint32 flags;
+ NTSTATUS status;
+} SRV_Q_NET_NAME_VALIDATE, SRV_R_NET_NAME_VALIDATE;
+
+/* SESS_INFO_0 (pointers to level 0 session info strings) */
+typedef struct ptr_sess_info0
+{
+ uint32 ptr_name; /* pointer to name. */
+
+} SESS_INFO_0;
+
+/* SESS_INFO_0_STR (level 0 session info strings) */
+typedef struct str_sess_info0
+{
+ UNISTR2 uni_name; /* unicode string of name */
+
+} SESS_INFO_0_STR;
+
+/* oops - this is going to take up a *massive* amount of stack. */
+/* the UNISTR2s already have 1024 uint16 chars in them... */
+#define MAX_SESS_ENTRIES 32
+
+/* SRV_SESS_INFO_0 */
+typedef struct srv_sess_info_0_info
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_sess_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ SESS_INFO_0 info_0 [MAX_SESS_ENTRIES]; /* session entry pointers */
+ SESS_INFO_0_STR info_0_str[MAX_SESS_ENTRIES]; /* session entry strings */
+
+} SRV_SESS_INFO_0;
+
+/* SESS_INFO_1 (pointers to level 1 session info strings) */
+typedef struct ptr_sess_info1
+{
+ uint32 ptr_name; /* pointer to name. */
+ uint32 ptr_user; /* pointer to user name. */
+
+ uint32 num_opens;
+ uint32 open_time;
+ uint32 idle_time;
+ uint32 user_flags;
+
+} SESS_INFO_1;
+
+/* SESS_INFO_1_STR (level 1 session info strings) */
+typedef struct str_sess_info1
+{
+ UNISTR2 uni_name; /* unicode string of name */
+ UNISTR2 uni_user; /* unicode string of user */
+
+} SESS_INFO_1_STR;
+
+/* SRV_SESS_INFO_1 */
+typedef struct srv_sess_info_1_info
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_sess_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ SESS_INFO_1 info_1 [MAX_SESS_ENTRIES]; /* session entry pointers */
+ SESS_INFO_1_STR info_1_str[MAX_SESS_ENTRIES]; /* session entry strings */
+
+} SRV_SESS_INFO_1;
+
+/* SRV_SESS_INFO_CTR */
+typedef struct srv_sess_info_ctr_info
+{
+ uint32 switch_value; /* switch value */
+ uint32 ptr_sess_ctr; /* pointer to sess info union */
+ union
+ {
+ SRV_SESS_INFO_0 info0; /* session info level 0 */
+ SRV_SESS_INFO_1 info1; /* session info level 1 */
+
+ } sess;
+
+} SRV_SESS_INFO_CTR;
+
+
+/* SRV_Q_NET_SESS_ENUM */
+typedef struct q_net_sess_enum_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* server name */
+
+ uint32 ptr_qual_name; /* pointer (to qualifier name) */
+ UNISTR2 uni_qual_name; /* qualifier name "\\qualifier" */
+
+ uint32 sess_level; /* session level */
+
+ SRV_SESS_INFO_CTR *ctr;
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+ ENUM_HND enum_hnd;
+
+} SRV_Q_NET_SESS_ENUM;
+
+/* SRV_R_NET_SESS_ENUM */
+typedef struct r_net_sess_enum_info
+{
+ uint32 sess_level; /* share level */
+
+ SRV_SESS_INFO_CTR *ctr;
+
+ uint32 total_entries; /* total number of entries */
+ ENUM_HND enum_hnd;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SESS_ENUM;
+
+/* CONN_INFO_0 (pointers to level 0 connection info strings) */
+typedef struct ptr_conn_info0
+{
+ uint32 id; /* connection id. */
+
+} CONN_INFO_0;
+
+/* oops - this is going to take up a *massive* amount of stack. */
+/* the UNISTR2s already have 1024 uint16 chars in them... */
+#define MAX_CONN_ENTRIES 32
+
+/* SRV_CONN_INFO_0 */
+typedef struct srv_conn_info_0_info
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_conn_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ CONN_INFO_0 info_0 [MAX_CONN_ENTRIES]; /* connection entry pointers */
+
+} SRV_CONN_INFO_0;
+
+/* CONN_INFO_1 (pointers to level 1 connection info strings) */
+typedef struct ptr_conn_info1
+{
+ uint32 id; /* connection id */
+ uint32 type; /* 0x3 */
+ uint32 num_opens;
+ uint32 num_users;
+ uint32 open_time;
+
+ uint32 ptr_usr_name; /* pointer to user name. */
+ uint32 ptr_net_name; /* pointer to network name (e.g IPC$). */
+
+} CONN_INFO_1;
+
+/* CONN_INFO_1_STR (level 1 connection info strings) */
+typedef struct str_conn_info1
+{
+ UNISTR2 uni_usr_name; /* unicode string of user */
+ UNISTR2 uni_net_name; /* unicode string of name */
+
+} CONN_INFO_1_STR;
+
+/* SRV_CONN_INFO_1 */
+typedef struct srv_conn_info_1_info
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_conn_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ CONN_INFO_1 info_1 [MAX_CONN_ENTRIES]; /* connection entry pointers */
+ CONN_INFO_1_STR info_1_str[MAX_CONN_ENTRIES]; /* connection entry strings */
+
+} SRV_CONN_INFO_1;
+
+/* SRV_CONN_INFO_CTR */
+typedef struct srv_conn_info_ctr_info
+{
+ uint32 switch_value; /* switch value */
+ uint32 ptr_conn_ctr; /* pointer to conn info union */
+ union
+ {
+ SRV_CONN_INFO_0 info0; /* connection info level 0 */
+ SRV_CONN_INFO_1 info1; /* connection info level 1 */
+
+ } conn;
+
+} SRV_CONN_INFO_CTR;
+
+
+/* SRV_Q_NET_CONN_ENUM */
+typedef struct q_net_conn_enum_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name) */
+ UNISTR2 uni_srv_name; /* server name "\\server" */
+
+ uint32 ptr_qual_name; /* pointer (to qualifier name) */
+ UNISTR2 uni_qual_name; /* qualifier name "\\qualifier" */
+
+ uint32 conn_level; /* connection level */
+
+ SRV_CONN_INFO_CTR *ctr;
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+ ENUM_HND enum_hnd;
+
+} SRV_Q_NET_CONN_ENUM;
+
+/* SRV_R_NET_CONN_ENUM */
+typedef struct r_net_conn_enum_info
+{
+ uint32 conn_level; /* share level */
+
+ SRV_CONN_INFO_CTR *ctr;
+
+ uint32 total_entries; /* total number of entries */
+ ENUM_HND enum_hnd;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_CONN_ENUM;
+
+/* SH_INFO_1 (pointers to level 1 share info strings) */
+typedef struct ptr_share_info1
+{
+ uint32 ptr_netname; /* pointer to net name. */
+ uint32 type; /* ipc, print, disk ... */
+ uint32 ptr_remark; /* pointer to comment. */
+
+} SH_INFO_1;
+
+/* SH_INFO_1_STR (level 1 share info strings) */
+typedef struct str_share_info1
+{
+ UNISTR2 uni_netname; /* unicode string of net name */
+ UNISTR2 uni_remark; /* unicode string of comment */
+
+} SH_INFO_1_STR;
+
+/* SRV_SHARE_INFO_1 */
+typedef struct share_info_1_info
+{
+ SH_INFO_1 info_1;
+ SH_INFO_1_STR info_1_str;
+
+} SRV_SHARE_INFO_1;
+
+/* SH_INFO_2 (pointers to level 2 share info strings) */
+typedef struct ptr_share_info2
+{
+ uint32 ptr_netname; /* pointer to net name. */
+ uint32 type; /* ipc, print, disk ... */
+ uint32 ptr_remark; /* pointer to comment. */
+ uint32 perms; /* permissions */
+ uint32 max_uses; /* maximum uses */
+ uint32 num_uses; /* current uses */
+ uint32 ptr_path; /* pointer to path name */
+ uint32 ptr_passwd; /* pointer to password */
+
+} SH_INFO_2;
+
+/* SH_INFO_2_STR (level 2 share info strings) */
+typedef struct str_share_info2
+{
+ UNISTR2 uni_netname; /* unicode string of net name (e.g NETLOGON) */
+ UNISTR2 uni_remark; /* unicode string of comment (e.g "Logon server share") */
+ UNISTR2 uni_path; /* unicode string of local path (e.g c:\winnt\system32\repl\import\scripts) */
+ UNISTR2 uni_passwd; /* unicode string of password - presumably for share level security (e.g NULL) */
+
+} SH_INFO_2_STR;
+
+/* SRV_SHARE_INFO_2 */
+typedef struct share_info_2_info
+{
+ SH_INFO_2 info_2;
+ SH_INFO_2_STR info_2_str;
+
+} SRV_SHARE_INFO_2;
+
+/* SH_INFO_502 (pointers to level 502 share info strings) */
+typedef struct ptr_share_info502
+{
+ uint32 ptr_netname; /* pointer to net name. */
+ uint32 type; /* ipc, print, disk ... */
+ uint32 ptr_remark; /* pointer to comment. */
+ uint32 perms; /* permissions */
+ uint32 max_uses; /* maximum uses */
+ uint32 num_uses; /* current uses */
+ uint32 ptr_path; /* pointer to path name */
+ uint32 ptr_passwd; /* pointer to password */
+ uint32 sd_size; /* size of security descriptor */
+ uint32 ptr_sd; /* pointer to security descriptor */
+
+} SH_INFO_502;
+
+/* SH_INFO_502_STR (level 502 share info strings) */
+typedef struct str_share_info502
+{
+ SH_INFO_502 *ptrs;
+
+ UNISTR2 uni_netname; /* unicode string of net name (e.g NETLOGON) */
+ UNISTR2 uni_remark; /* unicode string of comment (e.g "Logon server share") */
+ UNISTR2 uni_path; /* unicode string of local path (e.g c:\winnt\system32\repl\import\scripts) */
+ UNISTR2 uni_passwd; /* unicode string of password - presumably for share level security (e.g NULL) */
+
+ uint32 sd_size;
+ SEC_DESC *sd;
+
+} SH_INFO_502_STR;
+
+/* SRV_SHARE_INFO_502 */
+typedef struct share_info_502_info
+{
+ SH_INFO_502 info_502;
+ SH_INFO_502_STR info_502_str;
+
+} SRV_SHARE_INFO_502;
+
+/* SRV_SHARE_INFO_1005 */
+typedef struct share_info_1005_info
+{
+ uint32 dfs_root_flag;
+} SRV_SHARE_INFO_1005;
+
+/* SRV_SHARE_INFO_1501 */
+typedef struct share_info_1501_info
+{
+ SEC_DESC_BUF *sdb;
+} SRV_SHARE_INFO_1501;
+
+/* SRV_SHARE_INFO_CTR */
+typedef struct srv_share_info_ctr_info
+{
+ uint32 info_level;
+ uint32 switch_value;
+ uint32 ptr_share_info;
+
+ uint32 num_entries;
+ uint32 ptr_entries;
+ uint32 num_entries2;
+
+ union {
+ SRV_SHARE_INFO_1 *info1; /* share info level 1 */
+ SRV_SHARE_INFO_2 *info2; /* share info level 2 */
+ SRV_SHARE_INFO_502 *info502; /* share info level 502 */
+ void *info;
+
+ } share;
+
+} SRV_SHARE_INFO_CTR;
+
+/* SRV_Q_NET_SHARE_ENUM */
+typedef struct q_net_share_enum_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* server name */
+
+ SRV_SHARE_INFO_CTR ctr; /* share info container */
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+
+ ENUM_HND enum_hnd;
+
+} SRV_Q_NET_SHARE_ENUM;
+
+
+/* SRV_R_NET_SHARE_ENUM */
+typedef struct r_net_share_enum_info
+{
+ SRV_SHARE_INFO_CTR ctr; /* share info container */
+
+ uint32 total_entries; /* total number of entries */
+ ENUM_HND enum_hnd;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SHARE_ENUM;
+
+
+/* SRV_Q_NET_SHARE_GET_INFO */
+typedef struct q_net_share_get_info_info
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+
+ UNISTR2 uni_share_name;
+ uint32 info_level;
+
+} SRV_Q_NET_SHARE_GET_INFO;
+
+/* JRA. NB. We also need level 1004 and 1006 here. */
+
+/* SRV_SHARE_INFO */
+typedef struct srv_share_info {
+ uint32 switch_value;
+ uint32 ptr_share_ctr;
+
+ union {
+ SRV_SHARE_INFO_1 info1;
+ SRV_SHARE_INFO_2 info2;
+ SRV_SHARE_INFO_502 info502;
+ SRV_SHARE_INFO_1005 info1005;
+ SRV_SHARE_INFO_1501 info1501;
+ } share;
+} SRV_SHARE_INFO;
+
+/* SRV_R_NET_SHARE_GET_INFO */
+typedef struct r_net_share_get_info_info
+{
+ SRV_SHARE_INFO info;
+ NTSTATUS status;
+
+} SRV_R_NET_SHARE_GET_INFO;
+
+/* SRV_Q_NET_SHARE_SET_INFO */
+typedef struct q_net_share_set_info_info
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+
+ UNISTR2 uni_share_name;
+ uint32 info_level;
+
+ SRV_SHARE_INFO info;
+
+} SRV_Q_NET_SHARE_SET_INFO;
+
+/* SRV_R_NET_SHARE_SET_INFO */
+typedef struct r_net_share_set_info
+{
+ uint32 switch_value; /* switch value */
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SHARE_SET_INFO;
+
+/* SRV_Q_NET_SHARE_ADD */
+typedef struct q_net_share_add
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+
+ uint32 info_level;
+
+ SRV_SHARE_INFO info;
+
+} SRV_Q_NET_SHARE_ADD;
+
+/* SRV_R_NET_SHARE_ADD */
+typedef struct r_net_share_add
+{
+ uint32 switch_value; /* switch value */
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SHARE_ADD;
+
+/* SRV_Q_NET_SHARE_DEL */
+typedef struct q_net_share_del
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+ UNISTR2 uni_share_name;
+
+} SRV_Q_NET_SHARE_DEL;
+
+/* SRV_R_NET_SHARE_DEL */
+typedef struct r_net_share_del
+{
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SHARE_DEL;
+
+/* FILE_INFO_3 (level 3 file info strings) */
+typedef struct file_info3_info
+{
+ uint32 id; /* file index */
+ uint32 perms; /* file permissions. don't know what format */
+ uint32 num_locks; /* file locks */
+ uint32 ptr_path_name; /* file name */
+ uint32 ptr_user_name; /* file owner */
+
+} FILE_INFO_3;
+
+/* FILE_INFO_3_STR (level 3 file info strings) */
+typedef struct str_file_info3_info
+{
+ UNISTR2 uni_path_name; /* unicode string of file name */
+ UNISTR2 uni_user_name; /* unicode string of file owner. */
+
+} FILE_INFO_3_STR;
+
+/* oops - this is going to take up a *massive* amount of stack. */
+/* the UNISTR2s already have 1024 uint16 chars in them... */
+#define MAX_FILE_ENTRIES 32
+
+/* SRV_FILE_INFO_3 */
+typedef struct srv_file_info_3
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_file_info; /* Buffer */
+
+ uint32 num_entries_read2; /* EntriesRead */
+
+ FILE_INFO_3 info_3 [MAX_FILE_ENTRIES]; /* file entry details */
+ FILE_INFO_3_STR info_3_str[MAX_FILE_ENTRIES]; /* file entry strings */
+
+} SRV_FILE_INFO_3;
+
+/* SRV_FILE_INFO_CTR */
+typedef struct srv_file_info_3_info
+{
+ uint32 switch_value; /* switch value */
+ uint32 ptr_file_ctr; /* pointer to file info union */
+ union
+ {
+ SRV_FILE_INFO_3 info3; /* file info with 0 entries */
+
+ } file;
+
+} SRV_FILE_INFO_CTR;
+
+
+/* SRV_Q_NET_FILE_ENUM */
+typedef struct q_net_file_enum_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* server name */
+
+ uint32 ptr_qual_name; /* pointer (to qualifier name) */
+ UNISTR2 uni_qual_name; /* qualifier name "\\qualifier" */
+
+ uint32 file_level; /* file level */
+
+ SRV_FILE_INFO_CTR *ctr;
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+ ENUM_HND enum_hnd;
+
+} SRV_Q_NET_FILE_ENUM;
+
+
+/* SRV_R_NET_FILE_ENUM */
+typedef struct r_net_file_enum_info
+{
+ uint32 file_level; /* file level */
+
+ SRV_FILE_INFO_CTR *ctr;
+
+ uint32 total_entries; /* total number of files */
+ ENUM_HND enum_hnd;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_FILE_ENUM;
+
+/* SRV_INFO_100 */
+typedef struct srv_info_100_info
+{
+ uint32 platform_id; /* 0x500 */
+ uint32 ptr_name; /* pointer to server name */
+
+ UNISTR2 uni_name; /* server name "server" */
+
+} SRV_INFO_100;
+
+/* SRV_INFO_101 */
+typedef struct srv_info_101_info
+{
+ uint32 platform_id; /* 0x500 */
+ uint32 ptr_name; /* pointer to server name */
+ uint32 ver_major; /* 0x4 */
+ uint32 ver_minor; /* 0x2 */
+ uint32 srv_type; /* browse etc type */
+ uint32 ptr_comment; /* pointer to server comment */
+
+ UNISTR2 uni_name; /* server name "server" */
+ UNISTR2 uni_comment; /* server comment "samba x.x.x blah" */
+
+} SRV_INFO_101;
+
+/* SRV_INFO_102 */
+typedef struct srv_info_102_info
+{
+ uint32 platform_id; /* 0x500 */
+ uint32 ptr_name; /* pointer to server name */
+ uint32 ver_major; /* 0x4 */
+ uint32 ver_minor; /* 0x2 */
+ uint32 srv_type; /* browse etc type */
+ uint32 ptr_comment; /* pointer to server comment */
+ uint32 users; /* 0xffff ffff*/
+ uint32 disc; /* 0xf */
+ uint32 hidden; /* 0x0 */
+ uint32 announce; /* 240 */
+ uint32 ann_delta; /* 3000 */
+ uint32 licenses; /* 0 */
+ uint32 ptr_usr_path; /* pointer to user path */
+
+ UNISTR2 uni_name; /* server name "server" */
+ UNISTR2 uni_comment; /* server comment "samba x.x.x blah" */
+ UNISTR2 uni_usr_path; /* "c:\" (eh?) */
+
+} SRV_INFO_102;
+
+
+/* SRV_INFO_CTR */
+typedef struct srv_info_ctr_info
+{
+ uint32 switch_value; /* switch value */
+ uint32 ptr_srv_ctr; /* pointer to server info */
+ union
+ {
+ SRV_INFO_102 sv102; /* server info level 102 */
+ SRV_INFO_101 sv101; /* server info level 101 */
+ SRV_INFO_100 sv100; /* server info level 100 */
+
+ } srv;
+
+} SRV_INFO_CTR;
+
+/* SRV_Q_NET_SRV_GET_INFO */
+typedef struct q_net_srv_get_info
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name; /* "\\server" */
+ uint32 switch_value;
+
+} SRV_Q_NET_SRV_GET_INFO;
+
+/* SRV_R_NET_SRV_GET_INFO */
+typedef struct r_net_srv_get_info
+{
+ SRV_INFO_CTR *ctr;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SRV_GET_INFO;
+
+/* SRV_Q_NET_SRV_SET_INFO */
+typedef struct q_net_srv_set_info
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name; /* "\\server" */
+ uint32 switch_value;
+
+ SRV_INFO_CTR *ctr;
+
+} SRV_Q_NET_SRV_SET_INFO;
+
+
+/* SRV_R_NET_SRV_SET_INFO */
+typedef struct r_net_srv_set_info
+{
+ uint32 switch_value; /* switch value */
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_SRV_SET_INFO;
+
+/* SRV_Q_NET_REMOTE_TOD */
+typedef struct q_net_remote_tod
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name; /* "\\server" */
+
+} SRV_Q_NET_REMOTE_TOD;
+
+/* TIME_OF_DAY_INFO */
+typedef struct time_of_day_info
+{
+ uint32 elapsedt;
+ uint32 msecs;
+ uint32 hours;
+ uint32 mins;
+ uint32 secs;
+ uint32 hunds;
+ uint32 zone;
+ uint32 tintervals;
+ uint32 day;
+ uint32 month;
+ uint32 year;
+ uint32 weekday;
+
+} TIME_OF_DAY_INFO;
+
+/* SRV_R_NET_REMOTE_TOD */
+typedef struct r_net_remote_tod
+{
+ uint32 ptr_srv_tod; /* pointer to TOD */
+ TIME_OF_DAY_INFO *tod;
+
+ NTSTATUS status; /* return status */
+
+} SRV_R_NET_REMOTE_TOD;
+
+/* SRV_Q_NET_FILE_QUERY_SECDESC */
+typedef struct q_net_file_query_secdesc
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+ uint32 ptr_qual_name;
+ UNISTR2 uni_qual_name;
+ UNISTR2 uni_file_name;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+} SRV_Q_NET_FILE_QUERY_SECDESC;
+
+/* SRV_R_NET_FILE_QUERY_SECDESC */
+typedef struct r_net_file_query_secdesc
+{
+ uint32 ptr_response;
+ uint32 size_response;
+ uint32 ptr_secdesc;
+ uint32 size_secdesc;
+ SEC_DESC *sec_desc;
+ NTSTATUS status;
+} SRV_R_NET_FILE_QUERY_SECDESC;
+
+/* SRV_Q_NET_FILE_SET_SECDESC */
+typedef struct q_net_file_set_secdesc
+{
+ uint32 ptr_srv_name;
+ UNISTR2 uni_srv_name;
+ uint32 ptr_qual_name;
+ UNISTR2 uni_qual_name;
+ UNISTR2 uni_file_name;
+ uint32 sec_info;
+ uint32 size_set;
+ uint32 ptr_secdesc;
+ uint32 size_secdesc;
+ SEC_DESC *sec_desc;
+} SRV_Q_NET_FILE_SET_SECDESC;
+
+/* SRV_R_NET_FILE_SET_SECDESC */
+typedef struct r_net_file_set_secdesc
+{
+ NTSTATUS status;
+} SRV_R_NET_FILE_SET_SECDESC;
+#endif /* _RPC_SRVSVC_H */
diff --git a/source/include/rpc_wkssvc.h b/source/include/rpc_wkssvc.h
new file mode 100644
index 00000000000..57a70b4798e
--- /dev/null
+++ b/source/include/rpc_wkssvc.h
@@ -0,0 +1,73 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _RPC_WKS_H /* _RPC_WKS_H */
+#define _RPC_WKS_H
+
+
+/* wkssvc pipe */
+#define WKS_QUERY_INFO 0x00
+
+
+/* WKS_Q_QUERY_INFO - probably a capabilities request */
+typedef struct q_wks_query_info_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* unicode server name starting with '\\' */
+
+ uint16 switch_value; /* info level 100 (0x64) */
+
+} WKS_Q_QUERY_INFO;
+
+
+/* WKS_INFO_100 - level 100 info */
+typedef struct wks_info_100_info
+{
+ uint32 platform_id; /* 0x0000 01f4 - unknown */
+ uint32 ptr_compname; /* pointer to server name */
+ uint32 ptr_lan_grp ; /* pointer to domain name */
+ uint32 ver_major; /* 4 - unknown */
+ uint32 ver_minor; /* 0 - unknown */
+
+ UNISTR2 uni_compname; /* unicode server name */
+ UNISTR2 uni_lan_grp ; /* unicode domain name */
+
+} WKS_INFO_100;
+
+
+/* WKS_R_QUERY_INFO - probably a capabilities request */
+typedef struct r_wks_query_info_info
+{
+ uint16 switch_value; /* 100 (0x64) - switch value */
+
+ /* for now, only level 100 is supported. this should be an enum container */
+ uint32 ptr_1; /* pointer 1 */
+ WKS_INFO_100 *wks100; /* workstation info level 100 */
+
+ NTSTATUS status; /* return status */
+
+} WKS_R_QUERY_INFO;
+
+
+#endif /* _RPC_WKS_H */
+
diff --git a/source/include/safe_string.h b/source/include/safe_string.h
new file mode 100644
index 00000000000..e609381a898
--- /dev/null
+++ b/source/include/safe_string.h
@@ -0,0 +1,55 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Safe string handling routines.
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SAFE_STRING_H
+#define _SAFE_STRING_H
+
+#ifdef strcpy
+#undef strcpy
+#endif /* strcpy */
+#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
+
+#ifdef strcat
+#undef strcat
+#endif /* strcat */
+#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
+
+#ifdef sprintf
+#undef sprintf
+#endif /* sprintf */
+#define sprintf __ERROR__XX__NEVER_USE_SPRINTF__;
+
+#define pstrcpy(d,s) safe_strcpy((d),(s),sizeof(pstring)-1)
+#define pstrcat(d,s) safe_strcat((d),(s),sizeof(pstring)-1)
+#define fstrcpy(d,s) safe_strcpy((d),(s),sizeof(fstring)-1)
+#define fstrcat(d,s) safe_strcat((d),(s),sizeof(fstring)-1)
+
+#define wpstrcpy(d,s) safe_strcpy_w((d),(s),sizeof(wpstring))
+#define wpstrcat(d,s) safe_strcat_w((d),(s),sizeof(wpstring))
+#define wfstrcpy(d,s) safe_strcpy_w((d),(s),sizeof(wfstring))
+#define wfstrcat(d,s) safe_strcat_w((d),(s),sizeof(wfstring))
+
+/* replace some string functions with multi-byte
+ versions */
+#define strlower(s) strlower_m(s)
+#define strupper(s) strupper_m(s)
+
+#endif
diff --git a/source/include/secrets.h b/source/include/secrets.h
new file mode 100644
index 00000000000..5990170ccc9
--- /dev/null
+++ b/source/include/secrets.h
@@ -0,0 +1,40 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 3.0
+ * secrets.tdb file format info
+ * Copyright (C) Andrew Tridgell 2000
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SECRETS_H
+#define _SECRETS_H
+
+/* the first one is for the hashed password (NT4 style) the latter
+ for plaintext (ADS
+*/
+#define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
+#define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
+
+
+#define SECRETS_DOMAIN_SID "SECRETS/SID"
+#define SECRETS_SAM_SID "SAM/SID"
+
+struct machine_acct_pass {
+ uint8 hash[16];
+ time_t mod_time;
+};
+
+#endif /* _SECRETS_H */
diff --git a/source/include/session.h b/source/include/session.h
new file mode 100644
index 00000000000..9091223e99e
--- /dev/null
+++ b/source/include/session.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ session handling for recording currently vailid vuids
+ Copyright (C) tridge@samba.org 2001
+ Copyright (C) Andew Bartlett <abartlet@samba.org> 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* a "session" is claimed when we do a SessionSetupX operation
+ and is yielded when the corresponding vuid is destroyed.
+
+ sessions are used to populate utmp and PAM session structures
+*/
+
+struct sessionid {
+ uid_t uid;
+ gid_t gid;
+ fstring username;
+ fstring hostname;
+ fstring netbios_name;
+ fstring remote_machine;
+ fstring id_str;
+ uint32 id_num;
+ uint32 pid;
+ fstring ip_addr;
+};
+
diff --git a/source/include/sids.h b/source/include/sids.h
new file mode 100644
index 00000000000..86aa58b6218
--- /dev/null
+++ b/source/include/sids.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Elrond 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SIDS_H
+#define _SIDS_H
+
+extern DOM_SID global_sam_sid;
+extern fstring global_sam_name;
+
+extern DOM_SID global_member_sid;
+
+extern DOM_SID global_sid_S_1_5_32; /* local well-known domain */
+extern DOM_SID global_sid_S_1_1; /* Global Domain */
+extern DOM_SID global_sid_NULL;
+
+extern const DOM_SID *global_sid_everyone;
+extern const DOM_SID *global_sid_system; /* SYSTEM */
+extern const DOM_SID *global_sid_builtin;
+
+#endif /* _SIDS_H */
diff --git a/source/include/smb.h b/source/include/smb.h
index b7faffa9e92..8c0491a004b 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -2,7 +2,10 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,59 +21,29 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#ifndef _SMB_H
#define _SMB_H
-#ifndef MAX_CONNECTIONS
-#define MAX_CONNECTIONS 127
-#endif
-
-#ifndef MAX_OPEN_FILES
-#define MAX_OPEN_FILES 50
-#endif
-
-#ifndef GUEST_ACCOUNT
-#define GUEST_ACCOUNT "nobody"
-#endif
-
#define BUFFER_SIZE (0xFFFF)
#define SAFETY_MARGIN 1024
+#define LARGE_WRITEX_HDR_SIZE 65
-#ifndef EXTERN
-# define EXTERN extern
-#endif
+#define NMB_PORT 137
+#define DGRAM_PORT 138
+#define SMB_PORT 139
#define False (0)
#define True (1)
-#define BOOLSTR(b) ((b) ? "Yes" : "No")
-#define BITSETB(ptr,bit) ((((char *)ptr)[0] & (1<<(bit)))!=0)
-#define BITSETW(ptr,bit) ((SVAL(ptr,0) & (1<<(bit)))!=0)
-#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
+#define Auto (2)
+#ifndef _BOOL
typedef int BOOL;
-
-/*
- Samba needs type definitions for int16, int32, uint16 and uint32.
-
- Normally these are signed and unsigned 16 and 32 bit integers, but
- they actually only need to be at least 16 and 32 bits
- respectively. Thus if your word size is 8 bytes just defining them
- as signed and unsigned int will work.
-*/
-
-/* afs/stds.h defines int16 and int32 */
-#ifndef AFS_AUTH
-typedef short int16;
-typedef int int32;
+#define _BOOL /* So we don't typedef BOOL again in vfs.h */
#endif
-#ifndef uint16
-typedef unsigned short uint16;
-#endif
-
-#ifndef uint32
-typedef unsigned int uint32;
-#endif
+/* limiting size of ipc replies */
+#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
#define SIZEOFWORD 2
@@ -78,19 +51,24 @@ typedef unsigned int uint32;
#define DEF_CREATE_MASK (0755)
#endif
-#ifndef DEFAULT_PIPE_TIMEOUT
-#define DEFAULT_PIPE_TIMEOUT 10000000 /* Ten seconds */
-#endif
+/* string manipulation flags - see clistr.c and srvstr.c */
+#define STR_TERMINATE 1
+#define STR_UPPER 2
+#define STR_ASCII 4
+#define STR_UNICODE 8
+#define STR_NOALIGN 16
-/* debugging code */
-#ifndef SYSLOG
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))?(Debug1 body):0)
-#else
-EXTERN int syslog_level;
+/* how long to wait for secondary SMB packets (milli-seconds) */
+#define SMB_SECONDARY_WAIT (60*1000)
+
+/* Debugging stuff */
+#include "debug.h"
+
+/* this defines the error codes that receive_smb can put in smb_read_error */
+#define READ_TIMEOUT 1
+#define READ_EOF 2
+#define READ_ERROR 3
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? \
- (syslog_level = (level), Debug1 body):0)
-#endif
#define DIR_STRUCT_SIZE 43
@@ -116,212 +94,450 @@ implemented */
#define DENY_NONE 4
#define DENY_FCB 7
+/* open modes */
+#define DOS_OPEN_RDONLY 0
+#define DOS_OPEN_WRONLY 1
+#define DOS_OPEN_RDWR 2
+#define DOS_OPEN_FCB 0xF
+
+/* define shifts and masks for share and open modes. */
+#define OPEN_MODE_MASK 0xF
+#define SHARE_MODE_SHIFT 4
+#define SHARE_MODE_MASK 0x7
+#define GET_OPEN_MODE(x) ((x) & OPEN_MODE_MASK)
+#define SET_OPEN_MODE(x) ((x) & OPEN_MODE_MASK)
+#define GET_DENY_MODE(x) (((x)>>SHARE_MODE_SHIFT) & SHARE_MODE_MASK)
+#define SET_DENY_MODE(x) (((x) & SHARE_MODE_MASK) <<SHARE_MODE_SHIFT)
+
+/* Sync on open file (not sure if used anymore... ?) */
+#define FILE_SYNC_OPENMODE (1<<14)
+#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? True : False)
+
+/* allow delete on open file mode (used by NT SMB's). */
+#define ALLOW_SHARE_DELETE (1<<15)
+#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? True : False)
+#define SET_ALLOW_SHARE_DELETE(x) ((x) ? ALLOW_SHARE_DELETE : 0)
+
+/* delete on close flag (used by NT SMB's). */
+#define DELETE_ON_CLOSE_FLAG (1<<16)
+#define GET_DELETE_ON_CLOSE_FLAG(x) (((x) & DELETE_ON_CLOSE_FLAG) ? True : False)
+#define SET_DELETE_ON_CLOSE_FLAG(x) ((x) ? DELETE_ON_CLOSE_FLAG : 0)
+
+/* was delete access requested in NT open ? */
+#define DELETE_ACCESS_REQUESTED (1<<17)
+#define GET_DELETE_ACCESS_REQUESTED(x) (((x) & DELETE_ACCESS_REQUESTED) ? True : False)
+#define SET_DELETE_ACCESS_REQUESTED(x) ((x) ? DELETE_ACCESS_REQUESTED : 0)
+
+/* open disposition values */
+#define FILE_EXISTS_FAIL 0
+#define FILE_EXISTS_OPEN 1
+#define FILE_EXISTS_TRUNCATE 2
+
+/* mask for open disposition. */
+#define FILE_OPEN_MASK 0x3
+
+#define GET_FILE_OPEN_DISPOSITION(x) ((x) & FILE_OPEN_MASK)
+#define SET_FILE_OPEN_DISPOSITION(x) ((x) & FILE_OPEN_MASK)
+
+/* The above can be OR'ed with... */
+#define FILE_CREATE_IF_NOT_EXIST 0x10
+#define FILE_FAIL_IF_NOT_EXIST 0
+
+#define GET_FILE_CREATE_DISPOSITION(x) ((x) & (FILE_CREATE_IF_NOT_EXIST|FILE_FAIL_IF_NOT_EXIST))
+
/* share types */
-#define STYPE_DISKTREE 0 /* Disk drive */
-#define STYPE_PRINTQ 1 /* Spooler queue */
-#define STYPE_DEVICE 2 /* Serial device */
-#define STYPE_IPC 3 /* Interprocess communication (IPC) */
-
-/* SMB X/Open error codes for the ERRdos error class */
-#define ERRbadfunc 1 /* Invalid function (or system call) */
-#define ERRbadfile 2 /* File not found (pathname error) */
-#define ERRbadpath 3 /* Directory not found */
-#define ERRnofids 4 /* Too many open files */
-#define ERRnoaccess 5 /* Access denied */
-#define ERRbadfid 6 /* Invalid fid */
-#define ERRnomem 8 /* Out of memory */
-#define ERRbadmem 9 /* Invalid memory block address */
-#define ERRbadenv 10 /* Invalid environment */
-#define ERRbadaccess 12 /* Invalid open mode */
-#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
-#define ERRres 14 /* reserved */
-#define ERRbaddrive 15 /* Invalid drive */
-#define ERRremcd 16 /* Attempt to delete current directory */
-#define ERRdiffdevice 17 /* rename/move across different filesystems */
-#define ERRnofiles 18 /* no more files found in file search */
-#define ERRbadshare 32 /* Share mode on file conflict with open mode */
-#define ERRlock 33 /* Lock request conflicts with existing lock */
-#define ERRfilexists 80 /* File in operation already exists */
-#define ERRbadpipe 230 /* Named pipe invalid */
-#define ERRpipebusy 231 /* All instances of pipe are busy */
-#define ERRpipeclosing 232 /* named pipe close in progress */
-#define ERRnotconnected 233 /* No process on other end of named pipe */
-#define ERRmoredata 234 /* More data to be returned */
-#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
-#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */
-#define ERRunknownlevel 124
-#define ERRunknownipc 2142
-
-
-/* here's a special one from observing NT */
-#define ERRnoipc 66 /* don't support ipc */
-
-/* Error codes for the ERRSRV class */
-
-#define ERRerror 1 /* Non specific error code */
-#define ERRbadpw 2 /* Bad password */
-#define ERRbadtype 3 /* reserved */
-#define ERRaccess 4 /* No permissions to do the requested operation */
-#define ERRinvnid 5 /* tid invalid */
-#define ERRinvnetname 6 /* Invalid servername */
-#define ERRinvdevice 7 /* Invalid device */
-#define ERRqfull 49 /* Print queue full */
-#define ERRqtoobig 50 /* Queued item too big */
-#define ERRinvpfid 52 /* Invalid print file in smb_fid */
-#define ERRsmbcmd 64 /* Unrecognised command */
-#define ERRsrverror 65 /* smb server internal error */
-#define ERRfilespecs 67 /* fid and pathname invalid combination */
-#define ERRbadlink 68 /* reserved */
-#define ERRbadpermits 69 /* Access specified for a file is not valid */
-#define ERRbadpid 70 /* reserved */
-#define ERRsetattrmode 71 /* attribute mode invalid */
-#define ERRpaused 81 /* Message server paused */
-#define ERRmsgoff 82 /* Not receiving messages */
-#define ERRnoroom 83 /* No room for message */
-#define ERRrmuns 87 /* too many remote usernames */
-#define ERRtimeout 88 /* operation timed out */
-#define ERRnoresource 89 /* No resources currently available for request. */
-#define ERRtoomanyuids 90 /* too many userids */
-#define ERRbaduid 91 /* bad userid */
-#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
-#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
-#define ERRcontMPX 252 /* resume MPX mode */
-#define ERRbadPW /* reserved */
-#define ERRnosupport 0xFFFF
-#define ERRunknownsmb 22 /* from NT 3.5 response */
-
-
-/* Error codes for the ERRHRD class */
-
-#define ERRnowrite 19 /* read only media */
-#define ERRbadunit 20 /* Unknown device */
-#define ERRnotready 21 /* Drive not ready */
-#define ERRbadcmd 22 /* Unknown command */
-#define ERRdata 23 /* Data (CRC) error */
-#define ERRbadreq 24 /* Bad request structure length */
-#define ERRseek 25
-#define ERRbadmedia 26
-#define ERRbadsector 27
-#define ERRnopaper 28
-#define ERRwrite 29 /* write fault */
-#define ERRread 30 /* read fault */
-#define ERRgeneral 31 /* General hardware failure */
-#define ERRwrongdisk 34
-#define ERRFCBunavail 35
-#define ERRsharebufexc 36 /* share buffer exceeded */
-#define ERRdiskfull 39
-
-
-typedef char pstring[1024];
-typedef char fstring[128];
-typedef fstring string;
+#define STYPE_DISKTREE 0 /* Disk drive */
+#define STYPE_PRINTQ 1 /* Spooler queue */
+#define STYPE_DEVICE 2 /* Serial device */
+#define STYPE_IPC 3 /* Interprocess communication (IPC) */
+#define STYPE_HIDDEN 0x80000000 /* share is a hidden one (ends with $) */
+
+#include "doserr.h"
+
+#ifndef _PSTRING
+
+#define PSTRING_LEN 1024
+#define FSTRING_LEN 256
+
+typedef char pstring[PSTRING_LEN];
+typedef char fstring[FSTRING_LEN];
+
+#define _PSTRING
+
+#endif
+
+/*
+ * SMB UCS2 (16-bit unicode) internal type.
+ */
+
+typedef uint16 smb_ucs2_t;
+
+/* ucs2 string types. */
+typedef smb_ucs2_t wpstring[PSTRING_LEN];
+typedef smb_ucs2_t wfstring[FSTRING_LEN];
+
+
+#ifdef WORDS_BIGENDIAN
+#define UCS2_SHIFT 8
+#else
+#define UCS2_SHIFT 0
+#endif
+
+/* turn a 7 bit character into a ucs2 character */
+#define UCS2_CHAR(c) ((c) << UCS2_SHIFT)
+
+/* pipe string names */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_SAMR "\\PIPE\\samr"
+#define PIPE_WINREG "\\PIPE\\winreg"
+#define PIPE_WKSSVC "\\PIPE\\wkssvc"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_NTLSA "\\PIPE\\ntlsa"
+#define PIPE_NTSVCS "\\PIPE\\ntsvcs"
+#define PIPE_LSASS "\\PIPE\\lsass"
+#define PIPE_LSARPC "\\PIPE\\lsarpc"
+#define PIPE_SPOOLSS "\\PIPE\\spoolss"
+#define PIPE_NETDFS "\\PIPE\\netdfs"
+
+/* 64 bit time (100usec) since ????? - cifs6.txt, section 3.5, page 30 */
+typedef struct nttime_info
+{
+ uint32 low;
+ uint32 high;
+} NTTIME;
+
+
+/* the following rather strange looking definitions of NTSTATUS and WERROR
+ and there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using BOOL for internal functions
+*/
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} NTSTATUS;
+#define NT_STATUS(x) ((NTSTATUS) { x })
+#define NT_STATUS_V(x) ((x).v)
+#else
+typedef uint32 NTSTATUS;
+#define NT_STATUS(x) (x)
+#define NT_STATUS_V(x) (x)
+#endif
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32 v;} WERROR;
+#define W_ERROR(x) ((WERROR) { x })
+#define W_ERROR_V(x) ((x).v)
+#else
+typedef uint32 WERROR;
+#define W_ERROR(x) (x)
+#define W_ERROR_V(x) (x)
+#endif
+
+#define NT_STATUS_IS_OK(x) (NT_STATUS_V(x) == 0)
+#define NT_STATUS_IS_ERR(x) ((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000)
+#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
+#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
+
+
+/* Allowable account control bits */
+#define ACB_DISABLED 0x0001 /* 1 = User account disabled */
+#define ACB_HOMDIRREQ 0x0002 /* 1 = Home directory required */
+#define ACB_PWNOTREQ 0x0004 /* 1 = User password not required */
+#define ACB_TEMPDUP 0x0008 /* 1 = Temporary duplicate account */
+#define ACB_NORMAL 0x0010 /* 1 = Normal user account */
+#define ACB_MNS 0x0020 /* 1 = MNS logon user account */
+#define ACB_DOMTRUST 0x0040 /* 1 = Interdomain trust account */
+#define ACB_WSTRUST 0x0080 /* 1 = Workstation trust account */
+#define ACB_SVRTRUST 0x0100 /* 1 = Server trust account */
+#define ACB_PWNOEXP 0x0200 /* 1 = User password does not expire */
+#define ACB_AUTOLOCK 0x0400 /* 1 = Account auto locked */
+
+#define MAX_HOURS_LEN 32
typedef struct
{
- int size;
- int mode;
- int uid;
- int gid;
- /* these times are normally kept in GMT */
- time_t mtime;
- time_t atime;
- time_t ctime;
- pstring name;
-} file_info;
+ uint32 pid;
+ uint16 vuid;
+
+}
+vuser_key;
+
+
+struct use_info
+{
+ BOOL connected;
+ char *srv_name;
+ vuser_key key;
+ char *user_name;
+ char *domain;
+};
+
+#ifndef MAXSUBAUTHS
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+#endif
+
+#ifndef _DOM_SID
+/**
+ * @brief Security Identifier
+ *
+ * @sa http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/accctrl_38yn.asp
+ **/
+typedef struct sid_info
+{
+ uint8 sid_rev_num; /**< SID revision number */
+ uint8 num_auths; /**< Number of sub-authorities */
+ uint8 id_auth[6]; /**< Identifier Authority */
+ /*
+ * Pointer to sub-authorities.
+ *
+ * @note The values in these uint32's are in *native* byteorder, not
+ * neccessarily little-endian...... JRA.
+ */
+ uint32 sub_auths[MAXSUBAUTHS];
+
+} DOM_SID;
+#define _DOM_SID
+#endif
+
+/*
+ * The complete list of SIDS belonging to this user.
+ * Created when a vuid is registered.
+ * The definition of the user_sids array is as follows :
+ *
+ * token->user_sids[0] = primary user SID.
+ * token->user_sids[1] = primary group SID.
+ * token->user_sids[2..num_sids] = supplementary group SIDS.
+ */
+
+#define PRIMARY_USER_SID_INDEX 0
+#define PRIMARY_GROUP_SID_INDEX 1
+
+#ifndef _NT_USER_TOKEN
+typedef struct _nt_user_token {
+ size_t num_sids;
+ DOM_SID *user_sids;
+} NT_USER_TOKEN;
+#define _NT_USER_TOKEN
+#endif
+
+/*** query a local group, get a list of these: shows who is in that group ***/
+
+/* local group member info */
+typedef struct local_grp_member_info
+{
+ DOM_SID sid ; /* matches with name */
+ uint8 sid_use; /* usr=1 grp=2 dom=3 alias=4 wkng=5 del=6 inv=7 unk=8 */
+ fstring name ; /* matches with sid: must be of the form "DOMAIN\account" */
+
+} LOCAL_GRP_MEMBER;
+
+/* enumerate these to get list of local groups */
+
+/* local group info */
+typedef struct local_grp_info
+{
+ fstring name;
+ fstring comment;
+} LOCAL_GRP;
+
+/*** enumerate these to get list of domain groups ***/
+
+/* domain group member info */
+typedef struct domain_grp_info
+{
+ fstring name;
+ fstring comment;
+ uint32 rid; /* group rid */
+ uint8 attr; /* attributes forced to be set to 0x7: SE_GROUP_xxx */
+
+} DOMAIN_GRP;
+
+/*** query a domain group, get a list of these: shows who is in that group ***/
+
+/* domain group info */
+typedef struct domain_grp_member_info
+{
+ fstring name;
+ uint8 attr; /* attributes forced to be set to 0x7: SE_GROUP_xxx */
+
+} DOMAIN_GRP_MEMBER;
+
+/* 32 bit time (sec) since 01jan1970 - cifs6.txt, section 3.5, page 30 */
+typedef struct time_info
+{
+ uint32 time;
+} UTIME;
/* Structure used when SMBwritebmpx is active */
typedef struct
- {
- int wr_total_written; /* So we know when to discard this */
- int32 wr_timeout;
- int32 wr_errclass;
- int32 wr_error; /* Cached errors */
- BOOL wr_mode; /* write through mode) */
- BOOL wr_discard; /* discard all further data */
- } write_bmpx_struct;
+{
+ size_t wr_total_written; /* So we know when to discard this */
+ int32 wr_timeout;
+ int32 wr_errclass;
+ int32 wr_error; /* Cached errors */
+ BOOL wr_mode; /* write through mode) */
+ BOOL wr_discard; /* discard all further data */
+} write_bmpx_struct;
+
+typedef struct write_cache
+{
+ SMB_OFF_T file_size;
+ SMB_OFF_T offset;
+ size_t alloc_size;
+ size_t data_size;
+ char *data;
+} write_cache;
typedef struct
{
- int cnum;
- int fd;
- int pos;
- int size;
- int mode;
- char *mmap_ptr;
- int mmap_size;
- write_bmpx_struct *wbmpx_ptr;
- time_t open_time;
- BOOL open;
- BOOL can_lock;
- BOOL can_read;
- BOOL can_write;
- BOOL share_mode;
- BOOL share_pending;
- BOOL print_file;
- BOOL modified;
- char *name;
+ smb_ucs2_t *path;
+ smb_ucs2_t *name;
+ smb_ucs2_t *unixname;
+ smb_ucs2_t *dosname;
+ SMB_STRUCT_STAT *statinfo;
+} smb_filename;
+
+
+typedef struct files_struct
+{
+ struct files_struct *next, *prev;
+ int fnum;
+ struct connection_struct *conn;
+ int fd;
+ int print_jobid;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ BOOL delete_on_close;
+ SMB_OFF_T pos;
+ SMB_OFF_T size;
+ mode_t mode;
+ uint16 vuid;
+ write_bmpx_struct *wbmpx_ptr;
+ write_cache *wcp;
+ struct timeval open_time;
+ int share_mode;
+ time_t pending_modtime;
+ int oplock_type;
+ int sent_oplock_break;
+ unsigned long file_id;
+ BOOL can_lock;
+ BOOL can_read;
+ BOOL can_write;
+ BOOL print_file;
+ BOOL modified;
+ BOOL is_directory;
+ BOOL directory_delete_on_close;
+ BOOL stat_open;
+ char *fsp_name;
} files_struct;
+/*
+ * Structure used to keep directory state information around.
+ * Used in NT change-notify code.
+ */
+
+typedef struct
+{
+ time_t modify_time;
+ time_t status_time;
+} dir_status_struct;
struct uid_cache {
int entries;
- int list[UID_CACHE_SIZE];
+ uid_t list[UID_CACHE_SIZE];
};
typedef struct
{
- int service;
- BOOL force_user;
- int uid; /* uid of user who *opened* this connection */
- int gid; /* gid of user who *opened* this connection */
- struct uid_cache uid_cache;
- void *dirptr;
- BOOL open;
- BOOL printer;
- BOOL ipc;
- BOOL read_only;
- BOOL admin_user;
- char *dirpath;
- char *connectpath;
- char *origpath;
- char *user; /* name of user who *opened* this connection */
- /* following groups stuff added by ih */
- /* This groups info is valid for the user that *opened* the connection */
- int ngroups;
- gid_t *groups;
- int *igroups; /* an integer version - some OSes are broken :-( */
- time_t lastused;
- BOOL used;
- int num_files_open;
-} connection_struct;
+ char *name;
+ BOOL is_wild;
+} name_compare_entry;
+/* Include VFS stuff */
-typedef struct
+#include "vfs.h"
+
+typedef struct connection_struct
{
- int uid; /* uid of a validated user */
- int gid; /* gid of a validated user */
- fstring name; /* name of a validated user */
- BOOL guest;
- /* following groups stuff added by ih */
- /* This groups info is needed for when we become_user() for this uid */
- int user_ngroups;
- gid_t *user_groups;
- int *user_igroups; /* an integer version - some OSes are broken :-( */
-} user_struct;
+ struct connection_struct *next, *prev;
+ unsigned cnum; /* an index passed over the wire */
+ int service;
+ BOOL force_user;
+ struct uid_cache uid_cache;
+ void *dirptr;
+ BOOL printer;
+ BOOL ipc;
+ BOOL read_only;
+ BOOL admin_user;
+ char *dirpath;
+ char *connectpath;
+ char *origpath;
+
+ struct vfs_ops vfs_ops; /* Filesystem operations */
+ /* Handle on dlopen() call */
+ void *dl_handle;
+
+ char *user; /* name of user who *opened* this connection */
+ uid_t uid; /* uid of user who *opened* this connection */
+ gid_t gid; /* gid of user who *opened* this connection */
+ char client_address[18]; /* String version of client IP address. */
+
+ uint16 vuid; /* vuid of user who *opened* this connection, or UID_FIELD_INVALID */
+
+ /* following groups stuff added by ih */
+
+ /* This groups info is valid for the user that *opened* the connection */
+ int ngroups;
+ gid_t *groups;
+ NT_USER_TOKEN *nt_user_token;
+
+ time_t lastused;
+ BOOL used;
+ int num_files_open;
+ name_compare_entry *hide_list; /* Per-share list of files to return as hidden. */
+ name_compare_entry *veto_list; /* Per-share list of files to veto (never show). */
+ name_compare_entry *veto_oplock_list; /* Per-share list of files to refuse oplocks on. */
+} connection_struct;
-enum {LPQ_QUEUED,LPQ_PAUSED,LPQ_SPOOLING,LPQ_PRINTING};
+struct current_user
+{
+ connection_struct *conn;
+ uint16 vuid;
+ uid_t uid;
+ gid_t gid;
+ int ngroups;
+ gid_t *groups;
+ NT_USER_TOKEN *nt_user_token;
+};
-typedef struct
+/* Defines for the sent_oplock_break field above. */
+#define NO_BREAK_SENT 0
+#define EXCLUSIVE_BREAK_SENT 1
+#define LEVEL_II_BREAK_SENT 2
+
+typedef struct {
+ fstring smb_name; /* user name from the client */
+ fstring unix_name; /* unix user name of a validated user */
+ fstring full_name; /* to store full name (such as "Joe Bloggs") from gecos field of password file */
+ fstring domain; /* domain that the client specified */
+} userdom_struct;
+
+/* Extra fields above "LPQ_PRINTING" are used to map extra NT status codes. */
+
+enum {LPQ_QUEUED=0,LPQ_PAUSED,LPQ_SPOOLING,LPQ_PRINTING,LPQ_ERROR,LPQ_DELETING,
+ LPQ_OFFLINE,LPQ_PAPEROUT,LPQ_PRINTED,LPQ_DELETED,LPQ_BLOCKED,LPQ_USER_INTERVENTION};
+
+typedef struct _print_queue_struct
{
int job;
int size;
int status;
int priority;
time_t time;
- char user[30];
- char file[100];
+ fstring user;
+ fstring file;
} print_queue_struct;
enum {LPSTAT_OK, LPSTAT_STOPPED, LPSTAT_ERROR};
@@ -329,68 +545,219 @@ enum {LPSTAT_OK, LPSTAT_STOPPED, LPSTAT_ERROR};
typedef struct
{
fstring message;
+ int qcount;
int status;
} print_status_struct;
+/* used for server information: client, nameserv and ipc */
+struct server_info_struct
+{
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain; /* used ONLY in ipc.c NOT namework.c */
+ BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
+};
+
-/* this is used for smbstatus */
-struct connect_record
+/* used for network interfaces */
+struct interface
{
- int magic;
- int pid;
- int cnum;
- int uid;
- int gid;
- char name[24];
- char addr[24];
- char machine[128];
- time_t start;
+ struct interface *next, *prev;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
};
+/* struct returned by get_share_modes */
+typedef struct {
+ pid_t pid;
+ uint16 op_port;
+ uint16 op_type;
+ int share_mode;
+ struct timeval time;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ unsigned long share_file_id;
+} share_mode_entry;
+
+
+#define SHAREMODE_FN_CAST() \
+ void (*)(share_mode_entry *, char*)
+
+#define SHAREMODE_FN(fn) \
+ void (*fn)(share_mode_entry *, char*)
+
+typedef struct sam_passwd
+{
+ time_t logon_time; /* logon time */
+ time_t logoff_time; /* logoff time */
+ time_t kickoff_time; /* kickoff time */
+ time_t pass_last_set_time; /* password last set time */
+ time_t pass_can_change_time; /* password can change time */
+ time_t pass_must_change_time; /* password must change time */
+
+ pstring username; /* UNIX username string */
+ pstring domain; /* Windows Domain name */
+ pstring nt_username; /* Windows username string */
+ pstring full_name; /* user's full name string */
+ pstring home_dir; /* home directory string */
+ pstring dir_drive; /* home directory drive string */
+ pstring logon_script; /* logon script string */
+ pstring profile_path; /* profile path string */
+ pstring acct_desc ; /* user description string */
+ pstring workstations; /* login from workstations string */
+ pstring unknown_str ; /* don't know what this is, yet. */
+ pstring munged_dial ; /* munged path name and dial-back tel number */
+
+ uid_t *uid; /* this is a pointer to the unix uid_t */
+ gid_t *gid; /* this is a pointer to the unix gid_t */
+ uint32 user_rid; /* Primary User ID */
+ uint32 group_rid; /* Primary Group ID */
+
+ unsigned char *lm_pw; /* Null if no password */
+ unsigned char *nt_pw; /* Null if no password */
+
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ uint32 unknown_3; /* 0x00ff ffff */
+
+ uint16 logon_divs; /* 168 - number of hours in a week */
+ uint32 hours_len; /* normally 21 bytes */
+ uint8 hours[MAX_HOURS_LEN];
+
+ uint32 unknown_5; /* 0x0002 0000 */
+ uint32 unknown_6; /* 0x0000 04ec */
+
+} SAM_ACCOUNT;
+
+/*
+ * Flags for account policy.
+ */
+#define AP_MIN_PASSWORD_LEN 1
+#define AP_PASSWORD_HISTORY 2
+#define AP_USER_MUST_LOGON_TO_CHG_PASS 3
+#define AP_MAX_PASSWORD_AGE 4
+#define AP_MIN_PASSWORD_AGE 5
+#define AP_LOCK_ACCOUNT_DURATION 6
+#define AP_RESET_COUNT_TIME 7
+#define AP_BAD_ATTEMPT_LOCKOUT 8
+#define AP_TIME_TO_LOGOUT 9
+
+
+/*
+ * Flags for local user manipulation.
+ */
+
+#define LOCAL_ADD_USER 0x1
+#define LOCAL_DELETE_USER 0x2
+#define LOCAL_DISABLE_USER 0x4
+#define LOCAL_ENABLE_USER 0x8
+#define LOCAL_TRUST_ACCOUNT 0x10
+#define LOCAL_SET_NO_PASSWORD 0x20
+#define LOCAL_SET_PASSWORD 0x40
+#define LOCAL_SET_LDAP_ADMIN_PW 0x80
+#define LOCAL_INTERDOM_ACCOUNT 0x100
+
+/* key and data in the connections database - used in smbstatus and smbd */
+struct connections_key {
+ pid_t pid;
+ int cnum;
+ fstring name;
+};
+
+struct connections_data {
+ int magic;
+ pid_t pid;
+ int cnum;
+ uid_t uid;
+ gid_t gid;
+ char name[24];
+ char addr[24];
+ char machine[FSTRING_LEN];
+ time_t start;
+};
+
+
+/* key and data records in the tdb locking database */
+struct locking_key {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+};
+
+struct locking_data {
+ union {
+ int num_share_mode_entries;
+ share_mode_entry dummy; /* Needed for alignment. */
+ } u;
+ /* the following two entries are implicit
+ share_mode_entry modes[num_share_mode_entries];
+ char file_name[];
+ */
+};
+
+
+/* the following are used by loadparm for option lists */
+typedef enum
+{
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
+ P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM,P_SEP
+} parm_type;
+
+typedef enum
+{
+ P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
+} parm_class;
+
+/* passed to br lock code */
+enum brl_type {READ_LOCK, WRITE_LOCK};
+
+struct enum_list {
+ int value;
+ char *name;
+};
+
+#define BRLOCK_FN_CAST() \
+ void (*)(SMB_DEV_T dev, SMB_INO_T ino, int pid, \
+ enum brl_type lock_type, \
+ br_off start, br_off size)
+#define BRLOCK_FN(fn) \
+ void (*fn)(SMB_DEV_T dev, SMB_INO_T ino, int pid, \
+ enum brl_type lock_type, \
+ br_off start, br_off size)
+struct parm_struct
+{
+ char *label;
+ parm_type type;
+ parm_class class;
+ void *ptr;
+ BOOL (*special)(char *, char **);
+ struct enum_list *enum_list;
+ unsigned flags;
+ union {
+ BOOL bvalue;
+ int ivalue;
+ char *svalue;
+ char cvalue;
+ char **lvalue;
+ } def;
+};
+
+struct bitmap {
+ uint32 *b;
+ int n;
+};
+
+#define FLAG_BASIC 0x01 /* fundamental options */
+#define FLAG_SHARE 0x02 /* file sharing options */
+#define FLAG_PRINT 0x04 /* printing options */
+#define FLAG_GLOBAL 0x08 /* local options that should be globally settable in SWAT */
+#define FLAG_DEPRECATED 0x10 /* options that should no longer be used */
+#define FLAG_HIDE 0x20 /* options that should be hidden in SWAT */
+
+#ifndef LOCKING_VERSION
+#define LOCKING_VERSION 4
+#endif /* LOCKING_VERSION */
-#define LOCKING_VERSION 2
-
-/* these are useful macros for checking validity of handles */
-#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_OPEN_FILES))
-#define OPEN_FNUM(fnum) (VALID_FNUM(fnum) && Files[fnum].open)
-#define VALID_CNUM(cnum) (((cnum) >= 0) && ((cnum) < MAX_CONNECTIONS))
-#define OPEN_CNUM(cnum) (VALID_CNUM(cnum) && Connections[cnum].open)
-#define IS_IPC(cnum) (VALID_CNUM(cnum) && Connections[cnum].ipc)
-#define FNUM_OK(fnum,c) (OPEN_FNUM(fnum) && (c)==Files[fnum].cnum)
-
-#define CHECK_FNUM(fnum,c) if (!FNUM_OK(fnum,c)) \
- return(ERROR(ERRDOS,ERRbadfid))
-#define CHECK_READ(fnum) if (!Files[fnum].can_read) \
- return(ERROR(ERRDOS,ERRbadaccess))
-#define CHECK_WRITE(fnum) if (!Files[fnum].can_write) \
- return(ERROR(ERRDOS,ERRbadaccess))
-#define CHECK_ERROR(fnum) if (HAS_CACHED_ERROR(fnum)) \
- return(CACHED_ERROR(fnum))
-
-/* translates a connection number into a service number */
-#define SNUM(cnum) (Connections[cnum].service)
-
-/* access various service details */
-#define SERVICE(snum) (lp_servicename(snum))
-#define PRINTCAP (lp_printcapname())
-#define PRINTCOMMAND(snum) (lp_printcommand(snum))
-#define PRINTERNAME(snum) (lp_printername(snum))
-#define CAN_WRITE(cnum) (OPEN_CNUM(cnum) && !Connections[cnum].read_only)
-#define VALID_SNUM(snum) (lp_snum_ok(snum))
-#define GUEST_OK(snum) (VALID_SNUM(snum) && lp_guest_ok(snum))
-#define GUEST_ONLY(snum) (VALID_SNUM(snum) && lp_guest_only(snum))
-#define CAN_SETDIR(snum) (!lp_no_set_dir(snum))
-#define CAN_PRINT(cnum) (OPEN_CNUM(cnum) && lp_print_ok(SNUM(cnum)))
-#define POSTSCRIPT(cnum) (OPEN_CNUM(cnum) && lp_postscript(SNUM(cnum)))
-#define MAP_HIDDEN(cnum) (OPEN_CNUM(cnum) && lp_map_hidden(SNUM(cnum)))
-#define MAP_SYSTEM(cnum) (OPEN_CNUM(cnum) && lp_map_system(SNUM(cnum)))
-#define MAP_ARCHIVE(cnum) (OPEN_CNUM(cnum) && lp_map_archive(SNUM(cnum)))
-#define CREATE_MODE(cnum) (lp_create_mode(SNUM(cnum)) | 0700)
-#ifdef SMB_PASSWD
-#define SMBENCRYPT() (lp_encrypted_passwords())
-#else
-#define SMBENCRYPT() (False)
-#endif
/* the basic packet size, assuming no words or bytes */
#define smb_size 39
@@ -428,6 +795,15 @@ struct connect_record
#define smb_vwv16 69
#define smb_vwv17 71
+/* flag defines. CIFS spec 3.1.1 */
+#define FLAG_SUPPORT_LOCKREAD 0x01
+#define FLAG_CLIENT_BUF_AVAIL 0x02
+#define FLAG_RESERVED 0x04
+#define FLAG_CASELESS_PATHNAMES 0x08
+#define FLAG_CANONICAL_PATHNAMES 0x10
+#define FLAG_REQUEST_OPLOCK 0x20
+#define FLAG_REQUEST_BATCH_OPLOCK 0x40
+#define FLAG_REPLY 0x80
/* the complete */
#define SMBmkdir 0x00 /* create directory */
@@ -501,6 +877,7 @@ struct connect_record
#define SMBffirst 0x82 /* find first */
#define SMBfunique 0x83 /* find unique */
#define SMBfclose 0x84 /* find close */
+#define SMBkeepalive 0x85 /* keepalive */
#define SMBinvalid 0xFE /* invalid command */
/* Extended 2.0 protocol */
@@ -510,23 +887,41 @@ struct connect_record
#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
#define SMBulogoffX 0x74 /* user logoff */
-
-/* these are the TRANS2 sub commands */
-#define TRANSACT2_OPEN 0
-#define TRANSACT2_FINDFIRST 1
-#define TRANSACT2_FINDNEXT 2
-#define TRANSACT2_QFSINFO 3
-#define TRANSACT2_SETFSINFO 4
-#define TRANSACT2_QPATHINFO 5
-#define TRANSACT2_SETPATHINFO 6
-#define TRANSACT2_QFILEINFO 7
-#define TRANSACT2_SETFILEINFO 8
-#define TRANSACT2_FSCTL 9
-#define TRANSACT2_IOCTL 10
-#define TRANSACT2_FINDNOTIFYFIRST 11
-#define TRANSACT2_FINDNOTIFYNEXT 12
-#define TRANSACT2_MKDIR 13
-
+/* NT SMB extensions. */
+#define SMBnttrans 0xA0 /* NT transact */
+#define SMBnttranss 0xA1 /* NT transact secondary */
+#define SMBntcreateX 0xA2 /* NT create and X */
+#define SMBntcancel 0xA4 /* NT cancel */
+
+/* These are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0
+#define TRANSACT2_FINDFIRST 1
+#define TRANSACT2_FINDNEXT 2
+#define TRANSACT2_QFSINFO 3
+#define TRANSACT2_SETFSINFO 4
+#define TRANSACT2_QPATHINFO 5
+#define TRANSACT2_SETPATHINFO 6
+#define TRANSACT2_QFILEINFO 7
+#define TRANSACT2_SETFILEINFO 8
+#define TRANSACT2_FSCTL 9
+#define TRANSACT2_IOCTL 0xA
+#define TRANSACT2_FINDNOTIFYFIRST 0xB
+#define TRANSACT2_FINDNOTIFYNEXT 0xC
+#define TRANSACT2_MKDIR 0xD
+#define TRANSACT2_SESSION_SETUP 0xE
+#define TRANSACT2_GET_DFS_REFERRAL 0x10
+#define TRANSACT2_REPORT_DFS_INCONSISTANCY 0x11
+
+/* These are the NT transact sub commands. */
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
+
+/* Relevant IOCTL codes */
+#define IOCTL_QUERY_JOB_INFO 0x530060
/* these are the trans2 sub fields for primary requests */
#define smb_tpscnt smb_vwv0
@@ -565,369 +960,259 @@ struct connect_record
#define smb_droff smb_vwv7
#define smb_drdisp smb_vwv8
+/* these are for the NT trans primary request. */
+#define smb_nt_MaxSetupCount smb_vwv0
+#define smb_nt_Flags (smb_vwv0 + 1)
+#define smb_nt_TotalParameterCount (smb_vwv0 + 3)
+#define smb_nt_TotalDataCount (smb_vwv0 + 7)
+#define smb_nt_MaxParameterCount (smb_vwv0 + 11)
+#define smb_nt_MaxDataCount (smb_vwv0 + 15)
+#define smb_nt_ParameterCount (smb_vwv0 + 19)
+#define smb_nt_ParameterOffset (smb_vwv0 + 23)
+#define smb_nt_DataCount (smb_vwv0 + 27)
+#define smb_nt_DataOffset (smb_vwv0 + 31)
+#define smb_nt_SetupCount (smb_vwv0 + 35)
+#define smb_nt_Function (smb_vwv0 + 36)
+#define smb_nt_SetupStart (smb_vwv0 + 38)
+
+/* these are for the NT trans secondary request. */
+#define smb_nts_TotalParameterCount (smb_vwv0 + 3)
+#define smb_nts_TotalDataCount (smb_vwv0 + 7)
+#define smb_nts_ParameterCount (smb_vwv0 + 11)
+#define smb_nts_ParameterOffset (smb_vwv0 + 15)
+#define smb_nts_ParameterDisplacement (smb_vwv0 + 19)
+#define smb_nts_DataCount (smb_vwv0 + 23)
+#define smb_nts_DataOffset (smb_vwv0 + 27)
+#define smb_nts_DataDisplacement (smb_vwv0 + 31)
+
+/* these are for the NT trans reply. */
+#define smb_ntr_TotalParameterCount (smb_vwv0 + 3)
+#define smb_ntr_TotalDataCount (smb_vwv0 + 7)
+#define smb_ntr_ParameterCount (smb_vwv0 + 11)
+#define smb_ntr_ParameterOffset (smb_vwv0 + 15)
+#define smb_ntr_ParameterDisplacement (smb_vwv0 + 19)
+#define smb_ntr_DataCount (smb_vwv0 + 23)
+#define smb_ntr_DataOffset (smb_vwv0 + 27)
+#define smb_ntr_DataDisplacement (smb_vwv0 + 31)
+
+/* these are for the NT create_and_X */
+#define smb_ntcreate_NameLength (smb_vwv0 + 5)
+#define smb_ntcreate_Flags (smb_vwv0 + 7)
+#define smb_ntcreate_RootDirectoryFid (smb_vwv0 + 11)
+#define smb_ntcreate_DesiredAccess (smb_vwv0 + 15)
+#define smb_ntcreate_AllocationSize (smb_vwv0 + 19)
+#define smb_ntcreate_FileAttributes (smb_vwv0 + 27)
+#define smb_ntcreate_ShareAccess (smb_vwv0 + 31)
+#define smb_ntcreate_CreateDisposition (smb_vwv0 + 35)
+#define smb_ntcreate_CreateOptions (smb_vwv0 + 39)
+#define smb_ntcreate_ImpersonationLevel (smb_vwv0 + 43)
+#define smb_ntcreate_SecurityFlags (smb_vwv0 + 47)
+
+/* this is used on a TConX. I'm not sure the name is very helpful though */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001
+#define SMB_SHARE_IN_DFS 0x0002
+
+/* Named pipe write mode flags. Used in writeX calls. */
+#define PIPE_RAW_MODE 0x4
+#define PIPE_START_MESSAGE 0x8
+
+/* these are the constants used in the above call. */
+/* DesiredAccess */
+/* File Specific access rights. */
+#define FILE_READ_DATA 0x001
+#define FILE_WRITE_DATA 0x002
+#define FILE_APPEND_DATA 0x004
+#define FILE_READ_EA 0x008
+#define FILE_WRITE_EA 0x010
+#define FILE_EXECUTE 0x020
+#define FILE_DELETE_CHILD 0x040
+#define FILE_READ_ATTRIBUTES 0x080
+#define FILE_WRITE_ATTRIBUTES 0x100
+
+#define FILE_ALL_ACCESS 0x1FF
+
+/* the desired access to use when opening a pipe */
+#define DESIRED_ACCESS_PIPE 0x2019f
+
+/* Generic access masks & rights. */
+#define SPECIFIC_RIGHTS_MASK 0x00FFFFL
+#define STANDARD_RIGHTS_MASK 0xFF0000L
+#define DELETE_ACCESS (1L<<16) /* 0x00010000 */
+#define READ_CONTROL_ACCESS (1L<<17) /* 0x00020000 */
+#define WRITE_DAC_ACCESS (1L<<18) /* 0x00040000 */
+#define WRITE_OWNER_ACCESS (1L<<19) /* 0x00080000 */
+#define SYNCHRONIZE_ACCESS (1L<<20) /* 0x00100000 */
+
+/* Combinations of standard masks. */
+#define STANDARD_RIGHTS_ALL_ACCESS (DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS)
+#define STANDARD_RIGHTS_EXECUTE_ACCESS (READ_CONTROL_ACCESS)
+#define STANDARD_RIGHTS_READ_ACCESS (READ_CONTROL_ACCESS)
+#define STANDARD_RIGHTS_REQUIRED_ACCESS (DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS)
+#define STANDARD_RIGHTS_WRITE_ACCESS (READ_CONTROL_ACCESS)
+
+#define SYSTEM_SECURITY_ACCESS (1L<<24) /* 0x01000000 */
+#define MAXIMUM_ALLOWED_ACCESS (1L<<25) /* 0x02000000 */
+#define GENERIC_ALL_ACCESS (1<<28) /* 0x10000000 */
+#define GENERIC_EXECUTE_ACCESS (1<<29) /* 0x20000000 */
+#define GENERIC_WRITE_ACCESS (1<<30) /* 0x40000000 */
+#define GENERIC_READ_ACCESS (((unsigned)1)<<31) /* 0x80000000 */
+
+/* Mapping of generic access rights for files to specific rights. */
+
+#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS| SYNCHRONIZE_ACCESS|FILE_ALL_ACCESS)
+
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|FILE_READ_DATA|FILE_READ_ATTRIBUTES|\
+ FILE_READ_EA|SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE_ACCESS|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|\
+ FILE_WRITE_EA|FILE_APPEND_DATA|SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|FILE_READ_ATTRIBUTES|\
+ FILE_EXECUTE|SYNCHRONIZE_ACCESS)
+
+/* Mapping of access rights to UNIX perms. */
+#define UNIX_ACCESS_RWX FILE_GENERIC_ALL
+#define UNIX_ACCESS_R FILE_GENERIC_READ
+#define UNIX_ACCESS_W FILE_GENERIC_WRITE
+#define UNIX_ACCESS_X FILE_GENERIC_EXECUTE
+
+#if 0
+/*
+ * This is the old mapping we used to use. To get W2KSP2 profiles
+ * working we need to map to the canonical file perms.
+ */
+#define UNIX_ACCESS_RWX (UNIX_ACCESS_R|UNIX_ACCESS_W|UNIX_ACCESS_X)
+#define UNIX_ACCESS_R (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_READ_ATTRIBUTES|FILE_READ_EA|FILE_READ_DATA)
+#define UNIX_ACCESS_W (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA|\
+ FILE_APPEND_DATA|FILE_WRITE_DATA)
+#define UNIX_ACCESS_X (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
+ FILE_EXECUTE|FILE_READ_ATTRIBUTES)
+#endif
+
+#define UNIX_ACCESS_NONE (WRITE_OWNER_ACCESS)
+
+/* Flags field. */
+#define REQUEST_OPLOCK 2
+#define REQUEST_BATCH_OPLOCK 4
+#define OPEN_DIRECTORY 8
+
+/* ShareAccess field. */
+#define FILE_SHARE_NONE 0 /* Cannot be used in bitmask. */
+#define FILE_SHARE_READ 1
+#define FILE_SHARE_WRITE 2
+#define FILE_SHARE_DELETE 4
+
+/* FileAttributesField */
+#define FILE_ATTRIBUTE_READONLY aRONLY
+#define FILE_ATTRIBUTE_HIDDEN aHIDDEN
+#define FILE_ATTRIBUTE_SYSTEM aSYSTEM
+#define FILE_ATTRIBUTE_DIRECTORY aDIR
+#define FILE_ATTRIBUTE_ARCHIVE aARCH
+#define FILE_ATTRIBUTE_NORMAL 0x80L
+#define FILE_ATTRIBUTE_TEMPORARY 0x100L
+#define FILE_ATTRIBUTE_SPARSE 0x200L
+#define FILE_ATTRIBUTE_COMPRESSED 0x800L
+#define FILE_ATTRIBUTE_NONINDEXED 0x2000L
+#define SAMBA_ATTRIBUTES_MASK 0x7F
+
+/* Flags - combined with attributes. */
+#define FILE_FLAG_WRITE_THROUGH 0x80000000L
+#define FILE_FLAG_NO_BUFFERING 0x20000000L
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000L
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000L
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000L
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000L
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000L
+
+/* CreateDisposition field. */
+#define FILE_SUPERSEDE 0
+#define FILE_OPEN 1
+#define FILE_CREATE 2
+#define FILE_OPEN_IF 3
+#define FILE_OVERWRITE 4
+#define FILE_OVERWRITE_IF 5
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE 0x0001
+#define FILE_WRITE_THROUGH 0x0002
+#define FILE_SEQUENTIAL_ONLY 0x0004
+#define FILE_NON_DIRECTORY_FILE 0x0040
+#define FILE_NO_EA_KNOWLEDGE 0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400
+#define FILE_RANDOM_ACCESS 0x0800
+#define FILE_DELETE_ON_CLOSE 0x1000
+
+/* Responses when opening a file. */
+#define FILE_WAS_OPENED 1
+#define FILE_WAS_CREATED 2
+#define FILE_WAS_OVERWRITTEN 3
+
+/* File type flags */
+#define FILE_TYPE_DISK 0
+#define FILE_TYPE_BYTE_MODE_PIPE 1
+#define FILE_TYPE_MESSAGE_MODE_PIPE 2
+#define FILE_TYPE_PRINTER 3
+#define FILE_TYPE_COMM_DEVICE 4
+#define FILE_TYPE_UNKNOWN 0xFFFF
+
+/* Flag for NT transact rename call. */
+#define RENAME_REPLACE_IF_EXISTS 1
+
+/* Filesystem Attributes. */
+#define FILE_CASE_SENSITIVE_SEARCH 0x01
+#define FILE_CASE_PRESERVED_NAMES 0x02
+#define FILE_UNICODE_ON_DISK 0x04
+/* According to cifs9f, this is 4, not 8 */
+/* Acconding to testing, this actually sets the security attribute! */
+#define FILE_PERSISTENT_ACLS 0x08
+/* These entries added from cifs9f --tsb */
+#define FILE_FILE_COMPRESSION 0x10
+#define FILE_VOLUME_QUOTAS 0x20
+/* I think this is wrong. JRA #define FILE_DEVICE_IS_MOUNTED 0x20 */
+#define FILE_VOLUME_SPARSE_FILE 0x40
+#define FILE_VOLUME_IS_COMPRESSED 0x8000
+
+/* ChangeNotify flags. */
+#define FILE_NOTIFY_CHANGE_FILE 0x001
+#define FILE_NOTIFY_CHANGE_DIR_NAME 0x002
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x004
+#define FILE_NOTIFY_CHANGE_SIZE 0x008
+#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x010
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x020
+#define FILE_NOTIFY_CHANGE_CREATION 0x040
+#define FILE_NOTIFY_CHANGE_EA 0x080
+#define FILE_NOTIFY_CHANGE_SECURITY 0x100
+#define FILE_NOTIFY_CHANGE_FILE_NAME 0x200
+
/* where to find the base of the SMB packet proper */
#define smb_base(buf) (((char *)(buf))+4)
+/* we don't allow server strings to be longer than 48 characters as
+ otherwise NT will not honour the announce packets */
+#define MAX_SERVER_STRING_LENGTH 48
-#define SUCCESS 0 /* The request was successful. */
-#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
-#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
-#define ERRHRD 0x03 /* Error is an hardware error. */
-#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
-/* structure used to hold the incoming hosts info */
-struct from_host {
- char *name; /* host name */
- char *addr; /* host address */
- struct sockaddr_in *sin; /* their side of the link */
-};
+#define SMB_SUCCESS 0 /* The request was successful. */
-/* and a few prototypes */
-BOOL user_ok(char *user,int snum);
-int sys_rename(char *from, char *to);
-int sys_select(fd_set *fds,struct timeval *tval);
-int sys_unlink(char *fname);
-int sys_open(char *fname,int flags,int mode);
-DIR *sys_opendir(char *dname);
-int sys_stat(char *fname,struct stat *sbuf);
-int sys_lstat(char *fname,struct stat *sbuf);
-int sys_mkdir(char *dname,int mode);
-int sys_rmdir(char *dname);
-int sys_chdir(char *dname);
-int sys_utime(char *fname,struct utimbuf *times);
-int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize);
-void lpq_reset(int);
-void status_printjob(int cnum,int snum,int jobid,int status);
-void DirCacheAdd(char *path,char *name,char *dname,int snum);
-char *DirCacheCheck(char *path,char *name,int snum);
-void DirCacheFlush(int snum);
-int interpret_character_set(char *str, int def);
-char *dos2unix_format(char *, BOOL);
-char *unix2dos_format(char *, BOOL);
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type);
-void BlockSignals(BOOL block);
-void msleep(int t);
-int file_lock(char *name,int timeout);
-void file_unlock(int fd);
-int find_service(char *service);
-int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
-int smb_offset(char *p,char *buf);
-void sync_file(int fnum);
-int PutUniCode(char *dst,char *src);
-void map_username(char *user);
-void close_low_fds(void);
-void clean_share_files(void);
-int write_socket(int fd,char *buf,int len);
-char *readdirname(void *p);
-int dos_chmod(int cnum,char *fname,int mode,struct stat *st);
-int smb_numwords(char *buf);
-int get_share_mode(int cnum,struct stat *sbuf,int *pid);
-void del_share_mode(int fnum);
-BOOL set_share_mode(int fnum,int mode);
-int DSTDiff(time_t t);
-void TimeInit(void);
-void put_long_date(char *p,time_t t);
-time_t interpret_long_date(char *p);
-void dptr_idlecnum(int cnum);
-void dptr_closecnum(int cnum);
-void init_dptrs(void);
-void fault_setup();
-void set_socket_options(int fd, char *options);
-void putip(void *dest,void *src);
-void standard_sub_basic(char *s);
-void *OpenDir(char *name);
-void CloseDir(void *p);
-char *ReadDirName(void *p);
-BOOL SeekDir(void *p,int pos);
-int TellDir(void *p);
-int write_data(int fd,char *buffer,int N);
-BOOL server_cryptkey(char *buf);
-BOOL server_validate(char *buf);
-BOOL become_service(int cnum,BOOL do_chdir);
-BOOL snum_used(int snum);
-BOOL reload_services(BOOL test);
-void reopen_logs(void);
-int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align);
-int str_checksum(char *s);
-time_t file_modtime(char *fname);
-BOOL do_match(char *str, char *regexp, int case_sig);
-BOOL is_a_socket(int fd);
-void _smb_setlen(char *buf,int len);
-void valid_initialise(void);
-BOOL is_8_3(char *fname);
-BOOL is_mangled(char *s);
-void standard_sub(int cnum,char *s);
-void del_printqueue(int cnum,int snum,int jobid);
-BOOL strisnormal(char *s);
-BOOL check_mangled_stack(char *s);
-int sys_chown(char *fname,int uid,int gid);
-int sys_chroot(char *dname);
-BOOL next_token(char **ptr,char *buff,char *sep);
-void invalidate_uid(int uid);
-char *fgets_slash(char *s,int maxlen,FILE *f);
-int read_udp_socket(int fd,char *buf,int len);
-void exit_server(char *reason);
-BOOL process_exists(int pid);
-BOOL chgpasswd(char *name,char *oldpass,char *newpass);
-void array_promote(char *array,int elsize,int element);
-void string_replace(char *s,char oldc,char newc);
-BOOL user_in_list(char *user,char *list);
-BOOL string_sub(char *s,char *pattern,char *insert);
-char *StrnCpy(char *dest,const char *src,int n);
-char *validated_username(int vuid);
-BOOL set_user_password(char *user,char *oldpass,char *newpass);
-int smb_buf_ofs(char *buf);
-char *skip_string(char *buf,int n);
-BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset);
-int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact);
-int write_file(int fnum,char *data,int n);
-BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
-int seek_file(int fnum,int pos);
-BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
-int get_printqueue(int snum,int cnum,print_queue_struct **queue,print_status_struct *status);
-void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev);
-int setup_groups(char *user,int uid, int gid, int *p_ngroups,
- int **p_igroups, gid_t **p_groups);
-int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid);
-char *dptr_path(int key);
-char *dptr_wcard(int key);
-BOOL dptr_set_wcard(int key, char *wcard);
-BOOL dptr_set_attr(int key, uint16 attr);
-uint16 dptr_attr(int key);
-void dptr_close(int key);
-void dptr_closepath(char *path,int pid);
-int dptr_create(int cnum,char *path, BOOL expect_close,int pid);
-BOOL dptr_fill(char *buf,unsigned int key);
-BOOL dptr_zero(char *buf);
-void *dptr_fetch(char *buf,int *num);
-void *dptr_fetch_lanman2(char *params,int dptr_num);
-BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend);
-void open_file(int fnum,int cnum,char *fname,int flags,int mode);
-void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,int mode,int *Access,int *action);
-void close_file(int fnum);
-int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize);
-int reply_trans(char *inbuf,char *outbuf);
-char *ufc_crypt(char *key,char *salt);
-BOOL authorise_login(int snum,char *user,char *password, int pwlen,
- BOOL *guest,BOOL *force,int vuid);
-void add_session_user(char *user);
-int valid_uid(int uid);
-user_struct *get_valid_user_struct(int uid);
-BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL nt_password);
-void register_uid(int uid,int gid,char *name,BOOL guest);
-BOOL fromhost(int sock,struct from_host *f);
-BOOL strhasupper(char *s);
-BOOL strhaslower(char *s);
-int disk_free(char *path,int *bsize,int *dfree,int *dsize);
-char *uidtoname(int uid);
-char *gidtoname(int gid);
-int get_share_mode_byname(int cnum,char *fname,int *pid);
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid);
-BOOL check_file_sharing(int cnum,char *fname);
-char *StrCpy(char *dest,char *src);
-int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
-time_t make_unix_date2(void *date_ptr);
-int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
-mode_t unix_mode(int cnum,int dosmode);
-BOOL check_name(char *name,int cnum);
-int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
-int find_free_file(void );
-BOOL unix_convert(char *name,int cnum);
-void unix_convert_lanman2(char *s,char *home,BOOL case_is_sig);
-void print_file(int fnum);
-int read_smb_length(int fd,char *inbuf,int timeout);
-int read_predict(int fd,int offset,char *buf,char **ptr,int num);
-void invalidate_read_prediction(int fd);
-void do_read_prediction();
-BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear);
-BOOL yield_connection(int cnum,char *name,int max_connections);
-int count_chars(char *s,char c);
-int smbrun(char *,char *);
-BOOL name_map_mangle(char *OutName,BOOL need83,int snum);
-struct hostent *Get_Hostbyname(char *name);
-struct passwd *Get_Pwnam(char *user,BOOL allow_change);
-void Abort(void);
-void *Realloc(void *p,int size);
-void smb_setlen(char *buf,int len);
-int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
-BOOL check_access(int snum);
-BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups);
-BOOL string_set(char **dest,char *src);
-BOOL string_init(char **dest,char *src);
-void string_free(char **s);
-char *attrib_string(int mode);
-void unix_format(char *fname);
-BOOL directory_exist(char *dname,struct stat *st);
-time_t make_unix_date3(void *date_ptr);
-void put_dos_date3(char *buf,int offset,time_t unixdate);
-void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date);
-BOOL in_list(char *s,char *list,BOOL case_sensitive);
-void strupper(char *s);
-BOOL file_exist(char *fname,struct stat *sbuf);
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt, long time_out, BOOL exact);
-void close_sockets(void );
-BOOL send_smb(int fd,char *buffer);
-BOOL send_keepalive(int client);
-int read_data(int fd,char *buffer,int N);
-int smb_len(char *buf);
-BOOL receive_smb(int fd,char *buffer,int timeout);
-void show_msg(char *buf);
-BOOL big_endian(void );
-BOOL become_user(int cnum, int uid);
-BOOL unbecome_user(void);
-void become_daemon(void);
-BOOL reduce_name(char *s,char *dir,BOOL widelinks);
-void strlower(char *s);
-void strnorm(char *s);
-char *smb_buf(char *buf);
-char *smb_trans2_param(char *buf);
-char *smb_trans2_data(char *buf);
-BOOL strequal(char *,char *);
-BOOL strnequal(char *,char *,int n);
-BOOL strcsequal(char *,char *);
-BOOL mask_match( char *str, char *regexp, int case_sig, BOOL trans2);
-int dos_mode(int ,char *,struct stat *);
-char *timestring();
-BOOL ip_equal(struct in_addr ip1,struct in_addr ip2);
-BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type);
-char *get_home_dir(char *);
-int set_filelen(int fd, long len);
-void put_dos_date(char *buf,int offset,time_t unixdate);
-void put_dos_date2(char *buf,int offset,time_t unixdate);
-int lp_keepalive(void);
-int name_len(char *s);
-void dos_clean_name(char *s);
-void unix_clean_name(char *s);
-time_t make_unix_date(void *date_ptr);
-BOOL lanman2_match( char *str, char *regexp, int case_sig, BOOL autoext);
-BOOL trim_string(char *s,char *front,char *back);
-int byte_checksum(char *buf,int len);
-BOOL yesno(char *p);
-uint32 file_size(char *file_name);
-void dos_format(char *fname);
-char *GetWd(char *s);
-int name_mangle(char *in,char *out,char name_type);
-int name_len(char *s);
-void create_mangled_stack(int size);
-int name_extract(char *buf,int ofs,char *name);
-void get_broadcast(struct in_addr *if_ipaddr, struct in_addr *if_bcast, struct in_addr *if_nmask);
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
-#ifdef __STDC__
-int Debug1(char *, ...);
-#else
-int Debug1();
-#endif
-BOOL check_hosts_equiv(char *user);
-int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize);
-void close_cnum(int cnum,int uid);
-char *smb_errstr(char *inbuf);
-void GetTimeOfDay(struct timeval *tval);
-struct tm *LocalTime(time_t *t,int);
-int TimeDiff(time_t t);
-BOOL set_filetime(char *fname,time_t mtime);
-char *dirname_dos(char *path,char *buf);
-BOOL get_myname(char *myname,struct in_addr *ip);
-void expand_mask(char *Mask, BOOL);
-BOOL sane_unix_date(time_t unixdate);
-time_t start_of_month(void);
-char *smb_fn_name(int cnum);
-void get_machine_info(void);
-int open_socket_in(int type, int port, int dlevel);
-int open_socket_out(int type,struct in_addr *addr, int port );
-struct in_addr *interpret_addr2(char *str);
-BOOL zero_ip(struct in_addr ip);
-int read_max_udp(int fd,char *buffer,int bufsize,int maxtime);
-int interpret_protocol(char *str,int def);
-int interpret_security(char *str,int def);
-int ChDir(char *path);
-int smb_buflen(char *buf);
-unsigned long interpret_addr(char *str);
-void mangle_name_83(char *s);
-BOOL lp_casesignames(void);
-void setup_logging(char *pname,BOOL interactive);
-#ifdef DFS_AUTH
+#ifdef WITH_DFS
void dfs_unlogin(void);
extern int dcelogin_atmost_once;
#endif
-#if AJT
-void ajt_panic(void);
-#endif
+
#ifdef NOSTRDUP
char *strdup(char *s);
#endif
-#ifdef REPLACE_STRLEN
-int Strlen(char *);
-#endif
-#ifdef REPLACE_STRSTR
-char *Strstr(char *s, char *p);
-#endif
-
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-#ifndef MAX
-#define MAX(a,b) ((a)>(b)?(a):(b))
-#endif
-
-#ifndef ABS
-#define ABS(a) ((a)>0?(a):(-(a)))
-#endif
#ifndef SIGNAL_CAST
-#define SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
#endif
#ifndef SELECT_CAST
#define SELECT_CAST
#endif
-
-/* Some POSIX definitions for those without */
-
-#ifndef S_IFDIR
-#define S_IFDIR 0x4000
-#endif
-#ifndef S_ISDIR
-#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR)
-#endif
-#ifndef S_IRWXU
-#define S_IRWXU 00700 /* read, write, execute: owner */
-#endif
-#ifndef S_IRUSR
-#define S_IRUSR 00400 /* read permission: owner */
-#endif
-#ifndef S_IWUSR
-#define S_IWUSR 00200 /* write permission: owner */
-#endif
-#ifndef S_IXUSR
-#define S_IXUSR 00100 /* execute permission: owner */
-#endif
-#ifndef S_IRWXG
-#define S_IRWXG 00070 /* read, write, execute: group */
-#endif
-#ifndef S_IRGRP
-#define S_IRGRP 00040 /* read permission: group */
-#endif
-#ifndef S_IWGRP
-#define S_IWGRP 00020 /* write permission: group */
-#endif
-#ifndef S_IXGRP
-#define S_IXGRP 00010 /* execute permission: group */
-#endif
-#ifndef S_IRWXO
-#define S_IRWXO 00007 /* read, write, execute: other */
-#endif
-#ifndef S_IROTH
-#define S_IROTH 00004 /* read permission: other */
-#endif
-#ifndef S_IWOTH
-#define S_IWOTH 00002 /* write permission: other */
-#endif
-#ifndef S_IXOTH
-#define S_IXOTH 00001 /* execute permission: other */
-#endif
-
-
/* these are used in NetServerEnum to choose what to receive */
#define SV_TYPE_WORKSTATION 0x00000001
#define SV_TYPE_SERVER 0x00000002
@@ -951,56 +1236,431 @@ char *Strstr(char *s, char *p);
#define SV_TYPE_DOMAIN_MASTER 0x00080000
#define SV_TYPE_SERVER_OSF 0x00100000
#define SV_TYPE_SERVER_VMS 0x00200000
+#define SV_TYPE_WIN95_PLUS 0x00400000
+#define SV_TYPE_DFS_SERVER 0x00800000
#define SV_TYPE_ALTERNATE_XPORT 0x20000000
#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000
#define SV_TYPE_DOMAIN_ENUM 0x80000000
#define SV_TYPE_ALL 0xFFFFFFFF
+/* This was set by JHT in liaison with Jeremy Allison early 1997
+ * History:
+ * Version 4.0 - never made public
+ * Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9
+ * - Reappeared in 1.9.16p11 with fixed smbd services
+ * Version 4.20 - To indicate that nmbd and browsing now works better
+ * Version 4.50 - Set at release of samba-2.2.0 by JHT
+ *
+ * Note: In the presence of NT4.X do not set above 4.9
+ * Setting this above 4.9 can have undesired side-effects.
+ * This may change again in Samba-3.0 after further testing. JHT
+ */
+
+#define DEFAULT_MAJOR_VERSION 0x04
+#define DEFAULT_MINOR_VERSION 0x05
+/* Browser Election Values */
+#define BROWSER_ELECTION_VERSION 0x010f
+#define BROWSER_CONSTANT 0xaa55
+
+/* NT Flags2 bits - cifs6.txt section 3.1.2 */
+
+#define FLAGS2_LONG_PATH_COMPONENTS 0x0001
+#define FLAGS2_EXTENDED_ATTRIBUTES 0x0002
+#define FLAGS2_EXTENDED_SECURITY 0x0800
+#define FLAGS2_DFS_PATHNAMES 0x1000
+#define FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000
+#define FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define FLAGS2_UNICODE_STRINGS 0x8000
+
+#define FLAGS2_WIN2K_SIGNATURE 0xC852 /* Hack alert ! For now... JRA. */
+
+/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
+
+#define CAP_RAW_MODE 0x0001
+#define CAP_MPX_MODE 0x0002
+#define CAP_UNICODE 0x0004
+#define CAP_LARGE_FILES 0x0008
+#define CAP_NT_SMBS 0x0010
+#define CAP_RPC_REMOTE_APIS 0x0020
+#define CAP_STATUS32 0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ 0x0100
+#define CAP_NT_FIND 0x0200
+#define CAP_DFS 0x1000
+#define CAP_W2K_SMBS 0x2000
+#define CAP_LARGE_READX 0x4000
+#define CAP_LARGE_WRITEX 0x8000
+#define CAP_EXTENDED_SECURITY 0x80000000
/* protocol types. It assumes that higher protocols include lower protocols
as subsets */
enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1};
/* security levels */
-enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER};
+enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER,SEC_DOMAIN,SEC_ADS};
+
+/* server roles */
+enum server_types
+{
+ ROLE_STANDALONE,
+ ROLE_DOMAIN_MEMBER,
+ ROLE_DOMAIN_BDC,
+ ROLE_DOMAIN_PDC
+};
/* printing types */
-enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,PRINT_QNX};
+enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
+ PRINT_QNX,PRINT_PLP,PRINT_LPRNG,PRINT_SOFTQ,
+ PRINT_CUPS,PRINT_LPRNT,PRINT_LPROS2
+#ifdef DEVELOPER
+,PRINT_TEST,PRINT_VLP
+#endif /* DEVELOPER */
+};
+
+/* LDAP schema types */
+enum schema_types {SCHEMA_COMPAT, SCHEMA_AD, SCHEMA_SAMBA};
+/* LDAP SSL options */
+enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS};
+
+/* Remote architectures we know about. */
+enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_WIN2K, RA_SAMBA};
/* case handling */
enum case_handling {CASE_LOWER,CASE_UPPER};
+#ifdef WITH_SSL
+/* SSL version options */
+enum ssl_version_enum {SMB_SSL_V2,SMB_SSL_V3,SMB_SSL_V23,SMB_SSL_TLS1};
+#endif /* WITH_SSL */
+
+/*
+ * Global value meaing that the smb_uid field should be
+ * ingored (in share level security and protocol level == CORE)
+ */
+
+#define UID_FIELD_INVALID 0
+#define VUID_OFFSET 100 /* Amount to bias returned vuid numbers */
+
+/* Defines needed for multi-codepage support. */
+#define MSDOS_LATIN_1_CODEPAGE 850
+#define KANJI_CODEPAGE 932
+#define HANGUL_CODEPAGE 949
+#define BIG5_CODEPAGE 950
+#define SIMPLIFIED_CHINESE_CODEPAGE 936
+
+#ifdef KANJI
+/*
+ * Default client code page - Japanese
+ */
+#define DEFAULT_CLIENT_CODE_PAGE KANJI_CODEPAGE
+#else /* KANJI */
+/*
+ * Default client code page - 850 - Western European
+ */
+#define DEFAULT_CLIENT_CODE_PAGE MSDOS_LATIN_1_CODEPAGE
+#endif /* KANJI */
+
+/* Global val set if multibyte codepage. */
+extern int global_is_multibyte_codepage;
+
+#define get_character_len(x) (global_is_multibyte_codepage ? skip_multibyte_char((x)) : 0)
+
+/*
+ * Size of buffer to use when moving files across filesystems.
+ */
+#define COPYBUF_SIZE (8*1024)
+
+/*
+ * Integers used to override error codes.
+ */
+extern int unix_ERR_class;
+extern int unix_ERR_code;
+
+/*
+ * Used in chaining code.
+ */
+extern int chain_size;
+
+/*
+ * Map the Core and Extended Oplock requesst bits down
+ * to common bits (EXCLUSIVE_OPLOCK & BATCH_OPLOCK).
+ */
+
+/*
+ * Core protocol.
+ */
+#define CORE_OPLOCK_REQUEST(inbuf) \
+ ((CVAL(inbuf,smb_flg)&(FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK))>>5)
+
+/*
+ * Extended protocol.
+ */
+#define EXTENDED_OPLOCK_REQUEST(inbuf) ((SVAL(inbuf,smb_vwv2)&((1<<1)|(1<<2)))>>1)
+
+/* Lock types. */
+#define LOCKING_ANDX_SHARED_LOCK 0x1
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x2
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x4
+#define LOCKING_ANDX_CANCEL_LOCK 0x8
+#define LOCKING_ANDX_LARGE_FILES 0x10
-/* Macros to get at offsets within smb_lkrng and smb_unlkrng
- structures. We cannot define these as actual structures
- due to possible differences in structure packing
- on different machines/compilers. */
+/* Oplock levels */
+#define OPLOCKLEVEL_NONE 0
+#define OPLOCKLEVEL_II 1
+
+/*
+ * Bits we test with.
+ */
+
+#define NO_OPLOCK 0
+#define EXCLUSIVE_OPLOCK 1
+#define BATCH_OPLOCK 2
+#define LEVEL_II_OPLOCK 4
+
+#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+#define BATCH_OPLOCK_TYPE(lck) ((lck) & BATCH_OPLOCK)
+#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & LEVEL_II_OPLOCK)
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+/*
+ * Return values for oplock types.
+ */
+
+#define NO_OPLOCK_RETURN 0
+#define EXCLUSIVE_OPLOCK_RETURN 1
+#define BATCH_OPLOCK_RETURN 2
+#define LEVEL_II_OPLOCK_RETURN 3
+
+/*
+ * Loopback command offsets.
+ */
+
+#define OPBRK_CMD_LEN_OFFSET 0
+#define OPBRK_CMD_PORT_OFFSET 4
+#define OPBRK_CMD_HEADER_LEN 6
+
+#define OPBRK_MESSAGE_CMD_OFFSET 0
+
+/*
+ * Oplock break command code to send over the udp socket.
+ * The same message is sent for both exlusive and level II breaks.
+ *
+ * The form of this is :
+ *
+ * 0 2 2+pid 2+pid+dev 2+pid+dev+ino
+ * +----+--------+-------+--------+---------+
+ * | cmd| pid | dev | inode | fileid |
+ * +----+--------+-------+--------+---------+
+ */
+
+#define OPLOCK_BREAK_CMD 0x1
+#define OPLOCK_BREAK_PID_OFFSET 2
+#define OPLOCK_BREAK_DEV_OFFSET (OPLOCK_BREAK_PID_OFFSET + sizeof(pid_t))
+#define OPLOCK_BREAK_INODE_OFFSET (OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))
+#define OPLOCK_BREAK_FILEID_OFFSET (OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
+#define OPLOCK_BREAK_MSG_LEN (OPLOCK_BREAK_FILEID_OFFSET + sizeof(unsigned long))
+
+#define KERNEL_OPLOCK_BREAK_CMD 0x2
+#define LEVEL_II_OPLOCK_BREAK_CMD 0x3
+
+/*
+ * Capabilities abstracted for different systems.
+ */
+
+#define KERNEL_OPLOCK_CAPABILITY 0x1
+
+/*
+ * Oplock break command code sent via the kernel interface (if it exists).
+ *
+ * Form of this is :
+ *
+ * 0 2 2+devsize 2+devsize+inodesize
+ * +----+--------+--------+----------+
+ * | cmd| dev | inode | fileid |
+ * +----+--------+--------+----------+
+ */
+#define KERNEL_OPLOCK_BREAK_DEV_OFFSET 2
+#define KERNEL_OPLOCK_BREAK_INODE_OFFSET (KERNEL_OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))
+#define KERNEL_OPLOCK_BREAK_FILEID_OFFSET (KERNEL_OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
+#define KERNEL_OPLOCK_BREAK_MSG_LEN (KERNEL_OPLOCK_BREAK_FILEID_OFFSET + sizeof(unsigned long))
+
+
+/* if a kernel does support oplocks then a structure of the following
+ typee is used to describe how to interact with the kernel */
+struct kernel_oplocks {
+ BOOL (*receive_message)(fd_set *fds, char *buffer, int buffer_len);
+ BOOL (*set_oplock)(files_struct *fsp, int oplock_type);
+ void (*release_oplock)(files_struct *fsp);
+ BOOL (*parse_message)(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev, unsigned long *file_id);
+ BOOL (*msg_waiting)(fd_set *fds);
+ int notification_fd;
+};
+
+
+#define CMD_REPLY 0x8000
+
+/* this structure defines the functions for doing change notify in
+ various implementations */
+struct cnotify_fns {
+ void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
+ BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
+ void (*remove_notify)(void *data);
+ int select_time;
+};
+
+
+
+#include "smb_macros.h"
+
+/* A netbios name structure. */
+struct nmb_name {
+ char name[17];
+ char scope[64];
+ unsigned int name_type;
+};
+
+
+/* A netbios node status array element. */
+struct node_status {
+ char name[16];
+ unsigned char type;
+ unsigned char flags;
+};
+
+
+
+#define AGENT_CMD_CON 0
+#define AGENT_CMD_CON_ANON 2
+#define AGENT_CMD_CON_REUSE 1
+
+struct pwd_info
+{
+ BOOL null_pwd;
+ BOOL cleartext;
+ BOOL crypted;
+
+ fstring password;
+
+ uchar smb_lm_pwd[16];
+ uchar smb_nt_pwd[16];
+
+ uchar smb_lm_owf[24];
+ uchar smb_nt_owf[128];
+ size_t nt_owf_len;
+
+ uchar lm_cli_chal[8];
+ uchar nt_cli_chal[128];
+ size_t nt_cli_chal_len;
+
+ uchar sess_key[16];
+};
+
+/*
+ * Network Computing Architechture Context Name Named Pipe
+ * See MSDN docs for more information
+ */
+struct ncacn_np
+{
+ fstring pipe_name;
+ struct cli_state *smb;
+ uint16 fnum;
+ BOOL initialised;
+};
+
+#include "rpc_creds.h"
+#include "rpc_misc.h"
+#include "rpc_secdes.h"
+#include "nt_printing.h"
+
+typedef struct user_struct
+{
+ struct user_struct *next, *prev;
+ uint16 vuid; /* Tag for this entry. */
+ uid_t uid; /* uid of a validated user */
+ gid_t gid; /* gid of a validated user */
+
+ userdom_struct user;
+ BOOL guest;
+
+ /* following groups stuff added by ih */
+ /* This groups info is needed for when we become_user() for this uid */
+ int n_groups;
+ gid_t *groups;
+
+ NT_USER_TOKEN *nt_user_token;
+
+ int session_id; /* used by utmp and pam session code */
+} user_struct;
+
+/* used to hold an arbitrary blob of data */
+typedef struct {
+ uint8 *data;
+ size_t length;
+} DATA_BLOB;
+
+
+#include "ntdomain.h"
+
+#include "client.h"
+
+/*
+ * Size of new password account encoding string. This is enough space to
+ * hold 11 ACB characters, plus the surrounding [] and a terminating null.
+ * Do not change unless you are adding new ACB bits!
+ */
+
+#define NEW_PW_FORMAT_SPACE_PADDED_LEN 14
+
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
+
+ You have 3 choices in the setting of map_to_guest:
+
+ "NEVER_MAP_TO_GUEST" means session setups with an invalid password
+ are rejected. This is the default.
+
+ "MAP_TO_GUEST_ON_BAD_USER" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+
+ "MAP_TO_GUEST_ON_BAD_PASSWORD" means session setups with an invalid password
+ are treated as a guest login
+
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
-#define SMB_LPID_OFFSET(indx) (10 * (indx))
-#define SMB_LKOFF_OFFSET(indx) ( 2 + (10 * (indx)))
-#define SMB_LKLEN_OFFSET(indx) ( 6 + (10 * (indx)))
+#define NEVER_MAP_TO_GUEST 0
+#define MAP_TO_GUEST_ON_BAD_USER 1
+#define MAP_TO_GUEST_ON_BAD_PASSWORD 2
-/* Macro to cache an error in a write_bmpx_struct */
-#define CACHE_ERROR(w,c,e) ((w)->wr_errclass = (c), (w)->wr_error = (e), \
- w->wr_discard = True, -1)
-/* Macro to test if an error has been cached for this fnum */
-#define HAS_CACHED_ERROR(fnum) (Files[(fnum)].open && \
- Files[(fnum)].wbmpx_ptr && \
- Files[(fnum)].wbmpx_ptr->wr_discard)
-/* Macro to turn the cached error into an error packet */
-#define CACHED_ERROR(fnum) cached_error_packet(inbuf,outbuf,fnum,__LINE__)
+#define SAFE_NETBIOS_CHARS ". -_"
-/* these are the datagram types */
-#define DGRAM_DIRECT_UNIQUE 0x10
+#include "nsswitch/winbindd_nss.h"
+#include "smb_acls.h"
-#define ERROR(class,x) error_packet(inbuf,outbuf,class,x,__LINE__)
+/* generic iconv conversion structure */
+typedef struct {
+ size_t (*direct)(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*pull)(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ void *cd_direct, *cd_pull, *cd_push;
+ char *from_name, *to_name;
+} *smb_iconv_t;
-/* this is how errors are generated */
-#define UNIXERROR(defclass,deferror) unix_error_packet(inbuf,outbuf,defclass,deferror,__LINE__)
+/* The maximum length of a trust account password.
+ Used when we randomly create it, 15 char passwords
+ exceed NT4's max password length */
-#define ROUNDUP(x,g) (((x)+((g)-1))&~((g)-1))
+#define DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH 14
-#endif
-/* _SMB_H */
+#endif /* _SMB_H */
diff --git a/source/include/smb_acls.h b/source/include/smb_acls.h
new file mode 100644
index 00000000000..53adf39dbc5
--- /dev/null
+++ b/source/include/smb_acls.h
@@ -0,0 +1,279 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.x
+ Portable SMB ACL interface
+ Copyright (C) Jeremy Allison 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SMB_ACLS_H
+#define _SMB_ACLS_H
+
+#include "includes.h"
+
+#if defined(HAVE_POSIX_ACLS)
+
+/* This is an identity mapping (just remove the SMB_). */
+
+#define SMB_ACL_TAG_T acl_tag_t
+#define SMB_ACL_TYPE_T acl_type_t
+#define SMB_ACL_PERMSET_T acl_permset_t
+#define SMB_ACL_PERM_T acl_perm_t
+#define SMB_ACL_READ ACL_READ
+#define SMB_ACL_WRITE ACL_WRITE
+#define SMB_ACL_EXECUTE ACL_EXECUTE
+
+/* Types of ACLs. */
+#define SMB_ACL_USER ACL_USER
+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
+#define SMB_ACL_GROUP ACL_GROUP
+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
+#define SMB_ACL_OTHER ACL_OTHER
+#define SMB_ACL_MASK ACL_MASK
+
+#define SMB_ACL_T acl_t
+
+#define SMB_ACL_ENTRY_T acl_entry_t
+
+#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
+#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
+
+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
+
+#elif defined(HAVE_TRU64_ACLS)
+
+/* This is for DEC/Compaq Tru64 UNIX */
+
+#define SMB_ACL_TAG_T acl_tag_t
+#define SMB_ACL_TYPE_T acl_type_t
+#define SMB_ACL_PERMSET_T acl_permset_t
+#define SMB_ACL_PERM_T acl_perm_t
+#define SMB_ACL_READ ACL_READ
+#define SMB_ACL_WRITE ACL_WRITE
+#define SMB_ACL_EXECUTE ACL_EXECUTE
+
+/* Types of ACLs. */
+#define SMB_ACL_USER ACL_USER
+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
+#define SMB_ACL_GROUP ACL_GROUP
+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
+#define SMB_ACL_OTHER ACL_OTHER
+#define SMB_ACL_MASK ACL_MASK
+
+#define SMB_ACL_T acl_t
+
+#define SMB_ACL_ENTRY_T acl_entry_t
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
+
+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
+/*
+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
+ */
+
+/* SVR4.2 ES/MP ACLs */
+typedef int SMB_ACL_TAG_T;
+typedef int SMB_ACL_TYPE_T;
+typedef ushort *SMB_ACL_PERMSET_T;
+typedef ushort SMB_ACL_PERM_T;
+#define SMB_ACL_READ 4
+#define SMB_ACL_WRITE 2
+#define SMB_ACL_EXECUTE 1
+
+/* Types of ACLs. */
+#define SMB_ACL_USER USER
+#define SMB_ACL_USER_OBJ USER_OBJ
+#define SMB_ACL_GROUP GROUP
+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
+#define SMB_ACL_OTHER OTHER_OBJ
+#define SMB_ACL_MASK CLASS_OBJ
+
+typedef struct SMB_ACL_T {
+ int size;
+ int count;
+ int next;
+ struct acl acl[1];
+} *SMB_ACL_T;
+
+typedef struct acl *SMB_ACL_ENTRY_T;
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS 0
+#define SMB_ACL_TYPE_DEFAULT 1
+
+#elif defined(HAVE_HPUX_ACLS)
+
+/*
+ * Based on the Solaris & UnixWare code.
+ */
+
+#undef GROUP
+#include <sys/aclv.h>
+
+/* SVR4.2 ES/MP ACLs */
+typedef int SMB_ACL_TAG_T;
+typedef int SMB_ACL_TYPE_T;
+typedef ushort *SMB_ACL_PERMSET_T;
+typedef ushort SMB_ACL_PERM_T;
+#define SMB_ACL_READ 4
+#define SMB_ACL_WRITE 2
+#define SMB_ACL_EXECUTE 1
+
+/* Types of ACLs. */
+#define SMB_ACL_USER USER
+#define SMB_ACL_USER_OBJ USER_OBJ
+#define SMB_ACL_GROUP GROUP
+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
+#define SMB_ACL_OTHER OTHER_OBJ
+#define SMB_ACL_MASK CLASS_OBJ
+
+typedef struct SMB_ACL_T {
+ int size;
+ int count;
+ int next;
+ struct acl acl[1];
+} *SMB_ACL_T;
+
+typedef struct acl *SMB_ACL_ENTRY_T;
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS 0
+#define SMB_ACL_TYPE_DEFAULT 1
+
+#elif defined(HAVE_IRIX_ACLS)
+
+#define SMB_ACL_TAG_T acl_tag_t
+#define SMB_ACL_TYPE_T acl_type_t
+#define SMB_ACL_PERMSET_T acl_permset_t
+#define SMB_ACL_PERM_T acl_perm_t
+#define SMB_ACL_READ ACL_READ
+#define SMB_ACL_WRITE ACL_WRITE
+#define SMB_ACL_EXECUTE ACL_EXECUTE
+
+/* Types of ACLs. */
+#define SMB_ACL_USER ACL_USER
+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
+#define SMB_ACL_GROUP ACL_GROUP
+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
+#define SMB_ACL_OTHER ACL_OTHER_OBJ
+#define SMB_ACL_MASK ACL_MASK
+
+typedef struct SMB_ACL_T {
+ int next;
+ BOOL freeaclp;
+ struct acl *aclp;
+} *SMB_ACL_T;
+
+#define SMB_ACL_ENTRY_T acl_entry_t
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
+
+#elif defined(HAVE_AIX_ACLS)
+
+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
+
+#include "/usr/include/acl.h"
+
+typedef uint *SMB_ACL_PERMSET_T;
+
+struct acl_entry_link{
+ struct acl_entry_link *prevp;
+ struct new_acl_entry *entryp;
+ struct acl_entry_link *nextp;
+ int count;
+};
+
+struct new_acl_entry{
+ unsigned short ace_len;
+ unsigned short ace_type;
+ unsigned int ace_access;
+ struct ace_id ace_id[1];
+};
+
+#define SMB_ACL_ENTRY_T struct new_acl_entry*
+#define SMB_ACL_T struct acl_entry_link*
+
+#define SMB_ACL_TAG_T unsigned short
+#define SMB_ACL_TYPE_T int
+#define SMB_ACL_PERM_T uint
+#define SMB_ACL_READ S_IRUSR
+#define SMB_ACL_WRITE S_IWUSR
+#define SMB_ACL_EXECUTE S_IXUSR
+
+/* Types of ACLs. */
+#define SMB_ACL_USER ACEID_USER
+#define SMB_ACL_USER_OBJ 3
+#define SMB_ACL_GROUP ACEID_GROUP
+#define SMB_ACL_GROUP_OBJ 4
+#define SMB_ACL_OTHER 5
+#define SMB_ACL_MASK 6
+
+
+#define SMB_ACL_FIRST_ENTRY 1
+#define SMB_ACL_NEXT_ENTRY 2
+
+#define SMB_ACL_TYPE_ACCESS 0
+#define SMB_ACL_TYPE_DEFAULT 1
+
+#else /* No ACLs. */
+
+/* No ACLS - fake it. */
+#define SMB_ACL_TAG_T int
+#define SMB_ACL_TYPE_T int
+#define SMB_ACL_PERMSET_T mode_t
+#define SMB_ACL_PERM_T mode_t
+#define SMB_ACL_READ S_IRUSR
+#define SMB_ACL_WRITE S_IWUSR
+#define SMB_ACL_EXECUTE S_IXUSR
+
+/* Types of ACLs. */
+#define SMB_ACL_USER 0
+#define SMB_ACL_USER_OBJ 1
+#define SMB_ACL_GROUP 2
+#define SMB_ACL_GROUP_OBJ 3
+#define SMB_ACL_OTHER 4
+#define SMB_ACL_MASK 5
+
+typedef struct SMB_ACL_T {
+ int dummy;
+} *SMB_ACL_T;
+
+typedef struct SMB_ACL_ENTRY_T {
+ int dummy;
+} *SMB_ACL_ENTRY_T;
+
+#define SMB_ACL_FIRST_ENTRY 0
+#define SMB_ACL_NEXT_ENTRY 1
+
+#define SMB_ACL_TYPE_ACCESS 0
+#define SMB_ACL_TYPE_DEFAULT 1
+
+#endif /* No ACLs. */
+#endif /* _SMB_ACLS_H */
diff --git a/source/include/smb_macros.h b/source/include/smb_macros.h
new file mode 100644
index 00000000000..44b8c26da94
--- /dev/null
+++ b/source/include/smb_macros.h
@@ -0,0 +1,270 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) John H Terpstra 1996-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+ Copyright (C) Paul Ashton 1998 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SMB_MACROS_H
+#define _SMB_MACROS_H
+
+/* Misc bit macros */
+#define BOOLSTR(b) ((b) ? "Yes" : "No")
+#define BITSETB(ptr,bit) ((((char *)ptr)[0] & (1<<(bit)))!=0)
+#define BITSETW(ptr,bit) ((SVAL(ptr,0) & (1<<(bit)))!=0)
+
+/* for readability... */
+#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
+#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
+#define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0)
+#define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
+#define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
+
+/* free memory if the pointer is valid and zero the pointer */
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+
+/* zero a structure */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+
+/* zero a structure given a pointer to the structure - no zero check */
+#define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x)))
+
+/* zero an array - note that sizeof(array) must work - ie. it must not be a
+ pointer */
+#define ZERO_ARRAY(x) memset((char *)(x), 0, sizeof(x))
+
+/* pointer difference macro */
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+
+/* work out how many elements there are in a static array */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* assert macros */
+#define SMB_ASSERT(b) ((b)?(void)0: \
+ (DEBUG(0,("PANIC: assert failed at %s(%d)\n", \
+ __FILE__, __LINE__)), smb_panic("assert failed")))
+#define SMB_ASSERT_ARRAY(a,n) SMB_ASSERT((sizeof(a)/sizeof((a)[0])) >= (n))
+
+/* these are useful macros for checking validity of handles */
+#define OPEN_FSP(fsp) ((fsp) && !(fsp)->is_directory)
+#define OPEN_CONN(conn) ((conn) && (conn)->open)
+#define IS_IPC(conn) ((conn) && (conn)->ipc)
+#define IS_PRINT(conn) ((conn) && (conn)->printer)
+#define FNUM_OK(fsp,c) (OPEN_FSP(fsp) && (c)==(fsp)->conn)
+
+#define CHECK_FSP(fsp,conn) if (!FNUM_OK(fsp,conn)) \
+ return(ERROR_DOS(ERRDOS,ERRbadfid)); \
+ else if((fsp)->fd == -1) \
+ return(ERROR_DOS(ERRDOS,ERRbadaccess))
+
+#define CHECK_READ(fsp) if (!(fsp)->can_read) \
+ return(ERROR_DOS(ERRDOS,ERRbadaccess))
+#define CHECK_WRITE(fsp) if (!(fsp)->can_write) \
+ return(ERROR_DOS(ERRDOS,ERRbadaccess))
+
+#define CHECK_ERROR(fsp) if (HAS_CACHED_ERROR(fsp)) \
+ return(CACHED_ERROR(fsp))
+
+/* translates a connection number into a service number */
+#define SNUM(conn) ((conn)?(conn)->service:-1)
+
+/* access various service details */
+#define SERVICE(snum) (lp_servicename(snum))
+#define PRINTCAP (lp_printcapname())
+#define PRINTCOMMAND(snum) (lp_printcommand(snum))
+#define PRINTERNAME(snum) (lp_printername(snum))
+#define CAN_WRITE(conn) (!conn->read_only)
+#define VALID_SNUM(snum) (lp_snum_ok(snum))
+#define GUEST_OK(snum) (VALID_SNUM(snum) && lp_guest_ok(snum))
+#define GUEST_ONLY(snum) (VALID_SNUM(snum) && lp_guest_only(snum))
+#define CAN_SETDIR(snum) (!lp_no_set_dir(snum))
+#define CAN_PRINT(conn) ((conn) && lp_print_ok((conn)->service))
+#define MAP_HIDDEN(conn) ((conn) && lp_map_hidden((conn)->service))
+#define MAP_SYSTEM(conn) ((conn) && lp_map_system((conn)->service))
+#define MAP_ARCHIVE(conn) ((conn) && lp_map_archive((conn)->service))
+#define IS_HIDDEN_PATH(conn,path) ((conn) && is_in_path((path),(conn)->hide_list))
+#define IS_VETO_PATH(conn,path) ((conn) && is_in_path((path),(conn)->veto_list))
+#define IS_VETO_OPLOCK_PATH(conn,path) ((conn) && is_in_path((path),(conn)->veto_oplock_list))
+
+/*
+ * Used by the stat cache code to check if a returned
+ * stat structure is valid.
+ */
+
+#define VALID_STAT(st) ((st).st_nlink != 0)
+#define VALID_STAT_OF_DIR(st) (VALID_STAT(st) && S_ISDIR((st).st_mode))
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a)>0?(a):(-(a)))
+#endif
+
+/* Macros to get at offsets within smb_lkrng and smb_unlkrng
+ structures. We cannot define these as actual structures
+ due to possible differences in structure packing
+ on different machines/compilers. */
+
+#define SMB_LPID_OFFSET(indx) (10 * (indx))
+#define SMB_LKOFF_OFFSET(indx) ( 2 + (10 * (indx)))
+#define SMB_LKLEN_OFFSET(indx) ( 6 + (10 * (indx)))
+#define SMB_LARGE_LPID_OFFSET(indx) (20 * (indx))
+#define SMB_LARGE_LKOFF_OFFSET_HIGH(indx) (4 + (20 * (indx)))
+#define SMB_LARGE_LKOFF_OFFSET_LOW(indx) (8 + (20 * (indx)))
+#define SMB_LARGE_LKLEN_OFFSET_HIGH(indx) (12 + (20 * (indx)))
+#define SMB_LARGE_LKLEN_OFFSET_LOW(indx) (16 + (20 * (indx)))
+
+/* Macro to cache an error in a write_bmpx_struct */
+#define CACHE_ERROR(w,c,e) ((w)->wr_errclass = (c), (w)->wr_error = (e), \
+ w->wr_discard = True, -1)
+/* Macro to test if an error has been cached for this fnum */
+#define HAS_CACHED_ERROR(fsp) ((fsp)->wbmpx_ptr && \
+ (fsp)->wbmpx_ptr->wr_discard)
+/* Macro to turn the cached error into an error packet */
+#define CACHED_ERROR(fsp) cached_error_packet(outbuf,fsp,__LINE__,__FILE__)
+
+/* these are the datagram types */
+#define DGRAM_DIRECT_UNIQUE 0x10
+
+#define ERROR_DOS(class,code) error_packet(outbuf,NT_STATUS_OK,class,code,__LINE__,__FILE__)
+#define ERROR_NT(status) error_packet(outbuf,status,0,0,__LINE__,__FILE__)
+#define ERROR_BOTH(status,class,code) error_packet(outbuf,status,class,code,__LINE__,__FILE__)
+
+/* this is how errors are generated */
+#define UNIXERROR(defclass,deferror) unix_error_packet(outbuf,defclass,deferror,__LINE__,__FILE__)
+
+#define SMB_ROUNDUP(x,g) (((x)+((g)-1))&~((g)-1))
+#define SMB_ROUNDUP_ALLOCATION(s) (SMB_ROUNDUP((SMB_OFF_T)((s)+1), ((SMB_OFF_T)SMB_ROUNDUP_ALLOCATION_SIZE)))
+
+/* Extra macros added by Ying Chen at IBM - speed increase by inlining. */
+#define smb_buf(buf) (buf + smb_size + CVAL(buf,smb_wct)*2)
+#define smb_buflen(buf) (SVAL(buf,smb_vwv0 + (int)CVAL(buf, smb_wct)*2))
+
+/* Note that chain_size must be available as an extern int to this macro. */
+#define smb_offset(p,buf) (PTR_DIFF(p,buf+4) + chain_size)
+
+#define smb_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|((PVAL(buf,1)&1)<<16))
+#define _smb_setlen(buf,len) buf[0] = 0; buf[1] = (len&0x10000)>>16; \
+ buf[2] = (len&0xFF00)>>8; buf[3] = len&0xFF;
+
+/*******************************************************************
+find the difference in milliseconds between two struct timeval
+values
+********************************************************************/
+
+#define TvalDiff(tvalold,tvalnew) \
+ (((tvalnew)->tv_sec - (tvalold)->tv_sec)*1000 + \
+ ((int)(tvalnew)->tv_usec - (int)(tvalold)->tv_usec)/1000)
+
+/****************************************************************************
+true if two IP addresses are equal
+****************************************************************************/
+
+#define ip_equal(ip1,ip2) ((ip1).s_addr == (ip2).s_addr)
+
+/*****************************************************************
+ splits out the last subkey of a key
+ *****************************************************************/
+
+#define reg_get_subkey(full_keyname, key_name, subkey_name) \
+ split_at_last_component(full_keyname, key_name, '\\', subkey_name)
+
+/****************************************************************************
+ Used by dptr_zero.
+****************************************************************************/
+
+#define DPTR_MASK ((uint32)(((uint32)1)<<31))
+
+/****************************************************************************
+ Return True if the offset is at zero.
+****************************************************************************/
+
+#define dptr_zero(buf) ((IVAL(buf,1)&~DPTR_MASK) == 0)
+
+/*******************************************************************
+copy an IP address from one buffer to another
+********************************************************************/
+
+#define putip(dest,src) memcpy(dest,src,4)
+
+/****************************************************************************
+ Make a filename into unix format.
+****************************************************************************/
+
+#define unix_format(fname) string_replace(fname,'\\','/')
+#define unix_format_w(fname) string_replace_w(fname, UCS2_CHAR('\\'), UCS2_CHAR('/'))
+
+/****************************************************************************
+ Make a file into DOS format.
+****************************************************************************/
+
+#define dos_format(fname) string_replace(fname,'/','\\')
+
+/*******************************************************************
+ vfs stat wrapper that calls internal2unix.
+********************************************************************/
+
+#define vfs_stat(conn, fname, st) ((conn)->vfs_ops.stat((conn), fname,(st)))
+
+/*******************************************************************
+ vfs fstat wrapper
+********************************************************************/
+
+#define vfs_fstat(fsp, fd, st) ((fsp)->conn->vfs_ops.fstat((fsp),(fd),(st)))
+
+/*******************************************************************
+ vfs rmdir wrapper that calls internal2unix.
+********************************************************************/
+
+#define vfs_rmdir(conn,fname) ((conn)->vfs_ops.rmdir((conn),fname))
+
+/*******************************************************************
+ vfs Unlink wrapper that calls internal2unix.
+********************************************************************/
+
+#define vfs_unlink(conn, fname) ((conn)->vfs_ops.unlink((conn),fname))
+
+/*******************************************************************
+ vfs chmod wrapper that calls internal2unix.
+********************************************************************/
+
+#define vfs_chmod(conn,fname,mode) ((conn)->vfs_ops.chmod((conn),fname,(mode)))
+
+/*******************************************************************
+ vfs chown wrapper that calls internal2unix.
+********************************************************************/
+
+#define vfs_chown(conn,fname,uid,gid) ((conn)->vfs_ops.chown((conn),fname,(uid),(gid)))
+
+/*******************************************************************
+ A wrapper for vfs_chdir().
+********************************************************************/
+
+#define vfs_chdir(conn,fname) ((conn)->vfs_ops.chdir((conn),fname))
+
+#endif /* _SMB_MACROS_H */
diff --git a/source/include/smbprofile.h b/source/include/smbprofile.h
new file mode 100644
index 00000000000..fbd83d6e3e1
--- /dev/null
+++ b/source/include/smbprofile.h
@@ -0,0 +1,461 @@
+#ifndef _PROFILE_H_
+#define _PROFILE_H_
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ store smbd profiling information in shared memory
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/*
+ * Reasons for cache flush.
+ */
+
+#define NUM_FLUSH_REASONS 8 /* Keep this in sync with the enum below. */
+enum flush_reason_enum { SEEK_FLUSH, READ_FLUSH, WRITE_FLUSH, READRAW_FLUSH,
+ OPLOCK_RELEASE_FLUSH, CLOSE_FLUSH, SYNC_FLUSH, SIZECHANGE_FLUSH };
+
+/* this file defines the profile structure in the profile shared
+ memory area */
+
+#define PROF_SHMEM_KEY ((key_t)0x07021999)
+#define PROF_SHM_MAGIC 0x6349985
+#define PROF_SHM_VERSION 5
+
+/* time values in the following structure are in microseconds */
+
+struct profile_stats {
+/* general counters */
+ unsigned smb_count; /* how many SMB packets we have processed */
+ unsigned uid_changes; /* how many times we change our effective uid */
+/* system call counters */
+ unsigned syscall_opendir_count;
+ unsigned syscall_opendir_time;
+ unsigned syscall_readdir_count;
+ unsigned syscall_readdir_time;
+ unsigned syscall_mkdir_count;
+ unsigned syscall_mkdir_time;
+ unsigned syscall_rmdir_count;
+ unsigned syscall_rmdir_time;
+ unsigned syscall_closedir_count;
+ unsigned syscall_closedir_time;
+ unsigned syscall_open_count;
+ unsigned syscall_open_time;
+ unsigned syscall_close_count;
+ unsigned syscall_close_time;
+ unsigned syscall_read_count;
+ unsigned syscall_read_time;
+ unsigned syscall_read_bytes; /* bytes read with read syscall */
+ unsigned syscall_write_count;
+ unsigned syscall_write_time;
+ unsigned syscall_write_bytes; /* bytes written with write syscall */
+ unsigned syscall_lseek_count;
+ unsigned syscall_lseek_time;
+ unsigned syscall_rename_count;
+ unsigned syscall_rename_time;
+ unsigned syscall_fsync_count;
+ unsigned syscall_fsync_time;
+ unsigned syscall_stat_count;
+ unsigned syscall_stat_time;
+ unsigned syscall_fstat_count;
+ unsigned syscall_fstat_time;
+ unsigned syscall_lstat_count;
+ unsigned syscall_lstat_time;
+ unsigned syscall_unlink_count;
+ unsigned syscall_unlink_time;
+ unsigned syscall_chmod_count;
+ unsigned syscall_chmod_time;
+ unsigned syscall_fchmod_count;
+ unsigned syscall_fchmod_time;
+ unsigned syscall_chown_count;
+ unsigned syscall_chown_time;
+ unsigned syscall_fchown_count;
+ unsigned syscall_fchown_time;
+ unsigned syscall_chdir_count;
+ unsigned syscall_chdir_time;
+ unsigned syscall_getwd_count;
+ unsigned syscall_getwd_time;
+ unsigned syscall_utime_count;
+ unsigned syscall_utime_time;
+ unsigned syscall_ftruncate_count;
+ unsigned syscall_ftruncate_time;
+ unsigned syscall_fcntl_lock_count;
+ unsigned syscall_fcntl_lock_time;
+ unsigned syscall_readlink_count;
+ unsigned syscall_readlink_time;
+ unsigned syscall_symlink_count;
+ unsigned syscall_symlink_time;
+/* stat cache counters */
+ unsigned statcache_lookups;
+ unsigned statcache_misses;
+ unsigned statcache_hits;
+/* write cache counters */
+ unsigned writecache_read_hits;
+ unsigned writecache_abutted_writes;
+ unsigned writecache_total_writes;
+ unsigned writecache_non_oplock_writes;
+ unsigned writecache_direct_writes;
+ unsigned writecache_init_writes;
+ unsigned writecache_flushed_writes[NUM_FLUSH_REASONS];
+ unsigned writecache_num_perfect_writes;
+ unsigned writecache_num_write_caches;
+ unsigned writecache_allocated_write_caches;
+/* counters for individual SMB types */
+ unsigned SMBmkdir_count; /* create directory */
+ unsigned SMBmkdir_time;
+ unsigned SMBrmdir_count; /* delete directory */
+ unsigned SMBrmdir_time;
+ unsigned SMBopen_count; /* open file */
+ unsigned SMBopen_time;
+ unsigned SMBcreate_count; /* create file */
+ unsigned SMBcreate_time;
+ unsigned SMBclose_count; /* close file */
+ unsigned SMBclose_time;
+ unsigned SMBflush_count; /* flush file */
+ unsigned SMBflush_time;
+ unsigned SMBunlink_count; /* delete file */
+ unsigned SMBunlink_time;
+ unsigned SMBmv_count; /* rename file */
+ unsigned SMBmv_time;
+ unsigned SMBgetatr_count; /* get file attributes */
+ unsigned SMBgetatr_time;
+ unsigned SMBsetatr_count; /* set file attributes */
+ unsigned SMBsetatr_time;
+ unsigned SMBread_count; /* read from file */
+ unsigned SMBread_time;
+ unsigned SMBwrite_count; /* write to file */
+ unsigned SMBwrite_time;
+ unsigned SMBlock_count; /* lock byte range */
+ unsigned SMBlock_time;
+ unsigned SMBunlock_count; /* unlock byte range */
+ unsigned SMBunlock_time;
+ unsigned SMBctemp_count; /* create temporary file */
+ unsigned SMBctemp_time;
+ /* SMBmknew stats are currently combined with SMBcreate */
+ unsigned SMBmknew_count; /* make new file */
+ unsigned SMBmknew_time;
+ unsigned SMBchkpth_count; /* check directory path */
+ unsigned SMBchkpth_time;
+ unsigned SMBexit_count; /* process exit */
+ unsigned SMBexit_time;
+ unsigned SMBlseek_count; /* seek */
+ unsigned SMBlseek_time;
+ unsigned SMBlockread_count; /* Lock a range and read */
+ unsigned SMBlockread_time;
+ unsigned SMBwriteunlock_count; /* Unlock a range then write */
+ unsigned SMBwriteunlock_time;
+ unsigned SMBreadbraw_count; /* read a block of data with no smb header */
+ unsigned SMBreadbraw_time;
+ unsigned SMBreadBmpx_count; /* read block multiplexed */
+ unsigned SMBreadBmpx_time;
+ unsigned SMBreadBs_count; /* read block (secondary response) */
+ unsigned SMBreadBs_time;
+ unsigned SMBwritebraw_count; /* write a block of data with no smb header */
+ unsigned SMBwritebraw_time;
+ unsigned SMBwriteBmpx_count; /* write block multiplexed */
+ unsigned SMBwriteBmpx_time;
+ unsigned SMBwriteBs_count; /* write block (secondary request) */
+ unsigned SMBwriteBs_time;
+ unsigned SMBwritec_count; /* secondary write request */
+ unsigned SMBwritec_time;
+ unsigned SMBsetattrE_count; /* set file attributes expanded */
+ unsigned SMBsetattrE_time;
+ unsigned SMBgetattrE_count; /* get file attributes expanded */
+ unsigned SMBgetattrE_time;
+ unsigned SMBlockingX_count; /* lock/unlock byte ranges and X */
+ unsigned SMBlockingX_time;
+ unsigned SMBtrans_count; /* transaction - name, bytes in/out */
+ unsigned SMBtrans_time;
+ unsigned SMBtranss_count; /* transaction (secondary request/response) */
+ unsigned SMBtranss_time;
+ unsigned SMBioctl_count; /* IOCTL */
+ unsigned SMBioctl_time;
+ unsigned SMBioctls_count; /* IOCTL (secondary request/response) */
+ unsigned SMBioctls_time;
+ unsigned SMBcopy_count; /* copy */
+ unsigned SMBcopy_time;
+ unsigned SMBmove_count; /* move */
+ unsigned SMBmove_time;
+ unsigned SMBecho_count; /* echo */
+ unsigned SMBecho_time;
+ unsigned SMBwriteclose_count; /* write a file then close it */
+ unsigned SMBwriteclose_time;
+ unsigned SMBopenX_count; /* open and X */
+ unsigned SMBopenX_time;
+ unsigned SMBreadX_count; /* read and X */
+ unsigned SMBreadX_time;
+ unsigned SMBwriteX_count; /* write and X */
+ unsigned SMBwriteX_time;
+ unsigned SMBtrans2_count; /* TRANS2 protocol set */
+ unsigned SMBtrans2_time;
+ unsigned SMBtranss2_count; /* TRANS2 protocol set, secondary command */
+ unsigned SMBtranss2_time;
+ unsigned SMBfindclose_count; /* Terminate a TRANSACT2_FINDFIRST */
+ unsigned SMBfindclose_time;
+ unsigned SMBfindnclose_count; /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+ unsigned SMBfindnclose_time;
+ unsigned SMBtcon_count; /* tree connect */
+ unsigned SMBtcon_time;
+ unsigned SMBtdis_count; /* tree disconnect */
+ unsigned SMBtdis_time;
+ unsigned SMBnegprot_count; /* negotiate protocol */
+ unsigned SMBnegprot_time;
+ unsigned SMBsesssetupX_count; /* Session Set Up & X (including User Logon) */
+ unsigned SMBsesssetupX_time;
+ unsigned SMBulogoffX_count; /* user logoff */
+ unsigned SMBulogoffX_time;
+ unsigned SMBtconX_count; /* tree connect and X*/
+ unsigned SMBtconX_time;
+ unsigned SMBdskattr_count; /* get disk attributes */
+ unsigned SMBdskattr_time;
+ unsigned SMBsearch_count; /* search directory */
+ unsigned SMBsearch_time;
+ /* SBMffirst stats combined with SMBsearch */
+ unsigned SMBffirst_count; /* find first */
+ unsigned SMBffirst_time;
+ /* SBMfunique stats combined with SMBsearch */
+ unsigned SMBfunique_count; /* find unique */
+ unsigned SMBfunique_time;
+ unsigned SMBfclose_count; /* find close */
+ unsigned SMBfclose_time;
+ unsigned SMBnttrans_count; /* NT transact */
+ unsigned SMBnttrans_time;
+ unsigned SMBnttranss_count; /* NT transact secondary */
+ unsigned SMBnttranss_time;
+ unsigned SMBntcreateX_count; /* NT create and X */
+ unsigned SMBntcreateX_time;
+ unsigned SMBntcancel_count; /* NT cancel */
+ unsigned SMBntcancel_time;
+ unsigned SMBsplopen_count; /* open print spool file */
+ unsigned SMBsplopen_time;
+ unsigned SMBsplwr_count; /* write to print spool file */
+ unsigned SMBsplwr_time;
+ unsigned SMBsplclose_count; /* close print spool file */
+ unsigned SMBsplclose_time;
+ unsigned SMBsplretq_count; /* return print queue */
+ unsigned SMBsplretq_time;
+ unsigned SMBsends_count; /* send single block message */
+ unsigned SMBsends_time;
+ unsigned SMBsendb_count; /* send broadcast message */
+ unsigned SMBsendb_time;
+ unsigned SMBfwdname_count; /* forward user name */
+ unsigned SMBfwdname_time;
+ unsigned SMBcancelf_count; /* cancel forward */
+ unsigned SMBcancelf_time;
+ unsigned SMBgetmac_count; /* get machine name */
+ unsigned SMBgetmac_time;
+ unsigned SMBsendstrt_count; /* send start of multi-block message */
+ unsigned SMBsendstrt_time;
+ unsigned SMBsendend_count; /* send end of multi-block message */
+ unsigned SMBsendend_time;
+ unsigned SMBsendtxt_count; /* send text of multi-block message */
+ unsigned SMBsendtxt_time;
+ unsigned SMBinvalid_count; /* invalid command */
+ unsigned SMBinvalid_time;
+/* Pathworks setdir command */
+ unsigned pathworks_setdir_count;
+ unsigned pathworks_setdir_time;
+/* These are the TRANS2 sub commands */
+ unsigned Trans2_open_count;
+ unsigned Trans2_open_time;
+ unsigned Trans2_findfirst_count;
+ unsigned Trans2_findfirst_time;
+ unsigned Trans2_findnext_count;
+ unsigned Trans2_findnext_time;
+ unsigned Trans2_qfsinfo_count;
+ unsigned Trans2_qfsinfo_time;
+ unsigned Trans2_setfsinfo_count;
+ unsigned Trans2_setfsinfo_time;
+ unsigned Trans2_qpathinfo_count;
+ unsigned Trans2_qpathinfo_time;
+ unsigned Trans2_setpathinfo_count;
+ unsigned Trans2_setpathinfo_time;
+ unsigned Trans2_qfileinfo_count;
+ unsigned Trans2_qfileinfo_time;
+ unsigned Trans2_setfileinfo_count;
+ unsigned Trans2_setfileinfo_time;
+ unsigned Trans2_fsctl_count;
+ unsigned Trans2_fsctl_time;
+ unsigned Trans2_ioctl_count;
+ unsigned Trans2_ioctl_time;
+ unsigned Trans2_findnotifyfirst_count;
+ unsigned Trans2_findnotifyfirst_time;
+ unsigned Trans2_findnotifynext_count;
+ unsigned Trans2_findnotifynext_time;
+ unsigned Trans2_mkdir_count;
+ unsigned Trans2_mkdir_time;
+ unsigned Trans2_session_setup_count;
+ unsigned Trans2_session_setup_time;
+ unsigned Trans2_get_dfs_referral_count;
+ unsigned Trans2_get_dfs_referral_time;
+ unsigned Trans2_report_dfs_inconsistancy_count;
+ unsigned Trans2_report_dfs_inconsistancy_time;
+/* These are the NT transact sub commands. */
+ unsigned NT_transact_create_count;
+ unsigned NT_transact_create_time;
+ unsigned NT_transact_ioctl_count;
+ unsigned NT_transact_ioctl_time;
+ unsigned NT_transact_set_security_desc_count;
+ unsigned NT_transact_set_security_desc_time;
+ unsigned NT_transact_notify_change_count;
+ unsigned NT_transact_notify_change_time;
+ unsigned NT_transact_rename_count;
+ unsigned NT_transact_rename_time;
+ unsigned NT_transact_query_security_desc_count;
+ unsigned NT_transact_query_security_desc_time;
+/* These are ACL manipulation calls */
+ unsigned get_nt_acl_count;
+ unsigned get_nt_acl_time;
+ unsigned fget_nt_acl_count;
+ unsigned fget_nt_acl_time;
+ unsigned set_nt_acl_count;
+ unsigned set_nt_acl_time;
+ unsigned fset_nt_acl_count;
+ unsigned fset_nt_acl_time;
+ unsigned chmod_acl_count;
+ unsigned chmod_acl_time;
+ unsigned fchmod_acl_count;
+ unsigned fchmod_acl_time;
+/* These are nmbd stats */
+ unsigned name_release_count;
+ unsigned name_release_time;
+ unsigned name_refresh_count;
+ unsigned name_refresh_time;
+ unsigned name_registration_count;
+ unsigned name_registration_time;
+ unsigned node_status_count;
+ unsigned node_status_time;
+ unsigned name_query_count;
+ unsigned name_query_time;
+ unsigned host_announce_count;
+ unsigned host_announce_time;
+ unsigned workgroup_announce_count;
+ unsigned workgroup_announce_time;
+ unsigned local_master_announce_count;
+ unsigned local_master_announce_time;
+ unsigned master_browser_announce_count;
+ unsigned master_browser_announce_time;
+ unsigned lm_host_announce_count;
+ unsigned lm_host_announce_time;
+ unsigned get_backup_list_count;
+ unsigned get_backup_list_time;
+ unsigned reset_browser_count;
+ unsigned reset_browser_time;
+ unsigned announce_request_count;
+ unsigned announce_request_time;
+ unsigned lm_announce_request_count;
+ unsigned lm_announce_request_time;
+ unsigned domain_logon_count;
+ unsigned domain_logon_time;
+ unsigned sync_browse_lists_count;
+ unsigned sync_browse_lists_time;
+ unsigned run_elections_count;
+ unsigned run_elections_time;
+ unsigned election_count;
+ unsigned election_time;
+};
+
+struct profile_header {
+ int prof_shm_magic;
+ int prof_shm_version;
+ struct profile_stats stats;
+};
+
+extern struct profile_header *profile_h;
+extern struct profile_stats *profile_p;
+extern struct timeval profile_starttime;
+extern struct timeval profile_endtime;
+extern struct timeval profile_starttime_nested;
+extern struct timeval profile_endtime_nested;
+extern BOOL do_profile_flag;
+extern BOOL do_profile_times;
+
+/* these are helper macros - do not call them directly in the code
+ * use the DO_PROFILE_* START_PROFILE and END_PROFILE ones
+ * below which test for the profile flage first
+ */
+#define INC_PROFILE_COUNT(x) profile_p->x++
+#define DEC_PROFILE_COUNT(x) profile_p->x--
+#define ADD_PROFILE_COUNT(x,y) profile_p->x += (y)
+#define PROFILE_TIME \
+ ((profile_endtime.tv_sec - profile_starttime.tv_sec) *1000000 + \
+ ((int)profile_endtime.tv_usec - (int)profile_starttime.tv_usec))
+#define PROFILE_TIME_NESTED \
+ ((profile_endtime_nested.tv_sec - profile_starttime_nested.tv_sec) *1000000 + \
+ ((int)profile_endtime_nested.tv_usec - (int)profile_starttime_nested.tv_usec))
+
+#ifdef WITH_PROFILE
+#define DO_PROFILE_INC(x) \
+ if (do_profile_flag) { \
+ INC_PROFILE_COUNT(x); \
+ }
+#define DO_PROFILE_DEC(x) \
+ if (do_profile_flag) { \
+ DEC_PROFILE_COUNT(x); \
+ }
+#define DO_PROFILE_DEC_INC(x,y) \
+ if (do_profile_flag) { \
+ DEC_PROFILE_COUNT(x); \
+ INC_PROFILE_COUNT(y); \
+ }
+#define DO_PROFILE_ADD(x,n) \
+ if (do_profile_flag) { \
+ ADD_PROFILE_COUNT(x,n); \
+ }
+#define START_PROFILE(x) \
+ if (do_profile_flag) { \
+ if (do_profile_times) \
+ GetTimeOfDay(&profile_starttime); \
+ INC_PROFILE_COUNT(x##_count); \
+ }
+#define START_PROFILE_NESTED(x) \
+ if (do_profile_flag) { \
+ if (do_profile_times) \
+ GetTimeOfDay(&profile_starttime_nested); \
+ INC_PROFILE_COUNT(x##_count); \
+ }
+#define START_PROFILE_BYTES(x,n) \
+ if (do_profile_flag) { \
+ if (do_profile_times) \
+ GetTimeOfDay(&profile_starttime); \
+ INC_PROFILE_COUNT(x##_count); \
+ ADD_PROFILE_COUNT(x##_bytes,n); \
+ }
+#define END_PROFILE(x) \
+ if (do_profile_times) { \
+ GetTimeOfDay(&profile_endtime); \
+ ADD_PROFILE_COUNT(x##_time,PROFILE_TIME); \
+ }
+#define END_PROFILE_NESTED(x) \
+ if (do_profile_times) { \
+ GetTimeOfDay(&profile_endtime_nested); \
+ ADD_PROFILE_COUNT(x##_time,PROFILE_TIME_NESTED); \
+ }
+#else
+#define DO_PROFILE_INC(x)
+#define DO_PROFILE_DEC(x)
+#define DO_PROFILE_DEC_INC(x,y)
+#define DO_PROFILE_ADD(x,n)
+#define START_PROFILE(x)
+#define START_PROFILE_NESTED(x)
+#define START_PROFILE_BYTES(x,n)
+#define END_PROFILE(x)
+#define END_PROFILE_NESTED(x)
+#endif
+
+#endif
diff --git a/source/include/stamp-h.in b/source/include/stamp-h.in
new file mode 100644
index 00000000000..c9061b3ad3d
--- /dev/null
+++ b/source/include/stamp-h.in
@@ -0,0 +1 @@
+Sun Jul 18 20:32:29 UTC 1999
diff --git a/source/include/talloc.h b/source/include/talloc.h
new file mode 100644
index 00000000000..d8a98f07e69
--- /dev/null
+++ b/source/include/talloc.h
@@ -0,0 +1,46 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba temporary memory allocation functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ * @ingroup talloc
+ * @{
+ * @sa talloc.c
+ */
+
+/**
+ * talloc allocation pool. All allocated blocks can be freed in one go.
+ **/
+typedef struct talloc_ctx TALLOC_CTX;
+
+TALLOC_CTX *talloc_init_named(char const *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
+ PRINTF_ATTRIBUTE(2, 0);
+
+char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2, 3);
+
+/** @} */
+
+#endif /* ndef _TALLOC_H_ */
diff --git a/source/include/trans2.h b/source/include/trans2.h
index cc366ccaea0..3bf6203710e 100644
--- a/source/include/trans2.h
+++ b/source/include/trans2.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994
+ Copyright (C) Jeremy Allison 1994-1998
Extensively modified by Andrew Tridgell, 1995
@@ -194,6 +194,11 @@ Byte offset Type name description
} FSINFO;
*************************************************************/
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EA_SIZE 2
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_IS_NAME_VALID 6
#define SMB_QUERY_FS_LABEL_INFO 0x101
#define SMB_QUERY_FS_VOLUME_INFO 0x102
#define SMB_QUERY_FS_SIZE_INFO 0x103
@@ -226,14 +231,74 @@ Byte offset Type name description
#define SMB_SET_FILE_ALLOCATION_INFO 0x103
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
-#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
+/*
+ * Thursby MAC extensions....
+ */
-/* Function prototypes */
+#define SMB_MAC_QUERY_FS_INFO 0x301
+#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
-int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
+/*
+ * DeviceType and Characteristics returned in a
+ * SMB_QUERY_FS_DEVICE_INFO call.
+ */
+
+#define DEVICETYPE_CD_ROM 0x2
+#define DEVICETYPE_CD_ROM_FILE_SYSTEM 0x3
+#define DEVICETYPE_DISK 0x7
+#define DEVICETYPE_DISK_FILE_SYSTEM 0x8
+#define DEVICETYPE_FILE_SYSTEM 0x9
+
+/* Characteristics. */
+#define TYPE_REMOVABLE_MEDIA 0x1
+#define TYPE_READ_ONLY_DEVICE 0x2
+#define TYPE_FLOPPY 0x4
+#define TYPE_WORM 0x8
+#define TYPE_REMOTE 0x10
+#define TYPE_MOUNTED 0x20
+#define TYPE_VIRTUAL 0x40
+
+/* NT passthrough levels... */
+
+#define SMB_FILE_DIRECTORY_INFORMATION 1001
+#define SMB_FILE_FULL_DIRECTORY_INFORMATION 1002
+#define SMB_FILE_BOTH_DIRECTORY_INFORMATION 1003
+#define SMB_FILE_BASIC_INFORMATION 1004
+#define SMB_FILE_STANDARD_INFORMATION 1005
+#define SMB_FILE_INTERNAL_INFORMATION 1006
+#define SMB_FILE_EA_INFORMATION 1007
+#define SMB_FILE_ACCESS_INFORMATION 1008
+#define SMB_FILE_NAME_INFORMATION 1009
+#define SMB_FILE_RENAME_INFORMATION 1010
+#define SMB_FILE_LINK_INFORMATION 1011
+#define SMB_FILE_NAMES_INFORMATION 1012
+#define SMB_FILE_DISPOSITION_INFORMATION 1013
+#define SMB_FILE_POSITION_INFORMATION 1014
+#define SMB_FILE_FULL_EA_INFORMATION 1015
+#define SMB_FILE_MODE_INFORMATION 1016
+#define SMB_FILE_ALIGNMENT_INFORMATION 1017
+#define SMB_FILE_ALL_INFORMATION 1018
+#define SMB_FILE_ALLOCATION_INFORMATION 1019
+#define SMB_FILE_END_OF_FILE_INFORMATION 1020
+#define SMB_FILE_ALTERNATE_NAME_INFORMATION 1021
+#define SMB_FILE_STREAM_INFORMATION 1022
+#define SMB_FILE_PIPE_INFORMATION 1023
+#define SMB_FILE_PIPE_LOCAL_INFORMATION 1024
+#define SMB_FILE_PIPE_REMOTE_INFORMATION 1025
+#define SMB_FILE_MAILSLOT_QUERY_INFORMATION 1026
+#define SMB_FILE_MAILSLOT_SET_INFORMATION 1027
+#define SMB_FILE_COMPRESSION_INFORMATION 1028
+#define SMB_FILE_OBJECTID_INFORMATION 1029
+#define SMB_FILE_COMPLETION_INFORMATION 1030
+#define SMB_FILE_MOVE_CLUSTER_INFORMATION 1031
+#define SMB_FILE_QUOTA_INFORMATION 1032
+#define SMB_FILE_REPARSEPOINT_INFORMATION 1033
+#define SMB_FILE_NETWORK_OPEN_INFORMATION 1034
+#define SMB_FILE_ATTRIBUTE_TAG_INFORMATION 1035
+#define SMB_FILE_TRACKING_INFORMATION 1036
+#define SMB_FILE_MAXIMUM_INFORMATION 1037
-int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
#endif
diff --git a/source/include/util_getent.h b/source/include/util_getent.h
new file mode 100644
index 00000000000..5d4674ddefa
--- /dev/null
+++ b/source/include/util_getent.h
@@ -0,0 +1,62 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba utility functions
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _UTIL_GETENT_H
+#define _UTIL_GETENT_H
+
+/* Element for a single linked list of group entries */
+/* Replace the use of struct group in some cases */
+/* Used by getgrent_list() */
+
+struct sys_grent {
+ char *gr_name;
+ char *gr_passwd;
+ gid_t gr_gid;
+ char **gr_mem;
+ struct sys_grent *next;
+};
+
+/* Element for a single linked list of passwd entries */
+/* Replace the use of struct passwd in some cases */
+/* Used by getpwent_list() */
+
+struct sys_pwent {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+ struct sys_pwent *next;
+};
+
+/* Element for a single linked list of user names in a group. */
+/* Used to return group lists that may span multiple lines in
+ /etc/group file. */
+/* Used by get_users_in_group() */
+
+struct sys_userlist {
+ struct sys_userlist *next, *prev;
+ char *unix_name;
+};
+
+#endif /* _UTIL_GETENT_H */
diff --git a/source/include/util_list.h b/source/include/util_list.h
new file mode 100644
index 00000000000..4ccb1667f01
--- /dev/null
+++ b/source/include/util_list.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Gerald Carter <jerry@samba.org> 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/******************************************************************
+ Implementation of a generic list. See lib/util_list.c for
+ details on using this.
+ *****************************************************************/
+
+#include "smb.h"
+
+#ifndef _GENERIC_LIST_H
+#define _GENERIC_LIST_H
+
+struct _list_node;
+
+/*
+ * node container in list
+ */
+struct _list_node {
+
+ void *data; /* generic container pointer */
+ uint8 type; /* needed for identifiers
+ in a hetergenous list */
+ struct _list_node *next; /* next in the list */
+
+};
+
+/*
+ * list data structure
+ */
+typedef struct _generic_list {
+
+ struct _list_node *head, *tail;
+ uint32 length;
+ BOOL initialized;
+
+} GENERIC_LIST;
+
+
+#endif /* _GENERIC_LIST_H */
diff --git a/source/include/version.h b/source/include/version.h
index 9ad8b7d44b5..c3ed33a300c 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "3.0-alpha12"
diff --git a/source/include/vfs.h b/source/include/vfs.h
new file mode 100644
index 00000000000..5a8451fb148
--- /dev/null
+++ b/source/include/vfs.h
@@ -0,0 +1,112 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ VFS structures and parameters
+ Copyright (C) Tim Potter 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _VFS_H
+#define _VFS_H
+
+/* Avoid conflict with an AIX include file */
+
+#ifdef vfs_ops
+#undef vfs_ops
+#endif
+
+/*
+ * As we're now (thanks Andrew ! :-) using file_structs and connection
+ * structs in the vfs - then anyone writing a vfs must include includes.h...
+ */
+
+/*
+ * This next constant specifies the version number of the VFS interface
+ * this smbd will load. Increment this if *ANY* changes are made to the
+ * vfs_ops below. JRA.
+ */
+
+#define SMB_VFS_INTERFACE_VERSION 2
+
+/* VFS operations structure */
+
+struct connection_struct;
+struct files_struct;
+struct security_descriptor_info;
+
+struct vfs_ops {
+
+ /* Disk operations */
+
+ int (*connect)(struct connection_struct *conn, const char *service, const char *user);
+ void (*disconnect)(struct connection_struct *conn);
+ SMB_BIG_UINT (*disk_free)(struct connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+
+ /* Directory operations */
+
+ DIR *(*opendir)(struct connection_struct *conn, const char *fname);
+ struct dirent *(*readdir)(struct connection_struct *conn, DIR *dirp);
+ int (*mkdir)(struct connection_struct *conn, const char *path, mode_t mode);
+ int (*rmdir)(struct connection_struct *conn, const char *path);
+ int (*closedir)(struct connection_struct *conn, DIR *dir);
+
+ /* File operations */
+
+ int (*open)(struct connection_struct *conn, const char *fname, int flags, mode_t mode);
+ int (*close)(struct files_struct *fsp, int fd);
+ ssize_t (*read)(struct files_struct *fsp, int fd, void *data, size_t n);
+ ssize_t (*write)(struct files_struct *fsp, int fd, const void *data, size_t n);
+ SMB_OFF_T (*lseek)(struct files_struct *fsp, int filedes, SMB_OFF_T offset, int whence);
+ int (*rename)(struct connection_struct *conn, const char *old, const char *new);
+ int (*fsync)(struct files_struct *fsp, int fd);
+ int (*stat)(struct connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf);
+ int (*fstat)(struct files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf);
+ int (*lstat)(struct connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf);
+ int (*unlink)(struct connection_struct *conn, const char *path);
+ int (*chmod)(struct connection_struct *conn, const char *path, mode_t mode);
+ int (*fchmod)(struct files_struct *fsp, int fd, mode_t mode);
+ int (*chown)(struct connection_struct *conn, const char *path, uid_t uid, gid_t gid);
+ int (*fchown)(struct files_struct *fsp, int fd, uid_t uid, gid_t gid);
+ int (*chdir)(struct connection_struct *conn, const char *path);
+ char *(*getwd)(struct connection_struct *conn, char *buf);
+ int (*utime)(struct connection_struct *conn, const char *path, struct utimbuf *times);
+ int (*ftruncate)(struct files_struct *fsp, int fd, SMB_OFF_T offset);
+ BOOL (*lock)(struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+ int (*symlink)(struct connection_struct *conn, const char *oldpath, const char *newpath);
+ int (*readlink)(struct connection_struct *conn, const char *path, char *buf, size_t bufsiz);
+
+ /* NT ACL operations. */
+
+ size_t (*fget_nt_acl)(struct files_struct *fsp, int fd, struct security_descriptor_info **ppdesc);
+ size_t (*get_nt_acl)(struct files_struct *fsp, const char *name, struct security_descriptor_info **ppdesc);
+ BOOL (*fset_nt_acl)(struct files_struct *fsp, int fd, uint32 security_info_sent, struct security_descriptor_info *psd);
+ BOOL (*set_nt_acl)(struct files_struct *fsp, const char *name, uint32 security_info_sent, struct security_descriptor_info *psd);
+
+ /* POSIX ACL operations. */
+
+ int (*chmod_acl)(struct connection_struct *conn, const char *name, mode_t mode);
+ int (*fchmod_acl)(struct files_struct *fsp, int fd, mode_t mode);
+
+};
+
+struct vfs_options {
+ struct vfs_options *prev, *next;
+ char *name;
+ char *value;
+};
+
+#endif /* _VFS_H */
diff --git a/source/include/xfile.h b/source/include/xfile.h
new file mode 100644
index 00000000000..fa4752fe30b
--- /dev/null
+++ b/source/include/xfile.h
@@ -0,0 +1,48 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ stdio replacement
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _XFILE_H_
+#define _XFILE_H_
+/*
+ see xfile.c for explanations
+*/
+
+typedef struct {
+ int fd;
+ char *buf;
+ char *next;
+ int bufsize;
+ int bufused;
+ int open_flags;
+ int buftype;
+ int flags;
+} XFILE;
+
+extern XFILE *x_stdin, *x_stdout, *x_stderr;
+
+/* buffering type */
+#define X_IOFBF 0
+#define X_IOLBF 1
+#define X_IONBF 2
+
+#define x_getc(f) x_fgetc(f)
+
+#endif /* _XFILE_H_ */
diff --git a/source/install-sh b/source/install-sh
new file mode 100755
index 00000000000..58719246f04
--- /dev/null
+++ b/source/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/source/internals.doc b/source/internals.doc
new file mode 100644
index 00000000000..c8cc6dd1367
--- /dev/null
+++ b/source/internals.doc
@@ -0,0 +1,281 @@
+internals.txt, 8 May 1996
+Written by David Chappell <David.Chappell@mail.trincoll.edu>.
+
+This document describes some of the internal functions which must be
+understood by anyone wishing to add features to Samba.
+
+
+
+=============================================================================
+This section describes character set handling in Samba, as implemented in
+Samba 3.0 and above
+
+In the past Samba had very ad-hoc character set handling. Scattered
+throughout the code were numerous calls which converted particular
+strings to/from DOS codepages. The problem is that there was no way of
+telling if a particular char* is in dos codepage or unix
+codepage. This led to a nightmare of code that tried to cope with
+particular cases without handlingt the general case.
+
+The new system works like this:
+
+- all char* strings inside Samba are "unix" strings. These are
+ multi-byte strings that are in the charset defined by the "unix
+ charset" option in smb.conf.
+
+- there is no single fixed character set for unix strings, but any
+ character set that is used does need the following properties:
+ * must not contain NULLs except for termination
+ * must be 7-bit compatible with C strings, so that a constant
+ string or character in C will be byte-for-byte identical to the
+ equivalent string in the chosen character set.
+ * when you uppercase or lowercase a string it does not become
+ longer than the original string
+ * must be able to correctly hold all characters that your client
+ will throw at it
+ For example, UTF-8 is fine, and most multi-byte asian character sets
+ are fine, but UCS2 could not be used for unix strings as they
+ contain nulls.
+
+- when you need to put a string into a buffer that will be sent on the
+ wire, or you need a string in a character set format that is
+ compatible with the clients character set then you need to use a
+ pull_ or push_ function. The pull_ functions pull a string from a
+ wire buffer into a (multi-byte) unix string. The push_ functions
+ push a string out to a wire buffer.
+
+- the two main pull_ and push_ functions you need to understand are
+ pull_string and push_string. These functions take a base pointer
+ that should point at the start of the SMB packet that the string is
+ in. The functions will check the flags field in this packet to
+ automatically determine if the packet is marked as a unicode packet,
+ and they will choose whether to use unicode for this string based on
+ that flag. You may also force this decision using the STR_UNICODE or
+ STR_ASCII flags. For use in smbd/ and libsmb/ there are wrapper
+ functions clistr_ and srvstr_ that call the pull_/push_ functions
+ with the appropriate first argument.
+
+ You may also call the pull_ascii/pull_ucs2 or push_ascii/push_ucs2
+ functions if you know that a particular string is ascii or
+ unicode. There are also a number of other convenience functions in
+ charcnv.c that call the pull_/push_ functions with particularly
+ common arguments, such as pull_ascii_pstring()
+
+The biggest thing to remember is that internal (unix) strings in Samba
+may now contain multi-byte characters. This means you cannot assume
+that characters are always 1 byte long. Often this means that you will
+have to convert strings to ucs2 and back again in order to do some
+(seemingly) simple task. For examples of how to do this see functions
+like strchr_m(). I know this is very slow, and we will eventually
+speed it up but right now we want this stuff correct not fast.
+
+Other rules:
+
+ - all lp_ functions now return unix strings. The magic "DOS" flag on
+ parameters is gone.
+ - all vfs functions take unix strings. Don't convert when passing to
+ them
+
+
+=============================================================================
+This section describes the macros defined in byteorder.h. These macros
+are used extensively in the Samba code.
+
+-----------------------------------------------------------------------------
+CVAL(buf,pos)
+
+returns the byte at offset pos within buffer buf as an unsigned character.
+
+-----------------------------------------------------------------------------
+PVAL(buf,pos)
+
+returns the value of CVAL(buf,pos) cast to type unsigned integer.
+
+-----------------------------------------------------------------------------
+SCVAL(buf,pos,val)
+
+sets the byte at offset pos within buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) little-endian integer at
+offset pos within buffer buf. An integer of this type is sometimes
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+IVAL(buf,pos)
+
+returns the value of the unsigned 32 bit little-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+SVALS(buf,pos)
+
+returns the value of the signed short (16 bit) little-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+IVALS(buf,pos)
+
+returns the value of the signed 32 bit little-endian integer at offset pos
+within buffer buf.
+
+-----------------------------------------------------------------------------
+SSVAL(buf,pos,val)
+
+sets the unsigned short (16 bit) little-endian integer at offset pos within
+buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SIVAL(buf,pos,val)
+
+sets the unsigned 32 bit little-endian integer at offset pos within buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+SSVALS(buf,pos,val)
+
+sets the short (16 bit) signed little-endian integer at offset pos within
+buffer buf to the value val.
+
+-----------------------------------------------------------------------------
+SIVALS(buf,pos,val)
+
+sets the signed 32 bit little-endian integer at offset pos withing buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+RSVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RIVAL(buf,pos)
+
+returns the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RSSVAL(buf,pos,val)
+
+sets the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf to value val.
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+RSIVAL(buf,pos,val)
+
+sets the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf to value val.
+
+
+
+
+
+=============================================================================
+This section describes the functions need to make a LAN Manager RPC call.
+This information had been obtained by examining the Samba code and the LAN
+Manager 2.0 API documentation. It should not be considered entirely
+reliable.
+
+-----------------------------------------------------------------------------
+call_api(int prcnt, int drcnt, int mprcnt, int mdrcnt,
+ char *param, char *data, char **rparam, char **rdata);
+
+This function is defined in client.c. It uses an SMB transaction to call a
+remote api.
+
+The parameters are as follows:
+
+prcnt: the number of bytes of parameters begin sent.
+drcnt: the number of bytes of data begin sent.
+mprcnt: the maximum number of bytes of parameters which should be returned
+mdrcnt: the maximum number of bytes of data which should be returned
+param: a pointer to the parameters to be sent.
+data: a pointer to the data to be sent.
+rparam: a pointer to a pointer which will be set to point to the returned
+ paramters. The caller of call_api() must deallocate this memory.
+rdata: a pointer to a pointer which will be set to point to the returned
+ data. The caller of call_api() must deallocate this memory.
+
+-----------------------------------------------------------------------------
+These are the parameters which you ought to send, in the order of their
+appearance in the parameter block:
+
+* An unsigned 16 bit integer API number. You should set this value with
+SSVAL(). I do not know where these numbers are described.
+
+* An ASCIIZ string describing the parameters to the API function as defined
+in the LAN Manager documentation. The first parameter, which is the server
+name, is ommited. This string is based uppon the API function as described
+in the manual, not the data which is actually passed.
+
+* An ASCIIZ string describing the data structure which ought to be returned.
+
+* Any parameters which appear in the function call, as defined in the LAN
+Manager API documentation, after the "Server" and up to and including the
+"uLevel" parameters.
+
+* An unsigned 16 bit integer which gives the size in bytes of the buffer we
+will use to receive the returned array of data structures. Presumably this
+should be the same as mdrcnt. This value should be set with SSVAL().
+
+* An ASCIIZ string describing substructures which should be returned. If no
+substructures apply, this string is of zero length.
+
+-----------------------------------------------------------------------------
+The code in client.c always calls call_api() with no data. It is unclear
+when a non-zero length data buffer would be sent.
+
+-----------------------------------------------------------------------------
+The returned parameters (pointed to by rparam), in their order of appearance
+are:
+
+* An unsigned 16 bit integer which contains the API function's return code.
+This value should be read with SVAL().
+
+* An adjustment which tells the amount by which pointers in the returned
+data should be adjusted. This value should be read with SVAL(). Basically,
+the address of the start of the returned data buffer should have the returned
+pointer value added to it and then have this value subtracted from it in
+order to obtain the currect offset into the returned data buffer.
+
+* A count of the number of elements in the array of structures returned.
+It is also possible that this may sometimes be the number of bytes returned.
+
+-----------------------------------------------------------------------------
+When call_api() returns, rparam points to the returned parameters. The
+first if these is the result code. It will be zero if the API call
+suceeded. This value by be read with "SVAL(rparam,0)".
+
+The second parameter may be read as "SVAL(rparam,2)". It is a 16 bit offset
+which indicates what the base address of the returned data buffer was when
+it was built on the server. It should be used to correct pointer before
+use.
+
+The returned data buffer contains the array of returned data structures.
+Note that all pointers must be adjusted before use. The function
+fix_char_ptr() in client.c can be used for this purpose.
+
+The third parameter (which may be read as "SVAL(rparam,4)") has something to
+do with indicating the amount of data returned or possibly the amount of
+data which can be returned if enough buffer space is allowed.
+
+-----------------------------------------------------------------------------
+Certain data structures are described by means of ASCIIz strings containing
+code characters. These are the code characters:
+
+W a type byte little-endian unsigned integer
+N a count of substructures which follow
+D a four byte little-endian unsigned integer
+B a byte (with optional count expressed as trailing ASCII digits)
+z a four byte offset to a NULL terminated string
+l a four byte offset to non-string user data
+b an offset to data (with count expressed as trailing ASCII digits)
+r pointer to returned data buffer???
+L length in bytes of returned data buffer???
+h number of bytes of information available???
+
+----------------------------------------------------------------------------
diff --git a/source/intl/.cvsignore b/source/intl/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/intl/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/intl/lang_tdb.c b/source/intl/lang_tdb.c
new file mode 100644
index 00000000000..36f8020bbe1
--- /dev/null
+++ b/source/intl/lang_tdb.c
@@ -0,0 +1,223 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ tdb based replacement for gettext
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb;
+
+/* the currently selected language */
+static char *current_lang;
+
+
+/* load a msg file into the tdb */
+static BOOL load_msg(const char *msg_file)
+{
+ char **lines;
+ int num_lines, i;
+ char *msgid, *msgstr;
+ TDB_DATA key, data;
+
+ lines = file_lines_load(msg_file, &num_lines);
+
+ if (!lines) {
+ return False;
+ }
+
+ if (tdb_lockall(tdb) != 0) return False;
+
+ /* wipe the db */
+ tdb_traverse(tdb, (tdb_traverse_func) tdb_delete, NULL);
+
+ msgid = NULL;
+
+ for (i=0;i<num_lines;i++) {
+ if (strncmp(lines[i], "msgid \"", 7) == 0) {
+ msgid = lines[i] + 7;
+ }
+ if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
+ msgstr = lines[i] + 8;
+ trim_string(msgid, NULL, "\"");
+ trim_string(msgstr, NULL, "\"");
+ if (*msgstr == 0) {
+ msgstr = msgid;
+ }
+ key.dptr = msgid;
+ key.dsize = strlen(msgid)+1;
+ data.dptr = msgstr;
+ data.dsize = strlen(msgstr)+1;
+ tdb_store(tdb, key, data, 0);
+ msgid = NULL;
+ }
+ }
+
+ file_lines_free(lines);
+ tdb_unlockall(tdb);
+
+ return True;
+}
+
+
+/* work out what language to use from locale variables */
+static char *get_lang(void)
+{
+ char *vars[] = {"LANGUAGE", "LC_ALL", "LC_LANG", "LANG", NULL};
+ int i;
+ char *p;
+
+ for (i=0; vars[i]; i++) {
+ if ((p = getenv(vars[i]))) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+/* initialise the message translation subsystem. If the "lang" argument
+ is NULL then get the language from the normal environment variables */
+BOOL lang_tdb_init(const char *lang)
+{
+ char *path = NULL;
+ char *msg_path = NULL;
+ struct stat st;
+ static int initialised;
+ time_t loadtime;
+
+ /* we only want to init once per process, unless given
+ an override */
+ if (initialised && !lang) return True;
+
+ if (initialised) {
+ /* we are re-initialising, free up any old init */
+ tdb_close(tdb);
+ tdb = NULL;
+ SAFE_FREE(current_lang);
+ }
+
+ initialised = 1;
+
+ if (!lang) {
+ /* no lang given, use environment */
+ lang = get_lang();
+ }
+
+ /* if no lang then we don't translate */
+ if (!lang) return True;
+
+ asprintf(&msg_path, "%s.msg", lib_path((char *)lang));
+ if (stat(msg_path, &st) != 0) {
+ /* the msg file isn't available */
+ free(msg_path);
+ return False;
+ }
+
+
+ asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang);
+
+ tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
+ if (!tdb) {
+ tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDONLY, 0);
+ free(path);
+ free(msg_path);
+ if (!tdb) return False;
+ current_lang = strdup(lang);
+ return True;
+ }
+
+ free(path);
+
+ loadtime = tdb_fetch_int(tdb, "/LOADTIME/");
+
+ if (loadtime == -1 || loadtime < st.st_mtime) {
+ load_msg(msg_path);
+ tdb_store_int(tdb, "/LOADTIME/", (int)time(NULL));
+ }
+ free(msg_path);
+
+ current_lang = strdup(lang);
+
+ return True;
+}
+
+/* translate a msgid to a message string in the current language
+ returns a string that must be freed by calling lang_msg_free()
+*/
+const char *lang_msg(const char *msgid)
+{
+ TDB_DATA key, data;
+
+ lang_tdb_init(NULL);
+
+ if (!tdb) return msgid;
+
+ key.dptr = (char *)msgid;
+ key.dsize = strlen(msgid)+1;
+
+ data = tdb_fetch(tdb, key);
+
+ /* if the message isn't found then we still need to return a pointer
+ that can be freed. Pity. */
+ if (!data.dptr) return strdup(msgid);
+
+ return (const char *)data.dptr;
+}
+
+
+/* free up a string from lang_msg() */
+void lang_msg_free(const char *msgstr)
+{
+ if (!tdb) return;
+ free((void *)msgstr);
+}
+
+
+/*
+ when the _() translation macro is used there is no obvious place to free
+ the resulting string and there is no easy way to give a static pointer.
+ All we can do is rotate between some static buffers and hope a single d_printf()
+ doesn't have more calls to _() than the number of buffers
+*/
+const char *lang_msg_rotate(const char *msgid)
+{
+#define NUM_LANG_BUFS 4
+ char *msgstr;
+ static pstring bufs[NUM_LANG_BUFS];
+ static int next;
+
+ msgstr = (char *)lang_msg(msgid);
+ if (!msgstr) return msgid;
+
+ pstrcpy(bufs[next], msgstr);
+ msgstr = bufs[next];
+
+ next = (next+1) % NUM_LANG_BUFS;
+
+ return msgstr;
+}
+
+
+/*
+ return the current language - needed for language file mappings
+*/
+char *lang_tdb_current(void)
+{
+ return current_lang;
+}
diff --git a/source/intl/linux-msg.sed b/source/intl/linux-msg.sed
new file mode 100644
index 00000000000..5918e720a9a
--- /dev/null
+++ b/source/intl/linux-msg.sed
@@ -0,0 +1,100 @@
+# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number. We use always set number 1.
+#
+1 {
+ i\
+$set 1 # Automatically created by po2msg.sed
+ h
+ s/.*/0/
+ x
+}
+#
+# Mitch's old catalog format does not allow comments.
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+ s/msgid[ ]*"//
+#
+# This does not work now with the new format.
+# /"$/! {
+# s/\\$//
+# s/$/ ... (more lines following)"/
+# }
+ x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+ td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+ :d
+ s/9\(_*\)$/_\1/
+ td
+# Assure at least one digit is available.
+ s/^\(_*\)$/0\1/
+# Increment the last digit.
+ s/8\(_*\)$/9\1/
+ s/7\(_*\)$/8\1/
+ s/6\(_*\)$/7\1/
+ s/5\(_*\)$/6\1/
+ s/4\(_*\)$/5\1/
+ s/3\(_*\)$/4\1/
+ s/2\(_*\)$/3\1/
+ s/1\(_*\)$/2\1/
+ s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+ s/_/0/g
+ x
+ G
+ s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID. Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here. (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+ s/msgstr[ ]*"\(.*\)"/# \1/
+# Clear substitution flag.
+ tb
+# Append the next line.
+ :b
+ N
+# Look whether second part is continuation line.
+ s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+ ta
+ P
+ D
+# Note that D includes a jump to the start!!
+# We found a continuation line. But before printing insert '\'.
+ :a
+ s/\(.*\)\(\n.*\)/\1\\\2/
+ P
+# We cannot use D here.
+ s/.*\n\(.*\)/\1/
+ tb
+}
+d
diff --git a/source/lib/.cvsignore b/source/lib/.cvsignore
new file mode 100644
index 00000000000..07da2225c72
--- /dev/null
+++ b/source/lib/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source/lib/access.c b/source/lib/access.c
index 14a84b2fb44..f59bf860577 100644
--- a/source/lib/access.c
+++ b/source/lib/access.c
@@ -1,147 +1,154 @@
/*
-This module is an adaption of code from the tcpd-1.4 package written
-by Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ This module is an adaption of code from the tcpd-1.4 package written
+ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
-The code is used here with permission.
+ The code is used here with permission.
-The code has been considerably changed from the original. Bug reports
-should be sent to Andrew.Tridgell@anu.edu.au
+ The code has been considerably changed from the original. Bug reports
+ should be sent to samba@samba.org
*/
#include "includes.h"
-#include "loadparm.h"
-#define ALLOW_PURE_ADDRESSES
-
-extern int DEBUGLEVEL;
-
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long)~0)
-#endif
-
-
-#define FROM_ADDRLEN (4*3+3+1)
-#define Good True
-#define Bad False
-
-#define CLIENT_MATCH client_match
-
-/* Delimiters for lists of daemons or clients. */
-
-static char sep[] = ", \t";
-
-/* Constants to be used in assignments only, not in comparisons... */
-
-#define YES 1
-#define NO 0
#define FAIL (-1)
-/* Forward declarations. */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
-static int list_match(char *list,char *item, int (*match_fn)());
-static int client_match(char *tok,char *item);
-static int string_match(char *tok,char *s);
-static int masked_match(char *tok, char *slash, char *s);
-static int matchname(char *remotehost,struct in_addr addr);
-BOOL fromhost(int sock,struct from_host *f);
-
-
-/* Size of logical line buffer. */
-#define BUFLEN 2048
-
+/* masked_match - match address against netnumber/netmask */
+static int masked_match(char *tok, char *slash, char *s)
+{
+ uint32 net;
+ uint32 mask;
+ uint32 addr;
+
+ if ((addr = interpret_addr(s)) == INADDR_NONE)
+ return (False);
+ *slash = 0;
+ net = interpret_addr(tok);
+ *slash = '/';
+ if (net == INADDR_NONE ||
+ (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
+ DEBUG(0,("access: bad net/mask access control: %s\n", tok));
+ return (False);
+ }
+ return ((addr & mask) == net);
+}
-/* return true if access should be allowed to a service*/
-BOOL check_access(int snum)
+/* string_match - match string against token */
+static int string_match(char *tok,char *s, char *invalid_char)
{
- extern int Client;
- extern struct from_host Client_info;
- char *denyl,*allowl;
- BOOL ret = False;
+ size_t tok_len;
+ size_t str_len;
+ char *cut;
+
+ *invalid_char = '\0';
+
+ /* Return True if a token has the magic value "ALL". Return
+ * FAIL if the token is "FAIL". If the token starts with a "."
+ * (domain name), return True if it matches the last fields of
+ * the string. If the token has the magic value "LOCAL",
+ * return True if the string does not contain a "."
+ * character. If the token ends on a "." (network number),
+ * return True if it matches the first fields of the
+ * string. If the token begins with a "@" (netgroup name),
+ * return True if the string is a (host) member of the
+ * netgroup. Return True if the token fully matches the
+ * string. If the token is a netnumber/netmask pair, return
+ * True if the address is a member of the specified subnet.
+ */
+
+ if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(s)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, s + str_len - tok_len) == 0)
+ return (True);
+ } else if (tok[0] == '@') { /* netgroup: look it up */
+#ifdef HAVE_NETGROUP
+ static char *mydomain = NULL;
+ char *hostname = NULL;
+ BOOL netgroup_ok = False;
+
+ if (!mydomain) yp_get_default_domain(&mydomain);
+
+ if (!mydomain) {
+ DEBUG(0,("Unable to get default yp domain.\n"));
+ return False;
+ }
+ if (!(hostname = strdup(s))) {
+ DEBUG(1,("out of memory for strdup!\n"));
+ return False;
+ }
+
+ netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
+
+ DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
+ hostname,
+ mydomain,
+ tok+1,
+ BOOLSTR(netgroup_ok)));
+
+ SAFE_FREE(hostname);
+
+ if (netgroup_ok) return(True);
+#else
+ DEBUG(0,("access: netgroup support is not configured\n"));
+ return (False);
+#endif
+ } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */
+ return (True);
+ } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */
+ return (FAIL);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr_m(s, '.') == 0 && strcasecmp(s, "unknown") != 0)
+ return (True);
+ } else if (!strcasecmp(tok, s)) { /* match host name or address */
+ return (True);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
+ if (strncmp(tok, s, tok_len) == 0)
+ return (True);
+ } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */
+ if (isdigit((int)s[0]) && masked_match(tok, cut, s))
+ return (True);
+ } else if (strchr_m(tok, '*') != 0) {
+ *invalid_char = '*';
+ } else if (strchr_m(tok, '?') != 0) {
+ *invalid_char = '?';
+ }
+ return (False);
+}
- denyl = lp_hostsdeny(snum);
- if (denyl) denyl = strdup(denyl);
- allowl = lp_hostsallow(snum);
- if (allowl) allowl = strdup(allowl);
+/* client_match - match host name and address against token */
+static int client_match(char *tok,char *item)
+{
+ char **client = (char **)item;
+ int match;
+ char invalid_char = '\0';
+ /*
+ * Try to match the address first. If that fails, try to match the host
+ * name if available.
+ */
- fromhost(Client,&Client_info);
+ if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
+ if(invalid_char)
+ DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
+token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
- if ((!denyl || *denyl==0) && (!allowl || *allowl==0))
- ret = True;
+ if (client[0][0] != 0)
+ match = string_match(tok, client[0], &invalid_char);
- if (!ret)
- {
- if (!fromhost(Client,&Client_info))
- DEBUG(0,("ERROR: Can't get from_host info\n"));
- else
- {
- if (allow_access(denyl,allowl,&Client_info))
- {
- if (snum >= 0)
- DEBUG(2,("Allowed connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
- ret = True;
- }
- else
- if (snum >= 0)
- DEBUG(0,("Denied connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
+ if(invalid_char)
+ DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
+token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
}
- }
-
- if (denyl) free(denyl);
- if (allowl) free(allowl);
- return(ret);
-}
-
-/* return true if access should be allowed */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client)
-{
- /* if theres no deny list and no allow list then allow access */
- if ((!deny_list || *deny_list == 0) && (!allow_list || *allow_list == 0))
- return(True);
-
- /* if there is an allow list but no deny list then allow only hosts
- on the allow list */
- if (!deny_list || *deny_list == 0)
- return(list_match(allow_list,(char *)client,CLIENT_MATCH));
-
- /* if theres a deny list but no allow list then allow
- all hosts not on the deny list */
- if (!allow_list || *allow_list == 0)
- return(!list_match(deny_list,(char *)client,CLIENT_MATCH));
-
- /* if there are both type of list then allow all hosts on the allow list */
- if (list_match(allow_list,(char *)client,CLIENT_MATCH))
- return (True);
-
- /* if there are both type of list and it's not on the allow then
- allow it if its not on the deny */
- if (list_match(deny_list,(char *)client,CLIENT_MATCH))
- return (False);
-
- return (True);
+ return (match);
}
/* list_match - match an item against a list of tokens with exceptions */
-/* (All modifications are marked with the initials "jkf") */
-static int list_match(char *list,char *item, int (*match_fn)())
+static int list_match(char **list,char *item, int (*match_fn)(char *, char *))
{
- char *tok;
- char *listcopy; /* jkf */
- int match = NO;
-
- /*
- * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match()
- * overwriting the list given as its first parameter.
- */
+ int match = False;
- /* jkf -- can get called recursively with NULL list */
- listcopy = (list == 0) ? (char *)0 : strdup(list);
+ if (!list) return False;
/*
* Process tokens one at a time. We have exhausted all possible matches
@@ -150,240 +157,152 @@ static int list_match(char *list,char *item, int (*match_fn)())
* the match is affected by any exceptions.
*/
- for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) {
- if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ for (; *list ; list++) {
+ if (strcasecmp(*list, "EXCEPT") == 0) /* EXCEPT: give up */
break;
- if ((match = (*match_fn) (tok, item))) /* YES or FAIL */
+ if ((match = (*match_fn) (*list, item))) /* True or FAIL */
break;
}
- /* Process exceptions to YES or FAIL matches. */
-
- if (match != NO) {
- while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
- /* VOID */ ;
- if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) {
- if (listcopy != 0) free(listcopy); /* jkf */
- return (match);
- }
- }
-
- if (listcopy != 0) free(listcopy); /* jkf */
- return (NO);
-}
+ /* Process exceptions to True or FAIL matches. */
+ if (match != False) {
+ while (*list && strcasecmp(*list, "EXCEPT"))
+ list++;
-/* client_match - match host name and address against token */
-static int client_match(char *tok,char *item)
-{
- struct from_host *client = (struct from_host *) item;
- int match;
-
- /*
- * Try to match the address first. If that fails, try to match the host
- * name if available.
- */
+ for (; *list; list++) {
+ if ((*match_fn) (*list, item)) /* Exception Found */
+ return False;
+ }
+ }
- if ((match = string_match(tok, client->addr)) == 0)
- if (client->name[0] != 0)
- match = string_match(tok, client->name);
return (match);
}
-/* string_match - match string against token */
-static int string_match(char *tok,char *s)
-{
- int tok_len;
- int str_len;
- char *cut;
-
- /*
- * Return YES if a token has the magic value "ALL". Return FAIL if the
- * token is "FAIL". If the token starts with a "." (domain name), return
- * YES if it matches the last fields of the string. If the token has the
- * magic value "LOCAL", return YES if the string does not contain a "."
- * character. If the token ends on a "." (network number), return YES if
- * it matches the first fields of the string. If the token begins with a
- * "@" (netgroup name), return YES if the string is a (host) member of
- * the netgroup. Return YES if the token fully matches the string. If the
- * token is a netnumber/netmask pair, return YES if the address is a
- * member of the specified subnet.
- */
- if (tok[0] == '.') { /* domain: match last fields */
- if ((str_len = strlen(s)) > (tok_len = strlen(tok))
- && strcasecmp(tok, s + str_len - tok_len) == 0)
- return (YES);
- } else if (tok[0] == '@') { /* netgroup: look it up */
-#ifdef NETGROUP
- static char *mydomain = NULL;
- char *hostname = NULL;
- BOOL netgroup_ok = False;
-
- if (!mydomain) yp_get_default_domain(&mydomain);
-
- if (!(hostname = strdup(s))) {
- DEBUG(1,("out of memory for strdup!\n"));
- return NO;
- }
-
- netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
-
- DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
- hostname,
- mydomain,
- tok+1,
- BOOLSTR(netgroup_ok)));
-
-#ifdef NETGROUP_INSECURE
- /* if you really want netgroups that match non qualified names
- then define NETGROUP_INSECURE. It can, however, be a big
- security hole */
- {
- char *clnt_domain;
- if (!netgroup_ok && (clnt_domain=strchr(hostname,'.'))) {
- *clnt_domain++ = '\0';
- netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
+/* return true if access should be allowed */
+BOOL allow_access(char **deny_list,char **allow_list,
+ char *cname,char *caddr)
+{
+ char *client[2];
+
+ client[0] = cname;
+ client[1] = caddr;
+
+ /* if it is loopback then always allow unless specifically denied */
+ if (strcmp(caddr, "127.0.0.1") == 0) {
+ if (deny_list &&
+ list_match(deny_list,(char *)client,client_match)) {
+ return False;
+ }
+ return True;
}
- }
-#endif
- free(hostname);
-
- if (netgroup_ok) return(YES);
-#else
- DEBUG(0,("access: netgroup support is not configured"));
- return (NO);
-#endif
- } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */
- return (YES);
- } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */
- return (FAIL);
- } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
- if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0)
- return (YES);
- } else if (!strcasecmp(tok, s)) { /* match host name or address */
- return (YES);
- } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
- if (strncmp(tok, s, tok_len) == 0)
- return (YES);
- } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */
- if (isdigit(s[0]) && masked_match(tok, cut, s))
- return (YES);
- }
- return (NO);
-}
+ /* if theres no deny list and no allow list then allow access */
+ if ((!deny_list || *deny_list == 0) &&
+ (!allow_list || *allow_list == 0)) {
+ return(True);
+ }
-/* masked_match - match address against netnumber/netmask */
-static int masked_match(char *tok, char *slash, char *s)
-{
- unsigned long net;
- unsigned long mask;
- unsigned long addr;
-
- if ((addr = interpret_addr(s)) == INADDR_NONE)
- return (NO);
- *slash = 0;
- net = interpret_addr(tok);
- *slash = '/';
- if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
- DEBUG(0,("access: bad net/mask access control: %s", tok));
- return (NO);
- }
- return ((addr & mask) == net);
+ /* if there is an allow list but no deny list then allow only hosts
+ on the allow list */
+ if (!deny_list || *deny_list == 0)
+ return(list_match(allow_list,(char *)client,client_match));
+
+ /* if theres a deny list but no allow list then allow
+ all hosts not on the deny list */
+ if (!allow_list || *allow_list == 0)
+ return(!list_match(deny_list,(char *)client,client_match));
+
+ /* if there are both types of list then allow all hosts on the
+ allow list */
+ if (list_match(allow_list,(char *)client,client_match))
+ return (True);
+
+ /* if there are both types of list and it's not on the allow then
+ allow it if its not on the deny */
+ if (list_match(deny_list,(char *)client,client_match))
+ return (False);
+
+ return (True);
}
-
-/* fromhost - find out what is at the other end of a socket */
-BOOL fromhost(int sock,struct from_host *f)
+/* return true if the char* contains ip addrs only. Used to avoid
+gethostbyaddr() calls */
+static BOOL only_ipaddrs_in_list(char** list)
{
- static struct sockaddr sa;
- struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
- struct hostent *hp;
- int length = sizeof(sa);
- static char addr_buf[FROM_ADDRLEN];
- static char name_buf[MAXHOSTNAMELEN];
- BOOL takeAddressAsHostname = False;
-
- if (getpeername(sock, &sa, &length) < 0)
- {
- DEBUG(0,("getpeername failed\n"));
- return(False);
- }
-
- f->sin = sockin;
- f->addr = strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
-
- /* Look up the remote host name. */
- if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
- sizeof(sockin->sin_addr),
- AF_INET)) == 0) {
- DEBUG(1,("Gethostbyaddr failed for %s\n",addr_buf));
-#ifdef ALLOW_PURE_ADDRESSES
- takeAddressAsHostname = True;
-#else
- return(False);
-#endif
- }
-
- /* Save the host name. A later gethostbyxxx() call may clobber it. */
- f->name = StrnCpy(name_buf,
- takeAddressAsHostname? f->addr : hp->h_name,
- sizeof(name_buf) - 1);
-
- /*
- * Verify that the host name does not belong to someone else. If host
- * name verification fails, pretend that the host name lookup failed.
- */
- if (!takeAddressAsHostname && !matchname(f->name, sockin->sin_addr))
- {
- DEBUG(0,("Matchname failed\n"));
- return(False);
- }
-
- return(True);
+ BOOL only_ip = True;
+
+ if (!list) return True;
+
+ for (; *list ; list++)
+ {
+ /* factor out the special strings */
+ if (!strcasecmp(*list, "ALL") || !strcasecmp(*list, "FAIL") ||
+ !strcasecmp(*list, "EXCEPT"))
+ {
+ continue;
+ }
+
+ if (!is_ipaddress(*list))
+ {
+ char *p;
+ /*
+ * if we failed, make sure that it was not because the token
+ * was a network/netmask pair. Only network/netmask pairs
+ * have a '/' in them
+ */
+ if ((p=strchr_m(*list, '/')) == NULL)
+ {
+ only_ip = False;
+ DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
+ break;
+ }
+ }
+ }
+
+ return only_ip;
}
-/* matchname - determine if host name matches IP address */
-static int matchname(char *remotehost,struct in_addr addr)
+/* return true if access should be allowed to a service for a socket */
+BOOL check_access(int sock, char **allow_list, char **deny_list)
{
- struct hostent *hp;
- int i;
-
- if ((hp = Get_Hostbyname(remotehost)) == 0) {
- DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
- return (Bad);
- }
-
- /*
- * Make sure that gethostbyname() returns the "correct" host name.
- * Unfortunately, gethostbyname("localhost") sometimes yields
- * "localhost.domain". Since the latter host name comes from the
- * local DNS, we just have to trust it (all bets are off if the local
- * DNS is perverted). We always check the address list, though.
- */
-
- if (strcasecmp(remotehost, hp->h_name)
- && strcasecmp(remotehost, "localhost")) {
- DEBUG(0,("host name/name mismatch: %s != %s",
- remotehost, hp->h_name));
- return (Bad);
- }
+ BOOL ret = False;
+ BOOL only_ip = False;
- /* Look up the host address in the address list we just got. */
- for (i = 0; hp->h_addr_list[i]; i++) {
- if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
- return (Good);
- }
-
- /*
- * The host name does not map to the original host address. Perhaps
- * someone has compromised a name server. More likely someone botched
- * it, but that could be dangerous, too.
- */
-
- DEBUG(0,("host name/address mismatch: %s != %s",
- inet_ntoa(addr), hp->h_name));
- return (Bad);
-}
+ if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
+ {
+ ret = True;
+ }
+ if (!ret)
+ {
+ /* bypass gethostbyaddr() calls if the lists only contain IP addrs */
+ if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list))
+ {
+ only_ip = True;
+ DEBUG (3, ("check_access: no hostnames in host allow/deny list.\n"));
+ ret = allow_access(deny_list,allow_list, "", get_socket_addr(sock));
+ }
+ else
+ {
+ DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
+ ret = allow_access(deny_list,allow_list, get_socket_name(sock),
+ get_socket_addr(sock));
+ }
+
+ if (ret)
+ {
+ DEBUG(2,("Allowed connection from %s (%s)\n",
+ only_ip ? "" : get_socket_name(sock),
+ get_socket_addr(sock)));
+ }
+ else
+ {
+ DEBUG(0,("Denied connection from %s (%s)\n",
+ only_ip ? "" : get_socket_name(sock),
+ get_socket_addr(sock)));
+ }
+ }
+ return(ret);
+}
diff --git a/source/lib/account_pol.c b/source/lib/account_pol.c
new file mode 100644
index 00000000000..74c8883ed13
--- /dev/null
+++ b/source/lib/account_pol.c
@@ -0,0 +1,136 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * account policy storage
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+static TDB_CONTEXT *tdb; /* used for driver files */
+
+#define DATABASE_VERSION 1
+
+/****************************************************************************
+open the account policy tdb
+****************************************************************************/
+BOOL init_account_policy(void)
+{
+ static pid_t local_pid;
+ char *vstring = "INFO/version";
+
+ if (tdb && local_pid == sys_getpid()) return True;
+ tdb = tdb_open_log(lock_path("account_policy.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb) {
+ DEBUG(0,("Failed to open account policy database\n"));
+ return False;
+ }
+
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb, vstring);
+ if (tdb_fetch_int(tdb, vstring) != DATABASE_VERSION) {
+ tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
+ tdb_store_int(tdb, vstring, DATABASE_VERSION);
+
+ account_policy_set(AP_MIN_PASSWORD_LEN, MINPASSWDLENGTH); /* 5 chars minimum */
+ account_policy_set(AP_PASSWORD_HISTORY, 0); /* don't keep any old password */
+ account_policy_set(AP_USER_MUST_LOGON_TO_CHG_PASS, 0); /* don't force user to logon */
+ account_policy_set(AP_MAX_PASSWORD_AGE, MAX_PASSWORD_AGE); /* 21 days */
+ account_policy_set(AP_MIN_PASSWORD_AGE, 0); /* 0 days */
+ account_policy_set(AP_LOCK_ACCOUNT_DURATION, 0); /* lockout for 0 minutes */
+ account_policy_set(AP_RESET_COUNT_TIME, 0); /* reset immediatly */
+ account_policy_set(AP_BAD_ATTEMPT_LOCKOUT, 0); /* don't lockout */
+ account_policy_set(AP_TIME_TO_LOGOUT, -1); /* don't force logout */
+ }
+ tdb_unlock_bystring(tdb, vstring);
+
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static char *decode_account_policy_name(int field)
+{
+ switch (field) {
+ case AP_MIN_PASSWORD_LEN:
+ return "min password length";
+ break;
+ case AP_PASSWORD_HISTORY:
+ return "password history";
+ break;
+ case AP_USER_MUST_LOGON_TO_CHG_PASS:
+ return "user must logon to change password";
+ break;
+ case AP_MAX_PASSWORD_AGE:
+ return "maximum password age";
+ break;
+ case AP_MIN_PASSWORD_AGE:
+ return "minimum password age";
+ break;
+ case AP_LOCK_ACCOUNT_DURATION:
+ return "lockout duration";
+ break;
+ case AP_RESET_COUNT_TIME:
+ return "reset count minutes";
+ break;
+ case AP_BAD_ATTEMPT_LOCKOUT:
+ return "bad lockout attempt";
+ break;
+ case AP_TIME_TO_LOGOUT:
+ return "disconnect time";
+ break;
+ default:
+ return "undefined value";
+ break;
+ }
+}
+
+
+/****************************************************************************
+****************************************************************************/
+BOOL account_policy_get(int field, int *value)
+{
+ fstring name;
+
+ init_account_policy();
+
+ fstrcpy(name, decode_account_policy_name(field));
+ *value=tdb_fetch_int(tdb, name);
+ DEBUG(10,("account_policy_get: %s:%d\n", name, *value));
+ return True;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+BOOL account_policy_set(int field, int value)
+{
+ fstring name;
+
+ init_account_policy();
+
+ fstrcpy(name, decode_account_policy_name(field));
+ if ( tdb_store_int(tdb, name, value)== -1)
+ return False;
+ DEBUG(10,("account_policy_set: %s:%d\n", name, value));
+
+ return True;
+}
+
diff --git a/source/lib/bitmap.c b/source/lib/bitmap.c
new file mode 100644
index 00000000000..da123837d0d
--- /dev/null
+++ b/source/lib/bitmap.c
@@ -0,0 +1,140 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ simple bitmap functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* these functions provide a simple way to allocate integers from a
+ pool without repetition */
+
+/****************************************************************************
+allocate a bitmap of the specified size
+****************************************************************************/
+struct bitmap *bitmap_allocate(int n)
+{
+ struct bitmap *bm;
+
+ bm = (struct bitmap *)malloc(sizeof(*bm));
+
+ if (!bm) return NULL;
+
+ bm->n = n;
+ bm->b = (uint32 *)malloc(sizeof(bm->b[0])*(n+31)/32);
+ if (!bm->b) {
+ SAFE_FREE(bm);
+ return NULL;
+ }
+
+ memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32);
+
+ return bm;
+}
+
+/****************************************************************************
+free a bitmap.
+****************************************************************************/
+
+void bitmap_free(struct bitmap *bm)
+{
+ if (!bm)
+ return;
+
+ SAFE_FREE(bm->b);
+ SAFE_FREE(bm);
+}
+
+/****************************************************************************
+set a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_set(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] |= (1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+clear a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_clear(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] &= ~(1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+query a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_query(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) return False;
+ if (bm->b[i/32] & (1<<(i%32))) {
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+find a zero bit in a bitmap starting at the specified offset, with
+wraparound
+****************************************************************************/
+int bitmap_find(struct bitmap *bm, unsigned ofs)
+{
+ int i, j;
+
+ if (ofs > bm->n) ofs = 0;
+
+ i = ofs;
+ while (i < bm->n) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ i = 0;
+ while (i < ofs) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ return -1;
+}
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index 049390f2a43..256bd7e88c7 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -1,8 +1,10 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
+ Version 3.0
Character set conversion Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,107 +22,547 @@
*/
#include "includes.h"
-extern int DEBUGLEVEL;
-static char cvtbuf[1024];
+static pstring cvtbuf;
-static mapsinited = 0;
+static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
-static char unix2dos[256];
-static char dos2unix[256];
+static int initialized;
-static void initmaps() {
- int k;
+/****************************************************************************
+return the name of a charset to give to iconv()
+****************************************************************************/
+static char *charset_name(charset_t ch)
+{
+ char *ret = NULL;
+
+ if (ch == CH_UCS2) ret = "UCS-2LE";
+ else if (ch == CH_UNIX) ret = lp_unix_charset();
+ else if (ch == CH_DOS) ret = lp_dos_charset();
+ else if (ch == CH_DISPLAY) ret = lp_display_charset();
+
+ if (!ret || !*ret) ret = "ASCII";
+ return ret;
+}
+
+/****************************************************************************
+ Initialize iconv conversion descriptors
+****************************************************************************/
+void init_iconv(void)
+{
+ int c1, c2;
+ BOOL did_reload = False;
+
+ /* so that charset_name() works we need to get the UNIX<->UCS2 going
+ first */
+ if (!conv_handles[CH_UNIX][CH_UCS2]) {
+ conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
+ }
+ if (!conv_handles[CH_UCS2][CH_UNIX]) {
+ conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
+ }
+
+
+ for (c1=0;c1<NUM_CHARSETS;c1++) {
+ for (c2=0;c2<NUM_CHARSETS;c2++) {
+ char *n1 = charset_name((charset_t)c1);
+ char *n2 = charset_name((charset_t)c2);
+ if (conv_handles[c1][c2] &&
+ strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
+ strcmp(n2, conv_handles[c1][c2]->to_name) == 0) continue;
+
+ did_reload = True;
+
+ if (conv_handles[c1][c2]) {
+ smb_iconv_close(conv_handles[c1][c2]);
+ }
+ conv_handles[c1][c2] = smb_iconv_open(n2,n1);
+ if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
+ DEBUG(0,("Conversion from %s to %s not supported\n",
+ charset_name((charset_t)c1), charset_name((charset_t)c2)));
+ conv_handles[c1][c2] = NULL;
+ }
+ }
+ }
+
+ if (did_reload) {
+ init_valid_table();
+ }
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ *
+ * @param descriptor conversion descriptor, created in init_iconv()
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @retval the number of bytes occupied in the destination
+ **/
+size_t convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen)
+{
+ size_t i_len, o_len;
+ size_t retval;
+ const char* inbuf = (const char*)src;
+ char* outbuf = (char*)dest;
+ smb_iconv_t descriptor;
+
+ if (srclen == -1) srclen = strlen(src)+1;
+
+ if (!initialized) {
+ initialized = 1;
+ load_case_tables();
+ init_iconv();
+ init_valid_table();
+ }
+
+ descriptor = conv_handles[from][to];
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ /* conversion not supported, use as is */
+ int len = MIN(srclen,destlen);
+ memcpy(dest,src,len);
+ return len;
+ }
+
+ i_len=srclen;
+ o_len=destlen;
+ retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
+ if(retval==-1)
+ {
+ char *reason="unknown error";
+ switch(errno)
+ { case EINVAL: reason="Incomplete multibyte sequence"; break;
+ case E2BIG: reason="No more room";
+ DEBUG(0, ("Required %d, available %d\n",
+ srclen, destlen));
+ /* we are not sure we need srclen bytes,
+ may be more, may be less.
+ We only know we need more than destlen
+ bytes ---simo */
+
+
+ break;
+ case EILSEQ: reason="Illegal myltibyte sequence"; break;
+ }
+ /* smb_panic(reason); */
+ }
+ return destlen-o_len;
+}
+
+/**
+ * Convert between character sets, allocating a new buffer for the result.
+ *
+ * @param srclen length of source buffer.
+ * @note -1 is not accepted for srclen.
+ *
+ * @retval Size in bytes of the converted string; or -1 in case of error.
+ **/
+size_t convert_string_allocate(charset_t from, charset_t to,
+ void const *src, size_t srclen, void **dest)
+{
+ size_t i_len, o_len, destlen;
+ size_t retval;
+ const char *inbuf = (const char *)src;
+ char *outbuf, *ob;
+ smb_iconv_t descriptor;
+
+ *dest = NULL;
+
+ if (src == NULL || srclen == -1) return -1;
+
+ if (!initialized) {
+ initialized = 1;
+ load_case_tables();
+ init_iconv();
+ }
+
+ descriptor = conv_handles[from][to];
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ /* conversion not supported, return -1*/
+ return -1;
+ }
+
+ destlen = MAX(srclen, 512);
+ outbuf = NULL;
+convert:
+ destlen = destlen * 2;
+ ob = (char *)realloc(outbuf, destlen);
+ if (!ob) {
+ DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
+ SAFE_FREE(outbuf);
+ return -1;
+ }
+ else outbuf = ob;
+ i_len = srclen;
+ o_len = destlen;
+ retval = smb_iconv(descriptor,
+ &inbuf, &i_len,
+ &outbuf, &o_len);
+ if(retval == -1)
+ {
+ char *reason="unknown error";
+ switch(errno)
+ {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ break;
+ case E2BIG:
+ goto convert;
+ break;
+ case EILSEQ:
+ reason="Illegal myltibyte sequence";
+ break;
+ }
+ DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
+ /* smb_panic(reason); */
+ return -1;
+ }
+
+ destlen = destlen - o_len;
+ *dest = (char *)Realloc(ob,destlen);
+ if (!*dest) {
+ DEBUG(0, ("convert_string_allocate: out of memory!\n"));
+ SAFE_FREE(ob);
+ return -1;
+ }
+
+ return destlen;
+}
+
+int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+ int size;
+ smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
+ size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
+ if (!strupper_w(buffer) && (dest == src)) return srclen;
+ return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+}
+
+int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+ int size;
+ smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
+ size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
+ if (!strlower_w(buffer) && (dest == src)) return srclen;
+ return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+}
+
+
+int ucs2_align(const void *base_ptr, const void *p, int flags)
+{
+ if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
+ return PTR_DIFF(p, base_ptr) & 1;
+}
+
+
+/****************************************************************************
+copy a string from a char* unix src to a dos codepage string destination
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_ascii(void *dest, const char *src, int dest_len, int flags)
+{
+ int src_len = strlen(src);
+ pstring tmpbuf;
+
+ /* treat a pstring as "unlimited" length */
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_UPPER) {
+ pstrcpy(tmpbuf, src);
+ strupper(tmpbuf);
+ src = tmpbuf;
+ }
+
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
+}
+
+int push_ascii_fstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
+}
- for (k = 0; k < 256; k++) unix2dos[k] = k;
- for (k = 0; k < 256; k++) dos2unix[k] = k;
+int push_ascii_pstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
+}
- mapsinited = 1;
+int push_pstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
-static void update_map(char * str) {
- char *p;
- for (p = str; *p; p++) {
- if (p[1]) {
- unix2dos[(unsigned char)*p] = p[1];
- dos2unix[(unsigned char)p[1]] = *p;
- p++;
- }
- }
+/****************************************************************************
+copy a string from a dos codepage source to a unix char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_ascii(char *dest, const void *src, int dest_len, int src_len, int flags)
+{
+ int ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_TERMINATE) src_len = strlen(src)+1;
+
+ ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
+
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return src_len;
}
-static void initiso() {
+int pull_ascii_pstring(char *dest, const void *src)
+{
+ return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
+}
- if (!mapsinited) initmaps();
+int pull_ascii_fstring(char *dest, const void *src)
+{
+ return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/****************************************************************************
+copy a string from a char* src to a unicode destination
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+ STR_NOALIGN means don't do alignment
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
+{
+ int len=0;
+ int src_len = strlen(src);
+ pstring tmpbuf;
+
+ /* treat a pstring as "unlimited" length */
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_UPPER) {
+ pstrcpy(tmpbuf, src);
+ strupper(tmpbuf);
+ src = tmpbuf;
+ }
- update_map("\241\255\242\233\243\234\244\236\245\235\246\272\247\025\250\251");
- update_map("\251\273\252\246\253\256\254\252\255\274\256\310\257\257\260\370");
- update_map("\261\361\262\375\263\264\264\265\265\266\266\024\267\371\270\267");
- update_map("\271\270\272\247\273\275\274\254\275\253\276\276\277\250\200\277");
- update_map("\301\300\302\301\303\302\304\216\305\217\306\222\307\200\310\303");
- update_map("\311\220\312\305\313\306\314\307\315\315\316\317\317\320\320\311");
- update_map("\321\245\322\321\323\322\324\323\325\324\326\231\327\312\330\325");
- update_map("\331\326\332\327\333\330\334\232\335\313\336\314\337\341\340\205");
- update_map("\341\240\342\203\343\331\344\204\345\206\346\221\347\207\350\212");
- update_map("\351\202\352\210\353\211\354\215\355\241\356\214\357\213\360\316");
- update_map("\361\244\362\225\363\242\364\223\365\332\366\224\367\366\370\362");
- update_map("\371\227\372\243\373\226\374\201\375\304\376\263\377\230");
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ if (ucs2_align(base_ptr, dest, flags)) {
+ *(char *)dest = 0;
+ dest = (void *)((char *)dest + 1);
+ if (dest_len) dest_len--;
+ len++;
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ dest_len &= ~1;
+
+ len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
+ return len;
}
-/*
- * Convert unix to dos
- */
-char *
-unix2dos_format(char *str,BOOL overwrite)
+
+/****************************************************************************
+copy a string from a ucs2 source to a unix char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+ STR_NOALIGN means don't try to align
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_ucs2(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
{
- char *p;
- char *dp;
+ int ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (ucs2_align(base_ptr, src, flags)) {
+ src = (const void *)((const char *)src + 1);
+ if (src_len > 0) src_len--;
+ }
- if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = unix2dos[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = unix2dos[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
- }
+ if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
+
+ /* ucs2 is always a multiple of 2 bytes */
+ src_len &= ~1;
+
+ ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+int pull_ucs2_pstring(char *dest, const void *src)
+{
+ return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
+}
+
+int pull_ucs2_fstring(char *dest, const void *src)
+{
+ return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+
+/****************************************************************************
+copy a string from a char* src to a unicode or ascii
+dos codepage destination choosing unicode or ascii based on the
+flags in the SMB buffer starting at base_ptr
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+ STR_ASCII use ascii even with unicode packet
+ STR_NOALIGN means don't do alignment
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_string(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return push_ucs2(base_ptr, dest, src, dest_len, flags);
+ }
+ return push_ascii(dest, src, dest_len, flags);
}
-/*
- * Convert dos to unix
- */
-char *
-dos2unix_format (char *str, BOOL overwrite)
+
+/****************************************************************************
+copy a string from a unicode or ascii source (depending on
+the packet flags) to a char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+ STR_UNICODE means to force as unicode
+ STR_ASCII use ascii even with unicode packet
+ STR_NOALIGN means don't do alignment
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_string(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
+ }
+ return pull_ascii(dest, src, dest_len, src_len, flags);
+}
+
+int align_string(const void *base_ptr, const char *p, int flags)
{
- char *p;
- char *dp;
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return ucs2_align(base_ptr, p, flags);
+ }
+ return 0;
+}
+
- if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = dos2unix[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = dos2unix[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
- }
+
+/****************************************************************************
+convert from ucs2 to unix charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+char *acnv_u2ux(const smb_ucs2_t *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
+ dlen = convert_string_allocate(CH_UCS2, CH_UNIX, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
}
+/****************************************************************************
+convert from unix to ucs2 charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+smb_ucs2_t *acnv_uxu2(const char *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = strlen(src) + 1;
+ dlen = convert_string_allocate(CH_UNIX, CH_UCS2, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
+}
-/*
- * Interpret character set.
- */
-int
-interpret_character_set (char *str, int def)
+/****************************************************************************
+convert from ucs2 to dos charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+char *acnv_u2dos(const smb_ucs2_t *src)
{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
+ dlen = convert_string_allocate(CH_UCS2, CH_DOS, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
+}
- if (strequal (str, "iso8859-1")) {
- initiso();
- return def;
- } else {
- DEBUG(0,("unrecognized character set\n"));
- }
- return def;
+/****************************************************************************
+convert from dos to ucs2 charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+smb_ucs2_t *acnv_dosu2(const char *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = strlen(src) + 1;
+ dlen = convert_string_allocate(CH_DOS, CH_UCS2, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
}
diff --git a/source/lib/charset.c b/source/lib/charset.c
deleted file mode 100644
index ada3ef790aa..00000000000
--- a/source/lib/charset.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Character set handling
- Copyright (C) Andrew Tridgell 1992-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define CHARSET_C
-#include "includes.h"
-
-extern int DEBUGLEVEL;
-
-char xx_dos_char_map[256];
-char xx_upper_char_map[256];
-char xx_lower_char_map[256];
-
-char *dos_char_map = NULL;
-char *upper_char_map = NULL;
-char *lower_char_map = NULL;
-
-static void add_dos_char(int lower, int upper)
-{
- DEBUG(6,("Adding chars 0%o 0%o\n",lower,upper));
- if (lower) dos_char_map[(char)lower] = 1;
- if (upper) dos_char_map[(char)upper] = 1;
- if (lower && upper) {
- lower_char_map[(char)upper] = (char)lower;
- upper_char_map[(char)lower] = (char)upper;
- }
-}
-
-/****************************************************************************
-initialise the charset arrays
-****************************************************************************/
-void charset_initialise(void)
-{
- int i;
-
- dos_char_map = &xx_dos_char_map[128];
- upper_char_map = &xx_upper_char_map[128];
- lower_char_map = &xx_lower_char_map[128];
-
- for (i= -128;i<=127;i++) {
- dos_char_map[(char)i] = 0;
- }
-
- for (i=0;i<=127;i++) {
- if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i))
- add_dos_char(i,0);
- }
-
- for (i= -128;i<=127;i++) {
- char c = (char)i;
- upper_char_map[i] = lower_char_map[i] = c;
- if (isupper(c)) lower_char_map[c] = tolower(c);
- if (islower(c)) upper_char_map[c] = toupper(c);
- }
-
- /* valid for all DOS PC */
- add_dos_char(142,0); /* A trema */
- add_dos_char(143,0); /* A o */
- add_dos_char(144,0); /* E ' */
- add_dos_char(146,0); /* AE */
- add_dos_char(153,0); /* O trema */
- add_dos_char(154,0); /* U trema */
- add_dos_char(165,0); /* N tilda */
- add_dos_char(128,0); /* C cedille */
- add_dos_char(156,0); /* Pound */
- add_dos_char(183,0); /* A ` (WIN)*/
- add_dos_char(157,0); /* Phi (WIN)*/
- add_dos_char(212,0); /* E` (WIN)*/
-}
-
-
-/*******************************************************************
-add characters depending on a string passed by the user
-********************************************************************/
-void add_char_string(char *s)
-{
- char *extra_chars = (char *)strdup(s);
- char *t;
- if (!extra_chars) return;
-
- for (t=strtok(extra_chars," \t\r\n"); t; t=strtok(NULL," \t\r\n")) {
- char c1=0,c2=0;
- int i1=0,i2=0;
- if (isdigit(*t) || (*t)=='-') {
- sscanf(t,"%i:%i",&i1,&i2);
- add_dos_char(i1,i2);
- } else {
- sscanf(t,"%c:%c",&c1,&c2);
- add_dos_char(c1,c2);
- }
- }
-
- free(extra_chars);
-}
diff --git a/source/lib/crc32.c b/source/lib/crc32.c
new file mode 100644
index 00000000000..e026fbf8615
--- /dev/null
+++ b/source/lib/crc32.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright Francesco Ferrara, 1998 <francesco@aerra.it>
+ *
+ * Used by kind permission, 14th October 1998. http://www.aerre.it/francesco
+ *
+ *
+ */
+
+#include "includes.h"
+
+static unsigned long CRCTable[256] =
+{
+ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,
+ 0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,
+ 0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,
+ 0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
+ 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,
+ 0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,
+ 0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
+ 0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+ 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,
+ 0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,
+ 0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,0x76DC4190,0x01DB7106,
+ 0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
+ 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,
+ 0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
+ 0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,
+ 0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+ 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,
+ 0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,
+ 0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,0x5005713C,0x270241AA,
+ 0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
+ 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
+ 0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,
+ 0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,
+ 0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+ 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,
+ 0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,
+ 0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,0xA1D1937E,
+ 0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
+ 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,
+ 0x316E8EEF,0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,
+ 0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,
+ 0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+ 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,
+ 0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,
+ 0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
+ 0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
+ 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,
+ 0x616BFFD3,0x166CCF45,0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,
+ 0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,
+ 0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+ 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,
+ 0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
+ 0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
+};
+
+uint32 crc32_calc_buffer( char *buffer, uint32 count)
+{
+ uint32 crc=0xffffffff;
+ int i;
+ for(i=0;i<count;i++)
+ crc = (crc>>8) ^ CRCTable[(buffer[i] ^ crc) & 0xff];
+ crc^=0xffffffff;
+ DEBUG(10,("crc32_calc_buffer: %x\n", crc));
+ dump_data(100, buffer, count);
+ return crc;
+}
diff --git a/source/lib/debug.c b/source/lib/debug.c
new file mode 100644
index 00000000000..a77328e3432
--- /dev/null
+++ b/source/lib/debug.c
@@ -0,0 +1,769 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ *
+ * FORMAT_BUFR_MAX - Index of the last byte of the format buffer;
+ * format_bufr[FORMAT_BUFR_MAX] should always be reserved
+ * for a terminating null byte.
+ */
+
+#define FORMAT_BUFR_MAX ( sizeof( format_bufr ) - 1 )
+
+/* -------------------------------------------------------------------------- **
+ * This module implements Samba's debugging utility.
+ *
+ * The syntax of a debugging log file is represented as:
+ *
+ * <debugfile> :== { <debugmsg> }
+ *
+ * <debugmsg> :== <debughdr> '\n' <debugtext>
+ *
+ * <debughdr> :== '[' TIME ',' LEVEL ']' [ [FILENAME ':'] [FUNCTION '()'] ]
+ *
+ * <debugtext> :== { <debugline> }
+ *
+ * <debugline> :== TEXT '\n'
+ *
+ * TEXT is a string of characters excluding the newline character.
+ * LEVEL is the DEBUG level of the message (an integer in the range 0..10).
+ * TIME is a timestamp.
+ * FILENAME is the name of the file from which the debug message was generated.
+ * FUNCTION is the function from which the debug message was generated.
+ *
+ * Basically, what that all means is:
+ *
+ * - A debugging log file is made up of debug messages.
+ *
+ * - Each debug message is made up of a header and text. The header is
+ * separated from the text by a newline.
+ *
+ * - The header begins with the timestamp and debug level of the message
+ * enclosed in brackets. The filename and function from which the
+ * message was generated may follow. The filename is terminated by a
+ * colon, and the function name is terminated by parenthesis.
+ *
+ * - The message text is made up of zero or more lines, each terminated by
+ * a newline.
+ */
+
+/* -------------------------------------------------------------------------- **
+ * External variables.
+ *
+ * dbf - Global debug file handle.
+ * debugf - Debug file name.
+ * append_log - If True, then the output file will be opened in append
+ * mode.
+ * DEBUGLEVEL - System-wide debug message limit. Messages with message-
+ * levels higher than DEBUGLEVEL will not be processed.
+ */
+
+XFILE *dbf = NULL;
+pstring debugf = "";
+BOOL append_log = False;
+
+int DEBUGLEVEL_CLASS[DBGC_LAST];
+BOOL DEBUGLEVEL_CLASS_ISSET[DBGC_LAST];
+int DEBUGLEVEL = DEBUGLEVEL_CLASS;
+
+
+/* -------------------------------------------------------------------------- **
+ * Internal variables.
+ *
+ * stdout_logging - Default False, if set to True then dbf will be set to
+ * stdout and debug output will go to dbf only, and not
+ * to syslog. Set in setup_logging() and read in Debug1().
+ *
+ * debug_count - Number of debug messages that have been output.
+ * Used to check log size.
+ *
+ * syslog_level - Internal copy of the message debug level. Written by
+ * dbghdr() and read by Debug1().
+ *
+ * format_bufr - Used to format debug messages. The dbgtext() function
+ * prints debug messages to a string, and then passes the
+ * string to format_debug_text(), which uses format_bufr
+ * to build the formatted output.
+ *
+ * format_pos - Marks the first free byte of the format_bufr.
+ *
+ *
+ * log_overflow - When this variable is True, never attempt to check the
+ * size of the log. This is a hack, so that we can write
+ * a message using DEBUG, from open_logs() when we
+ * are unable to open a new log file for some reason.
+ */
+
+static BOOL stdout_logging = False;
+static int debug_count = 0;
+#ifdef WITH_SYSLOG
+static int syslog_level = 0;
+#endif
+static pstring format_bufr = { '\0' };
+static size_t format_pos = 0;
+static BOOL log_overflow = False;
+
+/*
+ * Define all the debug class selection names here. Names *MUST NOT* contain
+ * white space. There must be one name for each DBGC_<class name>, and they
+ * must be in the table in the order of DBGC_<class name>..
+ */
+char *classname_table[] = {
+ "all", /* DBGC_ALL; index refs traditional DEBUGLEVEL */
+ "tdb", /* DBGC_TDB */
+ "printdrivers", /* DBGC_PRINTDRIVERS */
+ "lanman", /* DBGC_LANMAN */
+ "smb", /* DBGC_SMB */
+ "rpc", /* DBGC_RPC */
+ "rpc_hdr", /* DBGC_RPC_HDR */
+ "bdc", /* DBGC_BDC */
+};
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+/****************************************************************************
+utility access to debug class names's
+****************************************************************************/
+char* debug_classname_from_index(int ndx)
+{
+ return classname_table[ndx];
+}
+
+/****************************************************************************
+utility to translate names to debug class index's
+****************************************************************************/
+int debug_lookup_classname(char* classname)
+{
+ int i;
+
+ if (!classname) return -1;
+
+ for (i=0; i<DBGC_LAST; i++) {
+ if (strcmp(classname, classname_table[i])==0)
+ return i;
+ }
+ return -1;
+}
+
+/****************************************************************************
+parse the debug levels from smbcontrol. Example debug level parameter:
+ printdrivers:7
+****************************************************************************/
+BOOL debug_parse_params(char **params, int *debuglevel_class,
+ BOOL *debuglevel_class_isset)
+{
+ int i, ndx;
+ char *class_name;
+ char *class_level;
+
+ /* Set the new debug level array to the current DEBUGLEVEL array */
+ memcpy(debuglevel_class, DEBUGLEVEL_CLASS, sizeof(DEBUGLEVEL_CLASS));
+
+ /* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
+ * v.s. "all:10", this is the traditional way to set DEBUGLEVEL
+ */
+ if (isdigit((int)params[0][0])) {
+ debuglevel_class[DBGC_ALL] = atoi(params[0]);
+ debuglevel_class_isset[DBGC_ALL] = True;
+ i = 1; /* start processing at the next params */
+ }
+ else
+ i = 0; /* DBGC_ALL not specified OR class name was included */
+
+ /* Fill in new debug class levels */
+ for (; i < DBGC_LAST && params[i]; i++) {
+ if ((class_name=strtok(params[i],":")) &&
+ (class_level=strtok(NULL, "\0")) &&
+ ((ndx = debug_lookup_classname(class_name)) != -1)) {
+ debuglevel_class[ndx] = atoi(class_level);
+ debuglevel_class_isset[ndx] = True;
+ } else {
+ DEBUG(0,("debug_parse_params: unrecognized debug class name or format [%s]\n", params[i]));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+parse the debug levels from smb.conf. Example debug level string:
+ 3 tdb:5 printdrivers:7
+Note: the 1st param has no "name:" preceeding it.
+****************************************************************************/
+BOOL debug_parse_levels(char *params_str)
+{
+ int i;
+ char *params[DBGC_LAST];
+ int debuglevel_class[DBGC_LAST];
+ BOOL debuglevel_class_isset[DBGC_LAST];
+
+ ZERO_ARRAY(params);
+ ZERO_ARRAY(debuglevel_class);
+ ZERO_ARRAY(debuglevel_class_isset);
+
+ if ((params[0]=strtok(params_str," ,"))) {
+ for (i=1; i<DBGC_LAST;i++) {
+ if ((params[i]=strtok(NULL," ,"))==NULL)
+ break;
+ }
+ }
+ else
+ return False;
+
+ if (debug_parse_params(params, debuglevel_class,
+ debuglevel_class_isset)) {
+ debug_message(0, getpid(), (void*)debuglevel_class, sizeof(debuglevel_class));
+
+ memcpy(DEBUGLEVEL_CLASS, debuglevel_class,
+ sizeof(debuglevel_class));
+
+ memcpy(DEBUGLEVEL_CLASS_ISSET, debuglevel_class_isset,
+ sizeof(debuglevel_class_isset));
+
+ {
+ int q;
+
+ for (q = 0; q < DBGC_LAST; q++)
+ DEBUG(5, ("%s: %d/%d\n",
+ classname_table[q],
+ DEBUGLEVEL_CLASS[q],
+ DEBUGLEVEL_CLASS_ISSET[q]));
+ }
+
+ return True;
+ } else
+ return False;
+}
+
+/****************************************************************************
+receive a "set debug level" message
+****************************************************************************/
+void debug_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ struct debuglevel_message *dm = (struct debuglevel_message *)buf;
+ int i;
+
+ /* Set the new DEBUGLEVEL_CLASS array from the passed message */
+ memcpy(DEBUGLEVEL_CLASS, dm->debuglevel_class, sizeof(dm->debuglevel_class));
+ memcpy(DEBUGLEVEL_CLASS_ISSET, dm->debuglevel_class_isset, sizeof(dm->debuglevel_class_isset));
+
+ DEBUG(3,("INFO: Debug class %s level = %d (pid %u from pid %u)\n",
+ classname_table[DBGC_ALL],
+ DEBUGLEVEL_CLASS[DBGC_ALL], (unsigned int)getpid(), (unsigned int)src));
+
+ for (i=1; i<DBGC_LAST; i++) {
+ if (DEBUGLEVEL_CLASS[i])
+ DEBUGADD(3,("INFO: Debug class %s level = %d\n",
+ classname_table[i], DEBUGLEVEL_CLASS[i]));
+ }
+}
+
+
+/****************************************************************************
+send a "set debug level" message
+****************************************************************************/
+void debug_message_send(pid_t pid, int level)
+{
+ message_send_pid(pid, MSG_DEBUG, &level, sizeof(int), False);
+}
+
+
+/* ************************************************************************** **
+ * get ready for syslog stuff
+ * ************************************************************************** **
+ */
+void setup_logging(char *pname, BOOL interactive)
+{
+ message_register(MSG_DEBUG, debug_message);
+
+ /* reset to allow multiple setup calls, going from interactive to
+ non-interactive */
+ stdout_logging = False;
+ dbf = NULL;
+
+ if (interactive) {
+ stdout_logging = True;
+ dbf = x_stdout;
+ }
+#ifdef WITH_SYSLOG
+ else {
+ char *p = strrchr_m( pname,'/' );
+ if (p)
+ pname = p + 1;
+#ifdef LOG_DAEMON
+ openlog( pname, LOG_PID, SYSLOG_FACILITY );
+#else
+ /* for old systems that have no facility codes. */
+ openlog( pname, LOG_PID );
+#endif
+ }
+#endif
+} /* setup_logging */
+
+/* ************************************************************************** **
+ * reopen the log files
+ * note that we now do this unconditionally
+ * We attempt to open the new debug fp before closing the old. This means
+ * if we run out of fd's we just keep using the old fd rather than aborting.
+ * Fix from dgibson@linuxcare.com.
+ * ************************************************************************** **
+ */
+
+BOOL reopen_logs( void )
+{
+ pstring fname;
+ mode_t oldumask;
+ XFILE *new_dbf = NULL;
+ BOOL ret = True;
+
+ if (stdout_logging)
+ return True;
+
+ oldumask = umask( 022 );
+
+ pstrcpy(fname, debugf );
+
+ if (lp_loaded()) {
+ char *logfname;
+
+ logfname = lp_logfile();
+ if (*logfname)
+ pstrcpy(fname, logfname);
+ }
+
+ pstrcpy( debugf, fname );
+ if (append_log)
+ new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
+ else
+ new_dbf = x_fopen( debugf, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+
+ if (!new_dbf) {
+ log_overflow = True;
+ DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
+ log_overflow = False;
+ if (dbf)
+ x_fflush(dbf);
+ ret = False;
+ } else {
+ x_setbuf(new_dbf, NULL);
+ if (dbf)
+ (void) x_fclose(dbf);
+ dbf = new_dbf;
+ }
+
+ /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
+ * to fix problem where smbd's that generate less
+ * than 100 messages keep growing the log.
+ */
+ force_check_log_size();
+ (void)umask(oldumask);
+
+ return ret;
+}
+
+/* ************************************************************************** **
+ * Force a check of the log size.
+ * ************************************************************************** **
+ */
+void force_check_log_size( void )
+{
+ debug_count = 100;
+}
+
+/***************************************************************************
+ Check to see if there is any need to check if the logfile has grown too big.
+**************************************************************************/
+
+BOOL need_to_check_log_size( void )
+{
+ int maxlog;
+
+ if( debug_count++ < 100 )
+ return( False );
+
+ maxlog = lp_max_log_size() * 1024;
+ if( !dbf || maxlog <= 0 ) {
+ debug_count = 0;
+ return(False);
+ }
+ return( True );
+}
+
+/* ************************************************************************** **
+ * Check to see if the log has grown to be too big.
+ * ************************************************************************** **
+ */
+
+void check_log_size( void )
+{
+ int maxlog;
+ SMB_STRUCT_STAT st;
+
+ /*
+ * We need to be root to check/change log-file, skip this and let the main
+ * loop check do a new check as root.
+ */
+
+ if( geteuid() != 0 )
+ return;
+
+ if(log_overflow || !need_to_check_log_size() )
+ return;
+
+ maxlog = lp_max_log_size() * 1024;
+
+ if( sys_fstat( x_fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) {
+ (void)reopen_logs();
+ if( dbf && get_file_size( debugf ) > maxlog ) {
+ pstring name;
+
+ slprintf( name, sizeof(name)-1, "%s.old", debugf );
+ (void)rename( debugf, name );
+
+ if (!reopen_logs()) {
+ /* We failed to reopen a log - continue using the old name. */
+ (void)rename(name, debugf);
+ }
+ }
+ }
+
+ /*
+ * Here's where we need to panic if dbf == NULL..
+ */
+
+ if(dbf == NULL) {
+ /* This code should only be reached in very strange
+ * circumstances. If we merely fail to open the new log we
+ * should stick with the old one. ergo this should only be
+ * reached when opening the logs for the first time: at
+ * startup or when the log level is increased from zero.
+ * -dwg 6 June 2000
+ */
+ dbf = x_fopen( "/dev/console", O_WRONLY, 0);
+ if(dbf) {
+ DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
+ debugf ));
+ } else {
+ /*
+ * We cannot continue without a debug file handle.
+ */
+ abort();
+ }
+ }
+ debug_count = 0;
+} /* check_log_size */
+
+/* ************************************************************************** **
+ * Write an debug message on the debugfile.
+ * This is called by dbghdr() and format_debug_text().
+ * ************************************************************************** **
+ */
+ int Debug1( char *format_str, ... )
+{
+ va_list ap;
+ int old_errno = errno;
+
+ if( stdout_logging )
+ {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ errno = old_errno;
+ return( 0 );
+ }
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ if( !dbf )
+ {
+ mode_t oldumask = umask( 022 );
+
+ if( append_log )
+ dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
+ else
+ dbf = x_fopen( debugf, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+ (void)umask( oldumask );
+ if( dbf )
+ {
+ x_setbuf( dbf, NULL );
+ }
+ else
+ {
+ errno = old_errno;
+ return(0);
+ }
+ }
+ }
+
+#ifdef WITH_SYSLOG
+ if( syslog_level < lp_syslog() )
+ {
+ /* map debug levels to syslog() priorities
+ * note that not all DEBUG(0, ...) calls are
+ * necessarily errors
+ */
+ static int priority_map[] = {
+ LOG_ERR, /* 0 */
+ LOG_WARNING, /* 1 */
+ LOG_NOTICE, /* 2 */
+ LOG_INFO, /* 3 */
+ };
+ int priority;
+ pstring msgbuf;
+
+ if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) )
+ || syslog_level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[syslog_level];
+
+ va_start( ap, format_str );
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ msgbuf[255] = '\0';
+ syslog( priority, "%s", msgbuf );
+ }
+#endif
+
+ check_log_size();
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ if(dbf)
+ (void)x_fflush( dbf );
+ }
+
+ errno = old_errno;
+
+ return( 0 );
+ } /* Debug1 */
+
+
+/* ************************************************************************** **
+ * Print the buffer content via Debug1(), then reset the buffer.
+ *
+ * Input: none
+ * Output: none
+ *
+ * ************************************************************************** **
+ */
+static void bufr_print( void )
+ {
+ format_bufr[format_pos] = '\0';
+ (void)Debug1( "%s", format_bufr );
+ format_pos = 0;
+ } /* bufr_print */
+
+/* ************************************************************************** **
+ * Format the debug message text.
+ *
+ * Input: msg - Text to be added to the "current" debug message text.
+ *
+ * Output: none.
+ *
+ * Notes: The purpose of this is two-fold. First, each call to syslog()
+ * (used by Debug1(), see above) generates a new line of syslog
+ * output. This is fixed by storing the partial lines until the
+ * newline character is encountered. Second, printing the debug
+ * message lines when a newline is encountered allows us to add
+ * spaces, thus indenting the body of the message and making it
+ * more readable.
+ *
+ * ************************************************************************** **
+ */
+static void format_debug_text( char *msg )
+ {
+ size_t i;
+ BOOL timestamp = (!stdout_logging && (lp_timestamp_logs() ||
+ !(lp_loaded())));
+
+ for( i = 0; msg[i]; i++ )
+ {
+ /* Indent two spaces at each new line. */
+ if(timestamp && 0 == format_pos)
+ {
+ format_bufr[0] = format_bufr[1] = ' ';
+ format_pos = 2;
+ }
+
+ /* If there's room, copy the character to the format buffer. */
+ if( format_pos < FORMAT_BUFR_MAX )
+ format_bufr[format_pos++] = msg[i];
+
+ /* If a newline is encountered, print & restart. */
+ if( '\n' == msg[i] )
+ bufr_print();
+
+ /* If the buffer is full dump it out, reset it, and put out a line
+ * continuation indicator.
+ */
+ if( format_pos >= FORMAT_BUFR_MAX )
+ {
+ bufr_print();
+ (void)Debug1( " +>\n" );
+ }
+ }
+
+ /* Just to be safe... */
+ format_bufr[format_pos] = '\0';
+ } /* format_debug_text */
+
+/* ************************************************************************** **
+ * Flush debug output, including the format buffer content.
+ *
+ * Input: none
+ * Output: none
+ *
+ * ************************************************************************** **
+ */
+void dbgflush( void )
+ {
+ bufr_print();
+ if(dbf)
+ (void)x_fflush( dbf );
+ } /* dbgflush */
+
+/* ************************************************************************** **
+ * Print a Debug Header.
+ *
+ * Input: level - Debug level of the message (not the system-wide debug
+ * level. )
+ * file - Pointer to a string containing the name of the file
+ * from which this function was called, or an empty string
+ * if the __FILE__ macro is not implemented.
+ * func - Pointer to a string containing the name of the function
+ * from which this function was called, or an empty string
+ * if the __FUNCTION__ macro is not implemented.
+ * line - line number of the call to dbghdr, assuming __LINE__
+ * works.
+ *
+ * Output: Always True. This makes it easy to fudge a call to dbghdr()
+ * in a macro, since the function can be called as part of a test.
+ * Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
+ *
+ * Notes: This function takes care of setting syslog_level.
+ *
+ * ************************************************************************** **
+ */
+
+BOOL dbghdr( int level, char *file, char *func, int line )
+{
+ /* Ensure we don't lose any real errno value. */
+ int old_errno = errno;
+
+ if( format_pos ) {
+ /* This is a fudge. If there is stuff sitting in the format_bufr, then
+ * the *right* thing to do is to call
+ * format_debug_text( "\n" );
+ * to write the remainder, and then proceed with the new header.
+ * Unfortunately, there are several places in the code at which
+ * the DEBUG() macro is used to build partial lines. That in mind,
+ * we'll work under the assumption that an incomplete line indicates
+ * that a new header is *not* desired.
+ */
+ return( True );
+ }
+
+#ifdef WITH_SYSLOG
+ /* Set syslog_level. */
+ syslog_level = level;
+#endif
+
+ /* Don't print a header if we're logging to stdout. */
+ if( stdout_logging )
+ return( True );
+
+ /* Print the header if timestamps are turned on. If parameters are
+ * not yet loaded, then default to timestamps on.
+ */
+ if( lp_timestamp_logs() || !(lp_loaded()) ) {
+ char header_str[200];
+
+ header_str[0] = '\0';
+
+ if( lp_debug_pid())
+ slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)sys_getpid());
+
+ if( lp_debug_uid()) {
+ size_t hs_len = strlen(header_str);
+ slprintf(header_str + hs_len,
+ sizeof(header_str) - 1 - hs_len,
+ ", effective(%u, %u), real(%u, %u)",
+ (unsigned int)geteuid(), (unsigned int)getegid(),
+ (unsigned int)getuid(), (unsigned int)getgid());
+ }
+
+ /* Print it all out at once to prevent split syslog output. */
+ (void)Debug1( "[%s, %d%s] %s:%s(%d)\n",
+ timestring(lp_debug_hires_timestamp()), level,
+ header_str, file, func, line );
+ }
+
+ errno = old_errno;
+ return( True );
+}
+
+/* ************************************************************************** **
+ * Add text to the body of the "current" debug message via the format buffer.
+ *
+ * Input: format_str - Format string, as used in printf(), et. al.
+ * ... - Variable argument list.
+ *
+ * ..or.. va_alist - Old style variable parameter list starting point.
+ *
+ * Output: Always True. See dbghdr() for more info, though this is not
+ * likely to be used in the same way.
+ *
+ * ************************************************************************** **
+ */
+ BOOL dbgtext( char *format_str, ... )
+ {
+ va_list ap;
+ pstring msgbuf;
+
+ va_start( ap, format_str );
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ format_debug_text( msgbuf );
+
+ return( True );
+ } /* dbgtext */
+
+
+/* ************************************************************************** */
diff --git a/source/lib/dprintf.c b/source/lib/dprintf.c
new file mode 100644
index 00000000000..11c9f23e9d7
--- /dev/null
+++ b/source/lib/dprintf.c
@@ -0,0 +1,111 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ display print functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/*
+ this module provides functions for printing internal strings in the "display charset"
+ This charset may be quite different from the chosen unix charset
+
+ Eventually these functions will need to take care of column count constraints
+
+ The d_ prefix on print functions in Samba refers to the display character set
+ conversion
+*/
+
+#include "includes.h"
+
+int d_vfprintf(FILE *f, const char *format, va_list ap)
+{
+ char *p, *p2;
+ int ret, maxlen, clen;
+ const char *msgstr;
+
+ /* do any message translations */
+ msgstr = lang_msg(format);
+ if (!msgstr) return -1;
+
+ ret = vasprintf(&p, msgstr, ap);
+
+ lang_msg_free(msgstr);
+
+ if (ret <= 0) return ret;
+
+ /* now we have the string in unix format, convert it to the display
+ charset, but beware of it growing */
+ maxlen = ret*2;
+again:
+ p2 = malloc(maxlen);
+ if (!p2) {
+ SAFE_FREE(p);
+ return -1;
+ }
+ clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
+
+ if (clen >= maxlen) {
+ /* it didn't fit - try a larger buffer */
+ maxlen *= 2;
+ SAFE_FREE(p2);
+ goto again;
+ }
+
+ /* good, its converted OK */
+ SAFE_FREE(p);
+ ret = fwrite(p2, 1, clen, f);
+ SAFE_FREE(p2);
+
+ return ret;
+}
+
+
+ int d_fprintf(FILE *f, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = d_vfprintf(f, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static FILE *outfile;
+
+ int d_printf(const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!outfile) outfile = stdout;
+
+ va_start(ap, format);
+ ret = d_vfprintf(outfile, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* interactive programs need a way of tell d_*() to write to stderr instead
+ of stdout */
+void display_set_stderr(void)
+{
+ outfile = stderr;
+}
diff --git a/source/lib/error.c b/source/lib/error.c
new file mode 100644
index 00000000000..cb2fffb9629
--- /dev/null
+++ b/source/lib/error.c
@@ -0,0 +1,75 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9
+ * Unix/DOS/NT error code conversions
+ * Copyright (C) Tim Potter 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/* Mapping between Unix, DOS and NT error numbers */
+
+struct {
+ int unix_error;
+ int dos_error;
+ NTSTATUS nt_error;
+} unix_dos_nt_errmap[] = {
+ { EPERM, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { EACCES, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
+ { ENOTDIR, ERRbadpath, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EEXIST, ERRfilexists, NT_STATUS_ACCESS_DENIED},
+ { ENFILE, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, ERRdiskfull, NT_STATUS_DISK_FULL },
+#ifdef EDQUOT
+ { EDQUOT, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, ERRnoaccess, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+ { EROFS, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+
+ { 0, 0, NT_STATUS_OK }
+};
+
+/* Map an NT error code from a Unix error code */
+NTSTATUS map_nt_error_from_unix(int unix_error)
+{
+ int i = 0;
+
+ if (unix_error == 0) return NT_STATUS_OK;
+
+ /* Look through list */
+ while(unix_dos_nt_errmap[i].unix_error != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == unix_error) {
+ return unix_dos_nt_errmap[i].nt_error;
+ }
+
+ i++;
+ }
+
+ /* Default return */
+
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/source/lib/fault.c b/source/lib/fault.c
index 20c75f7876c..885e35e0233 100644
--- a/source/lib/fault.c
+++ b/source/lib/fault.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Critical Fault handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,44 +19,39 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifdef LINUX
-#define __KERNEL__
-#endif
-
#include "includes.h"
-extern int DEBUGLEVEL;
-
-
-static void (*cont_fn)();
+static void (*cont_fn)(void *);
/*******************************************************************
report a fault
********************************************************************/
static void fault_report(int sig)
{
- DEBUG(0,("===============================================================\n"));
- DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION));
- DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
- DEBUG(0,("===============================================================\n"));
+ static int counter;
+
+ if (counter) _exit(1);
+
+ counter++;
+
+ DEBUG(0,("===============================================================\n"));
+ DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),VERSION));
+ DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
+ DEBUG(0,("===============================================================\n"));
-#if AJT
- ajt_panic();
-#endif
+ smb_panic("internal error");
- if (cont_fn)
- {
- fault_setup(cont_fn);
- cont_fn(NULL);
+ if (cont_fn) {
+ cont_fn(NULL);
#ifdef SIGSEGV
- signal(SIGSEGV,SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
#endif
#ifdef SIGBUS
- signal(SIGBUS,SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
#endif
- return; /* this should cause a core dump */
- }
- exit(1);
+ return; /* this should cause a core dump */
+ }
+ exit(1);
}
/****************************************************************************
@@ -64,21 +59,21 @@ catch serious errors
****************************************************************************/
static void sig_fault(int sig)
{
- fault_report(sig);
+ fault_report(sig);
}
/*******************************************************************
setup our fault handlers
********************************************************************/
-void fault_setup(void (*fn)())
+void fault_setup(void (*fn)(void *))
{
- cont_fn = fn;
+ cont_fn = fn;
#ifdef SIGSEGV
- signal(SIGSEGV,SIGNAL_CAST sig_fault);
+ CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
#endif
#ifdef SIGBUS
- signal(SIGBUS,SIGNAL_CAST sig_fault);
+ CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
#endif
}
diff --git a/source/lib/fsusage.c b/source/lib/fsusage.c
new file mode 100644
index 00000000000..1bff1f953e0
--- /dev/null
+++ b/source/lib/fsusage.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+*/
+static SMB_BIG_UINT adjust_blocks(SMB_BIG_UINT blocks, SMB_BIG_UINT fromsize, SMB_BIG_UINT tosize)
+{
+ if (fromsize == tosize) /* e.g., from 512 to 512 */
+ return blocks;
+ else if (fromsize > tosize) /* e.g., from 2048 to 512 */
+ return blocks * (fromsize / tosize);
+ else /* e.g., from 256 to 512 */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+/* this does all of the system specific guff to get the free disk space.
+ It is derived from code in the GNU fileutils package, but has been
+ considerably mangled for use here
+
+ results are returned in *dfree and *dsize, in 512 byte units
+*/
+int sys_fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+#ifdef STAT_STATFS3_OSF1
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)1024, (SMB_BIG_UINT)512)
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+
+ (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
+ (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+
+#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+ /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+ struct statfs are truncated to 2GB. These conditions detect that
+ truncation, presumably without botching the 4.1.1 case, in which
+ the values are not truncated. The correct counts are stored in
+ undocumented spare fields. */
+ if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
+ fsd.f_blocks = fsd.f_spare[0];
+ fsd.f_bfree = fsd.f_spare[1];
+ fsd.f_bavail = fsd.f_spare[2];
+ }
+#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+#endif /* STAT_STATFS2_BSIZE */
+
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+# define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+# ifdef _CRAY
+# define f_bavail f_bfree
+# endif
+# else
+# define CONVERT_BLOCKS(B) ((SMB_BIG_UINT)B)
+# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
+# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+
+#endif /* STAT_STATFS4 */
+
+#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((SMB_BIG_UINT)(B), fsd.f_frsize ? (SMB_BIG_UINT)fsd.f_frsize : (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+
+#ifdef STAT_STATVFS64
+ struct statvfs64 fsd;
+ if (statvfs64(path, &fsd) < 0) return -1;
+#else
+ struct statvfs fsd;
+ if (statvfs(path, &fsd) < 0) return -1;
+#endif
+
+ /* f_frsize isn't guaranteed to be supported. */
+
+#endif /* STAT_STATVFS */
+
+#ifndef CONVERT_BLOCKS
+ /* we don't have any dfree code! */
+ return -1;
+#else
+#if !defined(STAT_STATFS2_FS_DATA)
+ /* !Ultrix */
+ (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
+ (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
+#endif /* not STAT_STATFS2_FS_DATA */
+#endif
+
+ return 0;
+}
diff --git a/source/lib/genrand.c b/source/lib/genrand.c
new file mode 100644
index 00000000000..39e56db9609
--- /dev/null
+++ b/source/lib/genrand.c
@@ -0,0 +1,267 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static unsigned char hash[258];
+static uint32 counter;
+unsigned char *reseed_data;
+size_t reseed_data_size;
+
+/****************************************************************
+ Copy any user given reseed data.
+*****************************************************************/
+
+void set_rand_reseed_data(unsigned char *data, size_t len)
+{
+ SAFE_FREE(reseed_data);
+ reseed_data_size = 0;
+
+ reseed_data = (unsigned char *)memdup(data, len);
+ if (reseed_data)
+ reseed_data_size = len;
+}
+
+/****************************************************************
+ Setup the seed.
+*****************************************************************/
+
+static void seed_random_stream(unsigned char *seedval, size_t seedlen)
+{
+ unsigned char j = 0;
+ size_t ind;
+
+ for (ind = 0; ind < 256; ind++)
+ hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (hash[ind] + seedval[ind%seedlen]);
+
+ tc = hash[ind];
+ hash[ind] = hash[j];
+ hash[j] = tc;
+ }
+
+ hash[256] = 0;
+ hash[257] = 0;
+}
+
+/****************************************************************
+ Get datasize bytes worth of random data.
+*****************************************************************/
+
+static void get_random_stream(unsigned char *data, size_t datasize)
+{
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ size_t ind;
+
+ for( ind = 0; ind < datasize; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/****************************************************************
+ Get a 16 byte hash from the contents of a file.
+ Note that the hash is not initialised.
+*****************************************************************/
+
+static void do_filehash(char *fname, unsigned char *the_hash)
+{
+ unsigned char buf[1011]; /* deliberate weird size */
+ unsigned char tmp_md4[16];
+ int fd, n;
+
+ fd = sys_open(fname,O_RDONLY,0);
+ if (fd == -1)
+ return;
+
+ while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
+ mdfour(tmp_md4, buf, n);
+ for (n=0;n<16;n++)
+ the_hash[n] ^= tmp_md4[n];
+ }
+ close(fd);
+}
+
+/**************************************************************
+ Try and get a good random number seed. Try a number of
+ different factors. Firstly, try /dev/urandom - use if exists.
+
+ We use /dev/urandom as a read of /dev/random can block if
+ the entropy pool dries up. This leads clients to timeout
+ or be very slow on connect.
+
+ If we can't use /dev/urandom then seed the stream random generator
+ above...
+**************************************************************/
+
+static int do_reseed(BOOL use_fd, int fd)
+{
+ unsigned char seed_inbuf[40];
+ uint32 v1, v2; struct timeval tval; pid_t mypid;
+ struct passwd *pw;
+
+ if (use_fd) {
+ if (fd != -1)
+ return fd;
+
+ fd = sys_open( "/dev/urandom", O_RDONLY,0);
+ if(fd >= 0)
+ return fd;
+ }
+
+ /* Add in some secret file contents */
+
+ do_filehash("/etc/shadow", &seed_inbuf[0]);
+ do_filehash(lp_smb_passwd_file(), &seed_inbuf[16]);
+
+ /*
+ * Add in the root encrypted password.
+ * On any system where security is taken
+ * seriously this will be secret.
+ */
+
+ pw = sys_getpwnam("root");
+ if (pw && pw->pw_passwd) {
+ size_t i;
+ unsigned char md4_tmp[16];
+ mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
+ for (i=0;i<16;i++)
+ seed_inbuf[8+i] ^= md4_tmp[i];
+ }
+
+ /*
+ * Add the counter, time of day, and pid.
+ */
+
+ GetTimeOfDay(&tval);
+ mypid = sys_getpid();
+ v1 = (counter++) + mypid + tval.tv_sec;
+ v2 = (counter++) * mypid + tval.tv_usec;
+
+ SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
+ SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
+
+ /*
+ * Add any user-given reseed data.
+ */
+
+ if (reseed_data) {
+ size_t i;
+ for (i = 0; i < sizeof(seed_inbuf); i++)
+ seed_inbuf[i] ^= reseed_data[i % reseed_data_size];
+ }
+
+ seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
+
+ return -1;
+}
+
+/*******************************************************************
+ Interface to the (hopefully) good crypto random number generator.
+********************************************************************/
+
+void generate_random_buffer( unsigned char *out, int len, BOOL do_reseed_now)
+{
+ static BOOL done_reseed = False;
+ static int urand_fd = -1;
+ unsigned char md4_buf[64];
+ unsigned char tmp_buf[16];
+ unsigned char *p;
+
+ if(!done_reseed || do_reseed_now) {
+ urand_fd = do_reseed(True, urand_fd);
+ done_reseed = True;
+ }
+
+ if (urand_fd != -1 && len > 0) {
+
+ if (read(urand_fd, out, len) == len)
+ return; /* len bytes of random data read from urandom. */
+
+ /* Read of urand error, drop back to non urand method. */
+ close(urand_fd);
+ urand_fd = -1;
+ do_reseed(False, -1);
+ done_reseed = True;
+ }
+
+ /*
+ * Generate random numbers in chunks of 64 bytes,
+ * then md4 them & copy to the output buffer.
+ * This way the raw state of the stream is never externally
+ * seen.
+ */
+
+ p = out;
+ while(len > 0) {
+ int copy_len = len > 16 ? 16 : len;
+
+ get_random_stream(md4_buf, sizeof(md4_buf));
+ mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
+ memcpy(p, tmp_buf, copy_len);
+ p += copy_len;
+ len -= copy_len;
+ }
+}
+
+/*******************************************************************
+ Use the random number generator to generate a random string.
+********************************************************************/
+
+static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+
+char *generate_random_str(size_t len)
+{
+ static unsigned char retstr[256];
+ size_t i;
+
+ memset(retstr, '\0', sizeof(retstr));
+
+ if (len > sizeof(retstr)-1)
+ len = sizeof(retstr) -1;
+ generate_random_buffer( retstr, len, False);
+ for (i = 0; i < len; i++)
+ retstr[i] = c_list[ retstr[i] % sizeof(c_list) ];
+
+ retstr[i] = '\0';
+
+ return (char *)retstr;
+}
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index 07a7dbfd9b5..0874529d325 100644
--- a/source/lib/getsmbpass.c
+++ b/source/lib/getsmbpass.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1992-1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -40,20 +40,19 @@ static struct termio t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct termio *t)
+static int tcgetattr(int fd, struct termio *t)
{
return ioctl(fd, TCGETA, t);
}
-int tcsetattr(int fd, int flags, const struct termio *t)
+static int tcsetattr(int fd, int flags, struct termio *t)
{
if(flags & TCSAFLUSH)
ioctl(fd, TCFLSH, TCIOFLUSH);
return ioctl(fd, TCSETS, t);
}
-#else /* SYSV_TERMIO */
-#ifdef BSD_TERMIO
+#elif !defined(TCSAFLUSH)
/* BSD TERMIO HANDLING */
@@ -63,37 +62,28 @@ static struct sgttyb t;
#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
-#ifndef TCSAFLUSH
#define TCSAFLUSH 1
-#endif
-
-#ifndef TCSANOW
#define TCSANOW 0
-#endif
-int tcgetattr(int fd, struct sgttyb *t)
+static int tcgetattr(int fd, struct sgttyb *t)
{
return ioctl(fd, TIOCGETP, (char *)t);
}
-int tcsetattr(int fd, int flags, const struct sgttyb *t)
+static int tcsetattr(int fd, int flags, struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
-#else /* BSD_TERMIO */
-
-/* POSIX TERMIO HANDLING */
+#else /* POSIX TERMIO HANDLING */
#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
static struct termios t;
-#endif /* BSD_TERMIO */
#endif /* SYSV_TERMIO */
-char *
-getsmbpass(char *prompt)
+char *getsmbpass(char *prompt)
{
FILE *in, *out;
int echo_off;
@@ -102,7 +92,7 @@ getsmbpass(char *prompt)
size_t nread;
/* Catch problematic signals */
- signal(SIGINT, SIGNAL_CAST SIG_IGN);
+ CatchSignal(SIGINT, SIGNAL_CAST SIG_IGN);
/* Try to write to and read from the terminal if we can.
If we can't open the terminal, use stderr and stdin. */
@@ -154,13 +144,13 @@ getsmbpass(char *prompt)
fclose (in);
/* Catch problematic signals */
- signal(SIGINT, SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL);
printf("\n");
return buf;
}
#else
-
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy(void);
+ void getsmbpasswd_dummy(void) {;}
#endif
diff --git a/source/lib/hash.c b/source/lib/hash.c
new file mode 100644
index 00000000000..68c334a8ca8
--- /dev/null
+++ b/source/lib/hash.c
@@ -0,0 +1,316 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Copyright (C) Ying Chen 2000.
+ Copyright (C) Jeremy Allison 2000.
+ - added some defensive programming.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * NB. We may end up replacing this functionality in a future 2.x
+ * release to reduce the number of hashing/lookup methods we support. JRA.
+ */
+
+#include "includes.h"
+
+static BOOL enlarge_hash_table(hash_table *table);
+static int primes[] =
+ {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411};
+
+/****************************************************************************
+ * This function initializes the hash table.
+ * This hash function hashes on string keys.
+ * This number of hash buckets is always rounded up to a power of
+ * 2 first, then to a prime number that is large than the power of two.
+ * Input:
+ * table -- the hash table pointer.
+ * num_buckets -- the number of buckets to be allocated. This
+ * hash function can dynamically increase its size when the
+ * the hash table size becomes small. There is a MAX hash table
+ * size defined in hash.h.
+ * compare_func -- the function pointer to a comparison function
+ * used by the hash key comparison.
+ ****************************************************************************
+ */
+
+BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func)
+{
+ int i;
+ ubi_dlList *bucket;
+
+ table->num_elements = 0;
+ table->size = 2;
+ table->comp_func = compare_func;
+ while (table->size < num_buckets)
+ table->size <<= 1;
+ for (i = 0; i < ARRAY_SIZE(primes); i++) {
+ if (primes[i] > table->size) {
+ table->size = primes[i];
+ break;
+ }
+ }
+
+ DEBUG(5, ("Hash size = %d.\n", table->size));
+
+ if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) {
+ DEBUG(0,("hash_table_init: malloc fail !\n"));
+ return False;
+ }
+ ubi_dlInitList(&(table->lru_chain));
+ for (i=0, bucket = table->buckets; i < table->size; i++, bucket++)
+ ubi_dlInitList(bucket);
+
+ return True;
+}
+
+/*
+ **************************************************************
+ * Compute a hash value based on a string key value.
+ * Make the string key into an array of int's if possible.
+ * For the last few chars that cannot be int'ed, use char instead.
+ * The function returns the bucket index number for the hashed
+ * key.
+ **************************************************************
+ */
+
+static int string_hash(int hash_size, const char *key)
+{
+ u32 value; /* Used to compute the hash value. */
+ u32 i; /* Used to cycle through random values. */
+
+ for (value = 0x238F13AF, i=0; key[i]; i++)
+ value = (value + (key[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345) % hash_size;
+}
+
+
+/* *************************************************************************
+ * Search the hash table for the entry in the hash chain.
+ * The function returns the pointer to the
+ * element found in the chain or NULL if none is found.
+ * If the element is found, the element is also moved to
+ * the head of the LRU list.
+ *
+ * Input:
+ * table -- The hash table where the element is stored in.
+ * hash_chain -- The pointer to the bucket that stores the
+ * element to be found.
+ * key -- The hash key to be found.
+ ***************************************************************************
+ */
+
+static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key)
+{
+ hash_element *hash_elem;
+ ubi_dlNodePtr lru_item;
+ int i = 0;
+
+ for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count;
+ i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) {
+ if ((table->comp_func)(hash_elem->key, key) == 0) {
+ /* Move to the head of the lru List. */
+ lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlAddHead(&(table->lru_chain), lru_item);
+ return(hash_elem);
+ }
+ }
+ return ((hash_element *) NULL);
+}
+
+/* ***************************************************************************
+ *
+ * Lookup a hash table for an element with key.
+ * The function returns a pointer to the hash element.
+ * If no element is found, the function returns NULL.
+ *
+ * Input:
+ * table -- The hash table to be searched on.
+ * key -- The key to be found.
+ *****************************************************************************
+ */
+
+hash_element *hash_lookup(hash_table *table, char *key)
+{
+ return (hash_chain_find(table, &table->buckets[string_hash(table->size, key)], key));
+}
+
+/* ***************************************************************
+ *
+ * This function first checks if an element with key "key"
+ * exists in the hash table. If so, the function moves the
+ * element to the front of the LRU list. Otherwise, a new
+ * hash element corresponding to "value" and "key" is allocated
+ * and inserted into the hash table. The new elements are
+ * always inserted in the LRU order to the LRU list as well.
+ *
+ * Input:
+ * table -- The hash table to be inserted in.
+ * value -- The content of the element to be inserted.
+ * key -- The key of the new element to be inserted.
+ *
+ ****************************************************************
+ */
+
+hash_element *hash_insert(hash_table *table, char *value, char *key)
+{
+ hash_element *hash_elem;
+ ubi_dlNodePtr lru_item;
+ ubi_dlList *bucket;
+
+ /*
+ * If the hash table size has not reached the MAX_HASH_TABLE_SIZE,
+ * the hash table may be enlarged if the current hash table is full.
+ * If the hash table size has reached the MAX_HASH_TABLE_SIZE,
+ * use LRU to remove the oldest element from the hash table.
+ */
+
+ if ((table->num_elements >= table->size) &&
+ (table->num_elements < MAX_HASH_TABLE_SIZE)) {
+ if(!enlarge_hash_table(table))
+ return (hash_element *)NULL;
+ table->num_elements += 1;
+ } else if (table->num_elements >= MAX_HASH_TABLE_SIZE) {
+ /* Do an LRU replacement. */
+ lru_item = ubi_dlLast(&(table->lru_chain));
+ hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem);
+ bucket = hash_elem->bucket;
+ ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ } else {
+ table->num_elements += 1;
+ }
+
+ bucket = &table->buckets[string_hash(table->size, key)];
+
+ /* Since we only have 1-byte for the key string, we need to
+ * allocate extra space in the hash_element to store the entire key
+ * string.
+ */
+
+ if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + strlen(key)))) {
+ DEBUG(0,("hash_insert: malloc fail !\n"));
+ return (hash_element *)NULL;
+ }
+
+ safe_strcpy((char *) hash_elem->key, key, strlen(key)+1);
+
+ hash_elem->value = (char *)value;
+ hash_elem->bucket = bucket;
+ /* Insert in front of the lru list and the bucket list. */
+ ubi_dlAddHead(bucket, hash_elem);
+ hash_elem->lru_link.hash_elem = hash_elem;
+ ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+
+ return(hash_elem);
+}
+
+/* **************************************************************************
+ *
+ * Remove a hash element from the hash table. The hash element is
+ * removed from both the LRU list and the hash bucket chain.
+ *
+ * Input:
+ * table -- the hash table to be manipulated on.
+ * hash_elem -- the element to be removed.
+ **************************************************************************
+ */
+
+void hash_remove(hash_table *table, hash_element *hash_elem)
+{
+ if (hash_elem) {
+ ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ table->num_elements--;
+ }
+}
+
+/* ******************************************************************
+ * Increase the hash table size if it is too small.
+ * The hash table size is increased by the HASH_TABLE_INCREMENT
+ * ratio.
+ * Input:
+ * table -- the hash table to be enlarged.
+ ******************************************************************
+ */
+
+static BOOL enlarge_hash_table(hash_table *table)
+{
+ hash_element *hash_elem;
+ int size, hash_value;
+ ubi_dlList *buckets;
+ ubi_dlList *old_bucket;
+ ubi_dlList *bucket;
+ ubi_dlList lru_chain;
+
+ buckets = table->buckets;
+ lru_chain = table->lru_chain;
+ size = table->size;
+
+ /* Reinitialize the hash table. */
+ if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func))
+ return False;
+
+ for (old_bucket = buckets; size > 0; size--, old_bucket++) {
+ while (old_bucket->count != 0) {
+ hash_elem = (hash_element *) ubi_dlRemHead(old_bucket);
+ ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link));
+ hash_value = string_hash(table->size, (char *) hash_elem->key);
+ bucket = &(table->buckets[hash_value]);
+ ubi_dlAddHead(bucket, hash_elem);
+ ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ hash_elem->bucket = bucket;
+ hash_elem->lru_link.hash_elem = hash_elem;
+ table->num_elements++;
+ }
+ }
+ SAFE_FREE(buckets);
+
+ return True;
+}
+
+/* **********************************************************************
+ *
+ * Remove everything from a hash table and free up the memory it
+ * occupies.
+ * Input:
+ * table -- the hash table to be cleared.
+ *
+ *************************************************************************
+ */
+
+void hash_clear(hash_table *table)
+{
+ int i;
+ ubi_dlList *bucket = table->buckets;
+ hash_element *hash_elem;
+ for (i = 0; i < table->size; bucket++, i++) {
+ while (bucket->count != 0) {
+ hash_elem = (hash_element *) ubi_dlRemHead(bucket);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ }
+ }
+ table->size = 0;
+ SAFE_FREE(table->buckets);
+ table->buckets = NULL;
+}
diff --git a/source/lib/hmacmd5.c b/source/lib/hmacmd5.c
new file mode 100644
index 00000000000..1d9b89e0cce
--- /dev/null
+++ b/source/lib/hmacmd5.c
@@ -0,0 +1,136 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ HMAC MD5 code for use in NTLMv2
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* taken direct from rfc2104 implementation and modified for suitable use
+ * for ntlmv2.
+ */
+
+#include "includes.h"
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64)
+ {
+ uchar tk[16];
+ struct MD5Context tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ bcopy( key, ctx->k_ipad, key_len);
+ bcopy( key, ctx->k_opad, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++)
+ {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_limK_to_64(const uchar* key, int key_len,
+ HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes truncate it */
+ if (key_len > 64)
+ {
+ key_len = 64;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ bcopy( key, ctx->k_ipad, key_len);
+ bcopy( key, ctx->k_opad, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++)
+ {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx)
+{
+ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
+
+{
+ struct MD5Context ctx_o;
+
+ MD5Final(digest, &ctx->ctx);
+
+ MD5Init(&ctx_o);
+ MD5Update(&ctx_o, ctx->k_opad, 64);
+ MD5Update(&ctx_o, digest, 16);
+ MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
+{
+ HMACMD5Context ctx;
+ hmac_md5_init_limK_to_64(key, 16, &ctx);
+ if (data_len != 0)
+ {
+ hmac_md5_update(data, data_len, &ctx);
+ }
+ hmac_md5_final(digest, &ctx);
+}
+
diff --git a/source/lib/iconv.c b/source/lib/iconv.c
new file mode 100644
index 00000000000..c08524eaa03
--- /dev/null
+++ b/source/lib/iconv.c
@@ -0,0 +1,582 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ minimal iconv implementation
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static size_t ascii_pull(void *,char **, size_t *, char **, size_t *);
+static size_t ascii_push(void *,char **, size_t *, char **, size_t *);
+static size_t utf8_pull(void *,char **, size_t *, char **, size_t *);
+static size_t utf8_push(void *,char **, size_t *, char **, size_t *);
+static size_t weird_pull(void *,char **, size_t *, char **, size_t *);
+static size_t weird_push(void *,char **, size_t *, char **, size_t *);
+static size_t ucs2hex_pull(void *,char **, size_t *, char **, size_t *);
+static size_t ucs2hex_push(void *,char **, size_t *, char **, size_t *);
+static size_t iconv_copy(void *,char **, size_t *, char **, size_t *);
+
+/*
+ for each charset we have a function that pulls from that charset to
+ a ucs2 buffer, and a function that pushes to a ucs2 buffer
+*/
+static struct {
+ char *name;
+ size_t (*pull)(void *, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+} charsets[] = {
+ {"UCS-2LE", iconv_copy, iconv_copy},
+ {"UTF8", utf8_pull, utf8_push},
+ {"ASCII", ascii_pull, ascii_push},
+ {"WEIRD", weird_pull, weird_push},
+ {"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
+ {NULL, NULL, NULL}
+};
+
+
+/* if there was an error then reset the internal state,
+ this ensures that we don't have a shift state remaining for
+ character sets like SJIS */
+static size_t sys_iconv(void *cd,
+ char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+#ifdef HAVE_NATIVE_ICONV
+ size_t ret = iconv((iconv_t)cd,
+ inbuf, inbytesleft,
+ outbuf, outbytesleft);
+ if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
+ return ret;
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+/*
+ this is a simple portable iconv() implementaion. It only knows about
+ a very small number of character sets - just enough that Samba works
+ on systems that don't have iconv
+ */
+size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ char cvtbuf[2048];
+ char *bufp = cvtbuf;
+ size_t bufsize;
+
+ /* in many cases we can go direct */
+ if (cd->direct) {
+ return cd->direct(cd->cd_direct,
+ (char **)inbuf, inbytesleft, outbuf, outbytesleft);
+ }
+
+
+ /* otherwise we have to do it chunks at a time */
+ while (*inbytesleft > 0) {
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf);
+
+ if (cd->pull(cd->cd_pull,
+ (char **)inbuf, inbytesleft, &bufp, &bufsize) == -1
+ && errno != E2BIG) return -1;
+
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf) - bufsize;
+
+ if (cd->push(cd->cd_push,
+ &bufp, &bufsize,
+ outbuf, outbytesleft) == -1) return -1;
+ }
+
+ return 0;
+}
+
+/*
+ simple iconv_open() wrapper
+ */
+smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
+{
+ smb_iconv_t ret;
+ int from, to;
+
+ ret = (smb_iconv_t)malloc(sizeof(*ret));
+ if (!ret) {
+ errno = ENOMEM;
+ return (smb_iconv_t)-1;
+ }
+ memset(ret, 0, sizeof(*ret));
+
+ ret->from_name = strdup(fromcode);
+ ret->to_name = strdup(tocode);
+
+ /* check for the simplest null conversion */
+ if (strcmp(fromcode, tocode) == 0) {
+ ret->direct = iconv_copy;
+ return ret;
+ }
+
+ for (from=0; charsets[from].name; from++) {
+ if (strcasecmp(charsets[from].name, fromcode) == 0) break;
+ }
+ for (to=0; charsets[to].name; to++) {
+ if (strcasecmp(charsets[to].name, tocode) == 0) break;
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ if (!charsets[from].name) {
+ ret->pull = sys_iconv;
+ ret->cd_pull = iconv_open("UCS-2LE", fromcode);
+ if (ret->cd_pull == (iconv_t)-1) goto failed;
+ }
+ if (!charsets[to].name) {
+ ret->push = sys_iconv;
+ ret->cd_push = iconv_open(tocode, "UCS-2LE");
+ if (ret->cd_push == (iconv_t)-1) goto failed;
+ }
+#else
+ if (!charsets[from].name || !charsets[to].name) {
+ goto failed;
+ }
+#endif
+
+ /* check for conversion to/from ucs2 */
+ if (from == 0 && charsets[to].name) {
+ ret->direct = charsets[to].push;
+ return ret;
+ }
+ if (to == 0 && charsets[from].name) {
+ ret->direct = charsets[from].pull;
+ return ret;
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ if (from == 0) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_push;
+ ret->cd_push = NULL;
+ return ret;
+ }
+ if (to == 0) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_pull;
+ ret->cd_pull = NULL;
+ return ret;
+ }
+#endif
+
+ /* the general case has to go via a buffer */
+ if (!ret->pull) ret->pull = charsets[from].pull;
+ if (!ret->push) ret->push = charsets[to].push;
+ return ret;
+
+failed:
+ SAFE_FREE(ret);
+ errno = EINVAL;
+ return (smb_iconv_t)-1;
+}
+
+/*
+ simple iconv_close() wrapper
+*/
+int smb_iconv_close (smb_iconv_t cd)
+{
+#ifdef HAVE_NATIVE_ICONV
+ if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
+ if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
+ if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
+#endif
+
+ SAFE_FREE(cd->from_name);
+ SAFE_FREE(cd->to_name);
+
+ memset(cd, 0, sizeof(*cd));
+ SAFE_FREE(cd);
+ return 0;
+}
+
+
+/**********************************************************************
+ the following functions implement the builtin character sets in Samba
+ and also the "test" character sets that are designed to test
+ multi-byte character set support for english users
+***********************************************************************/
+
+static size_t ascii_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0] & 0x7F;
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+
+static size_t ucs2hex_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ unsigned v;
+
+ if ((*inbuf)[0] != '@') {
+ /* seven bit ascii case */
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ continue;
+ }
+ /* it's a hex character */
+ if (*inbytesleft < 5) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ (*outbuf)[0] = v&0xff;
+ (*outbuf)[1] = v>>8;
+ (*inbytesleft) -= 5;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 5;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ char buf[6];
+
+ if ((*inbuf)[1] == 0 &&
+ ((*inbuf)[0] & 0x80) == 0 &&
+ (*inbuf)[0] != '@') {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ continue;
+ }
+ if (*outbytesleft < 5) {
+ errno = E2BIG;
+ return -1;
+ }
+ snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
+ memcpy(*outbuf, buf, 5);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 5;
+ (*inbuf) += 2;
+ (*outbuf) += 5;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* the "weird" character set is very useful for testing multi-byte
+ support and finding bugs. Don't use on a production system!
+*/
+static struct {
+ char from;
+ char *to;
+ int len;
+} weird_table[] = {
+ {'q', "^q^", 3},
+ {'Q', "^Q^", 3},
+ {0, NULL}
+};
+
+static size_t weird_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ int i;
+ int done = 0;
+ for (i=0;weird_table[i].from;i++) {
+ if (strncmp((*inbuf),
+ weird_table[i].to,
+ weird_table[i].len) == 0) {
+ if (*inbytesleft < weird_table[i].len) {
+ DEBUG(0,("ERROR: truncated weird string\n"));
+ /* smb_panic("weird_pull"); */
+
+ } else {
+ (*outbuf)[0] = weird_table[i].from;
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= weird_table[i].len;
+ (*outbytesleft) -= 2;
+ (*inbuf) += weird_table[i].len;
+ (*outbuf) += 2;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t weird_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ int i;
+ int done=0;
+ for (i=0;weird_table[i].from;i++) {
+ if ((*inbuf)[0] == weird_table[i].from &&
+ (*inbuf)[1] == 0) {
+ if (*outbytesleft < weird_table[i].len) {
+ DEBUG(0,("No room for weird character\n"));
+ /* smb_panic("weird_push"); */
+ } else {
+ memcpy(*outbuf, weird_table[i].to,
+ weird_table[i].len);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= weird_table[i].len;
+ (*inbuf) += 2;
+ (*outbuf) += weird_table[i].len;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ memmove(*outbuf, *inbuf, n);
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ unsigned char *c = (unsigned char *)*inbuf;
+ unsigned char *uc = (unsigned char *)*outbuf;
+ int len = 1;
+
+ if ((c[0] & 0x80) == 0) {
+ uc[0] = c[0];
+ uc[1] = 0;
+ } else if ((c[0] & 0xf0) == 0xe0) {
+ if (*inbytesleft < 3) {
+ DEBUG(0,("short utf8 char\n"));
+ goto badseq;
+ }
+ uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
+ uc[0] = (c[1]<<6) | (c[2]&0x3f);
+ len = 3;
+ } else if ((c[0] & 0xe0) == 0xc0) {
+ if (*inbytesleft < 2) {
+ DEBUG(0,("short utf8 char\n"));
+ goto badseq;
+ }
+ uc[1] = (c[0]>>2) & 0x7;
+ uc[0] = (c[0]<<6) | (c[1]&0x3f);
+ len = 2;
+ }
+
+ (*inbuf) += len;
+ (*inbytesleft) -= len;
+ (*outbytesleft) -= 2;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+
+badseq:
+ errno = EINVAL;
+ return -1;
+}
+
+static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ unsigned char *c = (unsigned char *)*outbuf;
+ unsigned char *uc = (unsigned char *)*inbuf;
+ int len=1;
+
+ if (uc[1] & 0xf8) {
+ if (*outbytesleft < 3) {
+ DEBUG(0,("short utf8 write\n"));
+ goto toobig;
+ }
+ c[0] = 0xe0 | (uc[1]>>4);
+ c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6);
+ c[2] = 0x80 | (uc[0]&0x3f);
+ len = 3;
+ } else if (uc[1] | (uc[0] & 0x80)) {
+ if (*outbytesleft < 2) {
+ DEBUG(0,("short utf8 write\n"));
+ goto toobig;
+ }
+ c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6);
+ c[1] = 0x80 | (uc[0]&0x3f);
+ len = 2;
+ } else {
+ c[0] = uc[0];
+ }
+
+
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= len;
+ (*inbuf) += 2;
+ (*outbuf) += len;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+
+toobig:
+ errno = E2BIG;
+ return -1;
+}
+
diff --git a/source/lib/interface.c b/source/lib/interface.c
new file mode 100644
index 00000000000..08636fa3067
--- /dev/null
+++ b/source/lib/interface.c
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ multiple interface handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static struct iface_struct *probed_ifaces;
+static int total_probed;
+
+struct in_addr allones_ip;
+struct in_addr loopback_ip;
+
+static struct interface *local_interfaces;
+
+#define ALLONES ((uint32)0xFFFFFFFF)
+#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
+#define MKNETADDR(_IP, _NM) (_IP & _NM)
+
+/****************************************************************************
+Try and find an interface that matches an ip. If we cannot, return NULL
+ **************************************************************************/
+static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
+{
+ struct interface *i;
+ if (is_zero_ip(ip)) return local_interfaces;
+
+ for (i=local_interfaces;i;i=i->next)
+ if (CheckMask) {
+ if (same_net(i->ip,ip,i->nmask)) return i;
+ } else if ((i->ip).s_addr == ip.s_addr) return i;
+
+ return NULL;
+}
+
+
+/****************************************************************************
+add an interface to the linked list of interfaces
+****************************************************************************/
+static void add_interface(struct in_addr ip, struct in_addr nmask)
+{
+ struct interface *iface;
+ if (iface_find(ip, False)) {
+ DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
+ return;
+ }
+
+ if (ip_equal(nmask, allones_ip)) {
+ DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
+ return;
+ }
+
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ ZERO_STRUCTPN(iface);
+
+ iface->ip = ip;
+ iface->nmask = nmask;
+ iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
+
+ DLIST_ADD(local_interfaces, iface);
+
+ DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
+ DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
+}
+
+
+
+/****************************************************************************
+interpret a single element from a interfaces= config line
+
+This handles the following different forms:
+
+1) wildcard interface name
+2) DNS name
+3) IP/masklen
+4) ip/mask
+5) bcast/mask
+****************************************************************************/
+static void interpret_interface(char *token)
+{
+ struct in_addr ip, nmask;
+ char *p;
+ int i, added=0;
+
+ zero_ip(&ip);
+ zero_ip(&nmask);
+
+ /* first check if it is an interface name */
+ for (i=0;i<total_probed;i++) {
+ if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ added = 1;
+ }
+ }
+ if (added) return;
+
+ /* maybe it is a DNS name */
+ p = strchr_m(token,'/');
+ if (!p) {
+ ip = *interpret_addr2(token);
+ for (i=0;i<total_probed;i++) {
+ if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
+ !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ return;
+ }
+ }
+ DEBUG(2,("can't determine netmask for %s\n", token));
+ return;
+ }
+
+ /* parse it into an IP address/netmasklength pair */
+ *p++ = 0;
+
+ ip = *interpret_addr2(token);
+
+ if (strlen(p) > 2) {
+ nmask = *interpret_addr2(p);
+ } else {
+ nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
+ }
+
+ /* maybe the first component was a broadcast address */
+ if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
+ ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
+ for (i=0;i<total_probed;i++) {
+ if (same_net(ip, probed_ifaces[i].ip, nmask)) {
+ add_interface(probed_ifaces[i].ip, nmask);
+ return;
+ }
+ }
+ DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
+ return;
+ }
+
+ add_interface(ip, nmask);
+}
+
+
+/****************************************************************************
+load the list of network interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ char **ptr;
+ int i;
+ struct iface_struct ifaces[MAX_INTERFACES];
+
+ ptr = lp_interfaces();
+
+ allones_ip = *interpret_addr2("255.255.255.255");
+ loopback_ip = *interpret_addr2("127.0.0.1");
+
+ SAFE_FREE(probed_ifaces);
+
+ /* dump the current interfaces if any */
+ while (local_interfaces) {
+ struct interface *iface = local_interfaces;
+ DLIST_REMOVE(local_interfaces, local_interfaces);
+ ZERO_STRUCTPN(iface);
+ SAFE_FREE(iface);
+ }
+
+ /* probe the kernel for interfaces */
+ total_probed = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if (total_probed > 0) {
+ probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
+ }
+
+ /* if we don't have a interfaces line then use all broadcast capable
+ interfaces except loopback */
+ if (!ptr || !*ptr || !**ptr) {
+ if (total_probed <= 0) {
+ DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
+ exit(1);
+ }
+ for (i=0;i<total_probed;i++) {
+ if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
+ probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ }
+ }
+ return;
+ }
+
+ if (ptr) {
+ while (*ptr) {
+ interpret_interface(*ptr);
+ ptr++;
+ }
+ }
+
+ if (!local_interfaces) {
+ DEBUG(0,("WARNING: no network interfaces found\n"));
+ }
+}
+
+
+/****************************************************************************
+return True if the list of probed interfaces has changed
+****************************************************************************/
+BOOL interfaces_changed(void)
+{
+ int n;
+ struct iface_struct ifaces[MAX_INTERFACES];
+
+ n = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if ((n > 0 )&& (n != total_probed ||
+ memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
+ return True;
+ }
+
+ return False;
+}
+
+
+/****************************************************************************
+ check if an IP is one of mine
+ **************************************************************************/
+BOOL ismyip(struct in_addr ip)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->ip,ip)) return True;
+ return False;
+}
+
+/****************************************************************************
+ check if a packet is from a local (known) net
+ **************************************************************************/
+BOOL is_local_net(struct in_addr from)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next) {
+ if((from.s_addr & i->nmask.s_addr) ==
+ (i->ip.s_addr & i->nmask.s_addr))
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ how many interfaces do we have
+ **************************************************************************/
+int iface_count(void)
+{
+ int ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next)
+ ret++;
+ return ret;
+}
+
+/****************************************************************************
+ True if we have two or more interfaces.
+ **************************************************************************/
+BOOL we_are_multihomed(void)
+{
+ static int multi = -1;
+
+ if(multi == -1)
+ multi = (iface_count() > 1 ? True : False);
+
+ return multi;
+}
+
+/****************************************************************************
+ return the Nth interface
+ **************************************************************************/
+struct interface *get_interface(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return i;
+ return NULL;
+}
+
+/****************************************************************************
+ return IP of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_ip(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->ip;
+ return NULL;
+}
+
+/****************************************************************************
+ return bcast of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_bcast(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->bcast;
+ return NULL;
+}
+
+
+/****************************************************************************
+this function provides a simple hash of the configured interfaces. It is
+used to detect a change in interfaces to tell us whether to discard
+the current wins.dat file.
+Note that the result is independent of the order of the interfaces
+ **************************************************************************/
+unsigned iface_hash(void)
+{
+ unsigned ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next) {
+ unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
+ unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
+ ret ^= (x1 ^ x2);
+ }
+
+ return ret;
+}
+
+
+/* these 3 functions return the ip/bcast/nmask for the interface
+ most appropriate for the given ip address. If they can't find
+ an appropriate interface they return the requested field of the
+ first known interface. */
+
+struct in_addr *iface_bcast(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip, True);
+ return(i ? &i->bcast : &local_interfaces->bcast);
+}
+
+struct in_addr *iface_ip(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip, True);
+ return(i ? &i->ip : &local_interfaces->ip);
+}
diff --git a/source/lib/interfaces.c b/source/lib/interfaces.c
new file mode 100644
index 00000000000..6e031a1dabd
--- /dev/null
+++ b/source/lib/interfaces.c
@@ -0,0 +1,402 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ return a list of network interfaces
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/* working out the interfaces for a OS is an incredibly non-portable
+ thing. We have several possible implementations below, and autoconf
+ tries each of them to see what works
+
+ Note that this file does _not_ include includes.h. That is so this code
+ can be called directly from the autoconf tests. That also means
+ this code cannot use any of the normal Samba debug stuff or defines.
+ This is standalone code.
+
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+
+#ifndef SIOCGIFCONF
+#include <sys/sockio.h>
+#endif
+
+#ifdef AUTOCONF_TEST
+struct iface_struct {
+ char name[16];
+ struct in_addr ip;
+ struct in_addr netmask;
+};
+#else
+#include "config.h"
+#include "interfaces.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#if HAVE_IFACE_IFCONF
+
+/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
+ V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
+
+ It probably also works on any BSD style system. */
+
+/****************************************************************************
+ get the netmask address for a local interface
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ struct ifconf ifc;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ int total = 0;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ n = ifc.ifc_len / sizeof(struct ifreq);
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i=n-1;i>=0 && total < max_interfaces;i--) {
+ if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
+ continue;
+ }
+
+ iname = ifr[i].ifr_name;
+ ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
+ continue;
+ }
+
+ if (!(ifr[i].ifr_flags & IFF_UP)) {
+ continue;
+ }
+
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
+ continue;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+ total++;
+ }
+
+ close(fd);
+
+ return total;
+}
+
+#elif HAVE_IFACE_IFREQ
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+/****************************************************************************
+this should cover most of the streams based systems
+Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ int total = 0;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = buff;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(fd, I_STR, &strioctl) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ /* we can ignore the possible sizeof(int) here as the resulting
+ number of interface structures won't change */
+ n = strioctl.ic_len / sizeof(struct ifreq);
+
+ /* we will assume that the kernel returns the length as an int
+ at the start of the buffer if the offered size is a
+ multiple of the structure size plus an int */
+ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
+ ifr = (struct ifreq *)(buff + sizeof(int));
+ } else {
+ ifr = (struct ifreq *)buff;
+ }
+
+ /* Loop through interfaces */
+
+ for (i = 0; i<n && total < max_interfaces; i++) {
+ ifreq = ifr[i];
+
+ strioctl.ic_cmd = SIOCGIFFLAGS;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ if (!(ifreq.ifr_flags & IFF_UP)) {
+ continue;
+ }
+
+ strioctl.ic_cmd = SIOCGIFADDR;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
+ iname = ifreq.ifr_name;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+
+ total++;
+ }
+
+ close(fd);
+
+ return total;
+}
+
+#elif HAVE_IFACE_AIX
+
+/****************************************************************************
+this one is for AIX (tested on 4.2)
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ char buff[8192];
+ int fd, i;
+ struct ifconf ifc;
+ struct ifreq *ifr=NULL;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+ int total = 0;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces */
+ i = ifc.ifc_len;
+
+ while (i > 0 && total < max_interfaces) {
+ unsigned inc;
+
+ inc = ifr->ifr_addr.sa_len;
+
+ if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+ goto next;
+ }
+
+ ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
+ iname = ifr->ifr_name;
+
+ if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
+ goto next;
+ }
+
+ if (!(ifr->ifr_flags & IFF_UP)) {
+ goto next;
+ }
+
+ if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+ goto next;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+
+ total++;
+
+ next:
+ /*
+ * Patch from Archie Cobbs (archie@whistle.com). The
+ * addresses in the SIOCGIFCONF interface list have a
+ * minimum size. Usually this doesn't matter, but if
+ * your machine has tunnel interfaces, etc. that have
+ * a zero length "link address", this does matter. */
+
+ if (inc < sizeof(ifr->ifr_addr))
+ inc = sizeof(ifr->ifr_addr);
+ inc += IFNAMSIZ;
+
+ ifr = (struct ifreq*) (((char*) ifr) + inc);
+ i -= inc;
+ }
+
+
+ close(fd);
+ return total;
+}
+
+#else /* a dummy version */
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ return -1;
+}
+#endif
+
+
+static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
+{
+ int r;
+ r = strcmp(i1->name, i2->name);
+ if (r) return r;
+ r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
+ if (r) return r;
+ r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
+ return r;
+}
+
+/* this wrapper is used to remove duplicates from the interface list generated
+ above */
+int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ int total, i, j;
+
+ total = _get_interfaces(ifaces, max_interfaces);
+ if (total <= 0) return total;
+
+ /* now we need to remove duplicates */
+ qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
+
+ for (i=1;i<total;) {
+ if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
+ for (j=i-1;j<total-1;j++) {
+ ifaces[j] = ifaces[j+1];
+ }
+ total--;
+ } else {
+ i++;
+ }
+ }
+
+ return total;
+}
+
+
+#ifdef AUTOCONF_TEST
+/* this is the autoconf driver to test get_interfaces() */
+
+#define MAX_INTERFACES 128
+
+ int main()
+{
+ struct iface_struct ifaces[MAX_INTERFACES];
+ int total = get_interfaces(ifaces, MAX_INTERFACES);
+ int i;
+
+ printf("got %d interfaces:\n", total);
+ if (total <= 0) exit(1);
+
+ for (i=0;i<total;i++) {
+ printf("%-10s ", ifaces[i].name);
+ printf("IP=%s ", inet_ntoa(ifaces[i].ip));
+ printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
+ }
+ return 0;
+}
+#endif
diff --git a/source/lib/kanji.c b/source/lib/kanji.c
deleted file mode 100644
index 0af476eb157..00000000000
--- a/source/lib/kanji.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Adding for Japanese language by <fujita@ainix.isac.co.jp> 1994.9.5
- and extend coding system to EUC/SJIS/JIS/HEX at 1994.10.11
- and add all jis codes sequence type at 1995.8.16
- Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp>
-*/
-#ifdef KANJI
-
-#define _KANJI_C_
-#include "includes.h"
-
-/* coding system keep in */
-int coding_system = SJIS_CODE;
-
-/* jis si/so sequence */
-char jis_kso = JIS_KSO;
-char jis_ksi = JIS_KSI;
-char hex_tag = HEXTAG;
-
-/*******************************************************************
- SHIFT JIS functions
-********************************************************************/
-/*******************************************************************
- search token from S1 separated any char of S2
- S1 contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strtok (char *s1, const char *s2)
-{
- static char *s = NULL;
- char *q;
- if (!s1) {
- if (!s) {
- return NULL;
- }
- s1 = s;
- }
- for (q = s1; *s1; ) {
- if (is_shift_jis (*s1)) {
- s1 += 2;
- } else if (is_kana (*s1)) {
- s1++;
- } else {
- char *p = strchr (s2, *s1);
- if (p) {
- if (s1 != q) {
- s = s1 + 1;
- *s1 = '\0';
- return q;
- }
- q = s1 + 1;
- }
- s1++;
- }
- }
- s = NULL;
- if (*q) {
- return q;
- }
- return NULL;
-}
-
-/*******************************************************************
- search string S2 from S1
- S1 contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strstr (const char *s1, const char *s2)
-{
- register int len = strlen ((char *) s2);
- if (!*s2)
- return (char *) s1;
- for (;*s1;) {
- if (*s1 == *s2) {
- if (strncmp (s1, s2, len) == 0)
- return (char *) s1;
- }
- if (is_shift_jis (*s1)) {
- s1 += 2;
- } else {
- s1++;
- }
- }
- return 0;
-}
-
-/*******************************************************************
- Search char C from beginning of S.
- S contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strchr (const char *s, int c)
-{
- for (; *s; ) {
- if (*s == c)
- return (char *) s;
- if (is_shift_jis (*s)) {
- s += 2;
- } else {
- s++;
- }
- }
- return 0;
-}
-
-/*******************************************************************
- Search char C end of S.
- S contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strrchr (const char *s, int c)
-{
- register char *q;
-
- for (q = 0; *s; ) {
- if (*s == c) {
- q = (char *) s;
- }
- if (is_shift_jis (*s)) {
- s += 2;
- } else {
- s++;
- }
- }
- return q;
-}
-
-/*******************************************************************
- Code conversion
-********************************************************************/
-/* convesion buffer */
-static char cvtbuf[1024];
-
-/*******************************************************************
- EUC <-> SJIS
-********************************************************************/
-static int
-euc2sjis (register int hi, register int lo)
-{
- if (hi & 1)
- return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) |
- (lo - (lo >= 0xe0 ? 0x60 : 0x61));
- else
- return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2);
-}
-
-static int
-sjis2euc (register int hi, register int lo)
-{
- if (lo >= 0x9f)
- return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2);
- else
- return ((hi * 2 - (hi >= 0xe0 ? 0xe1 : 0x61)) << 8) |
- (lo + (lo >= 0x7f ? 0x60 : 0x61));
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to EUC codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_euc (const char *from, BOOL overwrite)
-{
- register char *out;
- char *save;
-
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_shift_jis (*from)) {
- int code = sjis2euc ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (*from)) {
- *out++ = euc_kana;
- *out++ = *from++;
- } else {
- *out++ = *from++;
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy((char *) save, (char *) cvtbuf);
- return (char *) save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain EUC codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-euc_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- char *save;
-
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_euc (*from)) {
- int code = euc2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_euc_kana (*from)) {
- *out++ = from[1];
- from += 2;
- } else {
- *out++ = *from++;
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy(save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- JIS7,JIS8,JUNET <-> SJIS
-********************************************************************/
-static int
-sjis2jis (register int hi, register int lo)
-{
- if (lo >= 0x9f)
- return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e);
- else
- return ((hi * 2 - (hi >= 0xe0 ? 0x161 : 0xe1)) << 8) |
- (lo - (lo >= 0x7f ? 0x20 : 0x1f));
-}
-
-static int
-jis2sjis (register int hi, register int lo)
-{
- if (hi & 1)
- return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) |
- (lo + (lo >= 0x60 ? 0x20 : 0x1f));
- else
- return ((hi / 2 + (hi < 0x5f ? 0x70 : 0xb0)) << 8) | (lo + 0x7e);
-}
-
-/*******************************************************************
- Convert FROM contain JIS codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-jis8_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to JIS codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_jis8 (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_kso;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN/KANA */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN/KANA */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain 7 bits JIS codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-jis7_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else if (is_so (*from)) {
- shifted = _KJ_KANA; /* to KANA */
- from++;
- } else if (is_si (*from)) {
- shifted = _KJ_ROMAN; /* to ROMAN */
- from++;
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- case _KJ_KANA:
- *out++ = ((int) from[0]) + 0x80;
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to 7 bits JIS codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_jis7 (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN and through down */
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_kso;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (from[0])) {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- case _KJ_ROMAN: /* to KANA */
- *out++ = jis_so;
- shifted = _KJ_KANA;
- break;
- }
- *out++ = ((int) *from++) - 0x80;
- } else {
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN */
- shifted = _KJ_ROMAN;
- break;
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN */
- break;
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain 7 bits JIS(junet) codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-junet_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else if (is_juk1(from[1]) && is_juk2 (from[2])) {
- shifted = _KJ_KANA;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- case _KJ_KANA:
- *out++ = ((int) from[0]) + 0x80;
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to 7 bits JIS(junet) codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_junet (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_so2;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (from[0])) {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN */
- case _KJ_ROMAN: /* to KANA */
- *out++ = jis_esc;
- *out++ = junet_kana1;
- *out++ = junet_kana2;
- shifted = _KJ_KANA;
- break;
- }
- *out++ = ((int) *from++) - 0x80;
- } else {
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_si2;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_si2;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- HEX <-> SJIS
-********************************************************************/
-/* ":xx" -> a byte */
-static char *
-hex_to_sj (const char *from, BOOL overwrite)
-{
- char *sp, *dp;
-
- sp = (char *) from;
- dp = cvtbuf;
- while (*sp) {
- if (*sp == hex_tag && isxdigit (sp[1]) && isxdigit (sp[2])) {
- *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2]));
- sp += 3;
- } else
- *dp++ = *sp++;
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- kanji/kana -> ":xx"
-********************************************************************/
-static char *
-sj_to_hex (const char *from, BOOL overwrite)
-{
- unsigned char *sp, *dp;
-
- sp = (unsigned char*) from;
- dp = (unsigned char*) cvtbuf;
- while (*sp) {
- if (is_kana(*sp)) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else if (is_shift_jis (*sp) && is_shift_jis2 (sp[1])) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else
- *dp++ = *sp++;
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- kanji/kana -> ":xx"
-********************************************************************/
-static char *
-sj_to_cap (const char *from, BOOL overwrite)
-{
- unsigned char *sp, *dp;
-
- sp = (unsigned char*) from;
- dp = (unsigned char*) cvtbuf;
- while (*sp) {
- if (*sp >= 0x80) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else {
- *dp++ = *sp++;
- }
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- sj to sj
-********************************************************************/
-static char *
-sj_to_sj (const char *from, BOOL overwrite)
-{
- if (!overwrite) {
- strcpy (cvtbuf, (char *) from);
- return cvtbuf;
- } else {
- return (char *) from;
- }
-}
-
-/************************************************************************
- conversion:
- _dos_to_unix _unix_to_dos
-************************************************************************/
-
-char* (*_dos_to_unix) (const char *str, BOOL overwrite) = sj_to_sj;
-char* (*_unix_to_dos) (const char *str, BOOL overwrite) = sj_to_sj;
-
-static int
-setup_string_function (int codes)
-{
- switch (codes) {
- default:
- case SJIS_CODE:
- _dos_to_unix = sj_to_sj;
- _unix_to_dos = sj_to_sj;
-
- break;
-
- case EUC_CODE:
- _dos_to_unix = sj_to_euc;
- _unix_to_dos = euc_to_sj;
- break;
-
- case JIS7_CODE:
- _dos_to_unix = sj_to_jis7;
- _unix_to_dos = jis7_to_sj;
- break;
-
- case JIS8_CODE:
- _dos_to_unix = sj_to_jis8;
- _unix_to_dos = jis8_to_sj;
- break;
-
- case JUNET_CODE:
- _dos_to_unix = sj_to_junet;
- _unix_to_dos = junet_to_sj;
- break;
-
- case HEX_CODE:
- _dos_to_unix = sj_to_hex;
- _unix_to_dos = hex_to_sj;
- break;
-
- case CAP_CODE:
- _dos_to_unix = sj_to_cap;
- _unix_to_dos = hex_to_sj;
- break;
- }
- return codes;
-}
-
-/*
- * Interpret coding system.
- */
-int
-interpret_coding_system (char *str, int def)
-{
- int codes = def;
-
- if (strequal (str, "sjis")) {
- codes = SJIS_CODE;
- } else if (strequal (str, "euc")) {
- codes = EUC_CODE;
- } else if (strequal (str, "cap")) {
- codes = CAP_CODE;
- hex_tag = HEXTAG;
- } else if (strequal (str, "hex")) {
- codes = HEX_CODE;
- hex_tag = HEXTAG;
- } else if (strncasecmp (str, "hex", 3)) {
- codes = HEX_CODE;
- hex_tag = (str[3] ? str[3] : HEXTAG);
- } else if (strequal (str, "j8bb")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "j8bj") || strequal (str, "jis8")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "j8bh")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "j8@b")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "j8@j")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "j8@h")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- } else if (strequal (str, "j7bb")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "j7bj") || strequal (str, "jis7")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "j7bh")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "j7@b")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "j7@j")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "j7@h")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- } else if (strequal (str, "jubb")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "jubj") || strequal (str, "junet")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "jubh")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "ju@b")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "ju@j")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "ju@h")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- }
- return setup_string_function (codes);
-}
-#else
-int kanji_dummy_procedure(void)
-{return 0;}
-#endif /* KANJI */
diff --git a/source/lib/md4.c b/source/lib/md4.c
index 485e231a784..95fd90512cc 100644
--- a/source/lib/md4.c
+++ b/source/lib/md4.c
@@ -1,299 +1,170 @@
-#ifdef SMB_PASSWD
-/*
- This code is from rfc1186.
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
- /*
- ** ********************************************************************
- ** md4.c -- Implementation of MD4 Message Digest Algorithm **
- ** Updated: 2/16/90 by Ronald L. Rivest **
- ** (C) 1990 RSA Data Security, Inc. **
- ** ********************************************************************
- */
+#include "includes.h"
- /*
- ** To use MD4:
- ** -- Include md4.h in your program
- ** -- Declare an MDstruct MD to hold the state of the digest
- ** computation.
- ** -- Initialize MD using MDbegin(&MD)
- ** -- For each full block (64 bytes) X you wish to process, call
- ** MDupdate(&MD,X,512)
- ** (512 is the number of bits in a full block.)
- ** -- For the last block (less than 64 bytes) you wish to process,
- ** MDupdate(&MD,X,n)
- ** where n is the number of bits in the partial block. A partial
- ** block terminates the computation, so every MD computation
- ** should terminate by processing a partial block, even if it
- ** has n = 0.
- ** -- The message digest is available in MD.buffer[0] ...
- ** MD.buffer[3]. (Least-significant byte of each word
- ** should be output first.)
- ** -- You can print out the digest using MDprint(&MD)
- */
+/* NOTE: This code makes no attempt to be fast!
- /* Implementation notes:
- ** This implementation assumes that ints are 32-bit quantities.
- ** If the machine stores the least-significant byte of an int in the
- ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
- ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
- ** should be set to FALSE. Note that on machines with LOWBYTEFIRST
- ** FALSE the routine MDupdate modifies has a side-effect on its input
- ** array (the order of bytes in each word are reversed). If this is
- ** undesired a call to MDreverse(X) can reverse the bytes of X back
- ** into order after each call to MDupdate.
- */
-
-#define TRUE 1
-#define FALSE 0
-
- /* Compile-time includes
- */
-
-#include <stdio.h>
-#include "md4.h"
-
-#define uchar unsigned char
-#define int16 unsigned short
-#define uint32 unsigned int
-
-#include "byteorder.h"
-
- /* Compile-time declarations of MD4 "magic constants".
- */
-#define I0 0x67452301 /* Initial values for MD buffer */
-#define I1 0xefcdab89
-#define I2 0x98badcfe
-#define I3 0x10325476
-#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
-#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
- /* C2 and C3 are from Knuth, The Art of Programming, Volume 2
- ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
- ** Table 2, page 660.
- */
-
-#define fs1 3 /* round 1 shift amounts */
-#define fs2 7
-#define fs3 11
-#define fs4 19
-#define gs1 3 /* round 2 shift amounts */
-#define gs2 5
-#define gs3 9
-#define gs4 13
-#define hs1 3 /* round 3 shift amounts */
-#define hs2 9
-#define hs3 11
-#define hs4 15
-
- /* Compile-time macro declarations for MD4.
- ** Note: The "rot" operator uses the variable "tmp".
- ** It assumes tmp is declared as unsigned int, so that the >>
- ** operator will shift in zeros rather than extending the sign bit.
- */
-#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
-#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
-#define h(X,Y,Z) (X^Y^Z)
-#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
-#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
-#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
-#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+ It assumes that a int is at least 32 bits long
+*/
- /* MDprint(MDp)
- ** Print message digest buffer MDp as 32 hexadecimal digits.
- ** Order is from low-order byte of buffer[0] to high-order byte of
- ** buffer[3].
- ** Each byte is printed with high-order hexadecimal digit first.
- ** This is a user-callable routine.
- */
- void
- MDprint(MDp)
- MDptr MDp;
- { int i,j;
- for (i=0;i<4;i++)
- for (j=0;j<32;j=j+8)
- printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
- }
+static uint32 A, B, C, D;
+
+static uint32 F(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | ((~X)&Z);
+}
+
+static uint32 G(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | (X&Z) | (Y&Z);
+}
+
+static uint32 H(uint32 X, uint32 Y, uint32 Z)
+{
+ return X^Y^Z;
+}
+
+static uint32 lshift(uint32 x, int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32 *M)
+{
+ int j;
+ uint32 AA, BB, CC, DD;
+ uint32 X[16];
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB; C += CC; D += DD;
+
+ A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+ C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+}
+
+static void copy64(uint32 *M, const unsigned char *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out, uint32 x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void mdfour(unsigned char *out, const unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ uint32 M[16];
+ uint32 b = n * 8;
+ int i;
+
+ A = 0x67452301;
+ B = 0xefcdab89;
+ C = 0x98badcfe;
+ D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ }
- /* MDbegin(MDp)
- ** Initialize message digest buffer MDp.
- ** This is a user-callable routine.
- */
- void
- MDbegin(MDp)
- MDptr MDp;
- { int i;
- MDp->buffer[0] = I0;
- MDp->buffer[1] = I1;
- MDp->buffer[2] = I2;
- MDp->buffer[3] = I3;
- for (i=0;i<8;i++) MDp->count[i] = 0;
- MDp->done = 0;
- }
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
- /* MDreverse(X)
- ** Reverse the byte-ordering of every int in X.
- ** Assumes X is an array of 16 ints.
- ** The macro revx reverses the byte-ordering of the next word of X.
- */
- void MDreverse(X)
- unsigned int *X;
- { register unsigned int t;
- register unsigned int i;
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ copy64(M, buf);
- for(i = 0; i < 16; i++) {
- t = X[i];
- SIVAL(X,i*4,t);
- }
- }
+ copy4(out, A);
+ copy4(out+4, B);
+ copy4(out+8, C);
+ copy4(out+12, D);
- /* MDblock(MDp,X)
- ** Update message digest buffer MDp->buffer using 16-word data block X.
- ** Assumes all 16 words of X are full of data.
- ** Does not update MDp->count.
- ** This routine is not user-callable.
- */
- static void
- MDblock(MDp,X)
- MDptr MDp;
- unsigned int *X;
- {
- register unsigned int tmp, A, B, C, D;
- MDreverse(X);
- A = MDp->buffer[0];
- B = MDp->buffer[1];
- C = MDp->buffer[2];
- D = MDp->buffer[3];
- /* Update the message digest buffer */
- ff(A , B , C , D , 0 , fs1); /* Round 1 */
- ff(D , A , B , C , 1 , fs2);
- ff(C , D , A , B , 2 , fs3);
- ff(B , C , D , A , 3 , fs4);
- ff(A , B , C , D , 4 , fs1);
- ff(D , A , B , C , 5 , fs2);
- ff(C , D , A , B , 6 , fs3);
- ff(B , C , D , A , 7 , fs4);
- ff(A , B , C , D , 8 , fs1);
- ff(D , A , B , C , 9 , fs2);
- ff(C , D , A , B , 10 , fs3);
- ff(B , C , D , A , 11 , fs4);
- ff(A , B , C , D , 12 , fs1);
- ff(D , A , B , C , 13 , fs2);
- ff(C , D , A , B , 14 , fs3);
- ff(B , C , D , A , 15 , fs4);
- gg(A , B , C , D , 0 , gs1); /* Round 2 */
- gg(D , A , B , C , 4 , gs2);
- gg(C , D , A , B , 8 , gs3);
- gg(B , C , D , A , 12 , gs4);
- gg(A , B , C , D , 1 , gs1);
- gg(D , A , B , C , 5 , gs2);
- gg(C , D , A , B , 9 , gs3);
- gg(B , C , D , A , 13 , gs4);
- gg(A , B , C , D , 2 , gs1);
- gg(D , A , B , C , 6 , gs2);
- gg(C , D , A , B , 10 , gs3);
- gg(B , C , D , A , 14 , gs4);
- gg(A , B , C , D , 3 , gs1);
- gg(D , A , B , C , 7 , gs2);
- gg(C , D , A , B , 11 , gs3);
- gg(B , C , D , A , 15 , gs4);
- hh(A , B , C , D , 0 , hs1); /* Round 3 */
- hh(D , A , B , C , 8 , hs2);
- hh(C , D , A , B , 4 , hs3);
- hh(B , C , D , A , 12 , hs4);
- hh(A , B , C , D , 2 , hs1);
- hh(D , A , B , C , 10 , hs2);
- hh(C , D , A , B , 6 , hs3);
- hh(B , C , D , A , 14 , hs4);
- hh(A , B , C , D , 1 , hs1);
- hh(D , A , B , C , 9 , hs2);
- hh(C , D , A , B , 5 , hs3);
- hh(B , C , D , A , 13 , hs4);
- hh(A , B , C , D , 3 , hs1);
- hh(D , A , B , C , 11 , hs2);
- hh(C , D , A , B , 7 , hs3);
- hh(B , C , D , A , 15 , hs4);
- MDp->buffer[0] += A;
- MDp->buffer[1] += B;
- MDp->buffer[2] += C;
- MDp->buffer[3] += D;
- }
+ A = B = C = D = 0;
+}
- /* MDupdate(MDp,X,count)
- ** Input: MDp -- an MDptr
- ** X -- a pointer to an array of unsigned characters.
- ** count -- the number of bits of X to use.
- ** (if not a multiple of 8, uses high bits of last byte.)
- ** Update MDp using the number of bits of X given by count.
- ** This is the basic input routine for an MD4 user.
- ** The routine completes the MD computation when count < 512, so
- ** every MD computation should end with one call to MDupdate with a
- ** count less than 512. A call with count 0 will be ignored if the
- ** MD has already been terminated (done != 0), so an extra call with
- ** count 0 can be given as a "courtesy close" to force termination
- ** if desired.
- */
- void
- MDupdate(MDp,X,count)
- MDptr MDp;
- unsigned char *X;
- unsigned int count;
- { unsigned int i, tmp, bit, byte, mask;
- unsigned char XX[64];
- unsigned char *p;
- /* return with no error if this is a courtesy close with count
- ** zero and MDp->done is true.
- */
- if (count == 0 && MDp->done) return;
- /* check to see if MD is already done and report error */
- if (MDp->done)
- { printf("\nError: MDupdate MD already done."); return; }
- /* Add count to MDp->count */
- tmp = count;
- p = MDp->count;
- while (tmp)
- { tmp += *p;
- *p++ = tmp;
- tmp = tmp >> 8;
- }
- /* Process data */
- if (count == 512)
- { /* Full block of data to handle */
- MDblock(MDp,(unsigned int *)X);
- }
- else if (count > 512) /* Check for count too large */
- { printf("\nError: MDupdate called with illegal count value %d."
- ,count);
- return;
- }
- else /* partial block -- must be last block so finish up */
- { /* Find out how many bytes and residual bits there are */
- byte = count >> 3;
- bit = count & 7;
- /* Copy X into XX since we need to modify it */
- for (i=0;i<=byte;i++) XX[i] = X[i];
- for (i=byte+1;i<64;i++) XX[i] = 0;
- /* Add padding '1' bit and low-order zeros in last byte */
- mask = 1 << (7 - bit);
- XX[byte] = (XX[byte] | mask) & ~( mask - 1);
- /* If room for bit count, finish up with this block */
- if (byte <= 55)
- { for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- else /* need to do two blocks to finish up */
- { MDblock(MDp,(unsigned int *)XX);
- for (i=0;i<56;i++) XX[i] = 0;
- for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- /* Set flag saying we're done with MD computation */
- MDp->done = 1;
- }
- }
- /*
- ** End of md4.c
- */
-#else
-void md4_dummy() {;}
-#endif
diff --git a/source/lib/md5.c b/source/lib/md5.c
new file mode 100644
index 00000000000..627725bb252
--- /dev/null
+++ b/source/lib/md5.c
@@ -0,0 +1,245 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code slightly modified to fit into Samba by
+ abartlet@samba.org Jun 2001 */
+
+#include "includes.h"
+
+#include "md5.h"
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ register uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/source/lib/messages.c b/source/lib/messages.c
new file mode 100644
index 00000000000..f63e2c47668
--- /dev/null
+++ b/source/lib/messages.c
@@ -0,0 +1,430 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba internal messaging functions
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ @file messages.c
+
+ This module is used for internal messaging between Samba daemons.
+
+ The idea is that if a part of Samba wants to do communication with
+ another Samba process then it will do a message_register() of a
+ dispatch function, and use message_send_pid() to send messages to
+ that process.
+
+ The dispatch function is given the pid of the sender, and it can
+ use that to reply by message_send_pid(). See ping_message() for a
+ simple example.
+
+ This system doesn't have any inherent size limitations but is not
+ very efficient for large messages or when messages are sent in very
+ quick succession.
+
+*/
+
+#include "includes.h"
+
+/* the locking database handle */
+static TDB_CONTEXT *tdb;
+static int received_signal;
+
+/* change the message version with any incompatible changes in the protocol */
+#define MESSAGE_VERSION 1
+
+struct message_rec {
+ int msg_version;
+ int msg_type;
+ pid_t dest;
+ pid_t src;
+ size_t len;
+};
+
+/* we have a linked list of dispatch handlers */
+static struct dispatch_fns {
+ struct dispatch_fns *next, *prev;
+ int msg_type;
+ void (*fn)(int msg_type, pid_t pid, void *buf, size_t len);
+} *dispatch_fns;
+
+/****************************************************************************
+ Notifications come in as signals.
+****************************************************************************/
+
+static void sig_usr1(void)
+{
+ received_signal = 1;
+ sys_select_signal();
+}
+
+/****************************************************************************
+ A useful function for testing the message system.
+****************************************************************************/
+
+void ping_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ char *msg = buf ? buf : "none";
+ DEBUG(1,("INFO: Received PING message from PID %u [%s]\n",(unsigned int)src, msg));
+ message_send_pid(src, MSG_PONG, buf, len, True);
+}
+
+/****************************************************************************
+ Return current debug level.
+****************************************************************************/
+
+void debuglevel_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %u\n",(unsigned int)src));
+ message_send_pid(src, MSG_DEBUGLEVEL, DEBUGLEVEL_CLASS, sizeof(DEBUGLEVEL_CLASS), True);
+}
+
+/****************************************************************************
+ Initialise the messaging functions.
+****************************************************************************/
+
+BOOL message_init(void)
+{
+ if (tdb) return True;
+
+ tdb = tdb_open_log(lock_path("messages.tdb"),
+ 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR|O_CREAT,0600);
+
+ if (!tdb) {
+ DEBUG(0,("ERROR: Failed to initialise messages database\n"));
+ return False;
+ }
+
+ CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
+
+ message_register(MSG_PING, ping_message);
+ message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
+
+ return True;
+}
+
+/*******************************************************************
+ Form a static tdb key from a pid.
+******************************************************************/
+
+static TDB_DATA message_key_pid(pid_t pid)
+{
+ static char key[20];
+ TDB_DATA kbuf;
+
+ slprintf(key, sizeof(key)-1, "PID/%d", (int)pid);
+
+ kbuf.dptr = (char *)key;
+ kbuf.dsize = strlen(key)+1;
+ return kbuf;
+}
+
+/****************************************************************************
+ Notify a process that it has a message. If the process doesn't exist
+ then delete its record in the database.
+****************************************************************************/
+
+static BOOL message_notify(pid_t pid)
+{
+ if (kill(pid, SIGUSR1) == -1) {
+ if (errno == ESRCH) {
+ DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
+ tdb_delete(tdb, message_key_pid(pid));
+ } else {
+ DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
+ }
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Send a message to a particular pid.
+****************************************************************************/
+
+BOOL message_send_pid(pid_t pid, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
+{
+ TDB_DATA kbuf;
+ TDB_DATA dbuf;
+ struct message_rec rec;
+ void *p;
+
+ rec.msg_version = MESSAGE_VERSION;
+ rec.msg_type = msg_type;
+ rec.dest = pid;
+ rec.src = sys_getpid();
+ rec.len = len;
+
+ kbuf = message_key_pid(pid);
+
+ /* lock the record for the destination */
+ tdb_chainlock(tdb, kbuf);
+
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ /* its a new record */
+ p = (void *)malloc(len + sizeof(rec));
+ if (!p) goto failed;
+
+ memcpy(p, &rec, sizeof(rec));
+ if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len);
+
+ dbuf.dptr = p;
+ dbuf.dsize = len + sizeof(rec);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ SAFE_FREE(p);
+ goto ok;
+ }
+
+ if (!duplicates_allowed) {
+ char *ptr;
+ struct message_rec prec;
+
+ for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) {
+ /*
+ * First check if the message header matches, then, if it's a non-zero
+ * sized message, check if the data matches. If so it's a duplicate and
+ * we can discard it. JRA.
+ */
+
+ if (!memcmp(ptr, &rec, sizeof(rec))) {
+ if (!len || (len && !memcmp( ptr + sizeof(rec), (char *)buf, len))) {
+ DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+ }
+ }
+ memcpy(&prec, ptr, sizeof(prec));
+ ptr += sizeof(rec) + prec.len;
+ }
+ }
+
+ /* we're adding to an existing entry */
+ p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
+ if (!p) goto failed;
+
+ memcpy(p, dbuf.dptr, dbuf.dsize);
+ memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
+ if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
+
+ SAFE_FREE(dbuf.dptr);
+ dbuf.dptr = p;
+ dbuf.dsize += len + sizeof(rec);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ SAFE_FREE(dbuf.dptr);
+
+ ok:
+ tdb_chainunlock(tdb, kbuf);
+ errno = 0; /* paranoia */
+ return message_notify(pid);
+
+ failed:
+ tdb_chainunlock(tdb, kbuf);
+ errno = 0; /* paranoia */
+ return False;
+}
+
+/****************************************************************************
+ Retrieve the next message for the current process.
+****************************************************************************/
+
+static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
+{
+ TDB_DATA kbuf;
+ TDB_DATA dbuf;
+ struct message_rec rec;
+
+ kbuf = message_key_pid(sys_getpid());
+
+ tdb_chainlock(tdb, kbuf);
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
+
+ memcpy(&rec, dbuf.dptr, sizeof(rec));
+
+ if (rec.msg_version != MESSAGE_VERSION) {
+ DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
+ goto failed;
+ }
+
+ if (rec.len > 0) {
+ (*buf) = (void *)malloc(rec.len);
+ if (!(*buf)) goto failed;
+
+ memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
+ } else {
+ *buf = NULL;
+ }
+
+ *len = rec.len;
+ *msg_type = rec.msg_type;
+ *src = rec.src;
+
+ if (dbuf.dsize - (sizeof(rec)+rec.len) > 0)
+ memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
+ dbuf.dsize -= sizeof(rec)+rec.len;
+
+ if (dbuf.dsize == 0)
+ tdb_delete(tdb, kbuf);
+ else
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+
+ failed:
+ tdb_chainunlock(tdb, kbuf);
+ return False;
+}
+
+/****************************************************************************
+ Receive and dispatch any messages pending for this process.
+ Notice that all dispatch handlers for a particular msg_type get called,
+ so you can register multiple handlers for a message.
+****************************************************************************/
+
+void message_dispatch(void)
+{
+ int msg_type;
+ pid_t src;
+ void *buf;
+ size_t len;
+ struct dispatch_fns *dfn;
+
+ if (!received_signal) return;
+
+ DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
+
+ received_signal = 0;
+
+ while (message_recv(&msg_type, &src, &buf, &len)) {
+ for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
+ if (dfn->msg_type == msg_type) {
+ DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
+ dfn->fn(msg_type, src, buf, len);
+ }
+ }
+ SAFE_FREE(buf);
+ }
+}
+
+/****************************************************************************
+ Register a dispatch function for a particular message type.
+****************************************************************************/
+
+void message_register(int msg_type,
+ void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
+{
+ struct dispatch_fns *dfn;
+
+ dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
+
+ if (dfn != NULL) {
+
+ ZERO_STRUCTPN(dfn);
+
+ dfn->msg_type = msg_type;
+ dfn->fn = fn;
+
+ DLIST_ADD(dispatch_fns, dfn);
+ }
+ else {
+
+ DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
+ }
+}
+
+/****************************************************************************
+ De-register the function for a particular message type.
+****************************************************************************/
+
+void message_deregister(int msg_type)
+{
+ struct dispatch_fns *dfn, *next;
+
+ for (dfn = dispatch_fns; dfn; dfn = next) {
+ next = dfn->next;
+ if (dfn->msg_type == msg_type) {
+ DLIST_REMOVE(dispatch_fns, dfn);
+ SAFE_FREE(dfn);
+ }
+ }
+}
+
+struct msg_all {
+ int msg_type;
+ void *buf;
+ size_t len;
+ BOOL duplicates;
+};
+
+/****************************************************************************
+ Send one of the messages for the broadcast.
+****************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct connections_data crec;
+ struct msg_all *msg_all = (struct msg_all *)state;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum != -1)
+ return 0;
+
+ /* if the msg send fails because the pid was not found (i.e. smbd died),
+ * the msg has already been deleted from the messages.tdb.*/
+ if (!message_send_pid(crec.pid, msg_all->msg_type, msg_all->buf, msg_all->len,
+ msg_all->duplicates)) {
+
+ /* if the pid was not found delete the entry from connections.tdb */
+ if (errno == ESRCH) {
+ DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
+ (unsigned int)crec.pid, crec.cnum, crec.name));
+ tdb_delete(the_tdb, kbuf);
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+ This is a useful function for sending messages to all smbd processes.
+ It isn't very efficient, but should be OK for the sorts of applications that
+ use it. When we need efficient broadcast we can add it.
+****************************************************************************/
+
+BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
+{
+ struct msg_all msg_all;
+
+ msg_all.msg_type = msg_type;
+ msg_all.buf = buf;
+ msg_all.len = len;
+ msg_all.duplicates = duplicates_allowed;
+
+ tdb_traverse(conn_tdb, traverse_fn, &msg_all);
+ return True;
+}
diff --git a/source/lib/ms_fnmatch.c b/source/lib/ms_fnmatch.c
new file mode 100644
index 00000000000..cc54ffb68eb
--- /dev/null
+++ b/source/lib/ms_fnmatch.c
@@ -0,0 +1,226 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ filename matching routine
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ This module was originally based on fnmatch.c copyright by the Free
+ Software Foundation. It bears little resemblence to that code now
+*/
+
+
+#if FNMATCH_TEST
+#include <stdio.h>
+#include <stdlib.h>
+#else
+#include "includes.h"
+#endif
+
+/*
+ bugger. we need a separate wildcard routine for older versions
+ of the protocol. This is not yet perfect, but its a lot
+ better than what we had */
+static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
+ const smb_ucs2_t *string)
+{
+ const smb_ucs2_t *p = pattern, *n = string;
+ smb_ucs2_t c;
+
+ if (strcmp_wa(p, "?")==0 && strcmp_wa(n, ".")) goto match;
+
+ while ((c = *p++)) {
+ switch (c) {
+ case UCS2_CHAR('.'):
+ if (! *n) goto next;
+ if (*n != UCS2_CHAR('.')) goto nomatch;
+ n++;
+ break;
+
+ case UCS2_CHAR('?'):
+ if (! *n) goto next;
+ if ((*n == UCS2_CHAR('.') &&
+ n[1] != UCS2_CHAR('.')) || ! *n)
+ goto next;
+ n++;
+ break;
+
+ case UCS2_CHAR('>'):
+ if (! *n) goto next;
+ if (n[0] == UCS2_CHAR('.')) {
+ if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+ }
+ n++;
+ break;
+
+ case UCS2_CHAR('*'):
+ if (! *n) goto next;
+ if (! *p) goto match;
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ }
+ break;
+
+ case UCS2_CHAR('<'):
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n == UCS2_CHAR('.') &&
+ !strchr_w(n+1,UCS2_CHAR('.'))) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case UCS2_CHAR('"'):
+ if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n != UCS2_CHAR('.')) goto nomatch;
+ n++;
+ break;
+
+ default:
+ if (c != *n) goto nomatch;
+ n++;
+ }
+ }
+
+ if (! *n) goto match;
+
+ nomatch:
+ /*
+ if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
+ */
+ return -1;
+
+next:
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+
+ match:
+ /*
+ if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
+ */
+ return 0;
+}
+
+static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern, const smb_ucs2_t *string)
+{
+ if (!strpbrk_wa(pattern, "?*<>\"")) {
+ smb_ucs2_t s[] = {UCS2_CHAR('.'), 0};
+ if (strcmp_wa(string,"..") == 0) string = s;
+ return strcasecmp_w(pattern, string);
+ }
+
+ if (strcmp_wa(string,"..") == 0 || strcmp_wa(string,".") == 0) {
+ smb_ucs2_t dot[] = {UCS2_CHAR('.'), 0};
+ smb_ucs2_t dotdot[] = {UCS2_CHAR('.'), UCS2_CHAR('.'), 0};
+ return ms_fnmatch_lanman_core(pattern, dotdot) &&
+ ms_fnmatch_lanman_core(pattern, dot);
+ }
+
+ return ms_fnmatch_lanman_core(pattern, string);
+}
+
+
+/* the following function was derived using the masktest utility -
+ after years of effort we finally have a perfect MS wildcard
+ matching routine!
+
+ NOTE: this matches only filenames with no directory component
+
+ Returns 0 on match, -1 on fail.
+*/
+static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string, int protocol)
+{
+ const smb_ucs2_t *p = pattern, *n = string;
+ smb_ucs2_t c;
+
+ if (protocol <= PROTOCOL_LANMAN2) {
+ return ms_fnmatch_lanman1(pattern, string);
+ }
+
+ while ((c = *p++)) {
+ switch (c) {
+ case UCS2_CHAR('?'):
+ if (! *n) return -1;
+ n++;
+ break;
+
+ case UCS2_CHAR('>'):
+ if (n[0] == UCS2_CHAR('.')) {
+ if (! n[1] && ms_fnmatch_w(p, n+1, protocol) == 0) return 0;
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ return -1;
+ }
+ if (! *n) return ms_fnmatch_w(p, n, protocol);
+ n++;
+ break;
+
+ case UCS2_CHAR('*'):
+ for (; *n; n++) {
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ }
+ break;
+
+ case UCS2_CHAR('<'):
+ for (; *n; n++) {
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case UCS2_CHAR('"'):
+ if (*n == 0 && ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ if (*n != UCS2_CHAR('.')) return -1;
+ n++;
+ break;
+
+ default:
+ if (c != *n) return -1;
+ n++;
+ }
+ }
+
+ if (! *n) return 0;
+
+ return -1;
+}
+
+
+int ms_fnmatch(const char *pattern, const char *string, int protocol)
+{
+ wpstring p, s;
+ int ret;
+
+ pstrcpy_wa(p, pattern);
+ pstrcpy_wa(s, string);
+
+ ret = ms_fnmatch_w(p, s, protocol);
+/* DEBUG(0,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, ret)); */
+ return ret;
+}
+
+/* a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string)
+{
+ return ms_fnmatch(pattern, string, PROTOCOL_NT1);
+}
diff --git a/source/lib/netatalk.c b/source/lib/netatalk.c
new file mode 100644
index 00000000000..654d3f78d4c
--- /dev/null
+++ b/source/lib/netatalk.c
@@ -0,0 +1,156 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ netatalk.c : routines for improving interaction between Samba and netatalk.
+ Copyright (C) John D. Blair <jdblair@cobaltnet.com> 1998
+ Cobalt Networks, Inc.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_NETATALK
+
+/*****************
+ ntalk_resourcepath: creates the path to the netatalk resource fork for
+ a given file
+
+ fname: normal filename
+ doublename: buffer that will contain the location of the resource fork
+ length: length of this buffer (to prevent overflows)
+
+ NOTE: doesn't currently gracefully deal with buffer overflows- it just
+ doesn't allow them to occur.
+******************/
+void ntalk_resourcepath(const char *fname, char *doublename, const int length)
+{
+ int i;
+ int charnum;
+ int lastslash;
+ char appledouble[] = APPLEDOUBLE;
+
+ /* copy fname to doublename and find last slash */
+ for (i = 0; (fname[i] != 0) && (i <= length); i++) {
+ if (fname[i] == '/') {
+ lastslash = i;
+ }
+ doublename[i] = fname[i];
+ }
+ lastslash++; /* location just after last slash */
+
+ /* insert .AppleDouble */
+ charnum = lastslash;
+ for (i = 0; (appledouble[i] != 0) && (i <= length); i++) {
+ doublename[charnum] = appledouble[i];
+ charnum++;
+ }
+
+ /* append last part of file name */
+ for (i = lastslash; (fname[i] != 0) && (i <= length); i++) {
+ doublename[charnum] = fname[i];
+ charnum++;
+ }
+
+ doublename[charnum] = 0;
+}
+
+/**********************
+ ntalk_mkresdir: creates a new .AppleDouble directory (if necessary)
+ for the resource fork of a specified file
+**********************/
+int ntalk_mkresdir(const char *fname)
+{
+ char fdir[255];
+ int i;
+ int lastslash;
+ SMB_STRUCT_STAT dirstats;
+ char appledouble[] = APPLEDOUBLE;
+
+ /* find directory containing fname */
+ for (i = 0; (fname[i] != 0) && (i <= 254); i++) {
+ fdir[i] = fname[i];
+ if (fdir[i] == '/') {
+ lastslash = i;
+ }
+ }
+ lastslash++;
+ fdir[lastslash] = 0;
+ sys_lstat(fdir, &dirstats);
+
+ /* append .AppleDouble */
+ for (i = 0; (appledouble[i] != 0) && (lastslash <= 254); i++) {
+ fdir[lastslash] = appledouble[i];
+ lastslash++;
+ }
+ fdir[lastslash] = 0;
+
+ /* create this directory */
+ /* silently ignore EEXIST error */
+ if ((mkdir(fdir, dirstats.st_mode) < 0) && (errno != EEXIST)) {
+ return errno;
+ }
+
+ /* set ownership of this dir to the same as its parent */
+ /* holy race condition, batman! */
+ /* warning: this doesn't check for errors */
+ chown(fdir, dirstats.st_uid, dirstats.st_gid);
+
+ printf("%s\n", fdir);
+
+ return 1;
+}
+
+/**********************
+ ntalk_unlink: unlink a file and its resource fork
+**********************/
+int ntalk_unlink(const char *fname)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ unlink(buf);
+ return unlink(fname);
+}
+
+/**********************
+ ntalk_chown: chown a file and its resource fork
+**********************/
+int ntalk_chown(const char *fname, const uid_t uid, const gid_t gid)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ chown(buf, uid, gid);
+ return chown(fname, uid, gid);
+}
+
+/**********************
+ ntalk_chmod: chmod a file and its resource fork
+**********************/
+int ntalk_chmod(const char *fname, mode_t perms)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ chmod(buf, perms);
+ return chmod(fname, perms);
+}
+
+#endif /* WITH_NETATALK */
diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c
new file mode 100644
index 00000000000..a9b2da0d7fd
--- /dev/null
+++ b/source/lib/pidfile.c
@@ -0,0 +1,110 @@
+/* this code is broken - there is a race condition with the unlink (tridge) */
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ pidfile handling
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK
+#endif
+
+/* return the pid in a pidfile. return 0 if the process (or pidfile)
+ does not exist */
+pid_t pidfile_pid(char *name)
+{
+ int fd;
+ char pidstr[20];
+ unsigned ret;
+ pstring pidFile;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
+ if (fd == -1) {
+ return 0;
+ }
+
+ ZERO_ARRAY(pidstr);
+
+ if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
+ goto noproc;
+ }
+
+ ret = atoi(pidstr);
+
+ if (!process_exists((pid_t)ret)) {
+ goto noproc;
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_RDLCK)) {
+ /* we could get the lock - it can't be a Samba process */
+ goto noproc;
+ }
+
+ close(fd);
+ return (pid_t)ret;
+
+ noproc:
+ close(fd);
+ unlink(pidFile);
+ return 0;
+}
+
+/* create a pid file in the lock directory. open it and leave it locked */
+void pidfile_create(char *name)
+{
+ int fd;
+ char buf[20];
+ pstring pidFile;
+ pid_t pid;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ pid = pidfile_pid(name);
+ if (pid != 0) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, (int)pid));
+ exit(1);
+ }
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (fd == -1) {
+ DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
+ strerror(errno)));
+ exit(1);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
+ name, pidFile, strerror(errno)));
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) sys_getpid());
+ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ DEBUG(0,("ERROR: can't write to file %s: %s\n",
+ pidFile, strerror(errno)));
+ exit(1);
+ }
+ /* Leave pid file open & locked for the duration... */
+}
diff --git a/source/lib/readline.c b/source/lib/readline.c
new file mode 100644
index 00000000000..325b70d2cf4
--- /dev/null
+++ b/source/lib/readline.c
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_NEW_LIBREADLINE
+# define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0 (approximately) */
+# define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+
+/****************************************************************************
+display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+static char *smb_readline_replacement(char *prompt, void (*callback)(void),
+ char **(completion_fn)(char *text,
+ int start,
+ int end))
+{
+ fd_set fds;
+ static pstring line;
+ struct timeval timeout;
+ int fd = fileno(stdin);
+ char *ret;
+
+ x_fprintf(dbf, "%s", prompt);
+ x_fflush(dbf);
+
+ while (1) {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ if (sys_select_intr(fd+1,&fds,&timeout) == 1) {
+ ret = fgets(line, sizeof(line), stdin);
+ return ret;
+ }
+ if (callback) callback();
+ }
+}
+
+/****************************************************************************
+display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+char *smb_readline(char *prompt, void (*callback)(void),
+ char **(completion_fn)(char *text, int start, int end))
+{
+#if HAVE_LIBREADLINE
+ char *ret;
+
+ /* Aargh! Readline does bizzare things with the terminal width
+ that mucks up expect(1). Set CLI_NO_READLINE in the environment
+ to force readline not to be used. */
+
+ if (getenv("CLI_NO_READLINE"))
+ return smb_readline_replacement(prompt, callback,
+ completion_fn);
+
+ if (completion_fn) {
+ /* The callback prototype has changed slightly between
+ different versions of Readline, so the same function
+ works in all of them to date, but we get compiler
+ warnings in some. */
+ rl_attempted_completion_function = RL_COMPLETION_CAST
+ completion_fn;
+ }
+
+ if (callback) rl_event_hook = (Function *)callback;
+ ret = readline(prompt);
+ if (ret && *ret) add_history(ret);
+ return ret;
+#else
+ return smb_readline_replacement(prompt, callback, completion_fn);
+#endif
+}
+
+/****************************************************************************
+history
+****************************************************************************/
+int cmd_history(void)
+{
+#if defined(HAVE_LIBREADLINE)
+ HIST_ENTRY **hlist;
+ int i;
+
+ hlist = history_list();
+
+ for (i = 0; hlist && hlist[i]; i++) {
+ DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+ }
+#else
+ DEBUG(0,("no history without readline support\n"));
+#endif
+
+ return 0;
+}
diff --git a/source/lib/replace.c b/source/lib/replace.c
new file mode 100644
index 00000000000..54ad36e1395
--- /dev/null
+++ b/source/lib/replace.c
@@ -0,0 +1,417 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+ void replace_dummy(void);
+ void replace_dummy(void) {}
+
+#ifndef HAVE_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+ int ftruncate(int f,SMB_OFF_T l)
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+}
+#endif /* HAVE_FTRUNCATE */
+
+
+#ifndef HAVE_STRLCPY
+/* like strncpy but does not 0 fill the buffer and always null
+ terminates. bufsize is the size of the destination buffer */
+ size_t strlcpy(char *d, const char *s, size_t bufsize)
+{
+ size_t len = strlen(s);
+ size_t ret = len;
+ if (bufsize <= 0) return 0;
+ if (len >= bufsize) len = bufsize-1;
+ memcpy(d, s, len);
+ d[len] = 0;
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null
+ terminates. bufsize is the length of the buffer, which should
+ be one more than the maximum resulting string length */
+ size_t strlcat(char *d, const char *s, size_t bufsize)
+{
+ size_t len1 = strlen(d);
+ size_t len2 = strlen(s);
+ size_t ret = len1 + len2;
+
+ if (len1+len2 >= bufsize) {
+ len2 = bufsize - (len1+1);
+ }
+ if (len2 > 0) {
+ memcpy(d+len1, s, len2);
+ d[len1+len2] = 0;
+ }
+ return ret;
+}
+#endif
+
+#ifndef HAVE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+Corrections by richard.kettlewell@kewill.com
+********************************************************************/
+
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+ time_t mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int n;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ n = t->tm_year + 1900 - 1;
+ epoch = (t->tm_year - 70) * YEAR +
+ ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+ y = t->tm_year + 1900;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+ }
+
+ return(epoch);
+}
+#endif /* !HAVE_MKTIME */
+
+
+
+#ifndef HAVE_RENAME
+/* Rename a file. (from libiberty in GNU binutils) */
+ int rename(const char *zfrom, const char *zto)
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#endif /* HAVE_RENAME */
+
+
+#ifndef HAVE_INNETGR
+#if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+ int innetgr(const char *group,const char *host,const char *user,const char *dom)
+{
+ char *hst, *usr, *dm;
+
+ setnetgrent(group);
+ while (getnetgrent(&hst, &usr, &dm)) {
+ if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
+ ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
+ ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ }
+ endnetgrent();
+ return (0);
+}
+#endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
+#endif /* HAVE_INNETGR */
+
+
+
+#ifndef HAVE_INITGROUPS
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+ int initgroups(char *name,gid_t id)
+{
+#ifndef HAVE_SETGROUPS
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: running without setgroups\n"));
+ done=1;
+ }
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ return(0);
+#else /* HAVE_SETGROUPS */
+ gid_t *grouplst = NULL;
+ int max_gr = groups_max();
+ int ret;
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ if((grouplst = (gid_t *)malloc(sizeof(gid_t) * max_gr)) == NULL) {
+ DEBUG(0,("initgroups: malloc fail !\n"));
+ return -1;
+ }
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ ret = sys_setgroups(i,grouplst);
+ SAFE_FREE(grouplst);
+ return ret;
+#endif /* HAVE_SETGROUPS */
+}
+#endif /* HAVE_INITGROUPS */
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+ long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+ }
+#endif
+
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have it's own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+ void *memmove(void *dest,const void *src,int size)
+{
+ unsigned long d,s;
+ int i;
+ if (dest==src || !size) return(dest);
+
+ d = (unsigned long)dest;
+ s = (unsigned long)src;
+
+ if ((d >= (s+size)) || (s >= (d+size))) {
+ /* no overlap */
+ memcpy(dest,src,size);
+ return(dest);
+ }
+
+ if (d < s) {
+ /* we can forward copy */
+ if (s-d >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=0;i<size;i++) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=0;i<size;i++) cdest[i] = csrc[i];
+ }
+ } else {
+ /* must backward copy */
+ if (d-s >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+ }
+ }
+ return(dest);
+}
+#endif /* HAVE_MEMMOVE */
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+ char *strdup(const char *s)
+{
+ size_t len;
+ char *ret;
+
+ if (!s) return(NULL);
+
+ len = strlen(s)+1;
+ ret = (char *)malloc(len);
+ if (!ret) return(NULL);
+ memcpy(ret,s,len);
+ return(ret);
+}
+#endif /* HAVE_STRDUP */
+
+#ifdef REPLACE_INET_NTOA
+char *rep_inet_ntoa(struct in_addr ip)
+{
+ unsigned char *p = (unsigned char *)&ip.s_addr;
+ static char buf[18];
+#if WORDS_BIGENDIAN
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+#else /* WORDS_BIGENDIAN */
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[3], (int)p[2], (int)p[1], (int)p[0]);
+#endif /* WORDS_BIGENDIAN */
+ return buf;
+}
+#endif /* REPLACE_INET_NTOA */
+
+#ifndef HAVE_STRTOUL
+#ifndef ULONG_MAX
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */
+#endif
+
+/*
+ * Convert a string to an unsigned long integer.
+ * Taken from libg++ - libiberty code.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+ unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s = nptr;
+ unsigned long acc;
+ int c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return (acc);
+}
+#endif /* HAVE_STRTOUL */
+
+#ifndef HAVE_SETLINEBUF
+ int setlinebuf(FILE *stream)
+{
+ return setvbuf(stream, (char *)NULL, _IOLBF, 0);
+}
+#endif /* HAVE_SETLINEBUF */
diff --git a/source/lib/select.c b/source/lib/select.c
new file mode 100644
index 00000000000..396ecb5dd6b
--- /dev/null
+++ b/source/lib/select.c
@@ -0,0 +1,129 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* this is here because it allows us to avoid a nasty race in signal handling.
+ We need to guarantee that when we get a signal we get out of a select immediately
+ but doing that involves a race condition. We can avoid the race by getting the
+ signal handler to write to a pipe that is in the select/poll list
+
+ this means all Samba signal handlers should call sys_select_signal()
+*/
+static pid_t initialised;
+static int select_pipe[2];
+static VOLATILE unsigned pipe_written, pipe_read;
+
+
+/*******************************************************************
+call this from all Samba signal handlers if you want to avoid a
+nasty signal race condition
+********************************************************************/
+void sys_select_signal(void)
+{
+ char c = 1;
+ if (!initialised) return;
+
+ if (pipe_written > pipe_read+256) return;
+
+ if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
+}
+
+/*******************************************************************
+like select() but avoids the signal race using a pipe
+it also guuarantees that fds on return only ever contains bits set
+for file descriptors that were readable
+********************************************************************/
+int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
+{
+ int ret, saved_errno;
+
+ if (initialised != sys_getpid()) {
+ pipe(select_pipe);
+
+ /*
+ * These next two lines seem to fix a bug with the Linux
+ * 2.0.x kernel (and probably other UNIXes as well) where
+ * the one byte read below can block even though the
+ * select returned that there is data in the pipe and
+ * the pipe_written variable was incremented. Thanks to
+ * HP for finding this one. JRA.
+ */
+
+ if(set_blocking(select_pipe[0],0)==-1)
+ smb_panic("select_pipe[0]: O_NONBLOCK failed.\n");
+ if(set_blocking(select_pipe[1],0)==-1)
+ smb_panic("select_pipe[1]: O_NONBLOCK failed.\n");
+
+ initialised = sys_getpid();
+ }
+
+ maxfd = MAX(select_pipe[0]+1, maxfd);
+ FD_SET(select_pipe[0], fds);
+ errno = 0;
+ ret = select(maxfd,fds,NULL,NULL,tval);
+
+ if (ret <= 0) {
+ FD_ZERO(fds);
+ }
+
+ if (FD_ISSET(select_pipe[0], fds)) {
+ FD_CLR(select_pipe[0], fds);
+ ret--;
+ if (ret == 0) {
+ ret = -1;
+ errno = EINTR;
+ }
+ }
+
+ saved_errno = errno;
+
+ while (pipe_written != pipe_read) {
+ char c;
+ /* Due to the linux kernel bug in 2.0.x, we
+ * always increment here even if the read failed... */
+ read(select_pipe[0], &c, 1);
+ pipe_read++;
+ }
+
+ errno = saved_errno;
+
+ return ret;
+}
+
+/*******************************************************************
+similar to sys_select() but catch EINTR and continue
+this is what sys_select() used to do in Samba
+********************************************************************/
+int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval)
+{
+ int ret;
+ fd_set fds2;
+
+ do {
+ fds2 = *fds;
+ ret = sys_select(maxfd, &fds2, tval);
+ } while (ret == -1 && errno == EINTR);
+
+ *fds = fds2;
+
+ return ret;
+}
diff --git a/source/lib/signal.c b/source/lib/signal.c
new file mode 100644
index 00000000000..9c78fad8862
--- /dev/null
+++ b/source/lib/signal.c
@@ -0,0 +1,140 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ signal handling functions
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+ while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+ ;
+
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+#else
+ ;
+#endif
+}
+
+/*******************************************************************
+ Block sigs.
+********************************************************************/
+
+void BlockSignals(BOOL block,int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+ if (block) {
+ sigblock(sigmask(signum));
+ } else {
+ sigsetmask(siggetmask() & ~sigmask(signum));
+ }
+#else
+ /* yikes! This platform can't block signals? */
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: No signal blocking available\n"));
+ done=1;
+ }
+#endif
+}
+
+/*******************************************************************
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+********************************************************************/
+
+void CatchSignal(int signum,void (*handler)(int ))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,NULL);
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ signal(signum, handler);
+#endif
+}
+
+/*******************************************************************
+ Ignore SIGCLD via whatever means is necessary for this OS.
+********************************************************************/
+
+void CatchChild(void)
+{
+ CatchSignal(SIGCLD, sig_cld);
+}
+
+/*******************************************************************
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+********************************************************************/
+
+void CatchChildLeaveStatus(void)
+{
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+}
diff --git a/source/lib/smbpasswd.c b/source/lib/smbpasswd.c
new file mode 100644
index 00000000000..dbd12d90db0
--- /dev/null
+++ b/source/lib/smbpasswd.c
@@ -0,0 +1,201 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ smbpasswd file format routines
+
+ Copyright (C) Andrew Tridgell 1992-1998
+ Modified by Jeremy Allison 1995.
+ Modified by Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*! \file lib/smbpasswd.c
+
+ The smbpasswd file is used to store encrypted passwords in a similar
+ fashion to the /etc/passwd file. The format is colon separated fields
+ with one user per line like so:
+
+ <username>:<uid>:<lanman hash>:<nt hash>:<acb info>:<last change time>
+
+ The username and uid must correspond to an entry in the /etc/passwd
+ file. The lanman and nt password hashes are 32 hex digits corresponding
+ to the 16-byte lanman and nt hashes respectively.
+
+ The password last change time is stored as a string of the format
+ LCD-<change time> where the change time is expressed as an
+
+ 'N' No password
+ 'D' Disabled
+ 'H' Homedir required
+ 'T' Temp account.
+ 'U' User account (normal)
+ 'M' MNS logon user account - what is this ?
+ 'W' Workstation account
+ 'S' Server account
+ 'L' Locked account
+ 'X' No Xpiry on password
+ 'I' Interdomain trust account
+
+*/
+
+#include "includes.h"
+
+/*! Convert 32 hex characters into a 16 byte array. */
+
+BOOL smbpasswd_gethexpwd(char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p) return (False);
+
+ for (i = 0; i < 32; i += 2)
+ {
+ hinybble = toupper(p[i]);
+ lonybble = toupper(p[i + 1]);
+
+ p1 = strchr_m(hexchars, hinybble);
+ p2 = strchr_m(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ {
+ return (False);
+ }
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/*! Convert a 16-byte array into 32 hex characters. */
+
+void smbpasswd_sethexpwd(fstring p, unsigned char *pwd, uint16 acb_info)
+{
+ if (pwd != NULL) {
+ int i;
+ for (i = 0; i < 16; i++)
+ slprintf(&p[i*2], 3, "%02X", pwd[i]);
+ } else {
+ if (acb_info & ACB_PWNOTREQ)
+ safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
+ else
+ safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
+ }
+}
+
+/*! Decode the account control bits (ACB) info from a string. */
+
+uint16 smbpasswd_decode_acb_info(const char *p)
+{
+ uint16 acb_info = 0;
+ BOOL finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[') return 0;
+
+ for (p++; *p && !finished; p++)
+ {
+ switch (*p) {
+ case 'N': /* 'N'o password. */
+ acb_info |= ACB_PWNOTREQ;
+ break;
+ case 'D': /* 'D'isabled. */
+ acb_info |= ACB_DISABLED;
+ break;
+ case 'H': /* 'H'omedir required. */
+ acb_info |= ACB_HOMDIRREQ;
+ break;
+ case 'T': /* 'T'emp account. */
+ acb_info |= ACB_TEMPDUP;
+ break;
+ case 'U': /* 'U'ser account (normal). */
+ acb_info |= ACB_NORMAL;
+ break;
+ case 'M': /* 'M'NS logon user account. What is this ? */
+ acb_info |= ACB_MNS;
+ break;
+ case 'W': /* 'W'orkstation account. */
+ acb_info |= ACB_WSTRUST;
+ break;
+ case 'S': /* 'S'erver account. */
+ acb_info |= ACB_SVRTRUST;
+ break;
+ case 'L': /* 'L'ocked account. */
+ acb_info |= ACB_AUTOLOCK;
+ break;
+ case 'X': /* No 'X'piry on password */
+ acb_info |= ACB_PWNOEXP;
+ break;
+ case 'I': /* 'I'nterdomain trust account. */
+ acb_info |= ACB_DOMTRUST;
+ break;
+
+ case ' ':
+ break;
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default:
+ finished = True;
+ break;
+ }
+ }
+
+ return acb_info;
+}
+
+/*! Encode account control bits (ACBs) into a string. */
+
+char *smbpasswd_encode_acb_info(uint16 acb_info)
+{
+ static fstring acct_str;
+ size_t i = 0;
+
+ acct_str[i++] = '[';
+
+ if (acb_info & ACB_PWNOTREQ ) acct_str[i++] = 'N';
+ if (acb_info & ACB_DISABLED ) acct_str[i++] = 'D';
+ if (acb_info & ACB_HOMDIRREQ) acct_str[i++] = 'H';
+ if (acb_info & ACB_TEMPDUP ) acct_str[i++] = 'T';
+ if (acb_info & ACB_NORMAL ) acct_str[i++] = 'U';
+ if (acb_info & ACB_MNS ) acct_str[i++] = 'M';
+ if (acb_info & ACB_WSTRUST ) acct_str[i++] = 'W';
+ if (acb_info & ACB_SVRTRUST ) acct_str[i++] = 'S';
+ if (acb_info & ACB_AUTOLOCK ) acct_str[i++] = 'L';
+ if (acb_info & ACB_PWNOEXP ) acct_str[i++] = 'X';
+ if (acb_info & ACB_DOMTRUST ) acct_str[i++] = 'I';
+
+ for ( ; i < NEW_PW_FORMAT_SPACE_PADDED_LEN - 2 ; i++ )
+ acct_str[i] = ' ';
+
+ i = NEW_PW_FORMAT_SPACE_PADDED_LEN - 2;
+ acct_str[i++] = ']';
+ acct_str[i++] = '\0';
+
+ return acct_str;
+}
diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c
new file mode 100644
index 00000000000..1ace6e3a991
--- /dev/null
+++ b/source/lib/smbrun.c
@@ -0,0 +1,181 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ run a command as a specified user
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* need to move this from here!! need some sleep ... */
+struct current_user current_user;
+
+/****************************************************************************
+This is a utility function of smbrun().
+****************************************************************************/
+
+static int setup_out_fd(void)
+{
+ int fd;
+ pstring path;
+
+ slprintf(path, sizeof(path)-1, "%s/smb.XXXXXX", tmpdir());
+
+ /* now create the file */
+ fd = smb_mkstemp(path);
+
+ if (fd == -1) {
+ DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
+ path, strerror(errno) ));
+ return -1;
+ }
+
+ DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
+
+ /* Ensure file only kept around by open fd. */
+ unlink(path);
+ return fd;
+}
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+****************************************************************************/
+
+int smbrun(char *cmd, int *outfd)
+{
+ pid_t pid;
+ uid_t uid = current_user.uid;
+ gid_t gid = current_user.gid;
+
+ /*
+ * Lose any kernel oplock capabilities we may have.
+ */
+ oplock_set_capability(False, False);
+
+ /* point our stdout at the file we want output to go into */
+
+ if (outfd && ((*outfd = setup_out_fd()) == -1)) {
+ return -1;
+ }
+
+ /* in this method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid=sys_fork()) < 0) {
+ DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
+ CatchChild();
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return errno;
+ }
+
+ if (pid) {
+ /*
+ * Parent.
+ */
+ int status=0;
+ pid_t wpid;
+
+
+ /* the parent just waits for the child to exit */
+ while((wpid = sys_waitpid(pid,&status,0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ CatchChild();
+
+ if (wpid != pid) {
+ DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return -1;
+ }
+
+ /* Reset the seek pointer. */
+ if (outfd) {
+ sys_lseek(*outfd, 0, SEEK_SET);
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+#endif
+
+ return status;
+ }
+
+ CatchChild();
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ /* point our stdout at the file we want output to go into */
+ if (outfd) {
+ close(1);
+ if (dup2(*outfd,1) != 1) {
+ DEBUG(2,("Failed to create stdout file descriptor\n"));
+ close(*outfd);
+ exit(80);
+ }
+ }
+
+ /* now completely lose our privileges. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+
+ become_user_permanently(uid, gid);
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privileges - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+#ifndef __INSURE__
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ {
+ int fd;
+ for (fd=3;fd<256;fd++) close(fd);
+ }
+#endif
+
+ execl("/bin/sh","sh","-c",cmd,NULL);
+
+ /* not reached */
+ exit(82);
+ return 1;
+}
diff --git a/source/lib/snprintf.c b/source/lib/snprintf.c
new file mode 100644
index 00000000000..900ba381a0d
--- /dev/null
+++ b/source/lib/snprintf.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge@samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ * got rid of fcvt code (twas buggy and made testing harder)
+ * added C99 semantics
+ *
+ **************************************************************/
+
+#ifndef NO_CONFIG_H /* for some tests */
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#include <sys/types.h>
+#include <stdarg.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void) {}
+#else
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format,
+ va_list args);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ long value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_CONV 6
+#define DP_S_DONE 7
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT 1
+#define DP_C_LONG 2
+#define DP_C_LDOUBLE 3
+#define DP_C_LLONG 4
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+ char ch;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ int min;
+ int max;
+ int state;
+ int flags;
+ int cflags;
+ size_t currlen;
+
+ state = DP_S_DEFAULT;
+ currlen = flags = cflags = min = 0;
+ max = -1;
+ ch = *format++;
+
+ while (state != DP_S_DONE) {
+ if (ch == '\0')
+ state = DP_S_DONE;
+
+ switch(state) {
+ case DP_S_DEFAULT:
+ if (ch == '%')
+ state = DP_S_FLAGS;
+ else
+ dopr_outch (buffer, &currlen, maxlen, ch);
+ ch = *format++;
+ break;
+ case DP_S_FLAGS:
+ switch (ch) {
+ case '-':
+ flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if (isdigit((unsigned char)ch)) {
+ min = 10*min + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ min = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_DOT;
+ } else {
+ state = DP_S_DOT;
+ }
+ break;
+ case DP_S_DOT:
+ if (ch == '.') {
+ state = DP_S_MAX;
+ ch = *format++;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MAX:
+ if (isdigit((unsigned char)ch)) {
+ if (max < 0)
+ max = 0;
+ max = 10*max + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ max = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_MOD;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MOD:
+ switch (ch) {
+ case 'h':
+ cflags = DP_C_SHORT;
+ ch = *format++;
+ break;
+ case 'l':
+ cflags = DP_C_LONG;
+ ch = *format++;
+ if (ch == 'l') { /* It's a long long */
+ cflags = DP_C_LLONG;
+ ch = *format++;
+ }
+ break;
+ case 'L':
+ cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ switch (ch) {
+ case 'd':
+ case 'i':
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, LLONG);
+ else
+ value = va_arg (args, int);
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'o':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (long)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+ break;
+ case 'u':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (LLONG)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'X':
+ flags |= DP_F_UP;
+ case 'x':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (LLONG)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+ break;
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'E':
+ flags |= DP_F_UP;
+ case 'e':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ break;
+ case 'G':
+ flags |= DP_F_UP;
+ case 'g':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ break;
+ case 'c':
+ dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+ break;
+ case 's':
+ strvalue = va_arg (args, char *);
+ if (!strvalue) strvalue = "(NULL)";
+ if (max == -1) {
+ max = strlen(strvalue);
+ }
+ if (min > 0 && max >= 0 && min > max) max = min;
+ fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+ break;
+ case 'p':
+ strvalue = va_arg (args, void *);
+ fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+ break;
+ case 'n':
+ if (cflags == DP_C_SHORT) {
+ short int *num;
+ num = va_arg (args, short int *);
+ *num = currlen;
+ } else if (cflags == DP_C_LONG) {
+ long int *num;
+ num = va_arg (args, long int *);
+ *num = (long int)currlen;
+ } else if (cflags == DP_C_LLONG) {
+ LLONG *num;
+ num = va_arg (args, LLONG *);
+ *num = (LLONG)currlen;
+ } else {
+ int *num;
+ num = va_arg (args, int *);
+ *num = currlen;
+ }
+ break;
+ case '%':
+ dopr_outch (buffer, &currlen, maxlen, ch);
+ break;
+ case 'w':
+ /* not supported yet, treat as next char */
+ ch = *format++;
+ break;
+ default:
+ /* Unknown, skip */
+ break;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ flags = cflags = min = 0;
+ max = -1;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+ if (maxlen != 0) {
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else if (maxlen > 0)
+ buffer[maxlen - 1] = '\0';
+ }
+
+ return currlen;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+ if (value == 0) {
+ value = "<NULL>";
+ }
+
+ for (strln = 0; value[strln]; ++strln); /* strlen */
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while ((padlen > 0) && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ ++cnt;
+ }
+ while (*value && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while ((padlen < 0) && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ ++cnt;
+ }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ long value, int base, int min, int max, int flags)
+{
+ int signvalue = 0;
+ unsigned long uvalue;
+ char convert[20];
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ int caps = 0;
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if(!(flags & DP_F_UNSIGNED)) {
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ } else {
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+ do {
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < 20));
+ if (place == 20) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO) {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+ printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place);
+#endif
+
+ /* Spaces */
+ while (spadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0) {
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+ LDOUBLE result = value;
+
+ if (value < 0)
+ result = -value;
+
+ return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+ LDOUBLE result = 1;
+
+ while (exp) {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+ LLONG intpart;
+
+ intpart = (LLONG)value;
+ value = value - intpart;
+ if (value >= 0.5) intpart++;
+
+ return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+ be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+ int i;
+ long l;
+ double x = x0;
+ double f = 1.0;
+
+ for (i=0;i<100;i++) {
+ l = (long)x;
+ if (l <= (x+1) && l >= (x-1)) break;
+ x *= 0.1;
+ f *= 10.0;
+ }
+
+ if (i == 100) {
+ /* yikes! the number is beyond what we can handle. What do we do? */
+ (*iptr) = 0;
+ return 0;
+ }
+
+ if (i != 0) {
+ double i2;
+ double ret;
+
+ ret = my_modf(x0-l*f, &i2);
+ (*iptr) = l*f + i2;
+ return ret;
+ }
+
+ (*iptr) = l;
+ return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
+{
+ int signvalue = 0;
+ double ufvalue;
+ char iconvert[311];
+ char fconvert[311];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int index;
+ double intpart;
+ double fracpart;
+ double temp;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val (fvalue);
+
+ if (fvalue < 0) {
+ signvalue = '-';
+ } else {
+ if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+ signvalue = '+';
+ } else {
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+ if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+ /*
+ * Sorry, we only support 16 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 16)
+ max = 16;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+
+ temp = ufvalue;
+ my_modf(temp, &intpart);
+
+ fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+ if (fracpart >= POW10(max)) {
+ intpart++;
+ fracpart -= POW10(max);
+ }
+
+
+ /* Convert integer part */
+ do {
+ temp = intpart;
+ my_modf(intpart*0.1, &intpart);
+ temp = temp*0.1;
+ index = (int) ((temp -intpart +0.05)* 10.0);
+ /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+ /* printf ("%llf, %f, %x\n", temp, intpart, index); */
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
+ } while (intpart && (iplace < 311));
+ if (iplace == 311) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ if (fracpart)
+ {
+ do {
+ temp = fracpart;
+ my_modf(fracpart*0.1, &fracpart);
+ temp = temp*0.1;
+ index = (int) ((temp -fracpart +0.05)* 10.0);
+ /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
+ /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
+ } while(fracpart && (fplace < 311));
+ if (fplace == 311) fplace--;
+ }
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0) zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {
+ if (signvalue) {
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0) {
+ dopr_outch (buffer, currlen, maxlen, '.');
+
+ while (fplace > 0)
+ dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
+
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen < maxlen) {
+ buffer[(*currlen)] = c;
+ }
+ (*currlen)++;
+}
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+ return dopr(str, count, fmt, args);
+}
+#endif
+
+/* yes this really must be a ||. Don't muck wiith this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test. Perhaps
+ * these should really be smb_snprintf to avoid conflicts with buggy
+ * linkers? -- mbp
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
+ int snprintf(char *str,size_t count,const char *fmt,...)
+{
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
+
+#endif
+
+#ifndef HAVE_VASPRINTF
+ int vasprintf(char **ptr, const char *format, va_list ap)
+{
+ int ret;
+
+ ret = vsnprintf(NULL, 0, format, ap);
+ if (ret <= 0) return ret;
+
+ (*ptr) = (char *)malloc(ret+1);
+ if (!*ptr) return -1;
+ ret = vsnprintf(*ptr, ret+1, format, ap);
+
+ return ret;
+}
+#endif
+
+
+#ifndef HAVE_ASPRINTF
+ int asprintf(char **ptr, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(ptr, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+ void vsyslog (int facility_priority, char *format, va_list arglist)
+{
+ char *msg = NULL;
+ vasprintf(&msg, format, argslist);
+ if (!msg)
+ return;
+ syslog(facility_priority, "%s", msg);
+ free(msg);
+}
+#endif /* HAVE_SYSLOG */
+#endif /* HAVE_VSYSLOG */
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+
+ int main (void)
+{
+ char buf1[1024];
+ char buf2[1024];
+ char *fp_fmt[] = {
+ "%1.1f",
+ "%-1.5f",
+ "%1.5f",
+ "%123.9f",
+ "%10.5f",
+ "% 10.5f",
+ "%+22.9f",
+ "%+4.9f",
+ "%01.3f",
+ "%4f",
+ "%3.1f",
+ "%3.2f",
+ "%.0f",
+ "%f",
+ "-16.16f",
+ NULL
+ };
+ double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
+ 0.9996, 1.996, 4.136, 0};
+ char *int_fmt[] = {
+ "%-1.5d",
+ "%1.5d",
+ "%123.9d",
+ "%5.5d",
+ "%10.5d",
+ "% 10.5d",
+ "%+22.33d",
+ "%01.3d",
+ "%4d",
+ "%d",
+ NULL
+ };
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
+ char *str_fmt[] = {
+ "10.5s",
+ "5.10s",
+ "10.1s",
+ "0.10s",
+ "10.0s",
+ "1.10s",
+ "%s",
+ "%.1s",
+ "%.10s",
+ "%10s",
+ NULL
+ };
+ char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+ int x, y;
+ int fail = 0;
+ int num = 0;
+
+ printf ("Testing snprintf format codes against system sprintf...\n");
+
+ for (x = 0; fp_fmt[x] ; x++) {
+ for (y = 0; fp_nums[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+ sprintf (buf2, fp_fmt[x], fp_nums[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ fp_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; int_fmt[x] ; x++) {
+ for (y = 0; int_nums[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+ sprintf (buf2, int_fmt[x], int_nums[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ int_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; str_fmt[x] ; x++) {
+ for (y = 0; str_vals[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+ sprintf (buf2, str_fmt[x], str_vals[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ str_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ printf ("%d tests failed out of %d.\n", fail, num);
+
+ printf("seeing how many digits we support\n");
+ {
+ double v0 = 0.12345678901234567890123456789012345678901;
+ for (x=0; x<100; x++) {
+ snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
+ sprintf(buf2, "%1.1f", v0*pow(10, x));
+ if (strcmp(buf1, buf2)) {
+ printf("we seem to support %d digits\n", x-1);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* SNPRINTF_TEST */
diff --git a/source/lib/substitute.c b/source/lib/substitute.c
new file mode 100644
index 00000000000..2669929920c
--- /dev/null
+++ b/source/lib/substitute.c
@@ -0,0 +1,327 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ string substitution functions
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+fstring local_machine="";
+fstring remote_arch="UNKNOWN";
+userdom_struct current_user_info;
+fstring remote_proto="UNKNOWN";
+fstring remote_machine="";
+extern pstring global_myname;
+
+/*******************************************************************
+ Given a pointer to a %$(NAME) expand it as an environment variable.
+ Return the number of characters by which the pointer should be advanced.
+ Based on code by Branko Cibej <branko.cibej@hermes.si>
+ When this is called p points at the '%' character.
+********************************************************************/
+static size_t expand_env_var(char *p, int len)
+{
+ fstring envname;
+ char *envval;
+ char *q, *r;
+ int copylen;
+
+ if (p[1] != '$')
+ return 1;
+
+ if (p[2] != '(')
+ return 2;
+
+ /*
+ * Look for the terminating ')'.
+ */
+
+ if ((q = strchr_m(p,')')) == NULL) {
+ DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
+ return 2;
+ }
+
+ /*
+ * Extract the name from within the %$(NAME) string.
+ */
+
+ r = p+3;
+ copylen = MIN((q-r),(sizeof(envname)-1));
+ strncpy(envname,r,copylen);
+ envname[copylen] = '\0';
+
+ if ((envval = getenv(envname)) == NULL) {
+ DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
+ return 2;
+ }
+
+ /*
+ * Copy the full %$(NAME) into envname so it
+ * can be replaced.
+ */
+
+ copylen = MIN((q+1-p),(sizeof(envname)-1));
+ strncpy(envname,p,copylen);
+ envname[copylen] = '\0';
+ string_sub(p,envname,envval,len);
+ return 0; /* Allow the environment contents to be parsed. */
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Added this to implement %p (NIS auto-map version of %H)
+*******************************************************************/
+static char *automount_path(char *user_name)
+{
+ static pstring server_path;
+
+ /* use the passwd entry as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ /* pstrcpy() copes with get_user_home_dir() returning NULL */
+ pstrcpy(server_path, get_user_home_dir(user_name));
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+ if (lp_nis_home_map()) {
+ char *home_path_start;
+ char *automount_value = automount_lookup(user_name);
+
+ if(strlen(automount_value) > 0) {
+ home_path_start = strchr_m(automount_value,':');
+ if (home_path_start != NULL) {
+ DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n",
+ home_path_start?(home_path_start+1):""));
+ pstrcpy(server_path, home_path_start+1);
+ }
+ } else {
+ /* NIS key lookup failed: default to user home directory from password file */
+ pstrcpy(server_path, get_user_home_dir(user_name));
+ DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n",
+ server_path ));
+ }
+ }
+#endif
+
+ DEBUG(4,("Home server path: %s\n", server_path));
+
+ return server_path;
+}
+
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ This is Luke's original function with the NIS lookup code
+ moved out to a separate function.
+*******************************************************************/
+static char *automount_server(char *user_name)
+{
+ static pstring server_name;
+
+ /* use the local machine name as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ if (*local_machine) {
+ pstrcpy(server_name, local_machine);
+ } else {
+ pstrcpy(server_name, global_myname);
+ }
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+ if (lp_nis_home_map())
+ {
+ int home_server_len;
+ char *automount_value = automount_lookup(user_name);
+ home_server_len = strcspn(automount_value,":");
+ DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len));
+ if (home_server_len > sizeof(pstring))
+ {
+ home_server_len = sizeof(pstring);
+ }
+ strncpy(server_name, automount_value, home_server_len);
+ server_name[home_server_len] = '\0';
+ }
+#endif
+
+ DEBUG(4,("Home server: %s\n", server_name));
+
+ return server_name;
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+void standard_sub_basic(char *smb_name, char *str)
+{
+ char *p, *s;
+ fstring pidstr;
+ struct passwd *pass;
+
+ for (s=str; (p=strchr_m(s, '%'));s=p) {
+ fstring tmp_str;
+
+ int l = sizeof(pstring) - (int)(p-str);
+
+ switch (*(p+1)) {
+ case 'U' :
+ fstrcpy(tmp_str, smb_name);
+ strlower(tmp_str);
+ string_sub(p,"%U",tmp_str,l);
+ break;
+ case 'G' :
+ fstrcpy(tmp_str, smb_name);
+ if ((pass = Get_Pwnam(tmp_str))!=NULL) {
+ string_sub(p,"%G",gidtoname(pass->pw_gid),l);
+ } else {
+ p += 2;
+ }
+ break;
+ case 'D' :
+ fstrcpy(tmp_str, current_user_info.domain);
+ strupper(tmp_str);
+ string_sub(p,"%D", tmp_str,l);
+ break;
+ case 'I' : string_sub(p,"%I", client_addr(),l); break;
+ case 'L' :
+ if (*local_machine) {
+ string_sub(p,"%L", local_machine,l);
+ } else {
+ string_sub(p,"%L", global_myname,l);
+ }
+ break;
+ case 'M' : string_sub(p,"%M", client_name(),l); break;
+ case 'R' : string_sub(p,"%R", remote_proto,l); break;
+ case 'T' : string_sub(p,"%T", timestring(False),l); break;
+ case 'a' : string_sub(p,"%a", remote_arch,l); break;
+ case 'd' :
+ slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
+ string_sub(p,"%d", pidstr,l);
+ break;
+ case 'h' : string_sub(p,"%h", myhostname(),l); break;
+ case 'm' : string_sub(p,"%m", remote_machine,l); break;
+ case 'v' : string_sub(p,"%v", VERSION,l); break;
+ case '$' : p += expand_env_var(p,l); break; /* Expand environment variables */
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string */
+
+ default: p+=2;
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+void standard_sub_advanced(int snum, char *user, char *connectpath, gid_t gid, char *smb_name, char *str)
+{
+ char *p, *s, *home;
+
+ for (s=str; (p=strchr_m(s, '%'));s=p) {
+ int l = sizeof(pstring) - (int)(p-str);
+
+ switch (*(p+1)) {
+ case 'N' : string_sub(p,"%N", automount_server(user),l); break;
+ case 'H':
+ if ((home = get_user_home_dir(user))) {
+ string_sub(p,"%H",home, l);
+ } else {
+ p += 2;
+ }
+ break;
+ case 'P':
+ string_sub(p,"%P", connectpath, l);
+ break;
+
+ case 'S':
+ string_sub(p,"%S", lp_servicename(snum), l);
+ break;
+
+ case 'g':
+ string_sub(p,"%g", gidtoname(gid), l);
+ break;
+ case 'u':
+ string_sub(p,"%u", user, l);
+ break;
+
+ /* Patch from jkf@soton.ac.uk Left the %N (NIS
+ * server name) in standard_sub_basic as it is
+ * a feature for logon servers, hence uses the
+ * username. The %p (NIS server path) code is
+ * here as it is used instead of the default
+ * "path =" string in [homes] and so needs the
+ * service name, not the username. */
+ case 'p':
+ string_sub(p,"%p", automount_path(lp_servicename(snum)), l);
+ break;
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string */
+
+ default: p+=2;
+ break;
+ }
+ }
+
+ standard_sub_basic(smb_name, str);
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+void standard_sub_conn(connection_struct *conn, char *str)
+{
+ standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath, conn->gid, current_user_info.smb_name, str);
+}
+
+/****************************************************************************
+like standard_sub but by snum
+****************************************************************************/
+void standard_sub_snum(int snum, char *str)
+{
+ extern struct current_user current_user;
+ static uid_t cached_uid = -1;
+ static fstring cached_user;
+ /* calling uidtoname() on every substitute would be too expensive, so
+ we cache the result here as nearly every call is for the same uid */
+
+ if (cached_uid != current_user.uid) {
+ fstrcpy(cached_user, uidtoname(current_user.uid));
+ cached_uid = current_user.uid;
+ }
+
+ standard_sub_advanced(snum, cached_user, "", -1, current_user_info.smb_name, str);
+}
+
+/*******************************************************************
+ Substitute strings with useful parameters.
+********************************************************************/
+void standard_sub_vuser(char *str, user_struct *vuser)
+{
+ standard_sub_advanced(-1, vuser->user.unix_name, "", -1, current_user_info.smb_name, str);
+}
+
+/*******************************************************************
+ Substitute strings with useful parameters.
+********************************************************************/
+void standard_sub_vsnum(char *str, user_struct *vuser, int snum)
+{
+ standard_sub_advanced(snum, vuser->user.unix_name, "", -1, current_user_info.smb_name, str);
+}
diff --git a/source/lib/sysacls.c b/source/lib/sysacls.c
new file mode 100644
index 00000000000..b14b99b80dd
--- /dev/null
+++ b/source/lib/sysacls.c
@@ -0,0 +1,3211 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+ Samba system utilities for ACL support.
+ Copyright (C) Jeremy Allison 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ This file wraps all differing system ACL interfaces into a consistent
+ one based on the POSIX interface. It also returns the correct errors
+ for older UNIX systems that don't support ACLs.
+
+ The interfaces that each ACL implementation must support are as follows :
+
+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+ SMB_ACL_T sys_acl_get_fd(int fd)
+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
+ SMB_ACL_T sys_acl_init( int count)
+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+ int sys_acl_valid( SMB_ACL_T theacl )
+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+ int sys_acl_delete_def_file(const char *path)
+
+ This next one is not POSIX complient - but we *have* to have it !
+ More POSIX braindamage.
+
+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+
+ The generic POSIX free is the following call. We split this into
+ several different free functions as we may need to add tag info
+ to structures when emulating the POSIX interface.
+
+ int sys_acl_free( void *obj_p)
+
+ The calls we actually use are :
+
+ int sys_acl_free_text(char *text) - free acl_to_text
+ int sys_acl_free_acl(SMB_ACL_T posix_acl)
+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
+
+*/
+
+#if defined(HAVE_POSIX_ACLS)
+
+/* Identity mapping - easy. */
+
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ return acl_get_entry( the_acl, entry_id, entry_p);
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ return acl_get_tag_type( entry_d, tag_type_p);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ return acl_get_permset( entry_d, permset_p);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return acl_get_qualifier( entry_d);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return acl_get_file( path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ return acl_get_fd(fd);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ return acl_clear_perms(permset);
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return acl_add_perm(permset, perm);
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+#if defined(HAVE_ACL_GET_PERM_NP)
+ /*
+ * Required for TrustedBSD-based ACL implementations where
+ * non-POSIX.1e functions are denoted by a _np (non-portable)
+ * suffix.
+ */
+ return acl_get_perm_np(permset, perm);
+#else
+ return acl_get_perm(permset, perm);
+#endif
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ return acl_to_text( the_acl, plen);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ return acl_init(count);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ return acl_create_entry(pacl, pentry);
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ return acl_set_tag_type(entry, tagtype);
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ return acl_set_qualifier(entry, qual);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ return acl_set_permset(entry, permset);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ return acl_valid(theacl);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ return acl_set_file(name, acltype, theacl);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ return acl_set_fd(fd, theacl);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file(name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return acl_free(text);
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ return acl_free(the_acl);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return acl_free(qual);
+}
+
+#elif defined(HAVE_TRU64_ACLS)
+/*
+ * The interface to DEC/Compaq Tru64 UNIX ACLs
+ * is based on Draft 13 of the POSIX spec which is
+ * slightly different from the Draft 16 interface.
+ *
+ * Also, some of the permset manipulation functions
+ * such as acl_clear_perm() and acl_add_perm() appear
+ * to be broken on Tru64 so we have to manipulate
+ * the permission bits in the permset directly.
+ */
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_ENTRY_T entry;
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
+ return -1;
+ }
+
+ errno = 0;
+ if ((entry = acl_get_entry(the_acl)) != NULL) {
+ *entry_p = entry;
+ return 1;
+ }
+
+ return errno ? -1 : 0;
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ return acl_get_tag_type( entry_d, tag_type_p);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ return acl_get_permset( entry_d, permset_p);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return acl_get_qualifier( entry_d);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return acl_get_file((char *)path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ return acl_get_fd(fd, ACL_TYPE_ACCESS);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ *permset = 0; /* acl_clear_perm() is broken on Tru64 */
+
+ return 0;
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset |= perm; /* acl_add_perm() is broken on Tru64 */
+
+ return 0;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ return acl_to_text( the_acl, plen);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ return acl_init(count);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ SMB_ACL_ENTRY_T entry;
+
+ if ((entry = acl_create_entry(pacl)) == NULL) {
+ return -1;
+ }
+
+ *pentry = entry;
+ return 0;
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ return acl_set_tag_type(entry, tagtype);
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ return acl_set_qualifier(entry, qual);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ return acl_set_permset(entry, permset);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ acl_entry_t entry;
+
+ return acl_valid(theacl, &entry);
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ return acl_set_file((char *)name, acltype, theacl);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file((char *)name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ /*
+ * (void) cast and explicit return 0 are for DEC UNIX
+ * which just #defines acl_free_text() to be free()
+ */
+ (void) acl_free_text(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ return acl_free(the_acl);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return acl_free_qualifier(qual, tagtype);
+}
+
+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
+
+/*
+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
+ */
+
+/*
+ * Note that while this code implements sufficient functionality
+ * to support the sys_acl_* interfaces it does not provide all
+ * of the semantics of the POSIX ACL interfaces.
+ *
+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
+ * from a call to sys_acl_get_entry() should not be assumed to be
+ * valid after calling any of the following functions, which may
+ * reorder the entries in the ACL.
+ *
+ * sys_acl_valid()
+ * sys_acl_set_file()
+ * sys_acl_set_fd()
+ */
+
+/*
+ * The only difference between Solaris and UnixWare / OpenUNIX is
+ * that the #defines for the ACL operations have different names
+ */
+#if defined(HAVE_UNIXWARE_ACLS)
+
+#define SETACL ACL_SET
+#define GETACL ACL_GET
+#define GETACLCNT ACL_CNT
+
+#endif
+
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->count) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->acl[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->a_type;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = &entry_d->a_perm;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->a_type != SMB_ACL_USER
+ && entry_d->a_type != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->a_id;
+}
+
+/*
+ * There is no way of knowing what size the ACL returned by
+ * GETACL will be unless you first call GETACLCNT which means
+ * making an additional system call.
+ *
+ * In the hope of avoiding the cost of the additional system
+ * call in most cases, we initially allocate enough space for
+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
+ * be too small then we use GETACLCNT to find out the actual
+ * size, reallocate the ACL buffer, and then call GETACL again.
+ */
+
+#define INITIAL_ACL_SIZE 16
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+ int ndefault; /* # of default ACL entries */
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If there isn't enough space for the ACL entries we use
+ * GETACLCNT to determine the actual number of ACL entries
+ * reallocate and try again. This is in a loop because it
+ * is possible that someone else could modify the ACL and
+ * increase the number of entries between the call to
+ * GETACLCNT and the call to GETACL.
+ */
+ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
+ && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access and default ACL entries
+ *
+ * Note: we assume that the acl() system call returned a
+ * well formed ACL which is sorted so that all of the
+ * access ACL entries preceed any default ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+ ndefault = count - naccess;
+
+ /*
+ * if the caller wants the default ACL we have to copy
+ * the entries down to the start of the acl[] buffer
+ * and mask out the ACL_DEFAULT flag from the type field
+ */
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ int i, j;
+
+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
+ acl_d->acl[i] = acl_d->acl[j];
+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
+ }
+
+ acl_d->count = ndefault;
+ } else {
+ acl_d->count = naccess;
+ }
+
+ return acl_d;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
+ && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+
+ acl_d->count = naccess;
+
+ return acl_d;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ *permset_d = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset_d |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return *permset_d & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ int i;
+ int len, maxlen;
+ char *text;
+
+ /*
+ * use an initial estimate of 20 bytes per ACL entry
+ * when allocating memory for the text representation
+ * of the ACL
+ */
+ len = 0;
+ maxlen = 20 * acl_d->count;
+ if ((text = malloc(maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < acl_d->count; i++) {
+ struct acl *ap = &acl_d->acl[i];
+ struct passwd *pw;
+ struct group *gr;
+ char tagbuf[12];
+ char idbuf[12];
+ char *tag;
+ char *id = "";
+ char perms[4];
+ int nbytes;
+
+ switch (ap->a_type) {
+ /*
+ * for debugging purposes it's probably more
+ * useful to dump unknown tag types rather
+ * than just returning an error
+ */
+ default:
+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
+ ap->a_type);
+ tag = tagbuf;
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ break;
+
+ case SMB_ACL_USER:
+ if ((pw = sys_getpwuid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = pw->pw_name;
+ }
+ case SMB_ACL_USER_OBJ:
+ tag = "user";
+ break;
+
+ case SMB_ACL_GROUP:
+ if ((gr = getgrgid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = gr->gr_name;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ tag = "group";
+ break;
+
+ case SMB_ACL_OTHER:
+ tag = "other";
+ break;
+
+ case SMB_ACL_MASK:
+ tag = "mask";
+ break;
+
+ }
+
+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
+ perms[3] = '\0';
+
+ /* <tag> : <qualifier> : rwx \n \0 */
+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
+
+ /*
+ * If this entry would overflow the buffer
+ * allocate enough additional memory for this
+ * entry and an estimate of another 20 bytes
+ * for each entry still to be processed
+ */
+ if ((len + nbytes) > maxlen) {
+ char *oldtext = text;
+
+ maxlen += nbytes + 20 * (acl_d->count - i);
+
+ if ((text = Realloc(oldtext, maxlen)) == NULL) {
+ SAFE_FREE(oldtext);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
+ len += nbytes - 1;
+ }
+
+ if (len_p)
+ *len_p = len;
+
+ return text;
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * note that since the definition of the structure pointed
+ * to by the SMB_ACL_T includes the first element of the
+ * acl[] array, this actually allocates an ACL with room
+ * for (count+1) entries
+ */
+ if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->size = count + 1;
+ a->count = 0;
+ a->next = -1;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->count >= acl_d->size) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->acl[acl_d->count++];
+ entry_d->a_type = 0;
+ entry_d->a_id = -1;
+ entry_d->a_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->a_type = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->a_type != SMB_ACL_GROUP
+ && entry_d->a_type != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->a_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->a_perm = *permset_d;
+
+ return 0;
+}
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask so, in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it ...)
+ */
+
+static int acl_sort(SMB_ACL_T acl_d)
+{
+ int fixmask = (acl_d->count <= 4);
+
+ if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_sort(acl_d);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ struct stat s;
+ struct acl *acl_p;
+ int acl_count;
+ struct acl *acl_buf = NULL;
+ int ret;
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ acl_p = &acl_d->acl[0];
+ acl_count = acl_d->count;
+
+ /*
+ * if it's a directory there is extra work to do
+ * since the acl() system call will replace both
+ * the access ACLs and the default ACLs (if any)
+ */
+ if (stat(name, &s) != 0) {
+ return -1;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ SMB_ACL_T acc_acl;
+ SMB_ACL_T def_acl;
+ SMB_ACL_T tmp_acl;
+ int i;
+
+ if (type == SMB_ACL_TYPE_ACCESS) {
+ acc_acl = acl_d;
+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
+
+ } else {
+ def_acl = acl_d;
+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (tmp_acl == NULL) {
+ return -1;
+ }
+
+ /*
+ * allocate a temporary buffer for the complete ACL
+ */
+ acl_count = acc_acl->count + def_acl->count;
+ acl_p = acl_buf = malloc(acl_count * sizeof(acl_buf[0]));
+
+ if (acl_buf == NULL) {
+ sys_acl_free_acl(tmp_acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /*
+ * copy the access control and default entries into the buffer
+ */
+ memcpy(&acl_buf[0], &acc_acl->acl[0],
+ acc_acl->count * sizeof(acl_buf[0]));
+
+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
+ def_acl->count * sizeof(acl_buf[0]));
+
+ /*
+ * set the ACL_DEFAULT flag on the default entries
+ */
+ for (i = acc_acl->count; i < acl_count; i++) {
+ acl_buf[i].a_type |= ACL_DEFAULT;
+ }
+
+ sys_acl_free_acl(tmp_acl);
+
+ } else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = acl(name, SETACL, acl_count, acl_p);
+
+ SAFE_FREE(acl_buf);
+
+ return ret;
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
+}
+
+int sys_acl_delete_def_file(const char *path)
+{
+ SMB_ACL_T acl_d;
+ int ret;
+
+ /*
+ * fetching the access ACL and rewriting it has
+ * the effect of deleting the default ACL
+ */
+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
+ return -1;
+ }
+
+ ret = acl(path, SETACL, acl_d->count, acl_d->acl);
+
+ sys_acl_free_acl(acl_d);
+
+ return ret;
+}
+
+int sys_acl_free_text(char *text)
+{
+ SAFE_FREE(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ SAFE_FREE(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_HPUX_ACLS)
+#include <dl.h>
+
+/*
+ * Based on the Solaris/SCO code - with modifications.
+ */
+
+/*
+ * Note that while this code implements sufficient functionality
+ * to support the sys_acl_* interfaces it does not provide all
+ * of the semantics of the POSIX ACL interfaces.
+ *
+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
+ * from a call to sys_acl_get_entry() should not be assumed to be
+ * valid after calling any of the following functions, which may
+ * reorder the entries in the ACL.
+ *
+ * sys_acl_valid()
+ * sys_acl_set_file()
+ * sys_acl_set_fd()
+ */
+
+/* This checks if the POSIX ACL system call is defined */
+/* which basically corresponds to whether JFS 3.3 or */
+/* higher is installed. If acl() was called when it */
+/* isn't defined, it causes the process to core dump */
+/* so it is important to check this and avoid acl() */
+/* calls if it isn't there. */
+
+static BOOL hpux_acl_call_presence(void)
+{
+
+ shl_t handle = NULL;
+ void *value;
+ int ret_val=0;
+ static BOOL already_checked=0;
+
+ if(already_checked)
+ return True;
+
+
+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
+
+ if(ret_val != 0) {
+ DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
+ ret_val, errno, strerror(errno)));
+ DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
+ return False;
+ }
+
+ DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
+
+ already_checked = True;
+ return True;
+}
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->count) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->acl[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->a_type;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = &entry_d->a_perm;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->a_type != SMB_ACL_USER
+ && entry_d->a_type != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->a_id;
+}
+
+/*
+ * There is no way of knowing what size the ACL returned by
+ * ACL_GET will be unless you first call ACL_CNT which means
+ * making an additional system call.
+ *
+ * In the hope of avoiding the cost of the additional system
+ * call in most cases, we initially allocate enough space for
+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
+ * be too small then we use ACL_CNT to find out the actual
+ * size, reallocate the ACL buffer, and then call ACL_GET again.
+ */
+
+#define INITIAL_ACL_SIZE 16
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+ int ndefault; /* # of default ACL entries */
+
+ if(hpux_acl_call_presence() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ return NULL;
+ }
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If there isn't enough space for the ACL entries we use
+ * ACL_CNT to determine the actual number of ACL entries
+ * reallocate and try again. This is in a loop because it
+ * is possible that someone else could modify the ACL and
+ * increase the number of entries between the call to
+ * ACL_CNT and the call to ACL_GET.
+ */
+ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access and default ACL entries
+ *
+ * Note: we assume that the acl() system call returned a
+ * well formed ACL which is sorted so that all of the
+ * access ACL entries preceed any default ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+ ndefault = count - naccess;
+
+ /*
+ * if the caller wants the default ACL we have to copy
+ * the entries down to the start of the acl[] buffer
+ * and mask out the ACL_DEFAULT flag from the type field
+ */
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ int i, j;
+
+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
+ acl_d->acl[i] = acl_d->acl[j];
+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
+ }
+
+ acl_d->count = ndefault;
+ } else {
+ acl_d->count = naccess;
+ }
+
+ return acl_d;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+
+ files_struct *fsp = file_find_fd(fd);
+
+ if (fsp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+
+ return sys_acl_get_file(dos_to_unix(fsp->fsp_name,False), SMB_ACL_TYPE_ACCESS);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ *permset_d = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset_d |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return *permset_d & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ int i;
+ int len, maxlen;
+ char *text;
+
+ /*
+ * use an initial estimate of 20 bytes per ACL entry
+ * when allocating memory for the text representation
+ * of the ACL
+ */
+ len = 0;
+ maxlen = 20 * acl_d->count;
+ if ((text = malloc(maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < acl_d->count; i++) {
+ struct acl *ap = &acl_d->acl[i];
+ struct passwd *pw;
+ struct group *gr;
+ char tagbuf[12];
+ char idbuf[12];
+ char *tag;
+ char *id = "";
+ char perms[4];
+ int nbytes;
+
+ switch (ap->a_type) {
+ /*
+ * for debugging purposes it's probably more
+ * useful to dump unknown tag types rather
+ * than just returning an error
+ */
+ default:
+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
+ ap->a_type);
+ tag = tagbuf;
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ break;
+
+ case SMB_ACL_USER:
+ if ((pw = sys_getpwuid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = pw->pw_name;
+ }
+ case SMB_ACL_USER_OBJ:
+ tag = "user";
+ break;
+
+ case SMB_ACL_GROUP:
+ if ((gr = getgrgid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = gr->gr_name;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ tag = "group";
+ break;
+
+ case SMB_ACL_OTHER:
+ tag = "other";
+ break;
+
+ case SMB_ACL_MASK:
+ tag = "mask";
+ break;
+
+ }
+
+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
+ perms[3] = '\0';
+
+ /* <tag> : <qualifier> : rwx \n \0 */
+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
+
+ /*
+ * If this entry would overflow the buffer
+ * allocate enough additional memory for this
+ * entry and an estimate of another 20 bytes
+ * for each entry still to be processed
+ */
+ if ((len + nbytes) > maxlen) {
+ char *oldtext = text;
+
+ maxlen += nbytes + 20 * (acl_d->count - i);
+
+ if ((text = Realloc(oldtext, maxlen)) == NULL) {
+ free(oldtext);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
+ len += nbytes - 1;
+ }
+
+ if (len_p)
+ *len_p = len;
+
+ return text;
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * note that since the definition of the structure pointed
+ * to by the SMB_ACL_T includes the first element of the
+ * acl[] array, this actually allocates an ACL with room
+ * for (count+1) entries
+ */
+ if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->size = count + 1;
+ a->count = 0;
+ a->next = -1;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->count >= acl_d->size) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->acl[acl_d->count++];
+ entry_d->a_type = 0;
+ entry_d->a_id = -1;
+ entry_d->a_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->a_type = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->a_type != SMB_ACL_GROUP
+ && entry_d->a_type != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->a_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->a_perm = *permset_d;
+
+ return 0;
+}
+
+/* Structure to capture the count for each type of ACE. */
+
+struct hpux_acl_types {
+ int n_user;
+ int n_def_user;
+ int n_user_obj;
+ int n_def_user_obj;
+
+ int n_group;
+ int n_def_group;
+ int n_group_obj;
+ int n_def_group_obj;
+
+ int n_other;
+ int n_other_obj;
+ int n_def_other_obj;
+
+ int n_class_obj;
+ int n_def_class_obj;
+
+ int n_illegal_obj;
+};
+
+/* count_obj:
+ * Counts the different number of objects in a given array of ACL
+ * structures.
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL strucutres.
+ * aclp - Array of ACL structures.
+ * acl_type_count - Pointer to acl_types structure. Should already be
+ * allocated.
+ * Output:
+ *
+ * acl_type_count - This structure is filled up with counts of various
+ * acl types.
+ */
+
+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
+{
+ int i;
+
+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
+
+ for(i=0;i<acl_count;i++) {
+ switch(aclp[i].a_type) {
+ case USER:
+ acl_type_count->n_user++;
+ break;
+ case USER_OBJ:
+ acl_type_count->n_user_obj++;
+ break;
+ case DEF_USER_OBJ:
+ acl_type_count->n_def_user_obj++;
+ break;
+ case GROUP:
+ acl_type_count->n_group++;
+ break;
+ case GROUP_OBJ:
+ acl_type_count->n_group_obj++;
+ break;
+ case DEF_GROUP_OBJ:
+ acl_type_count->n_def_group_obj++;
+ break;
+ case OTHER_OBJ:
+ acl_type_count->n_other_obj++;
+ break;
+ case DEF_OTHER_OBJ:
+ acl_type_count->n_def_other_obj++;
+ break;
+ case CLASS_OBJ:
+ acl_type_count->n_class_obj++;
+ break;
+ case DEF_CLASS_OBJ:
+ acl_type_count->n_def_class_obj++;
+ break;
+ case DEF_USER:
+ acl_type_count->n_def_user++;
+ break;
+ case DEF_GROUP:
+ acl_type_count->n_def_group++;
+ break;
+ default:
+ acl_type_count->n_illegal_obj++;
+ break;
+ }
+ }
+}
+
+/* swap_acl_entries: Swaps two ACL entries.
+ *
+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
+ */
+
+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
+{
+ struct acl temp_acl;
+
+ temp_acl.a_type = aclp0->a_type;
+ temp_acl.a_id = aclp0->a_id;
+ temp_acl.a_perm = aclp0->a_perm;
+
+ aclp0->a_type = aclp1->a_type;
+ aclp0->a_id = aclp1->a_id;
+ aclp0->a_perm = aclp1->a_perm;
+
+ aclp1->a_type = temp_acl.a_type;
+ aclp1->a_id = temp_acl.a_id;
+ aclp1->a_perm = temp_acl.a_perm;
+}
+
+/* prohibited_duplicate_type
+ * Identifies if given ACL type can have duplicate entries or
+ * not.
+ *
+ * Inputs: acl_type - ACL Type.
+ *
+ * Outputs:
+ *
+ * Return..
+ *
+ * True - If the ACL type matches any of the prohibited types.
+ * False - If the ACL type doesn't match any of the prohibited types.
+ */
+
+static BOOL hpux_prohibited_duplicate_type(int acl_type)
+{
+ switch(acl_type) {
+ case USER:
+ case GROUP:
+ case DEF_USER:
+ case DEF_GROUP:
+ return True;
+ default:
+ return False;
+ }
+}
+
+/* get_needed_class_perm
+ * Returns the permissions of a ACL structure only if the ACL
+ * type matches one of the pre-determined types for computing
+ * CLASS_OBJ permissions.
+ *
+ * Inputs: aclp - Pointer to ACL structure.
+ */
+
+static int hpux_get_needed_class_perm(struct acl *aclp)
+{
+ switch(aclp->a_type) {
+ case USER:
+ case GROUP_OBJ:
+ case GROUP:
+ case DEF_USER_OBJ:
+ case DEF_USER:
+ case DEF_GROUP_OBJ:
+ case DEF_GROUP:
+ case DEF_CLASS_OBJ:
+ case DEF_OTHER_OBJ:
+ return aclp->a_perm;
+ default:
+ return 0;
+ }
+}
+
+/* acl_sort for HPUX.
+ * Sorts the array of ACL structures as per the description in
+ * aclsort man page. Refer to aclsort man page for more details
+ *
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL structures.
+ * calclass - If this is not zero, then we compute the CLASS_OBJ
+ * permissions.
+ * aclp - Array of ACL structures.
+ *
+ * Outputs:
+ *
+ * aclp - Sorted array of ACL structures.
+ *
+ * Outputs:
+ *
+ * Returns 0 for success -1 for failure. Prints a message to the Samba
+ * debug log in case of failure.
+ */
+
+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
+{
+#if !defined(HAVE_HPUX_ACLSORT)
+ /*
+ * The aclsort() system call is availabe on the latest HPUX General
+ * Patch Bundles. So for HPUX, we developed our version of acl_sort
+ * function. Because, we don't want to update to a new
+ * HPUX GR bundle just for aclsort() call.
+ */
+
+ struct hpux_acl_types acl_obj_count;
+ int n_class_obj_perm = 0;
+ int i, j;
+
+ if(!acl_count) {
+ DEBUG(10,("Zero acl count passed. Returning Success\n"));
+ return 0;
+ }
+
+ if(aclp == NULL) {
+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
+ return -1;
+ }
+
+ /* Count different types of ACLs in the ACLs array */
+
+ hpux_count_obj(acl_count, aclp, &acl_obj_count);
+
+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
+ * CLASS_OBJ and OTHER_OBJ
+ */
+
+ if( (acl_obj_count.n_user_obj != 1) ||
+ (acl_obj_count.n_group_obj != 1) ||
+ (acl_obj_count.n_class_obj != 1) ||
+ (acl_obj_count.n_other_obj != 1)
+ ) {
+ DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
+ return -1;
+ }
+
+ /* If any of the default objects are present, there should be only
+ * one of them each.
+ */
+
+ if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
+ (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
+ DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
+ return -1;
+ }
+
+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
+ * structures.
+ *
+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of
+ * same ACL type, sort by ACL id.
+ *
+ * I am using the trival kind of sorting method here because, performance isn't
+ * really effected by the ACLs feature. More over there aren't going to be more
+ * than 17 entries on HPUX.
+ */
+
+ for(i=0; i<acl_count;i++) {
+ for (j=i+1; j<acl_count; j++) {
+ if( aclp[i].a_type > aclp[j].a_type ) {
+ /* ACL entries out of order, swap them */
+
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+
+ } else if ( aclp[i].a_type == aclp[j].a_type ) {
+
+ /* ACL entries of same type, sort by id */
+
+ if(aclp[i].a_id > aclp[j].a_id) {
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+ } else if (aclp[i].a_id == aclp[j].a_id) {
+ /* We have a duplicate entry. */
+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
+ DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
+ aclp[i].a_type, aclp[i].a_id));
+ return -1;
+ }
+ }
+
+ }
+ }
+ }
+
+ /* set the class obj permissions to the computed one. */
+ if(calclass) {
+ int n_class_obj_index = -1;
+
+ for(i=0;i<acl_count;i++) {
+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
+
+ if(aclp[i].a_type == CLASS_OBJ)
+ n_class_obj_index = i;
+ }
+ aclp[n_class_obj_index].a_perm = n_class_obj_perm;
+ }
+
+ return 0;
+#else
+ return aclsort(acl_count, calclass, aclp);
+#endif
+}
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask so, in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it ...)
+ */
+
+static int acl_sort(SMB_ACL_T acl_d)
+{
+ int fixmask = (acl_d->count <= 4);
+
+ if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_sort(acl_d);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ struct stat s;
+ struct acl *acl_p;
+ int acl_count;
+ struct acl *acl_buf = NULL;
+ int ret;
+
+ if(hpux_acl_call_presence() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ errno=ENOSYS;
+ return -1;
+ }
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ acl_p = &acl_d->acl[0];
+ acl_count = acl_d->count;
+
+ /*
+ * if it's a directory there is extra work to do
+ * since the acl() system call will replace both
+ * the access ACLs and the default ACLs (if any)
+ */
+ if (stat(name, &s) != 0) {
+ return -1;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ SMB_ACL_T acc_acl;
+ SMB_ACL_T def_acl;
+ SMB_ACL_T tmp_acl;
+ int i;
+
+ if (type == SMB_ACL_TYPE_ACCESS) {
+ acc_acl = acl_d;
+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
+
+ } else {
+ def_acl = acl_d;
+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (tmp_acl == NULL) {
+ return -1;
+ }
+
+ /*
+ * allocate a temporary buffer for the complete ACL
+ */
+ acl_count = acc_acl->count + def_acl->count;
+ acl_p = acl_buf = malloc(acl_count * sizeof(acl_buf[0]));
+
+ if (acl_buf == NULL) {
+ sys_acl_free_acl(tmp_acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /*
+ * copy the access control and default entries into the buffer
+ */
+ memcpy(&acl_buf[0], &acc_acl->acl[0],
+ acc_acl->count * sizeof(acl_buf[0]));
+
+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
+ def_acl->count * sizeof(acl_buf[0]));
+
+ /*
+ * set the ACL_DEFAULT flag on the default entries
+ */
+ for (i = acc_acl->count; i < acl_count; i++) {
+ acl_buf[i].a_type |= ACL_DEFAULT;
+ }
+
+ sys_acl_free_acl(tmp_acl);
+
+ } else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = acl(name, ACL_SET, acl_count, acl_p);
+
+ if (acl_buf) {
+ free(acl_buf);
+ }
+
+ return ret;
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+
+ files_struct *fsp = file_find_fd(fd);
+
+ if (fsp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+
+ return sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), SMB_ACL_TYPE_ACCESS, acl_d);
+}
+
+int sys_acl_delete_def_file(const char *path)
+{
+ SMB_ACL_T acl_d;
+ int ret;
+
+ /*
+ * fetching the access ACL and rewriting it has
+ * the effect of deleting the default ACL
+ */
+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
+ return -1;
+ }
+
+ ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
+
+ sys_acl_free_acl(acl_d);
+
+ return ret;
+}
+
+int sys_acl_free_text(char *text)
+{
+ free(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ free(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_IRIX_ACLS)
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->aclp->acl_cnt) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->ae_tag;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = entry_d;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->ae_tag != SMB_ACL_USER
+ && entry_d->ae_tag != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->ae_id;
+}
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T a;
+
+ if ((a = malloc(sizeof(*a))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
+ SAFE_FREE(a);
+ return NULL;
+ }
+ a->next = -1;
+ a->freeaclp = True;
+ return a;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ SMB_ACL_T a;
+
+ if ((a = malloc(sizeof(*a))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if ((a->aclp = acl_get_fd(fd)) == NULL) {
+ SAFE_FREE(a);
+ return NULL;
+ }
+ a->next = -1;
+ a->freeaclp = True;
+ return a;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ permset_d->ae_perm = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ permset_d->ae_perm |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return permset_d->ae_perm & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ return acl_to_text(acl_d->aclp, len_p);
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if ((a = malloc(sizeof(*a) + sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->next = -1;
+ a->freeaclp = False;
+ a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
+ a->aclp->acl_cnt = 0;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
+ entry_d->ae_tag = 0;
+ entry_d->ae_id = 0;
+ entry_d->ae_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->ae_tag = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->ae_tag != SMB_ACL_GROUP
+ && entry_d->ae_tag != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->ae_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->ae_perm = permset_d->ae_perm;
+
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_valid(acl_d->aclp);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return acl_set_file(name, type, acl_d->aclp);
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ return acl_set_fd(fd, acl_d->aclp);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file(name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return acl_free(text);
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ if (acl_d->freeaclp) {
+ acl_free(acl_d->aclp);
+ }
+ acl_free(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_AIX_ACLS)
+
+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
+
+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ struct acl_entry_link *link;
+ struct new_acl_entry *entry;
+ int keep_going;
+
+ DEBUG(10,("This is the count: %d\n",theacl->count));
+
+ /* Check if count was previously set to -1. *
+ * If it was, that means we reached the end *
+ * of the acl last time. */
+ if(theacl->count == -1)
+ return(0);
+
+ link = theacl;
+ /* To get to the next acl, traverse linked list until index *
+ * of acl matches the count we are keeping. This count is *
+ * incremented each time we return an acl entry. */
+
+ for(keep_going = 0; keep_going < theacl->count; keep_going++)
+ link = link->nextp;
+
+ entry = *entry_p = link->entryp;
+
+ DEBUG(10,("*entry_p is %d\n",entry_p));
+ DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
+
+ /* Increment count */
+ theacl->count++;
+ if(link->nextp == NULL)
+ theacl->count = -1;
+
+ return(1);
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ /* Initialize tag type */
+
+ *tag_type_p = -1;
+ DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
+
+ /* Depending on what type of entry we have, *
+ * return tag type. */
+ switch(entry_d->ace_id->id_type) {
+ case ACEID_USER:
+ *tag_type_p = SMB_ACL_USER;
+ break;
+ case ACEID_GROUP:
+ *tag_type_p = SMB_ACL_GROUP;
+ break;
+
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ *tag_type_p = entry_d->ace_id->id_type;
+ break;
+
+ default:
+ return(-1);
+ }
+
+ return(0);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
+ *permset_p = &entry_d->ace_access;
+ DEBUG(10,("**permset_p is %d\n",**permset_p));
+ if(!(**permset_p & S_IXUSR) &&
+ !(**permset_p & S_IWUSR) &&
+ !(**permset_p & S_IRUSR) &&
+ (**permset_p != 0))
+ return(-1);
+
+ DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
+ return(0);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return(entry_d->ace_id->id_data);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ struct acl *file_acl = (struct acl *)NULL;
+ struct acl_entry *acl_entry;
+ struct new_acl_entry *new_acl_entry;
+ struct ace_id *idp;
+ struct acl_entry_link *acl_entry_link;
+ struct acl_entry_link *acl_entry_link_head;
+ int i;
+ int rc = 0;
+ uid_t user_id;
+
+ /* Get the acl using statacl */
+
+ DEBUG(10,("Entering sys_acl_get_file\n"));
+ DEBUG(10,("path_p is %s\n",path_p));
+
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
+ if(rc == -1) {
+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+ /* Point to the first acl entry in the acl */
+ acl_entry = file_acl->acl_ext;
+
+ /* Begin setting up the head of the linked list *
+ * that will be used for the storing the acl *
+ * in a way that is useful for the posix_acls.c *
+ * code. */
+
+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
+ if(acl_entry_link_head == NULL)
+ return(NULL);
+
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ DEBUG(10,("acl_entry is %d\n",acl_entry));
+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
+
+ /* Check if the extended acl bit is on. *
+ * If it isn't, do not show the *
+ * contents of the acl since AIX intends *
+ * the extended info to remain unused */
+
+ if(file_acl->acl_mode & S_IXACL){
+ /* while we are not pointing to the very end */
+ while(acl_entry < acl_last(file_acl)) {
+ /* before we malloc anything, make sure this is */
+ /* a valid acl entry and one that we want to map */
+ idp = id_nxt(acl_entry->ace_id);
+ if((acl_entry->ace_type == ACC_SPECIFY ||
+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
+ acl_entry = acl_nxt(acl_entry);
+ continue;
+ }
+
+ idp = acl_entry->ace_id;
+
+ /* Check if this is the first entry in the linked list. *
+ * The first entry needs to keep prevp pointing to NULL *
+ * and already has entryp allocated. */
+
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)
+ malloc(sizeof(struct acl_entry_link));
+
+ if(acl_entry_link->nextp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+ acl_entry_link->nextp = NULL;
+ }
+
+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
+
+ /* Don't really need this since all types are going *
+ * to be specified but, it's better than leaving it 0 */
+
+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
+
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+
+ memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
+
+ /* The access in the acl entries must be left shifted by *
+ * three bites, because they will ultimately be compared *
+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
+
+ switch(acl_entry->ace_type){
+ case ACC_PERMIT:
+ case ACC_SPECIFY:
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ case ACC_DENY:
+ /* Since there is no way to return a DENY acl entry *
+ * change to PERMIT and then shift. */
+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ default:
+ return(0);
+ }
+
+ DEBUG(10,("acl_entry = %d\n",acl_entry));
+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
+
+ acl_entry = acl_nxt(acl_entry);
+ }
+ } /* end of if enabled */
+
+ /* Since owner, group, other acl entries are not *
+ * part of the acl entries in an acl, they must *
+ * be dummied up to become part of the list. */
+
+ for( i = 1; i < 4; i++) {
+ DEBUG(10,("i is %d\n",i));
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+ }
+
+ acl_entry_link->nextp = NULL;
+
+ new_acl_entry = acl_entry_link->entryp;
+ idp = new_acl_entry->ace_id;
+
+ new_acl_entry->ace_len = sizeof(struct acl_entry);
+ new_acl_entry->ace_type = ACC_PERMIT;
+ idp->id_len = sizeof(struct ace_id);
+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
+ memset(idp->id_data,0,sizeof(uid_t));
+
+ switch(i) {
+ case 2:
+ new_acl_entry->ace_access = file_acl->g_access << 6;
+ idp->id_type = SMB_ACL_GROUP_OBJ;
+ break;
+
+ case 3:
+ new_acl_entry->ace_access = file_acl->o_access << 6;
+ idp->id_type = SMB_ACL_OTHER;
+ break;
+
+ case 1:
+ new_acl_entry->ace_access = file_acl->u_access << 6;
+ idp->id_type = SMB_ACL_USER_OBJ;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ acl_entry_link_head->count++;
+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
+ }
+
+ acl_entry_link_head->count = 0;
+ SAFE_FREE(file_acl);
+
+ return(acl_entry_link_head);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ struct acl *file_acl = (struct acl *)NULL;
+ struct acl_entry *acl_entry;
+ struct new_acl_entry *new_acl_entry;
+ struct ace_id *idp;
+ struct acl_entry_link *acl_entry_link;
+ struct acl_entry_link *acl_entry_link_head;
+ int i;
+ int rc = 0;
+ uid_t user_id;
+
+ /* Get the acl using fstatacl */
+
+ DEBUG(10,("Entering sys_acl_get_fd\n"));
+ DEBUG(10,("fd is %d\n",fd));
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = fstatacl(fd,0,file_acl,BUFSIZ);
+ if(rc == -1) {
+ DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+ /* Point to the first acl entry in the acl */
+
+ acl_entry = file_acl->acl_ext;
+ /* Begin setting up the head of the linked list *
+ * that will be used for the storing the acl *
+ * in a way that is useful for the posix_acls.c *
+ * code. */
+
+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
+ if(acl_entry_link_head == NULL){
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+
+ if(acl_entry_link->entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("acl_entry is %d\n",acl_entry));
+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
+
+ /* Check if the extended acl bit is on. *
+ * If it isn't, do not show the *
+ * contents of the acl since AIX intends *
+ * the extended info to remain unused */
+
+ if(file_acl->acl_mode & S_IXACL){
+ /* while we are not pointing to the very end */
+ while(acl_entry < acl_last(file_acl)) {
+ /* before we malloc anything, make sure this is */
+ /* a valid acl entry and one that we want to map */
+
+ idp = id_nxt(acl_entry->ace_id);
+ if((acl_entry->ace_type == ACC_SPECIFY ||
+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
+ acl_entry = acl_nxt(acl_entry);
+ continue;
+ }
+
+ idp = acl_entry->ace_id;
+
+ /* Check if this is the first entry in the linked list. *
+ * The first entry needs to keep prevp pointing to NULL *
+ * and already has entryp allocated. */
+
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->nextp = NULL;
+ }
+
+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
+
+ /* Don't really need this since all types are going *
+ * to be specified but, it's better than leaving it 0 */
+
+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+
+ memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
+
+ /* The access in the acl entries must be left shifted by *
+ * three bites, because they will ultimately be compared *
+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
+
+ switch(acl_entry->ace_type){
+ case ACC_PERMIT:
+ case ACC_SPECIFY:
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ case ACC_DENY:
+ /* Since there is no way to return a DENY acl entry *
+ * change to PERMIT and then shift. */
+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ default:
+ return(0);
+ }
+
+ DEBUG(10,("acl_entry = %d\n",acl_entry));
+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
+
+ acl_entry = acl_nxt(acl_entry);
+ }
+ } /* end of if enabled */
+
+ /* Since owner, group, other acl entries are not *
+ * part of the acl entries in an acl, they must *
+ * be dummied up to become part of the list. */
+
+ for( i = 1; i < 4; i++) {
+ DEBUG(10,("i is %d\n",i));
+ if(acl_entry_link_head->count != 0){
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ return(NULL);
+ }
+ }
+
+ acl_entry_link->nextp = NULL;
+
+ new_acl_entry = acl_entry_link->entryp;
+ idp = new_acl_entry->ace_id;
+
+ new_acl_entry->ace_len = sizeof(struct acl_entry);
+ new_acl_entry->ace_type = ACC_PERMIT;
+ idp->id_len = sizeof(struct ace_id);
+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
+ memset(idp->id_data,0,sizeof(uid_t));
+
+ switch(i) {
+ case 2:
+ new_acl_entry->ace_access = file_acl->g_access << 6;
+ idp->id_type = SMB_ACL_GROUP_OBJ;
+ break;
+
+ case 3:
+ new_acl_entry->ace_access = file_acl->o_access << 6;
+ idp->id_type = SMB_ACL_OTHER;
+ break;
+
+ case 1:
+ new_acl_entry->ace_access = file_acl->u_access << 6;
+ idp->id_type = SMB_ACL_USER_OBJ;
+ break;
+
+ default:
+ return(NULL);
+ }
+
+ acl_entry_link_head->count++;
+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
+ }
+
+ acl_entry_link_head->count = 0;
+ SAFE_FREE(file_acl);
+
+ return(acl_entry_link_head);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ *permset = *permset & ~0777;
+ return(0);
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ if((perm != 0) &&
+ (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
+ return(-1);
+
+ *permset |= perm;
+ DEBUG(10,("This is the permset now: %d\n",*permset));
+ return(0);
+}
+
+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
+{
+ return(NULL);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ struct acl_entry_link *theacl = NULL;
+
+ DEBUG(10,("Entering sys_acl_init\n"));
+
+ theacl = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(theacl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_init is %d\n",errno));
+ return(NULL);
+ }
+
+ theacl->count = 0;
+ theacl->nextp = NULL;
+ theacl->prevp = NULL;
+ theacl->entryp = NULL;
+ DEBUG(10,("Exiting sys_acl_init\n"));
+ return(theacl);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ struct acl_entry_link *theacl;
+ struct acl_entry_link *acl_entryp;
+ struct acl_entry_link *temp_entry;
+ int counting;
+
+ DEBUG(10,("Entering the sys_acl_create_entry\n"));
+
+ theacl = acl_entryp = *pacl;
+
+ /* Get to the end of the acl before adding entry */
+
+ for(counting=0; counting < theacl->count; counting++){
+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
+ temp_entry = acl_entryp;
+ acl_entryp = acl_entryp->nextp;
+ }
+
+ if(theacl->count != 0){
+ temp_entry->nextp = acl_entryp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
+ return(-1);
+ }
+
+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
+ acl_entryp->prevp = temp_entry;
+ DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
+ }
+
+ *pentry = acl_entryp->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(*pentry == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
+ return(-1);
+ }
+
+ memset(*pentry,0,sizeof(struct new_acl_entry));
+ acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
+ acl_entryp->entryp->ace_type = ACC_PERMIT;
+ acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
+ acl_entryp->nextp = NULL;
+ theacl->count++;
+ DEBUG(10,("Exiting sys_acl_create_entry\n"));
+ return(0);
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
+ entry->ace_id->id_type = tagtype;
+ DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
+ DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
+ memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
+ DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
+ return(0);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
+ if(!(*permset & S_IXUSR) &&
+ !(*permset & S_IWUSR) &&
+ !(*permset & S_IRUSR) &&
+ (*permset != 0))
+ return(-1);
+
+ entry->ace_access = *permset;
+ DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
+ DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
+ return(0);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ int user_obj = 0;
+ int group_obj = 0;
+ int other_obj = 0;
+ struct acl_entry_link *acl_entry;
+
+ for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
+ user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
+ group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
+ other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
+ }
+
+ DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
+
+ if(user_obj != 1 || group_obj != 1 || other_obj != 1)
+ return(-1);
+
+ return(0);
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ struct acl_entry_link *acl_entry_link = NULL;
+ struct acl *file_acl = NULL;
+ struct acl *file_acl_temp = NULL;
+ struct acl_entry *acl_entry = NULL;
+ struct ace_id *ace_id = NULL;
+ uint id_type;
+ uint ace_access;
+ uint user_id;
+ uint acl_length;
+ uint rc;
+
+ DEBUG(10,("Entering sys_acl_set_file\n"));
+ DEBUG(10,("File name is %s\n",name));
+
+ /* AIX has no default ACL */
+ if(acltype == SMB_ACL_TYPE_DEFAULT)
+ return(0);
+
+ acl_length = BUFSIZ;
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
+ return(-1);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ file_acl->acl_len = ACL_SIZ;
+ file_acl->acl_mode = S_IXACL;
+
+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
+ acl_entry_link->entryp->ace_access >>= 6;
+ id_type = acl_entry_link->entryp->ace_id->id_type;
+
+ switch(id_type) {
+ case SMB_ACL_USER_OBJ:
+ file_acl->u_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_GROUP_OBJ:
+ file_acl->g_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_OTHER:
+ file_acl->o_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_MASK:
+ continue;
+ }
+
+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
+ acl_length += sizeof(struct acl_entry);
+ file_acl_temp = (struct acl *)malloc(acl_length);
+ if(file_acl_temp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
+ return(-1);
+ }
+
+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
+ SAFE_FREE(file_acl);
+ file_acl = file_acl_temp;
+ }
+
+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
+ file_acl->acl_len += sizeof(struct acl_entry);
+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
+
+ /* In order to use this, we'll need to wait until we can get denies */
+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
+ acl_entry->ace_type = ACC_SPECIFY; */
+
+ acl_entry->ace_type = ACC_SPECIFY;
+
+ ace_id = acl_entry->ace_id;
+
+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
+ memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
+ }
+
+ rc = chacl(name,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting the sys_acl_set_file\n"));
+ return(rc);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ struct acl_entry_link *acl_entry_link = NULL;
+ struct acl *file_acl = NULL;
+ struct acl *file_acl_temp = NULL;
+ struct acl_entry *acl_entry = NULL;
+ struct ace_id *ace_id = NULL;
+ uint id_type;
+ uint user_id;
+ uint acl_length;
+ uint rc;
+
+ DEBUG(10,("Entering sys_acl_set_fd\n"));
+ acl_length = BUFSIZ;
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
+ return(-1);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ file_acl->acl_len = ACL_SIZ;
+ file_acl->acl_mode = S_IXACL;
+
+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
+ acl_entry_link->entryp->ace_access >>= 6;
+ id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id_type is %d\n",id_type));
+
+ switch(id_type) {
+ case SMB_ACL_USER_OBJ:
+ file_acl->u_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_GROUP_OBJ:
+ file_acl->g_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_OTHER:
+ file_acl->o_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_MASK:
+ continue;
+ }
+
+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
+ acl_length += sizeof(struct acl_entry);
+ file_acl_temp = (struct acl *)malloc(acl_length);
+ if(file_acl_temp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
+ return(-1);
+ }
+
+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
+ SAFE_FREE(file_acl);
+ file_acl = file_acl_temp;
+ }
+
+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
+ file_acl->acl_len += sizeof(struct acl_entry);
+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
+
+ /* In order to use this, we'll need to wait until we can get denies */
+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
+ acl_entry->ace_type = ACC_SPECIFY; */
+
+ acl_entry->ace_type = ACC_SPECIFY;
+
+ ace_id = acl_entry->ace_id;
+
+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
+ memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
+ }
+
+ rc = fchacl(fd,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting sys_acl_set_fd\n"));
+ return(rc);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ /* AIX has no default ACL */
+ return 0;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return(*permset & perm);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return(0);
+}
+
+int sys_acl_free_acl(SMB_ACL_T posix_acl)
+{
+ struct acl_entry_link *acl_entry_link;
+
+ for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
+ SAFE_FREE(acl_entry_link->prevp->entryp);
+ SAFE_FREE(acl_entry_link->prevp);
+ }
+
+ SAFE_FREE(acl_entry_link->prevp->entryp);
+ SAFE_FREE(acl_entry_link->prevp);
+ SAFE_FREE(acl_entry_link->entryp);
+ SAFE_FREE(acl_entry_link);
+
+ return(0);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return(0);
+}
+
+#else /* No ACLs. */
+
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ errno = ENOSYS;
+ return (SMB_ACL_T)NULL;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ errno = ENOSYS;
+ return (SMB_ACL_T)NULL;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ errno = ENOSYS;
+ return (permset & perm) ? 1 : 0;
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+int sys_acl_free_text(char *text)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif /* No ACLs. */
diff --git a/source/lib/system.c b/source/lib/system.c
index 938746e9c9d..4114ce456cf 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Samba system utilities
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,202 +21,964 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/*
The idea is that this file will eventually have wrappers around all
- important system calls in samba. The aim is twofold:
+ important system calls in samba. The aims are:
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other "pseudo-filesystems"
- to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
*/
+
/*******************************************************************
-this replaces the normal select() system call
-return if some data has arrived on one of the file descriptors
-return -1 means error
+ A wrapper for usleep in case we don't have one.
********************************************************************/
-#ifdef NO_SELECT
-static int pollfd(int fd)
-{
- int r=0;
-#ifdef HAS_RDCHK
- r = rdchk(fd);
-#elif defined(TCRDCHK)
- (void)ioctl(fd, TCRDCHK, &r);
-#else
- (void)ioctl(fd, FIONREAD, &r);
+int sys_usleep(long usecs)
+{
+#ifndef HAVE_USLEEP
+ struct timeval tval;
#endif
- return(r);
+ /*
+ * We need this braindamage as the glibc usleep
+ * is not SPEC1170 complient... grumble... JRA.
+ */
+
+ if(usecs < 0 || usecs > 1000000) {
+ errno = EINVAL;
+ return -1;
+ }
+
+#if HAVE_USLEEP
+ usleep(usecs);
+ return 0;
+#else /* HAVE_USLEEP */
+ /*
+ * Fake it with select...
+ */
+ tval.tv_sec = 0;
+ tval.tv_usec = usecs/1000;
+ select(0,NULL,NULL,NULL,&tval);
+ return 0;
+#endif /* HAVE_USLEEP */
}
-int sys_select(fd_set *fds,struct timeval *tval)
+/*******************************************************************
+A stat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
{
- fd_set fds2;
- int counter=0;
- int found=0;
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
+ ret = stat64(fname, sbuf);
+#else
+ ret = stat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
- FD_ZERO(&fds2);
+/*******************************************************************
+ An fstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
- while (1)
- {
- int i;
- for (i=0;i<255;i++) {
- if (FD_ISSET(i,fds) && pollfd(i)>0) {
- found++;
- FD_SET(i,&fds2);
- }
- }
-
- if (found) {
- memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
- return(found);
- }
-
- if (tval && tval.tv_sec < counter) return(0);
- sleep(1);
- counter++;
- }
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
+ ret = fstat64(fd, sbuf);
+#else
+ ret = fstat(fd, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
}
-#else
-int sys_select(fd_set *fds,struct timeval *tval)
+/*******************************************************************
+ An lstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
{
- struct timeval t2;
- int selrtn;
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
+ ret = lstat64(fname, sbuf);
+#else
+ ret = lstat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
- do {
- if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
- errno = 0;
- selrtn = select(16,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
- } while (selrtn<0 && errno == EINTR);
+/*******************************************************************
+ An ftruncate() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
- return(selrtn);
-}
+int sys_ftruncate(int fd, SMB_OFF_T offset)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
+ return ftruncate64(fd, offset);
+#else
+ return ftruncate(fd, offset);
#endif
-
+}
/*******************************************************************
-just a unlink wrapper
+ An lseek() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_unlink(char *fname)
+
+SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
{
- return(unlink(dos_to_unix(fname,False)));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
+ return lseek64(fd, offset, whence);
+#else
+ return lseek(fd, offset, whence);
+#endif
}
-
/*******************************************************************
-a simple open() wrapper
+ An fseek() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_open(char *fname,int flags,int mode)
+
+int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
{
- return(open(dos_to_unix(fname,False),flags,mode));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
+ return fseek64(fp, offset, whence);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
+ return fseeko64(fp, offset, whence);
+#else
+ return fseek(fp, offset, whence);
+#endif
}
-
/*******************************************************************
-a simple opendir() wrapper
+ An ftell() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-DIR *sys_opendir(char *dname)
+
+SMB_OFF_T sys_ftell(FILE *fp)
{
- return(opendir(dos_to_unix(dname,False)));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
+ return (SMB_OFF_T)ftell64(fp);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
+ return (SMB_OFF_T)ftello64(fp);
+#else
+ return (SMB_OFF_T)ftell(fp);
+#endif
}
-
/*******************************************************************
-and a stat() wrapper
+ A creat() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_stat(char *fname,struct stat *sbuf)
+
+int sys_creat(const char *path, mode_t mode)
{
- return(stat(dos_to_unix(fname,False),sbuf));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
+ return creat64(path, mode);
+#else
+ /*
+ * If creat64 isn't defined then ensure we call a potential open64.
+ * JRA.
+ */
+ return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+#endif
}
/*******************************************************************
-don't forget lstat()
+ An open() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_lstat(char *fname,struct stat *sbuf)
+
+int sys_open(const char *path, int oflag, mode_t mode)
{
- return(lstat(dos_to_unix(fname,False),sbuf));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
+ return open64(path, oflag, mode);
+#else
+ return open(path, oflag, mode);
+#endif
}
-
/*******************************************************************
-mkdir() gets a wrapper
+ An fopen() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_mkdir(char *dname,int mode)
+
+FILE *sys_fopen(const char *path, const char *type)
{
- return(mkdir(dos_to_unix(dname,False),mode));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
+ return fopen64(path, type);
+#else
+ return fopen(path, type);
+#endif
}
-
/*******************************************************************
-do does rmdir()
+ A readdir wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_rmdir(char *dname)
+
+SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
{
- return(rmdir(dos_to_unix(dname,False)));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
+ return readdir64(dirp);
+#else
+ return readdir(dirp);
+#endif
}
-
/*******************************************************************
-I almost forgot chdir()
+The wait() calls vary between systems
********************************************************************/
-int sys_chdir(char *dname)
+
+int sys_waitpid(pid_t pid,int *status,int options)
{
- return(chdir(dos_to_unix(dname,False)));
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* HAVE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* HAVE_WAITPID */
}
-
/*******************************************************************
-now for utime()
+system wrapper for getwd
********************************************************************/
-int sys_utime(char *fname,struct utimbuf *times)
+char *sys_getwd(char *s)
{
- return(utime(dos_to_unix(fname,False),times));
+ char *wd;
+#ifdef HAVE_GETCWD
+ wd = (char *)getcwd(s, sizeof (pstring));
+#else
+ wd = (char *)getwd(s);
+#endif
+ return wd;
}
/*******************************************************************
-for rename()
+system wrapper for symlink
********************************************************************/
-int sys_rename(char *from, char *to)
+
+int sys_symlink(const char *oldpath, const char *newpath)
{
-#ifdef KANJI
- pstring zfrom, zto;
- strcpy (zfrom, dos_to_unix (from, False));
- strcpy (zto, dos_to_unix (to, False));
- return rename (zfrom, zto);
-#else
- return rename (from, to);
-#endif /* KANJI */
+#ifndef HAVE_SYMLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return symlink(oldpath, newpath);
+#endif
}
+/*******************************************************************
+system wrapper for readlink
+********************************************************************/
+
+int sys_readlink(const char *path, char *buf, size_t bufsiz)
+{
+#ifndef HAVE_READLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return readlink(path, buf, bufsiz);
+#endif
+}
/*******************************************************************
chown isn't used much but OS/2 doesn't have it
********************************************************************/
-int sys_chown(char *fname,int uid,int gid)
+
+int sys_chown(const char *fname,uid_t uid,gid_t gid)
{
-#ifdef NO_CHOWN
- DEBUG(1,("Warning - chown(%s,%d,%d) not done\n",fname,uid,gid));
+#ifndef HAVE_CHOWN
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chown!\n"));
+ done=1;
+ }
#else
- return(chown(fname,uid,gid));
+ return(chown(fname,uid,gid));
#endif
}
/*******************************************************************
os/2 also doesn't have chroot
********************************************************************/
-int sys_chroot(char *dname)
+int sys_chroot(const char *dname)
+{
+#ifndef HAVE_CHROOT
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chroot!\n"));
+ done=1;
+ }
+ errno = ENOSYS;
+ return -1;
+#else
+ return(chroot(dname));
+#endif
+}
+
+/**************************************************************************
+A wrapper for gethostbyname() that tries avoids looking up hostnames
+in the root domain, which can cause dial-on-demand links to come up for no
+apparent reason.
+****************************************************************************/
+struct hostent *sys_gethostbyname(const char *name)
+{
+#ifdef REDUCE_ROOT_DNS_LOOKUPS
+ char query[256], hostname[256];
+ char *domain;
+
+ /* Does this name have any dots in it? If so, make no change */
+
+ if (strchr_m(name, '.'))
+ return(gethostbyname(name));
+
+ /* Get my hostname, which should have domain name
+ attached. If not, just do the gethostname on the
+ original string.
+ */
+
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = 0;
+ if ((domain = strchr_m(hostname, '.')) == NULL)
+ return(gethostbyname(name));
+
+ /* Attach domain name to query and do modified query.
+ If names too large, just do gethostname on the
+ original string.
+ */
+
+ if((strlen(name) + strlen(domain)) >= sizeof(query))
+ return(gethostbyname(name));
+
+ slprintf(query, sizeof(query)-1, "%s%s", name, domain);
+ return(gethostbyname(query));
+#else /* REDUCE_ROOT_DNS_LOOKUPS */
+ return(gethostbyname(name));
+#endif /* REDUCE_ROOT_DNS_LOOKUPS */
+}
+
+
+#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+/**************************************************************************
+ Try and abstract process capabilities (for systems that have them).
+****************************************************************************/
+static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
+ {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_effective |= CAP_NETWORK_MGT;
+ else
+ cap->cap_effective &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+
+/**************************************************************************
+ Try and abstract inherited process capabilities (for systems that have them).
+****************************************************************************/
+
+static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
+ {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_inheritable |= CAP_NETWORK_MGT;
+ else
+ cap->cap_inheritable &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+#endif
+
+/****************************************************************************
+gain the oplock capability from the kernel if possible
+****************************************************************************/
+void oplock_set_capability(BOOL this_process, BOOL inherit)
+{
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for random().
+****************************************************************************/
+
+long sys_random(void)
+{
+#if defined(HAVE_RANDOM)
+ return (long)random();
+#elif defined(HAVE_RAND)
+ return (long)rand();
+#else
+ DEBUG(0,("Error - no random function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for srandom().
+****************************************************************************/
+
+void sys_srandom(unsigned int seed)
+{
+#if defined(HAVE_SRANDOM)
+ srandom(seed);
+#elif defined(HAVE_SRAND)
+ srand(seed);
+#else
+ DEBUG(0,("Error - no srandom function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Returns equivalent to NGROUPS_MAX - using sysconf if needed.
+****************************************************************************/
+
+int groups_max(void)
+{
+#if defined(SYSCONF_SC_NGROUPS_MAX)
+ int ret = sysconf(_SC_NGROUPS_MAX);
+ return (ret == -1) ? NGROUPS_MAX : ret;
+#else
+ return NGROUPS_MAX;
+#endif
+}
+
+/**************************************************************************
+ Wrapper for getgroups. Deals with broken (int) case.
+****************************************************************************/
+
+int sys_getgroups(int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_BROKEN_GETGROUPS)
+ return getgroups(setlen, gidset);
+#else
+
+ GID_T gid;
+ GID_T *group_list;
+ int i, ngroups;
+
+ if(setlen == 0) {
+ return getgroups(setlen, &gid);
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if(setlen < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (setlen == 0)
+ setlen = groups_max();
+
+ if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+ DEBUG(0,("sys_getgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ if((ngroups = getgroups(setlen, group_list)) < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ for(i = 0; i < ngroups; i++)
+ gidset[i] = (gid_t)group_list[i];
+
+ SAFE_FREE(group_list);
+ return ngroups;
+#endif /* HAVE_BROKEN_GETGROUPS */
+}
+
+#ifdef HAVE_SETGROUPS
+
+/**************************************************************************
+ Wrapper for setgroups. Deals with broken (int) case. Automatically used
+ if we have broken getgroups.
+****************************************************************************/
+
+int sys_setgroups(int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_BROKEN_GETGROUPS)
+ return setgroups(setlen, gidset);
+#else
+
+ GID_T *group_list;
+ int i ;
+
+ if (setlen == 0)
+ return 0 ;
+
+ if (setlen < 0 || setlen > groups_max()) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+ DEBUG(0,("sys_setgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ for(i = 0; i < setlen; i++)
+ group_list[i] = (GID_T) gidset[i];
+
+ if(setgroups(setlen, group_list) != 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ SAFE_FREE(group_list);
+ return 0 ;
+#endif /* HAVE_BROKEN_GETGROUPS */
+}
+
+#endif /* HAVE_SETGROUPS */
+
+/*
+ * We only wrap pw_name and pw_passwd for now as these
+ * are the only potentially modified fields.
+ */
+
+/**************************************************************************
+ Helper function for getpwnam/getpwuid wrappers.
+****************************************************************************/
+
+struct saved_pw {
+ fstring pw_name;
+ fstring pw_passwd;
+ fstring pw_gecos;
+ pstring pw_dir;
+ pstring pw_shell;
+ struct passwd pass;
+};
+
+static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
+static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
+
+static int num_lookups; /* Counter so we don't always use cache. */
+#ifndef PW_RET_CACHE_MAX_LOOKUPS
+#define PW_RET_CACHE_MAX_LOOKUPS 100
+#endif
+
+static void copy_pwent(struct saved_pw *dst, struct passwd *pass)
+{
+ memcpy((char *)&dst->pass, pass, sizeof(struct passwd));
+
+ fstrcpy(dst->pw_name, pass->pw_name);
+ dst->pass.pw_name = dst->pw_name;
+
+ fstrcpy(dst->pw_passwd, pass->pw_passwd);
+ dst->pass.pw_passwd = dst->pw_passwd;
+
+ fstrcpy(dst->pw_gecos, pass->pw_gecos);
+ dst->pass.pw_gecos = dst->pw_gecos;
+
+ pstrcpy(dst->pw_dir, pass->pw_dir);
+ dst->pass.pw_dir = dst->pw_dir;
+
+ pstrcpy(dst->pw_shell, pass->pw_shell);
+ dst->pass.pw_shell = dst->pw_shell;
+}
+
+static struct passwd *setup_pwret(struct passwd *pass)
+{
+ if (pass == NULL) {
+ /* Clear the caches. */
+ memset(&pw_cache, '\0', sizeof(struct saved_pw));
+ memset(&pw_mod, '\0', sizeof(struct saved_pw));
+ num_lookups = 0;
+ return NULL;
+ }
+
+ copy_pwent( &pw_mod, pass);
+
+ if (pass != &pw_cache.pass) {
+
+ /* If it's a cache miss we must also refill the cache. */
+
+ copy_pwent( &pw_cache, pass);
+ num_lookups = 1;
+
+ } else {
+
+ /* Cache hit. */
+
+ num_lookups++;
+ num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
+ }
+
+ return &pw_mod.pass;
+}
+
+/**************************************************************************
+ Wrappers for setpwent(), getpwent() and endpwent()
+****************************************************************************/
+
+void sys_setpwent(void)
+{
+ setup_pwret(NULL); /* Clear cache. */
+ setpwent();
+}
+
+struct passwd *sys_getpwent(void)
+{
+ return setup_pwret(getpwent());
+}
+
+void sys_endpwent(void)
+{
+ setup_pwret(NULL); /* Clear cache. */
+ endpwent();
+}
+
+/**************************************************************************
+ Wrapper for getpwnam(). Always returns a static that can be modified.
+****************************************************************************/
+
+struct passwd *sys_getpwnam(const char *name)
+{
+ if (!name || !name[0])
+ return NULL;
+
+ /* check for a cache hit first */
+ if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
+ return setup_pwret(&pw_cache.pass);
+ }
+
+ return setup_pwret(getpwnam(name));
+}
+
+/**************************************************************************
+ Wrapper for getpwuid(). Always returns a static that can be modified.
+****************************************************************************/
+
+struct passwd *sys_getpwuid(uid_t uid)
+{
+ if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
+ return setup_pwret(&pw_cache.pass);
+ }
+
+ return setup_pwret(getpwuid(uid));
+}
+
+/**************************************************************************
+ Extract a command into an arg list. Uses a static pstring for storage.
+ Caller frees returned arg list (which contains pointers into the static pstring).
+****************************************************************************/
+
+static char **extract_args(const char *command)
+{
+ static pstring trunc_cmd;
+ char *ptr;
+ int argcl;
+ char **argl = NULL;
+ int i;
+
+ pstrcpy(trunc_cmd, command);
+
+ if(!(ptr = strtok(trunc_cmd, " \t"))) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * Count the args.
+ */
+
+ for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
+ argcl++;
+
+ if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
+ return NULL;
+
+ /*
+ * Now do the extraction.
+ */
+
+ pstrcpy(trunc_cmd, command);
+
+ ptr = strtok(trunc_cmd, " \t");
+ i = 0;
+ argl[i++] = ptr;
+
+ while((ptr = strtok(NULL, " \t")) != NULL)
+ argl[i++] = ptr;
+
+ argl[i++] = NULL;
+ return argl;
+}
+
+/**************************************************************************
+ Wrapper for fork. Ensures that mypid is reset. Used so we can write
+ a sys_getpid() that only does a system call *once*.
+****************************************************************************/
+
+static pid_t mypid = (pid_t)-1;
+
+pid_t sys_fork(void)
+{
+ pid_t forkret = fork();
+
+ if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
+ mypid = (pid_t) -1;
+
+ return forkret;
+}
+
+/**************************************************************************
+ Wrapper for getpid. Ensures we only do a system call *once*.
+****************************************************************************/
+
+pid_t sys_getpid(void)
+{
+ if (mypid == (pid_t)-1)
+ mypid = getpid();
+
+ return mypid;
+}
+
+/**************************************************************************
+ Wrapper for popen. Safer as it doesn't search a path.
+ Modified from the glibc sources.
+ modified by tridge to return a file descriptor. We must kick our FILE* habit
+****************************************************************************/
+
+typedef struct _popen_list
+{
+ int fd;
+ pid_t child_pid;
+ struct _popen_list *next;
+} popen_list;
+
+static popen_list *popen_chain;
+
+int sys_popen(const char *command)
+{
+ int parent_end, child_end;
+ int pipe_fds[2];
+ popen_list *entry = NULL;
+ char **argl = NULL;
+
+ if (pipe(pipe_fds) < 0)
+ return -1;
+
+ parent_end = pipe_fds[0];
+ child_end = pipe_fds[1];
+
+ if (!*command) {
+ errno = EINVAL;
+ goto err_exit;
+ }
+
+ if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
+ goto err_exit;
+
+ ZERO_STRUCTP(entry);
+
+ /*
+ * Extract the command and args into a NULL terminated array.
+ */
+
+ if(!(argl = extract_args(command)))
+ goto err_exit;
+
+ entry->child_pid = sys_fork();
+
+ if (entry->child_pid == -1) {
+ goto err_exit;
+ }
+
+ if (entry->child_pid == 0) {
+
+ /*
+ * Child !
+ */
+
+ int child_std_end = STDOUT_FILENO;
+ popen_list *p;
+
+ close(parent_end);
+ if (child_end != child_std_end) {
+ dup2 (child_end, child_std_end);
+ close (child_end);
+ }
+
+ /*
+ * POSIX.2: "popen() shall ensure that any streams from previous
+ * popen() calls that remain open in the parent process are closed
+ * in the new child process."
+ */
+
+ for (p = popen_chain; p; p = p->next)
+ close(p->fd);
+
+ execv(argl[0], argl);
+ _exit (127);
+ }
+
+ /*
+ * Parent.
+ */
+
+ close (child_end);
+ SAFE_FREE(argl);
+
+ /* Link into popen_chain. */
+ entry->next = popen_chain;
+ popen_chain = entry;
+ entry->fd = parent_end;
+
+ return entry->fd;
+
+err_exit:
+
+ SAFE_FREE(entry);
+ SAFE_FREE(argl);
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return -1;
+}
+
+/**************************************************************************
+ Wrapper for pclose. Modified from the glibc sources.
+****************************************************************************/
+int sys_pclose(int fd)
+{
+ int wstatus;
+ popen_list **ptr = &popen_chain;
+ popen_list *entry = NULL;
+ pid_t wait_pid;
+ int status = -1;
+
+ /* Unlink from popen_chain. */
+ for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
+ if ((*ptr)->fd == fd) {
+ entry = *ptr;
+ *ptr = (*ptr)->next;
+ status = 0;
+ break;
+ }
+ }
+
+ if (status < 0 || close(entry->fd) < 0)
+ return -1;
+
+ /*
+ * As Samba is catching and eating child process
+ * exits we don't really care about the child exit
+ * code, a -1 with errno = ECHILD will do fine for us.
+ */
+
+ do {
+ wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ SAFE_FREE(entry);
+
+ if (wait_pid == -1)
+ return -1;
+ return wstatus;
+}
+
+/**************************************************************************
+ Wrappers for dlopen, dlsym, dlclose.
+****************************************************************************/
+
+void *sys_dlopen(const char *name, int flags)
+{
+#ifdef HAVE_LIBDL
+ return dlopen(name, flags);
+#else
+ return NULL;
+#endif
+}
+
+void *sys_dlsym(void *handle, char *symbol)
+{
+#ifdef HAVE_LIBDL
+ return dlsym(handle, symbol);
+#else
+ return NULL;
+#endif
+}
+
+int sys_dlclose (void *handle)
+{
+#ifdef HAVE_LIBDL
+ return dlclose(handle);
+#else
+ return 0;
+#endif
+}
+
+const char *sys_dlerror(void)
{
-#ifdef NO_CHROOT
- DEBUG(1,("Warning - chroot(%s) not done\n",dname));
+#ifdef HAVE_LIBDL
+ return dlerror();
#else
- return(chroot(dname));
+ return NULL;
#endif
}
diff --git a/source/lib/talloc.c b/source/lib/talloc.c
new file mode 100644
index 00000000000..8496170daf2
--- /dev/null
+++ b/source/lib/talloc.c
@@ -0,0 +1,313 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba temporary memory allocation functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ @defgroup talloc Simple memory allocator
+ @{
+
+ This is a very simple temporary memory allocator. To use it do the following:
+
+ 1) when you first want to allocate a pool of meomry use
+ talloc_init() and save the resulting context pointer somewhere
+
+ 2) to allocate memory use talloc()
+
+ 3) when _all_ of the memory allocated using this context is no longer needed
+ use talloc_destroy()
+
+ talloc does not zero the memory. It guarantees memory of a
+ TALLOC_ALIGN alignment
+
+ @sa talloc.h
+*/
+
+/**
+ * @todo We could allocate both the talloc_chunk structure, and the
+ * memory it contains all in one allocation, which might be a bit
+ * faster and perhaps use less memory overhead.
+ *
+ * That smells like a premature optimization, though. -- mbp
+ **/
+
+/**
+ * If you want testing for memory corruption, link with dmalloc or use
+ * Insure++. It doesn't seem useful to duplicate them here.
+ **/
+
+#include "includes.h"
+
+struct talloc_chunk {
+ struct talloc_chunk *next;
+ size_t size;
+ void *ptr;
+};
+
+
+struct talloc_ctx {
+ struct talloc_chunk *list;
+ size_t total_alloc_size;
+
+ /** The name recorded for this pool, if any. Should describe
+ * the purpose for which it was allocated. The string is
+ * allocated within the pool. **/
+ char *name;
+
+ /** Pointer to the next allocate talloc pool, so that we can
+ * summarize all talloc memory usage. **/
+ struct talloc_ctx *next_ctx;
+};
+
+
+/**
+ * Start of linked list of all talloc pools.
+ **/
+TALLOC_CTX *list_head = NULL;
+
+
+/**
+ * Add to the global list
+ **/
+static void talloc_enroll(TALLOC_CTX *t)
+{
+ t->next_ctx = list_head;
+ list_head = t;
+}
+
+
+static void talloc_disenroll(TALLOC_CTX *t)
+{
+ TALLOC_CTX **ttmp;
+
+ /* Use a double-* so that no special case is required for the
+ * list head. */
+ for (ttmp = &list_head; *ttmp; ttmp = &((*ttmp)->next_ctx))
+ if (*ttmp == t) {
+ /* ttmp is the link that points to t, either
+ * list_head or the next_ctx link in its
+ * predecessor */
+ *ttmp = t->next_ctx;
+ t->next_ctx = NULL; /* clobber */
+ return;
+ }
+ abort(); /* oops, this talloc was already
+ * clobbered or something else went
+ * wrong. */
+}
+
+
+/** Create a new talloc context. **/
+TALLOC_CTX *talloc_init(void)
+{
+ TALLOC_CTX *t;
+
+ t = (TALLOC_CTX *)malloc(sizeof(*t));
+ if (!t) return NULL;
+
+ t->list = NULL;
+ t->total_alloc_size = 0;
+ t->name = NULL;
+ talloc_enroll(t);
+
+ return t;
+}
+
+
+
+/**
+ * Create a new talloc context, with a name specifying its purpose.
+ * Please call this in preference to talloc_init().
+ **/
+ TALLOC_CTX *talloc_init_named(char const *fmt, ...)
+{
+ TALLOC_CTX *t;
+ va_list ap;
+
+ t = talloc_init();
+ if (fmt) {
+ va_start(ap, fmt);
+ t->name = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ }
+
+ return t;
+}
+
+
+/** Allocate a bit of memory from the specified pool **/
+void *talloc(TALLOC_CTX *t, size_t size)
+{
+ void *p;
+ struct talloc_chunk *tc;
+
+ if (size == 0) return NULL;
+
+ p = malloc(size);
+ if (!p) return p;
+
+ tc = malloc(sizeof(*tc));
+ if (!tc) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+ tc->ptr = p;
+ tc->size = size;
+ tc->next = t->list;
+ t->list = tc;
+ t->total_alloc_size += size;
+
+ return p;
+}
+
+/** A talloc version of realloc */
+void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
+{
+ struct talloc_chunk *tc;
+
+ /* size zero is equivalent to free() */
+ if (size == 0)
+ return NULL;
+
+ /* realloc(NULL) is equavalent to malloc() */
+ if (ptr == NULL)
+ return talloc(t, size);
+
+ for (tc=t->list; tc; tc=tc->next) {
+ if (tc->ptr == ptr) {
+ ptr = Realloc(ptr, size);
+ if (ptr) {
+ t->total_alloc_size += (size - tc->size);
+ tc->size = size;
+ tc->ptr = ptr;
+ }
+ return ptr;
+ }
+ }
+ return NULL;
+}
+
+/** Destroy all the memory allocated inside @p t, but not @p t
+ * itself. */
+void talloc_destroy_pool(TALLOC_CTX *t)
+{
+ struct talloc_chunk *c;
+
+ if (!t)
+ return;
+
+ while (t->list) {
+ c = t->list->next;
+ SAFE_FREE(t->list->ptr);
+ SAFE_FREE(t->list);
+ t->list = c;
+ }
+
+ t->total_alloc_size = 0;
+}
+
+/** Destroy a whole pool including the context */
+void talloc_destroy(TALLOC_CTX *t)
+{
+ if (!t)
+ return;
+ talloc_destroy_pool(t);
+ talloc_disenroll(t);
+ memset(t, 0, sizeof(*t));
+ SAFE_FREE(t);
+}
+
+/** Return the current total size of the pool. */
+size_t talloc_pool_size(TALLOC_CTX *t)
+{
+ return t->total_alloc_size;
+}
+
+const char * talloc_pool_name(TALLOC_CTX const *t)
+{
+ return t->name;
+}
+
+
+/** talloc and zero memory. */
+void *talloc_zero(TALLOC_CTX *t, size_t size)
+{
+ void *p = talloc(t, size);
+
+ if (p)
+ memset(p, '\0', size);
+
+ return p;
+}
+
+/** memdup with a talloc. */
+void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
+{
+ void *newp = talloc(t,size);
+
+ if (!newp)
+ return 0;
+
+ memcpy(newp, p, size);
+
+ return newp;
+}
+
+/** strdup with a talloc */
+char *talloc_strdup(TALLOC_CTX *t, const char *p)
+{
+ return talloc_memdup(t, p, strlen(p) + 1);
+}
+
+/**
+ * Perform string formatting, and return a pointer to newly allocated
+ * memory holding the result, inside a memory pool.
+ **/
+ char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ /* work out how long it will be */
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+ char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
+{
+ int len;
+ char *ret;
+
+ len = vsnprintf(NULL, 0, fmt, ap);
+
+ ret = talloc(t, len+1);
+ if (!ret) return NULL;
+
+ vsnprintf(ret, len+1, fmt, ap);
+
+ return ret;
+}
+
+
+/** @} */
diff --git a/source/lib/talloctort.c b/source/lib/talloctort.c
new file mode 100644
index 00000000000..427e7dee70b
--- /dev/null
+++ b/source/lib/talloctort.c
@@ -0,0 +1,63 @@
+/*
+ Unix SMB/Netbios implementation.
+ Samba temporary memory allocation functions -- torturer
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define NCTX 10
+#define NOBJ 20
+
+int main(void)
+{
+ int i;
+ TALLOC_CTX *ctx[NCTX];
+
+ for (i = 0; i < NCTX; i++) {
+ ctx[i] = talloc_init_named("torture(%d)", i);
+ }
+
+ for (i = 0; i < NCTX; i++) {
+ int j;
+ for (j = 0; j < NOBJ; j++) {
+ char *p;
+ size_t size = 1<<(i/3+j);
+
+ p = talloc(ctx[i], size);
+ if (!p) {
+ fprintf(stderr,
+ "failed to talloc %.0f bytes\n",
+ (double) size);
+ exit(1);
+ }
+
+ memset(p, 'A' + j, size);
+ }
+ }
+
+ for (i = 0; i < NCTX; i++) {
+ printf("talloc@%p %-40s %dkB\n", ctx[i],
+ talloc_pool_name(ctx[i]),
+ talloc_pool_size(ctx[i]) >> 10);
+ }
+
+ for (i = NCTX - 1; i >= 0; i--)
+ talloc_destroy(ctx[i]);
+
+ return 0;
+}
diff --git a/source/lib/time.c b/source/lib/time.c
new file mode 100644
index 00000000000..f0f62ca8419
--- /dev/null
+++ b/source/lib/time.c
@@ -0,0 +1,725 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ time handling functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
+ in May 1996
+ */
+
+
+int extra_time_offset = 0;
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef TIME_T_MIN
+#define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
+ : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+/*******************************************************************
+ External access to time_t_min and time_t_max.
+********************************************************************/
+
+time_t get_time_t_min(void)
+{
+ return TIME_T_MIN;
+}
+
+time_t get_time_t_max(void)
+{
+ return TIME_T_MAX;
+}
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef HAVE_GETTIMEOFDAY_TZ
+ gettimeofday(tval,NULL);
+#else
+ gettimeofday(tval);
+#endif
+}
+
+#define TM_YEAR_BASE 1900
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_BASE - 1);
+ int by = b->tm_year + (TM_YEAR_BASE - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+
+ return seconds;
+}
+
+/*******************************************************************
+ return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
+ ******************************************************************/
+static int TimeZone(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ struct tm tm_utc;
+ if (!tm)
+ return 0;
+ tm_utc = *tm;
+ tm = localtime(&t);
+ if (!tm)
+ return 0;
+ return tm_diff(&tm_utc,tm);
+
+}
+
+static BOOL done_serverzone_init;
+
+/* Return the smb serverzone value */
+
+static int get_serverzone(void)
+{
+ static int serverzone;
+
+ if (!done_serverzone_init) {
+ serverzone = TimeZone(time(NULL));
+
+ if ((serverzone % 60) != 0) {
+ DEBUG(1,("WARNING: Your timezone is not a multiple of 1 minute.\n"));
+ }
+
+ DEBUG(4,("Serverzone is %d\n",serverzone));
+
+ done_serverzone_init = True;
+ }
+
+ return serverzone;
+}
+
+/* Re-read the smb serverzone value */
+
+void TimeInit(void)
+{
+ done_serverzone_init = False;
+ get_serverzone();
+}
+
+/*******************************************************************
+return the same value as TimeZone, but it should be more efficient.
+
+We keep a table of DST offsets to prevent calling localtime() on each
+call of this function. This saves a LOT of time on many unixes.
+
+Updated by Paul Eggert <eggert@twinsun.com>
+********************************************************************/
+static int TimeZoneFaster(time_t t)
+{
+ static struct dst_table {time_t start,end; int zone;} *tdt, *dst_table = NULL;
+ static int table_size = 0;
+ int i;
+ int zone = 0;
+
+ if (t == 0) t = time(NULL);
+
+ /* Tunis has a 8 day DST region, we need to be careful ... */
+#define MAX_DST_WIDTH (365*24*60*60)
+#define MAX_DST_SKIP (7*24*60*60)
+
+ for (i=0;i<table_size;i++)
+ if (t >= dst_table[i].start && t <= dst_table[i].end) break;
+
+ if (i<table_size) {
+ zone = dst_table[i].zone;
+ } else {
+ time_t low,high;
+
+ zone = TimeZone(t);
+ tdt = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!tdt) {
+ DEBUG(0,("TimeZoneFaster: out of memory!\n"));
+ SAFE_FREE(dst_table);
+ table_size = 0;
+ } else {
+ dst_table = tdt;
+ table_size++;
+
+ dst_table[i].zone = zone;
+ dst_table[i].start = dst_table[i].end = t;
+
+ /* no entry will cover more than 6 months */
+ low = t - MAX_DST_WIDTH/2;
+ if (t < low)
+ low = TIME_T_MIN;
+
+ high = t + MAX_DST_WIDTH/2;
+ if (high < t)
+ high = TIME_T_MAX;
+
+ /* widen the new entry using two bisection searches */
+ while (low+60*60 < dst_table[i].start) {
+ if (dst_table[i].start - low > MAX_DST_SKIP*2)
+ t = dst_table[i].start - MAX_DST_SKIP;
+ else
+ t = low + (dst_table[i].start-low)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].start = t;
+ else
+ low = t;
+ }
+
+ while (high-60*60 > dst_table[i].end) {
+ if (high - dst_table[i].end > MAX_DST_SKIP*2)
+ t = dst_table[i].end + MAX_DST_SKIP;
+ else
+ t = high - (high-dst_table[i].end)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].end = t;
+ else
+ high = t;
+ }
+#if 0
+ DEBUG(1,("Added DST entry from %s ",
+ asctime(localtime(&dst_table[i].start))));
+ DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
+ dst_table[i].zone));
+#endif
+ }
+ }
+ return zone;
+}
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time offset
+ **************************************************************************/
+int TimeDiff(time_t t)
+{
+ return TimeZoneFaster(t) + 60*extra_time_offset;
+}
+
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time
+ offset, for a local time value. If ut = lt + LocTimeDiff(lt), then
+ lt = ut - TimeDiff(ut), but the converse does not necessarily hold near
+ daylight savings transitions because some local times are ambiguous.
+ LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions.
+ +**************************************************************************/
+static int LocTimeDiff(time_t lte)
+{
+ time_t lt = lte - 60*extra_time_offset;
+ int d = TimeZoneFaster(lt);
+ time_t t = lt + d;
+
+ /* if overflow occurred, ignore all the adjustments so far */
+ if (((lte < lt) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0)))
+ t = lte;
+
+ /* now t should be close enough to the true UTC to yield the right answer */
+ return TimeDiff(t);
+}
+
+
+/****************************************************************************
+try to optimise the localtime call, it can be quite expensive on some machines
+****************************************************************************/
+struct tm *LocalTime(time_t *t)
+{
+ time_t t2 = *t;
+
+ t2 -= TimeDiff(t2);
+
+ return(gmtime(&t2));
+}
+
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+
+It appears to be kludge-GMT (at least for file listings). This means
+its the GMT you get by taking a localtime and adding the
+serverzone. This is NOT the same as GMT in some cases. This routine
+converts this to real GMT.
+****************************************************************************/
+time_t nt_time_to_unix(NTTIME *nt)
+{
+ double d;
+ time_t ret;
+ /* The next two lines are a fix needed for the
+ broken SCO compiler. JRA. */
+ time_t l_time_min = TIME_T_MIN;
+ time_t l_time_max = TIME_T_MAX;
+
+ if (nt->high == 0) return(0);
+
+ d = ((double)nt->high)*4.0*(double)(1<<30);
+ d += (nt->low&0xFFF00000);
+ d *= 1.0e-7;
+
+ /* now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT;
+
+ if (!(l_time_min <= d && d <= l_time_max))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= get_serverzone();
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+/****************************************************************************
+convert a NTTIME structure to a time_t
+It's originally in "100ns units"
+
+this is an absolute version of the one above.
+By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
+if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
+****************************************************************************/
+time_t nt_time_to_unix_abs(NTTIME *nt)
+{
+ double d;
+ time_t ret;
+ /* The next two lines are a fix needed for the
+ broken SCO compiler. JRA. */
+ time_t l_time_min = TIME_T_MIN;
+ time_t l_time_max = TIME_T_MAX;
+
+ if (nt->high == 0)
+ return(0);
+
+ if (nt->high==0x80000000 && nt->low==0)
+ return -1;
+
+ /* reverse the time */
+ /* it's a negative value, turn it to positive */
+ nt->high=~nt->high;
+ nt->low=~nt->low;
+
+ d = ((double)nt->high)*4.0*(double)(1<<30);
+ d += (nt->low&0xFFF00000);
+ d *= 1.0e-7;
+
+ if (!(l_time_min <= d && d <= l_time_max))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= get_serverzone();
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+
+
+/****************************************************************************
+interprets an nt time into a unix time_t
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+ NTTIME nt;
+ nt.low = IVAL(p,0);
+ nt.high = IVAL(p,4);
+ return nt_time_to_unix(&nt);
+}
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes real GMT as input and converts to kludge-GMT
+****************************************************************************/
+void unix_to_nt_time(NTTIME *nt, time_t t)
+{
+ double d;
+
+ if (t==0)
+ {
+ nt->low = 0;
+ nt->high = 0;
+ return;
+ }
+ if (t == TIME_T_MAX)
+ {
+ nt->low = 0xffffffff;
+ nt->high = 0x7fffffff;
+ return;
+ }
+ if (t == -1)
+ {
+ nt->low = 0xffffffff;
+ nt->high = 0xffffffff;
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= LocTimeDiff(t) - get_serverzone();
+
+ d = (double)(t);
+ d += TIME_FIXUP_CONSTANT;
+ d *= 1.0e7;
+
+ nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
+}
+
+/****************************************************************************
+convert a time_t to a NTTIME structure
+
+this is an absolute version of the one above.
+By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
+if the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
+****************************************************************************/
+void unix_to_nt_time_abs(NTTIME *nt, time_t t)
+{
+ double d;
+
+ if (t==0) {
+ nt->low = 0;
+ nt->high = 0;
+ return;
+ }
+
+ if (t == TIME_T_MAX) {
+ nt->low = 0xffffffff;
+ nt->high = 0x7fffffff;
+ return;
+ }
+
+ if (t == -1) {
+ /* that's what NT uses for infinite */
+ nt->low = 0x0;
+ nt->high = 0x80000000;
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= LocTimeDiff(t) - get_serverzone();
+
+ d = (double)(t);
+ d *= 1.0e7;
+
+ nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
+
+ /* convert to a negative value */
+ nt->high=~nt->high;
+ nt->low=~nt->low;
+}
+
+
+/****************************************************************************
+take an NTTIME structure, containing high / low time. convert to unix time.
+lkclXXXX this may need 2 SIVALs not a memcpy. we'll see...
+****************************************************************************/
+void put_long_date(char *p,time_t t)
+{
+ NTTIME nt;
+ unix_to_nt_time(&nt, t);
+ SIVAL(p, 0, nt.low);
+ SIVAL(p, 4, nt.high);
+}
+
+/****************************************************************************
+check if it's a null mtime
+****************************************************************************/
+BOOL null_mtime(time_t mtime)
+{
+ if (mtime == 0 || mtime == 0xFFFFFFFF || mtime == (time_t)-1)
+ return(True);
+ return(False);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16 make_dos_date1(struct tm *t)
+{
+ uint16 ret=0;
+ ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16 make_dos_time1(struct tm *t)
+{
+ uint16 ret=0;
+ ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32 make_dos_date(time_t unixdate)
+{
+ struct tm *t;
+ uint32 ret=0;
+
+ t = LocalTime(&unixdate);
+ if (!t)
+ return 0xFFFFFFFF;
+
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
+
+ return(ret);
+}
+
+/*******************************************************************
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date2(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+********************************************************************/
+void put_dos_date3(char *buf,int offset,time_t unixdate)
+{
+ if (!null_mtime(unixdate))
+ unixdate -= TimeDiff(unixdate);
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32 p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+********************************************************************/
+time_t make_unix_date(void *date_ptr)
+{
+ uint32 dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return(0);
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_isdst = -1;
+
+ /* mktime() also does the local to GMT time conversion for us */
+ ret = mktime(&t);
+
+ return(ret);
+}
+
+/*******************************************************************
+like make_unix_date() but the words are reversed
+********************************************************************/
+time_t make_unix_date2(void *date_ptr)
+{
+ uint32 x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return(make_unix_date((void *)&x));
+}
+
+/*******************************************************************
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+ ******************************************************************/
+time_t make_unix_date3(void *date_ptr)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+ if (!null_mtime(t))
+ t += LocTimeDiff(t);
+ return(t);
+}
+
+
+/***************************************************************************
+return a HTTP/1.0 time string
+ ***************************************************************************/
+char *http_timestring(time_t t)
+{
+ static fstring buf;
+ struct tm *tm = LocalTime(&t);
+
+ if (!tm)
+ slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
+ else
+#ifndef HAVE_STRFTIME
+ fstrcpy(buf, asctime(tm));
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+#else /* !HAVE_STRFTIME */
+ strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+#endif /* !HAVE_STRFTIME */
+ return buf;
+}
+
+
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timestring(BOOL hires)
+{
+ static fstring TimeBuf;
+ struct timeval tp;
+ time_t t;
+ struct tm *tm;
+
+ if (hires) {
+ GetTimeOfDay(&tp);
+ t = (time_t)tp.tv_sec;
+ } else {
+ t = time(NULL);
+ }
+ tm = LocalTime(&t);
+ if (!tm) {
+ if (hires) {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld.%06ld seconds since the Epoch",
+ (long)tp.tv_sec,
+ (long)tp.tv_usec);
+ } else {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+ } else {
+#ifdef HAVE_STRFTIME
+ if (hires) {
+ strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
+ slprintf(TimeBuf+strlen(TimeBuf),
+ sizeof(TimeBuf)-1 - strlen(TimeBuf),
+ ".%06ld",
+ (long)tp.tv_usec);
+ } else {
+ strftime(TimeBuf,100,"%Y/%m/%d %H:%M:%S",tm);
+ }
+#else
+ if (hires) {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%s.%06ld",
+ asctime(tm),
+ (long)tp.tv_usec);
+ } else {
+ fstrcpy(TimeBuf, asctime(tm));
+ }
+#endif
+ }
+ return(TimeBuf);
+}
+
+/****************************************************************************
+ return the best approximation to a 'create time' under UNIX from a stat
+ structure.
+****************************************************************************/
+
+time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
+{
+ time_t ret, ret1;
+
+ if(S_ISDIR(st->st_mode) && fake_dirs)
+ return (time_t)315493200L; /* 1/1/1980 */
+
+ ret = MIN(st->st_ctime, st->st_mtime);
+ ret1 = MIN(ret, st->st_atime);
+
+ if(ret1 != (time_t)0)
+ return ret1;
+
+ /*
+ * One of ctime, mtime or atime was zero (probably atime).
+ * Just return MIN(ctime, mtime).
+ */
+ return ret;
+}
+
+/****************************************************************************
+initialise an NTTIME to -1, which means "unknown" or "don't expire"
+****************************************************************************/
+
+void init_nt_time(NTTIME *nt)
+{
+ nt->high = 0x7FFFFFFF;
+ nt->low = 0xFFFFFFFF;
+}
diff --git a/source/lib/ufc.c b/source/lib/ufc.c
index 8417285821a..ecc04d9e97c 100644
--- a/source/lib/ufc.c
+++ b/source/lib/ufc.c
@@ -16,12 +16,14 @@
*/
-#ifdef UFC_CRYPT
+#include "includes.h"
+
+#ifndef HAVE_CRYPT
/*
* UFC-crypt: ultra fast crypt(3) implementation
*
- * Copyright (C) 1991, 1992, Free Software Foundation, Inc.
+ * Copyright (C) 1991-1998, Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -42,7 +44,6 @@
* Support routines
*
*/
-#include "includes.h"
#ifndef long32
@@ -281,9 +282,7 @@ static ufc_long longmask[32] = {
* bzero and some don't have memset.
*/
-static void clearmem(start, cnt)
- char *start;
- int cnt;
+static void clearmem(char *start, int cnt)
{ while(cnt--)
*start++ = '\0';
}
@@ -299,7 +298,7 @@ static int initialized = 0;
* by fcrypt users.
*/
-static void ufc_init_des()
+static void ufc_init_des(void)
{ int comes_from_bit;
int bit, sg;
ufc_long j;
@@ -350,13 +349,13 @@ static void ufc_init_des()
clearmem((char*)eperm32tab, sizeof(eperm32tab));
for(bit = 0; bit < 48; bit++) {
- ufc_long mask1,comes_from;
+ ufc_long inner_mask1,comes_from;
comes_from = perm32[esel[bit]-1]-1;
- mask1 = bytemask[comes_from % 8];
+ inner_mask1 = bytemask[comes_from % 8];
for(j = 256; j--;) {
- if(j & mask1)
+ if(j & inner_mask1)
eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
}
}
@@ -431,7 +430,7 @@ static void ufc_init_des()
clearmem((char*)efp, sizeof efp);
for(bit = 0; bit < 64; bit++) {
int o_bit, o_long;
- ufc_long word_value, mask1, mask2;
+ ufc_long word_value, inner_mask1, inner_mask2;
int comes_from_f_bit, comes_from_e_bit;
int comes_from_word, bit_within_word;
@@ -451,12 +450,12 @@ static void ufc_init_des()
comes_from_word = comes_from_e_bit / 6; /* 0..15 */
bit_within_word = comes_from_e_bit % 6; /* 0..5 */
- mask1 = longmask[bit_within_word + 26];
- mask2 = longmask[o_bit];
+ inner_mask1 = longmask[bit_within_word + 26];
+ inner_mask2 = longmask[o_bit];
for(word_value = 64; word_value--;) {
- if(word_value & mask1)
- efp[comes_from_word][word_value][o_long] |= mask2;
+ if(word_value & inner_mask1)
+ efp[comes_from_word][word_value][o_long] |= inner_mask2;
}
}
initialized++;
@@ -468,9 +467,7 @@ static void ufc_init_des()
*/
#ifdef _UFC_32_
-static void shuffle_sb(k, saltbits)
- long32 *k;
- ufc_long saltbits;
+static void shuffle_sb(long32 *k, ufc_long saltbits)
{ ufc_long j;
long32 x;
for(j=4096; j--;) {
@@ -482,9 +479,7 @@ static void shuffle_sb(k, saltbits)
#endif
#ifdef _UFC_64_
-static void shuffle_sb(k, saltbits)
- long64 *k;
- ufc_long saltbits;
+static void shuffle_sb(long64 *k, ufc_long saltbits)
{ ufc_long j;
long64 x;
for(j=4096; j--;) {
@@ -503,9 +498,9 @@ static unsigned char current_salt[3] = "&&"; /* invalid value */
static ufc_long current_saltbits = 0;
static int direction = 0;
-static void setup_salt(char *s1)
+static void setup_salt(const char *s1)
{ ufc_long i, j, saltbits;
- unsigned char *s2 = (unsigned char *)s1;
+ const unsigned char *s2 = (const unsigned char *)s1;
if(!initialized)
ufc_init_des();
@@ -543,8 +538,7 @@ static void setup_salt(char *s1)
current_saltbits = saltbits;
}
-static void ufc_mk_keytab(key)
- char *key;
+static void ufc_mk_keytab(char *key)
{ ufc_long v1, v2, *k1;
int i;
#ifdef _UFC_32_
@@ -593,8 +587,7 @@ static void ufc_mk_keytab(key)
* Undo an extra E selection and do final permutations
*/
-ufc_long *_ufc_dofinalperm(l1, l2, r1, r2)
- ufc_long l1,l2,r1,r2;
+ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
{ ufc_long v1, v2, x;
static ufc_long ary[2];
@@ -632,9 +625,7 @@ ufc_long *_ufc_dofinalperm(l1, l2, r1, r2)
* prefixing with the salt
*/
-static char *output_conversion(v1, v2, salt)
- ufc_long v1, v2;
- char *salt;
+static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
{ static char outbuf[14];
int i, s;
@@ -656,13 +647,13 @@ static char *output_conversion(v1, v2, salt)
return outbuf;
}
-ufc_long *_ufc_doit();
-
/*
* UNIX crypt function
*/
+
+static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
-char *ufc_crypt(char *key,char *salt)
+char *ufc_crypt(const char *key,const char *salt)
{ ufc_long *s;
char ktab[9];
@@ -702,8 +693,7 @@ extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
- ufc_long l1, l2, r1, r2, itr;
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
{ int i;
long32 s, *k;
@@ -742,8 +732,7 @@ extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
- ufc_long l1, l2, r1, r2, itr;
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
{ int i;
long64 l, r, s, *k;
@@ -777,6 +766,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
#else
-int ufc_dummy_procedure(void)
-{return 0;}
+ int ufc_dummy_procedure(void);
+ int ufc_dummy_procedure(void) {return 0;}
#endif
diff --git a/source/lib/username.c b/source/lib/username.c
index 3d214fbbdab..8154a2b40e4 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -2,7 +2,8 @@
Unix SMB/Netbios implementation.
Version 1.9.
Username handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1997-2001.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,227 +21,624 @@
*/
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
+/* internal functions */
+static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (const char *), int N);
+static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (const char *), int N);
+
+/*****************************************************************
+ Check if a user or group name is local (this is a *local* name for
+ *local* people, there's nothing for you here...).
+*****************************************************************/
+
+BOOL name_is_local(const char *name)
+{
+ return !strchr_m(name, *lp_winbind_separator());
+}
/****************************************************************************
-get a users home directory. tries as-is then lower case
+ Get a users home directory.
****************************************************************************/
-char *get_home_dir(char *user)
+
+char *get_user_home_dir(const char *user)
{
- static struct passwd *pass;
+ static struct passwd *pass;
+ int snum;
- pass = Get_Pwnam(user,False);
+ /* If a path is specified in [homes] then use it instead of the
+ user's home directory from struct passwd. */
- if (!pass) return(NULL);
- return(pass->pw_dir);
-}
+ if ((snum = lp_servicenumber(HOMES_NAME)) != -1) {
+ static pstring home_dir;
+
+ pstrcpy(home_dir, lp_pathname(snum));
+ standard_sub_snum(snum, home_dir);
+ if (home_dir[0])
+ return home_dir;
+ }
+
+ /* Get home directory from struct passwd. */
+
+ pass = Get_Pwnam(user);
+
+ if (!pass)
+ return(NULL);
+ return(pass->pw_dir);
+}
/*******************************************************************
-map a username from a dos name to a unix name by looking in the username
-map
+ Map a username from a dos name to a unix name by looking in the username
+ map. Note that this modifies the name in place.
+ This is the main function that should be called *once* on
+ any incoming or new username - in order to canonicalize the name.
+ This is being done to de-couple the case conversions from the user mapping
+ function. Previously, the map_username was being called
+ every time Get_Pwnam was called.
+ Returns True if username was changed, false otherwise.
********************************************************************/
-void map_username(char *user)
+
+BOOL map_username(char *user)
{
- static int depth=0;
- static BOOL initialised=False;
- static fstring last_from,last_to;
- FILE *f;
- char *s;
- char *mapfile = lp_username_map();
- if (!*mapfile || depth) return;
-
- if (!*user) return;
-
- if (!initialised) {
- *last_from = *last_to = 0;
- initialised = True;
- }
-
- if (strequal(user,last_to)) return;
-
- if (strequal(user,last_from)) {
- DEBUG(3,("Mapped user %s to %s\n",user,last_to));
- strcpy(user,last_to);
- return;
- }
+ static BOOL initialised=False;
+ static fstring last_from,last_to;
+ XFILE *f;
+ char *mapfile = lp_username_map();
+ char *s;
+ pstring buf;
+ BOOL mapped_user = False;
+
+ if (!*user)
+ return False;
+
+ if (!*mapfile)
+ return False;
+
+ if (!initialised) {
+ *last_from = *last_to = 0;
+ initialised = True;
+ }
+
+ if (strequal(user,last_to))
+ return False;
+
+ if (strequal(user,last_from)) {
+ DEBUG(3,("Mapped user %s to %s\n",user,last_to));
+ fstrcpy(user,last_to);
+ return True;
+ }
- f = fopen(mapfile,"r");
- if (!f) {
- DEBUG(0,("can't open username map %s\n",mapfile));
- return;
- }
+ f = x_fopen(mapfile,O_RDONLY, 0);
+ if (!f) {
+ DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) ));
+ return False;
+ }
- DEBUG(4,("Scanning username map %s\n",mapfile));
+ DEBUG(4,("Scanning username map %s\n",mapfile));
- depth++;
+ while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
+ char *unixname = s;
+ char *dosname = strchr_m(unixname,'=');
+ char **dosuserlist;
+ BOOL return_if_mapped = False;
- for (; (s=fgets_slash(NULL,80,f)); free(s)) {
- char *unixname = s;
- char *dosname = strchr(unixname,'=');
+ if (!dosname)
+ continue;
- if (!dosname) continue;
- *dosname++ = 0;
+ *dosname++ = 0;
- while (isspace(*unixname)) unixname++;
- if (!*unixname || strchr("#;",*unixname)) continue;
+ while (isspace((int)*unixname))
+ unixname++;
- {
- int l = strlen(unixname);
- while (l && isspace(unixname[l-1])) {
- unixname[l-1] = 0;
- l--;
- }
- }
+ if ('!' == *unixname) {
+ return_if_mapped = True;
+ unixname++;
+ while (*unixname && isspace((int)*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr_m("#;",*unixname))
+ continue;
- if (strchr(dosname,'*') || user_in_list(user,dosname)) {
- DEBUG(3,("Mapped user %s to %s\n",user,unixname));
- StrnCpy(last_from,user,sizeof(last_from)-1);
- sscanf(unixname,"%s",user);
- StrnCpy(last_to,user,sizeof(last_to)-1);
- }
- }
+ {
+ int l = strlen(unixname);
+ while (l && isspace((int)unixname[l-1])) {
+ unixname[l-1] = 0;
+ l--;
+ }
+ }
- fclose(f);
+ dosuserlist = lp_list_make(dosname);
+ if (!dosuserlist) {
+ DEBUG(0,("Unable to build user list\n"));
+ return False;
+ }
- depth--;
+ if (strchr_m(dosname,'*') || user_in_list(user, dosuserlist)) {
+ DEBUG(3,("Mapped user %s to %s\n",user,unixname));
+ mapped_user = True;
+ fstrcpy(last_from,user);
+ sscanf(unixname,"%s",user);
+ fstrcpy(last_to,user);
+ if(return_if_mapped) {
+ lp_list_free (&dosuserlist);
+ x_fclose(f);
+ return True;
+ }
+ }
+
+ lp_list_free (&dosuserlist);
+ }
+
+ x_fclose(f);
+
+ /*
+ * Setup the last_from and last_to as an optimization so
+ * that we don't scan the file again for the same user.
+ */
+ fstrcpy(last_from,user);
+ fstrcpy(last_to,user);
+
+ return mapped_user;
}
/****************************************************************************
-internals of Get_Pwnam wrapper
+ Get_Pwnam wrapper
****************************************************************************/
-static struct passwd *_Get_Pwnam(char *s)
+
+static struct passwd *_Get_Pwnam(const char *s)
{
- struct passwd *ret;
-
- ret = getpwnam(s);
- if (ret)
- {
-#ifdef GETPWANAM
- struct passwd_adjunct *pwret;
- pwret = getpwanam(s);
- if (pwret)
- {
- free(ret->pw_passwd);
- ret->pw_passwd = pwret->pwa_passwd;
- }
+ struct passwd *ret;
+
+ ret = sys_getpwnam(s);
+ if (ret) {
+#ifdef HAVE_GETPWANAM
+ struct passwd_adjunct *pwret;
+ pwret = getpwanam(s);
+ if (pwret && pwret->pwa_passwd)
+ pstrcpy(ret->pw_passwd,pwret->pwa_passwd);
#endif
+ }
- }
-
- return(ret);
+ return(ret);
}
/****************************************************************************
-a wrapper for getpwnam() that tries with all lower and all upper case
-if the initial name fails. Also tried with first letter capitalised
-Note that this changes user!
+ * A wrapper for getpwnam(). The following variations are tried:
+ * - as transmitted
+ * - in all lower case if this differs from transmitted
+ * - in all upper case if this differs from transmitted
+ * - using lp_usernamelevel() for permutations.
****************************************************************************/
-struct passwd *Get_Pwnam(char *user,BOOL allow_change)
+
+struct passwd *Get_Pwnam_internals(const char *user, char *user2)
{
- fstring user2;
+ struct passwd *ret = NULL;
+
+ if (!user2 || !(*user2))
+ return(NULL);
+
+ if (!user || !(*user))
+ return(NULL);
+
+ /* Try in all lower case first as this is the most
+ common case on UNIX systems */
+ strlower(user2);
+ DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
+ ret = _Get_Pwnam(user2);
+ if(ret)
+ goto done;
+
+ /* Try as given, if username wasn't originally lowercase */
+ if(strcmp(user,user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",user));
+ ret = _Get_Pwnam(user);
+ if(ret)
+ goto done;
+ }
+
+ /* Try as uppercase, if username wasn't originally uppercase */
+ strupper(user2);
+ if(strcmp(user,user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",user2));
+ ret = _Get_Pwnam(user2);
+ if(ret)
+ goto done;
+ }
- struct passwd *ret;
+ /* Try all combinations up to usernamelevel */
+ strlower(user2);
+ DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",lp_usernamelevel(),user2));
+ ret = uname_string_combinations(user2, _Get_Pwnam, lp_usernamelevel());
- if (!user || !(*user))
- return(NULL);
+done:
+ DEBUG(5,("Get_Pwnam %s find a valid username!\n",ret ? "did":"didn't"));
+ return ret;
+}
- StrnCpy(user2,user,sizeof(user2)-1);
+/****************************************************************************
+ Get_Pwnam wrapper for modification.
+ NOTE: This can potentially modify 'user'!
+****************************************************************************/
- if (!allow_change) {
- user = &user2[0];
- }
+struct passwd *Get_Pwnam_Modify(char *user)
+{
+ fstring user2;
+ struct passwd *ret;
- map_username(user);
+ fstrcpy(user2, user);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+ ret = Get_Pwnam_internals(user, user2);
+
+ /* If caller wants the modified username, ensure they get it */
+ fstrcpy(user,user2);
- strlower(user);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+ /* We can safely assume ret is NULL if none of the above succeed */
+ return(ret);
+}
- strupper(user);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+/****************************************************************************
+ Get_Pwnam wrapper without modification.
+ NOTE: This with NOT modify 'user'!
+****************************************************************************/
- /* try with first letter capitalised */
- if (strlen(user) > 1)
- strlower(user+1);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+struct passwd *Get_Pwnam(const char *user)
+{
+ fstring user2;
+ struct passwd *ret;
- if (allow_change)
- strcpy(user,user2);
+ fstrcpy(user2, user);
- return(NULL);
+ ret = Get_Pwnam_internals(user, user2);
+
+ /* We can safely assume ret is NULL if none of the above succeed */
+ return(ret);
}
+/****************************************************************************
+ Check if a user is in a netgroup user list.
+****************************************************************************/
+
+static BOOL user_in_netgroup_list(const char *user, const char *ngname)
+{
+#ifdef HAVE_NETGROUP
+ static char *mydomain = NULL;
+ if (mydomain == NULL)
+ yp_get_default_domain(&mydomain);
+
+ if(mydomain == NULL) {
+ DEBUG(5,("Unable to get default yp domain\n"));
+ return False;
+ }
+
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ user, mydomain, ngname));
+ DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain)
+ ? "TRUE" : "FALSE"));
+
+ if (innetgr(ngname, NULL, user, mydomain))
+ return (True);
+#endif /* HAVE_NETGROUP */
+ return False;
+}
/****************************************************************************
-check if a user is in a user list
+ Check if a user is in a winbind group.
****************************************************************************/
-BOOL user_in_list(char *user,char *list)
+
+static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL *winbind_answered)
{
- pstring tok;
- char *p=list;
-
- while (next_token(&p,tok,LIST_SEP))
- {
- if (strequal(user,tok))
- return(True);
-
-#ifdef NETGROUP
- if (*tok == '@')
- {
- static char *mydomain = NULL;
- if (mydomain == 0)
- yp_get_default_domain(&mydomain);
-
- DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
- user, mydomain, &tok[1]));
- DEBUG(5,("innetgr is %s\n",
- innetgr(&tok[1], (char *) 0, user, mydomain)
- ? "TRUE" : "FALSE"));
-
- if (innetgr(&tok[1], (char *)0, user, mydomain))
- return (True);
+ int num_groups;
+ int i;
+ gid_t *groups = NULL;
+ gid_t gid;
+ BOOL ret = False;
+
+ *winbind_answered = False;
+
+ /*
+ * Get the gid's that this user belongs to.
+ */
+
+ if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1)
+ return False;
+
+ if (num_groups == 0) {
+ *winbind_answered = True;
+ return False;
+ }
+
+ if ((groups = (gid_t *)malloc(sizeof(gid_t) * num_groups )) == NULL) {
+ DEBUG(0,("user_in_winbind_group_list: malloc fail.\n"));
+ goto err;
+ }
+
+ if ((num_groups = winbind_getgroups(user, num_groups, groups)) == -1) {
+ DEBUG(0,("user_in_winbind_group_list: second winbind_getgroups call \
+failed with error %s\n", strerror(errno) ));
+ goto err;
}
-#endif
+
+ /*
+ * Now we have the gid list for this user - convert the gname
+ * to a gid_t via either winbind or the local UNIX lookup and do the comparison.
+ */
+
+ if ((gid = nametogid(gname)) == (gid_t)-1) {
+ DEBUG(0,("user_in_winbind_group_list: winbind_lookup_name for group %s failed.\n",
+ gname ));
+ goto err;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ if (gid == groups[i]) {
+ ret = True;
+ break;
+ }
+ }
+
+ *winbind_answered = True;
+ SAFE_FREE(groups);
+ return ret;
+
+ err:
+
+ *winbind_answered = False;
+ SAFE_FREE(groups);
+ return False;
+}
+
+/****************************************************************************
+ Check if a user is in a UNIX group.
+****************************************************************************/
+static BOOL user_in_unix_group_list(const char *user,const char *gname)
+{
+ struct passwd *pass = Get_Pwnam(user);
+ struct sys_userlist *user_list;
+ struct sys_userlist *member;
+
+ DEBUG(10,("user_in_unix_group_list: checking user %s in group %s\n", user, gname));
+
+ /*
+ * We need to check the users primary group as this
+ * group is implicit and often not listed in the group database.
+ */
+
+ if (pass) {
+ if (strequal(gname,gidtoname(pass->pw_gid))) {
+ DEBUG(10,("user_in_unix_group_list: group %s is primary group.\n", gname ));
+ return True;
+ }
+ }
+
+ user_list = get_users_in_group(gname);
+ if (user_list == NULL) {
+ DEBUG(10,("user_in_unix_group_list: no such group %s\n", gname ));
+ return False;
+ }
+
+ for (member = user_list; member; member = member->next) {
+ DEBUG(10,("user_in_unix_group_list: checking user %s against member %s\n",
+ user, member->unix_name ));
+ if (strequal(member->unix_name,user)) {
+ free_userlist(user_list);
+ return(True);
+ }
+ }
-#if HAVE_GETGRNAM
- if (*tok == '@')
- {
- struct group *gptr;
- char **member;
- struct passwd *pass = Get_Pwnam(user,False);
+ free_userlist(user_list);
+ return False;
+}
- if (pass) {
- gptr = getgrgid(pass->pw_gid);
- if (gptr && strequal(gptr->gr_name,&tok[1]))
- return(True);
- }
+/****************************************************************************
+ Check if a user is in a group list. Ask winbind first, then use UNIX.
+****************************************************************************/
- gptr = (struct group *)getgrnam(&tok[1]);
+BOOL user_in_group_list(const char *user, const char *gname)
+{
+ BOOL winbind_answered = False;
+ BOOL ret;
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- if (strequal(*member,user))
- return(True);
- member++;
+ ret = user_in_winbind_group_list(user, gname, &winbind_answered);
+ if (!winbind_answered)
+ ret = user_in_unix_group_list(user, gname);
+
+ if (ret)
+ DEBUG(10,("user_in_group_list: user |%s| is in group |%s|\n", user, gname));
+ return ret;
+}
+
+/****************************************************************************
+ Check if a user is in a user list - can check combinations of UNIX
+ and netgroup lists.
+****************************************************************************/
+
+BOOL user_in_list(const char *user,char **list)
+{
+ if (!list || !*list)
+ return False;
+
+ DEBUG(10,("user_in_list: checking user %s in list\n", user));
+
+ while (*list) {
+
+ DEBUG(10,("user_in_list: checking user |%s| in group |%s|\n", user, *list));
+
+ /*
+ * Check raw username.
+ */
+ if (strequal(user, *list))
+ return(True);
+
+ /*
+ * Now check to see if any combination
+ * of UNIX and netgroups has been specified.
+ */
+
+ if(**list == '@') {
+ /*
+ * Old behaviour. Check netgroup list
+ * followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user, *list +1))
+ return True;
+ if(user_in_group_list(user, *list +1))
+ return True;
+ } else if (**list == '+') {
+
+ if((*(*list +1)) == '&') {
+ /*
+ * Search UNIX list followed by netgroup.
+ */
+ if(user_in_group_list(user, *list +2))
+ return True;
+ if(user_in_netgroup_list(user, *list +2))
+ return True;
+
+ } else {
+
+ /*
+ * Just search UNIX list.
+ */
+
+ if(user_in_group_list(user, *list +1))
+ return True;
+ }
+
+ } else if (**list == '&') {
+
+ if(*(*list +1) == '+') {
+ /*
+ * Search netgroup list followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user, *list +2))
+ return True;
+ if(user_in_group_list(user, *list +2))
+ return True;
+ } else {
+ /*
+ * Just search netgroup list.
+ */
+ if(user_in_netgroup_list(user, *list +1))
+ return True;
+ }
+ } else if (!name_is_local(*list)) {
+ /*
+ * If user name did not match and token is not
+ * a unix group and the token has a winbind separator in the
+ * name then see if it is a Windows group.
+ */
+
+ DOM_SID g_sid;
+ enum SID_NAME_USE name_type;
+ BOOL winbind_answered = False;
+ BOOL ret;
+
+ /* Check to see if name is a Windows group */
+ if (winbind_lookup_name(*list, &g_sid, &name_type) && name_type == SID_NAME_DOM_GRP) {
+
+ /* Check if user name is in the Windows group */
+ ret = user_in_winbind_group_list(user, *list, &winbind_answered);
+
+ if (winbind_answered && ret == True) {
+ DEBUG(10,("user_in_list: user |%s| is in group |%s|\n", user, *list));
+ return ret;
+ }
+ }
}
- }
- }
-#endif
- }
- return(False);
+
+ list++;
+ }
+ return(False);
}
+/* The functions below have been taken from password.c and slightly modified */
+/****************************************************************************
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
+****************************************************************************/
+static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(const char *),int N)
+{
+ ssize_t len = (ssize_t)strlen(s);
+ int i;
+ struct passwd *ret;
+
+ if (N <= 0 || offset >= len)
+ return(fn(s));
+
+ for (i=offset;i<(len-(N-1));i++) {
+ char c = s[i];
+ if (!islower((int)c))
+ continue;
+ s[i] = toupper(c);
+ ret = uname_string_combinations2(s,i+1,fn,N-1);
+ if(ret)
+ return(ret);
+ s[i] = c;
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with up to N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
+****************************************************************************/
+
+static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(const char *),int N)
+{
+ int n;
+ struct passwd *ret;
+
+ for (n=1;n<=N;n++) {
+ ret = uname_string_combinations2(s,0,fn,n);
+ if(ret)
+ return(ret);
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+ These wrappers allow appliance mode to work. In appliance mode the username
+ takes the form DOMAIN/user.
+****************************************************************************/
+
+struct passwd *smb_getpwnam(char *user, BOOL allow_change)
+{
+ struct passwd *pw;
+ char *p;
+ char *sep;
+ extern pstring global_myname;
+
+ if (allow_change)
+ pw = Get_Pwnam_Modify(user);
+ else
+ pw = Get_Pwnam(user);
+
+ if (pw)
+ return pw;
+
+ /*
+ * If it is a domain qualified name and it isn't in our password
+ * database but the domain portion matches our local machine name then
+ * lookup just the username portion locally.
+ */
+
+ sep = lp_winbind_separator();
+ p = strchr_m(user,*sep);
+ if (p && strncasecmp(global_myname, user, strlen(global_myname))==0) {
+ if (allow_change)
+ pw = Get_Pwnam_Modify(p+1);
+ else
+ pw = Get_Pwnam(p+1);
+ }
+ return NULL;
+}
diff --git a/source/lib/util.c b/source/lib/util.c
index 7bd6298c4ca..55bb3647fc8 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -2,7 +2,9 @@
Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,41 +22,51 @@
*/
#include "includes.h"
-#include "loadparm.h"
-pstring scope = "";
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+#ifdef WITH_NISPLUS_HOME
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
-int DEBUGLEVEL = 1;
+#if defined(GROUP)
+#undef GROUP
+#endif
-BOOL passive = False;
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
-int Protocol = PROTOCOL_COREPLUS;
+#endif /* BROKEN_NISPLUS_INCLUDE_FILES */
-int serverzone=0;
+#include <rpcsvc/nis.h>
-/* a default finfo structure to ensure all fields are sensible */
-file_info def_finfo = {-1,0,0,0,0,0,0,""};
+#else /* !WITH_NISPLUS_HOME */
-/* these are some file handles where debug info will be stored */
-FILE *dbf = NULL;
+#include "rpcsvc/ypclnt.h"
-/* the client file descriptor */
-int Client = -1;
+#endif /* WITH_NISPLUS_HOME */
+#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */
-/* info on the client */
-struct from_host Client_info=
-{"UNKNOWN","0.0.0.0",NULL};
+#ifdef WITH_SSL
+#include <openssl/ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* WITH_SSL */
-/* the last IP received from */
-struct in_addr lastip;
+int Protocol = PROTOCOL_COREPLUS;
-/* the last port received from */
-int lastport=0;
+/* a default finfo structure to ensure all fields are sensible */
+file_info def_finfo = {-1,0,0,0,0,0,0,"",""};
-/* my IP, the broadcast IP and the Netmask */
-struct in_addr myip;
-struct in_addr bcast_ip;
-struct in_addr Netmask;
+/* this is used by the chaining code */
+int chain_size = 0;
int trans_num = 0;
@@ -63,13 +75,6 @@ int trans_num = 0;
*/
int case_default = CASE_LOWER;
-
-/* size of reads during a direct file to file transfer */
-int ReadSize = 16*1024;
-
-pstring debugf = "/tmp/log.samba";
-int syslog_level;
-
/* the following control case operations - they are put here so the
client can link easily */
BOOL case_sensitive;
@@ -78,916 +83,110 @@ BOOL use_mangled_map = False;
BOOL short_case_preserve;
BOOL case_mangle;
-fstring remote_machine="";
-fstring local_machine="";
-fstring remote_arch="UNKNOWN";
-fstring remote_proto="UNKNOWN";
-pstring myhostname="";
-pstring user_socket_options="";
-pstring sesssetup_user="";
-
-
-static char *filename_dos(char *path,char *buf);
-
-static BOOL stdout_logging = False;
-
-
-/*******************************************************************
- get ready for syslog stuff
- ******************************************************************/
-void setup_logging(char *pname,BOOL interactive)
-{
-#ifdef SYSLOG
- if (!interactive) {
- char *p = strrchr(pname,'/');
- if (p) pname = p+1;
- openlog(pname, LOG_PID, LOG_DAEMON);
- }
-#endif
- if (interactive) {
- stdout_logging = True;
- dbf = stdout;
- }
-}
-
-
-BOOL append_log=False;
-
-
-/****************************************************************************
-reopen the log files
-****************************************************************************/
-void reopen_logs(void)
-{
- extern FILE *dbf;
- pstring fname;
-
- if (DEBUGLEVEL > 0)
- {
- strcpy(fname,debugf);
- if (lp_loaded() && (*lp_logfile()))
- strcpy(fname,lp_logfile());
-
- if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
- {
- strcpy(debugf,fname);
- if (dbf) fclose(dbf);
- if (append_log)
- dbf = fopen(debugf,"a");
- else
- dbf = fopen(debugf,"w");
- if (dbf) setbuf(dbf,NULL);
- }
- }
- else
- {
- if (dbf)
- {
- fclose(dbf);
- dbf = NULL;
- }
- }
-}
-
-
-/*******************************************************************
-write an debug message on the debugfile. This is called by the DEBUG
-macro
-********************************************************************/
-#ifdef __STDC__
-int Debug1(char *format_str, ...)
-{
-#else
-int Debug1(va_alist)
-va_dcl
-{
- char *format_str;
-#endif
- va_list ap;
-
-#ifdef __STDC__
- va_start(ap, format_str);
-#else
- va_start(ap);
- format_str = va_arg(ap,char *);
-#endif
-
- if (stdout_logging) {
- vfprintf(dbf,format_str,ap);
- va_end(ap);
- return(0);
- }
-
- {
- static int debug_count=0;
-
- debug_count++;
- if (debug_count == 100) {
- int maxlog = lp_max_log_size() * 1024;
- if (dbf && maxlog > 0)
- {
- struct stat st;
-
- if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
- fclose(dbf); dbf = NULL;
- reopen_logs();
- if (dbf && file_size(debugf) > maxlog) {
- pstring name;
- fclose(dbf); dbf = NULL;
- sprintf(name,"%s.old",debugf);
- sys_rename(debugf,name);
- reopen_logs();
- }
- }
- }
- debug_count=0;
- }
- }
-
-#ifdef SYSLOG
- if (!lp_syslog_only())
-#endif
- {
- if (!dbf)
- {
- dbf = fopen(debugf,"w");
- if (dbf)
- setbuf(dbf,NULL);
- else
- return(0);
- }
- }
-
-#ifdef SYSLOG
- if (syslog_level < lp_syslog())
- {
- /*
- * map debug levels to syslog() priorities
- * note that not all DEBUG(0, ...) calls are
- * necessarily errors
- */
- static int priority_map[] = {
- LOG_ERR, /* 0 */
- LOG_WARNING, /* 1 */
- LOG_NOTICE, /* 2 */
- LOG_INFO, /* 3 */
- };
- int priority;
- pstring msgbuf;
-
- if (syslog_level >= sizeof(priority_map) / sizeof(priority_map[0]) ||
- syslog_level < 0)
- priority = LOG_DEBUG;
- else
- priority = priority_map[syslog_level];
-
- vsprintf(msgbuf, format_str, ap);
-
- msgbuf[255] = '\0';
- syslog(priority, "%s", msgbuf);
- }
-#endif
-
-#ifdef SYSLOG
- if (!lp_syslog_only())
-#endif
- {
- vfprintf(dbf,format_str,ap);
- fflush(dbf);
- }
-
- va_end(ap);
- return(0);
-}
-
-/****************************************************************************
-routine to do file locking
-****************************************************************************/
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
-{
-#if HAVE_FCNTL_LOCK
- struct flock lock;
- int ret;
-
-#if 1
- uint32 mask = 0xC0000000;
-
- /* make sure the count is reasonable, we might kill the lockd otherwise */
- count &= ~mask;
-
- /* the offset is often strange - remove 2 of its bits if either of
- the top two bits are set. Shift the top ones by two bits. This
- still allows OLE2 apps to operate, but should stop lockd from
- dieing */
- if ((offset & mask) != 0)
- offset = (offset & ~mask) | ((offset & mask) >> 2);
-#else
- unsigned long mask = ((unsigned)1<<31);
-
- /* interpret negative counts as large numbers */
- if (count < 0)
- count &= ~mask;
-
- /* no negative offsets */
- offset &= ~mask;
-
- /* count + offset must be in range */
- while ((offset < 0 || (offset + count < 0)) && mask)
- {
- offset &= ~mask;
- mask = mask >> 1;
- }
-#endif
-
-
- DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = (int)offset;
- lock.l_len = (int)count;
- lock.l_pid = 0;
-
- errno = 0;
-
- ret = fcntl(fd,op,&lock);
-
- if (errno != 0)
- DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
- /* a lock query */
- if (op == F_GETLK)
- {
- if ((ret != -1) &&
- (lock.l_type != F_UNLCK) &&
- (lock.l_pid != 0) &&
- (lock.l_pid != getpid()))
- {
- DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
- return(True);
- }
-
- /* it must be not locked or locked by me */
- return(False);
- }
-
- /* a lock set or unset */
- if (ret == -1)
- {
- DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
- offset,count,op,type,strerror(errno)));
-
- /* perhaps it doesn't support this sort of locking?? */
- if (errno == EINVAL)
- {
- DEBUG(3,("locking not supported? returning True\n"));
- return(True);
- }
-
- return(False);
- }
-
- /* everything went OK */
- DEBUG(5,("Lock call successful\n"));
-
- return(True);
-#else
- return(False);
-#endif
-}
-
-/*******************************************************************
-lock a file - returning a open file descriptor or -1 on failure
-The timeout is in seconds. 0 means no timeout
-********************************************************************/
-int file_lock(char *name,int timeout)
-{
- int fd = open(name,O_RDWR|O_CREAT,0666);
- time_t t=0;
- if (fd < 0) return(-1);
-
-#if HAVE_FCNTL_LOCK
- if (timeout) t = time(NULL);
- while (!timeout || (time(NULL)-t < timeout)) {
- if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
- msleep(LOCK_RETRY_TIMEOUT);
- }
- return(-1);
-#else
- return(fd);
-#endif
-}
+static enum remote_arch_types ra_type = RA_UNKNOWN;
+pstring user_socket_options=DEFAULT_SOCKET_OPTIONS;
-/*******************************************************************
-unlock a file locked by file_lock
-********************************************************************/
-void file_unlock(int fd)
-{
- if (fd<0) return;
-#if HAVE_FCNTL_LOCK
- fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
-#endif
- close(fd);
-}
-
-/*******************************************************************
-a gettimeofday wrapper
-********************************************************************/
-void GetTimeOfDay(struct timeval *tval)
-{
-#ifdef GETTIMEOFDAY1
- gettimeofday(tval);
-#else
- gettimeofday(tval,NULL);
-#endif
-}
-
-int extra_time_offset = 0;
-
-static int timediff = 0;
-
-/*******************************************************************
-init the time differences
-********************************************************************/
-void TimeInit(void)
-{
- struct tm tm_utc,tm_local;
- time_t t;
-
- t = time(NULL);
-
- tm_utc = *(gmtime(&t));
- tm_local = *(localtime(&t));
-
-#ifdef HAVE_GMTOFF
- timediff = -tm_local.tm_gmtoff;
-#else
- timediff = mktime(&tm_utc) - mktime(&tm_local);
-#endif
-
- if (serverzone == 0) {
- serverzone = timediff - DSTDiff(t);
- DEBUG(4,("Serverzone is %d\n",serverzone));
- }
-}
-
-
-/*******************************************************************
-return the DST offset for a particular time
-We keep a table of DST offsets to prevent calling localtime() on each
-call of this function. This saves a LOT of time on many unixes.
-********************************************************************/
-int DSTDiff(time_t t)
-{
- static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL;
- static int table_size = 0;
- int i;
- BOOL is_dst = False;
-
- if (t == 0) t = time(NULL);
-
-#ifndef NO_ISDST
- for (i=0;i<table_size;i++)
- if (t >= dst_table[i].start && t <= dst_table[i].end) break;
-
- if (i<table_size) {
- is_dst = dst_table[i].is_dst;
- } else {
- time_t low,high;
-
- dst_table = (struct dst_table *)Realloc(dst_table,
- sizeof(dst_table[0])*(i+1));
- if (!dst_table) {
- table_size = 0;
- return(0);
- }
-
- table_size++;
-
- dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);;
- dst_table[i].start = dst_table[i].end = t;
-
- /* no entry will cover more than 6 months */
- low = t - 3*30*24*60*60;
- high = t + 3*30*24*60*60;
-
- /* widen the new entry using two bisection searches */
- while (low+60*60 < dst_table[i].start) {
- t = low + (dst_table[i].start-low)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].start = t;
- else
- low = t;
- }
-
- while (high-60*60 > dst_table[i].end) {
- t = high + (high-dst_table[i].end)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].end = t;
- else
- high = t;
- }
-
-/*
- DEBUG(1,("Added DST entry from %s ",
- asctime(localtime(&dst_table[i].start))));
- DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
- dst_table[i].is_dst));
-*/
- }
-#endif
-
- return((is_dst?60*60:0) - (extra_time_offset*60));
-}
-
-/****************************************************************************
-return the difference between local and GMT time
-****************************************************************************/
-int TimeDiff(time_t t)
-{
- static BOOL initialised = False;
- if (!initialised) {initialised=True; TimeInit();}
- return(timediff - DSTDiff(t));
-}
-
-/****************************************************************************
-try to optimise the localtime call, it can be quite expenive on some machines
-timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0
-****************************************************************************/
-struct tm *LocalTime(time_t *t,int timemul)
-{
- time_t t2 = *t;
-
- if (timemul)
- t2 += timemul * TimeDiff(t2);
-
- return(gmtime(&t2));
-}
+pstring global_myname = "";
+fstring global_myworkgroup = "";
+char **my_netbios_names;
/****************************************************************************
-determine if a file descriptor is in fact a socket
-****************************************************************************/
-BOOL is_a_socket(int fd)
+ find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+ ****************************************************************************/
+char *tmpdir(void)
{
- int v,l;
- l = sizeof(int);
- return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
-}
-
-
-static char *last_ptr=NULL;
-
-/****************************************************************************
- Get the next token from a string, return False if none found
- handles double-quotes.
-Based on a routine by GJC@VILLAGE.COM.
-Extensively modified by Andrew.Tridgell@anu.edu.au
-****************************************************************************/
-BOOL next_token(char **ptr,char *buff,char *sep)
-{
- char *s;
- BOOL quoted;
-
- if (!ptr) ptr = &last_ptr;
- if (!ptr) return(False);
-
- s = *ptr;
-
- /* default to simple separators */
- if (!sep) sep = " \t\n\r";
-
- /* find the first non sep char */
- while(*s && strchr(sep,*s)) s++;
-
- /* nothing left? */
- if (! *s) return(False);
-
- /* copy over the token */
- for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++)
- {
- if (*s == '\"')
- quoted = !quoted;
- else
- *buff++ = *s;
- }
-
- *ptr = (*s) ? s+1 : s;
- *buff = 0;
- last_ptr = *ptr;
-
- return(True);
+ char *p;
+ if ((p = getenv("TMPDIR")))
+ return p;
+ return "/tmp";
}
/****************************************************************************
-Convert list of tokens to array; dependent on above routine.
-Uses last_ptr from above - bit of a hack.
+ Determine whether we are in the specified group.
****************************************************************************/
-char **toktocliplist(int *ctok, char *sep)
-{
- char *s=last_ptr;
- int ictok=0;
- char **ret, **iret;
-
- if (!sep) sep = " \t\n\r";
-
- while(*s && strchr(sep,*s)) s++;
-
- /* nothing left? */
- if (!*s) return(NULL);
-
- do {
- ictok++;
- while(*s && (!strchr(sep,*s))) s++;
- while(*s && strchr(sep,*s)) *s++=0;
- } while(*s);
- *ctok=ictok;
- s=last_ptr;
-
- if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
-
- while(ictok--) {
- *iret++=s;
- while(*s++);
- while(!*s) s++;
- }
-
- return ret;
-}
-
-#ifndef HAVE_MEMMOVE
-/*******************************************************************
-safely copies memory, ensuring no overlap problems.
-this is only used if the machine does not have it's own memmove().
-this is not the fastest algorithm in town, but it will do for our
-needs.
-********************************************************************/
-void *MemMove(void *dest,void *src,int size)
+BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups)
{
- unsigned long d,s;
- int i;
- if (dest==src || !size) return(dest);
+ int i;
- d = (unsigned long)dest;
- s = (unsigned long)src;
+ if (group == current_gid)
+ return(True);
- if ((d >= (s+size)) || (s >= (d+size))) {
- /* no overlap */
- memcpy(dest,src,size);
- return(dest);
- }
+ for (i=0;i<ngroups;i++)
+ if (group == groups[i])
+ return(True);
- if (d < s)
- {
- /* we can forward copy */
- if (s-d >= sizeof(int) &&
- !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
- /* do it all as words */
- int *idest = (int *)dest;
- int *isrc = (int *)src;
- size /= sizeof(int);
- for (i=0;i<size;i++) idest[i] = isrc[i];
- } else {
- /* simplest */
- char *cdest = (char *)dest;
- char *csrc = (char *)src;
- for (i=0;i<size;i++) cdest[i] = csrc[i];
- }
- }
- else
- {
- /* must backward copy */
- if (d-s >= sizeof(int) &&
- !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
- /* do it all as words */
- int *idest = (int *)dest;
- int *isrc = (int *)src;
- size /= sizeof(int);
- for (i=size-1;i>=0;i--) idest[i] = isrc[i];
- } else {
- /* simplest */
- char *cdest = (char *)dest;
- char *csrc = (char *)src;
- for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
- }
- }
- return(dest);
+ return(False);
}
-#endif
-
/****************************************************************************
-prompte a dptr (to make it recently used)
+ Like atoi but gets the value up to the separater character.
****************************************************************************/
-void array_promote(char *array,int elsize,int element)
-{
- char *p;
- if (element == 0)
- return;
-
- p = (char *)malloc(elsize);
- if (!p)
- {
- DEBUG(5,("Ahh! Can't malloc\n"));
- return;
- }
- memcpy(p,array + element * elsize, elsize);
- memmove(array + elsize,array,elsize*element);
- memcpy(array,p,elsize);
- free(p);
-}
-
-enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
-
-struct
+char *Atoic(char *p, int *n, char *c)
{
- char *name;
- int level;
- int option;
- int value;
- int opttype;
-} socket_options[] = {
- {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
- {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
- {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
-#ifdef TCP_NODELAY
- {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
-#endif
-#ifdef IPTOS_LOWDELAY
- {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
-#endif
-#ifdef IPTOS_THROUGHPUT
- {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
-#endif
-#ifdef SO_SNDBUF
- {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
-#endif
-#ifdef SO_RCVBUF
- {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
-#endif
-#ifdef SO_SNDLOWAT
- {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
-#endif
-#ifdef SO_RCVLOWAT
- {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
-#endif
- {NULL,0,0,0,0}};
-
-
-
-/****************************************************************************
-set user socket options
-****************************************************************************/
-void set_socket_options(int fd, char *options)
-{
- string tok;
-
- while (next_token(&options,tok," \t,"))
- {
- int ret=0,i;
- int value = 1;
- char *p;
- BOOL got_value = False;
-
- if ((p = strchr(tok,'=')))
- {
- *p = 0;
- value = atoi(p+1);
- got_value = True;
+ if (!isdigit((int)*p)) {
+ DEBUG(5, ("Atoic: malformed number\n"));
+ return NULL;
}
- for (i=0;socket_options[i].name;i++)
- if (strequal(socket_options[i].name,tok))
- break;
+ (*n) = atoi(p);
- if (!socket_options[i].name)
- {
- DEBUG(0,("Unknown socket option %s\n",tok));
- continue;
- }
+ while ((*p) && isdigit((int)*p))
+ p++;
- switch (socket_options[i].opttype)
+ if (strchr_m(c, *p) == NULL)
{
- case OPT_BOOL:
- case OPT_INT:
- ret = setsockopt(fd,socket_options[i].level,
- socket_options[i].option,(char *)&value,sizeof(int));
- break;
-
- case OPT_ON:
- if (got_value)
- DEBUG(0,("syntax error - %s does not take a value\n",tok));
-
- {
- int on = socket_options[i].value;
- ret = setsockopt(fd,socket_options[i].level,
- socket_options[i].option,(char *)&on,sizeof(int));
- }
- break;
+ DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c));
+ return NULL;
}
-
- if (ret != 0)
- DEBUG(0,("Failed to set socket option %s\n",tok));
- }
-}
-
-
-/****************************************************************************
- close the socket communication
-****************************************************************************/
-void close_sockets(void )
-{
- close(Client);
- Client = 0;
+ return p;
}
-/****************************************************************************
- return the date and time as a string
-****************************************************************************/
-char *timestring(void )
-{
- static char TimeBuf[100];
- time_t t;
- t = time(NULL);
-#ifdef NO_STRFTIME
- strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL)));
-#elif defined(CLIX) || defined(CONVEX)
- strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(AMPM)
- strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(TZ_TIME)
- {
- strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0));
- sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d",
- -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60);
- }
-#else
- strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL));
-#endif
- return(TimeBuf);
-}
+/*************************************************************************
+ Reads a list of numbers.
+ *************************************************************************/
-/****************************************************************************
-determine whether we are in the specified group
-****************************************************************************/
-BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
+char *get_numlist(char *p, uint32 **num, int *count)
{
- int i;
+ int val;
- if (group == current_gid) return(True);
+ if (num == NULL || count == NULL)
+ return NULL;
- for (i=0;i<ngroups;i++)
- if (group == groups[i])
- return(True);
+ (*count) = 0;
+ (*num ) = NULL;
- return(False);
-}
-
-/****************************************************************************
-this is a safer strcpy(), meant to prevent core dumps when nasty things happen
-****************************************************************************/
-char *StrCpy(char *dest,char *src)
-{
- char *d = dest;
-
-#if AJT
- /* I don't want to get lazy with these ... */
- if (!dest || !src) {
- DEBUG(0,("ERROR: NULL StrCpy() called!\n"));
- ajt_panic();
- }
-#endif
-
- if (!dest) return(NULL);
- if (!src) {
- *dest = 0;
- return(dest);
- }
- while ((*d++ = *src++)) ;
- return(dest);
-}
+ while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') {
+ uint32 *tn;
+
+ tn = Realloc((*num), ((*count)+1) * sizeof(uint32));
+ if (tn == NULL)
+ {
+ SAFE_FREE(*num);
+ return NULL;
+ } else
+ (*num) = tn;
+ (*num)[(*count)] = val;
+ (*count)++;
+ p++;
+ }
-/****************************************************************************
-line strncpy but always null terminates. Make sure there is room!
-****************************************************************************/
-char *StrnCpy(char *dest,const char *src,int n)
-{
- char *d = dest;
- if (!dest) return(NULL);
- if (!src) {
- *dest = 0;
- return(dest);
- }
- while (n-- && (*d++ = *src++)) ;
- *d = 0;
- return(dest);
+ return p;
}
-
/*******************************************************************
-copy an IP address from one buffer to another
+ Check if a file exists - call vfs_file_exist for samba files.
********************************************************************/
-void putip(void *dest,void *src)
-{
- memcpy(dest,src,4);
-}
-
-/****************************************************************************
-interpret the weird netbios "name". Return the name type
-****************************************************************************/
-static int name_interpret(char *in,char *out)
+BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
{
- int ret;
- int len = (*in++) / 2;
-
- *out=0;
-
- if (len > 30 || len<1) return(0);
-
- while (len--)
- {
- if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
- *out = 0;
- return(0);
- }
- *out = ((in[0]-'A')<<4) + (in[1]-'A');
- in += 2;
- out++;
- }
- *out = 0;
- ret = out[-1];
-
-#ifdef NETBIOS_SCOPE
- /* Handle any scope names */
- while(*in)
- {
- *out++ = '.'; /* Scope names are separated by periods */
- len = *(unsigned char *)in++;
- StrnCpy(out, in, len);
- out += len;
- *out=0;
- in += len;
- }
-#endif
- return(ret);
-}
-
-/****************************************************************************
-mangle a name into netbios format
-****************************************************************************/
-int name_mangle(char *In,char *Out,char name_type)
-{
- fstring name;
- char buf[20];
- char *in = (char *)&buf[0];
- char *out = (char *)Out;
- char *p, *label;
- int i;
-
- if (In[0] != '*') {
- StrnCpy(name,In,sizeof(name)-1);
- sprintf(buf,"%-15.15s%c",name,name_type);
- } else {
- buf[0]='*';
- memset(&buf[1],0,16);
- }
-
- *out++ = 32;
- for (i=0;i<16;i++) {
- char c = toupper(in[i]);
- out[i*2] = (c>>4) + 'A';
- out[i*2+1] = (c & 0xF) + 'A';
- }
- out[32]=0;
- out += 32;
-
- label = scope;
- while (*label)
- {
- p = strchr(label, '.');
- if (p == 0)
- p = label + strlen(label);
- *out++ = p - label;
- memcpy(out, label, p - label);
- out += p - label;
- label += p - label + (*p == '.');
- }
- *out = 0;
- return(name_len(Out));
-}
-
-
-/*******************************************************************
- check if a file exists
-********************************************************************/
-BOOL file_exist(char *fname,struct stat *sbuf)
-{
- struct stat st;
- if (!sbuf) sbuf = &st;
+ SMB_STRUCT_STAT st;
+ if (!sbuf)
+ sbuf = &st;
if (sys_stat(fname,sbuf) != 0)
return(False);
@@ -996,11 +195,12 @@ BOOL file_exist(char *fname,struct stat *sbuf)
}
/*******************************************************************
-check a files mod time
+ Check a files mod time.
********************************************************************/
+
time_t file_modtime(char *fname)
{
- struct stat st;
+ SMB_STRUCT_STAT st;
if (sys_stat(fname,&st) != 0)
return(0);
@@ -1009,444 +209,99 @@ time_t file_modtime(char *fname)
}
/*******************************************************************
- check if a directory exists
+ Check if a directory exists.
********************************************************************/
-BOOL directory_exist(char *dname,struct stat *st)
+
+BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
{
- struct stat st2;
+ SMB_STRUCT_STAT st2;
+ BOOL ret;
+
if (!st) st = &st2;
if (sys_stat(dname,st) != 0)
return(False);
- return(S_ISDIR(st->st_mode));
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
}
/*******************************************************************
returns the size in bytes of the named file
********************************************************************/
-uint32 file_size(char *file_name)
+SMB_OFF_T get_file_size(char *file_name)
{
- struct stat buf;
+ SMB_STRUCT_STAT buf;
buf.st_size = 0;
- sys_stat(file_name,&buf);
+ if(sys_stat(file_name,&buf) != 0)
+ return (SMB_OFF_T)-1;
return(buf.st_size);
}
-/****************************************************************************
-check if it's a null mtime
-****************************************************************************/
-static BOOL null_mtime(time_t mtime)
-{
- if (mtime == 0 || mtime == 0xFFFFFFFF)
- return(True);
- return(False);
-}
-
-/*******************************************************************
- create a 16 bit dos packed date
-********************************************************************/
-static uint16 make_dos_date1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
- ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 16 bit dos packed time
-********************************************************************/
-static uint16 make_dos_time1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
- ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 32 bit dos packed date/time from some parameters
- This takes a GMT time and returns a packed localtime structure
-********************************************************************/
-static uint32 make_dos_date(time_t unixdate)
-{
- struct tm *t;
- uint32 ret=0;
-
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
-
- ret = make_dos_date1(unixdate,t);
- ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t);
-
- return(ret);
-}
-
-/*******************************************************************
-put a dos date into a buffer (time/date format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos date into a buffer (date/time format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date2(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos 32 bit "unix like" date into a buffer. This routine takes
-GMT and converts it to LOCAL time before putting it (most SMBs assume
-localtime for this sort of date)
-********************************************************************/
-void put_dos_date3(char *buf,int offset,time_t unixdate)
-{
- if (!null_mtime(unixdate))
- unixdate += GMT_TO_LOCAL*TimeDiff(unixdate);
- SIVAL(buf,offset,unixdate);
-}
-
-/*******************************************************************
- interpret a 32 bit dos packed date/time to some parameters
-********************************************************************/
-static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
-{
- uint32 p0,p1,p2,p3;
-
- p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
- p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
-
- *second = 2*(p0 & 0x1F);
- *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
- *hour = (p1>>3)&0xFF;
- *day = (p2&0x1F);
- *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
- *year = ((p3>>1)&0xFF) + 80;
-}
-
-/*******************************************************************
- create a unix date (int GMT) from a dos date (which is actually in
- localtime)
-********************************************************************/
-time_t make_unix_date(void *date_ptr)
-{
- uint32 dos_date=0;
- struct tm t;
- time_t ret;
-
- dos_date = IVAL(date_ptr,0);
-
- if (dos_date == 0) return(0);
-
- interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
- &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
- t.tm_wday = 1;
- t.tm_yday = 1;
- t.tm_isdst = -1;
-
- /* mktime() also does the local to GMT time conversion for us. XXXXX
- Do all unixes do this the same?? */
- ret = mktime(&t);
-
- return(ret);
-}
-
-/*******************************************************************
-like make_unix_date() but the words are reversed
-********************************************************************/
-time_t make_unix_date2(void *date_ptr)
-{
- uint32 x,x2;
-
- x = IVAL(date_ptr,0);
- x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(&x,0,x2);
-
- return(make_unix_date((void *)&x));
-}
-
-/*******************************************************************
- create a unix GMT date from a dos date in 32 bit "unix like" format
-these generally arrive as localtimes, with corresponding DST
-********************************************************************/
-time_t make_unix_date3(void *date_ptr)
-{
- time_t t = IVAL(date_ptr,0);
- if (!null_mtime(t))
- t += LOCAL_TO_GMT*TimeDiff(t);
- return(t);
-}
-
/*******************************************************************
return a string representing an attribute for a file
********************************************************************/
-char *attrib_string(int mode)
+char *attrib_string(uint16 mode)
{
- static char attrstr[10];
+ static fstring attrstr;
attrstr[0] = 0;
- if (mode & aVOLID) strcat(attrstr,"V");
- if (mode & aDIR) strcat(attrstr,"D");
- if (mode & aARCH) strcat(attrstr,"A");
- if (mode & aHIDDEN) strcat(attrstr,"H");
- if (mode & aSYSTEM) strcat(attrstr,"S");
- if (mode & aRONLY) strcat(attrstr,"R");
+ if (mode & aVOLID) fstrcat(attrstr,"V");
+ if (mode & aDIR) fstrcat(attrstr,"D");
+ if (mode & aARCH) fstrcat(attrstr,"A");
+ if (mode & aHIDDEN) fstrcat(attrstr,"H");
+ if (mode & aSYSTEM) fstrcat(attrstr,"S");
+ if (mode & aRONLY) fstrcat(attrstr,"R");
return(attrstr);
}
-
-/*******************************************************************
- case insensitive string compararison
-********************************************************************/
-int StrCaseCmp(char *s, char *t)
-{
- for (; tolower(*s) == tolower(*t); ++s, ++t)
- if (!*s) return 0;
-
- return tolower(*s) - tolower(*t);
-}
-
-/*******************************************************************
- case insensitive string compararison, length limited
-********************************************************************/
-int StrnCaseCmp(char *s, char *t, int n)
-{
- while (n-- && *s && *t) {
- if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
- s++; t++;
- }
- if (n) return(tolower(*s) - tolower(*t));
-
- return(0);
-}
-
-/*******************************************************************
- compare 2 strings
-********************************************************************/
-BOOL strequal(char *s1,char *s2)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2) return(False);
-
- return(StrCaseCmp(s1,s2)==0);
-}
-
-/*******************************************************************
- compare 2 strings up to and including the nth char.
- ******************************************************************/
-BOOL strnequal(char *s1,char *s2,int n)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2 || !n) return(False);
-
- return(StrnCaseCmp(s1,s2,n)==0);
-}
-
-/*******************************************************************
- compare 2 strings (case sensitive)
-********************************************************************/
-BOOL strcsequal(char *s1,char *s2)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2) return(False);
-
- return(strcmp(s1,s2)==0);
-}
-
-
/*******************************************************************
- convert a string to lower case
+ show a smb message structure
********************************************************************/
-void strlower(char *s)
+void show_msg(char *buf)
{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s))
- *s = tolower(*s);
- s++;
+ int i;
+ int bcc=0;
+
+ if (DEBUGLEVEL < 5) return;
+
+ DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
+ smb_len(buf),
+ (int)CVAL(buf,smb_com),
+ (int)CVAL(buf,smb_rcls),
+ (int)CVAL(buf,smb_reh),
+ (int)SVAL(buf,smb_err),
+ (int)CVAL(buf,smb_flg),
+ (int)SVAL(buf,smb_flg2)));
+ DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
+ (int)SVAL(buf,smb_tid),
+ (int)SVAL(buf,smb_pid),
+ (int)SVAL(buf,smb_uid),
+ (int)SVAL(buf,smb_mid),
+ (int)CVAL(buf,smb_wct)));
+
+ for (i=0;i<(int)CVAL(buf,smb_wct);i++)
+ {
+ DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
+ SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
}
-#else
- if (isupper(*s))
- *s = tolower(*s);
- s++;
-#endif /* KANJI */
- }
-}
-/*******************************************************************
- convert a string to upper case
-********************************************************************/
-void strupper(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s))
- *s = toupper(*s);
- s++;
- }
-#else
- if (islower(*s))
- *s = toupper(*s);
- s++;
-#endif
- }
-}
+ bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
-/*******************************************************************
- convert a string to "normal" form
-********************************************************************/
-void strnorm(char *s)
-{
- if (case_default == CASE_UPPER)
- strupper(s);
- else
- strlower(s);
-}
-
-/*******************************************************************
-check if a string is in "normal" case
-********************************************************************/
-BOOL strisnormal(char *s)
-{
- if (case_default == CASE_UPPER)
- return(!strhaslower(s));
-
- return(!strhasupper(s));
-}
+ DEBUG(5,("smb_bcc=%d\n",bcc));
+ if (DEBUGLEVEL < 10) return;
-/****************************************************************************
- string replace
-****************************************************************************/
-void string_replace(char *s,char oldc,char newc)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (oldc == *s)
- *s = newc;
- s++;
+ if (DEBUGLEVEL < 50)
+ {
+ bcc = MIN(bcc, 512);
}
-#else
- if (oldc == *s)
- *s = newc;
- s++;
-#endif /* KANJI */
- }
-}
-/****************************************************************************
- make a file into unix format
-****************************************************************************/
-void unix_format(char *fname)
-{
- pstring namecopy;
- string_replace(fname,'\\','/');
-#ifndef KANJI
- dos2unix_format(fname, True);
-#endif /* KANJI */
-
- if (*fname == '/')
- {
- strcpy(namecopy,fname);
- strcpy(fname,".");
- strcat(fname,namecopy);
- }
-}
-
-/****************************************************************************
- make a file into dos format
-****************************************************************************/
-void dos_format(char *fname)
-{
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif /* KANJI */
- string_replace(fname,'/','\\');
-}
-
-
-/*******************************************************************
- show a smb message structure
-********************************************************************/
-void show_msg(char *buf)
-{
- int i;
- int bcc=0;
- if (DEBUGLEVEL < 5)
- return;
-
- DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
- smb_len(buf),
- (int)CVAL(buf,smb_com),
- (int)CVAL(buf,smb_rcls),
- (int)CVAL(buf,smb_reh),
- (int)SVAL(buf,smb_err),
- (int)CVAL(buf,smb_flg),
- (int)SVAL(buf,smb_flg2)));
- DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
- (int)SVAL(buf,smb_tid),
- (int)SVAL(buf,smb_pid),
- (int)SVAL(buf,smb_uid),
- (int)SVAL(buf,smb_mid),
- (int)CVAL(buf,smb_wct)));
- for (i=0;i<(int)CVAL(buf,smb_wct);i++)
- DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
- SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
- bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
- DEBUG(5,("smb_bcc=%d\n",bcc));
- if (DEBUGLEVEL < 10)
- return;
- for (i=0;i<MIN(bcc,128);i++)
- DEBUG(10,("%X ",CVAL(smb_buf(buf),i)));
- DEBUG(10,("\n"));
-}
-
-/*******************************************************************
- return the length of an smb packet
-********************************************************************/
-int smb_len(char *buf)
-{
- return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) );
-}
-
-/*******************************************************************
- set the length of an smb packet
-********************************************************************/
-void _smb_setlen(char *buf,int len)
-{
- buf[0] = 0;
- buf[1] = (len&0x10000)>>16;
- buf[2] = (len&0xFF00)>>8;
- buf[3] = len&0xFF;
+ dump_data(10, smb_buf(buf), bcc);
}
/*******************************************************************
@@ -1467,93 +322,35 @@ void smb_setlen(char *buf,int len)
********************************************************************/
int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
{
- if (zero)
- bzero(buf + smb_size,num_words*2 + num_bytes);
- CVAL(buf,smb_wct) = num_words;
- SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
- smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
- return (smb_size + num_words*2 + num_bytes);
+ if (zero)
+ memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+ CVAL(buf,smb_wct) = num_words;
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
}
/*******************************************************************
-return the number of smb words
+ setup only the byte count for a smb message
********************************************************************/
-int smb_numwords(char *buf)
+int set_message_bcc(char *buf,int num_bytes)
{
- return (CVAL(buf,smb_wct));
+ int num_words = CVAL(buf,smb_wct);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
}
/*******************************************************************
-return the size of the smb_buf region of a message
+ setup only the byte count for a smb message, using the end of the
+ message as a marker
********************************************************************/
-int smb_buflen(char *buf)
+int set_message_end(void *outbuf,void *end_ptr)
{
- return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2));
+ return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
}
/*******************************************************************
- return a pointer to the smb_buf data area
-********************************************************************/
-int smb_buf_ofs(char *buf)
-{
- return (smb_size + CVAL(buf,smb_wct)*2);
-}
-
-/*******************************************************************
- return a pointer to the smb_buf data area
-********************************************************************/
-char *smb_buf(char *buf)
-{
- return (buf + smb_buf_ofs(buf));
-}
-
-/*******************************************************************
-return the SMB offset into an SMB buffer
-********************************************************************/
-int smb_offset(char *p,char *buf)
-{
- return(PTR_DIFF(p,buf+4));
-}
-
-
-/*******************************************************************
-skip past some strings in a buffer
-********************************************************************/
-char *skip_string(char *buf,int n)
-{
- while (n--)
- buf += strlen(buf) + 1;
- return(buf);
-}
-
-/*******************************************************************
-trim the specified elements off the front and back of a string
-********************************************************************/
-BOOL trim_string(char *s,char *front,char *back)
-{
- BOOL ret = False;
- while (front && *front && strncmp(s,front,strlen(front)) == 0)
- {
- char *p = s;
- ret = True;
- while (1)
- {
- if (!(*p = p[strlen(front)]))
- break;
- p++;
- }
- }
- while (back && *back && strlen(s) >= strlen(back) &&
- (strncmp(s+strlen(s)-strlen(back),back,strlen(back))==0))
- {
- ret = True;
- s[strlen(s)-strlen(back)] = 0;
- }
- return(ret);
-}
-
-
-/*******************************************************************
reduce a file name, removing .. elements.
********************************************************************/
void dos_clean_name(char *s)
@@ -1563,25 +360,25 @@ void dos_clean_name(char *s)
DEBUG(3,("dos_clean_name [%s]\n",s));
/* remove any double slashes */
- string_sub(s, "\\\\", "\\");
+ all_string_sub(s, "\\\\", "\\", 0);
while ((p = strstr(s,"\\..\\")) != NULL)
{
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
- if ((p=strrchr(s,'\\')) != NULL)
+ if ((p=strrchr_m(s,'\\')) != NULL)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"\\..");
- string_sub(s, "\\.\\", "\\");
+ all_string_sub(s, "\\.\\", "\\", 0);
}
/*******************************************************************
@@ -1594,474 +391,117 @@ void unix_clean_name(char *s)
DEBUG(3,("unix_clean_name [%s]\n",s));
/* remove any double slashes */
- string_sub(s, "//","/");
+ all_string_sub(s, "//","/", 0);
+
+ /* Remove leading ./ characters */
+ if(strncmp(s, "./", 2) == 0) {
+ trim_string(s, "./", NULL);
+ if(*s == 0)
+ pstrcpy(s,"./");
+ }
while ((p = strstr(s,"/../")) != NULL)
{
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
- if ((p=strrchr(s,'/')) != NULL)
+ if ((p=strrchr_m(s,'/')) != NULL)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"/..");
}
-
-/*******************************************************************
-a wrapper for the normal chdir() function
-********************************************************************/
-int ChDir(char *path)
-{
- int res;
- static pstring LastDir="";
-
- if (strcsequal(path,".")) return(0);
-
- if (*path == '/' && strcsequal(LastDir,path)) return(0);
- DEBUG(3,("chdir to %s\n",path));
- res = sys_chdir(path);
- if (!res)
- strcpy(LastDir,path);
- return(res);
-}
-
-
-/*******************************************************************
- return the absolute current directory path. A dumb version.
-********************************************************************/
-static char *Dumb_GetWd(char *s)
-{
-#ifdef USE_GETCWD
- return ((char *)getcwd(s,sizeof(pstring)));
-#else
- return ((char *)getwd(s));
-#endif
-}
-
-
-/* number of list structures for a caching GetWd function. */
-#define MAX_GETWDCACHE (50)
-
-struct
-{
- ino_t inode;
- dev_t dev;
- char *text;
- BOOL valid;
-} ino_list[MAX_GETWDCACHE];
-
-BOOL use_getwd_cache=True;
-
/*******************************************************************
- return the absolute current directory path
+convert '\' to '/'
+reduce a file name, removing or reducing /../ , /./ , // elements.
+remove also any trailing . and /
+return a new allocated string.
********************************************************************/
-char *GetWd(char *str)
-{
- pstring s;
- static BOOL getwd_cache_init = False;
- struct stat st, st2;
- int i;
-
- *s = 0;
-
- if (!use_getwd_cache)
- return(Dumb_GetWd(str));
-
- /* init the cache */
- if (!getwd_cache_init)
- {
- getwd_cache_init = True;
- for (i=0;i<MAX_GETWDCACHE;i++)
- {
- string_init(&ino_list[i].text,"");
- ino_list[i].valid = False;
- }
- }
-
- /* Get the inode of the current directory, if this doesn't work we're
- in trouble :-) */
-
- if (stat(".",&st) == -1)
- {
- DEBUG(0,("Very strange, couldn't stat \".\"\n"));
- return(Dumb_GetWd(str));
- }
-
-
- for (i=0; i<MAX_GETWDCACHE; i++)
- if (ino_list[i].valid)
- {
-
- /* If we have found an entry with a matching inode and dev number
- then find the inode number for the directory in the cached string.
- If this agrees with that returned by the stat for the current
- directory then all is o.k. (but make sure it is a directory all
- the same...) */
-
- if (st.st_ino == ino_list[i].inode &&
- st.st_dev == ino_list[i].dev)
- {
- if (stat(ino_list[i].text,&st2) == 0)
- {
- if (st.st_ino == st2.st_ino &&
- st.st_dev == st2.st_dev &&
- (st2.st_mode & S_IFMT) == S_IFDIR)
- {
- strcpy (str, ino_list[i].text);
-
- /* promote it for future use */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
- return (str);
- }
- else
- {
- /* If the inode is different then something's changed,
- scrub the entry and start from scratch. */
- ino_list[i].valid = False;
- }
- }
- }
- }
-
-
- /* We don't have the information to hand so rely on traditional methods.
- The very slow getcwd, which spawns a process on some systems, or the
- not quite so bad getwd. */
-
- if (!Dumb_GetWd(s))
- {
- DEBUG(0,("Getwd failed, errno %d\n",errno));
- return (NULL);
- }
-
- strcpy(str,s);
-
- DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev));
-
- /* add it to the cache */
- i = MAX_GETWDCACHE - 1;
- string_set(&ino_list[i].text,s);
- ino_list[i].dev = st.st_dev;
- ino_list[i].inode = st.st_ino;
- ino_list[i].valid = True;
-
- /* put it at the top of the list */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
-
- return (str);
-}
-
-
-
-/*******************************************************************
-reduce a file name, removing .. elements and checking that
-it is below dir in the heirachy. This uses GetWd() and so must be run
-on the system that has the referenced file system.
-
-widelinks are allowed if widelinks is true
-********************************************************************/
-BOOL reduce_name(char *s,char *dir,BOOL widelinks)
-{
-#ifndef REDUCE_PATHS
- return True;
-#else
- pstring dir2;
- pstring wd;
- pstring basename;
- pstring newname;
- char *p=NULL;
- BOOL relative = (*s != '/');
-
- *dir2 = *wd = *basename = *newname = 0;
-
- if (widelinks)
- {
- unix_clean_name(s);
- /* can't have a leading .. */
- if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
- {
- DEBUG(3,("Illegal file name? (%s)\n",s));
- return(False);
- }
- return(True);
- }
-
- DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
-
- /* remove any double slashes */
- string_sub(s,"//","/");
-
- strcpy(basename,s);
- p = strrchr(basename,'/');
-
- if (!p)
- return(True);
-
- if (!GetWd(wd))
- {
- DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
- return(False);
- }
-
- if (ChDir(dir) != 0)
- {
- DEBUG(0,("couldn't chdir to %s\n",dir));
- return(False);
- }
-
- if (!GetWd(dir2))
- {
- DEBUG(0,("couldn't getwd for %s\n",dir));
- ChDir(wd);
- return(False);
- }
-
-
- if (p && (p != basename))
- {
- *p = 0;
- if (strcmp(p+1,".")==0)
- p[1]=0;
- if (strcmp(p+1,"..")==0)
- *p = '/';
- }
-
- if (ChDir(basename) != 0)
- {
- ChDir(wd);
- DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename));
- return(False);
- }
-
- if (!GetWd(newname))
- {
- ChDir(wd);
- DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
- return(False);
- }
-
- if (p && (p != basename))
- {
- strcat(newname,"/");
- strcat(newname,p+1);
- }
-
- {
- int l = strlen(dir2);
- if (dir2[l-1] == '/')
- l--;
-
- if (strncmp(newname,dir2,l) != 0)
- {
- ChDir(wd);
- DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l));
- return(False);
- }
-
- if (relative)
- {
- if (newname[l] == '/')
- strcpy(s,newname + l + 1);
- else
- strcpy(s,newname+l);
- }
- else
- strcpy(s,newname);
- }
-
- ChDir(wd);
-
- if (strlen(s) == 0)
- strcpy(s,"./");
-
- DEBUG(3,("reduced to %s\n",s));
- return(True);
-#endif
-}
-
-/****************************************************************************
-expand some *s
-****************************************************************************/
-static void expand_one(char *Mask,int len)
-{
- char *p1;
- while ((p1 = strchr(Mask,'*')) != NULL)
- {
- int lfill = (len+1) - strlen(Mask);
- int l1= (p1 - Mask);
- pstring tmp;
- strcpy(tmp,Mask);
- memset(tmp+l1,'?',lfill);
- strcpy(tmp + l1 + lfill,Mask + l1 + 1);
- strcpy(Mask,tmp);
- }
-}
-
-/****************************************************************************
-expand a wildcard expression, replacing *s with ?s
-****************************************************************************/
-void expand_mask(char *Mask,BOOL doext)
-{
- pstring mbeg,mext;
- pstring dirpart;
- pstring filepart;
- BOOL hasdot = False;
- char *p1;
- BOOL absolute = (*Mask == '\\');
-
- *mbeg = *mext = *dirpart = *filepart = 0;
-
- /* parse the directory and filename */
- if (strchr(Mask,'\\'))
- dirname_dos(Mask,dirpart);
-
- filename_dos(Mask,filepart);
-
- strcpy(mbeg,filepart);
- if ((p1 = strchr(mbeg,'.')) != NULL)
- {
- hasdot = True;
- *p1 = 0;
- p1++;
- strcpy(mext,p1);
- }
- else
- {
- strcpy(mext,"");
- if (strlen(mbeg) > 8)
- {
- strcpy(mext,mbeg + 8);
- mbeg[8] = 0;
+smb_ucs2_t *unix_clean_path(const smb_ucs2_t *s)
+{
+ smb_ucs2_t *ns;
+ smb_ucs2_t *p, *r, *t;
+
+ DEBUG(3, ("unix_clean_path\n")); /* [%unicode]\n")); */
+
+ /* convert '\' to '/' */
+ ns = strdup_w(s);
+ if (!ns) return NULL;
+ unix_format_w(ns);
+
+ /* remove all double slashes */
+ p = ns;
+ ns = all_string_sub_wa(p, "//", "/");
+ SAFE_FREE(p);
+ if (!ns) return NULL;
+
+ /* remove any /./ */
+ p = ns;
+ ns = all_string_sub_wa(p, "/./", "/");
+ SAFE_FREE(p);
+ if (!ns) return NULL;
+
+ /* reduce any /../ */
+ t = ns;
+ while ((r = strstr_wa(t, "/.."))) {
+ t = &(r[3]);
+ if (*t == UCS2_CHAR('/') || *t == 0) {
+ *r = 0;
+ p = strrchr_w(ns, UCS2_CHAR('/'));
+ if (!p) p = ns;
+ memmove(p, t, (strlen_w(t) + 1) * sizeof(smb_ucs2_t));
+ t = p;
+ }
}
- }
-
- if (*mbeg == 0)
- strcpy(mbeg,"????????");
- if ((*mext == 0) && doext && !hasdot)
- strcpy(mext,"???");
- if (strequal(mbeg,"*") && *mext==0)
- strcpy(mext,"*");
+ /* remove any trailing /. */
+ trim_string_wa(ns, NULL, "/.");
- /* expand *'s */
- expand_one(mbeg,8);
- if (*mext)
- expand_one(mext,3);
+ /* remove any leading and trailing / */
+ trim_string_wa(ns, "/", "/");
- strcpy(Mask,dirpart);
- if (*dirpart || absolute) strcat(Mask,"\\");
- strcat(Mask,mbeg);
- strcat(Mask,".");
- strcat(Mask,mext);
-
- DEBUG(6,("Mask expanded to [%s]\n",Mask));
-}
-
-
-/****************************************************************************
-does a string have any uppercase chars in it?
-****************************************************************************/
-BOOL strhasupper(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s)) return(True);
- s++;
- }
-#else
- if (isupper(*s)) return(True);
- s++;
-#endif /* KANJI */
- }
- return(False);
+ return ns;
}
/****************************************************************************
-does a string have any lowercase chars in it?
-****************************************************************************/
-BOOL strhaslower(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s)) return(True);
- s++;
- }
-#else
- if (islower(*s)) return(True);
- s++;
-#endif /* KANJI */
- }
- return(False);
-}
-
-/****************************************************************************
-find the number of chars in a string
-****************************************************************************/
-int count_chars(char *s,char c)
-{
- int count=0;
- while (*s)
- {
- if (*s == c)
- count++;
- s++;
- }
- return(count);
-}
-
-
-/****************************************************************************
make a dir struct
****************************************************************************/
-void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date)
+void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date)
{
char *p;
pstring mask2;
- strcpy(mask2,mask);
+ pstrcpy(mask2,mask);
if ((mode & aDIR) != 0)
size = 0;
memset(buf+1,' ',11);
- if ((p = strchr(mask2,'.')) != NULL)
+ if ((p = strchr_m(mask2,'.')) != NULL)
{
*p = 0;
- memcpy(buf+1,mask2,MIN(strlen(mask2),8));
- memcpy(buf+9,p+1,MIN(strlen(p+1),3));
+ push_ascii(buf+1,mask2,8, 0);
+ push_ascii(buf+9,p+1,3, 0);
*p = '.';
}
else
- memcpy(buf+1,mask2,MIN(strlen(mask2),11));
+ push_ascii(buf+1,mask2,11, 0);
- bzero(buf+21,DIR_STRUCT_SIZE-21);
+ memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
CVAL(buf,21) = mode;
put_dos_date(buf,22,date);
SSVAL(buf,26,size & 0xFFFF);
- SSVAL(buf,28,size >> 16);
- StrnCpy(buf+30,fname,12);
+ SSVAL(buf,28,(size >> 16)&0xFFFF);
+ push_ascii(buf+30,fname,12, 0);
if (!case_sensitive)
strupper(buf+30);
- DEBUG(8,("put name [%s] into dir struct\n",buf+30));
+ DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
}
@@ -2072,12 +512,15 @@ void close_low_fds(void)
{
int fd;
int i;
- close(0); close(1); close(2);
+ close(0); close(1);
+#ifndef __INSURE__
+ close(2);
+#endif
/* try and use up these file descriptors, so silly
library routines writing to stdout etc won't cause havoc */
for (i=0;i<3;i++) {
- fd = open("/dev/null",O_RDWR,0);
- if (fd < 0) fd = open("/dev/null",O_WRONLY,0);
+ fd = sys_open("/dev/null",O_RDWR,0);
+ if (fd < 0) fd = sys_open("/dev/null",O_WRONLY,0);
if (fd < 0) {
DEBUG(0,("Can't open /dev/null\n"));
return;
@@ -2089,48 +532,6 @@ void close_low_fds(void)
}
}
-
-/****************************************************************************
-write to a socket
-****************************************************************************/
-int write_socket(int fd,char *buf,int len)
-{
- int ret=0;
-
- if (passive)
- return(len);
- DEBUG(6,("write_socket(%d,%d)\n",fd,len));
- ret = write_data(fd,buf,len);
-
- DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret));
- return(ret);
-}
-
-/****************************************************************************
-read from a socket
-****************************************************************************/
-int read_udp_socket(int fd,char *buf,int len)
-{
- int ret;
- struct sockaddr sock;
- int socklen;
-
- socklen = sizeof(sock);
- bzero((char *)&sock,socklen);
- bzero((char *)&lastip,sizeof(lastip));
- ret = recvfrom(fd,buf,len,0,&sock,&socklen);
- if (ret <= 0)
- {
- DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
- return(0);
- }
-
- lastip = *(struct in_addr *) &sock.sa_data[2];
- lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
-
- return(ret);
-}
-
/****************************************************************************
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
@@ -2139,7 +540,7 @@ if BSD use FNDELAY
****************************************************************************/
int set_blocking(int fd, BOOL set)
{
-int val;
+ int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
@@ -2150,7 +551,7 @@ int val;
#endif
#endif
- if((val = fcntl(fd, F_GETFL, 0))==-1)
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
if(set) /* Turn blocking on - ie. clear nonblock flag */
val &= ~FLAG_TO_SET;
@@ -2160,2351 +561,1585 @@ int val;
#undef FLAG_TO_SET
}
-
/****************************************************************************
-Calculate the difference in timeout values. Return 1 if val1 > val2,
-0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval
-may be == val1 or val2
+ Transfer some data between two fd's.
****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
-{
- int usecdiff = val1->tv_usec - val2->tv_usec;
- int secdiff = val1->tv_sec - val2->tv_sec;
- if(usecdiff < 0) {
- usecdiff = 1000000 + usecdiff;
- secdiff--;
- }
- retval->tv_sec = secdiff;
- retval->tv_usec = usecdiff;
- if(secdiff < 0)
- return -1;
- if(secdiff > 0)
- return 1;
- return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0);
-}
-/****************************************************************************
-read data from a device with a timout in msec.
-mincount = if timeout, minimum to read before returning
-maxcount = number to be read.
-****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
+ssize_t transfer_file_internal(int infd, int outfd, size_t n, ssize_t (*read_fn)(int, void *, size_t),
+ ssize_t (*write_fn)(int, const void *, size_t))
{
- fd_set fds;
- int selrtn;
- int readret;
- int nread = 0;
- struct timeval timeout, tval1, tval2, tvaldiff;
- int error_limit = 5;
-
- /* just checking .... */
- if (maxcnt <= 0) return(0);
+ static char buf[16384];
+ size_t total = 0;
+ ssize_t read_ret;
+ size_t write_total = 0;
+ ssize_t write_ret;
- if(time_out == -2)
- time_out = DEFAULT_PIPE_TIMEOUT;
+ while (total < n) {
+ size_t num_to_read_thistime = MIN((n - total), sizeof(buf));
- /* Blocking read */
- if(time_out < 0) {
- if (mincnt == 0) mincnt = maxcnt;
+ read_ret = (*read_fn)(infd, buf + total, num_to_read_thistime);
+ if (read_ret == -1) {
+ DEBUG(0,("transfer_file_internal: read failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (read_ret == 0)
+ break;
- while (nread < mincnt)
- {
- readret = read(fd, buf + nread, maxcnt - nread);
- if (readret <= 0) return(nread);
- nread += readret;
- }
- return(nread);
- }
-
- /* Non blocking read */
- if(time_out == 0) {
- set_blocking(fd, False);
- nread = read_data(fd, buf, mincnt);
- if (nread < maxcnt)
- nread += read(fd,buf+nread,maxcnt-nread);
- if(nread == -1 && errno == EWOULDBLOCK)
- nread = 0;
- set_blocking(fd,True);
- return nread;
- }
-
- /* Most difficult - timeout read */
- /* If this is ever called on a disk file and
- mincnt is greater then the filesize then
- system performance will suffer severely as
- select always return true on disk files */
-
- /* Set initial timeout */
- timeout.tv_sec = time_out / 1000;
- timeout.tv_usec = 1000 * (time_out % 1000);
-
- /* As most UNIXes don't modify the value of timeout
- when they return from select we need to get the timeofday (in usec)
- now, and also after the select returns so we know
- how much time has elapsed */
-
- if (exact)
- GetTimeOfDay( &tval1);
- nread = 0; /* Number of bytes we have read */
-
- for(;;)
- {
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
-
- selrtn = sys_select(&fds,&timeout);
-
- /* Check if error */
- if(selrtn == -1) {
- errno = EBADF;
- return -1;
- }
-
- /* Did we timeout ? */
- if (selrtn == 0) {
- if (nread < mincnt) return -1;
- break; /* Yes */
- }
-
- readret = read(fd, buf+nread, maxcnt-nread);
- if (readret == 0 && nread < mincnt) {
- /* error_limit should not really be needed, but some systems
- do strange things ... I don't want to just continue
- indefinately in case we get an infinite loop */
- if (error_limit--) continue;
- return(-1);
- }
+ write_total = 0;
+
+ while (write_total < read_ret) {
+ write_ret = (*write_fn)(outfd,buf + total, read_ret);
+
+ if (write_ret == -1) {
+ DEBUG(0,("transfer_file_internal: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (write_ret == 0)
+ return (ssize_t)total;
+
+ write_total += (size_t)write_ret;
+ }
- if (readret < 0) {
- /* force a particular error number for
- portability */
- DEBUG(5,("read gave error %s\n",strerror(errno)));
- errno = EBADF;
- return -1;
- }
-
- nread += readret;
-
- /* If we have read more than mincnt then return */
- if (nread >= mincnt)
- break;
-
- /* We need to do another select - but first reduce the
- time_out by the amount of time already elapsed - if
- this is less than zero then return */
- if (exact) {
- GetTimeOfDay(&tval2);
- (void)tval_sub( &tvaldiff, &tval2, &tval1);
-
- if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0)
- break; /* We timed out */
- }
-
- /* Save the time of day as we need to do the select
- again (saves a system call) */
- tval1 = tval2;
- }
+ total += (size_t)read_ret;
+ }
- /* Return the number we got */
- return(nread);
+ return (ssize_t)total;
}
-/****************************************************************************
-read data from the client. Maxtime is in milliseconds
-****************************************************************************/
-int read_max_udp(int fd,char *buffer,int bufsize,int maxtime)
+SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n)
{
- fd_set fds;
- int selrtn;
- int nread;
- struct timeval timeout;
-
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
-
- timeout.tv_sec = maxtime / 1000;
- timeout.tv_usec = (maxtime % 1000) * 1000;
-
- selrtn = sys_select(&fds,maxtime>0?&timeout:NULL);
-
- if (!FD_ISSET(fd,&fds))
- return 0;
-
- nread = read_udp_socket(fd, buffer, bufsize);
-
- /* return the number got */
- return(nread);
+ return (SMB_OFF_T)transfer_file_internal(infd, outfd, (size_t)n, read, write);
}
/*******************************************************************
-find the difference in milliseconds between two struct timeval
-values
+ Sleep for a specified number of milliseconds.
********************************************************************/
-int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew)
-{
- return((tvalnew->tv_sec - tvalold->tv_sec)*1000 +
- ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000);
-}
-/****************************************************************************
-send a keepalive packet (rfc1002)
-****************************************************************************/
-BOOL send_keepalive(int client)
+void msleep(int t)
{
- unsigned char buf[4];
+ int tdiff=0;
+ struct timeval tval,t1,t2;
+ fd_set fds;
- buf[0] = 0x85;
- buf[1] = buf[2] = buf[3] = 0;
+ GetTimeOfDay(&t1);
+ GetTimeOfDay(&t2);
+
+ while (tdiff < t) {
+ tval.tv_sec = (t-tdiff)/1000;
+ tval.tv_usec = 1000*((t-tdiff)%1000);
+
+ FD_ZERO(&fds);
+ errno = 0;
+ sys_select_intr(0,&fds,&tval);
- return(write_data(client,(char *)buf,4) == 4);
+ GetTimeOfDay(&t2);
+ tdiff = TvalDiff(&t1,&t2);
+ }
}
-
-
/****************************************************************************
- read data from the client, reading exactly N bytes.
+ Become a daemon, discarding the controlling terminal.
****************************************************************************/
-int read_data(int fd,char *buffer,int N)
+
+void become_daemon(void)
{
- int ret;
- int total=0;
-
- while (total < N)
- {
- ret = read(fd,buffer + total,N - total);
+ if (sys_fork()) {
+ _exit(0);
+ }
- /* this is for portability */
- if (ret < 0)
- errno = EBADF;
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ setsid();
+#elif defined(TIOCNOTTY)
+ {
+ int i = sys_open("/dev/tty", O_RDWR, 0);
+ if (i != -1) {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif /* HAVE_SETSID */
- if (ret <= 0)
- return total;
- total += ret;
- }
- return total;
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds();
}
/****************************************************************************
- write data to a fd
+put up a yes/no prompt
****************************************************************************/
-int write_data(int fd,char *buffer,int N)
+BOOL yesno(char *p)
{
- int total=0;
- int ret;
+ pstring ans;
+ printf("%s",p);
- while (total < N)
- {
- ret = write(fd,buffer + total,N - total);
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
- if (ret <= 0)
- return total;
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
- total += ret;
- }
- return total;
+ return(False);
}
-
-/* variables used by the read prediction module */
-int rp_fd = -1;
-int rp_offset = 0;
-int rp_length = 0;
-int rp_alloced = 0;
-int rp_predict_fd = -1;
-int rp_predict_offset = 0;
-int rp_predict_length = 0;
-int rp_timeout = 5;
-time_t rp_time = 0;
-char *rp_buffer = NULL;
-BOOL predict_skip=False;
-time_t smb_last_time=(time_t)0;
-
/****************************************************************************
-handle read prediction on a file
+ Expand a pointer to be a particular size.
****************************************************************************/
-int read_predict(int fd,int offset,char *buf,char **ptr,int num)
-{
- int ret = 0;
- int possible = rp_length - (offset - rp_offset);
-
- possible = MIN(possible,num);
-
- /* give data if possible */
- if (fd == rp_fd &&
- offset >= rp_offset &&
- possible>0 &&
- smb_last_time-rp_time < rp_timeout)
- {
- ret = possible;
- if (buf)
- memcpy(buf,rp_buffer + (offset-rp_offset),possible);
- else
- *ptr = rp_buffer + (offset-rp_offset);
- DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
- }
- if (ret == num) {
- predict_skip = True;
- } else {
- predict_skip = False;
+void *Realloc(void *p,size_t size)
+{
+ void *ret=NULL;
- /* prepare the next prediction */
- rp_predict_fd = fd;
- rp_predict_offset = offset + num;
- rp_predict_length = num;
+ if (size == 0) {
+ SAFE_FREE(p);
+ DEBUG(5,("Realloc asked for 0 bytes\n"));
+ return NULL;
}
- if (ret < 0) ret = 0;
+ if (!p)
+ ret = (void *)malloc(size);
+ else
+ ret = (void *)realloc(p,size);
+
+ if (!ret)
+ DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size));
return(ret);
}
/****************************************************************************
-pre-read some data
+ Free memory, checks for NULL.
+use directly SAFE_FREE()
+exist only because we need to pass a function pointer somewhere --SSS
****************************************************************************/
-void do_read_prediction()
-{
- if (predict_skip) return;
- if (rp_predict_fd == -1)
- return;
-
- rp_fd = rp_predict_fd;
- rp_offset = rp_predict_offset;
- rp_length = 0;
-
- rp_predict_fd = -1;
-
- rp_predict_length = MIN(rp_predict_length,2*ReadSize);
- rp_predict_length = MAX(rp_predict_length,1024);
- rp_offset = (rp_offset/1024)*1024;
- rp_predict_length = (rp_predict_length/1024)*1024;
-
- if (rp_predict_length > rp_alloced)
- {
- rp_buffer = Realloc(rp_buffer,rp_predict_length);
- rp_alloced = rp_predict_length;
- if (!rp_buffer)
- {
- DEBUG(0,("can't allocate read-prediction buffer\n"));
- rp_predict_fd = -1;
- rp_fd = -1;
- rp_alloced = 0;
- return;
- }
- }
-
- if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
- rp_fd = -1;
- rp_predict_fd = -1;
- return;
- }
-
- rp_length = read(rp_fd,rp_buffer,rp_predict_length);
- rp_time = time(NULL);
- if (rp_length < 0)
- rp_length = 0;
-}
-
-/****************************************************************************
-invalidate read-prediction on a fd
-****************************************************************************/
-void invalidate_read_prediction(int fd)
+void safe_free(void *p)
{
- if (rp_fd == fd)
- rp_fd = -1;
- if (rp_predict_fd == fd)
- rp_predict_fd = -1;
+ SAFE_FREE(p);
}
-
/****************************************************************************
-transfer some data between two fd's
+ Get my own name and IP.
****************************************************************************/
-int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
-{
- static char *buf=NULL;
- char *buf1,*abuf;
- static int size = 0;
- int total = 0;
-
- DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
-
- if ((size < ReadSize) && buf) {
- free(buf);
- buf = NULL;
- }
-
- size = MAX(ReadSize,1024);
-
- while (!buf && size>0) {
- buf = (char *)Realloc(buf,size+8);
- if (!buf) size /= 2;
- }
- if (!buf) {
- DEBUG(0,("Can't allocate transfer buffer!\n"));
- exit(1);
- }
-
- abuf = buf + (align%8);
- if (header)
- n += headlen;
-
- while (n > 0)
- {
- int s = MIN(n,size);
- int ret,ret2=0;
-
- ret = 0;
-
- if (header && (headlen >= MIN(s,1024))) {
- buf1 = header;
- s = headlen;
- ret = headlen;
- headlen = 0;
- header = NULL;
- } else {
- buf1 = abuf;
- }
-
- if (header && headlen > 0)
- {
- ret = MIN(headlen,size);
- memcpy(buf1,header,ret);
- headlen -= ret;
- header += ret;
- if (headlen <= 0) header = NULL;
- }
-
- if (s > ret)
- ret += read(infd,buf1+ret,s-ret);
-
- if (ret > 0)
- {
- ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret);
- if (ret2 > 0) total += ret2;
- /* if we can't write then dump excess data */
- if (ret2 != ret)
- transfer_file(infd,-1,n-(ret+headlen),NULL,0,0);
- }
- if (ret <= 0 || ret2 != ret)
- return(total);
- n -= ret;
- }
- return(total);
-}
-
-
-/****************************************************************************
-read 4 bytes of a smb packet and return the smb length of the packet
-possibly store the result in the buffer
-****************************************************************************/
-int read_smb_length(int fd,char *inbuf,int timeout)
+BOOL get_myname(char *my_name)
{
- char *buffer;
- char buf[4];
- int len=0, msg_type;
- BOOL ok=False;
+ pstring hostname;
- if (inbuf)
- buffer = inbuf;
- else
- buffer = buf;
+ *hostname = 0;
- while (!ok)
- {
- if (timeout > 0)
- ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
- else
- ok = (read_data(fd,buffer,4) == 4);
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
- if (!ok)
- {
- if (timeout>0)
- {
- DEBUG(10,("select timeout (%d)\n", timeout));
- return(-1);
- }
- else
- {
- DEBUG(6,("couldn't read from client\n"));
- exit(1);
- }
- }
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
- len = smb_len(buffer);
- msg_type = CVAL(buffer,0);
+ if (my_name) {
+ /* split off any parts after an initial . */
+ char *p = strchr_m(hostname,'.');
- if (msg_type == 0x85)
- {
- DEBUG(5,( "Got keepalive packet\n"));
- ok = False;
+ if (p)
+ *p = 0;
+
+ fstrcpy(my_name,hostname);
}
- }
-
- DEBUG(10,("got smb length of %d\n",len));
-
- return(len);
+
+ return(True);
}
-
-
/****************************************************************************
- read an smb from a fd and return it's length
-The timeout is in milli seconds
+ Interpret a protocol description string, with a default.
****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
-{
- int len;
- BOOL ok;
-
- bzero(buffer,smb_size + 100);
-
- len = read_smb_length(fd,buffer,timeout);
- if (len == -1)
- return(False);
-
- if (len > BUFFER_SIZE)
- {
- DEBUG(0,("Invalid packet length! (%d bytes)\n",len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
- exit(1);
- }
-
- ok = (read_data(fd,buffer+4,len) == len);
-
- if (!ok)
- {
- close_sockets();
- exit(1);
- }
-
- return(True);
-}
-
-/****************************************************************************
- send an smb to a fd
-****************************************************************************/
-BOOL send_smb(int fd,char *buffer)
+int interpret_protocol(char *str,int def)
{
- int len;
- int ret,nwritten=0;
- len = smb_len(buffer) + 4;
-
- while (nwritten < len)
- {
- ret = write_socket(fd,buffer+nwritten,len - nwritten);
- if (ret <= 0)
- {
- DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret));
- close_sockets();
- exit(1);
- }
- nwritten += ret;
- }
-
-
- return True;
+ if (strequal(str,"NT1"))
+ return(PROTOCOL_NT1);
+ if (strequal(str,"LANMAN2"))
+ return(PROTOCOL_LANMAN2);
+ if (strequal(str,"LANMAN1"))
+ return(PROTOCOL_LANMAN1);
+ if (strequal(str,"CORE"))
+ return(PROTOCOL_CORE);
+ if (strequal(str,"COREPLUS"))
+ return(PROTOCOL_COREPLUS);
+ if (strequal(str,"CORE+"))
+ return(PROTOCOL_COREPLUS);
+
+ DEBUG(0,("Unrecognised protocol level %s\n",str));
+
+ return(def);
}
-
/****************************************************************************
-find a pointer to a netbios name
+ Return true if a string could be a pure IP address.
****************************************************************************/
-char *name_ptr(char *buf,int ofs)
-{
- unsigned char c = *(unsigned char *)(buf+ofs);
-
- if ((c & 0xC0) == 0xC0)
- {
- uint16 l;
- char p[2];
- memcpy(p,buf+ofs,2);
- p[0] &= ~0xC0;
- l = RSVAL(p,0);
- DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
- return(buf + l);
- }
- else
- return(buf+ofs);
-}
-/****************************************************************************
-extract a netbios name from a buf
-****************************************************************************/
-int name_extract(char *buf,int ofs,char *name)
+BOOL is_ipaddress(const char *str)
{
- char *p = name_ptr(buf,ofs);
- int d = PTR_DIFF(p,buf+ofs);
- strcpy(name,"");
- if (d < -50 || d > 50) return(0);
- return(name_interpret(p,name));
-}
+ BOOL pure_address = True;
+ int i;
+ for (i=0; pure_address && str[i]; i++)
+ if (!(isdigit((int)str[i]) || str[i] == '.'))
+ pure_address = False;
-/****************************************************************************
-return the total storage length of a mangled name
-****************************************************************************/
-int name_len(char *s)
-{
- char *s0=s;
- unsigned char c = *(unsigned char *)s;
- if ((c & 0xC0) == 0xC0)
- return(2);
- while (*s) s += (*s)+1;
- return(PTR_DIFF(s,s0)+1);
+ /* Check that a pure number is not misinterpreted as an IP */
+ pure_address = pure_address && (strchr_m(str, '.') != NULL);
+
+ return pure_address;
}
/****************************************************************************
-send a single packet to a port on another machine
+interpret an internet address or name into an IP address in 4 byte form
****************************************************************************/
-BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+
+uint32 interpret_addr(const char *str)
{
- BOOL ret;
- int out_fd;
- struct sockaddr_in sock_out;
+ struct hostent *hp;
+ uint32 res;
- if (passive)
- return(True);
+ if (strcmp(str,"0.0.0.0") == 0) return(0);
+ if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
- /* create a socket to write to */
- out_fd = socket(AF_INET, type, 0);
- if (out_fd == -1)
- {
- DEBUG(0,("socket failed"));
- return False;
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (is_ipaddress(str)) {
+ res = inet_addr(str);
+ } else {
+ /* otherwise assume it's a network name of some sort and use
+ sys_gethostbyname */
+ if ((hp = sys_gethostbyname(str)) == 0) {
+ DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str));
+ return 0;
}
+ if(hp->h_addr == NULL) {
+ DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str));
+ return 0;
+ }
+ putip((char *)&res,(char *)hp->h_addr);
+ }
- /* set the address and port */
- bzero((char *)&sock_out,sizeof(sock_out));
- putip((char *)&sock_out.sin_addr,(char *)&ip);
- sock_out.sin_port = htons( port );
- sock_out.sin_family = AF_INET;
-
- if (DEBUGLEVEL > 0)
- DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
- len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
-
- /* send it */
- ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
-
- if (!ret)
- DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
- inet_ntoa(ip),port,errno));
+ if (res == (uint32)-1) return(0);
- close(out_fd);
- return(ret);
+ return(res);
}
/*******************************************************************
-sleep for a specified number of milliseconds
-********************************************************************/
-void msleep(int t)
+ a convenient addition to interpret_addr()
+ ******************************************************************/
+struct in_addr *interpret_addr2(const char *str)
{
- int tdiff=0;
- struct timeval tval,t1,t2;
- fd_set fds;
-
- GetTimeOfDay(&t1);
- GetTimeOfDay(&t2);
-
- while (tdiff < t) {
- tval.tv_sec = (t-tdiff)/1000;
- tval.tv_usec = 1000*((t-tdiff)%1000);
-
- FD_ZERO(&fds);
- errno = 0;
- sys_select(&fds,&tval);
-
- GetTimeOfDay(&t2);
- tdiff = TvalDiff(&t1,&t2);
- }
+ static struct in_addr ret;
+ uint32 a = interpret_addr(str);
+ ret.s_addr = a;
+ return(&ret);
}
-/****************************************************************************
-check if a string is part of a list
-****************************************************************************/
-BOOL in_list(char *s,char *list,BOOL casesensitive)
+/*******************************************************************
+ check if an IP is the 0.0.0.0
+ ******************************************************************/
+BOOL is_zero_ip(struct in_addr ip)
{
- pstring tok;
- char *p=list;
-
- if (!list) return(False);
-
- while (next_token(&p,tok,LIST_SEP))
- {
- if (casesensitive) {
- if (strcmp(tok,s) == 0)
- return(True);
- } else {
- if (StrCaseCmp(tok,s) == 0)
- return(True);
- }
- }
- return(False);
+ uint32 a;
+ putip((char *)&a,(char *)&ip);
+ return(a == 0);
}
-/* this is used to prevent lots of mallocs of size 1 */
-static char *null_string = NULL;
+/* Set an IP to 0.0.0.0 */
-/****************************************************************************
-set a string value, allocing the space for the string
-****************************************************************************/
-BOOL string_init(char **dest,char *src)
+void zero_ip(struct in_addr *ip)
{
- int l;
- if (!src)
- src = "";
-
- l = strlen(src);
+ static BOOL init;
+ static struct in_addr ipzero;
- if (l == 0)
- {
- if (!null_string)
- null_string = (char *)malloc(1);
+ if (!init) {
+ ipzero = *interpret_addr2("0.0.0.0");
+ init = True;
+ }
- *null_string = 0;
- *dest = null_string;
- }
- else
- {
- *dest = (char *)malloc(l+1);
- strcpy(*dest,src);
- }
- return(True);
+ *ip = ipzero;
}
-/****************************************************************************
-free a string value
-****************************************************************************/
-void string_free(char **s)
-{
- if (!s || !(*s)) return;
- if (*s == null_string)
- *s = NULL;
- if (*s) free(*s);
- *s = NULL;
-}
+#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
+/******************************************************************
+ Remove any mount options such as -rsize=2048,wsize=2048 etc.
+ Based on a fix from <Thomas.Hepper@icem.de>.
+*******************************************************************/
-/****************************************************************************
-set a string value, allocing the space for the string, and deallocating any
-existing space
-****************************************************************************/
-BOOL string_set(char **dest,char *src)
+static void strip_mount_options( pstring *str)
{
- string_free(dest);
-
- return(string_init(dest,src));
-}
-
-/****************************************************************************
-substitute a string for a pattern in another string. Make sure there is
-enough room!
-
-This routine looks for pattern in s and replaces it with
-insert. It may do multiple replacements.
-
-return True if a substitution was done.
-****************************************************************************/
-BOOL string_sub(char *s,char *pattern,char *insert)
-{
- BOOL ret = False;
- char *p;
- int ls,lp,li;
-
- if (!insert || !pattern || !s) return(False);
-
- ls = strlen(s);
- lp = strlen(pattern);
- li = strlen(insert);
-
- if (!*pattern) return(False);
+ if (**str == '-')
+ {
+ char *p = *str;
+ while(*p && !isspace(*p))
+ p++;
+ while(*p && isspace(*p))
+ p++;
+ if(*p) {
+ pstring tmp_str;
- while (lp <= ls && (p = strstr(s,pattern)))
- {
- ret = True;
- memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
- memcpy(p,insert,li);
- s = p + li;
- ls = strlen(s);
+ pstrcpy(tmp_str, p);
+ pstrcpy(*str, tmp_str);
}
- return(ret);
+ }
}
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Split Luke's automount_server into YP lookup and string splitter
+ so can easily implement automount_path().
+ As we may end up doing both, cache the last YP result.
+*******************************************************************/
-
-/*********************************************************
-* Recursive routine that is called by mask_match.
-* Does the actual matching.
-*********************************************************/
-BOOL do_match(char *str, char *regexp, int case_sig)
+#ifdef WITH_NISPLUS_HOME
+char *automount_lookup(const char *user_name)
{
- char *p;
-
- for( p = regexp; *p && *str; ) {
- switch(*p) {
- case '?':
- str++; p++;
- break;
-
- case '*':
- /* Look for a character matching
- the one after the '*' */
- p++;
- if(!*p)
- return True; /* Automatic match */
- while(*str) {
- while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
- str++;
- if(do_match(str,p,case_sig))
- return True;
- if(!*str)
- return False;
- else
- str++;
+ static fstring last_key = "";
+ static pstring last_value = "";
+
+ char *nis_map = (char *)lp_nis_home_map_name();
+
+ char buffer[NIS_MAXATTRVAL + 1];
+ nis_result *result;
+ nis_object *object;
+ entry_obj *entry;
+
+ if (strcmp(user_name, last_key))
+ {
+ slprintf(buffer, sizeof(buffer)-1, "[key=%s],%s", user_name, nis_map);
+ DEBUG(5, ("NIS+ querystring: %s\n", buffer));
+
+ if (result = nis_list(buffer, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP, NULL, NULL))
+ {
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
+ fstrcpy(last_key, ""); pstrcpy(last_value, "");
}
- return False;
-
- default:
- if(case_sig) {
- if(*str != *p)
- return False;
- } else {
- if(toupper(*str) != toupper(*p))
- return False;
+ else
+ {
+ object = result->objects.objects_val;
+ if (object->zo_data.zo_type == ENTRY_OBJ)
+ {
+ entry = &object->zo_data.objdata_u.en_data;
+ DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type));
+ DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val));
+
+ pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
+ pstring_sub(last_value, "&", user_name);
+ fstrcpy(last_key, user_name);
+ }
}
- str++, p++;
- break;
}
+ nis_freeresult(result);
}
- if(!*p && !*str)
- return True;
- if (!*p && str[0] == '.' && str[1] == 0)
- return(True);
-
- if (!*str && *p == '?')
- {
- while (*p == '?') p++;
- return(!*p);
- }
+ strip_mount_options(&last_value);
- if(!*str && (*p == '*' && p[1] == '\0'))
- return True;
- return False;
+ DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
}
-
-
-/*********************************************************
-* Routine to match a given string with a regexp - uses
-* simplified regexp that takes * and ? only. Case can be
-* significant or not.
-*********************************************************/
-BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
+#else /* WITH_NISPLUS_HOME */
+char *automount_lookup(const char *user_name)
{
- char *p;
- pstring p1, p2;
- fstring ebase,eext,sbase,sext;
-
- BOOL matched;
+ static fstring last_key = "";
+ static pstring last_value = "";
- /* Make local copies of str and regexp */
- StrnCpy(p1,regexp,sizeof(pstring)-1);
- StrnCpy(p2,str,sizeof(pstring)-1);
+ int nis_error; /* returned by yp all functions */
+ char *nis_result; /* yp_match inits this */
+ int nis_result_len; /* and set this */
+ char *nis_domain; /* yp_get_default_domain inits this */
+ char *nis_map = (char *)lp_nis_home_map_name();
- if (!strchr(p2,'.')) {
- strcat(p2,".");
+ if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ return last_value;
}
-/*
- if (!strchr(p1,'.')) {
- strcat(p1,".");
- }
-*/
+ DEBUG(5, ("NIS Domain: %s\n", nis_domain));
-#if 0
- if (strchr(p1,'.'))
- {
- string_sub(p1,"*.*","*");
- string_sub(p1,".*","*");
- }
-#endif
-
- /* Remove any *? and ** as they are meaningless */
- for(p = p1; *p; p++)
- while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
- (void)strcpy( &p[1], &p[2]);
-
- if (strequal(p1,"*")) return(True);
+ if (!strcmp(user_name, last_key)) {
+ nis_result = last_value;
+ nis_result_len = strlen(last_value);
+ nis_error = 0;
- DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
-
- if (trans2) {
- strcpy(ebase,p1);
- strcpy(sbase,p2);
} else {
- if ((p=strrchr(p1,'.'))) {
- *p = 0;
- strcpy(ebase,p1);
- strcpy(eext,p+1);
+
+ if ((nis_error = yp_match(nis_domain, nis_map,
+ user_name, strlen(user_name),
+ &nis_result, &nis_result_len)) == 0) {
+ if (!nis_error && nis_result_len >= sizeof(pstring)) {
+ nis_result_len = sizeof(pstring)-1;
+ }
+ fstrcpy(last_key, user_name);
+ strncpy(last_value, nis_result, nis_result_len);
+ last_value[nis_result_len] = '\0';
+ strip_mount_options(&last_value);
+
+ } else if(nis_error == YPERR_KEY) {
+
+ /* If Key lookup fails user home server is not in nis_map
+ use default information for server, and home directory */
+ last_value[0] = 0;
+ DEBUG(3, ("YP Key not found: while looking up \"%s\" in map \"%s\"\n",
+ user_name, nis_map));
+ DEBUG(3, ("using defaults for server and home directory\n"));
} else {
- strcpy(ebase,p1);
- eext[0] = 0;
+ DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n",
+ yperr_string(nis_error), user_name, nis_map));
}
-
- if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
- *p = 0;
- strcpy(sbase,p2);
- strcpy(sext,p+1);
- } else {
- strcpy(sbase,p2);
- strcpy(sext,"");
}
- }
-
- matched = do_match(sbase,ebase,case_sig) &&
- (trans2 || do_match(sext,eext,case_sig));
- DEBUG(5,("mask_match returning %d\n", matched));
- return matched;
+ DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
}
+#endif /* WITH_NISPLUS_HOME */
+#endif
-
-/****************************************************************************
-become a daemon, discarding the controlling terminal
-****************************************************************************/
-void become_daemon(void)
+/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
{
-#ifndef NO_FORK_DEBUG
- if (fork())
- exit(0);
+ uint32 net1,net2,nmask;
- /* detach from the terminal */
-#ifdef USE_SETSID
- setsid();
-#else
-#ifdef TIOCNOTTY
- {
- int i = open("/dev/tty", O_RDWR);
- if (i >= 0)
- {
- ioctl(i, (int) TIOCNOTTY, (char *)0);
- close(i);
- }
- }
-#endif
-#endif
-#endif
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
}
+
/****************************************************************************
-calculate the default netmask for an address
+check if a process exists. Does this work on all unixes?
****************************************************************************/
-static void default_netmask(struct in_addr *inm, struct in_addr *iad)
+
+BOOL process_exists(pid_t pid)
{
- unsigned long ad = ntohl(iad->s_addr);
- unsigned long nm;
- /*
- ** Guess a netmask based on the class of the IP address given.
- */
- if ( (ad & 0x80000000) == 0 ) {
- /* class A address */
- nm = 0xFF000000;
- } else if ( (ad & 0xC0000000) == 0x80000000 ) {
- /* class B address */
- nm = 0xFFFF0000;
- } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
- /* class C address */
- nm = 0xFFFFFF00;
- } else {
- /* class D or E; netmask doesn't make much sense - guess 4 bits */
- nm = 0xFFFFFFF0;
- }
- inm->s_addr = htonl(nm);
+ return(kill(pid,0) == 0 || errno != ESRCH);
}
-/****************************************************************************
- get the broadcast address for our address
-(troyer@saifr00.ateng.az.honeywell.com)
-****************************************************************************/
-void get_broadcast(struct in_addr *if_ipaddr,
- struct in_addr *if_bcast,
- struct in_addr *if_nmask)
-{
- BOOL found = False;
-#ifndef NO_GET_BROADCAST
- int sock = -1; /* AF_INET raw socket desc */
- char buff[1024];
- struct ifreq *ifr=NULL;
- int i;
-#if defined(EVEREST)
- int n_interfaces;
- struct ifconf ifc;
- struct ifreq *ifreqs;
-#elif defined(USE_IFREQ)
- struct ifreq ifreq;
- struct strioctl strioctl;
- struct ifconf *ifc;
-#else
- struct ifconf ifc;
-#endif
-#endif
+/*******************************************************************
+ Convert a uid into a user name.
+********************************************************************/
- /* get a default netmask and broadcast */
- default_netmask(if_nmask, if_ipaddr);
+char *uidtoname(uid_t uid)
+{
+ static fstring name;
+ struct passwd *pass;
-#ifndef NO_GET_BROADCAST
- /* Create a socket to the INET kernel. */
-#if USE_SOCKRAW
- if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
-#else
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
-#endif
- {
- DEBUG(0,( "Unable to open socket to get broadcast address\n"));
- return;
- }
-
- /* Get a list of the configured interfaces */
-#ifdef EVEREST
- /* This is part of SCO Openserver 5: The ioctls are no longer part
- if the lower level STREAMS interface glue. They are now real
- ioctl calls */
-
- if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
- DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
- } else {
- DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
+ if (winbind_uidtoname(name, uid))
+ return name;
- ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
- ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+ pass = sys_getpwuid(uid);
+ if (pass) return(pass->pw_name);
+ slprintf(name, sizeof(name) - 1, "%d",(int)uid);
+ return(name);
+}
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
- DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
- else {
- ifr = ifc.ifc_req;
- for (i = 0; i < n_interfaces; ++i) {
- if (if_ipaddr->s_addr ==
- ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
- }
-#elif defined(USE_IFREQ)
- ifc = (struct ifconf *)buff;
- ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
- strioctl.ic_cmd = SIOCGIFCONF;
- strioctl.ic_dp = (char *)ifc;
- strioctl.ic_len = sizeof(buff);
- if (ioctl(sock, I_STR, &strioctl) < 0) {
- DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = (struct ifreq *)ifc->ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#elif defined(__FreeBSD__) || defined(NETBSD)
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
- /* Loop through interfaces, looking for given IP address */
- i = ifc.ifc_len;
- while (i > 0) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
- ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
- }
- }
-#else
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
-#ifdef BSDI
- if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
-#endif
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#endif
-
- if (!found) {
- DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
- } else {
- /* Get the netmask address from the kernel */
-#ifdef USE_IFREQ
- ifreq = *ifr;
-
- strioctl.ic_cmd = SIOCGIFNETMASK;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(sock, I_STR, &strioctl) < 0)
- DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
- else
- *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
-#else
- if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
- DEBUG(0,("SIOCGIFNETMASK failed\n"));
- else
- *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
-#endif
-
- DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name,
- inet_ntoa(*if_nmask)));
- }
+/*******************************************************************
+ Convert a gid into a group name.
+********************************************************************/
- /* Close up shop */
- (void) close(sock);
-
-#endif
+char *gidtoname(gid_t gid)
+{
+ static fstring name;
+ struct group *grp;
- /* sanity check on the netmask */
- {
- unsigned long nm = ntohl(if_nmask->s_addr);
- if ((nm >> 24) != 0xFF) {
- DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
- default_netmask(if_nmask, if_ipaddr);
- }
- }
+ if (winbind_gidtoname(name, gid))
+ return name;
- /* derive the broadcast assuming a 1's broadcast, as this is what
- all MS operating systems do, we have to comply even if the unix
- box is setup differently */
- {
- unsigned long ad = ntohl(if_ipaddr->s_addr);
- unsigned long nm = ntohl(if_nmask->s_addr);
- unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
- if_bcast->s_addr = htonl(bc);
- }
-
- DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
-} /* get_broadcast */
+ grp = getgrgid(gid);
+ if (grp) return(grp->gr_name);
+ slprintf(name,sizeof(name) - 1, "%d",(int)gid);
+ return(name);
+}
+/*******************************************************************
+ Convert a user name into a uid. If winbindd is present uses this.
+********************************************************************/
-/****************************************************************************
-put up a yes/no prompt
-****************************************************************************/
-BOOL yesno(char *p)
+uid_t nametouid(char *name)
{
- pstring ans;
- printf("%s",p);
+ struct passwd *pass;
+ char *p;
+ uid_t u;
- if (!fgets(ans,sizeof(ans)-1,stdin))
- return(False);
+ u = (uid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return u;
- if (*ans == 'y' || *ans == 'Y')
- return(True);
+ if (winbind_nametouid(&u, name))
+ return u;
- return(False);
+ pass = sys_getpwnam(name);
+ if (pass)
+ return(pass->pw_uid);
+ return (uid_t)-1;
}
-/****************************************************************************
-read a line from a file with possible \ continuation chars.
-Blanks at the start or end of a line are stripped.
-The string will be allocated if s2 is NULL
-****************************************************************************/
-char *fgets_slash(char *s2,int maxlen,FILE *f)
-{
- char *s=s2;
- int len = 0;
- int c;
- BOOL start_of_line = True;
+/*******************************************************************
+ Convert a name to a gid_t if possible. Return -1 if not a group. If winbindd
+ is present does a shortcut lookup...
+********************************************************************/
- if (feof(f))
- return(NULL);
+gid_t nametogid(const char *name)
+{
+ struct group *grp;
+ char *p;
+ gid_t g;
- if (!s2)
- {
- maxlen = MIN(maxlen,8);
- s = (char *)Realloc(s,maxlen);
- }
+ g = (gid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return g;
- if (!s || maxlen < 2) return(NULL);
+ if (winbind_nametogid(&g, name))
+ return g;
- *s = 0;
+ grp = getgrnam(name);
+ if (grp)
+ return(grp->gr_gid);
+ return (gid_t)-1;
+}
- while (len < maxlen-1)
- {
- c = getc(f);
- switch (c)
- {
- case '\r':
- break;
- case '\n':
- while (len > 0 && s[len-1] == ' ')
- {
- s[--len] = 0;
- }
- if (len > 0 && s[len-1] == '\\')
- {
- s[--len] = 0;
- start_of_line = True;
- break;
- }
- return(s);
- case EOF:
- if (len <= 0 && !s2)
- free(s);
- return(len>0?s:NULL);
- case ' ':
- if (start_of_line)
- break;
- default:
- start_of_line = False;
- s[len++] = c;
- s[len] = 0;
- }
- if (!s2 && len > maxlen-3)
- {
- maxlen *= 2;
- s = (char *)Realloc(s,maxlen);
- if (!s) return(NULL);
+/*******************************************************************
+something really nasty happened - panic!
+********************************************************************/
+void smb_panic(char *why)
+{
+ char *cmd = lp_panic_action();
+ if (cmd && *cmd) {
+ system(cmd);
}
- }
- return(s);
+ DEBUG(0,("PANIC: %s\n", why));
+ dbgflush();
+ abort();
}
-
-/****************************************************************************
-set the length of a file from a filedescriptor.
-Returns 0 on success, -1 on failure.
-****************************************************************************/
-int set_filelen(int fd, long len)
+/*******************************************************************
+a readdir wrapper which just returns the file name
+********************************************************************/
+char *readdirname(DIR *p)
{
-/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
- extend a file with ftruncate. Provide alternate implementation
- for this */
+ SMB_STRUCT_DIRENT *ptr;
+ char *dname;
-#if FTRUNCATE_CAN_EXTEND
- return ftruncate(fd, len);
-#else
- struct stat st;
- char c = 0;
- long currpos = lseek(fd, 0L, SEEK_CUR);
-
- if(currpos < 0)
- return -1;
- /* Do an fstat to see if the file is longer than
- the requested size (call ftruncate),
- or shorter, in which case seek to len - 1 and write 1
- byte of zero */
- if(fstat(fd, &st)<0)
- return -1;
-
-#ifdef S_ISFIFO
- if (S_ISFIFO(st.st_mode)) return 0;
+ if (!p) return(NULL);
+
+ ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p);
+ if (!ptr) return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0) return(NULL);
#endif
- if(st.st_size == len)
- return 0;
- if(st.st_size > len)
- return ftruncate(fd, len);
-
- if(lseek(fd, len-1, SEEK_SET) != len -1)
- return -1;
- if(write(fd, &c, 1)!=1)
- return -1;
- /* Seek to where we were */
- lseek(fd, currpos, SEEK_SET);
- return 0;
+#ifdef HAVE_BROKEN_READDIR
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
#endif
-}
+ {
+ static pstring buf;
+ int len = NAMLEN(ptr);
+ memcpy(buf, dname, len);
+ buf[len] = 0;
+ dname = buf;
+ }
-/****************************************************************************
-return the byte checksum of some data
-****************************************************************************/
-int byte_checksum(char *buf,int len)
-{
- unsigned char *p = (unsigned char *)buf;
- int ret = 0;
- while (len--)
- ret += *p++;
- return(ret);
+ return(dname);
}
+/*******************************************************************
+ Utility function used to decide if the last component
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
-
-#ifdef HPUX
-/****************************************************************************
-this is a version of setbuffer() for those machines that only have setvbuf
-****************************************************************************/
-void setbuffer(FILE *f,char *buf,int bufsize)
+BOOL is_in_path(char *name, name_compare_entry *namelist)
{
- setvbuf(f,buf,_IOFBF,bufsize);
-}
-#endif
+ pstring last_component;
+ char *p;
+ DEBUG(8, ("is_in_path: %s\n", name));
-/****************************************************************************
-parse out a directory name from a path name. Assumes dos style filenames.
-****************************************************************************/
-char *dirname_dos(char *path,char *buf)
-{
- char *p = strrchr(path,'\\');
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL)))
+ {
+ DEBUG(8,("is_in_path: no name list.\n"));
+ return False;
+ }
- if (!p)
- strcpy(buf,path);
- else
+ /* Get the last component of the unix name. */
+ p = strrchr_m(name, '/');
+ strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
+ last_component[sizeof(last_component)-1] = '\0';
+
+ for(; namelist->name != NULL; namelist++)
+ {
+ if(namelist->is_wild)
{
- *p = 0;
- strcpy(buf,path);
- *p = '\\';
+ if (mask_match(last_component, namelist->name, case_sensitive))
+ {
+ DEBUG(8,("is_in_path: mask match succeeded\n"));
+ return True;
+ }
}
-
- return(buf);
+ else
+ {
+ if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+ (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
+ {
+ DEBUG(8,("is_in_path: match succeeded\n"));
+ return True;
+ }
+ }
+ }
+ DEBUG(8,("is_in_path: match not found\n"));
+
+ return False;
}
-
-/****************************************************************************
-parse out a filename from a path name. Assumes dos style filenames.
-****************************************************************************/
-static char *filename_dos(char *path,char *buf)
+/*******************************************************************
+ Strip a '/' separated list into an array of
+ name_compare_enties structures suitable for
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
+
+void set_namearray(name_compare_entry **ppname_array, char *namelist)
{
- char *p = strrchr(path,'\\');
+ char *name_end;
+ char *nameptr = namelist;
+ int num_entries = 0;
+ int i;
- if (!p)
- strcpy(buf,path);
- else
- strcpy(buf,p+1);
+ (*ppname_array) = NULL;
- return(buf);
-}
+ if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0')))
+ return;
+ /* We need to make two passes over the string. The
+ first to count the number of elements, the second
+ to split it.
+ */
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ name_end = strchr_m(nameptr, '/');
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
-/****************************************************************************
-expand a pointer to be a particular size
-****************************************************************************/
-void *Realloc(void *p,int size)
-{
- void *ret=NULL;
- if (!p)
- ret = (void *)malloc(size);
- else
- ret = (void *)realloc(p,size);
+ /* next segment please */
+ nameptr = name_end + 1;
+ num_entries++;
+ }
- if (!ret)
- DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size));
+ if(num_entries == 0)
+ return;
- return(ret);
-}
+ if(( (*ppname_array) = (name_compare_entry *)malloc(
+ (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail\n"));
+ return;
+ }
+
+ /* Now copy out the names */
+ nameptr = namelist;
+ i = 0;
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ if ((name_end = strchr_m(nameptr, '/')) != NULL)
+ {
+ *name_end = 0;
+ }
-/****************************************************************************
-set the time on a file
-****************************************************************************/
-BOOL set_filetime(char *fname,time_t mtime)
-{
- struct utimbuf times;
+ /* oops - the last check for a / didn't find one. */
+ if(name_end == NULL)
+ break;
- if (null_mtime(mtime)) return(True);
+ (*ppname_array)[i].is_wild = ms_has_wild(nameptr);
+ if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail (1)\n"));
+ return;
+ }
- times.modtime = times.actime = mtime;
+ /* next segment please */
+ nameptr = name_end + 1;
+ i++;
+ }
+
+ (*ppname_array)[i].name = NULL;
- if (sys_utime(fname,&times)) {
- DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
- }
-
- return(True);
+ return;
}
-
-#ifdef NOSTRDUP
/****************************************************************************
-duplicate a string
+routine to free a namearray.
****************************************************************************/
-char *strdup(char *s)
-{
- char *ret = NULL;
- if (!s) return(NULL);
- ret = (char *)malloc(strlen(s)+1);
- if (!ret) return(NULL);
- strcpy(ret,s);
- return(ret);
-}
-#endif
-
-/****************************************************************************
- Signal handler for SIGPIPE (write on a disconnected socket)
-****************************************************************************/
-void Abort(void )
+void free_namearray(name_compare_entry *name_array)
{
- DEBUG(0,("Probably got SIGPIPE\nExiting\n"));
- exit(2);
-}
-
+ if(name_array == NULL)
+ return;
-#ifdef REPLACE_STRLEN
-/****************************************************************************
-a replacement strlen() that returns int for solaris
-****************************************************************************/
-int Strlen(char *s)
-{
- int ret=0;
- if (!s) return(0);
- while (*s++) ret++;
- return(ret);
+ SAFE_FREE(name_array->name);
+ SAFE_FREE(name_array);
}
-#endif
-
/****************************************************************************
-return a time at the start of the current month
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
****************************************************************************/
-time_t start_of_month(void)
-{
- time_t t = time(NULL);
- struct tm *t2;
-
- t2 = gmtime(&t);
-
- t2->tm_mday = 1;
- t2->tm_hour = 0;
- t2->tm_min = 0;
- t2->tm_sec = 0;
-
- return(mktime(t2));
-}
-
-/*******************************************************************
- check for a sane unix date
-********************************************************************/
-BOOL sane_unix_date(time_t unixdate)
+BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
- struct tm t,today;
- time_t t_today = time(NULL);
-
- t = *(LocalTime(&unixdate,LOCAL_TO_GMT));
- today = *(LocalTime(&t_today,LOCAL_TO_GMT));
-
- if (t.tm_year < 80)
- return(False);
-
- if (t.tm_year > today.tm_year)
- return(False);
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon > today.tm_mon)
- return(False);
-
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon == today.tm_mon &&
- t.tm_mday > (today.tm_mday+1))
- return(False);
-
- return(True);
-}
-
-
-
-#ifdef NO_FTRUNCATE
- /*******************************************************************
-ftruncate for operating systems that don't have it
-********************************************************************/
-int ftruncate(int f,long l)
-{
- struct flock fl;
-
- fl.l_whence = 0;
- fl.l_len = 0;
- fl.l_start = l;
- fl.l_type = F_WRLCK;
- return fcntl(f, F_FREESP, &fl);
-}
-#endif
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+ DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = offset;
+ lock.l_len = count;
+ lock.l_pid = 0;
-/****************************************************************************
-get my own name and IP
-****************************************************************************/
-BOOL get_myname(char *myname,struct in_addr *ip)
-{
- struct hostent *hp;
- pstring hostname;
+ errno = 0;
- *hostname = 0;
+ ret = fcntl(fd,op,&lock);
- /* get my host name */
- if (gethostname(hostname, MAXHOSTNAMELEN) == -1)
- {
- DEBUG(0,("gethostname failed\n"));
- return False;
- }
+ if (errno != 0)
+ DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
- /* get host info */
- if ((hp = Get_Hostbyname(hostname)) == 0)
+ /* a lock query */
+ if (op == SMB_F_GETLK)
+ {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != sys_getpid()))
{
- DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
- return False;
+ DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
+ return(True);
}
- if (myname)
- {
- /* split off any parts after an initial . */
- char *p = strchr(hostname,'.');
- if (p) *p = 0;
+ /* it must be not locked or locked by me */
+ return(False);
+ }
- strcpy(myname,hostname);
- }
+ /* a lock set or unset */
+ if (ret == -1)
+ {
+ DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+ return(False);
+ }
- if (ip)
- putip((char *)ip,(char *)hp->h_addr);
+ /* everything went OK */
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
return(True);
}
-
-/****************************************************************************
-true if two IP addresses are equal
-****************************************************************************/
-BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long a1,a2;
- a1 = ntohl(ip1.s_addr);
- a2 = ntohl(ip2.s_addr);
- return(a1 == a2);
-}
-
-
-/****************************************************************************
-open a socket of the specified type, port and address for incoming data
-****************************************************************************/
-int open_socket_in(int type, int port, int dlevel)
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
{
- struct hostent *hp;
- struct sockaddr_in sock;
- pstring host_name;
- int res;
-
- /* get my host name */
-#ifdef MAXHOSTNAMELEN
- if (gethostname(host_name, MAXHOSTNAMELEN) == -1)
-#else
- if (gethostname(host_name, sizeof(host_name)) == -1)
-#endif
- { DEBUG(0,("gethostname failed\n")); return -1; }
-
- /* get host info */
- if ((hp = Get_Hostbyname(host_name)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name));
- return -1;
- }
-
- bzero((char *)&sock,sizeof(sock));
- memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
-#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */
- sock.sin_len = sizeof(sock);
-#endif
- sock.sin_port = htons( port );
- sock.sin_family = hp->h_addrtype;
- sock.sin_addr.s_addr = INADDR_ANY;
- res = socket(hp->h_addrtype, type, 0);
- if (res == -1)
- { DEBUG(0,("socket failed\n")); return -1; }
+ int n;
+ BOOL ret = False;
- {
- int one=1;
- setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
+ for (n=0; my_netbios_names[n]; n++) {
+ if (strequal(my_netbios_names[n], s))
+ ret=True;
}
+ DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+ return(ret);
+}
- /* now we've got a socket - we need to bind it */
- if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0)
- {
- if (port) {
- if (port == 139 || port == 137)
- DEBUG(dlevel,("bind failed on port %d (%s)\n",
- port,strerror(errno)));
- close(res);
-
- if (dlevel > 0 && port < 1000)
- port = 7999;
-
- if (port >= 1000 && port < 9000)
- return(open_socket_in(type,port+1,dlevel));
- }
+BOOL is_myname_or_ipaddr(char *s)
+{
+ char **ptr;
+
+ /* optimize for the common case */
+ if (strequal(s, global_myname))
+ return True;
- return(-1);
- }
- DEBUG(3,("bind succeeded on port %d\n",port));
+ /* maybe its an IP address? */
+ if (is_ipaddress(s))
+ {
+ struct iface_struct nics[MAX_INTERFACES];
+ int i, n;
+ uint32 ip;
+
+ ip = interpret_addr(s);
+ if ((ip==0) || (ip==0xffffffff))
+ return False;
+
+ n = get_interfaces(nics, MAX_INTERFACES);
+ for (i=0; i<n; i++) {
+ if (ip == nics[i].ip.s_addr)
+ return True;
+ }
+ }
+
+ /* check for an alias */
+ ptr = lp_netbios_aliases();
+ for ( ; *ptr; ptr++ )
+ {
+ if (StrCaseCmp(s, *ptr) == 0)
+ return True;
+ }
+
+
+ /* no match */
+ return False;
- return res;
}
-/****************************************************************************
- create an outgoing socket
- **************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port )
+/*******************************************************************
+set the horrid remote_arch string based on an enum.
+********************************************************************/
+void set_remote_arch(enum remote_arch_types type)
{
- struct sockaddr_in sock_out;
- int res;
-
- /* create a socket to write to */
- res = socket(PF_INET, type, 0);
- if (res == -1)
- { DEBUG(0,("socket error\n")); return -1; }
-
- if (type != SOCK_STREAM) return(res);
-
- bzero((char *)&sock_out,sizeof(sock_out));
- putip((char *)&sock_out.sin_addr,(char *)addr);
-
- sock_out.sin_port = htons( port );
- sock_out.sin_family = PF_INET;
-
- DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
-
- /* and connect it to the destination */
- if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) {
- DEBUG(0,("connect error: %s\n",strerror(errno)));
- close(res);
- return(-1);
+ extern fstring remote_arch;
+ ra_type = type;
+ switch( type )
+ {
+ case RA_WFWG:
+ fstrcpy(remote_arch, "WfWg");
+ return;
+ case RA_OS2:
+ fstrcpy(remote_arch, "OS2");
+ return;
+ case RA_WIN95:
+ fstrcpy(remote_arch, "Win95");
+ return;
+ case RA_WINNT:
+ fstrcpy(remote_arch, "WinNT");
+ return;
+ case RA_WIN2K:
+ fstrcpy(remote_arch, "Win2K");
+ return;
+ case RA_SAMBA:
+ fstrcpy(remote_arch,"Samba");
+ return;
+ default:
+ ra_type = RA_UNKNOWN;
+ fstrcpy(remote_arch, "UNKNOWN");
+ break;
}
+}
- return res;
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch(void)
+{
+ return ra_type;
}
-/****************************************************************************
-interpret a protocol description string, with a default
-****************************************************************************/
-int interpret_protocol(char *str,int def)
+void out_ascii(FILE *f, unsigned char *buf,int len)
{
- if (strequal(str,"NT1"))
- return(PROTOCOL_NT1);
- if (strequal(str,"LANMAN2"))
- return(PROTOCOL_LANMAN2);
- if (strequal(str,"LANMAN1"))
- return(PROTOCOL_LANMAN1);
- if (strequal(str,"CORE"))
- return(PROTOCOL_CORE);
- if (strequal(str,"COREPLUS"))
- return(PROTOCOL_COREPLUS);
- if (strequal(str,"CORE+"))
- return(PROTOCOL_COREPLUS);
-
- DEBUG(0,("Unrecognised protocol level %s\n",str));
-
- return(def);
+ int i;
+ for (i=0;i<len;i++)
+ {
+ fprintf(f, "%c", isprint(buf[i])?buf[i]:'.');
+ }
}
-/****************************************************************************
-interpret a security level
-****************************************************************************/
-int interpret_security(char *str,int def)
+void out_data(FILE *f,char *buf1,int len, int per_line)
{
- if (strequal(str,"SERVER"))
- return(SEC_SERVER);
- if (strequal(str,"USER"))
- return(SEC_USER);
- if (strequal(str,"SHARE"))
- return(SEC_SHARE);
-
- DEBUG(0,("Unrecognised security level %s\n",str));
-
- return(def);
-}
+ unsigned char *buf = (unsigned char *)buf1;
+ int i=0;
+ if (len<=0)
+ {
+ return;
+ }
+ fprintf(f, "[%03X] ",i);
+ for (i=0;i<len;)
+ {
+ fprintf(f, "%02X ",(int)buf[i]);
+ i++;
+ if (i%(per_line/2) == 0) fprintf(f, " ");
+ if (i%per_line == 0)
+ {
+ out_ascii(f,&buf[i-per_line ],per_line/2); fprintf(f, " ");
+ out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n");
+ if (i<len) fprintf(f, "[%03X] ",i);
+ }
+ }
+ if ((i%per_line) != 0)
+ {
+ int n;
+
+ n = per_line - (i%per_line);
+ fprintf(f, " ");
+ if (n>(per_line/2)) fprintf(f, " ");
+ while (n--)
+ {
+ fprintf(f, " ");
+ }
+ n = MIN(per_line/2,i%per_line);
+ out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " ");
+ n = (i%per_line) - n;
+ if (n>0) out_ascii(f,&buf[i-n],n);
+ fprintf(f, "\n");
+ }
+}
-/****************************************************************************
-interpret an internet address or name into an IP address in 4 byte form
-****************************************************************************/
-unsigned long interpret_addr(char *str)
+void print_asc(int level, const unsigned char *buf,int len)
{
- struct hostent *hp;
- unsigned long res;
+ int i;
+ for (i=0;i<len;i++)
+ DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
- if (strcmp(str,"0.0.0.0") == 0) return(0);
- if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
+void dump_data(int level, const char *buf1,int len)
+{
+ const unsigned char *buf = (const unsigned char *)buf1;
+ int i=0;
+ if (len<=0) return;
- /* if it's in the form of an IP address then get the lib to interpret it */
- if (isdigit(str[0])) {
- res = inet_addr(str);
- } else {
- /* otherwise assume it's a network name of some sort and use Get_Hostbyname */
- if ((hp = Get_Hostbyname(str)) == 0) {
- DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
- return 0;
+ DEBUG(level,("[%03X] ",i));
+ for (i=0;i<len;) {
+ DEBUG(level,("%02X ",(int)buf[i]));
+ i++;
+ if (i%8 == 0) DEBUG(level,(" "));
+ if (i%16 == 0) {
+ print_asc(level,&buf[i-16],8); DEBUG(level,(" "));
+ print_asc(level,&buf[i-8],8); DEBUG(level,("\n"));
+ if (i<len) DEBUG(level,("[%03X] ",i));
}
- putip((char *)&res,(char *)hp->h_addr);
}
-
- if (res == (unsigned long)-1) return(0);
-
- return(res);
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ DEBUG(level,(" "));
+ if (n>8) DEBUG(level,(" "));
+ while (n--) DEBUG(level,(" "));
+
+ n = MIN(8,i%16);
+ print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" "));
+ n = (i%16) - n;
+ if (n>0) print_asc(level,&buf[i-n],n);
+ DEBUG(level,("\n"));
+ }
}
-/*******************************************************************
- a convenient addition to interpret_addr()
- ******************************************************************/
-struct in_addr *interpret_addr2(char *str)
+char *tab_depth(int depth)
{
- static struct in_addr ret;
- unsigned long a = interpret_addr(str);
- putip((char *)&ret,(char *)&a);
- return(&ret);
+ static pstring spaces;
+ memset(spaces, ' ', depth * 4);
+ spaces[depth * 4] = 0;
+ return spaces;
}
-/*******************************************************************
- check if an IP is the 0.0.0.0
- ******************************************************************/
-BOOL zero_ip(struct in_addr ip)
+/*****************************************************************************
+ * Provide a checksum on a string
+ *
+ * Input: s - the null-terminated character string for which the checksum
+ * will be calculated.
+ *
+ * Output: The checksum value calculated for s.
+ *
+ * ****************************************************************************
+ */
+int str_checksum(const char *s)
{
- unsigned long a;
- putip((char *)&a,(char *)&ip);
- return(a == 0);
-}
+ int res = 0;
+ int c;
+ int i=0;
+
+ while(*s) {
+ c = *s;
+ res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
+ s++;
+ i++;
+ }
+ return(res);
+} /* str_checksum */
-#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
-/****************************************************************************
-interpret an 8 byte "filetime" structure to a time_t
-It's originally in "100ns units since jan 1st 1601"
-It appears to be kludge-GMT (at least for file listings). This means
-its the GMT you get by taking a localtime and adding the
-serverzone. This is NOT the same as GMT in some cases. This routine
-converts this to real GMT.
-****************************************************************************/
-time_t interpret_long_date(char *p)
+/*****************************************************************
+zero a memory area then free it. Used to catch bugs faster
+*****************************************************************/
+void zero_free(void *p, size_t size)
{
- double d;
- time_t ret;
- uint32 tlow,thigh;
- tlow = IVAL(p,0);
- thigh = IVAL(p,4);
-
- if (thigh == 0) return(0);
-
- d = ((double)thigh)*4.0*(double)(1<<30);
- d += (tlow&0xFFF00000);
- d *= 1.0e-7;
-
- /* now adjust by 369 years to make the secs since 1970 */
- d -= TIME_FIXUP_CONSTANT;
-
- if (d>=MAXINT)
- return(0);
-
- ret = (time_t)(d+0.5);
-
- /* this takes us from kludge-GMT to real GMT */
- ret += TimeDiff(ret) - serverzone;
-
- return(ret);
+ memset(p, 0, size);
+ SAFE_FREE(p);
}
-/****************************************************************************
-put a 8 byte filetime from a time_t
-This takes real GMT as input and converts to kludge-GMT
-****************************************************************************/
-void put_long_date(char *p,time_t t)
+/*****************************************************************
+set our open file limit to a requested max and return the limit
+*****************************************************************/
+int set_maxfiles(int requested_max)
{
- uint32 tlow,thigh;
- double d;
-
- if (t==0) {
- SIVAL(p,0,0); SIVAL(p,4,0);
- return;
- }
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ struct rlimit rlp;
+ int saved_current_limit;
- /* this converts GMT to kludge-GMT */
- t -= TimeDiff(t) - serverzone;
-
- d = (double) (t);
-
- d += TIME_FIXUP_CONSTANT;
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return requested_max;
+ }
- d *= 1.0e7;
+ /*
+ * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
+ * account for the extra fd we need
+ * as well as the log files and standard
+ * handles etc. Save the limit we want to set in case
+ * we are running on an OS that doesn't support this limit (AIX)
+ * which always returns RLIM_INFINITY for rlp.rlim_max.
+ */
- thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
- tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+ /* Try raising the hard (max) limit to the requested amount. */
- SIVAL(p,0,tlow);
- SIVAL(p,4,thigh);
-}
+#if defined(RLIM_INFINITY)
+ if (rlp.rlim_max != RLIM_INFINITY) {
+ int orig_max = rlp.rlim_max;
-/*******************************************************************
-sub strings with useful parameters
-********************************************************************/
-void standard_sub_basic(char *s)
-{
- if (!strchr(s,'%')) return;
+ if ( rlp.rlim_max < requested_max )
+ rlp.rlim_max = requested_max;
- string_sub(s,"%R",remote_proto);
- string_sub(s,"%a",remote_arch);
- string_sub(s,"%m",remote_machine);
- string_sub(s,"%L",local_machine);
+ /* This failing is not an error - many systems (Linux) don't
+ support our default request of 10,000 open files. JRA. */
- if (!strchr(s,'%')) return;
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(3,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d max files failed with error %s\n",
+ (int)rlp.rlim_max, strerror(errno) ));
- string_sub(s,"%v",VERSION);
- string_sub(s,"%h",myhostname);
- string_sub(s,"%U",sesssetup_user);
-
- if (!strchr(s,'%')) return;
+ /* Set failed - restore original value from get. */
+ rlp.rlim_max = orig_max;
+ }
+ }
+#endif
- string_sub(s,"%I",Client_info.addr);
- string_sub(s,"%M",Client_info.name);
- string_sub(s,"%T",timestring());
+ /* Now try setting the soft (current) limit. */
- if (!strchr(s,'%')) return;
+ saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max);
- {
- char pidstr[10];
- sprintf(pidstr,"%d",(int)getpid());
- string_sub(s,"%d",pidstr);
- }
-
- if (!strchr(s,'%')) return;
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n",
+ (int)rlp.rlim_cur, strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
+ }
- {
- struct passwd *pass = Get_Pwnam(sesssetup_user,False);
- if (pass) {
- string_sub(s,"%G",gidtoname(pass->pw_gid));
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
}
- }
-}
-
-
-/*******************************************************************
-write a string in unicoode format
-********************************************************************/
-int PutUniCode(char *dst,char *src)
-{
- int ret = 0;
- while (*src) {
- dst[ret++] = src[0];
- dst[ret++] = 0;
- src++;
- }
- dst[ret++]=0;
- dst[ret++]=0;
- return(ret);
-}
-
-
-pstring smbrun_path = SMBRUN;
-/****************************************************************************
-run a command via system() using smbrun
-****************************************************************************/
-int smbrun(char *cmd,char *outfile)
-{
- int ret;
- pstring syscmd;
-
- if (!file_exist(smbrun_path,NULL))
- {
- DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path));
- return(1);
- }
+#if defined(RLIM_INFINITY)
+ if(rlp.rlim_cur == RLIM_INFINITY)
+ return saved_current_limit;
+#endif
- sprintf(syscmd,"%s \"(%s 2>&1) > %s\"",
- smbrun_path,cmd,
- outfile?outfile:"/dev/null");
+ if((int)rlp.rlim_cur > saved_current_limit)
+ return saved_current_limit;
- DEBUG(5,("smbrun - running %s ",syscmd));
- ret = system(syscmd);
- DEBUG(5,("gave %d\n",ret));
- return(ret);
+ return rlp.rlim_cur;
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+ /*
+ * No way to know - just guess...
+ */
+ return requested_max;
+#endif
}
-
-/****************************************************************************
-a wrapper for gethostbyname() that tries with all lower and all upper case
-if the initial name fails
-****************************************************************************/
-struct hostent *Get_Hostbyname(char *name)
+/*****************************************************************
+ splits out the start of the key (HKLM or HKU) and the rest of the key
+ *****************************************************************/
+BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name)
{
- char *name2 = strdup(name);
- struct hostent *ret;
+ pstring tmp;
- if (!name2)
- {
- DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n"));
- exit(0);
- }
+ if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp)))
+ {
+ return False;
+ }
- if (!isalnum(*name2))
- {
- free(name2);
- return(NULL);
- }
+ (*reg_type) = 0;
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
+ DEBUG(10, ("reg_split_key: hive %s\n", tmp));
- /* try with all lowercase */
- strlower(name2);
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
+ if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE"))
+ {
+ (*reg_type) = HKEY_LOCAL_MACHINE;
+ }
+ else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS"))
+ {
+ (*reg_type) = HKEY_USERS;
+ }
+ else
+ {
+ DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp));
+ return False;
+ }
+
+ if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp)))
+ {
+ fstrcpy(key_name, tmp);
+ }
+ else
+ {
+ key_name[0] = 0;
+ }
- /* try with all uppercase */
- strupper(name2);
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
-
- /* nothing works :-( */
- free(name2);
- return(NULL);
+ DEBUG(10, ("reg_split_key: name %s\n", key_name));
+
+ return True;
}
-/****************************************************************************
-check if a process exists. Does this work on all unixes?
-****************************************************************************/
-BOOL process_exists(int pid)
+/*****************************************************************
+possibly replace mkstemp if it is broken
+*****************************************************************/
+int smb_mkstemp(char *template)
{
-#ifdef LINUX
- fstring s;
- sprintf(s,"/proc/%d",pid);
- return(directory_exist(s,NULL));
+#if HAVE_SECURE_MKSTEMP
+ return mkstemp(template);
#else
- {
- static BOOL tested=False;
- static BOOL ok=False;
- fstring s;
- if (!tested) {
- tested = True;
- sprintf(s,"/proc/%05d",getpid());
- ok = file_exist(s,NULL);
- }
- if (ok) {
- sprintf(s,"/proc/%05d",pid);
- return(file_exist(s,NULL));
- }
- }
-
- /* a best guess for non root access */
- if (geteuid() != 0) return(True);
-
- /* otherwise use kill */
- return(pid == getpid() || kill(pid,0) == 0);
+ /* have a reasonable go at emulating it. Hope that
+ the system mktemp() isn't completly hopeless */
+ char *p = mktemp(template);
+ if (!p) return -1;
+ return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
#endif
}
-/*******************************************************************
-turn a uid into a user name
-********************************************************************/
-char *uidtoname(int uid)
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+void *smb_xmalloc(size_t size)
{
- static char name[40];
- struct passwd *pass = getpwuid(uid);
- if (pass) return(pass->pw_name);
- sprintf(name,"%d",uid);
- return(name);
+ void *p;
+ if (size == 0)
+ smb_panic("smb_xmalloc: called with zero size.\n");
+ if ((p = malloc(size)) == NULL)
+ smb_panic("smb_xmalloc: malloc fail.\n");
+ return p;
}
-/*******************************************************************
-turn a gid into a group name
-********************************************************************/
-char *gidtoname(int gid)
+/**
+ Memdup with smb_panic on fail.
+**/
+void *smb_xmemdup(const void *p, size_t size)
{
- static char name[40];
- struct group *grp = getgrgid(gid);
- if (grp) return(grp->gr_name);
- sprintf(name,"%d",gid);
- return(name);
+ void *p2;
+ p2 = smb_xmalloc(size);
+ memcpy(p2, p, size);
+ return p2;
}
-/*******************************************************************
-block sigs
-********************************************************************/
-void BlockSignals(BOOL block)
+/**
+ strdup that aborts on malloc fail.
+**/
+char *smb_xstrdup(const char *s)
{
-#ifdef USE_SIGBLOCK
- int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV)
- |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)|
- sigmask(SIGINT));
- if (block)
- sigblock(block_mask);
- else
- sigunblock(block_mask);
-#endif
+ char *s1 = strdup(s);
+ if (!s1)
+ smb_panic("smb_xstrdup: malloc fail\n");
+ return s1;
}
-#if AJT
-/*******************************************************************
-my own panic function - not suitable for general use
-********************************************************************/
-void ajt_panic(void)
+/*
+ vasprintf that aborts on malloc fail
+*/
+int smb_xvasprintf(char **ptr, const char *format, va_list ap)
{
- pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &";
- smbrun(cmd,NULL);
+ int n;
+ n = vasprintf(ptr, format, ap);
+ if (n == -1 || ! *ptr) {
+ smb_panic("smb_xvasprintf: out of memory");
+ }
+ return n;
}
-#endif
-#ifdef USE_DIRECT
-#define DIRECT direct
-#else
-#define DIRECT dirent
-#endif
-
-/*******************************************************************
-a readdir wrapper which just returns the file name
-also return the inode number if requested
-********************************************************************/
-char *readdirname(void *p)
+/*****************************************************************
+like strdup but for memory
+ *****************************************************************/
+void *memdup(const void *p, size_t size)
{
- struct DIRECT *ptr;
- char *dname;
-
- if (!p) return(NULL);
-
- ptr = (struct DIRECT *)readdir(p);
- if (!ptr) return(NULL);
+ void *p2;
+ if (size == 0) return NULL;
+ p2 = malloc(size);
+ if (!p2) return NULL;
+ memcpy(p2, p, size);
+ return p2;
+}
- dname = ptr->d_name;
+/*****************************************************************
+get local hostname and cache result
+ *****************************************************************/
+char *myhostname(void)
+{
+ static pstring ret;
+ if (ret[0] == 0) {
+ get_myname(ret);
+ }
+ return ret;
+}
-#ifdef KANJI
- {
- static pstring buf;
- strcpy(buf, dname);
- unix_to_dos(buf, True);
- dname = buf;
- }
-#endif
-#ifdef NEXT2
- if (telldir(p) < 0) return(NULL);
-#endif
+/*****************************************************************
+a useful function for returning a path in the Samba lock directory
+ *****************************************************************/
+char *lock_path(char *name)
+{
+ static pstring fname;
-#ifdef SUNOS5
- /* this handles a broken compiler setup, causing a mixture
- of BSD and SYSV headers and libraries */
- {
- static BOOL broken_readdir = False;
- if (!broken_readdir && !(*(dname)) && strequal("..",dname-2))
- {
- DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n"));
- broken_readdir = True;
- }
- if (broken_readdir)
- return(dname-2);
- }
-#endif
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,"","/");
+
+ if (!directory_exist(fname,NULL)) {
+ mkdir(fname,0755);
+ }
+
+ pstrcat(fname,"/");
+ pstrcat(fname,name);
- return(dname);
+ return fname;
}
-
-#if (defined(SecureWare) && defined(SCO))
-/* This is needed due to needing the nap() function but we don't want
- to include the Xenix libraries since that will break other things...
- BTW: system call # 0x0c28 is the same as calling nap() */
-long nap(long milliseconds) {
- return syscall(0x0c28, milliseconds);
+/**
+ * @brief Returns an absolute path to a file in the Samba lib directory.
+ *
+ * @param name File to find, relative to LIBDIR.
+ *
+ * @retval Pointer to a static #pstring containing the full path.
+ **/
+char *lib_path(char *name)
+{
+ static pstring fname;
+ snprintf(fname, sizeof(fname), "%s/%s", dyn_LIBDIR, name);
+ return fname;
}
-#endif
-
-#ifdef NO_INITGROUPS
-#include <sys/types.h>
-#include <limits.h>
-#include <grp.h>
-#ifndef NULL
-#define NULL (void *)0
-#endif
+/*******************************************************************
+ Given a filename - get its directory name
+ NB: Returned in static storage. Caveats:
+ o Not safe in thread environment.
+ o Caller must not free.
+ o If caller wishes to preserve, they should copy.
+********************************************************************/
-/****************************************************************************
- some systems don't have an initgroups call
-****************************************************************************/
-int initgroups(char *name,gid_t id)
+char *parent_dirname(const char *path)
{
-#ifdef NO_SETGROUPS
- /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
- return(0);
-#else
- gid_t grouplst[NGROUPS_MAX];
- int i,j;
- struct group *g;
- char *gr;
-
- grouplst[0] = id;
- i = 1;
- while (i < NGROUPS_MAX &&
- ((g = (struct group *)getgrent()) != (struct group *)NULL))
- {
- if (g->gr_gid == id)
- continue;
- j = 0;
- gr = g->gr_mem[0];
- while (gr && (*gr != (char)NULL)) {
- if (strcmp(name,gr) == 0) {
- grouplst[i] = g->gr_gid;
- i++;
- gr = (char *)NULL;
- break;
- }
- gr = g->gr_mem[++j];
- }
- }
- endgrent();
- return(setgroups(i,grouplst));
-#endif
-}
-#endif
+ static pstring dirpath;
+ char *p;
+ if (!path)
+ return(NULL);
-#if WRAP_MALLOC
+ pstrcpy(dirpath, path);
+ p = strrchr_m(dirpath, '/'); /* Find final '/', if any */
+ if (!p) {
+ pstrcpy(dirpath, "."); /* No final "/", so dir is "." */
+ } else {
+ if (p == dirpath)
+ ++p; /* For root "/", leave "/" in place */
+ *p = '\0';
+ }
+ return dirpath;
+}
-/* undo the wrapping temporarily */
-#undef malloc
-#undef realloc
-#undef free
-/****************************************************************************
-wrapper for malloc() to catch memory errors
-****************************************************************************/
-void *malloc_wrapped(int size,char *file,int line)
+/*******************************************************************
+determine if a pattern contains any Microsoft wildcard characters
+ *******************************************************************/
+BOOL ms_has_wild(char *s)
{
-#ifdef xx_old_malloc
- void *res = xx_old_malloc(size);
-#else
- void *res = malloc(size);
-#endif
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
+ char c;
+ while ((c = *s++)) {
+ switch (c) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return True;
+ }
+ }
+ return False;
}
-/****************************************************************************
-wrapper for realloc() to catch memory errors
-****************************************************************************/
-void *realloc_wrapped(void *ptr,int size,char *file,int line)
+BOOL ms_has_wild_w(const smb_ucs2_t *s)
{
-#ifdef xx_old_realloc
- void *res = xx_old_realloc(ptr,size);
-#else
- void *res = realloc(ptr,size);
-#endif
- DEBUG(3,("Realloc\n"));
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,
- (unsigned int)ptr));
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
+ smb_ucs2_t c;
+ while ((c = *s++)) {
+ switch (c) {
+ case UCS2_CHAR('*'):
+ case UCS2_CHAR('?'):
+ case UCS2_CHAR('<'):
+ case UCS2_CHAR('>'):
+ case UCS2_CHAR('"'):
+ return True;
+ }
+ }
+ return False;
}
-/****************************************************************************
-wrapper for free() to catch memory errors
-****************************************************************************/
-void free_wrapped(void *ptr,char *file,int line)
+/*******************************************************************
+ a wrapper that handles case sensitivity and the special handling
+ of the ".." name
+ *******************************************************************/
+BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive)
{
-#ifdef xx_old_free
- xx_old_free(ptr);
-#else
- free(ptr);
-#endif
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,(unsigned int)ptr));
- return;
+ fstring p2, s2;
+
+ if (strcmp(string,"..") == 0) string = ".";
+ if (strcmp(pattern,".") == 0) return False;
+
+ if (is_case_sensitive) {
+ return ms_fnmatch(pattern, string, Protocol) == 0;
+ }
+
+ fstrcpy(p2, pattern);
+ fstrcpy(s2, string);
+ strlower(p2);
+ strlower(s2);
+ return ms_fnmatch(p2, s2, Protocol) == 0;
}
-/* and re-do the define for spots lower in this file */
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
-#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
-#endif
+static BOOL unix_do_match(char *regexp, char *str)
+{
+ char *p;
+
+ for( p = regexp; *p && *str; ) {
+
+ switch(*p) {
+ case '?':
+ str++;
+ p++;
+ break;
+
+ case '*':
+
+ /*
+ * Look for a character matching
+ * the one after the '*'.
+ */
+ p++;
+ if(!*p)
+ return True; /* Automatic match */
+ while(*str) {
+
+ while(*str && (*p != *str))
+ str++;
+
+ /*
+ * Patch from weidel@multichart.de. In the case of the regexp
+ * '*XX*' we want to ensure there are at least 2 'X' characters
+ * in the string after the '*' for a match to be made.
+ */
+
+ {
+ int matchcount=0;
+
+ /*
+ * Eat all the characters that match, but count how many there were.
+ */
+
+ while(*str && (*p == *str)) {
+ str++;
+ matchcount++;
+ }
+
+ /*
+ * Now check that if the regexp had n identical characters that
+ * matchcount had at least that many matches.
+ */
+
+ while ( *(p+1) && (*(p+1) == *p)) {
+ p++;
+ matchcount--;
+ }
+
+ if ( matchcount <= 0 )
+ return False;
+ }
+
+ str--; /* We've eaten the match char after the '*' */
+
+ if(unix_do_match(p, str))
+ return True;
+
+ if(!*str)
+ return False;
+ else
+ str++;
+ }
+ return False;
+
+ default:
+ if(*str != *p)
+ return False;
+ str++;
+ p++;
+ break;
+ }
+ }
-#ifdef REPLACE_STRSTR
-/****************************************************************************
-Mips version of strstr doesn't seem to work correctly.
-There is a #define in includes.h to redirect calls to this function.
-****************************************************************************/
-char *Strstr(char *s, char *p)
-{
- int len = strlen(p);
+ if(!*p && !*str)
+ return True;
- while ( *s != '\0' ) {
- if ( strncmp(s, p, len) == 0 )
- return s;
- s++;
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return(True);
+
+ if (!*str && *p == '?') {
+ while (*p == '?')
+ p++;
+ return(!*p);
}
- return NULL;
-}
-#endif /* REPLACE_STRSTR */
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return True;
+ return False;
+}
-#ifdef REPLACE_MKTIME
/*******************************************************************
-a mktime() replacement for those who don't have it - contributed by
-C.A. Lademann <cal@zls.com>
-********************************************************************/
-#define MINUTE 60
-#define HOUR 60*MINUTE
-#define DAY 24*HOUR
-#define YEAR 365*DAY
-time_t Mktime(struct tm *t)
+ Simple case insensitive interface to a UNIX wildcard matcher.
+*******************************************************************/
+
+BOOL unix_wild_match(char *pattern, char *string)
{
- struct tm *u;
- time_t epoch = 0;
- int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- y, m, i;
-
- if(t->tm_year < 70)
- return((time_t)-1);
-
- epoch = (t->tm_year - 70) * YEAR +
- (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
-
- y = t->tm_year;
- m = 0;
-
- for(i = 0; i < t->tm_mon; i++) {
- epoch += mon [m] * DAY;
- if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
- epoch += DAY;
-
- if(++m > 11) {
- m = 0;
- y++;
- }
- }
+ pstring p2, s2;
+ char *p;
- epoch += (t->tm_mday - 1) * DAY;
- epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
-
- if((u = localtime(&epoch)) != NULL) {
- t->tm_sec = u->tm_sec;
- t->tm_min = u->tm_min;
- t->tm_hour = u->tm_hour;
- t->tm_mday = u->tm_mday;
- t->tm_mon = u->tm_mon;
- t->tm_year = u->tm_year;
- t->tm_wday = u->tm_wday;
- t->tm_yday = u->tm_yday;
- t->tm_isdst = u->tm_isdst;
-#ifndef NO_TM_NAME
- memcpy(t->tm_name, u->tm_name, LTZNMAX);
-#endif
- }
+ pstrcpy(p2, pattern);
+ pstrcpy(s2, string);
+ strlower(p2);
+ strlower(s2);
- return(epoch);
+ /* Remove any *? and ** from the pattern as they are meaningless */
+ for(p = p2; *p; p++)
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
+ pstrcpy( &p[1], &p[2]);
+
+ if (strequal(p2,"*"))
+ return True;
+
+ return unix_do_match(p2, s2) == 0;
}
-#endif /* REPLACE_MKTIME */
+/*******************************************************************
+ construct a data blob, must be freed with data_blob_free()
+*******************************************************************/
+DATA_BLOB data_blob(const void *p, size_t length)
+{
+ DATA_BLOB ret;
+ if (!p || !length) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
-#ifdef REPLACE_RENAME
-/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
- const char *zfrom;
- const char *zto;
-{
- if (link (zfrom, zto) < 0)
- {
- if (errno != EEXIST)
- return -1;
- if (unlink (zto) < 0
- || link (zfrom, zto) < 0)
- return -1;
- }
- return unlink (zfrom);
+ ret.data = smb_xmemdup(p, length);
+ ret.length = length;
+ return ret;
}
-#endif
+/*******************************************************************
+free a data blob
+*******************************************************************/
+void data_blob_free(DATA_BLOB *d)
+{
+ SAFE_FREE(d->data);
+}
-#ifdef REPLACE_INNETGR
-/*
- * Search for a match in a netgroup. This replaces it on broken systems.
- */
-int InNetGr(group, host, user, dom)
- char *group, *host, *user, *dom;
+/*******************************************************************
+free a data blob and clear its contents
+*******************************************************************/
+void data_blob_clear_free(DATA_BLOB *d)
{
- char *hst, *usr, *dm;
-
- setnetgrent(group);
- while (getnetgrent(&hst, &usr, &dm))
- if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
- ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
- ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
- endnetgrent();
- return (1);
- }
- endnetgrent();
- return (0);
+ if (d->data) {
+ memset(d->data, 0, d->length);
+ }
+ data_blob_free(d);
}
-#endif
+#ifdef __INSURE__
-#if WRAP_MEMCPY
-#undef memcpy
/*******************************************************************
-a wrapper around memcpy for diagnostic purposes
+This routine is a trick to immediately catch errors when debugging
+with insure. A xterm with a gdb is popped up when insure catches
+a error. It is Linux specific.
********************************************************************/
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
-{
- if (l>64 && (((int)d)%4) != (((int)s)%4))
- DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
-#ifdef xx_old_memcpy
- return(xx_old_memcpy(d,s,l));
-#else
- return(memcpy(d,s,l));
-#endif
-}
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-#endif
+int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
+{
+ static int (*fn)();
+ int ret;
+ char pidstr[10];
+ /* you can get /usr/bin/backtrace from
+ http://samba.org/ftp/unpacked/junkcode/backtrace */
+ pstring cmd = "/usr/bin/backtrace %d";
+
+ slprintf(pidstr, sizeof(pidstr)-1, "%d", sys_getpid());
+ pstring_sub(cmd, "%d", pidstr);
+
+ if (!fn) {
+ static void *h;
+ h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
+ fn = dlsym(h, "_Insure_trap_error");
+ }
+ ret = fn(a1, a2, a3, a4, a5, a6);
+ system(cmd);
+ return ret;
+}
+#endif
diff --git a/source/lib/util_file.c b/source/lib/util_file.c
new file mode 100644
index 00000000000..0cd60fed268
--- /dev/null
+++ b/source/lib/util_file.c
@@ -0,0 +1,594 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+static int gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ Lock or unlock a fd for a known lock type. Abandon after waitsecs
+ seconds.
+****************************************************************/
+
+BOOL do_file_lock(int fd, int waitsecs, int type)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ lock.l_pid = 0;
+
+ alarm(waitsecs);
+ ret = fcntl(fd, SMB_F_SETLKW, &lock);
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm) {
+ DEBUG(0, ("do_file_lock: failed to %s file.\n",
+ type == F_UNLCK ? "unlock" : "lock"));
+ return False;
+ }
+
+ return (ret == 0);
+}
+
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+BOOL file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ (*plock_depth)++;
+
+ if ((*plock_depth) == 0)
+ {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+BOOL file_unlock(int fd, int *plock_depth)
+{
+ BOOL ret=True;
+
+ if(*plock_depth == 1)
+ ret = do_file_lock(fd, 5, F_UNLCK);
+
+ (*plock_depth)--;
+
+ if(!ret)
+ DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+/***************************************************************
+ locks a file for enumeration / modification.
+ update to be set = True if modification is required.
+****************************************************************/
+
+void *startfilepwent(char *pfile, char *s_readbuf, int bufsize,
+ int *file_lock_depth, BOOL update)
+{
+ FILE *fp = NULL;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("startfilepwent: No file set\n"));
+ return (NULL);
+ }
+ DEBUG(10, ("startfilepwent: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, update ? "r+b" : "rb");
+
+ if (fp == NULL) {
+ DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, s_readbuf, _IOFBF, bufsize);
+
+ if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth))
+ {
+ DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return NULL;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a lock on the file. */
+ return (void *)fp;
+}
+
+/***************************************************************
+ End enumeration of the file.
+****************************************************************/
+void endfilepwent(void *vp, int *file_lock_depth)
+{
+ FILE *fp = (FILE *)vp;
+
+ file_unlock(fileno(fp), file_lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endfilepwent: closed file.\n"));
+}
+
+/*************************************************************************
+ Return the current position in the file list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+SMB_BIG_UINT getfilepwpos(void *vp)
+{
+ return (SMB_BIG_UINT)sys_ftell((FILE *)vp);
+}
+
+/*************************************************************************
+ Set the current position in the file list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET);
+}
+
+/*************************************************************************
+ gets a line out of a file.
+ line is of format "xxxx:xxxxxx:xxxxx:".
+ lines with "#" at the front are ignored.
+*************************************************************************/
+int getfileline(void *vp, char *linebuf, int linebuf_size)
+{
+ /* Static buffers we will return. */
+ FILE *fp = (FILE *)vp;
+ unsigned char c;
+ unsigned char *p;
+ size_t linebuf_len;
+
+ if (fp == NULL)
+ {
+ DEBUG(0,("getfileline: Bad file pointer.\n"));
+ return -1;
+ }
+
+ /*
+ * Scan the file, a line at a time.
+ */
+ while (!feof(fp))
+ {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, linebuf_size, fp);
+ if (ferror(fp))
+ {
+ return -1;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+
+ linebuf_len = strlen(linebuf);
+ if (linebuf_len == 0)
+ {
+ linebuf[0] = '\0';
+ return 0;
+ }
+
+ if (linebuf[linebuf_len - 1] != '\n')
+ {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp))
+ {
+ c = fgetc(fp);
+ if (c == '\n')
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getfileline: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp))
+ {
+ DEBUG(4, ("getfileline: end of file reached\n"));
+ return 0;
+ }
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ {
+ DEBUG(6, ("getfileline: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getfileline: malformed line entry (no :)\n"));
+ continue;
+ }
+ return linebuf_len;
+ }
+ return -1;
+}
+
+
+/****************************************************************************
+read a line from a file with possible \ continuation chars.
+Blanks at the start or end of a line are stripped.
+The string will be allocated if s2 is NULL
+****************************************************************************/
+char *fgets_slash(char *s2,int maxlen,XFILE *f)
+{
+ char *s=s2;
+ int len = 0;
+ int c;
+ BOOL start_of_line = True;
+
+ if (x_feof(f))
+ return(NULL);
+
+ if (maxlen <2) return(NULL);
+
+ if (!s2)
+ {
+ maxlen = MIN(maxlen,8);
+ s = (char *)malloc(maxlen);
+ }
+
+ if (!s) return(NULL);
+
+ *s = 0;
+
+ while (len < maxlen-1)
+ {
+ c = x_getc(f);
+ switch (c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ')
+ {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\')
+ {
+ s[--len] = 0;
+ start_of_line = True;
+ break;
+ }
+ return(s);
+ case EOF:
+ if (len <= 0 && !s2)
+ SAFE_FREE(s);
+ return(len>0?s:NULL);
+ case ' ':
+ if (start_of_line)
+ break;
+ default:
+ start_of_line = False;
+ s[len++] = c;
+ s[len] = 0;
+ }
+ if (!s2 && len > maxlen-3)
+ {
+ char *t;
+
+ maxlen *= 2;
+ t = (char *)Realloc(s,maxlen);
+ if (!t) {
+ DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
+ SAFE_FREE(s);
+ return(NULL);
+ } else s = t;
+ }
+ }
+ return(s);
+}
+
+
+/****************************************************************************
+load from a pipe into memory
+****************************************************************************/
+char *file_pload(char *syscmd, size_t *size)
+{
+ int fd, n;
+ char *p, *tp;
+ pstring buf;
+ size_t total;
+
+ fd = sys_popen(syscmd);
+ if (fd == -1) return NULL;
+
+ p = NULL;
+ total = 0;
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ tp = Realloc(p, total + n + 1);
+ if (!tp) {
+ DEBUG(0,("file_pload: failed to exand buffer!\n"));
+ close(fd);
+ SAFE_FREE(p);
+ return NULL;
+ } else p = tp;
+ memcpy(p+total, buf, n);
+ total += n;
+ }
+ if (p) p[total] = 0;
+
+ sys_pclose(fd);
+
+ if (size) *size = total;
+
+ return p;
+}
+
+/****************************************************************************
+load a file into memory from a fd.
+****************************************************************************/
+
+char *fd_load(int fd, size_t *size)
+{
+ SMB_STRUCT_STAT sbuf;
+ char *p;
+
+ if (sys_fstat(fd, &sbuf) != 0) return NULL;
+
+ p = (char *)malloc(sbuf.st_size+1);
+ if (!p) return NULL;
+
+ if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ p[sbuf.st_size] = 0;
+
+ if (size) *size = sbuf.st_size;
+
+ return p;
+}
+
+/****************************************************************************
+load a file into memory
+****************************************************************************/
+char *file_load(const char *fname, size_t *size)
+{
+ int fd;
+ char *p;
+
+ if (!fname || !*fname) return NULL;
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) return NULL;
+
+ p = fd_load(fd, size);
+
+ close(fd);
+
+ return p;
+}
+
+
+/*******************************************************************
+mmap (if possible) or read a file
+********************************************************************/
+void *map_file(char *fname, size_t size)
+{
+ size_t s2 = 0;
+ void *p = NULL;
+#ifdef HAVE_MMAP
+ if (lp_use_mmap()) {
+ int fd;
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == -1) {
+ DEBUG(1,("Failed to load %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
+ close(fd);
+ if (p == MAP_FAILED) {
+ DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ }
+#endif
+ if (!p) {
+ p = file_load(fname, &s2);
+ if (!p || s2 != size) {
+ DEBUG(1,("incorrect size for %s - got %d expected %d\n",
+ fname, s2, size));
+ if (p) free(p);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+
+/****************************************************************************
+parse a buffer into lines
+****************************************************************************/
+static char **file_lines_parse(char *p, size_t size, int *numlines)
+{
+ int i;
+ char *s, **ret;
+
+ if (!p) return NULL;
+
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') i++;
+ }
+
+ ret = (char **)malloc(sizeof(ret[0])*(i+2));
+ if (!ret) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(ret[0])*(i+2));
+ if (numlines) *numlines = i;
+
+ ret[0] = p;
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') {
+ s[0] = 0;
+ i++;
+ ret[i] = s+1;
+ }
+ if (s[0] == '\r') s[0] = 0;
+ }
+
+ return ret;
+}
+
+
+/****************************************************************************
+load a file into memory and return an array of pointers to lines in the file
+must be freed with file_lines_free().
+****************************************************************************/
+char **file_lines_load(const char *fname, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = file_load(fname, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with file_lines_free(). If convert is true calls unix_to_dos on
+the list.
+****************************************************************************/
+char **fd_lines_load(int fd, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = fd_load(fd, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+
+/****************************************************************************
+load a pipe into memory and return an array of pointers to lines in the data
+must be freed with file_lines_free().
+****************************************************************************/
+char **file_lines_pload(char *syscmd, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = file_pload(syscmd, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+free lines loaded with file_lines_load
+****************************************************************************/
+void file_lines_free(char **lines)
+{
+ if (!lines) return;
+ SAFE_FREE(lines[0]);
+ SAFE_FREE(lines);
+}
+
+
+/****************************************************************************
+take a lislist of lines and modify them to produce a list where \ continues
+a line
+****************************************************************************/
+void file_lines_slashcont(char **lines)
+{
+ int i, j;
+
+ for (i=0; lines[i];) {
+ int len = strlen(lines[i]);
+ if (lines[i][len-1] == '\\') {
+ lines[i][len-1] = ' ';
+ if (lines[i+1]) {
+ char *p = &lines[i][len];
+ while (p < lines[i+1]) *p++ = ' ';
+ for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
+ }
+ } else {
+ i++;
+ }
+ }
+}
+
+/*
+ save a lump of data into a file. Mostly used for debugging
+*/
+BOOL file_save(const char *fname, void *packet, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ return False;
+ }
+ if (write(fd, packet, length) != length) {
+ return False;
+ }
+ close(fd);
+ return True;
+}
diff --git a/source/lib/util_getent.c b/source/lib/util_getent.c
new file mode 100644
index 00000000000..81b36effcb4
--- /dev/null
+++ b/source/lib/util_getent.c
@@ -0,0 +1,313 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba utility functions
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if 0
+static void print_grent_list(struct sys_grent *glist)
+{
+ DEBUG(100, ("print_grent_list: %x\n", glist ));
+ while (glist) {
+ DEBUG(100,("glist: %x ", glist));
+ if (glist->gr_name)
+ DEBUG(100,(": gr_name = (%x) %s ", glist->gr_name, glist->gr_name));
+ if (glist->gr_passwd)
+ DEBUG(100,(": gr_passwd = (%x) %s ", glist->gr_passwd, glist->gr_passwd));
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ DEBUG(100,(" : gr_mem[%d] = (%x) %s ", i, glist->gr_mem[i], glist->gr_mem[i]));
+ }
+ DEBUG(100,(": gr_next = %x\n", glist->next ));
+ glist = glist->next;
+ }
+ DEBUG(100,("FINISHED !\n\n"));
+}
+#endif
+
+/****************************************************************
+ Returns a single linked list of group entries.
+ Use grent_free() to free it after use.
+****************************************************************/
+
+struct sys_grent * getgrent_list(void)
+{
+ struct sys_grent *glist;
+ struct sys_grent *gent;
+ struct group *grp;
+
+ gent = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent == NULL) {
+ DEBUG (0, ("Out of memory in getgrent_list!\n"));
+ return NULL;
+ }
+ memset(gent, '\0', sizeof(struct sys_grent));
+ glist = gent;
+
+ setgrent();
+ grp = getgrent();
+ if (grp == NULL) {
+ endgrent();
+ SAFE_FREE(glist);
+ return NULL;
+ }
+
+ while (grp != NULL) {
+ int i,num;
+
+ if (grp->gr_name) {
+ if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
+ goto err;
+ }
+ if (grp->gr_passwd) {
+ if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
+ goto err;
+ }
+ gent->gr_gid = grp->gr_gid;
+
+ /* number of strings in gr_mem */
+ for (num = 0; grp->gr_mem[num]; num++)
+ ;
+
+ /* alloc space for gr_mem string pointers */
+ if ((gent->gr_mem = (char **) malloc((num+1) * sizeof(char *))) == NULL)
+ goto err;
+
+ memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
+
+ for (i=0; i < num; i++) {
+ if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
+ goto err;
+ }
+ gent->gr_mem[num] = NULL;
+
+ grp = getgrent();
+ if (grp) {
+ gent->next = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent->next == NULL)
+ goto err;
+ gent = gent->next;
+ memset(gent, '\0', sizeof(struct sys_grent));
+ }
+ }
+
+ endgrent();
+ return glist;
+
+ err:
+
+ endgrent();
+ DEBUG(0, ("Out of memory in getgrent_list!\n"));
+ grent_free(glist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of group entries made by
+ getgrent_list()
+****************************************************************/
+
+void grent_free (struct sys_grent *glist)
+{
+ while (glist) {
+ struct sys_grent *prev;
+
+ SAFE_FREE(glist->gr_name);
+ SAFE_FREE(glist->gr_passwd);
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ SAFE_FREE(glist->gr_mem[i]);
+ SAFE_FREE(glist->gr_mem);
+ }
+ prev = glist;
+ glist = glist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Returns a single linked list of passwd entries.
+ Use pwent_free() to free it after use.
+****************************************************************/
+
+struct sys_pwent * getpwent_list(void)
+{
+ struct sys_pwent *plist;
+ struct sys_pwent *pent;
+ struct passwd *pwd;
+
+ pent = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent == NULL) {
+ DEBUG (0, ("Out of memory in getpwent_list!\n"));
+ return NULL;
+ }
+ plist = pent;
+
+ setpwent();
+ pwd = getpwent();
+ while (pwd != NULL) {
+ memset(pent, '\0', sizeof(struct sys_pwent));
+ if (pwd->pw_name) {
+ if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_passwd) {
+ if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
+ goto err;
+ }
+ pent->pw_uid = pwd->pw_uid;
+ pent->pw_gid = pwd->pw_gid;
+ if (pwd->pw_gecos) {
+ if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_dir) {
+ if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_shell) {
+ if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
+ goto err;
+ }
+
+ pwd = getpwent();
+ if (pwd) {
+ pent->next = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent->next == NULL)
+ goto err;
+ pent = pent->next;
+ }
+ }
+
+ endpwent();
+ return plist;
+
+ err:
+
+ endpwent();
+ DEBUG(0, ("Out of memory in getpwent_list!\n"));
+ pwent_free(plist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of passwd entries made by
+ getpwent_list()
+****************************************************************/
+
+void pwent_free (struct sys_pwent *plist)
+{
+ while (plist) {
+ struct sys_pwent *prev;
+
+ SAFE_FREE(plist->pw_name);
+ SAFE_FREE(plist->pw_passwd);
+ SAFE_FREE(plist->pw_gecos);
+ SAFE_FREE(plist->pw_dir);
+ SAFE_FREE(plist->pw_shell);
+
+ prev = plist;
+ plist = plist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Add the individual group users onto the list.
+****************************************************************/
+
+static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
+{
+ size_t num_users, i;
+
+ /* Count the number of users. */
+ for (num_users = 0; grp->gr_mem[num_users]; num_users++)
+ ;
+
+ for (i = 0; i < num_users; i++) {
+ struct sys_userlist *entry = (struct sys_userlist *)malloc(sizeof(*entry));
+ size_t len = strlen(grp->gr_mem[i])+1;
+ if (entry == NULL) {
+ free_userlist(list_head);
+ return NULL;
+ }
+ entry->unix_name = (char *)malloc(len);
+ if (entry->unix_name == NULL) {
+ SAFE_FREE(entry);
+ free_userlist(list_head);
+ return NULL;
+ }
+ safe_strcpy(entry->unix_name, grp->gr_mem[i],len);
+ DLIST_ADD(list_head, entry);
+ }
+ return list_head;
+}
+
+/****************************************************************
+ Get the list of UNIX users in a group.
+ We have to enumerate the /etc/group file as some UNIX getgrnam()
+ calls won't do that for us (notably Tru64 UNIX).
+****************************************************************/
+
+struct sys_userlist *get_users_in_group(const char *gname)
+{
+ struct sys_userlist *list_head = NULL;
+ struct group *gptr;
+
+ /*
+ * If we're doing this via winbindd, don't do the
+ * entire group list enumeration as we know this is
+ * pointless (and slow).
+ */
+
+ if (strchr(gname,*lp_winbind_separator())) {
+ if ((gptr = (struct group *)getgrnam(gname)) == NULL)
+ return NULL;
+ return add_members_to_userlist(list_head, gptr);
+ }
+
+ setgrent();
+ while((gptr = getgrent()) != NULL) {
+ if (strequal(gname, gptr->gr_name)) {
+ list_head = add_members_to_userlist(list_head, gptr);
+ if (list_head == NULL)
+ return NULL;
+ }
+ }
+ endgrent();
+ return list_head;
+}
+
+/****************************************************************
+ Free list allocated above.
+****************************************************************/
+
+void free_userlist(struct sys_userlist *list_head)
+{
+ while (list_head) {
+ struct sys_userlist *old_head = list_head;
+ DLIST_REMOVE(list_head, list_head);
+ SAFE_FREE(old_head->unix_name);
+ SAFE_FREE(old_head);
+ }
+}
diff --git a/source/lib/util_seaccess.c b/source/lib/util_seaccess.c
new file mode 100644
index 00000000000..1ff7c329572
--- /dev/null
+++ b/source/lib/util_seaccess.c
@@ -0,0 +1,422 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
+ Copyright (C) Tim Potter 2000.
+ Copyright (C) Re-written by Jeremy Allison 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "nterr.h"
+#include "sids.h"
+
+/**********************************************************************************
+ Check if this ACE has a SID in common with the token.
+**********************************************************************************/
+
+static BOOL token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
+{
+ size_t i;
+
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&ace->trustee, &token->user_sids[i]))
+ return True;
+ }
+
+ return False;
+}
+
+/*********************************************************************************
+ Check an ACE against a SID. We return the remaining needed permission
+ bits not yet granted. Zero means permission allowed (no more needed bits).
+**********************************************************************************/
+
+static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired,
+ NTSTATUS *status)
+{
+ uint32 mask = ace->info.mask;
+
+ /*
+ * Inherit only is ignored.
+ */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ return acc_desired;
+ }
+
+ /*
+ * If this ACE has no SID in common with the token,
+ * ignore it as it cannot be used to make an access
+ * determination.
+ */
+
+ if (!token_sid_in_ace( token, ace))
+ return acc_desired;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ /*
+ * This is explicitly allowed.
+ * Remove the bits from the remaining
+ * access required. Return the remaining
+ * bits needed.
+ */
+ acc_desired &= ~mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ /*
+ * This is explicitly denied.
+ * If any bits match terminate here,
+ * we are denied.
+ */
+ if (acc_desired & mask) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ return 0xFFFFFFFF;
+ }
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ return 0xFFFFFFFF;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ return 0xFFFFFFFF;
+ }
+
+ return acc_desired;
+}
+
+/*********************************************************************************
+ Maximum access was requested. Calculate the max possible. Fail if it doesn't
+ include other bits requested.
+**********************************************************************************/
+
+static BOOL get_max_access( SEC_ACL *the_acl, NT_USER_TOKEN *token, uint32 *granted,
+ uint32 desired,
+ NTSTATUS *status)
+{
+ uint32 acc_denied = 0;
+ uint32 acc_granted = 0;
+ size_t i;
+
+ for ( i = 0 ; i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+ uint32 mask = ace->info.mask;
+
+ if (!token_sid_in_ace( token, ace))
+ continue;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ acc_granted |= (mask & ~acc_denied);
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ acc_denied |= (mask & ~acc_granted);
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ *granted = 0;
+ return False;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ *granted = 0;
+ return False;
+ }
+ }
+
+ /*
+ * If we were granted no access, or we desired bits that we
+ * didn't get, then deny.
+ */
+
+ if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ *granted = 0;
+ return False;
+ }
+
+ /*
+ * Return the access we did get.
+ */
+
+ *granted = acc_granted;
+ *status = NT_STATUS_OK;
+ return True;
+}
+
+/* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping)
+{
+ uint32 old_mask = *access_mask;
+
+ if (*access_mask & GENERIC_READ_ACCESS) {
+ *access_mask &= ~GENERIC_READ_ACCESS;
+ *access_mask |= mapping->generic_read;
+ }
+
+ if (*access_mask & GENERIC_WRITE_ACCESS) {
+ *access_mask &= ~GENERIC_WRITE_ACCESS;
+ *access_mask |= mapping->generic_write;
+ }
+
+ if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+ *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+ *access_mask |= mapping->generic_execute;
+ }
+
+ if (*access_mask & GENERIC_ALL_ACCESS) {
+ *access_mask &= ~GENERIC_ALL_ACCESS;
+ *access_mask |= mapping->generic_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/*****************************************************************************
+ Check access rights of a user against a security descriptor. Look at
+ each ACE in the security descriptor until an access denied ACE denies
+ any of the desired rights to the user or any of the users groups, or one
+ or more ACEs explicitly grant all requested access rights. See
+ "Access-Checking" document in MSDN.
+*****************************************************************************/
+
+BOOL se_access_check(SEC_DESC *sd, NT_USER_TOKEN *token,
+ uint32 acc_desired, uint32 *acc_granted,
+ NTSTATUS *status)
+{
+ extern NT_USER_TOKEN anonymous_token;
+ size_t i;
+ SEC_ACL *the_acl;
+ fstring sid_str;
+ uint32 tmp_acc_desired = acc_desired;
+
+ if (!status || !acc_granted)
+ return False;
+
+ if (!token)
+ token = &anonymous_token;
+
+ *status = NT_STATUS_OK;
+ *acc_granted = 0;
+
+ DEBUG(10,("se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s.\n",
+ (unsigned int)acc_desired, (unsigned int)token->num_sids,
+ sid_to_string(sid_str, &token->user_sids[0])));
+
+ /*
+ * No security descriptor or security descriptor with no DACL
+ * present allows all access.
+ */
+
+ /* ACL must have something in it */
+
+ if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
+ *status = NT_STATUS_OK;
+ *acc_granted = acc_desired;
+ DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
+ return True;
+ }
+
+ /* The user sid is the first in the token */
+
+ DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[PRIMARY_USER_SID_INDEX]) ));
+
+ for (i = 1; i < token->num_sids; i++) {
+ DEBUG(3, ("se_access_check: also %s\n",
+ sid_to_string(sid_str, &token->user_sids[i])));
+ }
+
+ /* Is the token the owner of the SID ? */
+
+ if (sd->owner_sid) {
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
+ /*
+ * The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL.
+ */
+ if (tmp_acc_desired & WRITE_DAC_ACCESS)
+ tmp_acc_desired &= ~WRITE_DAC_ACCESS;
+ if (tmp_acc_desired & READ_CONTROL_ACCESS)
+ tmp_acc_desired &= ~READ_CONTROL_ACCESS;
+ }
+ }
+ }
+
+ the_acl = sd->dacl;
+
+ if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
+ tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
+ return get_max_access( the_acl, token, acc_granted, tmp_acc_desired,
+ status);
+ }
+
+ for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+
+ DEBUG(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n",
+ (unsigned int)i, ace->type, ace->flags,
+ sid_to_string(sid_str, &ace->trustee),
+ (unsigned int) ace->info.mask,
+ (unsigned int)tmp_acc_desired ));
+
+ tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
+ if (NT_STATUS_V(*status)) {
+ *acc_granted = 0;
+ DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, get_nt_error_msg(*status)));
+ return False;
+ }
+ }
+
+ /*
+ * If there are no more desired permissions left then
+ * access was allowed.
+ */
+
+ if (tmp_acc_desired == 0) {
+ *acc_granted = acc_desired;
+ *status = NT_STATUS_OK;
+ DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
+ return True;
+ }
+
+ *acc_granted = 0;
+ *status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
+ return False;
+}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
+ BOOL child_container)
+{
+ SEC_DESC_BUF *sdb;
+ SEC_DESC *sd;
+ SEC_ACL *new_dacl, *the_acl;
+ SEC_ACE *new_ace_list = NULL;
+ int new_ace_list_ndx = 0, i;
+ size_t size;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ the_acl = parent_ctr->dacl;
+
+ if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces)))
+ return NULL;
+
+ for (i = 0; the_acl && i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+ SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
+ uint8 new_flags = 0;
+ BOOL inherit = False;
+ fstring sid_str;
+
+ /* The OBJECT_INHERIT_ACE flag causes the ACE to be
+ inherited by non-container children objects. Container
+ children objects will inherit it as an INHERIT_ONLY
+ ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+
+ if (!child_container) {
+ new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
+ } else {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ inherit = True;
+ }
+
+ /* The CONAINER_INHERIT_ACE flag means all child container
+ objects will inherit and use the ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (!child_container) {
+ inherit = False;
+ } else {
+ new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
+ }
+ }
+
+ /* The INHERIT_ONLY_ACE is not used by the se_access_check()
+ function for the parent container, but is inherited by
+ all child objects as a normal ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ /* Move along, nothing to see here */
+ }
+
+ /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
+ is inherited by child objects but not grandchildren
+ objects. We clear the object inherit and container
+ inherit flags in the inherited ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ /* Add ACE to ACE list */
+
+ if (!inherit)
+ continue;
+
+ init_sec_access(&new_ace->info, ace->info.mask);
+ init_sec_ace(new_ace, &ace->trustee, ace->type,
+ new_ace->info, new_flags);
+
+ sid_to_string(sid_str, &ace->trustee);
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
+ ace->type, ace->flags, ace->info.mask,
+ sid_str, new_ace->type, new_ace->flags,
+ new_ace->info.mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /* Create child security descriptor to return */
+
+ new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
+
+ /* Use the existing user and group sids. I don't think this is
+ correct. Perhaps the user and group should be passed in as
+ parameters by the caller? */
+
+ sd = make_sec_desc(ctx, SEC_DESC_REVISION,
+ parent_ctr->owner_sid,
+ parent_ctr->grp_sid,
+ parent_ctr->sacl,
+ new_dacl, &size);
+
+ sdb = make_sec_desc_buf(ctx, size, sd);
+
+ return sdb;
+}
diff --git a/source/lib/util_sec.c b/source/lib/util_sec.c
new file mode 100644
index 00000000000..c559647bf45
--- /dev/null
+++ b/source/lib/util_sec.c
@@ -0,0 +1,423 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ Copyright (C) Jeremy Allison 1998.
+ rewritten for version 2.0.6 by Tridge
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef AUTOCONF_TEST
+#include "includes.h"
+#else
+/* we are running this code in autoconf test mode to see which type of setuid
+ function works */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#define DEBUG(x, y) printf y
+#define smb_panic(x) exit(1)
+#define BOOL int
+#endif
+
+/* are we running as non-root? This is used by the regresison test code,
+ and potentially also for sites that want non-root smbd */
+static uid_t initial_uid;
+static gid_t initial_gid;
+
+/****************************************************************************
+remember what uid we got started as - this allows us to run correctly
+as non-root while catching trapdoor systems
+****************************************************************************/
+void sec_init(void)
+{
+ initial_uid = geteuid();
+ initial_gid = getegid();
+}
+
+/****************************************************************************
+some code (eg. winbindd) needs to know what uid we started as
+****************************************************************************/
+uid_t sec_initial_uid(void)
+{
+ return initial_uid;
+}
+
+/****************************************************************************
+some code (eg. winbindd, profiling shm) needs to know what gid we started as
+****************************************************************************/
+gid_t sec_initial_gid(void)
+{
+ return initial_gid;
+}
+
+/****************************************************************************
+are we running in non-root mode?
+****************************************************************************/
+BOOL non_root_mode(void)
+{
+ return (initial_uid != (uid_t)0);
+}
+
+/****************************************************************************
+abort if we haven't set the uid correctly
+****************************************************************************/
+static void assert_uid(uid_t ruid, uid_t euid)
+{
+ if ((euid != (uid_t)-1 && geteuid() != euid) ||
+ (ruid != (uid_t)-1 && getuid() != ruid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
+ (int)ruid, (int)euid,
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set uid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+abort if we haven't set the gid correctly
+****************************************************************************/
+static void assert_gid(gid_t rgid, gid_t egid)
+{
+ if ((egid != (gid_t)-1 && getegid() != egid) ||
+ (rgid != (gid_t)-1 && getgid() != rgid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
+ (int)rgid, (int)egid,
+ (int)getgid(), (int)getegid(),
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set gid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+ Gain root privilege before doing something.
+ We want to end up with ruid==euid==0
+****************************************************************************/
+void gain_root_privilege(void)
+{
+#if USE_SETRESUID
+ setresuid(0,0,0);
+#endif
+
+#if USE_SETEUID
+ seteuid(0);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, 0);
+ setuidx(ID_REAL, 0);
+#endif
+
+ /* this is needed on some systems */
+ setuid(0);
+
+ assert_uid(0, 0);
+}
+
+
+/****************************************************************************
+ Ensure our real and effective groups are zero.
+ we want to end up with rgid==egid==0
+****************************************************************************/
+void gain_root_group_privilege(void)
+{
+#if USE_SETRESUID
+ setresgid(0,0,0);
+#endif
+
+#if USE_SETREUID
+ setregid(0,0);
+#endif
+
+#if USE_SETEUID
+ setegid(0);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, 0);
+ setgidx(ID_REAL, 0);
+#endif
+
+ setgid(0);
+
+ assert_gid(0, 0);
+}
+
+
+/****************************************************************************
+ Set *only* the effective uid.
+ we want to end up with ruid==0 and euid==uid
+****************************************************************************/
+void set_effective_uid(uid_t uid)
+{
+#if USE_SETRESUID
+ setresuid(-1,uid,-1);
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,uid);
+#endif
+
+#if USE_SETEUID
+ seteuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, uid);
+#endif
+
+ assert_uid(-1, uid);
+}
+
+/****************************************************************************
+ Set *only* the effective gid.
+ we want to end up with rgid==0 and egid==gid
+****************************************************************************/
+void set_effective_gid(gid_t gid)
+{
+#if USE_SETRESUID
+ setresgid(-1,gid,-1);
+#endif
+
+#if USE_SETREUID
+ setregid(-1,gid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, gid);
+#endif
+
+ assert_gid(-1, gid);
+}
+
+static uid_t saved_euid, saved_ruid;
+
+/****************************************************************************
+ save the real and effective uid for later restoration. Used by the quotas
+ code
+****************************************************************************/
+void save_re_uid(void)
+{
+ saved_ruid = getuid();
+ saved_euid = geteuid();
+}
+
+
+/****************************************************************************
+ and restore them!
+****************************************************************************/
+void restore_re_uid(void)
+{
+ set_effective_uid(0);
+
+#if USE_SETRESUID
+ setresuid(saved_ruid, saved_euid, -1);
+#elif USE_SETREUID
+ setreuid(saved_ruid, -1);
+ setreuid(-1,saved_euid);
+#elif USE_SETUIDX
+ setuidx(ID_REAL, saved_ruid);
+ setuidx(ID_EFFECTIVE, saved_euid);
+#else
+ set_effective_uid(saved_euid);
+ if (getuid() != saved_ruid)
+ setuid(saved_ruid);
+ set_effective_uid(saved_euid);
+#endif
+
+ assert_uid(saved_ruid, saved_euid);
+}
+
+/****************************************************************************
+ set the real AND effective uid to the current effective uid in a way that
+ allows root to be regained.
+ This is only possible on some platforms.
+****************************************************************************/
+int set_re_uid(void)
+{
+ uid_t uid = geteuid();
+
+#if USE_SETRESUID
+ setresuid(geteuid(), -1, -1);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+ setreuid(uid, -1);
+ setreuid(-1, uid);
+#endif
+
+#if USE_SETEUID
+ /* can't be done */
+ return -1;
+#endif
+
+#if USE_SETUIDX
+ /* can't be done */
+ return -1;
+#endif
+
+ assert_uid(uid, uid);
+ return 0;
+}
+
+
+/****************************************************************************
+ Become the specified uid and gid - permanently !
+ there should be no way back if possible
+****************************************************************************/
+void become_user_permanently(uid_t uid, gid_t gid)
+{
+ /*
+ * First - gain root privilege. We do this to ensure
+ * we can lose it again.
+ */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+#if USE_SETRESUID
+ setresgid(gid,gid,gid);
+ setgid(gid);
+ setresuid(uid,uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETREUID
+ setregid(gid,gid);
+ setgid(gid);
+ setreuid(uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+ setgid(gid);
+ setuid(uid);
+ seteuid(uid);
+ setuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_REAL, gid);
+ setgidx(ID_EFFECTIVE, gid);
+ setgid(gid);
+ setuidx(ID_REAL, uid);
+ setuidx(ID_EFFECTIVE, uid);
+ setuid(uid);
+#endif
+
+ assert_uid(uid, uid);
+ assert_gid(gid, gid);
+}
+
+#ifdef AUTOCONF_TEST
+
+/****************************************************************************
+this function just checks that we don't get ENOSYS back
+****************************************************************************/
+static int have_syscall(void)
+{
+ errno = 0;
+
+#if USE_SETRESUID
+ setresuid(-1,-1,-1);
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,-1);
+#endif
+
+#if USE_SETEUID
+ seteuid(-1);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, -1);
+#endif
+
+ if (errno == ENOSYS) return -1;
+
+ return 0;
+}
+
+main()
+{
+ if (getuid() != 0) {
+#if (defined(AIX) && defined(USE_SETREUID))
+ /* setreuid is badly broken on AIX 4.1, we avoid it completely */
+ fprintf(stderr,"avoiding possibly broken setreuid\n");
+ exit(1);
+#endif
+
+ /* if not running as root then at least check to see if we get ENOSYS - this
+ handles Linux 2.0.x with glibc 2.1 */
+ fprintf(stderr,"not running as root: checking for ENOSYS\n");
+ exit(have_syscall());
+ }
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+ set_effective_gid(1);
+ set_effective_uid(1);
+ save_re_uid();
+ restore_re_uid();
+ gain_root_privilege();
+ gain_root_group_privilege();
+ become_user_permanently(1, 1);
+ setuid(0);
+ if (getuid() == 0) {
+ fprintf(stderr,"uid not set permanently\n");
+ exit(1);
+ }
+
+ printf("OK\n");
+
+ exit(0);
+}
+#endif
+
+/****************************************************************************
+Check if we are setuid root. Used in libsmb and smbpasswd parinoia checks.
+****************************************************************************/
+BOOL is_setuid_root(void)
+{
+ return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
+}
diff --git a/source/lib/util_sid.c b/source/lib/util_sid.c
new file mode 100644
index 00000000000..009cc7742af
--- /dev/null
+++ b/source/lib/util_sid.c
@@ -0,0 +1,710 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+DOM_SID global_sam_sid;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/*
+ * Some useful sids
+ */
+
+DOM_SID global_sid_Builtin; /* Local well-known domain */
+DOM_SID global_sid_World_Domain; /* Everyone domain */
+DOM_SID global_sid_World; /* Everyone */
+DOM_SID global_sid_Creator_Owner_Domain; /* Creator Owner domain */
+DOM_SID global_sid_Creator_Owner; /* Creator Owner */
+DOM_SID global_sid_NT_Authority; /* NT Authority */
+DOM_SID global_sid_NULL; /* NULL sid */
+DOM_SID global_sid_Builtin_Guests; /* Builtin guest users */
+DOM_SID global_sid_Authenticated_Users; /* All authenticated rids */
+DOM_SID global_sid_Network; /* Network rids */
+DOM_SID global_sid_Anonymous; /* Anonymous login */
+DOM_SID global_sid_nonexistent; /* S-0-0. Used in Lsa level 3. */
+
+const DOM_SID *global_sid_everyone = &global_sid_World;
+
+typedef struct _known_sid_users {
+ uint32 rid;
+ enum SID_NAME_USE sid_name_use;
+ char *known_user_name;
+} known_sid_users;
+
+/* static known_sid_users no_users[] = {{0, 0, NULL}}; */
+
+static known_sid_users everyone_users[] = {
+ { 0, SID_NAME_WKN_GRP, "Everyone" },
+ {0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users creator_owner_users[] = {
+ { 0, SID_NAME_ALIAS, "Creator Owner" },
+ {0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users nt_authority_users[] = {
+ { 1, SID_NAME_ALIAS, "Dialup" },
+ { 2, SID_NAME_ALIAS, "Network"},
+ { 3, SID_NAME_ALIAS, "Batch"},
+ { 4, SID_NAME_ALIAS, "Interactive"},
+ { 6, SID_NAME_ALIAS, "Service"},
+ { 7, SID_NAME_ALIAS, "AnonymousLogon"},
+ { 8, SID_NAME_ALIAS, "Proxy"},
+ { 9, SID_NAME_ALIAS, "ServerLogon"},
+ { 11, SID_NAME_ALIAS, "Authenticated Users"},
+ { 18, SID_NAME_ALIAS, "SYSTEM"},
+ { 0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users builtin_groups[] = {
+ { BUILTIN_ALIAS_RID_ADMINS, SID_NAME_ALIAS, "Administrators" },
+ { BUILTIN_ALIAS_RID_USERS, SID_NAME_ALIAS, "Users" },
+ { BUILTIN_ALIAS_RID_GUESTS, SID_NAME_ALIAS, "Guests" },
+ { BUILTIN_ALIAS_RID_ACCOUNT_OPS, SID_NAME_ALIAS, "Account Operators" },
+ { BUILTIN_ALIAS_RID_SYSTEM_OPS, SID_NAME_ALIAS, "Server Operators" },
+ { BUILTIN_ALIAS_RID_PRINT_OPS, SID_NAME_ALIAS, "Print Operators" },
+ { BUILTIN_ALIAS_RID_BACKUP_OPS, SID_NAME_ALIAS, "Backup Operators" },
+ { 0, (enum SID_NAME_USE)0, NULL}};
+
+#define MAX_SID_NAMES 7
+
+static struct sid_name_map_info
+{
+ DOM_SID *sid;
+ char *name;
+ known_sid_users *known_users;
+} sid_name_map[MAX_SID_NAMES];
+
+static BOOL sid_name_map_initialized = False;
+
+/*
+ * An NT compatible anonymous token.
+ */
+
+static DOM_SID anon_sid_array[3];
+
+NT_USER_TOKEN anonymous_token = {
+ 3,
+ anon_sid_array
+};
+
+/**************************************************************************
+ quick init function
+ *************************************************************************/
+static void init_sid_name_map (void)
+{
+ int i = 0;
+
+ if (sid_name_map_initialized) return;
+
+
+ if ((lp_security() == SEC_USER) && lp_domain_logons()) {
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myworkgroup;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myname;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ }
+ else {
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myname;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ }
+
+ sid_name_map[i].sid = &global_sid_Builtin;
+ sid_name_map[i].name = "BUILTIN";
+ sid_name_map[i].known_users = &builtin_groups[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_World_Domain;
+ sid_name_map[i].name = "";
+ sid_name_map[i].known_users = &everyone_users[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_Creator_Owner_Domain;
+ sid_name_map[i].name = "";
+ sid_name_map[i].known_users = &creator_owner_users[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_NT_Authority;
+ sid_name_map[i].name = "NT Authority";
+ sid_name_map[i].known_users = &nt_authority_users[0];
+ i++;
+
+
+ /* end of array */
+ sid_name_map[i].sid = NULL;
+ sid_name_map[i].name = NULL;
+ sid_name_map[i].known_users = NULL;
+
+ sid_name_map_initialized = True;
+
+ return;
+
+}
+
+/****************************************************************************
+ Creates some useful well known sids
+****************************************************************************/
+
+void generate_wellknown_sids(void)
+{
+ string_to_sid(&global_sid_Builtin, "S-1-5-32");
+ string_to_sid(&global_sid_Builtin_Guests, "S-1-5-32-546");
+ string_to_sid(&global_sid_World_Domain, "S-1-1");
+ string_to_sid(&global_sid_World, "S-1-1-0");
+ string_to_sid(&global_sid_Creator_Owner_Domain, "S-1-3");
+ string_to_sid(&global_sid_Creator_Owner, "S-1-3-0");
+ string_to_sid(&global_sid_NT_Authority, "S-1-5");
+ string_to_sid(&global_sid_NULL, "S-1-0-0");
+ string_to_sid(&global_sid_Authenticated_Users, "S-1-5-11");
+ string_to_sid(&global_sid_Network, "S-1-5-2");
+ string_to_sid(&global_sid_Anonymous, "S-1-5-7");
+ string_to_sid(&global_sid_nonexistent, "S-0-0"); /* Used in Lsa level 3. */
+
+ /* Create the anon token. */
+ sid_copy( &anonymous_token.user_sids[0], &global_sid_World);
+ sid_copy( &anonymous_token.user_sids[1], &global_sid_Network);
+ sid_copy( &anonymous_token.user_sids[2], &global_sid_Anonymous);
+}
+
+/**************************************************************************
+ Turns a domain SID into a name, returned in the nt_domain argument.
+***************************************************************************/
+
+BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
+{
+ fstring sid_str;
+ int i = 0;
+
+ sid_to_string(sid_str, sid);
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
+
+ if (nt_domain == NULL)
+ return False;
+
+ while (sid_name_map[i].sid != NULL) {
+ sid_to_string(sid_str, sid_name_map[i].sid);
+ DEBUG(5,("map_domain_sid_to_name: compare: %s\n", sid_str));
+ if (sid_equal(sid_name_map[i].sid, sid)) {
+ fstrcpy(nt_domain, sid_name_map[i].name);
+ DEBUG(5,("map_domain_sid_to_name: found '%s'\n", nt_domain));
+ return True;
+ }
+ i++;
+ }
+
+ DEBUG(5,("map_domain_sid_to_name: mapping for %s not found\n", sid_str));
+
+ return False;
+}
+
+/**************************************************************************
+ Looks up a known username from one of the known domains.
+***************************************************************************/
+
+BOOL lookup_known_rid(DOM_SID *sid, uint32 rid, char *name, enum SID_NAME_USE *psid_name_use)
+{
+ int i = 0;
+ struct sid_name_map_info *psnm;
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ for(i = 0; sid_name_map[i].sid != NULL; i++) {
+ psnm = &sid_name_map[i];
+ if(sid_equal(psnm->sid, sid)) {
+ int j;
+ for(j = 0; psnm->known_users && psnm->known_users[j].known_user_name != NULL; j++) {
+ if(rid == psnm->known_users[j].rid) {
+ DEBUG(5,("lookup_builtin_rid: rid = %u, domain = '%s', user = '%s'\n",
+ (unsigned int)rid, psnm->name, psnm->known_users[j].known_user_name ));
+ fstrcpy( name, psnm->known_users[j].known_user_name);
+ *psid_name_use = psnm->known_users[j].sid_name_use;
+ return True;
+ }
+ }
+ }
+ }
+
+ return False;
+}
+
+/**************************************************************************
+ Turns a domain name into a SID.
+ *** side-effect: if the domain name is NULL, it is set to our domain ***
+***************************************************************************/
+
+BOOL map_domain_name_to_sid(DOM_SID *sid, char *nt_domain)
+{
+ int i = 0;
+
+ if (nt_domain == NULL) {
+ DEBUG(5,("map_domain_name_to_sid: mapping NULL domain to our SID.\n"));
+ sid_copy(sid, &global_sam_sid);
+ return True;
+ }
+
+ if (nt_domain[0] == 0) {
+ fstrcpy(nt_domain, global_myname);
+ DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n", nt_domain));
+ sid_copy(sid, &global_sam_sid);
+ return True;
+ }
+
+ DEBUG(5,("map_domain_name_to_sid: %s\n", nt_domain));
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ while (sid_name_map[i].name != NULL) {
+ DEBUG(5,("map_domain_name_to_sid: compare: %s\n", sid_name_map[i].name));
+ if (strequal(sid_name_map[i].name, nt_domain)) {
+ fstring sid_str;
+ sid_copy(sid, sid_name_map[i].sid);
+ sid_to_string(sid_str, sid_name_map[i].sid);
+ DEBUG(5,("map_domain_name_to_sid: found %s\n", sid_str));
+ return True;
+ }
+ i++;
+ }
+
+ DEBUG(0,("map_domain_name_to_sid: mapping to %s not found.\n", nt_domain));
+ return False;
+}
+
+/**************************************************************************
+ Splits a name of format \DOMAIN\name or name into its two components.
+ Sets the DOMAIN name to global_myname if it has not been specified.
+***************************************************************************/
+
+void split_domain_name(const char *fullname, char *domain, char *name)
+{
+ pstring full_name;
+ char *p, *sep;
+
+ sep = lp_winbind_separator();
+
+ *domain = *name = '\0';
+
+ if (fullname[0] == sep[0] || fullname[0] == '\\')
+ fullname++;
+
+ pstrcpy(full_name, fullname);
+ p = strchr_m(full_name+1, '\\');
+ if (!p) p = strchr_m(full_name+1, sep[0]);
+
+ if (p != NULL) {
+ *p = 0;
+ fstrcpy(domain, full_name);
+ fstrcpy(name, p+1);
+ } else {
+ fstrcpy(domain, global_myname);
+ fstrcpy(name, full_name);
+ }
+
+ DEBUG(10,("split_domain_name:name '%s' split into domain :'%s' and user :'%s'\n",
+ fullname, domain, name));
+}
+
+/*****************************************************************
+ Convert a SID to an ascii string.
+*****************************************************************/
+
+char *sid_to_string(fstring sidstr_out, DOM_SID *sid)
+{
+ char subauth[16];
+ int i;
+ /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+ uint32 ia = (sid->id_auth[5]) +
+ (sid->id_auth[4] << 8 ) +
+ (sid->id_auth[3] << 16) +
+ (sid->id_auth[2] << 24);
+
+ slprintf(sidstr_out, sizeof(fstring) - 1, "S-%u-%lu", (unsigned int)sid->sid_rev_num, (unsigned long)ia);
+
+ for (i = 0; i < sid->num_auths; i++) {
+ slprintf(subauth, sizeof(subauth)-1, "-%lu", (unsigned long)sid->sub_auths[i]);
+ fstrcat(sidstr_out, subauth);
+ }
+
+ return sidstr_out;
+}
+
+/*
+ useful function for debug lines
+*/
+const char *sid_string_static(DOM_SID *sid)
+{
+ static fstring sid_str;
+ sid_to_string(sid_str, sid);
+ return sid_str;
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+*****************************************************************/
+
+BOOL string_to_sid(DOM_SID *sidout, const char *sidstr)
+{
+ pstring tok;
+ const char *p = sidstr;
+ /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+ uint32 ia;
+
+ memset((char *)sidout, '\0', sizeof(DOM_SID));
+
+ if (StrnCaseCmp( sidstr, "S-", 2)) {
+ DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
+ return False;
+ }
+
+ p += 2;
+ if (!next_token(&p, tok, "-", sizeof(tok))) {
+ DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ return False;
+ }
+
+ /* Get the revision number. */
+ sidout->sid_rev_num = (uint8)strtoul(tok, NULL, 10);
+
+ if (!next_token(&p, tok, "-", sizeof(tok))) {
+ DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ return False;
+ }
+
+ /* identauth in decimal should be < 2^32 */
+ ia = (uint32)strtoul(tok, NULL, 10);
+
+ /* NOTE - the ia value is in big-endian format. */
+ sidout->id_auth[0] = 0;
+ sidout->id_auth[1] = 0;
+ sidout->id_auth[2] = (ia & 0xff000000) >> 24;
+ sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
+ sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
+ sidout->id_auth[5] = (ia & 0x000000ff);
+
+ sidout->num_auths = 0;
+
+ while(next_token(&p, tok, "-", sizeof(tok)) &&
+ sidout->num_auths < MAXSUBAUTHS) {
+ /*
+ * NOTE - the subauths are in native machine-endian format. They
+ * are converted to little-endian when linearized onto the wire.
+ */
+ sid_append_rid(sidout, (uint32)strtoul(tok, NULL, 10));
+ }
+
+ return True;
+}
+
+/*****************************************************************
+ Add a rid to the end of a sid
+*****************************************************************/
+
+BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
+{
+ if (sid->num_auths < MAXSUBAUTHS) {
+ sid->sub_auths[sid->num_auths++] = rid;
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Removes the last rid from the end of a sid
+*****************************************************************/
+
+BOOL sid_split_rid(DOM_SID *sid, uint32 *rid)
+{
+ if (sid->num_auths > 0) {
+ sid->num_auths--;
+ *rid = sid->sub_auths[sid->num_auths];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+*****************************************************************/
+
+BOOL sid_peek_rid(DOM_SID *sid, uint32 *rid)
+{
+ if (sid->num_auths > 0) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Copies a sid
+*****************************************************************/
+
+void sid_copy(DOM_SID *dst, const DOM_SID *src)
+{
+ int i;
+
+ memset((char *)dst, '\0', sizeof(DOM_SID));
+
+ dst->sid_rev_num = src->sid_rev_num;
+ dst->num_auths = src->num_auths;
+
+ memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
+
+ for (i = 0; i < src->num_auths; i++)
+ dst->sub_auths[i] = src->sub_auths[i];
+}
+
+/*****************************************************************
+ Duplicates a sid - mallocs the target.
+*****************************************************************/
+
+DOM_SID *sid_dup(DOM_SID *src)
+{
+ DOM_SID *dst;
+
+ if(!src)
+ return NULL;
+
+ if((dst = malloc(sizeof(DOM_SID))) != NULL) {
+ memset(dst, '\0', sizeof(DOM_SID));
+ sid_copy( dst, src);
+ }
+
+ return dst;
+}
+
+/*****************************************************************
+ Write a sid out into on-the-wire format.
+*****************************************************************/
+BOOL sid_linearize(char *outbuf, size_t len, DOM_SID *sid)
+{
+ size_t i;
+
+ if (len < sid_size(sid))
+ return False;
+
+ SCVAL(outbuf,0,sid->sid_rev_num);
+ SCVAL(outbuf,1,sid->num_auths);
+ memcpy(&outbuf[2], sid->id_auth, 6);
+ for(i = 0; i < sid->num_auths; i++)
+ SIVAL(outbuf, 8 + (i*4), sid->sub_auths[i]);
+
+ return True;
+}
+
+/*****************************************************************
+ parse a on-the-wire SID to a DOM_SID
+*****************************************************************/
+BOOL sid_parse(char *inbuf, size_t len, DOM_SID *sid)
+{
+ int i;
+ if (len < 8) return False;
+ sid->sid_rev_num = CVAL(inbuf, 0);
+ sid->num_auths = CVAL(inbuf, 1);
+ memcpy(sid->id_auth, inbuf+2, 6);
+ if (len < 8 + sid->num_auths*4) return False;
+ for (i=0;i<sid->num_auths;i++) {
+ sid->sub_auths[i] = IVAL(inbuf, 8+i*4);
+ }
+ return True;
+}
+
+
+/*****************************************************************
+ Compare the auth portion of two sids.
+*****************************************************************/
+int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2) return 0;
+ if (!sid1) return -1;
+ if (!sid2) return 1;
+
+ if (sid1->sid_rev_num != sid2->sid_rev_num)
+ return sid1->sid_rev_num - sid2->sid_rev_num;
+
+ for (i = 0; i < 6; i++)
+ if (sid1->id_auth[i] != sid2->id_auth[i])
+ return sid1->id_auth[i] - sid2->id_auth[i];
+
+ return 0;
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2) return 0;
+ if (!sid1) return -1;
+ if (!sid2) return 1;
+
+ /* compare most likely different rids, first: i.e start at end */
+ if (sid1->num_auths != sid2->num_auths)
+ return sid1->num_auths - sid2->num_auths;
+
+ for (i = sid1->num_auths-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+see if 2 SIDs are in the same domain
+this just compares the leading sub-auths
+*****************************************************************/
+int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int n, i;
+
+ n = MIN(sid1->num_auths, sid2->num_auths);
+
+ for (i = n-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+BOOL sid_equal(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ return sid_compare(sid1, sid2) == 0;
+}
+
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_domain(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sam_sid);
+}
+
+
+/*****************************************************************
+ Check if the SID is the builtin SID (S-1-5-32).
+*****************************************************************/
+BOOL sid_check_is_builtin(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sid_Builtin);
+}
+
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_in_our_domain(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_equal(&dom_sid, &global_sam_sid);
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_in_builtin(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_equal(&dom_sid, &global_sid_Builtin);
+}
+
+
+/*****************************************************************
+ Calculates size of a sid.
+*****************************************************************/
+
+size_t sid_size(DOM_SID *sid)
+{
+ if (sid == NULL)
+ return 0;
+
+ return sid->num_auths * sizeof(uint32) + 8;
+}
+
+/*****************************************************************
+ Returns true if SID is internal (and non-mappable).
+*****************************************************************/
+
+BOOL non_mappable_sid(DOM_SID *sid)
+{
+ DOM_SID dom;
+ uint32 rid;
+
+ sid_copy(&dom, sid);
+ sid_split_rid(&dom, &rid);
+
+ if (sid_equal(&dom, &global_sid_Builtin))
+ return True;
+
+ if (sid_equal(&dom, &global_sid_Creator_Owner_Domain))
+ return True;
+
+ if (sid_equal(&dom, &global_sid_NT_Authority))
+ return True;
+
+ return False;
+}
+
+/*
+ return the binary string representation of a DOM_SID
+ caller must free
+*/
+char *sid_binstring(DOM_SID *sid)
+{
+ char *buf, *s;
+ int len = sid_size(sid);
+ buf = malloc(len);
+ if (!buf) return NULL;
+ sid_linearize(buf, len, sid);
+ s = binary_string(buf, len);
+ free(buf);
+ return s;
+}
+
diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c
new file mode 100644
index 00000000000..a56a9741935
--- /dev/null
+++ b/source/lib/util_sock.c
@@ -0,0 +1,1206 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_SSL
+#include <openssl/ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* WITH_SSL */
+
+/* the last IP received from */
+struct in_addr lastip;
+
+/* the last port received from */
+int lastport=0;
+
+int smb_read_error = 0;
+
+/****************************************************************************
+ Determine if a file descriptor is in fact a socket.
+****************************************************************************/
+
+BOOL is_a_socket(int fd)
+{
+ int v,l;
+ l = sizeof(int);
+ return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+typedef struct smb_socket_option
+{
+ char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} smb_socket_option;
+
+smb_socket_option socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+ {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+/****************************************************************************
+ Print socket options.
+****************************************************************************/
+static void print_socket_options(int s)
+{
+ int value, vlen = 4;
+ smb_socket_option *p = &socket_options[0];
+
+ for (; p->name != NULL; p++) {
+ if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) {
+ DEBUG(5,("Could not test socket option %s.\n", p->name));
+ } else {
+ DEBUG(5,("socket option %s = %d\n",p->name,value));
+ }
+ }
+ }
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+
+void set_socket_options(int fd, char *options)
+{
+ fstring tok;
+
+ while (next_token(&options,tok," \t,", sizeof(tok))) {
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ BOOL got_value = False;
+
+ if ((p = strchr_m(tok,'='))) {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = True;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name) {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype) {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0)
+ DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
+ }
+
+ print_socket_options(fd);
+}
+
+/****************************************************************************
+ Read from a socket.
+****************************************************************************/
+
+ssize_t read_udp_socket(int fd,char *buf,size_t len)
+{
+ ssize_t ret;
+ struct sockaddr_in sock;
+ socklen_t socklen = sizeof(sock);
+
+ memset((char *)&sock,'\0',socklen);
+ memset((char *)&lastip,'\0',sizeof(lastip));
+ ret = (ssize_t)recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
+ if (ret <= 0) {
+ DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
+ return(0);
+ }
+
+ lastip = sock.sin_addr;
+ lastport = ntohs(sock.sin_port);
+
+ DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n",
+ inet_ntoa(lastip), lastport, ret));
+
+ return(ret);
+}
+
+/****************************************************************************
+ Read data from a socket with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+****************************************************************************/
+
+static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
+{
+ fd_set fds;
+ int selrtn;
+ ssize_t readret;
+ size_t nread = 0;
+ struct timeval timeout;
+
+ /* just checking .... */
+ if (maxcnt <= 0)
+ return(0);
+
+ smb_read_error = 0;
+
+ /* Blocking read */
+ if (time_out <= 0) {
+ if (mincnt == 0) mincnt = maxcnt;
+
+ while (nread < mincnt) {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
+ if (readret == 0) {
+ DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n"));
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ nread += readret;
+ }
+ return((ssize_t)nread);
+ }
+
+ /* Most difficult - timeout read */
+ /* If this is ever called on a disk file and
+ mincnt is greater then the filesize then
+ system performance will suffer severely as
+ select always returns true on disk files */
+
+ /* Set initial timeout */
+ timeout.tv_sec = (time_t)(time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+ for (nread=0; nread < mincnt; ) {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ selrtn = sys_select_intr(fd+1,&fds,&timeout);
+
+ /* Check if error */
+ if(selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n"));
+ smb_read_error = READ_TIMEOUT;
+ return -1;
+ }
+
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n"));
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ nread += readret;
+ }
+
+ /* Return the number we got */
+ return((ssize_t)nread);
+}
+
+/****************************************************************************
+ Read data from a fd with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+****************************************************************************/
+
+ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
+{
+ fd_set fds;
+ int selrtn;
+ ssize_t readret;
+ size_t nread = 0;
+ struct timeval timeout;
+
+ /* just checking .... */
+ if (maxcnt <= 0)
+ return(0);
+
+ /* Blocking read */
+ if (time_out <= 0) {
+ if (mincnt == 0) mincnt = maxcnt;
+
+ while (nread < mincnt) {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
+ if (readret <= 0)
+ return readret;
+
+ nread += readret;
+ }
+ return((ssize_t)nread);
+ }
+
+ /* Most difficult - timeout read */
+ /* If this is ever called on a disk file and
+ mincnt is greater then the filesize then
+ system performance will suffer severely as
+ select always returns true on disk files */
+
+ /* Set initial timeout */
+ timeout.tv_sec = (time_t)(time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+ for (nread=0; nread < mincnt; ) {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ selrtn = sys_select_intr(fd+1,&fds,&timeout);
+
+ if(selrtn <= 0)
+ return selrtn;
+
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
+ if (readret <= 0)
+ return readret;
+
+ nread += readret;
+ }
+
+ /* Return the number we got */
+ return((ssize_t)nread);
+}
+
+/****************************************************************************
+send a keepalive packet (rfc1002)
+****************************************************************************/
+
+BOOL send_keepalive(int client)
+{
+ unsigned char buf[4];
+
+ buf[0] = SMBkeepalive;
+ buf[1] = buf[2] = buf[3] = 0;
+
+ return(write_socket_data(client,(char *)buf,4) == 4);
+}
+
+/****************************************************************************
+ read data from the client, reading exactly N bytes.
+****************************************************************************/
+
+ssize_t read_data(int fd,char *buffer,size_t N)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ smb_read_error = 0;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
+ ret = read(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == 0)
+ {
+ DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Read data from a socket, reading exactly N bytes.
+****************************************************************************/
+
+static ssize_t read_socket_data(int fd,char *buffer,size_t N)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ smb_read_error = 0;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
+ ret = read(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == 0)
+ {
+ DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a fd.
+****************************************************************************/
+
+ssize_t write_data(int fd,char *buffer,size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
+ ret = write(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = write(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == -1) {
+ DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (ret == 0) return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a socket - use send rather than write.
+****************************************************************************/
+
+ssize_t write_socket_data(int fd,char *buffer,size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
+ ret = send(fd,buffer + total,N - total, 0);
+ }
+#else /* WITH_SSL */
+ ret = send(fd,buffer + total,N - total,0);
+#endif /* WITH_SSL */
+
+ if (ret == -1) {
+ DEBUG(0,("write_socket_data: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (ret == 0) return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+write to a socket
+****************************************************************************/
+
+ssize_t write_socket(int fd,char *buf,size_t len)
+{
+ ssize_t ret=0;
+
+ DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len));
+ ret = write_socket_data(fd,buf,len);
+
+ DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret));
+ if(ret <= 0)
+ DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
+ (int)len, fd, strerror(errno) ));
+
+ return(ret);
+}
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer
+This version of the function will return a length of zero on receiving
+a keepalive packet.
+timeout is in milliseconds.
+****************************************************************************/
+
+static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout)
+{
+ ssize_t len=0;
+ int msg_type;
+ BOOL ok = False;
+
+ while (!ok)
+ {
+ if (timeout > 0)
+ ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4);
+ else
+ ok = (read_socket_data(fd,inbuf,4) == 4);
+
+ if (!ok)
+ return(-1);
+
+ len = smb_len(inbuf);
+ msg_type = CVAL(inbuf,0);
+
+ if (msg_type == SMBkeepalive)
+ DEBUG(5,("Got keepalive packet\n"));
+ }
+
+ DEBUG(10,("got smb length of %d\n",len));
+
+ return(len);
+}
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer. This version of the function will
+never return a session keepalive (length of zero).
+timeout is in milliseconds.
+****************************************************************************/
+
+ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout)
+{
+ ssize_t len;
+
+ for(;;)
+ {
+ len = read_smb_length_return_keepalive(fd, inbuf, timeout);
+
+ if(len < 0)
+ return len;
+
+ /* Ignore session keepalives. */
+ if(CVAL(inbuf,0) != SMBkeepalive)
+ break;
+ }
+
+ DEBUG(10,("read_smb_length: got smb length of %d\n",len));
+
+ return len;
+}
+
+/****************************************************************************
+ read an smb from a fd. Note that the buffer *MUST* be of size
+ BUFFER_SIZE+SAFETY_MARGIN.
+ The timeout is in milliseconds.
+ This function will return on a
+ receipt of a session keepalive packet.
+****************************************************************************/
+
+BOOL receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+ ssize_t len,ret;
+
+ smb_read_error = 0;
+
+ memset(buffer,'\0',smb_size + 100);
+
+ len = read_smb_length_return_keepalive(fd,buffer,timeout);
+ if (len < 0) {
+ DEBUG(10,("receive_smb: length < 0!\n"));
+ return(False);
+ }
+
+ /*
+ * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+ * of header. Don't print the error if this fits.... JRA.
+ */
+
+ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+ }
+
+ if(len > 0) {
+ ret = read_socket_data(fd,buffer+4,len);
+ if (ret != len) {
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ read an smb from a fd ignoring all keepalive packets. Note that the buffer
+ *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+ The timeout is in milliseconds
+
+ This is exactly the same as receive_smb except that it never returns
+ a session keepalive packet (just as receive_smb used to do).
+ receive_smb was changed to return keepalives as the oplock processing means this call
+ should never go into a blocking read.
+****************************************************************************/
+
+BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+ BOOL ret;
+
+ for(;;)
+ {
+ ret = receive_smb(fd, buffer, timeout);
+
+ if (!ret)
+ {
+ DEBUG(10,("client_receive_smb failed\n"));
+ show_msg(buffer);
+ return ret;
+ }
+
+ /* Ignore session keepalive packets. */
+ if(CVAL(buffer,0) != SMBkeepalive)
+ break;
+ }
+ show_msg(buffer);
+ return ret;
+}
+
+/****************************************************************************
+ send an smb to a fd
+****************************************************************************/
+
+BOOL send_smb(int fd,char *buffer)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+ len = smb_len(buffer) + 4;
+
+ while (nwritten < len) {
+ ret = write_socket(fd,buffer+nwritten,len - nwritten);
+ if (ret <= 0) {
+ DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ return False;
+ }
+ nwritten += ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+send a single packet to a port on another machine
+****************************************************************************/
+
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+{
+ BOOL ret;
+ int out_fd;
+ struct sockaddr_in sock_out;
+
+ /* create a socket to write to */
+ out_fd = socket(AF_INET, type, 0);
+ if (out_fd == -1)
+ {
+ DEBUG(0,("socket failed"));
+ return False;
+ }
+
+ /* set the address and port */
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&ip);
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = AF_INET;
+
+ if (DEBUGLEVEL > 0)
+ DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
+ len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
+
+ /* send it */
+ ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
+
+ if (!ret)
+ DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
+
+ close(out_fd);
+ return(ret);
+}
+
+/****************************************************************************
+ Open a socket of the specified type, port, and address for incoming data.
+****************************************************************************/
+
+int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind )
+{
+ struct sockaddr_in sock;
+ int res;
+
+ memset( (char *)&sock, '\0', sizeof(sock) );
+
+#ifdef HAVE_SOCK_SIN_LEN
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = htons( port );
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = socket_addr;
+
+ res = socket( AF_INET, type, 0 );
+ if( res == -1 ) {
+ if( DEBUGLVL(0) ) {
+ dbgtext( "open_socket_in(): socket() call failed: " );
+ dbgtext( "%s\n", strerror( errno ) );
+ }
+ return -1;
+ }
+
+ /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
+ {
+ int val = rebind ? 1 : 0;
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: " );
+ dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
+#ifdef SO_REUSEPORT
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: ");
+ dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
+#endif /* SO_REUSEPORT */
+ }
+
+ /* now we've got a socket - we need to bind it */
+ if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) {
+ if( DEBUGLVL(dlevel) && (port == SMB_PORT || port == NMB_PORT) ) {
+ dbgtext( "bind failed on port %d ", port );
+ dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) );
+ dbgtext( "Error = %s\n", strerror(errno) );
+ }
+ close( res );
+ return( -1 );
+ }
+
+ DEBUG( 3, ( "bind succeeded on port %d\n", port ) );
+
+ return( res );
+ }
+
+/****************************************************************************
+ create an outgoing socket. timeout is in milliseconds.
+ **************************************************************************/
+
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
+{
+ struct sockaddr_in sock_out;
+ int res,ret;
+ int connect_loop = 250; /* 250 milliseconds */
+ int loops = (timeout) / connect_loop;
+
+ /* create a socket to write to */
+ res = socket(PF_INET, type, 0);
+ if (res == -1)
+ { DEBUG(0,("socket error\n")); return -1; }
+
+ if (type != SOCK_STREAM) return(res);
+
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)addr);
+
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = PF_INET;
+
+ /* set it non-blocking */
+ set_blocking(res,False);
+
+ DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
+
+ /* and connect it to the destination */
+connect_again:
+ ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
+
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && loops--) {
+ msleep(connect_loop);
+ goto connect_again;
+ }
+
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
+ DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
+ close(res);
+ return -1;
+ }
+
+#ifdef EISCONN
+ if (ret < 0 && errno == EISCONN) {
+ errno = 0;
+ ret = 0;
+ }
+#endif
+
+ if (ret < 0) {
+ DEBUG(2,("error connecting to %s:%d (%s)\n",
+ inet_ntoa(*addr),port,strerror(errno)));
+ close(res);
+ return -1;
+ }
+
+ /* set it blocking again */
+ set_blocking(res,True);
+
+ return res;
+}
+
+/*
+ open a connected UDP socket to host on port
+*/
+int open_udp_socket(const char *host, int port)
+{
+ int type = SOCK_DGRAM;
+ struct sockaddr_in sock_out;
+ int res;
+ struct in_addr *addr;
+
+ addr = interpret_addr2(host);
+
+ res = socket(PF_INET, type, 0);
+ if (res == -1) {
+ return -1;
+ }
+
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)addr);
+ sock_out.sin_port = htons(port);
+ sock_out.sin_family = PF_INET;
+
+ if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
+ close(res);
+ return -1;
+ }
+
+ return res;
+}
+
+
+/* the following 3 client_*() functions are nasty ways of allowing
+ some generic functions to get info that really should be hidden in
+ particular modules */
+static int client_fd = -1;
+
+void client_setfd(int fd)
+{
+ client_fd = fd;
+}
+
+char *client_name(void)
+{
+ return get_socket_name(client_fd);
+}
+
+char *client_addr(void)
+{
+ return get_socket_addr(client_fd);
+}
+
+/*******************************************************************
+ matchname - determine if host name matches IP address. Used to
+ confirm a hostname lookup to prevent spoof attacks
+ ******************************************************************/
+static BOOL matchname(char *remotehost,struct in_addr addr)
+{
+ struct hostent *hp;
+ int i;
+
+ if ((hp = sys_gethostbyname(remotehost)) == 0) {
+ DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", remotehost));
+ return False;
+ }
+
+ /*
+ * Make sure that gethostbyname() returns the "correct" host name.
+ * Unfortunately, gethostbyname("localhost") sometimes yields
+ * "localhost.domain". Since the latter host name comes from the
+ * local DNS, we just have to trust it (all bets are off if the local
+ * DNS is perverted). We always check the address list, though.
+ */
+
+ if (strcasecmp(remotehost, hp->h_name)
+ && strcasecmp(remotehost, "localhost")) {
+ DEBUG(0,("host name/name mismatch: %s != %s\n",
+ remotehost, hp->h_name));
+ return False;
+ }
+
+ /* Look up the host address in the address list we just got. */
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
+ return True;
+ }
+
+ /*
+ * The host name does not map to the original host address. Perhaps
+ * someone has compromised a name server. More likely someone botched
+ * it, but that could be dangerous, too.
+ */
+
+ DEBUG(0,("host name/address mismatch: %s != %s\n",
+ inet_ntoa(addr), hp->h_name));
+ return False;
+}
+
+
+/*******************************************************************
+ return the DNS name of the remote end of a socket
+ ******************************************************************/
+char *get_socket_name(int fd)
+{
+ static pstring name_buf;
+ static fstring addr_buf;
+ struct hostent *hp;
+ struct in_addr addr;
+ char *p;
+
+ /* reverse lookups can be *very* expensive, and in many
+ situations won't work because many networks don't link dhcp
+ with dns. To avoid the delay we avoid the lookup if
+ possible */
+ if (!lp_hostname_lookups()) {
+ return get_socket_addr(fd);
+ }
+
+ p = get_socket_addr(fd);
+
+ /* it might be the same as the last one - save some DNS work */
+ if (strcmp(p, addr_buf) == 0) return name_buf;
+
+ pstrcpy(name_buf,"UNKNOWN");
+ if (fd == -1) return name_buf;
+
+ fstrcpy(addr_buf, p);
+
+ addr = *interpret_addr2(p);
+
+ /* Look up the remote host name. */
+ if ((hp = gethostbyaddr((char *)&addr.s_addr, sizeof(addr.s_addr), AF_INET)) == 0) {
+ DEBUG(1,("Gethostbyaddr failed for %s\n",p));
+ pstrcpy(name_buf, p);
+ } else {
+ pstrcpy(name_buf,(char *)hp->h_name);
+ if (!matchname(name_buf, addr)) {
+ DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
+ pstrcpy(name_buf,"UNKNOWN");
+ }
+ }
+
+ alpha_strcpy(name_buf, name_buf, "_-.", sizeof(name_buf));
+ if (strstr(name_buf,"..")) {
+ pstrcpy(name_buf, "UNKNOWN");
+ }
+
+ return name_buf;
+}
+
+/*******************************************************************
+ return the IP addr of the remote end of a socket as a string
+ ******************************************************************/
+char *get_socket_addr(int fd)
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static fstring addr_buf;
+
+ fstrcpy(addr_buf,"0.0.0.0");
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (getpeername(fd, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
+ return addr_buf;
+ }
+
+ fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+
+ return addr_buf;
+}
+
+/*******************************************************************
+ opens and connects to a unix pipe socket
+ ******************************************************************/
+int open_pipe_sock(char *path)
+{
+ int sock;
+ struct sockaddr_un sa;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock < 0)
+ {
+ DEBUG(0, ("unix socket open failed\n"));
+ return sock;
+ }
+
+ ZERO_STRUCT(sa);
+ sa.sun_family = AF_UNIX;
+ safe_strcpy(sa.sun_path, path, sizeof(sa.sun_path)-1);
+
+ DEBUG(10, ("socket open succeeded. file name: %s\n", sa.sun_path));
+
+ if (connect(sock, (struct sockaddr*) &sa, sizeof(sa)) < 0)
+ {
+ DEBUG(0,("socket connect to %s failed\n", sa.sun_path));
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+static int socketpair_tcp(int fd[2])
+{
+ int listener;
+ struct sockaddr_in sock;
+ struct sockaddr_in sock2;
+ socklen_t socklen = sizeof(sock);
+ int connect_done = 0;
+
+ fd[0] = fd[1] = listener = -1;
+
+ memset(&sock, 0, sizeof(sock));
+
+ if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCK_SIN_LEN
+ sock2.sin_len = sizeof(sock2);
+#endif
+ sock2.sin_family = PF_INET;
+
+ bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
+
+ if (listen(listener, 1) != 0) goto failed;
+
+ if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+ if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ set_blocking(fd[1], 0);
+
+ sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
+ if (errno != EINPROGRESS) goto failed;
+ } else {
+ connect_done = 1;
+ }
+
+ if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+ close(listener);
+ if (connect_done == 0) {
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
+ && errno != EISCONN) goto failed;
+ }
+
+ set_blocking(fd[1], 1);
+
+ /* all OK! */
+ return 0;
+
+ failed:
+ if (fd[0] != -1) close(fd[0]);
+ if (fd[1] != -1) close(fd[1]);
+ if (listener != -1) close(listener);
+ return -1;
+}
+
+
+/*******************************************************************
+run a program on a local tcp socket, this is used to launch smbd
+when regression testing
+the return value is a socket which is attached to a subprocess
+running "prog". stdin and stdout are attached. stderr is left
+attached to the original stderr
+ ******************************************************************/
+int sock_exec(const char *prog)
+{
+ int fd[2];
+ if (socketpair_tcp(fd) != 0) {
+ DEBUG(0,("socketpair_tcp failed (%s)\n", strerror(errno)));
+ return -1;
+ }
+ if (fork() == 0) {
+ close(fd[0]);
+ close(0);
+ close(1);
+ dup(fd[1]);
+ dup(fd[1]);
+ exit(system(prog));
+ }
+ close(fd[1]);
+ return fd[0];
+}
diff --git a/source/lib/util_str.c b/source/lib/util_str.c
new file mode 100644
index 00000000000..14d50384c28
--- /dev/null
+++ b/source/lib/util_str.c
@@ -0,0 +1,939 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Get the next token from a string, return False if none found
+ handles double-quotes.
+Based on a routine by GJC@VILLAGE.COM.
+Extensively modified by Andrew.Tridgell@anu.edu.au
+****************************************************************************/
+BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
+{
+ char *s;
+ BOOL quoted;
+ size_t len=1;
+
+ if (!ptr) return(False);
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep) sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while (*s && strchr_m(sep,*s)) s++;
+
+ /* nothing left? */
+ if (! *s) return(False);
+
+ /* copy over the token */
+ for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+This is like next_token but is not re-entrant and "remembers" the first
+parameter so you can pass NULL. This is useful for user interface code
+but beware the fact that it is not re-entrant!
+****************************************************************************/
+static char *last_ptr=NULL;
+
+BOOL next_token_nr(char **ptr,char *buff,char *sep, size_t bufsize)
+{
+ BOOL ret;
+ if (!ptr) ptr = &last_ptr;
+
+ ret = next_token(ptr, buff, sep, bufsize);
+ last_ptr = *ptr;
+ return ret;
+}
+
+static uint16 tmpbuf[sizeof(pstring)];
+
+void set_first_token(char *ptr)
+{
+ last_ptr = ptr;
+}
+
+
+/****************************************************************************
+Convert list of tokens to array; dependent on above routine.
+Uses last_ptr from above - bit of a hack.
+****************************************************************************/
+char **toktocliplist(int *ctok, char *sep)
+{
+ char *s=last_ptr;
+ int ictok=0;
+ char **ret, **iret;
+
+ if (!sep) sep = " \t\n\r";
+
+ while(*s && strchr_m(sep,*s)) s++;
+
+ /* nothing left? */
+ if (!*s) return(NULL);
+
+ do {
+ ictok++;
+ while(*s && (!strchr_m(sep,*s))) s++;
+ while(*s && strchr_m(sep,*s)) *s++=0;
+ } while(*s);
+
+ *ctok=ictok;
+ s=last_ptr;
+
+ if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
+
+ while(ictok--) {
+ *iret++=s;
+ while(*s++);
+ while(!*s) s++;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ case insensitive string compararison
+********************************************************************/
+int StrCaseCmp(const char *s, const char *t)
+{
+ pstring buf1, buf2;
+ unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
+ unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
+ return strcmp(buf1,buf2);
+}
+
+/*******************************************************************
+ case insensitive string compararison, length limited
+********************************************************************/
+int StrnCaseCmp(const char *s, const char *t, size_t n)
+{
+ pstring buf1, buf2;
+ unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
+ unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
+ return strncmp(buf1,buf2,n);
+}
+
+/*******************************************************************
+ compare 2 strings
+********************************************************************/
+BOOL strequal(const char *s1, const char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(StrCaseCmp(s1,s2)==0);
+}
+
+/*******************************************************************
+ compare 2 strings up to and including the nth char.
+ ******************************************************************/
+BOOL strnequal(const char *s1,const char *s2,size_t n)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2 || !n) return(False);
+
+ return(StrnCaseCmp(s1,s2,n)==0);
+}
+
+/*******************************************************************
+ compare 2 strings (case sensitive)
+********************************************************************/
+BOOL strcsequal(const char *s1,const char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(strcmp(s1,s2)==0);
+}
+
+/***************************************************************************
+Do a case-insensitive, whitespace-ignoring string compare.
+***************************************************************************/
+int strwicmp(const char *psz1, const char *psz2)
+{
+ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
+ /* appropriate value. */
+ if (psz1 == psz2)
+ return (0);
+ else if (psz1 == NULL)
+ return (-1);
+ else if (psz2 == NULL)
+ return (1);
+
+ /* sync the strings on first non-whitespace */
+ while (1)
+ {
+ while (isspace((int)*psz1))
+ psz1++;
+ while (isspace((int)*psz2))
+ psz2++;
+ if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
+ || *psz2 == '\0')
+ break;
+ psz1++;
+ psz2++;
+ }
+ return (*psz1 - *psz2);
+}
+
+
+/*******************************************************************
+ convert a string to "normal" form
+********************************************************************/
+void strnorm(char *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ strupper(s);
+ else
+ strlower(s);
+}
+
+/*******************************************************************
+check if a string is in "normal" case
+********************************************************************/
+BOOL strisnormal(char *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ return(!strhaslower(s));
+
+ return(!strhasupper(s));
+}
+
+
+/****************************************************************************
+ string replace
+ NOTE: oldc and newc must be 7 bit characters
+****************************************************************************/
+void string_replace(char *s,char oldc,char newc)
+{
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
+ pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
+}
+
+
+/*******************************************************************
+skip past some strings in a buffer
+********************************************************************/
+char *skip_string(char *buf,size_t n)
+{
+ while (n--)
+ buf += strlen(buf) + 1;
+ return(buf);
+}
+
+/*******************************************************************
+ Count the number of characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+********************************************************************/
+size_t str_charnum(const char *s)
+{
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ return strlen_w(tmpbuf);
+}
+
+/*******************************************************************
+trim the specified elements off the front and back of a string
+********************************************************************/
+
+BOOL trim_string(char *s,const char *front,const char *back)
+{
+ BOOL ret = False;
+ size_t front_len;
+ size_t back_len;
+ size_t len;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0'))
+ return False;
+
+ front_len = front? strlen(front) : 0;
+ back_len = back? strlen(back) : 0;
+
+ len = strlen(s);
+
+ if (front_len) {
+ while (len && strncmp(s, front, front_len)==0) {
+ memcpy(s, s+front_len, (len-front_len)+1);
+ len -= front_len;
+ ret=True;
+ }
+ }
+
+ if (back_len) {
+ while (strncmp(s+len-back_len,back,back_len)==0) {
+ s[len-back_len]='\0';
+ len -= back_len;
+ ret=True;
+ }
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+does a string have any uppercase chars in it?
+****************************************************************************/
+BOOL strhasupper(const char *s)
+{
+ smb_ucs2_t *ptr;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++)
+ if(isupper_w(*ptr)) return True;
+ return(False);
+}
+
+/****************************************************************************
+does a string have any lowercase chars in it?
+****************************************************************************/
+BOOL strhaslower(const char *s)
+{
+ smb_ucs2_t *ptr;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++)
+ if(islower_w(*ptr)) return True;
+ return(False);
+}
+
+/****************************************************************************
+find the number of 'c' chars in a string
+****************************************************************************/
+size_t count_chars(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+ int count;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(count=0,ptr=tmpbuf;*ptr;ptr++) if(*ptr==UCS2_CHAR(c)) count++;
+ return(count);
+}
+
+/*******************************************************************
+Return True if a string consists only of one particular character.
+********************************************************************/
+
+BOOL str_is_all(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+
+ if(s == NULL) return False;
+ if(!*s) return False;
+
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++) if(*ptr!=UCS2_CHAR(c)) return False;
+
+ return True;
+}
+
+/*******************************************************************
+safe string copy into a known length string. maxlength does not
+include the terminating zero.
+********************************************************************/
+
+char *safe_strcpy(char *dest,const char *src, size_t maxlength)
+{
+ size_t len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+
+ if (len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
+ (int)(len-maxlength), src));
+ len = maxlength;
+ }
+
+ memmove(dest, src, len);
+ dest[len] = 0;
+ return dest;
+}
+
+/*******************************************************************
+safe string cat into a string. maxlength does not
+include the terminating zero.
+********************************************************************/
+
+char *safe_strcat(char *dest, const char *src, size_t maxlength)
+{
+ size_t src_len, dest_len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ return dest;
+ }
+
+ src_len = strlen(src);
+ dest_len = strlen(dest);
+
+ if (src_len + dest_len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
+ (int)(src_len + dest_len - maxlength), src));
+ src_len = maxlength - dest_len;
+ }
+
+ memcpy(&dest[dest_len], src, src_len);
+ dest[dest_len + src_len] = 0;
+ return dest;
+}
+
+/*******************************************************************
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
+ and replaces with '_'. Deliberately does *NOT* check for multibyte
+ characters. Don't change it !
+********************************************************************/
+
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
+{
+ size_t len, i;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+ if (len >= maxlength)
+ len = maxlength - 1;
+
+ if (!other_safe_chars)
+ other_safe_chars = "";
+
+ for(i = 0; i < len; i++) {
+ int val = (src[i] & 0xff);
+ if(isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
+ dest[i] = src[i];
+ else
+ dest[i] = '_';
+ }
+
+ dest[i] = '\0';
+
+ return dest;
+}
+
+/****************************************************************************
+ Like strncpy but always null terminates. Make sure there is room!
+ The variable n should always be one less than the available size.
+****************************************************************************/
+
+char *StrnCpy(char *dest,const char *src,size_t n)
+{
+ char *d = dest;
+ if (!dest) return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while (n-- && (*d++ = *src++)) ;
+ *d = 0;
+ return(dest);
+}
+
+/****************************************************************************
+like strncpy but copies up to the character marker. always null terminates.
+returns a pointer to the character marker in the source string (src).
+****************************************************************************/
+char *strncpyn(char *dest, const char *src,size_t n, char c)
+{
+ char *p;
+ size_t str_len;
+
+ p = strchr_m(src, c);
+ if (p == NULL)
+ {
+ DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
+ return NULL;
+ }
+
+ str_len = PTR_DIFF(p, src);
+ strncpy(dest, src, MIN(n, str_len));
+ dest[str_len] = '\0';
+
+ return p;
+}
+
+
+/*************************************************************
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped. "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+**************************************************************/
+size_t strhex_to_str(char *p, size_t len, const char *strhex)
+{
+ size_t i;
+ size_t num_chars = 0;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1 = NULL, *p2 = NULL;
+
+ for (i = 0; i < len && strhex[i] != 0; i++)
+ {
+ if (strnequal(hexchars, "0x", 2))
+ {
+ i++; /* skip two chars */
+ continue;
+ }
+
+ if (!(p1 = strchr_m(hexchars, toupper(strhex[i]))))
+ {
+ break;
+ }
+
+ i++; /* next hex digit */
+
+ if (!(p2 = strchr_m(hexchars, toupper(strhex[i]))))
+ {
+ break;
+ }
+
+ /* get the two nybbles */
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ p[num_chars] = (hinybble << 4) | lonybble;
+ num_chars++;
+
+ p1 = NULL;
+ p2 = NULL;
+ }
+ return num_chars;
+}
+
+/****************************************************************************
+check if a string is part of a list
+****************************************************************************/
+BOOL in_list(char *s,char *list,BOOL casesensitive)
+{
+ pstring tok;
+ char *p=list;
+
+ if (!list) return(False);
+
+ while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
+ if (casesensitive) {
+ if (strcmp(tok,s) == 0)
+ return(True);
+ } else {
+ if (StrCaseCmp(tok,s) == 0)
+ return(True);
+ }
+ }
+ return(False);
+}
+
+/* this is used to prevent lots of mallocs of size 1 */
+static char *null_string = NULL;
+
+/****************************************************************************
+set a string value, allocing the space for the string
+****************************************************************************/
+static BOOL string_init(char **dest,const char *src)
+{
+ size_t l;
+ if (!src)
+ src = "";
+
+ l = strlen(src);
+
+ if (l == 0)
+ {
+ if (!null_string) {
+ if((null_string = (char *)malloc(1)) == NULL) {
+ DEBUG(0,("string_init: malloc fail for null_string.\n"));
+ return False;
+ }
+ *null_string = 0;
+ }
+ *dest = null_string;
+ }
+ else
+ {
+ (*dest) = (char *)malloc(l+1);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
+ }
+
+ pstrcpy(*dest,src);
+ }
+ return(True);
+}
+
+/****************************************************************************
+free a string value
+****************************************************************************/
+void string_free(char **s)
+{
+ if (!s || !(*s)) return;
+ if (*s == null_string)
+ *s = NULL;
+ SAFE_FREE(*s);
+}
+
+/****************************************************************************
+set a string value, allocing the space for the string, and deallocating any
+existing space
+****************************************************************************/
+BOOL string_set(char **dest,const char *src)
+{
+ string_free(dest);
+
+ return(string_init(dest,src));
+}
+
+
+/****************************************************************************
+substitute a string for a pattern in another string. Make sure there is
+enough room!
+
+This routine looks for pattern in s and replaces it with
+insert. It may do multiple replacements.
+
+any of " ; ' $ or ` in the insert string are replaced with _
+if len==0 then no length check is performed
+****************************************************************************/
+void string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li, i;
+
+ if (!insert || !pattern || !s) return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern) return;
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (len && (ls + (li-lp) >= len)) {
+ DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ for (i=0;i<li;i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ case '%':
+ case '\r':
+ case '\n':
+ p[i] = '_';
+ break;
+ default:
+ p[i] = insert[i];
+ }
+ }
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+void fstring_sub(char *s,const char *pattern,const char *insert)
+{
+ string_sub(s, pattern, insert, sizeof(fstring));
+}
+
+void pstring_sub(char *s,const char *pattern,const char *insert)
+{
+ string_sub(s, pattern, insert, sizeof(pstring));
+}
+
+/****************************************************************************
+similar to string_sub() but allows for any character to be substituted.
+Use with caution!
+if len==0 then no length check is performed
+****************************************************************************/
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li;
+
+ if (!insert || !pattern || !s) return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern) return;
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (len && (ls + (li-lp) >= len)) {
+ DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, insert, li);
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+/****************************************************************************
+similar to all_string_sub but for unicode strings.
+return a new allocate unicode string.
+len is the number of bytes, not chars
+ similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then no length check is performed
+****************************************************************************/
+
+smb_ucs2_t *all_string_sub_w(smb_ucs2_t *s, const smb_ucs2_t *pattern,
+ const smb_ucs2_t *insert)
+{
+ smb_ucs2_t *r, *rp, *sp;
+ size_t lr, lp, li, lt;
+
+ if (!insert || !pattern || !*pattern || !s) return NULL;
+
+ lt = (size_t)strlen_w(s);
+ lp = (size_t)strlen_w(pattern);
+ li = (size_t)strlen_w(insert);
+
+ if (li > lp) {
+ smb_ucs2_t *st = s;
+ int ld = li - lp;
+ while ((sp = strstr_w(st, pattern))) {
+ st = sp + lp;
+ lt += ld;
+ }
+ }
+
+ r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
+ if (!r) {
+ DEBUG(0, ("all_string_sub_w: out of memory!\n"));
+ return NULL;
+ }
+
+ while ((sp = strstr_w(s, pattern))) {
+ memcpy(rp, s, (sp - s));
+ rp += ((sp - s) / sizeof(smb_ucs2_t));
+ memcpy(rp, insert, (li * sizeof(smb_ucs2_t)));
+ s = sp + lp;
+ rp += li;
+ }
+ lr = ((rp - r) / sizeof(smb_ucs2_t));
+ if (lr < lt) {
+ memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t)));
+ rp += (lt - lr);
+ }
+ *rp = 0;
+
+ return r;
+}
+
+smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
+ const char *insert)
+{
+ wpstring p, i;
+
+ if (!insert || !pattern || !s) return NULL;
+ push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
+ push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
+ return all_string_sub_w(s, p, i);
+}
+
+/****************************************************************************
+ splits out the front and back at a separator.
+****************************************************************************/
+void split_at_last_component(char *path, char *front, char sep, char *back)
+{
+ char *p = strrchr_m(path, sep);
+
+ if (p != NULL)
+ {
+ *p = 0;
+ }
+ if (front != NULL)
+ {
+ pstrcpy(front, path);
+ }
+ if (p != NULL)
+ {
+ if (back != NULL)
+ {
+ pstrcpy(back, p+1);
+ }
+ *p = '\\';
+ }
+ else
+ {
+ if (back != NULL)
+ {
+ back[0] = 0;
+ }
+ }
+}
+
+
+/****************************************************************************
+write an octal as a string
+****************************************************************************/
+char *octal_string(int i)
+{
+ static char ret[64];
+ if (i == -1) {
+ return "-1";
+ }
+ slprintf(ret, sizeof(ret)-1, "0%o", i);
+ return ret;
+}
+
+
+/****************************************************************************
+truncate a string at a specified length
+****************************************************************************/
+char *string_truncate(char *s, int length)
+{
+ if (s && strlen(s) > length) {
+ s[length] = 0;
+ }
+ return s;
+}
+
+
+/****************************************************************************
+strchr and strrchr_m are very hard to do on general multi-byte strings.
+we convert via ucs2 for now
+****************************************************************************/
+char *strchr_m(const char *s, char c)
+{
+ wpstring ws;
+ pstring s2;
+ smb_ucs2_t *p;
+
+ push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+ p = strchr_w(ws, UCS2_CHAR(c));
+ if (!p) return NULL;
+ *p = 0;
+ pull_ucs2_pstring(s2, ws);
+ return (char *)(s+strlen(s2));
+}
+
+char *strrchr_m(const char *s, char c)
+{
+ wpstring ws;
+ pstring s2;
+ smb_ucs2_t *p;
+
+ push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+ p = strrchr_w(ws, UCS2_CHAR(c));
+ if (!p) return NULL;
+ *p = 0;
+ pull_ucs2_pstring(s2, ws);
+ return (char *)(s+strlen(s2));
+}
+
+/*******************************************************************
+ convert a string to lower case
+********************************************************************/
+void strlower_m(char *s)
+{
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in UTF-8 encoding. (VIV) */
+ unix_strlower(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+/*******************************************************************
+ convert a string to upper case
+********************************************************************/
+void strupper_m(char *s)
+{
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in multibyte encoding. (VIV) */
+ unix_strupper(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+/*
+ return a RFC2254 binary string representation of a buffer
+ used in LDAP filters
+ caller must free
+*/
+char *binary_string(char *buf, int len)
+{
+ char *s;
+ int i, j;
+ const char *hex = "0123456789ABCDEF";
+ s = malloc(len * 3 + 1);
+ if (!s) return NULL;
+ for (j=i=0;i<len;i++) {
+ s[j] = '\\';
+ s[j+1] = hex[((unsigned char)buf[i]) >> 4];
+ s[j+2] = hex[((unsigned char)buf[i]) & 0xF];
+ j += 3;
+ }
+ s[j] = 0;
+ return s;
+}
+
diff --git a/source/lib/util_unistr.c b/source/lib/util_unistr.c
new file mode 100644
index 00000000000..0a0424763df
--- /dev/null
+++ b/source/lib/util_unistr.c
@@ -0,0 +1,729 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifndef MAXUNI
+#define MAXUNI 1024
+#endif
+
+/* these 3 tables define the unicode case handling. They are loaded
+ at startup either via mmap() or read() from the lib directory */
+static smb_ucs2_t *upcase_table;
+static smb_ucs2_t *lowcase_table;
+static uint8 *valid_table;
+
+
+/*******************************************************************
+load the case handling tables
+********************************************************************/
+void load_case_tables(void)
+{
+ static int initialised;
+ int i;
+
+ if (initialised) return;
+ initialised = 1;
+
+ upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
+ lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
+
+ /* we would like Samba to limp along even if these tables are
+ not available */
+ if (!upcase_table) {
+ DEBUG(1,("creating lame upcase table\n"));
+ upcase_table = malloc(0x20000);
+ for (i=0;i<0x10000;i++) upcase_table[i] = i;
+ for (i=0;i<256;i++) upcase_table[UCS2_CHAR(i)] = UCS2_CHAR(islower(i)?toupper(i):i);
+ }
+
+ if (!lowcase_table) {
+ DEBUG(1,("creating lame lowcase table\n"));
+ lowcase_table = malloc(0x20000);
+ for (i=0;i<0x10000;i++) lowcase_table[i] = i;
+ for (i=0;i<256;i++) lowcase_table[UCS2_CHAR(i)] = UCS2_CHAR(isupper(i)?tolower(i):i);
+ }
+}
+
+/*
+ see if a ucs2 character can be mapped correctly to a dos character
+ and mapped back to the same character in ucs2
+*/
+static int check_dos_char(smb_ucs2_t c)
+{
+ char buf[10];
+ smb_ucs2_t c2 = 0;
+ int len1, len2;
+ len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf));
+ if (len1 == 0) return 0;
+ len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2);
+ if (len2 != 2) return 0;
+ return (c == c2);
+}
+
+/*******************************************************************
+load the valid character map table
+********************************************************************/
+void init_valid_table(void)
+{
+ static int initialised;
+ static int mapped_file;
+ int i;
+ const char *allowed = ".!#$%&'()_-@^`~";
+
+ if (initialised && mapped_file) return;
+ initialised = 1;
+
+ valid_table = map_file(lib_path("valid.dat"), 0x10000);
+ if (valid_table) {
+ mapped_file = 1;
+ return;
+ }
+
+ if (valid_table) free(valid_table);
+
+ DEBUG(2,("creating default valid table\n"));
+ valid_table = malloc(0x10000);
+ for (i=0;i<128;i++) valid_table[UCS2_CHAR(i)] = isalnum(i) ||
+ strchr(allowed,i);
+ for (;i<0x10000;i++) {
+ smb_ucs2_t c;
+ SSVAL(&c, 0, i);
+ valid_table[c] = check_dos_char(c);
+ }
+}
+
+
+/*******************************************************************
+ Write a string in (little-endian) unicode format. src is in
+ the current DOS codepage. len is the length in bytes of the
+ string pointed to by dst.
+
+ if null_terminate is True then null terminate the packet (adds 2 bytes)
+
+ the return value is the length in bytes consumed by the string, including the
+ null termination if applied
+********************************************************************/
+
+size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
+{
+ return push_ucs2(NULL, dst, src, len,
+ STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
+}
+
+
+/*******************************************************************
+ Skip past a unicode string, but not more than len. Always move
+ past a terminating zero if found.
+********************************************************************/
+
+char *skip_unibuf(char *src, size_t len)
+{
+ char *srcend = src + len;
+
+ while (src < srcend && SVAL(src,0))
+ src += 2;
+
+ if(!SVAL(src,0))
+ src += 2;
+
+ return src;
+}
+
+/* Copy a string from little-endian or big-endian unicode source (depending
+ * on flags) to internal samba format destination
+ */
+int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
+{
+ if(dest_len==-1) dest_len=MAXUNI-3;
+ return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/* Copy a string from a unistr2 source to internal samba format
+ destination. Use this instead of direct calls to rpcstr_pull() to avoid
+ having to determine whether the source string is null terminated. */
+
+int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
+{
+ return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
+ src->uni_str_len * 2, 0);
+}
+
+/* Converts a string from internal samba format to unicode
+ */
+int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
+{
+ return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/*******************************************************************
+ Return a DOS codepage version of a little-endian unicode string.
+ len is the filename length (ignoring any terminating zero) in uin16
+ units. Always null terminates.
+ Hack alert: uses fixed buffer(s).
+********************************************************************/
+char *dos_unistrn2(const uint16 *src, int len)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ nexti = (nexti+1)%8;
+ pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
+ return lbuf;
+}
+
+/*******************************************************************
+ Convert a (little-endian) UNISTR2 structure to an ASCII string
+********************************************************************/
+void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
+{
+ if (str == NULL) {
+ *dest='\0';
+ return;
+ }
+ pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
+}
+
+
+/*******************************************************************
+ duplicate a UNISTR2 string into a null terminated char*
+ using a talloc context
+********************************************************************/
+char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
+{
+ char *s;
+ int maxlen = (str->uni_str_len+1)*4;
+ if (!str->buffer) return NULL;
+ s = (char *)talloc(ctx, maxlen); /* convervative */
+ if (!s) return NULL;
+ pull_ucs2(NULL, s, str->buffer, maxlen, str->uni_str_len*2,
+ STR_NOALIGN);
+ return s;
+}
+
+
+/*******************************************************************
+Return a number stored in a buffer
+********************************************************************/
+
+uint32 buffer2_to_uint32(BUFFER2 *str)
+{
+ if (str->buf_len == 4)
+ return IVAL(str->buffer, 0);
+ else
+ return 0;
+}
+
+/*******************************************************************
+ Convert a wchar to upper case.
+********************************************************************/
+
+smb_ucs2_t toupper_w(smb_ucs2_t val)
+{
+ return upcase_table[val];
+}
+
+/*******************************************************************
+ Convert a wchar to lower case.
+********************************************************************/
+
+smb_ucs2_t tolower_w( smb_ucs2_t val )
+{
+ return lowcase_table[val];
+}
+
+/*******************************************************************
+determine if a character is lowercase
+********************************************************************/
+BOOL islower_w(smb_ucs2_t c)
+{
+ return upcase_table[c] != c;
+}
+
+/*******************************************************************
+determine if a character is uppercase
+********************************************************************/
+BOOL isupper_w(smb_ucs2_t c)
+{
+ return lowcase_table[c] != c;
+}
+
+
+/*******************************************************************
+determine if a character is valid in a 8.3 name
+********************************************************************/
+BOOL isvalid83_w(smb_ucs2_t c)
+{
+ return valid_table[c] != 0;
+}
+
+/*******************************************************************
+ Count the number of characters in a smb_ucs2_t string.
+********************************************************************/
+size_t strlen_w(const smb_ucs2_t *src)
+{
+ size_t len;
+
+ for(len = 0; *src++; len++) ;
+
+ return len;
+}
+
+/*******************************************************************
+ Count up to max number of characters in a smb_ucs2_t string.
+********************************************************************/
+size_t strnlen_w(const smb_ucs2_t *src, size_t max)
+{
+ size_t len;
+
+ for(len = 0; *src++ && (len < max); len++) ;
+
+ return len;
+}
+
+/*******************************************************************
+wide strchr()
+********************************************************************/
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ while (*s != 0) {
+ if (c == *s) return (smb_ucs2_t *)s;
+ s++;
+ }
+ return NULL;
+}
+
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
+{
+ return strchr_w(s, UCS2_CHAR(c));
+}
+
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+ if (len == 0) return NULL;
+ p += (len - 1);
+ do {
+ if (c == *p) return (smb_ucs2_t *)p;
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+wide strstr()
+********************************************************************/
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
+{
+ smb_ucs2_t *r;
+ size_t slen, inslen;
+
+ if (!s || !*s || !ins || !*ins) return NULL;
+ slen = strlen_w(s);
+ inslen = strlen_w(ins);
+ r = (smb_ucs2_t *)s;
+ while ((r = strchr_w(r, *ins))) {
+ if (strncmp_w(r, ins, inslen) == 0) return r;
+ r++;
+ }
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a string to lower case.
+ return True if any char is converted
+********************************************************************/
+BOOL strlower_w(smb_ucs2_t *s)
+{
+ BOOL ret = False;
+ while (*s) {
+ smb_ucs2_t v = tolower_w(*s);
+ if (v != *s) {
+ *s = v;
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Convert a string to upper case.
+ return True if any char is converted
+********************************************************************/
+BOOL strupper_w(smb_ucs2_t *s)
+{
+ BOOL ret = False;
+ while (*s) {
+ smb_ucs2_t v = toupper_w(*s);
+ if (v != *s) {
+ *s = v;
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ convert a string to "normal" form
+********************************************************************/
+void strnorm_w(smb_ucs2_t *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ strupper_w(s);
+ else
+ strlower_w(s);
+}
+
+int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ while (*b && *a == *b) { a++; b++; }
+ return (*a - *b);
+ /* warning: if *a != *b and both are not 0 we retrun a random
+ greater or lesser than 0 number not realted to which
+ string is longer */
+}
+
+int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && *a == *b) { a++; b++; n++;}
+ return (len - n)?(*a - *b):0;
+}
+
+/*******************************************************************
+case insensitive string comparison
+********************************************************************/
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
+ return (tolower_w(*a) - tolower_w(*b));
+}
+
+/*******************************************************************
+case insensitive string comparison, lenght limited
+********************************************************************/
+int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && (toupper_w(*a) == toupper_w(*b))) { a++; b++; n++; }
+ return (len - n)?(tolower_w(*a) - tolower_w(*b)):0;
+}
+
+/*******************************************************************
+ compare 2 strings
+********************************************************************/
+BOOL strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(strcasecmp_w(s1,s2)==0);
+}
+
+/*******************************************************************
+ compare 2 strings up to and including the nth char.
+ ******************************************************************/
+BOOL strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2 || !n) return(False);
+
+ return(strncasecmp_w(s1,s2,n)==0);
+}
+
+/*******************************************************************
+duplicate string
+********************************************************************/
+smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
+{
+ return strndup_w(src, 0);
+}
+
+/* if len == 0 then duplicate the whole string */
+smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
+{
+ smb_ucs2_t *dest;
+
+ if (!len) len = strlen_w(src);
+ dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
+ if (!dest) {
+ DEBUG(0,("strdup_w: out of memory!\n"));
+ return NULL;
+ }
+
+ memcpy(dest, src, len * sizeof(smb_ucs2_t));
+ dest[len] = 0;
+
+ return dest;
+}
+
+/*******************************************************************
+copy a string with max len
+********************************************************************/
+
+smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ for (len = 0; (src[len] != 0) && (len < max); len++)
+ dest[len] = src[len];
+ while (len < max)
+ dest[len++] = 0;
+
+ return dest;
+}
+
+
+/*******************************************************************
+append a string of len bytes and add a terminator
+********************************************************************/
+
+smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ size_t start;
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ start = strlen_w(dest);
+ len = strnlen_w(src, max);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ dest[start+len] = 0;
+
+ return dest;
+}
+
+smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
+{
+ size_t start;
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ start = strlen_w(dest);
+ len = strlen_w(src);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ dest[start+len] = 0;
+
+ return dest;
+}
+
+
+/*******************************************************************
+replace any occurence of oldc with newc in unicode string
+********************************************************************/
+
+void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
+{
+ for(;*s;s++) {
+ if(*s==oldc) *s=newc;
+ }
+}
+
+/*******************************************************************
+trim unicode string
+********************************************************************/
+
+BOOL trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
+ const smb_ucs2_t *back)
+{
+ BOOL ret = False;
+ size_t len, front_len, back_len;
+
+ if (!s || !*s) return False;
+
+ len = strlen_w(s);
+
+ if (front && *front) {
+ front_len = strlen_w(front);
+ while (len && strncmp_w(s, front, front_len) == 0) {
+ memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
+ len -= front_len;
+ ret = True;
+ }
+ }
+
+ if (back && *back) {
+ back_len = strlen_w(back);
+ while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
+ s[len - back_len] = 0;
+ len -= back_len;
+ ret = True;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ The *_wa() functions take a combination of 7 bit ascii
+ and wide characters They are used so that you can use string
+ functions combining C string constants with ucs2 strings
+
+ The char* arguments must NOT be multibyte - to be completely sure
+ of this only pass string constants */
+
+
+void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
+{
+ int i;
+ for (i=0;i<PSTRING_LEN;i++) {
+ dest[i] = UCS2_CHAR(src[i]);
+ if (src[i] == 0) return;
+ }
+}
+
+int strcmp_wa(const smb_ucs2_t *a, const char *b)
+{
+ while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
+ return (*a - UCS2_CHAR(*b));
+}
+
+int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && *a == UCS2_CHAR(*b)) { a++; b++; n++;}
+ return (len - n)?(*a - UCS2_CHAR(*b)):0;
+}
+
+smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
+{
+ while (*s != 0) {
+ int i;
+ for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++)
+ ;
+ if (p[i]) return (smb_ucs2_t *)s;
+ s++;
+ }
+ return NULL;
+}
+
+smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
+{
+ smb_ucs2_t *r;
+ size_t slen, inslen;
+
+ if (!s || !*s || !ins || !*ins) return NULL;
+ slen = strlen_w(s);
+ inslen = strlen(ins);
+ r = (smb_ucs2_t *)s;
+ while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
+ if (strncmp_wa(r, ins, inslen) == 0) return r;
+ r++;
+ }
+ return NULL;
+}
+
+/*******************************************************************
+copy a string with max len
+********************************************************************/
+
+smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strncpy_w(dest, ucs2_src, max);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+/*******************************************************************
+convert and duplicate an ascii string
+********************************************************************/
+smb_ucs2_t *strdup_wa(const char *src)
+{
+ return strndup_wa(src, 0);
+}
+
+/* if len == 0 then duplicate the whole string */
+smb_ucs2_t *strndup_wa(const char *src, size_t len)
+{
+ smb_ucs2_t *dest, *s;
+
+ s = acnv_dosu2(src);
+ if (!len) len = strlen_w(s);
+ dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
+ if (!dest) {
+ DEBUG(0,("strdup_w: out of memory!\n"));
+ SAFE_FREE(s);
+ return NULL;
+ }
+
+ memcpy(dest, src, len * sizeof(smb_ucs2_t));
+ dest[len] = 0;
+
+ SAFE_FREE(s);
+ return dest;
+}
+
+/*******************************************************************
+append a string of len bytes and add a terminator
+********************************************************************/
+
+smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strncat_w(dest, ucs2_src, max);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+smb_ucs2_t *strcat_wa(smb_ucs2_t *dest, const char *src)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strcat_w(dest, ucs2_src);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+BOOL trim_string_wa(smb_ucs2_t *s, const char *front,
+ const char *back)
+{
+ wpstring f, b;
+
+ if (front) push_ucs2(NULL, f, front, sizeof(wpstring) - 1, STR_TERMINATE);
+ else *f = 0;
+ if (back) push_ucs2(NULL, b, back, sizeof(wpstring) - 1, STR_TERMINATE);
+ else *b = 0;
+ return trim_string_w(s, f, b);
+}
diff --git a/source/lib/wins_srv.c b/source/lib/wins_srv.c
new file mode 100644
index 00000000000..92cd51d8bbc
--- /dev/null
+++ b/source/lib/wins_srv.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Christopher R. Hertel 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Discussion...
+ *
+ * This module implements WINS failover.
+ *
+ * Microsoft's WINS servers provide a feature called WINS replication,
+ * which synchronises the WINS name databases between two or more servers.
+ * This means that the two servers can be used interchangably (more or
+ * less). WINS replication is particularly useful if you are trying to
+ * synchronise the WINS namespace between servers in remote locations, or
+ * if your WINS servers tend to crash a lot.
+ *
+ * WINS failover allows the client to 'switch' to a different WINS server
+ * if the current WINS server mysteriously disappears. On Windows
+ * systems, this is typically represented as 'primary' and 'secondary'
+ * WINS servers.
+ *
+ * Failover only works if the WINS servers are synced. If they are not,
+ * then
+ * a) if the primary WINS server never fails the client will never 'see'
+ * the secondary (or tertiary or...) WINS server name space.
+ * b) if the primary *does* fail, the client will be entering an
+ * unfamiliar namespace. The client itself will not be registered in
+ * that namespace and any names which match names in the previous
+ * space will likely resolve to different host IP addresses.
+ *
+ * One key thing to remember regarding WINS failover is that Samba does
+ * not (yet) implement WINS replication. For those interested, sniff port
+ * 42 (TCP? UDP? ...dunno off hand) and see what two MS WINS servers do.
+ *
+ * At this stage, only failover is implemented. The next thing is to add
+ * support for multi-WINS server registration and query (multi-membership).
+ *
+ * Multi-membership is a little wierd. The idea is that the client can
+ * register itself with multiple non-replicated WINS servers, and query
+ * all of those servers (in a prescribed sequence) to resolve a name.
+ *
+ * The implications of multi-membership are not quite clear. Worth
+ * trying, I suppose. Changes will be needed in the name query and
+ * registration code to accomodate this feature. Also, there will need to
+ * be some sort of syntax extension for the 'wins server' parameter in
+ * smb.conf. I'm thinking that a colon could be used as a separator.
+ *
+ * Of course, for each WINS namespace there might be multiple, synced WINS
+ * servers. The change to this module would likely be the addition of a
+ * linked list of linked lists.
+ *
+ * crh@samba.org
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ *
+ * NECROMANCYCLE - The dead server retry period, in seconds. When a WINS
+ * server is declared dead, wait this many seconds before
+ * attempting to communicate with it.
+ */
+
+#define NECROMANCYCLE 600 /* 600 seconds == 10 minutes. */
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ */
+
+typedef struct
+ {
+ ubi_slNode node; /* Linked list node structure. */
+ time_t mourning; /* If > current time then server is dead, Jim. */
+ char *server; /* DNS name or IP of NBNS server to query. */
+ struct in_addr ip_addr; /* Cache translated IP. */
+ } list_entry;
+
+/* -------------------------------------------------------------------------- **
+ * Private, static variables.
+ */
+
+static ubi_slNewList( wins_srv_list );
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+
+BOOL wins_srv_load_list( char *src )
+ /* ------------------------------------------------------------------------ **
+ * Create or recreate the linked list of failover WINS servers.
+ *
+ * Input: src - String of DNS names and/or IP addresses delimited by the
+ * characters listed in LIST_SEP (see include/local.h).
+ *
+ * Output: True if at least one name or IP could be parsed out of the
+ * list, else False.
+ *
+ * Notes: There is no syntax checking done on the names or IPs. We do
+ * check to see if the field is an IP, in which case we copy it
+ * to the ip_addr field of the entry. Don't bother to to a host
+ * name lookup on all names now. They're done as needed in
+ * wins_srv_ip().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ list_entry *entry;
+ char *p = src;
+ pstring wins_id_bufr;
+ unsigned long count;
+
+ /* Empty the list. */
+ while( NULL != (entry =(list_entry *)ubi_slRemHead( wins_srv_list )) )
+ {
+ SAFE_FREE( entry->server );
+ SAFE_FREE( entry );
+ }
+ (void)ubi_slInitList( wins_srv_list ); /* shouldn't be needed */
+
+ /* Parse out the DNS names or IP addresses of the WINS servers. */
+ DEBUG( 4, ("wins_srv_load_list(): Building WINS server list:\n") );
+ while( next_token( &p, wins_id_bufr, LIST_SEP, sizeof( wins_id_bufr ) ) )
+ {
+ entry = (list_entry *)malloc( sizeof( list_entry ) );
+ if( NULL == entry )
+ {
+ DEBUG( 0, ("wins_srv_load_list(): malloc(list_entry) failed.\n") );
+ }
+ else
+ {
+ entry->mourning = 0;
+ /* Create a copy of the server name and store it in the list. */
+ if( NULL == (entry->server = strdup( wins_id_bufr )) )
+ {
+ SAFE_FREE( entry );
+ DEBUG( 0,
+ ("wins_srv_load_list(): strdup(\"%s\") failed.\n", wins_id_bufr) );
+ }
+ else
+ {
+ /* Add server to list.
+ * If the server name was actually an IP address we will store that
+ * too. It it was a DNS name, we will wait until we need to use
+ * the WINS server before doing the DNS lookup. Since this may be
+ * a list, and since we will reload the list whenever smb.conf is
+ * reloaded, there's no point in trying to look up names until we
+ * need them. ...of course, once we do the lookup we will cache
+ * the result. See wins_srv_ip().
+ */
+ if( is_ipaddress( wins_id_bufr ) )
+ entry->ip_addr = *interpret_addr2( wins_id_bufr );
+ else
+ entry->ip_addr = *interpret_addr2( "0.0.0.0" );
+ (void)ubi_slAddTail( wins_srv_list, entry );
+ DEBUGADD( 4, ("%s,\n", wins_id_bufr) );
+ }
+ }
+ }
+
+ count = ubi_slCount( wins_srv_list );
+ DEBUGADD( 4,
+ ( "%d WINS server%s listed.\n", (int)count, (1==count)?"":"s" ) );
+
+ return( (count > 0) ? True : False );
+ } /* wins_srv_load_list */
+
+
+struct in_addr wins_srv_ip( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the IP address of an NBNS (WINS) server thought to be active.
+ *
+ * Input: none.
+ *
+ * Output: An IP address in struct in_addr form.
+ *
+ * Notes: This function will return the IP address of the first available
+ * NBNS (WINS) server. The order of the list is determined in
+ * smb.conf. If all of the WINS servers have been marked 'dead'
+ * then the zero IP (0.0.0.0) is returned. The zero IP is not a
+ * valid Unicast address on any system.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ time_t now = time(NULL);
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+
+ while( NULL != entry )
+ {
+ if( now >= entry->mourning ) /* Found a live one. */
+ {
+ /* If we don't have the IP, look it up. */
+ if( is_zero_ip( entry->ip_addr ) )
+ entry->ip_addr = *interpret_addr2( entry->server );
+
+ /* If we still don't have the IP then kill it, else return it. */
+ if( is_zero_ip( entry->ip_addr ) )
+ entry->mourning = now + NECROMANCYCLE;
+ else
+ return( entry->ip_addr );
+ }
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ /* If there are no live entries, return the zero IP. */
+ return( *interpret_addr2( "0.0.0.0" ) );
+ } /* wins_srv_ip */
+
+
+char *wins_srv_name( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the name of first live WINS server in the list.
+ *
+ * Input: none.
+ *
+ * Output: A pointer to a string containing either the DNS name or IP
+ * address of the WINS server as given in the WINS SERVER
+ * parameter in smb.conf, or NULL if no (live) WINS servers are
+ * in the list.
+ *
+ * Notes: This function will return the name of the first available
+ * NBNS (WINS) server. The order of the list is determined in
+ * smb.conf. If all of the WINS servers have been marked 'dead'
+ * then NULL is returned.
+ *
+ * - This function does not verify that the name can be mapped to
+ * an IP address, or that the WINS server is running.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ time_t now = time(NULL);
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+
+ while( NULL != entry )
+ {
+ if( now >= entry->mourning )
+ return( entry->server ); /* Found a live one. */
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ /* If there are no live entries, return NULL. */
+ return( NULL );
+ } /* wins_srv_name */
+
+
+void wins_srv_died( struct in_addr boothill_ip )
+ /* ------------------------------------------------------------------------ **
+ * Called to indicate that a specific WINS server has died.
+ *
+ * Input: boothill_ip - IP address of an NBNS (WINS) server that has
+ * failed.
+ *
+ * Notes: This function marks the record 'dead' for NECROMANCYCLE
+ * seconds.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ list_entry *entry;
+
+ if( is_zero_ip( boothill_ip ) )
+ {
+ DEBUG( 4, ("wins_srv_died(): Invalid request to mark zero IP down.\n") );
+ return;
+ }
+
+ entry = (list_entry *)ubi_slFirst( wins_srv_list );
+ while( NULL != entry )
+ {
+ /* Match based on IP. */
+ if( ip_equal( boothill_ip, entry->ip_addr ) )
+ {
+ entry->mourning = time(NULL) + NECROMANCYCLE;
+ entry->ip_addr.s_addr = 0; /* Force a re-lookup at re-birth. */
+ DEBUG( 2, ( "wins_srv_died(): WINS server %s appears to be down.\n",
+ entry->server ) );
+ return;
+ }
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ if( DEBUGLVL( 1 ) )
+ {
+ dbgtext( "wins_srv_died(): Could not mark WINS server %s down.\n",
+ inet_ntoa( boothill_ip ) );
+ dbgtext( "Address not found in server list.\n" );
+ }
+ } /* wins_srv_died */
+
+
+unsigned long wins_srv_count( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the total number of entries in the list, dead or alive.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ unsigned long count = ubi_slCount( wins_srv_list );
+
+ if( DEBUGLVL( 8 ) )
+ {
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+ time_t now = time(NULL);
+
+ dbgtext( "wins_srv_count: WINS status: %ld servers.\n", count );
+ while( NULL != entry )
+ {
+ dbgtext( " %s <%s>: ", entry->server, inet_ntoa( entry->ip_addr ) );
+ if( now >= entry->mourning )
+ dbgtext( "alive\n" );
+ else
+ dbgtext( "dead for %d more seconds\n", (int)(entry->mourning - now) );
+
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+ }
+
+ return( count );
+ } /* wins_srv_count */
+
+/* ========================================================================== */
diff --git a/source/lib/xfile.c b/source/lib/xfile.c
new file mode 100644
index 00000000000..7fc519e451a
--- /dev/null
+++ b/source/lib/xfile.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ stdio replacement
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ stdio is very convenient, but on some systems the file descriptor
+ in FILE* is 8 bits, so it fails when more than 255 files are open.
+
+ XFILE replaces stdio. It is less efficient, but at least it works
+ when you have lots of files open
+
+ The main restriction on XFILE is that it doesn't support seeking,
+ and doesn't support O_RDWR. That keeps the code simple.
+*/
+
+#include "includes.h"
+
+static XFILE _x_stdin = { 0, NULL, NULL, 0, 0, O_RDONLY, X_IOFBF, 0 };
+static XFILE _x_stdout = { 1, NULL, NULL, 0, 0, O_WRONLY, X_IOLBF, 0 };
+static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
+
+XFILE *x_stdin = &_x_stdin;
+XFILE *x_stdout = &_x_stdout;
+XFILE *x_stderr = &_x_stderr;
+
+#define XBUFSIZE BUFSIZ
+
+#define X_FLAG_EOF 1
+#define X_FLAG_ERROR 2
+
+/* simulate setvbuf() */
+int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
+{
+ x_fflush(f);
+ if (f->bufused) return -1;
+
+ /* on files being read full buffering is the only option */
+ if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
+ mode = X_IOFBF;
+ }
+
+ /* destroy any earlier buffer */
+ SAFE_FREE(f->buf);
+ f->buf = 0;
+ f->bufsize = 0;
+ f->next = NULL;
+ f->bufused = 0;
+ f->buftype = mode;
+
+ if (f->buftype == X_IONBF) return 0;
+
+ /* if buffering then we need some size */
+ if (size == 0) size = XBUFSIZE;
+
+ f->bufsize = size;
+ f->bufused = 0;
+
+ return 0;
+}
+
+/* allocate the buffer */
+static int x_allocate_buffer(XFILE *f)
+{
+ if (f->buf) return 1;
+ if (f->bufsize == 0) return 0;
+ f->buf = malloc(f->bufsize);
+ if (!f->buf) return 0;
+ f->next = f->buf;
+ return 1;
+}
+
+
+/* this looks more like open() than fopen(), but that is quite deliberate.
+ I want programmers to *think* about O_EXCL, O_CREAT etc not just
+ get them magically added
+*/
+XFILE *x_fopen(const char *fname, int flags, mode_t mode)
+{
+ XFILE *ret;
+
+ ret = (XFILE *)malloc(sizeof(XFILE));
+ if (!ret) return NULL;
+
+ memset(ret, 0, sizeof(XFILE));
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ /* we don't support RDWR in XFILE - use file
+ descriptors instead */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ret->open_flags = flags;
+
+ ret->fd = sys_open(fname, flags, mode);
+ if (ret->fd == -1) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
+
+ return ret;
+}
+
+/* simulate fclose() */
+int x_fclose(XFILE *f)
+{
+ int ret;
+
+ /* make sure we flush any buffered data */
+ x_fflush(f);
+
+ ret = close(f->fd);
+ f->fd = -1;
+ if (f->buf) {
+ /* make sure data can't leak into a later malloc */
+ memset(f->buf, 0, f->bufsize);
+ SAFE_FREE(f->buf);
+ }
+ SAFE_FREE(f);
+ return ret;
+}
+
+/* simulate fwrite() */
+int x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ int ret, total=0;
+
+ /* we might be writing unbuffered */
+ if (f->buftype == X_IONBF ||
+ (!f->buf && !x_allocate_buffer(f))) {
+ ret = write(f->fd, p, size*nmemb);
+ if (ret == -1) return -1;
+ return ret/size;
+ }
+
+
+ while (total < size*nmemb) {
+ int n = f->bufsize - f->bufused;
+ n = MIN(n, (size*nmemb)-total);
+
+ if (n == 0) {
+ /* it's full, flush it */
+ x_fflush(f);
+ continue;
+ }
+
+ memcpy(f->buf + f->bufused, total+(const char *)p, n);
+ f->bufused += n;
+ total += n;
+ }
+
+ /* when line buffered we need to flush at the last linefeed. This can
+ flush a bit more than necessary, but that is harmless */
+ if (f->buftype == X_IOLBF && f->bufused) {
+ int i;
+ for (i=size-1; i>=0; i--) {
+ if (*(i+(const char *)p) == '\n') {
+ x_fflush(f);
+ break;
+ }
+ }
+ }
+
+ return total/size;
+}
+
+/* thank goodness for asprintf() */
+int x_vfprintf(XFILE *f, const char *format, va_list ap)
+{
+ char *p;
+ int len, ret;
+ len = vasprintf(&p, format, ap);
+ if (len <= 0) return len;
+ ret = x_fwrite(p, 1, len, f);
+ SAFE_FREE(p);
+ return ret;
+}
+
+int x_fprintf(XFILE *f, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = x_vfprintf(f, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+/* at least fileno() is simple! */
+int x_fileno(XFILE *f)
+{
+ return f->fd;
+}
+
+/* simulate fflush() */
+int x_fflush(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & X_FLAG_ERROR) return -1;
+
+ if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (f->bufused == 0) return 0;
+
+ ret = write(f->fd, f->buf, f->bufused);
+ if (ret == -1) return -1;
+
+ f->bufused -= ret;
+ if (f->bufused > 0) {
+ f->flags |= X_FLAG_ERROR;
+ memmove(f->buf, ret + (char *)f->buf, f->bufused);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* simulate setbuffer() */
+void x_setbuffer(XFILE *f, char *buf, size_t size)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
+}
+
+/* simulate setbuf() */
+void x_setbuf(XFILE *f, char *buf)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
+}
+
+/* simulate setlinebuf() */
+void x_setlinebuf(XFILE *f)
+{
+ x_setvbuf(f, NULL, X_IOLBF, 0);
+}
+
+
+/* simulate feof() */
+int x_feof(XFILE *f)
+{
+ if (f->flags & X_FLAG_EOF) return 1;
+ return 0;
+}
+
+/* simulate ferror() */
+int x_ferror(XFILE *f)
+{
+ if (f->flags & X_FLAG_ERROR) return 1;
+ return 0;
+}
+
+/* fill the read buffer */
+static void x_fillbuf(XFILE *f)
+{
+ int n;
+
+ if (f->bufused) return;
+
+ if (!f->buf && !x_allocate_buffer(f)) return;
+
+ n = read(f->fd, f->buf, f->bufsize);
+ if (n <= 0) return;
+ f->bufused = n;
+ f->next = f->buf;
+}
+
+/* simulate fgetc() */
+int x_fgetc(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
+
+ if (f->bufused == 0) x_fillbuf(f);
+
+ if (f->bufused == 0) {
+ f->flags |= X_FLAG_EOF;
+ return EOF;
+ }
+
+ ret = *(unsigned char *)(f->next);
+ f->next++;
+ f->bufused--;
+ return ret;
+}
+
+/* simulate fread */
+size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ size_t total = 0;
+ while (total < size*nmemb) {
+ int c = x_fgetc(f);
+ if (c == EOF) break;
+ (total+(char *)p)[0] = (char)c;
+ total++;
+ }
+ return total/size;
+}
+
+/* simulate fgets() */
+char *x_fgets(char *s, int size, XFILE *stream)
+{
+ char *s0 = s;
+ int l = size;
+ while (l>1) {
+ int c = x_fgetc(stream);
+ if (c == EOF) break;
+ *s++ = (char)c;
+ l--;
+ if (c == '\n') break;
+ }
+ if (l==size || x_ferror(stream)) {
+ return 0;
+ }
+ *s = 0;
+ return s0;
+}
diff --git a/source/libads/.cvsignore b/source/libads/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/libads/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/libads/ads_struct.c b/source/libads/ads_struct.c
new file mode 100644
index 00000000000..013491eaed1
--- /dev/null
+++ b/source/libads/ads_struct.c
@@ -0,0 +1,162 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ ads (active directory) utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* return a dn of the form "dc=AA,dc=BB,dc=CC" from a
+ realm of the form AA.BB.CC
+ caller must free
+*/
+char *ads_build_dn(const char *realm)
+{
+ char *p, *r;
+ int numdots = 0;
+ char *ret;
+ int len;
+
+ r = strdup(realm);
+
+ if (!r || !*r) return r;
+
+ for (p=r; *p; p++) {
+ if (*p == '.') numdots++;
+ }
+
+ len = (numdots+1)*4 + strlen(r) + 1;
+
+ ret = malloc(len);
+ strlcpy(ret,"dc=", len);
+ p=strtok(r,".");
+ strlcat(ret, p, len);
+
+ while ((p=strtok(NULL,"."))) {
+ strlcat(ret,",dc=", len);
+ strlcat(ret, p, len);
+ }
+
+ free(r);
+
+ return ret;
+}
+
+
+#ifdef HAVE_LDAP
+/*
+ find the ldap server from DNS
+*/
+static char *find_ldap_server(ADS_STRUCT *ads)
+{
+ char *list = NULL;
+ struct in_addr ip;
+
+ if (ads->realm &&
+ ldap_domain2hostlist(ads->realm, &list) == LDAP_SUCCESS) {
+ char *p;
+ p = strchr(list, ':');
+ if (p) *p = 0;
+ return list;
+ }
+
+ /* get desperate, find the domain controller IP */
+ if (resolve_name(lp_workgroup(), &ip, 0x1B)) {
+ return strdup(inet_ntoa(ip));
+ }
+
+ return NULL;
+}
+
+#else
+
+static char *find_ldap_server(ADS_STRUCT *ads)
+{
+ /* Without LDAP this doesn't make much sense */
+ return NULL;
+}
+
+#endif
+
+#ifndef LDAP_PORT
+#define LDAP_PORT 389
+#endif
+
+/*
+ initialise a ADS_STRUCT, ready for some ads_ ops
+*/
+ADS_STRUCT *ads_init(const char *realm,
+ const char *ldap_server,
+ const char *bind_path,
+ const char *password)
+{
+ ADS_STRUCT *ads;
+
+ ads = (ADS_STRUCT *)smb_xmalloc(sizeof(*ads));
+ ZERO_STRUCTP(ads);
+
+ ads->realm = realm? strdup(realm) : NULL;
+ ads->ldap_server = ldap_server? strdup(ldap_server) : NULL;
+ ads->bind_path = bind_path? strdup(bind_path) : NULL;
+ ads->ldap_port = LDAP_PORT;
+ if (password) ads->password = strdup(password);
+
+ if (!ads->realm) {
+ ads->realm = strdup(lp_realm());
+ if (!ads->realm[0]) {
+ SAFE_FREE(ads->realm);
+ }
+ }
+ if (!ads->bind_path && ads->realm) {
+ ads->bind_path = ads_build_dn(ads->realm);
+ }
+ if (!ads->ldap_server) {
+ ads->ldap_server = strdup(lp_ads_server());
+ if (!ads->ldap_server[0]) {
+ ads->ldap_server = find_ldap_server(ads);
+ }
+ }
+ if (!ads->kdc_server) {
+ /* assume its the same as LDAP */
+ ads->kdc_server = ads->ldap_server? strdup(ads->ldap_server) : NULL;
+ }
+
+ return ads;
+}
+
+/*
+ free the memory used by the ADS structure initialized with 'ads_init(...)'
+*/
+void ads_destroy(ADS_STRUCT **ads)
+{
+ if (ads && *ads) {
+#if HAVE_LDAP
+ if ((*ads)->ld) ldap_unbind((*ads)->ld);
+#endif
+ SAFE_FREE((*ads)->realm);
+ SAFE_FREE((*ads)->ldap_server);
+ SAFE_FREE((*ads)->ldap_server_name);
+ SAFE_FREE((*ads)->kdc_server);
+ SAFE_FREE((*ads)->bind_path);
+ SAFE_FREE((*ads)->password);
+ SAFE_FREE((*ads)->user_name);
+ ZERO_STRUCTP(*ads);
+ SAFE_FREE(*ads);
+ }
+}
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
new file mode 100644
index 00000000000..aba22e023b2
--- /dev/null
+++ b/source/libads/kerberos.c
@@ -0,0 +1,239 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ kerberos utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+/*
+ simulate a kinit, putting the tgt in the default cache location
+ remus@snapserver.com
+*/
+int kerberos_kinit_password(const char *principal, const char *password)
+{
+ krb5_context ctx;
+ krb5_error_code code = 0;
+ krb5_ccache cc;
+ krb5_principal me;
+ krb5_creds my_creds;
+
+ if (! *password) {
+ /* kerberos dies on an empty password! */
+ return KRB5_PARSE_MALFORMED;
+ }
+
+ if ((code = krb5_init_context(&ctx)))
+ return code;
+
+ if ((code = krb5_cc_default(ctx, &cc))) {
+ krb5_free_context(ctx);
+ return code;
+ }
+
+ if ((code = krb5_parse_name(ctx, principal, &me))) {
+ krb5_free_context(ctx);
+ return code;
+ }
+
+ if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, (char*)password, NULL,
+ NULL, 0, NULL, NULL))) {
+ krb5_free_principal(ctx, me);
+ krb5_free_context(ctx);
+ return code;
+ }
+
+ if ((code = krb5_cc_initialize(ctx, cc, me))) {
+ krb5_free_cred_contents(ctx, &my_creds);
+ krb5_free_principal(ctx, me);
+ krb5_free_context(ctx);
+ return code;
+ }
+
+ if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
+ krb5_cc_close(ctx, cc);
+ krb5_free_cred_contents(ctx, &my_creds);
+ krb5_free_principal(ctx, me);
+ krb5_free_context(ctx);
+ return code;
+ }
+
+ krb5_cc_close(ctx, cc);
+ krb5_free_cred_contents(ctx, &my_creds);
+ krb5_free_principal(ctx, me);
+ krb5_free_context(ctx);
+
+ return 0;
+}
+
+
+
+/* run kinit to setup our ccache */
+int ads_kinit_password(ADS_STRUCT *ads)
+{
+ char *s;
+ int ret;
+
+ if (!ads->user_name) {
+ /* by default use the machine account */
+ extern pstring global_myname;
+ fstring myname;
+ fstrcpy(myname, global_myname);
+ strlower(myname);
+ asprintf(&ads->user_name, "HOST/%s", global_myname);
+ }
+ asprintf(&s, "%s@%s", ads->user_name, ads->realm);
+ ret = kerberos_kinit_password(s, ads->password);
+
+ if (ret) {
+ DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
+ s, error_message(ret)));
+ }
+ free(s);
+ return ret;
+}
+
+/*
+ verify an incoming ticket and parse out the principal name and
+ authorization_data if available
+*/
+NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
+ char **principal, DATA_BLOB *auth_data)
+{
+ krb5_context context;
+ krb5_auth_context auth_context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_data packet;
+ krb5_ticket *tkt = NULL;
+ krb5_data salt;
+ krb5_encrypt_block eblock;
+ int ret;
+ krb5_keyblock * key;
+ krb5_principal host_princ;
+ char *host_princ_s;
+ extern pstring global_myname;
+ fstring myname;
+ char *password_s;
+ krb5_data password;
+
+ if (!secrets_init()) {
+ DEBUG(1,("secrets_init failed\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ password_s = secrets_fetch_machine_password();
+ if (!password_s) {
+ DEBUG(1,("failed to fetch machine password\n"));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ password.data = password_s;
+ password.length = strlen(password_s);
+
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ ret = krb5_set_default_realm(context, ads->realm);
+ if (ret) {
+ DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
+ ads_destroy(&ads);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* this whole process is far more complex than I would
+ like. We have to go through all this to allow us to store
+ the secret internally, instead of using /etc/krb5.keytab */
+ ret = krb5_auth_con_init(context, &auth_context);
+ if (ret) {
+ DEBUG(1,("krb5_auth_con_init failed (%s)\n", error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ fstrcpy(myname, global_myname);
+ strlower(myname);
+ asprintf(&host_princ_s, "HOST/%s@%s", myname, lp_realm());
+ ret = krb5_parse_name(context, host_princ_s, &host_princ);
+ if (ret) {
+ DEBUG(1,("krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ ret = krb5_principal2salt(context, host_princ, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_MD5);
+
+ ret = krb5_string_to_key(context, &eblock, key, &password, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_string_to_key failed (%s)\n", error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ krb5_auth_con_setuseruserkey(context, auth_context, key);
+
+ packet.length = ticket->length;
+ packet.data = (krb5_pointer)ticket->data;
+
+#if 0
+ file_save("/tmp/ticket.dat", ticket->data, ticket->length);
+#endif
+
+ if ((ret = krb5_rd_req(context, &auth_context, &packet,
+ NULL, keytab, NULL, &tkt))) {
+ DEBUG(3,("krb5_rd_req with auth failed (%s)\n",
+ error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (tkt->enc_part2) {
+ *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
+ tkt->enc_part2->authorization_data[0]->length);
+ }
+
+#if 0
+ if (tkt->enc_part2) {
+ file_save("/tmp/authdata.dat",
+ tkt->enc_part2->authorization_data[0]->contents,
+ tkt->enc_part2->authorization_data[0]->length);
+ }
+#endif
+
+ if ((ret = krb5_unparse_name(context, tkt->enc_part2->client, principal))) {
+ DEBUG(3,("krb5_unparse_name failed (%s)\n",
+ error_message(ret)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+#endif
diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c
new file mode 100644
index 00000000000..e15c22091d2
--- /dev/null
+++ b/source/libads/krb5_setpw.c
@@ -0,0 +1,469 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ krb5 set password implementation
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#define DEFAULT_KPASSWD_PORT 464
+#define KRB5_KPASSWD_VERS_CHANGEPW 1
+#define KRB5_KPASSWD_VERS_SETPW 0xff80
+#define KRB5_KPASSWD_ACCESSDENIED 5
+#define KRB5_KPASSWD_BAD_VERSION 6
+
+/* This implements the Kerb password change protocol as specifed in
+ * kerb-chg-password-02.txt
+ */
+static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
+{
+ char* princ_part1 = NULL;
+ char* princ_part2 = NULL;
+ char* realm = NULL;
+ char* c;
+ char* princ;
+
+ ASN1_DATA req;
+ DATA_BLOB ret;
+
+
+ princ = strdup(principal);
+
+ if ((c = strchr(princ, '/')) == NULL) {
+ c = princ;
+ } else {
+ *c = '\0';
+ c++;
+ princ_part1 = princ;
+ }
+
+ princ_part2 = c;
+
+ if ((c = strchr(c, '@')) != NULL) {
+ *c = '\0';
+ c++;
+ realm = c;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+ asn1_push_tag(&req, ASN1_CONTEXT(0));
+ asn1_write_OctetString(&req, password, strlen(password));
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(1));
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&req, ASN1_CONTEXT(0));
+ asn1_write_Integer(&req, 1);
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(1));
+ asn1_push_tag(&req, ASN1_SEQUENCE(0));
+
+ if (princ_part1)
+ asn1_write_GeneralString(&req, princ_part1);
+
+ asn1_write_GeneralString(&req, princ_part2);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+
+ asn1_push_tag(&req, ASN1_CONTEXT(2));
+ asn1_write_GeneralString(&req, realm);
+ asn1_pop_tag(&req);
+ asn1_pop_tag(&req);
+
+ ret = data_blob(req.data, req.length);
+ asn1_free(&req);
+
+ free(princ);
+
+ return ret;
+}
+
+static krb5_error_code build_setpw_request(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_data *ap_req,
+ const char *princ,
+ const char *passwd,
+ krb5_data *packet)
+{
+ krb5_error_code ret;
+ krb5_data cipherpw;
+ krb5_data encoded_setpw;
+ krb5_replay_data replay;
+ char *p;
+ DATA_BLOB setpw;
+
+ ret = krb5_auth_con_setflags(context,
+ auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ if (ret) {
+ DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ setpw = encode_krb5_setpw(princ, passwd);
+
+ encoded_setpw.data = setpw.data;
+ encoded_setpw.length = setpw.length;
+
+ ret = krb5_mk_priv(context, auth_context,
+ &encoded_setpw, &cipherpw, &replay);
+
+ data_blob_free(&setpw); /*from 'encode_krb5_setpw(...)' */
+
+ if (ret) {
+ DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+
+ packet->data = (char *)malloc(ap_req->length + cipherpw.length + 6);
+
+ /* see the RFC for details */
+ p = packet->data + 2;
+ RSSVAL(p, 0, 0xff80); p += 2;
+ RSSVAL(p, 0, ap_req->length); p += 2;
+ memcpy(p, ap_req->data, ap_req->length); p += ap_req->length;
+ memcpy(p, cipherpw.data, cipherpw.length); p += cipherpw.length;
+ packet->length = PTR_DIFF(p,packet->data);
+ RSSVAL(packet->data, 0, packet->length);
+
+ free(cipherpw.data); /* from 'krb5_mk_priv(...)' */
+
+ return 0;
+}
+
+static krb5_error_code parse_setpw_reply(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_data *packet)
+{
+ krb5_data ap_rep;
+ char *p;
+ int vnum, ret, res_code;
+ krb5_data cipherresult;
+ krb5_data clearresult;
+ krb5_ap_rep_enc_part *ap_rep_enc;
+ krb5_replay_data replay;
+
+ if (packet->length < 4) {
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p = packet->data;
+
+ if (packet->data[0] == 0x7e || packet->data[0] == 0x5e) {
+ /* it's an error packet. We should parse it ... */
+ DEBUG(1,("Got error packet 0x%x from kpasswd server\n",
+ packet->data[0]));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (RSVAL(p, 0) != packet->length) {
+ DEBUG(1,("Bad packet length (%d/%d) from kpasswd server\n",
+ RSVAL(p, 0), packet->length));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p += 2;
+
+ vnum = RSVAL(p, 0); p += 2;
+
+ if (vnum != KRB5_KPASSWD_VERS_SETPW && vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
+ DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));
+ return KRB5KDC_ERR_BAD_PVNO;
+ }
+
+ ap_rep.length = RSVAL(p, 0); p += 2;
+
+ if (p + ap_rep.length >= packet->data + packet->length) {
+ DEBUG(1,("ptr beyond end of packet from kpasswd server\n"));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (ap_rep.length == 0) {
+ DEBUG(1,("got unencrypted setpw result?!\n"));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ /* verify ap_rep */
+ ap_rep.data = p;
+ p += ap_rep.length;
+
+ ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
+ if (ret) {
+ DEBUG(1,("failed to rd setpw reply (%s)\n", error_message(ret)));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+
+ cipherresult.data = p;
+ cipherresult.length = (packet->data + packet->length) - p;
+
+ ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+ &replay);
+ if (ret) {
+ DEBUG(1,("failed to decrypt setpw reply (%s)\n", error_message(ret)));
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ if (clearresult.length < 2) {
+ free(clearresult.data);
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ p = clearresult.data;
+
+ res_code = RSVAL(p, 0);
+
+ free(clearresult.data);
+
+ if ((res_code < KRB5_KPASSWD_SUCCESS) ||
+ (res_code >= KRB5_KPASSWD_ACCESSDENIED)) {
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ return 0;
+}
+
+ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw)
+{
+ krb5_context context;
+ krb5_auth_context auth_context = NULL;
+ krb5_principal principal;
+ char *princ_name;
+ char *realm;
+ krb5_creds creds, *credsp;
+ krb5_ccache ccache;
+ krb5_data ap_req, chpw_req, chpw_rep;
+ int ret, sock, addr_len;
+ struct sockaddr remote_addr, local_addr;
+ krb5_address local_kaddr, remote_kaddr;
+
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = krb5_cc_default(context, &ccache);
+ if (ret) {
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ZERO_STRUCT(creds);
+
+ realm = strchr(princ, '@');
+ realm++;
+
+ asprintf(&princ_name, "kadmin/changepw@%s", realm);
+ ret = krb5_parse_name(context, princ_name, &creds.server);
+ if (ret) {
+ krb5_free_context(context);
+ DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+ free(princ_name);
+
+ /* parse the principal we got as a function argument */
+ ret = krb5_parse_name(context, princ, &principal);
+ if (ret) {
+ krb5_free_context(context);
+ DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ krb5_princ_set_realm(context, creds.server,
+ krb5_princ_realm(context, principal));
+
+ ret = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (ret) {
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get principal from ccache (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+ if (ret) {
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ //we might have to call krb5_free_creds(...) from now on ...
+ ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
+ NULL, credsp, &ap_req);
+ if (ret) {
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
+ if (sock == -1) {
+ int rc = errno;
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("failed to open kpasswd socket to %s (%s)\n",
+ kdc_host, strerror(errno)));
+ return ADS_ERROR_SYSTEM(rc);
+ }
+
+ addr_len = sizeof(remote_addr);
+ getpeername(sock, &remote_addr, &addr_len);
+ addr_len = sizeof(local_addr);
+ getsockname(sock, &local_addr, &addr_len);
+
+ remote_kaddr.addrtype = ADDRTYPE_INET;
+ remote_kaddr.length = sizeof(((struct sockaddr_in *)&remote_addr)->sin_addr);
+ remote_kaddr.contents = (char *)&(((struct sockaddr_in *)&remote_addr)->sin_addr);
+ local_kaddr.addrtype = ADDRTYPE_INET;
+ local_kaddr.length = sizeof(((struct sockaddr_in *)&local_addr)->sin_addr);
+ local_kaddr.contents = (char *)&(((struct sockaddr_in *)&local_addr)->sin_addr);
+
+ ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
+ if (ret) {
+ close(sock);
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = build_setpw_request(context, auth_context, &ap_req,
+ princ, newpw, &chpw_req);
+ if (ret) {
+ close(sock);
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ if (write(sock, chpw_req.data, chpw_req.length) != chpw_req.length) {
+ close(sock);
+ free(chpw_req.data);
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
+ return ADS_ERROR(LDAP_ENCODING_ERROR);
+ }
+
+ free(chpw_req.data);
+
+ chpw_rep.length = 1500;
+ chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+ ret = read(sock, chpw_rep.data, chpw_rep.length);
+ if (ret < 0) {
+ close(sock);
+ free(chpw_rep.data);
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
+ return ADS_ERROR_SYSTEM(errno);
+ }
+
+ close(sock);
+ chpw_rep.length = ret;
+
+ ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
+ if (ret) {
+ free(chpw_rep.data);
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ ret = parse_setpw_reply(context, auth_context, &chpw_rep);
+ free(chpw_rep.data);
+
+ if (ret) {
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+ DEBUG(1,("parse_setpw_reply failed (%s)\n",
+ error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ free(ap_req.data);
+ krb5_free_creds(context, credsp);
+ krb5_free_principal(context, creds.client);
+ krb5_free_principal(context, principal);
+ krb5_free_context(context);
+
+ return ADS_SUCCESS;
+}
+
+
+ADS_STATUS kerberos_set_password(const char *kpasswd_server,
+ const char *auth_principal, const char *auth_password,
+ const char *target_principal, const char *new_password)
+{
+ int ret;
+
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password))) {
+ DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
+ return ADS_ERROR_KRB5(ret);
+ }
+
+ return krb5_set_password(kpasswd_server, target_principal, new_password);
+}
+
+
+#endif
diff --git a/source/libads/ldap.c b/source/libads/ldap.c
new file mode 100644
index 00000000000..8966ceb32a9
--- /dev/null
+++ b/source/libads/ldap.c
@@ -0,0 +1,701 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ ads (active directory) utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_ADS
+
+/*
+ build a ADS_STATUS structure
+*/
+ADS_STATUS ads_build_error(enum ads_error_type etype,
+ int rc, int minor_status)
+{
+ ADS_STATUS ret;
+ ret.error_type = etype;
+ ret.rc = rc;
+ ret.minor_status = minor_status;
+ return ret;
+}
+
+/*
+ do a rough conversion between ads error codes and NT status codes
+ we'll need to fill this in more
+*/
+NTSTATUS ads_ntstatus(ADS_STATUS rc)
+{
+ if (ADS_ERR_OK(rc)) return NT_STATUS_OK;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*
+ return a string for an error from a ads routine
+*/
+const char *ads_errstr(ADS_STATUS status)
+{
+ gss_buffer_desc msg1, msg2;
+ uint32 minor;
+ int msg_ctx;
+ static char *ret;
+
+ SAFE_FREE(ret);
+ msg_ctx = 0;
+
+ switch (status.error_type) {
+ case ADS_ERROR_KRB5:
+ return error_message(status.rc);
+ case ADS_ERROR_LDAP:
+ return ldap_err2string(status.rc);
+ case ADS_ERROR_SYSTEM:
+ return strerror(status.rc);
+ case ADS_ERROR_GSS:
+ msg1.value = NULL;
+ msg2.value = NULL;
+ gss_display_status(&minor, status.rc, GSS_C_GSS_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &msg1);
+ gss_display_status(&minor, status.minor_status, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &msg2);
+ asprintf(&ret, "%s : %s", (char *)msg1.value, (char *)msg2.value);
+ gss_release_buffer(&minor, &msg1);
+ gss_release_buffer(&minor, &msg2);
+ return ret;
+ }
+
+ return "Unknown ADS error type!?";
+}
+
+/*
+ connect to the LDAP server
+*/
+ADS_STATUS ads_connect(ADS_STRUCT *ads)
+{
+ int version = LDAP_VERSION3;
+ ADS_STATUS status;
+
+ ads->last_attempt = time(NULL);
+
+ ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
+ if (!ads->ld) {
+ return ADS_ERROR_SYSTEM(errno)
+ }
+ status = ads_server_info(ads);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("Failed to get ldap server info\n"));
+ return status;
+ }
+
+ ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ if (ads->password) {
+ ads_kinit_password(ads);
+ }
+
+ return ads_sasl_bind(ads);
+}
+
+/*
+ do a search with a timeout
+*/
+ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *exp,
+ const char **attrs, void **res)
+{
+ struct timeval timeout;
+ int rc;
+
+ timeout.tv_sec = ADS_SEARCH_TIMEOUT;
+ timeout.tv_usec = 0;
+ *res = NULL;
+
+ rc = ldap_search_ext_s(ads->ld,
+ bind_path, scope,
+ exp, attrs, 0, NULL, NULL,
+ &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
+ return ADS_ERROR(rc);
+}
+/*
+ do a general ADS search
+*/
+ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
+ const char *exp,
+ const char **attrs)
+{
+ return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
+ exp, attrs, res);
+}
+
+/*
+ do a search on a specific DistinguishedName
+*/
+ADS_STATUS ads_search_dn(ADS_STRUCT *ads, void **res,
+ const char *dn,
+ const char **attrs)
+{
+ return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res);
+}
+
+/*
+ free up memory from a ads_search
+*/
+void ads_msgfree(ADS_STRUCT *ads, void *msg)
+{
+ if (!msg) return;
+ ldap_msgfree(msg);
+}
+
+/*
+ find a machine account given a hostname
+*/
+ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
+{
+ ADS_STATUS status;
+ char *exp;
+
+ /* the easiest way to find a machine account anywhere in the tree
+ is to look for hostname$ */
+ asprintf(&exp, "(samAccountName=%s$)", host);
+ status = ads_search(ads, res, exp, NULL);
+ free(exp);
+ return status;
+}
+
+
+/*
+ a convenient routine for adding a generic LDAP record
+*/
+ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ...)
+{
+ int i;
+ va_list ap;
+ LDAPMod **mods;
+ char *name, *value;
+ int ret;
+#define MAX_MOD_VALUES 10
+
+ /* count the number of attributes */
+ va_start(ap, new_dn);
+ for (i=0; va_arg(ap, char *); i++) {
+ /* skip the values */
+ while (va_arg(ap, char *)) ;
+ }
+ va_end(ap);
+
+ mods = malloc(sizeof(LDAPMod *) * (i+1));
+
+ va_start(ap, new_dn);
+ for (i=0; (name=va_arg(ap, char *)); i++) {
+ char **values;
+ int j;
+ values = (char **)malloc(sizeof(char *) * (MAX_MOD_VALUES+1));
+ for (j=0; (value=va_arg(ap, char *)) && j < MAX_MOD_VALUES; j++) {
+ values[j] = value;
+ }
+ values[j] = NULL;
+ mods[i] = malloc(sizeof(LDAPMod));
+ mods[i]->mod_type = name;
+ mods[i]->mod_op = LDAP_MOD_ADD;
+ mods[i]->mod_values = values;
+ }
+ mods[i] = NULL;
+ va_end(ap);
+
+ ret = ldap_add_s(ads->ld, new_dn, mods);
+
+ for (i=0; mods[i]; i++) {
+ free(mods[i]->mod_values);
+ free(mods[i]);
+ }
+ free(mods);
+
+ return ADS_ERROR(ret);
+}
+
+/*
+ add a machine account to the ADS server
+*/
+static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
+ const char *org_unit)
+{
+ ADS_STATUS ret;
+ char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
+
+ asprintf(&host_spn, "HOST/%s", hostname);
+ asprintf(&host_upn, "%s@%s", host_spn, ads->realm);
+ asprintf(&new_dn, "cn=%s,cn=%s,%s", hostname, org_unit, ads->bind_path);
+ asprintf(&samAccountName, "%s$", hostname);
+ asprintf(&controlstr, "%u",
+ UF_DONT_EXPIRE_PASSWD | UF_WORKSTATION_TRUST_ACCOUNT |
+ UF_TRUSTED_FOR_DELEGATION | UF_USE_DES_KEY_ONLY);
+
+ ret = ads_gen_add(ads, new_dn,
+ "cn", hostname, NULL,
+ "sAMAccountName", samAccountName, NULL,
+ "objectClass",
+ "top", "person", "organizationalPerson",
+ "user", "computer", NULL,
+ "userPrincipalName", host_upn, NULL,
+ "servicePrincipalName", host_spn, NULL,
+ "dNSHostName", hostname, NULL,
+ "userAccountControl", controlstr, NULL,
+ "operatingSystem", "Samba", NULL,
+ "operatingSystemVersion", VERSION, NULL,
+ NULL);
+
+ free(host_spn);
+ free(host_upn);
+ free(new_dn);
+ free(samAccountName);
+ free(controlstr);
+
+ return ret;
+}
+
+/*
+ dump a binary result from ldap
+*/
+static void dump_binary(const char *field, struct berval **values)
+{
+ int i, j;
+ for (i=0; values[i]; i++) {
+ printf("%s: ", field);
+ for (j=0; j<values[i]->bv_len; j++) {
+ printf("%02X", (unsigned char)values[i]->bv_val[j]);
+ }
+ printf("\n");
+ }
+}
+
+/*
+ dump a sid result from ldap
+*/
+static void dump_sid(const char *field, struct berval **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+ DOM_SID sid;
+ sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
+ printf("%s: %s\n", field, sid_string_static(&sid));
+ }
+}
+
+/*
+ dump a string result from ldap
+*/
+static void dump_string(const char *field, struct berval **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+ printf("%s: %s\n", field, values[i]->bv_val);
+ }
+}
+
+/*
+ dump a record from LDAP on stdout
+ used for debugging
+*/
+void ads_dump(ADS_STRUCT *ads, void *res)
+{
+ char *field;
+ void *msg;
+ BerElement *b;
+ struct {
+ char *name;
+ void (*handler)(const char *, struct berval **);
+ } handlers[] = {
+ {"objectGUID", dump_binary},
+ {"objectSid", dump_sid},
+ {NULL, NULL}
+ };
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ for (field = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &b);
+ field;
+ field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) {
+ struct berval **values;
+ int i;
+
+ values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field);
+
+ for (i=0; handlers[i].name; i++) {
+ if (StrCaseCmp(handlers[i].name, field) == 0) {
+ handlers[i].handler(field, values);
+ break;
+ }
+ }
+ if (!handlers[i].name) {
+ dump_string(field, values);
+ }
+ ldap_value_free_len(values);
+ ldap_memfree(field);
+ }
+
+ ber_free(b, 1);
+ printf("\n");
+ }
+}
+
+/*
+ count how many replies are in a LDAPMessage
+*/
+int ads_count_replies(ADS_STRUCT *ads, void *res)
+{
+ return ldap_count_entries(ads->ld, (LDAPMessage *)res);
+}
+
+/*
+ join a machine to a realm, creating the machine account
+ and setting the machine password
+*/
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
+{
+ ADS_STATUS status;
+ LDAPMessage *res;
+ char *host;
+
+ /* hostname must be lowercase */
+ host = strdup(hostname);
+ strlower(host);
+
+ status = ads_find_machine_acct(ads, (void **)&res, host);
+ if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
+ DEBUG(0, ("Host account for %s already exists\n", host));
+ return ADS_SUCCESS;
+ }
+
+ status = ads_add_machine_acct(ads, host, org_unit);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
+ return status;
+ }
+
+ status = ads_find_machine_acct(ads, (void **)&res, host);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("Host account test failed\n"));
+ return status;
+ }
+
+ free(host);
+
+ return status;
+}
+
+/*
+ delete a machine from the realm
+*/
+ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
+{
+ ADS_STATUS status;
+ void *res;
+ char *hostnameDN, *host;
+ int rc;
+
+ /* hostname must be lowercase */
+ host = strdup(hostname);
+ strlower(host);
+
+ status = ads_find_machine_acct(ads, &res, host);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("Host account for %s does not exist.\n", host));
+ return status;
+ }
+
+ hostnameDN = ldap_get_dn(ads->ld, (LDAPMessage *)res);
+ rc = ldap_delete_s(ads->ld, hostnameDN);
+ ldap_memfree(hostnameDN);
+ if (rc != LDAP_SUCCESS) {
+ return ADS_ERROR(rc);
+ }
+
+ status = ads_find_machine_acct(ads, &res, host);
+ if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
+ DEBUG(0, ("Failed to remove host account.\n"));
+ return status;
+ }
+
+ free(host);
+
+ return status;
+}
+
+
+ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
+ const char *hostname,
+ const char *password)
+{
+ ADS_STATUS status;
+ char *host = strdup(hostname);
+ char *principal;
+
+ strlower(host);
+
+ asprintf(&principal, "%s@%s", host, ads->realm);
+
+ status = krb5_set_password(ads->kdc_server, principal, password);
+
+ free(host);
+ free(principal);
+
+ return status;
+}
+
+/*
+ pull the first entry from a ADS result
+*/
+void *ads_first_entry(ADS_STRUCT *ads, void *res)
+{
+ return (void *)ldap_first_entry(ads->ld, (LDAPMessage *)res);
+}
+
+/*
+ pull the next entry from a ADS result
+*/
+void *ads_next_entry(ADS_STRUCT *ads, void *res)
+{
+ return (void *)ldap_next_entry(ads->ld, (LDAPMessage *)res);
+}
+
+/*
+ pull a single string from a ADS result
+*/
+char *ads_pull_string(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx, void *msg, const char *field)
+{
+ char **values;
+ char *ret = NULL;
+
+ values = ldap_get_values(ads->ld, msg, field);
+ if (!values) return NULL;
+
+ if (values[0]) {
+ ret = talloc_strdup(mem_ctx, values[0]);
+ }
+ ldap_value_free(values);
+ return ret;
+}
+
+/*
+ pull a single uint32 from a ADS result
+*/
+BOOL ads_pull_uint32(ADS_STRUCT *ads,
+ void *msg, const char *field, uint32 *v)
+{
+ char **values;
+
+ values = ldap_get_values(ads->ld, msg, field);
+ if (!values) return False;
+ if (!values[0]) {
+ ldap_value_free(values);
+ return False;
+ }
+
+ *v = atoi(values[0]);
+ ldap_value_free(values);
+ return True;
+}
+
+/*
+ pull a single DOM_SID from a ADS result
+*/
+BOOL ads_pull_sid(ADS_STRUCT *ads,
+ void *msg, const char *field, DOM_SID *sid)
+{
+ struct berval **values;
+ BOOL ret = False;
+
+ values = ldap_get_values_len(ads->ld, msg, field);
+
+ if (!values) return False;
+
+ if (values[0]) {
+ ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
+ }
+
+ ldap_value_free_len(values);
+ return ret;
+}
+
+/*
+ pull an array of DOM_SIDs from a ADS result
+ return the count of SIDs pulled
+*/
+int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ void *msg, const char *field, DOM_SID **sids)
+{
+ struct berval **values;
+ BOOL ret;
+ int count, i;
+
+ values = ldap_get_values_len(ads->ld, msg, field);
+
+ if (!values) return 0;
+
+ for (i=0; values[i]; i++) /* nop */ ;
+
+ (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i);
+
+ count = 0;
+ for (i=0; values[i]; i++) {
+ ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
+ if (ret) count++;
+ }
+
+ ldap_value_free_len(values);
+ return count;
+}
+
+
+/* find the update serial number - this is the core of the ldap cache */
+ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
+{
+ const char *attrs[] = {"highestCommittedUSN", NULL};
+ ADS_STATUS status;
+ void *res;
+
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) return status;
+
+ if (ads_count_replies(ads, res) != 1) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ ads_pull_uint32(ads, res, "highestCommittedUSN", usn);
+ ads_msgfree(ads, res);
+ return ADS_SUCCESS;
+}
+
+
+/* find the servers name and realm - this can be done before authentication
+ The ldapServiceName field on w2k looks like this:
+ vnet3.home.samba.org:win2000-vnet3$@VNET3.HOME.SAMBA.ORG
+*/
+ADS_STATUS ads_server_info(ADS_STRUCT *ads)
+{
+ const char *attrs[] = {"ldapServiceName", NULL};
+ ADS_STATUS status;
+ void *res;
+ char **values;
+ char *p;
+
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) return status;
+
+ values = ldap_get_values(ads->ld, res, "ldapServiceName");
+ if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+
+ p = strchr(values[0], ':');
+ if (!p) {
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ return ADS_ERROR(LDAP_DECODING_ERROR);
+ }
+
+ SAFE_FREE(ads->ldap_server_name);
+
+ ads->ldap_server_name = strdup(p+1);
+ p = strchr(ads->ldap_server_name, '$');
+ if (!p || p[1] != '@') {
+ ldap_value_free(values);
+ ldap_msgfree(res);
+ SAFE_FREE(ads->ldap_server_name);
+ return ADS_ERROR(LDAP_DECODING_ERROR);
+ }
+
+ *p = 0;
+
+ SAFE_FREE(ads->server_realm);
+ SAFE_FREE(ads->bind_path);
+
+ ads->server_realm = strdup(p+2);
+ ads->bind_path = ads_build_dn(ads->server_realm);
+
+ /* in case the realm isn't configured in smb.conf */
+ if (!ads->realm || !ads->realm[0]) {
+ SAFE_FREE(ads->realm);
+ ads->realm = strdup(ads->server_realm);
+ }
+
+ DEBUG(3,("got ldap server name %s@%s\n",
+ ads->ldap_server_name, ads->realm));
+
+ return ADS_SUCCESS;
+}
+
+
+/*
+ find the list of trusted domains
+*/
+ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ int *num_trusts, char ***names, DOM_SID **sids)
+{
+ const char *attrs[] = {"flatName", "securityIdentifier", NULL};
+ ADS_STATUS status;
+ void *res, *msg;
+ int count, i;
+
+ *num_trusts = 0;
+
+ status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
+ if (!ADS_ERR_OK(status)) return status;
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ (*names) = talloc(mem_ctx, sizeof(char *) * count);
+ (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
+ if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
+
+ for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
+ ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i]);
+ i++;
+ }
+
+ ads_msgfree(ads, res);
+
+ *num_trusts = i;
+
+ return ADS_SUCCESS;
+}
+
+/* find the domain sid for our domain */
+ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
+{
+ const char *attrs[] = {"objectSid", NULL};
+ void *res;
+ ADS_STATUS rc;
+
+ rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
+ attrs, &res);
+ if (!ADS_ERR_OK(rc)) return rc;
+ if (!ads_pull_sid(ads, res, "objectSid", sid)) {
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+ ads_msgfree(ads, res);
+
+ return ADS_SUCCESS;
+}
+
+#endif
diff --git a/source/libads/sasl.c b/source/libads/sasl.c
new file mode 100644
index 00000000000..48873252f08
--- /dev/null
+++ b/source/libads/sasl.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ ads sasl code
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_ADS
+
+#if USE_CYRUS_SASL
+/*
+ this is a minimal interact function, just enough for SASL to talk
+ GSSAPI/kerberos to W2K
+ Error handling is a bit of a problem. I can't see how to get Cyrus-sasl
+ to give sensible errors
+*/
+static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in)
+{
+ sasl_interact_t *interact = in;
+
+ while (interact->id != SASL_CB_LIST_END) {
+ interact->result = strdup("");
+ interact->len = strlen(interact->result);
+ interact++;
+ }
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+
+#define MAX_GSS_PASSES 3
+
+/* this performs a SASL/gssapi bind
+ we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
+ is very dependent on correctly configured DNS whereas
+ this routine is much less fragile
+ see RFC2078 for details
+*/
+ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+{
+ int minor_status;
+ gss_name_t serv_name;
+ gss_buffer_desc input_name;
+ gss_ctx_id_t context_handle;
+ gss_OID mech_type = GSS_C_NULL_OID;
+ gss_buffer_desc output_token, input_token;
+ OM_uint32 ret_flags, conf_state;
+ struct berval cred;
+ struct berval *scred;
+ int i=0;
+ int gss_rc, rc;
+ uint8 *p;
+ uint32 max_msg_size;
+ char *sname;
+ ADS_STATUS status;
+ krb5_principal principal;
+ krb5_context ctx;
+ krb5_enctype enc_types[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
+ gss_OID_desc nt_principal =
+ {10, "\052\206\110\206\367\022\001\002\002\002"};
+
+ /* we need to fetch a service ticket as the ldap user in the
+ servers realm, regardless of our realm */
+ asprintf(&sname, "ldap/%s@%s", ads->ldap_server_name, ads->server_realm);
+ krb5_init_context(&ctx);
+ krb5_set_default_tgs_ktypes(ctx, enc_types);
+ krb5_parse_name(ctx, sname, &principal);
+ free(sname);
+ krb5_free_context(ctx);
+
+ input_name.value = &principal;
+ input_name.length = sizeof(principal);
+
+ gss_rc = gss_import_name(&minor_status,&input_name,&nt_principal, &serv_name);
+ if (gss_rc) {
+ return ADS_ERROR_GSS(gss_rc, minor_status);
+ }
+
+ context_handle = GSS_C_NO_CONTEXT;
+
+ input_token.value = NULL;
+ input_token.length = 0;
+
+ for (i=0; i < MAX_GSS_PASSES; i++) {
+ gss_rc = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &context_handle,
+ serv_name,
+ mech_type,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ NULL,
+ &input_token,
+ NULL,
+ &output_token,
+ &ret_flags,
+ NULL);
+
+ if (input_token.value) {
+ gss_release_buffer(&minor_status, &input_token);
+ }
+
+ if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ cred.bv_val = output_token.value;
+ cred.bv_len = output_token.length;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ &scred);
+ if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = ADS_ERROR(rc);
+ goto failed;
+ }
+
+ if (output_token.value) {
+ gss_release_buffer(&minor_status, &output_token);
+ }
+
+ if (scred) {
+ input_token.value = scred->bv_val;
+ input_token.length = scred->bv_len;
+ } else {
+ input_token.value = NULL;
+ input_token.length = 0;
+ }
+
+ if (gss_rc == 0) break;
+ }
+
+ gss_release_name(&minor_status, &serv_name);
+
+ gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
+ &conf_state,NULL);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ gss_release_buffer(&minor_status, &input_token);
+
+ p = (uint8 *)output_token.value;
+
+ max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
+
+ gss_release_buffer(&minor_status, &output_token);
+
+ output_token.value = malloc(strlen(ads->bind_path) + 8);
+ p = output_token.value;
+
+ *p++ = 1; /* no sign or seal */
+ /* choose the same size as the server gave us */
+ *p++ = max_msg_size>>16;
+ *p++ = max_msg_size>>8;
+ *p++ = max_msg_size;
+ snprintf(p, strlen(ads->bind_path)+1, "dn:%s", ads->bind_path);
+ p += strlen(ads->bind_path);
+
+ output_token.length = strlen(ads->bind_path) + 8;
+
+ gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
+ &output_token, &conf_state,
+ &input_token);
+ if (gss_rc) {
+ status = ADS_ERROR_GSS(gss_rc, minor_status);
+ goto failed;
+ }
+
+ free(output_token.value);
+
+ cred.bv_val = input_token.value;
+ cred.bv_len = input_token.length;
+
+ rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ &scred);
+ status = ADS_ERROR(rc);
+
+ gss_release_buffer(&minor_status, &input_token);
+
+failed:
+ return status;
+}
+
+ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
+{
+#if USE_CYRUS_SASL
+ int rc;
+ rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL,
+ LDAP_SASL_QUIET,
+ sasl_interact, NULL);
+ return ADS_ERROR(rc);
+#else
+ return ads_sasl_gssapi_bind(ads);
+#endif
+}
+
+#endif
+
diff --git a/source/libads/util.c b/source/libads/util.c
new file mode 100644
index 00000000000..8f22adb7af4
--- /dev/null
+++ b/source/libads/util.c
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ krb5 set password implementation
+ Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
+{
+ char *tmp_password;
+ char *password;
+ char *new_password;
+ char *service_principal;
+ ADS_STATUS ret;
+
+ if ((password = secrets_fetch_machine_password()) == NULL) {
+ DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+
+ tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ new_password = strdup(tmp_password);
+ asprintf(&service_principal, "HOST/%s", host_principal);
+
+ ret = kerberos_set_password(ads->kdc_server, host_principal, password,
+ service_principal, new_password);
+
+ if (!secrets_store_machine_password(new_password)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ return ADS_ERROR_SYSTEM(EACCES);
+ }
+
+ SAFE_FREE(service_principal);
+ SAFE_FREE(new_password);
+
+ return ret;
+}
+
+
+
+#endif
diff --git a/source/libsmb/.cvsignore b/source/libsmb/.cvsignore
new file mode 100644
index 00000000000..07da2225c72
--- /dev/null
+++ b/source/libsmb/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source/libsmb/asn1.c b/source/libsmb/asn1.c
new file mode 100644
index 00000000000..93e95b52bbb
--- /dev/null
+++ b/source/libsmb/asn1.c
@@ -0,0 +1,414 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ simple SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* free an asn1 structure */
+void asn1_free(ASN1_DATA *data)
+{
+ SAFE_FREE(data->data);
+}
+
+/* write to the ASN1 buffer, advancing the buffer pointer */
+BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
+{
+ if (data->has_error) return False;
+ if (data->length < data->ofs+len) {
+ uint8 *newp;
+ newp = Realloc(data->data, data->ofs+len);
+ if (!newp) {
+ SAFE_FREE(data->data);
+ data->has_error = True;
+ return False;
+ }
+ data->data = newp;
+ data->length = data->ofs+len;
+ }
+ memcpy(data->data + data->ofs, p, len);
+ data->ofs += len;
+ return True;
+}
+
+/* useful fn for writing a uint8 */
+BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
+{
+ return asn1_write(data, &v, 1);
+}
+
+/* push a tag onto the asn1 data buffer. Used for nested structures */
+BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
+{
+ struct nesting *nesting;
+
+ asn1_write_uint8(data, tag);
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return asn1_write_uint8(data, 0xff);
+}
+
+/* pop a tag */
+BOOL asn1_pop_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+ size_t len;
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+ len = data->ofs - (nesting->start+1);
+ /* yes, this is ugly. We don't know in advance how many bytes the length
+ of a tag will take, so we assumed 1 byte. If we were wrong then we
+ need to correct our mistake */
+ if (len > 255) {
+ data->data[nesting->start] = 0x82;
+ if (!asn1_write_uint8(data, 0)) return False;
+ if (!asn1_write_uint8(data, 0)) return False;
+ memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len>>8;
+ data->data[nesting->start+2] = len&0xff;
+ } else if (len > 127) {
+ data->data[nesting->start] = 0x81;
+ if (!asn1_write_uint8(data, 0)) return False;
+ memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len;
+ } else {
+ data->data[nesting->start] = len;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return True;
+}
+
+
+/* write an integer */
+BOOL asn1_write_Integer(ASN1_DATA *data, int i)
+{
+ if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
+ do {
+ asn1_write_uint8(data, i);
+ i = i >> 8;
+ } while (i);
+ return asn1_pop_tag(data);
+}
+
+/* write an object ID to a ASN1 buffer */
+BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
+{
+ unsigned v, v2;
+ const char *p = (const char *)OID;
+ char *newp;
+
+ if (!asn1_push_tag(data, ASN1_OID))
+ return False;
+ v = strtol(p, &newp, 10);
+ p = newp;
+ v2 = strtol(p, &newp, 10);
+ p = newp;
+ if (!asn1_write_uint8(data, 40*v + v2))
+ return False;
+
+ while (*p) {
+ v = strtol(p, &newp, 10);
+ p = newp;
+ if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
+ if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
+ if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
+ if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
+ if (!asn1_write_uint8(data, v&0x7f))
+ return False;
+ }
+ return asn1_pop_tag(data);
+}
+
+/* write an octet string */
+BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
+{
+ asn1_push_tag(data, ASN1_OCTET_STRING);
+ asn1_write(data, p, length);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a general string */
+BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
+{
+ asn1_push_tag(data, ASN1_GENERAL_STRING);
+ asn1_write(data, s, strlen(s));
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a BOOLEAN */
+BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
+{
+ asn1_write_uint8(data, ASN1_BOOLEAN);
+ asn1_write_uint8(data, v);
+ return !data->has_error;
+}
+
+/* check a BOOLEAN */
+BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
+{
+ uint8 b = 0;
+
+ asn1_read_uint8(data, &b);
+ if (b != ASN1_BOOLEAN) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read_uint8(data, &b);
+ if (b != v) {
+ data->has_error = True;
+ return False;
+ }
+ return !data->has_error;
+}
+
+
+/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
+BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
+{
+ ZERO_STRUCTP(data);
+ data->data = memdup(blob.data, blob.length);
+ if (!data->data) {
+ data->has_error = True;
+ return False;
+ }
+ data->length = blob.length;
+ return True;
+}
+
+/* read from a ASN1 buffer, advancing the buffer pointer */
+BOOL asn1_read(ASN1_DATA *data, void *p, int len)
+{
+ if (data->ofs + len > data->length) {
+ data->has_error = True;
+ return False;
+ }
+ memcpy(p, data->data + data->ofs, len);
+ data->ofs += len;
+ return True;
+}
+
+/* read a uint8 from a ASN1 buffer */
+BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
+{
+ return asn1_read(data, v, 1);
+}
+
+/* start reading a nested asn1 structure */
+BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
+{
+ uint8 b;
+ struct nesting *nesting;
+
+ asn1_read_uint8(data, &b);
+ if (b != tag) {
+ data->has_error = True;
+ return False;
+ }
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ asn1_read_uint8(data, &b);
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (n > 2) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read_uint8(data, &b);
+ nesting->taglen = b;
+ if (n == 2) {
+ asn1_read_uint8(data, &b);
+ nesting->taglen = (nesting->taglen << 8) | b;
+ }
+ } else {
+ nesting->taglen = b;
+ }
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return !data->has_error;
+}
+
+
+/* stop reading a tag */
+BOOL asn1_end_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+
+ /* make sure we read it all */
+ if (asn1_tag_remaining(data) != 0) {
+ data->has_error = True;
+ return False;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return True;
+}
+
+/* work out how many bytes are left in this nested tag */
+int asn1_tag_remaining(ASN1_DATA *data)
+{
+ if (!data->nesting) {
+ data->has_error = True;
+ return -1;
+ }
+ return data->nesting->taglen - (data->ofs - data->nesting->start);
+}
+
+/* read an object ID from a ASN1 buffer */
+BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
+{
+ uint8 b;
+ pstring oid;
+ fstring el;
+
+ if (!asn1_start_tag(data, ASN1_OID)) return False;
+ asn1_read_uint8(data, &b);
+
+ oid[0] = 0;
+ snprintf(el, sizeof(el), "%u", b/40);
+ pstrcat(oid, el);
+ snprintf(el, sizeof(el), " %u", b%40);
+ pstrcat(oid, el);
+
+ while (asn1_tag_remaining(data) > 0) {
+ unsigned v = 0;
+ do {
+ asn1_read_uint8(data, &b);
+ v = (v<<7) | (b&0x7f);
+ } while (!data->has_error && b & 0x80);
+ snprintf(el, sizeof(el), " %u", v);
+ pstrcat(oid, el);
+ }
+
+ asn1_end_tag(data);
+
+ *OID = strdup(oid);
+
+ return !data->has_error;
+}
+
+/* check that the next object ID is correct */
+BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
+{
+ char *id;
+
+ if (!asn1_read_OID(data, &id)) return False;
+
+ if (strcmp(id, OID) != 0) {
+ data->has_error = True;
+ return False;
+ }
+ free(id);
+ return True;
+}
+
+/* read a GeneralString from a ASN1 buffer */
+BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
+{
+ int len;
+ if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
+ len = asn1_tag_remaining(data);
+ *s = malloc(len+1);
+ if (! *s) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read(data, *s, len);
+ (*s)[len] = 0;
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
+/* read a octet string blob */
+BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
+{
+ int len;
+ if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
+ len = asn1_tag_remaining(data);
+ blob->data = malloc(len);
+ if (!blob->data) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read(data, blob->data, len);
+ blob->length = len;
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
+/* read an interger */
+BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
+{
+ uint8 b;
+ *i = 0;
+
+ if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
+ while (asn1_tag_remaining(data)>0) {
+ *i = (*i << 8) + asn1_read_uint8(data, &b);
+ }
+ return asn1_end_tag(data);
+
+}
+
+/* check a enumarted value is correct */
+BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
+{
+ uint8 b;
+ if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
+ asn1_read_uint8(data, &b);
+ asn1_end_tag(data);
+ return !data->has_error && (v == b);
+}
+
+/* check a enumarted value is correct */
+BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
+{
+ if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
+ asn1_write_uint8(data, v);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
diff --git a/source/libsmb/cli_dfs.c b/source/libsmb/cli_dfs.c
new file mode 100644
index 00000000000..83220fd1afc
--- /dev/null
+++ b/source/libsmb/cli_dfs.c
@@ -0,0 +1,254 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to the netdfs pipe */
+
+struct cli_state *cli_dfs_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_NETDFS, creds);
+}
+
+/* Query DFS support */
+
+NTSTATUS cli_dfs_exist(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL *dfs_exists)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_EXIST q;
+ DFS_R_DFS_EXIST r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_exist(&q);
+
+ if (!dfs_io_q_dfs_exist("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_EXIST, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_exist("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ *dfs_exists = (r.status != 0);
+
+ result = NT_STATUS_OK;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_add(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ char *comment, uint32 flags)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ADD q;
+ DFS_R_DFS_ADD r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_add(&q, entrypath, servername, sharename, comment,
+ flags);
+
+ if (!dfs_io_q_dfs_add("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ADD, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_add("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_remove(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_REMOVE q;
+ DFS_R_DFS_REMOVE r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_remove(&q, entrypath, servername, sharename);
+
+ if (!dfs_io_q_dfs_remove("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_REMOVE, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_remove("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_get_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_GET_INFO q;
+ DFS_R_DFS_GET_INFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_get_info(&q, entrypath, servername, sharename,
+ info_level);
+
+ if (!dfs_io_q_dfs_get_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_GET_INFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_get_info("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+ *ctr = r.ctr;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate dfs shares */
+
+NTSTATUS cli_dfs_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ENUM q;
+ DFS_R_DFS_ENUM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_enum(&q, info_level, ctr);
+
+ if (!dfs_io_q_dfs_enum("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ENUM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!dfs_io_r_dfs_enum("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source/libsmb/cli_lsarpc.c b/source/libsmb/cli_lsarpc.c
new file mode 100644
index 00000000000..0720cadfbd4
--- /dev/null
+++ b/source/libsmb/cli_lsarpc.c
@@ -0,0 +1,1140 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,2000,
+ Copyright (C) Paul Ashton 1997,2000,
+ Copyright (C) Elrond 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/** @defgroup lsa LSA rpc client routines
+ * @ingroup rpc_client
+ *
+ * @{
+ **/
+
+/**
+ * @file cli_lsarpc.c
+ *
+ * RPC client routines for the LSA RPC pipe. LSA means "local
+ * security authority", which is half of a password database.
+ **/
+
+/** Opens a SMB connection and connects to the LSARPC pipe.
+ *
+ * @param cli Uninitialised client handle.
+ * @param system_name NETBIOS name of the machine to connect to.
+ * @param creds User credentials to connect as.
+ * @returns Initialised client handle.
+ */
+struct cli_state *cli_lsa_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_LSARPC, creds);
+}
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL q;
+ LSA_R_OPEN_POL r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol(&q, '\\', 0, des_access, &qos);
+ } else {
+ init_q_open_pol(&q, '\\', 0, des_access, NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA policy handle */
+
+NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL2 q;
+ LSA_R_OPEN_POL2 r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol2(&q, cli->clnt_name_slash, 0, des_access,
+ &qos);
+ } else {
+ init_q_open_pol2(&q, cli->clnt_name_slash, 0, des_access,
+ NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Close a LSA policy handle */
+
+NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_CLOSE q;
+ LSA_R_CLOSE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_close(&q, pol);
+
+ if (!lsa_io_q_close("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_CLOSE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_close("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of sids */
+
+NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_sids, DOM_SID *sids,
+ char ***names, uint32 **types, int *num_names)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_SIDS q;
+ LSA_R_LOOKUP_SIDS r;
+ DOM_R_REF ref;
+ LSA_TRANS_NAME_ENUM t_names;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
+
+ if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ ZERO_STRUCT(t_names);
+
+ r.dom_ref = &ref;
+ r.names = &t_names;
+
+ if (!lsa_io_r_lookup_sids("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_FILES_OPEN)) {
+ /* An actual error occured */
+
+ goto done;
+ }
+
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ (*num_names) = r.mapped_count;
+ result = NT_STATUS_OK;
+
+ if (!((*names) = (char **)talloc(mem_ctx, sizeof(char *) * r.mapped_count))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types) = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.mapped_count))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.mapped_count; i++) {
+ fstring name, dom_name, full_name;
+ uint32 dom_idx = t_names.name[i].domain_idx;
+
+ /* Translate optimised name through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ rpcstr_pull_unistr2_fstring(
+ dom_name, &ref.ref_dom[dom_idx].uni_dom_name);
+ rpcstr_pull_unistr2_fstring(
+ name, &t_names.uni_name[i]);
+
+ slprintf(full_name, sizeof(full_name) - 1,
+ "%s%s%s", dom_name,
+ (dom_name[0] && name[0]) ?
+ lp_winbind_separator() : "", name);
+
+ (*names)[i] = talloc_strdup(mem_ctx, full_name);
+ (*types)[i] = t_names.name[i].sid_name_use;
+
+ } else {
+ (*names)[i] = NULL;
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of names */
+
+NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_names, const char **names,
+ DOM_SID **sids, uint32 **types, int *num_sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_NAMES q;
+ LSA_R_LOOKUP_NAMES r;
+ DOM_R_REF ref;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
+
+ if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ r.dom_ref = &ref;
+
+ if (!lsa_io_r_lookup_names("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result)) {
+ /* An actual error occured */
+
+ goto done;
+ }
+
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ (*num_sids) = r.mapped_count;
+ result = NT_STATUS_OK;
+
+ if (!((*sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * r.mapped_count)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.mapped_count)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.mapped_count; i++) {
+ DOM_RID2 *t_rids = r.dom_rid;
+ uint32 dom_idx = t_rids[i].rid_idx;
+ uint32 dom_rid = t_rids[i].rid;
+ DOM_SID *sid = &(*sids)[i];
+
+ /* Translate optimised sid through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid);
+
+ if (dom_rid != 0xffffffff) {
+ sid_append_rid(sid, dom_rid);
+ }
+
+ (*types)[i] = t_rids[i].type;
+ } else {
+ ZERO_STRUCTP(sid);
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query info policy */
+
+NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint16 info_class,
+ fstring domain_name, DOM_SID *domain_sid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_INFO q;
+ LSA_R_QUERY_INFO r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query(&q, pol, info_class);
+
+ if (!lsa_io_q_query("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ ZERO_STRUCTP(domain_sid);
+ domain_name[0] = '\0';
+
+ switch (info_class) {
+
+ case 3:
+ if (r.dom.id3.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name,
+ &r.dom.id3.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id3.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id3.dom_sid.sid;
+ }
+
+ break;
+
+ case 5:
+
+ if (r.dom.id5.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name, &r.dom.id5.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id5.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id5.dom_sid.sid;
+ }
+
+ break;
+
+ default:
+ DEBUG(3, ("unknown info class %d\n", info_class));
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate list of trusted domains */
+
+NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx,
+ uint32 *num_domains, char ***domain_names,
+ DOM_SID **domain_sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_TRUST_DOM q;
+ LSA_R_ENUM_TRUST_DOM r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_enum_trust_dom(&q, pol, *enum_ctx, 0xffffffff);
+
+ if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_trust_dom("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_NO_MORE_ENTRIES)) {
+
+ /* An actual error ocured */
+
+ goto done;
+ }
+
+ result = NT_STATUS_OK;
+
+ /* Return output parameters */
+
+ if (r.num_domains) {
+
+ /* Allocate memory for trusted domain names and sids */
+
+ *domain_names = (char **)talloc(mem_ctx, sizeof(char *) *
+ r.num_domains);
+
+ if (!*domain_names) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ *domain_sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) *
+ r.num_domains);
+ if (!domain_sids) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.num_domains; i++) {
+ fstring tmp;
+
+ unistr2_to_ascii(tmp, &r.uni_domain_name[i],
+ sizeof(tmp) - 1);
+ (*domain_names)[i] = strdup(tmp);
+ sid_copy(&(*domain_sids)[i], &r.domain_sid[i].sid);
+ }
+ }
+
+ *num_domains = r.num_domains;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate privileges*/
+
+NTSTATUS cli_lsa_enum_privilege(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_context, uint32 pref_max_length,
+ uint32 *count, char ***privs_name, uint32 **privs_high, uint32 **privs_low)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_PRIVS q;
+ LSA_R_ENUM_PRIVS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_enum_privs(&q, pol, *enum_context, pref_max_length);
+
+ if (!lsa_io_q_enum_privs("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_PRIVS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privs("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ *enum_context = r.enum_context;
+ *count = r.count;
+
+ if (!((*privs_name = (char **)talloc(mem_ctx, sizeof(char *) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_high = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_low = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.count; i++) {
+ fstring name;
+
+ rpcstr_pull_unistr2_fstring( name, &r.privs[i].name);
+
+ (*privs_name)[i] = talloc_strdup(mem_ctx, name);
+
+ (*privs_high)[i] = r.privs[i].luid_high;
+ (*privs_low)[i] = r.privs[i].luid_low;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get privilege name */
+
+NTSTATUS cli_lsa_get_dispname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, uint16 lang_id, uint16 lang_id_sys,
+ fstring description, uint16 *lang_id_desc)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_PRIV_GET_DISPNAME q;
+ LSA_R_PRIV_GET_DISPNAME r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_priv_get_dispname(&q, pol, name, lang_id, lang_id_sys);
+
+ if (!lsa_io_q_priv_get_dispname("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_PRIV_GET_DISPNAME, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_priv_get_dispname("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ rpcstr_pull_unistr2_fstring(description , &r.desc);
+ *lang_id_desc = r.lang_id;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate list of SIDs */
+
+NTSTATUS cli_lsa_enum_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx, uint32 pref_max_length,
+ uint32 *num_sids, DOM_SID **sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_ACCOUNTS q;
+ LSA_R_ENUM_ACCOUNTS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_enum_accounts(&q, pol, *enum_ctx, pref_max_length);
+
+ if (!lsa_io_q_enum_accounts("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_ACCOUNTS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_accounts("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.sids.num_entries==0)
+ goto done;
+
+ /* Return output parameters */
+
+ *sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * r.sids.num_entries);
+ if (!*sids) {
+ DEBUG(0, ("(cli_lsa_enum_sids): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.sids.num_entries; i++) {
+ sid_copy(&(*sids)[i], &r.sids.sid[i].sid);
+ }
+
+ *num_sids= r.sids.num_entries;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA user handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_account(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *dom_pol, DOM_SID *sid, uint32 des_access,
+ POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPENACCOUNT q;
+ LSA_R_OPENACCOUNT r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_open_account(&q, dom_pol, sid, des_access);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_account("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_account("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *user_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate user privileges
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_enum_privsaccount(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *count, LUID_ATTR **set)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUMPRIVSACCOUNT q;
+ LSA_R_ENUMPRIVSACCOUNT r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_enum_privsaccount(&q, pol);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_enum_privsaccount("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMPRIVSACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privsaccount("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.count == 0)
+ goto done;
+
+ if (!((*set = (LUID_ATTR *)talloc(mem_ctx, sizeof(LUID_ATTR) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privsaccount): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i=0; i<r.count; i++) {
+ (*set)[i].luid.low = r.set.set[i].luid.low;
+ (*set)[i].luid.high = r.set.set[i].luid.high;
+ (*set)[i].attr = r.set.set[i].attr;
+ }
+
+ *count=r.count;
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get a privilege value given its name */
+
+NTSTATUS cli_lsa_lookupprivvalue(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, LUID *luid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUPPRIVVALUE q;
+ LSA_R_LOOKUPPRIVVALUE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_lookupprivvalue(&q, pol, name);
+
+ if (!lsa_io_q_lookupprivvalue("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPPRIVVALUE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_lookupprivvalue("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ (*luid).low=r.luid.low;
+ (*luid).high=r.luid.high;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query LSA security object */
+
+NTSTATUS cli_lsa_query_secobj(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 sec_info,
+ SEC_DESC_BUF **psdb)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_SEC_OBJ q;
+ LSA_R_QUERY_SEC_OBJ r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query_sec_obj(&q, pol, sec_info);
+
+ if (!lsa_io_q_query_sec_obj("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYSECOBJ, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query_sec_obj("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (psdb)
+ *psdb = r.buf;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Fetch a DOMAIN sid. Does complete cli setup / teardown anonymously. */
+
+BOOL fetch_domain_sid( char *domain, char *remote_machine, DOM_SID *psid)
+{
+ extern pstring global_myname;
+ struct cli_state cli;
+ NTSTATUS result;
+ POLICY_HND lsa_pol;
+ BOOL ret = False;
+
+ ZERO_STRUCT(cli);
+ if(cli_initialise(&cli) == False) {
+ DEBUG(0,("fetch_domain_sid: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
+ DEBUG(0,("fetch_domain_sid: Can't resolve address for %s\n", remote_machine));
+ goto done;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the NetBIOS \
+session request. Error was %s\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (cli.protocol != PROTOCOL_NT1) {
+ DEBUG(0,("fetch_domain_sid: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ goto done;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!(cli.sec_mode & 1)) {
+ DEBUG(0,("fetch_domain_sid: machine %s isn't in user level security mode\n",
+ remote_machine));
+ goto done;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ /* Fetch domain sid */
+
+ if (!cli_nt_session_open(&cli, PIPE_LSARPC)) {
+ DEBUG(0, ("fetch_domain_sid: Error connecting to SAM pipe\n"));
+ goto done;
+ }
+
+ result = cli_lsa_open_policy(&cli, cli.mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, &lsa_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error opening lsa policy handle. %s\n",
+ get_nt_error_msg(result) ));
+ goto done;
+ }
+
+ result = cli_lsa_query_info_policy(&cli, cli.mem_ctx, &lsa_pol, 5, domain, psid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error querying lsa policy handle. %s\n",
+ get_nt_error_msg(result) ));
+ goto done;
+ }
+
+ ret = True;
+
+ done:
+
+ cli_shutdown(&cli);
+ return ret;
+}
+/** @} **/
diff --git a/source/libsmb/cli_netlogon.c b/source/libsmb/cli_netlogon.c
new file mode 100644
index 00000000000..8840a6264bb
--- /dev/null
+++ b/source/libsmb/cli_netlogon.c
@@ -0,0 +1,587 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Paul Ashton 1997.
+ Copyright (C) Jeremy Allison 1998.
+ Copyright (C) Andrew Bartlett 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to the netlogon pipe */
+
+struct cli_state *cli_netlogon_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_NETLOGON, creds);
+}
+
+/* LSA Request Challenge. Sends our challenge to server, then gets
+ server response. These are used to generate the credentials. */
+
+NTSTATUS new_cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_REQ_CHAL q;
+ NET_R_REQ_CHAL r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_REQCHAL */
+
+ DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
+ cli->desthost, global_myname, credstr(clnt_chal->data)));
+
+ /* store the parameters */
+ init_q_req_chal(&q, cli->srv_name_slash, global_myname, clnt_chal);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_req_chal("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_REQCHAL, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarhall response */
+
+ if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ result = r.status;
+
+ /* Return result */
+
+ if (NT_STATUS_IS_OK(result)) {
+ memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+LSA Authenticate 2
+
+Send the client credential, receive back a server credential.
+Ensure that the server credential returned matches the session key
+encrypt of the server challenge originally received. JRA.
+****************************************************************************/
+
+NTSTATUS new_cli_net_auth2(struct cli_state *cli, uint16 sec_chan,
+ uint32 neg_flags, DOM_CHAL *srv_chal)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_AUTH_2 q;
+ NET_R_AUTH_2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_AUTH2 */
+
+ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
+ credstr(cli->clnt_cred.challenge.data), neg_flags));
+
+ /* store the parameters */
+ init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct,
+ sec_chan, global_myname, &cli->clnt_cred.challenge,
+ neg_flags);
+
+ /* turn parameters into data stream */
+
+ if (!net_io_q_auth_2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_AUTH2, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ result = r.status;
+
+ if (NT_STATUS_IS_OK(result)) {
+ UTIME zerotime;
+
+ /*
+ * Check the returned value using the initial
+ * server received challenge.
+ */
+
+ zerotime.time = 0;
+ if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal,
+ zerotime) == 0) {
+
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Initialize domain session credentials */
+
+NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli,
+ unsigned char mach_pwd[16])
+{
+ DOM_CHAL clnt_chal;
+ DOM_CHAL srv_chal;
+ UTIME zerotime;
+ NTSTATUS result;
+
+ /******************* Request Challenge ********************/
+
+ generate_random_buffer(clnt_chal.data, 8, False);
+
+ /* send a client challenge; receive a server challenge */
+ result = new_cli_net_req_chal(cli, &clnt_chal, &srv_chal);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
+ return result;
+ }
+
+ /**************** Long-term Session key **************/
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd,
+ cli->sess_key);
+ memset((char *)cli->sess_key+8, '\0', 8);
+
+ /******************* Authenticate 2 ********************/
+
+ /* calculate auth-2 credentials */
+ zerotime.time = 0;
+ cred_create(cli->sess_key, &clnt_chal, zerotime,
+ &cli->clnt_cred.challenge);
+
+ /*
+ * Send client auth-2 challenge.
+ * Receive an auth-2 challenge response and check it.
+ */
+
+ result = new_cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+ SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff,
+ &srv_chal);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed %s\n",
+ get_nt_error_msg(result)));
+ }
+
+ return result;
+}
+
+/* Logon Control 2 */
+
+NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 query_level)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_LOGON_CTRL2 q;
+ NET_R_LOGON_CTRL2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_net_q_logon_ctrl2(&q, cli->srv_name_slash, query_level);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_logon_ctrl2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_logon_ctrl2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+Generate the next creds to use. Yuck - this is a cut&paste from another
+file. They should be combined at some stage. )-:
+****************************************************************************/
+
+static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
+{
+ /*
+ * Create the new client credentials.
+ */
+
+ cli->clnt_cred.timestamp.time = time(NULL);
+
+ memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
+
+ /* Calculate the new credentials. */
+ cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
+ new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
+
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx, DOM_CRED *ret_creds,
+ uint32 database_id, uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_SYNC q;
+ NET_R_SAM_SYNC r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2,
+ &clnt_creds, ret_creds, database_id);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_sync("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_sync("", cli->sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds));
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 database_id, UINT64_S seqnum,
+ uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_DELTAS q;
+ NET_R_SAM_DELTAS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_deltas(&q, cli->srv_name_slash,
+ cli->clnt_name_slash + 2, &clnt_creds,
+ database_id, seqnum);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_deltas("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_deltas("", cli->sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Logon domain user */
+
+NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *username, char *password,
+ int logon_type)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_LOGON q;
+ NET_R_SAM_LOGON r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds, dummy_rtn_creds;
+ extern pstring global_myname;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 user;
+ int validation_level = 3;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ q.validation_level = validation_level;
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+ dummy_rtn_creds.timestamp.time = time(NULL);
+
+ ctr.switch_value = logon_type;
+
+ switch (logon_type) {
+ case INTERACTIVE_LOGON_TYPE: {
+ unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
+
+ nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
+
+ init_id_info1(&ctr.auth.id1, lp_workgroup(),
+ 0, /* param_ctrl */
+ 0xdead, 0xbeef, /* LUID? */
+ username, cli->clnt_name_slash,
+ cli->sess_key, lm_owf_user_pwd,
+ nt_owf_user_pwd);
+
+ break;
+ }
+ case NET_LOGON_TYPE: {
+ uint8 chal[8];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+
+ generate_random_buffer(chal, 8, False);
+
+ SMBencrypt(password, chal, local_lm_response);
+ SMBNTencrypt(password, chal, local_nt_response);
+
+ init_id_info2(&ctr.auth.id2, lp_workgroup(),
+ 0, /* param_ctrl */
+ 0xdead, 0xbeef, /* LUID? */
+ username, cli->clnt_name_slash, chal,
+ local_lm_response, 24, local_nt_response, 24);
+ break;
+ }
+ default:
+ DEBUG(0, ("switch value %d not supported\n",
+ ctr.switch_value));
+ goto done;
+ }
+
+ init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname,
+ &clnt_creds, &dummy_rtn_creds, logon_type,
+ &ctr);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.user = &user;
+
+ if (!net_io_r_sam_logon("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/***************************************************************************
+LSA Server Password Set.
+****************************************************************************/
+
+NTSTATUS cli_net_srv_pwset(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char* machine_name, uint8 hashed_mach_pwd[16])
+{
+ prs_struct rbuf;
+ prs_struct qbuf;
+ DOM_CRED new_clnt_cred;
+ NET_Q_SRV_PWSET q_s;
+ uint16 sec_chan_type = 2;
+ NTSTATUS nt_status;
+ char *mach_acct;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&qbuf , 1024, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SRV_PWSET */
+
+ mach_acct = talloc_asprintf(mem_ctx, "%s$", machine_name);
+
+ if (!mach_acct) {
+ DEBUG(0,("talloc_asprintf failed!\n"));
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, mach_acct, sec_chan_type, machine_name,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+
+ /* store the parameters */
+ init_q_srv_pwset(&q_s, cli->srv_name_slash, cli->sess_key,
+ mach_acct, sec_chan_type, machine_name,
+ &new_clnt_cred, (char *)hashed_mach_pwd);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_srv_pwset("", &q_s, &qbuf, 0)) {
+ DEBUG(0,("cli_net_srv_pwset: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SRVPWSET, &qbuf, &rbuf))
+ {
+ NET_R_SRV_PWSET r_s;
+
+ if (!net_io_r_srv_pwset("", &r_s, &rbuf, 0)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ nt_status = r_s.status;
+
+ if (!NT_STATUS_IS_OK(r_s.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_srv_pwset: %s\n", get_nt_error_msg(nt_status)));
+ goto done;
+ }
+
+ /* Update the credentials. */
+ if (!clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred)))
+ {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return nt_status;
+}
+
diff --git a/source/libsmb/cli_pipe_util.c b/source/libsmb/cli_pipe_util.c
new file mode 100644
index 00000000000..9521d817fa5
--- /dev/null
+++ b/source/libsmb/cli_pipe_util.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client utility functions
+ Copyright (C) Tim Potter 2001,
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to a named pipe */
+
+struct cli_state *cli_pipe_initialise(struct cli_state *cli, char *system_name,
+ char *pipe_name,
+ struct ntuser_creds *creds)
+{
+ struct in_addr dest_ip;
+ struct nmb_name calling, called;
+ fstring dest_host;
+ extern pstring global_myname;
+ struct ntuser_creds anon;
+
+ /* Initialise cli_state information */
+
+ if (!cli_initialise(cli)) {
+ return NULL;
+ }
+
+ if (!creds) {
+ ZERO_STRUCT(anon);
+ anon.pwd.null_pwd = 1;
+ creds = &anon;
+ }
+
+ cli_init_creds(cli, creds);
+
+ /* Establish a SMB connection */
+
+ if (!resolve_srv_name(system_name, dest_host, &dest_ip)) {
+ return NULL;
+ }
+
+ make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ if (!cli_establish_connection(cli, dest_host, &dest_ip, &calling,
+ &called, "IPC$", "IPC", False, True)) {
+ return NULL;
+ }
+
+ /* Open a NT session thingy */
+
+ if (!cli_nt_session_open(cli, pipe_name)) {
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ return cli;
+}
+
+/* Shut down a SMB connection to the SAMR pipe */
+
+void cli_pipe_shutdown(struct cli_state *cli)
+{
+ if (cli->fd != -1) cli_ulogoff(cli);
+ cli_shutdown(cli);
+}
diff --git a/source/libsmb/cli_reg.c b/source/libsmb/cli_reg.c
new file mode 100644
index 00000000000..73eea58cb77
--- /dev/null
+++ b/source/libsmb/cli_reg.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC Pipe client
+
+ Copyright (C) Andrew Tridgell 1992-1998,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ Copyright (C) Paul Ashton 1997-1998.
+ Copyright (C) Jeremy Allison 1999.
+ Copyright (C) Simo Sorce 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to the WINREG pipe */
+
+struct cli_state *cli_winreg_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_WINREG, creds);
+}
+
+/* Shutdown a server */
+
+NTSTATUS cli_reg_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx,
+ const char *srv_name, const char *msg,
+ uint32 timeout, uint16 flags)
+{
+ prs_struct qbuf;
+ prs_struct rbuf;
+ REG_Q_SHUTDOWN q_s;
+ REG_R_SHUTDOWN r_s;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (msg == NULL) return NT_STATUS_INVALID_PARAMETER;
+
+ ZERO_STRUCT (q_s);
+ ZERO_STRUCT (r_s);
+
+ prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_reg_q_shutdown(&q_s, msg, timeout, flags);
+
+ if (!reg_io_q_shutdown("", &q_s, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, REG_SHUTDOWN, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if(reg_io_r_shutdown("", &r_s, &rbuf, 0))
+ result = r_s.status;
+
+done:
+ prs_mem_free(&rbuf);
+ prs_mem_free(&qbuf);
+
+ return result;
+}
+
+
+/* Abort a server shutdown */
+
+NTSTATUS cli_reg_abort_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx,
+ const char *srv_name)
+{
+ prs_struct rbuf;
+ prs_struct qbuf;
+ REG_Q_ABORT_SHUTDOWN q_s;
+ REG_R_ABORT_SHUTDOWN r_s;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT (q_s);
+ ZERO_STRUCT (r_s);
+
+ prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_reg_q_abort_shutdown(&q_s);
+
+ if (!reg_io_q_abort_shutdown("", &q_s, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, REG_ABORT_SHUTDOWN, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (reg_io_r_abort_shutdown("", &r_s, &rbuf, 0))
+ result = r_s.status;
+
+done:
+ prs_mem_free(&rbuf);
+ prs_mem_free(&qbuf );
+
+ return result;
+}
diff --git a/source/libsmb/cli_samr.c b/source/libsmb/cli_samr.c
new file mode 100644
index 00000000000..ddcfe890786
--- /dev/null
+++ b/source/libsmb/cli_samr.c
@@ -0,0 +1,1257 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,2000,
+ Copyright (C) Paul Ashton 1997,2000,
+ Copyright (C) Elrond 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to the SAMR pipe */
+
+struct cli_state *cli_samr_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SAMR, creds);
+}
+
+/* Connect to SAMR database */
+
+NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 access_mask, POLICY_HND *connect_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CONNECT q;
+ SAMR_R_CONNECT r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_connect(&q, cli->desthost, access_mask);
+
+ if (!samr_io_q_connect("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CONNECT, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_connect("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *connect_pol = r.connect_pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Close SAMR handle */
+
+NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *connect_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CLOSE_HND q;
+ SAMR_R_CLOSE_HND r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_close_hnd(&q, connect_pol);
+
+ if (!samr_io_q_close_hnd("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CLOSE_HND, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_close_hnd("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *connect_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a domain */
+
+NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *connect_pol, uint32 access_mask,
+ const DOM_SID *domain_sid, POLICY_HND *domain_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_DOMAIN q;
+ SAMR_R_OPEN_DOMAIN r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_domain(&q, connect_pol, access_mask, domain_sid);
+
+ if (!samr_io_q_open_domain("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_DOMAIN, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_domain("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *domain_pol = r.domain_pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a user */
+
+NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 user_rid, POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_USER q;
+ SAMR_R_OPEN_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_user(&q, domain_pol, access_mask, user_rid);
+
+ if (!samr_io_q_open_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *user_pol = r.user_pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a group */
+
+NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 group_rid, POLICY_HND *group_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_GROUP q;
+ SAMR_R_OPEN_GROUP r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_group(&q, domain_pol, access_mask, group_rid);
+
+ if (!samr_io_q_open_group("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_GROUP, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_group("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *group_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user info */
+
+NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ SAM_USERINFO_CTR **ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERINFO q;
+ SAMR_R_QUERY_USERINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_userinfo(&q, user_pol, switch_value);
+
+ if (!samr_io_q_query_userinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_userinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+ *ctr = r.ctr;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query group info */
+
+NTSTATUS cli_samr_query_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *group_pol, uint32 info_level,
+ GROUP_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_GROUPINFO q;
+ SAMR_R_QUERY_GROUPINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_groupinfo(&q, group_pol, info_level);
+
+ if (!samr_io_q_query_groupinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_GROUPINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_groupinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user groups */
+
+NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint32 *num_groups,
+ DOM_GID **gid)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERGROUPS q;
+ SAMR_R_QUERY_USERGROUPS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_usergroups(&q, user_pol);
+
+ if (!samr_io_q_query_usergroups("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_usergroups("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_groups = r.num_entries;
+ *gid = r.gid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user aliases */
+
+NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint32 num_sids, DOM_SID2 *sid,
+ uint32 *num_aliases, uint32 **als_rids)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERALIASES q;
+ SAMR_R_QUERY_USERALIASES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint ptr=1;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_useraliases(&q, user_pol, num_sids, &ptr, sid);
+
+ if (!samr_io_q_query_useraliases("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERALIASES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_useraliases("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_aliases = r.num_entries;
+ *als_rids = r.rid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user groups */
+
+NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *group_pol, uint32 *num_mem,
+ uint32 **rid, uint32 **attr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_GROUPMEM q;
+ SAMR_R_QUERY_GROUPMEM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_groupmem(&q, group_pol);
+
+ if (!samr_io_q_query_groupmem("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_groupmem("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_mem = r.num_entries;
+ *rid = r.rid;
+ *attr = r.attr;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *start_idx,
+ uint32 size, struct acct_info **dom_groups,
+ uint32 *num_dom_groups)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_ENUM_DOM_GROUPS q;
+ SAMR_R_ENUM_DOM_GROUPS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 name_idx, i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_enum_dom_groups(&q, pol, *start_idx, size);
+
+ if (!samr_io_q_enum_dom_groups("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_enum_dom_groups("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_dom_groups = r.num_entries2;
+
+ if (!((*dom_groups) = (struct acct_info *)
+ talloc(mem_ctx, sizeof(struct acct_info) * *num_dom_groups))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ memset(*dom_groups, 0, sizeof(struct acct_info) * *num_dom_groups);
+
+ name_idx = 0;
+
+ for (i = 0; i < *num_dom_groups; i++) {
+
+ (*dom_groups)[i].rid = r.sam[i].rid;
+
+ if (r.sam[i].hdr_name.buffer) {
+ unistr2_to_ascii((*dom_groups)[i].acct_name,
+ &r.uni_grp_name[name_idx],
+ sizeof(fstring) - 1);
+ name_idx++;
+ }
+
+ *start_idx = r.next_idx;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *start_idx,
+ uint32 size, struct acct_info **dom_groups,
+ uint32 *num_dom_groups)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_ENUM_DOM_ALIASES q;
+ SAMR_R_ENUM_DOM_ALIASES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 name_idx, i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_enum_dom_aliases(&q, pol, *start_idx, size);
+
+ if (!samr_io_q_enum_dom_aliases("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_enum_dom_aliases("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_dom_groups = r.num_entries2;
+
+ if (!((*dom_groups) = (struct acct_info *)
+ talloc(mem_ctx, sizeof(struct acct_info) * *num_dom_groups))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ memset(*dom_groups, 0, sizeof(struct acct_info) * *num_dom_groups);
+
+ name_idx = 0;
+
+ for (i = 0; i < *num_dom_groups; i++) {
+
+ (*dom_groups)[i].rid = r.sam[i].rid;
+
+ if (r.sam[i].hdr_name.buffer) {
+ unistr2_to_ascii((*dom_groups)[i].acct_name,
+ &r.uni_grp_name[name_idx],
+ sizeof(fstring) - 1);
+ name_idx++;
+ }
+
+ *start_idx = r.next_idx;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query alias members */
+
+NTSTATUS cli_samr_query_aliasmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *alias_pol, uint32 *num_mem,
+ DOM_SID **sids)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_ALIASMEM q;
+ SAMR_R_QUERY_ALIASMEM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_aliasmem(&q, alias_pol);
+
+ if (!samr_io_q_query_aliasmem("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_ALIASMEM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_aliasmem("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ *num_mem = r.num_sids;
+
+ if (!(*sids = talloc(mem_ctx, sizeof(DOM_SID) * *num_mem))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < *num_mem; i++) {
+ (*sids)[i] = r.sid[i].sid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on an alias */
+
+NTSTATUS cli_samr_open_alias(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 alias_rid, POLICY_HND *alias_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_ALIAS q;
+ SAMR_R_OPEN_ALIAS r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_alias(&q, domain_pol, access_mask, alias_rid);
+
+ if (!samr_io_q_open_alias("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_ALIAS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_alias("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *alias_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query domain info */
+
+NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint16 switch_value,
+ SAM_UNK_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_DOMAIN_INFO q;
+ SAMR_R_QUERY_DOMAIN_INFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_dom_info(&q, domain_pol, switch_value);
+
+ if (!samr_io_q_query_dom_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_dom_info("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query display info */
+
+NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 *start_idx,
+ uint16 switch_value, uint32 *num_entries,
+ uint32 max_entries, SAM_DISPINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_DISPINFO q;
+ SAMR_R_QUERY_DISPINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_dispinfo(&q, domain_pol, switch_value,
+ *start_idx, max_entries);
+
+ if (!samr_io_q_query_dispinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_dispinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_entries = r.num_entries;
+ *start_idx += r.num_entries; /* No next_idx in this structure! */
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Lookup rids. Note that NT4 seems to crash if more than ~1000 rids are
+ looked up in one packet. */
+
+NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 flags,
+ uint32 num_rids, uint32 *rids,
+ uint32 *num_names, char ***names,
+ uint32 **name_types)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_LOOKUP_RIDS q;
+ SAMR_R_LOOKUP_RIDS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ if (num_rids > 1000) {
+ DEBUG(2, ("cli_samr_lookup_rids: warning: NT4 can crash if "
+ "more than ~1000 rids are looked up at once.\n"));
+ }
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_lookup_rids(mem_ctx, &q, domain_pol, flags,
+ num_rids, rids);
+
+ if (!samr_io_q_lookup_rids("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_lookup_rids("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.num_names1 == 0) {
+ *num_names = 0;
+ *names = NULL;
+ goto done;
+ }
+
+ *num_names = r.num_names1;
+ *names = talloc(mem_ctx, sizeof(char *) * r.num_names1);
+ *name_types = talloc(mem_ctx, sizeof(uint32) * r.num_names1);
+
+ for (i = 0; i < r.num_names1; i++) {
+ fstring tmp;
+
+ unistr2_to_ascii(tmp, &r.uni_name[i], sizeof(tmp) - 1);
+ (*names)[i] = talloc_strdup(mem_ctx, tmp);
+ (*name_types)[i] = r.type[i];
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Lookup names */
+
+NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 flags,
+ uint32 num_names, char **names,
+ uint32 *num_rids, uint32 **rids,
+ uint32 **rid_types)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_LOOKUP_NAMES q;
+ SAMR_R_LOOKUP_NAMES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_lookup_names(mem_ctx, &q, domain_pol, flags,
+ num_names, names);
+
+ if (!samr_io_q_lookup_names("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_LOOKUP_NAMES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_lookup_names("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.num_rids1 == 0) {
+ *num_rids = 0;
+ goto done;
+ }
+
+ *num_rids = r.num_rids1;
+ *rids = talloc(mem_ctx, sizeof(uint32) * r.num_rids1);
+ *rid_types = talloc(mem_ctx, sizeof(uint32) * r.num_rids1);
+
+ for (i = 0; i < r.num_rids1; i++) {
+ (*rids)[i] = r.rids[i];
+ (*rid_types)[i] = r.types[i];
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Create a domain user */
+
+NTSTATUS cli_samr_create_dom_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, const char *acct_name,
+ uint32 acb_info, uint32 unknown,
+ POLICY_HND *user_pol, uint32 *rid)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CREATE_USER q;
+ SAMR_R_CREATE_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_create_user(&q, domain_pol, acct_name, acb_info, unknown);
+
+ if (!samr_io_q_create_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CREATE_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_create_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (user_pol)
+ *user_pol = r.user_pol;
+
+ if (rid)
+ *rid = r.user_rid;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Set userinfo */
+
+NTSTATUS cli_samr_set_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_SET_USERINFO q;
+ SAMR_R_SET_USERINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ q.ctr = ctr;
+
+ init_samr_q_set_userinfo(&q, user_pol, sess_key, switch_value,
+ ctr->info.id);
+
+ if (!samr_io_q_set_userinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_SET_USERINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_set_userinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Set userinfo2 */
+
+NTSTATUS cli_samr_set_userinfo2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_SET_USERINFO2 q;
+ SAMR_R_SET_USERINFO2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_set_userinfo2(&q, user_pol, sess_key, switch_value, ctr);
+
+ if (!samr_io_q_set_userinfo2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_SET_USERINFO2, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_set_userinfo2("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Delete domain user */
+
+NTSTATUS cli_samr_delete_dom_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_DELETE_DOM_USER q;
+ SAMR_R_DELETE_DOM_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_delete_dom_user(&q, user_pol);
+
+ if (!samr_io_q_delete_dom_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_DELETE_DOM_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_delete_dom_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user security object */
+
+NTSTATUS cli_samr_query_sec_obj(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ TALLOC_CTX *ctx, SEC_DESC_BUF **sec_desc_buf)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_SEC_OBJ q;
+ SAMR_R_QUERY_SEC_OBJ r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_sec_obj(&q, user_pol, switch_value);
+
+ if (!samr_io_q_query_sec_obj("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_SEC_OBJECT, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_sec_obj("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+ *sec_desc_buf=dup_sec_desc_buf(ctx, r.buf);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source/libsmb/cli_spoolss.c b/source/libsmb/cli_spoolss.c
new file mode 100644
index 00000000000..c87a36e3024
--- /dev/null
+++ b/source/libsmb/cli_spoolss.c
@@ -0,0 +1,1134 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001,
+ Copyright (C) Tim Potter 2000,
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Jean-Francois Micouleau 1999-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/* Opens a SMB connection to the SPOOLSS pipe */
+struct cli_state *cli_spoolss_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SPOOLSS, creds);
+}
+
+/* Open printer ex */
+
+NTSTATUS cli_spoolss_open_printer_ex(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ char *printername,
+ char *datatype,
+ uint32 access_required,
+ char *station,
+ char *username,
+ POLICY_HND *pol
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_OPEN_PRINTER_EX q;
+ SPOOL_R_OPEN_PRINTER_EX r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_open_printer_ex(&q, printername, datatype,
+ access_required, station, username);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_open_printer_ex("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_OPENPRINTEREX, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_open_printer_ex("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (W_ERROR_IS_OK(r.status)) {
+ result = NT_STATUS_OK;
+ *pol = r.handle;
+ } else {
+ result = werror_to_ntstatus(r.status);
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Close a printer handle */
+
+NTSTATUS cli_spoolss_close_printer(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_CLOSEPRINTER q;
+ SPOOL_R_CLOSEPRINTER r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_closeprinter(&q, pol);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_closeprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_CLOSEPRINTER, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_closeprinter("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (W_ERROR_IS_OK(r.status)) {
+ *pol = r.handle;
+ result = NT_STATUS_OK;
+ } else {
+ result = werror_to_ntstatus(r.status);
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Initialize a spoolss NEW_BUFFER */
+
+static void init_buffer(NEW_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
+{
+ buffer->ptr = (size != 0);
+ buffer->size = size;
+ buffer->string_at_end = size;
+ prs_init(&buffer->prs, size, ctx, MARSHALL);
+ buffer->struct_start = prs_offset(&buffer->prs);
+}
+
+/* Decode various printer info levels - perhaps this should live in
+ parse_spoolss.c? */
+
+static void decode_printer_info_0(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PRINTER_INFO_0 **info
+)
+{
+ uint32 i;
+ PRINTER_INFO_0 *inf;
+
+ inf=(PRINTER_INFO_0 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_0));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_info_0("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_1(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PRINTER_INFO_1 **info
+)
+{
+ uint32 i;
+ PRINTER_INFO_1 *inf;
+
+ inf=(PRINTER_INFO_1 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_info_1("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_2(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PRINTER_INFO_2 **info
+)
+{
+ uint32 i;
+ PRINTER_INFO_2 *inf;
+
+ inf=(PRINTER_INFO_2 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ /* a little initialization as we go */
+ inf[i].secdesc = NULL;
+ smb_io_printer_info_2("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_3(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PRINTER_INFO_3 **info
+)
+{
+ uint32 i;
+ PRINTER_INFO_3 *inf;
+
+ inf=(PRINTER_INFO_3 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ inf[i].secdesc = NULL;
+ smb_io_printer_info_3("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_1 struct from a NEW_BUFFER
+**********************************************************************/
+static void decode_port_info_1(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PORT_INFO_1 **info
+)
+{
+ uint32 i;
+ PORT_INFO_1 *inf;
+
+ inf=(PORT_INFO_1*)talloc(mem_ctx, returned*sizeof(PORT_INFO_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ smb_io_port_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_2 struct from a NEW_BUFFER
+**********************************************************************/
+static void decode_port_info_2(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ PORT_INFO_2 **info)
+{
+ uint32 i;
+ PORT_INFO_2 *inf;
+
+ inf=(PORT_INFO_2*)talloc(mem_ctx, returned*sizeof(PORT_INFO_2));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ smb_io_port_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_1(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ DRIVER_INFO_1 **info
+)
+{
+ uint32 i;
+ DRIVER_INFO_1 *inf;
+
+ inf=(DRIVER_INFO_1 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_2(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ DRIVER_INFO_2 **info
+)
+{
+ uint32 i;
+ DRIVER_INFO_2 *inf;
+
+ inf=(DRIVER_INFO_2 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_3(
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ DRIVER_INFO_3 **info
+)
+{
+ uint32 i;
+ DRIVER_INFO_3 *inf;
+
+ inf=(DRIVER_INFO_3 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printerdriverdir_1 (
+ TALLOC_CTX *mem_ctx,
+ NEW_BUFFER *buffer,
+ uint32 returned,
+ DRIVER_DIRECTORY_1 **info
+)
+{
+ DRIVER_DIRECTORY_1 *inf;
+
+ inf=(DRIVER_DIRECTORY_1 *)talloc(mem_ctx, sizeof(DRIVER_DIRECTORY_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ smb_io_driverdir_1("", buffer, inf, 0);
+
+ *info=inf;
+}
+
+
+/* Enumerate printers */
+
+NTSTATUS cli_spoolss_enum_printers(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 flags,
+ uint32 level,
+ int *returned,
+ PRINTER_INFO_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERS q;
+ SPOOL_R_ENUMPRINTERS r;
+ NEW_BUFFER buffer;
+ uint32 needed = 100;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ fstrcpy (server, cli->desthost);
+ strupper (server);
+
+ do {
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_enumprinters(&q, flags, server, level, &buffer,
+ needed);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumprinters("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMPRINTERS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_enumprinters("", &r, &rbuf, 0)) {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ if (!W_ERROR_IS_OK(r.status)) {
+ result = werror_to_ntstatus(r.status);
+ goto done;
+ }
+
+ if ((*returned = r.returned)) {
+ switch (level) {
+ case 1:
+ decode_printer_info_1(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_1);
+ break;
+ case 2:
+ decode_printer_info_2(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_2);
+ break;
+ case 3:
+ decode_printer_info_3(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+/* Enumerate printer ports */
+NTSTATUS cli_spoolss_enum_ports(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ int *returned,
+ PORT_INFO_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPORTS q;
+ SPOOL_R_ENUMPORTS r;
+ NEW_BUFFER buffer;
+ uint32 needed = 100;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ do {
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_enumports(&q, server, level, &buffer, needed);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumports("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMPORTS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_enumports("", &r, &rbuf, 0)) {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+
+ if (NT_STATUS_IS_OK(result) &&
+ r.returned > 0) {
+
+ *returned = r.returned;
+
+ switch (level) {
+ case 1:
+ decode_port_info_1(mem_ctx, r.buffer, r.returned,
+ &ctr->port.info_1);
+ break;
+ case 2:
+ decode_port_info_2(mem_ctx, r.buffer, r.returned,
+ &ctr->port.info_2);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+/* Get printer info */
+NTSTATUS cli_spoolss_getprinter(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTER q;
+ SPOOL_R_GETPRINTER r;
+ NEW_BUFFER buffer;
+ uint32 needed = 100;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ do {
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_getprinter(mem_ctx, &q, pol, level, &buffer, needed);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_getprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_GETPRINTER, &qbuf, &rbuf))
+ {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_getprinter("", &r, &rbuf, 0)) {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+ if (NT_STATUS_IS_OK(result)) {
+ switch (level) {
+ case 0:
+ decode_printer_info_0(mem_ctx, r.buffer, 1, &ctr->printers_0);
+ break;
+ case 1:
+ decode_printer_info_1(mem_ctx, r.buffer, 1, &ctr->printers_1);
+ break;
+ case 2:
+ decode_printer_info_2(mem_ctx, r.buffer, 1, &ctr->printers_2);
+ break;
+ case 3:
+ decode_printer_info_3(mem_ctx, r.buffer, 1, &ctr->printers_3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+/**********************************************************************
+ * Set printer info
+ */
+NTSTATUS cli_spoolss_setprinter(
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr,
+ uint32 command
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTER q;
+ SPOOL_R_SETPRINTER r;
+ NTSTATUS result = NT_STATUS_ACCESS_DENIED;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise input parameters */
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_setprinter(mem_ctx, &q, pol, level, ctr, command);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_setprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_SETPRINTER, &qbuf, &rbuf))
+ {
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (!spoolss_io_r_setprinter("", &r, &rbuf, 0))
+ {
+ goto done;
+ }
+
+ result = werror_to_ntstatus(r.status);
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+
+ return result;
+}
+
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+NTSTATUS cli_spoolss_getprinterdriver (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol,
+ uint32 level,
+ char* env,
+ PRINTER_DRIVER_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVER2 q;
+ SPOOL_R_GETPRINTERDRIVER2 r;
+ NEW_BUFFER buffer;
+ uint32 needed = 1024;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ fstrcpy (server, cli->desthost);
+ strupper (server);
+
+ do
+ {
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_getprinterdriver2(&q, pol, env, level, 2, 2, &buffer, needed);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_getprinterdriver2 ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_GETPRINTERDRIVER2, &qbuf, &rbuf))
+ {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_getprinterdriver2 ("", &r, &rbuf, 0))
+ {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+ if (NT_STATUS_IS_OK(result))
+ {
+ switch (level)
+ {
+ case 1:
+ decode_printer_driver_1(mem_ctx, r.buffer, 1, &ctr->info1);
+ break;
+ case 2:
+ decode_printer_driver_2(mem_ctx, r.buffer, 1, &ctr->info2);
+ break;
+ case 3:
+ decode_printer_driver_3(mem_ctx, r.buffer, 1, &ctr->info3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+NTSTATUS cli_spoolss_enumprinterdrivers (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ char* env,
+ uint32 *returned,
+ PRINTER_DRIVER_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERDRIVERS q;
+ SPOOL_R_ENUMPRINTERDRIVERS r;
+ NEW_BUFFER buffer;
+ uint32 needed = 0;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ do
+ {
+ /* Initialise input parameters */
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_enumprinterdrivers(&q, server, env, level, &buffer, needed);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_enumprinterdrivers ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ENUMPRINTERDRIVERS, &qbuf, &rbuf))
+ {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_enumprinterdrivers ("", &r, &rbuf, 0))
+ {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+ if (NT_STATUS_IS_OK(result) &&
+ (r.returned != 0))
+ {
+ *returned = r.returned;
+
+ switch (level)
+ {
+ case 1:
+ decode_printer_driver_1(mem_ctx, r.buffer, r.returned, &ctr->info1);
+ break;
+ case 2:
+ decode_printer_driver_2(mem_ctx, r.buffer, r.returned, &ctr->info2);
+ break;
+ case 3:
+ decode_printer_driver_3(mem_ctx, r.buffer, r.returned, &ctr->info3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+NTSTATUS cli_spoolss_getprinterdriverdir (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ char* env,
+ DRIVER_DIRECTORY_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVERDIR q;
+ SPOOL_R_GETPRINTERDRIVERDIR r;
+ NEW_BUFFER buffer;
+ uint32 needed = 100;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ do
+ {
+ /* Initialise input parameters */
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_getprinterdriverdir(&q, server, env, level, &buffer, needed);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_getprinterdriverdir ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_GETPRINTERDRIVERDIRECTORY, &qbuf, &rbuf))
+ {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+ if (spoolss_io_r_getprinterdriverdir ("", &r, &rbuf, 0))
+ {
+ needed = r.needed;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+ if (NT_STATUS_IS_OK(result))
+ {
+ switch (level)
+ {
+ case 1:
+ decode_printerdriverdir_1(mem_ctx, r.buffer, 1, &ctr->info1);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ } while (NT_STATUS_V(result) == NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ return result;
+}
+
+/**********************************************************************
+ * Install a printer driver
+ */
+NTSTATUS cli_spoolss_addprinterdriver (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ PRINTER_DRIVER_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTERDRIVER q;
+ SPOOL_R_ADDPRINTERDRIVER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_addprinterdriver (mem_ctx, &q, server, level, ctr);
+
+ /* Marshall data and send request */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_q_addprinterdriver ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTERDRIVER, &qbuf, &rbuf))
+ {
+ goto done;
+ }
+
+
+ /* Unmarshall response */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_r_addprinterdriver ("", &r, &rbuf, 0))
+ {
+ goto done;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/**********************************************************************
+ * Install a printer
+ */
+NTSTATUS cli_spoolss_addprinterex (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTEREX q;
+ SPOOL_R_ADDPRINTEREX r;
+ NTSTATUS result;
+ fstring server,
+ client,
+ user;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (client, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (client);
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+ fstrcpy (user, cli->user_name);
+
+
+ /* Initialise input parameters */
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_addprinterex (mem_ctx, &q, server, client, user, level, ctr);
+
+ /* Marshall data and send request */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_q_addprinterex ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTEREX, &qbuf, &rbuf))
+ {
+ goto done;
+ }
+
+
+ /* Unmarshall response */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_r_addprinterex ("", &r, &rbuf, 0))
+ {
+ goto done;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/**********************************************************************
+ * Delete a Printer Driver from the server (does not remove
+ * the driver files
+ */
+NTSTATUS cli_spoolss_deleteprinterdriver (
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ char *arch,
+ char *driver
+)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDRIVER q;
+ SPOOL_R_DELETEPRINTERDRIVER r;
+ NTSTATUS result;
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+
+ /* Initialise input parameters */
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* write the request */
+ make_spoolss_q_deleteprinterdriver (mem_ctx, &q, server, arch, driver);
+
+ /* Marshall data and send request */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_q_deleteprinterdriver ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli,SPOOLSS_DELETEPRINTERDRIVER , &qbuf, &rbuf))
+ {
+ goto done;
+ }
+
+
+ /* Unmarshall response */
+ result = NT_STATUS_UNSUCCESSFUL;
+ if (!spoolss_io_r_deleteprinterdriver ("", &r, &rbuf, 0))
+ {
+ goto done;
+ }
+
+ /* Return output parameters */
+ result = werror_to_ntstatus(r.status);
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Get print processor directory */
+
+NTSTATUS cli_spoolss_getprintprocessordirectory(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ char *name,
+ char *environment,
+ fstring procdir)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTPROCESSORDIRECTORY q;
+ SPOOL_R_GETPRINTPROCESSORDIRECTORY r;
+ NTSTATUS result;
+ int level = 1;
+ NEW_BUFFER buffer;
+ uint32 needed = 100;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+
+ /* Initialise input parameters */
+
+ do {
+ init_buffer(&buffer, needed, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_getprintprocessordirectory(&q, name,
+ environment, level,
+ &buffer, needed);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getprintprocessordirectory("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_GETPRINTPROCESSORDIRECTORY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_getprintprocessordirectory("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = werror_to_ntstatus(r.status);
+
+ } while (NT_STATUS_V(result) ==
+ NT_STATUS_V(ERROR_INSUFFICIENT_BUFFER));
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source/libsmb/cli_srvsvc.c b/source/libsmb/cli_srvsvc.c
new file mode 100644
index 00000000000..c9bd4643622
--- /dev/null
+++ b/source/libsmb/cli_srvsvc.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Opens a SMB connection to the svrsvc pipe */
+
+struct cli_state *cli_svrsvc_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SRVSVC, creds);
+}
+
+NTSTATUS cli_srvsvc_net_srv_get_info(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 switch_value, SRV_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SRV_Q_NET_SRV_GET_INFO q;
+ SRV_R_NET_SRV_GET_INFO r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_srv_q_net_srv_get_info(&q, cli->srv_name_slash, switch_value);
+
+ /* Marshall data and send request */
+
+ if (!srv_io_q_net_srv_get_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SRV_NET_SRV_GET_INFO, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!srv_io_r_net_srv_get_info("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
new file mode 100644
index 00000000000..fc50e8e02fe
--- /dev/null
+++ b/source/libsmb/cliconnect.c
@@ -0,0 +1,1343 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+static const struct {
+ int prot;
+ const char *name;
+ }
+prots[] =
+ {
+ {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1,"LANMAN1.0"},
+ {PROTOCOL_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+ {-1,NULL}
+ };
+
+
+/****************************************************************************
+do an old lanman2 style session setup
+****************************************************************************/
+static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
+ char *pass, int passlen)
+{
+ fstring pword;
+ char *p;
+
+ if (passlen > sizeof(pword)-1) {
+ return False;
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(cli->sec_mode & 1)) {
+ passlen = 0;
+ }
+
+ if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
+ /* Encrypted mode needed, and non encrypted password supplied. */
+ passlen = 24;
+ clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
+ } else if ((cli->sec_mode & 2) && passlen == 24) {
+ /* Encrypted mode needed, and encrypted password supplied. */
+ memcpy(pword, pass, passlen);
+ } else if (passlen > 0) {
+ /* Plaintext mode needed, assume plaintext supplied. */
+ passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,10, 0, True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+work out suitable capabilities to offer the server
+****************************************************************************/
+static uint32 cli_session_setup_capabilities(struct cli_state *cli)
+{
+ uint32 capabilities = CAP_NT_SMBS;
+
+ if (!cli->force_dos_errors) {
+ capabilities |= CAP_STATUS32;
+ }
+
+ if (cli->use_level_II_oplocks) {
+ capabilities |= CAP_LEVEL_II_OPLOCKS;
+ }
+
+ if (cli->capabilities & CAP_UNICODE) {
+ capabilities |= CAP_UNICODE;
+ }
+
+ return capabilities;
+}
+
+
+/****************************************************************************
+do a NT1 guest session setup
+****************************************************************************/
+static BOOL cli_session_setup_guest(struct cli_state *cli)
+{
+ char *p;
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+
+ set_message(cli->outbuf,13,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ fstrcpy(cli->user_name, "");
+
+ return True;
+}
+
+
+/****************************************************************************
+do a NT1 plaintext session setup
+****************************************************************************/
+static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ fstring pword;
+ int passlen;
+ char *p;
+
+ passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
+
+ set_message(cli->outbuf,13,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p, pword, passlen);
+ p += passlen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+do a NT1 NTLM/LM encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ fstring pword, ntpword;
+ char *p;
+
+ if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
+ return False;
+ }
+
+ if (passlen != 24) {
+ /* non encrypted password supplied. Ignore ntpass. */
+ passlen = 24;
+ ntpasslen = 24;
+ clistr_push(cli, pword,
+ pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
+ clistr_push(cli, ntpword,
+ pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
+ SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
+ SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
+ } else {
+ memcpy(pword, pass, passlen);
+ memcpy(ntpword, ntpass, ntpasslen);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,13,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen); p += passlen;
+ memcpy(p,ntpword,ntpasslen); p += ntpasslen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a extended security session setup blob, returning a reply blob
+****************************************************************************/
+static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ char *p;
+ DATA_BLOB blob2;
+
+ blob2 = data_blob(NULL, 0);
+
+ capabilities |= CAP_EXTENDED_SECURITY;
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,12,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv7,blob.length);
+ SIVAL(cli->outbuf,smb_vwv10,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p, blob.data, blob.length);
+ p += blob.length;
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return blob2;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return blob2;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+
+ blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
+
+ p += blob2.length;
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ return blob2;
+}
+
+
+#ifdef HAVE_KRB5
+/****************************************************************************
+do a spnego/kerberos encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
+{
+ DATA_BLOB blob2, negTokenTarg;
+
+ DEBUG(2,("Doing kerberos session setup\n"));
+
+ /* generate the encapsulated kerberos5 ticket */
+ negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
+
+ if (!negTokenTarg.data) return False;
+
+#if 0
+ file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+#endif
+
+ blob2 = cli_session_setup_blob(cli, negTokenTarg);
+
+ /* we don't need this blob for kerberos */
+ data_blob_free(&blob2);
+
+ data_blob_free(&negTokenTarg);
+
+ return !cli_is_error(cli);
+}
+#endif
+
+/****************************************************************************
+do a spnego/NTLMSSP encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ const char *mechs[] = {OID_NTLMSSP, NULL};
+ DATA_BLOB msg1;
+ DATA_BLOB blob, chal1, chal2, auth;
+ uint8 challenge[8];
+ uint8 nthash[24], lmhash[24], sess_key[16];
+ uint32 neg_flags;
+
+ neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_LM_KEY |
+ NTLMSSP_NEGOTIATE_NTLM;
+
+ memset(sess_key, 0, 16);
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(&blob, "CddB",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ neg_flags,
+ sess_key, 16);
+
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenTarg(mechs, blob);
+ data_blob_free(&blob);
+
+ /* now send that blob on its way */
+ blob = cli_session_setup_blob(cli, msg1);
+
+ data_blob_free(&msg1);
+
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return False;
+ }
+
+#if 0
+ file_save("chal.dat", blob.data, blob.length);
+#endif
+
+ /* the server gives us back two challenges */
+ if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
+ DEBUG(3,("Failed to parse challenges\n"));
+ return False;
+ }
+
+ data_blob_free(&blob);
+
+ /* encrypt the password with the challenge */
+ memcpy(challenge, chal1.data + 24, 8);
+ SMBencrypt((unsigned char *)pass, challenge,lmhash);
+ SMBNTencrypt((unsigned char *)pass, challenge,nthash);
+
+#if 0
+ file_save("nthash.dat", nthash, 24);
+ file_save("lmhash.dat", lmhash, 24);
+ file_save("chal1.dat", chal1.data, chal1.length);
+#endif
+
+ data_blob_free(&chal1);
+ data_blob_free(&chal2);
+
+ /* this generates the actual auth packet */
+ msrpc_gen(&blob, "CdBBUUUBd",
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lmhash, 24,
+ nthash, 24,
+ workgroup,
+ user,
+ cli->calling.name,
+ sess_key, 16,
+ neg_flags);
+
+ /* wrap it in SPNEGO */
+ auth = spnego_gen_auth(blob);
+
+ data_blob_free(&blob);
+
+ /* now send the auth packet and we should be done */
+ blob = cli_session_setup_blob(cli, auth);
+
+ data_blob_free(&auth);
+ data_blob_free(&blob);
+
+ return !cli_is_error(cli);
+}
+
+
+/****************************************************************************
+do a spnego encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ char *principal;
+ char *OIDs[ASN1_MAX_OIDS];
+ uint8 guid[16];
+ int i;
+ BOOL got_kerberos_mechanism = False;
+
+ DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
+
+ /* the server might not even do spnego */
+ if (cli->secblob.length == 16) {
+ DEBUG(3,("server didn't supply a full spnego negprot\n"));
+ goto ntlmssp;
+ }
+
+#if 0
+ file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
+#endif
+
+ /* the server sent us the first part of the SPNEGO exchange in the negprot
+ reply */
+ if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
+ return False;
+ }
+
+ /* make sure the server understands kerberos */
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ got_kerberos_mechanism = True;
+ }
+ free(OIDs[i]);
+ }
+ DEBUG(3,("got principal=%s\n", principal));
+
+ fstrcpy(cli->user_name, user);
+
+#ifdef HAVE_KRB5
+ if (got_kerberos_mechanism && cli->use_kerberos) {
+ return cli_session_setup_kerberos(cli, principal, workgroup);
+ }
+#endif
+
+ free(principal);
+
+ntlmssp:
+
+ return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
+}
+
+
+/****************************************************************************
+ Send a session setup. The username and workgroup is in UNIX character
+ format and must be converted to DOS codepage format before sending. If the
+ password is in plaintext, the same should be done.
+****************************************************************************/
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ char *p;
+ fstring user2;
+
+ /* allow for workgroups as part of the username */
+ fstrcpy(user2, user);
+ if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
+ *p = 0;
+ user = p+1;
+ workgroup = user2;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN1)
+ return True;
+
+ /* now work out what sort of session setup we are going to
+ do. I have split this into separate functions to make the
+ flow a bit easier to understand (tridge) */
+
+ /* if its an older server then we have to use the older request format */
+ if (cli->protocol < PROTOCOL_NT1) {
+ return cli_session_setup_lanman2(cli, user, pass, passlen);
+ }
+
+ /* if no user is supplied then we have to do an anonymous connection.
+ passwords are ignored */
+ if (!user || !*user) {
+ return cli_session_setup_guest(cli);
+ }
+
+ /* if the server is share level then send a plaintext null
+ password at this point. The password is sent in the tree
+ connect */
+ if ((cli->sec_mode & 1) == 0) {
+ return cli_session_setup_plaintext(cli, user, "", workgroup);
+ }
+
+ /* if the server doesn't support encryption then we have to use plaintext. The
+ second password is ignored */
+ if ((cli->sec_mode & 2) == 0) {
+ return cli_session_setup_plaintext(cli, user, pass, workgroup);
+ }
+
+ /* if the server supports extended security then use SPNEGO */
+ if (cli->capabilities & CAP_EXTENDED_SECURITY) {
+ return cli_session_setup_spnego(cli, user, pass, workgroup);
+ }
+
+ /* otherwise do a NT1 style session setup */
+ return cli_session_setup_nt1(cli, user,
+ pass, passlen, ntpass, ntpasslen,
+ workgroup);
+}
+
+/****************************************************************************
+ Send a uloggoff.
+*****************************************************************************/
+
+BOOL cli_ulogoff(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,2,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBulogoffX;
+ cli_setup_packet(cli);
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ return !cli_is_error(cli);
+}
+
+/****************************************************************************
+send a tconX
+****************************************************************************/
+BOOL cli_send_tconX(struct cli_state *cli,
+ const char *share, const char *dev, const char *pass, int passlen)
+{
+ fstring fullshare, pword, dos_pword;
+ char *p;
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ fstrcpy(cli->share, share);
+
+ /* in user level security don't send a password now */
+ if (cli->sec_mode & 1) {
+ passlen = 1;
+ pass = "";
+ }
+
+ if ((cli->sec_mode & 2) && *pass && passlen != 24) {
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before encryption.
+ */
+ passlen = 24;
+ clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
+ SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
+ } else {
+ if((cli->sec_mode & 3) == 0) {
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before using.
+ */
+ passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+ }
+
+ if (cli->port == 445) {
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "%s", share);
+ } else {
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "\\\\%s\\%s", cli->desthost, share);
+ }
+
+ set_message(cli->outbuf,4, 0, True);
+ CVAL(cli->outbuf,smb_com) = SMBtconX;
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv3,passlen);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
+ fstrcpy(p, dev); p += strlen(dev)+1;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
+
+ if (strcasecmp(share,"IPC$")==0) {
+ fstrcpy(cli->dev, "IPC");
+ }
+
+ if (cli->protocol >= PROTOCOL_NT1 &&
+ smb_buflen(cli->inbuf) == 3) {
+ /* almost certainly win95 - enable bug fixes */
+ cli->win95 = True;
+ }
+
+ cli->cnum = SVAL(cli->inbuf,smb_tid);
+ return True;
+}
+
+
+/****************************************************************************
+send a tree disconnect
+****************************************************************************/
+BOOL cli_tdis(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBtdis;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ return !cli_is_error(cli);
+}
+
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+void cli_negprot_send(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ set_message(cli->outbuf,0,0,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ CVAL(cli->outbuf,smb_com) = SMBnegprot;
+ cli_setup_bcc(cli, p);
+ cli_setup_packet(cli);
+
+ CVAL(smb_buf(cli->outbuf),0) = 2;
+
+ cli_send_smb(cli);
+}
+
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+BOOL cli_negprot(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+ int plength;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ for (plength=0,numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++)
+ plength += strlen(prots[numprots].name)+2;
+
+ set_message(cli->outbuf,0,plength,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ CVAL(cli->outbuf,smb_com) = SMBnegprot;
+ cli_setup_packet(cli);
+
+ CVAL(smb_buf(cli->outbuf),0) = 2;
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) ||
+ ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
+ return(False);
+ }
+
+ cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+
+ if (cli->protocol >= PROTOCOL_NT1) {
+ /* NT protocol */
+ cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
+ cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
+ cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
+ cli->serverzone *= 60;
+ /* this time arrives in real GMT */
+ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
+ if (cli->capabilities & CAP_RAW_MODE) {
+ cli->readbraw_supported = True;
+ cli->writebraw_supported = True;
+ }
+ /* work out if they sent us a workgroup */
+ if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
+ smb_buflen(cli->inbuf) > 8) {
+ clistr_pull(cli, cli->server_domain,
+ smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
+ smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
+ }
+ } else if (cli->protocol >= PROTOCOL_LANMAN1) {
+ cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
+ cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
+ cli->serverzone *= 60;
+ /* this time is converted to GMT by make_unix_date */
+ cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
+ cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
+ cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ } else {
+ /* the old core protocol */
+ cli->sec_mode = 0;
+ cli->serverzone = TimeDiff(time(NULL));
+ }
+
+ cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
+
+ /* a way to force ascii SMB */
+ if (getenv("CLI_FORCE_ASCII")) {
+ cli->capabilities &= ~CAP_UNICODE;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ send a session request. see rfc1002.txt 4.3 and 4.3.2
+****************************************************************************/
+BOOL cli_session_request(struct cli_state *cli,
+ struct nmb_name *calling, struct nmb_name *called)
+{
+ char *p;
+ int len = 4;
+ extern pstring user_socket_options;
+
+ /* 445 doesn't have session request */
+ if (cli->port == 445) return True;
+
+ /* send a session request (RFC 1002) */
+ memcpy(&(cli->calling), calling, sizeof(*calling));
+ memcpy(&(cli->called ), called , sizeof(*called ));
+
+ /* put in the destination name */
+ p = cli->outbuf+len;
+ name_mangle(cli->called .name, p, cli->called .name_type);
+ len += name_len(p);
+
+ /* and my name */
+ p = cli->outbuf+len;
+ name_mangle(cli->calling.name, p, cli->calling.name_type);
+ len += name_len(p);
+
+ /* setup the packet length */
+ _smb_setlen(cli->outbuf,len);
+ CVAL(cli->outbuf,0) = 0x81;
+
+#ifdef WITH_SSL
+retry:
+#endif /* WITH_SSL */
+
+ cli_send_smb(cli);
+ DEBUG(5,("Sent session request\n"));
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (CVAL(cli->inbuf,0) == 0x84) {
+ /* C. Hoch 9/14/95 Start */
+ /* For information, here is the response structure.
+ * We do the byte-twiddling to for portability.
+ struct RetargetResponse{
+ unsigned char type;
+ unsigned char flags;
+ int16 length;
+ int32 ip_addr;
+ int16 port;
+ };
+ */
+ int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
+ /* SESSION RETARGET */
+ putip((char *)&cli->dest_ip,cli->inbuf+4);
+
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
+ if (cli->fd == -1)
+ return False;
+
+ DEBUG(3,("Retargeted\n"));
+
+ set_socket_options(cli->fd,user_socket_options);
+
+ /* Try again */
+ {
+ static int depth;
+ BOOL ret;
+ if (depth > 4) {
+ DEBUG(0,("Retarget recursion - failing\n"));
+ return False;
+ }
+ depth++;
+ ret = cli_session_request(cli, calling, called);
+ depth--;
+ return ret;
+ }
+ } /* C. Hoch 9/14/95 End */
+
+#ifdef WITH_SSL
+ if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
+ if (!sslutil_fd_is_ssl(cli->fd)){
+ if (sslutil_connect(cli->fd) == 0)
+ goto retry;
+ }
+ }
+#endif /* WITH_SSL */
+
+ if (CVAL(cli->inbuf,0) != 0x82) {
+ /* This is the wrong place to put the error... JRA. */
+ cli->rap_error = CVAL(cli->inbuf,4);
+ return False;
+ }
+ return(True);
+}
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
+{
+ extern pstring user_socket_options;
+ int name_type = 0x20;
+ char *p;
+
+ /* reasonable default hostname */
+ if (!host) host = "*SMBSERVER";
+
+ fstrcpy(cli->desthost, host);
+
+ /* allow hostnames of the form NAME#xx and do a netbios lookup */
+ if ((p = strchr(cli->desthost, '#'))) {
+ name_type = strtol(p+1, NULL, 16);
+ *p = 0;
+ }
+
+ if (!ip || is_zero_ip(*ip)) {
+ if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
+ return False;
+ }
+ if (ip) *ip = cli->dest_ip;
+ } else {
+ cli->dest_ip = *ip;
+ }
+
+ if (getenv("LIBSMB_PROG")) {
+ cli->fd = sock_exec(getenv("LIBSMB_PROG"));
+ } else {
+ /* try 445 first, then 139 */
+ int port = cli->port?cli->port:445;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
+ port, cli->timeout);
+ if (cli->fd == -1 && cli->port == 0) {
+ port = 139;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
+ port, cli->timeout);
+ }
+ if (cli->fd != -1) cli->port = port;
+ }
+ if (cli->fd == -1) {
+ DEBUG(1,("Error connecting to %s (%s)\n",
+ inet_ntoa(*ip),strerror(errno)));
+ return False;
+ }
+
+ set_socket_options(cli->fd,user_socket_options);
+
+ return True;
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, password in cache.
+****************************************************************************/
+BOOL cli_establish_connection(struct cli_state *cli,
+ char *dest_host, struct in_addr *dest_ip,
+ struct nmb_name *calling, struct nmb_name *called,
+ char *service, char *service_type,
+ BOOL do_shutdown, BOOL do_tcon)
+{
+ DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
+ nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
+ cli->user_name, cli->domain));
+
+ /* establish connection */
+
+ if ((!cli->initialised))
+ {
+ return False;
+ }
+
+ /* cli_establish_connection() can't handle spnego yet. Once we get rid of
+ pwd_cache and other horrors we can get rid of this */
+ cli->use_spnego = False;
+
+ if (cli->fd == -1)
+ {
+ if (!cli_connect(cli, dest_host, dest_ip))
+ {
+ DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
+ nmb_namestr(called), inet_ntoa(*dest_ip)));
+ return False;
+ }
+ }
+
+ if (!cli_session_request(cli, calling, called))
+ {
+ DEBUG(1,("failed session request\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_negprot(cli))
+ {
+ DEBUG(1,("failed negprot\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (cli->pwd.cleartext || cli->pwd.null_pwd)
+ {
+ fstring passwd;
+ int pass_len;
+
+ if (cli->pwd.null_pwd)
+ {
+ /* attempt null session */
+ passwd[0] = 0;
+ pass_len = 1;
+ }
+ else
+ {
+ /* attempt clear-text session */
+ pwd_get_cleartext(&(cli->pwd), passwd);
+ pass_len = strlen(passwd);
+ }
+
+ /* attempt clear-text session */
+ if (!cli_session_setup(cli, cli->user_name,
+ passwd, pass_len,
+ NULL, 0,
+ cli->domain))
+ {
+ DEBUG(1,("failed session setup\n"));
+ if (do_shutdown)
+ {
+ cli_shutdown(cli);
+ }
+ return False;
+ }
+ if (do_tcon)
+ {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)passwd, strlen(passwd)))
+ {
+ DEBUG(1,("failed tcon_X\n"));
+ if (do_shutdown)
+ {
+ cli_shutdown(cli);
+ }
+ return False;
+ }
+ }
+ }
+ else
+ {
+ /* attempt encrypted session */
+ unsigned char nt_sess_pwd[24];
+ unsigned char lm_sess_pwd[24];
+
+ /* creates (storing a copy of) and then obtains a 24 byte password OWF */
+ pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
+ pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
+
+ /* attempt encrypted session */
+ if (!cli_session_setup(cli, cli->user_name,
+ (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
+ (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
+ cli->domain))
+ {
+ DEBUG(1,("failed session setup\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ DEBUG(1,("session setup ok\n"));
+
+ if (*cli->server_domain || *cli->server_os || *cli->server_type)
+ {
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ cli->server_domain,
+ cli->server_os,
+ cli->server_type));
+ }
+
+ if (do_tcon)
+ {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
+ {
+ DEBUG(1,("failed tcon_X\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+ }
+ }
+
+ if (do_shutdown)
+ cli_shutdown(cli);
+
+ return True;
+}
+
+/* Initialise client credentials for authenticated pipe access */
+
+static void init_creds(struct ntuser_creds *creds, char* username,
+ char* domain, char* password, int pass_len)
+{
+ ZERO_STRUCTP(creds);
+
+ pwd_set_cleartext(&creds->pwd, password);
+
+ fstrcpy(creds->user_name, username);
+ fstrcpy(creds->domain, domain);
+
+ if (!*username) {
+ creds->pwd.null_pwd = True;
+ }
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, password specified.
+****************************************************************************/
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name, const char *dest_host,
+ struct in_addr *dest_ip, int port,
+ char *service, char *service_type,
+ char *user, char *domain,
+ char *password, int pass_len)
+{
+ struct ntuser_creds creds;
+ NTSTATUS nt_status;
+ struct nmb_name calling;
+ struct nmb_name called;
+ struct cli_state *cli;
+ struct in_addr ip;
+
+ make_nmb_name(&calling, my_name, 0x0);
+ make_nmb_name(&called , dest_host, 0x20);
+
+again:
+
+ if (!(cli = cli_initialise(NULL))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (cli_set_port(cli, port) != port) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ip = *dest_ip;
+
+ DEBUG(3,("Connecting to host=%s share=%s\n\n",
+ dest_host, service));
+
+ if (!cli_connect(cli, dest_host, &ip))
+ {
+ DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
+ nmb_namestr(&called), inet_ntoa(*dest_ip)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ char *p;
+ DEBUG(1,("session request to %s failed (%s)\n",
+ called.name, cli_errstr(cli)));
+ cli_shutdown(cli);
+ if ((p=strchr(called.name, '.'))) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_negprot(cli))
+ {
+ DEBUG(1,("failed negprot\n"));
+ nt_status = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ if (!cli_session_setup(cli, user,
+ password, pass_len,
+ NULL, 0,
+ domain))
+ {
+ DEBUG(1,("failed session setup\n"));
+ nt_status = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ if (service)
+ {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)password, pass_len))
+ {
+ DEBUG(1,("failed tcon_X\n"));
+ nt_status = cli_nt_error(cli);
+ cli_shutdown(cli);
+ return nt_status;
+ }
+ }
+
+ init_creds(&creds, user, domain, password, pass_len);
+ cli_init_creds(cli, &creds);
+
+ *output_cli = cli;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
+****************************************************************************/
+
+BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
+ struct in_addr *pdest_ip)
+{
+ struct nmb_name calling, called;
+
+ make_nmb_name(&calling, srchost, 0x0);
+
+ /*
+ * If the called name is an IP address
+ * then use *SMBSERVER immediately.
+ */
+
+ if(is_ipaddress(desthost))
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+ else
+ make_nmb_name(&called, desthost, 0x20);
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ struct nmb_name smbservername;
+
+ make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
+
+ /*
+ * If the name wasn't *SMBSERVER then
+ * try with *SMBSERVER if the first name fails.
+ */
+
+ if (nmb_name_equal(&called, &smbservername)) {
+
+ /*
+ * The name used was *SMBSERVER, don't bother with another name.
+ */
+
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
+with error %s.\n", desthost, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli_shutdown(cli);
+
+ if (!cli_initialise(cli) ||
+ !cli_connect(cli, desthost, pdest_ip) ||
+ !cli_session_request(cli, &calling, &smbservername)) {
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
+name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+
diff --git a/source/libsmb/clidgram.c b/source/libsmb/clidgram.c
new file mode 100644
index 00000000000..e990739de5a
--- /dev/null
+++ b/source/libsmb/clidgram.c
@@ -0,0 +1,272 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client dgram calls
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*
+ * cli_send_mailslot, send a mailslot for client code ...
+ */
+
+int cli_send_mailslot(int dgram_sock, BOOL unique, char *mailslot,
+ char *buf, int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ struct in_addr dest_ip, struct in_addr src_ip,
+ int dest_port, int src_port)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr, *p2;
+ char tmp[4];
+
+ memset((char *)&p, '\0', sizeof(p));
+
+ /*
+ * Next, build the DGRAM ...
+ */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ dgram->header.source_ip.s_addr = src_ip.s_addr;
+ /*fprintf(stderr, "Source IP = %0X\n", dgram->header.source_ip); */
+ dgram->header.source_port = ntohs(src_port);
+ fprintf(stderr, "Source Port = %0X\n", dgram->header.source_port);
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ pstrcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = dest_ip;
+ p.port = dest_port;
+ p.fd = dgram_sock;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+ nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+ return send_packet(&p);
+
+}
+
+/*
+ * cli_get_response: Get a response ...
+ */
+int cli_get_response(int dgram_sock, BOOL unique, char *mailslot, char *buf, int bufsiz)
+{
+ struct packet_struct *packet;
+
+ packet = receive_dgram_packet(dgram_sock, 5, mailslot);
+
+ if (packet) { /* We got one, pull what we want out of the SMB data ... */
+
+ struct dgram_packet *dgram = &packet->packet.dgram;
+
+ /*
+ * We should probably parse the SMB, but for now, we will pull what
+ * from fixed, known locations ...
+ */
+
+ /* Copy the data to buffer, respecting sizes ... */
+
+ bcopy(&dgram->data[92], buf, MIN(bufsiz, (dgram->datasize - 92)));
+
+ }
+ else
+ return -1;
+
+ return 0;
+
+}
+
+/*
+ * cli_get_backup_list: Send a get backup list request ...
+ */
+
+static char cli_backup_list[1024];
+
+int cli_get_backup_list(const char *myname, const char *send_to_name)
+{
+ char outbuf[15];
+ char *p;
+ struct in_addr sendto_ip, my_ip;
+ int dgram_sock;
+ struct sockaddr_in sock_out;
+ socklen_t name_size;
+
+ if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
+
+ DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
+ return False;
+
+ }
+
+ my_ip.s_addr = inet_addr("0.0.0.0");
+
+ if (!resolve_name(myname, &my_ip, 0x00)) { /* FIXME: Call others here */
+
+ DEBUG(0, ("Could not resolve name: %s<00>\n", myname));
+
+ }
+
+ if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) {
+
+ DEBUG(4, ("open_sock_out failed ..."));
+ return False;
+
+ }
+
+ /* Make it a broadcast socket ... */
+
+ set_socket_options(dgram_sock, "SO_BROADCAST");
+
+ /* Make it non-blocking??? */
+
+ if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) {
+
+ DEBUG(0, ("Unable to set non blocking on dgram sock\n"));
+
+ }
+
+ /* Now, bind a local addr to it ... Try port 138 first ... */
+
+ memset((char *)&sock_out, '\0', sizeof(sock_out));
+ sock_out.sin_addr.s_addr = INADDR_ANY;
+ sock_out.sin_port = htons(138);
+ sock_out.sin_family = AF_INET;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ /* Try again on any port ... */
+
+ sock_out.sin_port = INADDR_ANY;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ DEBUG(4, ("failed to bind socket to address ...\n"));
+ return False;
+
+ }
+
+ }
+
+ /* Now, figure out what socket name we were bound to. We want the port */
+
+ name_size = sizeof(sock_out);
+
+ getsockname(dgram_sock, (struct sockaddr *)&sock_out, &name_size);
+
+ DEBUG(5, ("Socket bound to IP:%s, port: %d\n", inet_ntoa(sock_out.sin_addr), ntohs(sock_out.sin_port)));
+
+ /* Now, build the request */
+
+ memset(cli_backup_list, '\0', sizeof(cli_backup_list));
+ memset(outbuf, '\0', sizeof(outbuf));
+
+ p = outbuf;
+
+ SCVAL(p, 0, ANN_GetBackupListReq);
+ p++;
+
+ SCVAL(p, 0, 1); /* Count pointer ... */
+ p++;
+
+ SIVAL(p, 0, 1); /* The sender's token ... */
+ p += 4;
+
+ cli_send_mailslot(dgram_sock, True, "\\MAILSLOT\\BROWSE", outbuf,
+ PTR_DIFF(p, outbuf), myname, 0, send_to_name,
+ 0x1d, sendto_ip, my_ip, 138, sock_out.sin_port);
+
+ /* We should check the error and return if we got one */
+
+ /* Now, get the response ... */
+
+ cli_get_response(dgram_sock, True, "\\MAILSLOT\\BROWSE", cli_backup_list, sizeof(cli_backup_list));
+
+ /* Should check the response here ... FIXME */
+
+ close(dgram_sock);
+
+ return True;
+
+}
+
+/*
+ * cli_get_backup_server: Get the backup list and retrieve a server from it
+ */
+
+int cli_get_backup_server(char *my_name, char *target, char *servername, int namesize)
+{
+
+ /* Get the backup list first. We could pull this from the cache later */
+
+ cli_get_backup_list(my_name, target); /* FIXME: Check the response */
+
+ if (!cli_backup_list[0]) { /* Empty list ... try again */
+
+ cli_get_backup_list(my_name, target);
+
+ }
+
+ strncpy(servername, cli_backup_list, MIN(16, namesize));
+
+ return True;
+
+}
+
+
+
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
new file mode 100644
index 00000000000..610af9cc237
--- /dev/null
+++ b/source/libsmb/clientgen.c
@@ -0,0 +1,281 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client generic functions
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*
+ * Change the port number used to call on
+ */
+int cli_set_port(struct cli_state *cli, int port)
+{
+ cli->port = port;
+ return port;
+}
+
+/****************************************************************************
+recv an smb
+****************************************************************************/
+BOOL cli_receive_smb(struct cli_state *cli)
+{
+ BOOL ret;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1) return False;
+
+ again:
+ ret = client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
+
+ if (ret) {
+ /* it might be an oplock break request */
+ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
+ CVAL(cli->inbuf,smb_com) == SMBlockingX &&
+ SVAL(cli->inbuf,smb_vwv6) == 0 &&
+ SVAL(cli->inbuf,smb_vwv7) == 0) {
+ if (cli->oplock_handler) {
+ int fnum = SVAL(cli->inbuf,smb_vwv2);
+ unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
+ if (!cli->oplock_handler(cli, fnum, level)) return False;
+ }
+ /* try to prevent loops */
+ CVAL(cli->inbuf,smb_com) = 0xFF;
+ goto again;
+ }
+ }
+
+ /* If the server is not responding, note that now */
+
+ if (!ret) {
+ close(cli->fd);
+ cli->fd = -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ send an smb to a fd.
+****************************************************************************/
+
+BOOL cli_send_smb(struct cli_state *cli)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1) return False;
+
+ len = smb_len(cli->outbuf) + 4;
+
+ while (nwritten < len) {
+ ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
+ if (ret <= 0) {
+ close(cli->fd);
+ cli->fd = -1;
+ DEBUG(0,("Error writing %d bytes to client. %d\n",
+ (int)len,(int)ret));
+ return False;
+ }
+ nwritten += ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+void cli_setup_packet(struct cli_state *cli)
+{
+ cli->rap_error = 0;
+ SSVAL(cli->outbuf,smb_pid,cli->pid);
+ SSVAL(cli->outbuf,smb_uid,cli->vuid);
+ SSVAL(cli->outbuf,smb_mid,cli->mid);
+ if (cli->protocol > PROTOCOL_CORE) {
+ uint16 flags2;
+ SCVAL(cli->outbuf,smb_flg,0x8);
+ flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+ if (cli->capabilities & CAP_UNICODE) {
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ }
+ if (cli->capabilities & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ }
+ if (cli->use_spnego) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+ SSVAL(cli->outbuf,smb_flg2, flags2);
+ }
+}
+
+/****************************************************************************
+setup the bcc length of the packet from a pointer to the end of the data
+****************************************************************************/
+void cli_setup_bcc(struct cli_state *cli, void *p)
+{
+ set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf)));
+}
+
+
+
+/****************************************************************************
+initialise a client structure
+****************************************************************************/
+void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
+{
+ /* copy_nt_creds(&cli->usr, usr); */
+ safe_strcpy(cli->domain , usr->domain , sizeof(usr->domain )-1);
+ safe_strcpy(cli->user_name, usr->user_name, sizeof(usr->user_name)-1);
+ memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
+ cli->ntlmssp_flags = usr->ntlmssp_flags;
+ cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
+
+ DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
+ cli->user_name, cli->domain,
+ cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+}
+
+
+/****************************************************************************
+initialise a client structure
+****************************************************************************/
+struct cli_state *cli_initialise(struct cli_state *cli)
+{
+ BOOL alloced_cli = False;
+
+ /* Check the effective uid - make sure we are not setuid */
+ if (is_setuid_root()) {
+ DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
+ return NULL;
+ }
+
+ if (!cli) {
+ cli = (struct cli_state *)malloc(sizeof(*cli));
+ if (!cli)
+ return NULL;
+ ZERO_STRUCTP(cli);
+ alloced_cli = True;
+ }
+
+ if (cli->initialised) {
+ cli_shutdown(cli);
+ }
+
+ ZERO_STRUCTP(cli);
+
+ cli->port = 0;
+ cli->fd = -1;
+ cli->cnum = -1;
+ cli->pid = (uint16)sys_getpid();
+ cli->mid = 1;
+ cli->vuid = UID_FIELD_INVALID;
+ cli->protocol = PROTOCOL_NT1;
+ cli->timeout = 20000; /* Timeout is in milliseconds. */
+ cli->bufsize = CLI_BUFFER_SIZE+4;
+ cli->max_xmit = cli->bufsize;
+ cli->outbuf = (char *)malloc(cli->bufsize);
+ cli->inbuf = (char *)malloc(cli->bufsize);
+ cli->oplock_handler = cli_oplock_ack;
+ cli->use_spnego = True;
+
+ /* Set the CLI_FORCE_DOSERR environment variable to test
+ client routines using DOS errors instead of STATUS32
+ ones. This intended only as a temporary hack. */
+ if (getenv("CLI_FORCE_DOSERR")) {
+ cli->force_dos_errors = True;
+ }
+
+ if (!cli->outbuf || !cli->inbuf)
+ goto error;
+
+ if ((cli->mem_ctx = talloc_init()) == NULL)
+ goto error;
+
+ memset(cli->outbuf, 0, cli->bufsize);
+ memset(cli->inbuf, 0, cli->bufsize);
+
+ cli->nt_pipe_fnum = 0;
+
+ cli->initialised = 1;
+ cli->allocated = alloced_cli;
+
+ return cli;
+
+ /* Clean up after malloc() error */
+
+ error:
+
+ SAFE_FREE(cli->inbuf);
+ SAFE_FREE(cli->outbuf);
+
+ if (alloced_cli)
+ SAFE_FREE(cli);
+
+ return NULL;
+}
+
+/****************************************************************************
+shutdown a client structure
+****************************************************************************/
+void cli_shutdown(struct cli_state *cli)
+{
+ BOOL allocated;
+ SAFE_FREE(cli->outbuf);
+ SAFE_FREE(cli->inbuf);
+
+ data_blob_free(&cli->secblob);
+
+ if (cli->mem_ctx)
+ talloc_destroy(cli->mem_ctx);
+
+#ifdef WITH_SSL
+ if (cli->fd != -1)
+ sslutil_disconnect(cli->fd);
+#endif /* WITH_SSL */
+ if (cli->fd != -1)
+ close(cli->fd);
+ allocated = cli->allocated;
+ ZERO_STRUCTP(cli);
+ if (allocated) {
+ free(cli);
+ }
+}
+
+
+/****************************************************************************
+set socket options on a open connection
+****************************************************************************/
+void cli_sockopt(struct cli_state *cli, char *options)
+{
+ set_socket_options(cli->fd, options);
+}
+
+/****************************************************************************
+set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+uint16 cli_setpid(struct cli_state *cli, uint16 pid)
+{
+ uint16 ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
diff --git a/source/libsmb/clierror.c b/source/libsmb/clierror.c
new file mode 100644
index 00000000000..81e8be36a8f
--- /dev/null
+++ b/source/libsmb/clierror.c
@@ -0,0 +1,268 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client error handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*****************************************************
+ RAP error codes - a small start but will be extended.
+*******************************************************/
+
+static const struct
+{
+ int err;
+ char *message;
+} rap_errmap[] =
+{
+ {5, "User has insufficient privilege" },
+ {86, "The specified password is invalid" },
+ {2226, "Operation only permitted on a Primary Domain Controller" },
+ {2242, "The password of this user has expired." },
+ {2243, "The password of this user cannot change." },
+ {2244, "This password cannot be used now (password history conflict)." },
+ {2245, "The password is shorter than required." },
+ {2246, "The password of this user is too recent to change."},
+
+ /* these really shouldn't be here ... */
+ {0x80, "Not listening on called name"},
+ {0x81, "Not listening for calling name"},
+ {0x82, "Called name not present"},
+ {0x83, "Called name present, but insufficient resources"},
+
+ {0, NULL}
+};
+
+/****************************************************************************
+ return a description of an SMB error
+****************************************************************************/
+static char *cli_smb_errstr(struct cli_state *cli)
+{
+ return smb_dos_errstr(cli->inbuf);
+}
+
+/***************************************************************************
+ Return an error message - either an NT error, SMB error or a RAP error.
+ Note some of the NT errors are actually warnings or "informational" errors
+ in which case they can be safely ignored.
+****************************************************************************/
+
+char *cli_errstr(struct cli_state *cli)
+{
+ static fstring cli_error_message;
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
+ uint8 errclass;
+ int i;
+
+ /* Case #1: RAP error */
+ if (cli->rap_error) {
+ for (i = 0; rap_errmap[i].message != NULL; i++) {
+ if (rap_errmap[i].err == cli->rap_error) {
+ return rap_errmap[i].message;
+ }
+ }
+
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d",
+ cli->rap_error);
+
+ return cli_error_message;
+ }
+
+ /* Case #2: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+
+ return get_nt_error_msg(status);
+ }
+
+ cli_dos_error(cli, &errclass, &errnum);
+
+ /* Case #3: SMB error */
+
+ return cli_smb_errstr(cli);
+}
+
+
+/* Return the 32-bit NT status code from the last packet */
+NTSTATUS cli_nt_error(struct cli_state *cli)
+{
+ int flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ if (!(flgs2 & FLAGS2_32_BIT_ERROR_CODES)) {
+ int class = CVAL(cli->inbuf,smb_rcls);
+ int code = SVAL(cli->inbuf,smb_err);
+ return dos_to_ntstatus(class, code);
+ }
+
+ return NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+}
+
+
+/* Return the DOS error from the last packet - an error class and an error
+ code. */
+void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
+{
+ int flgs2;
+ char rcls;
+ int code;
+
+ if(!cli->initialised) return;
+
+ flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS ntstatus = NT_STATUS(IVAL(cli->inbuf, smb_rcls));
+ ntstatus_to_dos(ntstatus, eclass, ecode);
+ return;
+ }
+
+ rcls = CVAL(cli->inbuf,smb_rcls);
+ code = SVAL(cli->inbuf,smb_err);
+
+ if (eclass) *eclass = rcls;
+ if (ecode) *ecode = code;
+}
+
+/* Return a UNIX errno from a dos error class, error number tuple */
+
+int cli_errno_from_dos(uint8 eclass, uint32 num)
+{
+ if (eclass == ERRDOS) {
+ switch (num) {
+ case ERRbadfile: return ENOENT;
+ case ERRbadpath: return ENOTDIR;
+ case ERRnoaccess: return EACCES;
+ case ERRfilexists: return EEXIST;
+ case ERRrename: return EEXIST;
+ case ERRbadshare: return EBUSY;
+ case ERRlock: return EBUSY;
+ case ERRinvalidname: return ENOENT;
+ case ERRnosuchshare: return ENODEV;
+ }
+ }
+
+ if (eclass == ERRSRV) {
+ switch (num) {
+ case ERRbadpw: return EPERM;
+ case ERRaccess: return EACCES;
+ case ERRnoresource: return ENOMEM;
+ case ERRinvdevice: return ENODEV;
+ case ERRinvnetname: return ENODEV;
+ }
+ }
+
+ /* for other cases */
+ return EINVAL;
+}
+
+/* Return a UNIX errno from a NT status code */
+static struct {
+ NTSTATUS status;
+ int error;
+} nt_errno_map[] = {
+ {NT_STATUS_ACCESS_VIOLATION, EACCES},
+ {NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_DEVICE, ENODEV},
+ {NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_NO_MEMORY, ENOMEM},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
+ {NT_STATUS_SHARING_VIOLATION, EBUSY},
+ {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
+ {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
+ {NT_STATUS_PATH_NOT_COVERED, ENOENT},
+ {NT_STATUS(0), 0}
+};
+
+int cli_errno_from_nt(NTSTATUS status)
+{
+ int i;
+ DEBUG(10,("cli_errno_from_nt: 32 bit codes: code=%08x\n", NT_STATUS_V(status)));
+
+ /* Status codes without this bit set are not errors */
+
+ if (!(NT_STATUS_V(status) & 0xc0000000))
+ return 0;
+
+ for (i=0;nt_errno_map[i].error;i++) {
+ if (NT_STATUS_V(nt_errno_map[i].status) ==
+ NT_STATUS_V(status)) return nt_errno_map[i].error;
+ }
+
+ /* for all other cases - a default code */
+ return EINVAL;
+}
+
+/* Return a UNIX errno appropriate for the error received in the last
+ packet. */
+
+int cli_errno(struct cli_state *cli)
+{
+ NTSTATUS status;
+
+ if (cli_is_dos_error(cli)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(cli, &eclass, &ecode);
+ return cli_errno_from_dos(eclass, ecode);
+ }
+
+ status = cli_nt_error(cli);
+
+ return cli_errno_from_nt(status);
+}
+
+/* Return true if the last packet was in error */
+
+BOOL cli_is_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), rcls = 0;
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ /* Return error is error bits are set */
+ rcls = IVAL(cli->inbuf, smb_rcls);
+ return (rcls & 0xF0000000) == 0xC0000000;
+ }
+
+ /* Return error if error class in non-zero */
+
+ rcls = CVAL(cli->inbuf, smb_rcls);
+ return rcls != 0;
+}
+
+/* Return true if the last error was an NT error */
+
+BOOL cli_is_nt_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ return cli_is_error(cli) && (flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
+
+/* Return true if the last error was a DOS error */
+
+BOOL cli_is_dos_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c
new file mode 100644
index 00000000000..5c372552784
--- /dev/null
+++ b/source/libsmb/clifile.c
@@ -0,0 +1,830 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/****************************************************************************
+ Rename a file.
+****************************************************************************/
+
+BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1, 0, True);
+
+ CVAL(cli->outbuf,smb_com) = SMBmv;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli))
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+
+BOOL cli_unlink(struct cli_state *cli, const char *fname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1, 0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBunlink;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Create a directory.
+****************************************************************************/
+
+BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0, 0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBmkdir;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+
+BOOL cli_rmdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0, 0, True);
+
+ CVAL(cli->outbuf,smb_com) = SMBrmdir;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set or clear the delete on close flag.
+****************************************************************************/
+
+int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+{
+ int data_len = 1;
+ int param_len = 6;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ pstring param;
+ unsigned char data;
+ char *rparam=NULL, *rdata=NULL;
+
+ memset(param, 0, param_len);
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
+
+ data = flag ? 1 : 0;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ Open a file - exposing the full horror of the NT API :-).
+ Used in smbtorture.
+****************************************************************************/
+
+int cli_nt_create_full(struct cli_state *cli, const char *fname, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions)
+{
+ char *p;
+ int len;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,24,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBntcreateX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ if (cli->use_oplocks)
+ SIVAL(cli->outbuf,smb_ntcreate_Flags, REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
+ else
+ SIVAL(cli->outbuf,smb_ntcreate_Flags, 0);
+ SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
+ SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, FileAttributes);
+ SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, ShareAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions);
+ SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
+
+ p = smb_buf(cli->outbuf);
+ /* this alignment and termination is critical for netapp filers. Don't change */
+ p += clistr_align_out(cli, p, 0);
+ len = clistr_push(cli, p, fname, -1, 0);
+ p += len;
+ SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
+ /* sigh. this copes with broken netapp filer behaviour */
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2 + 1);
+}
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
+{
+ return cli_nt_create_full(cli, fname, DesiredAccess, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_EXISTS_OPEN, 0x0);
+}
+
+/****************************************************************************
+ Open a file
+ WARNING: if you open with O_WRONLY then getattrE won't work!
+****************************************************************************/
+
+int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+{
+ char *p;
+ unsigned openfn=0;
+ unsigned accessmode=0;
+
+ if (flags & O_CREAT)
+ openfn |= (1<<4);
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= (1<<14);
+ }
+#endif /* O_SYNC */
+
+ if (share_mode == DENY_FCB) {
+ accessmode = 0xFF;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,15,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBopenX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ SSVAL(cli->outbuf,smb_vwv3,accessmode);
+ SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
+ SSVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv8,openfn);
+
+ if (cli->use_oplocks) {
+ /* if using oplocks then ask for a batch oplock via
+ core and extended methods */
+ CVAL(cli->outbuf,smb_flg) |=
+ FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
+ SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
+ }
+
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2);
+}
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,3,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBclose;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ return !cli_is_error(cli);
+}
+
+/****************************************************************************
+ Lock a file.
+****************************************************************************/
+
+BOOL cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = (lock_type == READ_LOCK? 1 : 0);
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ p += 10;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file.
+****************************************************************************/
+
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = 0;
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+ p += 10;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Lock a file with 64 bit offsets.
+****************************************************************************/
+
+BOOL cli_lock64(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+ int ltype;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_lock(cli, fnum, offset, len, timeout, lock_type);
+ }
+
+ ltype = (lock_type == READ_LOCK? 1 : 0);
+ ltype |= LOCKING_ANDX_LARGE_FILES;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = ltype;
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file with 64 bit offsets.
+****************************************************************************/
+
+BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+{
+ char *p;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = LOCKING_ANDX_LARGE_FILES;
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetattrE call.
+****************************************************************************/
+
+BOOL cli_getattrE(struct cli_state *cli, int fd,
+ uint16 *attr, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBgetattrE;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fd);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv6);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv10);
+ }
+
+ if (c_time) {
+ *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
+ }
+
+ if (a_time) {
+ *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
+ }
+
+ if (m_time) {
+ *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetatr call
+****************************************************************************/
+
+BOOL cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, size_t *size, time_t *t)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBgetatr;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv3);
+ }
+
+ if (t) {
+ *t = make_unix_date3(cli->inbuf+smb_vwv1);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv0);
+ }
+
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBsetatr call.
+****************************************************************************/
+
+BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBsetatr;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, attr);
+ put_dos_date3(cli->outbuf,smb_vwv1, t);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+ *p++ = 4;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Check for existance of a dir.
+****************************************************************************/
+
+BOOL cli_chkpath(struct cli_state *cli, const char *path)
+{
+ pstring path2;
+ char *p;
+
+ safe_strcpy(path2,path,sizeof(pstring));
+ trim_string(path2,NULL,"\\");
+ if (!*path2) *path2 = '\\';
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBchkpth);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path2, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Query disk space.
+****************************************************************************/
+
+BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBdskattr;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
+ *total = SVAL(cli->inbuf,smb_vwv0);
+ *avail = SVAL(cli->inbuf,smb_vwv3);
+
+ return True;
+}
+
+/****************************************************************************
+ Create and open a temporary file.
+****************************************************************************/
+
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
+{
+ int len;
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,3,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBctemp;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ /* despite the spec, the result has a -1, followed by
+ length, followed by name */
+ p = smb_buf(cli->inbuf);
+ p += 4;
+ len = smb_buflen(cli->inbuf) - 4;
+ if (len <= 0) return -1;
+
+ if (tmp_path) {
+ pstring path2;
+ clistr_pull(cli, path2, p,
+ sizeof(path2), len, STR_ASCII);
+ *tmp_path = strdup(path2);
+ }
+
+ return SVAL(cli->inbuf,smb_vwv0);
+}
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
new file mode 100644
index 00000000000..cc77c08d26a
--- /dev/null
+++ b/source/libsmb/clikrb5.c
@@ -0,0 +1,146 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ simple kerberos5 routines for active directory
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+/*
+ we can't use krb5_mk_req because w2k wants the service to be in a particular format
+*/
+static krb5_error_code krb5_mk_req2(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
+{
+ krb5_error_code retval;
+ krb5_principal server;
+ krb5_creds * credsp;
+ krb5_creds creds;
+ krb5_data in_data;
+
+ retval = krb5_parse_name(context, principal, &server);
+ if (retval) {
+ DEBUG(1,("Failed to parse principal %s\n", principal));
+ return retval;
+ }
+
+ /* obtain ticket & session key */
+ memset((char *)&creds, 0, sizeof(creds));
+ if ((retval = krb5_copy_principal(context, server, &creds.server))) {
+ DEBUG(1,("krb5_copy_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_princ;
+ }
+
+ if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
+ DEBUG(1,("krb5_cc_get_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ if ((retval = krb5_get_credentials(context, 0,
+ ccache, &creds, &credsp))) {
+ DEBUG(1,("krb5_get_credentials failed for %s (%s)\n",
+ principal, error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ in_data.length = 0;
+ retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
+ &in_data, credsp, outbuf);
+ if (retval) {
+ DEBUG(1,("krb5_mk_req_extended failed (%s)\n",
+ error_message(retval)));
+ }
+
+ krb5_free_creds(context, credsp);
+
+cleanup_creds:
+ krb5_free_cred_contents(context, &creds);
+
+cleanup_princ:
+ krb5_free_principal(context, server);
+
+ return retval;
+}
+
+/*
+ get a kerberos5 ticket for the given service
+*/
+DATA_BLOB krb5_get_ticket(char *principal)
+{
+ krb5_error_code retval;
+ krb5_data packet;
+ krb5_ccache ccdef;
+ krb5_context context;
+ krb5_auth_context auth_context = NULL;
+ DATA_BLOB ret;
+ krb5_enctype enc_types[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
+
+ retval = krb5_init_context(&context);
+ if (retval) {
+ DEBUG(1,("krb5_init_context failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_cc_default(context, &ccdef))) {
+ DEBUG(1,("krb5_cc_default failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
+ DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_mk_req2(context,
+ &auth_context,
+ 0,
+ principal,
+ ccdef, &packet))) {
+ goto failed;
+ }
+
+ ret = data_blob(packet.data, packet.length);
+/* Hmm, heimdal dooesn't have this - what's the correct call? */
+/* krb5_free_data_contents(context, &packet); */
+ krb5_free_context(context);
+ return ret;
+
+failed:
+ krb5_free_context(context);
+ return data_blob(NULL, 0);
+}
+
+
+#else /* HAVE_KRB5 */
+ /* this saves a few linking headaches */
+ DATA_BLOB krb5_get_ticket(char *principal)
+ {
+ DEBUG(0,("NO KERBEROS SUPPORT\n"));
+ return data_blob(NULL, 0);
+ }
+#endif
diff --git a/source/libsmb/clilist.c b/source/libsmb/clilist.c
new file mode 100644
index 00000000000..a9212c9dba1
--- /dev/null
+++ b/source/libsmb/clilist.c
@@ -0,0 +1,465 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client directory list routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+interpret a long filename structure - this is mostly guesses at the moment
+The length of the structure is returned
+The structure of a long filename depends on the info level. 260 is used
+by NT and 2 is used by OS/2
+****************************************************************************/
+static int interpret_long_filename(struct cli_state *cli,
+ int level,char *p,file_info *finfo)
+{
+ extern file_info def_finfo;
+ file_info finfo2;
+ int len;
+ char *base = p;
+
+ if (!finfo) finfo = &finfo2;
+
+ memcpy(finfo,&def_finfo,sizeof(*finfo));
+
+ switch (level)
+ {
+ case 1: /* OS/2 understands this */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 26);
+ p += 27;
+ p += clistr_align_in(cli, p, 0);
+ p += clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ len,
+ STR_TERMINATE);
+ return PTR_DIFF(p, base);
+
+ case 2: /* this is what OS/2 uses mostly */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 30);
+ p += 31;
+ /* check for unisys! */
+ p += clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ len,
+ STR_NOALIGN);
+ return PTR_DIFF(p, base) + 1;
+
+ case 260: /* NT uses this, but also accepts 2 */
+ {
+ int namelen, slen;
+ p += 4; /* next entry offset */
+ p += 4; /* fileindex */
+
+ /* these dates appear to arrive in a
+ weird way. It seems to be localtime
+ plus the serverzone given in the
+ initial connect. This is GMT when
+ DST is not in effect and one hour
+ from GMT otherwise. Can this really
+ be right??
+
+ I suppose this could be called
+ kludge-GMT. Is is the GMT you get
+ by using the current DST setting on
+ a different localtime. It will be
+ cheap to calculate, I suppose, as
+ no DST tables will be needed */
+
+ finfo->ctime = interpret_long_date(p); p += 8;
+ finfo->atime = interpret_long_date(p); p += 8;
+ finfo->mtime = interpret_long_date(p); p += 8; p += 8;
+ finfo->size = IVAL(p,0); p += 8;
+ p += 8; /* alloc size */
+ finfo->mode = CVAL(p,0); p += 4;
+ namelen = IVAL(p,0); p += 4;
+ p += 4; /* EA size */
+ slen = SVAL(p, 0);
+ p += 2;
+ {
+ /* stupid NT bugs. grr */
+ int flags = 0;
+ if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
+ clistr_pull(cli, finfo->short_name, p,
+ sizeof(finfo->short_name),
+ slen, flags);
+ }
+ p += 24; /* short name? */
+ clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ namelen, 0);
+ return SVAL(base, 0);
+ }
+ }
+
+ DEBUG(1,("Unknown long filename format %d\n",level));
+ return(SVAL(p,0));
+}
+
+
+/****************************************************************************
+ do a directory listing, calling fn on each file found
+ ****************************************************************************/
+int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ int max_matches = 512;
+ int info_level;
+ char *p, *p2;
+ pstring mask;
+ file_info finfo;
+ int i;
+ char *tdl, *dirlist = NULL;
+ int dirlist_len = 0;
+ int total_received = -1;
+ BOOL First = True;
+ int ff_searchcount=0;
+ int ff_eos=0;
+ int ff_lastname=0;
+ int ff_dir_handle=0;
+ int loop_count = 0;
+ char *rparam=NULL, *rdata=NULL;
+ int param_len, data_len;
+ uint16 setup;
+ pstring param;
+
+ /* NT uses 260, OS/2 uses 2. Both accept 1. */
+ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
+
+ pstrcpy(mask,Mask);
+
+ while (ff_eos == 0) {
+ loop_count++;
+ if (loop_count > 200) {
+ DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+ break;
+ }
+
+ if (First) {
+ setup = TRANSACT2_FINDFIRST;
+ SSVAL(param,0,attribute); /* attribute */
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,4+2); /* resume required + close on end */
+ SSVAL(param,6,info_level);
+ SIVAL(param,8,0);
+ p = param+12;
+ p += clistr_push(cli, param+12, mask, -1,
+ STR_TERMINATE);
+ } else {
+ setup = TRANSACT2_FINDNEXT;
+ SSVAL(param,0,ff_dir_handle);
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,info_level);
+ SIVAL(param,6,0); /* ff_resume_key */
+ SSVAL(param,10,8+4+2); /* continue + resume required + close on end */
+ p = param+12;
+ p += clistr_push(cli, param+12, mask, -1,
+ STR_TERMINATE);
+ }
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, 0,
+ cli->max_xmit /* data, length, max */
+ )) {
+ break;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len) &&
+ cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ continue;
+ }
+
+ if (cli_is_error(cli) || !rdata || !rparam)
+ break;
+
+ if (total_received == -1) total_received = 0;
+
+ /* parse out some important return info */
+ p = rparam;
+ if (First) {
+ ff_dir_handle = SVAL(p,0);
+ ff_searchcount = SVAL(p,2);
+ ff_eos = SVAL(p,4);
+ ff_lastname = SVAL(p,8);
+ } else {
+ ff_searchcount = SVAL(p,0);
+ ff_eos = SVAL(p,2);
+ ff_lastname = SVAL(p,6);
+ }
+
+ if (ff_searchcount == 0)
+ break;
+
+ /* point to the data bytes */
+ p = rdata;
+
+ /* we might need the lastname for continuations */
+ if (ff_lastname > 0) {
+ switch(info_level)
+ {
+ case 260:
+ clistr_pull(cli, mask, p+ff_lastname,
+ sizeof(mask),
+ data_len-ff_lastname,
+ STR_TERMINATE);
+ break;
+ case 1:
+ clistr_pull(cli, mask, p+ff_lastname+1,
+ sizeof(mask),
+ -1,
+ STR_TERMINATE);
+ break;
+ }
+ } else {
+ pstrcpy(mask,"");
+ }
+
+ /* and add them to the dirlist pool */
+ tdl = Realloc(dirlist,dirlist_len + data_len);
+
+ if (!tdl) {
+ DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
+ break;
+ }
+ else dirlist = tdl;
+
+ /* put in a length for the last entry, to ensure we can chain entries
+ into the next packet */
+ for (p2=p,i=0;i<(ff_searchcount-1);i++)
+ p2 += interpret_long_filename(cli,info_level,p2,NULL);
+ SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
+
+ /* grab the data for later use */
+ memcpy(dirlist+dirlist_len,p,data_len);
+ dirlist_len += data_len;
+
+ total_received += ff_searchcount;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ DEBUG(3,("received %d entries (eos=%d)\n",
+ ff_searchcount,ff_eos));
+
+ if (ff_searchcount > 0) loop_count = 0;
+
+ First = False;
+ }
+
+ for (p=dirlist,i=0;i<total_received;i++) {
+ p += interpret_long_filename(cli,info_level,p,&finfo);
+ fn(&finfo, Mask, state);
+ }
+
+ /* free up the dirlist buffer */
+ SAFE_FREE(dirlist);
+ return(total_received);
+}
+
+
+
+/****************************************************************************
+interpret a short filename structure
+The length of the structure is returned
+****************************************************************************/
+static int interpret_short_filename(struct cli_state *cli, char *p,file_info *finfo)
+{
+ extern file_info def_finfo;
+
+ *finfo = def_finfo;
+
+ finfo->mode = CVAL(p,21);
+
+ /* this date is converted to GMT by make_unix_date */
+ finfo->ctime = make_unix_date(p+22);
+ finfo->mtime = finfo->atime = finfo->ctime;
+ finfo->size = IVAL(p,26);
+ clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII);
+ if (strcmp(finfo->name, "..") && strcmp(finfo->name, "."))
+ fstrcpy(finfo->short_name,finfo->name);
+
+ return(DIR_STRUCT_SIZE);
+}
+
+
+/****************************************************************************
+ do a directory listing, calling fn on each file found
+ this uses the old SMBsearch interface. It is needed for testing Samba,
+ but should otherwise not be used
+ ****************************************************************************/
+int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ char *p;
+ int received = 0;
+ BOOL first = True;
+ char status[21];
+ int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
+ int num_received = 0;
+ int i;
+ char *tdl, *dirlist = NULL;
+ pstring mask;
+
+ ZERO_ARRAY(status);
+
+ pstrcpy(mask,Mask);
+
+ while (1) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,2,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBsearch;
+
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,num_asked);
+ SSVAL(cli->outbuf,smb_vwv1,attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+
+ p += clistr_push(cli, p, first?mask:"", -1, STR_TERMINATE);
+ *p++ = 5;
+ if (first) {
+ SSVAL(p,0,0);
+ p += 2;
+ } else {
+ SSVAL(p,0,21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+ }
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) break;
+
+ received = SVAL(cli->inbuf,smb_vwv0);
+ if (received <= 0) break;
+
+ first = False;
+
+ tdl = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
+
+ if (!tdl) {
+ DEBUG(0,("cli_list_old: failed to expand dirlist"));
+ SAFE_FREE(dirlist);
+ return 0;
+ }
+ else dirlist = tdl;
+
+ p = smb_buf(cli->inbuf) + 3;
+
+ memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
+ p,received*DIR_STRUCT_SIZE);
+
+ memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
+
+ num_received += received;
+
+ if (cli_is_error(cli)) break;
+ }
+
+ if (!first) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,2,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBfclose;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf, smb_vwv0, 0); /* find count? */
+ SSVAL(cli->outbuf, smb_vwv1, attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ fstrcpy(p, "");
+ p += strlen(p) + 1;
+ *p++ = 5;
+ SSVAL(p, 0, 21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ DEBUG(0,("Error closing search: %s\n",cli_errstr(cli)));
+ }
+ }
+
+ for (p=dirlist,i=0;i<num_received;i++) {
+ file_info finfo;
+ p += interpret_short_filename(cli, p,&finfo);
+ fn(&finfo, Mask, state);
+ }
+
+ SAFE_FREE(dirlist);
+ return(num_received);
+}
+
+
+/****************************************************************************
+ do a directory listing, calling fn on each file found
+ this auto-switches between old and new style
+ ****************************************************************************/
+int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ if (cli->protocol <= PROTOCOL_LANMAN1) {
+ return cli_list_old(cli, Mask, attribute, fn, state);
+ }
+ return cli_list_new(cli, Mask, attribute, fn, state);
+}
diff --git a/source/libsmb/climessage.c b/source/libsmb/climessage.c
new file mode 100644
index 00000000000..d32c5de0420
--- /dev/null
+++ b/source/libsmb/climessage.c
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client message handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+start a message sequence
+****************************************************************************/
+BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
+ int *grp)
+{
+ char *p;
+
+ /* send a SMBsendstrt command */
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsendstrt;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, username, -1, STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, host, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ *grp = SVAL(cli->inbuf,smb_vwv0);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a message
+****************************************************************************/
+BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,1,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsendtxt;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+ SSVAL(p,0,len); p += 2;
+ memcpy(p,msg,len);
+ p += len;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+end a message
+****************************************************************************/
+BOOL cli_message_end(struct cli_state *cli, int grp)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,1,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsendend;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
diff --git a/source/libsmb/clioplock.c b/source/libsmb/clioplock.c
new file mode 100644
index 00000000000..b38933181eb
--- /dev/null
+++ b/source/libsmb/clioplock.c
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ SMB client oplock functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/****************************************************************************
+send an ack for an oplock break request
+****************************************************************************/
+BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level)
+{
+ char *oldbuf = cli->outbuf;
+ pstring buf;
+ BOOL ret;
+
+ cli->outbuf = buf;
+
+ memset(buf,'\0',smb_size);
+ set_message(buf,8,0,True);
+
+ CVAL(buf,smb_com) = SMBlockingX;
+ SSVAL(buf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+ SSVAL(buf,smb_vwv0,0xFF);
+ SSVAL(buf,smb_vwv1,0);
+ SSVAL(buf,smb_vwv2,fnum);
+ if (level == 1)
+ SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
+ else
+ SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */
+ SIVAL(buf,smb_vwv4,0); /* timoeut */
+ SSVAL(buf,smb_vwv6,0); /* unlockcount */
+ SSVAL(buf,smb_vwv7,0); /* lockcount */
+
+ ret = cli_send_smb(cli);
+
+ cli->outbuf = oldbuf;
+
+ return ret;
+}
+
+
+/****************************************************************************
+set the oplock handler for a connection
+****************************************************************************/
+void cli_oplock_handler(struct cli_state *cli,
+ BOOL (*handler)(struct cli_state *, int, unsigned char))
+{
+ cli->oplock_handler = handler;
+}
diff --git a/source/libsmb/cliprint.c b/source/libsmb/cliprint.c
new file mode 100644
index 00000000000..57e2c049d8f
--- /dev/null
+++ b/source/libsmb/cliprint.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client print routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*****************************************************************************
+ Convert a character pointer in a cli_call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns
+ invalid data.
+*****************************************************************************/
+static char *fix_char_ptr(unsigned int datap, unsigned int converter,
+ char *rdata, int rdrcnt)
+{
+ if (datap == 0) { /* turn NULL pointers into zero length strings */
+ return "";
+ } else {
+ unsigned int offset = datap - converter;
+
+ if (offset >= rdrcnt) {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
+ datap, converter, rdrcnt));
+ return "<ERROR>";
+ } else {
+ return &rdata[offset];
+ }
+ }
+}
+
+
+/****************************************************************************
+call fn() on each entry in a print queue
+****************************************************************************/
+int cli_print_queue(struct cli_state *cli,
+ void (*fn)(struct print_job_info *))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+ int i = -1;
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
+ p += 2;
+ pstrcpy(p,"zWrLeh"); /* parameter description? */
+ p = skip_string(p,1);
+ pstrcpy(p,"WWzWWDDzz"); /* returned data format */
+ p = skip_string(p,1);
+ pstrcpy(p,cli->share); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ pstrcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ if (result_code == 0) {
+ struct print_job_info job;
+
+ p = rdata;
+
+ for (i = 0; i < SVAL(rparam,4); ++i) {
+ job.id = SVAL(p,0);
+ job.priority = SVAL(p,2);
+ fstrcpy(job.user,
+ fix_char_ptr(SVAL(p,4), converter,
+ rdata, rdrcnt));
+ job.t = make_unix_date3(p + 12);
+ job.size = IVAL(p,16);
+ fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
+ converter,
+ rdata, rdrcnt));
+ fn(&job);
+ p += 28;
+ }
+ }
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return i;
+}
+
+/****************************************************************************
+ cancel a print job
+ ****************************************************************************/
+int cli_printjob_del(struct cli_state *cli, int job)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, ret = -1;
+ pstring param;
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,81); /* DosPrintJobDel() */
+ p += 2;
+ pstrcpy(p,"W");
+ p = skip_string(p,1);
+ pstrcpy(p,"");
+ p = skip_string(p,1);
+ SSVAL(p,0,job);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ ret = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+
diff --git a/source/libsmb/clirap.c b/source/libsmb/clirap.c
new file mode 100644
index 00000000000..4484b613810
--- /dev/null
+++ b/source/libsmb/clirap.c
@@ -0,0 +1,694 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client RAP calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
+****************************************************************************/
+BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name,
+ uint16 *setup, uint32 setup_count, uint32 max_setup_count,
+ char *params, uint32 param_count, uint32 max_param_count,
+ char *data, uint32 data_count, uint32 max_data_count,
+ char **rparam, uint32 *rparam_count,
+ char **rdata, uint32 *rdata_count)
+{
+ cli_send_trans(cli, SMBtrans,
+ pipe_name,
+ 0,0, /* fid, flags */
+ setup, setup_count, max_setup_count,
+ params, param_count, max_param_count,
+ data, data_count, max_data_count);
+
+ return (cli_receive_trans(cli, SMBtrans,
+ rparam, (int *)rparam_count,
+ rdata, (int *)rdata_count));
+}
+
+/****************************************************************************
+call a remote api
+****************************************************************************/
+BOOL cli_api(struct cli_state *cli,
+ char *param, int prcnt, int mprcnt,
+ char *data, int drcnt, int mdrcnt,
+ char **rparam, int *rprcnt,
+ char **rdata, int *rdrcnt)
+{
+ cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* Name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* Setup, length, max */
+ param, prcnt, mprcnt, /* Params, length, max */
+ data, drcnt, mdrcnt /* Data, length, max */
+ );
+
+ return (cli_receive_trans(cli,SMBtrans,
+ rparam, rprcnt,
+ rdata, rdrcnt));
+}
+
+
+/****************************************************************************
+perform a NetWkstaUserLogon
+****************************************************************************/
+BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring param;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogon */
+ p = param;
+ SSVAL(p,0,132); /* api number */
+ p += 2;
+ pstrcpy(p,"OOWb54WrLh");
+ p = skip_string(p,1);
+ pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
+ p = skip_string(p,1);
+ SSVAL(p,0,1);
+ p += 2;
+ pstrcpy(p,user);
+ strupper(p);
+ p += 21;
+ p++;
+ p += 15;
+ p++;
+ pstrcpy(p, workstation);
+ strupper(p);
+ p += 16;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = rparam? SVAL(rparam,0) : -1;
+ p = rdata;
+
+ if (cli->rap_error == 0) {
+ DEBUG(4,("NetWkstaUserLogon success\n"));
+ cli->privileges = SVAL(p, 24);
+ fstrcpy(cli->eff_name,p+2);
+ } else {
+ DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+/****************************************************************************
+call a NetShareEnum - try and browse available connections on a host
+****************************************************************************/
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring param;
+ int count = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = param;
+ SSVAL(p,0,0); /* api number */
+ p += 2;
+ pstrcpy(p,"WrLeh");
+ p = skip_string(p,1);
+ pstrcpy(p,"B13BWz");
+ p = skip_string(p,1);
+ SSVAL(p,0,1);
+ /*
+ * Win2k needs a *smaller* buffer than 0xFFFF here -
+ * it returns "out of server memory" with 0xFFFF !!! JRA.
+ */
+ SSVAL(p,2,0xFFE0);
+ p += 4;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata) {
+ int converter=SVAL(rparam,2);
+ int i;
+
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i=0;i<count;i++,p+=20) {
+ char *sname = p;
+ int type = SVAL(p,14);
+ int comment_offset = IVAL(p,16) & 0xFFFF;
+ char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
+ pstring s1, s2;
+
+ pull_ascii_pstring(s1, sname);
+ pull_ascii_pstring(s2, cmnt);
+
+ fn(s1, type, s2, state);
+ }
+ } else {
+ DEBUG(4,("NetShareEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetShareEnum failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+
+/****************************************************************************
+call a NetServerEnum for the specified workgroup and servertype mask. This
+function then calls the specified callback function for each name returned.
+
+The callback function takes 4 arguments: the machine name, the server type,
+the comment and a state pointer.
+****************************************************************************/
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ pstring param;
+ int uLevel = 1;
+ int count = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = param;
+ SSVAL(p,0,0x68); /* api number */
+ p += 2;
+ pstrcpy(p,"WrLehDz");
+ p = skip_string(p,1);
+
+ pstrcpy(p,"B16BBDz");
+
+ p = skip_string(p,1);
+ SSVAL(p,0,uLevel);
+ SSVAL(p,2,CLI_BUFFER_SIZE);
+ p += 4;
+ SIVAL(p,0,stype);
+ p += 4;
+
+ p += push_pstring(p, workgroup);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ int res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata) {
+ int i;
+ int converter=SVAL(rparam,2);
+
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i = 0;i < count;i++, p += 26) {
+ char *sname = p;
+ int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
+ char *cmnt = comment_offset?(rdata+comment_offset):"";
+ pstring s1, s2;
+
+ if (comment_offset < 0 || comment_offset > rdrcnt) continue;
+
+ stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ pull_ascii_pstring(s1, sname);
+ pull_ascii_pstring(s2, cmnt);
+ fn(s1, stype, s2, state);
+ }
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(count > 0);
+}
+
+
+
+/****************************************************************************
+Send a SamOEMChangePassword command
+****************************************************************************/
+BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+ const char *old_password)
+{
+ char param[16+sizeof(fstring)];
+ char data[532];
+ char *p = param;
+ fstring upper_case_old_pw;
+ fstring upper_case_new_pw;
+ unsigned char old_pw_hash[16];
+ unsigned char new_pw_hash[16];
+ int data_len;
+ int param_len = 0;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ pstring dos_new_password;
+
+ if (strlen(user) >= sizeof(fstring)-1) {
+ DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
+ return False;
+ }
+
+ SSVAL(p,0,214); /* SamOEMChangePassword command. */
+ p += 2;
+ pstrcpy(p, "zsT");
+ p = skip_string(p,1);
+ pstrcpy(p, "B516B16");
+ p = skip_string(p,1);
+ pstrcpy(p,user);
+ p = skip_string(p,1);
+ SSVAL(p,0,532);
+ p += 2;
+
+ param_len = PTR_DIFF(p,param);
+
+ /*
+ * Get the Lanman hash of the old password, we
+ * use this as the key to make_oem_passwd_hash().
+ */
+ memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
+ clistr_push(cli, upper_case_old_pw, old_password, -1,STR_TERMINATE|STR_UPPER|STR_ASCII);
+ E_P16((uchar *)upper_case_old_pw, old_pw_hash);
+
+ clistr_push(cli, dos_new_password, new_password, -1, STR_TERMINATE|STR_ASCII);
+
+ if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
+ return False;
+
+ /*
+ * Now place the old password hash in the data.
+ */
+ memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
+ clistr_push(cli, upper_case_new_pw, new_password, -1, STR_TERMINATE|STR_UPPER|STR_ASCII);
+
+ E_P16((uchar *)upper_case_new_pw, new_pw_hash);
+
+ E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
+
+ data_len = 532;
+
+ if (cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* setup, length, max */
+ param,param_len,2, /* param, length, max */
+ data,data_len,0 /* data, length, max */
+ ) == False) {
+ DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
+ user ));
+ return False;
+ }
+
+ if (cli_receive_trans(cli,SMBtrans,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ if (rparam)
+ cli->rap_error = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return (cli->rap_error == 0);
+}
+
+
+/****************************************************************************
+send a qpathinfo call
+****************************************************************************/
+BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ size_t *size, uint16 *mode)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ BOOL ret;
+ time_t (*date_fn)(void *);
+ char *p;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_INFO_STANDARD);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len));
+ if (!ret && cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ if (!ret || !rdata || data_len < 22) {
+ return False;
+ }
+
+ if (cli->win95) {
+ date_fn = make_unix_date;
+ } else {
+ date_fn = make_unix_date2;
+ }
+
+ if (c_time) {
+ *c_time = date_fn(rdata+0);
+ }
+ if (a_time) {
+ *a_time = date_fn(rdata+4);
+ }
+ if (m_time) {
+ *m_time = date_fn(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+ if (mode) {
+ *mode = SVAL(rdata,l1_attrFile);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
+****************************************************************************/
+BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, size_t *size, uint16 *mode,
+ SMB_INO_T *ino)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+ }
+ if (a_time) {
+ *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+ }
+ if (m_time) {
+ *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+ }
+ if (w_time) {
+ *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL(rdata, 48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, SMB_INO_T *ino)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95) return False;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 68) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+ }
+ if (a_time) {
+ *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+ }
+ if (m_time) {
+ *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+ }
+ if (w_time) {
+ *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL(rdata, 48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char *outdata)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95) return False;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ memcpy(outdata, rdata, data_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+
+
+/****************************************************************************
+send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
+****************************************************************************/
+NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ char *p;
+ BOOL ret;
+ int len;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len));
+ if (!ret && cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ if (!ret || !rdata || data_len < 4) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ len = IVAL(rdata, 0);
+
+ if (len > data_len - 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, 0);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return NT_STATUS_OK;
+}
diff --git a/source/libsmb/clirap2.c b/source/libsmb/clirap2.c
new file mode 100644
index 00000000000..2fde0c70e50
--- /dev/null
+++ b/source/libsmb/clirap2.c
@@ -0,0 +1,1962 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ More client RAP (SMB Remote Procedure Calls) functions
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*****************************************************/
+/* */
+/* Additional RAP functionality */
+/* */
+/* RAP is the original SMB RPC, documented */
+/* by Microsoft and X/Open in the 1990s and */
+/* supported by most SMB/CIFS servers although */
+/* it is unlikely that any one implementation */
+/* supports all RAP command codes since some */
+/* are quite obsolete and a few are specific */
+/* to a particular network operating system */
+/* */
+/* Although it has largely been replaced */
+/* for complex remote admistration and management */
+/* (of servers) by the relatively newer */
+/* DCE/RPC based remote API (which better handles */
+/* large >64K data structures), there are many */
+/* important administrative and resource location */
+/* tasks and user tasks (e.g. password change) */
+/* that are performed via RAP. */
+/* */
+/* Although a few of the RAP calls are implemented */
+/* in the Samba client library already (clirap.c) */
+/* the new ones are in clirap2.c for easy patching */
+/* and integration and a corresponding header */
+/* file, rap.h, has been created. */
+/* */
+/* This is based on data from the CIFS spec */
+/* and the LAN Server and LAN Manager */
+/* Programming Reference books and published */
+/* RAP document and CIFS forum postings and */
+/* lots of trial and error */
+/* */
+/* Function names changed from API_ (as they are */
+/* in the CIFS specification) to RAP_ in order */
+/* to avoid confusion with other API calls */
+/* sent via DCE RPC */
+/* */
+/*****************************************************/
+
+/*****************************************************/
+/* */
+/* cifsrap.c already includes support for: */
+/* */
+/* WshareEnum ( API number 0, level 1) */
+/* NetServerEnum2 (API num 104, level 1) */
+/* WWkstaUserLogon (132) */
+/* SamOEMchgPasswordUser2_P (214) */
+/* */
+/* cifsprint.c already includes support for: */
+/* */
+/* WPrintJobEnum (API num 76, level 2) */
+/* WPrintJobDel (API num 81) */
+/* */
+/*****************************************************/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#define WORDSIZE 2
+#define DWORDSIZE 4
+
+#define PUTBYTE(p,b) do {SCVAL(p,0,b); p++;} while(0)
+#define GETBYTE(p,b) do {b = CVAL(p,0); p++;} while(0)
+#define PUTWORD(p,w) do {SSVAL(p,0,w); p += WORDSIZE;} while(0)
+#define GETWORD(p,w) do {w = SVAL(p,0); p += WORDSIZE;} while(0)
+#define PUTDWORD(p,d) do {SIVAL(p,0,d); p += DWORDSIZE;} while(0)
+#define GETDWORD(p,d) do {d = IVAL(p,0); p += DWORDSIZE;} while(0)
+#define GETRES(p) p ? SVAL(p,0) : -1
+/* put string s at p with max len n and increment p past string */
+#define PUTSTRING(p,s,n) do {\
+ push_ascii(p,s?s:"",n?n:256,STR_TERMINATE);\
+ p = skip_string(p,1);\
+ } while(0)
+/* put string s and p, using fixed len l, and increment p by l */
+#define PUTSTRINGF(p,s,l) do {\
+ push_ascii(p,s?s:"",l,STR_TERMINATE);\
+ p += l;\
+ } while (0)
+/* put string pointer at p, supplying offset o from rdata r, store */
+/* dword offset at p, increment p by 4 and o by length of s. This */
+/* means on the first call, you must calc the offset yourself! */
+#define PUTSTRINGP(p,s,r,o) do {\
+ if (s) {\
+ push_ascii(r+o,s,strlen(s)+1,STR_TERMINATE);\
+ PUTDWORD(p,o);\
+ o += strlen(s) + 1;\
+ } else PUTDWORD(p,0);\
+ }while(0);
+/* get asciiz string s from p, increment p past string */
+#define GETSTRING(p,s) do {\
+ pull_ascii_pstring(s,p);\
+ p = skip_string(p,1);\
+ } while(0)
+/* get fixed length l string s from p, increment p by l */
+#define GETSTRINGF(p,s,l) do {\
+ pull_ascii_pstring(s,p);\
+ p += l;\
+ } while(0)
+/* get string s from offset (obtained at p) from rdata r - converter c */
+#define GETSTRINGP(p,s,r,c) do {\
+ uint32 off;\
+ GETDWORD(p,off);\
+ off &= 0x0000FFFF; /* mask the obsolete segment number from the offset */ \
+ pull_ascii_pstring(s, off?(r+off-c):"");\
+ } while(0)
+
+static char *make_header(char *param, uint16 apinum, char *reqfmt, char *datafmt)
+{
+ PUTWORD(param,apinum);
+ if (reqfmt)
+ PUTSTRING(param,reqfmt,0);
+ else
+ *param++ = (char) 0;
+
+ if (datafmt)
+ PUTSTRING(param,datafmt,0);
+ else
+ *param++ = (char) 0;
+
+ return param;
+}
+
+
+/****************************************************************************
+ call a NetGroupDelete - delete user group from remote server
+****************************************************************************/
+int cli_NetGroupDelete(struct cli_state *cli, const char *group_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api GroupDel */
+ p = make_header(param, RAP_WGroupDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, group_name, RAP_GROUPNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2220) {
+ DEBUG (1, ("Group does not exist\n"));
+ }
+ else {
+ DEBUG(4,("NetGroupDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetGroupAdd - add user group to remote server
+****************************************************************************/
+int cli_NetGroupAdd(struct cli_state *cli, RAP_GROUP_INFO_1 * grinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAdd_REQ) /* req string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+
+ char data[1024];
+
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset = RAP_GROUPNAME_LEN + 1 + DWORDSIZE;
+
+ /* now send a SMBtrans command with api WGroupAdd */
+
+ p = make_header(param, RAP_WGroupAdd,
+ RAP_NetGroupAdd_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, grinfo->group_name, RAP_GROUPNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGP(p, grinfo->comment, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2223) {
+ DEBUG (1, ("Group already exists\n"));
+ }
+ else {
+ DEBUG(4,("NetGroupAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetGroupEnum - try and list user groups on a different host
+****************************************************************************/
+int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupEnum_REQ) /* parm string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WGroupEnum,
+ RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */ /* add level 0 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if(cli->rap_error == 234)
+ DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
+ else if (cli->rap_error != 0) {
+ DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring comment;
+ char groupname[RAP_GROUPNAME_LEN];
+
+ GETSTRINGF(p, groupname, RAP_GROUPNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGP(p, comment, rdata, converter);
+
+ fn(groupname, comment, cli);
+ }
+ } else {
+ DEBUG(4,("NetGroupEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetGroupEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDelUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to del */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupDelUser, RAP_NetGroupDelUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ case 2237:
+ DEBUG(1, ("User is not in group\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupDelUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAddUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to add */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupAddUser, RAP_NetGroupAddUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupAddUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAddUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupGetUsers_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WGroupGetUsers,
+ RAP_NetGroupGetUsers_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetGroupGetUsers gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ fstring username;
+ p = rparam +WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata; i<count; i++) {
+ GETSTRINGF(p, username, RAP_USERNAME_LEN);
+ fn(username, state);
+ }
+ } else {
+ DEBUG(4,("NetGroupGetUsers res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetGroupGetUsers no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserGetGroups_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_USERNAME_LEN /* user name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WUserGetGroups,
+ RAP_NetUserGetGroups_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetUserGetGroups gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ fstring groupname;
+ p = rparam +WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata; i<count; i++) {
+ GETSTRINGF(p, groupname, RAP_USERNAME_LEN);
+ fn(groupname, state);
+ }
+ } else {
+ DEBUG(4,("NetUserGetGroups res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetUserGetGroups no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+
+/****************************************************************************
+ call a NetUserDelete - delete user from remote server
+****************************************************************************/
+int cli_NetUserDelete(struct cli_state *cli, const char * user_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_USERNAME_LEN /* user to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api UserDel */
+ p = make_header(param, RAP_WUserDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, user_name, RAP_USERNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2221) {
+ DEBUG (1, ("User does not exist\n"));
+ }
+ else {
+ DEBUG(4,("NetUserDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetUserAdd - add user to remote server
+****************************************************************************/
+int cli_NetUserAdd(struct cli_state *cli, RAP_USER_INFO_1 * userinfo )
+{
+
+
+
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserAdd2_REQ) /* req string */
+ +sizeof(RAP_USER_INFO_L1) /* data string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer length */
+ +WORDSIZE]; /* reserved */
+
+ char data[1024];
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset=RAP_USERNAME_LEN+1 /* user name + pad */
+ + RAP_UPASSWD_LEN /* password */
+ + DWORDSIZE /* password age */
+ + WORDSIZE /* privilege */
+ + DWORDSIZE /* home dir ptr */
+ + DWORDSIZE /* comment ptr */
+ + WORDSIZE /* flags */
+ + DWORDSIZE; /* login script ptr*/
+
+ /* now send a SMBtrans command with api NetUserAdd */
+ p = make_header(param, RAP_WUserAdd2,
+ RAP_NetUserAdd2_REQ, RAP_USER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+
+ PUTWORD(p, 0); /* pwencrypt */
+ if(userinfo->passwrd)
+ PUTWORD(p,MIN(strlen(userinfo->passwrd), RAP_UPASSWD_LEN));
+ else
+ PUTWORD(p, 0); /* password length */
+
+ p = data;
+ memset(data, '\0', soffset);
+
+ PUTSTRINGF(p, userinfo->user_name, RAP_USERNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGF(p, userinfo->passwrd, RAP_UPASSWD_LEN);
+ PUTDWORD(p, 0); /* pw age - n.a. on user add */
+ PUTWORD(p, userinfo->priv);
+ PUTSTRINGP(p, userinfo->home_dir, data, soffset);
+ PUTSTRINGP(p, userinfo->comment, data, soffset);
+ PUTWORD(p, userinfo->userflags);
+ PUTSTRINGP(p, userinfo->logon_script, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2224) {
+ DEBUG (1, ("User already exists\n"));
+ }
+ else {
+ DEBUG(4,("NetUserAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetUserEnum - try and list users on a different host
+****************************************************************************/
+int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserEnum_REQ) /* parm string */
+ +sizeof(RAP_USER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WUserEnum,
+ RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFF00); /* Return buffer size */
+
+/* BB Fix handling of large numbers of users to be returned */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ char username[RAP_USERNAME_LEN];
+ char userpw[RAP_UPASSWD_LEN];
+ pstring comment, homedir, logonscript;
+ int pwage, priv, flags;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ GETSTRINGF(p, username, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, userpw, RAP_UPASSWD_LEN);
+ GETDWORD(p, pwage); /* password age */
+ GETWORD(p, priv); /* 0=guest, 1=user, 2=admin */
+ GETSTRINGP(p, homedir, rdata, converter);
+ GETSTRINGP(p, comment, rdata, converter);
+ GETWORD(p, flags);
+ GETSTRINGP(p, logonscript, rdata, converter);
+
+ fn(username, comment, homedir, logonscript, cli);
+ }
+ } else {
+ DEBUG(4,("NetUserEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetUserEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetFileClose2 - close open file on another session to server
+****************************************************************************/
+int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileClose2_REQ) /* req string */
+ +1 /* no ret string */
+ +DWORDSIZE]; /* file ID */
+ int res = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
+ PUTDWORD(p, file_id);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if (res == 2314){
+ DEBUG(1, ("NetFileClose2 - attempt to close non-existant file open instance\n"));
+ } else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetFileGetInfo - get information about server file opened from other
+ workstation
+****************************************************************************/
+int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileGetInfo2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +DWORDSIZE /* file ID */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileGetInfo2,
+ RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3);
+ PUTDWORD(p, file_id);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0x1000); /* buffer size */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0x1000, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+ if (res == 0 || res == ERRmoredata) {
+ int converter,id, perms, locks;
+ pstring fpath, fuser;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+
+ p = rdata;
+ GETDWORD(p, id);
+ GETWORD(p, perms);
+ GETWORD(p, locks);
+ GETSTRINGP(p, fpath, rdata, converter);
+ GETSTRINGP(p, fuser, rdata, converter);
+
+ fn(fpath, fuser, perms, locks, id);
+ } else {
+ DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileGetInfo2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+* Call a NetFileEnum2 - list open files on an SMB server
+*
+* PURPOSE: Remotes a NetFileEnum API call to the current server or target
+* server listing the files open via the network (and their
+* corresponding open instance ids)
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* user - if present, return only files opened by this remote user
+* base_path - if present, return only files opened below this
+* base path
+* fn - display function to invoke for each entry in the result
+*
+*
+* Returns:
+* True - success
+* False - failure
+*
+****************************************************************************/
+int cli_NetFileEnum(struct cli_state *cli, char * user, char * base_path, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileEnum2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +256 /* base path (opt) */
+ +RAP_USERNAME_LEN /* user name (opt) */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* resume key ? */
+ +DWORDSIZE]; /* resume key ? */
+ int count = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileEnum2,
+ RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3);
+
+ PUTSTRING(p, base_path, 256);
+ PUTSTRING(p, user, RAP_USERNAME_LEN);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0xFF00); /* buffer size */
+ PUTDWORD(p, 0); /* zero out the resume key */
+ PUTDWORD(p, 0); /* or is this one the resume key? */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFF00, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ int converter, i;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i=0; i<count; i++) {
+ int id, perms, locks;
+ pstring fpath, fuser;
+
+ GETDWORD(p, id);
+ GETWORD(p, perms);
+ GETWORD(p, locks);
+ GETSTRINGP(p, fpath, rdata, converter);
+ GETSTRINGP(p, fuser, rdata, converter);
+
+ fn(fpath, fuser, perms, locks, id);
+ } /* BB fix ERRmoredata case to send resume request */
+ } else {
+ DEBUG(4,("NetFileEnum2 res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetFileEnum2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+/****************************************************************************
+ call a NetShareAdd - share/export directory on remote server
+****************************************************************************/
+int cli_NetShareAdd(struct cli_state *cli, RAP_SHARE_INFO_2 * sinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareAdd_REQ) /* req string */
+ +sizeof(RAP_SHARE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+ char data[1024];
+ /* offset to free format string section following fixed length data. */
+ /* will be updated by PUTSTRINGP macro and will end up with total len */
+ int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad */
+ + WORDSIZE /* share type */
+ + DWORDSIZE /* comment pointer */
+ + WORDSIZE /* permissions */
+ + WORDSIZE /* max users */
+ + WORDSIZE /* active users */
+ + DWORDSIZE /* share path */
+ + RAP_SPASSWD_LEN + 1; /* share password + pad */
+
+ memset(param,'\0',sizeof(param));
+ /* now send a SMBtrans command with api RNetShareAdd */
+ p = make_header(param, RAP_WshareAdd,
+ RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2);
+ PUTWORD(p, 2); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, sinfo->share_name, RAP_SHARENAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+
+ PUTWORD(p, sinfo->share_type);
+ PUTSTRINGP(p, sinfo->comment, data, soffset);
+ PUTWORD(p, sinfo->perms);
+ PUTWORD(p, sinfo->maximum_users);
+ PUTWORD(p, sinfo->active_users);
+ PUTSTRINGP(p, sinfo->path, data, soffset);
+ PUTSTRINGF(p, sinfo->password, RAP_SPASSWD_LEN);
+ SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetShareAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetShareAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+/****************************************************************************
+ call a NetShareDelete - unshare exported directory on remote server
+****************************************************************************/
+int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareDel_REQ) /* req string */
+ +1 /* no ret string */
+ +RAP_SHARENAME_LEN /* share to del */
+ +WORDSIZE]; /* reserved word */
+
+
+ /* now send a SMBtrans command with api RNetShareDelete */
+ p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
+ PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetShareDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetShareDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+/*************************************************************************
+*
+* Function Name: cli_get_pdc_name
+*
+* PURPOSE: Remotes a NetServerEnum API call to the current server
+* requesting the name of a server matching the server
+* type of SV_TYPE_DOMAIN_CTRL (PDC).
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing name of domain
+* pdc_name - pointer to string that will contain PDC name
+* on successful return
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+BOOL cli_get_pdc_name(struct cli_state *cli, char *workgroup, char *pdc_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ int count = -1;
+
+ *pdc_name = '\0';
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = GETRES(rparam);
+
+ /*
+ * We only really care to copy a name if the
+ * API succeeded and we got back a name.
+ */
+ if (cli->rap_error == 0) {
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count);
+ p = rdata;
+
+ if (count > 0)
+ GETSTRING(p, pdc_name);
+ }
+ else {
+ DEBUG(4,("cli_get_pdc_name: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(count > 0);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_domain
+*
+* PURPOSE: Remotes a NetWkstaGetInfo API call to the current server
+* requesting wksta_info_10 level information to determine
+* the domain the server belongs to. On success, this
+* routine sets the server_domain field in the cli_state structure
+* to the server's domain name.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+BOOL cli_get_server_domain(struct cli_state *cli)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WWkstaGetInfo_REQ) /* req string */
+ +sizeof(RAP_WKSTA_INFO_L10) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetWkstaGetInfo */
+ p = make_header(param, RAP_WWkstaGetInfo,
+ RAP_WWkstaGetInfo_REQ, RAP_WKSTA_INFO_L10);
+ PUTWORD(p, 10); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt)) { /* return data, return size */
+ res = GETRES(rparam);
+ p = rdata;
+
+ if (res == 0) {
+ int converter;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+
+ p = rdata + DWORDSIZE + DWORDSIZE; /* skip computer & user names */
+ GETSTRINGP(p, cli->server_domain, rdata, converter);
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_type
+*
+* PURPOSE: Remotes a NetServerGetInfo API call to the current server
+* requesting server_info_1 level information to retrieve
+* the server type.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* pstype - pointer to uint32 to contain returned server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+BOOL cli_get_server_type(struct cli_state *cli, uint32 *pstype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WserverGetInfo_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerGetInfo */
+ p = make_header(param, RAP_WserverGetInfo,
+ RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+
+ res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ p = rdata;
+ *pstype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0 || res == ERRmoredata);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_ns_check_server_type
+*
+* PURPOSE: Remotes a NetServerEnum2 API call to the current server
+* requesting server_info_0 level information of machines
+* matching the given server type. If the returned server
+* list contains the machine name contained in cli->desthost
+* then we conclude the server type checks out. This routine
+* is useful to retrieve list of server's of a certain
+* type when all you have is a null session connection and
+* can't remote API calls such as NetWkstaGetInfo or
+* NetServerGetInfo.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing domain
+* stype - server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+BOOL cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L0) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ BOOL found_server = False;
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
+ PUTWORD(p, 0); /* info level 0 */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, stype);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+
+ res = GETRES(rparam);
+ cli->rap_error = res;
+
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i = 0;i < count;i++, p += 16) {
+ char ret_server[RAP_MACHNAME_LEN];
+
+ GETSTRINGF(p, ret_server, RAP_MACHNAME_LEN);
+ if (strequal(ret_server, cli->desthost)) {
+ found_server = True;
+ break;
+ }
+ }
+ }
+ else {
+ DEBUG(4,("cli_ns_check_server_type: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return found_server;
+ }
+
+
+/****************************************************************************
+ perform a NetWkstaUserLogoff
+****************************************************************************/
+BOOL cli_NetWkstaUserLogoff(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string */
+ +sizeof(RAP_USER_LOGOFF_INFO_L1) /* return string */
+ +RAP_USERNAME_LEN+1 /* user name+pad */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* buffer size */
+ +WORDSIZE]; /* buffer size? */
+ fstring upperbuf;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogoff */
+ p = make_header(param, RAP_WWkstaUserLogoff,
+ RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
+ PUTDWORD(p, 0); /* Null pointer */
+ PUTDWORD(p, 0); /* Null pointer */
+ fstrcpy(upperbuf, user);
+ strupper(upperbuf);
+ PUTSTRINGF(p, upperbuf, RAP_USERNAME_LEN);
+ p++; /* strange format, but ok */
+ fstrcpy(upperbuf, workstation);
+ strupper(upperbuf);
+ PUTSTRINGF(p, upperbuf, RAP_MACHNAME_LEN);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = GETRES(rparam);
+
+ if (cli->rap_error != 0) {
+ DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+int cli_NetPrintQEnum(struct cli_state *cli,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQEnum_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQEnum,
+ RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQEnum gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i=0;i<count;i++) {
+ pstring qname, sep_file, print_proc, dest, parms, comment;
+ uint16 jobcount, priority, start_time, until_time, status;
+
+ GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
+ p++; /* pad */
+ GETWORD(p, priority);
+ GETWORD(p, start_time);
+ GETWORD(p, until_time);
+ GETSTRINGP(p, sep_file, rdata, converter);
+ GETSTRINGP(p, print_proc, rdata, converter);
+ GETSTRINGP(p, dest, rdata, converter);
+ GETSTRINGP(p, parms, rdata, converter);
+ GETSTRINGP(p, parms, comment, converter);
+ GETWORD(p, status);
+ GETWORD(p, jobcount);
+
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+
+ if (jobcount) {
+ int j;
+ for (j=0;j<jobcount;j++) {
+ uint16 jid, pos, fsstatus;
+ pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
+ uint submitted, jsize;
+
+ GETWORD(p, jid);
+ GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
+ GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
+ GETSTRINGP(p, jparms, rdata, converter);
+ GETWORD(p, pos);
+ GETWORD(p, fsstatus);
+ GETSTRINGP(p, jstatus, rdata, converter);
+ GETDWORD(p, submitted);
+ GETDWORD(p, jsize);
+ GETSTRINGP(p, jcomment, rdata, converter);
+
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ }
+ } else {
+ DEBUG(4,("NetPrintQEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetPrintQEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +RAP_SHARENAME_LEN /* printer name */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQGetInfo,
+ RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
+ PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
+ PUTWORD(p, 2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int rsize, converter;
+ pstring qname, sep_file, print_proc, dest, parms, comment;
+ uint16 jobcount, priority, start_time, until_time, status;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, rsize);
+
+ p = rdata;
+ GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
+ p++; /* pad */
+ GETWORD(p, priority);
+ GETWORD(p, start_time);
+ GETWORD(p, until_time);
+ GETSTRINGP(p, sep_file, rdata, converter);
+ GETSTRINGP(p, print_proc, rdata, converter);
+ GETSTRINGP(p, dest, rdata, converter);
+ GETSTRINGP(p, parms, rdata, converter);
+ GETSTRINGP(p, comment, rdata, converter);
+ GETWORD(p, status);
+ GETWORD(p, jobcount);
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+ if (jobcount) {
+ int j;
+ for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize);j++) {
+ uint16 jid, pos, fsstatus;
+ pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
+ uint submitted, jsize;
+
+ GETWORD(p, jid);
+ GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
+ GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
+ GETSTRINGP(p, jparms, rdata, converter);
+ GETWORD(p, pos);
+ GETWORD(p, fsstatus);
+ GETSTRINGP(p, jstatus, rdata, converter);
+ GETDWORD(p, submitted);
+ GETDWORD(p, jsize);
+ GETSTRINGP(p, jcomment, rdata, converter);
+
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ } else {
+ DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetPrintQGetInfo no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetServiceEnum - list running services on a different host
+****************************************************************************/
+int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServiceEnum_REQ) /* parm string */
+ +sizeof(RAP_SERVICE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WServiceEnum,
+ RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if(cli->rap_error == 234)
+ DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
+ else if (cli->rap_error != 0) {
+ DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring comment;
+ char servicename[RAP_SRVCNAME_LEN];
+
+ GETSTRINGF(p, servicename, RAP_SRVCNAME_LEN);
+ p+=8; /* pass status words */
+ GETSTRINGF(p, comment, RAP_SRVCCMNT_LEN);
+
+ fn(servicename, comment, cli); /* BB add status too */
+ }
+ } else {
+ DEBUG(4,("NetServiceEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetServiceEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+/****************************************************************************
+call a NetSessionEnum - list workstations with sessions to an SMB server
+****************************************************************************/
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionEnum_REQ) /* parm string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionEnum,
+ RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetSessionEnum gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring wsname, username, clitype_name;
+ uint16 num_conns, num_opens, num_users;
+ uint sess_time, idle_time, user_flags;
+
+ GETSTRINGP(p, wsname, rdata, converter);
+ GETSTRINGP(p, username, rdata, converter);
+ GETWORD(p, num_conns);
+ GETWORD(p, num_opens);
+ GETWORD(p, num_users);
+ GETDWORD(p, sess_time);
+ GETDWORD(p, idle_time);
+ GETDWORD(p, user_flags);
+ GETSTRINGP(p, clitype_name, rdata, converter);
+
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ }
+
+ } else {
+ DEBUG(4,("NetSessionEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetSesssionEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetSessionGetInfo - get information about other session to an SMB server.
+****************************************************************************/
+
+int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionGetInfo_REQ) /* req string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionGetInfo,
+ RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ cli->rap_error = SVAL(rparam,0);
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ int rsize, converter;
+ pstring wsname, username, clitype_name;
+ uint16 num_conns, num_opens, num_users;
+ uint sess_time, idle_time, user_flags;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, rsize);
+
+ p = rdata;
+ GETSTRINGP(p, wsname, rdata, converter);
+ GETSTRINGP(p, username, rdata, converter);
+ GETWORD(p, num_conns);
+ GETWORD(p, num_opens);
+ GETWORD(p, num_users);
+ GETDWORD(p, sess_time);
+ GETDWORD(p, idle_time);
+ GETDWORD(p, user_flags);
+ GETSTRINGP(p, clitype_name, rdata, converter);
+
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ } else {
+ DEBUG(4,("NetSessionGetInfo res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetSessionGetInfo no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetSessionDel - close a session to an SMB server
+****************************************************************************/
+int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionDel_REQ) /* req string */
+ +1 /* no return string */
+ +RAP_MACHNAME_LEN /* workstation name */
+ +WORDSIZE]; /* reserved (0) */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,0); /* reserved word of 0 */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier, void (*fn)(uint16 conid, uint16 contype, uint16 numopens, uint16 numusers, uint32 contime, const char *username, const char *netname))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetConnectionEnum_REQ) /* req string */
+ +sizeof(RAP_CONNECTION_INFO_L1) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WconnectionEnum,
+ RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
+ PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetConnectionEnum gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring netname, username;
+ uint16 conn_id, conn_type, num_opens, num_users;
+ uint conn_time;
+
+ GETWORD(p,conn_id);
+ GETWORD(p,conn_type);
+ GETWORD(p,num_opens);
+ GETWORD(p,num_users);
+ GETDWORD(p,conn_time);
+ GETSTRINGP(p, username, rdata, converter);
+ GETSTRINGP(p, netname, rdata, converter);
+
+ fn(conn_id, conn_type, num_opens, num_users, conn_time,
+ username, netname);
+ }
+
+ } else {
+ DEBUG(4,("NetConnectionEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetConnectionEnum no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
diff --git a/source/libsmb/clireadwrite.c b/source/libsmb/clireadwrite.c
new file mode 100644
index 00000000000..f141a208bf9
--- /dev/null
+++ b/source/libsmb/clireadwrite.c
@@ -0,0 +1,364 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client file read/write routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/****************************************************************************
+Issue a single SMBread and don't wait for a reply.
+****************************************************************************/
+
+static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
+ size_t size, int i)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,10,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBreadX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SSVAL(cli->outbuf,smb_vwv5,size);
+ SSVAL(cli->outbuf,smb_vwv6,size);
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+Issue a single SMBreadraw and don't wait for a reply.
+****************************************************************************/
+
+static BOOL cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset,
+ size_t size, int i)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,10,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBreadbraw;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVAL(cli->outbuf,smb_vwv1,offset);
+ SSVAL(cli->outbuf,smb_vwv2,size);
+ SSVAL(cli->outbuf,smb_vwv3,size);
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+ Read size bytes at offset offset using SMBreadX.
+****************************************************************************/
+
+ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
+{
+ char *p;
+ int size2;
+ int readsize;
+ ssize_t total = 0;
+
+ if (size == 0)
+ return 0;
+
+ /*
+ * Set readsize to the maximum size we can handle in one readX,
+ * rounded down to a multiple of 1024.
+ */
+
+ readsize = (cli->max_xmit - (smb_size+32)) & ~1023;
+
+ while (total < size) {
+ readsize = MIN(readsize, size-total);
+
+ /* Issue a read and receive a reply */
+
+ if (!cli_issue_read(cli, fnum, offset, readsize, 0))
+ return -1;
+
+ if (!cli_receive_smb(cli))
+ return -1;
+
+ /* Check for error. Make sure to check for DOS and NT
+ errors. */
+
+ if (cli_is_error(cli)) {
+ NTSTATUS status = NT_STATUS_OK;
+ uint8 eclass = 0;
+ uint32 ecode = 0;
+
+ if (cli_is_nt_error(cli))
+ status = cli_nt_error(cli);
+ else
+ cli_dos_error(cli, &eclass, &ecode);
+
+ if ((eclass == ERRDOS && ecode == ERRmoredata) ||
+ NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES))
+ return -1;
+ }
+
+ size2 = SVAL(cli->inbuf, smb_vwv5);
+
+ if (size2 > readsize) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ return -1;
+ } else if (size2 < 0) {
+ DEBUG(5,("read return < 0!\n"));
+ return -1;
+ }
+
+ /* Copy data into buffer */
+
+ p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+ memcpy(buf + total, p, size2);
+
+ total += size2;
+ offset += size2;
+
+ /*
+ * If the server returned less than we asked for we're at EOF.
+ */
+
+ if (size2 < readsize)
+ break;
+ }
+
+ return total;
+}
+
+/****************************************************************************
+ Tester for the readraw call.
+****************************************************************************/
+
+ssize_t cli_readraw(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
+{
+ char *p;
+ int size2;
+ size_t readsize;
+ ssize_t total = 0;
+
+ if (size == 0)
+ return 0;
+
+ /*
+ * Set readsize to the maximum size we can handle in one readraw.
+ */
+
+ readsize = 0xFFFF;
+
+ while (total < size) {
+ readsize = MIN(readsize, size-total);
+
+ /* Issue a read and receive a reply */
+
+ if (!cli_issue_readraw(cli, fnum, offset, readsize, 0))
+ return -1;
+
+ if (!client_receive_smb(cli->fd, cli->inbuf, cli->timeout))
+ return -1;
+
+ size2 = smb_len(cli->inbuf);
+
+ if (size2 > readsize) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ return -1;
+ } else if (size2 < 0) {
+ DEBUG(5,("read return < 0!\n"));
+ return -1;
+ }
+
+ /* Copy data into buffer */
+
+ if (size2) {
+ p = cli->inbuf + 4;
+ memcpy(buf + total, p, size2);
+ }
+
+ total += size2;
+ offset += size2;
+
+ /*
+ * If the server returned less than we asked for we're at EOF.
+ */
+
+ if (size2 < readsize)
+ break;
+ }
+
+ return total;
+}
+
+/****************************************************************************
+issue a single SMBwrite and don't wait for a reply
+****************************************************************************/
+
+static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
+ size_t size, int i)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ if (size > 0xFFFF)
+ set_message(cli->outbuf,14,0,True);
+ else
+ set_message(cli->outbuf,12,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBwriteX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SIVAL(cli->outbuf,smb_vwv5,(mode & 0x0008) ? 0xFFFFFFFF : 0);
+ SSVAL(cli->outbuf,smb_vwv7,mode);
+
+ SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
+ SSVAL(cli->outbuf,smb_vwv9,((size>>16)&1));
+ SSVAL(cli->outbuf,smb_vwv10,size);
+ SSVAL(cli->outbuf,smb_vwv11,
+ smb_buf(cli->outbuf) - smb_base(cli->outbuf));
+
+ p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
+ memcpy(p, buf, size);
+ cli_setup_bcc(cli, p+size);
+
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ show_msg(cli->outbuf);
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+ write to a file
+ write_mode: 0x0001 disallow write cacheing
+ 0x0002 return bytes remaining
+ 0x0004 use raw named pipe protocol
+ 0x0008 start of message mode named pipe protocol
+****************************************************************************/
+
+ssize_t cli_write(struct cli_state *cli,
+ int fnum, uint16 write_mode,
+ char *buf, off_t offset, size_t size)
+{
+ int bwritten = 0;
+ int issued = 0;
+ int received = 0;
+ int mpx = MAX(cli->max_mux-1, 1);
+ int block = (cli->max_xmit - (smb_size+32)) & ~1023;
+ int blocks = (size + (block-1)) / block;
+
+ while (received < blocks) {
+
+ while ((issued - received < mpx) && (issued < blocks)) {
+ int bsent = issued * block;
+ int size1 = MIN(block, size - bsent);
+
+ if (!cli_issue_write(cli, fnum, offset + bsent,
+ write_mode,
+ buf + bsent,
+ size1, issued))
+ return -1;
+ issued++;
+ }
+
+ if (!cli_receive_smb(cli))
+ return bwritten;
+
+ received++;
+
+ if (cli_is_error(cli))
+ break;
+
+ bwritten += SVAL(cli->inbuf, smb_vwv2);
+ }
+
+ while (received < issued && cli_receive_smb(cli))
+ received++;
+
+ return bwritten;
+}
+
+/****************************************************************************
+ write to a file using a SMBwrite and not bypassing 0 byte writes
+****************************************************************************/
+
+ssize_t cli_smbwrite(struct cli_state *cli,
+ int fnum, char *buf, off_t offset, size_t size1)
+{
+ char *p;
+ ssize_t total = 0;
+
+ do {
+ size_t size = MIN(size1, cli->max_xmit - 48);
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,5, 0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBwrite;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SSVAL(cli->outbuf,smb_vwv1,size);
+ SIVAL(cli->outbuf,smb_vwv2,offset);
+ SSVAL(cli->outbuf,smb_vwv4,0);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+ SSVAL(p, 0, size); p += 2;
+ memcpy(p, buf, size); p += size;
+
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli))
+ return -1;
+
+ if (!cli_receive_smb(cli))
+ return -1;
+
+ if (cli_is_error(cli))
+ return -1;
+
+ size = SVAL(cli->inbuf,smb_vwv0);
+ if (size == 0)
+ break;
+
+ size1 -= size;
+ total += size;
+ } while (size1);
+
+ return total;
+}
diff --git a/source/libsmb/clisecdesc.c b/source/libsmb/clisecdesc.c
new file mode 100644
index 00000000000..0e0884b843c
--- /dev/null
+++ b/source/libsmb/clisecdesc.c
@@ -0,0 +1,132 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client security descriptor functions
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ query the security descriptor for a open file
+ ****************************************************************************/
+SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum,
+ TALLOC_CTX *mem_ctx)
+{
+ char param[8];
+ char *rparam=NULL, *rdata=NULL;
+ int rparam_count=0, rdata_count=0;
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_QUERY_SECURITY_DESC,
+ 0,
+ NULL, 0, 0,
+ param, 8, 4,
+ NULL, 0, 0x10000)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_QUERY_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("Failed to recv NT_TRANSACT_QUERY_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+ prs_init(&pd, rdata_count, mem_ctx, UNMARSHALL);
+ prs_append_data(&pd, rdata, rdata_count);
+ pd.data_offset = 0;
+
+ if (!sec_io_desc("sd data", &psd, &pd, 1)) {
+ DEBUG(1,("Failed to parse secdesc\n"));
+ goto cleanup;
+ }
+
+ cleanup:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ prs_mem_free(&pd);
+ return psd;
+}
+
+/****************************************************************************
+ set the security descriptor for a open file
+ ****************************************************************************/
+BOOL cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd)
+{
+ char param[8];
+ char *rparam=NULL, *rdata=NULL;
+ int rparam_count=0, rdata_count=0;
+ TALLOC_CTX *mem_ctx;
+ prs_struct pd;
+ BOOL ret = False;
+
+ if ((mem_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("talloc_init failed.\n"));
+ goto cleanup;
+ }
+
+ prs_init(&pd, 0, mem_ctx, MARSHALL);
+ prs_give_memory(&pd, NULL, 0, True);
+
+ if (!sec_io_desc("sd data", &sd, &pd, 1)) {
+ DEBUG(1,("Failed to marshall secdesc\n"));
+ goto cleanup;
+ }
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_SET_SECURITY_DESC,
+ 0,
+ NULL, 0, 0,
+ param, 8, 0,
+ pd.data_p, pd.data_offset, 0)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("NT_TRANSACT_SET_SECURITY_DESC failed\n"));
+ goto cleanup;
+ }
+
+ ret = True;
+
+ cleanup:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ talloc_destroy(mem_ctx);
+
+ prs_mem_free(&pd);
+ return ret;
+}
diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c
new file mode 100644
index 00000000000..bc3873bf186
--- /dev/null
+++ b/source/libsmb/clispnego.c
@@ -0,0 +1,615 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ generate a negTokenInit packet given a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+DATA_BLOB spnego_gen_negTokenInit(uint8 guid[16],
+ const char *OIDs[],
+ const char *principal)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_write(&data, guid, 16);
+ asn1_push_tag(&data,ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_write_GeneralString(&data,principal);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ parse a negTokenInit packet giving a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+BOOL spnego_parse_negTokenInit(DATA_BLOB blob,
+ uint8 guid[16],
+ char *OIDs[ASN1_MAX_OIDS],
+ char **principal)
+{
+ int i;
+ BOOL ret;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+
+ asn1_read(&data, guid, 16);
+ asn1_start_tag(&data,ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
+ char *oid = NULL;
+ asn1_read_OID(&data,&oid);
+ OIDs[i] = oid;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data, ASN1_CONTEXT(3));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_read_GeneralString(&data,principal);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+ asn1_free(&data);
+ return ret;
+}
+
+
+/*
+ generate a negTokenTarg packet given a list of OIDs and a security blob
+*/
+DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ parse a negTokenTarg packet giving a list of OIDs and a security blob
+*/
+BOOL parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob)
+{
+ int i;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
+ char *oid = NULL;
+ asn1_read_OID(&data,&oid);
+ OIDs[i] = oid;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,secblob);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to parse negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a krb5 GSS-API wrapper packet given a ticket
+*/
+DATA_BLOB spnego_gen_krb5_wrap(DATA_BLOB ticket)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data, OID_KERBEROS5);
+ asn1_write_BOOLEAN(&data, 0);
+ asn1_write(&data, ticket.data, ticket.length);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a krb5 GSS-API wrapper packet giving a ticket
+*/
+BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket)
+{
+ BOOL ret;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data, OID_KERBEROS5);
+ asn1_check_BOOLEAN(&data, 0);
+ *ticket = data_blob(data.data, asn1_tag_remaining(&data));
+ asn1_read(&data, ticket->data, ticket->length);
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
+ kerberos session setup
+*/
+DATA_BLOB spnego_gen_negTokenTarg(struct cli_state *cli, char *principal)
+{
+ DATA_BLOB tkt, tkt_wrapped, targ;
+ const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
+
+ /* get a kerberos ticket for the service */
+ tkt = krb5_get_ticket(principal);
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt);
+
+ /* and wrap that in a shiny SPNEGO wrapper */
+ targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
+
+ data_blob_free(&tkt_wrapped);
+ data_blob_free(&tkt);
+
+ return targ;
+}
+
+
+/*
+ parse a spnego NTLMSSP challenge packet giving two security blobs
+*/
+BOOL spnego_parse_challenge(DATA_BLOB blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2)
+{
+ BOOL ret;
+ ASN1_DATA data;
+
+ ZERO_STRUCTP(chal1);
+ ZERO_STRUCTP(chal2);
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data,1);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, OID_NTLMSSP);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, chal1);
+ asn1_end_tag(&data);
+
+ /* the second challenge is optional (XP doesn't send it) */
+ if (asn1_tag_remaining(&data)) {
+ asn1_start_tag(&data,ASN1_CONTEXT(3));
+ asn1_read_OctetString(&data, chal2);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+ asn1_free(&data);
+ return ret;
+}
+
+
+/*
+ generate a spnego NTLMSSP challenge packet given two security blobs
+ The second challenge is optional
+*/
+BOOL spnego_gen_challenge(DATA_BLOB *blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2)
+{
+ ASN1_DATA data;
+
+ ZERO_STRUCT(data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_write_enumerated(&data,1);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_write_OID(&data, OID_NTLMSSP);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data, chal1->data, chal1->length);
+ asn1_pop_tag(&data);
+
+ /* the second challenge is optional (XP doesn't send it) */
+ if (chal2) {
+ asn1_push_tag(&data,ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, chal2->data, chal2->length);
+ asn1_pop_tag(&data);
+ }
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ return False;
+ }
+
+ *blob = data_blob(data.data, data.length);
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords
+*/
+DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(1));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ ret = data_blob(data.data, data.length);
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords
+*/
+BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,auth);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth failed at %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular varient of our rpc code. This
+ generator is not general enough for all our rpc needs, its just
+ enough for the spnego/ntlmssp code
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+BOOL msrpc_gen(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, n;
+ va_list ap;
+ char *s;
+ uint8 *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+
+ /* first scan the format to work out the header and body size */
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_charnum(s) * 2;
+ break;
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ head_size += 8;
+ data_size += va_arg(ap, int);
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ head_size += va_arg(ap, int);
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_size += str_charnum(s) + 1;
+ break;
+ }
+ }
+ va_end(ap);
+
+ /* allocate the space, then scan the format again to fill in the values */
+ blob->data = malloc(head_size + data_size);
+ blob->length = head_size + data_size;
+ if (!blob->data) return False;
+
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ n = str_charnum(s);
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
+ data_ofs += n*2;
+ break;
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ memcpy(blob->data+data_ofs, b, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ SIVAL(blob->data, head_ofs, n); head_ofs += 4;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ memcpy(blob->data + head_ofs, b, n);
+ head_ofs += n;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += push_string(NULL, blob->data+head_ofs, s, -1,
+ STR_ASCII|STR_TERMINATE);
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
+
+
+/*
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+BOOL msrpc_parse(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ int head_ofs = 0;
+ uint16 len1, len2;
+ uint32 ptr;
+ uint32 *v;
+ pstring p;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || (len1&1) || ptr + len1 > blob->length) {
+ return False;
+ }
+ ps = va_arg(ap, char **);
+ pull_string(NULL, p, blob->data + ptr, -1, len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = strdup(p);
+ break;
+ case 'B':
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ *b = data_blob(blob->data + ptr, len1);
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned);
+ *b = data_blob(blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32 *);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += pull_string(NULL, p, blob->data+head_ofs, -1,
+ blob->length - head_ofs,
+ STR_ASCII|STR_TERMINATE);
+ if (strcmp(s, p) != 0) {
+ return False;
+ }
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
diff --git a/source/libsmb/clistr.c b/source/libsmb/clistr.c
new file mode 100644
index 00000000000..baec3e5da8d
--- /dev/null
+++ b/source/libsmb/clistr.c
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client string routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+int clistr_push(struct cli_state *cli, void *dest, const char *src, int dest_len, int flags)
+{
+ return push_string(cli->outbuf, dest, src, dest_len, flags);
+}
+
+int clistr_pull(struct cli_state *cli, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ return pull_string(cli->inbuf, dest, src, dest_len, src_len, flags);
+}
+
+
+int clistr_align_out(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->outbuf, p, flags);
+}
+
+int clistr_align_in(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->inbuf, p, flags);
+}
diff --git a/source/libsmb/clitrans.c b/source/libsmb/clitrans.c
new file mode 100644
index 00000000000..8da1cc665f0
--- /dev/null
+++ b/source/libsmb/clitrans.c
@@ -0,0 +1,469 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client transaction calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+ send a SMB trans or trans2 request
+ ****************************************************************************/
+BOOL cli_send_trans(struct cli_state *cli, int trans,
+ const char *pipe_name,
+ int fid, int flags,
+ uint16 *setup, int lsetup, int msetup,
+ char *param, int lparam, int mparam,
+ char *data, int ldata, int mdata)
+{
+ int i;
+ int this_ldata,this_lparam;
+ int tot_data=0,tot_param=0;
+ char *outdata,*outparam;
+ char *p;
+ int pipe_name_len=0;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,14+lsetup,0,True);
+ CVAL(cli->outbuf,smb_com) = trans;
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ if (pipe_name) {
+ pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
+ }
+
+ outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
+ SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
+ SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
+ SSVAL(cli->outbuf,smb_flags,flags); /* flags */
+ SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
+ SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
+ p = smb_buf(cli->outbuf);
+ if (trans != SMBtrans) {
+ *p++ = 0; /* put in a null smb_name */
+ *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
+ }
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) ||
+ cli_is_error(cli)) {
+ return(False);
+ }
+
+ tot_data = this_ldata;
+ tot_param = this_lparam;
+
+ while (tot_data < ldata || tot_param < lparam) {
+ this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
+
+ set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
+ CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
+
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
+ SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
+ if (trans==SMBtrans2)
+ SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_trans(struct cli_state *cli,int trans,
+ char **param, int *param_len,
+ char **data, int *data_len)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+ NTSTATUS status;
+ char *tdata;
+ char *tparam;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+
+ /*
+ * An NT RPC pipe call can return ERRDOS, ERRmoredata
+ * to a trans call. This is not an error and should not
+ * be treated as such.
+ */
+ status = cli_nt_error(cli);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return False;
+ }
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ /* allocate it */
+ if (total_data!=0) {
+ tdata = Realloc(*data,total_data);
+ if (!tdata) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
+ return False;
+ }
+ else
+ *data = tdata;
+ }
+
+ if (total_param!=0) {
+ tparam = Realloc(*param,total_param);
+ if (!tparam) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
+ return False;
+ }
+ else
+ *param = tparam;
+ }
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_drcnt);
+ this_param = SVAL(cli->inbuf,smb_prcnt);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ return False;
+ }
+
+ if (this_data)
+ memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
+ this_param);
+ *data_len += this_data;
+ *param_len += this_param;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
+ return(False);
+ }
+ }
+
+ return(True);
+}
+
+
+
+
+/****************************************************************************
+ send a SMB nttrans request
+ ****************************************************************************/
+BOOL cli_send_nt_trans(struct cli_state *cli,
+ int function,
+ int flags,
+ uint16 *setup, int lsetup, int msetup,
+ char *param, int lparam, int mparam,
+ char *data, int ldata, int mdata)
+{
+ int i;
+ int this_ldata,this_lparam;
+ int tot_data=0,tot_param=0;
+ char *outdata,*outparam;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,19+lsetup,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBnttrans;
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ outparam = smb_buf(cli->outbuf)+3;
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
+ SCVAL(cli->outbuf,smb_nt_Flags,flags);
+ SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
+ SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
+ SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
+ SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
+ SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
+ SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
+ SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
+ SIVAL(cli->outbuf,smb_nt_Function, function);
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
+
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) ||
+ cli_is_error(cli)) {
+ return(False);
+ }
+
+ tot_data = this_ldata;
+ tot_param = this_lparam;
+
+ while (tot_data < ldata || tot_param < lparam) {
+ this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
+
+ set_message(cli->outbuf,18,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBnttranss;
+
+ /* XXX - these should probably be aligned */
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
+ SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
+ SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
+ SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
+ SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
+ SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+ receive a SMB nttrans response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_nt_trans(struct cli_state *cli,
+ char **param, int *param_len,
+ char **data, int *data_len)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+ uint8 eclass;
+ uint32 ecode;
+ char *tdata;
+ char *tparam;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+
+ /*
+ * An NT RPC pipe call can return ERRDOS, ERRmoredata
+ * to a trans call. This is not an error and should not
+ * be treated as such.
+ */
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
+ return(False);
+ }
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+
+ /* allocate it */
+ if (total_data) {
+ tdata = Realloc(*data,total_data);
+ if (!tdata) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
+ return False;
+ } else {
+ *data = tdata;
+ }
+ }
+
+ if (total_param) {
+ tparam = Realloc(*param,total_param);
+ if (!tparam) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
+ return False;
+ } else {
+ *param = tparam;
+ }
+ }
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
+ this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ return False;
+ }
+
+ if (this_data)
+ memcpy(*data + SVAL(cli->inbuf,smb_ntr_DataDisplacement),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_DataOffset),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(cli->inbuf,smb_ntr_ParameterDisplacement),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_ParameterOffset),
+ this_param);
+ *data_len += this_data;
+ *param_len += this_param;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if(cli->nt_pipe_fnum == 0 ||
+ !(eclass == ERRDOS && ecode == ERRmoredata))
+ return(False);
+ }
+ }
+
+ return(True);
+}
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
new file mode 100644
index 00000000000..5f65c13edd9
--- /dev/null
+++ b/source/libsmb/credentials.c
@@ -0,0 +1,216 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ code to manipulate domain credentials
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+represent a credential as a string
+****************************************************************************/
+char *credstr(uchar *cred)
+{
+ static fstring buf;
+ slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
+ cred[0], cred[1], cred[2], cred[3],
+ cred[4], cred[5], cred[6], cred[7]);
+ return buf;
+}
+
+
+/****************************************************************************
+ setup the session key.
+Input: 8 byte challenge block
+ 8 byte server challenge block
+ 16 byte md4 encrypted password
+Output:
+ 8 byte session key
+****************************************************************************/
+void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass,
+ uchar session_key[8])
+{
+ uint32 sum[2];
+ unsigned char sum2[8];
+
+ sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0);
+ sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ cred_hash1(session_key, sum2,(unsigned char *)pass);
+
+ /* debug output */
+ DEBUG(4,("cred_session_key\n"));
+
+ DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data)));
+ DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data)));
+ DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+}
+
+
+/****************************************************************************
+create a credential
+
+Input:
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ 8 byte credential
+****************************************************************************/
+void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred)
+{
+ DOM_CHAL time_cred;
+
+ SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time);
+ SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
+
+ cred_hash2(cred->data, time_cred.data, session_key);
+
+ /* debug output*/
+ DEBUG(4,("cred_create\n"));
+
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+ DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data)));
+ DEBUG(5,(" timestamp: %x\n" , timestamp.time));
+ DEBUG(5,(" timecred : %s\n", credstr(time_cred.data)));
+ DEBUG(5,(" calc_cred: %s\n", credstr(cred->data)));
+}
+
+
+/****************************************************************************
+ check a supplied credential
+
+Input:
+ 8 byte received credential
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ returns 1 if computed credential matches received credential
+ returns 0 otherwise
+****************************************************************************/
+int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
+ UTIME timestamp)
+{
+ DOM_CHAL cred2;
+
+ cred_create(session_key, stored_cred, timestamp, &cred2);
+
+ /* debug output*/
+ DEBUG(4,("cred_assert\n"));
+
+ DEBUG(5,(" challenge : %s\n", credstr(cred->data)));
+ DEBUG(5,(" calculated: %s\n", credstr(cred2.data)));
+
+ if (memcmp(cred->data, cred2.data, 8) == 0)
+ {
+ DEBUG(5, ("credentials check ok\n"));
+ return True;
+ }
+ else
+ {
+ DEBUG(5, ("credentials check wrong\n"));
+ return False;
+ }
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL clnt_deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
+
+ /* increment client time by one second */
+ new_clnt_time.time = sto_clnt_cred->timestamp.time + 1;
+
+ /* check that the received server credentials are valid */
+ if (!cred_assert(&rcv_srv_cred->challenge, sess_key,
+ &sto_clnt_cred->challenge, new_clnt_time))
+ {
+ return False;
+ }
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data)));
+ return True;
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred,
+ DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("deal_with_creds: %d\n", __LINE__));
+
+ /* check that the received client credentials are valid */
+ if (!cred_assert(&rcv_clnt_cred->challenge, sess_key,
+ &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp))
+ {
+ return False;
+ }
+
+ /* increment client time by one second */
+ new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1;
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred));
+
+ /* doesn't matter that server time is 0 */
+ rtn_srv_cred->timestamp.time = 0;
+
+ DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time));
+
+ /* create return credentials for inclusion in the reply */
+ cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time,
+ &rtn_srv_cred->challenge);
+
+ DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data)));
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ return True;
+}
diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c
new file mode 100644
index 00000000000..ab524a01f59
--- /dev/null
+++ b/source/libsmb/errormap.c
@@ -0,0 +1,1438 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 3.0
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/* NT status -> dos error map */
+static struct {
+ uint8 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} ntstatus_to_dos_map[] = {
+ {ERRDOS, 997, NT_STATUS(0x00000103)},
+ {ERRDOS, 111, STATUS_MORE_ENTRIES},
+ {ERRDOS, 1300, NT_STATUS(0x00000106)},
+ {ERRDOS, 1301, NT_STATUS(0x00000107)},
+ {ERRDOS, 1022, NT_STATUS(0x0000010c)},
+ {ERRDOS, 1302, NT_STATUS(0x0000010d)},
+ {ERRDOS, 8201, NT_STATUS(0x00000121)},
+ {ERRDOS, 31, NT_STATUS_UNSUCCESSFUL},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH},
+ {ERRDOS, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRDOS, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRDOS, 1454, NT_STATUS_PAGEFILE_QUOTA},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRDOS, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_CID},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_INVALID_DEVICE_REQUEST},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRDOS, 1785, NT_STATUS_UNRECOGNIZED_MEDIA},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRDOS, 111, NT_STATUS_MORE_PROCESSING_REQUIRED},
+ {ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW},
+ {ERRDOS, ERRbadpipe, NT_STATUS(0xc000001a)},
+ {ERRDOS, ERRbadpipe, NT_STATUS_UNABLE_TO_DELETE_SECTION},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_INVALID_SYSTEM_SERVICE},
+ {ERRDOS, 29, NT_STATUS_ILLEGAL_INSTRUCTION},
+ {ERRDOS, ERRbadaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRbadaccess, NT_STATUS_INVALID_VIEW_SIZE},
+ {ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION},
+ {ERRDOS, ERRbadaccess, NT_STATUS_ALREADY_COMMITTED},
+ {ERRDOS, ERRbadaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, ERRinsufficientbuffer, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH},
+ {ERRDOS, 37, NT_STATUS_NONCONTINUABLE_EXCEPTION},
+ {ERRDOS, 38, NT_STATUS_INVALID_DISPOSITION},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRDOS, 43, NT_STATUS_PARITY_ERROR},
+ {ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+ {ERRDOS, 487, NT_STATUS_NOT_COMMITTED},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_MIX},
+ {ERRDOS, 26, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRSRV, 206, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND},
+ {ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED},
+ {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+ {ERRDOS, 1117, NT_STATUS_DATA_OVERRUN},
+ {ERRDOS, 1117, NT_STATUS_DATA_LATE_ERROR},
+ {ERRDOS, ERRbaddata, NT_STATUS_DATA_ERROR},
+ {ERRDOS, ERRbaddata, NT_STATUS_CRC_ERROR},
+ {ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG},
+ {ERRDOS, ERRbadaccess, NT_STATUS_PORT_CONNECTION_REFUSED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRDOS, 1816, NT_STATUS_QUOTA_EXCEEDED},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PAGE_PROTECTION},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, ERRbadpipe, NT_STATUS_PORT_ALREADY_SET},
+ {ERRDOS, ERRbadpipe, NT_STATUS_SECTION_NOT_IMAGE},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, ERRbadaccess, NT_STATUS_THREAD_IS_TERMINATING},
+ {ERRDOS, ERRbadpipe, NT_STATUS_BAD_WORKING_SET_LIMIT},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INCOMPATIBLE_FILE_MAP},
+ {ERRDOS, ERRbadpipe, NT_STATUS_SECTION_PROTECTION},
+ {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 276, NT_STATUS_NO_EAS_ON_FILE},
+ {ERRDOS, 276, NT_STATUS_EA_CORRUPT_ERROR},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED},
+ {ERRDOS, ERRbadaccess, NT_STATUS_DELETE_PENDING},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRDOS, 1305, NT_STATUS_UNKNOWN_REVISION},
+ {ERRDOS, 1306, NT_STATUS_REVISION_MISMATCH},
+ {ERRDOS, 1307, NT_STATUS_INVALID_OWNER},
+ {ERRDOS, 1308, NT_STATUS_INVALID_PRIMARY_GROUP},
+ {ERRDOS, 1309, NT_STATUS_NO_IMPERSONATION_TOKEN},
+ {ERRDOS, 1310, NT_STATUS_CANT_DISABLE_MANDATORY},
+ {ERRDOS, 1311, NT_STATUS_NO_LOGON_SERVERS},
+ {ERRDOS, 1312, NT_STATUS_NO_SUCH_LOGON_SESSION},
+ {ERRDOS, 1313, NT_STATUS_NO_SUCH_PRIVILEGE},
+ {ERRDOS, 1314, NT_STATUS_PRIVILEGE_NOT_HELD},
+ {ERRDOS, 1315, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {ERRDOS, 1316, NT_STATUS_USER_EXISTS},
+ {ERRDOS, 1317, NT_STATUS_NO_SUCH_USER},
+ {ERRDOS, 1318, NT_STATUS_GROUP_EXISTS},
+ {ERRDOS, 1319, NT_STATUS_NO_SUCH_GROUP},
+ {ERRDOS, 1320, NT_STATUS_MEMBER_IN_GROUP},
+ {ERRDOS, 1321, NT_STATUS_MEMBER_NOT_IN_GROUP},
+ {ERRDOS, 1322, NT_STATUS_LAST_ADMIN},
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRDOS, 1324, NT_STATUS_ILL_FORMED_PASSWORD},
+ {ERRDOS, 1325, NT_STATUS_PASSWORD_RESTRICTION},
+ {ERRDOS, ERRlogonfailure, NT_STATUS_LOGON_FAILURE},
+ {ERRDOS, 1327, NT_STATUS_ACCOUNT_RESTRICTION},
+ {ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS},
+ {ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED},
+ {ERRDOS, 1332, NT_STATUS_NONE_MAPPED},
+ {ERRDOS, 1333, NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+ {ERRDOS, 1334, NT_STATUS_LUIDS_EXHAUSTED},
+ {ERRDOS, 1335, NT_STATUS_INVALID_SUB_AUTHORITY},
+ {ERRDOS, 1336, NT_STATUS_INVALID_ACL},
+ {ERRDOS, 1337, NT_STATUS_INVALID_SID},
+ {ERRDOS, 1338, NT_STATUS_INVALID_SECURITY_DESCR},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT},
+ {ERRDOS, 1008, NT_STATUS_NO_TOKEN},
+ {ERRDOS, 1340, NT_STATUS_BAD_INHERITANCE_ACL},
+ {ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED},
+ {ERRSRV, ERRnoroom, NT_STATUS_DISK_FULL},
+ {ERRDOS, 1341, NT_STATUS_SERVER_DISABLED},
+ {ERRDOS, 1342, NT_STATUS_SERVER_NOT_DISABLED},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRDOS, 1343, NT_STATUS_INVALID_ID_AUTHORITY},
+ {ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA},
+ {ERRDOS, 1812, NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+ {ERRDOS, 1813, NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+ {ERRDOS, 1814, NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+ {ERRDOS, 140, NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+ {ERRDOS, 141, NT_STATUS_FLOAT_DENORMAL_OPERAND},
+ {ERRDOS, 142, NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+ {ERRDOS, 143, NT_STATUS_FLOAT_INEXACT_RESULT},
+ {ERRDOS, 144, NT_STATUS_FLOAT_INVALID_OPERATION},
+ {ERRDOS, 145, NT_STATUS_FLOAT_OVERFLOW},
+ {ERRDOS, 146, NT_STATUS_FLOAT_STACK_CHECK},
+ {ERRDOS, 147, NT_STATUS_FLOAT_UNDERFLOW},
+ {ERRDOS, 148, NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRDOS, 150, NT_STATUS_PRIVILEGED_INSTRUCTION},
+ {ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES},
+ {ERRDOS, 1006, NT_STATUS_FILE_INVALID},
+ {ERRDOS, 1344, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND},
+ {ERRDOS, ERRbaddata, NT_STATUS_DEVICE_DATA_ERROR},
+ {ERRDOS, 1167, NT_STATUS_DEVICE_NOT_CONNECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE},
+ {ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE},
+ {ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED},
+ {ERRDOS, 1453, NT_STATUS_WORKING_SET_QUOTA},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY},
+ {ERRDOS, 1345, NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+ {ERRDOS, 1346, NT_STATUS_BAD_IMPERSONATION_LEVEL},
+ {ERRDOS, 1347, NT_STATUS_CANT_OPEN_ANONYMOUS},
+ {ERRDOS, 1348, NT_STATUS_BAD_VALIDATION_CLASS},
+ {ERRDOS, 1349, NT_STATUS_BAD_TOKEN_TYPE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_BAD_MASTER_BOOT_RECORD},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_ILLEGAL_FUNCTION},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRDOS, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRDOS, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED},
+ {ERRDOS, ERRbadaccess, NT_STATUS_FILE_IS_A_DIRECTORY},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRSRV, ERRqfull, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRSRV, ERRqtoobig, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRSRV, ERRinvpfid, NT_STATUS_PRINT_CANCELLED},
+ {ERRSRV, ERRinvnid, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRSRV, ERRaccess, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRbadtype, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRinvnetname, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES},
+ {ERRSRV, ERRtoomanyuids, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRSRV, ERRpaused, NT_STATUS_SHARING_PAUSED},
+ {ERRSRV, ERRmsgoff, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRbadaccess, NT_STATUS_FILE_RENAMED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRDOS, 1350, NT_STATUS_NO_SECURITY_ON_OBJECT},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY},
+ {ERRDOS, 1351, NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+ {ERRDOS, 1352, NT_STATUS_INVALID_SERVER_STATE},
+ {ERRDOS, 1353, NT_STATUS_INVALID_DOMAIN_STATE},
+ {ERRDOS, 1354, NT_STATUS_INVALID_DOMAIN_ROLE},
+ {ERRDOS, 1355, NT_STATUS_NO_SUCH_DOMAIN},
+ {ERRDOS, 1356, NT_STATUS_DOMAIN_EXISTS},
+ {ERRDOS, 1357, NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRDOS, 1358, NT_STATUS_INTERNAL_DB_CORRUPTION},
+ {ERRDOS, 1359, NT_STATUS_INTERNAL_ERROR},
+ {ERRDOS, 1360, NT_STATUS_GENERIC_NOT_MAPPED},
+ {ERRDOS, 1361, NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+ {ERRDOS, 1784, NT_STATUS_INVALID_USER_BUFFER},
+ {ERRDOS, 1362, NT_STATUS_NOT_LOGON_PROCESS},
+ {ERRDOS, 1363, NT_STATUS_LOGON_SESSION_EXISTS},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_1},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_2},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_3},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_4},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_5},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_6},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_7},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_8},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_9},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_10},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_11},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PARAMETER_12},
+ {ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED},
+ {ERRDOS, 1001, NT_STATUS_STACK_OVERFLOW},
+ {ERRDOS, 1364, NT_STATUS_NO_SUCH_PACKAGE},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, ERRremcd, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, 276, NT_STATUS_FILE_CORRUPT_ERROR},
+ {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRDOS, 1365, NT_STATUS_BAD_LOGON_SESSION_STATE},
+ {ERRDOS, 1366, NT_STATUS_LOGON_SESSION_COLLISION},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, 2401, NT_STATUS_FILES_OPEN},
+ {ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE},
+ {ERRDOS, ERRbadaccess, NT_STATUS_PROCESS_IS_TERMINATING},
+ {ERRDOS, 1367, NT_STATUS_INVALID_LOGON_TYPE},
+ {ERRDOS, 1368, NT_STATUS_CANNOT_IMPERSONATE},
+ {ERRDOS, 1056, NT_STATUS_IMAGE_ALREADY_LOADED},
+ {ERRDOS, 1444, NT_STATUS_NO_LDT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+ {ERRDOS, 1369, NT_STATUS_RXACT_INVALID_STATE},
+ {ERRDOS, 1370, NT_STATUS_RXACT_COMMIT_FAILURE},
+ {ERRDOS, 1006, NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRDOS, 995, NT_STATUS_CANCELLED},
+ {ERRDOS, ERRbadaccess, NT_STATUS_CANNOT_DELETE},
+ {ERRDOS, 1210, NT_STATUS_INVALID_COMPUTER_NAME},
+ {ERRDOS, ERRbadaccess, NT_STATUS_FILE_DELETED},
+ {ERRDOS, 1371, NT_STATUS_SPECIAL_ACCOUNT},
+ {ERRDOS, 1372, NT_STATUS_SPECIAL_GROUP},
+ {ERRDOS, 1373, NT_STATUS_SPECIAL_USER},
+ {ERRDOS, 1374, NT_STATUS_MEMBERS_PRIMARY_GROUP},
+ {ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED},
+ {ERRDOS, 1375, NT_STATUS_TOKEN_ALREADY_IN_USE},
+ {ERRDOS, 1455, NT_STATUS_COMMITMENT_LIMIT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16},
+ {ERRDOS, 1398, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND},
+ {ERRSRV, ERRinvnid, NT_STATUS_LOCAL_DISCONNECT},
+ {ERRSRV, ERRinvnid, NT_STATUS_REMOTE_DISCONNECT},
+ {ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES},
+ {ERRDOS, 59, NT_STATUS_LINK_FAILED},
+ {ERRDOS, 59, NT_STATUS_LINK_TIMEOUT},
+ {ERRDOS, 59, NT_STATUS_INVALID_CONNECTION},
+ {ERRDOS, 59, NT_STATUS_INVALID_ADDRESS},
+ {ERRDOS, 1114, NT_STATUS_DLL_INIT_FAILED},
+ {ERRDOS, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD_CORE},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRDOS, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRDOS, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRDOS, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRDOS, 1118, NT_STATUS_SERIAL_NO_DEVICE_INITED},
+ {ERRDOS, 1376, NT_STATUS_NO_SUCH_ALIAS},
+ {ERRDOS, 1377, NT_STATUS_MEMBER_NOT_IN_ALIAS},
+ {ERRDOS, 1378, NT_STATUS_MEMBER_IN_ALIAS},
+ {ERRDOS, 1379, NT_STATUS_ALIAS_EXISTS},
+ {ERRDOS, 1380, NT_STATUS_LOGON_NOT_GRANTED},
+ {ERRDOS, 1381, NT_STATUS_TOO_MANY_SECRETS},
+ {ERRDOS, 1382, NT_STATUS_SECRET_TOO_LONG},
+ {ERRDOS, 1383, NT_STATUS_INTERNAL_DB_ERROR},
+ {ERRDOS, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRDOS, 1384, NT_STATUS_TOO_MANY_CONTEXT_IDS},
+ {ERRDOS, 1385, NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+ {ERRDOS, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRDOS, 1386, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+ {ERRDOS, 1117, NT_STATUS_FT_MISSING_MEMBER},
+ {ERRDOS, 1113, NT_STATUS_UNMAPPABLE_CHARACTER},
+ {ERRDOS, 1122, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+ {ERRDOS, 1123, NT_STATUS_FLOPPY_WRONG_CYLINDER},
+ {ERRDOS, 1124, NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+ {ERRDOS, 1125, NT_STATUS_FLOPPY_BAD_REGISTERS},
+ {ERRDOS, 1126, NT_STATUS_DISK_RECALIBRATE_FAILED},
+ {ERRDOS, 1127, NT_STATUS_DISK_OPERATION_FAILED},
+ {ERRDOS, 1128, NT_STATUS_DISK_RESET_FAILED},
+ {ERRDOS, 1119, NT_STATUS_SHARED_IRQ_BUSY},
+ {ERRDOS, 1117, NT_STATUS_FT_ORPHANING},
+ {ERRDOS, 1105, NT_STATUS_PARTITION_FAILURE},
+ {ERRDOS, 1106, NT_STATUS_INVALID_BLOCK_LENGTH},
+ {ERRDOS, 1107, NT_STATUS_DEVICE_NOT_PARTITIONED},
+ {ERRDOS, 1108, NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+ {ERRDOS, 1109, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+ {ERRDOS, 1129, NT_STATUS_EOM_OVERFLOW},
+ {ERRDOS, 1112, NT_STATUS_NO_MEDIA},
+ {ERRDOS, 1387, NT_STATUS_NO_SUCH_MEMBER},
+ {ERRDOS, 1388, NT_STATUS_INVALID_MEMBER},
+ {ERRDOS, 1018, NT_STATUS_KEY_DELETED},
+ {ERRDOS, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRDOS, 1389, NT_STATUS_TOO_MANY_SIDS},
+ {ERRDOS, 1390, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+ {ERRDOS, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRDOS, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+ {ERRDOS, 1117, NT_STATUS_DRIVER_INTERNAL_ERROR},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRDOS, 1117, NT_STATUS_IO_DEVICE_ERROR},
+ {ERRDOS, 1117, NT_STATUS_DEVICE_PROTOCOL_ERROR},
+ {ERRDOS, 1502, NT_STATUS_LOG_FILE_FULL},
+ {ERRDOS, 19, NT_STATUS_TOO_LATE},
+ {ERRDOS, 1786, NT_STATUS_NO_TRUST_LSA_SECRET},
+ {ERRDOS, 1787, NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+ {ERRDOS, 1788, NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+ {ERRDOS, 1789, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+ {ERRDOS, 1500, NT_STATUS_EVENTLOG_FILE_CORRUPT},
+ {ERRDOS, 1501, NT_STATUS_EVENTLOG_CANT_START},
+ {ERRDOS, 1790, NT_STATUS_TRUST_FAILURE},
+ {ERRDOS, 1792, NT_STATUS_NETLOGON_NOT_STARTED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED},
+ {ERRDOS, 1131, NT_STATUS_POSSIBLE_DEADLOCK},
+ {ERRDOS, 1219, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+ {ERRDOS, 1220, NT_STATUS_REMOTE_SESSION_LIMIT},
+ {ERRDOS, 1503, NT_STATUS_EVENTLOG_FILE_CHANGED},
+ {ERRDOS, 1807, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+ {ERRDOS, 1808, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+ {ERRDOS, 1809, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+ {ERRDOS, 1810, NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+ {ERRDOS, 1394, NT_STATUS_NO_USER_SESSION_KEY},
+ {ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED},
+ {ERRDOS, 1815, NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+ {ERRDOS, 1130, NT_STATUS_INSUFF_SERVER_RESOURCES},
+ {ERRDOS, 1784, NT_STATUS_INVALID_BUFFER_SIZE},
+ {ERRDOS, 1214, NT_STATUS_INVALID_ADDRESS_COMPONENT},
+ {ERRDOS, 1214, NT_STATUS_INVALID_ADDRESS_WILDCARD},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES},
+ {ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS},
+ {ERRSRV, ERRinvnid, NT_STATUS_ADDRESS_CLOSED},
+ {ERRSRV, ERRinvnid, NT_STATUS_CONNECTION_DISCONNECTED},
+ {ERRSRV, ERRinvnid, NT_STATUS_CONNECTION_RESET},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NODES},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION},
+ {ERRDOS, 6118, NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+ {ERRDOS, 1132, NT_STATUS_MAPPED_ALIGNMENT},
+ {ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {ERRDOS, 1168, NT_STATUS_NOT_FOUND},
+ {ERRDOS, 554, NT_STATUS_DUPLICATE_OBJECTID},
+ {ERRDOS, 555, NT_STATUS_OBJECTID_EXISTS},
+ {ERRDOS, 1237, NT_STATUS_RETRY},
+ {ERRDOS, 1170, NT_STATUS_PROPSET_NOT_FOUND},
+ {ERRDOS, 1908, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE},
+ {ERRDOS, 1225, NT_STATUS_CONNECTION_REFUSED},
+ {ERRDOS, 1226, NT_STATUS_GRACEFUL_DISCONNECT},
+ {ERRDOS, 1227, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+ {ERRDOS, 1228, NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+ {ERRDOS, 1229, NT_STATUS_CONNECTION_INVALID},
+ {ERRDOS, 1230, NT_STATUS_CONNECTION_ACTIVE},
+ {ERRDOS, 1231, NT_STATUS_NETWORK_UNREACHABLE},
+ {ERRDOS, 1232, NT_STATUS_HOST_UNREACHABLE},
+ {ERRDOS, 1233, NT_STATUS_PROTOCOL_UNREACHABLE},
+ {ERRDOS, 1234, NT_STATUS_PORT_UNREACHABLE},
+ {ERRDOS, 1235, NT_STATUS_REQUEST_ABORTED},
+ {ERRDOS, 1236, NT_STATUS_CONNECTION_ABORTED},
+ {ERRDOS, 1224, NT_STATUS_USER_MAPPED_FILE},
+ {ERRDOS, 1238, NT_STATUS_CONNECTION_COUNT_LIMIT},
+ {ERRDOS, 1239, NT_STATUS_LOGIN_TIME_RESTRICTION},
+ {ERRDOS, 1240, NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+ {ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH},
+ {ERRDOS, 1359, NT_STATUS_LPC_REPLY_LOST},
+ {ERRDOS, 1232, NT_STATUS_PATH_NOT_COVERED},
+ {ERRDOS, 1395, NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+ {ERRDOS, 1058, NT_STATUS_PLUGPLAY_NO_DEVICE},
+ {ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+ {ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED},
+ {ERRDOS, 1142, NT_STATUS_TOO_MANY_LINKS},
+ {ERRDOS, 4350, NT_STATUS_FILE_IS_OFFLINE},
+ {ERRDOS, 2001, NT_STATUS(0xc000026c)},
+ {ERRDOS, 1201, NT_STATUS(0xc000026d)},
+ {ERRDOS, 21, NT_STATUS(0xc000026e)},
+ {ERRDOS, 1169, NT_STATUS(0xc0000272)},
+ {ERRDOS, 4390, NT_STATUS(0xc0000275)},
+ {ERRDOS, 4393, NT_STATUS(0xc0000276)},
+ {ERRDOS, 4394, NT_STATUS(0xc0000277)},
+ {ERRDOS, 4392, NT_STATUS(0xc0000278)},
+ {ERRDOS, 1920, NT_STATUS(0xc0000279)},
+ {ERRDOS, 1921, NT_STATUS(0xc0000280)},
+ {ERRDOS, 161, NT_STATUS(0xc0000281)},
+ {ERRDOS, 1160, NT_STATUS(0xc0000283)},
+ {ERRDOS, 1161, NT_STATUS(0xc0000284)},
+ {ERRDOS, 1162, NT_STATUS(0xc0000285)},
+ {ERRDOS, 1163, NT_STATUS(0xc0000286)},
+ {ERRDOS, 1164, NT_STATUS(0xc0000287)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc000028a)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc000028b)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc000028d)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc000028e)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc000028f)},
+ {ERRDOS, ERRbadaccess, NT_STATUS(0xc0000290)},
+ {ERRDOS, 6007, NT_STATUS(0xc0000291)},
+ {ERRDOS, 6008, NT_STATUS(0xc0000292)},
+ {ERRDOS, 6002, NT_STATUS(0xc0000293)},
+ {ERRDOS, 4200, NT_STATUS(0xc0000295)},
+ {ERRDOS, 4201, NT_STATUS(0xc0000296)},
+ {ERRDOS, 4202, NT_STATUS(0xc0000297)},
+ {ERRDOS, 4203, NT_STATUS(0xc0000298)},
+ {ERRDOS, 8218, NT_STATUS(0xc0000299)},
+ {ERRDOS, 8219, NT_STATUS(0xc000029a)},
+ {ERRDOS, 8220, NT_STATUS(0xc000029b)},
+ {ERRSRV, ERRsmbcmd, NT_STATUS(0xc000029c)},
+ {ERRDOS, 4351, NT_STATUS(0xc000029d)},
+ {ERRDOS, 4352, NT_STATUS(0xc000029e)},
+ {ERRDOS, 1172, NT_STATUS(0xc000029f)},
+ {ERRDOS, 8202, NT_STATUS(0xc00002a1)},
+ {ERRDOS, 8203, NT_STATUS(0xc00002a2)},
+ {ERRDOS, 8204, NT_STATUS(0xc00002a3)},
+ {ERRDOS, 8205, NT_STATUS(0xc00002a4)},
+ {ERRDOS, 8206, NT_STATUS(0xc00002a5)},
+ {ERRDOS, 8207, NT_STATUS(0xc00002a6)},
+ {ERRDOS, 8208, NT_STATUS(0xc00002a7)},
+ {ERRDOS, 8209, NT_STATUS(0xc00002a8)},
+ {ERRDOS, 8210, NT_STATUS(0xc00002a9)},
+ {ERRDOS, 8211, NT_STATUS(0xc00002aa)},
+ {ERRDOS, 8212, NT_STATUS(0xc00002ab)},
+ {ERRDOS, 8213, NT_STATUS(0xc00002ac)},
+ {ERRDOS, 8214, NT_STATUS(0xc00002ad)},
+ {ERRDOS, 8215, NT_STATUS(0xc00002ae)},
+ {ERRDOS, 8216, NT_STATUS(0xc00002af)},
+ {ERRDOS, 8217, NT_STATUS(0xc00002b0)},
+ {ERRDOS, 8478, NT_STATUS(0xc00002b1)},
+ {ERRDOS, 4391, NT_STATUS(0xc00002b2)},
+ {ERRDOS, 1617, NT_STATUS(0xc00002b6)},
+ {ERRDOS, 1178, NT_STATUS(0xc00002b7)},
+ {ERRDOS, 1179, NT_STATUS(0xc00002b8)},
+ {ERRDOS, 8228, NT_STATUS(0xc00002c1)},
+ {ERRDOS, 1397, NT_STATUS(0xc00002c3)},
+ {ERRDOS, 998, NT_STATUS(0xc00002c5)},
+ {ERRDOS, 4213, NT_STATUS(0xc00002c6)},
+ {ERRDOS, 4214, NT_STATUS(0xc00002c7)},
+ {ERRDOS, 4328, NT_STATUS(0xc00002ca)},
+ {ERRDOS, 8504, NT_STATUS(0xc00002cb)},
+ {ERRDOS, 1251, NT_STATUS(0xc00002cc)},
+ {ERRDOS, 8505, NT_STATUS(0xc00002cd)},
+ {ERRDOS, 1181, NT_STATUS(0xc00002cf)},
+ {ERRDOS, 8506, NT_STATUS(0xc00002d0)},
+ {ERRDOS, 8513, NT_STATUS(0xc00002d4)},
+ {ERRDOS, 8514, NT_STATUS(0xc00002d5)},
+ {ERRDOS, 8515, NT_STATUS(0xc00002d6)},
+ {ERRDOS, 8516, NT_STATUS(0xc00002d7)},
+ {ERRDOS, 8517, NT_STATUS(0xc00002d8)},
+ {ERRDOS, 8518, NT_STATUS(0xc00002d9)},
+ {ERRDOS, 8519, NT_STATUS(0xc00002da)},
+ {ERRDOS, 8520, NT_STATUS(0xc00002db)},
+ {ERRDOS, 8521, NT_STATUS(0xc00002dc)},
+ {ERRDOS, ERRunsup, NT_STATUS(0xc00002dd)},
+ {ERRDOS, 8529, NT_STATUS(0xc00002df)},
+ {ERRDOS, 8530, NT_STATUS(0xc00002e0)},
+ {ERRDOS, 8531, NT_STATUS(0xc00002e1)},
+ {ERRDOS, 8532, NT_STATUS(0xc00002e2)},
+ {ERRDOS, 8541, NT_STATUS(0xc00002e3)},
+ {ERRDOS, 8547, NT_STATUS(0xc00002e4)},
+ {ERRDOS, 8548, NT_STATUS(0xc00002e5)},
+ {ERRDOS, 8549, NT_STATUS(0xc00002e6)},
+ {ERRDOS, 8557, NT_STATUS(0xc00002e7)},
+ {ERRDOS, 1115, NT_STATUS(0xc00002fe)},
+ {ERRDOS, 1255, NT_STATUS(0xc00002ff)},
+ {ERRDOS, 1254, NT_STATUS(0xc0000300)},
+ {ERRDOS, ERRbadfunc, NT_STATUS(0x80000001)},
+ {ERRDOS, 998, NT_STATUS(0x80000002)},
+ {ERRDOS, ERRbadpath, NT_STATUS(0x80000003)},
+ {ERRDOS, ERRnofids, NT_STATUS(0x80000004)},
+ {ERRDOS, 234, NT_STATUS(0x80000005)},
+ {ERRDOS, ERRnofiles, NT_STATUS(0x80000006)},
+ {ERRDOS, 1391, NT_STATUS(0x8000000b)},
+ {ERRDOS, 299, NT_STATUS(0x8000000d)},
+ {ERRDOS, 28, NT_STATUS(0x8000000e)},
+ {ERRDOS, 21, NT_STATUS(0x8000000f)},
+ {ERRDOS, 21, NT_STATUS(0x80000010)},
+ {ERRDOS, 170, NT_STATUS(0x80000011)},
+ {ERRDOS, 259, NT_STATUS(0x80000012)},
+ {ERRDOS, 254, NT_STATUS(0x80000013)},
+ {ERRDOS, 275, NT_STATUS(0x80000014)},
+ {ERRDOS, 275, NT_STATUS(0x80000015)},
+ {ERRDOS, 1110, NT_STATUS(0x80000016)},
+ {ERRDOS, 259, NT_STATUS_UNABLE_TO_FREE_VM},
+ {ERRDOS, 1101, NT_STATUS(0x8000001b)},
+ {ERRDOS, 1110, NT_STATUS(0x8000001c)},
+ {ERRDOS, 1111, NT_STATUS(0x8000001d)},
+ {ERRDOS, 1100, NT_STATUS(0x8000001e)},
+ {ERRDOS, 1102, NT_STATUS(0x8000001f)},
+ {ERRDOS, 1103, NT_STATUS(0x80000021)},
+ {ERRDOS, 1104, NT_STATUS(0x80000022)},
+ {ERRDOS, 2402, NT_STATUS(0x80000025)},
+ {ERRDOS, 1165, NT_STATUS(0x80000288)},
+ {ERRDOS, 1166, NT_STATUS(0x80000289)},
+};
+
+
+/* dos -> nt status error map */
+static struct {
+ uint8 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} dos_to_ntstatus_map[] = {
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRbaddata, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, ERRremcd, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnofiles, NT_STATUS(0x80000006)},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 24, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 26, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRDOS, 28, NT_STATUS(0x8000000e)},
+ {ERRDOS, 31, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRDOS, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRDOS, 111, STATUS_MORE_ENTRIES},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, 170, NT_STATUS(0x80000011)},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRmoredata, STATUS_MORE_ENTRIES},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRDOS, 254, NT_STATUS(0x80000013)},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRDOS, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 299, NT_STATUS(0x8000000d)},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRDOS, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRDOS, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, 995, NT_STATUS_CANCELLED},
+ {ERRDOS, 997, NT_STATUS(0x00000103)},
+ {ERRDOS, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRDOS, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRDOS, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRDOS, 1006, NT_STATUS_FILE_INVALID},
+ {ERRDOS, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRDOS, 1008, NT_STATUS_NO_TOKEN},
+ {ERRDOS, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRDOS, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRDOS, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRDOS, 1018, NT_STATUS_KEY_DELETED},
+ {ERRDOS, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRDOS, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRDOS, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 1022, NT_STATUS(0x0000010c)},
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRSRV, ERRbadtype, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRaccess, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRinvnid, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRSRV, ERRinvnetname, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRqfull, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRSRV, ERRqtoobig, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRSRV, ERRinvpfid, NT_STATUS_PRINT_CANCELLED},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRSRV, ERRbadpermits, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRpaused, NT_STATUS_SHARING_PAUSED},
+ {ERRSRV, ERRmsgoff, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRnoroom, NT_STATUS_DISK_FULL},
+ {ERRSRV, ERRnoresource, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRtoomanyuids, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRSRV, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRSRV, 206, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 1, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRHRD, 2, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRHRD, 3, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRHRD, 4, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, 5, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 6, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, 8, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRHRD, 12, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 13, NT_STATUS_DATA_ERROR},
+ {ERRHRD, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRHRD, 16, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 17, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRHRD, 18, NT_STATUS(0x80000006)},
+ {ERRHRD, ERRnowrite, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRHRD, ERRnotready, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRbadcmd, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRdata, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadreq, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadmedia, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRHRD, ERRbadsector, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRHRD, ERRnopaper, NT_STATUS(0x8000000e)},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRHRD, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRHRD, ERRwrongdisk, NT_STATUS_WRONG_VOLUME},
+ {ERRHRD, 38, NT_STATUS_END_OF_FILE},
+ {ERRHRD, 50, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRHRD, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRHRD, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRHRD, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRHRD, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRHRD, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRHRD, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRHRD, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRHRD, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRHRD, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRHRD, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRHRD, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRHRD, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRHRD, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRHRD, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRHRD, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRHRD, 67, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRHRD, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRHRD, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRHRD, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRHRD, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRHRD, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRHRD, 80, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRHRD, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, 111, STATUS_MORE_ENTRIES},
+ {ERRHRD, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRHRD, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRHRD, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRHRD, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRHRD, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRHRD, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRHRD, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRHRD, 170, NT_STATUS(0x80000011)},
+ {ERRHRD, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRHRD, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRHRD, 203, NT_STATUS(0xc0000100)},
+ {ERRHRD, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRHRD, 230, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 231, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRHRD, 232, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, 233, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRHRD, 234, STATUS_MORE_ENTRIES},
+ {ERRHRD, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, 254, NT_STATUS(0x80000013)},
+ {ERRHRD, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRHRD, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRHRD, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRHRD, 299, NT_STATUS(0x8000000d)},
+ {ERRHRD, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRHRD, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRHRD, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRHRD, 995, NT_STATUS_CANCELLED},
+ {ERRHRD, 997, NT_STATUS(0x00000103)},
+ {ERRHRD, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRHRD, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, 1006, NT_STATUS_FILE_INVALID},
+ {ERRHRD, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, 1008, NT_STATUS_NO_TOKEN},
+ {ERRHRD, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, 1018, NT_STATUS_KEY_DELETED},
+ {ERRHRD, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRHRD, 1022, NT_STATUS(0x0000010c)},
+};
+
+/* errmap NTSTATUS->Win32 */
+static struct {
+ NTSTATUS ntstatus;
+ WERROR werror;
+} ntstatus_to_werror_map[] = {
+ {NT_STATUS(0x103), W_ERROR(0x3e5)},
+ {NT_STATUS(0x105), W_ERROR(0xea)},
+ {NT_STATUS(0x106), W_ERROR(0x514)},
+ {NT_STATUS(0x107), W_ERROR(0x515)},
+ {NT_STATUS(0x10c), W_ERROR(0x3fe)},
+ {NT_STATUS(0x10d), W_ERROR(0x516)},
+ {NT_STATUS(0x121), W_ERROR(0x2009)},
+ {NT_STATUS(0xc0000001), W_ERROR(0x1f)},
+ {NT_STATUS(0xc0000002), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000003), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000004), W_ERROR(0x18)},
+ {NT_STATUS(0xc0000005), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc0000006), W_ERROR(0x3e7)},
+ {NT_STATUS(0xc0000007), W_ERROR(0x5ae)},
+ {NT_STATUS(0xc0000008), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000009), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc000000a), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000000b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000e), W_ERROR(0x2)},
+ {NT_STATUS(0xc000000f), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000010), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000011), W_ERROR(0x26)},
+ {NT_STATUS(0xc0000012), W_ERROR(0x22)},
+ {NT_STATUS(0xc0000013), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000014), W_ERROR(0x6f9)},
+ {NT_STATUS(0xc0000015), W_ERROR(0x1b)},
+ {NT_STATUS(0xc0000016), W_ERROR(0xea)},
+ {NT_STATUS(0xc0000017), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000018), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000019), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000001a), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000001d), W_ERROR(0xc000001d)},
+ {NT_STATUS(0xc000001e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000001f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000020), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000021), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000022), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000023), W_ERROR(0x7a)},
+ {NT_STATUS(0xc0000024), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000025), W_ERROR(0xc0000025)},
+ {NT_STATUS(0xc0000026), W_ERROR(0xc0000026)},
+ {NT_STATUS(0xc000002a), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000002b), W_ERROR(0xc000002b)},
+ {NT_STATUS(0xc000002c), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000002d), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000030), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000032), W_ERROR(0x571)},
+ {NT_STATUS(0xc0000033), W_ERROR(0x7b)},
+ {NT_STATUS(0xc0000034), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000035), W_ERROR(0xb7)},
+ {NT_STATUS(0xc0000037), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000039), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003a), W_ERROR(0x3)},
+ {NT_STATUS(0xc000003b), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003c), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003e), W_ERROR(0x17)},
+ {NT_STATUS(0xc000003f), W_ERROR(0x17)},
+ {NT_STATUS(0xc0000040), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000041), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000042), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000043), W_ERROR(0x20)},
+ {NT_STATUS(0xc0000044), W_ERROR(0x718)},
+ {NT_STATUS(0xc0000045), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000046), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000047), W_ERROR(0x12a)},
+ {NT_STATUS(0xc0000048), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000049), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004a), W_ERROR(0x9c)},
+ {NT_STATUS(0xc000004b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000004c), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004e), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004f), W_ERROR(0x11a)},
+ {NT_STATUS(0xc0000050), W_ERROR(0xff)},
+ {NT_STATUS(0xc0000051), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000052), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000053), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000054), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000055), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000056), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000057), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000058), W_ERROR(0x519)},
+ {NT_STATUS(0xc0000059), W_ERROR(0x51a)},
+ {NT_STATUS(0xc000005a), W_ERROR(0x51b)},
+ {NT_STATUS(0xc000005b), W_ERROR(0x51c)},
+ {NT_STATUS(0xc000005c), W_ERROR(0x51d)},
+ {NT_STATUS(0xc000005d), W_ERROR(0x51e)},
+ {NT_STATUS(0xc000005e), W_ERROR(0x51f)},
+ {NT_STATUS(0xc000005f), W_ERROR(0x520)},
+ {NT_STATUS(0xc0000060), W_ERROR(0x521)},
+ {NT_STATUS(0xc0000061), W_ERROR(0x522)},
+ {NT_STATUS(0xc0000062), W_ERROR(0x523)},
+ {NT_STATUS(0xc0000063), W_ERROR(0x524)},
+ {NT_STATUS(0xc0000064), W_ERROR(0x525)},
+ {NT_STATUS(0xc0000065), W_ERROR(0x526)},
+ {NT_STATUS(0xc0000066), W_ERROR(0x527)},
+ {NT_STATUS(0xc0000067), W_ERROR(0x528)},
+ {NT_STATUS(0xc0000068), W_ERROR(0x529)},
+ {NT_STATUS(0xc0000069), W_ERROR(0x52a)},
+ {NT_STATUS(0xc000006a), W_ERROR(0x56)},
+ {NT_STATUS(0xc000006b), W_ERROR(0x52c)},
+ {NT_STATUS(0xc000006c), W_ERROR(0x52d)},
+ {NT_STATUS(0xc000006d), W_ERROR(0x52e)},
+ {NT_STATUS(0xc000006e), W_ERROR(0x52f)},
+ {NT_STATUS(0xc000006f), W_ERROR(0x530)},
+ {NT_STATUS(0xc0000070), W_ERROR(0x531)},
+ {NT_STATUS(0xc0000071), W_ERROR(0x532)},
+ {NT_STATUS(0xc0000072), W_ERROR(0x533)},
+ {NT_STATUS(0xc0000073), W_ERROR(0x534)},
+ {NT_STATUS(0xc0000074), W_ERROR(0x535)},
+ {NT_STATUS(0xc0000075), W_ERROR(0x536)},
+ {NT_STATUS(0xc0000076), W_ERROR(0x537)},
+ {NT_STATUS(0xc0000077), W_ERROR(0x538)},
+ {NT_STATUS(0xc0000078), W_ERROR(0x539)},
+ {NT_STATUS(0xc0000079), W_ERROR(0x53a)},
+ {NT_STATUS(0xc000007a), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000007b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000007c), W_ERROR(0x3f0)},
+ {NT_STATUS(0xc000007d), W_ERROR(0x53c)},
+ {NT_STATUS(0xc000007e), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000007f), W_ERROR(0x70)},
+ {NT_STATUS(0xc0000080), W_ERROR(0x53d)},
+ {NT_STATUS(0xc0000081), W_ERROR(0x53e)},
+ {NT_STATUS(0xc0000082), W_ERROR(0x44)},
+ {NT_STATUS(0xc0000083), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000084), W_ERROR(0x53f)},
+ {NT_STATUS(0xc0000085), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000086), W_ERROR(0x9a)},
+ {NT_STATUS(0xc0000087), W_ERROR(0xe)},
+ {NT_STATUS(0xc0000088), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000089), W_ERROR(0x714)},
+ {NT_STATUS(0xc000008a), W_ERROR(0x715)},
+ {NT_STATUS(0xc000008b), W_ERROR(0x716)},
+ {NT_STATUS(0xc000008c), W_ERROR(0xc000008c)},
+ {NT_STATUS(0xc000008d), W_ERROR(0xc000008d)},
+ {NT_STATUS(0xc000008e), W_ERROR(0xc000008e)},
+ {NT_STATUS(0xc000008f), W_ERROR(0xc000008f)},
+ {NT_STATUS(0xc0000090), W_ERROR(0xc0000090)},
+ {NT_STATUS(0xc0000091), W_ERROR(0xc0000091)},
+ {NT_STATUS(0xc0000092), W_ERROR(0xc0000092)},
+ {NT_STATUS(0xc0000093), W_ERROR(0xc0000093)},
+ {NT_STATUS(0xc0000094), W_ERROR(0xc0000094)},
+ {NT_STATUS(0xc0000095), W_ERROR(0x216)},
+ {NT_STATUS(0xc0000096), W_ERROR(0xc0000096)},
+ {NT_STATUS(0xc0000097), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000098), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc0000099), W_ERROR(0x540)},
+ {NT_STATUS(0xc000009a), W_ERROR(0x5aa)},
+ {NT_STATUS(0xc000009b), W_ERROR(0x3)},
+ {NT_STATUS(0xc000009c), W_ERROR(0x17)},
+ {NT_STATUS(0xc000009d), W_ERROR(0x48f)},
+ {NT_STATUS(0xc000009e), W_ERROR(0x15)},
+ {NT_STATUS(0xc000009f), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a0), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a1), W_ERROR(0x5ad)},
+ {NT_STATUS(0xc00000a2), W_ERROR(0x13)},
+ {NT_STATUS(0xc00000a3), W_ERROR(0x15)},
+ {NT_STATUS(0xc00000a4), W_ERROR(0x541)},
+ {NT_STATUS(0xc00000a5), W_ERROR(0x542)},
+ {NT_STATUS(0xc00000a6), W_ERROR(0x543)},
+ {NT_STATUS(0xc00000a7), W_ERROR(0x544)},
+ {NT_STATUS(0xc00000a8), W_ERROR(0x545)},
+ {NT_STATUS(0xc00000a9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000ab), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ac), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ad), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000ae), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000af), W_ERROR(0x1)},
+ {NT_STATUS(0xc00000b0), W_ERROR(0xe9)},
+ {NT_STATUS(0xc00000b1), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000b2), W_ERROR(0x217)},
+ {NT_STATUS(0xc00000b3), W_ERROR(0x218)},
+ {NT_STATUS(0xc00000b4), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000b5), W_ERROR(0x79)},
+ {NT_STATUS(0xc00000b6), W_ERROR(0x26)},
+ {NT_STATUS(0xc00000ba), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000bb), W_ERROR(0x32)},
+ {NT_STATUS(0xc00000bc), W_ERROR(0x33)},
+ {NT_STATUS(0xc00000bd), W_ERROR(0x34)},
+ {NT_STATUS(0xc00000be), W_ERROR(0x35)},
+ {NT_STATUS(0xc00000bf), W_ERROR(0x36)},
+ {NT_STATUS(0xc00000c0), W_ERROR(0x37)},
+ {NT_STATUS(0xc00000c1), W_ERROR(0x38)},
+ {NT_STATUS(0xc00000c2), W_ERROR(0x39)},
+ {NT_STATUS(0xc00000c3), W_ERROR(0x3a)},
+ {NT_STATUS(0xc00000c4), W_ERROR(0x3b)},
+ {NT_STATUS(0xc00000c5), W_ERROR(0x3c)},
+ {NT_STATUS(0xc00000c6), W_ERROR(0x3d)},
+ {NT_STATUS(0xc00000c7), W_ERROR(0x3e)},
+ {NT_STATUS(0xc00000c8), W_ERROR(0x3f)},
+ {NT_STATUS(0xc00000c9), W_ERROR(0x40)},
+ {NT_STATUS(0xc00000ca), W_ERROR(0x41)},
+ {NT_STATUS(0xc00000cb), W_ERROR(0x42)},
+ {NT_STATUS(0xc00000cc), W_ERROR(0x43)},
+ {NT_STATUS(0xc00000cd), W_ERROR(0x44)},
+ {NT_STATUS(0xc00000ce), W_ERROR(0x45)},
+ {NT_STATUS(0xc00000cf), W_ERROR(0x46)},
+ {NT_STATUS(0xc00000d0), W_ERROR(0x47)},
+ {NT_STATUS(0xc00000d1), W_ERROR(0x48)},
+ {NT_STATUS(0xc00000d2), W_ERROR(0x58)},
+ {NT_STATUS(0xc00000d4), W_ERROR(0x11)},
+ {NT_STATUS(0xc00000d5), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000d6), W_ERROR(0xf0)},
+ {NT_STATUS(0xc00000d7), W_ERROR(0x546)},
+ {NT_STATUS(0xc00000d9), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000da), W_ERROR(0x547)},
+ {NT_STATUS(0xc00000dc), W_ERROR(0x548)},
+ {NT_STATUS(0xc00000dd), W_ERROR(0x549)},
+ {NT_STATUS(0xc00000de), W_ERROR(0x54a)},
+ {NT_STATUS(0xc00000df), W_ERROR(0x54b)},
+ {NT_STATUS(0xc00000e0), W_ERROR(0x54c)},
+ {NT_STATUS(0xc00000e1), W_ERROR(0x54d)},
+ {NT_STATUS(0xc00000e2), W_ERROR(0x12c)},
+ {NT_STATUS(0xc00000e3), W_ERROR(0x12d)},
+ {NT_STATUS(0xc00000e4), W_ERROR(0x54e)},
+ {NT_STATUS(0xc00000e5), W_ERROR(0x54f)},
+ {NT_STATUS(0xc00000e6), W_ERROR(0x550)},
+ {NT_STATUS(0xc00000e7), W_ERROR(0x551)},
+ {NT_STATUS(0xc00000e8), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc00000ed), W_ERROR(0x552)},
+ {NT_STATUS(0xc00000ee), W_ERROR(0x553)},
+ {NT_STATUS(0xc00000ef), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f0), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f1), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f2), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f3), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f4), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f5), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f6), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f7), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f8), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fa), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fb), W_ERROR(0x3)},
+ {NT_STATUS(0xc00000fd), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc00000fe), W_ERROR(0x554)},
+ {NT_STATUS(0xc0000100), W_ERROR(0xcb)},
+ {NT_STATUS(0xc0000101), W_ERROR(0x91)},
+ {NT_STATUS(0xc0000102), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000103), W_ERROR(0x10b)},
+ {NT_STATUS(0xc0000104), W_ERROR(0x555)},
+ {NT_STATUS(0xc0000105), W_ERROR(0x556)},
+ {NT_STATUS(0xc0000106), W_ERROR(0xce)},
+ {NT_STATUS(0xc0000107), W_ERROR(0x961)},
+ {NT_STATUS(0xc0000108), W_ERROR(0x964)},
+ {NT_STATUS(0xc000010a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000010b), W_ERROR(0x557)},
+ {NT_STATUS(0xc000010d), W_ERROR(0x558)},
+ {NT_STATUS(0xc000010e), W_ERROR(0x420)},
+ {NT_STATUS(0xc0000117), W_ERROR(0x5a4)},
+ {NT_STATUS(0xc000011b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000011c), W_ERROR(0x559)},
+ {NT_STATUS(0xc000011d), W_ERROR(0x55a)},
+ {NT_STATUS(0xc000011e), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc000011f), W_ERROR(0x4)},
+ {NT_STATUS(0xc0000120), W_ERROR(0x3e3)},
+ {NT_STATUS(0xc0000121), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000122), W_ERROR(0x4ba)},
+ {NT_STATUS(0xc0000123), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000124), W_ERROR(0x55b)},
+ {NT_STATUS(0xc0000125), W_ERROR(0x55c)},
+ {NT_STATUS(0xc0000126), W_ERROR(0x55d)},
+ {NT_STATUS(0xc0000127), W_ERROR(0x55e)},
+ {NT_STATUS(0xc0000128), W_ERROR(0x6)},
+ {NT_STATUS(0xc000012b), W_ERROR(0x55f)},
+ {NT_STATUS(0xc000012d), W_ERROR(0x5af)},
+ {NT_STATUS(0xc000012e), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000012f), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000130), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000131), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000133), W_ERROR(0x576)},
+ {NT_STATUS(0xc0000135), W_ERROR(0x7e)},
+ {NT_STATUS(0xc0000138), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000139), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000013b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013d), W_ERROR(0x33)},
+ {NT_STATUS(0xc000013e), W_ERROR(0x3b)},
+ {NT_STATUS(0xc000013f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000140), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000141), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000142), W_ERROR(0x45a)},
+ {NT_STATUS(0xc0000148), W_ERROR(0x7c)},
+ {NT_STATUS(0xc0000149), W_ERROR(0x56)},
+ {NT_STATUS(0xc000014b), W_ERROR(0x6d)},
+ {NT_STATUS(0xc000014c), W_ERROR(0x3f1)},
+ {NT_STATUS(0xc000014d), W_ERROR(0x3f8)},
+ {NT_STATUS(0xc000014f), W_ERROR(0x3ed)},
+ {NT_STATUS(0xc0000150), W_ERROR(0x45e)},
+ {NT_STATUS(0xc0000151), W_ERROR(0x560)},
+ {NT_STATUS(0xc0000152), W_ERROR(0x561)},
+ {NT_STATUS(0xc0000153), W_ERROR(0x562)},
+ {NT_STATUS(0xc0000154), W_ERROR(0x563)},
+ {NT_STATUS(0xc0000155), W_ERROR(0x564)},
+ {NT_STATUS(0xc0000156), W_ERROR(0x565)},
+ {NT_STATUS(0xc0000157), W_ERROR(0x566)},
+ {NT_STATUS(0xc0000158), W_ERROR(0x567)},
+ {NT_STATUS(0xc0000159), W_ERROR(0x3ef)},
+ {NT_STATUS(0xc000015a), W_ERROR(0x568)},
+ {NT_STATUS(0xc000015b), W_ERROR(0x569)},
+ {NT_STATUS(0xc000015c), W_ERROR(0x3f9)},
+ {NT_STATUS(0xc000015d), W_ERROR(0x56a)},
+ {NT_STATUS(0xc000015f), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000162), W_ERROR(0x459)},
+ {NT_STATUS(0xc0000165), W_ERROR(0x462)},
+ {NT_STATUS(0xc0000166), W_ERROR(0x463)},
+ {NT_STATUS(0xc0000167), W_ERROR(0x464)},
+ {NT_STATUS(0xc0000168), W_ERROR(0x465)},
+ {NT_STATUS(0xc0000169), W_ERROR(0x466)},
+ {NT_STATUS(0xc000016a), W_ERROR(0x467)},
+ {NT_STATUS(0xc000016b), W_ERROR(0x468)},
+ {NT_STATUS(0xc000016c), W_ERROR(0x45f)},
+ {NT_STATUS(0xc000016d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000172), W_ERROR(0x451)},
+ {NT_STATUS(0xc0000173), W_ERROR(0x452)},
+ {NT_STATUS(0xc0000174), W_ERROR(0x453)},
+ {NT_STATUS(0xc0000175), W_ERROR(0x454)},
+ {NT_STATUS(0xc0000176), W_ERROR(0x455)},
+ {NT_STATUS(0xc0000177), W_ERROR(0x469)},
+ {NT_STATUS(0xc0000178), W_ERROR(0x458)},
+ {NT_STATUS(0xc000017a), W_ERROR(0x56b)},
+ {NT_STATUS(0xc000017b), W_ERROR(0x56c)},
+ {NT_STATUS(0xc000017c), W_ERROR(0x3fa)},
+ {NT_STATUS(0xc000017d), W_ERROR(0x3fb)},
+ {NT_STATUS(0xc000017e), W_ERROR(0x56d)},
+ {NT_STATUS(0xc000017f), W_ERROR(0x56e)},
+ {NT_STATUS(0xc0000180), W_ERROR(0x3fc)},
+ {NT_STATUS(0xc0000181), W_ERROR(0x3fd)},
+ {NT_STATUS(0xc0000182), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000183), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000184), W_ERROR(0x16)},
+ {NT_STATUS(0xc0000185), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000186), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000188), W_ERROR(0x5de)},
+ {NT_STATUS(0xc0000189), W_ERROR(0x13)},
+ {NT_STATUS(0xc000018a), W_ERROR(0x6fa)},
+ {NT_STATUS(0xc000018b), W_ERROR(0x6fb)},
+ {NT_STATUS(0xc000018c), W_ERROR(0x6fc)},
+ {NT_STATUS(0xc000018d), W_ERROR(0x6fd)},
+ {NT_STATUS(0xc000018e), W_ERROR(0x5dc)},
+ {NT_STATUS(0xc000018f), W_ERROR(0x5dd)},
+ {NT_STATUS(0xc0000190), W_ERROR(0x6fe)},
+ {NT_STATUS(0xc0000192), W_ERROR(0x700)},
+ {NT_STATUS(0xc0000193), W_ERROR(0x701)},
+ {NT_STATUS(0xc0000194), W_ERROR(0x46b)},
+ {NT_STATUS(0xc0000195), W_ERROR(0x4c3)},
+ {NT_STATUS(0xc0000196), W_ERROR(0x4c4)},
+ {NT_STATUS(0xc0000197), W_ERROR(0x5df)},
+ {NT_STATUS(0xc0000198), W_ERROR(0x70f)},
+ {NT_STATUS(0xc0000199), W_ERROR(0x710)},
+ {NT_STATUS(0xc000019a), W_ERROR(0x711)},
+ {NT_STATUS(0xc000019b), W_ERROR(0x712)},
+ {NT_STATUS(0xc0000202), W_ERROR(0x572)},
+ {NT_STATUS(0xc0000203), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000204), W_ERROR(0x717)},
+ {NT_STATUS(0xc0000205), W_ERROR(0x46a)},
+ {NT_STATUS(0xc0000206), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc0000207), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000208), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000209), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020a), W_ERROR(0x34)},
+ {NT_STATUS(0xc000020b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020d), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020e), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000210), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000211), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000212), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000213), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000214), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000215), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000216), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000217), W_ERROR(0x32)},
+ {NT_STATUS(0xc000021c), W_ERROR(0x17e6)},
+ {NT_STATUS(0xc0000220), W_ERROR(0x46c)},
+ {NT_STATUS(0xc0000221), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000224), W_ERROR(0x773)},
+ {NT_STATUS(0xc0000225), W_ERROR(0x490)},
+ {NT_STATUS(0xc000022a), W_ERROR(0xc000022a)},
+ {NT_STATUS(0xc000022b), W_ERROR(0xc000022b)},
+ {NT_STATUS(0xc000022d), W_ERROR(0x4d5)},
+ {NT_STATUS(0xc0000230), W_ERROR(0x492)},
+ {NT_STATUS(0xc0000233), W_ERROR(0x774)},
+ {NT_STATUS(0xc0000234), W_ERROR(0x775)},
+ {NT_STATUS(0xc0000235), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000236), W_ERROR(0x4c9)},
+ {NT_STATUS(0xc0000237), W_ERROR(0x4ca)},
+ {NT_STATUS(0xc0000238), W_ERROR(0x4cb)},
+ {NT_STATUS(0xc0000239), W_ERROR(0x4cc)},
+ {NT_STATUS(0xc000023a), W_ERROR(0x4cd)},
+ {NT_STATUS(0xc000023b), W_ERROR(0x4ce)},
+ {NT_STATUS(0xc000023c), W_ERROR(0x4cf)},
+ {NT_STATUS(0xc000023d), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc000023e), W_ERROR(0x4d1)},
+ {NT_STATUS(0xc000023f), W_ERROR(0x4d2)},
+ {NT_STATUS(0xc0000240), W_ERROR(0x4d3)},
+ {NT_STATUS(0xc0000241), W_ERROR(0x4d4)},
+ {NT_STATUS(0xc0000243), W_ERROR(0x4c8)},
+ {NT_STATUS(0xc0000246), W_ERROR(0x4d6)},
+ {NT_STATUS(0xc0000247), W_ERROR(0x4d7)},
+ {NT_STATUS(0xc0000248), W_ERROR(0x4d8)},
+ {NT_STATUS(0xc0000249), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000253), W_ERROR(0x54f)},
+ {NT_STATUS(0xc0000257), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc0000259), W_ERROR(0x573)},
+ {NT_STATUS(0xc000025e), W_ERROR(0x422)},
+ {NT_STATUS(0xc0000262), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000263), W_ERROR(0x7f)},
+ {NT_STATUS(0xc0000264), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000265), W_ERROR(0x476)},
+ {NT_STATUS(0xc0000267), W_ERROR(0x10fe)},
+ {NT_STATUS(0xc000026c), W_ERROR(0x7d1)},
+ {NT_STATUS(0xc000026d), W_ERROR(0x4b1)},
+ {NT_STATUS(0xc000026e), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000272), W_ERROR(0x491)},
+ {NT_STATUS(0xc0000275), W_ERROR(0x1126)},
+ {NT_STATUS(0xc0000276), W_ERROR(0x1129)},
+ {NT_STATUS(0xc0000277), W_ERROR(0x112a)},
+ {NT_STATUS(0xc0000278), W_ERROR(0x1128)},
+ {NT_STATUS(0xc0000279), W_ERROR(0x780)},
+ {NT_STATUS(0xc0000280), W_ERROR(0x781)},
+ {NT_STATUS(0xc0000281), W_ERROR(0xa1)},
+ {NT_STATUS(0xc0000283), W_ERROR(0x488)},
+ {NT_STATUS(0xc0000284), W_ERROR(0x489)},
+ {NT_STATUS(0xc0000285), W_ERROR(0x48a)},
+ {NT_STATUS(0xc0000286), W_ERROR(0x48b)},
+ {NT_STATUS(0xc0000287), W_ERROR(0x48c)},
+ {NT_STATUS(0xc000028a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028d), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000290), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000291), W_ERROR(0x1777)},
+ {NT_STATUS(0xc0000292), W_ERROR(0x1778)},
+ {NT_STATUS(0xc0000293), W_ERROR(0x1772)},
+ {NT_STATUS(0xc0000295), W_ERROR(0x1068)},
+ {NT_STATUS(0xc0000296), W_ERROR(0x1069)},
+ {NT_STATUS(0xc0000297), W_ERROR(0x106a)},
+ {NT_STATUS(0xc0000298), W_ERROR(0x106b)},
+ {NT_STATUS(0xc0000299), W_ERROR(0x201a)},
+ {NT_STATUS(0xc000029a), W_ERROR(0x201b)},
+ {NT_STATUS(0xc000029b), W_ERROR(0x201c)},
+ {NT_STATUS(0xc000029c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000029d), W_ERROR(0x10ff)},
+ {NT_STATUS(0xc000029e), W_ERROR(0x1100)},
+ {NT_STATUS(0xc000029f), W_ERROR(0x494)},
+ {NT_STATUS(0xc00002a1), W_ERROR(0x200a)},
+ {NT_STATUS(0xc00002a2), W_ERROR(0x200b)},
+ {NT_STATUS(0xc00002a3), W_ERROR(0x200c)},
+ {NT_STATUS(0xc00002a4), W_ERROR(0x200d)},
+ {NT_STATUS(0xc00002a5), W_ERROR(0x200e)},
+ {NT_STATUS(0xc00002a6), W_ERROR(0x200f)},
+ {NT_STATUS(0xc00002a7), W_ERROR(0x2010)},
+ {NT_STATUS(0xc00002a8), W_ERROR(0x2011)},
+ {NT_STATUS(0xc00002a9), W_ERROR(0x2012)},
+ {NT_STATUS(0xc00002aa), W_ERROR(0x2013)},
+ {NT_STATUS(0xc00002ab), W_ERROR(0x2014)},
+ {NT_STATUS(0xc00002ac), W_ERROR(0x2015)},
+ {NT_STATUS(0xc00002ad), W_ERROR(0x2016)},
+ {NT_STATUS(0xc00002ae), W_ERROR(0x2017)},
+ {NT_STATUS(0xc00002af), W_ERROR(0x2018)},
+ {NT_STATUS(0xc00002b0), W_ERROR(0x2019)},
+ {NT_STATUS(0xc00002b1), W_ERROR(0x211e)},
+ {NT_STATUS(0xc00002b2), W_ERROR(0x1127)},
+ {NT_STATUS(0xc00002b6), W_ERROR(0x651)},
+ {NT_STATUS(0xc00002b7), W_ERROR(0x49a)},
+ {NT_STATUS(0xc00002b8), W_ERROR(0x49b)},
+ {NT_STATUS(0xc00002c1), W_ERROR(0x2024)},
+ {NT_STATUS(0xc00002c3), W_ERROR(0x575)},
+ {NT_STATUS(0xc00002c5), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc00002c6), W_ERROR(0x1075)},
+ {NT_STATUS(0xc00002c7), W_ERROR(0x1076)},
+ {NT_STATUS(0xc00002ca), W_ERROR(0x10e8)},
+ {NT_STATUS(0xc00002cb), W_ERROR(0x2138)},
+ {NT_STATUS(0xc00002cc), W_ERROR(0x4e3)},
+ {NT_STATUS(0xc00002cd), W_ERROR(0x2139)},
+ {NT_STATUS(0xc00002cf), W_ERROR(0x49d)},
+ {NT_STATUS(0xc00002d0), W_ERROR(0x213a)},
+ {NT_STATUS(0xc00002d4), W_ERROR(0x2141)},
+ {NT_STATUS(0xc00002d5), W_ERROR(0x2142)},
+ {NT_STATUS(0xc00002d6), W_ERROR(0x2143)},
+ {NT_STATUS(0xc00002d7), W_ERROR(0x2144)},
+ {NT_STATUS(0xc00002d8), W_ERROR(0x2145)},
+ {NT_STATUS(0xc00002d9), W_ERROR(0x2146)},
+ {NT_STATUS(0xc00002da), W_ERROR(0x2147)},
+ {NT_STATUS(0xc00002db), W_ERROR(0x2148)},
+ {NT_STATUS(0xc00002dc), W_ERROR(0x2149)},
+ {NT_STATUS(0xc00002dd), W_ERROR(0x32)},
+ {NT_STATUS(0xc00002df), W_ERROR(0x2151)},
+ {NT_STATUS(0xc00002e0), W_ERROR(0x2152)},
+ {NT_STATUS(0xc00002e1), W_ERROR(0x2153)},
+ {NT_STATUS(0xc00002e2), W_ERROR(0x2154)},
+ {NT_STATUS(0xc00002e3), W_ERROR(0x215d)},
+ {NT_STATUS(0xc00002e4), W_ERROR(0x2163)},
+ {NT_STATUS(0xc00002e5), W_ERROR(0x2164)},
+ {NT_STATUS(0xc00002e6), W_ERROR(0x2165)},
+ {NT_STATUS(0xc00002e7), W_ERROR(0x216d)},
+ {NT_STATUS(0xc00002fe), W_ERROR(0x45b)},
+ {NT_STATUS(0xc00002ff), W_ERROR(0x4e7)},
+ {NT_STATUS(0xc0000300), W_ERROR(0x4e6)},
+ {NT_STATUS(0x80000001), W_ERROR(0x80000001)},
+ {NT_STATUS(0x80000002), W_ERROR(0x3e6)},
+ {NT_STATUS(0x80000003), W_ERROR(0x80000003)},
+ {NT_STATUS(0x80000004), W_ERROR(0x80000004)},
+ {NT_STATUS(0x80000005), W_ERROR(0xea)},
+ {NT_STATUS(0x80000006), W_ERROR(0x12)},
+ {NT_STATUS(0x8000000b), W_ERROR(0x56f)},
+ {NT_STATUS(0x8000000d), W_ERROR(0x12b)},
+ {NT_STATUS(0x8000000e), W_ERROR(0x1c)},
+ {NT_STATUS(0x8000000f), W_ERROR(0x15)},
+ {NT_STATUS(0x80000010), W_ERROR(0x15)},
+ {NT_STATUS(0x80000011), W_ERROR(0xaa)},
+ {NT_STATUS(0x80000012), W_ERROR(0x103)},
+ {NT_STATUS(0x80000013), W_ERROR(0xfe)},
+ {NT_STATUS(0x80000014), W_ERROR(0xff)},
+ {NT_STATUS(0x80000015), W_ERROR(0xff)},
+ {NT_STATUS(0x80000016), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001a), W_ERROR(0x103)},
+ {NT_STATUS(0x8000001b), W_ERROR(0x44d)},
+ {NT_STATUS(0x8000001c), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001d), W_ERROR(0x457)},
+ {NT_STATUS(0x8000001e), W_ERROR(0x44c)},
+ {NT_STATUS(0x8000001f), W_ERROR(0x44e)},
+ {NT_STATUS(0x80000021), W_ERROR(0x44f)},
+ {NT_STATUS(0x80000022), W_ERROR(0x450)},
+ {NT_STATUS(0x80000025), W_ERROR(0x962)},
+ {NT_STATUS(0x80000288), W_ERROR(0x48d)},
+ {NT_STATUS(0x80000289), W_ERROR(0x48e)},
+ {NT_STATUS_OK, WERR_OK}};
+
+
+/*****************************************************************************
+convert a dos eclas/ecode to a NT status32 code
+ *****************************************************************************/
+NTSTATUS dos_to_ntstatus(int eclass, int ecode)
+{
+ int i;
+ if (eclass == 0 && ecode == 0) return NT_STATUS_OK;
+ for (i=0; NT_STATUS_V(dos_to_ntstatus_map[i].ntstatus); i++) {
+ if (eclass == dos_to_ntstatus_map[i].dos_class &&
+ ecode == dos_to_ntstatus_map[i].dos_code) {
+ return dos_to_ntstatus_map[i].ntstatus;
+ }
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8 *eclass, uint32 *ecode)
+{
+ int i;
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ *eclass = 0;
+ *ecode = 0;
+ return;
+ }
+ for (i=0; NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(ntstatus) ==
+ NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus)) {
+ *eclass = ntstatus_to_dos_map[i].dos_class;
+ *ecode = ntstatus_to_dos_map[i].dos_code;
+ return;
+ }
+ }
+ *eclass = ERRSRV;
+ *ecode = ERRerror;
+}
+
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error)
+{
+ int i;
+ if (W_ERROR_IS_OK(error)) return NT_STATUS_OK;
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(ntstatus_to_werror_map[i].werror)) {
+ return ntstatus_to_werror_map[i].ntstatus;
+ }
+ }
+
+ /* just guess ... */
+ return NT_STATUS(W_ERROR_V(error) | 0xc0000000);
+}
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error)
+{
+ int i;
+ if (NT_STATUS_IS_OK(error)) return WERR_OK;
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(error) ==
+ NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus)) {
+ return ntstatus_to_werror_map[i].werror;
+ }
+ }
+
+ /* a lame guess */
+ return W_ERROR(NT_STATUS_V(error) & 0xffff);
+}
diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c
new file mode 100644
index 00000000000..33aeb62af8f
--- /dev/null
+++ b/source/libsmb/libsmbclient.c
@@ -0,0 +1,2583 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpstra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+
+/* Structure for servers ... Held here so we don't need an include ...
+ * May be better to put in an include file
+ */
+
+struct smbc_server {
+ struct smbc_server *next, *prev;
+ struct cli_state cli;
+ dev_t dev;
+ char *server_name;
+ char *share_name;
+ char *workgroup;
+ char *username;
+ BOOL no_pathinfo2;
+};
+
+/* Keep directory entries in a list */
+struct smbc_dir_list {
+ struct smbc_dir_list *next;
+ struct smbc_dirent *dirent;
+};
+
+struct smbc_file {
+ int cli_fd;
+ int smbc_fd;
+ char *fname;
+ off_t offset;
+ struct smbc_server *srv;
+ BOOL file;
+ struct smbc_dir_list *dir_list, *dir_end, *dir_next;
+ int dir_type, dir_error;
+};
+
+int smbc_fstatdir(int fd, struct stat *st); /* Forward decl */
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino);
+
+extern BOOL in_client;
+extern pstring global_myname;
+static int smbc_initialized = 0;
+static smbc_get_auth_data_fn smbc_auth_fn = NULL;
+/*static int smbc_debug;*/
+static int smbc_start_fd;
+static int smbc_max_fd = 10000;
+static struct smbc_file **smbc_file_table;
+static struct smbc_server *smbc_srvs;
+static pstring my_netbios_name;
+static pstring smbc_user;
+
+/*
+ * Function to parse a path and turn it into components
+ *
+ * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
+ *
+ * smb:// means show all the workgroups
+ * smb://name/ means, if name<1D> exists, list servers in workgroup,
+ * else, if name<20> exists, list all shares for server ...
+ */
+
+static const char *smbc_prefix = "smb:";
+
+static int
+smbc_parse_path(const char *fname, char *server, char *share, char *path,
+ char *user, char *password) /* FIXME, lengths of strings */
+{
+ static pstring s;
+ pstring userinfo;
+ char *p;
+ char *q, *r;
+ int len;
+
+ server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
+ pstrcpy(s, fname);
+
+ /* clean_fname(s); causing problems ... */
+
+ /* see if it has the right prefix */
+ len = strlen(smbc_prefix);
+ if (strncmp(s,smbc_prefix,len) ||
+ (s[len] != '/' && s[len] != 0)) return -1; /* What about no smb: ? */
+
+ p = s + len;
+
+ /* Watch the test below, we are testing to see if we should exit */
+
+ if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
+
+ return -1;
+
+ }
+
+ p += 2; /* Skip the // or \\ */
+
+ if (*p == (char)0)
+ return 0;
+
+ if (*p == '/') {
+
+ strncpy(server, (char *)lp_workgroup(), 16); /* FIXME: Danger here */
+ return 0;
+
+ }
+
+ /*
+ * ok, its for us. Now parse out the server, share etc.
+ *
+ * However, we want to parse out [[domain;]user[:password]@] if it
+ * exists ...
+ */
+
+ /* check that '@' occurs before '/', if '/' exists at all */
+ q = strchr_m(p, '@');
+ r = strchr_m(p, '/');
+ if (q && (!r || q < r)) {
+ pstring username, passwd, domain;
+ char *u = userinfo;
+
+ next_token(&p, userinfo, "@", sizeof(fstring));
+
+ username[0] = passwd[0] = domain[0] = 0;
+
+ if (strchr_m(u, ';')) {
+
+ next_token(&u, domain, ";", sizeof(fstring));
+
+ }
+
+ if (strchr_m(u, ':')) {
+
+ next_token(&u, username, ":", sizeof(fstring));
+
+ pstrcpy(passwd, u);
+
+ }
+ else {
+
+ pstrcpy(username, u);
+
+ }
+
+ if (username[0])
+ strncpy(user, username, sizeof(fstring)); /* FIXME, size and domain */
+
+ if (passwd[0])
+ strncpy(password, passwd, sizeof(fstring)); /* FIXME, size */
+
+ }
+
+ if (!next_token(&p, server, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ if (*p == (char)0) return 0; /* That's it ... */
+
+ if (!next_token(&p, share, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ pstrcpy(path, p);
+
+ all_string_sub(path, "/", "\\", 0);
+
+ return 0;
+}
+
+/*
+ * Convert an SMB error into a UNIX error ...
+ */
+
+int smbc_errno(struct cli_state *c)
+{
+ int ret;
+
+ if (cli_is_dos_error(c)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(c, &eclass, &ecode);
+ ret = cli_errno_from_dos(eclass, ecode);
+
+ DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
+ (int)eclass, (int)ecode, (int)ecode, ret));
+ } else {
+ NTSTATUS status;
+
+ status = cli_nt_error(c);
+ ret = cli_errno_from_nt(status);
+
+ DEBUG(3,("smbc errno %s -> %d\n",
+ get_nt_error_msg(status), ret));
+ }
+
+ return ret;
+}
+
+/*
+ * Connect to a server, possibly on an existing connection
+ *
+ * Here, what we want to do is: If the server and username
+ * match an existing connection, reuse that, otherwise, establish a
+ * new connection.
+ *
+ * If we have to create a new connection, call the auth_fn to get the
+ * info we need, unless the username and password were passed in.
+ */
+
+struct smbc_server *smbc_server(char *server, char *share,
+ char *workgroup, char *username,
+ char *password)
+{
+ struct smbc_server *srv=NULL;
+ struct cli_state c;
+ struct nmb_name called, calling;
+ char *p, *server_n = server;
+ fstring group;
+ pstring ipenv;
+ struct in_addr ip;
+
+ zero_ip(&ip);
+ ZERO_STRUCT(c);
+
+ /* try to use an existing connection */
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ if (server[0] == 0) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ /*
+ * Pick up the auth info here, once we know we need to connect
+ * But only if we do not have a username and password ...
+ */
+
+ if (!username[0] || !password[0])
+ smbc_auth_fn(server, share, workgroup, sizeof(fstring),
+ username, sizeof(fstring), password, sizeof(fstring));
+
+ /*
+ * However, smbc_auth_fn may have picked up info relating to an
+ * existing connection, so try for an existing connection again ...
+ */
+
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ make_nmb_name(&calling, my_netbios_name, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
+
+ if ((p=strchr_m(server_n,'#')) &&
+ (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
+
+ fstrcpy(group, server_n);
+ p = strchr_m(group,'#');
+ *p = 0;
+
+ }
+
+ DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
+
+ again:
+ slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
+
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
+ if (c.initialised) cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_request(&c, &calling, &called)) {
+ cli_shutdown(&c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ errno = ENOENT;
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(&c)) {
+ cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_setup(&c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup) &&
+ /* try an anonymous login if it failed */
+ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
+ cli_shutdown(&c);
+ errno = EPERM;
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(&c, share, "?????",
+ password, strlen(password)+1)) {
+ errno = smbc_errno(&c);
+ cli_shutdown(&c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ srv = (struct smbc_server *)malloc(sizeof(*srv));
+ if (!srv) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(srv);
+
+ srv->cli = c;
+
+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+
+ srv->server_name = strdup(server);
+ if (!srv->server_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->share_name = strdup(share);
+ if (!srv->share_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->workgroup = strdup(workgroup);
+ if (!srv->workgroup) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->username = strdup(username);
+ if (!srv->username) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ DLIST_ADD(smbc_srvs, srv);
+
+ return srv;
+
+ failed:
+ cli_shutdown(&c);
+ if (!srv) return NULL;
+
+ SAFE_FREE(srv->server_name);
+ SAFE_FREE(srv->share_name);
+ SAFE_FREE(srv->workgroup);
+ SAFE_FREE(srv->username);
+ SAFE_FREE(srv);
+ return NULL;
+}
+
+/*
+ *Remove a server from the list smbc_srvs if it's unused -- Tom (tom@ninja.nl)
+ *
+ * We accept a *srv
+ */
+BOOL smbc_remove_unused_server(struct smbc_server * s)
+{
+ int p;
+
+ /* are we being fooled ? */
+ if (!s) return False;
+
+ /* close all open files/directories on this server */
+ for (p = 0; p < SMBC_MAX_FD; p++) {
+ if (smbc_file_table[p] &&
+ smbc_file_table[p]->srv == s) {
+ /* Still used .. DARN */
+ DEBUG(3, ("smbc_remove_usused_server: %x still used by %s (%d).\n", (int) s,
+ smbc_file_table[p]->fname, smbc_file_table[p]->smbc_fd));
+ return False;
+ }
+ }
+
+ cli_shutdown(&s->cli);
+
+ SAFE_FREE(s->username);
+ SAFE_FREE(s->workgroup);
+ SAFE_FREE(s->server_name);
+ SAFE_FREE(s->share_name);
+ DLIST_REMOVE(smbc_srvs, s);
+ DEBUG(3, ("smbc_remove_usused_server: %x removed.\n", (int) s));
+ SAFE_FREE(s);
+ return True;
+}
+
+/*
+ *Initialise the library etc
+ *
+ * We accept valid values for debug from 0 to 100,
+ * and insist that fn must be non-null.
+ */
+
+int smbc_init(smbc_get_auth_data_fn fn, int debug)
+{
+ pstring conf;
+ int p, pid;
+ char *user = NULL, *home = NULL, *pname="libsmbclient";
+
+ if (!fn || debug < 0 || debug > 100) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_initialized) { /* Don't go through this if we have already done it */
+
+ return 0;
+
+ }
+
+ smbc_initialized = 1;
+ smbc_auth_fn = fn;
+ /* smbc_debug = debug; */
+
+ DEBUGLEVEL = -1;
+
+ setup_logging(pname, False);
+
+ /* Here we would open the smb.conf file if needed ... */
+
+ home = getenv("HOME");
+
+ slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
+
+ load_interfaces(); /* Load the list of interfaces ... */
+
+ in_client = True; /* FIXME, make a param */
+
+ if (!lp_load(conf, True, False, False)) {
+
+ /*
+ * Hmmm, what the hell do we do here ... we could not parse the
+ * config file ... We must return an error ... and keep info around
+ * about why we failed
+ */
+
+ errno = ENOENT; /* FIXME: Figure out the correct error response */
+ return -1;
+
+ }
+
+ reopen_logs(); /* Get logging working ... */
+
+ /*
+ * FIXME: Is this the best way to get the user info?
+ */
+
+ user = getenv("USER");
+ /* walk around as "guest" if no username can be found */
+ if (!user) user = strdup("guest");
+ pstrcpy(smbc_user, user); /* Save for use elsewhere */
+
+ /*
+ * We try to get our netbios name from the config. If that fails we fall
+ * back on constructing our netbios name from our hostname etc
+ */
+ if (global_myname) {
+ pstrcpy(my_netbios_name, global_myname);
+ }
+ else {
+ /*
+ * Hmmm, I want to get hostname as well, but I am too lazy for the moment
+ */
+ pid = getpid();
+ slprintf(my_netbios_name, 16, "smbc%s%d", user, pid);
+ }
+ DEBUG(0,("Using netbios name %s.\n", my_netbios_name));
+
+ name_register_wins(my_netbios_name, 0);
+
+ /*
+ * Now initialize the file descriptor array and figure out what the
+ * max open files is, so we can return FD's that are above the max
+ * open file, and separated by a guard band
+ */
+
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ do {
+ struct rlimit rlp;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlp)) {
+
+ DEBUG(0, ("smbc_init: getrlimit(1) for RLIMIT_NOFILE failed with error %s\n", strerror(errno)));
+
+ smbc_start_fd = 1000000;
+
+ }
+ else {
+
+ smbc_start_fd = rlp.rlim_max + 10000; /* Leave a guard space of 10,000 */
+
+ }
+ } while ( 0 );
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+
+ smbc_start_fd = 1000000;
+
+#endif
+
+ smbc_file_table = malloc(SMBC_MAX_FD * sizeof(struct smbc_file *));
+
+ for (p = 0; p < SMBC_MAX_FD; p++)
+ smbc_file_table[p] = NULL;
+
+ if (!smbc_file_table)
+ return ENOMEM;
+
+ return 0; /* Success */
+
+}
+
+/*
+ * Routine to open() a file ...
+ */
+
+int smbc_open(const char *fname, int flags, mode_t mode)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ int fd;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ if (errno == EPERM) errno = EACCES;
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* Hmmm, the test for a directory is suspect here ... FIXME */
+
+ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
+
+ fd = -1;
+
+ }
+ else {
+
+ int slot = 0;
+
+ /* Find a free slot first */
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > SMBC_MAX_FD) {
+
+ errno = ENOMEM; /* FIXME, is this best? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) {
+
+ /* Handle the error ... */
+
+ SAFE_FREE(smbc_file_table[slot]);
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* Fill in file struct */
+
+ smbc_file_table[slot]->cli_fd = fd;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = srv;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = True;
+
+ return smbc_file_table[slot]->smbc_fd;
+
+ }
+
+ /* Check if opendir needed ... */
+
+ if (fd == -1) {
+ int eno = 0;
+
+ eno = smbc_errno(&srv->cli);
+ fd = smbc_opendir(fname);
+ if (fd < 0) errno = eno;
+ return fd;
+
+ }
+
+ return 1; /* Success, with fd ... */
+
+}
+
+/*
+ * Routine to create a file
+ */
+
+static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
+
+int smbc_creat(const char *path, mode_t mode)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ return smbc_open(path, creat_bits, mode);
+}
+
+/*
+ * Routine to read() a file ...
+ */
+
+ssize_t smbc_read(int fd, void *buf, size_t count)
+{
+ struct smbc_file *fe;
+ int ret;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_read(%d, %d)\n", fd, (int)count));
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_read(&fe->srv->cli, fe->cli_fd, buf, fe->offset, count);
+
+ if (ret < 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ DEBUG(4, (" --> %d\n", ret));
+
+ return ret; /* Success, ret bytes of data ... */
+
+}
+
+/*
+ * Routine to write() a file ...
+ */
+
+ssize_t smbc_write(int fd, void *buf, size_t count)
+{
+ int ret;
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_write(&fe->srv->cli, fe->cli_fd, 0, buf, fe->offset, count);
+
+ if (ret <= 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ return ret; /* Success, 0 bytes of data ... */
+}
+
+/*
+ * Routine to close() a file ...
+ */
+
+int smbc_close(int fd)
+{
+ struct smbc_file *fe;
+ struct smbc_server *srv;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_closedir(fd);
+
+ }
+
+ if (!cli_close(&fe->srv->cli, fe->cli_fd)) {
+
+ DEBUG(3, ("cli_close failed on %s (%d). purging server.\n",
+ fe->fname, fe->smbc_fd));
+ /* Deallocate slot and remove the server
+ * from the server cache if unused */
+ errno = smbc_errno(&fe->srv->cli);
+ srv = fe->srv;
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe);
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+ smbc_remove_unused_server(srv);
+
+ return -1;
+
+ }
+
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe);
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+}
+
+/*
+ * Routine to unlink() a file
+ */
+
+int smbc_unlink(const char *fname)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ int job = smbc_stat_printjob(srv, path, NULL, NULL);
+ if (job == -1) {
+
+ return -1;
+
+ }
+ if ((err = cli_printjob_del(&srv->cli, job)) != 0) {
+
+
+ return -1;
+
+ }
+ } else */
+
+ if (!cli_unlink(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the file is a directory */
+
+ int saverr = errno;
+ size_t size = 0;
+ uint16 mode = 0;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ /* Hmmm, bad error ... What? */
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ else {
+
+ if (IS_DOS_DIR(mode))
+ errno = EISDIR;
+ else
+ errno = saverr; /* Restore this */
+
+ }
+ }
+
+ return -1;
+
+ }
+
+ return 0; /* Success ... */
+
+}
+
+/*
+ * Routine to rename() a file
+ */
+
+int smbc_rename(const char *oname, const char *nname)
+{
+ fstring server1, share1, server2, share2, user1, user2, password1, password2, workgroup;
+ pstring path1, path2;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!oname || !nname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
+
+ smbc_parse_path(oname, server1, share1, path1, user1, password1);
+
+ if (user1[0] == (char)0) pstrcpy(user1, smbc_user);
+
+ smbc_parse_path(nname, server2, share2, path2, user2, password2);
+
+ if (user2[0] == (char)0) pstrcpy(user2, smbc_user);
+
+ if (strcmp(server1, server2) || strcmp(share1, share2) ||
+ strcmp(user1, user2)) {
+
+ /* Can't rename across file systems, or users?? */
+
+ errno = EXDEV;
+ return -1;
+
+ }
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server1, share1, workgroup, user1, password1);
+ if (!srv) {
+
+ return -1;
+
+ }
+
+ if (!cli_rename(&srv->cli, path1, path2)) {
+ int eno = smbc_errno(&srv->cli);
+
+ if (eno != EEXIST ||
+ !cli_unlink(&srv->cli, path2) ||
+ !cli_rename(&srv->cli, path1, path2)) {
+
+ errno = eno;
+ return -1;
+
+ }
+ }
+
+ return 0; /* Success */
+
+}
+
+/*
+ * A routine to lseek() a file
+ */
+
+off_t smbc_lseek(int fd, off_t offset, int whence)
+{
+ struct smbc_file *fe;
+ size_t size;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ errno = EINVAL;
+ return -1; /* Can't lseek a dir ... */
+
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ fe->offset = offset;
+ break;
+
+ case SEEK_CUR:
+ fe->offset += offset;
+ break;
+
+ case SEEK_END:
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL, NULL, NULL) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL)) {
+
+ errno = EINVAL;
+ return -1;
+ }
+ fe->offset = size + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ break;
+
+ }
+
+ return fe->offset;
+
+}
+
+/*
+ * Generate an inode number from file name for those things that need it
+ */
+
+static
+ino_t smbc_inode(const char *name)
+{
+
+ if (!*name) return 2; /* FIXME, why 2 ??? */
+ return (ino_t)str_checksum(name);
+
+}
+
+/*
+ * Routine to put basic stat info into a stat structure ... Used by stat and
+ * fstat below.
+ */
+
+static
+int smbc_setup_stat(struct stat *st, char *fname, size_t size, int mode)
+{
+
+ st->st_mode = 0;
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_mode = SMBC_DIR_MODE;
+ } else {
+ st->st_mode = SMBC_FILE_MODE;
+ }
+
+ if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
+ if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
+ if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
+ if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
+
+ st->st_size = size;
+ st->st_blksize = 512;
+ st->st_blocks = (size+511)/512;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_nlink = 2;
+ } else {
+ st->st_nlink = 1;
+ }
+
+ if (st->st_ino == 0) {
+ st->st_ino = smbc_inode(fname);
+ }
+
+ return True; /* FIXME: Is this needed ? */
+
+}
+
+/*
+ * Get info from an SMB server on a file. Use a qpathinfo call first
+ * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
+ */
+
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
+
+ if (!srv->no_pathinfo2 &&
+ cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
+ size, mode, ino)) return True;
+
+ /* if this is NT then don't bother with the getatr */
+ if (srv->cli.capabilities & CAP_NT_SMBS) return False;
+
+ if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
+ a_time = c_time = m_time;
+ srv->no_pathinfo2 = True;
+ return True;
+ }
+ return False;
+}
+
+/*
+ * Routine to stat a file given a name
+ */
+
+int smbc_stat(const char *fname, struct stat *st)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ size_t size = 0;
+ uint16 mode = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_stat(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* } */
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, path, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to stat a file given an fd
+ */
+
+int smbc_fstat(int fd, struct stat *st)
+{
+ struct smbc_file *fe;
+ time_t c_time, a_time, m_time;
+ size_t size;
+ uint16 mode;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_fstatdir(fd, st);
+
+ }
+
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time, NULL, &ino) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, fe->fname, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = fe->srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to open a directory
+ *
+ * We want to allow:
+ *
+ * smb: which should list all the workgroups available
+ * smb:workgroup
+ * smb:workgroup//server
+ * smb://server
+ * smb://server/share
+ * smb://<IP-addr> which should list shares on server
+ * smb://<IP-addr>/share which should list files on share
+ */
+
+static void smbc_remove_dir(struct smbc_file *dir)
+{
+ struct smbc_dir_list *d,*f;
+
+ d = dir->dir_list;
+ while (d) {
+
+ f = d; d = d->next;
+
+ SAFE_FREE(f->dirent);
+ SAFE_FREE(f);
+
+ }
+
+ dir->dir_list = dir->dir_end = dir->dir_next = NULL;
+
+}
+
+static int add_dirent(struct smbc_file *dir, const char *name, const char *comment, uint32 type)
+{
+ struct smbc_dirent *dirent;
+ int size;
+
+ /*
+ * Allocate space for the dirent, which must be increased by the
+ * size of the name and the comment and 1 for the null on the comment.
+ * The null on the name is already accounted for.
+ */
+
+ size = sizeof(struct smbc_dirent) + (name?strlen(name):0) +
+ (comment?strlen(comment):0) + 1;
+
+ dirent = malloc(size);
+
+ if (!dirent) {
+
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ if (dir->dir_list == NULL) {
+
+ dir->dir_list = malloc(sizeof(struct smbc_dir_list));
+ if (!dir->dir_list) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_next = dir->dir_list;
+
+ }
+ else {
+
+ dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
+
+ if (!dir->dir_end) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_end->next;
+
+ }
+
+ dir->dir_end->next = NULL;
+ dir->dir_end->dirent = dirent;
+
+ dirent->smbc_type = type;
+ dirent->namelen = (name?strlen(name):0);
+ dirent->commentlen = (comment?strlen(comment):0);
+ dirent->dirlen = size;
+
+ strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
+
+ dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
+ strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
+
+ return 0;
+
+}
+
+static void
+list_fn(const char *name, uint32 type, const char *comment, void *state)
+{
+ struct smbc_file *dir = (struct smbc_file *)state;
+ int dirent_type;
+
+ /* We need to process the type a little ... */
+
+ if (dir->dir_type == SMBC_FILE_SHARE) {
+
+ switch (type) {
+ case 0: /* Directory tree */
+ dirent_type = SMBC_FILE_SHARE;
+ break;
+
+ case 1:
+ dirent_type = SMBC_PRINTER_SHARE;
+ break;
+
+ case 2:
+ dirent_type = SMBC_COMMS_SHARE;
+ break;
+
+ case 3:
+ dirent_type = SMBC_IPC_SHARE;
+ break;
+
+ default:
+ dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
+ break;
+ }
+
+ }
+ else dirent_type = dir->dir_type;
+
+ if (add_dirent(dir, name, comment, dirent_type) < 0) {
+
+ /* An error occurred, what do we do? */
+ /* FIXME: Add some code here */
+
+ }
+
+}
+
+static void
+dir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ if (add_dirent((struct smbc_file *)state, finfo->name, "",
+ (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
+
+ /* Handle an error ... */
+ /* FIXME: Add some code ... */
+
+ }
+
+}
+
+int smbc_opendir(const char *fname)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ struct in_addr rem_ip;
+ int slot = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_parse_path(fname, server, share, path, user, password)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ /* Get a file entry ... */
+
+ slot = 0;
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > SMBC_MAX_FD) {
+
+ errno = ENOMEM;
+ return -1; /* FIXME, ... move into a func */
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->cli_fd = 0;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = NULL;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = False;
+ smbc_file_table[slot]->dir_list =
+ smbc_file_table[slot]->dir_next =
+ smbc_file_table[slot]->dir_end = NULL;
+
+ if (server[0] == (char)0) {
+
+ if (share[0] != (char)0 || path[0] != (char)0) {
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ /* We have server and share and path empty ... so list the workgroups */
+
+ if (!resolve_name(lp_workgroup(), &rem_ip, 0x1d)) {
+
+ errno = EINVAL; /* Something wrong with smb.conf? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->dir_type = SMBC_WORKGROUP;
+
+ /* find the name of the server ... */
+
+ if (!name_status_find("*", 0, 0, rem_ip, server)) {
+
+ DEBUG(0, ("Could not get the name of local master browser for server %s\n", server));
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(server, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the stuff ... */
+
+ if (!cli_NetServerEnum(&srv->cli, workgroup, 0x80000000, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = cli_errno(&srv->cli);
+ return -1;
+
+ }
+ }
+ else { /* Server not an empty string ... Check the rest and see what gives */
+
+ if (share[0] == (char)0) {
+
+ if (path[0] != (char)0) { /* Should not have empty share with path */
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ /* Check to see if <server><1D> translates, or <server><20> translates */
+ /* However, we check to see if <server> is an IP address first */
+
+ if (!is_ipaddress(server) && /* Not an IP addr so check next */
+ resolve_name(server, &rem_ip, 0x1d)) { /* Found LMB */
+ pstring buserver;
+
+ smbc_file_table[slot]->dir_type = SMBC_SERVER;
+
+ /*
+ * Get the backup list ...
+ */
+
+
+ if (!name_status_find("*", 0, 0, rem_ip, buserver)) {
+
+ DEBUG(0, ("Could not get name of local master browser %s\n", server));
+ errno = EPERM; /* FIXME, is this correct */
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(buserver, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = cli_errno(&srv->cli);
+ return -1;
+
+ }
+
+ }
+ else {
+
+ if (resolve_name(server, &rem_ip, 0x20)) {
+
+ /* Now, list the shares ... */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (cli_RNetShareEnum(&srv->cli, list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ errno = cli_errno(&srv->cli);
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ }
+ else {
+
+ errno = ENODEV; /* Neither the workgroup nor server exists */
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ }
+
+ }
+ else { /* The server and share are specified ... work from there ... */
+
+ /* Well, we connect to the server and list the directory */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the files ... */
+
+ pstrcat(path, "\\*");
+
+ if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ }
+
+ }
+
+ return smbc_file_table[slot]->smbc_fd;
+
+}
+
+/*
+ * Routine to close a directory
+ */
+
+int smbc_closedir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ smbc_remove_dir(fe); /* Clean it up */
+
+ if (fe) {
+
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe); /* Free the space too */
+
+ }
+
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+
+}
+
+/*
+ * Routine to get a directory entry
+ */
+
+static char smbc_local_dirent[512]; /* Make big enough */
+
+struct smbc_dirent *smbc_readdir(unsigned int fd)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirp, *dirent;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return NULL;
+
+ }
+
+ if (!fe->dir_next)
+ return NULL;
+ else {
+
+ dirent = fe->dir_next->dirent;
+
+ if (!dirent) {
+
+ errno = ENOENT;
+ return NULL;
+
+ }
+
+ /* Hmmm, do I even need to copy it? */
+
+ bcopy(dirent, smbc_local_dirent, dirent->dirlen); /* Copy the dirent */
+
+ dirp = (struct smbc_dirent *)smbc_local_dirent;
+
+ dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
+
+ fe->dir_next = fe->dir_next->next;
+
+ return (struct smbc_dirent *)smbc_local_dirent;
+ }
+
+}
+
+/*
+ * Routine to get directory entries
+ */
+
+int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count)
+{
+ struct smbc_file *fe;
+ struct smbc_dir_list *dir;
+ int rem = count, reqd;
+ char *ndir = (char *)dirp;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /*
+ * Now, retrieve the number of entries that will fit in what was passed
+ * We have to figure out if the info is in the list, or we need to
+ * send a request to the server to get the info.
+ */
+
+ while ((dir = fe->dir_next)) {
+ struct smbc_dirent *dirent;
+
+ if (!dir->dirent) {
+
+ errno = ENOENT; /* Bad error */
+ return -1;
+
+ }
+
+ if (rem < (reqd = (sizeof(struct smbc_dirent) + dir->dirent->namelen +
+ dir->dirent->commentlen + 1))) {
+
+ if (rem < count) { /* We managed to copy something */
+
+ errno = 0;
+ return count - rem;
+
+ }
+ else { /* Nothing copied ... */
+
+ errno = EINVAL; /* Not enough space ... */
+ return -1;
+
+ }
+
+ }
+
+ dirent = dir->dirent;
+
+ bcopy(dirent, ndir, reqd); /* Copy the data in ... */
+
+ ((struct smbc_dirent *)ndir)->comment =
+ (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1);
+
+ ndir += reqd;
+
+ rem -= reqd;
+
+ fe->dir_next = dir = dir -> next;
+ }
+
+ if (rem == count)
+ return 0;
+ else
+ return count - rem;
+
+}
+
+/*
+ * Routine to create a directory ...
+ */
+
+int smbc_mkdir(const char *fname, mode_t mode)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_mkdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_mkdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Our list function simply checks to see if a directory is not empty
+ */
+
+static int smbc_rmdir_dirempty = True;
+
+static void rmdir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0)
+ smbc_rmdir_dirempty = False;
+
+}
+
+/*
+ * Routine to remove a directory
+ */
+
+int smbc_rmdir(const char *fname)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rmdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_rmdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the dir empty or not */
+
+ pstring lpath; /* Local storage to avoid buffer overflows */
+
+ smbc_rmdir_dirempty = True; /* Make this so ... */
+
+ pstrcpy(lpath, path);
+ pstrcat(lpath, "\\*");
+
+ if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn,
+ NULL) < 0) {
+
+ /* Fix errno to ignore latest error ... */
+
+ DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n",
+ smbc_errno(&srv->cli)));
+ errno = EACCES;
+
+ }
+
+ if (smbc_rmdir_dirempty)
+ errno = EACCES;
+ else
+ errno = ENOTEMPTY;
+
+ }
+
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Routine to return the current directory position
+ */
+
+off_t smbc_telldir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ return (off_t) fe->dir_next;
+
+}
+
+/*
+ * A routine to run down the list and see if the entry is OK
+ */
+
+struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list,
+ struct smbc_dirent *dirent)
+{
+
+ /* Run down the list looking for what we want */
+
+ if (dirent) {
+
+ struct smbc_dir_list *tmp = list;
+
+ while (tmp) {
+
+ if (tmp->dirent == dirent)
+ return tmp;
+
+ tmp = tmp->next;
+
+ }
+
+ }
+
+ return NULL; /* Not found, or an error */
+
+}
+
+
+/*
+ * Routine to seek on a directory
+ */
+
+int smbc_lseekdir(int fd, off_t offset)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirent = (struct smbc_dirent *)offset;
+ struct smbc_dir_list *list_ent = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /* Now, check what we were passed and see if it is OK ... */
+
+ if (dirent == NULL) { /* Seek to the begining of the list */
+
+ fe->dir_next = fe->dir_list;
+ return 0;
+
+ }
+
+ /* Now, run down the list and make sure that the entry is OK */
+ /* This may need to be changed if we change the format of the list */
+
+ if ((list_ent = smbc_check_dir_ent(fe->dir_list, dirent)) == NULL) {
+
+ errno = EINVAL; /* Bad entry */
+ return -1;
+
+ }
+
+ fe->dir_next = list_ent;
+
+ return 0;
+
+}
+
+/*
+ * Routine to fstat a dir
+ */
+
+int smbc_fstatdir(int fd, struct stat *st)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* No code yet ... */
+
+ return 0;
+
+}
+
+/*
+ * Routine to print a file on a remote server ...
+ *
+ * We open the file, which we assume to be on a remote server, and then
+ * copy it to a print file on the share specified by printq.
+ */
+
+int smbc_print_file(const char *fname, const char *printq)
+{
+ int fid1, fid2, bytes, saverr, tot_bytes = 0;
+ char buf[4096];
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname && !printq) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* Try to open the file for reading ... */
+
+ if ((fid1 = smbc_open(fname, O_RDONLY, 0666)) < 0) {
+
+ DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
+ return -1; /* smbc_open sets errno */
+
+ }
+
+ /* Now, try to open the printer file for writing */
+
+ if ((fid2 = smbc_open_print_job(printq)) < 0) {
+
+ saverr = errno; /* Save errno */
+ smbc_close(fid1);
+ errno = saverr;
+ return -1;
+
+ }
+
+ while ((bytes = smbc_read(fid1, buf, sizeof(buf))) > 0) {
+
+ tot_bytes += bytes;
+
+ if ((smbc_write(fid2, buf, bytes)) < 0) {
+
+ saverr = errno;
+ smbc_close(fid1);
+ smbc_close(fid2);
+ errno = saverr;
+
+ }
+
+ }
+
+ saverr = errno;
+
+ smbc_close(fid1); /* We have to close these anyway */
+ smbc_close(fid2);
+
+ if (bytes < 0) {
+
+ errno = saverr;
+ return -1;
+
+ }
+
+ return tot_bytes;
+
+}
+
+/*
+ * Open a print file to be written to by other calls
+ */
+
+int smbc_open_print_job(const char *fname)
+{
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_open_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ /* What if the path is empty, or the file exists? */
+
+ return smbc_open(fname, O_WRONLY, 666);
+
+}
+
+/*
+ * Routine to list print jobs on a printer share ...
+ */
+
+int smbc_list_print_jobs(const char *fname, void (*fn)(struct print_job_info *))
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if (cli_print_queue(&srv->cli, fn) < 0) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Delete a print job from a remote printer share
+ */
+
+int smbc_unlink_print_job(const char *fname, int id)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ int err;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if ((err = cli_printjob_del(&srv->cli, id)) != 0) {
+
+ if (err < 0)
+ errno = smbc_errno(&srv->cli);
+ else if (err == ERRnosuchprintjob)
+ errno = EINVAL;
+ return -1;
+
+
+ }
+
+ return 0;
+
+}
+
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
new file mode 100644
index 00000000000..2c235417a80
--- /dev/null
+++ b/source/libsmb/namequery.c
@@ -0,0 +1,1233 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ name query routines
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/* nmbd.c sets this to True. */
+BOOL global_in_nmbd = False;
+
+/****************************************************************************
+generate a random trn_id
+****************************************************************************/
+static int generate_trn_id(void)
+{
+ static int trn_id;
+
+ if (trn_id == 0) {
+ sys_srandom(sys_getpid());
+ }
+
+ trn_id = sys_random();
+
+ return trn_id % (unsigned)0x7FFF;
+}
+
+
+/****************************************************************************
+ parse a node status response into an array of structures
+****************************************************************************/
+static struct node_status *parse_node_status(char *p, int *num_names)
+{
+ struct node_status *ret;
+ int i;
+
+ *num_names = CVAL(p,0);
+
+ if (*num_names == 0) return NULL;
+
+ ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
+ if (!ret) return NULL;
+
+ p++;
+ for (i=0;i< *num_names;i++) {
+ StrnCpy(ret[i].name,p,15);
+ trim_string(ret[i].name,NULL," ");
+ ret[i].type = CVAL(p,15);
+ ret[i].flags = p[16];
+ p += 18;
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+do a NBT node status query on an open socket and return an array of
+structures holding the returned names or NULL if the query failed
+**************************************************************************/
+struct node_status *node_status_query(int fd,struct nmb_name *name,
+ struct in_addr to_ip, int *num_names)
+{
+ BOOL found=False;
+ int retries = 2;
+ int retry_time = 2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct node_status *ret;
+
+ ZERO_STRUCT(p);
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->question.question_name = *name;
+ nmb->question.question_type = 0x21;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount ||
+ nmb2->answers->rr_type != 0x21) {
+ /* XXXX what do we do with this? could be a
+ redirect, but we'll discard it for the
+ moment */
+ free_packet(p2);
+ continue;
+ }
+
+ ret = parse_node_status(&nmb2->answers->rdata[0], num_names);
+ free_packet(p2);
+ return ret;
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+find the first type XX name in a node status reply - used for finding
+a servers name given its IP
+return the matched name in *name
+**************************************************************************/
+
+BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name)
+{
+ struct node_status *status;
+ struct nmb_name nname;
+ int count, i;
+ int sock;
+
+ sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
+ if (sock == -1)
+ return False;
+
+ /* W2K PDC's seem not to respond to '*'#0. JRA */
+ make_nmb_name(&nname, q_name, q_type);
+ status = node_status_query(sock, &nname, to_ip, &count);
+ close(sock);
+ if (!status)
+ return False;
+
+ for (i=0;i<count;i++) {
+ if (status[i].type == type)
+ break;
+ }
+ if (i == count)
+ return False;
+
+ pull_ascii(name, status[i].name, 15, 0, STR_TERMINATE);
+
+ SAFE_FREE(status);
+ return True;
+}
+
+/****************************************************************************
+ Do a NetBIOS name registation to try to claim a name ...
+***************************************************************************/
+BOOL name_register(int fd, const char *name, int name_type,
+ struct in_addr name_ip, int opcode,
+ BOOL bcast,
+ struct in_addr to_ip, int *count)
+{
+ int retries = 3;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct in_addr register_ip;
+
+ DEBUG(4, ("name_register: %s as %s on %s\n", name, inet_ntoa(name_ip), inet_ntoa(to_ip)));
+
+ register_ip.s_addr = name_ip.s_addr; /* Fix this ... */
+
+ memset((char *)&p, '\0', sizeof(p));
+
+ *count = 0;
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = True; /* ? */
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 1;
+
+ make_nmb_name(&nmb->question.question_name, name, name_type);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ /* Now, create the additional stuff for a registration request */
+
+ if ((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
+
+ DEBUG(0, ("name_register: malloc fail for additional record.\n"));
+ return False;
+
+ }
+
+ memset((char *)nmb->additional, '\0', sizeof(struct res_rec));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ nmb->additional->rdata[0] = NB_MFLAG & 0xFF;
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], &register_ip);
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return False;
+
+ retries--;
+
+ if ((p2 = receive_nmb_packet(fd, 10, nmb->header.name_trn_id))) {
+ debug_nmb_packet(p2);
+ SAFE_FREE(p2); /* No memory leaks ... */
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a netbios name query to find someones IP.
+ Returns an array of IP addresses or NULL if none.
+ *count will be set to the number of addresses returned.
+****************************************************************************/
+struct in_addr *name_query(int fd,const char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count)
+{
+ BOOL found=False;
+ int i, retries = 3;
+ int retry_time = bcast?250:2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct in_addr *ip_list = NULL;
+
+ memset((char *)&p,'\0',sizeof(p));
+ (*count) = 0;
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ struct in_addr *tmp_ip_list;
+
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ /* If we get a Negative Name Query Response from a WINS
+ * server, we should report it and give up.
+ */
+ if( 0 == nmb2->header.opcode /* A query response */
+ && !(bcast) /* from a WINS server */
+ && nmb2->header.rcode /* Error returned */
+ ) {
+
+ if( DEBUGLVL( 3 ) ) {
+ /* Only executed if DEBUGLEVEL >= 3 */
+ dbgtext( "Negative name query response, rcode 0x%02x: ", nmb2->header.rcode );
+ switch( nmb2->header.rcode ) {
+ case 0x01:
+ dbgtext( "Request was invalidly formatted.\n" );
+ break;
+ case 0x02:
+ dbgtext( "Problem with NBNS, cannot process name.\n");
+ break;
+ case 0x03:
+ dbgtext( "The name requested does not exist.\n" );
+ break;
+ case 0x04:
+ dbgtext( "Unsupported request error.\n" );
+ break;
+ case 0x05:
+ dbgtext( "Query refused error.\n" );
+ break;
+ default:
+ dbgtext( "Unrecognized error code.\n" );
+ break;
+ }
+ }
+ free_packet(p2);
+ return( NULL );
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /*
+ * XXXX what do we do with this? Could be a
+ * redirect, but we'll discard it for the
+ * moment.
+ */
+ free_packet(p2);
+ continue;
+ }
+
+ tmp_ip_list = (struct in_addr *)Realloc( ip_list, sizeof( ip_list[0] )
+ * ( (*count) + nmb2->answers->rdlength/6 ) );
+
+ if (!tmp_ip_list) {
+ DEBUG(0,("name_query: Realloc failed.\n"));
+ SAFE_FREE(ip_list);
+ }
+
+ ip_list = tmp_ip_list;
+
+ if (ip_list) {
+ DEBUG(2,("Got a positive name query response from %s ( ", inet_ntoa(p2->ip)));
+ for (i=0;i<nmb2->answers->rdlength/6;i++) {
+ putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
+ DEBUGADD(2,("%s ",inet_ntoa(ip_list[(*count)])));
+ (*count)++;
+ }
+ DEBUGADD(2,(")\n"));
+ }
+
+ found=True;
+ retries=0;
+ free_packet(p2);
+ /*
+ * If we're doing a unicast lookup we only
+ * expect one reply. Don't wait the full 2
+ * seconds if we got one. JRA.
+ */
+ if(!bcast && found)
+ break;
+ }
+ }
+
+ /* Reach here if we've timed out waiting for replies.. */
+ if( !bcast && !found ) {
+ /* Timed out wating for WINS server to respond. Mark it dead. */
+ wins_srv_died( to_ip );
+ }
+
+ return ip_list;
+}
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+XFILE *startlmhosts(char *fname)
+{
+ XFILE *fp = x_fopen(fname,O_RDONLY, 0);
+ if (!fp) {
+ DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
+ fname, strerror(errno)));
+ return NULL;
+ }
+ return fp;
+}
+
+/********************************************************
+ Parse the next line in the lmhosts file.
+*********************************************************/
+
+BOOL getlmhostsent( XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
+{
+ pstring line;
+
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ pstring ip,flags,extra;
+ char *ptr;
+ int count = 0;
+
+ *name_type = -1;
+
+ if (!fgets_slash(line,sizeof(pstring),fp))
+ continue;
+
+ if (*line == '#')
+ continue;
+
+ pstrcpy(ip,"");
+ pstrcpy(name,"");
+ pstrcpy(flags,"");
+
+ ptr = line;
+
+ if (next_token(&ptr,ip ,NULL,sizeof(ip)))
+ ++count;
+ if (next_token(&ptr,name ,NULL, sizeof(pstring)))
+ ++count;
+ if (next_token(&ptr,flags,NULL, sizeof(flags)))
+ ++count;
+ if (next_token(&ptr,extra,NULL, sizeof(extra)))
+ ++count;
+
+ if (count <= 0)
+ continue;
+
+ if (count > 0 && count < 2)
+ {
+ DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
+ continue;
+ }
+
+ if (count >= 4)
+ {
+ DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
+ continue;
+ }
+
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
+
+ if (strchr_m(flags,'G') || strchr_m(flags,'S'))
+ {
+ DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
+
+ *ipaddr = *interpret_addr2(ip);
+
+ /* Extra feature. If the name ends in '#XX', where XX is a hex number,
+ then only add that name type. */
+ if((ptr = strchr_m(name, '#')) != NULL)
+ {
+ char *endptr;
+
+ ptr++;
+ *name_type = (int)strtol(ptr, &endptr, 16);
+
+ if(!*ptr || (endptr == ptr))
+ {
+ DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
+ continue;
+ }
+
+ *(--ptr) = '\0'; /* Truncate at the '#' */
+ }
+
+ return True;
+ }
+
+ return False;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(XFILE *fp)
+{
+ x_fclose(fp);
+}
+
+BOOL name_register_wins(const char *name, int name_type)
+{
+ int sock, i, return_count;
+ int num_interfaces = iface_count();
+ struct in_addr sendto_ip;
+
+ /*
+ * Check if we have any interfaces, prevents a segfault later
+ */
+
+ if (num_interfaces <= 0)
+ return False; /* Should return some indication of the problem */
+
+ /*
+ * Do a broadcast register ...
+ */
+
+ if (0 == wins_srv_count())
+ return False;
+
+ if( DEBUGLVL( 4 ) )
+ {
+ dbgtext( "name_register_wins: Registering my name %s ", name );
+ dbgtext( "with WINS server %s.\n", wins_srv_name() );
+ }
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr("0.0.0.0"), True );
+
+ if (sock == -1) return False;
+
+ set_socket_options(sock, "SO_BROADCAST"); /* ????! crh */
+
+ sendto_ip = wins_srv_ip();
+
+ if (num_interfaces > 1) {
+
+ for (i = 0; i < num_interfaces; i++) {
+
+ if (!name_register(sock, name, name_type, *iface_n_ip(i),
+ NMB_NAME_MULTIHOMED_REG_OPCODE,
+ True, sendto_ip, &return_count)) {
+
+ close(sock);
+ return False;
+
+ }
+
+ }
+
+ }
+ else {
+
+ if (!name_register(sock, name, name_type, *iface_n_ip(0),
+ NMB_NAME_REG_OPCODE,
+ True, sendto_ip, &return_count)) {
+
+ close(sock);
+ return False;
+
+ }
+
+ }
+
+ close(sock);
+
+ return True;
+
+}
+
+/********************************************************
+ Resolve via "bcast" method.
+*********************************************************/
+
+BOOL name_resolve_bcast(const char *name, int name_type,
+ struct in_addr **return_ip_list, int *return_count)
+{
+ int sock, i;
+ int num_interfaces = iface_count();
+
+ *return_ip_list = NULL;
+ *return_count = 0;
+
+ /*
+ * "bcast" means do a broadcast lookup on all the local interfaces.
+ */
+
+ DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()), True );
+
+ if (sock == -1) return False;
+
+ set_socket_options(sock,"SO_BROADCAST");
+ /*
+ * Lookup the name on all the interfaces, return on
+ * the first successful match.
+ */
+ for( i = num_interfaces-1; i >= 0; i--) {
+ struct in_addr sendto_ip;
+ /* Done this way to fix compiler error on IRIX 5.x */
+ sendto_ip = *iface_bcast(*iface_n_ip(i));
+ *return_ip_list = name_query(sock, name, name_type, True,
+ True, sendto_ip, return_count);
+ if(*return_ip_list != NULL) {
+ close(sock);
+ return True;
+ }
+ }
+
+ close(sock);
+ return False;
+}
+
+/********************************************************
+ Resolve via "wins" method.
+*********************************************************/
+
+static BOOL resolve_wins(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ int sock;
+ struct in_addr wins_ip;
+ BOOL wins_ismyip;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ /*
+ * "wins" means do a unicast lookup to the WINS server.
+ * Ignore if there is no WINS server specified or if the
+ * WINS server is one of our interfaces (if we're being
+ * called from within nmbd - we can't do this call as we
+ * would then block).
+ */
+
+ DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
+
+ if (lp_wins_support()) {
+ /*
+ * We're providing WINS support. Call ourselves so
+ * long as we're not nmbd.
+ */
+ extern struct in_addr loopback_ip;
+ wins_ip = loopback_ip;
+ wins_ismyip = True;
+ } else if( wins_srv_count() < 1 ) {
+ DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
+ return False;
+ } else {
+ wins_ip = wins_srv_ip();
+ wins_ismyip = ismyip(wins_ip);
+ }
+
+ DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
+ if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()),
+ True );
+ if (sock != -1) {
+ *return_iplist = name_query( sock, name,
+ name_type, False,
+ True, wins_ip,
+ return_count);
+ if(*return_iplist != NULL) {
+ close(sock);
+ return True;
+ }
+ close(sock);
+ }
+ }
+
+ return False;
+}
+
+/********************************************************
+ Resolve via "lmhosts" method.
+*********************************************************/
+
+static BOOL resolve_lmhosts(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ XFILE *fp;
+ pstring lmhost_name;
+ int name_type2;
+ struct in_addr return_ip;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
+
+ fp = startlmhosts(dyn_LMHOSTSFILE);
+ if(fp) {
+ while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
+ if (strequal(name, lmhost_name) &&
+ ((name_type2 == -1) || (name_type == name_type2))
+ ) {
+ endlmhosts(fp);
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
+ return False;
+ }
+ **return_iplist = return_ip;
+ *return_count = 1;
+ return True;
+ }
+ }
+ endlmhosts(fp);
+ }
+ return False;
+}
+
+
+/********************************************************
+ Resolve via "hosts" method.
+*********************************************************/
+
+static BOOL resolve_hosts(const char *name,
+ struct in_addr **return_iplist, int *return_count)
+{
+ /*
+ * "host" means do a localhost, or dns lookup.
+ */
+ struct hostent *hp;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
+
+ if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
+ struct in_addr return_ip;
+ putip((char *)&return_ip,(char *)hp->h_addr);
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("resolve_hosts: malloc fail !\n"));
+ return False;
+ }
+ **return_iplist = return_ip;
+ *return_count = 1;
+ return True;
+ }
+ return False;
+}
+
+/********************************************************
+ Internal interface to resolve a name into an IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+static BOOL internal_resolve_name(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ pstring name_resolve_list;
+ fstring tok;
+ char *ptr;
+ BOOL allones = (strcmp(name,"255.255.255.255") == 0);
+ BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
+ BOOL is_address = is_ipaddress(name);
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ if (allzeros || allones || is_address) {
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("internal_resolve_name: malloc fail !\n"));
+ return False;
+ }
+ if(is_address) {
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ (*return_iplist)->s_addr = inet_addr(name);
+ } else {
+ (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
+ *return_count = 1;
+ }
+ return True;
+ }
+
+ pstrcpy(name_resolve_list, lp_name_resolve_order());
+ ptr = name_resolve_list;
+ if (!ptr || !*ptr)
+ ptr = "host";
+
+ while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
+ if((strequal(tok, "host") || strequal(tok, "hosts"))) {
+ if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) {
+ return True;
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
+ return True;
+ }
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D &&
+ resolve_wins(name, name_type, return_iplist, return_count)) {
+ return True;
+ }
+ } else if(strequal( tok, "bcast")) {
+ if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
+ return True;
+ }
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
+ }
+ }
+
+ SAFE_FREE(*return_iplist);
+ return False;
+}
+
+/********************************************************
+ Internal interface to resolve a name into one IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+
+ if(internal_resolve_name(name, name_type, &ip_list, &count)) {
+ *return_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ SAFE_FREE(ip_list);
+ return False;
+}
+
+
+/********************************************************
+ resolve a name of format \\server_name or \\ipaddress
+ into a name. also, cut the \\ from the front for us.
+*********************************************************/
+
+BOOL resolve_srv_name(const char* srv_name, fstring dest_host,
+ struct in_addr *ip)
+{
+ BOOL ret;
+ const char *sv_name = srv_name;
+
+ DEBUG(10,("resolve_srv_name: %s\n", srv_name));
+
+ if (srv_name == NULL || strequal("\\\\.", srv_name))
+ {
+ extern pstring global_myname;
+ fstrcpy(dest_host, global_myname);
+ ip = interpret_addr2("127.0.0.1");
+ return True;
+ }
+
+ if (strnequal("\\\\", srv_name, 2))
+ {
+ sv_name = &srv_name[2];
+ }
+
+ fstrcpy(dest_host, sv_name);
+ /* treat the '*' name specially - it is a magic name for the PDC */
+ if (strcmp(dest_host,"*") == 0) {
+ extern pstring global_myname;
+ ret = resolve_name(lp_workgroup(), ip, 0x1B);
+ lookup_dc_name(global_myname, lp_workgroup(), ip, dest_host);
+ } else {
+ ret = resolve_name(dest_host, ip, 0x20);
+ }
+
+ if (is_ipaddress(dest_host))
+ {
+ fstrcpy(dest_host, "*SMBSERVER");
+ }
+
+ return ret;
+}
+
+
+/********************************************************
+ Find the IP address of the master browser or DMB for a workgroup.
+*********************************************************/
+
+BOOL find_master_ip(char *group, struct in_addr *master_ip)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+
+ if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
+ *master_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
+ *master_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+
+ SAFE_FREE(ip_list);
+ return False;
+}
+
+/********************************************************
+ Lookup a DC name given a Domain name and IP address.
+*********************************************************/
+
+BOOL lookup_dc_name(const char *srcname, const char *domain,
+ struct in_addr *dc_ip, char *ret_name)
+{
+#if !defined(I_HATE_WINDOWS_REPLY_CODE)
+
+ fstring dc_name;
+ BOOL ret;
+
+ /*
+ * Due to the fact win WinNT *sucks* we must do a node status
+ * query here... JRA.
+ */
+
+ *dc_name = '\0';
+
+ ret = name_status_find(domain, 0x1c, 0x20, *dc_ip, dc_name);
+
+ if(ret && *dc_name) {
+ fstrcpy(ret_name, dc_name);
+ return True;
+ }
+
+ return False;
+
+#else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
+
+JRA - This code is broken with BDC rollover - we need to do a full
+NT GETDC call, UNICODE, NT domain SID and uncle tom cobbley and all...
+
+ int retries = 3;
+ int retry_time = 2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr,*p2;
+ char tmp[4];
+ int len;
+ struct sockaddr_in sock_name;
+ int sock_len = sizeof(sock_name);
+ const char *mailslot = NET_LOGON_MAILSLOT;
+ char *mailslot_name;
+ char buffer[1024];
+ char *bufp;
+ int dgm_id = generate_trn_id();
+ int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
+
+ if(sock == -1)
+ return False;
+
+ /* Find out the transient UDP port we have been allocated. */
+ if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
+ DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
+ strerror(errno)));
+ close(sock);
+ return False;
+ }
+
+ /*
+ * Create the request data.
+ */
+
+ memset(buffer,'\0',sizeof(buffer));
+ bufp = buffer;
+ SSVAL(bufp,0,QUERYFORPDC);
+ bufp += 2;
+ fstrcpy(bufp,srcname);
+ bufp += (strlen(bufp) + 1);
+ slprintf(bufp, sizeof(fstring)-1, "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
+ mailslot_name = bufp;
+ bufp += (strlen(bufp) + 1);
+ bufp = ALIGN2(bufp, buffer);
+ bufp += push_ucs2(NULL, bufp, srcname, sizeof(buffer) - (bufp - buffer), STR_TERMINATE);
+
+ SIVAL(bufp,0,1);
+ SSVAL(bufp,4,0xFFFF);
+ SSVAL(bufp,6,0xFFFF);
+ bufp += 8;
+ len = PTR_DIFF(bufp,buffer);
+
+ memset((char *)&p,'\0',sizeof(p));
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = 0x10;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = dgm_id;
+ dgram->header.source_ip = *iface_ip(*pdc_ip);
+ dgram->header.source_port = ntohs(sock_name.sin_port);
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,0);
+ make_nmb_name(&dgram->dest_name,domain,0x1C);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ pstrcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buffer,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = *pdc_ip;
+ p.port = DGRAM_PORT;
+ p.fd = sock;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p)) {
+ DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
+ close(sock);
+ return False;
+ }
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ struct packet_struct *p_ret;
+
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!send_packet(&p)) {
+ DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
+ close(sock);
+ return False;
+ }
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
+ struct dgram_packet *dgram2 = &p_ret->packet.dgram;
+ char *buf;
+ char *buf2;
+
+ buf = &dgram2->data[0];
+ buf -= 4;
+
+ if (CVAL(buf,smb_com) != SMBtrans) {
+ DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
+ CVAL(buf,smb_com), (unsigned int)SMBtrans ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ if (len <= 0) {
+ DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
+ nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
+ inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
+
+ if(SVAL(buf2,0) != QUERYFORPDC_R) {
+ DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
+ (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ buf2 += 2;
+ /* Note this is safe as it is a bounded strcpy. */
+ fstrcpy(ret_name, buf2);
+ ret_name[sizeof(fstring)-1] = '\0';
+ close(sock);
+ free_packet(p_ret);
+ return True;
+ }
+ }
+
+ close(sock);
+ return False;
+#endif /* defined(I_HATE_WINDOWS_REPLY_CODE) */
+}
+
+
+/********************************************************
+ Get the IP address list of the PDC/BDC's of a Domain.
+*********************************************************/
+
+BOOL get_dc_list(BOOL pdc_only, char *group, struct in_addr **ip_list, int *count)
+{
+ int name_type = pdc_only ? 0x1B : 0x1C;
+
+ /*
+ * If it's our domain then
+ * use the 'password server' parameter.
+ */
+
+ if (strequal(group, lp_workgroup())) {
+ char *p;
+ char *pserver = lp_passwordserver();
+ fstring name;
+ int num_adresses = 0;
+ struct in_addr *return_iplist = NULL;
+
+ if (! *pserver)
+ return internal_resolve_name(group, name_type, ip_list, count);
+
+ p = pserver;
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ if (strequal(name, "*"))
+ return internal_resolve_name(group, name_type, ip_list, count);
+ num_adresses++;
+ }
+ if (num_adresses == 0)
+ return internal_resolve_name(group, name_type, ip_list, count);
+
+ return_iplist = (struct in_addr *)malloc(num_adresses * sizeof(struct in_addr));
+ if(return_iplist == NULL) {
+ DEBUG(3,("get_dc_list: malloc fail !\n"));
+ return False;
+ }
+ p = pserver;
+ *count = 0;
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ struct in_addr name_ip;
+ if (resolve_name( name, &name_ip, 0x20) == False)
+ continue;
+ return_iplist[(*count)++] = name_ip;
+ }
+ *ip_list = return_iplist;
+ return (*count != 0);
+ } else
+ return internal_resolve_name(group, name_type, ip_list, count);
+}
+
+/********************************************************
+ Get the IP address list of the Local Master Browsers
+ ********************************************************/
+BOOL get_lmb_list(struct in_addr **ip_list, int *count)
+{
+ return internal_resolve_name( MSBROWSE, 0x1, ip_list, count);
+}
diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c
index 67432271737..0061a4b9772 100644
--- a/source/libsmb/nmblib.c
+++ b/source/libsmb/nmblib.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,24 +21,141 @@
*/
#include "includes.h"
-#include "nameserv.h"
-extern int DEBUGLEVEL;
+int num_good_sends = 0;
+int num_good_receives = 0;
+
+static const struct opcode_names {
+ char *nmb_opcode_name;
+ int opcode;
+} nmb_header_opcode_names[] = {
+ {"Query", 0 },
+ {"Registration", 5 },
+ {"Release", 6 },
+ {"WACK", 7 },
+ {"Refresh", 8 },
+ {"Refresh(altcode)", 9 },
+ {"Multi-homed Registration", 15 },
+ {0, -1 }
+};
-int num_good_sends=0;
-int num_good_receives=0;
-static uint16 name_trn_id = 0;
-BOOL CanRecurse = True;
-extern pstring scope;
+/****************************************************************************
+ * Lookup a nmb opcode name.
+ ****************************************************************************/
+static const char *lookup_opcode_name( int opcode )
+{
+ const struct opcode_names *op_namep;
+ int i;
+
+ for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
+ op_namep = &nmb_header_opcode_names[i];
+ if(opcode == op_namep->opcode)
+ return op_namep->nmb_opcode_name;
+ }
+ return "<unknown opcode>";
+}
+
+/****************************************************************************
+ print out a res_rec structure
+ ****************************************************************************/
+static void debug_nmb_res_rec(struct res_rec *res, char *hdr)
+{
+ int i, j;
+
+ DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
+ hdr,
+ nmb_namestr(&res->rr_name),
+ res->rr_type,
+ res->rr_class,
+ res->ttl ) );
+
+ if( res->rdlength == 0 || res->rdata == NULL )
+ return;
+
+ for (i = 0; i < res->rdlength; i+= 16)
+ {
+ DEBUGADD(4, (" %s %3x char ", hdr, i));
+
+ for (j = 0; j < 16; j++)
+ {
+ uchar x = res->rdata[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= res->rdlength) break;
+ DEBUGADD(4, ("%c", x));
+ }
+
+ DEBUGADD(4, (" hex "));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= res->rdlength) break;
+ DEBUGADD(4, ("%02X", (uchar)res->rdata[i+j]));
+ }
+
+ DEBUGADD(4, ("\n"));
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+void debug_nmb_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ if( DEBUGLVL( 4 ) )
+ {
+ dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
+ inet_ntoa(p->ip), p->port,
+ nmb->header.name_trn_id,
+ lookup_opcode_name(nmb->header.opcode),
+ nmb->header.opcode,
+ BOOLSTR(nmb->header.response) );
+ dbgtext( " header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
+ BOOLSTR(nmb->header.nm_flags.bcast),
+ BOOLSTR(nmb->header.nm_flags.recursion_available),
+ BOOLSTR(nmb->header.nm_flags.recursion_desired),
+ BOOLSTR(nmb->header.nm_flags.trunc),
+ BOOLSTR(nmb->header.nm_flags.authoritative) );
+ dbgtext( " header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
+ nmb->header.rcode,
+ nmb->header.qdcount,
+ nmb->header.ancount,
+ nmb->header.nscount,
+ nmb->header.arcount );
+ }
+
+ if (nmb->header.qdcount)
+ {
+ DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n",
+ nmb_namestr(&nmb->question.question_name),
+ nmb->question.question_type,
+ nmb->question.question_class) );
+ }
+
+ if (nmb->answers && nmb->header.ancount)
+ {
+ debug_nmb_res_rec(nmb->answers,"answers");
+ }
+ if (nmb->nsrecs && nmb->header.nscount)
+ {
+ debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
+ }
+ if (nmb->additional && nmb->header.arcount)
+ {
+ debug_nmb_res_rec(nmb->additional,"additional");
+ }
+}
/*******************************************************************
handle "compressed" name pointers
******************************************************************/
-static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+static BOOL handle_name_ptrs(uchar *ubuf,int *offset,int length,
BOOL *got_pointer,int *ret)
{
int loop_count=0;
-
+
while ((ubuf[*offset] & 0xC0) == 0xC0) {
if (!*got_pointer) (*ret) += 2;
(*got_pointer)=True;
@@ -54,34 +171,41 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
parse a nmb name from "compressed" format to something readable
return the space taken by the name, or 0 if the name is invalid
******************************************************************/
-static int parse_nmb_name(char *inbuf,int offset,int length,
- struct nmb_name *name)
+static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
{
int m,n=0;
- unsigned char *ubuf = (unsigned char *)inbuf;
+ uchar *ubuf = (uchar *)inbuf;
int ret = 0;
BOOL got_pointer=False;
+ int loop_count=0;
+ int offset = ofs;
- if (length - offset < 2) return(0);
+ if (length - offset < 2)
+ return(0);
/* handle initial name pointers */
- if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0);
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
m = ubuf[offset];
- if (!m) return(0);
- if ((m & 0xC0) || offset+m+2 > length) return(0);
+ if (!m)
+ return(0);
+ if ((m & 0xC0) || offset+m+2 > length)
+ return(0);
- bzero((char *)name,sizeof(*name));
+ memset((char *)name,'\0',sizeof(*name));
/* the "compressed" part */
- if (!got_pointer) ret += m + 2;
+ if (!got_pointer)
+ ret += m + 2;
offset++;
- while (m) {
- unsigned char c1,c2;
+ while (m > 0) {
+ uchar c1,c2;
c1 = ubuf[offset++]-'A';
c2 = ubuf[offset++]-'A';
- if ((c1 & 0xF0) || (c2 & 0xF0)) return(0);
+ if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+ return(0);
name->name[n++] = (c1<<4) | c2;
m -= 2;
}
@@ -90,25 +214,43 @@ static int parse_nmb_name(char *inbuf,int offset,int length,
if (n==16) {
/* parse out the name type,
its always in the 16th byte of the name */
- name->name_type = name->name[15];
+ name->name_type = ((uchar)name->name[15]) & 0xff;
/* remove trailing spaces */
name->name[15] = 0;
n = 14;
- while (n && name->name[n]==' ') name->name[n--] = 0;
+ while (n && name->name[n]==' ')
+ name->name[n--] = 0;
}
/* now the domain parts (if any) */
n = 0;
- while ((m=ubuf[offset])) {
+ while (ubuf[offset]) {
/* we can have pointers within the domain part as well */
- if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0);
-
- if (!got_pointer) ret += m+1;
- if (n) name->scope[n++] = '.';
- if (m+2+offset>length || n+m+1>sizeof(name->scope)) return(0);
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
+
+ m = ubuf[offset];
+ /*
+ * Don't allow null domain parts.
+ */
+ if (!m)
+ return(0);
+ if (!got_pointer)
+ ret += m+1;
+ if (n)
+ name->scope[n++] = '.';
+ if (m+2+offset>length || n+m+1>sizeof(name->scope))
+ return(0);
offset++;
- while (m--) name->scope[n++] = (char)ubuf[offset++];
+ while (m--)
+ name->scope[n++] = (char)ubuf[offset++];
+
+ /*
+ * Watch for malicious loops.
+ */
+ if (loop_count++ == 10)
+ return 0;
}
name->scope[n++] = 0;
@@ -130,12 +272,13 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
fstring buf1;
char *p;
- if (name->name[0] == '*') {
+ if (strcmp(name->name,"*") == 0) {
/* special case for wildcard name */
- bzero(buf1,20);
+ memset(buf1,'\0',20);
buf1[0] = '*';
+ buf1[15] = name->name_type;
} else {
- sprintf(buf1,"%-15.15s%c",name->name,name->name_type);
+ slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
}
buf[offset] = 0x20;
@@ -153,12 +296,12 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
if (name->scope[0]) {
/* XXXX this scope handling needs testing */
ret += strlen(name->scope) + 1;
- strcpy(&buf[offset+1],name->scope);
+ pstrcpy(&buf[offset+1],name->scope);
p = &buf[offset+1];
- while ((p = strchr(p,'.'))) {
- buf[offset] = PTR_DIFF(p,&buf[offset]);
- offset += buf[offset];
+ while ((p = strchr_m(p,'.'))) {
+ buf[offset] = PTR_DIFF(p,&buf[offset+1]);
+ offset += (buf[offset] + 1);
p = &buf[offset+1];
}
buf[offset] = strlen(&buf[offset+1]);
@@ -170,39 +313,38 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
/*******************************************************************
useful for debugging messages
******************************************************************/
-char *namestr(struct nmb_name *n)
+char *nmb_namestr(struct nmb_name *n)
{
static int i=0;
static fstring ret[4];
char *p = ret[i];
if (!n->scope[0])
- sprintf(p,"%s(%x)",n->name,n->name_type);
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
else
- sprintf(p,"%s(%x).%s",n->name,n->name_type,n->scope);
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
i = (i+1)%4;
return(p);
}
/*******************************************************************
- allocate are parse some resource records
+ allocate and parse some resource records
******************************************************************/
static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
- struct res_rec **recs,
- int count)
+ struct res_rec **recs, int count)
{
int i;
*recs = (struct res_rec *)malloc(sizeof(**recs)*count);
if (!*recs) return(False);
- bzero(*recs,sizeof(**recs)*count);
+ memset((char *)*recs,'\0',sizeof(**recs)*count);
for (i=0;i<count;i++) {
int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
(*offset) += l;
if (!l || (*offset)+10 > length) {
- free(*recs);
+ SAFE_FREE(*recs);
return(False);
}
(*recs)[i].rr_type = RSVAL(inbuf,(*offset));
@@ -212,7 +354,7 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
(*offset) += 10;
if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
(*offset)+(*recs)[i].rdlength > length) {
- free(*recs);
+ SAFE_FREE(*recs);
return(False);
}
memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
@@ -246,6 +388,27 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
}
/*******************************************************************
+ put a compressed name pointer record into a packet
+ ******************************************************************/
+static int put_compressed_name_ptr(uchar *buf,int offset,struct res_rec *rec,int ptr_offset)
+{
+ int ret=0;
+ buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
+ buf[offset+1] = (ptr_offset & 0xFF);
+ offset += 2;
+ ret += 2;
+ RSSVAL(buf,offset,rec->rr_type);
+ RSSVAL(buf,offset+2,rec->rr_class);
+ RSIVAL(buf,offset+4,rec->ttl);
+ RSSVAL(buf,offset+8,rec->rdlength);
+ memcpy(buf+offset+10,rec->rdata,rec->rdlength);
+ offset += 10+rec->rdlength;
+ ret += 10+rec->rdlength;
+
+ return(ret);
+}
+
+/*******************************************************************
parse a dgram packet. Return False if the packet can't be parsed
or is invalid for some reason, True otherwise
@@ -256,7 +419,7 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
int offset;
int flags;
- bzero((char *)dgram,sizeof(*dgram));
+ memset((char *)dgram,'\0',sizeof(*dgram));
if (length < 14) return(False);
@@ -298,12 +461,15 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
{
int nm_flags,offset;
- bzero((char *)nmb,sizeof(*nmb));
+ memset((char *)nmb,'\0',sizeof(*nmb));
if (length < 12) return(False);
/* parse the header */
nmb->header.name_trn_id = RSVAL(inbuf,0);
+
+ DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
+
nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
@@ -311,7 +477,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
- nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
+ nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
nmb->header.rcode = CVAL(inbuf,3) & 0xF;
nmb->header.qdcount = RSVAL(inbuf,4);
nmb->header.ancount = RSVAL(inbuf,6);
@@ -351,13 +517,128 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
}
/*******************************************************************
+ 'Copy constructor' for an nmb packet
+ ******************************************************************/
+static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
+{
+ struct nmb_packet *nmb;
+ struct nmb_packet *copy_nmb;
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* Ensure this copy has no resource records. */
+ nmb = &packet->packet.nmb;
+ copy_nmb = &pkt_copy->packet.nmb;
+
+ copy_nmb->answers = NULL;
+ copy_nmb->nsrecs = NULL;
+ copy_nmb->additional = NULL;
+
+ /* Now copy any resource records. */
+
+ if (nmb->answers)
+ {
+ if((copy_nmb->answers = (struct res_rec *)
+ malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
+ nmb->header.ancount * sizeof(struct res_rec));
+ }
+ if (nmb->nsrecs)
+ {
+ if((copy_nmb->nsrecs = (struct res_rec *)
+ malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
+ nmb->header.nscount * sizeof(struct res_rec));
+ }
+ if (nmb->additional)
+ {
+ if((copy_nmb->additional = (struct res_rec *)
+ malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
+ nmb->header.arcount * sizeof(struct res_rec));
+ }
+
+ return pkt_copy;
+
+free_and_exit:
+
+ SAFE_FREE(copy_nmb->answers);
+ SAFE_FREE(copy_nmb->nsrecs);
+ SAFE_FREE(copy_nmb->additional);
+ SAFE_FREE(pkt_copy);
+
+ DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+ return NULL;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a dgram packet
+ ******************************************************************/
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* There are no additional pointers in a dgram packet,
+ we are finished. */
+ return pkt_copy;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a generic packet
+ ******************************************************************/
+struct packet_struct *copy_packet(struct packet_struct *packet)
+{
+ if(packet->packet_type == NMB_PACKET)
+ return copy_nmb_packet(packet);
+ else if (packet->packet_type == DGRAM_PACKET)
+ return copy_dgram_packet(packet);
+ return NULL;
+}
+
+/*******************************************************************
free up any resources associated with an nmb packet
******************************************************************/
-void free_nmb_packet(struct nmb_packet *nmb)
+static void free_nmb_packet(struct nmb_packet *nmb)
{
- if (nmb->answers) free(nmb->answers);
- if (nmb->nsrecs) free(nmb->nsrecs);
- if (nmb->additional) free(nmb->additional);
+ SAFE_FREE(nmb->answers);
+ SAFE_FREE(nmb->nsrecs);
+ SAFE_FREE(nmb->additional);
+}
+
+/*******************************************************************
+ free up any resources associated with a dgram packet
+ ******************************************************************/
+static void free_dgram_packet(struct dgram_packet *nmb)
+{
+ /* We have nothing to do for a dgram packet. */
}
/*******************************************************************
@@ -365,58 +646,80 @@ void free_nmb_packet(struct nmb_packet *nmb)
******************************************************************/
void free_packet(struct packet_struct *packet)
{
+ if (packet->locked)
+ return;
if (packet->packet_type == NMB_PACKET)
free_nmb_packet(&packet->packet.nmb);
- free(packet);
+ else if (packet->packet_type == DGRAM_PACKET)
+ free_dgram_packet(&packet->packet.dgram);
+ ZERO_STRUCTPN(packet);
+ SAFE_FREE(packet);
}
/*******************************************************************
- read a packet from a socket and parse it, returning a packet ready
- to be used or put on the queue. This assumes a UDP socket
+parse a packet buffer into a packet structure
******************************************************************/
-struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+struct packet_struct *parse_packet(char *buf,int length,
+ enum packet_type packet_type)
{
- extern struct in_addr lastip;
- extern int lastport;
- struct packet_struct *packet;
- char buf[MAX_DGRAM_SIZE];
- int length;
- BOOL ok=False;
-
- length = read_udp_socket(fd,buf,sizeof(buf));
- if (length < MIN_DGRAM_SIZE) return(NULL);
-
- packet = (struct packet_struct *)malloc(sizeof(*packet));
- if (!packet) return(NULL);
-
- packet->next = NULL;
- packet->prev = NULL;
- packet->ip = lastip;
- packet->port = lastport;
- packet->fd = fd;
- packet->timestamp = time(NULL);
- packet->packet_type = packet_type;
- switch (packet_type)
- {
- case NMB_PACKET:
- ok = parse_nmb(buf,length,&packet->packet.nmb);
- break;
+ extern struct in_addr lastip;
+ extern int lastport;
+ struct packet_struct *p;
+ BOOL ok=False;
+
+ p = (struct packet_struct *)malloc(sizeof(*p));
+ if (!p) return(NULL);
+
+ p->next = NULL;
+ p->prev = NULL;
+ p->ip = lastip;
+ p->port = lastport;
+ p->locked = False;
+ p->timestamp = time(NULL);
+ p->packet_type = packet_type;
+
+ switch (packet_type) {
+ case NMB_PACKET:
+ ok = parse_nmb(buf,length,&p->packet.nmb);
+ break;
+
+ case DGRAM_PACKET:
+ ok = parse_dgram(buf,length,&p->packet.dgram);
+ break;
+ }
- case DGRAM_PACKET:
- ok = parse_dgram(buf,length,&packet->packet.dgram);
- break;
- }
- if (!ok) {
- free(packet);
- return(NULL);
- }
+ if (!ok) {
+ free_packet(p);
+ return NULL;
+ }
- num_good_receives++;
+ return p;
+}
- DEBUG(4,("%s received a packet of len %d from (%s) port %d\n",
- timestring(),length,inet_ntoa(packet->ip),packet->port));
+/*******************************************************************
+ read a packet from a socket and parse it, returning a packet ready
+ to be used or put on the queue. This assumes a UDP socket
+ ******************************************************************/
+struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+{
+ struct packet_struct *packet;
+ char buf[MAX_DGRAM_SIZE];
+ int length;
+
+ length = read_udp_socket(fd,buf,sizeof(buf));
+ if (length < MIN_DGRAM_SIZE) return(NULL);
+
+ packet = parse_packet(buf, length, packet_type);
+ if (!packet) return NULL;
- return(packet);
+ packet->fd = fd;
+
+ num_good_receives++;
+
+ DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+ length, inet_ntoa(packet->ip), packet->port ) );
+
+ return(packet);
}
@@ -425,20 +728,28 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
******************************************************************/
static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
{
- BOOL ret;
+ BOOL ret = False;
+ int i;
struct sockaddr_in sock_out;
/* set the address and port */
- bzero((char *)&sock_out,sizeof(sock_out));
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
putip((char *)&sock_out.sin_addr,(char *)&ip);
sock_out.sin_port = htons( port );
sock_out.sin_family = AF_INET;
- DEBUG(4,("%s sending a packet of len %d to (%s) on port %d\n",
- timestring(),len,inet_ntoa(ip),port));
+ DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
+ len, inet_ntoa(ip), port ) );
+
+ /*
+ * Patch to fix asynch error notifications from Linux kernel.
+ */
- ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
- sizeof(sock_out)) >= 0);
+ for (i = 0; i < 5; i++) {
+ ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0);
+ if (ret || errno != ECONNREFUSED)
+ break;
+ }
if (!ret)
DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
@@ -460,7 +771,7 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
static int build_dgram(char *buf,struct packet_struct *p)
{
struct dgram_packet *dgram = &p->packet.dgram;
- unsigned char *ubuf = (unsigned char *)buf;
+ uchar *ubuf = (uchar *)buf;
int offset=0;
/* put in the header */
@@ -494,15 +805,27 @@ static int build_dgram(char *buf,struct packet_struct *p)
/*******************************************************************
build a nmb name
- ******************************************************************/
-void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
+ *******************************************************************/
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
{
- strcpy(n->name,name);
- strupper(n->name);
- n->name_type = type;
- strcpy(n->scope,this_scope);
+ extern pstring global_scope;
+ memset( (char *)n, '\0', sizeof(struct nmb_name) );
+ push_ascii(n->name, name, 16, STR_TERMINATE|STR_UPPER);
+ n->name_type = (unsigned int)type & 0xFF;
+ StrnCpy( n->scope, global_scope, 63 );
+ strupper( n->scope );
}
+/*******************************************************************
+ Compare two nmb names
+ ******************************************************************/
+
+BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+{
+ return ((n1->name_type == n2->name_type) &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope));
+}
/*******************************************************************
build a nmb packet ready for sending
@@ -515,19 +838,22 @@ void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
static int build_nmb(char *buf,struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
- unsigned char *ubuf = (unsigned char *)buf;
+ uchar *ubuf = (uchar *)buf;
int offset=0;
/* put in the header */
RSSVAL(ubuf,offset,nmb->header.name_trn_id);
ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
if (nmb->header.response) ubuf[offset+2] |= (1<<7);
- if (nmb->header.nm_flags.authoritative) ubuf[offset+2] |= 0x4;
+ if (nmb->header.nm_flags.authoritative &&
+ nmb->header.response) ubuf[offset+2] |= 0x4;
if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
- if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80;
+ if (nmb->header.nm_flags.recursion_available &&
+ nmb->header.response) ubuf[offset+3] |= 0x80;
if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
RSSVAL(ubuf,offset+4,nmb->header.qdcount);
RSSVAL(ubuf,offset+6,nmb->header.ancount);
RSSVAL(ubuf,offset+8,nmb->header.nscount);
@@ -550,15 +876,52 @@ static int build_nmb(char *buf,struct packet_struct *p)
offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
nmb->header.nscount);
- if (nmb->header.arcount)
+ /*
+ * The spec says we must put compressed name pointers
+ * in the following outgoing packets :
+ * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
+ * NAME_RELEASE_REQUEST.
+ */
+
+ if((nmb->header.response == False) &&
+ ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
+ (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
+ (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
+ (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
+ (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
+ (nmb->header.arcount == 1)) {
+
+ offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12);
+
+ } else if (nmb->header.arcount) {
offset += put_res_rec((char *)ubuf,offset,nmb->additional,
nmb->header.arcount);
-
+ }
return(offset);
}
/*******************************************************************
+linearise a packet
+ ******************************************************************/
+int build_packet(char *buf, struct packet_struct *p)
+{
+ int len = 0;
+
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ len = build_nmb(buf,p);
+ break;
+
+ case DGRAM_PACKET:
+ len = build_dgram(buf,p);
+ break;
+ }
+
+ return len;
+}
+
+/*******************************************************************
send a packet_struct
******************************************************************/
BOOL send_packet(struct packet_struct *p)
@@ -566,18 +929,9 @@ BOOL send_packet(struct packet_struct *p)
char buf[1024];
int len=0;
- bzero(buf,sizeof(buf));
-
- switch (p->packet_type)
- {
- case NMB_PACKET:
- len = build_nmb(buf,p);
- break;
+ memset(buf,'\0',sizeof(buf));
- case DGRAM_PACKET:
- len = build_dgram(buf,p);
- break;
- }
+ len = build_packet(buf, p);
if (!len) return(False);
@@ -590,347 +944,327 @@ BOOL send_packet(struct packet_struct *p)
***************************************************************************/
struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
{
- fd_set fds;
- struct timeval timeout;
+ fd_set fds;
+ struct timeval timeout;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+ timeout.tv_sec = t/1000;
+ timeout.tv_usec = 1000*(t%1000);
+
+ if ((ret = sys_select_intr(fd+1,&fds,&timeout)) == -1) {
+ /* errno should be EBADF or EINVAL. */
+ DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno));
+ return NULL;
+ }
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
- timeout.tv_sec = t/1000;
- timeout.tv_usec = 1000*(t%1000);
+ if (ret == 0) /* timeout */
+ return NULL;
- sys_select(&fds,&timeout);
+ if (FD_ISSET(fd,&fds))
+ return(read_packet(fd,type));
+
+ return(NULL);
+}
- if (FD_ISSET(fd,&fds))
- return(read_packet(fd,type));
- return(NULL);
-}
+/****************************************************************************
+ receive a UDP/137 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified trn_id
+ The timeout is in milliseconds
+ ***************************************************************************/
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
+{
+ struct packet_struct *p;
+ p = receive_packet(fd, NMB_PACKET, t);
+
+ if (p && p->packet.nmb.header.response &&
+ p->packet.nmb.header.name_trn_id == trn_id) {
+ return p;
+ }
+ if (p) free_packet(p);
+
+ /* try the unexpected packet queue */
+ return receive_unexpected(NMB_PACKET, trn_id, NULL);
+}
/****************************************************************************
-interpret a node status response
-****************************************************************************/
-static void interpret_node_status(char *p, char *master,char *rname)
+ receive a UDP/138 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified mailslot name
+ The timeout is in milliseconds
+ ***************************************************************************/
+struct packet_struct *receive_dgram_packet(int fd, int t, char *mailslot_name)
{
- int level = (master||rname)?4:0;
- int numnames = CVAL(p,0);
- DEBUG(level,("received %d names\n",numnames));
+ struct packet_struct *p;
- if (rname) *rname = 0;
- if (master) *master = 0;
+ p = receive_packet(fd, DGRAM_PACKET, t);
- p += 1;
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- *flags = 0;
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- p += 16;
-
- if (p[0] & 0x80) strcat(flags,"<GROUP> ");
- if ((p[0] & 0x60) == 0) strcat(flags,"B ");
- if ((p[0] & 0x60) == 1) strcat(flags,"P ");
- if ((p[0] & 0x60) == 2) strcat(flags,"M ");
- if ((p[0] & 0x60) == 3) strcat(flags,"_ ");
- if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
- if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
- if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
- if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
-
- if (master && !*master && type == 0x1d) {
- StrnCpy(master,qname,15);
- trim_string(master,NULL," ");
- }
+ if (p && match_mailslot_name(p, mailslot_name)) {
+ return p;
+ }
+ if (p) free_packet(p);
- if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
- StrnCpy(rname,qname,15);
- trim_string(rname,NULL," ");
- }
-
- DEBUG(level,("\t%s (type=0x%x)\t%s\n",qname,type,flags));
- p+=2;
- }
- DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
+ /* try the unexpected packet queue */
+ return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
}
/****************************************************************************
- do a netbios name status query on a host
-
- the "master" parameter is a hack used for finding workgroups.
- **************************************************************************/
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)())
-{
- BOOL found=False;
- int retries = 2;
- int retry_time = 5000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = 0x21;
- nmb->question.question_class = 0x1;
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- GetTimeOfDay(&tval);
-
- if (!send_packet(&p))
- return(False);
+ see if a datagram has the right mailslot name
+***************************************************************************/
+BOOL match_mailslot_name(struct packet_struct *p, char *mailslot_name)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *buf;
- retries--;
+ buf = &dgram->data[0];
+ buf -= 4;
- while (1)
- {
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
- }
+ buf = smb_buf(buf);
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount ||
- nmb2->answers->rr_type != 0x21) {
- /* XXXX what do we do with this? could be a redirect, but
- we'll discard it for the moment */
- free_packet(p2);
- continue;
- }
-
- interpret_node_status(&nmb2->answers->rdata[0], master,rname);
- free_packet(p2);
- return(True);
+ if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+ return True;
}
- }
-
- DEBUG(0,("No status response (this is not unusual)\n"));
+ return False;
+}
+
+
+/****************************************************************************
+return the number of bits that match between two 4 character buffers
+ ***************************************************************************/
+static int matching_bits(uchar *p1, uchar *p2)
+{
+ int i, j, ret = 0;
+ for (i=0; i<4; i++) {
+ if (p1[i] != p2[i]) break;
+ ret += 8;
+ }
+
+ if (i==4) return ret;
+
+ for (j=0; j<8; j++) {
+ if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break;
+ ret++;
+ }
+
+ return ret;
+}
+
+
+static uchar sort_ip[4];
+
+/****************************************************************************
+compare two query reply records
+ ***************************************************************************/
+static int name_query_comp(uchar *p1, uchar *p2)
+{
+ return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip);
+}
+
+/****************************************************************************
+sort a set of 6 byte name query response records so that the IPs that
+have the most leading bits in common with the specified address come first
+ ***************************************************************************/
+void sort_query_replies(char *data, int n, struct in_addr ip)
+{
+ if (n <= 1) return;
+
+ putip(sort_ip, (char *)&ip);
- return(False);
+ qsort(data, n, 6, QSORT_CAST name_query_comp);
+}
+
+
+#define TRUNCATE_NETBIOS_NAME 1
+
+/*******************************************************************
+ convert, possibly using a stupid microsoft-ism which has destroyed
+ the transport independence of netbios (for CIFS vendors that usually
+ use the Win95-type methods, not for NT to NT communication, which uses
+ DCE/RPC and therefore full-length unicode strings...) a dns name into
+ a netbios name.
+
+ the netbios name (NOT necessarily null-terminated) is truncated to 15
+ characters.
+
+ ******************************************************************/
+char *dns_to_netbios_name(char *dns_name)
+{
+ static char netbios_name[16];
+ int i;
+ StrnCpy(netbios_name, dns_name, 15);
+ netbios_name[15] = 0;
+
+#ifdef TRUNCATE_NETBIOS_NAME
+ /* ok. this is because of a stupid microsoft-ism. if the called host
+ name contains a '.', microsoft clients expect you to truncate the
+ netbios name up to and including the '.' this even applies, by
+ mistake, to workgroup (domain) names, which is _really_ daft.
+ */
+ for (i = 15; i >= 0; i--)
+ {
+ if (netbios_name[i] == '.')
+ {
+ netbios_name[i] = 0;
+ break;
+ }
+ }
+#endif /* TRUNCATE_NETBIOS_NAME */
+
+ return netbios_name;
}
/****************************************************************************
- do a netbios name query to find someones IP
- ****************************************************************************/
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)())
-{
- BOOL found=False;
- int retries = 3;
- int retry_time = bcast?250:2000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = 0x20;
- nmb->question.question_class = 0x1;
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- GetTimeOfDay(&tval);
-
- if (!send_packet(&p))
- return(False);
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+ int ret;
+ int len = (*in++) / 2;
- retries--;
+ *out=0;
- while (1)
+ if (len > 30 || len<1) return(0);
+
+ while (len--)
{
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
+ if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+ *out = 0;
+ return(0);
}
-
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later
- (put it on the queue?) */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount) {
- /* XXXX what do we do with this? could be a redirect, but
- we'll discard it for the moment */
- free_packet(p2);
- continue;
- }
-
- if (ip) {
- putip((char *)ip,&nmb2->answers->rdata[2]);
- DEBUG(fn?3:2,("Got a positive name query response from %s",
- inet_ntoa(p2->ip)));
- DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
- }
- found=True; retries=0;
- free_packet(p2);
- if (fn) break;
- }
+ *out = ((in[0]-'A')<<4) + (in[1]-'A');
+ in += 2;
+ out++;
}
+ *out = 0;
+ ret = out[-1];
- return(found);
+#ifdef NETBIOS_SCOPE
+ /* Handle any scope names */
+ while(*in)
+ {
+ *out++ = '.'; /* Scope names are separated by periods */
+ len = *(uchar *)in++;
+ StrnCpy(out, in, len);
+ out += len;
+ *out=0;
+ in += len;
+ }
+#endif
+ return(ret);
}
-
/****************************************************************************
- construct and send a netbios DGRAM
-
- Note that this currently sends all answers to port 138. thats the
- wrong things to do! I should send to the requestors port. XXX
- **************************************************************************/
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip)
-{
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- char *ptr,*p2;
- char tmp[4];
-
- bzero((char *)&p,sizeof(p));
-
- dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = name_trn_id++;
- dgram->header.source_ip = src_ip;
- dgram->header.source_port = DGRAM_PORT;
- dgram->header.dgm_length = 0; /* let build_dgram() handle this */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,src_type,scope);
- make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
+mangle a name into netbios format
- ptr = &dgram->data[0];
+ Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
+****************************************************************************/
+int name_mangle( char *In, char *Out, char name_type )
+ {
+ int i;
+ int c;
+ int len;
+ char buf[20];
+ char *p = Out;
+ extern pstring global_scope;
+
+ /* Safely copy the input string, In, into buf[]. */
+ (void)memset( buf, 0, 20 );
+ if (strcmp(In,"*") == 0)
+ buf[0] = '*';
+ else
+ (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
- /* now setup the smb part */
- ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
- memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
- memcpy(ptr,tmp,4);
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
- CVAL(ptr,smb_com) = SMBtrans;
- SSVAL(ptr,smb_vwv1,len);
- SSVAL(ptr,smb_vwv11,len);
- SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
- SSVAL(ptr,smb_vwv13,3);
- SSVAL(ptr,smb_vwv14,1);
- SSVAL(ptr,smb_vwv15,1);
- SSVAL(ptr,smb_vwv16,2);
- p2 = smb_buf(ptr);
- strcpy(p2,mailslot);
- p2 = skip_string(p2,1);
+ /* Now convert the name to the rfc1001/1002 format. */
+ for( i = 0; i < 16; i++ )
+ {
+ c = toupper( buf[i] );
+ p[i*2] = ( (c >> 4) & 0x000F ) + 'A';
+ p[(i*2)+1] = (c & 0x000F) + 'A';
+ }
+ p += 32;
+ p[0] = '\0';
- memcpy(p2,buf,len);
- p2 += len;
+ /* Add the scope string. */
+ for( i = 0, len = 0; NULL != global_scope; i++, len++ )
+ {
+ switch( global_scope[i] )
+ {
+ case '\0':
+ p[0] = len;
+ if( len > 0 )
+ p[len+1] = 0;
+ return( name_len(Out) );
+ case '.':
+ p[0] = len;
+ p += (len + 1);
+ len = -1;
+ break;
+ default:
+ p[len+1] = global_scope[i];
+ break;
+ }
+ }
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
+ return( name_len(Out) );
+ } /* name_mangle */
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
- return(send_packet(&p));
-}
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+static char *name_ptr(char *buf,int ofs)
+{
+ uchar c = *(uchar *)(buf+ofs);
+
+ if ((c & 0xC0) == 0xC0)
+ {
+ uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+ DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+ return(buf + l);
+ }
+ else
+ return(buf+ofs);
+}
+/****************************************************************************
+extract a netbios name from a buf
+****************************************************************************/
+int name_extract(char *buf,int ofs,char *name)
+{
+ char *p = name_ptr(buf,ofs);
+ int d = PTR_DIFF(p,buf+ofs);
+ pstrcpy(name,"");
+ if (d < -50 || d > 50) return(0);
+ return(name_interpret(p,name));
+}
+
+/****************************************************************************
+return the total storage length of a mangled name
+****************************************************************************/
+int name_len(char *s1)
+{
+ /* NOTE: this argument _must_ be unsigned */
+ uchar *s = (uchar *)s1;
+ int len;
+
+ /* If the two high bits of the byte are set, return 2. */
+ if (0xC0 == (*s & 0xC0))
+ return(2);
+
+ /* Add up the length bytes. */
+ for (len = 1; (*s); s += (*s) + 1) {
+ len += *s + 1;
+ SMB_ASSERT(len < 80);
+ }
+ return(len);
+} /* name_len */
diff --git a/source/libsmb/nterr.c b/source/libsmb/nterr.c
new file mode 100644
index 00000000000..25286156ee3
--- /dev/null
+++ b/source/libsmb/nterr.c
@@ -0,0 +1,581 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+
+typedef const struct
+{
+ char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+nt_err_code_struct nt_errs[] =
+{
+ { "NT_STATUS_OK", NT_STATUS_OK },
+ { "NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL },
+ { "NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED },
+ { "NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS },
+ { "NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION },
+ { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW },
+ { "NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR },
+ { "NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA },
+ { "NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE },
+ { "NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK },
+ { "NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC },
+ { "NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID },
+ { "NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED },
+ { "NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER },
+ { "NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE },
+ { "NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE },
+ { "NT_STATUS_INVALID_DEVICE_REQUEST", NT_STATUS_INVALID_DEVICE_REQUEST },
+ { "NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE },
+ { "NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME },
+ { "NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE },
+ { "NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA },
+ { "NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR },
+ { "NT_STATUS_MORE_PROCESSING_REQUIRED", NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { "NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY },
+ { "NT_STATUS_CONFLICTING_ADDRESSES", NT_STATUS_CONFLICTING_ADDRESSES },
+ { "NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW },
+ { "NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM },
+ { "NT_STATUS_UNABLE_TO_DELETE_SECTION", NT_STATUS_UNABLE_TO_DELETE_SECTION },
+ { "NT_STATUS_INVALID_SYSTEM_SERVICE", NT_STATUS_INVALID_SYSTEM_SERVICE },
+ { "NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION },
+ { "NT_STATUS_INVALID_LOCK_SEQUENCE", NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { "NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE },
+ { "NT_STATUS_INVALID_FILE_FOR_SECTION", NT_STATUS_INVALID_FILE_FOR_SECTION },
+ { "NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED },
+ { "NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED },
+ { "NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL },
+ { "NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH },
+ { "NT_STATUS_NONCONTINUABLE_EXCEPTION", NT_STATUS_NONCONTINUABLE_EXCEPTION },
+ { "NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION },
+ { "NT_STATUS_UNWIND", NT_STATUS_UNWIND },
+ { "NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK },
+ { "NT_STATUS_INVALID_UNWIND_TARGET", NT_STATUS_INVALID_UNWIND_TARGET },
+ { "NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED },
+ { "NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR },
+ { "NT_STATUS_UNABLE_TO_DECOMMIT_VM", NT_STATUS_UNABLE_TO_DECOMMIT_VM },
+ { "NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED },
+ { "NT_STATUS_INVALID_PORT_ATTRIBUTES", NT_STATUS_INVALID_PORT_ATTRIBUTES },
+ { "NT_STATUS_PORT_MESSAGE_TOO_LONG", NT_STATUS_PORT_MESSAGE_TOO_LONG },
+ { "NT_STATUS_INVALID_PARAMETER_MIX", NT_STATUS_INVALID_PARAMETER_MIX },
+ { "NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER },
+ { "NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR },
+ { "NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID },
+ { "NT_STATUS_OBJECT_NAME_NOT_FOUND", NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { "NT_STATUS_OBJECT_NAME_COLLISION", NT_STATUS_OBJECT_NAME_COLLISION },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED },
+ { "NT_STATUS_DEVICE_ALREADY_ATTACHED", NT_STATUS_DEVICE_ALREADY_ATTACHED },
+ { "NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID },
+ { "NT_STATUS_OBJECT_PATH_NOT_FOUND", NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", NT_STATUS_OBJECT_PATH_SYNTAX_BAD },
+ { "NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN },
+ { "NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR },
+ { "NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR },
+ { "NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR },
+ { "NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG },
+ { "NT_STATUS_PORT_CONNECTION_REFUSED", NT_STATUS_PORT_CONNECTION_REFUSED },
+ { "NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE },
+ { "NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION },
+ { "NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED },
+ { "NT_STATUS_INVALID_PAGE_PROTECTION", NT_STATUS_INVALID_PAGE_PROTECTION },
+ { "NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED },
+ { "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED },
+ { "NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET },
+ { "NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE },
+ { "NT_STATUS_SUSPEND_COUNT_EXCEEDED", NT_STATUS_SUSPEND_COUNT_EXCEEDED },
+ { "NT_STATUS_THREAD_IS_TERMINATING", NT_STATUS_THREAD_IS_TERMINATING },
+ { "NT_STATUS_BAD_WORKING_SET_LIMIT", NT_STATUS_BAD_WORKING_SET_LIMIT },
+ { "NT_STATUS_INCOMPATIBLE_FILE_MAP", NT_STATUS_INCOMPATIBLE_FILE_MAP },
+ { "NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION },
+ { "NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED },
+ { "NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE },
+ { "NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY },
+ { "NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE },
+ { "NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR },
+ { "NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT },
+ { "NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED },
+ { "NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING },
+ { "NT_STATUS_CTL_FILE_NOT_SUPPORTED", NT_STATUS_CTL_FILE_NOT_SUPPORTED },
+ { "NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION },
+ { "NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH },
+ { "NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER },
+ { "NT_STATUS_INVALID_PRIMARY_GROUP", NT_STATUS_INVALID_PRIMARY_GROUP },
+ { "NT_STATUS_NO_IMPERSONATION_TOKEN", NT_STATUS_NO_IMPERSONATION_TOKEN },
+ { "NT_STATUS_CANT_DISABLE_MANDATORY", NT_STATUS_CANT_DISABLE_MANDATORY },
+ { "NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS },
+ { "NT_STATUS_NO_SUCH_LOGON_SESSION", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD },
+ { "NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS },
+ { "NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER },
+ { "NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS },
+ { "NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP },
+ { "NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP },
+ { "NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN },
+ { "NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD },
+ { "NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION },
+ { "NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE },
+ { "NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS },
+ { "NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION },
+ { "NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED },
+ { "NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED },
+ { "NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED },
+ { "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", NT_STATUS_TOO_MANY_LUIDS_REQUESTED },
+ { "NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_SUB_AUTHORITY", NT_STATUS_INVALID_SUB_AUTHORITY },
+ { "NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL },
+ { "NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID },
+ { "NT_STATUS_INVALID_SECURITY_DESCR", NT_STATUS_INVALID_SECURITY_DESCR },
+ { "NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT },
+ { "NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN },
+ { "NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL },
+ { "NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED },
+ { "NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL },
+ { "NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED },
+ { "NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED },
+ { "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", NT_STATUS_TOO_MANY_GUIDS_REQUESTED },
+ { "NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY },
+ { "NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED },
+ { "NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL },
+ { "NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED },
+ { "NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA },
+ { "NT_STATUS_RESOURCE_DATA_NOT_FOUND", NT_STATUS_RESOURCE_DATA_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", NT_STATUS_RESOURCE_TYPE_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NAME_NOT_FOUND", NT_STATUS_RESOURCE_NAME_NOT_FOUND },
+ { "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", NT_STATUS_ARRAY_BOUNDS_EXCEEDED },
+ { "NT_STATUS_FLOAT_DENORMAL_OPERAND", NT_STATUS_FLOAT_DENORMAL_OPERAND },
+ { "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO },
+ { "NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT },
+ { "NT_STATUS_FLOAT_INVALID_OPERATION", NT_STATUS_FLOAT_INVALID_OPERATION },
+ { "NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW },
+ { "NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK },
+ { "NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW },
+ { "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", NT_STATUS_INTEGER_DIVIDE_BY_ZERO },
+ { "NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW },
+ { "NT_STATUS_PRIVILEGED_INSTRUCTION", NT_STATUS_PRIVILEGED_INSTRUCTION },
+ { "NT_STATUS_TOO_MANY_PAGING_FILES", NT_STATUS_TOO_MANY_PAGING_FILES },
+ { "NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID },
+ { "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", NT_STATUS_ALLOTTED_SPACE_EXCEEDED },
+ { "NT_STATUS_INSUFFICIENT_RESOURCES", NT_STATUS_INSUFFICIENT_RESOURCES },
+ { "NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND },
+ { "NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR },
+ { "NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE },
+ { "NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED },
+ { "NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA },
+ { "NT_STATUS_MEDIA_WRITE_PROTECTED", NT_STATUS_MEDIA_WRITE_PROTECTED },
+ { "NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY },
+ { "NT_STATUS_INVALID_GROUP_ATTRIBUTES", NT_STATUS_INVALID_GROUP_ATTRIBUTES },
+ { "NT_STATUS_BAD_IMPERSONATION_LEVEL", NT_STATUS_BAD_IMPERSONATION_LEVEL },
+ { "NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS },
+ { "NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS },
+ { "NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE },
+ { "NT_STATUS_BAD_MASTER_BOOT_RECORD", NT_STATUS_BAD_MASTER_BOOT_RECORD },
+ { "NT_STATUS_INSTRUCTION_MISALIGNMENT", NT_STATUS_INSTRUCTION_MISALIGNMENT },
+ { "NT_STATUS_INSTANCE_NOT_AVAILABLE", NT_STATUS_INSTANCE_NOT_AVAILABLE },
+ { "NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE },
+ { "NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY },
+ { "NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION },
+ { "NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED },
+ { "NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING },
+ { "NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED },
+ { "NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING },
+ { "NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE },
+ { "NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT },
+ { "NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED },
+ { "NT_STATUS_PROFILING_NOT_STARTED", NT_STATUS_PROFILING_NOT_STARTED },
+ { "NT_STATUS_PROFILING_NOT_STOPPED", NT_STATUS_PROFILING_NOT_STOPPED },
+ { "NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET },
+ { "NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY },
+ { "NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED },
+ { "NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME },
+ { "NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH },
+ { "NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY },
+ { "NT_STATUS_DEVICE_DOES_NOT_EXIST", NT_STATUS_DEVICE_DOES_NOT_EXIST },
+ { "NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS },
+ { "NT_STATUS_ADAPTER_HARDWARE_ERROR", NT_STATUS_ADAPTER_HARDWARE_ERROR },
+ { "NT_STATUS_INVALID_NETWORK_RESPONSE", NT_STATUS_INVALID_NETWORK_RESPONSE },
+ { "NT_STATUS_UNEXPECTED_NETWORK_ERROR", NT_STATUS_UNEXPECTED_NETWORK_ERROR },
+ { "NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER },
+ { "NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL },
+ { "NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE },
+ { "NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED },
+ { "NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED },
+ { "NT_STATUS_NETWORK_ACCESS_DENIED", NT_STATUS_NETWORK_ACCESS_DENIED },
+ { "NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE },
+ { "NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME },
+ { "NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES },
+ { "NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS },
+ { "NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED },
+ { "NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED },
+ { "NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED },
+ { "NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT },
+ { "NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT },
+ { "NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE },
+ { "NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED },
+ { "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", NT_STATUS_VIRTUAL_CIRCUIT_CLOSED },
+ { "NT_STATUS_NO_SECURITY_ON_OBJECT", NT_STATUS_NO_SECURITY_ON_OBJECT },
+ { "NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT },
+ { "NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY },
+ { "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", NT_STATUS_CANT_ACCESS_DOMAIN_INFO },
+ { "NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF },
+ { "NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN },
+ { "NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS },
+ { "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED },
+ { "NT_STATUS_INVALID_OPLOCK_PROTOCOL", NT_STATUS_INVALID_OPLOCK_PROTOCOL },
+ { "NT_STATUS_INTERNAL_DB_CORRUPTION", NT_STATUS_INTERNAL_DB_CORRUPTION },
+ { "NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR },
+ { "NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED },
+ { "NT_STATUS_BAD_DESCRIPTOR_FORMAT", NT_STATUS_BAD_DESCRIPTOR_FORMAT },
+ { "NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER },
+ { "NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", NT_STATUS_UNEXPECTED_MM_CREATE_ERR },
+ { "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", NT_STATUS_UNEXPECTED_MM_MAP_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", NT_STATUS_UNEXPECTED_MM_EXTEND_ERR },
+ { "NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS },
+ { "NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS },
+ { "NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1 },
+ { "NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2 },
+ { "NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3 },
+ { "NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4 },
+ { "NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5 },
+ { "NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6 },
+ { "NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7 },
+ { "NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8 },
+ { "NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9 },
+ { "NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10 },
+ { "NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11 },
+ { "NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12 },
+ { "NT_STATUS_REDIRECTOR_NOT_STARTED", NT_STATUS_REDIRECTOR_NOT_STARTED },
+ { "NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED },
+ { "NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW },
+ { "NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE },
+ { "NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE },
+ { "NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { "NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR },
+ { "NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY },
+ { "NT_STATUS_BAD_LOGON_SESSION_STATE", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "NT_STATUS_LOGON_SESSION_COLLISION", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG },
+ { "NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN },
+ { "NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE },
+ { "NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND },
+ { "NT_STATUS_PROCESS_IS_TERMINATING", NT_STATUS_PROCESS_IS_TERMINATING },
+ { "NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE },
+ { "NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION },
+ { "NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE },
+ { "NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED },
+ { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT },
+ { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST },
+ { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED },
+ { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER },
+ { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND },
+ { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID },
+ { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE },
+ { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR },
+ { "NT_STATUS_NO_LDT", NT_STATUS_NO_LDT },
+ { "NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE },
+ { "NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET },
+ { "NT_STATUS_INVALID_LDT_DESCRIPTOR", NT_STATUS_INVALID_LDT_DESCRIPTOR },
+ { "NT_STATUS_INVALID_IMAGE_NE_FORMAT", NT_STATUS_INVALID_IMAGE_NE_FORMAT },
+ { "NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE },
+ { "NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE },
+ { "NT_STATUS_MAPPED_FILE_SIZE_ZERO", NT_STATUS_MAPPED_FILE_SIZE_ZERO },
+ { "NT_STATUS_TOO_MANY_OPENED_FILES", NT_STATUS_TOO_MANY_OPENED_FILES },
+ { "NT_STATUS_CANCELLED", NT_STATUS_CANCELLED },
+ { "NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE },
+ { "NT_STATUS_INVALID_COMPUTER_NAME", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED },
+ { "NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT },
+ { "NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP },
+ { "NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER },
+ { "NT_STATUS_MEMBERS_PRIMARY_GROUP", NT_STATUS_MEMBERS_PRIMARY_GROUP },
+ { "NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED },
+ { "NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS },
+ { "NT_STATUS_THREAD_NOT_IN_PROCESS", NT_STATUS_THREAD_NOT_IN_PROCESS },
+ { "NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE },
+ { "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", NT_STATUS_PAGEFILE_QUOTA_EXCEEDED },
+ { "NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT },
+ { "NT_STATUS_INVALID_IMAGE_LE_FORMAT", NT_STATUS_INVALID_IMAGE_LE_FORMAT },
+ { "NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ },
+ { "NT_STATUS_INVALID_IMAGE_PROTECT", NT_STATUS_INVALID_IMAGE_PROTECT },
+ { "NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16 },
+ { "NT_STATUS_LOGON_SERVER_CONFLICT", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "NT_STATUS_TIME_DIFFERENCE_AT_DC", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "NT_STATUS_SYNCHRONIZATION_REQUIRED", NT_STATUS_SYNCHRONIZATION_REQUIRED },
+ { "NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND },
+ { "NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED },
+ { "NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED },
+ { "NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT },
+ { "NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT },
+ { "NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT },
+ { "NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES },
+ { "NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED },
+ { "NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT },
+ { "NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION },
+ { "NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS },
+ { "NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED },
+ { "NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE },
+ { "NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION },
+ { "NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE },
+ { "NT_STATUS_PAGEFILE_CREATE_FAILED", NT_STATUS_PAGEFILE_CREATE_FAILED },
+ { "NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE },
+ { "NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL },
+ { "NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE },
+ { "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", NT_STATUS_ILLEGAL_FLOAT_CONTEXT },
+ { "NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN },
+ { "NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT },
+ { "NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED },
+ { "NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR },
+ { "NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME },
+ { "NT_STATUS_SERIAL_NO_DEVICE_INITED", NT_STATUS_SERIAL_NO_DEVICE_INITED },
+ { "NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS },
+ { "NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS },
+ { "NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS },
+ { "NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS },
+ { "NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED },
+ { "NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS },
+ { "NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG },
+ { "NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR },
+ { "NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE },
+ { "NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS },
+ { "NT_STATUS_LOGON_TYPE_NOT_GRANTED", NT_STATUS_LOGON_TYPE_NOT_GRANTED },
+ { "NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE },
+ { "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR },
+ { "NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER },
+ { "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", NT_STATUS_ILL_FORMED_SERVICE_ENTRY },
+ { "NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER },
+ { "NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER },
+ { "NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER },
+ { "NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME },
+ { "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND },
+ { "NT_STATUS_FLOPPY_WRONG_CYLINDER", NT_STATUS_FLOPPY_WRONG_CYLINDER },
+ { "NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR },
+ { "NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS },
+ { "NT_STATUS_DISK_RECALIBRATE_FAILED", NT_STATUS_DISK_RECALIBRATE_FAILED },
+ { "NT_STATUS_DISK_OPERATION_FAILED", NT_STATUS_DISK_OPERATION_FAILED },
+ { "NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED },
+ { "NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY },
+ { "NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING },
+ { "NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE },
+ { "NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH },
+ { "NT_STATUS_DEVICE_NOT_PARTITIONED", NT_STATUS_DEVICE_NOT_PARTITIONED },
+ { "NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA },
+ { "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", NT_STATUS_UNABLE_TO_UNLOAD_MEDIA },
+ { "NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW },
+ { "NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA },
+ { "NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER },
+ { "NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER },
+ { "NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED },
+ { "NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE },
+ { "NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS },
+ { "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN },
+ { "NT_STATUS_CHILD_MUST_BE_VOLATILE", NT_STATUS_CHILD_MUST_BE_VOLATILE },
+ { "NT_STATUS_DEVICE_CONFIGURATION_ERROR", NT_STATUS_DEVICE_CONFIGURATION_ERROR },
+ { "NT_STATUS_DRIVER_INTERNAL_ERROR", NT_STATUS_DRIVER_INTERNAL_ERROR },
+ { "NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE },
+ { "NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR },
+ { "NT_STATUS_DEVICE_PROTOCOL_ERROR", NT_STATUS_DEVICE_PROTOCOL_ERROR },
+ { "NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER },
+ { "NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL },
+ { "NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE },
+ { "NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "NT_STATUS_TRUSTED_DOMAIN_FAILURE", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "NT_STATUS_EVENTLOG_FILE_CORRUPT", NT_STATUS_EVENTLOG_FILE_CORRUPT },
+ { "NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START },
+ { "NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE },
+ { "NT_STATUS_MUTANT_LIMIT_EXCEEDED", NT_STATUS_MUTANT_LIMIT_EXCEEDED },
+ { "NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED },
+ { "NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK },
+ { "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "NT_STATUS_EVENTLOG_FILE_CHANGED", NT_STATUS_EVENTLOG_FILE_CHANGED },
+ { "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED },
+ { "NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY },
+ { "NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED },
+ { "NT_STATUS_RESOURCE_LANG_NOT_FOUND", NT_STATUS_RESOURCE_LANG_NOT_FOUND },
+ { "NT_STATUS_INSUFF_SERVER_RESOURCES", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE },
+ { "NT_STATUS_INVALID_ADDRESS_COMPONENT", NT_STATUS_INVALID_ADDRESS_COMPONENT },
+ { "NT_STATUS_INVALID_ADDRESS_WILDCARD", NT_STATUS_INVALID_ADDRESS_WILDCARD },
+ { "NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES },
+ { "NT_STATUS_ADDRESS_ALREADY_EXISTS", NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { "NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED },
+ { "NT_STATUS_CONNECTION_DISCONNECTED", NT_STATUS_CONNECTION_DISCONNECTED },
+ { "NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET },
+ { "NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES },
+ { "NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED },
+ { "NT_STATUS_TRANSACTION_TIMED_OUT", NT_STATUS_TRANSACTION_TIMED_OUT },
+ { "NT_STATUS_TRANSACTION_NO_RELEASE", NT_STATUS_TRANSACTION_NO_RELEASE },
+ { "NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH },
+ { "NT_STATUS_TRANSACTION_RESPONDED", NT_STATUS_TRANSACTION_RESPONDED },
+ { "NT_STATUS_TRANSACTION_INVALID_ID", NT_STATUS_TRANSACTION_INVALID_ID },
+ { "NT_STATUS_TRANSACTION_INVALID_TYPE", NT_STATUS_TRANSACTION_INVALID_TYPE },
+ { "NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION },
+ { "NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION },
+ { "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", NT_STATUS_CANNOT_LOAD_REGISTRY_FILE },
+ { "NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED },
+ { "NT_STATUS_SYSTEM_PROCESS_TERMINATED", NT_STATUS_SYSTEM_PROCESS_TERMINATED },
+ { "NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED },
+ { "NT_STATUS_NO_BROWSER_SERVERS_FOUND", NT_STATUS_NO_BROWSER_SERVERS_FOUND },
+ { "NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR },
+ { "NT_STATUS_DRIVER_CANCEL_TIMEOUT", NT_STATUS_DRIVER_CANCEL_TIMEOUT },
+ { "NT_STATUS_REPLY_MESSAGE_MISMATCH", NT_STATUS_REPLY_MESSAGE_MISMATCH },
+ { "NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT },
+ { "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", NT_STATUS_IMAGE_CHECKSUM_MISMATCH },
+ { "NT_STATUS_LOST_WRITEBEHIND_DATA", NT_STATUS_LOST_WRITEBEHIND_DATA },
+ { "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID },
+ { "NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND },
+ { "NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM },
+ { "NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE },
+ { "NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ },
+ { "NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK },
+ { "NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID },
+ { "NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS },
+ { "NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE },
+ { "NT_STATUS_RETRY", NT_STATUS_RETRY },
+ { "NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE },
+ { "NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET },
+ { "NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND },
+ { "NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW },
+ { "NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT },
+ { "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE },
+ { "NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED },
+ { "NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT },
+ { "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", NT_STATUS_ADDRESS_ALREADY_ASSOCIATED },
+ { "NT_STATUS_ADDRESS_NOT_ASSOCIATED", NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+ { "NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID },
+ { "NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE },
+ { "NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE },
+ { "NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE },
+ { "NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE },
+ { "NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE },
+ { "NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED },
+ { "NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED },
+ { "NT_STATUS_BAD_COMPRESSION_BUFFER", NT_STATUS_BAD_COMPRESSION_BUFFER },
+ { "NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE },
+ { "NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED },
+ { "NT_STATUS_TIMER_RESOLUTION_NOT_SET", NT_STATUS_TIMER_RESOLUTION_NOT_SET },
+ { "NT_STATUS_CONNECTION_COUNT_LIMIT", NT_STATUS_CONNECTION_COUNT_LIMIT },
+ { "NT_STATUS_LOGIN_TIME_RESTRICTION", NT_STATUS_LOGIN_TIME_RESTRICTION },
+ { "NT_STATUS_LOGIN_WKSTA_RESTRICTION", NT_STATUS_LOGIN_WKSTA_RESTRICTION },
+ { "NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH },
+ { "NT_STATUS_INSUFFICIENT_LOGON_INFO", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+ { "NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT },
+ { "NT_STATUS_BAD_SERVICE_ENTRYPOINT", NT_STATUS_BAD_SERVICE_ENTRYPOINT },
+ { "NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1 },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2 },
+ { "NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT },
+ { "NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED },
+ { "NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE },
+ { "NT_STATUS_LICENSE_QUOTA_EXCEEDED", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+ { "NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT },
+ { "NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT },
+ { "NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE },
+ { "NT_STATUS_UNSUPPORTED_COMPRESSION", NT_STATUS_UNSUPPORTED_COMPRESSION },
+ { "NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE },
+ { "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH },
+ { "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", NT_STATUS_DRIVER_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED },
+ { "NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS },
+ { "NT_STATUS_QUOTA_LIST_INCONSISTENT", NT_STATUS_QUOTA_LIST_INCONSISTENT },
+ { "NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE },
+ { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES },
+ { NULL, NT_STATUS(0) }
+};
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+char *get_nt_error_msg(NTSTATUS nt_code)
+{
+ static pstring msg;
+ int idx = 0;
+
+ slprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ return msg;
+}
+
+/*****************************************************************************
+ returns an NT_STATUS constant as a string for inclusion in autogen C code
+ *****************************************************************************/
+char *get_nt_error_c_code(NTSTATUS nt_code)
+{
+ static pstring out;
+ int idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ slprintf(out, sizeof(out), "NT_STATUS(0x%08x)", NT_STATUS_V(nt_code));
+
+ return out;
+}
diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c
new file mode 100644
index 00000000000..335d9a7d1ab
--- /dev/null
+++ b/source/libsmb/passchange.c
@@ -0,0 +1,102 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client password change routine
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+extern pstring global_myname;
+
+/*************************************************************
+change a password on a remote machine using IPC calls
+*************************************************************/
+BOOL remote_password_change(const char *remote_machine, const char *user_name,
+ const char *old_passwd, const char *new_passwd,
+ char *err_str, size_t err_str_len)
+{
+ struct nmb_name calling, called;
+ struct cli_state cli;
+ struct in_addr ip;
+
+ *err_str = '\0';
+
+ if(!resolve_name( remote_machine, &ip, 0x20)) {
+ slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n",
+ remote_machine );
+ return False;
+ }
+
+ ZERO_STRUCT(cli);
+
+ if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
+ slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ return False;
+ }
+
+ make_nmb_name(&calling, global_myname , 0x0);
+ make_nmb_name(&called , remote_machine, 0x20);
+
+ if (!cli_session_request(&cli, &calling, &called)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /*
+ * We should connect as the anonymous user here, in case
+ * the server has "must change password" checked...
+ * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli_shutdown(&cli);
+ return True;
+}
diff --git a/source/libsmb/pwd_cache.c b/source/libsmb/pwd_cache.c
new file mode 100644
index 00000000000..94045882238
--- /dev/null
+++ b/source/libsmb/pwd_cache.c
@@ -0,0 +1,250 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password cacheing. obfuscation is planned
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Initialises a password structure.
+****************************************************************************/
+
+void pwd_init(struct pwd_info *pwd)
+{
+ memset((char *)pwd->password , '\0', sizeof(pwd->password ));
+ memset((char *)pwd->smb_lm_pwd, '\0', sizeof(pwd->smb_lm_pwd));
+ memset((char *)pwd->smb_nt_pwd, '\0', sizeof(pwd->smb_nt_pwd));
+ memset((char *)pwd->smb_lm_owf, '\0', sizeof(pwd->smb_lm_owf));
+ memset((char *)pwd->smb_nt_owf, '\0', sizeof(pwd->smb_nt_owf));
+
+ pwd->null_pwd = True; /* safest option... */
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Returns NULL password flag.
+****************************************************************************/
+
+BOOL pwd_is_nullpwd(const struct pwd_info *pwd)
+{
+ return pwd->null_pwd;
+}
+
+/****************************************************************************
+ Compares two passwords. hmm, not as trivial as expected. hmm.
+****************************************************************************/
+
+BOOL pwd_compare(const struct pwd_info *pwd1, const struct pwd_info *pwd2)
+{
+ if (pwd1->cleartext && pwd2->cleartext) {
+ if (strequal(pwd1->password, pwd2->password))
+ return True;
+ }
+ if (pwd1->null_pwd && pwd2->null_pwd)
+ return True;
+
+ if (!pwd1->null_pwd && !pwd2->null_pwd &&
+ !pwd1->cleartext && !pwd2->cleartext) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("pwd compare: nt#\n"));
+ dump_data(100, pwd1->smb_nt_pwd, 16);
+ dump_data(100, pwd2->smb_nt_pwd, 16);
+#endif
+ if (memcmp(pwd1->smb_nt_pwd, pwd2->smb_nt_pwd, 16) == 0)
+ return True;
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("pwd compare: lm#\n"));
+ dump_data(100, pwd1->smb_lm_pwd, 16);
+ dump_data(100, pwd2->smb_lm_pwd, 16);
+#endif
+ if (memcmp(pwd1->smb_lm_pwd, pwd2->smb_lm_pwd, 16) == 0)
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Reads a password.
+****************************************************************************/
+
+void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt)
+{
+ /* grab a password */
+ char *user_pass;
+
+ pwd_init(pwd);
+
+ user_pass = (char*)getpass(passwd_report);
+
+ /*
+ * Do not assume that an empty string is a NULL password.
+ * If you do this will break the session key generation for
+ * and account with an emtpy password. If you wish to use
+ * a NULL password, use the -N option to smbclient and rpcclient
+ * --jerry
+ */
+#if 0
+ if (user_pass == NULL || user_pass[0] == 0)
+ pwd_set_nullpwd(pwd);
+ else if (do_encrypt)
+#endif
+ if (do_encrypt)
+ pwd_make_lm_nt_16(pwd, user_pass);
+ else
+ pwd_set_cleartext(pwd, user_pass);
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_nullpwd(struct pwd_info *pwd)
+{
+ pwd_init(pwd);
+
+ pwd->cleartext = False;
+ pwd->null_pwd = True;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_cleartext(struct pwd_info *pwd, char *clr)
+{
+ pwd_init(pwd);
+ push_ascii_fstring(pwd->password, clr);
+ pwd->cleartext = True;
+ pwd->null_pwd = False;
+ pwd->crypted = False;
+ pwd_make_lm_nt_16(pwd, clr);
+}
+
+/****************************************************************************
+ Gets a cleartext password.
+****************************************************************************/
+
+void pwd_get_cleartext(struct pwd_info *pwd, char *clr)
+{
+ if (pwd->cleartext)
+ fstrcpy(clr, pwd->password);
+ else
+ clr[0] = 0;
+
+}
+
+/****************************************************************************
+ Stores lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_set_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16])
+{
+ pwd_init(pwd);
+
+ if (lm_pwd)
+ memcpy(pwd->smb_lm_pwd, lm_pwd, 16);
+ else
+ memset((char *)pwd->smb_lm_pwd, '\0', 16);
+
+ if (nt_pwd)
+ memcpy(pwd->smb_nt_pwd, nt_pwd, 16);
+ else
+ memset((char *)pwd->smb_nt_pwd, '\0', 16);
+
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Gets lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16])
+{
+ if (lm_pwd != NULL)
+ memcpy(lm_pwd, pwd->smb_lm_pwd, 16);
+ if (nt_pwd != NULL)
+ memcpy(nt_pwd, pwd->smb_nt_pwd, 16);
+}
+
+/****************************************************************************
+ Makes lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr)
+{
+ pstring dos_passwd;
+
+ pwd_init(pwd);
+
+ push_ascii_pstring(dos_passwd, clr);
+
+ nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Makes lm and nt OWF crypts.
+****************************************************************************/
+
+void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8])
+{
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("client cryptkey: "));
+ dump_data(100, (char *)cryptkey, 8);
+#endif
+
+ SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_owf_passwd: "));
+ dump_data(100, (char *)pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf));
+ DEBUG(100,("nt_sess_pwd: "));
+ dump_data(100, (char *)pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd));
+#endif
+
+ SMBOWFencrypt(pwd->smb_lm_pwd, cryptkey, pwd->smb_lm_owf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm_owf_passwd: "));
+ dump_data(100, (char *)pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf));
+ DEBUG(100,("lm_sess_pwd: "));
+ dump_data(100, (char *)pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd));
+#endif
+
+ pwd->crypted = True;
+}
+
+/****************************************************************************
+ Gets lm and nt crypts.
+****************************************************************************/
+
+void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24])
+{
+ if (lm_owf != NULL)
+ memcpy(lm_owf, pwd->smb_lm_owf, 24);
+ if (nt_owf != NULL)
+ memcpy(nt_owf, pwd->smb_nt_owf, 24);
+}
diff --git a/source/libsmb/smbdes.c b/source/libsmb/smbdes.c
new file mode 100644
index 00000000000..866fc0c7e0b
--- /dev/null
+++ b/source/libsmb/smbdes.c
@@ -0,0 +1,416 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+
+
+#define uchar unsigned char
+
+static uchar perm1[56] = {57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4};
+
+static uchar perm2[48] = {14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32};
+
+static uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7};
+
+static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1};
+
+static uchar perm5[32] = { 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25};
+
+
+static uchar perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static uchar sbox[8][4][16] = {
+ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void permute(char *out, char *in, uchar *p, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in[p[i]-1];
+}
+
+static void lshift(char *d, int count, int n)
+{
+ char out[64];
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = d[(i+count)%n];
+ for (i=0;i<n;i++)
+ d[i] = out[i];
+}
+
+static void concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+ while (l1--)
+ *out++ = *in1++;
+ while (l2--)
+ *out++ = *in2++;
+}
+
+static void xor(char *out, char *in1, char *in2, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void dohash(char *out, char *in, char *key, int forw)
+{
+ int i, j, k;
+ char pk1[56];
+ char c[28];
+ char d[28];
+ char cd[56];
+ char ki[16][48];
+ char pd1[64];
+ char l[32], r[32];
+ char rl[64];
+
+ permute(pk1, key, perm1, 56);
+
+ for (i=0;i<28;i++)
+ c[i] = pk1[i];
+ for (i=0;i<28;i++)
+ d[i] = pk1[i+28];
+
+ for (i=0;i<16;i++) {
+ lshift(c, sc[i], 28);
+ lshift(d, sc[i], 28);
+
+ concat(cd, c, d, 28, 28);
+ permute(ki[i], cd, perm2, 48);
+ }
+
+ permute(pd1, in, perm3, 64);
+
+ for (j=0;j<32;j++) {
+ l[j] = pd1[j];
+ r[j] = pd1[j+32];
+ }
+
+ for (i=0;i<16;i++) {
+ char er[48];
+ char erk[48];
+ char b[8][6];
+ char cb[32];
+ char pcb[32];
+ char r2[32];
+
+ permute(er, r, perm4, 48);
+
+ xor(erk, er, ki[forw ? i : 15 - i], 48);
+
+ for (j=0;j<8;j++)
+ for (k=0;k<6;k++)
+ b[j][k] = erk[j*6 + k];
+
+ for (j=0;j<8;j++) {
+ int m, n;
+ m = (b[j][0]<<1) | b[j][5];
+
+ n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
+
+ for (k=0;k<4;k++)
+ b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
+ }
+
+ for (j=0;j<8;j++)
+ for (k=0;k<4;k++)
+ cb[j*4+k] = b[j][k];
+ permute(pcb, cb, perm5, 32);
+
+ xor(r2, l, pcb, 32);
+
+ for (j=0;j<32;j++)
+ l[j] = r[j];
+
+ for (j=0;j<32;j++)
+ r[j] = r2[j];
+ }
+
+ concat(rl, r, l, 32, 32);
+
+ permute(out, rl, perm6, 64);
+}
+
+static void str_to_key(const unsigned char *str,unsigned char *key)
+{
+ int i;
+
+ key[0] = str[0]>>1;
+ key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+ key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+ key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+ key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+ key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+ key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+ key[7] = str[6]&0x7F;
+ for (i=0;i<8;i++) {
+ key[i] = (key[i]<<1);
+ }
+}
+
+
+static void smbhash(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw)
+{
+ int i;
+ char outb[64];
+ char inb[64];
+ char keyb[64];
+ unsigned char key2[8];
+
+ str_to_key(key, key2);
+
+ for (i=0;i<64;i++) {
+ inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb, forw);
+
+ for (i=0;i<8;i++) {
+ out[i] = 0;
+ }
+
+ for (i=0;i<64;i++) {
+ if (outb[i])
+ out[i/8] |= (1<<(7-(i%8)));
+ }
+}
+
+void E_P16(const unsigned char *p14,unsigned char *p16)
+{
+ unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ smbhash(p16, sp8, p14, 1);
+ smbhash(p16+8, sp8, p14+7, 1);
+}
+
+void E_P24(const unsigned char *p21, const unsigned char *c8, unsigned char *p24)
+{
+ smbhash(p24, c8, p21, 1);
+ smbhash(p24+8, c8, p21+7, 1);
+ smbhash(p24+16, c8, p21+14, 1);
+}
+
+void D_P16(const unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 0);
+ smbhash(out+8, in+8, p14+7, 0);
+}
+
+void E_old_pw_hash( unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 1);
+ smbhash(out+8, in+8, p14+7, 1);
+}
+
+void cred_hash1(unsigned char *out, const unsigned char *in,unsigned char *key)
+{
+ unsigned char buf[8];
+
+ smbhash(buf, in, key, 1);
+ smbhash(out, buf, key+9, 1);
+}
+
+void cred_hash2(unsigned char *out, const unsigned char *in,unsigned char *key)
+{
+ unsigned char buf[8];
+ static unsigned char key2[8];
+
+ smbhash(buf, in, key, 1);
+ key2[0] = key[7];
+ smbhash(out, buf, key2, 1);
+}
+
+void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw)
+{
+ static unsigned char key2[8];
+
+ smbhash(out, in, key, forw);
+ key2[0] = key[7];
+ smbhash(out + 8, in + 8, key2, forw);
+}
+
+void SamOEMhash( unsigned char *data, const unsigned char *key, int val)
+{
+ unsigned char s_box[256];
+ unsigned char index_i = 0;
+ unsigned char index_j = 0;
+ unsigned char j = 0;
+ int ind;
+
+ for (ind = 0; ind < 256; ind++)
+ {
+ s_box[ind] = (unsigned char)ind;
+ }
+
+ for( ind = 0; ind < 256; ind++)
+ {
+ unsigned char tc;
+
+ j += (s_box[ind] + key[ind%16]);
+
+ tc = s_box[ind];
+ s_box[ind] = s_box[j];
+ s_box[j] = tc;
+ }
+ for( ind = 0; ind < val; ind++)
+ {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += s_box[index_i];
+
+ tc = s_box[index_i];
+ s_box[index_i] = s_box[index_j];
+ s_box[index_j] = tc;
+
+ t = s_box[index_i] + s_box[index_j];
+ data[ind] = data[ind] ^ s_box[t];
+ }
+}
+
+/* Decode a sam password hash into a password. The password hash is the
+ same method used to store passwords in the NT registry. The DES key
+ used is based on the RID of the user. */
+
+void sam_pwd_hash(unsigned int rid, const uchar *in, uchar *out, int forw)
+{
+ uchar s[14];
+
+ s[0] = s[4] = s[8] = s[12] = (uchar)(rid & 0xFF);
+ s[1] = s[5] = s[9] = s[13] = (uchar)((rid >> 8) & 0xFF);
+ s[2] = s[6] = s[10] = (uchar)((rid >> 16) & 0xFF);
+ s[3] = s[7] = s[11] = (uchar)((rid >> 24) & 0xFF);
+
+ smbhash(out, in, s, forw);
+ smbhash(out+8, in+8, s+7, forw);
+}
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index a0683b5d282..b0fecd1c192 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -1,10 +1,11 @@
-#ifdef SMB_PASSWD
/*
Unix SMB/Netbios implementation.
Version 1.9.
SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
Modified by Jeremy Allison 1995.
+ Copyright (C) Jeremy Allison 1995-2000.
+ Copyright (C) Luke Kennethc Casson Leighton 1996-2000.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,181 +23,322 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "des.h"
-#include "md4.h"
-
-extern int DEBUGLEVEL;
-
-#ifndef uchar
-#define uchar unsigned char
-#endif
-#ifndef int16
-#define int16 unsigned short
-#endif
-#ifndef uint16
-#define uint16 unsigned short
-#endif
-#ifndef uint32
-#define uint32 unsigned int
-#endif
-
#include "byteorder.h"
-void str_to_key(uchar *str,uchar *key)
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password, a 8 byte "crypt key" and puts 24 bytes of
+ encrypted password into p24 */
+void SMBencrypt(const uchar *passwd, const uchar *c8, uchar *p24)
{
- void des_set_odd_parity(des_cblock *);
- int i;
-
- key[0] = str[0]>>1;
- key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
- key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
- key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
- key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
- key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
- key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
- key[7] = str[6]&0x7F;
- for (i=0;i<8;i++) {
- key[i] = (key[i]<<1);
- }
- des_set_odd_parity((des_cblock *)key);
-}
+ uchar p14[15], p21[21];
-void D1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
+ memset(p21,'\0',21);
+ memset(p14,'\0',14);
+ StrnCpy((char *)p14,(const char *)passwd,14);
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_DECRYPT);
-}
+ strupper((char *)p14);
+ E_P16(p14, p21);
-void E1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
+ SMBOWFencrypt(p21, c8, p24);
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_ENCRYPT);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
+ dump_data(100, (char *)p21, 16);
+ dump_data(100, (const char *)c8, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
}
+
+/*
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
-void E_P16(uchar *p14,uchar *p16)
+void E_md4hash(const uchar *passwd, uchar *p16)
{
- uchar sp7[7];
- /* the following constant makes us compatible with other
- implementations. Note that publishing this constant does not reduce the
- security of the encryption mechanism */
- uchar sp8[] = {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE};
- uchar x[8];
-
- memset(sp7,'\0',7);
-
- D1(sp7, sp8, x);
- E1(p14, x, p16);
- E1(p14+7, x, p16+8);
+ int len;
+ smb_ucs2_t wpwd[129];
+
+ /* Password cannot be longer than 128 characters */
+ len = strlen((const char *)passwd);
+ if(len > 128)
+ len = 128;
+ /* Password must be converted to NT unicode - null terminated. */
+ push_ucs2(NULL, wpwd, (const char *)passwd, 256, STR_UNICODE|STR_NOALIGN|STR_TERMINATE);
+ /* Calculate length in bytes */
+ len = strlen_w(wpwd) * sizeof(int16);
+
+ mdfour(p16, (unsigned char *)wpwd, len);
}
-void E_P24(uchar *p21, uchar *c8, uchar *p24)
+/* Does both the NT and LM owfs of a user's password */
+void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16])
{
- E1(p21, c8, p24);
- E1(p21+7, c8, p24+8);
- E1(p21+14, c8, p24+16);
-}
+ char passwd[514];
+ memset(passwd,'\0',514);
+ safe_strcpy( passwd, pwd, sizeof(passwd)-1);
-/*
- This implements the X/Open SMB password encryption
- It takes a password, a 8 byte "crypt key" and puts 24 bytes of
- encrypted password into p24 */
-void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
-{
- uchar p14[15], p21[21];
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash((uchar *)passwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
+ dump_data(120, passwd, strlen(passwd));
+ dump_data(100, (char *)nt_p16, 16);
+#endif
- memset(p21,'\0',21);
- memset(p14,'\0',14);
- StrnCpy((char *)p14,(char *)passwd,14);
+ /* Mangle the passwords into Lanman format */
+ passwd[14] = '\0';
+ strupper(passwd);
- strupper((char *)p14);
- E_P16(p14, p21);
- E_P24(p21, c8, p24);
+ /* Calculate the SMB (lanman) hash functions of the password */
+
+ memset(p16, '\0', 16);
+ E_P16((uchar *) passwd, (uchar *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, passwd, strlen(passwd));
+ dump_data(100, (char *)p16, 16);
+#endif
+ /* clear out local copy of user's password (just being paranoid). */
+ memset(passwd, '\0', sizeof(passwd));
}
-/* Routines for Windows NT MD4 Hash functions. */
-static int _my_wcslen(int16 *str)
+/* Does both the NTLMv2 owfs of a user's password */
+void ntv2_owf_gen(const uchar owf[16],
+ const char *user_n, const char *domain_n, uchar kr_buf[16])
{
- int len = 0;
- while(*str++ != 0)
- len++;
- return len;
+ pstring user_u;
+ pstring dom_u;
+ HMACMD5Context ctx;
+
+ int user_l = strlen(user_n);
+ int domain_l = strlen(domain_n);
+
+ push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+ push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+
+ hmac_md5_init_limK_to_64(owf, 16, &ctx);
+ hmac_md5_update((const unsigned char *)user_u, user_l * 2, &ctx);
+ hmac_md5_update((const unsigned char *)dom_u, domain_l * 2, &ctx);
+ hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, user_u, user_l * 2);
+ dump_data(100, dom_u, domain_l * 2);
+ dump_data(100, owf, 16);
+ dump_data(100, kr_buf, 16);
+#endif
}
-/*
- * Convert a string into an NT UNICODE string.
- * Note that regardless of processor type
- * this must be in intel (little-endian)
- * format.
- */
-
-static int _my_mbstowcs(int16 *dst, uchar *src, int len)
+/* Does the des encryption from the NT or LM MD4 hash. */
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
{
- int i;
- int16 val;
+ uchar p21[21];
- for(i = 0; i < len; i++) {
- val = *src;
- SSVAL(dst,0,val);
- dst++;
- src++;
- if(val == 0)
- break;
- }
- return i;
+ memset(p21,'\0',21);
+
+ memcpy(p21, passwd, 16);
+ E_P24(p21, c8, p24);
}
-/*
- * Creates the MD4 Hash of the users password in NT UNICODE.
- */
-
-void E_md4hash(uchar *passwd, uchar *p16)
+/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+void NTLMSSPOWFencrypt(const uchar passwd[8], const uchar *ntlmchalresp, uchar p24[24])
{
- int i, len;
- int16 wpwd[129];
- MDstruct MD;
-
- /* Password cannot be longer than 128 characters */
- len = strlen(passwd);
- if(len > 128)
- len = 128;
- /* Password must be converted to NT unicode */
- _my_mbstowcs( wpwd, passwd, len);
- wpwd[len] = 0; /* Ensure string is null terminated */
- /* Calculate length in bytes */
- len = _my_wcslen(wpwd) * sizeof(int16);
+ uchar p21[21];
- MDbegin(&MD);
- for(i = 0; i + 64 <= len; i += 64)
- MDupdate(&MD,wpwd + (i/2), 512);
- MDupdate(&MD,wpwd + (i/2),(len-i)*8);
- SIVAL(p16,0,MD.buffer[0]);
- SIVAL(p16,4,MD.buffer[1]);
- SIVAL(p16,8,MD.buffer[2]);
- SIVAL(p16,12,MD.buffer[3]);
+ memset(p21,'\0',21);
+ memcpy(p21, passwd, 8);
+ memset(p21 + 8, 0xbd, 8);
+
+ E_P24(p21, ntlmchalresp, p24);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
+ dump_data(100, (char *)p21, 21);
+ dump_data(100, (const char *)ntlmchalresp, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
}
+
/* Does the NT MD4 hash then des encryption. */
-void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
+void SMBNTencrypt(const uchar *passwd, uchar *c8, uchar *p24)
{
uchar p21[21];
memset(p21,'\0',21);
E_md4hash(passwd, p21);
- E_P24(p21, c8, p24);
+ SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
+ dump_data(100, (char *)p21, 16);
+ dump_data(100, (char *)c8, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
+}
+
+BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
+{
+ int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
+
+ if (new_pw_len > 512)
+ {
+ DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
+ return False;
+ }
+
+ /*
+ * Now setup the data area.
+ * We need to generate a random fill
+ * for this area to make it harder to
+ * decrypt. JRA.
+ */
+ generate_random_buffer((unsigned char *)data, 516, False);
+ push_string(NULL, &data[512 - new_pw_len], passwd, new_pw_len,
+ STR_NOALIGN | (unicode?STR_UNICODE:STR_ASCII));
+ SIVAL(data, 512, new_pw_len);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("make_oem_passwd_hash\n"));
+ dump_data(100, data, 516);
+#endif
+ SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
+
+ return True;
+}
+
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void SMBOWFencrypt_ntv2(const uchar kr[16],
+ const DATA_BLOB srv_chal,
+ const DATA_BLOB cli_chal,
+ char resp_buf[16])
+{
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
+ hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
+ hmac_md5_final((unsigned char *)resp_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
+ dump_data(100, srv_chal.data, srv_chal.length);
+ dump_data(100, cli_chal.data, cli_chal.length);
+ dump_data(100, resp_buf, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv2(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(nt_resp, 16, &ctx);
+ hmac_md5_final((unsigned char *)sess_key, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv1(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ mdfour((unsigned char *)sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
}
-#else
-void smbencrypt_dummy(void){}
+/***********************************************************
+ encode a password buffer. The caller gets to figure out
+ what to put in it.
+************************************************************/
+BOOL encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length)
+{
+ generate_random_buffer((unsigned char *)buffer, 516, True);
+
+ memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length);
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ SIVAL(buffer, 512, new_pw_length);
+
+ return True;
+}
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd,
+ int new_pwrd_size, uint32 *new_pw_len)
+{
+ int byte_len=0;
+
+ /*
+ Warning !!! : This function is called from some rpc call.
+ The password IN the buffer is a UNICODE string.
+ The password IN new_pwrd is an ASCII string
+ If you reuse that code somewhere else check first.
+ */
+
+ /* The length of the new password is in the last 4 bytes of the data buffer. */
+
+ byte_len = IVAL(in_buffer, 512);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, in_buffer, 516);
#endif
+
+ /* Password cannot be longer than 128 characters */
+ if ( (byte_len < 0) || (byte_len > new_pwrd_size - 1)) {
+ DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len));
+ DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n"));
+ return False;
+ }
+
+ /* decode into the return buffer. Buffer must be a pstring */
+ *new_pw_len = pull_string(NULL, new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size, byte_len, STR_UNICODE);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decode_pw_buffer: new_pwrd: "));
+ dump_data(100, (char *)new_pwrd, *new_pw_len);
+ DEBUG(100,("multibyte len:%d\n", *new_pw_len));
+ DEBUG(100,("original char len:%d\n", byte_len/2));
+#endif
+
+ return True;
+
+}
+
+/* Calculate the NT owfs of a user's password */
+void nt_owf_genW(const UNISTR2 *pwd, uchar nt_p16[16])
+{
+ char buf[512];
+ int i;
+
+ for (i = 0; i < MIN(pwd->uni_str_len, sizeof(buf) / 2); i++)
+ {
+ SIVAL(buf, i * 2, pwd->buffer[i]);
+ }
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ mdfour(nt_p16, (const unsigned char *)buf, pwd->uni_str_len * 2);
+
+ /* clear out local copy of user's password (just being paranoid). */
+ ZERO_STRUCT(buf);
+}
diff --git a/source/libsmb/smberr.c b/source/libsmb/smberr.c
new file mode 100644
index 00000000000..71e609ff3a7
--- /dev/null
+++ b/source/libsmb/smberr.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+
+/* There is a big list of error codes and their meanings at:
+
+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/errlist_7oz7.asp
+
+ and if you don't like MSDN try:
+
+ http://www.siris.gr/computers/library/error.htm
+
+*/
+
+typedef const struct
+{
+ char *name;
+ int code;
+ char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+err_code_struct dos_msgs[] = {
+ {"ERRbadfunc",ERRbadfunc,"Invalid function."},
+ {"ERRbadfile",ERRbadfile,"File not found."},
+ {"ERRbadpath",ERRbadpath,"Directory invalid."},
+ {"ERRnofids",ERRnofids,"No file descriptors available"},
+ {"ERRnoaccess",ERRnoaccess,"Access denied."},
+ {"ERRbadfid",ERRbadfid,"Invalid file handle."},
+ {"ERRbadmcb",7,"Memory control blocks destroyed."},
+ {"ERRnomem",ERRnomem,"Insufficient server memory to perform the requested function."},
+ {"ERRbadmem",ERRbadmem,"Invalid memory block address."},
+ {"ERRbadenv",ERRbadenv,"Invalid environment."},
+ {"ERRbadformat",11,"Invalid format."},
+ {"ERRbadaccess",ERRbadaccess,"Invalid open mode."},
+ {"ERRbaddata",ERRbaddata,"Invalid data."},
+ {"ERR",ERRres,"reserved."},
+ {"ERRbaddrive",ERRbaddrive,"Invalid drive specified."},
+ {"ERRremcd",ERRremcd,"A Delete Directory request attempted to remove the server's current directory."},
+ {"ERRdiffdevice",ERRdiffdevice,"Not same device."},
+ {"ERRnofiles",ERRnofiles,"A File Search command can find no more files matching the specified criteria."},
+ {"ERRbadshare",ERRbadshare,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
+ {"ERRlock",ERRlock,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRunsup", ERRunsup, "The operation is unsupported"},
+ {"ERRnosuchshare", ERRnosuchshare, "You specified an invalid share name"},
+ {"ERRfilexists",ERRfilexists,"The file named in a Create Directory, Make New File or Link request already exists."},
+ {"ERRinvalidname",ERRinvalidname, "Invalid name"},
+ {"ERRbadpipe",ERRbadpipe,"Pipe invalid."},
+ {"ERRpipebusy",ERRpipebusy,"All instances of the requested pipe are busy."},
+ {"ERRpipeclosing",ERRpipeclosing,"Pipe close in progress."},
+ {"ERRnotconnected",ERRnotconnected,"No process on other end of pipe."},
+ {"ERRmoredata",ERRmoredata,"There is more data to be returned."},
+ {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
+ {"ERRlogonfailure",ERRlogonfailure,"Logon failure"},
+ {"ERRdiskfull",ERRdiskfull,"Disk full"},
+ {NULL,-1,NULL}};
+
+/* Server Error Messages */
+err_code_struct server_msgs[] = {
+ {"ERRerror",1,"Non-specific error code."},
+ {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+ {"ERRbadtype",3,"reserved."},
+ {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
+ {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
+ {"ERRinvnetname",6,"Invalid network name in tree connect."},
+ {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
+ {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
+ {"ERRqtoobig",50,"Print queue full -- no space."},
+ {"ERRqeof",51,"EOF on print queue dump."},
+ {"ERRinvpfid",52,"Invalid print file FID."},
+ {"ERRsmbcmd",64,"The server did not recognize the command received."},
+ {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
+ {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."},
+ {"ERRreserved",68,"reserved."},
+ {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
+ {"ERRreserved",70,"reserved."},
+ {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
+ {"ERRpaused",81,"Server is paused."},
+ {"ERRmsgoff",82,"Not receiving messages."},
+ {"ERRnoroom",83,"No room to buffer message."},
+ {"ERRrmuns",87,"Too many remote user names."},
+ {"ERRtimeout",88,"Operation timed out."},
+ {"ERRnoresource",89,"No resources currently available for request."},
+ {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
+ {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
+ {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
+ {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
+ {"ERRcontmpx",252,"Continue in MPX mode."},
+ {"ERRreserved",253,"reserved."},
+ {"ERRreserved",254,"reserved."},
+ {"ERRnosupport",0xFFFF,"Function not supported."},
+ {NULL,-1,NULL}};
+
+/* Hard Error Messages */
+err_code_struct hard_msgs[] = {
+ {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
+ {"ERRbadunit",20,"Unknown unit."},
+ {"ERRnotready",21,"Drive not ready."},
+ {"ERRbadcmd",22,"Unknown command."},
+ {"ERRdata",23,"Data error (CRC)."},
+ {"ERRbadreq",24,"Bad request structure length."},
+ {"ERRseek",25 ,"Seek error."},
+ {"ERRbadmedia",26,"Unknown media type."},
+ {"ERRbadsector",27,"Sector not found."},
+ {"ERRnopaper",28,"Printer out of paper."},
+ {"ERRwrite",29,"Write fault."},
+ {"ERRread",30,"Read fault."},
+ {"ERRgeneral",31,"General failure."},
+ {"ERRbadshare",32,"An open conflicts with an existing open."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
+ {"ERRFCBUnavail",35,"No FCBs are available to process request."},
+ {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
+ {NULL,-1,NULL}};
+
+
+const struct
+{
+ int code;
+ char *class;
+ err_code_struct *err_msgs;
+} err_classes[] = {
+ {0,"SUCCESS",NULL},
+ {0x01,"ERRDOS",dos_msgs},
+ {0x02,"ERRSRV",server_msgs},
+ {0x03,"ERRHRD",hard_msgs},
+ {0x04,"ERRXOS",NULL},
+ {0xE1,"ERRRMX1",NULL},
+ {0xE2,"ERRRMX2",NULL},
+ {0xE3,"ERRRMX3",NULL},
+ {0xFF,"ERRCMD",NULL},
+ {-1,NULL,NULL}};
+
+
+/****************************************************************************
+return a SMB error name from a class and code
+****************************************************************************/
+char *smb_dos_err_name(uint8 class, uint16 num)
+{
+ static pstring ret;
+ int i,j;
+
+ for (i=0;err_classes[i].class;i++)
+ if (err_classes[i].code == class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code) {
+ return err[j].name;
+ }
+ }
+ slprintf(ret, sizeof(ret) - 1, "%d",num);
+ return ret;
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error class (%d,%d)",class,num);
+ return(ret);
+}
+
+
+/****************************************************************************
+return a SMB error class name as a string.
+****************************************************************************/
+char *smb_dos_err_class(uint8 class)
+{
+ static pstring ret;
+ int i;
+
+ for (i=0;err_classes[i].class;i++) {
+ if (err_classes[i].code == class) {
+ return err_classes[i].class;
+ }
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown class (%d)",class);
+ return(ret);
+}
+
+/****************************************************************************
+return a SMB string from an SMB buffer
+****************************************************************************/
+char *smb_dos_errstr(char *inbuf)
+{
+ static pstring ret;
+ int class = CVAL(inbuf,smb_rcls);
+ int num = SVAL(inbuf,smb_err);
+ int i,j;
+
+ for (i=0;err_classes[i].class;i++)
+ if (err_classes[i].code == class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code) {
+ if (DEBUGLEVEL > 0)
+ slprintf(ret, sizeof(ret) - 1, "%s - %s (%s)",
+ err_classes[i].class,
+ err[j].name,err[j].message);
+ else
+ slprintf(ret, sizeof(ret) - 1, "%s - %s",
+ err_classes[i].class,err[j].name);
+ return ret;
+ }
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "%s - %d",err_classes[i].class,num);
+ return ret;
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)",class,num);
+ return(ret);
+}
+
+
+/*****************************************************************************
+ returns an WERROR error message.
+ *****************************************************************************/
+char *werror_str(WERROR status)
+{
+ static fstring msg;
+ slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status));
+ return msg;
+}
+
+
+/*****************************************************************************
+map a unix errno to a win32 error
+ *****************************************************************************/
+WERROR map_werror_from_unix(int error)
+{
+ NTSTATUS status = map_nt_error_from_unix(error);
+ return ntstatus_to_werror(status);
+}
diff --git a/source/libsmb/trust_passwd.c b/source/libsmb/trust_passwd.c
new file mode 100644
index 00000000000..7f7a5d29dcf
--- /dev/null
+++ b/source/libsmb/trust_passwd.c
@@ -0,0 +1,116 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 3.0
+ * Routines to change
+ * Copyright (C) Andrew Bartlett 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Change the domain password on the PDC.
+
+ Just changes the password betwen the two values specified.
+
+ Caller must have the cli connected to the netlogon pipe
+ already.
+**********************************************************/
+static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ unsigned char orig_trust_passwd_hash[16],
+ unsigned char new_trust_passwd_hash[16])
+{
+ NTSTATUS result;
+ result = new_cli_nt_setup_creds(cli, orig_trust_passwd_hash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("just_change_the_password: unable to setup creds (%s)!\n",
+ get_nt_error_msg(result)));
+ return result;
+ }
+
+ result = cli_net_srv_pwset(cli, mem_ctx, global_myname, new_trust_passwd_hash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
+ get_nt_error_msg(result)));
+ }
+ return result;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Store the password ourselves, but use the supplied password
+ Caller must have already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ unsigned char orig_trust_passwd_hash[16])
+{
+ unsigned char new_trust_passwd_hash[16];
+ char *new_trust_passwd;
+ char *str;
+ NTSTATUS nt_status;
+
+ /* Create a random machine account password */
+ str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ new_trust_passwd = talloc_strdup(mem_ctx, str);
+
+ E_md4hash((uchar *)new_trust_passwd, new_trust_passwd_hash);
+
+ nt_status = just_change_the_password(cli, mem_ctx, orig_trust_passwd_hash,
+ new_trust_passwd_hash);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("%s : change_trust_account_password: Changed password.\n", timestring(False)));
+ /*
+ * Return the result of trying to write the new password
+ * back into the trust account file.
+ */
+ if (!secrets_store_machine_password(new_trust_passwd)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return nt_status;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Do most of the legwork ourselfs. Caller must have
+ already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx, char *domain)
+{
+ unsigned char old_trust_passwd_hash[16];
+ char *up_domain;
+
+ up_domain = talloc_strdup(mem_ctx, domain);
+
+ if (!secrets_fetch_trust_account_password(domain,
+ old_trust_passwd_hash,
+ NULL)) {
+ DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return trust_pw_change_and_store_it(cli, mem_ctx, old_trust_passwd_hash);
+
+}
+
diff --git a/source/libsmb/unexpected.c b/source/libsmb/unexpected.c
new file mode 100644
index 00000000000..b77e7490a0d
--- /dev/null
+++ b/source/libsmb/unexpected.c
@@ -0,0 +1,165 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ handle unexpected packets
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdbd = NULL;
+
+/* the key type used in the unexpeceted packet database */
+struct unexpected_key {
+ enum packet_type packet_type;
+ time_t timestamp;
+ int count;
+};
+
+
+
+/****************************************************************************
+ all unexpected packets are passed in here, to be stored in a unexpected
+ packet database. This allows nmblookup and other tools to receive packets
+ erroneoously sent to the wrong port by broken MS systems
+ **************************************************************************/
+void unexpected_packet(struct packet_struct *p)
+{
+ static int count;
+ TDB_DATA kbuf, dbuf;
+ struct unexpected_key key;
+ char buf[1024];
+ int len=0;
+
+ if (!tdbd) {
+ tdbd = tdb_open_log(lock_path("unexpected.tdb"), 1,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ if (!tdbd) {
+ DEBUG(0,("Failed to open unexpected.tdb\n"));
+ return;
+ }
+ }
+
+ memset(buf,'\0',sizeof(buf));
+
+ len = build_packet(buf, p);
+
+ key.packet_type = p->packet_type;
+ key.timestamp = p->timestamp;
+ key.count = count++;
+
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ tdb_store(tdbd, kbuf, dbuf, TDB_REPLACE);
+}
+
+
+static time_t lastt;
+
+/****************************************************************************
+delete the record if it is too old
+ **************************************************************************/
+static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct unexpected_key key;
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
+ tdb_delete(ttdb, kbuf);
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+delete all old unexpected packets
+ **************************************************************************/
+void clear_unexpected(time_t t)
+{
+ if (!tdbd) return;
+
+ if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
+ return;
+
+ lastt = t;
+
+ tdb_traverse(tdbd, traverse_fn, NULL);
+}
+
+
+static struct packet_struct *matched_packet;
+static int match_id;
+static enum packet_type match_type;
+static char *match_name;
+
+/****************************************************************************
+tdb traversal fn to find a matching 137 packet
+ **************************************************************************/
+static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct unexpected_key key;
+ struct packet_struct *p;
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (key.packet_type != match_type) return 0;
+
+ p = parse_packet(dbuf.dptr, dbuf.dsize, match_type);
+
+ if ((match_type == NMB_PACKET &&
+ p->packet.nmb.header.name_trn_id == match_id) ||
+ (match_type == DGRAM_PACKET &&
+ match_mailslot_name(p, match_name))) {
+ matched_packet = p;
+ return -1;
+ }
+
+ free_packet(p);
+
+ return 0;
+}
+
+
+/****************************************************************************
+check for a particular packet in the unexpected packet queue
+ **************************************************************************/
+struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
+ char *mailslot_name)
+{
+ TDB_CONTEXT *tdb2;
+
+ tdb2 = tdb_open_log(lock_path("unexpected.tdb"), 0, 0, O_RDONLY, 0);
+ if (!tdb2) return NULL;
+
+ matched_packet = NULL;
+ match_id = id;
+ match_type = packet_type;
+ match_name = mailslot_name;
+
+ tdb_traverse(tdb2, traverse_match, NULL);
+
+ tdb_close(tdb2);
+
+ return matched_packet;
+}
diff --git a/source/locking/brlock.c b/source/locking/brlock.c
new file mode 100644
index 00000000000..cbf98c46a5e
--- /dev/null
+++ b/source/locking/brlock.c
@@ -0,0 +1,598 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ byte range locking code
+ Updated to handle range splits/merges.
+
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This module implements a tdb based byte range locking service,
+ replacing the fcntl() based byte range locking previously
+ used. This allows us to provide the same semantics as NT */
+
+#include "includes.h"
+
+#define ZERO_ZERO 0
+
+/* This contains elements that differentiate locks. The smbpid is a
+ client supplied pid, and is essentially the locking context for
+ this client */
+
+struct lock_context {
+ uint16 smbpid;
+ uint16 tid;
+ pid_t pid;
+};
+
+/* The data in brlock records is an unsorted linear array of these
+ records. It is unnecessary to store the count as tdb provides the
+ size of the record */
+
+struct lock_struct {
+ struct lock_context context;
+ br_off start;
+ br_off size;
+ int fnum;
+ enum brl_type lock_type;
+};
+
+/* The key used in the brlock database. */
+
+struct lock_key {
+ SMB_DEV_T device;
+ SMB_INO_T inode;
+};
+
+/* The open brlock.tdb database. */
+
+static TDB_CONTEXT *tdb;
+
+/****************************************************************************
+ Create a locking key - ensuring zero filled for pad purposes.
+****************************************************************************/
+
+static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ static struct lock_key key;
+ TDB_DATA kbuf;
+
+ memset(&key, '\0', sizeof(key));
+ key.device = dev;
+ key.inode = inode;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ return kbuf;
+}
+
+/****************************************************************************
+ See if two locking contexts are equal.
+****************************************************************************/
+
+static BOOL brl_same_context(struct lock_context *ctx1,
+ struct lock_context *ctx2)
+{
+ return (ctx1->pid == ctx2->pid) &&
+ (ctx1->smbpid == ctx2->smbpid) &&
+ (ctx1->tid == ctx2->tid);
+}
+
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place.
+****************************************************************************/
+
+static BOOL brl_conflict(struct lock_struct *lck1,
+ struct lock_struct *lck2)
+{
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size)) {
+ return False;
+ }
+
+ return True;
+}
+
+#if ZERO_ZERO
+static BOOL brl_conflict1(struct lock_struct *lck1,
+ struct lock_struct *lck2)
+{
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
+ return True;
+ }
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size)) {
+ return False;
+ }
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+ Check to see if this lock conflicts, but ignore our own locks on the
+ same fnum only.
+****************************************************************************/
+
+static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
+{
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
+ return False;
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck1->fnum == lck2->fnum)
+ return False;
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size)) return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+ Delete a record if it is for a dead process, if check_self is true, then
+ delete any records belonging to this pid also (there shouldn't be any).
+****************************************************************************/
+
+static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct lock_struct *locks;
+ int count, i;
+ BOOL check_self = *(BOOL *)state;
+ pid_t mypid = sys_getpid();
+
+ tdb_chainlock(tdb, kbuf);
+
+ locks = (struct lock_struct *)dbuf.dptr;
+
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ /* If check_self is true we want to remove our own records. */
+ if (check_self && (mypid == lock->context.pid)) {
+
+ DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
+ (unsigned int)lock->context.pid ));
+
+ } else if (process_exists(lock->context.pid)) {
+
+ DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
+ continue;
+ }
+
+ DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
+ (unsigned int)lock->context.pid ));
+
+ if (count > 1 && i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ count--;
+ i--;
+ }
+
+ if (count == 0) {
+ tdb_delete(tdb, kbuf);
+ } else if (count < (dbuf.dsize / sizeof(*locks))) {
+ dbuf.dsize = count * sizeof(*locks);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+
+ tdb_chainunlock(tdb, kbuf);
+ return 0;
+}
+
+/****************************************************************************
+ Open up the brlock.tdb database.
+****************************************************************************/
+
+void brl_init(int read_only)
+{
+ BOOL check_self = False;
+
+ if (tdb)
+ return;
+ tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
+ if (!tdb) {
+ DEBUG(0,("Failed to open byte range locking database\n"));
+ return;
+ }
+
+ /* delete any dead locks */
+ if (!read_only)
+ tdb_traverse(tdb, delete_fn, &check_self);
+}
+
+/****************************************************************************
+ Close down the brlock.tdb database.
+****************************************************************************/
+
+void brl_shutdown(int read_only)
+{
+ BOOL check_self = True;
+
+ if (!tdb)
+ return;
+
+ /* delete any dead locks */
+ if (!read_only)
+ tdb_traverse(tdb, delete_fn, &check_self);
+
+ tdb_close(tdb);
+}
+
+#if ZERO_ZERO
+/****************************************************************************
+compare two locks for sorting
+****************************************************************************/
+static int lock_compare(struct lock_struct *lck1,
+ struct lock_struct *lck2)
+{
+ if (lck1->start != lck2->start) return (lck1->start - lck2->start);
+ if (lck2->size != lck1->size) {
+ return ((int)lck1->size - (int)lck2->size);
+ }
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ Lock a range of bytes.
+****************************************************************************/
+
+NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
+ uint16 smbpid, pid_t pid, uint16 tid,
+ br_off start, br_off size,
+ enum brl_type lock_type)
+{
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct lock, *locks;
+ char *tp;
+ NTSTATUS status = NT_STATUS_OK;
+
+ kbuf = locking_key(dev,ino);
+
+ dbuf.dptr = NULL;
+
+#if !ZERO_ZERO
+ if (start == 0 && size == 0) {
+ DEBUG(0,("client sent 0/0 lock - please report this\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+#endif
+
+ tdb_chainlock(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = tid;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = fnum;
+ lock.lock_type = lock_type;
+
+ if (dbuf.dptr) {
+ /* there are existing locks - make sure they don't conflict */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ if (brl_conflict(&locks[i], &lock)) {
+ status = NT_STATUS_LOCK_NOT_GRANTED;
+ goto fail;
+ }
+#if ZERO_ZERO
+ if (lock.start == 0 && lock.size == 0 &&
+ locks[i].size == 0) {
+ break;
+ }
+#endif
+ }
+ }
+
+ /* no conflicts - add it to the list of locks */
+ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
+ if (!tp) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ } else {
+ dbuf.dptr = tp;
+ }
+ memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
+ dbuf.dsize += sizeof(lock);
+
+#if ZERO_ZERO
+ /* sort the lock list */
+ qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
+#endif
+
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return NT_STATUS_OK;
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return status;
+}
+
+/****************************************************************************
+ Unlock a range of bytes.
+****************************************************************************/
+
+BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
+ uint16 smbpid, pid_t pid, uint16 tid,
+ br_off start, br_off size)
+{
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct *locks;
+ struct lock_context context;
+
+ kbuf = locking_key(dev,ino);
+
+ dbuf.dptr = NULL;
+
+ tdb_chainlock(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
+ goto fail;
+ }
+
+ context.smbpid = smbpid;
+ context.pid = pid;
+ context.tid = tid;
+
+ /* there are existing locks - find a match */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+
+#if ZERO_ZERO
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->lock_type == WRITE_LOCK &&
+ brl_same_context(&lock->context, &context) &&
+ lock->fnum == fnum &&
+ lock->start == start &&
+ lock->size == size) {
+ /* found it - delete it */
+ if (count == 1) {
+ tdb_delete(tdb, kbuf);
+ } else {
+ if (i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ dbuf.dsize -= sizeof(*locks);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+ }
+ }
+#endif
+
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (brl_same_context(&lock->context, &context) &&
+ lock->fnum == fnum &&
+ lock->start == start &&
+ lock->size == size) {
+ /* found it - delete it */
+ if (count == 1) {
+ tdb_delete(tdb, kbuf);
+ } else {
+ if (i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ dbuf.dsize -= sizeof(*locks);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+ }
+ }
+
+ /* we didn't find it */
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return False;
+}
+
+
+/****************************************************************************
+ Test if we could add a lock if we wanted to.
+****************************************************************************/
+
+BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
+ uint16 smbpid, pid_t pid, uint16 tid,
+ br_off start, br_off size,
+ enum brl_type lock_type, int check_self)
+{
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct lock, *locks;
+
+ kbuf = locking_key(dev,ino);
+
+ dbuf.dptr = NULL;
+
+ tdb_chainlock(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = tid;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = fnum;
+ lock.lock_type = lock_type;
+
+ if (dbuf.dptr) {
+ /* there are existing locks - make sure they don't conflict */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ if (check_self) {
+ if (brl_conflict(&locks[i], &lock))
+ goto fail;
+ } else {
+ /*
+ * Our own locks don't conflict.
+ */
+ if (brl_conflict_other(&locks[i], &lock))
+ goto fail;
+ }
+ }
+ }
+
+ /* no conflicts - we could have added it */
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return False;
+}
+
+/****************************************************************************
+ Remove any locks associated with a open file.
+****************************************************************************/
+
+void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
+{
+ TDB_DATA kbuf, dbuf;
+ int count, i, dcount=0;
+ struct lock_struct *locks;
+
+ kbuf = locking_key(dev,ino);
+
+ dbuf.dptr = NULL;
+
+ tdb_chainlock(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) goto fail;
+
+ /* there are existing locks - remove any for this fnum */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->context.tid == tid &&
+ lock->context.pid == pid &&
+ lock->fnum == fnum) {
+ /* found it - delete it */
+ if (count > 1 && i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ count--;
+ i--;
+ dcount++;
+ }
+ }
+
+ if (count == 0) {
+ tdb_delete(tdb, kbuf);
+ } else if (count < (dbuf.dsize / sizeof(*locks))) {
+ dbuf.dsize -= dcount * sizeof(*locks);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+
+ /* we didn't find it */
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+}
+
+/****************************************************************************
+ Traverse the whole database with this function, calling traverse_callback
+ on each lock.
+****************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct lock_struct *locks;
+ struct lock_key *key;
+ int i;
+
+ BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
+
+ locks = (struct lock_struct *)dbuf.dptr;
+ key = (struct lock_key *)kbuf.dptr;
+
+ for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
+ traverse_callback(key->device, key->inode,
+ locks[i].context.pid,
+ locks[i].lock_type,
+ locks[i].start,
+ locks[i].size);
+ }
+ return 0;
+}
+
+/*******************************************************************
+ Call the specified function on each lock in the database.
+********************************************************************/
+
+int brl_forall(BRLOCK_FN(fn))
+{
+ if (!tdb) return 0;
+ return tdb_traverse(tdb, traverse_fn, (void *)fn);
+}
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 6ff3ab5d125..cb523532d8f 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -1,8 +1,9 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
+ Version 3.0
Locking functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,314 +18,744 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+ locking to deal with multiple share modes per open file.
+
+ September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+ support.
+
+ rewrtten completely to use new tdb code. Tridge, Dec '99
+
+ Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
*/
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
+uint16 global_smbpid;
-pstring share_del_pending="";
+/* the locking database handle */
+static TDB_CONTEXT *tdb;
+
+/****************************************************************************
+ Debugging aid :-).
+****************************************************************************/
+static const char *lock_type_name(enum brl_type lock_type)
+{
+ return (lock_type == READ_LOCK) ? "READ" : "WRITE";
+}
/****************************************************************************
- utility function called to see if a file region is locked
+ Utility function called to see if a file region is locked.
+ If check_self is True, then checks on our own fd with the same locking context
+ are still made. If check_self is False, then checks are not made on our own fd
+ with the same locking context are not made.
****************************************************************************/
-BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
+
+BOOL is_locked(files_struct *fsp,connection_struct *conn,
+ SMB_BIG_UINT count,SMB_BIG_UINT offset,
+ enum brl_type lock_type, BOOL check_self)
{
- int snum = SNUM(cnum);
+ int snum = SNUM(conn);
+ BOOL ret;
+
+ if (count == 0)
+ return(False);
+
+ if (!lp_locking(snum) || !lp_strict_locking(snum))
+ return(False);
+
+ ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
+ global_smbpid, sys_getpid(), conn->cnum,
+ offset, count, lock_type, check_self);
+
+ DEBUG(10,("is_locked: brl start=%.0f len=%.0f %s for file %s\n",
+ (double)offset, (double)count, ret ? "locked" : "unlocked",
+ fsp->fsp_name ));
+
+ /*
+ * There is no lock held by an SMB daemon, check to
+ * see if there is a POSIX lock from a UNIX or NFS process.
+ */
- if (count == 0)
- return(False);
+ if(!ret && lp_posix_locking(snum)) {
+ ret = is_posix_locked(fsp, offset, count, lock_type);
- if (!lp_locking(snum) || !lp_strict_locking(snum))
- return(False);
+ DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
+ (double)offset, (double)count, ret ? "locked" : "unlocked",
+ fsp->fsp_name ));
+ }
- return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
- (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
+ return ret;
}
+/****************************************************************************
+ Utility function called by locking requests.
+****************************************************************************/
+
+NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
+ SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type)
+{
+ NTSTATUS status;
+
+ if (!lp_locking(SNUM(conn)))
+ return NT_STATUS_OK;
+
+ /* NOTE! 0 byte long ranges ARE allowed and should be stored */
+
+
+ DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n",
+ lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name ));
+
+ if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
+ status = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
+ lock_pid, sys_getpid(), conn->cnum,
+ offset, count,
+ lock_type);
+
+ if (NT_STATUS_IS_OK(status) && lp_posix_locking(SNUM(conn))) {
+
+ /*
+ * Try and get a POSIX lock on this range.
+ * Note that this is ok if it is a read lock
+ * overlapping on a different fd. JRA.
+ */
+
+ if (!set_posix_lock(fsp, offset, count, lock_type)) {
+ status = NT_STATUS_LOCK_NOT_GRANTED;
+ /*
+ * We failed to map - we must now remove the brl
+ * lock entry.
+ */
+ (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+ lock_pid, sys_getpid(), conn->cnum,
+ offset, count);
+ }
+ }
+ }
+
+ return status;
+}
/****************************************************************************
- utility function called by locking requests
+ Utility function called by unlocking requests.
****************************************************************************/
-BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+
+NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
+ SMB_BIG_UINT count,SMB_BIG_UINT offset)
{
- BOOL ok = False;
-
- if (!lp_locking(SNUM(cnum)))
- return(True);
-
- if (count == 0) {
- *eclass = ERRDOS;
- *ecode = ERRnoaccess;
- return False;
- }
-
- if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
- ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
- (Files[fnum].can_write?F_WRLCK:F_RDLCK));
-
- if (!ok) {
- *eclass = ERRDOS;
- *ecode = ERRlock;
- return False;
- }
- return True; /* Got lock */
+ BOOL ok = False;
+
+ if (!lp_locking(SNUM(conn)))
+ return NT_STATUS_OK;
+
+ if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ /*
+ * Remove the existing lock record from the tdb lockdb
+ * before looking at POSIX locks. If this record doesn't
+ * match then don't bother looking to remove POSIX locks.
+ */
+
+ ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+ lock_pid, sys_getpid(), conn->cnum, offset, count);
+
+ if (!ok) {
+ DEBUG(10,("do_unlock: returning ERRlock.\n" ));
+ return NT_STATUS_LOCK_NOT_GRANTED;
+ }
+
+ if (!lp_posix_locking(SNUM(conn)))
+ return NT_STATUS_OK;
+
+ (void)release_posix_lock(fsp, offset, count);
+
+ return NT_STATUS_OK;
}
+/****************************************************************************
+ Remove any locks on this fd. Called from file_close().
+****************************************************************************/
+
+void locking_close_file(files_struct *fsp)
+{
+ pid_t pid = sys_getpid();
+
+ if (!lp_locking(SNUM(fsp->conn)))
+ return;
+
+ /*
+ * Just release all the brl locks, no need to release individually.
+ */
+
+ brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
+
+ if(lp_posix_locking(SNUM(fsp->conn))) {
+
+ /*
+ * Release all the POSIX locks.
+ */
+ posix_locking_close_file(fsp);
+
+ }
+}
/****************************************************************************
- utility function called by unlocking requests
+ Initialise the locking functions.
****************************************************************************/
-BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+
+static int open_read_only;
+
+BOOL locking_init(int read_only)
{
- BOOL ok = False;
+ brl_init(read_only);
- if (!lp_locking(SNUM(cnum)))
- return(True);
+ if (tdb)
+ return True;
- if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
- ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
-
- if (!ok) {
- *eclass = ERRDOS;
- *ecode = ERRlock;
- return False;
- }
- return True; /* Did unlock */
+ tdb = tdb_open_log(lock_path("locking.tdb"),
+ 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
+ read_only?O_RDONLY:O_RDWR|O_CREAT,
+ 0644);
+
+ if (!tdb) {
+ DEBUG(0,("ERROR: Failed to initialise locking database\n"));
+ return False;
+ }
+
+ if (!posix_locking_init(read_only))
+ return False;
+
+ open_read_only = read_only;
+
+ return True;
}
/*******************************************************************
- name a share file
- ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
+ Deinitialize the share_mode management.
+******************************************************************/
+
+BOOL locking_end(void)
{
- strcpy(name,lp_lockdir());
- standard_sub(cnum,name);
- trim_string(name,"","/");
- if (!*name) return(False);
- name += strlen(name);
-
- sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
- return(True);
+
+ brl_shutdown(open_read_only);
+ if (tdb) {
+
+ if (tdb_close(tdb) != 0)
+ return False;
+ }
+
+ return True;
}
/*******************************************************************
- use the fnum to get the share file name
- ******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+ Form a static locking key for a dev/inode pair.
+******************************************************************/
+
+static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
{
- struct stat st;
- if (fstat(Files[fnum].fd,&st) != 0) return(False);
- return(share_name(Files[fnum].cnum,&st,name));
+ static struct locking_key key;
+ TDB_DATA kbuf;
+
+ memset(&key, '\0', sizeof(key));
+ key.dev = dev;
+ key.inode = inode;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ return kbuf;
}
+static TDB_DATA locking_key_fsp(files_struct *fsp)
+{
+ return locking_key(fsp->dev, fsp->inode);
+}
/*******************************************************************
- get the share mode of a file using the fnum
- ******************************************************************/
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+ Lock a hash bucket entry.
+******************************************************************/
+
+BOOL lock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode)
{
- struct stat sbuf;
- if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
+ return tdb_chainlock(tdb, locking_key(dev, inode)) == 0;
}
/*******************************************************************
- get the share mode of a file using the files name
- ******************************************************************/
-int get_share_mode_byname(int cnum,char *fname,int *pid)
+ Unlock a hash bucket entry.
+******************************************************************/
+
+void unlock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode)
{
- struct stat sbuf;
- if (stat(fname,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
-}
+ tdb_chainunlock(tdb, locking_key(dev, inode));
+}
+
+/*******************************************************************
+ Lock a hash bucket entry. use a fsp for convenience
+******************************************************************/
+
+BOOL lock_share_entry_fsp(files_struct *fsp)
+{
+ return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
+}
+
+/*******************************************************************
+ Unlock a hash bucket entry.
+******************************************************************/
+void unlock_share_entry_fsp(files_struct *fsp)
+{
+ tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode));
+}
+
+/*******************************************************************
+ Get all share mode entries for a dev/inode pair.
+********************************************************************/
+
+int get_share_modes(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry **pp_shares)
+{
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ int num_share_modes;
+ share_mode_entry *shares = NULL;
+
+ *pp_shares = NULL;
+
+ dbuf = tdb_fetch(tdb, locking_key(dev, inode));
+ if (!dbuf.dptr)
+ return 0;
+
+ data = (struct locking_data *)dbuf.dptr;
+ num_share_modes = data->u.num_share_mode_entries;
+ if(num_share_modes) {
+ int i;
+ int del_count = 0;
+
+ shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data),
+ num_share_modes * sizeof(share_mode_entry));
+
+ if (!shares) {
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+
+ /*
+ * Ensure that each entry has a real process attached.
+ */
+
+ for (i = 0; i < num_share_modes; ) {
+ share_mode_entry *entry_p = &shares[i];
+ if (process_exists(entry_p->pid))
+ i++;
+ else {
+ memcpy( &shares[i], &shares[i+1],
+ sizeof(share_mode_entry) * (num_share_modes - i - 1));
+ num_share_modes--;
+ del_count++;
+ }
+ }
+
+ /* Did we delete any ? If so, re-store in tdb. */
+ if (del_count) {
+ data->u.num_share_mode_entries = num_share_modes;
+
+ if (num_share_modes)
+ memcpy(dbuf.dptr + sizeof(*data), shares,
+ num_share_modes * sizeof(share_mode_entry));
+
+ /* The record has shrunk a bit */
+ dbuf.dsize -= del_count * sizeof(share_mode_entry);
+
+ if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1) {
+ SAFE_FREE(shares);
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ *pp_shares = shares;
+ return num_share_modes;
+}
/*******************************************************************
-get the share mode of a file
+ Fill a share mode entry.
********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+
+static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
{
- pstring fname;
- int fd2;
- char buf[16];
- int ret;
- time_t t;
-
- *pid = 0;
-
- if (!share_name(cnum,sbuf,fname)) return(0);
-
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return(0);
-
- if (read(fd2,buf,16) != 16) {
- close(fd2);
- unlink(fname);
- return(0);
- }
- close(fd2);
-
- t = IVAL(buf,0);
- ret = IVAL(buf,4);
- *pid = IVAL(buf,8);
-
- if (IVAL(buf,12) != LOCKING_VERSION) {
- if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
- *pid = 0;
- return(0);
- }
-
- if (*pid && !process_exists(*pid)) {
- ret=0;
- *pid = 0;
- }
-
- if (! *pid) unlink(fname); /* XXXXX race, race */
-
- if (*pid)
- DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
-
- return(ret);
+ share_mode_entry *e = (share_mode_entry *)p;
+ void *x = &e->time; /* Needed to force alignment. p may not be aligned.... */
+
+ memset(e, '\0', sizeof(share_mode_entry));
+ e->pid = sys_getpid();
+ e->share_mode = fsp->share_mode;
+ e->op_port = port;
+ e->op_type = op_type;
+ memcpy(x, &fsp->open_time, sizeof(struct timeval));
+ e->share_file_id = fsp->file_id;
+ e->dev = fsp->dev;
+ e->inode = fsp->inode;
}
+/*******************************************************************
+ Check if two share mode entries are identical, ignoring oplock
+ and port info.
+********************************************************************/
+
+BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
+{
+#if 1 /* JRA PARANOIA TEST - REMOVE LATER */
+ if (e1->pid == e2->pid &&
+ e1->share_file_id == e2->share_file_id &&
+ e1->dev == e2->dev &&
+ e1->inode == e2->inode &&
+ (e1->share_mode & ~DELETE_ON_CLOSE_FLAG) != (e2->share_mode & ~DELETE_ON_CLOSE_FLAG)) {
+ DEBUG(0,("PANIC: share_modes_identical: share_mode missmatch (e1 = %u, e2 = %u). Logic error.\n",
+ (unsigned int)(e1->share_mode & ~DELETE_ON_CLOSE_FLAG),
+ (unsigned int)(e2->share_mode & ~DELETE_ON_CLOSE_FLAG) ));
+ smb_panic("PANIC: share_modes_identical logic error.\n");
+ }
+#endif
+
+ return (e1->pid == e2->pid &&
+ (e1->share_mode & ~DELETE_ON_CLOSE_FLAG) == (e2->share_mode & ~DELETE_ON_CLOSE_FLAG) &&
+ e1->dev == e2->dev &&
+ e1->inode == e2->inode &&
+ e1->share_file_id == e2->share_file_id );
+}
/*******************************************************************
-del the share mode of a file, if we set it last
+ Delete a specific share mode. Return the number
+ of entries left, and a memdup'ed copy of the entry deleted (if required).
+ Ignore if no entry deleted.
********************************************************************/
-void del_share_mode(int fnum)
+
+ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry *entry, share_mode_entry **ppse)
{
- pstring fname;
- int fd2;
- char buf[16];
- time_t t=0;
- int pid=0;
- BOOL del = False;
-
- if (!share_name_fnum(fnum,fname)) return;
-
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return;
- if (read(fd2,buf,16) != 16)
- del = True;
- close(fd2);
-
- if (!del) {
- t = IVAL(buf,0);
- pid = IVAL(buf,8);
- }
-
- if (!del)
- if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
- del = True;
-
- if (!del && t == Files[fnum].open_time && pid==(int)getpid())
- del = True;
-
- if (del) {
- if (!unlink(fname))
- DEBUG(2,("Deleted share file %s\n",fname));
- else {
- DEBUG(3,("Pending delete share file %s\n",fname));
- if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
- strcpy(share_del_pending,fname);
- }
- }
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ int i, del_count=0;
+ share_mode_entry *shares;
+ ssize_t count = 0;
+
+ if (ppse)
+ *ppse = NULL;
+
+ /* read in the existing share modes */
+ dbuf = tdb_fetch(tdb, locking_key(dev, inode));
+ if (!dbuf.dptr)
+ return -1;
+
+ data = (struct locking_data *)dbuf.dptr;
+ shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
+
+ /*
+ * Find any with this pid and delete it
+ * by overwriting with the rest of the data
+ * from the record.
+ */
+
+ DEBUG(10,("del_share_entry: num_share_modes = %d\n", data->u.num_share_mode_entries ));
+
+ for (i=0;i<data->u.num_share_mode_entries;) {
+ if (share_modes_identical(&shares[i], entry)) {
+ if (ppse)
+ *ppse = memdup(&shares[i], sizeof(*shares));
+ data->u.num_share_mode_entries--;
+ memmove(&shares[i], &shares[i+1],
+ dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
+ del_count++;
+
+ DEBUG(10,("del_share_entry: deleting entry %d\n", i ));
+
+ } else {
+ i++;
+ }
+ }
+
+ if (del_count) {
+ /* the record may have shrunk a bit */
+ dbuf.dsize -= del_count * sizeof(*shares);
+
+ count = (ssize_t)data->u.num_share_mode_entries;
+
+ /* store it back in the database */
+ if (data->u.num_share_mode_entries == 0) {
+ if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
+ count = -1;
+ } else {
+ if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
+ count = -1;
+ }
+ }
+ SAFE_FREE(dbuf.dptr);
+ return count;
}
-
/*******************************************************************
-set the share mode of a file
+ Del the share mode of a file for this process. Return the number
+ of entries left, and a memdup'ed copy of the entry deleted.
********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+
+ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse)
{
- pstring fname;
- int fd2;
- char buf[16];
- int pid = (int)getpid();
+ share_mode_entry entry;
+
+ /*
+ * Fake up a share_mode_entry for comparisons.
+ */
- if (!share_name_fnum(fnum,fname)) return(False);
+ fill_share_mode((char *)&entry, fsp, 0, 0);
+ return del_share_entry(fsp->dev, fsp->inode, &entry, ppse);
+}
- {
- int old_umask = umask(0);
- fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
- umask(old_umask);
- }
- if (fd2 < 0) {
- DEBUG(2,("Failed to create share file %s\n",fname));
- return(False);
- }
+/*******************************************************************
+ Set the share mode of a file. Return False on fail, True on success.
+********************************************************************/
+
+BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
+{
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ char *p=NULL;
+ int size;
+ BOOL ret = True;
+
+ /* read in the existing share modes if any */
+ dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
+ if (!dbuf.dptr) {
+ /* we'll need to create a new record */
+ pstring fname;
+
+ pstrcpy(fname, fsp->conn->connectpath);
+ pstrcat(fname, "/");
+ pstrcat(fname, fsp->fsp_name);
+
+ size = sizeof(*data) + sizeof(share_mode_entry) + strlen(fname) + 1;
+ p = (char *)malloc(size);
+ if (!p)
+ return False;
+ data = (struct locking_data *)p;
+ data->u.num_share_mode_entries = 1;
+ pstrcpy(p + sizeof(*data) + sizeof(share_mode_entry), fname);
+ fill_share_mode(p + sizeof(*data), fsp, port, op_type);
+ dbuf.dptr = p;
+ dbuf.dsize = size;
+ if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
+ ret = False;
+ SAFE_FREE(p);
+ return ret;
+ }
+
+ /* we're adding to an existing entry - this is a bit fiddly */
+ data = (struct locking_data *)dbuf.dptr;
+
+ data->u.num_share_mode_entries++;
+ size = dbuf.dsize + sizeof(share_mode_entry);
+ p = malloc(size);
+ if (!p)
+ return False;
+ memcpy(p, dbuf.dptr, sizeof(*data));
+ fill_share_mode(p + sizeof(*data), fsp, port, op_type);
+ memcpy(p + sizeof(*data) + sizeof(share_mode_entry), dbuf.dptr + sizeof(*data),
+ dbuf.dsize - sizeof(*data));
+ SAFE_FREE(dbuf.dptr);
+ dbuf.dptr = p;
+ dbuf.dsize = size;
+ if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
+ ret = False;
+ SAFE_FREE(p);
+ return ret;
+}
- SIVAL(buf,0,Files[fnum].open_time);
- SIVAL(buf,4,mode);
- SIVAL(buf,8,pid);
- SIVAL(buf,12,LOCKING_VERSION);
+/*******************************************************************
+ A generic in-place modification call for share mode entries.
+********************************************************************/
- if (write(fd2,buf,16) != 16) {
- close(fd2);
- unlink(fname);
- return(False);
- }
+static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry,
+ void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
+ void *param)
+{
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ int i;
+ share_mode_entry *shares;
+ BOOL need_store=False;
+
+ /* read in the existing share modes */
+ dbuf = tdb_fetch(tdb, locking_key(dev, inode));
+ if (!dbuf.dptr)
+ return False;
+
+ data = (struct locking_data *)dbuf.dptr;
+ shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
+
+ /* find any with our pid and call the supplied function */
+ for (i=0;i<data->u.num_share_mode_entries;i++) {
+ if (share_modes_identical(entry, &shares[i])) {
+ mod_fn(&shares[i], dev, inode, param);
+ need_store=True;
+ }
+ }
+
+ /* if the mod fn was called then store it back */
+ if (need_store) {
+ if (data->u.num_share_mode_entries == 0) {
+ if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
+ need_store = False;
+ } else {
+ if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
+ need_store = False;
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ return need_store;
+}
- write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+/*******************************************************************
+ Static function that actually does the work for the generic function
+ below.
+********************************************************************/
- close(fd2);
+static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
+ void *param)
+{
+ DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode ));
+ /* Delete the oplock info. */
+ entry->op_port = 0;
+ entry->op_type = NO_OPLOCK;
+}
- DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+/*******************************************************************
+ Remove an oplock port and mode entry from a share mode.
+********************************************************************/
- return(True);
+BOOL remove_share_oplock(files_struct *fsp)
+{
+ share_mode_entry entry;
+ /*
+ * Fake up an entry for comparisons...
+ */
+ fill_share_mode((char *)&entry, fsp, 0, 0);
+ return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL);
}
-
/*******************************************************************
-cleanup any stale share files
+ Static function that actually does the work for the generic function
+ below.
********************************************************************/
-void clean_share_files(void)
+
+static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
+ void *param)
{
- char *lockdir = lp_lockdir();
- void *dir;
- char *s;
+ DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode ));
+ entry->op_type = LEVEL_II_OPLOCK;
+}
+
+/*******************************************************************
+ Downgrade a oplock type from exclusive to level II.
+********************************************************************/
- if (!*lockdir) return;
+BOOL downgrade_share_oplock(files_struct *fsp)
+{
+ share_mode_entry entry;
+ /*
+ * Fake up an entry for comparisons...
+ */
+ fill_share_mode((char *)&entry, fsp, 0, 0);
+ return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL);
+}
- dir = opendir(lockdir);
- if (!dir) return;
+/*******************************************************************
+ Get/Set the delete on close flag in a set of share modes.
+ Return False on fail, True on success.
+********************************************************************/
- while ((s=readdirname(dir))) {
- char buf[16];
- int pid;
- int fd;
- pstring lname;
- int dev,inode;
+BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
+{
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ int i;
+ share_mode_entry *shares;
+
+ /* read in the existing share modes */
+ dbuf = tdb_fetch(tdb, locking_key(dev, inode));
+ if (!dbuf.dptr)
+ return False;
+
+ data = (struct locking_data *)dbuf.dptr;
+ shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
+
+ /* Set/Unset the delete on close element. */
+ for (i=0;i<data->u.num_share_mode_entries;i++,shares++) {
+ shares->share_mode = (delete_on_close ?
+ (shares->share_mode | DELETE_ON_CLOSE_FLAG) :
+ (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) );
+ }
+
+ /* store it back */
+ if (data->u.num_share_mode_entries) {
+ if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1) {
+ SAFE_FREE(dbuf.dptr);
+ return False;
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ return True;
+}
- if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
+/****************************************************************************
+ Traverse the whole database with this function, calling traverse_callback
+ on each share mode
+****************************************************************************/
- strcpy(lname,lp_lockdir());
- trim_string(lname,NULL,"/");
- strcat(lname,"/");
- strcat(lname,s);
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void* state)
+{
+ struct locking_data *data;
+ share_mode_entry *shares;
+ char *name;
+ int i;
- fd = open(lname,O_RDONLY,0);
- if (fd < 0) continue;
+ SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
- if (read(fd,buf,16) != 16) {
- close(fd);
- if (!unlink(lname))
- printf("Deleted corrupt share file %s\n",s);
- continue;
- }
- close(fd);
+ data = (struct locking_data *)dbuf.dptr;
+ shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
+ name = dbuf.dptr + sizeof(*data) + data->u.num_share_mode_entries*sizeof(*shares);
- pid = IVAL(buf,8);
+ for (i=0;i<data->u.num_share_mode_entries;i++) {
+ traverse_callback(&shares[i], name);
+ }
+ return 0;
+}
- if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
- if (!unlink(lname))
- printf("Deleted stale share file %s\n",s);
- }
- }
+/*******************************************************************
+ Call the specified function on each entry under management by the
+ share mode system.
+********************************************************************/
- closedir(dir);
+int share_mode_forall(SHAREMODE_FN(fn))
+{
+ if (!tdb)
+ return 0;
+ return tdb_traverse(tdb, traverse_fn, (void*)fn);
}
diff --git a/source/locking/posix.c b/source/locking/posix.c
new file mode 100644
index 00000000000..8b3538d8ca1
--- /dev/null
+++ b/source/locking/posix.c
@@ -0,0 +1,1316 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Locking functions
+ Copyright (C) Jeremy Allison 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
+*/
+
+#include "includes.h"
+
+/*
+ * The POSIX locking database handle.
+ */
+
+static TDB_CONTEXT *posix_lock_tdb;
+
+/*
+ * The pending close database handle.
+ */
+
+static TDB_CONTEXT *posix_pending_close_tdb;
+
+/*
+ * The data in POSIX lock records is an unsorted linear array of these
+ * records. It is unnecessary to store the count as tdb provides the
+ * size of the record.
+ */
+
+struct posix_lock {
+ int fd;
+ SMB_OFF_T start;
+ SMB_OFF_T size;
+ int lock_type;
+};
+
+/*
+ * The data in POSIX pending close records is an unsorted linear array of int
+ * records. It is unnecessary to store the count as tdb provides the
+ * size of the record.
+ */
+
+/* The key used in both the POSIX databases. */
+
+struct posix_lock_key {
+ SMB_DEV_T device;
+ SMB_INO_T inode;
+};
+
+/*******************************************************************
+ Form a static locking key for a dev/inode pair.
+******************************************************************/
+
+static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ static struct posix_lock_key key;
+ TDB_DATA kbuf;
+
+ memset(&key, '\0', sizeof(key));
+ key.device = dev;
+ key.inode = inode;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ return kbuf;
+}
+
+/*******************************************************************
+ Convenience function to get a key from an fsp.
+******************************************************************/
+
+static TDB_DATA locking_key_fsp(files_struct *fsp)
+{
+ return locking_key(fsp->dev, fsp->inode);
+}
+
+/****************************************************************************
+ Add an fd to the pending close tdb.
+****************************************************************************/
+
+static BOOL add_fd_to_close_entry(files_struct *fsp)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ char *tp;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
+
+ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(int));
+ if (!tp) {
+ DEBUG(0,("add_fd_to_close_entry: Realloc fail !\n"));
+ SAFE_FREE(dbuf.dptr);
+ return False;
+ } else
+ dbuf.dptr = tp;
+
+ memcpy(dbuf.dptr + dbuf.dsize, &fsp->fd, sizeof(int));
+ dbuf.dsize += sizeof(int);
+
+ if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
+ DEBUG(0,("add_fd_to_close_entry: tdb_store fail !\n"));
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ return True;
+}
+
+/****************************************************************************
+ Remove all fd entries for a specific dev/inode pair from the tdb.
+****************************************************************************/
+
+static void delete_close_entries(files_struct *fsp)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+
+ if (tdb_delete(posix_pending_close_tdb, kbuf) == -1)
+ DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
+}
+
+/****************************************************************************
+ Get the array of POSIX pending close records for an open fsp. Caller must
+ free. Returns number of entries.
+****************************************************************************/
+
+static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ size_t count = 0;
+
+ *entries = NULL;
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ return 0;
+ }
+
+ *entries = (int *)dbuf.dptr;
+ count = (size_t)(dbuf.dsize / sizeof(int));
+
+ return count;
+}
+
+/****************************************************************************
+ Get the array of POSIX locks for an fsp. Caller must free. Returns
+ number of entries.
+****************************************************************************/
+
+static size_t get_posix_lock_entries(files_struct *fsp, struct posix_lock **entries)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ size_t count = 0;
+
+ *entries = NULL;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_lock_tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ return 0;
+ }
+
+ *entries = (struct posix_lock *)dbuf.dptr;
+ count = (size_t)(dbuf.dsize / sizeof(struct posix_lock));
+
+ return count;
+}
+
+/****************************************************************************
+ Deal with pending closes needed by POSIX locking support.
+ Note that posix_locking_close_file() is expected to have been called
+ to delete all locks on this fsp before this function is called.
+****************************************************************************/
+
+int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
+{
+ int saved_errno = 0;
+ int ret;
+ size_t count, i;
+ struct posix_lock *entries = NULL;
+ int *fd_array = NULL;
+ BOOL locks_on_other_fds = False;
+
+ if (!lp_posix_locking(SNUM(conn))) {
+ /*
+ * No POSIX to worry about, just close.
+ */
+ ret = conn->vfs_ops.close(fsp,fsp->fd);
+ fsp->fd = -1;
+ return ret;
+ }
+
+ /*
+ * Get the number of outstanding POSIX locks on this dev/inode pair.
+ */
+
+ count = get_posix_lock_entries(fsp, &entries);
+
+ /*
+ * Check if there are any outstanding locks belonging to
+ * other fd's. This should never be the case if posix_locking_close_file()
+ * has been called first, but it never hurts to be *sure*.
+ */
+
+ for (i = 0; i < count; i++) {
+ if (entries[i].fd != fsp->fd) {
+ locks_on_other_fds = True;
+ break;
+ }
+ }
+
+ if (locks_on_other_fds) {
+
+ /*
+ * There are outstanding locks on this dev/inode pair on other fds.
+ * Add our fd to the pending close tdb and set fsp->fd to -1.
+ */
+
+ if (!add_fd_to_close_entry(fsp)) {
+ SAFE_FREE(entries);
+ return False;
+ }
+
+ SAFE_FREE(entries);
+ fsp->fd = -1;
+ return 0;
+ }
+
+ SAFE_FREE(entries);
+
+ /*
+ * No outstanding POSIX locks. Get the pending close fd's
+ * from the tdb and close them all.
+ */
+
+ count = get_posix_pending_close_entries(fsp, &fd_array);
+
+ if (count) {
+ DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count ));
+
+ for(i = 0; i < count; i++) {
+ if (conn->vfs_ops.close(fsp,fd_array[i]) == -1) {
+ saved_errno = errno;
+ }
+ }
+
+ /*
+ * Delete all fd's stored in the tdb
+ * for this dev/inode pair.
+ */
+
+ delete_close_entries(fsp);
+ }
+
+ SAFE_FREE(fd_array);
+
+ /*
+ * Finally close the fd associated with this fsp.
+ */
+
+ ret = conn->vfs_ops.close(fsp,fsp->fd);
+
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ ret = -1;
+ }
+
+ fsp->fd = -1;
+
+ return ret;
+}
+
+/****************************************************************************
+ Debugging aid :-).
+****************************************************************************/
+
+static const char *posix_lock_type_name(int lock_type)
+{
+ return (lock_type == F_RDLCK) ? "READ" : "WRITE";
+}
+
+/****************************************************************************
+ Delete a POSIX lock entry by index number. Used if the tdb add succeeds, but
+ then the POSIX fcntl lock fails.
+****************************************************************************/
+
+static BOOL delete_posix_lock_entry_by_index(files_struct *fsp, size_t entry)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ struct posix_lock *locks;
+ size_t count;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_lock_tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ DEBUG(10,("delete_posix_lock_entry_by_index: tdb_fetch failed !\n"));
+ goto fail;
+ }
+
+ count = (size_t)(dbuf.dsize / sizeof(struct posix_lock));
+ locks = (struct posix_lock *)dbuf.dptr;
+
+ if (count == 1) {
+ tdb_delete(posix_lock_tdb, kbuf);
+ } else {
+ if (entry < count-1) {
+ memmove(&locks[entry], &locks[entry+1], sizeof(*locks)*((count-1) - entry));
+ }
+ dbuf.dsize -= sizeof(*locks);
+ tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+
+ SAFE_FREE(dbuf.dptr);
+
+ return True;
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ return False;
+}
+
+/****************************************************************************
+ Add an entry into the POSIX locking tdb. We return the index number of the
+ added lock (used in case we need to delete *exactly* this entry). Returns
+ False on fail, True on success.
+****************************************************************************/
+
+static BOOL add_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, int lock_type, size_t *pentry_num)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ struct posix_lock pl;
+ char *tp;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_lock_tdb, kbuf);
+
+ *pentry_num = (size_t)(dbuf.dsize / sizeof(pl));
+
+ /*
+ * Add new record.
+ */
+
+ pl.fd = fsp->fd;
+ pl.start = start;
+ pl.size = size;
+ pl.lock_type = lock_type;
+
+ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(pl));
+ if (!tp) {
+ DEBUG(0,("add_posix_lock_entry: Realloc fail !\n"));
+ goto fail;
+ } else
+ dbuf.dptr = tp;
+
+ memcpy(dbuf.dptr + dbuf.dsize, &pl, sizeof(pl));
+ dbuf.dsize += sizeof(pl);
+
+ if (tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
+ DEBUG(0,("add_posix_lock: Failed to add lock entry on file %s\n", fsp->fsp_name));
+ goto fail;
+ }
+
+ SAFE_FREE(dbuf.dptr);
+
+ DEBUG(10,("add_posix_lock: File %s: type = %s: start=%.0f size=%.0f: dev=%.0f inode=%.0f\n",
+ fsp->fsp_name, posix_lock_type_name(lock_type), (double)start, (double)size,
+ (double)fsp->dev, (double)fsp->inode ));
+
+ return True;
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ return False;
+}
+
+/****************************************************************************
+ Calculate if locks have any overlap at all.
+****************************************************************************/
+
+static BOOL does_lock_overlap(SMB_OFF_T start1, SMB_OFF_T size1, SMB_OFF_T start2, SMB_OFF_T size2)
+{
+ if (start1 >= start2 && start1 <= start2 + size2)
+ return True;
+
+ if (start1 < start2 && start1 + size1 > start2)
+ return True;
+
+ return False;
+}
+
+/****************************************************************************
+ Delete an entry from the POSIX locking tdb. Returns a copy of the entry being
+ deleted and the number of records that are overlapped by this one, or -1 on error.
+****************************************************************************/
+
+static int delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, struct posix_lock *pl)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ struct posix_lock *locks;
+ size_t i, count;
+ BOOL found = False;
+ int num_overlapping_records = 0;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_lock_tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ DEBUG(10,("delete_posix_lock_entry: tdb_fetch failed !\n"));
+ goto fail;
+ }
+
+ /* There are existing locks - find a match. */
+ locks = (struct posix_lock *)dbuf.dptr;
+ count = (size_t)(dbuf.dsize / sizeof(*locks));
+
+ /*
+ * Search for and delete the first record that matches the
+ * unlock criteria.
+ */
+
+ for (i=0; i<count; i++) {
+ struct posix_lock *entry = &locks[i];
+
+ if (entry->fd == fsp->fd &&
+ entry->start == start &&
+ entry->size == size) {
+
+ /* Make a copy if requested. */
+ if (pl)
+ *pl = *entry;
+
+ /* Found it - delete it. */
+ if (count == 1) {
+ tdb_delete(posix_lock_tdb, kbuf);
+ } else {
+ if (i < count-1) {
+ memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i));
+ }
+ dbuf.dsize -= sizeof(*locks);
+ tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE);
+ }
+ count--;
+ found = True;
+ break;
+ }
+ }
+
+ if (!found)
+ goto fail;
+
+ /*
+ * Count the number of entries that are
+ * overlapped by this unlock request.
+ */
+
+ for (i = 0; i < count; i++) {
+ struct posix_lock *entry = &locks[i];
+
+ if (fsp->fd == entry->fd &&
+ does_lock_overlap( start, size, entry->start, entry->size))
+ num_overlapping_records++;
+ }
+
+ DEBUG(10,("delete_posix_lock_entry: type = %s: start=%.0f size=%.0f, num_records = %d\n",
+ posix_lock_type_name(pl->lock_type), (double)pl->start, (double)pl->size,
+ (unsigned int)num_overlapping_records ));
+
+ SAFE_FREE(dbuf.dptr);
+
+ return num_overlapping_records;
+
+ fail:
+ SAFE_FREE(dbuf.dptr);
+ return -1;
+}
+
+/****************************************************************************
+ Utility function to map a lock type correctly depending on the open
+ mode of a file.
+****************************************************************************/
+
+static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
+{
+ if((lock_type == WRITE_LOCK) && !fsp->can_write) {
+ /*
+ * Many UNIX's cannot get a write lock on a file opened read-only.
+ * Win32 locking semantics allow this.
+ * Do the best we can and attempt a read-only lock.
+ */
+ DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
+ return F_RDLCK;
+ } else if((lock_type == READ_LOCK) && !fsp->can_read) {
+ /*
+ * Ditto for read locks on write only files.
+ */
+ DEBUG(10,("map_posix_lock_type: Changing read lock to write due to write-only file.\n"));
+ return F_WRLCK;
+ }
+
+ /*
+ * This return should be the most normal, as we attempt
+ * to always open files read/write.
+ */
+
+ return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
+}
+
+/****************************************************************************
+ Check to see if the given unsigned lock range is within the possible POSIX
+ range. Modifies the given args to be in range if possible, just returns
+ False if not.
+****************************************************************************/
+
+static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
+ SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
+{
+ SMB_OFF_T offset = (SMB_OFF_T)u_offset;
+ SMB_OFF_T count = (SMB_OFF_T)u_count;
+
+ /*
+ * For the type of system we are, attempt to
+ * find the maximum positive lock offset as an SMB_OFF_T.
+ */
+
+#if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
+
+ /*
+ * In this case SMB_OFF_T is 64 bits,
+ * and the underlying system can handle 64 bit signed locks.
+ */
+
+ SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
+ SMB_OFF_T mask = (mask2<<1);
+ SMB_OFF_T max_positive_lock_offset = ~mask;
+
+#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * In this case either SMB_OFF_T is 32 bits,
+ * or the underlying system cannot handle 64 bit signed locks.
+ * All offsets & counts must be 2^31 or less.
+ */
+
+ SMB_OFF_T max_positive_lock_offset = 0x7FFFFFFF;
+
+#endif /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * POSIX locks of length zero mean lock to end-of-file.
+ * Win32 locks of length zero are point probes. Ignore
+ * any Win32 locks of length zero. JRA.
+ */
+
+ if (count == (SMB_OFF_T)0) {
+ DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n"));
+ return False;
+ }
+
+ /*
+ * If the given offset was > max_positive_lock_offset then we cannot map this at all
+ * ignore this lock.
+ */
+
+ if (u_offset & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
+ DEBUG(10,("posix_lock_in_range: (offset = %.0f) offset > %.0f and we cannot handle this. Ignoring lock.\n",
+ (double)u_offset, (double)((SMB_BIG_UINT)max_positive_lock_offset) ));
+ return False;
+ }
+
+ /*
+ * We must truncate the offset and count to less than max_positive_lock_offset.
+ */
+
+ offset &= max_positive_lock_offset;
+ count &= max_positive_lock_offset;
+
+
+ /*
+ * Deal with a very common case of count of all ones.
+ * (lock entire file).
+ */
+
+ if(count == (SMB_OFF_T)-1)
+ count = max_positive_lock_offset;
+
+ /*
+ * Truncate count to end at max lock offset.
+ */
+
+ if (offset + count < 0 || offset + count > max_positive_lock_offset)
+ count = max_positive_lock_offset - offset;
+
+ /*
+ * If we ate all the count, ignore this lock.
+ */
+
+ if (count == 0) {
+ DEBUG(10,("posix_lock_in_range: Count = 0. Ignoring lock u_offset = %.0f, u_count = %.0f\n",
+ (double)u_offset, (double)u_count ));
+ return False;
+ }
+
+ /*
+ * The mapping was successful.
+ */
+
+ DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
+ (double)offset, (double)count ));
+
+ *offset_out = offset;
+ *count_out = count;
+
+ return True;
+}
+
+/****************************************************************************
+ Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
+ broken NFS implementations.
+****************************************************************************/
+
+static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ int ret;
+ struct connection_struct *conn = fsp->conn;
+
+ DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fd,op,(double)offset,(double)count,type));
+
+ ret = conn->vfs_ops.lock(fsp,fsp->fd,op,offset,count,type);
+
+ if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
+
+ DEBUG(0,("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n",
+ (double)offset,(double)count));
+ DEBUG(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
+ DEBUG(0,("on 32 bit NFS mounted file systems.\n"));
+
+ /*
+ * If the offset is > 0x7FFFFFFF then this will cause problems on
+ * 32 bit NFS mounted filesystems. Just ignore it.
+ */
+
+ if (offset & ~((SMB_OFF_T)0x7fffffff)) {
+ DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
+ return True;
+ }
+
+ if (count & ~((SMB_OFF_T)0x7fffffff)) {
+ /* 32 bit NFS file system, retry with smaller offset */
+ DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
+ errno = 0;
+ count &= 0x7fffffff;
+ ret = conn->vfs_ops.lock(fsp,fsp->fd,op,offset,count,type);
+ }
+ }
+
+ DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
+
+ return ret;
+}
+
+/****************************************************************************
+ POSIX function to see if a file region is locked. Returns True if the
+ region is locked, False otherwise.
+****************************************************************************/
+
+BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ int posix_lock_type = map_posix_lock_type(fsp,lock_type);
+
+ DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * never set it, so presume it is not locked.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
+ return False;
+
+ /*
+ * Note that most UNIX's can *test* for a write lock on
+ * a read-only fd, just not *set* a write lock on a read-only
+ * fd. So we don't need to use map_lock_type here.
+ */
+
+ return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
+}
+
+/*
+ * Structure used when splitting a lock range
+ * into a POSIX lock range. Doubly linked list.
+ */
+
+struct lock_list {
+ struct lock_list *next;
+ struct lock_list *prev;
+ SMB_OFF_T start;
+ SMB_OFF_T size;
+};
+
+/****************************************************************************
+ Create a list of lock ranges that don't overlap a given range. Used in calculating
+ POSIX locks and unlocks. This is a difficult function that requires ASCII art to
+ understand it :-).
+****************************************************************************/
+
+static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, struct lock_list *lhead, files_struct *fsp)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+ TDB_DATA dbuf;
+ struct posix_lock *locks;
+ size_t num_locks, i;
+
+ dbuf.dptr = NULL;
+
+ dbuf = tdb_fetch(posix_lock_tdb, kbuf);
+
+ if (!dbuf.dptr)
+ return lhead;
+
+ locks = (struct posix_lock *)dbuf.dptr;
+ num_locks = (size_t)(dbuf.dsize / sizeof(*locks));
+
+ /*
+ * Check the current lock list on this dev/inode pair.
+ * Quit if the list is deleted.
+ */
+
+ DEBUG(10,("posix_lock_list: curr: start=%.0f,size=%.0f\n",
+ (double)lhead->start, (double)lhead->size ));
+
+ for (i=0; i<num_locks && lhead; i++) {
+
+ struct posix_lock *lock = &locks[i];
+ struct lock_list *l_curr;
+
+ /*
+ * Walk the lock list, checking for overlaps. Note that
+ * the lock list can expand within this loop if the current
+ * range being examined needs to be split.
+ */
+
+ for (l_curr = lhead; l_curr;) {
+
+ DEBUG(10,("posix_lock_list: lock: fd=%d: start=%.0f,size=%.0f:type=%s", lock->fd,
+ (double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) ));
+
+ if ( (l_curr->start >= (lock->start + lock->size)) ||
+ (lock->start >= (l_curr->start + l_curr->size))) {
+
+ /* No overlap with this lock - leave this range alone. */
+/*********************************************
+ +---------+
+ | l_curr |
+ +---------+
+ +-------+
+ | lock |
+ +-------+
+OR....
+ +---------+
+ | l_curr |
+ +---------+
+**********************************************/
+
+ DEBUG(10,("no overlap case.\n" ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start >= lock->start) &&
+ (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
+
+ /*
+ * This unlock is completely overlapped by this existing lock range
+ * and thus should have no effect (not be unlocked). Delete it from the list.
+ */
+/*********************************************
+ +---------+
+ | l_curr |
+ +---------+
+ +---------------------------+
+ | lock |
+ +---------------------------+
+**********************************************/
+ /* Save the next pointer */
+ struct lock_list *ul_next = l_curr->next;
+
+ DEBUG(10,("delete case.\n" ));
+
+ DLIST_REMOVE(lhead, l_curr);
+ if(lhead == NULL)
+ break; /* No more list... */
+
+ l_curr = ul_next;
+
+ } else if ( (l_curr->start >= lock->start) &&
+ (l_curr->start < lock->start + lock->size) &&
+ (l_curr->start + l_curr->size > lock->start + lock->size) ) {
+
+ /*
+ * This unlock overlaps the existing lock range at the high end.
+ * Truncate by moving start to existing range end and reducing size.
+ */
+/*********************************************
+ +---------------+
+ | l_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ | l_curr|
+ +-------+
+**********************************************/
+
+ l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size);
+ l_curr->start = lock->start + lock->size;
+
+ DEBUG(10,("truncate high case: start=%.0f,size=%.0f\n",
+ (double)l_curr->start, (double)l_curr->size ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start < lock->start) &&
+ (l_curr->start + l_curr->size > lock->start) &&
+ (l_curr->start + l_curr->size <= lock->start + lock->size) ) {
+
+ /*
+ * This unlock overlaps the existing lock range at the low end.
+ * Truncate by reducing size.
+ */
+/*********************************************
+ +---------------+
+ | l_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ | l_curr|
+ +-------+
+**********************************************/
+
+ l_curr->size = lock->start - l_curr->start;
+
+ DEBUG(10,("truncate low case: start=%.0f,size=%.0f\n",
+ (double)l_curr->start, (double)l_curr->size ));
+
+ l_curr = l_curr->next;
+
+ } else if ( (l_curr->start < lock->start) &&
+ (l_curr->start + l_curr->size > lock->start + lock->size) ) {
+ /*
+ * Worst case scenario. Unlock request completely overlaps an existing
+ * lock range. Split the request into two, push the new (upper) request
+ * into the dlink list, and continue with the entry after ul_new (as we
+ * know that ul_new will not overlap with this lock).
+ */
+/*********************************************
+ +---------------------------+
+ | l_curr |
+ +---------------------------+
+ +---------+
+ | lock |
+ +---------+
+BECOMES.....
+ +-------+ +---------+
+ | l_curr| | l_new |
+ +-------+ +---------+
+**********************************************/
+ struct lock_list *l_new = (struct lock_list *)talloc(ctx,
+ sizeof(struct lock_list));
+
+ if(l_new == NULL) {
+ DEBUG(0,("posix_lock_list: talloc fail.\n"));
+ return NULL; /* The talloc_destroy takes care of cleanup. */
+ }
+
+ ZERO_STRUCTP(l_new);
+ l_new->start = lock->start + lock->size;
+ l_new->size = l_curr->start + l_curr->size - l_new->start;
+
+ /* Truncate the l_curr. */
+ l_curr->size = lock->start - l_curr->start;
+
+ DEBUG(10,("split case: curr: start=%.0f,size=%.0f \
+new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size,
+ (double)l_new->start, (double)l_new->size ));
+
+ /*
+ * Add into the dlink list after the l_curr point - NOT at lhead.
+ * Note we can't use DLINK_ADD here as this inserts at the head of the given list.
+ */
+
+ l_new->prev = l_curr;
+ l_new->next = l_curr->next;
+ l_curr->next = l_new;
+
+ /* And move after the link we added. */
+ l_curr = l_new->next;
+
+ } else {
+
+ /*
+ * This logic case should never happen. Ensure this is the
+ * case by forcing an abort.... Remove in production.
+ */
+ pstring msg;
+
+ slprintf(msg, sizeof(msg)-1, "logic flaw in cases: l_curr: start = %.0f, size = %.0f : \
+lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size, (double)lock->start, (double)lock->size );
+
+ smb_panic(msg);
+ }
+ } /* end for ( l_curr = lhead; l_curr;) */
+ } /* end for (i=0; i<num_locks && ul_head; i++) */
+
+ SAFE_FREE(dbuf.dptr);
+
+ return lhead;
+}
+
+/****************************************************************************
+ POSIX function to acquire a lock. Returns True if the
+ lock could be granted, False if not.
+****************************************************************************/
+
+BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ BOOL ret = True;
+ size_t entry_num = 0;
+ size_t lock_count;
+ TALLOC_CTX *l_ctx = NULL;
+ struct lock_list *llist = NULL;
+ struct lock_list *ll = NULL;
+ int posix_lock_type = map_posix_lock_type(fsp,lock_type);
+
+ DEBUG(5,("set_posix_lock: File %s, offset = %.0f, count = %.0f, type = %s\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
+ return True;
+
+ /*
+ * Windows is very strange. It allows read locks to be overlayed
+ * (even over a write lock), but leaves the write lock in force until the first
+ * unlock. It also reference counts the locks. This means the following sequence :
+ *
+ * process1 process2
+ * ------------------------------------------------------------------------
+ * WRITE LOCK : start = 2, len = 10
+ * READ LOCK: start =0, len = 10 - FAIL
+ * READ LOCK : start = 0, len = 14
+ * READ LOCK: start =0, len = 10 - FAIL
+ * UNLOCK : start = 2, len = 10
+ * READ LOCK: start =0, len = 10 - OK
+ *
+ * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but
+ * would leave a single read lock over the 0-14 region. In order to
+ * re-create Windows semantics mapped to POSIX locks, we create multiple TDB
+ * entries, one for each overlayed lock request. We are guarenteed by the brlock
+ * semantics that if a write lock is added, then it will be first in the array.
+ */
+
+ if ((l_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("set_posix_lock: unable to init talloc context.\n"));
+ return True; /* Not a fatal error. */
+ }
+
+ if ((ll = (struct lock_list *)talloc(l_ctx, sizeof(struct lock_list))) == NULL) {
+ DEBUG(0,("set_posix_lock: unable to talloc unlock list.\n"));
+ talloc_destroy(l_ctx);
+ return True; /* Not a fatal error. */
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to add.
+ */
+
+ ZERO_STRUCTP(ll);
+ ll->start = offset;
+ ll->size = count;
+
+ DLIST_ADD(llist, ll);
+
+ /*
+ * The following call calculates if there are any
+ * overlapping locks held by this process on
+ * fd's open on the same file and splits this list
+ * into a list of lock ranges that do not overlap with existing
+ * POSIX locks.
+ */
+
+ llist = posix_lock_list(l_ctx, llist, fsp);
+
+ /*
+ * Now we have the list of ranges to lock it is safe to add the
+ * entry into the POSIX lock tdb. We take note of the entry we
+ * added here in case we have to remove it on POSIX lock fail.
+ */
+
+ if (!add_posix_lock_entry(fsp,offset,count,posix_lock_type,&entry_num)) {
+ DEBUG(0,("set_posix_lock: Unable to create posix lock entry !\n"));
+ talloc_destroy(l_ctx);
+ return False;
+ }
+
+ /*
+ * Add the POSIX locks on the list of ranges returned.
+ * As the lock is supposed to be added atomically, we need to
+ * back out all the locks if any one of these calls fail.
+ */
+
+ for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) {
+ offset = ll->start;
+ count = ll->size;
+
+ DEBUG(5,("set_posix_lock: Real lock: Type = %s: offset = %.0f, count = %.0f\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
+ DEBUG(5,("set_posix_lock: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
+ ret = False;
+ break;
+ }
+ }
+
+ if (!ret) {
+
+ /*
+ * Back out all the POSIX locks we have on fail.
+ */
+
+ for (ll = llist; lock_count; ll = ll->next, lock_count--) {
+ offset = ll->start;
+ count = ll->size;
+
+ DEBUG(5,("set_posix_lock: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n",
+ posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
+
+ posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK);
+ }
+
+ /*
+ * Remove the tdb entry for this lock.
+ */
+
+ delete_posix_lock_entry_by_index(fsp,entry_num);
+ }
+
+ talloc_destroy(l_ctx);
+ return ret;
+}
+
+/****************************************************************************
+ POSIX function to release a lock. Returns True if the
+ lock could be released, False if not.
+****************************************************************************/
+
+BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
+{
+ SMB_OFF_T offset;
+ SMB_OFF_T count;
+ BOOL ret = True;
+ TALLOC_CTX *ul_ctx = NULL;
+ struct lock_list *ulist = NULL;
+ struct lock_list *ul = NULL;
+ struct posix_lock deleted_lock;
+ int num_overlapped_entries;
+
+ DEBUG(5,("release_posix_lock: File %s, offset = %.0f, count = %.0f\n",
+ fsp->fsp_name, (double)u_offset, (double)u_count ));
+
+ /*
+ * If the requested lock won't fit in the POSIX range, we will
+ * pretend it was successful.
+ */
+
+ if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
+ return True;
+
+ /*
+ * We treat this as one unlock request for POSIX accounting purposes even
+ * if it may later be split into multiple smaller POSIX unlock ranges.
+ * num_overlapped_entries is the number of existing locks that have any
+ * overlap with this unlock request.
+ */
+
+ num_overlapped_entries = delete_posix_lock_entry(fsp, offset, count, &deleted_lock);
+
+ if (num_overlapped_entries == -1) {
+ smb_panic("release_posix_lock: unable find entry to delete !\n");
+ }
+
+ /*
+ * If num_overlapped_entries is > 0, and the lock_type we just deleted from the tdb was
+ * a POSIX write lock, then before doing the unlock we need to downgrade
+ * the POSIX lock to a read lock. This allows any overlapping read locks
+ * to be atomically maintained.
+ */
+
+ if (num_overlapped_entries > 0 && deleted_lock.lock_type == F_WRLCK) {
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) {
+ DEBUG(0,("release_posix_lock: downgrade of lock failed with error %s !\n", strerror(errno) ));
+ return False;
+ }
+ }
+
+ if ((ul_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("release_posix_lock: unable to init talloc context.\n"));
+ return True; /* Not a fatal error. */
+ }
+
+ if ((ul = (struct lock_list *)talloc(ul_ctx, sizeof(struct lock_list))) == NULL) {
+ DEBUG(0,("release_posix_lock: unable to talloc unlock list.\n"));
+ talloc_destroy(ul_ctx);
+ return True; /* Not a fatal error. */
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to remove.
+ */
+
+ ZERO_STRUCTP(ul);
+ ul->start = offset;
+ ul->size = count;
+
+ DLIST_ADD(ulist, ul);
+
+ /*
+ * The following call calculates if there are any
+ * overlapping locks held by this process on
+ * fd's open on the same file and creates a
+ * list of unlock ranges that will allow
+ * POSIX lock ranges to remain on the file whilst the
+ * unlocks are performed.
+ */
+
+ ulist = posix_lock_list(ul_ctx, ulist, fsp);
+
+ /*
+ * Release the POSIX locks on the list of ranges returned.
+ */
+
+ for(; ulist; ulist = ulist->next) {
+ offset = ulist->start;
+ count = ulist->size;
+
+ DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n",
+ (double)offset, (double)count ));
+
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK))
+ ret = False;
+ }
+
+ talloc_destroy(ul_ctx);
+
+ return ret;
+}
+
+/****************************************************************************
+ Remove all lock entries for a specific dev/inode pair from the tdb.
+****************************************************************************/
+
+static void delete_posix_lock_entries(files_struct *fsp)
+{
+ TDB_DATA kbuf = locking_key_fsp(fsp);
+
+ if (tdb_delete(posix_lock_tdb, kbuf) == -1)
+ DEBUG(0,("delete_close_entries: tdb_delete fail !\n"));
+}
+
+/****************************************************************************
+ Debug function.
+****************************************************************************/
+
+static void dump_entry(struct posix_lock *pl)
+{
+ DEBUG(10,("entry: start=%.0f, size=%.0f, type=%d, fd=%i\n",
+ (double)pl->start, (double)pl->size, (int)pl->lock_type, pl->fd ));
+}
+
+/****************************************************************************
+ Remove any locks on this fd. Called from file_close().
+****************************************************************************/
+
+void posix_locking_close_file(files_struct *fsp)
+{
+ struct posix_lock *entries = NULL;
+ size_t count, i;
+
+ /*
+ * Optimization for the common case where we are the only
+ * opener of a file. If all fd entries are our own, we don't
+ * need to explicitly release all the locks via the POSIX functions,
+ * we can just remove all the entries in the tdb and allow the
+ * close to remove the real locks.
+ */
+
+ count = get_posix_lock_entries(fsp, &entries);
+
+ if (count == 0) {
+ DEBUG(10,("posix_locking_close_file: file %s has no outstanding locks.\n", fsp->fsp_name ));
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (entries[i].fd != fsp->fd )
+ break;
+
+ dump_entry(&entries[i]);
+ }
+
+ if (i == count) {
+ /* All locks are ours. */
+ DEBUG(10,("posix_locking_close_file: file %s has %u outstanding locks, but all on one fd.\n",
+ fsp->fsp_name, (unsigned int)count ));
+ SAFE_FREE(entries);
+ delete_posix_lock_entries(fsp);
+ return;
+ }
+
+ /*
+ * Difficult case. We need to delete all our locks, whilst leaving
+ * all other POSIX locks in place.
+ */
+
+ for (i = 0; i < count; i++) {
+ struct posix_lock *pl = &entries[i];
+ if (pl->fd == fsp->fd)
+ release_posix_lock(fsp, (SMB_BIG_UINT)pl->start, (SMB_BIG_UINT)pl->size );
+ }
+ SAFE_FREE(entries);
+}
+
+/*******************************************************************
+ Create the in-memory POSIX lock databases.
+********************************************************************/
+
+BOOL posix_locking_init(int read_only)
+{
+ if (posix_lock_tdb && posix_pending_close_tdb)
+ return True;
+
+ if (!posix_lock_tdb)
+ posix_lock_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
+ if (!posix_lock_tdb) {
+ DEBUG(0,("Failed to open POSIX byte range locking database.\n"));
+ return False;
+ }
+ if (!posix_pending_close_tdb)
+ posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
+ if (!posix_pending_close_tdb) {
+ DEBUG(0,("Failed to open POSIX pending close database.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Delete the in-memory POSIX lock databases.
+********************************************************************/
+
+BOOL posix_locking_end(void)
+{
+ if (posix_lock_tdb && tdb_close(posix_lock_tdb) != 0)
+ return False;
+ if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0)
+ return False;
+ return True;
+}
diff --git a/source/mainpage.dox b/source/mainpage.dox
new file mode 100644
index 00000000000..8b72f804627
--- /dev/null
+++ b/source/mainpage.dox
@@ -0,0 +1,7 @@
+/**
+
+@mainpage
+
+@li \ref CodingSuggestions
+
+**/
diff --git a/source/md4.h b/source/md4.h
deleted file mode 100644
index 3f60d75fe3c..00000000000
--- a/source/md4.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This code is from rfc1186.
-*/
-
- /*
- ** ********************************************************************
- ** md4.h -- Header file for implementation of **
- ** MD4 Message Digest Algorithm **
- ** Updated: 2/13/90 by Ronald L. Rivest **
- ** (C) 1990 RSA Data Security, Inc. **
- ** ********************************************************************
- */
-
- /* MDstruct is the data structure for a message digest computation.
- */
- typedef struct {
- unsigned int buffer[4]; /* Holds 4-word result of MD computation */
- unsigned char count[8]; /* Number of bits processed so far */
- unsigned int done; /* Nonzero means MD computation finished */
- } MDstruct, *MDptr;
-
- /* MDbegin(MD)
-
-
-
- ** Input: MD -- an MDptr
- ** Initialize the MDstruct prepatory to doing a message digest
- ** computation.
- */
- extern void MDbegin();
-
- /* MDupdate(MD,X,count)
- ** Input: MD -- an MDptr
- ** X -- a pointer to an array of unsigned characters.
- ** count -- the number of bits of X to use (an unsigned int).
- ** Updates MD using the first "count" bits of X.
- ** The array pointed to by X is not modified.
- ** If count is not a multiple of 8, MDupdate uses high bits of
- ** last byte.
- ** This is the basic input routine for a user.
- ** The routine terminates the MD computation when count < 512, so
- ** every MD computation should end with one call to MDupdate with a
- ** count less than 512. Zero is OK for a count.
- */
- extern void MDupdate();
-
- /* MDprint(MD)
- ** Input: MD -- an MDptr
- ** Prints message digest buffer MD as 32 hexadecimal digits.
- ** Order is from low-order byte of buffer[0] to high-order byte
- ** of buffer[3].
- ** Each byte is printed with high-order hexadecimal digit first.
- */
- extern void MDprint();
-
- /*
- ** End of md4.h
- */
diff --git a/source/msdfs/README b/source/msdfs/README
new file mode 100644
index 00000000000..0e924b31dce
--- /dev/null
+++ b/source/msdfs/README
@@ -0,0 +1,32 @@
+Setting up MS Dfs in Samba
+kalele@veritas.com March 2000
+
+Currently, MS Dfs support is a configure time parameter (--with-msdfs). Can be changed later to always compile it in..
+
+To have a server announce itself as a Dfs server, add a "host msdfs=yes" entry to smb.conf.
+
+To make a share a Dfs root, add a "msdfs root=yes" entry to the share definition
+in the smb.conf file.
+e.g.
+[pub]
+ path = /export/publicsmb
+ msdfs root = yes
+
+To create dfs volumes/junctions in the share, create symbolic links of the
+format msdfs:server1\share1,server2\share2 and so on.
+
+In the above example, create a dfs volume "dfsstorage" in the [pub] share as:
+cd /export/publicsmb
+ln -s msdfs:serverA\\share dfsstorage
+
+Clicking on dfsstorage from a dfs-aware client will show you the contents of
+\\serverA\share
+
+Shares with "msdfs root = no" (which is the default) entries are served as normal
+shares and the client stops talking Dfs with Samba after a tconX.
+
+NOTES:
+* Windows clients need to be rebooted if a non-dfs root is made a dfs root or
+ vice versa. A better option is to introduce a new share and make it the dfs root.
+* Currently there's a restriction that msdfs symlink names should be all
+ lowercase.
diff --git a/source/msdfs/msdfs.c b/source/msdfs/msdfs.c
new file mode 100644
index 00000000000..f2915606e83
--- /dev/null
+++ b/source/msdfs/msdfs.c
@@ -0,0 +1,738 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ MSDfs services for Samba
+ Copyright (C) Shirish Kalele 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/**********************************************************************
+ Create a tcon relative path from a dfs_path structure
+ **********************************************************************/
+
+static void create_nondfs_path(char* pathname, struct dfs_path* pdp)
+{
+ pstrcpy(pathname,pdp->volumename);
+ pstrcat(pathname,"\\");
+ pstrcat(pathname,pdp->restofthepath);
+}
+
+/**********************************************************************
+ Parse the pathname of the form \hostname\service\volume\restofthepath
+ into the dfs_path structure
+ **********************************************************************/
+
+static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
+{
+ pstring pathname_local;
+ char* p,*temp;
+
+ pstrcpy(pathname_local,pathname);
+ p = temp = pathname_local;
+
+ ZERO_STRUCTP(pdp);
+
+ trim_string(temp,"\\","\\");
+ DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
+
+ /* now tokenize */
+ /* parse out hostname */
+ p = strchr_m(temp,'\\');
+ if(p == NULL)
+ return False;
+ *p = '\0';
+ pstrcpy(pdp->hostname,temp);
+ DEBUG(10,("hostname: %s\n",pdp->hostname));
+
+ /* parse out servicename */
+ temp = p+1;
+ p = strchr_m(temp,'\\');
+ if(p == NULL) {
+ pstrcpy(pdp->servicename,temp);
+ return True;
+ }
+ *p = '\0';
+ pstrcpy(pdp->servicename,temp);
+ DEBUG(10,("servicename: %s\n",pdp->servicename));
+
+ /* parse out volumename */
+ temp = p+1;
+ p = strchr_m(temp,'\\');
+ if(p == NULL) {
+ pstrcpy(pdp->volumename,temp);
+ return True;
+ }
+ *p = '\0';
+ pstrcpy(pdp->volumename,temp);
+ DEBUG(10,("volumename: %s\n",pdp->volumename));
+
+ /* remaining path .. */
+ pstrcpy(pdp->restofthepath,p+1);
+ DEBUG(10,("rest of the path: %s\n",pdp->restofthepath));
+ return True;
+}
+
+/********************************************************
+ Fake up a connection struct for the VFS layer.
+*********************************************************/
+
+static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
+{
+ ZERO_STRUCTP(conn);
+ conn->service = snum;
+ conn->connectpath = path;
+
+ if (!smbd_vfs_init(conn)) {
+ DEBUG(0,("create_conn_struct: vfs init failed.\n"));
+ return False;
+ }
+ return True;
+}
+
+/**********************************************************************
+ Forms a valid Unix pathname from the junction
+ **********************************************************************/
+
+static BOOL form_path_from_junction(struct junction_map* jn, char* path, int max_pathlen,
+ connection_struct *conn)
+{
+ int snum;
+
+ if(!path || !jn)
+ return False;
+
+ snum = lp_servicenumber(jn->service_name);
+ if(snum < 0)
+ return False;
+
+ safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
+ safe_strcat(path, "/", max_pathlen-1);
+ strlower(jn->volume_name);
+ safe_strcat(path, jn->volume_name, max_pathlen-1);
+
+ if (!create_conn_struct(conn, snum, path))
+ return False;
+
+ return True;
+}
+
+/**********************************************************************
+ Creates a junction structure from the Dfs pathname
+ **********************************************************************/
+
+BOOL create_junction(char* pathname, struct junction_map* jn)
+{
+ struct dfs_path dp;
+
+ parse_dfs_path(pathname,&dp);
+
+ /* check if path is dfs : check hostname is the first token */
+ if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0)) {
+ DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n", dp.hostname, pathname));
+ return False;
+ }
+
+ /* Check for a non-DFS share */
+ if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
+ DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
+ return False;
+ }
+
+ pstrcpy(jn->service_name,dp.servicename);
+ pstrcpy(jn->volume_name,dp.volumename);
+ return True;
+}
+
+/**********************************************************************
+ Parse the contents of a symlink to verify if it is an msdfs referral
+ A valid referral is of the form: msdfs:server1\share1,server2\share2
+ **********************************************************************/
+
+static BOOL parse_symlink(char* buf,struct referral** preflist, int* refcount)
+{
+ pstring temp;
+ char* prot;
+ char* alt_path[MAX_REFERRAL_COUNT];
+ int count=0, i;
+ struct referral* reflist;
+
+ pstrcpy(temp,buf);
+
+ prot = strtok(temp,":");
+
+ if(!strequal(prot, "msdfs"))
+ return False;
+
+ /* It's an msdfs referral */
+ if(!preflist)
+ return True;
+
+ /* parse out the alternate paths */
+ while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
+ count++;
+
+ DEBUG(10,("parse_symlink: count=%d\n", count));
+
+ reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
+ if(reflist == NULL) {
+ DEBUG(0,("parse_symlink: Malloc failed!\n"));
+ return False;
+ }
+
+ for(i=0;i<count;i++) {
+ /* replace / in the alternate path by a \ */
+ char* p = strchr_m(alt_path[i],'/');
+ if(p)
+ *p = '\\';
+
+ pstrcpy(reflist[i].alternate_path, "\\");
+ pstrcat(reflist[i].alternate_path, alt_path[i]);
+ reflist[i].proximity = 0;
+ reflist[i].ttl = REFERRAL_TTL;
+ DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
+ }
+
+ if(refcount)
+ *refcount = count;
+
+ return True;
+}
+
+/**********************************************************************
+ Returns true if the unix path is a valid msdfs symlink
+ **********************************************************************/
+
+BOOL is_msdfs_link(connection_struct* conn, char* path)
+{
+ SMB_STRUCT_STAT st;
+ pstring referral;
+ int referral_len = 0;
+
+ if(!path || !conn)
+ return False;
+
+ strlower(path);
+
+ if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
+ DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
+ return False;
+ }
+
+ if(S_ISLNK(st.st_mode)) {
+ /* open the link and read it */
+ referral_len = conn->vfs_ops.readlink(conn, path, referral, sizeof(pstring));
+ if(referral_len == -1)
+ DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
+
+ referral[referral_len] = '\0';
+ DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
+ if(parse_symlink(referral, NULL, NULL))
+ return True;
+ }
+ return False;
+}
+
+/**********************************************************************
+ Fills in the junction_map struct with the referrals from the
+ symbolic link
+ **********************************************************************/
+
+BOOL get_referred_path(struct junction_map* junction)
+{
+ pstring path;
+ pstring buf;
+ SMB_STRUCT_STAT st;
+ connection_struct conns;
+ connection_struct *conn = &conns;
+
+ if(!form_path_from_junction(junction, path, sizeof(path), conn))
+ return False;
+
+ DEBUG(5,("get_referred_path: lstat target: %s\n", path));
+
+ if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
+ DEBUG(5,("get_referred_path: %s does not exist.\n",path));
+ return False;
+ }
+
+ if(S_ISLNK(st.st_mode)) {
+ /* open the link and read it to get the dfs referral */
+ int linkcnt = 0;
+ linkcnt = conn->vfs_ops.readlink(conn, path, buf, sizeof(buf));
+ buf[linkcnt] = '\0';
+ DEBUG(5,("get_referred_path: Referral: %s\n",buf));
+ if(parse_symlink(buf, &junction->referral_list, &junction->referral_count))
+ return True;
+ }
+ return False;
+}
+
+/**************************************************************
+Decides if given pathname is Dfs and if it should be redirected
+Converts pathname to non-dfs format if Dfs redirection not required
+**************************************************************/
+
+BOOL dfs_redirect(char* pathname, connection_struct* conn)
+{
+ struct dfs_path dp;
+ pstring temp;
+ fstring path;
+
+ pstrcpy(temp,pathname);
+
+ if(!lp_msdfs_root(SNUM(conn)) )
+ return False;
+
+ parse_dfs_path(pathname,&dp);
+
+ if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0))
+ return False;
+
+ /* check if need to redirect */
+ fstrcpy(path, conn->connectpath);
+ fstrcat(path, "/");
+ fstrcat(path, dp.volumename);
+ if(is_msdfs_link(conn, path)) {
+ DEBUG(4,("dfs_redirect: Redirecting %s\n",temp));
+ return True;
+ } else {
+ create_nondfs_path(pathname,&dp);
+ DEBUG(4,("dfs_redirect: Not redirecting %s. Converted to non-dfs pathname \'%s\'\n",
+ temp,pathname));
+ return False;
+ }
+}
+
+/*
+ Special DFS redirect call for findfirst's.
+ If the findfirst is for the dfs junction, then no redirection,
+ if it is for the underlying directory contents, redirect.
+ */
+
+BOOL dfs_findfirst_redirect(char* pathname, connection_struct* conn)
+{
+ struct dfs_path dp;
+
+ pstring temp;
+
+ pstrcpy(temp,pathname);
+
+ /* Is the path Dfs-redirectable? */
+ if(!dfs_redirect(temp,conn)) {
+ pstrcpy(pathname,temp);
+ return False;
+ }
+
+ parse_dfs_path(pathname,&dp);
+ DEBUG(8,("dfs_findfirst_redirect: path %s is in Dfs. dp.restofthepath=.%s.\n",
+ pathname,dp.restofthepath));
+ if(!(*(dp.restofthepath))) {
+ create_nondfs_path(pathname,&dp);
+ return False;
+ }
+
+ return True;
+}
+
+static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
+ struct junction_map* junction,
+ BOOL self_referral)
+{
+ char* pdata = *ppdata;
+
+ unsigned char uni_requestedpath[1024];
+ int uni_reqpathoffset1,uni_reqpathoffset2;
+ int uni_curroffset;
+ int requestedpathlen=0;
+ int offset;
+ int reply_size = 0;
+ int i=0;
+
+ DEBUG(10,("setting up version2 referral\nRequested path:\n"));
+
+ requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
+ STR_TERMINATE);
+
+ dump_data(10,(const char *)uni_requestedpath,requestedpathlen);
+
+ DEBUG(10,("ref count = %u\n",junction->referral_count));
+
+ uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
+ VERSION2_REFERRAL_SIZE * junction->referral_count;
+
+ uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
+
+ uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
+
+ reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
+ 2 * requestedpathlen;
+ DEBUG(10,("reply_size: %u\n",reply_size));
+
+ /* add up the unicode lengths of all the referral paths */
+ for(i=0;i<junction->referral_count;i++) {
+ DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
+ reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
+ }
+
+ DEBUG(10,("reply_size = %u\n",reply_size));
+ /* add the unexplained 0x16 bytes */
+ reply_size += 0x16;
+
+ pdata = Realloc(pdata,reply_size);
+ if(pdata == NULL) {
+ DEBUG(0,("malloc failed for Realloc!\n"));
+ return -1;
+ }
+ else *ppdata = pdata;
+
+ /* copy in the dfs requested paths.. required for offset calculations */
+ memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
+ memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
+
+ /* create the header */
+ SSVAL(pdata,0,requestedpathlen-2); /* path consumed */
+ SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
+ if(self_referral)
+ SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
+ else
+ SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
+
+ offset = 8;
+ /* add the referral elements */
+ for(i=0;i<junction->referral_count;i++) {
+ struct referral* ref = &(junction->referral_list[i]);
+ int unilen;
+
+ SSVAL(pdata,offset,2); /* version 2 */
+ SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
+ if(self_referral)
+ SSVAL(pdata,offset+4,1);
+ else
+ SSVAL(pdata,offset+4,0);
+ SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
+ SIVAL(pdata,offset+8,ref->proximity);
+ SIVAL(pdata,offset+12,ref->ttl);
+
+ SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
+ SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
+ /* copy referred path into current offset */
+ unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
+ -1, STR_UNICODE);
+ SSVAL(pdata,offset+20,uni_curroffset-offset);
+
+ uni_curroffset += unilen;
+ offset += VERSION2_REFERRAL_SIZE;
+ }
+ /* add in the unexplained 22 (0x16) bytes at the end */
+ memset(pdata+uni_curroffset,'\0',0x16);
+ SAFE_FREE(junction->referral_list);
+ return reply_size;
+}
+
+static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
+ struct junction_map* junction,
+ BOOL self_referral)
+{
+ char* pdata = *ppdata;
+
+ unsigned char uni_reqpath[1024];
+ int uni_reqpathoffset1, uni_reqpathoffset2;
+ int uni_curroffset;
+ int reply_size = 0;
+
+ int reqpathlen = 0;
+ int offset,i=0;
+
+ DEBUG(10,("setting up version3 referral\n"));
+
+ reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
+
+ dump_data(10,(const char *)uni_reqpath,reqpathlen);
+
+ uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
+ uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
+ reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
+
+ for(i=0;i<junction->referral_count;i++) {
+ DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
+ reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
+ }
+
+ pdata = Realloc(pdata,reply_size);
+ if(pdata == NULL) {
+ DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
+ return -1;
+ }
+ else *ppdata = pdata;
+
+ /* create the header */
+ SSVAL(pdata,0,reqpathlen-2); /* path consumed */
+ SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
+ if(self_referral)
+ SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
+ else
+ SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
+
+ /* copy in the reqpaths */
+ memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
+ memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
+
+ offset = 8;
+ for(i=0;i<junction->referral_count;i++) {
+ struct referral* ref = &(junction->referral_list[i]);
+ int unilen;
+
+ SSVAL(pdata,offset,3); /* version 3 */
+ SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
+ if(self_referral)
+ SSVAL(pdata,offset+4,1);
+ else
+ SSVAL(pdata,offset+4,0);
+
+ SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
+ SIVAL(pdata,offset+8,ref->ttl);
+
+ SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
+ SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
+ /* copy referred path into current offset */
+
+ unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
+ -1, STR_UNICODE|STR_TERMINATE);
+ SSVAL(pdata,offset+16,uni_curroffset-offset);
+ /* copy 0x10 bytes of 00's in the ServiceSite GUID */
+ memset(pdata+offset+18,'\0',16);
+
+ uni_curroffset += unilen;
+ offset += VERSION3_REFERRAL_SIZE;
+ }
+ SAFE_FREE(junction->referral_list);
+ return reply_size;
+}
+
+/******************************************************************
+ * Set up the Dfs referral for the dfs pathname
+ ******************************************************************/
+
+int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
+{
+ struct junction_map junction;
+
+ BOOL self_referral;
+
+ int reply_size = 0;
+
+ ZERO_STRUCT(junction);
+
+ if(!create_junction(pathname, &junction))
+ return -1;
+
+ /* get the junction entry */
+ if(!get_referred_path(&junction)) {
+
+ /* refer the same pathname, create a standard referral struct */
+ struct referral* ref;
+ self_referral = True;
+ junction.referral_count = 1;
+ if((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
+ DEBUG(0,("malloc failed for referral\n"));
+ return -1;
+ }
+
+ pstrcpy(ref->alternate_path,pathname);
+ ref->proximity = 0;
+ ref->ttl = REFERRAL_TTL;
+ junction.referral_list = ref;
+ } else {
+ self_referral = False;
+ if( DEBUGLVL( 3 ) ) {
+ int i=0;
+ dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathname);
+ for(i=0;i<junction.referral_count;i++)
+ dbgtext(" %s",junction.referral_list[i].alternate_path);
+ dbgtext(".\n");
+ }
+ }
+
+ /* create the referral depeding on version */
+ DEBUG(10,("max_referral_level :%d\n",max_referral_level));
+ if(max_referral_level<2 || max_referral_level>3)
+ max_referral_level = 2;
+
+ switch(max_referral_level) {
+ case 2:
+ {
+ reply_size = setup_ver2_dfs_referral(pathname, ppdata, &junction, self_referral);
+ break;
+ }
+ case 3:
+ {
+ reply_size = setup_ver3_dfs_referral(pathname, ppdata, &junction, self_referral);
+ break;
+ }
+ default:
+ {
+ DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
+ return -1;
+ }
+ }
+
+ DEBUG(10,("DFS Referral pdata:\n"));
+ dump_data(10,*ppdata,reply_size);
+ return reply_size;
+}
+
+/**********************************************************************
+ The following functions are called by the NETDFS RPC pipe functions
+ **********************************************************************/
+
+BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
+{
+ pstring path;
+ pstring msdfs_link;
+ connection_struct conns;
+ connection_struct *conn = &conns;
+ int i=0;
+
+ if(!form_path_from_junction(jn, path, sizeof(path), conn))
+ return False;
+
+ /* form the msdfs_link contents */
+ pstrcpy(msdfs_link, "msdfs:");
+ for(i=0; i<jn->referral_count; i++) {
+ char* refpath = jn->referral_list[i].alternate_path;
+
+ trim_string(refpath, "\\", "\\");
+ if(*refpath == '\0')
+ continue;
+
+ if(i>0)
+ pstrcat(msdfs_link, ",");
+
+ pstrcat(msdfs_link, refpath);
+ }
+
+ DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
+
+ if(exists)
+ if(conn->vfs_ops.unlink(conn,path)!=0)
+ return False;
+
+ if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
+ DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
+ path, msdfs_link, strerror(errno)));
+ return False;
+ }
+ return True;
+}
+
+BOOL remove_msdfs_link(struct junction_map* jn)
+{
+ pstring path;
+ connection_struct conns;
+ connection_struct *conn = &conns;
+
+ if(!form_path_from_junction(jn, path, sizeof(path), conn))
+ return False;
+
+ if(conn->vfs_ops.unlink(conn, path)!=0)
+ return False;
+
+ return True;
+}
+
+static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
+{
+ int cnt = *jn_count;
+ DIR *dirp;
+ char* dname;
+ pstring connect_path;
+ char* service_name = lp_servicename(snum);
+ connection_struct conns;
+ connection_struct *conn = &conns;
+
+ pstrcpy(connect_path,lp_pathname(snum));
+
+ if(*connect_path == '\0')
+ return False;
+
+ /*
+ * Fake up a connection struct for the VFS layer.
+ */
+
+ if (!create_conn_struct(conn, snum, connect_path))
+ return False;
+
+ /* form a junction for the msdfs root - convention */
+ /*
+ pstrpcy(jn[cnt].service_name, service_name);
+ jn[cnt].volume_name[0] = '\0';
+ jn[cnt].referral_count = 1;
+
+ slprintf(alt_path,sizeof(alt_path)-1"\\\\%s\\%s", global_myname, service_name);
+ jn[cnt].referral_l
+ */
+
+ dirp = conn->vfs_ops.opendir(conn, connect_path);
+ if(!dirp)
+ return False;
+
+ while((dname = vfs_readdirname(conn, dirp)) != NULL) {
+ SMB_STRUCT_STAT st;
+ pstring pathreal;
+ fstring buf;
+ int buflen = 0;
+ pstrcpy(pathreal, connect_path);
+ pstrcat(pathreal, "/");
+ pstrcat(pathreal, dname);
+
+ if(conn->vfs_ops.lstat(conn,pathreal,&st) != 0) {
+ DEBUG(4,("lstat error for %s: %s\n",pathreal, strerror(errno)));
+ continue;
+ }
+ if(S_ISLNK(st.st_mode)) {
+ buflen = conn->vfs_ops.readlink(conn, pathreal, buf, sizeof(fstring));
+ buf[buflen] = '\0';
+ if(parse_symlink(buf, &(jn[cnt].referral_list), &(jn[cnt].referral_count))) {
+ pstrcpy(jn[cnt].service_name, service_name);
+ pstrcpy(jn[cnt].volume_name, dname);
+ cnt++;
+ }
+ }
+ }
+
+ conn->vfs_ops.closedir(conn,dirp);
+ *jn_count = cnt;
+ return True;
+}
+
+int enum_msdfs_links(struct junction_map* jn)
+{
+ int i=0;
+ int jn_count = 0;
+
+ if(!lp_host_msdfs())
+ return -1;
+
+ for(i=0;*lp_servicename(i);i++) {
+ if(lp_msdfs_root(i))
+ form_junctions(i,jn,&jn_count);
+ }
+ return jn_count;
+}
diff --git a/source/nameserv.c b/source/nameserv.c
deleted file mode 100644
index 802b98ec0a0..00000000000
--- a/source/nameserv.c
+++ /dev/null
@@ -1,2318 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.h"
-
-
-static void queue_packet(struct packet_struct *packet);
-void process(void);
-static void dump_names(void);
-static void announce_request(char *group);
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip);
-
-extern int DEBUGLEVEL;
-
-extern pstring debugf;
-pstring servicesf = CONFIGFILE;
-
-extern pstring scope;
-
-extern BOOL CanRecurse;
-
-extern struct in_addr myip;
-extern struct in_addr bcast_ip;
-extern struct in_addr Netmask;
-extern pstring myhostname;
-static pstring host_file;
-static pstring myname="";
-
-static int ClientNMB= -1;
-static int ClientDGRAM= -1;
-
-static BOOL needannounce=True;
-
-/* this is our name database */
-static struct name_record *namelist = NULL;
-
-/* list of servers to be returned by NetServerEnum */
-static struct server_record *serverlist = NULL;
-
-/* this is the domain list. For the moment we will assume that our
- primary domain is the first one listed in this list */
-static struct domain_record *domainlist = NULL;
-
-/* are we running as a daemon ? */
-static BOOL is_daemon = False;
-
-/* machine comment for host announcements */
-static pstring ServerComment="";
-
-static BOOL got_bcast = False;
-static BOOL got_myip = False;
-static BOOL got_nmask = False;
-
-static BOOL updatedlists = False;
-static int updatecount=0;
-
-/* what server type are we currently */
-static int ServerType =
-SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_TIME_SOURCE |
-SV_TYPE_SERVER_UNIX |
-SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER;
-
-/* here are my election parameters */
-
-/* NTAS uses 2, NT uses 1, WfWg uses 0 */
-#define MAINTAIN_LIST 1
-#define ELECTION_VERSION 1
-
-static BOOL RunningElection = False;
-static BOOL needelection = False;
-static int ElectionCount = 0;
-static int StartupTime =0;
-
-
-/* WfWg uses 01040b01 */
-/* Win95 uses 01041501 */
-/* NTAS uses ?? */
-static uint32 ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
-
-/* we currently support being the master for just one group. Being the
- master for more than one group might be tricky as NetServerEnum is
- often asked for a list without naming the group */
-static fstring PrimaryGroup="";
-
-#define AM_MASTER (PrimaryGroup[0] && (ServerType & SV_TYPE_MASTER_BROWSER))
-
-#define MSBROWSE "\001\002__MSBROWSE__\002"
-
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
-
-/****************************************************************************
-catch a sighup
-****************************************************************************/
-static int sig_hup()
-{
- BlockSignals(True);
-
- DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
- dump_names();
- reload_services(True);
-
- BlockSignals(False);
-#ifndef DONT_REINSTALL_SIG
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
- return(0);
-}
-
-/****************************************************************************
-catch a sigpipe
-****************************************************************************/
-static int sig_pipe()
-{
- BlockSignals(True);
-
- DEBUG(0,("Got SIGPIPE\n"));
- if (!is_daemon)
- exit(1);
- BlockSignals(False);
- return(0);
-}
-
-#if DUMP_CORE
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
-static BOOL dump_core(void)
-{
- char *p;
- pstring dname;
- strcpy(dname,debugf);
- if ((p=strrchr(dname,'/'))) *p=0;
- strcat(dname,"/corefiles");
- mkdir(dname,0700);
- sys_chown(dname,getuid(),getgid());
- chmod(dname,0700);
- if (chdir(dname)) return(False);
- umask(~(0700));
-
-#ifndef NO_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit(RLIMIT_CORE, &rlp);
- rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
- setrlimit(RLIMIT_CORE, &rlp);
- getrlimit(RLIMIT_CORE, &rlp);
- DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
- }
-#endif
-#endif
-
-
- DEBUG(0,("Dumping core in %s\n",dname));
- return(True);
-}
-#endif
-
-
-/****************************************************************************
-possibly continue after a fault
-****************************************************************************/
-static void fault_continue(void)
-{
- static int errcount=1;
-
- errcount--;
-
- if (is_daemon && errcount)
- process();
-
-#if DUMP_CORE
- if (dump_core()) return;
-#endif
-
- return;
-}
-
-
-/*******************************************************************
- wrapper to get the DC
- ******************************************************************/
-static char *domain_controller(void)
-{
- char *dc = lp_domain_controller();
- /* so many people mistake this for a bool that we need to handle it. sigh. */
- if (!*dc || strequal(dc,"yes") || strequal(dc,"true"))
- strcpy(dc,myname);
- return(dc);
-}
-
-
-
-/****************************************************************************
- true if two netbios names are equal
-****************************************************************************/
-static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
-{
- if (n1->name_type != n2->name_type) return(False);
-
- return(strequal(n1->name,n2->name) && strequal(n1->scope,n2->scope));
-}
-
-/****************************************************************************
- add a netbios name into the namelist
- **************************************************************************/
-static void add_name(struct name_record *n)
-{
- struct name_record *n2;
-
- if (!namelist) {
- namelist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
-
- for (n2 = namelist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-}
-
-/****************************************************************************
- add a domain into the list
- **************************************************************************/
-static void add_domain(struct domain_record *d)
-{
- struct domain_record *d2;
-
- if (!domainlist) {
- domainlist = d;
- d->prev = NULL;
- d->next = NULL;
- return;
- }
-
- for (d2 = domainlist; d2->next; d2 = d2->next) ;
-
- d2->next = d;
- d->next = NULL;
- d->prev = d2;
-}
-
-
-/****************************************************************************
- add a server into the list
- **************************************************************************/
-static void add_server(struct server_record *s)
-{
- struct server_record *s2;
-
- if (!serverlist) {
- serverlist = s;
- s->prev = NULL;
- s->next = NULL;
- return;
- }
-
- for (s2 = serverlist; s2->next; s2 = s2->next) ;
-
- s2->next = s;
- s->next = NULL;
- s->prev = s2;
-}
-
-/****************************************************************************
- remove a name from the namelist. The pointer must be an element just
- retrieved
- **************************************************************************/
-static void remove_name(struct name_record *n)
-{
- struct name_record *nlist = namelist;
- while (nlist && nlist != n) nlist = nlist->next;
- if (nlist) {
- if (nlist->next) nlist->next->prev = nlist->prev;
- if (nlist->prev) nlist->prev->next = nlist->next;
- free(nlist);
- }
-}
-
-/****************************************************************************
- find a name in the namelist
- **************************************************************************/
-static struct name_record *find_name(struct nmb_name *n)
-{
- struct name_record *ret;
- for (ret = namelist; ret; ret = ret->next)
- if (name_equal(&ret->name,n)) return(ret);
-
- return(NULL);
-}
-
-/****************************************************************************
- dump a copy of the name table
- **************************************************************************/
-static void dump_names(void)
-{
- time_t t = time(NULL);
- struct name_record *n;
- struct domain_record *d;
-
- DEBUG(3,("Dump of local name table:\n"));
-
- for (n = namelist; n; n = n->next) {
- DEBUG(3,("%s %s TTL=%d Unique=%s\n",
- namestr(&n->name),
- inet_ntoa(n->ip),
- n->death_time?n->death_time-t:0,
- BOOLSTR(n->unique)));
- }
-
- DEBUG(3,("\nDump of domain list:\n"));
- for (d = domainlist; d; d = d->next)
- DEBUG(3,("%s %s\n",d->name,inet_ntoa(d->bcast_ip)));
-}
-
-
-/****************************************************************************
- add a host entry to the name list
- ****************************************************************************/
-static struct name_record *add_host_entry(char *name,int type,BOOL unique,int ttl,
- enum name_source source,
- struct in_addr ip)
-{
- struct name_record *n;
- struct name_record *n2=NULL;
-
- n = (struct name_record *)malloc(sizeof(*n));
- if (!n) return(NULL);
-
- bzero((char *)n,sizeof(*n));
-
- make_nmb_name(&n->name,name,type,scope);
- if ((n2=find_name(&n->name))) {
- free(n);
- n = n2;
- }
-
- if (ttl) n->death_time = time(NULL)+ttl*3;
- n->ip = ip;
- n->unique = unique;
- n->source = source;
-
- if (!n2) add_name(n);
-
- DEBUG(3,("Added host entry %s at %s ttl=%d unique=%s\n",
- namestr(&n->name),inet_ntoa(ip),ttl,BOOLSTR(unique)));
-
- return(n);
-}
-
-
-/****************************************************************************
- add a domain entry
- ****************************************************************************/
-static struct domain_record *add_domain_entry(char *name,struct in_addr ip)
-{
- struct domain_record *d;
-
- d = (struct domain_record *)malloc(sizeof(*d));
-
- if (!d) return(NULL);
-
- bzero((char *)d,sizeof(*d));
-
- if (zero_ip(ip)) ip = bcast_ip;
-
- StrnCpy(d->name,name,sizeof(d->name)-1);
- d->bcast_ip = ip;
-
- if (!PrimaryGroup[0] && ip_equal(bcast_ip,ip) && name[0] != '*') {
- strcpy(PrimaryGroup,name);
- strupper(PrimaryGroup);
- DEBUG(3,("Setting primary group to %s (%s)\n",PrimaryGroup,inet_ntoa(ip)));
- }
-
- add_domain(d);
-
- ip = *interpret_addr2("255.255.255.255");
- if (name[0] != '*') add_host_entry(name,0x1e,False,0,SELF,ip);
-
- DEBUG(3,("Added domain entry %s at %s\n",
- name,inet_ntoa(ip)));
-
- return(d);
-}
-
-/****************************************************************************
- add a server entry
- ****************************************************************************/
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace)
-{
- BOOL newentry=False;
- struct server_record *s;
-
- for (s = serverlist; s; s = s->next)
- if (strequal(name,s->name)) break;
-
- if (s && !replace) {
- DEBUG(4,("Not replacing %s\n",name));
- return(s);
- }
-
- updatedlists=True;
-
- if (!s) {
- newentry = True;
- s = (struct server_record *)malloc(sizeof(*s));
-
- if (!s) return(NULL);
-
- bzero((char *)s,sizeof(*s));
- }
-
- /* update the entry */
- StrnCpy(s->name,name,sizeof(s->name)-1);
- StrnCpy(s->comment,comment,sizeof(s->comment)-1);
- s->servertype = servertype;
- s->death_time = ttl?time(NULL)+ttl*3:0;
- strupper(s->name);
- if (s->servertype & SV_TYPE_DOMAIN_ENUM) strupper(s->comment);
-
- if (!newentry) return(s);
-
- add_server(s);
-
- if (newentry) {
- DEBUG(3,("Added server entry %s of type %x (%s)\n",
- name,servertype,comment));
- } else {
- DEBUG(3,("Updated server entry %s of type %x (%s)\n",
- name,servertype,comment));
- }
-
- return(s);
-}
-
-
-/****************************************************************************
- add the magic samba names, useful for finding samba servers
- **************************************************************************/
-static void add_my_names(void)
-{
- struct in_addr ip;
-
- ip = *interpret_addr2("0.0.0.0");
-
- add_host_entry(myname,0x20,True,0,SELF,ip);
- add_host_entry(myname,0x0,True,0,SELF,ip);
- add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */
- add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */
-
- if (!domainlist)
- add_domain_entry(lp_workgroup(),bcast_ip);
- add_server_entry(myname,
- ServerType,
- 0,ServerComment,True);
-
- add_host_entry("__SAMBA__",0x20,True,0,SELF,ip);
- add_host_entry("__SAMBA__",0x0,True,0,SELF,ip);
-
- if (lp_preferred_master()) {
- DEBUG(3,("Preferred master startup\n"));
- needelection = True;
- ElectionCriterion |= (1<<3);
- }
-
- ElectionCriterion |= (lp_os_level() << 24);
-}
-
-
-/*******************************************************************
- write out browse.dat
- ******************************************************************/
-static void write_browse_list(void)
-{
- struct server_record *s;
- pstring fname,fnamenew;
- FILE *f;
-
- updatecount++;
-
- strcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
- strcpy(fnamenew,fname);
- strcat(fnamenew,".");
-
- f = fopen(fnamenew,"w");
-
- if (!f) {
- DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
- }
-
- for (s=serverlist; s ; s = s->next) {
- /* don't list domains I don't have a master for */
- if ((s->servertype & SV_TYPE_DOMAIN_ENUM) && !s->comment[0]) continue;
-
- fprintf(f,"\"%s\"\t%08x\t\"%s\"\n",s->name,s->servertype,s->comment);
- }
-
-
- fclose(f);
- chmod(fnamenew,0644);
- /* unlink(fname); */
- rename(fnamenew,fname);
- DEBUG(3,("Wrote browse list %s\n",fname));
-}
-
-/*******************************************************************
- expire old names in the namelist and serverlist
- ******************************************************************/
-static void expire_names(void)
-{
- static time_t lastrun=0;
- time_t t = time(NULL);
- struct name_record *n;
- struct name_record *next;
- struct server_record *s;
- struct server_record *nexts;
-
- if (!lastrun) lastrun = t;
- if (t < lastrun + 5) return;
- lastrun = t;
-
- /* expire old names */
- for (n = namelist; n; n = next) {
- if (n->death_time && n->death_time < t) {
- DEBUG(3,("Removing dead name %s\n",
- namestr(&n->name)));
- next = n->next;
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
- if (namelist == n) namelist = n->next;
- free(n);
- } else {
- next = n->next;
- }
- }
-
- /* expire old entries in the serverlist */
- for (s = serverlist; s; s = nexts) {
- if (s->death_time && s->death_time < t) {
- DEBUG(3,("Removing dead server %s\n",s->name));
- updatedlists = True;
- nexts = s->next;
- if (s->prev) s->prev->next = s->next;
- if (s->next) s->next->prev = s->prev;
- if (serverlist == s) serverlist = s->next;
- free(s);
- } else {
- nexts = s->next;
- }
- }
-}
-
-
-/*******************************************************************
- delete old names from the namelist
- ******************************************************************/
-static void housekeeping(void)
-{
- time_t t = time(NULL);
-
- expire_names();
-
- /* write out the browse.dat database for smbd to get */
- if (updatedlists) {
- write_browse_list();
- updatedlists = False;
- }
-
- {
- /* occasionally check to see if the master browser is around */
- static time_t lastrun=0;
- if (!lastrun) lastrun = t;
- if (t < lastrun + 5*60) return;
- lastrun = t;
-
- if (!AM_MASTER && PrimaryGroup[0] &&
- !name_query(ClientNMB,PrimaryGroup,0x1d,True,False,
- bcast_ip,NULL,queue_packet)) {
- DEBUG(2,("Forcing election on %s\n",PrimaryGroup));
- needelection = True;
- }
- }
-}
-
-
-/****************************************************************************
- reload the services file
- **************************************************************************/
-BOOL reload_services(BOOL test)
-{
- BOOL ret;
- extern fstring remote_machine;
-
- strcpy(remote_machine,"nmbd");
-
- if (lp_loaded())
- {
- pstring fname;
- strcpy(fname,lp_configfile());
- if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
- {
- strcpy(servicesf,fname);
- test = False;
- }
- }
-
- if (test && !lp_file_list_changed())
- return(True);
-
- ret = lp_load(servicesf,True);
-
- /* perhaps the config filename is now set */
- if (!test)
- reload_services(True);
-
- return(ret);
-}
-
-
-
-/****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
-{
- FILE *f = fopen(fname,"r");
- pstring line;
- if (!f) {
- DEBUG(2,("Can't open lmhosts file %s\n",fname));
- return;
- }
-
- while (!feof(f))
- {
- if (!fgets_slash(line,sizeof(pstring),f)) continue;
-
- if (*line == '#') continue;
-
- {
- BOOL group=False;
- string ip,name,flags,extra;
- char *ptr;
- int count = 0;
- struct in_addr ipaddr;
- enum name_source source = LMHOSTS;
-
- *ip = *name = *flags = *extra = 0;
-
- ptr = line;
-
- if (next_token(&ptr,ip,NULL)) ++count;
- if (next_token(&ptr,name,NULL)) ++count;
- if (next_token(&ptr,flags,NULL)) ++count;
- if (next_token(&ptr,extra,NULL)) ++count;
-
- if (count <= 0) continue;
-
- if (count > 0 && count < 2)
- {
- DEBUG(0,("Ill formed hosts line [%s]\n",line));
- continue;
- }
-
- if (strchr(flags,'G') || strchr(flags,'S'))
- group = True;
-
- if (strchr(flags,'M') && !group) {
- source = SELF;
- strcpy(myname,name);
- }
-
- ipaddr = *interpret_addr2(ip);
-
- if (group) {
- add_domain_entry(name,ipaddr);
- } else {
- add_host_entry(name,0x20,True,0,source,ipaddr);
- }
- }
- }
-
- fclose(f);
-}
-
-/*******************************************************************
- check if 2 IPs are on the same net
- we will assume the local netmask, although this could be wrong XXXX
- ******************************************************************/
-static BOOL same_net(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long net1,net2,nmask;
-
- nmask = ntohl(Netmask.s_addr);
- net1 = ntohl(ip1.s_addr);
- net2 = ntohl(ip2.s_addr);
-
- return((net1 & nmask) == (net2 & nmask));
-}
-
-/****************************************************************************
- send an election packet
- **************************************************************************/
-static void send_election(char *group,uint32 criterion,int timeup,char *name)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending election to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 8; /* election */
- p++;
-
- CVAL(p,0) = ELECTION_VERSION;
- SIVAL(p,1,criterion);
- SIVAL(p,5,timeup*1000); /* ms - despite the spec */
- p += 13;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- name,group,0,0x1e,bcast_ip,myip);
-}
-
-
-/****************************************************************************
- send a backup list response
- **************************************************************************/
-static void send_backup_list(char *name,int token,struct nmb_name *to,
- struct in_addr ip)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending backup list to %s for workgroup %s\n",
- inet_ntoa(ip),PrimaryGroup));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 10; /* backup list response */
- p++;
-
- CVAL(p,0) = 1; /* count */
- SIVAL(p,1,token);
- p += 5;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,to->name,0,to->name_type,ip,myip);
-}
-
-
-/*******************************************************************
- become the master browser
- ******************************************************************/
-static void become_master(void)
-{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX;
- DEBUG(2,("Becoming master for %s\n",PrimaryGroup));
-
- ServerType |= SV_TYPE_MASTER_BROWSER;
- ServerType |= SV_TYPE_BACKUP_BROWSER;
- ElectionCriterion |= 0x5;
-
- add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip);
- add_host_entry(MSBROWSE,1,False,0,SELF,myip);
-
- if (lp_domain_master()) {
- add_host_entry(myname,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip);
- ServerType |= SV_TYPE_DOMAIN_MASTER;
- if (lp_domain_logons()) {
- ServerType |= SV_TYPE_DOMAIN_CTRL;
- ServerType |= SV_TYPE_DOMAIN_MEMBER;
- domain_type |= SV_TYPE_DOMAIN_CTRL;
- }
- }
-
- add_server_entry(PrimaryGroup,domain_type,0,myname,True);
- add_server_entry(myname,ServerType,0,ServerComment,True);
-
- announce_request(PrimaryGroup);
-
- needannounce = True;
-}
-
-
-/*******************************************************************
- unbecome the master browser
- ******************************************************************/
-static void become_nonmaster(void)
-{
- struct name_record *n;
- struct nmb_name nn;
-
- DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup));
-
- ServerType &= ~SV_TYPE_MASTER_BROWSER;
- ServerType &= ~SV_TYPE_DOMAIN_CTRL;
- ServerType &= ~SV_TYPE_DOMAIN_MASTER;
-
- ElectionCriterion &= ~0x4;
-
- make_nmb_name(&nn,PrimaryGroup,0x1d,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,PrimaryGroup,0x1b,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,MSBROWSE,1,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-}
-
-
-/*******************************************************************
- run the election
- ******************************************************************/
-static void run_election(void)
-{
- time_t t = time(NULL);
- static time_t lastime = 0;
-
- if (!PrimaryGroup[0] || !RunningElection) return;
-
- /* send election packets once a second */
- if (lastime &&
- t-lastime <= 0) return;
-
- lastime = t;
-
- send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname);
-
- if (ElectionCount++ < 4) return;
-
- /* I won! now what :-) */
- RunningElection = False;
- DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup));
- become_master();
-}
-
-
-/****************************************************************************
- construct a host announcement unicast
- **************************************************************************/
-static void announce_host(struct domain_record *d,char *my_name,char *comment)
-{
- time_t t = time(NULL);
- pstring outbuf;
- char *p;
- char *namep;
- char *stypep;
- char *commentp;
- uint32 stype = ServerType;
-
- if (needannounce) {
- /* drop back to a max 3 minute announce - this is to prevent a
- single lost packet from stuffing things up for too long */
- d->announce_interval = MIN(d->announce_interval,3*60);
- d->lastannounce_time = t - (d->announce_interval+1);
- }
-
- /* announce every minute at first then progress to every 12 mins */
- if (d->lastannounce_time &&
- (t - d->lastannounce_time) < d->announce_interval)
- return;
-
- if (d->announce_interval < 12*60) d->announce_interval += 60;
- d->lastannounce_time = t;
-
- DEBUG(2,("Sending announcement to %s for workgroup %s\n",
- inet_ntoa(d->bcast_ip),d->name));
-
- if (!strequal(PrimaryGroup,d->name) ||
- !ip_equal(bcast_ip,d->bcast_ip)) {
- stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
- SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
- SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
- }
-
- if (!*comment) comment = "NoComment";
- if (!*my_name) my_name = "NoName";
-
- if (strlen(comment) > 43) comment[43] = 0;
-
- bzero(outbuf,sizeof(outbuf));
- CVAL(outbuf,0) = 1; /* host announce */
- p = outbuf+1;
-
- CVAL(p,0) = updatecount;
- SIVAL(p,1,d->announce_interval*1000); /* ms - despite the spec */
- namep = p+5;
- StrnCpy(p+5,my_name,16);
- strupper(p+5);
- CVAL(p,21) = 2; /* major version */
- CVAL(p,22) = 2; /* minor version */
- stypep = p+23;
- SIVAL(p,23,stype);
- SSVAL(p,27,0xaa55); /* browse signature */
- SSVAL(p,29,1); /* browse version */
- commentp = p+31;
- strcpy(p+31,comment);
- p += 31;
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- my_name,d->name,0,0x1d,d->bcast_ip,myip);
-
- /* if I'm the master then I also need to do a local master and
- domain announcement */
-
- if (AM_MASTER &&
- strequal(d->name,PrimaryGroup) &&
- ip_equal(bcast_ip,d->bcast_ip)) {
-
- /* do master announcements as well */
- SIVAL(stypep,0,ServerType);
-
- CVAL(outbuf,0) = 15; /* local master announce */
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- my_name,PrimaryGroup,0,0x1e,d->bcast_ip,myip);
-
- CVAL(outbuf,0) = 12; /* domain announce */
- StrnCpy(namep,PrimaryGroup,15);
- strupper(namep);
- StrnCpy(commentp,myname,15);
- strupper(commentp);
- SIVAL(stypep,0,(unsigned)0x80000000);
- p = commentp + strlen(commentp) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- my_name,MSBROWSE,0,1,d->bcast_ip,myip);
- }
-}
-
-
-/****************************************************************************
- send a announce request to the local net
- **************************************************************************/
-static void announce_request(char *group)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending announce request to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 2; /* announce request */
- p++;
-
- CVAL(p,0) = 0; /* flags?? */
- p++;
- StrnCpy(p,myname,16);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,group,0,0,bcast_ip,myip);
-}
-
-/****************************************************************************
- announce myself as a master to the PDC
- **************************************************************************/
-static void announce_master(char *group)
-{
- static time_t last=0;
- time_t t = time(NULL);
- pstring outbuf;
- char *p;
- struct in_addr ip,pdc_ip;
- fstring pdcname;
- *pdcname = 0;
-
- if (strequal(domain_controller(),myname)) return;
-
- if (!AM_MASTER || (last && (t-last < 10*60))) return;
- last = t;
-
- ip = *interpret_addr2(domain_controller());
-
- if (zero_ip(ip)) ip = bcast_ip;
-
- if (!name_query(ClientNMB,PrimaryGroup,
- 0x1b,False,False,ip,&pdc_ip,queue_packet)) {
- DEBUG(2,("Failed to find PDC at %s\n",domain_controller()));
- return;
- }
-
- name_status(ClientNMB,PrimaryGroup,0x1b,False,
- pdc_ip,NULL,pdcname,queue_packet);
-
- if (!pdcname[0]) {
- DEBUG(3,("Can't find netbios name of PDC at %s\n",inet_ntoa(pdc_ip)));
- } else {
- sync_browse_lists(pdcname,0x20,myname,PrimaryGroup,pdc_ip);
- }
-
-
- DEBUG(2,("Sending master announce to %s for workgroup %s\n",
- inet_ntoa(pdc_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 13; /* announce request */
- p++;
-
- StrnCpy(p,myname,16);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,PrimaryGroup,0x1b,0,pdc_ip,myip);
-}
-
-
-/*******************************************************************
- am I listening on a name. Should check name_type as well
-
- This is primarily used to prevent us gathering server lists from
- other workgroups we aren't a part of
- ******************************************************************/
-static BOOL listening(struct nmb_name *n)
-{
- if (!strequal(n->scope,scope)) return(False);
-
- if (strequal(n->name,myname) ||
- strequal(n->name,PrimaryGroup) ||
- strequal(n->name,MSBROWSE))
- return(True);
-
- return(False);
-}
-
-
-/*******************************************************************
- process a domain announcement frame
-
- Announce frames come in 3 types. Servers send host announcements
- (command=1) to let the master browswer know they are
- available. Master browsers send local master announcements
- (command=15) to let other masters and backups that they are the
- master. They also send domain announcements (command=12) to register
- the domain
-
- The comment field of domain announcements contains the master
- browser name. The servertype is used by NetServerEnum to select
- resources. We just have to pass it to smbd (via browser.dat) and let
- the client choose using bit masks.
- ******************************************************************/
-static void process_announce(struct packet_struct *p,int command,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int update_count = CVAL(buf,0);
- int ttl = IVAL(buf,1)/1000;
- char *name = buf+5;
- int osmajor=CVAL(buf,21);
- int osminor=CVAL(buf,22);
- uint32 servertype = IVAL(buf,23);
- char *comment = buf+31;
-
- name[15] = 0;
- comment[43] = 0;
-
- DEBUG(3,("Announce(%d) %s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
- command,name,update_count,ttl,osmajor,osminor,
- servertype,comment));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!listening(&dgram->dest_name)) return;
-
- ttl = GET_TTL(ttl);
-
- /* add them to our browse list */
- add_server_entry(name,servertype,ttl,comment,True);
-
-}
-
-/*******************************************************************
- process a master announcement frame
- ******************************************************************/
-static void process_master_announce(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- char *name = buf;
-
- name[15] = 0;
-
- DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!AM_MASTER || !listening(&dgram->dest_name)) return;
-
- /* merge browse lists with them */
- if (lp_domain_master())
- sync_browse_lists(name,0x20,myname,PrimaryGroup,p->ip);
-}
-
-
-/*******************************************************************
- process a backup list request
-
- A client send a backup list request to ask for a list of servers on
- the net that maintain server lists for a domain. A server is then
- chosen from this list to send NetServerEnum commands to to list
- available servers.
-
- Currently samba only sends back one name in the backup list, its
- wn. For larger nets we'll have to add backups and send "become
- backup" requests occasionally.
- ******************************************************************/
-static void process_backup_list(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int count = CVAL(buf,0);
- int token = IVAL(buf,1);
-
- DEBUG(3,("Backup request to %s token=%d\n",
- namestr(&dgram->dest_name),
- token));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (count <= 0) return;
-
- if (!AM_MASTER ||
- !strequal(PrimaryGroup,dgram->dest_name.name))
- return;
-
- if (!listening(&dgram->dest_name)) return;
-
- send_backup_list(myname,token,
- &dgram->source_name,
- p->ip);
-}
-
-
-/*******************************************************************
- work out if I win an election
- ******************************************************************/
-static BOOL win_election(int version,uint32 criterion,int timeup,char *name)
-{
- time_t t = time(NULL);
- uint32 mycriterion;
- if (version > ELECTION_VERSION) return(False);
- if (version < ELECTION_VERSION) return(True);
-
- mycriterion = ElectionCriterion;
-
- if (criterion > mycriterion) return(False);
- if (criterion < mycriterion) return(True);
-
- if (timeup > (t - StartupTime)) return(False);
- if (timeup < (t - StartupTime)) return(True);
-
- if (strcasecmp(myname,name) > 0) return(False);
-
- return(True);
-}
-
-
-/*******************************************************************
- process a election packet
-
- An election dynamically decides who will be the master.
- ******************************************************************/
-static void process_election(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int version = CVAL(buf,0);
- uint32 criterion = IVAL(buf,1);
- int timeup = IVAL(buf,5)/1000;
- char *name = buf+13;
-
- name[15] = 0;
-
- DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
- name,version,criterion,timeup));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!listening(&dgram->dest_name)) return;
-
- if (win_election(version,criterion,timeup,name)) {
- if (!RunningElection) {
- needelection = True;
- ElectionCount=0;
- }
- } else {
- needelection = False;
- if (RunningElection) {
- RunningElection = False;
- DEBUG(3,(">>> Lost election on %s <<<\n",PrimaryGroup));
-
- /* if we are the master then remove our masterly names */
- if (AM_MASTER)
- become_nonmaster();
- }
- }
-}
-
-
-/*******************************************************************
- process a announcement request
-
- clients send these when they want everyone to send an announcement
- immediately. This can cause quite a storm of packets!
- ******************************************************************/
-static void process_announce_request(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int flags = CVAL(buf,0);
- char *name = buf+1;
-
- name[15] = 0;
-
- DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- needannounce = True;
-}
-
-
-/****************************************************************************
-process a browse frame
-****************************************************************************/
-static void process_browse_packet(struct packet_struct *p,char *buf,int len)
-{
- int command = CVAL(buf,0);
- switch (command)
- {
- case 1: /* host announce */
- case 12: /* domain announce */
- case 15: /* local master announce */
- process_announce(p,command,buf+1);
- break;
-
- case 2: /* announce request */
- process_announce_request(p,buf+1);
- break;
-
- case 8: /* election */
- process_election(p,buf+1);
- break;
-
- case 9: /* get backup list */
- process_backup_list(p,buf+1);
- break;
-
- case 13: /* master announcement */
- process_master_announce(p,buf+1);
- break;
- }
-}
-
-
-/****************************************************************************
- process a domain logon packet
- **************************************************************************/
-static void process_logon_packet(struct packet_struct *p,char *buf,int len)
-{
- char *logname,*q;
- pstring outbuf;
- struct dgram_packet *dgram = &p->packet.dgram;
- int code;
-
- if (!lp_domain_logons()) {
- DEBUG(3,("No domain logons\n"));
- return;
- }
- if (!listening(&dgram->dest_name)) {
- DEBUG(4,("Not listening to that domain\n"));
- return;
- }
-
- q = outbuf;
- bzero(outbuf,sizeof(outbuf));
-
- code = SVAL(buf,0);
- switch (code) {
- case 0:
- {
- char *machine = buf+2;
- char *user = skip_string(machine,1);
- logname = skip_string(user,1);
-
- SSVAL(q,0,6);
- q += 2;
- strcpy(q,"\\\\");
- q += 2;
- StrnCpy(q,myname,16);
- strupper(q);
- q = skip_string(q,1);
- SSVAL(q,0,0xFFFF);
- q += 2;
-
- DEBUG(3,("Domain login request from %s(%s) user=%s\n",
- machine,inet_ntoa(p->ip),user));
- }
- break;
- case 7:
- {
- char *machine = buf+2;
- logname = skip_string(machine,1);
-
- SSVAL(q,0,0xc);
- q += 2;
- StrnCpy(q,domain_controller(),16);
- strupper(q);
- q = skip_string(q,1);
- q += PutUniCode(q,domain_controller());
- q += PutUniCode(q,dgram->dest_name.name);
- SSVAL(q,0,0xFFFF);
- q += 2;
-
- DEBUG(3,("GETDC request from %s(%s)\n",
- machine,inet_ntoa(p->ip)));
- }
- break;
- default:
- DEBUG(3,("Unknown domain request %d\n",code));
- return;
- }
-
-
- send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
- myname,&dgram->source_name.name[0],0,0,p->ip,myip);
-}
-
-/****************************************************************************
-process udp 138 datagrams
-****************************************************************************/
-static void process_dgram(struct packet_struct *p)
-{
- char *buf;
- char *buf2;
- int len;
- struct dgram_packet *dgram = &p->packet.dgram;
-
- if (dgram->header.msg_type != 0x10 &&
- dgram->header.msg_type != 0x11 &&
- dgram->header.msg_type != 0x12) {
- /* don't process error packets etc yet */
- return;
- }
-
- buf = &dgram->data[0];
- buf -= 4; /* XXXX for the pseudo tcp length -
- someday I need to get rid of this */
-
- if (CVAL(buf,smb_com) != SMBtrans) return;
-
- len = SVAL(buf,smb_vwv11);
- buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
-
- DEBUG(3,("datagram from %s to %s for %s of type %d len=%d\n",
- namestr(&dgram->source_name),namestr(&dgram->dest_name),
- smb_buf(buf),CVAL(buf2,0),len));
-
- if (len <= 0) return;
-
- if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE")) {
- process_browse_packet(p,buf2,len);
- } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) {
- process_logon_packet(p,buf2,len);
- }
-
-}
-
-/*******************************************************************
- find a workgroup using the specified broadcast
- ******************************************************************/
-static BOOL find_workgroup(char *name,struct in_addr ip)
-{
- fstring name1;
- BOOL ret;
- struct in_addr ipout;
-
- strcpy(name1,MSBROWSE);
-
- ret = name_query(ClientNMB,name1,0x1,True,False,ip,&ipout,queue_packet);
- if (!ret) return(False);
-
- name_status(ClientNMB,name1,0x1,False,ipout,name,NULL,queue_packet);
-
- if (name[0] != '*') {
- DEBUG(2,("Found workgroup %s on broadcast %s\n",name,inet_ntoa(ip)));
- } else {
- DEBUG(3,("Failed to find workgroup %s on broadcast %s\n",name,inet_ntoa(ip)));
- }
- return(name[0] != '*');
-}
-
-
-/****************************************************************************
- a hook for announce handling - called every minute
- **************************************************************************/
-static void do_announcements(void)
-{
- struct domain_record *d;
-
- for (d = domainlist; d; d = d->next) {
- /* if the ip address is 0 then set to the broadcast */
- if (zero_ip(d->bcast_ip)) d->bcast_ip = bcast_ip;
-
- /* if the workgroup is '*' then find a workgroup to be part of */
- if (d->name[0] == '*') {
- if (!find_workgroup(d->name,d->bcast_ip)) continue;
- add_host_entry(d->name,0x1e,False,0,SELF,
- *interpret_addr2("255.255.255.255"));
- if (!PrimaryGroup[0] && ip_equal(bcast_ip,d->bcast_ip)) {
- strcpy(PrimaryGroup,d->name);
- strupper(PrimaryGroup);
- }
- }
-
- announce_host(d,myname,ServerComment);
- }
-
- /* if I have a domain controller then announce to it */
- if (AM_MASTER)
- announce_master(PrimaryGroup);
-
- needannounce=False;
-}
-
-/*******************************************************************
- check if someone still owns a name
- ******************************************************************/
-static BOOL confirm_name(struct name_record *n)
-{
- struct in_addr ipout;
- BOOL ret = name_query(ClientNMB,n->name.name,
- n->name.name_type,False,
- False,n->ip,&ipout,queue_packet);
- return(ret && ip_equal(ipout,n->ip));
-}
-
-/****************************************************************************
-reply to a name release
-****************************************************************************/
-static void reply_name_release(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- struct in_addr ip;
- int rcode=0;
- int nb_flags = nmb->additional->rdata[0];
- BOOL bcast = nmb->header.nm_flags.bcast;
-
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- {
- struct name_record *n = find_name(&nmb->question.question_name);
- if (n && n->unique && n->source == REGISTER &&
- ip_equal(ip,n->ip)) {
- remove_name(n); n = NULL;
- }
-
- /* XXXX under what conditions should we reject the removal?? */
- }
-
- DEBUG(3,("Name release on name %s rcode=%d\n",
- namestr(&nmb->question.question_name),rcode));
-
- if (bcast) return;
-
- /* Send a NAME RELEASE RESPONSE */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True;
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = 0;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = nb_flags;
- putip(&nmb2->answers->rdata[2],(char *)&ip);
-
- send_packet(&p2);
-}
-
-/****************************************************************************
- reply to a reg request
- **************************************************************************/
-static void reply_name_reg(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- BOOL bcast = nmb->header.nm_flags.bcast;
- int ttl = GET_TTL(nmb->additional->ttl);
- int name_type = nmb->question.question_name.name_type;
- int nb_flags = nmb->additional->rdata[0];
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- struct in_addr ip;
- BOOL group = (nb_flags&0x80)?True:False;
- int rcode = 0;
-
- if (wildcard) return;
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- if (group) {
- /* apparently we should return 255.255.255.255 for group queries (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
-
- {
- struct name_record *n = find_name(&nmb->question.question_name);
-
- if (n) {
- if (!group && !ip_equal(ip,n->ip)) {
- /* check if the previous owner still wants it,
- if so reject the registration, otherwise change the owner
- and refresh */
- if (n->source != REGISTER || confirm_name(n)) {
- rcode = 6;
- } else {
- n->ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s changed owner to %s\n",
- namestr(&n->name),inet_ntoa(n->ip)));
- }
- } else {
- /* refresh the name */
- if (n->source != SELF)
- n->death_time = ttl?p->timestamp + ttl*3:0;
- }
- } else {
- /* add the name to our database */
- n = add_host_entry(qname,name_type,!group,ttl,REGISTER,ip);
- }
- }
-
- if (bcast) return;
-
- DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
- namestr(&nmb->question.question_name),
- inet_ntoa(ip),rcode));
-
- /* Send a NAME REGISTRATION RESPONSE */
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.opcode = 5;
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True;
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
-
- nmb2->answers->ttl = ttl;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = nb_flags;
- putip(&nmb2->answers->rdata[2],(char *)&ip);
-
- send_packet(&p2);
-}
-
-
-/****************************************************************************
-reply to a name status query
-****************************************************************************/
-static void reply_name_status(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- char *buf;
- int count;
- int rcode = 0;
- struct name_record *n = find_name(&nmb->question.question_name);
-
- DEBUG(3,("Name status for name %s\n",
- namestr(&nmb->question.question_name)));
-
- if (!wildcard && (!n || n->source != SELF))
- return;
-
- /* Send a POSITIVE NAME STATUS RESPONSE */
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True; /* WfWg ignores
- non-authoritative answers */
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = 0;
-
- for (count=0, n = namelist ; n; n = n->next) {
- if (n->source != SELF) continue;
- count++;
- }
-
- count = MIN(count,400/18); /* XXXX hack, we should calculate exactly
- how many will fit */
-
-
- buf = &nmb2->answers->rdata[0];
- SCVAL(buf,0,count);
- buf += 1;
-
- for (n = namelist ; n; n = n->next)
- {
- if (n->source != SELF) continue;
-
- bzero(buf,18);
- strcpy(buf,n->name.name);
- strupper(buf);
- buf[15] = n->name.name_type;
- buf += 16;
- buf[0] = 0x4; /* active */
- if (!n->unique) buf[0] |= 0x80; /* group */
- buf += 2;
- count--;
- }
-
- /* XXXXXXX we should fill in more fields of the statistics structure */
- bzero(buf,64);
- {
- extern int num_good_sends,num_good_receives;
- SIVAL(buf,20,num_good_sends);
- SIVAL(buf,24,num_good_receives);
- }
- SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
-
- buf += 64;
-
- nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]);
-
- send_packet(&p2);
-}
-
-
-
-/****************************************************************************
-reply to a name query
-****************************************************************************/
-static void reply_name_query(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct in_addr retip;
- int name_type = nmb->question.question_name.name_type;
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- int ttl=0;
- int rcode=0;
- BOOL unique = True;
-
- DEBUG(3,("Name query for %s from %s (bcast=%s) - ",
- namestr(&nmb->question.question_name),
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
-
- if (wildcard)
- retip = myip;
-
- if (!wildcard) {
- struct name_record *n = find_name(&nmb->question.question_name);
-
- if (!n) {
- struct in_addr ip;
- unsigned long a;
-
- /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
- if (name_type != 0x20 && name_type != 0) {
- DEBUG(3,("not found\n"));
- return;
- }
-
- /* look it up with DNS */
- a = interpret_addr(qname);
-
- putip((char *)&ip,(char *)&a);
-
- if (!a) {
- /* no luck with DNS. We could possibly recurse here XXXX */
- /* if this isn't a bcast then we should send a negative reply XXXX */
- DEBUG(3,("no recursion\n"));
- add_host_entry(qname,name_type,True,60*60,DNSFAIL,ip);
- return;
- }
-
- /* add it to our cache of names. give it 2 hours in the cache */
- n = add_host_entry(qname,name_type,True,2*60*60,DNS,ip);
-
- /* failed to add it? yikes! */
- if (!n) return;
- }
-
- /* don't respond to bcast queries for group names unless we own them */
- if (bcast && !n->unique && !n->source == SELF) {
- DEBUG(3,("no bcast replies\n"));
- return;
- }
-
- /* don't respond to bcast queries for addresses on the same net as the
- machine doing the querying unless its our IP */
- if (bcast &&
- n->source != SELF &&
- same_net(n->ip,p->ip)) {
- DEBUG(3,("same net\n"));
- return;
- }
-
- /* is our entry already dead? */
- if (n->death_time) {
- if (n->death_time < p->timestamp) return;
- ttl = n->death_time - p->timestamp;
- }
-
- retip = n->ip;
- unique = n->unique;
-
- /* it may have been an earlier failure */
- if (n->source == DNSFAIL) {
- DEBUG(3,("DNSFAIL\n"));
- return;
- }
- }
-
- /* if the IP is 0 then substitute my IP - we should see which one is on the
- right interface for the caller to do this right XXX */
- if (zero_ip(retip)) retip = myip;
-
- DEBUG(3,("OK %s rcode=%d\n",inet_ntoa(retip),rcode));
-
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True; /* WfWg ignores
- non-authoritative answers */
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = ttl;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = unique?0:0x80;
- nmb2->answers->rdata[1] = 0;
- putip(&nmb2->answers->rdata[2],(char *)&retip);
-
- send_packet(&p2);
-}
-
-
-
-/* the global packet linked-list. incoming entries are added to the
- end of this list. it is supposed to remain fairly short so we
- won't bother with an end pointer. */
-static struct packet_struct *packet_queue = NULL;
-
-
-/*******************************************************************
- queue a packet into the packet queue
- ******************************************************************/
-static void queue_packet(struct packet_struct *packet)
-{
- struct packet_struct *p;
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
- }
-
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next) ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
-
-/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-static void process_nmb(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
-
- /* if this is a response then ignore it */
- if (nmb->header.response) return;
-
- switch (nmb->header.opcode)
- {
- case 5:
- case 8:
- case 9:
- if (nmb->header.qdcount>0 &&
- nmb->header.arcount>0) {
- reply_name_reg(p);
- return;
- }
- break;
-
- case 0:
- if (nmb->header.qdcount>0)
- {
- switch (nmb->question.question_type)
- {
- case 0x20:
- reply_name_query(p);
- break;
-
- case 0x21:
- reply_name_status(p);
- break;
- }
- return;
- }
- break;
-
- case 6:
- if (nmb->header.qdcount>0 &&
- nmb->header.arcount>0) {
- reply_name_release(p);
- return;
- }
- break;
- }
-
-}
-
-
-
-/*******************************************************************
- run elements off the packet queue till its empty
- ******************************************************************/
-static void run_packet_queue(void)
-{
- struct packet_struct *p;
-
- while ((p=packet_queue)) {
- switch (p->packet_type)
- {
- case NMB_PACKET:
- process_nmb(p);
- break;
-
- case DGRAM_PACKET:
- process_dgram(p);
- break;
- }
-
- packet_queue = packet_queue->next;
- if (packet_queue) packet_queue->prev = NULL;
- free_packet(p);
- }
-}
-
-
-/****************************************************************************
- The main select loop, listen for packets and respond
- ***************************************************************************/
-void process(void)
-{
-
- while (True)
- {
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
- if (needelection && PrimaryGroup[0] && !RunningElection) {
- DEBUG(3,(">>> Starting election on %s <<<\n",PrimaryGroup));
- ElectionCount = 0;
- RunningElection = True;
- needelection = False;
- }
-
- FD_ZERO(&fds);
- FD_SET(ClientNMB,&fds);
- FD_SET(ClientDGRAM,&fds);
- /* during elections we need to send election packets at one
- second intervals */
- timeout.tv_sec = RunningElection?1:NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
-
- selrtn = sys_select(&fds,&timeout);
-
- if (FD_ISSET(ClientNMB,&fds)) {
- struct packet_struct *packet = read_packet(ClientNMB,NMB_PACKET);
- if (packet) queue_packet(packet);
- }
-
- if (FD_ISSET(ClientDGRAM,&fds)) {
- struct packet_struct *packet = read_packet(ClientDGRAM,DGRAM_PACKET);
- if (packet) queue_packet(packet);
- }
-
- if (RunningElection)
- run_election();
-
- run_packet_queue();
-
- do_announcements();
-
- housekeeping();
- }
-}
-
-
-/****************************************************************************
- open the socket communication
-****************************************************************************/
-static BOOL open_sockets(BOOL isdaemon,int port)
-{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
- if (isdaemon)
- ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
- else
- ClientNMB = 0;
-
- ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
-
- if (ClientNMB == -1)
- return(False);
-
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-
- set_socket_options(ClientNMB,"SO_BROADCAST");
- set_socket_options(ClientDGRAM,"SO_BROADCAST");
-
- DEBUG(3, ("Socket opened.\n"));
- return True;
-}
-
-
-/*******************************************************************
- check that a IP, bcast and netmask and consistent. Must be a 1s
- broadcast
- ******************************************************************/
-static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast,
- struct in_addr nmask)
-{
- unsigned long a_ip,a_bcast,a_nmask;
-
- a_ip = ntohl(ip.s_addr);
- a_bcast = ntohl(bcast.s_addr);
- a_nmask = ntohl(nmask.s_addr);
-
- /* check the netmask is sane */
- if (((a_nmask>>24)&0xFF) != 0xFF) {
- DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask)));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_ip&a_nmask) != (a_bcast&a_nmask)) {
- DEBUG(0,("IP and broadcast are on different nets!\n"));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_bcast|a_nmask) != 0xFFFFFFFF) {
- DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast)));
- return(False);
- }
-
- return(True);
-}
-
-/****************************************************************************
- initialise connect, service and file structs
-****************************************************************************/
-static BOOL init_structs(void )
-{
- if (!get_myname(myhostname,got_myip?NULL:&myip))
- return(False);
-
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip1,ip2;
-
- ip0 = myip;
-
- if (!(got_bcast && got_nmask))
- {
- get_broadcast(&ip0,&ip1,&ip2);
-
- if (!got_myip)
- myip = ip0;
-
- if (!got_bcast)
- bcast_ip = ip1;
-
- if (!got_nmask)
- Netmask = ip2;
- }
-
- DEBUG(1,("Using IP %s ",inet_ntoa(myip)));
- DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip)));
- DEBUG(1,("netmask %s\n",inet_ntoa(Netmask)));
-
- if (!ip_consistent(myip,bcast_ip,Netmask)) {
- DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n"));
- DEBUG(0,("You are likely to experience problems with this setup!\n"));
- }
- }
-
- if (! *myname) {
- char *p;
- strcpy(myname,myhostname);
- p = strchr(myname,'.');
- if (p) *p = 0;
- }
-
- {
- extern fstring local_machine;
- strcpy(local_machine,myname);
- strupper(local_machine);
- }
-
- return True;
-}
-
-/****************************************************************************
-usage on the program
-****************************************************************************/
-static void usage(char *pname)
-{
- DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
-
- printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
- printf("\t-l log basename. Basename for log/debug files\n");
- printf("\t-n netbiosname. the netbios name to advertise for this host\n");
- printf("\t-B broadcast address the address to use for broadcasts\n");
- printf("\t-N netmask the netmask to use for subnet determination\n");
- printf("\t-H hosts file load a netbios hosts file\n");
- printf("\t-I ip-address override the IP address\n");
- printf("\t-G group name add a group name to be part of\n");
- printf("\t-C comment sets the machine comment that appears in browse lists\n");
- printf("\n");
-}
-
-
-/****************************************************************************
- main program
- **************************************************************************/
-int main(int argc,char *argv[])
-{
- int port = NMB_PORT;
- int opt;
- extern FILE *dbf;
- extern char *optarg;
-
- *host_file = 0;
-
-#if 0
- sleep(10);
-#endif
-
- StartupTime = time(NULL);
-
- TimeInit();
-
- strcpy(debugf,NMBLOGFILE);
-
- setup_logging(argv[0],False);
-
- charset_initialise();
-
-#ifdef LMHOSTSFILE
- strcpy(host_file,LMHOSTSFILE);
-#endif
-
- /* this is for people who can't start the program correctly */
- while (argc > 1 && (*argv[1] != '-'))
- {
- argv++;
- argc--;
- }
-
- fault_setup(fault_continue);
-
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-
- bcast_ip = *interpret_addr2("0.0.0.0");
- myip = *interpret_addr2("0.0.0.0");
-
- while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
- switch (opt)
- {
- case 's':
- strcpy(servicesf,optarg);
- break;
- case 'C':
- strcpy(ServerComment,optarg);
- break;
- case 'G':
- add_domain_entry(optarg,bcast_ip);
- break;
- case 'H':
- strcpy(host_file,optarg);
- break;
- case 'I':
- myip = *interpret_addr2(optarg);
- got_myip = True;
- break;
- case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
- break;
- case 'N':
- Netmask = *interpret_addr2(optarg);
- got_nmask = True;
- break;
- case 'n':
- strcpy(myname,optarg);
- break;
- case 'l':
- sprintf(debugf,"%s.nmb",optarg);
- break;
- case 'i':
- strcpy(scope,optarg);
- strupper(scope);
- break;
- case 'D':
- is_daemon = True;
- break;
- case 'd':
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'h':
- usage(argv[0]);
- exit(0);
- break;
- default:
- if (!is_a_socket(0))
- usage(argv[0]);
- break;
- }
-
- DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
- DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
-
- init_structs();
-
- if (!reload_services(False))
- return(-1);
-
- if (*host_file)
- {
- load_hosts_file(host_file);
- DEBUG(3,("Loaded hosts file\n"));
- }
-
- if (!*ServerComment)
- strcpy(ServerComment,"Samba %v");
- string_sub(ServerComment,"%v",VERSION);
- string_sub(ServerComment,"%h",myhostname);
-
- add_my_names();
-
- DEBUG(3,("Checked names\n"));
-
- dump_names();
-
- DEBUG(3,("Dumped names\n"));
-
- if (!is_daemon && !is_a_socket(0)) {
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
- is_daemon = True;
- }
-
-
- if (is_daemon) {
- DEBUG(2,("%s becoming a daemon\n",timestring()));
- become_daemon();
- }
-
-
- DEBUG(3,("Opening sockets\n"));
-
- if (open_sockets(is_daemon,port))
- {
- process();
- close_sockets();
- }
-
- if (dbf)
- fclose(dbf);
- return(0);
-}
diff --git a/source/nmbd/.cvsignore b/source/nmbd/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/nmbd/.cvsignore
diff --git a/source/nmbd/asyncdns.c b/source/nmbd/asyncdns.c
new file mode 100644
index 00000000000..5ae2eb202da
--- /dev/null
+++ b/source/nmbd/asyncdns.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/Netbios implementation.
+ a async DNS handler
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/***************************************************************************
+ Add a DNS result to the name cache.
+****************************************************************************/
+
+static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+
+
+ if (!addr.s_addr) {
+ /* add the fail to WINS cache of names. give it 1 hour in the cache */
+ DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
+ (void)add_name_to_subnet( wins_server_subnet, qname, name_type,
+ NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr );
+ return( NULL );
+ }
+
+ /* add it to our WINS cache of names. give it 2 hours in the cache */
+ DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
+
+ return( add_name_to_subnet( wins_server_subnet, qname, name_type,
+ NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr ) );
+}
+
+
+
+#ifndef SYNC_DNS
+
+static int fd_in = -1, fd_out = -1;
+static pid_t child_pid = -1;
+static int in_dns;
+
+/* this is the structure that is passed between the parent and child */
+struct query_record {
+ struct nmb_name name;
+ struct in_addr result;
+};
+
+/* a queue of pending requests waiting to be sent to the DNS child */
+static struct packet_struct *dns_queue;
+
+/* the packet currently being processed by the dns child */
+static struct packet_struct *dns_current;
+
+
+/***************************************************************************
+ return the fd used to gather async dns replies. This is added to the select
+ loop
+ ****************************************************************************/
+int asyncdns_fd(void)
+{
+ return fd_in;
+}
+
+/***************************************************************************
+ handle DNS queries arriving from the parent
+ ****************************************************************************/
+static void asyncdns_process(void)
+{
+ struct query_record r;
+ fstring qname;
+
+ DEBUGLEVEL = -1;
+
+ while (1) {
+ if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+
+ fstrcpy(qname, r.name.name);
+
+ r.result.s_addr = interpret_addr(qname);
+
+ if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+ }
+
+ _exit(0);
+}
+
+/**************************************************************************** **
+ catch a sigterm (in the child process - the parent has a different handler
+ see nmbd.c for details).
+ We need a separate term handler here so we don't release any
+ names that our parent is going to release, or overwrite a
+ WINS db that our parent is going to write.
+ **************************************************************************** */
+
+static void sig_term(int sig)
+{
+ _exit(0);
+}
+
+/***************************************************************************
+ Called by the parent process when it receives a SIGTERM - also kills the
+ child so we don't get child async dns processes lying around, causing trouble.
+ ****************************************************************************/
+
+void kill_async_dns_child(void)
+{
+ if(child_pid != 0 && child_pid != -1)
+ kill(child_pid, SIGTERM);
+}
+
+/***************************************************************************
+ create a child process to handle DNS lookups
+ ****************************************************************************/
+void start_async_dns(void)
+{
+ int fd1[2], fd2[2];
+
+ CatchChild();
+
+ if (pipe(fd1) || pipe(fd2)) {
+ DEBUG(0,("can't create asyncdns pipes\n"));
+ return;
+ }
+
+ child_pid = sys_fork();
+
+ if (child_pid) {
+ fd_in = fd1[0];
+ fd_out = fd2[1];
+ close(fd1[1]);
+ close(fd2[0]);
+ DEBUG(0,("started asyncdns process %d\n", (int)child_pid));
+ return;
+ }
+
+ fd_in = fd2[0];
+ fd_out = fd1[1];
+
+ CatchSignal(SIGUSR2, SIG_IGN);
+ CatchSignal(SIGUSR1, SIG_IGN);
+ CatchSignal(SIGHUP, SIG_IGN);
+ CatchSignal(SIGTERM, SIGNAL_CAST sig_term );
+
+ asyncdns_process();
+}
+
+
+/***************************************************************************
+check if a particular name is already being queried
+ ****************************************************************************/
+static BOOL query_current(struct query_record *r)
+{
+ return dns_current &&
+ nmb_name_equal(&r->name,
+ &dns_current->packet.nmb.question.question_name);
+}
+
+
+/***************************************************************************
+ write a query to the child process
+ ****************************************************************************/
+static BOOL write_child(struct packet_struct *p)
+{
+ struct query_record r;
+
+ r.name = p->packet.nmb.question.question_name;
+
+ return write_data(fd_out, (char *)&r, sizeof(r)) == sizeof(r);
+}
+
+/***************************************************************************
+ check the DNS queue
+ ****************************************************************************/
+void run_dns_queue(void)
+{
+ struct query_record r;
+ struct packet_struct *p, *p2;
+ struct name_record *namerec;
+ int size;
+
+ if (fd_in == -1)
+ return;
+
+ /* Allow SIGTERM to kill us. */
+ BlockSignals(False, SIGTERM);
+
+ if (!process_exists(child_pid)) {
+ close(fd_in);
+ start_async_dns();
+ }
+
+ if ((size=read_data(fd_in, (char *)&r, sizeof(r))) != sizeof(r)) {
+ if (size) {
+ DEBUG(0,("Incomplete DNS answer from child!\n"));
+ fd_in = -1;
+ }
+ BlockSignals(True, SIGTERM);
+ return;
+ }
+
+ BlockSignals(True, SIGTERM);
+
+ namerec = add_dns_result(&r.name, r.result);
+
+ if (dns_current) {
+ if (query_current(&r)) {
+ DEBUG(3,("DNS calling send_wins_name_query_response\n"));
+ in_dns = 1;
+ if(namerec == NULL)
+ send_wins_name_query_response(NAM_ERR, dns_current, NULL);
+ else
+ send_wins_name_query_response(0,dns_current,namerec);
+ in_dns = 0;
+ }
+
+ dns_current->locked = False;
+ free_packet(dns_current);
+ dns_current = NULL;
+ }
+
+ /* loop over the whole dns queue looking for entries that
+ match the result we just got */
+ for (p = dns_queue; p;) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ if (nmb_name_equal(question, &r.name)) {
+ DEBUG(3,("DNS calling send_wins_name_query_response\n"));
+ in_dns = 1;
+ if(namerec == NULL)
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+ else
+ send_wins_name_query_response(0,p,namerec);
+ in_dns = 0;
+ p->locked = False;
+
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ dns_queue = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ p2 = p->next;
+ free_packet(p);
+ p = p2;
+ } else {
+ p = p->next;
+ }
+ }
+
+ if (dns_queue) {
+ dns_current = dns_queue;
+ dns_queue = dns_queue->next;
+ if (dns_queue) dns_queue->prev = NULL;
+ dns_current->next = NULL;
+
+ if (!write_child(dns_current)) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return;
+ }
+ }
+
+}
+
+/***************************************************************************
+queue a DNS query
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ if (in_dns || fd_in == -1)
+ return False;
+
+ if (!dns_current) {
+ if (!write_child(p)) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return False;
+ }
+ dns_current = p;
+ p->locked = True;
+ } else {
+ p->locked = True;
+ p->next = dns_queue;
+ p->prev = NULL;
+ if (p->next)
+ p->next->prev = p;
+ dns_queue = p;
+ }
+
+ DEBUG(3,("added DNS query for %s\n", nmb_namestr(question)));
+ return True;
+}
+
+#else
+
+
+/***************************************************************************
+ we use this when we can't do async DNS lookups
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ char *qname = question->name;
+ struct in_addr dns_ip;
+
+ DEBUG(3,("DNS search for %s - ", nmb_namestr(question)));
+
+ /* Unblock TERM signal so we can be killed in DNS lookup. */
+ BlockSignals(False, SIGTERM);
+
+ dns_ip.s_addr = interpret_addr(qname);
+
+ /* Re-block TERM signal. */
+ BlockSignals(True, SIGTERM);
+
+ *n = add_dns_result(question, dns_ip);
+ if(*n == NULL)
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+ else
+ send_wins_name_query_response(0, p, *n);
+ return False;
+}
+
+/***************************************************************************
+ With sync dns there is no child to kill on SIGTERM.
+ ****************************************************************************/
+void kill_async_dns_child(void)
+{
+ return;
+}
+#endif
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
new file mode 100644
index 00000000000..80d712036da
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,869 @@
+/*
+ Unix SMB/Netbios implementation.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+int global_nmb_port = -1;
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+
+extern BOOL global_in_nmbd;
+
+/* are we running as a daemon ? */
+static BOOL is_daemon = False;
+
+/* have we found LanMan clients yet? */
+BOOL found_lm_clients = False;
+
+/* what server type are we currently */
+
+time_t StartupTime = 0;
+
+/**************************************************************************** **
+ catch a sigterm
+ **************************************************************************** */
+static void sig_term(int sig)
+{
+ BlockSignals(True,SIGTERM);
+
+ DEBUG(0,("Got SIGTERM: going down...\n"));
+
+ /* Write out wins.dat file if samba is a WINS server */
+ wins_write_database(False);
+
+ /* Remove all SELF registered names. */
+ release_my_names();
+
+ /* Announce all server entries as 0 time-to-live, 0 type. */
+ announce_my_servers_removed();
+
+ /* If there was an async dns child - kill it. */
+ kill_async_dns_child();
+
+ exit(0);
+
+} /* sig_term */
+
+/**************************************************************************** **
+ catch a sighup
+ **************************************************************************** */
+static VOLATILE sig_atomic_t reload_after_sighup = False;
+
+static void sig_hup(int sig)
+{
+ BlockSignals( True, SIGHUP );
+
+ DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
+
+ write_browse_list( 0, True );
+
+ dump_all_namelists();
+
+ reload_after_sighup = True;
+
+ BlockSignals(False,SIGHUP);
+
+} /* sig_hup */
+
+
+#if DUMP_CORE
+/**************************************************************************** **
+ prepare to dump a core file - carefully!
+ **************************************************************************** */
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ pstrcpy( dname, lp_logfile() );
+ if ((p=strrchr_m(dname,'/')))
+ *p=0;
+ pstrcat( dname, "/corefiles" );
+ mkdir( dname, 0700 );
+ sys_chown( dname, getuid(), getgid() );
+ chmod( dname, 0700 );
+ if ( chdir(dname) )
+ return( False );
+ umask( ~(0700) );
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit( RLIMIT_CORE, &rlp );
+ rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
+ setrlimit( RLIMIT_CORE, &rlp );
+ getrlimit( RLIMIT_CORE, &rlp );
+ DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
+ }
+#endif
+#endif
+
+
+ DEBUG(0,("Dumping core in %s\n",dname));
+ abort();
+ return( True );
+} /* dump_core */
+#endif
+
+
+/**************************************************************************** **
+ possibly continue after a fault
+ **************************************************************************** */
+static void fault_continue(void)
+{
+#if DUMP_CORE
+ dump_core();
+#endif
+} /* fault_continue */
+
+/**************************************************************************** **
+ expire old names from the namelist and server list
+ **************************************************************************** */
+static void expire_names_and_servers(time_t t)
+{
+ static time_t lastrun = 0;
+
+ if ( !lastrun )
+ lastrun = t;
+ if ( t < (lastrun + 5) )
+ return;
+ lastrun = t;
+
+ /*
+ * Expire any timed out names on all the broadcast
+ * subnets and those registered with the WINS server.
+ * (nmbd_namelistdb.c)
+ */
+ expire_names(t);
+
+ /*
+ * Go through all the broadcast subnets and for each
+ * workgroup known on that subnet remove any expired
+ * server names. If a workgroup has an empty serverlist
+ * and has itself timed out then remove the workgroup.
+ * (nmbd_workgroupdb.c)
+ */
+ expire_workgroups_and_servers(t);
+} /* expire_names_and_servers */
+
+
+/************************************************************************** **
+reload the list of network interfaces
+ ************************************************************************** */
+static BOOL reload_interfaces(time_t t)
+{
+ static time_t lastt;
+ int n;
+ struct subnet_record *subrec;
+ extern BOOL rescan_listen_set;
+ extern struct in_addr loopback_ip;
+
+ if (t && ((t - lastt) < NMBD_INTERFACES_RELOAD)) return False;
+ lastt = t;
+
+ if (!interfaces_changed()) return False;
+
+ /* the list of probed interfaces has changed, we may need to add/remove
+ some subnets */
+ load_interfaces();
+
+ /* find any interfaces that need adding */
+ for (n=iface_count() - 1; n >= 0; n--) {
+ struct interface *iface = get_interface(n);
+
+ /*
+ * We don't want to add a loopback interface, in case
+ * someone has added 127.0.0.1 for smbd, nmbd needs to
+ * ignore it here. JRA.
+ */
+
+ if (ip_equal(iface->ip, loopback_ip)) {
+ DEBUG(2,("reload_interfaces: Ignoring loopback interface %s\n", inet_ntoa(iface->ip)));
+ continue;
+ }
+
+ for (subrec=subnetlist; subrec; subrec=subrec->next) {
+ if (ip_equal(iface->ip, subrec->myip) &&
+ ip_equal(iface->nmask, subrec->mask_ip)) break;
+ }
+
+ if (!subrec) {
+ /* it wasn't found! add it */
+ DEBUG(2,("Found new interface %s\n",
+ inet_ntoa(iface->ip)));
+ subrec = make_normal_subnet(iface);
+ if (subrec) register_my_workgroup_one_subnet(subrec);
+ }
+ }
+
+ /* find any interfaces that need deleting */
+ for (subrec=subnetlist; subrec; subrec=subrec->next) {
+ for (n=iface_count() - 1; n >= 0; n--) {
+ struct interface *iface = get_interface(n);
+ if (ip_equal(iface->ip, subrec->myip) &&
+ ip_equal(iface->nmask, subrec->mask_ip)) break;
+ }
+ if (n == -1) {
+ /* oops, an interface has disapeared. This is
+ tricky, we don't dare actually free the
+ interface as it could be being used, so
+ instead we just wear the memory leak and
+ remove it from the list of interfaces without
+ freeing it */
+ DEBUG(2,("Deleting dead interface %s\n",
+ inet_ntoa(subrec->myip)));
+ close_subnet(subrec);
+ }
+ }
+
+ rescan_listen_set = True;
+
+ /* We need to shutdown if there are no subnets... */
+ if (FIRST_SUBNET == NULL) {
+ DEBUG(0,("reload_interfaces: No subnets to listen to. Shutting down...\n"));
+ return True;
+ }
+ return False;
+}
+
+
+
+/**************************************************************************** **
+ reload the services file
+ **************************************************************************** */
+static BOOL reload_nmbd_services(BOOL test)
+{
+ BOOL ret;
+ extern fstring remote_machine;
+
+ fstrcpy( remote_machine, "nmbd" );
+
+ if ( lp_loaded() )
+ {
+ pstring fname;
+ pstrcpy( fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE))
+ {
+ pstrcpy(dyn_CONFIGFILE,fname);
+ test = False;
+ }
+ }
+
+ if ( test && !lp_file_list_changed() )
+ return(True);
+
+ ret = lp_load( dyn_CONFIGFILE, True , False, False);
+
+ /* perhaps the config filename is now set */
+ if ( !test )
+ {
+ DEBUG( 3, ( "services not loaded\n" ) );
+ reload_nmbd_services( True );
+ }
+
+ /* Do a sanity check for a misconfigured nmbd */
+ if( lp_wins_support() && wins_srv_count() )
+ {
+ if( DEBUGLVL(0) )
+ {
+ dbgtext( "ERROR: 'wins support = true' and 'wins server = <server>'\n" );
+ dbgtext( "are conflicting settings. nmbd aborting.\n" );
+ }
+ exit(10);
+ }
+
+ return(ret);
+} /* reload_nmbd_services */
+
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
+static void process(void)
+{
+ BOOL run_election;
+
+ while( True )
+ {
+ time_t t = time(NULL);
+
+ /* check for internal messages */
+ message_dispatch();
+
+ /*
+ * Check all broadcast subnets to see if
+ * we need to run an election on any of them.
+ * (nmbd_elections.c)
+ */
+ run_election = check_elections();
+
+ /*
+ * Read incoming UDP packets.
+ * (nmbd_packets.c)
+ */
+ if(listen_for_packets(run_election))
+ return;
+
+ /*
+ * Process all incoming packets
+ * read above. This calls the success and
+ * failure functions registered when response
+ * packets arrrive, and also deals with request
+ * packets from other sources.
+ * (nmbd_packets.c)
+ */
+ run_packet_queue();
+
+ /*
+ * Run any elections - initiate becoming
+ * a local master browser if we have won.
+ * (nmbd_elections.c)
+ */
+ run_elections(t);
+
+ /*
+ * Send out any broadcast announcements
+ * of our server names. This also announces
+ * the workgroup name if we are a local
+ * master browser.
+ * (nmbd_sendannounce.c)
+ */
+ announce_my_server_names(t);
+
+ /*
+ * Send out any LanMan broadcast announcements
+ * of our server names.
+ * (nmbd_sendannounce.c)
+ */
+ announce_my_lm_server_names(t);
+
+ /*
+ * If we are a local master browser, periodically
+ * announce ourselves to the domain master browser.
+ * This also deals with syncronising the domain master
+ * browser server lists with ourselves as a local
+ * master browser.
+ * (nmbd_sendannounce.c)
+ */
+ announce_myself_to_domain_master_browser(t);
+
+ /*
+ * Fullfill any remote announce requests.
+ * (nmbd_sendannounce.c)
+ */
+ announce_remote(t);
+
+ /*
+ * Fullfill any remote browse sync announce requests.
+ * (nmbd_sendannounce.c)
+ */
+ browse_sync_remote(t);
+
+ /*
+ * Scan the broadcast subnets, and WINS client
+ * namelists and refresh any that need refreshing.
+ * (nmbd_mynames.c)
+ */
+ refresh_my_names(t);
+
+ /*
+ * Scan the subnet namelists and server lists and
+ * expire thos that have timed out.
+ * (nmbd.c)
+ */
+ expire_names_and_servers(t);
+
+ /*
+ * Write out a snapshot of our current browse list into
+ * the browse.dat file. This is used by smbd to service
+ * incoming NetServerEnum calls - used to synchronise
+ * browse lists over subnets.
+ * (nmbd_serverlistdb.c)
+ */
+ write_browse_list(t, False);
+
+ /*
+ * If we are a domain master browser, we have a list of
+ * local master browsers we should synchronise browse
+ * lists with (these are added by an incoming local
+ * master browser announcement packet). Expire any of
+ * these that are no longer current, and pull the server
+ * lists from each of these known local master browsers.
+ * (nmbd_browsesync.c)
+ */
+ dmb_expire_and_sync_browser_lists(t);
+
+ /*
+ * Check that there is a local master browser for our
+ * workgroup for all our broadcast subnets. If one
+ * is not found, start an election (which we ourselves
+ * may or may not participate in, depending on the
+ * setting of the 'local master' parameter.
+ * (nmbd_elections.c)
+ */
+ check_master_browser_exists(t);
+
+ /*
+ * If we are configured as a logon server, attempt to
+ * register the special NetBIOS names to become such
+ * (WORKGROUP<1c> name) on all broadcast subnets and
+ * with the WINS server (if used). If we are configured
+ * to become a domain master browser, attempt to register
+ * the special NetBIOS name (WORKGROUP<1b> name) to
+ * become such.
+ * (nmbd_become_dmb.c)
+ */
+ add_domain_names(t);
+
+ /*
+ * If we are a WINS server, do any timer dependent
+ * processing required.
+ * (nmbd_winsserver.c)
+ */
+ initiate_wins_processing(t);
+
+ /*
+ * If we are a domain master browser, attempt to contact the
+ * WINS server to get a list of all known WORKGROUPS/DOMAINS.
+ * This will only work to a Samba WINS server.
+ * (nmbd_browsesync.c)
+ */
+ if (lp_enhanced_browsing()) {
+ collect_all_workgroup_names_from_wins_server(t);
+ }
+
+ /*
+ * Go through the response record queue and time out or re-transmit
+ * and expired entries.
+ * (nmbd_packets.c)
+ */
+ retransmit_or_expire_response_records(t);
+
+ /*
+ * check to see if any remote browse sync child processes have completed
+ */
+ sync_check_completion();
+
+ /*
+ * regularly sync with any other DMBs we know about
+ */
+ if (lp_enhanced_browsing()) {
+ sync_all_dmbs(t);
+ }
+
+ /*
+ * clear the unexpected packet queue
+ */
+ clear_unexpected(t);
+
+ /*
+ * Reload the services file if we got a sighup.
+ */
+
+ if(reload_after_sighup) {
+ reload_nmbd_services( True );
+ reopen_logs();
+ if(reload_interfaces(0))
+ return;
+ reload_after_sighup = False;
+ }
+
+ /* check for new network interfaces */
+ if(reload_interfaces(t))
+ return;
+
+ /* free up temp memory */
+ lp_talloc_free();
+ }
+} /* process */
+
+
+/**************************************************************************** **
+ open the socket communication
+ **************************************************************************** */
+static BOOL open_sockets(BOOL isdaemon, int port)
+{
+ /* The sockets opened here will be used to receive broadcast
+ packets *only*. Interface specific sockets are opened in
+ make_subnet() in namedbsubnet.c. Thus we bind to the
+ address "0.0.0.0". The parameter 'socket address' is
+ now deprecated.
+ */
+
+ if ( isdaemon )
+ ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True);
+ else
+ ClientNMB = 0;
+
+ ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True);
+
+ if ( ClientNMB == -1 )
+ return( False );
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+ set_socket_options( ClientNMB, "SO_BROADCAST" );
+ set_socket_options( ClientDGRAM, "SO_BROADCAST" );
+
+ DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
+ return( True );
+} /* open_sockets */
+
+
+/**************************************************************************** **
+ initialise connect, service and file structs
+ **************************************************************************** */
+static BOOL init_structs(void)
+{
+ extern fstring local_machine;
+ char *p, **ptr;
+ int namecount;
+ int n;
+ int nodup;
+ char *nbname;
+
+ if (! *global_myname)
+ {
+ fstrcpy( global_myname, myhostname() );
+ p = strchr_m( global_myname, '.' );
+ if (p)
+ *p = 0;
+ }
+ strupper( global_myname );
+
+ /* Add any NETBIOS name aliases. Ensure that the first entry
+ is equal to global_myname.
+ */
+ /* Work out the max number of netbios aliases that we have */
+ ptr = lp_netbios_aliases();
+ namecount = 0;
+ if (ptr)
+ for( ; *ptr; namecount++,ptr++ )
+ ;
+ if ( *global_myname )
+ namecount++;
+
+ /* Allocate space for the netbios aliases */
+ my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
+ if( NULL == my_netbios_names )
+ {
+ DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
+ return( False );
+ }
+
+ /* Use the global_myname string first */
+ namecount=0;
+ if ( *global_myname )
+ my_netbios_names[namecount++] = global_myname;
+
+ ptr = lp_netbios_aliases();
+ if (ptr)
+ {
+ while ( *ptr )
+ {
+ nbname = strdup(*ptr);
+ if (nbname == NULL)
+ {
+ DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
+ return False;
+ }
+ strupper( nbname );
+ /* Look for duplicates */
+ nodup=1;
+ for( n=0; n<namecount; n++ )
+ {
+ if( 0 == strcmp( nbname, my_netbios_names[n] ) )
+ nodup=0;
+ }
+ if (nodup)
+ my_netbios_names[namecount++] = nbname;
+ else
+ SAFE_FREE(nbname);
+
+ ptr++;
+ }
+ }
+
+ /* Terminate name list */
+ my_netbios_names[namecount++] = NULL;
+
+ fstrcpy( local_machine, global_myname );
+ trim_string( local_machine, " ", " " );
+ p = strchr_m( local_machine, ' ' );
+ if (p)
+ *p = 0;
+ strlower( local_machine );
+
+ DEBUG( 5, ("Netbios name list:-\n") );
+ for( n=0; my_netbios_names[n]; n++ )
+ DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
+
+ return( True );
+} /* init_structs */
+
+/**************************************************************************** **
+ usage on the program
+ **************************************************************************** */
+static void usage(char *pname)
+{
+
+ printf( "Usage: %s [-DaohV] [-H lmhosts file] [-d debuglevel] [-l log basename]\n", pname );
+ printf( " [-n name] [-p port] [-s configuration file]\n" );
+ printf( "\t-D Become a daemon\n" );
+ printf( "\t-a Append to log file (default)\n" );
+ printf( "\t-o Overwrite log file, don't append\n" );
+ printf( "\t-h Print usage\n" );
+ printf( "\t-V Print version\n" );
+ printf( "\t-H hosts file Load a netbios hosts file\n" );
+ printf( "\t-d debuglevel Set the debuglevel\n" );
+ printf( "\t-l log basename. Basename for log/debug files\n" );
+ printf( "\t-n netbiosname. Primary netbios name\n" );
+ printf( "\t-p port Listen on the specified port\n" );
+ printf( "\t-s configuration file Configuration file name\n" );
+ printf( "\n");
+} /* usage */
+
+
+/**************************************************************************** **
+ main program
+ **************************************************************************** */
+ int main(int argc,char *argv[])
+{
+ int opt;
+ extern char *optarg;
+ extern BOOL append_log;
+ BOOL opt_interactive = False;
+ pstring logfile;
+
+ append_log = True; /* Default, override with '-o' option. */
+
+ global_nmb_port = NMB_PORT;
+ global_in_nmbd = True;
+
+ StartupTime = time(NULL);
+
+ sys_srandom(time(NULL) ^ sys_getpid());
+
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-'))
+ {
+ argv++;
+ argc--;
+ }
+
+ fault_setup((void (*)(void *))fault_continue );
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't recieve them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGTERM);
+
+ CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
+ CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+ /* We no longer use USR2... */
+#if defined(SIGUSR2)
+ BlockSignals(True, SIGUSR2);
+#endif
+
+ while( EOF !=
+ (opt = getopt( argc, argv, "Vaos:T:I:C:bAB:N:Rn:l:d:Dp:hSH:G:f:i" )) )
+ {
+ switch (opt)
+ {
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ case 'N':
+ case 'B':
+ case 'I':
+ case 'C':
+ case 'G':
+ DEBUG(0,("Obsolete option '%c' used\n",opt));
+ break;
+ case 'i':
+ opt_interactive = True;
+ break;
+ case 'H':
+ pstrcpy(dyn_LMHOSTSFILE, optarg);
+ break;
+ case 'n':
+ pstrcpy(global_myname,optarg);
+ strupper(global_myname);
+ break;
+ case 'l':
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", optarg);
+ lp_set_logfile(logfile);
+ break;
+ case 'a':
+ append_log = True;
+ break;
+ case 'o':
+ append_log = False;
+ break;
+ case 'D':
+ is_daemon = True;
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'p':
+ global_nmb_port = atoi(optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'V':
+ printf( "Version %s\n", VERSION );
+ exit(0);
+ break;
+ default:
+ if( !is_a_socket(0) )
+ {
+ DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
+ usage(argv[0]);
+ exit(0);
+ }
+ break;
+ }
+ }
+
+ setup_logging( argv[0], opt_interactive );
+
+ reopen_logs();
+
+ DEBUG( 1, ( "Netbios nameserver version %s started.\n", VERSION ) );
+ DEBUGADD( 1, ( "Copyright Andrew Tridgell 1994-1998\n" ) );
+
+ if ( !reload_nmbd_services(False) )
+ return(-1);
+
+ if(!init_structs())
+ return -1;
+
+ reload_nmbd_services( True );
+
+ fstrcpy( global_myworkgroup, lp_workgroup() );
+
+ if (strequal(global_myworkgroup,"*"))
+ {
+ DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+ exit(1);
+ }
+
+ set_samba_nb_type();
+
+ if (!is_daemon && !is_a_socket(0))
+ {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon && !opt_interactive)
+ {
+ DEBUG( 2, ( "Becoming a daemon.\n" ) );
+ become_daemon();
+ }
+
+#ifndef SYNC_DNS
+ /* Setup the async dns. We do it here so it doesn't have all the other
+ stuff initialised and thus chewing memory and sockets */
+ if(lp_we_are_a_wins_server()) {
+ start_async_dns();
+ }
+#endif
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ pidfile_create("nmbd");
+ message_init();
+ message_register(MSG_FORCE_ELECTION, nmbd_message_election);
+
+ DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
+
+ if ( !open_sockets( is_daemon, global_nmb_port ) )
+ return 1;
+
+ /* Determine all the IP addresses we have. */
+ load_interfaces();
+
+ /* Create an nmbd subnet record for each of the above. */
+ if( False == create_subnets() )
+ {
+ DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
+ exit(1);
+ }
+
+ /* Load in any static local names. */
+ load_lmhosts_file(dyn_LMHOSTSFILE);
+ DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
+
+ /* If we are acting as a WINS server, initialise data structures. */
+ if( !initialise_wins() )
+ {
+ DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
+ exit(1);
+ }
+
+ /*
+ * Register nmbd primary workgroup and nmbd names on all
+ * the broadcast subnets, and on the WINS server (if specified).
+ * Also initiate the startup of our primary workgroup (start
+ * elections if we are setup as being able to be a local
+ * master browser.
+ */
+
+ if( False == register_my_workgroup_and_names() )
+ {
+ DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
+ exit(1);
+ }
+
+ /* We can only take signals in the select. */
+ BlockSignals( True, SIGTERM );
+
+ process();
+
+ if (dbf)
+ x_fclose(dbf);
+ return(0);
+} /* main */
diff --git a/source/nmbd/nmbd_become_dmb.c b/source/nmbd/nmbd_become_dmb.c
new file mode 100644
index 00000000000..d62607a643a
--- /dev/null
+++ b/source/nmbd/nmbd_become_dmb.c
@@ -0,0 +1,400 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr allones_ip;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+static void become_domain_master_browser_bcast(char *);
+
+/****************************************************************************
+ Fail to become a Domain Master Browser on a subnet.
+ ****************************************************************************/
+
+static void become_domain_master_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
+ struct server_record *servrec;
+
+ if(!work)
+ {
+ DEBUG(0,("become_domain_master_fail: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+ return;
+ }
+
+ /* Set the state back to DOMAIN_NONE. */
+ work->dom_state = DOMAIN_NONE;
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, work->work_group, subrec->subnet_name));
+ return;
+ }
+
+ /* Update our server status. */
+ servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+}
+
+/****************************************************************************
+ Become a Domain Master Browser on a subnet.
+ ****************************************************************************/
+
+static void become_domain_master_stage2(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+ struct server_record *servrec;
+
+ if(!work)
+ {
+ DEBUG(0,("become_domain_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, registered_name->name, subrec->subnet_name));
+ work->dom_state = DOMAIN_NONE;
+ return;
+ }
+
+ /* Set the state in the workgroup structure. */
+ work->dom_state = DOMAIN_MST; /* Become domain master. */
+
+ /* Update our server status. */
+ servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "*****\n\nSamba server %s ", global_myname );
+ dbgtext( "is now a domain master browser for " );
+ dbgtext( "workgroup %s ", work->work_group );
+ dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
+ }
+
+ if( subrec == unicast_subnet )
+ {
+ struct nmb_name nmbname;
+ struct in_addr my_first_ip;
+
+ /* Put our name and first IP address into the
+ workgroup struct as domain master browser. This
+ will stop us syncing with ourself if we are also
+ a local master browser. */
+
+ make_nmb_name(&nmbname, global_myname, 0x20);
+
+ work->dmb_name = nmbname;
+ /* Pick the first interface ip address as the domain master browser ip. */
+ my_first_ip = *iface_n_ip(0);
+
+ putip((char *)&work->dmb_addr, &my_first_ip);
+
+ /* We successfully registered by unicast with the
+ WINS server. We now expect to become the domain
+ master on the local subnets. If this fails, it's
+ probably a 1.9.16p2 to 1.9.16p11 server's fault.
+
+ This is a configuration issue that should be addressed
+ by the network administrator - you shouldn't have
+ several machines configured as a domain master browser
+ for the same WINS scope (except if they are 1.9.17 or
+ greater, and you know what you're doing.
+
+ see docs/DOMAIN.txt.
+
+ */
+ become_domain_master_browser_bcast(work->work_group);
+ }
+ else
+ {
+ /*
+ * Now we are a domain master on a broadcast subnet, we need to add
+ * the WORKGROUP<1b> name to the unicast subnet so that we can answer
+ * unicast requests sent to this name. This bug wasn't found for a while
+ * as it is strange to have a DMB without using WINS. JRA.
+ */
+ insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
+ }
+}
+
+/****************************************************************************
+ Start the name registration process when becoming a Domain Master Browser
+ on a subnet.
+ ****************************************************************************/
+
+static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name)
+{
+ struct work_record *work;
+
+ DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
+workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
+
+ /* First, find the workgroup on the subnet. */
+ if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL)
+ {
+ DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
+ wg_name, subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
+ work->dom_state = DOMAIN_WAIT;
+
+ /* WORKGROUP<1b> is the domain master browser name. */
+ register_name(subrec, work->work_group,0x1b,samba_nb_type,
+ become_domain_master_stage2,
+ become_domain_master_fail, NULL);
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name succeeds.
+ This is normally a fail condition as it means there is already
+ a domain master browser for a workgroup and we were trying to
+ become one.
+****************************************************************************/
+
+static void become_domain_master_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, struct in_addr ip,
+ struct res_rec *rrec)
+{
+ /* If the given ip is not ours, then we can't become a domain
+ controler as the name is already registered.
+ */
+
+ /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
+ address or zero ip for this query. Pretend this is ok. */
+
+ if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip))
+ {
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "become_domain_master_query_success():\n" );
+ dbgtext( "Our address (%s) ", inet_ntoa(ip) );
+ dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
+ dbgtext( "(domain master browser name) " );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ dbgtext( "Continuing with domain master code.\n" );
+ }
+
+ become_domain_master_stage1(subrec, nmbname->name);
+ }
+ else
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "become_domain_master_query_success:\n" );
+ dbgtext( "There is already a domain master browser at " );
+ dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), nmbname->name );
+ dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
+ }
+ }
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name fails.
+ This is normally a success condition as it then allows us to register
+ our own Domain Master Browser name.
+ ****************************************************************************/
+
+static void become_domain_master_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
+ then this is a failure. Otherwise, not finding the name is what we want. */
+ if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
+ {
+ DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
+querying WINS server for name %s.\n",
+ fail_code, nmb_namestr(question_name)));
+ return;
+ }
+
+ /* Otherwise - not having the name allows us to register it. */
+ become_domain_master_stage1(subrec, question_name->name);
+}
+
+/****************************************************************************
+ Attempt to become a domain master browser on all broadcast subnets.
+ ****************************************************************************/
+
+static void become_domain_master_browser_bcast(char *workgroup_name)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+ if (work && (work->dom_state == DOMAIN_NONE))
+ {
+ struct nmb_name nmbname;
+ make_nmb_name(&nmbname,workgroup_name,0x1b);
+
+ /*
+ * Check for our name on the given broadcast subnet first, only initiate
+ * further processing if we cannot find it.
+ */
+
+ if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "become_domain_master_browser_bcast:\n" );
+ dbgtext( "Attempting to become domain master browser on " );
+ dbgtext( "workgroup %s on subnet %s\n",
+ workgroup_name, subrec->subnet_name );
+ }
+
+ /* Send out a query to establish whether there's a
+ domain controller on the local subnet. If not,
+ we can become a domain controller.
+ */
+
+ DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
+for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
+
+ query_name(subrec, nmbname.name, nmbname.name_type,
+ become_domain_master_query_success,
+ become_domain_master_query_fail,
+ NULL);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ Attempt to become a domain master browser by registering with WINS.
+ ****************************************************************************/
+
+static void become_domain_master_browser_wins(char *workgroup_name)
+{
+ struct work_record *work;
+
+ work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
+
+ if (work && (work->dom_state == DOMAIN_NONE))
+ {
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname,workgroup_name,0x1b);
+
+ /*
+ * Check for our name on the unicast subnet first, only initiate
+ * further processing if we cannot find it.
+ */
+
+ if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "become_domain_master_browser_wins:\n" );
+ dbgtext( "Attempting to become domain master browser " );
+ dbgtext( "on workgroup %s, subnet %s.\n",
+ workgroup_name, unicast_subnet->subnet_name );
+ }
+
+ /* Send out a query to establish whether there's a
+ domain master broswer registered with WINS. If not,
+ we can become a domain master browser.
+ */
+
+ DEBUG(0,("become_domain_master_browser_wins: querying WINS server at IP %s \
+for domain master browser name %s on workgroup %s\n",
+ inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
+
+ query_name(unicast_subnet, nmbname.name, nmbname.name_type,
+ become_domain_master_query_success,
+ become_domain_master_query_fail,
+ NULL);
+ }
+ }
+}
+
+/****************************************************************************
+ Add the domain logon server and domain master browser names
+ if we are set up to do so.
+ **************************************************************************/
+
+void add_domain_names(time_t t)
+{
+ static time_t lastrun = 0;
+
+ if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
+ return;
+
+ lastrun = t;
+
+ /* Do the "internet group" - <1c> names. */
+ if (lp_domain_logons())
+ add_logon_names();
+
+ /* Do the domain master names. */
+ if(lp_server_role() == ROLE_DOMAIN_PDC)
+ {
+ if(we_are_a_wins_client())
+ {
+ /* We register the WORKGROUP<1b> name with the WINS
+ server first, and call add_domain_master_bcast()
+ only if this is successful.
+
+ This results in domain logon services being gracefully provided,
+ as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
+ 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
+ cannot provide domain master / domain logon services.
+ */
+ become_domain_master_browser_wins(global_myworkgroup);
+ }
+ else
+ become_domain_master_browser_bcast(global_myworkgroup);
+ }
+}
diff --git a/source/nmbd/nmbd_become_lmb.c b/source/nmbd/nmbd_become_lmb.c
new file mode 100644
index 00000000000..52955d9bfc0
--- /dev/null
+++ b/source/nmbd/nmbd_become_lmb.c
@@ -0,0 +1,608 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
+
+/*******************************************************************
+ Utility function to add a name to the unicast subnet, or add in
+ our IP address if it already exists.
+******************************************************************/
+
+void insert_permanent_name_into_unicast( struct subnet_record *subrec,
+ struct nmb_name *nmbname, uint16 nb_type )
+{
+ struct name_record *namerec;
+
+ if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
+ {
+ /* The name needs to be created on the unicast subnet. */
+ (void)add_name_to_subnet( unicast_subnet, nmbname->name,
+ nmbname->name_type, nb_type,
+ PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
+ }
+ else
+ {
+ /* The name already exists on the unicast subnet. Add our local
+ IP for the given broadcast subnet to the name. */
+ add_ip_to_name_record( namerec, subrec->myip);
+ }
+}
+
+/*******************************************************************
+ Utility function to remove a name from the unicast subnet.
+******************************************************************/
+
+static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
+ struct nmb_name *nmbname )
+{
+ struct name_record *namerec;
+
+ if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL)
+ {
+ /* Remove this broadcast subnet IP address from the name. */
+ remove_ip_from_name_record( namerec, subrec->myip);
+ if(namerec->data.num_ips == 0)
+ remove_name_from_namelist( unicast_subnet, namerec);
+ }
+}
+
+/*******************************************************************
+ Utility function always called to set our workgroup and server
+ state back to potential browser, or none.
+******************************************************************/
+
+static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name,
+ BOOL force_new_election )
+{
+ struct work_record *work;
+ struct server_record *servrec;
+ struct nmb_name nmbname;
+
+ if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
+ {
+ DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, subrec->subnet_name ));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, work->work_group, subrec->subnet_name));
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ return;
+ }
+
+ /* Update our server status - remove any master flag and replace
+ it with the potential browser flag. */
+ servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
+ servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ /* Reset our election flags. */
+ work->ElectionCriterion &= ~0x4;
+
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+
+ /* Forget who the local master browser was for
+ this workgroup. */
+
+ set_workgroup_local_master_browser_name( work, "");
+
+ /*
+ * Ensure the IP address of this subnet is not registered as one
+ * of the IP addresses of the WORKGROUP<1d> name on the unicast
+ * subnet. This undoes what we did below when we became a local
+ * master browser.
+ */
+
+ make_nmb_name(&nmbname, work->work_group, 0x1d);
+
+ remove_permanent_name_from_unicast( subrec, &nmbname);
+
+ if(force_new_election)
+ work->needelection = True;
+}
+
+/*******************************************************************
+ Unbecome the local master browser name release success function.
+******************************************************************/
+
+static void unbecome_local_master_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *released_name,
+ struct in_addr released_ip)
+{
+ BOOL force_new_election = False;
+
+ memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
+
+ DEBUG(3,("unbecome_local_master_success: released name %s.\n",
+ nmb_namestr(released_name)));
+
+ /* Now reset the workgroup and server state. */
+ reset_workgroup_state( subrec, released_name->name, force_new_election );
+
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "*****\n\n" );
+ dbgtext( "Samba name server %s ", global_myname );
+ dbgtext( "has stopped being a local master browser " );
+ dbgtext( "for workgroup %s ", released_name->name );
+ dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
+ }
+
+}
+
+/*******************************************************************
+ Unbecome the local master browser name release fail function.
+******************************************************************/
+
+static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct name_record *namerec;
+ struct userdata_struct *userdata = rrec->userdata;
+ BOOL force_new_election = False;
+
+ memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
+
+ DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
+Removing from namelist anyway.\n", nmb_namestr(fail_name)));
+
+ /* Do it anyway. */
+ namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+ if(namerec)
+ remove_name_from_namelist(subrec, namerec);
+
+ /* Now reset the workgroup and server state. */
+ reset_workgroup_state( subrec, fail_name->name, force_new_election );
+
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "*****\n\n" );
+ dbgtext( "Samba name server %s ", global_myname );
+ dbgtext( "has stopped being a local master browser " );
+ dbgtext( "for workgroup %s ", fail_name->name );
+ dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
+ }
+}
+
+/*******************************************************************
+ Utility function to remove the WORKGROUP<1d> name.
+******************************************************************/
+
+static void release_1d_name( struct subnet_record *subrec, char *workgroup_name,
+ BOOL force_new_election)
+{
+ struct nmb_name nmbname;
+ struct name_record *namerec;
+
+ make_nmb_name(&nmbname, workgroup_name, 0x1d);
+ if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
+ {
+ struct userdata_struct *userdata;
+ int size = sizeof(struct userdata_struct) + sizeof(BOOL);
+
+ if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
+ {
+ DEBUG(0,("release_1d_name: malloc fail.\n"));
+ return;
+ }
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(BOOL);
+ memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
+
+ release_name(subrec, namerec,
+ unbecome_local_master_success,
+ unbecome_local_master_fail,
+ userdata);
+
+ zero_free(userdata, size);
+ }
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release success function.
+******************************************************************/
+
+static void release_msbrowse_name_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *released_name,
+ struct in_addr released_ip)
+{
+ DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
+ nmb_namestr(released_name), subrec->subnet_name ));
+
+ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+ remove_permanent_name_from_unicast( subrec, released_name);
+}
+
+/*******************************************************************
+ Unbecome the local master browser MSBROWSE name release fail function.
+******************************************************************/
+
+static void release_msbrowse_name_fail( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct name_record *namerec;
+
+ DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
+ nmb_namestr(fail_name), subrec->subnet_name ));
+
+ /* Release the name anyway. */
+ namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
+ if(namerec)
+ remove_name_from_namelist(subrec, namerec);
+
+ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
+ remove_permanent_name_from_unicast( subrec, fail_name);
+}
+
+/*******************************************************************
+ Unbecome the local master browser. If force_new_election is true, restart
+ the election process after we've unbecome the local master.
+******************************************************************/
+
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
+ BOOL force_new_election)
+{
+ struct name_record *namerec;
+ struct nmb_name nmbname;
+
+ /* Sanity check. */
+
+ DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
+on subnet %s\n",work->work_group, subrec->subnet_name));
+
+ if(find_server_in_workgroup( work, global_myname) == NULL)
+ {
+ DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, work->work_group, subrec->subnet_name));
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ return;
+ }
+
+ /* Set the state to unbecoming. */
+ work->mst_state = MST_UNBECOMING_MASTER;
+
+ /*
+ * Release the WORKGROUP<1d> name asap to allow another machine to
+ * claim it.
+ */
+
+ release_1d_name( subrec, work->work_group, force_new_election);
+
+ /* Deregister any browser names we may have. */
+ make_nmb_name(&nmbname, MSBROWSE, 0x1);
+ if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
+ {
+ release_name(subrec, namerec,
+ release_msbrowse_name_success,
+ release_msbrowse_name_fail,
+ NULL);
+ }
+
+ /*
+ * Ensure we have sent and processed these release packets
+ * before returning - we don't want to process any election
+ * packets before dealing with the 1d release.
+ */
+
+ retransmit_or_expire_response_records(time(NULL));
+}
+
+/****************************************************************************
+ Success in registering the WORKGROUP<1d> name.
+ We are now *really* a local master browser.
+ ****************************************************************************/
+
+static void become_local_master_stage2(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ int i = 0;
+ struct server_record *sl;
+ struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+ struct server_record *servrec;
+
+ if(!work)
+ {
+ DEBUG(0,("become_local_master_stage2: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, registered_name->name, subrec->subnet_name));
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ return;
+ }
+
+ DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
+on subnet %s\n", work->work_group, subrec->subnet_name));
+
+ work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
+
+ /* update our server status */
+ servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
+ servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ /* Add this name to the workgroup as local master browser. */
+ set_workgroup_local_master_browser_name( work, global_myname);
+
+ /* Count the number of servers we have on our list. If it's
+ less than 10 (just a heuristic) request the servers
+ to announce themselves.
+ */
+ for( sl = work->serverlist; sl != NULL; sl = sl->next)
+ i++;
+
+ if (i < 10)
+ {
+ /* Ask all servers on our local net to announce to us. */
+ broadcast_announce_request(subrec, work);
+ }
+
+ /*
+ * Now we are a local master on a broadcast subnet, we need to add
+ * the WORKGROUP<1d> name to the unicast subnet so that we can answer
+ * unicast requests sent to this name. We can create this name directly on
+ * the unicast subnet as a WINS server always returns true when registering
+ * this name, and discards the registration. We use the number of IP
+ * addresses registered to this name as a reference count, as we
+ * remove this broadcast subnet IP address from it when we stop becoming a local
+ * master browser for this broadcast subnet.
+ */
+
+ insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
+
+ /* Reset the announce master browser timer so that we try and tell a domain
+ master browser as soon as possible that we are a local master browser. */
+ reset_announce_timer();
+
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "*****\n\n" );
+ dbgtext( "Samba name server %s ", global_myname );
+ dbgtext( "is now a local master browser " );
+ dbgtext( "for workgroup %s ", work->work_group );
+ dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
+ }
+
+}
+
+/****************************************************************************
+ Failed to register the WORKGROUP<1d> name.
+ ****************************************************************************/
+static void become_local_master_fail2(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
+
+ DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
+Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
+
+ if(!work)
+ {
+ DEBUG(0,("become_local_master_fail2: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+ return;
+ }
+
+ /* Roll back all the way by calling unbecome_local_master_browser(). */
+ unbecome_local_master_browser(subrec, work, False);
+}
+
+/****************************************************************************
+ Success in registering the MSBROWSE name.
+ ****************************************************************************/
+
+static void become_local_master_stage1(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ char *work_name = userdata->data;
+ struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
+
+ if(!work)
+ {
+ DEBUG(0,("become_local_master_stage1: Error - cannot find \
+workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
+ work->work_group));
+
+ work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
+
+ /*
+ * We registered the MSBROWSE name on a broadcast subnet, now need to add
+ * the MSBROWSE name to the unicast subnet so that we can answer
+ * unicast requests sent to this name. We create this name directly on
+ * the unicast subnet.
+ */
+
+ insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
+
+ /* Attempt to register the WORKGROUP<1d> name. */
+ register_name(subrec, work->work_group,0x1d,samba_nb_type,
+ become_local_master_stage2,
+ become_local_master_fail2,
+ NULL);
+}
+
+/****************************************************************************
+ Failed to register the MSBROWSE name.
+ ****************************************************************************/
+
+static void become_local_master_fail1(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ char *work_name = rrec->userdata->data;
+ struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(!work)
+ {
+ DEBUG(0,("become_local_master_fail1: Error - cannot find \
+workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
+ return;
+ }
+
+ if(find_server_in_workgroup(work, global_myname) == NULL)
+ {
+ DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, work->work_group, subrec->subnet_name));
+ return;
+ }
+
+ reset_workgroup_state( subrec, work->work_group, False );
+
+ DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+}
+
+/******************************************************************
+ Become the local master browser on a subnet.
+ This gets called if we win an election on this subnet.
+
+ Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
+ Stage 2: mst_state was MST_BACKUP - go to MST_MSB and register WORKGROUP<1d>.
+ Stage 3: mst_state was MST_MSB - go to MST_BROWSER.
+******************************************************************/
+
+void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
+{
+ struct userdata_struct *userdata;
+ int size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
+
+ /* Sanity check. */
+ if (!lp_local_master())
+ {
+ DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
+ return;
+ }
+
+ if(!AM_POTENTIAL_MASTER_BROWSER(work))
+ {
+ DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
+ work->mst_state ));
+ return;
+ }
+
+ if(find_server_in_workgroup( work, global_myname) == NULL)
+ {
+ DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, work->work_group, subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
+%s on subnet %s\n", work->work_group, subrec->subnet_name));
+
+ DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
+ work->mst_state = MST_BACKUP; /* an election win was successful */
+
+ work->ElectionCriterion |= 0x5;
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ /* Setup the userdata_struct. */
+ if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
+ {
+ DEBUG(0,("become_local_master_browser: malloc fail.\n"));
+ return;
+ }
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = strlen(work->work_group)+1;
+ pstrcpy(userdata->data, work->work_group);
+
+ /* Register the special browser group name. */
+ register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
+ become_local_master_stage1,
+ become_local_master_fail1,
+ userdata);
+
+ zero_free(userdata, size);
+}
+
+/***************************************************************
+ Utility function to set the local master browser name. Does
+ some sanity checking as old versions of Samba seem to sometimes
+ say that the master browser name for a workgroup is the same
+ as the workgroup name.
+****************************************************************/
+
+void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
+{
+ DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
+for workgroup %s.\n", newname, work->work_group ));
+
+#if 0
+ /*
+ * Apparently some sites use the workgroup name as the local
+ * master browser name. Arrrrggghhhhh ! (JRA).
+ */
+ if(strequal( work->work_group, newname))
+ {
+ DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
+local_master_browser_name for workgroup %s to workgroup name.\n",
+ work->work_group ));
+ return;
+ }
+#endif
+
+ StrnCpy(work->local_master_browser_name, newname,
+ sizeof(work->local_master_browser_name)-1);
+}
diff --git a/source/nmbd/nmbd_browserdb.c b/source/nmbd/nmbd_browserdb.c
new file mode 100644
index 00000000000..cbf871a700d
--- /dev/null
+++ b/source/nmbd/nmbd_browserdb.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+ Copyright (C) Christopher R. Hertel 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/* -------------------------------------------------------------------------- **
+ * Modified July 1998 by CRH.
+ * I converted this module to use the canned doubly-linked lists. I also
+ * added comments above the functions where possible.
+ */
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Variables...
+ *
+ * lmb_browserlist - This is our local master browser list.
+ */
+
+ubi_dlNewList( lmb_browserlist );
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+/* ************************************************************************** **
+ * Remove and free a browser list entry.
+ *
+ * Input: browc - A pointer to the entry to be removed from the list and
+ * freed.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+static void remove_lmb_browser_entry( struct browse_cache_record *browc )
+ {
+ safe_free( ubi_dlRemThis( lmb_browserlist, browc ) );
+ } /* remove_lmb_browser_entry */
+
+/* ************************************************************************** **
+ * Update a browser death time.
+ *
+ * Input: browc - Pointer to the entry to be updated.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+void update_browser_death_time( struct browse_cache_record *browc )
+ {
+ /* Allow the new lmb to miss an announce period before we remove it. */
+ browc->death_time = time(NULL) + ( (CHECK_TIME_MST_ANNOUNCE + 2) * 60 );
+ } /* update_browser_death_time */
+
+/* ************************************************************************** **
+ * Create a browser entry and add it to the local master browser list.
+ *
+ * Input: work_name
+ * browser_name
+ * ip
+ *
+ * Output: Pointer to the new entry, or NULL if malloc() failed.
+ *
+ * ************************************************************************** **
+ */
+struct browse_cache_record *create_browser_in_lmb_cache( char *work_name,
+ char *browser_name,
+ struct in_addr ip )
+ {
+ struct browse_cache_record *browc;
+ time_t now = time( NULL );
+
+ browc = (struct browse_cache_record *)malloc( sizeof( *browc ) );
+
+ if( NULL == browc )
+ {
+ DEBUG( 0, ("create_browser_in_lmb_cache: malloc fail !\n") );
+ return( NULL );
+ }
+
+ memset( (char *)browc, '\0', sizeof( *browc ) );
+
+ /* For a new lmb entry we want to sync with it after one minute. This
+ will allow it time to send out a local announce and build its
+ browse list.
+ */
+ browc->sync_time = now + 60;
+
+ /* Allow the new lmb to miss an announce period before we remove it. */
+ browc->death_time = now + ( (CHECK_TIME_MST_ANNOUNCE + 2) * 60 );
+
+ StrnCpy( browc->lmb_name, browser_name, sizeof(browc->lmb_name)-1 );
+ StrnCpy( browc->work_group, work_name, sizeof(browc->work_group)-1 );
+ strupper( browc->lmb_name );
+ strupper( browc->work_group );
+
+ browc->ip = ip;
+
+ (void)ubi_dlAddTail( lmb_browserlist, browc );
+
+ if( DEBUGLVL( 3 ) )
+ {
+ Debug1( "nmbd_browserdb:create_browser_in_lmb_cache()\n" );
+ Debug1( " Added lmb cache entry for workgroup %s ", browc->work_group );
+ Debug1( "name %s IP %s ", browc->lmb_name, inet_ntoa(ip) );
+ Debug1( "ttl %d\n", (int)browc->death_time );
+ }
+
+ return( browc );
+ } /* create_browser_in_lmb_cache */
+
+/* ************************************************************************** **
+ * Find a browser entry in the local master browser list.
+ *
+ * Input: browser_name - The name for which to search.
+ *
+ * Output: A pointer to the matching entry, or NULL if no match was found.
+ *
+ * ************************************************************************** **
+ */
+struct browse_cache_record *find_browser_in_lmb_cache( char *browser_name )
+ {
+ struct browse_cache_record *browc;
+
+ for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
+ browc;
+ browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
+ if( strequal( browser_name, browc->lmb_name ) )
+ break;
+
+ return( browc );
+ } /* find_browser_in_lmb_cache */
+
+/* ************************************************************************** **
+ * Expire timed out browsers in the browserlist.
+ *
+ * Input: t - Expiration time. Entries with death times less than this
+ * value will be removed from the list.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+void expire_lmb_browsers( time_t t )
+ {
+ struct browse_cache_record *browc;
+ struct browse_cache_record *nextbrowc;
+
+ for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
+ browc;
+ browc = nextbrowc )
+ {
+ nextbrowc = (struct browse_cache_record *)ubi_dlNext( browc );
+
+ if( browc->death_time < t )
+ {
+ if( DEBUGLVL( 3 ) )
+ {
+ Debug1( "nmbd_browserdb:expire_lmb_browsers()\n" );
+ Debug1( " Removing timed out lmb entry %s\n", browc->lmb_name );
+ }
+ remove_lmb_browser_entry( browc );
+ }
+ }
+ } /* expire_lmb_browsers */
diff --git a/source/nmbd/nmbd_browsesync.c b/source/nmbd/nmbd_browsesync.c
new file mode 100644
index 00000000000..35bd29334e0
--- /dev/null
+++ b/source/nmbd/nmbd_browsesync.c
@@ -0,0 +1,704 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/* This is our local master browser list database. */
+extern ubi_dlList lmb_browserlist[];
+
+/****************************************************************************
+As a domain master browser, do a sync with a local master browser.
+**************************************************************************/
+static void sync_with_lmb(struct browse_cache_record *browc)
+{
+ struct work_record *work;
+
+ if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "Failed to get a workgroup for a local master browser " );
+ dbgtext( "cache entry workgroup " );
+ dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
+ }
+ return;
+ }
+
+ /* We should only be doing this if we are a domain master browser for
+ the given workgroup. Ensure this is so. */
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work))
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "We are trying to sync with a local master browser " );
+ dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
+ dbgtext( "and we are not a domain master browser on this workgroup.\n" );
+ dbgtext( "Error!\n" );
+ }
+ return;
+ }
+
+ if( DEBUGLVL( 2 ) )
+ {
+ dbgtext( "sync_with_lmb:\n" );
+ dbgtext( "Initiating sync with local master browser " );
+ dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
+ dbgtext( "for workgroup %s\n", browc->work_group );
+ }
+
+ sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
+
+ browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
+}
+
+/****************************************************************************
+Sync or expire any local master browsers.
+**************************************************************************/
+void dmb_expire_and_sync_browser_lists(time_t t)
+{
+ static time_t last_run = 0;
+ struct browse_cache_record *browc;
+
+ /* Only do this every 20 seconds. */
+ if (t - last_run < 20)
+ return;
+
+ last_run = t;
+
+ expire_lmb_browsers(t);
+
+ for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
+ browc;
+ browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
+ {
+ if (browc->sync_time < t)
+ sync_with_lmb(browc);
+ }
+}
+
+/****************************************************************************
+As a local master browser, send an announce packet to the domain master browser.
+**************************************************************************/
+
+static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
+{
+ pstring outbuf;
+ char *p;
+
+ if(ismyip(work->dmb_addr))
+ {
+ if( DEBUGLVL( 2 ) )
+ {
+ dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
+ dbgtext( "We are both a domain and a local master browser for " );
+ dbgtext( "workgroup %s. ", work->work_group );
+ dbgtext( "Do not announce to ourselves.\n" );
+ }
+ return;
+ }
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_MasterAnnouncement;
+ p++;
+
+ StrnCpy(p,global_myname,15);
+ strupper(p);
+ p = skip_string(p,1);
+
+ if( DEBUGLVL( 4 ) )
+ {
+ dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
+ dbgtext( "Sending local master announce to " );
+ dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
+ work->work_group );
+ }
+
+ send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname, 0x0, work->dmb_name.name, 0x0,
+ work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
+
+}
+
+/****************************************************************************
+As a local master browser, do a sync with a domain master browser.
+**************************************************************************/
+
+static void sync_with_dmb(struct work_record *work)
+{
+ if( DEBUGLVL( 2 ) )
+ {
+ dbgtext( "sync_with_dmb:\n" );
+ dbgtext( "Initiating sync with domain master browser " );
+ dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
+ dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
+ dbgtext( "for workgroup %s\n", work->work_group );
+ }
+
+ sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
+ work->dmb_addr, False, True);
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP succeeds.
+****************************************************************************/
+
+static void domain_master_node_status_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct res_rec *answers,
+ struct in_addr from_ip)
+{
+ struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
+
+ if( work == NULL )
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Unable to find workgroup " );
+ dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
+ }
+ return;
+ }
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Success in node status for workgroup " );
+ dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
+ }
+
+ /* Go through the list of names found at answers->rdata and look for
+ the first SERVER<0x20> name. */
+
+ if(answers->rdata != NULL)
+ {
+ char *p = answers->rdata;
+ int numnames = CVAL(p, 0);
+
+ p += 1;
+
+ while (numnames--)
+ {
+ char qname[17];
+ uint16 nb_flags;
+ int name_type;
+
+ StrnCpy(qname,p,15);
+ name_type = CVAL(p,15);
+ nb_flags = get_nb_flags(&p[16]);
+ trim_string(qname,NULL," ");
+
+ p += 18;
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
+ {
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, qname, name_type);
+
+ /* Copy the dmb name and IP address
+ into the workgroup struct. */
+
+ work->dmb_name = nmbname;
+ putip((char *)&work->dmb_addr, &from_ip);
+
+ /* Do the local master browser announcement to the domain
+ master browser name and IP. */
+ announce_local_master_browser_to_domain_master_browser( work );
+
+ /* Now synchronise lists with the domain master browser. */
+ sync_with_dmb(work);
+ break;
+ }
+ }
+ }
+ else
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "domain_master_node_status_success:\n" );
+ dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
+ dbgtext( "%s.\n", inet_ntoa(from_ip) );
+ }
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP fails.
+****************************************************************************/
+
+static void domain_master_node_status_fail(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "domain_master_node_status_fail:\n" );
+ dbgtext( "Doing a node status request to the domain master browser\n" );
+ dbgtext( "for workgroup %s ", userdata->data );
+ dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
+ dbgtext( "Cannot sync browser lists.\n" );
+ }
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name succeeds.
+****************************************************************************/
+
+static void find_domain_master_name_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata_in,
+ struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
+{
+ /*
+ * Unfortunately, finding the IP address of the Domain Master Browser,
+ * as we have here, is not enough. We need to now do a sync to the
+ * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
+ * respond to the SMBSERVER name. To get this name from IP
+ * address we do a Node status request, and look for the first
+ * NAME<0x20> in the response, and take that as the server name.
+ * We also keep a cache of the Domain Master Browser name for this
+ * workgroup in the Workgroup struct, so that if the same IP addess
+ * is returned every time, we don't need to do the node status
+ * request.
+ */
+
+ struct work_record *work;
+ struct nmb_name nmbname;
+ struct userdata_struct *userdata;
+ int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
+
+ if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "find_domain_master_name_query_success:\n" );
+ dbgtext( "Failed to find workgroup %s\n", q_name->name );
+ }
+ return;
+ }
+
+ /* First check if we already have a dmb for this workgroup. */
+
+ if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip))
+ {
+ /* Do the local master browser announcement to the domain
+ master browser name and IP. */
+ announce_local_master_browser_to_domain_master_browser( work );
+
+ /* Now synchronise lists with the domain master browser. */
+ sync_with_dmb(work);
+ return;
+ }
+ else
+ zero_ip(&work->dmb_addr);
+
+ /* Now initiate the node status request. */
+ make_nmb_name(&nmbname,"*",0x0);
+
+ /* Put the workgroup name into the userdata so we know
+ what workgroup we're talking to when the reply comes
+ back. */
+
+ /* Setup the userdata_struct - this is copied so we can use
+ a stack variable for this. */
+ if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
+ {
+ DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
+ return;
+ }
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = strlen(work->work_group)+1;
+ pstrcpy(userdata->data, work->work_group);
+
+ node_status( subrec, &nmbname, answer_ip,
+ domain_master_node_status_success,
+ domain_master_node_status_fail,
+ userdata);
+
+ zero_free(userdata, size);
+}
+
+/****************************************************************************
+ Function called when a query for a WORKGROUP<1b> name fails.
+ ****************************************************************************/
+static void find_domain_master_name_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "find_domain_master_name_query_fail:\n" );
+ dbgtext( "Unable to find the Domain Master Browser name " );
+ dbgtext( "%s for the workgroup %s.\n",
+ nmb_namestr(question_name), question_name->name );
+ dbgtext( "Unable to sync browse lists in this workgroup.\n" );
+ }
+}
+
+/****************************************************************************
+As a local master browser for a workgroup find the domain master browser
+name, announce ourselves as local master browser to it and then pull the
+full domain browse lists from it onto the given subnet.
+**************************************************************************/
+
+void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
+ struct work_record *work)
+{
+ struct nmb_name nmbname;
+
+ /* Only do this if we are using a WINS server. */
+ if(we_are_a_wins_client() == False)
+ {
+ if( DEBUGLVL( 10 ) )
+ {
+ dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
+ dbgtext( "Ignoring, as we are not a WINS client.\n" );
+ }
+ return;
+ }
+
+ make_nmb_name(&nmbname,work->work_group,0x1b);
+
+ /* First, query for the WORKGROUP<1b> name from the WINS server. */
+ query_name(unicast_subnet, nmbname.name, nmbname.name_type,
+ find_domain_master_name_query_success,
+ find_domain_master_name_query_fail,
+ NULL);
+
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP succeeds.
+ This function is only called on query to a Samba 1.9.18 or above WINS server.
+
+ Note that adding the workgroup name is enough for this workgroup to be
+ browsable by clients, as clients query the WINS server or broadcast
+ nets for the WORKGROUP<1b> name when they want to browse a workgroup
+ they are not in. We do not need to do a sync with this Domain Master
+ Browser in order for our browse clients to see machines in this workgroup.
+ JRA.
+****************************************************************************/
+
+static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct res_rec *answers,
+ struct in_addr from_ip)
+{
+ struct work_record *work;
+ fstring server_name;
+
+ server_name[0] = 0;
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
+ }
+
+ /*
+ * Go through the list of names found at answers->rdata and look for
+ * the first WORKGROUP<0x1b> name.
+ */
+
+ if(answers->rdata != NULL)
+ {
+ char *p = answers->rdata;
+ int numnames = CVAL(p, 0);
+
+ p += 1;
+
+ while (numnames--)
+ {
+ char qname[17];
+ uint16 nb_flags;
+ int name_type;
+
+ StrnCpy(qname,p,15);
+ name_type = CVAL(p,15);
+ nb_flags = get_nb_flags(&p[16]);
+ trim_string(qname,NULL," ");
+
+ p += 18;
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
+ server_name[0] == 0) {
+ /* this is almost certainly the server netbios name */
+ fstrcpy(server_name, qname);
+ continue;
+ }
+
+ if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
+ {
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
+ dbgtext( "is a domain master browser for workgroup " );
+ dbgtext( "%s. Adding this name.\n", qname );
+ }
+
+ /*
+ * If we don't already know about this workgroup, add it
+ * to the workgroup list on the unicast_subnet.
+ */
+ if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
+ {
+ struct nmb_name nmbname;
+ /*
+ * Add it - with an hour in the cache.
+ */
+ if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
+ return;
+
+ /* remember who the master is */
+ fstrcpy(work->local_master_browser_name, server_name);
+ make_nmb_name(&nmbname, server_name, 0x20);
+ work->dmb_name = nmbname;
+ work->dmb_addr = from_ip;
+ }
+ break;
+ }
+ }
+ }
+ else
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "get_domain_master_name_node_status_success:\n" );
+ dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
+ dbgtext( "%s.\n", inet_ntoa(from_ip) );
+ }
+}
+
+/****************************************************************************
+ Function called when a node status query to a domain master browser IP fails.
+****************************************************************************/
+
+static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "get_domain_master_name_node_status_fail:\n" );
+ dbgtext( "Doing a node status request to the domain master browser " );
+ dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
+ dbgtext( "Cannot get workgroup name.\n" );
+ }
+}
+
+/****************************************************************************
+ Function called when a query for *<1b> name succeeds.
+****************************************************************************/
+
+static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata_in,
+ struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
+{
+ /*
+ * We now have a list of all the domain master browsers for all workgroups
+ * that have registered with the WINS server. Now do a node status request
+ * to each one and look for the first 1b name in the reply. This will be
+ * the workgroup name that we will add to the unicast subnet as a 'non-local'
+ * workgroup.
+ */
+
+ struct nmb_name nmbname;
+ struct in_addr send_ip;
+ int i;
+
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "find_all_domain_master_names_query_succes:\n" );
+ dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
+ dbgtext( "IP addresses for Domain Master Browsers.\n" );
+ }
+
+ for(i = 0; i < rrec->rdlength / 6; i++)
+ {
+ /* Initiate the node status requests. */
+ make_nmb_name(&nmbname, "*", 0);
+
+ putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
+
+ /*
+ * Don't send node status requests to ourself.
+ */
+
+ if(ismyip( send_ip ))
+ {
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "find_all_domain_master_names_query_succes:\n" );
+ dbgtext( "Not sending node status to our own IP " );
+ dbgtext( "%s.\n", inet_ntoa(send_ip) );
+ }
+ continue;
+ }
+
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "find_all_domain_master_names_query_success:\n" );
+ dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
+ }
+
+ node_status( subrec, &nmbname, send_ip,
+ get_domain_master_name_node_status_success,
+ get_domain_master_name_node_status_fail,
+ NULL);
+ }
+}
+
+/****************************************************************************
+ Function called when a query for *<1b> name fails.
+ ****************************************************************************/
+static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ if( DEBUGLVL( 10 ) )
+ {
+ dbgtext( "find_domain_master_name_query_fail:\n" );
+ dbgtext( "WINS server did not reply to a query for name " );
+ dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
+ dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
+ }
+}
+
+/****************************************************************************
+ If we are a domain master browser on the unicast subnet, do a query to the
+ WINS server for the *<1b> name. This will only work to a Samba WINS server,
+ so ignore it if we fail. If we succeed, contact each of the IP addresses in
+ turn and do a node status request to them. If this succeeds then look for a
+ <1b> name in the reply - this is the workgroup name. Add this to the unicast
+ subnet. This is expensive, so we only do this every 15 minutes.
+**************************************************************************/
+void collect_all_workgroup_names_from_wins_server(time_t t)
+{
+ static time_t lastrun = 0;
+ struct work_record *work;
+ struct nmb_name nmbname;
+
+ /* Only do this if we are using a WINS server. */
+ if(we_are_a_wins_client() == False)
+ return;
+
+ /* Check to see if we are a domain master browser on the unicast subnet. */
+ if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
+ dbgtext( "Cannot find my workgroup %s ", global_myworkgroup );
+ dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
+ }
+ return;
+ }
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work))
+ return;
+
+ if ((lastrun != 0) && (t < lastrun + (15 * 60)))
+ return;
+
+ lastrun = t;
+
+ make_nmb_name(&nmbname,"*",0x1b);
+
+ /* First, query for the *<1b> name from the WINS server. */
+ query_name(unicast_subnet, nmbname.name, nmbname.name_type,
+ find_all_domain_master_names_query_success,
+ find_all_domain_master_names_query_fail,
+ NULL);
+}
+
+
+/****************************************************************************
+ If we are a domain master browser on the unicast subnet, do a regular sync
+ with all other DMBs that we know of on that subnet.
+
+To prevent exponential network traffic with large numbers of workgroups
+we use a randomised system where sync probability is inversely proportional
+to the number of known workgroups
+**************************************************************************/
+void sync_all_dmbs(time_t t)
+{
+ static time_t lastrun = 0;
+ struct work_record *work;
+ int count=0;
+
+ /* Only do this if we are using a WINS server. */
+ if(we_are_a_wins_client() == False)
+ return;
+
+ /* Check to see if we are a domain master browser on the
+ unicast subnet. */
+ work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
+ if (!work) return;
+
+ if (!AM_DOMAIN_MASTER_BROWSER(work))
+ return;
+
+ if ((lastrun != 0) && (t < lastrun + (5 * 60)))
+ return;
+
+ /* count how many syncs we might need to do */
+ for (work=unicast_subnet->workgrouplist; work; work = work->next) {
+ if (strcmp(global_myworkgroup, work->work_group)) {
+ count++;
+ }
+ }
+
+ /* sync with a probability of 1/count */
+ for (work=unicast_subnet->workgrouplist; work; work = work->next) {
+ if (strcmp(global_myworkgroup, work->work_group)) {
+ if (((unsigned)sys_random()) % count != 0) continue;
+
+ lastrun = t;
+
+ if (!work->dmb_name.name[0]) {
+ /* we don't know the DMB - assume it is
+ the same as the unicast local master */
+ make_nmb_name(&work->dmb_name,
+ work->local_master_browser_name,
+ 0x20);
+ }
+
+ DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
+ work->dmb_name.name,
+ inet_ntoa(work->dmb_addr)));
+ sync_browse_lists(work,
+ work->dmb_name.name,
+ work->dmb_name.name_type,
+ work->dmb_addr, False, False);
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_elections.c b/source/nmbd/nmbd_elections.c
new file mode 100644
index 00000000000..6db595269f7
--- /dev/null
+++ b/source/nmbd/nmbd_elections.c
@@ -0,0 +1,407 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/* Election parameters. */
+extern time_t StartupTime;
+
+/****************************************************************************
+ Send an election datagram packet.
+**************************************************************************/
+static void send_election_dgram(struct subnet_record *subrec, char *workgroup_name,
+ uint32 criterion, int timeup,char *server_name)
+{
+ pstring outbuf;
+ char *p;
+
+ DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
+ workgroup_name, subrec->subnet_name ));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_Election; /* Election opcode. */
+ p++;
+
+ CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
+ SIVAL(p,1,criterion);
+ SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
+ p += 13;
+ pstrcpy(p,server_name);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+ global_myname, 0,
+ workgroup_name, 0x1e,
+ subrec->bcast_ip, subrec->myip, DGRAM_PORT);
+}
+
+/*******************************************************************
+ We found a current master browser on one of our broadcast interfaces.
+******************************************************************/
+
+static void check_for_master_browser_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *answer_name,
+ struct in_addr answer_ip, struct res_rec *rrec)
+{
+ DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
+IP %s (just checking).\n", answer_name->name, inet_ntoa(answer_ip) ));
+}
+
+/*******************************************************************
+ We failed to find a current master browser on one of our broadcast interfaces.
+******************************************************************/
+
+static void check_for_master_browser_fail( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name,
+ int fail_code)
+{
+ char *workgroup_name = question_name->name;
+ struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
+
+ if(work == NULL)
+ {
+ DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
+ workgroup_name, subrec->subnet_name ));
+ return;
+ }
+
+ if (strequal(work->work_group, global_myworkgroup))
+ {
+
+ if (lp_local_master())
+ {
+ /* We have discovered that there is no local master
+ browser, and we are configured to initiate
+ an election that we will participate in.
+ */
+ DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
+ work->work_group, subrec->subnet_name ));
+
+ /* Setting this means we will participate when the
+ election is run in run_elections(). */
+ work->needelection = True;
+ }
+ else
+ {
+ /* We need to force an election, because we are configured
+ not to become the local master, but we still need one,
+ having detected that one doesn't exist.
+ */
+ send_election_dgram(subrec, work->work_group, 0, 0, "");
+ }
+ }
+}
+
+/*******************************************************************
+ Ensure there is a local master browser for a workgroup on our
+ broadcast interfaces.
+******************************************************************/
+
+void check_master_browser_exists(time_t t)
+{
+ static time_t lastrun=0;
+ struct subnet_record *subrec;
+ char *workgroup_name = global_myworkgroup;
+
+ if (!lastrun)
+ lastrun = t;
+
+ if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
+ return;
+
+ lastrun = t;
+
+ dump_workgroups(False);
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work))
+ {
+ /* Do a name query for the local master browser on this net. */
+ query_name( subrec, work->work_group, 0x1d,
+ check_for_master_browser_success,
+ check_for_master_browser_fail,
+ NULL);
+ }
+ }
+ }
+}
+
+/*******************************************************************
+ Run an election.
+******************************************************************/
+
+void run_elections(time_t t)
+{
+ static time_t lastime = 0;
+
+ struct subnet_record *subrec;
+
+ /* Send election packets once every 2 seconds - note */
+ if (lastime && (t - lastime < 2))
+ return;
+
+ lastime = t;
+
+ START_PROFILE(run_elections);
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ if (work->RunningElection)
+ {
+ /*
+ * We can only run an election for a workgroup if we have
+ * registered the WORKGROUP<1e> name, as that's the name
+ * we must listen to.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, work->work_group, 0x1e);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
+ send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
+ t - StartupTime, global_myname);
+
+ if (work->ElectionCount++ >= 4)
+ {
+ /* Won election (4 packets were sent out uncontested. */
+ DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+
+ work->RunningElection = False;
+
+ become_local_master_browser(subrec, work);
+ }
+ }
+ }
+ }
+ END_PROFILE(run_elections);
+}
+
+/*******************************************************************
+ Determine if I win an election.
+******************************************************************/
+
+static BOOL win_election(struct work_record *work, int version,
+ uint32 criterion, int timeup, char *server_name)
+{
+ int mytimeup = time(NULL) - StartupTime;
+ uint32 mycriterion = work->ElectionCriterion;
+
+ /* If local master is false then never win
+ in election broadcasts. */
+ if(!lp_local_master())
+ {
+ DEBUG(3,("win_election: Losing election as local master == False\n"));
+ return False;
+ }
+
+ DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n",
+ version, ELECTION_VERSION,
+ criterion, mycriterion,
+ timeup, mytimeup,
+ server_name, global_myname));
+
+ if (version > ELECTION_VERSION)
+ return(False);
+ if (version < ELECTION_VERSION)
+ return(True);
+
+ if (criterion > mycriterion)
+ return(False);
+ if (criterion < mycriterion)
+ return(True);
+
+ if (timeup > mytimeup)
+ return(False);
+ if (timeup < mytimeup)
+ return(True);
+
+ if (strcasecmp(global_myname, server_name) > 0)
+ return(False);
+
+ return(True);
+}
+
+/*******************************************************************
+ Process an incoming election datagram packet.
+******************************************************************/
+
+void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int version = CVAL(buf,0);
+ uint32 criterion = IVAL(buf,1);
+ int timeup = IVAL(buf,5)/1000;
+ char *server_name = buf+13;
+ struct work_record *work;
+ char *workgroup_name = dgram->dest_name.name;
+
+ START_PROFILE(election);
+ server_name[15] = 0;
+
+ DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n",
+ server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name ));
+
+ DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup));
+
+ if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+ {
+ DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
+ workgroup_name, subrec->subnet_name ));
+ goto done;
+ }
+
+ if (!strequal(work->work_group, global_myworkgroup))
+ {
+ DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
+is not my workgroup.\n", work->work_group, subrec->subnet_name ));
+ goto done;
+ }
+
+ if (win_election(work, version,criterion,timeup,server_name))
+ {
+ /* We take precedence over the requesting server. */
+ if (!work->RunningElection)
+ {
+ /* We weren't running an election - start running one. */
+
+ work->needelection = True;
+ work->ElectionCount=0;
+ }
+
+ /* Note that if we were running an election for this workgroup on this
+ subnet already, we just ignore the server we take precedence over. */
+ }
+ else
+ {
+ /* We lost. Stop participating. */
+ work->needelection = False;
+
+ if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work))
+ {
+ work->RunningElection = False;
+ DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+ if (AM_LOCAL_MASTER_BROWSER(work))
+ unbecome_local_master_browser(subrec, work, False);
+ }
+ }
+done:
+ END_PROFILE(election);
+}
+
+/****************************************************************************
+ This function looks over all the workgroups known on all the broadcast
+ subnets and decides if a browser election is to be run on that workgroup.
+ It returns True if any election packets need to be sent (this will then
+ be done by run_elections().
+***************************************************************************/
+
+BOOL check_elections(void)
+{
+ struct subnet_record *subrec;
+ BOOL run_any_election = False;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ run_any_election |= work->RunningElection;
+
+ /*
+ * Start an election if we have any chance of winning.
+ * Note this is a change to the previous code, that would
+ * only run an election if nmbd was in the potential browser
+ * state. We need to run elections in any state if we're told
+ * to. JRA.
+ */
+
+ if (work->needelection && !work->RunningElection && lp_local_master())
+ {
+ /*
+ * We can only run an election for a workgroup if we have
+ * registered the WORKGROUP<1e> name, as that's the name
+ * we must listen to.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, work->work_group, 0x1e);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
+ DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
+ work->work_group, subrec->subnet_name ));
+
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+
+
+
+/****************************************************************************
+process a internal Samba message forcing an election
+***************************************************************************/
+void nmbd_message_election(int msg_type, pid_t src, void *buf, size_t len)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next) {
+ if (strequal(work->work_group, global_myworkgroup)) {
+ work->needelection = True;
+ work->ElectionCount=0;
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ }
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_incomingdgrams.c b/source/nmbd/nmbd_incomingdgrams.c
new file mode 100644
index 00000000000..d10e6ec0b0d
--- /dev/null
+++ b/source/nmbd/nmbd_incomingdgrams.c
@@ -0,0 +1,861 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern BOOL found_lm_clients;
+
+#if 0
+
+/* XXXX note: This function is currently unsuitable for use, as it
+ does not properly check that a server is in a fit state to become
+ a backup browser before asking it to be one.
+ The code is left here to be worked on at a later date.
+*/
+
+/****************************************************************************
+Tell a server to become a backup browser
+**************************************************************************/
+
+void tell_become_backup(void)
+{
+ struct subnet_record *subrec;
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ struct server_record *servrec;
+ int num_servers = 0;
+ int num_backups = 0;
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ num_servers++;
+
+ if (is_myname(servrec->serv.name))
+ continue;
+
+ if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER)
+ {
+ num_backups++;
+ continue;
+ }
+
+ if (servrec->serv.type & SV_TYPE_MASTER_BROWSER)
+ continue;
+
+ if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER))
+ continue;
+
+ DEBUG(3,("num servers: %d num backups: %d\n",
+ num_servers, num_backups));
+
+ /* make first server a backup server. thereafter make every
+ tenth server a backup server */
+ if (num_backups != 0 && (num_servers+9) / num_backups > 10)
+ continue;
+
+ DEBUG(2,("sending become backup to %s %s for %s\n",
+ servrec->serv.name, inet_ntoa(subrec->bcast_ip),
+ work->work_group));
+
+ /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
+ do_announce_request(servrec->serv.name, work->work_group,
+ ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip);
+ }
+ }
+ }
+}
+#endif
+
+/*******************************************************************
+ Process an incoming host announcement packet.
+*******************************************************************/
+
+void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int ttl = IVAL(buf,1)/1000;
+ char *announce_name = buf+5;
+ uint32 servertype = IVAL(buf,23);
+ char *comment = buf+31;
+ struct work_record *work;
+ struct server_record *servrec;
+ char *work_name;
+ char *source_name = dgram->source_name.name;
+
+ START_PROFILE(host_announce);
+ comment[43] = 0;
+
+ DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),announce_name));
+
+ DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
+ ttl, servertype,comment));
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* A host announcement must be sent to the name WORKGROUP<1d>. */
+ if(dgram->dest_name.name_type != 0x1d)
+ {
+ DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1d. Allowing packet anyway.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ /* Change it so it was. */
+ dgram->dest_name.name_type = 0x1d;
+ }
+
+ /* For a host announce the workgroup name is the destination name. */
+ work_name = dgram->dest_name.name;
+
+ /*
+ * Syntax servers version 5.1 send HostAnnounce packets to
+ * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
+ * instead of WORKGROUP<1d> name. So to fix this we check if
+ * the workgroup name is our own name, and if so change it
+ * to be our primary workgroup name.
+ */
+
+ if(strequal(work_name, global_myname))
+ work_name = global_myworkgroup;
+
+ /*
+ * We are being very agressive here in adding a workgroup
+ * name on the basis of a host announcing itself as being
+ * in that workgroup. Maybe we should wait for the workgroup
+ * announce instead ? JRA.
+ */
+
+ work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(servertype != 0)
+ {
+ if (work ==NULL )
+ {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ if((servrec = find_server_in_workgroup( work, announce_name))==NULL)
+ {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, announce_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ }
+ else
+ {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl( servrec, ttl);
+ StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+ }
+ }
+ else
+ {
+ /*
+ * This server is announcing it is going down. Remove it from the
+ * workgroup.
+ */
+ if(!is_myname(announce_name) && (work != NULL) &&
+ ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)
+ )
+ {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+ subrec->work_changed = True;
+done:
+ END_PROFILE(host_announce);
+}
+
+/*******************************************************************
+ Process an incoming WORKGROUP announcement packet.
+*******************************************************************/
+
+void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int ttl = IVAL(buf,1)/1000;
+ char *workgroup_announce_name = buf+5;
+ uint32 servertype = IVAL(buf,23);
+ char *master_name = buf+31;
+ struct work_record *work;
+ char *source_name = dgram->source_name.name;
+
+ START_PROFILE(workgroup_announce);
+ master_name[43] = 0;
+
+ DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
+%s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),workgroup_announce_name));
+
+ DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
+ ttl, servertype, master_name));
+
+ /* Workgroup announcements must only go to the MSBROWSE name. */
+ if (!strequal(dgram->dest_name.name, MSBROWSE) || (dgram->dest_name.name_type != 0x1))
+ {
+ DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ goto done;
+ }
+
+ if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL)
+ {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
+ goto done;
+ }
+ else
+ {
+ /* Update the workgroup death_time. */
+ update_workgroup_ttl(work, ttl);
+ }
+
+ if(*work->local_master_browser_name == '\0')
+ {
+ /* Set the master browser name. */
+ set_workgroup_local_master_browser_name( work, master_name );
+ }
+
+ subrec->work_changed = True;
+done:
+ END_PROFILE(workgroup_announce);
+}
+
+/*******************************************************************
+ Process an incoming local master browser announcement packet.
+*******************************************************************/
+
+void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int ttl = IVAL(buf,1)/1000;
+ char *server_name = buf+5;
+ uint32 servertype = IVAL(buf,23);
+ char *comment = buf+31;
+ char *work_name;
+ struct work_record *work;
+ struct server_record *servrec;
+ char *source_name = dgram->source_name.name;
+
+ START_PROFILE(local_master_announce);
+ comment[43] = 0;
+
+ DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),server_name));
+
+ DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
+ ttl, servertype, comment));
+
+ /* A local master announcement must be sent to the name WORKGROUP<1e>. */
+ if(dgram->dest_name.name_type != 0x1e)
+ {
+ DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x1e. Ignoring packet.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ goto done;
+ }
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* For a local master announce the workgroup name is the destination name. */
+ work_name = dgram->dest_name.name;
+
+ if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL)
+ {
+ /* Don't bother adding if it's a local master release announce. */
+ if(servertype == 0)
+ goto done;
+
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ /* If we think we're the local master browser for this workgroup,
+ we should never have got this packet. We don't see our own
+ packets.
+ */
+ if(AM_LOCAL_MASTER_BROWSER(work))
+ {
+ DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
+a local master browser for workgroup %s and we think we are master. Forcing election.\n",
+ server_name, inet_ntoa(p->ip), work_name));
+
+ /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
+ they have become a local master browser once, they will never
+ stop sending local master announcements. To fix this we send
+ them a reset browser packet, with level 0x2 on the __SAMBA__
+ name that only they should be listening to. */
+
+ send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
+
+ /* We should demote ourself and force an election. */
+
+ unbecome_local_master_browser( subrec, work, True);
+
+ /* The actual election requests are handled in
+ nmbd_election.c */
+ goto done;
+ }
+
+ /* Find the server record on this workgroup. If it doesn't exist, add it. */
+
+ if(servertype != 0)
+ {
+ if((servrec = find_server_in_workgroup( work, server_name))==NULL)
+ {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, server_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ }
+ else
+ {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl(servrec, ttl);
+ StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+ }
+
+ set_workgroup_local_master_browser_name( work, server_name );
+ }
+ else
+ {
+ /*
+ * This server is announcing it is going down. Remove it from the
+ * workgroup.
+ */
+ if(!is_myname(server_name) && (work != NULL) &&
+ ((servrec = find_server_in_workgroup( work, server_name))!=NULL)
+ )
+ {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+
+ subrec->work_changed = True;
+done:
+ END_PROFILE(local_master_announce);
+}
+
+/*******************************************************************
+ Process a domain master announcement frame.
+ Domain master browsers receive these from local masters. The Domain
+ master should then issue a sync with the local master, asking for
+ that machines local server list.
+******************************************************************/
+
+void process_master_browser_announce(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf)
+{
+ char *local_master_name = buf;
+ struct work_record *work;
+ struct browse_cache_record *browrec;
+
+ START_PROFILE(master_browser_announce);
+ local_master_name[15] = 0;
+
+ DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
+ local_master_name, inet_ntoa(p->ip)));
+
+ if (!lp_domain_master())
+ {
+ DEBUG(0,("process_master_browser_announce: Not configured as domain \
+master - ignoring master announce.\n"));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(subrec, global_myworkgroup)) == NULL)
+ {
+ DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
+ global_myworkgroup, subrec->subnet_name));
+ goto done;
+ }
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work))
+ {
+ DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
+%s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
+ goto done;
+ }
+
+ /* Add this host as a local master browser entry on the browse lists.
+ This causes a sync request to be made to it at a later date.
+ */
+
+ if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL)
+ {
+ /* Add it. */
+ create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
+ }
+ else
+ update_browser_death_time(browrec);
+done:
+ END_PROFILE(master_browser_announce);
+}
+
+/*******************************************************************
+ Process an incoming LanMan host announcement packet.
+*******************************************************************/
+
+void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ uint32 servertype = IVAL(buf,1);
+ int osmajor=CVAL(buf,5); /* major version of node software */
+ int osminor=CVAL(buf,6); /* minor version of node software */
+ int ttl = SVAL(buf,7);
+ char *announce_name = buf+9;
+ struct work_record *work;
+ struct server_record *servrec;
+ char *work_name;
+ char *source_name = dgram->source_name.name;
+ pstring comment;
+ char *s = buf+9;
+
+ START_PROFILE(lm_host_announce);
+ s = skip_string(s,1);
+ StrnCpy(comment, s, 43);
+
+ DEBUG(3,("process_lm_host_announce: LM Announcement from %s<%02x> IP %s to \
+%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name),announce_name));
+
+ DEBUG(5,("process_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s\n",
+ osmajor, osminor, ttl, servertype,comment));
+
+ if ((osmajor < 36) || (osmajor > 38) || (osminor !=0))
+ {
+ DEBUG(5,("process_lm_host_announce: LM Announcement packet does not \
+originate from OS/2 Warp client. Ignoring packet.\n"));
+ /* Could have been from a Windows machine (with its LM Announce enabled),
+ or a Samba server. Then don't disrupt the current browse list. */
+ goto done;
+ }
+
+ /* Filter servertype to remove impossible bits. */
+ servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
+
+ /* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
+ if(dgram->dest_name.name_type != 0x00)
+ {
+ DEBUG(2,("process_lm_host_announce: incorrect name type for destination from IP %s \
+(was %02x) should be 0x00. Allowing packet anyway.\n",
+ inet_ntoa(p->ip), dgram->dest_name.name_type));
+ /* Change it so it was. */
+ dgram->dest_name.name_type = 0x00;
+ }
+
+ /* For a LanMan host announce the workgroup name is the destination name. */
+ work_name = dgram->dest_name.name;
+
+ /*
+ * Syntax servers version 5.1 send HostAnnounce packets to
+ * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
+ * instead of WORKGROUP<1d> name. So to fix this we check if
+ * the workgroup name is our own name, and if so change it
+ * to be our primary workgroup name. This code is probably
+ * not needed in the LanMan announce code, but it won't hurt.
+ */
+
+ if(strequal(work_name, global_myname))
+ work_name = global_myworkgroup;
+
+ /*
+ * We are being very agressive here in adding a workgroup
+ * name on the basis of a host announcing itself as being
+ * in that workgroup. Maybe we should wait for the workgroup
+ * announce instead ? JRA.
+ */
+
+ work = find_workgroup_on_subnet(subrec, work_name);
+
+ if(servertype != 0)
+ {
+ if (work == NULL)
+ {
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ goto done;
+ }
+
+ if((servrec = find_server_in_workgroup( work, announce_name))==NULL)
+ {
+ /* If this server is not already in the workgroup, add it. */
+ create_server_on_workgroup(work, announce_name,
+ servertype|SV_TYPE_LOCAL_LIST_ONLY,
+ ttl, comment);
+ }
+ else
+ {
+ /* Update the record. */
+ servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
+ update_server_ttl( servrec, ttl);
+ StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+ }
+ }
+ else
+ {
+ /*
+ * This server is announcing it is going down. Remove it from the
+ * workgroup.
+ */
+ if(!is_myname(announce_name) && (work != NULL) &&
+ ((servrec = find_server_in_workgroup( work, announce_name))!=NULL)
+ )
+ {
+ remove_server_from_workgroup( work, servrec);
+ }
+ }
+
+ subrec->work_changed = True;
+ found_lm_clients = True;
+done:
+ END_PROFILE(lm_host_announce);
+}
+
+/****************************************************************************
+ Send a backup list response.
+*****************************************************************************/
+static void send_backup_list_response(struct subnet_record *subrec,
+ struct work_record *work,
+ struct nmb_name *send_to_name,
+ unsigned char max_number_requested,
+ uint32 token, struct in_addr sendto_ip,
+ int port)
+{
+ char outbuf[1024];
+ char *p, *countptr;
+ unsigned int count = 0;
+#if 0
+ struct server_record *servrec;
+#endif
+
+ memset(outbuf,'\0',sizeof(outbuf));
+
+ DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
+ work->work_group, nmb_namestr(send_to_name), inet_ntoa(sendto_ip)));
+
+ p = outbuf;
+
+ SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
+ p++;
+
+ countptr = p;
+ p++;
+
+ SIVAL(p,0,token); /* The sender's unique info. */
+ p += 4;
+
+ /* We always return at least one name - our own. */
+ count = 1;
+ StrnCpy(p,global_myname,15);
+ strupper(p);
+ p = skip_string(p,1);
+
+ /* Look for backup browsers in this workgroup. */
+
+#if 0
+ /* we don't currently send become_backup requests so we should never
+ send any other servers names out as backups for our
+ workgroup. That's why this is commented out (tridge) */
+
+ /*
+ * NB. Note that the struct work_record here is not neccessarily
+ * attached to the subnet *subrec.
+ */
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ int len = PTR_DIFF(p, outbuf);
+ if((sizeof(outbuf) - len) < 16)
+ break;
+
+ if(count >= (unsigned int)max_number_requested)
+ break;
+
+ if(strnequal(servrec->serv.name, global_myname,15))
+ continue;
+
+ if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
+ continue;
+
+ StrnCpy(p, servrec->serv.name, 15);
+ strupper(p);
+ count++;
+
+ DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
+ p, count));
+
+ p = skip_string(p,1);
+ }
+#endif
+
+ SCVAL(countptr, 0, count);
+
+ DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
+ send_to_name->name, inet_ntoa(sendto_ip), count));
+
+ send_mailslot(True, BROWSE_MAILSLOT,
+ outbuf,PTR_DIFF(p,outbuf),
+ global_myname, 0,
+ send_to_name->name,0,
+ sendto_ip, subrec->myip, port);
+}
+
+/*******************************************************************
+ Process a send backup list request packet.
+
+ A client sends a backup list request to ask for a list of servers on
+ the net that maintain server lists for a domain. A server is then
+ chosen from this list to send NetServerEnum commands to to list
+ available servers.
+
+********************************************************************/
+
+void process_get_backup_list_request(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ unsigned char max_number_requested = CVAL(buf,0);
+ uint32 token = IVAL(buf,1); /* Sender's key index for the workgroup. */
+ int name_type = dgram->dest_name.name_type;
+ char *workgroup_name = dgram->dest_name.name;
+ struct subnet_record *search_subrec = subrec;
+
+ START_PROFILE(get_backup_list);
+ DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We have to be a master browser, or a domain master browser
+ for the requested workgroup. That means it must be our
+ workgroup. */
+
+ if(strequal(workgroup_name, global_myworkgroup) == False)
+ {
+ DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(search_subrec, workgroup_name)) == NULL)
+ {
+ DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, search_subrec->subnet_name));
+ goto done;
+ }
+
+ /*
+ * If the packet was sent to WORKGROUP<1b> instead
+ * of WORKGROUP<1d> then it was unicast to us a domain master
+ * browser. Change search subrec to unicast.
+ */
+
+ if(name_type == 0x1b)
+ {
+ /* We must be a domain master browser in order to
+ process this packet. */
+
+ if(!AM_DOMAIN_MASTER_BROWSER(work))
+ {
+ DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a domain master browser.\n", workgroup_name));
+ goto done;
+ }
+
+ search_subrec = unicast_subnet;
+ }
+ else if (name_type == 0x1d)
+ {
+ /* We must be a local master browser in order to
+ process this packet. */
+
+ if(!AM_LOCAL_MASTER_BROWSER(work))
+ {
+ DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
+and I am not a local master browser.\n", workgroup_name));
+ goto done;
+ }
+ }
+ else
+ {
+ DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
+ name_type));
+ goto done;
+ }
+
+ send_backup_list_response(subrec, work, &dgram->source_name,
+ max_number_requested, token, p->ip, p->port);
+done:
+ END_PROFILE(get_backup_list);
+}
+
+/*******************************************************************
+ Process a reset browser state packet.
+
+ Diagnostic packet:
+ 0x1 - Stop being a master browser and become a backup browser.
+ 0x2 - Discard browse lists, stop being a master browser, try again.
+ 0x4 - Stop being a master browser forever.
+
+******************************************************************/
+
+void process_reset_browser(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int state = CVAL(buf,0);
+ struct subnet_record *sr;
+
+ START_PROFILE(reset_browser);
+ DEBUG(1,("process_reset_browser: received diagnostic browser reset \
+request from %s IP %s state=0x%X\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip), state));
+
+ /* Stop being a local master browser on all our broadcast subnets. */
+ if (state & 0x1)
+ {
+ for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr))
+ {
+ struct work_record *work;
+ for (work = sr->workgrouplist; work; work = work->next)
+ {
+ if (AM_LOCAL_MASTER_BROWSER(work))
+ unbecome_local_master_browser(sr, work, True);
+ }
+ }
+ }
+
+ /* Discard our browse lists. */
+ if (state & 0x2)
+ {
+ /*
+ * Calling expire_workgroups_and_servers with a -1
+ * time causes all servers not marked with a PERMANENT_TTL
+ * on the workgroup lists to be discarded, and all
+ * workgroups with empty server lists to be discarded.
+ * This means we keep our own server names and workgroup
+ * as these have a PERMANENT_TTL.
+ */
+
+ expire_workgroups_and_servers(-1);
+ }
+
+ /* Request to stop browsing altogether. */
+ if (state & 0x4)
+ DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
+
+ END_PROFILE(reset_browser);
+}
+
+/*******************************************************************
+ Process an announcement request packet.
+ We don't respond immediately, we just check it's a request for
+ our workgroup and then set the flag telling the announce code
+ in nmbd_sendannounce.c:announce_my_server_names that an
+ announcement is needed soon.
+******************************************************************/
+
+void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ char *workgroup_name = dgram->dest_name.name;
+
+ START_PROFILE(announce_request);
+ DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We only send announcement requests on our workgroup. */
+ if(strequal(workgroup_name, global_myworkgroup) == False)
+ {
+ DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+ {
+ DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+ workgroup_name));
+ goto done;
+ }
+
+ work->needannounce = True;
+done:
+ END_PROFILE(lm_host_announce);
+}
+
+/*******************************************************************
+ Process a LanMan announcement request packet.
+ We don't respond immediately, we just check it's a request for
+ our workgroup and then set the flag telling that we have found
+ a LanMan client (DOS or OS/2) and that we will have to start
+ sending LanMan announcements (unless specifically disabled
+ through the "lm announce" parameter in smb.conf)
+******************************************************************/
+
+void process_lm_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *workgroup_name = dgram->dest_name.name;
+
+ START_PROFILE(lm_announce_request);
+ DEBUG(3,("process_lm_announce_request: Announce request from %s IP %s to %s.\n",
+ nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
+ nmb_namestr(&dgram->dest_name)));
+
+ /* We only send announcement requests on our workgroup. */
+ if(strequal(workgroup_name, global_myworkgroup) == False)
+ {
+ DEBUG(7,("process_lm_announce_request: Ignoring announce request for workgroup %s.\n",
+ workgroup_name));
+ goto done;
+ }
+
+ if(find_workgroup_on_subnet(subrec, workgroup_name) == NULL)
+ {
+ DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+ workgroup_name));
+ goto done;
+ }
+
+ found_lm_clients = True;
+done:
+ END_PROFILE(lm_host_announce);
+}
diff --git a/source/nmbd/nmbd_incomingrequests.c b/source/nmbd/nmbd_incomingrequests.c
new file mode 100644
index 00000000000..81e6bb9629f
--- /dev/null
+++ b/source/nmbd/nmbd_incomingrequests.c
@@ -0,0 +1,624 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file contains all the code to process NetBIOS requests coming
+ in on port 137. It does not deal with the code needed to service
+ WINS server requests, but only broadcast and unicast requests.
+
+*/
+
+#include "includes.h"
+
+extern fstring global_myworkgroup;
+
+/****************************************************************************
+Send a name release response.
+**************************************************************************/
+
+static void send_name_release_response(int rcode, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_REL, /* nmbd type code. */
+ NMB_NAME_RELEASE_OPCODE, /* opcode. */
+ 0, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/****************************************************************************
+Process a name release packet on a broadcast subnet.
+Ignore it if it's not one of our names.
+****************************************************************************/
+
+void process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr owner_ip;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ BOOL group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec;
+ int rcode = 0;
+
+ putip((char *)&owner_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast)
+ {
+ /* We should only get broadcast name release packets here.
+ Anyone trying to release unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_release_request: unicast name release request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
+
+ send_name_release_response(FMT_ERR, p);
+ return;
+ }
+
+ DEBUG(3,("process_name_release_request: Name release on name %s, \
+subnet %s from owner IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ subrec->subnet_name, inet_ntoa(owner_ip)));
+
+ /* If someone is releasing a broadcast group name, just ignore it. */
+ if( group && !ismyip(owner_ip) )
+ return;
+
+ /*
+ * Code to work around a bug in FTP OnNet software NBT implementation.
+ * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
+ * names and *don't set the group bit* !!!!!
+ */
+
+ if( !group && !ismyip(owner_ip) && strequal(question->name, global_myworkgroup) &&
+ ((question->name_type == 0x0) || (question->name_type == 0x1e)))
+ {
+ DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
+group release name %s from IP %s on subnet %s with no group bit set.\n",
+ nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
+ return;
+ }
+
+ namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_ANY_NAME);
+
+ /* We only care about someone trying to release one of our names. */
+ if( namerec
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME) ) )
+ {
+ rcode = ACT_ERR;
+ DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
+on subnet %s being rejected as it is one of our names.\n",
+ nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
+ }
+
+ if(rcode == 0)
+ return;
+
+ /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+ send_name_release_response(rcode, p);
+}
+
+/****************************************************************************
+Send a name registration response.
+**************************************************************************/
+
+static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_REG, /* nmbd type code. */
+ NMB_NAME_REG_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/****************************************************************************
+Process a name refresh request on a broadcast subnet.
+**************************************************************************/
+
+void process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct in_addr from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast)
+ {
+ /* We should only get broadcast name refresh packets here.
+ Anyone trying to refresh unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_refresh_request: unicast name registration request \
+received for name %s from IP %s on subnet %s.\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ DEBUG(0,("Error - should be sent to WINS server\n"));
+
+ send_name_registration_response(FMT_ERR, 0, p);
+ return;
+ }
+
+ /* Just log a message. We really don't care about broadcast name
+ refreshes. */
+
+ DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
+IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+}
+
+/****************************************************************************
+Process a name registration request on a broadcast subnet.
+**************************************************************************/
+
+void process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ BOOL group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec = NULL;
+ int ttl = nmb->additional->ttl;
+ struct in_addr from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(!bcast)
+ {
+ /* We should only get broadcast name registration packets here.
+ Anyone trying to register unicast should be going to a WINS
+ server. If the code gets here, then either we are not a wins
+ server and they sent it anyway, or we are a WINS server and
+ the request was malformed. Either way, log an error here.
+ and send an error reply back.
+ */
+ DEBUG(0,("process_name_registration_request: unicast name registration request \
+received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+ send_name_registration_response(FMT_ERR, 0, p);
+ return;
+ }
+
+ DEBUG(3,("process_name_registration_request: Name registration for name %s \
+IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+ /* See if the name already exists. */
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * If the name being registered exists and is a WINS_PROXY_NAME
+ * then delete the WINS proxy name entry so we don't reply erroneously
+ * later to queries.
+ */
+
+ if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME))
+ {
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ }
+
+ if (!group)
+ {
+ /* Unique name. */
+
+ if( (namerec != NULL)
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME)
+ || NAME_GROUP(namerec) ) )
+ {
+ /* No-one can register one of Samba's names, nor can they
+ register a name that's a group name as a unique name */
+
+ send_name_registration_response(ACT_ERR, 0, p);
+ return;
+ }
+ else if(namerec != NULL)
+ {
+ /* Update the namelist record with the new information. */
+ namerec->data.ip[0] = from_ip;
+ update_name_ttl(namerec, ttl);
+
+ DEBUG(3,("process_name_registration_request: Updated name record %s \
+with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+ }
+ else
+ {
+ /* Group name. */
+
+ if( (namerec != NULL)
+ && !NAME_GROUP(namerec)
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME) ) )
+ {
+ /* Disallow group names when we have a unique name. */
+ send_name_registration_response(ACT_ERR, 0, p);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+This is used to sort names for a name status into a sensible order.
+We put our own names first, then in alphabetical order.
+**************************************************************************/
+
+static int status_compare(char *n1,char *n2)
+{
+ extern pstring global_myname;
+ int l1,l2,l3;
+
+ /* It's a bit tricky because the names are space padded */
+ for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
+ for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
+ l3 = strlen(global_myname);
+
+ if ((l1==l3) && strncmp(n1,global_myname,l3) == 0 &&
+ (l2!=l3 || strncmp(n2,global_myname,l3) != 0))
+ return -1;
+
+ if ((l2==l3) && strncmp(n2,global_myname,l3) == 0 &&
+ (l1!=l3 || strncmp(n1,global_myname,l3) != 0))
+ return 1;
+
+ return memcmp(n1,n2,18);
+}
+
+
+/****************************************************************************
+ Process a node status query
+ ****************************************************************************/
+
+void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *qname = nmb->question.question_name.name;
+ int ques_type = nmb->question.question_name.name_type;
+ char rdata[MAX_DGRAM_SIZE];
+ char *countptr, *buf, *bufend, *buf0;
+ int names_added,i;
+ struct name_record *namerec;
+
+ DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip),
+ subrec->subnet_name));
+
+ if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name,
+ FIND_SELF_NAME)) == 0)
+ {
+ DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
+subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
+ inet_ntoa(p->ip), subrec->subnet_name));
+
+ return;
+ }
+
+ /* this is not an exact calculation. the 46 is for the stats buffer
+ and the 60 is to leave room for the header etc */
+ bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
+ countptr = buf = rdata;
+ buf += 1;
+ buf0 = buf;
+
+ names_added = 0;
+
+ namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+
+ while (buf < bufend)
+ {
+ if( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME) )
+ {
+ int name_type = namerec->name.name_type;
+
+ if (!strequal(namerec->name.name,"*") &&
+ !strequal(namerec->name.name,"__SAMBA__") &&
+ (name_type < 0x1b || name_type >= 0x20 ||
+ ques_type < 0x1b || ques_type >= 0x20 ||
+ strequal(qname, namerec->name.name)))
+ {
+ /* Start with the name. */
+ memset(buf,'\0',18);
+ slprintf(buf, 17, "%-15.15s",namerec->name.name);
+ strupper(buf);
+
+ /* Put the name type and netbios flags in the buffer. */
+ buf[15] = name_type;
+ set_nb_flags( &buf[16],namerec->data.nb_flags );
+ buf[16] |= NB_ACTIVE; /* all our names are active */
+
+ buf += 18;
+
+ names_added++;
+ }
+ }
+
+ /* Remove duplicate names. */
+ if (names_added > 1) {
+ qsort( buf0, names_added, 18, QSORT_CAST status_compare );
+ }
+
+ for( i=1; i < names_added ; i++ )
+ {
+ if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0)
+ {
+ names_added--;
+ if (names_added == i)
+ break;
+ memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
+ i--;
+ }
+ }
+
+ buf = buf0 + 18*names_added;
+
+ namerec = (struct name_record *)ubi_trNext( namerec );
+
+ if (!namerec)
+ {
+ /* End of the subnet specific name list. Now
+ add the names on the unicast subnet . */
+ struct subnet_record *uni_subrec = unicast_subnet;
+
+ if (uni_subrec != subrec)
+ {
+ subrec = uni_subrec;
+ namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ }
+ }
+ if (!namerec)
+ break;
+
+ }
+
+ SCVAL(countptr,0,names_added);
+
+ /* We don't send any stats as they could be used to attack
+ the protocol. */
+ memset(buf,'\0',46);
+
+ buf += 46;
+
+ /* Send a NODE STATUS RESPONSE */
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_STATUS, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ 0, /* ttl. */
+ rdata, /* data to send. */
+ PTR_DIFF(buf,rdata)); /* data length. */
+}
+
+
+/***************************************************************************
+Process a name query.
+
+For broadcast name queries:
+
+ - Only reply if the query is for one of YOUR names.
+ - NEVER send a negative response to a broadcast query.
+
+****************************************************************************/
+
+void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ int ttl=0;
+ int rcode = 0;
+ char *prdata = NULL;
+ char rdata[6];
+ BOOL success = False;
+ struct name_record *namerec = NULL;
+ int reply_data_len = 0;
+ int i;
+
+ DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
+ inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
+
+ /* Look up the name in the cache - if the request is a broadcast request that
+ came from a subnet we don't know about then search all the broadcast subnets
+ for a match (as we don't know what interface the request came in on). */
+
+ if(subrec == remote_broadcast_subnet)
+ namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
+ else
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+
+ /* Check if it is a name that expired */
+ if( namerec
+ && ( (namerec->data.death_time != PERMANENT_TTL)
+ && (namerec->data.death_time < p->timestamp) ) )
+ {
+ DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
+ namerec = NULL;
+ }
+
+ if (namerec)
+ {
+
+ /*
+ * Always respond to unicast queries.
+ * Don't respond to broadcast queries unless the query is for
+ * a name we own, a Primary Domain Controller name, or a WINS_PROXY
+ * name with type 0 or 0x20. WINS_PROXY names are only ever added
+ * into the namelist if we were configured as a WINS proxy.
+ */
+
+ if( !bcast
+ || ( bcast
+ && ( (name_type == 0x1b)
+ || (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == PERMANENT_NAME)
+ || ( (namerec->data.source == WINS_PROXY_NAME)
+ && ( (name_type == 0) || (name_type == 0x20) )
+ )
+ )
+ )
+ )
+ {
+
+ /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
+ or it's a Domain Master type. */
+
+ /*
+ * If this is a WINS_PROXY_NAME, then ceck that none of the IP
+ * addresses we are returning is on the same broadcast subnet
+ * as the requesting packet. If it is then don't reply as the
+ * actual machine will be replying also and we don't want two
+ * replies to a broadcast query.
+ */
+
+ if( namerec->data.source == WINS_PROXY_NAME )
+ {
+ for( i = 0; i < namerec->data.num_ips; i++)
+ {
+ if(same_net( namerec->data.ip[i], subrec->myip, subrec->mask_ip ))
+ {
+ DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also \
+on the same subnet (%s) as the requestor. Not replying.\n",
+ nmb_namestr(&namerec->name), subrec->subnet_name ));
+ return;
+ }
+ }
+ }
+
+ ttl = (namerec->data.death_time != PERMANENT_TTL) ?
+ namerec->data.death_time - p->timestamp : lp_max_ttl();
+
+ /* Copy all known ip addresses into the return data. */
+ /* Optimise for the common case of one IP address so
+ we don't need a malloc. */
+
+ if( namerec->data.num_ips == 1 )
+ prdata = rdata;
+ else
+ {
+ if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL)
+ {
+ DEBUG(0,("process_name_query_request: malloc fail !\n"));
+ return;
+ }
+ }
+
+ for( i = 0; i < namerec->data.num_ips; i++ )
+ {
+ set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
+ putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
+ }
+
+ sort_query_replies(prdata, i, p->ip);
+
+ reply_data_len = namerec->data.num_ips * 6;
+ success = True;
+ }
+ }
+
+ /*
+ * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
+ * set we should initiate a WINS query here. On success we add the resolved name
+ * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
+ */
+
+ if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
+ bcast && (subrec != remote_broadcast_subnet))
+ {
+ make_wins_proxy_name_query_request( subrec, p, question );
+ return;
+ }
+
+ if (!success && bcast)
+ {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return; /* Never reply with a negative response to broadcasts. */
+ }
+
+ /*
+ * Final check. From observation, if a unicast packet is sent
+ * to a non-WINS server with the recursion desired bit set
+ * then never send a negative response.
+ */
+
+ if(!success && !bcast && nmb->header.nm_flags.recursion_desired)
+ {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return;
+ }
+
+ if (success)
+ {
+ rcode = 0;
+ DEBUG(3,("OK\n"));
+ }
+ else
+ {
+ rcode = NAM_ERR;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ /* See rfc1002.txt 4.2.13. */
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ prdata, /* data to send. */
+ reply_data_len); /* data length. */
+
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+}
diff --git a/source/nmbd/nmbd_lmhosts.c b/source/nmbd/nmbd_lmhosts.c
new file mode 100644
index 00000000000..4d819b41e96
--- /dev/null
+++ b/source/nmbd/nmbd_lmhosts.c
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ Handle lmhosts file reading.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+Load a lmhosts file.
+****************************************************************************/
+void load_lmhosts_file(char *fname)
+{
+ pstring name;
+ int name_type;
+ struct in_addr ipaddr;
+ XFILE *fp = startlmhosts( fname );
+
+ if (!fp) {
+ DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n",
+ fname, strerror(errno)));
+ return;
+ }
+
+ while (getlmhostsent(fp, name, &name_type, &ipaddr) )
+ {
+ struct subnet_record *subrec = NULL;
+ enum name_source source = LMHOSTS_NAME;
+
+ /* We find a relevent subnet to put this entry on, then add it. */
+ /* Go through all the broadcast subnets and see if the mask matches. */
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ if(same_net(ipaddr, subrec->bcast_ip, subrec->mask_ip))
+ break;
+ }
+
+ /* If none match add the name to the remote_broadcast_subnet. */
+ if(subrec == NULL)
+ subrec = remote_broadcast_subnet;
+
+ if(name_type == -1)
+ {
+ /* Add the (0) and (0x20) names directly into the namelist for this subnet. */
+ (void)add_name_to_subnet(subrec,name,0x00,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+ (void)add_name_to_subnet(subrec,name,0x20,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+ }
+ else
+ {
+ /* Add the given name type to the subnet namelist. */
+ (void)add_name_to_subnet(subrec,name,name_type,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
+ }
+ }
+
+ endlmhosts(fp);
+}
+
+/****************************************************************************
+ Find a name read from the lmhosts file. We secretly check the names on
+ the remote_broadcast_subnet as if the name was added to a regular broadcast
+ subnet it will be found by normal name query processing.
+****************************************************************************/
+
+BOOL find_name_in_lmhosts(struct nmb_name *nmbname, struct name_record **namerecp)
+{
+ struct name_record *namerec;
+
+ *namerecp = NULL;
+
+ if((namerec = find_name_on_subnet(remote_broadcast_subnet, nmbname,
+ FIND_ANY_NAME))==NULL)
+ return False;
+
+ if(!NAME_IS_ACTIVE(namerec) || (namerec->data.source != LMHOSTS_NAME))
+ return False;
+
+ *namerecp = namerec;
+ return True;
+}
diff --git a/source/nmbd/nmbd_logonnames.c b/source/nmbd/nmbd_logonnames.c
new file mode 100644
index 00000000000..52340f1f310
--- /dev/null
+++ b/source/nmbd/nmbd_logonnames.c
@@ -0,0 +1,166 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr allones_ip;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+/****************************************************************************
+ Fail to become a Logon server on a subnet.
+ ****************************************************************************/
+static void become_logon_server_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *fail_name)
+{
+ struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
+ struct server_record *servrec;
+
+ if(!work)
+ {
+ DEBUG(0,("become_logon_server_fail: Error - cannot find \
+workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("become_logon_server_fail: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, fail_name->name, subrec->subnet_name));
+ work->log_state = LOGON_NONE;
+ return;
+ }
+
+ /* Set the state back to LOGON_NONE. */
+ work->log_state = LOGON_NONE;
+
+ servrec->serv.type &= ~SV_TYPE_DOMAIN_CTRL;
+
+ DEBUG(0,("become_logon_server_fail: Failed to become a domain master for \
+workgroup %s on subnet %s. Couldn't register name %s.\n",
+ work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
+
+}
+
+/****************************************************************************
+ Become a Logon server on a subnet.
+ ****************************************************************************/
+
+static void become_logon_server_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *registered_name,
+ uint16 nb_flags,
+ int ttl, struct in_addr registered_ip)
+{
+ struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
+ struct server_record *servrec;
+
+ if(!work)
+ {
+ DEBUG(0,("become_logon_server_success: Error - cannot find \
+workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
+ return;
+ }
+
+ if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+ {
+ DEBUG(0,("become_logon_server_success: Error - cannot find server %s \
+in workgroup %s on subnet %s\n",
+ global_myname, registered_name->name, subrec->subnet_name));
+ work->log_state = LOGON_NONE;
+ return;
+ }
+
+ /* Set the state in the workgroup structure. */
+ work->log_state = LOGON_SRV; /* Become domain master. */
+
+ /* Update our server status. */
+ servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER);
+ /* To allow Win95 policies to load we need to set type domain
+ controller.
+ */
+ servrec->serv.type |= SV_TYPE_DOMAIN_CTRL;
+
+ /* Tell the namelist writer to write out a change. */
+ subrec->work_changed = True;
+
+ DEBUG(0,("become_logon_server_success: Samba is now a logon server \
+for workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+}
+
+/*******************************************************************
+ Become a logon server by attempting to register the WORKGROUP<1c>
+ group name.
+******************************************************************/
+
+static void become_logon_server(struct subnet_record *subrec,
+ struct work_record *work)
+{
+ DEBUG(2,("become_logon_server: Atempting to become logon server for workgroup %s \
+on subnet %s\n", work->work_group,subrec->subnet_name));
+
+ DEBUG(3,("become_logon_server: go to first stage: register %s<1c> name\n",
+ work->work_group));
+ work->log_state = LOGON_WAIT;
+
+ register_name(subrec, work->work_group,0x1c,samba_nb_type|NB_GROUP,
+ become_logon_server_success,
+ become_logon_server_fail, NULL);
+}
+
+/*****************************************************************************
+ Add the internet group <1c> logon names by unicast and broadcast.
+ ****************************************************************************/
+void add_logon_names(void)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
+
+ if (work && (work->log_state == LOGON_NONE))
+ {
+ struct nmb_name nmbname;
+ make_nmb_name(&nmbname,global_myworkgroup,0x1c);
+
+ if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "add_domain_logon_names:\n" );
+ dbgtext( "Attempting to become logon server " );
+ dbgtext( "for workgroup %s ", global_myworkgroup );
+ dbgtext( "on subnet %s\n", subrec->subnet_name );
+ }
+ become_logon_server(subrec, work);
+ }
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_mynames.c b/source/nmbd/nmbd_mynames.c
new file mode 100644
index 00000000000..7f9a3441a8c
--- /dev/null
+++ b/source/nmbd/nmbd_mynames.c
@@ -0,0 +1,225 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern char **my_netbios_names;
+extern fstring global_myworkgroup;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
+
+/****************************************************************************
+ Fail funtion when registering my netbios names.
+ **************************************************************************/
+
+static void my_name_register_failed(struct subnet_record *subrec,
+ struct response_record *rrec, struct nmb_name *nmbname)
+{
+ DEBUG(0,("my_name_register_failed: Failed to register my name %s on subnet %s.\n",
+ nmb_namestr(nmbname), subrec->subnet_name));
+}
+
+
+/****************************************************************************
+ Add my workgroup and my given names to one subnet
+ Also add the magic Samba names.
+ **************************************************************************/
+void register_my_workgroup_one_subnet(struct subnet_record *subrec)
+{
+ int i;
+
+ struct work_record *work;
+
+ /* Create the workgroup on the subnet. */
+ if((work = create_workgroup_on_subnet(subrec, global_myworkgroup,
+ PERMANENT_TTL)) == NULL) {
+ DEBUG(0,("register_my_workgroup_and_names: Failed to create my workgroup %s on subnet %s. \
+Exiting.\n", global_myworkgroup, subrec->subnet_name));
+ return;
+ }
+
+ /* Each subnet entry, except for the wins_server_subnet has
+ the magic Samba names. */
+ add_samba_names_to_subnet(subrec);
+
+ /* Register all our names including aliases. */
+ for (i=0; my_netbios_names[i]; i++) {
+ register_name(subrec, my_netbios_names[i],0x20,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ register_name(subrec, my_netbios_names[i],0x03,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ register_name(subrec, my_netbios_names[i],0x00,samba_nb_type,
+ NULL,
+ my_name_register_failed, NULL);
+ }
+
+ /* Initiate election processing, register the workgroup names etc. */
+ initiate_myworkgroup_startup(subrec, work);
+}
+
+
+/****************************************************************************
+ Add my workgroup and my given names to the subnet lists.
+ Also add the magic Samba names.
+ **************************************************************************/
+
+BOOL register_my_workgroup_and_names(void)
+{
+ struct subnet_record *subrec;
+ int i;
+
+ for(subrec = FIRST_SUBNET;
+ subrec;
+ subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ register_my_workgroup_one_subnet(subrec);
+ }
+
+ /* If we are not a WINS client, we still need to add the magic Samba
+ names and the netbios names to the unicast subnet directly. This is
+ to allow unicast node status requests and queries to still work
+ in a broadcast only environment. */
+
+ if(we_are_a_wins_client() == False)
+ {
+ add_samba_names_to_subnet(unicast_subnet);
+
+ for (i=0; my_netbios_names[i]; i++)
+ {
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ /*
+ * Ensure all the IP addresses are added if we are multihomed.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, my_netbios_names[i],0x20);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names[i],0x3);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names[i],0x0);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type);
+ }
+ }
+
+ /*
+ * Add the WORKGROUP<0> and WORKGROUP<1e> group names to the unicast subnet
+ * also for the same reasons.
+ */
+
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ /*
+ * Ensure all the IP addresses are added if we are multihomed.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, global_myworkgroup, 0x0);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
+
+ make_nmb_name(&nmbname, global_myworkgroup, 0x1e);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
+ }
+ }
+
+ /*
+ * We need to add the Samba names to the remote broadcast subnet,
+ * as NT 4.x does directed broadcast requests to the *<0x0> name.
+ */
+ add_samba_names_to_subnet(remote_broadcast_subnet);
+
+ return True;
+}
+
+/****************************************************************************
+ Remove all the names we registered.
+**************************************************************************/
+
+void release_my_names(void)
+{
+#if 0 /*JRR: do WINS server only, otherwise clients ignore us when we come back up*/
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+#else
+ struct subnet_record *subrec = unicast_subnet;
+#endif
+ {
+ struct name_record *namerec, *nextnamerec;
+
+ for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = nextnamerec)
+ {
+ nextnamerec = (struct name_record *)ubi_trNext( namerec );
+ if( (namerec->data.source == SELF_NAME)
+ && !NAME_IS_DEREGISTERING(namerec) )
+ release_name( subrec, namerec, standard_success_release,
+ NULL, NULL);
+ }
+ }
+}
+
+/*******************************************************************
+ Refresh our registered names.
+ ******************************************************************/
+
+void refresh_my_names(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ struct name_record *namerec;
+
+ /* B nodes don't send out name refresh requests, see RFC 1001, 15.5.1 */
+ if (subrec != unicast_subnet)
+ continue;
+
+ for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = (struct name_record *)ubi_trNext( namerec ) )
+ {
+ /* Each SELF name has an individual time to be refreshed. */
+ if( (namerec->data.source == SELF_NAME)
+ && (namerec->data.refresh_time < t)
+ && ( namerec->data.death_time != PERMANENT_TTL) )
+ {
+ /* We cheat here and pretend the refresh is going to be
+ successful & update the refresh times. This stops
+ multiple refresh calls being done. We actually
+ deal with refresh failure in the fail_fn.
+ */
+ if( !is_refresh_already_queued( subrec, namerec) )
+ refresh_name( subrec, namerec, NULL, NULL, NULL );
+ namerec->data.death_time = t + lp_max_ttl();
+ namerec->data.refresh_time = t + MIN(lp_max_ttl(), MAX_REFRESH_TIME);
+ }
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_namelistdb.c b/source/nmbd/nmbd_namelistdb.c
new file mode 100644
index 00000000000..aa9589e45a9
--- /dev/null
+++ b/source/nmbd/nmbd_namelistdb.c
@@ -0,0 +1,626 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern char **my_netbios_names;
+
+uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
+
+
+/* ************************************************************************** **
+ * Set Samba's NetBIOS name type.
+ * ************************************************************************** **
+ */
+void set_samba_nb_type(void)
+ {
+ if( lp_wins_support() || wins_srv_count() )
+ samba_nb_type = NB_MFLAG; /* samba is a 'hybrid' node type. */
+ else
+ samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
+ } /* set_samba_nb_type */
+
+/* ************************************************************************** **
+ * Convert a NetBIOS name to upper case.
+ * ************************************************************************** **
+ */
+static void upcase_name( struct nmb_name *target, struct nmb_name *source )
+ {
+ int i;
+
+ if( NULL != source )
+ (void)memcpy( target, source, sizeof( struct nmb_name ) );
+
+ strupper( target->name );
+ strupper( target->scope );
+
+ /* fudge... We're using a byte-by-byte compare, so we must be sure that
+ * unused space doesn't have garbage in it.
+ */
+ for( i = strlen( target->name ); i < sizeof( target->name ); i++ )
+ target->name[i] = '\0';
+ for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ )
+ target->scope[i] = '\0';
+ } /* upcase_name */
+
+/* ************************************************************************** **
+ * Add a new or overwrite an existing namelist entry.
+ * ************************************************************************** **
+ */
+static void update_name_in_namelist( struct subnet_record *subrec,
+ struct name_record *namerec )
+ {
+ struct name_record *oldrec = NULL;
+
+ (void)ubi_trInsert( subrec->namelist, namerec, &(namerec->name), &oldrec );
+ if( oldrec )
+ {
+ SAFE_FREE( oldrec->data.ip );
+ SAFE_FREE( oldrec );
+ }
+ } /* update_name_in_namelist */
+
+/* ************************************************************************** **
+ * Remove a name from the namelist.
+ * ************************************************************************** **
+ */
+void remove_name_from_namelist( struct subnet_record *subrec,
+ struct name_record *namerec )
+ {
+ (void)ubi_trRemove( subrec->namelist, namerec );
+
+ SAFE_FREE(namerec->data.ip);
+
+ ZERO_STRUCTP(namerec);
+ SAFE_FREE(namerec);
+
+ subrec->namelist_changed = True;
+ } /* remove_name_from_namelist */
+
+/* ************************************************************************** **
+ * Find a name in a subnet.
+ * ************************************************************************** **
+ */
+struct name_record *find_name_on_subnet( struct subnet_record *subrec,
+ struct nmb_name *nmbname,
+ BOOL self_only )
+ {
+ struct nmb_name uc_name[1];
+ struct name_record *name_ret;
+
+ upcase_name( uc_name, nmbname );
+ name_ret = (struct name_record *)ubi_trFind( subrec->namelist, uc_name );
+ if( name_ret )
+ {
+ /* Self names only - these include permanent names. */
+ if( self_only
+ && (name_ret->data.source != SELF_NAME)
+ && (name_ret->data.source != PERMANENT_NAME) )
+ {
+ DEBUG( 9,
+ ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
+ subrec->subnet_name, nmb_namestr(nmbname) ) );
+ return( NULL );
+ }
+ DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
+ subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
+ return( name_ret );
+ }
+ DEBUG( 9,
+ ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
+ subrec->subnet_name, nmb_namestr(nmbname) ) );
+ return( NULL );
+ } /* find_name_on_subnet */
+
+/* ************************************************************************** **
+ * Find a name over all known broadcast subnets.
+ * ************************************************************************** **
+ */
+struct name_record *find_name_for_remote_broadcast_subnet(
+ struct nmb_name *nmbname,
+ BOOL self_only )
+ {
+ struct subnet_record *subrec;
+ struct name_record *namerec = NULL;
+
+ for( subrec = FIRST_SUBNET;
+ subrec;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
+ {
+ if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) )
+ break;
+ }
+
+ return( namerec );
+ } /* find_name_for_remote_broadcast_subnet */
+
+/* ************************************************************************** **
+ * Update the ttl of an entry in a subnet name list.
+ * ************************************************************************** **
+ */
+void update_name_ttl( struct name_record *namerec, int ttl )
+{
+ time_t time_now = time(NULL);
+
+ if( namerec->data.death_time != PERMANENT_TTL )
+ namerec->data.death_time = time_now + ttl;
+
+ namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
+
+ namerec->subnet->namelist_changed = True;
+} /* update_name_ttl */
+
+/* ************************************************************************** **
+ * Add an entry to a subnet name list.
+ * ************************************************************************** **
+ */
+struct name_record *add_name_to_subnet( struct subnet_record *subrec,
+ char *name,
+ int type,
+ uint16 nb_flags,
+ int ttl,
+ enum name_source source,
+ int num_ips,
+ struct in_addr *iplist)
+{
+ struct name_record *namerec;
+ time_t time_now = time(NULL);
+
+ namerec = (struct name_record *)malloc( sizeof(*namerec) );
+ if( NULL == namerec )
+ {
+ DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
+ return( NULL );
+ }
+
+ memset( (char *)namerec, '\0', sizeof(*namerec) );
+ namerec->data.ip = (struct in_addr *)malloc( sizeof(struct in_addr)
+ * num_ips );
+ if( NULL == namerec->data.ip )
+ {
+ DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
+
+ ZERO_STRUCTP(namerec);
+ SAFE_FREE(namerec);
+ return NULL;
+ }
+
+ namerec->subnet = subrec;
+
+ make_nmb_name(&namerec->name, name, type);
+ upcase_name(&namerec->name, NULL );
+
+ /* Enter the name as active. */
+ namerec->data.nb_flags = nb_flags | NB_ACTIVE;
+
+ /* If it's our primary name, flag it as so. */
+ if( strequal( my_netbios_names[0], name ) )
+ namerec->data.nb_flags |= NB_PERM;
+
+ /* Copy the IPs. */
+ namerec->data.num_ips = num_ips;
+ memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) );
+
+ /* Data source. */
+ namerec->data.source = source;
+
+ /* Setup the death_time and refresh_time. */
+ if( ttl == PERMANENT_TTL )
+ namerec->data.death_time = PERMANENT_TTL;
+ else
+ namerec->data.death_time = time_now + ttl;
+
+ namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
+
+ /* Now add the record to the name list. */
+ update_name_in_namelist( subrec, namerec );
+
+ DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
+ttl=%d nb_flags=%2x to subnet %s\n",
+ nmb_namestr( &namerec->name ),
+ inet_ntoa( *iplist ),
+ ttl,
+ (unsigned int)nb_flags,
+ subrec->subnet_name ) );
+
+ subrec->namelist_changed = True;
+
+ return(namerec);
+}
+
+/*******************************************************************
+ Utility function automatically called when a name refresh or register
+ succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
+ it).
+ ******************************************************************/
+
+void standard_success_register(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, uint16 nb_flags, int ttl,
+ struct in_addr registered_ip)
+{
+ struct name_record *namerec;
+
+ namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
+ if( NULL == namerec )
+ (void)add_name_to_subnet( subrec, nmbname->name, nmbname->name_type,
+ nb_flags, ttl, SELF_NAME, 1, &registered_ip );
+ else
+ update_name_ttl( namerec, ttl );
+}
+
+/*******************************************************************
+ Utility function automatically called when a name refresh or register
+ fails. Note that this is only ever called on a broadcast subnet with
+ one IP address per name. This is why it can just delete the name
+ without enumerating the IP adresses. JRA.
+ ******************************************************************/
+
+void standard_fail_register( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *nmbname )
+{
+ struct name_record *namerec;
+
+ namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
+
+ DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
+on subnet %s\n",
+ nmb_namestr(nmbname), subrec->subnet_name) );
+
+ /* Remove the name from the subnet. */
+ if( namerec )
+ remove_name_from_namelist(subrec, namerec);
+}
+
+/*******************************************************************
+ Utility function to remove an IP address from a name record.
+ ******************************************************************/
+
+static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
+{
+ if( ind != namerec->data.num_ips )
+ memmove( (char *)(&namerec->data.ip[ind]),
+ (char *)(&namerec->data.ip[ind+1]),
+ ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
+
+ namerec->data.num_ips--;
+ namerec->subnet->namelist_changed = True;
+}
+
+/*******************************************************************
+ Utility function to check if an IP address exists in a name record.
+ ******************************************************************/
+
+BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
+{
+ int i;
+
+ for(i = 0; i < namerec->data.num_ips; i++)
+ if(ip_equal( namerec->data.ip[i], ip))
+ return True;
+
+ return False;
+}
+
+/*******************************************************************
+ Utility function to add an IP address to a name record.
+ ******************************************************************/
+
+void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip )
+{
+ struct in_addr *new_list;
+
+ /* Don't add one we already have. */
+ if( find_ip_in_name_record( namerec, new_ip ) )
+ return;
+
+ new_list = (struct in_addr *)malloc( (namerec->data.num_ips + 1)
+ * sizeof(struct in_addr) );
+ if( NULL == new_list )
+ {
+ DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
+ return;
+ }
+
+ memcpy( (char *)new_list,
+ (char *)namerec->data.ip,
+ namerec->data.num_ips * sizeof(struct in_addr) );
+ new_list[namerec->data.num_ips] = new_ip;
+
+ SAFE_FREE(namerec->data.ip);
+ namerec->data.ip = new_list;
+ namerec->data.num_ips += 1;
+
+ namerec->subnet->namelist_changed = True;
+}
+
+/*******************************************************************
+ Utility function to remove an IP address from a name record.
+ ******************************************************************/
+
+void remove_ip_from_name_record( struct name_record *namerec,
+ struct in_addr remove_ip )
+{
+ /* Try and find the requested ip address - remove it. */
+ int i;
+ int orig_num = namerec->data.num_ips;
+
+ for(i = 0; i < orig_num; i++)
+ if( ip_equal( remove_ip, namerec->data.ip[i]) )
+ {
+ remove_nth_ip_in_record( namerec, i);
+ break;
+ }
+}
+
+/*******************************************************************
+ Utility function that release_name callers can plug into as the
+ success function when a name release is successful. Used to save
+ duplication of success_function code.
+ ******************************************************************/
+
+void standard_success_release( struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr released_ip )
+{
+ struct name_record *namerec;
+
+ namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
+
+ if( namerec == NULL )
+ {
+ DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
+on subnet %s. Name was not found on subnet.\n",
+ nmb_namestr(nmbname),
+ inet_ntoa(released_ip),
+ subrec->subnet_name) );
+ return;
+ }
+ else
+ {
+ int orig_num = namerec->data.num_ips;
+
+ remove_ip_from_name_record( namerec, released_ip );
+
+ if( namerec->data.num_ips == orig_num )
+ DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
+on subnet %s. This ip is not known for this name.\n",
+ nmb_namestr(nmbname),
+ inet_ntoa(released_ip),
+ subrec->subnet_name ) );
+ }
+
+ if( namerec->data.num_ips == 0 )
+ remove_name_from_namelist( subrec, namerec );
+}
+
+/*******************************************************************
+ Expires old names in a subnet namelist.
+ ******************************************************************/
+
+void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
+{
+ struct name_record *namerec;
+ struct name_record *next_namerec;
+
+ for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = next_namerec )
+ {
+ next_namerec = (struct name_record *)ubi_trNext( namerec );
+ if( (namerec->data.death_time != PERMANENT_TTL)
+ && (namerec->data.death_time < t) )
+ {
+ if( namerec->data.source == SELF_NAME )
+ {
+ DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
+name %s\n",
+ subrec->subnet_name, nmb_namestr(&namerec->name) ) );
+ namerec->data.death_time += 300;
+ namerec->subnet->namelist_changed = True;
+ continue;
+ }
+ DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
+ subrec->subnet_name, nmb_namestr(&namerec->name)));
+
+ remove_name_from_namelist( subrec, namerec );
+ }
+ }
+}
+
+/*******************************************************************
+ Expires old names in all subnet namelists.
+ ******************************************************************/
+
+void expire_names(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for( subrec = FIRST_SUBNET;
+ subrec;
+ subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
+ {
+ expire_names_on_subnet( subrec, t );
+ }
+}
+
+/****************************************************************************
+ Add the magic samba names, useful for finding samba servers.
+ These go directly into the name list for a particular subnet,
+ without going through the normal registration process.
+ When adding them to the unicast subnet, add them as a list of
+ all broadcast subnet IP addresses.
+**************************************************************************/
+
+void add_samba_names_to_subnet( struct subnet_record *subrec )
+{
+ struct in_addr *iplist = &subrec->myip;
+ int num_ips = 1;
+
+ /* These names are added permanently (ttl of zero) and will NOT be
+ refreshed. */
+
+ if( (subrec == unicast_subnet)
+ || (subrec == wins_server_subnet)
+ || (subrec == remote_broadcast_subnet) )
+ {
+ struct subnet_record *bcast_subrecs;
+ int i;
+ /* Create an IP list containing all our known subnets. */
+
+ num_ips = iface_count();
+ iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) );
+ if( NULL == iplist )
+ {
+ DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
+ return;
+ }
+
+ for( bcast_subrecs = FIRST_SUBNET, i = 0;
+ bcast_subrecs;
+ bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ )
+ iplist[i] = bcast_subrecs->myip;
+
+ }
+
+ (void)add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ (void)add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ (void)add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+ (void)add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
+ PERMANENT_NAME, num_ips, iplist);
+
+ if(iplist != &subrec->myip)
+ SAFE_FREE(iplist);
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp)
+{
+ struct name_record *namerec;
+ char *src_type;
+ struct tm *tm;
+ int i;
+
+ x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
+ for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = (struct name_record *)ubi_trNext( namerec ) )
+ {
+ x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
+ switch(namerec->data.source)
+ {
+ case LMHOSTS_NAME:
+ src_type = "LMHOSTS_NAME";
+ break;
+ case WINS_PROXY_NAME:
+ src_type = "WINS_PROXY_NAME";
+ break;
+ case REGISTER_NAME:
+ src_type = "REGISTER_NAME";
+ break;
+ case SELF_NAME:
+ src_type = "SELF_NAME";
+ break;
+ case DNS_NAME:
+ src_type = "DNS_NAME";
+ break;
+ case DNSFAIL_NAME:
+ src_type = "DNSFAIL_NAME";
+ break;
+ case PERMANENT_NAME:
+ src_type = "PERMANENT_NAME";
+ break;
+ default:
+ src_type = "unknown!";
+ break;
+ }
+ x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
+
+ if(namerec->data.death_time != PERMANENT_TTL)
+ {
+ tm = LocalTime(&namerec->data.death_time);
+ x_fprintf(fp, "death_time = %s\t", asctime(tm));
+ }
+ else
+ x_fprintf(fp, "death_time = PERMANENT\t");
+
+ if(namerec->data.refresh_time != PERMANENT_TTL)
+ {
+ tm = LocalTime(&namerec->data.refresh_time);
+ x_fprintf(fp, "refresh_time = %s\n", asctime(tm));
+ }
+ else
+ x_fprintf(fp, "refresh_time = PERMANENT\n");
+
+ x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
+ for(i = 0; i < namerec->data.num_ips; i++)
+ x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
+
+ x_fprintf(fp, "\n\n");
+ }
+}
+
+/****************************************************************************
+ Dump the contents of the namelists on all the subnets (including unicast)
+ into a file. Initiated by SIGHUP - used to debug the state of the namelists.
+**************************************************************************/
+
+void dump_all_namelists(void)
+{
+ XFILE *fp;
+ struct subnet_record *subrec;
+
+ fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+ if (!fp)
+ {
+ DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
+ "namelist.debug",strerror(errno)));
+ return;
+ }
+
+ for( subrec = FIRST_SUBNET;
+ subrec;
+ subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
+ dump_subnet_namelist( subrec, fp );
+
+ if( !we_are_a_wins_client() )
+ dump_subnet_namelist( unicast_subnet, fp );
+
+ if( remote_broadcast_subnet->namelist != NULL )
+ dump_subnet_namelist( remote_broadcast_subnet, fp );
+
+ if( wins_server_subnet != NULL )
+ dump_subnet_namelist( wins_server_subnet, fp );
+ x_fclose( fp );
+}
diff --git a/source/nmbd/nmbd_namequery.c b/source/nmbd/nmbd_namequery.c
new file mode 100644
index 00000000000..9d2a7a48958
--- /dev/null
+++ b/source/nmbd/nmbd_namequery.c
@@ -0,0 +1,296 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a response packet when querying a name.
+****************************************************************************/
+
+static void query_name_response( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL success = False;
+ struct nmb_name *question_name =
+ &rrec->packet->packet.nmb.question.question_name;
+ struct in_addr answer_ip;
+
+ zero_ip(&answer_ip);
+
+ /* Ensure we don't retry the query but leave the response record cleanup
+ to the timeout code. We may get more answer responses in which case
+ we should mark the name in conflict.. */
+ rrec->repeat_count = 0;
+
+ if(rrec->num_msgs == 1)
+ {
+ /* This is the first response. */
+
+ if(nmb->header.opcode == NMB_WACK_OPCODE)
+ {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more query requests. */
+
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "query_name_response: " );
+ dbgtext( "WACK from WINS server %s ", inet_ntoa(p->ip) );
+ dbgtext( "in querying name %s ", nmb_namestr(question_name) );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ }
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ }
+ else if(nmb->header.rcode != 0)
+ {
+ success = False;
+
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
+ dbgtext( "- negative response from IP %s ", inet_ntoa(p->ip) );
+ dbgtext( "for name %s. ", nmb_namestr(question_name) );
+ dbgtext( "Error code was %d.\n", nmb->header.rcode );
+ }
+ }
+ else
+ {
+ success = True;
+
+ putip((char *)&answer_ip,&nmb->answers->rdata[2]);
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
+ dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
+ dbgtext( "for name %s. ", nmb_namestr(question_name) );
+ dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
+ }
+
+ /* Interestingly, we could add these names to our namelists, and
+ change nmbd to a model that checked its own name cache first,
+ before sending out a query. This is a task for another day, though.
+ */
+ }
+ }
+ else if( rrec->num_msgs > 1)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
+ dbgtext( "query_name_response: " );
+ dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
+ dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
+ dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
+ dbgtext( "was from IP %s, reporting", inet_ntoa(p->ip) );
+ dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
+ }
+
+ /* We have already called the success or fail function, so we
+ don't call again here. Leave the response record around in
+ case we get more responses. */
+
+ return;
+ }
+
+ if(success && rrec->success_fn)
+ (*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
+ else if( rrec->fail_fn)
+ (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
+
+}
+
+/****************************************************************************
+ Deal with a timeout when querying a name.
+****************************************************************************/
+
+static void query_name_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ /* We can only fail here, never succeed. */
+ BOOL failed = True;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+ if(rrec->num_msgs != 0)
+ {
+ /* We got at least one response, and have called the success/fail
+ function already. */
+
+ failed = False;
+ }
+
+ if(failed)
+ {
+ if( DEBUGLVL( 5 ) )
+ {
+ dbgtext( "query_name_timeout_response: No response to " );
+ dbgtext( "query for name %s ", nmb_namestr(question_name) );
+ dbgtext( "on subnet %s.\n", subrec->subnet_name );
+ }
+ if(rrec->fail_fn)
+ (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
+ }
+
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Lookup a name on our local namelists. We check the lmhosts file first. If the
+ name is not there we look for the name on the given subnet.
+****************************************************************************/
+
+static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
+ struct name_record **namerecp)
+{
+ struct name_record *namerec;
+
+ *namerecp = NULL;
+
+ if(find_name_in_lmhosts(nmbname, namerecp))
+ return True;
+
+ if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
+ return False;
+
+ if( NAME_IS_ACTIVE(namerec)
+ && ( (namerec->data.source == SELF_NAME)
+ || (namerec->data.source == LMHOSTS_NAME) ) )
+ {
+ *namerecp = namerec;
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Try and query for a name.
+****************************************************************************/
+
+BOOL query_name(struct subnet_record *subrec, char *name, int type,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct nmb_name nmbname;
+ struct name_record *namerec;
+
+ make_nmb_name(&nmbname, name, type);
+
+ /*
+ * We need to check our local namelists first.
+ * It may be an magic name, lmhosts name or just
+ * a name we have registered.
+ */
+
+ if(query_local_namelists(subrec, &nmbname, &namerec) == True)
+ {
+ struct res_rec rrec;
+ int i;
+
+ memset((char *)&rrec, '\0', sizeof(struct res_rec));
+
+ /* Fake up the needed res_rec just in case it's used. */
+ rrec.rr_name = nmbname;
+ rrec.rr_type = RR_TYPE_NB;
+ rrec.rr_class = RR_CLASS_IN;
+ rrec.ttl = PERMANENT_TTL;
+ rrec.rdlength = namerec->data.num_ips * 6;
+ if(rrec.rdlength > MAX_DGRAM_SIZE)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "query_name: nmbd internal error - " );
+ dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
+ dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
+ }
+ return False;
+ }
+
+ for( i = 0; i < namerec->data.num_ips; i++)
+ {
+ set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
+ putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
+ }
+
+ /* Call the success function directly. */
+ if(success_fn)
+ (*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
+ return False;
+ }
+
+ if(queue_query_name( subrec,
+ query_name_response,
+ query_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "query_name: Failed to send packet " );
+ dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
+ }
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Try and query for a name from nmbd acting as a WINS server.
+****************************************************************************/
+
+BOOL query_name_from_wins_server(struct in_addr ip_to,
+ char *name, int type,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, name, type);
+
+ if(queue_query_name_from_wins_server( ip_to,
+ query_name_response,
+ query_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname) == NULL)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "query_name_from_wins_server: Failed to send packet " );
+ dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
+ }
+ return True;
+ }
+ return False;
+}
diff --git a/source/nmbd/nmbd_nameregister.c b/source/nmbd/nmbd_nameregister.c
new file mode 100644
index 00000000000..c3361cec60b
--- /dev/null
+++ b/source/nmbd/nmbd_nameregister.c
@@ -0,0 +1,400 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern fstring global_myworkgroup;
+
+/****************************************************************************
+ Deal with a response packet when registering one of our names.
+****************************************************************************/
+
+static void register_name_response(struct subnet_record *subrec,
+ struct response_record *rrec, struct packet_struct *p)
+{
+ /*
+ * If we are registering broadcast, then getting a response is an
+ * error - we do not have the name. If we are registering unicast,
+ * then we expect to get a response.
+ */
+
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ BOOL success = True;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+ int ttl = 0;
+ uint16 nb_flags = 0;
+ struct in_addr registered_ip;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!question_name || !answer_name)
+ {
+ DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
+ question_name ? "question_name" : "answer_name" ));
+ return;
+ }
+
+ if(!nmb_name_equal(question_name, answer_name))
+ {
+ DEBUG(0,("register_name_response: Answer name %s differs from question \
+name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ if(bcast)
+ {
+ /*
+ * Special hack to cope with old Samba nmbd's.
+ * Earlier versions of Samba (up to 1.9.16p11) respond
+ * to a broadcast name registration of WORKGROUP<1b> when
+ * they should not. Hence, until these versions are gone,
+ * we should treat such errors as success for this particular
+ * case only. jallison@whistle.com.
+ */
+
+#if 1 /* OLD_SAMBA_SERVER_HACK */
+ if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) &&
+ (answer_name->name_type == 0x1b))
+ {
+ /* Pretend we did not get this. */
+ rrec->num_msgs--;
+
+ DEBUG(5,("register_name_response: Ignoring broadcast response to \
+registration of name %s due to old Samba server bug.\n", nmb_namestr(answer_name)));
+ return;
+ }
+#endif /* OLD_SAMBA_SERVER_HACK */
+
+ /* Someone else has the name. Log the problem. */
+ DEBUG(1,("register_name_response: Failed to register \
+name %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n",
+ nmb_namestr(answer_name),
+ subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
+ success = False;
+ }
+ else
+ {
+ /* Unicast - check to see if the response allows us to have the name. */
+ if(nmb->header.rcode != 0)
+ {
+ /* Error code - we didn't get the name. */
+ success = False;
+
+ DEBUG(0,("register_name_response: server at IP %s rejected our \
+name registration of %s with error code %d.\n", inet_ntoa(p->ip),
+ nmb_namestr(answer_name), nmb->header.rcode));
+
+ }
+ else if(nmb->header.opcode == NMB_WACK_OPCODE)
+ {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more register requests. */
+
+ DEBUG(5,("register_name_response: WACK from WINS server %s in registering \
+name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ }
+ else
+ {
+ success = True;
+ /* Get the data we need to pass to the success function. */
+ nb_flags = get_nb_flags(nmb->answers->rdata);
+ putip((char*)&registered_ip,&nmb->answers->rdata[2]);
+ ttl = nmb->answers->ttl;
+ }
+ }
+
+ DEBUG(5,("register_name_response: %s in registering name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
+
+ if(success)
+ {
+ /* Enter the registered name into the subnet name database before calling
+ the success function. */
+ standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
+ }
+ else
+ {
+ if( rrec->fail_fn)
+ (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ /* Remove the name. */
+ standard_fail_register( subrec, rrec, question_name);
+ }
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when registering one of our names.
+****************************************************************************/
+
+static void register_name_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ /*
+ * If we are registering unicast, then NOT getting a response is an
+ * error - we do not have the name. If we are registering broadcast,
+ * then we don't expect to get a response.
+ */
+
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ BOOL bcast = sent_nmb->header.nm_flags.bcast;
+ BOOL success = False;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+ uint16 nb_flags = 0;
+ int ttl = 0;
+ struct in_addr registered_ip;
+
+ if(bcast)
+ {
+ if(rrec->num_msgs == 0)
+ {
+ /* Not receiving a message is success for broadcast registration. */
+ success = True;
+
+ /* Pull the success values from the original request packet. */
+ nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ ttl = sent_nmb->additional->ttl;
+ putip(&registered_ip,&sent_nmb->additional->rdata[2]);
+ }
+ }
+ else
+ {
+ /* Unicast - if no responses then it's an error. */
+ if(rrec->num_msgs == 0)
+ {
+ DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \
+responding.\n", inet_ntoa(rrec->packet->ip)));
+
+ /* Keep trying to contact the WINS server periodically. This allows
+ us to work correctly if the WINS server is down temporarily when
+ we come up. */
+
+ /* Reset the number of attempts to zero and double the interval between
+ retries. Max out at 5 minutes. */
+ rrec->repeat_count = 3;
+ rrec->repeat_interval *= 2;
+ if(rrec->repeat_interval > (5 * 60))
+ rrec->repeat_interval = (5 * 60);
+ rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+ rrec->in_expiration_processing = False;
+
+ DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+ (int)rrec->repeat_interval));
+ return; /* Don't remove the response record. */
+ }
+ }
+
+ DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
+ if(success)
+ {
+ /* Enter the registered name into the subnet name database before calling
+ the success function. */
+ standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+ }
+ else
+ {
+ if( rrec->fail_fn)
+ (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ /* Remove the name. */
+ standard_fail_register( subrec, rrec, question_name);
+ }
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and register one of our names on the unicast subnet - multihomed.
+****************************************************************************/
+
+static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ /*
+ If we are adding a group name, we just send multiple
+ register name packets to the WINS server (this is an
+ internet group name.
+
+ If we are adding a unique name, We need first to add
+ our names to the unicast subnet namelist. This is
+ because when a WINS server receives a multihomed
+ registration request, the first thing it does is to
+ send a name query to the registering machine, to see
+ if it has put the name in it's local namelist.
+ We need the name there so the query response code in
+ nmbd_incomingrequests.c will find it.
+
+ We are adding this name prematurely (we don't really
+ have it yet), but as this is on the unicast subnet
+ only we will get away with this (only the WINS server
+ will ever query names from us on this subnet).
+ */
+
+ int num_ips=0;
+ int i;
+ struct in_addr *ip_list = NULL;
+ struct subnet_record *subrec;
+
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
+ num_ips++;
+
+ if((ip_list = (struct in_addr *)malloc(num_ips * sizeof(struct in_addr)))==NULL)
+ {
+ DEBUG(0,("multihomed_register_name: malloc fail !\n"));
+ return True;
+ }
+
+ for( subrec = FIRST_SUBNET, i = 0;
+ subrec;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ )
+ ip_list[i] = subrec->myip;
+
+ (void)add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
+ nb_flags, lp_max_ttl(), SELF_NAME,
+ num_ips, ip_list);
+
+ /* Now try and register the name, num_ips times. On the last time use
+ the given success and fail functions. */
+
+ for( i = 0; i < num_ips; i++)
+ {
+ if(queue_register_multihomed_name( unicast_subnet,
+ register_name_response,
+ register_name_timeout_response,
+ (i == num_ips - 1) ? success_fn : NULL,
+ (i == num_ips - 1) ? fail_fn : NULL,
+ (i == num_ips - 1) ? userdata : NULL,
+ nmbname,
+ nb_flags,
+ ip_list[i]) == NULL)
+ {
+ DEBUG(0,("multihomed_register_name: Failed to send packet trying to \
+register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip_list[i]) ));
+
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ }
+
+ SAFE_FREE(ip_list);
+
+ return False;
+}
+
+/****************************************************************************
+ Try and register one of our names.
+****************************************************************************/
+
+BOOL register_name(struct subnet_record *subrec,
+ char *name, int type, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, name, type);
+
+ /* Always set the NB_ACTIVE flag on the name we are
+ registering. Doesn't make sense without it.
+ */
+
+ nb_flags |= NB_ACTIVE;
+
+ /* If this is the unicast subnet, and we are a multi-homed
+ host, then register a multi-homed name. */
+
+ if( (subrec == unicast_subnet) && we_are_multihomed())
+ return multihomed_register_name(&nmbname, nb_flags,
+ success_fn, fail_fn,
+ userdata);
+
+ if(queue_register_name( subrec,
+ register_name_response,
+ register_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname,
+ nb_flags) == NULL)
+ {
+ DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
+ nmb_namestr(&nmbname)));
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Try and refresh one of our names.
+****************************************************************************/
+
+BOOL refresh_name(struct subnet_record *subrec, struct name_record *namerec,
+ refresh_name_success_function success_fn,
+ refresh_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ int i;
+
+ /*
+ * Go through and refresh the name for all known ip addresses.
+ * Only call the success/fail function on the last one (it should
+ * only be done once).
+ */
+
+ for( i = 0; i < namerec->data.num_ips; i++)
+ {
+ if(queue_refresh_name( subrec,
+ register_name_response,
+ register_name_timeout_response,
+ (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
+ namerec,
+ namerec->data.ip[i]) == NULL)
+ {
+ DEBUG(0,("refresh_name: Failed to send packet trying to refresh name %s\n",
+ nmb_namestr(&namerec->name)));
+ return True;
+ }
+ }
+ return False;
+}
diff --git a/source/nmbd/nmbd_namerelease.c b/source/nmbd/nmbd_namerelease.c
new file mode 100644
index 00000000000..30a9d165612
--- /dev/null
+++ b/source/nmbd/nmbd_namerelease.c
@@ -0,0 +1,234 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a response packet when releasing one of our names.
+****************************************************************************/
+
+static void release_name_response(struct subnet_record *subrec,
+ struct response_record *rrec, struct packet_struct *p)
+{
+ /*
+ * If we are releasing broadcast, then getting a response is an
+ * error. If we are releasing unicast, then we expect to get a response.
+ */
+
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ BOOL success = True;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+ struct in_addr released_ip;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!nmb_name_equal(question_name, answer_name))
+ {
+ DEBUG(0,("release_name_response: Answer name %s differs from question \
+name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ if(bcast)
+ {
+ /* Someone sent a response. This shouldn't happen/ */
+ DEBUG(1,("release_name_response: A response for releasing name %s was received on a \
+broadcast subnet %s. This should not happen !\n", nmb_namestr(answer_name), subrec->subnet_name));
+ return;
+ }
+ else
+ {
+ /* Unicast - check to see if the response allows us to release the name. */
+ if(nmb->header.rcode != 0)
+ {
+ /* Error code - we were told not to release the name ! What now ! */
+ success = False;
+
+ DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
+name release of name %s with error code %d.\n", inet_ntoa(p->ip),
+ nmb_namestr(answer_name), nmb->header.rcode));
+
+ }
+ else if(nmb->header.opcode == NMB_WACK_OPCODE)
+ {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more release requests. */
+
+ DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
+name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ }
+ }
+
+ DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
+
+ if(success)
+ {
+ putip((char*)&released_ip ,&nmb->answers->rdata[2]);
+
+ if(rrec->success_fn)
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
+ standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
+ }
+ else
+ {
+ /* We have no standard_fail_release - maybe we should add one ? */
+ if(rrec->fail_fn)
+ (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name);
+ }
+
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when releasing one of our names.
+****************************************************************************/
+
+static void release_name_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ /*
+ * If we are releasing unicast, then NOT getting a response is an
+ * error - we could not release the name. If we are releasing broadcast,
+ * then we don't expect to get a response.
+ */
+
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ BOOL bcast = sent_nmb->header.nm_flags.bcast;
+ BOOL success = False;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+ struct in_addr released_ip;
+
+ if(bcast)
+ {
+ if(rrec->num_msgs == 0)
+ {
+ /* Not receiving a message is success for broadcast release. */
+ success = True;
+
+ /* Get the ip address we were trying to release. */
+ putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
+ }
+ }
+ else
+ {
+ /* Unicast - if no responses then it's an error. */
+ if(rrec->num_msgs == 0)
+ {
+ DEBUG(2,("release_name_timeout_response: WINS server at address %s is not \
+responding.\n", inet_ntoa(rrec->packet->ip)));
+
+ /* Keep trying to contact the WINS server periodically. This allows
+ us to work correctly if the WINS server is down temporarily when
+ we want to delete the name. */
+
+ /* Reset the number of attempts to zero and double the interval between
+ retries. Max out at 5 minutes. */
+ rrec->repeat_count = 3;
+ rrec->repeat_interval *= 2;
+ if(rrec->repeat_interval > (5 * 60))
+ rrec->repeat_interval = (5 * 60);
+ rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+
+ DEBUG(5,("release_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+ (int)rrec->repeat_interval));
+ return; /* Don't remove the response record. */
+ }
+ }
+
+ DEBUG(5,("release_name_timeout_response: %s in releasing name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
+
+ if(success && rrec->success_fn)
+ {
+ if(rrec->success_fn)
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
+ standard_success_release( subrec, rrec->userdata, question_name, released_ip);
+ }
+ else
+ {
+ /* We have no standard_fail_release - maybe we should add one ? */
+ if( rrec->fail_fn)
+ (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ }
+
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and release one of our names.
+****************************************************************************/
+
+BOOL release_name(struct subnet_record *subrec, struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ int i;
+
+ /* Ensure it's a SELF name, and in the ACTIVE state. */
+ if((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec))
+ {
+ DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
+ nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source));
+ return True;
+ }
+
+ /* Set the name into the deregistering state. */
+ namerec->data.nb_flags |= NB_DEREG;
+
+ /*
+ * Go through and release the name for all known ip addresses.
+ * Only call the success/fail function on the last one (it should
+ * only be done once).
+ */
+
+ for( i = 0; i < namerec->data.num_ips; i++)
+ {
+ if(queue_release_name( subrec,
+ release_name_response,
+ release_name_timeout_response,
+ (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
+ &namerec->name,
+ namerec->data.nb_flags,
+ namerec->data.ip[i]) == NULL)
+ {
+ DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+ nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
+ return True;
+ }
+ }
+ return False;
+}
diff --git a/source/nmbd/nmbd_nodestatus.c b/source/nmbd/nmbd_nodestatus.c
new file mode 100644
index 00000000000..eeb532d4109
--- /dev/null
+++ b/source/nmbd/nmbd_nodestatus.c
@@ -0,0 +1,95 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Deal with a successful node status response.
+****************************************************************************/
+static void node_status_response(struct subnet_record *subrec,
+ struct response_record *rrec, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!nmb_name_equal(question_name, answer_name))
+ {
+ DEBUG(0,("node_status_response: Answer name %s differs from question \
+name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
+ nmb_namestr(answer_name), subrec->subnet_name));
+
+ /* Just send the whole answer resource record for the success function
+ to parse. */
+ if(rrec->success_fn)
+ (*(node_status_success_function)rrec->success_fn)(subrec, rrec->userdata, nmb->answers, p->ip);
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Deal with a timeout when requesting a node status.
+****************************************************************************/
+static void node_status_timeout_response(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+
+ DEBUG(5,("node_status_timeout_response: failed to get node status from name %s on subnet %s\n",
+ nmb_namestr(question_name), subrec->subnet_name));
+
+ if( rrec->fail_fn)
+ (*rrec->fail_fn)(subrec, rrec);
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
+
+/****************************************************************************
+ Try and do a node status to a name - given the name & IP address.
+****************************************************************************/
+
+BOOL node_status(struct subnet_record *subrec, struct nmb_name *nmbname,
+ struct in_addr send_ip, node_status_success_function success_fn,
+ node_status_fail_function fail_fn, struct userdata_struct *userdata)
+{
+ if(queue_node_status( subrec,
+ node_status_response, node_status_timeout_response,
+ success_fn, fail_fn, userdata, nmbname, send_ip)==NULL)
+ {
+ DEBUG(0,("node_status: Failed to send packet trying to get node status for \
+name %s, IP address %s\n", nmb_namestr(nmbname), inet_ntoa(send_ip)));
+ return True;
+ }
+ return False;
+}
diff --git a/source/nmbd/nmbd_packets.c b/source/nmbd/nmbd_packets.c
new file mode 100644
index 00000000000..ace4ddfa25c
--- /dev/null
+++ b/source/nmbd/nmbd_packets.c
@@ -0,0 +1,1979 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int num_response_packets;
+
+extern struct in_addr loopback_ip;
+
+static void queue_packet(struct packet_struct *packet);
+
+BOOL rescan_listen_set = False;
+
+
+/*******************************************************************
+ The global packet linked-list. Incoming entries are
+ added to the end of this list. It is supposed to remain fairly
+ short so we won't bother with an end pointer.
+******************************************************************/
+
+static struct packet_struct *packet_queue = NULL;
+
+/***************************************************************************
+Utility function to find the specific fd to send a packet out on.
+**************************************************************************/
+
+static int find_subnet_fd_for_address( struct in_addr local_ip )
+{
+ struct subnet_record *subrec;
+
+ for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ if(ip_equal(local_ip, subrec->myip))
+ return subrec->nmb_sock;
+
+ return ClientNMB;
+}
+
+/***************************************************************************
+Utility function to find the specific fd to send a mailslot packet out on.
+**************************************************************************/
+
+static int find_subnet_mailslot_fd_for_address( struct in_addr local_ip )
+{
+ struct subnet_record *subrec;
+
+ for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ if(ip_equal(local_ip, subrec->myip))
+ return subrec->dgram_sock;
+
+ return ClientDGRAM;
+}
+
+/***************************************************************************
+Get/Set problematic nb_flags as network byte order 16 bit int.
+**************************************************************************/
+
+uint16 get_nb_flags(char *buf)
+{
+ return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);
+}
+
+void set_nb_flags(char *buf, uint16 nb_flags)
+{
+ *buf++ = ((nb_flags & NB_FLGMSK) & 0xFF);
+ *buf = '\0';
+}
+
+/***************************************************************************
+Dumps out the browse packet data.
+**************************************************************************/
+
+static void debug_browse_data(char *outbuf, int len)
+{
+ int i,j;
+
+ DEBUG( 4, ( "debug_browse_data():\n" ) );
+ for (i = 0; i < len; i+= 16)
+ {
+ DEBUGADD( 4, ( "%3x char ", i ) );
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x;
+ if (i+j >= len)
+ break;
+
+ x = outbuf[i+j];
+ if (x < 32 || x > 127)
+ x = '.';
+
+ DEBUGADD( 4, ( "%c", x ) );
+ }
+
+ DEBUGADD( 4, ( "%*s hex", 16-j, "" ) );
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= len)
+ break;
+ DEBUGADD( 4, ( " %02x", (unsigned char)outbuf[i+j] ) );
+ }
+
+ DEBUGADD( 4, ("\n") );
+ }
+}
+
+/***************************************************************************
+ Generates the unique transaction identifier
+**************************************************************************/
+
+static uint16 name_trn_id=0;
+
+static uint16 generate_name_trn_id(void)
+{
+
+ if (!name_trn_id)
+ {
+ name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ }
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+ return name_trn_id;
+}
+
+/***************************************************************************
+ Either loops back or sends out a completed NetBIOS packet.
+**************************************************************************/
+
+static BOOL send_netbios_packet(struct packet_struct *p)
+{
+ BOOL loopback_this_packet = False;
+
+ /* Check if we are sending to or from ourselves as a WINS server. */
+ if(ismyip(p->ip) && (p->port == global_nmb_port))
+ loopback_this_packet = True;
+
+ if(loopback_this_packet)
+ {
+ struct packet_struct *lo_packet = NULL;
+ DEBUG(5,("send_netbios_packet: sending packet to ourselves.\n"));
+ if((lo_packet = copy_packet(p)) == NULL)
+ return False;
+ queue_packet(lo_packet);
+ }
+ else if (!send_packet(p))
+ {
+ DEBUG(0,("send_netbios_packet: send_packet() to IP %s port %d failed\n",
+ inet_ntoa(p->ip),p->port));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ Sets up the common elements of an outgoing NetBIOS packet.
+
+ Note: do not attempt to rationalise whether rec_des should be set or not
+ in a particular situation. Just follow rfc_1002 or look at examples from WinXX.
+ It does NOT follow the rule that requests to the wins server always have
+ rec_des true. See for example name releases and refreshes
+**************************************************************************/
+
+static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
+ BOOL bcast, BOOL rec_des,
+ struct in_addr to_ip)
+{
+ struct packet_struct *packet = NULL;
+ struct nmb_packet *nmb = NULL;
+
+ /* Allocate the packet_struct we will return. */
+ if((packet = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
+ return NULL;
+ }
+
+ memset((char *)packet,'\0',sizeof(*packet));
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.name_trn_id = generate_name_trn_id();
+ nmb->header.response = False;
+ nmb->header.nm_flags.recursion_desired = rec_des;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.nm_flags.bcast = bcast;
+
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+
+ nmb->question.question_name = *nmbname;
+ nmb->question.question_type = QUESTION_TYPE_NB_QUERY;
+ nmb->question.question_class = QUESTION_CLASS_IN;
+
+ packet->ip = to_ip;
+ packet->port = NMB_PORT;
+ packet->fd = ClientNMB;
+ packet->timestamp = time(NULL);
+ packet->packet_type = NMB_PACKET;
+ packet->locked = False;
+
+ return packet; /* Caller must free. */
+}
+
+/***************************************************************************
+ Sets up the common elements of register, refresh or release packet.
+**************************************************************************/
+
+static BOOL create_and_init_additional_record(struct packet_struct *packet,
+ uint16 nb_flags,
+ struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL)
+ {
+ DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+ return False;
+ }
+
+ memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ set_nb_flags(nmb->additional->rdata,nb_flags);
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], register_ip);
+
+ /* Ensure that we send out the file descriptor to give us the
+ the specific source address we are registering as our
+ IP source address. */
+
+ packet->fd = find_subnet_fd_for_address( *register_ip );
+
+ return True;
+}
+
+/***************************************************************************
+ Sends out a name query.
+**************************************************************************/
+
+static BOOL initiate_name_query_packet( struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = NULL;
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ DEBUG(4,("initiate_name_query_packet: sending query for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name query - from a WINS server.
+**************************************************************************/
+
+static BOOL initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = NULL;
+
+ nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ DEBUG(4,("initiate_name_query_packet_from_wins_server: sending query for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name register.
+**************************************************************************/
+
+static BOOL initiate_name_register_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_REG_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_register_packet: sending registration for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a multihomed name register.
+**************************************************************************/
+
+static BOOL initiate_multihomed_name_register_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *register_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+ fstring second_ip_buf;
+
+ fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
+
+ nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+for name %s IP %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+ BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name refresh.
+**************************************************************************/
+
+static BOOL initiate_name_refresh_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *refresh_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_REFRESH_OPCODE_8;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ if(create_and_init_additional_record(packet, nb_flags, refresh_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_refresh_packet: sending refresh for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a name release.
+**************************************************************************/
+
+static BOOL initiate_name_release_packet( struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *release_ip)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_RELEASE_OPCODE;
+ nmb->header.arcount = 1;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ if(create_and_init_additional_record(packet, nb_flags, release_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_name_release_packet: sending release for name %s (bcast=%s) to IP %s\n",
+ nmb_namestr(&nmb->additional->rr_name),
+ BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/***************************************************************************
+ Sends out a node status.
+**************************************************************************/
+
+static BOOL initiate_node_status_packet( struct packet_struct *packet )
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+ nmb->header.arcount = 0;
+
+ nmb->header.nm_flags.recursion_desired = False;
+
+ nmb->question.question_type = QUESTION_TYPE_NB_STATUS;
+
+ DEBUG(4,("initiate_node_status_packet: sending node status request for name %s to IP %s\n",
+ nmb_namestr(&nmb->question.question_name),
+ inet_ntoa(packet->ip)));
+
+ return send_netbios_packet( packet );
+}
+
+/****************************************************************************
+ Simplification functions for queuing standard packets.
+ These should be the only publicly callable functions for sending
+ out packets.
+****************************************************************************/
+
+/****************************************************************************
+ Assertion - we should never be sending nmbd packets on the remote
+ broadcast subnet.
+****************************************************************************/
+
+static BOOL assert_check_subnet(struct subnet_record *subrec)
+{
+ if( subrec == remote_broadcast_subnet)
+ {
+ DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
+This is a bug.\n"));
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Queue a register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_register_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ /* note that all name registration requests have RD set (rfc1002 -
+ section 4.2.2 */
+ if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), True,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ if(initiate_name_register_packet( p, nb_flags,
+ iface_ip(subrec->bcast_ip)) == False)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a multihomed register name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr register_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ BOOL ret;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet)
+ {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+ return NULL;
+ }
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, False, True,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ if (nb_flags & NB_GROUP)
+ ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+ else
+ ret = initiate_multihomed_name_register_packet( p, nb_flags, &register_ip);
+
+ if(ret == False)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a release name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_release_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr release_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ if(initiate_name_release_packet( p, nb_flags, &release_ip) == False)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ /*
+ * For a broadcast release packet, only send once.
+ * This will cause us to remove the name asap. JRA.
+ */
+
+ if (subrec != unicast_subnet) {
+ rrec->repeat_count = 0;
+ rrec->repeat_time = 0;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_refresh_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ refresh_name_success_function success_fn,
+ refresh_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct name_record *namerec,
+ struct in_addr refresh_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(&namerec->name, (subrec != unicast_subnet), False,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ if( !initiate_name_refresh_packet( p, namerec->data.nb_flags, &refresh_ip ) )
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to the broadcast address of a subnet.
+****************************************************************************/
+
+struct response_record *queue_query_name( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname,
+ (subrec != unicast_subnet),
+ (subrec == unicast_subnet),
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ if(lp_bind_interfaces_only()) {
+ int i;
+
+ DEBUG(10,("queue_query_name: bind_interfaces_only is set, looking for suitable source IP\n"));
+ for(i = 0; i < iface_count(); i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if(ifip == NULL) {
+ DEBUG(0,("queue_query_name: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+
+ if (ip_equal(*ifip,loopback_ip)) {
+ DEBUG(5,("queue_query_name: ignoring loopback interface (%d)\n", i));
+ continue;
+ }
+
+ DEBUG(10,("queue_query_name: using source IP %s\n",inet_ntoa(*ifip)));
+ p->fd = find_subnet_fd_for_address( *ifip );
+ break;
+ }
+ }
+
+ if(initiate_name_query_packet( p ) == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a query name packet to a given address from the WINS subnet.
+****************************************************************************/
+
+struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ query_name_success_function success_fn,
+ query_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, False, to_ip)) == NULL)
+ return NULL;
+
+ if(initiate_name_query_packet_from_wins_server( p ) == False)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(wins_server_subnet, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Queue a node status packet to a given name and address.
+****************************************************************************/
+
+struct response_record *queue_node_status( struct subnet_record *subrec,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ node_status_success_function success_fn,
+ node_status_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr send_ip)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet)
+ {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
+unicast subnet. subnet is %s\n.", subrec->subnet_name ));
+ return NULL;
+ }
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, False, False,
+ send_ip)) == NULL)
+ return NULL;
+
+ if(initiate_node_status_packet(p) == False)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL)
+ {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
+}
+
+/****************************************************************************
+ Reply to a netbios name packet. see rfc1002.txt
+****************************************************************************/
+
+void reply_netbios_packet(struct packet_struct *orig_packet,
+ int rcode, enum netbios_reply_type_code rcv_code, int opcode,
+ int ttl, char *data,int len)
+{
+ struct packet_struct packet;
+ struct nmb_packet *nmb = NULL;
+ struct res_rec answers;
+ struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
+ BOOL loopback_this_packet = False;
+ char *packet_type = "unknown";
+
+ /* Check if we are sending to or from ourselves. */
+ if(ismyip(orig_packet->ip) && (orig_packet->port == global_nmb_port))
+ loopback_this_packet = True;
+
+ nmb = &packet.packet.nmb;
+
+ /* Do a partial copy of the packet. We clear the locked flag and
+ the resource record pointers. */
+ packet = *orig_packet; /* Full structure copy. */
+ packet.locked = False;
+ nmb->answers = NULL;
+ nmb->nsrecs = NULL;
+ nmb->additional = NULL;
+
+ switch (rcv_code)
+ {
+ case NMB_STATUS:
+ {
+ packet_type = "nmb_status";
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.recursion_available = False;
+ break;
+ }
+ case NMB_QUERY:
+ {
+ packet_type = "nmb_query";
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.recursion_available = True;
+ break;
+ }
+ case NMB_REG:
+ case NMB_REG_REFRESH:
+ {
+ packet_type = "nmb_reg";
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.recursion_available = True;
+ break;
+ }
+ case NMB_REL:
+ {
+ packet_type = "nmb_rel";
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.recursion_available = False;
+ break;
+ }
+ case NMB_WAIT_ACK:
+ {
+ packet_type = "nmb_wack";
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.recursion_available = False;
+ break;
+ }
+ case WINS_REG:
+ {
+ packet_type = "wins_reg";
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.recursion_available = True;
+ break;
+ }
+ case WINS_QUERY:
+ {
+ packet_type = "wins_query";
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.recursion_available = True;
+ break;
+ }
+
+ default:
+ {
+ DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
+ packet_type, nmb_namestr(&orig_nmb->question.question_name),
+ inet_ntoa(packet.ip)));
+
+ return;
+ }
+ }
+
+ DEBUG(4,("reply_netbios_packet: sending a reply of packet type: %s %s to ip %s \
+for id %hu\n",
+ packet_type, nmb_namestr(&orig_nmb->question.question_name),
+ inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
+
+ nmb->header.name_trn_id = orig_nmb->header.name_trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.rcode = rcode;
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ memset((char*)&nmb->question,'\0',sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = orig_nmb->question.question_name;
+ nmb->answers->rr_type = orig_nmb->question.question_type;
+ nmb->answers->rr_class = orig_nmb->question.question_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ packet.packet_type = NMB_PACKET;
+ /* Ensure we send out on the same fd that the original
+ packet came in on to give the correct source IP address. */
+ packet.fd = orig_packet->fd;
+ packet.timestamp = time(NULL);
+
+ debug_nmb_packet(&packet);
+
+ if(loopback_this_packet)
+ {
+ struct packet_struct *lo_packet;
+ DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
+ if((lo_packet = copy_packet(&packet)) == NULL)
+ return;
+ queue_packet(lo_packet);
+ }
+ else if (!send_packet(&packet))
+ {
+ DEBUG(0,("reply_netbios_packet: send_packet to IP %s port %d failed\n",
+ inet_ntoa(packet.ip),packet.port));
+ }
+}
+
+/*******************************************************************
+ Queue a packet into a packet queue
+******************************************************************/
+static void queue_packet(struct packet_struct *packet)
+{
+ struct packet_struct *p;
+
+ if (!packet_queue)
+ {
+ packet->prev = NULL;
+ packet->next = NULL;
+ packet_queue = packet;
+ return;
+ }
+
+ /* find the bottom */
+ for (p=packet_queue;p->next;p=p->next)
+ ;
+
+ p->next = packet;
+ packet->next = NULL;
+ packet->prev = p;
+}
+
+/****************************************************************************
+ Try and find a matching subnet record for a datagram port 138 packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_dgram_browse_packet(struct packet_struct *p)
+{
+ struct subnet_record *subrec;
+
+ /* Go through all the broadcast subnets and see if the mask matches. */
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ return subrec;
+ }
+
+ /* If the subnet record is the remote announce broadcast subnet,
+ hack it here to be the first subnet. This is really gross and
+ is needed due to people turning on port 137/138 broadcast
+ forwarding on their routers. May fire and brimstone rain
+ down upon them...
+ */
+
+ return FIRST_SUBNET;
+}
+
+/****************************************************************************
+Dispatch a browse frame from port 138 to the correct processing function.
+****************************************************************************/
+static void process_browse_packet(struct packet_struct *p, char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int command = CVAL(buf,0);
+ struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
+ extern pstring global_scope;
+
+ /* Drop the packet if it's a different NetBIOS scope, or
+ the source is from one of our names. */
+
+ if (!strequal(dgram->dest_name.scope, global_scope))
+ {
+ DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+ return;
+ }
+
+ if (is_myname(dgram->source_name.name))
+ {
+ DEBUG(0,("process_browse_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+ return;
+ }
+
+ switch (command)
+ {
+ case ANN_HostAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_host_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_DomainAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_workgroup_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_LocalMasterAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_local_master_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_AnnouncementRequest:
+ {
+ debug_browse_data(buf, len);
+ process_announce_request(subrec, p, buf+1);
+ break;
+ }
+ case ANN_Election:
+ {
+ debug_browse_data(buf, len);
+ process_election(subrec, p, buf+1);
+ break;
+ }
+ case ANN_GetBackupListReq:
+ {
+ debug_browse_data(buf, len);
+ process_get_backup_list_request(subrec, p, buf+1);
+ break;
+ }
+ case ANN_GetBackupListResp:
+ {
+ debug_browse_data(buf, len);
+ /* We never send ANN_GetBackupListReq so we
+ should never get these. */
+ DEBUG(0,("process_browse_packet: Discarding GetBackupListResponse \
+packet from %s IP %s\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip)));
+ break;
+ }
+ case ANN_ResetBrowserState:
+ {
+ debug_browse_data(buf, len);
+ process_reset_browser(subrec, p, buf+1);
+ break;
+ }
+ case ANN_MasterAnnouncement:
+ {
+ /* Master browser datagrams must be processed
+ on the unicast subnet. */
+ subrec = unicast_subnet;
+
+ debug_browse_data(buf, len);
+ process_master_browser_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_BecomeBackup:
+ {
+ /*
+ * We don't currently implement this. Log it just in case.
+ */
+ debug_browse_data(buf, len);
+ DEBUG(10,("process_browse_packet: On subnet %s ignoring browse packet \
+command ANN_BecomeBackup from %s IP %s to %s\n",
+ subrec->subnet_name, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ break;
+ }
+ default:
+ {
+ debug_browse_data(buf, len);
+ DEBUG(0,("process_browse_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n",
+ subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ }
+ }
+}
+
+/****************************************************************************
+ Dispatch a LanMan browse frame from port 138 to the correct processing function.
+****************************************************************************/
+static void process_lanman_packet(struct packet_struct *p, char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int command = SVAL(buf,0);
+ struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
+ extern pstring global_scope;
+
+ /* Drop the packet if it's a different NetBIOS scope, or
+ the source is from one of our names. */
+
+ if (!strequal(dgram->dest_name.scope, global_scope))
+ {
+ DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+ return;
+ }
+
+ if (is_myname(dgram->source_name.name))
+ {
+ DEBUG(0,("process_lanman_packet: Discarding datagram from IP %s. Source name \
+%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
+ return;
+ }
+
+ switch (command)
+ {
+ case ANN_HostAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_lm_host_announce(subrec, p, buf+1);
+ break;
+ }
+ case ANN_AnnouncementRequest:
+ {
+ process_lm_announce_request(subrec, p, buf+1);
+ break;
+ }
+ default:
+ {
+ DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
+command code %d from %s IP %s to %s\n",
+ subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
+ inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
+ }
+ }
+}
+
+/****************************************************************************
+ Determine if a packet is for us on port 138. Note that to have any chance of
+ being efficient we need to drop as many packets as possible at this
+ stage as subsequent processing is expensive.
+****************************************************************************/
+
+static BOOL listening(struct packet_struct *p,struct nmb_name *nbname)
+{
+ struct subnet_record *subrec = NULL;
+
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ break;
+ }
+
+ if(subrec == NULL)
+ subrec = unicast_subnet;
+
+ return (find_name_on_subnet(subrec, nbname, FIND_SELF_NAME) != NULL);
+}
+
+/****************************************************************************
+ Process udp 138 datagrams
+****************************************************************************/
+static void process_dgram(struct packet_struct *p)
+{
+ char *buf;
+ char *buf2;
+ int len;
+ struct dgram_packet *dgram = &p->packet.dgram;
+
+ /* If we aren't listening to the destination name then ignore the packet */
+ if (!listening(p,&dgram->dest_name))
+ {
+ unexpected_packet(p);
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from %s\n",
+ nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (dgram->header.msg_type != 0x10 &&
+ dgram->header.msg_type != 0x11 &&
+ dgram->header.msg_type != 0x12)
+ {
+ unexpected_packet(p);
+ /* Don't process error packets etc yet */
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from IP %s as it is \
+an error packet of type %x\n",
+ nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip), dgram->header.msg_type));
+ return;
+ }
+
+ buf = &dgram->data[0];
+ buf -= 4; /* XXXX for the pseudo tcp length -
+ someday I need to get rid of this */
+
+ if (CVAL(buf,smb_com) != SMBtrans)
+ return;
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ if (len <= 0)
+ return;
+
+ if (buf2 + len > buf + sizeof(dgram->data)) {
+ DEBUG(2,("process_dgram: datagram from %s to %s IP %s for %s len=%d too long.\n",
+ nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),len));
+ len = (buf + sizeof(dgram->data)) - buf;
+ }
+
+ DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
+ nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+
+
+ /* Datagram packet received for the browser mailslot */
+ if (strequal(smb_buf(buf),BROWSE_MAILSLOT))
+ {
+ process_browse_packet(p,buf2,len);
+ return;
+ }
+
+ /* Datagram packet received for the LAN Manager mailslot */
+ if (strequal(smb_buf(buf),LANMAN_MAILSLOT)) {
+ process_lanman_packet(p,buf2,len);
+ return;
+ }
+
+ /* Datagram packet received for the domain logon mailslot */
+ if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT))
+ {
+ process_logon_packet(p,buf2,len,NET_LOGON_MAILSLOT);
+ return;
+ }
+
+ /* Datagram packet received for the NT domain logon mailslot */
+ if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT))
+ {
+ process_logon_packet(p,buf2,len,NT_LOGON_MAILSLOT);
+ return;
+ }
+
+ unexpected_packet(p);
+}
+
+/****************************************************************************
+ Validate a response nmb packet.
+****************************************************************************/
+
+static BOOL validate_nmb_response_packet( struct nmb_packet *nmb )
+{
+ BOOL ignore = False;
+
+ switch (nmb->header.opcode)
+ {
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ if (nmb->header.ancount == 0)
+ {
+ DEBUG(0,("validate_nmb_response_packet: Bad REG/REFRESH Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_QUERY_OPCODE:
+ if ((nmb->header.ancount != 0) && (nmb->header.ancount != 1))
+ {
+ DEBUG(0,("validate_nmb_response_packet: Bad QUERY Packet. "));
+ ignore = True;
+ }
+ break;
+ case NMB_NAME_RELEASE_OPCODE:
+ if (nmb->header.ancount == 0)
+ {
+ DEBUG(0,("validate_nmb_response_packet: Bad RELEASE Packet. "));
+ ignore = True;
+ }
+ break;
+ case NMB_WACK_OPCODE:
+ /* Check WACK response here. */
+ if (nmb->header.ancount != 1)
+ {
+ DEBUG(0,("validate_nmb_response_packet: Bad WACK Packet. "));
+ ignore = True;
+ }
+ break;
+ default:
+ DEBUG(0,("validate_nmb_response_packet: Ignoring packet with unknown opcode %d.\n",
+ nmb->header.opcode));
+ return True;
+ }
+
+ if(ignore)
+ DEBUG(0,("Ignoring response packet with opcode %d.\n", nmb->header.opcode));
+
+ return ignore;
+}
+
+/****************************************************************************
+ Validate a request nmb packet.
+****************************************************************************/
+
+static BOOL validate_nmb_packet( struct nmb_packet *nmb )
+{
+ BOOL ignore = False;
+
+ switch (nmb->header.opcode)
+ {
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+ {
+ DEBUG(0,("validate_nmb_packet: Bad REG/REFRESH Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_QUERY_OPCODE:
+ if ((nmb->header.qdcount == 0) ||
+ ((nmb->question.question_type != QUESTION_TYPE_NB_QUERY) &&
+ (nmb->question.question_type != QUESTION_TYPE_NB_STATUS)))
+ {
+ DEBUG(0,("validate_nmb_packet: Bad QUERY Packet. "));
+ ignore = True;
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+ {
+ DEBUG(0,("validate_nmb_packet: Bad RELEASE Packet. "));
+ ignore = True;
+ }
+ break;
+ default:
+ DEBUG(0,("validate_nmb_packet: Ignoring packet with unknown opcode %d.\n",
+ nmb->header.opcode));
+ return True;
+ }
+
+ if(ignore)
+ DEBUG(0,("validate_nmb_packet: Ignoring request packet with opcode %d.\n", nmb->header.opcode));
+
+ return ignore;
+}
+
+/****************************************************************************
+ Find a subnet (and potentially a response record) for a packet.
+****************************************************************************/
+
+static struct subnet_record *find_subnet_for_nmb_packet( struct packet_struct *p,
+ struct response_record **pprrec)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct response_record *rrec = NULL;
+ struct subnet_record *subrec = NULL;
+
+ if(pprrec != NULL)
+ *pprrec = NULL;
+
+ if(nmb->header.response)
+ {
+ /* It's a response packet. Find a record for it or it's an error. */
+
+ rrec = find_response_record( &subrec, nmb->header.name_trn_id);
+ if(rrec == NULL)
+ {
+ DEBUG(3,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
+ nmb->header.name_trn_id));
+ unexpected_packet(p);
+ return NULL;
+ }
+
+ if(subrec == NULL)
+ {
+ DEBUG(0,("find_subnet_for_nmb_packet: subnet record not found for response id %hu\n",
+ nmb->header.name_trn_id));
+ return NULL;
+ }
+
+ if(pprrec != NULL)
+ *pprrec = rrec;
+ return subrec;
+ }
+
+ /* Try and see what subnet this packet belongs to. */
+
+ /* WINS server ? */
+ if(packet_is_for_wins_server(p))
+ return wins_server_subnet;
+
+ /* If it wasn't a broadcast packet then send to the UNICAST subnet. */
+ if(nmb->header.nm_flags.bcast == False)
+ return unicast_subnet;
+
+ /* Go through all the broadcast subnets and see if the mask matches. */
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ return subrec;
+ }
+
+ /* If none match it must have been a directed broadcast - assign
+ the remote_broadcast_subnet. */
+ return remote_broadcast_subnet;
+}
+
+/****************************************************************************
+ Process a nmb request packet - validate the packet and route it.
+****************************************************************************/
+
+static void process_nmb_request(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct subnet_record *subrec = NULL;
+
+ debug_nmb_packet(p);
+
+ /* Ensure we have a good packet. */
+ if(validate_nmb_packet(nmb))
+ return;
+
+ /* Allocate a subnet to this packet - if we cannot - fail. */
+ if((subrec = find_subnet_for_nmb_packet(p, NULL))==NULL)
+ return;
+
+ switch (nmb->header.opcode)
+ {
+ case NMB_NAME_REG_OPCODE:
+ if(subrec == wins_server_subnet)
+ wins_process_name_registration_request(subrec, p);
+ else
+ process_name_registration_request(subrec, p);
+ break;
+
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9:
+ if(subrec == wins_server_subnet)
+ wins_process_name_refresh_request(subrec, p);
+ else
+ process_name_refresh_request(subrec, p);
+ break;
+
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ if(subrec == wins_server_subnet)
+ wins_process_multihomed_name_registration_request(subrec, p);
+ else
+ {
+ DEBUG(0,("process_nmb_request: Multihomed registration request must be \
+directed at a WINS server.\n"));
+ }
+ break;
+
+ case NMB_NAME_QUERY_OPCODE:
+ switch (nmb->question.question_type)
+ {
+ case QUESTION_TYPE_NB_QUERY:
+ {
+ if(subrec == wins_server_subnet)
+ wins_process_name_query_request(subrec, p);
+ else
+ process_name_query_request(subrec, p);
+ break;
+ }
+ case QUESTION_TYPE_NB_STATUS:
+ {
+ if(subrec == wins_server_subnet)
+ {
+ DEBUG(0,("process_nmb_request: NB_STATUS request directed at WINS server is \
+not allowed.\n"));
+ break;
+ }
+ else
+ process_node_status_request(subrec, p);
+ break;
+ }
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if(subrec == wins_server_subnet)
+ wins_process_name_release_request(subrec, p);
+ else
+ process_name_release_request(subrec, p);
+ break;
+ }
+}
+
+/****************************************************************************
+ Process a nmb response packet - validate the packet and route it.
+ to either the WINS server or a normal response.
+****************************************************************************/
+
+static void process_nmb_response(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct subnet_record *subrec = NULL;
+ struct response_record *rrec = NULL;
+
+ debug_nmb_packet(p);
+
+ if(validate_nmb_response_packet(nmb))
+ return;
+
+ if((subrec = find_subnet_for_nmb_packet(p, &rrec))==NULL)
+ return;
+
+ if(rrec == NULL)
+ {
+ DEBUG(0,("process_nmb_response: response packet received but no response record \
+found for id = %hu. Ignoring packet.\n", nmb->header.name_trn_id));
+ return;
+ }
+
+ /* Increment the number of responses received for this record. */
+ rrec->num_msgs++;
+ /* Ensure we don't re-send the request. */
+ rrec->repeat_count = 0;
+
+ /* Call the response received function for this packet. */
+ (*rrec->resp_fn)(subrec, rrec, p);
+}
+
+
+/*******************************************************************
+ Run elements off the packet queue till its empty
+******************************************************************/
+
+void run_packet_queue(void)
+{
+ struct packet_struct *p;
+
+ while ((p = packet_queue))
+ {
+ packet_queue = p->next;
+ if (packet_queue)
+ packet_queue->prev = NULL;
+ p->next = p->prev = NULL;
+
+ switch (p->packet_type)
+ {
+ case NMB_PACKET:
+ if(p->packet.nmb.header.response)
+ process_nmb_response(p);
+ else
+ process_nmb_request(p);
+ break;
+
+ case DGRAM_PACKET:
+ process_dgram(p);
+ break;
+ }
+ free_packet(p);
+ }
+}
+
+/*******************************************************************
+ Retransmit or timeout elements from all the outgoing subnet response
+ record queues. NOTE that this code must also check the WINS server
+ subnet for response records to timeout as the WINS server code
+ can send requests to check if a client still owns a name.
+ (Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>).
+******************************************************************/
+
+void retransmit_or_expire_response_records(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec;
+ subrec = get_next_subnet_maybe_unicast_or_wins_server(subrec))
+ {
+ struct response_record *rrec, *nextrrec;
+
+ for (rrec = subrec->responselist; rrec; rrec = nextrrec)
+ {
+ nextrrec = rrec->next;
+
+ if (rrec->repeat_time <= t)
+ {
+ if (rrec->repeat_count > 0)
+ {
+ /* Resend while we have a non-zero repeat_count. */
+ if(!send_packet(rrec->packet))
+ {
+ DEBUG(0,("retransmit_or_expire_response_records: Failed to resend packet id %hu \
+to IP %s on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip),
+ subrec->subnet_name));
+ }
+ rrec->repeat_time += rrec->repeat_interval;
+ rrec->repeat_count--;
+ }
+ else
+ {
+ DEBUG(4,("retransmit_or_expire_response_records: timeout for packet id %hu to IP %s \
+on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip),
+ subrec->subnet_name));
+
+ /*
+ * Check the flag in this record to prevent recursion if we end
+ * up in this function again via the timeout function call.
+ */
+
+ if(!rrec->in_expiration_processing)
+ {
+
+ /*
+ * Set the recursion protection flag in this record.
+ */
+
+ rrec->in_expiration_processing = True;
+
+ /* Call the timeout function. This will deal with removing the
+ timed out packet. */
+ if(rrec->timeout_fn)
+ (*rrec->timeout_fn)(subrec, rrec);
+ else
+ {
+ /* We must remove the record ourself if there is
+ no timeout function. */
+ remove_response_record(subrec, rrec);
+ }
+ } /* !rrec->in_expitation_processing */
+ } /* rrec->repeat_count > 0 */
+ } /* rrec->repeat_time <= t */
+ } /* end for rrec */
+ } /* end for subnet */
+}
+
+/****************************************************************************
+ Create an fd_set containing all the sockets in the subnet structures,
+ plus the broadcast sockets.
+***************************************************************************/
+
+static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
+{
+ int *sock_array = NULL;
+ struct subnet_record *subrec = NULL;
+ int count = 0;
+ int num = 0;
+ fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
+
+ if(pset == NULL)
+ {
+ DEBUG(0,("create_listen_fdset: malloc fail !\n"));
+ return True;
+ }
+
+ /* Check that we can add all the fd's we need. */
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ count++;
+
+ if((count*2) + 2 > FD_SETSIZE)
+ {
+ DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
+only use %d.\n", (count*2) + 2, FD_SETSIZE));
+ return True;
+ }
+
+ if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL)
+ {
+ DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+ return True;
+ }
+
+ FD_ZERO(pset);
+
+ /* Add in the broadcast socket on 137. */
+ FD_SET(ClientNMB,pset);
+ sock_array[num++] = ClientNMB;
+
+ /* Add in the 137 sockets on all the interfaces. */
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ FD_SET(subrec->nmb_sock,pset);
+ sock_array[num++] = subrec->nmb_sock;
+ }
+
+ /* Add in the broadcast socket on 138. */
+ FD_SET(ClientDGRAM,pset);
+ sock_array[num++] = ClientDGRAM;
+
+ /* Add in the 138 sockets on all the interfaces. */
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ FD_SET(subrec->dgram_sock,pset);
+ sock_array[num++] = subrec->dgram_sock;
+ }
+
+ *listen_number = (count*2) + 2;
+
+ SAFE_FREE(*ppset);
+ SAFE_FREE(*psock_array);
+
+ *ppset = pset;
+ *psock_array = sock_array;
+
+ return False;
+}
+
+/****************************************************************************
+ Listens for NMB or DGRAM packets, and queues them.
+ return True if the socket is dead
+***************************************************************************/
+
+BOOL listen_for_packets(BOOL run_election)
+{
+ static fd_set *listen_set = NULL;
+ static int listen_number = 0;
+ static int *sock_array = NULL;
+ int i;
+
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+#ifndef SYNC_DNS
+ int dns_fd;
+#endif
+
+ if(listen_set == NULL || rescan_listen_set)
+ {
+ if(create_listen_fdset(&listen_set, &sock_array, &listen_number))
+ {
+ DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
+ return True;
+ }
+ rescan_listen_set = False;
+ }
+
+ memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+
+#ifndef SYNC_DNS
+ dns_fd = asyncdns_fd();
+ if (dns_fd != -1) {
+ FD_SET(dns_fd, &fds);
+ }
+#endif
+
+
+ /*
+ * During elections and when expecting a netbios response packet we
+ * need to send election packets at tighter intervals.
+ * Ideally it needs to be the interval (in ms) between time now and
+ * the time we are expecting the next netbios packet.
+ */
+
+ timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
+ timeout.tv_usec = 0;
+
+ /* Prepare for the select - allow certain signals. */
+
+ BlockSignals(False, SIGTERM);
+
+ selrtn = sys_select(FD_SETSIZE,&fds,&timeout);
+
+ /* We can only take signals when we are in the select - block them again here. */
+
+ BlockSignals(True, SIGTERM);
+
+ if(selrtn == -1) {
+ return False;
+ }
+
+#ifndef SYNC_DNS
+ if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
+ run_dns_queue();
+ }
+#endif
+
+ for(i = 0; i < listen_number; i++) {
+ if (i < (listen_number/2)) {
+ /* Processing a 137 socket. */
+ if (FD_ISSET(sock_array[i],&fds)) {
+ struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
+ if (packet) {
+ /*
+ * If we got a packet on the broadcast socket and interfaces
+ * only is set then check it came from one of our local nets.
+ */
+ if(lp_bind_interfaces_only() && (sock_array[i] == ClientNMB) &&
+ (!is_local_net(packet->ip))) {
+ DEBUG(7,("discarding nmb packet sent to broadcast socket from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else if ((ip_equal(loopback_ip, packet->ip) ||
+ ismyip(packet->ip)) && packet->port == global_nmb_port) {
+ DEBUG(7,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else {
+ /* Save the file descriptor this packet came in on. */
+ packet->fd = sock_array[i];
+ queue_packet(packet);
+ }
+ }
+ }
+ } else {
+ /* Processing a 138 socket. */
+ if (FD_ISSET(sock_array[i],&fds)) {
+ struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
+ if (packet) {
+ /*
+ * If we got a packet on the broadcast socket and interfaces
+ * only is set then check it came from one of our local nets.
+ */
+ if(lp_bind_interfaces_only() && (sock_array[i] == ClientDGRAM) &&
+ (!is_local_net(packet->ip))) {
+ DEBUG(7,("discarding dgram packet sent to broadcast socket from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else if ((ip_equal(loopback_ip, packet->ip) ||
+ ismyip(packet->ip)) && packet->port == DGRAM_PORT) {
+ DEBUG(7,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else {
+ /* Save the file descriptor this packet came in on. */
+ packet->fd = sock_array[i];
+ queue_packet(packet);
+ }
+ }
+ }
+ } /* end processing 138 socket. */
+ } /* end for */
+ return False;
+}
+
+/****************************************************************************
+ Construct and send a netbios DGRAM.
+**************************************************************************/
+BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len,
+ char *srcname, int src_type,
+ char *dstname, int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip,
+ int dest_port)
+{
+ BOOL loopback_this_packet = False;
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr,*p2;
+ char tmp[4];
+
+ memset((char *)&p,'\0',sizeof(p));
+
+ if(ismyip(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
+ loopback_this_packet = True;
+
+ /* generate_name_trn_id(); */ /* Not used, so gone, RJS */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = generate_name_trn_id();
+ dgram->header.source_ip = src_ip;
+ dgram->header.source_port = DGRAM_PORT;
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ pstrcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = dest_ip;
+ p.port = dest_port;
+ p.fd = find_subnet_mailslot_fd_for_address( src_ip );
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+ nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+ debug_browse_data(buf, len);
+
+ if(loopback_this_packet)
+ {
+ struct packet_struct *lo_packet = NULL;
+ DEBUG(5,("send_mailslot: sending packet to ourselves.\n"));
+ if((lo_packet = copy_packet(&p)) == NULL)
+ return False;
+ queue_packet(lo_packet);
+ return True;
+ }
+ else
+ return(send_packet(&p));
+}
diff --git a/source/nmbd/nmbd_processlogon.c b/source/nmbd/nmbd_processlogon.c
new file mode 100644
index 00000000000..bcd1e1a1ff3
--- /dev/null
+++ b/source/nmbd/nmbd_processlogon.c
@@ -0,0 +1,390 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+struct sam_database_info {
+ uint32 index;
+ uint32 serial_lo, serial_hi;
+ uint32 date_lo, date_hi;
+};
+
+/****************************************************************************
+Send a message to smbd to do a sam delta sync
+**************************************************************************/
+static void send_repl_message(uint32 low_serial)
+{
+ TDB_CONTEXT *tdb;
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0,
+ TDB_DEFAULT, O_RDONLY, 0);
+
+ if (!tdb) {
+ DEBUG(3, ("send_repl_message(): failed to open connections "
+ "database\n"));
+ return;
+ }
+
+ DEBUG(3, ("sending replication message, serial = 0x%04x\n",
+ low_serial));
+
+ message_send_all(tdb, MSG_SMB_SAM_REPL, &low_serial,
+ sizeof(low_serial), False);
+
+ tdb_close(tdb);
+}
+
+/****************************************************************************
+Process a domain logon packet
+**************************************************************************/
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len,
+ char *mailslot)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ pstring my_name;
+ fstring reply_name;
+ pstring outbuf;
+ int code;
+ uint16 token = 0;
+ uint32 ntversion = 0;
+ uint16 lmnttoken = 0;
+ uint16 lm20token = 0;
+ uint32 domainsidsize;
+ BOOL short_request = False;
+ char *getdc;
+ char *uniuser; /* Unicode user name. */
+ pstring ascuser;
+ char *unicomp; /* Unicode computer name. */
+
+ memset(outbuf, 0, sizeof(outbuf));
+
+ if (!lp_domain_logons())
+ {
+ DEBUG(3,("process_logon_packet: Logon packet received from IP %s and domain \
+logons are not enabled.\n", inet_ntoa(p->ip) ));
+ return;
+ }
+
+ pstrcpy(my_name, global_myname);
+ strupper(my_name);
+
+ code = SVAL(buf,0);
+ DEBUG(1,("process_logon_packet: Logon from %s: code = 0x%x\n", inet_ntoa(p->ip), code));
+
+ switch (code)
+ {
+ case 0:
+ {
+ char *q = buf + 2;
+ char *machine = q;
+ char *user = skip_string(machine,1);
+
+ getdc = skip_string(user,1);
+ q = skip_string(getdc,1);
+ token = SVAL(q,3);
+
+ fstrcpy(reply_name,my_name);
+
+ DEBUG(3,("process_logon_packet: Domain login request from %s at IP %s user=%s token=%x\n",
+ machine,inet_ntoa(p->ip),user,token));
+
+ q = outbuf;
+ SSVAL(q, 0, 6);
+ q += 2;
+
+ fstrcpy(reply_name, "\\\\");
+ fstrcat(reply_name, my_name);
+ fstrcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
+
+ SSVAL(q, 0, token);
+ q += 2;
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot(True, getdc,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname, 0x0,
+ machine,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ break;
+ }
+
+ case QUERYFORPDC:
+ {
+ char *q = buf + 2;
+ char *machine = q;
+
+ if (!lp_domain_master())
+ {
+ /* We're not Primary Domain Controller -- ignore this */
+ return;
+ }
+
+ getdc = skip_string(machine,1);
+ q = skip_string(getdc,1);
+ q = ALIGN2(q, buf);
+
+ /* at this point we can work out if this is a W9X or NT style
+ request. Experiments show that the difference is wether the
+ packet ends here. For a W9X request we now end with a pair of
+ bytes (usually 0xFE 0xFF) whereas with NT we have two further
+ strings - the following is a simple way of detecting this */
+ if (len - PTR_DIFF(q, buf) <= 3) {
+ short_request = True;
+ } else {
+ unicomp = q;
+
+ /* A full length (NT style) request */
+ q = skip_unibuf(unicomp, PTR_DIFF(buf + len, unicomp));
+
+ if (len - PTR_DIFF(q, buf) > 8) {
+ /* with NT5 clients we can sometimes
+ get additional data - a length specificed string
+ containing the domain name, then 16 bytes of
+ data (no idea what it is) */
+ int dom_len = CVAL(q, 0);
+ q++;
+ if (dom_len != 0) {
+ q += dom_len + 1;
+ }
+ q += 16;
+ }
+ ntversion = IVAL(q, 0);
+ lmnttoken = SVAL(q, 4);
+ lm20token = SVAL(q, 6);
+ }
+
+ /* Construct reply. */
+ q = outbuf;
+ SSVAL(q, 0, QUERYFORPDC_R);
+ q += 2;
+
+ fstrcpy(reply_name,my_name);
+ fstrcpy(q, reply_name);
+ q = skip_string(q, 1); /* PDC name */
+
+ /* PDC and domain name */
+ if (!short_request) /* Make a full reply */
+ {
+ q = ALIGN2(q, outbuf);
+
+ q += dos_PutUniCode(q, my_name, sizeof(pstring), True); /* PDC name */
+ q += dos_PutUniCode(q, global_myworkgroup,sizeof(pstring), True); /* Domain name*/
+ SIVAL(q, 0, 1); /* our nt version */
+ SSVAL(q, 4, 0xffff); /* our lmnttoken */
+ SSVAL(q, 6, 0xffff); /* our lm20token */
+ q += 8;
+ }
+
+ /* RJS, 21-Feb-2000, we send a short reply if the request was short */
+
+ DEBUG(3,("process_logon_packet: GETDC request from %s at IP %s, \
+reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
+ machine,inet_ntoa(p->ip), reply_name, global_myworkgroup,
+ QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
+ (uint32)lm20token ));
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot(True, getdc,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname, 0x0,
+ dgram->source_name.name,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ return;
+ }
+
+ case SAMLOGON:
+ {
+ char *q = buf + 2;
+ fstring asccomp;
+
+ q += 2;
+ unicomp = q;
+ uniuser = skip_unibuf(unicomp, PTR_DIFF(buf+len, unicomp));
+ getdc = skip_unibuf(uniuser,PTR_DIFF(buf+len, uniuser));
+ q = skip_string(getdc,1);
+ q += 4; /* Account Control Bits - indicating username type */
+ domainsidsize = IVAL(q, 0);
+ q += 4;
+
+ DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d, len = %d\n", domainsidsize, len));
+
+ if (domainsidsize < (len - PTR_DIFF(q, buf)) && (domainsidsize != 0)) {
+ q += domainsidsize;
+ q = ALIGN4(q, buf);
+ }
+
+ DEBUG(3,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %d\n", len, PTR_DIFF(q, buf) ));
+
+ if (len - PTR_DIFF(q, buf) > 8) {
+ /* with NT5 clients we can sometimes
+ get additional data - a length specificed string
+ containing the domain name, then 16 bytes of
+ data (no idea what it is) */
+ int dom_len = CVAL(q, 0);
+ q++;
+ if (dom_len < (len - PTR_DIFF(q, buf)) && (dom_len != 0)) {
+ q += dom_len + 1;
+ }
+ q += 16;
+ }
+
+ ntversion = IVAL(q, 0);
+ lmnttoken = SVAL(q, 4);
+ lm20token = SVAL(q, 6);
+ q += 8;
+
+ DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
+
+ /*
+ * we respond regadless of whether the machine is in our password
+ * database. If it isn't then we let smbd send an appropriate error.
+ * Let's ignore the SID.
+ */
+ pull_ucs2_pstring(ascuser, uniuser);
+ pull_ucs2_fstring(asccomp, unicomp);
+ DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser));
+
+ fstrcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER. */
+ fstrcpy(reply_name+2,my_name);
+
+ DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
+ asccomp,inet_ntoa(p->ip), ascuser, reply_name, global_myworkgroup,
+ SAMLOGON_R ,lmnttoken));
+
+ /* Construct reply. */
+
+ q = outbuf;
+ if (SVAL(uniuser, 0) == 0) {
+ SSVAL(q, 0, SAMLOGON_UNK_R); /* user unknown */
+ } else {
+ SSVAL(q, 0, SAMLOGON_R);
+ }
+ q += 2;
+
+ q += dos_PutUniCode(q, reply_name,sizeof(pstring), True);
+ q += dos_PutUniCode(q, ascuser, sizeof(pstring), True);
+ q += dos_PutUniCode(q, global_myworkgroup,sizeof(pstring), True);
+
+ /* tell the client what version we are */
+ SIVAL(q, 0, 1); /* our ntversion */
+ SSVAL(q, 4, 0xffff); /* our lmnttoken */
+ SSVAL(q, 6, 0xffff); /* our lm20token */
+ q += 8;
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot(True, getdc,
+ outbuf,PTR_DIFF(q,outbuf),
+ global_myname, 0x0,
+ dgram->source_name.name,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ break;
+ }
+
+ /* Announce change to UAS or SAM. Send by the domain controller when a
+ replication event is required. */
+
+ case SAM_UAS_CHANGE: {
+ struct sam_database_info *db_info;
+ char *q = buf + 2;
+ int i, db_count;
+ uint32 low_serial;
+
+ /* Header */
+
+ low_serial = IVAL(q, 0); q += 4; /* Low serial number */
+
+ q += 4; /* Date/time */
+ q += 4; /* Pulse */
+ q += 4; /* Random */
+
+ /* Domain info */
+
+ q = skip_string(q, 1); /* PDC name */
+ q = skip_string(q, 1); /* Domain name */
+ q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode PDC name */
+ q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode domain name */
+
+ /* Database info */
+
+ db_count = SVAL(q, 0); q += 2;
+
+ db_info = (struct sam_database_info *)
+ malloc(sizeof(struct sam_database_info) * db_count);
+
+ if (db_info == NULL) {
+ DEBUG(3, ("out of memory allocating info for %d databases\n",
+ db_count));
+ return;
+ }
+
+ for (i = 0; i < db_count; i++) {
+ db_info[i].index = IVAL(q, 0);
+ db_info[i].serial_lo = IVAL(q, 4);
+ db_info[i].serial_hi = IVAL(q, 8);
+ db_info[i].date_lo = IVAL(q, 12);
+ db_info[i].date_hi = IVAL(q, 16);
+ q += 20;
+ }
+
+ /* Domain SID */
+
+ q += IVAL(q, 0) + 4; /* 4 byte length plus data */
+
+ q += 2; /* Alignment? */
+
+ /* Misc other info */
+
+ q += 4; /* NT version (0x1) */
+ q += 2; /* LMNT token (0xff) */
+ q += 2; /* LM20 token (0xff) */
+
+ SAFE_FREE(db_info); /* Not sure whether we need to do anything
+ useful with these */
+
+ /* Send message to smbd */
+
+ send_repl_message(low_serial);
+
+ break;
+ }
+
+ default:
+ {
+ DEBUG(3,("process_logon_packet: Unknown domain request %d\n",code));
+ return;
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_responserecordsdb.c b/source/nmbd/nmbd_responserecordsdb.c
new file mode 100644
index 00000000000..63601ff26c4
--- /dev/null
+++ b/source/nmbd/nmbd_responserecordsdb.c
@@ -0,0 +1,265 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+int num_response_packets = 0;
+
+/***************************************************************************
+ Add an expected response record into the list
+ **************************************************************************/
+
+static void add_response_record(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct response_record *rrec2;
+
+ num_response_packets++; /* count of total number of packets still around */
+
+ DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
+ rrec->response_id, subrec->subnet_name, num_response_packets));
+
+ if (!subrec->responselist)
+ {
+ subrec->responselist = rrec;
+ rrec->prev = NULL;
+ rrec->next = NULL;
+ return;
+ }
+
+ for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next)
+ ;
+
+ rrec2->next = rrec;
+ rrec->next = NULL;
+ rrec->prev = rrec2;
+}
+
+/***************************************************************************
+ Remove an expected response record from the list
+ **************************************************************************/
+
+void remove_response_record(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ if (rrec->prev)
+ rrec->prev->next = rrec->next;
+ if (rrec->next)
+ rrec->next->prev = rrec->prev;
+
+ if (subrec->responselist == rrec)
+ subrec->responselist = rrec->next;
+
+ if(rrec->userdata)
+ {
+ if(rrec->userdata->free_fn) {
+ (*rrec->userdata->free_fn)(rrec->userdata);
+ } else {
+ ZERO_STRUCTP(rrec->userdata);
+ SAFE_FREE(rrec->userdata);
+ }
+ }
+
+ /* Ensure we can delete. */
+ rrec->packet->locked = False;
+ free_packet(rrec->packet);
+
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+
+ num_response_packets--; /* count of total number of packets still around */
+}
+
+/****************************************************************************
+ Create a response record for an outgoing packet.
+ **************************************************************************/
+
+struct response_record *make_response_record( struct subnet_record *subrec,
+ struct packet_struct *p,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ success_function success_fn,
+ fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ struct response_record *rrec;
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ if (!(rrec = (struct response_record *)malloc(sizeof(*rrec))))
+ {
+ DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
+ return NULL;
+ }
+
+ memset((char *)rrec, '\0', sizeof(*rrec));
+
+ rrec->response_id = nmb->header.name_trn_id;
+
+ rrec->resp_fn = resp_fn;
+ rrec->timeout_fn = timeout_fn;
+ rrec->success_fn = success_fn;
+ rrec->fail_fn = fail_fn;
+
+ rrec->packet = p;
+
+ if(userdata)
+ {
+ /* Intelligent userdata. */
+ if(userdata->copy_fn)
+ {
+ if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL)
+ {
+ DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Primitive userdata, do a memcpy. */
+ if((rrec->userdata = (struct userdata_struct *)
+ malloc(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL)
+ {
+ DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
+ ZERO_STRUCTP(rrec);
+ SAFE_FREE(rrec);
+ return NULL;
+ }
+ rrec->userdata->copy_fn = userdata->copy_fn;
+ rrec->userdata->free_fn = userdata->free_fn;
+ rrec->userdata->userdata_len = userdata->userdata_len;
+ memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
+ }
+ }
+ else
+ rrec->userdata = NULL;
+
+ rrec->num_msgs = 0;
+
+ if(!nmb->header.nm_flags.bcast)
+ rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
+ else
+ rrec->repeat_interval = 1; /* XXXX should be in ms */
+ rrec->repeat_count = 3; /* 3 retries */
+ rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
+
+ /* This packet is not being processed. */
+ rrec->in_expiration_processing = False;
+
+ /* Lock the packet so we won't lose it while it's on the list. */
+ p->locked = True;
+
+ add_response_record(subrec, rrec);
+
+ return rrec;
+}
+
+/****************************************************************************
+ Find a response in a subnet's name query response list.
+ **************************************************************************/
+
+static struct response_record *find_response_record_on_subnet(
+ struct subnet_record *subrec, uint16 id)
+{
+ struct response_record *rrec = NULL;
+
+ for (rrec = subrec->responselist; rrec; rrec = rrec->next)
+ {
+ if (rrec->response_id == id)
+ {
+ DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
+ id, subrec->subnet_name));
+ break;
+ }
+ }
+ return rrec;
+}
+
+/****************************************************************************
+ Find a response in any subnet's name query response list.
+ **************************************************************************/
+
+struct response_record *find_response_record(struct subnet_record **ppsubrec,
+ uint16 id)
+{
+ struct response_record *rrec = NULL;
+
+ for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec);
+ (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec))
+ {
+ if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
+ return rrec;
+ }
+
+ /* There should never be response records on the remote_broadcast subnet.
+ Sanity check to ensure this is so. */
+ if(remote_broadcast_subnet->responselist != NULL)
+ {
+ DEBUG(0,("find_response_record: response record found on subnet %s. This should \
+never happen !\n", remote_broadcast_subnet->subnet_name));
+ }
+
+ /* Now check the WINS server subnet if it exists. */
+ if(wins_server_subnet != NULL)
+ {
+ *ppsubrec = wins_server_subnet;
+ if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
+ return rrec;
+ }
+
+ DEBUG(0,("find_response_record: response packet id %hu received with no \
+matching record.\n", id));
+
+ *ppsubrec = NULL;
+
+ return NULL;
+}
+
+/****************************************************************************
+ Check if a refresh is queued for a particular name on a particular subnet.
+ **************************************************************************/
+
+BOOL is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec)
+{
+ struct response_record *rrec = NULL;
+
+ for (rrec = subrec->responselist; rrec; rrec = rrec->next)
+ {
+ struct packet_struct *p = rrec->packet;
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
+ (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9))
+ {
+ /* Yes it's a queued refresh - check if the name is correct. */
+ if(nmb_name_equal(&nmb->question.question_name, &namerec->name))
+ return True;
+ }
+ }
+
+ return False;
+}
diff --git a/source/nmbd/nmbd_sendannounce.c b/source/nmbd/nmbd_sendannounce.c
new file mode 100644
index 00000000000..1f56dea8824
--- /dev/null
+++ b/source/nmbd/nmbd_sendannounce.c
@@ -0,0 +1,606 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern int updatecount;
+extern BOOL found_lm_clients;
+
+/****************************************************************************
+ Send a browser reset packet.
+**************************************************************************/
+
+void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip)
+{
+ pstring outbuf;
+ char *p;
+
+ DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
+ reset_type, to_name, to_type, inet_ntoa(to_ip) ));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_ResetBrowserState;
+ p++;
+ CVAL(p,0) = reset_type;
+ p++;
+
+ send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname, 0x0, to_name, to_type, to_ip,
+ FIRST_SUBNET->myip, DGRAM_PORT);
+}
+
+/****************************************************************************
+ Broadcast a packet to the local net requesting that all servers in this
+ workgroup announce themselves to us.
+ **************************************************************************/
+
+void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
+{
+ pstring outbuf;
+ char *p;
+
+ work->needannounce = True;
+
+ DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
+to subnet %s\n", work->work_group, subrec->subnet_name));
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_AnnouncementRequest;
+ p++;
+
+ CVAL(p,0) = work->token; /* (local) Unique workgroup token id. */
+ p++;
+ p += push_string(NULL, p+1, global_myname, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+
+ send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname, 0x0, work->work_group,0x1e, subrec->bcast_ip,
+ subrec->myip, DGRAM_PORT);
+}
+
+/****************************************************************************
+ Broadcast an announcement.
+ **************************************************************************/
+
+static void send_announcement(struct subnet_record *subrec, int announce_type,
+ char *from_name, char *to_name, int to_type, struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p;
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf+1;
+
+ CVAL(outbuf,0) = announce_type;
+
+ /* Announcement parameters. */
+ CVAL(p,0) = updatecount;
+ SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
+
+ push_string(NULL, p+5, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+
+ CVAL(p,21) = lp_major_announce_version(); /* Major version. */
+ CVAL(p,22) = lp_minor_announce_version(); /* Minor version. */
+
+ SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ /* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */
+ SSVAL(p,27,BROWSER_ELECTION_VERSION);
+ SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
+
+ p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
+
+ send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+ from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
+ DGRAM_PORT);
+}
+
+/****************************************************************************
+ Broadcast a LanMan announcement.
+**************************************************************************/
+
+static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
+ char *from_name, char *to_name, int to_type, struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p=outbuf;
+
+ memset(outbuf,'\0',sizeof(outbuf));
+
+ SSVAL(p,0,announce_type);
+ SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ CVAL(p,6) = lp_major_announce_version(); /* Major version. */
+ CVAL(p,7) = lp_minor_announce_version(); /* Minor version. */
+ SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
+
+ p += 10;
+ /*StrnCpy(p,server_name,15);
+ strupper(p);
+ p = skip_string(p,1);
+ pstrcpy(p,server_comment);
+ p = skip_string(p,1);*/
+ p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+ p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+
+ send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
+ from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
+ DGRAM_PORT);
+}
+
+/****************************************************************************
+ We are a local master browser. Announce this to WORKGROUP<1e>.
+****************************************************************************/
+
+static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec)
+{
+ /* Ensure we don't have the prohibited bit set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
+ type, global_myname, subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_LocalMasterAnnouncement,
+ global_myname, /* From nbt name. */
+ work->work_group, 0x1e, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ global_myname, /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce the workgroup WORKGROUP to MSBROWSE<01>.
+****************************************************************************/
+
+static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
+{
+ DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
+ subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_DomainAnnouncement,
+ global_myname, /* From nbt name. */
+ MSBROWSE, 0x1, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ work->work_group, /* Name to announce. */
+ SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */
+ global_myname); /* From name as comment. */
+}
+
+/****************************************************************************
+ Announce the given host to WORKGROUP<1d>.
+****************************************************************************/
+
+static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec)
+{
+ /* Ensure we don't have the prohibited bits set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
+ type, servrec->serv.name, subrec->subnet_name, work->work_group));
+
+ send_announcement(subrec, ANN_HostAnnouncement,
+ servrec->serv.name, /* From nbt name. */
+ work->work_group, 0x1d, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ work->announce_interval, /* Time until next announce. */
+ servrec->serv.name, /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce the given LanMan host
+****************************************************************************/
+
+static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec, int lm_interval)
+{
+ /* Ensure we don't have the prohibited bits set. */
+ uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
+ type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
+
+ send_lm_announcement(subrec, ANN_HostAnnouncement,
+ servrec->serv.name, /* From nbt name. */
+ work->work_group, 0x00, /* To nbt name. */
+ subrec->bcast_ip, /* To ip. */
+ lm_interval, /* Time until next announce. */
+ servrec->serv.name, /* Name to announce. */
+ type, /* Type field. */
+ servrec->serv.comment);
+}
+
+/****************************************************************************
+ Announce a server record.
+ ****************************************************************************/
+
+static void announce_server(struct subnet_record *subrec, struct work_record *work,
+ struct server_record *servrec)
+{
+ /* Only do domain announcements if we are a master and it's
+ our primary name we're being asked to announce. */
+
+ if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname,servrec->serv.name))
+ {
+ send_local_master_announcement(subrec, work, servrec);
+ send_workgroup_announcement(subrec, work);
+ }
+ else
+ {
+ send_host_announcement(subrec, work, servrec);
+ }
+}
+
+/****************************************************************************
+ Go through all my registered names on all broadcast subnets and announce
+ them if the timeout requires it.
+ **************************************************************************/
+
+void announce_my_server_names(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
+
+ if(work)
+ {
+ struct server_record *servrec;
+
+ if (work->needannounce)
+ {
+ /* Drop back to a max 3 minute announce. This is to prevent a
+ single lost packet from breaking things for too long. */
+
+ work->announce_interval = MIN(work->announce_interval,
+ CHECK_TIME_MIN_HOST_ANNCE*60);
+ work->lastannounce_time = t - (work->announce_interval+1);
+ work->needannounce = False;
+ }
+
+ /* Announce every minute at first then progress to every 12 mins */
+ if ((t - work->lastannounce_time) < work->announce_interval)
+ continue;
+
+ if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
+ work->announce_interval += 60;
+
+ work->lastannounce_time = t;
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ if (is_myname(servrec->serv.name))
+ announce_server(subrec, work, servrec);
+ }
+ } /* if work */
+ } /* for subrec */
+}
+
+/****************************************************************************
+ Go through all my registered names on all broadcast subnets and announce
+ them as a LanMan server if the timeout requires it.
+**************************************************************************/
+
+void announce_my_lm_server_names(time_t t)
+{
+ struct subnet_record *subrec;
+ static time_t last_lm_announce_time=0;
+ int announce_interval = lp_lm_interval();
+ int lm_announce = lp_lm_announce();
+
+ if ((announce_interval <= 0) || (lm_announce <= 0))
+ {
+ /* user absolutely does not want LM announcements to be sent. */
+ return;
+ }
+
+ if ((lm_announce >= 2) && (!found_lm_clients))
+ {
+ /* has been set to 2 (Auto) but no LM clients detected (yet). */
+ return;
+ }
+
+ /* Otherwise: must have been set to 1 (Yes), or LM clients *have*
+ been detected. */
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
+
+ if(work)
+ {
+ struct server_record *servrec;
+
+ if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
+ continue;
+
+ last_lm_announce_time = t;
+
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ if (is_myname(servrec->serv.name))
+ /* skipping equivalent of announce_server() */
+ send_lm_host_announcement(subrec, work, servrec, announce_interval);
+ }
+ } /* if work */
+ } /* for subrec */
+}
+
+/* Announce timer. Moved into global static so it can be reset
+ when a machine becomes a local master browser. */
+static time_t announce_timer_last=0;
+
+/****************************************************************************
+ Reset the announce_timer so that a local master browser announce will be done
+ immediately.
+ ****************************************************************************/
+
+void reset_announce_timer(void)
+{
+ announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
+}
+
+/****************************************************************************
+ Announce myself as a local master browser to a domain master browser.
+ **************************************************************************/
+
+void announce_myself_to_domain_master_browser(time_t t)
+{
+ struct subnet_record *subrec;
+ struct work_record *work;
+
+ if(!we_are_a_wins_client())
+ {
+ DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
+ return;
+ }
+
+ if (!announce_timer_last)
+ announce_timer_last = t;
+
+ if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60))
+ {
+ DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
+ (int)t, (int)announce_timer_last,
+ CHECK_TIME_MST_ANNOUNCE * 60 ));
+ return;
+ }
+
+ announce_timer_last = t;
+
+ /* Look over all our broadcast subnets to see if any of them
+ has the state set as local master browser. */
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ if (AM_LOCAL_MASTER_BROWSER(work))
+ {
+ DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
+workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+
+ /* Look in nmbd_browsersync.c for the rest of this code. */
+ announce_and_sync_with_domain_master_browser(subrec, work);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+Announce all samba's server entries as 'gone'.
+This must *only* be called on shutdown.
+****************************************************************************/
+
+void announce_my_servers_removed(void)
+{
+ int announce_interval = lp_lm_interval();
+ int lm_announce = lp_lm_announce();
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ struct server_record *servrec;
+
+ work->announce_interval = 0;
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ if (!is_myname(servrec->serv.name))
+ continue;
+ servrec->serv.type = 0;
+ if(AM_LOCAL_MASTER_BROWSER(work))
+ send_local_master_announcement(subrec, work, servrec);
+ send_host_announcement(subrec, work, servrec);
+
+
+ if ((announce_interval <= 0) || (lm_announce <= 0))
+ {
+ /* user absolutely does not want LM announcements to be sent. */
+ continue;
+ }
+
+ if ((lm_announce >= 2) && (!found_lm_clients))
+ {
+ /* has been set to 2 (Auto) but no LM clients detected (yet). */
+ continue;
+ }
+
+ /*
+ * lm announce was set or we have seen lm announcements, so do
+ * a lm announcement of host removed.
+ */
+
+ send_lm_host_announcement(subrec, work, servrec, 0);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ Do all the "remote" announcements. These are used to put ourselves
+ on a remote browse list. They are done blind, no checking is done to
+ see if there is actually a local master browser at the other end.
+ **************************************************************************/
+
+void announce_remote(time_t t)
+{
+ char *s,*ptr;
+ static time_t last_time = 0;
+ pstring s2;
+ struct in_addr addr;
+ char *comment;
+ int stype = lp_default_server_announce();
+
+ if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
+ return;
+
+ last_time = t;
+
+ s = lp_remote_announce();
+ if (!*s)
+ return;
+
+ comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
+
+ for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
+ {
+ /* The entries are of the form a.b.c.d/WORKGROUP with
+ WORKGROUP being optional */
+ char *wgroup;
+ int i;
+
+ wgroup = strchr_m(s2,'/');
+ if (wgroup)
+ *wgroup++ = 0;
+ if (!wgroup || !*wgroup)
+ wgroup = global_myworkgroup;
+
+ addr = *interpret_addr2(s2);
+
+ /* Announce all our names including aliases */
+ /* Give the ip address as the address of our first
+ broadcast subnet. */
+
+ for(i=0; my_netbios_names[i]; i++)
+ {
+ char *name = my_netbios_names[i];
+
+ DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
+ name, inet_ntoa(addr) ));
+
+ send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
+ name, /* From nbt name. */
+ wgroup, 0x1d, /* To nbt name. */
+ addr, /* To ip. */
+ REMOTE_ANNOUNCE_INTERVAL, /* Time until next announce. */
+ name, /* Name to announce. */
+ stype, /* Type field. */
+ comment);
+ }
+ }
+}
+
+/****************************************************************************
+ Implement the 'remote browse sync' feature Andrew added.
+ These are used to put our browse lists into remote browse lists.
+ **************************************************************************/
+
+void browse_sync_remote(time_t t)
+{
+ char *s,*ptr;
+ static time_t last_time = 0;
+ pstring s2;
+ struct in_addr addr;
+ struct work_record *work;
+ pstring outbuf;
+ char *p;
+
+ if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
+ return;
+
+ last_time = t;
+
+ s = lp_remote_browse_sync();
+ if (!*s)
+ return;
+
+ /*
+ * We only do this if we are the local master browser
+ * for our workgroup on the firsst subnet.
+ */
+
+ if((work = find_workgroup_on_subnet(FIRST_SUBNET, global_myworkgroup)) == NULL)
+ {
+ DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
+ global_myworkgroup, FIRST_SUBNET->subnet_name ));
+ return;
+ }
+
+ if(!AM_LOCAL_MASTER_BROWSER(work))
+ {
+ DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
+for workgroup %s on subnet %s.\n", global_myworkgroup, FIRST_SUBNET->subnet_name ));
+ return;
+ }
+
+ memset(outbuf,'\0',sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_MasterAnnouncement;
+ p++;
+
+ StrnCpy(p,global_myname,15);
+ strupper(p);
+ p = skip_string(p,1);
+
+ for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
+ {
+ /* The entries are of the form a.b.c.d */
+ addr = *interpret_addr2(s2);
+
+ DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
+ global_myname, inet_ntoa(addr) ));
+
+ send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
+ global_myname, 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
+ }
+}
diff --git a/source/nmbd/nmbd_serverlistdb.c b/source/nmbd/nmbd_serverlistdb.c
new file mode 100644
index 00000000000..183ea343207
--- /dev/null
+++ b/source/nmbd/nmbd_serverlistdb.c
@@ -0,0 +1,457 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+
+int updatecount = 0;
+
+/*******************************************************************
+ Remove all the servers in a work group.
+ ******************************************************************/
+
+void remove_all_servers(struct work_record *work)
+{
+ struct server_record *servrec;
+ struct server_record *nexts;
+
+ for (servrec = work->serverlist; servrec; servrec = nexts)
+ {
+ DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
+ nexts = servrec->next;
+
+ if (servrec->prev)
+ servrec->prev->next = servrec->next;
+ if (servrec->next)
+ servrec->next->prev = servrec->prev;
+
+ if (work->serverlist == servrec)
+ work->serverlist = servrec->next;
+
+ ZERO_STRUCTP(servrec);
+ SAFE_FREE(servrec);
+
+ }
+
+ work->subnet->work_changed = True;
+}
+
+/***************************************************************************
+ Add a server into the a workgroup serverlist.
+ **************************************************************************/
+
+static void add_server_to_workgroup(struct work_record *work,
+ struct server_record *servrec)
+{
+ struct server_record *servrec2;
+
+ if (!work->serverlist)
+ {
+ work->serverlist = servrec;
+ servrec->prev = NULL;
+ servrec->next = NULL;
+ return;
+ }
+
+ for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
+ ;
+
+ servrec2->next = servrec;
+ servrec->next = NULL;
+ servrec->prev = servrec2;
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Find a server in a server list.
+ **************************************************************************/
+
+struct server_record *find_server_in_workgroup(struct work_record *work, char *name)
+{
+ struct server_record *ret;
+
+ for (ret = work->serverlist; ret; ret = ret->next)
+ {
+ if (strequal(ret->serv.name,name))
+ return ret;
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ Remove a server entry from this workgroup.
+ ****************************************************************************/
+
+void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
+{
+ if (servrec->prev)
+ servrec->prev->next = servrec->next;
+ if (servrec->next)
+ servrec->next->prev = servrec->prev;
+
+ if (work->serverlist == servrec)
+ work->serverlist = servrec->next;
+
+ ZERO_STRUCTP(servrec);
+ SAFE_FREE(servrec);
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Create a server entry on this workgroup.
+ ****************************************************************************/
+
+struct server_record *create_server_on_workgroup(struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment)
+{
+ struct server_record *servrec;
+
+ if (name[0] == '*')
+ {
+ DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
+ name));
+ return (NULL);
+ }
+
+ if((servrec = find_server_in_workgroup(work, name)) != NULL)
+ {
+ DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
+workgroup %s. This is a bug.\n", name, work->work_group));
+ return NULL;
+ }
+
+ if((servrec = (struct server_record *)malloc(sizeof(*servrec))) == NULL)
+ {
+ DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
+ return NULL;
+ }
+
+ memset((char *)servrec,'\0',sizeof(*servrec));
+
+ servrec->subnet = work->subnet;
+
+ StrnCpy(servrec->serv.name,name,sizeof(servrec->serv.name)-1);
+ StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
+ strupper(servrec->serv.name);
+ servrec->serv.type = servertype;
+
+ update_server_ttl(servrec, ttl);
+
+ add_server_to_workgroup(work, servrec);
+
+ DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
+workgroup %s.\n", name,servertype,comment, work->work_group));
+
+ work->subnet->work_changed = True;
+
+ return(servrec);
+}
+
+/*******************************************************************
+ Update the ttl field of a server record.
+*******************************************************************/
+
+void update_server_ttl(struct server_record *servrec, int ttl)
+{
+ if(ttl > lp_max_ttl())
+ ttl = lp_max_ttl();
+
+ if(is_myname(servrec->serv.name))
+ servrec->death_time = PERMANENT_TTL;
+ else
+ servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+
+ servrec->subnet->work_changed = True;
+}
+
+/*******************************************************************
+ Expire old servers in the serverlist. A time of -1 indicates
+ everybody dies except those with a death_time of PERMANENT_TTL (which is 0).
+ This should only be called from expire_workgroups_and_servers().
+ ******************************************************************/
+
+void expire_servers(struct work_record *work, time_t t)
+{
+ struct server_record *servrec;
+ struct server_record *nexts;
+
+ for (servrec = work->serverlist; servrec; servrec = nexts)
+ {
+ nexts = servrec->next;
+
+ if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t)))
+ {
+ DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
+ remove_server_from_workgroup(work, servrec);
+ work->subnet->work_changed = True;
+ }
+ }
+}
+
+/*******************************************************************
+ Decide if we should write out a server record for this server.
+ We return zero if we should not. Check if we've already written
+ out this server record from an earlier subnet.
+******************************************************************/
+
+static uint32 write_this_server_name( struct subnet_record *subrec,
+ struct work_record *work,
+ struct server_record *servrec)
+{
+ struct subnet_record *ssub;
+ struct work_record *iwork;
+
+ /* Go through all the subnets we have already seen. */
+ for (ssub = FIRST_SUBNET; ssub != subrec; ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub))
+ {
+ for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next)
+ {
+ if(find_server_in_workgroup( iwork, servrec->serv.name) != NULL)
+ {
+ /*
+ * We have already written out this server record, don't
+ * do it again. This gives precedence to servers we have seen
+ * on the broadcast subnets over servers that may have been
+ * added via a sync on the unicast_subet.
+ *
+ * The correct way to do this is to have a serverlist file
+ * per subnet - this means changes to smbd as well. I may
+ * add this at a later date (JRA).
+ */
+
+ return 0;
+ }
+ }
+ }
+
+ return servrec->serv.type;
+}
+
+/*******************************************************************
+ Decide if we should write out a workgroup record for this workgroup.
+ We return zero if we should not. Don't write out global_myworkgroup (we've
+ already done it) and also don't write out a second workgroup record
+ on the unicast subnet that we've already written out on one of the
+ broadcast subnets.
+******************************************************************/
+
+static uint32 write_this_workgroup_name( struct subnet_record *subrec,
+ struct work_record *work)
+{
+ struct subnet_record *ssub;
+
+ if(strequal(global_myworkgroup, work->work_group))
+ return 0;
+
+ /* This is a workgroup we have seen on a broadcast subnet. All
+ these have the same type. */
+
+ if(subrec != unicast_subnet)
+ return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
+
+ for(ssub = FIRST_SUBNET; ssub; ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub))
+ {
+ /* This is the unicast subnet so check if we've already written out
+ this subnet when we passed over the broadcast subnets. */
+
+ if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
+ return 0;
+ }
+
+ /* All workgroups on the unicast subnet (except our own, which we
+ have already written out) cannot be local. */
+
+ return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
+}
+
+/*******************************************************************
+ Write out the browse.dat file.
+ ******************************************************************/
+
+void write_browse_list(time_t t, BOOL force_write)
+{
+ struct subnet_record *subrec;
+ struct work_record *work;
+ struct server_record *servrec;
+ pstring fname,fnamenew;
+ uint32 stype;
+ fstring tmp;
+ int i;
+ XFILE *fp;
+ BOOL list_changed = force_write;
+ static time_t lasttime = 0;
+
+ /* Always dump if we're being told to by a signal. */
+ if(force_write == False)
+ {
+ if (!lasttime)
+ lasttime = t;
+ if (t - lasttime < 5)
+ return;
+ }
+
+ lasttime = t;
+
+ dump_workgroups(force_write);
+
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ if(subrec->work_changed)
+ {
+ list_changed = True;
+ break;
+ }
+ }
+
+ if(!list_changed)
+ return;
+
+ updatecount++;
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ pstrcat(fname,"/");
+ pstrcat(fname,SERVER_LIST);
+ pstrcpy(fnamenew,fname);
+ pstrcat(fnamenew,".");
+
+ fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+ if (!fp)
+ {
+ DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
+ fnamenew,strerror(errno)));
+ return;
+ }
+
+ /*
+ * Write out a record for our workgroup. Use the record from the first
+ * subnet.
+ */
+
+ if((work = find_workgroup_on_subnet(FIRST_SUBNET, global_myworkgroup)) == NULL)
+ {
+ DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
+ global_myworkgroup));
+ x_fclose(fp);
+ return;
+ }
+
+ slprintf(tmp,sizeof(tmp)-1, "\"%s\"", work->work_group);
+ x_fprintf(fp, "%-25s ", tmp);
+ x_fprintf(fp, "%08x ", SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", work->local_master_browser_name);
+ x_fprintf(fp, "%-30s", tmp);
+ x_fprintf(fp, "\"%s\"\n", work->work_group);
+
+ /*
+ * We need to do something special for our own names.
+ * This is due to the fact that we may be a local master browser on
+ * one of our broadcast subnets, and a domain master on the unicast
+ * subnet. We iterate over the subnets and only write out the name
+ * once.
+ */
+
+ for (i=0; my_netbios_names[i]; i++)
+ {
+ stype = 0;
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ if((work = find_workgroup_on_subnet( subrec, global_myworkgroup )) == NULL)
+ continue;
+ if((servrec = find_server_in_workgroup( work, my_netbios_names[i])) == NULL)
+ continue;
+
+ stype |= servrec->serv.type;
+ }
+
+ /* Output server details, plus what workgroup they're in. */
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\"", my_netbios_names[i]);
+ x_fprintf(fp, "%-25s ", tmp);
+ x_fprintf(fp, "%08x ", stype);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ",
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ x_fprintf(fp, "%-30s", tmp);
+ x_fprintf(fp, "\"%s\"\n", global_myworkgroup);
+ }
+
+ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ subrec->work_changed = False;
+
+ for (work = subrec->workgrouplist; work ; work = work->next)
+ {
+ /* Write out a workgroup record for a workgroup. */
+ uint32 wg_type = write_this_workgroup_name( subrec, work);
+
+ if(wg_type)
+ {
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\"", work->work_group);
+ x_fprintf(fp, "%-25s ", tmp);
+
+ x_fprintf(fp, "%08x ", wg_type);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", work->local_master_browser_name);
+ x_fprintf(fp, "%-30s", tmp);
+ x_fprintf(fp, "\"%s\"\n", work->work_group);
+ }
+
+ /* Now write out any server records a workgroup may have. */
+
+ for (servrec = work->serverlist; servrec ; servrec = servrec->next)
+ {
+ uint32 serv_type;
+
+ /* We have already written our names here. */
+ if(is_myname(servrec->serv.name))
+ continue;
+
+ serv_type = write_this_server_name(subrec, work, servrec);
+
+ if(serv_type)
+ {
+ /* Output server details, plus what workgroup they're in. */
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\"", servrec->serv.name);
+ x_fprintf(fp, "%-25s ", tmp);
+ x_fprintf(fp, "%08x ", serv_type);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", servrec->serv.comment);
+ x_fprintf(fp, "%-30s", tmp);
+ x_fprintf(fp, "\"%s\"\n", work->work_group);
+ }
+ }
+ }
+ }
+
+ x_fclose(fp);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+ DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
+}
diff --git a/source/nmbd/nmbd_subnetdb.c b/source/nmbd/nmbd_subnetdb.c
new file mode 100644
index 00000000000..3b450f67124
--- /dev/null
+++ b/source/nmbd/nmbd_subnetdb.c
@@ -0,0 +1,395 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+
+/* This is the broadcast subnets database. */
+struct subnet_record *subnetlist = NULL;
+
+/* Extra subnets - keep these separate so enumeration code doesn't
+ run onto it by mistake. */
+
+struct subnet_record *unicast_subnet = NULL;
+struct subnet_record *remote_broadcast_subnet = NULL;
+struct subnet_record *wins_server_subnet = NULL;
+
+extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
+
+/****************************************************************************
+ Add a subnet into the list.
+ **************************************************************************/
+
+static void add_subnet(struct subnet_record *subrec)
+{
+ DLIST_ADD(subnetlist, subrec);
+}
+
+/* ************************************************************************** **
+ * Comparison routine for ordering the splay-tree based namelists assoicated
+ * with each subnet record.
+ *
+ * Input: Item - Pointer to the comparison key.
+ * Node - Pointer to a node the splay tree.
+ *
+ * Output: The return value will be <0 , ==0, or >0 depending upon the
+ * ordinal relationship of the two keys.
+ *
+ * ************************************************************************** **
+ */
+static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
+ {
+ struct name_record *NR = (struct name_record *)Node;
+
+ if( DEBUGLVL( 10 ) )
+ {
+ struct nmb_name *Iname = (struct nmb_name *)Item;
+
+ Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
+ Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
+ memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
+ nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
+ }
+
+ return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
+ } /* namelist_entry_compare */
+
+
+/****************************************************************************
+stop listening on a subnet
+we don't free the record as we don't have proper reference counting for it
+yet and it may be in use by a response record
+ ****************************************************************************/
+void close_subnet(struct subnet_record *subrec)
+{
+ DLIST_REMOVE(subnetlist, subrec);
+
+ if (subrec->dgram_sock != -1) {
+ close(subrec->dgram_sock);
+ subrec->dgram_sock = -1;
+ }
+ if (subrec->nmb_sock != -1) {
+ close(subrec->nmb_sock);
+ subrec->nmb_sock = -1;
+ }
+}
+
+
+
+/****************************************************************************
+ Create a subnet entry.
+ ****************************************************************************/
+
+static struct subnet_record *make_subnet(char *name, enum subnet_type type,
+ struct in_addr myip, struct in_addr bcast_ip,
+ struct in_addr mask_ip)
+{
+ struct subnet_record *subrec = NULL;
+ int nmb_sock, dgram_sock;
+
+ /* Check if we are creating a non broadcast subnet - if so don't create
+ sockets.
+ */
+
+ if(type != NORMAL_SUBNET)
+ {
+ nmb_sock = -1;
+ dgram_sock = -1;
+ }
+ else
+ {
+ /*
+ * Attempt to open the sockets on port 137/138 for this interface
+ * and bind them.
+ * Fail the subnet creation if this fails.
+ */
+
+ if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", global_nmb_port );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ Debug1( "nmbd_subnetdb:make_subnet()\n" );
+ Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
+ Debug1( "for port %d. ", DGRAM_PORT );
+ Debug1( "Error was %s\n", strerror(errno) );
+ }
+ return NULL;
+ }
+
+ /* Make sure we can broadcast from these sockets. */
+ set_socket_options(nmb_sock,"SO_BROADCAST");
+ set_socket_options(dgram_sock,"SO_BROADCAST");
+
+ }
+
+ subrec = (struct subnet_record *)malloc(sizeof(*subrec));
+
+ if (!subrec)
+ {
+ DEBUG(0,("make_subnet: malloc fail !\n"));
+ close(nmb_sock);
+ close(dgram_sock);
+ return(NULL);
+ }
+
+ memset( (char *)subrec, '\0', sizeof(*subrec) );
+ (void)ubi_trInitTree( subrec->namelist,
+ namelist_entry_compare,
+ ubi_trOVERWRITE );
+
+ if((subrec->subnet_name = strdup(name)) == NULL)
+ {
+ DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
+ close(nmb_sock);
+ close(dgram_sock);
+ ZERO_STRUCTP(subrec);
+ SAFE_FREE(subrec);
+ return(NULL);
+ }
+
+ DEBUG(2, ("making subnet name:%s ", name ));
+ DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
+ DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
+
+ subrec->namelist_changed = False;
+ subrec->work_changed = False;
+
+ subrec->bcast_ip = bcast_ip;
+ subrec->mask_ip = mask_ip;
+ subrec->myip = myip;
+ subrec->type = type;
+ subrec->nmb_sock = nmb_sock;
+ subrec->dgram_sock = dgram_sock;
+
+ return subrec;
+}
+
+
+/****************************************************************************
+ Create a normal subnet
+**************************************************************************/
+struct subnet_record *make_normal_subnet(struct interface *iface)
+{
+ struct subnet_record *subrec;
+
+ subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
+ iface->ip, iface->bcast, iface->nmask);
+ if (subrec) {
+ add_subnet(subrec);
+ }
+ return subrec;
+}
+
+
+/****************************************************************************
+ Create subnet entries.
+**************************************************************************/
+
+BOOL create_subnets(void)
+{
+ int num_interfaces = iface_count();
+ int i;
+ struct in_addr unicast_ip, ipzero;
+ extern struct in_addr loopback_ip;
+
+ if(num_interfaces == 0)
+ {
+ DEBUG(0,("create_subnets: No local interfaces !\n"));
+ return False;
+ }
+
+ /*
+ * Create subnets from all the local interfaces and thread them onto
+ * the linked list.
+ */
+
+ for (i = 0 ; i < num_interfaces; i++)
+ {
+ struct interface *iface = get_interface(i);
+
+ /*
+ * We don't want to add a loopback interface, in case
+ * someone has added 127.0.0.1 for smbd, nmbd needs to
+ * ignore it here. JRA.
+ */
+
+ if (ip_equal(iface->ip, loopback_ip)) {
+ DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
+ continue;
+ }
+
+ if (!make_normal_subnet(iface)) return False;
+ }
+
+ /*
+ * If we have been configured to use a WINS server, then try and
+ * get the ip address of it here. If we are the WINS server then
+ * set the unicast subnet address to be the first of our own real
+ * addresses.
+ *
+ * NOTE: I'm not sure of the implications of WINS server failover
+ * on this bit of code. Because of failover, the WINS
+ * server address can change. crh
+ */
+
+ if( wins_srv_count() )
+ {
+ struct in_addr real_wins_ip;
+ real_wins_ip = wins_srv_ip();
+
+ if (!is_zero_ip(real_wins_ip))
+ {
+ unicast_ip = real_wins_ip;
+ }
+ else
+ {
+ /* wins_srv_ip() can return a zero IP if all servers are
+ * either down or incorrectly entered in smb.conf. crh
+ */
+ DEBUG(0,("No 'live' WINS servers found. Check 'wins server' parameter.\n"));
+ return False;
+ }
+ }
+ else if(lp_we_are_a_wins_server())
+ {
+ /* Pick the first interface ip address as the WINS server ip. */
+ unicast_ip = *iface_n_ip(0);
+ }
+ else
+ {
+ /* We should not be using a WINS server at all. Set the
+ ip address of the subnet to be zero. */
+ zero_ip(&unicast_ip);
+ }
+
+ /*
+ * Create the unicast and remote broadcast subnets.
+ * Don't put these onto the linked list.
+ * The ip address of the unicast subnet is set to be
+ * the WINS server address, if it exists, or ipzero if not.
+ */
+
+ unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
+ unicast_ip, unicast_ip, unicast_ip);
+
+ zero_ip(&ipzero);
+
+ remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
+ REMOTE_BROADCAST_SUBNET,
+ ipzero, ipzero, ipzero);
+
+ if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
+ return False;
+
+ /*
+ * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
+ * the linked list.
+ */
+
+ if (lp_we_are_a_wins_server())
+ {
+ if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
+ WINS_SERVER_SUBNET,
+ ipzero, ipzero, ipzero )) == NULL )
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+Function to tell us if we can use the unicast subnet.
+******************************************************************/
+
+BOOL we_are_a_wins_client(void)
+{
+ static int cache_we_are_a_wins_client = -1;
+
+ if(cache_we_are_a_wins_client == -1)
+ cache_we_are_a_wins_client = (is_zero_ip(unicast_subnet->myip) ?
+ False : True);
+
+ return cache_we_are_a_wins_client;
+}
+
+/*******************************************************************
+Access function used by NEXT_SUBNET_INCLUDING_UNICAST
+******************************************************************/
+
+struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
+{
+ if(subrec == unicast_subnet)
+ return NULL;
+ else if((subrec->next == NULL) && we_are_a_wins_client())
+ return unicast_subnet;
+ else
+ return subrec->next;
+}
+
+/*******************************************************************
+ Access function used by retransmit_or_expire_response_records() in
+ nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
+ Needed when we need to enumerate all the broadcast, unicast and
+ WINS subnets.
+******************************************************************/
+
+struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
+{
+ if(subrec == unicast_subnet)
+ {
+ if(wins_server_subnet)
+ return wins_server_subnet;
+ else
+ return NULL;
+ }
+
+ if(wins_server_subnet && subrec == wins_server_subnet)
+ return NULL;
+
+ if((subrec->next == NULL) && we_are_a_wins_client())
+ return unicast_subnet;
+ else
+ return subrec->next;
+}
diff --git a/source/nmbd/nmbd_synclists.c b/source/nmbd/nmbd_synclists.c
new file mode 100644
index 00000000000..f6d1165e576
--- /dev/null
+++ b/source/nmbd/nmbd_synclists.c
@@ -0,0 +1,298 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/* this file handles asynchronous browse synchronisation requests. The
+ requests are done by forking and putting the result in a file in the
+ locks directory. We do it this way because we don't want nmbd to be
+ blocked waiting for some server to respond on a TCP connection. This
+ also allows us to have more than 1 sync going at once (tridge) */
+
+#include "includes.h"
+#include "smb.h"
+
+struct sync_record {
+ struct sync_record *next, *prev;
+ fstring workgroup;
+ fstring server;
+ pstring fname;
+ struct in_addr ip;
+ pid_t pid;
+};
+
+/* a linked list of current sync connections */
+static struct sync_record *syncs;
+
+static XFILE *fp;
+
+/*******************************************************************
+ This is the NetServerEnum callback.
+ Note sname and comment are in UNIX codepage format.
+ ******************************************************************/
+static void callback(const char *sname, uint32 stype,
+ const char *comment, void *state)
+{
+ x_fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment);
+}
+
+/*******************************************************************
+ Synchronise browse lists with another browse server.
+ Log in on the remote server's SMB port to their IPC$ service,
+ do a NetServerEnum and record the results in fname
+******************************************************************/
+static void sync_child(char *name, int nm_type,
+ char *workgroup,
+ struct in_addr ip, BOOL local, BOOL servers,
+ char *fname)
+{
+ extern fstring local_machine;
+ fstring unix_workgroup;
+ static struct cli_state cli;
+ uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
+ struct nmb_name called, calling;
+
+ if (!cli_initialise(&cli) || !cli_connect(&cli, name, &ip)) {
+ return;
+ }
+
+ make_nmb_name(&calling, local_machine, 0x0);
+ make_nmb_name(&called , name , nm_type);
+
+ if (!cli_session_request(&cli, &calling, &called))
+ {
+ cli_shutdown(&cli);
+ return;
+ }
+
+ if (!cli_negprot(&cli)) {
+ cli_shutdown(&cli);
+ return;
+ }
+
+ if (!cli_session_setup(&cli, "", "", 1, "", 0, workgroup)) {
+ cli_shutdown(&cli);
+ return;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ cli_shutdown(&cli);
+ return;
+ }
+
+ /* All the cli_XX functions take UNIX character set. */
+ fstrcpy(unix_workgroup, cli.server_domain?cli.server_domain:workgroup);
+
+ /* Fetch a workgroup list. */
+ cli_NetServerEnum(&cli, unix_workgroup,
+ local_type|SV_TYPE_DOMAIN_ENUM,
+ callback, NULL);
+
+ /* Now fetch a server list. */
+ if (servers) {
+ fstrcpy(unix_workgroup, workgroup);
+ cli_NetServerEnum(&cli, unix_workgroup,
+ local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
+ callback, NULL);
+ }
+
+ cli_shutdown(&cli);
+}
+
+
+/*******************************************************************
+ initialise a browse sync with another browse server. Log in on the
+ remote server's SMB port to their IPC$ service, do a NetServerEnum
+ and record the results
+******************************************************************/
+void sync_browse_lists(struct work_record *work,
+ char *name, int nm_type,
+ struct in_addr ip, BOOL local, BOOL servers)
+{
+ struct sync_record *s;
+ static int counter;
+
+ START_PROFILE(sync_browse_lists);
+ /* Check we're not trying to sync with ourselves. This can
+ happen if we are a domain *and* a local master browser. */
+ if (ismyip(ip)) {
+done:
+ END_PROFILE(sync_browse_lists);
+ return;
+ }
+
+ s = (struct sync_record *)malloc(sizeof(*s));
+ if (!s) goto done;
+
+ ZERO_STRUCTP(s);
+
+ fstrcpy(s->workgroup, work->work_group);
+ fstrcpy(s->server, name);
+ s->ip = ip;
+
+ slprintf(s->fname, sizeof(pstring)-1,
+ "%s/sync.%d", lp_lockdir(), counter++);
+ all_string_sub(s->fname,"//", "/", 0);
+
+ DLIST_ADD(syncs, s);
+
+ /* the parent forks and returns, leaving the child to do the
+ actual sync and call END_PROFILE*/
+ CatchChild();
+ if ((s->pid = sys_fork())) return;
+
+ BlockSignals( False, SIGTERM );
+
+ DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
+ work->work_group, name, inet_ntoa(ip)));
+
+ fp = x_fopen(s->fname,O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (!fp) {
+ END_PROFILE(sync_browse_lists);
+ _exit(1);
+ }
+
+ sync_child(name, nm_type, work->work_group, ip, local, servers,
+ s->fname);
+
+ x_fclose(fp);
+ END_PROFILE(sync_browse_lists);
+ _exit(0);
+}
+
+/**********************************************************************
+handle one line from a completed sync file
+ **********************************************************************/
+static void complete_one(struct sync_record *s,
+ char *sname, uint32 stype, char *comment)
+{
+ struct work_record *work;
+ struct server_record *servrec;
+
+ stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (stype & SV_TYPE_DOMAIN_ENUM) {
+ /* See if we can find the workgroup on this subnet. */
+ if((work=find_workgroup_on_subnet(unicast_subnet, sname))) {
+ /* We already know about this workgroup -
+ update the ttl. */
+ update_workgroup_ttl(work,lp_max_ttl());
+ } else {
+ /* Create the workgroup on the subnet. */
+ work = create_workgroup_on_subnet(unicast_subnet,
+ sname, lp_max_ttl());
+ if (work) {
+ /* remember who the master is */
+ fstrcpy(work->local_master_browser_name,
+ comment);
+ }
+ }
+ return;
+ }
+
+ work = find_workgroup_on_subnet(unicast_subnet, s->workgroup);
+ if (!work) {
+ DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n",
+ s->workgroup));
+ return;
+ }
+
+ if ((servrec = find_server_in_workgroup( work, sname))) {
+ /* Check that this is not a locally known
+ server - if so ignore the entry. */
+ if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) {
+ /* We already know about this server - update
+ the ttl. */
+ update_server_ttl(servrec, lp_max_ttl());
+ /* Update the type. */
+ servrec->serv.type = stype;
+ }
+ return;
+ }
+
+ /* Create the server in the workgroup. */
+ create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
+}
+
+
+/**********************************************************************
+read the completed sync info
+ **********************************************************************/
+static void complete_sync(struct sync_record *s)
+{
+ XFILE *f;
+ fstring server, type_str;
+ unsigned type;
+ pstring comment;
+ pstring line;
+ char *ptr;
+ int count=0;
+
+ f = x_fopen(s->fname,O_RDONLY, 0);
+
+ if (!f) return;
+
+ while (!x_feof(f)) {
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ ptr = line;
+
+ if (!next_token(&ptr,server,NULL,sizeof(server)) ||
+ !next_token(&ptr,type_str,NULL, sizeof(type_str)) ||
+ !next_token(&ptr,comment,NULL, sizeof(comment))) {
+ continue;
+ }
+
+ sscanf(type_str, "%X", &type);
+
+ complete_one(s, server, type, comment);
+
+ count++;
+ }
+
+ x_fclose(f);
+
+ unlink(s->fname);
+
+ DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n",
+ s->server, inet_ntoa(s->ip), s->workgroup, count));
+}
+
+/**********************************************************************
+check for completion of any of the child processes
+ **********************************************************************/
+void sync_check_completion(void)
+{
+ struct sync_record *s, *next;
+
+ for (s=syncs;s;s=next) {
+ next = s->next;
+ if (!process_exists(s->pid)) {
+ /* it has completed - grab the info */
+ complete_sync(s);
+ DLIST_REMOVE(syncs, s);
+ ZERO_STRUCTP(s);
+ SAFE_FREE(s);
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_winsproxy.c b/source/nmbd/nmbd_winsproxy.c
new file mode 100644
index 00000000000..84102289587
--- /dev/null
+++ b/source/nmbd/nmbd_winsproxy.c
@@ -0,0 +1,222 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+Function called when the name lookup succeeded.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_success( struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname, struct in_addr ip, struct res_rec *rrec)
+{
+ struct packet_struct *original_packet;
+ struct subnet_record *orig_broadcast_subnet;
+ struct name_record *namerec;
+ uint16 nb_flags;
+ int num_ips;
+ int i;
+ int ttl = 3600; /* By default one hour in the cache. */
+ struct in_addr *iplist;
+
+ /* Extract the original packet and the original broadcast subnet from
+ the userdata. */
+
+ memcpy( (char *)&orig_broadcast_subnet, userdata->data, sizeof(struct subnet_record *) );
+ memcpy( (char *)&original_packet, &userdata->data[sizeof(struct subnet_record *)],
+ sizeof(struct packet_struct *) );
+
+ nb_flags = get_nb_flags( rrec->rdata );
+
+ num_ips = rrec->rdlength / 6;
+ if(num_ips == 0)
+ {
+ DEBUG(0,("wins_proxy_name_query_request_success: Invalid number of IP records (0) \
+returned for name %s.\n", nmb_namestr(nmbname) ));
+ return;
+ }
+
+ if(num_ips == 1)
+ iplist = &ip;
+ else
+ {
+ if((iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) )) == NULL)
+ {
+ DEBUG(0,("wins_proxy_name_query_request_success: malloc fail !\n"));
+ return;
+ }
+
+ for(i = 0; i < num_ips; i++)
+ putip( (char *)&iplist[i], (char *)&rrec->rdata[ (i*6) + 2]);
+ }
+
+ /* Add the queried name to the original subnet as a WINS_PROXY_NAME. */
+
+ if(rrec == PERMANENT_TTL)
+ ttl = lp_max_ttl();
+
+ namerec = add_name_to_subnet( orig_broadcast_subnet, nmbname->name,
+ nmbname->name_type, nb_flags, ttl,
+ WINS_PROXY_NAME, num_ips, iplist );
+
+ if(iplist != &ip)
+ SAFE_FREE(iplist);
+
+ /*
+ * Check that none of the IP addresses we are returning is on the
+ * same broadcast subnet as the original requesting packet. If it
+ * is then don't reply (although we still need to add the name
+ * to the cache) as the actual machine will be replying also
+ * and we don't want two replies to a broadcast query.
+ */
+
+ if(namerec && original_packet->packet.nmb.header.nm_flags.bcast)
+ {
+ for( i = 0; i < namerec->data.num_ips; i++)
+ {
+ if( same_net( namerec->data.ip[i],
+ orig_broadcast_subnet->myip,
+ orig_broadcast_subnet->mask_ip ) )
+ {
+ DEBUG( 5, ( "wins_proxy_name_query_request_success: name %s is a WINS \
+proxy name and is also on the same subnet (%s) as the requestor. \
+Not replying.\n",
+ nmb_namestr(&namerec->name),
+ orig_broadcast_subnet->subnet_name ) );
+ return;
+ }
+ }
+ }
+
+ /* Finally reply to the original name query. */
+ reply_netbios_packet(original_packet, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rrec->rdata, /* data to send. */
+ rrec->rdlength); /* data length. */
+}
+
+/****************************************************************************
+Function called when the name lookup failed.
+****************************************************************************/
+
+static void wins_proxy_name_query_request_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name, int fail_code)
+{
+ DEBUG(4,("wins_proxy_name_query_request_fail: WINS server returned error code %d for lookup \
+of name %s.\n", fail_code, nmb_namestr(question_name) ));
+}
+
+/****************************************************************************
+Function to make a deep copy of the userdata we will need when the WINS
+proxy query returns.
+****************************************************************************/
+
+static struct userdata_struct *wins_proxy_userdata_copy_fn(struct userdata_struct *userdata)
+{
+ struct packet_struct *p, *copy_of_p;
+ struct userdata_struct *new_userdata =
+ (struct userdata_struct *)malloc( userdata->userdata_len );
+
+ if(new_userdata == NULL)
+ return NULL;
+
+ new_userdata->copy_fn = userdata->copy_fn;
+ new_userdata->free_fn = userdata->free_fn;
+ new_userdata->userdata_len = userdata->userdata_len;
+
+ /* Copy the subnet_record pointer. */
+ memcpy( new_userdata->data, userdata->data, sizeof(struct subnet_record *) );
+
+ /* Extract the pointer to the packet struct */
+ memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
+ sizeof(struct packet_struct *) );
+
+ /* Do a deep copy of the packet. */
+ if((copy_of_p = copy_packet(p)) == NULL)
+ {
+ SAFE_FREE(new_userdata);
+ return NULL;
+ }
+
+ /* Lock the copy. */
+ copy_of_p->locked = True;
+
+ memcpy( &new_userdata->data[sizeof(struct subnet_record *)], (char *)&copy_of_p,
+ sizeof(struct packet_struct *) );
+
+ return new_userdata;
+}
+
+/****************************************************************************
+Function to free the deep copy of the userdata we used when the WINS
+proxy query returned.
+****************************************************************************/
+
+static void wins_proxy_userdata_free_fn(struct userdata_struct *userdata)
+{
+ struct packet_struct *p;
+
+ /* Extract the pointer to the packet struct */
+ memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
+ sizeof(struct packet_struct *));
+
+ /* Unlock the packet. */
+ p->locked = False;
+
+ free_packet(p);
+ ZERO_STRUCTP(userdata);
+ SAFE_FREE(userdata);
+}
+
+/****************************************************************************
+ Make a WINS query on behalf of a broadcast client name query request.
+****************************************************************************/
+
+void make_wins_proxy_name_query_request( struct subnet_record *subrec,
+ struct packet_struct *incoming_packet,
+ struct nmb_name *question_name)
+{
+ long *ud[(sizeof(struct userdata_struct) + sizeof(struct subrec *) +
+ sizeof(struct packet_struct *))/sizeof(long *) + 1];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ memset(ud, '\0', sizeof(ud));
+
+ userdata->copy_fn = wins_proxy_userdata_copy_fn;
+ userdata->free_fn = wins_proxy_userdata_free_fn;
+ userdata->userdata_len = sizeof(ud);
+ memcpy( userdata->data, (char *)&subrec, sizeof(struct subnet_record *));
+ memcpy( &userdata->data[sizeof(struct subnet_record *)], (char *)&incoming_packet,
+ sizeof(struct packet_struct *));
+
+ /* Now use the unicast subnet to query the name with the WINS server. */
+ query_name( unicast_subnet, question_name->name, question_name->name_type,
+ wins_proxy_name_query_request_success,
+ wins_proxy_name_query_request_fail,
+ userdata);
+}
diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c
new file mode 100644
index 00000000000..ecb5f2da55b
--- /dev/null
+++ b/source/nmbd/nmbd_winsserver.c
@@ -0,0 +1,1659 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+#define WINS_LIST "wins.dat"
+#define WINS_VERSION 1
+
+/****************************************************************************
+possibly call the WINS hook external program when a WINS change is made
+*****************************************************************************/
+static void wins_hook(char *operation, struct name_record *namerec, int ttl)
+{
+ pstring command;
+ char *cmd = lp_wins_hook();
+ char *p;
+ int i;
+
+ if (!cmd || !*cmd) return;
+
+ for (p=namerec->name.name; *p; p++) {
+ if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
+ DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
+ return;
+ }
+ }
+
+ p = command;
+ p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d",
+ cmd,
+ operation,
+ namerec->name.name,
+ namerec->name.name_type,
+ ttl);
+
+ for (i=0;i<namerec->data.num_ips;i++) {
+ p += slprintf(p, sizeof(command) - (p-command) -1, " %s", inet_ntoa(namerec->data.ip[i]));
+ }
+
+ DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
+ smbrun(command, NULL);
+}
+
+
+/****************************************************************************
+hash our interfaces and netbios names settings
+*****************************************************************************/
+static unsigned wins_hash(void)
+{
+ int i;
+ unsigned ret = iface_hash();
+ extern char **my_netbios_names;
+
+ for (i=0;my_netbios_names[i];i++)
+ ret ^= str_checksum(my_netbios_names[i]);
+
+ ret ^= str_checksum(lp_workgroup());
+
+ return ret;
+}
+
+
+/****************************************************************************
+Determine if this packet should be allocated to the WINS server.
+*****************************************************************************/
+
+BOOL packet_is_for_wins_server(struct packet_struct *packet)
+{
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ /* Only unicast packets go to a WINS server. */
+ if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True))
+ {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
+ return False;
+ }
+
+ /* Check for node status requests. */
+ if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY)
+ return False;
+
+ switch(nmb->header.opcode)
+ {
+ /*
+ * A WINS server issues WACKS, not receives them.
+ */
+ case NMB_WACK_OPCODE:
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
+ return False;
+ /*
+ * A WINS server only processes registration and
+ * release requests, not responses.
+ */
+ case NMB_NAME_REG_OPCODE:
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
+ case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
+ if(nmb->header.response)
+ {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
+ return False;
+ }
+ break;
+
+ case NMB_NAME_RELEASE_OPCODE:
+ if(nmb->header.response)
+ {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
+ return False;
+ }
+ break;
+
+ /*
+ * Only process unicast name queries with rd = 1.
+ */
+ case NMB_NAME_QUERY_OPCODE:
+ if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired)
+ {
+ DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
+ return False;
+ }
+ break;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+Utility function to decide what ttl to give a register/refresh request.
+*****************************************************************************/
+
+static int get_ttl_from_packet(struct nmb_packet *nmb)
+{
+ int ttl = nmb->additional->ttl;
+
+ if(ttl < lp_min_wins_ttl() )
+ ttl = lp_min_wins_ttl();
+
+ if(ttl > lp_max_wins_ttl() )
+ ttl = lp_max_wins_ttl();
+
+ return ttl;
+}
+
+/****************************************************************************
+Load or create the WINS database.
+*****************************************************************************/
+
+BOOL initialise_wins(void)
+{
+ time_t time_now = time(NULL);
+ XFILE *fp;
+ pstring line;
+
+ if(!lp_we_are_a_wins_server())
+ return True;
+
+ add_samba_names_to_subnet(wins_server_subnet);
+
+ if((fp = x_fopen(lock_path(WINS_LIST),O_RDONLY, 0)) == NULL)
+ {
+ DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
+ WINS_LIST, strerror(errno) ));
+ return True;
+ }
+
+ while (!x_feof(fp))
+ {
+ pstring name_str, ip_str, ttl_str, nb_flags_str;
+ unsigned int num_ips;
+ pstring name;
+ struct in_addr *ip_list;
+ int type = 0;
+ int nb_flags;
+ int ttl;
+ char *ptr;
+ char *p;
+ BOOL got_token;
+ BOOL was_ip;
+ int i;
+ unsigned hash;
+ int version;
+
+ /* Read a line from the wins.dat file. Strips whitespace
+ from the beginning and end of the line.
+ */
+ if (!fgets_slash(line,sizeof(pstring),fp))
+ continue;
+
+ if (*line == '#')
+ continue;
+
+ if (strncmp(line,"VERSION ", 8) == 0) {
+ if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
+ version != WINS_VERSION ||
+ hash != wins_hash()) {
+ DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
+ x_fclose(fp);
+ return True;
+ }
+ continue;
+ }
+
+ ptr = line;
+
+ /*
+ * Now we handle multiple IP addresses per name we need
+ * to iterate over the line twice. The first time to
+ * determine how many IP addresses there are, the second
+ * time to actually parse them into the ip_list array.
+ */
+
+ if (!next_token(&ptr,name_str,NULL,sizeof(name_str)))
+ {
+ DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
+ continue;
+ }
+
+ if (!next_token(&ptr,ttl_str,NULL,sizeof(ttl_str)))
+ {
+ DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
+ continue;
+ }
+
+ /*
+ * Determine the number of IP addresses per line.
+ */
+ num_ips = 0;
+ do
+ {
+ got_token = next_token(&ptr,ip_str,NULL,sizeof(ip_str));
+ was_ip = False;
+
+ if(got_token && strchr_m(ip_str, '.'))
+ {
+ num_ips++;
+ was_ip = True;
+ }
+ } while( got_token && was_ip);
+
+ if(num_ips == 0)
+ {
+ DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
+ continue;
+ }
+
+ if(!got_token)
+ {
+ DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
+ continue;
+ }
+
+ /* Allocate the space for the ip_list. */
+ if((ip_list = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr))) == NULL)
+ {
+ DEBUG(0,("initialise_wins: Malloc fail !\n"));
+ return False;
+ }
+
+ /* Reset and re-parse the line. */
+ ptr = line;
+ next_token(&ptr,name_str,NULL,sizeof(name_str));
+ next_token(&ptr,ttl_str,NULL,sizeof(ttl_str));
+ for(i = 0; i < num_ips; i++)
+ {
+ next_token(&ptr, ip_str, NULL, sizeof(ip_str));
+ ip_list[i] = *interpret_addr2(ip_str);
+ }
+ next_token(&ptr,nb_flags_str,NULL, sizeof(nb_flags_str));
+
+ /*
+ * Deal with SELF or REGISTER name encoding. Default is REGISTER
+ * for compatibility with old nmbds.
+ */
+
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'S')
+ {
+ DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
+ SAFE_FREE(ip_list);
+ continue;
+ }
+
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'R')
+ nb_flags_str[strlen(nb_flags_str)-1] = '\0';
+
+ /* Netbios name. # divides the name from the type (hex): netbios#xx */
+ pstrcpy(name,name_str);
+
+ if((p = strchr_m(name,'#')) != NULL)
+ {
+ *p = 0;
+ sscanf(p+1,"%x",&type);
+ }
+
+ /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
+ sscanf(nb_flags_str,"%x",&nb_flags);
+ sscanf(ttl_str,"%d",&ttl);
+
+ /* add all entries that have 60 seconds or more to live */
+ if ((ttl - 60) > time_now || ttl == PERMANENT_TTL)
+ {
+ if(ttl != PERMANENT_TTL)
+ ttl -= time_now;
+
+ DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
+ name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+
+ (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
+ ttl, REGISTER_NAME, num_ips, ip_list );
+
+ }
+ else
+ {
+ DEBUG(4, ("initialise_wins: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
+ name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
+ }
+
+ SAFE_FREE(ip_list);
+ }
+
+ x_fclose(fp);
+ return True;
+}
+
+/****************************************************************************
+Send a WINS WACK (Wait ACKnowledgement) response.
+**************************************************************************/
+
+static void send_wins_wack_response(int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ unsigned char rdata[2];
+
+ rdata[0] = rdata[1] = 0;
+
+ /* Taken from nmblib.c - we need to send back almost
+ identical bytes from the requesting packet header. */
+
+ rdata[0] = (nmb->header.opcode & 0xF) << 3;
+ if (nmb->header.nm_flags.authoritative &&
+ nmb->header.response) rdata[0] |= 0x4;
+ if (nmb->header.nm_flags.trunc) rdata[0] |= 0x2;
+ if (nmb->header.nm_flags.recursion_desired) rdata[0] |= 0x1;
+ if (nmb->header.nm_flags.recursion_available &&
+ nmb->header.response) rdata[1] |= 0x80;
+ if (nmb->header.nm_flags.bcast) rdata[1] |= 0x10;
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ NMB_WAIT_ACK, /* nmbd type code. */
+ NMB_WACK_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ (char *)rdata, /* data to send. */
+ 2); /* data length. */
+}
+
+/****************************************************************************
+Send a WINS name registration response.
+**************************************************************************/
+
+static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ WINS_REG, /* nmbd type code. */
+ NMB_NAME_REG_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name refresh request to a WINS server.
+************************************************************************/
+
+void wins_process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ BOOL group = (nb_flags & NB_GROUP) ? True : False;
+ struct name_record *namerec = NULL;
+ int ttl = get_ttl_from_packet(nmb);
+ struct in_addr from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast)
+ {
+ /*
+ * We should only get unicast name refresh packets here.
+ * Anyone trying to refresh broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_name_refresh_request: broadcast name refresh request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s \
+IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * If this is a refresh request and the name doesn't exist then
+ * treat it like a registration request. This allows us to recover
+ * from errors (tridge)
+ */
+
+ if(namerec == NULL)
+ {
+ DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s and \
+the name does not exist. Treating as registration.\n", nmb_namestr(question) ));
+ wins_process_name_registration_request(subrec,p);
+ return;
+ }
+
+ /*
+ * Check that the group bits for the refreshing name and the
+ * name in our database match.
+ */
+
+ if((namerec != NULL) && ((group && !NAME_GROUP(namerec)) || (!group && NAME_GROUP(namerec))) )
+ {
+ DEBUG(3,("wins_process_name_refresh_request: Name %s group bit = %s \
+does not match group bit in WINS for this name.\n", nmb_namestr(question), group ? "True" : "False" ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * For a unique name check that the person refreshing the name is one of the registered IP
+ * addresses. If not - fail the refresh. Do the same for group names with a type of 0x1c.
+ * Just return success for unique 0x1d refreshes. For normal group names update the ttl
+ * and return success.
+ */
+
+ if((!group || (group && (question->name_type == 0x1c))) && find_ip_in_name_record(namerec, from_ip ))
+ {
+ /*
+ * Update the ttl.
+ */
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ wins_hook("refresh", namerec, ttl);
+ return;
+ }
+ else if(group)
+ {
+ /*
+ * Normal groups are all registered with an IP address of 255.255.255.255
+ * so we can't search for the IP address.
+ */
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ else if(!group && (question->name_type == 0x1d))
+ {
+ /*
+ * Special name type - just pretend the refresh succeeded.
+ */
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ else
+ {
+ /*
+ * Fail the refresh.
+ */
+
+ DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s with IP %s and \
+is IP is not known to the name.\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+}
+
+/***********************************************************************
+ Deal with a name registration request query success to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The success here is actually a failure as it means
+ the client we queried wants to keep the name, so we must return
+ a registration failure to the original requestor.
+************************************************************************/
+
+static void wins_register_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *question_name,
+ struct in_addr ip,
+ struct res_rec *answers)
+{
+ struct packet_struct *orig_reg_packet;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
+name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
+
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request query failure to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer. The failure here is actually a success as it means
+ the client we queried didn't want to keep the name, so we can remove
+ the old name record and then successfully add the new name.
+************************************************************************/
+
+static void wins_register_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name,
+ int rcode)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+ struct packet_struct *orig_reg_packet;
+ struct name_record *namerec = NULL;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ /*
+ * We want to just add the name, as we now know the original owner
+ * didn't want it. But we can't just do that as an arbitary
+ * amount of time may have taken place between the name query
+ * request and this timeout/error response. So we check that
+ * the name still exists and is in the same state - if so
+ * we remove it and call wins_process_name_registration_request()
+ * as we know it will do the right thing now.
+ */
+
+ namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
+
+ if( (namerec != NULL)
+ && (namerec->data.source == REGISTER_NAME)
+ && ip_equal(rrec->packet->ip, *namerec->data.ip) )
+ {
+ remove_name_from_namelist( subrec, namerec);
+ namerec = NULL;
+ }
+
+ if(namerec == NULL)
+ wins_process_name_registration_request(subrec, orig_reg_packet);
+ else
+ DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between \
+querying for name %s in order to replace it and this reply.\n", nmb_namestr(question_name) ));
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request to a WINS server.
+
+ Use the following pseudocode :
+
+ registering_group
+ |
+ |
+ +--------name exists
+ | |
+ | |
+ | +--- existing name is group
+ | | |
+ | | |
+ | | +--- add name (return).
+ | |
+ | |
+ | +--- exiting name is unique
+ | |
+ | |
+ | +--- query existing owner (return).
+ |
+ |
+ +--------name doesn't exist
+ |
+ |
+ +--- add name (return).
+
+ registering_unique
+ |
+ |
+ +--------name exists
+ | |
+ | |
+ | +--- existing name is group
+ | | |
+ | | |
+ | | +--- fail add (return).
+ | |
+ | |
+ | +--- exiting name is unique
+ | |
+ | |
+ | +--- query existing owner (return).
+ |
+ |
+ +--------name doesn't exist
+ |
+ |
+ +--- add name (return).
+
+ As can be seen from the above, the two cases may be collapsed onto each
+ other with the exception of the case where the name already exists and
+ is a group name. This case we handle with an if statement.
+
+************************************************************************/
+
+void wins_process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ int ttl = get_ttl_from_packet(nmb);
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast)
+ {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
+IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * Deal with the case where the name found was a dns entry.
+ * Remove it as we now have a NetBIOS client registering the
+ * name.
+ */
+
+ if( (namerec != NULL)
+ && ( (namerec->data.source == DNS_NAME)
+ || (namerec->data.source == DNSFAIL_NAME) ) )
+ {
+ DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
+a dns lookup - removing it.\n", nmb_namestr(question) ));
+ remove_name_from_namelist( subrec, namerec );
+ namerec = NULL;
+ }
+
+ /*
+ * Reject if the name exists and is not a REGISTER_NAME.
+ * (ie. Don't allow any static names to be overwritten.
+ */
+
+ if((namerec != NULL) && (namerec->data.source != REGISTER_NAME))
+ {
+ DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
+to register name %s. Name already exists in WINS with source type %d.\n",
+ nmb_namestr(question), namerec->data.source ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * Special policy decisions based on MS documentation.
+ * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
+ * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
+ */
+
+ /*
+ * A group name is always added as the local broadcast address, except
+ * for group names ending in 0x1c.
+ * Group names with type 0x1c are registered with individual IP addresses.
+ */
+
+ if(registering_group_name && (question->name_type != 0x1c))
+ from_ip = *interpret_addr2("255.255.255.255");
+
+ /*
+ * Ignore all attempts to register a unique 0x1d name, although return success.
+ */
+
+ if(!registering_group_name && (question->name_type == 0x1d))
+ {
+ DEBUG(3,("wins_process_name_registration_request: Ignoring request \
+to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+
+ /*
+ * Next two cases are the 'if statement' mentioned above.
+ */
+
+ if((namerec != NULL) && NAME_GROUP(namerec))
+ {
+ if(registering_group_name)
+ {
+ /*
+ * If we are adding a group name, the name exists and is also a group entry just add this
+ * IP address to it and update the ttl.
+ */
+
+ DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
+ inet_ntoa(from_ip), nmb_namestr(question) ));
+ /*
+ * Check the ip address is not already in the group.
+ */
+ if(!find_ip_in_name_record(namerec, from_ip))
+ add_ip_to_name_record(namerec, from_ip);
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ else
+ {
+ /*
+ * If we are adding a unique name, the name exists in the WINS db
+ * and is a group name then reject the registration.
+ */
+
+ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+ }
+
+ /*
+ * From here on down we know that if the name exists in the WINS db it is
+ * a unique name, not a group name.
+ */
+
+ /*
+ * If the name exists and is one of our names then check the
+ * registering IP address. If it's not one of ours then automatically
+ * reject without doing the query - we know we will reject it.
+ */
+
+ if((namerec != NULL) && (is_myname(namerec->name.name)) )
+ {
+ if(!ismyip(from_ip))
+ {
+ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+ else
+ {
+ /*
+ * It's one of our names and one of our IP's - update the ttl.
+ */
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ wins_hook("refresh", namerec, ttl);
+ return;
+ }
+ }
+
+ /*
+ * If the name exists and it is a unique registration and the registering IP
+ * is the same as the the (single) already registered IP then just update the ttl.
+ */
+
+ if( !registering_group_name
+ && (namerec != NULL)
+ && (namerec->data.num_ips == 1)
+ && ip_equal( namerec->data.ip[0], from_ip ) )
+ {
+ update_name_ttl( namerec, ttl );
+ send_wins_name_registration_response( 0, ttl, p );
+ wins_hook("refresh", namerec, ttl);
+ return;
+ }
+
+ /*
+ * Finally if the name exists do a query to the registering machine
+ * to see if they still claim to have the name.
+ */
+
+ if( namerec != NULL )
+ {
+ long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ /*
+ * First send a WACK to the registering machine.
+ */
+
+ send_wins_wack_response(60, p);
+
+ /*
+ * When the reply comes back we need the original packet.
+ * Lock this so it won't be freed and then put it into
+ * the userdata structure.
+ */
+
+ p->locked = True;
+
+ userdata = (struct userdata_struct *)ud;
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(struct packet_struct *);
+ memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+ /*
+ * Use the new call to send a query directly to an IP address.
+ * This sends the query directly to the IP address, and ensures
+ * the recursion desired flag is not set (you were right Luke :-).
+ * This function should *only* be called from the WINS server
+ * code. JRA.
+ */
+
+ query_name_from_wins_server( *namerec->data.ip,
+ question->name,
+ question->name_type,
+ wins_register_query_success,
+ wins_register_query_fail,
+ userdata );
+ return;
+ }
+
+ /*
+ * Name did not exist - add it.
+ */
+
+ (void)add_name_to_subnet( subrec, question->name, question->name_type,
+ nb_flags, ttl, REGISTER_NAME, 1, &from_ip );
+ if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
+ wins_hook("add", namerec, ttl);
+ }
+
+ send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Deal with a mutihomed name query success to the machine that
+ requested the multihomed name registration.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer.
+************************************************************************/
+
+static void wins_multihomed_register_query_success(struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *question_name,
+ struct in_addr ip,
+ struct res_rec *answers)
+{
+ struct packet_struct *orig_reg_packet;
+ struct nmb_packet *nmb;
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ int ttl;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ nmb = &orig_reg_packet->packet.nmb;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ ttl = get_ttl_from_packet(nmb);
+
+ /*
+ * We want to just add the new IP, as we now know the requesting
+ * machine claims to own it. But we can't just do that as an arbitary
+ * amount of time may have taken place between the name query
+ * request and this response. So we check that
+ * the name still exists and is in the same state - if so
+ * we just add the extra IP and update the ttl.
+ */
+
+ namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
+
+ if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) )
+ {
+ DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
+a subsequent IP addess.\n", nmb_namestr(question_name) ));
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+
+ return;
+ }
+
+ if(!find_ip_in_name_record(namerec, from_ip))
+ add_ip_to_name_record(namerec, from_ip);
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, orig_reg_packet);
+ wins_hook("add", namerec, ttl);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+}
+
+/***********************************************************************
+ Deal with a name registration request query failure to a client that
+ owned the name.
+
+ We have a locked pointer to the original packet stashed away in the
+ userdata pointer.
+************************************************************************/
+
+static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *question_name,
+ int rcode)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+ struct packet_struct *orig_reg_packet;
+
+ memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
+
+ DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
+query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
+ send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
+
+ orig_reg_packet->locked = False;
+ free_packet(orig_reg_packet);
+ return;
+}
+
+/***********************************************************************
+ Deal with a multihomed name registration request to a WINS server.
+ These cannot be group name registrations.
+***********************************************************************/
+
+void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ int ttl = get_ttl_from_packet(nmb);
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ BOOL group = (nb_flags & NB_GROUP) ? True : False;;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast)
+ {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ /*
+ * Only unique names should be registered multihomed.
+ */
+
+ if(group)
+ {
+ DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
+received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
+IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * Deal with policy regarding 0x1d names.
+ */
+
+ if(question->name_type == 0x1d)
+ {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
+to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /*
+ * Deal with the case where the name found was a dns entry.
+ * Remove it as we now have a NetBIOS client registering the
+ * name.
+ */
+
+ if( (namerec != NULL)
+ && ( (namerec->data.source == DNS_NAME)
+ || (namerec->data.source == DNSFAIL_NAME) ) )
+ {
+ DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
+- removing it.\n", nmb_namestr(question) ));
+ remove_name_from_namelist( subrec, namerec);
+ namerec = NULL;
+ }
+
+ /*
+ * Reject if the name exists and is not a REGISTER_NAME.
+ * (ie. Don't allow any static names to be overwritten.
+ */
+
+ if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) )
+ {
+ DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
+to register name %s. Name already exists in WINS with source type %d.\n",
+ nmb_namestr(question), namerec->data.source ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * Reject if the name exists and is a GROUP name.
+ */
+
+ if((namerec != NULL) && NAME_GROUP(namerec))
+ {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+
+ /*
+ * From here on down we know that if the name exists in the WINS db it is
+ * a unique name, not a group name.
+ */
+
+ /*
+ * If the name exists and is one of our names then check the
+ * registering IP address. If it's not one of ours then automatically
+ * reject without doing the query - we know we will reject it.
+ */
+
+ if((namerec != NULL) && (is_myname(namerec->name.name)) )
+ {
+ if(!ismyip(from_ip))
+ {
+ DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
+is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ }
+ else
+ {
+ /*
+ * It's one of our names and one of our IP's. Ensure the IP is in the record and
+ * update the ttl.
+ */
+ if(!find_ip_in_name_record(namerec, from_ip)) {
+ add_ip_to_name_record(namerec, from_ip);
+ wins_hook("add", namerec, ttl);
+ } else {
+ wins_hook("refresh", namerec, ttl);
+ }
+
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
+ }
+
+ /*
+ * If the name exists check if the IP address is already registered
+ * to that name. If so then update the ttl and reply success.
+ */
+
+ if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip))
+ {
+ update_name_ttl(namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ wins_hook("refresh", namerec, ttl);
+ return;
+ }
+
+ /*
+ * If the name exists do a query to the owner
+ * to see if they still want the name.
+ */
+
+ if(namerec != NULL)
+ {
+ long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ /*
+ * First send a WACK to the registering machine.
+ */
+
+ send_wins_wack_response(60, p);
+
+ /*
+ * When the reply comes back we need the original packet.
+ * Lock this so it won't be freed and then put it into
+ * the userdata structure.
+ */
+
+ p->locked = True;
+
+ userdata = (struct userdata_struct *)ud;
+
+ userdata->copy_fn = NULL;
+ userdata->free_fn = NULL;
+ userdata->userdata_len = sizeof(struct packet_struct *);
+ memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
+
+ /*
+ * Use the new call to send a query directly to an IP address.
+ * This sends the query directly to the IP address, and ensures
+ * the recursion desired flag is not set (you were right Luke :-).
+ * This function should *only* be called from the WINS server
+ * code. JRA.
+ *
+ * Note that this packet is sent to the current owner of the name,
+ * not the person who sent the packet
+ */
+
+ query_name_from_wins_server( namerec->data.ip[0],
+ question->name,
+ question->name_type,
+ wins_multihomed_register_query_success,
+ wins_multihomed_register_query_fail,
+ userdata );
+
+ return;
+ }
+
+ /*
+ * Name did not exist - add it.
+ */
+
+ (void)add_name_to_subnet( subrec, question->name, question->name_type,
+ nb_flags, ttl, REGISTER_NAME, 1, &from_ip );
+
+ if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
+ wins_hook("add", namerec, ttl);
+ }
+
+ send_wins_name_registration_response(0, ttl, p);
+}
+
+/***********************************************************************
+ Deal with the special name query for *<1b>.
+***********************************************************************/
+
+static void process_wins_dmb_query_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct name_record *namerec = NULL;
+ char *prdata;
+ int num_ips;
+
+ /*
+ * Go through all the names in the WINS db looking for those
+ * ending in <1b>. Use this to calculate the number of IP
+ * addresses we need to return.
+ */
+
+ num_ips = 0;
+ for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = (struct name_record *)ubi_trNext( namerec ) )
+ {
+ if( namerec->name.name_type == 0x1b )
+ num_ips += namerec->data.num_ips;
+ }
+
+ if(num_ips == 0)
+ {
+ /*
+ * There are no 0x1b names registered. Return name query fail.
+ */
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+ return;
+ }
+
+ if((prdata = (char *)malloc( num_ips * 6 )) == NULL)
+ {
+ DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
+ return;
+ }
+
+ /*
+ * Go through all the names again in the WINS db looking for those
+ * ending in <1b>. Add their IP addresses into the list we will
+ * return.
+ */
+
+ num_ips = 0;
+ for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = (struct name_record *)ubi_trNext( namerec ) )
+ {
+ if(namerec->name.name_type == 0x1b)
+ {
+ int i;
+ for(i = 0; i < namerec->data.num_ips; i++)
+ {
+ set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
+ putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
+ num_ips++;
+ }
+ }
+ }
+
+ /*
+ * Send back the reply containing the IP list.
+ */
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ 0, /* Result code. */
+ WINS_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ lp_min_wins_ttl(), /* ttl. */
+ prdata, /* data to send. */
+ num_ips*6); /* data length. */
+
+ SAFE_FREE(prdata);
+}
+
+/****************************************************************************
+Send a WINS name query response.
+**************************************************************************/
+
+void send_wins_name_query_response(int rcode, struct packet_struct *p,
+ struct name_record *namerec)
+{
+ char rdata[6];
+ char *prdata = rdata;
+ int reply_data_len = 0;
+ int ttl = 0;
+ int i;
+
+ memset(rdata,'\0',6);
+
+ if(rcode == 0)
+ {
+ ttl = (namerec->data.death_time != PERMANENT_TTL) ?
+ namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
+
+ /* Copy all known ip addresses into the return data. */
+ /* Optimise for the common case of one IP address so
+ we don't need a malloc. */
+
+ if( namerec->data.num_ips == 1 )
+ prdata = rdata;
+ else
+ {
+ if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL)
+ {
+ DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
+ return;
+ }
+ }
+
+ for(i = 0; i < namerec->data.num_ips; i++)
+ {
+ set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
+ putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
+ }
+
+ sort_query_replies(prdata, i, p->ip);
+
+ reply_data_len = namerec->data.num_ips * 6;
+ }
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ WINS_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ prdata, /* data to send. */
+ reply_data_len); /* data length. */
+
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+}
+
+/***********************************************************************
+ Deal with a name query.
+***********************************************************************/
+
+void wins_process_name_query_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ struct name_record *namerec = NULL;
+
+ DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
+ nmb_namestr(question), inet_ntoa(p->ip) ));
+
+ /*
+ * Special name code. If the queried name is *<1b> then search
+ * the entire WINS database and return a list of all the IP addresses
+ * registered to any <1b> name. This is to allow domain master browsers
+ * to discover other domains that may not have a presence on their subnet.
+ */
+
+ if(strequal( question->name, "*") && (question->name_type == 0x1b))
+ {
+ process_wins_dmb_query_request( subrec, p);
+ return;
+ }
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ if(namerec != NULL)
+ {
+ /*
+ * If it's a DNSFAIL_NAME then reply name not found.
+ */
+
+ if( namerec->data.source == DNSFAIL_NAME )
+ {
+ DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
+ nmb_namestr(question) ));
+ send_wins_name_query_response(NAM_ERR, p, namerec);
+ return;
+ }
+
+ /*
+ * If the name has expired then reply name not found.
+ */
+
+ if( (namerec->data.death_time != PERMANENT_TTL)
+ && (namerec->data.death_time < p->timestamp) )
+ {
+ DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
+ nmb_namestr(question) ));
+ send_wins_name_query_response(NAM_ERR, p, namerec);
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
+ nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
+
+ send_wins_name_query_response(0, p, namerec);
+ return;
+ }
+
+ /*
+ * Name not found in WINS - try a dns query if it's a 0x20 name.
+ */
+
+ if(lp_dns_proxy() &&
+ ((question->name_type == 0x20) || question->name_type == 0))
+ {
+
+ DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
+ nmb_namestr(question) ));
+
+ queue_dns_query(p, question, &namerec);
+ return;
+ }
+
+ /*
+ * Name not found - return error.
+ */
+
+ send_wins_name_query_response(NAM_ERR, p, NULL);
+}
+
+/****************************************************************************
+Send a WINS name release response.
+**************************************************************************/
+
+static void send_wins_name_release_response(int rcode, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char rdata[6];
+
+ memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_REL, /* nmbd type code. */
+ NMB_NAME_RELEASE_OPCODE, /* opcode. */
+ 0, /* ttl. */
+ rdata, /* data to send. */
+ 6); /* data length. */
+}
+
+/***********************************************************************
+ Deal with a name release.
+***********************************************************************/
+
+void wins_process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
+ struct name_record *namerec = NULL;
+ struct in_addr from_ip;
+ BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+
+ if(bcast)
+ {
+ /*
+ * We should only get unicast name registration packets here.
+ * Anyone trying to register broadcast should not be going to a WINS
+ * server. Log an error here.
+ */
+
+ DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
+received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
+ nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
+IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
+
+ /*
+ * Deal with policy regarding 0x1d names.
+ */
+
+ if(!releasing_group_name && (question->name_type == 0x1d))
+ {
+ DEBUG(3,("wins_process_name_release_request: Ignoring request \
+to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
+ send_wins_name_release_response(0, p);
+ return;
+ }
+
+ /*
+ * See if the name already exists.
+ */
+
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ if( (namerec == NULL)
+ || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) )
+ {
+ send_wins_name_release_response(NAM_ERR, p);
+ return;
+ }
+
+ /*
+ * Check that the sending machine has permission to release this name.
+ * If it's a group name not ending in 0x1c then just say yes and let
+ * the group time out.
+ */
+
+ if(releasing_group_name && (question->name_type != 0x1c))
+ {
+ send_wins_name_release_response(0, p);
+ return;
+ }
+
+ /*
+ * Check that the releasing node is on the list of IP addresses
+ * for this name. Disallow the release if not.
+ */
+
+ if(!find_ip_in_name_record(namerec, from_ip))
+ {
+ DEBUG(3,("wins_process_name_release_request: Refusing request to \
+release name %s as IP %s is not one of the known IP's for this name.\n",
+ nmb_namestr(question), inet_ntoa(from_ip) ));
+ send_wins_name_release_response(NAM_ERR, p);
+ return;
+ }
+
+ /*
+ * Release the name and then remove the IP from the known list.
+ */
+
+ send_wins_name_release_response(0, p);
+ remove_ip_from_name_record(namerec, from_ip);
+
+ wins_hook("delete", namerec, 0);
+
+ /*
+ * Remove the name entirely if no IP addresses left.
+ */
+ if (namerec->data.num_ips == 0)
+ remove_name_from_namelist(subrec, namerec);
+
+}
+
+/*******************************************************************
+ WINS time dependent processing.
+******************************************************************/
+
+void initiate_wins_processing(time_t t)
+{
+ static time_t lasttime = 0;
+
+ if (!lasttime)
+ lasttime = t;
+ if (t - lasttime < 20)
+ return;
+
+ lasttime = t;
+
+ if(!lp_we_are_a_wins_server())
+ return;
+
+ expire_names_on_subnet(wins_server_subnet, t);
+
+ if(wins_server_subnet->namelist_changed)
+ wins_write_database(True);
+
+ wins_server_subnet->namelist_changed = False;
+}
+
+/*******************************************************************
+ Write out the current WINS database.
+******************************************************************/
+void wins_write_database(BOOL background)
+{
+ struct name_record *namerec;
+ pstring fname, fnamenew;
+ XFILE *fp;
+
+ if(!lp_we_are_a_wins_server())
+ return;
+
+ /* we will do the writing in a child process to ensure that the parent
+ doesn't block while this is done */
+ if (background) {
+ CatchChild();
+ if (sys_fork()) {
+ return;
+ }
+ }
+
+ slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST);
+ all_string_sub(fname,"//", "/", 0);
+ slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid());
+
+ if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644)) == NULL)
+ {
+ DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
+ if (background) {
+ _exit(0);
+ }
+ return;
+ }
+
+ DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
+
+ x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, wins_hash());
+
+ for( namerec
+ = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist );
+ namerec;
+ namerec = (struct name_record *)ubi_trNext( namerec ) )
+ {
+ int i;
+ struct tm *tm;
+
+ DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
+
+ if( namerec->data.death_time != PERMANENT_TTL )
+ {
+ char *ts, *nl;
+
+ tm = LocalTime(&namerec->data.death_time);
+ ts = asctime(tm);
+ nl = strrchr_m( ts, '\n' );
+ if( NULL != nl )
+ *nl = '\0';
+ DEBUGADD(4,("TTL = %s ", ts ));
+ }
+ else
+ DEBUGADD(4,("TTL = PERMANENT "));
+
+ for (i = 0; i < namerec->data.num_ips; i++)
+ DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
+ DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
+
+ if( namerec->data.source == REGISTER_NAME )
+ {
+ x_fprintf(fp, "\"%s#%02x\" %d ",
+ namerec->name.name,namerec->name.name_type, /* Ignore scope. */
+ (int)namerec->data.death_time);
+
+ for (i = 0; i < namerec->data.num_ips; i++)
+ x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
+ x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
+ }
+ }
+
+ x_fclose(fp);
+ chmod(fnamenew,0644);
+ unlink(fname);
+ rename(fnamenew,fname);
+ if (background) {
+ _exit(0);
+ }
+}
diff --git a/source/nmbd/nmbd_workgroupdb.c b/source/nmbd/nmbd_workgroupdb.c
new file mode 100644
index 00000000000..4551eaf46b4
--- /dev/null
+++ b/source/nmbd/nmbd_workgroupdb.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1994-1998
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern uint16 samba_nb_type;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+/****************************************************************************
+ Add a workgroup into the list.
+ **************************************************************************/
+
+static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
+{
+ work->subnet = subrec;
+ DLIST_ADD(subrec->workgrouplist, work);
+ subrec->work_changed = True;
+}
+
+/****************************************************************************
+ Create an empty workgroup.
+ **************************************************************************/
+
+static struct work_record *create_workgroup(const char *name, int ttl)
+{
+ struct work_record *work;
+ struct subnet_record *subrec;
+ int t = -1;
+
+ if((work = (struct work_record *)malloc(sizeof(*work))) == NULL)
+ {
+ DEBUG(0,("create_workgroup: malloc fail !\n"));
+ return NULL;
+ }
+ memset((char *)work, '\0', sizeof(*work));
+
+ StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
+ work->serverlist = NULL;
+
+ work->RunningElection = False;
+ work->ElectionCount = 0;
+ work->announce_interval = 0;
+ work->needelection = False;
+ work->needannounce = True;
+ work->lastannounce_time = time(NULL);
+ work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
+ work->dom_state = DOMAIN_NONE;
+ work->log_state = LOGON_NONE;
+
+ work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
+
+ /* Make sure all token representations of workgroups are unique. */
+
+ for (subrec = FIRST_SUBNET; subrec && (t == -1);
+ subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ struct work_record *w;
+ for (w = subrec->workgrouplist; w && t == -1; w = w->next)
+ {
+ if (strequal(w->work_group, work->work_group))
+ t = w->token;
+ }
+ }
+
+ if (t == -1)
+ work->token = ++workgroup_count;
+ else
+ work->token = t;
+
+ /* No known local master browser as yet. */
+ *work->local_master_browser_name = '\0';
+
+ /* No known domain master browser as yet. */
+ *work->dmb_name.name = '\0';
+ zero_ip(&work->dmb_addr);
+
+ /* WfWg uses 01040b01 */
+ /* Win95 uses 01041501 */
+ /* NTAS uses ???????? */
+ work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
+ work->ElectionCriterion |= (lp_os_level() << 24);
+ if (lp_domain_master())
+ work->ElectionCriterion |= 0x80;
+
+ return work;
+}
+
+/*******************************************************************
+ Remove a workgroup.
+ ******************************************************************/
+
+static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec,
+ struct work_record *work)
+{
+ struct work_record *ret_work = NULL;
+
+ DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
+
+ ret_work = work->next;
+
+ remove_all_servers(work);
+
+ if (!work->serverlist)
+ {
+ if (work->prev)
+ work->prev->next = work->next;
+ if (work->next)
+ work->next->prev = work->prev;
+
+ if (subrec->workgrouplist == work)
+ subrec->workgrouplist = work->next;
+
+ ZERO_STRUCTP(work);
+ SAFE_FREE(work);
+ }
+
+ subrec->work_changed = True;
+
+ return ret_work;
+}
+
+
+/****************************************************************************
+ Find a workgroup in the workgroup list of a subnet.
+ **************************************************************************/
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *name)
+{
+ struct work_record *ret;
+
+ DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
+ name, subrec->subnet_name));
+
+ for (ret = subrec->workgrouplist; ret; ret = ret->next)
+ {
+ if (!strcmp(ret->work_group,name))
+ {
+ DEBUGADD(4, ("found.\n"));
+ return(ret);
+ }
+ }
+ DEBUGADD(4, ("not found.\n"));
+ return NULL;
+}
+
+/****************************************************************************
+ Create a workgroup in the workgroup list of the subnet.
+ **************************************************************************/
+
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+ const char *name, int ttl)
+{
+ struct work_record *work = NULL;
+
+ DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
+ name, subrec->subnet_name));
+
+ if ((work = create_workgroup(name, ttl)))
+ {
+ add_workgroup(subrec, work);
+
+ subrec->work_changed = True;
+
+ return(work);
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Update a workgroup ttl.
+ **************************************************************************/
+
+void update_workgroup_ttl(struct work_record *work, int ttl)
+{
+ if(work->death_time != PERMANENT_TTL)
+ work->death_time = time(NULL)+(ttl*3);
+ work->subnet->work_changed = True;
+}
+
+/****************************************************************************
+ Fail function called if we cannot register the WORKGROUP<0> and
+ WORKGROUP<1e> names on the net.
+**************************************************************************/
+
+static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
+ struct nmb_name *nmbname)
+{
+ DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
+ nmb_namestr(nmbname), subrec->subnet_name));
+}
+
+/****************************************************************************
+ If the workgroup is our primary workgroup, add the required names to it.
+**************************************************************************/
+
+void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
+{
+ int i;
+
+ if(!strequal(global_myworkgroup, work->work_group))
+ return;
+
+ /* If this is a broadcast subnet then start elections on it
+ if we are so configured. */
+
+ if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
+ (subrec != wins_server_subnet) && lp_preferred_master() &&
+ lp_local_master())
+ {
+ DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
+workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
+ work->needelection = True;
+ work->ElectionCriterion |= (1<<3);
+ }
+
+ /* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
+
+ register_name(subrec,global_myworkgroup,0x0,samba_nb_type|NB_GROUP,
+ NULL,
+ fail_register,NULL);
+
+ register_name(subrec,global_myworkgroup,0x1e,samba_nb_type|NB_GROUP,
+ NULL,
+ fail_register,NULL);
+
+ for( i = 0; my_netbios_names[i]; i++)
+ {
+ char *name = my_netbios_names[i];
+ int stype = lp_default_server_announce() | (lp_local_master() ?
+ SV_TYPE_POTENTIAL_BROWSER : 0 );
+
+ if(!strequal(global_myname, name))
+ stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
+ SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+
+ create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY,
+ PERMANENT_TTL,
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
+on subnet %s\n", name, subrec->subnet_name));
+ }
+}
+
+/****************************************************************************
+ Dump a copy of the workgroup database into the log file.
+ **************************************************************************/
+
+void dump_workgroups(BOOL force_write)
+{
+ struct subnet_record *subrec;
+ int debuglevel = force_write ? 0 : 4;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ if (subrec->workgrouplist)
+ {
+ struct work_record *work;
+
+ if( DEBUGLVL( debuglevel ) )
+ {
+ dbgtext( "dump_workgroups()\n " );
+ dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
+ dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
+ }
+
+ for (work = subrec->workgrouplist; work; work = work->next)
+ {
+ DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n",
+ work->work_group,
+ work->token,
+ *work->local_master_browser_name
+ ? work->local_master_browser_name : "UNKNOWN" ) );
+ if (work->serverlist)
+ {
+ struct server_record *servrec;
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
+ servrec->serv.name,
+ servrec->serv.type,
+ servrec->serv.comment ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ Expire any dead servers on all workgroups. If the workgroup has expired
+ remove it.
+ **************************************************************************/
+
+void expire_workgroups_and_servers(time_t t)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ struct work_record *work;
+ struct work_record *nextwork;
+
+ for (work = subrec->workgrouplist; work; work = nextwork)
+ {
+ nextwork = work->next;
+ expire_servers(work, t);
+
+ if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) &&
+ ((t == -1) || (work->death_time < t)))
+ {
+ DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
+ work->work_group));
+ remove_workgroup_from_subnet(subrec, work);
+ }
+ }
+ }
+}
diff --git a/source/nmbsync.c b/source/nmbsync.c
deleted file mode 100644
index 5a77d6cc486..00000000000
--- a/source/nmbsync.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines to synchronise browse lists
- Copyright (C) Andrew Tridgell 1994-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.h"
-
-extern int DEBUGLEVEL;
-
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace);
-
-
-/****************************************************************************
-call a remote api
-****************************************************************************/
-static BOOL call_remote_api(int fd,int cnum,int uid,int timeout,
- char *inbuf,char *outbuf,
- int prcnt,int drcnt,
- int mprcnt,int mdrcnt,
- int *rprcnt,int *rdrcnt,
- char *param,char *data,
- char **rparam,char **rdata)
-{
- char *p1,*p2;
-
- /* send a SMBtrans command */
- bzero(outbuf,smb_size);
- set_message(outbuf,14,0,True);
- CVAL(outbuf,smb_com) = SMBtrans;
- SSVAL(outbuf,smb_tid,cnum);
- SSVAL(outbuf,smb_uid,uid);
-
- p1 = smb_buf(outbuf);
- strcpy(p1,"\\PIPE\\LANMAN");
- p1 = skip_string(p1,1);
- p2 = p1 + prcnt;
-
- if (prcnt > 0)
- memcpy(p1,param,prcnt);
- if (drcnt > 0)
- memcpy(p2,data,drcnt);
-
- SSVAL(outbuf,smb_vwv0,prcnt); /* param count */
- SSVAL(outbuf,smb_vwv1,drcnt); /* data count */
- SSVAL(outbuf,smb_vwv2,mprcnt); /* mprcnt */
- SSVAL(outbuf,smb_vwv3,mdrcnt); /* mdrcnt */
- SSVAL(outbuf,smb_vwv4,0); /* msrcnt */
- SSVAL(outbuf,smb_vwv5,0); /* flags */
- SSVAL(outbuf,smb_vwv9,prcnt); /* pscnt */
- SSVAL(outbuf,smb_vwv10,smb_offset(p1,outbuf)); /* psoff */
- SSVAL(outbuf,smb_vwv11,drcnt); /* dscnt */
- SSVAL(outbuf,smb_vwv12,smb_offset(p2,outbuf)); /* dsoff */
- CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */
-
- set_message(outbuf,14,PTR_DIFF(p2+drcnt,smb_buf(outbuf)),False);
-
- send_smb(fd,outbuf);
-
- if (receive_smb(fd,inbuf,timeout) &&
- CVAL(inbuf,smb_rcls) == 0)
- {
- if (rparam)
- *rparam = inbuf+4 + SVAL(inbuf,smb_vwv4);
- if (rdata)
- *rdata = inbuf+4 + SVAL(inbuf,smb_vwv7);
- if (rprcnt)
- *rprcnt = SVAL(inbuf,smb_vwv3);
- if (rdrcnt)
- *rdrcnt = SVAL(inbuf,smb_vwv6);
- return(True);
- }
-
- return(False);
-}
-
-
-/*******************************************************************
- synchronise browse lists with another browse server
- ******************************************************************/
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip)
-{
- char *protocol = "LM1.2X002";
- char *service = "IPC$";
- char *dev = "IPC";
- int timeout=2000;
- char *inbuf=NULL;
- pstring outbuf;
- char *p;
- int len;
- uint32 sesskey;
- int cnum,uid;
- BOOL ret;
-
- int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT);
- if (fd < 0) {
- DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip)));
- return;
- }
-
- if (!(inbuf = (char *)malloc(0xFFFF+1024))) return;
-
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(name,p,name_type);
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(myname,p,0x20);
- len += name_len(p);
-
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,5000);
-
- bzero(outbuf,smb_size);
-
- /* setup the protocol string */
- set_message(outbuf,0,strlen(protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,protocol);
-
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
-
- if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
- DEBUG(3,("%s rejected the protocol\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- sesskey = IVAL(inbuf,smb_vwv6);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,10,2,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,0xFFFF);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,1);
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected session setup\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- uid = SVAL(inbuf,smb_uid);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) +
- 1 + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- SSVAL(outbuf,smb_uid,uid);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,1);
-
- p = smb_buf(outbuf) + 1;
- strcpy(p, "\\\\");
- strcat(p, name);
- strcat(p, "\\");
- strcat(p,service);
- p = skip_string(p,1);
- strcpy(p,dev);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name,
- CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err)));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- cnum = SVAL(inbuf,smb_tid);
-
- /* now I need to send a NetServerEnum */
- {
- fstring param;
- uint32 *typep;
- char *rparam,*rdata;
-
- p = param;
- SSVAL(p,0,0x68); /* api number */
- p += 2;
- strcpy(p,"WrLehDz");
- p = skip_string(p,1);
-
- strcpy(p,"B16BBDz");
-
- p = skip_string(p,1);
- SSVAL(p,0,1); /* level 1 */
- SSVAL(p,2,0xFFFF - 500); /* buf length */
- p += 4;
- typep = (uint32 *)p;
- p += 4;
- strcpy(p,domain);
- strupper(p);
- p = skip_string(p,1);
-
- SIVAL(typep,0,0x80000000); /* domain list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
- char *p2 = rdata;
- for (i=0;i<count;i++) {
- char *sname = p2;
- uint32 type = IVAL(p2,18);
- int comment_offset = IVAL(p2,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
-
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p2 += 26;
- }
- }
-
- SIVAL(typep,0,0xFFFFFFFF); /* server list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
-
- p = rdata;
- for (i=0;i<count;i++) {
- char *sname = p;
- uint32 type = IVAL(p,18);
- int comment_offset = IVAL(p,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
-
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p += 26;
- }
- }
- }
-
- /* close up */
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBtdis;
- SSVAL(outbuf,smb_uid,uid);
- SSVAL(outbuf,smb_tid,cnum);
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,1000);
-
- close(fd);
- if (inbuf) free(inbuf);
-}
diff --git a/source/nsswitch/.cvsignore b/source/nsswitch/.cvsignore
new file mode 100644
index 00000000000..090b859b372
--- /dev/null
+++ b/source/nsswitch/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+diffs
diff --git a/source/nsswitch/README b/source/nsswitch/README
new file mode 100644
index 00000000000..9f0c581df60
--- /dev/null
+++ b/source/nsswitch/README
@@ -0,0 +1,13 @@
+This extension provides a "wins" module for NSS on glibc2/Linux. This
+allows you to use a WINS entry in /etc/nsswitch.conf for hostname
+resolution, allowing you to resolve netbios names via start unix
+gethostbyname() calls. The end result is that you can use netbios
+names as host names in unix apps.
+
+1) run configure
+2) run "make nsswitch"
+3) cp nsswitch/libnss_wins.so /lib/libnss_wins.so.2
+4) add a wins entry to the hosts line in /etc/nsswitch.conf
+5) use it
+
+tridge@linuxcare.com
diff --git a/source/nsswitch/nss.h b/source/nsswitch/nss.h
new file mode 100644
index 00000000000..a29271529fd
--- /dev/null
+++ b/source/nsswitch/nss.h
@@ -0,0 +1,89 @@
+#ifndef _NSSWITCH_NSS_H
+#define _NSSWITCH_NSS_H
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ a common place to work out how to define NSS_STATUS on various
+ platforms
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_NSS_COMMON_H
+
+/* Sun Solaris */
+
+#include <nss_common.h>
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
+
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
+
+#elif HAVE_NSS_H
+
+/* GNU */
+
+#include <nss.h>
+
+typedef enum nss_status NSS_STATUS;
+
+#elif HAVE_NS_API_H
+
+/* SGI IRIX */
+
+/* following required to prevent warnings of double definition
+ * of datum from ns_api.h
+*/
+#ifdef DATUM
+#define _DATUM_DEFINED
+#endif
+
+#include <ns_api.h>
+
+typedef enum
+{
+ NSS_STATUS_SUCCESS=NS_SUCCESS,
+ NSS_STATUS_NOTFOUND=NS_NOTFOUND,
+ NSS_STATUS_UNAVAIL=NS_UNAVAIL,
+ NSS_STATUS_TRYAGAIN=NS_TRYAGAIN
+} NSS_STATUS;
+
+#define NSD_MEM_STATIC 0
+#define NSD_MEM_VOLATILE 1
+#define NSD_MEM_DYNAMIC 2
+
+#else /* Nothing's defined. Neither gnu nor sun */
+
+typedef enum
+{
+ NSS_STATUS_SUCCESS=0,
+ NSS_STATUS_NOTFOUND=1,
+ NSS_STATUS_UNAVAIL=2,
+ NSS_STATUS_TRYAGAIN=3
+} NSS_STATUS;
+
+#endif
+
+#endif /* _NSSWITCH_NSS_H */
+
diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c
new file mode 100644
index 00000000000..b3dea202c2c
--- /dev/null
+++ b/source/nsswitch/pam_winbind.c
@@ -0,0 +1,514 @@
+/* pam_winbind module
+
+ Copyright Andrew Tridgell <tridge@samba.org> 2000
+
+ largely based on pam_userdb by Christian Gafton <gafton@redhat.com>
+*/
+
+#include "pam_winbind.h"
+
+/* prototypes from common.c */
+void init_request(struct winbindd_request *req,int rq_type);
+int write_sock(void *buffer, int count);
+int read_reply(struct winbindd_response *response);
+
+/* some syslogging */
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+static int ctrl = 0;
+
+static int _pam_parse(int argc, const char **argv)
+{
+ /* step through arguments */
+ for (ctrl = 0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_DEBUG_ARG;
+ else if (!strcasecmp(*argv, "use_authtok"))
+ ctrl |= PAM_USE_AUTHTOK_ARG;
+ else if (!strcasecmp(*argv, "unknown_ok"))
+ ctrl |= PAM_UNKNOWN_OK_ARG;
+ else {
+ _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
+ }
+ }
+
+ return ctrl;
+}
+
+static int winbind_request(enum winbindd_cmd req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ /* Fill in request and send down pipe */
+ init_request(request, req_type);
+
+ if (write_sock(request, sizeof(*request)) == -1) {
+ return -2;
+ }
+
+ /* Wait for reply */
+ if (read_reply(response) == -1) {
+ return -2;
+ }
+
+ /* Copy reply data from socket */
+ if (response->result != WINBINDD_OK) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* talk to winbindd */
+static int winbind_auth_request(const char *user, const char *pass)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+
+ strncpy(request.data.auth.user, user,
+ sizeof(request.data.auth.user)-1);
+
+ strncpy(request.data.auth.pass, pass,
+ sizeof(request.data.auth.pass)-1);
+
+ return winbind_request(WINBINDD_PAM_AUTH, &request, &response);
+}
+
+/* talk to winbindd */
+static int winbind_chauthtok_request(const char *user, const char *oldpass,
+ const char *newpass)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+
+ if (request.data.chauthtok.user == NULL) return -2;
+
+ strncpy(request.data.chauthtok.user, user,
+ sizeof(request.data.chauthtok.user) - 1);
+
+ if (oldpass != NULL) {
+ strncpy(request.data.chauthtok.oldpass, oldpass,
+ sizeof(request.data.chauthtok.oldpass) - 1);
+ } else {
+ request.data.chauthtok.oldpass[0] = '\0';
+ }
+
+ if (newpass != NULL) {
+ strncpy(request.data.chauthtok.newpass, newpass,
+ sizeof(request.data.chauthtok.newpass) - 1);
+ } else {
+ request.data.chauthtok.newpass[0] = '\0';
+ }
+
+ return winbind_request(WINBINDD_PAM_CHAUTHTOK, &request, &response);
+}
+
+/*
+ * Looks up an user name and checks the password
+ *
+ * return values:
+ * 1 = User not found
+ * 0 = OK
+ * -1 = Password incorrect
+ * -2 = System error
+ */
+static int user_lookup(const char *user, const char *pass)
+{
+ return winbind_auth_request(user, pass);
+}
+
+/*
+ * Checks if a user has an account
+ *
+ * return values:
+ * 1 = User not found
+ * 0 = OK
+ * -1 = System error
+ */
+static int valid_user(const char *user)
+{
+ if (getpwnam(user)) return 0;
+ return 1;
+}
+
+/* --- authentication management functions --- */
+
+/* Attempt a conversation */
+
+static int converse(pam_handle_t *pamh, int nargs,
+ struct pam_message **message,
+ struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
+ if (retval == PAM_SUCCESS) {
+ retval = conv->conv(nargs, (const struct pam_message **)message,
+ response, conv->appdata_ptr);
+ }
+
+ return retval; /* propagate error status */
+}
+
+
+static char *_pam_delete(register char *xx)
+{
+ _pam_overwrite(xx);
+ _pam_drop(xx);
+ return NULL;
+}
+
+/*
+ * This is a conversation function to obtain the user's password
+ */
+static int auth_conversation(pam_handle_t *pamh)
+{
+ struct pam_message msg, *pmsg;
+ struct pam_response *resp;
+ int retval;
+ char * token = NULL;
+
+ pmsg = &msg;
+ msg.msg_style = PAM_PROMPT_ECHO_OFF;
+ msg.msg = "Password: ";
+
+ /* so call the conversation expecting i responses */
+ resp = NULL;
+ retval = converse(pamh, 1, &pmsg, &resp);
+
+ if (resp != NULL) {
+ char * const item;
+ /* interpret the response */
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+ token = x_strdup(resp[0].resp);
+ if (token == NULL) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+
+ /* set the auth token */
+ retval = pam_set_item(pamh, PAM_AUTHTOK, token);
+ token = _pam_delete(token); /* clean it up */
+ if ( (retval != PAM_SUCCESS) ||
+ (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
+ return retval;
+ }
+
+ _pam_drop_reply(resp, 1);
+ } else {
+ retval = (retval == PAM_SUCCESS)
+ ? PAM_AUTHTOK_RECOVER_ERR:retval ;
+ }
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ const char *password;
+ int retval = PAM_AUTH_ERR;
+
+ /* parse arguments */
+ ctrl = _pam_parse(argc, argv);
+
+ /* Get the username */
+ retval = pam_get_user(pamh, &username, NULL);
+ if ((retval != PAM_SUCCESS) || (!username)) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"can not get the username");
+ return PAM_SERVICE_ERR;
+ }
+
+ if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
+ /* Converse just to be sure we have the password */
+ retval = auth_conversation(pamh);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "could not obtain password for `%s'",
+ username);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ /* Get the password */
+ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR, "Could not retrive user's password");
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
+ username, password);
+
+ /* Now use the username to look up password */
+ retval = user_lookup(username, password);
+ switch (retval) {
+ case -2:
+ /* some sort of system error. The log was already printed */
+ return PAM_SERVICE_ERR;
+ case -1:
+ /* incorrect password */
+ _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
+ return PAM_AUTH_ERR;
+ case 1:
+ /* the user does not exist */
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE, "user `%s' not found",
+ username);
+ if (ctrl & PAM_UNKNOWN_OK_ARG) {
+ return PAM_IGNORE;
+ }
+ return PAM_USER_UNKNOWN;
+ case 0:
+ /* Otherwise, the authentication looked good */
+ _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
+ return PAM_SUCCESS;
+ default:
+ /* we don't know anything about this return value */
+ _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
+ retval, username);
+ return PAM_SERVICE_ERR;
+ }
+ /* should not be reached */
+ return PAM_IGNORE;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+/*
+ * Account management. We want to verify that the account exists
+ * before returning PAM_SUCCESS
+ */
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ int retval = PAM_USER_UNKNOWN;
+
+ /* parse arguments */
+ ctrl = _pam_parse(argc, argv);
+
+ /* Get the username */
+ retval = pam_get_user(pamh, &username, NULL);
+ if ((retval != PAM_SUCCESS) || (!username)) {
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"can not get the username");
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Verify the username */
+ retval = valid_user(username);
+ switch (retval) {
+ case -1:
+ /* some sort of system error. The log was already printed */
+ return PAM_SERVICE_ERR;
+ case 1:
+ /* the user does not exist */
+ if (ctrl & PAM_DEBUG_ARG)
+ _pam_log(LOG_NOTICE, "user `%s' not found",
+ username);
+ if (ctrl & PAM_UNKNOWN_OK_ARG)
+ return PAM_IGNORE;
+ return PAM_USER_UNKNOWN;
+ case 0:
+ /* Otherwise, the authentication looked good */
+ _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
+ return PAM_SUCCESS;
+ default:
+ /* we don't know anything about this return value */
+ _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
+ retval, username);
+ return PAM_SERVICE_ERR;
+ }
+
+ /* should not be reached */
+ return PAM_IGNORE;
+}
+
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ int retval;
+ char *newpw, *oldpw;
+ const char *user;
+
+ /* Get name of a user */
+
+ retval = pam_get_user(pamh, &user, "Username: ");
+
+ if (retval != PAM_SUCCESS) {
+ return retval;
+ }
+
+ /* XXX check in domain format */
+
+ /* Perform preliminary check and store requested password for updating
+ later on */
+
+ if (flags & PAM_PRELIM_CHECK) {
+ struct pam_message msg[3], *pmsg[3];
+ struct pam_response *resp;
+
+ /* Converse to ensure we have the current password */
+
+ retval = auth_conversation(pamh);
+
+ if (retval != PAM_SUCCESS) {
+ return retval;
+ }
+
+ /* Obtain and verify current password */
+
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = "Changing password for user %s";
+
+ pmsg[1] = &msg[1];
+ msg[1].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[1].msg = "New NT password: ";
+
+ pmsg[2] = &msg[2];
+ msg[2].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[2].msg = "Retype new NT password: ";
+
+ resp = NULL;
+
+ retval = converse(pamh, 3, pmsg, &resp);
+
+ if (resp != NULL) {
+
+ if (retval == PAM_SUCCESS) {
+
+ /* Check password entered correctly */
+
+ if (strcmp(resp[1].resp, resp[2].resp) != 0) {
+ struct pam_response *resp2;
+
+ msg[0].msg_style = PAM_ERROR_MSG;
+ msg[0].msg = "Sorry, passwords do not match";
+
+ converse(pamh, 1, pmsg, &resp2);
+
+ _pam_drop_reply(resp, 3);
+ _pam_drop_reply(resp2, 1);
+
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+
+ /* Store passwords */
+
+ retval = pam_set_item(pamh, PAM_OLDAUTHTOK, resp[1].resp);
+ _pam_drop_reply(resp, 3);
+ }
+ }
+
+ /* XXX What happens if root? */
+ /* XXX try first pass and use first pass args */
+
+ return retval;
+ }
+
+ if (flags & PAM_UPDATE_AUTHTOK) {
+
+ retval = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&newpw);
+ if (retval != PAM_SUCCESS) {
+ return PAM_AUTHTOK_ERR;
+ }
+
+ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&oldpw);
+ if (retval != PAM_SUCCESS) {
+ return PAM_AUTHTOK_ERR;
+ }
+
+ fprintf(stderr, "oldpw = %s, newpw = %s\n", oldpw, newpw);
+
+ if (retval == PAM_SUCCESS &&
+ winbind_chauthtok_request(user, oldpw, newpw) == 0) {
+ return PAM_SUCCESS;
+ }
+
+ return PAM_AUTHTOK_ERR;
+ }
+
+ return PAM_SERVICE_ERR;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_winbind_modstruct = {
+ MODULE_NAME,
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ pam_sm_chauthtok
+};
+
+#endif
+
+/*
+ * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
+ * Copyright (c) Tim Potter <tpot@samba.org> 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h
new file mode 100644
index 00000000000..991c117656f
--- /dev/null
+++ b/source/nsswitch/pam_winbind.h
@@ -0,0 +1,81 @@
+/* pam_winbind header file
+ (Solaris needs some macros from Linux for common PAM code)
+
+ Shirish Kalele 2000
+*/
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <config.h>
+
+#define MODULE_NAME "pam_winbind"
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#if defined(SUNOS5) || defined(SUNOS4)
+
+/* Solaris always uses dynamic pam modules */
+#define PAM_EXTERN extern
+#include <security/pam_appl.h>
+
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+#ifdef HAVE_SECURITY_PAM_MODULES_H
+#include <security/pam_modules.h>
+#endif
+
+#ifdef HAVE_SECURITY__PAM_MACROS_H
+#include <security/_pam_macros.h>
+#else
+/* Define required macros from (Linux PAM 0.68) security/_pam_macros.h */
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) SAFE_FREE(X)
+
+#define x_strdup(s) ( (s) ? strdup(s):NULL )
+#endif
+
+#define PAM_DEBUG_ARG (1<<0)
+#define PAM_USE_AUTHTOK_ARG (1<<1)
+#define PAM_UNKNOWN_OK_ARG (1<<2)
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
diff --git a/source/nsswitch/wb_client.c b/source/nsswitch/wb_client.c
new file mode 100644
index 00000000000..7bfa65176c7
--- /dev/null
+++ b/source/nsswitch/wb_client.c
@@ -0,0 +1,472 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ winbind client code
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "includes.h"
+#include "nsswitch/nss.h"
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
+{
+ char *p = strchr(domuser,*lp_winbind_separator());
+
+ if (!p)
+ return False;
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper(domain);
+ return True;
+}
+
+/* Call winbindd to convert a name to a sid */
+
+BOOL winbind_lookup_name(const char *name, DOM_SID *sid,
+ enum SID_NAME_USE *name_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+
+ if (!sid || !name_type)
+ return False;
+
+ /*
+ * Don't do the lookup if the name has no separator.
+ */
+
+ if (!strchr(name, *lp_winbind_separator()))
+ return False;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.name, name);
+
+ if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request,
+ &response)) == NSS_STATUS_SUCCESS) {
+ string_to_sid(sid, response.data.sid.sid);
+ *name_type = (enum SID_NAME_USE)response.data.sid.type;
+ }
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/* Call winbindd to convert sid to name */
+
+BOOL winbind_lookup_sid(DOM_SID *sid, fstring dom_name, fstring name,
+ enum SID_NAME_USE *name_type)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ fstring sid_str;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ parse_domain_user(response.data.name.name, dom_name, name);
+ *name_type = (enum SID_NAME_USE)response.data.name.type;
+
+ DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n",
+ sid_str, dom_name, name));
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert SID to uid */
+
+BOOL winbind_sid_to_uid(uid_t *puid, DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!puid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *puid = response.data.uid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert uid to sid */
+
+BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ if (!sid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.uid = uid;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ string_to_sid(sid, response.data.sid.sid);
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert SID to gid */
+
+BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+ fstring sid_str;
+
+ if (!pgid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ sid_to_string(sid_str, sid);
+ fstrcpy(request.data.sid, sid_str);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ *pgid = response.data.gid;
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Call winbindd to convert gid to sid */
+
+BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ if (!sid)
+ return False;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
+
+ /* Copy out result */
+
+ if (result == NSS_STATUS_SUCCESS) {
+ string_to_sid(sid, response.data.sid.sid);
+ } else {
+ sid_copy(sid, &global_sid_NULL);
+ }
+
+ return (result == NSS_STATUS_SUCCESS);
+}
+
+/* Fetch the list of groups a user is a member of from winbindd. This is
+ used by winbind_initgroups and winbind_getgroups. */
+
+static int wb_getgroups(const char *user, gid_t **groups)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ /* Call winbindd */
+
+ fstrcpy(request.data.username, user);
+
+ ZERO_STRUCT(response);
+
+ result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+
+ if (result == NSS_STATUS_SUCCESS) {
+
+ /* Return group list. Don't forget to free the group list
+ when finished. */
+
+ *groups = (gid_t *)response.extra_data;
+ return response.data.num_entries;
+ }
+
+ return -1;
+}
+
+/* Call winbindd to initialise group membership. This is necessary for
+ some systems (i.e RH5.2) that do not have an initgroups function as part
+ of the nss extension. In RH5.2 this is implemented using getgrent()
+ which can be amazingly inefficient as well as having problems with
+ username case. */
+
+int winbind_initgroups(char *user, gid_t gid)
+{
+ gid_t *tgr, *groups = NULL;
+ int result;
+
+ /* Call normal initgroups if we are a local user */
+
+ if (!strchr(user, *lp_winbind_separator())) {
+ return initgroups(user, gid);
+ }
+
+ result = wb_getgroups(user, &groups);
+
+ DEBUG(10,("winbind_getgroups: %s: result = %s\n", user,
+ result == -1 ? "FAIL" : "SUCCESS"));
+
+ if (result != -1) {
+ int ngroups = result, i;
+ BOOL is_member = False;
+
+ /* Check to see if the passed gid is already in the list */
+
+ for (i = 0; i < ngroups; i++) {
+ if (groups[i] == gid) {
+ is_member = True;
+ }
+ }
+
+ /* Add group to list if necessary */
+
+ if (!is_member) {
+ tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
+
+ if (!tgr) {
+ errno = ENOMEM;
+ result = -1;
+ goto done;
+ }
+ else groups = tgr;
+
+ groups[ngroups] = gid;
+ ngroups++;
+ }
+
+ /* Set the groups */
+
+ if (sys_setgroups(ngroups, groups) == -1) {
+ errno = EPERM;
+ result = -1;
+ goto done;
+ }
+
+ } else {
+
+ /* The call failed. Set errno to something so we don't get
+ a bogus value from the last failed system call. */
+
+ errno = EIO;
+ }
+
+ /* Free response data if necessary */
+
+ done:
+ SAFE_FREE(groups);
+
+ return result;
+}
+
+/* Return a list of groups the user is a member of. This function is
+ useful for large systems where inverting the group database would be too
+ time consuming. If size is zero, list is not modified and the total
+ number of groups for the user is returned. */
+
+int winbind_getgroups(const char *user, int size, gid_t *list)
+{
+ gid_t *groups = NULL;
+ int result, i;
+
+ /*
+ * Don't do the lookup if the name has no separator.
+ */
+
+ if (!strchr(user, *lp_winbind_separator()))
+ return -1;
+
+ /* Fetch list of groups */
+
+ result = wb_getgroups(user, &groups);
+
+ if (size == 0)
+ goto done;
+
+ if (result > size) {
+ result = -1;
+ errno = EINVAL; /* This is what getgroups() does */
+ goto done;
+ }
+
+ /* Copy list of groups across */
+
+ for (i = 0; i < result; i++) {
+ list[i] = groups[i];
+ }
+
+ done:
+ SAFE_FREE(groups);
+ return result;
+}
+
+/* Utility function. Convert a uid_t to a name if possible. */
+
+BOOL winbind_uidtoname(fstring name, uid_t uid)
+{
+ DOM_SID sid;
+ fstring dom_name;
+ fstring user_name;
+ enum SID_NAME_USE name_type;
+
+ if (!winbind_uid_to_sid(&sid, uid))
+ return False;
+ if (!winbind_lookup_sid(&sid, dom_name, user_name, &name_type))
+ return False;
+
+ if (name_type != SID_NAME_USER)
+ return False;
+
+ slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name,
+ lp_winbind_separator(), user_name);
+
+ return True;
+}
+
+/* Utility function. Convert a gid_t to a name if possible. */
+
+BOOL winbind_gidtoname(fstring name, gid_t gid)
+{
+ DOM_SID sid;
+ fstring dom_name;
+ fstring group_name;
+ enum SID_NAME_USE name_type;
+
+ if (!winbind_gid_to_sid(&sid, gid))
+ return False;
+ if (!winbind_lookup_sid(&sid, dom_name, group_name, &name_type))
+ return False;
+
+ if (name_type != SID_NAME_DOM_GRP)
+ return False;
+
+ slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name,
+ lp_winbind_separator(), group_name);
+
+ return True;
+}
+
+/* Utility function. Convert a name to a uid_t if possible. */
+
+BOOL winbind_nametouid(uid_t *puid, const char *name)
+{
+ DOM_SID sid;
+ enum SID_NAME_USE name_type;
+
+ if (!winbind_lookup_name(name, &sid, &name_type))
+ return False;
+
+ if (name_type != SID_NAME_USER)
+ return False;
+
+ return winbind_sid_to_uid(puid, &sid);
+}
+
+/* Utility function. Convert a name to a gid_t if possible. */
+
+BOOL winbind_nametogid(gid_t *pgid, const char *gname)
+{
+ DOM_SID g_sid;
+ enum SID_NAME_USE name_type;
+
+ if (!winbind_lookup_name(gname, &g_sid, &name_type))
+ return False;
+
+ if (name_type != SID_NAME_DOM_GRP)
+ return False;
+
+ return winbind_sid_to_gid(pgid, &g_sid);
+}
diff --git a/source/nsswitch/wb_common.c b/source/nsswitch/wb_common.c
new file mode 100644
index 00000000000..0cfefa6f860
--- /dev/null
+++ b/source/nsswitch/wb_common.c
@@ -0,0 +1,374 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ winbind client common code
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+
+/* Global variables. These are effectively the client state information */
+
+static int established_socket = -1; /* fd for winbindd socket */
+static char *excluded_domain;
+
+/*
+ smbd needs to be able to exclude lookups for its own domain
+*/
+void winbind_exclude_domain(const char *domain)
+{
+ SAFE_FREE(excluded_domain);
+ excluded_domain = strdup(domain);
+}
+
+
+/* Initialise a request structure */
+
+void init_request(struct winbindd_request *request, int request_type)
+{
+ static char *domain_env;
+ static BOOL initialised;
+
+ request->cmd = (enum winbindd_cmd)request_type;
+ request->pid = getpid();
+ request->domain[0] = '\0';
+
+ if (!initialised) {
+ initialised = True;
+ domain_env = getenv(WINBINDD_DOMAIN_ENV);
+ }
+
+ if (domain_env) {
+ strncpy(request->domain, domain_env,
+ sizeof(request->domain) - 1);
+ request->domain[sizeof(request->domain) - 1] = '\0';
+ }
+}
+
+/* Initialise a response structure */
+
+void init_response(struct winbindd_response *response)
+{
+ /* Initialise return value */
+
+ response->result = WINBINDD_ERROR;
+}
+
+/* Close established socket */
+
+void close_sock(void)
+{
+ if (established_socket != -1) {
+ close(established_socket);
+ established_socket = -1;
+ }
+}
+
+/* Connect to winbindd socket */
+
+static int open_pipe_sock(void)
+{
+ struct sockaddr_un sunaddr;
+ static pid_t our_pid;
+ struct stat st;
+ pstring path;
+
+ if (our_pid != getpid()) {
+ if (established_socket != -1) {
+ close(established_socket);
+ }
+ established_socket = -1;
+ our_pid = getpid();
+ }
+
+ if (established_socket != -1) {
+ return established_socket;
+ }
+
+ /* Check permissions on unix socket directory */
+
+ if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
+ return -1;
+ }
+
+ if (!S_ISDIR(st.st_mode) ||
+ (st.st_uid != 0 && st.st_uid != geteuid())) {
+ return -1;
+ }
+
+ /* Connect to socket */
+
+ strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1);
+ path[sizeof(path) - 1] = '\0';
+
+ strncat(path, "/", sizeof(path) - 1);
+ path[sizeof(path) - 1] = '\0';
+
+ strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1);
+ path[sizeof(path) - 1] = '\0';
+
+ ZERO_STRUCT(sunaddr);
+ sunaddr.sun_family = AF_UNIX;
+ strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
+
+ /* If socket file doesn't exist, don't bother trying to connect
+ with retry. This is an attempt to make the system usable when
+ the winbindd daemon is not running. */
+
+ if (lstat(path, &st) == -1) {
+ return -1;
+ }
+
+ /* Check permissions on unix socket file */
+
+ if (!S_ISSOCK(st.st_mode) ||
+ (st.st_uid != 0 && st.st_uid != geteuid())) {
+ return -1;
+ }
+
+ /* Connect to socket */
+
+ if ((established_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ return -1;
+ }
+
+ if (connect(established_socket, (struct sockaddr *)&sunaddr,
+ sizeof(sunaddr)) == -1) {
+ close_sock();
+ established_socket = -1;
+ return -1;
+ }
+
+ return established_socket;
+}
+
+/* Write data to winbindd socket with timeout */
+
+int write_sock(void *buffer, int count)
+{
+ int result, nwritten;
+
+ /* Open connection to winbind daemon */
+
+ restart:
+
+ if (open_pipe_sock() == -1) {
+ return -1;
+ }
+
+ /* Write data to socket */
+
+ nwritten = 0;
+
+ while(nwritten < count) {
+ struct timeval tv;
+ fd_set r_fds;
+ int selret;
+
+ /* Catch pipe close on other end by checking if a read()
+ call would not block by calling select(). */
+
+ FD_ZERO(&r_fds);
+ FD_SET(established_socket, &r_fds);
+ ZERO_STRUCT(tv);
+
+ if ((selret = select(established_socket + 1, &r_fds,
+ NULL, NULL, &tv)) == -1) {
+ close_sock();
+ return -1; /* Select error */
+ }
+
+ /* Write should be OK if fd not available for reading */
+
+ if (!FD_ISSET(established_socket, &r_fds)) {
+
+ /* Do the write */
+
+ result = write(established_socket,
+ (char *)buffer + nwritten,
+ count - nwritten);
+
+ if ((result == -1) || (result == 0)) {
+
+ /* Write failed */
+
+ close_sock();
+ return -1;
+ }
+
+ nwritten += result;
+
+ } else {
+
+ /* Pipe has closed on remote end */
+
+ close_sock();
+ goto restart;
+ }
+ }
+
+ return nwritten;
+}
+
+/* Read data from winbindd socket with timeout */
+
+static int read_sock(void *buffer, int count)
+{
+ int result = 0, nread = 0;
+
+ /* Read data from socket */
+
+ while(nread < count) {
+
+ result = read(established_socket, (char *)buffer + nread,
+ count - nread);
+
+ if ((result == -1) || (result == 0)) {
+
+ /* Read failed. I think the only useful thing we
+ can do here is just return -1 and fail since the
+ transaction has failed half way through. */
+
+ close_sock();
+ return -1;
+ }
+
+ nread += result;
+ }
+
+ return result;
+}
+
+/* Read reply */
+
+int read_reply(struct winbindd_response *response)
+{
+ int result1, result2 = 0;
+
+ if (!response) {
+ return -1;
+ }
+
+ /* Read fixed length response */
+
+ if ((result1 = read_sock(response, sizeof(struct winbindd_response)))
+ == -1) {
+
+ return -1;
+ }
+
+ /* We actually send the pointer value of the extra_data field from
+ the server. This has no meaning in the client's address space
+ so we clear it out. */
+
+ response->extra_data = NULL;
+
+ /* Read variable length response */
+
+ if (response->length > sizeof(struct winbindd_response)) {
+ int extra_data_len = response->length -
+ sizeof(struct winbindd_response);
+
+ /* Mallocate memory for extra data */
+
+ if (!(response->extra_data = malloc(extra_data_len))) {
+ return -1;
+ }
+
+ if ((result2 = read_sock(response->extra_data, extra_data_len))
+ == -1) {
+ return -1;
+ }
+ }
+
+ /* Return total amount of data read */
+
+ return result1 + result2;
+}
+
+/* Free a response structure */
+
+void free_response(struct winbindd_response *response)
+{
+ /* Free any allocated extra_data */
+
+ if (response)
+ SAFE_FREE(response->extra_data);
+}
+
+/* Handle simple types of requests */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
+{
+ struct winbindd_request lrequest;
+ struct winbindd_response lresponse;
+
+ /* Check for our tricky environment variable */
+
+ if (getenv(WINBINDD_DONT_ENV)) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* smbd may have excluded this domain */
+ if (excluded_domain &&
+ strcasecmp(excluded_domain, request->domain) == 0) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (!response) {
+ ZERO_STRUCT(lresponse);
+ response = &lresponse;
+ }
+
+ if (!request) {
+ ZERO_STRUCT(lrequest);
+ request = &lrequest;
+ }
+
+ /* Fill in request and send down pipe */
+
+ init_request(request, req_type);
+ init_response(response);
+
+ if (write_sock(request, sizeof(*request)) == -1) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* Wait for reply */
+ if (read_reply(response) == -1) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* Throw away extra data if client didn't request it */
+ if (response == &lresponse) {
+ free_response(response);
+ }
+
+ /* Copy reply data from socket */
+ if (response->result != WINBINDD_OK) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c
new file mode 100644
index 00000000000..9c012eb85da
--- /dev/null
+++ b/source/nsswitch/wbinfo.c
@@ -0,0 +1,658 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind status program.
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#include "debug.h"
+
+/* Prototypes from common.h */
+
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
+/* List groups a user is a member of */
+
+static BOOL wbinfo_get_usergroups(char *user)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ int i;
+
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ fstrcpy(request.data.username, user);
+
+ result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+
+ if (result != NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ for (i = 0; i < response.data.num_entries; i++) {
+ printf("%d\n", (int)((gid_t *)response.extra_data)[i]);
+ }
+
+ return True;
+}
+
+/* List trusted domains */
+
+static BOOL wbinfo_list_domains(void)
+{
+ struct winbindd_response response;
+ fstring name;
+
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ if (response.extra_data) {
+ while(next_token((char **)&response.extra_data, name, ",",
+ sizeof(fstring))) {
+ printf("%s\n", name);
+ }
+ }
+
+ return True;
+}
+
+/* Check trust account password */
+
+static BOOL wbinfo_check_secret(void)
+{
+ struct winbindd_response response;
+ BOOL result;
+
+ ZERO_STRUCT(response);
+
+ result = winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response) ==
+ NSS_STATUS_SUCCESS;
+
+ if (result) {
+
+ if (response.data.num_entries == 0) {
+ printf("Secret is good\n");
+ } else {
+ printf("Secret is bad\n0x%08x\n",
+ response.data.num_entries);
+ }
+
+ return True;
+ }
+
+ return False;
+}
+
+/* Convert uid to sid */
+
+static BOOL wbinfo_uid_to_sid(uid_t uid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ request.data.uid = uid;
+ if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%s\n", response.data.sid.sid);
+
+ return True;
+}
+
+/* Convert gid to sid */
+
+static BOOL wbinfo_gid_to_sid(gid_t gid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ request.data.gid = gid;
+ if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%s\n", response.data.sid.sid);
+
+ return True;
+}
+
+/* Convert sid to uid */
+
+static BOOL wbinfo_sid_to_uid(char *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ fstrcpy(request.data.sid, sid);
+ if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%d\n", (int)response.data.uid);
+
+ return True;
+}
+
+static BOOL wbinfo_sid_to_gid(char *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send request */
+
+ fstrcpy(request.data.sid, sid);
+ if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%d\n", (int)response.data.gid);
+
+ return True;
+}
+
+/* Convert sid to string */
+
+static BOOL wbinfo_lookupsid(char *sid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ fstrcpy(request.data.sid, sid);
+ if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%s %d\n", response.data.name.name, response.data.name.type);
+
+ return True;
+}
+
+/* Convert string to sid */
+
+static BOOL wbinfo_lookupname(char *name)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /*
+ * Don't do the lookup if the name has no separator.
+ */
+
+ if (!strchr(name, *lp_winbind_separator()))
+ return False;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.name, name);
+ if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Display response */
+
+ printf("%s %d\n", response.data.sid.sid, response.data.sid.type);
+
+ return True;
+}
+
+/* Authenticate a user with a plaintext password */
+
+static BOOL wbinfo_auth(char *username)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ char *p;
+
+ /*
+ * Don't do the lookup if the name has no separator.
+ */
+
+ if (!strchr(username, *lp_winbind_separator()))
+ return False;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ p = strchr(username, '%');
+
+ if (p) {
+ *p = 0;
+ fstrcpy(request.data.auth.user, username);
+ fstrcpy(request.data.auth.pass, p + 1);
+ *p = '%';
+ } else
+ fstrcpy(request.data.auth.user, username);
+
+ result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
+
+ /* Display response */
+
+ printf("plaintext password authentication %s\n",
+ (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/* Authenticate a user with a challenge/response */
+
+static BOOL wbinfo_auth_crap(char *username)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ NSS_STATUS result;
+ fstring pass;
+ char *p;
+
+ /*
+ * Don't do the lookup if the name has no separator.
+ */
+
+ if (!strchr(username, *lp_winbind_separator()))
+ return False;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ p = strchr(username, '%');
+
+ if (p) {
+ *p = 0;
+ fstrcpy(request.data.auth_crap.user, username);
+ fstrcpy(pass, p + 1);
+ *p = '%';
+ } else
+ fstrcpy(request.data.auth_crap.user, username);
+
+ generate_random_buffer(request.data.auth_crap.chal, 8, False);
+
+ SMBencrypt((uchar *)pass, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.lm_resp);
+ SMBNTencrypt((uchar *)pass, request.data.auth_crap.chal,
+ (uchar *)request.data.auth_crap.nt_resp);
+
+ request.data.auth_crap.lm_resp_len = 24;
+ request.data.auth_crap.nt_resp_len = 24;
+
+ result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
+
+ /* Display response */
+
+ printf("challenge/response password authentication %s\n",
+ (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
+
+ return result == NSS_STATUS_SUCCESS;
+}
+
+/* Print domain users */
+
+static BOOL print_domain_users(void)
+{
+ struct winbindd_response response;
+ fstring name;
+
+ /* Send request to winbind daemon */
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Look through extra data */
+
+ if (!response.extra_data) {
+ return False;
+ }
+
+ while(next_token((char **)&response.extra_data, name, ",",
+ sizeof(fstring))) {
+ printf("%s\n", name);
+ }
+
+ return True;
+}
+
+/* Print domain groups */
+
+static BOOL print_domain_groups(void)
+{
+ struct winbindd_response response;
+ fstring name;
+
+ ZERO_STRUCT(response);
+
+ if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ return False;
+ }
+
+ /* Look through extra data */
+
+ if (!response.extra_data) {
+ return False;
+ }
+
+ while(next_token((char **)&response.extra_data, name, ",",
+ sizeof(fstring))) {
+ printf("%s\n", name);
+ }
+
+ return True;
+}
+
+/* Set the authorised user for winbindd access in secrets.tdb */
+
+static BOOL wbinfo_set_auth_user(char *username)
+{
+ char *password;
+
+ /* Separate into user and password */
+
+ password = strchr(username, '%');
+
+ if (password) {
+ *password = 0;
+ password++;
+ } else
+ password = "";
+
+ /* Store in secrets.tdb */
+
+ if (!secrets_store(SECRETS_AUTH_USER, username, strlen(username) + 1) ||
+ !secrets_store(SECRETS_AUTH_PASSWORD, password, strlen(password) + 1)) {
+ fprintf(stderr, "error storing authenticated user info\n");
+ return False;
+ }
+
+ return True;
+}
+
+/* Print program usage */
+
+static void usage(void)
+{
+ printf("Usage: wbinfo -ug | -n name | -sSY sid | -UG uid/gid | -tm "
+ "| -a user%%password\n");
+ printf("\t-u\t\t\tlists all domain users\n");
+ printf("\t-g\t\t\tlists all domain groups\n");
+ printf("\t-n name\t\t\tconverts name to sid\n");
+ printf("\t-s sid\t\t\tconverts sid to name\n");
+ printf("\t-U uid\t\t\tconverts uid to sid\n");
+ printf("\t-G gid\t\t\tconverts gid to sid\n");
+ printf("\t-S sid\t\t\tconverts sid to uid\n");
+ printf("\t-Y sid\t\t\tconverts sid to gid\n");
+ printf("\t-t\t\t\tcheck shared secret\n");
+ printf("\t-m\t\t\tlist trusted domains\n");
+ printf("\t-r user\t\t\tget user groups\n");
+ printf("\t-a user%%password\tauthenticate user\n");
+}
+
+/* Main program */
+
+enum {
+ OPT_SET_AUTH_USER = 1000
+};
+
+int main(int argc, char **argv)
+{
+ extern pstring global_myname;
+ int opt;
+
+ poptContext pc;
+ static char *string_arg;
+ static int int_arg;
+ BOOL got_command = False;
+
+ struct poptOption long_options[] = {
+
+ /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+ { "help", 'h', POPT_ARG_NONE, 0, 'h' },
+ { "domain-users", 'u', POPT_ARG_NONE, 0, 'u' },
+ { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g' },
+ { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n' },
+ { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's' },
+ { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U' },
+ { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G' },
+ { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S' },
+ { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y' },
+ { "check-secret", 't', POPT_ARG_NONE, 0, 't' },
+ { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm' },
+ { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r' },
+ { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a' },
+ { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER },
+ { 0, 0, 0, 0 }
+ };
+
+ /* Samba client initialisation */
+
+ if (!*global_myname) {
+ char *p;
+
+ fstrcpy(global_myname, myhostname());
+ p = strchr(global_myname, '.');
+ if (p) {
+ *p = 0;
+ }
+ }
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
+ fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
+ dyn_CONFIGFILE, strerror(errno));
+ exit(1);
+ }
+
+ load_interfaces();
+
+ /* Parse command line options */
+
+ if (argc == 1) {
+ usage();
+ return 1;
+ }
+
+ /* Parse options */
+
+ pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ if (got_command) {
+ fprintf(stderr, "No more than one command may be specified "
+ "at once.\n");
+ exit(1);
+ }
+ got_command = True;
+ }
+
+ pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'u':
+ if (!print_domain_users()) {
+ printf("Error looking up domain users\n");
+ return 1;
+ }
+ break;
+ case 'g':
+ if (!print_domain_groups()) {
+ printf("Error looking up domain groups\n");
+ return 1;
+ }
+ break;
+ case 's':
+ if (!wbinfo_lookupsid(string_arg)) {
+ printf("Could not lookup sid %s\n", string_arg);
+ return 1;
+ }
+ break;
+ case 'n':
+ if (!wbinfo_lookupname(string_arg)) {
+ printf("Could not lookup name %s\n", string_arg);
+ return 1;
+ }
+ break;
+ case 'U':
+ if (!wbinfo_uid_to_sid(int_arg)) {
+ printf("Could not convert uid %d to sid\n", int_arg);
+ return 1;
+ }
+ break;
+ case 'G':
+ if (!wbinfo_gid_to_sid(int_arg)) {
+ printf("Could not convert gid %d to sid\n",
+ int_arg);
+ return 1;
+ }
+ break;
+ case 'S':
+ if (!wbinfo_sid_to_uid(string_arg)) {
+ printf("Could not convert sid %s to uid\n",
+ string_arg);
+ return 1;
+ }
+ break;
+ case 'Y':
+ if (!wbinfo_sid_to_gid(string_arg)) {
+ printf("Could not convert sid %s to gid\n",
+ string_arg);
+ return 1;
+ }
+ break;
+ case 't':
+ if (!wbinfo_check_secret()) {
+ printf("Could not check secret\n");
+ return 1;
+ }
+ break;
+ case 'm':
+ if (!wbinfo_list_domains()) {
+ printf("Could not list trusted domains\n");
+ return 1;
+ }
+ break;
+ case 'r':
+ if (!wbinfo_get_usergroups(string_arg)) {
+ printf("Could not get groups for user %s\n",
+ string_arg);
+ return 1;
+ }
+ break;
+ case 'a': {
+ BOOL got_error = False;
+
+ if (!wbinfo_auth(string_arg)) {
+ printf("Could not authenticate user %s with "
+ "plaintext password\n", string_arg);
+ got_error = True;
+ }
+
+ if (!wbinfo_auth_crap(string_arg)) {
+ printf("Could not authenticate user %s with "
+ "challenge/response\n", string_arg);
+ got_error = True;
+ }
+
+ if (got_error)
+ return 1;
+ break;
+ }
+ case OPT_SET_AUTH_USER:
+ if (!(wbinfo_set_auth_user(string_arg))) {
+ return 1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Invalid option\n");
+ usage();
+ return 1;
+ }
+ }
+
+ /* Clean exit */
+
+ return 0;
+}
diff --git a/source/nsswitch/winbind_nss.c b/source/nsswitch/winbind_nss.c
new file mode 100644
index 00000000000..462c791277f
--- /dev/null
+++ b/source/nsswitch/winbind_nss.c
@@ -0,0 +1,846 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Windows NT Domain nsswitch module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
+
+/* Prototypes from common.c */
+
+void init_request(struct winbindd_request *req,int rq_type);
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+int write_sock(void *buffer, int count);
+int read_reply(struct winbindd_response *response);
+void free_response(struct winbindd_response *response);
+
+/* Allocate some space from the nss static buffer. The buffer and buflen
+ are the pointers passed in by the C library to the _nss_ntdom_*
+ functions. */
+
+static char *get_static(char **buffer, int *buflen, int len)
+{
+ char *result;
+
+ /* Error check. We return false if things aren't set up right, or
+ there isn't enough buffer space left. */
+
+ if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
+ return NULL;
+ }
+
+ /* Some architectures, like Sparc, need pointers aligned on
+ boundaries */
+#if _ALIGNMENT_REQUIRED
+ {
+ int mod = len % _MAX_ALIGNMENT;
+ if(mod != 0)
+ len += _MAX_ALIGNMENT - mod;
+ }
+#endif
+
+ /* Return an index into the static buffer */
+
+ result = *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ return result;
+}
+
+/* I've copied the strtok() replacement function next_token() from
+ lib/util_str.c as I really don't want to have to link in any other
+ objects if I can possibly avoid it. */
+
+BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
+{
+ char *s;
+ BOOL quoted;
+ size_t len=1;
+
+ if (!ptr) return(False);
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep) sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while (*s && strchr(sep,*s)) s++;
+
+ /* nothing left? */
+ if (! *s) return(False);
+
+ /* copy over the token */
+ for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+
+ return(True);
+}
+
+
+/* Fill a pwent structure from a winbindd_response structure. We use
+ the static data passed to us by libc to put strings and stuff in.
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
+
+static NSS_STATUS fill_pwent(struct passwd *result,
+ struct winbindd_pw *pw,
+ char **buffer, int *buflen)
+{
+ /* User name */
+
+ if ((result->pw_name =
+ get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_name, pw->pw_name);
+
+ /* Password */
+
+ if ((result->pw_passwd =
+ get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_passwd, pw->pw_passwd);
+
+ /* [ug]id */
+
+ result->pw_uid = pw->pw_uid;
+ result->pw_gid = pw->pw_gid;
+
+ /* GECOS */
+
+ if ((result->pw_gecos =
+ get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_gecos, pw->pw_gecos);
+
+ /* Home directory */
+
+ if ((result->pw_dir =
+ get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_dir, pw->pw_dir);
+
+ /* Logon shell */
+
+ if ((result->pw_shell =
+ get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->pw_shell, pw->pw_shell);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* Fill a grent structure from a winbindd_response structure. We use
+ the static data passed to us by libc to put strings and stuff in.
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
+
+static int fill_grent(struct group *result, struct winbindd_gr *gr,
+ char *gr_mem, char **buffer, int *buflen)
+{
+ fstring name;
+ int i;
+
+ /* Group name */
+
+ if ((result->gr_name =
+ get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->gr_name, gr->gr_name);
+
+ /* Password */
+
+ if ((result->gr_passwd =
+ get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy(result->gr_passwd, gr->gr_passwd);
+
+ /* gid */
+
+ result->gr_gid = gr->gr_gid;
+
+ /* Group membership */
+
+ if ((gr->num_gr_mem < 0) || !gr_mem) {
+ gr->num_gr_mem = 0;
+ }
+
+ if ((result->gr_mem =
+ (char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) *
+ sizeof(char *))) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (gr->num_gr_mem == 0) {
+
+ /* Group is empty */
+
+ *(result->gr_mem) = NULL;
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* Start looking at extra data */
+
+ i = 0;
+
+ while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
+
+ /* Allocate space for member */
+
+ if (((result->gr_mem)[i] =
+ get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
+
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ strcpy((result->gr_mem)[i], name);
+ i++;
+ }
+
+ /* Terminate list */
+
+ (result->gr_mem)[i] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * NSS user functions
+ */
+
+static struct winbindd_response getpwent_response;
+
+static int ndx_pw_cache; /* Current index into pwd cache */
+static int num_pw_cache; /* Current size of pwd cache */
+
+/* Rewind "file pointer" to start of ntdom password database */
+
+NSS_STATUS
+_nss_winbind_setpwent(void)
+{
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setpwent\n", getpid());
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+
+ return winbindd_request(WINBINDD_SETPWENT, NULL, NULL);
+}
+
+/* Close ntdom password database "file pointer" */
+
+NSS_STATUS
+_nss_winbind_endpwent(void)
+{
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endpwent\n", getpid());
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+
+ return winbindd_request(WINBINDD_ENDPWENT, NULL, NULL);
+}
+
+/* Fetch the next password entry from ntdom password database */
+
+#define MAX_GETPWENT_USERS 250
+
+NSS_STATUS
+_nss_winbind_getpwent_r(struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ static int called_again;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwent\n", getpid());
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_pw_cache < num_pw_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_pw_cache > 0) {
+ free_response(&getpwent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getpwent_response);
+
+ request.data.num_entries = MAX_GETPWENT_USERS;
+
+ ret = winbindd_request(WINBINDD_GETPWENT, &request,
+ &getpwent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_pw *pw_cache;
+
+ /* Fill cache */
+
+ ndx_pw_cache = 0;
+ num_pw_cache = getpwent_response.data.num_entries;
+
+ /* Return a result */
+
+ return_result:
+
+ pw_cache = getpwent_response.extra_data;
+
+ /* Check data is valid */
+
+ if (pw_cache == NULL) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
+ &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ *errnop = errno = 0;
+ called_again = False;
+ ndx_pw_cache++;
+
+ /* If we've finished with this lot of results free cache */
+
+ if (ndx_pw_cache == num_pw_cache) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+ }
+
+ return ret;
+}
+
+/* Return passwd struct from uid */
+
+NSS_STATUS
+_nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response=0;
+
+ /* If our static buffer needs to be expanded we are called again */
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ request.data.uid = uid;
+
+ ret = winbindd_request(WINBINDD_GETPWNAM_FROM_UID, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = errno = 0;
+ }
+
+ free_response(&response);
+ return ret;
+}
+
+/* Return passwd struct from username */
+
+NSS_STATUS
+_nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
+
+ strncpy(request.data.username, name,
+ sizeof(request.data.username) - 1);
+ request.data.username
+ [sizeof(request.data.username) - 1] = '\0';
+
+ ret = winbindd_request(WINBINDD_GETPWNAM_FROM_USER, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw, &buffer,
+ &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = errno = 0;
+ }
+
+ free_response(&response);
+ return ret;
+}
+
+/*
+ * NSS group functions
+ */
+
+static struct winbindd_response getgrent_response;
+
+static int ndx_gr_cache; /* Current index into grp cache */
+static int num_gr_cache; /* Current size of grp cache */
+
+/* Rewind "file pointer" to start of ntdom group database */
+
+NSS_STATUS
+_nss_winbind_setgrent(void)
+{
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setgrent\n", getpid());
+#endif
+
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+
+ return winbindd_request(WINBINDD_SETGRENT, NULL, NULL);
+}
+
+/* Close "file pointer" for ntdom group database */
+
+NSS_STATUS
+_nss_winbind_endgrent(void)
+{
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endgrent\n", getpid());
+#endif
+
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+
+ return winbindd_request(WINBINDD_ENDGRENT, NULL, NULL);
+}
+
+/* Get next entry from ntdom group database */
+
+#define MAX_GETGRENT_USERS 250
+
+NSS_STATUS
+_nss_winbind_getgrent_r(struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_request request;
+ static int called_again;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrent\n", getpid());
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_gr_cache < num_gr_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_gr_cache > 0) {
+ free_response(&getgrent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getgrent_response);
+
+ request.data.num_entries = MAX_GETGRENT_USERS;
+
+ ret = winbindd_request(WINBINDD_GETGRENT, &request,
+ &getgrent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_gr *gr_cache;
+ int mem_ofs;
+
+ /* Fill cache */
+
+ ndx_gr_cache = 0;
+ num_gr_cache = getgrent_response.data.num_entries;
+
+ /* Return a result */
+
+ return_result:
+
+ gr_cache = getgrent_response.extra_data;
+
+ /* Check data is valid */
+
+ if (gr_cache == NULL) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Fill group membership. The offset into the extra data
+ for the group membership is the reported offset plus the
+ size of all the winbindd_gr records returned. */
+
+ mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
+ num_gr_cache * sizeof(struct winbindd_gr);
+
+ ret = fill_grent(result, &gr_cache[ndx_gr_cache],
+ ((char *)getgrent_response.extra_data)+mem_ofs,
+ &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ *errnop = 0;
+ called_again = False;
+ ndx_gr_cache++;
+
+ /* If we've finished with this lot of results free cache */
+
+ if (ndx_gr_cache == num_gr_cache) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+ }
+
+ return ret;
+}
+
+/* Return group struct from group name */
+
+NSS_STATUS
+_nss_winbind_getgrnam_r(const char *name,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.groupname, name,
+ sizeof(request.data.groupname));
+ request.data.groupname
+ [sizeof(request.data.groupname) - 1] = '\0';
+
+ ret = winbindd_request(WINBINDD_GETGRNAM_FROM_GROUP,
+ &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = 0;
+ }
+
+ free_response(&response);
+ return ret;
+}
+
+/* Return group struct from gid */
+
+NSS_STATUS
+_nss_winbind_getgrgid_r(gid_t gid,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
+{
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ ret = winbindd_request(WINBINDD_GETGRNAM_FROM_GID, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = 0;
+ }
+
+ free_response(&response);
+ return ret;
+}
+
+/* Initialise supplementary groups */
+
+NSS_STATUS
+_nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
+ long int *size, gid_t **groups, long int limit,
+ int *errnop)
+{
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int i;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
+ user, group);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.username, user,
+ sizeof(request.data.username) - 1);
+
+ ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ int num_gids = response.data.num_entries;
+ gid_t *gid_list = (gid_t *)response.extra_data;
+
+ /* Copy group list to client */
+
+ for (i = 0; i < num_gids; i++) {
+
+ /* Skip primary group */
+
+ if (gid_list[i] == group) continue;
+
+ /* Add to buffer */
+
+ if (*start == *size && limit <= 0) {
+ (*groups) = realloc(
+ (*groups), (2 * (*size) + 1) * sizeof(**groups));
+ if (! *groups) goto done;
+ *size = 2 * (*size) + 1;
+ }
+
+ if (*start == *size) goto done;
+
+ (*groups)[*start] = gid_list[i];
+ *start += 1;
+
+ /* Filled buffer? */
+
+ if (*start == limit) goto done;
+ }
+ }
+
+ /* Back to your regularly scheduled programming */
+
+ done:
+ return ret;
+}
diff --git a/source/nsswitch/winbind_nss_config.h b/source/nsswitch/winbind_nss_config.h
new file mode 100644
index 00000000000..88561ee8084
--- /dev/null
+++ b/source/nsswitch/winbind_nss_config.h
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _WINBIND_NSS_CONFIG_H
+#define _WINBIND_NSS_CONFIG_H
+
+/* Include header files from data in config.h file */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <pwd.h>
+#include "nsswitch/nss.h"
+
+/* Declarations for functions in winbind_nss.c
+ needed in winbind_nss_solaris.c (solaris wrapper to nss) */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result,
+ char* buffer, size_t buflen, int* errnop);
+
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+
+/* I'm trying really hard not to include anything from smb.h with the
+ result of some silly looking redeclaration of structures. */
+
+#ifndef _PSTRING
+#define _PSTRING
+#define PSTRING_LEN 1024
+#define FSTRING_LEN 256
+typedef char pstring[PSTRING_LEN];
+typedef char fstring[FSTRING_LEN];
+#endif
+
+#ifndef _BOOL
+#define _BOOL /* So we don't typedef BOOL again in vfs.h */
+#define False (0)
+#define True (1)
+#define Auto (2)
+typedef int BOOL;
+#endif
+
+#if !defined(uint32)
+#if (SIZEOF_INT == 4)
+#define uint32 unsigned int
+#elif (SIZEOF_LONG == 4)
+#define uint32 unsigned long
+#elif (SIZEOF_SHORT == 4)
+#define uint32 unsigned short
+#endif
+#endif
+
+#if !defined(uint16)
+#if (SIZEOF_SHORT == 4)
+#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
+#else /* SIZEOF_SHORT != 4 */
+#define uint16 unsigned short
+#endif /* SIZEOF_SHORT != 4 */
+#endif
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+/* zero a structure */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
+
+/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
+
+#ifndef S_IFSOCK
+#define S_IFSOCK S_IFIFO
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK)
+#endif
+
+#endif
diff --git a/source/nsswitch/winbind_nss_solaris.c b/source/nsswitch/winbind_nss_solaris.c
new file mode 100644
index 00000000000..9c71c75e9d2
--- /dev/null
+++ b/source/nsswitch/winbind_nss_solaris.c
@@ -0,0 +1,279 @@
+/*
+ Solaris NSS wrapper for winbind
+ - Shirish Kalele 2000
+
+ Based on Luke Howard's ldap_nss module for Solaris
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <sys/syslog.h>
+#include "includes.h"
+#include "winbind_nss_config.h"
+
+#ifdef HAVE_NSS_COMMON_H
+
+#undef NSS_DEBUG
+
+#ifdef NSS_DEBUG
+#define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
+#else
+#define NSS_DEBUG(str) ;
+#endif
+
+#define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
+
+#define make_pwent_str(dest, src) \
+{ \
+ if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
+ { \
+ *errnop = ERANGE; \
+ NSS_DEBUG("ERANGE error"); \
+ return NSS_STATUS_TRYAGAIN; \
+ } \
+ strcpy(dest, src); \
+}
+
+static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_DEBUG("_nss_winbind_setpwent_solwrap");
+ return _nss_winbind_setpwent();
+}
+
+static NSS_STATUS
+_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
+{
+ NSS_DEBUG("_nss_winbind_endpwent_solwrap");
+ return _nss_winbind_endpwent();
+}
+
+static NSS_STATUS
+_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
+{
+ NSS_STATUS ret;
+ char* buffer = NSS_ARGS(args)->buf.buffer;
+ int buflen = NSS_ARGS(args)->buf.buflen;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+ int* errnop = &NSS_ARGS(args)->erange;
+ char logmsg[80];
+
+ ret = _nss_winbind_getpwent_r(result, buffer,
+ buflen, errnop);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ {
+ snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
+ result->pw_name);
+ NSS_DEBUG(logmsg);
+ NSS_ARGS(args)->returnval = (void*) result;
+ } else {
+ snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
+ NSS_DEBUG(logmsg);
+ }
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
+
+ ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
+ ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
+{
+ SAFE_FREE(be);
+ NSS_DEBUG("_nss_winbind_passwd_destr");
+ return NSS_STATUS_SUCCESS;
+}
+
+static nss_backend_op_t passwd_ops[] =
+{
+ _nss_winbind_passwd_destr,
+ _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */
+ _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */
+ _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */
+ _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */
+ _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */
+};
+
+nss_backend_t*
+_nss_winbind_passwd_constr (const char* db_name,
+ const char* src_name,
+ const char* cfg_args)
+{
+ nss_backend_t *be;
+
+ if(!(be = (nss_backend_t*) malloc(sizeof(nss_backend_t))) )
+ return NULL;
+
+ be->ops = passwd_ops;
+ be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
+
+ NSS_DEBUG("Initialized nss_winbind passwd backend");
+ return be;
+}
+
+/*****************************************************************
+ GROUP database backend
+ *****************************************************************/
+
+static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
+{
+ NSS_DEBUG("_nss_winbind_setgrent_solwrap");
+ return _nss_winbind_setgrent();
+}
+
+static NSS_STATUS
+_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
+{
+ NSS_DEBUG("_nss_winbind_endgrent_solwrap");
+ return _nss_winbind_endgrent();
+}
+
+static NSS_STATUS
+_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ char* buffer = NSS_ARGS(args)->buf.buffer;
+ int buflen = NSS_ARGS(args)->buf.buflen;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+ int* errnop = &NSS_ARGS(args)->erange;
+ char logmsg[80];
+
+ ret = _nss_winbind_getgrent_r(result, buffer,
+ buflen, errnop);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ {
+ snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
+ NSS_DEBUG(logmsg);
+ NSS_ARGS(args)->returnval = (void*) result;
+ } else {
+ snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
+ NSS_DEBUG(logmsg);
+ }
+
+ return ret;
+
+}
+
+static NSS_STATUS
+_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
+ ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_STATUS ret;
+ struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
+
+ NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
+ ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
+ result,
+ NSS_ARGS(args)->buf.buffer,
+ NSS_ARGS(args)->buf.buflen,
+ &NSS_ARGS(args)->erange);
+
+ if(ret == NSS_STATUS_SUCCESS)
+ NSS_ARGS(args)->returnval = (void*) result;
+
+ return ret;
+}
+
+static NSS_STATUS
+_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
+{
+ NSS_DEBUG("_nss_winbind_getgroupsbymember");
+ return NSS_STATUS_NOTFOUND;
+}
+
+static NSS_STATUS
+_nss_winbind_group_destr (nss_backend_t* be, void* args)
+{
+ SAFE_FREE(be);
+ NSS_DEBUG("_nss_winbind_group_destr");
+ return NSS_STATUS_SUCCESS;
+}
+
+static nss_backend_op_t group_ops[] =
+{
+ _nss_winbind_group_destr,
+ _nss_winbind_endgrent_solwrap,
+ _nss_winbind_setgrent_solwrap,
+ _nss_winbind_getgrent_solwrap,
+ _nss_winbind_getgrnam_solwrap,
+ _nss_winbind_getgrgid_solwrap,
+ _nss_winbind_getgroupsbymember_solwrap
+};
+
+nss_backend_t*
+_nss_winbind_group_constr (const char* db_name,
+ const char* src_name,
+ const char* cfg_args)
+{
+ nss_backend_t* be;
+
+ if(!(be = (nss_backend_t*) malloc(sizeof(nss_backend_t))) )
+ return NULL;
+
+ be->ops = group_ops;
+ be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
+
+ NSS_DEBUG("Initialized nss_winbind group backend");
+ return be;
+}
+
+#endif /* SUN_NSS */
+
+
diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c
new file mode 100644
index 00000000000..e68708469c8
--- /dev/null
+++ b/source/nsswitch/winbindd.c
@@ -0,0 +1,870 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) by Tim Potter 2000, 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/* List of all connected clients */
+
+struct winbindd_cli_state *client_list;
+static int num_clients;
+BOOL opt_nocache;
+
+/* Reload configuration */
+
+static BOOL reload_services_file(BOOL test)
+{
+ BOOL ret;
+ pstring logfile;
+
+ if (lp_loaded()) {
+ pstring fname;
+
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) {
+ pstrcpy(dyn_CONFIGFILE,fname);
+ test = False;
+ }
+ }
+
+ snprintf(logfile, sizeof(logfile), "%s/log.winbindd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+
+ reopen_logs();
+ ret = lp_load(dyn_CONFIGFILE,False,False,True);
+
+ snprintf(logfile, sizeof(logfile), "%s/log.winbindd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+
+ reopen_logs();
+ load_interfaces();
+
+ return(ret);
+}
+
+#if DUMP_CORE
+
+/**************************************************************************** **
+ Prepare to dump a core file - carefully!
+ **************************************************************************** */
+
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ pstrcpy( dname, lp_logfile() );
+ if ((p=strrchr(dname,'/')))
+ *p=0;
+ pstrcat( dname, "/corefiles" );
+ mkdir( dname, 0700 );
+ sys_chown( dname, getuid(), getgid() );
+ chmod( dname, 0700 );
+ if ( chdir(dname) )
+ return( False );
+ umask( ~(0700) );
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit( RLIMIT_CORE, &rlp );
+ rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
+ setrlimit( RLIMIT_CORE, &rlp );
+ getrlimit( RLIMIT_CORE, &rlp );
+ DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
+ }
+#endif
+#endif
+
+ DEBUG(0,("Dumping core in %s\n",dname));
+ abort();
+ return( True );
+} /* dump_core */
+#endif
+
+/**************************************************************************** **
+ Handle a fault..
+ **************************************************************************** */
+
+static void fault_quit(void)
+{
+#if DUMP_CORE
+ dump_core();
+#endif
+}
+
+static void winbindd_status(void)
+{
+ struct winbindd_cli_state *tmp;
+
+ DEBUG(0, ("winbindd status:\n"));
+
+ /* Print client state information */
+
+ DEBUG(0, ("\t%d clients currently active\n", num_clients));
+
+ if (DEBUGLEVEL >= 2 && num_clients) {
+ DEBUG(2, ("\tclient list:\n"));
+ for(tmp = client_list; tmp; tmp = tmp->next) {
+ DEBUG(2, ("\t\tpid %d, sock %d, rbl %d, wbl %d\n",
+ tmp->pid, tmp->sock, tmp->read_buf_len,
+ tmp->write_buf_len));
+ }
+ }
+}
+
+/* Print winbindd status to log file */
+
+static void print_winbindd_status(void)
+{
+ winbindd_status();
+ winbindd_idmap_status();
+ winbindd_cm_status();
+}
+
+/* Flush client cache */
+
+static void flush_caches(void)
+{
+ /* Clear cached user and group enumation info */
+ wcache_flush_cache();
+}
+
+/* Handle the signal by unlinking socket and exiting */
+
+static void terminate(void)
+{
+ pstring path;
+
+ /* Remove socket file */
+ snprintf(path, sizeof(path), "%s/%s",
+ WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
+ unlink(path);
+ exit(0);
+}
+
+static BOOL do_sigterm;
+
+static void termination_handler(int signum)
+{
+ do_sigterm = True;
+}
+
+static BOOL do_sigusr1;
+
+static void sigusr1_handler(int signum)
+{
+ do_sigusr1 = True;
+}
+
+static BOOL do_sighup;
+
+static void sighup_handler(int signum)
+{
+ do_sighup = True;
+}
+
+/* Create winbindd socket */
+
+static int create_sock(void)
+{
+ struct sockaddr_un sunaddr;
+ struct stat st;
+ int sock;
+ mode_t old_umask;
+ pstring path;
+
+ /* Create the socket directory or reuse the existing one */
+
+ if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
+
+ if (errno == ENOENT) {
+
+ /* Create directory */
+
+ if (mkdir(WINBINDD_SOCKET_DIR, 0755) == -1) {
+ DEBUG(0, ("error creating socket directory "
+ "%s: %s\n", WINBINDD_SOCKET_DIR,
+ strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ DEBUG(0, ("lstat failed on socket directory %s: %s\n",
+ WINBINDD_SOCKET_DIR, strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ /* Check ownership and permission on existing directory */
+
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("socket directory %s isn't a directory\n",
+ WINBINDD_SOCKET_DIR));
+ return -1;
+ }
+
+ if ((st.st_uid != sec_initial_uid()) ||
+ ((st.st_mode & 0777) != 0755)) {
+ DEBUG(0, ("invalid permissions on socket directory "
+ "%s\n", WINBINDD_SOCKET_DIR));
+ return -1;
+ }
+ }
+
+ /* Create the socket file */
+
+ old_umask = umask(0);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock == -1) {
+ perror("socket");
+ return -1;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s",
+ WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
+
+ unlink(path);
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
+
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+ DEBUG(0, ("bind failed on winbind socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ return -1;
+ }
+
+ if (listen(sock, 5) == -1) {
+ DEBUG(0, ("listen failed on winbind socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ return -1;
+ }
+
+ umask(old_umask);
+
+ /* Success! */
+
+ return sock;
+}
+
+struct dispatch_table {
+ enum winbindd_cmd cmd;
+ enum winbindd_result (*fn)(struct winbindd_cli_state *state);
+ char *winbindd_cmd_name;
+};
+
+static struct dispatch_table dispatch_table[] = {
+
+ /* User functions */
+
+ { WINBINDD_GETPWNAM_FROM_USER, winbindd_getpwnam_from_user, "GETPWNAM_FROM_USER" },
+ { WINBINDD_GETPWNAM_FROM_UID, winbindd_getpwnam_from_uid, "GETPWNAM_FROM_UID" },
+
+ { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" },
+ { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" },
+ { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" },
+
+ { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" },
+
+ /* Group functions */
+
+ { WINBINDD_GETGRNAM_FROM_GROUP, winbindd_getgrnam_from_group, "GETGRNAM_FROM_GROUP" },
+ { WINBINDD_GETGRNAM_FROM_GID, winbindd_getgrnam_from_gid, "GETGRNAM_FROM_GID" },
+ { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" },
+ { WINBINDD_ENDGRENT, winbindd_endgrent, "ENDGRENT" },
+ { WINBINDD_GETGRENT, winbindd_getgrent, "GETGRENT" },
+
+ /* PAM auth functions */
+
+ { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" },
+ { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" },
+ { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" },
+
+ /* Enumeration functions */
+
+ { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" },
+ { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
+ { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" },
+
+ /* SID related functions */
+
+ { WINBINDD_LOOKUPSID, winbindd_lookupsid, "LOOKUPSID" },
+ { WINBINDD_LOOKUPNAME, winbindd_lookupname, "LOOKUPNAME" },
+
+ /* Lookup related functions */
+
+ { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" },
+ { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
+ { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
+ { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
+
+ /* Miscellaneous */
+
+ { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
+
+ /* End of list */
+
+ { WINBINDD_NUM_CMDS, NULL, "NONE" }
+};
+
+static void process_request(struct winbindd_cli_state *state)
+{
+ struct dispatch_table *table = dispatch_table;
+
+ /* Free response data - we may be interrupted and receive another
+ command before being able to send this data off. */
+
+ SAFE_FREE(state->response.extra_data);
+
+ ZERO_STRUCT(state->response);
+
+ state->response.result = WINBINDD_ERROR;
+ state->response.length = sizeof(struct winbindd_response);
+
+ /* Process command */
+
+ for (table = dispatch_table; table->fn; table++) {
+ if (state->request.cmd == table->cmd) {
+ DEBUG(10,("process_request: request fn %s\n", table->winbindd_cmd_name ));
+ state->response.result = table->fn(state);
+ break;
+ }
+ }
+
+ if (!table->fn)
+ DEBUG(10,("process_request: unknown request fn number %d\n", (int)state->request.cmd ));
+
+ /* In case extra data pointer is NULL */
+
+ if (!state->response.extra_data)
+ state->response.length = sizeof(struct winbindd_response);
+}
+
+/* Process a new connection by adding it to the client connection list */
+
+static void new_connection(int accept_sock)
+{
+ struct sockaddr_un sunaddr;
+ struct winbindd_cli_state *state;
+ socklen_t len;
+ int sock;
+
+ /* Accept connection */
+
+ len = sizeof(sunaddr);
+
+ do {
+ sock = accept(accept_sock, (struct sockaddr *)&sunaddr, &len);
+ } while (sock == -1 && errno == EINTR);
+
+ if (sock == -1)
+ return;
+
+ DEBUG(6,("accepted socket %d\n", sock));
+
+ /* Create new connection structure */
+
+ if ((state = (struct winbindd_cli_state *)
+ malloc(sizeof(*state))) == NULL)
+ return;
+
+ ZERO_STRUCTP(state);
+ state->sock = sock;
+
+ /* Add to connection list */
+
+ DLIST_ADD(client_list, state);
+ num_clients++;
+}
+
+/* Remove a client connection from client connection list */
+
+static void remove_client(struct winbindd_cli_state *state)
+{
+ /* It's a dead client - hold a funeral */
+
+ if (state != NULL) {
+
+ /* Close socket */
+
+ close(state->sock);
+
+ /* Free any getent state */
+
+ free_getent_state(state->getpwent_state);
+ free_getent_state(state->getgrent_state);
+
+ /* We may have some extra data that was not freed if the
+ client was killed unexpectedly */
+
+ SAFE_FREE(state->response.extra_data);
+
+ /* Remove from list and free */
+
+ DLIST_REMOVE(client_list, state);
+ SAFE_FREE(state);
+ num_clients--;
+ }
+}
+
+/* Process a complete received packet from a client */
+
+static void process_packet(struct winbindd_cli_state *state)
+{
+ /* Process request */
+
+ state->pid = state->request.pid;
+
+ process_request(state);
+
+ /* Update client state */
+
+ state->read_buf_len = 0;
+ state->write_buf_len = sizeof(struct winbindd_response);
+}
+
+/* Read some data from a client connection */
+
+static void client_read(struct winbindd_cli_state *state)
+{
+ int n;
+
+ /* Read data */
+
+ do {
+ n = read(state->sock, state->read_buf_len + (char *)&state->request,
+ sizeof(state->request) - state->read_buf_len);
+ } while (n == -1 && errno == EINTR);
+
+ DEBUG(10,("client_read: read %d bytes. Need %d more for a full request.\n", n,
+ sizeof(state->request) - n - state->read_buf_len ));
+
+ /* Read failed, kill client */
+
+ if (n == -1 || n == 0) {
+ DEBUG(5,("read failed on sock %d, pid %d: %s\n",
+ state->sock, state->pid,
+ (n == -1) ? strerror(errno) : "EOF"));
+
+ state->finished = True;
+ return;
+ }
+
+ /* Update client state */
+
+ state->read_buf_len += n;
+}
+
+/* Write some data to a client connection */
+
+static void client_write(struct winbindd_cli_state *state)
+{
+ char *data;
+ int num_written;
+
+ /* Write some data */
+
+ if (!state->write_extra_data) {
+
+ /* Write response structure */
+
+ data = (char *)&state->response + sizeof(state->response) -
+ state->write_buf_len;
+
+ } else {
+
+ /* Write extra data */
+
+ data = (char *)state->response.extra_data +
+ state->response.length -
+ sizeof(struct winbindd_response) -
+ state->write_buf_len;
+ }
+
+ do {
+ num_written = write(state->sock, data, state->write_buf_len);
+ } while (num_written == -1 && errno == EINTR);
+
+ DEBUG(10,("client_write: wrote %d bytes.\n", num_written ));
+
+ /* Write failed, kill cilent */
+
+ if (num_written == -1 || num_written == 0) {
+
+ DEBUG(3,("write failed on sock %d, pid %d: %s\n",
+ state->sock, state->pid,
+ (num_written == -1) ? strerror(errno) : "EOF"));
+
+ state->finished = True;
+
+ SAFE_FREE(state->response.extra_data);
+
+ return;
+ }
+
+ /* Update client state */
+
+ state->write_buf_len -= num_written;
+
+ /* Have we written all data? */
+
+ if (state->write_buf_len == 0) {
+
+ /* Take care of extra data */
+
+ if (state->write_extra_data) {
+
+ SAFE_FREE(state->response.extra_data);
+
+ state->write_extra_data = False;
+
+ DEBUG(10,("client_write: client_write: complete response written.\n"));
+
+ } else if (state->response.length >
+ sizeof(struct winbindd_response)) {
+
+ /* Start writing extra data */
+
+ state->write_buf_len =
+ state->response.length -
+ sizeof(struct winbindd_response);
+
+ DEBUG(10,("client_write: need to write %d extra data bytes.\n", (int)state->write_buf_len));
+
+ state->write_extra_data = True;
+ }
+ }
+}
+
+/* Process incoming clients on accept_sock. We use a tricky non-blocking,
+ non-forking, non-threaded model which allows us to handle many
+ simultaneous connections while remaining impervious to many denial of
+ service attacks. */
+
+static void process_loop(int accept_sock)
+{
+ /* We'll be doing this a lot */
+
+ while (1) {
+ struct winbindd_cli_state *state;
+ fd_set r_fds, w_fds;
+ int maxfd = accept_sock, selret;
+ struct timeval timeout;
+
+ /* Free up temporary memory */
+
+ lp_talloc_free();
+
+ /* Initialise fd lists for select() */
+
+ FD_ZERO(&r_fds);
+ FD_ZERO(&w_fds);
+ FD_SET(accept_sock, &r_fds);
+
+ timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
+ timeout.tv_usec = 0;
+
+ /* Set up client readers and writers */
+
+ state = client_list;
+
+ while (state) {
+
+ /* Dispose of client connection if it is marked as
+ finished */
+
+ if (state->finished) {
+ struct winbindd_cli_state *next = state->next;
+
+ remove_client(state);
+ state = next;
+ continue;
+ }
+
+ /* Select requires we know the highest fd used */
+
+ if (state->sock > maxfd)
+ maxfd = state->sock;
+
+ /* Add fd for reading */
+
+ if (state->read_buf_len != sizeof(state->request))
+ FD_SET(state->sock, &r_fds);
+
+ /* Add fd for writing */
+
+ if (state->write_buf_len)
+ FD_SET(state->sock, &w_fds);
+
+ state = state->next;
+ }
+
+ /* Call select */
+
+ selret = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
+
+ if (selret == 0)
+ continue;
+
+ if ((selret == -1 && errno != EINTR) || selret == 0) {
+
+ /* Select error, something is badly wrong */
+
+ perror("select");
+ exit(1);
+ }
+
+ /* Create a new connection if accept_sock readable */
+
+ if (selret > 0) {
+
+ if (FD_ISSET(accept_sock, &r_fds))
+ new_connection(accept_sock);
+
+ /* Process activity on client connections */
+
+ for (state = client_list; state; state = state->next) {
+
+ /* Data available for reading */
+
+ if (FD_ISSET(state->sock, &r_fds)) {
+
+ /* Read data */
+
+ client_read(state);
+
+#if 0
+ /* JRA - currently there's no length field in the request... */
+ /*
+ * If we have the start of a
+ * packet, then check the
+ * length field to make sure
+ * the client's not talking
+ * Mock Swedish.
+ */
+
+ if (state->read_buf_len >= sizeof(int)
+ && *(int *) state->buf != sizeof(state->request)) {
+
+ struct winbindd_cli_state *rem_state = state;
+
+ DEBUG(0,("process_loop: Invalid request size (%d) send, should be (%d)\n",
+ *(int *) rem_state->buf, sizeof(rem_state->request) ));
+
+ state = state_next;
+ remove_client(rem_state);
+ continue;
+ }
+#endif
+
+ /* A request packet might be
+ complete */
+
+ if (state->read_buf_len ==
+ sizeof(state->request)) {
+ process_packet(state);
+ }
+ }
+
+ /* Data available for writing */
+
+ if (FD_ISSET(state->sock, &w_fds))
+ client_write(state);
+ }
+ }
+
+ /* Check signal handling things */
+
+ if (do_sigterm)
+ terminate();
+
+ if (do_sighup) {
+
+ /* Flush winbindd cache */
+
+ flush_caches();
+ reload_services_file(True);
+ do_sighup = False;
+ }
+
+ if (do_sigusr1) {
+ print_winbindd_status();
+ do_sigusr1 = False;
+ }
+ }
+}
+
+/* Main function */
+
+struct winbindd_state server_state; /* Server state information */
+
+int main(int argc, char **argv)
+{
+ extern pstring global_myname;
+ extern fstring global_myworkgroup;
+ pstring logfile;
+ int accept_sock;
+ BOOL interactive = False;
+ int opt, new_debuglevel = -1;
+
+ /* glibc (?) likes to print "User defined signal 1" and exit if a
+ SIGUSR1 is received before a handler is installed */
+
+ CatchSignal(SIGUSR1, SIG_IGN);
+
+ fault_setup((void (*)(void *))fault_quit );
+ snprintf(logfile, sizeof(logfile), "%s/log.winbindd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+
+ /* Initialise for running in non-root mode */
+
+ sec_init();
+
+ /* Set environment variable so we don't recursively call ourselves.
+ This may also be useful interactively. */
+
+ SETENV(WINBINDD_DONT_ENV, "1", 1);
+
+ /* Initialise samba/rpc client stuff */
+
+ while ((opt = getopt(argc, argv, "id:s:n")) != EOF) {
+ switch (opt) {
+
+ /* Don't become a daemon */
+ case 'i':
+ interactive = True;
+ break;
+
+ /* disable cacheing */
+ case 'n':
+ opt_nocache = True;
+ break;
+
+ /* Run with specified debug level */
+ case 'd':
+ new_debuglevel = atoi(optarg);
+ break;
+
+ /* Load a different smb.conf file */
+ case 's':
+ pstrcpy(dyn_CONFIGFILE,optarg);
+ break;
+
+ default:
+ printf("Unknown option %c\n", (char)opt);
+ exit(1);
+ }
+ }
+
+ snprintf(logfile, sizeof(logfile), "%s/log.winbindd", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
+ setup_logging("winbindd", interactive);
+ reopen_logs();
+
+ DEBUG(1, ("winbindd version %s started.\n", VERSION ) );
+ DEBUGADD( 1, ( "Copyright The Samba Team 2000-2001\n" ) );
+
+ if (!reload_services_file(False)) {
+ DEBUG(0, ("error opening config file\n"));
+ exit(1);
+ }
+
+ /* Setup names. */
+ if (!*global_myname) {
+ char *p;
+
+ fstrcpy(global_myname, myhostname());
+ p = strchr(global_myname, '.');
+ if (p)
+ *p = 0;
+ }
+
+ fstrcpy(global_myworkgroup, lp_workgroup());
+
+ if (new_debuglevel != -1)
+ DEBUGLEVEL = new_debuglevel;
+
+ if (!interactive)
+ become_daemon();
+
+ load_interfaces();
+
+ secrets_init();
+
+ /* Get list of domains we look up requests for. This includes the
+ domain which we are a member of as well as any trusted
+ domains. */
+
+ get_domain_info();
+
+ ZERO_STRUCT(server_state);
+
+ /* Winbind daemon initialisation */
+
+ if (!winbindd_param_init())
+ return 1;
+
+ if (!winbindd_idmap_init())
+ return 1;
+
+ /* Unblock all signals we are interested in as they may have been
+ blocked by the parent process. */
+
+ BlockSignals(False, SIGINT);
+ BlockSignals(False, SIGQUIT);
+ BlockSignals(False, SIGTERM);
+ BlockSignals(False, SIGUSR1);
+ BlockSignals(False, SIGHUP);
+
+ /* Setup signal handlers */
+
+ CatchSignal(SIGINT, termination_handler); /* Exit on these sigs */
+ CatchSignal(SIGQUIT, termination_handler);
+ CatchSignal(SIGTERM, termination_handler);
+
+ CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
+
+ CatchSignal(SIGUSR1, sigusr1_handler); /* Debugging sigs */
+ CatchSignal(SIGHUP, sighup_handler);
+
+ /* Create UNIX domain socket */
+
+ if ((accept_sock = create_sock()) == -1) {
+ DEBUG(0, ("failed to create socket\n"));
+ return 1;
+ }
+
+ /* Loop waiting for requests */
+
+ process_loop(accept_sock);
+
+ return 0;
+}
diff --git a/source/nsswitch/winbindd.h b/source/nsswitch/winbindd.h
new file mode 100644
index 00000000000..74206da9ef0
--- /dev/null
+++ b/source/nsswitch/winbindd.h
@@ -0,0 +1,203 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _WINBINDD_H
+#define _WINBINDD_H
+
+#include "includes.h"
+#include "nterr.h"
+
+#include "winbindd_nss.h"
+
+/* Client state structure */
+
+struct winbindd_cli_state {
+ struct winbindd_cli_state *prev, *next; /* Linked list pointers */
+ int sock; /* Open socket from client */
+ pid_t pid; /* pid of client */
+ int read_buf_len, write_buf_len; /* Indexes in request/response */
+ BOOL finished; /* Can delete from list */
+ BOOL write_extra_data; /* Write extra_data field */
+ struct winbindd_request request; /* Request from client */
+ struct winbindd_response response; /* Respose to client */
+ struct getent_state *getpwent_state; /* State for getpwent() */
+ struct getent_state *getgrent_state; /* State for getgrent() */
+};
+
+/* State between get{pw,gr}ent() calls */
+
+struct getent_state {
+ struct getent_state *prev, *next;
+ void *sam_entries;
+ uint32 sam_entry_index, num_sam_entries;
+ BOOL got_sam_entries;
+ struct winbindd_domain *domain;
+};
+
+/* Storage for cached getpwent() user entries */
+
+struct getpwent_user {
+ fstring name; /* Account name */
+ fstring gecos; /* User information */
+ uint32 user_rid, group_rid; /* NT user and group rids */
+};
+
+/* Server state structure */
+
+struct winbindd_state {
+
+ /* User and group id pool */
+
+ uid_t uid_low, uid_high; /* Range of uids to allocate */
+ gid_t gid_low, gid_high; /* Range of gids to allocate */
+};
+
+extern struct winbindd_state server_state; /* Server information */
+
+typedef struct {
+ char *acct_name;
+ char *full_name;
+ uint32 user_rid;
+ uint32 group_rid; /* primary group */
+} WINBIND_USERINFO;
+
+/* per-domain methods. This is how LDAP vs RPC is selected
+ */
+struct winbindd_methods {
+ /* does this backend provide a consistent view of the data? (ie. is the primary group
+ always correct) */
+ BOOL consistent;
+
+ /* get a list of users, returning a WINBIND_USERINFO for each one */
+ NTSTATUS (*query_user_list)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info);
+
+ /* get a list of groups */
+ NTSTATUS (*enum_dom_groups)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info);
+
+ /* convert one user or group name to a sid */
+ NTSTATUS (*name_to_sid)(struct winbindd_domain *domain,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type);
+
+ /* convert a sid to a user or group name */
+ NTSTATUS (*sid_to_name)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type);
+
+ /* lookup user info for a given rid */
+ NTSTATUS (*query_user)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ WINBIND_USERINFO *user_info);
+
+ /* lookup all groups that a user is a member of. The backend
+ can also choose to lookup by username or rid for this
+ function */
+ NTSTATUS (*lookup_usergroups)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ uint32 *num_groups, uint32 **user_gids);
+
+ /* find all members of the group with the specified group_rid */
+ NTSTATUS (*lookup_groupmem)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 *num_names,
+ uint32 **rid_mem, char ***names,
+ uint32 **name_types);
+
+ /* return the current global sequence number */
+ NTSTATUS (*sequence_number)(struct winbindd_domain *domain, uint32 *seq);
+
+ /* enumerate trusted domains */
+ NTSTATUS (*trusted_domains)(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ DOM_SID **dom_sids);
+
+ /* find the domain sid */
+ NTSTATUS (*domain_sid)(struct winbindd_domain *domain,
+ DOM_SID *sid);
+};
+
+/* Structures to hold per domain information */
+struct winbindd_domain {
+ fstring name; /* Domain name */
+ fstring full_name; /* full Domain name (realm) */
+ DOM_SID sid; /* SID for this domain */
+ struct winbindd_methods *methods; /* lookup methods for
+ this domain (LDAP or
+ RPC) */
+ void *private; /* private data for the backends (used for connection cache) */
+ time_t last_seq_check;
+ uint32 sequence_number;
+ struct winbindd_domain *prev, *next; /* Linked list info */
+};
+
+extern struct winbindd_domain *domain_list; /* List of domains we know */
+
+/* Used to glue a policy handle and cli_state together */
+
+typedef struct {
+ struct cli_state *cli;
+ POLICY_HND pol;
+} CLI_POLICY_HND;
+
+#include "winbindd_proto.h"
+
+#include "rpc_parse.h"
+#include "rpc_client.h"
+
+#define WINBINDD_ESTABLISH_LOOP 30
+#define DOM_SEQUENCE_NONE ((uint32)-1)
+
+/* SETENV */
+#if HAVE_SETENV
+#define SETENV(name, value, overwrite) setenv(name,value,overwrite)
+#elif HAVE_PUTENV
+#define SETENV(name, value, overwrite) \
+{ \
+ fstring envvar; \
+ slprintf(envvar, sizeof(fstring), "%s=%s", name, value); \
+ putenv(envvar); \
+}
+#else
+#define SETENV(name, value, overwrite) ;
+#endif
+
+/* Authenticated user info is stored in secrets.tdb under these keys */
+
+#define SECRETS_AUTH_USER "SECRETS/AUTH_USER"
+#define SECRETS_AUTH_PASSWORD "SECRETS/AUTH_PASSWORD"
+
+#endif /* _WINBINDD_H */
diff --git a/source/nsswitch/winbindd_ads.c b/source/nsswitch/winbindd_ads.c
new file mode 100644
index 00000000000..a0d35030bf6
--- /dev/null
+++ b/source/nsswitch/winbindd_ads.c
@@ -0,0 +1,752 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Winbind ADS backend functions
+
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+#ifdef HAVE_ADS
+
+/* the realm of our primary LDAP server */
+static char *primary_realm;
+
+
+/*
+ a wrapper around ldap_search_s that retries depending on the error code
+ this is supposed to catch dropped connections and auto-reconnect
+*/
+ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *exp,
+ const char **attrs, void **res)
+{
+ ADS_STATUS status;
+ int count = 3;
+
+ if (!ads->ld &&
+ time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) {
+ return ADS_ERROR(LDAP_SERVER_DOWN);
+ }
+
+ while (count--) {
+ status = ads_do_search(ads, bind_path, scope, exp, attrs, res);
+ if (ADS_ERR_OK(status)) {
+ DEBUG(5,("Search for %s gave %d replies\n",
+ exp, ads_count_replies(ads, *res)));
+ return status;
+ }
+
+ if (*res) ads_msgfree(ads, *res);
+ *res = NULL;
+ DEBUG(1,("Reopening ads connection after error %s\n",
+ ads_errstr(status)));
+ if (ads->ld) {
+ /* we should unbind here, but that seems to trigger openldap bugs :(
+ ldap_unbind(ads->ld);
+ */
+ }
+ ads->ld = NULL;
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
+ ads_errstr(status)));
+ ads_destroy(&ads);
+ return status;
+ }
+ }
+
+ DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(status)));
+ return status;
+}
+
+
+ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
+ const char *exp,
+ const char **attrs)
+{
+ return ads_do_search_retry(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
+ exp, attrs, res);
+}
+
+ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, void **res,
+ const char *dn,
+ const char **attrs)
+{
+ return ads_do_search_retry(ads, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, res);
+}
+
+/*
+ return our ads connections structure for a domain. We keep the connection
+ open to make things faster
+*/
+static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ char *ccache;
+ struct in_addr server_ip;
+ char *sname;
+
+ if (domain->private) {
+ return (ADS_STRUCT *)domain->private;
+ }
+
+ /* we don't want this to affect the users ccache */
+ ccache = lock_path("winbindd_ccache");
+ SETENV("KRB5CCNAME", ccache, 1);
+ unlink(ccache);
+
+ if (resolve_name(domain->name, &server_ip, 0x1b)) {
+ sname = inet_ntoa(server_ip);
+ } else {
+ if (strcasecmp(domain->name, lp_workgroup()) != 0) {
+ DEBUG(1,("can't find domain controller for %s\n", domain->name));
+ return NULL;
+ }
+ sname = NULL;
+ }
+
+ ads = ads_init(primary_realm, sname, NULL, NULL);
+ if (!ads) {
+ DEBUG(1,("ads_init for domain %s failed\n", domain->name));
+ return NULL;
+ }
+
+ /* the machine acct password might have change - fetch it every time */
+ SAFE_FREE(ads->password);
+ ads->password = secrets_fetch_machine_password();
+
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status)) {
+ extern struct winbindd_methods msrpc_methods;
+ DEBUG(1,("ads_connect for domain %s failed: %s\n",
+ domain->name, ads_errstr(status)));
+ ads_destroy(&ads);
+
+ /* if we get ECONNREFUSED then it might be a NT4
+ server, fall back to MSRPC */
+ if (status.error_type == ADS_ERROR_SYSTEM &&
+ status.rc == ECONNREFUSED) {
+ DEBUG(1,("Trying MSRPC methods\n"));
+ domain->methods = &msrpc_methods;
+ }
+ return NULL;
+ }
+
+ /* remember our primary realm for trusted domain support */
+ if (!primary_realm) {
+ primary_realm = strdup(ads->realm);
+ }
+
+ fstrcpy(domain->full_name, ads->server_realm);
+
+ domain->private = (void *)ads;
+ return ads;
+}
+
+/* useful utility */
+static void sid_from_rid(struct winbindd_domain *domain, uint32 rid, DOM_SID *sid)
+{
+ sid_copy(sid, &domain->sid);
+ sid_append_rid(sid, rid);
+}
+
+/* turn a sAMAccountType into a SID_NAME_USE */
+static enum SID_NAME_USE ads_atype_map(uint32 atype)
+{
+ switch (atype & 0xF0000000) {
+ case ATYPE_GROUP:
+ return SID_NAME_DOM_GRP;
+ case ATYPE_USER:
+ return SID_NAME_USER;
+ default:
+ DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
+ }
+ return SID_NAME_UNKNOWN;
+}
+
+/* Query display info for a realm. This is the basic user list fn */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"sAMAccountName", "name", "objectSid", "primaryGroupID",
+ "sAMAccountType", NULL};
+ int i, count;
+ ADS_STATUS rc;
+ void *res = NULL;
+ void *msg = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ *num_entries = 0;
+
+ DEBUG(3,("ads: query_user_list\n"));
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ DEBUG(1,("query_user_list: No users found\n"));
+ goto done;
+ }
+
+ (*info) = talloc(mem_ctx, count * sizeof(**info));
+ if (!*info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ i = 0;
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ char *name, *gecos;
+ DOM_SID sid;
+ uint32 rid, group;
+ uint32 atype;
+
+ if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
+ ads_atype_map(atype) != SID_NAME_USER) {
+ DEBUG(1,("Not a user account? atype=0x%x\n", atype));
+ continue;
+ }
+
+ name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+ gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+ if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ DEBUG(1,("No sid for %s !?\n", name));
+ continue;
+ }
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
+ DEBUG(1,("No primary group for %s !?\n", name));
+ continue;
+ }
+
+ if (!sid_peek_rid(&sid, &rid)) {
+ DEBUG(1,("No rid for %s !?\n", name));
+ continue;
+ }
+
+ (*info)[i].acct_name = name;
+ (*info)[i].full_name = gecos;
+ (*info)[i].user_rid = rid;
+ (*info)[i].group_rid = group;
+ i++;
+ }
+
+ (*num_entries) = i;
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
+
+done:
+ if (res) ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"sAMAccountName", "name", "objectSid",
+ "sAMAccountType", NULL};
+ int i, count;
+ ADS_STATUS rc;
+ void *res = NULL;
+ void *msg = NULL;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ *num_entries = 0;
+
+ DEBUG(3,("ads: enum_dom_groups\n"));
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ DEBUG(1,("query_user_list: No users found\n"));
+ goto done;
+ }
+
+ (*info) = talloc(mem_ctx, count * sizeof(**info));
+ if (!*info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ i = 0;
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ char *name, *gecos;
+ DOM_SID sid;
+ uint32 rid;
+ uint32 account_type;
+
+ if (!ads_pull_uint32(ads, msg, "sAMAccountType",
+ &account_type) ||
+ !(account_type & ATYPE_GROUP)) continue;
+
+ name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+ gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+ if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ DEBUG(1,("No sid for %s !?\n", name));
+ continue;
+ }
+
+ if (!sid_peek_rid(&sid, &rid)) {
+ DEBUG(1,("No rid for %s !?\n", name));
+ continue;
+ }
+
+ fstrcpy((*info)[i].acct_name, name);
+ fstrcpy((*info)[i].acct_desc, gecos);
+ (*info)[i].rid = rid;
+ i++;
+ }
+
+ (*num_entries) = i;
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
+
+done:
+ if (res) ads_msgfree(ads, res);
+
+ return status;
+}
+
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"objectSid", "sAMAccountType", NULL};
+ int count;
+ ADS_STATUS rc;
+ void *res = NULL;
+ char *exp;
+ uint32 t;
+ fstring name2, dom2, fullname2;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ /* sigh. Need to fix interface to give us a raw name */
+ fstrcpy(fullname2, name);
+ fstring_sub(fullname2, "\\", lp_winbind_separator());
+ if (!parse_domain_user(fullname2, dom2, name2)) {
+ goto done;
+ }
+
+ DEBUG(3,("ads: name_to_sid\n"));
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ asprintf(&exp, "(sAMAccountName=%s)", name2);
+ rc = ads_search_retry(ads, &res, exp, attrs);
+ free(exp);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count != 1) {
+ DEBUG(1,("name_to_sid: %s not found\n", name));
+ goto done;
+ }
+
+ if (!ads_pull_sid(ads, res, "objectSid", sid)) {
+ DEBUG(1,("No sid for %s !?\n", name));
+ goto done;
+ }
+
+ if (!ads_pull_uint32(ads, res, "sAMAccountType", &t)) {
+ DEBUG(1,("No sAMAccountType for %s !?\n", name));
+ goto done;
+ }
+
+ *type = ads_atype_map(t);
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads name_to_sid mapped %s\n", name));
+
+done:
+ if (res) ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* convert a sid to a user or group name */
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"sAMAccountName", "sAMAccountType", NULL};
+ ADS_STATUS rc;
+ void *msg = NULL;
+ char *exp;
+ char *sidstr;
+ uint32 atype;
+ char *s;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ DEBUG(3,("ads: sid_to_name\n"));
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ sidstr = sid_binstring(sid);
+ asprintf(&exp, "(objectSid=%s)", sidstr);
+ rc = ads_search_retry(ads, &msg, exp, attrs);
+ free(exp);
+ free(sidstr);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("sid_to_name ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
+ goto done;
+ }
+
+ s = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+ *name = talloc_asprintf(mem_ctx, "%s%s%s", domain->name, lp_winbind_separator(), s);
+ *type = ads_atype_map(atype);
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads sid_to_name mapped %s\n", *name));
+
+done:
+ if (msg) ads_msgfree(ads, msg);
+
+ return status;
+}
+
+
+/* Lookup user information from a rid */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ WINBIND_USERINFO *info)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"sAMAccountName", "name", "objectSid",
+ "primaryGroupID", NULL};
+ ADS_STATUS rc;
+ int count;
+ void *msg = NULL;
+ char *exp;
+ DOM_SID sid;
+ char *sidstr;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ DEBUG(3,("ads: query_user\n"));
+
+ sid_from_rid(domain, user_rid, &sid);
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ sidstr = sid_binstring(&sid);
+ asprintf(&exp, "(objectSid=%s)", sidstr);
+ rc = ads_search_retry(ads, &msg, exp, attrs);
+ free(exp);
+ free(sidstr);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("query_user(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, msg);
+ if (count != 1) {
+ DEBUG(1,("query_user(rid=%d): Not found\n", user_rid));
+ goto done;
+ }
+
+ info->acct_name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+ info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
+ if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ DEBUG(1,("No sid for %d !?\n", user_rid));
+ goto done;
+ }
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &info->group_rid)) {
+ DEBUG(1,("No primary group for %d !?\n", user_rid));
+ goto done;
+ }
+
+ if (!sid_peek_rid(&sid, &info->user_rid)) {
+ DEBUG(1,("No rid for %d !?\n", user_rid));
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+ DEBUG(3,("ads query_user gave %s\n", info->acct_name));
+done:
+ if (msg) ads_msgfree(ads, msg);
+
+ return status;
+}
+
+
+/* Lookup groups a user is a member of. */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ uint32 *num_groups, uint32 **user_gids)
+{
+ ADS_STRUCT *ads = NULL;
+ const char *attrs[] = {"distinguishedName", NULL};
+ const char *attrs2[] = {"tokenGroups", "primaryGroupID", NULL};
+ ADS_STATUS rc;
+ int count;
+ void *msg = NULL;
+ char *exp;
+ char *user_dn;
+ DOM_SID *sids;
+ int i;
+ uint32 primary_group;
+ DOM_SID sid;
+ char *sidstr;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ *num_groups = 0;
+
+ DEBUG(3,("ads: lookup_usergroups\n"));
+
+ (*num_groups) = 0;
+
+ sid_from_rid(domain, user_rid, &sid);
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ sidstr = sid_binstring(&sid);
+ asprintf(&exp, "(objectSid=%s)", sidstr);
+ rc = ads_search_retry(ads, &msg, exp, attrs);
+ free(exp);
+ free(sidstr);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("lookup_usergroups(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
+ goto done;
+ }
+
+ user_dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
+
+ if (msg) ads_msgfree(ads, msg);
+
+ rc = ads_search_retry_dn(ads, &msg, user_dn, attrs2);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("lookup_usergroups(rid=%d) ads_search tokenGroups: %s\n", user_rid, ads_errstr(rc)));
+ goto done;
+ }
+
+ if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group)) {
+ DEBUG(1,("%s: No primary group for rid=%d !?\n", domain->name, user_rid));
+ goto done;
+ }
+
+ count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids) + 1;
+ (*user_gids) = (uint32 *)talloc(mem_ctx, sizeof(uint32) * count);
+ (*user_gids)[(*num_groups)++] = primary_group;
+
+ for (i=1;i<count;i++) {
+ uint32 rid;
+ if (!sid_peek_rid(&sids[i-1], &rid)) continue;
+ (*user_gids)[*num_groups] = rid;
+ (*num_groups)++;
+ }
+
+ status = NT_STATUS_OK;
+ DEBUG(3,("ads lookup_usergroups for rid=%d\n", user_rid));
+done:
+ if (msg) ads_msgfree(ads, msg);
+
+ return status;
+}
+
+
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 *num_names,
+ uint32 **rid_mem, char ***names,
+ uint32 **name_types)
+{
+ DOM_SID group_sid;
+ char *sidstr;
+ const char *attrs[] = {"sAMAccountName", "objectSid", "sAMAccountType", NULL};
+ ADS_STATUS rc;
+ int count;
+ void *res=NULL, *msg=NULL;
+ ADS_STRUCT *ads = NULL;
+ char *exp;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ *num_names = 0;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) goto done;
+
+ sid_from_rid(domain, group_rid, &group_sid);
+ sidstr = sid_binstring(&group_sid);
+ /* search for all users who have that group sid as primary group or as member */
+ asprintf(&exp, "(&(objectCategory=user)(|(primaryGroupID=%d)(memberOf=%s)))",
+ group_rid, sidstr);
+ rc = ads_search_retry(ads, &res, exp, attrs);
+ free(exp);
+ free(sidstr);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ status = NT_STATUS_OK;
+ goto done;
+ }
+
+ (*rid_mem) = talloc(mem_ctx, sizeof(uint32) * count);
+ (*name_types) = talloc(mem_ctx, sizeof(uint32) * count);
+ (*names) = talloc(mem_ctx, sizeof(char *) * count);
+
+ for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ uint32 atype, rid;
+ DOM_SID sid;
+
+ (*names)[*num_names] = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+ if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
+ continue;
+ }
+ (*name_types)[*num_names] = ads_atype_map(atype);
+ if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
+ DEBUG(1,("No sid for %s !?\n", (*names)[*num_names]));
+ continue;
+ }
+ if (!sid_peek_rid(&sid, &rid)) {
+ DEBUG(1,("No rid for %s !?\n", (*names)[*num_names]));
+ continue;
+ }
+ (*rid_mem)[*num_names] = rid;
+ (*num_names)++;
+ }
+
+ status = NT_STATUS_OK;
+ DEBUG(3,("ads lookup_groupmem for rid=%d\n", group_rid));
+done:
+ if (res) ads_msgfree(ads, res);
+
+ return status;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS rc;
+
+ *seq = DOM_SEQUENCE_NONE;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+ rc = ads_USN(ads, seq);
+ return ads_ntstatus(rc);
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ DOM_SID **dom_sids)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+
+ *num_domains = 0;
+ *names = NULL;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+ rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids);
+
+ return ads_ntstatus(rc);
+}
+
+/* find the domain sid for a domain */
+static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+ rc = ads_domain_sid(ads, sid);
+
+ return ads_ntstatus(rc);
+}
+
+/* the ADS backend methods are exposed via this structure */
+struct winbindd_methods ads_methods = {
+ True,
+ query_user_list,
+ enum_dom_groups,
+ name_to_sid,
+ sid_to_name,
+ query_user,
+ lookup_usergroups,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ domain_sid
+};
+
+#endif
diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c
new file mode 100644
index 00000000000..847ec9e5417
--- /dev/null
+++ b/source/nsswitch/winbindd_cache.c
@@ -0,0 +1,856 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Winbind cache backend functions
+
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+struct winbind_cache {
+ struct winbindd_methods *backend;
+ TDB_CONTEXT *tdb;
+};
+
+struct cache_entry {
+ NTSTATUS status;
+ uint32 sequence_number;
+ uint8 *data;
+ uint32 len, ofs;
+};
+
+static struct winbind_cache *wcache;
+
+/* flush the cache */
+void wcache_flush_cache(void)
+{
+ extern BOOL opt_nocache;
+
+ if (!wcache) return;
+ if (wcache->tdb) {
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+ }
+ if (opt_nocache) return;
+
+ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
+ TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC, 0600);
+
+ if (!wcache->tdb) {
+ DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
+ }
+}
+
+/* get the winbind_cache structure */
+static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+{
+ extern struct winbindd_methods msrpc_methods;
+ struct winbind_cache *ret = wcache;
+
+ if (ret) return ret;
+
+ ret = smb_xmalloc(sizeof(*ret));
+ ZERO_STRUCTP(ret);
+ switch (lp_security()) {
+#ifdef HAVE_ADS
+ case SEC_ADS: {
+ extern struct winbindd_methods ads_methods;
+ ret->backend = &ads_methods;
+ break;
+ }
+#endif
+ default:
+ ret->backend = &msrpc_methods;
+ }
+
+ wcache = ret;
+ wcache_flush_cache();
+
+ return ret;
+}
+
+/*
+ free a centry structure
+*/
+static void centry_free(struct cache_entry *centry)
+{
+ if (!centry) return;
+ SAFE_FREE(centry->data);
+ free(centry);
+}
+
+
+/*
+ pull a uint32 from a cache entry
+*/
+static uint32 centry_uint32(struct cache_entry *centry)
+{
+ uint32 ret;
+ if (centry->len - centry->ofs < 4) {
+ DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
+ centry->len - centry->ofs));
+ smb_panic("centry_uint32");
+ }
+ ret = IVAL(centry->data, centry->ofs);
+ centry->ofs += 4;
+ return ret;
+}
+
+/*
+ pull a uint8 from a cache entry
+*/
+static uint8 centry_uint8(struct cache_entry *centry)
+{
+ uint8 ret;
+ if (centry->len - centry->ofs < 1) {
+ DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
+ centry->len - centry->ofs));
+ smb_panic("centry_uint32");
+ }
+ ret = CVAL(centry->data, centry->ofs);
+ centry->ofs += 1;
+ return ret;
+}
+
+/* pull a string from a cache entry, using the supplied
+ talloc context
+*/
+static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
+{
+ uint32 len;
+ char *ret;
+
+ len = centry_uint8(centry);
+
+ if (len == 0xFF) {
+ /* a deliberate NULL string */
+ return NULL;
+ }
+
+ if (centry->len - centry->ofs < len) {
+ DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
+ len, centry->len - centry->ofs));
+ smb_panic("centry_string");
+ }
+
+ ret = talloc(mem_ctx, len+1);
+ if (!ret) {
+ smb_panic("centry_string out of memory\n");
+ }
+ memcpy(ret,centry->data + centry->ofs, len);
+ ret[len] = 0;
+ centry->ofs += len;
+ return ret;
+}
+
+/* the server is considered down if it can't give us a sequence number */
+static BOOL wcache_server_down(struct winbindd_domain *domain)
+{
+ if (!wcache->tdb) return False;
+ return (domain->sequence_number == DOM_SEQUENCE_NONE);
+}
+
+
+/*
+ refresh the domain sequence number. If force is True
+ then always refresh it, no matter how recently we fetched it
+*/
+static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
+{
+ NTSTATUS status;
+
+ /* see if we have to refetch the domain sequence number */
+ if (!force && (time(NULL) - domain->last_seq_check < lp_winbind_cache_time())) {
+ return;
+ }
+
+ status = wcache->backend->sequence_number(domain, &domain->sequence_number);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ domain->sequence_number = DOM_SEQUENCE_NONE;
+ }
+
+ domain->last_seq_check = time(NULL);
+}
+
+/*
+ decide if a cache entry has expired
+*/
+static BOOL centry_expired(struct winbindd_domain *domain, struct cache_entry *centry)
+{
+ /* if the server is OK and our cache entry came from when it was down then
+ the entry is invalid */
+ if (domain->sequence_number != DOM_SEQUENCE_NONE &&
+ centry->sequence_number == DOM_SEQUENCE_NONE) {
+ return True;
+ }
+
+ /* if the server is down or the cache entry is not older than the
+ current sequence number then it is OK */
+ if (wcache_server_down(domain) ||
+ centry->sequence_number >= domain->sequence_number) {
+ return False;
+ }
+
+ /* it's expired */
+ return True;
+}
+
+/*
+ fetch an entry from the cache, with a varargs key. auto-fetch the sequence
+ number and return status
+*/
+static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
+ struct winbindd_domain *domain,
+ const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA data;
+ struct cache_entry *centry;
+ TDB_DATA key;
+
+ refresh_sequence_number(domain, False);
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key.dptr = kstr;
+ key.dsize = strlen(kstr);
+ data = tdb_fetch(wcache->tdb, key);
+ free(kstr);
+ if (!data.dptr) {
+ /* a cache miss */
+ return NULL;
+ }
+
+ centry = smb_xmalloc(sizeof(*centry));
+ centry->data = data.dptr;
+ centry->len = data.dsize;
+ centry->ofs = 0;
+
+ if (centry->len < 8) {
+ /* huh? corrupt cache? */
+ centry_free(centry);
+ return NULL;
+ }
+
+ centry->status = NT_STATUS(centry_uint32(centry));
+ centry->sequence_number = centry_uint32(centry);
+
+ if (centry_expired(domain, centry)) {
+ centry_free(centry);
+ return NULL;
+ }
+
+ return centry;
+}
+
+/*
+ make sure we have at least len bytes available in a centry
+*/
+static void centry_expand(struct cache_entry *centry, uint32 len)
+{
+ uint8 *p;
+ if (centry->len - centry->ofs >= len) return;
+ centry->len *= 2;
+ p = realloc(centry->data, centry->len);
+ if (!p) {
+ DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
+ smb_panic("out of memory in centry_expand");
+ }
+ centry->data = p;
+}
+
+/*
+ push a uint32 into a centry
+*/
+static void centry_put_uint32(struct cache_entry *centry, uint32 v)
+{
+ centry_expand(centry, 4);
+ SIVAL(centry->data, centry->ofs, v);
+ centry->ofs += 4;
+}
+
+/*
+ push a uint8 into a centry
+*/
+static void centry_put_uint8(struct cache_entry *centry, uint8 v)
+{
+ centry_expand(centry, 1);
+ SCVAL(centry->data, centry->ofs, v);
+ centry->ofs += 1;
+}
+
+/*
+ push a string into a centry
+ */
+static void centry_put_string(struct cache_entry *centry, const char *s)
+{
+ int len;
+
+ if (!s) {
+ /* null strings are marked as len 0xFFFF */
+ centry_put_uint8(centry, 0xFF);
+ return;
+ }
+
+ len = strlen(s);
+ /* can't handle more than 254 char strings. Truncating is probably best */
+ if (len > 254) len = 254;
+ centry_put_uint8(centry, len);
+ centry_expand(centry, len);
+ memcpy(centry->data + centry->ofs, s, len);
+ centry->ofs += len;
+}
+
+/*
+ start a centry for output. When finished, call centry_end()
+*/
+struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
+{
+ struct cache_entry *centry;
+
+ if (!wcache->tdb) return NULL;
+
+ centry = smb_xmalloc(sizeof(*centry));
+
+ centry->len = 8192; /* reasonable default */
+ centry->data = smb_xmalloc(centry->len);
+ centry->ofs = 0;
+ centry->sequence_number = domain->sequence_number;
+ centry_put_uint32(centry, NT_STATUS_V(status));
+ centry_put_uint32(centry, centry->sequence_number);
+ return centry;
+}
+
+/*
+ finish a centry and write it to the tdb
+*/
+static void centry_end(struct cache_entry *centry, const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA key, data;
+
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key.dptr = kstr;
+ key.dsize = strlen(kstr);
+ data.dptr = centry->data;
+ data.dsize = centry->ofs;
+
+ tdb_store(wcache->tdb, key, data, TDB_REPLACE);
+ free(kstr);
+}
+
+/* form a name with the domain part stuck on the front */
+static char *prepend_domain(struct winbindd_domain *domain, const char *name)
+{
+ static fstring s;
+ snprintf(s, sizeof(s), "%s%s%s", domain->name, lp_winbind_separator(), name);
+ return s;
+}
+
+/* form a sid from the domain plus rid */
+static DOM_SID *form_sid(struct winbindd_domain *domain, uint32 rid)
+{
+ static DOM_SID sid;
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, rid);
+ return &sid;
+}
+
+static void wcache_save_name_to_sid(struct winbindd_domain *domain, NTSTATUS status,
+ const char *name, DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct cache_entry *centry;
+ uint32 len;
+
+ centry = centry_start(domain, status);
+ if (!centry) return;
+ len = sid_size(sid);
+ centry_expand(centry, len);
+ centry_put_uint32(centry, type);
+ sid_linearize(centry->data + centry->ofs, len, sid);
+ centry->ofs += len;
+ centry_end(centry, "NS/%s/%s", domain->name, name);
+ centry_free(centry);
+}
+
+static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
+ DOM_SID *sid, const char *name, enum SID_NAME_USE type, uint32 rid)
+{
+ struct cache_entry *centry;
+
+ centry = centry_start(domain, status);
+ if (!centry) return;
+ if (NT_STATUS_IS_OK(status)) {
+ centry_put_uint32(centry, type);
+ centry_put_string(centry, name);
+ }
+ centry_end(centry, "SN/%s/%d", domain->name, rid);
+ centry_free(centry);
+}
+
+
+static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
+{
+ struct cache_entry *centry;
+
+ centry = centry_start(domain, status);
+ if (!centry) return;
+ centry_put_string(centry, info->acct_name);
+ centry_put_string(centry, info->full_name);
+ centry_put_uint32(centry, info->user_rid);
+ centry_put_uint32(centry, info->group_rid);
+ centry_end(centry, "U/%s/%x", domain->name, info->user_rid);
+ centry_free(centry);
+}
+
+
+/* Query display info. This is the basic user list fn */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
+ if (!centry) goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0) goto do_cached;
+
+ (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
+ if (! (*info)) smb_panic("query_user_list out of memory");
+ for (i=0; i<(*num_entries); i++) {
+ (*info)[i].acct_name = centry_string(centry, mem_ctx);
+ (*info)[i].full_name = centry_string(centry, mem_ctx);
+ (*info)[i].user_rid = centry_uint32(centry);
+ (*info)[i].group_rid = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ status = cache->backend->query_user_list(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ centry = centry_start(domain, status);
+ if (!centry) goto skip_save;
+ centry_put_uint32(centry, *num_entries);
+ for (i=0; i<(*num_entries); i++) {
+ centry_put_string(centry, (*info)[i].acct_name);
+ centry_put_string(centry, (*info)[i].full_name);
+ centry_put_uint32(centry, (*info)[i].user_rid);
+ centry_put_uint32(centry, (*info)[i].group_rid);
+ if (cache->backend->consistent) {
+ /* when the backend is consistent we can pre-prime some mappings */
+ wcache_save_name_to_sid(domain, NT_STATUS_OK,
+ prepend_domain(domain, (*info)[i].acct_name),
+ form_sid(domain, (*info)[i].user_rid),
+ SID_NAME_USER);
+ wcache_save_sid_to_name(domain, NT_STATUS_OK,
+ form_sid(domain, (*info)[i].user_rid),
+ prepend_domain(domain, (*info)[i].acct_name),
+ SID_NAME_USER, (*info)[i].user_rid);
+ wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
+ }
+ }
+ centry_end(centry, "UL/%s", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GL/%s", domain->name);
+ if (!centry) goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0) goto do_cached;
+
+ (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
+ if (! (*info)) smb_panic("enum_dom_groups out of memory");
+ for (i=0; i<(*num_entries); i++) {
+ fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
+ fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
+ (*info)[i].rid = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ status = cache->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ centry = centry_start(domain, status);
+ if (!centry) goto skip_save;
+ centry_put_uint32(centry, *num_entries);
+ for (i=0; i<(*num_entries); i++) {
+ centry_put_string(centry, (*info)[i].acct_name);
+ centry_put_string(centry, (*info)[i].acct_desc);
+ centry_put_uint32(centry, (*info)[i].rid);
+ }
+ centry_end(centry, "GL/%s", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "NS/%s/%s", domain->name, name);
+ if (!centry) goto do_query;
+ *type = centry_uint32(centry);
+ sid_parse(centry->data + centry->ofs, centry->len - centry->ofs, sid);
+
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(sid);
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+ status = cache->backend->name_to_sid(domain, name, sid, type);
+
+ /* and save it */
+ wcache_save_name_to_sid(domain, status, name, sid, *type);
+
+ return status;
+}
+
+/* convert a sid to a user or group name. The sid is guaranteed to be in the domain
+ given */
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ uint32 rid = 0;
+
+ sid_peek_rid(sid, &rid);
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "SN/%s/%d", domain->name, rid);
+ if (!centry) goto do_query;
+ if (NT_STATUS_IS_OK(centry->status)) {
+ *type = centry_uint32(centry);
+ *name = centry_string(centry, mem_ctx);
+ }
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ *name = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+ status = cache->backend->sid_to_name(domain, mem_ctx, sid, name, type);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ wcache_save_sid_to_name(domain, status, sid, *name, *type, rid);
+
+ return status;
+}
+
+
+/* Lookup user information from a rid */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ WINBIND_USERINFO *info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "U/%s/%x", domain->name, user_rid);
+ if (!centry) goto do_query;
+
+ info->acct_name = centry_string(centry, mem_ctx);
+ info->full_name = centry_string(centry, mem_ctx);
+ info->user_rid = centry_uint32(centry);
+ info->group_rid = centry_uint32(centry);
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(info);
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ status = cache->backend->query_user(domain, mem_ctx, user_rid, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ wcache_save_user(domain, status, info);
+
+ return status;
+}
+
+
+/* Lookup groups a user is a member of. */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ uint32 *num_groups, uint32 **user_gids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "UG/%s/%x", domain->name, user_rid);
+ if (!centry) goto do_query;
+
+ *num_groups = centry_uint32(centry);
+
+ if (*num_groups == 0) goto do_cached;
+
+ (*user_gids) = talloc(mem_ctx, sizeof(**user_gids) * (*num_groups));
+ if (! (*user_gids)) smb_panic("lookup_usergroups out of memory");
+ for (i=0; i<(*num_groups); i++) {
+ (*user_gids)[i] = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_groups) = 0;
+ (*user_gids) = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+ status = cache->backend->lookup_usergroups(domain, mem_ctx, user_rid, num_groups, user_gids);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ centry = centry_start(domain, status);
+ if (!centry) goto skip_save;
+ centry_put_uint32(centry, *num_groups);
+ for (i=0; i<(*num_groups); i++) {
+ centry_put_uint32(centry, (*user_gids)[i]);
+ }
+ centry_end(centry, "UG/%s/%x", domain->name, user_rid);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 *num_names,
+ uint32 **rid_mem, char ***names,
+ uint32 **name_types)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ int i;
+
+ if (!cache->tdb) goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GM/%s/%x", domain->name, group_rid);
+ if (!centry) goto do_query;
+
+ *num_names = centry_uint32(centry);
+
+ if (*num_names == 0) goto do_cached;
+
+ (*rid_mem) = talloc(mem_ctx, sizeof(**rid_mem) * (*num_names));
+ (*names) = talloc(mem_ctx, sizeof(**names) * (*num_names));
+ (*name_types) = talloc(mem_ctx, sizeof(**name_types) * (*num_names));
+
+ if (! (*rid_mem) || ! (*names) || ! (*name_types)) {
+ smb_panic("lookup_groupmem out of memory");
+ }
+
+ for (i=0; i<(*num_names); i++) {
+ (*rid_mem)[i] = centry_uint32(centry);
+ (*names)[i] = centry_string(centry, mem_ctx);
+ (*name_types)[i] = centry_uint32(centry);
+ }
+
+do_cached:
+ status = centry->status;
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_names) = 0;
+ (*rid_mem) = NULL;
+ (*names) = NULL;
+ (*name_types) = NULL;
+
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+ status = cache->backend->lookup_groupmem(domain, mem_ctx, group_rid, num_names,
+ rid_mem, names, name_types);
+
+ /* and save it */
+ refresh_sequence_number(domain, True);
+ centry = centry_start(domain, status);
+ if (!centry) goto skip_save;
+ centry_put_uint32(centry, *num_names);
+ for (i=0; i<(*num_names); i++) {
+ centry_put_uint32(centry, (*rid_mem)[i]);
+ centry_put_string(centry, (*names)[i]);
+ centry_put_uint32(centry, (*name_types)[i]);
+ }
+ centry_end(centry, "GM/%s/%x", domain->name, group_rid);
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ refresh_sequence_number(domain, False);
+
+ *seq = domain->sequence_number;
+
+ return NT_STATUS_OK;
+}
+
+/* enumerate trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ DOM_SID **dom_sids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+
+ /* we don't cache this call */
+ return cache->backend->trusted_domains(domain, mem_ctx, num_domains,
+ names, dom_sids);
+}
+
+/* find the domain sid */
+static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
+{
+ struct winbind_cache *cache = get_cache(domain);
+
+ /* we don't cache this call */
+ return cache->backend->domain_sid(domain, sid);
+}
+
+/* the ADS backend methods are exposed via this structure */
+struct winbindd_methods cache_methods = {
+ True,
+ query_user_list,
+ enum_dom_groups,
+ name_to_sid,
+ sid_to_name,
+ query_user,
+ lookup_usergroups,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ domain_sid
+};
+
+
diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c
new file mode 100644
index 00000000000..31ab61a7de4
--- /dev/null
+++ b/source/nsswitch/winbindd_cm.c
@@ -0,0 +1,732 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+
+ Winbind daemon connection manager
+
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ We need to manage connections to domain controllers without having to
+ mess up the main winbindd code with other issues. The aim of the
+ connection manager is to:
+
+ - make connections to domain controllers and cache them
+ - re-establish connections when networks or servers go down
+ - centralise the policy on connection timeouts, domain controller
+ selection etc
+ - manage re-entrancy for when winbindd becomes able to handle
+ multiple outstanding rpc requests
+
+ Why not have connection management as part of the rpc layer like tng?
+ Good question. This code may morph into libsmb/rpc_cache.c or something
+ like that but at the moment it's simply staying as part of winbind. I
+ think the TNG architecture of forcing every user of the rpc layer to use
+ the connection caching system is a bad idea. It should be an optional
+ method of using the routines.
+
+ The TNG design is quite good but I disagree with some aspects of the
+ implementation. -tpot
+
+ */
+
+/*
+ TODO:
+
+ - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
+ moved down into another function.
+
+ - There needs to be a utility function in libsmb/namequery.c that does
+ cm_get_dc_name()
+
+ - Take care when destroying cli_structs as they can be shared between
+ various sam handles.
+
+ */
+
+#include "winbindd.h"
+
+/* Global list of connections. Initially a DLIST but can become a hash
+ table or whatever later. */
+
+struct winbindd_cm_conn {
+ struct winbindd_cm_conn *prev, *next;
+ fstring domain;
+ fstring controller;
+ fstring pipe_name;
+ struct cli_state *cli;
+ POLICY_HND pol;
+};
+
+static struct winbindd_cm_conn *cm_conns = NULL;
+
+/* Get a domain controller name. Cache positive and negative lookups so we
+ don't go to the network too often when something is badly broken. */
+
+#define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
+
+struct get_dc_name_cache {
+ fstring domain_name;
+ fstring srv_name;
+ time_t lookup_time;
+ struct get_dc_name_cache *prev, *next;
+};
+
+static BOOL cm_get_dc_name(char *domain, fstring srv_name)
+{
+ static struct get_dc_name_cache *get_dc_name_cache;
+ struct get_dc_name_cache *dcc;
+ struct in_addr *ip_list, dc_ip;
+ int count, i;
+
+ /* Check the cache for previous lookups */
+
+ for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
+
+ if (!strequal(domain, dcc->domain_name))
+ continue; /* Not our domain */
+
+ if ((time(NULL) - dcc->lookup_time) >
+ GET_DC_NAME_CACHE_TIMEOUT) {
+
+ /* Cache entry has expired, delete it */
+
+ DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain));
+
+ DLIST_REMOVE(get_dc_name_cache, dcc);
+ SAFE_FREE(dcc);
+
+ break;
+ }
+
+ /* Return a positive or negative lookup for this domain */
+
+ if (dcc->srv_name[0]) {
+ DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain));
+ fstrcpy(srv_name, dcc->srv_name);
+ return True;
+ } else {
+ DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain));
+ return False;
+ }
+ }
+
+ /* Add cache entry for this lookup. */
+
+ DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
+
+ if (!(dcc = (struct get_dc_name_cache *)
+ malloc(sizeof(struct get_dc_name_cache))))
+ return False;
+
+ ZERO_STRUCTP(dcc);
+
+ fstrcpy(dcc->domain_name, domain);
+ dcc->lookup_time = time(NULL);
+
+ DLIST_ADD(get_dc_name_cache, dcc);
+
+ /* Lookup domain controller name */
+
+ if (!get_dc_list(False, domain, &ip_list, &count)) {
+ DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+ return False;
+ }
+
+ /* Firstly choose a PDC/BDC who has the same network address as any
+ of our interfaces. */
+
+ for (i = 0; i < count; i++) {
+ if(is_local_net(ip_list[i]))
+ goto got_ip;
+ }
+
+ if (count == 0) {
+ DEBUG(3, ("No domain controllers for domain %s\n", domain));
+ return False;
+ }
+
+ i = (sys_random() % count);
+
+ got_ip:
+ dc_ip = ip_list[i];
+ SAFE_FREE(ip_list);
+
+ /* We really should be doing a GETDC call here rather than a node
+ status lookup. */
+
+ if (!name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) {
+ DEBUG(3, ("Error looking up DC name for %s in domain %s\n", inet_ntoa(dc_ip), domain));
+ return False;
+ }
+
+ /* We have a name so make the cache entry positive now */
+
+ fstrcpy(dcc->srv_name, srv_name);
+
+ return True;
+}
+
+/* Choose between anonymous or authenticated connections. We need to use
+ an authenticated connection if DCs have the RestrictAnonymous registry
+ entry set > 0, or the "Additional restrictions for anonymous
+ connections" set in the win2k Local Security Policy. */
+
+void cm_init_creds(struct ntuser_creds *creds)
+{
+ char *username, *password;
+
+ ZERO_STRUCTP(creds);
+
+ creds->pwd.null_pwd = True; /* anonymoose */
+
+ username = secrets_fetch(SECRETS_AUTH_USER, NULL);
+ password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+
+ if (username && *username) {
+ pwd_set_cleartext(&creds->pwd, password);
+
+ fstrcpy(creds->user_name, username);
+ fstrcpy(creds->domain, lp_workgroup());
+
+ DEBUG(3, ("IPC$ connections done %s\\%s\n", creds->domain,
+ creds->user_name));
+ } else
+ DEBUG(3, ("IPC$ connections done anonymously\n"));
+}
+
+/* Open a new smb pipe connection to a DC on a given domain. Cache
+ negative creation attempts so we don't try and connect to broken
+ machines too often. */
+
+#define OPEN_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
+
+struct open_connection_cache {
+ fstring domain_name;
+ fstring controller;
+ time_t lookup_time;
+ struct open_connection_cache *prev, *next;
+};
+
+static BOOL cm_open_connection(char *domain, char *pipe_name,
+ struct winbindd_cm_conn *new_conn)
+{
+ static struct open_connection_cache *open_connection_cache;
+ struct open_connection_cache *occ;
+ struct nmb_name calling, called;
+ extern pstring global_myname;
+ fstring dest_host;
+ struct in_addr dest_ip;
+ BOOL result = False;
+ struct ntuser_creds creds;
+
+ fstrcpy(new_conn->domain, domain);
+ fstrcpy(new_conn->pipe_name, pipe_name);
+
+ /* Look for a domain controller for this domain. Negative results
+ are cached so don't bother applying the caching for this
+ function just yet. */
+
+ if (!cm_get_dc_name(domain, new_conn->controller))
+ goto done;
+
+ /* Return false if we have tried to look up this domain and netbios
+ name before and failed. */
+
+ for (occ = open_connection_cache; occ; occ = occ->next) {
+
+ if (!(strequal(domain, occ->domain_name) &&
+ strequal(new_conn->controller, occ->controller)))
+ continue; /* Not our domain */
+
+ if ((time(NULL) - occ->lookup_time) >
+ OPEN_CONNECTION_CACHE_TIMEOUT) {
+
+ /* Cache entry has expired, delete it */
+
+ DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain, new_conn->controller));
+
+ DLIST_REMOVE(open_connection_cache, occ);
+ free(occ);
+
+ break;
+ }
+
+ /* The timeout hasn't expired yet so return false */
+
+ DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain, new_conn->controller));
+
+ goto done;
+ }
+
+ /* Initialise SMB connection */
+
+ if (!(new_conn->cli = cli_initialise(NULL)))
+ goto done;
+
+ if (!resolve_srv_name(new_conn->controller, dest_host, &dest_ip))
+ goto done;
+
+ make_nmb_name(&called, dns_to_netbios_name(new_conn->controller), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ cm_init_creds(&creds);
+
+ cli_init_creds(new_conn->cli, &creds);
+
+ if (!cli_establish_connection(new_conn->cli, new_conn->controller,
+ &dest_ip, &calling, &called, "IPC$",
+ "IPC", False, True))
+ goto done;
+
+ if (!cli_nt_session_open (new_conn->cli, pipe_name))
+ goto done;
+
+ result = True;
+
+ done:
+
+ /* Create negative lookup cache entry for this domain and controller */
+
+ if (!result) {
+ if (!(occ = (struct open_connection_cache *)
+ malloc(sizeof(struct open_connection_cache))))
+ return False;
+
+ ZERO_STRUCTP(occ);
+
+ fstrcpy(occ->domain_name, domain);
+ fstrcpy(occ->controller, new_conn->controller);
+ occ->lookup_time = time(NULL);
+
+ DLIST_ADD(open_connection_cache, occ);
+ }
+
+ if (!result && new_conn->cli)
+ cli_shutdown(new_conn->cli);
+
+ return result;
+}
+
+/* Return true if a connection is still alive */
+
+static BOOL connection_ok(struct winbindd_cm_conn *conn)
+{
+ if (!conn->cli->initialised)
+ return False;
+
+ if (conn->cli->fd == -1)
+ return False;
+
+ return True;
+}
+
+/* Return a LSA policy handle on a domain */
+
+CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
+{
+ struct winbindd_cm_conn *conn;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ NTSTATUS result;
+ static CLI_POLICY_HND hnd;
+
+ /* Look for existing connections */
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_LSARPC)) {
+
+ if (!connection_ok(conn)) {
+ DLIST_REMOVE(cm_conns, conn);
+ return NULL;
+ }
+
+ goto ok;
+ }
+ }
+
+ /* Create a new one */
+
+ if (!(conn = (struct winbindd_cm_conn *) malloc(sizeof(struct winbindd_cm_conn))))
+ return NULL;
+
+ ZERO_STRUCTP(conn);
+
+ if (!cm_open_connection(domain, PIPE_LSARPC, conn)) {
+ DEBUG(3, ("Could not connect to a dc for domain %s\n", domain));
+ return NULL;
+ }
+
+ result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
+ des_access, &conn->pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return NULL;
+
+ /* Add to list */
+
+ DLIST_ADD(cm_conns, conn);
+
+ ok:
+ hnd.pol = conn->pol;
+ hnd.cli = conn->cli;
+
+ return &hnd;
+}
+
+/* Return a SAM policy handle on a domain */
+
+CLI_POLICY_HND *cm_get_sam_handle(char *domain)
+{
+ struct winbindd_cm_conn *conn;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ NTSTATUS result;
+ static CLI_POLICY_HND hnd;
+
+ /* Look for existing connections */
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) && strequal(conn->pipe_name, PIPE_SAMR)) {
+
+ if (!connection_ok(conn)) {
+ DLIST_REMOVE(cm_conns, conn);
+ return NULL;
+ }
+
+ goto ok;
+ }
+ }
+
+ /* Create a new one */
+
+ if (!(conn = (struct winbindd_cm_conn *)
+ malloc(sizeof(struct winbindd_cm_conn))))
+ return NULL;
+
+ ZERO_STRUCTP(conn);
+
+ if (!cm_open_connection(domain, PIPE_SAMR, conn)) {
+ DEBUG(3, ("Could not connect to a dc for domain %s\n", domain));
+ return NULL;
+ }
+
+ result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
+ des_access, &conn->pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return NULL;
+
+ /* Add to list */
+
+ DLIST_ADD(cm_conns, conn);
+
+ ok:
+ hnd.pol = conn->pol;
+ hnd.cli = conn->cli;
+
+ return &hnd;
+}
+
+#if 0
+
+/* Return a SAM domain policy handle on a domain */
+
+CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
+{
+ struct winbindd_cm_conn *conn, *basic_conn = NULL;
+ static CLI_POLICY_HND hnd;
+ NTSTATUS result;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+ /* Look for existing connections */
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
+
+ if (!connection_ok(conn)) {
+ DLIST_REMOVE(cm_conns, conn);
+ return NULL;
+ }
+
+ goto ok;
+ }
+ }
+
+ /* Create a basic handle to open a domain handle from */
+
+ if (!cm_get_sam_handle(domain))
+ return False;
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
+ basic_conn = conn;
+ }
+
+ if (!(conn = (struct winbindd_cm_conn *)
+ malloc(sizeof(struct winbindd_cm_conn))))
+ return NULL;
+
+ ZERO_STRUCTP(conn);
+
+ fstrcpy(conn->domain, basic_conn->domain);
+ fstrcpy(conn->controller, basic_conn->controller);
+ fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+
+ conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
+ conn->cli = basic_conn->cli;
+
+ result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
+ &basic_conn->pol, des_access,
+ domain_sid, &conn->pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return NULL;
+
+ /* Add to list */
+
+ DLIST_ADD(cm_conns, conn);
+
+ ok:
+ hnd.pol = conn->pol;
+ hnd.cli = conn->cli;
+
+ return &hnd;
+}
+
+/* Return a SAM policy handle on a domain user */
+
+CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
+ uint32 user_rid)
+{
+ struct winbindd_cm_conn *conn, *basic_conn = NULL;
+ static CLI_POLICY_HND hnd;
+ NTSTATUS result;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+ /* Look for existing connections */
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
+ conn->pipe_data.samr.rid == user_rid) {
+
+ if (!connection_ok(conn)) {
+ DLIST_REMOVE(cm_conns, conn);
+ return NULL;
+ }
+
+ goto ok;
+ }
+ }
+
+ /* Create a domain handle to open a user handle from */
+
+ if (!cm_get_sam_dom_handle(domain, domain_sid))
+ return NULL;
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
+ basic_conn = conn;
+ }
+
+ if (!basic_conn) {
+ DEBUG(0, ("No domain sam handle was created!\n"));
+ return NULL;
+ }
+
+ if (!(conn = (struct winbindd_cm_conn *)
+ malloc(sizeof(struct winbindd_cm_conn))))
+ return NULL;
+
+ ZERO_STRUCTP(conn);
+
+ fstrcpy(conn->domain, basic_conn->domain);
+ fstrcpy(conn->controller, basic_conn->controller);
+ fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+
+ conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
+ conn->cli = basic_conn->cli;
+ conn->pipe_data.samr.rid = user_rid;
+
+ result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
+ &basic_conn->pol, des_access, user_rid,
+ &conn->pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return NULL;
+
+ /* Add to list */
+
+ DLIST_ADD(cm_conns, conn);
+
+ ok:
+ hnd.pol = conn->pol;
+ hnd.cli = conn->cli;
+
+ return &hnd;
+}
+
+/* Return a SAM policy handle on a domain group */
+
+CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
+ uint32 group_rid)
+{
+ struct winbindd_cm_conn *conn, *basic_conn = NULL;
+ static CLI_POLICY_HND hnd;
+ NTSTATUS result;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+ /* Look for existing connections */
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
+ conn->pipe_data.samr.rid == group_rid) {
+
+ if (!connection_ok(conn)) {
+ DLIST_REMOVE(cm_conns, conn);
+ return NULL;
+ }
+
+ goto ok;
+ }
+ }
+
+ /* Create a domain handle to open a user handle from */
+
+ if (!cm_get_sam_dom_handle(domain, domain_sid))
+ return NULL;
+
+ for (conn = cm_conns; conn; conn = conn->next) {
+ if (strequal(conn->domain, domain) &&
+ strequal(conn->pipe_name, PIPE_SAMR) &&
+ conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
+ basic_conn = conn;
+ }
+
+ if (!basic_conn) {
+ DEBUG(0, ("No domain sam handle was created!\n"));
+ return NULL;
+ }
+
+ if (!(conn = (struct winbindd_cm_conn *)
+ malloc(sizeof(struct winbindd_cm_conn))))
+ return NULL;
+
+ ZERO_STRUCTP(conn);
+
+ fstrcpy(conn->domain, basic_conn->domain);
+ fstrcpy(conn->controller, basic_conn->controller);
+ fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+
+ conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
+ conn->cli = basic_conn->cli;
+ conn->pipe_data.samr.rid = group_rid;
+
+ result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
+ &basic_conn->pol, des_access, group_rid,
+ &conn->pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return NULL;
+
+ /* Add to list */
+
+ DLIST_ADD(cm_conns, conn);
+
+ ok:
+ hnd.pol = conn->pol;
+ hnd.cli = conn->cli;
+
+ return &hnd;
+}
+
+#endif
+
+/* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
+ netlogon pipe as no handle is returned. */
+
+NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
+ struct cli_state **cli)
+{
+ struct winbindd_cm_conn conn;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ /* Open an initial conection */
+
+ ZERO_STRUCT(conn);
+
+ if (!cm_open_connection(domain, PIPE_NETLOGON, &conn)) {
+ DEBUG(3, ("Could not open a connection to %s\n", domain));
+ return result;
+ }
+
+ result = cli_nt_setup_creds(conn.cli, trust_passwd);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("error connecting to domain password server: %s\n",
+ get_nt_error_msg(result)));
+ cli_shutdown(conn.cli);
+ return result;
+ }
+
+ if (cli)
+ *cli = conn.cli;
+
+ return result;
+}
+
+/* Dump the current connection status */
+
+static void dump_conn_list(void)
+{
+ struct winbindd_cm_conn *con;
+
+ DEBUG(0, ("\tDomain Controller Pipe\n"));
+
+ for(con = cm_conns; con; con = con->next) {
+ char *msg;
+
+ /* Display pipe info */
+
+ asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name);
+
+ DEBUG(0, ("%s\n", msg));
+ free(msg);
+ }
+}
+
+void winbindd_cm_status(void)
+{
+ /* List open connections */
+
+ DEBUG(0, ("winbindd connection manager status:\n"));
+
+ if (cm_conns)
+ dump_conn_list();
+ else
+ DEBUG(0, ("\tNo active connections\n"));
+}
diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c
new file mode 100644
index 00000000000..6e22a8b5591
--- /dev/null
+++ b/source/nsswitch/winbindd_group.c
@@ -0,0 +1,841 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/***************************************************************
+ Empty static struct for negative caching.
+****************************************************************/
+
+/* Fill a grent structure from various other information */
+
+static BOOL fill_grent(struct winbindd_gr *gr, char *gr_name,
+ gid_t unix_gid)
+{
+ /* Fill in uid/gid */
+
+ gr->gr_gid = unix_gid;
+
+ /* Group name and password */
+
+ safe_strcpy(gr->gr_name, gr_name, sizeof(gr->gr_name) - 1);
+ safe_strcpy(gr->gr_passwd, "x", sizeof(gr->gr_passwd) - 1);
+
+ return True;
+}
+
+/* Fill in the group membership field of a NT group given by group_rid */
+
+static BOOL fill_grent_mem(struct winbindd_domain *domain,
+ uint32 group_rid,
+ enum SID_NAME_USE group_name_type,
+ int *num_gr_mem, char **gr_mem, int *gr_mem_len)
+{
+ uint32 *rid_mem = NULL, num_names = 0;
+ uint32 *name_types = NULL;
+ int buf_len, buf_ndx, i;
+ char **names = NULL, *buf;
+ BOOL result = False;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ if (!(mem_ctx = talloc_init()))
+ return False;
+
+ /* Initialise group membership information */
+
+ DEBUG(10, ("fill_grent_mem(): group %s rid 0x%x\n",
+ domain ? domain->name : "NULL", group_rid));
+
+ *num_gr_mem = 0;
+
+ if (group_name_type != SID_NAME_DOM_GRP) {
+ DEBUG(1, ("fill_grent_mem(): rid %d in domain %s isn't a "
+ "domain group\n", group_rid, domain->name));
+ goto done;
+ }
+
+ /* Lookup group members */
+ status = domain->methods->lookup_groupmem(domain, mem_ctx, group_rid, &num_names,
+ &rid_mem, &names, &name_types);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("fill_grent_mem(): could not lookup membership "
+ "for group rid %d in domain %s\n",
+ group_rid, domain->name));
+
+ goto done;
+ }
+
+ DEBUG(10, ("fill_grent_mem(): looked up %d names\n", num_names));
+
+ if (DEBUGLEVEL >= 10) {
+ for (i = 0; i < num_names; i++)
+ DEBUG(10, ("\t%20s %x %d\n", names[i], rid_mem[i],
+ name_types[i]));
+ }
+
+ /* Add members to list */
+
+ buf = NULL;
+ buf_len = buf_ndx = 0;
+
+ again:
+
+ for (i = 0; i < num_names; i++) {
+ char *the_name;
+ fstring name;
+ int len;
+
+ the_name = names[i];
+
+ DEBUG(10, ("fill_grent_mem(): processing name %s\n",
+ the_name));
+
+ /* FIXME: need to cope with groups within groups. These
+ occur in Universal groups on a Windows 2000 native mode
+ server. */
+
+ if (name_types[i] != SID_NAME_USER) {
+ DEBUG(3, ("fill_grent_mem(): name %s isn't a domain "
+ "user\n", the_name));
+ continue;
+ }
+
+ /* Don't bother with machine accounts */
+
+ if (the_name[strlen(the_name) - 1] == '$') {
+ DEBUG(10, ("fill_grent_mem(): %s is machine account\n",
+ the_name));
+ continue;
+ }
+
+ /* Append domain name */
+
+ snprintf(name, sizeof(name), "%s%s%s", domain->name,
+ lp_winbind_separator(), the_name);
+
+ len = strlen(name);
+
+ /* Add to list or calculate buffer length */
+
+ if (!buf) {
+ buf_len += len + 1; /* List is comma separated */
+ (*num_gr_mem)++;
+ DEBUG(10, ("fill_grent_mem(): buf_len + %d = %d\n", len + 1,
+ buf_len));
+ } else {
+ DEBUG(10, ("fill_grent_mem(): appending %s at index %d\n",
+ name, len));
+ safe_strcpy(&buf[buf_ndx], name, len);
+ buf_ndx += len;
+ buf[buf_ndx] = ',';
+ buf_ndx++;
+ }
+ }
+
+ /* Allocate buffer */
+
+ if (!buf) {
+ if (!(buf = malloc(buf_len))) {
+ DEBUG(1, ("fill_grent_mem(): out of memory\n"));
+ result = False;
+ goto done;
+ }
+ memset(buf, 0, buf_len);
+ goto again;
+ }
+
+ if (buf && buf_ndx > 0) {
+ buf[buf_ndx - 1] = '\0';
+ }
+
+ *gr_mem = buf;
+ *gr_mem_len = buf_len;
+
+ DEBUG(10, ("fill_grent_mem(): num_mem = %d, len = %d, mem = %s\n",
+ *num_gr_mem, buf_len, *num_gr_mem ? buf : "NULL"));
+
+ result = True;
+
+done:
+
+ talloc_destroy(mem_ctx);
+
+ DEBUG(10, ("fill_grent_mem(): returning %d\n", result));
+
+ return result;
+}
+
+/* Return a group structure from a group name */
+
+enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state)
+{
+ DOM_SID group_sid;
+ struct winbindd_domain *domain;
+ enum SID_NAME_USE name_type;
+ uint32 group_rid;
+ fstring name_domain, name_group, name;
+ char *tmp, *gr_mem;
+ gid_t gid;
+ int gr_mem_len;
+
+ DEBUG(3, ("[%5d]: getgrnam %s\n", state->pid,
+ state->request.data.groupname));
+
+ /* Parse domain and groupname */
+
+ memset(name_group, 0, sizeof(fstring));
+
+ tmp = state->request.data.groupname;
+ if (!parse_domain_user(tmp, name_domain, name_group))
+ return WINBINDD_ERROR;
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("getgrname_from_group(): could not get domain "
+ "sid for domain %s\n", name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ snprintf(name, sizeof(name), "%s\\%s", name_domain, name_group);
+
+ /* Get rid and name type from name */
+
+ if (!winbindd_lookup_sid_by_name(domain, name, &group_sid, &name_type)) {
+ DEBUG(1, ("group %s in domain %s does not exist\n",
+ name_group, name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
+ DEBUG(1, ("from_group: name '%s' is not a local or domain "
+ "group: %d\n", name_group, name_type));
+ return WINBINDD_ERROR;
+ }
+
+ /* Fill in group structure */
+
+ sid_split_rid(&group_sid, &group_rid);
+
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
+ DEBUG(1, ("error sursing unix gid for sid\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if (!fill_grent(&state->response.data.gr,
+ state->request.data.groupname, gid) ||
+ !fill_grent_mem(domain, group_rid, name_type,
+ &state->response.data.gr.num_gr_mem,
+ &gr_mem, &gr_mem_len)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Group membership lives at start of extra data */
+
+ state->response.data.gr.gr_mem_ofs = 0;
+
+ state->response.length += gr_mem_len;
+ state->response.extra_data = gr_mem;
+
+ return WINBINDD_OK;
+}
+
+/* Return a group structure from a gid number */
+
+enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
+ *state)
+{
+ struct winbindd_domain *domain;
+ DOM_SID group_sid;
+ enum SID_NAME_USE name_type;
+ fstring group_name;
+ uint32 group_rid;
+ int gr_mem_len;
+ char *gr_mem;
+
+ DEBUG(3, ("[%5d]: getgrgid %d\n", state->pid,
+ state->request.data.gid));
+
+ /* Bug out if the gid isn't in the winbind range */
+
+ if ((state->request.data.gid < server_state.gid_low) ||
+ (state->request.data.gid > server_state.gid_high))
+ return WINBINDD_ERROR;
+
+ /* Get rid from gid */
+
+ if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid,
+ &group_rid, &domain)) {
+ DEBUG(1, ("Could not convert gid %d to rid\n",
+ state->request.data.gid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Get sid from gid */
+
+ sid_copy(&group_sid, &domain->sid);
+ sid_append_rid(&group_sid, group_rid);
+
+ if (!winbindd_lookup_name_by_sid(&group_sid, group_name, &name_type)) {
+ DEBUG(1, ("Could not lookup sid\n"));
+ return WINBINDD_ERROR;
+ }
+
+ if (strcmp(lp_winbind_separator(),"\\"))
+ string_sub(group_name, "\\", lp_winbind_separator(),
+ sizeof(fstring));
+
+ if (!((name_type == SID_NAME_ALIAS) ||
+ (name_type == SID_NAME_DOM_GRP))) {
+ DEBUG(1, ("from_gid: name '%s' is not a local or domain "
+ "group: %d\n", group_name, name_type));
+ return WINBINDD_ERROR;
+ }
+
+ /* Fill in group structure */
+
+ if (!fill_grent(&state->response.data.gr, group_name,
+ state->request.data.gid) ||
+ !fill_grent_mem(domain, group_rid, name_type,
+ &state->response.data.gr.num_gr_mem,
+ &gr_mem, &gr_mem_len))
+ return WINBINDD_ERROR;
+
+ /* Group membership lives at start of extra data */
+
+ state->response.data.gr.gr_mem_ofs = 0;
+
+ state->response.length += gr_mem_len;
+ state->response.extra_data = gr_mem;
+
+ return WINBINDD_OK;
+}
+
+/*
+ * set/get/endgrent functions
+ */
+
+/* "Rewind" file pointer for group database enumeration */
+
+enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *tmp;
+
+ DEBUG(3, ("[%5d]: setgrent\n", state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_groups())
+ return WINBINDD_ERROR;
+
+ /* Free old static data if it exists */
+
+ if (state->getgrent_state != NULL) {
+ free_getent_state(state->getgrent_state);
+ state->getgrent_state = NULL;
+ }
+
+ /* Create sam pipes for each domain we know about */
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ struct getent_state *domain_state;
+
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
+
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, tmp->name))
+ continue;
+
+ /* Create a state record for this domain */
+
+ if ((domain_state = (struct getent_state *)
+ malloc(sizeof(struct getent_state))) == NULL)
+ return WINBINDD_ERROR;
+
+ ZERO_STRUCTP(domain_state);
+
+ domain_state->domain = tmp;
+
+ /* Add to list of open domains */
+
+ DLIST_ADD(state->getgrent_state, domain_state);
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Close file pointer to ntdom group database */
+
+enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5d]: endgrent\n", state->pid));
+
+ free_getent_state(state->getgrent_state);
+ state->getgrent_state = NULL;
+
+ return WINBINDD_OK;
+}
+
+/* Get the list of domain groups and domain aliases for a domain. We fill in
+ the sam_entries and num_sam_entries fields with domain group information.
+ The dispinfo_ndx field is incremented to the index of the next group to
+ fetch. Return True if some groups were returned, False otherwise. */
+
+#define MAX_FETCH_SAM_ENTRIES 100
+
+static BOOL get_sam_group_entries(struct getent_state *ent)
+{
+ NTSTATUS status;
+ uint32 num_entries;
+ struct acct_info *name_list = NULL;
+ TALLOC_CTX *mem_ctx;
+ BOOL result = False;
+ struct acct_info *sam_grp_entries = NULL;
+
+ if (ent->got_sam_entries)
+ return False;
+
+ if (!(mem_ctx = talloc_init()))
+ return False;
+
+ /* Free any existing group info */
+
+ SAFE_FREE(ent->sam_entries);
+ ent->num_sam_entries = 0;
+ ent->got_sam_entries = True;
+
+ /* Enumerate domain groups */
+ num_entries = 0;
+
+ status = ent->domain->methods->enum_dom_groups(ent->domain,
+ mem_ctx,
+ &num_entries,
+ &sam_grp_entries);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ result = False;
+ goto done;
+ }
+
+ /* Copy entries into return buffer */
+ if (num_entries) {
+ name_list = malloc(sizeof(struct acct_info) * num_entries);
+ memcpy(name_list, sam_grp_entries,
+ num_entries * sizeof(struct acct_info));
+ }
+
+ ent->num_sam_entries = num_entries;
+
+ /* Fill in remaining fields */
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+
+ result = (ent->num_sam_entries > 0);
+
+ done:
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Fetch next group entry from ntdom database */
+
+#define MAX_GETGRENT_GROUPS 500
+
+enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
+{
+ struct getent_state *ent;
+ struct winbindd_gr *group_list = NULL;
+ int num_groups, group_list_ndx = 0, i, gr_mem_list_len = 0;
+ char *sep, *new_extra_data, *gr_mem_list = NULL;
+
+ DEBUG(3, ("[%5d]: getgrent\n", state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_groups())
+ return WINBINDD_ERROR;
+
+ num_groups = MIN(MAX_GETGRENT_GROUPS, state->request.data.num_entries);
+
+ if ((state->response.extra_data =
+ malloc(num_groups * sizeof(struct winbindd_gr))) == NULL)
+ return WINBINDD_ERROR;
+
+ state->response.data.num_entries = 0;
+
+ group_list = (struct winbindd_gr *)state->response.extra_data;
+ sep = lp_winbind_separator();
+
+ if (!(ent = state->getgrent_state))
+ return WINBINDD_ERROR;
+
+ /* Start sending back groups */
+
+ for (i = 0; i < num_groups; i++) {
+ struct acct_info *name_list = NULL;
+ fstring domain_group_name;
+ uint32 result;
+ gid_t group_gid;
+ int gr_mem_len;
+ char *gr_mem, *new_gr_mem_list;
+
+ /* Do we need to fetch another chunk of groups? */
+
+ tryagain:
+
+ DEBUG(10, ("getgrent(): entry_index = %d, num_entries = %d\n",
+ ent->sam_entry_index, ent->num_sam_entries));
+
+ if (ent->num_sam_entries == ent->sam_entry_index) {
+
+ while(ent && !get_sam_group_entries(ent)) {
+ struct getent_state *next_ent;
+
+ DEBUG(10, ("getgrent(): freeing state info for "
+ "domain %s\n", ent->domain->name));
+
+ /* Free state information for this domain */
+
+ SAFE_FREE(ent->sam_entries);
+
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getgrent_state, ent);
+
+ SAFE_FREE(ent);
+ ent = next_ent;
+ }
+
+ /* No more domains */
+
+ if (!ent)
+ break;
+ }
+
+ name_list = ent->sam_entries;
+
+ /* Lookup group info */
+
+ if (!winbindd_idmap_get_gid_from_rid(
+ ent->domain->name,
+ name_list[ent->sam_entry_index].rid,
+ &group_gid)) {
+
+ DEBUG(1, ("getgrent(): could not look up gid for group %s\n",
+ name_list[ent->sam_entry_index].acct_name));
+
+ ent->sam_entry_index++;
+ goto tryagain;
+ }
+
+ DEBUG(10, ("getgrent(): got gid %d for group %x\n", group_gid,
+ name_list[ent->sam_entry_index].rid));
+
+ /* Fill in group entry */
+
+ slprintf(domain_group_name, sizeof(domain_group_name) - 1,
+ "%s%s%s", ent->domain->name, lp_winbind_separator(),
+ name_list[ent->sam_entry_index].acct_name);
+
+ result = fill_grent(&group_list[group_list_ndx],
+ domain_group_name, group_gid);
+
+ /* Fill in group membership entry */
+
+ if (result) {
+ /* Get group membership */
+ result = fill_grent_mem(
+ ent->domain,
+ name_list[ent->sam_entry_index].rid,
+ SID_NAME_DOM_GRP,
+ &group_list[group_list_ndx].num_gr_mem,
+ &gr_mem, &gr_mem_len);
+ }
+
+ if (result) {
+ /* Append to group membership list */
+ new_gr_mem_list = Realloc(
+ gr_mem_list,
+ gr_mem_list_len + gr_mem_len);
+
+ if (!new_gr_mem_list && (group_list[group_list_ndx].num_gr_mem != 0)) {
+ DEBUG(0, ("getgrent(): out of memory\n"));
+ SAFE_FREE(gr_mem_list);
+ gr_mem_list_len = 0;
+ break;
+ }
+
+ DEBUG(10, ("getgrent(): list_len = %d, mem_len = %d\n",
+ gr_mem_list_len, gr_mem_len));
+
+ gr_mem_list = new_gr_mem_list;
+
+ memcpy(&gr_mem_list[gr_mem_list_len], gr_mem,
+ gr_mem_len);
+
+ SAFE_FREE(gr_mem);
+
+ group_list[group_list_ndx].gr_mem_ofs =
+ gr_mem_list_len;
+
+ gr_mem_list_len += gr_mem_len;
+ }
+
+ ent->sam_entry_index++;
+
+ /* Add group to return list */
+
+ if (result) {
+
+ DEBUG(10, ("getgrent(): adding group num_entries = %d\n",
+ state->response.data.num_entries));
+
+ group_list_ndx++;
+ state->response.data.num_entries++;
+
+ state->response.length +=
+ sizeof(struct winbindd_gr);
+
+ } else {
+ DEBUG(0, ("could not lookup domain group %s\n",
+ domain_group_name));
+ }
+ }
+
+ /* Copy the list of group memberships to the end of the extra data */
+
+ if (group_list_ndx == 0)
+ goto done;
+
+ new_extra_data = Realloc(
+ state->response.extra_data,
+ group_list_ndx * sizeof(struct winbindd_gr) + gr_mem_list_len);
+
+ if (!new_extra_data) {
+ DEBUG(0, ("out of memory\n"));
+ group_list_ndx = 0;
+ SAFE_FREE(state->response.extra_data);
+ SAFE_FREE(gr_mem_list);
+
+ return WINBINDD_ERROR;
+ }
+
+ state->response.extra_data = new_extra_data;
+
+ memcpy(&((char *)state->response.extra_data)
+ [group_list_ndx * sizeof(struct winbindd_gr)],
+ gr_mem_list, gr_mem_list_len);
+
+ SAFE_FREE(gr_mem_list);
+
+ state->response.length += gr_mem_list_len;
+
+ DEBUG(10, ("getgrent(): returning %d groups, length = %d\n",
+ group_list_ndx, gr_mem_list_len));
+
+ /* Out of domains */
+
+ done:
+
+ return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* List domain groups without mapping to unix ids */
+
+enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
+{
+ uint32 total_entries = 0;
+ struct winbindd_domain *domain;
+ char *extra_data = NULL;
+ char *ted = NULL;
+ int extra_data_len = 0, i;
+
+ DEBUG(3, ("[%5d]: list groups\n", state->pid));
+
+ /* Enumerate over trusted domains */
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ for (domain = domain_list; domain; domain = domain->next) {
+ struct getent_state groups;
+
+ ZERO_STRUCT(groups);
+
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, domain->name))
+ continue;
+
+ /* Get list of sam groups */
+ ZERO_STRUCT(groups);
+ groups.domain = domain;
+
+ get_sam_group_entries(&groups);
+
+ if (groups.num_sam_entries == 0) {
+ /* this domain is empty or in an error state */
+ continue;
+ }
+
+ /* keep track the of the total number of groups seen so
+ far over all domains */
+ total_entries += groups.num_sam_entries;
+
+ /* Allocate some memory for extra data. Note that we limit
+ account names to sizeof(fstring) = 128 characters. */
+ ted = Realloc(extra_data, sizeof(fstring) * total_entries);
+
+ if (!ted) {
+ DEBUG(0,("winbindd_list_groups: failed to enlarge "
+ "buffer!\n"));
+ SAFE_FREE(extra_data);
+ return WINBINDD_ERROR;
+ } else
+ extra_data = ted;
+
+ /* Pack group list into extra data fields */
+ for (i = 0; i < groups.num_sam_entries; i++) {
+ char *group_name = ((struct acct_info *)
+ groups.sam_entries)[i].acct_name;
+ fstring name;
+
+ snprintf(name, sizeof(name), "%s%s%s", domain->name,
+ lp_winbind_separator(), group_name);
+
+ /* Append to extra data */
+ memcpy(&extra_data[extra_data_len], name,
+ strlen(name));
+ extra_data_len += strlen(name);
+ extra_data[extra_data_len++] = ',';
+ }
+
+ free(groups.sam_entries);
+ }
+
+ /* Assign extra_data fields in response structure */
+ if (extra_data) {
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ /* No domains may have responded but that's still OK so don't
+ return an error. */
+
+ return WINBINDD_OK;
+}
+
+/* Get user supplementary groups. This is much quicker than trying to
+ invert the groups database. */
+
+enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
+{
+ fstring name_domain, name_user, name;
+ DOM_SID user_sid;
+ enum SID_NAME_USE name_type;
+ uint32 user_rid, num_groups, num_gids;
+ NTSTATUS status;
+ uint32 *user_gids;
+ struct winbindd_domain *domain;
+ enum winbindd_result result = WINBINDD_ERROR;
+ gid_t *gid_list;
+ int i;
+ TALLOC_CTX *mem_ctx;
+
+ DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
+ state->request.data.username));
+
+ if (!(mem_ctx = talloc_init()))
+ return WINBINDD_ERROR;
+
+ /* Parse domain and username */
+
+ if (!parse_domain_user(state->request.data.username, name_domain,
+ name_user))
+ goto done;
+
+ /* Get info for the domain */
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("could not find domain entry for domain %s\n",
+ name_domain));
+ goto done;
+ }
+
+ slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user);
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ if (!winbindd_lookup_sid_by_name(domain, name, &user_sid, &name_type)) {
+ DEBUG(1, ("user '%s' does not exist\n", name_user));
+ goto done;
+ }
+
+ if (name_type != SID_NAME_USER) {
+ DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
+ name_type));
+ goto done;
+ }
+
+ sid_split_rid(&user_sid, &user_rid);
+
+ status = domain->methods->lookup_usergroups(domain, mem_ctx, user_rid, &num_groups, &user_gids);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ /* Copy data back to client */
+
+ num_gids = 0;
+ gid_list = malloc(sizeof(gid_t) * num_groups);
+
+ if (state->response.extra_data)
+ goto done;
+
+ for (i = 0; i < num_groups; i++) {
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, user_gids[i], &gid_list[num_gids])) {
+ DEBUG(1, ("unable to convert group rid %d to gid\n", user_gids[i]));
+ continue;
+ }
+
+ num_gids++;
+ }
+
+ state->response.data.num_entries = num_gids;
+ state->response.extra_data = gid_list;
+ state->response.length += num_gids * sizeof(gid_t);
+
+ result = WINBINDD_OK;
+
+ done:
+
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
diff --git a/source/nsswitch/winbindd_idmap.c b/source/nsswitch/winbindd_idmap.c
new file mode 100644
index 00000000000..a96111a6084
--- /dev/null
+++ b/source/nsswitch/winbindd_idmap.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon - user related function
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/* High water mark keys */
+
+#define HWM_GROUP "GROUP HWM"
+#define HWM_USER "USER HWM"
+
+/* Globals */
+
+static TDB_CONTEXT *idmap_tdb;
+
+/* Allocate either a user or group id from the pool */
+
+static BOOL allocate_id(uid_t *id, BOOL isgroup)
+{
+ int hwm;
+
+ /* Get current high water mark */
+
+ if ((hwm = tdb_fetch_int(idmap_tdb,
+ isgroup ? HWM_GROUP : HWM_USER)) == -1) {
+ return False;
+ }
+
+ /* Return next available uid in list */
+
+ if ((isgroup && (hwm > server_state.gid_high)) ||
+ (!isgroup && (hwm > server_state.uid_high))) {
+ DEBUG(0, ("winbind %sid range full!\n", isgroup ? "g" : "u"));
+ return False;
+ }
+
+ if (id) {
+ *id = hwm;
+ }
+
+ hwm++;
+
+ /* Store new high water mark */
+
+ tdb_store_int(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm);
+
+ return True;
+}
+
+/* Get an id from a rid */
+
+static BOOL get_id_from_rid(char *domain_name, uint32 rid, uid_t *id,
+ BOOL isgroup)
+{
+ TDB_DATA data, key;
+ fstring keystr;
+ BOOL result = False;
+
+ /* Check if rid is present in database */
+
+ slprintf(keystr, sizeof(keystr), "%s/%d", domain_name, rid);
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ data = tdb_fetch(idmap_tdb, key);
+
+ if (data.dptr) {
+ fstring scanstr;
+ int the_id;
+
+ /* Parse and return existing uid */
+
+ fstrcpy(scanstr, isgroup ? "GID" : "UID");
+ fstrcat(scanstr, " %d");
+
+ if (sscanf(data.dptr, scanstr, &the_id) == 1) {
+
+ /* Store uid */
+
+ if (id) {
+ *id = the_id;
+ }
+
+ result = True;
+ }
+
+ SAFE_FREE(data.dptr);
+
+ } else {
+
+ /* Allocate a new id for this rid */
+
+ if (id && allocate_id(id, isgroup)) {
+ fstring keystr2;
+
+ /* Store new id */
+
+ slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" :
+ "UID", *id);
+
+ data.dptr = keystr2;
+ data.dsize = strlen(keystr2) + 1;
+
+ tdb_store(idmap_tdb, key, data, TDB_REPLACE);
+ tdb_store(idmap_tdb, data, key, TDB_REPLACE);
+
+ result = True;
+ }
+ }
+
+ return result;
+}
+
+/* Get a uid from a user rid */
+
+BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid,
+ uid_t *uid)
+{
+ return get_id_from_rid(domain_name, user_rid, uid, False);
+}
+
+/* Get a gid from a group rid */
+
+BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid,
+ gid_t *gid)
+{
+ return get_id_from_rid(domain_name, group_rid, gid, True);
+}
+
+BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
+ BOOL isgroup)
+{
+ TDB_DATA key, data;
+ fstring keystr;
+ BOOL result = False;
+
+ slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id);
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ data = tdb_fetch(idmap_tdb, key);
+
+ if (data.dptr) {
+ char *p = data.dptr;
+ fstring domain_name;
+ uint32 the_rid;
+
+ if (next_token(&p, domain_name, "/", sizeof(fstring))) {
+
+ the_rid = atoi(p);
+
+ if (rid) {
+ *rid = the_rid;
+ }
+
+ if (domain) {
+ *domain = find_domain_from_name(domain_name);
+ if (*domain == NULL) {
+ DEBUG(1, ("unknown domain %s for rid %d\n",
+ domain_name, the_rid));
+ result = False;
+ goto done;
+ }
+ }
+
+ result = True;
+ }
+ done:
+ SAFE_FREE(data.dptr);
+ }
+
+ return result;
+}
+
+/* Get a user rid from a uid */
+
+BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
+ struct winbindd_domain **domain)
+{
+ return get_rid_from_id((int)uid, user_rid, domain, False);
+}
+
+/* Get a group rid from a gid */
+
+BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
+ struct winbindd_domain **domain)
+{
+ return get_rid_from_id((int)gid, group_rid, domain, True);
+}
+
+/* Initialise idmap database */
+
+BOOL winbindd_idmap_init(void)
+{
+ /* Open tdb cache */
+
+ if (!(idmap_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
+ TDB_NOLOCK, O_RDWR | O_CREAT, 0600))) {
+ DEBUG(0, ("Unable to open idmap database\n"));
+ return False;
+ }
+
+ /* Create high water marks for group and user id */
+
+ if (tdb_fetch_int(idmap_tdb, HWM_USER) == -1) {
+ if (tdb_store_int(idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
+ DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
+ return False;
+ }
+ }
+
+ if (tdb_fetch_int(idmap_tdb, HWM_GROUP) == -1) {
+ if (tdb_store_int(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
+ DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/* Dump status information to log file. Display different stuff based on
+ the debug level:
+
+ Debug Level Information Displayed
+ =================================================================
+ 0 Percentage of [ug]id range allocated
+ 0 High water marks (next allocated ids)
+*/
+
+#define DUMP_INFO 0
+
+void winbindd_idmap_status(void)
+{
+ int user_hwm, group_hwm;
+
+ DEBUG(0, ("winbindd idmap status:\n"));
+
+ /* Get current high water marks */
+
+ if ((user_hwm = tdb_fetch_int(idmap_tdb, HWM_USER)) == -1) {
+ DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n"));
+ }
+
+ if ((group_hwm = tdb_fetch_int(idmap_tdb, HWM_GROUP)) == -1) {
+ DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n"));
+ }
+
+ /* Display next ids to allocate */
+
+ if (user_hwm != -1) {
+ DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm));
+ }
+
+ if (group_hwm != -1) {
+ DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm));
+ }
+
+ /* Display percentage of id range already allocated. */
+
+ if (user_hwm != -1) {
+ int num_users = user_hwm - server_state.uid_low;
+ int total_users = server_state.uid_high - server_state.uid_low;
+
+ DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n",
+ num_users * 100 / total_users, num_users,
+ total_users));
+ }
+
+ if (group_hwm != -1) {
+ int num_groups = group_hwm - server_state.gid_low;
+ int total_groups = server_state.gid_high - server_state.gid_low;
+
+ DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n",
+ num_groups * 100 / total_groups, num_groups,
+ total_groups));
+ }
+
+ /* Display complete mapping of users and groups to rids */
+}
diff --git a/source/nsswitch/winbindd_misc.c b/source/nsswitch/winbindd_misc.c
new file mode 100644
index 00000000000..2718a753856
--- /dev/null
+++ b/source/nsswitch/winbindd_misc.c
@@ -0,0 +1,152 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon - miscellaneous other functions
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+extern pstring global_myname;
+
+/************************************************************************
+ Routine to get the trust account password for a domain
+************************************************************************/
+static BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd,
+ time_t *pass_last_set_time)
+{
+ struct machine_acct_pass *pass;
+ size_t size;
+
+ if (!(pass = secrets_fetch(trust_keystr(domain), &size)) ||
+ size != sizeof(*pass))
+ return False;
+
+ if (pass_last_set_time)
+ *pass_last_set_time = pass->mod_time;
+
+ memcpy(ret_pwd, pass->hash, 16);
+ SAFE_FREE(pass);
+
+ return True;
+}
+
+/* Check the machine account password is valid */
+
+enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uchar trust_passwd[16];
+ int num_retries = 0;
+ struct cli_state *cli;
+ DEBUG(3, ("[%5d]: check machine account\n", state->pid));
+
+ /* Get trust account password */
+
+ again:
+ if (!_get_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ /* This call does a cli_nt_setup_creds() which implicitly checks
+ the trust account password. */
+
+ result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ cli_shutdown(cli);
+
+ /* There is a race condition between fetching the trust account
+ password and joining the domain so it's possible that the trust
+ account password has been changed on us. We are returned
+ NT_STATUS_ACCESS_DENIED if this happens. */
+
+#define MAX_RETRIES 8
+
+ if ((num_retries < MAX_RETRIES) &&
+ NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
+ num_retries++;
+ goto again;
+ }
+
+ /* Pass back result code - zero for success, other values for
+ specific failures. */
+
+ DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
+ "good" : "bad"));
+
+ done:
+ state->response.data.num_entries = NT_STATUS_V(result);
+
+ return WINBINDD_OK;
+}
+
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
+ *state)
+{
+ struct winbindd_domain *domain;
+ int total_entries = 0, extra_data_len = 0;
+ char *ted, *extra_data = NULL;
+
+ DEBUG(3, ("[%5d]: list trusted domains\n", state->pid));
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ for(domain = domain_list; domain; domain = domain->next) {
+
+ /* Skip own domain */
+
+ if (strequal(domain->name, lp_workgroup())) continue;
+
+ /* Add domain to list */
+
+ total_entries++;
+ ted = Realloc(extra_data, sizeof(fstring) *
+ total_entries);
+
+ if (!ted) {
+ DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
+ SAFE_FREE(extra_data);
+ return WINBINDD_ERROR;
+ } else
+ extra_data = ted;
+
+ memcpy(&extra_data[extra_data_len], domain->name,
+ strlen(domain->name));
+
+ extra_data_len += strlen(domain->name);
+ extra_data[extra_data_len++] = ',';
+ }
+
+ if (extra_data) {
+ if (extra_data_len > 1)
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ return WINBINDD_OK;
+}
diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h
new file mode 100644
index 00000000000..4fb9458c141
--- /dev/null
+++ b/source/nsswitch/winbindd_nss.h
@@ -0,0 +1,187 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0)
+#endif
+
+#ifndef _WINBINDD_NTDOM_H
+#define _WINBINDD_NTDOM_H
+
+#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */
+#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */
+
+#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */
+#define WINBINDD_DONT_ENV "_NO_WINBINDD"
+
+/* Socket commands */
+
+enum winbindd_cmd {
+
+ /* Get users and groups */
+
+ WINBINDD_GETPWNAM_FROM_USER,
+ WINBINDD_GETPWNAM_FROM_UID,
+ WINBINDD_GETGRNAM_FROM_GROUP,
+ WINBINDD_GETGRNAM_FROM_GID,
+ WINBINDD_GETGROUPS,
+
+ /* Enumerate users and groups */
+
+ WINBINDD_SETPWENT,
+ WINBINDD_ENDPWENT,
+ WINBINDD_GETPWENT,
+ WINBINDD_SETGRENT,
+ WINBINDD_ENDGRENT,
+ WINBINDD_GETGRENT,
+
+ /* PAM authenticate and password change */
+
+ WINBINDD_PAM_AUTH,
+ WINBINDD_PAM_AUTH_CRAP,
+ WINBINDD_PAM_CHAUTHTOK,
+
+ /* List various things */
+
+ WINBINDD_LIST_USERS, /* List w/o rid->id mapping */
+ WINBINDD_LIST_GROUPS, /* Ditto */
+ WINBINDD_LIST_TRUSTDOM,
+
+ /* SID conversion */
+
+ WINBINDD_LOOKUPSID,
+ WINBINDD_LOOKUPNAME,
+
+ /* Lookup functions */
+
+ WINBINDD_SID_TO_UID,
+ WINBINDD_SID_TO_GID,
+ WINBINDD_UID_TO_SID,
+ WINBINDD_GID_TO_SID,
+
+ /* Miscellaneous other stuff */
+
+ WINBINDD_CHECK_MACHACC, /* Check machine account pw works */
+
+ /* Placeholder for end of cmd list */
+
+ WINBINDD_NUM_CMDS
+};
+
+/* Winbind request structure */
+
+struct winbindd_request {
+ enum winbindd_cmd cmd; /* Winbindd command to execute */
+ pid_t pid; /* pid of calling process */
+
+ union {
+ fstring username; /* getpwnam */
+ fstring groupname; /* getgrnam */
+ uid_t uid; /* getpwuid, uid_to_sid */
+ gid_t gid; /* getgrgid, gid_to_sid */
+ struct {
+ fstring user;
+ fstring pass;
+ } auth; /* pam_winbind auth module */
+ struct {
+ unsigned char chal[8];
+ fstring user;
+ fstring lm_resp;
+ uint16 lm_resp_len;
+ fstring nt_resp;
+ uint16 nt_resp_len;
+ } auth_crap;
+ struct {
+ fstring user;
+ fstring oldpass;
+ fstring newpass;
+ } chauthtok; /* pam_winbind passwd module */
+ fstring sid; /* lookupsid, sid_to_[ug]id */
+ fstring name; /* lookupname */
+ uint32 num_entries; /* getpwent, getgrent */
+ } data;
+ fstring domain; /* {set,get,end}{pw,gr}ent() */
+};
+
+/* Response values */
+
+enum winbindd_result {
+ WINBINDD_ERROR,
+ WINBINDD_OK
+};
+
+/* Winbind response structure */
+
+struct winbindd_response {
+
+ /* Header information */
+
+ int length; /* Length of response */
+ enum winbindd_result result; /* Result code */
+
+ /* Fixed length return data */
+
+ union {
+
+ /* getpwnam, getpwuid */
+
+ struct winbindd_pw {
+ fstring pw_name;
+ fstring pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ fstring pw_gecos;
+ fstring pw_dir;
+ fstring pw_shell;
+ } pw;
+
+ /* getgrnam, getgrgid */
+
+ struct winbindd_gr {
+ fstring gr_name;
+ fstring gr_passwd;
+ gid_t gr_gid;
+ int num_gr_mem;
+ int gr_mem_ofs; /* offset to group membership */
+ } gr;
+
+ uint32 num_entries; /* getpwent, getgrent */
+ struct winbindd_sid {
+ fstring sid; /* lookupname, [ug]id_to_sid */
+ int type;
+ } sid;
+ struct winbindd_name {
+ fstring name; /* lookupsid */
+ int type;
+ } name;
+ uid_t uid; /* sid_to_uid */
+ gid_t gid; /* sid_to_gid */
+ } data;
+
+ /* Variable length return data */
+
+ void *extra_data; /* getgrnam, getgrgid, getgrent */
+};
+
+#endif
diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c
new file mode 100644
index 00000000000..b602ccf5828
--- /dev/null
+++ b/source/nsswitch/winbindd_pam.c
@@ -0,0 +1,204 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+
+ Winbind daemon - pam auth funcions
+
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/* Return a password structure from a username. */
+
+enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ fstring name_domain, name_user;
+ int passlen;
+ unsigned char trust_passwd[16];
+ time_t last_change_time;
+ auth_usersupplied_info *user_info;
+ uint32 smb_uid_low;
+ NET_USER_INFO_3 info3;
+ NET_ID_INFO_CTR ctr;
+ struct cli_state *cli;
+ uchar chal[8];
+
+ DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
+ state->request.data.auth.user));
+
+ /* Parse domain and username */
+
+ if (!parse_domain_user(state->request.data.auth.user, name_domain,
+ name_user))
+ return WINBINDD_ERROR;
+
+ passlen = strlen(state->request.data.auth.pass);
+
+ if (state->request.data.auth.pass[0])
+ make_user_info_winbind(&user_info,
+ name_user, name_domain,
+ state->request.data.auth.pass,
+ chal);
+ else
+ return WINBINDD_ERROR;
+
+ /*
+ * Get the machine account password for our primary domain
+ */
+
+ if (!secrets_fetch_trust_account_password(
+ lp_workgroup(), trust_passwd, &last_change_time)) {
+ DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
+ "password for domain %s\n", lp_workgroup()));
+ return WINBINDD_ERROR;
+ }
+
+ /* We really don't care what LUID we give the user. */
+
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ ZERO_STRUCT(info3);
+
+ result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ result = cli_nt_login_network(cli, user_info, chal, smb_uid_low,
+ &ctr, &info3);
+
+ free_user_info(&user_info);
+
+ cli_shutdown(cli);
+
+ done:
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* Challenge Response Authentication Protocol */
+
+enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
+{
+ NTSTATUS result;
+ fstring name_domain, name_user;
+ unsigned char trust_passwd[16];
+ time_t last_change_time;
+
+ auth_usersupplied_info *user_info;
+ uint32 smb_uid_low;
+ NET_USER_INFO_3 info3;
+ NET_ID_INFO_CTR ctr;
+ struct cli_state *cli;
+
+ DEBUG(3, ("[%5d]: pam auth crap %s\n", state->pid,
+ state->request.data.auth_crap.user));
+
+ /* Parse domain and username */
+
+ if (!parse_domain_user(state->request.data.auth_crap.user, name_domain,
+ name_user))
+ return WINBINDD_ERROR;
+
+ make_user_info_winbind_crap(
+ &user_info, name_user,
+ name_domain,
+ (uchar *)state->request.data.auth_crap.lm_resp,
+ state->request.data.auth_crap.lm_resp_len,
+ (uchar *)state->request.data.auth_crap.nt_resp,
+ state->request.data.auth_crap.nt_resp_len);
+
+ /*
+ * Get the machine account password for our primary domain
+ */
+
+ if (!secrets_fetch_trust_account_password(
+ lp_workgroup(), trust_passwd, &last_change_time)) {
+ DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
+ "password for domain %s\n", lp_workgroup()));
+ return WINBINDD_ERROR;
+ }
+
+ /* We really don't care what LUID we give the user. */
+
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ ZERO_STRUCT(info3);
+
+ result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ result = cli_nt_login_network(cli, user_info, state->request.data.auth_crap.chal,
+ smb_uid_low, &ctr, &info3);
+
+ free_user_info(&user_info);
+
+ cli_shutdown(cli);
+
+ done:
+ return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* Change a user password */
+
+enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
+{
+ char *oldpass, *newpass;
+ fstring domain, user;
+ uchar nt_oldhash[16];
+ uchar lm_oldhash[16];
+
+ DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
+ state->request.data.chauthtok.user));
+
+ /* Setup crap */
+
+ if (state == NULL)
+ return WINBINDD_ERROR;
+
+ if (!parse_domain_user(state->request.data.chauthtok.user, domain, user))
+ return WINBINDD_ERROR;
+
+ oldpass = state->request.data.chauthtok.oldpass;
+ newpass = state->request.data.chauthtok.newpass;
+
+ nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash);
+
+ /* Change password */
+
+#if 0
+
+ /* XXX */
+
+ if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user,
+ lm_oldhash, nt_oldhash, newpass)) {
+ DEBUG(0, ("password change failed for user %s/%s\n", domain, user));
+ return WINBINDD_ERROR;
+ }
+#endif
+
+ return WINBINDD_OK;
+}
diff --git a/source/nsswitch/winbindd_proto.h b/source/nsswitch/winbindd_proto.h
new file mode 100644
index 00000000000..f0badc4331b
--- /dev/null
+++ b/source/nsswitch/winbindd_proto.h
@@ -0,0 +1,114 @@
+#ifndef _WINBINDD_PROTO_H_
+#define _WINBINDD_PROTO_H_
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/* The following definitions come from nsswitch/winbindd.c */
+
+int main(int argc, char **argv);
+
+/* The following definitions come from nsswitch/winbindd_ads.c */
+
+ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
+ const char *exp,
+ const char **attrs, void **res);
+ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
+ const char *exp,
+ const char **attrs);
+ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, void **res,
+ const char *dn,
+ const char **attrs);
+
+/* The following definitions come from nsswitch/winbindd_cache.c */
+
+void wcache_flush_cache(void);
+struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status);
+
+/* The following definitions come from nsswitch/winbindd_cm.c */
+
+void cm_init_creds(struct ntuser_creds *creds);
+CLI_POLICY_HND *cm_get_lsa_handle(char *domain);
+CLI_POLICY_HND *cm_get_sam_handle(char *domain);
+CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid);
+CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
+ uint32 user_rid);
+CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
+ uint32 group_rid);
+NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
+ struct cli_state **cli);
+void winbindd_cm_status(void);
+
+/* The following definitions come from nsswitch/winbindd_group.c */
+
+enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
+ *state);
+enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_endgrent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state);
+
+/* The following definitions come from nsswitch/winbindd_idmap.c */
+
+BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid,
+ uid_t *uid);
+BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid,
+ gid_t *gid);
+BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain,
+ BOOL isgroup);
+BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
+ struct winbindd_domain **domain);
+BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid,
+ struct winbindd_domain **domain);
+BOOL winbindd_idmap_init(void);
+void winbindd_idmap_status(void);
+
+/* The following definitions come from nsswitch/winbindd_misc.c */
+
+enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
+ *state);
+
+/* The following definitions come from nsswitch/winbindd_pam.c */
+
+enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) ;
+enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) ;
+enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state);
+
+/* The following definitions come from nsswitch/winbindd_rpc.c */
+
+
+/* The following definitions come from nsswitch/winbindd_sid.c */
+
+enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state);
+
+/* The following definitions come from nsswitch/winbindd_user.c */
+
+enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state) ;
+enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state);
+enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state);
+
+/* The following definitions come from nsswitch/winbindd_util.c */
+
+struct winbindd_domain *find_domain_from_name(char *domain_name);
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid);
+BOOL get_domain_info(void);
+BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
+ const char *name, DOM_SID *sid, enum SID_NAME_USE *type);
+BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
+ fstring name,
+ enum SID_NAME_USE *type);
+void free_getent_state(struct getent_state *state);
+BOOL winbindd_param_init(void);
+BOOL check_domain_env(char *domain_env, char *domain);
+BOOL parse_domain_user(const char *domuser, fstring domain, fstring user);
+#endif /* _PROTO_H_ */
diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c
new file mode 100644
index 00000000000..87656d7ae24
--- /dev/null
+++ b/source/nsswitch/winbindd_rpc.c
@@ -0,0 +1,570 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Winbind rpc backend functions
+
+ Copyright (C) Tim Potter 2000-2001
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/* Query display info for a domain. This returns enough information plus a
+ bit extra to give an overview of domain users for the User Manager
+ application. */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ CLI_POLICY_HND *hnd;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND dom_pol;
+ BOOL got_dom_pol = False;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ SAM_DISPINFO_CTR ctr;
+ SAM_DISPINFO_1 info1;
+ int i;
+
+ *num_entries = 0;
+ *info = NULL;
+
+ /* Get sam handle */
+
+ if (!(hnd = cm_get_sam_handle(domain->name)))
+ goto done;
+
+ /* Get domain handle */
+
+ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
+ des_access, &domain->sid, &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_dom_pol = True;
+
+ ctr.sam.info1 = &info1;
+
+ i = 0;
+ do {
+ uint32 count = 0, start=i;
+ int j;
+
+
+ /* Query display info level 1 */
+ result = cli_samr_query_dispinfo(hnd->cli, mem_ctx,
+ &dom_pol, &start, 1,
+ &count, 0xFFFF, &ctr);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
+
+ (*num_entries) += count;
+
+ /* now map the result into the WINBIND_USERINFO structure */
+ (*info) = talloc_realloc(mem_ctx, *info,
+ (*num_entries)*sizeof(WINBIND_USERINFO));
+ if (!(*info)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (j=0;j<count;i++, j++) {
+ (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
+ (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
+ (*info)[i].user_rid = info1.sam[j].rid_user;
+ /* For the moment we set the primary group for
+ every user to be the Domain Users group.
+ There are serious problems with determining
+ the actual primary group for large domains.
+ This should really be made into a 'winbind
+ force group' smb.conf parameter or
+ something like that. */
+ (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
+ }
+ } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+
+ done:
+
+ if (got_dom_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ CLI_POLICY_HND *hnd;
+ POLICY_HND dom_pol;
+ NTSTATUS status;
+
+ *num_entries = 0;
+ *info = NULL;
+
+ if (!(hnd = cm_get_sam_handle(domain->name))) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ status = cli_samr_open_domain(hnd->cli, mem_ctx,
+ &hnd->pol, des_access, &domain->sid, &dom_pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ do {
+ struct acct_info *info2 = NULL;
+ uint32 count = 0, start = *num_entries;
+ TALLOC_CTX *mem_ctx2;
+
+ mem_ctx2 = talloc_init();
+
+ status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
+ &start,
+ 0xFFFF, /* buffer size? */
+ &info2, &count);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ talloc_destroy(mem_ctx2);
+ break;
+ }
+
+ (*info) = talloc_realloc(mem_ctx, *info,
+ sizeof(**info) * ((*num_entries) + count));
+ if (! *info) {
+ talloc_destroy(mem_ctx2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
+ (*num_entries) += count;
+ talloc_destroy(mem_ctx2);
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ return status;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
+{
+ TALLOC_CTX *mem_ctx;
+ CLI_POLICY_HND *hnd;
+ NTSTATUS status;
+ DOM_SID *sids = NULL;
+ uint32 *types = NULL;
+ int num_sids;
+
+ if (!(mem_ctx = talloc_init()))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(hnd = cm_get_lsa_handle(domain->name)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, &name,
+ &sids, &types, &num_sids);
+
+ /* Return rid and type if lookup successful */
+ if (NT_STATUS_IS_OK(status)) {
+ sid_copy(sid, &sids[0]);
+ *type = types[0];
+ }
+
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type)
+{
+ CLI_POLICY_HND *hnd;
+ char **names;
+ uint32 *types;
+ int num_names;
+ NTSTATUS status;
+
+ if (!(hnd = cm_get_lsa_handle(domain->name)))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
+ 1, sid, &names, &types,
+ &num_names);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *type = types[0];
+ *name = names[0];
+ DEBUG(5,("Mapped sid to %s\n", *name));
+ }
+
+ return status;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ WINBIND_USERINFO *user_info)
+{
+ CLI_POLICY_HND *hnd;
+ NTSTATUS result;
+ POLICY_HND dom_pol, user_pol;
+ BOOL got_dom_pol = False, got_user_pol = False;
+ SAM_USERINFO_CTR *ctr;
+
+ /* Get sam handle */
+ if (!(hnd = cm_get_sam_handle(domain->name)))
+ goto done;
+
+ /* Get domain handle */
+
+ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain->sid, &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_dom_pol = True;
+
+ /* Get user handle */
+ result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Get user info */
+ result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
+ 0x15, &ctr);
+
+ cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+
+ user_info->group_rid = ctr->info.id21->group_rid;
+ user_info->acct_name = unistr2_tdup(mem_ctx,
+ &ctr->info.id21->uni_user_name);
+ user_info->full_name = unistr2_tdup(mem_ctx,
+ &ctr->info.id21->uni_full_name);
+
+ done:
+ /* Clean up policy handles */
+ if (got_user_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+
+ if (got_dom_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 user_rid,
+ uint32 *num_groups, uint32 **user_gids)
+{
+ CLI_POLICY_HND *hnd;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND dom_pol, user_pol;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ BOOL got_dom_pol = False, got_user_pol = False;
+ DOM_GID *user_groups;
+ int i;
+
+ *num_groups = 0;
+
+ /* Get sam handle */
+ if (!(hnd = cm_get_sam_handle(domain->name)))
+ goto done;
+
+ /* Get domain handle */
+ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
+ des_access, &domain->sid, &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_dom_pol = True;
+
+ /* Get user handle */
+ result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
+ des_access, user_rid, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_user_pol = True;
+
+ /* Query user rids */
+ result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
+ num_groups, &user_groups);
+
+ if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
+ goto done;
+
+ (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
+ for (i=0;i<(*num_groups);i++) {
+ (*user_gids)[i] = user_groups[i].g_rid;
+ }
+
+ done:
+ /* Clean up policy handles */
+ if (got_user_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &user_pol);
+
+ if (got_dom_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+
+/* Lookup group membership given a rid. */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 group_rid, uint32 *num_names,
+ uint32 **rid_mem, char ***names,
+ uint32 **name_types)
+{
+ CLI_POLICY_HND *hnd;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i, total_names = 0;
+ POLICY_HND dom_pol, group_pol;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+ BOOL got_dom_pol = False, got_group_pol = False;
+
+ *num_names = 0;
+
+ /* Get sam handle */
+
+ if (!(hnd = cm_get_sam_handle(domain->name)))
+ goto done;
+
+ /* Get domain handle */
+
+ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
+ des_access, &domain->sid, &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_dom_pol = True;
+
+ /* Get group handle */
+
+ result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
+ des_access, group_rid, &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_group_pol = True;
+
+ /* Step #1: Get a list of user rids that are the members of the
+ group. */
+
+ result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
+ &group_pol, num_names, rid_mem,
+ name_types);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Step #2: Convert list of rids into list of usernames. Do this
+ in bunches of ~1000 to avoid crashing NT4. It looks like there
+ is a buffer overflow or something like that lurking around
+ somewhere. */
+
+#define MAX_LOOKUP_RIDS 900
+
+ *names = talloc(mem_ctx, *num_names * sizeof(char *));
+ *name_types = talloc(mem_ctx, *num_names * sizeof(uint32));
+
+ for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
+ int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
+ uint32 tmp_num_names = 0;
+ char **tmp_names = NULL;
+ uint32 *tmp_types = NULL;
+
+ /* Lookup a chunk of rids */
+
+ result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
+ &dom_pol, 1000, /* flags */
+ num_lookup_rids,
+ &(*rid_mem)[i],
+ &tmp_num_names,
+ &tmp_names, &tmp_types);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Copy result into array. The talloc system will take
+ care of freeing the temporary arrays later on. */
+
+ memcpy(&(*names)[i], tmp_names, sizeof(char *) *
+ tmp_num_names);
+
+ memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
+ tmp_num_names);
+
+ total_names += tmp_num_names;
+ }
+
+ *num_names = total_names;
+
+ done:
+ if (got_group_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &group_pol);
+
+ if (got_dom_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ TALLOC_CTX *mem_ctx;
+ CLI_POLICY_HND *hnd;
+ SAM_UNK_CTR ctr;
+ uint16 switch_value = 2;
+ NTSTATUS result;
+ uint32 seqnum = DOM_SEQUENCE_NONE;
+ POLICY_HND dom_pol;
+ BOOL got_dom_pol = False;
+ uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+ *seq = DOM_SEQUENCE_NONE;
+
+ if (!(mem_ctx = talloc_init()))
+ return NT_STATUS_NO_MEMORY;
+
+ /* Get sam handle */
+
+ if (!(hnd = cm_get_sam_handle(domain->name)))
+ goto done;
+
+ /* Get domain handle */
+
+ result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
+ des_access, &domain->sid, &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_dom_pol = True;
+
+ /* Query domain info */
+
+ result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
+ switch_value, &ctr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ seqnum = ctr.info.inf2.seq_num;
+ DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
+ } else {
+ DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
+ (unsigned)seqnum, domain->name ));
+ }
+
+ done:
+
+ if (got_dom_pol)
+ cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
+
+ talloc_destroy(mem_ctx);
+
+ *seq = seqnum;
+
+ return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ DOM_SID **dom_sids)
+{
+ CLI_POLICY_HND *hnd;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 enum_ctx = 0;
+
+ *num_domains = 0;
+
+ if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
+ goto done;
+
+ result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
+ &hnd->pol, &enum_ctx, num_domains,
+ names, dom_sids);
+done:
+ return result;
+}
+
+/* find the domain sid for a domain */
+static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ TALLOC_CTX *mem_ctx;
+ CLI_POLICY_HND *hnd;
+ fstring level5_dom;
+
+ if (!(mem_ctx = talloc_init()))
+ return NT_STATUS_NO_MEMORY;
+
+ /* Get sam handle */
+ if (!(hnd = cm_get_lsa_handle(domain->name)))
+ goto done;
+
+ status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
+ &hnd->pol, 0x05, level5_dom, sid);
+
+done:
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods msrpc_methods = {
+ False,
+ query_user_list,
+ enum_dom_groups,
+ name_to_sid,
+ sid_to_name,
+ query_user,
+ lookup_usergroups,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ domain_sid
+};
diff --git a/source/nsswitch/winbindd_sid.c b/source/nsswitch/winbindd_sid.c
new file mode 100644
index 00000000000..a6daecff712
--- /dev/null
+++ b/source/nsswitch/winbindd_sid.c
@@ -0,0 +1,250 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon - sid related functions
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+#include "sids.h"
+
+/* Convert a string */
+
+enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
+{
+ extern DOM_SID global_sid_Builtin;
+ enum SID_NAME_USE type;
+ DOM_SID sid, tmp_sid;
+ uint32 rid;
+ fstring name;
+
+ DEBUG(3, ("[%5d]: lookupsid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Lookup sid from PDC using lsa_lookup_sids() */
+
+ string_to_sid(&sid, state->request.data.sid);
+
+ /* Don't look up BUILTIN sids */
+
+ sid_copy(&tmp_sid, &sid);
+ sid_split_rid(&tmp_sid, &rid);
+
+ if (sid_equal(&tmp_sid, &global_sid_Builtin)) {
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup the sid */
+
+ if (!winbindd_lookup_name_by_sid(&sid, name, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ string_sub(name, "\\", lp_winbind_separator(), sizeof(fstring));
+ fstrcpy(state->response.data.name.name, name);
+ state->response.data.name.type = type;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a string */
+
+enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
+{
+ enum SID_NAME_USE type;
+ fstring sid_str, name_domain, name_user, name;
+ DOM_SID sid;
+ struct winbindd_domain *domain;
+ DEBUG(3, ("[%5d]: lookupname %s\n", state->pid,
+ state->request.data.name));
+
+ if (!parse_domain_user(state->request.data.name, name_domain, name_user))
+ return WINBINDD_ERROR;
+
+ snprintf(name, sizeof(name), "%s\\%s", name_domain, name_user);
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(0, ("could not find domain entry for domain %s\n",
+ name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ /* Lookup name from PDC using lsa_lookup_names() */
+ if (!winbindd_lookup_sid_by_name(domain, name, &sid, &type)) {
+ return WINBINDD_ERROR;
+ }
+
+ sid_to_string(sid_str, &sid);
+ fstrcpy(state->response.data.sid.sid, sid_str);
+ state->response.data.sid.type = type;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a uid. We assume we only have one rid attached to the
+ sid. */
+
+enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 user_rid;
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5d]: sid to uid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Split sid into domain sid and user rid */
+
+ string_to_sid(&sid, state->request.data.sid);
+ sid_split_rid(&sid, &user_rid);
+
+ /* Find domain this sid belongs to */
+
+ if ((domain = find_domain_from_sid(&sid)) == NULL) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sid);
+ DEBUG(1, ("Could not find domain for sid %s\n", sid_str));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find uid for this sid and return it */
+
+ if (!winbindd_idmap_get_uid_from_rid(domain->name, user_rid,
+ &state->response.data.uid)) {
+ DEBUG(1, ("Could not get uid for sid %s\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Convert a sid to a gid. We assume we only have one rid attached to the
+ sid.*/
+
+enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
+{
+ DOM_SID sid;
+ uint32 group_rid;
+ struct winbindd_domain *domain;
+
+ DEBUG(3, ("[%5d]: sid to gid %s\n", state->pid,
+ state->request.data.sid));
+
+ /* Split sid into domain sid and user rid */
+
+ string_to_sid(&sid, state->request.data.sid);
+ sid_split_rid(&sid, &group_rid);
+
+ /* Find domain this sid belongs to */
+
+ if ((domain = find_domain_from_sid(&sid)) == NULL) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sid);
+ DEBUG(1, ("Could not find domain for sid %s\n", sid_str));
+ return WINBINDD_ERROR;
+ }
+
+ /* Find uid for this sid and return it */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid,
+ &state->response.data.gid)) {
+ DEBUG(1, ("Could not get gid for sid %s\n",
+ state->request.data.sid));
+ return WINBINDD_ERROR;
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Convert a uid to a sid */
+
+enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ uint32 user_rid;
+ DOM_SID sid;
+
+ /* Bug out if the uid isn't in the winbind range */
+
+ if ((state->request.data.uid < server_state.uid_low ) ||
+ (state->request.data.uid > server_state.uid_high)) {
+ return WINBINDD_ERROR;
+ }
+
+ DEBUG(3, ("[%5d]: uid to sid %d\n", state->pid,
+ state->request.data.uid));
+
+ /* Lookup rid for this uid */
+
+ if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid,
+ &user_rid, &domain)) {
+ DEBUG(1, ("Could not convert uid %d to rid\n",
+ state->request.data.uid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Construct sid and return it */
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, user_rid);
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_USER;
+
+ return WINBINDD_OK;
+}
+
+/* Convert a gid to a sid */
+
+enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ uint32 group_rid;
+ DOM_SID sid;
+
+ /* Bug out if the gid isn't in the winbind range */
+
+ if ((state->request.data.gid < server_state.gid_low) ||
+ (state->request.data.gid > server_state.gid_high)) {
+ return WINBINDD_ERROR;
+ }
+
+ DEBUG(3, ("[%5d]: gid to sid %d\n", state->pid,
+ state->request.data.gid));
+
+ /* Lookup rid for this uid */
+
+ if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid,
+ &group_rid, &domain)) {
+ DEBUG(1, ("Could not convert gid %d to rid\n",
+ state->request.data.gid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Construct sid and return it */
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, group_rid);
+ sid_to_string(state->response.data.sid.sid, &sid);
+ state->response.data.sid.type = SID_NAME_DOM_GRP;
+
+ return WINBINDD_OK;
+}
diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c
new file mode 100644
index 00000000000..6f38b13548a
--- /dev/null
+++ b/source/nsswitch/winbindd_user.c
@@ -0,0 +1,616 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+
+ Winbind daemon - user related functions
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/* Fill a pwent structure with information we have obtained */
+
+static BOOL winbindd_fill_pwent(char *domain_name, char *name,
+ uint32 user_rid, uint32 group_rid,
+ char *full_name, struct winbindd_pw *pw)
+{
+ extern userdom_struct current_user_info;
+ fstring name_domain, name_user;
+ pstring homedir;
+
+ if (!pw || !name)
+ return False;
+
+ /* Resolve the uid number */
+
+ if (!winbindd_idmap_get_uid_from_rid(domain_name, user_rid,
+ &pw->pw_uid)) {
+ DEBUG(1, ("error getting user id for rid %d\n", user_rid));
+ return False;
+ }
+
+ /* Resolve the gid number */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain_name, group_rid,
+ &pw->pw_gid)) {
+ DEBUG(1, ("error getting group id for rid %d\n", group_rid));
+ return False;
+ }
+
+ /* Username */
+
+ safe_strcpy(pw->pw_name, name, sizeof(pw->pw_name) - 1);
+
+ /* Full name (gecos) */
+
+ safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
+
+ /* Home directory and shell - use template config parameters. The
+ defaults are /tmp for the home directory and /bin/false for
+ shell. */
+
+ if (!parse_domain_user(name, name_domain, name_user)) {
+ DEBUG(1, ("error parsing domain user for %s\n", name_user ));
+ return False;
+ }
+
+ /* The substitution of %U and %D in the 'template homedir' is done
+ by lp_string() calling standard_sub_basic(). */
+
+ fstrcpy(current_user_info.smb_name, name_user);
+ fstrcpy(current_user_info.domain, name_domain);
+
+ pstrcpy(homedir, lp_template_homedir());
+
+ safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
+
+ safe_strcpy(pw->pw_shell, lp_template_shell(),
+ sizeof(pw->pw_shell) - 1);
+
+ /* Password - set to "x" as we can't generate anything useful here.
+ Authentication can be done using the pam_ntdom module. */
+
+ safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+
+ return True;
+}
+
+/* Return a password structure from a username. */
+
+enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state)
+{
+ uint32 user_rid;
+ WINBIND_USERINFO user_info;
+ DOM_SID user_sid;
+ NTSTATUS status;
+ fstring name_domain, name_user, name;
+ enum SID_NAME_USE name_type;
+ struct winbindd_domain *domain;
+ TALLOC_CTX *mem_ctx;
+
+ DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid,
+ state->request.data.username));
+
+ /* Parse domain and username */
+
+ if (!parse_domain_user(state->request.data.username, name_domain,
+ name_user))
+ return WINBINDD_ERROR;
+
+ if ((domain = find_domain_from_name(name_domain)) == NULL) {
+ DEBUG(5, ("No such domain: %s\n", name_domain));
+ return WINBINDD_ERROR;
+ }
+
+ slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user);
+
+ /* Get rid and name type from name */
+
+ if (!winbindd_lookup_sid_by_name(domain, name, &user_sid, &name_type)) {
+ DEBUG(1, ("user '%s' does not exist\n", name_user));
+ return WINBINDD_ERROR;
+ }
+
+ if (name_type != SID_NAME_USER) {
+ DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
+ name_type));
+ return WINBINDD_ERROR;
+ }
+
+ /* Get some user info. Split the user rid from the sid obtained
+ from the winbind_lookup_by_name() call and use it in a
+ winbind_lookup_userinfo() */
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(1, ("out of memory\n"));
+ return WINBINDD_ERROR;
+ }
+
+ sid_split_rid(&user_sid, &user_rid);
+
+ status = domain->methods->query_user(domain, mem_ctx, user_rid, &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("pwnam_from_user(): error getting user info for "
+ "user '%s'\n", name_user));
+ talloc_destroy(mem_ctx);
+ return WINBINDD_ERROR;
+ }
+
+ /* Now take all this information and fill in a passwd structure */
+ if (!winbindd_fill_pwent(name_domain, state->request.data.username,
+ user_rid, user_info.group_rid, user_info.full_name,
+ &state->response.data.pw)) {
+ talloc_destroy(mem_ctx);
+ return WINBINDD_ERROR;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return WINBINDD_OK;
+}
+
+/* Return a password structure given a uid number */
+
+enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ struct winbindd_domain *domain;
+ uint32 user_rid;
+ fstring user_name;
+ enum SID_NAME_USE name_type;
+ WINBIND_USERINFO user_info;
+ gid_t gid;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ /* Bug out if the uid isn't in the winbind range */
+
+ if ((state->request.data.uid < server_state.uid_low ) ||
+ (state->request.data.uid > server_state.uid_high))
+ return WINBINDD_ERROR;
+
+ DEBUG(3, ("[%5d]: getpwuid %d\n", state->pid,
+ state->request.data.uid));
+
+ /* Get rid from uid */
+
+ if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid,
+ &user_rid, &domain)) {
+ DEBUG(1, ("Could not convert uid %d to rid\n",
+ state->request.data.uid));
+ return WINBINDD_ERROR;
+ }
+
+ /* Get name and name type from rid */
+
+ sid_copy(&user_sid, &domain->sid);
+ sid_append_rid(&user_sid, user_rid);
+
+ if (!winbindd_lookup_name_by_sid(&user_sid, user_name, &name_type)) {
+ fstring temp;
+
+ sid_to_string(temp, &user_sid);
+ DEBUG(1, ("Could not lookup sid %s\n", temp));
+ return WINBINDD_ERROR;
+ }
+
+ if (strcmp("\\", lp_winbind_separator()))
+ string_sub(user_name, "\\", lp_winbind_separator(),
+ sizeof(fstring));
+
+ /* Get some user info */
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(1, ("out of memory\n"));
+ return WINBINDD_ERROR;
+ }
+
+ status = domain->methods->query_user(domain, mem_ctx, user_rid, &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("pwnam_from_uid(): error getting user info for "
+ "user '%s'\n", user_name));
+ return WINBINDD_ERROR;
+ }
+
+ /* Resolve gid number */
+
+ if (!winbindd_idmap_get_gid_from_rid(domain->name, user_info.group_rid, &gid)) {
+ DEBUG(1, ("error getting group id for user %s\n", user_name));
+ return WINBINDD_ERROR;
+ }
+
+ /* Fill in password structure */
+
+ if (!winbindd_fill_pwent(domain->name, user_name, user_rid, user_info.group_rid,
+ user_info.full_name, &state->response.data.pw)) {
+ return WINBINDD_ERROR;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return WINBINDD_OK;
+}
+
+/*
+ * set/get/endpwent functions
+ */
+
+/* Rewind file pointer for ntdom passwd database */
+
+enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *tmp;
+
+ DEBUG(3, ("[%5d]: setpwent\n", state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_users())
+ return WINBINDD_ERROR;
+
+ /* Free old static data if it exists */
+
+ if (state->getpwent_state != NULL) {
+ free_getent_state(state->getpwent_state);
+ state->getpwent_state = NULL;
+ }
+
+ /* Create sam pipes for each domain we know about */
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ for(tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ struct getent_state *domain_state;
+
+ /*
+ * Skip domains other than WINBINDD_DOMAIN environment
+ * variable.
+ */
+
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, tmp->name))
+ continue;
+
+ /* Create a state record for this domain */
+
+ if ((domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL)
+ return WINBINDD_ERROR;
+
+ ZERO_STRUCTP(domain_state);
+
+ domain_state->domain = tmp;
+
+ /* Add to list of open domains */
+
+ DLIST_ADD(state->getpwent_state, domain_state);
+ }
+
+ return WINBINDD_OK;
+}
+
+/* Close file pointer to ntdom passwd database */
+
+enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
+{
+ DEBUG(3, ("[%5d]: endpwent\n", state->pid));
+
+ free_getent_state(state->getpwent_state);
+ state->getpwent_state = NULL;
+
+ return WINBINDD_OK;
+}
+
+/* Get partial list of domain users for a domain. We fill in the sam_entries,
+ and num_sam_entries fields with domain user information. The dispinfo_ndx
+ field is incremented to the index of the next user to fetch. Return True if
+ some users were returned, False otherwise. */
+
+#define MAX_FETCH_SAM_ENTRIES 100
+
+static BOOL get_sam_user_entries(struct getent_state *ent)
+{
+ NTSTATUS status;
+ uint32 num_entries;
+ WINBIND_USERINFO *info;
+ struct getpwent_user *name_list = NULL;
+ BOOL result = False;
+ TALLOC_CTX *mem_ctx;
+ struct winbindd_methods *methods;
+ int i;
+
+ if (ent->num_sam_entries)
+ return False;
+
+ if (!(mem_ctx = talloc_init()))
+ return False;
+
+ methods = ent->domain->methods;
+
+ /* Free any existing user info */
+
+ SAFE_FREE(ent->sam_entries);
+ ent->num_sam_entries = 0;
+
+ /* Call query_user_list to get a list of usernames and user rids */
+ num_entries = 0;
+
+ status = methods->query_user_list(ent->domain, mem_ctx,
+ &num_entries, &info);
+
+ if (num_entries) {
+ struct getpwent_user *tnl;
+
+ tnl = (struct getpwent_user *)Realloc(name_list,
+ sizeof(struct getpwent_user) *
+ (ent->num_sam_entries +
+ num_entries));
+
+ if (!tnl) {
+ DEBUG(0,("get_sam_user_entries: Realloc failed.\n"));
+ SAFE_FREE(name_list);
+ goto done;
+ } else
+ name_list = tnl;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ /* Store account name and gecos */
+ if (!info[i].acct_name) {
+ fstrcpy(name_list[ent->num_sam_entries + i].name, "");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].name,
+ info[i].acct_name);
+ }
+ if (!info[i].full_name) {
+ fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
+ } else {
+ fstrcpy(name_list[ent->num_sam_entries + i].gecos,
+ info[i].full_name);
+ }
+
+ /* User and group ids */
+ name_list[ent->num_sam_entries+i].user_rid = info[i].user_rid;
+ name_list[ent->num_sam_entries+i].group_rid = info[i].group_rid;
+ }
+
+ ent->num_sam_entries += num_entries;
+
+ /* Fill in remaining fields */
+
+ ent->sam_entries = name_list;
+ ent->sam_entry_index = 0;
+ result = ent->num_sam_entries > 0;
+
+ done:
+
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Fetch next passwd entry from ntdom database */
+
+#define MAX_GETPWENT_USERS 500
+
+enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
+{
+ struct getent_state *ent;
+ struct winbindd_pw *user_list;
+ int num_users, user_list_ndx = 0, i;
+ char *sep;
+
+ DEBUG(3, ("[%5d]: getpwent\n", state->pid));
+
+ /* Check user has enabled this */
+
+ if (!lp_winbind_enum_users())
+ return WINBINDD_ERROR;
+
+ /* Allocate space for returning a chunk of users */
+
+ num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
+
+ if ((state->response.extra_data =
+ malloc(num_users * sizeof(struct winbindd_pw))) == NULL)
+ return WINBINDD_ERROR;
+
+ memset(state->response.extra_data, 0, num_users *
+ sizeof(struct winbindd_pw));
+
+ user_list = (struct winbindd_pw *)state->response.extra_data;
+ sep = lp_winbind_separator();
+
+ if (!(ent = state->getpwent_state))
+ return WINBINDD_ERROR;
+
+ /* Start sending back users */
+
+ for (i = 0; i < num_users; i++) {
+ struct getpwent_user *name_list = NULL;
+ fstring domain_user_name;
+ uint32 result;
+
+ /* Do we need to fetch another chunk of users? */
+
+ if (ent->num_sam_entries == ent->sam_entry_index) {
+
+ while(ent && !get_sam_user_entries(ent)) {
+ struct getent_state *next_ent;
+
+ /* Free state information for this domain */
+
+ SAFE_FREE(ent->sam_entries);
+
+ next_ent = ent->next;
+ DLIST_REMOVE(state->getpwent_state, ent);
+
+ SAFE_FREE(ent);
+ ent = next_ent;
+ }
+
+ /* No more domains */
+
+ if (!ent)
+ break;
+ }
+
+ name_list = ent->sam_entries;
+
+ /* Skip machine accounts */
+
+ if (name_list[ent->sam_entry_index].
+ name[strlen(name_list[ent->sam_entry_index].name) - 1]
+ == '$') {
+ ent->sam_entry_index++;
+ continue;
+ }
+
+ /* Lookup user info */
+
+ slprintf(domain_user_name, sizeof(domain_user_name) - 1,
+ "%s%s%s", ent->domain->name, sep,
+ name_list[ent->sam_entry_index].name);
+
+ result = winbindd_fill_pwent(
+ ent->domain->name,
+ domain_user_name,
+ name_list[ent->sam_entry_index].user_rid,
+ name_list[ent->sam_entry_index].group_rid,
+ name_list[ent->sam_entry_index].gecos,
+ &user_list[user_list_ndx]);
+
+ ent->sam_entry_index++;
+
+ /* Add user to return list */
+
+ if (result) {
+
+ user_list_ndx++;
+ state->response.data.num_entries++;
+ state->response.length +=
+ sizeof(struct winbindd_pw);
+
+ } else
+ DEBUG(1, ("could not lookup domain user %s\n",
+ domain_user_name));
+ }
+
+ /* Out of domains */
+
+ return (user_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
+}
+
+/* List domain users without mapping to unix ids */
+
+enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ WINBIND_USERINFO *info;
+ uint32 num_entries = 0, total_entries = 0;
+ char *ted, *extra_data = NULL;
+ int extra_data_len = 0;
+ TALLOC_CTX *mem_ctx;
+ enum winbindd_result rv = WINBINDD_ERROR;
+
+ DEBUG(3, ("[%5d]: list users\n", state->pid));
+
+ if (!(mem_ctx = talloc_init()))
+ return WINBINDD_ERROR;
+
+ /* Enumerate over trusted domains */
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ for (domain = domain_list; domain; domain = domain->next) {
+ NTSTATUS status;
+ struct winbindd_methods *methods;
+ int i;
+
+ /* Skip domains other than WINBINDD_DOMAIN environment
+ variable */
+
+ if ((strcmp(state->request.domain, "") != 0) &&
+ !check_domain_env(state->request.domain, domain->name))
+ continue;
+
+ methods = domain->methods;
+
+ /* Query display info */
+ status = methods->query_user_list(domain, mem_ctx,
+ &num_entries, &info);
+
+ if (num_entries == 0)
+ continue;
+
+ /* Allocate some memory for extra data */
+ total_entries += num_entries;
+
+ ted = Realloc(extra_data, sizeof(fstring) * total_entries);
+
+ if (!ted) {
+ DEBUG(0,("winbindd_list_users: failed to enlarge buffer!\n"));
+ SAFE_FREE(extra_data);
+ goto done;
+ } else
+ extra_data = ted;
+
+ /* Pack user list into extra data fields */
+
+ for (i = 0; i < num_entries; i++) {
+ fstring acct_name, name;
+
+ if (!info[i].acct_name) {
+ fstrcpy(acct_name, "");
+ } else {
+ fstrcpy(acct_name, info[i].acct_name);
+ }
+
+ slprintf(name, sizeof(name) - 1, "%s%s%s",
+ domain->name, lp_winbind_separator(),
+ acct_name);
+
+ /* Append to extra data */
+ memcpy(&extra_data[extra_data_len], name,
+ strlen(name));
+ extra_data_len += strlen(name);
+ extra_data[extra_data_len++] = ',';
+ }
+ }
+
+ /* Assign extra_data fields in response structure */
+
+ if (extra_data) {
+ extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ /* No domains responded but that's still OK so don't return an
+ error. */
+
+ rv = WINBINDD_OK;
+
+ done:
+
+ talloc_destroy(mem_ctx);
+
+ return rv;
+}
diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c
new file mode 100644
index 00000000000..2f21f81ea87
--- /dev/null
+++ b/source/nsswitch/winbindd_util.c
@@ -0,0 +1,324 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Winbind daemon for ntdom nss module
+
+ Copyright (C) Tim Potter 2000-2001
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+#include "sids.h"
+
+/**
+ * @file winbindd_util.c
+ *
+ * Winbind daemon for NT domain authentication nss module.
+ **/
+
+
+/**
+ * Used to clobber name fields that have an undefined value.
+ *
+ * Correct code should never look at a field that has this value.
+ **/
+static const fstring name_deadbeef = "<deadbeef>";
+
+
+/* Globals for domain list stuff */
+struct winbindd_domain *domain_list = NULL;
+
+/* Given a domain name, return the struct winbindd domain info for it
+ if it is actually working. */
+
+struct winbindd_domain *find_domain_from_name(char *domain_name)
+{
+ struct winbindd_domain *tmp;
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ /* Search through list */
+
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ if (strcasecmp(domain_name, tmp->name) == 0 ||
+ strcasecmp(domain_name, tmp->full_name) == 0)
+ return tmp;
+ }
+
+ /* Not found */
+
+ return NULL;
+}
+
+/* Given a domain sid, return the struct winbindd domain info for it */
+
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
+{
+ struct winbindd_domain *tmp;
+
+ if (domain_list == NULL)
+ get_domain_info();
+
+ /* Search through list */
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ if (sid_compare_domain(sid, &tmp->sid) == 0)
+ return tmp;
+ }
+
+ /* Not found */
+
+ return NULL;
+}
+
+/* Add a trusted domain to our list of domains */
+
+static struct winbindd_domain *add_trusted_domain(char *domain_name,
+ struct winbindd_methods *methods)
+{
+ struct winbindd_domain *domain, *tmp;
+
+ for (tmp = domain_list; tmp != NULL; tmp = tmp->next) {
+ if (strcmp(domain_name, tmp->name) == 0) {
+ DEBUG(3, ("domain %s already in domain list\n", domain_name));
+ return tmp;
+ }
+ }
+
+ /* Create new domain entry */
+ if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL)
+ return NULL;
+
+ /* Fill in fields */
+
+ ZERO_STRUCTP(domain);
+ fstrcpy(domain->name, domain_name);
+ domain->methods = methods;
+ domain->sequence_number = DOM_SEQUENCE_NONE;
+ domain->last_seq_check = 0;
+
+ /* Link to domain list */
+
+ DLIST_ADD(domain_list, domain);
+
+ return domain;
+}
+
+/* Look up global info for the winbind daemon */
+
+BOOL get_domain_info(void)
+{
+ NTSTATUS result;
+ TALLOC_CTX *mem_ctx;
+ extern struct winbindd_methods cache_methods;
+ struct winbindd_domain *domain;
+ DOM_SID *dom_sids;
+ char **names;
+ int num_domains = 0;
+
+ if (!(mem_ctx = talloc_init()))
+ return False;
+
+ domain = add_trusted_domain(lp_workgroup(), &cache_methods);
+
+ /* now we *must* get the domain sid for our primary domain. Go into a holding
+ pattern until that is available */
+ result = cache_methods.domain_sid(domain, &domain->sid);
+ while (!NT_STATUS_IS_OK(result)) {
+ sleep(10);
+ DEBUG(1,("Retrying startup domain sid fetch for %s\n",
+ domain->name));
+ result = cache_methods.domain_sid(domain, &domain->sid);
+ }
+
+ DEBUG(1,("Added domain %s (%s)\n",
+ domain->name,
+ sid_string_static(&domain->sid)));
+
+ DEBUG(1, ("getting trusted domain list\n"));
+
+ result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains,
+ &names, &dom_sids);
+
+ /* Add each domain to the trusted domain list */
+ if (NT_STATUS_IS_OK(result)) {
+ int i;
+ for(i = 0; i < num_domains; i++) {
+ domain = add_trusted_domain(names[i], &cache_methods);
+ if (domain) {
+ sid_copy(&domain->sid, &dom_sids[i]);
+ }
+ DEBUG(1,("Added domain %s (%s)\n",
+ domain->name,
+ sid_string_static(&domain->sid)));
+
+ /* this primes the connection */
+ cache_methods.domain_sid(domain, &domain->sid);
+ }
+ }
+
+ talloc_destroy(mem_ctx);
+ return True;
+}
+
+
+/* Lookup a sid in a domain from a name */
+BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain,
+ const char *name, DOM_SID *sid, enum SID_NAME_USE *type)
+{
+ NTSTATUS result;
+
+ /* Don't bother with machine accounts */
+
+ if (name[strlen(name) - 1] == '$')
+ return False;
+
+ /* Lookup name */
+ result = domain->methods->name_to_sid(domain, name, sid, type);
+
+ /* Return rid and type if lookup successful */
+ if (!NT_STATUS_IS_OK(result)) {
+ *type = SID_NAME_UNKNOWN;
+ }
+
+ return NT_STATUS_IS_OK(result);
+}
+
+/**
+ * @brief Lookup a name in a domain from a sid.
+ *
+ * @param sid Security ID you want to look up.
+ *
+ * @param name On success, set to the name corresponding to @p sid.
+ *
+ * @param type On success, contains the type of name: alias, group or
+ * user.
+ *
+ * @retval True if the name exists, in which case @p name and @p type
+ * are set, otherwise False.
+ **/
+BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
+ fstring name,
+ enum SID_NAME_USE *type)
+{
+ char *names;
+ NTSTATUS result;
+ TALLOC_CTX *mem_ctx;
+ BOOL rv = False;
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_sid(sid);
+ if (!domain) {
+ DEBUG(1,("Can't find domain from sid\n"));
+ return False;
+ }
+
+ /* Lookup name */
+
+ if (!(mem_ctx = talloc_init()))
+ return False;
+
+ result = domain->methods->sid_to_name(domain, mem_ctx, sid, &names, type);
+
+ /* Return name and type if successful */
+
+ if ((rv = NT_STATUS_IS_OK(result))) {
+ fstrcpy(name, names);
+ } else {
+ *type = SID_NAME_UNKNOWN;
+ fstrcpy(name, name_deadbeef);
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return rv;
+}
+
+
+/* Free state information held for {set,get,end}{pw,gr}ent() functions */
+
+void free_getent_state(struct getent_state *state)
+{
+ struct getent_state *temp;
+
+ /* Iterate over state list */
+
+ temp = state;
+
+ while(temp != NULL) {
+ struct getent_state *next;
+
+ /* Free sam entries then list entry */
+
+ SAFE_FREE(state->sam_entries);
+ DLIST_REMOVE(state, state);
+ next = temp->next;
+
+ SAFE_FREE(temp);
+ temp = next;
+ }
+}
+
+/* Initialise trusted domain info */
+
+BOOL winbindd_param_init(void)
+{
+ /* Parse winbind uid and winbind_gid parameters */
+
+ if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) {
+ DEBUG(0, ("winbind uid range missing or invalid\n"));
+ return False;
+ }
+
+ if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) {
+ DEBUG(0, ("winbind gid range missing or invalid\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/* Check if a domain is present in a comma-separated list of domains */
+
+BOOL check_domain_env(char *domain_env, char *domain)
+{
+ fstring name;
+ char *tmp = domain_env;
+
+ while(next_token(&tmp, name, ",", sizeof(fstring))) {
+ if (strequal(name, domain))
+ return True;
+ }
+
+ return False;
+}
+
+/* Parse a string of the form DOMAIN/user into a domain and a user */
+
+BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
+{
+ char *p = strchr(domuser,*lp_winbind_separator());
+
+ if (!p)
+ return False;
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+ strupper(domain);
+ return True;
+}
diff --git a/source/nsswitch/wins.c b/source/nsswitch/wins.c
new file mode 100644
index 00000000000..0ab09548125
--- /dev/null
+++ b/source/nsswitch/wins.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ a WINS nsswitch module
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+#ifdef HAVE_NS_API_H
+#undef VOLATILE
+
+#include <ns_daemon.h>
+#define NSD_LOGLEVEL NSD_LOG_MIN
+#endif
+
+#ifndef INADDRSZ
+#define INADDRSZ 4
+#endif
+
+static int initialised;
+
+
+/* Use our own create socket code so we don't recurse.... */
+
+static int wins_lookup_open_socket_in(void)
+{
+ struct sockaddr_in sock;
+ int val=1;
+ int res;
+
+ memset((char *)&sock,'\0',sizeof(sock));
+
+#ifdef HAVE_SOCK_SIN_LEN
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = 0;
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
+ res = socket(AF_INET, SOCK_DGRAM, 0);
+ if (res == -1)
+ return -1;
+
+ setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
+#ifdef SO_REUSEPORT
+ setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
+#endif /* SO_REUSEPORT */
+
+ /* now we've got a socket - we need to bind it */
+
+ if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0)
+ return(-1);
+
+ return res;
+}
+
+
+static void nss_wins_init(void)
+{
+ initialised = 1;
+ DEBUGLEVEL = 0;
+
+ setup_logging("nss_wins",False);
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+}
+
+static struct in_addr *lookup_backend(const char *name, int *count)
+{
+ int fd;
+ struct in_addr *ret = NULL;
+ struct in_addr p;
+ int j;
+
+ if (!initialised) {
+ nss_wins_init();
+ }
+
+ *count = 0;
+
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1)
+ return NULL;
+
+ set_socket_options(fd,"SO_BROADCAST");
+
+/* The next four lines commented out by JHT
+ and replaced with the four lines following */
+/* if( !is_zero_ip( wins_ip ) ) {
+ * ret = name_query( fd, name, 0x20, False, True, wins_src_ip(), count );
+ * goto out;
+ * }
+ */
+ p = wins_srv_ip();
+ if( !is_zero_ip(p) ) {
+ ret = name_query(fd,name,0x20,False,True, p, count);
+ goto out;
+ }
+
+ if (lp_wins_support()) {
+ /* we are our own WINS server */
+ ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count);
+ goto out;
+ }
+
+ /* uggh, we have to broadcast to each interface in turn */
+ for (j=iface_count() - 1;
+ j >= 0;
+ j--) {
+ struct in_addr *bcast = iface_n_bcast(j);
+ ret = name_query(fd,name,0x20,True,True,*bcast,count);
+ if (ret) break;
+ }
+
+ out:
+
+ close(fd);
+ return ret;
+}
+
+
+/****************************************************************************
+gethostbyname() - we ignore any domain portion of the name and only
+handle names that are at most 15 characters long
+ **************************************************************************/
+#ifdef HAVE_NS_API_H
+/* IRIX version */
+
+int init(void)
+{
+ nsd_logprintf(NSD_LOGLEVEL, "init (wins)\n");
+ nss_wins_init();
+ return NSD_OK;
+}
+
+int lookup(nsd_file_t *rq)
+{
+ char *map;
+ char *key;
+ struct in_addr *ip_list;
+ int count;
+ char response[80];
+
+ nsd_logprintf(NSD_LOGLEVEL, "lookup (wins)\n");
+ if (! rq)
+ return NSD_ERROR;
+
+ map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
+ if (! map) {
+ rq->f_status = NS_FATAL;
+ return NSD_ERROR;
+ }
+
+ if (strcasecmp(map,"hosts.byname") != 0) {
+ rq->f_status = NS_NOTFOUND;
+ return NSD_NEXT;
+ }
+
+ key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
+ if (! key || ! *key) {
+ rq->f_status = NS_FATAL;
+ return NSD_ERROR;
+ }
+
+ ip_list = lookup_backend(key, &count);
+
+ if (!ip_list) {
+ rq->f_status = NSS_STATUS_NOTFOUND;
+ return NSD_NEXT;
+ }
+ snprintf(response,79,"%s %s\n",inet_ntoa(*ip_list),key);
+ free(ip_list);
+
+ nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
+ return NSD_OK;
+}
+
+#else
+NSS_STATUS
+_nss_wins_gethostbyname_r(const char *name, struct hostent *he,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop)
+{
+ char **host_addresses;
+ struct in_addr *ip_list;
+ int i, count;
+ size_t namelen = strlen(name) + 1;
+
+ memset(he, '\0', sizeof(*he));
+
+ ip_list = lookup_backend(name, &count);
+ if (!ip_list) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (buflen < namelen + (2*count+1)*INADDRSZ) {
+ /* no ENOMEM error type?! */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+
+ host_addresses = (char **)buffer;
+ he->h_addr_list = host_addresses;
+ host_addresses[count] = NULL;
+ buffer += (count + 1) * INADDRSZ;
+ buflen += (count + 1) * INADDRSZ;
+ he->h_addrtype = AF_INET;
+ he->h_length = INADDRSZ;
+
+ for (i=0;i<count;i++) {
+ memcpy(buffer, &ip_list[i].s_addr, INADDRSZ);
+ *host_addresses = buffer;
+ buffer += INADDRSZ;
+ buflen -= INADDRSZ;
+ host_addresses++;
+ }
+
+ if (ip_list)
+ free(ip_list);
+
+ memcpy(buffer, name, namelen);
+ he->h_name = buffer;
+
+ return NSS_STATUS_SUCCESS;
+}
+#endif
+
diff --git a/source/pam_smbpass/CHANGELOG b/source/pam_smbpass/CHANGELOG
new file mode 100644
index 00000000000..96ef7840084
--- /dev/null
+++ b/source/pam_smbpass/CHANGELOG
@@ -0,0 +1,31 @@
+version 0.7.5 25 Mar 2001
+ - Use Samba 2.2.0 (alpha) as the target codebase, since it doesn't look
+ like Samba will be offering shared libraries in the near future.
+ - added a Makefile and support scripts to make the build process easier.
+ - imported some Solaris fixes that I've been sitting on.
+
+version 0.7.4 20 Jan 2000
+ - added a 'migrate' option to the authentication code which makes no
+ effort to authenticate the user, or even to ask for a password, but
+ it can be useful for filling in an SMB password db.
+
+version 0.7.3 19 Jan 2000
+ - updated to use the SAMBA_TNG Samba branch, allowing us to dynamically
+ link against Luke's new shared libs (libsamba, libsmb).
+
+version 0.7.2 20 Jul 1999
+ - miscellaneous bugfixes. Cleanup of legacy pam_pwdb code.
+ - fixed return value of pam_sm_setcred function.
+ - fix to autoconf support
+ - clarified some of the messages being logged
+
+version 0.6, 15 Jul 1999
+ - updated to use the new Samba (2.0) password database API.
+ - added autoconf support. May now theoretically compile on more
+ platforms than PAM itself does.
+ - added support for account management functions (i.e., disabled
+ accounts)
+
+version 0.5, 4 Apr 1998
+ - added support for hashed passwords as input. Now capable of serving
+ as an authentication agent for encrypted network transactions.
diff --git a/source/pam_smbpass/README b/source/pam_smbpass/README
new file mode 100644
index 00000000000..2a9641c5d76
--- /dev/null
+++ b/source/pam_smbpass/README
@@ -0,0 +1,66 @@
+25 Mar 2001
+
+pam_smbpass is a PAM module which can be used on conforming systems to
+keep the smbpasswd (Samba password) database in sync with the unix
+password file. PAM (Pluggable Authentication Modules) is an API supported
+under some Unices, such as Solaris, HPUX and Linux, that provides a
+generic interface to authentication mechanisms.
+
+For more information on PAM, see http://ftp.kernel.org/pub/linux/libs/pam/
+
+This module authenticates a local smbpasswd user database. If you require
+support for authenticating against a remote SMB server, or if you're
+concerned about the presence of suid root binaries on your system, it is
+recommended that you use one of the other two following modules
+
+ pam_smb - http://www.csn.ul.ie/~airlied/pam_smb/
+ authenticates against any remote SMB server
+
+ pam_ntdom - ftp://ftp.samba.org/pub/samba/pam_ntdom/
+ authenticates against an NT or Samba domain controller
+
+Options recognized by this module are as follows:
+
+ debug - log more debugging info
+ audit - like debug, but also logs unknown usernames
+ use_first_pass - don't prompt the user for passwords;
+ take them from PAM_ items instead
+ try_first_pass - try to get the password from a previous
+ PAM module, fall back to prompting the user
+ use_authtok - like try_first_pass, but *fail* if the new
+ PAM_AUTHTOK has not been previously set.
+ (intended for stacking password modules only)
+ not_set_pass - don't make passwords used by this module
+ available to other modules.
+ nodelay - don't insert ~1 second delays on authentication
+ failure.
+ nullok - null passwords are allowed.
+ nonull - null passwords are not allowed. Used to
+ override the Samba configuration.
+ migrate - only meaningful in an "auth" context;
+ used to update smbpasswd file with a
+ password used for successful authentication.
+ smbconf=<file> - specify an alternate path to the smb.conf
+ file.
+
+See the samples/ directory for example PAM configurations using this
+module.
+
+Thanks go to the following people:
+
+* Andrew Morgan <morgan@transmeta.com>, for providing the Linux-PAM
+framework, without which none of this would have happened
+
+* Christian Gafton <gafton@redhat.com> and Andrew Morgan again, for the
+pam_pwdb module upon which pam_smbpass was originally based
+
+* Luke Leighton <lkcl@switchboard.net> for being receptive to the idea,
+and for the occasional good-natured complaint about the project's status
+that keep me working on it :)
+
+* and of course, all the other members of the Samba team
+<samba@samba.org>, for creating a great product and for giving this
+project a purpose
+
+---------------------
+Stephen Langasek <vorlon@netexpress.net>
diff --git a/source/pam_smbpass/TODO b/source/pam_smbpass/TODO
new file mode 100644
index 00000000000..20cf4fb0987
--- /dev/null
+++ b/source/pam_smbpass/TODO
@@ -0,0 +1,7 @@
+This is a tentative TODO file which will probably get much longer before
+it gets much shorter.
+
+- Recognizing (and overriding) debug options in the smb.conf file
+- Support for 'name=value' parameters in the PAM config
+- Compliant handling of unrecognized PAM parameters (i.e., fail on error)
+-
diff --git a/source/pam_smbpass/general.h b/source/pam_smbpass/general.h
new file mode 100644
index 00000000000..0291146cbba
--- /dev/null
+++ b/source/pam_smbpass/general.h
@@ -0,0 +1,123 @@
+#ifndef LINUX
+/* This is only needed by modules in the Sun implementation. */
+#include <security/pam_appl.h>
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#ifndef PAM_AUTHTOK_RECOVER_ERR
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+/*
+ * here is the string to inform the user that the new passwords they
+ * typed were not the same.
+ */
+
+#define MISTYPED_PASS "Sorry, passwords do not match"
+
+/* type definition for the control options */
+
+typedef struct {
+ const char *token;
+ unsigned int mask; /* shall assume 32 bits of flags */
+ unsigned int flag;
+} SMB_Ctrls;
+
+#ifndef False
+#define False (0)
+#endif
+
+#ifndef True
+#define True (1)
+#endif
+
+/* macro to determine if a given flag is on */
+#define on(x,ctrl) (smb_args[x].flag & ctrl)
+
+/* macro to determine that a given flag is NOT on */
+#define off(x,ctrl) (!on(x,ctrl))
+
+/* macro to turn on/off a ctrl flag manually */
+#define set(x,ctrl) (ctrl = ((ctrl)&smb_args[x].mask)|smb_args[x].flag)
+#define unset(x,ctrl) (ctrl &= ~(smb_args[x].flag))
+
+#ifndef __linux__
+#define strncasecmp(s1,s2,n) StrnCaseCmp(s1,s2,n)
+#endif
+
+/* the generic mask */
+#define _ALL_ON_ (~0U)
+
+/* end of macro definitions definitions for the control flags */
+
+/*
+ * These are the options supported by the smb password module, very
+ * similar to the pwdb options
+ */
+
+#define SMB__OLD_PASSWD 0 /* internal */
+#define SMB__VERIFY_PASSWD 1 /* internal */
+
+#define SMB_AUDIT 2 /* print more things than debug..
+ some information may be sensitive */
+#define SMB_USE_FIRST_PASS 3
+#define SMB_TRY_FIRST_PASS 4
+#define SMB_NOT_SET_PASS 5 /* don't set the AUTHTOK items */
+
+#define SMB__NONULL 6 /* internal */
+#define SMB__QUIET 7 /* internal */
+#define SMB_USE_AUTHTOK 8 /* insist on reading PAM_AUTHTOK */
+#define SMB__NULLOK 9 /* Null token ok */
+#define SMB_DEBUG 10 /* send more info to syslog(3) */
+#define SMB_NODELAY 11 /* admin does not want a fail-delay */
+#define SMB_MIGRATE 12 /* Does no authentication, just
+ updates the smb database. */
+#define SMB_CONF_FILE 13 /* Alternate location of smb.conf */
+
+#define SMB_CTRLS_ 14 /* number of ctrl arguments defined */
+
+static const SMB_Ctrls smb_args[SMB_CTRLS_] = {
+/* symbol token name ctrl mask ctrl *
+ * ------------------ ------------------ -------------- ---------- */
+
+/* SMB__OLD_PASSWD */ { NULL, _ALL_ON_, 01 },
+/* SMB__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 },
+/* SMB_AUDIT */ { "audit", _ALL_ON_, 04 },
+/* SMB_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(030), 010 },
+/* SMB_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(030), 020 },
+/* SMB_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 040 },
+/* SMB__NONULL */ { "nonull", _ALL_ON_, 0100 },
+/* SMB__QUIET */ { NULL, _ALL_ON_, 0200 },
+/* SMB_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 0400 },
+/* SMB__NULLOK */ { "nullok", _ALL_ON_^(0100), 0 },
+/* SMB_DEBUG */ { "debug", _ALL_ON_, 01000 },
+/* SMB_NODELAY */ { "nodelay", _ALL_ON_, 02000 },
+/* SMB_MIGRATE */ { "migrate", _ALL_ON_^(0100), 04000 },
+/* SMB_CONF_FILE */ { "smbconf=", _ALL_ON_, 0 },
+};
+
+#define SMB_DEFAULTS (smb_args[SMB__NONULL].flag)
+
+/*
+ * the following is used to keep track of the number of times a user fails
+ * to authenticate themself.
+ */
+
+#define FAIL_PREFIX "-SMB-FAIL-"
+#define SMB_MAX_RETRIES 3
+
+struct _pam_failed_auth {
+ char *user; /* user that's failed to be authenticated */
+ int id; /* uid of requested user */
+ char *agent; /* attempt from user with name */
+ int count; /* number of failures so far */
+};
diff --git a/source/pam_smbpass/pam_smb_acct.c b/source/pam_smbpass/pam_smb_acct.c
new file mode 100644
index 00000000000..8ed3ad7eda2
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_acct.c
@@ -0,0 +1,112 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_ACCT
+
+#include "includes.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+/*
+ * pam_sm_acct_mgmt() verifies whether or not the account is disabled.
+ *
+ */
+
+int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags,
+ int argc, const char **argv )
+{
+ unsigned int ctrl;
+ int retval;
+
+ const char *name;
+ const char *p;
+ struct smb_passwd *smb_pwent = NULL;
+
+ extern BOOL in_client;
+
+ /* Samba initialization. */
+ setup_logging( "pam_smbpass", False );
+ in_client = True;
+
+ ctrl = set_ctrl( flags, argc, argv );
+
+ /* get the username */
+
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: username [%s] obtained", name );
+ }
+
+ if (!initialize_password_db(True)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* Get the user's record. */
+ smb_pwent = getsmbpwnam( name );
+
+ if (!smb_pwent)
+ return PAM_USER_UNKNOWN;
+
+ if (smb_pwent->acct_ctrl & ACB_DISABLED) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG
+ , "acct: account %s is administratively disabled", name );
+ }
+ make_remark( pamh, ctrl, PAM_ERROR_MSG
+ , "Your account has been disabled; "
+ "please see your system administrator." );
+
+ return PAM_ACCT_EXPIRED;
+ }
+
+ /* TODO: support for expired passwords. */
+
+ return PAM_SUCCESS;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_acct_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/source/pam_smbpass/pam_smb_auth.c b/source/pam_smbpass/pam_smb_auth.c
new file mode 100644
index 00000000000..4b56b2b3019
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_auth.c
@@ -0,0 +1,245 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_AUTH
+
+#include "includes.h"
+#include "debug.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+#define AUTH_RETURN \
+do { \
+ if(ret_data) { \
+ *ret_data = retval; \
+ pam_set_data( pamh, "smb_setcred_return" \
+ , (void *) ret_data, NULL ); \
+ } \
+ return retval; \
+} while (0)
+
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct smb_passwd *smb_pwent);
+
+/*
+ * pam_sm_authenticate() authenticates users against the samba password file.
+ *
+ * First, obtain the password from the user. Then use a
+ * routine in 'support.c' to authenticate the user.
+ */
+
+#define _SMB_AUTHTOK "-SMB-PASS"
+
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval, *ret_data = NULL;
+
+ const char *name;
+
+ /* Points to memory managed by the PAM library. Do not free. */
+ const char *p = NULL;
+
+ struct smb_passwd *smb_pwent = NULL;
+
+ extern BOOL in_client;
+
+ /* Samba initialization. */
+ setup_logging("pam_smbpass",False);
+ in_client = True;
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /* Get a few bytes so we can pass our return value to
+ pam_sm_setcred(). Used in AUTH_RETURN macro */
+ ret_data = malloc(sizeof(int));
+
+ /* get the username */
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if ( retval != PAM_SUCCESS ) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err(LOG_DEBUG, "auth: could not identify user");
+ }
+ AUTH_RETURN;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", name );
+ }
+
+ if (!initialize_password_db(True)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ retval = PAM_AUTHINFO_UNAVAIL;
+ AUTH_RETURN;
+ }
+
+ smb_pwent = getsmbpwnam( name );
+
+ if (on( SMB_MIGRATE, ctrl )) {
+ retval = _smb_add_user(pamh, ctrl, name, smb_pwent);
+ AUTH_RETURN;
+ }
+
+ if (smb_pwent == NULL) {
+ _log_err(LOG_ALERT, "Failed to find entry for user %s.", name);
+ retval = PAM_USER_UNKNOWN;
+ AUTH_RETURN;
+ }
+
+ /* if this user does not have a password... */
+
+ if (_smb_blankpasswd( ctrl, smb_pwent )) {
+ smb_pwent = NULL;
+ retval = PAM_SUCCESS;
+ AUTH_RETURN;
+ }
+
+ /* get this user's authentication token */
+
+ retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL
+ , _SMB_AUTHTOK, &p);
+ if (retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "auth: no password provided for [%s]"
+ , name);
+ smb_pwent = NULL;
+ AUTH_RETURN;
+ }
+
+ /* verify the password of this user */
+
+ retval = _smb_verify_password( pamh, smb_pwent, p, ctrl );
+ smb_pwent = NULL;
+ p = NULL;
+ AUTH_RETURN;
+}
+
+/*
+ * This function is for setting samba credentials. If anyone comes up
+ * with any credentials they think should be set, let me know.
+ */
+
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval, *pretval = NULL;
+
+ retval = PAM_SUCCESS;
+
+ pam_get_data(pamh, "smb_setcred_return", (const void **) &pretval);
+ if(pretval) {
+ retval = *pretval;
+ free(pretval);
+ }
+ pam_set_data(pamh, "smb_setcred_return", NULL, NULL);
+
+ return retval;
+}
+
+
+/* Helper function for adding a user to the db. */
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct smb_passwd *smb_pwent)
+{
+ pstring err_str;
+ pstring msg_str;
+ const char *pass = NULL;
+ int retval;
+
+ err_str[0] = '\0';
+ msg_str[0] = '\0';
+
+ /* Get the authtok; if we don't have one, silently fail. */
+ retval = pam_get_item( pamh, PAM_AUTHTOK, (const void **) &pass );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_ALERT
+ , "pam_get_item returned error to pam_sm_authenticate" );
+ return PAM_AUTHTOK_RECOVER_ERR;
+ } else if (pass == NULL) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+
+ /* Add the user to the db if they aren't already there. */
+ if (smb_pwent == NULL) {
+ retval = local_password_change( name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD,
+ pass, err_str,
+ sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+ if (!retval && *err_str)
+ {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+ else if (*msg_str)
+ {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ pass = NULL;
+
+ return PAM_IGNORE;
+ }
+
+ /* Change the user's password IFF it's null. */
+ if (smb_pwent->smb_passwd == NULL && (smb_pwent->acct_ctrl & ACB_PWNOTREQ))
+ {
+ retval = local_password_change( name, LOCAL_SET_PASSWORD,
+ pass, err_str,
+ sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+ if (!retval && *err_str)
+ {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+ else if (*msg_str)
+ {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ }
+ pass = NULL;
+
+ return PAM_IGNORE;
+}
+
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_auth_modstruct = {
+ "pam_smbpass",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/source/pam_smbpass/pam_smb_passwd.c b/source/pam_smbpass/pam_smb_passwd.c
new file mode 100644
index 00000000000..8c207cee0df
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_passwd.c
@@ -0,0 +1,313 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_PASSWORD
+
+#include "includes.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user
+ , const char *pass_new )
+{
+ char c;
+ int retval, i;
+ pstring err_str;
+ pstring msg_str;
+
+ err_str[0] = '\0';
+ msg_str[0] = '\0';
+
+ retval = local_password_change( user, LOCAL_SET_PASSWORD, pass_new, err_str, sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+
+ if (!retval) {
+ if (*err_str) {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+
+ /* FIXME: what value is appropriate here? */
+ retval = PAM_AUTHTOK_ERR;
+ } else {
+ if (*msg_str) {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ retval = PAM_SUCCESS;
+ }
+
+ return retval;
+
+}
+
+
+/* data tokens */
+
+#define _SMB_OLD_AUTHTOK "-SMB-OLD-PASS"
+#define _SMB_NEW_AUTHTOK "-SMB-NEW-PASS"
+
+/*
+ * FUNCTION: pam_sm_chauthtok()
+ *
+ * This function is called twice by the PAM library, once with
+ * PAM_PRELIM_CHECK set, and then again with PAM_UPDATE_AUTHTOK set. With
+ * Linux-PAM, these two passes generally involve first checking the old
+ * token and then changing the token. This is what we do here.
+ *
+ * Having obtained a new password. The function updates the
+ * SMB_PASSWD_FILE file (normally, $(LIBDIR)/smbpasswd).
+ */
+
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ extern BOOL in_client;
+
+ struct smb_passwd *smb_pwent=NULL;
+ const char *user;
+ const char *pass_old, *pass_new;
+
+ /* Samba initialization. */
+ setup_logging( "pam_smbpass", False );
+ in_client = True;
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /*
+ * First get the name of a user. No need to do anything if we can't
+ * determine this.
+ */
+
+ retval = pam_get_user( pamh, &user, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "password: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", user );
+ }
+
+ if (!initialize_password_db(True)) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* obtain user record */
+ smb_pwent = getsmbpwnam(user);
+
+ if (smb_pwent == NULL) {
+ _log_err( LOG_ALERT, "Failed to find entry for user %s.", user );
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (flags & PAM_PRELIM_CHECK) {
+ /*
+ * obtain and verify the current password (OLDAUTHTOK) for
+ * the user.
+ */
+
+ char *Announce;
+
+ if (_smb_blankpasswd( ctrl, smb_pwent )) {
+
+ return PAM_SUCCESS;
+
+ }
+
+ /* Password change by root, or for an expired token, doesn't
+ require authentication. Is this a good choice? */
+ if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
+
+ /* tell user what is happening */
+#define greeting "Changing password for "
+ Announce = (char *) malloc(sizeof(greeting)+strlen(user));
+ if (Announce == NULL) {
+ _log_err(LOG_CRIT, "password: out of memory");
+ return PAM_BUF_ERR;
+ }
+ strncpy( Announce, greeting, sizeof(greeting) );
+ strncpy( Announce+sizeof(greeting)-1, user, strlen(user)+1 );
+#undef greeting
+
+ set( SMB__OLD_PASSWD, ctrl );
+ retval = _smb_read_password( pamh, ctrl
+ , Announce
+ , "Current SMB password: "
+ , NULL
+ , _SMB_OLD_AUTHTOK
+ , &pass_old );
+ free( Announce );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE
+ , "password - (old) token not obtained" );
+ return retval;
+ }
+
+ /* verify that this is the password for this user */
+
+ retval = _smb_verify_password( pamh, smb_pwent, pass_old, ctrl );
+
+ } else {
+ pass_old = NULL;
+ retval = PAM_SUCCESS; /* root doesn't have to */
+ }
+
+ pass_old = NULL;
+ return retval;
+
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+
+ if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
+ /* NOTE: there is currently no support for password expiring
+ under Samba. Support will be added here when it becomes
+ available. */
+ return PAM_SUCCESS;
+ }
+ /*
+ * obtain the proposed password
+ */
+
+ /*
+ * get the old token back. NULL was ok only if root [at this
+ * point we assume that this has already been enforced on a
+ * previous call to this function].
+ */
+
+ if (off( SMB_NOT_SET_PASS, ctrl )) {
+ retval = pam_get_item( pamh, PAM_OLDAUTHTOK,
+ (const void **)&pass_old );
+ } else {
+ retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK,
+ (const void **)&pass_old );
+ if (retval == PAM_NO_MODULE_DATA) {
+ pass_old = NULL;
+ retval = PAM_SUCCESS;
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE, "password: user not authenticated" );
+ return retval;
+ }
+
+ /*
+ * use_authtok is to force the use of a previously entered
+ * password -- needed for pluggable password strength checking
+ * or other module stacking
+ */
+
+ if (on( SMB_USE_AUTHTOK, ctrl )) {
+ set( SMB_USE_FIRST_PASS, ctrl );
+ }
+
+ retval = _smb_read_password( pamh, ctrl
+ , NULL
+ , "Enter new SMB password: "
+ , "Retype new SMB password: "
+ , _SMB_NEW_AUTHTOK
+ , &pass_new );
+
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_ALERT
+ , "password: new password not obtained" );
+ }
+ pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ /*
+ * At this point we know who the user is and what they
+ * propose as their new password. Verify that the new
+ * password is acceptable.
+ */
+
+ if (pass_new[0] == '\0') { /* "\0" password = NULL */
+ pass_new = NULL;
+ }
+
+ retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);
+
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "new password not acceptable");
+ pass_new = pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ /*
+ * By reaching here we have approved the passwords and must now
+ * rebuild the smb password file.
+ */
+
+ /* update the password database */
+
+ retval = smb_update_db(pamh, ctrl, user, pass_new);
+ if (retval == PAM_SUCCESS) {
+ /* password updated */
+ _log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)"
+ , user, smb_pwent->smb_userid, uidtoname( getuid() )
+ , getuid() );
+ } else {
+ _log_err( LOG_ERR, "password change failed for user %s"
+ , user );
+ }
+
+ pass_old = pass_new = NULL;
+ smb_pwent = NULL;
+
+ } else { /* something has broken with the library */
+
+ _log_err( LOG_ALERT, "password received unknown request" );
+ retval = PAM_ABORT;
+
+ }
+
+ return retval;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_passwd_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok
+};
+#endif
+
diff --git a/source/pam_smbpass/samples/README b/source/pam_smbpass/samples/README
new file mode 100644
index 00000000000..d77603306f1
--- /dev/null
+++ b/source/pam_smbpass/samples/README
@@ -0,0 +1,3 @@
+This directory contains example configurations demonstrating various uses
+of pam_smbpass. These examples use Linux-style /etc/pam.d syntax, and
+must be modified for use on Solaris systems.
diff --git a/source/pam_smbpass/samples/kdc-pdc b/source/pam_smbpass/samples/kdc-pdc
new file mode 100644
index 00000000000..70f1998f32a
--- /dev/null
+++ b/source/pam_smbpass/samples/kdc-pdc
@@ -0,0 +1,15 @@
+#%PAM-1.0
+# kdc-pdc
+#
+# A sample PAM configuration that shows pam_smbpass used together with
+# pam_krb5. This could be useful on a Samba PDC that is also a member of
+# a Kerberos realm.
+
+auth requisite pam_nologin.so
+auth requisite pam_krb5.so
+auth optional pam_smbpass.so migrate
+account required pam_krb5.so
+password requisite pam_cracklib.so retry=3
+password optional pam_smbpass.so nullok use_authtok try_first_pass
+password required pam_krb5.so use_authtok try_first_pass
+session required pam_krb5.so
diff --git a/source/pam_smbpass/samples/password-mature b/source/pam_smbpass/samples/password-mature
new file mode 100644
index 00000000000..6d73e0906fc
--- /dev/null
+++ b/source/pam_smbpass/samples/password-mature
@@ -0,0 +1,14 @@
+#%PAM-1.0
+# password-mature
+#
+# A sample PAM configuration for a 'mature' smbpasswd installation.
+# private/smbpasswd is fully populated, and we consider it an error if
+# the smbpasswd doesn't exist or doesn't match the Unix password.
+
+auth requisite pam_nologin.so
+auth required pam_unix.so
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password required pam_smbpass.so use_authtok use_first_pass
+session required pam_unix.so
diff --git a/source/pam_smbpass/samples/password-migration b/source/pam_smbpass/samples/password-migration
new file mode 100644
index 00000000000..305cb53858e
--- /dev/null
+++ b/source/pam_smbpass/samples/password-migration
@@ -0,0 +1,18 @@
+#%PAM-1.0
+# password-migration
+#
+# A sample PAM configuration that shows the use of pam_smbpass to migrate
+# from plaintext to encrypted passwords for Samba. Unlike other methods,
+# this can be used for users who have never connected to Samba shares:
+# password migration takes place when users ftp in, login using ssh, pop
+# their mail, etc.
+
+auth requisite pam_nologin.so
+# pam_smbpass is called IFF pam_unix succeeds.
+auth requisite pam_unix.so
+auth optional pam_smbpass.so migrate
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password optional pam_smbpass.so nullok use_authtok try_first_pass
+session required pam_unix.so
diff --git a/source/pam_smbpass/samples/password-sync b/source/pam_smbpass/samples/password-sync
new file mode 100644
index 00000000000..0a950dd2e9a
--- /dev/null
+++ b/source/pam_smbpass/samples/password-sync
@@ -0,0 +1,15 @@
+#%PAM-1.0
+# password-sync
+#
+# A sample PAM configuration that shows the use of pam_smbpass to make
+# sure private/smbpasswd is kept in sync when /etc/passwd (/etc/shadow)
+# is changed. Useful when an expired password might be changed by an
+# application (such as ssh).
+
+auth requisite pam_nologin.so
+auth required pam_unix.so
+account required pam_unix.so
+password requisite pam_cracklib.so retry=3
+password requisite pam_unix.so shadow md5 use_authtok try_first_pass
+password required pam_smbpass.so nullok use_authtok try_first_pass
+session required pam_unix.so
diff --git a/source/pam_smbpass/support.c b/source/pam_smbpass/support.c
new file mode 100644
index 00000000000..f35a354b7c0
--- /dev/null
+++ b/source/pam_smbpass/support.c
@@ -0,0 +1,624 @@
+/* Unix NT password database implementation, version 0.6.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "general.h"
+
+#include "support.h"
+
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) \
+do { \
+ if (X) { \
+ free(X); \
+ X=NULL; \
+ } \
+} while (0)
+
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+
+int converse(pam_handle_t *, int, int, struct pam_message **,
+ struct pam_response **);
+int make_remark(pam_handle_t *, unsigned int, int, const char *);
+void _cleanup(pam_handle_t *, void *, int);
+char *_pam_delete(register char *);
+
+/* syslogging function for errors and other information */
+
+void _log_err( int err, const char *format, ... )
+{
+ va_list args;
+
+ va_start( args, format );
+ openlog( "PAM_smbpass", LOG_CONS | LOG_PID, LOG_AUTH );
+ vsyslog( err, format, args );
+ va_end( args );
+ closelog();
+}
+
+/* this is a front-end for module-application conversations */
+
+int converse( pam_handle_t * pamh, int ctrl, int nargs
+ , struct pam_message **message
+ , struct pam_response **response )
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
+ if (retval == PAM_SUCCESS) {
+
+ retval = conv->conv(nargs, (const struct pam_message **) message
+ ,response, conv->appdata_ptr);
+
+ if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) {
+ _log_err(LOG_DEBUG, "conversation failure [%s]"
+ ,pam_strerror(pamh, retval));
+ }
+ } else {
+ _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
+ ,pam_strerror(pamh, retval));
+ }
+
+ return retval; /* propagate error status */
+}
+
+int make_remark( pam_handle_t * pamh, unsigned int ctrl
+ , int type, const char *text )
+{
+ if (off(SMB__QUIET, ctrl)) {
+ struct pam_message *pmsg[1], msg[1];
+ struct pam_response *resp;
+
+ pmsg[0] = &msg[0];
+ msg[0].msg = text;
+ msg[0].msg_style = type;
+ resp = NULL;
+
+ return converse(pamh, ctrl, 1, pmsg, &resp);
+ }
+ return PAM_SUCCESS;
+}
+
+
+/* set the control flags for the SMB module. */
+
+int set_ctrl( int flags, int argc, const char **argv )
+{
+ int i = 0;
+ const char *service_file = dyn_CONFIGFILE;
+ unsigned int ctrl;
+
+ ctrl = SMB_DEFAULTS; /* the default selection of options */
+
+ /* set some flags manually */
+
+ /* A good, sane default (matches Samba's behavior). */
+ set( SMB__NONULL, ctrl );
+
+ if (flags & PAM_SILENT) {
+ set( SMB__QUIET, ctrl );
+ }
+
+ /* Run through the arguments once, looking for an alternate smb config
+ file location */
+ while (i < argc) {
+ int j;
+
+ for (j = 0; j < SMB_CTRLS_; ++j) {
+ if (smb_args[j].token
+ && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token)))
+ {
+ break;
+ }
+ }
+
+ if (j == SMB_CONF_FILE) {
+ service_file = argv[i] + 8;
+ }
+ i++;
+ }
+
+ /* Read some options from the Samba config. Can be overridden by
+ the PAM config. */
+ if(lp_load(service_file,True,False,False) == False) {
+ _log_err( LOG_ERR, "Error loading service file %s", service_file );
+ }
+
+ if (lp_null_passwords()) {
+ set( SMB__NULLOK, ctrl );
+ }
+
+ /* now parse the rest of the arguments to this module */
+
+ while (argc-- > 0) {
+ int j;
+
+ for (j = 0; j < SMB_CTRLS_; ++j) {
+ if (smb_args[j].token
+ && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token)))
+ {
+ break;
+ }
+ }
+
+ if (j >= SMB_CTRLS_) {
+ _log_err( LOG_ERR, "unrecognized option [%s]", *argv );
+ } else {
+ ctrl &= smb_args[j].mask; /* for turning things off */
+ ctrl |= smb_args[j].flag; /* for turning things on */
+ }
+
+ ++argv; /* step to next argument */
+ }
+
+ /* auditing is a more sensitive version of debug */
+
+ if (on( SMB_AUDIT, ctrl )) {
+ set( SMB_DEBUG, ctrl );
+ }
+ /* return the set of flags */
+
+ return ctrl;
+}
+
+/* use this to free strings. ESPECIALLY password strings */
+
+char * _pam_delete( register char *xx )
+{
+ _pam_overwrite( xx );
+ _pam_drop( xx );
+ return NULL;
+}
+
+void _cleanup( pam_handle_t * pamh, void *x, int error_status )
+{
+ x = _pam_delete( (char *) x );
+}
+
+/* ************************************************************** *
+ * Useful non-trivial functions *
+ * ************************************************************** */
+
+void _cleanup_failures( pam_handle_t * pamh, void *fl, int err )
+{
+ int quiet;
+ const char *service = NULL;
+ struct _pam_failed_auth *failure;
+
+#ifdef PAM_DATA_SILENT
+ quiet = err & PAM_DATA_SILENT; /* should we log something? */
+#else
+ quiet = 0;
+#endif
+#ifdef PAM_DATA_REPLACE
+ err &= PAM_DATA_REPLACE; /* are we just replacing data? */
+#endif
+ failure = (struct _pam_failed_auth *) fl;
+
+ if (failure != NULL) {
+
+#ifdef PAM_DATA_SILENT
+ if (!quiet && !err) { /* under advisement from Sun,may go away */
+#else
+ if (!quiet) { /* under advisement from Sun,may go away */
+#endif
+
+ /* log the number of authentication failures */
+ if (failure->count != 0) {
+ pam_get_item( pamh, PAM_SERVICE, (const void **) &service );
+ _log_err( LOG_NOTICE
+ , "%d authentication %s "
+ "from %s for service %s as %s(%d)"
+ , failure->count
+ , failure->count == 1 ? "failure" : "failures"
+ , failure->agent
+ , service == NULL ? "**unknown**" : service
+ , failure->user, failure->id );
+ if (failure->count > SMB_MAX_RETRIES) {
+ _log_err( LOG_ALERT
+ , "service(%s) ignoring max retries; %d > %d"
+ , service == NULL ? "**unknown**" : service
+ , failure->count
+ , SMB_MAX_RETRIES );
+ }
+ }
+ }
+ _pam_delete( failure->agent ); /* tidy up */
+ _pam_delete( failure->user ); /* tidy up */
+ free( failure );
+ }
+}
+
+int _smb_verify_password( pam_handle_t * pamh
+ , const struct smb_passwd *smb_pwent
+ , const char *p, unsigned int ctrl )
+{
+ uchar hash_pass[16];
+ uchar lm_pw[16];
+ uchar nt_pw[16];
+ int retval;
+ char *data_name;
+ const char *name;
+
+ if (!smb_pwent)
+ return PAM_ABORT;
+
+ name = smb_pwent->smb_name;
+
+#ifdef HAVE_PAM_FAIL_DELAY
+ if (off( SMB_NODELAY, ctrl )) {
+ (void) pam_fail_delay( pamh, 1000000 ); /* 1 sec delay for on failure */
+ }
+#endif
+
+ if (!smb_pwent->smb_passwd)
+ {
+ _log_err( LOG_DEBUG, "user %s has null SMB password"
+ , name );
+
+ if (off( SMB__NONULL, ctrl )
+ && (smb_pwent->acct_ctrl & ACB_PWNOTREQ))
+ { /* this means we've succeeded */
+ return PAM_SUCCESS;
+ } else {
+ const char *service;
+
+ pam_get_item( pamh, PAM_SERVICE, (const void **)&service );
+ _log_err( LOG_NOTICE
+ , "failed auth request by %s for service %s as %s(%d)"
+ , uidtoname( getuid() )
+ , service ? service : "**unknown**", name
+ , smb_pwent->smb_userid );
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ data_name = (char *) malloc( sizeof(FAIL_PREFIX)
+ + strlen( name ));
+ if (data_name == NULL) {
+ _log_err( LOG_CRIT, "no memory for data-name" );
+ }
+ strncpy( data_name, FAIL_PREFIX, sizeof(FAIL_PREFIX) );
+ strncpy( data_name + sizeof(FAIL_PREFIX) - 1, name, strlen( name ) + 1 );
+
+ /* First we check whether we've been given the password in already
+ encrypted form. */
+ if (strlen( p ) == 16 || (strlen( p ) == 32
+ && pdb_gethexpwd( p, (char *) hash_pass ))) {
+
+ if (!memcmp( hash_pass, smb_pwent->smb_passwd, 16 )
+ || (smb_pwent->smb_nt_passwd
+ && !memcmp( hash_pass, smb_pwent->smb_nt_passwd, 16 )))
+ {
+ retval = PAM_SUCCESS;
+ if (data_name) { /* reset failures */
+ pam_set_data( pamh, data_name, NULL, _cleanup_failures );
+ }
+ _pam_delete( data_name );
+ memset( hash_pass, '\0', 16 );
+ smb_pwent = NULL;
+ return retval;
+ }
+ }
+
+ /*
+ * The password we were given wasn't an encrypted password, or it
+ * didn't match the one we have. We encrypt the password now and try
+ * again.
+ */
+
+ nt_lm_owf_gen(p, nt_pw, lm_pw);
+
+ /* the moment of truth -- do we agree with the password? */
+
+ if (!memcmp( nt_pw, smb_pwent->smb_nt_passwd, 16 )) {
+
+ retval = PAM_SUCCESS;
+ if (data_name) { /* reset failures */
+ pam_set_data(pamh, data_name, NULL, _cleanup_failures);
+ }
+ } else {
+
+ const char *service;
+
+ pam_get_item( pamh, PAM_SERVICE, (const void **)&service );
+
+ if (data_name != NULL) {
+ struct _pam_failed_auth *new = NULL;
+ const struct _pam_failed_auth *old = NULL;
+
+ /* get a failure recorder */
+
+ new = (struct _pam_failed_auth *)
+ malloc( sizeof(struct _pam_failed_auth) );
+
+ if (new != NULL) {
+
+ /* any previous failures for this user ? */
+ pam_get_data(pamh, data_name, (const void **) &old);
+
+ if (old != NULL) {
+ new->count = old->count + 1;
+ if (new->count >= SMB_MAX_RETRIES) {
+ retval = PAM_MAXTRIES;
+ }
+ } else {
+ _log_err( LOG_NOTICE
+ , "failed auth request by %s for service %s as %s(%d)"
+ , uidtoname( getuid() )
+ , service ? service : "**unknown**", name
+ , smb_pwent->smb_userid );
+ new->count = 1;
+ }
+ new->user = smb_xstrdup( name );
+ new->id = smb_pwent->smb_userid;
+ new->agent = smb_xstrdup( uidtoname( getuid() ) );
+ pam_set_data( pamh, data_name, new, _cleanup_failures );
+
+ } else {
+ _log_err( LOG_CRIT, "no memory for failure recorder" );
+ _log_err( LOG_NOTICE
+ , "failed auth request by %s for service %s as %s(%d)"
+ , uidtoname( getuid() )
+ , service ? service : "**unknown**", name
+ , smb_pwent->smb_userid );
+ }
+ } else {
+ _log_err( LOG_NOTICE
+ , "failed auth request by %s for service %s as %s(%d)"
+ , uidtoname( getuid() )
+ , service ? service : "**unknown**", name
+ , smb_pwent->smb_userid );
+ retval = PAM_AUTH_ERR;
+ }
+ }
+
+ _pam_delete( data_name );
+ smb_pwent = NULL;
+ return retval;
+}
+
+
+/*
+ * _smb_blankpasswd() is a quick check for a blank password
+ *
+ * returns TRUE if user does not have a password
+ * - to avoid prompting for one in such cases (CG)
+ */
+
+int _smb_blankpasswd( unsigned int ctrl, const struct smb_passwd *smb_pwent )
+{
+ int retval;
+
+ /*
+ * This function does not have to be too smart if something goes
+ * wrong, return FALSE and let this case to be treated somewhere
+ * else (CG)
+ */
+
+ if (on( SMB__NONULL, ctrl ))
+ return 0; /* will fail but don't let on yet */
+
+ if (smb_pwent->smb_passwd == NULL)
+ retval = 1;
+ else
+ retval = 0;
+
+ return retval;
+}
+
+/*
+ * obtain a password from the user
+ */
+
+int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl
+ , const char *comment, const char *prompt1
+ , const char *prompt2, const char *data_name
+ , const char **pass )
+{
+ int authtok_flag;
+ int retval;
+ const char *item = NULL;
+ char *token;
+
+ struct pam_message msg[3], *pmsg[3];
+ struct pam_response *resp;
+ int i, expect;
+
+
+ /* make sure nothing inappropriate gets returned */
+
+ *pass = token = NULL;
+
+ /* which authentication token are we getting? */
+
+ authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
+
+ /* should we obtain the password from a PAM item ? */
+
+ if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) {
+ retval = pam_get_item( pamh, authtok_flag, (const void **) &item );
+ if (retval != PAM_SUCCESS) {
+ /* very strange. */
+ _log_err( LOG_ALERT
+ , "pam_get_item returned error to smb_read_password" );
+ return retval;
+ } else if (item != NULL) { /* we have a password! */
+ *pass = item;
+ item = NULL;
+ return PAM_SUCCESS;
+ } else if (on( SMB_USE_FIRST_PASS, ctrl )) {
+ return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
+ } else if (on( SMB_USE_AUTHTOK, ctrl )
+ && off( SMB__OLD_PASSWD, ctrl ))
+ {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+ }
+
+ /*
+ * getting here implies we will have to get the password from the
+ * user directly.
+ */
+
+ /* prepare to converse */
+ if (comment != NULL && off(SMB__QUIET, ctrl)) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+ msg[0].msg = comment;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = prompt1;
+
+ if (prompt2 != NULL) {
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = prompt2;
+ expect = 2;
+ } else
+ expect = 1;
+
+ resp = NULL;
+
+ retval = converse( pamh, ctrl, i, pmsg, &resp );
+
+ if (resp != NULL) {
+ int j = comment ? 1 : 0;
+ /* interpret the response */
+
+ if (retval == PAM_SUCCESS) { /* a good conversation */
+
+ token = smb_xstrdup(resp[j++].resp);
+ if (token != NULL) {
+ if (expect == 2) {
+ /* verify that password entered correctly */
+ if (!resp[j].resp || strcmp( token, resp[j].resp )) {
+ _pam_delete( token );
+ retval = PAM_AUTHTOK_RECOVER_ERR;
+ make_remark( pamh, ctrl, PAM_ERROR_MSG
+ , MISTYPED_PASS );
+ }
+ }
+ } else {
+ _log_err(LOG_NOTICE, "could not recover authentication token");
+ }
+ }
+
+ /* tidy up */
+ _pam_drop_reply( resp, expect );
+
+ } else {
+ retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval;
+ }
+
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl ))
+ _log_err( LOG_DEBUG, "unable to obtain a password" );
+ return retval;
+ }
+ /* 'token' is the entered password */
+
+ if (off( SMB_NOT_SET_PASS, ctrl )) {
+
+ /* we store this password as an item */
+
+ retval = pam_set_item( pamh, authtok_flag, (const void *)token );
+ _pam_delete( token ); /* clean it up */
+ if (retval != PAM_SUCCESS
+ || (retval = pam_get_item( pamh, authtok_flag
+ ,(const void **)&item )) != PAM_SUCCESS)
+ {
+ _log_err( LOG_CRIT, "error manipulating password" );
+ return retval;
+ }
+ } else {
+ /*
+ * then store it as data specific to this module. pam_end()
+ * will arrange to clean it up.
+ */
+
+ retval = pam_set_data( pamh, data_name, (void *) token, _cleanup );
+ if (retval != PAM_SUCCESS
+ || (retval = pam_get_data( pamh, data_name, (const void **)&item ))
+ != PAM_SUCCESS)
+ {
+ _log_err( LOG_CRIT, "error manipulating password data [%s]"
+ , pam_strerror( pamh, retval ));
+ _pam_delete( token );
+ item = NULL;
+ return retval;
+ }
+ token = NULL; /* break link to password */
+ }
+
+ *pass = item;
+ item = NULL; /* break link to password */
+
+ return PAM_SUCCESS;
+}
+
+int _pam_smb_approve_pass(pam_handle_t * pamh
+ ,unsigned int ctrl
+ ,const char *pass_old
+ ,const char *pass_new)
+{
+
+ /* Further checks should be handled through module stacking. -SRL */
+ if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new )))
+ {
+ if (on(SMB_DEBUG, ctrl)) {
+ _log_err( LOG_DEBUG,
+ "passwd: bad authentication token (null or unchanged)" );
+ }
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
+ "No password supplied" : "Password unchanged" );
+ return PAM_AUTHTOK_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
diff --git a/source/pam_smbpass/support.h b/source/pam_smbpass/support.h
new file mode 100644
index 00000000000..85bbd0a523c
--- /dev/null
+++ b/source/pam_smbpass/support.h
@@ -0,0 +1,52 @@
+/* syslogging function for errors and other information */
+extern void _log_err(int, const char *, ...);
+
+/* set the control flags for the UNIX module. */
+extern int set_ctrl(int, int, const char **);
+
+/* generic function for freeing pam data segments */
+extern void _cleanup(pam_handle_t *, void *, int);
+
+/*
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ */
+
+extern char *xstrdup(const char *);
+
+/* ************************************************************** *
+ * Useful non-trivial functions *
+ * ************************************************************** */
+
+extern void _cleanup_failures(pam_handle_t *, void *, int);
+
+/* compare 2 strings */
+extern BOOL strequal(const char *, const char *);
+
+extern struct smb_passwd *
+_my_get_smbpwnam(FILE *, const char *, BOOL *, BOOL *, long *);
+
+extern int _smb_verify_password( pam_handle_t *pamh
+ , const struct smb_passwd *smb_pwent
+ , const char *p, unsigned int ctrl );
+
+/*
+ * this function obtains the name of the current user and ensures
+ * that the PAM_USER item is set to this value
+ */
+
+extern int _smb_get_user(pam_handle_t *, unsigned int,
+ const char *, const char **);
+
+/* _smb_blankpasswd() is a quick check for a blank password */
+
+extern int _smb_blankpasswd(unsigned int, const struct smb_passwd *);
+
+
+/* obtain a password from the user */
+extern int _smb_read_password( pam_handle_t *, unsigned int, const char*,
+ const char *, const char *, const char *,
+ const char **);
+
+extern int _pam_smb_approve_pass(pam_handle_t *, unsigned int, const char *,
+ const char *);
diff --git a/source/param/.cvsignore b/source/param/.cvsignore
new file mode 100644
index 00000000000..76e2d7ff3eb
--- /dev/null
+++ b/source/param/.cvsignore
@@ -0,0 +1,3 @@
+*.po32
+*.po
+
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..335995b0dd2 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -2,9 +2,11 @@
Unix SMB/Netbios implementation.
Version 1.9.
Parameter loading functions
- Copyright (C) Karl Auer 1993,1994
+ Copyright (C) Karl Auer 1993-1998
Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,29 +51,19 @@
#include "includes.h"
-#include "params.h"
-#include "loadparm.h"
-#include "pcap.h"
-
+BOOL in_client = False; /* Not in the client by default */
BOOL bLoaded = False;
-extern int DEBUGLEVEL;
-extern int ReadSize;
+extern userdom_struct current_user_info;
+extern int DEBUGLEVEL_CLASS[DBGC_LAST];
extern pstring user_socket_options;
-extern pstring smbrun_path;
+extern pstring global_myname;
+pstring global_scope = "";
#ifndef GLOBAL_NAME
#define GLOBAL_NAME "global"
#endif
-#ifndef PRINTCAP_NAME
-#ifdef AIX
-#define PRINTCAP_NAME "/etc/qconfig"
-#else
-#define PRINTCAP_NAME "/etc/printcap"
-#endif
-#endif
-
#ifndef PRINTERS_NAME
#define PRINTERS_NAME "printers"
#endif
@@ -81,87 +73,202 @@ extern pstring smbrun_path;
#endif
/* some helpful bits */
-#define pSERVICE(i) ServicePtrs[i]
-#define iSERVICE(i) (*pSERVICE(i))
-#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices) && iSERVICE(iService).valid)
-#define VALID(i) iSERVICE(i).valid
-
-/* these are the types of parameter we have */
-typedef enum
-{
- P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_STRING,P_GSTRING
-} parm_type;
+#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && ServicePtrs[(i)]->valid)
+#define VALID(i) ServicePtrs[i]->valid
-typedef enum
-{
- P_LOCAL,P_GLOBAL,P_NONE
-} parm_class;
-
-int keepalive=0;
-extern BOOL use_getwd_cache;
+int keepalive = DEFAULT_KEEPALIVE;
+BOOL use_getwd_cache = True;
extern int extra_time_offset;
-#ifdef KANJI
-extern int coding_system;
-#endif
+
+static BOOL defaults_saved = False;
/*
* This structure describes global (ie., server-wide) parameters.
*/
typedef struct
{
- char *szPrintcapname;
- char *szLockDir;
- char *szRootdir;
- char *szDefaultService;
- char *szDfree;
- char *szMsgCommand;
- char *szHostsEquiv;
- char *szServerString;
- char *szAutoServices;
- char *szPasswdProgram;
- char *szPasswdChat;
- char *szLogFile;
- char *szConfigFile;
- char *szSMBPasswdFile;
- char *szPasswordServer;
- char *szSocketOptions;
- char *szValidChars;
- char *szWorkGroup;
- char *szDomainController;
- char *szUsernameMap;
- char *szCharacterSet;
- char *szLogonScript;
- int max_log_size;
- int mangled_stack;
- int max_xmit;
- int max_mux;
- int max_packet;
- int pwordlevel;
- int deadtime;
- int maxprotocol;
- int security;
- int printing;
- int maxdisksize;
- int lpqcachetime;
- int syslog;
- int os_level;
- int max_ttl;
- BOOL bPreferredMaster;
- BOOL bDomainMaster;
- BOOL bDomainLogons;
- BOOL bEncryptPasswords;
- BOOL bStripDot;
- BOOL bNullPasswords;
- BOOL bLoadPrinters;
- BOOL bUseRhosts;
- BOOL bReadRaw;
- BOOL bWriteRaw;
- BOOL bReadPrediction;
- BOOL bReadbmpx;
- BOOL bSyslogOnly;
- BOOL bBrowseList;
-} global;
+ char *dos_charset;
+ char *unix_charset;
+ char *display_charset;
+ char *szPrintcapname;
+ char *szEnumPortsCommand;
+ char *szAddPrinterCommand;
+ char *szDeletePrinterCommand;
+ char *szOs2DriverMap;
+ char *szLockDir;
+ char *szRootdir;
+ char *szDefaultService;
+ char *szDfree;
+ char *szMsgCommand;
+ char *szHostsEquiv;
+ char *szServerString;
+ char *szAutoServices;
+ char *szPasswdProgram;
+ char *szPasswdChat;
+ char *szLogFile;
+ char *szConfigFile;
+ char *szSMBPasswdFile;
+ char *szPrivateDir;
+ char *szPassdbModulePath;
+ char *szPasswordServer;
+ char *szSocketOptions;
+ char *szWorkGroup;
+ char *szRealm;
+ char *szADSserver;
+ char *szUsernameMap;
+ char *szLogonScript;
+ char *szLogonPath;
+ char *szLogonDrive;
+ char *szLogonHome;
+ char *szWINSserver;
+ char **szInterfaces;
+ char *szRemoteAnnounce;
+ char *szRemoteBrowseSync;
+ char *szSocketAddress;
+ char *szNISHomeMapName;
+ char *szAnnounceVersion; /* This is initialised in init_globals */
+ char **szNetbiosAliases;
+ char *szDomainOtherSIDs;
+ char *szNameResolveOrder;
+ char *szPanicAction;
+ char *szAddUserScript;
+ char *szDelUserScript;
+ char *szAddGroupScript;
+ char *szDelGroupScript;
+ char *szAddUserToGroupScript;
+ char *szDelUserToGroupScript;
+ char *szAddMachineScript;
+ char *szShutdownScript;
+ char *szAbortShutdownScript;
+ char *szWINSHook;
+#ifdef WITH_UTMP
+ char *szUtmpDir;
+ char *szWtmpDir;
+ BOOL bUtmp;
+#endif
+ char *szSourceEnv;
+ char *szWinbindUID;
+ char *szWinbindGID;
+ char *szTemplateHomedir;
+ char *szTemplateShell;
+ char *szWinbindSeparator;
+ BOOL bWinbindEnumUsers;
+ BOOL bWinbindEnumGroups;
+ char *szAddShareCommand;
+ char *szChangeShareCommand;
+ char *szDeleteShareCommand;
+ char *szGuestaccount;
+ int max_log_size;
+ int mangled_stack;
+ int max_xmit;
+ int max_mux;
+ int max_open_files;
+ int max_packet;
+ int pwordlevel;
+ int unamelevel;
+ int deadtime;
+ int maxprotocol;
+ int minprotocol;
+ int security;
+ char **AuthMethods;
+ BOOL paranoid_server_security;
+ int maxdisksize;
+ int lpqcachetime;
+ int iMaxSmbdProcesses;
+ BOOL bDisableSpoolss;
+ int iTotalPrintJobs;
+ int syslog;
+ int os_level;
+ int enhanced_browsing;
+ int max_ttl;
+ int max_wins_ttl;
+ int min_wins_ttl;
+ int ReadSize;
+ int lm_announce;
+ int lm_interval;
+ int announce_as; /* This is initialised in init_globals */
+ int machine_password_timeout;
+ int change_notify_timeout;
+ int stat_cache_size;
+ int map_to_guest;
+ int min_passwd_length;
+ int oplock_break_wait_time;
+ int winbind_cache_time;
+#ifdef WITH_LDAP_SAM
+ int ldap_port;
+ int ldap_ssl;
+ char *szLdapServer;
+ char *szLdapSuffix;
+ char *szLdapFilter;
+ char *szLdapAdminDn;
+#endif /* WITH_LDAP_SAM */
+#ifdef WITH_SSL
+ int sslVersion;
+ char **sslHostsRequire;
+ char **sslHostsResign;
+ char *sslCaCertDir;
+ char *sslCaCertFile;
+ char *sslServerCert;
+ char *sslServerPrivKey;
+ char *sslClientCert;
+ char *sslClientPrivKey;
+ char *sslCiphers;
+ char *sslEgdSocket;
+ char *sslEntropyFile;
+ int sslEntropyBytes;
+ BOOL sslEnabled;
+ BOOL sslReqClientCert;
+ BOOL sslReqServerCert;
+ BOOL sslCompatibility;
+#endif /* WITH_SSL */
+ BOOL bMsAddPrinterWizard;
+ BOOL bDNSproxy;
+ BOOL bWINSsupport;
+ BOOL bWINSproxy;
+ BOOL bLocalMaster;
+ BOOL bPreferredMaster;
+ BOOL bDomainMaster;
+ BOOL bDomainLogons;
+ BOOL bEncryptPasswords;
+ BOOL bUpdateEncrypt;
+ BOOL bStripDot;
+ BOOL bNullPasswords;
+ BOOL bObeyPamRestrictions;
+ BOOL bLoadPrinters;
+ BOOL bLargeReadwrite;
+ BOOL bReadRaw;
+ BOOL bWriteRaw;
+ BOOL bReadPrediction;
+ BOOL bReadbmpx;
+ BOOL bSyslogOnly;
+ BOOL bBrowseList;
+ BOOL bNISHomeMap;
+ BOOL bTimeServer;
+ BOOL bBindInterfacesOnly;
+ BOOL bPamPasswordChange;
+ BOOL bUnixPasswdSync;
+ BOOL bPasswdChatDebug;
+ BOOL bTimestampLogs;
+ BOOL bNTSmbSupport;
+ BOOL bNTPipeSupport;
+ BOOL bStatCache;
+ BOOL bKernelOplocks;
+ BOOL bAllowTrustedDomains;
+ BOOL bRestrictAnonymous;
+ BOOL bLanmanAuth;
+ BOOL bNTLMAuth;
+ BOOL bDebugHiresTimestamp;
+ BOOL bDebugPid;
+ BOOL bDebugUid;
+ BOOL bHostMSDfs;
+ BOOL bHideLocalUsers;
+ BOOL bUnicode;
+ BOOL bUseMmap;
+ BOOL bHostnameLookups;
+ BOOL bUseSpnego;
+}
+global;
static global Globals;
@@ -172,142 +279,228 @@ static global Globals;
*/
typedef struct
{
- BOOL valid;
- char *szService;
- char *szPath;
- char *szUsername;
- char *szGuestaccount;
- char *szInvalidUsers;
- char *szValidUsers;
- char *szAdminUsers;
- char *szCopy;
- char *szInclude;
- char *szPreExec;
- char *szPostExec;
- char *szRootPreExec;
- char *szRootPostExec;
- char *szPrintcommand;
- char *szLpqcommand;
- char *szLprmcommand;
- char *szLppausecommand;
- char *szLpresumecommand;
- char *szPrintername;
- char *szDontdescend;
- char *szHostsallow;
- char *szHostsdeny;
- char *szMagicScript;
- char *szMagicOutput;
- char *szMangledMap;
- char *comment;
- char *force_user;
- char *force_group;
- char *readlist;
- char *writelist;
- char *volume;
- int iMinPrintSpace;
- int iCreate_mode;
- int iMaxConnections;
- int iDefaultCase;
- BOOL bAlternatePerm;
- BOOL bRevalidate;
- BOOL bCaseSensitive;
- BOOL bCasePreserve;
- BOOL bShortCasePreserve;
- BOOL bCaseMangle;
- BOOL status;
- BOOL bHideDotFiles;
- BOOL bBrowseable;
- BOOL bAvailable;
- BOOL bRead_only;
- BOOL bNo_set_dir;
- BOOL bGuest_only;
- BOOL bGuest_ok;
- BOOL bPrint_ok;
- BOOL bPostscript;
- BOOL bMap_system;
- BOOL bMap_hidden;
- BOOL bMap_archive;
- BOOL bLocking;
- BOOL bStrictLocking;
- BOOL bShareModes;
- BOOL bOnlyUser;
- BOOL bMangledNames;
- BOOL bWidelinks;
- BOOL bSyncAlways;
- char magic_char;
- BOOL *copymap;
- char dummy[3]; /* for alignment */
-} service;
+ BOOL valid;
+ BOOL autoloaded;
+ char *szService;
+ char *szPath;
+ char *szUsername;
+ char **szInvalidUsers;
+ char **szValidUsers;
+ char **szAdminUsers;
+ char *szCopy;
+ char *szInclude;
+ char *szPreExec;
+ char *szPostExec;
+ char *szRootPreExec;
+ char *szRootPostExec;
+ char *szPrintcommand;
+ char *szLpqcommand;
+ char *szLprmcommand;
+ char *szLppausecommand;
+ char *szLpresumecommand;
+ char *szQueuepausecommand;
+ char *szQueueresumecommand;
+ char *szPrintername;
+ char *szPrinterDriver;
+ char *szPrinterDriverLocation;
+ char *szDriverFile;
+ char *szDontdescend;
+ char **szHostsallow;
+ char **szHostsdeny;
+ char *szMagicScript;
+ char *szMagicOutput;
+ char *szMangledMap;
+ char *szVetoFiles;
+ char *szHideFiles;
+ char *szVetoOplockFiles;
+ char *comment;
+ char *force_user;
+ char *force_group;
+ char **readlist;
+ char **writelist;
+ char **printer_admin;
+ char *volume;
+ char *fstype;
+ char *szVfsObjectFile;
+ char *szVfsOptions;
+ int iMinPrintSpace;
+ int iMaxPrintJobs;
+ int iWriteCacheSize;
+ int iCreate_mask;
+ int iCreate_force_mode;
+ int iSecurity_mask;
+ int iSecurity_force_mode;
+ int iDir_mask;
+ int iDir_force_mode;
+ int iDir_Security_mask;
+ int iDir_Security_force_mode;
+ int iMaxConnections;
+ int iDefaultCase;
+ int iPrinting;
+ int iOplockContentionLimit;
+ BOOL bAlternatePerm;
+ BOOL bPreexecClose;
+ BOOL bRootpreexecClose;
+ BOOL bCaseSensitive;
+ BOOL bCasePreserve;
+ BOOL bShortCasePreserve;
+ BOOL bCaseMangle;
+ BOOL bHideDotFiles;
+ BOOL bHideUnReadable;
+ BOOL bBrowseable;
+ BOOL bAvailable;
+ BOOL bRead_only;
+ BOOL bNo_set_dir;
+ BOOL bGuest_only;
+ BOOL bGuest_ok;
+ BOOL bPrint_ok;
+ BOOL bPostscript;
+ BOOL bMap_system;
+ BOOL bMap_hidden;
+ BOOL bMap_archive;
+ BOOL bLocking;
+ BOOL bStrictLocking;
+ BOOL bPosixLocking;
+ BOOL bShareModes;
+ BOOL bOpLocks;
+ BOOL bLevel2OpLocks;
+ BOOL bOnlyUser;
+ BOOL bMangledNames;
+ BOOL bWidelinks;
+ BOOL bSymlinks;
+ BOOL bSyncAlways;
+ BOOL bStrictAllocate;
+ BOOL bStrictSync;
+ char magic_char;
+ BOOL *copymap;
+ BOOL bDeleteReadonly;
+ BOOL bFakeOplocks;
+ BOOL bDeleteVetoFiles;
+ BOOL bDosFilemode;
+ BOOL bDosFiletimes;
+ BOOL bDosFiletimeResolution;
+ BOOL bFakeDirCreateTimes;
+ BOOL bBlockingLocks;
+ BOOL bInheritPerms;
+ BOOL bMSDfsRoot;
+ BOOL bUseClientDriver;
+ BOOL bNTAclSupport;
+
+ char dummy[3]; /* for alignment */
+}
+service;
/* This is a default service used to prime a services structure */
-static service sDefault =
-{
- True, /* valid */
- NULL, /* szService */
- NULL, /* szPath */
- NULL, /* szUsername */
- NULL, /* szGuestAccount */
- NULL, /* szInvalidUsers */
- NULL, /* szValidUsers */
- NULL, /* szAdminUsers */
- NULL, /* szCopy */
- NULL, /* szInclude */
- NULL, /* szPreExec */
- NULL, /* szPostExec */
- NULL, /* szRootPreExec */
- NULL, /* szRootPostExec */
- NULL, /* szPrintcommand */
- NULL, /* szLpqcommand */
- NULL, /* szLprmcommand */
- NULL, /* szLppausecommand */
- NULL, /* szLpresumecommand */
- NULL, /* szPrintername */
- NULL, /* szDontdescend */
- NULL, /* szHostsallow */
- NULL, /* szHostsdeny */
- NULL, /* szMagicScript */
- NULL, /* szMagicOutput */
- NULL, /* szMangledMap */
- NULL, /* comment */
- NULL, /* force user */
- NULL, /* force group */
- NULL, /* readlist */
- NULL, /* writelist */
- NULL, /* volume */
- 0, /* iMinPrintSpace */
- 0755, /* iCreate_mode */
- 0, /* iMaxConnections */
- CASE_LOWER, /* iDefaultCase */
- False, /* bAlternatePerm */
- False, /* revalidate */
- False, /* case sensitive */
- False, /* case preserve */
- False, /* short case preserve */
- False, /* case mangle */
- True, /* status */
- True, /* bHideDotFiles */
- True, /* bBrowseable */
- True, /* bAvailable */
- True, /* bRead_only */
- True, /* bNo_set_dir */
- False, /* bGuest_only */
- False, /* bGuest_ok */
- False, /* bPrint_ok */
- False, /* bPostscript */
- False, /* bMap_system */
- False, /* bMap_hidden */
- True, /* bMap_archive */
- True, /* bLocking */
- False, /* bStrictLocking */
- True, /* bShareModes */
- False, /* bOnlyUser */
- True, /* bMangledNames */
- True, /* bWidelinks */
- False, /* bSyncAlways */
- '~', /* magic char */
- NULL, /* copymap */
- "" /* dummy */
+static service sDefault = {
+ True, /* valid */
+ False, /* not autoloaded */
+ NULL, /* szService */
+ NULL, /* szPath */
+ NULL, /* szUsername */
+ NULL, /* szInvalidUsers */
+ NULL, /* szValidUsers */
+ NULL, /* szAdminUsers */
+ NULL, /* szCopy */
+ NULL, /* szInclude */
+ NULL, /* szPreExec */
+ NULL, /* szPostExec */
+ NULL, /* szRootPreExec */
+ NULL, /* szRootPostExec */
+ NULL, /* szPrintcommand */
+ NULL, /* szLpqcommand */
+ NULL, /* szLprmcommand */
+ NULL, /* szLppausecommand */
+ NULL, /* szLpresumecommand */
+ NULL, /* szQueuepausecommand */
+ NULL, /* szQueueresumecommand */
+ NULL, /* szPrintername */
+ NULL, /* szPrinterDriver - this is set in init_globals() */
+ NULL, /* szPrinterDriverLocation */
+ NULL, /* szDriverFile */
+ NULL, /* szDontdescend */
+ NULL, /* szHostsallow */
+ NULL, /* szHostsdeny */
+ NULL, /* szMagicScript */
+ NULL, /* szMagicOutput */
+ NULL, /* szMangledMap */
+ NULL, /* szVetoFiles */
+ NULL, /* szHideFiles */
+ NULL, /* szVetoOplockFiles */
+ NULL, /* comment */
+ NULL, /* force user */
+ NULL, /* force group */
+ NULL, /* readlist */
+ NULL, /* writelist */
+ NULL, /* printer admin */
+ NULL, /* volume */
+ NULL, /* fstype */
+ NULL, /* vfs object */
+ NULL, /* vfs options */
+ 0, /* iMinPrintSpace */
+ 1000, /* iMaxPrintJobs */
+ 0, /* iWriteCacheSize */
+ 0744, /* iCreate_mask */
+ 0000, /* iCreate_force_mode */
+ 0777, /* iSecurity_mask */
+ 0, /* iSecurity_force_mode */
+ 0755, /* iDir_mask */
+ 0000, /* iDir_force_mode */
+ 0777, /* iDir_Security_mask */
+ 0, /* iDir_Security_force_mode */
+ 0, /* iMaxConnections */
+ CASE_LOWER, /* iDefaultCase */
+ DEFAULT_PRINTING, /* iPrinting */
+ 2, /* iOplockContentionLimit */
+ False, /* bAlternatePerm */
+ False, /* bPreexecClose */
+ False, /* bRootpreexecClose */
+ False, /* case sensitive */
+ True, /* case preserve */
+ True, /* short case preserve */
+ False, /* case mangle */
+ True, /* bHideDotFiles */
+ False, /* bHideUnReadable */
+ True, /* bBrowseable */
+ True, /* bAvailable */
+ True, /* bRead_only */
+ True, /* bNo_set_dir */
+ False, /* bGuest_only */
+ False, /* bGuest_ok */
+ False, /* bPrint_ok */
+ False, /* bPostscript */
+ False, /* bMap_system */
+ False, /* bMap_hidden */
+ True, /* bMap_archive */
+ True, /* bLocking */
+ True, /* bStrictLocking */
+ True, /* bPosixLocking */
+ True, /* bShareModes */
+ True, /* bOpLocks */
+ True, /* bLevel2OpLocks */
+ False, /* bOnlyUser */
+ True, /* bMangledNames */
+ True, /* bWidelinks */
+ True, /* bSymlinks */
+ False, /* bSyncAlways */
+ False, /* bStrictAllocate */
+ False, /* bStrictSync */
+ '~', /* magic char */
+ NULL, /* copymap */
+ False, /* bDeleteReadonly */
+ False, /* bFakeOplocks */
+ False, /* bDeleteVetoFiles */
+ False, /* bDosFilemode */
+ False, /* bDosFiletimes */
+ False, /* bDosFiletimeResolution */
+ False, /* bFakeDirCreateTimes */
+ True, /* bBlockingLocks */
+ False, /* bInheritPerms */
+ False, /* bMSDfsRoot */
+ False, /* bUseClientDriver */
+ True, /* bNTAclSupport */
+
+ "" /* dummy */
};
@@ -318,331 +511,907 @@ static int iNumServices = 0;
static int iServiceIndex = 0;
static BOOL bInGlobalSection = True;
static BOOL bGlobalOnly = False;
-
+static int server_role;
+static int default_server_announce;
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
/* prototypes for the special type handlers */
-static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
static BOOL handle_include(char *pszParmValue, char **ptr);
static BOOL handle_copy(char *pszParmValue, char **ptr);
-static BOOL handle_protocol(char *pszParmValue,int *val);
-static BOOL handle_security(char *pszParmValue,int *val);
-static BOOL handle_case(char *pszParmValue,int *val);
-static BOOL handle_printing(char *pszParmValue,int *val);
-static BOOL handle_character_set(char *pszParmValue,int *val);
-#ifdef KANJI
-static BOOL handle_coding_system(char *pszParmValue,int *val);
-#endif /* KANJI */
-
-struct parm_struct
-{
- char *label;
- parm_type type;
- parm_class class;
- void *ptr;
- BOOL (*special)();
-} parm_table[] =
-{
- {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL},
- {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL},
- {"syslog", P_INTEGER, P_GLOBAL, &Globals.syslog, NULL},
- {"syslog only", P_BOOL, P_GLOBAL, &Globals.bSyslogOnly, NULL},
- {"protocol", P_INTEGER, P_GLOBAL, &Globals.maxprotocol,handle_protocol},
- {"security", P_INTEGER, P_GLOBAL, &Globals.security,handle_security},
- {"printing", P_INTEGER, P_GLOBAL, &Globals.printing,handle_printing},
- {"max disk size", P_INTEGER, P_GLOBAL, &Globals.maxdisksize, NULL},
- {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL},
- {"encrypt passwords",P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL},
- {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL},
- {"read prediction", P_BOOL, P_GLOBAL, &Globals.bReadPrediction, NULL},
- {"read bmpx", P_BOOL, P_GLOBAL, &Globals.bReadbmpx, NULL},
- {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL},
- {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL},
- {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL},
- {"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL},
- {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL},
- {"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL},
- {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL},
- {"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL},
- {"smbrun", P_GSTRING, P_GLOBAL, smbrun_path, NULL},
- {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL},
- {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL},
- {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL},
- {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL},
- {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL},
- {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL},
- {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL},
- {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL},
- {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL},
- {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL},
- {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL},
- {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"root", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL},
- {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL},
- {"message command", P_STRING, P_GLOBAL, &Globals.szMsgCommand, NULL},
- {"dfree command", P_STRING, P_GLOBAL, &Globals.szDfree, NULL},
- {"passwd program", P_STRING, P_GLOBAL, &Globals.szPasswdProgram, NULL},
- {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL},
- {"valid chars", P_STRING, P_GLOBAL, &Globals.szValidChars, handle_valid_chars},
- {"workgroup", P_STRING, P_GLOBAL, &Globals.szWorkGroup, NULL},
- {"domain controller",P_STRING, P_GLOBAL, &Globals.szDomainController,NULL},
- {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL},
- {"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set},
- {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL},
- {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL},
- {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL},
- {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL},
- {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL},
- {"max packet", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL},
- {"packet size", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL},
- {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL},
- {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL},
- {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL},
- {"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL},
- {"read size", P_INTEGER, P_GLOBAL, &ReadSize, NULL},
-#ifdef KANJI
- {"coding system", P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
-#endif /* KANJI */
- {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL},
- {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL},
- {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
- {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
- {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL},
- {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL},
- {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL},
-
- {"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL},
- {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL},
- {"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy},
- {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include},
- {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL},
- {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL},
- {"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL},
- {"root preexec", P_STRING, P_LOCAL, &sDefault.szRootPreExec, NULL},
- {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL},
- {"alternate permissions",P_BOOL,P_LOCAL, &sDefault.bAlternatePerm, NULL},
- {"revalidate", P_BOOL, P_LOCAL, &sDefault.bRevalidate, NULL},
- {"default case", P_INTEGER, P_LOCAL, &sDefault.iDefaultCase, handle_case},
- {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL},
- {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL},
- {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL},
- {"short preserve case",P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve,NULL},
- {"mangle case", P_BOOL, P_LOCAL, &sDefault.bCaseMangle, NULL},
- {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL},
- {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL},
- {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL},
- {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL},
- {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL},
- {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL},
- {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"guest account", P_STRING, P_LOCAL, &sDefault.szGuestaccount, NULL},
- {"invalid users", P_STRING, P_LOCAL, &sDefault.szInvalidUsers, NULL},
- {"valid users", P_STRING, P_LOCAL, &sDefault.szValidUsers, NULL},
- {"admin users", P_STRING, P_LOCAL, &sDefault.szAdminUsers, NULL},
- {"read list", P_STRING, P_LOCAL, &sDefault.readlist, NULL},
- {"write list", P_STRING, P_LOCAL, &sDefault.writelist, NULL},
- {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL},
- {"force user", P_STRING, P_LOCAL, &sDefault.force_user, NULL},
- {"force group", P_STRING, P_LOCAL, &sDefault.force_group, NULL},
- {"group", P_STRING, P_LOCAL, &sDefault.force_group, NULL},
- {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL},
- {"write ok", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
- {"writeable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
- {"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
- {"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL},
- {"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL},
- {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mode, NULL},
- {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mode, NULL},
- {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL},
- {"status", P_BOOL, P_LOCAL, &sDefault.status, NULL},
- {"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL},
- {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL},
- {"only guest", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL},
- {"guest ok", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL},
- {"public", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL},
- {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL},
- {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL},
- {"postscript", P_BOOL, P_LOCAL, &sDefault.bPostscript, NULL},
- {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL},
- {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL},
- {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL},
- {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL},
- {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL},
- {"share modes", P_BOOL, P_LOCAL, &sDefault.bShareModes, NULL},
- {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL},
- {"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL},
- {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL},
- {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL},
- {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL},
- {"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL},
- {"lprm command", P_STRING, P_LOCAL, &sDefault.szLprmcommand, NULL},
- {"lppause command", P_STRING, P_LOCAL, &sDefault.szLppausecommand, NULL},
- {"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand,NULL},
- {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
- {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
- {"hosts allow", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
- {"allow hosts", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
- {"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL},
- {"deny hosts", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL},
- {"dont descend", P_STRING, P_LOCAL, &sDefault.szDontdescend, NULL},
- {"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL},
- {"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL},
- {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL},
-
- {NULL, P_BOOL, P_NONE, NULL, NULL}
+static BOOL handle_vfs_object(char *pszParmValue, char **ptr);
+static BOOL handle_source_env(char *pszParmValue, char **ptr);
+static BOOL handle_netbios_name(char *pszParmValue, char **ptr);
+static BOOL handle_winbind_uid(char *pszParmValue, char **ptr);
+static BOOL handle_winbind_gid(char *pszParmValue, char **ptr);
+static BOOL handle_wins_server_list(char *pszParmValue, char **ptr);
+static BOOL handle_debug_list( char *pszParmValue, char **ptr );
+
+static void set_server_role(void);
+static void set_default_server_announce_type(void);
+
+static struct enum_list enum_protocol[] = {
+ {PROTOCOL_NT1, "NT1"},
+ {PROTOCOL_LANMAN2, "LANMAN2"},
+ {PROTOCOL_LANMAN1, "LANMAN1"},
+ {PROTOCOL_CORE, "CORE"},
+ {PROTOCOL_COREPLUS, "COREPLUS"},
+ {PROTOCOL_COREPLUS, "CORE+"},
+ {-1, NULL}
};
+static struct enum_list enum_security[] = {
+ {SEC_SHARE, "SHARE"},
+ {SEC_USER, "USER"},
+ {SEC_SERVER, "SERVER"},
+ {SEC_DOMAIN, "DOMAIN"},
+ {SEC_ADS, "ADS"},
+ {-1, NULL}
+};
+static struct enum_list enum_printing[] = {
+ {PRINT_SYSV, "sysv"},
+ {PRINT_AIX, "aix"},
+ {PRINT_HPUX, "hpux"},
+ {PRINT_BSD, "bsd"},
+ {PRINT_QNX, "qnx"},
+ {PRINT_PLP, "plp"},
+ {PRINT_LPRNG, "lprng"},
+ {PRINT_SOFTQ, "softq"},
+ {PRINT_CUPS, "cups"},
+ {PRINT_LPRNT, "nt"},
+ {PRINT_LPROS2, "os2"},
+#ifdef DEVELOPER
+ {PRINT_TEST, "test"},
+ {PRINT_VLP, "vlp"},
+#endif /* DEVELOPER */
+ {-1, NULL}
+};
-/***************************************************************************
-Initialise the global parameter structure.
-***************************************************************************/
-static void init_globals(void)
-{
- static BOOL done_init = False;
- pstring s;
+#ifdef WITH_LDAP_SAM
+static struct enum_list enum_ldap_ssl[] = {
+ {LDAP_SSL_ON, "Yes"},
+ {LDAP_SSL_ON, "yes"},
+ {LDAP_SSL_ON, "on"},
+ {LDAP_SSL_ON, "On"},
+ {LDAP_SSL_OFF, "no"},
+ {LDAP_SSL_OFF, "No"},
+ {LDAP_SSL_OFF, "off"},
+ {LDAP_SSL_OFF, "Off"},
+ {LDAP_SSL_START_TLS, "start tls"},
+ {-1, NULL}
+};
+#endif /* WITH_LDAP_SAM */
+
+/* Types of machine we can announce as. */
+#define ANNOUNCE_AS_NT_SERVER 1
+#define ANNOUNCE_AS_WIN95 2
+#define ANNOUNCE_AS_WFW 3
+#define ANNOUNCE_AS_NT_WORKSTATION 4
+
+static struct enum_list enum_announce_as[] = {
+ {ANNOUNCE_AS_NT_SERVER, "NT"},
+ {ANNOUNCE_AS_NT_SERVER, "NT Server"},
+ {ANNOUNCE_AS_NT_WORKSTATION, "NT Workstation"},
+ {ANNOUNCE_AS_WIN95, "win95"},
+ {ANNOUNCE_AS_WFW, "WfW"},
+ {-1, NULL}
+};
+
+static struct enum_list enum_case[] = {
+ {CASE_LOWER, "lower"},
+ {CASE_UPPER, "upper"},
+ {-1, NULL}
+};
+
+static struct enum_list enum_bool_auto[] = {
+ {False, "False"},
+ {False, "No"},
+ {False, "0"},
+ {True, "True"},
+ {True, "Yes"},
+ {True, "1"},
+ {Auto, "Auto"},
+ {-1, NULL}
+};
- if (!done_init)
- {
- int i;
- bzero((void *)&Globals,sizeof(Globals));
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
- for (i = 0; parm_table[i].label; i++)
- if (parm_table[i].type == P_STRING &&
- parm_table[i].ptr)
- string_init(parm_table[i].ptr,"");
+ You have 3 choices in the setting of map_to_guest:
- string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
+ "Never" means session setups with an invalid password
+ are rejected. This is the default.
- done_init = True;
- }
+ "Bad User" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+ "Bad Password" means session setups with an invalid password
+ are treated as a guest login
- DEBUG(3,("Initialising global parameters\n"));
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
-#ifdef SMB_PASSWD_FILE
- string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
+static struct enum_list enum_map_to_guest[] = {
+ {NEVER_MAP_TO_GUEST, "Never"},
+ {MAP_TO_GUEST_ON_BAD_USER, "Bad User"},
+ {MAP_TO_GUEST_ON_BAD_PASSWORD, "Bad Password"},
+ {-1, NULL}
+};
+
+#ifdef WITH_SSL
+static struct enum_list enum_ssl_version[] = {
+ {SMB_SSL_V2, "ssl2"},
+ {SMB_SSL_V3, "ssl3"},
+ {SMB_SSL_V23, "ssl2or3"},
+ {SMB_SSL_TLS1, "tls1"},
+ {-1, NULL}
+};
#endif
- string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
- string_set(&Globals.szWorkGroup, WORKGROUP);
-#ifdef SMB_PASSWD
- string_set(&Globals.szPasswdProgram, SMB_PASSWD);
-#else
- string_set(&Globals.szPasswdProgram, "/bin/passwd");
+
+/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
+static struct parm_struct parm_table[] = {
+ {"Base Options", P_SEP, P_SEPARATOR},
+
+ {"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, NULL, NULL, 0},
+ {"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, NULL, NULL, 0},
+ {"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, NULL, NULL, 0},
+ {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, 0},
+ {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkGroup, NULL, NULL, FLAG_BASIC},
+ {"realm", P_USTRING, P_GLOBAL, &Globals.szRealm, NULL, NULL, FLAG_BASIC},
+ {"ADS server", P_STRING, P_GLOBAL, &Globals.szADSserver, NULL, NULL, FLAG_BASIC},
+ {"netbios name", P_UGSTRING, P_GLOBAL, global_myname, handle_netbios_name, NULL, FLAG_BASIC},
+ {"netbios aliases", P_LIST, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL, 0},
+ {"netbios scope", P_UGSTRING, P_GLOBAL, global_scope, NULL, NULL, 0},
+ {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL, NULL, FLAG_BASIC },
+ {"interfaces", P_LIST, P_GLOBAL, &Globals.szInterfaces, NULL, NULL, FLAG_BASIC},
+ {"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, 0},
+
+ {"Security Options", P_SEP, P_SEPARATOR},
+
+ {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security, FLAG_BASIC},
+ {"auth methods", P_LIST, P_GLOBAL, &Globals.AuthMethods, NULL, NULL, FLAG_BASIC},
+ {"encrypt passwords", P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC},
+ {"update encrypted", P_BOOL, P_GLOBAL, &Globals.bUpdateEncrypt, NULL, NULL, FLAG_BASIC},
+ {"allow trusted domains", P_BOOL, P_GLOBAL, &Globals.bAllowTrustedDomains, NULL, NULL, 0},
+ {"alternate permissions", P_BOOL, P_LOCAL, &sDefault.bAlternatePerm, NULL, NULL, FLAG_GLOBAL | FLAG_DEPRECATED},
+ {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL, 0},
+ {"min passwd length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, 0},
+ {"min password length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, 0},
+ {"map to guest", P_ENUM, P_GLOBAL, &Globals.map_to_guest, NULL, enum_map_to_guest, 0},
+ {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, 0},
+ {"obey pam restrictions", P_BOOL, P_GLOBAL, &Globals.bObeyPamRestrictions, NULL, NULL, 0},
+ {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL, NULL, 0},
+ {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL, NULL, 0},
+ {"private dir", P_STRING, P_GLOBAL, &Globals.szPrivateDir, NULL, NULL, 0},
+ {"passdb module path", P_STRING, P_GLOBAL, &Globals.szPassdbModulePath, NULL, NULL, 0},
+ {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, 0},
+ {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, 0},
+ {"root", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, 0},
+ {"guest account", P_STRING, P_GLOBAL, &Globals.szGuestaccount, NULL, NULL, FLAG_BASIC},
+
+ {"pam password change", P_BOOL, P_GLOBAL, &Globals.bPamPasswordChange, NULL, NULL, 0},
+ {"passwd program", P_STRING, P_GLOBAL, &Globals.szPasswdProgram, NULL, NULL, 0},
+ {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL, 0},
+ {"passwd chat debug", P_BOOL, P_GLOBAL, &Globals.bPasswdChatDebug, NULL, NULL, 0},
+ {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL, NULL, 0},
+ {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL, 0},
+ {"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL, NULL, 0},
+ {"unix password sync", P_BOOL, P_GLOBAL, &Globals.bUnixPasswdSync, NULL, NULL, 0},
+ {"restrict anonymous", P_BOOL, P_GLOBAL, &Globals.bRestrictAnonymous, NULL, NULL, 0},
+ {"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, 0},
+ {"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, 0},
+
+ {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, 0},
+ {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, 0},
+
+ {"invalid users", P_LIST, P_LOCAL, &sDefault.szInvalidUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"valid users", P_LIST, P_LOCAL, &sDefault.szValidUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"admin users", P_LIST, P_LOCAL, &sDefault.szAdminUsers, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"read list", P_LIST, P_LOCAL, &sDefault.readlist, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"write list", P_LIST, P_LOCAL, &sDefault.writelist, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"printer admin", P_LIST, P_LOCAL, &sDefault.printer_admin, NULL, NULL, FLAG_GLOBAL | FLAG_PRINT},
+ {"force user", P_STRING, P_LOCAL, &sDefault.force_user, NULL, NULL, FLAG_SHARE},
+ {"force group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL, FLAG_SHARE},
+ {"group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL, 0},
+
+ {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_BASIC | FLAG_SHARE},
+ {"write ok", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL, 0},
+ {"writeable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL, 0},
+ {"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL, 0},
+
+ {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_GLOBAL},
+ {"force create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_force_mode, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"security mask", P_OCTAL, P_LOCAL, &sDefault.iSecurity_mask, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"force security mode", P_OCTAL, P_LOCAL, &sDefault.iSecurity_force_mode, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"directory mask", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL, NULL, FLAG_GLOBAL},
+ {"force directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_force_mode, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"directory security mask", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_mask, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"force directory security mode", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_force_mode, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
+ {"inherit permissions", P_BOOL, P_LOCAL, &sDefault.bInheritPerms, NULL, NULL, FLAG_SHARE},
+ {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_SHARE},
+ {"only guest", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, 0},
+
+ {"guest ok", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL, FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"public", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL, 0},
+
+ {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL, NULL, FLAG_SHARE},
+ {"hosts allow", P_LIST, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"allow hosts", P_LIST, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, 0},
+ {"hosts deny", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"deny hosts", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, 0},
+
+#ifdef WITH_SSL
+ {"Secure Socket Layer Options", P_SEP, P_SEPARATOR},
+ {"ssl", P_BOOL, P_GLOBAL, &Globals.sslEnabled, NULL, NULL, 0},
+
+ {"ssl hosts", P_LIST, P_GLOBAL, &Globals.sslHostsRequire, NULL, NULL, 0},
+ {"ssl hosts resign", P_LIST, P_GLOBAL, &Globals.sslHostsResign, NULL, NULL, 0},
+ {"ssl CA certDir", P_STRING, P_GLOBAL, &Globals.sslCaCertDir, NULL, NULL, 0},
+ {"ssl CA certFile", P_STRING, P_GLOBAL, &Globals.sslCaCertFile, NULL, NULL, 0},
+ {"ssl server cert", P_STRING, P_GLOBAL, &Globals.sslServerCert, NULL, NULL, 0},
+ {"ssl server key", P_STRING, P_GLOBAL, &Globals.sslServerPrivKey, NULL, NULL, 0},
+ {"ssl client cert", P_STRING, P_GLOBAL, &Globals.sslClientCert, NULL, NULL, 0},
+ {"ssl client key", P_STRING, P_GLOBAL, &Globals.sslClientPrivKey, NULL, NULL, 0},
+ {"ssl egd socket", P_STRING, P_GLOBAL, &Globals.sslEgdSocket, NULL, NULL, 0},
+ {"ssl entropy file", P_STRING, P_GLOBAL, &Globals.sslEntropyFile, NULL, NULL, 0},
+ {"ssl entropy bytes", P_INTEGER, P_GLOBAL, &Globals.sslEntropyBytes, NULL, NULL, 0},
+ {"ssl require clientcert", P_BOOL, P_GLOBAL, &Globals.sslReqClientCert, NULL, NULL, 0},
+ {"ssl require servercert", P_BOOL, P_GLOBAL, &Globals.sslReqServerCert, NULL, NULL, 0},
+ {"ssl ciphers", P_STRING, P_GLOBAL, &Globals.sslCiphers, NULL, NULL, 0},
+ {"ssl version", P_ENUM, P_GLOBAL, &Globals.sslVersion, NULL, enum_ssl_version, 0},
+ {"ssl compatibility", P_BOOL, P_GLOBAL, &Globals.sslCompatibility, NULL, NULL, 0},
+#endif /* WITH_SSL */
+
+ {"Logging Options", P_SEP, P_SEPARATOR},
+ {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL_CLASS[DBGC_ALL], handle_debug_list, NULL, 0},
+ {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL_CLASS[DBGC_ALL], handle_debug_list, NULL, 0},
+ {"syslog", P_INTEGER, P_GLOBAL, &Globals.syslog, NULL, NULL, 0},
+ {"syslog only", P_BOOL, P_GLOBAL, &Globals.bSyslogOnly, NULL, NULL, 0},
+ {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL, NULL, 0},
+
+ {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL, NULL, 0},
+ {"timestamp logs", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, 0},
+ {"debug timestamp", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, 0},
+ {"debug hires timestamp", P_BOOL, P_GLOBAL, &Globals.bDebugHiresTimestamp, NULL, NULL, 0},
+ {"debug pid", P_BOOL, P_GLOBAL, &Globals.bDebugPid, NULL, NULL, 0},
+ {"debug uid", P_BOOL, P_GLOBAL, &Globals.bDebugUid, NULL, NULL, 0},
+
+ {"Protocol Options", P_SEP, P_SEPARATOR},
+
+ {"protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, 0},
+ {"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, 0},
+ {"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, 0},
+ {"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, 0},
+ {"unicode", P_BOOL, P_GLOBAL, &Globals.bUnicode, NULL, NULL, 0},
+ {"read bmpx", P_BOOL, P_GLOBAL, &Globals.bReadbmpx, NULL, NULL, 0},
+ {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL, 0},
+ {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL, 0},
+
+ {"nt pipe support", P_BOOL, P_GLOBAL, &Globals.bNTPipeSupport, NULL, NULL, 0},
+ {"nt acl support", P_BOOL, P_LOCAL, &sDefault.bNTAclSupport, NULL, NULL, 0},
+ {"announce version", P_STRING, P_GLOBAL, &Globals.szAnnounceVersion, NULL, NULL, 0},
+ {"announce as", P_ENUM, P_GLOBAL, &Globals.announce_as, NULL, enum_announce_as, 0},
+ {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL, NULL, 0},
+ {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL, NULL, 0},
+
+ {"name resolve order", P_STRING, P_GLOBAL, &Globals.szNameResolveOrder, NULL, NULL, 0},
+ {"max packet", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL, NULL, 0},
+ {"packet size", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL, NULL, 0},
+ {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL, NULL, 0},
+ {"max wins ttl", P_INTEGER, P_GLOBAL, &Globals.max_wins_ttl, NULL, NULL, 0},
+ {"min wins ttl", P_INTEGER, P_GLOBAL, &Globals.min_wins_ttl, NULL, NULL, 0},
+ {"time server", P_BOOL, P_GLOBAL, &Globals.bTimeServer, NULL, NULL, 0},
+ {"use spnego", P_BOOL, P_GLOBAL, &Globals.bUseSpnego, NULL, NULL, 0},
+
+ {"Tuning Options", P_SEP, P_SEPARATOR},
+
+ {"change notify timeout", P_INTEGER, P_GLOBAL, &Globals.change_notify_timeout, NULL, NULL, 0},
+ {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL, NULL, 0},
+ {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL, NULL, 0},
+ {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL, NULL, 0},
+
+ {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL, 0},
+ {"max smbd processes", P_INTEGER, P_GLOBAL, &Globals.iMaxSmbdProcesses, NULL, NULL, 0},
+ {"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL, NULL, FLAG_SHARE},
+ {"paranoid server security", P_BOOL, P_GLOBAL, &Globals.paranoid_server_security, NULL, NULL, 0},
+ {"max disk size", P_INTEGER, P_GLOBAL, &Globals.maxdisksize, NULL, NULL, 0},
+ {"max open files", P_INTEGER, P_GLOBAL, &Globals.max_open_files, NULL, NULL, 0},
+ {"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL, NULL, FLAG_PRINT},
+ {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL, NULL, 0},
+
+ {"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL, NULL, 0},
+ {"stat cache size", P_INTEGER, P_GLOBAL, &Globals.stat_cache_size, NULL, NULL, 0},
+ {"strict allocate", P_BOOL, P_LOCAL, &sDefault.bStrictAllocate, NULL, NULL, FLAG_SHARE},
+ {"strict sync", P_BOOL, P_LOCAL, &sDefault.bStrictSync, NULL, NULL, FLAG_SHARE},
+ {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL, NULL, FLAG_SHARE},
+ {"use mmap", P_BOOL, P_GLOBAL, &Globals.bUseMmap, NULL, NULL, 0},
+ {"hostname lookups", P_BOOL, P_GLOBAL, &Globals.bHostnameLookups, NULL, NULL, 0},
+ {"write cache size", P_INTEGER, P_LOCAL, &sDefault.iWriteCacheSize, NULL, NULL, FLAG_SHARE},
+
+ {"Printing Options", P_SEP, P_SEPARATOR},
+
+ {"total print jobs", P_INTEGER, P_GLOBAL, &Globals.iTotalPrintJobs, NULL, NULL, FLAG_PRINT},
+ {"max print jobs", P_INTEGER, P_LOCAL, &sDefault.iMaxPrintJobs, NULL, NULL, FLAG_PRINT},
+ {"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL, NULL, FLAG_PRINT},
+ {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, FLAG_PRINT},
+ {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, 0},
+ {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_PRINT},
+ {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, 0},
+ {"postscript", P_BOOL, P_LOCAL, &sDefault.bPostscript, NULL, NULL, FLAG_PRINT},
+ {"printing", P_ENUM, P_LOCAL, &sDefault.iPrinting, NULL, enum_printing, FLAG_PRINT | FLAG_GLOBAL},
+ {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"disable spoolss", P_BOOL, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"lprm command", P_STRING, P_LOCAL, &sDefault.szLprmcommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"lppause command", P_STRING, P_LOCAL, &sDefault.szLppausecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"queuepause command", P_STRING, P_LOCAL, &sDefault.szQueuepausecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+ {"queueresume command", P_STRING, P_LOCAL, &sDefault.szQueueresumecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+
+ {"enumports command", P_STRING, P_GLOBAL, &Globals.szEnumPortsCommand, NULL, NULL, 0},
+ {"addprinter command", P_STRING, P_GLOBAL, &Globals.szAddPrinterCommand, NULL, NULL, 0},
+ {"deleteprinter command", P_STRING, P_GLOBAL, &Globals.szDeletePrinterCommand, NULL, NULL, 0},
+ {"show add printer wizard", P_BOOL, P_GLOBAL, &Globals.bMsAddPrinterWizard, NULL, NULL, 0},
+ {"os2 driver map", P_STRING, P_GLOBAL, &Globals.szOs2DriverMap, NULL, NULL, 0},
+
+ {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_PRINT},
+ {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, 0},
+ {"use client driver", P_BOOL, P_LOCAL, &sDefault.bUseClientDriver, NULL, NULL, FLAG_PRINT},
+ {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL, NULL, FLAG_PRINT},
+ {"printer driver file", P_STRING, P_LOCAL, &sDefault.szDriverFile, NULL, NULL, FLAG_PRINT},
+ {"printer driver location", P_STRING, P_LOCAL, &sDefault.szPrinterDriverLocation, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
+
+ {"Filename Handling", P_SEP, P_SEPARATOR},
+ {"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL, NULL, 0},
+
+ {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL, NULL, 0},
+ {"default case", P_ENUM, P_LOCAL, &sDefault.iDefaultCase, NULL, enum_case, FLAG_SHARE},
+ {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, 0},
+ {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"short preserve case", P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"mangle case", P_BOOL, P_LOCAL, &sDefault.bCaseMangle, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"hide unreadable", P_BOOL, P_LOCAL, &sDefault.bHideUnReadable, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"delete veto files", P_BOOL, P_LOCAL, &sDefault.bDeleteVetoFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL },
+ {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL },
+ {"veto oplock files", P_STRING, P_LOCAL, &sDefault.szVetoOplockFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL },
+ {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"stat cache", P_BOOL, P_GLOBAL, &Globals.bStatCache, NULL, NULL, 0},
+
+ {"Domain Options", P_SEP, P_SEPARATOR},
+
+ {"machine password timeout", P_INTEGER, P_GLOBAL, &Globals.machine_password_timeout, NULL, NULL, 0},
+
+ {"Logon Options", P_SEP, P_SEPARATOR},
+
+ {"add user script", P_STRING, P_GLOBAL, &Globals.szAddUserScript, NULL, NULL, 0},
+ {"delete user script", P_STRING, P_GLOBAL, &Globals.szDelUserScript, NULL, NULL, 0},
+ {"add group script", P_STRING, P_GLOBAL, &Globals.szAddGroupScript, NULL, NULL, 0},
+ {"delete group script", P_STRING, P_GLOBAL, &Globals.szDelGroupScript, NULL, NULL, 0},
+ {"add user to group script", P_STRING, P_GLOBAL, &Globals.szAddUserToGroupScript, NULL, NULL, 0},
+ {"delete user from group script", P_STRING, P_GLOBAL, &Globals.szDelUserToGroupScript, NULL, NULL, 0},
+ {"add machine script", P_STRING, P_GLOBAL, &Globals.szAddMachineScript, NULL, NULL, 0},
+ {"shutdown script", P_STRING, P_GLOBAL, &Globals.szShutdownScript, NULL, NULL, 0},
+ {"abort shutdown script", P_STRING, P_GLOBAL, &Globals.szAbortShutdownScript, NULL, NULL, 0},
+
+ {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL, NULL, 0},
+ {"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL, NULL, 0},
+ {"logon drive", P_STRING, P_GLOBAL, &Globals.szLogonDrive, NULL, NULL, 0},
+ {"logon home", P_STRING, P_GLOBAL, &Globals.szLogonHome, NULL, NULL, 0},
+ {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL, NULL, 0},
+
+ {"Browse Options", P_SEP, P_SEPARATOR},
+
+ {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL, NULL, FLAG_BASIC},
+ {"lm announce", P_ENUM, P_GLOBAL, &Globals.lm_announce, NULL, enum_bool_auto, 0},
+ {"lm interval", P_INTEGER, P_GLOBAL, &Globals.lm_interval, NULL, NULL, 0},
+ {"preferred master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_BASIC},
+ {"prefered master", P_ENUM, P_GLOBAL, &Globals.bPreferredMaster, NULL, enum_bool_auto, FLAG_HIDE},
+ {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL, NULL, FLAG_BASIC},
+ {"domain master", P_ENUM, P_GLOBAL, &Globals.bDomainMaster, NULL, enum_bool_auto, FLAG_BASIC},
+ {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL, NULL, 0},
+ {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, 0},
+ {"enhanced browsing", P_BOOL, P_GLOBAL, &Globals.enhanced_browsing, NULL, NULL},
+
+ {"WINS Options", P_SEP, P_SEPARATOR},
+ {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, NULL, NULL, 0},
+ {"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL, NULL, 0},
+
+ {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, handle_wins_server_list, NULL, FLAG_BASIC},
+ {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC},
+ {"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, 0},
+
+ {"Locking Options", P_SEP, P_SEPARATOR},
+
+ {"blocking locks", P_BOOL, P_LOCAL, &sDefault.bBlockingLocks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"fake oplocks", P_BOOL, P_LOCAL, &sDefault.bFakeOplocks, NULL, NULL, FLAG_SHARE},
+ {"kernel oplocks", P_BOOL, P_GLOBAL, &Globals.bKernelOplocks, NULL, NULL, FLAG_GLOBAL},
+ {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+
+ {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"level2 oplocks", P_BOOL, P_LOCAL, &sDefault.bLevel2OpLocks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"oplock break wait time", P_INTEGER, P_GLOBAL, &Globals.oplock_break_wait_time, NULL, NULL, FLAG_GLOBAL},
+ {"oplock contention limit", P_INTEGER, P_LOCAL, &sDefault.iOplockContentionLimit, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"posix locking", P_BOOL, P_LOCAL, &sDefault.bPosixLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"share modes", P_BOOL, P_LOCAL, &sDefault.bShareModes, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+
+#ifdef WITH_LDAP_SAM
+ {"Ldap Options", P_SEP, P_SEPARATOR},
+
+ {"ldap server", P_STRING, P_GLOBAL, &Globals.szLdapServer, NULL, NULL, 0},
+ {"ldap port", P_INTEGER, P_GLOBAL, &Globals.ldap_port, NULL, NULL, 0},
+ {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, 0},
+ {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, 0},
+ {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, 0},
+ {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, 0},
+#endif /* WITH_LDAP_SAM */
+
+ {"Miscellaneous Options", P_SEP, P_SEPARATOR},
+ {"add share command", P_STRING, P_GLOBAL, &Globals.szAddShareCommand, NULL, NULL, 0},
+ {"change share command", P_STRING, P_GLOBAL, &Globals.szChangeShareCommand, NULL, NULL, 0},
+ {"delete share command", P_STRING, P_GLOBAL, &Globals.szDeleteShareCommand, NULL, NULL, 0},
+
+ {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL, FLAG_HIDE},
+ {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, 0},
+ {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL, 0},
+ {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, 0},
+ {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL, 0},
+#ifdef WITH_UTMP
+ {"utmp directory", P_STRING, P_GLOBAL, &Globals.szUtmpDir, NULL, NULL, 0},
+ {"wtmp directory", P_STRING, P_GLOBAL, &Globals.szWtmpDir, NULL, NULL, 0},
+ {"utmp", P_BOOL, P_GLOBAL, &Globals.bUtmp, NULL, NULL, 0},
#endif
- string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
- string_set(&Globals.szLockDir, LOCKDIR);
- string_set(&Globals.szRootdir, "/");
- sprintf(s,"Samba %s",VERSION);
- string_set(&Globals.szServerString,s);
- Globals.bLoadPrinters = True;
- Globals.bUseRhosts = False;
- Globals.max_packet = 65535;
- Globals.mangled_stack = 50;
- Globals.max_xmit = Globals.max_packet;
- Globals.max_mux = 2;
- Globals.lpqcachetime = 10;
- Globals.pwordlevel = 0;
- Globals.deadtime = 0;
- Globals.max_log_size = 5000;
- Globals.maxprotocol = PROTOCOL_NT1;
- Globals.security = SEC_SHARE;
- Globals.bEncryptPasswords = False;
- Globals.printing = DEFAULT_PRINTING;
- Globals.bReadRaw = True;
- Globals.bWriteRaw = True;
- Globals.bReadPrediction = False;
- Globals.bReadbmpx = True;
- Globals.bNullPasswords = False;
- Globals.bStripDot = False;
- Globals.syslog = 1;
- Globals.bSyslogOnly = False;
- Globals.os_level = 0;
- Globals.max_ttl = 60*60*4; /* 2 hours default */
- Globals.bPreferredMaster = True;
- Globals.bDomainMaster = False;
- Globals.bDomainLogons = False;
- Globals.bBrowseList = True;
-
-#ifdef KANJI
- coding_system = interpret_coding_system (KANJI, SJIS_CODE);
-#endif /* KANJI */
+
+ {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL, 0},
+ {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL, 0},
+ {"message command", P_STRING, P_GLOBAL, &Globals.szMsgCommand, NULL, NULL, 0},
+ {"dfree command", P_STRING, P_GLOBAL, &Globals.szDfree, NULL, NULL, 0},
+ {"remote announce", P_STRING, P_GLOBAL, &Globals.szRemoteAnnounce, NULL, NULL, 0},
+ {"remote browse sync", P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync, NULL, NULL, 0},
+ {"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL, NULL, 0},
+ {"homedir map", P_STRING, P_GLOBAL, &Globals.szNISHomeMapName, NULL, NULL, 0},
+ {"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL, NULL, 0},
+ {"NIS homedir", P_BOOL, P_GLOBAL, &Globals.bNISHomeMap, NULL, NULL, 0},
+ {"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL, NULL, FLAG_HIDE},
+
+ {"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy, NULL, FLAG_HIDE},
+ {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include, NULL, FLAG_HIDE},
+ {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, FLAG_SHARE | FLAG_PRINT},
+ {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, 0},
+
+ {"preexec close", P_BOOL, P_LOCAL, &sDefault.bPreexecClose, NULL, NULL, FLAG_SHARE},
+ {"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL, NULL, FLAG_SHARE | FLAG_PRINT},
+ {"root preexec", P_STRING, P_LOCAL, &sDefault.szRootPreExec, NULL, NULL, FLAG_SHARE | FLAG_PRINT},
+ {"root preexec close", P_BOOL, P_LOCAL, &sDefault.bRootpreexecClose, NULL, NULL, FLAG_SHARE},
+ {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, FLAG_SHARE | FLAG_PRINT},
+ {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_SHARE | FLAG_PRINT},
+ {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, FLAG_SHARE },
+ {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, FLAG_SHARE},
+ {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL, NULL, FLAG_SHARE},
+ {"source environment", P_STRING, P_GLOBAL, &Globals.szSourceEnv, handle_source_env, NULL, 0},
+ {"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"follow symlinks", P_BOOL, P_LOCAL, &sDefault.bSymlinks, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"dont descend", P_STRING, P_LOCAL, &sDefault.szDontdescend, NULL, NULL, FLAG_SHARE},
+ {"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL, NULL, FLAG_SHARE},
+ {"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL, NULL, FLAG_SHARE},
+ {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"dos filemode", P_BOOL, P_LOCAL, &sDefault.bDosFilemode, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"dos filetimes", P_BOOL, P_LOCAL, &sDefault.bDosFiletimes, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"dos filetime resolution", P_BOOL, P_LOCAL, &sDefault.bDosFiletimeResolution, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+
+ {"fake directory create times", P_BOOL, P_LOCAL, &sDefault.bFakeDirCreateTimes, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+ {"panic action", P_STRING, P_GLOBAL, &Globals.szPanicAction, NULL, NULL, 0},
+ {"hide local users", P_BOOL, P_GLOBAL, &Globals.bHideLocalUsers, NULL,
+ NULL, 0},
+
+ {"VFS options", P_SEP, P_SEPARATOR},
+
+ {"vfs object", P_STRING, P_LOCAL, &sDefault.szVfsObjectFile, handle_vfs_object, NULL, FLAG_SHARE},
+ {"vfs options", P_STRING, P_LOCAL, &sDefault.szVfsOptions, NULL, NULL, FLAG_SHARE},
+
+
+ {"msdfs root", P_BOOL, P_LOCAL, &sDefault.bMSDfsRoot, NULL, NULL, FLAG_SHARE},
+ {"host msdfs", P_BOOL, P_GLOBAL, &Globals.bHostMSDfs, NULL, NULL, 0},
+
+ {"Winbind options", P_SEP, P_SEPARATOR},
+
+ {"winbind uid", P_STRING, P_GLOBAL, &Globals.szWinbindUID, handle_winbind_uid, NULL, 0},
+ {"winbind gid", P_STRING, P_GLOBAL, &Globals.szWinbindGID, handle_winbind_gid, NULL, 0},
+ {"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, 0},
+ {"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, 0},
+ {"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, 0},
+ {"winbind cache time", P_INTEGER, P_GLOBAL, &Globals.winbind_cache_time, NULL, NULL, 0},
+ {"winbind enum users", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumUsers, NULL, NULL, 0},
+ {"winbind enum groups", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumGroups, NULL, NULL, 0},
+
+ {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
+};
-}
/***************************************************************************
-check if a string is initialised and if not then initialise it
+Initialise the sDefault parameter structure for the printer values.
***************************************************************************/
-static void string_initial(char **s,char *v)
+static void init_printer_values(void)
{
- if (!*s || !**s)
- string_init(s,v);
-}
+ string_set(&sDefault.szPrinterDriver, "");
+ string_set(&sDefault.szDriverFile, dyn_DRIVERFILE);
+
+ /* choose defaults depending on the type of printing */
+ switch (sDefault.iPrinting)
+ {
+ case PRINT_BSD:
+ case PRINT_AIX:
+ case PRINT_LPRNT:
+ case PRINT_LPROS2:
+ string_set(&sDefault.szLpqcommand, "lpq -P%p");
+ string_set(&sDefault.szLprmcommand, "lprm -P%p %j");
+ string_set(&sDefault.szPrintcommand,
+ "lpr -r -P%p %s");
+ break;
+
+ case PRINT_LPRNG:
+ case PRINT_PLP:
+ string_set(&sDefault.szLpqcommand, "lpq -P%p");
+ string_set(&sDefault.szLprmcommand, "lprm -P%p %j");
+ string_set(&sDefault.szPrintcommand,
+ "lpr -r -P%p %s");
+ string_set(&sDefault.szQueuepausecommand,
+ "lpc stop %p");
+ string_set(&sDefault.szQueueresumecommand,
+ "lpc start %p");
+ string_set(&sDefault.szLppausecommand,
+ "lpc hold %p %j");
+ string_set(&sDefault.szLpresumecommand,
+ "lpc release %p %j");
+ break;
+
+ case PRINT_CUPS:
+#ifdef HAVE_CUPS
+ string_set(&sDefault.szLpqcommand, "");
+ string_set(&sDefault.szLprmcommand, "");
+ string_set(&sDefault.szPrintcommand, "");
+ string_set(&sDefault.szLppausecommand, "");
+ string_set(&sDefault.szLpresumecommand, "");
+ string_set(&sDefault.szQueuepausecommand, "");
+ string_set(&sDefault.szQueueresumecommand, "");
+
+ string_set(&Globals.szPrintcapname, "cups");
+#else
+ string_set(&sDefault.szLpqcommand,
+ "/usr/bin/lpstat -o %p");
+ string_set(&sDefault.szLprmcommand,
+ "/usr/bin/cancel %p-%j");
+ string_set(&sDefault.szPrintcommand,
+ "/usr/bin/lp -d %p %s; rm %s");
+ string_set(&sDefault.szLppausecommand,
+ "lp -i %p-%j -H hold");
+ string_set(&sDefault.szLpresumecommand,
+ "lp -i %p-%j -H resume");
+ string_set(&sDefault.szQueuepausecommand,
+ "/usr/bin/disable %p");
+ string_set(&sDefault.szQueueresumecommand,
+ "/usr/bin/enable %p");
+ string_set(&Globals.szPrintcapname, "lpstat");
+#endif /* HAVE_CUPS */
+ break;
+
+ case PRINT_SYSV:
+ case PRINT_HPUX:
+ string_set(&sDefault.szLpqcommand, "lpstat -o%p");
+ string_set(&sDefault.szLprmcommand, "cancel %p-%j");
+ string_set(&sDefault.szPrintcommand,
+ "lp -c -d%p %s; rm %s");
+ string_set(&sDefault.szQueuepausecommand,
+ "disable %p");
+ string_set(&sDefault.szQueueresumecommand,
+ "enable %p");
+#ifndef HPUX
+ string_set(&sDefault.szLppausecommand,
+ "lp -i %p-%j -H hold");
+ string_set(&sDefault.szLpresumecommand,
+ "lp -i %p-%j -H resume");
+#endif /* SYSV */
+ break;
+
+ case PRINT_QNX:
+ string_set(&sDefault.szLpqcommand, "lpq -P%p");
+ string_set(&sDefault.szLprmcommand, "lprm -P%p %j");
+ string_set(&sDefault.szPrintcommand, "lp -r -P%p %s");
+ break;
+
+ case PRINT_SOFTQ:
+ string_set(&sDefault.szLpqcommand, "qstat -l -d%p");
+ string_set(&sDefault.szLprmcommand,
+ "qstat -s -j%j -c");
+ string_set(&sDefault.szPrintcommand,
+ "lp -d%p -s %s; rm %s");
+ string_set(&sDefault.szLppausecommand,
+ "qstat -s -j%j -h");
+ string_set(&sDefault.szLpresumecommand,
+ "qstat -s -j%j -r");
+ break;
+#ifdef DEVELOPER
+ case PRINT_TEST:
+ case PRINT_VLP:
+ string_set(&sDefault.szPrintcommand, "vlp print %p %s");
+ string_set(&sDefault.szLpqcommand, "vlp lpq %p");
+ string_set(&sDefault.szLprmcommand, "vlp lprm %p %j");
+ string_set(&sDefault.szLppausecommand, "vlp lppause %p %j");
+ string_set(&sDefault.szLpresumecommand, "vlp lpresum %p %j");
+ string_set(&sDefault.szQueuepausecommand, "vlp queuepause %p");
+ string_set(&sDefault.szQueueresumecommand, "vlp queueresume %p");
+ break;
+#endif /* DEVELOPER */
+ }
+}
/***************************************************************************
-Initialise the sDefault parameter structure.
+Initialise the global parameter structure.
***************************************************************************/
-static void init_locals(void)
-{
- /* choose defaults depending on the type of printing */
- switch (Globals.printing)
- {
- case PRINT_BSD:
- case PRINT_AIX:
- string_initial(&sDefault.szLpqcommand,"lpq -P%p");
- string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
- string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
- break;
-
- case PRINT_SYSV:
- case PRINT_HPUX:
- string_initial(&sDefault.szLpqcommand,"lpstat -o%p");
- string_initial(&sDefault.szLprmcommand,"cancel %p-%j");
- string_initial(&sDefault.szPrintcommand,"lp -c -d%p %s; rm %s");
-#ifdef SVR4
- string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
- string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
+static void init_globals(void)
+{
+ static BOOL done_init = False;
+ pstring s;
+
+ if (!done_init)
+ {
+ int i;
+ memset((void *)&Globals, '\0', sizeof(Globals));
+
+ for (i = 0; parm_table[i].label; i++)
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ parm_table[i].ptr)
+ string_set(parm_table[i].ptr, "");
+
+ string_set(&sDefault.fstype, FSTYPE_STRING);
+
+ init_printer_values();
+
+ done_init = True;
+ }
+
+
+ DEBUG(3, ("Initialising global parameters\n"));
+
+ string_set(&Globals.szSMBPasswdFile, dyn_SMB_PASSWD_FILE);
+ string_set(&Globals.szPrivateDir, dyn_PRIVATE_DIR);
+ string_set(&Globals.szPassdbModulePath, "");
+
+ string_set(&Globals.szGuestaccount, GUEST_ACCOUNT);
+
+ /*
+ * Allow the default PASSWD_CHAT to be overridden in local.h.
+ */
+ string_set(&Globals.szPasswdChat, DEFAULT_PASSWD_CHAT);
+ string_set(&Globals.szWorkGroup, WORKGROUP);
+ string_set(&Globals.szPasswdProgram, "");
+ string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
+ string_set(&Globals.szLockDir, dyn_LOCKDIR);
+ string_set(&Globals.szSocketAddress, "0.0.0.0");
+ pstrcpy(s, "Samba ");
+ pstrcat(s, VERSION);
+ string_set(&Globals.szServerString, s);
+ slprintf(s, sizeof(s) - 1, "%d.%d", DEFAULT_MAJOR_VERSION,
+ DEFAULT_MINOR_VERSION);
+ string_set(&Globals.szAnnounceVersion, s);
+
+ pstrcpy(user_socket_options, DEFAULT_SOCKET_OPTIONS);
+
+ string_set(&Globals.szLogonDrive, "");
+ /* %N is the NIS auto.home server if -DAUTOHOME is used, else same as %L */
+ string_set(&Globals.szLogonHome, "\\\\%N\\%U");
+ string_set(&Globals.szLogonPath, "\\\\%N\\%U\\profile");
+
+ string_set(&Globals.szNameResolveOrder, "lmhosts wins host bcast");
+
+ Globals.bLoadPrinters = True;
+ Globals.max_packet = 65535;
+ Globals.mangled_stack = 50;
+ Globals.max_xmit = 65535;
+ Globals.max_mux = 50; /* This is *needed* for profile support. */
+ Globals.lpqcachetime = 10;
+ Globals.bDisableSpoolss = False;
+ Globals.iMaxSmbdProcesses = 0;/* no limit specified */
+ Globals.iTotalPrintJobs = 0; /* no limit specified */
+ Globals.pwordlevel = 0;
+ Globals.unamelevel = 0;
+ Globals.deadtime = 0;
+ Globals.bLargeReadwrite = False;
+ Globals.max_log_size = 5000;
+ Globals.max_open_files = MAX_OPEN_FILES;
+ Globals.maxprotocol = PROTOCOL_NT1;
+ Globals.minprotocol = PROTOCOL_CORE;
+ Globals.security = SEC_USER;
+ Globals.paranoid_server_security = True;
+ Globals.bEncryptPasswords = True;
+ Globals.bUpdateEncrypt = False;
+ Globals.bReadRaw = True;
+ Globals.bWriteRaw = True;
+ Globals.bReadPrediction = False;
+ Globals.bReadbmpx = False;
+ Globals.bNullPasswords = False;
+ Globals.bObeyPamRestrictions = False;
+ Globals.bStripDot = False;
+ Globals.syslog = 1;
+ Globals.bSyslogOnly = False;
+ Globals.bTimestampLogs = True;
+ Globals.bDebugHiresTimestamp = False;
+ Globals.bDebugPid = False;
+ Globals.bDebugUid = False;
+ Globals.max_ttl = 60 * 60 * 24 * 3; /* 3 days default. */
+ Globals.max_wins_ttl = 60 * 60 * 24 * 6; /* 6 days default. */
+ Globals.min_wins_ttl = 60 * 60 * 6; /* 6 hours default. */
+ Globals.machine_password_timeout = 60 * 60 * 24 * 7; /* 7 days default. */
+ Globals.change_notify_timeout = 60; /* 1 minute default. */
+ Globals.ReadSize = 16 * 1024;
+ Globals.lm_announce = 2; /* = Auto: send only if LM clients found */
+ Globals.lm_interval = 60;
+ Globals.stat_cache_size = 50; /* Number of stat translations we'll keep */
+ Globals.announce_as = ANNOUNCE_AS_NT_SERVER;
+#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
+ Globals.bNISHomeMap = False;
+#ifdef WITH_NISPLUS_HOME
+ string_set(&Globals.szNISHomeMapName, "auto_home.org_dir");
+#else
+ string_set(&Globals.szNISHomeMapName, "auto.home");
+#endif
+#endif
+ Globals.bTimeServer = False;
+ Globals.bBindInterfacesOnly = False;
+ Globals.bUnixPasswdSync = False;
+ Globals.bPamPasswordChange = False;
+ Globals.bPasswdChatDebug = False;
+ Globals.bUnicode = True; /* Do unicode on the wire by default */
+ Globals.bNTPipeSupport = True; /* Do NT pipes by default. */
+ Globals.bStatCache = True; /* use stat cache by default */
+ Globals.bRestrictAnonymous = False;
+ Globals.bLanmanAuth = True; /* Do use the LanMan hash if it is available */
+ Globals.bNTLMAuth = True; /* Do use NTLMv1 if it is available (otherwise NTLMv2) */
+ Globals.map_to_guest = 0; /* By Default, "Never" */
+ Globals.min_passwd_length = MINPASSWDLENGTH; /* By Default, 5. */
+ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */
+ Globals.enhanced_browsing = True;
+#ifdef MMAP_BLACKLIST
+ Globals.bUseMmap = False;
+#else
+ Globals.bUseMmap = True;
#endif
- break;
- case PRINT_QNX:
- string_initial(&sDefault.szLpqcommand,"lpq -P%p");
- string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
- string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
- break;
+ /* hostname lookups can be very expensive and are broken on
+ a large number of sites (tridge) */
+ Globals.bHostnameLookups = False;
+
+#ifdef WITH_LDAP_SAM
+ string_set(&Globals.szLdapServer, "localhost");
+ string_set(&Globals.szLdapSuffix, "");
+ string_set(&Globals.szLdapFilter, "(&(uid=%u)(objectclass=sambaAccount))");
+ string_set(&Globals.szLdapAdminDn, "");
+ Globals.ldap_port = 389;
+ Globals.ldap_ssl = LDAP_SSL_OFF;
+#endif /* WITH_LDAP_SAM */
+
+#ifdef WITH_SSL
+ Globals.sslVersion = SMB_SSL_V23;
+ /* Globals.sslHostsRequire = NULL;
+ Globals.sslHostsResign = NULL; */
+ string_set(&Globals.sslCaCertDir, "");
+ string_set(&Globals.sslCaCertFile, "");
+ string_set(&Globals.sslServerCert, "");
+ string_set(&Globals.sslServerPrivKey, "");
+ string_set(&Globals.sslClientCert, "");
+ string_set(&Globals.sslClientPrivKey, "");
+ string_set(&Globals.sslCiphers, "");
+ string_set(&Globals.sslEgdSocket, "");
+ string_set(&Globals.sslEntropyFile, "");
+ Globals.sslEntropyBytes = 256;
+ Globals.sslEnabled = False;
+ Globals.sslReqClientCert = False;
+ Globals.sslReqServerCert = False;
+ Globals.sslCompatibility = False;
+#endif /* WITH_SSL */
+
+/* these parameters are set to defaults that are more appropriate
+ for the increasing samba install base:
+
+ as a member of the workgroup, that will possibly become a
+ _local_ master browser (lm = True). this is opposed to a forced
+ local master browser startup (pm = True).
+
+ doesn't provide WINS server service by default (wsupp = False),
+ and doesn't provide domain master browser services by default, either.
+
+*/
+
+ Globals.bMsAddPrinterWizard = True;
+ Globals.bPreferredMaster = Auto; /* depending on bDomainMaster */
+ Globals.os_level = 20;
+ Globals.bLocalMaster = True;
+ Globals.bDomainMaster = Auto; /* depending on bDomainLogons */
+ Globals.bDomainLogons = False;
+ Globals.bBrowseList = True;
+ Globals.bWINSsupport = False;
+ Globals.bWINSproxy = False;
+
+ Globals.bDNSproxy = True;
+
+ /* this just means to use them if they exist */
+ Globals.bKernelOplocks = True;
+
+ Globals.bAllowTrustedDomains = True;
+
+ string_set(&Globals.szTemplateShell, "/bin/false");
+ string_set(&Globals.szTemplateHomedir, "/home/%D/%U");
+ string_set(&Globals.szWinbindSeparator, "\\");
+
+ Globals.winbind_cache_time = 15;
+ Globals.bWinbindEnumUsers = True;
+ Globals.bWinbindEnumGroups = True;
+
+ Globals.bUseSpnego = True;
-
- }
}
+static TALLOC_CTX *lp_talloc;
+
+/******************************************************************* a
+free up temporary memory - called from the main loop
+********************************************************************/
+void lp_talloc_free(void)
+{
+ if (!lp_talloc)
+ return;
+ talloc_destroy(lp_talloc);
+ lp_talloc = NULL;
+}
/*******************************************************************
-a convenience rooutine to grab string parameters into a rotating
-static buffer, and run standard_sub_basic on them. The buffers
-can be written to by callers
+convenience routine to grab string parameters into temporary memory
+and run standard_sub_basic on them. The buffers can be written to by
+callers without affecting the source string.
********************************************************************/
-char *lp_string(char *s)
+static char *lp_string(const char *s)
{
- static pstring bufs[10];
- static int next=0;
- char *ret;
-
- ret = &bufs[next][0];
- next = (next+1)%10;
+ size_t len = s ? strlen(s) : 0;
+ char *ret;
+
+ if (!lp_talloc)
+ lp_talloc = talloc_init();
+
+ ret = (char *)talloc(lp_talloc, len + 100); /* leave room for substitution */
- if (!s)
- *ret = 0;
- else
- StrnCpy(ret,s,sizeof(pstring)-1);
+ if (!ret)
+ return NULL;
- standard_sub_basic(ret);
- return(ret);
+ if (!s)
+ *ret = 0;
+ else
+ StrnCpy(ret, s, len);
+
+ trim_string(ret, "\"", "\"");
+
+ standard_sub_basic(current_user_info.smb_name,ret);
+ return (ret);
}
@@ -653,6 +1422,8 @@ char *lp_string(char *s)
#define FN_GLOBAL_STRING(fn_name,ptr) \
char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
+#define FN_GLOBAL_LIST(fn_name,ptr) \
+ char **fn_name(void) {return(*(char ***)(ptr));}
#define FN_GLOBAL_BOOL(fn_name,ptr) \
BOOL fn_name(void) {return(*(BOOL *)(ptr));}
#define FN_GLOBAL_CHAR(fn_name,ptr) \
@@ -661,346 +1432,528 @@ char *lp_string(char *s)
int fn_name(void) {return(*(int *)(ptr));}
#define FN_LOCAL_STRING(fn_name,val) \
- char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : sDefault.val));}
+ char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i) && ServicePtrs[(i)]->val) ? ServicePtrs[(i)]->val : sDefault.val));}
+#define FN_LOCAL_LIST(fn_name,val) \
+ char **fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
#define FN_LOCAL_BOOL(fn_name,val) \
- BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
+ BOOL fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
#define FN_LOCAL_CHAR(fn_name,val) \
- char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
+ char fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
#define FN_LOCAL_INTEGER(fn_name,val) \
- int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
-
-FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
-FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
-FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
-FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
-FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
-FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
-FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
-FN_GLOBAL_STRING(lp_defaultservice,&Globals.szDefaultService)
-FN_GLOBAL_STRING(lp_msg_command,&Globals.szMsgCommand)
-FN_GLOBAL_STRING(lp_dfree_command,&Globals.szDfree)
-FN_GLOBAL_STRING(lp_hosts_equiv,&Globals.szHostsEquiv)
-FN_GLOBAL_STRING(lp_auto_services,&Globals.szAutoServices)
-FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
-FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
-FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
-FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
-FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController)
-FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
-FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet)
-FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript)
-
-FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
-FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
-FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
-FN_GLOBAL_BOOL(lp_load_printers,&Globals.bLoadPrinters)
-FN_GLOBAL_BOOL(lp_use_rhosts,&Globals.bUseRhosts)
-FN_GLOBAL_BOOL(lp_getwdcache,&use_getwd_cache)
-FN_GLOBAL_BOOL(lp_readprediction,&Globals.bReadPrediction)
-FN_GLOBAL_BOOL(lp_readbmpx,&Globals.bReadbmpx)
-FN_GLOBAL_BOOL(lp_readraw,&Globals.bReadRaw)
-FN_GLOBAL_BOOL(lp_writeraw,&Globals.bWriteRaw)
-FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords)
-FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
-FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
-FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
-FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
-
-FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
-FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
-FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
-FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
-FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
-FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
-FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
-FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
-FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
-FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
-FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
-FN_GLOBAL_INTEGER(lp_security,&Globals.security)
-FN_GLOBAL_INTEGER(lp_printing,&Globals.printing)
-FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
-FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
-FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
-
-FN_LOCAL_STRING(lp_preexec,szPreExec)
-FN_LOCAL_STRING(lp_postexec,szPostExec)
-FN_LOCAL_STRING(lp_rootpreexec,szRootPreExec)
-FN_LOCAL_STRING(lp_rootpostexec,szRootPostExec)
-FN_LOCAL_STRING(lp_servicename,szService)
-FN_LOCAL_STRING(lp_pathname,szPath)
-FN_LOCAL_STRING(lp_dontdescend,szDontdescend)
-FN_LOCAL_STRING(lp_username,szUsername)
-FN_LOCAL_STRING(lp_guestaccount,szGuestaccount)
-FN_LOCAL_STRING(lp_invalid_users,szInvalidUsers)
-FN_LOCAL_STRING(lp_valid_users,szValidUsers)
-FN_LOCAL_STRING(lp_admin_users,szAdminUsers)
-FN_LOCAL_STRING(lp_printcommand,szPrintcommand)
-FN_LOCAL_STRING(lp_lpqcommand,szLpqcommand)
-FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
-FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
-FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
-FN_LOCAL_STRING(lp_printername,szPrintername)
-FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
-FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
-FN_LOCAL_STRING(lp_magicscript,szMagicScript)
-FN_LOCAL_STRING(lp_magicoutput,szMagicOutput)
-FN_LOCAL_STRING(lp_comment,comment)
-FN_LOCAL_STRING(lp_force_user,force_user)
-FN_LOCAL_STRING(lp_force_group,force_group)
-FN_LOCAL_STRING(lp_readlist,readlist)
-FN_LOCAL_STRING(lp_writelist,writelist)
-FN_LOCAL_STRING(lp_volume,volume)
-FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
-
-FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
-FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
-FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
-FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
-FN_LOCAL_BOOL(lp_shortpreservecase,bShortCasePreserve)
-FN_LOCAL_BOOL(lp_casemangle,bCaseMangle)
-FN_LOCAL_BOOL(lp_status,status)
-FN_LOCAL_BOOL(lp_hide_dot_files,bHideDotFiles)
-FN_LOCAL_BOOL(lp_browseable,bBrowseable)
-FN_LOCAL_BOOL(lp_readonly,bRead_only)
-FN_LOCAL_BOOL(lp_no_set_dir,bNo_set_dir)
-FN_LOCAL_BOOL(lp_guest_ok,bGuest_ok)
-FN_LOCAL_BOOL(lp_guest_only,bGuest_only)
-FN_LOCAL_BOOL(lp_print_ok,bPrint_ok)
-FN_LOCAL_BOOL(lp_postscript,bPostscript)
-FN_LOCAL_BOOL(lp_map_hidden,bMap_hidden)
-FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
-FN_LOCAL_BOOL(lp_locking,bLocking)
-FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
-FN_LOCAL_BOOL(lp_share_modes,bShareModes)
-FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
-FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
-FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
-FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
-FN_LOCAL_BOOL(lp_map_system,bMap_system)
-
-FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
-FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
-FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
-FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
-
-FN_LOCAL_CHAR(lp_magicchar,magic_char)
-
-
+ int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
+
+FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
+FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
+FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
+FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
+FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
+FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
+FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
+FN_GLOBAL_STRING(lp_passdb_module_path, &Globals.szPassdbModulePath)
+FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
+FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname)
+FN_GLOBAL_STRING(lp_enumports_cmd, &Globals.szEnumPortsCommand)
+FN_GLOBAL_STRING(lp_addprinter_cmd, &Globals.szAddPrinterCommand)
+FN_GLOBAL_STRING(lp_deleteprinter_cmd, &Globals.szDeletePrinterCommand)
+FN_GLOBAL_STRING(lp_os2_driver_map, &Globals.szOs2DriverMap)
+FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
+#ifdef WITH_UTMP
+FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir)
+FN_GLOBAL_STRING(lp_wtmpdir, &Globals.szWtmpDir)
+FN_GLOBAL_BOOL(lp_utmp, &Globals.bUtmp)
+#endif
+FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
+FN_GLOBAL_STRING(lp_source_environment, &Globals.szSourceEnv)
+FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
+FN_GLOBAL_STRING(lp_msg_command, &Globals.szMsgCommand)
+FN_GLOBAL_STRING(lp_dfree_command, &Globals.szDfree)
+FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
+FN_GLOBAL_STRING(lp_auto_services, &Globals.szAutoServices)
+FN_GLOBAL_STRING(lp_passwd_program, &Globals.szPasswdProgram)
+FN_GLOBAL_STRING(lp_passwd_chat, &Globals.szPasswdChat)
+FN_GLOBAL_STRING(lp_passwordserver, &Globals.szPasswordServer)
+FN_GLOBAL_STRING(lp_name_resolve_order, &Globals.szNameResolveOrder)
+FN_GLOBAL_STRING(lp_workgroup, &Globals.szWorkGroup)
+FN_GLOBAL_STRING(lp_realm, &Globals.szRealm)
+FN_GLOBAL_STRING(lp_ads_server, &Globals.szADSserver)
+FN_GLOBAL_STRING(lp_username_map, &Globals.szUsernameMap)
+FN_GLOBAL_STRING(lp_logon_script, &Globals.szLogonScript)
+FN_GLOBAL_STRING(lp_logon_path, &Globals.szLogonPath)
+FN_GLOBAL_STRING(lp_logon_drive, &Globals.szLogonDrive)
+FN_GLOBAL_STRING(lp_logon_home, &Globals.szLogonHome)
+FN_GLOBAL_STRING(lp_remote_announce, &Globals.szRemoteAnnounce)
+FN_GLOBAL_STRING(lp_remote_browse_sync, &Globals.szRemoteBrowseSync)
+FN_GLOBAL_STRING(lp_wins_server_list, &Globals.szWINSserver)
+FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
+FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
+FN_GLOBAL_STRING(lp_nis_home_map_name, &Globals.szNISHomeMapName)
+static FN_GLOBAL_STRING(lp_announce_version, &Globals.szAnnounceVersion)
+FN_GLOBAL_LIST(lp_netbios_aliases, &Globals.szNetbiosAliases)
+FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction)
+FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript)
+FN_GLOBAL_STRING(lp_deluser_script, &Globals.szDelUserScript)
+
+FN_GLOBAL_STRING(lp_guestaccount, &Globals.szGuestaccount)
+FN_GLOBAL_STRING(lp_addgroup_script, &Globals.szAddGroupScript)
+FN_GLOBAL_STRING(lp_delgroup_script, &Globals.szDelGroupScript)
+FN_GLOBAL_STRING(lp_addusertogroup_script, &Globals.szAddUserToGroupScript)
+FN_GLOBAL_STRING(lp_deluserfromgroup_script, &Globals.szDelUserToGroupScript)
+
+FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
+
+FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript)
+FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
+
+FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
+FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
+FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
+FN_GLOBAL_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
+FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
+FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
+#ifdef WITH_LDAP_SAM
+FN_GLOBAL_STRING(lp_ldap_server, &Globals.szLdapServer)
+FN_GLOBAL_STRING(lp_ldap_suffix, &Globals.szLdapSuffix)
+FN_GLOBAL_STRING(lp_ldap_filter, &Globals.szLdapFilter)
+FN_GLOBAL_STRING(lp_ldap_admin_dn, &Globals.szLdapAdminDn)
+FN_GLOBAL_INTEGER(lp_ldap_port, &Globals.ldap_port)
+FN_GLOBAL_INTEGER(lp_ldap_ssl, &Globals.ldap_ssl)
+#endif /* WITH_LDAP_SAM */
+FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand)
+FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand)
+FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand)
+
+#ifdef WITH_SSL
+FN_GLOBAL_INTEGER(lp_ssl_version, &Globals.sslVersion)
+FN_GLOBAL_LIST(lp_ssl_hosts, &Globals.sslHostsRequire)
+FN_GLOBAL_LIST(lp_ssl_hosts_resign, &Globals.sslHostsResign)
+FN_GLOBAL_STRING(lp_ssl_cacertdir, &Globals.sslCaCertDir)
+FN_GLOBAL_STRING(lp_ssl_cacertfile, &Globals.sslCaCertFile)
+FN_GLOBAL_STRING(lp_ssl_server_cert, &Globals.sslServerCert)
+FN_GLOBAL_STRING(lp_ssl_server_privkey, &Globals.sslServerPrivKey)
+FN_GLOBAL_STRING(lp_ssl_client_cert, &Globals.sslClientCert)
+FN_GLOBAL_STRING(lp_ssl_client_privkey, &Globals.sslClientPrivKey)
+FN_GLOBAL_STRING(lp_ssl_ciphers, &Globals.sslCiphers)
+FN_GLOBAL_STRING(lp_ssl_egdsocket, &Globals.sslEgdSocket)
+FN_GLOBAL_STRING(lp_ssl_entropyfile, &Globals.sslEntropyFile)
+FN_GLOBAL_INTEGER(lp_ssl_entropybytes, &Globals.sslEntropyBytes)
+FN_GLOBAL_BOOL(lp_ssl_enabled, &Globals.sslEnabled)
+FN_GLOBAL_BOOL(lp_ssl_reqClientCert, &Globals.sslReqClientCert)
+FN_GLOBAL_BOOL(lp_ssl_reqServerCert, &Globals.sslReqServerCert)
+FN_GLOBAL_BOOL(lp_ssl_compatibility, &Globals.sslCompatibility)
+#endif /* WITH_SSL */
+
+FN_GLOBAL_BOOL(lp_ms_add_printer_wizard, &Globals.bMsAddPrinterWizard)
+FN_GLOBAL_BOOL(lp_dns_proxy, &Globals.bDNSproxy)
+FN_GLOBAL_BOOL(lp_wins_support, &Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_we_are_a_wins_server, &Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy)
+FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
+FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons)
+FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters)
+FN_GLOBAL_BOOL(lp_readprediction, &Globals.bReadPrediction)
+FN_GLOBAL_BOOL(lp_readbmpx, &Globals.bReadbmpx)
+FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
+FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
+FN_GLOBAL_BOOL(lp_writeraw, &Globals.bWriteRaw)
+FN_GLOBAL_BOOL(lp_null_passwords, &Globals.bNullPasswords)
+FN_GLOBAL_BOOL(lp_obey_pam_restrictions, &Globals.bObeyPamRestrictions)
+FN_GLOBAL_BOOL(lp_strip_dot, &Globals.bStripDot)
+FN_GLOBAL_BOOL(lp_encrypted_passwords, &Globals.bEncryptPasswords)
+FN_GLOBAL_BOOL(lp_update_encrypted, &Globals.bUpdateEncrypt)
+FN_GLOBAL_BOOL(lp_syslog_only, &Globals.bSyslogOnly)
+FN_GLOBAL_BOOL(lp_timestamp_logs, &Globals.bTimestampLogs)
+FN_GLOBAL_BOOL(lp_debug_hires_timestamp, &Globals.bDebugHiresTimestamp)
+FN_GLOBAL_BOOL(lp_debug_pid, &Globals.bDebugPid)
+FN_GLOBAL_BOOL(lp_debug_uid, &Globals.bDebugUid)
+FN_GLOBAL_BOOL(lp_browse_list, &Globals.bBrowseList)
+FN_GLOBAL_BOOL(lp_nis_home_map, &Globals.bNISHomeMap)
+static FN_GLOBAL_BOOL(lp_time_server, &Globals.bTimeServer)
+FN_GLOBAL_BOOL(lp_bind_interfaces_only, &Globals.bBindInterfacesOnly)
+FN_GLOBAL_BOOL(lp_pam_password_change, &Globals.bPamPasswordChange)
+FN_GLOBAL_BOOL(lp_unix_password_sync, &Globals.bUnixPasswdSync)
+FN_GLOBAL_BOOL(lp_passwd_chat_debug, &Globals.bPasswdChatDebug)
+FN_GLOBAL_BOOL(lp_unicode, &Globals.bUnicode)
+FN_GLOBAL_BOOL(lp_nt_pipe_support, &Globals.bNTPipeSupport)
+FN_GLOBAL_BOOL(lp_stat_cache, &Globals.bStatCache)
+FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
+FN_GLOBAL_BOOL(lp_restrict_anonymous, &Globals.bRestrictAnonymous)
+FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
+FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
+FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
+FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)
+FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing)
+FN_GLOBAL_BOOL(lp_use_mmap, &Globals.bUseMmap)
+FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
+FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
+FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
+FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
+FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
+FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
+FN_GLOBAL_INTEGER(lp_max_log_size, &Globals.max_log_size)
+FN_GLOBAL_INTEGER(lp_max_open_files, &Globals.max_open_files)
+FN_GLOBAL_INTEGER(lp_maxxmit, &Globals.max_xmit)
+FN_GLOBAL_INTEGER(lp_maxmux, &Globals.max_mux)
+FN_GLOBAL_INTEGER(lp_passwordlevel, &Globals.pwordlevel)
+FN_GLOBAL_INTEGER(lp_usernamelevel, &Globals.unamelevel)
+FN_GLOBAL_INTEGER(lp_readsize, &Globals.ReadSize)
+FN_GLOBAL_INTEGER(lp_deadtime, &Globals.deadtime)
+FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol)
+FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol)
+FN_GLOBAL_INTEGER(lp_security, &Globals.security)
+FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods)
+FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security)
+FN_GLOBAL_INTEGER(lp_maxdisksize, &Globals.maxdisksize)
+FN_GLOBAL_INTEGER(lp_lpqcachetime, &Globals.lpqcachetime)
+FN_GLOBAL_INTEGER(lp_max_smbd_processes, &Globals.iMaxSmbdProcesses)
+FN_GLOBAL_INTEGER(lp_disable_spoolss, &Globals.bDisableSpoolss)
+FN_GLOBAL_INTEGER(lp_totalprintjobs, &Globals.iTotalPrintJobs)
+FN_GLOBAL_INTEGER(lp_syslog, &Globals.syslog)
+static FN_GLOBAL_INTEGER(lp_announce_as, &Globals.announce_as)
+FN_GLOBAL_INTEGER(lp_lm_announce, &Globals.lm_announce)
+FN_GLOBAL_INTEGER(lp_lm_interval, &Globals.lm_interval)
+FN_GLOBAL_INTEGER(lp_machine_password_timeout, &Globals.machine_password_timeout)
+FN_GLOBAL_INTEGER(lp_change_notify_timeout, &Globals.change_notify_timeout)
+FN_GLOBAL_INTEGER(lp_stat_cache_size, &Globals.stat_cache_size)
+FN_GLOBAL_INTEGER(lp_map_to_guest, &Globals.map_to_guest)
+FN_GLOBAL_INTEGER(lp_min_passwd_length, &Globals.min_passwd_length)
+FN_GLOBAL_INTEGER(lp_oplock_break_wait_time, &Globals.oplock_break_wait_time)
+FN_LOCAL_STRING(lp_preexec, szPreExec)
+FN_LOCAL_STRING(lp_postexec, szPostExec)
+FN_LOCAL_STRING(lp_rootpreexec, szRootPreExec)
+FN_LOCAL_STRING(lp_rootpostexec, szRootPostExec)
+FN_LOCAL_STRING(lp_servicename, szService)
+FN_LOCAL_STRING(lp_pathname, szPath)
+FN_LOCAL_STRING(lp_dontdescend, szDontdescend)
+FN_LOCAL_STRING(lp_username, szUsername)
+FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
+FN_LOCAL_LIST(lp_valid_users, szValidUsers)
+FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
+FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
+FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
+FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
+FN_LOCAL_STRING(lp_lppausecommand, szLppausecommand)
+FN_LOCAL_STRING(lp_lpresumecommand, szLpresumecommand)
+FN_LOCAL_STRING(lp_queuepausecommand, szQueuepausecommand)
+FN_LOCAL_STRING(lp_queueresumecommand, szQueueresumecommand)
+static FN_LOCAL_STRING(_lp_printername, szPrintername)
+FN_LOCAL_STRING(lp_driverfile, szDriverFile)
+FN_LOCAL_STRING(lp_printerdriver, szPrinterDriver)
+FN_LOCAL_LIST(lp_hostsallow, szHostsallow)
+FN_LOCAL_LIST(lp_hostsdeny, szHostsdeny)
+FN_LOCAL_STRING(lp_magicscript, szMagicScript)
+FN_LOCAL_STRING(lp_magicoutput, szMagicOutput)
+FN_LOCAL_STRING(lp_comment, comment)
+FN_LOCAL_STRING(lp_force_user, force_user)
+FN_LOCAL_STRING(lp_force_group, force_group)
+FN_LOCAL_LIST(lp_readlist, readlist)
+FN_LOCAL_LIST(lp_writelist, writelist)
+FN_LOCAL_LIST(lp_printer_admin, printer_admin)
+FN_LOCAL_STRING(lp_fstype, fstype)
+FN_LOCAL_STRING(lp_vfsobj, szVfsObjectFile)
+static FN_LOCAL_STRING(lp_volume, volume)
+FN_LOCAL_STRING(lp_mangled_map, szMangledMap)
+FN_LOCAL_STRING(lp_veto_files, szVetoFiles)
+FN_LOCAL_STRING(lp_hide_files, szHideFiles)
+FN_LOCAL_STRING(lp_veto_oplocks, szVetoOplockFiles)
+FN_LOCAL_STRING(lp_driverlocation, szPrinterDriverLocation)
+FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
+FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
+FN_LOCAL_BOOL(lp_preexec_close, bPreexecClose)
+FN_LOCAL_BOOL(lp_rootpreexec_close, bRootpreexecClose)
+FN_LOCAL_BOOL(lp_casesensitive, bCaseSensitive)
+FN_LOCAL_BOOL(lp_preservecase, bCasePreserve)
+FN_LOCAL_BOOL(lp_shortpreservecase, bShortCasePreserve)
+FN_LOCAL_BOOL(lp_casemangle, bCaseMangle)
+FN_LOCAL_BOOL(lp_hide_dot_files, bHideDotFiles)
+FN_LOCAL_BOOL(lp_hideunreadable, bHideUnReadable)
+FN_LOCAL_BOOL(lp_browseable, bBrowseable)
+FN_LOCAL_BOOL(lp_readonly, bRead_only)
+FN_LOCAL_BOOL(lp_no_set_dir, bNo_set_dir)
+FN_LOCAL_BOOL(lp_guest_ok, bGuest_ok)
+FN_LOCAL_BOOL(lp_guest_only, bGuest_only)
+FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
+FN_LOCAL_BOOL(lp_postscript, bPostscript)
+FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
+FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
+FN_LOCAL_BOOL(lp_locking, bLocking)
+FN_LOCAL_BOOL(lp_strict_locking, bStrictLocking)
+FN_LOCAL_BOOL(lp_posix_locking, bPosixLocking)
+FN_LOCAL_BOOL(lp_share_modes, bShareModes)
+FN_LOCAL_BOOL(lp_oplocks, bOpLocks)
+FN_LOCAL_BOOL(lp_level2_oplocks, bLevel2OpLocks)
+FN_LOCAL_BOOL(lp_onlyuser, bOnlyUser)
+FN_LOCAL_BOOL(lp_manglednames, bMangledNames)
+FN_LOCAL_BOOL(lp_widelinks, bWidelinks)
+FN_LOCAL_BOOL(lp_symlinks, bSymlinks)
+FN_LOCAL_BOOL(lp_syncalways, bSyncAlways)
+FN_LOCAL_BOOL(lp_strict_allocate, bStrictAllocate)
+FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
+FN_LOCAL_BOOL(lp_map_system, bMap_system)
+FN_LOCAL_BOOL(lp_delete_readonly, bDeleteReadonly)
+FN_LOCAL_BOOL(lp_fake_oplocks, bFakeOplocks)
+FN_LOCAL_BOOL(lp_recursive_veto_delete, bDeleteVetoFiles)
+FN_LOCAL_BOOL(lp_dos_filemode, bDosFilemode)
+FN_LOCAL_BOOL(lp_dos_filetimes, bDosFiletimes)
+FN_LOCAL_BOOL(lp_dos_filetime_resolution, bDosFiletimeResolution)
+FN_LOCAL_BOOL(lp_fake_dir_create_times, bFakeDirCreateTimes)
+FN_LOCAL_BOOL(lp_blocking_locks, bBlockingLocks)
+FN_LOCAL_BOOL(lp_inherit_perms, bInheritPerms)
+FN_LOCAL_BOOL(lp_use_client_driver, bUseClientDriver)
+FN_LOCAL_BOOL(lp_nt_acl_support, bNTAclSupport)
+FN_LOCAL_INTEGER(lp_create_mask, iCreate_mask)
+FN_LOCAL_INTEGER(lp_force_create_mode, iCreate_force_mode)
+FN_LOCAL_INTEGER(lp_security_mask, iSecurity_mask)
+FN_LOCAL_INTEGER(lp_force_security_mode, iSecurity_force_mode)
+FN_LOCAL_INTEGER(lp_dir_mask, iDir_mask)
+FN_LOCAL_INTEGER(lp_force_dir_mode, iDir_force_mode)
+FN_LOCAL_INTEGER(lp_dir_security_mask, iDir_Security_mask)
+FN_LOCAL_INTEGER(lp_force_dir_security_mode, iDir_Security_force_mode)
+FN_LOCAL_INTEGER(lp_max_connections, iMaxConnections)
+FN_LOCAL_INTEGER(lp_defaultcase, iDefaultCase)
+FN_LOCAL_INTEGER(lp_minprintspace, iMinPrintSpace)
+FN_LOCAL_INTEGER(lp_maxprintjobs, iMaxPrintJobs)
+FN_LOCAL_INTEGER(lp_printing, iPrinting)
+FN_LOCAL_INTEGER(lp_oplock_contention_limit, iOplockContentionLimit)
+FN_LOCAL_INTEGER(lp_write_cache_size, iWriteCacheSize)
+FN_LOCAL_CHAR(lp_magicchar, magic_char)
+FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
+FN_GLOBAL_BOOL(lp_hide_local_users, &Globals.bHideLocalUsers)
/* local prototypes */
-static int strwicmp( char *psz1, char *psz2 );
-static int map_parameter( char *pszParmName);
-static BOOL set_boolean( BOOL *pb, char *pszParmValue );
-static int getservicebyname(char *pszServiceName, service *pserviceDest);
-static void copy_service( service *pserviceDest,
- service *pserviceSource,
- BOOL *pcopymapDest );
-static BOOL service_ok(int iService);
-static BOOL do_parameter(char *pszParmName, char *pszParmValue);
-static BOOL do_section(char *pszSectionName);
-static void dump_globals(void);
-static void dump_a_service(service *pService);
-static void init_copymap(service *pservice);
+
+static int map_parameter(char *pszParmName);
+static BOOL set_boolean(BOOL *pb, char *pszParmValue);
+static int getservicebyname(const char *pszServiceName,
+ service * pserviceDest);
+static void copy_service(service * pserviceDest,
+ service * pserviceSource, BOOL *pcopymapDest);
+static BOOL service_ok(int iService);
+static BOOL do_parameter(char *pszParmName, char *pszParmValue);
+static BOOL do_section(char *pszSectionName);
+static void init_copymap(service * pservice);
/***************************************************************************
initialise a service to the defaults
***************************************************************************/
-static void init_service(service *pservice)
+static void init_service(service * pservice)
{
- bzero((char *)pservice,sizeof(service));
- copy_service(pservice,&sDefault,NULL);
+ memset((char *)pservice, '\0', sizeof(service));
+ copy_service(pservice, &sDefault, NULL);
}
/***************************************************************************
free the dynamically allocated parts of a service struct
***************************************************************************/
-static void free_service(service *pservice)
+static void free_service(service * pservice)
{
- int i;
- if (!pservice)
- return;
+ int i;
+ if (!pservice)
+ return;
+
+ if (pservice->szService)
+ DEBUG(5,
+ ("free_service: Freeing service %s\n",
+ pservice->szService));
+
+ string_free(&pservice->szService);
+ SAFE_FREE(pservice->copymap);
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].type == P_STRING && parm_table[i].class == P_LOCAL)
- string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
+ for (i = 0; parm_table[i].label; i++)
+ {
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ parm_table[i].class == P_LOCAL)
+ string_free((char **)
+ (((char *)pservice) +
+ PTR_DIFF(parm_table[i].ptr, &sDefault)));
+ else if (parm_table[i].type == P_LIST &&
+ parm_table[i].class == P_LOCAL)
+ lp_list_free((char ***)
+ (((char *)pservice) +
+ PTR_DIFF(parm_table[i].ptr, &sDefault)));
+ }
+
+
+ ZERO_STRUCTP(pservice);
}
/***************************************************************************
add a new service to the services array initialising it with the given
-service
+service.
***************************************************************************/
-static int add_a_service(service *pservice, char *name)
+static int add_a_service(const service * pservice, const char *name)
{
- int i;
- service tservice;
- int num_to_alloc = iNumServices+1;
-
- tservice = *pservice;
+ int i;
+ service tservice;
+ int num_to_alloc = iNumServices + 1;
- /* it might already exist */
- if (name)
- {
- i = getservicebyname(name,NULL);
- if (i >= 0)
- return(i);
- }
+ tservice = *pservice;
- /* find an invalid one */
- for (i=0;i<iNumServices;i++)
- if (!pSERVICE(i)->valid)
- break;
-
- /* if not, then create one */
- if (i == iNumServices)
- {
- ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
- if (ServicePtrs)
- pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
-
- if (!ServicePtrs || !pSERVICE(iNumServices))
- return(-1);
+ /* it might already exist */
+ if (name)
+ {
+ i = getservicebyname(name, NULL);
+ if (i >= 0)
+ return (i);
+ }
- iNumServices++;
- }
- else
- free_service(pSERVICE(i));
+ /* find an invalid one */
+ for (i = 0; i < iNumServices; i++)
+ if (!ServicePtrs[i]->valid)
+ break;
- pSERVICE(i)->valid = True;
+ /* if not, then create one */
+ if (i == iNumServices)
+ {
+ service **tsp;
+
+ tsp = (service **) Realloc(ServicePtrs,
+ sizeof(service *) *
+ num_to_alloc);
+
+ if (!tsp) {
+ DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
+ return (-1);
+ }
+ else {
+ ServicePtrs = tsp;
+ ServicePtrs[iNumServices] =
+ (service *) malloc(sizeof(service));
+ }
+ if (!ServicePtrs[iNumServices]) {
+ DEBUG(0,("add_a_service: out of memory!\n"));
+ return (-1);
+ }
+
+ iNumServices++;
+ }
+ else
+ free_service(ServicePtrs[i]);
- init_service(pSERVICE(i));
- copy_service(pSERVICE(i),&tservice,NULL);
- if (name)
- string_set(&iSERVICE(i).szService,name);
+ ServicePtrs[i]->valid = True;
- return(i);
+ init_service(ServicePtrs[i]);
+ copy_service(ServicePtrs[i], &tservice, NULL);
+ if (name)
+ {
+ string_set(&ServicePtrs[i]->szService, name);
+ }
+ return (i);
}
/***************************************************************************
add a new home service, with the specified home directory, defaults coming
-from service ifrom
+from service ifrom.
***************************************************************************/
-BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
+BOOL lp_add_home(const char *pszHomename, int iDefaultService, const char *pszHomedir)
{
- int i = add_a_service(pSERVICE(iDefaultService),pszHomename);
+ int i;
+ SMB_STRUCT_STAT buf;
- if (i < 0)
- return(False);
+ /* if the user's home directory doesn't exist, then don't
+ add it to the list of available shares */
+ if (sys_stat(pszHomedir, &buf))
+ return False;
- if (!(*(iSERVICE(i).szPath)) || strequal(iSERVICE(i).szPath,lp_pathname(-1)))
- string_set(&iSERVICE(i).szPath,pszHomedir);
- if (!(*(iSERVICE(i).comment)))
- {
- pstring comment;
- sprintf(comment,"Home directory of %s",pszHomename);
- string_set(&iSERVICE(i).comment,comment);
- }
- iSERVICE(i).bAvailable = sDefault.bAvailable;
- iSERVICE(i).bBrowseable = sDefault.bBrowseable;
+ i = add_a_service(ServicePtrs[iDefaultService], pszHomename);
- DEBUG(3,("adding home directory %s at %s\n", pszHomename, pszHomedir));
+ if (i < 0)
+ return (False);
- return(True);
+ if (!(*(ServicePtrs[i]->szPath))
+ || strequal(ServicePtrs[i]->szPath, lp_pathname(-1)))
+ string_set(&ServicePtrs[i]->szPath, pszHomedir);
+ if (!(*(ServicePtrs[i]->comment)))
+ {
+ pstring comment;
+ slprintf(comment, sizeof(comment) - 1,
+ "Home directory of %s", pszHomename);
+ string_set(&ServicePtrs[i]->comment, comment);
+ }
+ ServicePtrs[i]->bAvailable = sDefault.bAvailable;
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+
+ DEBUG(3,
+ ("adding home directory %s at %s\n", pszHomename, pszHomedir));
+
+ return (True);
}
/***************************************************************************
-add a new service, based on an old one
+add a new service, based on an old one.
***************************************************************************/
int lp_add_service(char *pszService, int iDefaultService)
{
- return(add_a_service(pSERVICE(iDefaultService),pszService));
+ return (add_a_service(ServicePtrs[iDefaultService], pszService));
}
/***************************************************************************
add the IPC service
***************************************************************************/
-static BOOL lp_add_ipc(void)
+static BOOL lp_add_ipc(char *ipc_name, BOOL guest_ok)
{
- pstring comment;
- int i = add_a_service(&sDefault,"IPC$");
-
- if (i < 0)
- return(False);
-
- sprintf(comment,"IPC Service (%s)",lp_serverstring());
-
- string_set(&iSERVICE(i).szPath,"/tmp");
- string_set(&iSERVICE(i).szUsername,"");
- string_set(&iSERVICE(i).comment,comment);
- iSERVICE(i).status = False;
- iSERVICE(i).iMaxConnections = 0;
- iSERVICE(i).bAvailable = True;
- iSERVICE(i).bRead_only = True;
- iSERVICE(i).bGuest_only = False;
- iSERVICE(i).bGuest_ok = True;
- iSERVICE(i).bPrint_ok = False;
- iSERVICE(i).bBrowseable = sDefault.bBrowseable;
-
- DEBUG(3,("adding IPC service\n"));
-
- return(True);
+ pstring comment;
+ int i = add_a_service(&sDefault, ipc_name);
+
+ if (i < 0)
+ return (False);
+
+ slprintf(comment, sizeof(comment) - 1,
+ "IPC Service (%s)", Globals.szServerString);
+
+ string_set(&ServicePtrs[i]->szPath, tmpdir());
+ string_set(&ServicePtrs[i]->szUsername, "");
+ string_set(&ServicePtrs[i]->comment, comment);
+ string_set(&ServicePtrs[i]->fstype, "IPC");
+ ServicePtrs[i]->iMaxConnections = 0;
+ ServicePtrs[i]->bAvailable = True;
+ ServicePtrs[i]->bRead_only = True;
+ ServicePtrs[i]->bGuest_only = False;
+ ServicePtrs[i]->bGuest_ok = guest_ok;
+ ServicePtrs[i]->bPrint_ok = False;
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+
+ DEBUG(3, ("adding IPC service\n"));
+
+ return (True);
}
/***************************************************************************
-add a new printer service, with defaults coming from service iFrom
+add a new printer service, with defaults coming from service iFrom.
***************************************************************************/
BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
{
- char *comment = "From Printcap";
- int i = add_a_service(pSERVICE(iDefaultService),pszPrintername);
-
- if (i < 0)
- return(False);
-
- /* note that we do NOT default the availability flag to True - */
- /* we take it from the default service passed. This allows all */
- /* dynamic printers to be disabled by disabling the [printers] */
- /* entry (if/when the 'available' keyword is implemented!). */
-
- /* the printer name is set to the service name. */
- string_set(&iSERVICE(i).szPrintername,pszPrintername);
- string_set(&iSERVICE(i).comment,comment);
- iSERVICE(i).bBrowseable = sDefault.bBrowseable;
-
- DEBUG(3,("adding printer service %s\n",pszPrintername));
-
- return(True);
-}
-
-
-/***************************************************************************
-Do a case-insensitive, whitespace-ignoring string compare.
-***************************************************************************/
-static int strwicmp(char *psz1, char *psz2)
-{
- /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
- /* appropriate value. */
- if (psz1 == psz2)
- return (0);
- else
- if (psz1 == NULL)
- return (-1);
- else
- if (psz2 == NULL)
- return (1);
-
- /* sync the strings on first non-whitespace */
- while (1)
- {
- while (isspace(*psz1))
- psz1++;
- while (isspace(*psz2))
- psz2++;
- if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
- break;
- psz1++;
- psz2++;
- }
- return (*psz1 - *psz2);
+ char *comment = "From Printcap";
+ int i = add_a_service(ServicePtrs[iDefaultService], pszPrintername);
+
+ if (i < 0)
+ return (False);
+
+ /* note that we do NOT default the availability flag to True - */
+ /* we take it from the default service passed. This allows all */
+ /* dynamic printers to be disabled by disabling the [printers] */
+ /* entry (if/when the 'available' keyword is implemented!). */
+
+ /* the printer name is set to the service name. */
+ string_set(&ServicePtrs[i]->szPrintername, pszPrintername);
+ string_set(&ServicePtrs[i]->comment, comment);
+ ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+ /* Printers cannot be read_only. */
+ ServicePtrs[i]->bRead_only = False;
+ /* No share modes on printer services. */
+ ServicePtrs[i]->bShareModes = False;
+ /* No oplocks on printer services. */
+ ServicePtrs[i]->bOpLocks = False;
+ /* Printer services must be printable. */
+ ServicePtrs[i]->bPrint_ok = True;
+
+ DEBUG(3, ("adding printer service %s\n", pszPrintername));
+
+ return (True);
}
/***************************************************************************
@@ -1009,17 +1962,17 @@ Returns False if the parameter string is not recognised, else TRUE.
***************************************************************************/
static int map_parameter(char *pszParmName)
{
- int iIndex;
+ int iIndex;
- if (*pszParmName == '-')
- return(-1);
+ if (*pszParmName == '-')
+ return (-1);
- for (iIndex = 0; parm_table[iIndex].label; iIndex++)
- if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
- return(iIndex);
+ for (iIndex = 0; parm_table[iIndex].label; iIndex++)
+ if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
+ return (iIndex);
- DEBUG(0,( "Unknown parameter encountered: \"%s\"\n", pszParmName));
- return(-1);
+ DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
+ return (-1);
}
@@ -1030,44 +1983,45 @@ represent a boolean.
***************************************************************************/
static BOOL set_boolean(BOOL *pb, char *pszParmValue)
{
- BOOL bRetval;
-
- bRetval = True;
- if (strwicmp(pszParmValue, "yes") == 0 ||
- strwicmp(pszParmValue, "true") == 0 ||
- strwicmp(pszParmValue, "1") == 0)
- *pb = True;
- else
- if (strwicmp(pszParmValue, "no") == 0 ||
- strwicmp(pszParmValue, "False") == 0 ||
- strwicmp(pszParmValue, "0") == 0)
- *pb = False;
- else
- {
- DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
- pszParmValue));
- bRetval = False;
- }
- return (bRetval);
+ BOOL bRetval;
+
+ bRetval = True;
+ if (strwicmp(pszParmValue, "yes") == 0 ||
+ strwicmp(pszParmValue, "true") == 0 ||
+ strwicmp(pszParmValue, "1") == 0)
+ *pb = True;
+ else
+ if (strwicmp(pszParmValue, "no") == 0 ||
+ strwicmp(pszParmValue, "False") == 0 ||
+ strwicmp(pszParmValue, "0") == 0)
+ *pb = False;
+ else
+ {
+ DEBUG(0,
+ ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
+ pszParmValue));
+ bRetval = False;
+ }
+ return (bRetval);
}
/***************************************************************************
Find a service by name. Otherwise works like get_service.
***************************************************************************/
-static int getservicebyname(char *pszServiceName, service *pserviceDest)
+static int getservicebyname(const char *pszServiceName, service * pserviceDest)
{
- int iService;
-
- for (iService = iNumServices - 1; iService >= 0; iService--)
- if (VALID(iService) &&
- strwicmp(iSERVICE(iService).szService, pszServiceName) == 0)
- {
- if (pserviceDest != NULL)
- copy_service(pserviceDest, pSERVICE(iService), NULL);
- break;
- }
-
- return (iService);
+ int iService;
+
+ for (iService = iNumServices - 1; iService >= 0; iService--)
+ if (VALID(iService) &&
+ strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0)
+ {
+ if (pserviceDest != NULL)
+ copy_service(pserviceDest, ServicePtrs[iService], NULL);
+ break;
+ }
+
+ return (iService);
}
@@ -1077,54 +2031,67 @@ Copy a service structure to another
If pcopymapDest is NULL then copy all fields
***************************************************************************/
-static void copy_service(service *pserviceDest,
- service *pserviceSource,
- BOOL *pcopymapDest)
-{
- int i;
- BOOL bcopyall = (pcopymapDest == NULL);
-
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
- (bcopyall || pcopymapDest[i]))
- {
- void *def_ptr = parm_table[i].ptr;
- void *src_ptr =
- ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
- void *dest_ptr =
- ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
-
- switch (parm_table[i].type)
- {
- case P_BOOL:
- case P_BOOLREV:
- *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
- break;
-
- case P_INTEGER:
- case P_OCTAL:
- *(int *)dest_ptr = *(int *)src_ptr;
- break;
-
- case P_CHAR:
- *(char *)dest_ptr = *(char *)src_ptr;
- break;
-
- case P_STRING:
- string_set(dest_ptr,*(char **)src_ptr);
- break;
- default:
- break;
- }
- }
-
- if (bcopyall)
- {
- init_copymap(pserviceDest);
- if (pserviceSource->copymap)
- memcpy((void *)pserviceDest->copymap,
- (void *)pserviceSource->copymap,sizeof(BOOL)*NUMPARAMETERS);
- }
+static void copy_service(service * pserviceDest,
+ service * pserviceSource, BOOL *pcopymapDest)
+{
+ int i;
+ BOOL bcopyall = (pcopymapDest == NULL);
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].ptr && parm_table[i].class == P_LOCAL &&
+ (bcopyall || pcopymapDest[i]))
+ {
+ void *def_ptr = parm_table[i].ptr;
+ void *src_ptr =
+ ((char *)pserviceSource) + PTR_DIFF(def_ptr,
+ &sDefault);
+ void *dest_ptr =
+ ((char *)pserviceDest) + PTR_DIFF(def_ptr,
+ &sDefault);
+
+ switch (parm_table[i].type)
+ {
+ case P_BOOL:
+ case P_BOOLREV:
+ *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
+ break;
+
+ case P_INTEGER:
+ case P_ENUM:
+ case P_OCTAL:
+ *(int *)dest_ptr = *(int *)src_ptr;
+ break;
+
+ case P_CHAR:
+ *(char *)dest_ptr = *(char *)src_ptr;
+ break;
+
+ case P_STRING:
+ string_set(dest_ptr,
+ *(char **)src_ptr);
+ break;
+
+ case P_USTRING:
+ string_set(dest_ptr,
+ *(char **)src_ptr);
+ strupper(*(char **)dest_ptr);
+ break;
+ case P_LIST:
+ lp_list_copy((char ***)dest_ptr, *(char ***)src_ptr);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (bcopyall)
+ {
+ init_copymap(pserviceDest);
+ if (pserviceSource->copymap)
+ memcpy((void *)pserviceDest->copymap,
+ (void *)pserviceSource->copymap,
+ sizeof(BOOL) * NUMPARAMETERS);
+ }
}
/***************************************************************************
@@ -1133,78 +2100,94 @@ incomplete or faulty, else True.
***************************************************************************/
static BOOL service_ok(int iService)
{
- BOOL bRetval;
-
- bRetval = True;
- if (iSERVICE(iService).szService[0] == '\0')
- {
- DEBUG(0,( "The following message indicates an internal error:\n"));
- DEBUG(0,( "No service name in service entry.\n"));
- bRetval = False;
- }
-
- /* The [printers] entry MUST be printable. I'm all for flexibility, but */
- /* I can't see why you'd want a non-printable printer service... */
- if (strwicmp(iSERVICE(iService).szService,PRINTERS_NAME) == 0)
- if (!iSERVICE(iService).bPrint_ok)
- {
- DEBUG(0,( "WARNING: [%s] service MUST be printable!\n",
- iSERVICE(iService).szService));
- iSERVICE(iService).bPrint_ok = True;
- }
-
- if (iSERVICE(iService).szPath[0] == '\0' &&
- strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
- {
- DEBUG(0,("No path in service %s - using /tmp\n",iSERVICE(iService).szService));
- string_set(&iSERVICE(iService).szPath,"/tmp");
- }
-
- /* If a service is flagged unavailable, log the fact at level 0. */
- if (!iSERVICE(iService).bAvailable)
- DEBUG(1,( "NOTE: Service %s is flagged unavailable.\n",
- iSERVICE(iService).szService));
-
- return (bRetval);
-}
-
-static struct file_lists {
- struct file_lists *next;
- char *name;
- time_t modtime;
-} *file_lists = NULL;
+ BOOL bRetval;
+
+ bRetval = True;
+ if (ServicePtrs[iService]->szService[0] == '\0')
+ {
+ DEBUG(0,
+ ("The following message indicates an internal error:\n"));
+ DEBUG(0, ("No service name in service entry.\n"));
+ bRetval = False;
+ }
+
+ /* The [printers] entry MUST be printable. I'm all for flexibility, but */
+ /* I can't see why you'd want a non-printable printer service... */
+ if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
+ if (!ServicePtrs[iService]->bPrint_ok) {
+ DEBUG(0,
+ ("WARNING: [%s] service MUST be printable!\n",
+ ServicePtrs[iService]->szService));
+ ServicePtrs[iService]->bPrint_ok = True;
+ }
+ /* [printers] service must also be non-browsable. */
+ if (ServicePtrs[iService]->bBrowseable)
+ ServicePtrs[iService]->bBrowseable = False;
+ }
+
+ if (ServicePtrs[iService]->szPath[0] == '\0' &&
+ strwicmp(ServicePtrs[iService]->szService, HOMES_NAME) != 0)
+ {
+ DEBUG(0,
+ ("No path in service %s - using %s\n",
+ ServicePtrs[iService]->szService, tmpdir()));
+ string_set(&ServicePtrs[iService]->szPath, tmpdir());
+ }
+
+ /* If a service is flagged unavailable, log the fact at level 0. */
+ if (!ServicePtrs[iService]->bAvailable)
+ DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
+ ServicePtrs[iService]->szService));
+
+ return (bRetval);
+}
+
+static struct file_lists
+{
+ struct file_lists *next;
+ char *name;
+ char *subfname;
+ time_t modtime;
+}
+ *file_lists = NULL;
/*******************************************************************
keep a linked list of all config files so we know when one has changed
it's date and needs to be reloaded
********************************************************************/
-static void add_to_file_list(char *fname)
+static void add_to_file_list(char *fname, char *subfname)
{
- struct file_lists *f=file_lists;
+ struct file_lists *f = file_lists;
- while (f) {
- if (f->name && !strcmp(f->name,fname)) break;
- f = f->next;
- }
+ while (f)
+ {
+ if (f->name && !strcmp(f->name, fname))
+ break;
+ f = f->next;
+ }
- if (!f) {
- f = (struct file_lists *)malloc(sizeof(file_lists[0]));
- if (!f) return;
- f->next = file_lists;
- f->name = strdup(fname);
- if (!f->name) {
- free(f);
- return;
- }
- file_lists = f;
- }
+ if (!f)
+ {
+ f = (struct file_lists *)malloc(sizeof(file_lists[0]));
+ if (!f)
+ return;
+ f->next = file_lists;
+ f->name = strdup(fname);
+ if (!f->name)
+ {
+ SAFE_FREE(f);
+ return;
+ }
+ f->subfname = strdup(subfname);
+ if (!f->subfname)
+ {
+ SAFE_FREE(f);
+ return;
+ }
+ file_lists = f;
+ }
- {
- pstring n2;
- strcpy(n2,fname);
- standard_sub_basic(n2);
- f->modtime = file_modtime(n2);
- }
+ f->modtime = file_modtime(subfname);
}
@@ -1213,469 +2196,907 @@ check if a config file has changed date
********************************************************************/
BOOL lp_file_list_changed(void)
{
- struct file_lists *f = file_lists;
- while (f) {
- pstring n2;
- strcpy(n2,f->name);
- standard_sub_basic(n2);
- if (f->modtime != file_modtime(n2)) return(True);
- f = f->next;
- }
- return(False);
+ struct file_lists *f = file_lists;
+ DEBUG(6, ("lp_file_list_changed()\n"));
+
+ while (f)
+ {
+ pstring n2;
+ time_t mod_time;
+
+ pstrcpy(n2, f->name);
+ standard_sub_basic(current_user_info.smb_name, n2);
+
+ DEBUGADD(6, ("file %s -> %s last mod_time: %s\n",
+ f->name, n2, ctime(&f->modtime)));
+
+ mod_time = file_modtime(n2);
+
+ if ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))
+ {
+ DEBUGADD(6,
+ ("file %s modified: %s\n", n2,
+ ctime(&mod_time)));
+ f->modtime = mod_time;
+ SAFE_FREE(f->subfname);
+ f->subfname = strdup(n2);
+ return (True);
+ }
+ f = f->next;
+ }
+ return (False);
}
-#ifdef KANJI
/***************************************************************************
- handle the interpretation of the coding system parameter
- *************************************************************************/
-static BOOL handle_coding_system(char *pszParmValue,int *val)
+ Run standard_sub_basic on netbios name... needed because global_myname
+ is not accessed through any lp_ macro.
+ Note: We must *NOT* use string_set() here as ptr points to global_myname.
+***************************************************************************/
+
+static BOOL handle_netbios_name(char *pszParmValue, char **ptr)
{
- *val = interpret_coding_system(pszParmValue,*val);
- return(True);
+ pstring netbios_name;
+
+ pstrcpy(netbios_name, pszParmValue);
+
+ standard_sub_basic(current_user_info.smb_name, netbios_name);
+ strupper(netbios_name);
+
+ pstrcpy(global_myname, netbios_name);
+
+ DEBUG(4,
+ ("handle_netbios_name: set global_myname to: %s\n",
+ global_myname));
+
+ return (True);
}
-#endif /* KANJI */
/***************************************************************************
-handle the interpretation of the character set system parameter
+ Do the work of sourcing in environment variable/value pairs.
***************************************************************************/
-static BOOL handle_character_set(char *pszParmValue,int *val)
+
+static BOOL source_env(char **lines)
{
- string_set(&Globals.szCharacterSet,pszParmValue);
- *val = interpret_character_set(pszParmValue,*val);
- return(True);
-}
+ char *varval;
+ size_t len;
+ int i;
+ char *p;
+ for (i = 0; lines[i]; i++)
+ {
+ char *line = lines[i];
+
+ if ((len = strlen(line)) == 0)
+ continue;
+
+ if (line[len - 1] == '\n')
+ line[--len] = '\0';
+
+ if ((varval = malloc(len + 1)) == NULL)
+ {
+ DEBUG(0, ("source_env: Not enough memory!\n"));
+ return (False);
+ }
+
+ DEBUG(4, ("source_env: Adding to environment: %s\n", line));
+ strncpy(varval, line, len);
+ varval[len] = '\0';
+
+ p = strchr_m(line, (int)'=');
+ if (p == NULL)
+ {
+ DEBUG(4, ("source_env: missing '=': %s\n", line));
+ continue;
+ }
+
+ if (putenv(varval))
+ {
+ DEBUG(0,
+ ("source_env: Failed to put environment variable %s\n",
+ varval));
+ continue;
+ }
+
+ *p = '\0';
+ p++;
+ DEBUG(4,
+ ("source_env: getting var %s = %s\n", line,
+ getenv(line)));
+ }
+
+ DEBUG(4, ("source_env: returning successfully\n"));
+ return (True);
+}
/***************************************************************************
-handle the interpretation of the protocol parameter
+ Handle the source environment operation
***************************************************************************/
-static BOOL handle_protocol(char *pszParmValue,int *val)
+
+static BOOL handle_source_env(char *pszParmValue, char **ptr)
{
- *val = interpret_protocol(pszParmValue,*val);
- return(True);
+ pstring fname;
+ char *p = fname;
+ BOOL result;
+ char **lines;
+
+ pstrcpy(fname, pszParmValue);
+
+ standard_sub_basic(current_user_info.smb_name, fname);
+
+ string_set(ptr, pszParmValue);
+
+ DEBUG(4, ("handle_source_env: checking env type\n"));
+
+ /*
+ * Filename starting with '|' means popen and read from stdin.
+ */
+
+ if (*p == '|')
+ {
+ lines = file_lines_pload(p + 1, NULL);
+ }
+ else
+ {
+ lines = file_lines_load(fname, NULL);
+ }
+
+ if (!lines)
+ {
+ DEBUG(0,
+ ("handle_source_env: Failed to open file %s, Error was %s\n",
+ fname, strerror(errno)));
+ return (False);
+ }
+
+ result = source_env(lines);
+ file_lines_free(lines);
+
+ return (result);
}
/***************************************************************************
-handle the interpretation of the security parameter
-***************************************************************************/
-static BOOL handle_security(char *pszParmValue,int *val)
+ handle the interpretation of the vfs object parameter
+ *************************************************************************/
+static BOOL handle_vfs_object(char *pszParmValue, char **ptr)
{
- *val = interpret_security(pszParmValue,*val);
- return(True);
+ /* Set string value */
+
+ string_set(ptr, pszParmValue);
+
+ /* Do any other initialisation required for vfs. Note that
+ anything done here may have linking repercussions in nmbd. */
+
+ return True;
}
+
/***************************************************************************
-handle the interpretation of the default case
+handle the include operation
***************************************************************************/
-static BOOL handle_case(char *pszParmValue,int *val)
+
+static BOOL handle_include(char *pszParmValue, char **ptr)
{
- if (strequal(pszParmValue,"LOWER"))
- *val = CASE_LOWER;
- else if (strequal(pszParmValue,"UPPER"))
- *val = CASE_UPPER;
- return(True);
+ pstring fname;
+ pstrcpy(fname, pszParmValue);
+
+ standard_sub_basic(current_user_info.smb_name, fname);
+
+ add_to_file_list(pszParmValue, fname);
+
+ string_set(ptr, fname);
+
+ if (file_exist(fname, NULL))
+ return (pm_process(fname, do_section, do_parameter));
+
+ DEBUG(2, ("Can't find include file %s\n", fname));
+
+ return (False);
}
+
/***************************************************************************
-handle the interpretation of the printing system
+handle the interpretation of the copy parameter
***************************************************************************/
-static BOOL handle_printing(char *pszParmValue,int *val)
+static BOOL handle_copy(char *pszParmValue, char **ptr)
{
- if (strequal(pszParmValue,"sysv"))
- *val = PRINT_SYSV;
- else if (strequal(pszParmValue,"aix"))
- *val = PRINT_AIX;
- else if (strequal(pszParmValue,"hpux"))
- *val = PRINT_HPUX;
- else if (strequal(pszParmValue,"bsd"))
- *val = PRINT_BSD;
- else if (strequal(pszParmValue,"qnx"))
- *val = PRINT_QNX;
- return(True);
+ BOOL bRetval;
+ int iTemp;
+ service serviceTemp;
+
+ string_set(ptr, pszParmValue);
+
+ init_service(&serviceTemp);
+
+ bRetval = False;
+
+ DEBUG(3, ("Copying service from service %s\n", pszParmValue));
+
+ if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
+ {
+ if (iTemp == iServiceIndex)
+ {
+ DEBUG(0,
+ ("Can't copy service %s - unable to copy self!\n",
+ pszParmValue));
+ }
+ else
+ {
+ copy_service(ServicePtrs[iServiceIndex],
+ &serviceTemp,
+ ServicePtrs[iServiceIndex]->copymap);
+ bRetval = True;
+ }
+ }
+ else
+ {
+ DEBUG(0, ("Unable to copy service - source not found: %s\n",
+ pszParmValue));
+ bRetval = False;
+ }
+
+ free_service(&serviceTemp);
+ return (bRetval);
}
/***************************************************************************
-handle the valid chars lines
+ Handle winbind uid and gid allocation parameters. The format of these
+ parameters is:
+
+ [global]
+
+ winbind uid = 1000-1999
+ winbind gid = 700-899
+
+ We only do simple parsing checks here. The strings are parsed into useful
+ structures in the winbind daemon code.
+
***************************************************************************/
-static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
-{
- string_set(ptr,pszParmValue);
- add_char_string(pszParmValue);
- return(True);
+/* Some lp_ routines to return winbind [ug]id information */
+
+static uid_t winbind_uid_low, winbind_uid_high;
+static gid_t winbind_gid_low, winbind_gid_high;
+
+BOOL lp_winbind_uid(uid_t *low, uid_t *high)
+{
+ if (winbind_uid_low == 0 || winbind_uid_high == 0)
+ return False;
+
+ if (low)
+ *low = winbind_uid_low;
+
+ if (high)
+ *high = winbind_uid_high;
+
+ return True;
}
+BOOL lp_winbind_gid(gid_t *low, gid_t *high)
+{
+ if (winbind_gid_low == 0 || winbind_gid_high == 0)
+ return False;
-/***************************************************************************
-handle the include operation
-***************************************************************************/
-static BOOL handle_include(char *pszParmValue,char **ptr)
-{
- pstring fname;
- strcpy(fname,pszParmValue);
+ if (low)
+ *low = winbind_gid_low;
+
+ if (high)
+ *high = winbind_gid_high;
- add_to_file_list(fname);
+ return True;
+}
- standard_sub_basic(fname);
+/* Do some simple checks on "winbind [ug]id" parameter values */
- string_set(ptr,fname);
+static BOOL handle_winbind_uid(char *pszParmValue, char **ptr)
+{
+ uint32 low, high;
- if (file_exist(fname,NULL))
- return(pm_process(fname, do_section, do_parameter));
+ if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
+ return False;
- DEBUG(2,("Can't find include file %s\n",fname));
+ /* Parse OK */
- return(False);
+ string_set(ptr, pszParmValue);
+
+ winbind_uid_low = low;
+ winbind_uid_high = high;
+
+ return True;
}
+static BOOL handle_winbind_gid(char *pszParmValue, char **ptr)
+{
+ uint32 low, high;
+
+ if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
+ return False;
+
+ /* Parse OK */
+
+ string_set(ptr, pszParmValue);
+
+ winbind_gid_low = low;
+ winbind_gid_high = high;
+
+ return True;
+}
/***************************************************************************
-handle the interpretation of the copy parameter
+ Handle the WINS SERVER list
***************************************************************************/
-static BOOL handle_copy(char *pszParmValue,char **ptr)
-{
- BOOL bRetval;
- int iTemp;
- service serviceTemp;
+static BOOL handle_wins_server_list( char *pszParmValue, char **ptr )
+ {
+ if( !wins_srv_load_list( pszParmValue ) )
+ return( False ); /* Parse failed. */
- string_set(ptr,pszParmValue);
+ string_set( ptr, pszParmValue );
+ return( True );
+ }
- init_service(&serviceTemp);
- bRetval = False;
-
- DEBUG(3,("Copying service from service %s\n",pszParmValue));
-
- if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
- {
- if (iTemp == iServiceIndex)
- {
- DEBUG(0,("Can't copy service %s - unable to copy self!\n",
- pszParmValue));
- }
- else
- {
- copy_service(pSERVICE(iServiceIndex),
- &serviceTemp,
- iSERVICE(iServiceIndex).copymap);
- bRetval = True;
- }
- }
- else
- {
- DEBUG(0,( "Unable to copy service - source not found: %s\n",
- pszParmValue));
- bRetval = False;
- }
-
- free_service(&serviceTemp);
- return (bRetval);
+/***************************************************************************
+ Handle the DEBUG level list
+***************************************************************************/
+static BOOL handle_debug_list( char *pszParmValueIn, char **ptr )
+{
+ pstring pszParmValue;
+
+ pstrcpy(pszParmValue, pszParmValueIn);
+ return debug_parse_levels( pszParmValue );
}
/***************************************************************************
initialise a copymap
***************************************************************************/
-static void init_copymap(service *pservice)
+static void init_copymap(service * pservice)
{
- int i;
- if (pservice->copymap) free(pservice->copymap);
- pservice->copymap = (BOOL *)malloc(sizeof(BOOL)*NUMPARAMETERS);
- if (!pservice->copymap)
- DEBUG(0,("Couldn't allocate copymap!! (size %d)\n",NUMPARAMETERS));
+ int i;
+ SAFE_FREE(pservice->copymap);
+ pservice->copymap = (BOOL *)malloc(sizeof(BOOL) * NUMPARAMETERS);
+ if (!pservice->copymap)
+ DEBUG(0,
+ ("Couldn't allocate copymap!! (size %d)\n",
+ (int)NUMPARAMETERS));
+ else
+ for (i = 0; i < NUMPARAMETERS; i++)
+ pservice->copymap[i] = True;
+}
- for (i=0;i<NUMPARAMETERS;i++)
- pservice->copymap[i] = True;
+
+/***************************************************************************
+ return the local pointer to a parameter given the service number and the
+ pointer into the default structure
+***************************************************************************/
+void *lp_local_ptr(int snum, void *ptr)
+{
+ return (void *)(((char *)ServicePtrs[snum]) + PTR_DIFF(ptr, &sDefault));
}
+/***************************************************************************
+Process a parameter for a particular service number. If snum < 0
+then assume we are in the globals
+***************************************************************************/
+BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue)
+{
+ int parmnum, i;
+ void *parm_ptr = NULL; /* where we are going to store the result */
+ void *def_ptr = NULL;
+
+ parmnum = map_parameter(pszParmName);
+
+ if (parmnum < 0)
+ {
+ DEBUG(0,
+ ("Ignoring unknown parameter \"%s\"\n", pszParmName));
+ return (True);
+ }
+
+ if (parm_table[parmnum].flags & FLAG_DEPRECATED)
+ {
+ DEBUG(1, ("WARNING: The \"%s\"option is deprecated\n",
+ pszParmName));
+ }
+
+ def_ptr = parm_table[parmnum].ptr;
+
+ /* we might point at a service, the default service or a global */
+ if (snum < 0)
+ {
+ parm_ptr = def_ptr;
+ }
+ else
+ {
+ if (parm_table[parmnum].class == P_GLOBAL)
+ {
+ DEBUG(0,
+ ("Global parameter %s found in service section!\n",
+ pszParmName));
+ return (True);
+ }
+ parm_ptr =
+ ((char *)ServicePtrs[snum]) + PTR_DIFF(def_ptr,
+ &sDefault);
+ }
+
+ if (snum >= 0)
+ {
+ if (!ServicePtrs[snum]->copymap)
+ init_copymap(ServicePtrs[snum]);
+
+ /* this handles the aliases - set the copymap for other entries with
+ the same data pointer */
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].ptr == parm_table[parmnum].ptr)
+ ServicePtrs[snum]->copymap[i] = False;
+ }
+
+ /* if it is a special case then go ahead */
+ if (parm_table[parmnum].special)
+ {
+ parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
+ return (True);
+ }
+
+ /* now switch on the type of variable it is */
+ switch (parm_table[parmnum].type)
+ {
+ case P_BOOL:
+ set_boolean(parm_ptr, pszParmValue);
+ break;
+
+ case P_BOOLREV:
+ set_boolean(parm_ptr, pszParmValue);
+ *(BOOL *)parm_ptr = !*(BOOL *)parm_ptr;
+ break;
+
+ case P_INTEGER:
+ *(int *)parm_ptr = atoi(pszParmValue);
+ break;
+
+ case P_CHAR:
+ *(char *)parm_ptr = *pszParmValue;
+ break;
+
+ case P_OCTAL:
+ sscanf(pszParmValue, "%o", (int *)parm_ptr);
+ break;
+
+ case P_LIST:
+ *(char ***)parm_ptr = lp_list_make(pszParmValue);
+ break;
+
+ case P_STRING:
+ string_set(parm_ptr, pszParmValue);
+ break;
+
+ case P_USTRING:
+ string_set(parm_ptr, pszParmValue);
+ strupper(*(char **)parm_ptr);
+ break;
+
+ case P_GSTRING:
+ pstrcpy((char *)parm_ptr, pszParmValue);
+ break;
+
+ case P_UGSTRING:
+ pstrcpy((char *)parm_ptr, pszParmValue);
+ strupper((char *)parm_ptr);
+ break;
+
+ case P_ENUM:
+ for (i = 0; parm_table[parmnum].enum_list[i].name;
+ i++)
+ {
+ if (strequal
+ (pszParmValue,
+ parm_table[parmnum].enum_list[i].name))
+ {
+ *(int *)parm_ptr =
+ parm_table[parmnum].
+ enum_list[i].value;
+ break;
+ }
+ }
+ break;
+ case P_SEP:
+ break;
+ }
+
+ return (True);
+}
/***************************************************************************
Process a parameter.
***************************************************************************/
static BOOL do_parameter(char *pszParmName, char *pszParmValue)
{
- int parmnum;
- void *parm_ptr=NULL; /* where we are going to store the result */
- void *def_ptr=NULL;
+ if (!bInGlobalSection && bGlobalOnly)
+ return (True);
- if (!bInGlobalSection && bGlobalOnly) return(True);
+ DEBUGADD(4, ("doing parameter %s = %s\n", pszParmName, pszParmValue));
- DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
-
- parmnum = map_parameter(pszParmName);
-
- if (parmnum < 0)
- {
- DEBUG(0,( "Ignoring unknown parameter \"%s\"\n", pszParmName));
- return(True);
- }
-
- def_ptr = parm_table[parmnum].ptr;
-
- /* we might point at a service, the default service or a global */
- if (bInGlobalSection)
- parm_ptr = def_ptr;
- else
- {
- if (parm_table[parmnum].class == P_GLOBAL)
- {
- DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
- return(True);
- }
- parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr,&sDefault);
- }
-
- if (!bInGlobalSection)
- {
- int i;
- if (!iSERVICE(iServiceIndex).copymap)
- init_copymap(pSERVICE(iServiceIndex));
-
- /* this handles the aliases - set the copymap for other entries with
- the same data pointer */
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].ptr == parm_table[parmnum].ptr)
- iSERVICE(iServiceIndex).copymap[i] = False;
- }
-
- /* if it is a special case then go ahead */
- if (parm_table[parmnum].special)
- {
- parm_table[parmnum].special(pszParmValue,parm_ptr);
- return(True);
- }
-
- /* now switch on the type of variable it is */
- switch (parm_table[parmnum].type)
- {
- case P_BOOL:
- set_boolean(parm_ptr,pszParmValue);
- break;
-
- case P_BOOLREV:
- set_boolean(parm_ptr,pszParmValue);
- *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
- break;
-
- case P_INTEGER:
- *(int *)parm_ptr = atoi(pszParmValue);
- break;
-
- case P_CHAR:
- *(char *)parm_ptr = *pszParmValue;
- break;
-
- case P_OCTAL:
- sscanf(pszParmValue,"%o",(int *)parm_ptr);
- break;
-
- case P_STRING:
- string_set(parm_ptr,pszParmValue);
- break;
-
- case P_GSTRING:
- strcpy((char *)parm_ptr,pszParmValue);
- break;
- }
-
- return(True);
+ return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,
+ pszParmName, pszParmValue));
}
+
/***************************************************************************
print a parameter of the specified type
***************************************************************************/
-static void print_parameter(parm_type type,void *ptr)
-{
- switch (type)
- {
- case P_BOOL:
- printf("%s",BOOLSTR(*(BOOL *)ptr));
- break;
-
- case P_BOOLREV:
- printf("%s",BOOLSTR(! *(BOOL *)ptr));
- break;
-
- case P_INTEGER:
- printf("%d",*(int *)ptr);
- break;
-
- case P_CHAR:
- printf("%c",*(char *)ptr);
- break;
-
- case P_OCTAL:
- printf("0%o",*(int *)ptr);
- break;
-
- case P_GSTRING:
- if ((char *)ptr)
- printf("%s",(char *)ptr);
- break;
-
- case P_STRING:
- if (*(char **)ptr)
- printf("%s",*(char **)ptr);
- break;
- }
+static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
+{
+ int i;
+ switch (p->type)
+ {
+ case P_ENUM:
+ for (i = 0; p->enum_list[i].name; i++)
+ {
+ if (*(int *)ptr == p->enum_list[i].value)
+ {
+ fprintf(f, "%s",
+ p->enum_list[i].name);
+ break;
+ }
+ }
+ break;
+
+ case P_BOOL:
+ fprintf(f, "%s", BOOLSTR(*(BOOL *)ptr));
+ break;
+
+ case P_BOOLREV:
+ fprintf(f, "%s", BOOLSTR(!*(BOOL *)ptr));
+ break;
+
+ case P_INTEGER:
+ fprintf(f, "%d", *(int *)ptr);
+ break;
+
+ case P_CHAR:
+ fprintf(f, "%c", *(char *)ptr);
+ break;
+
+ case P_OCTAL:
+ fprintf(f, "%s", octal_string(*(int *)ptr));
+ break;
+
+ case P_LIST:
+ if ((char ***)ptr && *(char ***)ptr) {
+ char **list = *(char ***)ptr;
+
+ for (; *list; list++)
+ fprintf(f, "%s%s", *list,
+ ((*(list+1))?", ":""));
+ }
+ break;
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ if ((char *)ptr) {
+ fprintf(f, "%s", (char *)ptr);
+ }
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (*(char **)ptr) {
+ fprintf(f, "%s", *(char **)ptr);
+ }
+ break;
+ case P_SEP:
+ break;
+ }
}
/***************************************************************************
check if two parameters are equal
***************************************************************************/
-static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
-{
- switch (type)
- {
- case P_BOOL:
- case P_BOOLREV:
- return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
-
- case P_INTEGER:
- case P_OCTAL:
- return(*((int *)ptr1) == *((int *)ptr2));
-
- case P_CHAR:
- return(*((char *)ptr1) == *((char *)ptr2));
-
- case P_GSTRING:
- {
- char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
- if (p1 && !*p1) p1 = NULL;
- if (p2 && !*p2) p2 = NULL;
- return(p1==p2 || strequal(p1,p2));
- }
- case P_STRING:
- {
- char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
- if (p1 && !*p1) p1 = NULL;
- if (p2 && !*p2) p2 = NULL;
- return(p1==p2 || strequal(p1,p2));
- }
- }
- return(False);
+static BOOL equal_parameter(parm_type type, void *ptr1, void *ptr2)
+{
+ switch (type)
+ {
+ case P_BOOL:
+ case P_BOOLREV:
+ return (*((BOOL *)ptr1) == *((BOOL *)ptr2));
+
+ case P_INTEGER:
+ case P_ENUM:
+ case P_OCTAL:
+ return (*((int *)ptr1) == *((int *)ptr2));
+
+ case P_CHAR:
+ return (*((char *)ptr1) == *((char *)ptr2));
+
+ case P_LIST:
+ return lp_list_compare(*(char ***)ptr1, *(char ***)ptr2);
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ {
+ char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
+ if (p1 && !*p1)
+ p1 = NULL;
+ if (p2 && !*p2)
+ p2 = NULL;
+ return (p1 == p2 || strequal(p1, p2));
+ }
+ case P_STRING:
+ case P_USTRING:
+ {
+ char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
+ if (p1 && !*p1)
+ p1 = NULL;
+ if (p2 && !*p2)
+ p2 = NULL;
+ return (p1 == p2 || strequal(p1, p2));
+ }
+ case P_SEP:
+ break;
+ }
+ return (False);
+}
+
+/***************************************************************************
+ Initialize any local varients in the sDefault table.
+***************************************************************************/
+
+void init_locals(void)
+{
+ /* None as yet. */
}
/***************************************************************************
Process a new section (service). At this stage all sections are services.
Later we'll have special sections that permit server parameters to be set.
-Returns True on success, False on failure.
+Returns True on success, False on failure.
***************************************************************************/
static BOOL do_section(char *pszSectionName)
{
- BOOL bRetval;
- BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
- (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
- bRetval = False;
+ BOOL bRetval;
+ BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
+ (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
+ bRetval = False;
- /* if we were in a global section then do the local inits */
- if (bInGlobalSection && !isglobal)
- init_locals();
+ /* if we were in a global section then do the local inits */
+ if (bInGlobalSection && !isglobal)
+ init_locals();
- /* if we've just struck a global section, note the fact. */
- bInGlobalSection = isglobal;
+ /* if we've just struck a global section, note the fact. */
+ bInGlobalSection = isglobal;
- /* check for multiple global sections */
- if (bInGlobalSection)
- {
- DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
- return(True);
- }
+ /* check for multiple global sections */
+ if (bInGlobalSection)
+ {
+ DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
+ return (True);
+ }
- if (!bInGlobalSection && bGlobalOnly) return(True);
+ if (!bInGlobalSection && bGlobalOnly)
+ return (True);
- /* if we have a current service, tidy it up before moving on */
- bRetval = True;
+ /* if we have a current service, tidy it up before moving on */
+ bRetval = True;
- if (iServiceIndex >= 0)
- bRetval = service_ok(iServiceIndex);
+ if (iServiceIndex >= 0)
+ bRetval = service_ok(iServiceIndex);
- /* if all is still well, move to the next record in the services array */
- if (bRetval)
- {
- /* We put this here to avoid an odd message order if messages are */
- /* issued by the post-processing of a previous section. */
- DEBUG(2,( "Processing section \"[%s]\"\n", pszSectionName));
+ /* if all is still well, move to the next record in the services array */
+ if (bRetval)
+ {
+ /* We put this here to avoid an odd message order if messages are */
+ /* issued by the post-processing of a previous section. */
+ DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
+
+ if ((iServiceIndex = add_a_service(&sDefault, pszSectionName))
+ < 0)
+ {
+ DEBUG(0, ("Failed to add a new service\n"));
+ return (False);
+ }
+ }
+
+ return (bRetval);
+}
- if ((iServiceIndex=add_a_service(&sDefault,pszSectionName)) < 0)
- {
- DEBUG(0,("Failed to add a new service\n"));
- return(False);
- }
- }
- return (bRetval);
+/***************************************************************************
+determine if a partcular base parameter is currentl set to the default value.
+***************************************************************************/
+static BOOL is_default(int i)
+{
+ if (!defaults_saved)
+ return False;
+ switch (parm_table[i].type)
+ {
+ case P_LIST:
+ return lp_list_compare (parm_table[i].def.lvalue,
+ *(char ***)parm_table[i].ptr);
+ case P_STRING:
+ case P_USTRING:
+ return strequal(parm_table[i].def.svalue,
+ *(char **)parm_table[i].ptr);
+ case P_GSTRING:
+ case P_UGSTRING:
+ return strequal(parm_table[i].def.svalue,
+ (char *)parm_table[i].ptr);
+ case P_BOOL:
+ case P_BOOLREV:
+ return parm_table[i].def.bvalue ==
+ *(BOOL *)parm_table[i].ptr;
+ case P_CHAR:
+ return parm_table[i].def.cvalue ==
+ *(char *)parm_table[i].ptr;
+ case P_INTEGER:
+ case P_OCTAL:
+ case P_ENUM:
+ return parm_table[i].def.ivalue ==
+ *(int *)parm_table[i].ptr;
+ case P_SEP:
+ break;
+ }
+ return False;
}
+
/***************************************************************************
Display the contents of the global structure.
***************************************************************************/
-static void dump_globals(void)
+static void dump_globals(FILE *f)
+{
+ int i;
+ fprintf(f, "# Global parameters\n[global]\n");
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].class == P_GLOBAL &&
+ parm_table[i].ptr &&
+ (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr)))
+ {
+ if (defaults_saved && is_default(i))
+ continue;
+ fprintf(f, "\t%s = ", parm_table[i].label);
+ print_parameter(&parm_table[i], parm_table[i].ptr, f);
+ fprintf(f, "\n");
+ }
+}
+
+/***************************************************************************
+return True if a local parameter is currently set to the global default
+***************************************************************************/
+BOOL lp_is_default(int snum, struct parm_struct *parm)
{
- int i;
- printf("Global parameters:\n");
+ int pdiff = PTR_DIFF(parm->ptr, &sDefault);
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].class == P_GLOBAL &&
- parm_table[i].ptr &&
- (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
- {
- printf("\t%s: ",parm_table[i].label);
- print_parameter(parm_table[i].type,parm_table[i].ptr);
- printf("\n");
- }
+ return equal_parameter(parm->type,
+ ((char *)ServicePtrs[snum]) + pdiff,
+ ((char *)&sDefault) + pdiff);
}
+
/***************************************************************************
Display the contents of a single services record.
***************************************************************************/
-static void dump_a_service(service *pService)
-{
- int i;
- if (pService == &sDefault)
- printf("\nDefault service parameters:\n");
- else
- printf("\nService parameters [%s]:\n",pService->szService);
-
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].class == P_LOCAL &&
- parm_table[i].ptr &&
- (*parm_table[i].label != '-') &&
- (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
- {
- int pdiff = PTR_DIFF(parm_table[i].ptr,&sDefault);
-
- if (pService == &sDefault || !equal_parameter(parm_table[i].type,
- ((char *)pService) + pdiff,
- ((char *)&sDefault) + pdiff))
- {
- printf("\t%s: ",parm_table[i].label);
- print_parameter(parm_table[i].type,
- ((char *)pService) + pdiff);
- printf("\n");
- }
- }
+static void dump_a_service(service * pService, FILE * f)
+{
+ int i;
+ if (pService != &sDefault)
+ fprintf(f, "\n[%s]\n", pService->szService);
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].class == P_LOCAL &&
+ parm_table[i].ptr &&
+ (*parm_table[i].label != '-') &&
+ (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr)))
+ {
+ int pdiff = PTR_DIFF(parm_table[i].ptr, &sDefault);
+
+ if (pService == &sDefault)
+ {
+ if (defaults_saved && is_default(i))
+ continue;
+ }
+ else
+ {
+ if (equal_parameter(parm_table[i].type,
+ ((char *)pService) +
+ pdiff,
+ ((char *)&sDefault) +
+ pdiff))
+ continue;
+ }
+
+ fprintf(f, "\t%s = ", parm_table[i].label);
+ print_parameter(&parm_table[i],
+ ((char *)pService) + pdiff, f);
+ fprintf(f, "\n");
+ }
}
+
+/***************************************************************************
+return info about the next service in a service. snum==-1 gives the globals
+
+return NULL when out of parameters
+***************************************************************************/
+struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters)
+{
+ if (snum == -1)
+ {
+ /* do the globals */
+ for (; parm_table[*i].label; (*i)++)
+ {
+ if (parm_table[*i].class == P_SEPARATOR)
+ return &parm_table[(*i)++];
+
+ if (!parm_table[*i].ptr
+ || (*parm_table[*i].label == '-'))
+ continue;
+
+ if ((*i) > 0
+ && (parm_table[*i].ptr ==
+ parm_table[(*i) - 1].ptr))
+ continue;
+
+ return &parm_table[(*i)++];
+ }
+ }
+ else
+ {
+ service *pService = ServicePtrs[snum];
+
+ for (; parm_table[*i].label; (*i)++)
+ {
+ if (parm_table[*i].class == P_SEPARATOR)
+ return &parm_table[(*i)++];
+
+ if (parm_table[*i].class == P_LOCAL &&
+ parm_table[*i].ptr &&
+ (*parm_table[*i].label != '-') &&
+ ((*i) == 0 ||
+ (parm_table[*i].ptr !=
+ parm_table[(*i) - 1].ptr)))
+ {
+ int pdiff =
+ PTR_DIFF(parm_table[*i].ptr,
+ &sDefault);
+
+ if (allparameters ||
+ !equal_parameter(parm_table[*i].type,
+ ((char *)pService) +
+ pdiff,
+ ((char *)&sDefault) +
+ pdiff))
+ {
+ return &parm_table[(*i)++];
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
#if 0
/***************************************************************************
Display the contents of a single copy structure.
***************************************************************************/
static void dump_copy_map(BOOL *pcopymap)
{
- int i;
- if (!pcopymap) return;
-
- printf("\n\tNon-Copied parameters:\n");
-
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].class == P_LOCAL &&
- parm_table[i].ptr && !pcopymap[i] &&
- (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
- {
- printf("\t\t%s\n",parm_table[i].label);
- }
+ int i;
+ if (!pcopymap)
+ return;
+
+ printf("\n\tNon-Copied parameters:\n");
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].class == P_LOCAL &&
+ parm_table[i].ptr && !pcopymap[i] &&
+ (i == 0 || (parm_table[i].ptr != parm_table[i - 1].ptr)))
+ {
+ printf("\t\t%s\n", parm_table[i].label);
+ }
}
#endif
@@ -1684,208 +3105,789 @@ Return TRUE if the passed service number is within range.
***************************************************************************/
BOOL lp_snum_ok(int iService)
{
- return (LP_SNUM_OK(iService) && iSERVICE(iService).bAvailable);
+ return (LP_SNUM_OK(iService) && ServicePtrs[iService]->bAvailable);
}
/***************************************************************************
-auto-load some homes and printer services
+auto-load some home services
***************************************************************************/
static void lp_add_auto_services(char *str)
{
- char *s;
- char *p;
- int homes = lp_servicenumber(HOMES_NAME);
- int printers = lp_servicenumber(PRINTERS_NAME);
+ char *s;
+ char *p;
+ int homes;
- if (!str)
- return;
+ if (!str)
+ return;
- s = strdup(str);
- if (!s) return;
+ s = strdup(str);
+ if (!s)
+ return;
- for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP))
- {
- char *home = get_home_dir(p);
+ homes = lp_servicenumber(HOMES_NAME);
- if (lp_servicenumber(p) >= 0) continue;
-
- if (home && homes >= 0)
+ for (p = strtok(s, LIST_SEP); p; p = strtok(NULL, LIST_SEP))
{
- lp_add_home(p,homes,home);
- continue;
- }
+ char *home = get_user_home_dir(p);
- if (printers >= 0 && pcap_printername_ok(p,NULL))
- lp_add_printer(p,printers);
- }
- free(s);
+ if (lp_servicenumber(p) >= 0)
+ continue;
+
+ if (home && homes >= 0)
+ {
+ lp_add_home(p, homes, home);
+ }
+ }
+ SAFE_FREE(s);
}
/***************************************************************************
auto-load one printer
***************************************************************************/
-static void lp_add_one_printer(char *name,char *comment)
+void lp_add_one_printer(char *name, char *comment)
{
- int printers = lp_servicenumber(PRINTERS_NAME);
- int i;
+ int printers = lp_servicenumber(PRINTERS_NAME);
+ int i;
- if (lp_servicenumber(name) < 0)
- {
- lp_add_printer(name,printers);
- if ((i=lp_servicenumber(name)) >= 0)
- string_set(&iSERVICE(i).comment,comment);
- }
+ if (lp_servicenumber(name) < 0)
+ {
+ lp_add_printer(name, printers);
+ if ((i = lp_servicenumber(name)) >= 0)
+ {
+ string_set(&ServicePtrs[i]->comment, comment);
+ ServicePtrs[i]->autoloaded = True;
+ }
+ }
}
-
/***************************************************************************
-auto-load printer services
+have we loaded a services file yet?
***************************************************************************/
-static void lp_add_all_printers(void)
+BOOL lp_loaded(void)
{
- int printers = lp_servicenumber(PRINTERS_NAME);
-
- if (printers < 0) return;
+ return (bLoaded);
+}
- pcap_printer_fn(lp_add_one_printer);
+/***************************************************************************
+unload unused services
+***************************************************************************/
+void lp_killunused(BOOL (*snumused) (int))
+{
+ int i;
+ for (i = 0; i < iNumServices; i++)
+ {
+ if (!VALID(i))
+ continue;
+
+ if (!snumused || !snumused(i))
+ {
+ ServicePtrs[i]->valid = False;
+ free_service(ServicePtrs[i]);
+ }
+ }
}
+
/***************************************************************************
-have we loaded a services file yet?
+unload a service
***************************************************************************/
-BOOL lp_loaded(void)
+void lp_killservice(int iServiceIn)
{
- return(bLoaded);
+ if (VALID(iServiceIn))
+ {
+ ServicePtrs[iServiceIn]->valid = False;
+ free_service(ServicePtrs[iServiceIn]);
+ }
}
/***************************************************************************
-unload unused services
+save the curent values of all global and sDefault parameters into the
+defaults union. This allows swat and testparm to show only the
+changed (ie. non-default) parameters.
***************************************************************************/
-void lp_killunused(BOOL (*snumused)(int ))
+static void lp_save_defaults(void)
+{
+ int i;
+ for (i = 0; parm_table[i].label; i++)
+ {
+ if (i > 0 && parm_table[i].ptr == parm_table[i - 1].ptr)
+ continue;
+ switch (parm_table[i].type)
+ {
+ case P_LIST:
+ lp_list_copy(&(parm_table[i].def.lvalue),
+ *(char ***)parm_table[i].ptr);
+ break;
+ case P_STRING:
+ case P_USTRING:
+ parm_table[i].def.svalue =
+ strdup(*(char **)parm_table[i].ptr);
+ break;
+ case P_GSTRING:
+ case P_UGSTRING:
+ parm_table[i].def.svalue =
+ strdup((char *)parm_table[i].ptr);
+ break;
+ case P_BOOL:
+ case P_BOOLREV:
+ parm_table[i].def.bvalue =
+ *(BOOL *)parm_table[i].ptr;
+ break;
+ case P_CHAR:
+ parm_table[i].def.cvalue =
+ *(char *)parm_table[i].ptr;
+ break;
+ case P_INTEGER:
+ case P_OCTAL:
+ case P_ENUM:
+ parm_table[i].def.ivalue =
+ *(int *)parm_table[i].ptr;
+ break;
+ case P_SEP:
+ break;
+ }
+ }
+ defaults_saved = True;
+}
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+static void set_server_role(void)
{
- int i;
- for (i=0;i<iNumServices;i++)
- if (VALID(i) && !snumused(i))
- {
- iSERVICE(i).valid = False;
- free_service(pSERVICE(i));
- }
+ server_role = ROLE_STANDALONE;
+
+ switch (lp_security())
+ {
+ case SEC_SHARE:
+ {
+ if (lp_domain_logons())
+ {
+ DEBUG(0,
+ ("Server's Role (logon server) conflicts with share-level security\n"));
+ }
+ break;
+ }
+ case SEC_SERVER:
+ case SEC_DOMAIN:
+ case SEC_ADS:
+ {
+ if (lp_domain_logons())
+ {
+ server_role = ROLE_DOMAIN_BDC;
+ break;
+ }
+ server_role = ROLE_DOMAIN_MEMBER;
+ break;
+ }
+ case SEC_USER:
+ {
+ if (lp_domain_logons())
+ {
+ server_role = ROLE_DOMAIN_PDC;
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ DEBUG(0,
+ ("Server's Role undefined due to unknown security mode\n"));
+ }
+ }
}
+
/***************************************************************************
Load the services array from the services file. Return True on success,
False on failure.
***************************************************************************/
-BOOL lp_load(char *pszFname,BOOL global_only)
+BOOL lp_load(char *pszFname, BOOL global_only, BOOL save_defaults,
+ BOOL add_ipc)
{
- pstring n2;
- BOOL bRetval;
-
- add_to_file_list(pszFname);
+ pstring n2;
+ BOOL bRetval;
+
+ pstrcpy(n2, pszFname);
+ standard_sub_basic(current_user_info.smb_name, n2);
+
+ add_to_file_list(pszFname, n2);
+
+ bRetval = False;
- bRetval = False;
+ bInGlobalSection = True;
+ bGlobalOnly = global_only;
- bInGlobalSection = True;
- bGlobalOnly = global_only;
-
- init_globals();
-
- strcpy(n2,pszFname);
- standard_sub_basic(n2);
+ init_globals();
- /* We get sections first, so have to start 'behind' to make up */
- iServiceIndex = -1;
- bRetval = pm_process(n2, do_section, do_parameter);
-
- /* finish up the last section */
- DEBUG(3,("pm_process() returned %s\n", BOOLSTR(bRetval)));
- if (bRetval)
- if (iServiceIndex >= 0)
- bRetval = service_ok(iServiceIndex);
+ if (save_defaults)
+ {
+ init_locals();
+ lp_save_defaults();
+ }
+
+ /* We get sections first, so have to start 'behind' to make up */
+ iServiceIndex = -1;
+ bRetval = pm_process(n2, do_section, do_parameter);
+
+ /* finish up the last section */
+ DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
+ if (bRetval)
+ if (iServiceIndex >= 0)
+ bRetval = service_ok(iServiceIndex);
- lp_add_auto_services(lp_auto_services());
- if (lp_load_printers())
- lp_add_all_printers();
+ lp_add_auto_services(lp_auto_services());
- lp_add_ipc();
+ if (add_ipc) {
+ lp_add_ipc("IPC$", True);
+ lp_add_ipc("ADMIN$", False);
+ }
+
+ set_server_role();
+ set_default_server_announce_type();
- bLoaded = True;
+ bLoaded = True;
+
+ /* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
+ /* if bWINSsupport is true and we are in the client */
+ if (in_client && Globals.bWINSsupport) {
+ string_set(&Globals.szWINSserver, "127.0.0.1");
+ }
- return (bRetval);
+ init_iconv();
+
+ return (bRetval);
}
/***************************************************************************
+reset the max number of services
+***************************************************************************/
+void lp_resetnumservices(void)
+{
+ iNumServices = 0;
+}
+
+/***************************************************************************
return the max number of services
***************************************************************************/
int lp_numservices(void)
{
- return(iNumServices);
+ return (iNumServices);
}
/***************************************************************************
Display the contents of the services array in human-readable form.
***************************************************************************/
-void lp_dump(void)
+void lp_dump(FILE *f, BOOL show_defaults, int maxtoprint)
{
- int iService;
+ int iService;
- dump_globals();
-
- dump_a_service(&sDefault);
+ if (show_defaults)
+ {
+ defaults_saved = False;
+ }
+
+ dump_globals(f);
- for (iService = 0; iService < iNumServices; iService++)
- {
- if (VALID(iService))
- {
- if (iSERVICE(iService).szService[0] == '\0')
- break;
- dump_a_service(pSERVICE(iService));
- }
- }
+ dump_a_service(&sDefault, f);
+
+ for (iService = 0; iService < maxtoprint; iService++)
+ lp_dump_one(f, show_defaults, iService);
+}
+
+/***************************************************************************
+Display the contents of one service in human-readable form.
+***************************************************************************/
+void lp_dump_one(FILE * f, BOOL show_defaults, int snum)
+{
+ if (VALID(snum))
+ {
+ if (ServicePtrs[snum]->szService[0] == '\0')
+ return;
+ dump_a_service(ServicePtrs[snum], f);
+ }
}
+
/***************************************************************************
Return the number of the service with the given name, or -1 if it doesn't
exist. Note that this is a DIFFERENT ANIMAL from the internal function
getservicebyname()! This works ONLY if all services have been loaded, and
does not copy the found service.
***************************************************************************/
-int lp_servicenumber(char *pszServiceName)
+int lp_servicenumber(const char *pszServiceName)
{
- int iService;
+ int iService;
+ fstring serviceName;
+
+
+ for (iService = iNumServices - 1; iService >= 0; iService--)
+ {
+ if (VALID(iService) && ServicePtrs[iService]->szService)
+ {
+ /*
+ * The substitution here is used to support %U is
+ * service names
+ */
+ fstrcpy(serviceName, ServicePtrs[iService]->szService);
+ standard_sub_basic(current_user_info.smb_name, serviceName);
+ if (strequal(serviceName, pszServiceName))
+ break;
+ }
+ }
- for (iService = iNumServices - 1; iService >= 0; iService--)
- if (VALID(iService) &&
- strwicmp(iSERVICE(iService).szService, pszServiceName) == 0)
- break;
+ if (iService < 0)
+ DEBUG(7,("lp_servicenumber: couldn't find %s\n", pszServiceName));
- if (iService < 0)
- DEBUG(7,("lp_servicenumber: couldn't find %s\n",pszServiceName));
-
- return (iService);
+ return (iService);
}
+/*******************************************************************
+ A useful volume label function. Returns a string in DOS codepage.
+********************************************************************/
+char *volume_label(int snum)
+{
+ char *ret = lp_volume(snum);
+ if (!*ret)
+ return lp_servicename(snum);
+ return (ret);
+}
/*******************************************************************
- get a workgroup - but map to standalone if '*'
- ******************************************************************/
-char *my_workgroup(void)
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+static void set_default_server_announce_type(void)
+{
+ default_server_announce = 0;
+ default_server_announce |= SV_TYPE_WORKSTATION;
+ default_server_announce |= SV_TYPE_SERVER;
+ default_server_announce |= SV_TYPE_SERVER_UNIX;
+ default_server_announce |= SV_TYPE_PRINTQ_SERVER;
+
+ switch (lp_announce_as())
+ {
+ case ANNOUNCE_AS_NT_SERVER:
+ {
+ default_server_announce |= SV_TYPE_SERVER_NT;
+ /* fall through... */
+ }
+ case ANNOUNCE_AS_NT_WORKSTATION:
+ {
+ default_server_announce |= SV_TYPE_NT;
+ break;
+ }
+ case ANNOUNCE_AS_WIN95:
+ {
+ default_server_announce |= SV_TYPE_WIN95_PLUS;
+ break;
+ }
+ case ANNOUNCE_AS_WFW:
+ {
+ default_server_announce |= SV_TYPE_WFW;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ switch (lp_server_role())
+ {
+ case ROLE_DOMAIN_MEMBER:
+ {
+ default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
+ break;
+ }
+ case ROLE_DOMAIN_PDC:
+ {
+ default_server_announce |= SV_TYPE_DOMAIN_CTRL;
+ break;
+ }
+ case ROLE_DOMAIN_BDC:
+ {
+ default_server_announce |= SV_TYPE_DOMAIN_BAKCTRL;
+ break;
+ }
+ case ROLE_STANDALONE:
+ default:
+ {
+ break;
+ }
+ }
+
+ if (lp_time_server())
+ {
+ default_server_announce |= SV_TYPE_TIME_SOURCE;
+ }
+
+ if (lp_host_msdfs())
+ {
+ default_server_announce |= SV_TYPE_DFS_SERVER;
+ }
+}
+
+/***********************************************************
+ returns role of Samba server
+************************************************************/
+
+int lp_server_role(void)
{
- char *res = lp_workgroup();
- if (*res == '*') return("STANDALONE");
- return(res);
+ return server_role;
}
+/***********************************************************
+ If we are PDC then prefer us as DMB
+************************************************************/
+
+BOOL lp_domain_master(void)
+{
+ if (Globals.bDomainMaster == Auto)
+ {
+ return (lp_server_role() == ROLE_DOMAIN_PDC);
+ }
+
+ return Globals.bDomainMaster;
+}
+
+/***********************************************************
+ If we are DMB then prefer us as LMB
+************************************************************/
+
+BOOL lp_preferred_master(void)
+{
+ if (Globals.bPreferredMaster == Auto)
+ {
+ return (lp_local_master() && lp_domain_master());
+ }
+
+ return Globals.bPreferredMaster;
+}
+
+
+
/*******************************************************************
- a useful volume label function
- ******************************************************************/
-char *volume_label(int snum)
+remove a service
+********************************************************************/
+void lp_remove_service(int snum)
+{
+ ServicePtrs[snum]->valid = False;
+}
+
+/*******************************************************************
+copy a service.
+********************************************************************/
+void lp_copy_service(int snum, char *new_name)
+{
+ char *oldname = lp_servicename(snum);
+ do_section(new_name);
+ if (snum >= 0)
+ {
+ snum = lp_servicenumber(new_name);
+ if (snum >= 0)
+ lp_do_parameter(snum, "copy", oldname);
+ }
+}
+
+
+/*******************************************************************
+ Get the default server type we will announce as via nmbd.
+********************************************************************/
+int lp_default_server_announce(void)
+{
+ return default_server_announce;
+}
+
+/*******************************************************************
+ Split the announce version into major and minor numbers.
+********************************************************************/
+int lp_major_announce_version(void)
+{
+ static BOOL got_major = False;
+ static int major_version = DEFAULT_MAJOR_VERSION;
+ char *vers;
+ char *p;
+
+ if (got_major)
+ return major_version;
+
+ got_major = True;
+ if ((vers = lp_announce_version()) == NULL)
+ return major_version;
+
+ if ((p = strchr_m(vers, '.')) == 0)
+ return major_version;
+
+ *p = '\0';
+ major_version = atoi(vers);
+ return major_version;
+}
+
+int lp_minor_announce_version(void)
+{
+ static BOOL got_minor = False;
+ static int minor_version = DEFAULT_MINOR_VERSION;
+ char *vers;
+ char *p;
+
+ if (got_minor)
+ return minor_version;
+
+ got_minor = True;
+ if ((vers = lp_announce_version()) == NULL)
+ return minor_version;
+
+ if ((p = strchr_m(vers, '.')) == 0)
+ return minor_version;
+
+ p++;
+ minor_version = atoi(p);
+ return minor_version;
+}
+
+/***********************************************************
+ Set the global name resolution order (used in smbclient).
+************************************************************/
+
+void lp_set_name_resolve_order(char *new_order)
+{
+ Globals.szNameResolveOrder = new_order;
+}
+
+char *lp_printername(int snum)
+{
+ char *ret = _lp_printername(snum);
+ if (ret == NULL || (ret != NULL && *ret == '\0'))
+ ret = lp_servicename(snum);
+
+ return ret;
+}
+
+
+/***********************************************************
+ List Parameters manipulation functions
+***********************************************************/
+
+#define P_LIST_ABS 16 /* P_LIST Allocation Block Size */
+
+char **lp_list_make(char *string)
+{
+ char **list, **rlist;
+ char *str, *s;
+ int num, lsize;
+ pstring tok;
+
+ if (!string || !*string) return NULL;
+ s = strdup(string);
+ if (!s) {
+ DEBUG(0,("lp_list_make: Unable to allocate memory"));
+ return NULL;
+ }
+
+ num = lsize = 0;
+ list = NULL;
+
+ str = s;
+ while (next_token(&str, tok, LIST_SEP, sizeof(pstring)))
+ {
+ if (num == lsize) {
+ lsize += P_LIST_ABS;
+ rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
+ if (!rlist) {
+ DEBUG(0,("lp_list_make: Unable to allocate memory"));
+ lp_list_free(&list);
+ SAFE_FREE(s);
+ return NULL;
+ }
+ else list = rlist;
+ memset (&list[num], 0, ((sizeof(char**)) * (P_LIST_ABS +1)));
+ }
+
+ list[num] = strdup(tok);
+ if (!list[num]) {
+ DEBUG(0,("lp_list_make: Unable to allocate memory"));
+ lp_list_free(&list);
+ SAFE_FREE(s);
+ return NULL;
+ }
+
+ num++;
+ }
+
+ SAFE_FREE(s);
+ return list;
+}
+
+BOOL lp_list_copy(char ***dest, char **src)
+{
+ char **list, **rlist;
+ int num, lsize;
+
+ *dest = NULL;
+ if (!src) return False;
+
+ num = lsize = 0;
+ list = NULL;
+
+ while (src[num])
+ {
+ if (num == lsize) {
+ lsize += P_LIST_ABS;
+ rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
+ if (!rlist) {
+ DEBUG(0,("lp_list_copy: Unable to allocate memory"));
+ lp_list_free(&list);
+ return False;
+ }
+ else list = rlist;
+ memset (&list[num], 0, ((sizeof(char **)) * (P_LIST_ABS +1)));
+ }
+
+ list[num] = strdup(src[num]);
+ if (!list[num]) {
+ DEBUG(0,("lp_list_copy: Unable to allocate memory"));
+ lp_list_free(&list);
+ return False;
+ }
+
+ num++;
+ }
+
+ *dest = list;
+ return True;
+}
+
+/* return true if all the elemnts of the list matches exactly */
+BOOL lp_list_compare(char **list1, char **list2)
+{
+ int num;
+
+ if (!list1 || !list2) return (list1 == list2);
+
+ for (num = 0; list1[num]; num++) {
+ if (!list2[num]) return False;
+ if (!strcsequal(list1[num], list2[num])) return False;
+ }
+ if (list2[num]) return False; /* if list2 has more elements than list1 fail */
+
+ return True;
+}
+
+void lp_list_free(char ***list)
+{
+ char **tlist;
+
+ if (!list || !*list) return;
+ tlist = *list;
+ for(; *tlist; tlist++) SAFE_FREE(*tlist);
+ SAFE_FREE(*list);
+}
+
+BOOL lp_list_substitute(char **list, const char *pattern, const char *insert)
+{
+ char *p, *s, *t;
+ ssize_t ls, lp, li, ld, i, d;
+
+ if (!list) return False;
+ if (!pattern) return False;
+ if (!insert) return False;
+
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+ ld = li -lp;
+
+ while (*list)
+ {
+ s = *list;
+ ls = (ssize_t)strlen(s);
+
+ while ((p = strstr(s, pattern)))
+ {
+ t = *list;
+ d = p -t;
+ if (ld)
+ {
+ t = (char *) malloc(ls +ld +1);
+ if (!t) {
+ DEBUG(0,("lp_list_substitute: Unable to allocate memory"));
+ return False;
+ }
+ memcpy(t, *list, d);
+ memcpy(t +d +li, p +lp, ls -d -lp +1);
+ SAFE_FREE(*list);
+ *list = t;
+ ls += ld;
+ s = t +d +li;
+ }
+
+ for (i = 0; i < li; i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ case '%':
+ case '\r':
+ case '\n':
+ t[d +i] = '_';
+ break;
+ default:
+ t[d +i] = insert[i];
+ }
+ }
+ }
+
+ list++;
+ }
+
+ return True;
+}
+
+/****************************************************************
+ Compatibility fn. for 2.2.2 code.....
+*****************************************************************/
+
+void get_private_directory(pstring privdir)
+{
+ pstrcpy (privdir, lp_private_dir());
+}
+
+
+/****************************************************************
+ Is netbios alias or name
+*****************************************************************/
+
+BOOL is_netbios_alias_or_name(char *name)
+{
+ char **netbios_aliases = lp_netbios_aliases();
+
+ if (StrCaseCmp(name, global_myname) == 0) {
+ return True;
+ }
+
+ for (netbios_aliases = lp_netbios_aliases();
+ netbios_aliases && *netbios_aliases;
+ netbios_aliases++) {
+ if (StrCaseCmp(name, *netbios_aliases) == 0) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/***********************************************************
+ Allow daemons such as winbindd to fix their logfile name.
+************************************************************/
+
+void lp_set_logfile(const char *name)
{
- char *ret = lp_volume(snum);
- if (!*ret) return(lp_servicename(snum));
- return(ret);
+ extern pstring debugf;
+ pstrcpy(Globals.szLogFile, name);
+ pstrcpy(debugf, name);
}
diff --git a/source/param/params.c b/source/param/params.c
index b9d61382a18..bc93a1fedfe 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -1,335 +1,599 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Parameter loading utlities
- Copyright (C) Karl Auer 1993,1994
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/**************************************************************************
-PARAMS.C
-
-Copyright (C) 1990, 1991, 1992, 1993, 1994 Karl Auer
-
-This module provides for streamlines retrieval of information from a
-Windows-like parameter files. There is a function which will search for
-all sections in the file and call a specified function with each. There is
-a similar function which will call a specified function for all parameters
-in a section. The idea is that you pass the addresses of suitable functions
-to a single function in this module which will then enumerate all sections,
-and within each section all parameters, to your program.
-
-Parameter files contain text lines (newline delimited) which consist of
-either a section name in square brackets or a parameter name, delimited
-from the parameter value by an equals sign. Blank lines or lines where the
-first non-whitespace character is a colon are ignored. All whitespace in
-section names and parameter names is compressed to single spaces. Leading
-and trailing whitespace on parameter names and parameter values is stripped.
-
-Only the first equals sign in a parameter line is significant - parameter
-values may contain equals signs, square brackets and semicolons. Internal
-whitespace is retained in parameter values. Parameter names may not start
-with a square bracket, an equals sign or a semicolon, for obvious reasons.
-
-A sample parameter file might look like this:
-
-[things]
-this=1
-that=2
-[other things]
-the other = 3
-
-**************************************************************************/
+/* -------------------------------------------------------------------------- **
+ * Microsoft Network Services for Unix, AKA., Andrew Tridgell's SAMBA.
+ *
+ * This module Copyright (C) 1990-1998 Karl Auer
+ *
+ * Rewritten almost completely by Christopher R. Hertel
+ * at the University of Minnesota, September, 1997.
+ * This module Copyright (C) 1997-1998 by the University of Minnesota
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Module name: params
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This module performs lexical analysis and initial parsing of a
+ * Windows-like parameter file. It recognizes and handles four token
+ * types: section-name, parameter-name, parameter-value, and
+ * end-of-file. Comments and line continuation are handled
+ * internally.
+ *
+ * The entry point to the module is function pm_process(). This
+ * function opens the source file, calls the Parse() function to parse
+ * the input, and then closes the file when either the EOF is reached
+ * or a fatal error is encountered.
+ *
+ * A sample parameter file might look like this:
+ *
+ * [section one]
+ * parameter one = value string
+ * parameter two = another value
+ * [section two]
+ * new parameter = some value or t'other
+ *
+ * The parameter file is divided into sections by section headers:
+ * section names enclosed in square brackets (eg. [section one]).
+ * Each section contains parameter lines, each of which consist of a
+ * parameter name and value delimited by an equal sign. Roughly, the
+ * syntax is:
+ *
+ * <file> :== { <section> } EOF
+ *
+ * <section> :== <section header> { <parameter line> }
+ *
+ * <section header> :== '[' NAME ']'
+ *
+ * <parameter line> :== NAME '=' VALUE '\n'
+ *
+ * Blank lines and comment lines are ignored. Comment lines are lines
+ * beginning with either a semicolon (';') or a pound sign ('#').
+ *
+ * All whitespace in section names and parameter names is compressed
+ * to single spaces. Leading and trailing whitespace is stipped from
+ * both names and values.
+ *
+ * Only the first equals sign in a parameter line is significant.
+ * Parameter values may contain equals signs, square brackets and
+ * semicolons. Internal whitespace is retained in parameter values,
+ * with the exception of the '\r' character, which is stripped for
+ * historic reasons. Parameter names may not start with a left square
+ * bracket, an equal sign, a pound sign, or a semicolon, because these
+ * are used to identify other tokens.
+ *
+ * -------------------------------------------------------------------------- **
+ */
#include "includes.h"
-#include "smb.h"
-#include "params.h"
-
-/* local variable pointing to passed filename */
-static char *pszParmFile = NULL;
-extern int DEBUGLEVEL;
-
-/* local prototypes */
-static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc);
-static BOOL enumerate_sections(FILE *infile,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc);
-
-/* prototypes for local toolbox functions */
-static void trimleft(char *psz);
-static void trimright(char *psz);
-static void collapse_spaces(char *psz);
-static int firstnonwhite(char *psz);
-
-/**************************************************************************
-Identifies all parameters in the current section, calls the parameter
-function for each. Ignores comment lines, stops and backs up in file when
-a section is encountered. Returns True on success, False on error.
-**************************************************************************/
-static BOOL enumerate_parameters(FILE *fileIn, PM_PARMFUNC pfunc)
+/* -------------------------------------------------------------------------- **
+ * Constants...
+ */
+
+#define BUFR_INC 1024
+
+
+/* -------------------------------------------------------------------------- **
+ * Variables...
+ *
+ * DEBUGLEVEL - The ubiquitous DEBUGLEVEL. This determines which DEBUG()
+ * messages will be produced.
+ * bufr - pointer to a global buffer. This is probably a kludge,
+ * but it was the nicest kludge I could think of (for now).
+ * bSize - The size of the global buffer <bufr>.
+ */
+
+static char *bufr = NULL;
+static int bSize = 0;
+
+/* we can't use FILE* due to the 256 fd limit - use this cheap hack
+ instead */
+typedef struct {
+ char *buf;
+ char *p;
+ size_t size;
+} myFILE;
+
+static int mygetc(myFILE *f)
{
- pstring szBuf;
- char *pszTemp;
- BOOL bRetval;
- long lFileOffset;
- int cTemp;
- BOOL bParmFound;
-
- bRetval = False;
- bParmFound = False;
- while (True)
- {
- /* first remember where we are */
- if ((lFileOffset = ftell(fileIn)) >= 0L)
- {
- /* then get and check a line */
- if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
- {
- /* stop - return OK unless file error */
- bRetval = !ferror(fileIn);
- if (!bRetval)
- DEBUG(0,( "Read error on configuration file (enumerating parameters)!\n"));
- break;
- }
- else
- /* if first non-white is a '[', stop (new section) */
- if ((cTemp = firstnonwhite(szBuf)) == '[')
- {
- /* restore position to start of new section */
- if (fseek(fileIn, lFileOffset, SEEK_SET) < 0L)
- {
- DEBUG(0,( "Seek error on configuration file!\n"));
- break;
- }
-
- /* return success */
- bRetval = True;
- break;
- }
- else
- /* if it's a semicolon or line is blank, ignore the line */
- if (!cTemp || strchr(";#",cTemp))
- {
- continue;
- }
- else
- /* if no equals sign and line contains non-whitespace */
- /* then line is badly formed */
- if ((pszTemp = strchr(szBuf, '=')) == NULL)
- {
- DEBUG(0,( "Ignoring badly formed line: %s", szBuf));
- }
- else
- {
- /* Note that we have found a parameter */
- bParmFound = True;
- /* cut line at the equals sign */
- *pszTemp++ = '\0';
- /* trim leading and trailing space from both halves */
- trimright(szBuf);
- trimleft(szBuf);
- trimright(pszTemp);
- trimleft(pszTemp);
- /* process the parameter iff passed pointer not NULL */
- if (pfunc != NULL)
- if (!pfunc(szBuf, pszTemp))
- break;
- }
- }
- }
- return (bRetval);
+ if (f->p >= f->buf+f->size) return EOF;
+ /* be sure to return chars >127 as positive values */
+ return (int)( *(f->p++) & 0x00FF );
}
+static void myfile_close(myFILE *f)
+{
+ if (!f) return;
+ SAFE_FREE(f->buf);
+ SAFE_FREE(f);
+}
-/***********************************************************************
-Close up s by n chars, at offset start.
-***********************************************************************/
-static void closestr(char *s, int start, int n)
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static int EatWhitespace( myFILE *InFile )
+ /* ------------------------------------------------------------------------ **
+ * Scan past whitespace (see ctype(3C)) and return the first non-whitespace
+ * character, or newline, or EOF.
+ *
+ * Input: InFile - Input source.
+ *
+ * Output: The next non-whitespace character in the input stream.
+ *
+ * Notes: Because the config files use a line-oriented grammar, we
+ * explicitly exclude the newline character from the list of
+ * whitespace characters.
+ * - Note that both EOF (-1) and the nul character ('\0') are
+ * considered end-of-file markers.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ for( c = mygetc( InFile ); isspace( c ) && ('\n' != c); c = mygetc( InFile ) )
+ ;
+ return( c );
+ } /* EatWhitespace */
+
+static int EatComment( myFILE *InFile )
+ /* ------------------------------------------------------------------------ **
+ * Scan to the end of a comment.
+ *
+ * Input: InFile - Input source.
+ *
+ * Output: The character that marks the end of the comment. Normally,
+ * this will be a newline, but it *might* be an EOF.
+ *
+ * Notes: Because the config files use a line-oriented grammar, we
+ * explicitly exclude the newline character from the list of
+ * whitespace characters.
+ * - Note that both EOF (-1) and the nul character ('\0') are
+ * considered end-of-file markers.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ for( c = mygetc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = mygetc( InFile ) )
+ ;
+ return( c );
+ } /* EatComment */
+
+/*****************************************************************************
+ * Scan backards within a string to discover if the last non-whitespace
+ * character is a line-continuation character ('\\').
+ *
+ * Input: line - A pointer to a buffer containing the string to be
+ * scanned.
+ * pos - This is taken to be the offset of the end of the
+ * string. This position is *not* scanned.
+ *
+ * Output: The offset of the '\\' character if it was found, or -1 to
+ * indicate that it was not.
+ *
+ *****************************************************************************/
+
+static int Continuation(char *line, int pos )
{
- char *src;
- char *dest;
- int len;
+ pos--;
+ while( (pos >= 0) && isspace((int)line[pos]))
+ pos--;
- if (n > 0)
- if ((src = dest = s) != NULL)
+ return (((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
+}
+
+
+static BOOL Section( myFILE *InFile, BOOL (*sfunc)(char *) )
+ /* ------------------------------------------------------------------------ **
+ * Scan a section name, and pass the name to function sfunc().
+ *
+ * Input: InFile - Input source.
+ * sfunc - Pointer to the function to be called if the section
+ * name is successfully read.
+ *
+ * Output: True if the section name was read and True was returned from
+ * <sfunc>. False if <sfunc> failed or if a lexical error was
+ * encountered.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+ int i;
+ int end;
+ char *func = "params.c:Section() -";
+
+ i = 0; /* <i> is the offset of the next free byte in bufr[] and */
+ end = 0; /* <end> is the current "end of string" offset. In most */
+ /* cases these will be the same, but if the last */
+ /* character written to bufr[] is a space, then <end> */
+ /* will be one less than <i>. */
+
+ c = EatWhitespace( InFile ); /* We've already got the '['. Scan */
+ /* past initial white space. */
+
+ while( (EOF != c) && (c > 0) )
+ {
+
+ /* Check that the buffer is big enough for the next character. */
+ if( i > (bSize - 2) )
{
- len = strlen(s);
- if (start >= 0 && start < len - n)
- {
- src += start + n;
- dest += start;
-
- while (*src)
- *dest++ = *src++;
- *dest = '\0';
- }
+ char *tb;
+
+ tb = Realloc( bufr, bSize +BUFR_INC );
+ if( NULL == tb )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
+ bufr = tb;
+ bSize += BUFR_INC;
}
-}
-/**************************************************************************
-Identifies all sections in the parameter file, calls passed section_func()
-for each, passing the section name, then calls enumerate_parameters().
-Returns True on success, False on failure. Note that the section and
-parameter names will have all internal whitespace areas collapsed to a
-single space for processing.
-**************************************************************************/
-static BOOL enumerate_sections(FILE *fileIn,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
-{
- pstring szBuf;
- BOOL bRetval;
- BOOL bSectionFound;
-
- /* this makes sure we get include lines right */
- enumerate_parameters(fileIn, pfunc);
-
- bRetval = False;
- bSectionFound = False;
- while (True)
- {
- if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
+ /* Handle a single character. */
+ switch( c )
{
- /* stop - return OK unless file error */
- bRetval = !ferror(fileIn);
- if (!bRetval)
- DEBUG(0,( "Read error on configuration file (enumerating sections)!\n"));
- break;
+ case ']': /* Found the closing bracket. */
+ bufr[end] = '\0';
+ if( 0 == end ) /* Don't allow an empty name. */
+ {
+ DEBUG(0, ("%s Empty section name in configuration file.\n", func ));
+ return( False );
+ }
+ if( !sfunc(bufr) ) /* Got a valid name. Deal with it. */
+ return( False );
+ (void)EatComment( InFile ); /* Finish off the line. */
+ return( True );
+
+ case '\n': /* Got newline before closing ']'. */
+ i = Continuation( bufr, i ); /* Check for line continuation. */
+ if( i < 0 )
+ {
+ bufr[end] = '\0';
+ DEBUG(0, ("%s Badly formed line in configuration file: %s\n",
+ func, bufr ));
+ return( False );
+ }
+ end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+ c = mygetc( InFile ); /* Continue with next line. */
+ break;
+
+ default: /* All else are a valid name chars. */
+ if( isspace( c ) ) /* One space per whitespace region. */
+ {
+ bufr[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ }
+ else /* All others copy verbatim. */
+ {
+ bufr[i++] = c;
+ end = i;
+ c = mygetc( InFile );
+ }
}
- else
+ }
+
+ /* We arrive here if we've met the EOF before the closing bracket. */
+ DEBUG(0, ("%s Unexpected EOF in the configuration file: %s\n", func, bufr ));
+ return( False );
+ } /* Section */
+
+static BOOL Parameter( myFILE *InFile, BOOL (*pfunc)(char *, char *), int c )
+ /* ------------------------------------------------------------------------ **
+ * Scan a parameter name and value, and pass these two fields to pfunc().
+ *
+ * Input: InFile - The input source.
+ * pfunc - A pointer to the function that will be called to
+ * process the parameter, once it has been scanned.
+ * c - The first character of the parameter name, which
+ * would have been read by Parse(). Unlike a comment
+ * line or a section header, there is no lead-in
+ * character that can be discarded.
+ *
+ * Output: True if the parameter name and value were scanned and processed
+ * successfully, else False.
+ *
+ * Notes: This function is in two parts. The first loop scans the
+ * parameter name. Internal whitespace is compressed, and an
+ * equal sign (=) terminates the token. Leading and trailing
+ * whitespace is discarded. The second loop scans the parameter
+ * value. When both have been successfully identified, they are
+ * passed to pfunc() for processing.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int i = 0; /* Position within bufr. */
+ int end = 0; /* bufr[end] is current end-of-string. */
+ int vstart = 0; /* Starting position of the parameter value. */
+ char *func = "params.c:Parameter() -";
+
+ /* Read the parameter name. */
+ while( 0 == vstart ) /* Loop until we've found the start of the value. */
+ {
+
+ if( i > (bSize - 2) ) /* Ensure there's space for next char. */
{
- trimleft(szBuf);
- trimright(szBuf);
- if (szBuf[0] == '[')
- {
- closestr(szBuf, 0, 1);
- if (strlen(szBuf) > 1)
- if (szBuf[strlen(szBuf) - 1] == ']')
- {
- /* found a section - note the fact */
- bSectionFound = True;
- /* remove trailing metabracket */
- szBuf[strlen(szBuf) - 1] = '\0';
- /* remove leading and trailing whitespace from name */
- trimleft(szBuf);
- trimright(szBuf);
- /* reduce all internal whitespace to one space */
- collapse_spaces(szBuf);
- /* process it - stop if the processing fails */
- if (sfunc != NULL)
- if (!sfunc(szBuf))
- break;
- if (!enumerate_parameters(fileIn, pfunc))
- break;
- }
- }
+ char *tb;
+
+ tb = Realloc( bufr, bSize + BUFR_INC );
+ if( NULL == tb )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
+ bufr = tb;
+ bSize += BUFR_INC;
}
- }
-
- return (bRetval);
-}
-
-/**************************************************************************
-Process the passed parameter file.
-
-Returns True if successful, else False.
-**************************************************************************/
-BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
-{
- FILE *fileIn;
- BOOL bRetval;
- bRetval = False;
+ switch( c )
+ {
+ case '=': /* Equal sign marks end of param name. */
+ if( 0 == end ) /* Don't allow an empty name. */
+ {
+ DEBUG(0, ("%s Invalid parameter name in config. file.\n", func ));
+ return( False );
+ }
+ bufr[end++] = '\0'; /* Mark end of string & advance. */
+ i = end; /* New string starts here. */
+ vstart = end; /* New string is parameter value. */
+ bufr[i] = '\0'; /* New string is nul, for now. */
+ break;
+
+ case '\n': /* Find continuation char, else error. */
+ i = Continuation( bufr, i );
+ if( i < 0 )
+ {
+ bufr[end] = '\0';
+ DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n",
+ func, bufr ));
+ return( True );
+ }
+ end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+ c = mygetc( InFile ); /* Read past eoln. */
+ break;
+
+ case '\0': /* Shouldn't have EOF within param name. */
+ case EOF:
+ bufr[i] = '\0';
+ DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, bufr ));
+ return( True );
+
+ default:
+ if( isspace( c ) ) /* One ' ' per whitespace region. */
+ {
+ bufr[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ }
+ else /* All others verbatim. */
+ {
+ bufr[i++] = c;
+ end = i;
+ c = mygetc( InFile );
+ }
+ }
+ }
- /* record the filename for use in error messages one day... */
- pszParmFile = pszFileName;
+ /* Now parse the value. */
+ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
+ while( (EOF !=c) && (c > 0) )
+ {
- if (pszParmFile == NULL || strlen(pszParmFile) < 1)
- DEBUG(0,( "No configuration filename specified!\n"));
- else
- if ((fileIn = fopen(pszParmFile, "r")) == NULL)
- DEBUG(0,( "Unable to open configuration file \"%s\"!\n", pszParmFile));
- else
+ if( i > (bSize - 2) ) /* Make sure there's enough room. */
{
- DEBUG(2,( "Processing configuration file \"%s\"\n", pszParmFile));
- bRetval = enumerate_sections(fileIn, sfunc, pfunc);
- fclose(fileIn);
+ char *tb;
+
+ tb = Realloc( bufr, bSize + BUFR_INC );
+ if( NULL == tb )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
+ bufr = tb;
+ bSize += BUFR_INC;
}
- if (!bRetval)
- DEBUG(0,("pm_process retuned false\n"));
- return (bRetval);
-}
-
+ switch( c )
+ {
+ case '\r': /* Explicitly remove '\r' because the older */
+ c = mygetc( InFile ); /* version called fgets_slash() which also */
+ break; /* removes them. */
+
+ case '\n': /* Marks end of value unless there's a '\'. */
+ i = Continuation( bufr, i );
+ if( i < 0 )
+ c = 0;
+ else
+ {
+ for( end = i; (end >= 0) && isspace((int)bufr[end]); end-- )
+ ;
+ c = mygetc( InFile );
+ }
+ break;
+
+ default: /* All others verbatim. Note that spaces do */
+ bufr[i++] = c; /* not advance <end>. This allows trimming */
+ if( !isspace( c ) ) /* of whitespace at the end of the line. */
+ end = i;
+ c = mygetc( InFile );
+ break;
+ }
+ }
+ bufr[end] = '\0'; /* End of value. */
+
+ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
+ } /* Parameter */
+
+static BOOL Parse( myFILE *InFile,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) )
+ /* ------------------------------------------------------------------------ **
+ * Scan & parse the input.
+ *
+ * Input: InFile - Input source.
+ * sfunc - Function to be called when a section name is scanned.
+ * See Section().
+ * pfunc - Function to be called when a parameter is scanned.
+ * See Parameter().
+ *
+ * Output: True if the file was successfully scanned, else False.
+ *
+ * Notes: The input can be viewed in terms of 'lines'. There are four
+ * types of lines:
+ * Blank - May contain whitespace, otherwise empty.
+ * Comment - First non-whitespace character is a ';' or '#'.
+ * The remainder of the line is ignored.
+ * Section - First non-whitespace character is a '['.
+ * Parameter - The default case.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ c = EatWhitespace( InFile );
+ while( (EOF != c) && (c > 0) )
+ {
+ switch( c )
+ {
+ case '\n': /* Blank line. */
+ c = EatWhitespace( InFile );
+ break;
+
+ case ';': /* Comment line. */
+ case '#':
+ c = EatComment( InFile );
+ break;
+
+ case '[': /* Section Header. */
+ if( !Section( InFile, sfunc ) )
+ return( False );
+ c = EatWhitespace( InFile );
+ break;
+
+ case '\\': /* Bogus backslash. */
+ c = EatWhitespace( InFile );
+ break;
+
+ default: /* Parameter line. */
+ if( !Parameter( InFile, pfunc, c ) )
+ return( False );
+ c = EatWhitespace( InFile );
+ break;
+ }
+ }
+ return( True );
+ } /* Parse */
+
+static myFILE *OpenConfFile( char *FileName )
+ /* ------------------------------------------------------------------------ **
+ * Open a configuration file.
+ *
+ * Input: FileName - The pathname of the config file to be opened.
+ *
+ * Output: A pointer of type (char **) to the lines of the file
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ char *func = "params.c:OpenConfFile() -";
+ extern BOOL in_client;
+ int lvl = in_client?1:0;
+ myFILE *ret;
+
+ ret = (myFILE *)malloc(sizeof(*ret));
+ if (!ret) return NULL;
+
+ ret->buf = file_load(FileName, &ret->size);
+ if( NULL == ret->buf )
+ {
+ DEBUG( lvl,
+ ("%s Unable to open configuration file \"%s\":\n\t%s\n",
+ func, FileName, strerror(errno)) );
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ ret->p = ret->buf;
+ return( ret );
+ } /* OpenConfFile */
+
+BOOL pm_process( char *FileName,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) )
+ /* ------------------------------------------------------------------------ **
+ * Process the named parameter file.
+ *
+ * Input: FileName - The pathname of the parameter file to be opened.
+ * sfunc - A pointer to a function that will be called when
+ * a section name is discovered.
+ * pfunc - A pointer to a function that will be called when
+ * a parameter name and value are discovered.
+ *
+ * Output: TRUE if the file was successfully parsed, else FALSE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int result;
+ myFILE *InFile;
+ char *func = "params.c:pm_process() -";
+
+ InFile = OpenConfFile( FileName ); /* Open the config file. */
+ if( NULL == InFile )
+ return( False );
+
+ DEBUG( 3, ("%s Processing configuration file \"%s\"\n", func, FileName) );
+
+ if( NULL != bufr ) /* If we already have a buffer */
+ result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */
+ /* use it. */
+
+ else /* If we don't have a buffer */
+ { /* allocate one, then parse, */
+ bSize = BUFR_INC; /* then free. */
+ bufr = (char *)malloc( bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0,("%s memory allocation failure.\n", func));
+ myfile_close(InFile);
+ return( False );
+ }
+ result = Parse( InFile, sfunc, pfunc );
+ SAFE_FREE( bufr );
+ bufr = NULL;
+ bSize = 0;
+ }
-/**************************************************************************
-Strip all leading whitespace from a string.
-**************************************************************************/
-static void trimleft(char *psz)
-{
- char *pszDest;
-
- pszDest = psz;
- if (psz != NULL)
- {
- while (*psz != '\0' && isspace(*psz))
- psz++;
- while (*psz != '\0')
- *pszDest++ = *psz++;
- *pszDest = '\0';
- }
-}
+ myfile_close(InFile);
-/**************************************************************************
-Strip all trailing whitespace from a string.
-**************************************************************************/
-static void trimright(char *psz)
-{
- char *pszTemp;
-
- if (psz != NULL && psz[0] != '\0')
- {
- pszTemp = psz + strlen(psz) - 1;
- while (isspace(*pszTemp))
- *pszTemp-- = '\0';
- }
-}
+ if( !result ) /* Generic failure. */
+ {
+ DEBUG(0,("%s Failed. Error returned from params.c:parse().\n", func));
+ return( False );
+ }
-/***********************************************************************
-Collapse each whitespace area in a string to a single space.
-***********************************************************************/
-static void collapse_spaces(char *psz)
-{
- while (*psz)
- if (isspace(*psz))
- {
- *psz++ = ' ';
- trimleft(psz);
- }
- else
- psz++;
-}
+ return( True ); /* Generic success. */
+ } /* pm_process */
-/**************************************************************************
-Return the value of the first non-white character in the specified string.
-The terminating NUL counts as non-white for the purposes of this function.
-Note - no check for a NULL string! What would we return?
-**************************************************************************/
-static int firstnonwhite(char *psz)
-{
- while (isspace(*psz) && (*psz != '\0'))
- psz++;
- return (*psz);
-}
+/* -------------------------------------------------------------------------- */
diff --git a/source/parsing.doc b/source/parsing.doc
new file mode 100644
index 00000000000..d26a64ae4e8
--- /dev/null
+++ b/source/parsing.doc
@@ -0,0 +1,363 @@
+Chris Hertel, Samba Team
+November 1997
+
+This is a quick overview of the lexical analysis, syntax, and semantics
+of the smb.conf file.
+
+Lexical Analysis:
+
+ Basically, the file is processed on a line by line basis. There are
+ four types of lines that are recognized by the lexical analyzer
+ (params.c):
+
+ Blank lines - Lines containing only whitespace.
+ Comment lines - Lines beginning with either a semi-colon or a
+ pound sign (';' or '#').
+ Section header lines - Lines beginning with an open square bracket
+ ('[').
+ Parameter lines - Lines beginning with any other character.
+ (The default line type.)
+
+ The first two are handled exclusively by the lexical analyzer, which
+ ignores them. The latter two line types are scanned for
+
+ - Section names
+ - Parameter names
+ - Parameter values
+
+ These are the only tokens passed to the parameter loader
+ (loadparm.c). Parameter names and values are divided from one
+ another by an equal sign: '='.
+
+
+ Handling of Whitespace:
+
+ Whitespace is defined as all characters recognized by the isspace()
+ function (see ctype(3C)) except for the newline character ('\n')
+ The newline is excluded because it identifies the end of the line.
+
+ - The lexical analyzer scans past white space at the beginning of a
+ line.
+
+ - Section and parameter names may contain internal white space. All
+ whitespace within a name is compressed to a single space character.
+
+ - Internal whitespace within a parameter value is kept verbatim with
+ the exception of carriage return characters ('\r'), all of which
+ are removed.
+
+ - Leading and trailing whitespace is removed from names and values.
+
+
+ Handling of Line Continuation:
+
+ Long section header and parameter lines may be extended across
+ multiple lines by use of the backslash character ('\\'). Line
+ continuation is ignored for blank and comment lines.
+
+ If the last (non-whitespace) character within a section header or on
+ a parameter line is a backslash, then the next line will be
+ (logically) concatonated with the current line by the lexical
+ analyzer. For example:
+
+ param name = parameter value string \
+ with line continuation.
+
+ Would be read as
+
+ param name = parameter value string with line continuation.
+
+ Note that there are five spaces following the word 'string',
+ representing the one space between 'string' and '\\' in the top
+ line, plus the four preceeding the word 'with' in the second line.
+ (Yes, I'm counting the indentation.)
+
+ Line continuation characters are ignored on blank lines and at the end
+ of comments. They are *only* recognized within section and parameter
+ lines.
+
+
+ Line Continuation Quirks:
+
+ Note the following example:
+
+ param name = parameter value string \
+ \
+ with line continuation.
+
+ The middle line is *not* parsed as a blank line because it is first
+ concatonated with the top line. The result is
+
+ param name = parameter value string with line continuation.
+
+ The same is true for comment lines.
+
+ param name = parameter value string \
+ ; comment \
+ with a comment.
+
+ This becomes:
+
+ param name = parameter value string ; comment with a comment.
+
+ On a section header line, the closing bracket (']') is considered a
+ terminating character, and the rest of the line is ignored. The lines
+
+ [ section name ] garbage \
+ param name = value
+
+ are read as
+
+ [section name]
+ param name = value
+
+
+
+Syntax:
+
+ The syntax of the smb.conf file is as follows:
+
+ <file> :== { <section> } EOF
+
+ <section> :== <section header> { <parameter line> }
+
+ <section header> :== '[' NAME ']'
+
+ <parameter line> :== NAME '=' VALUE NL
+
+
+ Basically, this means that
+
+ - a file is made up of zero or more sections, and is terminated by
+ an EOF (we knew that).
+
+ - A section is made up of a section header followed by zero or more
+ parameter lines.
+
+ - A section header is identified by an opening bracket and
+ terminated by the closing bracket. The enclosed NAME identifies
+ the section.
+
+ - A parameter line is divided into a NAME and a VALUE. The *first*
+ equal sign on the line separates the NAME from the VALUE. The
+ VALUE is terminated by a newline character (NL = '\n').
+
+
+About params.c:
+
+ The parsing of the config file is a bit unusual if you are used to
+ lex, yacc, bison, etc. Both lexical analysis (scanning) and parsing
+ are performed by params.c. Values are loaded via callbacks to
+ loadparm.c.
+
+--------------------------------------------------------------------------
+
+ Samba DEBUG
+
+Chris Hertel, Samba Team
+July, 1998
+
+ Here's the scoop on the update to the DEBUG() system.
+
+ First, my goals are:
+ * Backward compatibility (ie., I don't want to break any Samba code
+ that already works).
+ * Debug output should be timestamped and easy to read (format-wise).
+ * Debug output should be parsable by software.
+ * There should be convenient tools for composing debug messages.
+
+ NOTE: the Debug functionality has been moved from util.c to the new
+ debug.c module.
+
+New Output Syntax
+
+ The syntax of a debugging log file is represented as:
+ <debugfile> :== { <debugmsg> }
+
+ <debugmsg> :== <debughdr> '\n' <debugtext>
+
+ <debughdr> :== '[' TIME ',' LEVEL ']' FILE ':' [FUNCTION] '(' LINE ')'
+
+ <debugtext> :== { <debugline> }
+
+ <debugline> :== TEXT '\n'
+
+ TEXT is a string of characters excluding the newline character.
+ LEVEL is the DEBUG level of the message (an integer in the range
+ 0..10).
+ TIME is a timestamp.
+ FILE is the name of the file from which the debug message was
+ generated.
+ FUNCTION is the function from which the debug message was generated.
+ LINE is the line number of the debug statement that generated the
+ message.
+
+ Basically, what that all means is:
+ * A debugging log file is made up of debug messages.
+ * Each debug message is made up of a header and text. The header is
+ separated from the text by a newline.
+ * The header begins with the timestamp and debug level of the
+ message enclosed in brackets. The filename, function, and line
+ number at which the message was generated follow. The filename is
+ terminated by a colon, and the function name is terminated by the
+ parenthesis which contain the line number. Depending upon the
+ compiler, the function name may be missing (it is generated by the
+ __FUNCTION__ macro, which is not universally implemented, dangit).
+ * The message text is made up of zero or more lines, each terminated
+ by a newline.
+
+ Here's some example output:
+
+ [1998/08/03 12:55:25, 1] nmbd.c:(659)
+ Netbios nameserver version 1.9.19-prealpha started.
+ Copyright Andrew Tridgell 1994-1997
+ [1998/08/03 12:55:25, 3] loadparm.c:(763)
+ Initializing global parameters
+
+ Note that in the above example the function names are not listed on
+ the header line. That's because the example above was generated on an
+ SGI Indy, and the SGI compiler doesn't support the __FUNCTION__ macro.
+
+The DEBUG() Macro
+
+ Use of the DEBUG() macro is unchanged. DEBUG() takes two parameters.
+ The first is the message level, the second is the body of a function
+ call to the Debug1() function.
+
+ That's confusing.
+
+ Here's an example which may help a bit. If you would write
+
+ printf( "This is a %s message.\n", "debug" );
+
+ to send the output to stdout, then you would write
+
+ DEBUG( 0, ( "This is a %s message.\n", "debug" ) );
+
+ to send the output to the debug file. All of the normal printf()
+ formatting escapes work.
+
+ Note that in the above example the DEBUG message level is set to 0.
+ Messages at level 0 always print. Basically, if the message level is
+ less than or equal to the global value DEBUGLEVEL, then the DEBUG
+ statement is processed.
+
+ The output of the above example would be something like:
+
+ [1998/07/30 16:00:51, 0] file.c:function(128)
+ This is a debug message.
+
+ Each call to DEBUG() creates a new header *unless* the output produced
+ by the previous call to DEBUG() did not end with a '\n'. Output to the
+ debug file is passed through a formatting buffer which is flushed
+ every time a newline is encountered. If the buffer is not empty when
+ DEBUG() is called, the new input is simply appended.
+
+ ...but that's really just a Kludge. It was put in place because
+ DEBUG() has been used to write partial lines. Here's a simple (dumb)
+ example of the kind of thing I'm talking about:
+
+ DEBUG( 0, ("The test returned " ) );
+ if( test() )
+ DEBUG(0, ("True") );
+ else
+ DEBUG(0, ("False") );
+ DEBUG(0, (".\n") );
+
+ Without the format buffer, the output (assuming test() returned true)
+ would look like this:
+
+ [1998/07/30 16:00:51, 0] file.c:function(256)
+ The test returned
+ [1998/07/30 16:00:51, 0] file.c:function(258)
+ True
+ [1998/07/30 16:00:51, 0] file.c:function(261)
+ .
+
+ Which isn't much use. The format buffer kludge fixes this problem.
+
+The DEBUGADD() Macro
+
+ In addition to the kludgey solution to the broken line problem
+ described above, there is a clean solution. The DEBUGADD() macro never
+ generates a header. It will append new text to the current debug
+ message even if the format buffer is empty. The syntax of the
+ DEBUGADD() macro is the same as that of the DEBUG() macro.
+
+ DEBUG( 0, ("This is the first line.\n" ) );
+ DEBUGADD( 0, ("This is the second line.\nThis is the third line.\n" ) );
+
+ Produces
+ [1998/07/30 16:00:51, 0] file.c:function(512)
+ This is the first line.
+ This is the second line.
+ This is the third line.
+
+The DEBUGLVL() Macro
+
+ One of the problems with the DEBUG() macro was that DEBUG() lines
+ tended to get a bit long. Consider this example from
+ nmbd_sendannounce.c:
+
+ DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
+ type, global_myname, subrec->subnet_name, work->work_group));
+
+ One solution to this is to break it down using DEBUG() and DEBUGADD(),
+ as follows:
+
+ DEBUG( 3, ( "send_local_master_announcement: " ) );
+ DEBUGADD( 3, ( "type %x for name %s ", type, global_myname ) );
+ DEBUGADD( 3, ( "on subnet %s ", subrec->subnet_name ) );
+ DEBUGADD( 3, ( "for workgroup %s\n", work->work_group ) );
+
+ A similar, but arguably nicer approach is to use the DEBUGLVL() macro.
+ This macro returns True if the message level is less than or equal to
+ the global DEBUGLEVEL value, so:
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "send_local_master_announcement: " );
+ dbgtext( "type %x for name %s ", type, global_myname );
+ dbgtext( "on subnet %s ", subrec->subnet_name );
+ dbgtext( "for workgroup %s\n", work->work_group );
+ }
+
+ (The dbgtext() function is explained below.)
+
+ There are a few advantages to this scheme:
+ * The test is performed only once.
+ * You can allocate variables off of the stack that will only be used
+ within the DEBUGLVL() block.
+ * Processing that is only relevant to debug output can be contained
+ within the DEBUGLVL() block.
+
+New Functions
+
+ dbgtext()
+ This function prints debug message text to the debug file (and
+ possibly to syslog) via the format buffer. The function uses a
+ variable argument list just like printf() or Debug1(). The
+ input is printed into a buffer using the vslprintf() function,
+ and then passed to format_debug_text().
+
+ If you use DEBUGLVL() you will probably print the body of the
+ message using dbgtext().
+
+ dbghdr()
+ This is the function that writes a debug message header.
+ Headers are not processed via the format buffer. Also note that
+ if the format buffer is not empty, a call to dbghdr() will not
+ produce any output. See the comments in dbghdr() for more info.
+
+ It is not likely that this function will be called directly. It
+ is used by DEBUG() and DEBUGADD().
+
+ format_debug_text()
+ This is a static function in debug.c. It stores the output text
+ for the body of the message in a buffer until it encounters a
+ newline. When the newline character is found, the buffer is
+ written to the debug file via the Debug1() function, and the
+ buffer is reset. This allows us to add the indentation at the
+ beginning of each line of the message body, and also ensures
+ that the output is written a line at a time (which cleans up
+ syslog output).
diff --git a/source/passdb/.cvsignore b/source/passdb/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/passdb/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/passdb/ldap.c b/source/passdb/ldap.c
new file mode 100644
index 00000000000..e0ac013fc8f
--- /dev/null
+++ b/source/passdb/ldap.c
@@ -0,0 +1,1017 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Jean François Micouleau 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef WITH_LDAP
+
+#include "includes.h"
+
+#include <lber.h>
+#include <ldap.h>
+
+#define ADD_USER 1
+#define MODIFY_USER 2
+
+/*******************************************************************
+ open a connection to the ldap serve.
+******************************************************************/
+static BOOL ldap_open_connection(LDAP **ldap_struct)
+{
+ if ( (*ldap_struct = ldap_open(lp_ldap_server(),lp_ldap_port()) ) == NULL)
+ {
+ DEBUG( 0, ( "The LDAP server is not responding !\n" ) );
+ return( False );
+ }
+ DEBUG(2,("ldap_open_connection: connection opened\n"));
+ return (True);
+}
+
+
+/*******************************************************************
+ connect anonymously to the ldap server.
+ FIXME: later (jfm)
+******************************************************************/
+static BOOL ldap_connect_anonymous(LDAP *ldap_struct)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server !\n" ) );
+ return(False);
+ }
+ return (True);
+}
+
+
+/*******************************************************************
+ connect to the ldap server under system privileg.
+******************************************************************/
+static BOOL ldap_connect_system(LDAP *ldap_struct)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server!\n" ) );
+ return(False);
+ }
+ DEBUG(2,("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ connect to the ldap server under a particular user.
+******************************************************************/
+static BOOL ldap_connect_user(LDAP *ldap_struct, const char *user, const char *password)
+{
+ if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) ! = LDAP_SUCCESS)
+ {
+ DEBUG( 0, ( "Couldn't bind to the LDAP server !\n" ) );
+ return(False);
+ }
+ DEBUG(2,("ldap_connect_user: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static BOOL ldap_search_one_user(LDAP *ldap_struct, char *filter, LDAPMessage **result)
+{
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+
+ DEBUG(2,("ldap_search_one_user: searching for:[%s]\n", filter));
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, result);
+
+ if (rc ! = LDAP_SUCCESS )
+ {
+ DEBUG( 0, ( "Problem during the LDAP search\n" ) );
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static BOOL ldap_search_one_user_by_name(LDAP *ldap_struct, const char *user, LDAPMessage **result)
+{
+ pstring filter;
+ /*
+ in the filter expression, replace %u with the real name
+ so in ldap filter, %u MUST exist :-)
+ */
+ pstrcpy(filter,lp_ldap_filter());
+ pstring_sub(filter,"%u",user);
+
+ if ( !ldap_search_one_user(ldap_struct, filter, result) )
+ {
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static BOOL ldap_search_one_user_by_uid(LDAP *ldap_struct, int uid, LDAPMessage **result)
+{
+ pstring filter;
+
+ slprintf(filter, sizeof(pstring)-1, "uidAccount = %d", uid);
+
+ if ( !ldap_search_one_user(ldap_struct, filter, result) )
+ {
+ return(False);
+ }
+ return (True);
+}
+
+/*******************************************************************
+ search an attribute and return the first value found.
+******************************************************************/
+static void get_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, char *attribute, char *value)
+{
+ char **valeurs;
+
+ if ( (valeurs = ldap_get_values(ldap_struct, entry, attribute)) ! = NULL)
+ {
+ pstrcpy(value, valeurs[0]);
+ ldap_value_free(valeurs);
+ DEBUG(3,("get_single_attribute: [%s] = [%s]\n", attribute, value));
+ }
+ else
+ {
+ value = NULL;
+ }
+}
+
+/*******************************************************************
+ check if the returned entry is a sambaAccount objectclass.
+******************************************************************/
+static BOOL ldap_check_user(LDAP *ldap_struct, LDAPMessage *entry)
+{
+ BOOL sambaAccount = False;
+ char **valeur;
+ int i;
+
+ DEBUG(2,("ldap_check_user: "));
+ valeur = ldap_get_values(ldap_struct, entry, "objectclass");
+ if (valeur! = NULL)
+ {
+ for (i = 0;valeur[i]! = NULL;i++)
+ {
+ if (!strcmp(valeur[i],"sambaAccount")) sambaAccount = True;
+ }
+ }
+ DEBUG(2,("%s\n",sambaAccount?"yes":"no"));
+ ldap_value_free(valeur);
+ return (sambaAccount);
+}
+
+/*******************************************************************
+ check if the returned entry is a sambaTrust objectclass.
+******************************************************************/
+static BOOL ldap_check_trust(LDAP *ldap_struct, LDAPMessage *entry)
+{
+ BOOL sambaTrust = False;
+ char **valeur;
+ int i;
+
+ DEBUG(2,("ldap_check_trust: "));
+ valeur = ldap_get_values(ldap_struct, entry, "objectclass");
+ if (valeur! = NULL)
+ {
+ for (i = 0;valeur[i]! = NULL;i++)
+ {
+ if (!strcmp(valeur[i],"sambaTrust")) sambaTrust = True;
+ }
+ }
+ DEBUG(2,("%s\n",sambaTrust?"yes":"no"));
+ ldap_value_free(valeur);
+ return (sambaTrust);
+}
+
+/*******************************************************************
+ retrieve the user's info and contruct a smb_passwd structure.
+******************************************************************/
+static void ldap_get_smb_passwd(LDAP *ldap_struct,LDAPMessage *entry,
+ struct smb_passwd *user)
+{
+ static pstring user_name;
+ static pstring user_pass;
+ static pstring temp;
+ static unsigned char smblmpwd[16];
+ static unsigned char smbntpwd[16];
+
+ pdb_init_smb(user);
+
+ memset((char *)smblmpwd, '\0', sizeof(smblmpwd));
+ memset((char *)smbntpwd, '\0', sizeof(smbntpwd));
+
+ get_single_attribute(ldap_struct, entry, "cn", user_name);
+ DEBUG(2,("ldap_get_smb_passwd: user: %s\n",user_name));
+
+#ifdef LDAP_PLAINTEXT_PASSWORD
+ get_single_attribute(ldap_struct, entry, "userPassword", temp);
+ nt_lm_owf_gen(temp, user->smb_nt_passwd, user->smb_passwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+#else
+ get_single_attribute(ldap_struct, entry, "unicodePwd", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+
+ get_single_attribute(ldap_struct, entry, "dBCSPwd", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp)); /* destroy local copy of the password */
+#endif
+
+ get_single_attribute(ldap_struct, entry, "userAccountControl", temp);
+ user->acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+
+ /* the smb (unix) ids are not stored: they are created */
+ user->smb_userid = pdb_user_rid_to_uid (atoi(temp));
+
+ if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
+ {
+ DEBUG(0,("Inconsistency in the LDAP database\n"));
+ }
+ if (user->acct_ctrl & ACB_NORMAL)
+ {
+ user->smb_name = user_name;
+ user->smb_passwd = smblmpwd;
+ user->smb_nt_passwd = smbntpwd;
+ }
+}
+
+/*******************************************************************
+ retrieve the user's info and contruct a sam_passwd structure.
+
+ calls ldap_get_smb_passwd function first, though, to save code duplication.
+
+******************************************************************/
+static void ldap_get_sam_passwd(LDAP *ldap_struct, LDAPMessage *entry,
+ struct sam_passwd *user)
+{
+ static pstring user_name;
+ static pstring fullname;
+ static pstring home_dir;
+ static pstring dir_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring workstations;
+ static pstring temp;
+ static struct smb_passwd pw_buf;
+
+ pdb_init_sam(user);
+
+ ldap_get_smb_passwd(ldap_struct, entry, &pw_buf);
+
+ user->pass_last_set_time = pw_buf.pass_last_set_time;
+
+ get_single_attribute(ldap_struct, entry, "logonTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logoffTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
+ user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
+
+ user->smb_name = pw_buf.smb_name;
+
+ DEBUG(2,("ldap_get_sam_passwd: user: %s\n", user_name));
+
+ get_single_attribute(ldap_struct, entry, "userFullName", fullname);
+ user->full_name = fullname;
+
+ get_single_attribute(ldap_struct, entry, "homeDirectory", home_dir);
+ user->home_dir = home_dir;
+
+ get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
+ user->dir_drive = dir_drive;
+
+ get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
+ user->logon_script = logon_script;
+
+ get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
+ user->profile_path = profile_path;
+
+ get_single_attribute(ldap_struct, entry, "comment", acct_desc);
+ user->acct_desc = acct_desc;
+
+ get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
+ user->workstations = workstations;
+
+ user->unknown_str = NULL; /* don't know, yet! */
+ user->munged_dial = NULL; /* "munged" dial-back telephone number */
+
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user->user_rid = atoi(temp);
+
+ get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
+ user->group_rid = atoi(temp);
+
+ /* the smb (unix) ids are not stored: they are created */
+ user->smb_userid = pw_buf.smb_userid;
+ user->smb_grpid = group_rid_to_uid(user->group_rid);
+
+ user->acct_ctrl = pw_buf.acct_ctrl;
+
+ user->unknown_3 = 0xffffff; /* don't know */
+ user->logon_divs = 168; /* hours per week */
+ user->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->hours, 0xff, user->hours_len); /* available at all hours */
+ user->unknown_5 = 0x00000000; /* don't know */
+ user->unknown_6 = 0x000004ec; /* don't know */
+
+ if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
+ {
+ DEBUG(0,("Inconsistency in the LDAP database\n"));
+ }
+
+ if (!(user->acct_ctrl & ACB_NORMAL))
+ {
+ DEBUG(0,("User's acct_ctrl bits not set to ACT_NORMAL in LDAP database\n"));
+ return;
+ }
+}
+
+/************************************************************************
+ Routine to manage the LDAPMod structure array
+ manage memory used by the array, by each struct, and values
+
+************************************************************************/
+static void make_a_mod(LDAPMod ***modlist,int modop, const char *attribute, const char *value)
+{
+ LDAPMod **mods, **tmods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (mods == NULL)
+ {
+ tmods = (LDAPMod **)malloc( sizeof(LDAPMod *) );
+ if (tmods == NULL)
+ {
+ DEBUG(0,("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods = tmods;
+ mods[0] = NULL;
+ }
+
+ for ( i = 0; mods[ i ] ! = NULL; ++i )
+ {
+ if ( mods[ i ]->mod_op == modop &&
+ !strcasecmp( mods[ i ]->mod_type, attribute ) )
+ {
+ break;
+ }
+ }
+
+ if (mods[i] == NULL)
+ {
+ tmods = (LDAPMod **)Realloc( mods, (i+2) * sizeof( LDAPMod * ) );
+ if (tmods == NULL)
+ {
+ DEBUG(0,("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods = tmods;
+ mods[i] = (LDAPMod *)malloc( sizeof( LDAPMod ) );
+ if (mods[i] == NULL)
+ {
+ DEBUG(0,("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i]->mod_op = modop;
+ mods[i]->mod_values = NULL;
+ mods[i]->mod_type = strdup( attribute );
+ mods[i+1] = NULL;
+ }
+
+ if (value ! = NULL )
+ {
+ char **tmval;
+
+ j = 0;
+ if ( mods[ i ]->mod_values ! = NULL )
+ {
+ for ( ; mods[ i ]->mod_values[ j ] ! = NULL; j++ );
+ }
+ tmval = (char **)Realloc(mods[ i ]->mod_values,
+ (j+2) * sizeof( char * ));
+ if ( tmval == NULL)
+ {
+ DEBUG(0, "make_a_mod: Memory allocation failure!\n");
+ return;
+ }
+ mods[ i ]->mod_values = tmval;
+ mods[ i ]->mod_values[ j ] = strdup(value);
+ mods[ i ]->mod_values[ j + 1 ] = NULL;
+ }
+ *modlist = mods;
+}
+
+/************************************************************************
+ Add or modify an entry. Only the smb struct values
+
+*************************************************************************/
+static BOOL modadd_ldappwd_entry(struct smb_passwd *newpwd, int flag)
+{
+
+ /* assume the struct is correct and filled
+ that's the job of passdb.c to check */
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+ char *smb_name;
+ int trust = False;
+ int ldap_state;
+ pstring filter;
+ pstring dn;
+ pstring lmhash;
+ pstring nthash;
+ pstring rid;
+ pstring lst;
+ pstring temp;
+
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMod **mods;
+
+ smb_name = newpwd->smb_name;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (smb_name[strlen(smb_name)-1] == '$' )
+ {
+ smb_name[strlen(smb_name)-1] = '\0';
+ trust = True;
+ }
+
+ slprintf(filter, sizeof(filter)-1,
+ "(&(cn = %s)(|(objectclass = sambaTrust)(objectclass = sambaAccount)))",
+ smb_name);
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &result);
+
+ switch (flag)
+ {
+ case ADD_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 0)
+ {
+ DEBUG(0,("User already in the base, with samba properties\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_ADD;
+ break;
+ }
+ case MODIFY_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(0,("No user to modify !\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_REPLACE;
+ break;
+ }
+ default:
+ {
+ DEBUG(0,("How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+ slprintf(dn, sizeof(dn)-1, "cn = %s, %s",smb_name, lp_ldap_suffix() );
+
+ if (newpwd->smb_passwd ! = NULL)
+ {
+ int i;
+ for( i = 0; i < 16; i++)
+ {
+ slprintf(&temp[2*i], sizeof(temp) - 1, "%02X", newpwd->smb_passwd[i]);
+ }
+
+ }
+ else
+ {
+ if (newpwd->acct_ctrl & ACB_PWNOTREQ)
+ {
+ slprintf(temp, sizeof(temp) - 1, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ }
+ else
+ {
+ slprintf(temp, sizeof(temp) - 1, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ }
+ slprintf(lmhash, sizeof(lmhash)-1, "%s", temp);
+
+ if (newpwd->smb_nt_passwd ! = NULL)
+ {
+ int i;
+ for( i = 0; i < 16; i++)
+ {
+ slprintf(&temp[2*i], sizeof(temp) - 1, "%02X", newpwd->smb_nt_passwd[i]);
+ }
+
+ }
+ else
+ {
+ if (newpwd->acct_ctrl & ACB_PWNOTREQ)
+ {
+ slprintf(temp, sizeof(temp) - 1, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ }
+ else
+ {
+ slprintf(temp, sizeof(temp) - 1, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ }
+ slprintf(nthash, sizeof(nthash)-1, "%s", temp);
+
+ slprintf(rid, sizeof(rid)-1, "%d", uid_to_user_rid(newpwd->smb_userid) );
+ slprintf(lst, sizeof(lst)-1, "%08X", newpwd->pass_last_set_time);
+
+ mods = NULL;
+
+ if (trust)
+ {
+ make_a_mod(&mods, ldap_state, "objectclass", "sambaTrust");
+ make_a_mod(&mods, ldap_state, "netbiosTrustName", smb_name);
+ make_a_mod(&mods, ldap_state, "trustPassword", nthash);
+ }
+ else
+ {
+ make_a_mod(&mods, ldap_state, "objectclass", "sambaAccount");
+ make_a_mod(&mods, ldap_state, "dBCSPwd", lmhash);
+ make_a_mod(&mods, ldap_state, "uid", smb_name);
+ make_a_mod(&mods, ldap_state, "unicodePwd", nthash);
+ }
+
+ make_a_mod(&mods, ldap_state, "cn", smb_name);
+
+ make_a_mod(&mods, ldap_state, "rid", rid);
+ make_a_mod(&mods, ldap_state, "pwdLastSet", lst);
+ make_a_mod(&mods, ldap_state, "userAccountControl",
+ smbpasswd_encode_acb_info(newpwd->acct_ctrl));
+
+ switch(flag)
+ {
+ case ADD_USER:
+ {
+ ldap_add_s(ldap_struct, dn, mods);
+ DEBUG(2,("modadd_ldappwd_entry: added: cn = %s in the LDAP database\n",smb_name));
+ break;
+ }
+ case MODIFY_USER:
+ {
+ ldap_modify_s(ldap_struct, dn, mods);
+ DEBUG(2,("modadd_ldappwd_entry: changed: cn = %s in the LDAP database_n",smb_name));
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("modadd_ldappwd_entry: How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+
+ ldap_mods_free(mods, 1);
+
+ ldap_unbind(ldap_struct);
+
+ return True;
+}
+
+/************************************************************************
+ Add or modify an entry. everything except the smb struct
+
+*************************************************************************/
+static BOOL modadd_ldap21pwd_entry(struct sam_passwd *newpwd, int flag)
+{
+
+ /* assume the struct is correct and filled
+ that's the job of passdb.c to check */
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+ char *smb_name;
+ int trust = False;
+ int ldap_state;
+ pstring filter;
+ pstring dn;
+ pstring lmhash;
+ pstring nthash;
+ pstring rid;
+ pstring lst;
+ pstring temp;
+
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMod **mods;
+
+ smb_name = newpwd->smb_name;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (smb_name[strlen(smb_name)-1] == '$' )
+ {
+ smb_name[strlen(smb_name)-1] = '\0';
+ trust = True;
+ }
+
+ slprintf(filter, sizeof(filter)-1,
+ "(&(cn = %s)(|(objectclass = sambaTrust)(objectclass = sambaAccount)))",
+ smb_name);
+
+ rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &result);
+
+ switch (flag)
+ {
+ case ADD_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(2,("User already in the base, with samba properties\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_ADD;
+ break;
+ }
+
+ case MODIFY_USER:
+ {
+ if (ldap_count_entries(ldap_struct, result) ! = 1)
+ {
+ DEBUG(2,("No user to modify !\n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_state = LDAP_MOD_REPLACE;
+ break;
+ }
+
+ default:
+ {
+ DEBUG(2,("How did you come here? \n"));
+ ldap_unbind(ldap_struct);
+ return False;
+ break;
+ }
+ }
+ slprintf(dn, sizeof(dn)-1, "cn = %s, %s",smb_name, lp_ldap_suffix() );
+
+ mods = NULL;
+
+ if (trust)
+ {
+ }
+ else
+ {
+ }
+
+ make_a_mod(&mods, ldap_state, "cn", smb_name);
+
+ make_a_mod(&mods, ldap_state, "rid", rid);
+ make_a_mod(&mods, ldap_state, "pwdLastSet", lst);
+ make_a_mod(&mods, ldap_state, "userAccountControl",
+ smbpasswd_encode_acct_ctrl(newpwd->acct_ctrl));
+
+ ldap_modify_s(ldap_struct, dn, mods);
+
+ ldap_mods_free(mods, 1);
+
+ ldap_unbind(ldap_struct);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to add an entry to the ldap passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_ldappwd_entry(struct smb_passwd *newpwd)
+{
+ return (modadd_ldappwd_entry(newpwd, ADD_USER) );
+}
+
+/************************************************************************
+ Routine to search the ldap passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startldappwent()/
+ getldappwent()/endldappwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_ldappwd_entry(struct smb_passwd *pwd, BOOL override)
+{
+ return (modadd_ldappwd_entry(pwd, MODIFY_USER) );
+}
+
+/************************************************************************
+ Routine to add an entry to the ldap passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_ldap21pwd_entry(struct sam_passwd *newpwd)
+{
+ return( modadd_ldappwd_entry(newpwd, ADD_USER)?
+ modadd_ldap21pwd_entry(newpwd, ADD_USER):False);
+}
+
+/************************************************************************
+ Routine to search the ldap passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startldappwent()/
+ getldappwent()/endldappwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_ldap21pwd_entry(struct sam_passwd *pwd, BOOL override)
+{
+ return( modadd_ldappwd_entry(pwd, MODIFY_USER)?
+ modadd_ldap21pwd_entry(pwd, MODIFY_USER):False);
+}
+
+struct ldap_enum_info
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+};
+
+static struct ldap_enum_info ldap_ent;
+
+/***************************************************************
+ Start to enumerate the ldap passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ do not call this function directly. use passdb.c instead.
+
+ ****************************************************************/
+static void *startldappwent(BOOL update)
+{
+ int scope = LDAP_SCOPE_ONELEVEL;
+ int rc;
+
+ pstring filter;
+
+ if (!ldap_open_connection(&ldap_ent.ldap_struct)) /* open a connection to the server */
+ {
+ return NULL;
+ }
+
+ if (!ldap_connect_system(ldap_ent.ldap_struct)) /* connect as system account */
+ {
+ return NULL;
+ }
+
+ /* when the class is known the search is much faster */
+ switch (0)
+ {
+ case 1:
+ {
+ pstrcpy(filter, "objectclass = sambaAccount");
+ break;
+ }
+ case 2:
+ {
+ pstrcpy(filter, "objectclass = sambaTrust");
+ break;
+ }
+ default:
+ {
+ pstrcpy(filter, "(|(objectclass = sambaTrust)(objectclass = sambaAccount))");
+ break;
+ }
+ }
+
+ rc = ldap_search_s(ldap_ent.ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &ldap_ent.result);
+
+ DEBUG(2,("%d entries in the base!\n", ldap_count_entries(ldap_ent.ldap_struct, ldap_ent.result) ));
+
+ ldap_ent.entry = ldap_first_entry(ldap_ent.ldap_struct, ldap_ent.result);
+
+ return &ldap_ent;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct smb_passwd *getldappwent(void *vp)
+{
+ static struct smb_passwd user;
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+
+ ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
+
+ if (ldap_vp->entry ! = NULL)
+ {
+ ldap_get_smb_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
+ return &user;
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct sam_passwd *getldap21pwent(void *vp)
+{
+ static struct sam_passwd user;
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+
+ ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
+
+ if (ldap_vp->entry ! = NULL)
+ {
+ ldap_get_sam_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
+ return &user;
+ }
+ return NULL;
+}
+
+/***************************************************************
+ End enumeration of the ldap passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+****************************************************************/
+static void endldappwent(void *vp)
+{
+ struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
+ ldap_msgfree(ldap_vp->result);
+ ldap_unbind(ldap_vp->ldap_struct);
+}
+
+/*************************************************************************
+ Return the current position in the ldap passwd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static SMB_BIG_UINT getldappwpos(void *vp)
+{
+ return (SMB_BIG_UINT)0;
+}
+
+/*************************************************************************
+ Set the current position in the ldap passwd list from SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL setldappwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return False;
+}
+
+/*
+ * Ldap derived functions.
+ */
+
+static struct smb_passwd *getldappwnam(char *name)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwnam(name));
+}
+
+static struct smb_passwd *getldappwuid(uid_t smb_userid)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwuid(smb_userid));
+}
+
+static struct smb_passwd *getldappwrid(uint32 user_rid)
+{
+ return pdb_sam_to_smb(iterate_getsam21pwuid(pdb_user_rid_to_uid(user_rid)));
+}
+
+static struct smb_passwd *getldappwent(void *vp)
+{
+ return pdb_sam_to_smb(getldap21pwent(vp));
+}
+
+static BOOL add_ldappwd_entry(struct smb_passwd *newpwd)
+{
+ return add_ldap21pwd_entry(pdb_smb_to_sam(newpwd));
+}
+
+static BOOL mod_ldappwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ return mod_ldap21pwd_entry(pdb_smb_to_sam(pwd), override);
+}
+
+static BOOL del_ldappwd_entry(const char *name)
+{
+ return False; /* Dummy... */
+}
+
+static struct sam_passwd *getldap21pwuid(uid_t uid)
+{
+ return pdb_smb_to_sam(iterate_getsam21pwuid(pdb_uid_to_user_rid(uid)));
+}
+
+static struct passdb_ops ldap_ops =
+{
+ startldappwent,
+ endldappwent,
+ getldappwpos,
+ setldappwpos,
+ getldappwnam,
+ getldappwuid,
+ getldappwrid,
+ getldappwent,
+ add_ldappwd_entry,
+ mod_ldappwd_entry,
+ del_ldappwd_entry,
+ getldap21pwent,
+ iterate_getsam21pwnam, /* From passdb.c */
+ iterate_getsam21pwuid, /* From passdb.c */
+ iterate_getsam21pwrid, /* From passdb.c */
+ add_ldap21pwd_entry,
+ mod_ldap21pwd_entry
+};
+
+struct passdb_ops *ldap_initialize_password_db(void)
+{
+ return &ldap_ops;
+}
+
+#else
+ void dummy_function(void);
+ void dummy_function(void) { } /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/machine_sid.c b/source/passdb/machine_sid.c
new file mode 100644
index 00000000000..859f00b4c6e
--- /dev/null
+++ b/source/passdb/machine_sid.c
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Read the machine SID from a file.
+****************************************************************************/
+
+static BOOL read_sid_from_file(int fd, char *sid_file)
+{
+ fstring fline;
+
+ memset(fline, '\0', sizeof(fline));
+
+ if(read(fd, fline, sizeof(fline) -1 ) < 0) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Convert to the machine SID.
+ */
+
+ fline[sizeof(fline)-1] = '\0';
+ if(!string_to_sid( &global_sam_sid, fline)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Generate the global machine sid. Look for the MACHINE.SID file first, if
+ not found then look in smb.conf and use it to create the MACHINE.SID file.
+ Note this function will be replaced soon. JRA.
+****************************************************************************/
+
+BOOL pdb_generate_sam_sid(void)
+{
+ int fd;
+ pstring sid_file;
+ fstring sid_string;
+ SMB_STRUCT_STAT st;
+ BOOL overwrite_bad_sid = False;
+
+ generate_wellknown_sids();
+
+ pstrcpy(sid_file, lp_private_dir());
+
+ if (!directory_exist(sid_file, NULL)) {
+ if (mkdir(sid_file, 0700) != 0) {
+ DEBUG(0,("can't create private directory %s : %s\n",
+ sid_file, strerror(errno)));
+ return False;
+ }
+ }
+
+ pstrcat(sid_file, "/MACHINE.SID");
+
+ if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
+ DEBUG(0,("unable to open or create file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Check if the file contains data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * We have a valid SID - read it.
+ */
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ /*
+ * JRA. Reversed the sense of this test now that I have
+ * actually done this test *personally*. One more reason
+ * to never trust third party information you have not
+ * independently verified.... sigh. JRA.
+ */
+
+ if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
+ /*
+ * Fix and re-write...
+ */
+ overwrite_bad_sid = True;
+ global_sam_sid.sub_auths[0] = 21;
+ DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
+detected - re-writing to be decimal 21 instead.\n" ));
+ sid_to_string(sid_string, &global_sam_sid);
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
+ DEBUG(0,("unable to seek file file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ } else {
+ close(fd);
+ return True;
+ }
+ } else {
+ /*
+ * The file contains no data - we need to generate our
+ * own sid.
+ * Generate the new sid data & turn it into a string.
+ */
+ int i;
+ uchar raw_sid_data[12];
+ DOM_SID mysid;
+
+ memset((char *)&mysid, '\0', sizeof(DOM_SID));
+ mysid.sid_rev_num = 1;
+ mysid.id_auth[5] = 5;
+ mysid.num_auths = 0;
+ mysid.sub_auths[mysid.num_auths++] = 21;
+
+ generate_random_buffer( raw_sid_data, 12, True);
+ for( i = 0; i < 3; i++)
+ mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
+
+ sid_to_string(sid_string, &mysid);
+ }
+
+ fstrcat(sid_string, "\n");
+
+ /*
+ * Ensure our new SID is valid.
+ */
+
+ if(!string_to_sid( &global_sam_sid, sid_string)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ /*
+ * Do an exclusive blocking lock on the file.
+ */
+
+ if(!do_file_lock( fd, 60, F_WRLCK)) {
+ DEBUG(0,("unable to lock file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(!overwrite_bad_sid) {
+ /*
+ * At this point we have a blocking lock on the SID
+ * file - check if in the meantime someone else wrote
+ * SID data into the file. If so - they were here first,
+ * use their data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * Unlock as soon as possible to reduce
+ * contention on the exclusive lock.
+ */
+ do_file_lock( fd, 60, F_UNLCK);
+
+ /*
+ * We have a valid SID - read it.
+ */
+
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ close(fd);
+ return True;
+ }
+ }
+
+ /*
+ * The file is still empty and we have an exlusive lock on it,
+ * or we're fixing an earlier mistake.
+ * Write out out SID data into the file.
+ */
+
+ /*
+ * Use chmod here as some (strange) UNIX's don't
+ * have fchmod. JRA.
+ */
+
+ if(chmod(sid_file, 0644) < 0) {
+ DEBUG(0,("unable to set correct permissions on file %s. \
+Error was %s\n", sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
+ DEBUG(0,("unable to write file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ /*
+ * Unlock & exit.
+ */
+
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return True;
+}
+
+
diff --git a/source/passdb/nispass.c b/source/passdb/nispass.c
new file mode 100644
index 00000000000..2b1f6b54927
--- /dev/null
+++ b/source/passdb/nispass.c
@@ -0,0 +1,1083 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_NISPLUS
+
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
+
+#if defined(GROUP)
+#undef GROUP
+#endif
+
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
+
+#endif
+
+#include <rpcsvc/nis.h>
+
+extern int DEBUGLEVEL;
+
+static VOLATILE sig_atomic_t gotalarm;
+
+/***************************************************************
+
+ the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
+
+ name=S,nogw=r
+ uid=S,nogw=r
+ user_rid=S,nogw=r
+ smb_grpid=,nw+r
+ group_rid=,nw+r
+ acb=,nw+r
+
+ lmpwd=C,nw=,g=r,o=rm
+ ntpwd=C,nw=,g=r,o=rm
+
+ logon_t=,nw+r
+ logoff_t=,nw+r
+ kick_t=,nw+r
+ pwdlset_t=,nw+r
+ pwdlchg_t=,nw+r
+ pwdmchg_t=,nw+r
+
+ full_name=,nw+r
+ home_dir=,nw+r
+ dir_drive=,nw+r
+ logon_script=,nw+r
+ profile_path=,nw+r
+ acct_desc=,nw+r
+ workstations=,nw+r
+
+ hours=,nw+r
+
+****************************************************************/
+
+#define NPF_NAME 0
+#define NPF_UID 1
+#define NPF_USER_RID 2
+#define NPF_SMB_GRPID 3
+#define NPF_GROUP_RID 4
+#define NPF_ACB 5
+#define NPF_LMPWD 6
+#define NPF_NTPWD 7
+#define NPF_LOGON_T 8
+#define NPF_LOGOFF_T 9
+#define NPF_KICK_T 10
+#define NPF_PWDLSET_T 11
+#define NPF_PWDLCHG_T 12
+#define NPF_PWDMCHG_T 13
+#define NPF_FULL_NAME 14
+#define NPF_HOME_DIR 15
+#define NPF_DIR_DRIVE 16
+#define NPF_LOGON_SCRIPT 17
+#define NPF_PROFILE_PATH 18
+#define NPF_ACCT_DESC 19
+#define NPF_WORKSTATIONS 20
+#define NPF_HOURS 21
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ make_nisname_from_user_rid
+ ****************************************************************/
+static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_uid
+ ****************************************************************/
+static char *make_nisname_from_uid(int uid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_name
+ ****************************************************************/
+static char *make_nisname_from_name(char *user_name, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
+ safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/*************************************************************************
+ gets a NIS+ attribute
+ *************************************************************************/
+static void get_single_attribute(nis_object *new_obj, int col,
+ char *val, int len)
+{
+ int entry_len;
+
+ if (new_obj == NULL || val == NULL) return;
+
+ entry_len = ENTRY_LEN(new_obj, col);
+ if (len > entry_len)
+ {
+ DEBUG(10,("get_single_attribute: entry length truncated\n"));
+ len = entry_len;
+ }
+
+ safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ object.
+ ************************************************************************/
+static BOOL make_sam_from_nisp_object(struct sam_passwd *pw_buf, nis_object *obj)
+{
+ int uidval;
+ static pstring user_name;
+ static pstring full_name;
+ static pstring home_dir;
+ static pstring home_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring workstations;
+ static pstring temp;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+
+ char *p;
+
+ pdb_init_sam(pw_buf);
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ pstrcpy(user_name, ENTRY_VAL(obj, NPF_NAME));
+ pw_buf->smb_name = user_name;
+
+ uidval = atoi(ENTRY_VAL(obj, NPF_UID));
+ pw_buf->smb_userid = uidval;
+
+ /* Check the lanman password column. */
+ p = (char *)ENTRY_VAL(obj, NPF_LMPWD);
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("make_sam_from_nisp_object: entry invalidated for user %s\n", user_name));
+ pw_buf->smb_nt_passwd = NULL;
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_DISABLED;
+ return True;
+ }
+ if (!strncasecmp(p, "NO PASSWORD", 11)) {
+ pw_buf->smb_passwd = NULL;
+ pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (strlen(p) != 32 || !pdb_gethexpwd(p, smbpwd))
+ {
+ DEBUG(0, ("make_sam_from_nisp_object: malformed LM pwd entry.\n"));
+ return False;
+ }
+ }
+
+ pw_buf->smb_passwd = smbpwd;
+
+ /* Check the NT password column. */
+ p = ENTRY_VAL(obj, NPF_NTPWD);
+ if (*p != '*' && *p != 'X') {
+ if (strlen(p) != 32 || !pdb_gethexpwd(p, smbntpwd))
+ {
+ DEBUG(0, ("make_smb_from_nisp_object: malformed NT pwd entry\n"));
+ return False;
+ }
+ pw_buf->smb_nt_passwd = smbntpwd;
+ }
+
+ p = (char *)ENTRY_VAL(obj, NPF_ACB);
+ if (*p == '[')
+ {
+ pw_buf->acct_ctrl = pdb_decode_acct_ctrl(p);
+
+ /* Must have some account type set. */
+ if(pw_buf->acct_ctrl == 0)
+ pw_buf->acct_ctrl = ACB_NORMAL;
+
+ /* Now try and get the last change time. */
+ if(*p == ']')
+ p++;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp(p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf->pass_last_set_time = (time_t)strtol(p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
+ pw_buf->acct_ctrl &= ~ACB_NORMAL;
+ pw_buf->acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ get_single_attribute(obj, NPF_SMB_GRPID, temp, sizeof(pstring));
+ pw_buf->smb_grpid = atoi(temp);
+
+ get_single_attribute(obj, NPF_USER_RID, temp, sizeof(pstring));
+ pw_buf->user_rid = (strlen(temp) > 0) ?
+ strtol(temp, NULL, 16) : pdb_uid_to_user_rid (pw_buf->smb_userid);
+
+ if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$') {
+
+ get_single_attribute(obj, NPF_GROUP_RID, temp, sizeof(pstring));
+
+ if (strlen(temp) > 0)
+ pw_buf->group_rid = strtol(temp, NULL, 16);
+ else {
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pw_buf->smb_grpid, &map, MAPPING_WITHOUT_PRIV)) {
+ pw_buf->group_rid = map.rid;
+ }
+ else
+ pw_buf->group_rid = pdb_gid_to_group_rid(pw_buf->smb_grpid);
+ }
+
+ get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
+#if 1
+ /* It seems correct to use the global values - but in that case why
+ * do we want these NIS+ entries anyway ??
+ */
+ pstrcpy(logon_script , lp_logon_script ());
+ pstrcpy(profile_path , lp_logon_path ());
+ pstrcpy(home_drive , lp_logon_drive ());
+ pstrcpy(home_dir , lp_logon_home ());
+#else
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script, sizeof(pstring));
+ get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
+ get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
+ get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
+#endif
+ get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
+ get_single_attribute(obj, NPF_WORKSTATIONS, workstations, sizeof(pstring));
+
+ } else {
+
+ pw_buf->group_rid = DOMAIN_GROUP_RID_USERS; /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+
+ pstrcpy(full_name , "");
+ pstrcpy(logon_script , "");
+ pstrcpy(profile_path , "");
+ pstrcpy(home_drive , "");
+ pstrcpy(home_dir , "");
+ pstrcpy(acct_desc , "");
+ pstrcpy(workstations , "");
+ }
+
+ pw_buf->full_name = full_name;
+ pw_buf->home_dir = home_dir;
+ pw_buf->dir_drive = home_drive;
+ pw_buf->logon_script = logon_script;
+ pw_buf->profile_path = profile_path;
+ pw_buf->acct_desc = acct_desc;
+ pw_buf->workstations = workstations;
+
+ pw_buf->unknown_str = NULL; /* don't know, yet! */
+ pw_buf->munged_dial = NULL; /* "munged" dial-back telephone number */
+
+ pw_buf->unknown_3 = 0xffffff; /* don't know */
+ pw_buf->logon_divs = 168; /* hours per week */
+ pw_buf->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(pw_buf->hours, 0xff, pw_buf->hours_len); /* available at all hours */
+ pw_buf->unknown_5 = 0x00000000; /* don't know */
+ pw_buf->unknown_6 = 0x000004ec; /* don't know */
+
+ return True;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisresult(struct sam_passwd *pw_buf, nis_result *result)
+{
+ if (pw_buf == NULL || result == NULL) return False;
+
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(0, ("make_sam_from_nisresult: NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("make_sam_from_nisresult: user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("make_sam_from_nisresult: WARNING: Multiple entries for user in NIS+ table!\n"));
+ }
+
+ /* Grab the first hit. */
+ return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
+ }
+
+/***************************************************************
+ calls nis_list, returns results.
+ ****************************************************************/
+static nis_result *nisp_get_nis_list(char *nis_name)
+{
+ nis_result *result;
+ result = nis_list(nis_name, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("nisp_get_nis_list: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+ return result;
+}
+
+
+
+struct nisp_enum_info
+{
+ nis_result *result;
+ int enum_entry;
+};
+
+/***************************************************************
+ Start to enumerate the nisplus passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ do not call this function directly. use passdb.c instead.
+
+ ****************************************************************/
+static void *startnisppwent(BOOL update)
+{
+ static struct nisp_enum_info res;
+ res.result = nisp_get_nis_list(lp_smb_passwd_file());
+ res.enum_entry = 0;
+ return res.result != NULL ? &res : NULL;
+}
+
+/***************************************************************
+ End enumeration of the nisplus passwd list.
+****************************************************************/
+static void endnisppwent(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ nis_freeresult(res->result);
+ DEBUG(7,("endnisppwent: freed enumeration list\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwent(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ static struct sam_passwd pw_buf;
+ int which;
+ BOOL ret;
+
+ if (res == NULL || (int)(res->enum_entry) < 0 ||
+ (int)(res->enum_entry) > (NIS_RES_NUMOBJ(res->result) - 1)) {
+ ret = False;
+ } else {
+ which = (int)(res->enum_entry);
+ ret = make_sam_from_nisp_object(&pw_buf,
+ &NIS_RES_OBJECT(res->result)[which]);
+ if (ret && which < (NIS_RES_NUMOBJ(res->result) - 1))
+ (int)(res->enum_entry)++;
+ }
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*************************************************************************
+ Return the current position in the nisplus passwd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static SMB_BIG_UINT getnisppwpos(void *vp)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ return (SMB_BIG_UINT)(res->enum_entry);
+}
+
+/*************************************************************************
+ Set the current position in the nisplus passwd list from SMB_BIG_UINT.
+ This must be treated as an opaque token.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL setnisppwpos(void *vp, SMB_BIG_UINT tok)
+{
+ struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
+ if (tok < (NIS_RES_NUMOBJ(res->result) - 1)) {
+ res->enum_entry = tok;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+/*************************************************************************
+ sets a NIS+ attribute
+ *************************************************************************/
+static void set_single_attribute(nis_object *new_obj, int col,
+ const char *val, int len, int flags)
+{
+ if (new_obj == NULL) return;
+
+ ENTRY_VAL(new_obj, col) = val;
+ ENTRY_LEN(new_obj, col) = len+1;
+
+ if (flags != 0)
+ {
+ new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
+ }
+}
+
+/************************************************************************
+ Routine to add an entry to the nisplus passwd file.
+
+ do not call this function directly. use passdb.c instead.
+
+*************************************************************************/
+static BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
+{
+ char *pfile;
+ char *nisname;
+ nis_result *nis_user;
+ nis_result *result = NULL,
+ *tblresult = NULL,
+ *addresult = NULL;
+ nis_object new_obj, *obj;
+
+ fstring uid;
+ fstring user_rid;
+ fstring smb_grpid;
+ fstring group_rid;
+ fstring acb;
+
+ fstring smb_passwd;
+ fstring smb_nt_passwd;
+
+ fstring logon_t;
+ fstring logoff_t;
+ fstring kickoff_t;
+ fstring pwdlset_t;
+ fstring pwdlchg_t;
+ fstring pwdmchg_t;
+
+ memset((char *)logon_t , '\0', sizeof(logon_t ));
+ memset((char *)logoff_t , '\0', sizeof(logoff_t ));
+ memset((char *)kickoff_t, '\0', sizeof(kickoff_t));
+ memset((char *)pwdlset_t, '\0', sizeof(pwdlset_t));
+ memset((char *)pwdlchg_t, '\0', sizeof(pwdlchg_t));
+ memset((char *)pwdmchg_t, '\0', sizeof(pwdmchg_t));
+
+ pfile = lp_smb_passwd_file();
+
+ nisname = make_nisname_from_name(newpwd->smb_name, pfile);
+ result = nisp_get_nis_list(nisname);
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(3, ( "add_nis21ppwd_entry: nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
+ {
+ DEBUG(3, ("add_nisp21pwd_entry: User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+#if 0
+ /* User not found. */
+ if (!add_user)
+ {
+ DEBUG(3, ("add_nisp21pwd_entry: User not found in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+#endif
+
+ tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ nis_freeresult(result);
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "add_nisp21pwd_entry: nis_lookup failure: %s\n",
+ nis_sperrno(tblresult->status)));
+ return False;
+ }
+
+ new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
+ new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
+ new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
+ new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
+ new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
+ new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
+
+ new_obj.zo_data.zo_type = ENTRY_OBJ;
+
+ new_obj.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
+ new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_maxcol;
+ new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val = calloc(new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len, sizeof(entry_col));
+
+ if (new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val == NULL)
+ {
+ DEBUG(0, ("add_nisp21pwd_entry: memory allocation failure\n"));
+ nis_freeresult(result);
+ nis_freeresult(tblresult);
+ return False;
+ }
+
+ pdb_sethexpwd(smb_passwd , newpwd->smb_passwd , newpwd->acct_ctrl);
+ pdb_sethexpwd(smb_nt_passwd, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+
+ newpwd->pass_last_set_time = (time_t)time(NULL);
+ newpwd->logon_time = (time_t)-1;
+ newpwd->logoff_time = (time_t)-1;
+ newpwd->kickoff_time = (time_t)-1;
+ newpwd->pass_can_change_time = (time_t)-1;
+ newpwd->pass_must_change_time = (time_t)-1;
+
+ slprintf(logon_t, 13, "LNT-%08X", (uint32)newpwd->logon_time);
+ slprintf(logoff_t, 13, "LOT-%08X", (uint32)newpwd->logoff_time);
+ slprintf(kickoff_t, 13, "KOT-%08X", (uint32)newpwd->kickoff_time);
+ slprintf(pwdlset_t, 13, "LCT-%08X", (uint32)newpwd->pass_last_set_time);
+ slprintf(pwdlchg_t, 13, "CCT-%08X", (uint32)newpwd->pass_can_change_time);
+ slprintf(pwdmchg_t, 13, "MCT-%08X", (uint32)newpwd->pass_must_change_time);
+
+ slprintf(uid, sizeof(uid)-1, "%u", newpwd->smb_userid);
+ slprintf(user_rid, sizeof(user_rid)-1, "0x%x", newpwd->user_rid);
+ slprintf(smb_grpid, sizeof(smb_grpid)-1, "%u", newpwd->smb_grpid);
+ slprintf(group_rid, sizeof(group_rid)-1, "0x%x", newpwd->group_rid);
+
+ safe_strcpy(acb, smbpasswd_encode_acct_ctrl(newpwd->acct_ctrl),
+ sizeof(acb)-1);
+
+ set_single_attribute(&new_obj, NPF_NAME , newpwd->smb_name , strlen(newpwd->smb_name) , 0);
+ set_single_attribute(&new_obj, NPF_UID , uid , strlen(uid) , 0);
+ set_single_attribute(&new_obj, NPF_USER_RID , user_rid , strlen(user_rid) , 0);
+ set_single_attribute(&new_obj, NPF_SMB_GRPID , smb_grpid , strlen(smb_grpid) , 0);
+ set_single_attribute(&new_obj, NPF_GROUP_RID , group_rid , strlen(group_rid) , 0);
+ set_single_attribute(&new_obj, NPF_ACB , acb , strlen(acb) , 0);
+ set_single_attribute(&new_obj, NPF_LMPWD , smb_passwd , strlen(smb_passwd) , EN_CRYPT);
+ set_single_attribute(&new_obj, NPF_NTPWD , smb_nt_passwd , strlen(smb_nt_passwd) , EN_CRYPT);
+ set_single_attribute(&new_obj, NPF_LOGON_T , logon_t , strlen(logon_t) , 0);
+ set_single_attribute(&new_obj, NPF_LOGOFF_T , logoff_t , strlen(logoff_t) , 0);
+ set_single_attribute(&new_obj, NPF_KICK_T , kickoff_t , strlen(kickoff_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDLSET_T , pwdlset_t , strlen(pwdlset_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDLCHG_T , pwdlchg_t , strlen(pwdlchg_t) , 0);
+ set_single_attribute(&new_obj, NPF_PWDMCHG_T , pwdmchg_t , strlen(pwdmchg_t) , 0);
+#if 0
+ set_single_attribute(&new_obj, NPF_FULL_NAME , newpwd->full_name , strlen(newpwd->full_name) , 0);
+ set_single_attribute(&new_obj, NPF_HOME_DIR , newpwd->home_dir , strlen(newpwd->home_dir) , 0);
+ set_single_attribute(&new_obj, NPF_DIR_DRIVE , newpwd->dir_drive , strlen(newpwd->dir_drive) , 0);
+ set_single_attribute(&new_obj, NPF_LOGON_SCRIPT , newpwd->logon_script , strlen(newpwd->logon_script) , 0);
+ set_single_attribute(&new_obj, NPF_PROFILE_PATH , newpwd->profile_path , strlen(newpwd->profile_path) , 0);
+ set_single_attribute(&new_obj, NPF_ACCT_DESC , newpwd->acct_desc , strlen(newpwd->acct_desc) , 0);
+ set_single_attribute(&new_obj, NPF_WORKSTATIONS , newpwd->workstations , strlen(newpwd->workstations) , 0);
+ set_single_attribute(&new_obj, NPF_HOURS , newpwd->hours , newpwd->hours_len , 0);
+#endif
+
+ obj = &new_obj;
+
+ addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+
+ if (addresult->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "add_nisp21pwd_entry: NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(tblresult);
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(tblresult);
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startnisppwent()/
+ getnisppwent()/endnisppwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+
+ do not call this function directly. use passdb.c instead.
+
+************************************************************************/
+static BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
+{
+ char *oldnislmpwd, *oldnisntpwd, *oldnisacb, *oldnislct, *user_name;
+ char lmpwd[33], ntpwd[33], lct[13];
+ nis_result *result, *addresult;
+ nis_object *obj;
+ fstring acb;
+ pstring nisname;
+ BOOL got_pass_last_set_time, ret;
+ int i;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("mod_getnisp21pwd_entry: no SMB password file set\n"));
+ return False;
+ }
+
+ DEBUG(10, ("mod_getnisp21pwd_entry: search by name: %s\n", pwd->smb_name));
+ DEBUG(10, ("mod_getnisp21pwd_entry: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", pwd->smb_name, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("mod_getnisp21pwd_entry: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("mod_getnisp21pwd_entry: user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ DEBUG(6,("mod_getnisp21pwd_entry: entry exists\n"));
+
+ obj = NIS_RES_OBJECT(result);
+
+ user_name = ENTRY_VAL(obj, NPF_NAME);
+ oldnislmpwd = ENTRY_VAL(obj, NPF_LMPWD);
+ oldnisntpwd = ENTRY_VAL(obj, NPF_NTPWD);
+ oldnisacb = ENTRY_VAL(obj, NPF_ACB);
+ oldnislct = ENTRY_VAL(obj, NPF_PWDLSET_T);
+
+
+ if (!override && (*oldnislmpwd == '*' || *oldnislmpwd == 'X' ||
+ *oldnisntpwd == '*' || *oldnisntpwd == 'X')) {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("mod_nisp21pwd_entry: entry invalidated for user %s\n", user_name));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (strlen(oldnislmpwd) != 32 || strlen(oldnisntpwd) != 32) {
+ DEBUG(0, ("mod_nisp21pwd_entry: malformed password entry (incorrect length)\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+
+ /*
+ * If both NT and lanman passwords are provided - reset password
+ * not required flag.
+ */
+
+ if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
+ /* Require password in the future (should ACB_DISABLED also be reset?) */
+ pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
+ }
+
+ if (*oldnisacb == '[') {
+
+ i = 0;
+ acb[i++] = oldnisacb[i];
+ while(i < (sizeof(fstring) - 2) && (oldnisacb[i] != ']'))
+ acb[i] = oldnisacb[i++];
+
+ acb[i++] = ']';
+ acb[i++] = '\0';
+
+ if (i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(acb, smbpasswd_encode_acct_ctrl(pwd->acct_ctrl));
+ } else {
+ /*
+ * If using the old format and the ACB_DISABLED or
+ * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
+ * here as we have no space to encode the change.
+ */
+ if(pwd->acct_ctrl & (ACB_DISABLED|ACB_PWNOTREQ)) {
+ pwd->smb_passwd = NULL;
+ pwd->smb_nt_passwd = NULL;
+ }
+ }
+
+ /* Now do the LCT stuff. */
+ if (StrnCaseCmp(oldnislct, "LCT-", 4) == 0) {
+
+ for(i = 0; i < 8; i++) {
+ if(oldnislct[i+4] == '\0' || !isxdigit(oldnislct[i+4]))
+ break;
+ }
+ if (i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* StrnCaseCmp() */
+
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+
+
+ /* Create the 32 byte representation of the new p16 */
+ if(pwd->smb_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&lmpwd[i*2], 32, "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(lmpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(lmpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ /* Add on the NT md4 hash */
+ if (pwd->smb_nt_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ntpwd[i*2], 32, "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(ntpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(ntpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ pwd->pass_last_set_time = time(NULL);
+
+ if(got_pass_last_set_time) {
+ slprintf(lct, 13, "LCT-%08X", (uint32)pwd->pass_last_set_time);
+ }
+
+ set_single_attribute(obj, NPF_LMPWD, lmpwd, strlen(lmpwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_NTPWD, ntpwd, strlen(ntpwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
+ set_single_attribute(obj, NPF_PWDLSET_T, lct, strlen(lct), 0);
+
+ addresult =
+ nis_add_entry(lp_smb_passwd_file(), obj,
+ ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ if(addresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("mod_nisp21pwd_entry: NIS+ table update failed: %s %s\n", nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ DEBUG(6,("mod_nisp21pwd_entry: password changed\n"));
+
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwnam(char *name)
+{
+ /* Static buffers we will return. */
+ static struct sam_passwd pw_buf;
+ nis_result *result;
+ pstring nisname;
+ BOOL ret;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return NULL;
+ }
+
+ DEBUG(10, ("getnisp21pwnam: search by name: %s\n", name));
+ DEBUG(10, ("getnisp21pwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", name, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("getnisp21pwnam: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+
+ ret = make_sam_from_nisresult(&pw_buf, result);
+ nis_freeresult(result);
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwrid(uint32 rid)
+{
+ /* Static buffers we will return. */
+ static struct sam_passwd pw_buf;
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+
+ if (!*lp_smb_passwd_file())
+ {
+ DEBUG(0, ("getnisp21pwrid: no SMB password file set\n"));
+ return NULL;
+ }
+
+ DEBUG(10, ("getnisp21pwrid: search by rid: %x\n", rid));
+ DEBUG(10, ("getnisp21pwrid: using NIS+ table %s\n", lp_smb_passwd_file()));
+
+ nisname = make_nisname_from_user_rid(rid, lp_smb_passwd_file());
+
+ /* Search the table. */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(5);
+
+ result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("getnisp21pwrid: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+
+ ret = make_sam_from_nisresult(&pw_buf, result);
+ nis_freeresult(result);
+
+ return ret ? &pw_buf : NULL;
+}
+
+/*
+ * Derived functions for NIS+.
+ */
+
+static struct smb_passwd *getnisppwent(void *vp)
+{
+ return pdb_sam_to_smb(getnisp21pwent(vp));
+}
+
+static BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
+{
+ return add_nisp21pwd_entry(pdb_smb_to_sam(newpwd));
+}
+
+static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override);
+}
+
+static BOOL del_nisppwd_entry(const char *name)
+{
+ return False; /* Dummy. */
+}
+
+static struct smb_passwd *getnisppwnam(char *name)
+{
+ return pdb_sam_to_smb(getnisp21pwnam(name));
+}
+
+static struct sam_passwd *getnisp21pwuid(uid_t smb_userid)
+{
+ return getnisp21pwrid(pdb_uid_to_user_rid(smb_userid));
+}
+
+static struct smb_passwd *getnisppwrid(uint32 user_rid)
+{
+ return pdb_sam_to_smb(getnisp21pwuid(pdb_user_rid_to_uid(user_rid)));
+}
+
+static struct smb_passwd *getnisppwuid(uid_t smb_userid)
+{
+ return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
+}
+
+static struct passdb_ops nispasswd_ops = {
+ startnisppwent,
+ endnisppwent,
+ getnisppwpos,
+ setnisppwpos,
+ getnisppwnam,
+ getnisppwuid,
+ getnisppwrid,
+ getnisppwent,
+ add_nisppwd_entry,
+ mod_nisppwd_entry,
+ del_nisppwd_entry,
+ getnisp21pwent,
+ getnisp21pwnam,
+ getnisp21pwuid,
+ getnisp21pwrid,
+ add_nisp21pwd_entry,
+ mod_nisp21pwd_entry
+};
+
+struct passdb_ops *nisplus_initialize_password_db(void)
+{
+ return &nispasswd_ops;
+}
+
+#else
+ void nisplus_dummy_function(void);
+ void nisplus_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_NISPLUS */
+
+/* useful code i can't bring myself to delete */
+#if 0
+static void useful_code(void) {
+ /* checks user in unix password database. don't want to do that, here. */
+ nisname = make_nisname_from_name(newpwd->smb_name, "passwd.org_dir");
+
+ nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
+
+ if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
+ {
+ DEBUG(3, ("useful_code: Unable to get NIS+ passwd entry for user: %s.\n",
+ nis_sperrno(nis_user->status)));
+ return False;
+ }
+
+ user_obj = NIS_RES_OBJECT(nis_user);
+ make_nisname_from_name(ENTRY_VAL(user_obj,0), pfile);
+}
+#endif
diff --git a/source/passdb/pampass.c b/source/passdb/pampass.c
new file mode 100644
index 00000000000..018eae3a07e
--- /dev/null
+++ b/source/passdb/pampass.c
@@ -0,0 +1,892 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+ PAM Password checking
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) John H Terpsta 1999-2001
+ Copyright (C) Andrew Bartlett 2001
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * This module provides PAM based functions for validation of
+ * username/password pairs, account managment, session and access control.
+ * Note: SMB password checking is done in smbpass.c
+ */
+
+#include "includes.h"
+
+#ifdef WITH_PAM
+
+/*******************************************************************
+ * Handle PAM authentication
+ * - Access, Authentication, Session, Password
+ * Note: See PAM Documentation and refer to local system PAM implementation
+ * which determines what actions/limitations/allowances become affected.
+ *********************************************************************/
+
+#include <security/pam_appl.h>
+
+/*
+ * Structure used to communicate between the conversation function
+ * and the server_login/change password functions.
+ */
+
+struct smb_pam_userdata {
+ const char *PAM_username;
+ const char *PAM_password;
+ const char *PAM_newpassword;
+};
+
+typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
+
+/*
+ * Macros to help make life easy
+ */
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+/*******************************************************************
+ PAM error handler.
+ *********************************************************************/
+
+static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
+{
+
+ if( pam_error != PAM_SUCCESS) {
+ DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
+ msg, pam_strerror(pamh, pam_error)));
+
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ This function is a sanity check, to make sure that we NEVER report
+ failure as sucess.
+*********************************************************************/
+
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
+ char *msg, int dbglvl,
+ NTSTATUS *nt_status)
+{
+ if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
+ return True;
+
+ if (NT_STATUS_IS_OK(*nt_status)) {
+ /* Complain LOUDLY */
+ DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
+error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+ *nt_status = NT_STATUS_LOGON_FAILURE;
+ }
+ return False;
+}
+
+/*
+ * PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+
+ *resp = NULL;
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ memset(reply, '\0', sizeof(struct pam_response) * num_msg);
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_username);
+ /* PAM frees resp */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(udp->PAM_password);
+ /* PAM frees resp */
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/*
+ * PAM password change conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static void special_char_sub(char *buf)
+{
+ all_string_sub(buf, "\\n", "", 0);
+ all_string_sub(buf, "\\r", "", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass)
+{
+ pstring_sub(buf, "%u", username);
+ all_string_sub(buf, "%o", oldpass, sizeof(fstring));
+ all_string_sub(buf, "%n", newpass, sizeof(fstring));
+}
+
+
+struct chat_struct {
+ struct chat_struct *next, *prev;
+ fstring prompt;
+ fstring reply;
+};
+
+/**************************************************************
+ Create a linked list containing chat data.
+***************************************************************/
+
+static struct chat_struct *make_pw_chat(char *p)
+{
+ fstring prompt;
+ fstring reply;
+ struct chat_struct *list = NULL;
+ struct chat_struct *t;
+ struct chat_struct *tmp;
+
+ while (1) {
+ t = (struct chat_struct *)malloc(sizeof(*t));
+ if (!t) {
+ DEBUG(0,("make_pw_chat: malloc failed!\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(list, t, tmp);
+
+ if (!next_token(&p, prompt, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(prompt,"."))
+ fstrcpy(prompt,"*");
+
+ special_char_sub(prompt);
+ fstrcpy(t->prompt, prompt);
+ strlower(t->prompt);
+ trim_string(t->prompt, " ", " ");
+
+ if (!next_token(&p, reply, NULL, sizeof(fstring)))
+ break;
+
+ if (strequal(reply,"."))
+ fstrcpy(reply,"");
+
+ special_char_sub(reply);
+ fstrcpy(t->reply, reply);
+ strlower(t->reply);
+ trim_string(t->reply, " ", " ");
+
+ }
+ return list;
+}
+
+static void free_pw_chat(struct chat_struct *list)
+{
+ while (list) {
+ struct chat_struct *old_head = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
+}
+
+static int smb_pam_passchange_conv(int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+ fstring current_prompt;
+ fstring current_reply;
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
+ struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());
+ struct chat_struct *t;
+ BOOL found;
+ *resp = NULL;
+
+ DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));
+
+ if (num_msg <= 0)
+ return PAM_CONV_ERR;
+
+ if (pw_chat == NULL)
+ return PAM_CONV_ERR;
+
+ /*
+ * Apparantly HPUX has a buggy PAM that doesn't support the
+ * appdata_ptr. Fail if this is the case. JRA.
+ */
+
+ if (udp == NULL) {
+ DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) {
+ DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));
+ free_pw_chat(pw_chat);
+ return PAM_CONV_ERR;
+ }
+
+ for (replies = 0; replies < num_msg; replies++) {
+ found = False;
+ DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));
+#endif
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));
+ fstrcpy(current_prompt, msg[replies]->msg);
+ trim_string(current_prompt, " ", " ");
+ for (t=pw_chat; t; t=t->next) {
+
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
+ t->prompt, current_prompt ));
+
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
+ fstrcpy(current_reply, t->reply);
+ DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
+ pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(current_reply);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));
+#endif
+ found = True;
+ break;
+ }
+ }
+ /* PAM frees resp */
+
+ if (!found) {
+ DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ break;
+
+ case PAM_TEXT_INFO:
+ /* fall through */
+
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+
+ default:
+ /* Must be an error of some sort... */
+ free_pw_chat(pw_chat);
+ SAFE_FREE(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ free_pw_chat(pw_chat);
+ if (reply)
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+/***************************************************************************
+ Free up a malloced pam_conv struct.
+****************************************************************************/
+
+static void smb_free_pam_conv(struct pam_conv *pconv)
+{
+ if (pconv)
+ SAFE_FREE(pconv->appdata_ptr);
+
+ SAFE_FREE(pconv);
+}
+
+/***************************************************************************
+ Allocate a pam_conv struct.
+****************************************************************************/
+
+static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,
+ const char *passwd, const char *newpass)
+{
+ struct pam_conv *pconv = (struct pam_conv *)malloc(sizeof(struct pam_conv));
+ struct smb_pam_userdata *udp = (struct smb_pam_userdata *)malloc(sizeof(struct smb_pam_userdata));
+
+ if (pconv == NULL || udp == NULL) {
+ SAFE_FREE(pconv);
+ SAFE_FREE(udp);
+ return NULL;
+ }
+
+ udp->PAM_username = user;
+ udp->PAM_password = passwd;
+ udp->PAM_newpassword = newpass;
+
+ pconv->conv = smb_pam_conv_fnptr;
+ pconv->appdata_ptr = (void *)udp;
+ return pconv;
+}
+
+/*
+ * PAM Closing out cleanup handler
+ */
+
+static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
+{
+ int pam_error;
+
+ smb_free_pam_conv(smb_pam_conv_ptr);
+
+ if( pamh != NULL ) {
+ pam_error = pam_end(pamh, 0);
+ if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
+ DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
+ return True;
+ }
+ }
+ DEBUG(2,("smb_pam_end: PAM: not initialised"));
+ return False;
+}
+
+/*
+ * Start PAM authentication for specified account
+ */
+
+static BOOL smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv)
+{
+ int pam_error;
+ const char *our_rhost;
+
+ *pamh = (pam_handle_t *)NULL;
+
+ DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
+
+ pam_error = pam_start("samba", user, pconv, pamh);
+ if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+
+ if (rhost == NULL) {
+ our_rhost = client_name();
+ if (strequal(rhost,"UNKNOWN"))
+ our_rhost = client_addr();
+ } else {
+ our_rhost = rhost;
+ }
+
+#ifdef PAM_RHOST
+ DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", our_rhost));
+ pam_error = pam_set_item(*pamh, PAM_RHOST, our_rhost);
+ if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+#ifdef PAM_TTY
+ DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
+ pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
+ if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
+ smb_pam_end(*pamh, pconv);
+ *pamh = (pam_handle_t *)NULL;
+ return False;
+ }
+#endif
+ DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
+ return True;
+}
+
+/*
+ * PAM Authentication Handler
+ */
+static NTSTATUS smb_pam_auth(pam_handle_t *pamh, char *user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+
+ /*
+ * To enable debugging set in /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ */
+
+ DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
+ pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
+ switch( pam_error ){
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+ nt_status = NT_STATUS_WRONG_PASSWORD;
+ break;
+ case PAM_CRED_INSUFFICIENT:
+ DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
+ nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
+ break;
+ case PAM_AUTHINFO_UNAVAIL:
+ DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_MAXTRIES:
+ DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
+ nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
+ break;
+ case PAM_ABORT:
+ DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Account Handler
+ */
+static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
+ DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
+ switch( pam_error ) {
+ case PAM_AUTHTOK_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_ACCT_EXPIRED:
+ DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
+ nt_status = NT_STATUS_ACCOUNT_EXPIRED;
+ break;
+ case PAM_AUTH_ERR:
+ DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
+ nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Credential Setting
+ */
+
+static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+ int pam_error;
+ NTSTATUS nt_status = NT_STATUS_NO_TOKEN;
+
+ /*
+ * This will allow samba to aquire a kerberos token. And, when
+ * exporting an AFS cell, be able to /write/ to this cell.
+ */
+
+ DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
+ pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
+ switch( pam_error ) {
+ case PAM_CRED_UNAVAIL:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ case PAM_CRED_EXPIRED:
+ DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+ nt_status = NT_STATUS_PASSWORD_EXPIRED;
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ break;
+ case PAM_CRED_ERR:
+ DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+ nt_status = NT_STATUS_LOGON_FAILURE;
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
+ nt_status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+ nt_status = NT_STATUS_NO_TOKEN;
+ break;
+ }
+
+ smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
+ return nt_status;
+}
+
+/*
+ * PAM Internal Session Handler
+ */
+static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
+{
+ int pam_error;
+
+#ifdef PAM_TTY
+ DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
+ pam_error = pam_set_item(pamh, PAM_TTY, tty);
+ if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+ return False;
+#endif
+
+ if (flag) {
+ pam_error = pam_open_session(pamh, PAM_SILENT);
+ if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+ return False;
+ } else {
+ pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
+ pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
+ if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+ return False;
+ }
+ return (True);
+}
+
+/*
+ * Internal PAM Password Changer.
+ */
+
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, const char * user)
+{
+ int pam_error;
+
+ DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
+
+ pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+
+ switch( pam_error ) {
+ case PAM_AUTHTOK_ERR:
+ DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+ break;
+
+ /* This doesn't seem to be defined on Solaris. JRA */
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ case PAM_AUTHTOK_RECOVER_ERR:
+ DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+ break;
+#endif
+
+ case PAM_AUTHTOK_LOCK_BUSY:
+ DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+ break;
+ case PAM_AUTHTOK_DISABLE_AGING:
+ DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+ break;
+ case PAM_PERM_DENIED:
+ DEBUG(0, ("PAM: Permission denied.\n"));
+ break;
+ case PAM_TRY_AGAIN:
+ DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+ break;
+ case PAM_USER_UNKNOWN:
+ DEBUG(0, ("PAM: User not known to PAM\n"));
+ break;
+ case PAM_SUCCESS:
+ DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+ break;
+ default:
+ DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
+ }
+
+ if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
+ return False;
+ }
+
+ /* If this point is reached, the password has changed. */
+ return True;
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, True)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+
+BOOL smb_pam_close_session(char *user, char *tty, char *rhost)
+{
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return True;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return False;
+
+ if (!smb_pam_start(&pamh, user, rhost, pconv))
+ return False;
+
+ if (!smb_internal_pam_session(pamh, user, tty, False)) {
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+/*
+ * PAM Externally accessible Account handler
+ */
+
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv *pconv = NULL;
+
+ /* Ignore PAM if told to. */
+
+ if (!lp_obey_pam_restrictions())
+ return NT_STATUS_OK;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_ACCOUNT_DISABLED;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user)))
+ DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Validation Suite
+ */
+
+NTSTATUS smb_pam_passcheck(char * user, char * password)
+{
+ pam_handle_t *pamh = NULL;
+ NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+ struct pam_conv *pconv = NULL;
+
+ /*
+ * Note we can't ignore PAM here as this is the only
+ * way of doing auths on plaintext passwords when
+ * compiled --with-pam.
+ */
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!smb_pam_start(&pamh, user, NULL, pconv))
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status = smb_pam_setcred(pamh, user))) {
+ DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+ }
+
+ smb_pam_end(pamh, pconv);
+ return nt_status;
+}
+
+/*
+ * PAM Password Change Suite
+ */
+
+BOOL smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword)
+{
+ /* Appropriate quantities of root should be obtained BEFORE calling this function */
+ struct pam_conv *pconv = NULL;
+ pam_handle_t *pamh = NULL;
+
+ if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
+ return False;
+
+ if(!smb_pam_start(&pamh, user, NULL, pconv))
+ return False;
+
+ if (!smb_pam_chauthtok(pamh, user)) {
+ DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
+ smb_pam_end(pamh, pconv);
+ return False;
+ }
+
+ return smb_pam_end(pamh, pconv);
+}
+
+#else
+
+/* If PAM not used, no PAM restrictions on accounts. */
+NTSTATUS smb_pam_accountcheck(const char * user)
+{
+ return NT_STATUS_OK;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_claim_session(char *user, char *tty, char *rhost)
+{
+ return True;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+BOOL smb_pam_close_session(char *in_user, char *tty, char *rhost)
+{
+ return True;
+}
+#endif /* WITH_PAM */
diff --git a/source/passdb/pass_check.c b/source/passdb/pass_check.c
new file mode 100644
index 00000000000..77839e4bb0c
--- /dev/null
+++ b/source/passdb/pass_check.c
@@ -0,0 +1,776 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password checking
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this module is for checking a username/password against a system
+ password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+/* these are kept here to keep the string_combinations function simple */
+static fstring this_user;
+#if !defined(WITH_PAM)
+static fstring this_salt;
+static fstring this_crypted;
+#endif
+
+#ifdef WITH_AFS
+
+#include <afs/stds.h>
+#include <afs/kautils.h>
+
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static BOOL afs_auth(char *user, char *password)
+{
+ long password_expires = 0;
+ char *reason;
+
+ /* For versions of AFS prior to 3.3, this routine has few arguments, */
+ /* but since I can't find the old documentation... :-) */
+ setpag();
+ if (ka_UserAuthenticateGeneral
+ (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
+ (char *)0, /* cell */
+ password, 0, /* lifetime, default */
+ &password_expires, /*days 'til it expires */
+ 0, /* spare 2 */
+ &reason) == 0)
+ {
+ return (True);
+ }
+ DEBUG(1,
+ ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
+ return (False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+#include <dce/dce_error.h>
+#include <dce/sec_login.h>
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+ - Server credentials may expire
+ - Client credential cache files have wrong owner
+ - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static BOOL dfs_auth(char *user, char *password)
+{
+ error_status_t err;
+ int err2;
+ int prterr;
+ signed32 expire_time, current_time;
+ boolean32 password_reset;
+ struct passwd *pw;
+ sec_passwd_rec_t passwd_rec;
+ sec_login_auth_src_t auth_src = sec_login_auth_src_network;
+ unsigned char dce_errstr[dce_c_error_string_len];
+ gid_t egid;
+
+ if (dcelogin_atmost_once)
+ return (False);
+
+#ifdef HAVE_CRYPT
+ /*
+ * We only go for a DCE login context if the given password
+ * matches that stored in the local password file..
+ * Assumes local passwd file is kept in sync w/ DCE RGY!
+ */
+
+ if (strcmp((char *)crypt(password, this_salt), this_crypted))
+ {
+ return (False);
+ }
+#endif
+
+ sec_login_get_current_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ time(&current_time);
+
+ if (expire_time < (current_time + 60))
+ {
+ struct passwd *pw;
+ sec_passwd_rec_t *key;
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_refresh_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't refresh identity. %s\n",
+ dce_errstr));
+
+ return (False);
+ }
+
+ sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
+ (unsigned char *)pw->pw_name,
+ sec_c_key_version_none,
+ (void **)&key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get key for %s. %s\n",
+ pw->pw_name, dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_valid_and_cert_ident(my_dce_sec_context, key,
+ &password_reset, &auth_src,
+ &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE can't validate and certify identity for %s. %s\n",
+ pw->pw_name, dce_errstr));
+ }
+
+ sec_key_mgmt_free_key(key, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't free key.\n", dce_errstr));
+ }
+ }
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ return (False);
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
+
+ return (False);
+ }
+
+ /*
+ * NB. I'd like to change these to call something like change_to_user()
+ * instead but currently we don't have a connection
+ * context to become the correct user. This is already
+ * fairly platform specific code however, so I think
+ * this should be ok. I have added code to go
+ * back to being root on error though. JRA.
+ */
+
+ egid = getegid();
+
+ set_effective_gid(pw->pw_gid);
+ set_effective_uid(pw->pw_uid);
+
+ if (sec_login_setup_identity((unsigned char *)user,
+ sec_login_no_flags,
+ &my_dce_sec_context, &err) == 0)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ passwd_rec.version_number = sec_passwd_c_version_none;
+ passwd_rec.pepper = NULL;
+ passwd_rec.key.key_type = sec_passwd_plain;
+ passwd_rec.key.tagged_union.plain = (idl_char *) password;
+
+ sec_login_validate_identity(my_dce_sec_context,
+ &passwd_rec, &password_reset,
+ &auth_src, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE Identity Validation failed for principal %s: %s\n",
+ user, dce_errstr));
+ goto err;
+ }
+
+ sec_login_certify_identity(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
+ goto err;
+ }
+
+ if (auth_src != sec_login_auth_src_network)
+ {
+ DEBUG(0, ("DCE context has no network credentials.\n"));
+ }
+
+ sec_login_set_context(my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE login failed for principal %s, cant set context: %s\n",
+ user, dce_errstr));
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ goto err;
+ }
+
+ sec_login_get_pwent(my_dce_sec_context,
+ (sec_login_passwd_t *) & pw, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
+ goto err;
+ }
+
+ DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
+ user, sys_getpid()));
+
+ DEBUG(3, ("DCE principal: %s\n"
+ " uid: %d\n"
+ " gid: %d\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid));
+ DEBUG(3, (" info: %s\n"
+ " dir: %s\n"
+ " shell: %s\n",
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell));
+
+ sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
+ goto err;
+ }
+
+ set_effective_uid(0);
+ set_effective_gid(0);
+
+ DEBUG(0,
+ ("DCE context expires: %s", asctime(localtime(&expire_time))));
+
+ dcelogin_atmost_once = 1;
+ return (True);
+
+ err:
+
+ /* Go back to root, JRA. */
+ set_effective_uid(0);
+ set_effective_gid(egid);
+ return (False);
+}
+
+void dfs_unlogin(void)
+{
+ error_status_t err;
+ int err2;
+ unsigned char dce_errstr[dce_c_error_string_len];
+
+ sec_login_purge_context(&my_dce_sec_context, &err);
+ if (err != error_status_ok)
+ {
+ dce_error_inq_text(err, dce_errstr, &err2);
+ DEBUG(0,
+ ("DCE purge login context failed for server instance %d: %s\n",
+ sys_getpid(), dce_errstr));
+ }
+}
+#endif
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+static int linux_bigcrypt(char *password, char *salt1, char *crypted)
+{
+#define LINUX_PASSWORD_SEG_CHARS 8
+ char salt[3];
+ int i;
+
+ StrnCpy(salt, salt1, 2);
+ crypted += 2;
+
+ for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
+ char *p = crypt(password, salt) + 2;
+ if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
+ return (0);
+ password += LINUX_PASSWORD_SEG_CHARS;
+ crypted += strlen(p);
+ }
+
+ return (1);
+}
+#endif
+
+#ifdef OSF1_ENH_SEC
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+static char *osf1_bigcrypt(char *password, char *salt1)
+{
+ static char result[AUTH_MAX_PASSWD_LENGTH] = "";
+ char *p1;
+ char *p2 = password;
+ char salt[3];
+ int i;
+ int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
+ if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
+ parts++;
+
+ StrnCpy(salt, salt1, 2);
+ StrnCpy(result, salt1, 2);
+ result[2] = '\0';
+
+ for (i = 0; i < parts; i++) {
+ p1 = crypt(p2, salt);
+ strncat(result, p1 + 2,
+ AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
+ StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
+ p2 += AUTH_CLEARTEXT_SEG_CHARS;
+ }
+
+ return (result);
+}
+#endif
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (char *),
+ int N)
+{
+ int len = strlen(s);
+ int i;
+ NTSTATUS nt_status;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len, PASSWORD_LENGTH);
+#endif
+
+ if (N <= 0 || offset >= len)
+ return (fn(s));
+
+ for (i = offset; i < (len - (N - 1)); i++) {
+ char c = s[i];
+ if (!islower(c))
+ continue;
+ s[i] = toupper(c);
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
+ return (nt_status);
+ }
+ s[i] = c;
+ }
+ return (NT_STATUS_WRONG_PASSWORD);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (char *), int N)
+{
+ int n;
+ NTSTATUS nt_status;
+ for (n = 1; n <= N; n++)
+ if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
+ return nt_status;
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static NTSTATUS password_check(char *password)
+{
+#ifdef WITH_PAM
+ return smb_pam_passcheck(this_user, password);
+#else
+
+ BOOL ret;
+
+#ifdef WITH_AFS
+ if (afs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_AFS */
+
+#ifdef WITH_DFS
+ if (dfs_auth(this_user, password))
+ return NT_STATUS_OK;
+#endif /* WITH_DFS */
+
+#ifdef OSF1_ENH_SEC
+
+ ret = (strcmp(osf1_bigcrypt(password, this_salt),
+ this_crypted) == 0);
+ if (!ret) {
+ DEBUG(2,
+ ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ }
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* OSF1_ENH_SEC */
+
+#ifdef ULTRIX_AUTH
+ ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+#endif /* ULTRIX_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+ ret = (linux_bigcrypt(password, this_salt, this_crypted));
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* LINUX_BIGCRYPT */
+
+#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
+
+ /*
+ * Some systems have bigcrypt in the C library but might not
+ * actually use it for the password hashes (HPUX 10.20) is
+ * a noteable example. So we try bigcrypt first, followed
+ * by crypt.
+ */
+
+ if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
+ return NT_STATUS_OK;
+ else
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+
+#ifdef HAVE_BIGCRYPT
+ ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_BIGCRYPT */
+
+#ifndef HAVE_CRYPT
+ DEBUG(1, ("Warning - no crypt available\n"));
+ return NT_STATUS_LOGON_FAILURE;
+#else /* HAVE_CRYPT */
+ ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+ if (ret) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+#endif /* HAVE_CRYPT */
+#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
+#endif /* WITH_PAM || KRB4_AUTH || KRB5_AUTH */
+}
+
+
+
+/****************************************************************************
+CHECK if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file
+return NT_STATUS_OK on correct match, appropriate error otherwise
+****************************************************************************/
+
+NTSTATUS pass_check(struct passwd *pass, char *user, char *password,
+ int pwlen, BOOL (*fn) (char *, char *), BOOL run_cracker)
+{
+ pstring pass2;
+ int level = lp_passwordlevel();
+
+ NTSTATUS nt_status;
+ if (password)
+ password[pwlen] = 0;
+
+#if DEBUG_PASSWORD
+ DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
+#endif
+
+ if (!password)
+ return NT_STATUS_LOGON_FAILURE;
+
+ if (((!*password) || (!pwlen)) && !lp_null_passwords())
+ return NT_STATUS_LOGON_FAILURE;
+
+#if defined(WITH_PAM)
+
+ /*
+ * If we're using PAM we want to short-circuit all the
+ * checks below and dive straight into the PAM code.
+ */
+
+ fstrcpy(this_user, user);
+
+ DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
+
+#else /* Not using PAM or Kerebos */
+
+ DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
+
+ if (!pass) {
+ DEBUG(3, ("Couldn't find user %s\n", user));
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+#ifdef HAVE_GETSPNAM
+ {
+ struct spwd *spass;
+
+ /* many shadow systems require you to be root to get
+ the password, in most cases this should already be
+ the case when this function is called, except
+ perhaps for IPC password changing requests */
+
+ spass = getspnam(pass->pw_name);
+ if (spass && spass->sp_pwdp)
+ pstrcpy(pass->pw_passwd, spass->sp_pwdp);
+ }
+#elif defined(IA_UINFO)
+ {
+ /* Need to get password with SVR4.2's ia_ functions
+ instead of get{sp,pw}ent functions. Required by
+ UnixWare 2.x, tested on version
+ 2.1. (tangent@cyberport.com) */
+ uinfo_t uinfo;
+ if (ia_openinfo(pass->pw_name, &uinfo) != -1)
+ ia_get_logpwd(uinfo, &(pass->pw_passwd));
+ }
+#endif
+
+#ifdef HAVE_GETPRPWNAM
+ {
+ struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
+ if (pr_pw && pr_pw->ufld.fd_encrypt)
+ pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
+ }
+#endif
+
+#ifdef OSF1_ENH_SEC
+ {
+ struct pr_passwd *mypasswd;
+ DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
+ user));
+ mypasswd = getprpwnam(user);
+ if (mypasswd) {
+ fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
+ fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
+ } else {
+ DEBUG(5,
+ ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
+ user));
+ }
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ {
+ AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+ if (ap) {
+ fstrcpy(pass->pw_passwd, ap->a_password);
+ endauthent();
+ }
+ }
+#endif
+
+ /* extract relevant info */
+ fstrcpy(this_salt, pass->pw_passwd);
+
+#if defined(HAVE_TRUNCATED_SALT)
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ this_salt[2] = 0;
+#endif
+
+ fstrcpy(this_crypted, pass->pw_passwd);
+
+ if (!*this_crypted) {
+ if (!lp_null_passwords()) {
+ DEBUG(2, ("Disallowing %s with null password\n",
+ this_user));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ if (!*password) {
+ DEBUG(3,
+ ("Allowing access to %s with null password\n",
+ this_user));
+ return NT_STATUS_OK;
+ }
+ }
+
+#endif /* defined(WITH_PAM) */
+
+ /* try it as it came to us */
+ nt_status = password_check(password);
+ if NT_STATUS_IS_OK(nt_status) {
+ if (fn) {
+ fn(user, password);
+ }
+ return (nt_status);
+ } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+ return (nt_status);
+ }
+
+ if (!run_cracker) {
+ return (nt_status);
+ }
+
+ /* if the password was given to us with mixed case then we don't
+ * need to proceed as we know it hasn't been case modified by the
+ * client */
+ if (strhasupper(password) && strhaslower(password)) {
+ return nt_status;
+ }
+
+ /* make a copy of it */
+ StrnCpy(pass2, password, sizeof(pstring) - 1);
+
+ /* try all lowercase if it's currently all uppercase */
+ if (strhasupper(password)) {
+ strlower(password);
+ if NT_STATUS_IS_OK(nt_status = password_check(password)) {
+ if (fn)
+ fn(user, password);
+ return (nt_status);
+ }
+ }
+
+ /* give up? */
+ if (level < 1) {
+ /* restore it */
+ fstrcpy(password, pass2);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower(password);
+
+
+ if NT_STATUS_IS_OK(nt_status = string_combinations(password, password_check, level)) {
+ if (fn)
+ fn(user, password);
+ return nt_status;
+ }
+
+ /* restore it */
+ fstrcpy(password, pass2);
+
+ return NT_STATUS_WRONG_PASSWORD;
+}
diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c
new file mode 100644
index 00000000000..4c64ad5e017
--- /dev/null
+++ b/source/passdb/passdb.c
@@ -0,0 +1,1827 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-2001
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * This is set on startup - it defines the SID for this
+ * machine, and therefore the SAM database for which it is
+ * responsible.
+ */
+
+extern DOM_SID global_sam_sid;
+
+struct passdb_ops *pdb_ops;
+
+#if 0 /* JERRY */
+static void* pdb_handle = NULL;
+#endif
+
+/***************************************************************
+ Initialize the password db operations.
+***************************************************************/
+
+BOOL initialize_password_db(BOOL reload)
+{
+ /*
+ * This function is unfinished right now, so just
+ * ignore the details and always return True. It
+ * is here only as a placeholder --jerry
+ */
+ return True;
+
+}
+
+
+/************************************************************
+ Fill the SAM_ACCOUNT with default values.
+ ***********************************************************/
+
+static BOOL pdb_fill_default_sam(SAM_ACCOUNT *user)
+{
+ if (user == NULL) {
+ DEBUG(0,("pdb_fill_default_sam: SAM_ACCOUNT was NULL\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(user);
+
+ /* Don't change these timestamp settings without a good reason.
+ They are important for NT member server compatibility. */
+
+ user->logon_time = (time_t)0;
+ user->pass_last_set_time = (time_t)0;
+ user->pass_can_change_time = (time_t)0;
+ user->logoff_time =
+ user->kickoff_time =
+ user->pass_must_change_time = get_time_t_max();
+ user->unknown_3 = 0x00ffffff; /* don't know */
+ user->logon_divs = 168; /* hours per week */
+ user->hours_len = 21; /* 21 times 8 bits = 168 */
+ memset(user->hours, 0xff, user->hours_len); /* available at all hours */
+ user->unknown_5 = 0x00000000; /* don't know */
+ user->unknown_6 = 0x000004ec; /* don't know */
+ return True;
+}
+
+
+/*************************************************************
+ Alloc memory and initialises a struct sam_passwd.
+ ************************************************************/
+
+BOOL pdb_init_sam(SAM_ACCOUNT **user)
+{
+ if (*user != NULL) {
+ DEBUG(0,("pdb_init_sam: SAM_ACCOUNT was non NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_init_sam\n");
+#endif
+ return False;
+ }
+
+ *user=(SAM_ACCOUNT *)malloc(sizeof(SAM_ACCOUNT));
+
+ if (*user==NULL) {
+ DEBUG(0,("pdb_init_sam: error while allocating memory\n"));
+ return False;
+ }
+
+ pdb_fill_default_sam(*user);
+
+ return True;
+}
+
+
+/*************************************************************
+ Initialises a struct sam_passwd with sane values.
+ ************************************************************/
+
+BOOL pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd)
+{
+ pstring str;
+ GROUP_MAP map;
+ uint32 rid;
+
+ if (!pwd) {
+ new_sam_acct = NULL;
+ return False;
+ }
+
+ if (!pdb_init_sam(new_sam_acct)) {
+ new_sam_acct = NULL;
+ return False;
+ }
+
+ pdb_set_username(*new_sam_acct, pwd->pw_name);
+ pdb_set_fullname(*new_sam_acct, pwd->pw_gecos);
+
+ pdb_set_uid(*new_sam_acct, &pwd->pw_uid);
+ pdb_set_gid(*new_sam_acct, &pwd->pw_gid);
+
+ pdb_set_user_rid(*new_sam_acct, pdb_uid_to_user_rid(pwd->pw_uid));
+
+ /* call the mapping code here */
+ if(get_group_map_from_gid(pwd->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ } else
+ rid=pdb_gid_to_group_rid(pwd->pw_gid);
+ pdb_set_group_rid(*new_sam_acct, rid);
+
+ pstrcpy(str, lp_logon_path());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_profile_path(*new_sam_acct, str);
+
+ pstrcpy(str, lp_logon_home());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_homedir(*new_sam_acct, str);
+
+ pstrcpy(str, lp_logon_drive());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_dir_drive(*new_sam_acct, str);
+
+ pstrcpy(str, lp_logon_script());
+ standard_sub_advanced(-1, pwd->pw_name, "", pwd->pw_gid, pwd->pw_name, str);
+ pdb_set_logon_script(*new_sam_acct, str);
+
+ return True;
+}
+
+
+/************************************************************
+ Free the NT/LM hashes only.
+ ***********************************************************/
+
+static BOOL pdb_free_sam_contents(SAM_ACCOUNT *user)
+{
+ if (user == NULL) {
+ DEBUG(0,("pdb_free_sam_contents: SAM_ACCOUNT was NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_free_sam_contents\n");
+#endif
+ return False;
+ }
+
+ /* As we start mallocing more strings this is where
+ we should free them. */
+
+ SAFE_FREE(user->nt_pw);
+ SAFE_FREE(user->lm_pw);
+
+ SAFE_FREE(user->uid);
+ SAFE_FREE(user->gid);
+
+ return True;
+}
+
+
+/************************************************************
+ Reset the SAM_ACCOUNT and free the NT/LM hashes.
+ - note: they are not zero'ed out however.
+ ***********************************************************/
+
+BOOL pdb_reset_sam(SAM_ACCOUNT *user)
+{
+ if (user == NULL) {
+ DEBUG(0,("pdb_reset_sam: SAM_ACCOUNT was NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_free_sam\n");
+#endif
+ return False;
+ }
+
+ if (!pdb_free_sam_contents(user)) {
+ return False;
+ }
+
+ if (!pdb_fill_default_sam(user)) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/************************************************************
+ Free the SAM_ACCOUNT and the NT/LM hashes.
+ ***********************************************************/
+
+BOOL pdb_free_sam(SAM_ACCOUNT **user)
+{
+ if (*user == NULL) {
+ DEBUG(0,("pdb_free_sam: SAM_ACCOUNT was NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_free_sam\n");
+#endif
+ return False;
+ }
+
+ if (!pdb_free_sam_contents(*user)) {
+ return False;
+ }
+
+ SAFE_FREE(*user);
+
+ return True;
+}
+
+
+/**********************************************************
+ Encode the account control bits into a string.
+ length = length of string to encode into (including terminating
+ null). length *MUST BE MORE THAN 2* !
+ **********************************************************/
+
+char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
+{
+ static fstring acct_str;
+ size_t i = 0;
+
+ acct_str[i++] = '[';
+
+ if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
+ if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
+ if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
+ if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
+ if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
+ if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
+ if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
+ if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
+ if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
+ if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
+ if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
+
+ for ( ; i < length - 2 ; i++ )
+ acct_str[i] = ' ';
+
+ i = length - 2;
+ acct_str[i++] = ']';
+ acct_str[i++] = '\0';
+
+ return acct_str;
+}
+
+/**********************************************************
+ Decode the account control bits from a string.
+ **********************************************************/
+
+uint16 pdb_decode_acct_ctrl(const char *p)
+{
+ uint16 acct_ctrl = 0;
+ BOOL finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[')
+ return 0;
+
+ for (p++; *p && !finished; p++) {
+ switch (*p) {
+ case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
+ case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
+ case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
+ case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
+ case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
+ case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
+ case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
+ case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
+ case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
+ case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
+ case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
+ case ' ': { break; }
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default: { finished = True; }
+ }
+ }
+
+ return acct_ctrl;
+}
+
+/*************************************************************
+ Routine to set 32 hex password characters from a 16 byte array.
+**************************************************************/
+
+void pdb_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl)
+{
+ if (pwd != NULL) {
+ int i;
+ for (i = 0; i < 16; i++)
+ slprintf(&p[i*2], 3, "%02X", pwd[i]);
+ } else {
+ if (acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
+ else
+ safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
+ }
+}
+
+/*************************************************************
+ Routine to get the 32 hex characters and turn them
+ into a 16 byte array.
+**************************************************************/
+
+BOOL pdb_gethexpwd(const char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p)
+ return (False);
+
+ for (i = 0; i < 32; i += 2) {
+ hinybble = toupper(p[i]);
+ lonybble = toupper(p[i + 1]);
+
+ p1 = strchr(hexchars, hinybble);
+ p2 = strchr(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ return (False);
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/*******************************************************************
+ Group and User RID username mapping function
+ ********************************************************************/
+
+BOOL pdb_name_to_rid(const char *user_name, uint32 *u_rid, uint32 *g_rid)
+{
+ GROUP_MAP map;
+ struct passwd *pw = Get_Pwnam(user_name);
+
+ if (u_rid == NULL || g_rid == NULL || user_name == NULL)
+ return False;
+
+ if (!pw) {
+ DEBUG(1,("Username %s is invalid on this system\n", user_name));
+ return False;
+ }
+
+ /* turn the unix UID into a Domain RID. this is what the posix
+ sub-system does (adds 1000 to the uid) */
+ *u_rid = pdb_uid_to_user_rid(pw->pw_uid);
+
+ /* absolutely no idea what to do about the unix GID to Domain RID mapping */
+ /* map it ! */
+ if (get_group_map_from_gid(pw->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, g_rid);
+ } else
+ *g_rid = pdb_gid_to_group_rid(pw->pw_gid);
+
+ return True;
+}
+
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+ return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+
+/*******************************************************************
+ Converts NT group RID to a UNIX gid.
+ ********************************************************************/
+
+gid_t pdb_group_rid_to_gid(uint32 group_rid)
+{
+ return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ converts UNIX uid to an NT User RID.
+ ********************************************************************/
+
+uint32 pdb_uid_to_user_rid(uid_t uid)
+{
+ return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE);
+}
+
+/*******************************************************************
+ converts NT Group RID to a UNIX uid.
+
+ warning: you must not call that function only
+ you must do a call to the group mapping first.
+ there is not anymore a direct link between the gid and the rid.
+ ********************************************************************/
+
+uint32 pdb_gid_to_group_rid(gid_t gid)
+{
+ return (((((uint32)gid)*RID_MULTIPLIER) + 1000) | GROUP_RID_TYPE);
+}
+
+/*******************************************************************
+ Decides if a RID is a well known RID.
+ ********************************************************************/
+
+static BOOL pdb_rid_is_well_known(uint32 rid)
+{
+ return (rid < 1000);
+}
+
+/*******************************************************************
+ Decides if a RID is a user or group RID.
+ ********************************************************************/
+
+BOOL pdb_rid_is_user(uint32 rid)
+{
+ /* lkcl i understand that NT attaches an enumeration to a RID
+ * such that it can be identified as either a user, group etc
+ * type. there are 5 such categories, and they are documented.
+ */
+ if(pdb_rid_is_well_known(rid)) {
+ /*
+ * The only well known user RIDs are DOMAIN_USER_RID_ADMIN
+ * and DOMAIN_USER_RID_GUEST.
+ */
+ if(rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST)
+ return True;
+ } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ Convert a rid into a name. Used in the lookup SID rpc.
+ ********************************************************************/
+
+BOOL local_lookup_sid(DOM_SID *sid, char *name, enum SID_NAME_USE *psid_name_use)
+{
+ uint32 rid;
+ BOOL is_user;
+
+ sid_peek_rid(sid, &rid);
+ is_user = pdb_rid_is_user(rid);
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ DEBUG(5,("local_lookup_sid: looking up %s RID %u.\n", is_user ? "user" :
+ "group", (unsigned int)rid));
+
+ if(is_user) {
+ if(rid == DOMAIN_USER_RID_ADMIN) {
+ pstring admin_users;
+ char *p = admin_users;
+ *psid_name_use = SID_NAME_USER;
+ if(!next_token(&p, name, NULL, sizeof(fstring)))
+ fstrcpy(name, "Administrator");
+ } else if (rid == DOMAIN_USER_RID_GUEST) {
+ pstring guest_users;
+ char *p = guest_users;
+ *psid_name_use = SID_NAME_USER;
+ if(!next_token(&p, name, NULL, sizeof(fstring)))
+ fstrcpy(name, "Guest");
+ } else {
+ uid_t uid;
+ struct passwd *pass;
+
+ /*
+ * Don't try to convert the rid to a name if
+ * running in appliance mode
+ */
+ if (lp_hide_local_users())
+ return False;
+
+ uid = pdb_user_rid_to_uid(rid);
+ pass = sys_getpwuid(uid);
+
+ *psid_name_use = SID_NAME_USER;
+
+ DEBUG(5,("local_lookup_sid: looking up uid %u %s\n", (unsigned int)uid,
+ pass ? "succeeded" : "failed" ));
+
+ if(!pass) {
+ slprintf(name, sizeof(fstring)-1, "unix_user.%u", (unsigned int)uid);
+ return True;
+ }
+
+ fstrcpy(name, pass->pw_name);
+
+ DEBUG(5,("local_lookup_sid: found user %s for rid %u\n", name,
+ (unsigned int)rid ));
+ }
+
+ } else {
+ gid_t gid;
+ struct group *gr;
+ GROUP_MAP map;
+
+ /*
+ * Don't try to convert the rid to a name if running
+ * in appliance mode
+ */
+
+ if (lp_hide_local_users())
+ return False;
+
+ /* check if it's a mapped group */
+ if (get_group_map_from_sid(*sid, &map, MAPPING_WITHOUT_PRIV)) {
+ if (map.gid!=-1) {
+ DEBUG(5,("local_lookup_sid: mapped group %s to gid %u\n", map.nt_name, (unsigned int)map.gid));
+ fstrcpy(name, map.nt_name);
+ *psid_name_use = map.sid_name_use;
+ return True;
+ }
+ }
+
+ gid = pdb_group_rid_to_gid(rid);
+ gr = getgrgid(gid);
+
+ *psid_name_use = SID_NAME_ALIAS;
+
+ DEBUG(5,("local_lookup_sid: looking up gid %u %s\n", (unsigned int)gid,
+ gr ? "succeeded" : "failed" ));
+
+ if(!gr) {
+ slprintf(name, sizeof(fstring)-1, "unix_group.%u", (unsigned int)gid);
+ return False;
+ }
+
+ fstrcpy( name, gr->gr_name);
+
+ DEBUG(5,("local_lookup_sid: found group %s for rid %u\n", name,
+ (unsigned int)rid ));
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Convert a name into a SID. Used in the lookup name rpc.
+ ********************************************************************/
+
+BOOL local_lookup_name(const char *c_domain, const char *c_user, DOM_SID *psid, enum SID_NAME_USE *psid_name_use)
+{
+ extern DOM_SID global_sid_World_Domain;
+ struct passwd *pass = NULL;
+ DOM_SID local_sid;
+ fstring user;
+ fstring domain;
+
+ *psid_name_use = SID_NAME_UNKNOWN;
+
+ /*
+ * domain and user may be quoted const strings, and map_username and
+ * friends can modify them. Make a modifiable copy. JRA.
+ */
+
+ fstrcpy(domain, c_domain);
+ fstrcpy(user, c_user);
+
+ sid_copy(&local_sid, &global_sam_sid);
+
+ /*
+ * Special case for MACHINE\Everyone. Map to the world_sid.
+ */
+
+ if(strequal(user, "Everyone")) {
+ sid_copy( psid, &global_sid_World_Domain);
+ sid_append_rid(psid, 0);
+ *psid_name_use = SID_NAME_ALIAS;
+ return True;
+ }
+
+ /*
+ * Don't lookup local unix users if running in appliance mode
+ */
+ if (lp_hide_local_users())
+ return False;
+
+ (void)map_username(user);
+
+ if((pass = Get_Pwnam(user))) {
+ sid_append_rid( &local_sid, pdb_uid_to_user_rid(pass->pw_uid));
+ *psid_name_use = SID_NAME_USER;
+ } else {
+ /*
+ * Maybe it was a group ?
+ */
+ struct group *grp;
+ GROUP_MAP map;
+
+ /* check if it's a mapped group */
+ if (get_group_map_from_ntname(user, &map, MAPPING_WITHOUT_PRIV)) {
+ if (map.gid!=-1) {
+ /* yes it's a mapped group to a valid unix group */
+ sid_copy(&local_sid, &map.sid);
+ *psid_name_use = map.sid_name_use;
+ }
+ else
+ /* it's a correct name but not mapped so it points to nothing*/
+ return False;
+ } else {
+ /* it's not a mapped group */
+ grp = getgrnam(user);
+ if(!grp)
+ return False;
+
+ /*
+ *check if it's mapped, if it is reply it doesn't exist
+ *
+ * that's to prevent this case:
+ *
+ * unix group ug is mapped to nt group ng
+ * someone does a lookup on ug
+ * we must not reply as it doesn't "exist" anymore
+ * for NT. For NT only ng exists.
+ * JFM, 30/11/2001
+ */
+
+ if(get_group_map_from_gid(grp->gr_gid, &map, MAPPING_WITHOUT_PRIV)){
+ return False;
+ }
+
+ sid_append_rid( &local_sid, pdb_gid_to_group_rid(grp->gr_gid));
+ *psid_name_use = SID_NAME_ALIAS;
+ }
+ }
+
+ sid_copy( psid, &local_sid);
+
+ return True;
+}
+
+/****************************************************************************
+ Convert a uid to SID - locally.
+****************************************************************************/
+
+DOM_SID *local_uid_to_sid(DOM_SID *psid, uid_t uid)
+{
+ extern DOM_SID global_sam_sid;
+
+ sid_copy(psid, &global_sam_sid);
+ sid_append_rid(psid, pdb_uid_to_user_rid(uid));
+
+ return psid;
+}
+
+/****************************************************************************
+ Convert a SID to uid - locally.
+****************************************************************************/
+
+BOOL local_sid_to_uid(uid_t *puid, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern DOM_SID global_sam_sid;
+
+ DOM_SID dom_sid;
+ uint32 rid;
+ fstring str;
+ struct passwd *pass;
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ sid_copy(&dom_sid, psid);
+ sid_split_rid(&dom_sid, &rid);
+
+ if (!pdb_rid_is_user(rid))
+ return False;
+
+ /*
+ * We can only convert to a uid if this is our local
+ * Domain SID (ie. we are the controling authority).
+ */
+ if (!sid_equal(&global_sam_sid, &dom_sid))
+ return False;
+
+ *puid = pdb_user_rid_to_uid(rid);
+
+ /*
+ * Ensure this uid really does exist.
+ */
+ if(!(pass = sys_getpwuid(*puid)))
+ return False;
+
+ DEBUG(10,("local_sid_to_uid: SID %s -> uid (%u) (%s).\n", sid_to_string( str, psid),
+ (unsigned int)*puid, pass->pw_name ));
+
+ *name_type = SID_NAME_USER;
+
+ return True;
+}
+
+/****************************************************************************
+ Convert a gid to SID - locally.
+****************************************************************************/
+
+DOM_SID *local_gid_to_sid(DOM_SID *psid, gid_t gid)
+{
+ extern DOM_SID global_sam_sid;
+ GROUP_MAP map;
+
+ sid_copy(psid, &global_sam_sid);
+
+ if (get_group_map_from_gid(gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_copy(psid, &map.sid);
+ }
+ else {
+ sid_append_rid(psid, pdb_gid_to_group_rid(gid));
+ }
+
+ return psid;
+}
+
+/****************************************************************************
+ Convert a SID to gid - locally.
+****************************************************************************/
+
+BOOL local_sid_to_gid(gid_t *pgid, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern DOM_SID global_sam_sid;
+ DOM_SID dom_sid;
+ uint32 rid;
+ fstring str;
+ struct group *grp;
+ GROUP_MAP map;
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ sid_copy(&dom_sid, psid);
+ sid_split_rid(&dom_sid, &rid);
+
+ /*
+ * We can only convert to a gid if this is our local
+ * Domain SID (ie. we are the controling authority).
+ *
+ * Or in the Builtin SID too. JFM, 11/30/2001
+ */
+
+ if (!sid_equal(&global_sam_sid, &dom_sid))
+ return False;
+
+ if (pdb_rid_is_user(rid))
+ return False;
+
+ if (get_group_map_from_sid(*psid, &map, MAPPING_WITHOUT_PRIV)) {
+
+ /* the SID is in the mapping table but not mapped */
+ if (map.gid==-1)
+ return False;
+
+ sid_peek_rid(&map.sid, pgid);
+ *name_type = map.sid_name_use;
+ } else {
+ *pgid = pdb_group_rid_to_gid(rid);
+ *name_type = SID_NAME_ALIAS;
+ }
+
+ /*
+ * Ensure this gid really does exist.
+ */
+
+ if(!(grp = getgrgid(*pgid)))
+ return False;
+
+ DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u) (%s).\n", sid_to_string( str, psid),
+ (unsigned int)*pgid, grp->gr_name ));
+
+ return True;
+}
+
+static void select_name(pstring string, const UNISTR2 *from)
+{
+ if (from->buffer != 0)
+ unistr2_to_ascii(string, from, sizeof(pstring));
+}
+
+/*************************************************************
+ Copies a SAM_USER_INFO_23 to a SAM_ACCOUNT
+ **************************************************************/
+
+void copy_id23_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_23 *from)
+{
+
+ if (from == NULL || to == NULL)
+ return;
+
+ to->logon_time = nt_time_to_unix(&from->logon_time);
+ to->logoff_time = nt_time_to_unix(&from->logoff_time);
+ to->kickoff_time = nt_time_to_unix(&from->kickoff_time);
+ to->pass_last_set_time = nt_time_to_unix(&from->pass_last_set_time);
+ to->pass_can_change_time = nt_time_to_unix(&from->pass_can_change_time);
+ to->pass_must_change_time = nt_time_to_unix(&from->pass_must_change_time);
+
+ select_name(to->username , &from->uni_user_name );
+ select_name(to->full_name , &from->uni_full_name );
+ select_name(to->home_dir , &from->uni_home_dir );
+ select_name(to->dir_drive , &from->uni_dir_drive );
+ select_name(to->logon_script, &from->uni_logon_script);
+ select_name(to->profile_path, &from->uni_profile_path);
+ select_name(to->acct_desc , &from->uni_acct_desc );
+ select_name(to->workstations, &from->uni_workstations);
+ select_name(to->unknown_str , &from->uni_unknown_str );
+ select_name(to->munged_dial , &from->uni_munged_dial );
+
+ if (from->user_rid)
+ to->user_rid = from->user_rid;
+ if (from->group_rid)
+ to->group_rid = from->group_rid;
+
+ to->acct_ctrl = from->acb_info;
+ to->unknown_3 = from->unknown_3;
+
+ to->logon_divs = from->logon_divs;
+ to->hours_len = from->logon_hrs.len;
+ memcpy(to->hours, from->logon_hrs.hours, MAX_HOURS_LEN);
+
+ to->unknown_5 = from->unknown_5;
+ to->unknown_6 = from->unknown_6;
+}
+
+/*************************************************************
+ Copies a sam passwd.
+ **************************************************************/
+
+void copy_id21_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_21 *from)
+{
+ if (from == NULL || to == NULL)
+ return;
+
+ to->logon_time = nt_time_to_unix(&from->logon_time);
+ to->logoff_time = nt_time_to_unix(&from->logoff_time);
+ to->kickoff_time = nt_time_to_unix(&from->kickoff_time);
+ to->pass_last_set_time = nt_time_to_unix(&from->pass_last_set_time);
+ to->pass_can_change_time = nt_time_to_unix(&from->pass_can_change_time);
+ to->pass_must_change_time = nt_time_to_unix(&from->pass_must_change_time);
+
+ select_name(to->username , &from->uni_user_name );
+ select_name(to->full_name , &from->uni_full_name );
+ select_name(to->home_dir , &from->uni_home_dir );
+ select_name(to->dir_drive , &from->uni_dir_drive );
+ select_name(to->logon_script, &from->uni_logon_script);
+ select_name(to->profile_path, &from->uni_profile_path);
+ select_name(to->acct_desc , &from->uni_acct_desc );
+ select_name(to->workstations, &from->uni_workstations);
+ select_name(to->unknown_str , &from->uni_unknown_str );
+ select_name(to->munged_dial , &from->uni_munged_dial );
+
+ to->user_rid = from->user_rid;
+ to->group_rid = from->group_rid;
+
+ /* FIXME!! Do we need to copy the passwords here as well?
+ I don't know. Need to figure this out --jerry */
+
+ to->acct_ctrl = from->acb_info;
+ to->unknown_3 = from->unknown_3;
+
+ to->logon_divs = from->logon_divs;
+ to->hours_len = from->logon_hrs.len;
+ memcpy(to->hours, from->logon_hrs.hours, MAX_HOURS_LEN);
+
+ to->unknown_5 = from->unknown_5;
+ to->unknown_6 = from->unknown_6;
+}
+
+/*************************************************************
+ Change a password entry in the local smbpasswd file.
+
+ FIXME!! The function needs to be abstracted into the
+ passdb interface or something. It is currently being called
+ by _api_samr_create_user() in rpc_server/srv_samr.c,
+ in SWAT and by smbpasswd/pdbedit.
+
+ --jerry
+ *************************************************************/
+
+BOOL local_password_change(const char *user_name, int local_flags,
+ const char *new_passwd,
+ char *err_str, size_t err_str_len,
+ char *msg_str, size_t msg_str_len)
+{
+ struct passwd *pwd = NULL;
+ SAM_ACCOUNT *sam_pass=NULL;
+
+ *err_str = '\0';
+ *msg_str = '\0';
+
+ /* Get the smb passwd entry for this user */
+ pdb_init_sam(&sam_pass);
+ if(!pdb_getsampwnam(sam_pass, user_name)) {
+ pdb_free_sam(&sam_pass);
+
+ if (local_flags & LOCAL_ADD_USER) {
+ /*
+ * Check for a local account - if we're adding only.
+ */
+
+ if(!(pwd = sys_getpwnam(user_name))) {
+ slprintf(err_str, err_str_len - 1, "User %s does not \
+exist in system password file (usually /etc/passwd). Cannot add \
+account without a valid local system user.\n", user_name);
+ return False;
+ }
+ } else {
+ slprintf(err_str, err_str_len-1,"Failed to find entry for user %s.\n", user_name);
+ return False;
+ }
+
+ if (!pdb_init_sam_pw(&sam_pass, pwd)) {
+ slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
+ return False;
+ }
+
+
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'domain trust account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else {
+ if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL)) {
+ slprintf(err_str, err_str_len - 1, "Failed to set 'normal account' flags for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ } else {
+ /* the entry already existed */
+ local_flags &= ~LOCAL_ADD_USER;
+ }
+
+ /*
+ * We are root - just write the new password
+ * and the valid last change time.
+ */
+
+ if (local_flags & LOCAL_DISABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED)) {
+ slprintf(err_str, err_str_len-1, "Failed to set 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_ENABLE_USER) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ if (local_flags & LOCAL_SET_NO_PASSWORD) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ)) {
+ slprintf(err_str, err_str_len-1, "Failed to set 'no password required' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_SET_PASSWORD) {
+ /*
+ * If we're dealing with setting a completely empty user account
+ * ie. One with a password of 'XXXX', but not set disabled (like
+ * an account created from scratch) then if the old password was
+ * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
+ * We remove that as we're giving this user their first password
+ * and the decision hasn't really been made to disable them (ie.
+ * don't create them disabled). JRA.
+ */
+ if ((pdb_get_lanman_passwd(sam_pass)==NULL) && (pdb_get_acct_ctrl(sam_pass)&ACB_DISABLED)) {
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'disabled' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+ if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ))) {
+ slprintf(err_str, err_str_len-1, "Failed to unset 'no password required' flag for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) {
+ slprintf(err_str, err_str_len-1, "Failed to set password for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ }
+
+ if (local_flags & LOCAL_ADD_USER) {
+ if (pdb_add_sam_account(sam_pass)) {
+ slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return True;
+ } else {
+ slprintf(err_str, err_str_len-1, "Failed to add entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ } else if (local_flags & LOCAL_DELETE_USER) {
+ if (!pdb_delete_sam_account(user_name)) {
+ slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ slprintf(msg_str, msg_str_len-1, "Deleted user %s.\n", user_name);
+ } else {
+ if(!pdb_update_sam_account(sam_pass, True)) {
+ slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", user_name);
+ pdb_free_sam(&sam_pass);
+ return False;
+ }
+ if(local_flags & LOCAL_DISABLE_USER)
+ slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_ENABLE_USER)
+ slprintf(msg_str, msg_str_len-1, "Enabled user %s.\n", user_name);
+ else if (local_flags & LOCAL_SET_NO_PASSWORD)
+ slprintf(msg_str, msg_str_len-1, "User %s password set to none.\n", user_name);
+ }
+
+ pdb_free_sam(&sam_pass);
+ return True;
+}
+
+/*********************************************************************
+ Collection of get...() functions for SAM_ACCOUNT_INFO.
+ ********************************************************************/
+
+uint16 pdb_get_acct_ctrl (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->acct_ctrl);
+ else
+ return (ACB_DISABLED);
+}
+
+time_t pdb_get_logon_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_time);
+ else
+ return (0);
+}
+
+time_t pdb_get_logoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_kickoff_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->kickoff_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_last_set_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_last_set_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_can_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_can_change_time);
+ else
+ return (-1);
+}
+
+time_t pdb_get_pass_must_change_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->pass_must_change_time);
+ else
+ return (-1);
+}
+
+uint16 pdb_get_logon_divs (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_divs);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_hours_len (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->hours_len);
+ else
+ return (-1);
+}
+
+const uint8* pdb_get_hours (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->hours);
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_nt_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->nt_pw);
+ else
+ return (NULL);
+}
+
+const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->lm_pw);
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_user_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->user_rid);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_group_rid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->group_rid);
+ else
+ return (-1);
+}
+
+uid_t *pdb_get_uid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->uid);
+ else
+ return (NULL);
+}
+
+gid_t *pdb_get_gid (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->gid);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_domain (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->domain);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_nt_username (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->nt_username);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_fullname (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->full_name);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_homedir (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->home_dir);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_dirdrive (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->dir_drive);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_logon_script (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->logon_script);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_profile_path (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->profile_path);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_acct_desc (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->acct_desc);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_workstations (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->workstations);
+ else
+ return (NULL);
+}
+
+const char* pdb_get_munged_dial (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->munged_dial);
+ else
+ return (NULL);
+}
+
+uint32 pdb_get_unknown3 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->unknown_3);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown5 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->unknown_5);
+ else
+ return (-1);
+}
+
+uint32 pdb_get_unknown6 (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->unknown_6);
+ else
+ return (-1);
+}
+
+/*********************************************************************
+ Collection of set...() functions for SAM_ACCOUNT_INFO.
+ ********************************************************************/
+
+BOOL pdb_set_acct_ctrl (SAM_ACCOUNT *sampass, uint16 flags)
+{
+ if (!sampass)
+ return False;
+
+ if (sampass) {
+ sampass->acct_ctrl = flags;
+ return True;
+ }
+
+ return False;
+}
+
+BOOL pdb_set_logon_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logon_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_logoff_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logoff_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_kickoff_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->kickoff_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_can_change_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_can_change_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_must_change_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_must_change_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_pass_last_set_time (SAM_ACCOUNT *sampass, time_t mytime)
+{
+ if (!sampass)
+ return False;
+
+ sampass->pass_last_set_time = mytime;
+ return True;
+}
+
+BOOL pdb_set_hours_len (SAM_ACCOUNT *sampass, uint32 len)
+{
+ if (!sampass)
+ return False;
+
+ sampass->hours_len = len;
+ return True;
+}
+
+BOOL pdb_set_logons_divs (SAM_ACCOUNT *sampass, uint16 hours)
+{
+ if (!sampass)
+ return False;
+
+ sampass->logon_divs = hours;
+ return True;
+}
+
+/*********************************************************************
+ Set the user's UNIX uid, as a pointer to malloc'ed memory.
+ ********************************************************************/
+
+BOOL pdb_set_uid (SAM_ACCOUNT *sampass, const uid_t *uid)
+{
+ if (!sampass)
+ return False;
+
+ if (!uid) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->uid);
+ return True;
+ }
+
+ if (sampass->uid!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: uid non NULL overwritting ?\n"));
+ else
+ sampass->uid=(uid_t *)malloc(sizeof(uid_t));
+
+ if (sampass->uid==NULL)
+ return False;
+
+ *sampass->uid = *uid;
+
+ return True;
+
+}
+
+/*********************************************************************
+ Set the user's UNIX gid, as a pointer to malloc'ed memory.
+ ********************************************************************/
+
+BOOL pdb_set_gid (SAM_ACCOUNT *sampass, const gid_t *gid)
+{
+ if (!sampass)
+ return False;
+
+ if (!gid) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->gid);
+ return True;
+ }
+
+ if (sampass->gid!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: gid non NULL overwritting ?\n"));
+ else
+ sampass->gid=(gid_t *)malloc(sizeof(gid_t));
+
+ if (sampass->gid==NULL)
+ return False;
+
+ *sampass->gid = *gid;
+
+ return True;
+
+}
+
+BOOL pdb_set_user_rid (SAM_ACCOUNT *sampass, uint32 rid)
+{
+ if (!sampass)
+ return False;
+
+ sampass->user_rid = rid;
+ return True;
+}
+
+BOOL pdb_set_group_rid (SAM_ACCOUNT *sampass, uint32 grid)
+{
+ if (!sampass)
+ return False;
+
+ sampass->group_rid = grid;
+ return True;
+}
+
+/*********************************************************************
+ Set the user's UNIX name.
+ ********************************************************************/
+
+BOOL pdb_set_username(SAM_ACCOUNT *sampass, const char *username)
+{
+ if (!sampass)
+ return False;
+ *sampass->username = '\0';
+ if (!username)
+ return False;
+
+ StrnCpy (sampass->username, username, strlen(username));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the domain name.
+ ********************************************************************/
+
+BOOL pdb_set_domain(SAM_ACCOUNT *sampass, const char *domain)
+{
+ if (!sampass)
+ return False;
+ *sampass->domain = '\0';
+ if (!domain)
+ return False;
+
+ StrnCpy (sampass->domain, domain, strlen(domain));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT name.
+ ********************************************************************/
+
+BOOL pdb_set_nt_username(SAM_ACCOUNT *sampass, const char *nt_username)
+{
+ if (!sampass)
+ return False;
+ *sampass->nt_username = '\0';
+ if (!nt_username)
+ return False;
+
+ StrnCpy (sampass->nt_username, nt_username, strlen(nt_username));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's full name.
+ ********************************************************************/
+
+BOOL pdb_set_fullname(SAM_ACCOUNT *sampass, const char *fullname)
+{
+ if (!sampass)
+ return False;
+ *sampass->full_name = '\0';
+ if (!fullname)
+ return False;
+
+ StrnCpy (sampass->full_name, fullname, strlen(fullname));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's logon script.
+ ********************************************************************/
+
+BOOL pdb_set_logon_script(SAM_ACCOUNT *sampass, const char *logon_script)
+{
+ if (!sampass)
+ return False;
+ *sampass->logon_script = '\0';
+ if (!logon_script)
+ return False;
+
+ StrnCpy (sampass->logon_script, logon_script, strlen(logon_script));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's profile path.
+ ********************************************************************/
+
+BOOL pdb_set_profile_path (SAM_ACCOUNT *sampass, const char *profile_path)
+{
+ if (!sampass)
+ return False;
+ *sampass->profile_path = '\0';
+ if (!profile_path)
+ return False;
+
+ StrnCpy (sampass->profile_path, profile_path, strlen(profile_path));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's directory drive.
+ ********************************************************************/
+
+BOOL pdb_set_dir_drive (SAM_ACCOUNT *sampass, const char *dir_drive)
+{
+ if (!sampass)
+ return False;
+ *sampass->dir_drive = '\0';
+ if (!dir_drive)
+ return False;
+
+ StrnCpy (sampass->dir_drive, dir_drive, strlen(dir_drive));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's home directory.
+ ********************************************************************/
+
+BOOL pdb_set_homedir (SAM_ACCOUNT *sampass, const char *homedir)
+{
+ if (!sampass)
+ return False;
+ *sampass->home_dir = '\0';
+ if (!homedir)
+ return False;
+
+ StrnCpy (sampass->home_dir, homedir, strlen(homedir));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's account description.
+ ********************************************************************/
+
+BOOL pdb_set_acct_desc (SAM_ACCOUNT *sampass, const char *acct_desc)
+{
+ if (!sampass)
+ return False;
+ *sampass->acct_desc = '\0';
+ if (!acct_desc)
+ return False;
+
+ StrnCpy (sampass->acct_desc, acct_desc, strlen(acct_desc));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's workstation allowed list.
+ ********************************************************************/
+
+BOOL pdb_set_workstations (SAM_ACCOUNT *sampass, const char *workstations)
+{
+ if (!sampass)
+ return False;
+ *sampass->workstations = '\0';
+ if (!workstations)
+ return False;
+
+ StrnCpy (sampass->workstations, workstations, strlen(workstations));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's dial string.
+ ********************************************************************/
+
+BOOL pdb_set_munged_dial (SAM_ACCOUNT *sampass, const char *munged_dial)
+{
+ if (!sampass)
+ return False;
+ *sampass->munged_dial = '\0';
+ if (!munged_dial)
+ return False;
+
+ StrnCpy (sampass->munged_dial, munged_dial, strlen(munged_dial));
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's NT hash.
+ ********************************************************************/
+
+BOOL pdb_set_nt_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ if (!pwd) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->nt_pw);
+ return True;
+ }
+
+ if (sampass->nt_pw!=NULL)
+ DEBUG(4,("pdb_set_nt_passwd: NT hash non NULL overwritting ?\n"));
+ else
+ sampass->nt_pw=(unsigned char *)malloc(sizeof(unsigned char)*16);
+
+ if (sampass->nt_pw==NULL)
+ return False;
+
+ memcpy (sampass->nt_pw, pwd, 16);
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's LM hash.
+ ********************************************************************/
+
+BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 *pwd)
+{
+ if (!sampass)
+ return False;
+
+ if (!pwd) {
+ /* Allow setting to NULL */
+ SAFE_FREE(sampass->lm_pw);
+ return True;
+ }
+
+ if (sampass->lm_pw!=NULL)
+ DEBUG(4,("pdb_set_lanman_passwd: LM hash non NULL overwritting ?\n"));
+ else
+ sampass->lm_pw=(unsigned char *)malloc(sizeof(unsigned char)*16);
+
+ if (sampass->lm_pw==NULL)
+ return False;
+
+ memcpy (sampass->lm_pw, pwd, 16);
+
+ return True;
+}
+
+BOOL pdb_set_unknown_3 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_3 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_5 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_5 = unkn;
+ return True;
+}
+
+BOOL pdb_set_unknown_6 (SAM_ACCOUNT *sampass, uint32 unkn)
+{
+ if (!sampass)
+ return False;
+
+ sampass->unknown_6 = unkn;
+ return True;
+}
+
+BOOL pdb_set_hours (SAM_ACCOUNT *sampass, const uint8 *hours)
+{
+ if (!sampass)
+ return False;
+
+ if (!hours) {
+ memset ((char *)sampass->hours, 0, MAX_HOURS_LEN);
+ return True;
+ }
+
+ memcpy (sampass->hours, hours, MAX_HOURS_LEN);
+
+ return True;
+}
+
+
+/* Helpful interfaces to the above */
+
+/*********************************************************************
+ Sets the last changed times and must change times for a normal
+ password change.
+ ********************************************************************/
+
+BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass)
+{
+ time_t expire;
+
+ if (!sampass)
+ return False;
+
+ if (!pdb_set_pass_last_set_time (sampass, time(NULL)))
+ return False;
+
+ account_policy_get(AP_MAX_PASSWORD_AGE, (int *)&expire);
+
+ if (expire==-1) {
+ if (!pdb_set_pass_must_change_time (sampass, 0))
+ return False;
+ } else {
+ if (!pdb_set_pass_must_change_time (sampass,
+ pdb_get_pass_last_set_time(sampass)
+ + expire))
+ return False;
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Set the user's PLAINTEXT password. Used as an interface to the above.
+ Also sets the last change time to NOW.
+ ********************************************************************/
+
+BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext)
+{
+ uchar new_lanman_p16[16];
+ uchar new_nt_p16[16];
+
+ if (!sampass || !plaintext)
+ return False;
+
+ nt_lm_owf_gen (plaintext, new_nt_p16, new_lanman_p16);
+
+ if (!pdb_set_nt_passwd (sampass, new_nt_p16))
+ return False;
+
+ if (!pdb_set_lanman_passwd (sampass, new_lanman_p16))
+ return False;
+
+ if (!pdb_set_pass_changed_now (sampass))
+ return False;
+
+ return True;
+}
+
+
diff --git a/source/passdb/passgrp.c b/source/passdb/passgrp.c
new file mode 100644
index 00000000000..55a71e94a27
--- /dev/null
+++ b/source/passdb/passgrp.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * NOTE. All these functions are abstracted into a structure
+ * that points to the correct function for the selected database. JRA.
+ *
+ * the API does NOT fill in the gaps if you set an API function
+ * to NULL: it will deliberately attempt to call the NULL function.
+ *
+ */
+
+static struct passgrp_ops *pwgrp_ops;
+
+/***************************************************************
+ Initialise the passgrp operations.
+***************************************************************/
+
+BOOL initialise_passgrp_db(void)
+{
+ if (pwgrp_ops)
+ {
+ return True;
+ }
+
+#ifdef WITH_NISPLUS
+ pwgrp_ops = nisplus_initialise_password_grp();
+#elif defined(WITH_LDAP)
+ pwgrp_ops = ldap_initialize_password_grp();
+#else
+ pwgrp_ops = file_initialise_password_grp();
+#endif
+
+ return (pwgrp_ops != NULL);
+}
+
+/*
+ * Functions that return/manipulate a struct smb_passwd.
+ */
+
+/************************************************************************
+ Utility function to search smb passwd by rid.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrprid(uint32 user_rid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return iterate_getsmbgrpuid(pwdb_user_rid_to_uid(user_rid),
+ grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Utility function to search smb passwd by uid. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrpuid(uid_t smb_userid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ struct smb_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by smb_userid: %x\n", (int)smb_userid));
+
+ /* Open the smb password database - not for update. */
+ fp = startsmbgrpent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb passgrp database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && pwd->smb_userid != smb_userid)
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid));
+ }
+
+ endsmbgrpent(fp);
+ return pwd;
+}
+
+/************************************************************************
+ Utility function to search smb passwd by name. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbgrpnam(char *name,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ struct smb_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the passgrp file - not for update. */
+ fp = startsmbgrpent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb passgrp database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbgrpent(fp, grps, num_grps, alss, num_alss)) != NULL && !strequal(pwd->smb_name, name))
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endsmbgrpent(fp);
+ return pwd;
+}
+
+/***************************************************************
+ Start to enumerate the smb or sam passwd list. Returns a void pointer
+ to ensure no modification outside this module.
+
+ Note that currently it is being assumed that a pointer returned
+ from this function may be used to enumerate struct sam_passwd
+ entries as well as struct smb_passwd entries. This may need
+ to change. JRA.
+
+****************************************************************/
+
+void *startsmbgrpent(BOOL update)
+{
+ return pwgrp_ops->startsmbgrpent(update);
+}
+
+/***************************************************************
+ End enumeration of the smb or sam passwd list.
+
+ Note that currently it is being assumed that a pointer returned
+ from this function may be used to enumerate struct sam_passwd
+ entries as well as struct smb_passwd entries. This may need
+ to change. JRA.
+
+****************************************************************/
+
+void endsmbgrpent(void *vp)
+{
+ pwgrp_ops->endsmbgrpent(vp);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smb passwd list.
+ *************************************************************************/
+
+struct smb_passwd *getsmbgrpent(void *vp,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpent(vp, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by name.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrpnam(char *name,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpnam(name, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by user rid.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrprid(uint32 user_rid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrprid(user_rid, grps, num_grps, alss, num_alss);
+}
+
+/************************************************************************
+ Routine to search smb passwd by uid.
+*************************************************************************/
+
+struct smb_passwd *getsmbgrpuid(uid_t smb_userid,
+ uint32 **grps, int *num_grps,
+ uint32 **alss, int *num_alss)
+{
+ return pwgrp_ops->getsmbgrpuid(smb_userid, grps, num_grps, alss, num_alss);
+}
diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c
new file mode 100644
index 00000000000..f426f926b19
--- /dev/null
+++ b/source/passdb/pdb_ldap.c
@@ -0,0 +1,1045 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.9.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Shahms King 2001
+ Copyright (C) Jean François Micouleau 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+#ifdef WITH_LDAP_SAM
+/* TODO:
+* persistent connections: if using NSS LDAP, many connections are made
+* however, using only one within Samba would be nice
+*
+* Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
+*
+* Other LDAP based login attributes: accountExpires, etc.
+* (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
+* structures don't have fields for some of these attributes)
+*
+* SSL is done, but can't get the certificate based authentication to work
+* against on my test platform (Linux 2.4, OpenLDAP 2.x)
+*/
+
+/* NOTE: this will NOT work against an Active Directory server
+* due to the fact that the two password fields cannot be retrieved
+* from a server; recommend using security = domain in this situation
+* and/or winbind
+*/
+
+#include <lber.h>
+#include <ldap.h>
+
+#ifndef SAM_ACCOUNT
+#define SAM_ACCOUNT struct sam_passwd
+#endif
+
+struct ldap_enum_info
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+};
+
+static struct ldap_enum_info global_ldap_ent;
+
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static BOOL
+ldap_open_connection (LDAP ** ldap_struct)
+{
+ int port;
+ int version, rc;
+ int tls = LDAP_OPT_X_TLS_HARD;
+
+ if (lp_ldap_ssl() == LDAP_SSL_ON && lp_ldap_port() == 389) {
+ port = 636;
+ }
+ else {
+ port = lp_ldap_port();
+ }
+
+ if ((*ldap_struct = ldap_init(lp_ldap_server(), port)) == NULL) {
+ DEBUG(0, ("The LDAP server is not responding !\n"));
+ return (False);
+ }
+
+ /* Connect to older servers using SSL and V2 rather than Start TLS */
+ if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version != LDAP_VERSION2)
+ {
+ version = LDAP_VERSION2;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ }
+ }
+
+ switch (lp_ldap_ssl())
+ {
+ case LDAP_SSL_START_TLS:
+ if (ldap_get_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ }
+ }
+ if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
+ {
+ DEBUG(0,
+ ("Failed to issue the StartTLS instruction: %s\n",
+ ldap_err2string(rc)));
+ return False;
+ }
+ DEBUG (2, ("StartTLS issued: using a TLS connection\n"));
+ break;
+ case LDAP_SSL_ON:
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+ break;
+ case LDAP_SSL_OFF:
+ default:
+ }
+
+ DEBUG(2, ("ldap_open_connection: connection opened\n"));
+ return (True);
+}
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static BOOL ldap_connect_system(LDAP * ldap_struct)
+{
+ int rc;
+ static BOOL got_pw = False;
+ static pstring ldap_secret;
+
+ /* get the password if we don't have it already */
+ if (!got_pw && !(got_pw=fetch_ldap_pw(lp_ldap_admin_dn(), ldap_secret, sizeof(pstring))))
+ {
+ DEBUG(0, ("ldap_connect_system: Failed to retrieve password for %s from secrets.tdb\n",
+ lp_ldap_admin_dn()));
+ return False;
+ }
+
+ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
+ (OpenLDAP) doesnt' seem to support it */
+ if ((rc = ldap_simple_bind_s(ldap_struct, lp_ldap_admin_dn(),
+ ldap_secret)) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Bind failed: %s\n", ldap_err2string(rc)));
+ return (False);
+ }
+
+ DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldap_search_one_user (LDAP * ldap_struct, const char *filter, LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+
+ DEBUG(2, ("ldap_search_one_user: searching for:[%s]\n", filter));
+
+ rc = ldap_search_s (ldap_struct, lp_ldap_suffix (), scope,
+ filter, NULL, 0, result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldap_search_one_user: Problem during the LDAP search: %s\n",
+ ldap_err2string (rc)));
+ DEBUG(3,("ldap_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(),
+ filter));
+ }
+ return (rc);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldap_search_one_user_by_name (LDAP * ldap_struct, const char *user,
+ LDAPMessage ** result)
+{
+ pstring filter;
+
+ /*
+ in the filter expression, replace %u with the real name
+ so in ldap filter, %u MUST exist :-)
+ */
+ pstrcpy(filter, lp_ldap_filter());
+
+ /* have to use this here because $ is filtered out
+ * in pstring_sub
+ */
+ all_string_sub(filter, "%u", user, sizeof(pstring));
+
+ return ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static int ldap_search_one_user_by_uid(LDAP * ldap_struct, int uid,
+ LDAPMessage ** result)
+{
+ struct passwd *user;
+ pstring filter;
+
+ /* Get the username from the system and look that up in the LDAP */
+ user = sys_getpwuid(uid);
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
+
+ return ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by rid.
+******************************************************************/
+static int ldap_search_one_user_by_rid (LDAP * ldap_struct, uint32 rid,
+ LDAPMessage ** result)
+{
+ pstring filter;
+ int rc;
+
+ /* check if the user rid exsists, if not, try searching on the uid */
+ snprintf(filter, sizeof(filter) - 1, "rid=%i", rid);
+ rc = ldap_search_one_user(ldap_struct, filter, result);
+
+ if (rc != LDAP_SUCCESS)
+ rc = ldap_search_one_user_by_uid(ldap_struct,
+ pdb_user_rid_to_uid(rid), result);
+
+ return rc;
+}
+
+/*******************************************************************
+search an attribute and return the first value found.
+******************************************************************/
+static void get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ char *attribute, char *value)
+{
+ char **valeurs;
+
+ if ((valeurs = ldap_get_values (ldap_struct, entry, attribute)) != NULL) {
+ pstrcpy(value, valeurs[0]);
+ ldap_value_free(valeurs);
+ DEBUG (2, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
+ }
+ else {
+ value = NULL;
+ DEBUG (2, ("get_single_attribute: [%s] = [NULL]\n", attribute));
+ }
+}
+
+/************************************************************************
+Routine to manage the LDAPMod structure array
+manage memory used by the array, by each struct, and values
+
+************************************************************************/
+static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
+{
+ LDAPMod **mods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (attribute == NULL || *attribute == '\0')
+ return;
+
+ if (value == NULL || *value == '\0')
+ return;
+
+ if (mods == NULL)
+ {
+ mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[0] = NULL;
+ }
+
+ for (i = 0; mods[i] != NULL; ++i) {
+ if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
+ break;
+ }
+
+ if (mods[i] == NULL)
+ {
+ mods = (LDAPMod **) realloc (mods, (i + 2) * sizeof (LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
+ if (mods[i] == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i]->mod_op = modop;
+ mods[i]->mod_values = NULL;
+ mods[i]->mod_type = strdup(attribute);
+ mods[i + 1] = NULL;
+ }
+
+ if (value != NULL)
+ {
+ j = 0;
+ if (mods[i]->mod_values != NULL) {
+ for (; mods[i]->mod_values[j] != NULL; j++);
+ }
+ mods[i]->mod_values = (char **)realloc(mods[i]->mod_values,
+ (j + 2) * sizeof (char *));
+
+ if (mods[i]->mod_values == NULL) {
+ DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
+ return;
+ }
+ mods[i]->mod_values[j] = strdup(value);
+ mods[i]->mod_values[j + 1] = NULL;
+ }
+ *modlist = mods;
+}
+
+/* New Interface is being implemented here */
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_sam_from_buffer in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_sam_from_ldap (SAM_ACCOUNT * sampass,
+ LDAP * ldap_struct, LDAPMessage * entry)
+{
+ time_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ static pstring username;
+ static pstring domain;
+ static pstring nt_username;
+ static pstring fullname;
+ static pstring homedir;
+ static pstring dir_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring munged_dial;
+ static pstring workstations;
+ struct passwd *sys_user;
+ uint32 user_rid, group_rid;
+ static uint8 smblmpwd[16];
+ static uint8 smbntpwd[16];
+ uint16 acct_ctrl, logon_divs;
+ uint32 hours_len;
+ uint8 *hours;
+ pstring temp;
+
+ get_single_attribute(ldap_struct, entry, "uid", username);
+ DEBUG(2, ("Entry found for user: %s\n", username));
+
+ pstrcpy(nt_username, username);
+
+ get_single_attribute(ldap_struct, entry, "sambaDomain", domain);
+ if (!domain)
+ pstrcpy(domain, lp_workgroup());
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ pass_last_set_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logonTime", temp);
+ logon_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logoffTime", temp);
+ logoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
+ kickoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
+ pass_can_change_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
+ pass_must_change_time = (time_t) strtol(temp, NULL, 16);
+
+ /* recommend that 'gecos' and 'displayName' should refer to the same
+ * attribute OID. userFullName depreciated, only used by Samba
+ * primary rules of LDAP: don't make a new attribute when one is already defined
+ * that fits your needs; using gecos then displayName then cn rather than 'userFullName'
+ */
+
+ get_single_attribute(ldap_struct, entry, "gecos", fullname);
+
+ if (!fullname) {
+ get_single_attribute(ldap_struct, entry, "displayName", fullname);
+ get_single_attribute(ldap_struct, entry, "cn", fullname);
+ }
+
+ get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
+ DEBUG(5,("homeDrive is set to %s\n",dir_drive));
+ if (!*dir_drive) {
+ pstrcpy(dir_drive, lp_logon_drive());
+ DEBUG(5,("homeDrive fell back to %s\n",dir_drive));
+ }
+
+ get_single_attribute(ldap_struct, entry, "smbHome", homedir);
+ DEBUG(5,("smbHome is set to %s\n",homedir));
+ if (!*homedir) {
+ pstrcpy(homedir, lp_logon_home());
+ DEBUG(5,("smbHome fell back to %s\n",homedir));
+ }
+
+ get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
+ DEBUG(5,("scriptPath is set to %s\n",logon_script));
+ if (!*logon_script) {
+ pstrcpy(logon_script, lp_logon_script());
+ DEBUG(5,("scriptPath fell back to %s\n",logon_script));
+ }
+
+ get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
+ DEBUG(5,("profilePath is set to %s\n",profile_path));
+ if (!*profile_path) {
+ pstrcpy(profile_path, lp_logon_path());
+ DEBUG(5,("profilePath fell back to %s\n",profile_path));
+ }
+
+ get_single_attribute(ldap_struct, entry, "description", acct_desc);
+ get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user_rid = (uint32)strtol(temp, NULL, 10);
+ get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
+ group_rid = (uint32)strtol(temp, NULL, 10);
+
+
+ /* These values MAY be in LDAP, but they can also be retrieved through
+ * sys_getpw*() which is how we're doing it (if you use nss_ldap, then
+ * these values will be stored in LDAP as well, but if not, we want the
+ * local values to override the LDAP for this anyway
+ * homeDirectory attribute
+ */
+ sys_user = sys_getpwnam(username);
+ if (sys_user == NULL)
+ return False;
+
+
+ /* FIXME: hours stuff should be cleaner */
+ logon_divs = 168;
+ hours_len = 21;
+ hours = malloc(sizeof(hours) * hours_len);
+ memset(hours, 0xff, hours_len);
+
+ get_single_attribute (ldap_struct, entry, "lmPassword", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "ntPassword", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "acctFlags", temp);
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0)
+ acct_ctrl |= ACB_NORMAL;
+
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_logons_divs(sampass, logon_divs);
+
+ pdb_set_uid(sampass, &sys_user->pw_uid);
+ pdb_set_gid(sampass, &sys_user->pw_gid);
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+
+ pdb_set_username(sampass, username);
+
+ pdb_set_domain(sampass, domain);
+ pdb_set_nt_username(sampass, nt_username);
+
+ pdb_set_fullname(sampass, fullname);
+
+ pdb_set_logon_script(sampass, logon_script);
+ pdb_set_profile_path(sampass, profile_path);
+ pdb_set_dir_drive(sampass, dir_drive);
+ pdb_set_homedir(sampass, homedir);
+ pdb_set_acct_desc(sampass, acct_desc);
+ pdb_set_workstations(sampass, workstations);
+ pdb_set_munged_dial(sampass, munged_dial);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd))
+ return False;
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd))
+ return False;
+
+ /* pdb_set_unknown_3(sampass, unknown3); */
+ /* pdb_set_unknown_5(sampass, unknown5); */
+ /* pdb_set_unknown_6(sampass, unknown6); */
+
+ pdb_set_hours(sampass, hours);
+
+ return True;
+}
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_buffer_from_sam in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_ldap_from_sam (LDAPMod *** mods, int ldap_state, const SAM_ACCOUNT * sampass)
+{
+ pstring temp;
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+
+
+ make_a_mod(mods, ldap_state, "uid", pdb_get_username(sampass));
+ DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ /* not sure about using this for the nt_username */
+ make_a_mod(mods, ldap_state, "sambaDomain", pdb_get_domain(sampass));
+
+ slprintf(temp, sizeof(temp) - 1, "%i", pdb_get_uid(sampass));
+ make_a_mod(mods, ldap_state, "uidNumber", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdLastSet", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
+ make_a_mod(mods, ldap_state, "logonTime", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
+ make_a_mod(mods, ldap_state, "logoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
+ make_a_mod(mods, ldap_state, "kickoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdCanChange", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdMustChange", temp);
+
+ /* displayName, cn, and gecos should all be the same
+ * most easily accomplished by giving them the same OID
+ * gecos isn't set here b/c it should be handled by the
+ * add-user script
+ */
+
+ make_a_mod(mods, ldap_state, "displayName", pdb_get_fullname(sampass));
+ make_a_mod(mods, ldap_state, "cn", pdb_get_fullname(sampass));
+
+ make_a_mod(mods, ldap_state, "smbHome", pdb_get_homedir(sampass));
+ make_a_mod(mods, ldap_state, "homeDrive", pdb_get_dirdrive(sampass));
+ make_a_mod(mods, ldap_state, "scriptPath", pdb_get_logon_script(sampass));
+ make_a_mod(mods, ldap_state, "profilePath", pdb_get_profile_path(sampass));
+ make_a_mod(mods, ldap_state, "description", pdb_get_acct_desc(sampass));
+ make_a_mod(mods, ldap_state, "userWorkstations", pdb_get_workstations(sampass));
+
+ if ( !sampass->user_rid)
+ sampass->user_rid = pdb_uid_to_user_rid(pdb_get_uid(sampass));
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->user_rid);
+ make_a_mod(mods, ldap_state, "rid", temp);
+
+ if ( !sampass->group_rid) {
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pdb_get_gid(sampass), &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &sampass->group_rid);
+ }
+ else
+ sampass->group_rid = pdb_gid_to_group_rid(pdb_get_gid(sampass));
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->group_rid);
+ make_a_mod(mods, ldap_state, "primaryGroupID", temp);
+
+ /* FIXME: Hours stuff goes in LDAP */
+ pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_state, "lmPassword", temp);
+ pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_state, "ntPassword", temp);
+ make_a_mod (mods, ldap_state, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ return True;
+}
+
+/**********************************************************************
+Connect to LDAP server for password enumeration
+*********************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ int rc;
+ pstring filter;
+
+ if (!ldap_open_connection(&global_ldap_ent.ldap_struct))
+ {
+ return False;
+ }
+ if (!ldap_connect_system(global_ldap_ent.ldap_struct))
+ {
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ return False;
+ }
+
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", "*", sizeof(pstring));
+
+ rc = ldap_search_s(global_ldap_ent.ldap_struct, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0,
+ &global_ldap_ent.result);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
+ DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+ ldap_msgfree(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ return False;
+ }
+
+ DEBUG(2, ("pdb_setsampwent: %d entries in the base!\n",
+ ldap_count_entries(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result)));
+
+ global_ldap_ent.entry = ldap_first_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result);
+
+ return True;
+}
+
+/**********************************************************************
+End enumeration of the LDAP password list
+*********************************************************************/
+void pdb_endsampwent(void)
+{
+ if (global_ldap_ent.ldap_struct && global_ldap_ent.result)
+ {
+ ldap_msgfree(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ }
+}
+
+/**********************************************************************
+Get the next entry in the LDAP password database
+*********************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT * user)
+{
+ if (!global_ldap_ent.entry)
+ return False;
+
+ global_ldap_ent.entry = ldap_next_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+
+ if (global_ldap_ent.entry != NULL)
+ {
+ return init_sam_from_ldap(user, global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+ }
+ return False;
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by username
+*********************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_name(ldap_struct, sname, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this user [%s] count=%d\n", sname,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by rid
+*********************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_rid(ldap_struct, rid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this rid [%i] count=%d\n", rid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+ Get SAM_ACCOUNT entry from LDAP by uid
+*********************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_uid(ldap_struct, uid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this uid [%i] count=%d\n", uid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+
+/**********************************************************************
+Delete entry from LDAP for username
+*********************************************************************/
+BOOL pdb_delete_sam_account(const char *sname)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *entry;
+ LDAPMessage *result;
+
+ if (!ldap_open_connection (&ldap_struct))
+ return False;
+
+ DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
+
+ if (!ldap_connect_system (ldap_struct)) {
+ ldap_unbind (ldap_struct);
+ DEBUG(0, ("Failed to delete user %s from LDAP.\n", sname));
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name (ldap_struct, sname, &result);
+ if (ldap_count_entries (ldap_struct, result) == 0) {
+ DEBUG (0, ("User doesn't exit!\n"));
+ ldap_msgfree (result);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry (ldap_struct, result);
+ dn = ldap_get_dn (ldap_struct, entry);
+
+ rc = ldap_delete_s (ldap_struct, dn);
+
+ ldap_memfree (dn);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error;
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG (0,("failed to delete user with uid = %s with: %s\n\t%s\n",
+ sname, ldap_err2string (rc), ld_error));
+ free (ld_error);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ DEBUG (2,("successfully deleted uid = %s from the LDAP database\n", sname));
+ ldap_unbind (ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Update SAM_ACCOUNT
+*********************************************************************/
+BOOL pdb_update_sam_account(const SAM_ACCOUNT * newpwd, BOOL override)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ LDAPMod **mods;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ return False;
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name(ldap_struct,
+ pdb_get_username(newpwd), &result);
+
+ if (ldap_count_entries(ldap_struct, result) == 0)
+ {
+ DEBUG(0, ("No user to modify!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ init_ldap_from_sam(&mods, LDAP_MOD_REPLACE, newpwd);
+
+ entry = ldap_first_entry(ldap_struct, result);
+ dn = ldap_get_dn(ldap_struct, entry);
+
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+ ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,
+ ("failed to modify user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string(rc),
+ ld_error));
+ free(ld_error);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,
+ ("successfully modified uid = %s in the LDAP database\n",
+ pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Add SAM_ACCOUNT to LDAP
+*********************************************************************/
+BOOL pdb_add_sam_account(const SAM_ACCOUNT * newpwd)
+{
+ int rc;
+ pstring filter;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ pstring dn;
+ LDAPMod **mods;
+ int ldap_op = LDAP_MOD_ADD;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (pdb_get_username(newpwd) != NULL) {
+ slprintf (dn, sizeof (dn) - 1, "uid=%s,%s",
+ pdb_get_username(newpwd), lp_ldap_suffix ());
+ }
+ else
+ {
+ return False;
+ }
+
+
+ rc = ldap_search_one_user_by_name (ldap_struct, pdb_get_username(newpwd), &result);
+
+ if (ldap_count_entries(ldap_struct, result) != 0)
+ {
+ DEBUG(0,("User already in the base, with samba properties\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_msgfree(result);
+
+ slprintf (filter, sizeof (filter) - 1, "uid=%s", pdb_get_username(newpwd));
+ rc = ldap_search_one_user(ldap_struct, filter, &result);
+ if (ldap_count_entries(ldap_struct, result) == 1)
+ {
+ char *tmp;
+ LDAPMessage *entry;
+ DEBUG(3,("User exists without samba properties: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (ldap_struct, result);
+ tmp = ldap_get_dn (ldap_struct, entry);
+ slprintf (dn, sizeof (dn) - 1, "%s", tmp);
+ ldap_memfree (tmp);
+ }
+ else
+ {
+ DEBUG (3, ("More than one user with that uid exists: bailing out!\n"));
+ return False;
+ }
+
+ ldap_msgfree(result);
+
+ init_ldap_from_sam(&mods, ldap_op, newpwd);
+ make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
+
+ if (ldap_op == LDAP_MOD_REPLACE) {
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+ }
+ else {
+ rc = ldap_add_s(ldap_struct, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(0,("failed to modify user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string (rc), ld_error));
+ free(ld_error);
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+#else
+void dummy_function(void);
+void
+dummy_function (void)
+{
+} /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/pdb_nisplus.c b/source/passdb/pdb_nisplus.c
new file mode 100644
index 00000000000..2820fa14142
--- /dev/null
+++ b/source/passdb/pdb_nisplus.c
@@ -0,0 +1,1409 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
+ * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_NISPLUS_SAM
+
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
+
+#if defined(GROUP)
+#undef GROUP
+#endif
+
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
+
+#endif
+
+#include <rpcsvc/nis.h>
+
+extern int DEBUGLEVEL;
+
+struct nisp_enum_info
+{
+ nis_result *result;
+ int enum_entry;
+};
+
+static struct nisp_enum_info global_nisp_ent;
+static VOLATILE sig_atomic_t gotalarm;
+
+/***************************************************************
+
+ the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
+
+ name=S,nogw=r
+ uid=S,nogw=r
+ user_rid=S,nogw=r
+ smb_grpid=,nw+r
+ group_rid=,nw+r
+ acb=,nw+r
+
+ lmpwd=C,nw=,g=r,o=rm
+ ntpwd=C,nw=,g=r,o=rm
+
+ logon_t=,nw+r
+ logoff_t=,nw+r
+ kick_t=,nw+r
+ pwdlset_t=,nw+r
+ pwdlchg_t=,nw+r
+ pwdmchg_t=,nw+r
+
+ full_name=,nw+r
+ home_dir=,nw+r
+ dir_drive=,nw+r
+ logon_script=,nw+r
+ profile_path=,nw+r
+ acct_desc=,nw+r
+ workstations=,nw+r
+
+ hours=,nw+r
+
+****************************************************************/
+
+#define NPF_NAME 0
+#define NPF_UID 1
+#define NPF_USER_RID 2
+#define NPF_SMB_GRPID 3
+#define NPF_GROUP_RID 4
+#define NPF_ACB 5
+#define NPF_LMPWD 6
+#define NPF_NTPWD 7
+#define NPF_LOGON_T 8
+#define NPF_LOGOFF_T 9
+#define NPF_KICK_T 10
+#define NPF_PWDLSET_T 11
+#define NPF_PWDCCHG_T 12
+#define NPF_PWDMCHG_T 13
+#define NPF_FULL_NAME 14
+#define NPF_HOME_DIR 15
+#define NPF_DIR_DRIVE 16
+#define NPF_LOGON_SCRIPT 17
+#define NPF_PROFILE_PATH 18
+#define NPF_ACCT_DESC 19
+#define NPF_WORKSTATIONS 20
+#define NPF_HOURS 21
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ make_nisname_from_user_rid
+ ****************************************************************/
+static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_uid
+ ****************************************************************/
+static char *make_nisname_from_uid(int uid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_name
+ ****************************************************************/
+static char *make_nisname_from_name(const char *user_name, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
+ safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/*************************************************************************
+ gets a NIS+ attribute
+ *************************************************************************/
+static void get_single_attribute(const nis_object *new_obj, int col,
+ char *val, int len)
+{
+ int entry_len;
+
+ if (new_obj == NULL || val == NULL) return;
+
+ entry_len = ENTRY_LEN(new_obj, col);
+ if (len > entry_len)
+ {
+ len = entry_len;
+ }
+
+ safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ object.
+ ************************************************************************/
+static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, const nis_object *obj)
+{
+ char *ptr;
+ pstring full_name; /* this must be translated to dos code page */
+ pstring acct_desc; /* this must be translated to dos code page */
+ pstring home_dir; /* set default value from smb.conf for user */
+ pstring home_drive; /* set default value from smb.conf for user */
+ pstring logon_script; /* set default value from smb.conf for user */
+ pstring profile_path; /* set default value from smb.conf for user */
+ pstring hours;
+ int hours_len;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+
+ /*
+ * time values. note: this code assumes 32bit time_t!
+ */
+
+ /* Don't change these timestamp settings without a good reason. They are
+ important for NT member server compatibility. */
+
+ pdb_set_logon_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGON_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_logoff_time(pw_buf, get_time_t_max());
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGOFF_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_kickoff_time(pw_buf, get_time_t_max());
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_KICK_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_last_set_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDLSET_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_can_change_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDCCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDMCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ /* string values */
+ pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
+ pdb_set_domain(pw_buf, lp_workgroup());
+ /* pdb_set_nt_username() -- cant set it here... */
+
+ get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
+ unix_to_dos(full_name, True);
+ pdb_set_fullname(pw_buf, full_name);
+
+ pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
+ NPF_ACB)));
+
+ get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
+ unix_to_dos(acct_desc, True);
+ pdb_set_acct_desc(pw_buf, acct_desc);
+
+ pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
+ pdb_set_munged_dial(pw_buf, NULL);
+
+ pdb_set_uid(pw_buf, &atoi(ENTRY_VAL(obj, NPF_UID)));
+ pdb_set_gid(pw_buf, &atoi(ENTRY_VAL(obj, NPF_SMB_GRPID)));
+ pdb_set_user_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_USER_RID)));
+ pdb_set_group_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_GROUP_RID)));
+
+ /* values, must exist for user */
+ if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
+
+ get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
+ if( !(home_dir && *home_dir) )
+ pstrcpy(home_dir, lp_logon_home());
+ pdb_set_homedir(pw_buf, home_dir);
+
+ get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
+ if( !(home_drive && *home_drive) )
+ pstrcpy(home_drive, lp_logon_drive());
+ pdb_set_dir_drive(pw_buf, home_drive);
+
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
+ sizeof(pstring));
+ if( !(logon_script && *logon_script) )
+ pstrcpy(logon_script, lp_logon_script());
+ pdb_set_logon_script(pw_buf, logon_script);
+
+ get_single_attribute(obj, NPF_PROFILE_PATH, profile_path,
+ sizeof(pstring));
+ if( !(profile_path && *profile_path) )
+ pstrcpy(profile_path, lp_logon_path());
+ pdb_set_profile_path(pw_buf, profile_path);
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS);
+ }
+
+ /* Check the lanman password column. */
+ ptr = (char *)ENTRY_VAL(obj, NPF_LMPWD);
+ pdb_set_lanman_passwd(pw_buf, NULL);
+
+ if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
+ pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
+ } else {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
+ DEBUG(0, ("malformed LM pwd entry: %s.\n",
+ pdb_get_username(pw_buf)));
+ return False;
+ }
+ pdb_set_lanman_passwd(pw_buf, smbpwd);
+ }
+
+ /* Check the NT password column. */
+ ptr = ENTRY_VAL(obj, NPF_NTPWD);
+ pdb_set_nt_passwd(pw_buf, NULL);
+
+ if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
+ strncasecmp(ptr, "NO PASSWORD", 11)) {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
+ DEBUG(0, ("malformed NT pwd entry: uid = %d.\n",
+ pdb_get_uid(pw_buf)));
+ return False;
+ }
+ pdb_set_nt_passwd(pw_buf, smbntpwd);
+ }
+
+ pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
+ pdb_set_logons_divs(pw_buf, 168); /* hours per week */
+
+ if( (hours_len = ENTRY_LEN(obj, NPF_HOURS)) == 21 ) {
+ memcpy(hours, ENTRY_VAL(obj, NPF_HOURS), hours_len);
+ } else {
+ hours_len = 21; /* 21 times 8 bits = 168 */
+ /* available at all hours */
+ memset(hours, 0xff, hours_len);
+ }
+ pdb_set_hours_len(pw_buf, hours_len);
+ pdb_set_hours(pw_buf, hours);
+
+ pdb_set_unknown_5(pw_buf, 0x00020000); /* don't know */
+ pdb_set_unknown_6(pw_buf, 0x000004ec); /* don't know */
+
+ return True;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisresult(SAM_ACCOUNT *pw_buf, const nis_result *result)
+{
+ if (pw_buf == NULL || result == NULL) return False;
+
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(0, ("NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("WARNING: Multiple entries for user in NIS+ table!\n"));
+ }
+
+ /* Grab the first hit. */
+ return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
+}
+
+/*************************************************************************
+ sets a NIS+ attribute
+ *************************************************************************/
+static void set_single_attribute(nis_object *new_obj, int col,
+ const char *val, int len, int flags)
+{
+ if (new_obj == NULL) return;
+
+ ENTRY_VAL(new_obj, col) = val;
+ ENTRY_LEN(new_obj, col) = len+1;
+
+ if (flags != 0)
+ {
+ new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
+ }
+}
+
+/***************************************************************
+ copy or modify nis object. this object is used to add or update
+ nisplus table entry.
+ ****************************************************************/
+static BOOL init_nisp_from_sam(nis_object *obj, const SAM_ACCOUNT *sampass,
+ nis_object *old)
+{
+ /*
+ * Fill nis_object for entry add or update.
+ * if we are updateing, we have to find out differences and set
+ * EN_MODIFIED flag. also set need_to_modify to trigger
+ * nis_modify_entry() call in pdb_update_sam_account().
+ *
+ * TODO:
+ * get data from SAM
+ * if (modify) get data from nis_object, compare and store if
+ * different + set EN_MODIFIED and need_to_modify
+ * else
+ * store
+ */
+ BOOL need_to_modify = False;
+ const char *name = pdb_get_username(sampass); /* from SAM */
+ /* these must be static or allocate and free entry columns! */
+ static fstring uid; /* from SAM */
+ static fstring user_rid; /* from SAM */
+ static fstring gid; /* from SAM */
+ static fstring group_rid; /* from SAM */
+ char *acb; /* from SAM */
+ static fstring smb_passwd; /* from SAM */
+ static fstring smb_nt_passwd; /* from SAM */
+ static fstring logon_t; /* from SAM */
+ static fstring logoff_t; /* from SAM */
+ static fstring kickoff_t; /* from SAM */
+ static fstring pwdlset_t; /* from SAM */
+ static fstring pwdlchg_t; /* from SAM */
+ static fstring pwdmchg_t; /* from SAM */
+ static fstring full_name; /* from SAM */
+ static fstring acct_desc; /* from SAM */
+ static char empty[1]; /* just an empty string */
+
+ slprintf(uid, sizeof(uid)-1, "%u", pdb_get_uid(sampass));
+ slprintf(user_rid, sizeof(user_rid)-1, "%u",
+ pdb_get_user_rid(sampass)? pdb_get_user_rid(sampass):
+ pdb_uid_to_user_rid(pdb_get_uid(sampass)));
+ slprintf(gid, sizeof(gid)-1, "%u", pdb_get_gid(sampass));
+
+ {
+ uint32 rid;
+ GROUP_MAP map;
+
+ rid=pdb_get_group_rid(sampass);
+
+ if (rid==0) {
+ if (get_group_map_from_gid(pdb_get_gid(sampass), &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ } else
+ rid=pdb_gid_to_group_rid(pdb_get_gid(sampass));
+ }
+
+ slprintf(group_rid, sizeof(group_rid)-1, "%u", rid);
+ }
+
+ acb = pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN);
+ pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ slprintf(logon_t, 13, "LNT-%08X",
+ (uint32)pdb_get_logon_time(sampass));
+ slprintf(logoff_t, 13, "LOT-%08X",
+ (uint32)pdb_get_logoff_time(sampass));
+ slprintf(kickoff_t, 13, "KOT-%08X",
+ (uint32)pdb_get_kickoff_time(sampass));
+ slprintf(pwdlset_t, 13, "LCT-%08X",
+ (uint32)pdb_get_pass_last_set_time(sampass));
+ slprintf(pwdlchg_t, 13, "CCT-%08X",
+ (uint32)pdb_get_pass_can_change_time(sampass));
+ slprintf(pwdmchg_t, 13, "MCT-%08X",
+ (uint32)pdb_get_pass_must_change_time(sampass));
+ safe_strcpy(full_name, pdb_get_fullname(sampass), sizeof(full_name)-1);
+ dos_to_unix(full_name, True);
+ safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
+ dos_to_unix(acct_desc, True);
+
+ if( old ) {
+ /* name */
+ if(strcmp(ENTRY_VAL(old, NPF_NAME), name))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NAME, name, strlen(name),
+ EN_MODIFIED);
+ }
+
+
+ /* uid */
+ if(pdb_get_uid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_UID) || strcmp(ENTRY_VAL(old, NPF_UID), uid))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_UID, uid,
+ strlen(uid), EN_MODIFIED);
+ }
+ }
+
+ /* user_rid */
+ if (pdb_get_user_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_USER_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_USER_RID), user_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), EN_MODIFIED);
+ }
+ }
+
+ /* smb_grpid */
+ if (pdb_get_gid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_SMB_GRPID) ||
+ strcmp(ENTRY_VAL(old, NPF_SMB_GRPID), gid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_SMB_GRPID, gid,
+ strlen(gid), EN_MODIFIED);
+ }
+ }
+
+ /* group_rid */
+ if (pdb_get_group_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_GROUP_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_GROUP_RID), group_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), EN_MODIFIED);
+ }
+ }
+
+ /* acb */
+ if (!ENTRY_VAL(old, NPF_ACB) ||
+ strcmp(ENTRY_VAL(old, NPF_ACB), acb)) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), EN_MODIFIED);
+ }
+
+ /* lmpwd */
+ if(!ENTRY_VAL(old, NPF_LMPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_LMPWD), smb_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* ntpwd */
+ if(!ENTRY_VAL(old, NPF_NTPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_NTPWD), smb_nt_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* logon_t */
+ if( pdb_get_logon_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGON_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGON_T), logon_t ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), EN_MODIFIED);
+ }
+
+ /* logoff_t */
+ if( pdb_get_logoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGOFF_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGOFF_T), logoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), EN_MODIFIED);
+ }
+
+ /* kick_t */
+ if( pdb_get_kickoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_KICK_T) ||
+ strcmp(ENTRY_VAL(old, NPF_KICK_T), kickoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t), EN_MODIFIED);
+ }
+
+ /* pwdlset_t */
+ if( pdb_get_pass_last_set_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDLSET_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDLSET_T), pwdlset_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), EN_MODIFIED);
+ }
+
+ /* pwdlchg_t */
+ if( pdb_get_pass_can_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDCCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDCCHG_T), pwdlchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), EN_MODIFIED);
+ }
+
+ /* pwdmchg_t */
+ if( pdb_get_pass_must_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDMCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDMCHG_T), pwdmchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), EN_MODIFIED);
+ }
+
+ /* full_name */
+ /* must support set, unset and change */
+ if ( (pdb_get_fullname(sampass) &&
+ !ENTRY_VAL(old, NPF_FULL_NAME)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ !pdb_get_fullname(sampass)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ pdb_get_fullname(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_FULL_NAME), full_name ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_FULL_NAME, full_name,
+ strlen(full_name), EN_MODIFIED);
+ }
+
+ /* home_dir */
+ /* must support set, unset and change */
+ if( (pdb_get_homedir(sampass) &&
+ !ENTRY_VAL(old, NPF_HOME_DIR)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ !pdb_get_homedir(sampass)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ pdb_get_homedir(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_HOME_DIR),
+ pdb_get_homedir(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_HOME_DIR, pdb_get_homedir(sampass),
+ strlen(pdb_get_homedir(sampass)), EN_MODIFIED);
+ }
+
+ /* dir_drive */
+ /* must support set, unset and change */
+ if( (pdb_get_dirdrive(sampass) &&
+ !ENTRY_VAL(old, NPF_DIR_DRIVE)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ !pdb_get_dirdrive(sampass)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ pdb_get_dirdrive(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_DIR_DRIVE),
+ pdb_get_dirdrive(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_DIR_DRIVE, pdb_get_dirdrive(sampass),
+ strlen(pdb_get_dirdrive(sampass)), EN_MODIFIED);
+ }
+
+ /* logon_script */
+ /* must support set, unset and change */
+ if( (pdb_get_logon_script(sampass) &&
+ !ENTRY_VAL(old, NPF_LOGON_SCRIPT) ||
+ (ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ !pdb_get_logon_script(sampass)) ||
+ ( ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ pdb_get_logon_script(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_LOGON_SCRIPT),
+ pdb_get_logon_script(sampass))))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ pdb_get_logon_script(sampass),
+ strlen(pdb_get_logon_script(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* profile_path */
+ /* must support set, unset and change */
+ if( (pdb_get_profile_path(sampass) &&
+ !ENTRY_VAL(old, NPF_PROFILE_PATH)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ !pdb_get_profile_path(sampass)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ pdb_get_profile_path(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_PROFILE_PATH),
+ pdb_get_profile_path(sampass) ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ pdb_get_profile_path(sampass),
+ strlen(pdb_get_profile_path(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* acct_desc */
+ /* must support set, unset and change */
+ if( (pdb_get_acct_desc(sampass) &&
+ !ENTRY_VAL(old, NPF_ACCT_DESC)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ !pdb_get_acct_desc(sampass)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ pdb_get_acct_desc(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_ACCT_DESC), acct_desc ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACCT_DESC, acct_desc,
+ strlen(acct_desc), EN_MODIFIED);
+ }
+
+ /* workstations */
+ /* must support set, unset and change */
+ if ( (pdb_get_workstations(sampass) &&
+ !ENTRY_VAL(old, NPF_WORKSTATIONS) ) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ !pdb_get_workstations(sampass)) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ pdb_get_workstations(sampass)) &&
+ strcmp( ENTRY_VAL(old, NPF_WORKSTATIONS),
+ pdb_get_workstations(sampass))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ pdb_get_workstations(sampass),
+ strlen(pdb_get_workstations(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* hours */
+ if ((pdb_get_hours_len(sampass) != ENTRY_LEN(old, NPF_HOURS)) ||
+ memcmp(pdb_get_hours(sampass), ENTRY_VAL(old, NPF_HOURS),
+ ENTRY_LEN(old, NPF_HOURS))) {
+ need_to_modify = True;
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS, pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, EN_MODIFIED);
+ }
+ } else {
+ const char *homedir, *dirdrive, *logon_script, *profile_path, *workstations;
+
+ *empty = '\0'; /* empty string */
+
+ set_single_attribute(obj, NPF_NAME, name, strlen(name), 0);
+ set_single_attribute(obj, NPF_UID, uid, strlen(uid), 0);
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), 0);
+ set_single_attribute(obj, NPF_SMB_GRPID, gid, strlen(gid), 0);
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), 0);
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), 0);
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), 0);
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t),0);
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), 0);
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), 0);
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), 0);
+ set_single_attribute(obj, NPF_FULL_NAME ,
+ full_name, strlen(full_name), 0);
+
+ if(!(homedir = pdb_get_homedir(sampass)))
+ homedir = empty;
+
+ set_single_attribute(obj, NPF_HOME_DIR,
+ homedir, strlen(homedir), 0);
+
+ if(!(dirdrive = pdb_get_dirdrive(sampass)))
+ dirdrive = empty;
+
+ set_single_attribute(obj, NPF_DIR_DRIVE,
+ dirdrive, strlen(dirdrive), 0);
+
+ if(!(logon_script = pdb_get_logon_script(sampass)))
+ logon_script = empty;
+
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ logon_script, strlen(logon_script), 0);
+
+ if(!(profile_path = pdb_get_profile_path(sampass)))
+ profile_path = empty;
+
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ profile_path, strlen(profile_path), 0);
+
+ set_single_attribute(obj, NPF_ACCT_DESC,
+ acct_desc, strlen(acct_desc), 0);
+
+ if(!(workstations = pdb_get_workstations(sampass)))
+ workstations = empty;
+
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ workstations, strlen(workstations), 0);
+
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS,
+ pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, 0);
+ }
+
+ return need_to_modify;
+}
+
+/***************************************************************
+ calls nis_list, returns results.
+ ****************************************************************/
+static nis_result *nisp_get_nis_list(const char *nis_name, uint_t flags)
+{
+ nis_result *result;
+ int i;
+
+ if( ! flags)
+ flags = FOLLOW_LINKS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP;
+
+ for(i = 0; i<2;i++ ) {
+ alarm(60); /* hopefully ok for long searches */
+ result = nis_list(nis_name, flags,NULL,NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+ if( !(flags & MASTER_ONLY) && NIS_RES_NUMOBJ(result) <= 0 ) {
+ /* nis replicas are not in sync perhaps?
+ * this can happen, if account was just added.
+ */
+ DEBUG(10,("will try master only\n"));
+ nis_freeresult(result);
+ flags |= MASTER_ONLY;
+ } else
+ break;
+ }
+ return result;
+}
+
+/***************************************************************
+ Start to enumerate the nisplus passwd list.
+ ****************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ char *sp, * p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ pdb_endsampwent(); /* just in case */
+ global_nisp_ent.result = nisp_get_nis_list( pfiletmp, 0 );
+ global_nisp_ent.enum_entry = 0;
+ return global_nisp_ent.result != NULL ? True : False;
+}
+
+/***************************************************************
+ End enumeration of the nisplus passwd list.
+****************************************************************/
+void pdb_endsampwent(void)
+{
+ if( global_nisp_ent.result )
+ nis_freeresult(global_nisp_ent.result);
+ global_nisp_ent.result = NULL;
+ global_nisp_ent.enum_entry = 0;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+ *************************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ int enum_entry = (int)(global_nisp_ent.enum_entry);
+ nis_result *result = global_nisp_ent.result;
+
+ if (user==NULL) {
+ DEBUG(0,("SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ if (result == NULL ||
+ enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ(result) - 1))
+ {
+ return False;
+ }
+
+ if(!make_sam_from_nisp_object(user, &NIS_RES_OBJECT(result)[enum_entry]) )
+ {
+ DEBUG(0,("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
+ return False;
+ }
+ (int)(global_nisp_ent.enum_entry)++;
+ return True;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, const char *sname)
+{
+ /* Static buffers we will return. */
+ nis_result *result = NULL;
+ pstring nisname;
+ BOOL ret;
+ char *pfile = lp_smb_passwd_file();
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+ DEBUG(10, ("search by nisname: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+ char *sp, *p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if (!*p)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ nisname = make_nisname_from_user_rid(rid, pfiletmp);
+
+ DEBUG(10, ("search by rid: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+ char *sp, *p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if (!*p)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ nisname = make_nisname_from_uid(uid, pfiletmp);
+
+ DEBUG(10, ("search by uid: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to remove entry from the nisplus smbpasswd table
+ *************************************************************************/
+BOOL pdb_delete_sam_account(const char *sname)
+{
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ nis_result *result, *delresult;
+ nis_object *obj;
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s", sname, obj->zo_name,
+ obj->zo_domain);
+
+ DEBUG(10, ("removing name: %s\n", nisname));
+ delresult = nis_remove_entry(nisname, obj,
+ MASTER_ONLY|REM_MULTIPLE|ALL_RESULTS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+
+ nis_freeresult(result);
+
+ if(delresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(delresult->status)));
+ nis_freeresult(delresult);
+ return False;
+ }
+ nis_freeresult(delresult);
+ return True;
+}
+
+/************************************************************************
+ Routine to add an entry to the nisplus passwd file.
+*************************************************************************/
+BOOL pdb_add_sam_account(const SAM_ACCOUNT * newpwd)
+{
+ int local_user = 0;
+ char *pfile;
+ pstring pfiletmp;
+ char *nisname;
+ nis_result *result = NULL,
+ *tblresult = NULL;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+
+ /*
+ * 1. find user domain.
+ * a. try nis search in passwd.org_dir - if found use domain from result.
+ * b. try getpwnam. this may be needed if user is defined
+ * in /etc/passwd file (or elsewere) and not in passwd.org_dir.
+ * if found, use host default domain.
+ * c. exit with False - no such user.
+ *
+ * 2. add user
+ * a. find smbpasswd table
+ * search pfile in user domain if not found, try host default
+ * domain.
+ * b. smbpasswd domain is found, fill data and add entry.
+ *
+ * pfile should contain ONLY table name, org_dir will be concated.
+ * so, at first we will clear path prefix from pfile, and
+ * then we will use pfiletmp as playground to put together full
+ * nisname string.
+ * such approach will make it possible to specify samba private dir
+ * AND still use NIS+ table. as all domain related data is normally
+ * stored in org_dir.DOMAIN, this should be ok do do.
+ */
+
+ pfile = lp_smb_passwd_file();
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ /*
+ * Check if user is already there.
+ */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ if(pdb_get_username(newpwd) != NULL) {
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ pfiletmp);
+ } else {
+ return False;
+ }
+
+ if(!(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+ if (result->status != NIS_SUCCESS &&
+ result->status != NIS_NOTFOUND) {
+ DEBUG(3, ( "nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
+ {
+ DEBUG(3, ("User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(result); /* no such user, free results */
+
+ /*
+ * check for user in unix password database. we need this to get
+ * domain, where smbpasswd entry should be stored.
+ */
+
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ "passwd.org_dir");
+
+ result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP);
+
+ if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(3, ("nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+
+ if (!sys_getpwnam(pdb_get_username(newpwd))) {
+ /* no such user in system! */
+ return False;
+ }
+ /*
+ * user is defined, but not in passwd.org_dir.
+ */
+ local_user = 1;
+ } else {
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(result)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ nis_freeresult(result); /* not needed any more */
+
+ tblresult = nisp_get_nis_list(pfiletmp,
+ MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ }
+
+ if (local_user || tblresult->status != NIS_SUCCESS)
+ {
+ /*
+ * no user domain or
+ * smbpasswd table not found in user domain, fallback to
+ * default domain.
+ */
+ if (!local_user) /* free previous failed search result */
+ nis_freeresult(tblresult);
+
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ tblresult = nis_lookup(pfiletmp, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ /* still nothing. bail out */
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "nis_lookup failure: %s\n",
+ nis_sperrno(tblresult->status)));
+ return False;
+ }
+ /* we need full name for nis_add_entry() */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(tblresult)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ }
+
+ memset((char *)&new_obj, 0, sizeof (new_obj));
+ /* fill entry headers */
+ /* we do not free these. */
+ new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
+ new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
+ new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
+ new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
+ /* uints */
+ new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
+ new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
+
+ new_obj.zo_data.zo_type = ENTRY_OBJ;
+ new_obj.EN_data.en_type =
+ NIS_RES_OBJECT(tblresult)->TA_data.ta_type;
+
+ ta_maxcol = NIS_RES_OBJECT(tblresult)->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(tblresult);
+ return False;
+ }
+
+ memset((char *)ecol, 0, ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ init_nisp_from_sam(&new_obj, newpwd, NULL);
+
+ DEBUG(10, ( "add NIS+ entry: %s\n", nisname));
+ result = nis_add_entry(pfiletmp, &new_obj, 0);
+
+ free(ecol); /* free allocated entry space */
+
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to modify the nisplus passwd entry.
+************************************************************************/
+BOOL pdb_update_sam_account(const SAM_ACCOUNT * newpwd, BOOL override)
+{
+ nis_result *result, *addresult;
+ nis_object *obj;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir",
+ pdb_get_username(newpwd), pfile);
+
+ DEBUG(10, ("search by name: %s\n", nisname));
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ DEBUG(6,("entry found in %s\n", obj->zo_domain));
+
+ /* we must create new stub object with EN_MODIFIED flag.
+ this is because obj from result is going to be freed and
+ we do not want to break it or cause memory leaks or corruption.
+ */
+
+ memmove((char *)&new_obj, obj, sizeof (new_obj));
+ ta_maxcol = obj->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ memmove((char *)ecol, obj->EN_data.en_cols.en_cols_val,
+ ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ if ( init_nisp_from_sam(&new_obj, newpwd, obj) == True ) {
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s",
+ pdb_get_username(newpwd), pfile, obj->zo_domain);
+
+ DEBUG(10, ("NIS+ table update: %s\n", nisname));
+ addresult =
+ nis_modify_entry(nisname, &new_obj,
+ MOD_SAMEOBJ | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ if(addresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ free(ecol);
+ return False;
+ }
+
+ DEBUG(6,("password changed\n"));
+ nis_freeresult(addresult);
+ } else {
+ DEBUG(6,("nothing to change!\n"));
+ }
+
+ free(ecol);
+ nis_freeresult(result);
+
+ return True;
+}
+
+#else
+ void nisplus_dummy_function(void);
+ void nisplus_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_NISPLUSSAM */
+
diff --git a/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c
new file mode 100644
index 00000000000..9cfad2540c4
--- /dev/null
+++ b/source/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1545 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_SMBPASSWD_SAM
+
+
+/*
+ smb_passwd is analogous to sam_passwd used everywhere
+ else. However, smb_passwd is limited to the information
+ stored by an smbpasswd entry
+ */
+
+struct smb_passwd
+{
+ uid_t smb_userid; /* this is actually the unix uid_t */
+ const char *smb_name; /* username string */
+
+ const unsigned char *smb_passwd; /* Null if no password */
+ const unsigned char *smb_nt_passwd; /* Null if no password */
+
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ time_t pass_last_set_time; /* password last set time */
+};
+
+
+extern struct passdb_ops pdb_ops;
+
+/* used for maintain locks on the smbpasswd file */
+static int pw_file_lock_depth;
+static void *global_vp;
+
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ if(*plock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ (*plock_depth)++;
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_unlock(int fd, int *plock_depth)
+{
+ BOOL ret=True;
+
+ if(*plock_depth == 1)
+ ret = do_file_lock(fd, 5, F_UNLCK);
+
+ if (*plock_depth > 0)
+ (*plock_depth)--;
+
+ if(!ret)
+ DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+
+/**************************************************************
+ Intialize a smb_passwd struct
+ *************************************************************/
+
+static void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL)
+ return;
+ ZERO_STRUCTP (user);
+
+ user->pass_last_set_time = (time_t)0;
+}
+
+/***************************************************************
+ Internal fn to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module. Checks for atomic
+ rename of smbpasswd file on update or create once the lock has
+ been granted to prevent race conditions. JRA.
+****************************************************************/
+
+static void *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
+{
+ FILE *fp = NULL;
+ const char *open_mode = NULL;
+ int race_loop = 0;
+ int lock_type = F_RDLCK;
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+
+ switch(type) {
+ case PWF_READ:
+ open_mode = "rb";
+ lock_type = F_RDLCK;
+ break;
+ case PWF_UPDATE:
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ case PWF_CREATE:
+ /*
+ * Ensure atomic file creation.
+ */
+ {
+ int i, fd = -1;
+
+ for(i = 0; i < 5; i++) {
+ if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
+ break;
+ sys_usleep(200); /* Spin, spin... */
+ }
+ if(fd == -1) {
+ DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
+ return NULL;
+ }
+ close(fd);
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ }
+ }
+
+ for(race_loop = 0; race_loop < 5; race_loop++) {
+ DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+ if((fp = sys_fopen(pfile, open_mode)) == NULL) {
+ DEBUG(2, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
+ return NULL;
+ }
+
+ if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
+ fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Only check for replacement races on update or create.
+ * For read we don't mind if the data is one record out of date.
+ */
+
+ if(type == PWF_READ) {
+ break;
+ } else {
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ /*
+ * Avoid the potential race condition between the open and the lock
+ * by doing a stat on the filename and an fstat on the fd. If the
+ * two inodes differ then someone did a rename between the open and
+ * the lock. Back off and try the open again. Only do this 5 times to
+ * prevent infinate loops. JRA.
+ */
+
+ if (sys_stat(pfile,&sbuf1) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (sys_fstat(fileno(fp),&sbuf2) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if( sbuf1.st_ino == sbuf2.st_ino) {
+ /* No race. */
+ break;
+ }
+
+ /*
+ * Race occurred - back off and try again...
+ */
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ }
+ }
+
+ if(race_loop == 5) {
+ DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+ /* Make sure it is only rw by the owner */
+ if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+ DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
+Error was %s\n.", pfile, strerror(errno) ));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* We have a lock on the file. */
+ return (void *)fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+static void endsmbfilepwent(void *vp, int *lock_depth)
+{
+ FILE *fp = (FILE *)vp;
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+
+static struct smb_passwd *getsmbfilepwent(void *vp)
+{
+ /* Static buffers we will return. */
+ static struct smb_passwd pw_buf;
+ static pstring user_name;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+ FILE *fp = (FILE *)vp;
+ char linebuf[256];
+ unsigned char c;
+ unsigned char *p;
+ long uidval;
+ size_t linebuf_len;
+
+ if(fp == NULL) {
+ DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pdb_init_smb(&pw_buf);
+
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, 256, fp);
+ if (ferror(fp)) {
+ return NULL;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ if ((linebuf_len = strlen(linebuf)) == 0)
+ continue;
+
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n')
+ break;
+ }
+ } else
+ linebuf[linebuf_len - 1] = '\0';
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+ break;
+ }
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ * [Account type] is an ascii encoding of the type of account.
+ * LCT-(8 hex digits) is the time_t value of the last change time.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+ continue;
+ }
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+ continue;
+ }
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+
+ p++; /* Go past ':' */
+
+ if(*p == '-') {
+ DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
+ continue;
+ }
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
+ continue;
+ }
+
+ uidval = atoi((char *) p);
+
+ while (*p && isdigit(*p))
+ p++;
+
+ if (*p != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
+ continue;
+ }
+
+ pw_buf.smb_name = user_name;
+ pw_buf.smb_userid = uidval;
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+
+ /* Skip the ':' */
+ p++;
+
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
+ pw_buf.smb_nt_passwd = NULL;
+ pw_buf.smb_passwd = NULL;
+ pw_buf.acct_ctrl |= ACB_DISABLED;
+ return &pw_buf;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
+ continue;
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
+ continue;
+ }
+
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+ pw_buf.smb_passwd = NULL;
+ pw_buf.acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (!pdb_gethexpwd((char *)p, smbpwd)) {
+ DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
+ continue;
+ }
+ pw_buf.smb_passwd = smbpwd;
+ }
+
+ /*
+ * Now check if the NT compatible password is
+ * available.
+ */
+ pw_buf.smb_nt_passwd = NULL;
+
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if(pdb_gethexpwd((char *)p,smbntpwd))
+ pw_buf.smb_nt_passwd = smbntpwd;
+ }
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+ }
+
+ DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+ user_name, uidval));
+
+ if (*p == '[')
+ {
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+ pw_buf.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+ /* Must have some account type set. */
+ if(pw_buf.acct_ctrl == 0)
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
+ /* Now try and get the last change time. */
+ if(end_p)
+ p = end_p + 1;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
+ pw_buf.acct_ctrl &= ~ACB_NORMAL;
+ pw_buf.acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ return &pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Create a new smbpasswd entry - malloced space returned.
+*************************************************************************/
+
+static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
+{
+ int new_entry_length;
+ char *new_entry;
+ char *p;
+ int i;
+
+ new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
+
+ if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
+ DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
+ return NULL;
+ }
+
+ slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
+ p = &new_entry[strlen(new_entry)];
+
+ if(newpwd->smb_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
+ }
+ } else {
+ i=0;
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ if(newpwd->smb_nt_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ /* Add the account encoding and the last change time. */
+ slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
+ pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)newpwd->pass_last_set_time);
+
+ return new_entry;
+}
+
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static BOOL add_smbfilepwd_entry(const struct smb_passwd *newpwd)
+{
+ char *pfile = lp_smb_passwd_file();
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ int wr_len;
+ int fd;
+ size_t new_entry_length;
+ char *new_entry;
+ SMB_OFF_T offpos;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &pw_file_lock_depth);
+ }
+
+ if (fp == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(fp)) != NULL)
+ {
+ if (strequal(newpwd->smb_name, pwd->smb_name))
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+ }
+
+ /* Ok - entry doesn't exist. We can add it */
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ /*
+ * The add user write needs to be atomic - so get the fd from
+ * the fp and do a raw write() call.
+ */
+ fd = fileno(fp);
+
+ if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
+ fd, new_entry_length, new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
+Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
+
+ /* Remove the entry we just wrote. */
+ if(sys_ftruncate(fd, offpos) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ newpwd->smb_name, strerror(errno)));
+ }
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return True;
+}
+
+/************************************************************************
+ Routine to search the smbpasswd file for an entry matching the username.
+ and then modify its password entry. We can't use the startsmbpwent()/
+ getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+************************************************************************/
+
+static BOOL mod_smbfilepwd_entry(const struct smb_passwd* pwd, BOOL override)
+{
+ /* Static buffers we will return. */
+ static pstring user_name;
+
+ char linebuf[256];
+ char readbuf[1024];
+ unsigned char c;
+ fstring ascii_p16;
+ fstring encode_bits;
+ unsigned char *p = NULL;
+ size_t linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ char *pfile = lp_smb_passwd_file();
+ BOOL found_entry = False;
+ BOOL got_pass_last_set_time = False;
+
+ SMB_OFF_T pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile) {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, "r+");
+
+ if (fp == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ lockfd = fileno(fp);
+
+ if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ pwd_seekpos = sys_ftell(fp);
+
+ linebuf[0] = '\0';
+
+ fgets(linebuf, sizeof(linebuf), fp);
+ if (ferror(fp)) {
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+
+ if (p == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name)) {
+ found_entry = True;
+ break;
+ }
+ }
+
+ if (!found_entry) {
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ while (*p && isdigit(*p))
+ p++;
+ if (*p != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+ p++;
+
+ /* Record exact password position */
+ pwd_seekpos += PTR_DIFF(p, linebuf);
+
+ if (!override && (*p == '*' || *p == 'X')) {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (!override && (*p == '*' || *p == 'X')) {
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Now check if the NT compatible password is
+ available. */
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+
+ if (*p == '[') {
+
+ i = 0;
+ encode_bits[i++] = *p++;
+ while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
+ encode_bits[i++] = *p++;
+
+ encode_bits[i++] = ']';
+ encode_bits[i++] = '\0';
+
+ if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ } else {
+ DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format. This is no longer supported.!\n"));
+ DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
+ return False;
+ }
+
+ /* Go past the ']' */
+ if(linebuf_len > PTR_DIFF(p, linebuf))
+ p++;
+
+ if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+ p++;
+
+ /* We should be pointing at the LCT entry. */
+ if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
+
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* *p && StrnCaseCmp() */
+ } /* p == ':' */
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+ /* Create the 32 byte representation of the new p16 */
+ if(pwd->smb_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ wr_len = 66;
+ if (pwd->smb_nt_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ ascii_p16[65] = ':';
+ ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+ /* Add on the account info bits and the time of last
+ password change. */
+
+ if(got_pass_last_set_time) {
+ slprintf(&ascii_p16[strlen(ascii_p16)],
+ sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+ "%s:LCT-%08X:",
+ encode_bits, (uint32)pwd->pass_last_set_time );
+ wr_len = strlen(ascii_p16);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbfilepwd_entry: "));
+ dump_data(100, ascii_p16, wr_len);
+#endif
+
+ if(wr_len > sizeof(linebuf)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ /*
+ * Do an atomic write into the file at the position defined by
+ * seekpos.
+ */
+
+ /* The mod user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+
+ fd = fileno(fp);
+
+ if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Sanity check - ensure the areas we are writing are framed by ':' */
+ if (read(fd, linebuf, wr_len+1) != wr_len+1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
+ DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (write(fd, ascii_p16, wr_len) != wr_len) {
+ DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static BOOL del_smbfilepwd_entry(const char *name)
+{
+ char *pfile = lp_smb_passwd_file();
+ pstring pfile2;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ FILE *fp_write = NULL;
+ int pfile2_lockdepth = 0;
+
+ slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
+
+ /*
+ * Open the smbpassword file - for update. It needs to be update
+ * as we need any other processes to wait until we have replaced
+ * it.
+ */
+
+ if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ return False;
+ }
+
+ /*
+ * Create the replacement password file.
+ */
+ if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(fp)) != NULL) {
+ char *new_entry;
+ size_t new_entry_length;
+
+ if (strequal(name, pwd->smb_name)) {
+ DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
+ continue;
+ }
+
+ /*
+ * We need to copy the entry out into the second file.
+ */
+
+ if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+ if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ }
+
+ /*
+ * Ensure pfile2 is flushed before rename.
+ */
+
+ if(fflush(fp_write) != 0)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return False;
+ }
+
+ /*
+ * Do an atomic rename - then release the locks.
+ */
+
+ if(rename(pfile2,pfile) != 0) {
+ unlink(pfile2);
+ }
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return True;
+}
+
+/*********************************************************************
+ Create a smb_passwd struct from a SAM_ACCOUNT.
+ We will not allocate any new memory. The smb_passwd struct
+ should only stay around as long as the SAM_ACCOUNT does.
+ ********************************************************************/
+static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
+{
+ uid_t *uid;
+ gid_t *gid;
+
+ if (sampass == NULL)
+ return False;
+ uid = pdb_get_uid(sampass);
+ gid = pdb_get_gid(sampass);
+
+ if (!uid || !gid) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user without a UNIX uid or gid. \n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(smb_pw);
+
+ smb_pw->smb_userid=*uid;
+ smb_pw->smb_name=pdb_get_username(sampass);
+
+ smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
+ smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
+
+ smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
+ smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
+
+ if (*uid != pdb_user_rid_to_uid(pdb_get_user_rid(sampass))) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
+ return False;
+ }
+
+#if 0
+ /*
+ * ifdef'out by JFM on 11/29/2001.
+ * this assertion is no longer valid
+ * and I don't understand the goal
+ * and doing the same thing with the group mapping code
+ * is hairy !
+ *
+ * We just have the RID, in which SID is it valid ?
+ * our domain SID ? well known SID ? local SID ?
+ */
+
+ if (*gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
+ DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
+ DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
+ return False;
+ }
+#endif
+
+ return True;
+}
+
+/*********************************************************************
+ Create a SAM_ACCOUNT from a smb_passwd struct
+ ********************************************************************/
+static BOOL build_sam_account(SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
+{
+ struct passwd *pwfile;
+
+ if (sam_pass==NULL) {
+ DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
+ return False;
+ }
+
+ /* Verify in system password file...
+ FIXME!!! This is where we should look up an internal
+ mapping of allocated uid for machine accounts as well
+ --jerry */
+ pwfile = sys_getpwnam(pw_buf->smb_name);
+ if (pwfile == NULL) {
+ DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s not in unix passwd database!\n", pw_buf->smb_name));
+ return False;
+ }
+
+ pdb_set_uid (sam_pass, &pwfile->pw_uid);
+ pdb_set_gid (sam_pass, &pwfile->pw_gid);
+
+ pdb_set_fullname(sam_pass, pwfile->pw_gecos);
+
+ pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
+
+ {
+ uint32 rid;
+ GROUP_MAP map;
+
+ if (get_group_map_from_gid(pwfile->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ sid_peek_rid(&map.sid, &rid);
+ }
+ else
+ rid=pdb_gid_to_group_rid(pwfile->pw_gid);
+
+ pdb_set_group_rid(sam_pass, rid);
+ }
+
+ pdb_set_username (sam_pass, pw_buf->smb_name);
+ pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
+ pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
+ pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
+ pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
+ pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time);
+ pdb_set_domain (sam_pass, lp_workgroup());
+
+ pdb_set_dir_drive (sam_pass, lp_logon_drive());
+
+ /* the smbpasswd format doesn't have a must change time field, so
+ we can't get this right. The best we can do is to set this to
+ some time in the future. 21 days seems as reasonable as any other value :)
+ */
+ pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
+
+ /* check if this is a user account or a machine account */
+ if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$')
+ {
+ pstring str;
+
+ pstrcpy(str, lp_logon_path());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_profile_path(sam_pass, str);
+
+ pstrcpy(str, lp_logon_home());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_homedir(sam_pass, str);
+
+ pstrcpy(str, lp_logon_drive());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_dir_drive(sam_pass, str);
+
+ pstrcpy(str, lp_logon_script());
+ standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
+ pdb_set_logon_script(sam_pass, str);
+
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ /*pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS); */
+ }
+
+ return True;
+}
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+BOOL pdb_setsampwent (BOOL update)
+{
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+
+ /* did we fail? Should we try to create it? */
+ if (!global_vp && update && errno == ENOENT)
+ {
+ FILE *fp;
+ /* slprintf(msg_str,msg_str_len-1,
+ "smbpasswd file did not exist - attempting to create it.\n"); */
+ DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
+ fp = sys_fopen(lp_smb_passwd_file(), "w");
+ if (fp)
+ {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ }
+
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+ }
+
+ return (global_vp != NULL);
+}
+
+void pdb_endsampwent (void)
+{
+ endsmbfilepwent(global_vp, &pw_file_lock_depth);
+}
+
+/*****************************************************************
+ ****************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ struct smb_passwd *pw_buf=NULL;
+ BOOL done = False;
+ DEBUG(5,("pdb_getsampwent\n"));
+
+ if (user==NULL) {
+ DEBUG(5,("pdb_getsampwent: user is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwent\n");
+#endif
+ return False;
+ }
+
+ while (!done)
+ {
+ /* do we have an entry? */
+ pw_buf = getsmbfilepwent(global_vp);
+ if (pw_buf == NULL)
+ return False;
+
+ /* build the SAM_ACCOUNT entry from the smb_passwd struct.
+ We loop in case the user in the pdb does not exist in
+ the local system password file */
+ if (build_sam_account(user, pw_buf))
+ done = True;
+ }
+
+ DEBUG(5,("pdb_getsampwent:done\n"));
+
+ /* success */
+ return True;
+}
+
+
+/****************************************************************
+ Search smbpasswd file by iterating over the entries. Do not
+ call getpwnam() for unix account information until we have found
+ the correct entry
+ ***************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+ char *domain = NULL;
+ char *user = NULL;
+ fstring name;
+
+ DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
+
+
+ /* break the username from the domain if we have
+ been given a string in the form 'DOMAIN\user' */
+ fstrcpy (name, username);
+ if ((user=strchr_m(name, '\\')) != NULL) {
+ domain = name;
+ *user = '\0';
+ user++;
+ }
+
+ /* if a domain was specified and it wasn't ours
+ then there is no chance of matching */
+ if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
+ return False;
+
+ /* startsmbfilepwent() is used here as we don't want to lookup
+ the UNIX account in the local system password file until
+ we have a match. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ /* if we have a domain name, then we should map it to a UNIX
+ username first */
+ if ( domain )
+ map_username(user);
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwnam\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", (int)uid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwuid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwrid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account (sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_add_sam_account(const SAM_ACCOUNT *sampass)
+{
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ if (!build_smb_pass(&smb_pw, sampass)) {
+ return False;
+ }
+
+ /* add the entry */
+ if(!add_smbfilepwd_entry(&smb_pw)) {
+ return False;
+ }
+
+ return True;
+}
+
+BOOL pdb_update_sam_account(const SAM_ACCOUNT *sampass, BOOL override)
+{
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ build_smb_pass(&smb_pw, sampass);
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(&smb_pw, override))
+ return False;
+
+ return True;
+}
+
+BOOL pdb_delete_sam_account (const char* username)
+{
+ return del_smbfilepwd_entry(username);
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void smbpass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WTH_SMBPASSWD_SAM*/
+
diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c
new file mode 100644
index 00000000000..1f1d1ab455b
--- /dev/null
+++ b/source/passdb/pdb_tdb.c
@@ -0,0 +1,808 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000
+ * Copyright (C) Gerald Carter 2000
+ * Copyright (C) Jeremy Allison 2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_TDB_SAM
+
+#define PDB_VERSION "20010830"
+#define PASSDB_FILE_NAME "/passdb.tdb"
+#define TDB_FORMAT_STRING "ddddddBBBBBBBBBBBBddBBwdwdBdd"
+#define USERPREFIX "USER_"
+#define RIDPREFIX "RID_"
+
+extern int DEBUGLEVEL;
+
+struct tdb_enum_info {
+ TDB_CONTEXT *passwd_tdb;
+ TDB_DATA key;
+};
+
+static struct tdb_enum_info global_tdb_ent;
+/*static SAM_ACCOUNT global_sam_pass;*/
+
+/**********************************************************************
+ Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
+ *********************************************************************/
+
+static BOOL init_sam_from_buffer (SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username;
+ char *domain;
+ char *nt_username;
+ char *dir_drive;
+ char *unknown_str;
+ char *munged_dial;
+ char *fullname;
+ char *homedir;
+ char *logon_script;
+ char *profile_path;
+ char *acct_desc;
+ char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 /* uid, gid,*/ user_rid, group_rid, unknown_3, hours_len, unknown_5, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint8 *hours;
+ static uint8 *lm_pw_ptr, *nt_pw_ptr;
+ uint32 len = 0;
+ uint32 lmpwlen, ntpwlen, hourslen;
+ BOOL ret = True;
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING,
+ &logon_time,
+ &logoff_time,
+ &kickoff_time,
+ &pass_last_set_time,
+ &pass_can_change_time,
+ &pass_must_change_time,
+ &username_len, &username,
+ &domain_len, &domain,
+ &nt_username_len, &nt_username,
+ &fullname_len, &fullname,
+ &homedir_len, &homedir,
+ &dir_drive_len, &dir_drive,
+ &logon_script_len, &logon_script,
+ &profile_path_len, &profile_path,
+ &acct_desc_len, &acct_desc,
+ &workstations_len, &workstations,
+ &unknown_str_len, &unknown_str,
+ &munged_dial_len, &munged_dial,
+ &user_rid,
+ &group_rid,
+ &lmpwlen, &lm_pw_ptr,
+ &ntpwlen, &nt_pw_ptr,
+ &acct_ctrl,
+ &unknown_3,
+ &logon_divs,
+ &hours_len,
+ &hourslen, &hours,
+ &unknown_5,
+ &unknown_6);
+
+ if (len == -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_username (sampass, username_len?username:NULL);
+ pdb_set_domain (sampass, domain_len?domain:NULL);
+ pdb_set_nt_username (sampass, nt_username_len?nt_username:NULL);
+ pdb_set_fullname (sampass, fullname_len?fullname:NULL);
+ pdb_set_homedir (sampass, homedir_len?homedir:NULL);
+ pdb_set_dir_drive (sampass, dir_drive_len?dir_drive:NULL);
+ pdb_set_logon_script (sampass, logon_script_len?logon_script:NULL);
+ pdb_set_profile_path (sampass, profile_path_len?profile_path:NULL);
+ pdb_set_acct_desc (sampass, acct_desc_len?acct_desc:NULL);
+ pdb_set_workstations (sampass, workstations_len?workstations:NULL);
+ pdb_set_munged_dial (sampass, munged_dial_len?munged_dial:NULL);
+ pdb_set_lanman_passwd(sampass, lmpwlen?lm_pw_ptr:NULL);
+ pdb_set_nt_passwd (sampass, ntpwlen?nt_pw_ptr:NULL);
+
+ /*pdb_set_uid(sampass, uid);
+ pdb_set_gid(sampass, gid);*/
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+ pdb_set_unknown_3(sampass, unknown_3);
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_unknown_5(sampass, unknown_5);
+ pdb_set_unknown_6(sampass, unknown_6);
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logons_divs(sampass, logon_divs);
+ pdb_set_hours(sampass, hours);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+
+ return ret;
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a SAM_ACCOUNT struct
+ *********************************************************************/
+static uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass)
+{
+ size_t len, buflen;
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ const char *username;
+ const char *domain;
+ const char *nt_username;
+ const char *dir_drive;
+ const char *unknown_str;
+ const char *munged_dial;
+ const char *fullname;
+ const char *homedir;
+ const char *logon_script;
+ const char *profile_path;
+ const char *acct_desc;
+ const char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ const uint8 *lm_pw;
+ const uint8 *nt_pw;
+ uint32 lm_pw_len = 16;
+ uint32 nt_pw_len = 16;
+
+ /* do we have a valid SAM_ACCOUNT pointer? */
+ if (sampass == NULL)
+ return -1;
+
+ *buf = NULL;
+ buflen = 0;
+
+ logon_time = (uint32)pdb_get_logon_time(sampass);
+ logoff_time = (uint32)pdb_get_logoff_time(sampass);
+ kickoff_time = (uint32)pdb_get_kickoff_time(sampass);
+ pass_can_change_time = (uint32)pdb_get_pass_can_change_time(sampass);
+ pass_must_change_time = (uint32)pdb_get_pass_must_change_time(sampass);
+ pass_last_set_time = (uint32)pdb_get_pass_last_set_time(sampass);
+
+
+ username = pdb_get_username(sampass);
+ if (username)
+ username_len = strlen(username) +1;
+ else
+ username_len = 0;
+ domain = pdb_get_domain(sampass);
+ if (domain)
+ domain_len = strlen(domain) +1;
+ else
+ domain_len = 0;
+ nt_username = pdb_get_nt_username(sampass);
+ if (nt_username)
+ nt_username_len = strlen(nt_username) +1;
+ else
+ nt_username_len = 0;
+ dir_drive = pdb_get_dirdrive(sampass);
+ if (dir_drive)
+ dir_drive_len = strlen(dir_drive) +1;
+ else
+ dir_drive_len = 0;
+ unknown_str = NULL;
+ unknown_str_len = 0;
+ munged_dial = pdb_get_munged_dial(sampass);
+ if (munged_dial)
+ munged_dial_len = strlen(munged_dial) +1;
+ else
+ munged_dial_len = 0;
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname)
+ fullname_len = strlen(fullname) +1;
+ else
+ fullname_len = 0;
+ homedir = pdb_get_homedir(sampass);
+ if (homedir)
+ homedir_len = strlen(homedir) +1;
+ else
+ homedir_len = 0;
+ logon_script = pdb_get_logon_script(sampass);
+ if (logon_script)
+ logon_script_len = strlen(logon_script) +1;
+ else
+ logon_script_len = 0;
+ profile_path = pdb_get_profile_path(sampass);
+ if (profile_path)
+ profile_path_len = strlen(profile_path) +1;
+ else
+ profile_path_len = 0;
+ acct_desc = pdb_get_acct_desc(sampass);
+ if (acct_desc)
+ acct_desc_len = strlen(acct_desc) +1;
+ else
+ acct_desc_len = 0;
+ workstations = pdb_get_workstations(sampass);
+ if (workstations)
+ workstations_len = strlen(workstations) +1;
+ else
+ workstations_len = 0;
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ if (!lm_pw)
+ lm_pw_len = 0;
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ if (!nt_pw)
+ nt_pw_len = 0;
+
+ /* one time to get the size needed */
+ len = tdb_pack(NULL, 0, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* malloc the space needed */
+ if ( (*buf=(uint8*)malloc(len)) == NULL) {
+ DEBUG(0,("init_buffer_from_sam: Unable to malloc() memory for buffer!\n"));
+ return (-1);
+ }
+
+ /* now for the real call to tdb_pack() */
+ buflen = tdb_pack(*buf, len, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* check to make sure we got it correct */
+ if (buflen != len) {
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+/***************************************************************
+ Open the TDB passwd database for SAM account enumeration.
+****************************************************************/
+
+BOOL pdb_setsampwent(BOOL update)
+{
+ pstring tdbfile;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* Open tdb passwd */
+ if (!(global_tdb_ent.passwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)))
+ {
+ DEBUG(0, ("Unable to open/create TDB passwd\n"));
+ return False;
+ }
+
+ global_tdb_ent.key = tdb_firstkey(global_tdb_ent.passwd_tdb);
+
+ return True;
+}
+
+/***************************************************************
+ End enumeration of the TDB passwd list.
+****************************************************************/
+
+void pdb_endsampwent(void)
+{
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ DEBUG(7, ("endtdbpwent: closed password file.\n"));
+}
+
+/*****************************************************************
+ Get one SAM_ACCOUNT from the TDB (next in line)
+*****************************************************************/
+
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ TDB_DATA data;
+ struct passwd *pw;
+ uid_t uid;
+ gid_t gid;
+ char *prefix = USERPREFIX;
+ int prefixlen = strlen (prefix);
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_get_sampwent: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* skip all RID entries */
+ while ((global_tdb_ent.key.dsize != 0) && (strncmp (global_tdb_ent.key.dptr, prefix, prefixlen)))
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ /* do we have an valid interation pointer? */
+ if(global_tdb_ent.passwd_tdb == NULL) {
+ DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
+ return False;
+ }
+
+ data = tdb_fetch (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user))) == NULL) {
+ DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
+ pdb_get_username(user)));
+ return False;
+ }
+
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, &uid);
+ pdb_set_gid (user, &gid);
+
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ return True;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+BOOL pdb_getsampwnam (SAM_ACCOUNT *user, const char *sname)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ struct passwd *pw;
+ pstring tdbfile;
+ fstring name;
+ uid_t uid;
+ gid_t gid;
+
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* Data is stored in all lower-case */
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd!\n"));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user)))) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, &uid);
+ pdb_set_gid (user, &gid);
+ }
+
+ /* cleanup */
+ tdb_close (pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Search by uid
+ **************************************************************************/
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT* user, uid_t uid)
+{
+ struct passwd *pw;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwuid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ pw = sys_getpwuid(uid);
+ if (pw == NULL) {
+ DEBUG(0,("pdb_getsampwuid: getpwuid(%d) return NULL. User does not exist!\n", uid));
+ return False;
+ }
+ fstrcpy (name, pw->pw_name);
+
+ return pdb_getsampwnam (user, name);
+
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+BOOL pdb_getsampwrid (SAM_ACCOUNT *user, uint32 rid)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwrid (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ fstrcpy (name, data.dptr);
+ SAFE_FREE(data.dptr);
+
+ tdb_close (pwd_tdb);
+
+ return pdb_getsampwnam (user, name);
+}
+
+/***************************************************************************
+ Delete a SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_delete_sam_account(const char *sname)
+{
+ SAM_ACCOUNT *sam_pass = NULL;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA key, data;
+ fstring keystr;
+ pstring tdbfile;
+ uint32 rid;
+ fstring name;
+
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* open the TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR, 0600))) {
+ DEBUG(0, ("Unable to open TDB passwd!"));
+ return False;
+ }
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_delete_sam_account (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!pdb_init_sam (&sam_pass)) {
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ if (!init_sam_from_buffer (sam_pass, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ tdb_close (pwd_tdb);
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ pdb_free_sam (&sam_pass);
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ /* delete also the RID key */
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ tdb_close(pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Update the TDB SAM
+****************************************************************************/
+
+static BOOL tdb_update_sam(const SAM_ACCOUNT* newpwd, BOOL override, int flag)
+{
+ TDB_CONTEXT *pwd_tdb = NULL;
+ TDB_DATA key, data;
+ uint8 *buf = NULL;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+ BOOL ret = True;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* if we don't have a RID, then FAIL */
+ if (!pdb_get_user_rid(newpwd))
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a RID\n",pdb_get_username(newpwd)));
+ if (!pdb_get_group_rid(newpwd))
+ DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd)));
+
+ /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
+ if ((data.dsize=init_buffer_from_sam (&buf, newpwd)) == -1) {
+ DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
+ ret = False;
+ goto done;
+ }
+ data.dptr = buf;
+
+ unix_strlower(pdb_get_username(newpwd), -1, name, sizeof(name));
+
+ /* setup the USER index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* invalidate the existing TDB iterator if it is open */
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ /* open the account TDB passwd*/
+ pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+ if (!pwd_tdb)
+ {
+ DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd!\n"));
+ return False;
+ }
+
+ /* add the account */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify passwd TDB!"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ ret = False;
+ goto done;
+ }
+
+ /* setup RID data */
+ data.dsize = sizeof(fstring);
+ data.dptr = name;
+
+ /* setup the RID index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* add the reference */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify TDB passwd !"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ ret = False;
+ goto done;
+ }
+
+done:
+ /* cleanup */
+ tdb_close (pwd_tdb);
+ SAFE_FREE(buf);
+
+ return (ret);
+}
+
+/***************************************************************************
+ Modifies an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_update_sam_account (const SAM_ACCOUNT *newpwd, BOOL override)
+{
+ return (tdb_update_sam(newpwd, override, TDB_MODIFY));
+}
+
+/***************************************************************************
+ Adds an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_add_sam_account (const SAM_ACCOUNT *newpwd)
+{
+ return (tdb_update_sam(newpwd, True, TDB_INSERT));
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void samtdb_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_TDB_SAM */
diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c
new file mode 100644
index 00000000000..fd616c68414
--- /dev/null
+++ b/source/passdb/secrets.c
@@ -0,0 +1,288 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0.
+ Copyright (C) Andrew Tridgell 1992-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* the Samba secrets database stores any generated, private information
+ such as the local SID and machine trust password */
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdb;
+
+/* open up the secrets database */
+BOOL secrets_init(void)
+{
+ pstring fname;
+
+ if (tdb)
+ return True;
+
+ pstrcpy(fname, lp_private_dir());
+ pstrcat(fname,"/secrets.tdb");
+
+ tdb = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+
+ if (!tdb) {
+ DEBUG(0,("Failed to open %s\n", fname));
+ return False;
+ }
+ return True;
+}
+
+/* read a entry from the secrets database - the caller must free the result
+ if size is non-null then the size of the entry is put in there
+ */
+void *secrets_fetch(char *key, size_t *size)
+{
+ TDB_DATA kbuf, dbuf;
+ secrets_init();
+ if (!tdb)
+ return NULL;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (size)
+ *size = dbuf.dsize;
+ return dbuf.dptr;
+}
+
+/* store a secrets entry
+ */
+BOOL secrets_store(char *key, void *data, size_t size)
+{
+ TDB_DATA kbuf, dbuf;
+ secrets_init();
+ if (!tdb)
+ return False;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ dbuf.dptr = data;
+ dbuf.dsize = size;
+ return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) == 0;
+}
+
+
+/* delete a secets database entry
+ */
+BOOL secrets_delete(char *key)
+{
+ TDB_DATA kbuf;
+ secrets_init();
+ if (!tdb)
+ return False;
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key);
+ return tdb_delete(tdb, kbuf) == 0;
+}
+
+BOOL secrets_store_domain_sid(char *domain, DOM_SID *sid)
+{
+ fstring key;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
+ return secrets_store(key, sid, sizeof(DOM_SID));
+}
+
+BOOL secrets_fetch_domain_sid(char *domain, DOM_SID *sid)
+{
+ DOM_SID *dyn_sid;
+ fstring key;
+ size_t size;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
+ dyn_sid = (DOM_SID *)secrets_fetch(key, &size);
+
+ if (dyn_sid == NULL)
+ return False;
+
+ if (size != sizeof(DOM_SID))
+ {
+ SAFE_FREE(dyn_sid);
+ return False;
+ }
+
+ *sid = *dyn_sid;
+ SAFE_FREE(dyn_sid);
+ return True;
+}
+
+
+/************************************************************************
+form a key for fetching a domain trust password
+************************************************************************/
+char *trust_keystr(char *domain)
+{
+ static fstring keystr;
+
+ slprintf(keystr,sizeof(keystr)-1,"%s/%s",
+ SECRETS_MACHINE_ACCT_PASS, domain);
+
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+************************************************************************/
+BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16],
+ time_t *pass_last_set_time)
+{
+ struct machine_acct_pass *pass;
+ char *plaintext;
+ size_t size;
+
+ plaintext = secrets_fetch_machine_password();
+ if (plaintext) {
+ /* we have an ADS password - use that */
+ DEBUG(4,("Using ADS machine password\n"));
+ E_md4hash((uchar *)plaintext, ret_pwd);
+ SAFE_FREE(plaintext);
+ return True;
+ }
+
+ if (!(pass = secrets_fetch(trust_keystr(domain), &size))) {
+ DEBUG(5, ("secrets_fetch failed!\n"));
+ return False;
+ }
+
+ if (size != sizeof(*pass)) {
+ DEBUG(0, ("secrets were of incorrect size!\n"));
+ return False;
+ }
+
+ if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
+ memcpy(ret_pwd, pass->hash, 16);
+ SAFE_FREE(pass);
+ return True;
+}
+
+
+/************************************************************************
+ Routine to set the trust account password for a domain.
+************************************************************************/
+BOOL secrets_store_trust_account_password(char *domain, uint8 new_pwd[16])
+{
+ struct machine_acct_pass pass;
+
+ pass.mod_time = time(NULL);
+ memcpy(pass.hash, new_pwd, 16);
+
+ return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass));
+}
+
+/************************************************************************
+ Routine to set the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+BOOL secrets_store_machine_password(char *pass)
+{
+ return secrets_store(SECRETS_MACHINE_PASSWORD, pass, strlen(pass)+1);
+}
+
+
+/************************************************************************
+ Routine to fetch the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+char *secrets_fetch_machine_password(void)
+{
+ return (char *)secrets_fetch(SECRETS_MACHINE_PASSWORD, NULL);
+}
+
+
+
+/************************************************************************
+ Routine to delete the trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_delete(char *domain)
+{
+ return secrets_delete(trust_keystr(domain));
+}
+
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+void reset_globals_after_fork(void)
+{
+ unsigned char dummy;
+
+ secrets_init();
+
+ /*
+ * Increment the global seed value to ensure every smbd starts
+ * with a new random seed.
+ */
+
+ if (tdb) {
+ uint32 initial_val = sys_getpid();
+ tdb_change_int_atomic(tdb, "INFO/random_seed", (int *)&initial_val, 1);
+ set_rand_reseed_data((unsigned char *)&initial_val, sizeof(initial_val));
+ }
+
+ /*
+ * Re-seed the random crypto generator, so all smbd's
+ * started from the same parent won't generate the same
+ * sequence.
+ */
+ generate_random_buffer( &dummy, 1, True);
+}
+
+BOOL secrets_store_ldap_pw(char* dn, char* pw)
+{
+ fstring key;
+ char *p;
+
+ pstrcpy(key, dn);
+ for (p=key; *p; p++)
+ if (*p == ',') *p = '/';
+
+ return secrets_store(key, pw, strlen(pw));
+}
+
+BOOL fetch_ldap_pw(char *dn, char* pw, int len)
+{
+ fstring key;
+ char *p;
+ void *data = NULL;
+ size_t size;
+
+ pstrcpy(key, dn);
+ for (p=key; *p; p++)
+ if (*p == ',') *p = '/';
+
+ data=secrets_fetch(key, &size);
+ if (!size) {
+ DEBUG(0,("fetch_ldap_pw: no ldap secret retrieved!\n"));
+ return False;
+ }
+
+ if (size > len-1)
+ {
+ DEBUG(0,("fetch_ldap_pw: ldap secret is too long (%d > %d)!\n", size, len-1));
+ return False;
+ }
+
+ memcpy(pw, data, size);
+ pw[size] = '\0';
+
+ return True;
+}
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
deleted file mode 100644
index 2dec15ffb43..00000000000
--- a/source/passdb/smbpass.c
+++ /dev/null
@@ -1,304 +0,0 @@
-#ifdef SMB_PASSWD
-/*
- * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
- * Copyright (C) Andrew Tridgell 1992-1995 Modified by Jeremy Allison 1995.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 675
- * Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "includes.h"
-#include "loadparm.h"
-
-extern int DEBUGLEVEL;
-
-int gotalarm;
-
-void
-gotalarm_sig()
-{
- gotalarm = 1;
-}
-
-int
-do_pw_lock(int fd, int waitsecs, int type)
-{
- struct flock lock;
- int ret;
-
- gotalarm = 0;
- signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 1;
- lock.l_pid = 0;
-
- alarm(5);
- ret = fcntl(fd, F_SETLKW, &lock);
- alarm(0);
- signal(SIGALRM, SIGNAL_CAST SIG_DFL);
-
- if (gotalarm) {
- DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n",
- type == F_UNLCK ? "unlock" : "lock"));
- return -1;
- }
- return ret;
-}
-
-int
-pw_file_lock(char *name, int type, int secs)
-{
- int fd = open(name, O_RDWR | O_CREAT, 0666);
- if (fd < 0)
- return (-1);
- if (do_pw_lock(fd, secs, type)) {
- close(fd);
- return -1;
- }
- return fd;
-}
-
-int
-pw_file_unlock(int fd)
-{
- do_pw_lock(fd, 5, F_UNLCK);
- return close(fd);
-}
-
-/*
- * Routine to get the next 32 hex characters and turn them
- * into a 16 byte array.
- */
-
-static int gethexpwd(char *p, char *pwd)
-{
- int i;
- unsigned char lonybble, hinybble;
- char *hexchars = "0123456789ABCDEF";
- char *p1, *p2;
-
- for (i = 0; i < 32; i += 2) {
- hinybble = toupper(p[i]);
- lonybble = toupper(p[i + 1]);
-
- p1 = strchr(hexchars, hinybble);
- p2 = strchr(hexchars, lonybble);
- if (!p1 || !p2)
- return (False);
- hinybble = PTR_DIFF(p1, hexchars);
- lonybble = PTR_DIFF(p2, hexchars);
-
- pwd[i / 2] = (hinybble << 4) | lonybble;
- }
- return (True);
-}
-
-/*
- * Routine to search the smbpasswd file for an entry matching the username.
- */
-struct smb_passwd *
-get_smbpwnam(char *name)
-{
- /* Static buffers we will return. */
- static struct smb_passwd pw_buf;
- static pstring user_name;
- static unsigned char smbpwd[16];
- static unsigned char smbntpwd[16];
- char linebuf[256];
- char readbuf[16 * 1024];
- unsigned char c;
- unsigned char *p;
- long uidval;
- long linebuf_len;
- FILE *fp;
- int lockfd;
- char *pfile = lp_smb_passwd_file();
-
- if (!*pfile) {
- DEBUG(0, ("No SMB password file set\n"));
- return (NULL);
- }
- DEBUG(10, ("get_smbpwnam: opening file %s\n", pfile));
-
- fp = fopen(pfile, "r");
-
- if (fp == NULL) {
- DEBUG(0, ("get_smbpwnam: unable to open file %s\n", pfile));
- return NULL;
- }
- /* Set a 16k buffer to do more efficient reads */
- setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
-
- if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
- DEBUG(0, ("get_smbpwnam: unable to lock file %s\n", pfile));
- fclose(fp);
- return NULL;
- }
- /* make sure it is only rw by the owner */
- chmod(pfile, 0600);
-
- /* We have a read lock on the file. */
- /*
- * Scan the file, a line at a time and check if the name matches.
- */
- while (!feof(fp)) {
- linebuf[0] = '\0';
-
- fgets(linebuf, 256, fp);
- if (ferror(fp)) {
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- /*
- * Check if the string is terminated with a newline - if not
- * then we must keep reading and discard until we get one.
- */
- linebuf_len = strlen(linebuf);
- if (linebuf[linebuf_len - 1] != '\n') {
- c = '\0';
- while (!ferror(fp) && !feof(fp)) {
- c = fgetc(fp);
- if (c == '\n')
- break;
- }
- } else
- linebuf[linebuf_len - 1] = '\0';
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf));
-#endif
- if ((linebuf[0] == 0) && feof(fp)) {
- DEBUG(4, ("get_smbpwnam: end of file reached\n"));
- break;
- }
- /*
- * The line we have should be of the form :-
- *
- * username:uid:[32hex bytes]:....other flags presently
- * ignored....
- *
- * or,
- *
- * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
- *
- * if Windows NT compatible passwords are also present.
- */
-
- if (linebuf[0] == '#' || linebuf[0] == '\0') {
- DEBUG(6, ("get_smbpwnam: skipping comment or blank line\n"));
- continue;
- }
- p = (unsigned char *) strchr(linebuf, ':');
- if (p == NULL) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no :)\n"));
- continue;
- }
- /*
- * As 256 is shorter than a pstring we don't need to check
- * length here - if this ever changes....
- */
- strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
- user_name[PTR_DIFF(p, linebuf)] = '\0';
- if (!strequal(user_name, name))
- continue;
-
- /* User name matches - get uid and password */
- p++; /* Go past ':' */
- if (!isdigit(*p)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (uid not number)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- uidval = atoi((char *) p);
- while (*p && isdigit(*p))
- p++;
- if (*p != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no : after uid)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- /*
- * Now get the password value - this should be 32 hex digits
- * which are the ascii representations of a 16 byte string.
- * Get two at a time and put them into the password.
- */
- p++;
- if (*p == '*' || *p == 'X') {
- /* Password deliberately invalid - end here. */
- DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", user_name));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (passwd too short)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return (False);
- }
- if (p[32] != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no terminating :)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
- pw_buf.smb_passwd = NULL;
- } else {
- if(!gethexpwd(p,smbpwd)) {
- DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
- }
- pw_buf.smb_passwd = smbpwd;
- }
- pw_buf.smb_name = user_name;
- pw_buf.smb_userid = uidval;
- pw_buf.smb_nt_passwd = NULL;
-
- /* Now check if the NT compatible password is
- available. */
- p += 33; /* Move to the first character of the line after
- the lanman password. */
- if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
- if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
- }
- }
-
- fclose(fp);
- pw_file_unlock(lockfd);
- DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n",
- user_name, uidval));
- return &pw_buf;
- }
-
- fclose(fp);
- pw_file_unlock(lockfd);
- return NULL;
-}
-#else
-void
-smbpass_dummy(void)
-{
-} /* To avoid compiler complaints */
-#endif
diff --git a/source/passdb/smbpasschange.c b/source/passdb/smbpasschange.c
new file mode 100644
index 00000000000..f4af6e8745f
--- /dev/null
+++ b/source/passdb/smbpasschange.c
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ change a password in a local smbpasswd file
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+
diff --git a/source/passdb/smbpassgroup.c b/source/passdb/smbpassgroup.c
new file mode 100644
index 00000000000..808abde6617
--- /dev/null
+++ b/source/passdb/smbpassgroup.c
@@ -0,0 +1,195 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef USE_SMBPASS_DB
+
+static int grp_file_lock_depth = 0;
+
+/***************************************************************
+ Start to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+static void *startsmbfilegrpent(BOOL update)
+{
+ static char s_readbuf[1024];
+ return startfilepwent(lp_smb_passgrp_file(), s_readbuf, sizeof(s_readbuf),
+ &grp_file_lock_depth, update);
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+
+static void endsmbfilegrpent(void *vp)
+{
+ endfilepwent(vp, &grp_file_lock_depth);
+}
+
+/*************************************************************************
+ Return the current position in the smbpasswd list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+
+static SMB_BIG_UINT getsmbfilegrppos(void *vp)
+{
+ return getfilepwpos(vp);
+}
+
+/*************************************************************************
+ Set the current position in the smbpasswd list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+
+static BOOL setsmbfilegrppos(void *vp, SMB_BIG_UINT tok)
+{
+ return setfilepwpos(vp, tok);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+static struct smb_passwd *getsmbfilegrpent(void *vp,
+ uint32 **grp_rids, int *num_grps,
+ uint32 **als_rids, int *num_alss)
+{
+ /* Static buffers we will return. */
+ static struct smb_passwd pw_buf;
+ static pstring user_name;
+ struct passwd *pwfile;
+ pstring linebuf;
+ unsigned char *p;
+ int uidval;
+ size_t linebuf_len;
+
+ if (vp == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pwdb_init_smb(&pw_buf);
+
+ /*
+ * Scan the file, a line at a time.
+ */
+ while ((linebuf_len = getfileline(vp, linebuf, sizeof(linebuf))) > 0)
+ {
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:domainrid1,domainrid2..:aliasrid1,aliasrid2..:
+ */
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ p = strncpyn(user_name, linebuf, sizeof(user_name), ':');
+
+ /* Go past ':' */
+ p++;
+
+ /* Get smb uid. */
+
+ p = Atoic((char *) p, &uidval, ":");
+
+ pw_buf.smb_name = user_name;
+ pw_buf.smb_userid = uidval;
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+
+ /* Skip the ':' */
+ p++;
+
+ if (grp_rids != NULL && num_grps != NULL)
+ {
+ int i;
+ p = get_numlist(p, grp_rids, num_grps);
+ if (p == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: invalid line\n"));
+ return NULL;
+ }
+ for (i = 0; i < (*num_grps); i++)
+ {
+ (*grp_rids)[i] = pwdb_gid_to_group_rid((*grp_rids)[i]);
+ }
+ }
+
+ /* Skip the ':' */
+ p++;
+
+ if (als_rids != NULL && num_alss != NULL)
+ {
+ int i;
+ p = get_numlist(p, als_rids, num_alss);
+ if (p == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: invalid line\n"));
+ return NULL;
+ }
+ for (i = 0; i < (*num_alss); i++)
+ {
+ (*als_rids)[i] = pwdb_gid_to_alias_rid((*als_rids)[i]);
+ }
+ }
+
+ pwfile = Get_Pwnam(pw_buf.smb_name);
+ if (pwfile == NULL)
+ {
+ DEBUG(0,("getsmbfilegrpent: smbpasswd database is corrupt!\n"));
+ DEBUG(0,("getsmbfilegrpent: username %s not in unix passwd database!\n", pw_buf.smb_name));
+ return NULL;
+ }
+
+ return &pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilegrpent: end of file reached.\n"));
+ return NULL;
+}
+
+static struct passgrp_ops file_ops =
+{
+ startsmbfilegrpent,
+ endsmbfilegrpent,
+ getsmbfilegrppos,
+ setsmbfilegrppos,
+ iterate_getsmbgrpnam, /* In passgrp.c */
+ iterate_getsmbgrpuid, /* In passgrp.c */
+ iterate_getsmbgrprid, /* In passgrp.c */
+ getsmbfilegrpent,
+};
+
+struct passgrp_ops *file_initialise_password_grp(void)
+{
+ return &file_ops;
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void smbpass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* USE_SMBPASS_DB */
diff --git a/source/po/de.msg b/source/po/de.msg
new file mode 100644
index 00000000000..6a8da43ae3a
--- /dev/null
+++ b/source/po/de.msg
@@ -0,0 +1,1707 @@
+# German messages for international release of SWAT.
+# Copyright (C) 2001 Andreas Moroder
+
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-10-27 14:05+0100\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: Andreas Moroder"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=US-ASCII\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "ERRORE: Kann %s nicht öffnen\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "Hilfe"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Setze Standardwerte"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "Verbunden als <b>%s</b><p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "Globals"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "Freigaben"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "Drucker"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "Status"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Zeige Konfiguration"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "Passwortverwaltung"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Aktuelle Konfiguration"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "Normale Ansich"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Komplette Ansicht"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "Globale Variablen"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Speichere Änderungen"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "Setze Werte zurück"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Erweiterte Ansicht"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "Basis Ansicht"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "Parameter der Freigabe"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "Wähle Freigabe"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "Lösche Freigabe"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "Erstelle Freigabe"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "Änderung des Passworts im Demo modus nicht aktiv"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr " \"Benutzername\" muss angegeben werden \n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr " \"Altes Passwort\" muß angegeben werden \n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr " \"Remote Maschine\" muß angegeben werden \n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr " "Neues/Bestätige Passwort" muß angegeben werden \n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr " Das bestätigte Passwort stimmt nicht mit dem neuen Passwort überein\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " Das Passwort für '%s' wurde geändert. \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr " Das Passwort für '%s' wurde nicht geändert. \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "Verwaltung des Server Passwortes"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr " Benutzername : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr " Altes Passwort : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr " Neues Passwort : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr " Bestätige neues Passwort : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "Ändere Passwort"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "Füge Benutzer hinzu"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "Lösche Benutzer"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Desaktiviere Benutzer"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Aktiviere Benutzer"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "Client/Server Passwort Verwaltung"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " Remote Maschine : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "Drucker Parameter"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "Wichtige Hinweise:"
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Mit [*] gekennzeichnete Druckername in der Druckerauswahlliste"
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "wurde automatisch geladen von :"
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "Printcap Name"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "Der Versuch diese Drucker von SWAT aus zu löschen wird keine Auswirkung haben.\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "Wähle Drucker"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "Lösche Drucker"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "Ersteller Drucker"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr ""
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr ""
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr ""
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr ""
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr ""
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr ""
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr ""
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr ""
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr ""
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr ""
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr ""
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr ""
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr ""
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "Server Status"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Automatische Aktualisierung"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Aktualisierungsintervall: "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Stop Aktualisierung"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "Version:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "aktiv"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "inaktiv"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "Stopp smbd"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "Start smbd"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "Neustart smbd"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr ""
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "Stopp nmbd"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "Start nmbd"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "Neustart nmbd"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Aktive Verbindungen"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr ""
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "IP Adresse"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "Datum"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Kill"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Aktive Freigaben"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "Freigabe"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "Benutzer"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "Gruppe"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "Offene Dateien"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr ""
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Basisoptionen"
+
+#: param/loadparm.c:643
+msgid "dos charset"
+msgstr "dos Charakterset"
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr "unix Charakterset"
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr "Anzeige Charakterset"
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr "Kommentar"
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr "Pfad"
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr "Verzeichnis"
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr "Arbeitsgruppe"
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr "netbios name"
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr "netbios aliase"
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr "netbios scope"
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr "server string"
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr "Schnittstellen"
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr "verwende nur definierte Schnittstellen"
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "Sicherheitsoptionen"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr "Sicherheit"
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr "Verschlüsselte Passwörter"
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr "update Verschlüsselte"
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr "Erlaube Vertrauneswürdige Domänen"
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr "Alternative Berechtigungen"
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr ""
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr "Min. Länge Passwort"
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr "Min. Länge Passwort"
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr "Map nach Gast"
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr "leere Passwörter"
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr "Folge pam Einschränkungen"
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr "Serverpasswort"
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr "smb passwd Datei"
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr "Privates Verzeichnis"
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr "Pfad passdb Modul"
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr ""
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr ""
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr ""
+
+#: param/loadparm.c:678
+msgid "pam password change"
+msgstr "pam Passwortänderung"
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr ""
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr ""
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr ""
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr "username map"
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr "Stufe Passwort "
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr "Stufe Benutzer"
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr "Synchronisiere unix Passwort "
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr "Beschränke anonymus"
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr "plaintext to smbpasswd"
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr "use rhosts"
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr "Benutzername"
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr "Benutzer"
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr "Benutzer"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr "Gast Account"
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr "Ungültige Benutzer"
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr "Gültige Benutzer"
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr "Administratoren"
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr ""
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr ""
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr "Druckerverwalter"
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr ""
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr ""
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr "Gruppe"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr "nur lesen"
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr "Schreiben zulassen"
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr "Beschreibbar"
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr "Beschreibbar"
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr "Erstellungsmaske"
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr "Erstellungsmodus"
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr "Erzwinge Erstellungsmodus"
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr ""
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr "Erzwinge Sicherheitsmodus"
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr "Verzeichnismaske"
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr "Verzeichnismodus"
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr "Erzwinge Verzeichnismodus"
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr "Verzeichnis Sicherheitsmaske"
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr "Erzwinge Verzeichnis Sicherheitsmodus"
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr "Vererbe Rechte"
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr "nur Gäste"
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr "nur Gäste"
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr "Gäste erlaubt"
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr "Öffentlich"
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr "Nur Benutzer"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr "Erlaube hosts"
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr "Erlaube hosts"
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr "verbiete hosts"
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr "verbiete hosts"
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "Secure Socket Layer Optionen"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr ""
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr ""
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr ""
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr ""
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr ""
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr ""
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr ""
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr ""
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr ""
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr "ssl bedarf eines Clientzertifikats"
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr "ssl bedarf eines Serverzertifikats"
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr ""
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr ""
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr ""
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr "Log Optionen"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr "Log Stufe"
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr "Debug Stufe"
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr ""
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr "nur syslog"
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr "Log Datei"
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr "max log Grösse"
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr ""
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr ""
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr ""
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr ""
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr ""
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr " Protokoll Optionen"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr "Protokoll"
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr "max Protokoll"
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr "min Protokoll"
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr ""
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr ""
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr ""
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr "nt smb Unterstützung"
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr "nt pipe Unterstützung"
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr "ntacl Unterstützung"
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr "Melde Version"
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr "Melde als"
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr ""
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr ""
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr "Reihenfolge Namensauflösung"
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr "max Paket"
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr "Paketgröße"
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr ""
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr ""
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr "wins ttl minimo"
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr "Zeitserver"
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "Optimierungsoptionen"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr ""
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr ""
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr ""
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr ""
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr "Max Anzahl smbd Prozesse"
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr "Max. Verbindungen"
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr "Paranoide Serversicherheit"
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr "Max. Festplattengröße"
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr "max Anzahl offener Dateien"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr ""
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr ""
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr "Socket Optionen"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr "Grösse stat cache"
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr ""
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr ""
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr ""
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr "verwende mmap"
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr "größe Schreibpuffer"
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "Druckoptionen"
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr "Druckaufträge insges."
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr "Druckaufträge max."
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr "lade Drucker"
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr "printcap name"
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr ""
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr "Bedruckbar"
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr "Druck ok"
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr ""
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr "Druck"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr "Druckbefehl"
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr "deaktiviere spoolss"
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr "lpq Befehl"
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr "lprm Befehl"
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr "lppause Befehl"
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr "lpresume Befehl"
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr "queuepause Befehl"
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr "queueresume Befehl"
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr "enumports Befehl"
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr "addprinter Befehl"
+
+#: param/loadparm.c:842
+msgid "deleteprinter command"
+msgstr "deleteprinter Befehl"
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr "Zeige Wizzard zum hinzufügen von Druckern"
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr ""
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr "Druckername"
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr "Drucker
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr "Verwende client Treiber"
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr "Druckertreiber"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr "Druckertreiber Datei"
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr "Pfad Druckertreiber"
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "Verwaltung Dateinamen"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr "Entferne den Punkt"
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr ""
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr ""
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr ""
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr ""
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr ""
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr ""
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr ""
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr ""
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr ""
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr ""
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr ""
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr "Verstecke Dateien"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr ""
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr ""
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr ""
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr ""
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr ""
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr ""
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr ""
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "Domänen Optionen"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr "Gruppe Domänenadministratoren"
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr "Domänen Gastgruppen"
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr ""
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr "Verfall Maschinenpasswort"
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "Login optionen"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr ""
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr ""
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr ""
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr ""
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr ""
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr ""
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr ""
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr ""
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr ""
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr ""
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr ""
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr ""
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr ""
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr ""
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "Browsing Optionen"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr "os Stufe"
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr ""
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr ""
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr "Bevorzugter master"
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr "Bevorzugter master"
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr "Lokaler master"
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr "Domänen master"
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr "browsing Liste"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr ""
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr ""
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr "Erweitertes browsing"
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "WINS Optionen"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr ""
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr ""
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr ""
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr ""
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr ""
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "Locking Optionen"
+
+#: param/loadparm.c:930
+msgid "blocking locks"
+msgstr ""
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr ""
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr ""
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr ""
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr ""
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr ""
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr ""
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr ""
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr ""
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr ""
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr ""
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "LDAP Optionen"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr ""
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr ""
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr ""
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr ""
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr ""
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr ""
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "Verschiedene Optionen"
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr ""
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr ""
+
+#: param/loadparm.c:957
+msgid "delete share command"
+msgstr ""
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr "Konfigurationsdatei"
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr "Lade im Voraus"
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr ""
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr "Lock Verzeichnis"
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr "Lock Verzeichnis"
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr "utmp Verzeichnis"
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr "wtmp Verzeichnis"
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr ""
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr ""
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr ""
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr "Message Befehl"
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr "dfree Befehl"
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr "remote announce"
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr ""
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr ""
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr ""
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr ""
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr ""
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr ""
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr "Kopie"
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr "include"
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr ""
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr ""
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr ""
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr ""
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr ""
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr ""
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr ""
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr "Verfügbar"
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr ""
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr "Typ Dateisystem"
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr ""
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr ""
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr "Folge symlinks"
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr "nicht hinabsteigen"
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr ""
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr ""
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr "Lösche nur-lesen"
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr ""
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr ""
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr ""
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr ""
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr ""
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr "verstecke lokale Benutzer"
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr "VFS Optionen"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+msgid "vfs options"
+msgstr ""
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr ""
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr ""
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr "Winbind Optionen"
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr ""
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr ""
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr ""
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr ""
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr ""
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
diff --git a/source/po/en.msg b/source/po/en.msg
new file mode 100644
index 00000000000..2f78cb835e7
--- /dev/null
+++ b/source/po/en.msg
@@ -0,0 +1,1707 @@
+# English messages for international release of SWAT.
+# Copyright (C) 2001 Free Software Foundation, Inc.
+# TAKAHASHI Motonobu <monyo@samba.org>, 2001.
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-09-20 20:29+0900\n"
+"PO-Revision-Date: 2000-02-08 12:48+09:00\n"
+"Last-Translator: TAKAHASHI Motonobu <monyo@samba.gr.jp>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=US-ASCII\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr ""
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr ""
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr ""
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr ""
+
+#: web/swat.c:505
+msgid "Home"
+msgstr ""
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr ""
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr ""
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr ""
+
+#: web/swat.c:512
+msgid "Status"
+msgstr ""
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr ""
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr ""
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr ""
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr ""
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr ""
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr ""
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr ""
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr ""
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr ""
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr ""
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr ""
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr ""
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr ""
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr ""
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr ""
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr ""
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr ""
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr ""
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr ""
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr ""
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr ""
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr ""
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr ""
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr ""
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr ""
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr ""
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr ""
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr ""
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr ""
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr ""
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr ""
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr ""
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr ""
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr ""
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr ""
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr ""
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr ""
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr ""
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr ""
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr ""
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr ""
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr ""
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr ""
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr ""
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr ""
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr ""
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr ""
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr ""
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr ""
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr ""
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr ""
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr ""
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr ""
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr ""
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr ""
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr ""
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr ""
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr ""
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr ""
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr ""
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr ""
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr ""
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr ""
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr ""
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr ""
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr ""
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr ""
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr ""
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr ""
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr ""
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr ""
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr ""
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr ""
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr ""
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr ""
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr ""
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr ""
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr ""
+
+#: param/loadparm.c:643
+msgid "dos charset"
+msgstr ""
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr ""
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr ""
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr ""
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr ""
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr ""
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr ""
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr ""
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr ""
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr ""
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr ""
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr ""
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr ""
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr ""
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr ""
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr ""
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr ""
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr ""
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr ""
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr ""
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr ""
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr ""
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr ""
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr ""
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr ""
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr ""
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr ""
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr ""
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr ""
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr ""
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr ""
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr ""
+
+#: param/loadparm.c:678
+msgid "pam password change"
+msgstr ""
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr ""
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr ""
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr ""
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr ""
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr ""
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr ""
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr ""
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr ""
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr ""
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr ""
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr ""
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr ""
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr ""
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr ""
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr ""
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr ""
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr ""
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr ""
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr ""
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr ""
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr ""
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr ""
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr ""
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr ""
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr ""
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr ""
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr ""
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr ""
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr ""
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr ""
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr ""
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr ""
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr ""
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr ""
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr ""
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr ""
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr ""
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr ""
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr ""
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr ""
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr ""
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr ""
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr ""
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr ""
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr ""
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr ""
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr ""
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr ""
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr ""
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr ""
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr ""
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr ""
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr ""
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr ""
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr ""
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr ""
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr ""
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr ""
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr ""
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr ""
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr ""
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr ""
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr ""
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr ""
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr ""
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr ""
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr ""
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr ""
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr ""
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr ""
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr ""
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr ""
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr ""
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr ""
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr ""
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr ""
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr ""
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr ""
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr ""
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr ""
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr ""
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr ""
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr ""
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr ""
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr ""
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr ""
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr ""
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr ""
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr ""
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr ""
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr ""
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr ""
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr ""
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr ""
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr ""
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr ""
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr ""
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr ""
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr ""
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr ""
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr ""
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr ""
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr ""
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr ""
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr ""
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr ""
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr ""
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr ""
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr ""
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr ""
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr ""
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr ""
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr ""
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr ""
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr ""
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr ""
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr ""
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr ""
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr ""
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr ""
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr ""
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr ""
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr ""
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr ""
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr ""
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr ""
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr ""
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr ""
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr ""
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr ""
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr ""
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr ""
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr ""
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr ""
+
+#: param/loadparm.c:842
+msgid "deleteprinter command"
+msgstr ""
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr ""
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr ""
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr ""
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr ""
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr ""
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr ""
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr ""
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr ""
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr ""
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr ""
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr ""
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr ""
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr ""
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr ""
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr ""
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr ""
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr ""
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr ""
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr ""
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr ""
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr ""
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr ""
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr ""
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr ""
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr ""
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr ""
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr ""
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr ""
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr ""
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr ""
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr ""
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr ""
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr ""
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr ""
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr ""
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr ""
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr ""
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr ""
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr ""
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr ""
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr ""
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr ""
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr ""
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr ""
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr ""
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr ""
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr ""
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr ""
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr ""
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr ""
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr ""
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr ""
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr ""
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr ""
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr ""
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr ""
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr ""
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr ""
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr ""
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr ""
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr ""
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr ""
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr ""
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr ""
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr ""
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr ""
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr ""
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr ""
+
+#: param/loadparm.c:930
+msgid "blocking locks"
+msgstr ""
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr ""
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr ""
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr ""
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr ""
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr ""
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr ""
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr ""
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr ""
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr ""
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr ""
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr ""
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr ""
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr ""
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr ""
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr ""
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr ""
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr ""
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr ""
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr ""
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr ""
+
+#: param/loadparm.c:957
+msgid "delete share command"
+msgstr ""
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr ""
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr ""
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr ""
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr ""
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr ""
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr ""
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr ""
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr ""
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr ""
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr ""
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr ""
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr ""
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr ""
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr ""
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr ""
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr ""
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr ""
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr ""
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr ""
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr ""
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr ""
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr ""
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr ""
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr ""
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr ""
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr ""
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr ""
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr ""
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr ""
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr ""
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr ""
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr ""
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr ""
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr ""
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr ""
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr ""
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr ""
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr ""
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr ""
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr ""
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr ""
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr ""
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr ""
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr ""
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr ""
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+msgid "vfs options"
+msgstr ""
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr ""
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr ""
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr ""
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr ""
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr ""
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr ""
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr ""
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr ""
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
diff --git a/source/po/fr.msg b/source/po/fr.msg
new file mode 100644
index 00000000000..493db659ae6
--- /dev/null
+++ b/source/po/fr.msg
@@ -0,0 +1,1709 @@
+# French messages for international release of SWAT.
+# Copyright (C) 2001 François Le Lay <fanch@tuxfamily.org>
+
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-09-20 14:05+0100\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: François Le Lay <fanch@tuxfamily.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=US-ASCII\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "ERREUR: Impossible d'ouvrir %s\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "Aide"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Définir par défaut"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "Connecté en tant que <b>%s</b><p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "Paramètres Généraux"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "Partages"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "Imprimantes"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "Statut"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Voir Configuration"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "Gestion des mots de passe"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Configuration Actuelle"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "Vue Normale"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Vue Complète"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "Variables Globales"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Sauver les modifications"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "Réinitialiser Valeurs"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Vue Détaillée"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "Vue Basique"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "Paramètres de partage"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "Choisir un partage"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "Supprimer un partage"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "Créer un partage"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "changement de mot de passe en mode démo rejeté"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr " Le champ \"Nom d'utilisateur\" doit être spécifié\n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr " Le champ \"Ancien mot de passe\" doît être spécifié\n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr " Le champ \"Machine Distante\" doît être spécifié\n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr " Les champs \"Nouveau mot de passe\" et \"Confirmation du nouveau mot de passe\" doivent être spécifiés \n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr " Echec de la confirmation du nouveau mot de passe\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " Le mot de passe de '%s' a été modifié. \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The password for '%s' has NOT been changed. \n"
+msgstr " Le mot de passe de '%s' n'a PAS été modifié. \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "Gestion des mots de passe serveur"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr " Nom d'utilisateur : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr " Ancien mot de passe : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr " Nouveau mot de passe : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr " Confirmation du nouveau mot de passe : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "Modifier le mot de passe"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "Nouvel Utilisateur"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "Supprimer Utilisateur"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Désactiver Utilisateur"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Activer Utilisateur"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "Gestion des mots de passe Client/Serveur"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " Machine distante : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "Paramètres Imprimantes"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "Note Importante:"
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Les Noms d'imprimantes marqués du signe [*] dans le menu déroulant Choisir Imprimante"
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "désignent des imprimantes automatiquement chargées depuis le "
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "Nom Printcap"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "Essayer de supprimer ces imprimantes depuis SWAT n'aura aucun effet.\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "Choisir Imprimante"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "Supprimer Imprimante"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "Créer Imprimante"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr ""
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr ""
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr ""
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr ""
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr ""
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr ""
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr ""
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr ""
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr ""
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr ""
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr ""
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr ""
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr ""
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "Statut du Serveur"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Rafraîchissement Automatique"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Intervalle de rafraîchissement: "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Stopper Rafraîchissement"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "version:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "actif"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "non actif"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "Stopper smbd"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "Lancer smbd"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "Relancer smbd"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr ""
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "Stopper nmbd"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "Lancer nmbd"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "Relancer nmbd"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Connections Actives"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr ""
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "adresse IP"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "Date"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Terminer"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Partages Actifs"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "Partager"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "Utilisateur"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "Groupe"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "Fichiers Ouverts"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr "Fichier"
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Options de base"
+
+#: param/loadparm.c:643
+msgid "dos charset"
+msgstr "caractères dos"
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr "caractères unix"
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr "caractères display"
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr "commentaire"
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr "chemin"
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr "répertoire"
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr "groupe de travail"
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr "nom netbios"
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr "alias netbios"
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr ""
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr ""
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr ""
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr "lier uniquement les interfaces"
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "Options de Sécurité"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr "sécurité"
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr "crypter les mots de passe"
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr "mise à jour cryptés"
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr "autoriser les domaines de confiance"
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr "permissions alternatives"
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr ""
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr "taille minimale des mots de passe"
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr "taille minimale des mots de passe"
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr "associer à un invité"
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr "mots de passe null"
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr "utiliser les restrictions pam"
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr "serveur de mots de passe"
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr "fichier passwd de smb"
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr "répertoire privé"
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr "chemin du module passdb"
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr "répertoire root"
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr "répertoire root"
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr ""
+
+#: param/loadparm.c:678
+msgid "pam password change"
+msgstr "modification de mot de passe pam"
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr "programme passwd"
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr ""
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr ""
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr ""
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr "niveau mot de passe"
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr "niveau nom d'utilisateur"
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr "synchroniser avec mots de passe unix"
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr "limiter anonyme"
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr "texte brut vers smbpasswd"
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr "utiliser rhosts"
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr "nom d'utilisateur"
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr "utilisateur"
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr "utilisateurs"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr "compte invité"
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr "utilisateurs non-valides"
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr "utilisateurs valides"
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr "utilisateurs administrateurs"
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr ""
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr ""
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr "administrateur d'imprimante"
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr "forcer utilisateur"
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr "forcer le groupe"
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr "groupe"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr "lecture seule"
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr "écriture ok"
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr "écriture possible"
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr "écriture possible"
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr ""
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr "mode création"
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr "forcer le mode création"
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr ""
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr "forcer le mode sécurité"
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr "masque de répertoire"
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr "mode répertoire"
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr "forcer le mode répertoire"
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr "masque de sécurité répertoire"
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr "forcer le mode sécurité répertoire"
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr "héritage de permissions"
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr "invité seulement"
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr "invité seulement"
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr "invité ok"
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr "public"
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr "utilisateur seulement"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr "autoriser hosts"
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr "autoriser hosts"
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr "refuser hosts"
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr "refuser hosts"
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "Options Secure Socket Layer"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr ""
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr ""
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr ""
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr ""
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr ""
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr "certificat ssl serveur"
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr "clé ssl serveur"
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr "certificat ssl client"
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr "clé ssl client"
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr "ssl requiert un certificat client"
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr "ssl requiert un certificat serveur"
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr "chiffres ssl"
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr "ssl version"
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr "compatibilité ssl"
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr "Options de Logging"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr "niveau log"
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr "niveau debug"
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr ""
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr "syslog seulement"
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr "fichier log"
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr "taille maxi de la log"
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr ""
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr ""
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr ""
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr ""
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr ""
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr "Options de Protocole"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr "protocole"
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr "protocole maxi"
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr "protocole mini"
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr ""
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr ""
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr ""
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr "support smb nt"
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr "support pipe nt"
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr "support acl nt"
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr "annoncer la version"
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr "annoncer comme"
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr "mux maxi"
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr "xmit maxi"
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr "ordre de résolution des noms"
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr "paquet maxi"
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr "taille de paquet"
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr "ttl maxi"
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr "wins ttl maxi"
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr "wins ttl mini"
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr ""
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "Options de réglage"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr ""
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr ""
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr ""
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr ""
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr "nombre maxi de processus smbd"
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr "connections maxi"
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr ""
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr "taille maxi de disque"
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr "nombre maxi de fichiers ouverts"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr "espace d'impression mini"
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr ""
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr "options de socket"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr "taille du cache stat"
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr "allocation stricte"
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr "synchronisation stricte"
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr "toujours synchroniser"
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr "utiliser mmap"
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr "taille du cache d'écriture"
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "Options d'impression"
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr "total jobs d'impression"
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr "max jobs d'impression"
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr "charger imprimantes"
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr "nom printcap"
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr ""
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr "imprimable"
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr "imprimante ok"
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr ""
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr "impression"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr "commande d'impression"
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr "désactiver spoolss"
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr "commande lpq"
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr "commande lprm"
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr "commande lppause"
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr "commande lpresume"
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr "commande queuepause"
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr "commande queueresume"
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr "commande enumports"
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr "commande addprinter"
+
+#: param/loadparm.c:842
+msgid "deleteprinter command"
+msgstr "commande deleteprinter"
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr "Voir l'assistant d'ajout d'imprimante"
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr ""
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr "nom d'imprimante"
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr "imprimante"
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr "utiliser le pilote client"
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr "pilote d'imprimante"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr "fichier de pilote d'imprimante"
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr "adresse du pilote d'imprimante"
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "Gestion des noms de fichier"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr ""
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr ""
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr "casse par défaut"
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr "sensible à la casse"
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr ""
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr "garder la casse"
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr ""
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr ""
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr ""
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr ""
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr "supprimer les fichiers veto"
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr "fichiers veto"
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr "cacher les fichiers"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr ""
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr "map système"
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr "map caché"
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr ""
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr ""
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr ""
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr "cache stat"
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "Options de Domaine"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr "groupe d'administration du domaine"
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr "groupe invité du domaine"
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr "map noms de groupe"
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr ""
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "Options de Logon"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr "ajouter script utilisateur"
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr "supprimer script utilisateur"
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr "ajouter script de groupe"
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr "supprimer script de groupe"
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr "ajouter un utilisateur à un script de groupe"
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr "supprimer un utilisateur d'un script de groupe"
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr "ajouter un script machine"
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr "script shutdown"
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr "annuler script shutdown"
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr "script de logon"
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr ""
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr ""
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr ""
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr ""
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "Options de Navigation"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr "niveau os"
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr "annonce lm"
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr "intervalle lm"
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr "master préféré"
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr "master préféré"
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr "master local"
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr "master de domaine"
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr "parcourir la liste"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr "navigable"
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr "navigable"
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr "navigation améliorée"
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "Options WINS"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr ""
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr ""
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr ""
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr ""
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr ""
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "Options de Verrouillage"
+
+#: param/loadparm.c:930
+msgid "blocking locks"
+msgstr "verrous bloquants"
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr ""
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr ""
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr "verrouillage"
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr ""
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr ""
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr ""
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr ""
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr "verrouillage posix"
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr "verrouillage strict"
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr "modes de partage"
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "Options Ldap"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr "serveur ldap"
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr "port ldap"
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr "suffixe ldap"
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr "filtre ldap"
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr ""
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr ""
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "Options Diverses"
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr "ajouter une commande de partage"
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr "modifier une commande de partage"
+
+#: param/loadparm.c:957
+msgid "delete share command"
+msgstr "supprimer une commande de partage"
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr "fichier de configuration"
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr "pré-chargement"
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr ""
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr ""
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr ""
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr ""
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr ""
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr ""
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr "service par défaut"
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr "par défaut"
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr "commande message"
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr "commande dfree"
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr "annonce distante"
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr "synchronisation de navigation distante"
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr "adresse de socket"
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr ""
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr ""
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr ""
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr ""
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr ""
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr ""
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr ""
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr ""
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr ""
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr ""
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr ""
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr ""
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr ""
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr "disponible"
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr ""
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr ""
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr ""
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr ""
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr ""
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr "ne pas descendre"
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr ""
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr ""
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr "supprimer lecture seule"
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr ""
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr ""
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr ""
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr ""
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr ""
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr "cacher les utilisateurs locaux"
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr "Options VFS"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+msgid "vfs options"
+msgstr ""
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr ""
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr ""
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr "Options Winbind"
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr ""
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr ""
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr ""
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr ""
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr ""
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
+
+
diff --git a/source/po/it.msg b/source/po/it.msg
new file mode 100644
index 00000000000..708f2165ee3
--- /dev/null
+++ b/source/po/it.msg
@@ -0,0 +1,1707 @@
+# Italian messages for international release of SWAT.
+# Copyright (C) 2001 Simo Sorce <idra@samba.org>
+
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-09-20 14:05+0100\n"
+"PO-Revision-Date: 2000-02-08 14:45+0100\n"
+"Last-Translator: Simo Sorce <idra@samba.org>\n"
+"Language-Team: (Samba Team) <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=US-ASCII\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "ERRORE: Impossibile aprire %s\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "Aiuto"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Imposta Default"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "Connesso come <b>%s</b><p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "Home"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "Globali"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "Condivisioni"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "Stampanti"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "Stato"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Visualizza Configurazione"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "Gestione Password"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Configurazione Attuale"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "Vista Normale"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Vista Completa"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "Variabili Globali"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Salva Modifiche"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "Resetta Valori"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Vista Avanzata"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "Vista Semplice"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "Parametri Condivisioni"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "Scegli Condivisione"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "Cancella Condivisione"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "Crea Condivisione"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "cambio password in modalita' demo rigettata"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr " \"Nome Utente\" deve essere specificato \n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr " \"Vecchia Password\" deve essere specificato \n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr " \"Macchina Remota\" deve essere specificato \n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr " "Nuova/Conferma Password" devono essere specificati \n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr " la password di conferma non e' uguale alla nuova password\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " La password per '%s' e' stata cambiata. \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr " La password per '%s' non e' stata cambianta. \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "Gestione Password del Server"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr " Nome Utente : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr " Vecchia Password : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr " Nuova Password : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr " Conferma nuova Password : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "Cambia Password"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "Aggiungi Nuovo Utente"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "Cancella Utente"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Disabilita Utente"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Abilita Utente"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "Gestione Password Client/Server"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " Macchina Remota : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "Parametri Stampante"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "Nota Importante:"
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "nomi di stampante marcati con [*] nel riquadro a scomparsa Scegli Stampante"
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "sono stampanti caricate automaticamente da "
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "Nome Printcap"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "Il tentativo di cancellare queste stampanti da sWAT non avara' effetto.\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "Scegli Stampante"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "Cancella Stampante"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "Crea Stampante"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr ""
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr ""
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr ""
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr ""
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr ""
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr ""
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr ""
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr ""
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr ""
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr ""
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr ""
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr ""
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr ""
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "Stato del Server"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Rinfresco Automatico"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Intervallo Rinfresco: "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Ferma Rinfresco"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "versione:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "attivo"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "non attivo"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "Ferma smbd"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "Lancia smbd"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "Rilancia smbd"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr ""
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "Ferma nmbd"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "Lancia nmbd"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "Rilancia nmbd"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Connessioni Attive"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr ""
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "indirizzo IP"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "Data"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Termina"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Condivisioni Attive"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "Condivisione"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "Utente"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "Gruppo"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "File Aperti"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr ""
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Opzioni Basilari"
+
+#: param/loadparm.c:643
+msgid "dos charset"
+msgstr "set caratteri dos"
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr "set caratteri unix"
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr "set caratteri display"
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr "commento"
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr "percorso"
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr ""
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr ""
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr "nome netbios"
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr "alias netbios"
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr "scope netbios"
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr "stringa server"
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr "interfacce"
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr "usa solo interfacce definite"
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "Opzioni di Sicurezza"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr "sicurezza"
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr "password cryptate"
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr "aggiorna criptate"
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr "permetti domini trusted"
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr "permessi alternativi"
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr ""
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr "minima lunghezza passwd"
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr "minima lunghezza password"
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr "mappa su ospite"
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr "password nulle"
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr "usa restrizioni pam"
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr ""
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr ""
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr "directory privata"
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr "percorso modulo passdb"
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr ""
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr ""
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr ""
+
+#: param/loadparm.c:678
+msgid "pam password change"
+msgstr ""
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr ""
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr ""
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr ""
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr "mappa nomi utenti"
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr "livello password"
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr "livello nome utente"
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr "sincronizza password unix"
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr "limita anonimo"
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr "da plaintext a smbpasswd"
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr "usa rhosts"
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr "nome utente"
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr "utente"
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr "utenti"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr "account ospite"
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr "utenti non validi"
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr "utenti validi"
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr "utenti amministratori"
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr ""
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr ""
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr "amministratore stmapnati"
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr "forza utente"
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr "forza gruppo"
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr "gruppo"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr "sola lettura"
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr "ok scrittura"
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr "scrivibile"
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr "scrivibile"
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr ""
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr ""
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr "forza create mode"
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr ""
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr "forza security mode"
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr ""
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr ""
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr "forza directory mode"
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr ""
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr "forza directory security mode"
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr "eredita permessi"
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr "solo ospite"
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr "solo ospite"
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr "ok ospite"
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr "pubblico"
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr "solo utente"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr "permetti hosts"
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr "permetti hosts"
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr "vieta hosts"
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr "vieta hosts"
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "Opzioni Secure Socket Layer"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr ""
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr ""
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr ""
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr ""
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr ""
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr ""
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr ""
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr ""
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr ""
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr "ssl richiede certificato client"
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr "ssl richiede certificato server"
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr ""
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr "ssl versione"
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr ""
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr "Opzioni di Log"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr "livello log"
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr "livello debug"
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr ""
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr "solo syslog"
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr "file di log"
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr "massima dimensione log"
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr ""
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr ""
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr ""
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr ""
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr ""
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr "Opzioni Protocollo"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr "protocollo"
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr "protocollo massimo"
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr "protocollo minimo"
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr ""
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr ""
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr ""
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr "supporto smb nt"
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr "supporto pipe nt"
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr "supporto acl nt"
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr "annuncia versione"
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr "annuncia come"
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr "mux massimo"
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr "xmit massimo"
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr "ordine risoluzione nomi"
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr "pacchetto massimo"
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr "dimensione pacchetto"
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr "ttl massimo"
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr "wins ttl massimo"
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr "wins ttl minimo"
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr ""
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "Opzioni Tuning"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr ""
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr ""
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr ""
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr ""
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr "massimo n. processi smbd"
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr "massimo n. connessioni"
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr ""
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr "massima dimensione disco"
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr "massimo n. file aperti"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr "spazio stampa minimo"
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr ""
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr "opzioni socket"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr "dimensione stat cache"
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr "allocazione stretta"
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr "sincronizzazione stretta"
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr "sincronizza sempre"
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr "usa mmap"
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr "dimensione write cache"
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "Opzioni di Stampa"
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr "job stampa totali"
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr "massimo n. job stampa"
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr "carica stampanti"
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr "nome printcap"
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr ""
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr "stmpabile"
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr "ok stampa"
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr ""
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr "stampa"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr "comando stampa"
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr "disabilita spoolss"
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr "comando lpq"
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr "comando lprm"
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr "comando lppause"
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr "comando lpresume"
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr "comando queuepause"
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr "comando queueresume"
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr "cmando enumports"
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr "comando addprinter"
+
+#: param/loadparm.c:842
+msgid "deleteprinter command"
+msgstr "comando deleteprinter"
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr "mostra wizard aggiungi stampanti"
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr "mappa driver os2"
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr "nome stampante"
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr "stampante"
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr "usa client driver"
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr "driver stampante"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr "file driver stampante"
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr "posizione driver stampante"
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "Gestione Nomi File"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr "togli il punto"
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr ""
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr ""
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr ""
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr ""
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr ""
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr ""
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr ""
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr ""
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr ""
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr ""
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr ""
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr "nascondi file"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr ""
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr "mappa system"
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr "mappa hidden"
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr "mappa archive"
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr ""
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr ""
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr ""
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "Opzioni Dominio"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr "gruppo amministratori dominio"
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr "gruppo ospiti dominio"
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr "mappa nome gruppo"
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr ""
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "Opzioni di Logon"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr ""
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr ""
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr ""
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr ""
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr ""
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr ""
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr ""
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr ""
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr ""
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr ""
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr ""
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr ""
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr ""
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr ""
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "Opzioni Browsing"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr "livello os"
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr "annuncio lm"
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr "intervallo lm"
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr "master preferito"
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr "master preferito"
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr "master locale"
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr "master dominio"
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr "lista browsing"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr ""
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr ""
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr ""
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "opzioni WINS"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr ""
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr ""
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr ""
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr ""
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr ""
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "Opzioni Locking"
+
+#: param/loadparm.c:930
+msgid "blocking locks"
+msgstr ""
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr ""
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr ""
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr ""
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr ""
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr ""
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr ""
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr ""
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr ""
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr ""
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr ""
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "Opzioni Ldap"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr ""
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr ""
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr ""
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr ""
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr ""
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr ""
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "Opzioni Generiche"
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr ""
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr ""
+
+#: param/loadparm.c:957
+msgid "delete share command"
+msgstr ""
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr "file configurazione"
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr "precarica"
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr ""
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr ""
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr ""
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr ""
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr ""
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr ""
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr ""
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr ""
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr "comando message"
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr "comando dfree"
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr "annuncio remoto"
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr ""
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr ""
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr ""
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr ""
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr ""
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr ""
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr "copia"
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr "includi"
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr "esegui"
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr "pre-esegui"
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr "pre-esegui e chiudi"
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr "post-esegui"
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr "root pre-esegui"
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr "root pre-esegui e chiudi"
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr "root post-esegui"
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr "disponibile"
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr ""
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr "tipo file system"
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr ""
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr ""
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr ""
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr "non discendere"
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr ""
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr ""
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr "cancella sola-lettura"
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr ""
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr ""
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr ""
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr ""
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr ""
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr "nascondi utenti locali"
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr "Opzioni VFS"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+msgid "vfs options"
+msgstr ""
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr ""
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr ""
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr "Opzioni Winbind"
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr ""
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr ""
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr ""
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr ""
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr ""
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
diff --git a/source/po/ja.msg b/source/po/ja.msg
new file mode 100644
index 00000000000..e77f34e3c44
--- /dev/null
+++ b/source/po/ja.msg
@@ -0,0 +1,1821 @@
+# Japanese messages for international release of SWAT.
+# Copyright (C) 2001 Ryo Kawahara <rkawa@lbe.co.jp>, 2000.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n-swatE VERSION\n"
+"POT-Creation-Date: 2001-09-20 20:29+0900\n"
+"PO-Revision-Date: 2000-04-03 17:55+09:00\n"
+"Last-Translator: TAKAHASHI Motonobu <monyo@samba.gr.jp>\n"
+"Language-Team: Samba Team <samba-technical@samba.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=Shift_JIS\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "%s ‚ðƒI[ƒvƒ“‚Å‚«‚Ü‚¹‚ñ\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "à–¾"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Šù’è’l‚É–ß‚·"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "<b>%s</b>‚Æ‚µ‚ăƒOƒCƒ“<p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "ƒz[ƒ€"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "‘S‘ÌÝ’è"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "‹¤—LÝ’è"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "ƒvƒŠƒ“ƒ^Ý’è"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "“®ìó‹µ"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Ý’è•\\Ž¦"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "ƒpƒXƒ[ƒhŠÇ—Eƒ†[ƒUŠÇ—"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Œ»Ý‚ÌÝ’è"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "•W€•\Ž¦"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Š®‘S•\Ž¦"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "‘S‘ÌÝ’è"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Ý’è•ÏX"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "ƒŠƒZƒbƒg"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Úו\Ž¦"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "•W€•\Ž¦"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "‹¤—LÝ’è"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "‹¤—L‘I‘ð"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "‹¤—Líœ"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "V‹K‹¤—Lì¬"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "ƒfƒ‚Eƒ‚[ƒh‚ł̃pƒXƒ[ƒh•ÏX‚Í‚Å‚«‚Ü‚¹‚ñ\n"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr "uƒ†[ƒU–¼v‚ð“ü—Í‚­‚¾‚³‚¢\n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr "u‹ŒƒpƒXƒ[ƒhv‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢\n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr "uƒŠƒ‚[ƒg ƒ}ƒVƒ“v‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢\n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr "uVƒpƒXƒ[ƒhv‚ð“ü—Í‚µAÄ“ü—Í‚à‚µ‚Ä‚­‚¾‚³‚¢\n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr "VƒpƒXƒ[ƒh‚ÌÄ“ü—Í‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " '%s' ‚̃pƒXƒ[ƒh‚Í•ÏX‚³‚ê‚Ü‚µ‚½ \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr " '%s' ‚̃pƒXƒ[ƒh‚Í•ÏX‚³‚ê‚Ü‚¹‚ñ‚Å‚µ‚½ \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "ƒ[ƒJƒ‹ ƒ}ƒVƒ“‚̃pƒXƒ[ƒhŠÇ—"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr "ƒ†[ƒU–¼ : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr "‹ŒƒpƒXƒ[ƒh : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr "VƒpƒXƒ[ƒh : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr "VƒpƒXƒ[ƒhÄ“ü—Í : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "ƒpƒXƒ[ƒh•ÏX"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "V‹Kƒ†[ƒU’ljÁ"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "ƒ†[ƒU‚ð휂·‚é"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Žg—p•s‰Â‚É‚·‚é"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Žg—p‰Â”\‚É‚·‚é"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "ƒŠƒ‚[ƒg ƒ}ƒVƒ“‚̃pƒXƒ[ƒhŠÇ—"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " ƒŠƒ‚[ƒg ƒ}ƒVƒ“ : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "ƒvƒŠƒ“ƒ^Ý’è [Printer]"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "*’:"
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "–¼‘O‚Ì擪‚É [*] ‚ª‚‚¢‚½ƒvƒŠƒ“ƒ^"
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "‚ÍA"
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "printcap name ƒpƒ‰ƒ[ƒ^"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "‚©‚玩“®Ý’肳‚ꂽ‚à‚Ì‚Å‚·‚©‚çA휂·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "ƒvƒŠƒ“ƒ^‘I‘ð"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "ƒvƒŠƒ“ƒ^íœ"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "ƒvƒŠƒ“ƒ^V‹Kì¬"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr "‹‘”Û‚È‚µ"
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr "‚·‚ׂċ‘”Û"
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr "DOS‚ð‹‘”Û"
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr "ŽQÆ‚ð‹‘”Û"
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr "XV‚ð‹‘”Û"
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr "ŽQÆ‚Ì‚Ý"
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr "‘}“ü‚Ì‚Ý"
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr "XV "
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr "ê—L+ƒoƒbƒ` "
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr "ê—L "
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr "ƒoƒbƒ` "
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr "ƒŒƒxƒ‹_II "
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr "‚È‚µ "
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "ƒT[ƒo[“®ìó‹µ"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Ž©“®Ä•\Ž¦"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Ä•\Ž¦ŠÔŠu(•b): "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Ž©“®•\Ž¦’âŽ~"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "ƒo[ƒWƒ‡ƒ“:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr "ƒtƒ@ƒCƒ‹‹¤—Lƒf[ƒ‚ƒ“(smbd):"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "“®ì’†"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "’âŽ~’†"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "smbd’âŽ~"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "smbd‹N“®"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "smbdÄ‹N“®"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr "ƒl[ƒ€ ƒT[ƒrƒX ƒf[ƒ‚ƒ“(nmbd)"
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "nmbd’âŽ~"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "nmbd‹N“®"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "nmbdÄ‹N“®"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Ú‘±’†ƒNƒ‰ƒCƒAƒ“ƒg"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr "ƒvƒƒZƒXID"
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr "ƒNƒ‰ƒCƒAƒ“ƒg"
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "IPƒAƒhƒŒƒX"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "“ú•t"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Ø’f"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Ú‘±’†‹¤—L"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "‹¤—L–¼"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "ƒ†[ƒU"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "ƒOƒ‹[ƒv"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "Žg—p’†ƒtƒ@ƒCƒ‹"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr "”r‘¼ƒ‚[ƒh"
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr "ŽQÆ/XV"
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr "•Ö‹XƒƒbƒN(Oplock)"
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr "ƒtƒ@ƒCƒ‹–¼"
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Šî–{ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:643
+#, fuzzy
+msgid "dos charset"
+msgstr "—LŒø‚È•¶Žš"
+
+#: param/loadparm.c:644
+#, fuzzy
+msgid "unix charset"
+msgstr "—LŒø‚È•¶Žš"
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr ""
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr "ƒRƒƒ“ƒg"
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr "ƒpƒX"
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr "ƒ[ƒNƒOƒ‹[ƒv"
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr "netbios –¼"
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr "netbios ƒGƒCƒŠƒAƒX"
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr "netbios ƒXƒR[ƒv"
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr "ƒT[ƒo•¶Žš—ñ"
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr "ƒCƒ“ƒ^[ƒtƒF[ƒX"
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr "‚±‚̃Cƒ“ƒ^[ƒtƒF[ƒX‚Ì‚ÝŽg—p"
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "ƒZƒLƒ…ƒŠƒeƒB ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr "ƒZƒLƒ…ƒŠƒeƒB"
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr "ƒpƒXƒ[ƒh‚ðˆÃ†‰»"
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr "ˆÃ†‰»ƒpƒXƒ[ƒh‚ÉXV"
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr "M—Š‚Å‚«‚éƒhƒƒCƒ“‚ð‹–‰Â"
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr "‘ãsƒp[ƒ~ƒbƒVƒ‡ƒ“"
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr "“¯“™‚̃zƒXƒg"
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr "ŬƒpƒXƒ[ƒh’·"
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr "ŬƒpƒXƒ[ƒh’·"
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr "ƒQƒXƒg‚Ƀ}ƒbƒv"
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr "‹óƒpƒXƒ[ƒh"
+
+#: param/loadparm.c:669
+#, fuzzy
+msgid "obey pam restrictions"
+msgstr "æ“Ç‚Ý"
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr "ƒpƒXƒ[ƒh ƒT[ƒo"
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr "smb passwd ƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:672
+#, fuzzy
+msgid "private dir"
+msgstr "ƒvƒŠƒ“ƒ^ ƒhƒ‰ƒCƒo"
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr ""
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr "ƒ‹[ƒg ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr "ƒ‹[ƒg ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr "ƒ‹[ƒg"
+
+#: param/loadparm.c:678
+#, fuzzy
+msgid "pam password change"
+msgstr "ŬƒpƒXƒ[ƒh’·"
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr "ƒpƒXƒ[ƒh ƒvƒƒOƒ‰ƒ€"
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr "ƒpƒXƒ[ƒh ƒ`ƒƒƒbƒg"
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr "ƒpƒXƒ[ƒh ƒ`ƒƒƒbƒg ƒfƒoƒbƒO"
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr "ƒ†[ƒU–¼ƒ}ƒbƒv"
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr "ƒpƒXƒ[ƒh ƒŒƒxƒ‹"
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr "ƒ†[ƒU–¼ƒŒƒxƒ‹"
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr "unix ƒpƒXƒ[ƒh‚𓯊ú‚³‚¹‚é"
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr "“½–¼ƒAƒNƒZƒX‚̧ŒÀ"
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr ""
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr "rhosts ‚ðŽg‚¤"
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr "ƒ†[ƒU–¼"
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr "ƒ†[ƒU"
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr "ƒ†[ƒU"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr "ƒQƒXƒg ƒAƒJƒEƒ“ƒg"
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr "–³Œø‚ȃ†[ƒU"
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr "—LŒø‚ȃ†[ƒU"
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr "ŠÇ—ƒ†[ƒU"
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr "“Ç‚ÝŽæ‚胊ƒXƒg"
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr "‘‚«ž‚݃ŠƒXƒg"
+
+#: param/loadparm.c:702
+#, fuzzy
+msgid "printer admin"
+msgstr "ƒvƒŠƒ“ƒ^–¼"
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr "‹­§‚·‚郆[ƒU"
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr "‹­§‚·‚éƒOƒ‹[ƒv"
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr "ƒOƒ‹[ƒv"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr "“Ç‚ÝŽæ‚è‚Ì‚Ý"
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr "‘‚«ž‚݉Â"
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr "‘‚«ž‚݉Â"
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr "‘‚«ž‚݉Â"
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr "쬎ž‚Ƀ}ƒXƒN"
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr "쬎ž‚̃‚[ƒh"
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr "‹­§‚·‚é쬎ž‚̃‚[ƒh"
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr "ƒZƒLƒ…ƒŠƒeƒB ƒ}ƒXƒN"
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr "‹­§‚·‚éƒZƒLƒ…ƒŠƒeƒB ƒ‚[ƒh"
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ ƒ}ƒXƒN"
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ ƒ‚[ƒh"
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr "‹­§‚·‚éƒfƒBƒŒƒNƒgƒŠ ƒ‚[ƒh"
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ‚̃ZƒLƒ…ƒŠƒeƒB ƒ}ƒXƒN"
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr "‹­§‚·‚éƒfƒBƒŒƒNƒgƒŠ‚̃ZƒLƒ…ƒŠƒeƒB ƒ‚[ƒh"
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr "ƒp[ƒ~ƒbƒVƒ‡ƒ“‚ðŒp³"
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr "ƒQƒXƒg‚Ì‚Ý"
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr "ƒQƒXƒg‚Ì‚Ý"
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr "ƒQƒXƒg‰Â"
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr "ƒpƒuƒŠƒbƒN"
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr "ƒ†[ƒU‚Ì‚Ý"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr "‹–‰Â‚·‚éƒzƒXƒg"
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr "‹–‰Â‚·‚éƒzƒXƒg"
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr "‹‘”Û‚·‚éƒzƒXƒg"
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr "‹‘”Û‚·‚éƒzƒXƒg"
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "ƒZƒLƒ…ƒA ƒ\ƒPƒbƒg ƒŒƒCƒA[ ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr "ssl"
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr "ssl ƒzƒXƒg"
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr "ssl –¢Žg—pƒzƒXƒg"
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr "ssl CA ”F؃fƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr "ssl CA ”F؃tƒ@ƒCƒ‹"
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr "ssl ƒT[ƒo”FØ"
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr "ssl ƒT[ƒoŒ®"
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr "ssl ƒNƒ‰ƒCƒAƒ“ƒg”FØ"
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr "ssl ƒNƒ‰ƒCƒAƒ“ƒgŒ®"
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr "ssl ƒNƒ‰ƒCƒAƒ“ƒg”FØ‚ð—v‹"
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr "ssl ƒT[ƒo”FØ‚ð—v‹"
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr "ssl ˆÃ†"
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr "ssl ƒo[ƒWƒ‡ƒ“"
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr "ssl ŒÝŠ·«"
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr "ƒƒMƒ“ƒO ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr "ƒƒO ƒŒƒxƒ‹"
+
+#: param/loadparm.c:756
+#, fuzzy
+msgid "debuglevel"
+msgstr "ƒfƒoƒbƒOƒŒƒxƒ‹"
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr "syslog"
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr "syslog ‚Ì‚Ý"
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr "ƒƒO ƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr "ő僃O ƒTƒCƒY"
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr "ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv ƒƒO"
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr "ƒfƒoƒbƒO ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv"
+
+#: param/loadparm.c:764
+#, fuzzy
+msgid "debug hires timestamp"
+msgstr "ƒfƒoƒbƒO ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv"
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr "ƒfƒoƒbƒO pid"
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr "ƒfƒoƒbƒO uid"
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr "ƒvƒƒgƒRƒ‹ ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr "ƒvƒƒgƒRƒ‹"
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+#, fuzzy
+msgid "max protocol"
+msgstr "ƒvƒƒgƒRƒ‹"
+
+#: param/loadparm.c:773
+#, fuzzy
+msgid "min protocol"
+msgstr "ƒvƒƒgƒRƒ‹"
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr "bmpx “Ç‚Ýo‚µ"
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr "raw “Ç‚Ýo‚µ"
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr "raw ‘‚«ž‚Ý"
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr "nt smb ƒTƒ|[ƒg"
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr "nt pipe ƒTƒ|[ƒg"
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr "nt acl ƒTƒ|[ƒg"
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr "ƒAƒiƒEƒ“ƒX ƒo[ƒWƒ‡ƒ“"
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr "ƒAƒiƒEƒ“ƒX‚·‚éŽí—Þ"
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr "Å‘å mux"
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr "Å‘å xmit"
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr "–¼‘O‰ðŒˆ‚̇”Ô"
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr "Å‘åƒpƒPƒbƒg"
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr "ƒpƒPƒbƒg ƒTƒCƒY"
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr "Å‘å ttl"
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr "Å‘å wins ttl"
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr "Ŭ wins ttl"
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr "ƒ^ƒCƒ€ ƒT[ƒo"
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "ƒ`ƒ…[ƒjƒ“ƒO ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr "XV’Ê’m‚ÌŠÔŠu"
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr "Ø’f‚Ü‚Å‚ÌŽžŠÔ"
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr "getwd ƒLƒƒƒbƒVƒ…"
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr "lpq ƒLƒƒƒbƒVƒ…ŽžŠÔ"
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr ""
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr "Å‘åÚ‘±”"
+
+#: param/loadparm.c:805
+#, fuzzy
+msgid "paranoid server security"
+msgstr "ƒ†[ƒU’ljÁƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr "Å‘åƒfƒBƒXƒN ƒTƒCƒY"
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr "Å‘åƒtƒ@ƒCƒ‹ ƒI[ƒvƒ“”"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr "ŬˆóüƒXƒy[ƒX"
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr "“Ç‚ÝŽæ‚èƒTƒCƒY"
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr "ƒ\\ƒPƒbƒg ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr "stat ƒLƒƒƒbƒVƒ… ƒTƒCƒY"
+
+#: param/loadparm.c:813
+#, fuzzy
+msgid "strict allocate"
+msgstr "Œµ–§‚ȃƒbƒN"
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr "Œµ–§‚È sync"
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr "í‚É sync"
+
+#: param/loadparm.c:816
+#, fuzzy
+msgid "use mmap"
+msgstr "ƒ†[ƒU–¼ƒ}ƒbƒv"
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr "‘‚«ž‚݃LƒƒƒbƒVƒ… ƒTƒCƒY"
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "ˆóüƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:822
+#, fuzzy
+msgid "total print jobs"
+msgstr "ƒvƒŠƒ“ƒ^‚ðƒ[ƒh"
+
+#: param/loadparm.c:823
+#, fuzzy
+msgid "max print jobs"
+msgstr "ˆóü‰Â"
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr "ƒvƒŠƒ“ƒ^‚ðƒ[ƒh"
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr "printcap –¼"
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr "printcap"
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr "ˆóü‰Â"
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr "ˆóü‰Â"
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr "ƒ|ƒXƒgƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr "ˆóü•û–@"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr "ˆóüƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr ""
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr "lpq ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr "lprm ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr "lppause ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr "lpresume ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr "ƒLƒ…[’âŽ~ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr "ƒLƒ…[ÄŠJƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:840
+#, fuzzy
+msgid "enumports command"
+msgstr "ˆóüƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:841
+#, fuzzy
+msgid "addprinter command"
+msgstr "ˆóüƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:842
+#, fuzzy
+msgid "deleteprinter command"
+msgstr "ˆóüƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:843
+#, fuzzy
+msgid "show add printer wizard"
+msgstr "ƒvƒŠƒ“ƒ^‚ðƒ[ƒh"
+
+#: param/loadparm.c:844
+#, fuzzy
+msgid "os2 driver map"
+msgstr "ƒz[ƒ€ƒfƒBƒŒƒNƒgƒŠ ƒ}ƒbƒv"
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr "ƒvƒŠƒ“ƒ^–¼"
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr "ƒvƒŠƒ“ƒ^"
+
+#: param/loadparm.c:848
+#, fuzzy
+msgid "use client driver"
+msgstr "ssl ƒNƒ‰ƒCƒAƒ“ƒg”FØ"
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr "ƒvƒŠƒ“ƒ^ ƒhƒ‰ƒCƒo"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr "ƒvƒŠƒ“ƒ^ ƒhƒ‰ƒCƒo ƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr "ƒvƒŠƒ“ƒ^ ƒhƒ‰ƒCƒo‚ÌêŠ"
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "ƒtƒ@ƒCƒ‹–¼‚̎戵"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr "ƒhƒbƒg‚ðí‚é"
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr "–¼‘O•ÏŠ·—pƒXƒ^ƒbƒN"
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr "Šù’è‚Ì•¶Žš‚Ì‘å¬"
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr "‘å/¬•¶Žš‚Ì‹æ•Ê"
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr "‘å/¬•¶Žš‚Ì‹æ•Ê"
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr "•¶Žš‚̑嬂ð•Û‘¶"
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr "’ZŒ`Ž®‚Å•¶Žš‚̑嬂ð•Û‘¶"
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr "‘å/¬•¶Žš‚Ì•ÏŠ·"
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr "•ÏŠ·—p•¶Žš"
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr "ƒhƒbƒgƒtƒ@ƒCƒ‹‚ð‰B‚·"
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr "‹‘”Ûƒtƒ@ƒCƒ‹‚ðíœ"
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr "‹‘”Ûƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr "‰B‚µƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr "oplock ‚ð‹ÖŽ~‚·‚éƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr "ƒVƒXƒeƒ€‘®«‚Ƀ}ƒbƒv"
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr "‰B‚µ‘®«‚Ƀ}ƒbƒv"
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr "ƒA[ƒJƒCƒu‘®«‚Ƀ}ƒbƒv"
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr "•ÏŠ·‚µ‚½–¼‘O‚Å•\Ž¦"
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr "•ÏŠ·ƒ}ƒbƒv"
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr "stat ƒLƒƒƒbƒVƒ…"
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "ƒhƒƒCƒ“ ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr "ƒhƒƒCƒ“ŠÇ—ƒOƒ‹[ƒv"
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr "ƒhƒƒCƒ“ ƒQƒXƒg ƒOƒ‹[ƒv"
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr "ƒOƒ‹[ƒv–¼ƒ}ƒbƒv"
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr "ƒ}ƒVƒ“ ƒpƒXƒ[ƒh ƒ^ƒCƒ€ƒAƒEƒg"
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "ƒƒOƒIƒ“ ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr "ƒ†[ƒU’ljÁƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr "ƒ†[ƒU휃XƒNƒŠƒvƒg"
+
+#: param/loadparm.c:892
+#, fuzzy
+msgid "add group script"
+msgstr "ƒ†[ƒU’ljÁƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:893
+#, fuzzy
+msgid "delete group script"
+msgstr "ƒ†[ƒU휃XƒNƒŠƒvƒg"
+
+#: param/loadparm.c:894
+#, fuzzy
+msgid "add user to group script"
+msgstr "ƒ†[ƒU’ljÁƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:895
+#, fuzzy
+msgid "delete user from group script"
+msgstr "ƒ†[ƒU휃XƒNƒŠƒvƒg"
+
+#: param/loadparm.c:896
+#, fuzzy
+msgid "add machine script"
+msgstr "ƒ†[ƒU’ljÁƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:897
+#, fuzzy
+msgid "shutdown script"
+msgstr "ƒƒOƒIƒ“ ƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:898
+#, fuzzy
+msgid "abort shutdown script"
+msgstr "ƒƒOƒIƒ“ ƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr "ƒƒOƒIƒ“ ƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr "ƒƒOƒIƒ“ ƒpƒX"
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr "ƒƒOƒIƒ“ ƒhƒ‰ƒCƒu"
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr "ƒƒOƒIƒ“ ƒz[ƒ€"
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr "ƒhƒƒCƒ“ ƒƒOƒIƒ“"
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "ƒRƒ“ƒsƒ…[ƒ^ˆê——•\Ž¦ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr "os ƒŒƒxƒ‹"
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr "lm ƒAƒiƒEƒ“ƒX"
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr "lm ŠÔŠu"
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr "—Dæ‚·‚éƒ}ƒXƒ^"
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr "—Dæ‚·‚éƒ}ƒXƒ^"
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr "ƒ[ƒJƒ‹ ƒ}ƒXƒ^"
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr "ƒhƒƒCƒ“ ƒ}ƒXƒ^"
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr "ƒuƒ‰ƒEƒY ƒŠƒXƒg"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr "ƒuƒ‰ƒEƒY‰Â"
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr "ƒuƒ‰ƒEƒY‰Â"
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr ""
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "WINSƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr "dns ƒvƒƒLƒV"
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr "wins ƒvƒƒLƒV"
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr "wins ƒT[ƒo"
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr "wins ƒTƒ|[ƒg"
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr "wins ƒtƒbƒN"
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "ƒƒbƒLƒ“ƒO ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:930
+#, fuzzy
+msgid "blocking locks"
+msgstr "ƒƒbƒN"
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr "‹U‘• oplock"
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr "ƒJ[ƒlƒ‹ oplock"
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr "ƒƒbƒN"
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr "•Ö‹X“IƒƒbƒN"
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr "level2 oplocks"
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr "oplock ’†’f‚Ì‘Ò‚¿ŽžŠÔ"
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr "oplock ‹£‡‚ÌŒÀ“x"
+
+#: param/loadparm.c:939
+#, fuzzy
+msgid "posix locking"
+msgstr "Œµ–§‚ȃƒbƒN"
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr "Œµ–§‚ȃƒbƒN"
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr "‹¤—Lƒ‚[ƒh"
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "Ldap ƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr "ldap ƒT[ƒo"
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr "ldap ƒ|[ƒg"
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr "lpad ƒTƒtƒBƒbƒNƒX"
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr "ldap ƒtƒBƒ‹ƒ^["
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr "ldap ƒ‹[ƒg"
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr "ldap ƒ‹[ƒg ƒpƒXƒ[ƒh"
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "‚»‚Ì‘¼‚̃IƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:955
+#, fuzzy
+msgid "add share command"
+msgstr "dfree ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:956
+#, fuzzy
+msgid "change share command"
+msgstr "ƒƒbƒZ[ƒW ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:957
+#, fuzzy
+msgid "delete share command"
+msgstr "ƒƒbƒZ[ƒW ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr "Ý’èƒtƒ@ƒCƒ‹"
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr "ƒvƒŠƒ[ƒh"
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr "Ž©“®ƒT[ƒrƒX"
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr "ƒƒbƒN ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr "ƒƒbƒN ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr "utmp ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:966
+#, fuzzy
+msgid "wtmp directory"
+msgstr "utmp ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:967
+#, fuzzy
+msgid "utmp"
+msgstr "utmp ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr "Šù’èƒT[ƒrƒX"
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr "Šù’è"
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr "ƒƒbƒZ[ƒW ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr "dfree ƒRƒ}ƒ“ƒh"
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr "ƒŠƒ‚[ƒg ƒAƒiƒEƒ“ƒX"
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr "ƒŠƒ‚[ƒg‚̃uƒ‰ƒEƒYƒŠƒXƒg‚𓯊ú"
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr "ƒ\\ƒPƒbƒg ƒAƒhƒŒƒX"
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr "ƒz[ƒ€ƒfƒBƒŒƒNƒgƒŠ ƒ}ƒbƒv"
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr "ŽžŠÔƒIƒtƒZƒbƒg"
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr "NIS ƒz[ƒ€ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr "-valid"
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr "ƒRƒs["
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr "ƒCƒ“ƒNƒ‹[ƒh"
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr "ŽÀs"
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr "Ú‘±Žž‚ÉŽÀs"
+
+#: param/loadparm.c:987
+#, fuzzy
+msgid "preexec close"
+msgstr "Ú‘±Žž‚ÉŽÀs"
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr "Ø’fŽž‚ÉŽÀs"
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr "ƒ‹[ƒg‚ÅÚ‘±ŽžŽÀs"
+
+#: param/loadparm.c:990
+#, fuzzy
+msgid "root preexec close"
+msgstr "ƒ‹[ƒg‚ÅÚ‘±ŽžŽÀs"
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr "ƒ‹[ƒg‚ÅØ’fŽžŽÀs"
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr "—˜—p‰Â”\"
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr "ƒ{ƒŠƒ…[ƒ€"
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr "ƒtƒ@ƒCƒ‹ ƒVƒXƒeƒ€ ƒ^ƒCƒv"
+
+#: param/loadparm.c:995
+#, fuzzy
+msgid "set directory"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr "L‚­ƒŠƒ“ƒN"
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr "symlink æ‚ðŽQÆ"
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr "‰º‚É~‚è‚È‚¢ƒfƒBƒŒƒNƒgƒŠ"
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr "ƒ}ƒWƒbƒN ƒXƒNƒŠƒvƒg"
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr "ƒ}ƒWƒbƒN o—Í"
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr "“Ç‚ÝŽæ‚è‚݂̂̃tƒ@ƒCƒ‹‚ðíœ"
+
+#: param/loadparm.c:1003
+#, fuzzy
+msgid "dos filemode"
+msgstr "dos ‚̃tƒ@ƒCƒ‹Žž"
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr "dos ‚̃tƒ@ƒCƒ‹Žž"
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr "dos ‚̃tƒ@ƒCƒ‹Žž‚Ì•ª‰ð”\"
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr "‹U‚̃fƒBƒŒƒNƒgƒŠì¬Žž"
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr "ƒpƒjƒbƒN ƒAƒNƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1009
+#, fuzzy
+msgid "hide local users"
+msgstr "ƒ[ƒJƒ‹ ƒ}ƒXƒ^"
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr "VFSƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+#, fuzzy
+msgid "vfs options"
+msgstr "VFSƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1018
+#, fuzzy
+msgid "msdfs root"
+msgstr "ldap ƒ‹[ƒg"
+
+#: param/loadparm.c:1019
+#, fuzzy
+msgid "host msdfs"
+msgstr "‹‘”Û‚·‚éƒzƒXƒg"
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr "WinbindƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1023
+#, fuzzy
+msgid "winbind uid"
+msgstr "WinbindƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1024
+#, fuzzy
+msgid "winbind gid"
+msgstr "WinbindƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+#, fuzzy
+msgid "winbind separator"
+msgstr "WinbindƒIƒvƒVƒ‡ƒ“"
+
+#: param/loadparm.c:1028
+#, fuzzy
+msgid "winbind cache time"
+msgstr "lpq ƒLƒƒƒbƒVƒ…ŽžŠÔ"
+
+#: param/loadparm.c:1029
+#, fuzzy
+msgid "winbind enum users"
+msgstr "–³Œø‚ȃ†[ƒU"
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
+
+#~ msgid "failed to open %s for writing\n"
+#~ msgstr "%s ‚ð‘‚«ž‚Ý—p‚ɃI[ƒvƒ“‚Å‚«‚Ü‚¹‚ñ\n"
+
+#~ msgid "Can't reload %s\n"
+#~ msgstr "%s ‚ðÄ“Ç‚Ýž‚Ý‚Å‚«‚Ü‚¹‚ñ\n"
+
+#~ msgid "Can't setup password database vectors.\n"
+#~ msgstr "ƒpƒXƒ[ƒhEƒf[ƒ^ƒx[ƒX‚ªŒ©‚‚¯‚ç‚ê‚Ü‚¹‚ñ\n"
+
+#~ msgid "You need to have status=yes in your smb config file\n"
+#~ msgstr "smb.conf ‚Å status=yes ‚ðݒ肵‚Ä‚­‚¾‚³‚¢\n"
+
+#~ msgid "coding system"
+#~ msgstr "ƒR[ƒfƒBƒ“ƒO ƒVƒXƒeƒ€"
+
+#~ msgid "client code page"
+#~ msgstr "ƒNƒ‰ƒCƒAƒ“ƒg ƒR[ƒhƒy[ƒW"
+
+#~ msgid "revalidate"
+#~ msgstr "Ä”FØ"
+
+#~ msgid "status"
+#~ msgstr "ƒXƒe[ƒ^ƒX"
+
+#~ msgid "shared mem size"
+#~ msgstr "‹¤—Lƒƒ‚ƒŠ ƒTƒCƒY"
+
+#~ msgid "character set"
+#~ msgstr "•¶ŽšƒZƒbƒg"
+
+#~ msgid "domain groups"
+#~ msgstr "ƒhƒƒCƒ“ ƒOƒ‹[ƒv"
+
+#~ msgid "domain admin users"
+#~ msgstr "ƒhƒƒCƒ“ŠÇ—ƒ†[ƒU"
+
+#~ msgid "domain guest users"
+#~ msgstr "ƒhƒƒCƒ“ ƒQƒXƒg ƒ†[ƒU"
+
+#~ msgid "ole locking compatibility"
+#~ msgstr "ole ƒƒbƒN‚̌݊·«"
+
+#~ msgid "smbrun"
+#~ msgstr "smbrun"
+
+#, fuzzy
+#~ msgid "wtmp dir"
+#~ msgstr "utmp ƒfƒBƒŒƒNƒgƒŠ"
+
+#~ msgid "unix realname"
+#~ msgstr "unix ‚Ì–{–¼"
diff --git a/source/po/pl.msg b/source/po/pl.msg
new file mode 100644
index 00000000000..c547a94c936
--- /dev/null
+++ b/source/po/pl.msg
@@ -0,0 +1,1773 @@
+# Polish messages for international release of SWAT.
+# Copyright (C) 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-09-20 20:29+0900\n"
+"PO-Revision-Date: 2001-08-15 22:45+02:00\n"
+"Last-Translator: Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>\n"
+"Language-Team: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-2\n"
+"Content-Transfer-Encoding: \n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "B£¡D: Nie mo¿na otworzyæ %s\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "Pomoc"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Ustaw domy¶lnie"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "Zalogowany jako <b>%s</b><p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "Strona domowa"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "Ustawienia globalne"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "Wspó³udzia³y"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "Drukarki"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "Status"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Przejrzyj Konfiguracjê"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "Zarz±dzanie Has³ami"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Bie¿±ca Konfiguracja"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "Normalny Widok"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Pe³ny Widok"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "Zmienne Globalne"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Potwierd¼ Zmiany"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "Zresetuj Warto¶ci"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Widok Zaawansowany"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "Widok Podstawowy"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "Parametry Wspó³udzia³u"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "Wybierz Wspó³udzia³"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "Usuñ Wspó³udzia³"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "Utwórz Wspó³udzia³"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "zmiana has³a w trybie demo odrzucona\n"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr " Musisz podaæ \"Nazwê U¿ytkownika\" \n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr " Musisz podaæ \"Stare Has³o\" \n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr " Musisz podaæ \"Zdaln± Maszynê\" \n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr " Musisz podaæ \"Nowe Has³o, i ponownie wpisane Nowe Has³o\" \n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr " Ponownie wpisane has³o nie pasuje do nowego has³a\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " Has³o dla '%s' zosta³o zmienione. \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr " Has³o dla '%s' NIE zosta³o zmienione. \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "Zarz±dzanie Has³ami na Serwerze"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr " Nazwa U¿ytkownika : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr " Stare Has³o : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr " Nowe Has³o : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr " Ponownie wpisz Nowe Has³o : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "Zmieñ Has³o"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "Dodaj Nowego U¿ytkownika"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "Usuñ U¿ytkownika"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Zablokuj U¿ytkownika"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Odblokuj U¿ytkownika"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "Zarz±dzanie Has³ami Klient/Serwer"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " Zdalna Maszyna : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "Parametry Drukarki"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "Wa¿na Informacja:"
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Nazwy Drukarek zaznaczone [*] w rozwijanym polu Wybierz Drukarkê "
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "s± drukarkami automatycznie ³adowanymi z "
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "Nazwa Printcap"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "Próby usuniêcia tych drukarek ze SWAT nie przynios± efektu.\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "Wybierz Drukarkê"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "Usuñ Drukarkê"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "Utwórz Drukarkê"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr ""
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr ""
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr ""
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr ""
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr ""
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr ""
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr ""
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr ""
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr ""
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr ""
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr ""
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr ""
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr ""
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "Status Serwera"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Automatyczne Od¶wie¿anie"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Interwa³ Od¶wie¿ania: "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Zatrzymaj Od¶wie¿anie"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "wersja:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr ""
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "dzia³a"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "nie dzia³a"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "Zatrzymaj smbd"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "Uruchom smbd"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "Zrestartuj smbd"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr ""
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "Zatrzymaj nmbd"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "Uruchom nmbd"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "Zrestartuj nmbd"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Aktywne Po³±czenia"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr ""
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr "Klient"
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "adres IP"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "Data"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Zatrzymaj"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Aktywne Wspó³udzia³y"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "Wspó³udzia³"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "U¿ytkownik"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "Grupa"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "Otwarte Pliki"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr "Wspó³dzielenie"
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr ""
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr "Plik"
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Bazowe Opcje"
+
+#: param/loadparm.c:643
+#, fuzzy
+msgid "dos charset"
+msgstr "Wybierz Wspó³udzia³"
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr ""
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr ""
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr ""
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr ""
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr ""
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr ""
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr ""
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr ""
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr ""
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr ""
+
+#: param/loadparm.c:654
+#, fuzzy
+msgid "interfaces"
+msgstr "Drukarki"
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr ""
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "Opcje Zabezpieczeñ"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr ""
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr ""
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr ""
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr ""
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr ""
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr ""
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr ""
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr ""
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr ""
+
+#: param/loadparm.c:668
+#, fuzzy
+msgid "null passwords"
+msgstr "Zmieñ Has³o"
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr ""
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr ""
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr ""
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr ""
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr ""
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr ""
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr ""
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr ""
+
+#: param/loadparm.c:678
+#, fuzzy
+msgid "pam password change"
+msgstr "Zarz±dzanie Has³ami"
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr ""
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr ""
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr ""
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr ""
+
+#: param/loadparm.c:683
+#, fuzzy
+msgid "password level"
+msgstr "Zarz±dzanie Has³ami"
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr ""
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr ""
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr ""
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr ""
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr ""
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr ""
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr ""
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr ""
+
+#: param/loadparm.c:693
+#, fuzzy
+msgid "user"
+msgstr "U¿ytkownik"
+
+#: param/loadparm.c:694
+#, fuzzy
+msgid "users"
+msgstr "U¿ytkownik"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr ""
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr ""
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr ""
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr ""
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr ""
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr ""
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr ""
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr ""
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr ""
+
+#: param/loadparm.c:705
+#, fuzzy
+msgid "group"
+msgstr "Grupa"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr ""
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr ""
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr ""
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr ""
+
+#: param/loadparm.c:712
+#, fuzzy
+msgid "create mask"
+msgstr "Utwórz Wspó³udzia³"
+
+#: param/loadparm.c:713
+#, fuzzy
+msgid "create mode"
+msgstr "Utwórz Wspó³udzia³"
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr ""
+
+#: param/loadparm.c:715
+#, fuzzy
+msgid "security mask"
+msgstr "Opcje Zabezpieczeñ"
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr ""
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr ""
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr ""
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr ""
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr ""
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr ""
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr ""
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr ""
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr ""
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr ""
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr ""
+
+#: param/loadparm.c:729
+#, fuzzy
+msgid "only user"
+msgstr "Odblokuj U¿ytkownika"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr ""
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr ""
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr ""
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr ""
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "Opcje SSL"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr ""
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr ""
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr ""
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr ""
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr ""
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr ""
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr ""
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr ""
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr ""
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr ""
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr ""
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr ""
+
+#: param/loadparm.c:750
+#, fuzzy
+msgid "ssl version"
+msgstr "wersja:"
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr ""
+
+#: param/loadparm.c:754
+#, fuzzy
+msgid "Logging Options"
+msgstr "Opcje Blokowania"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr ""
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr ""
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr ""
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr ""
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr ""
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr ""
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr ""
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr ""
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr ""
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr ""
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr ""
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr "Opcje Protoko³u"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr ""
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr ""
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr ""
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr ""
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr ""
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr ""
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr ""
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr ""
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr ""
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr ""
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr ""
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr ""
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr ""
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr ""
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr ""
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr ""
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr ""
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr ""
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr ""
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr ""
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr ""
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr ""
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "Opcje Dostrajaj±ce"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr ""
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr ""
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr ""
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr ""
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr ""
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr ""
+
+#: param/loadparm.c:804
+#, fuzzy
+msgid "max connections"
+msgstr "Aktywne Po³±czenia"
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr ""
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr ""
+
+#: param/loadparm.c:807
+#, fuzzy
+msgid "max open files"
+msgstr "Otwarte Pliki"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr ""
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr ""
+
+#: param/loadparm.c:811
+#, fuzzy
+msgid "socket options"
+msgstr "Bazowe Opcje"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr ""
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr ""
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr ""
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr ""
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr ""
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr ""
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr ""
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "Opcje Drukowania"
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr ""
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr ""
+
+#: param/loadparm.c:824
+#, fuzzy
+msgid "load printers"
+msgstr "Drukarki"
+
+#: param/loadparm.c:825
+#, fuzzy
+msgid "printcap name"
+msgstr "Nazwa Printcap"
+
+#: param/loadparm.c:826
+#, fuzzy
+msgid "printcap"
+msgstr "Nazwa Printcap"
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr ""
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr ""
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr ""
+
+#: param/loadparm.c:830
+#, fuzzy
+msgid "printing"
+msgstr "dzia³a"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr ""
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr ""
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr ""
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr ""
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr ""
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr ""
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr ""
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr ""
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr ""
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr ""
+
+#: param/loadparm.c:842
+#, fuzzy
+msgid "deleteprinter command"
+msgstr "Usuñ Drukarkê"
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr ""
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr ""
+
+#: param/loadparm.c:846
+#, fuzzy
+msgid "printer name"
+msgstr "Parametry Drukarki"
+
+#: param/loadparm.c:847
+#, fuzzy
+msgid "printer"
+msgstr "Drukarki"
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr ""
+
+#: param/loadparm.c:849
+#, fuzzy
+msgid "printer driver"
+msgstr "Parametry Drukarki"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr ""
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr ""
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "Obs³uga Nazw Plików"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr ""
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr ""
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr ""
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr ""
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr ""
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr ""
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr ""
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr ""
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr ""
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr ""
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr ""
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr ""
+
+#: param/loadparm.c:867
+#, fuzzy
+msgid "veto files"
+msgstr "Otwarte Pliki"
+
+#: param/loadparm.c:868
+#, fuzzy
+msgid "hide files"
+msgstr "Otwarte Pliki"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr ""
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr ""
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr ""
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr ""
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr ""
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr ""
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr ""
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "Opcje Domeny"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr ""
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr ""
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr ""
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr ""
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "Opcje Logowania"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr ""
+
+#: param/loadparm.c:891
+#, fuzzy
+msgid "delete user script"
+msgstr "Usuñ U¿ytkownika"
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr ""
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr ""
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr ""
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr ""
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr ""
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr ""
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr ""
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr ""
+
+#: param/loadparm.c:901
+#, fuzzy
+msgid "logon path"
+msgstr "Opcje Logowania"
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr ""
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr ""
+
+#: param/loadparm.c:904
+#, fuzzy
+msgid "domain logons"
+msgstr "Opcje Domeny"
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "Opcje Przegl±dania"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr ""
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr ""
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr ""
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr ""
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr ""
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr ""
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr ""
+
+#: param/loadparm.c:915
+#, fuzzy
+msgid "browse list"
+msgstr "Opcje Przegl±dania"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr ""
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr ""
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr ""
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "Opcje WINS"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr ""
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr ""
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr ""
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr ""
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr ""
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "Opcje Blokowania"
+
+#: param/loadparm.c:930
+#, fuzzy
+msgid "blocking locks"
+msgstr "Opcje Blokowania"
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr ""
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr ""
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr ""
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr ""
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr ""
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr ""
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr ""
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr ""
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr ""
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr ""
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "Opcje Ldap"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr ""
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr ""
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr ""
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr ""
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr ""
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr ""
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "Pozosta³e Opcje"
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr ""
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr ""
+
+#: param/loadparm.c:957
+#, fuzzy
+msgid "delete share command"
+msgstr "Usuñ Wspó³udzia³"
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr ""
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr ""
+
+#: param/loadparm.c:961
+#, fuzzy
+msgid "auto services"
+msgstr "Automatyczne Od¶wie¿anie"
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr ""
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr ""
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr ""
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr ""
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr ""
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr ""
+
+#: param/loadparm.c:971
+#, fuzzy
+msgid "default"
+msgstr "Ustaw domy¶lnie"
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr ""
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr ""
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr ""
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr ""
+
+#: param/loadparm.c:976
+#, fuzzy
+msgid "socket address"
+msgstr "adres IP"
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr ""
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr ""
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr ""
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr ""
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr ""
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr ""
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr ""
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr ""
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr ""
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr ""
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr ""
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr ""
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr ""
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr ""
+
+#: param/loadparm.c:993
+#, fuzzy
+msgid "volume"
+msgstr "Strona domowa"
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr ""
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr ""
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr ""
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr ""
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr ""
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr ""
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr ""
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr ""
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr ""
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr ""
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr ""
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr ""
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr ""
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr ""
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr ""
+
+#: param/loadparm.c:1012
+#, fuzzy
+msgid "VFS options"
+msgstr "Opcje WINS"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr ""
+
+#: param/loadparm.c:1015
+#, fuzzy
+msgid "vfs options"
+msgstr "Bazowe Opcje"
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr ""
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr ""
+
+#: param/loadparm.c:1021
+#, fuzzy
+msgid "Winbind options"
+msgstr "Opcje Drukowania"
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr ""
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr ""
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr ""
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr ""
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr ""
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr ""
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr ""
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr ""
+
+#~ msgid "failed to open %s for writing\n"
+#~ msgstr "nie uda³o siê otworzyæ %s do zapisu\n"
+
+#~ msgid "Can't reload %s\n"
+#~ msgstr "Nie mogê prze³adowaæ %s\n"
+
+#~ msgid "Can't setup password database vectors.\n"
+#~ msgstr "Nie mo¿na ustawiæ wektorów bazy hase³.\n"
+
+#~ msgid "You need to have status=yes in your smb config file\n"
+#~ msgstr "Musisz mieæ status=yes w swoim pliku konfiguracyjnym smb\n"
diff --git a/source/po/tr.msg b/source/po/tr.msg
new file mode 100644
index 00000000000..6c2bc1f93d8
--- /dev/null
+++ b/source/po/tr.msg
@@ -0,0 +1,1723 @@
+# Swat Turkish Translation
+# Copyright (C) 2001 Deniz Akkus Kanca
+# Deniz Akkus Kanca <deniz@arayan.com>, 2001.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+msgid ""
+msgstr ""
+"Project-Id-Version: i18n_swat \n"
+"POT-Creation-Date: 2001-09-20 20:29+0900\n"
+"PO-Revision-Date: 2001-09-20 22:51EEST\n"
+"Last-Translator: Deniz Akkus Kanca <deniz@arayan.com>\n"
+"Language-Team: Turkish <gnu-tr-u12a@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-9\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 0.9.1\n"
+
+#: web/swat.c:120
+#, c-format
+msgid "ERROR: Can't open %s\n"
+msgstr "HATA: %s açýlamadý\n"
+
+#.
+#. str = stripspace(parm->label);
+#. strlower (str); //monyo
+#. d_printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\">%s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s</td><td>",
+#. str, _("Help"), parm->label);
+#.
+#: web/swat.c:211
+msgid "Help"
+msgstr "Yardým"
+
+#: web/swat.c:217 web/swat.c:231 web/swat.c:246 web/swat.c:254 web/swat.c:263
+#: web/swat.c:272 web/swat.c:278 web/swat.c:284 web/swat.c:297
+msgid "Set Default"
+msgstr "Öntanýmlýya Ayarla"
+
+#: web/swat.c:502
+#, c-format
+msgid "Logged in as <b>%s</b><p>\n"
+msgstr "<b>%s</b> kimliði ile oturum açýlmýþ<p>\n"
+
+#: web/swat.c:505
+msgid "Home"
+msgstr "Ev"
+
+#: web/swat.c:507
+msgid "Globals"
+msgstr "Evrenseller"
+
+#: web/swat.c:508
+msgid "Shares"
+msgstr "Paylaþýmlar"
+
+#: web/swat.c:509
+msgid "Printers"
+msgstr "Yazýcýlar"
+
+#: web/swat.c:512
+msgid "Status"
+msgstr "Durum"
+
+#: web/swat.c:513
+msgid "View Config"
+msgstr "Ayarlara Gözat"
+
+#: web/swat.c:515
+msgid "Password Management"
+msgstr "Þifre Yönetimi"
+
+#: web/swat.c:539
+msgid "Current Config"
+msgstr "Þimdiki Ayarlar"
+
+#: web/swat.c:543
+msgid "Normal View"
+msgstr "Normal Görünüm"
+
+#: web/swat.c:545
+msgid "Full View"
+msgstr "Tam Görünüm"
+
+#: web/swat.c:561
+msgid "Global Variables"
+msgstr "Genel Deðiþkenler"
+
+#: web/swat.c:575 web/swat.c:671 web/swat.c:1014
+msgid "Commit Changes"
+msgstr "Deðiþiklikleri Kaydet"
+
+#: web/swat.c:579 web/swat.c:674 web/swat.c:1016
+msgid "Reset Values"
+msgstr "Deðerleri Ýlk Haline Getir"
+
+#: web/swat.c:581 web/swat.c:676 web/swat.c:1018
+msgid "Advanced View"
+msgstr "Geliþmiþ Görünüm"
+
+#: web/swat.c:583 web/swat.c:678 web/swat.c:1020
+msgid "Basic View"
+msgstr "Temel Görünüm"
+
+#: web/swat.c:613
+msgid "Share Parameters"
+msgstr "Paylaþým Parametreleri"
+
+#: web/swat.c:642
+msgid "Choose Share"
+msgstr "Paylaþým Seçin"
+
+#: web/swat.c:656
+msgid "Delete Share"
+msgstr "Paylaþým Kaldýr"
+
+#: web/swat.c:663
+msgid "Create Share"
+msgstr "Paylaþým Oluþtur"
+
+#: web/swat.c:708
+msgid "password change in demo mode rejected\n"
+msgstr "demo kipinde þifre deðiþikliði kabul edilmedi\n"
+
+#: web/swat.c:747
+msgid " Must specify \"User Name\" \n"
+msgstr " \"Kullanýcý Adý\" belirtilmeli \n"
+
+#: web/swat.c:763
+msgid " Must specify \"Old Password\" \n"
+msgstr " \"Eski Þifre\" belirtilmeli \n"
+
+#: web/swat.c:769
+msgid " Must specify \"Remote Machine\" \n"
+msgstr " \"Uzak Makina\" belirtilmeli \n"
+
+#: web/swat.c:776
+msgid " Must specify \"New, and Re-typed Passwords\" \n"
+msgstr " \"Yeni ve Tekrar Girilmiþ Þifreler\" belirtilmeli \n"
+
+#: web/swat.c:782
+msgid " Re-typed password didn't match new password\n"
+msgstr " Tekrar girilen þifre yeni þifre ile eþleþmedi\n"
+
+#: web/swat.c:812
+#, c-format
+msgid " The passwd for '%s' has been changed. \n"
+msgstr " '%s' için þifre deðiþtirildi. \n"
+
+#: web/swat.c:814
+#, c-format
+msgid " The passwd for '%s' has NOT been changed. \n"
+msgstr " '%s' için þifre DEÐÝÞTÝRÝLMEDÝ. \n"
+
+#: web/swat.c:838
+msgid "Server Password Management"
+msgstr "Sunucu Þifre Yönetimi"
+
+#.
+#. * Create all the dialog boxes for data collection
+#.
+#: web/swat.c:847 web/swat.c:894
+msgid " User Name : "
+msgstr " Kullanýcý Adý : "
+
+#: web/swat.c:850 web/swat.c:896
+msgid " Old Password : "
+msgstr " Eski Þifre : "
+
+#: web/swat.c:853 web/swat.c:898
+msgid " New Password : "
+msgstr " Yeni Þifre : "
+
+#: web/swat.c:855 web/swat.c:900
+msgid " Re-type New Password : "
+msgstr " Yeni Þifre Tekrarý : "
+
+#: web/swat.c:863 web/swat.c:911
+msgid "Change Password"
+msgstr "Þifre Deðiþtir"
+
+#: web/swat.c:866
+msgid "Add New User"
+msgstr "Kull. Ekle"
+
+#: web/swat.c:868
+msgid "Delete User"
+msgstr "Kull. Sil"
+
+#: web/swat.c:870
+msgid "Disable User"
+msgstr "Kull. Etkisizleþtir"
+
+#: web/swat.c:872
+msgid "Enable User"
+msgstr "Kull. Etkinleþtir"
+
+#: web/swat.c:885
+msgid "Client/Server Password Management"
+msgstr "Ýstemci/Sunucu Þifre Yönetimi"
+
+#: web/swat.c:902
+msgid " Remote Machine : "
+msgstr " Uzak Makina : "
+
+#: web/swat.c:940
+msgid "Printer Parameters"
+msgstr "Yazýcý Bilgileri"
+
+#: web/swat.c:942
+msgid "Important Note:"
+msgstr "Önemli Not: "
+
+#: web/swat.c:943
+msgid "Printer names marked with [*] in the Choose Printer drop-down box "
+msgstr "Yazýcý Seç kutusunda [*] ile iþaretlenmiþ yazýcý isimleri "
+
+#: web/swat.c:944
+msgid "are autoloaded printers from "
+msgstr "otomatik yüklenen yazýcýlar "
+
+#: web/swat.c:945
+msgid "Printcap Name"
+msgstr "Printcap Adý"
+
+#: web/swat.c:946
+msgid "Attempting to delete these printers from SWAT will have no effect.\n"
+msgstr "Bu yazýcýlarý SWAT'dan silmek etkisiz olacaktýr.\n"
+
+#: web/swat.c:980
+msgid "Choose Printer"
+msgstr "Yazýcý Seç"
+
+#: web/swat.c:999
+msgid "Delete Printer"
+msgstr "Yazýcý Sil"
+
+#: web/swat.c:1006
+msgid "Create Printer"
+msgstr "Yazýcý Oluþtur"
+
+#: web/statuspage.c:40
+msgid "DENY_NONE"
+msgstr "HERKESE_AÇIK"
+
+#: web/statuspage.c:41
+msgid "DENY_ALL "
+msgstr "HERKESÝ_REDDET "
+
+#: web/statuspage.c:42
+msgid "DENY_DOS "
+msgstr "DOSU_REDDET "
+
+#: web/statuspage.c:43
+msgid "DENY_READ "
+msgstr "OKU_REDDET "
+
+#: web/statuspage.c:44
+msgid "DENY_WRITE "
+msgstr "YAZ_REDDET "
+
+#: web/statuspage.c:50
+msgid "RDONLY "
+msgstr "SALTOKUNUR "
+
+#: web/statuspage.c:51
+msgid "WRONLY "
+msgstr "SALTYAZILIR "
+
+#: web/statuspage.c:52
+msgid "RDWR "
+msgstr "O/Y "
+
+#: web/statuspage.c:60
+msgid "EXCLUSIVE+BATCH "
+msgstr "ÞAHSÝ+TOPTAN "
+
+#: web/statuspage.c:62
+msgid "EXCLUSIVE "
+msgstr "ÞAHSÝ "
+
+#: web/statuspage.c:64
+msgid "BATCH "
+msgstr "TOPTAN "
+
+#: web/statuspage.c:66
+msgid "LEVEL_II "
+msgstr "SEVÝYE_II "
+
+#: web/statuspage.c:68
+msgid "NONE "
+msgstr "HÝÇ "
+
+#: web/statuspage.c:195
+msgid "Server Status"
+msgstr "Sunucu Durumu"
+
+#: web/statuspage.c:200
+msgid "Auto Refresh"
+msgstr "Oto Tazele"
+
+#: web/statuspage.c:201 web/statuspage.c:206
+msgid "Refresh Interval: "
+msgstr "Tazeleme Aralýðý: "
+
+#: web/statuspage.c:205
+msgid "Stop Refreshing"
+msgstr "Tazelemeyi Durdur"
+
+#: web/statuspage.c:220
+msgid "version:"
+msgstr "sürüm:"
+
+#: web/statuspage.c:223
+msgid "smbd:"
+msgstr "smbd:"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "running"
+msgstr "çalýþýyor"
+
+#: web/statuspage.c:223 web/statuspage.c:235
+msgid "not running"
+msgstr "çalýþmýyor"
+
+#: web/statuspage.c:226
+msgid "Stop smbd"
+msgstr "Smbd'yi durdur"
+
+#: web/statuspage.c:228
+msgid "Start smbd"
+msgstr "Smbd'yi çalýþtýr"
+
+#: web/statuspage.c:230
+msgid "Restart smbd"
+msgstr "Smbd'yi yeniden çalýþtýr"
+
+#: web/statuspage.c:235
+msgid "nmbd:"
+msgstr "nmbd:"
+
+#: web/statuspage.c:238
+msgid "Stop nmbd"
+msgstr "Nmbd'yi durdur"
+
+#: web/statuspage.c:240
+msgid "Start nmbd"
+msgstr "Nmbd'yi çalýþtýr"
+
+#: web/statuspage.c:242
+msgid "Restart nmbd"
+msgstr "Nmbd'yi yeniden çalýþtýr"
+
+#: web/statuspage.c:249
+msgid "Active Connections"
+msgstr "Aktif Baðlantýlar"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "PID"
+msgstr "PID"
+
+#: web/statuspage.c:251 web/statuspage.c:264
+msgid "Client"
+msgstr "Ýstemci"
+
+#: web/statuspage.c:251
+msgid "IP address"
+msgstr "IP numarasý"
+
+#: web/statuspage.c:251 web/statuspage.c:264 web/statuspage.c:272
+msgid "Date"
+msgstr "Tarih"
+
+#: web/statuspage.c:253
+msgid "Kill"
+msgstr "Kapat"
+
+#: web/statuspage.c:261
+msgid "Active Shares"
+msgstr "Aktif Paylaþýmlar"
+
+#: web/statuspage.c:264
+msgid "Share"
+msgstr "Paylaþým"
+
+#: web/statuspage.c:264
+msgid "User"
+msgstr "Kullanýcý"
+
+#: web/statuspage.c:264
+msgid "Group"
+msgstr "Grup"
+
+#: web/statuspage.c:270
+msgid "Open Files"
+msgstr "Açýk Dosyalar"
+
+#: web/statuspage.c:272
+msgid "Sharing"
+msgstr "Paylaþýlýyor"
+
+#: web/statuspage.c:272
+msgid "R/W"
+msgstr "O/Y"
+
+#: web/statuspage.c:272
+msgid "Oplock"
+msgstr "Oplock"
+
+#: web/statuspage.c:272
+msgid "File"
+msgstr "Dosya"
+
+#: param/loadparm.c:641
+msgid "Base Options"
+msgstr "Temel Seçenekler"
+
+#: param/loadparm.c:643
+msgid "dos charset"
+msgstr "dos karakter kümesi"
+
+#: param/loadparm.c:644
+msgid "unix charset"
+msgstr "unix karakter kümesi"
+
+#: param/loadparm.c:645
+msgid "display charset"
+msgstr "karakter kümesini göster"
+
+#: param/loadparm.c:646
+msgid "comment"
+msgstr "açýklama"
+
+#: param/loadparm.c:647
+msgid "path"
+msgstr "yol"
+
+#: param/loadparm.c:648
+msgid "directory"
+msgstr "dizin"
+
+#: param/loadparm.c:649
+msgid "workgroup"
+msgstr "çalýþma grubu"
+
+#: param/loadparm.c:650
+msgid "netbios name"
+msgstr "netbios adý"
+
+#: param/loadparm.c:651
+msgid "netbios aliases"
+msgstr "netbios rumuzlarý"
+
+#: param/loadparm.c:652
+msgid "netbios scope"
+msgstr "netbios kapsamý"
+
+#: param/loadparm.c:653
+msgid "server string"
+msgstr "sunucu dizgesi"
+
+#: param/loadparm.c:654
+msgid "interfaces"
+msgstr "arayüzler"
+
+#: param/loadparm.c:655
+msgid "bind interfaces only"
+msgstr "yalnýzca arayüzleri baðla"
+
+#: param/loadparm.c:657
+msgid "Security Options"
+msgstr "Güvenlik Seçenekleri"
+
+#: param/loadparm.c:659
+msgid "security"
+msgstr "güvenlik"
+
+#: param/loadparm.c:660
+msgid "encrypt passwords"
+msgstr "þifreyi þifrele "
+
+#: param/loadparm.c:661
+msgid "update encrypted"
+msgstr "þifrelenmiþ güncelle"
+
+#: param/loadparm.c:662
+msgid "allow trusted domains"
+msgstr "güvenli alanlara izin ver"
+
+#: param/loadparm.c:663
+msgid "alternate permissions"
+msgstr "baþka izinler"
+
+#: param/loadparm.c:664
+msgid "hosts equiv"
+msgstr "hosts eþdeðerlisi"
+
+#: param/loadparm.c:665
+msgid "min passwd length"
+msgstr "en kýsa þifre uzunluðu"
+
+#: param/loadparm.c:666
+msgid "min password length"
+msgstr "en kýsa þifre uzunluðu"
+
+#: param/loadparm.c:667
+msgid "map to guest"
+msgstr "guest (misafir) kullanýcýya eþle"
+
+#: param/loadparm.c:668
+msgid "null passwords"
+msgstr "boþ þifreler"
+
+#: param/loadparm.c:669
+msgid "obey pam restrictions"
+msgstr "pam kýsýtlamalarýna uy"
+
+#: param/loadparm.c:670
+msgid "password server"
+msgstr "þifre sunucusu"
+
+#: param/loadparm.c:671
+msgid "smb passwd file"
+msgstr "smb þifre dosyasý"
+
+#: param/loadparm.c:672
+msgid "private dir"
+msgstr "özel dizin"
+
+#: param/loadparm.c:673
+msgid "passdb module path"
+msgstr "þifre veritabaný modül yolu"
+
+#: param/loadparm.c:674
+msgid "root directory"
+msgstr "kök dizin"
+
+#: param/loadparm.c:675
+msgid "root dir"
+msgstr "kök dizin"
+
+#: param/loadparm.c:676
+msgid "root"
+msgstr "kök"
+
+#: param/loadparm.c:678
+msgid "pam password change"
+msgstr "pam þifre deðiþikliði"
+
+#: param/loadparm.c:679
+msgid "passwd program"
+msgstr "þifre yazýlýmý"
+
+#: param/loadparm.c:680
+msgid "passwd chat"
+msgstr "þifre diyaloðu"
+
+#: param/loadparm.c:681
+msgid "passwd chat debug"
+msgstr "þifre diyalog hata ayýklamasý"
+
+#: param/loadparm.c:682
+msgid "username map"
+msgstr "kullanýcý adý eþlemesi"
+
+#: param/loadparm.c:683
+msgid "password level"
+msgstr "þifre seviyesi"
+
+#: param/loadparm.c:684
+msgid "username level"
+msgstr "kullanýcý kimliði seviyesi"
+
+#: param/loadparm.c:685
+msgid "unix password sync"
+msgstr "unix þifre senkronizasyonu"
+
+#: param/loadparm.c:686
+msgid "restrict anonymous"
+msgstr "anonim eriþimi kýsýtla"
+
+#: param/loadparm.c:687
+msgid "lanman auth"
+msgstr "lanman auth"
+
+#: param/loadparm.c:688
+msgid "ntlm auth"
+msgstr "ntlm auth"
+
+#: param/loadparm.c:689
+msgid "plaintext to smbpasswd"
+msgstr "düz metinden smbpasswd'e"
+
+#: param/loadparm.c:690
+msgid "use rhosts"
+msgstr "rhosts kullan"
+
+#: param/loadparm.c:692
+msgid "username"
+msgstr "kullanýcý adý"
+
+#: param/loadparm.c:693
+msgid "user"
+msgstr "kullanýcý"
+
+#: param/loadparm.c:694
+msgid "users"
+msgstr "kullanýcýlar"
+
+#: param/loadparm.c:696
+msgid "guest account"
+msgstr "misafir hesap"
+
+#: param/loadparm.c:697
+msgid "invalid users"
+msgstr "geçersiz kullanýcýlar"
+
+#: param/loadparm.c:698
+msgid "valid users"
+msgstr "geçerli kullanýcýlar"
+
+#: param/loadparm.c:699
+msgid "admin users"
+msgstr "yönetici kullanýcýlarý"
+
+#: param/loadparm.c:700
+msgid "read list"
+msgstr "okuma listesi"
+
+#: param/loadparm.c:701
+msgid "write list"
+msgstr "yazma listesi"
+
+#: param/loadparm.c:702
+msgid "printer admin"
+msgstr "yazýcý yönetimi"
+
+#: param/loadparm.c:703
+msgid "force user"
+msgstr "kullanýcýyý zorla"
+
+#: param/loadparm.c:704
+msgid "force group"
+msgstr "grubu zorla"
+
+#: param/loadparm.c:705
+msgid "group"
+msgstr "grup"
+
+#: param/loadparm.c:707
+msgid "read only"
+msgstr "salt okunur"
+
+#: param/loadparm.c:708
+msgid "write ok"
+msgstr "yazma tamam"
+
+#: param/loadparm.c:709
+msgid "writeable"
+msgstr "yazýlabilir"
+
+#: param/loadparm.c:710
+msgid "writable"
+msgstr "yazýlabilir"
+
+#: param/loadparm.c:712
+msgid "create mask"
+msgstr "oluþturma izinleri"
+
+#: param/loadparm.c:713
+msgid "create mode"
+msgstr "oluþturma kipi"
+
+#: param/loadparm.c:714
+msgid "force create mode"
+msgstr "oluþturma kipini zorla"
+
+#: param/loadparm.c:715
+msgid "security mask"
+msgstr "güvenlik izinleri"
+
+#: param/loadparm.c:716
+msgid "force security mode"
+msgstr "güvenlik kipini zorla"
+
+#: param/loadparm.c:717
+msgid "directory mask"
+msgstr "dizin izinleri"
+
+#: param/loadparm.c:718
+msgid "directory mode"
+msgstr "dizin kipi"
+
+#: param/loadparm.c:719
+msgid "force directory mode"
+msgstr "dizin kipini zorla"
+
+#: param/loadparm.c:720
+msgid "directory security mask"
+msgstr "dizin güvenlik izinleri"
+
+#: param/loadparm.c:721
+msgid "force directory security mode"
+msgstr "dizin güvenlik kipini zorla"
+
+#: param/loadparm.c:722
+msgid "inherit permissions"
+msgstr "izinleri ebeveynden al"
+
+#: param/loadparm.c:723
+msgid "guest only"
+msgstr "yalnýz misafir"
+
+#: param/loadparm.c:724
+msgid "only guest"
+msgstr "yalnýz misafir"
+
+#: param/loadparm.c:726
+msgid "guest ok"
+msgstr "misafir tamam"
+
+#: param/loadparm.c:727
+msgid "public"
+msgstr "genel"
+
+#: param/loadparm.c:729
+msgid "only user"
+msgstr "salt kullanýcý"
+
+#: param/loadparm.c:730
+msgid "hosts allow"
+msgstr "hosts izinli"
+
+#: param/loadparm.c:731
+msgid "allow hosts"
+msgstr "hosts izinli"
+
+#: param/loadparm.c:732
+msgid "hosts deny"
+msgstr "hosts izinsiz"
+
+#: param/loadparm.c:733
+msgid "deny hosts"
+msgstr "hosts izinsiz"
+
+#: param/loadparm.c:736
+msgid "Secure Socket Layer Options"
+msgstr "Güvenli Soket Katman Seçenekleri"
+
+#: param/loadparm.c:737
+msgid "ssl"
+msgstr "ssl"
+
+#: param/loadparm.c:739
+msgid "ssl hosts"
+msgstr "ssl hosts"
+
+#: param/loadparm.c:740
+msgid "ssl hosts resign"
+msgstr "ssl hosts istifa"
+
+#: param/loadparm.c:741
+msgid "ssl CA certDir"
+msgstr "ssl CA sertifika dizini"
+
+#: param/loadparm.c:742
+msgid "ssl CA certFile"
+msgstr "ssl CA sertifika dosyasý"
+
+#: param/loadparm.c:743
+msgid "ssl server cert"
+msgstr "ssl sunucu sertifikasý"
+
+#: param/loadparm.c:744
+msgid "ssl server key"
+msgstr "ssl sunucu anahtarý"
+
+#: param/loadparm.c:745
+msgid "ssl client cert"
+msgstr "ssl istemci sertifikasý"
+
+#: param/loadparm.c:746
+msgid "ssl client key"
+msgstr "ssl istemci anahtarý"
+
+#: param/loadparm.c:747
+msgid "ssl require clientcert"
+msgstr "ssl istemci sertifikasý iste"
+
+#: param/loadparm.c:748
+msgid "ssl require servercert"
+msgstr "ssl sunucu sertifikasý iste"
+
+#: param/loadparm.c:749
+msgid "ssl ciphers"
+msgstr "ssl þifreleri"
+
+#: param/loadparm.c:750
+msgid "ssl version"
+msgstr "ssl sürümü"
+
+#: param/loadparm.c:751
+msgid "ssl compatibility"
+msgstr "ssl uyumluluðu"
+
+#: param/loadparm.c:754
+msgid "Logging Options"
+msgstr "Günlük Kaydý Seçenekleri"
+
+#: param/loadparm.c:755
+msgid "log level"
+msgstr "günlük seviyesi"
+
+#: param/loadparm.c:756
+msgid "debuglevel"
+msgstr "hata ayýklama seviyesi"
+
+#: param/loadparm.c:757
+msgid "syslog"
+msgstr "sistem günlüðü"
+
+#: param/loadparm.c:758
+msgid "syslog only"
+msgstr "salt sistem günlüðü"
+
+#: param/loadparm.c:759
+msgid "log file"
+msgstr "günlük dosyasý"
+
+#: param/loadparm.c:761
+msgid "max log size"
+msgstr "maksimum günlük büyüklüðü"
+
+#: param/loadparm.c:762
+msgid "timestamp logs"
+msgstr "zaman damgasý günlükleri"
+
+#: param/loadparm.c:763
+msgid "debug timestamp"
+msgstr "hata ayýklama zaman damgasý"
+
+#: param/loadparm.c:764
+msgid "debug hires timestamp"
+msgstr "hata ayýklama yüksek çözünürlüklü zaman damgasý"
+
+#: param/loadparm.c:765
+msgid "debug pid"
+msgstr "hata ayýklama pid"
+
+#: param/loadparm.c:766
+msgid "debug uid"
+msgstr "hata ayýklama uid"
+
+#: param/loadparm.c:768
+msgid "Protocol Options"
+msgstr "Protokol Seçenekleri"
+
+#: param/loadparm.c:770
+msgid "protocol"
+msgstr "protokol"
+
+#: param/loadparm.c:771
+msgid "large readwrite"
+msgstr "büyük oku/yaz"
+
+#: param/loadparm.c:772
+msgid "max protocol"
+msgstr "max protokol"
+
+#: param/loadparm.c:773
+msgid "min protocol"
+msgstr "min protokol"
+
+#: param/loadparm.c:774
+msgid "unicode"
+msgstr "unicode"
+
+#: param/loadparm.c:775
+msgid "read bmpx"
+msgstr "bmpx oku"
+
+#: param/loadparm.c:776
+msgid "read raw"
+msgstr "ham oku"
+
+#: param/loadparm.c:777
+msgid "write raw"
+msgstr "ham yaz"
+
+#: param/loadparm.c:779
+msgid "nt smb support"
+msgstr "nt smb desteði"
+
+#: param/loadparm.c:780
+msgid "nt pipe support"
+msgstr "nt verihattý desteði"
+
+#: param/loadparm.c:781
+msgid "nt acl support"
+msgstr "nt acl desteði"
+
+#: param/loadparm.c:782
+msgid "announce version"
+msgstr "sürümü bildir"
+
+#: param/loadparm.c:783
+msgid "announce as"
+msgstr "bildir"
+
+#: param/loadparm.c:784
+msgid "max mux"
+msgstr "maksimum mux"
+
+#: param/loadparm.c:785
+msgid "max xmit"
+msgstr "maksimum xmit"
+
+#: param/loadparm.c:787
+msgid "name resolve order"
+msgstr "ad çözümleme sýrasý"
+
+#: param/loadparm.c:788
+msgid "max packet"
+msgstr "maksimum paket"
+
+#: param/loadparm.c:789
+msgid "packet size"
+msgstr "paket büyüklüðü"
+
+#: param/loadparm.c:790
+msgid "max ttl"
+msgstr "maksimum ttl"
+
+#: param/loadparm.c:791
+msgid "max wins ttl"
+msgstr "maksimum wins ttl"
+
+#: param/loadparm.c:792
+msgid "min wins ttl"
+msgstr "minimum wins ttl"
+
+#: param/loadparm.c:793
+msgid "time server"
+msgstr "zaman sunucusu"
+
+#: param/loadparm.c:795
+msgid "Tuning Options"
+msgstr "Ayar Seçenekleri"
+
+#: param/loadparm.c:797
+msgid "change notify timeout"
+msgstr "zamanaþýmý bildirmesini deðiþtir"
+
+#: param/loadparm.c:798
+msgid "deadtime"
+msgstr "ölüzaman"
+
+#: param/loadparm.c:799
+msgid "getwd cache"
+msgstr "getwd arabelleði"
+
+#: param/loadparm.c:800
+msgid "keepalive"
+msgstr "hayattatut"
+
+#: param/loadparm.c:802
+msgid "lpq cache time"
+msgstr "lpq arabellek zamaný"
+
+#: param/loadparm.c:803
+msgid "max smbd processes"
+msgstr "maksimum smbd süreci"
+
+#: param/loadparm.c:804
+msgid "max connections"
+msgstr "maksimum baðlantý"
+
+#: param/loadparm.c:805
+msgid "paranoid server security"
+msgstr "yüksek dereceli sunucu güvenliði"
+
+#: param/loadparm.c:806
+msgid "max disk size"
+msgstr "maksimum disk büyüklüðü"
+
+#: param/loadparm.c:807
+msgid "max open files"
+msgstr "maksimum açýk dosya"
+
+#: param/loadparm.c:808
+msgid "min print space"
+msgstr "minimum yazma alaný"
+
+#: param/loadparm.c:809
+msgid "read size"
+msgstr "okuma boyu"
+
+#: param/loadparm.c:811
+msgid "socket options"
+msgstr "soket seçenekleri"
+
+#: param/loadparm.c:812
+msgid "stat cache size"
+msgstr "durum arabelleði boyu"
+
+#: param/loadparm.c:813
+msgid "strict allocate"
+msgstr "sýký ayýrma"
+
+#: param/loadparm.c:814
+msgid "strict sync"
+msgstr "sýký senkronizasyon"
+
+#: param/loadparm.c:815
+msgid "sync always"
+msgstr "herzaman senkronize"
+
+#: param/loadparm.c:816
+msgid "use mmap"
+msgstr "bellek eþlemesi kullan"
+
+#: param/loadparm.c:817
+msgid "hostname lookups"
+msgstr "sunucu adý arama"
+
+#: param/loadparm.c:818
+msgid "write cache size"
+msgstr "yazma arabellek boyu"
+
+#: param/loadparm.c:820
+msgid "Printing Options"
+msgstr "Yazdýrma Seçenekleri"
+
+#: param/loadparm.c:822
+msgid "total print jobs"
+msgstr "toplam yazdýrma iþleri"
+
+#: param/loadparm.c:823
+msgid "max print jobs"
+msgstr "maksimum yazdýrma iþi"
+
+#: param/loadparm.c:824
+msgid "load printers"
+msgstr "yazýcýlarý yükle"
+
+#: param/loadparm.c:825
+msgid "printcap name"
+msgstr "printcap adý"
+
+#: param/loadparm.c:826
+msgid "printcap"
+msgstr "printcap"
+
+#: param/loadparm.c:827
+msgid "printable"
+msgstr "yazdýrýlabilir"
+
+#: param/loadparm.c:828
+msgid "print ok"
+msgstr "yazdýrma tamam"
+
+#: param/loadparm.c:829
+msgid "postscript"
+msgstr "postscript"
+
+#: param/loadparm.c:830
+msgid "printing"
+msgstr "yazdýrýyor"
+
+#: param/loadparm.c:831
+msgid "print command"
+msgstr "yazdýrma komutu"
+
+#: param/loadparm.c:832
+msgid "disable spoolss"
+msgstr "kuyruðu etkisizleþtir"
+
+#: param/loadparm.c:833
+msgid "lpq command"
+msgstr "lpq komutu"
+
+#: param/loadparm.c:834
+msgid "lprm command"
+msgstr "lprm komutu"
+
+#: param/loadparm.c:835
+msgid "lppause command"
+msgstr "lppause komutu"
+
+#: param/loadparm.c:836
+msgid "lpresume command"
+msgstr "lpresume komutu"
+
+#: param/loadparm.c:837
+msgid "queuepause command"
+msgstr "queuepause komutu"
+
+#: param/loadparm.c:838
+msgid "queueresume command"
+msgstr "queueresume komutu"
+
+#: param/loadparm.c:840
+msgid "enumports command"
+msgstr "port listele komutu"
+
+#: param/loadparm.c:841
+msgid "addprinter command"
+msgstr "yazýcý ekle komutu"
+
+#: param/loadparm.c:842
+msgid "deleteprinter command"
+msgstr "yazýcý sil komutu"
+
+#: param/loadparm.c:843
+msgid "show add printer wizard"
+msgstr "yazýcý ekleme sihirbazýný göster"
+
+#: param/loadparm.c:844
+msgid "os2 driver map"
+msgstr "os2 sürücü eþlemesi"
+
+#: param/loadparm.c:846
+msgid "printer name"
+msgstr "yazýcý adý"
+
+#: param/loadparm.c:847
+msgid "printer"
+msgstr "yazýcý"
+
+#: param/loadparm.c:848
+msgid "use client driver"
+msgstr "istemci sürücüsü kullan"
+
+#: param/loadparm.c:849
+msgid "printer driver"
+msgstr "yazýcý sürücüsü"
+
+#: param/loadparm.c:850
+msgid "printer driver file"
+msgstr "yazýcý sürücü dosyasý"
+
+#: param/loadparm.c:851
+msgid "printer driver location"
+msgstr "yazýcý sürücüsü yeri"
+
+#: param/loadparm.c:853
+msgid "Filename Handling"
+msgstr "Dosyaadý Ýþlenmesi"
+
+#: param/loadparm.c:854
+msgid "strip dot"
+msgstr "noktalarý bastýr"
+
+#: param/loadparm.c:856
+msgid "mangled stack"
+msgstr "karýþtýrýlmýþ yýðýt"
+
+#: param/loadparm.c:857
+msgid "default case"
+msgstr "öntanýmlý büyük/küçük harf"
+
+#: param/loadparm.c:858
+msgid "case sensitive"
+msgstr "büyük küçük harfe duyarlý"
+
+#: param/loadparm.c:859
+msgid "casesignames"
+msgstr "casesignames"
+
+#: param/loadparm.c:860
+msgid "preserve case"
+msgstr "büyük küçük harf ayrýmýný tut"
+
+#: param/loadparm.c:861
+msgid "short preserve case"
+msgstr "kýsa büyük küçük harf ayrýmýný tut"
+
+#: param/loadparm.c:862
+msgid "mangle case"
+msgstr "büyük küçük harf harmanla"
+
+#: param/loadparm.c:863
+msgid "mangling char"
+msgstr "karakter harmanlanýyor"
+
+#: param/loadparm.c:864
+msgid "hide dot files"
+msgstr "nokta ile baþlayan dosyalarý gizle"
+
+#: param/loadparm.c:865
+msgid "hide unreadable"
+msgstr "okunamazlarý sakla"
+
+#: param/loadparm.c:866
+msgid "delete veto files"
+msgstr "veto dosyalarýný sil"
+
+#: param/loadparm.c:867
+msgid "veto files"
+msgstr "veto dosyalarý"
+
+#: param/loadparm.c:868
+msgid "hide files"
+msgstr "dosyalarý gizle"
+
+#: param/loadparm.c:869
+msgid "veto oplock files"
+msgstr "veto oplock dosyalarý"
+
+#: param/loadparm.c:870
+msgid "map system"
+msgstr "sistemi eþle"
+
+#: param/loadparm.c:871
+msgid "map hidden"
+msgstr "gizlileri eþle"
+
+#: param/loadparm.c:872
+msgid "map archive"
+msgstr "arþivi eþle"
+
+#: param/loadparm.c:873
+msgid "mangled names"
+msgstr "harmanlanmýþ isimler"
+
+#: param/loadparm.c:874
+msgid "mangled map"
+msgstr "harmanlanmýþ eþleþme"
+
+#: param/loadparm.c:875
+msgid "stat cache"
+msgstr "durum arabelleði"
+
+#: param/loadparm.c:877
+msgid "Domain Options"
+msgstr "Alan Seçenekleri"
+
+#: param/loadparm.c:879
+msgid "domain admin group"
+msgstr "alan yönetici grubu"
+
+#: param/loadparm.c:880
+msgid "domain guest group"
+msgstr "alan misafir grubu"
+
+#: param/loadparm.c:883
+msgid "groupname map"
+msgstr "grup adý eþlemesi"
+
+#: param/loadparm.c:886
+msgid "machine password timeout"
+msgstr "makina þifresi zamanaþýmý"
+
+#: param/loadparm.c:888
+msgid "Logon Options"
+msgstr "Sistem Giriþ Seçenekleri"
+
+#: param/loadparm.c:890
+msgid "add user script"
+msgstr "kullanýcý ekleme betiði"
+
+#: param/loadparm.c:891
+msgid "delete user script"
+msgstr "kullanýcý silme betiði"
+
+#: param/loadparm.c:892
+msgid "add group script"
+msgstr "grup ekleme betiði"
+
+#: param/loadparm.c:893
+msgid "delete group script"
+msgstr "grup silme betiði"
+
+#: param/loadparm.c:894
+msgid "add user to group script"
+msgstr "gruba kullanýcý ekleme betiði"
+
+#: param/loadparm.c:895
+msgid "delete user from group script"
+msgstr "gruptan kullanýcý silme betiði"
+
+#: param/loadparm.c:896
+msgid "add machine script"
+msgstr "makina ekleme betiði"
+
+#: param/loadparm.c:897
+msgid "shutdown script"
+msgstr "sistem kapanýþ betiði"
+
+#: param/loadparm.c:898
+msgid "abort shutdown script"
+msgstr "sistem kapanýþ betiðini durdur"
+
+#: param/loadparm.c:900
+msgid "logon script"
+msgstr "sistem giriþ betiði"
+
+#: param/loadparm.c:901
+msgid "logon path"
+msgstr "sistem giriþ yolu"
+
+#: param/loadparm.c:902
+msgid "logon drive"
+msgstr "sistem giriþ aygýtý"
+
+#: param/loadparm.c:903
+msgid "logon home"
+msgstr "sistem giriþ kökü"
+
+#: param/loadparm.c:904
+msgid "domain logons"
+msgstr "alan giriþleri"
+
+#: param/loadparm.c:906
+msgid "Browse Options"
+msgstr "Gözatma Seçenekleri"
+
+#: param/loadparm.c:908
+msgid "os level"
+msgstr "iþletim sistem seviyesi"
+
+#: param/loadparm.c:909
+msgid "lm announce"
+msgstr "lm bildirimi"
+
+#: param/loadparm.c:910
+msgid "lm interval"
+msgstr "lm aralýðý"
+
+#: param/loadparm.c:911
+msgid "preferred master"
+msgstr "tercih edilen ana alan sunucusu"
+
+#: param/loadparm.c:912
+msgid "prefered master"
+msgstr "tercih edilen ana alan sunucusu"
+
+#: param/loadparm.c:913
+msgid "local master"
+msgstr "yerel alan sunucusu"
+
+#: param/loadparm.c:914
+msgid "domain master"
+msgstr "alan sunucusu"
+
+#: param/loadparm.c:915
+msgid "browse list"
+msgstr "gözatma listesi"
+
+#: param/loadparm.c:916
+msgid "browseable"
+msgstr "gözatýlabilir"
+
+#: param/loadparm.c:917
+msgid "browsable"
+msgstr "gözatýlabilir"
+
+#: param/loadparm.c:918
+msgid "enhanced browsing"
+msgstr "geliþkin gözatma"
+
+#: param/loadparm.c:920
+msgid "WINS Options"
+msgstr "WINS Seçenekleri"
+
+#: param/loadparm.c:921
+msgid "dns proxy"
+msgstr "dns proxy"
+
+#: param/loadparm.c:922
+msgid "wins proxy"
+msgstr "wins proxy"
+
+#: param/loadparm.c:924
+msgid "wins server"
+msgstr "wins sunucusu"
+
+#: param/loadparm.c:925
+msgid "wins support"
+msgstr "wins desteði"
+
+#: param/loadparm.c:926
+msgid "wins hook"
+msgstr "wins giriþi"
+
+#: param/loadparm.c:928
+msgid "Locking Options"
+msgstr "Kilitleme Seçenekleri"
+
+#: param/loadparm.c:930
+msgid "blocking locks"
+msgstr "engelleyen kilitler"
+
+#: param/loadparm.c:931
+msgid "fake oplocks"
+msgstr "sahte oplocklar"
+
+#: param/loadparm.c:932
+msgid "kernel oplocks"
+msgstr "çekirdek oplocklarý"
+
+#: param/loadparm.c:933
+msgid "locking"
+msgstr "kilitliyor"
+
+#: param/loadparm.c:935
+msgid "oplocks"
+msgstr "oplocklar"
+
+#: param/loadparm.c:936
+msgid "level2 oplocks"
+msgstr "Seviye 2 oplocklar"
+
+#: param/loadparm.c:937
+msgid "oplock break wait time"
+msgstr "oplock kýrma bekleme süresi"
+
+#: param/loadparm.c:938
+msgid "oplock contention limit"
+msgstr "oplock ihtilaf limiti"
+
+#: param/loadparm.c:939
+msgid "posix locking"
+msgstr "posix kilitlemesi"
+
+#: param/loadparm.c:940
+msgid "strict locking"
+msgstr "sýký kilitleme"
+
+#: param/loadparm.c:941
+msgid "share modes"
+msgstr "paylaþým kipleri"
+
+#: param/loadparm.c:944
+msgid "Ldap Options"
+msgstr "Ldap Seçenekleri"
+
+#: param/loadparm.c:946
+msgid "ldap server"
+msgstr "ldap sunucusu"
+
+#: param/loadparm.c:947
+msgid "ldap port"
+msgstr "ldap portu"
+
+#: param/loadparm.c:948
+msgid "ldap suffix"
+msgstr "ldap soneki"
+
+#: param/loadparm.c:949
+msgid "ldap filter"
+msgstr "ldap filtresi"
+
+#: param/loadparm.c:950
+msgid "ldap root"
+msgstr "ldap kökü"
+
+#: param/loadparm.c:951
+msgid "ldap root passwd"
+msgstr "ldap kök þifresi"
+
+#: param/loadparm.c:954
+msgid "Miscellaneous Options"
+msgstr "Diðer Seçenekler"
+
+#: param/loadparm.c:955
+msgid "add share command"
+msgstr "paylaþým ekle komutu"
+
+#: param/loadparm.c:956
+msgid "change share command"
+msgstr "paylaþým deðiþtir komutu"
+
+#: param/loadparm.c:957
+msgid "delete share command"
+msgstr "paylaþým sil komutu"
+
+#: param/loadparm.c:959
+msgid "config file"
+msgstr "ayar dosyasý"
+
+#: param/loadparm.c:960
+msgid "preload"
+msgstr "önyükle"
+
+#: param/loadparm.c:961
+msgid "auto services"
+msgstr "otomatik servisler"
+
+#: param/loadparm.c:962
+msgid "lock dir"
+msgstr "kilit dizini"
+
+#: param/loadparm.c:963
+msgid "lock directory"
+msgstr "kilit dizini"
+
+#: param/loadparm.c:965
+msgid "utmp directory"
+msgstr "utmp dizini"
+
+#: param/loadparm.c:966
+msgid "wtmp directory"
+msgstr "wtmp dizini"
+
+#: param/loadparm.c:967
+msgid "utmp"
+msgstr "utmp"
+
+#: param/loadparm.c:970
+msgid "default service"
+msgstr "öntanýmlý servis"
+
+#: param/loadparm.c:971
+msgid "default"
+msgstr "öntanýmlý"
+
+#: param/loadparm.c:972
+msgid "message command"
+msgstr "ileti komutu"
+
+#: param/loadparm.c:973
+msgid "dfree command"
+msgstr "dfree komutu"
+
+#: param/loadparm.c:974
+msgid "remote announce"
+msgstr "uzak bildirim"
+
+#: param/loadparm.c:975
+msgid "remote browse sync"
+msgstr "uzak gözatma senkronizasyonu"
+
+#: param/loadparm.c:976
+msgid "socket address"
+msgstr "soket adresi"
+
+#: param/loadparm.c:977
+msgid "homedir map"
+msgstr "evdizini eþlemesi"
+
+#: param/loadparm.c:978
+msgid "time offset"
+msgstr "zaman kaydýrmasý"
+
+#: param/loadparm.c:979
+msgid "NIS homedir"
+msgstr "NIS evdizini"
+
+#: param/loadparm.c:980
+msgid "-valid"
+msgstr "-geçerli"
+
+#: param/loadparm.c:982
+msgid "copy"
+msgstr "kopyala"
+
+#: param/loadparm.c:983
+msgid "include"
+msgstr "ekle"
+
+#: param/loadparm.c:984
+msgid "exec"
+msgstr "çalýþtýr"
+
+#: param/loadparm.c:985
+msgid "preexec"
+msgstr "preexec"
+
+#: param/loadparm.c:987
+msgid "preexec close"
+msgstr "preexec close"
+
+#: param/loadparm.c:988
+msgid "postexec"
+msgstr "postexec"
+
+#: param/loadparm.c:989
+msgid "root preexec"
+msgstr "root preexec"
+
+#: param/loadparm.c:990
+msgid "root preexec close"
+msgstr "root preexec close"
+
+#: param/loadparm.c:991
+msgid "root postexec"
+msgstr "root postexec"
+
+#: param/loadparm.c:992
+msgid "available"
+msgstr "mevcut"
+
+#: param/loadparm.c:993
+msgid "volume"
+msgstr "volume"
+
+#: param/loadparm.c:994
+msgid "fstype"
+msgstr "dosya sistem tipi"
+
+#: param/loadparm.c:995
+msgid "set directory"
+msgstr "dizini belirle"
+
+#: param/loadparm.c:996
+msgid "source environment"
+msgstr "source environment"
+
+#: param/loadparm.c:997
+msgid "wide links"
+msgstr "wide links"
+
+#: param/loadparm.c:998
+msgid "follow symlinks"
+msgstr "sembolik baðlarý izle"
+
+#: param/loadparm.c:999
+msgid "dont descend"
+msgstr "dont descend"
+
+#: param/loadparm.c:1000
+msgid "magic script"
+msgstr "magic script"
+
+#: param/loadparm.c:1001
+msgid "magic output"
+msgstr "magic output"
+
+#: param/loadparm.c:1002
+msgid "delete readonly"
+msgstr "salt okunurlarý sil"
+
+#: param/loadparm.c:1003
+msgid "dos filemode"
+msgstr "dos dosya kipi"
+
+#: param/loadparm.c:1004
+msgid "dos filetimes"
+msgstr "dos dosya zamanlarý"
+
+#: param/loadparm.c:1005
+msgid "dos filetime resolution"
+msgstr "dos dosya zamaný çözünürlüðü"
+
+#: param/loadparm.c:1007
+msgid "fake directory create times"
+msgstr "dizin oluþma zamanlarýný taklit et"
+
+#: param/loadparm.c:1008
+msgid "panic action"
+msgstr "panik iþlemi"
+
+#: param/loadparm.c:1009
+msgid "hide local users"
+msgstr "yerel kullanýcýlarý sakla"
+
+#: param/loadparm.c:1012
+msgid "VFS options"
+msgstr "VFS Seçenekleri"
+
+#: param/loadparm.c:1014
+msgid "vfs object"
+msgstr "vfs nesnesi"
+
+#: param/loadparm.c:1015
+msgid "vfs options"
+msgstr "vfs seçenekleri"
+
+#: param/loadparm.c:1018
+msgid "msdfs root"
+msgstr "msdfs kökü"
+
+#: param/loadparm.c:1019
+msgid "host msdfs"
+msgstr "host msdfs"
+
+#: param/loadparm.c:1021
+msgid "Winbind options"
+msgstr "Winbind seçenekleri"
+
+#: param/loadparm.c:1023
+msgid "winbind uid"
+msgstr "winbind uid"
+
+#: param/loadparm.c:1024
+msgid "winbind gid"
+msgstr "winbind gid"
+
+#: param/loadparm.c:1025
+msgid "template homedir"
+msgstr "örnek ev dizini"
+
+#: param/loadparm.c:1026
+msgid "template shell"
+msgstr "örnek kabuk"
+
+#: param/loadparm.c:1027
+msgid "winbind separator"
+msgstr "winbind ayracý"
+
+#: param/loadparm.c:1028
+msgid "winbind cache time"
+msgstr "winbind arabellek zamaný"
+
+#: param/loadparm.c:1029
+msgid "winbind enum users"
+msgstr "winbind kullanýcý listele"
+
+#: param/loadparm.c:1030
+msgid "winbind enum groups"
+msgstr "winbind grup listele"
+
diff --git a/source/popt/.cvsignore b/source/popt/.cvsignore
new file mode 100644
index 00000000000..86b08b58d2c
--- /dev/null
+++ b/source/popt/.cvsignore
@@ -0,0 +1,8 @@
+ID
+Makefile
+config.cache
+config.h
+config.log
+config.status
+rsync
+zlib/dummy
diff --git a/source/popt/CHANGES b/source/popt/CHANGES
new file mode 100644
index 00000000000..b6ab2aa3088
--- /dev/null
+++ b/source/popt/CHANGES
@@ -0,0 +1,43 @@
+1.3 ->
+ - heavy dose of const's
+ - poptParseArgvString() now NULL terminates the list
+
+1.2.3 -> 1.3
+ - added support for single -
+ - misc bug fixes
+ - portability improvements
+
+1.2.2 -> 1.2.3
+ - fixed memset() in help message generation (Dale Hawkins)
+ - added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins)
+ - const'ified poptParseArgvString (Jeff Garzik)
+
+1.2.1 -> 1.2.2
+ - fixed bug in chaind alias happens which seems to have only
+ affected --triggers in rpm
+ - added POPT_ARG_VAL
+ - popt.3 installed by default
+
+1.2 -> 1.2.1
+ - added POPT_ARG_INTL_DOMAIN (Elliot Lee)
+ - updated Makefile's to be more GNUish (Elliot Lee)
+
+1.1 -> 1.2
+ - added popt.3 man page (Robert Lynch)
+ - don't use mmap anymore (its lack of portability isn't worth the
+ trouble)
+ - added test script
+ - added support for exec
+ - removed support for *_POPT_ALIASES env variable -- it was a bad
+ idea
+ - reorganized into multiple source files
+ - added automatic help generation, POPT_AUTOHELP
+ - added table callbacks
+ - added table inclusion
+ - updated man page for new features
+ - added test scripts
+
+1.0 -> 1.1
+ - moved to autoconf (Fred Fish)
+ - added STRERROR replacement (Norbert Warmuth)
+ - added const keywords (Bruce Perens)
diff --git a/source/popt/COPYING b/source/popt/COPYING
new file mode 100644
index 00000000000..b4c7ca876c6
--- /dev/null
+++ b/source/popt/COPYING
@@ -0,0 +1,22 @@
+Copyright (c) 1998 Red Hat Software
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
diff --git a/source/popt/README b/source/popt/README
new file mode 100644
index 00000000000..7fccc836ffa
--- /dev/null
+++ b/source/popt/README
@@ -0,0 +1,18 @@
+This is the popt command line option parsing library. While it is similiar
+to getopt(3), it contains a number of enhancements, including:
+
+ 1) popt is fully reentrant
+ 2) popt can parse arbitrary argv[] style arrays while
+ getopt(2) makes this quite difficult
+ 3) popt allows users to alias command line arguments
+ 4) popt provides convience functions for parsting strings
+ into argv[] style arrays
+
+popt is used by rpm, the Red Hat install program, and many other Red Hat
+utilities, all of which provide excellent examples of how to use popt.
+Complete documentation on popt is available in popt.ps (included in this
+tarball), which is excerpted with permission from the book "Linux
+Application Development" by Michael K. Johnson and Erik Troan (availble
+from Addison Wesley in May, 1998).
+
+Comments on popt should be addressed to ewt@redhat.com.
diff --git a/source/popt/dummy.in b/source/popt/dummy.in
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/popt/dummy.in
diff --git a/source/popt/findme.c b/source/popt/findme.c
new file mode 100644
index 00000000000..f2ad05bb3fb
--- /dev/null
+++ b/source/popt/findme.c
@@ -0,0 +1,46 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#include "system.h"
+#include "findme.h"
+
+const char * findProgramPath(const char * argv0) {
+ char * path = getenv("PATH");
+ char * pathbuf;
+ char * start, * chptr;
+ char * buf, *local = NULL;
+
+ /* If there is a / in the argv[0], it has to be an absolute
+ path */
+ if (strchr(argv0, '/'))
+ return xstrdup(argv0);
+
+ if (!path) return NULL;
+
+ local = start = pathbuf = malloc(strlen(path) + 1);
+ buf = malloc(strlen(path) + strlen(argv0) + 2);
+ strcpy(pathbuf, path);
+
+ chptr = NULL;
+ do {
+ if ((chptr = strchr(start, ':')))
+ *chptr = '\0';
+ sprintf(buf, "%s/%s", start, argv0);
+
+ if (!access(buf, X_OK)) {
+ if (local) free(local);
+ return buf;
+ }
+
+ if (chptr)
+ start = chptr + 1;
+ else
+ start = NULL;
+ } while (start && *start);
+
+ free(buf);
+ if (local) free(local);
+
+ return NULL;
+}
diff --git a/source/popt/findme.h b/source/popt/findme.h
new file mode 100644
index 00000000000..5e93963d603
--- /dev/null
+++ b/source/popt/findme.h
@@ -0,0 +1,10 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#ifndef H_FINDME
+#define H_FINDME
+
+const char * findProgramPath(const char * argv0);
+
+#endif
diff --git a/source/popt/popt.c b/source/popt/popt.c
new file mode 100644
index 00000000000..9fa8650312c
--- /dev/null
+++ b/source/popt/popt.c
@@ -0,0 +1,782 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#include "system.h"
+#include "findme.h"
+#include "poptint.h"
+
+#ifndef HAVE_STRERROR
+static char * strerror(int errno) {
+ extern int sys_nerr;
+ extern char * sys_errlist[];
+
+ if ((0 <= errno) && (errno < sys_nerr))
+ return sys_errlist[errno];
+ else
+ return POPT_("unknown errno");
+}
+#endif
+
+void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
+ if (con->execPath) xfree(con->execPath);
+ con->execPath = xstrdup(path);
+ con->execAbsolute = allowAbsolute;
+}
+
+static void invokeCallbacks(poptContext con, const struct poptOption * table,
+ int post) {
+ const struct poptOption * opt = table;
+ poptCallbackType cb;
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ invokeCallbacks(con, opt->arg, post);
+ } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
+ ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
+ ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
+ cb = (poptCallbackType)opt->arg;
+ cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
+ NULL, NULL, opt->descrip);
+ }
+ opt++;
+ }
+}
+
+poptContext poptGetContext(const char * name, int argc, const char ** argv,
+ const struct poptOption * options, int flags) {
+ poptContext con = malloc(sizeof(*con));
+
+ memset(con, 0, sizeof(*con));
+
+ con->os = con->optionStack;
+ con->os->argc = argc;
+ con->os->argv = argv;
+ con->os->argb = NULL;
+
+ if (!(flags & POPT_CONTEXT_KEEP_FIRST))
+ con->os->next = 1; /* skip argv[0] */
+
+ con->leftovers = calloc( (argc + 1), sizeof(char *) );
+ con->options = options;
+ con->aliases = NULL;
+ con->numAliases = 0;
+ con->flags = flags;
+ con->execs = NULL;
+ con->numExecs = 0;
+ con->finalArgvAlloced = argc * 2;
+ con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
+ con->execAbsolute = 1;
+ con->arg_strip = NULL;
+
+ if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
+ con->flags |= POPT_CONTEXT_POSIXMEHARDER;
+
+ if (name)
+ con->appName = strcpy(malloc(strlen(name) + 1), name);
+
+ invokeCallbacks(con, con->options, 0);
+
+ return con;
+}
+
+static void cleanOSE(struct optionStackEntry *os)
+{
+ if (os->nextArg) {
+ xfree(os->nextArg);
+ os->nextArg = NULL;
+ }
+ if (os->argv) {
+ xfree(os->argv);
+ os->argv = NULL;
+ }
+ if (os->argb) {
+ PBM_FREE(os->argb);
+ os->argb = NULL;
+ }
+}
+
+void poptResetContext(poptContext con) {
+ int i;
+
+ while (con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ if (con->os->argb) {
+ PBM_FREE(con->os->argb);
+ con->os->argb = NULL;
+ }
+ con->os->currAlias = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->nextArg = NULL;
+ con->os->next = 1; /* skip argv[0] */
+
+ con->numLeftovers = 0;
+ con->nextLeftover = 0;
+ con->restLeftover = 0;
+ con->doExec = NULL;
+
+ for (i = 0; i < con->finalArgvCount; i++) {
+ if (con->finalArgv[i]) {
+ xfree(con->finalArgv[i]);
+ con->finalArgv[i] = NULL;
+ }
+ }
+
+ con->finalArgvCount = 0;
+
+ if (con->arg_strip) {
+ PBM_FREE(con->arg_strip);
+ con->arg_strip = NULL;
+ }
+}
+
+/* Only one of longName, shortName may be set at a time */
+static int handleExec(poptContext con, char * longName, char shortName) {
+ int i;
+
+ i = con->numExecs - 1;
+ if (longName) {
+ while (i >= 0 && (!con->execs[i].longName ||
+ strcmp(con->execs[i].longName, longName))) i--;
+ } else {
+ while (i >= 0 &&
+ con->execs[i].shortName != shortName) i--;
+ }
+
+ if (i < 0) return 0;
+
+ if (con->flags & POPT_CONTEXT_NO_EXEC)
+ return 1;
+
+ if (con->doExec == NULL) {
+ con->doExec = con->execs + i;
+ return 1;
+ }
+
+ /* We already have an exec to do; remember this option for next
+ time 'round */
+ if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
+ con->finalArgvAlloced += 10;
+ con->finalArgv = realloc(con->finalArgv,
+ sizeof(*con->finalArgv) * con->finalArgvAlloced);
+ }
+
+ i = con->finalArgvCount++;
+ { char *s = malloc((longName ? strlen(longName) : 0) + 3);
+ if (longName)
+ sprintf(s, "--%s", longName);
+ else
+ sprintf(s, "-%c", shortName);
+ con->finalArgv[i] = s;
+ }
+
+ return 1;
+}
+
+/* Only one of longName, shortName may be set at a time */
+static int handleAlias(poptContext con, const char * longName, char shortName,
+ /*@keep@*/ const char * nextCharArg) {
+ int i;
+
+ if (con->os->currAlias && con->os->currAlias->longName && longName &&
+ !strcmp(con->os->currAlias->longName, longName))
+ return 0;
+ if (con->os->currAlias && shortName &&
+ shortName == con->os->currAlias->shortName)
+ return 0;
+
+ i = con->numAliases - 1;
+ if (longName) {
+ while (i >= 0 && (!con->aliases[i].longName ||
+ strcmp(con->aliases[i].longName, longName))) i--;
+ } else {
+ while (i >= 0 &&
+ con->aliases[i].shortName != shortName) i--;
+ }
+
+ if (i < 0) return 0;
+
+ if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ if (nextCharArg && *nextCharArg)
+ con->os->nextCharArg = nextCharArg;
+
+ con->os++;
+ con->os->next = 0;
+ con->os->stuffed = 0;
+ con->os->nextArg = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->currAlias = con->aliases + i;
+ poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
+ &con->os->argc, &con->os->argv);
+ con->os->argb = NULL;
+
+ return 1;
+}
+
+static void execCommand(poptContext con) {
+ const char ** argv;
+ int pos = 0;
+ const char * script = con->doExec->script;
+
+ argv = malloc(sizeof(*argv) *
+ (6 + con->numLeftovers + con->finalArgvCount));
+
+ if (!con->execAbsolute && strchr(script, '/')) return;
+
+ if (!strchr(script, '/') && con->execPath) {
+ char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
+ sprintf(s, "%s/%s", con->execPath, script);
+ argv[pos] = s;
+ } else {
+ argv[pos] = script;
+ }
+ pos++;
+
+ argv[pos] = findProgramPath(con->os->argv[0]);
+ if (argv[pos]) pos++;
+ argv[pos++] = ";";
+
+ memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
+ pos += con->finalArgvCount;
+
+ if (con->numLeftovers) {
+ argv[pos++] = "--";
+ memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
+ pos += con->numLeftovers;
+ }
+
+ argv[pos++] = NULL;
+
+#ifdef __hpux
+ setresuid(getuid(), getuid(),-1);
+#else
+/*
+ * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
+ * XXX sez' Timur Bakeyev <mc@bat.ru>
+ * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
+ */
+#if defined(HAVE_SETUID)
+ setuid(getuid());
+#elif defined (HAVE_SETREUID)
+ setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
+#else
+ ; /* Can't drop privileges */
+#endif
+#endif
+
+ execvp(argv[0], (char *const *)argv);
+}
+
+/*@observer@*/ static const struct poptOption *
+findOption(const struct poptOption * table, const char * longName,
+ char shortName,
+ /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
+ int singleDash)
+{
+ const struct poptOption * opt = table;
+ const struct poptOption * opt2;
+ const struct poptOption * cb = NULL;
+
+ /* This happens when a single - is given */
+ if (singleDash && !shortName && !*longName)
+ shortName = '-';
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ opt2 = findOption(opt->arg, longName, shortName, callback,
+ callbackData, singleDash);
+ if (opt2) {
+ if (*callback && !*callbackData)
+ *callbackData = opt->descrip;
+ return opt2;
+ }
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
+ cb = opt;
+ } else if (longName && opt->longName &&
+ (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
+ !strcmp(longName, opt->longName)) {
+ break;
+ } else if (shortName && shortName == opt->shortName) {
+ break;
+ }
+ opt++;
+ }
+
+ if (!opt->longName && !opt->shortName) return NULL;
+ *callbackData = NULL;
+ *callback = NULL;
+ if (cb) {
+ *callback = (poptCallbackType)cb->arg;
+ if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
+ *callbackData = cb->descrip;
+ }
+
+ return opt;
+}
+
+static const char *findNextArg(poptContext con, unsigned argx, int delete)
+{
+ struct optionStackEntry * os = con->os;
+ const char * arg;
+
+ do {
+ int i;
+ arg = NULL;
+ while (os->next == os->argc && os > con->optionStack) os--;
+ if (os->next == os->argc && os == con->optionStack) break;
+ for (i = os->next; i < os->argc; i++) {
+ if (os->argb && PBM_ISSET(i, os->argb)) continue;
+ if (*os->argv[i] == '-') continue;
+ if (--argx > 0) continue;
+ arg = os->argv[i];
+ if (delete) {
+ if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
+ PBM_SET(i, os->argb);
+ }
+ break;
+ }
+ if (os > con->optionStack) os--;
+ } while (arg == NULL);
+ return arg;
+}
+
+static /*@only@*/ const char * expandNextArg(poptContext con, const char * s)
+{
+ const char *a;
+ size_t alen;
+ char *t, *te;
+ size_t tn = strlen(s) + 1;
+ char c;
+
+ te = t = malloc(tn);;
+ while ((c = *s++) != '\0') {
+ switch (c) {
+#if 0 /* XXX can't do this */
+ case '\\': /* escape */
+ c = *s++;
+ break;
+#endif
+ case '!':
+ if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
+ break;
+ if ((a = findNextArg(con, 1, 1)) == NULL)
+ break;
+ s += 3;
+
+ alen = strlen(a);
+ tn += alen;
+ *te = '\0';
+ t = realloc(t, tn);
+ te = t + strlen(t);
+ strncpy(te, a, alen); te += alen;
+ continue;
+ /*@notreached@*/ break;
+ default:
+ break;
+ }
+ *te++ = c;
+ }
+ *te = '\0';
+ t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */
+ return t;
+}
+
+static void poptStripArg(poptContext con, int which)
+{
+ if(con->arg_strip == NULL) {
+ con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
+ }
+ PBM_SET(which, con->arg_strip);
+}
+
+/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
+int poptGetNextOpt(poptContext con)
+{
+ const struct poptOption * opt = NULL;
+ int done = 0;
+
+ /* looks a bit tricky to get rid of alloca properly in this fn */
+#if HAVE_ALLOCA_H
+#define ALLOCA(x) alloca(x)
+#else
+#define ALLOCA(x) malloc(x)
+#endif
+
+
+ while (!done) {
+ const char * origOptString = NULL;
+ poptCallbackType cb = NULL;
+ const void * cbData = NULL;
+ const char * longArg = NULL;
+ int canstrip = 0;
+
+ while (!con->os->nextCharArg && con->os->next == con->os->argc
+ && con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ if (!con->os->nextCharArg && con->os->next == con->os->argc) {
+ invokeCallbacks(con, con->options, 1);
+ if (con->doExec) execCommand(con);
+ return -1;
+ }
+
+ /* Process next long option */
+ if (!con->os->nextCharArg) {
+ char * localOptString, * optString;
+ int thisopt;
+
+ if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
+ con->os->next++;
+ continue;
+ }
+ thisopt=con->os->next;
+ origOptString = con->os->argv[con->os->next++];
+
+ if (con->restLeftover || *origOptString != '-') {
+ con->leftovers[con->numLeftovers++] = origOptString;
+ if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
+ con->restLeftover = 1;
+ continue;
+ }
+
+ /* Make a copy we can hack at */
+ localOptString = optString =
+ strcpy(ALLOCA(strlen(origOptString) + 1),
+ origOptString);
+
+ if (!optString[0])
+ return POPT_ERROR_BADOPT;
+
+ if (optString[1] == '-' && !optString[2]) {
+ con->restLeftover = 1;
+ continue;
+ } else {
+ char *oe;
+ int singleDash;
+
+ optString++;
+ if (*optString == '-')
+ singleDash = 0, optString++;
+ else
+ singleDash = 1;
+
+ /* XXX aliases with arg substitution need "--alias=arg" */
+ if (handleAlias(con, optString, '\0', NULL))
+ continue;
+ if (handleExec(con, optString, '\0'))
+ continue;
+
+ /* Check for "--long=arg" option. */
+ for (oe = optString; *oe && *oe != '='; oe++)
+ ;
+ if (*oe == '=') {
+ *oe++ = '\0';
+ /* XXX longArg is mapped back to persistent storage. */
+ longArg = origOptString + (oe - localOptString);
+ }
+
+ opt = findOption(con->options, optString, '\0', &cb, &cbData,
+ singleDash);
+ if (!opt && !singleDash)
+ return POPT_ERROR_BADOPT;
+ }
+
+ if (!opt) {
+ con->os->nextCharArg = origOptString + 1;
+ } else {
+ if(con->os == con->optionStack &&
+ opt->argInfo & POPT_ARGFLAG_STRIP) {
+ canstrip = 1;
+ poptStripArg(con, thisopt);
+ }
+ }
+ }
+
+ /* Process next short option */
+ if (con->os->nextCharArg) {
+ origOptString = con->os->nextCharArg;
+
+ con->os->nextCharArg = NULL;
+
+ if (handleAlias(con, NULL, *origOptString,
+ origOptString + 1)) {
+ origOptString++;
+ continue;
+ }
+ if (handleExec(con, NULL, *origOptString))
+ continue;
+
+ opt = findOption(con->options, NULL, *origOptString, &cb,
+ &cbData, 0);
+ if (!opt)
+ return POPT_ERROR_BADOPT;
+
+ origOptString++;
+ if (*origOptString)
+ con->os->nextCharArg = origOptString;
+ }
+
+ if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
+ *((int *)opt->arg) = 1;
+ } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
+ if (opt->arg)
+ *((int *) opt->arg) = opt->val;
+ } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
+ if (con->os->nextArg) {
+ xfree(con->os->nextArg);
+ con->os->nextArg = NULL;
+ }
+ if (longArg) {
+ con->os->nextArg = expandNextArg(con, longArg);
+ } else if (con->os->nextCharArg) {
+ con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
+ con->os->nextCharArg = NULL;
+ } else {
+ while (con->os->next == con->os->argc &&
+ con->os > con->optionStack) {
+ cleanOSE(con->os--);
+ }
+ if (con->os->next == con->os->argc)
+ return POPT_ERROR_NOARG;
+
+ /* make sure this isn't part of a short arg or the
+ result of an alias expansion */
+ if(con->os == con->optionStack &&
+ opt->argInfo & POPT_ARGFLAG_STRIP &&
+ canstrip) {
+ poptStripArg(con, con->os->next);
+ }
+
+ con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
+ }
+
+ if (opt->arg) {
+ long aLong;
+ char *end;
+
+ switch (opt->argInfo & POPT_ARG_MASK) {
+ case POPT_ARG_STRING:
+ /* XXX memory leak, hard to plug */
+ *((const char **) opt->arg) = xstrdup(con->os->nextArg);
+ break;
+
+ case POPT_ARG_INT:
+ case POPT_ARG_LONG:
+ aLong = strtol(con->os->nextArg, &end, 0);
+ if (!(end && *end == '\0'))
+ return POPT_ERROR_BADNUMBER;
+
+ if (aLong == LONG_MIN || aLong == LONG_MAX)
+ return POPT_ERROR_OVERFLOW;
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
+ *((long *) opt->arg) = aLong;
+ } else {
+ if (aLong > INT_MAX || aLong < INT_MIN)
+ return POPT_ERROR_OVERFLOW;
+ *((int *) opt->arg) = aLong;
+ }
+ break;
+
+ default:
+ fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
+ opt->argInfo & POPT_ARG_MASK);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (cb)
+ cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
+ else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
+ done = 1;
+
+ if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
+ con->finalArgvAlloced += 10;
+ con->finalArgv = realloc(con->finalArgv,
+ sizeof(*con->finalArgv) * con->finalArgvAlloced);
+ }
+
+ { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
+ if (opt->longName)
+ sprintf(s, "--%s", opt->longName);
+ else
+ sprintf(s, "-%c", opt->shortName);
+ con->finalArgv[con->finalArgvCount++] = s;
+ }
+
+ if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
+ && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
+ con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
+ }
+ }
+
+ return opt->val;
+}
+
+const char * poptGetOptArg(poptContext con) {
+ const char * ret = con->os->nextArg;
+ con->os->nextArg = NULL;
+ return ret;
+}
+
+const char * poptGetArg(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+ return con->leftovers[con->nextLeftover++];
+}
+
+const char * poptPeekArg(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+ return con->leftovers[con->nextLeftover];
+}
+
+const char ** poptGetArgs(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+
+ /* some apps like [like RPM ;-) ] need this NULL terminated */
+ con->leftovers[con->numLeftovers] = NULL;
+
+ return (con->leftovers + con->nextLeftover);
+}
+
+void poptFreeContext(poptContext con) {
+ int i;
+
+ poptResetContext(con);
+ if (con->os->argb) free(con->os->argb);
+
+ for (i = 0; i < con->numAliases; i++) {
+ if (con->aliases[i].longName) xfree(con->aliases[i].longName);
+ free(con->aliases[i].argv);
+ }
+
+ for (i = 0; i < con->numExecs; i++) {
+ if (con->execs[i].longName) xfree(con->execs[i].longName);
+ xfree(con->execs[i].script);
+ }
+ if (con->execs) xfree(con->execs);
+
+ free(con->leftovers);
+ free(con->finalArgv);
+ if (con->appName) xfree(con->appName);
+ if (con->aliases) free(con->aliases);
+ if (con->otherHelp) xfree(con->otherHelp);
+ if (con->execPath) xfree(con->execPath);
+ if (con->arg_strip) PBM_FREE(con->arg_strip);
+
+ free(con);
+}
+
+int poptAddAlias(poptContext con, struct poptAlias newAlias,
+ /*@unused@*/ int flags)
+{
+ int aliasNum = con->numAliases++;
+ struct poptAlias * alias;
+
+ /* SunOS won't realloc(NULL, ...) */
+ if (!con->aliases)
+ con->aliases = malloc(sizeof(newAlias) * con->numAliases);
+ else
+ con->aliases = realloc(con->aliases,
+ sizeof(newAlias) * con->numAliases);
+ alias = con->aliases + aliasNum;
+
+ alias->longName = (newAlias.longName)
+ ? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
+ : NULL;
+ alias->shortName = newAlias.shortName;
+ alias->argc = newAlias.argc;
+ alias->argv = newAlias.argv;
+
+ return 0;
+}
+
+const char * poptBadOption(poptContext con, int flags) {
+ struct optionStackEntry * os;
+
+ if (flags & POPT_BADOPTION_NOALIAS)
+ os = con->optionStack;
+ else
+ os = con->os;
+
+ return os->argv[os->next - 1];
+}
+
+#define POPT_ERROR_NOARG -10
+#define POPT_ERROR_BADOPT -11
+#define POPT_ERROR_OPTSTOODEEP -13
+#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
+#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
+
+const char *poptStrerror(const int error) {
+ switch (error) {
+ case POPT_ERROR_NOARG:
+ return POPT_("missing argument");
+ case POPT_ERROR_BADOPT:
+ return POPT_("unknown option");
+ case POPT_ERROR_OPTSTOODEEP:
+ return POPT_("aliases nested too deeply");
+ case POPT_ERROR_BADQUOTE:
+ return POPT_("error in paramter quoting");
+ case POPT_ERROR_BADNUMBER:
+ return POPT_("invalid numeric value");
+ case POPT_ERROR_OVERFLOW:
+ return POPT_("number too large or too small");
+ case POPT_ERROR_ERRNO:
+ return strerror(errno);
+ default:
+ return POPT_("unknown error");
+ }
+}
+
+int poptStuffArgs(poptContext con, const char ** argv) {
+ int argc;
+
+ if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ for (argc = 0; argv[argc]; argc++)
+ ;
+
+ con->os++;
+ con->os->next = 0;
+ con->os->nextArg = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->currAlias = NULL;
+ poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
+ con->os->argb = NULL;
+ con->os->stuffed = 1;
+
+ return 0;
+}
+
+const char * poptGetInvocationName(poptContext con) {
+ return con->os->argv[0];
+}
+
+int poptStrippedArgv(poptContext con, int argc, char **argv)
+{
+ int i,j=1, numargs=argc;
+
+ for(i=1; i<argc; i++) {
+ if(PBM_ISSET(i, con->arg_strip)) {
+ numargs--;
+ }
+ }
+
+ for(i=1; i<argc; i++) {
+ if(PBM_ISSET(i, con->arg_strip)) {
+ continue;
+ } else {
+ if(j<numargs) {
+ argv[j++]=argv[i];
+ } else {
+ argv[j++]='\0';
+ }
+ }
+ }
+
+ return(numargs);
+}
diff --git a/source/popt/popt.h b/source/popt/popt.h
new file mode 100644
index 00000000000..c33cedaec99
--- /dev/null
+++ b/source/popt/popt.h
@@ -0,0 +1,130 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#ifndef H_POPT
+#define H_POPT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* for FILE * */
+
+#define POPT_OPTION_DEPTH 10
+
+#define POPT_ARG_NONE 0
+#define POPT_ARG_STRING 1
+#define POPT_ARG_INT 2
+#define POPT_ARG_LONG 3
+#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */
+#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be
+ set first in table; arg points
+ to callback, descrip points to
+ callback data to pass */
+#define POPT_ARG_INTL_DOMAIN 6 /* set the translation domain
+ for this table and any
+ included tables; arg points
+ to the domain string */
+#define POPT_ARG_VAL 7 /* arg should take value val */
+#define POPT_ARG_MASK 0x0000FFFF
+#define POPT_ARGFLAG_ONEDASH 0x80000000 /* allow -longoption */
+#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /* don't show in help/usage */
+#define POPT_ARGFLAG_STRIP 0x20000000 /* strip this arg from argv (only applies to long args) */
+#define POPT_CBFLAG_PRE 0x80000000 /* call the callback before parse */
+#define POPT_CBFLAG_POST 0x40000000 /* call the callback after parse */
+#define POPT_CBFLAG_INC_DATA 0x20000000 /* use data from the include line,
+ not the subtable */
+
+#define POPT_ERROR_NOARG -10
+#define POPT_ERROR_BADOPT -11
+#define POPT_ERROR_OPTSTOODEEP -13
+#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
+#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
+#define POPT_ERROR_BADNUMBER -17
+#define POPT_ERROR_OVERFLOW -18
+
+/* poptBadOption() flags */
+#define POPT_BADOPTION_NOALIAS (1 << 0) /* don't go into an alias */
+
+/* poptGetContext() flags */
+#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */
+#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */
+
+struct poptOption {
+ /*@observer@*/ /*@null@*/ const char * longName; /* may be NULL */
+ char shortName; /* may be '\0' */
+ int argInfo;
+ /*@shared@*/ /*@null@*/ void * arg; /* depends on argInfo */
+ int val; /* 0 means don't return, just update flag */
+ /*@shared@*/ /*@null@*/ const char * descrip; /* description for autohelp -- may be NULL */
+ /*@shared@*/ /*@null@*/ const char * argDescrip; /* argument description for autohelp */
+};
+
+struct poptAlias {
+ /*@owned@*/ /*@null@*/ const char * longName; /* may be NULL */
+ char shortName; /* may be '\0' */
+ int argc;
+ /*@owned@*/ const char ** argv; /* must be free()able */
+};
+
+extern struct poptOption poptHelpOptions[];
+#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
+ 0, "Help options", NULL },
+
+typedef struct poptContext_s * poptContext;
+#ifndef __cplusplus
+typedef struct poptOption * poptOption;
+#endif
+
+enum poptCallbackReason { POPT_CALLBACK_REASON_PRE,
+ POPT_CALLBACK_REASON_POST,
+ POPT_CALLBACK_REASON_OPTION };
+typedef void (*poptCallbackType)(poptContext con,
+ enum poptCallbackReason reason,
+ const struct poptOption * opt,
+ const char * arg, const void * data);
+
+/*@only@*/ poptContext poptGetContext(/*@keep@*/ const char * name,
+ int argc, /*@keep@*/ const char ** argv,
+ /*@keep@*/ const struct poptOption * options, int flags);
+void poptResetContext(poptContext con);
+
+/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
+int poptGetNextOpt(poptContext con);
+/* returns NULL if no argument is available */
+/*@observer@*/ /*@null@*/ const char * poptGetOptArg(poptContext con);
+/* returns NULL if no more options are available */
+/*@observer@*/ /*@null@*/ const char * poptGetArg(poptContext con);
+/*@observer@*/ /*@null@*/ const char * poptPeekArg(poptContext con);
+/*@observer@*/ /*@null@*/ const char ** poptGetArgs(poptContext con);
+/* returns the option which caused the most recent error */
+/*@observer@*/ const char * poptBadOption(poptContext con, int flags);
+void poptFreeContext( /*@only@*/ poptContext con);
+int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv);
+int poptAddAlias(poptContext con, struct poptAlias alias, int flags);
+int poptReadConfigFile(poptContext con, const char * fn);
+/* like above, but reads /etc/popt and $HOME/.popt along with environment
+ vars */
+int poptReadDefaultConfig(poptContext con, int useEnv);
+/* argv should be freed -- this allows ', ", and \ quoting, but ' is treated
+ the same as " and both may include \ quotes */
+int poptDupArgv(int argc, const char **argv,
+ /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
+int poptParseArgvString(const char * s,
+ /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
+/*@observer@*/ const char *poptStrerror(const int error);
+void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
+void poptPrintHelp(poptContext con, FILE * f, int flags);
+void poptPrintUsage(poptContext con, FILE * f, int flags);
+void poptSetOtherOptionHelp(poptContext con, const char * text);
+/*@observer@*/ const char * poptGetInvocationName(poptContext con);
+/* shuffles argv pointers to remove stripped args, returns new argc */
+int poptStrippedArgv(poptContext con, int argc, char **argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/popt/poptconfig.c b/source/popt/poptconfig.c
new file mode 100644
index 00000000000..eb769413630
--- /dev/null
+++ b/source/popt/poptconfig.c
@@ -0,0 +1,142 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#include "system.h"
+#include "poptint.h"
+
+static void configLine(poptContext con, char * line) {
+ int nameLength = strlen(con->appName);
+ char * opt;
+ struct poptAlias alias;
+ char * entryType;
+ char * longName = NULL;
+ char shortName = '\0';
+
+ if (strncmp(line, con->appName, nameLength)) return;
+ line += nameLength;
+ if (!*line || !isspace(*line)) return;
+ while (*line && isspace(*line)) line++;
+ entryType = line;
+
+ while (!*line || !isspace(*line)) line++;
+ *line++ = '\0';
+ while (*line && isspace(*line)) line++;
+ if (!*line) return;
+ opt = line;
+
+ while (!*line || !isspace(*line)) line++;
+ *line++ = '\0';
+ while (*line && isspace(*line)) line++;
+ if (!*line) return;
+
+ if (opt[0] == '-' && opt[1] == '-')
+ longName = opt + 2;
+ else if (opt[0] == '-' && !opt[2])
+ shortName = opt[1];
+
+ if (!strcmp(entryType, "alias")) {
+ if (poptParseArgvString(line, &alias.argc, &alias.argv)) return;
+ alias.longName = longName, alias.shortName = shortName;
+ poptAddAlias(con, alias, 0);
+ } else if (!strcmp(entryType, "exec")) {
+ con->execs = realloc(con->execs,
+ sizeof(*con->execs) * (con->numExecs + 1));
+ if (longName)
+ con->execs[con->numExecs].longName = xstrdup(longName);
+ else
+ con->execs[con->numExecs].longName = NULL;
+
+ con->execs[con->numExecs].shortName = shortName;
+ con->execs[con->numExecs].script = xstrdup(line);
+
+ con->numExecs++;
+ }
+}
+
+int poptReadConfigFile(poptContext con, const char * fn) {
+ char * file=NULL, * chptr, * end;
+ char * buf=NULL, * dst;
+ int fd, rc;
+ int fileLength;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return POPT_ERROR_ERRNO;
+ }
+
+ fileLength = lseek(fd, 0, SEEK_END);
+ (void) lseek(fd, 0, 0);
+
+ file = malloc(fileLength + 1);
+ if (read(fd, file, fileLength) != fileLength) {
+ rc = errno;
+ close(fd);
+ errno = rc;
+ if (file) free(file);
+ return POPT_ERROR_ERRNO;
+ }
+ close(fd);
+
+ dst = buf = malloc(fileLength + 1);
+
+ chptr = file;
+ end = (file + fileLength);
+ while (chptr < end) {
+ switch (*chptr) {
+ case '\n':
+ *dst = '\0';
+ dst = buf;
+ while (*dst && isspace(*dst)) dst++;
+ if (*dst && *dst != '#') {
+ configLine(con, dst);
+ }
+ chptr++;
+ break;
+ case '\\':
+ *dst++ = *chptr++;
+ if (chptr < end) {
+ if (*chptr == '\n')
+ dst--, chptr++;
+ /* \ at the end of a line does not insert a \n */
+ else
+ *dst++ = *chptr++;
+ }
+ break;
+ default:
+ *dst++ = *chptr++;
+ break;
+ }
+ }
+
+ free(file);
+ free(buf);
+
+ return 0;
+}
+
+int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
+ char * fn, * home;
+ int rc;
+
+ if (!con->appName) return 0;
+
+ rc = poptReadConfigFile(con, "/etc/popt");
+ if (rc) return rc;
+ if (getuid() != geteuid()) return 0;
+
+ if ((home = getenv("HOME"))) {
+ fn = malloc(strlen(home) + 20);
+ strcpy(fn, home);
+ strcat(fn, "/.popt");
+ rc = poptReadConfigFile(con, fn);
+ free(fn);
+ if (rc) return rc;
+ }
+
+ return 0;
+}
+
diff --git a/source/popt/popthelp.c b/source/popt/popthelp.c
new file mode 100644
index 00000000000..6b790a63e78
--- /dev/null
+++ b/source/popt/popthelp.c
@@ -0,0 +1,301 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#include "system.h"
+#include "poptint.h"
+
+static void displayArgs(poptContext con,
+ /*@unused@*/ enum poptCallbackReason foo,
+ struct poptOption * key,
+ /*@unused@*/ const char * arg, /*@unused@*/ void * data) {
+ if (key->shortName== '?')
+ poptPrintHelp(con, stdout, 0);
+ else
+ poptPrintUsage(con, stdout, 0);
+ exit(0);
+}
+
+struct poptOption poptHelpOptions[] = {
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
+ { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
+ { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
+ { NULL, '\0', 0, NULL, 0, NULL, NULL }
+} ;
+
+
+/*@observer@*/ /*@null@*/ static const char *
+getTableTranslationDomain(const struct poptOption *table)
+{
+ const struct poptOption *opt;
+
+ for(opt = table;
+ opt->longName || opt->shortName || opt->arg;
+ opt++) {
+ if(opt->argInfo == POPT_ARG_INTL_DOMAIN)
+ return opt->arg;
+ }
+
+ return NULL;
+}
+
+/*@observer@*/ /*@null@*/ static const char *
+getArgDescrip(const struct poptOption * opt, const char *translation_domain)
+{
+ if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
+
+ if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
+ if (opt->argDescrip) return POPT_(opt->argDescrip);
+
+ if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
+ return POPT_("ARG");
+}
+
+static void singleOptionHelp(FILE * f, int maxLeftCol,
+ const struct poptOption * opt,
+ const char *translation_domain) {
+ int indentLength = maxLeftCol + 5;
+ int lineLength = 79 - indentLength;
+ const char * help = D_(translation_domain, opt->descrip);
+ int helpLength;
+ const char * ch;
+ char format[10];
+ char * left;
+ const char * argDescrip = getArgDescrip(opt, translation_domain);
+
+ left = malloc(maxLeftCol + 1);
+ *left = '\0';
+
+ if (opt->longName && opt->shortName)
+ sprintf(left, "-%c, --%s", opt->shortName, opt->longName);
+ else if (opt->shortName)
+ sprintf(left, "-%c", opt->shortName);
+ else if (opt->longName)
+ sprintf(left, "--%s", opt->longName);
+ if (!*left) return ;
+ if (argDescrip) {
+ strcat(left, "=");
+ strcat(left, argDescrip);
+ }
+
+ if (help)
+ fprintf(f," %-*s ", maxLeftCol, left);
+ else {
+ fprintf(f," %s\n", left);
+ goto out;
+ }
+
+ helpLength = strlen(help);
+ while (helpLength > lineLength) {
+ ch = help + lineLength - 1;
+ while (ch > help && !isspace(*ch)) ch--;
+ if (ch == help) break; /* give up */
+ while (ch > (help + 1) && isspace(*ch)) ch--;
+ ch++;
+
+ sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
+ fprintf(f, format, help, " ");
+ help = ch;
+ while (isspace(*help) && *help) help++;
+ helpLength = strlen(help);
+ }
+
+ if (helpLength) fprintf(f, "%s\n", help);
+
+out:
+ free(left);
+}
+
+static int maxArgWidth(const struct poptOption * opt,
+ const char * translation_domain) {
+ int max = 0;
+ int this;
+ const char * s;
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ this = maxArgWidth(opt->arg, translation_domain);
+ if (this > max) max = this;
+ } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+ this = opt->shortName ? 2 : 0;
+ if (opt->longName) {
+ if (this) this += 2;
+ this += strlen(opt->longName) + 2;
+ }
+
+ s = getArgDescrip(opt, translation_domain);
+ if (s)
+ this += strlen(s) + 1;
+ if (this > max) max = this;
+ }
+
+ opt++;
+ }
+
+ return max;
+}
+
+static void singleTableHelp(FILE * f, const struct poptOption * table,
+ int left,
+ const char *translation_domain) {
+ const struct poptOption * opt;
+ const char *sub_transdom;
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
+ singleOptionHelp(f, left, opt, translation_domain);
+ opt++;
+ }
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ sub_transdom = getTableTranslationDomain(opt->arg);
+ if(!sub_transdom)
+ sub_transdom = translation_domain;
+
+ if (opt->descrip)
+ fprintf(f, "\n%s\n", D_(sub_transdom, opt->descrip));
+
+ singleTableHelp(f, opt->arg, left, sub_transdom);
+ }
+ opt++;
+ }
+}
+
+static int showHelpIntro(poptContext con, FILE * f) {
+ int len = 6;
+ const char * fn;
+
+ fprintf(f, POPT_("Usage:"));
+ if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
+ fn = con->optionStack->argv[0];
+ if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
+ fprintf(f, " %s", fn);
+ len += strlen(fn) + 1;
+ }
+
+ return len;
+}
+
+void poptPrintHelp(poptContext con, FILE * f, /*@unused@*/ int flags) {
+ int leftColWidth;
+
+ showHelpIntro(con, f);
+ if (con->otherHelp)
+ fprintf(f, " %s\n", con->otherHelp);
+ else
+ fprintf(f, " %s\n", POPT_("[OPTION...]"));
+
+ leftColWidth = maxArgWidth(con->options, NULL);
+ singleTableHelp(f, con->options, leftColWidth, NULL);
+}
+
+static int singleOptionUsage(FILE * f, int cursor,
+ const struct poptOption * opt,
+ const char *translation_domain) {
+ int len = 3;
+ char shortStr[2] = { '\0', '\0' };
+ const char * item = shortStr;
+ const char * argDescrip = getArgDescrip(opt, translation_domain);
+
+ if (opt->shortName) {
+ if (!(opt->argInfo & POPT_ARG_MASK))
+ return cursor; /* we did these already */
+ len++;
+ *shortStr = opt->shortName;
+ shortStr[1] = '\0';
+ } else if (opt->longName) {
+ len += 1 + strlen(opt->longName);
+ item = opt->longName;
+ }
+
+ if (len == 3) return cursor;
+
+ if (argDescrip)
+ len += strlen(argDescrip) + 1;
+
+ if ((cursor + len) > 79) {
+ fprintf(f, "\n ");
+ cursor = 7;
+ }
+
+ fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item,
+ argDescrip ? (opt->shortName ? " " : "=") : "",
+ argDescrip ? argDescrip : "");
+
+ return cursor + len + 1;
+}
+
+static int singleTableUsage(FILE * f, int cursor, const struct poptOption * table,
+ const char *translation_domain) {
+ const struct poptOption * opt;
+
+ opt = table;
+ while (opt->longName || opt->shortName || opt->arg) {
+ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN)
+ translation_domain = (const char *)opt->arg;
+ else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
+ cursor = singleTableUsage(f, cursor, opt->arg,
+ translation_domain);
+ else if ((opt->longName || opt->shortName) &&
+ !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
+ cursor = singleOptionUsage(f, cursor, opt, translation_domain);
+
+ opt++;
+ }
+
+ return cursor;
+}
+
+static int showShortOptions(const struct poptOption * opt, FILE * f,
+ char * str) {
+ char s[300]; /* this is larger then the ascii set, so
+ it should do just fine */
+
+ s[0] = '\0';
+ if (str == NULL) {
+ memset(s, 0, sizeof(s));
+ str = s;
+ }
+
+ while (opt->longName || opt->shortName || opt->arg) {
+ if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
+ str[strlen(str)] = opt->shortName;
+ else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
+ showShortOptions(opt->arg, f, str);
+
+ opt++;
+ }
+
+ if (s != str || !*s)
+ return 0;
+
+ fprintf(f, " [-%s]", s);
+ return strlen(s) + 4;
+}
+
+void poptPrintUsage(poptContext con, FILE * f, /*@unused@*/ int flags) {
+ int cursor;
+
+ cursor = showHelpIntro(con, f);
+ cursor += showShortOptions(con->options, f, NULL);
+ singleTableUsage(f, cursor, con->options, NULL);
+
+ if (con->otherHelp) {
+ cursor += strlen(con->otherHelp) + 1;
+ if (cursor > 79) fprintf(f, "\n ");
+ fprintf(f, " %s", con->otherHelp);
+ }
+
+ fprintf(f, "\n");
+}
+
+void poptSetOtherOptionHelp(poptContext con, const char * text) {
+ if (con->otherHelp) xfree(con->otherHelp);
+ con->otherHelp = xstrdup(text);
+}
diff --git a/source/popt/poptint.h b/source/popt/poptint.h
new file mode 100644
index 00000000000..1847ffafe67
--- /dev/null
+++ b/source/popt/poptint.h
@@ -0,0 +1,71 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#ifndef H_POPTINT
+#define H_POPTINT
+
+/* Bit mask macros. */
+typedef unsigned int __pbm_bits;
+#define __PBM_NBITS (8 * sizeof (__pbm_bits))
+#define __PBM_IX(d) ((d) / __PBM_NBITS)
+#define __PBM_MASK(d) ((__pbm_bits) 1 << ((d) % __PBM_NBITS))
+typedef struct {
+ __pbm_bits bits[1];
+} pbm_set;
+#define __PBM_BITS(set) ((set)->bits)
+
+#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
+#define PBM_FREE(s) free(s);
+#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
+#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
+#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
+
+struct optionStackEntry {
+ int argc;
+ /*@only@*/ const char ** argv;
+ /*@only@*/ pbm_set * argb;
+ int next;
+ /*@only@*/ const char * nextArg;
+ /*@keep@*/ const char * nextCharArg;
+ /*@dependent@*/ struct poptAlias * currAlias;
+ int stuffed;
+};
+
+struct execEntry {
+ const char * longName;
+ char shortName;
+ const char * script;
+};
+
+struct poptContext_s {
+ struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
+ /*@dependent@*/ struct optionStackEntry * os;
+ /*@owned@*/ const char ** leftovers;
+ int numLeftovers;
+ int nextLeftover;
+ /*@keep@*/ const struct poptOption * options;
+ int restLeftover;
+ /*@only@*/ const char * appName;
+ /*@only@*/ struct poptAlias * aliases;
+ int numAliases;
+ int flags;
+ struct execEntry * execs;
+ int numExecs;
+ /*@only@*/ const char ** finalArgv;
+ int finalArgvCount;
+ int finalArgvAlloced;
+ /*@dependent@*/ struct execEntry * doExec;
+ /*@only@*/ const char * execPath;
+ int execAbsolute;
+ /*@only@*/ const char * otherHelp;
+ pbm_set * arg_strip;
+};
+
+#define xfree(_a) free((void *)_a)
+
+#define POPT_(foo) (foo)
+#define D_(dom, str) (str)
+#define N_(foo) (foo)
+
+#endif
diff --git a/source/popt/poptparse.c b/source/popt/poptparse.c
new file mode 100644
index 00000000000..8f00769be9f
--- /dev/null
+++ b/source/popt/poptparse.c
@@ -0,0 +1,102 @@
+/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
+ file accompanying popt source distributions, available from
+ ftp://ftp.redhat.com/pub/code/popt */
+
+#include "system.h"
+
+#define POPT_ARGV_ARRAY_GROW_DELTA 5
+
+int poptDupArgv(int argc, const char **argv,
+ int * argcPtr, const char *** argvPtr)
+{
+ size_t nb = (argc + 1) * sizeof(*argv);
+ const char ** argv2;
+ char * dst;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i] == NULL)
+ return POPT_ERROR_NOARG;
+ nb += strlen(argv[i]) + 1;
+ }
+
+ dst = malloc(nb);
+ argv2 = (void *) dst;
+ dst += (argc + 1) * sizeof(*argv);
+
+ for (i = 0; i < argc; i++) {
+ argv2[i] = dst;
+ dst += strlen(strcpy(dst, argv[i])) + 1;
+ }
+ argv2[argc] = NULL;
+
+ *argvPtr = argv2;
+ *argcPtr = argc;
+ return 0;
+}
+
+int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
+{
+ const char * src;
+ char quote = '\0';
+ int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
+ const char ** argv = malloc(sizeof(*argv) * argvAlloced);
+ int argc = 0;
+ int buflen = strlen(s) + 1;
+ char *buf0 = calloc(buflen, 1);
+ char *buf = buf0;
+
+ argv[argc] = buf;
+
+ for (src = s; *src; src++) {
+ if (quote == *src) {
+ quote = '\0';
+ } else if (quote) {
+ if (*src == '\\') {
+ src++;
+ if (!*src) {
+ free(argv);
+ free(buf0);
+ return POPT_ERROR_BADQUOTE;
+ }
+ if (*src != quote) *buf++ = '\\';
+ }
+ *buf++ = *src;
+ } else if (isspace(*src)) {
+ if (*argv[argc]) {
+ buf++, argc++;
+ if (argc == argvAlloced) {
+ argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
+ argv = realloc(argv, sizeof(*argv) * argvAlloced);
+ }
+ argv[argc] = buf;
+ }
+ } else switch (*src) {
+ case '"':
+ case '\'':
+ quote = *src;
+ break;
+ case '\\':
+ src++;
+ if (!*src) {
+ free(argv);
+ free(buf0);
+ return POPT_ERROR_BADQUOTE;
+ }
+ /*@fallthrough@*/
+ default:
+ *buf++ = *src;
+ break;
+ }
+ }
+
+ if (strlen(argv[argc])) {
+ argc++, buf++;
+ }
+
+ (void) poptDupArgv(argc, argv, argcPtr, argvPtr);
+
+ free(argv);
+ free(buf0);
+ return 0;
+}
diff --git a/source/popt/system.h b/source/popt/system.h
new file mode 100644
index 00000000000..059c0458176
--- /dev/null
+++ b/source/popt/system.h
@@ -0,0 +1,53 @@
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#if HAVE_MCHECK_H
+#include <mcheck.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __NeXT
+/* access macros are not declared in non posix mode in unistd.h -
+ don't try to use posix on NeXTstep 3.3 ! */
+#include <libc.h>
+#endif
+
+/* AIX requires this to be the first thing in the file. */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+#pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
+#define alloca __builtin_alloca
+#endif
+
+/*@only@*/ char * xstrdup (const char *str);
+
+#if HAVE_MCHECK_H && defined(__GNUC__)
+#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
+#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
+#else
+#define xstrdup(_str) strdup(_str)
+#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
+
+
+#include "popt.h"
diff --git a/source/printing/.cvsignore b/source/printing/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/printing/.cvsignore
diff --git a/source/printing/load.c b/source/printing/load.c
new file mode 100644
index 00000000000..ae76229d773
--- /dev/null
+++ b/source/printing/load.c
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ load printer lists
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/***************************************************************************
+auto-load printer services
+***************************************************************************/
+void add_all_printers(void)
+{
+ int printers = lp_servicenumber(PRINTERS_NAME);
+
+ if (printers < 0) return;
+
+ pcap_printer_fn(lp_add_one_printer);
+}
+
+/***************************************************************************
+auto-load some homes and printer services
+***************************************************************************/
+static void add_auto_printers(void)
+{
+ char *p;
+ int printers;
+ char *str = strdup(lp_auto_services());
+
+ if (!str) return;
+
+ printers = lp_servicenumber(PRINTERS_NAME);
+
+ if (printers < 0) {
+ SAFE_FREE(str);
+ return;
+ }
+
+ for (p=strtok(str,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) {
+ if (lp_servicenumber(p) >= 0) continue;
+
+ if (pcap_printername_ok(p,NULL)) {
+ lp_add_printer(p,printers);
+ }
+ }
+
+ SAFE_FREE(str);
+}
+
+/***************************************************************************
+load automatic printer services
+***************************************************************************/
+void load_printers(void)
+{
+ add_auto_printers();
+ if (lp_load_printers())
+ add_all_printers();
+}
diff --git a/source/printing/lpq_parse.c b/source/printing/lpq_parse.c
new file mode 100644
index 00000000000..12f12fd33c6
--- /dev/null
+++ b/source/printing/lpq_parse.c
@@ -0,0 +1,1101 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ lpq parsing routines
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
+
+
+/*******************************************************************
+process time fields
+********************************************************************/
+static time_t EntryTime(fstring tok[], int ptr, int count, int minimum)
+{
+ time_t jobtime,jobtime1;
+
+ jobtime = time(NULL); /* default case: take current time */
+ if (count >= minimum) {
+ struct tm *t;
+ int i, day, hour, min, sec;
+ char *c;
+
+ for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
+ if (i<12) {
+ t = localtime(&jobtime);
+ day = atoi(tok[ptr+1]);
+ c=(char *)(tok[ptr+2]);
+ *(c+2)=0;
+ hour = atoi(c);
+ *(c+5)=0;
+ min = atoi(c+3);
+ if(*(c+6) != 0)sec = atoi(c+6);
+ else sec=0;
+
+ if ((t->tm_mon < i)||
+ ((t->tm_mon == i)&&
+ ((t->tm_mday < day)||
+ ((t->tm_mday == day)&&
+ (t->tm_hour*60+t->tm_min < hour*60+min)))))
+ t->tm_year--; /* last year's print job */
+
+ t->tm_mon = i;
+ t->tm_mday = day;
+ t->tm_hour = hour;
+ t->tm_min = min;
+ t->tm_sec = sec;
+ jobtime1 = mktime(t);
+ if (jobtime1 != (time_t)-1)
+ jobtime = jobtime1;
+ }
+ }
+ return jobtime;
+}
+
+
+/****************************************************************************
+parse a lpq line
+
+here is an example of lpq output under bsd
+
+Warning: no daemon present
+Rank Owner Job Files Total Size
+1st tridge 148 README 8096 bytes
+
+here is an example of lpq output under osf/1
+
+Warning: no daemon present
+Rank Pri Owner Job Files Total Size
+1st 0 tridge 148 README 8096 bytes
+
+
+<allan@umich.edu> June 30, 1998.
+Modified to handle file names with spaces, like the parse_lpq_lprng code
+further below.
+****************************************************************************/
+static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
+{
+#ifdef OSF1
+#define RANKTOK 0
+#define PRIOTOK 1
+#define USERTOK 2
+#define JOBTOK 3
+#define FILETOK 4
+#define TOTALTOK (count - 2)
+#define NTOK 6
+#define MAXTOK 128
+#else /* OSF1 */
+#define RANKTOK 0
+#define USERTOK 1
+#define JOBTOK 2
+#define FILETOK 3
+#define TOTALTOK (count - 2)
+#define NTOK 5
+#define MAXTOK 128
+#endif /* OSF1 */
+
+ char *tok[MAXTOK];
+ int count = 0;
+ pstring line2;
+
+ pstrcpy(line2,line);
+
+#ifdef OSF1
+ {
+ size_t length;
+ length = strlen(line2);
+ if (line2[length-3] == ':')
+ return(False);
+ }
+#endif /* OSF1 */
+
+ tok[0] = strtok(line2," \t");
+ count++;
+
+ while (((tok[count] = strtok(NULL," \t")) != NULL) && (count < MAXTOK)) {
+ count++;
+ }
+
+ /* we must get at least NTOK tokens */
+ if (count < NTOK)
+ return(False);
+
+ /* the Job and Total columns must be integer */
+ if (!isdigit((int)*tok[JOBTOK]) || !isdigit((int)*tok[TOTALTOK])) return(False);
+
+ buf->job = atoi(tok[JOBTOK]);
+ buf->size = atoi(tok[TOTALTOK]);
+ buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
+
+ if ((FILETOK + 1) != TOTALTOK) {
+ int bufsize;
+ int i;
+
+ bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+
+ for (i = (FILETOK + 1); i < TOTALTOK; i++) {
+ safe_strcat(buf->file," ",bufsize);
+ safe_strcat(buf->file,tok[i],bufsize - 1);
+ bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+ if (bufsize <= 0) {
+ break;
+ }
+ }
+ /* Ensure null termination. */
+ buf->file[sizeof(buf->file)-1] = '\0';
+ }
+
+#ifdef PRIOTOK
+ buf->priority = atoi(tok[PRIOTOK]);
+#else
+ buf->priority = 1;
+#endif
+ return(True);
+}
+
+/*
+<magnus@hum.auc.dk>
+LPRng_time modifies the current date by inserting the hour and minute from
+the lpq output. The lpq time looks like "23:15:07"
+
+<allan@umich.edu> June 30, 1998.
+Modified to work with the re-written parse_lpq_lprng routine.
+
+<J.P.M.v.Itegem@tue.nl> Dec 17,1999
+Modified to work with lprng 3.16
+With lprng 3.16 The lpq time looks like
+ "23:15:07"
+ "23:15:07.100"
+ "1999-12-16-23:15:07"
+ "1999-12-16-23:15:07.100"
+
+*/
+static time_t LPRng_time(char *time_string)
+{
+ time_t jobtime;
+ struct tm t;
+
+ jobtime = time(NULL); /* default case: take current time */
+ t = *localtime(&jobtime);
+
+ if ( atoi(time_string) < 24 ){
+ t.tm_hour = atoi(time_string);
+ t.tm_min = atoi(time_string+3);
+ t.tm_sec = atoi(time_string+6);
+ } else {
+ t.tm_year = atoi(time_string)-1900;
+ t.tm_mon = atoi(time_string+5)-1;
+ t.tm_mday = atoi(time_string+8);
+ t.tm_hour = atoi(time_string+11);
+ t.tm_min = atoi(time_string+14);
+ t.tm_sec = atoi(time_string+17);
+ }
+ jobtime = mktime(&t);
+
+ return jobtime;
+}
+
+
+/****************************************************************************
+ parse a lprng lpq line
+ <allan@umich.edu> June 30, 1998.
+ Re-wrote this to handle file names with spaces, multiple file names on one
+ lpq line, etc;
+****************************************************************************/
+static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
+{
+#define LPRNG_RANKTOK 0
+#define LPRNG_USERTOK 1
+#define LPRNG_PRIOTOK 2
+#define LPRNG_JOBTOK 3
+#define LPRNG_FILETOK 4
+#define LPRNG_TOTALTOK (num_tok - 2)
+#define LPRNG_TIMETOK (num_tok - 1)
+#define LPRNG_NTOK 7
+#define LPRNG_MAXTOK 128 /* PFMA just to keep us from running away. */
+
+ fstring tokarr[LPRNG_MAXTOK];
+ char *cptr;
+ int num_tok = 0;
+ pstring line2;
+
+ pstrcpy(line2,line);
+ cptr = line2;
+ while(next_token( &cptr, tokarr[num_tok], " \t", sizeof(fstring)) && (num_tok < LPRNG_MAXTOK))
+ num_tok++;
+
+ /* We must get at least LPRNG_NTOK tokens. */
+ if (num_tok < LPRNG_NTOK) {
+ return(False);
+ }
+
+ if (!isdigit((int)*tokarr[LPRNG_JOBTOK]) || !isdigit((int)*tokarr[LPRNG_TOTALTOK])) {
+ return(False);
+ }
+
+ buf->job = atoi(tokarr[LPRNG_JOBTOK]);
+ buf->size = atoi(tokarr[LPRNG_TOTALTOK]);
+
+ if (strequal(tokarr[LPRNG_RANKTOK],"active")) {
+ buf->status = LPQ_PRINTING;
+ } else if (isdigit((int)*tokarr[LPRNG_RANKTOK])) {
+ buf->status = LPQ_QUEUED;
+ } else {
+ buf->status = LPQ_PAUSED;
+ }
+
+ buf->priority = *tokarr[LPRNG_PRIOTOK] -'A';
+
+ buf->time = LPRng_time(tokarr[LPRNG_TIMETOK]);
+
+ StrnCpy(buf->user,tokarr[LPRNG_USERTOK],sizeof(buf->user)-1);
+
+ /* The '@hostname' prevents windows from displaying the printing icon
+ * for the current user on the taskbar. Plop in a null.
+ */
+
+ if ((cptr = strchr_m(buf->user,'@')) != NULL) {
+ *cptr = '\0';
+ }
+
+ StrnCpy(buf->file,tokarr[LPRNG_FILETOK],sizeof(buf->file)-1);
+
+ if ((LPRNG_FILETOK + 1) != LPRNG_TOTALTOK) {
+ int bufsize;
+ int i;
+
+ bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+
+ for (i = (LPRNG_FILETOK + 1); i < LPRNG_TOTALTOK; i++) {
+ safe_strcat(buf->file," ",bufsize);
+ safe_strcat(buf->file,tokarr[i],bufsize - 1);
+ bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+ if (bufsize <= 0) {
+ break;
+ }
+ }
+ /* Ensure null termination. */
+ buf->file[sizeof(buf->file)-1] = '\0';
+ }
+
+ return(True);
+}
+
+
+
+/*******************************************************************
+parse lpq on an aix system
+
+Queue Dev Status Job Files User PP % Blks Cp Rnk
+------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
+lazer lazer READY
+lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
+ QUEUED 538 C.ps root@IEDVB 124 1 2
+ QUEUED 539 E.ps root@IEDVB 28 1 3
+ QUEUED 540 L.ps root@IEDVB 172 1 4
+ QUEUED 541 P.ps root@IEDVB 22 1 5
+********************************************************************/
+static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
+{
+ fstring tok[11];
+ int count=0;
+
+ /* handle the case of "(standard input)" as a filename */
+ pstring_sub(line,"standard input","STDIN");
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0;
+ count<10 &&
+ next_token(&line,tok[count],NULL, sizeof(tok[count]));
+ count++) ;
+
+ /* we must get 6 tokens */
+ if (count < 10)
+ {
+ if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0)))
+ {
+ /* the 2nd and 5th columns must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4])) return(False);
+ buf->size = atoi(tok[4]) * 1024;
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[2],' '))
+ fstrcpy(tok[2],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr_m(tok[2],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[1]);
+ buf->status = strequal(tok[0],"HELD")?LPQ_PAUSED:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
+ }
+ else
+ {
+ DEBUG(6,("parse_lpq_aix count=%d\n", count));
+ return(False);
+ }
+ }
+ else
+ {
+ /* the 4th and 9th columns must be integer */
+ if (!isdigit((int)*tok[3]) || !isdigit((int)*tok[8])) return(False);
+ buf->size = atoi(tok[8]) * 1024;
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[4],' '))
+ fstrcpy(tok[4],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr_m(tok[4],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[4],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[3]);
+ buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
+ }
+
+
+ return(True);
+}
+
+
+/****************************************************************************
+parse a lpq line
+here is an example of lpq output under hpux; note there's no space after -o !
+$> lpstat -oljplus
+ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
+ util.c 125697 bytes
+ server.c 110712 bytes
+ljplus-2154 user priority 0 Jan 19 08:14 from client
+ (standard input) 7551 bytes
+****************************************************************************/
+static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
+{
+ /* must read two lines to process, therefore keep some values static */
+ static BOOL header_line_ok=False, base_prio_reset=False;
+ static fstring jobuser;
+ static int jobid;
+ static int jobprio;
+ static time_t jobtime;
+ static int jobstat=LPQ_QUEUED;
+ /* to store minimum priority to print, lpstat command should be invoked
+ with -p option first, to work */
+ static int base_prio;
+
+ int count;
+ char htab = '\011';
+ fstring tok[12];
+
+ /* If a line begins with a horizontal TAB, it is a subline type */
+
+ if (line[0] == htab) { /* subline */
+ /* check if it contains the base priority */
+ if (!strncmp(line,"\tfence priority : ",18)) {
+ base_prio=atoi(&line[18]);
+ DEBUG(4, ("fence priority set at %d\n", base_prio));
+ }
+ if (!header_line_ok) return (False); /* incorrect header line */
+ /* handle the case of "(standard input)" as a filename */
+ pstring_sub(line,"standard input","STDIN");
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0; count<2 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+ /* we must get 2 tokens */
+ if (count < 2) return(False);
+
+ /* the 2nd column must be integer */
+ if (!isdigit((int)*tok[1])) return(False);
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[0],' '))
+ fstrcpy(tok[0],"STDIN");
+
+ buf->size = atoi(tok[1]);
+ StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
+
+ /* fill things from header line */
+ buf->time = jobtime;
+ buf->job = jobid;
+ buf->status = jobstat;
+ buf->priority = jobprio;
+ StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
+
+ return(True);
+ }
+ else { /* header line */
+ header_line_ok=False; /* reset it */
+ if (first) {
+ if (!base_prio_reset) {
+ base_prio=0; /* reset it */
+ base_prio_reset=True;
+ }
+ }
+ else if (base_prio) base_prio_reset=False;
+
+ /* handle the dash in the job id */
+ pstring_sub(line,"-"," ");
+
+ for (count=0; count<12 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+
+ /* we must get 8 tokens */
+ if (count < 8) return(False);
+
+ /* first token must be printer name (cannot check ?) */
+ /* the 2nd, 5th & 7th column must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4]) || !isdigit((int)*tok[6])) return(False);
+ jobid = atoi(tok[1]);
+ StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
+ jobprio = atoi(tok[4]);
+
+ /* process time */
+ jobtime=EntryTime(tok, 5, count, 8);
+ if (jobprio < base_prio) {
+ jobstat = LPQ_PAUSED;
+ DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
+ }
+ else {
+ jobstat = LPQ_QUEUED;
+ if ((count >8) && (((strequal(tok[8],"on")) ||
+ ((strequal(tok[8],"from")) &&
+ ((count > 10)&&(strequal(tok[10],"on")))))))
+ jobstat = LPQ_PRINTING;
+ }
+
+ header_line_ok=True; /* information is correct */
+ return(False); /* need subline info to include into queuelist */
+ }
+}
+
+
+/****************************************************************************
+parse a lpstat line
+
+here is an example of "lpstat -o dcslw" output under sysv
+
+dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
+dcslw-897 tridge 4712 Dec 20 10:30:30 being held
+
+****************************************************************************/
+static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
+{
+ fstring tok[9];
+ int count=0;
+ char *p;
+
+ /*
+ * Handle the dash in the job id, but make sure that we skip over
+ * the printer name in case we have a dash in that.
+ * Patch from Dom.Mitchell@palmerharvey.co.uk.
+ */
+
+ /*
+ * Move to the first space.
+ */
+ for (p = line ; !isspace(*p) && *p; p++)
+ ;
+
+ /*
+ * Back up until the last '-' character or
+ * start of line.
+ */
+ for (; (p >= line) && (*p != '-'); p--)
+ ;
+
+ if((p >= line) && (*p == '-'))
+ *p = ' ';
+
+ for (count=0; count<9 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++)
+ ;
+
+ /* we must get 7 tokens */
+ if (count < 7)
+ return(False);
+
+ /* the 2nd and 4th, 6th columns must be integer */
+ if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[3]))
+ return(False);
+ if (!isdigit((int)*tok[5]))
+ return(False);
+
+ /* if the user contains a ! then trim the first part of it */
+ if ((p=strchr_m(tok[2],'!'))) {
+ fstring tmp;
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
+ }
+
+ buf->job = atoi(tok[1]);
+ buf->size = atoi(tok[3]);
+ if (count > 7 && strequal(tok[7],"on"))
+ buf->status = LPQ_PRINTING;
+ else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
+ buf->status = LPQ_PAUSED;
+ else
+ buf->status = LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = EntryTime(tok, 4, count, 7);
+ StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
+ return(True);
+}
+
+/****************************************************************************
+parse a lpq line
+
+here is an example of lpq output under qnx
+Spooler: /qnx/spooler, on node 1
+Printer: txt (ready)
+0000: root [job #1 ] active 1146 bytes /etc/profile
+0001: root [job #2 ] ready 2378 bytes /etc/install
+0002: root [job #3 ] ready 1146 bytes -- standard input --
+****************************************************************************/
+static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
+{
+ fstring tok[7];
+ int count=0;
+
+ DEBUG(4,("antes [%s]\n", line));
+
+ /* handle the case of "-- standard input --" as a filename */
+ pstring_sub(line,"standard input","STDIN");
+ DEBUG(4,("despues [%s]\n", line));
+ all_string_sub(line,"-- ","\"",0);
+ all_string_sub(line," --","\"",0);
+ DEBUG(4,("despues 1 [%s]\n", line));
+
+ pstring_sub(line,"[job #","");
+ pstring_sub(line,"]","");
+ DEBUG(4,("despues 2 [%s]\n", line));
+
+
+
+ for (count=0; count<7 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+
+ /* we must get 7 tokens */
+ if (count < 7)
+ return(False);
+
+ /* the 3rd and 5th columns must be integer */
+ if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) return(False);
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr_m(tok[6],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[2]);
+ buf->size = atoi(tok[4]);
+ buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
+ return(True);
+}
+
+
+/****************************************************************************
+ parse a lpq line for the plp printing system
+ Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
+
+redone by tridge. Here is a sample queue:
+
+Local Printer 'lp2' (fjall):
+ Printing (started at Jun 15 13:33:58, attempt 1).
+ Rank Owner Pr Opt Job Host Files Size Date
+ active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
+ 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
+
+****************************************************************************/
+static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
+{
+ fstring tok[11];
+ int count=0;
+
+ /* handle the case of "(standard input)" as a filename */
+ pstring_sub(line,"stdin","STDIN");
+ all_string_sub(line,"(","\"",0);
+ all_string_sub(line,")","\"",0);
+
+ for (count=0; count<11 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+
+ /* we must get 11 tokens */
+ if (count < 11)
+ return(False);
+
+ /* the first must be "active" or begin with an integer */
+ if (strcmp(tok[0],"active") && !isdigit((int)tok[0][0]))
+ return(False);
+
+ /* the 5th and 8th must be integer */
+ if (!isdigit((int)*tok[4]) || !isdigit((int)*tok[7]))
+ return(False);
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr_m(tok[6],' '))
+ fstrcpy(tok[6],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr_m(tok[6],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[4]);
+
+ buf->size = atoi(tok[7]);
+ if (strchr_m(tok[7],'K'))
+ buf->size *= 1024;
+ if (strchr_m(tok[7],'M'))
+ buf->size *= 1024*1024;
+
+ buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
+ return(True);
+}
+
+/****************************************************************************
+parse a qstat line
+
+here is an example of "qstat -l -d qms" output under softq
+
+Queue qms: 2 jobs; daemon active (313); enabled; accepting;
+ job-ID submission-time pri size owner title
+205980: H 98/03/09 13:04:05 0 15733 stephenf chap1.ps
+206086:> 98/03/12 17:24:40 0 659 chris -
+206087: 98/03/12 17:24:45 0 4876 chris -
+Total: 21268 bytes in queue
+
+
+****************************************************************************/
+static BOOL parse_lpq_softq(char *line,print_queue_struct *buf,BOOL first)
+{
+ fstring tok[10];
+ int count=0;
+
+ /* mung all the ":"s to spaces*/
+ pstring_sub(line,":"," ");
+
+ for (count=0; count<10 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+
+ /* we must get 9 tokens */
+ if (count < 9)
+ return(False);
+
+ /* the 1st and 7th columns must be integer */
+ if (!isdigit((int)*tok[0]) || !isdigit((int)*tok[6])) return(False);
+ /* if the 2nd column is either '>' or 'H' then the 7th and 8th must be
+ * integer, else it's the 6th and 7th that must be
+ */
+ if (*tok[1] == 'H' || *tok[1] == '>')
+ {
+ if (!isdigit((int)*tok[7]))
+ return(False);
+ buf->status = *tok[1] == '>' ? LPQ_PRINTING : LPQ_PAUSED;
+ count = 1;
+ }
+ else
+ {
+ if (!isdigit((int)*tok[5]))
+ return(False);
+ buf->status = LPQ_QUEUED;
+ count = 0;
+ }
+
+
+ buf->job = atoi(tok[0]);
+ buf->size = atoi(tok[count+6]);
+ buf->priority = atoi(tok[count+5]);
+ StrnCpy(buf->user,tok[count+7],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[count+8],sizeof(buf->file)-1);
+ buf->time = time(NULL); /* default case: take current time */
+ {
+ time_t jobtime;
+ struct tm *t;
+
+ t = localtime(&buf->time);
+ t->tm_mday = atoi(tok[count+2]+6);
+ t->tm_mon = atoi(tok[count+2]+3);
+ switch (*tok[count+2])
+ {
+ case 7: case 8: case 9: t->tm_year = atoi(tok[count+2]); break;
+ default: t->tm_year = atoi(tok[count+2]); break;
+ }
+
+ t->tm_hour = atoi(tok[count+3]);
+ t->tm_min = atoi(tok[count+4]);
+ t->tm_sec = atoi(tok[count+5]);
+ jobtime = mktime(t);
+ if (jobtime != (time_t)-1)
+ buf->time = jobtime;
+ }
+
+ return(True);
+}
+
+/*******************************************************************
+parse lpq on an NT system
+
+ Windows 2000 LPD Server
+ Printer \\10.0.0.2\NP17PCL (Paused)
+
+Owner Status Jobname Job-Id Size Pages Priority
+----------------------------------------------------------------------------
+root (9.99. Printing /usr/lib/rhs/rhs-pr 3 625 0 1
+root (9.99. Paused /usr/lib/rhs/rhs-pr 4 625 0 1
+jmcd Waiting Re: Samba Open Sour 26 32476 1 1
+
+********************************************************************/
+static BOOL parse_lpq_nt(char *line,print_queue_struct *buf,BOOL first)
+{
+#define LPRNT_OWNSIZ 11
+#define LPRNT_STATSIZ 9
+#define LPRNT_JOBSIZ 19
+#define LPRNT_IDSIZ 6
+#define LPRNT_SIZSIZ 9
+ typedef struct
+ {
+ char owner[LPRNT_OWNSIZ];
+ char space1;
+ char status[LPRNT_STATSIZ];
+ char space2;
+ char jobname[LPRNT_JOBSIZ];
+ char space3;
+ char jobid[LPRNT_IDSIZ];
+ char space4;
+ char size[LPRNT_SIZSIZ];
+ char terminator;
+ } nt_lpq_line;
+
+ nt_lpq_line parse_line;
+#define LPRNT_PRINTING "Printing"
+#define LPRNT_WAITING "Waiting"
+#define LPRNT_PAUSED "Paused"
+
+ memset(&parse_line, '\0', sizeof(parse_line));
+ strncpy((char *) &parse_line, line, sizeof(parse_line) -1);
+
+ if (strlen((char *) &parse_line) != sizeof(parse_line) - 1)
+ return(False);
+
+ /* Just want the first word in the owner field - the username */
+ if (strchr_m(parse_line.owner, ' '))
+ *(strchr_m(parse_line.owner, ' ')) = '\0';
+ else
+ parse_line.space1 = '\0';
+
+ /* Make sure we have an owner */
+ if (!strlen(parse_line.owner))
+ return(False);
+
+ /* Make sure the status is valid */
+ parse_line.space2 = '\0';
+ trim_string(parse_line.status, NULL, " ");
+ if (!strequal(parse_line.status, LPRNT_PRINTING) &&
+ !strequal(parse_line.status, LPRNT_PAUSED) &&
+ !strequal(parse_line.status, LPRNT_WAITING))
+ return(False);
+
+ parse_line.space3 = '\0';
+ trim_string(parse_line.jobname, NULL, " ");
+
+ buf->job = atoi(parse_line.jobid);
+ buf->priority = 0;
+ buf->size = atoi(parse_line.size);
+ buf->time = time(NULL);
+ StrnCpy(buf->user, parse_line.owner, sizeof(buf->user)-1);
+ StrnCpy(buf->file, parse_line.jobname, sizeof(buf->file)-1);
+ if (strequal(parse_line.status, LPRNT_PRINTING))
+ buf->status = LPQ_PRINTING;
+ else if (strequal(parse_line.status, LPRNT_PAUSED))
+ buf->status = LPQ_PAUSED;
+ else
+ buf->status = LPQ_QUEUED;
+
+ return(True);
+}
+
+/*******************************************************************
+parse lpq on an OS2 system
+
+JobID File Name Rank Size Status Comment
+----- --------------- ------ -------- ------------ ------------
+ 3 Control 1 68 Queued root@psflinu
+ 4 /etc/motd 2 11666 Queued root@psflinu
+
+********************************************************************/
+static BOOL parse_lpq_os2(char *line,print_queue_struct *buf,BOOL first)
+{
+#define LPROS2_IDSIZ 5
+#define LPROS2_JOBSIZ 15
+#define LPROS2_SIZSIZ 8
+#define LPROS2_STATSIZ 12
+#define LPROS2_OWNSIZ 12
+ typedef struct
+ {
+ char jobid[LPROS2_IDSIZ];
+ char space1[2];
+ char jobname[LPROS2_JOBSIZ];
+ char space2[14];
+ char size[LPROS2_SIZSIZ];
+ char space3[4];
+ char status[LPROS2_STATSIZ];
+ char space4[4];
+ char owner[LPROS2_OWNSIZ];
+ char terminator;
+ } os2_lpq_line;
+
+ os2_lpq_line parse_line;
+#define LPROS2_PRINTING "Printing"
+#define LPROS2_WAITING "Queued"
+#define LPROS2_PAUSED "Paused"
+
+ memset(&parse_line, '\0', sizeof(parse_line));
+ strncpy((char *) &parse_line, line, sizeof(parse_line) -1);
+
+ if (strlen((char *) &parse_line) != sizeof(parse_line) - 1)
+ return(False);
+
+ /* Get the jobid */
+ buf->job = atoi(parse_line.jobid);
+
+ /* Get the job name */
+ parse_line.space2[0] = '\0';
+ trim_string(parse_line.jobname, NULL, " ");
+ StrnCpy(buf->file, parse_line.jobname, sizeof(buf->file)-1);
+
+ buf->priority = 0;
+ buf->size = atoi(parse_line.size);
+ buf->time = time(NULL);
+
+ /* Make sure we have an owner */
+ if (!strlen(parse_line.owner))
+ return(False);
+
+ /* Make sure we have a valid status */
+ parse_line.space4[0] = '\0';
+ trim_string(parse_line.status, NULL, " ");
+ if (!strequal(parse_line.status, LPROS2_PRINTING) &&
+ !strequal(parse_line.status, LPROS2_PAUSED) &&
+ !strequal(parse_line.status, LPROS2_WAITING))
+ return(False);
+
+ StrnCpy(buf->user, parse_line.owner, sizeof(buf->user)-1);
+ if (strequal(parse_line.status, LPROS2_PRINTING))
+ buf->status = LPQ_PRINTING;
+ else if (strequal(parse_line.status, LPROS2_PAUSED))
+ buf->status = LPQ_PAUSED;
+ else
+ buf->status = LPQ_QUEUED;
+
+ return(True);
+}
+
+static char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
+static char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
+static char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
+
+#ifdef DEVELOPER
+
+/****************************************************************************
+parse a vlp line
+****************************************************************************/
+static BOOL parse_lpq_vlp(char *line,print_queue_struct *buf,BOOL first)
+{
+ int toknum = 0;
+ fstring tok;
+
+ /* First line is printer status */
+
+ if (!isdigit(line[0])) return False;
+
+ /* Parse a print job entry */
+
+ while(next_token(&line, tok, NULL, sizeof(fstring))) {
+ switch (toknum) {
+ case 0:
+ buf->job = atoi(tok);
+ break;
+ case 1:
+ buf->size = atoi(tok);
+ break;
+ case 2:
+ buf->status = atoi(tok);
+ break;
+ case 3:
+ buf->time = atoi(tok);
+ break;
+ case 4:
+ fstrcpy(buf->user, tok);
+ break;
+ case 5:
+ fstrcpy(buf->file, tok);
+ break;
+ }
+ toknum++;
+ }
+
+ return True;
+}
+
+#endif /* DEVELOPER */
+
+/****************************************************************************
+parse a lpq line. Choose printing style
+****************************************************************************/
+BOOL parse_lpq_entry(int snum,char *line,
+ print_queue_struct *buf,
+ print_status_struct *status,BOOL first)
+{
+ BOOL ret;
+
+ switch (lp_printing(snum))
+ {
+ case PRINT_SYSV:
+ ret = parse_lpq_sysv(line,buf,first);
+ break;
+ case PRINT_AIX:
+ ret = parse_lpq_aix(line,buf,first);
+ break;
+ case PRINT_HPUX:
+ ret = parse_lpq_hpux(line,buf,first);
+ break;
+ case PRINT_QNX:
+ ret = parse_lpq_qnx(line,buf,first);
+ break;
+ case PRINT_LPRNG:
+ ret = parse_lpq_lprng(line,buf,first);
+ break;
+ case PRINT_PLP:
+ ret = parse_lpq_plp(line,buf,first);
+ break;
+ case PRINT_SOFTQ:
+ ret = parse_lpq_softq(line,buf,first);
+ break;
+ case PRINT_LPRNT:
+ ret = parse_lpq_nt(line,buf,first);
+ break;
+ case PRINT_LPROS2:
+ ret = parse_lpq_os2(line,buf,first);
+ break;
+#ifdef DEVELOPER
+ case PRINT_VLP:
+ case PRINT_TEST:
+ ret = parse_lpq_vlp(line,buf,first);
+ break;
+#endif /* DEVELOPER */
+ default:
+ ret = parse_lpq_bsd(line,buf,first);
+ break;
+ }
+
+ /* We don't want the newline in the status message. */
+ {
+ char *p = strchr_m(line,'\n');
+ if (p) *p = 0;
+ }
+
+ /* in the LPRNG case, we skip lines starting by a space.*/
+ if (line && !ret && (lp_printing(snum)==PRINT_LPRNG) )
+ {
+ if (line[0]==' ')
+ return ret;
+ }
+
+
+ if (status && !ret)
+ {
+ /* a few simple checks to see if the line might be a
+ printer status line:
+ handle them so that most severe condition is shown */
+ int i;
+ strlower(line);
+
+ switch (status->status) {
+ case LPSTAT_OK:
+ for (i=0; stat0_strings[i]; i++)
+ if (strstr(line,stat0_strings[i])) {
+ StrnCpy(status->message,line,sizeof(status->message)-1);
+ status->status=LPSTAT_OK;
+ return ret;
+ }
+ case LPSTAT_STOPPED:
+ for (i=0; stat1_strings[i]; i++)
+ if (strstr(line,stat1_strings[i])) {
+ StrnCpy(status->message,line,sizeof(status->message)-1);
+ status->status=LPSTAT_STOPPED;
+ return ret;
+ }
+ case LPSTAT_ERROR:
+ for (i=0; stat2_strings[i]; i++)
+ if (strstr(line,stat2_strings[i])) {
+ StrnCpy(status->message,line,sizeof(status->message)-1);
+ status->status=LPSTAT_ERROR;
+ return ret;
+ }
+ break;
+ }
+ }
+
+ return(ret);
+}
diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c
new file mode 100644
index 00000000000..c2cd1d6eeb5
--- /dev/null
+++ b/source/printing/nt_printing.c
@@ -0,0 +1,3912 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern DOM_SID global_sid_World;
+
+static TDB_CONTEXT *tdb_forms; /* used for forms files */
+static TDB_CONTEXT *tdb_drivers; /* used for driver files */
+static TDB_CONTEXT *tdb_printers; /* used for printers files */
+
+#define FORMS_PREFIX "FORMS/"
+#define DRIVERS_PREFIX "DRIVERS/"
+#define DRIVER_INIT_PREFIX "DRIVER_INIT/"
+#define PRINTERS_PREFIX "PRINTERS/"
+#define SECDESC_PREFIX "SECDESC/"
+
+#define NTDRIVERS_DATABASE_VERSION_1 1
+#define NTDRIVERS_DATABASE_VERSION_2 2
+
+#define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_2
+
+/* Map generic permissions to printer object specific permissions */
+
+struct generic_mapping printer_generic_mapping = {
+ PRINTER_READ,
+ PRINTER_WRITE,
+ PRINTER_EXECUTE,
+ PRINTER_ALL_ACCESS
+};
+
+/* We need one default form to support our default printer. Msoft adds the
+forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
+array index). Letter is always first, so (for the current code) additions
+always put things in the correct order. */
+static nt_forms_struct default_forms[] = {
+ {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+ {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
+ {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
+ {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
+ {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
+ {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+ {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+ {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
+ {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+ {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+ {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
+ {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
+ {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+ {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
+ {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
+ {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
+ {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
+ {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
+ {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
+ {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
+ {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
+ {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+ {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
+ {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+ {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+ {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
+ {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
+ {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+ {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
+ {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+ {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
+ {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
+ {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
+ {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
+ {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
+ {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+ {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+ {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
+ {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
+ {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
+ {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
+ {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
+ {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+ {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+ {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+ {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
+ {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
+ {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
+ {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+ {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+ {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+ {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
+ {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
+ {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
+ {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
+ {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+ {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+ {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+ {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
+ {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
+ {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
+ {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+ {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+ {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
+ {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
+ {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
+ {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
+ {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
+ {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
+ {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
+ {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
+ {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
+ {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
+ {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
+ {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
+ {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
+ {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
+ {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
+ {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
+ {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
+ {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
+ {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
+ {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
+ {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
+ {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
+ {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
+ {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
+ {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
+ {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
+ {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
+ {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
+ {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
+ {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
+ {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
+ {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+ {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
+ {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
+ {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
+ {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+ {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+ {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
+ {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
+ {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
+ {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
+ {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
+ {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+ {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
+ {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
+ {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
+ {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
+ {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
+ {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
+ {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
+};
+
+static BOOL upgrade_to_version_2(void)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+
+ DEBUG(0,("upgrade_to_version_2: upgrading print tdb's to version 2\n"));
+
+ for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
+ newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+
+ dbuf = tdb_fetch(tdb_drivers, kbuf);
+
+ if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_2:moving form\n"));
+ if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_2:moving printer\n"));
+ if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
+ DEBUG(0,("upgrade_to_version_2:moving secdesc\n"));
+ if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
+ return False;
+ }
+ if (tdb_delete(tdb_drivers, kbuf) != 0) {
+ DEBUG(0,("upgrade_to_version_2: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
+ return False;
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+open the NT printing tdb
+****************************************************************************/
+BOOL nt_printing_init(void)
+{
+ static pid_t local_pid;
+ char *vstring = "INFO/version";
+
+ if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
+ return True;
+
+ tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_drivers) {
+ DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
+ lock_path("ntdrivers.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_printers) {
+ DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
+ lock_path("ntprinters.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb_forms) {
+ DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
+ lock_path("ntforms.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb_drivers, vstring);
+ if (tdb_fetch_int(tdb_drivers, vstring) != NTDRIVERS_DATABASE_VERSION) {
+
+ if (tdb_fetch_int(tdb_drivers, vstring) == NTDRIVERS_DATABASE_VERSION_1) {
+ if (!upgrade_to_version_2())
+ return False;
+ } else
+ tdb_traverse(tdb_drivers, (tdb_traverse_func)tdb_delete, NULL);
+
+ tdb_store_int(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
+ }
+ tdb_unlock_bystring(tdb_drivers, vstring);
+
+ return True;
+}
+
+/****************************************************************************
+ get builtin form struct list
+****************************************************************************/
+int get_builtin_ntforms(nt_forms_struct **list)
+{
+ *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
+ return sizeof(default_forms) / sizeof(default_forms[0]);
+}
+
+/****************************************************************************
+ get a builtin form struct
+****************************************************************************/
+
+BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
+{
+ int i,count;
+ fstring form_name;
+ unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
+ DEBUGADD(6,("Looking for builtin form %s \n", form_name));
+ count = sizeof(default_forms) / sizeof(default_forms[0]);
+ for (i=0;i<count;i++) {
+ if (strequal(form_name,default_forms[i].name)) {
+ DEBUGADD(6,("Found builtin form %s \n", form_name));
+ memcpy(form,&default_forms[i],sizeof(*form));
+ break;
+ }
+ }
+
+ return (i !=count);
+}
+
+/****************************************************************************
+get a form struct list
+****************************************************************************/
+int get_ntforms(nt_forms_struct **list)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+ nt_forms_struct *tl;
+ nt_forms_struct form;
+ int ret;
+ int i;
+ int n = 0;
+
+ for (kbuf = tdb_firstkey(tdb_forms);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+ if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) continue;
+
+ dbuf = tdb_fetch(tdb_forms, kbuf);
+ if (!dbuf.dptr) continue;
+
+ fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
+ &i, &form.flag, &form.width, &form.length, &form.left,
+ &form.top, &form.right, &form.bottom);
+ SAFE_FREE(dbuf.dptr);
+ if (ret != dbuf.dsize) continue;
+
+ tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
+ if (!tl) {
+ DEBUG(0,("get_ntforms: Realloc fail.\n"));
+ return 0;
+ }
+ *list = tl;
+ (*list)[n] = form;
+ n++;
+ }
+
+
+ return n;
+}
+
+/****************************************************************************
+write a form struct list
+****************************************************************************/
+int write_ntforms(nt_forms_struct **list, int number)
+{
+ pstring buf, key;
+ int len;
+ TDB_DATA kbuf,dbuf;
+ int i;
+
+ for (i=0;i<number;i++) {
+ /* save index, so list is rebuilt in correct order */
+ len = tdb_pack(buf, sizeof(buf), "dddddddd",
+ i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
+ (*list)[i].left, (*list)[i].top, (*list)[i].right,
+ (*list)[i].bottom);
+ if (len > sizeof(buf)) break;
+ slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+ dbuf.dsize = len;
+ dbuf.dptr = buf;
+ if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
+ }
+
+ return i;
+}
+
+/****************************************************************************
+add a form struct at the end of the list
+****************************************************************************/
+BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
+{
+ int n=0;
+ BOOL update;
+ fstring form_name;
+ nt_forms_struct *tl;
+
+ /*
+ * NT tries to add forms even when
+ * they are already in the base
+ * only update the values if already present
+ */
+
+ update=False;
+
+ unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
+ for (n=0; n<*count; n++) {
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
+ DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
+ update=True;
+ break;
+ }
+ }
+
+ if (update==False) {
+ if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
+ DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
+ return False;
+ }
+ *list = tl;
+ unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
+ (*count)++;
+ }
+
+ (*list)[n].flag=form->flags;
+ (*list)[n].width=form->size_x;
+ (*list)[n].length=form->size_y;
+ (*list)[n].left=form->left;
+ (*list)[n].top=form->top;
+ (*list)[n].right=form->right;
+ (*list)[n].bottom=form->bottom;
+
+ return True;
+}
+
+/****************************************************************************
+ delete a named form struct
+****************************************************************************/
+BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
+{
+ pstring key;
+ TDB_DATA kbuf;
+ int n=0;
+ fstring form_name;
+
+ *ret = WERR_OK;
+
+ unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
+
+ for (n=0; n<*count; n++) {
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
+ DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
+ break;
+ }
+ }
+
+ if (n == *count) {
+ DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
+ *ret = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+ if (tdb_delete(tdb_forms, kbuf) != 0) {
+ *ret = WERR_NOMEM;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+update a form struct
+****************************************************************************/
+void update_a_form(nt_forms_struct **list, const FORM *form, int count)
+{
+ int n=0;
+ fstring form_name;
+ unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
+
+ DEBUG(106, ("[%s]\n", form_name));
+ for (n=0; n<count; n++)
+ {
+ DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
+ break;
+ }
+
+ if (n==count) return;
+
+ (*list)[n].flag=form->flags;
+ (*list)[n].width=form->size_x;
+ (*list)[n].length=form->size_y;
+ (*list)[n].left=form->left;
+ (*list)[n].top=form->top;
+ (*list)[n].right=form->right;
+ (*list)[n].bottom=form->bottom;
+}
+
+/****************************************************************************
+get the nt drivers list
+
+traverse the database and look-up the matching names
+****************************************************************************/
+int get_ntdrivers(fstring **list, char *architecture, uint32 version)
+{
+ int total=0;
+ fstring short_archi;
+ fstring *fl;
+ pstring key;
+ TDB_DATA kbuf, newkey;
+
+ get_short_archi(short_archi, architecture);
+ slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
+
+ for (kbuf = tdb_firstkey(tdb_drivers);
+ kbuf.dptr;
+ newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
+ if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue;
+
+ if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
+ DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
+ return -1;
+ }
+ else *list = fl;
+
+ fstrcpy((*list)[total], kbuf.dptr+strlen(key));
+ total++;
+ }
+
+ return(total);
+}
+
+/****************************************************************************
+function to do the mapping between the long architecture name and
+the short one.
+****************************************************************************/
+BOOL get_short_archi(char *short_archi, char *long_archi)
+{
+ struct table {
+ char *long_archi;
+ char *short_archi;
+ };
+
+ struct table archi_table[]=
+ {
+ {"Windows 4.0", "WIN40" },
+ {"Windows NT x86", "W32X86" },
+ {"Windows NT R4000", "W32MIPS" },
+ {"Windows NT Alpha_AXP", "W32ALPHA" },
+ {"Windows NT PowerPC", "W32PPC" },
+ {NULL, "" }
+ };
+
+ int i=-1;
+
+ DEBUG(107,("Getting architecture dependant directory\n"));
+ do {
+ i++;
+ } while ( (archi_table[i].long_archi!=NULL ) &&
+ StrCaseCmp(long_archi, archi_table[i].long_archi) );
+
+ if (archi_table[i].long_archi==NULL) {
+ DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
+ return False;
+ }
+
+ StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
+
+ DEBUGADD(108,("index: [%d]\n", i));
+ DEBUGADD(108,("long architecture: [%s]\n", long_archi));
+ DEBUGADD(108,("short architecture: [%s]\n", short_archi));
+
+ return True;
+}
+
+/****************************************************************************
+Version information in Microsoft files is held in a VS_VERSION_INFO structure.
+There are two case to be covered here: PE (Portable Executable) and NE (New
+Executable) files. Both files support the same INFO structure, but PE files
+store the signature in unicode, and NE files store it as !unicode.
+****************************************************************************/
+static BOOL get_file_version(files_struct *fsp, char *fname,uint32 *major,
+ uint32 *minor)
+{
+ int i;
+ char *buf;
+ ssize_t byte_count;
+
+ if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
+ fname, PE_HEADER_SIZE));
+ goto error_exit;
+ }
+
+ /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
+ if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+ DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n",
+ fname, byte_count));
+ goto no_version_info;
+ }
+
+ /* Is this really a DOS header? */
+ if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+ DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
+ fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+ goto no_version_info;
+ }
+
+ /* Skip OEM header (if any) and the DOS stub to start of Windows header */
+ if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
+ fname, errno));
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ goto no_version_info;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
+ DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n",
+ fname, byte_count));
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ goto no_version_info;
+ }
+
+ /* The header may be a PE (Portable Executable) or an NE (New Executable) */
+ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+ int num_sections;
+ int section_table_bytes;
+
+ if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
+ DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
+ fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
+ /* At this point, we assume the file is in error. It still could be somthing
+ * else besides a PE file, but it unlikely at this point.
+ */
+ goto error_exit;
+ }
+
+ /* get the section table */
+ num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
+ section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
+ SAFE_FREE(buf);
+ if ((buf=malloc(section_table_bytes)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
+ fname, section_table_bytes));
+ goto error_exit;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
+ DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n",
+ fname, byte_count));
+ goto error_exit;
+ }
+
+ /* Iterate the section table looking for the resource section ".rsrc" */
+ for (i = 0; i < num_sections; i++) {
+ int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
+
+ if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
+ int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
+ int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
+
+ SAFE_FREE(buf);
+ if ((buf=malloc(section_bytes)) == NULL) {
+ DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
+ fname, section_bytes));
+ goto error_exit;
+ }
+
+ /* Seek to the start of the .rsrc section info */
+ if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
+ fname, errno));
+ goto error_exit;
+ }
+
+ if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
+ DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n",
+ fname, byte_count));
+ goto error_exit;
+ }
+
+ for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
+ /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
+ if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
+ /* Align to next long address */
+ int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
+
+ if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
+ *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
+ *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
+
+ DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+ fname, *major, *minor,
+ (*major>>16)&0xffff, *major&0xffff,
+ (*minor>>16)&0xffff, *minor&0xffff));
+ SAFE_FREE(buf);
+ return True;
+ }
+ }
+ }
+ }
+ }
+
+ /* Version info not found, fall back to origin date/time */
+ DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
+ SAFE_FREE(buf);
+ return False;
+
+ } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
+ if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
+ DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
+ fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+ /* At this point, we assume the file is in error. It still could be somthing
+ * else besides a NE file, but it unlikely at this point. */
+ goto error_exit;
+ }
+
+ /* Allocate a bit more space to speed up things */
+ SAFE_FREE(buf);
+ if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
+ DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
+ fname, PE_HEADER_SIZE));
+ goto error_exit;
+ }
+
+ /* This is a HACK! I got tired of trying to sort through the messy
+ * 'NE' file format. If anyone wants to clean this up please have at
+ * it, but this works. 'NE' files will eventually fade away. JRR */
+ while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
+ /* Cover case that should not occur in a well formed 'NE' .dll file */
+ if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
+
+ for(i=0; i<byte_count; i++) {
+ /* Fast skip past data that can't possibly match */
+ if (buf[i] != 'V') continue;
+
+ /* Potential match data crosses buf boundry, move it to beginning
+ * of buf, and fill the buf with as much as it will hold. */
+ if (i>byte_count-VS_VERSION_INFO_SIZE) {
+ int bc;
+
+ memcpy(buf, &buf[i], byte_count-i);
+ if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
+ (byte_count-i))) < 0) {
+
+ DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
+ fname, errno));
+ goto error_exit;
+ }
+
+ byte_count = bc + (byte_count - i);
+ if (byte_count<VS_VERSION_INFO_SIZE) break;
+
+ i = 0;
+ }
+
+ /* Check that the full signature string and the magic number that
+ * follows exist (not a perfect solution, but the chances that this
+ * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
+ * twice, as it is simpler to read the code. */
+ if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
+ /* Compute skip alignment to next long address */
+ int skip = -(fsp->conn->vfs_ops.lseek(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
+ sizeof(VS_SIGNATURE)) & 3;
+ if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
+
+ *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
+ *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
+ DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+ fname, *major, *minor,
+ (*major>>16)&0xffff, *major&0xffff,
+ (*minor>>16)&0xffff, *minor&0xffff));
+ SAFE_FREE(buf);
+ return True;
+ }
+ }
+ }
+
+ /* Version info not found, fall back to origin date/time */
+ DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
+ SAFE_FREE(buf);
+ return False;
+
+ } else
+ /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+ DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
+ fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+
+ no_version_info:
+ SAFE_FREE(buf);
+ return False;
+
+ error_exit:
+ SAFE_FREE(buf);
+ return -1;
+}
+
+/****************************************************************************
+Drivers for Microsoft systems contain multiple files. Often, multiple drivers
+share one or more files. During the MS installation process files are checked
+to insure that only a newer version of a shared file is installed over an
+older version. There are several possibilities for this comparison. If there
+is no previous version, the new one is newer (obviously). If either file is
+missing the version info structure, compare the creation date (on Unix use
+the modification date). Otherwise chose the numerically larger version number.
+****************************************************************************/
+static int file_version_is_newer(connection_struct *conn, fstring new_file,
+ fstring old_file)
+{
+ BOOL use_version = True;
+ pstring filepath;
+
+ uint32 new_major;
+ uint32 new_minor;
+ time_t new_create_time;
+
+ uint32 old_major;
+ uint32 old_minor;
+ time_t old_create_time;
+
+ int access_mode;
+ int action;
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ SMB_STRUCT_STAT stat_buf;
+ BOOL bad_path;
+
+ ZERO_STRUCT(st);
+ ZERO_STRUCT(stat_buf);
+ new_create_time = (time_t)0;
+ old_create_time = (time_t)0;
+
+ /* Get file version info (if available) for previous file (if it exists) */
+ pstrcpy(filepath, old_file);
+
+ unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
+
+ fsp = open_file_shared(conn, filepath, &stat_buf,
+ SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
+ if (!fsp) {
+ /* Old file not found, so by definition new file is in fact newer */
+ DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
+ filepath, errno));
+ return True;
+
+ } else {
+ int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
+ if (ret == -1) goto error_exit;
+
+ if (!ret) {
+ DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+ old_file));
+ use_version = False;
+ if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+ old_create_time = st.st_mtime;
+ DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
+ }
+ }
+ close_file(fsp, True);
+
+ /* Get file version info (if available) for new file */
+ pstrcpy(filepath, new_file);
+ unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
+
+ fsp = open_file_shared(conn, filepath, &stat_buf,
+ SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
+ if (!fsp) {
+ /* New file not found, this shouldn't occur if the caller did its job */
+ DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
+ filepath, errno));
+ goto error_exit;
+
+ } else {
+ int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
+ if (ret == -1) goto error_exit;
+
+ if (!ret) {
+ DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+ new_file));
+ use_version = False;
+ if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+ new_create_time = st.st_mtime;
+ DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
+ }
+ }
+ close_file(fsp, True);
+
+ if (use_version) {
+ /* Compare versions and choose the larger version number */
+ if (new_major > old_major ||
+ (new_major == old_major && new_minor > old_minor)) {
+
+ DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+ return True;
+ }
+ else {
+ DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+ return False;
+ }
+
+ } else {
+ /* Compare modification time/dates and choose the newest time/date */
+ if (new_create_time > old_create_time) {
+ DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+ return True;
+ }
+ else {
+ DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+ return False;
+ }
+ }
+
+ error_exit:
+ if(fsp)
+ close_file(fsp, True);
+ return -1;
+}
+
+/****************************************************************************
+Determine the correct cVersion associated with an architecture and driver
+****************************************************************************/
+static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
+ struct current_user *user, WERROR *perr)
+{
+ int cversion;
+ int access_mode;
+ int action;
+ NTSTATUS nt_status;
+ pstring driverpath;
+ DATA_BLOB null_pw;
+ files_struct *fsp = NULL;
+ BOOL bad_path;
+ SMB_STRUCT_STAT st;
+ connection_struct *conn;
+
+ ZERO_STRUCT(st);
+
+ /* If architecture is Windows 95/98/ME, the version is always 0. */
+ if (strcmp(architecture, "WIN40") == 0) {
+ DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
+ return 0;
+ }
+
+ /* connect to the print$ share under the same account as the user connected to the rpc pipe */
+ /* Null password is ok - we are already an authenticated user... */
+ null_pw = data_blob(NULL, 0);
+
+ become_root();
+ conn = make_connection("print$", null_pw, "A:", user->vuid, &nt_status);
+ unbecome_root();
+
+ if (conn == NULL) {
+ DEBUG(0,("get_correct_cversion: Unable to connect\n"));
+ *perr = ntstatus_to_werror(nt_status);
+ return -1;
+ }
+
+ /* We are temporarily becoming the connection user. */
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("get_correct_cversion: Can't become user!\n"));
+ *perr = WERR_ACCESS_DENIED;
+ return -1;
+ }
+
+ /* Open the driver file (Portable Executable format) and determine the
+ * deriver the cversion. */
+ slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
+
+ unix_convert(driverpath,conn,NULL,&bad_path,&st);
+
+ fsp = open_file_shared(conn, driverpath, &st,
+ SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
+ if (!fsp) {
+ DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
+ driverpath, errno));
+ *perr = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+ else {
+ uint32 major;
+ uint32 minor;
+ int ret = get_file_version(fsp, driverpath, &major, &minor);
+ if (ret == -1) goto error_exit;
+
+ if (!ret) {
+ DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
+ goto error_exit;
+ }
+
+ /*
+ * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
+ * for more details. Version in this case is not just the version of the
+ * file, but the version in the sense of kernal mode (2) vs. user mode
+ * (3) drivers. Other bits of the version fields are the version info.
+ * JRR 010716
+ */
+ cversion = major & 0x0000ffff;
+ switch (cversion) {
+ case 2: /* WinNT drivers */
+ case 3: /* Win2K drivers */
+ break;
+
+ default:
+ DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
+ driverpath, cversion));
+ goto error_exit;
+ }
+
+ DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
+ driverpath, major, minor));
+ }
+
+ DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+ driverpath, cversion));
+
+ close_file(fsp, True);
+ close_cnum(conn, user->vuid);
+ unbecome_user();
+ return cversion;
+
+ error_exit:
+
+ if(fsp)
+ close_file(fsp, True);
+
+ close_cnum(conn, user->vuid);
+ unbecome_user();
+ return -1;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
+ struct current_user *user)
+{
+ fstring architecture;
+ fstring new_name;
+ char *p;
+ int i;
+ WERROR err;
+
+ /* clean up the driver name.
+ * we can get .\driver.dll
+ * or worse c:\windows\system\driver.dll !
+ */
+ /* using an intermediate string to not have overlaping memcpy()'s */
+ if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->driverpath, new_name);
+ }
+
+ if ((p = strrchr(driver->datafile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->datafile, new_name);
+ }
+
+ if ((p = strrchr(driver->configfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->configfile, new_name);
+ }
+
+ if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->helpfile, new_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->dependentfiles[i], new_name);
+ }
+ }
+ }
+
+ get_short_archi(architecture, driver->environment);
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+ if ((driver->cversion = get_correct_cversion( architecture,
+ driver->driverpath, user, &err)) == -1)
+ return err;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver,
+ struct current_user *user)
+{
+ fstring architecture;
+ fstring new_name;
+ char *p;
+ int i;
+ WERROR err;
+
+ /* clean up the driver name.
+ * we can get .\driver.dll
+ * or worse c:\windows\system\driver.dll !
+ */
+ /* using an intermediate string to not have overlaping memcpy()'s */
+ if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->driverpath, new_name);
+ }
+
+ if ((p = strrchr(driver->datafile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->datafile, new_name);
+ }
+
+ if ((p = strrchr(driver->configfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->configfile, new_name);
+ }
+
+ if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->helpfile, new_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->dependentfiles[i], new_name);
+ }
+ }
+ }
+
+ get_short_archi(architecture, driver->environment);
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+ if ((driver->version = get_correct_cversion(architecture,
+ driver->driverpath, user, &err)) == -1)
+ return err;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
+ uint32 level, struct current_user *user)
+{
+ switch (level) {
+ case 3:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
+ driver=driver_abstract.info_3;
+ return clean_up_driver_struct_level_3(driver, user);
+ }
+ case 6:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
+ driver=driver_abstract.info_6;
+ return clean_up_driver_struct_level_6(driver, user);
+ }
+ default:
+ return WERR_INVALID_PARAM;
+ }
+}
+
+/****************************************************************************
+ This function sucks and should be replaced. JRA.
+****************************************************************************/
+
+static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
+{
+ dst->cversion = src->version;
+
+ fstrcpy( dst->name, src->name);
+ fstrcpy( dst->environment, src->environment);
+ fstrcpy( dst->driverpath, src->driverpath);
+ fstrcpy( dst->datafile, src->datafile);
+ fstrcpy( dst->configfile, src->configfile);
+ fstrcpy( dst->helpfile, src->helpfile);
+ fstrcpy( dst->monitorname, src->monitorname);
+ fstrcpy( dst->defaultdatatype, src->defaultdatatype);
+ dst->dependentfiles = src->dependentfiles;
+}
+
+#if 0 /* Debugging function */
+
+static char* ffmt(unsigned char *c){
+ int i;
+ static char ffmt_str[17];
+
+ for (i=0; i<16; i++) {
+ if ((c[i] < ' ') || (c[i] > '~'))
+ ffmt_str[i]='.';
+ else
+ ffmt_str[i]=c[i];
+ }
+ ffmt_str[16]='\0';
+ return ffmt_str;
+}
+
+#endif
+
+/****************************************************************************
+****************************************************************************/
+BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
+ struct current_user *user, WERROR *perr)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
+ fstring architecture;
+ pstring new_dir;
+ pstring old_name;
+ pstring new_name;
+ DATA_BLOB null_pw;
+ connection_struct *conn;
+ NTSTATUS nt_status;
+ int ver = 0;
+ int i;
+
+ *perr = WERR_OK;
+
+ if (level==3)
+ driver=driver_abstract.info_3;
+ else if (level==6) {
+ convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
+ driver = &converted_driver;
+ } else {
+ DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
+ return False;
+ }
+
+ get_short_archi(architecture, driver->environment);
+
+ /* connect to the print$ share under the same account as the user connected to the rpc pipe */
+ /* Null password is ok - we are already an authenticated user... */
+ null_pw = data_blob(NULL, 0);
+ conn = make_connection("print$", null_pw, "A:", user->vuid, &nt_status);
+
+ if (conn == NULL) {
+ DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
+ *perr = ntstatus_to_werror(nt_status);
+ return False;
+ }
+
+ /*
+ * Save who we are - we are temporarily becoming the connection user.
+ */
+
+ push_sec_ctx();
+
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
+ pop_sec_ctx();
+ return False;
+ }
+
+ /*
+ * make the directories version and version\driver_name
+ * under the architecture directory.
+ */
+ DEBUG(5,("Creating first directory\n"));
+ slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
+ mkdir_internal(conn, new_dir);
+
+ /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
+ * listed for this driver which has already been moved, skip it (note:
+ * drivers may list the same file name several times. Then check if the
+ * file already exists in archi\cversion\, if so, check that the version
+ * info (or time stamps if version info is unavailable) is newer (or the
+ * date is later). If it is, move it to archi\cversion\filexxx.yyy.
+ * Otherwise, delete the file.
+ *
+ * If a file is not moved to archi\cversion\ because of an error, all the
+ * rest of the 'unmoved' driver files are removed from archi\. If one or
+ * more of the driver's files was already moved to archi\cversion\, it
+ * potentially leaves the driver in a partially updated state. Version
+ * trauma will most likely occur if an client attempts to use any printer
+ * bound to the driver. Perhaps a rewrite to make sure the moves can be
+ * done is appropriate... later JRR
+ */
+
+ DEBUG(5,("Moving files now !\n"));
+
+ if (driver->driverpath && strlen(driver->driverpath)) {
+ slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
+ slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ NTSTATUS status;
+ status = rename_internals(conn, new_name, old_name, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = ntstatus_to_werror(status);
+ unlink_internals(conn, 0, new_name);
+ ver = -1;
+ }
+ }
+ else
+ unlink_internals(conn, 0, new_name);
+ }
+
+ if (driver->datafile && strlen(driver->datafile)) {
+ if (!strequal(driver->datafile, driver->driverpath)) {
+ slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
+ slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ NTSTATUS status;
+ status = rename_internals(conn, new_name, old_name, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = ntstatus_to_werror(status);
+ unlink_internals(conn, 0, new_name);
+ ver = -1;
+ }
+ }
+ else
+ unlink_internals(conn, 0, new_name);
+ }
+ }
+
+ if (driver->configfile && strlen(driver->configfile)) {
+ if (!strequal(driver->configfile, driver->driverpath) &&
+ !strequal(driver->configfile, driver->datafile)) {
+ slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
+ slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ NTSTATUS status;
+ status = rename_internals(conn, new_name, old_name, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = ntstatus_to_werror(status);
+ unlink_internals(conn, 0, new_name);
+ ver = -1;
+ }
+ }
+ else
+ unlink_internals(conn, 0, new_name);
+ }
+ }
+
+ if (driver->helpfile && strlen(driver->helpfile)) {
+ if (!strequal(driver->helpfile, driver->driverpath) &&
+ !strequal(driver->helpfile, driver->datafile) &&
+ !strequal(driver->helpfile, driver->configfile)) {
+ slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
+ slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ NTSTATUS status;
+ status = rename_internals(conn, new_name, old_name, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = ntstatus_to_werror(status);
+ unlink_internals(conn, 0, new_name);
+ ver = -1;
+ }
+ }
+ else
+ unlink_internals(conn, 0, new_name);
+ }
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
+ !strequal(driver->dependentfiles[i], driver->datafile) &&
+ !strequal(driver->dependentfiles[i], driver->configfile) &&
+ !strequal(driver->dependentfiles[i], driver->helpfile)) {
+ int j;
+ for (j=0; j < i; j++) {
+ if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
+ goto NextDriver;
+ }
+ }
+
+ slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
+ slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
+ if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+ NTSTATUS status;
+ status = rename_internals(conn, new_name, old_name, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+ new_name, old_name));
+ *perr = ntstatus_to_werror(status);
+ unlink_internals(conn, 0, new_name);
+ ver = -1;
+ }
+ }
+ else
+ unlink_internals(conn, 0, new_name);
+ }
+ NextDriver: ;
+ }
+ }
+
+ close_cnum(conn, user->vuid);
+ pop_sec_ctx();
+
+ return ver == -1 ? False : True;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+{
+ int len, buflen;
+ fstring architecture;
+ pstring directory;
+ pstring temp_name;
+ pstring key;
+ char *buf;
+ int i, ret;
+ TDB_DATA kbuf, dbuf;
+
+ get_short_archi(architecture, driver->environment);
+
+ /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
+ * \\server is added in the rpc server layer.
+ * It does make sense to NOT store the server's name in the printer TDB.
+ */
+
+ slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
+
+ /* .inf files do not always list a file for each of the four standard files.
+ * Don't prepend a path to a null filename, or client claims:
+ * "The server on which the printer resides does not have a suitable
+ * <printer driver name> printer driver installed. Click OK if you
+ * wish to install the driver on your local machine."
+ */
+ if (strlen(driver->driverpath)) {
+ fstrcpy(temp_name, driver->driverpath);
+ slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->datafile)) {
+ fstrcpy(temp_name, driver->datafile);
+ slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->configfile)) {
+ fstrcpy(temp_name, driver->configfile);
+ slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (strlen(driver->helpfile)) {
+ fstrcpy(temp_name, driver->helpfile);
+ slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ fstrcpy(temp_name, driver->dependentfiles[i]);
+ slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
+ }
+ }
+
+ slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
+
+ DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
+
+ buf = NULL;
+ len = buflen = 0;
+
+ again:
+ len = 0;
+ len += tdb_pack(buf+len, buflen-len, "dffffffff",
+ driver->cversion,
+ driver->name,
+ driver->environment,
+ driver->driverpath,
+ driver->datafile,
+ driver->configfile,
+ driver->helpfile,
+ driver->monitorname,
+ driver->defaultdatatype);
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ len += tdb_pack(buf+len, buflen-len, "f",
+ driver->dependentfiles[i]);
+ }
+ }
+
+ if (len != buflen) {
+ char *tb;
+
+ tb = (char *)Realloc(buf, len);
+ if (!tb) {
+ DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
+ ret = -1;
+ goto done;
+ }
+ else buf = tb;
+ buflen = len;
+ goto again;
+ }
+
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
+
+done:
+ if (ret)
+ DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
+
+ SAFE_FREE(buf);
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
+
+ ZERO_STRUCT(info3);
+ info3.cversion = driver->version;
+ fstrcpy(info3.name,driver->name);
+ fstrcpy(info3.environment,driver->environment);
+ fstrcpy(info3.driverpath,driver->driverpath);
+ fstrcpy(info3.datafile,driver->datafile);
+ fstrcpy(info3.configfile,driver->configfile);
+ fstrcpy(info3.helpfile,driver->helpfile);
+ fstrcpy(info3.monitorname,driver->monitorname);
+ fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
+ info3.dependentfiles = driver->dependentfiles;
+
+ return add_a_printer_driver_3(&info3);
+}
+
+
+/****************************************************************************
+****************************************************************************/
+static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring in_prt, fstring in_arch)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
+
+ ZERO_STRUCT(info);
+
+ fstrcpy(info.name, in_prt);
+ fstrcpy(info.defaultdatatype, "RAW");
+
+ fstrcpy(info.driverpath, "");
+ fstrcpy(info.datafile, "");
+ fstrcpy(info.configfile, "");
+ fstrcpy(info.helpfile, "");
+
+ if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
+ return WERR_NOMEM;
+
+ memset(info.dependentfiles, '\0', 2*sizeof(fstring));
+ fstrcpy(info.dependentfiles[0], "");
+
+ *info_ptr = memdup(&info, sizeof(info));
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring in_prt, fstring in_arch, uint32 version)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
+ TDB_DATA kbuf, dbuf;
+ fstring architecture;
+ int len = 0;
+ int i;
+ pstring key;
+
+ ZERO_STRUCT(driver);
+
+ get_short_archi(architecture, in_arch);
+
+ DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, in_prt));
+
+ slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, in_prt);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ dbuf = tdb_fetch(tdb_drivers, kbuf);
+#if 0
+ if (!dbuf.dptr) return get_a_printer_driver_3_default(info_ptr, in_prt, in_arch);
+#else
+ if (!dbuf.dptr) return WERR_ACCESS_DENIED;
+#endif
+ len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
+ &driver.cversion,
+ driver.name,
+ driver.environment,
+ driver.driverpath,
+ driver.datafile,
+ driver.configfile,
+ driver.helpfile,
+ driver.monitorname,
+ driver.defaultdatatype);
+
+ i=0;
+ while (len < dbuf.dsize) {
+ fstring *tddfs;
+
+ tddfs = (fstring *)Realloc(driver.dependentfiles,
+ sizeof(fstring)*(i+2));
+ if (tddfs == NULL) {
+ DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
+ break;
+ }
+ else driver.dependentfiles = tddfs;
+
+ len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
+ &driver.dependentfiles[i]);
+ i++;
+ }
+ if (driver.dependentfiles != NULL)
+ fstrcpy(driver.dependentfiles[i], "");
+
+ SAFE_FREE(dbuf.dptr);
+
+ if (len != dbuf.dsize) {
+ SAFE_FREE(driver.dependentfiles);
+
+ return get_a_printer_driver_3_default(info_ptr, in_prt, in_arch);
+ }
+
+ *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ TDB_DATA kbuf;
+ pstring key;
+ int i;
+ line[0] = '\0';
+
+ slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, "WIN40", 0, model);
+ DEBUG(10,("driver key: [%s]\n", key));
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+ if (!tdb_exists(tdb_drivers, kbuf)) return False;
+
+ ZERO_STRUCT(info3);
+ get_a_printer_driver_3(&info3, model, "Windows 4.0", 0);
+
+ DEBUGADD(10,("info3->name [%s]\n", info3->name));
+ DEBUGADD(10,("info3->datafile [%s]\n", info3->datafile));
+ DEBUGADD(10,("info3->helpfile [%s]\n", info3->helpfile));
+ DEBUGADD(10,("info3->monitorname [%s]\n", info3->monitorname));
+ DEBUGADD(10,("info3->defaultdatatype [%s]\n", info3->defaultdatatype));
+ for (i=0; info3->dependentfiles && *info3->dependentfiles[i]; i++) {
+ DEBUGADD(10,("info3->dependentfiles [%s]\n", info3->dependentfiles[i]));
+ }
+ DEBUGADD(10,("info3->environment [%s]\n", info3->environment));
+ DEBUGADD(10,("info3->driverpath [%s]\n", info3->driverpath));
+ DEBUGADD(10,("info3->configfile [%s]\n", info3->configfile));
+
+ /*pstrcat(line, info3->name); pstrcat(line, ":");*/
+ trim_string(info3->configfile, "\\print$\\WIN40\\0\\", 0);
+ pstrcat(line, info3->configfile);
+ pstrcat(line, ":");
+ trim_string(info3->datafile, "\\print$\\WIN40\\0\\", 0);
+ pstrcat(line, info3->datafile);
+ pstrcat(line, ":");
+ trim_string(info3->helpfile, "\\print$\\WIN40\\0\\", 0);
+ pstrcat(line, info3->helpfile);
+ pstrcat(line, ":");
+ trim_string(info3->monitorname, "\\print$\\WIN40\\0\\", 0);
+ pstrcat(line, info3->monitorname);
+ pstrcat(line, ":");
+ pstrcat(line, "RAW"); /*info3->defaultdatatype);*/
+ pstrcat(line, ":");
+
+ for (i=0; info3->dependentfiles &&
+ *info3->dependentfiles[i]; i++) {
+ if (i) pstrcat(line, ","); /* don't end in a "," */
+ trim_string(info3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
+ pstrcat(line, info3->dependentfiles[i]);
+ }
+
+ SAFE_FREE(info3);
+
+ return True;
+}
+
+/****************************************************************************
+debugging function, dump at level 6 the struct in the logs
+****************************************************************************/
+static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ int i;
+
+ DEBUG(106,("Dumping printer driver at level [%d]\n", level));
+
+ switch (level)
+ {
+ case 3:
+ {
+ if (driver.info_3 == NULL)
+ result=5;
+ else {
+ info3=driver.info_3;
+
+ DEBUGADD(106,("version:[%d]\n", info3->cversion));
+ DEBUGADD(106,("name:[%s]\n", info3->name));
+ DEBUGADD(106,("environment:[%s]\n", info3->environment));
+ DEBUGADD(106,("driverpath:[%s]\n", info3->driverpath));
+ DEBUGADD(106,("datafile:[%s]\n", info3->datafile));
+ DEBUGADD(106,("configfile:[%s]\n", info3->configfile));
+ DEBUGADD(106,("helpfile:[%s]\n", info3->helpfile));
+ DEBUGADD(106,("monitorname:[%s]\n", info3->monitorname));
+ DEBUGADD(106,("defaultdatatype:[%s]\n", info3->defaultdatatype));
+
+ for (i=0; info3->dependentfiles &&
+ *info3->dependentfiles[i]; i++) {
+ DEBUGADD(106,("dependentfile:[%s]\n",
+ info3->dependentfiles[i]));
+ }
+ result=0;
+ }
+ break;
+ }
+ default:
+ DEBUGADD(1,("Level not implemented\n"));
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+static int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
+{
+ int len = 0;
+
+ len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
+
+ if (!nt_devmode) return len;
+
+ len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
+ nt_devmode->devicename,
+ nt_devmode->formname,
+
+ nt_devmode->specversion,
+ nt_devmode->driverversion,
+ nt_devmode->size,
+ nt_devmode->driverextra,
+ nt_devmode->orientation,
+ nt_devmode->papersize,
+ nt_devmode->paperlength,
+ nt_devmode->paperwidth,
+ nt_devmode->scale,
+ nt_devmode->copies,
+ nt_devmode->defaultsource,
+ nt_devmode->printquality,
+ nt_devmode->color,
+ nt_devmode->duplex,
+ nt_devmode->yresolution,
+ nt_devmode->ttoption,
+ nt_devmode->collate,
+ nt_devmode->logpixels,
+
+ nt_devmode->fields,
+ nt_devmode->bitsperpel,
+ nt_devmode->pelswidth,
+ nt_devmode->pelsheight,
+ nt_devmode->displayflags,
+ nt_devmode->displayfrequency,
+ nt_devmode->icmmethod,
+ nt_devmode->icmintent,
+ nt_devmode->mediatype,
+ nt_devmode->dithertype,
+ nt_devmode->reserved1,
+ nt_devmode->reserved2,
+ nt_devmode->panningwidth,
+ nt_devmode->panningheight,
+ nt_devmode->private);
+
+
+ if (nt_devmode->private) {
+ len += tdb_pack(buf+len, buflen-len, "B",
+ nt_devmode->driverextra,
+ nt_devmode->private);
+ }
+
+ DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
+
+ return len;
+}
+
+/****************************************************************************
+****************************************************************************/
+static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen)
+{
+ int len = 0;
+
+ while (param != NULL) {
+ len += tdb_pack(buf+len, buflen-len, "pfdB",
+ param,
+ param->value,
+ param->type,
+ param->data_len,
+ param->data);
+ param=param->next;
+ }
+
+ len += tdb_pack(buf+len, buflen-len, "p", param);
+
+ return len;
+}
+
+
+/****************************************************************************
+delete a printer - this just deletes the printer info file, any open
+handles are not affected
+****************************************************************************/
+uint32 del_a_printer(char *sharename)
+{
+ pstring key;
+ TDB_DATA kbuf;
+
+ slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
+
+ kbuf.dptr=key;
+ kbuf.dsize=strlen(key)+1;
+
+ tdb_delete(tdb_printers, kbuf);
+ return 0;
+}
+
+/* FIXME!!! Reorder so this forward declaration is not necessary --jerry */
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, fstring);
+static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **);
+/****************************************************************************
+****************************************************************************/
+static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
+{
+ pstring key;
+ char *buf;
+ int buflen, len;
+ WERROR ret;
+ TDB_DATA kbuf, dbuf;
+
+ /*
+ * in addprinter: no servername and the printer is the name
+ * in setprinter: servername is \\server
+ * and printer is \\server\\printer
+ *
+ * Samba manages only local printers.
+ * we currently don't support things like path=\\other_server\printer
+ */
+
+ if (info->servername[0]!='\0') {
+ trim_string(info->printername, info->servername, NULL);
+ trim_string(info->printername, "\\", NULL);
+ info->servername[0]='\0';
+ }
+
+ /*
+ * JFM: one day I'll forget.
+ * below that's info->portname because that's the SAMBA sharename
+ * and I made NT 'thinks' it's the portname
+ * the info->sharename is the thing you can name when you add a printer
+ * that's the short-name when you create shared printer for 95/98
+ * So I've made a limitation in SAMBA: you can only have 1 printer model
+ * behind a SAMBA share.
+ */
+
+ buf = NULL;
+ buflen = 0;
+
+ again:
+ len = 0;
+ len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
+ info->attributes,
+ info->priority,
+ info->default_priority,
+ info->starttime,
+ info->untiltime,
+ info->status,
+ info->cjobs,
+ info->averageppm,
+ info->changeid,
+ info->c_setprinter,
+ info->setuptime,
+ info->servername,
+ info->printername,
+ info->sharename,
+ info->portname,
+ info->drivername,
+ info->comment,
+ info->location,
+ info->sepfile,
+ info->printprocessor,
+ info->datatype,
+ info->parameters);
+
+ len += pack_devicemode(info->devmode, buf+len, buflen-len);
+
+ len += pack_specifics(info->specific, buf+len, buflen-len);
+
+ if (buflen != len) {
+ char *tb;
+
+ tb = (char *)Realloc(buf, len);
+ if (!tb) {
+ DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
+ ret = WERR_NOMEM;
+ goto done;
+ }
+ else buf = tb;
+ buflen = len;
+ goto again;
+ }
+
+
+ slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
+
+done:
+ if (!W_ERROR_IS_OK(ret))
+ DEBUG(8, ("error updating printer to tdb on disk\n"));
+
+ SAFE_FREE(buf);
+
+ DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
+ info->sharename, info->drivername, info->portname, len));
+
+ return ret;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+void add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM **param)
+{
+ NT_PRINTER_PARAM *current;
+
+ DEBUG(108,("add_a_specific_param\n"));
+
+ (*param)->next=NULL;
+
+ if (info_2->specific == NULL)
+ {
+ info_2->specific=*param;
+ }
+ else
+ {
+ current=info_2->specific;
+ while (current->next != NULL) {
+ current=current->next;
+ }
+ current->next=*param;
+ }
+
+ *param = NULL;
+}
+
+/****************************************************************************
+****************************************************************************/
+BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
+{
+ NT_PRINTER_PARAM *current;
+ NT_PRINTER_PARAM *previous;
+
+ current=info_2->specific;
+ previous=current;
+
+ if (current==NULL) return (False);
+
+ if ( !strcmp(current->value, param->value) &&
+ (strlen(current->value)==strlen(param->value)) ) {
+ DEBUG(109,("deleting first value\n"));
+ info_2->specific=current->next;
+ SAFE_FREE(current->data);
+ SAFE_FREE(current);
+ DEBUG(109,("deleted first value\n"));
+ return (True);
+ }
+
+ current=previous->next;
+
+ while ( current!=NULL ) {
+ if (!strcmp(current->value, param->value) &&
+ strlen(current->value)==strlen(param->value) ) {
+ DEBUG(109,("deleting current value\n"));
+ previous->next=current->next;
+ SAFE_FREE(current->data);
+ SAFE_FREE(current);
+ DEBUG(109,("deleted current value\n"));
+ return(True);
+ }
+
+ previous=previous->next;
+ current=current->next;
+ }
+ return (False);
+}
+
+/****************************************************************************
+ Clean up and deallocate a (maybe partially) allocated NT_PRINTER_PARAM.
+****************************************************************************/
+void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr)
+{
+ NT_PRINTER_PARAM *param = *param_ptr;
+
+ if(param == NULL)
+ return;
+
+ DEBUG(106,("free_nt_printer_param: deleting param [%s]\n", param->value));
+
+ SAFE_FREE(param->data);
+ SAFE_FREE(*param_ptr);
+}
+
+/****************************************************************************
+ Malloc and return an NT devicemode.
+****************************************************************************/
+
+NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
+{
+/*
+ * should I init this ones ???
+ nt_devmode->devicename
+*/
+
+ char adevice[32];
+ NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
+
+ if (nt_devmode == NULL) {
+ DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(nt_devmode);
+
+ safe_strcpy(adevice, default_devicename, sizeof(adevice));
+ fstrcpy(nt_devmode->devicename, adevice);
+
+ fstrcpy(nt_devmode->formname, "Letter");
+
+ nt_devmode->specversion = 0x0401;
+ nt_devmode->driverversion = 0x0400;
+ nt_devmode->size = 0x00DC;
+ nt_devmode->driverextra = 0x0000;
+ nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
+ DEFAULTSOURCE | COPIES | SCALE |
+ PAPERSIZE | ORIENTATION;
+ nt_devmode->orientation = 1;
+ nt_devmode->papersize = PAPER_LETTER;
+ nt_devmode->paperlength = 0;
+ nt_devmode->paperwidth = 0;
+ nt_devmode->scale = 0x64;
+ nt_devmode->copies = 1;
+ nt_devmode->defaultsource = BIN_FORMSOURCE;
+ nt_devmode->printquality = RES_HIGH; /* 0x0258 */
+ nt_devmode->color = COLOR_MONOCHROME;
+ nt_devmode->duplex = DUP_SIMPLEX;
+ nt_devmode->yresolution = 0;
+ nt_devmode->ttoption = TT_SUBDEV;
+ nt_devmode->collate = COLLATE_FALSE;
+ nt_devmode->icmmethod = 0;
+ nt_devmode->icmintent = 0;
+ nt_devmode->mediatype = 0;
+ nt_devmode->dithertype = 0;
+
+ /* non utilisés par un driver d'imprimante */
+ nt_devmode->logpixels = 0;
+ nt_devmode->bitsperpel = 0;
+ nt_devmode->pelswidth = 0;
+ nt_devmode->pelsheight = 0;
+ nt_devmode->displayflags = 0;
+ nt_devmode->displayfrequency = 0;
+ nt_devmode->reserved1 = 0;
+ nt_devmode->reserved2 = 0;
+ nt_devmode->panningwidth = 0;
+ nt_devmode->panningheight = 0;
+
+ nt_devmode->private = NULL;
+ return nt_devmode;
+}
+
+/****************************************************************************
+ Deepcopy an NT devicemode.
+****************************************************************************/
+
+NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
+{
+ NT_DEVICEMODE *new_nt_devicemode = NULL;
+
+ if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
+ DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+
+ new_nt_devicemode->private = NULL;
+ if (nt_devicemode->private != NULL) {
+ if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
+ SAFE_FREE(new_nt_devicemode);
+ DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
+ return NULL;
+ }
+ }
+
+ return new_nt_devicemode;
+}
+
+/****************************************************************************
+ Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
+****************************************************************************/
+
+void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
+{
+ NT_DEVICEMODE *nt_devmode = *devmode_ptr;
+
+ if(nt_devmode == NULL)
+ return;
+
+ DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
+
+ SAFE_FREE(nt_devmode->private);
+ SAFE_FREE(*devmode_ptr);
+}
+
+/****************************************************************************
+ Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
+****************************************************************************/
+static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
+{
+ NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
+ NT_PRINTER_PARAM *param_ptr;
+
+ if(info == NULL)
+ return;
+
+ DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
+
+ free_nt_devicemode(&info->devmode);
+
+ for(param_ptr = info->specific; param_ptr; ) {
+ NT_PRINTER_PARAM *tofree = param_ptr;
+
+ param_ptr = param_ptr->next;
+ free_nt_printer_param(&tofree);
+ }
+
+ SAFE_FREE(*info_ptr);
+}
+
+
+/****************************************************************************
+****************************************************************************/
+static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
+{
+ int len = 0;
+ int extra_len = 0;
+ NT_DEVICEMODE devmode;
+
+ ZERO_STRUCT(devmode);
+
+ len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
+
+ if (!*nt_devmode) return len;
+
+ len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
+ devmode.devicename,
+ devmode.formname,
+
+ &devmode.specversion,
+ &devmode.driverversion,
+ &devmode.size,
+ &devmode.driverextra,
+ &devmode.orientation,
+ &devmode.papersize,
+ &devmode.paperlength,
+ &devmode.paperwidth,
+ &devmode.scale,
+ &devmode.copies,
+ &devmode.defaultsource,
+ &devmode.printquality,
+ &devmode.color,
+ &devmode.duplex,
+ &devmode.yresolution,
+ &devmode.ttoption,
+ &devmode.collate,
+ &devmode.logpixels,
+
+ &devmode.fields,
+ &devmode.bitsperpel,
+ &devmode.pelswidth,
+ &devmode.pelsheight,
+ &devmode.displayflags,
+ &devmode.displayfrequency,
+ &devmode.icmmethod,
+ &devmode.icmintent,
+ &devmode.mediatype,
+ &devmode.dithertype,
+ &devmode.reserved1,
+ &devmode.reserved2,
+ &devmode.panningwidth,
+ &devmode.panningheight,
+ &devmode.private);
+
+ if (devmode.private) {
+ /* the len in tdb_unpack is an int value and
+ * devmode.driverextra is only a short
+ */
+ len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
+ devmode.driverextra=(uint16)extra_len;
+
+ /* check to catch an invalid TDB entry so we don't segfault */
+ if (devmode.driverextra == 0) {
+ devmode.private = NULL;
+ }
+ }
+
+ *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
+
+ DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
+ if (devmode.private)
+ DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
+
+ return len;
+}
+
+/****************************************************************************
+****************************************************************************/
+static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen)
+{
+ int len = 0;
+ NT_PRINTER_PARAM param, *p;
+
+ *list = NULL;
+
+ while (1) {
+ len += tdb_unpack(buf+len, buflen-len, "p", &p);
+ if (!p) break;
+
+ len += tdb_unpack(buf+len, buflen-len, "fdB",
+ param.value,
+ &param.type,
+ &param.data_len,
+ &param.data);
+ param.next = *list;
+ *list = memdup(&param, sizeof(param));
+
+ DEBUG(8,("specific: [%s], len: %d\n", param.value, param.data_len));
+ }
+
+ return len;
+}
+
+static void map_to_os2_driver(fstring drivername)
+{
+ static BOOL initialised=False;
+ static fstring last_from,last_to;
+ char *mapfile = lp_os2_driver_map();
+ char **lines = NULL;
+ int numlines = 0;
+ int i;
+
+ if (!strlen(drivername))
+ return;
+
+ if (!*mapfile)
+ return;
+
+ if (!initialised) {
+ *last_from = *last_to = 0;
+ initialised = True;
+ }
+
+ if (strequal(drivername,last_from)) {
+ DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
+ fstrcpy(drivername,last_to);
+ return;
+ }
+
+ lines = file_lines_load(mapfile, &numlines);
+ if (numlines == 0) {
+ DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
+ return;
+ }
+
+ DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
+
+ for( i = 0; i < numlines; i++) {
+ char *nt_name = lines[i];
+ char *os2_name = strchr(nt_name,'=');
+
+ if (!os2_name)
+ continue;
+
+ *os2_name++ = 0;
+
+ while (isspace(*nt_name))
+ nt_name++;
+
+ if (!*nt_name || strchr("#;",*nt_name))
+ continue;
+
+ {
+ int l = strlen(nt_name);
+ while (l && isspace(nt_name[l-1])) {
+ nt_name[l-1] = 0;
+ l--;
+ }
+ }
+
+ while (isspace(*os2_name))
+ os2_name++;
+
+ {
+ int l = strlen(os2_name);
+ while (l && isspace(os2_name[l-1])) {
+ os2_name[l-1] = 0;
+ l--;
+ }
+ }
+
+ if (strequal(nt_name,drivername)) {
+ DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
+ fstrcpy(last_from,drivername);
+ fstrcpy(last_to,os2_name);
+ fstrcpy(drivername,os2_name);
+ file_lines_free(lines);
+ return;
+ }
+ }
+
+ file_lines_free(lines);
+}
+
+/****************************************************************************
+get a default printer info 2 struct
+****************************************************************************/
+static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
+{
+ extern pstring global_myname;
+ int snum;
+ NT_PRINTER_INFO_LEVEL_2 info;
+
+ ZERO_STRUCT(info);
+
+ snum = lp_servicenumber(sharename);
+
+ slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", global_myname);
+ slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
+ global_myname, sharename);
+ fstrcpy(info.sharename, sharename);
+ fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
+ fstrcpy(info.drivername, lp_printerdriver(snum));
+
+ /* by setting the driver name to an empty string, a local NT admin
+ can now run the **local** APW to install a local printer driver
+ for a Samba shared printer in 2.2. Without this, drivers **must** be
+ installed on the Samba server for NT clients --jerry */
+#if 0 /* JERRY --do not uncomment-- */
+ if (!*info.drivername)
+ fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
+#endif
+
+
+ DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
+
+ pstrcpy(info.comment, "");
+ fstrcpy(info.printprocessor, "winprint");
+ fstrcpy(info.datatype, "RAW");
+
+ info.attributes = PRINTER_ATTRIBUTE_SHARED \
+ | PRINTER_ATTRIBUTE_LOCAL \
+ | PRINTER_ATTRIBUTE_RAW_ONLY \
+ | PRINTER_ATTRIBUTE_QUEUED ; /* attributes */
+
+ info.starttime = 0; /* Minutes since 12:00am GMT */
+ info.untiltime = 0; /* Minutes since 12:00am GMT */
+ info.priority = 1;
+ info.default_priority = 1;
+ info.setuptime = (uint32)time(NULL) - 86400; /* minus 1 day */
+
+ /*
+ * I changed this as I think it is better to have a generic
+ * DEVMODE than to crash Win2k explorer.exe --jerry
+ * See the HP Deskjet 990c Win2k drivers for an example.
+ */
+
+#if 0 /* JRA - NO NOT CHANGE ! */
+ info.devmode = NULL;
+#else
+ /*
+ * We should not return a default devicemode, as this causes
+ * Win2K to not send the correct one on PCL drivers. It needs to
+ * see a null devicemode so it can then overwrite the devicemode
+ * on OpenPrinterEx. Yes this *is* insane :-). JRA.
+ */
+ if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
+ goto fail;
+#endif
+
+ /* This will get the current RPC talloc context, but we should be
+ passing this as a parameter... fixme... JRA ! */
+
+ if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
+ goto fail;
+
+ *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
+ if (! *info_ptr) {
+ DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
+ goto fail;
+ }
+
+ return WERR_OK;
+
+ fail:
+
+ if (info.devmode)
+ free_nt_devicemode(&info.devmode);
+ return WERR_ACCESS_DENIED;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
+{
+ pstring key;
+ NT_PRINTER_INFO_LEVEL_2 info;
+ int len = 0;
+ TDB_DATA kbuf, dbuf;
+ fstring printername;
+
+ ZERO_STRUCT(info);
+
+ slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ dbuf = tdb_fetch(tdb_printers, kbuf);
+ if (!dbuf.dptr)
+ return get_a_printer_2_default(info_ptr, sharename);
+
+ len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
+ &info.attributes,
+ &info.priority,
+ &info.default_priority,
+ &info.starttime,
+ &info.untiltime,
+ &info.status,
+ &info.cjobs,
+ &info.averageppm,
+ &info.changeid,
+ &info.c_setprinter,
+ &info.setuptime,
+ info.servername,
+ info.printername,
+ info.sharename,
+ info.portname,
+ info.drivername,
+ info.comment,
+ info.location,
+ info.sepfile,
+ info.printprocessor,
+ info.datatype,
+ info.parameters);
+
+ /* Samba has to have shared raw drivers. */
+ info.attributes |= (PRINTER_ATTRIBUTE_SHARED|PRINTER_ATTRIBUTE_RAW_ONLY);
+
+ /* Restore the stripped strings. */
+ slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", global_myname);
+ slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", global_myname,
+ info.printername);
+ fstrcpy(info.printername, printername);
+
+ len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
+#if 1
+ /*
+ * Some client drivers freak out if there is a NULL devmode
+ * (probably the driver is not checking before accessing
+ * the devmode pointer) --jerry
+ */
+ if (!info.devmode)
+ {
+ DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
+ printername));
+ info.devmode = construct_nt_devicemode(printername);
+ }
+#endif
+ len += unpack_specifics(&info.specific,dbuf.dptr+len, dbuf.dsize-len);
+
+ /* This will get the current RPC talloc context, but we should be
+ passing this as a parameter... fixme... JRA ! */
+
+ nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
+
+ /* Fix for OS/2 drivers. */
+
+ if (get_remote_arch() == RA_OS2)
+ map_to_os2_driver(info.drivername);
+
+ SAFE_FREE(dbuf.dptr);
+ *info_ptr=memdup(&info, sizeof(info));
+
+ DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
+ sharename, info.printername, info.drivername));
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+debugging function, dump at level 6 the struct in the logs
+****************************************************************************/
+static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+{
+ uint32 result;
+ NT_PRINTER_INFO_LEVEL_2 *info2;
+
+ DEBUG(106,("Dumping printer at level [%d]\n", level));
+
+ switch (level)
+ {
+ case 2:
+ {
+ if (printer.info_2 == NULL)
+ result=5;
+ else
+ {
+ info2=printer.info_2;
+
+ DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
+ DEBUGADD(106,("priority:[%d]\n", info2->priority));
+ DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
+ DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
+ DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
+ DEBUGADD(106,("status:[%s]\n", werror_str(info2->status)));
+ DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
+ DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
+ DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
+ DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
+ DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
+
+ DEBUGADD(106,("servername:[%s]\n", info2->servername));
+ DEBUGADD(106,("printername:[%s]\n", info2->printername));
+ DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
+ DEBUGADD(106,("portname:[%s]\n", info2->portname));
+ DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
+ DEBUGADD(106,("comment:[%s]\n", info2->comment));
+ DEBUGADD(106,("location:[%s]\n", info2->location));
+ DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
+ DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
+ DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
+ DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
+ result=0;
+ }
+ break;
+ }
+ default:
+ DEBUGADD(1,("Level not implemented\n"));
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Get the parameters we can substitute in an NT print job.
+****************************************************************************/
+
+void get_printer_subst_params(int snum, fstring *printername, fstring *sharename, fstring *portname)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ **printername = **sharename = **portname = '\0';
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return;
+
+ fstrcpy(*printername, printer->info_2->printername);
+ fstrcpy(*sharename, printer->info_2->sharename);
+ fstrcpy(*portname, printer->info_2->portname);
+
+ free_a_printer(&printer, 2);
+}
+
+/*
+ * The function below are the high level ones.
+ * only those ones must be called from the spoolss code.
+ * JFM.
+ */
+
+/****************************************************************************
+ Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
+****************************************************************************/
+
+WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+{
+ WERROR result;
+
+ dump_a_printer(printer, level);
+
+ switch (level)
+ {
+ case 2:
+ {
+ /*
+ * Update the changestamp. Emperical tests show that the
+ * ChangeID is always updated,but c_setprinter is only
+ * incremented on a SetPrinter() call.
+ */
+
+ time_t time_unix = time(NULL);
+
+ /* ChangeID **must** be increasing over the lifetime
+ of client's spoolss service in order for the
+ client's cache to show updates */
+
+ printer.info_2->changeid = time_unix * 100;
+
+ /*
+ * Because one day someone will ask:
+ * NT->NT An admin connection to a remote
+ * printer show changes imeediately in
+ * the properities dialog
+ *
+ * A non-admin connection will only show the
+ * changes after viewing the properites page
+ * 2 times. Seems to be related to a
+ * race condition in the client between the spooler
+ * updating the local cache and the Explorer.exe GUI
+ * actually displaying the properties.
+ *
+ * This is fixed in Win2k. admin/non-admin
+ * connections both display changes immediately.
+ *
+ * 14/12/01 --jerry
+ */
+
+ result=update_a_printer_2(printer.info_2);
+ break;
+ }
+ default:
+ result=WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Add a printer. This is called from ADDPRINTER(EX) and also SETPRINTER.
+ We split this out from mod_a_printer as it updates the id's and timestamps.
+****************************************************************************/
+
+WERROR add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+{
+ WERROR result;
+
+ dump_a_printer(printer, level);
+
+ switch (level)
+ {
+ case 2:
+ {
+ /*
+ * Update the changestamp. See comments in mod_a_printer()
+ * --jerry
+ */
+
+ time_t time_unix = time(NULL);
+
+ printer.info_2->changeid = time_unix * 100;
+ printer.info_2->c_setprinter++;
+
+ result=update_a_printer_2(printer.info_2);
+ break;
+ }
+ default:
+ result=WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Initialize printer devmode & data with previously saved driver init values.
+****************************************************************************/
+static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
+{
+ int len = 0;
+ pstring key;
+ TDB_DATA kbuf, dbuf;
+ NT_PRINTER_PARAM *current;
+ NT_PRINTER_INFO_LEVEL_2 info;
+
+ ZERO_STRUCT(info);
+
+ slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ dbuf = tdb_fetch(tdb_drivers, kbuf);
+ if (!dbuf.dptr)
+ return False;
+
+ /*
+ * Get the saved DEVMODE..
+ */
+ len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
+
+ /*
+ * The saved DEVMODE contains the devicename from the printer used during
+ * the initialization save. Change it to reflect the new printer.
+ */
+ ZERO_STRUCT(info.devmode->devicename);
+ fstrcpy(info.devmode->devicename, info_ptr->printername);
+
+ /*
+ * Bind the saved DEVMODE to the new the printer.
+ */
+ free_nt_devicemode(&info_ptr->devmode);
+ info_ptr->devmode = info.devmode;
+
+ DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n",
+ info_ptr->printername, info_ptr->drivername));
+
+ /*
+ * There should not be any printer data 'specifics' already set during the
+ * add printer operation, if there are delete them.
+ */
+ while ( (current=info_ptr->specific) != NULL ) {
+ info_ptr->specific=current->next;
+ SAFE_FREE(current->data);
+ SAFE_FREE(current);
+ }
+
+ /*
+ * Add the printer data 'specifics' to the new printer
+ */
+ len += unpack_specifics(&info_ptr->specific,dbuf.dptr+len, dbuf.dsize-len);
+
+ SAFE_FREE(dbuf.dptr);
+
+ return True;
+}
+
+/****************************************************************************
+ Initialize printer devmode & data with previously saved driver init values.
+ When a printer is created using AddPrinter, the drivername bound to the
+ printer is used to lookup previously saved driver initialization info, which
+ is bound to the new printer.
+****************************************************************************/
+
+uint32 set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ uint32 result;
+
+ switch (level)
+ {
+ case 2:
+ {
+ result=set_driver_init_2(printer->info_2);
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Pack up the DEVMODE and specifics for a printer into a 'driver init' entry
+ in the tdb. Note: this is different from the driver entry and the printer
+ entry. There should be a single driver init entry for each driver regardless
+ of whether it was installed from NT or 2K. Technically, they should be
+ different, but they work out to the same struct.
+****************************************************************************/
+static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
+{
+ pstring key;
+ char *buf;
+ int buflen, len, ret;
+ TDB_DATA kbuf, dbuf;
+
+ buf = NULL;
+ buflen = 0;
+
+ again:
+ len = 0;
+ len += pack_devicemode(info->devmode, buf+len, buflen-len);
+
+ len += pack_specifics(info->specific, buf+len, buflen-len);
+
+ if (buflen != len) {
+ char *tb;
+
+ tb = (char *)Realloc(buf, len);
+ if (!tb) {
+ DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
+ ret = -1;
+ goto done;
+ }
+ else buf = tb;
+ buflen = len;
+ goto again;
+ }
+
+ slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
+
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
+
+done:
+ if (ret == -1)
+ DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
+
+ SAFE_FREE(buf);
+
+ DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & specifics for driver [%s]\n",
+ info->sharename, info->drivername));
+
+ return ret;
+}
+
+/****************************************************************************
+ Update (i.e. save) the driver init info (DEVMODE and specifics) for a printer
+****************************************************************************/
+
+static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+{
+ uint32 result;
+
+ dump_a_printer(printer, level);
+
+ switch (level)
+ {
+ case 2:
+ {
+ result=update_driver_init_2(printer.info_2);
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+
+ return result;
+}
+
+/****************************************************************************
+ Convert the printer data value, a REG_BINARY array, into an initialization
+ DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
+ got to keep the endians happy :).
+****************************************************************************/
+
+static BOOL convert_driver_init(NT_PRINTER_PARAM *param, TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode)
+{
+ BOOL result = False;
+ prs_struct ps;
+ DEVICEMODE devmode;
+
+ ZERO_STRUCT(devmode);
+
+ prs_init(&ps, 0, ctx, UNMARSHALL);
+ ps.data_p = (char *)param->data;
+ ps.buffer_size = param->data_len;
+
+ if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
+ result = convert_devicemode("", &devmode, &nt_devmode);
+ else
+ DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
+
+ return result;
+}
+
+/****************************************************************************
+ Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
+
+ 1. Use the driver's config DLL to this UNC printername and:
+ a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
+ b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
+ 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
+
+ The last step triggers saving the "driver initialization" information for
+ this printer into the tdb. Later, new printers that use this driver will
+ have this initialization information bound to them. This simulates the
+ driver initialization, as if it had run on the Samba server (as it would
+ have done on NT).
+
+ The Win32 client side code requirement sucks! But until we can run arbitrary
+ Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
+
+ It would have been easier to use SetPrinter because all the UNMARSHALLING of
+ the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
+ about it and you will realize why. JRR 010720
+****************************************************************************/
+
+static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARAM *param)
+{
+ WERROR status = WERR_OK;
+ TALLOC_CTX *ctx = NULL;
+ NT_DEVICEMODE *nt_devmode = NULL;
+ NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
+
+ /*
+ * Set devmode on printer info, so entire printer initialization can be
+ * saved to tdb.
+ */
+ if ((ctx = talloc_init()) == NULL)
+ return WERR_NOMEM;
+
+ if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ ZERO_STRUCTP(nt_devmode);
+
+ /*
+ * The DEVMODE is held in the 'data' component of the param in raw binary.
+ * Convert it to to a devmode structure
+ */
+ if (!convert_driver_init(param, ctx, nt_devmode)) {
+ DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /*
+ * Pack up and add (or update) the DEVMODE and any current printer data to
+ * a 'driver init' element in the tdb
+ *
+ */
+ printer->info_2->devmode = nt_devmode;
+ if (update_driver_init(*printer, 2)!=0) {
+ DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * If driver initialization info was successfully saved, set the current
+ * printer to match it. This allows initialization of the current printer
+ * as well as the driver.
+ */
+ status = mod_a_printer(*printer, 2);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
+ printer->info_2->printername));
+ }
+
+ done:
+ talloc_destroy(ctx);
+ if (nt_devmode)
+ SAFE_FREE(nt_devmode->private);
+ SAFE_FREE(nt_devmode);
+ printer->info_2->devmode = tmp_devmode;
+
+ return status;
+}
+
+/****************************************************************************
+ Update the driver init info (DEVMODE and specifics) for a printer
+****************************************************************************/
+
+WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, NT_PRINTER_PARAM *param)
+{
+ WERROR status = WERR_OK;
+
+ switch (level)
+ {
+ case 2:
+ {
+ status=save_driver_init_2(printer, param);
+ break;
+ }
+ default:
+ status=WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return status;
+}
+
+/****************************************************************************
+ Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
+****************************************************************************/
+
+WERROR get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring sharename)
+{
+ WERROR result;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ *pp_printer = NULL;
+
+ DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
+
+ switch (level)
+ {
+ case 2:
+ {
+ if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
+ DEBUG(0,("get_a_printer: malloc fail.\n"));
+ return WERR_NOMEM;
+ }
+ ZERO_STRUCTP(printer);
+ result=get_a_printer_2(&printer->info_2, sharename);
+ if (W_ERROR_IS_OK(result)) {
+ dump_a_printer(*printer, level);
+ *pp_printer = printer;
+ } else {
+ SAFE_FREE(printer);
+ }
+ break;
+ }
+ default:
+ result=WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, werror_str(result)));
+
+ return result;
+}
+
+/****************************************************************************
+ Deletes a NT_PRINTER_INFO_LEVEL struct.
+****************************************************************************/
+
+uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
+{
+ uint32 result;
+ NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
+
+ DEBUG(104,("freeing a printer at level [%d]\n", level));
+
+ if (printer == NULL)
+ return 0;
+
+ switch (level)
+ {
+ case 2:
+ {
+ if (printer->info_2 != NULL)
+ {
+ free_nt_printer_info_level_2(&printer->info_2);
+ result=0;
+ }
+ else
+ {
+ result=4;
+ }
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+
+ SAFE_FREE(*pp_printer);
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+ DEBUG(104,("adding a printer at level [%d]\n", level));
+ dump_a_printer_driver(driver, level);
+
+ switch (level)
+ {
+ case 3:
+ {
+ result=add_a_printer_driver_3(driver.info_3);
+ break;
+ }
+
+ case 6:
+ {
+ result=add_a_printer_driver_6(driver.info_6);
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+
+ return result;
+}
+/****************************************************************************
+****************************************************************************/
+WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
+ fstring printername, fstring architecture, uint32 version)
+{
+ WERROR result;
+
+ switch (level)
+ {
+ case 3:
+ {
+ result=get_a_printer_driver_3(&driver->info_3, printername, architecture, version);
+ break;
+ }
+ default:
+ result=W_ERROR(1);
+ break;
+ }
+
+ if (W_ERROR_IS_OK(result))
+ dump_a_printer_driver(*driver, level);
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+{
+ uint32 result;
+
+ switch (level)
+ {
+ case 3:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
+ if (driver.info_3 != NULL)
+ {
+ info3=driver.info_3;
+ SAFE_FREE(info3->dependentfiles);
+ ZERO_STRUCTP(info3);
+ SAFE_FREE(info3);
+ result=0;
+ }
+ else
+ {
+ result=4;
+ }
+ break;
+ }
+ case 6:
+ {
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
+ if (driver.info_6 != NULL)
+ {
+ info6=driver.info_6;
+ SAFE_FREE(info6->dependentfiles);
+ SAFE_FREE(info6->previousnames);
+ ZERO_STRUCTP(info6);
+ SAFE_FREE(info6);
+ result=0;
+ }
+ else
+ {
+ result=4;
+ }
+ break;
+ }
+ default:
+ result=1;
+ break;
+ }
+ return result;
+}
+
+
+/****************************************************************************
+ Determine whether or not a particular driver is currently assigned
+ to a printer
+****************************************************************************/
+BOOL printer_driver_in_use (char *arch, char *driver)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+ NT_PRINTER_INFO_LEVEL_2 info;
+ int ret;
+
+ if (!tdb_printers)
+ if (!nt_printing_init())
+ return False;
+
+ DEBUG(5,("printer_driver_in_use: Beginning search through printers.tdb...\n"));
+
+ /* loop through the printers.tdb and check for the drivername */
+ for (kbuf = tdb_firstkey(tdb_printers); kbuf.dptr;
+ newkey = tdb_nextkey(tdb_printers, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
+ {
+
+ dbuf = tdb_fetch(tdb_printers, kbuf);
+ if (!dbuf.dptr)
+ continue;
+
+ if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) != 0)
+ continue;
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddddddfffffPfffff",
+ &info.attributes,
+ &info.priority,
+ &info.default_priority,
+ &info.starttime,
+ &info.untiltime,
+ &info.status,
+ &info.cjobs,
+ &info.averageppm,
+ &info.changeid,
+ &info.c_setprinter,
+ &info.setuptime,
+ info.servername,
+ info.printername,
+ info.sharename,
+ info.portname,
+ info.drivername,
+ info.comment,
+ info.location,
+ info.sepfile,
+ info.printprocessor,
+ info.datatype,
+ info.parameters);
+
+ SAFE_FREE(dbuf.dptr);
+
+ if (ret == -1) {
+ DEBUG (0,("printer_driver_in_use: tdb_unpack failed for printer %s\n",
+ info.printername));
+ continue;
+ }
+
+ DEBUG (10,("printer_driver_in_use: Printer - %s (%s)\n",
+ info.printername, info.drivername));
+
+ if (strcmp(info.drivername, driver) == 0)
+ {
+ DEBUG(5,("printer_driver_in_use: Printer %s using %s\n",
+ info.printername, driver));
+ return True;
+ }
+ }
+ DEBUG(5,("printer_driver_in_use: Completed search through printers.tdb...\n"));
+
+
+
+ /* report that the driver is in use by default */
+ return False;
+}
+
+/****************************************************************************
+ Remove a printer driver from the TDB. This assumes that the the driver was
+ previously looked up.
+ ***************************************************************************/
+WERROR delete_printer_driver (NT_PRINTER_DRIVER_INFO_LEVEL_3 *i)
+{
+ pstring key;
+ fstring arch;
+ TDB_DATA kbuf;
+
+
+ get_short_archi(arch, i->environment);
+ slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
+ arch, i->cversion, i->name);
+ DEBUG(5,("delete_printer_driver: key = [%s]\n", key));
+
+ kbuf.dptr=key;
+ kbuf.dsize=strlen(key)+1;
+
+ if (tdb_delete(tdb_drivers, kbuf) == -1) {
+ DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
+ return WERR_ACCESS_DENIED;
+ }
+
+ DEBUG(5,("delete_printer_driver: [%s] driver delete successful.\n",
+ i->name));
+
+ return WERR_OK;
+}
+/****************************************************************************
+****************************************************************************/
+BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
+ fstring value, uint8 **data, uint32 *type, uint32 *len)
+{
+ /* right now that's enough ! */
+ NT_PRINTER_PARAM *param;
+ int i=0;
+
+ param=printer.info_2->specific;
+
+ while (param != NULL && i < param_index) {
+ param=param->next;
+ i++;
+ }
+
+ if (param == NULL)
+ return False;
+
+ /* exited because it exist */
+ *type=param->type;
+ StrnCpy(value, param->value, sizeof(fstring)-1);
+ *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
+ if(*data == NULL)
+ return False;
+ ZERO_STRUCTP(*data);
+ memcpy(*data, param->data, param->data_len);
+ *len=param->data_len;
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
+ fstring value, uint8 **data, uint32 *type, uint32 *len)
+{
+ /* right now that's enough ! */
+ NT_PRINTER_PARAM *param;
+
+ DEBUG(10, ("get_specific_param\n"));
+
+ param=printer.info_2->specific;
+
+ while (param != NULL)
+ {
+#if 1 /* JRA - I think this should be case insensitive.... */
+ if ( strequal(value, param->value)
+#else
+ if ( !strcmp(value, param->value)
+#endif
+ && strlen(value)==strlen(param->value))
+ break;
+
+ param=param->next;
+ }
+
+ if (param != NULL)
+ {
+ DEBUGADD(10, ("get_specific_param: found one param\n"));
+ /* exited because it exist */
+ *type=param->type;
+
+ *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
+ if(*data == NULL)
+ return False;
+ memcpy(*data, param->data, param->data_len);
+ *len=param->data_len;
+
+ DEBUGADD(10, ("get_specific_param: exit true\n"));
+ return (True);
+ }
+ DEBUGADD(10, ("get_specific_param: exit false\n"));
+ return (False);
+}
+
+/****************************************************************************
+ Store a security desc for a printer.
+****************************************************************************/
+
+WERROR nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
+{
+ SEC_DESC_BUF *new_secdesc_ctr = NULL;
+ SEC_DESC_BUF *old_secdesc_ctr = NULL;
+ prs_struct ps;
+ TALLOC_CTX *mem_ctx = NULL;
+ fstring key;
+ WERROR status;
+
+ mem_ctx = talloc_init();
+ if (mem_ctx == NULL)
+ return WERR_NOMEM;
+
+ /* The old owner and group sids of the security descriptor are not
+ present when new ACEs are added or removed by changing printer
+ permissions through NT. If they are NULL in the new security
+ descriptor then copy them over from the old one. */
+
+ if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
+ DOM_SID *owner_sid, *group_sid;
+ SEC_ACL *dacl, *sacl;
+ SEC_DESC *psd = NULL;
+ size_t size;
+
+ nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
+
+ /* Pick out correct owner and group sids */
+
+ owner_sid = secdesc_ctr->sec->owner_sid ?
+ secdesc_ctr->sec->owner_sid :
+ old_secdesc_ctr->sec->owner_sid;
+
+ group_sid = secdesc_ctr->sec->grp_sid ?
+ secdesc_ctr->sec->grp_sid :
+ old_secdesc_ctr->sec->grp_sid;
+
+ dacl = secdesc_ctr->sec->dacl ?
+ secdesc_ctr->sec->dacl :
+ old_secdesc_ctr->sec->dacl;
+
+ sacl = secdesc_ctr->sec->sacl ?
+ secdesc_ctr->sec->sacl :
+ old_secdesc_ctr->sec->sacl;
+
+ /* Make a deep copy of the security descriptor */
+
+ psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision,
+ owner_sid, group_sid,
+ sacl,
+ dacl,
+ &size);
+
+ new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
+ }
+
+ if (!new_secdesc_ctr) {
+ new_secdesc_ctr = secdesc_ctr;
+ }
+
+ /* Store the security descriptor in a tdb */
+
+ prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
+ sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
+
+ if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
+ &ps, 1)) {
+ status = WERR_BADFUNC;
+ goto out;
+ }
+
+ slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
+
+ if (tdb_prs_store(tdb_printers, key, &ps)==0) {
+ status = WERR_OK;
+ } else {
+ DEBUG(1,("Failed to store secdesc for %s\n", printername));
+ status = WERR_BADFUNC;
+ }
+
+ /* Free malloc'ed memory */
+
+ out:
+
+ prs_mem_free(&ps);
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return status;
+}
+
+/****************************************************************************
+ Construct a default security descriptor buffer for a printer.
+****************************************************************************/
+
+static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
+{
+ SEC_ACE ace[3];
+ SEC_ACCESS sa;
+ SEC_ACL *psa = NULL;
+ SEC_DESC_BUF *sdb = NULL;
+ SEC_DESC *psd = NULL;
+ DOM_SID owner_sid;
+ size_t sd_size;
+ enum SID_NAME_USE name_type;
+
+ /* Create an ACE where Everyone is allowed to print */
+
+ init_sec_access(&sa, PRINTER_ACE_PRINT);
+ init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ /* Make the security descriptor owned by the Administrators group
+ on the PDC of the domain. */
+
+ if (winbind_lookup_name(lp_workgroup(), &owner_sid, &name_type)) {
+ sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+ } else {
+ uint32 owner_rid;
+
+ /* Backup plan - make printer owned by admins or root.
+ This should emulate a lanman printer as security
+ settings can't be changed. */
+
+ sid_peek_rid(&owner_sid, &owner_rid);
+
+ if (owner_rid != BUILTIN_ALIAS_RID_PRINT_OPS &&
+ owner_rid != BUILTIN_ALIAS_RID_ADMINS &&
+ owner_rid != DOMAIN_USER_RID_ADMIN &&
+ !lookup_name("root", &owner_sid, &name_type)) {
+ sid_copy(&owner_sid, &global_sid_World);
+ }
+ }
+
+ init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+ init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY);
+
+ init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+ init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+ sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ /* The ACL revision number in rpc_secdesc.h differs from the one
+ created by NT when setting ACE entries in printer
+ descriptors. NT4 complains about the property being edited by a
+ NT5 machine. */
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
+ psd = make_sec_desc(ctx, SEC_DESC_REVISION,
+ &owner_sid, NULL,
+ NULL, psa, &sd_size);
+ }
+
+ if (!psd) {
+ DEBUG(0,("construct_default_printer_sdb: Failed to make SEC_DESC.\n"));
+ return NULL;
+ }
+
+ sdb = make_sec_desc_buf(ctx, sd_size, psd);
+
+ DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
+ (unsigned int)sd_size));
+
+ return sdb;
+}
+
+/****************************************************************************
+ Get a security desc for a printer.
+****************************************************************************/
+
+BOOL nt_printing_getsec(TALLOC_CTX *ctx, char *printername, SEC_DESC_BUF **secdesc_ctr)
+{
+ prs_struct ps;
+ fstring key;
+ char *temp;
+
+ if ((temp = strchr(printername + 2, '\\'))) {
+ printername = temp + 1;
+ }
+
+ /* Fetch security descriptor from tdb */
+
+ slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
+
+ if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
+ !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
+
+ DEBUG(4,("using default secdesc for %s\n", printername));
+
+ if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
+ return False;
+ }
+
+ /* Save default security descriptor for later */
+
+ prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
+ sizeof(SEC_DESC_BUF), ctx, MARSHALL);
+
+ if (sec_io_desc_buf("nt_printing_setsec", secdesc_ctr, &ps, 1))
+ tdb_prs_store(tdb_printers, key, &ps);
+
+ prs_mem_free(&ps);
+
+ return True;
+ }
+
+ /* If security descriptor is owned by S-1-1-0 and winbindd is up,
+ this security descriptor has been created when winbindd was
+ down. Take ownership of security descriptor. */
+
+ if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
+ DOM_SID owner_sid;
+ enum SID_NAME_USE name_type;
+
+ /* Change sd owner to workgroup administrator */
+
+ if (winbind_lookup_name(lp_workgroup(), &owner_sid,
+ &name_type)) {
+ SEC_DESC_BUF *new_secdesc_ctr = NULL;
+ SEC_DESC *psd = NULL;
+ size_t size;
+
+ /* Create new sd */
+
+ sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+
+ psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision,
+ &owner_sid,
+ (*secdesc_ctr)->sec->grp_sid,
+ (*secdesc_ctr)->sec->sacl,
+ (*secdesc_ctr)->sec->dacl,
+ &size);
+
+ new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
+
+ /* Swap with other one */
+
+ *secdesc_ctr = new_secdesc_ctr;
+
+ /* Set it */
+
+ nt_printing_setsec(printername, *secdesc_ctr);
+ }
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
+ int i;
+
+ DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
+ printername, the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &the_acl->ace[i].trustee);
+
+ DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
+ the_acl->ace[i].type, the_acl->ace[i].flags,
+ the_acl->ace[i].info.mask));
+ }
+ }
+
+ prs_mem_free(&ps);
+ return True;
+}
+
+/* error code:
+ 0: everything OK
+ 1: level not implemented
+ 2: file doesn't exist
+ 3: can't allocate memory
+ 4: can't free memory
+ 5: non existant struct
+*/
+
+/*
+ A printer and a printer driver are 2 different things.
+ NT manages them separatelly, Samba does the same.
+ Why ? Simply because it's easier and it makes sense !
+
+ Now explanation: You have 3 printers behind your samba server,
+ 2 of them are the same make and model (laser A and B). But laser B
+ has an 3000 sheet feeder and laser A doesn't such an option.
+ Your third printer is an old dot-matrix model for the accounting :-).
+
+ If the /usr/local/samba/lib directory (default dir), you will have
+ 5 files to describe all of this.
+
+ 3 files for the printers (1 by printer):
+ NTprinter_laser A
+ NTprinter_laser B
+ NTprinter_accounting
+ 2 files for the drivers (1 for the laser and 1 for the dot matrix)
+ NTdriver_printer model X
+ NTdriver_printer model Y
+
+jfm: I should use this comment for the text file to explain
+ same thing for the forms BTW.
+ Je devrais mettre mes commentaires en francais, ca serait mieux :-)
+
+*/
+
+/* Convert generic access rights to printer object specific access rights.
+ It turns out that NT4 security descriptors use generic access rights and
+ NT5 the object specific ones. */
+
+void map_printer_permissions(SEC_DESC *sd)
+{
+ int i;
+
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ se_map_generic(&sd->dacl->ace[i].info.mask,
+ &printer_generic_mapping);
+ }
+}
+
+/****************************************************************************
+ Check a user has permissions to perform the given operation. We use the
+ permission constants defined in include/rpc_spoolss.h to check the various
+ actions we perform when checking printer access.
+
+ PRINTER_ACCESS_ADMINISTER:
+ print_queue_pause, print_queue_resume, update_printer_sec,
+ update_printer, spoolss_addprinterex_level_2,
+ _spoolss_setprinterdata
+
+ PRINTER_ACCESS_USE:
+ print_job_start
+
+ JOB_ACCESS_ADMINISTER:
+ print_job_delete, print_job_pause, print_job_resume,
+ print_queue_purge
+
+ ****************************************************************************/
+BOOL print_access_check(struct current_user *user, int snum, int access_type)
+{
+ SEC_DESC_BUF *secdesc = NULL;
+ uint32 access_granted;
+ NTSTATUS status;
+ BOOL result;
+ char *pname;
+ TALLOC_CTX *mem_ctx = NULL;
+ extern struct current_user current_user;
+
+ /* If user is NULL then use the current_user structure */
+
+ if (!user)
+ user = &current_user;
+
+ /* Always allow root or printer admins to do anything */
+
+ if (user->uid == 0 ||
+ user_in_list(uidtoname(user->uid), lp_printer_admin(snum))) {
+ return True;
+ }
+
+ /* Get printer name */
+
+ pname = PRINTERNAME(snum);
+
+ if (!pname || !*pname) {
+ errno = EACCES;
+ return False;
+ }
+
+ /* Get printer security descriptor */
+
+ if(!(mem_ctx = talloc_init())) {
+ errno = ENOMEM;
+ return False;
+ }
+
+ nt_printing_getsec(mem_ctx, pname, &secdesc);
+
+ if (access_type == JOB_ACCESS_ADMINISTER) {
+ SEC_DESC_BUF *parent_secdesc = secdesc;
+
+ /* Create a child security descriptor to check permissions
+ against. This is because print jobs are child objects
+ objects of a printer. */
+
+ secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
+
+ /* Now this is the bit that really confuses me. The access
+ type needs to be changed from JOB_ACCESS_ADMINISTER to
+ PRINTER_ACCESS_ADMINISTER for this to work. Something
+ to do with the child (job) object becoming like a
+ printer?? -tpot */
+
+ access_type = PRINTER_ACCESS_ADMINISTER;
+ }
+
+ /* Check access */
+
+ map_printer_permissions(secdesc->sec);
+
+ result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
+ &access_granted, &status);
+
+ DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
+
+ talloc_destroy(mem_ctx);
+
+ if (!result)
+ errno = EACCES;
+
+ return result;
+}
+
+/****************************************************************************
+ Check the time parameters allow a print operation.
+*****************************************************************************/
+
+BOOL print_time_access_check(int snum)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ BOOL ok = False;
+ time_t now = time(NULL);
+ struct tm *t;
+ uint32 mins;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return False;
+
+ if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
+ ok = True;
+
+ t = gmtime(&now);
+ mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
+
+ if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
+ ok = True;
+
+ free_a_printer(&printer, 2);
+
+ if (!ok)
+ errno = EACCES;
+
+ return ok;
+}
+
+/****************************************************************************
+ Attempt to write a default device.
+*****************************************************************************/
+
+WERROR printer_write_default_dev(int snum, const PRINTER_DEFAULT *printer_default)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ WERROR result;
+
+ /*
+ * Don't bother if no default devicemode was sent.
+ */
+
+ if (printer_default->devmode_cont.devmode == NULL)
+ return WERR_OK;
+
+ result = get_a_printer(&printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(result)) return result;
+
+ /*
+ * Just ignore it if we already have a devmode.
+ */
+#if 0
+ if (printer->info_2->devmode != NULL)
+ goto done;
+#endif
+ /*
+ * We don't have a devicemode and we're trying to write
+ * one. Check we have the access needed.
+ */
+ DEBUG(5,("printer_write_default_dev: access: %x\n", printer_default->access_required));
+
+ if ( (printer_default->access_required & PRINTER_ACCESS_ADMINISTER) !=
+ PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(5,("printer_write_default_dev: invalid request access to update: %x\n", printer_default->access_required));
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ DEBUG(5,("printer_write_default_dev: Access denied for printer %s\n",
+ lp_servicename(snum) ));
+ result = WERR_ACCESS_DENIED;
+ /*result = NT_STATUS_NO_PROBLEMO;*/
+ goto done;
+ }
+
+ DEBUG(5,("printer_write_default_dev: updating, check OK.\n"));
+
+ /*
+ * Convert the on the wire devicemode format to the internal one.
+ */
+
+ if (!convert_devicemode(printer->info_2->printername,
+ printer_default->devmode_cont.devmode,
+ &printer->info_2->devmode)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * Finally write back to the tdb.
+ */
+
+ result = add_a_printer(*printer, 2);
+
+ done:
+
+ free_a_printer(&printer, 2);
+ return result;
+}
diff --git a/source/printing/pcap.c b/source/printing/pcap.c
index 8973b1627fb..b10dbba9c57 100644
--- a/source/printing/pcap.c
+++ b/source/printing/pcap.c
@@ -2,11 +2,15 @@
Unix SMB/Netbios implementation.
Version 1.9.
printcap parsing
- Copyright (C) Karl Auer 1993,1994
+ Copyright (C) Karl Auer 1993-1998
Re-working by Martin Kiff, 1994
Re-written again by Andrew Tridgell
+
+ Modified for SVID support by Norm Jacobs, 1997
+
+ Modified for CUPS support by Michael Sweet, 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,15 +53,17 @@
* Opening a pipe for "lpc status" and reading that would probably
* be pretty effective. Code to do this already exists in the freely
* distributable PCNFS server code.
+ *
+ * Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
+ * in smb.conf under Solaris.
+ *
+ * Modified to call CUPS support if printcap name is set to "cups"
+ * in smb.conf.
*/
#include "includes.h"
#include "smb.h"
-#include "loadparm.h"
-#include "pcap.h"
-
-extern int DEBUGLEVEL;
#ifdef AIX
/* ******************************************
@@ -66,7 +72,7 @@ extern int DEBUGLEVEL;
****************************************** */
static int strlocate(char *xpLine,char *xpS)
{
- int iS,iL,i,iRet;
+ int iS,iL,iRet;
char *p;
iS = strlen(xpS);
iL = strlen(xpLine);
@@ -88,17 +94,17 @@ static int strlocate(char *xpLine,char *xpS)
/* ******************************************************************* */
/* * Scan qconfig and search all virtual printer (device printer) * */
/* ******************************************************************* */
-static void ScanQconfig_fn(char *psz,void (*fn)())
+static void ScanQconfig_fn(char *psz,void (*fn)(char *, char *))
{
- int iLg,iEtat;
- FILE *pfile;
+ int iEtat;
+ XFILE *pfile;
char *line,*p;
pstring name,comment;
line = NULL;
*name = 0;
*comment = 0;
- if ((pfile = fopen(psz, "r")) == NULL)
+ if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
{
DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
return;
@@ -114,13 +120,13 @@ static void ScanQconfig_fn(char *psz,void (*fn)())
{
case 0: /* locate an entry */
if (*line == '\t' || *line == ' ') continue;
- if ((p=strchr(line,':')))
+ if ((p=strchr_m(line,':')))
{
*p = '\0';
p = strtok(line,":");
if (strcmp(p,"bsh")!=0)
{
- strcpy(name,p);
+ pstrcpy(name,p);
iEtat = 1;
continue;
}
@@ -152,7 +158,7 @@ static void ScanQconfig_fn(char *psz,void (*fn)())
break;
}
}
- fclose(pfile);
+ x_fclose(pfile);
}
/* Scan qconfig file and locate de printername */
@@ -160,7 +166,7 @@ static void ScanQconfig_fn(char *psz,void (*fn)())
static BOOL ScanQconfig(char *psz,char *pszPrintername)
{
int iLg,iEtat;
- FILE *pfile;
+ XFILE *pfile;
char *pName;
char *line;
@@ -173,13 +179,13 @@ static BOOL ScanQconfig(char *psz,char *pszPrintername)
DEBUG(0,(" Unable to allocate memory for printer %s\n",pszPrintername));
return(False);
}
- if ((pfile = fopen(psz, "r")) == NULL)
+ if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
{
DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
free(pName);
return(False);
}
- sprintf(pName,"%s:",pszPrintername);
+ slprintf(pName, iLg + 9, "%s:",pszPrintername);
iLg = strlen(pName);
/*DEBUG(3,( " Looking for entry %s\n",pName));*/
iEtat = 0;
@@ -226,23 +232,27 @@ static BOOL ScanQconfig(char *psz,char *pszPrintername)
}
}
free (pName);
- fclose(pfile);
+ x_fclose(pfile);
return(False);
}
+#endif /* AIX */
+
-#endif
/***************************************************************************
Scan printcap file pszPrintcapname for a printer called pszPrintername.
Return True if found, else False. Returns False on error, too, after logging
the error at level 0. For generality, the printcap name may be passed - if
-passed as NULL, the configuration will be queried for the name.
+passed as NULL, the configuration will be queried for the name. pszPrintername
+must be in DOS codepage.
+The xxx_printername_ok functions need fixing to understand they are being
+given a DOS codepage. FIXME !! JRA.
***************************************************************************/
BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
{
char *line=NULL;
char *psz;
char *p,*q;
- FILE *pfile;
+ XFILE *pfile;
if (pszPrintername == NULL || pszPrintername[0] == '\0')
{
@@ -257,11 +267,23 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
DEBUG(0,( "No printcap file name configured!\n"));
return(False);
}
+
+#ifdef HAVE_CUPS
+ if (strequal(psz, "cups"))
+ return (cups_printername_ok(pszPrintername));
+#endif /* HAVE_CUPS */
+
+#ifdef SYSV
+ if (strequal(psz, "lpstat"))
+ return (sysv_printername_ok(pszPrintername));
+#endif
+
#ifdef AIX
- if (strlocate(psz,"/qconfig") != NULL)
+ if (strlocate(psz,"/qconfig"))
return(ScanQconfig(psz,pszPrintername));
#endif
- if ((pfile = fopen(psz, "r")) == NULL)
+
+ if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
{
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
return(False);
@@ -273,44 +295,45 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
continue;
/* now we have a real printer line - cut it off at the first : */
- p = strchr(line,':');
+ p = strchr_m(line,':');
if (p) *p = 0;
/* now just check if the name is in the list */
/* NOTE: I avoid strtok as the fn calling this one may be using it */
for (p=line; p; p=q)
{
- if ((q = strchr(p,'|'))) *q++ = 0;
+ if ((q = strchr_m(p,'|'))) *q++ = 0;
if (strequal(p,pszPrintername))
{
/* normalise the case */
- strcpy(pszPrintername,p);
+ pstrcpy(pszPrintername,p);
free(line);
- fclose(pfile);
+ x_fclose(pfile);
return(True);
}
p = q;
}
}
-
- fclose(pfile);
+ x_fclose(pfile);
return(False);
}
/***************************************************************************
run a function on each printer name in the printcap file. The function is
-passed the primary name and the comment (if possible)
+passed the primary name and the comment (if possible). Note the fn() takes
+strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed
+to return DOS codepage. FIXME !! JRA.
***************************************************************************/
-void pcap_printer_fn(void (*fn)())
+void pcap_printer_fn(void (*fn)(char *, char *))
{
pstring name,comment;
char *line;
char *psz;
char *p,*q;
- FILE *pfile;
+ XFILE *pfile;
/* only go looking if no printcap name supplied */
if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
@@ -319,14 +342,29 @@ void pcap_printer_fn(void (*fn)())
return;
}
+#ifdef HAVE_CUPS
+ if (strequal(psz, "cups")) {
+ cups_printer_fn(fn);
+ return;
+ }
+#endif /* HAVE_CUPS */
+
+#ifdef SYSV
+ if (strequal(psz, "lpstat")) {
+ sysv_printer_fn(fn);
+ return;
+ }
+#endif
+
#ifdef AIX
- if (strlocate(psz,"/qconfig") != NULL)
+ if (strlocate(psz,"/qconfig"))
{
ScanQconfig_fn(psz,fn);
return;
}
#endif
- if ((pfile = fopen(psz, "r")) == NULL)
+
+ if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
{
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
return;
@@ -338,7 +376,7 @@ void pcap_printer_fn(void (*fn)())
continue;
/* now we have a real printer line - cut it off at the first : */
- p = strchr(line,':');
+ p = strchr_m(line,':');
if (p) *p = 0;
/* now find the most likely printer name and comment
@@ -348,9 +386,9 @@ void pcap_printer_fn(void (*fn)())
for (p=line; p; p=q)
{
BOOL has_punctuation;
- if ((q = strchr(p,'|'))) *q++ = 0;
+ if ((q = strchr_m(p,'|'))) *q++ = 0;
- has_punctuation = (strchr(p,' ') || strchr(p,'(') || strchr(p,')'));
+ has_punctuation = (strchr_m(p,' ') || strchr_m(p,'\t') || strchr_m(p,'(') || strchr_m(p,')'));
if (strlen(p)>strlen(comment) && has_punctuation)
{
@@ -358,14 +396,14 @@ void pcap_printer_fn(void (*fn)())
continue;
}
- if (strlen(p) <= 8 && strlen(p)>strlen(name) && !has_punctuation)
+ if (strlen(p) <= MAXPRINTERLEN && strlen(p)>strlen(name) && !has_punctuation)
{
- if (!*comment) strcpy(comment,name);
- strcpy(name,p);
+ if (!*comment) pstrcpy(comment,name);
+ pstrcpy(name,p);
continue;
}
- if (!strchr(comment,' ') &&
+ if (!strchr_m(comment,' ') &&
strlen(p) > strlen(comment))
{
StrnCpy(comment,p,sizeof(comment)-1);
@@ -374,10 +412,10 @@ void pcap_printer_fn(void (*fn)())
}
comment[60] = 0;
- name[8] = 0;
+ name[MAXPRINTERLEN] = 0;
- if (*name)
+ if (*name)
fn(name,comment);
}
- fclose(pfile);
+ x_fclose(pfile);
}
diff --git a/source/printing/print_cups.c b/source/printing/print_cups.c
new file mode 100644
index 00000000000..3ab08de13da
--- /dev/null
+++ b/source/printing/print_cups.c
@@ -0,0 +1,1189 @@
+/*
+ * Support code for the Common UNIX Printing System ("CUPS")
+ *
+ * Copyright 1999-2001 by Michael R Sweet.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "printing.h"
+#include "smb.h"
+
+#ifdef HAVE_CUPS
+#include <cups/cups.h>
+#include <cups/language.h>
+
+
+/*
+ * CUPS printing interface definitions...
+ */
+
+static int cups_job_delete(int snum, struct printjob *pjob);
+static int cups_job_pause(int snum, struct printjob *pjob);
+static int cups_job_resume(int snum, struct printjob *pjob);
+static int cups_job_submit(int snum, struct printjob *pjob);
+static int cups_queue_get(int snum, print_queue_struct **q,
+ print_status_struct *status);
+static int cups_queue_pause(int snum);
+static int cups_queue_resume(int snum);
+
+
+struct printif cups_printif =
+ {
+ cups_queue_get,
+ cups_queue_pause,
+ cups_queue_resume,
+ cups_job_delete,
+ cups_job_pause,
+ cups_job_resume,
+ cups_job_submit,
+ };
+
+/*
+ * 'cups_passwd_cb()' - The CUPS password callback...
+ */
+
+const char * /* O - Password or NULL */
+cups_passwd_cb(const char *prompt) /* I - Prompt */
+{
+ /*
+ * Always return NULL to indicate that no password is available...
+ */
+
+ (void)prompt;
+
+ return (NULL);
+}
+
+
+/*
+ * 'cups_printer_fn()' - Call a function for every printer known to the
+ * system.
+ */
+
+void
+cups_printer_fn(void (*fn)(char *, char *)) /* I - Function to call */
+{
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ char *name, /* printer-name attribute */
+ *make_model, /* printer-make-and-model attribute */
+ *info; /* printer-info attribute */
+ static const char *requested[] =/* Requested attributes */
+ {
+ "printer-name",
+ "printer-make-and-model",
+ "printer-info"
+ };
+
+
+ DEBUG(5,("cups_printer_fn(%p)\n", fn));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return;
+ }
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_GET_PRINTERS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL)
+ {
+ DEBUG(0,("Unable to get printer list - %s\n",
+ ippErrorString(cupsLastError())));
+ httpClose(http);
+ return;
+ }
+
+ for (attr = response->attrs; attr != NULL;)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ name = NULL;
+ make_model = NULL;
+ info = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-make-and-model") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ make_model = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ info = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (name == NULL)
+ break;
+
+ if (info == NULL || !info[0])
+ (*fn)(name, make_model);
+ else
+ (*fn)(name,info);
+
+
+ }
+
+ ippDelete(response);
+ httpClose(http);
+}
+
+
+/*
+ * 'cups_printername_ok()' - Provide the equivalent of pcap_printername_ok()
+ * for CUPS.
+ */
+
+int /* O - 1 if printer name OK */
+cups_printername_ok(char *name) /* I - Name of printer */
+{
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_printername_ok(\"%s\")\n", name));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (0);
+ }
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes", NULL, "printer-uri");
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", name);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL)
+ {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", name,
+ ippErrorString(cupsLastError())));
+ httpClose(http);
+ return (0);
+ }
+
+ httpClose(http);
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", name,
+ ippErrorString(response->request.status.status_code)));
+ ippDelete(response);
+ return (0);
+ }
+ else
+ {
+ ippDelete(response);
+ return (1);
+ }
+}
+
+
+/*
+ * 'cups_job_delete()' - Delete a job.
+ */
+
+static int
+cups_job_delete(int snum, struct printjob *pjob)
+{
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_delete(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_CANCEL_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_CANCEL_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ret = 1;
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'cups_job_pause()' - Pause a job.
+ */
+
+static int
+cups_job_pause(int snum, struct printjob *pjob)
+{
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_HOLD_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_HOLD_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ret = 1;
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'cups_job_resume()' - Resume a paused job.
+ */
+
+static int
+cups_job_resume(int snum, struct printjob *pjob)
+{
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_RELEASE_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_RELEASE_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ret = 1;
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'cups_job_submit()' - Submit a job for printing.
+ */
+
+static int
+cups_job_submit(int snum, struct printjob *pjob)
+{
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_PRINT_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * [document-data]
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PRINT_JOB;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, pjob->user);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ pjob->jobname);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
+
+ ret = 1;
+ if ((response = cupsDoFileRequest(http, request, uri,
+ pjob->filename)) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'cups_queue_get()' - Get all the jobs in the print queue.
+ */
+
+static int
+cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
+{
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+ int qcount, /* Number of active queue entries */
+ qalloc; /* Number of queue entries allocated */
+ print_queue_struct *queue, /* Queue entries */
+ *temp; /* Temporary pointer for queue */
+ const char *user_name, /* job-originating-user-name attribute */
+ *job_name; /* job-name attribute */
+ int job_id; /* job-id attribute */
+ int job_k_octets; /* job-k-octets attribute */
+ time_t job_time; /* time-at-creation attribute */
+ ipp_jstate_t job_status; /* job-status attribute */
+ int job_priority; /* job-priority attribute */
+ static const char *jattrs[] = /* Requested job attributes */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-priority",
+ "job-state",
+ "time-at-creation",
+ };
+ static const char *pattrs[] = /* Requested printer attributes */
+ {
+ "printer-state",
+ "printer-state-message"
+ };
+
+
+ DEBUG(5,("cups_queue_get(%d, %p, %p)\n", snum, q, status));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (0);
+ }
+
+ /*
+ * Generate the printer URI...
+ */
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_JOBS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(jattrs) / sizeof(jattrs[0])),
+ NULL, jattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL)
+ {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(cupsLastError())));
+ httpClose(http);
+ return (0);
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ {
+ DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
+ ippErrorString(response->request.status.status_code)));
+ ippDelete(response);
+ httpClose(http);
+
+ return (0);
+ }
+
+ /*
+ * Process the jobs...
+ */
+
+ qcount = 0;
+ qalloc = 0;
+ queue = NULL;
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Allocate memory as needed...
+ */
+ if (qcount >= qalloc)
+ {
+ qalloc += 16;
+
+ temp = Realloc(queue, sizeof(print_queue_struct) * qalloc);
+
+ if (temp == NULL)
+ {
+ DEBUG(0,("cups_queue_get: Not enough memory!"));
+ ippDelete(response);
+ httpClose(http);
+
+ free (queue);
+ return (0);
+ }
+
+ queue = temp;
+ }
+
+ temp = queue + qcount;
+ memset(temp, 0, sizeof(print_queue_struct));
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ job_id = 0;
+ job_priority = 50;
+ job_status = IPP_JOB_PENDING;
+ job_time = 0;
+ job_k_octets = 0;
+ user_name = NULL;
+ job_name = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (attr->name == NULL)
+ {
+ attr = attr->next;
+ break;
+ }
+
+ if (strcmp(attr->name, "job-id") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-k-octets") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_k_octets = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-priority") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_priority = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ job_status = (ipp_jstate_t)(attr->values[0].integer);
+
+ if (strcmp(attr->name, "time-at-creation") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_time = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ job_name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-originating-user-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ user_name = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (user_name == NULL || job_name == NULL || job_id == 0)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ temp->job = job_id;
+ temp->size = job_k_octets * 1024;
+ temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
+ job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
+ job_status == IPP_JOB_HELD ? LPQ_PAUSED :
+ LPQ_PRINTING;
+ temp->priority = job_priority;
+ temp->time = job_time;
+ strncpy(temp->user, user_name, sizeof(temp->user) - 1);
+ strncpy(temp->file, job_name, sizeof(temp->file) - 1);
+
+ qcount ++;
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ (sizeof(pattrs) / sizeof(pattrs[0])),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) == NULL)
+ {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ httpClose(http);
+ *q = queue;
+ return (qcount);
+ }
+
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ {
+ DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(response->request.status.status_code)));
+ ippDelete(response);
+ httpClose(http);
+ *q = queue;
+ return (qcount);
+ }
+
+ /*
+ * Get the current printer status and convert it to the SAMBA values.
+ */
+
+ if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
+ {
+ if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+ status->status = LPSTAT_STOPPED;
+ else
+ status->status = LPSTAT_OK;
+ }
+
+ if ((attr = ippFindAttribute(response, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ fstrcpy(status->message, attr->values[0].string.text);
+
+ ippDelete(response);
+
+ /*
+ * Return the job queue...
+ */
+
+ httpClose(http);
+
+ *q = queue;
+ return (qcount);
+}
+
+
+/*
+ * 'cups_queue_pause()' - Pause a print queue.
+ */
+
+static int
+cups_queue_pause(int snum)
+{
+ extern userdom_struct current_user_info;
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_queue_pause(%d)\n", snum));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_PAUSE_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PAUSE_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, current_user_info.unix_name);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ret = 1;
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'cups_queue_resume()' - Restart a print queue.
+ */
+
+static int
+cups_queue_resume(int snum)
+{
+ extern userdom_struct current_user_info;
+ int ret; /* Return value */
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* printer-uri attribute */
+
+
+ DEBUG(5,("cups_queue_resume(%d)\n", snum));
+
+ /*
+ * Make sure we don't ask for passwords...
+ */
+
+ cupsSetPasswordCB(cups_passwd_cb);
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ {
+ DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
+ cupsServer(), strerror(errno)));
+ return (1);
+ }
+
+ /*
+ * Build an IPP_RESUME_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_RESUME_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
+ PRINTERNAME(snum));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, current_user_info.unix_name);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ret = 1;
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ if (response->request.status.status_code >= IPP_OK_CONFLICT)
+ DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+ else
+ ret = 0;
+
+ ippDelete(response);
+ }
+ else
+ DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
+ ippErrorString(cupsLastError())));
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+#else
+ /* this keeps fussy compilers happy */
+ void print_cups_dummy(void) {}
+#endif /* HAVE_CUPS */
diff --git a/source/printing/print_generic.c b/source/printing/print_generic.c
new file mode 100644
index 00000000000..87031df849f
--- /dev/null
+++ b/source/printing/print_generic.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing command routines
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "printing.h"
+
+
+/*
+ * Generic printing interface definitions...
+ */
+
+static int generic_job_delete(int snum, struct printjob *pjob);
+static int generic_job_pause(int snum, struct printjob *pjob);
+static int generic_job_resume(int snum, struct printjob *pjob);
+static int generic_job_submit(int snum, struct printjob *pjob);
+static int generic_queue_get(int snum, print_queue_struct **q,
+ print_status_struct *status);
+static int generic_queue_pause(int snum);
+static int generic_queue_resume(int snum);
+
+
+struct printif generic_printif =
+ {
+ generic_queue_get,
+ generic_queue_pause,
+ generic_queue_resume,
+ generic_job_delete,
+ generic_job_pause,
+ generic_job_resume,
+ generic_job_submit,
+ };
+
+/****************************************************************************
+run a given print command
+a null terminated list of value/substitute pairs is provided
+for local substitution strings
+****************************************************************************/
+static int print_run_command(int snum,char *command, int *outfd, ...)
+{
+
+ pstring syscmd;
+ char *p, *arg;
+ int ret;
+ va_list ap;
+ va_start(ap, outfd);
+
+ if (!command || !*command) return -1;
+
+ if (!VALID_SNUM(snum)) {
+ DEBUG(0,("Invalid snum %d for command %s\n", snum, command));
+ return -1;
+ }
+
+ pstrcpy(syscmd, command);
+
+ while ((arg = va_arg(ap, char *))) {
+ char *value = va_arg(ap,char *);
+ pstring_sub(syscmd, arg, value);
+ }
+ va_end(ap);
+
+ p = PRINTERNAME(snum);
+
+ pstring_sub(syscmd, "%p", p);
+ standard_sub_snum(snum,syscmd);
+
+ ret = smbrun(syscmd,outfd);
+
+ DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+
+ return ret;
+}
+
+
+/****************************************************************************
+delete a print job
+****************************************************************************/
+static int generic_job_delete(int snum, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to delete the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command(
+ snum,
+ lp_lprmcommand(snum), NULL,
+ "%j", jobstr,
+ "%T", http_timestring(pjob->starttime),
+ NULL);
+}
+
+/****************************************************************************
+pause a job
+****************************************************************************/
+static int generic_job_pause(int snum, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to pause the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command(snum,
+ lp_lppausecommand(snum), NULL,
+ "%j", jobstr,
+ NULL);
+}
+
+/****************************************************************************
+resume a job
+****************************************************************************/
+static int generic_job_resume(int snum, struct printjob *pjob)
+{
+ fstring jobstr;
+
+ /* need to pause the spooled entry */
+ slprintf(jobstr, sizeof(jobstr)-1, "%d", pjob->sysjob);
+ return print_run_command(snum,
+ lp_lpresumecommand(snum), NULL,
+ "%j", jobstr,
+ NULL);
+}
+
+/****************************************************************************
+ Submit a file for printing - called from print_job_end()
+****************************************************************************/
+
+static int generic_job_submit(int snum, struct printjob *pjob)
+{
+ int ret;
+ pstring current_directory;
+ pstring print_directory;
+ char *wd, *p;
+ pstring jobname;
+
+ /* we print from the directory path to give the best chance of
+ parsing the lpq output */
+ wd = sys_getwd(current_directory);
+ if (!wd)
+ return 0;
+
+ pstrcpy(print_directory, pjob->filename);
+ p = strrchr_m(print_directory,'/');
+ if (!p)
+ return 0;
+ *p++ = 0;
+
+ if (chdir(print_directory) != 0)
+ return 0;
+
+ pstrcpy(jobname, pjob->jobname);
+ pstring_sub(jobname, "'", "_");
+
+ /* send it to the system spooler */
+ ret = print_run_command(snum,
+ lp_printcommand(snum), NULL,
+ "%s", p,
+ "%J", jobname,
+ "%f", p,
+ NULL);
+
+ chdir(wd);
+
+ return ret;
+}
+
+
+/****************************************************************************
+get the current list of queued jobs
+****************************************************************************/
+static int generic_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
+{
+ char **qlines;
+ int fd;
+ int numlines, i, qcount;
+ print_queue_struct *queue = NULL;
+ fstring printer_name;
+
+ fstrcpy(printer_name, lp_servicename(snum));
+
+ print_run_command(snum, lp_lpqcommand(snum), &fd, NULL);
+
+ if (fd == -1) {
+ DEBUG(5,("generic_queue_get: Can't read print queue status for printer %s\n",
+ printer_name ));
+ return 0;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines);
+ close(fd);
+
+ /* turn the lpq output into a series of job structures */
+ qcount = 0;
+ ZERO_STRUCTP(status);
+ if (numlines)
+ queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*(numlines+1));
+
+ if (queue) {
+ for (i=0; i<numlines; i++) {
+ /* parse the line */
+ if (parse_lpq_entry(snum,qlines[i],
+ &queue[qcount],status,qcount==0)) {
+ qcount++;
+ }
+ }
+ }
+ file_lines_free(qlines);
+
+ *q = queue;
+ return qcount;
+}
+
+/****************************************************************************
+ pause a queue
+****************************************************************************/
+static int generic_queue_pause(int snum)
+{
+ return print_run_command(snum, lp_queuepausecommand(snum), NULL, NULL);
+}
+
+/****************************************************************************
+ resume a queue
+****************************************************************************/
+static int generic_queue_resume(int snum)
+{
+ return print_run_command(snum, lp_queueresumecommand(snum), NULL, NULL);
+}
diff --git a/source/printing/print_svid.c b/source/printing/print_svid.c
new file mode 100644
index 00000000000..44127c3700a
--- /dev/null
+++ b/source/printing/print_svid.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 1997-1998 by Norm Jacobs, Colorado Springs, Colorado, USA
+ * Copyright (C) 1997-1998 by Sun Microsystem, Inc.
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This module implements support for gathering and comparing available
+ * printer information on a SVID or XPG4 compliant system. It does this
+ * through the use of the SVID/XPG4 command "lpstat(1)".
+ *
+ * The expectations is that execution of the command "lpstat -v" will
+ * generate responses in the form of:
+ *
+ * device for serial: /dev/term/b
+ * system for fax: server
+ * system for color: server (as printer chroma)
+ */
+
+
+#include "includes.h"
+#include "smb.h"
+
+#ifdef SYSV
+
+typedef struct printer {
+ char *name;
+ struct printer *next;
+} printer_t;
+static printer_t *printers = NULL;
+
+static void populate_printers(void)
+{
+ char **lines;
+ int i;
+
+ lines = file_lines_pload("/usr/bin/lpstat -v", NULL);
+ if (!lines) return;
+
+ for (i=0;lines[i];i++) {
+ printer_t *ptmp;
+ char *name, *tmp;
+ char *buf = lines[i];
+
+ /* eat "system/device for " */
+ if (((tmp = strchr_m(buf, ' ')) == NULL) ||
+ ((tmp = strchr_m(++tmp, ' ')) == NULL))
+ continue;
+
+ /*
+ * In case we're only at the "for ".
+ */
+
+ if(!strncmp("for ",++tmp,4)) {
+ tmp=strchr_m(tmp, ' ');
+ tmp++;
+ }
+
+ /* Eat whitespace. */
+
+ while(*tmp == ' ')
+ ++tmp;
+
+ /*
+ * On HPUX there is an extra line that can be ignored.
+ * d.thibadeau 2001/08/09
+ */
+ if(!strncmp("remote to",tmp,9))
+ continue;
+
+ name = tmp;
+
+ /* truncate the ": ..." */
+ if ((tmp = strchr_m(name, ':')) != NULL)
+ *tmp = '\0';
+
+ /* add it to the cache */
+ if ((ptmp = malloc(sizeof (*ptmp))) != NULL) {
+ ZERO_STRUCTP(ptmp);
+ if((ptmp->name = strdup(name)) == NULL)
+ DEBUG(0,("populate_printers: malloc fail in strdup !\n"));
+ ptmp->next = printers;
+ printers = ptmp;
+ } else {
+ DEBUG(0,("populate_printers: malloc fail for ptmp\n"));
+ }
+ }
+
+ file_lines_free(lines);
+}
+
+
+/*
+ * provide the equivalent of pcap_printer_fn() for SVID/XPG4 conforming
+ * systems. It was unclear why pcap_printer_fn() was tossing names longer
+ * than 8 characters. I suspect that its a protocol limit, but amazingly
+ * names longer than 8 characters appear to work with my test
+ * clients (Win95/NT).
+ */
+void sysv_printer_fn(void (*fn)(char *, char *))
+{
+ printer_t *tmp;
+
+ if (printers == NULL)
+ populate_printers();
+ for (tmp = printers; tmp != NULL; tmp = tmp->next)
+ (fn)(tmp->name, "");
+}
+
+
+/*
+ * provide the equivalent of pcap_printername_ok() for SVID/XPG4 conforming
+ * systems.
+ */
+int sysv_printername_ok(char *name)
+{
+ printer_t *tmp;
+
+ if (printers == NULL)
+ populate_printers();
+ for (tmp = printers; tmp != NULL; tmp = tmp->next)
+ if (strcmp(tmp->name, name) == 0)
+ return (True);
+ return (False);
+}
+
+#else
+/* this keeps fussy compilers happy */
+ void print_svid_dummy(void);
+ void print_svid_dummy(void) {}
+#endif
diff --git a/source/printing/printfsp.c b/source/printing/printfsp.c
new file mode 100644
index 00000000000..322deadf0fa
--- /dev/null
+++ b/source/printing/printfsp.c
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ printing backend routines for smbd - using files_struct rather
+ than only snum
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/***************************************************************************
+open a print file and setup a fsp for it. This is a wrapper around
+print_job_start().
+***************************************************************************/
+
+files_struct *print_fsp_open(connection_struct *conn)
+{
+ int jobid;
+ SMB_STRUCT_STAT sbuf;
+ extern struct current_user current_user;
+ files_struct *fsp = file_new(conn);
+
+ if(!fsp)
+ return NULL;
+
+ jobid = print_job_start(&current_user, SNUM(conn), "smb.prn");
+ if (jobid == -1) {
+ file_free(fsp);
+ return NULL;
+ }
+
+ /* setup a full fsp */
+ fsp->print_jobid = jobid;
+ fsp->fd = print_job_fd(jobid);
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_user.vuid;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->can_lock = True;
+ fsp->can_read = False;
+ fsp->can_write = True;
+ fsp->share_mode = 0;
+ fsp->print_file = True;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ fsp->stat_open = False;
+ fsp->directory_delete_on_close = False;
+ fsp->conn = conn;
+ string_set(&fsp->fsp_name,print_job_fname(jobid));
+ fsp->wbmpx_ptr = NULL;
+ fsp->wcp = NULL;
+ conn->vfs_ops.fstat(fsp,fsp->fd, &sbuf);
+ fsp->mode = sbuf.st_mode;
+ fsp->inode = sbuf.st_ino;
+ fsp->dev = sbuf.st_dev;
+
+ conn->num_files_open++;
+
+ return fsp;
+}
+
+/****************************************************************************
+print a file - called on closing the file
+****************************************************************************/
+void print_fsp_end(files_struct *fsp, BOOL normal_close)
+{
+ if (fsp->share_mode == FILE_DELETE_ON_CLOSE) {
+ /*
+ * Truncate the job. print_job_end will take
+ * care of deleting it for us. JRA.
+ */
+ sys_ftruncate(fsp->fd, 0);
+ }
+
+ print_job_end(fsp->print_jobid, normal_close);
+
+ if (fsp->fsp_name) {
+ string_free(&fsp->fsp_name);
+ }
+}
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 1dd8921800a..fe16ee7283e 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -1,8 +1,8 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
- printing routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Version 3.0
+ printing backend routines
+ Copyright (C) Andrew Tridgell 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,841 +19,1330 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
-
-static BOOL * lpq_cache_reset=NULL;
-
-static int check_lpq_cache(int snum) {
- static int lpq_caches=0;
-
- if (lpq_caches <= snum) {
- BOOL * p;
- p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
- if (p) {
- lpq_cache_reset=p;
- lpq_caches = snum+1;
- }
- }
- return lpq_caches;
-}
-
-void lpq_reset(int snum)
-{
- if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
-}
-
-
-/****************************************************************************
-Build the print command in the supplied buffer. This means getting the
-print command for the service and inserting the printer name and the
-print file name. Return NULL on error, else the passed buffer pointer.
-****************************************************************************/
-static char *build_print_command(int cnum, char *command, char *syscmd, char *filename1)
-{
- int snum = SNUM(cnum);
- char *tstr;
- pstring filename;
-
- /* get the print command for the service. */
- tstr = command;
- if (!syscmd || !tstr) {
- DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
- return (NULL);
- }
-
- /* copy the command into the buffer for extensive meddling. */
- StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
-
- /* look for "%s" in the string. If there is no %s, we cannot print. */
- if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
- DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
- }
-
- if (strstr(syscmd,"%s")) {
- int iOffset = strstr(syscmd, "%s") - syscmd;
-
- /* construct the full path for the filename, shouldn't be necessary unless
- the subshell causes a "cd" to be executed.
- Only use the full path if there isn't a / preceding the %s */
- if (iOffset==0 || syscmd[iOffset-1] != '/') {
- StrnCpy(filename,Connections[cnum].connectpath,sizeof(filename)-1);
- trim_string(filename,"","/");
- strcat(filename,"/");
- strcat(filename,filename1);
- }
- else
- strcpy(filename,filename1);
-
- string_sub(syscmd, "%s", filename);
- }
-
- string_sub(syscmd, "%f", filename1);
-
- /* Does the service have a printername? If not, make a fake and empty */
- /* printer name. That way a %p is treated sanely if no printer */
- /* name was specified to replace it. This eventuality is logged. */
- tstr = PRINTERNAME(snum);
- if (tstr == NULL || tstr[0] == '\0') {
- DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
- tstr = SERVICE(snum);
- }
-
- string_sub(syscmd, "%p", tstr);
-
- standard_sub(cnum,syscmd);
-
- return (syscmd);
-}
-
-
-/****************************************************************************
-print a file - called on closing the file
-****************************************************************************/
-void print_file(int fnum)
-{
- pstring syscmd;
- int cnum = Files[fnum].cnum;
- int snum=SNUM(cnum);
- char *tempstr;
-
- *syscmd = 0;
-
- if (file_size(Files[fnum].name) <= 0) {
- DEBUG(3,("Discarding null print job %s\n",Files[fnum].name));
- sys_unlink(Files[fnum].name);
- return;
- }
-
- tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
- if (tempstr != NULL)
- {
- int ret = smbrun(syscmd,NULL);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
- }
- else
- DEBUG(0,("Null print command?\n"));
-
- lpq_reset(snum);
-}
-
-static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
-
-
-/*******************************************************************
-process time fields
-********************************************************************/
-static time_t EntryTime(string tok[], int ptr, int count, int minimum)
-{
- time_t jobtime;
-
- jobtime = time(NULL); /* default case: take current time */
- if (count >= minimum) {
- struct tm *t;
- int i, day, hour, min, sec;
- char *c;
-
- for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
- if (i<12) {
- t = localtime(&jobtime);
- day = atoi(tok[ptr+1]);
- c=(char *)(tok[ptr+2]);
- *(c+2)=0;
- hour = atoi(c);
- *(c+5)=0;
- min = atoi(c+3);
- if(*(c+6) != 0)sec = atoi(c+6);
- else sec=0;
-
- if ((t->tm_mon < i)||
- ((t->tm_mon == i)&&
- ((t->tm_mday < day)||
- ((t->tm_mday == day)&&
- (t->tm_hour*60+t->tm_min < hour*60+min)))))
- t->tm_year--; /* last year's print job */
-
- t->tm_mon = i;
- t->tm_mday = day;
- t->tm_hour = hour;
- t->tm_min = min;
- t->tm_sec = sec;
- jobtime = mktime(t);
- }
- }
- return jobtime;
-}
-
-
-/****************************************************************************
-parse a lpq line
-
-here is an example of lpq output under bsd
-
-Warning: no daemon present
-Rank Owner Job Files Total Size
-1st tridge 148 README 8096 bytes
-
-here is an example of lpq output under osf/1
-
-Warning: no daemon present
-Rank Pri Owner Job Files Total Size
-1st 0 tridge 148 README 8096 bytes
-****************************************************************************/
-static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
-{
-#ifdef OSF1
-#define RANKTOK 0
-#define PRIOTOK 1
-#define USERTOK 2
-#define JOBTOK 3
-#define FILETOK 4
-#define TOTALTOK 5
-#define NTOK 6
-#else /* OSF1 */
-#define RANKTOK 0
-#define USERTOK 1
-#define JOBTOK 2
-#define FILETOK 3
-#define TOTALTOK 4
-#define NTOK 5
-#endif /* OSF1 */
-
- string tok[NTOK];
- int count=0;
-
-#ifdef OSF1
- int length;
- length = strlen(line);
- if (line[length-3] == ':')
- return(False);
-#endif /* OSF1 */
-
- /* handle the case of "(standard input)" as a filename */
- string_sub(line,"standard input","STDIN");
- string_sub(line,"(","\"");
- string_sub(line,")","\"");
-
- for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
-
- /* we must get NTOK tokens */
- if (count < NTOK)
- return(False);
-
- /* the Job and Total columns must be integer */
- if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
-
- /* if the fname contains a space then use STDIN */
- if (strchr(tok[FILETOK],' '))
- strcpy(tok[FILETOK],"STDIN");
-
- /* only take the last part of the filename */
- {
- string tmp;
- char *p = strrchr(tok[FILETOK],'/');
- if (p)
- {
- strcpy(tmp,p+1);
- strcpy(tok[FILETOK],tmp);
- }
- }
+#include "printing.h"
+
+/* Current printer interface */
+struct printif *current_printif = &generic_printif;
+
+/*
+ the printing backend revolves around a tdb database that stores the
+ SMB view of the print queue
+
+ The key for this database is a jobid - a internally generated number that
+ uniquely identifies a print job
+
+ reading the print queue involves two steps:
+ - possibly running lpq and updating the internal database from that
+ - reading entries from the database
+
+ jobids are assigned when a job starts spooling.
+*/
+
+/* the open printing.tdb database */
+static TDB_CONTEXT *tdb;
+static pid_t local_pid;
+
+static int get_queue_status(int, print_status_struct *);
+
+/****************************************************************************
+initialise the printing backend. Called once at startup.
+Does not survive a fork
+****************************************************************************/
+BOOL print_backend_init(void)
+{
+ char *sversion = "INFO/version";
+
+ if (tdb && local_pid == sys_getpid()) return True;
+ tdb = tdb_open_log(lock_path("printing.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb) {
+ DEBUG(0,("print_backend_init: Failed to open printing backend database. Error = [%s]\n",
+ tdb_errorstr(tdb)));
+ return False;
+ }
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb, sversion);
+ if (tdb_fetch_int(tdb, sversion) != PRINT_DATABASE_VERSION) {
+ tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
+ tdb_store_int(tdb, sversion, PRINT_DATABASE_VERSION);
+ }
+ tdb_unlock_bystring(tdb, sversion);
+
+ /* select the appropriate printing interface... */
+#ifdef HAVE_CUPS
+ if (strcmp(lp_printcapname(), "cups") == 0)
+ current_printif = &cups_printif;
+#endif /* HAVE_CUPS */
+
+ /* do NT print initialization... */
+ return nt_printing_init();
+}
+
+/****************************************************************************
+useful function to generate a tdb key
+****************************************************************************/
+static TDB_DATA print_key(int jobid)
+{
+ static int j;
+ TDB_DATA ret;
+
+ j = jobid;
+ ret.dptr = (void *)&j;
+ ret.dsize = sizeof(j);
+ return ret;
+}
+
+/****************************************************************************
+useful function to find a print job in the database
+****************************************************************************/
+static struct printjob *print_job_find(int jobid)
+{
+ static struct printjob pjob;
+ TDB_DATA ret;
+
+ ret = tdb_fetch(tdb, print_key(jobid));
+ if (!ret.dptr || ret.dsize != sizeof(pjob)) return NULL;
+
+ memcpy(&pjob, ret.dptr, sizeof(pjob));
+ free(ret.dptr);
+ return &pjob;
+}
+
+/****************************************************************************
+store a job structure back to the database
+****************************************************************************/
+static BOOL print_job_store(int jobid, struct printjob *pjob)
+{
+ TDB_DATA d;
+ d.dptr = (void *)pjob;
+ d.dsize = sizeof(*pjob);
+
+ return (tdb_store(tdb, print_key(jobid), d, TDB_REPLACE) == 0);
+}
+
+/****************************************************************************
+parse a file name from the system spooler to generate a jobid
+****************************************************************************/
+static int print_parse_jobid(char *fname)
+{
+ int jobid;
+
+ if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0) return -1;
+ fname += strlen(PRINT_SPOOL_PREFIX);
+
+ jobid = atoi(fname);
+ if (jobid <= 0) return -1;
+
+ return jobid;
+}
+
+
+/****************************************************************************
+list a unix job in the print database
+****************************************************************************/
+static void print_unix_job(int snum, print_queue_struct *q)
+{
+ int jobid = q->job + UNIX_JOB_START;
+ struct printjob pj, *old_pj;
+
+ /* Preserve the timestamp on an existing unix print job */
+
+ old_pj = print_job_find(jobid);
+
+ ZERO_STRUCT(pj);
+
+ pj.pid = (pid_t)-1;
+ pj.sysjob = q->job;
+ pj.fd = -1;
+ pj.starttime = old_pj ? old_pj->starttime : q->time;
+ pj.status = q->status;
+ pj.size = q->size;
+ pj.spooled = True;
+ pj.smbjob = False;
+ fstrcpy(pj.filename, "");
+ fstrcpy(pj.jobname, q->file);
+ fstrcpy(pj.user, q->user);
+ fstrcpy(pj.qname, lp_servicename(snum));
+
+ print_job_store(jobid, &pj);
+}
+
+
+struct traverse_struct {
+ print_queue_struct *queue;
+ int qcount, snum, maxcount, total_jobs;
+};
+
+/* utility fn to delete any jobs that are no longer active */
+static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct traverse_struct *ts = (struct traverse_struct *)state;
+ struct printjob pjob;
+ int i, jobid;
+
+ if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
+ memcpy(&jobid, key.dptr, sizeof(jobid));
+ memcpy(&pjob, data.dptr, sizeof(pjob));
+
+ if (strcmp(lp_servicename(ts->snum), pjob.qname)) {
+ /* this isn't for the queue we are looking at */
+ ts->total_jobs++;
+ return 0;
+ }
+
+ if (!pjob.smbjob) {
+ /* remove a unix job if it isn't in the system queue any more */
+
+ for (i=0;i<ts->qcount;i++) {
+ if (jobid == ts->queue[i].job + UNIX_JOB_START) break;
+ }
+ if (i == ts->qcount)
+ tdb_delete(tdb, key);
+ else
+ ts->total_jobs++;
+ return 0;
+ }
+
+ /* maybe it hasn't been spooled yet */
+ if (!pjob.spooled) {
+ /* if a job is not spooled and the process doesn't
+ exist then kill it. This cleans up after smbd
+ deaths */
+ if (!process_exists(pjob.pid))
+ tdb_delete(tdb, key);
+ else
+ ts->total_jobs++;
+ return 0;
+ }
+
+ for (i=0;i<ts->qcount;i++) {
+ int qid = print_parse_jobid(ts->queue[i].file);
+ if (jobid == qid) break;
+ }
+
+ /* The job isn't in the system queue - we have to assume it has
+ completed, so delete the database entry. */
+
+ if (i == ts->qcount) {
+ time_t cur_t = time(NULL);
+
+ /* A race can occur between the time a job is spooled and
+ when it appears in the lpq output. This happens when
+ the job is added to printing.tdb when another smbd
+ running print_queue_update() has completed a lpq and
+ is currently traversing the printing tdb and deleting jobs.
+ A workaround is to not delete the job if it has been
+ submitted less than lp_lpqcachetime() seconds ago. */
+
+ if ((cur_t - pjob.starttime) > lp_lpqcachetime())
+ tdb_delete(t, key);
+ else
+ ts->total_jobs++;
+ }
+ else
+ ts->total_jobs++;
+
+ return 0;
+}
+
+/****************************************************************************
+check if the print queue has been updated recently enough
+****************************************************************************/
+static void print_cache_flush(int snum)
+{
+ fstring key;
+ slprintf(key, sizeof(key)-1, "CACHE/%s", lp_servicename(snum));
+ tdb_store_int(tdb, key, -1);
+}
+
+/****************************************************************************
+ Check if someone already thinks they are doing the update.
+****************************************************************************/
+
+static pid_t get_updating_pid(fstring printer_name)
+{
+ fstring keystr;
+ TDB_DATA data, key;
+ pid_t updating_pid;
+
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr);
+
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr || data.dsize != sizeof(pid_t))
+ return (pid_t)-1;
+
+ memcpy(&updating_pid, data.dptr, sizeof(pid_t));
+ free(data.dptr);
+
+ if (process_exists(updating_pid))
+ return updating_pid;
+
+ return (pid_t)-1;
+}
+
+/****************************************************************************
+ Set the fact that we're doing the update, or have finished doing the update
+ in th tdb.
+****************************************************************************/
+
+static void set_updating_pid(fstring printer_name, BOOL delete)
+{
+ fstring keystr;
+ TDB_DATA key;
+ TDB_DATA data;
+ pid_t updating_pid = getpid();
+
+ slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr);
+
+ if (delete) {
+ tdb_delete(tdb, key);
+ return;
+ }
+
+ data.dptr = (void *)&updating_pid;
+ data.dsize = sizeof(pid_t);
+
+ tdb_store(tdb, key, data, TDB_REPLACE);
+}
+
+/****************************************************************************
+update the internal database from the system print queue for a queue in the background
+****************************************************************************/
+
+static void print_queue_update_background(int snum)
+{
+ int i, qcount;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
+ print_status_struct old_status;
+ struct printjob *pjob;
+ struct traverse_struct tstruct;
+ fstring keystr, printer_name, cachestr;
+ TDB_DATA data, key;
+
+ fstrcpy(printer_name, lp_servicename(snum));
+
+ /*
+ * Check to see if someone else is doing this update.
+ * This is essentially a mutex on the update.
+ */
+
+ if (get_updating_pid(printer_name) != -1)
+ return;
+
+ /* Lock the queue for the database update */
+
+ slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
+ tdb_lock_bystring(tdb, keystr);
+
+ /*
+ * Ensure that no one else got in here.
+ * If the updating pid is still -1 then we are
+ * the winner.
+ */
+
+ if (get_updating_pid(printer_name) != -1) {
+ /*
+ * Someone else is doing the update, exit.
+ */
+ tdb_unlock_bystring(tdb, keystr);
+ return;
+ }
+
+ /*
+ * We're going to do the update ourselves.
+ */
+
+ /* Tell others we're doing the update. */
+ set_updating_pid(printer_name, False);
+
+ /*
+ * Allow others to enter and notice we're doing
+ * the update.
+ */
+
+ tdb_unlock_bystring(tdb, keystr);
+
+ /*
+ * Update the cache time FIRST ! Stops others even
+ * attempting to get the lock and doing this
+ * if the lpq takes a long time.
+ */
+
+ slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", printer_name);
+ tdb_store_int(tdb, cachestr, (int)time(NULL));
+
+ /* get the current queue using the appropriate interface */
+ ZERO_STRUCT(status);
+
+ qcount = (*(current_printif->queue_get))(snum, &queue, &status);
+
+ DEBUG(3, ("%d job%s in queue for %s\n", qcount, (qcount != 1) ?
+ "s" : "", printer_name));
+
+ /*
+ any job in the internal database that is marked as spooled
+ and doesn't exist in the system queue is considered finished
+ and removed from the database
+
+ any job in the system database but not in the internal database
+ is added as a unix job
+
+ fill in any system job numbers as we go
+ */
+ for (i=0; i<qcount; i++) {
+ int jobid = print_parse_jobid(queue[i].file);
+
+ if (jobid == -1) {
+ /* assume its a unix print job */
+ print_unix_job(snum, &queue[i]);
+ continue;
+ }
+
+ /* we have an active SMB print job - update its status */
+ pjob = print_job_find(jobid);
+ if (!pjob) {
+ /* err, somethings wrong. Probably smbd was restarted
+ with jobs in the queue. All we can do is treat them
+ like unix jobs. Pity. */
+ print_unix_job(snum, &queue[i]);
+ continue;
+ }
+
+ pjob->sysjob = queue[i].job;
+ pjob->status = queue[i].status;
+
+ print_job_store(jobid, pjob);
+ }
+
+ /* now delete any queued entries that don't appear in the
+ system queue */
+ tstruct.queue = queue;
+ tstruct.qcount = qcount;
+ tstruct.snum = snum;
+ tstruct.total_jobs = 0;
+
+ tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct);
+
+ safe_free(tstruct.queue);
+
+ tdb_store_int(tdb, "INFO/total_jobs", tstruct.total_jobs);
+
+ /*
+ * Get the old print status. We will use this to compare the
+ * number of jobs. If they have changed we need to send a
+ * "changed" message to the smbds.
+ */
+
+ if( qcount != get_queue_status(snum, &old_status)) {
+ DEBUG(10,("print_queue_update: queue status change %d jobs -> %d jobs for printer %s\n",
+ old_status.qcount, qcount, printer_name ));
+ message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+ }
+
+ /* store the new queue status structure */
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printer_name);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr);
+
+ status.qcount = qcount;
+ data.dptr = (void *)&status;
+ data.dsize = sizeof(status);
+ tdb_store(tdb, key, data, TDB_REPLACE);
+
+ /*
+ * Update the cache time again. We want to do this call
+ * as little as possible...
+ */
+
+ slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", printer_name);
+ tdb_store_int(tdb, keystr, (int)time(NULL));
+
+ /* Delete our pid from the db. */
+ set_updating_pid(printer_name, True);
+}
+
+/****************************************************************************
+this is the receive function of the background lpq updater
+****************************************************************************/
+static void print_queue_receive(int msg_type, pid_t src, void *buf, size_t len)
+{
+ int snum;
+ snum=*((int *)buf);
+ print_queue_update_background(snum);
+}
+
+static pid_t background_lpq_updater_pid;
+
+/****************************************************************************
+main thread of the background lpq updater
+****************************************************************************/
+void start_background_queue(void)
+{
+ DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
+ background_lpq_updater_pid = sys_fork();
+
+ if (background_lpq_updater_pid == -1) {
+ DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
+ exit(1);
+ }
+
+ if(background_lpq_updater_pid == 0) {
+ /* Child. */
+ DEBUG(5,("start_background_queue: background LPQ thread started\n"));
+
+ claim_connection(NULL,"smbd lpq backend",MAXSTATUS,False);
+
+ if (!locking_init(0)) {
+ exit(1);
+ }
+
+ if (!print_backend_init()) {
+ exit(1);
+ }
+
+ message_register(MSG_PRINTER_UPDATE, print_queue_receive);
+
+ DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
+ while (1) {
+ pause();
+ DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
+ message_dispatch();
+ }
+ }
+}
+
+/****************************************************************************
+update the internal database from the system print queue for a queue
+****************************************************************************/
+static void print_queue_update(int snum)
+{
+ message_send_pid(background_lpq_updater_pid, MSG_PRINTER_UPDATE, &snum, sizeof(snum), False);
+}
+
+/****************************************************************************
+check if a jobid is valid. It is valid if it exists in the database
+****************************************************************************/
+BOOL print_job_exists(int jobid)
+{
+ return tdb_exists(tdb, print_key(jobid));
+}
+
+
+/****************************************************************************
+work out which service a jobid is for
+note that we have to look up by queue name to ensure that it works for
+other than the process that started the job
+****************************************************************************/
+int print_job_snum(int jobid)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ if (!pjob) return -1;
+
+ return lp_servicenumber(pjob->qname);
+}
+
+/****************************************************************************
+give the fd used for a jobid
+****************************************************************************/
+int print_job_fd(int jobid)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ if (!pjob) return -1;
+ /* don't allow another process to get this info - it is meaningless */
+ if (pjob->pid != local_pid) return -1;
+ return pjob->fd;
+}
+
+/****************************************************************************
+give the filename used for a jobid
+only valid for the process doing the spooling and when the job
+has not been spooled
+****************************************************************************/
+char *print_job_fname(int jobid)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ if (!pjob || pjob->spooled || pjob->pid != local_pid) return NULL;
+ return pjob->filename;
+}
+
+
+/****************************************************************************
+set the place in the queue for a job
+****************************************************************************/
+BOOL print_job_set_place(int jobid, int place)
+{
+ DEBUG(2,("print_job_set_place not implemented yet\n"));
+ return False;
+}
+
+/****************************************************************************
+set the name of a job. Only possible for owner
+****************************************************************************/
+BOOL print_job_set_name(int jobid, char *name)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ if (!pjob || pjob->pid != local_pid) return False;
+
+ fstrcpy(pjob->jobname, name);
+ return print_job_store(jobid, pjob);
+}
+
+
+/****************************************************************************
+delete a print job - don't update queue
+****************************************************************************/
+static BOOL print_job_delete1(int jobid)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ int snum, result = 0;
+
+ if (!pjob) return False;
+
+ /*
+ * If already deleting just return.
+ */
+
+ if (pjob->status == LPQ_DELETING)
+ return True;
+
+ snum = print_job_snum(jobid);
+
+ /* Hrm - we need to be able to cope with deleting a job before it
+ has reached the spooler. */
+
+ if (pjob->sysjob == -1) {
+ DEBUG(5, ("attempt to delete job %d not seen by lpr\n",
+ jobid));
+ }
+
+ /* Set the tdb entry to be deleting. */
+
+ pjob->status = LPQ_DELETING;
+ print_job_store(jobid, pjob);
+
+ if (pjob->spooled && pjob->sysjob != -1)
+ result = (*(current_printif->job_delete))(snum, pjob);
+
+ /* Delete the tdb entry if the delete suceeded or the job hasn't
+ been spooled. */
+
+ if (result == 0) {
+ tdb_delete(tdb, print_key(jobid));
+ }
+
+ return (result == 0);
+}
+
+/****************************************************************************
+return true if the current user owns the print job
+****************************************************************************/
+static BOOL is_owner(struct current_user *user, int jobid)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ user_struct *vuser;
+
+ if (!pjob || !user) return False;
+
+ if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
+ return strequal(pjob->user, vuser->user.smb_name);
+ } else {
+ return strequal(pjob->user, uidtoname(user->uid));
+ }
+}
+
+/****************************************************************************
+delete a print job
+****************************************************************************/
+BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode)
+{
+ int snum = print_job_snum(jobid);
+ char *printer_name;
+ BOOL owner;
+
+ owner = is_owner(user, jobid);
+
+ /* Check access against security descriptor or whether the user
+ owns their job. */
+
+ if (!owner &&
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("delete denied by security descriptor\n"));
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ if (!print_job_delete1(jobid)) return False;
+
+ /* force update the database and say the delete failed if the
+ job still exists */
+
+ print_queue_update(snum);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ return !print_job_exists(jobid);
+}
+
+
+/****************************************************************************
+pause a job
+****************************************************************************/
+BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ int snum, ret = -1;
+ char *printer_name;
+
+ if (!pjob || !user) return False;
+
+ if (!pjob->spooled || pjob->sysjob == -1) return False;
+
+ snum = print_job_snum(jobid);
+
+ if (!is_owner(user, jobid) &&
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("pause denied by security descriptor\n"));
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ /* need to pause the spooled entry */
+ ret = (*(current_printif->job_pause))(snum, pjob);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(snum);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ /* how do we tell if this succeeded? */
+
+ return True;
+}
+
+/****************************************************************************
+resume a job
+****************************************************************************/
+BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ char *printer_name;
+ int snum, ret;
+ if (!pjob || !user) return False;
+
+ if (!pjob->spooled || pjob->sysjob == -1) return False;
+
+ snum = print_job_snum(jobid);
+
+ if (!is_owner(user, jobid) &&
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("resume denied by security descriptor\n"));
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ ret = (*(current_printif->job_resume))(snum, pjob);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(snum);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ return True;
+}
+
+/****************************************************************************
+write to a print file
+****************************************************************************/
+int print_job_write(int jobid, const char *buf, int size)
+{
+ int fd;
+
+ fd = print_job_fd(jobid);
+ if (fd == -1) return -1;
- buf->job = atoi(tok[JOBTOK]);
- buf->size = atoi(tok[TOTALTOK]);
- buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
- buf->time = time(NULL);
- StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
-#ifdef PRIOTOK
- buf->priority = atoi(tok[PRIOTOK]);
-#else
- buf->priority = 1;
-#endif
- return(True);
-}
-
-
-
-/*******************************************************************
-parse lpq on an aix system
-
-Queue Dev Status Job Files User PP % Blks Cp Rnk
-------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
-lazer lazer READY
-lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
- QUEUED 538 C.ps root@IEDVB 124 1 2
- QUEUED 539 E.ps root@IEDVB 28 1 3
- QUEUED 540 L.ps root@IEDVB 172 1 4
- QUEUED 541 P.ps root@IEDVB 22 1 5
-********************************************************************/
-static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
-{
- string tok[11];
- int count=0;
-
- /* handle the case of "(standard input)" as a filename */
- string_sub(line,"standard input","STDIN");
- string_sub(line,"(","\"");
- string_sub(line,")","\"");
-
- for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
-
- /* we must get 6 tokens */
- if (count < 10)
- {
- if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
- {
- /* the 2nd and 5th columns must be integer */
- if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
- buf->size = atoi(tok[4]) * 1024;
- /* if the fname contains a space then use STDIN */
- if (strchr(tok[2],' '))
- strcpy(tok[2],"STDIN");
-
- /* only take the last part of the filename */
- {
- string tmp;
- char *p = strrchr(tok[2],'/');
- if (p)
- {
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
- }
- }
-
-
- buf->job = atoi(tok[1]);
- buf->status = LPQ_QUEUED;
- buf->priority = 0;
- buf->time = time(NULL);
- StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
- }
- else
- {
- DEBUG(6,("parse_lpq_aix count=%d\n", count));
- return(False);
- }
- }
- else
- {
- /* the 4th and 9th columns must be integer */
- if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
- buf->size = atoi(tok[8]) * 1024;
- /* if the fname contains a space then use STDIN */
- if (strchr(tok[4],' '))
- strcpy(tok[4],"STDIN");
-
- /* only take the last part of the filename */
- {
- string tmp;
- char *p = strrchr(tok[4],'/');
- if (p)
- {
- strcpy(tmp,p+1);
- strcpy(tok[4],tmp);
- }
- }
-
-
- buf->job = atoi(tok[3]);
- buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
- buf->priority = 0;
- buf->time = time(NULL);
- StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
- }
-
-
- return(True);
-}
-
-
-/****************************************************************************
-parse a lpq line
-here is an example of lpq output under hpux; note there's no space after -o !
-$> lpstat -oljplus
-ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
- util.c 125697 bytes
- server.c 110712 bytes
-ljplus-2154 user priority 0 Jan 19 08:14 from client
- (standard input) 7551 bytes
-****************************************************************************/
-static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
-{
- /* must read two lines to process, therefore keep some values static */
- static BOOL header_line_ok=False, base_prio_reset=False;
- static string jobuser;
- static int jobid;
- static int jobprio;
- static time_t jobtime;
- static int jobstat=LPQ_QUEUED;
- /* to store minimum priority to print, lpstat command should be invoked
- with -p option first, to work */
- static int base_prio;
+ return write(fd, buf, size);
+}
+
+/****************************************************************************
+ Check if the print queue has been updated recently enough.
+****************************************************************************/
+
+static BOOL print_cache_expired(int snum)
+{
+ fstring key;
+ time_t t2, t = time(NULL);
+
+ slprintf(key, sizeof(key)-1, "CACHE/%s", lp_servicename(snum));
+ t2 = tdb_fetch_int(tdb, key);
+ if (t2 == ((time_t)-1) || (t - t2) >= lp_lpqcachetime()) {
+ DEBUG(3, ("print cache expired for queue %s \
+(last_cache = %d, time now = %d, qcachetime = %d)\n", lp_servicename(snum),
+ (int)t2, (int)t, (int)lp_lpqcachetime() ));
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Get the queue status - do not update if db is out of date.
+****************************************************************************/
+static int get_queue_status(int snum, print_status_struct *status)
+{
+ fstring keystr;
+ TDB_DATA data, key;
+
+ ZERO_STRUCTP(status);
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum));
+ key.dptr = keystr;
+ key.dsize = strlen(keystr);
+ data = tdb_fetch(tdb, key);
+ if (data.dptr) {
+ if (data.dsize == sizeof(print_status_struct)) {
+ memcpy(status, data.dptr, sizeof(print_status_struct));
+ }
+ free(data.dptr);
+ }
+ return status->qcount;
+}
+
+/****************************************************************************
+ Determine the number of jobs in a queue.
+****************************************************************************/
+
+int print_queue_length(int snum, print_status_struct *pstatus)
+{
+ print_status_struct status;
+ int len;
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum))
+ print_queue_update(snum);
- int count;
- char TAB = '\011';
- string tok[12];
-
- /* If a line begins with a horizontal TAB, it is a subline type */
-
- if (line[0] == TAB) { /* subline */
- /* check if it contains the base priority */
- if (!strncmp(line,"\tfence priority : ",18)) {
- base_prio=atoi(&line[18]);
- DEBUG(4, ("fence priority set at %d\n", base_prio));
- }
- if (!header_line_ok) return (False); /* incorrect header line */
- /* handle the case of "(standard input)" as a filename */
- string_sub(line,"standard input","STDIN");
- string_sub(line,"(","\"");
- string_sub(line,")","\"");
-
- for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
- /* we must get 2 tokens */
- if (count < 2) return(False);
-
- /* the 2nd column must be integer */
- if (!isdigit(*tok[1])) return(False);
-
- /* if the fname contains a space then use STDIN */
- if (strchr(tok[0],' '))
- strcpy(tok[0],"STDIN");
-
- buf->size = atoi(tok[1]);
- StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
-
- /* fill things from header line */
- buf->time = jobtime;
- buf->job = jobid;
- buf->status = jobstat;
- buf->priority = jobprio;
- StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
-
- return(True);
- }
- else { /* header line */
- header_line_ok=False; /* reset it */
- if (first) {
- if (!base_prio_reset) {
- base_prio=0; /* reset it */
- base_prio_reset=True;
- }
- }
- else if (base_prio) base_prio_reset=False;
-
- /* handle the dash in the job id */
- string_sub(line,"-"," ");
-
- for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
-
- /* we must get 8 tokens */
- if (count < 8) return(False);
-
- /* first token must be printer name (cannot check ?) */
- /* the 2nd, 5th & 7th column must be integer */
- if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
- jobid = atoi(tok[1]);
- StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
- jobprio = atoi(tok[4]);
-
- /* process time */
- jobtime=EntryTime(tok, 5, count, 8);
- if (jobprio < base_prio) {
- jobstat = LPQ_PAUSED;
- DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
- }
- else {
- jobstat = LPQ_QUEUED;
- if ((count >8) && (((strequal(tok[8],"on")) ||
- ((strequal(tok[8],"from")) &&
- ((count > 10)&&(strequal(tok[10],"on")))))))
- jobstat = LPQ_PRINTING;
- }
-
- header_line_ok=True; /* information is correct */
- return(False); /* need subline info to include into queuelist */
- }
-}
-
-
-/****************************************************************************
-parse a lpq line
-
-here is an example of "lpstat -o dcslw" output under sysv
-
-dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
-dcslw-897 tridge 4712 Dec 20 10:30:30 being held
-
-****************************************************************************/
-static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
-{
- string tok[9];
- int count=0;
- char *p;
-
- /* handle the dash in the job id */
- string_sub(line,"-"," ");
-
- for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
-
- /* we must get 7 tokens */
- if (count < 7)
- return(False);
-
- /* the 2nd and 4th, 6th columns must be integer */
- if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
- if (!isdigit(*tok[5])) return(False);
-
- /* if the user contains a ! then trim the first part of it */
- if ((p=strchr(tok[2],'!')))
- {
- string tmp;
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
- }
-
-
- buf->job = atoi(tok[1]);
- buf->size = atoi(tok[3]);
- if (count > 7 && strequal(tok[7],"on"))
- buf->status = LPQ_PRINTING;
- else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
- buf->status = LPQ_PAUSED;
- else
- buf->status = LPQ_QUEUED;
- buf->priority = 0;
- buf->time = EntryTime(tok, 4, count, 7);
- StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
- return(True);
-}
-
-/****************************************************************************
-parse a lpq line
-
-here is an example of lpq output under qnx
-Spooler: /qnx/spooler, on node 1
-Printer: txt (ready)
-0000: root [job #1 ] active 1146 bytes /etc/profile
-0001: root [job #2 ] ready 2378 bytes /etc/install
-0002: root [job #3 ] ready 1146 bytes -- standard input --
-****************************************************************************/
-static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
-{
- string tok[7];
- int count=0;
-
- DEBUG(0,("antes [%s]\n", line));
-
- /* handle the case of "-- standard input --" as a filename */
- string_sub(line,"standard input","STDIN");
- DEBUG(0,("despues [%s]\n", line));
- string_sub(line,"-- ","\"");
- string_sub(line," --","\"");
- DEBUG(0,("despues 1 [%s]\n", line));
-
- string_sub(line,"[job #","");
- string_sub(line,"]","");
- DEBUG(0,("despues 2 [%s]\n", line));
-
-
-
- for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
-
- /* we must get 7 tokens */
- if (count < 7)
- return(False);
-
- /* the 3rd and 5th columns must be integer */
- if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
+ /* also fetch the queue status */
+ memset(&status, 0, sizeof(status));
+ len = get_queue_status(snum, &status);
+ if (pstatus)
+ *pstatus = status;
+ return len;
+}
+
+/****************************************************************************
+ Determine the number of jobs in all queues.
+****************************************************************************/
+static int get_total_jobs(int snum)
+{
+ int total_jobs;
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum)) print_queue_update(snum);
+
+ total_jobs = tdb_fetch_int(tdb, "INFO/total_jobs");
+ if (total_jobs >0)
+ return total_jobs;
+ else
+ return 0;
+}
+
+/***************************************************************************
+start spooling a job - return the jobid
+***************************************************************************/
+int print_job_start(struct current_user *user, int snum, char *jobname)
+{
+ int jobid;
+ char *path;
+ struct printjob pjob;
+ int next_jobid;
+ user_struct *vuser;
+ int njobs = 0;
+
+ errno = 0;
+
+ if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
+ DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
+ return -1;
+ }
+
+ if (!print_time_access_check(snum)) {
+ DEBUG(3, ("print_job_start: job start denied by time check\n"));
+ return -1;
+ }
+
+ path = lp_pathname(snum);
+
+ /* see if we have sufficient disk space */
+ if (lp_minprintspace(snum)) {
+ SMB_BIG_UINT dspace, dsize;
+ if (sys_fsusage(path, &dspace, &dsize) == 0 &&
+ dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
+ DEBUG(3, ("print_job_start: disk space check failed.\n"));
+ errno = ENOSPC;
+ return -1;
+ }
+ }
+
+ /* for autoloaded printers, check that the printcap entry still exists */
+ if (lp_autoloaded(snum) && !pcap_printername_ok(lp_servicename(snum), NULL)) {
+ DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_servicename(snum) ));
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Insure the maximum queue size is not violated */
+ if (lp_maxprintjobs(snum) && (njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
+ DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per queue (%d).\n",
+ njobs, lp_maxprintjobs(snum) ));
+ errno = ENOSPC;
+ return -1;
+ }
+
+ /* Insure the maximum print jobs in the system is not violated */
+ if (lp_totalprintjobs() && get_total_jobs(snum) > lp_totalprintjobs()) {
+ DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per system (%d).\n",
+ njobs, lp_totalprintjobs() ));
+ errno = ENOSPC;
+ return -1;
+ }
+
+ /* create the database entry */
+ ZERO_STRUCT(pjob);
+ pjob.pid = local_pid;
+ pjob.sysjob = -1;
+ pjob.fd = -1;
+ pjob.starttime = time(NULL);
+ pjob.status = LPQ_SPOOLING;
+ pjob.size = 0;
+ pjob.spooled = False;
+ pjob.smbjob = True;
+
+ fstrcpy(pjob.jobname, jobname);
+
+ if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
+ fstrcpy(pjob.user, vuser->user.smb_name);
+ } else {
+ fstrcpy(pjob.user, uidtoname(user->uid));
+ }
+
+ fstrcpy(pjob.qname, lp_servicename(snum));
+
+ /* lock the database */
+ tdb_lock_bystring(tdb, "INFO/nextjob");
+
+ next_jobid = tdb_fetch_int(tdb, "INFO/nextjob");
+ if (next_jobid == -1)
+ next_jobid = 1;
+
+ for (jobid = NEXT_JOBID(next_jobid); jobid != next_jobid; jobid = NEXT_JOBID(jobid)) {
+ if (!print_job_exists(jobid))
+ break;
+ }
+ if (jobid == next_jobid || !print_job_store(jobid, &pjob)) {
+ DEBUG(3, ("print_job_start: either jobid (%d)==next_jobid(%d) or print_job_store failed.\n",
+ jobid, next_jobid ));
+ jobid = -1;
+ goto fail;
+ }
+
+ tdb_store_int(tdb, "INFO/nextjob", jobid);
+
+ /* we have a job entry - now create the spool file */
+ slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.6d.XXXXXX",
+ path, PRINT_SPOOL_PREFIX, jobid);
+ pjob.fd = smb_mkstemp(pjob.filename);
+
+ if (pjob.fd == -1) {
+ if (errno == EACCES) {
+ /* Common setup error, force a report. */
+ DEBUG(0, ("print_job_start: insufficient permissions \
+to open spool file %s.\n", pjob.filename));
+ } else {
+ /* Normal case, report at level 3 and above. */
+ DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
+ DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
+ }
+ goto fail;
+ }
+
+ print_job_store(jobid, &pjob);
+
+ tdb_unlock_bystring(tdb, "INFO/nextjob");
+
+ /*
+ * If the printer is marked as postscript output a leading
+ * file identifier to ensure the file is treated as a raw
+ * postscript file.
+ * This has a similar effect as CtrlD=0 in WIN.INI file.
+ * tim@fsg.com 09/06/94
+ */
+ if (lp_postscript(snum)) {
+ print_job_write(jobid, "%!\n",3);
+ }
- /* only take the last part of the filename */
- {
- string tmp;
- char *p = strrchr(tok[6],'/');
- if (p)
- {
- strcpy(tmp,p+1);
- strcpy(tok[6],tmp);
- }
- }
+ return jobid;
+
+ fail:
+ if (jobid != -1) {
+ tdb_delete(tdb, print_key(jobid));
+ }
+
+ tdb_unlock_bystring(tdb, "INFO/nextjob");
+
+ DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
+ return -1;
+}
+
+/****************************************************************************
+ Print a file - called on closing the file. This spools the job.
+ If normal close is false then we're tearing down the jobs - treat as an
+ error.
+****************************************************************************/
+
+BOOL print_job_end(int jobid, BOOL normal_close)
+{
+ struct printjob *pjob = print_job_find(jobid);
+ int snum, ret;
+ SMB_STRUCT_STAT sbuf;
+
+ if (!pjob)
+ return False;
+
+ if (pjob->spooled || pjob->pid != local_pid)
+ return False;
+
+ snum = print_job_snum(jobid);
+
+ if (normal_close && (sys_fstat(pjob->fd, &sbuf) == 0)) {
+ pjob->size = sbuf.st_size;
+ close(pjob->fd);
+ pjob->fd = -1;
+ } else {
+
+ /*
+ * Not a normal close or we couldn't stat the job file,
+ * so something has gone wrong. Cleanup.
+ */
+ close(pjob->fd);
+ pjob->fd = -1;
+ DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
+ goto fail;
+ }
+
+ /* Technically, this is not quit right. If the printer has a separator
+ * page turned on, the NT spooler prints the separator page even if the
+ * print job is 0 bytes. 010215 JRR */
+ if (pjob->size == 0 || pjob->status == LPQ_DELETING) {
+ /* don't bother spooling empty files or something being deleted. */
+ DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
+ pjob->filename, pjob->size ? "deleted" : "zero length" ));
+ unlink(pjob->filename);
+ tdb_delete(tdb, print_key(jobid));
+ return True;
+ }
+
+ ret = (*(current_printif->job_submit))(snum, pjob);
+
+ if (ret)
+ goto fail;
+
+ /* The print job has been sucessfully handed over to the back-end */
+
+ pjob->spooled = True;
+ pjob->status = LPQ_QUEUED;
+ print_job_store(jobid, pjob);
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum))
+ print_queue_update(snum);
+
+ return True;
+
+fail:
+
+ /* The print job was not succesfully started. Cleanup */
+ /* Still need to add proper error return propagation! 010122:JRR */
+ unlink(pjob->filename);
+ tdb_delete(tdb, print_key(jobid));
+ return False;
+}
+
+/* utility fn to enumerate the print queue */
+static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct traverse_struct *ts = (struct traverse_struct *)state;
+ struct printjob pjob;
+ int i, jobid;
+
+ if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
+ memcpy(&jobid, key.dptr, sizeof(jobid));
+ memcpy(&pjob, data.dptr, sizeof(pjob));
+
+ /* maybe it isn't for this queue */
+ if (ts->snum != print_queue_snum(pjob.qname)) return 0;
+
+ if (ts->qcount >= ts->maxcount) return 0;
+
+ i = ts->qcount;
+
+ ts->queue[i].job = jobid;
+ ts->queue[i].size = pjob.size;
+ ts->queue[i].status = pjob.status;
+ ts->queue[i].priority = 1;
+ ts->queue[i].time = pjob.starttime;
+ fstrcpy(ts->queue[i].user, pjob.user);
+ fstrcpy(ts->queue[i].file, pjob.jobname);
+
+ ts->qcount++;
+
+ return 0;
+}
+
+struct traverse_count_struct {
+ int snum, count;
+};
+
+/* utility fn to count the number of entries in the print queue */
+static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct traverse_count_struct *ts = (struct traverse_count_struct *)state;
+ struct printjob pjob;
+ int jobid;
+
+ if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
+ memcpy(&jobid, key.dptr, sizeof(jobid));
+ memcpy(&pjob, data.dptr, sizeof(pjob));
+
+ /* maybe it isn't for this queue */
+ if (ts->snum != print_queue_snum(pjob.qname)) return 0;
+
+ ts->count++;
+
+ return 0;
+}
+
+/* Sort print jobs by submittal time */
+
+static int printjob_comp(print_queue_struct *j1, print_queue_struct *j2)
+{
+ /* Silly cases */
+
+ if (!j1 && !j2) return 0;
+ if (!j1) return -1;
+ if (!j2) return 1;
+
+ /* Sort on job start time */
+
+ if (j1->time == j2->time) return 0;
+ return (j1->time > j2->time) ? 1 : -1;
+}
+
+/****************************************************************************
+get a printer queue listing
+****************************************************************************/
+int print_queue_status(int snum,
+ print_queue_struct **queue,
+ print_status_struct *status)
+{
+ struct traverse_struct tstruct;
+ struct traverse_count_struct tsc;
+ fstring keystr;
+ TDB_DATA data, key;
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum)) print_queue_update(snum);
+
+ *queue = NULL;
+
+ /*
+ * Fetch the queue status. We must do this first, as there may
+ * be no jobs in the queue.
+ */
+ ZERO_STRUCTP(status);
+ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum));
+ key.dptr = keystr;
+ key.dsize = strlen(keystr);
+ data = tdb_fetch(tdb, key);
+ if (data.dptr) {
+ if (data.dsize == sizeof(*status)) {
+ memcpy(status, data.dptr, sizeof(*status));
+ }
+ free(data.dptr);
+ }
+
+ /*
+ * Now, fetch the print queue information. We first count the number
+ * of entries, and then only retrieve the queue if necessary.
+ */
+ tsc.count = 0;
+ tsc.snum = snum;
+ tdb_traverse(tdb, traverse_count_fn_queue, (void *)&tsc);
+
+ if (tsc.count == 0)
+ return 0;
+
+ /* Allocate the queue size. */
+ if ((tstruct.queue = (print_queue_struct *)
+ malloc(sizeof(print_queue_struct)*tsc.count))
+ == NULL)
+ return 0;
+
+ /*
+ * Fill in the queue.
+ * We need maxcount as the queue size may have changed between
+ * the two calls to tdb_traverse.
+ */
+ tstruct.qcount = 0;
+ tstruct.maxcount = tsc.count;
+ tstruct.snum = snum;
+
+ tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct);
+
+ /* Sort the queue by submission time otherwise they are displayed
+ in hash order. */
+
+ qsort(tstruct.queue, tstruct.qcount, sizeof(print_queue_struct),
+ QSORT_CAST(printjob_comp));
+
+ *queue = tstruct.queue;
+ return tstruct.qcount;
+}
- buf->job = atoi(tok[2]);
- buf->size = atoi(tok[4]);
- buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
- buf->priority = 0;
- buf->time = time(NULL);
- StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
- return(True);
-}
-
-
-
-char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
-char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
-char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
-
-/****************************************************************************
-parse a lpq line. Choose printing style
-****************************************************************************/
-static BOOL parse_lpq_entry(int snum,char *line,
- print_queue_struct *buf,
- print_status_struct *status,BOOL first)
-{
- BOOL ret;
-
- switch (lp_printing())
- {
- case PRINT_SYSV:
- ret = parse_lpq_sysv(line,buf,first);
- break;
- case PRINT_AIX:
- ret = parse_lpq_aix(line,buf,first);
- break;
- case PRINT_HPUX:
- ret = parse_lpq_hpux(line,buf,first);
- break;
- case PRINT_QNX:
- ret = parse_lpq_qnx(line,buf,first);
- break;
- default:
- ret = parse_lpq_bsd(line,buf,first);
- break;
- }
-
-#ifdef LPQ_GUEST_TO_USER
- if (ret) {
- extern pstring sesssetup_user;
- /* change guest entries to the current logged in user to make
- them appear deletable to windows */
- if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
- strcpy(buf->user,sesssetup_user);
- }
-#endif
-
- if (status && !ret)
- {
- /* a few simple checks to see if the line might be a
- printer status line:
- handle them so that most severe condition is shown */
- int i;
- strlower(line);
-
- switch (status->status) {
- case LPSTAT_OK:
- for (i=0; stat0_strings[i]; i++)
- if (strstr(line,stat0_strings[i])) {
- StrnCpy(status->message,line,sizeof(status->message)-1);
- status->status=LPSTAT_OK;
- }
- case LPSTAT_STOPPED:
- for (i=0; stat1_strings[i]; i++)
- if (strstr(line,stat1_strings[i])) {
- StrnCpy(status->message,line,sizeof(status->message)-1);
- status->status=LPSTAT_STOPPED;
- }
- case LPSTAT_ERROR:
- for (i=0; stat2_strings[i]; i++)
- if (strstr(line,stat2_strings[i])) {
- StrnCpy(status->message,line,sizeof(status->message)-1);
- status->status=LPSTAT_ERROR;
- }
- break;
- }
- }
-
- return(ret);
-}
-
-/****************************************************************************
-get a printer queue
-****************************************************************************/
-int get_printqueue(int snum,int cnum,print_queue_struct **queue,
- print_status_struct *status)
-{
- char *lpq_command = lp_lpqcommand(snum);
- char *printername = PRINTERNAME(snum);
- int ret=0,count=0;
- pstring syscmd;
- fstring outfile;
- pstring line;
- FILE *f;
- struct stat sbuf;
- BOOL dorun=True;
- int cachetime = lp_lpqcachetime();
- int lfd = -1;
-
- *line = 0;
- check_lpq_cache(snum);
-
- if (!printername || !*printername)
- {
- DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
- lp_servicename(snum),snum));
- printername = lp_servicename(snum);
- }
-
- if (!lpq_command || !(*lpq_command))
- {
- DEBUG(5,("No lpq command\n"));
- return(0);
- }
-
- strcpy(syscmd,lpq_command);
- string_sub(syscmd,"%p",printername);
-
- standard_sub(cnum,syscmd);
-
- sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
-
- if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
- {
- if (time(NULL) - sbuf.st_mtime < cachetime) {
- DEBUG(3,("Using cached lpq output\n"));
- dorun = False;
- }
-
- if (dorun) {
- lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
- if (lfd<0 ||
- (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
- DEBUG(3,("Using cached lpq output\n"));
- dorun = False;
- file_unlock(lfd); lfd = -1;
- }
- }
- }
-
- if (dorun) {
- ret = smbrun(syscmd,outfile);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
- }
-
- lpq_cache_reset[snum] = False;
-
- f = fopen(outfile,"r");
- if (!f) {
- if (lfd >= 0) file_unlock(lfd);
- return(0);
- }
-
- if (status) {
- strcpy(status->message,"");
- status->status = LPSTAT_OK;
- }
-
- while (fgets(line,sizeof(pstring),f))
- {
- DEBUG(6,("QUEUE2: %s\n",line));
-
- *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
- if (! *queue)
- {
- count = 0;
- break;
- }
-
- bzero((char *)&(*queue)[count],sizeof(**queue));
-
- /* parse it */
- if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
- continue;
-
- count++;
- }
-
- fclose(f);
-
- if (lfd >= 0) file_unlock(lfd);
-
- if (!cachetime)
- unlink(outfile);
- else
- chmod(outfile,0666);
- return(count);
-}
-
-
-/****************************************************************************
-delete a printer queue entry
-****************************************************************************/
-void del_printqueue(int cnum,int snum,int jobid)
-{
- char *lprm_command = lp_lprmcommand(snum);
- char *printername = PRINTERNAME(snum);
- pstring syscmd;
- char jobstr[20];
- int ret;
-
- if (!printername || !*printername)
- {
- DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
- lp_servicename(snum),snum));
- printername = lp_servicename(snum);
- }
-
- if (!lprm_command || !(*lprm_command))
- {
- DEBUG(5,("No lprm command\n"));
- return;
- }
-
- sprintf(jobstr,"%d",jobid);
-
- strcpy(syscmd,lprm_command);
- string_sub(syscmd,"%p",printername);
- string_sub(syscmd,"%j",jobstr);
- standard_sub(cnum,syscmd);
-
- ret = smbrun(syscmd,NULL);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
- lpq_reset(snum); /* queue has changed */
-}
-
-/****************************************************************************
-change status of a printer queue entry
-****************************************************************************/
-void status_printjob(int cnum,int snum,int jobid,int status)
-{
- char *lpstatus_command =
- (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
- char *printername = PRINTERNAME(snum);
- pstring syscmd;
- char jobstr[20];
- int ret;
-
- if (!printername || !*printername)
- {
- DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
- lp_servicename(snum),snum));
- printername = lp_servicename(snum);
- }
-
- if (!lpstatus_command || !(*lpstatus_command))
- {
- DEBUG(5,("No lpstatus command to %s job\n",
- (status==LPQ_PAUSED?"pause":"resume")));
- return;
- }
-
- sprintf(jobstr,"%d",jobid);
-
- strcpy(syscmd,lpstatus_command);
- string_sub(syscmd,"%p",printername);
- string_sub(syscmd,"%j",jobstr);
- standard_sub(cnum,syscmd);
- ret = smbrun(syscmd,NULL);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
- lpq_reset(snum); /* queue has changed */
+/****************************************************************************
+turn a queue name into a snum
+****************************************************************************/
+int print_queue_snum(char *qname)
+{
+ int snum = lp_servicenumber(qname);
+ if (snum == -1 || !lp_print_ok(snum)) return -1;
+ return snum;
}
+/****************************************************************************
+ pause a queue
+****************************************************************************/
+BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
+{
+ char *printer_name;
+ int ret;
+
+ if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ ret = (*(current_printif->queue_pause))(snum);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* force update the database */
+ print_cache_flush(snum);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ return True;
+}
+
+/****************************************************************************
+ resume a queue
+****************************************************************************/
+BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
+{
+ char *printer_name;
+ int ret;
+
+ if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ *errcode = WERR_ACCESS_DENIED;
+ return False;
+ }
+
+ ret = (*(current_printif->queue_resume))(snum);
+
+ if (ret != 0) {
+ *errcode = WERR_INVALID_PARAM;
+ return False;
+ }
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum)) print_queue_update(snum);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ return True;
+}
+
+/****************************************************************************
+ purge a queue - implemented by deleting all jobs that we can delete
+****************************************************************************/
+BOOL print_queue_purge(struct current_user *user, int snum, WERROR *errcode)
+{
+ print_queue_struct *queue;
+ print_status_struct status;
+ char *printer_name;
+ int njobs, i;
+ BOOL can_job_admin;
+
+ /* Force and update so the count is accurate (i.e. not a cached count) */
+ print_queue_update(snum);
+
+ can_job_admin = print_access_check(user, snum, JOB_ACCESS_ADMINISTER);
+ njobs = print_queue_status(snum, &queue, &status);
+
+ for (i=0;i<njobs;i++) {
+ BOOL owner = is_owner(user, queue[i].job);
+
+ if (owner || can_job_admin) {
+ print_job_delete1(queue[i].job);
+ }
+ }
+
+ safe_free(queue);
+
+ /* Send a printer notify message */
+
+ printer_name = PRINTERNAME(snum);
+
+ message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
+
+ return True;
+}
diff --git a/source/profile/profile.c b/source/profile/profile.c
new file mode 100644
index 00000000000..555fe7de5a4
--- /dev/null
+++ b/source/profile/profile.c
@@ -0,0 +1,157 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ store smbd profiling information in shared memory
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
+
+static int shm_id;
+static BOOL read_only;
+
+struct profile_header *profile_h;
+struct profile_stats *profile_p;
+
+BOOL do_profile_flag = False;
+BOOL do_profile_times = False;
+
+struct timeval profile_starttime;
+struct timeval profile_endtime;
+struct timeval profile_starttime_nested;
+struct timeval profile_endtime_nested;
+
+/****************************************************************************
+receive a set profile level message
+****************************************************************************/
+void profile_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ int level;
+
+ memcpy(&level, buf, sizeof(int));
+ switch (level) {
+ case 0: /* turn off profiling */
+ do_profile_flag = False;
+ do_profile_times = False;
+ DEBUG(1,("INFO: Profiling turned OFF from pid %d\n", (int)src));
+ break;
+ case 1: /* turn on counter profiling only */
+ do_profile_flag = True;
+ do_profile_times = False;
+ DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n", (int)src));
+ break;
+ case 2: /* turn on complete profiling */
+ do_profile_flag = True;
+ do_profile_times = True;
+ DEBUG(1,("INFO: Full profiling turned ON from pid %d\n", (int)src));
+ break;
+ case 3: /* reset profile values */
+ memset((char *)profile_p, 0, sizeof(*profile_p));
+ DEBUG(1,("INFO: Profiling values cleared from pid %d\n", (int)src));
+ break;
+ }
+}
+
+/****************************************************************************
+receive a request profile level message
+****************************************************************************/
+void reqprofile_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ int level;
+
+#ifdef WITH_PROFILE
+ level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0);
+#else
+ level = 0;
+#endif
+ DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",(unsigned int)src));
+ message_send_pid(src, MSG_PROFILELEVEL, &level, sizeof(int), True);
+}
+
+/*******************************************************************
+ open the profiling shared memory area
+ ******************************************************************/
+BOOL profile_setup(BOOL rdonly)
+{
+ struct shmid_ds shm_ds;
+
+ read_only = rdonly;
+
+ again:
+ /* try to use an existing key */
+ shm_id = shmget(PROF_SHMEM_KEY, 0, 0);
+
+ /* if that failed then create one. There is a race condition here
+ if we are running from inetd. Bad luck. */
+ if (shm_id == -1) {
+ if (read_only) return False;
+ shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h),
+ IPC_CREAT | IPC_EXCL | IPC_PERMS);
+ }
+
+ if (shm_id == -1) {
+ DEBUG(0,("Can't create or use IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+
+ profile_h = (struct profile_header *)shmat(shm_id, 0,
+ read_only?SHM_RDONLY:0);
+ if ((long)profile_p == -1) {
+ DEBUG(0,("Can't attach to IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ /* find out who created this memory area */
+ if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
+ DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if (shm_ds.shm_perm.cuid != sec_initial_uid() || shm_ds.shm_perm.cgid != sec_initial_gid()) {
+ DEBUG(0,("ERROR: we did not create the shmem (owned by another user)\n"));
+ return False;
+ }
+
+ if (shm_ds.shm_segsz != sizeof(*profile_h)) {
+ DEBUG(0,("WARNING: profile size is %d (expected %d). Deleting\n",
+ (int)shm_ds.shm_segsz, sizeof(*profile_h)));
+ if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) {
+ goto again;
+ } else {
+ return False;
+ }
+ }
+
+ if (!read_only && (shm_ds.shm_nattch == 1)) {
+ memset((char *)profile_h, 0, sizeof(*profile_h));
+ profile_h->prof_shm_magic = PROF_SHM_MAGIC;
+ profile_h->prof_shm_version = PROF_SHM_VERSION;
+ DEBUG(3,("Initialised profile area\n"));
+ }
+
+ profile_p = &profile_h->stats;
+ message_register(MSG_PROFILE, profile_message);
+ message_register(MSG_REQ_PROFILELEVEL, reqprofile_message);
+ return True;
+}
diff --git a/source/rpc_client/cli_login.c b/source/rpc_client/cli_login.c
new file mode 100644
index 00000000000..be32533541c
--- /dev/null
+++ b/source/rpc_client/cli_login.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+
+/****************************************************************************
+Initialize domain session credentials.
+****************************************************************************/
+
+NTSTATUS cli_nt_setup_creds(struct cli_state *cli, unsigned char mach_pwd[16])
+{
+ NTSTATUS result;
+ DOM_CHAL clnt_chal;
+ DOM_CHAL srv_chal;
+
+ UTIME zerotime;
+
+ /******************* Request Challenge ********************/
+
+ generate_random_buffer( clnt_chal.data, 8, False);
+
+ /* send a client challenge; receive a server challenge */
+ if (!cli_net_req_chal(cli, &clnt_chal, &srv_chal))
+ {
+ DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /**************** Long-term Session key **************/
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, cli->sess_key);
+ memset((char *)cli->sess_key+8, '\0', 8);
+
+ /******************* Authenticate 2 ********************/
+
+ /* calculate auth-2 credentials */
+ zerotime.time = 0;
+ cred_create(cli->sess_key, &clnt_chal, zerotime, &(cli->clnt_cred.challenge));
+
+ /*
+ * Send client auth-2 challenge.
+ * Receive an auth-2 challenge response and check it.
+ */
+
+ result = cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+ SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff, &srv_chal);
+
+ if (!NT_STATUS_IS_OK(result))
+ {
+ DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed\n"));
+ return result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+NT login - interactive.
+*NEVER* use this code. This method of doing a logon (sending the cleartext
+password equivalents, protected by the session key) is inherently insecure
+given the current design of the NT Domain system. JRA.
+ ****************************************************************************/
+NTSTATUS cli_nt_login_interactive(struct cli_state *cli, char *domain, char *username,
+ uint32 smb_userid_low, char *password,
+ NET_ID_INFO_CTR *ctr, NET_USER_INFO_3 *user_info3)
+{
+ uchar lm_owf_user_pwd[16];
+ uchar nt_owf_user_pwd[16];
+ NTSTATUS ret;
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+ nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
+
+#ifdef DEBUG_PASSWORD
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, (char *)lm_owf_user_pwd, 16);
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, (char *)nt_owf_user_pwd, 16);
+
+#endif
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+ /* indicate an "interactive" login */
+ ctr->switch_value = INTERACTIVE_LOGON_TYPE;
+
+ /* Create the structure needed for SAM logon. */
+ init_id_info1(&ctr->auth.id1, domain, 0,
+ smb_userid_low, 0,
+ username, cli->clnt_name_slash,
+ (char *)cli->sess_key, lm_owf_user_pwd, nt_owf_user_pwd);
+
+ /* Ensure we overwrite all the plaintext password
+ equivalents. */
+ memset(lm_owf_user_pwd, '\0', sizeof(lm_owf_user_pwd));
+ memset(nt_owf_user_pwd, '\0', sizeof(nt_owf_user_pwd));
+
+ /* Send client sam-logon request - update credentials on success. */
+ ret = cli_net_sam_logon(cli, ctr, user_info3);
+
+ memset(ctr->auth.id1.lm_owf.data, '\0', sizeof(lm_owf_user_pwd));
+ memset(ctr->auth.id1.nt_owf.data, '\0', sizeof(nt_owf_user_pwd));
+
+ return ret;
+}
+
+/****************************************************************************
+NT login - network.
+*ALWAYS* use this call to validate a user as it does not expose plaintext
+password equivalents over the network. JRA.
+****************************************************************************/
+
+NTSTATUS cli_nt_login_network(struct cli_state *cli,
+ const auth_usersupplied_info *user_info,
+ uchar chal[8],
+ uint32 smb_userid_low, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
+{
+ DEBUG(5,("cli_nt_login_network: %d\n", __LINE__));
+ /* indicate a "network" login */
+ ctr->switch_value = NET_LOGON_TYPE;
+
+ /* Create the structure needed for SAM logon. */
+ init_id_info2(&ctr->auth.id2, user_info->domain.str, 0, smb_userid_low, 0,
+ user_info->smb_name.str,
+ /* Send our cleint's workstaion name if we have it, otherwise ours */
+ ((user_info->wksta_name.len > 0) ?
+ user_info->wksta_name.str :
+ cli->clnt_name_slash),
+ chal,
+ user_info->lm_resp.data, user_info->lm_resp.length,
+ user_info->nt_resp.data, user_info->nt_resp.length);
+
+ /* Send client sam-logon request - update credentials on success. */
+ return cli_net_sam_logon(cli, ctr, user_info3);
+}
+
+/****************************************************************************
+NT Logoff.
+****************************************************************************/
+BOOL cli_nt_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
+{
+ DEBUG(5,("cli_nt_logoff: %d\n", __LINE__));
+
+ /* Send client sam-logoff request - update credentials on success. */
+ return cli_net_sam_logoff(cli, ctr);
+}
diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c
new file mode 100644
index 00000000000..8a2d8e28cc1
--- /dev/null
+++ b/source/rpc_client/cli_netlogon.c
@@ -0,0 +1,471 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/****************************************************************************
+Generate the next creds to use.
+****************************************************************************/
+
+static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
+{
+ /*
+ * Create the new client credentials.
+ */
+
+ cli->clnt_cred.timestamp.time = time(NULL);
+
+ memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
+
+ /* Calculate the new credentials. */
+ cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
+ new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
+
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+do a LSA Logon Control2
+****************************************************************************/
+BOOL cli_net_logon_ctrl2(struct cli_state *cli, NTSTATUS status_level)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_LOGON_CTRL2 q_l;
+ BOOL ok = False;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
+
+ DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
+ global_myname, status_level));
+
+ /* store the parameters */
+ init_q_logon_ctrl2(&q_l, cli->srv_name_slash,
+ status_level);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_logon_ctrl2("", &q_l, &buf, 0)) {
+ DEBUG(0,("cli_net_logon_ctrl2: Error : failed to marshall NET_Q_LOGON_CTRL2 struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
+ {
+ NET_R_LOGON_CTRL2 r_l;
+
+ /*
+ * Unmarshall the return buffer.
+ */
+ ok = net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
+
+ if (ok && r_l.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("do_net_logon_ctrl2: Error %s\n", get_nt_error_msg(r_l.status)));
+ cli->nt_error = r_l.status;
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return ok;
+}
+#endif
+
+/****************************************************************************
+LSA Authenticate 2
+
+Send the client credential, receive back a server credential.
+Ensure that the server credential returned matches the session key
+encrypt of the server challenge originally received. JRA.
+****************************************************************************/
+
+NTSTATUS cli_net_auth2(struct cli_state *cli, uint16 sec_chan,
+ uint32 neg_flags, DOM_CHAL *srv_chal)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_AUTH_2 q_a;
+ BOOL ok = False;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_AUTH2 */
+
+ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
+ credstr(cli->clnt_cred.challenge.data), neg_flags));
+
+ /* store the parameters */
+ init_q_auth_2(&q_a, cli->srv_name_slash, cli->mach_acct,
+ sec_chan, global_myname, &cli->clnt_cred.challenge, neg_flags);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_auth_2("", &q_a, &buf, 0)) {
+ DEBUG(0,("cli_net_auth2: Error : failed to marshall NET_Q_AUTH_2 struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return result;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
+ {
+ NET_R_AUTH_2 r_a;
+
+ ok = net_io_r_auth_2("", &r_a, &rbuf, 0);
+ result = r_a.status;
+
+ if (ok && !NT_STATUS_IS_OK(result))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_auth2: Error %s\n", get_nt_error_msg(result)));
+ ok = False;
+ }
+
+ if (ok)
+ {
+ /*
+ * Check the returned value using the initial
+ * server received challenge.
+ */
+ UTIME zerotime;
+
+ zerotime.time = 0;
+ if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ ok = False;
+ }
+ }
+
+#if 0
+ /*
+ * Try commenting this out to see if this makes the connect
+ * work for a NT 3.51 PDC. JRA.
+ */
+
+ if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
+ {
+ /* report different neg_flags */
+ DEBUG(0,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
+ q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
+ ok = False;
+ }
+#endif
+
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+LSA Request Challenge. Sends our challenge to server, then gets
+server response. These are used to generate the credentials.
+****************************************************************************/
+
+BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_REQ_CHAL q_c;
+ BOOL valid_chal = False;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_REQCHAL */
+
+ DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
+ cli->desthost, global_myname, credstr(clnt_chal->data)));
+
+ /* store the parameters */
+ init_q_req_chal(&q_c, cli->srv_name_slash,
+ global_myname, clnt_chal);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_req_chal("", &q_c, &buf, 0)) {
+ DEBUG(0,("cli_net_req_chal: Error : failed to marshall NET_Q_REQ_CHAL struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
+ {
+ NET_R_REQ_CHAL r_c;
+ BOOL ok;
+
+ ok = net_io_r_req_chal("", &r_c, &rbuf, 0);
+
+ if (ok && !NT_STATUS_IS_OK(r_c.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
+ ok = False;
+ }
+
+ if (ok)
+ {
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
+ valid_chal = True;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return valid_chal;
+}
+/***************************************************************************
+ LSA SAM Logon internal - interactive or network. Does level 2 or 3 but always
+ returns level 3.
+****************************************************************************/
+
+static NTSTATUS cli_net_sam_logon_internal(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3,
+ uint16 validation_level)
+{
+ DOM_CRED new_clnt_cred;
+ DOM_CRED dummy_rtn_creds;
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_SAM_LOGON q_s;
+ NET_R_SAM_LOGON r_s;
+ NTSTATUS retval = NT_STATUS_OK;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SAMLOGON */
+
+ DEBUG(4,("cli_net_sam_logon_internal: srv:%s mc:%s clnt %s %x ll: %d\n",
+ cli->srv_name_slash, global_myname,
+ credstr(new_clnt_cred.challenge.data), cli->clnt_cred.timestamp.time,
+ ctr->switch_value));
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+ dummy_rtn_creds.timestamp.time = time(NULL);
+
+ /* store the parameters */
+ q_s.validation_level = validation_level;
+ init_sam_info(&q_s.sam_id, cli->srv_name_slash,
+ global_myname, &new_clnt_cred, &dummy_rtn_creds,
+ ctr->switch_value, ctr);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_sam_logon("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error : failed to marshall NET_Q_SAM_LOGON struct.\n"));
+ retval = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error rpc_api_pipe_req failed.\n"));
+ retval = NT_STATUS_UNSUCCESSFUL;
+ goto out;
+ }
+
+ r_s.user = user_info3;
+
+ if(!net_io_r_sam_logon("", &r_s, &rbuf, 0)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error : failed to unmarshal NET_R_SAM_LOGON struct.\n"));
+ retval = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ retval = r_s.status;
+
+ /*
+ * Don't treat NT_STATUS_INVALID_INFO_CLASS as an error - we will re-issue
+ * the call.
+ */
+
+ if (NT_STATUS_V(retval) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ goto out;
+ }
+
+ if (!NT_STATUS_IS_OK(retval)) {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logon_internal: %s\n", get_nt_error_msg(r_s.status)));
+ goto out;
+ }
+
+ /* Update the credentials. */
+ if (!clnt_deal_with_creds(cli->sess_key, &cli->clnt_cred, &r_s.srv_creds)) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_sam_logon_internal: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ retval = NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (r_s.switch_value != validation_level) {
+ /* report different switch_value */
+ DEBUG(0,("cli_net_sam_logon: switch_value of %x expected %x\n", (unsigned int)validation_level,
+ (unsigned int)r_s.switch_value));
+ retval = NT_STATUS_INVALID_PARAMETER;
+ }
+
+out:
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return retval;
+}
+
+/***************************************************************************
+LSA SAM Logon - interactive or network.
+****************************************************************************/
+
+NTSTATUS cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
+{
+ uint16 validation_level=3;
+ NTSTATUS result;
+
+ result = cli_net_sam_logon_internal(cli, ctr, user_info3,
+ validation_level);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cli_net_sam_logon: Success \n"));
+ } else if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ DEBUG(10,("cli_net_sam_logon: STATUS INVALID INFO CLASS \n"));
+
+ validation_level=2;
+
+ /*
+ * Since this is the second time we call this function, don't care
+ * for the error. If its error, return False.
+ */
+
+ result = cli_net_sam_logon_internal(cli, ctr, user_info3,
+ validation_level);
+ }
+
+ return result;
+}
+
+/***************************************************************************
+LSA SAM Logoff.
+
+This currently doesnt work correctly as the domain controller
+returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
+send a different info level. Right now though, I'm not sure
+what that needs to be (I need to see one on the wire before
+I can be sure). JRA.
+****************************************************************************/
+BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
+{
+ DOM_CRED new_clnt_cred;
+ DOM_CRED dummy_rtn_creds;
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_SAM_LOGOFF q_s;
+ BOOL ok = False;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SAMLOGOFF */
+
+ DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
+ cli->srv_name_slash, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
+ ctr->switch_value));
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+
+ init_sam_info(&q_s.sam_id, cli->srv_name_slash,
+ global_myname, &new_clnt_cred, &dummy_rtn_creds,
+ ctr->switch_value, ctr);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_sam_logoff("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_net_sam_logoff: Error : failed to marshall NET_Q_SAM_LOGOFF struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
+ {
+ NET_R_SAM_LOGOFF r_s;
+
+ ok = net_io_r_sam_logoff("", &r_s, &rbuf, 0);
+
+ if (ok && !NT_STATUS_IS_OK(r_s.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
+ ok = False;
+ }
+
+ /* Update the credentials. */
+ if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
+ {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return ok;
+}
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
new file mode 100644
index 00000000000..6eaab39bcc7
--- /dev/null
+++ b/source/rpc_client/cli_pipe.c
@@ -0,0 +1,1260 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1998.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern struct pipe_id_info pipe_names[];
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+
+/********************************************************************
+ Rpc pipe call id.
+ ********************************************************************/
+
+static uint32 get_rpc_call_id(void)
+{
+ static uint32 call_id = 0;
+ return ++call_id;
+}
+
+/*******************************************************************
+ Use SMBreadX to get rest of one fragment's worth of rpc data.
+ ********************************************************************/
+
+static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
+{
+ size_t size = (size_t)cli->max_recv_frag;
+ int stream_offset = 0;
+ int num_read;
+ char *pdata;
+ int extra_data_size = ((int)*rdata_offset) + ((int)data_to_read) - (int)prs_data_size(rdata);
+
+ DEBUG(5,("rpc_read: data_to_read: %u rdata offset: %u extra_data_size: %d\n",
+ (int)data_to_read, (unsigned int)*rdata_offset, extra_data_size));
+
+ /*
+ * Grow the buffer if needed to accommodate the data to be read.
+ */
+
+ if (extra_data_size > 0) {
+ if(!prs_force_grow(rdata, (uint32)extra_data_size)) {
+ DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", extra_data_size ));
+ return False;
+ }
+ DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", extra_data_size, prs_data_size(rdata) ));
+ }
+
+ pdata = prs_data_p(rdata) + *rdata_offset;
+
+ do /* read data using SMBreadX */
+ {
+ uint32 ecode;
+ uint8 eclass;
+
+ if (size > (size_t)data_to_read)
+ size = (size_t)data_to_read;
+
+ num_read = (int)cli_read(cli, cli->nt_pipe_fnum, pdata, (off_t)stream_offset, size);
+
+ DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
+ num_read, stream_offset, data_to_read));
+
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRDOS && ecode != ERRmoredata) {
+ DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
+ eclass, (unsigned int)ecode));
+ return False;
+ }
+ }
+
+ data_to_read -= num_read;
+ stream_offset += num_read;
+ pdata += num_read;
+
+ } while (num_read > 0 && data_to_read > 0);
+ /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
+
+ /*
+ * Update the current offset into rdata by the amount read.
+ */
+ *rdata_offset += stream_offset;
+
+ return True;
+}
+
+/****************************************************************************
+ Checks the header. This will set the endian bit in the rdata prs_struct. JRA.
+ ****************************************************************************/
+
+static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
+ BOOL *first, BOOL *last, uint32 *len)
+{
+ DEBUG(5,("rpc_check_hdr: rdata->data_size = %u\n", (uint32)prs_data_size(rdata) ));
+
+ /* Next call sets endian bit. */
+
+ if(!smb_io_rpc_hdr("rpc_hdr ", rhdr, rdata, 0)) {
+ DEBUG(0,("rpc_check_hdr: Failed to unmarshall RPC_HDR.\n"));
+ return False;
+ }
+
+ if (prs_offset(rdata) != RPC_HEADER_LEN) {
+ DEBUG(0,("rpc_check_hdr: offset was %x, should be %x.\n", prs_offset(rdata), RPC_HEADER_LEN));
+ return False;
+ }
+
+ (*first) = ((rhdr->flags & RPC_FLG_FIRST) != 0);
+ (*last) = ((rhdr->flags & RPC_FLG_LAST ) != 0);
+ (*len) = (uint32)rhdr->frag_len - prs_data_size(rdata);
+
+ return (rhdr->pkt_type != RPC_FAULT);
+}
+
+static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, uint32 len)
+{
+ unsigned char *hash = cli->ntlmssp_hash;
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ int ind;
+
+ for( ind = 0; ind < len; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = data[ind] ^ hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/****************************************************************************
+ Verify data on an rpc pipe.
+ The VERIFY & SEAL code is only executed on packets that look like this :
+
+ Request/Response PDU's look like the following...
+
+ |<------------------PDU len----------------------------------------------->|
+ |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
+
+ +------------+-----------------+-------------+---------------+-------------+
+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
+ +------------+-----------------+-------------+---------------+-------------+
+
+ Never on bind requests/responses.
+ ****************************************************************************/
+
+static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int auth_len)
+{
+ /*
+ * The following is that length of the data we must sign or seal.
+ * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
+ * preceeding the auth_data.
+ */
+
+ int data_len = len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len;
+
+ /*
+ * The start of the data to sign/seal is just after the RPC headers.
+ */
+ char *reply_data = prs_data_p(rdata) + RPC_HEADER_LEN + RPC_HDR_REQ_LEN;
+
+ BOOL auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ BOOL auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+
+ DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s\n",
+ len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal)));
+
+ /*
+ * Unseal any sealed data in the PDU, not including the
+ * 8 byte auth_header or the auth_data.
+ */
+
+ if (auth_seal) {
+ DEBUG(10,("rpc_auth_pipe: unseal\n"));
+ dump_data(100, reply_data, data_len);
+ NTLMSSPcalc_ap(cli, (uchar*)reply_data, data_len);
+ dump_data(100, reply_data, data_len);
+ }
+
+ if (auth_verify || auth_seal) {
+ RPC_HDR_AUTH rhdr_auth;
+ prs_struct auth_req;
+ char data[RPC_HDR_AUTH_LEN];
+ /*
+ * We set dp to be the end of the packet, minus the auth_len
+ * and the length of the header that preceeds the auth_data.
+ */
+ char *dp = prs_data_p(rdata) + len - auth_len - RPC_HDR_AUTH_LEN;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ memcpy(data, dp, sizeof(data));
+
+ prs_init(&auth_req , 0, cli->mem_ctx, UNMARSHALL);
+
+ /* The endianness must be preserved... JRA. */
+
+ prs_set_endian_data(&auth_req, rdata->bigendian_data);
+
+ prs_give_memory(&auth_req, data, RPC_HDR_AUTH_LEN, False);
+
+ /*
+ * Unmarshall the 8 byte auth_header that comes before the
+ * auth data.
+ */
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &auth_req, 0)) {
+ DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_HDR_AUTH failed.\n"));
+ return False;
+ }
+
+ if (!rpc_hdr_auth_chk(&rhdr_auth)) {
+ DEBUG(0,("rpc_auth_pipe: rpc_hdr_auth_chk failed.\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Now unseal and check the auth verifier in the auth_data at
+ * then end of the packet. The 4 bytes skipped in the unseal
+ * seem to be a buffer pointer preceeding the sealed data.
+ */
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK chk;
+ uint32 crc32;
+ prs_struct auth_verf;
+ char data[RPC_AUTH_NTLMSSP_CHK_LEN];
+ char *dp = prs_data_p(rdata) + len - auth_len;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ DEBUG(10,("rpc_auth_pipe: verify\n"));
+ dump_data(100, dp, auth_len);
+ NTLMSSPcalc_ap(cli, (uchar*)(dp+4), auth_len - 4);
+
+ memcpy(data, dp, RPC_AUTH_NTLMSSP_CHK_LEN);
+ dump_data(100, data, auth_len);
+
+ prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* The endinness must be preserved. JRA. */
+ prs_set_endian_data( &auth_verf, rdata->bigendian_data);
+
+ prs_give_memory(&auth_verf, data, RPC_AUTH_NTLMSSP_CHK_LEN, False);
+
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0)) {
+ DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_AUTH_NTLMSSP_CHK failed.\n"));
+ return False;
+ }
+
+ crc32 = crc32_calc_buffer(reply_data, data_len);
+
+ if (!rpc_auth_ntlmssp_chk(&chk, crc32 , cli->ntlmssp_seq_num)) {
+ DEBUG(0,("rpc_auth_pipe: rpc_auth_ntlmssp_chk failed.\n"));
+ return False;
+ }
+ cli->ntlmssp_seq_num++;
+ }
+ return True;
+}
+
+
+/****************************************************************************
+ Send data on an rpc pipe, which *must* be in one fragment.
+ receive response data from an rpc pipe, which may be large...
+
+ Read the first fragment: unfortunately have to use SMBtrans for the first
+ bit, then SMBreadX for subsequent bits.
+
+ If first fragment received also wasn't the last fragment, continue
+ getting fragments until we _do_ receive the last fragment.
+
+ Request/Response PDU's look like the following...
+
+ |<------------------PDU len----------------------------------------------->|
+ |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
+
+ +------------+-----------------+-------------+---------------+-------------+
+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
+ +------------+-----------------+-------------+---------------+-------------+
+
+ Where the presence of the AUTH_HDR and AUTH are dependent on the
+ signing & sealing being neogitated.
+
+ ****************************************************************************/
+
+static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, prs_struct *rdata)
+{
+ uint32 len;
+ char *rparam = NULL;
+ uint32 rparam_len = 0;
+ uint16 setup[2];
+ BOOL first = True;
+ BOOL last = True;
+ RPC_HDR rhdr;
+ char *pdata = data ? prs_data_p(data) : NULL;
+ uint32 data_len = data ? prs_offset(data) : 0;
+ char *prdata = NULL;
+ uint32 rdata_len = 0;
+ uint32 current_offset = 0;
+
+ /* Create setup parameters - must be in native byte order. */
+
+ setup[0] = cmd;
+ setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */
+
+ DEBUG(5,("rpc_api_pipe: cmd:%x fnum:%x\n", (int)cmd,
+ (int)cli->nt_pipe_fnum));
+
+ /* Send the RPC request and receive a response. For short RPC
+ calls (about 1024 bytes or so) the RPC request and response
+ appears in a SMBtrans request and response. Larger RPC
+ responses are received further on. */
+
+ if (!cli_api_pipe(cli, "\\PIPE\\",
+ setup, 2, 0, /* Setup, length, max */
+ NULL, 0, 0, /* Params, length, max */
+ pdata, data_len, data_len, /* data, length, max */
+ &rparam, &rparam_len, /* return params, len */
+ &prdata, &rdata_len)) /* return data, len */
+ {
+ DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
+ return False;
+ }
+
+ /* Throw away returned params - we know we won't use them. */
+
+ SAFE_FREE(rparam);
+
+ if (prdata == NULL) {
+ DEBUG(0,("rpc_api_pipe: cmd %x on pipe %x failed to return data.\n",
+ (int)cmd, (int)cli->nt_pipe_fnum));
+ return False;
+ }
+
+ /*
+ * Give this memory as dynamically allocated to the return parse
+ * struct.
+ */
+
+ prs_give_memory(rdata, prdata, rdata_len, True);
+ current_offset = rdata_len;
+
+ /* This next call sets the endian bit correctly in rdata. */
+
+ if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) {
+ prs_mem_free(rdata);
+ return False;
+ }
+
+ if (rhdr.pkt_type == RPC_BINDACK) {
+ if (!last && !first) {
+ DEBUG(5,("rpc_api_pipe: bug in server (AS/U?), setting fragment first/last ON.\n"));
+ first = True;
+ last = True;
+ }
+ }
+
+ if (rhdr.pkt_type == RPC_RESPONSE) {
+ RPC_HDR_RESP rhdr_resp;
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) {
+ DEBUG(5,("rpc_api_pipe: failed to unmarshal RPC_HDR_RESP.\n"));
+ prs_mem_free(rdata);
+ return False;
+ }
+ }
+
+ DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
+ (unsigned int)len, (unsigned int)rdata_len ));
+
+ /* check if data to be sent back was too large for one SMBtrans */
+ /* err status is only informational: the _real_ check is on the
+ length */
+
+ if (len > 0) {
+ /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */
+
+ /* Read the remaining part of the first response fragment */
+
+ if (!rpc_read(cli, rdata, len, &current_offset)) {
+ prs_mem_free(rdata);
+ return False;
+ }
+ }
+
+ /*
+ * Now we have a complete PDU, check the auth struct if any was sent.
+ */
+
+ if (rhdr.auth_len != 0) {
+ if(!rpc_auth_pipe(cli, rdata, rhdr.frag_len, rhdr.auth_len))
+ return False;
+ /*
+ * Drop the auth footers from the current offset.
+ * We need this if there are more fragments.
+ * The auth footers consist of the auth_data and the
+ * preceeding 8 byte auth_header.
+ */
+ current_offset -= (rhdr.auth_len + RPC_HDR_AUTH_LEN);
+ }
+
+ /*
+ * Only one rpc fragment, and it has been read.
+ */
+
+ if (first && last) {
+ DEBUG(6,("rpc_api_pipe: fragment first and last both set\n"));
+ return True;
+ }
+
+ /*
+ * Read more fragments using SMBreadX until we get one with the
+ * last bit set.
+ */
+
+ while (!last) {
+ RPC_HDR_RESP rhdr_resp;
+ int num_read;
+ char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN];
+ prs_struct hps;
+ uint8 eclass;
+ uint32 ecode;
+
+ /*
+ * First read the header of the next PDU.
+ */
+
+ prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
+ prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
+
+ num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRDOS && ecode != ERRmoredata) {
+ DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
+ return False;
+ }
+ }
+
+ DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read));
+
+ if (num_read != RPC_HEADER_LEN+RPC_HDR_RESP_LEN) {
+ DEBUG(0,("rpc_api_pipe: Error : requested %d bytes, got %d.\n",
+ RPC_HEADER_LEN+RPC_HDR_RESP_LEN, num_read ));
+ return False;
+ }
+
+ /* This call sets the endianness in hps. */
+
+ if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len))
+ return False;
+
+ /* Ensure the endianness in rdata is set correctly - must be same as hps. */
+
+ if (hps.bigendian_data != rdata->bigendian_data) {
+ DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n",
+ rdata->bigendian_data ? "big" : "little",
+ hps.bigendian_data ? "big" : "little" ));
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) {
+ DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n"));
+ return False;
+ }
+
+ if (first) {
+ DEBUG(0,("rpc_api_pipe: secondary PDU rpc header has 'first' set !\n"));
+ return False;
+ }
+
+ /*
+ * Now read the rest of the PDU.
+ */
+
+ if (!rpc_read(cli, rdata, len, &current_offset))
+ return False;
+
+ /*
+ * Verify any authentication footer.
+ */
+
+ if (rhdr.auth_len != 0 ) {
+ if(!rpc_auth_pipe(cli, rdata, rhdr.frag_len, rhdr.auth_len))
+ return False;
+ /*
+ * Drop the auth footers from the current offset.
+ * The auth footers consist of the auth_data and the
+ * preceeding 8 byte auth_header.
+ * We need this if there are more fragments.
+ */
+ current_offset -= (rhdr.auth_len + RPC_HDR_AUTH_LEN);
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ creates a DCE/RPC bind request
+
+ - initialises the parse structure.
+ - dynamically allocates the header data structure
+ - caller is expected to free the header data structure once used.
+
+ ********************************************************************/
+
+static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer,
+ char *my_name, char *domain, uint32 neg_flags)
+{
+ RPC_HDR hdr;
+ RPC_HDR_RB hdr_rb;
+ char buffer[4096];
+ prs_struct auth_info;
+ int auth_len = 0;
+
+ prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
+
+ if (do_auth) {
+ RPC_HDR_AUTH hdr_auth;
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
+
+ /*
+ * Create the auth structs we will marshall.
+ */
+
+ init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00, 1);
+ init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_NEGOTIATE);
+ init_rpc_auth_ntlmssp_neg(&ntlmssp_neg, neg_flags, my_name, domain);
+
+ /*
+ * Use the 4k buffer to store the auth info.
+ */
+
+ prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
+
+ /*
+ * Now marshall the data into the temporary parse_struct.
+ */
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_neg("ntlmssp_neg", &ntlmssp_neg, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_NTLMSSP_NEG.\n"));
+ return False;
+ }
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
+ }
+
+ /* create the request RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_BIND, 0x0, rpc_call_id,
+ RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
+ auth_len);
+
+ if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n"));
+ return False;
+ }
+
+ /* create the bind request RPC_HDR_RB */
+ init_rpc_hdr_rb(&hdr_rb, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN, 0x0,
+ 0x1, 0x0, 0x1, abstract, transfer);
+
+ /* Marshall the bind request data */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n"));
+ return False;
+ }
+
+ /*
+ * Grow the outgoing buffer to store any auth info.
+ */
+
+ if(hdr.auth_len != 0) {
+ if(!prs_append_prs_data( rpc_out, &auth_info)) {
+ DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Creates a DCE/RPC bind authentication response.
+ This is the packet that is sent back to the server once we
+ have received a BIND-ACK, to finish the third leg of
+ the authentication handshake.
+ ********************************************************************/
+
+static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
+ char *domain, char *user_name, char *my_name,
+ uint32 ntlmssp_cli_flgs,
+ uint32 rpc_call_id,
+ prs_struct *rpc_out)
+{
+ unsigned char lm_owf[24];
+ unsigned char nt_owf[24];
+ RPC_HDR hdr;
+ RPC_HDR_AUTHA hdr_autha;
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
+ char buffer[4096];
+ prs_struct auth_info;
+
+ /*
+ * Marshall the variable length data into a temporary parse
+ * struct, pointing into a 4k local buffer.
+ */
+ prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
+
+ /*
+ * Use the 4k buffer to store the auth info.
+ */
+
+ prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
+
+ /*
+ * Create the variable length auth_data.
+ */
+
+ init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH);
+
+ pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf);
+
+ init_rpc_auth_ntlmssp_resp(&ntlmssp_resp,
+ lm_owf, nt_owf,
+ domain, user_name, my_name,
+ ntlmssp_cli_flgs);
+
+ /*
+ * Marshall the variable length auth_data into a temp parse_struct.
+ */
+
+ if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_NTLMSSP_RESP.\n"));
+ return False;
+ }
+
+ /* Create the request RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id,
+ RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + prs_offset(&auth_info),
+ prs_offset(&auth_info) );
+
+ /* Marshall it. */
+ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR.\n"));
+ return False;
+ }
+
+ /* Create the request RPC_HDR_AUTHA */
+ init_rpc_hdr_autha(&hdr_autha, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN,
+ NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00);
+
+ if(!smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR_AUTHA.\n"));
+ return False;
+ }
+
+ /*
+ * Append the auth data to the outgoing buffer.
+ */
+
+ if(!prs_append_prs_data(rpc_out, &auth_info)) {
+ DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ Creates a DCE/RPC request.
+ ********************************************************************/
+
+static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len)
+{
+ uint32 alloc_hint;
+ RPC_HDR hdr;
+ RPC_HDR_REQ hdr_req;
+
+ DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n", op_num, data_len));
+
+ /* create the rpc header RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_REQUEST, RPC_FLG_FIRST | RPC_FLG_LAST,
+ get_rpc_call_id(), data_len, auth_len);
+
+ /*
+ * The alloc hint should be the amount of data, not including
+ * RPC headers & footers.
+ */
+
+ if (auth_len != 0)
+ alloc_hint = data_len - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len;
+ else
+ alloc_hint = data_len - RPC_HEADER_LEN;
+
+ DEBUG(10,("create_rpc_request: data_len: %x auth_len: %x alloc_hint: %x\n",
+ data_len, auth_len, alloc_hint));
+
+ /* Create the rpc request RPC_HDR_REQ */
+ init_rpc_hdr_req(&hdr_req, alloc_hint, op_num);
+
+ /* stream-time... */
+ if(!smb_io_rpc_hdr("hdr ", &hdr, rpc_out, 0))
+ return False;
+
+ if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, rpc_out, 0))
+ return False;
+
+ if (prs_offset(rpc_out) != RPC_HEADER_LEN + RPC_HDR_REQ_LEN)
+ return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+ Send a request on an rpc pipe.
+ ****************************************************************************/
+
+BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
+ prs_struct *data, prs_struct *rdata)
+{
+ prs_struct outgoing_packet;
+ uint32 data_len;
+ uint32 auth_len;
+ BOOL ret;
+ BOOL auth_verify;
+ BOOL auth_seal;
+ uint32 crc32 = 0;
+ char *pdata_out = NULL;
+
+ auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+
+ /*
+ * The auth_len doesn't include the RPC_HDR_AUTH_LEN.
+ */
+
+ auth_len = (auth_verify ? RPC_AUTH_NTLMSSP_CHK_LEN : 0);
+
+ /*
+ * PDU len is header, plus request header, plus data, plus
+ * auth_header_len (if present), plus auth_len (if present).
+ * NB. The auth stuff should be aligned on an 8 byte boundary
+ * to be totally DCE/RPC spec complient. For now we cheat and
+ * hope that the data structs defined are a multiple of 8 bytes.
+ */
+
+ if((prs_offset(data) % 8) != 0) {
+ DEBUG(5,("rpc_api_pipe_req: Outgoing data not a multiple of 8 bytes....\n"));
+ }
+
+ data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(data) +
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0) + auth_len;
+
+ /*
+ * Malloc a parse struct to hold it (and enough for alignments).
+ */
+
+ if(!prs_init(&outgoing_packet, data_len + 8, cli->mem_ctx, MARSHALL)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
+ return False;
+ }
+
+ pdata_out = prs_data_p(&outgoing_packet);
+
+ /*
+ * Write out the RPC header and the request header.
+ */
+
+ if(!create_rpc_request(&outgoing_packet, op_num, data_len, auth_len)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ /*
+ * Seal the outgoing data if requested.
+ */
+
+ if (auth_seal) {
+ crc32 = crc32_calc_buffer(prs_data_p(data), prs_offset(data));
+ NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data), prs_offset(data));
+ }
+
+ /*
+ * Now copy the data into the outgoing packet.
+ */
+
+ if(!prs_append_prs_data( &outgoing_packet, data)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to append data to outgoing packet.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ /*
+ * Add a trailing auth_verifier if needed.
+ */
+
+ if (auth_seal || auth_verify) {
+ RPC_HDR_AUTH hdr_auth;
+
+ init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
+ NTLMSSP_AUTH_LEVEL, 0x08, (auth_verify ? 1 : 0));
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &outgoing_packet, 0)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ }
+
+ /*
+ * Finally the auth data itself.
+ */
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK chk;
+ uint32 current_offset = prs_offset(&outgoing_packet);
+
+ init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION, crc32, cli->ntlmssp_seq_num++);
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &outgoing_packet, 0)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ NTLMSSPcalc_ap(cli, (unsigned char*)&pdata_out[current_offset+4], RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ }
+
+ DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet)));
+
+ ret = rpc_api_pipe(cli, 0x0026, &outgoing_packet, rdata);
+
+ prs_mem_free(&outgoing_packet);
+
+ return ret;
+}
+
+/****************************************************************************
+ Set the handle state.
+****************************************************************************/
+
+static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, const char *pipe_name, uint16 device_state)
+{
+ BOOL state_set = False;
+ char param[2];
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ char *rparam = NULL;
+ char *rdata = NULL;
+ uint32 rparam_len, rdata_len;
+
+ if (pipe_name == NULL)
+ return False;
+
+ DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
+ cli->nt_pipe_fnum, pipe_name, device_state));
+
+ /* create parameters: device state */
+ SSVAL(param, 0, device_state);
+
+ /* create setup parameters. */
+ setup[0] = 0x0001;
+ setup[1] = cli->nt_pipe_fnum; /* pipe file handle. got this from an SMBOpenX. */
+
+ /* send the data on \PIPE\ */
+ if (cli_api_pipe(cli, "\\PIPE\\",
+ setup, 2, 0, /* setup, length, max */
+ param, 2, 0, /* param, length, max */
+ NULL, 0, 1024, /* data, length, max */
+ &rparam, &rparam_len, /* return param, length */
+ &rdata, &rdata_len)) /* return data, length */
+ {
+ DEBUG(5, ("Set Handle state: return OK\n"));
+ state_set = True;
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return state_set;
+}
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+static BOOL valid_pipe_name(const char *pipe_name, RPC_IFACE *abstract, RPC_IFACE *transfer)
+{
+ int pipe_idx = 0;
+
+ while (pipe_names[pipe_idx].client_pipe != NULL) {
+ if (strequal(pipe_name, pipe_names[pipe_idx].client_pipe )) {
+ DEBUG(5,("Bind Abstract Syntax: "));
+ dump_data(5, (char*)&(pipe_names[pipe_idx].abstr_syntax),
+ sizeof(pipe_names[pipe_idx].abstr_syntax));
+ DEBUG(5,("Bind Transfer Syntax: "));
+ dump_data(5, (char*)&(pipe_names[pipe_idx].trans_syntax),
+ sizeof(pipe_names[pipe_idx].trans_syntax));
+
+ /* copy the required syntaxes out so we can do the right bind */
+ *transfer = pipe_names[pipe_idx].trans_syntax;
+ *abstract = pipe_names[pipe_idx].abstr_syntax;
+
+ return True;
+ }
+ pipe_idx++;
+ };
+
+ DEBUG(5,("Bind RPC Pipe[%s] unsupported\n", pipe_name));
+ return False;
+}
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const char *pipe_name, RPC_IFACE *transfer)
+{
+ int i = 0;
+
+ while ((pipe_names[i].client_pipe != NULL) && hdr_ba->addr.len > 0) {
+ if ((strequal(pipe_name, pipe_names[i].client_pipe ))) {
+ if (strequal(hdr_ba->addr.str, pipe_names[i].server_pipe )) {
+ DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n",
+ pipe_names[i].server_pipe ));
+ break;
+ } else {
+ DEBUG(4,("bind_rpc_pipe: pipe_name %s != expected pipe %s. oh well!\n",
+ pipe_names[i].server_pipe ,
+ hdr_ba->addr.str));
+ break;
+ }
+ } else {
+ i++;
+ }
+ }
+
+ if (pipe_names[i].server_pipe == NULL) {
+ DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba->addr.str));
+ return False;
+ }
+
+ /* check the transfer syntax */
+ if ((hdr_ba->transfer.version != transfer->version) ||
+ (memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
+ DEBUG(0,("bind_rpc_pipe: transfer syntax differs\n"));
+ return False;
+ }
+
+ /* lkclXXXX only accept one result: check the result(s) */
+ if (hdr_ba->res.num_results != 0x1 || hdr_ba->res.result != 0) {
+ DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
+ hdr_ba->res.num_results, hdr_ba->res.reason));
+ }
+
+ DEBUG(5,("bind_rpc_pipe: accepted!\n"));
+ return True;
+}
+
+/****************************************************************************
+ Create and send the third packet in an RPC auth.
+****************************************************************************/
+
+static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32 rpc_call_id)
+{
+ RPC_HDR_AUTH rhdr_auth;
+ RPC_AUTH_VERIFIER rhdr_verf;
+ RPC_AUTH_NTLMSSP_CHAL rhdr_chal;
+ char buffer[MAX_PDU_FRAG_LEN];
+ prs_struct rpc_out;
+ ssize_t ret;
+
+ unsigned char p24[24];
+ unsigned char lm_owf[24];
+ unsigned char lm_hash[16];
+
+ if(!smb_io_rpc_hdr_auth("", &rhdr_auth, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+ if(!smb_io_rpc_auth_verifier("", &rhdr_verf, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+ if(!smb_io_rpc_auth_ntlmssp_chal("", &rhdr_chal, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_NTLMSSP_CHAL.\n"));
+ return False;
+ }
+
+ cli->ntlmssp_cli_flgs = rhdr_chal.neg_flags;
+
+ pwd_make_lm_nt_owf(&cli->pwd, rhdr_chal.challenge);
+
+ prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
+
+ prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
+
+ create_rpc_bind_resp(&cli->pwd, cli->domain,
+ cli->user_name, global_myname,
+ cli->ntlmssp_cli_flgs, rpc_call_id,
+ &rpc_out);
+
+ pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL);
+ pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL);
+
+ NTLMSSPOWFencrypt(lm_hash, lm_owf, p24);
+
+ {
+ unsigned char j = 0;
+ int ind;
+ unsigned char k2[8];
+
+ memcpy(k2, p24, 5);
+ k2[5] = 0xe5;
+ k2[6] = 0x38;
+ k2[7] = 0xb0;
+
+ for (ind = 0; ind < 256; ind++)
+ cli->ntlmssp_hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (cli->ntlmssp_hash[ind] + k2[ind%8]);
+
+ tc = cli->ntlmssp_hash[ind];
+ cli->ntlmssp_hash[ind] = cli->ntlmssp_hash[j];
+ cli->ntlmssp_hash[j] = tc;
+ }
+
+ cli->ntlmssp_hash[256] = 0;
+ cli->ntlmssp_hash[257] = 0;
+ }
+
+ memset((char *)lm_hash, '\0', sizeof(lm_hash));
+
+ if ((ret = cli_write(cli, cli->nt_pipe_fnum, 0x8, prs_data_p(&rpc_out),
+ 0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
+ DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
+ return False;
+ }
+
+ cli->ntlmssp_srv_flgs = rhdr_chal.neg_flags;
+ return True;
+}
+
+/****************************************************************************
+ Do an rpc bind.
+****************************************************************************/
+
+BOOL rpc_pipe_bind(struct cli_state *cli, const char *pipe_name, char *my_name)
+{
+ RPC_IFACE abstract;
+ RPC_IFACE transfer;
+ prs_struct rpc_out;
+ prs_struct rdata;
+ BOOL do_auth = (cli->ntlmssp_cli_flgs != 0);
+ uint32 rpc_call_id;
+ char buffer[MAX_PDU_FRAG_LEN];
+
+ DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_name));
+
+ if (!valid_pipe_name(pipe_name, &abstract, &transfer))
+ return False;
+
+ prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
+
+ /*
+ * Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
+ */
+
+ prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
+
+ rpc_call_id = get_rpc_call_id();
+
+ /* Marshall the outgoing data. */
+ create_rpc_bind_req(&rpc_out, do_auth, rpc_call_id,
+ &abstract, &transfer,
+ global_myname, cli->domain, cli->ntlmssp_cli_flgs);
+
+ /* Initialize the incoming data struct. */
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* send data on \PIPE\. receive a response */
+ if (rpc_api_pipe(cli, 0x0026, &rpc_out, &rdata)) {
+ RPC_HDR_BA hdr_ba;
+
+ DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &rdata, 0)) {
+ DEBUG(0,("rpc_pipe_bind: Failed to unmarshall RPC_HDR_BA.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if(!check_bind_response(&hdr_ba, pipe_name, &transfer)) {
+ DEBUG(0,("rpc_pipe_bind: check_bind_response failed.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ cli->max_xmit_frag = hdr_ba.bba.max_tsize;
+ cli->max_recv_frag = hdr_ba.bba.max_rsize;
+
+ /*
+ * If we're doing NTLMSSP auth we need to send a reply to
+ * the bind-ack to complete the 3-way challenge response
+ * handshake.
+ */
+
+ if (do_auth && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
+ DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+ }
+
+ prs_mem_free(&rdata);
+ return True;
+}
+
+/****************************************************************************
+ Set ntlmssp negotiation flags.
+ ****************************************************************************/
+
+void cli_nt_set_ntlmssp_flgs(struct cli_state *cli, uint32 ntlmssp_flgs)
+{
+ cli->ntlmssp_cli_flgs = ntlmssp_flgs;
+}
+
+
+/****************************************************************************
+ Open a session.
+ ****************************************************************************/
+
+BOOL cli_nt_session_open(struct cli_state *cli, const char *pipe_name)
+{
+ int fnum;
+
+ SMB_ASSERT(cli->nt_pipe_fnum == 0);
+
+ if (cli->capabilities & CAP_NT_SMBS) {
+ if ((fnum = cli_nt_create(cli, &pipe_name[5], DESIRED_ACCESS_PIPE)) == -1) {
+ DEBUG(0,("cli_nt_session_open: cli_nt_create failed on pipe %s to machine %s. Error was %s\n",
+ &pipe_name[5], cli->desthost, cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+ } else {
+ if ((fnum = cli_open(cli, pipe_name, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
+ DEBUG(0,("cli_nt_session_open: cli_open failed on pipe %s to machine %s. Error was %s\n",
+ pipe_name, cli->desthost, cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+
+ /**************** Set Named Pipe State ***************/
+ if (!rpc_pipe_set_hnd_state(cli, pipe_name, 0x4300)) {
+ DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
+ cli_errstr(cli)));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+ }
+
+ /******************* bind request on pipe *****************/
+
+ if (!rpc_pipe_bind(cli, pipe_name, global_myname)) {
+ DEBUG(0,("cli_nt_session_open: rpc bind failed. Error was %s\n",
+ cli_errstr(cli)));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+
+ /*
+ * Setup the remote server name prefixed by \ and the machine account name.
+ */
+
+ fstrcpy(cli->srv_name_slash, "\\\\");
+ fstrcat(cli->srv_name_slash, cli->desthost);
+ strupper(cli->srv_name_slash);
+
+ fstrcpy(cli->clnt_name_slash, "\\\\");
+ fstrcat(cli->clnt_name_slash, global_myname);
+ strupper(cli->clnt_name_slash);
+
+ fstrcpy(cli->mach_acct, global_myname);
+ fstrcat(cli->mach_acct, "$");
+ strupper(cli->mach_acct);
+
+ return True;
+}
+
+/****************************************************************************
+close the session
+****************************************************************************/
+
+void cli_nt_session_close(struct cli_state *cli)
+{
+ cli_close(cli, cli->nt_pipe_fnum);
+ cli->nt_pipe_fnum = 0;
+}
diff --git a/source/rpc_client/cli_reg.c b/source/rpc_client/cli_reg.c
new file mode 100644
index 00000000000..cc433ab566b
--- /dev/null
+++ b/source/rpc_client/cli_reg.c
@@ -0,0 +1,1072 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "includes.h"
+
+/****************************************************************************
+do a REG Open Policy
+****************************************************************************/
+BOOL do_reg_connect(struct cli_state *cli, char *full_keyname, char *key_name,
+ POLICY_HND *reg_hnd)
+{
+ BOOL res = True;
+ uint32 reg_type = 0;
+
+ if (full_keyname == NULL)
+ return False;
+
+ ZERO_STRUCTP(reg_hnd);
+
+ /*
+ * open registry receive a policy handle
+ */
+
+ if (!reg_split_key(full_keyname, &reg_type, key_name)) {
+ DEBUG(0,("do_reg_connect: unrecognised key name %s\n", full_keyname));
+ return False;
+ }
+
+ switch (reg_type) {
+ case HKEY_LOCAL_MACHINE:
+ res = res ? do_reg_open_hklm(cli, 0x84E0, 0x02000000, reg_hnd) : False;
+ break;
+
+ case HKEY_USERS:
+ res = res ? do_reg_open_hku(cli, 0x84E0, 0x02000000, reg_hnd) : False;
+ break;
+
+ default:
+ DEBUG(0,("do_reg_connect: unrecognised hive key\n"));
+ return False;
+ }
+
+ return res;
+}
+
+/****************************************************************************
+do a REG Open Policy
+****************************************************************************/
+BOOL do_reg_open_hklm(struct cli_state *cli, uint16 unknown_0, uint32 level,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_HKLM q_o;
+ REG_R_OPEN_HKLM r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_HKLM */
+
+ DEBUG(4,("REG Open HKLM\n"));
+
+ init_reg_q_open_hklm(&q_o, unknown_0, level);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_hklm("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_OPEN_HKLM, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_hklm("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_HKLM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Open HKU
+****************************************************************************/
+BOOL do_reg_open_hku(struct cli_state *cli, uint16 unknown_0, uint32 level,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_HKU q_o;
+ REG_R_OPEN_HKU r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_HKU */
+
+ DEBUG(4,("REG Open HKU\n"));
+
+ init_reg_q_open_hku(&q_o, unknown_0, level);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_hku("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_OPEN_HKU, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_hku("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_HKU: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Unknown 0xB command. sent after a create key or create value.
+this might be some sort of "sync" or "refresh" command, sent after
+modification of the registry...
+****************************************************************************/
+BOOL do_reg_flush_key(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_FLUSH_KEY q_o;
+ REG_R_FLUSH_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_FLUSH_KEY */
+
+ DEBUG(4,("REG Unknown 0xB\n"));
+
+ init_reg_q_flush_key(&q_o, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_flush_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_FLUSH_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_flush_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_FLUSH_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Key
+****************************************************************************/
+BOOL do_reg_query_key(struct cli_state *cli, POLICY_HND *hnd,
+ char *class, uint32 *class_len,
+ uint32 *num_subkeys, uint32 *max_subkeylen,
+ uint32 *max_subkeysize, uint32 *num_values,
+ uint32 *max_valnamelen, uint32 *max_valbufsize,
+ uint32 *sec_desc, NTTIME *mod_time)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_QUERY_KEY q_o;
+ REG_R_QUERY_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_QUERY_KEY */
+
+ DEBUG(4,("REG Query Key\n"));
+
+ init_reg_q_query_key(&q_o, hnd, *class_len);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_query_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_QUERY_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_query_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_QUERY_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *class_len = r_o.hdr_class.uni_max_len;
+ rpcstr_pull(class, &r_o.uni_class, -1, -1, 0);
+ *num_subkeys = r_o.num_subkeys ;
+ *max_subkeylen = r_o.max_subkeylen ;
+ *max_subkeysize = r_o.max_subkeysize;
+ *num_values = r_o.num_values ;
+ *max_valnamelen = r_o.max_valnamelen;
+ *max_valbufsize = r_o.max_valbufsize;
+ *sec_desc = r_o.sec_desc ;
+ *mod_time = r_o.mod_time ;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Unknown 1A
+****************************************************************************/
+BOOL do_reg_unknown_1a(struct cli_state *cli, POLICY_HND *hnd, uint32 *unk)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_UNK_1A q_o;
+ REG_R_UNK_1A r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_UNKNOWN_1A */
+
+ DEBUG(4,("REG Unknown 1a\n"));
+
+ init_reg_q_unk_1a(&q_o, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_unk_1a("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_UNK_1A, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_unk_1a("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_UNK_1A: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*unk) = r_o.unknown;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Info
+****************************************************************************/
+BOOL do_reg_query_info(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_value, uint32* key_type)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_INFO q_o;
+ REG_R_INFO r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_INFO */
+
+ DEBUG(4,("REG Query Info\n"));
+
+ init_reg_q_info(&q_o, hnd, "ProductType");
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_info("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_INFO, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_info("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if ( r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /*fstrcpy(key_value, dos_buffer2_to_str(r_o.uni_val));*/
+ rpcstr_pull(key_value, r_o.uni_val->buffer, sizeof(fstring), r_o.uni_val->buf_len, 0);
+ *key_type = r_o.type;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Set Key Security
+****************************************************************************/
+BOOL do_reg_set_key_sec(struct cli_state *cli, POLICY_HND *hnd, SEC_DESC_BUF *sec_desc_buf)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_SET_KEY_SEC q_o;
+ REG_R_SET_KEY_SEC r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_SET_KEY_SEC */
+
+ DEBUG(4,("REG Set Key security.\n"));
+
+ init_reg_q_set_key_sec(&q_o, hnd, sec_desc_buf);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_set_key_sec("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_SET_KEY_SEC, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_set_key_sec("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Key Security
+****************************************************************************/
+
+BOOL do_reg_get_key_sec(struct cli_state *cli, POLICY_HND *hnd, uint32 *sec_buf_size, SEC_DESC_BUF **ppsec_desc_buf)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_GET_KEY_SEC q_o;
+ REG_R_GET_KEY_SEC r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_GET_KEY_SEC */
+
+ DEBUG(4,("REG query key security. buf_size: %d\n", *sec_buf_size));
+
+ init_reg_q_get_key_sec(&q_o, hnd, *sec_buf_size, NULL);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_get_key_sec("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_GET_KEY_SEC, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_get_key_sec("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status == 0x0000007a) {
+ /*
+ * get the maximum buffer size: it was too small
+ */
+ (*sec_buf_size) = r_o.hdr_sec.buf_max_len;
+ DEBUG(5,("sec_buf_size too small. use %d\n", *sec_buf_size));
+ } else if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_GET_KEY_SEC: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ } else {
+ (*sec_buf_size) = r_o.data->len;
+ *ppsec_desc_buf = r_o.data;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Delete Value
+****************************************************************************/
+BOOL do_reg_delete_val(struct cli_state *cli, POLICY_HND *hnd, char *val_name)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_DELETE_VALUE q_o;
+ REG_R_DELETE_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_DELETE_VALUE */
+
+ DEBUG(4,("REG Delete Value: %s\n", val_name));
+
+ init_reg_q_delete_val(&q_o, hnd, val_name);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_delete_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_DELETE_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_delete_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_DELETE_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Delete Key
+****************************************************************************/
+BOOL do_reg_delete_key(struct cli_state *cli, POLICY_HND *hnd, char *key_name)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_DELETE_KEY q_o;
+ REG_R_DELETE_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_DELETE_KEY */
+
+ DEBUG(4,("REG Delete Key: %s\n", key_name));
+
+ init_reg_q_delete_key(&q_o, hnd, key_name);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_delete_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_DELETE_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_delete_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_DELETE_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Create Key
+****************************************************************************/
+BOOL do_reg_create_key(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_name, char *key_class,
+ SEC_ACCESS *sam_access,
+ POLICY_HND *key)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CREATE_KEY q_o;
+ REG_R_CREATE_KEY r_o;
+ SEC_DESC *sec = NULL;
+ SEC_DESC_BUF *sec_buf = NULL;
+ size_t sec_len;
+
+ ZERO_STRUCT(q_o);
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api REG_CREATE_KEY */
+
+ DEBUG(4,("REG Create Key: %s %s 0x%08x\n", key_name, key_class,
+ sam_access != NULL ? sam_access->mask : 0));
+
+ if((sec = make_sec_desc( cli->mem_ctx, 1, NULL, NULL, NULL, NULL, &sec_len)) == NULL) {
+ DEBUG(0,("make_sec_desc : malloc fail.\n"));
+ return False;
+ }
+
+ DEBUG(10,("make_sec_desc: len = %d\n", (int)sec_len));
+
+ if((sec_buf = make_sec_desc_buf( cli->mem_ctx, (int)sec_len, sec)) == NULL) {
+ DEBUG(0,("make_sec_desc : malloc fail (1)\n"));
+ return False;
+ }
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ init_reg_q_create_key(&q_o, hnd, key_name, key_class, sam_access, sec_buf);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_create_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_CREATE_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_create_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CREATE_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *key = r_o.key_pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Enum Key
+****************************************************************************/
+BOOL do_reg_enum_key(struct cli_state *cli, POLICY_HND *hnd,
+ int key_index, char *key_name,
+ uint32 *unk_1, uint32 *unk_2,
+ time_t *mod_time)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_ENUM_KEY q_o;
+ REG_R_ENUM_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_ENUM_KEY */
+
+ DEBUG(4,("REG Enum Key\n"));
+
+ init_reg_q_enum_key(&q_o, hnd, key_index);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_enum_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_ENUM_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_enum_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_ENUM_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*unk_1) = r_o.unknown_1;
+ (*unk_2) = r_o.unknown_2;
+ rpcstr_pull(key_name, r_o.key_name.str.buffer, -1, -1, 0);
+ (*mod_time) = nt_time_to_unix(&r_o.time);
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Create Value
+****************************************************************************/
+BOOL do_reg_create_val(struct cli_state *cli, POLICY_HND *hnd,
+ char *val_name, uint32 type, BUFFER3 *data)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CREATE_VALUE q_o;
+ REG_R_CREATE_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_CREATE_VALUE */
+
+ DEBUG(4,("REG Create Value: %s\n", val_name));
+
+ init_reg_q_create_val(&q_o, hnd, val_name, type, data);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_create_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_CREATE_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_create_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CREATE_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Enum Value
+****************************************************************************/
+BOOL do_reg_enum_val(struct cli_state *cli, POLICY_HND *hnd,
+ int val_index, int max_valnamelen, int max_valbufsize,
+ fstring val_name,
+ uint32 *val_type, BUFFER2 *value)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_ENUM_VALUE q_o;
+ REG_R_ENUM_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_ENUM_VALUE */
+
+ DEBUG(4,("REG Enum Value\n"));
+
+ init_reg_q_enum_val(&q_o, hnd, val_index, max_valnamelen, max_valbufsize);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_enum_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_ENUM_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+ r_o.buf_value = value;
+
+ if(!reg_io_r_enum_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_ENUM_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*val_type) = r_o.type;
+ rpcstr_pull(val_name, &r_o.uni_name, -1, -1, 0);
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Open Key
+****************************************************************************/
+BOOL do_reg_open_entry(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_name, uint32 unk_0,
+ POLICY_HND *key_hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_ENTRY q_o;
+ REG_R_OPEN_ENTRY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_ENTRY */
+
+ DEBUG(4,("REG Open Entry\n"));
+
+ init_reg_q_open_entry(&q_o, hnd, key_name, unk_0);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_entry("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_OPEN_ENTRY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_entry("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_ENTRY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *key_hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Close
+****************************************************************************/
+BOOL do_reg_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CLOSE q_c;
+ REG_R_CLOSE r_c;
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api REG_CLOSE */
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("REG Close\n"));
+
+ /* store the parameters */
+ init_reg_q_close(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_close("", &q_c, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_CLOSE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_c);
+
+ if(!reg_io_r_close("", &r_c, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_c.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CLOSE: %s\n", get_nt_error_msg(r_c.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* check that the returned policy handle is all zeros */
+
+ if (IVAL(&r_c.pol.data1,0) || IVAL(&r_c.pol.data2,0) || SVAL(&r_c.pol.data3,0) ||
+ SVAL(&r_c.pol.data4,0) || IVAL(r_c.pol.data5,0) || IVAL(r_c.pol.data5,4) ) {
+ prs_mem_free(&rbuf);
+ DEBUG(0,("REG_CLOSE: non-zero handle returned\n"));
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_samr.c b/source/rpc_client/cli_samr.c
new file mode 100644
index 00000000000..ff8a3a3a67a
--- /dev/null
+++ b/source/rpc_client/cli_samr.c
@@ -0,0 +1,838 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+do a SAMR query user groups
+****************************************************************************/
+BOOL get_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol_open_domain, uint32 user_rid,
+ uint32 *num_groups, DOM_GID *gid)
+{
+ POLICY_HND pol_open_user;
+ if (pol_open_domain == NULL || num_groups == NULL || gid == NULL)
+ return False;
+
+ /* send open domain (on user sid) */
+ if (!do_samr_open_user(cli,
+ pol_open_domain,
+ 0x02011b, user_rid,
+ &pol_open_user))
+ {
+ return False;
+ }
+
+ /* send user groups query */
+ if (!do_samr_query_usergroups(cli,
+ &pol_open_user,
+ num_groups, gid))
+ {
+ DEBUG(5,("do_samr_query_usergroups: error in query user groups\n"));
+ }
+
+ return do_samr_close(cli, &pol_open_user);
+}
+
+#if 0
+/* DOES NOT COMPILE WITH THE NEW SAMR PARSE CODE. JRA. */
+
+/****************************************************************************
+do a SAMR query user info
+****************************************************************************/
+BOOL get_samr_query_userinfo(struct cli_state *cli,
+ POLICY_HND *pol_open_domain,
+ uint32 info_level,
+ uint32 user_rid, SAM_USER_INFO_21 *usr)
+{
+ POLICY_HND pol_open_user;
+ if (pol_open_domain == NULL || usr == NULL)
+ return False;
+
+ memset((char *)usr, '\0', sizeof(*usr));
+
+ /* send open domain (on user sid) */
+ if (!do_samr_open_user(cli,
+ pol_open_domain,
+ 0x02011b, user_rid,
+ &pol_open_user))
+ {
+ return False;
+ }
+
+ /* send user info query */
+ if (!do_samr_query_userinfo(cli,
+ &pol_open_user,
+ info_level, (void*)usr))
+ {
+ DEBUG(5,("do_samr_query_userinfo: error in query user info, level 0x%x\n",
+ info_level));
+ }
+
+ return do_samr_close(cli, &pol_open_user);
+}
+#endif
+
+/****************************************************************************
+do a SAMR change user password command
+****************************************************************************/
+BOOL do_samr_chgpasswd_user(struct cli_state *cli,
+ char *srv_name, char *user_name,
+ char nt_newpass[516], uchar nt_oldhash[16],
+ char lm_newpass[516], uchar lm_oldhash[16])
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CHGPASSWD_USER q_e;
+ SAMR_R_CHGPASSWD_USER r_e;
+
+ /* create and send a MSRPC command with api SAMR_CHGPASSWD_USER */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Change User Password. server:%s username:%s\n",
+ srv_name, user_name));
+
+ init_samr_q_chgpasswd_user(&q_e, srv_name, user_name,
+ nt_newpass, nt_oldhash,
+ lm_newpass, lm_oldhash);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_chgpasswd_user("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CHGPASSWD_USER, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_chgpasswd_user("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_CHGPASSWD_USER: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY THIS DOESN'T COMPILE AND IS NOT USED ANYWHERE. JRA. */
+
+/****************************************************************************
+do a SAMR unknown 0x38 command
+****************************************************************************/
+BOOL do_samr_unknown_38(struct cli_state *cli, char *srv_name)
+{
+ prs_struct data;
+ prs_struct rdata;
+
+ SAMR_Q_UNKNOWN_38 q_e;
+ SAMR_R_UNKNOWN_38 r_e;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Unknown 38 server:%s\n", srv_name));
+
+ init_samr_q_unknown_38(&q_e, srv_name);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_unknown_38("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_UNKNOWN_38, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_unknown_38("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_38: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR unknown 0x8 command
+****************************************************************************/
+BOOL do_samr_query_dom_info(struct cli_state *cli,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_DOMAIN_INFO q_e;
+ SAMR_R_QUERY_DOMAIN_INFO r_e;
+
+ if (domain_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Unknown 8 switch:%d\n", switch_value));
+
+ /* store the parameters */
+ init_samr_q_query_dom_info(&q_e, domain_pol, switch_value);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_dom_info("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_DOMAIN_INFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_query_dom_info("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_DOMAIN_INFO: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOESN'T COMPILE WITH THE NEW SAMR PARSE CODE. JRA */
+
+/****************************************************************************
+do a SAMR enumerate users
+****************************************************************************/
+BOOL do_samr_enum_dom_users(struct cli_state *cli,
+ POLICY_HND *pol, uint16 num_entries, uint16 unk_0,
+ uint16 acb_mask, uint16 unk_1, uint32 size,
+ struct acct_info **sam,
+ int *num_sam_users)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_ENUM_DOM_USERS q_e;
+ SAMR_R_ENUM_DOM_USERS r_e;
+ int i;
+ int name_idx = 0;
+
+ if (pol == NULL || num_sam_users == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Enum SAM DB max size:%x\n", size));
+
+ /* store the parameters */
+ init_samr_q_enum_dom_users(&q_e, pol,
+ num_entries, unk_0,
+ acb_mask, unk_1, size);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_enum_dom_users("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_ENUM_DOM_USERS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_enum_dom_users("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_ENUM_DOM_USERS: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ *num_sam_users = r_e.num_entries2;
+ if (*num_sam_users > MAX_SAM_ENTRIES) {
+ *num_sam_users = MAX_SAM_ENTRIES;
+ DEBUG(2,("do_samr_enum_dom_users: sam user entries limited to %d\n",
+ *num_sam_users));
+ }
+
+ *sam = (struct acct_info*) malloc(sizeof(struct acct_info) * (*num_sam_users));
+
+ if ((*sam) == NULL)
+ *num_sam_users = 0;
+
+ for (i = 0; i < *num_sam_users; i++) {
+ (*sam)[i].smb_userid = r_e.sam[i].rid;
+ if (r_e.sam[i].hdr_name.buffer) {
+ char *acct_name = dos_unistrn2(r_e.uni_acct_name[name_idx].buffer,
+ r_e.uni_acct_name[name_idx].uni_str_len);
+ fstrcpy((*sam)[i].acct_name, acct_name);
+ name_idx++;
+ } else {
+ memset((char *)(*sam)[i].acct_name, '\0', sizeof((*sam)[i].acct_name));
+ }
+
+ DEBUG(5,("do_samr_enum_dom_users: idx: %4d rid: %8x acct: %s\n",
+ i, (*sam)[i].smb_userid, (*sam)[i].acct_name));
+ }
+
+ prs_mem_free(&rdata );
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR Connect
+****************************************************************************/
+BOOL do_samr_connect(struct cli_state *cli,
+ char *srv_name, uint32 unknown_0,
+ POLICY_HND *connect_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CONNECT q_o;
+ SAMR_R_CONNECT r_o;
+
+ if (srv_name == NULL || connect_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_CONNECT */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Open Policy server:%s undoc value:%x\n",
+ srv_name, unknown_0));
+
+ /* store the parameters */
+ init_samr_q_connect(&q_o, srv_name, unknown_0);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_connect("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CONNECT, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_connect("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_CONNECT: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(connect_pol, &r_o.connect_pol, sizeof(r_o.connect_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a SAMR Open User
+****************************************************************************/
+BOOL do_samr_open_user(struct cli_state *cli,
+ POLICY_HND *pol, uint32 unk_0, uint32 rid,
+ POLICY_HND *user_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_OPEN_USER q_o;
+ SAMR_R_OPEN_USER r_o;
+
+ if (pol == NULL || user_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_USER */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Open User. unk_0: %08x RID:%x\n",
+ unk_0, rid));
+
+ /* store the parameters */
+ init_samr_q_open_user(&q_o, pol, unk_0, rid);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_open_user("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_OPEN_USER, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_open_user("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_USER: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(user_pol, &r_o.user_pol, sizeof(r_o.user_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a SAMR Open Domain
+****************************************************************************/
+BOOL do_samr_open_domain(struct cli_state *cli,
+ POLICY_HND *connect_pol, uint32 rid, DOM_SID *sid,
+ POLICY_HND *domain_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ pstring sid_str;
+ SAMR_Q_OPEN_DOMAIN q_o;
+ SAMR_R_OPEN_DOMAIN r_o;
+
+ if (connect_pol == NULL || sid == NULL || domain_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_DOMAIN */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ sid_to_string(sid_str, sid);
+ DEBUG(4,("SAMR Open Domain. SID:%s RID:%x\n", sid_str, rid));
+
+ /* store the parameters */
+ init_samr_q_open_domain(&q_o, connect_pol, rid, sid);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_open_domain("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_OPEN_DOMAIN, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_open_domain("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_DOMAIN: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(domain_pol, &r_o.domain_pol, sizeof(r_o.domain_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOES NOT COMPILE AND IS NOT USED ANYWHERE. JRA. */
+
+/****************************************************************************
+do a SAMR Query Unknown 12
+****************************************************************************/
+BOOL do_samr_query_unknown_12(struct cli_state *cli,
+ POLICY_HND *pol, uint32 rid, uint32 num_gids, uint32 *gids,
+ uint32 *num_aliases,
+ fstring als_names [MAX_LOOKUP_SIDS],
+ uint32 num_als_users[MAX_LOOKUP_SIDS])
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_LOOKUP_RIDS q_o;
+ SAMR_R_LOOKUP_RIDS r_o;
+
+ if (pol == NULL || rid == 0 || num_gids == 0 || gids == NULL ||
+ num_aliases == NULL || als_names == NULL || num_als_users == NULL )
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_UNKNOWN_12 */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query Unknown 12.\n"));
+
+ /* store the parameters */
+ init_samr_q_lookup_rids(&q_o, pol, rid, num_gids, gids);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_lookup_rids("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_LOOKUP_RIDS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_lookup_rids("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_12: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ptr_aliases != 0 && r_o.ptr_als_usrs != 0 &&
+ r_o.num_als_usrs1 == r_o.num_aliases1) {
+ int i;
+
+ *num_aliases = r_o.num_aliases1;
+
+ for (i = 0; i < r_o.num_aliases1; i++) {
+ fstrcpy(als_names[i], dos_unistrn2(r_o.uni_als_name[i].buffer,
+ r_o.uni_als_name[i].uni_str_len));
+ }
+ for (i = 0; i < r_o.num_als_usrs1; i++) {
+ num_als_users[i] = r_o.num_als_usrs[i];
+ }
+ } else if (r_o.ptr_aliases == 0 && r_o.ptr_als_usrs == 0) {
+ *num_aliases = 0;
+ } else {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR Query User Groups
+****************************************************************************/
+BOOL do_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol, uint32 *num_groups, DOM_GID *gid)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_USERGROUPS q_o;
+ SAMR_R_QUERY_USERGROUPS r_o;
+
+ if (pol == NULL || gid == NULL || num_groups == 0)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERGROUPS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query User Groups.\n"));
+
+ /* store the parameters */
+ init_samr_q_query_usergroups(&q_o, pol);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_usergroups("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_USERGROUPS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ /* get user info */
+ r_o.gid = gid;
+
+ if(!samr_io_r_query_usergroups("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERGROUPS: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ *num_groups = r_o.num_entries;
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOES NOT COMPILE WITH THE NEW SAMR PARSE CODE. JRA */
+
+/****************************************************************************
+do a SAMR Query User Info
+****************************************************************************/
+BOOL do_samr_query_userinfo(struct cli_state *cli,
+ POLICY_HND *pol, uint16 switch_value, void* usr)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_USERINFO q_o;
+ SAMR_R_QUERY_USERINFO r_o;
+
+ if (pol == NULL || usr == NULL || switch_value == 0)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERINFO */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query User Info. level: %d\n", switch_value));
+
+ /* store the parameters */
+ init_samr_q_query_userinfo(&q_o, pol, switch_value);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_userinfo("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_USERINFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ /* get user info */
+ r_o.info.id = usr;
+
+ if(!samr_io_r_query_userinfo("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.switch_value != switch_value) {
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: received incorrect level %d\n",
+ r_o.switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ptr == 0) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#endif
+
+/****************************************************************************
+do a SAMR Close
+****************************************************************************/
+BOOL do_samr_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CLOSE_HND q_c;
+ SAMR_R_CLOSE_HND r_c;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SAMR_CLOSE_HND */
+
+ DEBUG(4,("SAMR Close\n"));
+
+ /* store the parameters */
+ init_samr_q_close_hnd(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_close_hnd("", &q_c, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CLOSE_HND, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_close_hnd("", &r_c, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_c.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_CLOSE_HND: %s\n", get_nt_error_msg(r_c.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* check that the returned policy handle is all zeros */
+
+ if (IVAL(&r_c.pol.data1,0) || IVAL(&r_c.pol.data2,0) || SVAL(&r_c.pol.data3,0) ||
+ SVAL(&r_c.pol.data4,0) || IVAL(r_c.pol.data5,0) || IVAL(r_c.pol.data5,4) ) {
+ DEBUG(0,("SAMR_CLOSE_HND: non-zero handle returned\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_spoolss.c b/source/rpc_client/cli_spoolss.c
new file mode 100644
index 00000000000..39655519f99
--- /dev/null
+++ b/source/rpc_client/cli_spoolss.c
@@ -0,0 +1,818 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Paul Ashton 1997-2000,
+ * Copyright (C) Jean Francois Micouleau 1998-2000,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "rpc_parse.h"
+#include "nterr.h"
+
+/****************************************************************************
+do a SPOOLSS Enum Printer Drivers
+****************************************************************************/
+uint32 spoolss_enum_printerdrivers(const char *srv_name, const char *environment,
+ uint32 level, NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERDRIVERS q_o;
+ SPOOL_R_ENUMPRINTERDRIVERS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS Enum Printer Drivers (Server: %s Environment: %s level: %d)\n",
+ srv_name, environment, level));
+
+ make_spoolss_q_enumprinterdrivers(&q_o, srv_name, environment,
+ level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinterdrivers("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPRINTERDRIVERS, &buf, &rbuf))
+ {
+ prs_mem_free(&buf);
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_enumprinterdrivers("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPRINTERDRIVERS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Printers
+****************************************************************************/
+uint32 spoolss_enum_printers(uint32 flags, fstring srv_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERS q_o;
+ SPOOL_R_ENUMPRINTERS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS Enum Printers (Server: %s level: %d)\n", srv_name, level));
+
+ make_spoolss_q_enumprinters(&q_o, flags, "", level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinters("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPRINTERS, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(new_spoolss_io_r_enumprinters("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ENUMPRINTERS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Ports
+****************************************************************************/
+uint32 spoolss_enum_ports(fstring srv_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPORTS q_o;
+ SPOOL_R_ENUMPORTS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPORTS */
+
+ DEBUG(5,("SPOOLSS Enum Ports (Server: %s level: %d)\n", srv_name, level));
+
+ make_spoolss_q_enumports(&q_o, "", level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumports("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPORTS, &buf, &rbuf))
+ {
+ prs_mem_free(&buf );
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(new_spoolss_io_r_enumports("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPORTS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Jobs
+****************************************************************************/
+uint32 spoolss_enum_jobs(const POLICY_HND *hnd, uint32 firstjob, uint32 numofjobs,
+ uint32 level, NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMJOBS q_o;
+ SPOOL_R_ENUMJOBS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Jobs level: %d)\n", level));
+
+ make_spoolss_q_enumjobs(&q_o, hnd, firstjob, numofjobs, level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumjobs("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_ENUMJOBS, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_enumjobs("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMJOBS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/***************************************************************************
+do a SPOOLSS Enum printer datas
+****************************************************************************/
+uint32 spoolss_enum_printerdata(const POLICY_HND *hnd, uint32 idx,
+ uint32 *valuelen, uint16 *value, uint32 *rvaluelen,
+ uint32 *type, uint32 *datalen, uint8 *data,
+ uint32 *rdatalen)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERDATA q_o;
+ SPOOL_R_ENUMPRINTERDATA r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPRINTERDATA*/
+
+ DEBUG(4,("SPOOLSS Enum Printer data\n"));
+
+ make_spoolss_q_enumprinterdata(&q_o, hnd, idx, *valuelen, *datalen);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinterdata("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_ENUMPRINTERDATA, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.data=data;
+ r_o.value=value;
+
+ if(spoolss_io_r_enumprinterdata("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPRINTERDATA: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *valuelen=r_o.valuesize;
+ *rvaluelen=r_o.realvaluesize;
+ *type=r_o.type;
+ *datalen=r_o.datasize;
+ *rdatalen=r_o.realdatasize;
+
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum printer datas
+****************************************************************************/
+uint32 spoolss_getprinter(const POLICY_HND *hnd, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTER q_o;
+ SPOOL_R_GETPRINTER r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Printer data)\n"));
+
+ make_spoolss_q_getprinter(&q_o, hnd, level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinter("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTER, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(!spoolss_io_r_getprinter("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTER: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum printer driver
+****************************************************************************/
+uint32 spoolss_getprinterdriver(const POLICY_HND *hnd,
+ const char *environment, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDRIVER2 q_o;
+ SPOOL_R_GETPRINTERDRIVER2 r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Printer driver)\n"));
+
+ make_spoolss_q_getprinterdriver2(&q_o, hnd, environment, level, 2, 0, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdriver2("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTERDRIVER2, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_getprinterdriver2("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDRIVER2: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+
+
+/****************************************************************************
+do a SPOOLSS Open Printer Ex
+****************************************************************************/
+BOOL spoolss_open_printer_ex( const char *printername,
+ const char *datatype, uint32 access_required,
+ const char *station, const char *username,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_OPEN_PRINTER_EX q_o;
+ BOOL valid_pol = False;
+ fstring srv_name;
+ char *s = NULL;
+ struct cli_connection *con = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ memset(srv_name, 0, sizeof(srv_name));
+ fstrcpy(srv_name, printername);
+
+ s = strchr_m(&srv_name[2], '\\');
+ if (s != NULL)
+ *s = '\0';
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ if (hnd == NULL)
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_OPENPRINTEREX */
+
+ DEBUG(5,("SPOOLSS Open Printer Ex\n"));
+
+ make_spoolss_q_open_printer_ex(&q_o, printername, datatype,
+ access_required, station, username);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_open_printer_ex("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_OPENPRINTEREX, &buf, &rbuf))
+ {
+ SPOOL_R_OPEN_PRINTER_EX r_o;
+ BOOL p = True;
+
+ spoolss_io_r_open_printer_ex("", &r_o, &rbuf, 0);
+
+ if (prs_offset(&rbuf)!= 0 && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_OPENPRINTEREX: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.handle;
+
+ /* associate the handle returned with the current
+ state of the clienjt connection */
+ valid_pol = RpcHndList_set_connection(hnd, con);
+
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return valid_pol;
+}
+
+/****************************************************************************
+ do a SPOOLSS AddPrinterEx()
+ **ALWAYS** uses as PRINTER_INFO level 2 struct
+****************************************************************************/
+BOOL spoolss_addprinterex(POLICY_HND *hnd, const char* srv_name, PRINTER_INFO_2 *info2)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ADDPRINTEREX q_o;
+ SPOOL_R_ADDPRINTEREX r_o;
+ struct cli_connection *con = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ fstring the_client_name;
+ BOOL valid_pol = True;
+
+
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("spoolss_addprinterex: talloc_init() failed!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPORTS */
+ DEBUG(5,("SPOOLSS Add Printer Ex (Server: %s)\n", srv_name));
+
+ fstrcpy(the_client_name, "\\\\");
+ fstrcat(the_client_name, con->pCli_state->desthost);
+ strupper(the_client_name);
+
+
+ make_spoolss_q_addprinterex(mem_ctx, &q_o, srv_name, the_client_name,
+ /* "Administrator", */
+ con->pCli_state->user_name,
+ 2, info2);
+
+ /* turn parameters into data stream and send the request */
+ if (spoolss_io_q_addprinterex("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ADDPRINTEREX, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ if(spoolss_io_r_addprinterex("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ADDPRINTEREX: %s\n", get_nt_error_msg(r_o.status)));
+ valid_pol = False;
+ }
+ }
+
+ if (valid_pol)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ copy_policy_hnd( hnd, &r_o.handle);
+
+ /* associate the handle returned with the current
+ state of the clienjt connection */
+ RpcHndList_set_connection(hnd, con);
+ }
+ }
+
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return valid_pol;
+}
+
+/****************************************************************************
+do a SPOOL Close
+****************************************************************************/
+BOOL spoolss_closeprinter(POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_CLOSEPRINTER q_c;
+ BOOL valid_close = False;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SPOOLSS_CLOSEPRINTER */
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SPOOL Close Printer\n"));
+
+ /* store the parameters */
+ make_spoolss_q_closeprinter(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_closeprinter("", &q_c, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_CLOSEPRINTER, &buf, &rbuf))
+ {
+ SPOOL_R_CLOSEPRINTER r_c;
+
+ spoolss_io_r_closeprinter("", &r_c, &rbuf, 0);
+
+ if (prs_offset(&rbuf)!=0 && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOL_CLOSEPRINTER: %s\n", get_nt_error_msg(r_c.status)));
+ }
+ else
+ valid_close = True;
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ /* disassociate with the cli_connection */
+ RpcHndList_del_connection(hnd);
+
+ return valid_close;
+}
+
+/****************************************************************************
+do a SPOOLSS Get printer datas
+****************************************************************************/
+uint32 spoolss_getprinterdata(const POLICY_HND *hnd, const UNISTR2 *valuename,
+ uint32 in_size,
+ uint32 *type,
+ uint32 *out_size,
+ uint8 *data,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDATA q_o;
+ SPOOL_R_GETPRINTERDATA r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_GETPRINTERDATA */
+
+ DEBUG(5,("SPOOLSS Get Printer data)\n"));
+
+ make_spoolss_q_getprinterdata(&q_o, hnd,(UNISTR2 *)valuename, in_size);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdata("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTERDATA, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.data=data;
+
+ if(spoolss_io_r_getprinterdata("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDATA: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *type=r_o.type;
+ *out_size=r_o.size;
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Get Printer Driver Direcotry
+****************************************************************************/
+uint32 spoolss_getprinterdriverdir(fstring srv_name, fstring env_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDRIVERDIR q_o;
+ SPOOL_R_GETPRINTERDRIVERDIR r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS GetPrinterDriverDir (Server: %s Env: %s level: %d)\n",
+ srv_name, env_name, level));
+
+ make_spoolss_q_getprinterdriverdir(&q_o, srv_name, env_name, level,
+ buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdriverdir("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_GETPRINTERDRIVERDIRECTORY, &buf, &rbuf))
+ {
+ prs_mem_free(&buf );
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_getprinterdriverdir("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDRIVERDIRECTORY: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/******************************************************************************
+ AddPrinterDriver()
+ *****************************************************************************/
+uint32 spoolss_addprinterdriver(const char *srv_name, uint32 level, PRINTER_DRIVER_CTR *info)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ADDPRINTERDRIVER q_o;
+ SPOOL_R_ADDPRINTERDRIVER r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* make the ADDPRINTERDRIVER PDU */
+ make_spoolss_q_addprinterdriver(mem_ctx, &q_o, srv_name, level, info);
+
+ /* turn the data into an io stream */
+ if (spoolss_io_q_addprinterdriver("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ADDPRINTERDRIVER, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ if(spoolss_io_r_addprinterdriver("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ADDPRINTERDRIVER: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ }
+ }
+
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return r_o.status;
+
+}
diff --git a/source/rpc_client/cli_spoolss_notify.c b/source/rpc_client/cli_spoolss_notify.c
new file mode 100644
index 00000000000..2f89e200d21
--- /dev/null
+++ b/source/rpc_client/cli_spoolss_notify.c
@@ -0,0 +1,293 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean Francois Micouleau 1998-2000,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "rpc_parse.h"
+#include "nterr.h"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Disconnect from the client machine.
+**********************************************************/
+BOOL spoolss_disconnect_from_client( struct cli_state *cli)
+{
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+
+ return True;
+}
+
+
+/*********************************************************
+ Connect to the client machine.
+**********************************************************/
+
+BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine)
+{
+ ZERO_STRUCTP(cli);
+ if(cli_initialise(cli) == NULL) {
+ DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli->dest_ip, 0x20)) {
+ DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (ismyip(cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_connect(cli, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(cli, global_myname, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request. Error was %s\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(cli)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (cli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!(cli->sec_mode & 1)) {
+ DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_nt_session_open(cli, PIPE_SPOOLSS) == False) {
+ DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_open_printer(struct cli_state *cli, char *printer, uint32 localprinter, uint32 type, WERROR *status, POLICY_HND *handle)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYOPENPRINTER q_s;
+ SPOOL_R_REPLYOPENPRINTER r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_replyopenprinter(&q_s, printer, localprinter, type);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replyopenprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYOPENPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replyopenprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ memcpy(handle, &r_s.handle, sizeof(r_s.handle));
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_rrpcn(struct cli_state *cli, POLICY_HND *handle,
+ uint32 change_low, uint32 change_high, WERROR *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLY_RRPCN q_s;
+ SPOOL_R_REPLY_RRPCN r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_rrpcn(&q_s, handle, change_low, change_high);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_reply_rrpcn("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_close_printer(struct cli_state *cli, POLICY_HND *handle,
+ WERROR *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYCLOSEPRINTER q_s;
+ SPOOL_R_REPLYCLOSEPRINTER r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_closeprinter(&q_s, handle);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replycloseprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYCLOSEPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replycloseprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
diff --git a/source/rpc_client/cli_srvsvc.c b/source/rpc_client/cli_srvsvc.c
new file mode 100644
index 00000000000..50f2eeb1583
--- /dev/null
+++ b/source/rpc_client/cli_srvsvc.c
@@ -0,0 +1,401 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/****************************************************************************
+do a server net conn enum
+****************************************************************************/
+BOOL do_srv_net_srv_conn_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_CONN_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_CONN_ENUM q_o;
+ SRV_R_NET_CONN_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETCONNENUM */
+
+ DEBUG(4,("SRV Net Server Connection Enum(%s, %s), level %d, enum:%8x\n",
+ server_name, qual_name, switch_value, get_enum_hnd(hnd)));
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_conn_ctr = 1;
+ ctr->conn.info0.num_entries_read = 0;
+ ctr->conn.info0.ptr_conn_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_conn_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_conn_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if(!rpc_api_pipe_req(cli, SRV_NETCONNENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_conn_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_CONN_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_CONN_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net sess enum
+****************************************************************************/
+
+BOOL do_srv_net_srv_sess_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_SESS_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SESS_ENUM q_o;
+ SRV_R_NET_SESS_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETSESSENUM */
+
+ DEBUG(4,("SRV Net Session Enum (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_sess_ctr = 1;
+ ctr->sess.info0.num_entries_read = 0;
+ ctr->sess.info0.ptr_sess_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_sess_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_sess_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETSESSENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_sess_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_SESS_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_SESS_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net share enum
+****************************************************************************/
+BOOL do_srv_net_srv_share_enum(struct cli_state *cli,
+ char *server_name,
+ uint32 switch_value, SRV_R_NET_SHARE_ENUM *r_o,
+ uint32 preferred_len, ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SHARE_ENUM q_o;
+
+ if (server_name == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETSHAREENUM */
+
+ DEBUG(4,("SRV Get Share Info (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ /* store the parameters */
+ init_srv_q_net_share_enum(&q_o, server_name, switch_value,
+ preferred_len, hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_share_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETSHAREENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!srv_io_r_net_share_enum("", r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o->status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SHARE_ENUM: %s\n", get_nt_error_msg(r_o->status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o->ctr.switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SHARE_ENUM: info class %d does not match request %d\n",
+ r_o->ctr.switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net file enum
+****************************************************************************/
+
+BOOL do_srv_net_srv_file_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_FILE_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_FILE_ENUM q_o;
+ SRV_R_NET_FILE_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETFILEENUM */
+
+ DEBUG(4,("SRV Get File Info (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ q_o.file_level = switch_value;
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_file_ctr = 1;
+ ctr->file.info3.num_entries_read = 0;
+ ctr->file.info3.ptr_file_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_file_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_file_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETFILEENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_file_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_FILE_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_FILE_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server get info
+****************************************************************************/
+BOOL do_srv_net_srv_get_info(struct cli_state *cli,
+ char *server_name, uint32 switch_value, SRV_INFO_CTR *ctr)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SRV_GET_INFO q_o;
+ SRV_R_NET_SRV_GET_INFO r_o;
+
+ if (server_name == NULL || switch_value == 0 || ctr == NULL)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NET_SRV_GET_INFO */
+
+ DEBUG(4,("SRV Get Server Info (%s), level %d\n", server_name, switch_value));
+
+ /* store the parameters */
+ init_srv_q_net_srv_get_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_srv_get_info("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NET_SRV_GET_INFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_srv_get_info("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != q_o.switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, q_o.switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_trust.c b/source/rpc_client/cli_trust.c
new file mode 100644
index 00000000000..5322c4756fc
--- /dev/null
+++ b/source/rpc_client/cli_trust.c
@@ -0,0 +1,152 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ * Copyright (C) Andrew Bartlett 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Change the domain password on the PDC.
+**********************************************************/
+
+static NTSTATUS modify_trust_password( char *domain, char *remote_machine,
+ unsigned char orig_trust_passwd_hash[16])
+{
+ struct cli_state *cli;
+ DOM_SID domain_sid;
+ struct in_addr dest_ip;
+ NTSTATUS nt_status;
+
+ /*
+ * Ensure we have the domain SID for this domain.
+ */
+
+ if (!secrets_fetch_domain_sid(domain, &domain_sid)) {
+ DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
+ DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname, remote_machine,
+ &dest_ip, 0,
+ "IPC$", "IPC",
+ "", "",
+ "", 0))) {
+ DEBUG(0,("modify_trust_password: Connection to %s failed!\n", remote_machine));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_nt_session_open(cli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("modify_trust_password: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ nt_status = trust_pw_change_and_store_it(cli, cli->mem_ctx,
+ orig_trust_passwd_hash);
+
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return nt_status;
+}
+
+/************************************************************************
+ Change the trust account password for a domain.
+************************************************************************/
+
+NTSTATUS change_trust_account_password( char *domain, char *remote_machine_list)
+{
+ fstring remote_machine;
+ unsigned char old_trust_passwd_hash[16];
+ time_t lct;
+ NTSTATUS res = NT_STATUS_UNSUCCESSFUL;
+
+ if(!secrets_fetch_trust_account_password(domain, old_trust_passwd_hash, &lct)) {
+ DEBUG(0,("change_trust_account_password: unable to read the machine \
+account password for domain %s.\n", domain));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ while(remote_machine_list &&
+ next_token(&remote_machine_list, remote_machine,
+ LIST_SEP, sizeof(remote_machine))) {
+ strupper(remote_machine);
+ if(strequal(remote_machine, "*")) {
+
+ /*
+ * We have been asked to dynamcially determine the IP addresses of the PDC.
+ */
+
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+
+ /* Use the PDC *only* for this. */
+ if(!get_dc_list(True, domain, &ip_list, &count))
+ continue;
+
+ /*
+ * Try and connect to the PDC/BDC list in turn as an IP
+ * address used as a string.
+ */
+
+ for(i = 0; i < count; i++) {
+ fstring dc_name;
+ if(!lookup_dc_name(global_myname, domain, &ip_list[i], dc_name))
+ continue;
+ if(NT_STATUS_IS_OK(res = modify_trust_password( domain, dc_name,
+ old_trust_passwd_hash)))
+ break;
+ }
+
+ SAFE_FREE(ip_list);
+
+ } else {
+ res = modify_trust_password( domain, remote_machine,
+ old_trust_passwd_hash);
+ }
+
+ }
+
+ if (!NT_STATUS_IS_OK(res)) {
+ DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
+domain %s.\n", timestring(False), domain));
+ }
+
+ return res;
+}
diff --git a/source/rpc_client/cli_wkssvc.c b/source/rpc_client/cli_wkssvc.c
new file mode 100644
index 00000000000..745542e6513
--- /dev/null
+++ b/source/rpc_client/cli_wkssvc.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/****************************************************************************
+do a WKS Open Policy
+****************************************************************************/
+BOOL do_wks_query_info(struct cli_state *cli,
+ char *server_name, uint32 switch_value,
+ WKS_INFO_100 *wks100)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ WKS_Q_QUERY_INFO q_o;
+ WKS_R_QUERY_INFO r_o;
+
+ if (server_name == 0 || wks100 == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api WKS_QUERY_INFO */
+
+ DEBUG(4,("WKS Query Info\n"));
+
+ /* store the parameters */
+ init_wks_q_query_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ if(!wks_io_q_query_info("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ r_o.wks100 = wks100;
+
+ if(!wks_io_r_query_info("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("WKS_R_QUERY_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
diff --git a/source/rpc_client/msrpc_spoolss.c b/source/rpc_client/msrpc_spoolss.c
new file mode 100644
index 00000000000..3baec6c569b
--- /dev/null
+++ b/source/rpc_client/msrpc_spoolss.c
@@ -0,0 +1,810 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Jean-Francois Micouleau 1999-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "nterr.h"
+#include "rpc_parse.h"
+#include "rpcclient.h"
+
+#define DEBUG_TESTING
+
+extern FILE* out_hnd;
+
+extern struct user_creds *usr_creds;
+
+/********************************************************************
+initialize a spoolss NEW_BUFFER.
+********************************************************************/
+void init_buffer(NEW_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
+{
+ buffer->ptr = (size!=0)? 1:0;
+ buffer->size=size;
+ buffer->string_at_end=size;
+ prs_init(&buffer->prs, size, ctx, MARSHALL);
+ buffer->struct_start = prs_offset(&buffer->prs);
+}
+
+static void decode_printer_info_0(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_0 **info)
+{
+ uint32 i;
+ PRINTER_INFO_0 *inf;
+
+ inf=(PRINTER_INFO_0 *)malloc(returned*sizeof(PRINTER_INFO_0));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_0("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_1(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_1 **info)
+{
+ uint32 i;
+ PRINTER_INFO_1 *inf;
+
+ inf=(PRINTER_INFO_1 *)malloc(returned*sizeof(PRINTER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_2(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_2 **info)
+{
+ uint32 i;
+ PRINTER_INFO_2 *inf;
+
+ inf=(PRINTER_INFO_2 *)malloc(returned*sizeof(PRINTER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ /* a little initialization as we go */
+ inf[i].secdesc = NULL;
+ new_smb_io_printer_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_3(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_3 **info)
+{
+ uint32 i;
+ PRINTER_INFO_3 *inf;
+
+ inf=(PRINTER_INFO_3 *)malloc(returned*sizeof(PRINTER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_1(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_1 **info)
+{
+ uint32 i;
+ DRIVER_INFO_1 *inf;
+
+ inf=(DRIVER_INFO_1 *)malloc(returned*sizeof(DRIVER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_2(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_2 **info)
+{
+ uint32 i;
+ DRIVER_INFO_2 *inf;
+
+ inf=(DRIVER_INFO_2 *)malloc(returned*sizeof(DRIVER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_3(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_3 **info)
+{
+ uint32 i;
+ DRIVER_INFO_3 *inf;
+
+ inf=(DRIVER_INFO_3 *)malloc(returned*sizeof(DRIVER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printerdriverdir_info_1(NEW_BUFFER *buffer, DRIVER_DIRECTORY_1 *info)
+{
+/* DRIVER_DIRECTORY_1 *inf;
+
+ inf=(DRIVER_DIRECTORY_1 *)malloc(returned*sizeof(DRIVER_DIRECTORY_1));
+*/
+ prs_set_offset(&buffer->prs, 0);
+
+ new_smb_io_driverdir_1("", buffer, info, 0);
+
+/* *info=inf;*/
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_1 struct from a NEW_BUFFER
+**********************************************************************/
+void decode_port_info_1(NEW_BUFFER *buffer, uint32 returned,
+ PORT_INFO_1 **info)
+{
+ uint32 i;
+ PORT_INFO_1 *inf;
+
+ inf=(PORT_INFO_1*)malloc(returned*sizeof(PORT_INFO_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_port_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_2 struct from a NEW_BUFFER
+**********************************************************************/
+void decode_port_info_2(NEW_BUFFER *buffer, uint32 returned,
+ PORT_INFO_2 **info)
+{
+ uint32 i;
+ PORT_INFO_2 *inf;
+
+ inf=(PORT_INFO_2*)malloc(returned*sizeof(PORT_INFO_2));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_port_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_printers(char* srv_name, uint32 flags,
+ uint32 level, PRINTER_INFO_CTR ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_printers: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_enum_printers(flags, srv_name, level, &buffer, 0,
+ &needed, &returned);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_enum_printers(flags, srv_name, level, &buffer,
+ needed, &needed, &returned);
+ }
+
+ if (status!=NT_STATUS_OK)
+ {
+ DEBUG(0,("spoolss_enum_printers: %s\n", get_nt_error_msg(status)));
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* is there anything to process? */
+ if (returned != 0)
+ {
+ switch (level) {
+ case 1:
+ decode_printer_info_1(&buffer, returned, &(ctr.printers_1));
+ break;
+ case 2:
+ decode_printer_info_2(&buffer, returned, &(ctr.printers_2));
+ break;
+ case 3:
+ decode_printer_info_3(&buffer, returned, &(ctr.printers_3));
+ break;
+ }
+
+ display_printer_info_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_ports(char* srv_name,
+ uint32 level, PORT_INFO_CTR *ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_ports: talloc_init failed!\n"));
+ return False;
+ }
+
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_enum_ports(srv_name, level, &buffer, 0,
+ &needed, &returned);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_enum_ports(srv_name, level, &buffer,
+ needed, &needed, &returned);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* is there anything to process? */
+ if (returned != 0)
+ {
+ switch (level) {
+ case 1:
+ decode_port_info_1(&buffer, returned, &ctr->port.info_1);
+ break;
+ case 2:
+ decode_port_info_2(&buffer, returned, &ctr->port.info_2);
+ break;
+ default:
+ DEBUG(0,("Unable to decode unknown PORT_INFO_%d\n", level));
+ break;
+ }
+
+ display_port_info_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_port_info_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_port_info_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+ }
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+uint32 msrpc_spoolss_getprinterdata( const char* printer_name,
+ const char* station,
+ const char* user_name,
+ const char* value_name,
+ uint32 *type,
+ NEW_BUFFER *buffer,
+ void *fn)
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ uint32 needed;
+ uint32 size;
+ char *data;
+ UNISTR2 uni_val_name;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolgetdata - printer: %s server: %s user: %s value: %s\n",
+ printer_name, station, user_name, value_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name,
+ &hnd))
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ init_unistr2(&uni_val_name, value_name, 0);
+ size = 0;
+ data = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdata: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(buffer, size, mem_ctx);
+
+ status = spoolss_getprinterdata(&hnd, &uni_val_name, size, type, &size,
+ (unsigned char *)data, &needed);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ size = needed;
+ init_buffer(buffer, size, mem_ctx);
+ data = prs_data_p(&buffer->prs);
+ status = spoolss_getprinterdata(&hnd, &uni_val_name,
+ size, type, &size,
+ (unsigned char *)data, &needed);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status != NT_STATUS_OK)
+ {
+ if (!spoolss_closeprinter(&hnd))
+ return NT_STATUS_ACCESS_DENIED;
+ return status;
+ }
+
+#if 0
+ if (fn != NULL)
+ fn(printer_name, station, level, returned, *ctr);
+#endif
+
+ return status;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_jobs( const char* printer_name,
+ const char* station, const char* user_name,
+ uint32 level,
+ void ***ctr, JOB_INFO_FN(fn))
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ uint32 firstjob=0;
+ uint32 numofjobs=0xffff;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolopen - printer: %s server: %s user: %s\n",
+ printer_name, station, user_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+ status = spoolss_enum_jobs(&hnd, firstjob, numofjobs, level,
+ &buffer, 0, &needed, &returned);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_enum_jobs( &hnd, firstjob, numofjobs, level,
+ &buffer, needed, &needed, &returned);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ if (fn != NULL)
+ fn(printer_name, station, level, returned, *ctr);
+
+ return True;
+}
+
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_printerdata( const char* printer_name,
+ const char* station, const char* user_name )
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ uint32 idx;
+ uint32 valuelen;
+ uint16 *value;
+ uint32 rvaluelen;
+ uint32 type;
+ uint32 datalen;
+ uint8 *data;
+ uint32 rdatalen;
+ uint32 maxvaluelen;
+ uint32 maxdatalen;
+
+ DEBUG(4,("msrpc_spoolss_enum_printerdata - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name, &hnd))
+ return False;
+
+
+ idx=0;
+ valuelen=0;
+ rvaluelen=0;
+ type=0;
+ datalen=0;
+ rdatalen=0;
+
+ status = spoolss_enum_printerdata(&hnd, idx, &valuelen, value,
+ &rvaluelen, &type, &datalen,
+ data, &rdatalen);
+
+ DEBUG(4,("spoolenum_printerdata - got size: biggest value:[%d], biggest data:[%d]\n", rvaluelen, rdatalen));
+
+ maxvaluelen=valuelen=rvaluelen;
+ maxdatalen=datalen=rdatalen;
+
+ value=(uint16 *)malloc(valuelen*sizeof(uint16));
+ data=(uint8 *)malloc(datalen*sizeof(uint8));
+
+ display_printer_enumdata(out_hnd, ACTION_HEADER, idx, valuelen,
+ value, rvaluelen, type, datalen, data, rdatalen);
+
+ do {
+ valuelen=maxvaluelen;
+ datalen=maxdatalen;
+
+ status = spoolss_enum_printerdata(&hnd, idx, &valuelen,
+ value, &rvaluelen, &type,
+ &datalen, data, &rdatalen);
+ display_printer_enumdata(out_hnd, ACTION_ENUMERATE, idx,
+ valuelen, value, rvaluelen, type,
+ datalen, data, rdatalen);
+ idx++;
+
+ } while (status != 0x0103); /* NO_MORE_ITEMS */
+
+ display_printer_enumdata(out_hnd, ACTION_FOOTER, idx, valuelen,
+ value, rvaluelen, type, datalen, data, rdatalen);
+
+
+ if (status!=NT_STATUS_OK) {
+ /*
+ * the check on this if statement is redundant
+ * since is the status is bad we're going to
+ * return False anyways. The caller will be
+ * unable to determine if there really was a problem
+ * with the spoolss_closeprinter() call --jerry
+ */
+ spoolss_closeprinter(&hnd);
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinter( const char* printer_name, const uint32 level,
+ const char* station, const char* user_name,
+ PRINTER_INFO_CTR ctr)
+{
+ POLICY_HND hnd;
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed=1000;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolenum_getprinter - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, "", PRINTER_ALL_ACCESS, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinter: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, needed, mem_ctx);
+
+ status = spoolss_getprinter(&hnd, level, &buffer, needed, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_getprinter(&hnd, level, &buffer, needed, &needed);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 0:
+ decode_printer_info_0(&buffer, 1, &(ctr.printers_0));
+ break;
+ case 1:
+ decode_printer_info_1(&buffer, 1, &(ctr.printers_1));
+ break;
+ case 2:
+ decode_printer_info_2(&buffer, 1, &(ctr.printers_2));
+ break;
+ case 3:
+ decode_printer_info_3(&buffer, 1, &(ctr.printers_3));
+ break;
+ }
+
+ display_printer_info_ctr(out_hnd, ACTION_HEADER , level, 1, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_ENUMERATE, level, 1, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_FOOTER , level, 1, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinterdriver( const char* printer_name,
+ const char *environment, const uint32 level,
+ const char* station, const char* user_name,
+ PRINTER_DRIVER_CTR ctr)
+{
+ POLICY_HND hnd;
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("msrpc_spoolss_enum_getprinterdriver - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, "", PRINTER_ALL_ACCESS, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdriver: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ status = spoolss_getprinterdriver(&hnd, environment, level, &buffer, 0, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_getprinterdriver(&hnd, environment, level, &buffer, needed, &needed);
+ }
+
+ /* report(out_hnd, "\tstatus:[%d (%x)]\n", status, status); */
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 1:
+ decode_printer_driver_1(&buffer, 1, &(ctr.info1));
+ break;
+ case 2:
+ decode_printer_driver_2(&buffer, 1, &(ctr.info2));
+ break;
+ case 3:
+ decode_printer_driver_3(&buffer, 1, &(ctr.info3));
+ break;
+ }
+
+ display_printer_driver_ctr(out_hnd, ACTION_HEADER , level, 1, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_ENUMERATE, level, 1, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_FOOTER , level, 1, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enumprinterdrivers( const char* srv_name,
+ const char *environment, const uint32 level,
+ PRINTER_DRIVER_CTR ctr)
+{
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("msrpc_spoolss_enum_enumprinterdrivers - server: %s\n", srv_name));
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enumprinterdrivers: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ status = spoolss_enum_printerdrivers(srv_name, environment,
+ level, &buffer, 0, &needed, &returned);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_enum_printerdrivers( srv_name, environment,
+ level, &buffer, needed, &needed, &returned);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level)
+ {
+ case 1:
+ decode_printer_driver_1(&buffer, returned, &(ctr.info1));
+ break;
+ case 2:
+ decode_printer_driver_2(&buffer, returned, &(ctr.info2));
+ break;
+ case 3:
+ decode_printer_driver_3(&buffer, returned, &(ctr.info3));
+ break;
+ }
+
+ display_printer_driver_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinterdriverdir(char* srv_name, char* env_name, uint32 level, DRIVER_DIRECTORY_CTR ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdriverdir: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_getprinterdriverdir(srv_name, env_name, level, &buffer, 0, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_getprinterdriverdir(srv_name, env_name, level, &buffer, needed, &needed);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 1:
+ decode_printerdriverdir_info_1(&buffer, &(ctr.driver.info_1));
+ break;
+ }
+
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_HEADER , level, ctr);
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_ENUMERATE, level, ctr);
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_FOOTER , level, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
diff --git a/source/rpc_client/ntclienttrust.c b/source/rpc_client/ntclienttrust.c
new file mode 100644
index 00000000000..9518c6a4857
--- /dev/null
+++ b/source/rpc_client/ntclienttrust.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/************************************************************************
+ check workstation trust account status
+ ************************************************************************/
+BOOL trust_account_check(struct in_addr dest_ip, char *dest_host,
+ char *hostname, char *domain, fstring mach_acct,
+ fstring new_mach_pwd)
+{
+ pstring tmp;
+ fstring mach_pwd;
+ struct cli_state cli_trust;
+ uchar lm_owf_mach_pwd[16];
+ uchar nt_owf_mach_pwd[16];
+ uchar lm_sess_pwd[24];
+ uchar nt_sess_pwd[24];
+
+ BOOL right_error_code = False;
+ uint8 err_cls;
+ uint32 err_num;
+
+ char *start_mach_pwd;
+ char *change_mach_pwd;
+
+ /* initial machine password */
+ fstrcpy(mach_pwd, hostname);
+ strlower(mach_pwd);
+
+ slprintf(tmp, sizeof(tmp) - 1,"Enter Workstation Trust Account password for [%s].\nDefault is [%s].\nPassword:",
+ mach_acct, mach_pwd);
+
+ start_mach_pwd = (char*)getpass(tmp);
+
+ if (start_mach_pwd[0] != 0)
+ {
+ fstrcpy(mach_pwd, start_mach_pwd);
+ }
+
+ slprintf(tmp, sizeof(tmp)-1, "Enter new Workstation Trust Account password for [%s]\nPress Return to leave at old value.\nNew Password:",
+ mach_acct);
+
+ change_mach_pwd = (char*)getpass(tmp);
+
+ if (change_mach_pwd[0] != 0)
+ {
+ fstrcpy(new_mach_pwd, change_mach_pwd);
+ }
+ else
+ {
+ DEBUG(1,("trust_account_check: password change not requested\n"));
+ change_mach_pwd[0] = 0;
+ }
+
+ DEBUG(1,("initialise cli_trust connection\n"));
+
+ if (!cli_initialise(&cli_trust))
+ {
+ DEBUG(1,("cli_initialise failed for cli_trust\n"));
+ return False;
+ }
+
+ DEBUG(1,("server connect for cli_trust\n"));
+
+ if (!server_connect_init(&cli_trust, hostname, dest_ip, dest_host))
+ {
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
+ DEBUG(1,("server_connect_init failed (%s)\n", cli_errstr(&cli_trust)));
+
+ cli_shutdown(&cli_trust);
+ return False;
+ }
+
+ DEBUG(1,("server connect cli_trust succeeded\n"));
+
+ nt_lm_owf_gen(mach_pwd, nt_owf_mach_pwd, lm_owf_mach_pwd);
+
+ DEBUG(5,("generating nt owf from initial machine pwd: %s\n", mach_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("client cryptkey: "));
+ dump_data(100, cli_trust.cryptkey, sizeof(cli_trust.cryptkey));
+#endif
+
+ SMBencrypt(nt_owf_mach_pwd, cli_trust.cryptkey, nt_sess_pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_owf_mach_pwd: "));
+ dump_data(100, nt_owf_mach_pwd, sizeof(lm_owf_mach_pwd));
+ DEBUG(100,("nt_sess_pwd: "));
+ dump_data(100, nt_sess_pwd, sizeof(nt_sess_pwd));
+#endif
+
+ SMBencrypt(lm_owf_mach_pwd, cli_trust.cryptkey, lm_sess_pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm_owf_mach_pwd: "));
+ dump_data(100, lm_owf_mach_pwd, sizeof(lm_owf_mach_pwd));
+ DEBUG(100,("lm_sess_pwd: "));
+ dump_data(100, lm_sess_pwd, sizeof(lm_sess_pwd));
+#endif
+
+ right_error_code = False;
+
+ if (cli_session_setup(&cli_trust, mach_acct,
+ nt_owf_mach_pwd, sizeof(nt_owf_mach_pwd),
+ nt_owf_mach_pwd, sizeof(nt_owf_mach_pwd), domain))
+ {
+ DEBUG(0,("cli_session_setup: NO ERROR! AAAGH! BUG IN SERVER DETECTED!!!\n"));
+ cli_shutdown(&cli_trust);
+
+ return False;
+ }
+
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
+
+ if (err_num == (0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT))
+ {
+ DEBUG(1,("cli_send_tconX: valid workstation trust account exists\n"));
+ right_error_code = True;
+ }
+
+ if (err_num == (0xC0000000 | NT_STATUS_NO_SUCH_USER))
+ {
+ DEBUG(1,("cli_send_tconX: workstation trust account does not exist\n"));
+ right_error_code = False;
+ }
+
+ if (!right_error_code)
+ {
+ DEBUG(1,("server_validate failed (%s)\n", cli_errstr(&cli_trust)));
+ }
+
+ cli_shutdown(&cli_trust);
+ return right_error_code;
+}
diff --git a/source/rpc_parse/.cvsignore b/source/rpc_parse/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/rpc_parse/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/rpc_parse/parse_dfs.c b/source/rpc_parse/parse_dfs.c
new file mode 100644
index 00000000000..a152e3528e3
--- /dev/null
+++ b/source/rpc_parse/parse_dfs.c
@@ -0,0 +1,543 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * MSDfs RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Shirish Kalele 2000.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "nterr.h"
+#include "rpc_parse.h"
+
+/*******************************************************************
+Make a DFS_Q_DFS_QUERY structure
+*******************************************************************/
+
+void init_dfs_q_dfs_exist(DFS_Q_DFS_EXIST *q_d)
+{
+ q_d->dummy = 0;
+}
+
+/*************************************************************
+ Read/write a DFS_Q_DFS_EXIST structure - dummy...
+ ************************************************************/
+
+BOOL dfs_io_q_dfs_exist(char *desc, DFS_Q_DFS_EXIST *q_d, prs_struct *ps, int depth)
+{
+ if(q_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_q_dfs_exist");
+
+ return True;
+}
+
+/*************************************************************
+ Read/write a DFS_R_DFS_EXIST structure
+ ************************************************************/
+
+BOOL dfs_io_r_dfs_exist(char *desc, DFS_R_DFS_EXIST *q_d, prs_struct *ps, int depth)
+{
+ if(q_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_r_dfs_exist");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("exist flag", ps, 0, &q_d->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+Make a DFS_Q_DFS_REMOVE structure
+*******************************************************************/
+
+BOOL init_dfs_q_dfs_remove(DFS_Q_DFS_REMOVE *q_d, char *entrypath,
+ char *servername, char *sharename)
+{
+ DEBUG(5,("init_dfs_q_dfs_remove\n"));
+ init_unistr2(&q_d->DfsEntryPath, entrypath, strlen(entrypath)+1);
+ init_unistr2(&q_d->ServerName, servername, strlen(servername)+1);
+ init_unistr2(&q_d->ShareName, sharename, strlen(sharename)+1);
+ q_d->ptr_ServerName = q_d->ptr_ShareName = 1;
+ return True;
+}
+
+/*******************************************************************
+Read/write a DFS_Q_DFS_REMOVE structure
+*******************************************************************/
+
+BOOL dfs_io_q_dfs_remove(char *desc, DFS_Q_DFS_REMOVE *q_d, prs_struct *ps, int depth)
+{
+ if(q_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_q_dfs_remove");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("DfsEntryPath",&q_d->DfsEntryPath, 1, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_ServerName", ps, depth, &q_d->ptr_ServerName))
+ return False;
+ if(q_d->ptr_ServerName)
+ if (!smb_io_unistr2("ServerName",&q_d->ServerName, q_d->ptr_ServerName, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName))
+ return False;
+ if(q_d->ptr_ShareName)
+ if (!smb_io_unistr2("ShareName",&q_d->ShareName, q_d->ptr_ShareName, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+Read/write a DFS_R_DFS_REMOVE structure
+*******************************************************************/
+
+BOOL dfs_io_r_dfs_remove(char *desc, DFS_R_DFS_REMOVE *r_d, prs_struct *ps, int depth)
+{
+ if(r_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_r_dfs_remove");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &r_d->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+Make a DFS_Q_DFS_ADD structure
+*******************************************************************/
+
+BOOL init_dfs_q_dfs_add(DFS_Q_DFS_ADD *q_d, char *entrypath, char *servername,
+ char *sharename, char *comment, uint32 flags)
+{
+ DEBUG(5,("init_dfs_q_dfs_add\n"));
+ q_d->ptr_DfsEntryPath = q_d->ptr_ServerName = q_d->ptr_ShareName = 1;
+ init_unistr2(&q_d->DfsEntryPath, entrypath, strlen(entrypath)+1);
+ init_unistr2(&q_d->ServerName, servername, strlen(servername)+1);
+ init_unistr2(&q_d->ShareName, sharename, strlen(sharename)+1);
+ if(comment != NULL) {
+ init_unistr2(&q_d->Comment, comment, strlen(comment)+1);
+ q_d->ptr_Comment = 1;
+ } else {
+ q_d->ptr_Comment = 0;
+ }
+
+ q_d->Flags = flags;
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_Q_DFS_ADD structure
+ ************************************************************/
+
+BOOL dfs_io_q_dfs_add(char *desc, DFS_Q_DFS_ADD *q_d, prs_struct *ps, int depth)
+{
+ if(q_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_q_dfs_add");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("DfsEntryPath",&q_d->DfsEntryPath, 1, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("ServerName",&q_d->ServerName, 1, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_ShareName", ps, depth, &q_d->ptr_ShareName))
+ return False;
+ if(!smb_io_unistr2("ShareName",&q_d->ShareName, 1, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_Comment", ps, depth, &q_d->ptr_Comment))
+ return False;
+ if(!smb_io_unistr2("",&q_d->Comment, q_d->ptr_Comment , ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("Flags", ps, depth, &q_d->Flags))
+ return True;
+
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_R_DFS_ADD structure
+ ************************************************************/
+
+BOOL dfs_io_r_dfs_add(char *desc, DFS_R_DFS_ADD *r_d, prs_struct *ps, int depth)
+{
+ if(r_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_r_dfs_add");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &r_d->status))
+ return False;
+
+ return True;
+}
+
+BOOL init_dfs_q_dfs_get_info(DFS_Q_DFS_GET_INFO *q_d, char *entrypath,
+ char *servername, char *sharename,
+ uint32 info_level)
+{
+ DEBUG(5,("init_dfs_q2_get_info\n"));
+ init_unistr2(&q_d->uni_path, entrypath, strlen(entrypath)+1);
+ init_unistr2(&q_d->uni_server, servername, strlen(servername)+1);
+ init_unistr2(&q_d->uni_share, sharename, strlen(sharename)+1);
+ q_d->level = info_level;
+ q_d->ptr_server = q_d->ptr_share = 1;
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_Q_GET_INFO structure
+ ************************************************************/
+
+BOOL dfs_io_q_dfs_get_info(char* desc, DFS_Q_DFS_GET_INFO* q_i, prs_struct* ps, int depth)
+{
+ if(q_i == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_q_dfs_get_info");
+ depth++;
+
+ if(!smb_io_unistr2("",&q_i->uni_path, 1, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_server", ps, depth, &q_i->ptr_server))
+ return False;
+
+ if(q_i->ptr_server)
+ if (!smb_io_unistr2("",&q_i->uni_server, q_i->ptr_server, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_share", ps, depth, &q_i->ptr_share))
+ return False;
+ if(q_i->ptr_share)
+ if(!smb_io_unistr2("", &q_i->uni_share, q_i->ptr_share, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_i->level))
+ return False;
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_R_GET_INFO structure
+ ************************************************************/
+
+BOOL dfs_io_r_dfs_get_info(char* desc, DFS_R_DFS_GET_INFO* r_i, prs_struct* ps, int depth)
+{
+ if(r_i == NULL)
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &r_i->level))
+ return False;
+ if(!prs_uint32("ptr_ctr", ps, depth, &r_i->ptr_ctr))
+ return False;
+
+ if(!dfs_io_dfs_info_ctr("", &r_i->ctr, 1, r_i->level, ps, depth))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_i->status))
+ return False;
+ return True;
+}
+
+/************************************************************
+ Make a DFS_Q_DFS_ENUM structure
+ ************************************************************/
+BOOL init_dfs_q_dfs_enum(DFS_Q_DFS_ENUM *q_d, uint32 level, DFS_INFO_CTR *ctr)
+{
+ q_d->level = level;
+ q_d->maxpreflen = -1;
+ q_d->ptr_buffer = 1;
+ q_d->level2 = level;
+
+ q_d->ptr_num_entries = 1;
+ q_d->num_entries = 0;
+ q_d->num_entries2 = 0;
+ q_d->reshnd.ptr_hnd = 1;
+ q_d->reshnd.handle = 0;
+ return True;
+}
+
+/************************************************************
+ Read or write the DFS_Q_DFS_ENUM structure
+ ************************************************************/
+
+BOOL dfs_io_q_dfs_enum(char *desc, DFS_Q_DFS_ENUM *q_d, prs_struct *ps, int depth)
+{
+ if(q_d == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_q_dfs_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_d->level))
+ return False;
+ if(!prs_uint32("maxpreflen", ps, depth, &q_d->maxpreflen))
+ return False;
+ if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &q_d->level2))
+ return False;
+ if(!prs_uint32("level3", ps, depth, &q_d->level2))
+ return False;
+
+ if(!prs_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries))
+ return False;
+ if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries))
+ return False;
+ if(!prs_uint32("num_entries2", ps, depth, &q_d->num_entries2))
+ return False;
+ if(!smb_io_enum_hnd("resume_hnd",&q_d->reshnd, ps, depth))
+ return False;
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_INFO_CTR structure
+ ************************************************************/
+
+BOOL dfs_io_dfs_info_ctr(char* desc, DFS_INFO_CTR* ctr, uint32 num_entries, uint32 level, prs_struct* ps, int depth)
+{
+ int i=0;
+
+ switch(level) {
+ case 1:
+ depth++;
+ /* should depend on whether marshalling or unmarshalling! */
+ if(UNMARSHALLING(ps)) {
+ ctr->dfs.info1 = (DFS_INFO_1 *)prs_alloc_mem(ps, sizeof(DFS_INFO_1)*num_entries);
+ if (!ctr->dfs.info1)
+ return False;
+ }
+
+ for(i=0;i<num_entries;i++) {
+ if(!prs_uint32("ptr_entrypath",ps, depth, &ctr->dfs.info1[i].ptr_entrypath))
+ return False;
+ }
+ for(i=0;i<num_entries;i++) {
+ if(!smb_io_unistr2("", &ctr->dfs.info1[i].entrypath, ctr->dfs.info1[i].ptr_entrypath, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ depth--;
+ break;
+ case 2:
+ depth++;
+ if(UNMARSHALLING(ps)) {
+ ctr->dfs.info2 = (DFS_INFO_2 *)prs_alloc_mem(ps, num_entries*sizeof(DFS_INFO_2));
+ if (!ctr->dfs.info2)
+ return False;
+ }
+
+ for(i=0;i<num_entries;i++) {
+ if(!prs_uint32("ptr_entrypath", ps, depth, &ctr->dfs.info2[i].ptr_entrypath))
+ return False;
+ if(!prs_uint32("ptr_comment", ps, depth, &ctr->dfs.info2[i].ptr_comment))
+ return False;
+ if(!prs_uint32("state", ps, depth, &ctr->dfs.info2[i].state))
+ return False;
+ if(!prs_uint32("num_storages", ps, depth, &ctr->dfs.info2[i].num_storages))
+ return False;
+ }
+ for(i=0;i<num_entries;i++) {
+ if(!smb_io_unistr2("", &ctr->dfs.info2[i].entrypath, ctr->dfs.info2[i].ptr_entrypath, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("",&ctr->dfs.info2[i].comment, ctr->dfs.info2[i].ptr_comment, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ depth--;
+ break;
+ case 3:
+ depth++;
+ if(UNMARSHALLING(ps)) {
+ ctr->dfs.info3 = (DFS_INFO_3 *)prs_alloc_mem(ps, num_entries*sizeof(DFS_INFO_3));
+ if (!ctr->dfs.info3)
+ return False;
+ }
+
+ for(i=0;i<num_entries;i++) {
+ if(!prs_uint32("ptr_entrypath", ps, depth, &ctr->dfs.info3[i].ptr_entrypath))
+ return False;
+ if(!prs_uint32("ptr_comment", ps, depth, &ctr->dfs.info3[i].ptr_comment))
+ return False;
+ if(!prs_uint32("state", ps, depth, &ctr->dfs.info3[i].state))
+ return False;
+ if(!prs_uint32("num_storages", ps, depth, &ctr->dfs.info3[i].num_storages))
+ return False;
+ if(!prs_uint32("ptr_storages", ps, depth, &ctr->dfs.info3[i].ptr_storages))
+ return False;
+ }
+ for(i=0;i<num_entries;i++) {
+ if(!smb_io_unistr2("", &ctr->dfs.info3[i].entrypath, ctr->dfs.info3[i].ptr_entrypath, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &ctr->dfs.info3[i].comment, ctr->dfs.info3[i].ptr_comment, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_storage_infos", ps, depth, &ctr->dfs.info3[i].num_storage_infos))
+ return False;
+
+ if(!dfs_io_dfs_storage_info("storage_info", &ctr->dfs.info3[i], ps, depth))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/************************************************************
+ Read/write a DFS_R_DFS_ENUM structure
+ ************************************************************/
+
+BOOL dfs_io_r_dfs_enum(char *desc, DFS_R_DFS_ENUM *q_d, prs_struct *ps, int depth)
+{
+ DFS_INFO_CTR *ctr;
+ if(q_d == NULL)
+ return False;
+ ctr = q_d->ctr;
+ if(ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "dfs_io_r_dfs_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_buffer", ps, depth, &q_d->ptr_buffer))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_d->level))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_num_entries", ps, depth, &q_d->ptr_num_entries))
+ return False;
+ if(q_d->ptr_num_entries)
+ if(!prs_uint32("num_entries", ps, depth, &q_d->num_entries))
+ return False;
+ if(!prs_uint32("ptr_num_entries2", ps, depth, &q_d->ptr_num_entries2))
+ return False;
+ if(q_d->ptr_num_entries2)
+ if(!prs_uint32("num_entries2", ps, depth, &ctr->num_entries))
+ return False;
+
+ if(!dfs_io_dfs_info_ctr("", ctr, q_d->num_entries, q_d->level, ps, depth))
+ return False;
+
+ if(!smb_io_enum_hnd("resume_hnd", &q_d->reshnd, ps, depth))
+ return False;
+ if(!prs_werror("status", ps, depth, &q_d->status))
+ return False;
+ return True;
+}
+
+BOOL dfs_io_dfs_storage_info(char *desc, DFS_INFO_3* info3, prs_struct *ps, int depth)
+{
+ int i=0;
+ if(info3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dfs_storage_info");
+ depth++;
+
+ if(UNMARSHALLING(ps)) {
+ info3->storages = (DFS_STORAGE_INFO *)prs_alloc_mem(ps, info3->num_storage_infos*sizeof(DFS_STORAGE_INFO));
+ if (!info3->storages)
+ return False;
+ }
+
+ for(i=0;i<info3->num_storage_infos;i++) {
+ if(!prs_uint32("storage_state", ps, depth, &info3->storages[i].state))
+ return False;
+ if(!prs_uint32("ptr_servername", ps, depth, &info3->storages[i].ptr_servername))
+ return False;
+ if(!prs_uint32("ptr_sharename", ps, depth, &info3->storages[i].ptr_sharename))
+ return False;
+ }
+
+ for(i=0;i<info3->num_storage_infos;i++) {
+ if(!smb_io_unistr2("servername", &info3->storages[i].servername, info3->storages[i].ptr_servername, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("sharename", &info3->storages[i].sharename, info3->storages[i].ptr_sharename, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_lsa.c b/source/rpc_parse/parse_lsa.c
new file mode 100644
index 00000000000..12b0ec2e167
--- /dev/null
+++ b/source/rpc_parse/parse_lsa.c
@@ -0,0 +1,2098 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+static BOOL lsa_io_trans_names(char *desc, LSA_TRANS_NAME_ENUM *trn, prs_struct *ps, int depth);
+
+/*******************************************************************
+ Inits a LSA_TRANS_NAME structure.
+********************************************************************/
+
+void init_lsa_trans_name(LSA_TRANS_NAME *trn, UNISTR2 *uni_name,
+ uint16 sid_name_use, char *name, uint32 idx)
+{
+ int len_name = strlen(name);
+
+ if(len_name == 0)
+ len_name = 1;
+
+ trn->sid_name_use = sid_name_use;
+ init_uni_hdr(&trn->hdr_name, len_name);
+ init_unistr2(uni_name, name, len_name);
+ trn->domain_idx = idx;
+}
+
+/*******************************************************************
+ Reads or writes a LSA_TRANS_NAME structure.
+********************************************************************/
+
+static BOOL lsa_io_trans_name(char *desc, LSA_TRANS_NAME *trn, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_trans_name");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("sid_name_use", ps, depth, &trn->sid_name_use))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr ("hdr_name", &trn->hdr_name, ps, depth))
+ return False;
+ if(!prs_uint32("domain_idx ", ps, depth, &trn->domain_idx))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_R_REF structure.
+********************************************************************/
+
+static BOOL lsa_io_dom_r_ref(char *desc, DOM_R_REF *r_r, prs_struct *ps,
+ int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "lsa_io_dom_r_ref");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_ref_doms_1", ps, depth, &r_r->num_ref_doms_1)) /* num referenced domains? */
+ return False;
+ if(!prs_uint32("ptr_ref_dom ", ps, depth, &r_r->ptr_ref_dom)) /* undocumented buffer pointer. */
+ return False;
+ if(!prs_uint32("max_entries ", ps, depth, &r_r->max_entries)) /* 32 - max number of entries */
+ return False;
+
+ SMB_ASSERT_ARRAY(r_r->hdr_ref_dom, r_r->num_ref_doms_1);
+
+ if (r_r->ptr_ref_dom != 0) {
+
+ if(!prs_uint32("num_ref_doms_2", ps, depth, &r_r->num_ref_doms_2)) /* 4 - num referenced domains? */
+ return False;
+
+ SMB_ASSERT_ARRAY(r_r->ref_dom, r_r->num_ref_doms_2);
+
+ for (i = 0; i < r_r->num_ref_doms_1; i++) {
+ fstring t;
+
+ slprintf(t, sizeof(t) - 1, "dom_ref[%d] ", i);
+ if(!smb_io_unihdr(t, &r_r->hdr_ref_dom[i].hdr_dom_name, ps, depth))
+ return False;
+
+ slprintf(t, sizeof(t) - 1, "sid_ptr[%d] ", i);
+ if(!prs_uint32(t, ps, depth, &r_r->hdr_ref_dom[i].ptr_dom_sid))
+ return False;
+ }
+
+ for (i = 0; i < r_r->num_ref_doms_2; i++) {
+ fstring t;
+
+ if (r_r->hdr_ref_dom[i].hdr_dom_name.buffer != 0) {
+ slprintf(t, sizeof(t) - 1, "dom_ref[%d] ", i);
+ if(!smb_io_unistr2(t, &r_r->ref_dom[i].uni_dom_name, True, ps, depth)) /* domain name unicode string */
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ if (r_r->hdr_ref_dom[i].ptr_dom_sid != 0) {
+ slprintf(t, sizeof(t) - 1, "sid_ptr[%d] ", i);
+ if(!smb_io_dom_sid2(t, &r_r->ref_dom[i].ref_dom, ps, depth)) /* referenced domain SIDs */
+ return False;
+ }
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_SEC_QOS structure.
+********************************************************************/
+
+void init_lsa_sec_qos(LSA_SEC_QOS *qos, uint16 imp_lev, uint8 ctxt, uint8 eff)
+{
+ DEBUG(5, ("init_lsa_sec_qos\n"));
+
+ qos->len = 0x0c; /* length of quality of service block, in bytes */
+ qos->sec_imp_level = imp_lev;
+ qos->sec_ctxt_mode = ctxt;
+ qos->effective_only = eff;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_SEC_QOS structure.
+********************************************************************/
+
+static BOOL lsa_io_sec_qos(char *desc, LSA_SEC_QOS *qos, prs_struct *ps,
+ int depth)
+{
+ uint32 start;
+
+ prs_debug(ps, depth, desc, "lsa_io_obj_qos");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ start = prs_offset(ps);
+
+ /* these pointers had _better_ be zero, because we don't know
+ what they point to!
+ */
+ if(!prs_uint32("len ", ps, depth, &qos->len)) /* 0x18 - length (in bytes) inc. the length field. */
+ return False;
+ if(!prs_uint16("sec_imp_level ", ps, depth, &qos->sec_imp_level ))
+ return False;
+ if(!prs_uint8 ("sec_ctxt_mode ", ps, depth, &qos->sec_ctxt_mode ))
+ return False;
+ if(!prs_uint8 ("effective_only", ps, depth, &qos->effective_only))
+ return False;
+
+ if (qos->len != prs_offset(ps) - start) {
+ DEBUG(3,("lsa_io_sec_qos: length %x does not match size %x\n",
+ qos->len, prs_offset(ps) - start));
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_OBJ_ATTR structure.
+********************************************************************/
+
+void init_lsa_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, LSA_SEC_QOS *qos)
+{
+ DEBUG(5, ("init_lsa_obj_attr\n"));
+
+ attr->len = 0x18; /* length of object attribute block, in bytes */
+ attr->ptr_root_dir = 0;
+ attr->ptr_obj_name = 0;
+ attr->attributes = attributes;
+ attr->ptr_sec_desc = 0;
+
+ if (qos != NULL) {
+ attr->ptr_sec_qos = 1;
+ attr->sec_qos = qos;
+ } else {
+ attr->ptr_sec_qos = 0;
+ attr->sec_qos = NULL;
+ }
+}
+
+/*******************************************************************
+ Reads or writes an LSA_OBJ_ATTR structure.
+********************************************************************/
+
+static BOOL lsa_io_obj_attr(char *desc, LSA_OBJ_ATTR *attr, prs_struct *ps,
+ int depth)
+{
+ uint32 start;
+
+ prs_debug(ps, depth, desc, "lsa_io_obj_attr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ start = prs_offset(ps);
+
+ /* these pointers had _better_ be zero, because we don't know
+ what they point to!
+ */
+ if(!prs_uint32("len ", ps, depth, &attr->len)) /* 0x18 - length (in bytes) inc. the length field. */
+ return False;
+ if(!prs_uint32("ptr_root_dir", ps, depth, &attr->ptr_root_dir)) /* 0 - root directory (pointer) */
+ return False;
+ if(!prs_uint32("ptr_obj_name", ps, depth, &attr->ptr_obj_name)) /* 0 - object name (pointer) */
+ return False;
+ if(!prs_uint32("attributes ", ps, depth, &attr->attributes)) /* 0 - attributes (undocumented) */
+ return False;
+ if(!prs_uint32("ptr_sec_desc", ps, depth, &attr->ptr_sec_desc)) /* 0 - security descriptior (pointer) */
+ return False;
+ if(!prs_uint32("ptr_sec_qos ", ps, depth, &attr->ptr_sec_qos )) /* security quality of service (pointer) */
+ return False;
+
+ /* code commented out as it's not necessary true (tested with hyena). JFM, 11/22/2001 */
+#if 0
+ if (attr->len != prs_offset(ps) - start) {
+ DEBUG(3,("lsa_io_obj_attr: length %x does not match size %x\n",
+ attr->len, prs_offset(ps) - start));
+ return False;
+ }
+#endif
+
+ if (attr->ptr_sec_qos != 0) {
+ if (UNMARSHALLING(ps))
+ if (!(attr->sec_qos = (LSA_SEC_QOS *)prs_alloc_mem(ps,sizeof(LSA_SEC_QOS))))
+ return False;
+
+ if(!lsa_io_sec_qos("sec_qos", attr->sec_qos, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits an LSA_Q_OPEN_POL structure.
+********************************************************************/
+
+void init_q_open_pol(LSA_Q_OPEN_POL *r_q, uint16 system_name,
+ uint32 attributes, uint32 desired_access,
+ LSA_SEC_QOS *qos)
+{
+ DEBUG(5, ("init_open_pol: attr:%d da:%d\n", attributes,
+ desired_access));
+
+ r_q->ptr = 1; /* undocumented pointer */
+
+ r_q->des_access = desired_access;
+
+ r_q->system_name = system_name;
+ init_lsa_obj_attr(&r_q->attr, attributes, qos);
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_OPEN_POL structure.
+********************************************************************/
+
+BOOL lsa_io_q_open_pol(char *desc, LSA_Q_OPEN_POL *r_q, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_open_pol");
+ depth++;
+
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+ if(!prs_uint16("system_name", ps, depth, &r_q->system_name))
+ return False;
+ if(!prs_align( ps ))
+ return False;
+
+ if(!lsa_io_obj_attr("", &r_q->attr, ps, depth))
+ return False;
+
+ if(!prs_uint32("des_access", ps, depth, &r_q->des_access))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_OPEN_POL structure.
+********************************************************************/
+
+BOOL lsa_io_r_open_pol(char *desc, LSA_R_OPEN_POL *r_p, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_open_pol");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &r_p->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_p->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_Q_OPEN_POL2 structure.
+********************************************************************/
+
+void init_q_open_pol2(LSA_Q_OPEN_POL2 *r_q, char *server_name,
+ uint32 attributes, uint32 desired_access,
+ LSA_SEC_QOS *qos)
+{
+ DEBUG(5, ("init_q_open_pol2: attr:%d da:%d\n", attributes,
+ desired_access));
+
+ r_q->ptr = 1; /* undocumented pointer */
+
+ r_q->des_access = desired_access;
+
+ init_unistr2(&r_q->uni_server_name, server_name,
+ strlen(server_name) + 1);
+
+ init_lsa_obj_attr(&r_q->attr, attributes, qos);
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_OPEN_POL2 structure.
+********************************************************************/
+
+BOOL lsa_io_q_open_pol2(char *desc, LSA_Q_OPEN_POL2 *r_q, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_open_pol2");
+ depth++;
+
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+
+ if(!smb_io_unistr2 ("", &r_q->uni_server_name, r_q->ptr, ps, depth))
+ return False;
+ if(!lsa_io_obj_attr("", &r_q->attr, ps, depth))
+ return False;
+
+ if(!prs_uint32("des_access", ps, depth, &r_q->des_access))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_OPEN_POL2 structure.
+********************************************************************/
+
+BOOL lsa_io_r_open_pol2(char *desc, LSA_R_OPEN_POL2 *r_p, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_open_pol2");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &r_p->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_p->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes an LSA_Q_QUERY_SEC_OBJ structure.
+********************************************************************/
+
+void init_q_query_sec_obj(LSA_Q_QUERY_SEC_OBJ *q_q, const POLICY_HND *hnd,
+ uint32 sec_info)
+{
+ DEBUG(5, ("init_q_query_sec_obj\n"));
+
+ q_q->pol = *hnd;
+ q_q->sec_info = sec_info;
+
+ return;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_QUERY_SEC_OBJ structure.
+********************************************************************/
+
+BOOL lsa_io_q_query_sec_obj(char *desc, LSA_Q_QUERY_SEC_OBJ *q_q,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_query_sec_obj");
+ depth++;
+
+ if (!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if (!prs_uint32("sec_info", ps, depth, &q_q->sec_info))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a LSA_R_QUERY_SEC_OBJ structure.
+********************************************************************/
+
+BOOL lsa_io_r_query_sec_obj(char *desc, LSA_R_QUERY_SEC_OBJ *r_u,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_query_sec_obj");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if (!sec_io_desc_buf("sec", &r_u->buf, ps, depth))
+ return False;
+ }
+
+ if (!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+
+void init_q_query(LSA_Q_QUERY_INFO *q_q, POLICY_HND *hnd, uint16 info_class)
+{
+ DEBUG(5, ("init_q_query\n"));
+
+ memcpy(&q_q->pol, hnd, sizeof(q_q->pol));
+
+ q_q->info_class = info_class;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+
+BOOL lsa_io_q_query(char *desc, LSA_Q_QUERY_INFO *q_q, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_query");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("info_class", ps, depth, &q_q->info_class))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes an LSA_Q_ENUM_TRUST_DOM structure.
+********************************************************************/
+BOOL init_q_enum_trust_dom(LSA_Q_ENUM_TRUST_DOM * q_e, POLICY_HND *pol,
+ uint32 enum_context, uint32 preferred_len)
+{
+ DEBUG(5, ("init_q_enum_trust_dom\n"));
+
+ q_e->pol = *pol;
+ q_e->enum_context = enum_context;
+ q_e->preferred_len = preferred_len;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_ENUM_TRUST_DOM structure.
+********************************************************************/
+
+BOOL lsa_io_q_enum_trust_dom(char *desc, LSA_Q_ENUM_TRUST_DOM *q_e,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_enum_trust_dom");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("enum_context ", ps, depth, &q_e->enum_context))
+ return False;
+ if(!prs_uint32("preferred_len", ps, depth, &q_e->preferred_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_R_ENUM_TRUST_DOM structure.
+********************************************************************/
+
+void init_r_enum_trust_dom(TALLOC_CTX *ctx, LSA_R_ENUM_TRUST_DOM *r_e, uint32 enum_context,
+ char *domain_name, DOM_SID *domain_sid,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_r_enum_trust_dom\n"));
+
+ r_e->enum_context = enum_context;
+
+ if (NT_STATUS_IS_OK(status)) {
+ int len_domain_name = strlen(domain_name) + 1;
+
+ r_e->num_domains = 1;
+ r_e->ptr_enum_domains = 1;
+ r_e->num_domains2 = 1;
+
+ if (!(r_e->hdr_domain_name = (UNIHDR2 *)talloc(ctx,sizeof(UNIHDR2))))
+ return;
+
+ if (!(r_e->uni_domain_name = (UNISTR2 *)talloc(ctx,sizeof(UNISTR2))))
+ return;
+
+ if (!(r_e->domain_sid = (DOM_SID2 *)talloc(ctx,sizeof(DOM_SID2))))
+ return;
+
+ init_uni_hdr2(&r_e->hdr_domain_name[0], len_domain_name);
+ init_unistr2 (&r_e->uni_domain_name[0], domain_name,
+ len_domain_name);
+ init_dom_sid2(&r_e->domain_sid[0], domain_sid);
+ } else {
+ r_e->num_domains = 0;
+ r_e->ptr_enum_domains = 0;
+ }
+
+ r_e->status = status;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_ENUM_TRUST_DOM structure.
+********************************************************************/
+
+BOOL lsa_io_r_enum_trust_dom(char *desc, LSA_R_ENUM_TRUST_DOM *r_e,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_enum_trust_dom");
+ depth++;
+
+ if(!prs_uint32("enum_context ", ps, depth, &r_e->enum_context))
+ return False;
+ if(!prs_uint32("num_domains ", ps, depth, &r_e->num_domains))
+ return False;
+ if(!prs_uint32("ptr_enum_domains", ps, depth, &r_e->ptr_enum_domains))
+ return False;
+
+ if (r_e->ptr_enum_domains) {
+ int i, num_domains;
+
+ if(!prs_uint32("num_domains2", ps, depth, &r_e->num_domains2))
+ return False;
+
+ num_domains = r_e->num_domains2;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(r_e->hdr_domain_name = (UNIHDR2 *)prs_alloc_mem(ps,sizeof(UNIHDR2) * num_domains)))
+ return False;
+
+ if (!(r_e->uni_domain_name = (UNISTR2 *)prs_alloc_mem(ps,sizeof(UNISTR2) * num_domains)))
+ return False;
+
+ if (!(r_e->domain_sid = (DOM_SID2 *)prs_alloc_mem(ps,sizeof(DOM_SID2) * num_domains)))
+ return False;
+ }
+
+ for (i = 0; i < num_domains; i++) {
+ if(!smb_io_unihdr2 ("", &r_e->hdr_domain_name[i], ps,
+ depth))
+ return False;
+ }
+
+ for (i = 0; i < num_domains; i++) {
+ if(!smb_io_unistr2 ("", &r_e->uni_domain_name[i],
+ r_e->hdr_domain_name[i].buffer,
+ ps, depth))
+ return False;
+ if(!smb_io_dom_sid2("", &r_e->domain_sid[i], ps,
+ depth))
+ return False;
+ }
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_e->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+
+static BOOL lsa_io_dom_query(char *desc, DOM_QUERY *d_q, prs_struct *ps, int depth)
+{
+ if (d_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_dom_query");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("uni_dom_max_len", ps, depth, &d_q->uni_dom_max_len)) /* domain name string length * 2 */
+ return False;
+ if(!prs_uint16("uni_dom_str_len", ps, depth, &d_q->uni_dom_str_len)) /* domain name string length * 2 */
+ return False;
+
+ if(!prs_uint32("buffer_dom_name", ps, depth, &d_q->buffer_dom_name)) /* undocumented domain name string buffer pointer */
+ return False;
+ if(!prs_uint32("buffer_dom_sid ", ps, depth, &d_q->buffer_dom_sid)) /* undocumented domain SID string buffer pointer */
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &d_q->uni_domain_name, d_q->buffer_dom_name, ps, depth)) /* domain name (unicode string) */
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (d_q->buffer_dom_sid != 0) {
+ if(!smb_io_dom_sid2("", &d_q->dom_sid, ps, depth)) /* domain SID */
+ return False;
+ } else {
+ memset((char *)&d_q->dom_sid, '\0', sizeof(d_q->dom_sid));
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL lsa_io_dom_query_2(char *desc, DOM_QUERY_2 *d_q, prs_struct *ps, int depth)
+{
+ uint32 ptr = 1;
+
+ if (d_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_dom_query_2");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("auditing_enabled", ps, depth, &d_q->auditing_enabled))
+ return False;
+ if (!prs_uint32("ptr ", ps, depth, &ptr))
+ return False;
+ if (!prs_uint32("count1", ps, depth, &d_q->count1))
+ return False;
+ if (!prs_uint32("count2", ps, depth, &d_q->count2))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ d_q->auditsettings = (uint32 *)talloc_zero(ps->mem_ctx, d_q->count2 * sizeof(uint32));
+ }
+
+ if (d_q->auditsettings == NULL) {
+ DEBUG(1, ("lsa_io_dom_query_2: NULL auditsettings!\n"));
+ return False;
+ }
+
+ if (!prs_uint32s(False, "auditsettings", ps, depth, d_q->auditsettings, d_q->count2))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a dom query structure.
+********************************************************************/
+
+static BOOL lsa_io_dom_query_3(char *desc, DOM_QUERY_3 *d_q, prs_struct *ps, int depth)
+{
+ return lsa_io_dom_query("", d_q, ps, depth);
+}
+
+/*******************************************************************
+ Reads or writes a dom query structure.
+********************************************************************/
+
+BOOL lsa_io_dom_query_5(char *desc, DOM_QUERY_5 *d_q, prs_struct *ps, int depth)
+{
+ return lsa_io_dom_query("", d_q, ps, depth);
+}
+
+/*******************************************************************
+ Reads or writes a dom query structure.
+********************************************************************/
+
+static BOOL lsa_io_dom_query_6(char *desc, DOM_QUERY_6 *d_q, prs_struct *ps, int depth)
+{
+ if (d_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_dom_query_6");
+ depth++;
+
+ if (!prs_uint16("server_role", ps, depth, &d_q->server_role))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_QUERY_INFO structure.
+********************************************************************/
+
+BOOL lsa_io_r_query(char *desc, LSA_R_QUERY_INFO *r_q, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_query");
+ depth++;
+
+ if(!prs_uint32("undoc_buffer", ps, depth, &r_q->undoc_buffer))
+ return False;
+
+ if (r_q->undoc_buffer != 0) {
+ if(!prs_uint16("info_class", ps, depth, &r_q->info_class))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ switch (r_q->info_class) {
+ case 2:
+ if(!lsa_io_dom_query_2("", &r_q->dom.id2, ps, depth))
+ return False;
+ break;
+ case 3:
+ if(!lsa_io_dom_query_3("", &r_q->dom.id3, ps, depth))
+ return False;
+ break;
+ case 5:
+ if(!lsa_io_dom_query_5("", &r_q->dom.id5, ps, depth))
+ return False;
+ break;
+ case 6:
+ if(!lsa_io_dom_query_6("", &r_q->dom.id6, ps, depth))
+ return False;
+ break;
+ default:
+ /* PANIC! */
+ break;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a LSA_SID_ENUM structure.
+********************************************************************/
+
+void init_lsa_sid_enum(TALLOC_CTX *mem_ctx, LSA_SID_ENUM *sen,
+ int num_entries, DOM_SID *sids)
+{
+ int i;
+
+ DEBUG(5, ("init_lsa_sid_enum\n"));
+
+ sen->num_entries = num_entries;
+ sen->ptr_sid_enum = (num_entries != 0);
+ sen->num_entries2 = num_entries;
+
+ /* Allocate memory for sids and sid pointers */
+
+ if (num_entries == 0) return;
+
+ if ((sen->ptr_sid = (uint32 *)talloc_zero(mem_ctx, num_entries *
+ sizeof(uint32))) == NULL) {
+ DEBUG(3, ("init_lsa_sid_enum(): out of memory for ptr_sid\n"));
+ return;
+ }
+
+ if ((sen->sid = (DOM_SID2 *)talloc_zero(mem_ctx, num_entries *
+ sizeof(DOM_SID2))) == NULL) {
+ DEBUG(3, ("init_lsa_sid_enum(): out of memory for sids\n"));
+ return;
+ }
+
+ /* Copy across SIDs and SID pointers */
+
+ for (i = 0; i < num_entries; i++) {
+ sen->ptr_sid[i] = 1;
+ init_dom_sid2(&sen->sid[i], &sids[i]);
+ }
+}
+
+/*******************************************************************
+ Reads or writes a LSA_SID_ENUM structure.
+********************************************************************/
+
+static BOOL lsa_io_sid_enum(char *desc, LSA_SID_ENUM *sen, prs_struct *ps,
+ int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "lsa_io_sid_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries ", ps, depth, &sen->num_entries))
+ return False;
+ if(!prs_uint32("ptr_sid_enum", ps, depth, &sen->ptr_sid_enum))
+ return False;
+
+ /*
+ if the ptr is NULL, leave here. checked from a real w2k trace.
+ JFM, 11/23/2001
+ */
+
+ if (sen->ptr_sid_enum==0)
+ return True;
+
+ if(!prs_uint32("num_entries2", ps, depth, &sen->num_entries2))
+ return False;
+
+ /* Mallocate memory if we're unpacking from the wire */
+
+ if (UNMARSHALLING(ps)) {
+ if ((sen->ptr_sid = (uint32 *)prs_alloc_mem( ps,
+ sen->num_entries * sizeof(uint32))) == NULL) {
+ DEBUG(3, ("init_lsa_sid_enum(): out of memory for "
+ "ptr_sid\n"));
+ return False;
+ }
+
+ if ((sen->sid = (DOM_SID2 *)prs_alloc_mem( ps,
+ sen->num_entries * sizeof(DOM_SID2))) == NULL) {
+ DEBUG(3, ("init_lsa_sid_enum(): out of memory for "
+ "sids\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < sen->num_entries; i++) {
+ fstring temp;
+
+ slprintf(temp, sizeof(temp) - 1, "ptr_sid[%d]", i);
+ if(!prs_uint32(temp, ps, depth, &sen->ptr_sid[i])) {
+ return False;
+ }
+ }
+
+ for (i = 0; i < sen->num_entries; i++) {
+ fstring temp;
+
+ slprintf(temp, sizeof(temp) - 1, "sid[%d]", i);
+ if(!smb_io_dom_sid2(temp, &sen->sid[i], ps, depth)) {
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_R_ENUM_TRUST_DOM structure.
+********************************************************************/
+
+void init_q_lookup_sids(TALLOC_CTX *mem_ctx, LSA_Q_LOOKUP_SIDS *q_l,
+ POLICY_HND *hnd, int num_sids, DOM_SID *sids,
+ uint16 level)
+{
+ DEBUG(5, ("init_r_enum_trust_dom\n"));
+
+ ZERO_STRUCTP(q_l);
+
+ memcpy(&q_l->pol, hnd, sizeof(q_l->pol));
+ init_lsa_sid_enum(mem_ctx, &q_l->sids, num_sids, sids);
+
+ q_l->level.value = level;
+}
+
+/*******************************************************************
+ Reads or writes a LSA_Q_LOOKUP_SIDS structure.
+********************************************************************/
+
+BOOL lsa_io_q_lookup_sids(char *desc, LSA_Q_LOOKUP_SIDS *q_s, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_lookup_sids");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol_hnd", &q_s->pol, ps, depth)) /* policy handle */
+ return False;
+ if(!lsa_io_sid_enum("sids ", &q_s->sids, ps, depth)) /* sids to be looked up */
+ return False;
+ if(!lsa_io_trans_names("names ", &q_s->names, ps, depth)) /* translated names */
+ return False;
+ if(!smb_io_lookup_level("switch ", &q_s->level, ps, depth)) /* lookup level */
+ return False;
+
+ if(!prs_uint32("mapped_count", ps, depth, &q_s->mapped_count))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL lsa_io_trans_names(char *desc, LSA_TRANS_NAME_ENUM *trn,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "lsa_io_trans_names");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries ", ps, depth, &trn->num_entries))
+ return False;
+ if(!prs_uint32("ptr_trans_names", ps, depth, &trn->ptr_trans_names))
+ return False;
+
+ if (trn->ptr_trans_names != 0) {
+ if(!prs_uint32("num_entries2 ", ps, depth,
+ &trn->num_entries2))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if ((trn->name = (LSA_TRANS_NAME *)
+ prs_alloc_mem(ps, trn->num_entries *
+ sizeof(LSA_TRANS_NAME))) == NULL) {
+ return False;
+ }
+
+ if ((trn->uni_name = (UNISTR2 *)
+ prs_alloc_mem(ps, trn->num_entries *
+ sizeof(UNISTR2))) == NULL) {
+ return False;
+ }
+ }
+
+ for (i = 0; i < trn->num_entries2; i++) {
+ fstring t;
+ slprintf(t, sizeof(t) - 1, "name[%d] ", i);
+
+ if(!lsa_io_trans_name(t, &trn->name[i], ps, depth)) /* translated name */
+ return False;
+ }
+
+ for (i = 0; i < trn->num_entries2; i++) {
+ fstring t;
+ slprintf(t, sizeof(t) - 1, "name[%d] ", i);
+
+ if(!smb_io_unistr2(t, &trn->uni_name[i], trn->name[i].hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL lsa_io_r_lookup_sids(char *desc, LSA_R_LOOKUP_SIDS *r_s,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_lookup_sids");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_dom_ref", ps, depth, &r_s->ptr_dom_ref))
+ return False;
+
+ if (r_s->ptr_dom_ref != 0)
+ if(!lsa_io_dom_r_ref ("dom_ref", r_s->dom_ref, ps, depth)) /* domain reference info */
+ return False;
+
+ if(!lsa_io_trans_names("names ", r_s->names, ps, depth)) /* translated names */
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("mapped_count", ps, depth, &r_s->mapped_count))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_s->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_q_lookup_names(TALLOC_CTX *mem_ctx, LSA_Q_LOOKUP_NAMES *q_l,
+ POLICY_HND *hnd, int num_names, const char **names)
+{
+ int i;
+
+ DEBUG(5, ("init_q_lookup_names\n"));
+
+ ZERO_STRUCTP(q_l);
+
+ q_l->pol = *hnd;
+ q_l->num_entries = num_names;
+ q_l->num_entries2 = num_names;
+ q_l->lookup_level = 1;
+
+ if ((q_l->uni_name = (UNISTR2 *)talloc_zero(
+ mem_ctx, num_names * sizeof(UNISTR2))) == NULL) {
+ DEBUG(3, ("init_q_lookup_names(): out of memory\n"));
+ return;
+ }
+
+ if ((q_l->hdr_name = (UNIHDR *)talloc_zero(
+ mem_ctx, num_names * sizeof(UNIHDR))) == NULL) {
+ DEBUG(3, ("init_q_lookup_names(): out of memory\n"));
+ return;
+ }
+
+ for (i = 0; i < num_names; i++) {
+ const char *name = names[i];
+ int len = strlen(name);
+
+ init_uni_hdr(&q_l->hdr_name[i], len);
+ init_unistr2(&q_l->uni_name[i], name, len);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL lsa_io_q_lookup_names(char *desc, LSA_Q_LOOKUP_NAMES *q_r,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_lookup_names");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &q_r->pol, ps, depth)) /* policy handle */
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_entries ", ps, depth, &q_r->num_entries))
+ return False;
+ if(!prs_uint32("num_entries2 ", ps, depth, &q_r->num_entries2))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (q_r->num_entries) {
+ if ((q_r->hdr_name = (UNIHDR *)prs_alloc_mem(ps,
+ q_r->num_entries * sizeof(UNIHDR))) == NULL)
+ return False;
+ if ((q_r->uni_name = (UNISTR2 *)prs_alloc_mem(ps,
+ q_r->num_entries * sizeof(UNISTR2))) == NULL)
+ return False;
+ }
+ }
+
+ for (i = 0; i < q_r->num_entries; i++) {
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unihdr("hdr_name", &q_r->hdr_name[i], ps, depth)) /* pointer names */
+ return False;
+ }
+
+ for (i = 0; i < q_r->num_entries; i++) {
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("dom_name", &q_r->uni_name[i], q_r->hdr_name[i].buffer, ps, depth)) /* names to be looked up */
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_trans_entries ", ps, depth, &q_r->num_trans_entries))
+ return False;
+ if(!prs_uint32("ptr_trans_sids ", ps, depth, &q_r->ptr_trans_sids))
+ return False;
+ if(!prs_uint32("lookup_level ", ps, depth, &q_r->lookup_level))
+ return False;
+ if(!prs_uint32("mapped_count ", ps, depth, &q_r->mapped_count))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL lsa_io_r_lookup_names(char *desc, LSA_R_LOOKUP_NAMES *r_r,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_lookup_names");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_dom_ref", ps, depth, &r_r->ptr_dom_ref))
+ return False;
+
+ if (r_r->ptr_dom_ref != 0)
+ if(!lsa_io_dom_r_ref("", r_r->dom_ref, ps, depth))
+ return False;
+
+ if(!prs_uint32("num_entries", ps, depth, &r_r->num_entries))
+ return False;
+ if(!prs_uint32("ptr_entries", ps, depth, &r_r->ptr_entries))
+ return False;
+
+ if (r_r->ptr_entries != 0) {
+ if(!prs_uint32("num_entries2", ps, depth, &r_r->num_entries2))
+ return False;
+
+ if (r_r->num_entries2 != r_r->num_entries) {
+ /* RPC fault */
+ return False;
+ }
+
+ if (UNMARSHALLING(ps)) {
+ if ((r_r->dom_rid = (DOM_RID2 *)prs_alloc_mem(ps, r_r->num_entries2 * sizeof(DOM_RID2)))
+ == NULL) {
+ DEBUG(3, ("lsa_io_r_lookup_names(): out of memory\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_r->num_entries2; i++)
+ if(!smb_io_dom_rid2("", &r_r->dom_rid[i], ps, depth)) /* domain RIDs being looked up */
+ return False;
+ }
+
+ if(!prs_uint32("mapped_count", ps, depth, &r_r->mapped_count))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits an LSA_Q_CLOSE structure.
+********************************************************************/
+
+void init_lsa_q_close(LSA_Q_CLOSE *q_c, POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_lsa_q_close\n"));
+
+ memcpy(&q_c->pol, hnd, sizeof(q_c->pol));
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_CLOSE structure.
+********************************************************************/
+
+BOOL lsa_io_q_close(char *desc, LSA_Q_CLOSE *q_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_close");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &q_c->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_CLOSE structure.
+********************************************************************/
+
+BOOL lsa_io_r_close(char *desc, LSA_R_CLOSE *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_close");
+ depth++;
+
+ if(!smb_io_pol_hnd("", &r_c->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_OPEN_SECRET structure.
+********************************************************************/
+
+BOOL lsa_io_q_open_secret(char *desc, LSA_Q_OPEN_SECRET *q_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_open_secret");
+ depth++;
+
+ /* Don't bother to read or write at present... */
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_OPEN_SECRET structure.
+********************************************************************/
+
+BOOL lsa_io_r_open_secret(char *desc, LSA_R_OPEN_SECRET *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_open_secret");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("dummy1", ps, depth, &r_c->dummy1))
+ return False;
+ if(!prs_uint32("dummy2", ps, depth, &r_c->dummy2))
+ return False;
+ if(!prs_uint32("dummy3", ps, depth, &r_c->dummy3))
+ return False;
+ if(!prs_uint32("dummy4", ps, depth, &r_c->dummy4))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_Q_ENUM_PRIVS structure.
+********************************************************************/
+
+void init_q_enum_privs(LSA_Q_ENUM_PRIVS *q_q, POLICY_HND *hnd, uint32 enum_context, uint32 pref_max_length)
+{
+ DEBUG(5, ("init_q_enum_privs\n"));
+
+ memcpy(&q_q->pol, hnd, sizeof(q_q->pol));
+
+ q_q->enum_context = enum_context;
+ q_q->pref_max_length = pref_max_length;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_q_enum_privs(char *desc, LSA_Q_ENUM_PRIVS *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_enum_privs");
+ depth++;
+
+ if (!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("enum_context ", ps, depth, &q_q->enum_context))
+ return False;
+ if(!prs_uint32("pref_max_length", ps, depth, &q_q->pref_max_length))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL lsa_io_priv_entries(char *desc, LSA_PRIV_ENTRY *entries, uint32 count, prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (entries == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_priv_entries");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ for (i = 0; i < count; i++) {
+ if (!smb_io_unihdr("", &entries[i].hdr_name, ps, depth))
+ return False;
+ if(!prs_uint32("luid_low ", ps, depth, &entries[i].luid_low))
+ return False;
+ if(!prs_uint32("luid_high", ps, depth, &entries[i].luid_high))
+ return False;
+ }
+
+ for (i = 0; i < count; i++)
+ if (!smb_io_unistr2("", &entries[i].name, entries[i].hdr_name.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_R_ENUM_PRIVS structure.
+********************************************************************/
+
+void init_lsa_r_enum_privs(LSA_R_ENUM_PRIVS *r_u, uint32 enum_context,
+ uint32 count, LSA_PRIV_ENTRY *entries)
+{
+ DEBUG(5, ("init_lsa_r_enum_privs\n"));
+
+ r_u->enum_context=enum_context;
+ r_u->count=count;
+
+ if (entries!=NULL) {
+ r_u->ptr=1;
+ r_u->count1=count;
+ r_u->privs=entries;
+ } else {
+ r_u->ptr=0;
+ r_u->count1=0;
+ r_u->privs=NULL;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_r_enum_privs(char *desc, LSA_R_ENUM_PRIVS *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_enum_privs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("enum_context", ps, depth, &r_q->enum_context))
+ return False;
+ if(!prs_uint32("count", ps, depth, &r_q->count))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &r_q->ptr))
+ return False;
+
+ if (r_q->ptr) {
+ if(!prs_uint32("count1", ps, depth, &r_q->count1))
+ return False;
+
+ if (UNMARSHALLING(ps))
+ if (!(r_q->privs = (LSA_PRIV_ENTRY *)prs_alloc_mem(ps, sizeof(LSA_PRIV_ENTRY) * r_q->count1)))
+ return False;
+
+ if (!lsa_io_priv_entries("", r_q->privs, r_q->count1, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+void init_lsa_priv_get_dispname(LSA_Q_PRIV_GET_DISPNAME *trn, POLICY_HND *hnd, char *name, uint16 lang_id, uint16 lang_id_sys)
+{
+ int len_name = strlen(name);
+
+ if(len_name == 0)
+ len_name = 1;
+
+ memcpy(&trn->pol, hnd, sizeof(trn->pol));
+
+ init_uni_hdr(&trn->hdr_name, len_name);
+ init_unistr2(&trn->name, name, len_name);
+ trn->lang_id = lang_id;
+ trn->lang_id_sys = lang_id_sys;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_q_priv_get_dispname(char *desc, LSA_Q_PRIV_GET_DISPNAME *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_priv_get_dispname");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if (!smb_io_unihdr("hdr_name", &q_q->hdr_name, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("name", &q_q->name, q_q->hdr_name.buffer, ps, depth))
+ return False;
+
+ if(!prs_uint16("lang_id ", ps, depth, &q_q->lang_id))
+ return False;
+ if(!prs_uint16("lang_id_sys", ps, depth, &q_q->lang_id_sys))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_r_priv_get_dispname(char *desc, LSA_R_PRIV_GET_DISPNAME *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_priv_get_dispname");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr_info", ps, depth, &r_q->ptr_info))
+ return False;
+
+ if (r_q->ptr_info){
+ if (!smb_io_unihdr("hdr_name", &r_q->hdr_desc, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("desc", &r_q->desc, r_q->hdr_desc.buffer, ps, depth))
+ return False;
+ }
+/*
+ if(!prs_align(ps))
+ return False;
+*/
+ if(!prs_uint16("lang_id", ps, depth, &r_q->lang_id))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+void init_lsa_q_enum_accounts(LSA_Q_ENUM_ACCOUNTS *trn, POLICY_HND *hnd, uint32 enum_context, uint32 pref_max_length)
+{
+ memcpy(&trn->pol, hnd, sizeof(trn->pol));
+
+ trn->enum_context = enum_context;
+ trn->pref_max_length = pref_max_length;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_q_enum_accounts(char *desc, LSA_Q_ENUM_ACCOUNTS *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_enum_accounts");
+ depth++;
+
+ if (!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("enum_context ", ps, depth, &q_q->enum_context))
+ return False;
+ if(!prs_uint32("pref_max_length", ps, depth, &q_q->pref_max_length))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an LSA_R_ENUM_PRIVS structure.
+********************************************************************/
+
+void init_lsa_r_enum_accounts(LSA_R_ENUM_ACCOUNTS *r_u, uint32 enum_context)
+{
+ DEBUG(5, ("init_lsa_r_enum_accounts\n"));
+
+ r_u->enum_context=enum_context;
+ if (r_u->enum_context!=0) {
+ r_u->sids.num_entries=enum_context;
+ r_u->sids.ptr_sid_enum=1;
+ r_u->sids.num_entries2=enum_context;
+ } else {
+ r_u->sids.num_entries=0;
+ r_u->sids.ptr_sid_enum=0;
+ r_u->sids.num_entries2=0;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL lsa_io_r_enum_accounts(char *desc, LSA_R_ENUM_ACCOUNTS *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_enum_accounts");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("enum_context", ps, depth, &r_q->enum_context))
+ return False;
+
+ if (!lsa_io_sid_enum("sids", &r_q->sids, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Reads or writes an LSA_Q_UNK_GET_CONNUSER structure.
+********************************************************************/
+
+BOOL lsa_io_q_unk_get_connuser(char *desc, LSA_Q_UNK_GET_CONNUSER *q_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_unk_get_connuser");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srvname", ps, depth, &q_c->ptr_srvname))
+ return False;
+
+ if(!smb_io_unistr2("uni2_srvname", &q_c->uni2_srvname, q_c->ptr_srvname, ps, depth)) /* server name to be looked up */
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("unk1", ps, depth, &q_c->unk1))
+ return False;
+ if(!prs_uint32("unk2", ps, depth, &q_c->unk2))
+ return False;
+ if(!prs_uint32("unk3", ps, depth, &q_c->unk3))
+ return False;
+
+ /* Don't bother to read or write at present... */
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_UNK_GET_CONNUSER structure.
+********************************************************************/
+
+BOOL lsa_io_r_unk_get_connuser(char *desc, LSA_R_UNK_GET_CONNUSER *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_unk_get_connuser");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_user_name", ps, depth, &r_c->ptr_user_name))
+ return False;
+ if(!smb_io_unihdr("hdr_user_name", &r_c->hdr_user_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni2_user_name", &r_c->uni2_user_name, r_c->ptr_user_name, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("unk1", ps, depth, &r_c->unk1))
+ return False;
+
+ if(!prs_uint32("ptr_dom_name", ps, depth, &r_c->ptr_dom_name))
+ return False;
+ if(!smb_io_unihdr("hdr_dom_name", &r_c->hdr_dom_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni2_dom_name", &r_c->uni2_dom_name, r_c->ptr_dom_name, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+void init_lsa_q_open_account(LSA_Q_OPENACCOUNT *trn, POLICY_HND *hnd, DOM_SID *sid, uint32 desired_access)
+{
+ memcpy(&trn->pol, hnd, sizeof(trn->pol));
+
+ init_dom_sid2(&trn->sid, sid);
+ trn->access = desired_access;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_OPENACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_q_open_account(char *desc, LSA_Q_OPENACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_open_account");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ if(!smb_io_dom_sid2("sid", &r_c->sid, ps, depth)) /* domain SID */
+ return False;
+
+ if(!prs_uint32("access", ps, depth, &r_c->access))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_OPENACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_r_open_account(char *desc, LSA_R_OPENACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_open_account");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+void init_lsa_q_enum_privsaccount(LSA_Q_ENUMPRIVSACCOUNT *trn, POLICY_HND *hnd)
+{
+ memcpy(&trn->pol, hnd, sizeof(trn->pol));
+
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_ENUMPRIVSACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_q_enum_privsaccount(char *desc, LSA_Q_ENUMPRIVSACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_enum_privsaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LUID structure.
+********************************************************************/
+
+BOOL lsa_io_luid(char *desc, LUID *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_luid");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("low", ps, depth, &r_c->low))
+ return False;
+
+ if(!prs_uint32("high", ps, depth, &r_c->high))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LUID_ATTR structure.
+********************************************************************/
+
+BOOL lsa_io_luid_attr(char *desc, LUID_ATTR *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_luid_attr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!lsa_io_luid(desc, &r_c->luid, ps, depth))
+ return False;
+
+ if(!prs_uint32("attr", ps, depth, &r_c->attr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an PRIVILEGE_SET structure.
+********************************************************************/
+
+BOOL lsa_io_privilege_set(char *desc, PRIVILEGE_SET *r_c, prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "lsa_io_privilege_set");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count", ps, depth, &r_c->count))
+ return False;
+ if(!prs_uint32("control", ps, depth, &r_c->control))
+ return False;
+
+ for (i=0; i<r_c->count; i++) {
+ if (!lsa_io_luid_attr(desc, &r_c->set[i], ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+void init_lsa_r_enum_privsaccount(LSA_R_ENUMPRIVSACCOUNT *r_u, LUID_ATTR *set, uint32 count, uint32 control)
+{
+ r_u->ptr=1;
+ r_u->count=count;
+ r_u->set.set=set;
+ r_u->set.count=count;
+ r_u->set.control=control;
+ DEBUG(10,("init_lsa_r_enum_privsaccount: %d %d privileges\n", r_u->count, r_u->set.count));
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_ENUMPRIVSACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_r_enum_privsaccount(char *desc, LSA_R_ENUMPRIVSACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_enum_privsaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_c->ptr))
+ return False;
+
+ if (r_c->ptr!=0) {
+ if(!prs_uint32("count", ps, depth, &r_c->count))
+ return False;
+
+ /* malloc memory if unmarshalling here */
+
+ if (UNMARSHALLING(ps) && r_c->count!=0) {
+ if (!(r_c->set.set = (LUID_ATTR *)prs_alloc_mem(ps,sizeof(LUID_ATTR) * r_c->count)))
+ return False;
+
+ }
+
+ if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+
+/*******************************************************************
+ Reads or writes an LSA_Q_GETSYSTEMACCOUNTstructure.
+********************************************************************/
+
+BOOL lsa_io_q_getsystemaccount(char *desc, LSA_Q_GETSYSTEMACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_getsystemaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_GETSYSTEMACCOUNTstructure.
+********************************************************************/
+
+BOOL lsa_io_r_getsystemaccount(char *desc, LSA_R_GETSYSTEMACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_getsystemaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("access", ps, depth, &r_c->access))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Reads or writes an LSA_Q_SETSYSTEMACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_q_setsystemaccount(char *desc, LSA_Q_SETSYSTEMACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_setsystemaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("access", ps, depth, &r_c->access))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_SETSYSTEMACCOUNT structure.
+********************************************************************/
+
+BOOL lsa_io_r_setsystemaccount(char *desc, LSA_R_SETSYSTEMACCOUNT *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_setsystemaccount");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+void init_lsa_q_lookupprivvalue(LSA_Q_LOOKUPPRIVVALUE *trn, POLICY_HND *hnd, char *name)
+{
+ int len_name = strlen(name);
+ memcpy(&trn->pol, hnd, sizeof(trn->pol));
+
+ if(len_name == 0)
+ len_name = 1;
+
+ init_uni_hdr(&trn->hdr_right, len_name);
+ init_unistr2(&trn->uni2_right, name, len_name);
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_LOOKUPPRIVVALUE structure.
+********************************************************************/
+
+BOOL lsa_io_q_lookupprivvalue(char *desc, LSA_Q_LOOKUPPRIVVALUE *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_lookupprivvalue");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+ if(!smb_io_unihdr ("hdr_name", &r_c->hdr_right, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni2_right", &r_c->uni2_right, r_c->hdr_right.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_LOOKUPPRIVVALUE structure.
+********************************************************************/
+
+BOOL lsa_io_r_lookupprivvalue(char *desc, LSA_R_LOOKUPPRIVVALUE *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_lookupprivvalue");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!lsa_io_luid("luid", &r_c->luid, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Reads or writes an LSA_Q_ADDPRIVS structure.
+********************************************************************/
+
+BOOL lsa_io_q_addprivs(char *desc, LSA_Q_ADDPRIVS *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_addprivs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("count", ps, depth, &r_c->count))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_c->count!=0) {
+ if (!(r_c->set.set = (LUID_ATTR *)prs_alloc_mem(ps,sizeof(LUID_ATTR) * r_c->count)))
+ return False;
+ }
+
+ if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_ADDPRIVS structure.
+********************************************************************/
+
+BOOL lsa_io_r_addprivs(char *desc, LSA_R_ADDPRIVS *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_addprivs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_Q_REMOVEPRIVS structure.
+********************************************************************/
+
+BOOL lsa_io_q_removeprivs(char *desc, LSA_Q_REMOVEPRIVS *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_q_removeprivs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("allrights", ps, depth, &r_c->allrights))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_c->ptr))
+ return False;
+
+ /*
+ * JFM: I'm not sure at all if the count is inside the ptr
+ * never seen one with ptr=0
+ */
+
+ if (r_c->ptr!=0) {
+ if(!prs_uint32("count", ps, depth, &r_c->count))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_c->count!=0) {
+ if (!(r_c->set.set = (LUID_ATTR *)prs_alloc_mem(ps,sizeof(LUID_ATTR) * r_c->count)))
+ return False;
+ }
+
+ if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an LSA_R_REMOVEPRIVS structure.
+********************************************************************/
+
+BOOL lsa_io_r_removeprivs(char *desc, LSA_R_REMOVEPRIVS *r_c, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "lsa_io_r_removeprivs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
diff --git a/source/rpc_parse/parse_misc.c b/source/rpc_parse/parse_misc.c
new file mode 100644
index 00000000000..52e4b4b07c6
--- /dev/null
+++ b/source/rpc_parse/parse_misc.c
@@ -0,0 +1,1593 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/****************************************************************************
+ A temporary TALLOC context for things like unistrs, that is valid for
+ the life of a complete RPC call.
+****************************************************************************/
+
+static TALLOC_CTX *current_rpc_talloc = NULL;
+
+TALLOC_CTX *get_current_rpc_talloc(void)
+{
+ return current_rpc_talloc;
+}
+
+void set_current_rpc_talloc( TALLOC_CTX *ctx)
+{
+ current_rpc_talloc = ctx;
+}
+
+static TALLOC_CTX *main_loop_talloc = NULL;
+
+/*******************************************************************
+free up temporary memory - called from the main loop
+********************************************************************/
+
+void main_loop_talloc_free(void)
+{
+ if (!main_loop_talloc)
+ return;
+ talloc_destroy(main_loop_talloc);
+ main_loop_talloc = NULL;
+}
+
+/*******************************************************************
+ Get a talloc context that is freed in the main loop...
+********************************************************************/
+
+TALLOC_CTX *main_loop_talloc_get(void)
+{
+ if (!main_loop_talloc) {
+ main_loop_talloc = talloc_init();
+ if (!main_loop_talloc)
+ smb_panic("main_loop_talloc: malloc fail\n");
+ }
+
+ return main_loop_talloc;
+}
+
+/*******************************************************************
+ Try and get a talloc context. Get the rpc one if possible, else
+ get the main loop one. The main loop one is more dangerous as it
+ goes away between packets, the rpc one will stay around for as long
+ as a current RPC lasts.
+********************************************************************/
+
+TALLOC_CTX *get_talloc_ctx(void)
+{
+ TALLOC_CTX *tc = get_current_rpc_talloc();
+
+ if (tc)
+ return tc;
+ return main_loop_talloc_get();
+}
+
+/*******************************************************************
+ Reads or writes a UTIME type.
+********************************************************************/
+
+static BOOL smb_io_utime(char *desc, UTIME *t, prs_struct *ps, int depth)
+{
+ if (t == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_utime");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32 ("time", ps, depth, &t->time))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an NTTIME structure.
+********************************************************************/
+
+BOOL smb_io_time(char *desc, NTTIME *nttime, prs_struct *ps, int depth)
+{
+ if (nttime == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_time");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("low ", ps, depth, &nttime->low)) /* low part */
+ return False;
+ if(!prs_uint32("high", ps, depth, &nttime->high)) /* high part */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a LOOKUP_LEVEL structure.
+********************************************************************/
+
+BOOL smb_io_lookup_level(char *desc, LOOKUP_LEVEL *level, prs_struct *ps, int depth)
+{
+ if (level == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_lookup_level");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("value", ps, depth, &level->value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Gets an enumeration handle from an ENUM_HND structure.
+********************************************************************/
+
+uint32 get_enum_hnd(ENUM_HND *enh)
+{
+ return (enh && enh->ptr_hnd != 0) ? enh->handle : 0;
+}
+
+/*******************************************************************
+ Inits an ENUM_HND structure.
+********************************************************************/
+
+void init_enum_hnd(ENUM_HND *enh, uint32 hnd)
+{
+ DEBUG(5,("smb_io_enum_hnd\n"));
+
+ enh->ptr_hnd = (hnd != 0) ? 1 : 0;
+ enh->handle = hnd;
+}
+
+/*******************************************************************
+ Reads or writes an ENUM_HND structure.
+********************************************************************/
+
+BOOL smb_io_enum_hnd(char *desc, ENUM_HND *hnd, prs_struct *ps, int depth)
+{
+ if (hnd == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_enum_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_hnd", ps, depth, &hnd->ptr_hnd)) /* pointer */
+ return False;
+
+ if (hnd->ptr_hnd != 0) {
+ if(!prs_uint32("handle ", ps, depth, &hnd->handle )) /* enum handle */
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SID structure.
+********************************************************************/
+
+BOOL smb_io_dom_sid(char *desc, DOM_SID *sid, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8 ("sid_rev_num", ps, depth, &sid->sid_rev_num))
+ return False;
+ if(!prs_uint8 ("num_auths ", ps, depth, &sid->num_auths))
+ return False;
+
+ for (i = 0; i < 6; i++)
+ {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp) - 1, "id_auth[%d] ", i);
+ if(!prs_uint8 (tmp, ps, depth, &sid->id_auth[i]))
+ return False;
+ }
+
+ /* oops! XXXX should really issue a warning here... */
+ if (sid->num_auths > MAXSUBAUTHS)
+ sid->num_auths = MAXSUBAUTHS;
+
+ if(!prs_uint32s(False, "sub_auths ", ps, depth, sid->sub_auths, sid->num_auths))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_SID structure.
+
+ BIG NOTE: this function only does SIDS where the identauth is not >= 2^32
+ identauth >= 2^32 can be detected because it will be specified in hex
+********************************************************************/
+
+void init_dom_sid(DOM_SID *sid, char *str_sid)
+{
+ pstring domsid;
+ int identauth;
+ char *p;
+
+ if (str_sid == NULL)
+ {
+ DEBUG(4,("netlogon domain SID: none\n"));
+ sid->sid_rev_num = 0;
+ sid->num_auths = 0;
+ return;
+ }
+
+ pstrcpy(domsid, str_sid);
+
+ DEBUG(4,("init_dom_sid %d SID: %s\n", __LINE__, domsid));
+
+ /* assume, but should check, that domsid starts "S-" */
+ p = strtok(domsid+2,"-");
+ sid->sid_rev_num = atoi(p);
+
+ /* identauth in decimal should be < 2^32 */
+ /* identauth in hex should be >= 2^32 */
+ identauth = atoi(strtok(0,"-"));
+
+ DEBUG(4,("netlogon rev %d\n", sid->sid_rev_num));
+ DEBUG(4,("netlogon %s ia %d\n", p, identauth));
+
+ sid->id_auth[0] = 0;
+ sid->id_auth[1] = 0;
+ sid->id_auth[2] = (identauth & 0xff000000) >> 24;
+ sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
+ sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
+ sid->id_auth[5] = (identauth & 0x000000ff);
+
+ sid->num_auths = 0;
+
+ while ((p = strtok(0, "-")) != NULL && sid->num_auths < MAXSUBAUTHS)
+ sid->sub_auths[sid->num_auths++] = atoi(p);
+
+ DEBUG(4,("init_dom_sid: %d SID: %s\n", __LINE__, domsid));
+}
+
+/*******************************************************************
+ Inits a DOM_SID2 structure.
+********************************************************************/
+
+void init_dom_sid2(DOM_SID2 *sid2, const DOM_SID *sid)
+{
+ sid2->sid = *sid;
+ sid2->num_auths = sid2->sid.num_auths;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SID2 structure.
+********************************************************************/
+
+BOOL smb_io_dom_sid2(char *desc, DOM_SID2 *sid, prs_struct *ps, int depth)
+{
+ if (sid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_auths", ps, depth, &sid->num_auths))
+ return False;
+
+ if(!smb_io_dom_sid("sid", &sid->sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a STRHDR structure.
+********************************************************************/
+
+void init_str_hdr(STRHDR *hdr, int max_len, int len, uint32 buffer)
+{
+ hdr->str_max_len = max_len;
+ hdr->str_str_len = len;
+ hdr->buffer = buffer;
+}
+
+/*******************************************************************
+ Reads or writes a STRHDR structure.
+********************************************************************/
+
+BOOL smb_io_strhdr(char *desc, STRHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_strhdr");
+ depth++;
+
+ prs_align(ps);
+
+ if(!prs_uint16("str_str_len", ps, depth, &hdr->str_str_len))
+ return False;
+ if(!prs_uint16("str_max_len", ps, depth, &hdr->str_max_len))
+ return False;
+ if(!prs_uint32("buffer ", ps, depth, &hdr->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNIHDR structure.
+********************************************************************/
+
+void init_uni_hdr(UNIHDR *hdr, int len)
+{
+ hdr->uni_str_len = 2 * len;
+ hdr->uni_max_len = 2 * len;
+ hdr->buffer = len != 0 ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a UNIHDR structure.
+********************************************************************/
+
+BOOL smb_io_unihdr(char *desc, UNIHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unihdr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("uni_str_len", ps, depth, &hdr->uni_str_len))
+ return False;
+ if(!prs_uint16("uni_max_len", ps, depth, &hdr->uni_max_len))
+ return False;
+ if(!prs_uint32("buffer ", ps, depth, &hdr->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a BUFHDR structure.
+********************************************************************/
+
+void init_buf_hdr(BUFHDR *hdr, int max_len, int len)
+{
+ hdr->buf_max_len = max_len;
+ hdr->buf_len = len;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. Call this and it sets up a pointer to where the
+ uint16 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+BOOL smb_io_hdrbuf_pre(char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 *offset)
+{
+ (*offset) = prs_offset(ps);
+ if (ps->io) {
+
+ /* reading. */
+
+ if(!smb_io_hdrbuf(desc, hdr, ps, depth))
+ return False;
+
+ } else {
+
+ /* writing. */
+
+ if(!prs_set_offset(ps, prs_offset(ps) + (sizeof(uint32) * 2)))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ smb_io_hdrbuf wrapper. Call this and it retrospectively stores the size.
+ Does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+BOOL smb_io_hdrbuf_post(char *desc, BUFHDR *hdr, prs_struct *ps, int depth,
+ uint32 ptr_hdrbuf, uint32 max_len, uint32 len)
+{
+ if (!ps->io) {
+ /* writing: go back and do a retrospective job. i hate this */
+
+ uint32 old_offset = prs_offset(ps);
+
+ init_buf_hdr(hdr, max_len, len);
+ if(!prs_set_offset(ps, ptr_hdrbuf))
+ return False;
+ if(!smb_io_hdrbuf(desc, hdr, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a BUFHDR structure.
+********************************************************************/
+
+BOOL smb_io_hdrbuf(char *desc, BUFHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_hdrbuf");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_max_len", ps, depth, &hdr->buf_max_len))
+ return False;
+ if(!prs_uint32("buf_len ", ps, depth, &hdr->buf_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a UNIHDR2 structure.
+********************************************************************/
+
+void init_uni_hdr2(UNIHDR2 *hdr, int len)
+{
+ init_uni_hdr(&hdr->unihdr, len);
+ hdr->buffer = (len > 0) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a UNIHDR2 structure.
+********************************************************************/
+
+BOOL smb_io_unihdr2(char *desc, UNIHDR2 *hdr2, prs_struct *ps, int depth)
+{
+ if (hdr2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unihdr2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr", &hdr2->unihdr, ps, depth))
+ return False;
+ if(!prs_uint32("buffer", ps, depth, &hdr2->buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNISTR structure.
+********************************************************************/
+
+void init_unistr(UNISTR *str, const char *buf)
+{
+ size_t len;
+
+ if (buf == NULL) {
+ str->buffer = NULL;
+ return;
+ }
+
+
+ len = strlen(buf) + 1;
+
+ if (len < MAX_UNISTRLEN)
+ len = MAX_UNISTRLEN;
+ len *= sizeof(uint16);
+
+ str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+ if (str->buffer == NULL)
+ smb_panic("init_unistr: malloc fail\n");
+
+ rpcstr_push(str->buffer, buf, len, STR_TERMINATE);
+}
+
+/*******************************************************************
+reads or writes a UNISTR structure.
+XXXX NOTE: UNISTR structures NEED to be null-terminated.
+********************************************************************/
+
+BOOL smb_io_unistr(char *desc, UNISTR *uni, prs_struct *ps, int depth)
+{
+ if (uni == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unistr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_unistr("unistr", ps, depth, uni))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Allocate the BUFFER3 memory.
+********************************************************************/
+
+static void create_buffer3(BUFFER3 *str, size_t len)
+{
+ if (len < MAX_BUFFERLEN)
+ len = MAX_BUFFERLEN;
+
+ str->buffer = talloc_zero(get_talloc_ctx(), len);
+ if (str->buffer == NULL)
+ smb_panic("create_buffer3: talloc fail\n");
+
+}
+
+/*******************************************************************
+ Inits a BUFFER3 structure from a uint32
+********************************************************************/
+
+void init_buffer3_uint32(BUFFER3 *str, uint32 val)
+{
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ str->buf_max_len = sizeof(uint32);
+ str->buf_len = sizeof(uint32);
+
+ create_buffer3(str, sizeof(uint32));
+ SIVAL(str->buffer, 0, val);
+}
+
+/*******************************************************************
+ Inits a BUFFER3 structure.
+********************************************************************/
+
+void init_buffer3_str(BUFFER3 *str, char *buf, int len)
+{
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ str->buf_max_len = len * 2;
+ str->buf_len = len * 2;
+
+ create_buffer3(str, str->buf_max_len);
+
+ rpcstr_push(str->buffer, buf, str->buf_max_len, STR_TERMINATE);
+
+}
+
+/*******************************************************************
+ Inits a BUFFER3 structure from a hex string.
+********************************************************************/
+
+void init_buffer3_hex(BUFFER3 *str, char *buf)
+{
+ ZERO_STRUCTP(str);
+ create_buffer3(str, strlen(buf));
+ str->buf_max_len = str->buf_len = strhex_to_str((char *)str->buffer, sizeof(str->buffer), buf);
+}
+
+/*******************************************************************
+ Inits a BUFFER3 structure.
+********************************************************************/
+
+void init_buffer3_bytes(BUFFER3 *str, uint8 *buf, int len)
+{
+ ZERO_STRUCTP(str);
+
+ /* max buffer size (allocated size) */
+ str->buf_max_len = len;
+ if (buf != NULL) {
+ create_buffer3(str, len);
+ memcpy(str->buffer, buf, len);
+ }
+ str->buf_len = buf != NULL ? len : 0;
+}
+
+/*******************************************************************
+ Reads or writes a BUFFER3 structure.
+ the uni_max_len member tells you how large the buffer is.
+ the uni_str_len member tells you how much of the buffer is really used.
+********************************************************************/
+
+BOOL smb_io_buffer3(char *desc, BUFFER3 *buf3, prs_struct *ps, int depth)
+{
+ if (buf3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_buffer3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_max_len", ps, depth, &buf3->buf_max_len))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ buf3->buffer = (unsigned char *)prs_alloc_mem(ps, buf3->buf_max_len);
+ if (buf3->buffer == NULL)
+ return False;
+ }
+
+ if(!prs_uint8s(True, "buffer ", ps, depth, buf3->buffer, buf3->buf_max_len))
+ return False;
+
+ if(!prs_uint32("buf_len ", ps, depth, &buf3->buf_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a BUFFER5 structure.
+the buf_len member tells you how large the buffer is.
+********************************************************************/
+BOOL smb_io_buffer5(char *desc, BUFFER5 *buf5, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_buffer5");
+ depth++;
+
+ if (buf5 == NULL) return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("buf_len", ps, depth, &buf5->buf_len))
+ return False;
+
+
+ if(!prs_buffer5(True, "buffer" , ps, depth, buf5))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a BUFFER2 structure.
+********************************************************************/
+
+void init_buffer2(BUFFER2 *str, uint8 *buf, int len)
+{
+ ZERO_STRUCTP(str);
+
+ /* max buffer size (allocated size) */
+ str->buf_max_len = len;
+ str->undoc = 0;
+ str->buf_len = buf != NULL ? len : 0;
+
+ if (buf != NULL) {
+ if (len < MAX_BUFFERLEN)
+ len = MAX_BUFFERLEN;
+ str->buffer = talloc_zero(get_talloc_ctx(), len);
+ if (str->buffer == NULL)
+ smb_panic("init_buffer2: talloc fail\n");
+ memcpy(str->buffer, buf, MIN(str->buf_len, len));
+ }
+}
+
+/*******************************************************************
+ Reads or writes a BUFFER2 structure.
+ the uni_max_len member tells you how large the buffer is.
+ the uni_str_len member tells you how much of the buffer is really used.
+********************************************************************/
+
+BOOL smb_io_buffer2(char *desc, BUFFER2 *buf2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (buf2 == NULL)
+ return False;
+
+ if (buffer) {
+
+ prs_debug(ps, depth, desc, "smb_io_buffer2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_max_len", ps, depth, &buf2->buf_max_len))
+ return False;
+ if(!prs_uint32("undoc ", ps, depth, &buf2->undoc))
+ return False;
+ if(!prs_uint32("buf_len ", ps, depth, &buf2->buf_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+
+ if(!prs_buffer2(True, "buffer ", ps, depth, buf2))
+ return False;
+
+ } else {
+
+ prs_debug(ps, depth, desc, "smb_io_buffer2 - NULL");
+ depth++;
+ memset((char *)buf2, '\0', sizeof(*buf2));
+
+ }
+ return True;
+}
+
+/*******************************************************************
+creates a UNISTR2 structure: sets up the buffer, too
+********************************************************************/
+
+void init_buf_unistr2(UNISTR2 *str, uint32 *ptr, const char *buf)
+{
+ if (buf != NULL) {
+
+ *ptr = 1;
+ init_unistr2(str, buf, strlen(buf)+1);
+
+ } else {
+
+ *ptr = 0;
+ init_unistr2(str, "", 0);
+
+ }
+}
+
+/*******************************************************************
+ Copies a UNISTR2 structure.
+********************************************************************/
+
+void copy_unistr2(UNISTR2 *str, const UNISTR2 *from)
+{
+
+ /* set up string lengths. add one if string is not null-terminated */
+ str->uni_max_len = from->uni_max_len;
+ str->undoc = from->undoc;
+ str->uni_str_len = from->uni_str_len;
+
+ if (from->buffer == NULL)
+ return;
+
+ /* the string buffer is allocated to the maximum size
+ (the the length of the source string) to prevent
+ reallocation of memory. */
+ if (str->buffer == NULL) {
+ size_t len = from->uni_max_len * sizeof(uint16);
+
+ if (len < MAX_UNISTRLEN)
+ len = MAX_UNISTRLEN;
+ len *= sizeof(uint16);
+
+ str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+ if ((str->buffer == NULL) && (len > 0 ))
+ {
+ smb_panic("copy_unistr2: talloc fail\n");
+ return;
+ }
+ }
+
+ /* copy the string */
+ memcpy(str->buffer, from->buffer, from->uni_max_len*sizeof(uint16));
+}
+
+/*******************************************************************
+ Creates a STRING2 structure.
+********************************************************************/
+
+void init_string2(STRING2 *str, const char *buf, int max_len, int str_len)
+{
+ int alloc_len = 0;
+
+ /* set up string lengths. */
+ str->str_max_len = max_len;
+ str->undoc = 0;
+ str->str_str_len = str_len;
+
+ /* store the string */
+ if(str_len != 0) {
+ if (str_len < MAX_STRINGLEN)
+ alloc_len = MAX_STRINGLEN;
+ str->buffer = talloc_zero(get_talloc_ctx(), alloc_len);
+ if (str->buffer == NULL)
+ smb_panic("init_string2: malloc fail\n");
+ memcpy(str->buffer, buf, str_len);
+ }
+}
+
+/*******************************************************************
+ Reads or writes a STRING2 structure.
+ XXXX NOTE: STRING2 structures need NOT be null-terminated.
+ the str_str_len member tells you how long the string is;
+ the str_max_len member tells you how large the buffer is.
+********************************************************************/
+
+BOOL smb_io_string2(char *desc, STRING2 *str2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (str2 == NULL)
+ return False;
+
+ if (buffer) {
+
+ prs_debug(ps, depth, desc, "smb_io_string2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("str_max_len", ps, depth, &str2->str_max_len))
+ return False;
+ if(!prs_uint32("undoc ", ps, depth, &str2->undoc))
+ return False;
+ if(!prs_uint32("str_str_len", ps, depth, &str2->str_str_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ if(!prs_string2(True, "buffer ", ps, depth, str2))
+ return False;
+
+ } else {
+
+ prs_debug(ps, depth, desc, "smb_io_string2 - NULL");
+ depth++;
+ memset((char *)str2, '\0', sizeof(*str2));
+
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a UNISTR2 structure.
+********************************************************************/
+
+void init_unistr2(UNISTR2 *str, const char *buf, size_t len)
+{
+ ZERO_STRUCTP(str);
+
+ /* set up string lengths. */
+ str->uni_max_len = (uint32)len;
+ str->undoc = 0;
+ str->uni_str_len = (uint32)len;
+
+ if (len < MAX_UNISTRLEN)
+ len = MAX_UNISTRLEN;
+ len *= sizeof(uint16);
+
+ str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+ if ((str->buffer == NULL) && (len > 0))
+ {
+ smb_panic("init_unistr2: malloc fail\n");
+ return;
+ }
+
+ /*
+ * don't move this test above ! The UNISTR2 must be initialized !!!
+ * jfm, 7/7/2001.
+ */
+ if (buf==NULL)
+ return;
+
+ rpcstr_push((char *)str->buffer, buf, len, STR_TERMINATE);
+}
+
+/*******************************************************************
+ Inits a UNISTR2 structure from a UNISTR
+********************************************************************/
+void init_unistr2_from_unistr (UNISTR2 *to, UNISTR *from)
+{
+
+ uint32 i;
+
+ /* the destination UNISTR2 should never be NULL.
+ if it is it is a programming error */
+
+ /* if the source UNISTR is NULL, then zero out
+ the destination string and return */
+ ZERO_STRUCTP (to);
+ if ((from == NULL) || (from->buffer == NULL))
+ return;
+
+ /* get the length; UNISTR must be NULL terminated */
+ i = 0;
+ while ((from->buffer)[i]!='\0')
+ i++;
+ i++; /* one more to catch the terminating NULL */
+ /* is this necessary -- jerry? I need to think */
+
+ /* set up string lengths; uni_max_len is set to i+1
+ because we need to account for the final NULL termination */
+ to->uni_max_len = i;
+ to->undoc = 0;
+ to->uni_str_len = i;
+
+ /* allocate the space and copy the string buffer */
+ to->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), sizeof(uint16)*(to->uni_str_len));
+ if (to->buffer == NULL)
+ smb_panic("init_unistr2_from_unistr: malloc fail\n");
+ memcpy(to->buffer, from->buffer, to->uni_max_len*sizeof(uint16));
+
+ return;
+}
+
+
+/*******************************************************************
+ Reads or writes a UNISTR2 structure.
+ XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
+ the uni_str_len member tells you how long the string is;
+ the uni_max_len member tells you how large the buffer is.
+********************************************************************/
+
+BOOL smb_io_unistr2(char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (uni2 == NULL)
+ return False;
+
+ if (buffer) {
+
+ prs_debug(ps, depth, desc, "smb_io_unistr2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_max_len", ps, depth, &uni2->uni_max_len))
+ return False;
+ if(!prs_uint32("undoc ", ps, depth, &uni2->undoc))
+ return False;
+ if(!prs_uint32("uni_str_len", ps, depth, &uni2->uni_str_len))
+ return False;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ if(!prs_unistr2(True, "buffer ", ps, depth, uni2))
+ return False;
+
+ } else {
+
+ prs_debug(ps, depth, desc, "smb_io_unistr2 - NULL");
+ depth++;
+ memset((char *)uni2, '\0', sizeof(*uni2));
+
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_RID2 structure.
+********************************************************************/
+
+void init_dom_rid2(DOM_RID2 *rid2, uint32 rid, uint8 type, uint32 idx)
+{
+ rid2->type = type;
+ rid2->rid = rid;
+ rid2->rid_idx = idx;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_RID2 structure.
+********************************************************************/
+
+BOOL smb_io_dom_rid2(char *desc, DOM_RID2 *rid2, prs_struct *ps, int depth)
+{
+ if (rid2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8("type ", ps, depth, &rid2->type))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("rid ", ps, depth, &rid2->rid))
+ return False;
+ if(!prs_uint32("rid_idx", ps, depth, &rid2->rid_idx))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+creates a DOM_RID3 structure.
+********************************************************************/
+
+void init_dom_rid3(DOM_RID3 *rid3, uint32 rid, uint8 type)
+{
+ rid3->rid = rid;
+ rid3->type1 = type;
+ rid3->ptr_type = 0x1; /* non-zero, basically. */
+ rid3->type2 = 0x1;
+ rid3->unk = type;
+}
+
+/*******************************************************************
+reads or writes a DOM_RID3 structure.
+********************************************************************/
+
+BOOL smb_io_dom_rid3(char *desc, DOM_RID3 *rid3, prs_struct *ps, int depth)
+{
+ if (rid3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("rid ", ps, depth, &rid3->rid))
+ return False;
+ if(!prs_uint32("type1 ", ps, depth, &rid3->type1))
+ return False;
+ if(!prs_uint32("ptr_type", ps, depth, &rid3->ptr_type))
+ return False;
+ if(!prs_uint32("type2 ", ps, depth, &rid3->type2))
+ return False;
+ if(!prs_uint32("unk ", ps, depth, &rid3->unk))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_RID4 structure.
+********************************************************************/
+
+void init_dom_rid4(DOM_RID4 *rid4, uint16 unknown, uint16 attr, uint32 rid)
+{
+ rid4->unknown = unknown;
+ rid4->attr = attr;
+ rid4->rid = rid;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_SRV structure.
+********************************************************************/
+
+static void init_clnt_srv(DOM_CLNT_SRV *log, char *logon_srv, char *comp_name)
+{
+ DEBUG(5,("init_clnt_srv: %d\n", __LINE__));
+
+ if (logon_srv != NULL) {
+ log->undoc_buffer = 1;
+ init_unistr2(&log->uni_logon_srv, logon_srv, strlen(logon_srv)+1);
+ } else {
+ log->undoc_buffer = 0;
+ }
+
+ if (comp_name != NULL) {
+ log->undoc_buffer2 = 1;
+ init_unistr2(&log->uni_comp_name, comp_name, strlen(comp_name)+1);
+ } else {
+ log->undoc_buffer2 = 0;
+ }
+}
+
+/*******************************************************************
+ Inits or writes a DOM_CLNT_SRV structure.
+********************************************************************/
+
+static BOOL smb_io_clnt_srv(char *desc, DOM_CLNT_SRV *log, prs_struct *ps, int depth)
+{
+ if (log == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_srv");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer ", ps, depth, &log->undoc_buffer))
+ return False;
+
+ if (log->undoc_buffer != 0) {
+ if(!smb_io_unistr2("unistr2", &log->uni_logon_srv, log->undoc_buffer, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer2", ps, depth, &log->undoc_buffer2))
+ return False;
+
+ if (log->undoc_buffer2 != 0) {
+ if(!smb_io_unistr2("unistr2", &log->uni_comp_name, log->undoc_buffer2, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_LOG_INFO structure.
+********************************************************************/
+
+void init_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name)
+{
+ DEBUG(5,("make_log_info %d\n", __LINE__));
+
+ log->undoc_buffer = 1;
+
+ init_unistr2(&log->uni_logon_srv, logon_srv, strlen(logon_srv)+1);
+ init_unistr2(&log->uni_acct_name, acct_name, strlen(acct_name)+1);
+
+ log->sec_chan = sec_chan;
+
+ init_unistr2(&log->uni_comp_name, comp_name, strlen(comp_name)+1);
+}
+
+/*******************************************************************
+ Reads or writes a DOM_LOG_INFO structure.
+********************************************************************/
+
+BOOL smb_io_log_info(char *desc, DOM_LOG_INFO *log, prs_struct *ps, int depth)
+{
+ if (log == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_log_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer", ps, depth, &log->undoc_buffer))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &log->uni_logon_srv, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("unistr2", &log->uni_acct_name, True, ps, depth))
+ return False;
+
+ if(!prs_uint16("sec_chan", ps, depth, &log->sec_chan))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &log->uni_comp_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CHAL structure.
+********************************************************************/
+
+BOOL smb_io_chal(char *desc, DOM_CHAL *chal, prs_struct *ps, int depth)
+{
+ if (chal == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_chal");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s (False, "data", ps, depth, chal->data, 8))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CRED structure.
+********************************************************************/
+
+BOOL smb_io_cred(char *desc, DOM_CRED *cred, prs_struct *ps, int depth)
+{
+ if (cred == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_cred");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_chal ("", &cred->challenge, ps, depth))
+ return False;
+
+ if(!smb_io_utime("", &cred->timestamp, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_INFO2 structure.
+********************************************************************/
+
+void init_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred)
+{
+ DEBUG(5,("make_clnt_info: %d\n", __LINE__));
+
+ init_clnt_srv(&(clnt->login), logon_srv, comp_name);
+
+ if (clnt_cred != NULL) {
+ clnt->ptr_cred = 1;
+ memcpy(&(clnt->cred), clnt_cred, sizeof(clnt->cred));
+ } else {
+ clnt->ptr_cred = 0;
+ }
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CLNT_INFO2 structure.
+********************************************************************/
+
+BOOL smb_io_clnt_info2(char *desc, DOM_CLNT_INFO2 *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_clnt_srv("", &clnt->login, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_cred", ps, depth, &clnt->ptr_cred))
+ return False;
+ if(!smb_io_cred("", &clnt->cred, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_CLNT_INFO structure.
+********************************************************************/
+
+void init_clnt_info(DOM_CLNT_INFO *clnt,
+ char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name,
+ DOM_CRED *cred)
+{
+ DEBUG(5,("make_clnt_info\n"));
+
+ init_log_info(&clnt->login, logon_srv, acct_name, sec_chan, comp_name);
+ memcpy(&clnt->cred, cred, sizeof(clnt->cred));
+}
+
+/*******************************************************************
+ Reads or writes a DOM_CLNT_INFO structure.
+********************************************************************/
+
+BOOL smb_io_clnt_info(char *desc, DOM_CLNT_INFO *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_log_info("", &clnt->login, ps, depth))
+ return False;
+ if(!smb_io_cred("", &clnt->cred, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a DOM_LOGON_ID structure.
+********************************************************************/
+
+void init_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high)
+{
+ DEBUG(5,("make_logon_id: %d\n", __LINE__));
+
+ log->low = log_id_low;
+ log->high = log_id_high;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_LOGON_ID structure.
+********************************************************************/
+
+BOOL smb_io_logon_id(char *desc, DOM_LOGON_ID *log, prs_struct *ps, int depth)
+{
+ if (log == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_logon_id");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("low ", ps, depth, &log->low ))
+ return False;
+ if(!prs_uint32("high", ps, depth, &log->high))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an OWF_INFO structure.
+********************************************************************/
+
+void init_owf_info(OWF_INFO *hash, uint8 data[16])
+{
+ DEBUG(5,("init_owf_info: %d\n", __LINE__));
+
+ if (data != NULL)
+ memcpy(hash->data, data, sizeof(hash->data));
+ else
+ memset((char *)hash->data, '\0', sizeof(hash->data));
+}
+
+/*******************************************************************
+ Reads or writes an OWF_INFO structure.
+********************************************************************/
+
+BOOL smb_io_owf_info(char *desc, OWF_INFO *hash, prs_struct *ps, int depth)
+{
+ if (hash == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_owf_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s (False, "data", ps, depth, hash->data, 16))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_GID structure.
+********************************************************************/
+
+BOOL smb_io_gid(char *desc, DOM_GID *gid, prs_struct *ps, int depth)
+{
+ if (gid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_gid");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("g_rid", ps, depth, &gid->g_rid))
+ return False;
+ if(!prs_uint32("attr ", ps, depth, &gid->attr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an POLICY_HND structure.
+********************************************************************/
+
+BOOL smb_io_pol_hnd(char *desc, POLICY_HND *pol, prs_struct *ps, int depth)
+{
+ if (pol == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_pol_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(UNMARSHALLING(ps))
+ ZERO_STRUCTP(pol);
+
+ if (!prs_uint32("data1", ps, depth, &pol->data1))
+ return False;
+ if (!prs_uint32("data2", ps, depth, &pol->data2))
+ return False;
+ if (!prs_uint16("data3", ps, depth, &pol->data3))
+ return False;
+ if (!prs_uint16("data4", ps, depth, &pol->data4))
+ return False;
+ if(!prs_uint8s (False, "data5", ps, depth, pol->data5, sizeof(pol->data5)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Create a UNISTR3.
+********************************************************************/
+
+void init_unistr3(UNISTR3 *str, const char *buf)
+{
+ size_t len;
+
+ if (buf == NULL) {
+ str->uni_str_len=0;
+ str->str.buffer = NULL;
+ return;
+ }
+
+ len = strlen(buf) + 1;
+
+ str->uni_str_len=len;
+
+ if (len < MAX_UNISTRLEN)
+ len = MAX_UNISTRLEN;
+
+ len *= sizeof(uint16);
+
+ str->str.buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+ if (str->str.buffer == NULL)
+ smb_panic("init_unistr3: malloc fail\n");
+
+ rpcstr_push((char *)str->str.buffer, buf, len, STR_TERMINATE);
+}
+
+/*******************************************************************
+ Reads or writes a UNISTR3 structure.
+********************************************************************/
+
+BOOL smb_io_unistr3(char *desc, UNISTR3 *name, prs_struct *ps, int depth)
+{
+ if (name == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_unistr3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("uni_str_len", ps, depth, &name->uni_str_len))
+ return False;
+
+ /* don't know if len is specified by uni_str_len member... */
+ /* assume unicode string is unicode-null-terminated, instead */
+
+ if(!prs_unistr3(True, "unistr", name, ps, depth))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Stream a uint64_struct
+ ********************************************************************/
+BOOL prs_uint64(char *name, prs_struct *ps, int depth, UINT64_S *data64)
+{
+ return prs_uint32(name, ps, depth+1, &data64->low) &&
+ prs_uint32(name, ps, depth+1, &data64->high);
+}
+
+/*******************************************************************
+reads or writes a BUFHDR2 structure.
+********************************************************************/
+BOOL smb_io_bufhdr2(char *desc, BUFHDR2 *hdr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_bufhdr2");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("info_level", ps, depth, &(hdr->info_level));
+ prs_uint32("length ", ps, depth, &(hdr->length ));
+ prs_uint32("buffer ", ps, depth, &(hdr->buffer ));
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a BUFFER4 structure.
+********************************************************************/
+BOOL smb_io_buffer4(char *desc, BUFFER4 *buf4, uint32 buffer, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_buffer4");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("buf_len", ps, depth, &(buf4->buf_len));
+
+ if (buf4->buf_len > MAX_BUFFERLEN)
+ {
+ buf4->buf_len = MAX_BUFFERLEN;
+ }
+
+ prs_uint8s(True, "buffer", ps, depth, buf4->buffer, buf4->buf_len);
+
+ return True;
+}
+
+/*******************************************************************
+creates a UNIHDR structure.
+********************************************************************/
+
+BOOL make_uni_hdr(UNIHDR *hdr, int len)
+{
+ if (hdr == NULL)
+ {
+ return False;
+ }
+ hdr->uni_str_len = 2 * len;
+ hdr->uni_max_len = 2 * len;
+ hdr->buffer = len != 0 ? 1 : 0;
+
+ return True;
+}
+
+/*******************************************************************
+creates a BUFHDR2 structure.
+********************************************************************/
+BOOL make_bufhdr2(BUFHDR2 *hdr, uint32 info_level, uint32 length, uint32 buffer)
+{
+ hdr->info_level = info_level;
+ hdr->length = length;
+ hdr->buffer = buffer;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c
new file mode 100644
index 00000000000..b584673f386
--- /dev/null
+++ b/source/rpc_parse/parse_net.c
@@ -0,0 +1,2896 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL net_io_neg_flags(char *desc, NEG_FLAGS *neg, prs_struct *ps, int depth)
+{
+ if (neg == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_neg_flags");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("neg_flags", ps, depth, &neg->neg_flags))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a NETLOGON_INFO_3 structure.
+********************************************************************/
+
+static void init_netinfo_3(NETLOGON_INFO_3 *info, uint32 flags, uint32 logon_attempts)
+{
+ info->flags = flags;
+ info->logon_attempts = logon_attempts;
+ info->reserved_1 = 0x0;
+ info->reserved_2 = 0x0;
+ info->reserved_3 = 0x0;
+ info->reserved_4 = 0x0;
+ info->reserved_5 = 0x0;
+}
+
+/*******************************************************************
+ Reads or writes a NETLOGON_INFO_3 structure.
+********************************************************************/
+
+static BOOL net_io_netinfo_3(char *desc, NETLOGON_INFO_3 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("flags ", ps, depth, &info->flags))
+ return False;
+ if(!prs_uint32("logon_attempts", ps, depth, &info->logon_attempts))
+ return False;
+ if(!prs_uint32("reserved_1 ", ps, depth, &info->reserved_1))
+ return False;
+ if(!prs_uint32("reserved_2 ", ps, depth, &info->reserved_2))
+ return False;
+ if(!prs_uint32("reserved_3 ", ps, depth, &info->reserved_3))
+ return False;
+ if(!prs_uint32("reserved_4 ", ps, depth, &info->reserved_4))
+ return False;
+ if(!prs_uint32("reserved_5 ", ps, depth, &info->reserved_5))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a NETLOGON_INFO_1 structure.
+********************************************************************/
+
+static void init_netinfo_1(NETLOGON_INFO_1 *info, uint32 flags, uint32 pdc_status)
+{
+ info->flags = flags;
+ info->pdc_status = pdc_status;
+}
+
+/*******************************************************************
+ Reads or writes a NETLOGON_INFO_1 structure.
+********************************************************************/
+
+static BOOL net_io_netinfo_1(char *desc, NETLOGON_INFO_1 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("flags ", ps, depth, &info->flags))
+ return False;
+ if(!prs_uint32("pdc_status", ps, depth, &info->pdc_status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a NETLOGON_INFO_2 structure.
+********************************************************************/
+
+static void init_netinfo_2(NETLOGON_INFO_2 *info, uint32 flags, uint32 pdc_status,
+ uint32 tc_status, char *trusted_dc_name)
+{
+ int len_dc_name = strlen(trusted_dc_name);
+ info->flags = flags;
+ info->pdc_status = pdc_status;
+ info->ptr_trusted_dc_name = 1;
+ info->tc_status = tc_status;
+
+ if (trusted_dc_name != NULL)
+ init_unistr2(&info->uni_trusted_dc_name, trusted_dc_name, len_dc_name+1);
+ else
+ init_unistr2(&info->uni_trusted_dc_name, "", 1);
+}
+
+/*******************************************************************
+ Reads or writes a NETLOGON_INFO_2 structure.
+********************************************************************/
+
+static BOOL net_io_netinfo_2(char *desc, NETLOGON_INFO_2 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("flags ", ps, depth, &info->flags))
+ return False;
+ if(!prs_uint32("pdc_status ", ps, depth, &info->pdc_status))
+ return False;
+ if(!prs_uint32("ptr_trusted_dc_name", ps, depth, &info->ptr_trusted_dc_name))
+ return False;
+ if(!prs_uint32("tc_status ", ps, depth, &info->tc_status))
+ return False;
+
+ if (info->ptr_trusted_dc_name != 0) {
+ if(!smb_io_unistr2("unistr2", &info->uni_trusted_dc_name, info->ptr_trusted_dc_name, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an NET_Q_LOGON_CTRL2 structure.
+********************************************************************/
+
+BOOL net_io_q_logon_ctrl2(char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_logon_ctrl2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &q_l->ptr))
+ return False;
+
+ if(!smb_io_unistr2 ("", &q_l->uni_server_name, q_l->ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("function_code", ps, depth, &q_l->function_code))
+ return False;
+ if(!prs_uint32("query_level ", ps, depth, &q_l->query_level))
+ return False;
+ if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an NET_Q_LOGON_CTRL2 structure.
+********************************************************************/
+
+void init_net_q_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, char *srv_name,
+ uint32 query_level)
+{
+ DEBUG(5,("init_q_logon_ctrl2\n"));
+
+ q_l->function_code = 0x01;
+ q_l->query_level = query_level;
+ q_l->switch_value = 0x01;
+
+ init_unistr2(&q_l->uni_server_name, srv_name, strlen(srv_name) + 1);
+}
+
+/*******************************************************************
+ Inits an NET_R_LOGON_CTRL2 structure.
+********************************************************************/
+
+void init_net_r_logon_ctrl2(NET_R_LOGON_CTRL2 *r_l, uint32 query_level,
+ uint32 flags, uint32 pdc_status,
+ uint32 logon_attempts, uint32 tc_status,
+ char *trusted_domain_name)
+{
+ DEBUG(5,("init_r_logon_ctrl2\n"));
+
+ r_l->switch_value = query_level; /* should only be 0x1 */
+
+ switch (query_level) {
+ case 1:
+ r_l->ptr = 1; /* undocumented pointer */
+ init_netinfo_1(&r_l->logon.info1, flags, pdc_status);
+ r_l->status = NT_STATUS_OK;
+ break;
+ case 2:
+ r_l->ptr = 1; /* undocumented pointer */
+ init_netinfo_2(&r_l->logon.info2, flags, pdc_status,
+ tc_status, trusted_domain_name);
+ r_l->status = NT_STATUS_OK;
+ break;
+ case 3:
+ r_l->ptr = 1; /* undocumented pointer */
+ init_netinfo_3(&r_l->logon.info3, flags, logon_attempts);
+ r_l->status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(2,("init_r_logon_ctrl2: unsupported switch value %d\n",
+ r_l->switch_value));
+ r_l->ptr = 0; /* undocumented pointer */
+
+ /* take a guess at an error code... */
+ r_l->status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+}
+
+/*******************************************************************
+ Reads or writes an NET_R_LOGON_CTRL2 structure.
+********************************************************************/
+
+BOOL net_io_r_logon_ctrl2(char *desc, NET_R_LOGON_CTRL2 *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_logon_ctrl2");
+ depth++;
+
+ if(!prs_uint32("switch_value ", ps, depth, &r_l->switch_value))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &r_l->ptr))
+ return False;
+
+ if (r_l->ptr != 0) {
+ switch (r_l->switch_value) {
+ case 1:
+ if(!net_io_netinfo_1("", &r_l->logon.info1, ps, depth))
+ return False;
+ break;
+ case 2:
+ if(!net_io_netinfo_2("", &r_l->logon.info2, ps, depth))
+ return False;
+ break;
+ case 3:
+ if(!net_io_netinfo_3("", &r_l->logon.info3, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(2,("net_io_r_logon_ctrl2: unsupported switch value %d\n",
+ r_l->switch_value));
+ break;
+ }
+ }
+
+ if(!prs_ntstatus("status ", ps, depth, &r_l->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an NET_Q_LOGON_CTRL structure.
+********************************************************************/
+
+BOOL net_io_q_logon_ctrl(char *desc, NET_Q_LOGON_CTRL *q_l, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_q_logon_ctrl");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &q_l->ptr))
+ return False;
+
+ if(!smb_io_unistr2 ("", &q_l->uni_server_name, q_l->ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("function_code", ps, depth, &q_l->function_code))
+ return False;
+ if(!prs_uint32("query_level ", ps, depth, &q_l->query_level))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an NET_Q_LOGON_CTRL structure.
+********************************************************************/
+
+void init_net_q_logon_ctrl(NET_Q_LOGON_CTRL *q_l, char *srv_name,
+ uint32 query_level)
+{
+ DEBUG(5,("init_q_logon_ctrl\n"));
+
+ q_l->function_code = 0x01; /* ??? */
+ q_l->query_level = query_level;
+
+ init_unistr2(&q_l->uni_server_name, srv_name, strlen(srv_name) + 1);
+}
+
+/*******************************************************************
+ Inits an NET_R_LOGON_CTRL structure.
+********************************************************************/
+
+void init_net_r_logon_ctrl(NET_R_LOGON_CTRL *r_l, uint32 query_level,
+ uint32 flags, uint32 pdc_status)
+{
+ DEBUG(5,("init_r_logon_ctrl\n"));
+
+ r_l->switch_value = query_level; /* should only be 0x1 */
+
+ switch (query_level) {
+ case 1:
+ r_l->ptr = 1; /* undocumented pointer */
+ init_netinfo_1(&r_l->logon.info1, flags, pdc_status);
+ r_l->status = NT_STATUS_OK;
+ break;
+ default:
+ DEBUG(2,("init_r_logon_ctrl: unsupported switch value %d\n",
+ r_l->switch_value));
+ r_l->ptr = 0; /* undocumented pointer */
+
+ /* take a guess at an error code... */
+ r_l->status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+}
+
+/*******************************************************************
+ Reads or writes an NET_R_LOGON_CTRL structure.
+********************************************************************/
+
+BOOL net_io_r_logon_ctrl(char *desc, NET_R_LOGON_CTRL *r_l, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_r_logon_ctrl");
+ depth++;
+
+ if(!prs_uint32("switch_value ", ps, depth, &r_l->switch_value))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &r_l->ptr))
+ return False;
+
+ if (r_l->ptr != 0) {
+ switch (r_l->switch_value) {
+ case 1:
+ if(!net_io_netinfo_1("", &r_l->logon.info1, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(2,("net_io_r_logon_ctrl: unsupported switch value %d\n",
+ r_l->switch_value));
+ break;
+ }
+ }
+
+ if(!prs_ntstatus("status ", ps, depth, &r_l->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an NET_R_TRUST_DOM_LIST structure.
+********************************************************************/
+
+void init_r_trust_dom(NET_R_TRUST_DOM_LIST *r_t,
+ uint32 num_doms, char *dom_name)
+{
+ int i = 0;
+
+ DEBUG(5,("init_r_trust_dom\n"));
+
+ for (i = 0; i < MAX_TRUST_DOMS; i++) {
+ r_t->uni_trust_dom_name[i].uni_str_len = 0;
+ r_t->uni_trust_dom_name[i].uni_max_len = 0;
+ }
+ if (num_doms > MAX_TRUST_DOMS)
+ num_doms = MAX_TRUST_DOMS;
+
+ for (i = 0; i < num_doms; i++) {
+ fstring domain_name;
+ fstrcpy(domain_name, dom_name);
+ strupper(domain_name);
+ init_unistr2(&r_t->uni_trust_dom_name[i], domain_name, strlen(domain_name)+1);
+ /* the use of UNISTR2 here is non-standard. */
+ r_t->uni_trust_dom_name[i].undoc = 0x1;
+ }
+
+ r_t->status = NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Reads or writes an NET_R_TRUST_DOM_LIST structure.
+********************************************************************/
+
+BOOL net_io_r_trust_dom(char *desc, NET_R_TRUST_DOM_LIST *r_t, prs_struct *ps, int depth)
+{
+ uint32 value;
+
+ if (r_t == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_trust_dom");
+ depth++;
+
+ /* temporary code to give a valid response */
+ value=2;
+ if(!prs_uint32("status", ps, depth, &value))
+ return False;
+
+ value=1;
+ if(!prs_uint32("status", ps, depth, &value))
+ return False;
+ value=2;
+ if(!prs_uint32("status", ps, depth, &value))
+ return False;
+
+ value=0;
+ if(!prs_uint32("status", ps, depth, &value))
+ return False;
+
+ value=0;
+ if(!prs_uint32("status", ps, depth, &value))
+ return False;
+
+/* old non working code */
+#if 0
+ int i;
+
+ for (i = 0; i < MAX_TRUST_DOMS; i++) {
+ if (r_t->uni_trust_dom_name[i].uni_str_len == 0)
+ break;
+ if(!smb_io_unistr2("", &r_t->uni_trust_dom_name[i], True, ps, depth))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_t->status))
+ return False;
+#endif
+ return True;
+}
+
+
+/*******************************************************************
+ Reads or writes an NET_Q_TRUST_DOM_LIST structure.
+********************************************************************/
+
+BOOL net_io_q_trust_dom(char *desc, NET_Q_TRUST_DOM_LIST *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_trust_dom");
+ depth++;
+
+ if(!prs_uint32("ptr ", ps, depth, &q_l->ptr))
+ return False;
+ if(!smb_io_unistr2 ("", &q_l->uni_server_name, q_l->ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an NET_Q_REQ_CHAL structure.
+********************************************************************/
+
+void init_q_req_chal(NET_Q_REQ_CHAL *q_c,
+ char *logon_srv, char *logon_clnt,
+ DOM_CHAL *clnt_chal)
+{
+ DEBUG(5,("init_q_req_chal: %d\n", __LINE__));
+
+ q_c->undoc_buffer = 1; /* don't know what this buffer is */
+
+ init_unistr2(&q_c->uni_logon_srv, logon_srv , strlen(logon_srv )+1);
+ init_unistr2(&q_c->uni_logon_clnt, logon_clnt, strlen(logon_clnt)+1);
+
+ memcpy(q_c->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
+
+ DEBUG(5,("init_q_req_chal: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ Reads or writes an NET_Q_REQ_CHAL structure.
+********************************************************************/
+
+BOOL net_io_q_req_chal(char *desc, NET_Q_REQ_CHAL *q_c, prs_struct *ps, int depth)
+{
+ int old_align;
+
+ if (q_c == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_req_chal");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("undoc_buffer", ps, depth, &q_c->undoc_buffer))
+ return False;
+
+ if(!smb_io_unistr2("", &q_c->uni_logon_srv, True, ps, depth)) /* logon server unicode string */
+ return False;
+ if(!smb_io_unistr2("", &q_c->uni_logon_clnt, True, ps, depth)) /* logon client unicode string */
+ return False;
+
+ old_align = ps->align;
+ ps->align = 0;
+ /* client challenge is _not_ aligned after the unicode strings */
+ if(!smb_io_chal("", &q_c->clnt_chal, ps, depth)) {
+ /* client challenge */
+ ps->align = old_align;
+ return False;
+ }
+ ps->align = old_align;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_req_chal(char *desc, NET_R_REQ_CHAL *r_c, prs_struct *ps, int depth)
+{
+ if (r_c == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_req_chal");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_chal("", &r_c->srv_chal, ps, depth)) /* server challenge */
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_c->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_q_auth(char *desc, NET_Q_AUTH *q_a, prs_struct *ps, int depth)
+{
+ int old_align;
+ if (q_a == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_auth");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_log_info ("", &q_a->clnt_id, ps, depth)) /* client identification info */
+ return False;
+ /* client challenge is _not_ aligned */
+ old_align = ps->align;
+ ps->align = 0;
+ if(!smb_io_chal("", &q_a->clnt_chal, ps, depth)) {
+ /* client-calculated credentials */
+ ps->align = old_align;
+ return False;
+ }
+ ps->align = old_align;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_auth(char *desc, NET_R_AUTH *r_a, prs_struct *ps, int depth)
+{
+ if (r_a == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_auth");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_chal("", &r_a->srv_chal, ps, depth)) /* server challenge */
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_a->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a NET_Q_AUTH_2 struct.
+********************************************************************/
+
+void init_q_auth_2(NET_Q_AUTH_2 *q_a,
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CHAL *clnt_chal, uint32 clnt_flgs)
+{
+ DEBUG(5,("init_q_auth_2: %d\n", __LINE__));
+
+ init_log_info(&q_a->clnt_id, logon_srv, acct_name, sec_chan, comp_name);
+ memcpy(q_a->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
+ q_a->clnt_flgs.neg_flags = clnt_flgs;
+
+ DEBUG(5,("init_q_auth_2: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_q_auth_2(char *desc, NET_Q_AUTH_2 *q_a, prs_struct *ps, int depth)
+{
+ int old_align;
+ if (q_a == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_auth_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_log_info ("", &q_a->clnt_id, ps, depth)) /* client identification info */
+ return False;
+ /* client challenge is _not_ aligned */
+ old_align = ps->align;
+ ps->align = 0;
+ if(!smb_io_chal("", &q_a->clnt_chal, ps, depth)) {
+ /* client-calculated credentials */
+ ps->align = old_align;
+ return False;
+ }
+ ps->align = old_align;
+ if(!net_io_neg_flags("", &q_a->clnt_flgs, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_auth_2(char *desc, NET_R_AUTH_2 *r_a, prs_struct *ps, int depth)
+{
+ if (r_a == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_auth_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_chal("", &r_a->srv_chal, ps, depth)) /* server challenge */
+ return False;
+ if(!net_io_neg_flags("", &r_a->srv_flgs, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_a->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a NET_Q_SRV_PWSET.
+********************************************************************/
+
+void init_q_srv_pwset(NET_Q_SRV_PWSET *q_s, char *logon_srv, char *sess_key, char *acct_name,
+ uint16 sec_chan, char *comp_name, DOM_CRED *cred, char hashed_mach_pwd[16])
+{
+ unsigned char nt_cypher[16];
+
+ DEBUG(5,("init_q_srv_pwset\n"));
+
+ /* Process the new password. */
+ cred_hash3( nt_cypher, hashed_mach_pwd, sess_key, 1);
+
+ init_clnt_info(&q_s->clnt_id, logon_srv, acct_name, sec_chan, comp_name, cred);
+
+ memcpy(q_s->pwd, nt_cypher, sizeof(q_s->pwd));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_q_srv_pwset(char *desc, NET_Q_SRV_PWSET *q_s, prs_struct *ps, int depth)
+{
+ if (q_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_srv_pwset");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_clnt_info("", &q_s->clnt_id, ps, depth)) /* client identification/authentication info */
+ return False;
+ if(!prs_uint8s (False, "pwd", ps, depth, q_s->pwd, 16)) /* new password - undocumented */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_srv_pwset(char *desc, NET_R_SRV_PWSET *r_s, prs_struct *ps, int depth)
+{
+ if (r_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_srv_pwset");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_cred("", &r_s->srv_cred, ps, depth)) /* server challenge */
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_s->status))
+ return False;
+
+ return True;
+}
+
+/*************************************************************************
+ Init DOM_SID2 array from a string containing multiple sids
+ *************************************************************************/
+
+static int init_dom_sid2s(TALLOC_CTX *ctx, char *sids_str, DOM_SID2 **ppsids)
+{
+ char *ptr;
+ pstring s2;
+ int count = 0;
+
+ DEBUG(4,("init_dom_sid2s: %s\n", sids_str ? sids_str:""));
+
+ *ppsids = NULL;
+
+ if(sids_str) {
+ int number;
+ DOM_SID2 *sids;
+
+ /* Count the number of SIDs. */
+ for (count = 0, ptr = sids_str;
+ next_token(&ptr, s2, NULL, sizeof(s2)); count++)
+ ;
+
+ /* Now allocate space for them. */
+ *ppsids = (DOM_SID2 *)talloc_zero(ctx, count * sizeof(DOM_SID2));
+ if (*ppsids == NULL)
+ return 0;
+
+ sids = *ppsids;
+
+ for (number = 0, ptr = sids_str;
+ next_token(&ptr, s2, NULL, sizeof(s2)); number++) {
+ DOM_SID tmpsid;
+ string_to_sid(&tmpsid, s2);
+ init_dom_sid2(&sids[number], &tmpsid);
+ }
+ }
+
+ return count;
+}
+
+/*******************************************************************
+ Inits a NET_ID_INFO_1 structure.
+********************************************************************/
+
+void init_id_info1(NET_ID_INFO_1 *id, char *domain_name,
+ uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
+ char *user_name, char *wksta_name,
+ char *sess_key,
+ unsigned char lm_cypher[16], unsigned char nt_cypher[16])
+{
+ int len_domain_name = strlen(domain_name);
+ int len_user_name = strlen(user_name );
+ int len_wksta_name = strlen(wksta_name );
+
+ unsigned char lm_owf[16];
+ unsigned char nt_owf[16];
+
+ DEBUG(5,("init_id_info1: %d\n", __LINE__));
+
+ id->ptr_id_info1 = 1;
+
+ init_uni_hdr(&id->hdr_domain_name, len_domain_name);
+
+ id->param_ctrl = param_ctrl;
+ init_logon_id(&id->logon_id, log_id_low, log_id_high);
+
+ init_uni_hdr(&id->hdr_user_name, len_user_name);
+ init_uni_hdr(&id->hdr_wksta_name, len_wksta_name);
+
+ if (lm_cypher && nt_cypher) {
+ unsigned char key[16];
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm cypher:"));
+ dump_data(100, (char *)lm_cypher, 16);
+
+ DEBUG(100,("nt cypher:"));
+ dump_data(100, (char *)nt_cypher, 16);
+#endif
+
+ memset(key, 0, 16);
+ memcpy(key, sess_key, 8);
+
+ memcpy(lm_owf, lm_cypher, 16);
+ SamOEMhash(lm_owf, key, 16);
+ memcpy(nt_owf, nt_cypher, 16);
+ SamOEMhash(nt_owf, key, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("encrypt of lm owf password:"));
+ dump_data(100, (char *)lm_owf, 16);
+
+ DEBUG(100,("encrypt of nt owf password:"));
+ dump_data(100, (char *)nt_owf, 16);
+#endif
+ /* set up pointers to cypher blocks */
+ lm_cypher = lm_owf;
+ nt_cypher = nt_owf;
+ }
+
+ init_owf_info(&id->lm_owf, lm_cypher);
+ init_owf_info(&id->nt_owf, nt_cypher);
+
+ init_unistr2(&id->uni_domain_name, domain_name, len_domain_name);
+ init_unistr2(&id->uni_user_name, user_name, len_user_name);
+ init_unistr2(&id->uni_wksta_name, wksta_name, len_wksta_name);
+}
+
+/*******************************************************************
+ Reads or writes an NET_ID_INFO_1 structure.
+********************************************************************/
+
+static BOOL net_io_id_info1(char *desc, NET_ID_INFO_1 *id, prs_struct *ps, int depth)
+{
+ if (id == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_id_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_id_info1", ps, depth, &id->ptr_id_info1))
+ return False;
+
+ if (id->ptr_id_info1 != 0) {
+ if(!smb_io_unihdr("unihdr", &id->hdr_domain_name, ps, depth))
+ return False;
+
+ if(!prs_uint32("param_ctrl", ps, depth, &id->param_ctrl))
+ return False;
+ if(!smb_io_logon_id("", &id->logon_id, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("unihdr", &id->hdr_user_name, ps, depth))
+ return False;
+ if(!smb_io_unihdr("unihdr", &id->hdr_wksta_name, ps, depth))
+ return False;
+
+ if(!smb_io_owf_info("", &id->lm_owf, ps, depth))
+ return False;
+ if(!smb_io_owf_info("", &id->nt_owf, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &id->uni_domain_name,
+ id->hdr_domain_name.buffer, ps, depth))
+ return False;
+ if(!smb_io_unistr2("unistr2", &id->uni_user_name,
+ id->hdr_user_name.buffer, ps, depth))
+ return False;
+ if(!smb_io_unistr2("unistr2", &id->uni_wksta_name,
+ id->hdr_wksta_name.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+Inits a NET_ID_INFO_2 structure.
+
+This is a network logon packet. The log_id parameters
+are what an NT server would generate for LUID once the
+user is logged on. I don't think we care about them.
+
+Note that this has no access to the NT and LM hashed passwords,
+so it forwards the challenge, and the NT and LM responses (24
+bytes each) over the secure channel to the Domain controller
+for it to say yea or nay. This is the preferred method of
+checking for a logon as it doesn't export the password
+hashes to anyone who has compromised the secure channel. JRA.
+********************************************************************/
+
+void init_id_info2(NET_ID_INFO_2 * id, const char *domain_name,
+ uint32 param_ctrl,
+ uint32 log_id_low, uint32 log_id_high,
+ const char *user_name, const char *wksta_name,
+ const uchar lm_challenge[8],
+ const uchar * lm_chal_resp, int lm_chal_resp_len,
+ const uchar * nt_chal_resp, int nt_chal_resp_len)
+{
+ int len_domain_name = strlen(domain_name);
+ int len_user_name = strlen(user_name );
+ int len_wksta_name = strlen(wksta_name );
+ unsigned char lm_owf[24];
+ unsigned char nt_owf[128];
+
+ DEBUG(5,("init_id_info2: %d\n", __LINE__));
+
+ id->ptr_id_info2 = 1;
+
+ init_uni_hdr(&id->hdr_domain_name, len_domain_name);
+
+ id->param_ctrl = param_ctrl;
+ init_logon_id(&id->logon_id, log_id_low, log_id_high);
+
+ init_uni_hdr(&id->hdr_user_name, len_user_name);
+ init_uni_hdr(&id->hdr_wksta_name, len_wksta_name);
+
+ if (nt_chal_resp) {
+ /* oops. can only send what-ever-it-is direct */
+ memcpy(nt_owf, nt_chal_resp, MIN(sizeof(nt_owf), nt_chal_resp_len));
+ nt_chal_resp = nt_owf;
+ }
+ if (lm_chal_resp) {
+ /* oops. can only send what-ever-it-is direct */
+ memcpy(lm_owf, lm_chal_resp, MIN(sizeof(lm_owf), lm_chal_resp_len));
+ lm_chal_resp = lm_owf;
+ }
+
+ memcpy(id->lm_chal, lm_challenge, sizeof(id->lm_chal));
+ init_str_hdr(&id->hdr_nt_chal_resp, nt_chal_resp_len, nt_chal_resp_len, (nt_chal_resp != NULL) ? 1 : 0);
+ init_str_hdr(&id->hdr_lm_chal_resp, lm_chal_resp_len, lm_chal_resp_len, (lm_chal_resp != NULL) ? 1 : 0);
+
+ init_unistr2(&id->uni_domain_name, domain_name, len_domain_name);
+ init_unistr2(&id->uni_user_name, user_name, len_user_name);
+ init_unistr2(&id->uni_wksta_name, wksta_name, len_wksta_name);
+
+ init_string2(&id->nt_chal_resp, (const char *)nt_chal_resp, nt_chal_resp_len, nt_chal_resp_len);
+ init_string2(&id->lm_chal_resp, (const char *)lm_chal_resp, lm_chal_resp_len, lm_chal_resp_len);
+
+}
+
+/*******************************************************************
+ Reads or writes an NET_ID_INFO_2 structure.
+********************************************************************/
+
+static BOOL net_io_id_info2(char *desc, NET_ID_INFO_2 *id, prs_struct *ps, int depth)
+{
+ if (id == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_id_info2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_id_info2", ps, depth, &id->ptr_id_info2))
+ return False;
+
+ if (id->ptr_id_info2 != 0) {
+ if(!smb_io_unihdr("unihdr", &id->hdr_domain_name, ps, depth))
+ return False;
+
+ if(!prs_uint32("param_ctrl", ps, depth, &id->param_ctrl))
+ return False;
+ if(!smb_io_logon_id("", &id->logon_id, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("unihdr", &id->hdr_user_name, ps, depth))
+ return False;
+ if(!smb_io_unihdr("unihdr", &id->hdr_wksta_name, ps, depth))
+ return False;
+
+ if(!prs_uint8s (False, "lm_chal", ps, depth, id->lm_chal, 8)) /* lm 8 byte challenge */
+ return False;
+
+ if(!smb_io_strhdr("hdr_nt_chal_resp", &id->hdr_nt_chal_resp, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_lm_chal_resp", &id->hdr_lm_chal_resp, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_domain_name", &id->uni_domain_name,
+ id->hdr_domain_name.buffer, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_user_name ", &id->uni_user_name,
+ id->hdr_user_name.buffer, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_wksta_name ", &id->uni_wksta_name,
+ id->hdr_wksta_name.buffer, ps, depth))
+ return False;
+ if(!smb_io_string2("nt_chal_resp", &id->nt_chal_resp,
+ id->hdr_nt_chal_resp.buffer, ps, depth))
+ return False;
+ if(!smb_io_string2("lm_chal_resp", &id->lm_chal_resp,
+ id->hdr_lm_chal_resp.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a DOM_SAM_INFO structure.
+********************************************************************/
+
+void init_sam_info(DOM_SAM_INFO *sam,
+ char *logon_srv, char *comp_name, DOM_CRED *clnt_cred,
+ DOM_CRED *rtn_cred, uint16 logon_level,
+ NET_ID_INFO_CTR *ctr)
+{
+ DEBUG(5,("init_sam_info: %d\n", __LINE__));
+
+ init_clnt_info2(&sam->client, logon_srv, comp_name, clnt_cred);
+
+ if (rtn_cred != NULL) {
+ sam->ptr_rtn_cred = 1;
+ memcpy(&sam->rtn_cred, rtn_cred, sizeof(sam->rtn_cred));
+ } else {
+ sam->ptr_rtn_cred = 0;
+ }
+
+ sam->logon_level = logon_level;
+ sam->ctr = ctr;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SAM_INFO structure.
+********************************************************************/
+
+static BOOL net_io_id_info_ctr(char *desc, NET_ID_INFO_CTR **pp_ctr, prs_struct *ps, int depth)
+{
+ NET_ID_INFO_CTR *ctr = *pp_ctr;
+
+ prs_debug(ps, depth, desc, "smb_io_sam_info");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ ctr = *pp_ctr = (NET_ID_INFO_CTR *)prs_alloc_mem(ps, sizeof(NET_ID_INFO_CTR));
+ if (ctr == NULL)
+ return False;
+ }
+
+ if (ctr == NULL)
+ return False;
+
+ /* don't 4-byte align here! */
+
+ if(!prs_uint16("switch_value ", ps, depth, &ctr->switch_value))
+ return False;
+
+ switch (ctr->switch_value) {
+ case 1:
+ if(!net_io_id_info1("", &ctr->auth.id1, ps, depth))
+ return False;
+ break;
+ case 2:
+ if(!net_io_id_info2("", &ctr->auth.id2, ps, depth))
+ return False;
+ break;
+ default:
+ /* PANIC! */
+ DEBUG(4,("smb_io_sam_info: unknown switch_value!\n"));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a DOM_SAM_INFO structure.
+ ********************************************************************/
+
+static BOOL smb_io_sam_info(char *desc, DOM_SAM_INFO *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_sam_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_clnt_info2("", &sam->client, ps, depth))
+ return False;
+
+ if(!prs_uint32("ptr_rtn_cred ", ps, depth, &sam->ptr_rtn_cred))
+ return False;
+ if(!smb_io_cred("", &sam->rtn_cred, ps, depth))
+ return False;
+
+ if(!prs_uint16("logon_level ", ps, depth, &sam->logon_level))
+ return False;
+
+ if (sam->logon_level != 0) {
+ if(!net_io_id_info_ctr("logon_info", &sam->ctr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ Init
+ *************************************************************************/
+
+void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr, SAM_ACCOUNT *sampw,
+ uint16 logon_count, uint16 bad_pw_count,
+ uint32 num_groups, DOM_GID *gids,
+ uint32 user_flgs, uchar *sess_key,
+ char *logon_srv, char *logon_dom,
+ DOM_SID *dom_sid, char *other_sids)
+{
+ /* only cope with one "other" sid, right now. */
+ /* need to count the number of space-delimited sids */
+ int i;
+ int num_other_sids = 0;
+
+ NTTIME logon_time, logoff_time, kickoff_time,
+ pass_last_set_time, pass_can_change_time,
+ pass_must_change_time;
+
+ int len_user_name, len_full_name, len_home_dir,
+ len_dir_drive, len_logon_script, len_profile_path;
+
+ const char* user_name = pdb_get_username(sampw);
+ const char* full_name = pdb_get_fullname(sampw);
+ const char* home_dir = pdb_get_homedir(sampw);
+ const char* dir_drive = pdb_get_dirdrive(sampw);
+ const char* logon_script = pdb_get_logon_script(sampw);
+ const char* profile_path = pdb_get_profile_path(sampw);
+
+ int len_logon_srv = strlen(logon_srv);
+ int len_logon_dom = strlen(logon_dom);
+
+ len_user_name = strlen(user_name );
+ len_full_name = strlen(full_name );
+ len_home_dir = strlen(home_dir );
+ len_dir_drive = strlen(dir_drive );
+ len_logon_script = strlen(logon_script);
+ len_profile_path = strlen(profile_path);
+
+
+ ZERO_STRUCTP(usr);
+
+ usr->ptr_user_info = 1; /* yes, we're bothering to put USER_INFO data here */
+
+
+ /* Create NTTIME structs */
+ unix_to_nt_time (&logon_time, pdb_get_logon_time(sampw));
+ unix_to_nt_time (&logoff_time, pdb_get_logoff_time(sampw));
+ unix_to_nt_time (&kickoff_time, pdb_get_kickoff_time(sampw));
+ unix_to_nt_time (&pass_last_set_time, pdb_get_pass_last_set_time(sampw));
+ unix_to_nt_time (&pass_can_change_time, pdb_get_pass_can_change_time(sampw));
+ unix_to_nt_time (&pass_must_change_time,pdb_get_pass_must_change_time(sampw));
+
+ usr->logon_time = logon_time;
+ usr->logoff_time = logoff_time;
+ usr->kickoff_time = kickoff_time;
+ usr->pass_last_set_time = pass_last_set_time;
+ usr->pass_can_change_time = pass_can_change_time;
+ usr->pass_must_change_time = pass_must_change_time;
+
+ init_uni_hdr(&usr->hdr_user_name, len_user_name);
+ init_uni_hdr(&usr->hdr_full_name, len_full_name);
+ init_uni_hdr(&usr->hdr_logon_script, len_logon_script);
+ init_uni_hdr(&usr->hdr_profile_path, len_profile_path);
+ init_uni_hdr(&usr->hdr_home_dir, len_home_dir);
+ init_uni_hdr(&usr->hdr_dir_drive, len_dir_drive);
+
+ usr->logon_count = logon_count;
+ usr->bad_pw_count = bad_pw_count;
+
+ usr->user_rid = pdb_get_user_rid(sampw);
+ usr->group_rid = pdb_get_group_rid(sampw);
+ usr->num_groups = num_groups;
+
+ usr->buffer_groups = 1; /* indicates fill in groups, below, even if there are none */
+ usr->user_flgs = user_flgs;
+
+ if (sess_key != NULL)
+ memcpy(usr->user_sess_key, sess_key, sizeof(usr->user_sess_key));
+ else
+ memset((char *)usr->user_sess_key, '\0', sizeof(usr->user_sess_key));
+
+ init_uni_hdr(&usr->hdr_logon_srv, len_logon_srv);
+ init_uni_hdr(&usr->hdr_logon_dom, len_logon_dom);
+
+ usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
+
+ memset((char *)usr->padding, '\0', sizeof(usr->padding));
+
+ num_other_sids = init_dom_sid2s(ctx, other_sids, &usr->other_sids);
+
+ usr->num_other_sids = num_other_sids;
+ usr->buffer_other_sids = (num_other_sids != 0) ? 1 : 0;
+
+ init_unistr2(&usr->uni_user_name, user_name, len_user_name);
+ init_unistr2(&usr->uni_full_name, full_name, len_full_name);
+ init_unistr2(&usr->uni_logon_script, logon_script, len_logon_script);
+ init_unistr2(&usr->uni_profile_path, profile_path, len_profile_path);
+ init_unistr2(&usr->uni_home_dir, home_dir, len_home_dir);
+ init_unistr2(&usr->uni_dir_drive, dir_drive, len_dir_drive);
+
+ usr->num_groups2 = num_groups;
+
+ usr->gids = (DOM_GID *)talloc_zero(ctx,sizeof(DOM_GID) * (num_groups));
+ if (usr->gids == NULL && num_groups>0)
+ return;
+
+ for (i = 0; i < num_groups; i++)
+ usr->gids[i] = gids[i];
+
+ init_unistr2(&usr->uni_logon_srv, logon_srv, len_logon_srv);
+ init_unistr2(&usr->uni_logon_dom, logon_dom, len_logon_dom);
+
+ init_dom_sid2(&usr->dom_sid, dom_sid);
+ /* "other" sids are set up above */
+}
+
+/*******************************************************************
+ This code has been modified to cope with a NET_USER_INFO_2 - which is
+ exactly the same as a NET_USER_INFO_3, minus the other sids parameters.
+ We use validation level to determine if we're marshalling a info 2 or
+ INFO_3 - be we always return an INFO_3. Based on code donated by Marc
+ Jacobsen at HP. JRA.
+********************************************************************/
+
+static BOOL net_io_user_info3(char *desc, NET_USER_INFO_3 *usr, prs_struct *ps, int depth, uint16 validation_level)
+{
+ int i;
+
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "lsa_io_lsa_user_info");
+ depth++;
+
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(usr);
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_user_info ", ps, depth, &usr->ptr_user_info))
+ return False;
+
+ if (usr->ptr_user_info == 0)
+ return True;
+
+ if(!smb_io_time("logon time", &usr->logon_time, ps, depth)) /* logon time */
+ return False;
+ if(!smb_io_time("logoff time", &usr->logoff_time, ps, depth)) /* logoff time */
+ return False;
+ if(!smb_io_time("kickoff time", &usr->kickoff_time, ps, depth)) /* kickoff time */
+ return False;
+ if(!smb_io_time("last set time", &usr->pass_last_set_time, ps, depth)) /* password last set time */
+ return False;
+ if(!smb_io_time("can change time", &usr->pass_can_change_time , ps, depth)) /* password can change time */
+ return False;
+ if(!smb_io_time("must change time", &usr->pass_must_change_time, ps, depth)) /* password must change time */
+ return False;
+
+ if(!smb_io_unihdr("hdr_user_name", &usr->hdr_user_name, ps, depth)) /* username unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_full_name", &usr->hdr_full_name, ps, depth)) /* user's full name unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_logon_script", &usr->hdr_logon_script, ps, depth)) /* logon script unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_profile_path", &usr->hdr_profile_path, ps, depth)) /* profile path unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_home_dir", &usr->hdr_home_dir, ps, depth)) /* home directory unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_dir_drive", &usr->hdr_dir_drive, ps, depth)) /* home directory drive unicode string header */
+ return False;
+
+ if(!prs_uint16("logon_count ", ps, depth, &usr->logon_count)) /* logon count */
+ return False;
+ if(!prs_uint16("bad_pw_count ", ps, depth, &usr->bad_pw_count)) /* bad password count */
+ return False;
+
+ if(!prs_uint32("user_rid ", ps, depth, &usr->user_rid)) /* User RID */
+ return False;
+ if(!prs_uint32("group_rid ", ps, depth, &usr->group_rid)) /* Group RID */
+ return False;
+ if(!prs_uint32("num_groups ", ps, depth, &usr->num_groups)) /* num groups */
+ return False;
+ if(!prs_uint32("buffer_groups ", ps, depth, &usr->buffer_groups)) /* undocumented buffer pointer to groups. */
+ return False;
+ if(!prs_uint32("user_flgs ", ps, depth, &usr->user_flgs)) /* user flags */
+ return False;
+
+ if(!prs_uint8s(False, "user_sess_key", ps, depth, usr->user_sess_key, 16)) /* unused user session key */
+ return False;
+
+ if(!smb_io_unihdr("hdr_logon_srv", &usr->hdr_logon_srv, ps, depth)) /* logon server unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_logon_dom", &usr->hdr_logon_dom, ps, depth)) /* logon domain unicode string header */
+ return False;
+
+ if(!prs_uint32("buffer_dom_id ", ps, depth, &usr->buffer_dom_id)) /* undocumented logon domain id pointer */
+ return False;
+ if(!prs_uint8s (False, "padding ", ps, depth, usr->padding, 40)) /* unused padding bytes? */
+ return False;
+
+ if (validation_level == 3) {
+ if(!prs_uint32("num_other_sids", ps, depth, &usr->num_other_sids)) /* 0 - num_sids */
+ return False;
+ if(!prs_uint32("buffer_other_sids", ps, depth, &usr->buffer_other_sids)) /* NULL - undocumented pointer to SIDs. */
+ return False;
+ } else {
+ if (UNMARSHALLING(ps)) {
+ usr->num_other_sids = 0;
+ usr->buffer_other_sids = 0;
+ }
+ }
+
+ if(!smb_io_unistr2("uni_user_name", &usr->uni_user_name, usr->hdr_user_name.buffer, ps, depth)) /* username unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_full_name", &usr->uni_full_name, usr->hdr_full_name.buffer, ps, depth)) /* user's full name unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_logon_script", &usr->uni_logon_script, usr->hdr_logon_script.buffer, ps, depth)) /* logon script unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_profile_path", &usr->uni_profile_path, usr->hdr_profile_path.buffer, ps, depth)) /* profile path unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_home_dir", &usr->uni_home_dir, usr->hdr_home_dir.buffer, ps, depth)) /* home directory unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_dir_drive", &usr->uni_dir_drive, usr->hdr_dir_drive.buffer, ps, depth)) /* home directory drive unicode string */
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_groups2 ", ps, depth, &usr->num_groups2)) /* num groups */
+ return False;
+
+ if (UNMARSHALLING(ps) && usr->num_groups2 > 0) {
+ usr->gids = (DOM_GID *)prs_alloc_mem(ps, sizeof(DOM_GID)*usr->num_groups2);
+ if (usr->gids == NULL)
+ return False;
+ }
+
+ for (i = 0; i < usr->num_groups2; i++) {
+ if(!smb_io_gid("", &usr->gids[i], ps, depth)) /* group info */
+ return False;
+ }
+
+ if(!smb_io_unistr2("uni_logon_srv", &usr->uni_logon_srv, usr->hdr_logon_srv.buffer, ps, depth)) /* logon server unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_logon_dom", &usr->uni_logon_dom, usr->hdr_logon_srv.buffer, ps, depth)) /* logon domain unicode string */
+ return False;
+
+ if(!smb_io_dom_sid2("", &usr->dom_sid, ps, depth)) /* domain SID */
+ return False;
+
+ if (usr->num_other_sids) {
+
+ if (UNMARSHALLING(ps)) {
+ usr->other_sids = (DOM_SID2 *)prs_alloc_mem(ps, sizeof(DOM_SID2)*usr->num_other_sids);
+ if (usr->other_sids == NULL)
+ return False;
+ }
+
+ if(!prs_uint32("num_other_groups", ps, depth, &usr->num_other_groups))
+ return False;
+
+ if (UNMARSHALLING(ps) && usr->num_other_groups > 0) {
+ usr->other_gids = (DOM_GID *)prs_alloc_mem(ps, sizeof(DOM_GID)*usr->num_other_groups);
+ if (usr->other_gids == NULL)
+ return False;
+ }
+
+ for (i = 0; i < usr->num_other_groups; i++) {
+ if(!smb_io_gid("", &usr->other_gids[i], ps, depth)) /* other GIDs */
+ return False;
+ }
+ for (i = 0; i < usr->num_other_sids; i++) {
+ if(!smb_io_dom_sid2("", &usr->other_sids[i], ps, depth)) /* other domain SIDs */
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_q_sam_logon(char *desc, NET_Q_SAM_LOGON *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_sam_logon");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_sam_info("", &q_l->sam_id, ps, depth))
+ return False;
+
+ if(!prs_uint16("validation_level", ps, depth, &q_l->validation_level))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_sam_logon(char *desc, NET_R_SAM_LOGON *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_logon");
+ depth++;
+
+ if(!prs_uint32("buffer_creds", ps, depth, &r_l->buffer_creds)) /* undocumented buffer pointer */
+ return False;
+ if(!smb_io_cred("", &r_l->srv_creds, ps, depth)) /* server credentials. server time stamp appears to be ignored. */
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &r_l->switch_value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+#if 1 /* W2k always needs this - even for bad passwd. JRA */
+ if(!net_io_user_info3("", r_l->user, ps, depth, r_l->switch_value))
+ return False;
+#else
+ if (r_l->switch_value != 0) {
+ if(!net_io_user_info3("", r_l->user, ps, depth, r_l->switch_value))
+ return False;
+ }
+#endif
+
+ if(!prs_uint32("auth_resp ", ps, depth, &r_l->auth_resp)) /* 1 - Authoritative response; 0 - Non-Auth? */
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_l->status))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_q_sam_logoff(char *desc, NET_Q_SAM_LOGOFF *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_q_sam_logoff");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_sam_info("", &q_l->sam_id, ps, depth)) /* domain SID */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL net_io_r_sam_logoff(char *desc, NET_R_SAM_LOGOFF *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_logoff");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buffer_creds", ps, depth, &r_l->buffer_creds)) /* undocumented buffer pointer */
+ return False;
+ if(!smb_io_cred("", &r_l->srv_creds, ps, depth)) /* server credentials. server time stamp appears to be ignored. */
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_l->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a NET_Q_SAM_SYNC structure.
+********************************************************************/
+BOOL init_net_q_sam_sync(NET_Q_SAM_SYNC * q_s, const char *srv_name,
+ const char *cli_name, DOM_CRED *cli_creds,
+ DOM_CRED *ret_creds, uint32 database_id)
+{
+ DEBUG(5, ("init_q_sam_sync\n"));
+
+ init_unistr2(&q_s->uni_srv_name, srv_name, strlen(srv_name) + 1);
+ init_unistr2(&q_s->uni_cli_name, cli_name, strlen(cli_name) + 1);
+
+ if (cli_creds)
+ memcpy(&q_s->cli_creds, cli_creds, sizeof(q_s->cli_creds));
+
+ if (cli_creds)
+ memcpy(&q_s->ret_creds, ret_creds, sizeof(q_s->ret_creds));
+ else
+ memset(&q_s->ret_creds, 0, sizeof(q_s->ret_creds));
+
+ q_s->database_id = database_id;
+ q_s->restart_state = 0;
+ q_s->sync_context = 0;
+ q_s->max_size = 0xffff;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_q_sam_sync(char *desc, NET_Q_SAM_SYNC * q_s, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_q_sam_sync");
+ depth++;
+
+ if (!smb_io_unistr2("", &q_s->uni_srv_name, True, ps, depth))
+ return False;
+ if (!smb_io_unistr2("", &q_s->uni_cli_name, True, ps, depth))
+ return False;
+
+ if (!smb_io_cred("", &q_s->cli_creds, ps, depth))
+ return False;
+ if (!smb_io_cred("", &q_s->ret_creds, ps, depth))
+ return False;
+
+ if (!prs_uint32("database_id ", ps, depth, &q_s->database_id))
+ return False;
+ if (!prs_uint32("restart_state", ps, depth, &q_s->restart_state))
+ return False;
+ if (!prs_uint32("sync_context ", ps, depth, &q_s->sync_context))
+ return False;
+
+ if (!prs_uint32("max_size", ps, depth, &q_s->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_hdr(char *desc, SAM_DELTA_HDR * delta,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_hdr");
+ depth++;
+
+ if (!prs_uint16("type", ps, depth, &delta->type))
+ return False;
+ if (!prs_uint16("type2", ps, depth, &delta->type2))
+ return False;
+ if (!prs_uint32("target_rid", ps, depth, &delta->target_rid))
+ return False;
+
+ if (!prs_uint32("type3", ps, depth, &delta->type3))
+ return False;
+
+ /* Not sure why we need this but it seems to be necessary to get
+ sam deltas working. */
+
+ if (delta->type != 0x16) {
+ if (!prs_uint32("ptr_delta", ps, depth, &delta->ptr_delta))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_stamp(char *desc, SAM_DELTA_STAMP *info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_stamp");
+ depth++;
+
+ if (!prs_uint32("seqnum", ps, depth, &info->seqnum))
+ return False;
+ if (!prs_uint32("dom_mod_count_ptr", ps, depth,
+ &info->dom_mod_count_ptr))
+ return False;
+
+ if (info->dom_mod_count_ptr) {
+ if (!prs_uint64("dom_mod_count", ps, depth,
+ &info->dom_mod_count))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_domain_info(char *desc, SAM_DOMAIN_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_domain_info");
+ depth++;
+
+ if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_oem_info", &info->hdr_oem_info, ps, depth))
+ return False;
+
+ if (!prs_uint64("force_logoff", ps, depth, &info->force_logoff))
+ return False;
+ if (!prs_uint16("min_pwd_len", ps, depth, &info->min_pwd_len))
+ return False;
+ if (!prs_uint16("pwd_history_len", ps, depth, &info->pwd_history_len))
+ return False;
+ if (!prs_uint64("max_pwd_age", ps, depth, &info->max_pwd_age))
+ return False;
+ if (!prs_uint64("min_pwd_age", ps, depth, &info->min_pwd_age))
+ return False;
+ if (!prs_uint64("dom_mod_count", ps, depth, &info->dom_mod_count))
+ return False;
+ if (!smb_io_time("creation_time", &info->creation_time, ps, depth))
+ return False;
+
+ if (!smb_io_bufhdr2("hdr_sec_desc", &info->hdr_sec_desc, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_unknown", &info->hdr_unknown, ps, depth))
+ return False;
+
+ if (ps->data_offset + 40 > ps->buffer_size)
+ return False;
+ ps->data_offset += 40;
+
+ if (!smb_io_unistr2("uni_dom_name", &info->uni_dom_name,
+ info->hdr_dom_name.buffer, ps, depth))
+ return False;
+ if (!smb_io_unistr2("buf_oem_info", &info->buf_oem_info,
+ info->hdr_oem_info.buffer, ps, depth))
+ return False;
+
+ if (!smb_io_buffer4("buf_sec_desc", &info->buf_sec_desc,
+ info->hdr_sec_desc.buffer, ps, depth))
+ return False;
+ if (!smb_io_unistr2("buf_unknown", &info->buf_unknown,
+ info->hdr_unknown.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_group_info(char *desc, SAM_GROUP_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_group_info");
+ depth++;
+
+ if (!smb_io_unihdr("hdr_grp_name", &info->hdr_grp_name, ps, depth))
+ return False;
+ if (!smb_io_gid("gid", &info->gid, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_grp_desc", &info->hdr_grp_desc, ps, depth))
+ return False;
+ if (!smb_io_bufhdr2("hdr_sec_desc", &info->hdr_sec_desc, ps, depth))
+ return False;
+
+ if (ps->data_offset + 48 > ps->buffer_size)
+ return False;
+ ps->data_offset += 48;
+
+ if (!smb_io_unistr2("uni_grp_name", &info->uni_grp_name,
+ info->hdr_grp_name.buffer, ps, depth))
+ return False;
+ if (!smb_io_unistr2("uni_grp_desc", &info->uni_grp_desc,
+ info->hdr_grp_desc.buffer, ps, depth))
+ return False;
+ if (!smb_io_buffer4("buf_sec_desc", &info->buf_sec_desc,
+ info->hdr_sec_desc.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_passwd_info(char *desc, SAM_PWD * pwd,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_passwd_info");
+ depth++;
+
+ if (!prs_uint32("unk_0 ", ps, depth, &pwd->unk_0))
+ return False;
+
+ if (!smb_io_unihdr("hdr_lm_pwd", &pwd->hdr_lm_pwd, ps, depth))
+ return False;
+ if (!prs_uint8s(False, "buf_lm_pwd", ps, depth, pwd->buf_lm_pwd, 16))
+ return False;
+
+ if (!smb_io_unihdr("hdr_nt_pwd", &pwd->hdr_nt_pwd, ps, depth))
+ return False;
+ if (!prs_uint8s(False, "buf_nt_pwd", ps, depth, pwd->buf_nt_pwd, 16))
+ return False;
+
+ if (!smb_io_unihdr("", &pwd->hdr_empty_lm, ps, depth))
+ return False;
+ if (!smb_io_unihdr("", &pwd->hdr_empty_nt, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a SAM_ACCOUNT_INFO structure.
+********************************************************************/
+BOOL make_sam_account_info(SAM_ACCOUNT_INFO * info,
+ const UNISTR2 *user_name,
+ const UNISTR2 *full_name,
+ uint32 user_rid, uint32 group_rid,
+ const UNISTR2 *home_dir,
+ const UNISTR2 *dir_drive,
+ const UNISTR2 *log_scr,
+ const UNISTR2 *desc,
+ uint32 acb_info,
+ const UNISTR2 *prof_path,
+ const UNISTR2 *wkstas,
+ const UNISTR2 *unk_str, const UNISTR2 *mung_dial)
+{
+ int len_user_name = user_name != NULL ? user_name->uni_str_len : 0;
+ int len_full_name = full_name != NULL ? full_name->uni_str_len : 0;
+ int len_home_dir = home_dir != NULL ? home_dir->uni_str_len : 0;
+ int len_dir_drive = dir_drive != NULL ? dir_drive->uni_str_len : 0;
+ int len_logon_script = log_scr != NULL ? log_scr->uni_str_len : 0;
+ int len_profile_path = prof_path != NULL ? prof_path->uni_str_len : 0;
+ int len_description = desc != NULL ? desc->uni_str_len : 0;
+ int len_workstations = wkstas != NULL ? wkstas->uni_str_len : 0;
+ int len_unknown_str = unk_str != NULL ? unk_str->uni_str_len : 0;
+ int len_munged_dial = mung_dial != NULL ? mung_dial->uni_str_len : 0;
+
+ DEBUG(5, ("make_sam_account_info\n"));
+
+ make_uni_hdr(&info->hdr_acct_name, len_user_name);
+ make_uni_hdr(&info->hdr_full_name, len_full_name);
+ make_uni_hdr(&info->hdr_home_dir, len_home_dir);
+ make_uni_hdr(&info->hdr_dir_drive, len_dir_drive);
+ make_uni_hdr(&info->hdr_logon_script, len_logon_script);
+ make_uni_hdr(&info->hdr_profile, len_profile_path);
+ make_uni_hdr(&info->hdr_acct_desc, len_description);
+ make_uni_hdr(&info->hdr_workstations, len_workstations);
+ make_uni_hdr(&info->hdr_comment, len_unknown_str);
+ make_uni_hdr(&info->hdr_parameters, len_munged_dial);
+
+ /* not present */
+ make_bufhdr2(&info->hdr_sec_desc, 0, 0, 0);
+
+ info->user_rid = user_rid;
+ info->group_rid = group_rid;
+
+ init_nt_time(&info->logon_time);
+ init_nt_time(&info->logoff_time);
+ init_nt_time(&info->pwd_last_set_time);
+ init_nt_time(&info->acct_expiry_time);
+
+ info->logon_divs = 0xA8;
+ info->ptr_logon_hrs = 0; /* Don't care right now */
+
+ info->bad_pwd_count = 0;
+ info->logon_count = 0;
+ info->acb_info = acb_info;
+ info->nt_pwd_present = 0;
+ info->lm_pwd_present = 0;
+ info->pwd_expired = 0;
+ info->country = 0;
+ info->codepage = 0;
+
+ info->unknown1 = 0x4EC;
+ info->unknown2 = 0;
+
+ copy_unistr2(&info->uni_acct_name, user_name);
+ copy_unistr2(&info->uni_full_name, full_name);
+ copy_unistr2(&info->uni_home_dir, home_dir);
+ copy_unistr2(&info->uni_dir_drive, dir_drive);
+ copy_unistr2(&info->uni_logon_script, log_scr);
+ copy_unistr2(&info->uni_profile, prof_path);
+ copy_unistr2(&info->uni_acct_desc, desc);
+ copy_unistr2(&info->uni_workstations, wkstas);
+ copy_unistr2(&info->uni_comment, unk_str);
+ copy_unistr2(&info->uni_parameters, mung_dial);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_account_info(char *desc, uint8 sess_key[16],
+ SAM_ACCOUNT_INFO * info, prs_struct *ps,
+ int depth)
+{
+ BUFHDR2 hdr_priv_data;
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_account_info");
+ depth++;
+
+ if (!smb_io_unihdr("hdr_acct_name", &info->hdr_acct_name, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth))
+ return False;
+
+ if (!prs_uint32("user_rid ", ps, depth, &info->user_rid))
+ return False;
+ if (!prs_uint32("group_rid", ps, depth, &info->group_rid))
+ return False;
+
+ if (!smb_io_unihdr("hdr_home_dir ", &info->hdr_home_dir, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script, ps,
+ depth))
+ return False;
+
+ if (!smb_io_unihdr("hdr_acct_desc", &info->hdr_acct_desc, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_workstations", &info->hdr_workstations, ps,
+ depth))
+ return False;
+
+ if (!smb_io_time("logon_time", &info->logon_time, ps, depth))
+ return False;
+ if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth))
+ return False;
+
+ if (!prs_uint32("logon_divs ", ps, depth, &info->logon_divs))
+ return False;
+ if (!prs_uint32("ptr_logon_hrs", ps, depth, &info->ptr_logon_hrs))
+ return False;
+
+ if (!prs_uint16("bad_pwd_count", ps, depth, &info->bad_pwd_count))
+ return False;
+ if (!prs_uint16("logon_count", ps, depth, &info->logon_count))
+ return False;
+ if (!smb_io_time("pwd_last_set_time", &info->pwd_last_set_time, ps,
+ depth))
+ return False;
+ if (!smb_io_time("acct_expiry_time", &info->acct_expiry_time, ps,
+ depth))
+ return False;
+
+ if (!prs_uint32("acb_info", ps, depth, &info->acb_info))
+ return False;
+ if (!prs_uint8s(False, "nt_pwd", ps, depth, info->nt_pwd, 16))
+ return False;
+ if (!prs_uint8s(False, "lm_pwd", ps, depth, info->lm_pwd, 16))
+ return False;
+ if (!prs_uint8("lm_pwd_present", ps, depth, &info->lm_pwd_present))
+ return False;
+ if (!prs_uint8("nt_pwd_present", ps, depth, &info->nt_pwd_present))
+ return False;
+ if (!prs_uint8("pwd_expired", ps, depth, &info->pwd_expired))
+ return False;
+
+ if (!smb_io_unihdr("hdr_comment", &info->hdr_comment, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_parameters", &info->hdr_parameters, ps,
+ depth))
+ return False;
+ if (!prs_uint16("country", ps, depth, &info->country))
+ return False;
+ if (!prs_uint16("codepage", ps, depth, &info->codepage))
+ return False;
+
+ if (!smb_io_bufhdr2("hdr_priv_data", &hdr_priv_data, ps, depth))
+ return False;
+ if (!smb_io_bufhdr2("hdr_sec_desc", &info->hdr_sec_desc, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_profile", &info->hdr_profile, ps, depth))
+ return False;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (!smb_io_unihdr("hdr_reserved", &info->hdr_reserved[i],
+ ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!prs_uint32("dw_reserved", ps, depth,
+ &info->dw_reserved[i]))
+ return False;
+ }
+
+ if (!smb_io_unistr2("uni_acct_name", &info->uni_acct_name,
+ info->hdr_acct_name.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_full_name", &info->uni_full_name,
+ info->hdr_full_name.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_home_dir ", &info->uni_home_dir,
+ info->hdr_home_dir.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive,
+ info->hdr_dir_drive.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_logon_script", &info->uni_logon_script,
+ info->hdr_logon_script.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_acct_desc", &info->uni_acct_desc,
+ info->hdr_acct_desc.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_workstations", &info->uni_workstations,
+ info->hdr_workstations.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+
+ if (!prs_uint32("unknown1", ps, depth, &info->unknown1))
+ return False;
+ if (!prs_uint32("unknown2", ps, depth, &info->unknown2))
+ return False;
+
+ if (!smb_io_buffer4("buf_logon_hrs", &info->buf_logon_hrs,
+ info->ptr_logon_hrs, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_comment", &info->uni_comment,
+ info->hdr_comment.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_parameters", &info->uni_parameters,
+ info->hdr_parameters.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (hdr_priv_data.buffer != 0)
+ {
+ int old_offset = 0;
+ uint32 len = 0x44;
+ if (!prs_uint32("pwd_len", ps, depth, &len))
+ return False;
+ old_offset = ps->data_offset;
+ if (len == 0x44)
+ {
+ if (ps->io)
+ {
+ /* reading */
+ if (!prs_hash1(ps, ps->data_offset, sess_key))
+ return False;
+ }
+ if (!net_io_sam_passwd_info("pass", &info->pass,
+ ps, depth))
+ return False;
+
+ if (!ps->io)
+ {
+ /* writing */
+ if (!prs_hash1(ps, old_offset, sess_key))
+ return False;
+ }
+ }
+ if (old_offset + len > ps->buffer_size)
+ return False;
+ ps->data_offset = old_offset + len;
+ }
+ if (!smb_io_buffer4("buf_sec_desc", &info->buf_sec_desc,
+ info->hdr_sec_desc.buffer, ps, depth))
+ return False;
+ prs_align(ps);
+ if (!smb_io_unistr2("uni_profile", &info->uni_profile,
+ info->hdr_profile.buffer, ps, depth))
+ return False;
+
+ prs_align(ps);
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_group_mem_info(char *desc, SAM_GROUP_MEM_INFO * info,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ prs_debug(ps, depth, desc, "net_io_sam_group_mem_info");
+ depth++;
+
+ prs_align(ps);
+ if (!prs_uint32("ptr_rids ", ps, depth, &info->ptr_rids))
+ return False;
+ if (!prs_uint32("ptr_attribs", ps, depth, &info->ptr_attribs))
+ return False;
+ if (!prs_uint32("num_members", ps, depth, &info->num_members))
+ return False;
+
+ if (ps->data_offset + 16 > ps->buffer_size)
+ return False;
+ ps->data_offset += 16;
+
+ if (info->ptr_rids != 0)
+ {
+ if (!prs_uint32("num_members2", ps, depth,
+ &info->num_members2))
+ return False;
+
+ if (info->num_members2 != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->rids = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_members2);
+
+ if (info->rids == NULL) {
+ DEBUG(0, ("out of memory allocating %d rids\n",
+ info->num_members2));
+ return False;
+ }
+
+ for (i = 0; i < info->num_members2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "rids[%02d]", i);
+ if (!prs_uint32(tmp, ps, depth, &info->rids[i]))
+ return False;
+ }
+ }
+
+ if (info->ptr_attribs != 0)
+ {
+ if (!prs_uint32("num_members3", ps, depth,
+ &info->num_members3))
+ return False;
+ if (info->num_members3 != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->attribs = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_members3);
+
+ if (info->attribs == NULL) {
+ DEBUG(0, ("out of memory allocating %d attribs\n",
+ info->num_members3));
+ return False;
+ }
+
+ for (i = 0; i < info->num_members3; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "attribs[%02d]", i);
+ if (!prs_uint32(tmp, ps, depth, &info->attribs[i]))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_alias_info(char *desc, SAM_ALIAS_INFO * info,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_alias_info");
+ depth++;
+
+ if (!smb_io_unihdr("hdr_als_name", &info->hdr_als_name, ps, depth))
+ return False;
+ if (!prs_uint32("als_rid", ps, depth, &info->als_rid))
+ return False;
+ if (!smb_io_bufhdr2("hdr_sec_desc", &info->hdr_sec_desc, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_als_desc", &info->hdr_als_desc, ps, depth))
+ return False;
+
+ if (ps->data_offset + 40 > ps->buffer_size)
+ return False;
+ ps->data_offset += 40;
+
+ if (!smb_io_unistr2("uni_als_name", &info->uni_als_name,
+ info->hdr_als_name.buffer, ps, depth))
+ return False;
+ if (!smb_io_buffer4("buf_sec_desc", &info->buf_sec_desc,
+ info->hdr_sec_desc.buffer, ps, depth))
+ return False;
+ if (!smb_io_unistr2("uni_als_desc", &info->uni_als_desc,
+ info->hdr_als_name.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_alias_mem_info(char *desc, SAM_ALIAS_MEM_INFO * info,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ prs_debug(ps, depth, desc, "net_io_sam_alias_mem_info");
+ depth++;
+
+ prs_align(ps);
+ if (!prs_uint32("num_members", ps, depth, &info->num_members))
+ return False;
+ if (!prs_uint32("ptr_members", ps, depth, &info->ptr_members))
+ return False;
+
+ if (info->ptr_members != 0)
+ {
+ if (ps->data_offset + 16 > ps->buffer_size)
+ return False;
+ ps->data_offset += 16;
+
+ if (!prs_uint32("num_sids", ps, depth, &info->num_sids))
+ return False;
+ if (info->num_sids != info->num_members)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ info->ptr_sids = talloc(ps->mem_ctx, sizeof(uint32) *
+ info->num_sids);
+
+ if (info->ptr_sids == NULL) {
+ DEBUG(0, ("out of memory allocating %d ptr_sids\n",
+ info->num_sids));
+ return False;
+ }
+
+ for (i = 0; i < info->num_sids; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "ptr_sids[%02d]", i);
+ if (!prs_uint32(tmp, ps, depth, &info->ptr_sids[i]))
+ return False;
+ }
+
+ info->sids = talloc(ps->mem_ctx, sizeof(DOM_SID2) *
+ info->num_sids);
+
+ if (info->sids == NULL) {
+ DEBUG(0, ("error allocating %d sids\n",
+ info->num_sids));
+ return False;
+ }
+
+ for (i = 0; i < info->num_sids; i++)
+ {
+ if (info->ptr_sids[i] != 0)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "sids[%02d]",
+ i);
+ if (!smb_io_dom_sid2(tmp, &info->sids[i],
+ ps, depth))
+ return False;
+ }
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_dom_info(char *desc, SAM_DELTA_DOM *info,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_dom_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("unknown1", ps, depth, &info->unknown1))
+ return False;
+ if (!prs_uint32("unknown2", ps, depth, &info->unknown2))
+ return False;
+ if (!prs_uint32("unknown3", ps, depth, &info->unknown3))
+ return False;
+ if (!prs_uint32("unknown4", ps, depth, &info->unknown4))
+ return False;
+ if (!prs_uint32("count1", ps, depth, &info->count1))
+ return False;
+ if (!prs_uint32("ptr1", ps, depth, &info->ptr1))
+ return False;
+
+ if (!prs_uint16("count2", ps, depth, &info->count2))
+ return False;
+ if (!prs_uint16("count3", ps, depth, &info->count3))
+ return False;
+
+ if (!prs_uint32("ptr2", ps, depth, &info->ptr2))
+ return False;
+ if (!prs_uint32("ptr3", ps, depth, &info->ptr3))
+ return False;
+
+ if (!prs_uint32("unknown4b", ps, depth, &info->unknown4b))
+ return False;
+ if (!prs_uint32("unknown5", ps, depth, &info->unknown5))
+ return False;
+ if (!prs_uint32("unknown6", ps, depth, &info->unknown6))
+ return False;
+ if (!prs_uint32("unknown7", ps, depth, &info->unknown7))
+ return False;
+ if (!prs_uint32("unknown8", ps, depth, &info->unknown8))
+ return False;
+ if (!prs_uint32("unknown9", ps, depth, &info->unknown9))
+ return False;
+ if (!prs_uint32("unknown10", ps, depth, &info->unknown10))
+ return False;
+ if (!prs_uint32("unknown11", ps, depth, &info->unknown11))
+ return False;
+ if (!prs_uint32("unknown12", ps, depth, &info->unknown12))
+ return False;
+
+ if (!prs_uint32("unknown13", ps, depth, &info->unknown13))
+ return False;
+ if (!prs_uint32("unknown14", ps, depth, &info->unknown14))
+ return False;
+ if (!prs_uint32("unknown15", ps, depth, &info->unknown15))
+ return False;
+ if (!prs_uint32("unknown16", ps, depth, &info->unknown16))
+ return False;
+ if (!prs_uint32("unknown17", ps, depth, &info->unknown17))
+ return False;
+
+ for (i=0; i<info->count2; i++)
+ if (!prs_uint32("unknown18", ps, depth, &info->unknown18))
+ return False;
+
+ if (!prs_uint32("unknown19", ps, depth, &info->unknown19))
+ return False;
+
+ for (i=0; i<info->count1; i++)
+ if (!prs_uint32("unknown20", ps, depth, &info->unknown20))
+ return False;
+
+ if (!prs_uint32("ptr4", ps, depth, &info->ptr4))
+ return False;
+
+ if (!smb_io_unistr2("domain_name", &info->domain_name, True, ps, depth))
+ return False;
+
+ if(!smb_io_dom_sid2("domain_sid", &info->domain_sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_unk0e_info(char *desc, SAM_DELTA_UNK0E *info,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_unk0e_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_size", ps, depth, &info->buf_size))
+ return False;
+
+ if(!sec_io_desc("sec_desc", &info->sec_desc, ps, depth))
+ return False;
+
+ if(!smb_io_dom_sid2("sid", &info->sid, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_domain", &info->hdr_domain, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown0", ps, depth, &info->unknown0))
+ return False;
+ if(!prs_uint32("unknown1", ps, depth, &info->unknown1))
+ return False;
+ if(!prs_uint32("unknown2", ps, depth, &info->unknown2))
+ return False;
+
+ if(!prs_uint32("buf_size2", ps, depth, &info->buf_size2))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &info->ptr))
+ return False;
+
+ for (i=0; i<12; i++)
+ if(!prs_uint32("unknown3", ps, depth, &info->unknown3))
+ return False;
+
+ if (!smb_io_unistr2("domain", &info->domain, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_unk12_info(char *desc, SAM_DELTA_UNK12 *info,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_unk12_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_size", ps, depth, &info->buf_size))
+ return False;
+
+ if(!sec_io_desc("sec_desc", &info->sec_desc, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("secret", &info->secret, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count1", ps, depth, &info->count1))
+ return False;
+ if(!prs_uint32("count2", ps, depth, &info->count2))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &info->ptr))
+ return False;
+
+
+ if(!smb_io_time("time1", &info->time1, ps, depth)) /* logon time */
+ return False;
+ if(!prs_uint32("count3", ps, depth, &info->count3))
+ return False;
+ if(!prs_uint32("count4", ps, depth, &info->count4))
+ return False;
+ if(!prs_uint32("ptr2", ps, depth, &info->ptr2))
+ return False;
+ if(!smb_io_time("time2", &info->time2, ps, depth)) /* logon time */
+ return False;
+ if(!prs_uint32("unknow1", ps, depth, &info->unknow1))
+ return False;
+
+
+ if(!prs_uint32("buf_size2", ps, depth, &info->buf_size2))
+ return False;
+ if(!prs_uint32("ptr3", ps, depth, &info->ptr3))
+ return False;
+ for(i=0; i<12; i++)
+ if(!prs_uint32("unknow2", ps, depth, &info->unknow2))
+ return False;
+
+ if(!prs_uint32("chal_len", ps, depth, &info->chal_len))
+ return False;
+ if(!prs_uint32("reserved1", ps, depth, &info->reserved1))
+ return False;
+ if(!prs_uint32("chal_len2", ps, depth, &info->chal_len2))
+ return False;
+
+ if(!prs_uint8s (False, "chal", ps, depth, info->chal, info->chal_len2))
+ return False;
+
+ if(!prs_uint32("key_len", ps, depth, &info->key_len))
+ return False;
+ if(!prs_uint32("reserved2", ps, depth, &info->reserved2))
+ return False;
+ if(!prs_uint32("key_len2", ps, depth, &info->key_len2))
+ return False;
+
+ if(!prs_uint8s (False, "key", ps, depth, info->key, info->key_len2))
+ return False;
+
+
+ if(!prs_uint32("buf_size3", ps, depth, &info->buf_size3))
+ return False;
+
+ if(!sec_io_desc("sec_desc2", &info->sec_desc2, ps, depth))
+ return False;
+
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_privs_info(char *desc, SAM_DELTA_PRIVS *info,
+ prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_sam_privs_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("buf_size", ps, depth, &info->buf_size))
+ return False;
+
+ if(!sec_io_desc("sec_desc", &info->sec_desc, ps, depth))
+ return False;
+
+ if(!smb_io_dom_sid2("sid", &info->sid, ps, depth))
+ return False;
+
+ if(!prs_uint32("priv_count", ps, depth, &info->priv_count))
+ return False;
+ if(!prs_uint32("reserved1", ps, depth, &info->reserved1))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &info->ptr1))
+ return False;
+ if(!prs_uint32("ptr2", ps, depth, &info->ptr2))
+ return False;
+
+ if(!prs_uint32("unknown1", ps, depth, &info->unknown1))
+ return False;
+ if(!prs_uint32("unknown2", ps, depth, &info->unknown2))
+ return False;
+ if(!prs_uint32("unknown3", ps, depth, &info->unknown3))
+ return False;
+ if(!prs_uint32("unknown4", ps, depth, &info->unknown4))
+ return False;
+ if(!prs_uint32("unknown5", ps, depth, &info->unknown5))
+ return False;
+ if(!prs_uint32("unknown6", ps, depth, &info->unknown6))
+ return False;
+ if(!prs_uint32("unknown7", ps, depth, &info->unknown7))
+ return False;
+ if(!prs_uint32("unknown8", ps, depth, &info->unknown8))
+ return False;
+ if(!prs_uint32("unknown9", ps, depth, &info->unknown9))
+ return False;
+
+ if(!prs_uint32("buf_size2", ps, depth, &info->buf_size2))
+ return False;
+ if(!prs_uint32("ptr3", ps, depth, &info->ptr3))
+ return False;
+
+ for (i=0; i<12; i++)
+ if(!prs_uint32("unknown10", ps, depth, &info->unknown10))
+ return False;
+
+ if(!prs_uint32("attribute_count", ps, depth, &info->attribute_count))
+ return False;
+
+ info->attributes = talloc(ps->mem_ctx, sizeof(uint32) * info->attribute_count);
+
+ for (i=0; i<info->attribute_count; i++)
+ if(!prs_uint32("attributes", ps, depth, &info->attributes[i]))
+ return False;
+
+ if(!prs_uint32("privlist_count", ps, depth, &info->privlist_count))
+ return False;
+
+ info->hdr_privslist = talloc(ps->mem_ctx, sizeof(UNIHDR) * info->privlist_count);
+ info->uni_privslist = talloc(ps->mem_ctx, sizeof(UNISTR2) * info->privlist_count);
+
+ for (i=0; i<info->privlist_count; i++)
+ if(!smb_io_unihdr("hdr_privslist", &info->hdr_privslist[i], ps, depth))
+ return False;
+
+ for (i=0; i<info->privlist_count; i++)
+ if (!smb_io_unistr2("uni_privslist", &info->uni_privslist[i], True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static BOOL net_io_sam_delta_ctr(char *desc, uint8 sess_key[16],
+ SAM_DELTA_CTR * delta, uint16 type,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_sam_delta_ctr");
+ depth++;
+
+ switch (type) {
+ /* Seen in sam deltas */
+ case SAM_DELTA_SAM_STAMP:
+ if (!net_io_sam_delta_stamp("", &delta->stamp, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_DOMAIN_INFO:
+ if (!net_io_sam_domain_info("", &delta->domain_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_GROUP_INFO:
+ if (!net_io_sam_group_info("", &delta->group_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_ACCOUNT_INFO:
+ if (!net_io_sam_account_info("", sess_key, &delta->account_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_GROUP_MEM:
+ if (!net_io_sam_group_mem_info("", &delta->grp_mem_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_ALIAS_INFO:
+ if (!net_io_sam_alias_info("", &delta->alias_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_DOM_INFO:
+ if (!net_io_sam_dom_info("", &delta->dom_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_ALIAS_MEM:
+ if (!net_io_sam_alias_mem_info("", &delta->als_mem_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_PRIVS_INFO:
+ if (!net_io_sam_privs_info("", &delta->privs_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_UNK0E_INFO:
+ if (!net_io_sam_unk0e_info("", &delta->unk0e_info, ps, depth))
+ return False;
+ break;
+
+ case SAM_DELTA_UNK12_INFO:
+ if (!net_io_sam_unk12_info("", &delta->unk12_info, ps, depth))
+ return False;
+ break;
+
+ default:
+ DEBUG(0, ("Replication error: Unknown delta type 0x%x\n", type));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_r_sam_sync(char *desc, uint8 sess_key[16],
+ NET_R_SAM_SYNC * r_s, prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_sync");
+ depth++;
+
+ if (!smb_io_cred("srv_creds", &r_s->srv_creds, ps, depth))
+ return False;
+ if (!prs_uint32("sync_context", ps, depth, &r_s->sync_context))
+ return False;
+
+ if (!prs_uint32("ptr_deltas", ps, depth, &r_s->ptr_deltas))
+ return False;
+ if (r_s->ptr_deltas != 0)
+ {
+ if (!prs_uint32("num_deltas ", ps, depth, &r_s->num_deltas))
+ return False;
+ if (!prs_uint32("ptr_deltas2", ps, depth, &r_s->ptr_deltas2))
+ return False;
+ if (r_s->ptr_deltas2 != 0)
+ {
+ if (!prs_uint32("num_deltas2", ps, depth,
+ &r_s->num_deltas2))
+ return False;
+
+ if (r_s->num_deltas2 != r_s->num_deltas)
+ {
+ /* RPC fault */
+ return False;
+ }
+
+ if (r_s->num_deltas2 > 0) {
+ r_s->hdr_deltas = (SAM_DELTA_HDR *)
+ talloc(ps->mem_ctx, r_s->num_deltas2 *
+ sizeof(SAM_DELTA_HDR));
+
+ if (r_s->hdr_deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d delta headers\n",
+ r_s->num_deltas2));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas2; i++)
+ {
+ if (!net_io_sam_delta_hdr("",
+ &r_s->hdr_deltas[i],
+ ps, depth))
+ return False;
+ }
+
+ if (r_s->num_deltas2 > 0) {
+ r_s->deltas = (SAM_DELTA_CTR *)
+ talloc(ps->mem_ctx, r_s->num_deltas2 *
+ sizeof(SAM_DELTA_CTR));
+
+ if (r_s->deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d deltas\n",
+ r_s->num_deltas2));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas2; i++)
+ {
+ if (!net_io_sam_delta_ctr(
+ "", sess_key, &r_s->deltas[i],
+ r_s->hdr_deltas[i].type3,
+ ps, depth)) {
+ DEBUG(0, ("hmm, failed on i=%d\n", i));
+ return False;
+ }
+ }
+ }
+ }
+
+ prs_align(ps);
+ if (!prs_ntstatus("status", ps, depth, &(r_s->status)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a NET_Q_SAM_DELTAS structure.
+********************************************************************/
+BOOL init_net_q_sam_deltas(NET_Q_SAM_DELTAS *q_s, const char *srv_name,
+ const char *cli_name, DOM_CRED *cli_creds,
+ uint32 database_id, UINT64_S dom_mod_count)
+{
+ DEBUG(5, ("init_net_q_sam_deltas\n"));
+
+ init_unistr2(&q_s->uni_srv_name, srv_name, strlen(srv_name) + 1);
+ init_unistr2(&q_s->uni_cli_name, cli_name, strlen(cli_name) + 1);
+
+ memcpy(&q_s->cli_creds, cli_creds, sizeof(q_s->cli_creds));
+ memset(&q_s->ret_creds, 0, sizeof(q_s->ret_creds));
+
+ q_s->database_id = database_id;
+ q_s->dom_mod_count.low = dom_mod_count.low;
+ q_s->dom_mod_count.high = dom_mod_count.high;
+ q_s->max_size = 0xffff;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_q_sam_deltas(char *desc, NET_Q_SAM_DELTAS *q_s, prs_struct *ps,
+ int depth)
+{
+ prs_debug(ps, depth, desc, "net_io_q_sam_deltas");
+ depth++;
+
+ if (!smb_io_unistr2("", &q_s->uni_srv_name, True, ps, depth))
+ return False;
+ if (!smb_io_unistr2("", &q_s->uni_cli_name, True, ps, depth))
+ return False;
+
+ if (!smb_io_cred("", &q_s->cli_creds, ps, depth))
+ return False;
+ if (!smb_io_cred("", &q_s->ret_creds, ps, depth))
+ return False;
+
+ if (!prs_uint32("database_id ", ps, depth, &q_s->database_id))
+ return False;
+ if (!prs_uint64("dom_mod_count", ps, depth, &q_s->dom_mod_count))
+ return False;
+ if (!prs_uint32("max_size", ps, depth, &q_s->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL net_io_r_sam_deltas(char *desc, uint8 sess_key[16],
+ NET_R_SAM_DELTAS *r_s, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_deltas");
+ depth++;
+
+ if (!smb_io_cred("srv_creds", &r_s->srv_creds, ps, depth))
+ return False;
+ if (!prs_uint64("dom_mod_count", ps, depth, &r_s->dom_mod_count))
+ return False;
+
+ if (!prs_uint32("ptr_deltas", ps, depth, &r_s->ptr_deltas))
+ return False;
+ if (!prs_uint32("num_deltas", ps, depth, &r_s->num_deltas))
+ return False;
+ if (!prs_uint32("ptr_deltas2", ps, depth, &r_s->num_deltas2))
+ return False;
+
+ if (r_s->num_deltas2 != 0)
+ {
+ if (!prs_uint32("num_deltas2 ", ps, depth, &r_s->num_deltas2))
+ return False;
+
+ if (r_s->ptr_deltas != 0)
+ {
+ if (r_s->num_deltas > 0) {
+ r_s->hdr_deltas = (SAM_DELTA_HDR *)
+ talloc(ps->mem_ctx, r_s->num_deltas *
+ sizeof(SAM_DELTA_HDR));
+ if (r_s->hdr_deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d delta headers\n",
+ r_s->num_deltas));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas; i++)
+ {
+ net_io_sam_delta_hdr("", &r_s->hdr_deltas[i],
+ ps, depth);
+ }
+
+ if (r_s->num_deltas > 0) {
+ r_s->deltas = (SAM_DELTA_CTR *)
+ talloc(ps->mem_ctx, r_s->num_deltas *
+ sizeof(SAM_DELTA_CTR));
+
+ if (r_s->deltas == NULL) {
+ DEBUG(0, ("error tallocating memory "
+ "for %d deltas\n",
+ r_s->num_deltas));
+ return False;
+ }
+ }
+
+ for (i = 0; i < r_s->num_deltas; i++)
+ {
+ if (!net_io_sam_delta_ctr(
+ "", sess_key,
+ &r_s->deltas[i],
+ r_s->hdr_deltas[i].type2,
+ ps, depth))
+
+ return False;
+ }
+ }
+ }
+
+ prs_align(ps);
+ if (!prs_ntstatus("status", ps, depth, &r_s->status))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_prs.c b/source/rpc_parse/parse_prs.c
new file mode 100644
index 00000000000..f902210b7b8
--- /dev/null
+++ b/source/rpc_parse/parse_prs.c
@@ -0,0 +1,1237 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba memory buffer functions
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+dump a prs to a file
+ ********************************************************************/
+void prs_dump(char *name, int v, prs_struct *ps)
+{
+ int fd, i;
+ pstring fname;
+ if (DEBUGLEVEL < 50) return;
+ for (i=1;i<100;i++) {
+ if (v != -1) {
+ slprintf(fname,sizeof(fname)-1, "/tmp/%s_%d.%d.prs", name, v, i);
+ } else {
+ slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.prs", name, i);
+ }
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd != -1 || errno != EEXIST) break;
+ }
+ if (fd != -1) {
+ write(fd, ps->data_p + ps->data_offset, ps->buffer_size - ps->data_offset);
+ close(fd);
+ DEBUG(0,("created %s\n", fname));
+ }
+}
+
+
+
+/*******************************************************************
+ debug output for parsing info.
+
+ XXXX side-effect of this function is to increase the debug depth XXXX
+
+ ********************************************************************/
+void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
+{
+ DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
+}
+
+
+/**
+ * Initialise an expandable parse structure.
+ *
+ * @param size Initial buffer size. If >0, a new buffer will be
+ * created with malloc().
+ *
+ * @return False if allocation fails, otherwise True.
+ **/
+BOOL prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, BOOL io)
+{
+ ZERO_STRUCTP(ps);
+ ps->io = io;
+ ps->bigendian_data = RPC_LITTLE_ENDIAN;
+ ps->align = RPC_PARSE_ALIGN;
+ ps->is_dynamic = False;
+ ps->data_offset = 0;
+ ps->buffer_size = 0;
+ ps->data_p = NULL;
+ ps->mem_ctx = ctx;
+
+ if (size != 0) {
+ ps->buffer_size = size;
+ if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
+ DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
+ return False;
+ }
+ ps->is_dynamic = True; /* We own this memory. */
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ read from a socket into memory.
+ ********************************************************************/
+BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout)
+{
+ BOOL ok;
+ size_t prev_size = ps->buffer_size;
+ if (!prs_grow(ps, len))
+ return False;
+
+ if (timeout > 0) {
+ ok = (read_with_timeout(fd, &ps->data_p[prev_size],
+ len, len,timeout) == len);
+ } else {
+ ok = (read_data(fd, &ps->data_p[prev_size], len) == len);
+ }
+ return ok;
+}
+
+/*******************************************************************
+ Delete the memory in a parse structure - if we own it.
+ ********************************************************************/
+
+void prs_mem_free(prs_struct *ps)
+{
+ if(ps->is_dynamic)
+ SAFE_FREE(ps->data_p);
+ ps->is_dynamic = False;
+ ps->buffer_size = 0;
+ ps->data_offset = 0;
+}
+
+/*******************************************************************
+ Allocate memory when unmarshalling... Always zero clears.
+ ********************************************************************/
+
+char *prs_alloc_mem(prs_struct *ps, size_t size)
+{
+ char *ret = talloc(ps->mem_ctx, size);
+
+ if (ret)
+ memset(ret, '\0', size);
+
+ return ret;
+}
+
+/*******************************************************************
+ Return the current talloc context we're using.
+ ********************************************************************/
+
+TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
+{
+ return ps->mem_ctx;
+}
+
+/*******************************************************************
+ Hand some already allocated memory to a prs_struct.
+ ********************************************************************/
+
+void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
+{
+ ps->is_dynamic = is_dynamic;
+ ps->data_p = buf;
+ ps->buffer_size = size;
+}
+
+/*******************************************************************
+ Take some memory back from a prs_struct.
+ ********************************************************************/
+
+char *prs_take_memory(prs_struct *ps, uint32 *psize)
+{
+ char *ret = ps->data_p;
+ if(psize)
+ *psize = ps->buffer_size;
+ ps->is_dynamic = False;
+ prs_mem_free(ps);
+ return ret;
+}
+
+/*******************************************************************
+ Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
+ ********************************************************************/
+
+BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
+{
+ if (newsize > ps->buffer_size)
+ return prs_force_grow(ps, newsize - ps->buffer_size);
+
+ if (newsize < ps->buffer_size) {
+ char *new_data_p = Realloc(ps->data_p, newsize);
+ /* if newsize is zero, Realloc acts like free() & returns NULL*/
+ if (new_data_p == NULL && newsize != 0) {
+ DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
+ (unsigned int)newsize));
+ DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
+ return False;
+ }
+ ps->data_p = new_data_p;
+ ps->buffer_size = newsize;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Attempt, if needed, to grow a data buffer.
+ Also depends on the data stream mode (io).
+ ********************************************************************/
+
+BOOL prs_grow(prs_struct *ps, uint32 extra_space)
+{
+ uint32 new_size;
+ char *new_data;
+
+ ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
+
+ if(ps->data_offset + extra_space <= ps->buffer_size)
+ return True;
+
+ /*
+ * We cannot grow the buffer if we're not reading
+ * into the prs_struct, or if we don't own the memory.
+ */
+
+ if(UNMARSHALLING(ps) || !ps->is_dynamic) {
+ DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+ (unsigned int)extra_space));
+ return False;
+ }
+
+ /*
+ * Decide how much extra space we really need.
+ */
+
+ extra_space -= (ps->buffer_size - ps->data_offset);
+ if(ps->buffer_size == 0) {
+ /*
+ * Ensure we have at least a PDU's length, or extra_space, whichever
+ * is greater.
+ */
+
+ new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
+
+ if((new_data = malloc(new_size)) == NULL) {
+ DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
+ return False;
+ }
+ memset(new_data, '\0', new_size );
+ } else {
+ /*
+ * If the current buffer size is bigger than the space needed, just
+ * double it, else add extra_space.
+ */
+ new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);
+
+ if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+ DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
+ (unsigned int)new_size));
+ return False;
+ }
+
+ memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
+ }
+ ps->buffer_size = new_size;
+ ps->data_p = new_data;
+
+ return True;
+}
+
+/*******************************************************************
+ Attempt to force a data buffer to grow by len bytes.
+ This is only used when appending more data onto a prs_struct
+ when reading an rpc reply, before unmarshalling it.
+ ********************************************************************/
+
+BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
+{
+ uint32 new_size = ps->buffer_size + extra_space;
+ char *new_data;
+
+ if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
+ DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+ (unsigned int)extra_space));
+ return False;
+ }
+
+ if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+ DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
+ (unsigned int)new_size));
+ return False;
+ }
+
+ memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
+
+ ps->buffer_size = new_size;
+ ps->data_p = new_data;
+
+ return True;
+}
+
+/*******************************************************************
+ Get the data pointer (external interface).
+ ********************************************************************/
+
+char *prs_data_p(prs_struct *ps)
+{
+ return ps->data_p;
+}
+
+/*******************************************************************
+ Get the current data size (external interface).
+ ********************************************************************/
+
+uint32 prs_data_size(prs_struct *ps)
+{
+ return ps->buffer_size;
+}
+
+/*******************************************************************
+ Fetch the current offset (external interface).
+ ********************************************************************/
+
+uint32 prs_offset(prs_struct *ps)
+{
+ return ps->data_offset;
+}
+
+/*******************************************************************
+ Set the current offset (external interface).
+ ********************************************************************/
+
+BOOL prs_set_offset(prs_struct *ps, uint32 offset)
+{
+ if(offset <= ps->data_offset) {
+ ps->data_offset = offset;
+ return True;
+ }
+
+ if(!prs_grow(ps, offset - ps->data_offset))
+ return False;
+
+ ps->data_offset = offset;
+ return True;
+}
+
+/*******************************************************************
+ Append the data from one parse_struct into another.
+ ********************************************************************/
+
+BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
+{
+ if(!prs_grow(dst, prs_offset(src)))
+ return False;
+
+ memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src));
+ dst->data_offset += prs_offset(src);
+
+ return True;
+}
+
+/*******************************************************************
+ Append some data from one parse_struct into another.
+ ********************************************************************/
+
+BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
+{
+ if (len == 0)
+ return True;
+
+ if(!prs_grow(dst, len))
+ return False;
+
+ memcpy(&dst->data_p[dst->data_offset], prs_data_p(src)+start, (size_t)len);
+ dst->data_offset += len;
+
+ return True;
+}
+
+/*******************************************************************
+ Append the data from a buffer into a parse_struct.
+ ********************************************************************/
+
+BOOL prs_append_data(prs_struct *dst, char *src, uint32 len)
+{
+ if(!prs_grow(dst, len))
+ return False;
+
+ memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
+ dst->data_offset += len;
+
+ return True;
+}
+
+/*******************************************************************
+ Set the data as X-endian (external interface).
+ ********************************************************************/
+
+void prs_set_endian_data(prs_struct *ps, BOOL endian)
+{
+ ps->bigendian_data = endian;
+}
+
+/*******************************************************************
+ Align a the data_len to a multiple of align bytes - filling with
+ zeros.
+ ********************************************************************/
+
+BOOL prs_align(prs_struct *ps)
+{
+ uint32 mod = ps->data_offset & (ps->align-1);
+
+ if (ps->align != 0 && mod != 0) {
+ uint32 extra_space = (ps->align - mod);
+ if(!prs_grow(ps, extra_space))
+ return False;
+ memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+ ps->data_offset += extra_space;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Align only if required (for the unistr2 string mainly)
+ ********************************************************************/
+
+BOOL prs_align_needed(prs_struct *ps, uint32 needed)
+{
+ if (needed==0)
+ return True;
+ else
+ return prs_align(ps);
+}
+
+/*******************************************************************
+ Ensure we can read/write to a given offset.
+ ********************************************************************/
+
+char *prs_mem_get(prs_struct *ps, uint32 extra_size)
+{
+ if(UNMARSHALLING(ps)) {
+ /*
+ * If reading, ensure that we can read the requested size item.
+ */
+ if (ps->data_offset + extra_size > ps->buffer_size) {
+ DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
+ (unsigned int)extra_size ));
+ return NULL;
+ }
+ } else {
+ /*
+ * Writing - grow the buffer if needed.
+ */
+ if(!prs_grow(ps, extra_size))
+ return NULL;
+ }
+ return &ps->data_p[ps->data_offset];
+}
+
+/*******************************************************************
+ Change the struct type.
+ ********************************************************************/
+
+void prs_switch_type(prs_struct *ps, BOOL io)
+{
+ if ((ps->io ^ io) == True)
+ ps->io=io;
+}
+
+/*******************************************************************
+ Force a prs_struct to be dynamic even when it's size is 0.
+ ********************************************************************/
+
+void prs_force_dynamic(prs_struct *ps)
+{
+ ps->is_dynamic=True;
+}
+
+/*******************************************************************
+ Stream a uint8.
+ ********************************************************************/
+
+BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
+{
+ char *q = prs_mem_get(ps, 1);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps))
+ *data8 = CVAL(q,0);
+ else
+ SCVAL(q,0,*data8);
+
+ DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
+
+ ps->data_offset += 1;
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a uint16.
+ ********************************************************************/
+
+BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
+{
+ char *q = prs_mem_get(ps, sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data16 = RSVAL(q,0);
+ else
+ *data16 = SVAL(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSSVAL(q,0,*data16);
+ else
+ SSVAL(q,0,*data16);
+ }
+
+ DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16));
+
+ ps->data_offset += sizeof(uint16);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a uint32.
+ ********************************************************************/
+
+BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data32 = RIVAL(q,0);
+ else
+ *data32 = IVAL(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,*data32);
+ else
+ SIVAL(q,0,*data32);
+ }
+
+ DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a NTSTATUS
+ ********************************************************************/
+
+BOOL prs_ntstatus(char *name, prs_struct *ps, int depth, NTSTATUS *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = NT_STATUS(RIVAL(q,0));
+ else
+ *status = NT_STATUS(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,NT_STATUS_V(*status));
+ else
+ SIVAL(q,0,NT_STATUS_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name,
+ get_nt_error_msg(*status)));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a WERROR
+ ********************************************************************/
+
+BOOL prs_werror(char *name, prs_struct *ps, int depth, WERROR *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = W_ERROR(RIVAL(q,0));
+ else
+ *status = W_ERROR(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,W_ERROR_V(*status));
+ else
+ SIVAL(q,0,W_ERROR_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name,
+ werror_str(*status)));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+
+/******************************************************************
+ Stream an array of uint8s. Length is number of uint8s.
+ ********************************************************************/
+
+BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ for (i = 0; i < len; i++)
+ data8s[i] = CVAL(q,i);
+ } else {
+ for (i = 0; i < len; i++)
+ SCVAL(q, i, data8s[i]);
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data8s, len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%02x ", data8s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of uint16s. Length is number of uint16s.
+ ********************************************************************/
+
+BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ data16s[i] = RSVAL(q, 2*i);
+ } else {
+ for (i = 0; i < len; i++)
+ data16s[i] = SVAL(q, 2*i);
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSSVAL(q, 2*i, data16s[i]);
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(q, 2*i, data16s[i]);
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data16s, 2*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%04x ", data16s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += (len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Start using a function for streaming unicode chars. If unmarshalling,
+ output must be little-endian, if marshalling, input must be little-endian.
+ ********************************************************************/
+
+static void dbg_rw_punival(BOOL charmode, char *name, int depth, prs_struct *ps,
+ char *in_buf, char *out_buf, int len)
+{
+ int i;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
+ } else {
+ for (i = 0; i < len; i++)
+ SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)out_buf, 2*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%04x ", out_buf[i]));
+ }
+ DEBUG(5,("\n"));
+}
+
+/******************************************************************
+ Stream a unistr. Always little endian.
+ ********************************************************************/
+
+BOOL prs_uint16uni(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
+{
+ char *q = prs_mem_get(ps, len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
+ ps->data_offset += (len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of uint32s. Length is number of uint32s.
+ ********************************************************************/
+
+BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
+{
+ int i;
+ char *q = prs_mem_get(ps, len * sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ data32s[i] = RIVAL(q, 4*i);
+ } else {
+ for (i = 0; i < len; i++)
+ data32s[i] = IVAL(q, 4*i);
+ }
+ } else {
+ if (ps->bigendian_data) {
+ for (i = 0; i < len; i++)
+ RSIVAL(q, 4*i, data32s[i]);
+ } else {
+ for (i = 0; i < len; i++)
+ SIVAL(q, 4*i, data32s[i]);
+ }
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)data32s, 4*len);
+ else {
+ for (i = 0; i < len; i++)
+ DEBUG(5,("%08x ", data32s[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += (len * sizeof(uint32));
+
+ return True;
+}
+
+/******************************************************************
+ Stream an array of unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+BOOL prs_buffer5(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER5 *str)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len * sizeof(uint16));
+ if (str->buffer == NULL)
+ return False;
+ }
+
+ /* If the string is empty, we don't have anything to stream */
+ if (str->buf_len==0)
+ return True;
+
+ p = (char *)str->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
+
+ ps->data_offset += (str->buf_len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream a "not" unicode string, length/buffer specified separately,
+ in byte chars. String is in little-endian format.
+ ********************************************************************/
+
+BOOL prs_buffer2(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER2 *str)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->buf_len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len);
+ if (str->buffer == NULL)
+ return False;
+ }
+
+ p = (char *)str->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len/2);
+ ps->data_offset += str->buf_len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream a string, length/buffer specified separately,
+ in uint8 chars.
+ ********************************************************************/
+
+BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str)
+{
+ int i;
+ char *q = prs_mem_get(ps, str->str_max_len);
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ str->buffer = (unsigned char *)prs_alloc_mem(ps,str->str_max_len);
+ if (str->buffer == NULL)
+ return False;
+ }
+
+ if (UNMARSHALLING(ps)) {
+ for (i = 0; i < str->str_str_len; i++)
+ str->buffer[i] = CVAL(q,i);
+ } else {
+ for (i = 0; i < str->str_str_len; i++)
+ SCVAL(q, i, str->buffer[i]);
+ }
+
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
+ if (charmode)
+ print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
+ else {
+ for (i = 0; i < str->str_str_len; i++)
+ DEBUG(5,("%02x ", str->buffer[i]));
+ }
+ DEBUG(5,("\n"));
+
+ ps->data_offset += str->str_str_len;
+
+ return True;
+}
+
+/******************************************************************
+ Stream a unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ /* If the string is empty, we don't have anything to stream */
+ if (str->uni_str_len==0)
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ str->buffer = (uint16 *)prs_alloc_mem(ps,str->uni_max_len * sizeof(uint16));
+ if (str->buffer == NULL)
+ return False;
+ }
+
+ p = (char *)str->buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
+
+ ps->data_offset += (str->uni_str_len * sizeof(uint16));
+
+ return True;
+}
+
+/******************************************************************
+ Stream a unicode string, length/buffer specified separately,
+ in uint16 chars. The unicode string is already in little-endian format.
+ ********************************************************************/
+
+BOOL prs_unistr3(BOOL charmode, char *name, UNISTR3 *str, prs_struct *ps, int depth)
+{
+ char *p;
+ char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ str->str.buffer = (uint16 *)prs_alloc_mem(ps,str->uni_str_len * sizeof(uint16));
+ if (str->str.buffer == NULL)
+ return False;
+ }
+
+ p = (char *)str->str.buffer;
+
+ dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
+ ps->data_offset += (str->uni_str_len * sizeof(uint16));
+
+ return True;
+}
+
+/*******************************************************************
+ Stream a unicode null-terminated string. As the string is already
+ in little-endian format then do it as a stream of bytes.
+ ********************************************************************/
+
+BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
+{
+ int len = 0;
+ unsigned char *p = (unsigned char *)str->buffer;
+ uint8 *start;
+ char *q;
+ uint32 max_len;
+ uint16* ptr;
+
+ if (MARSHALLING(ps)) {
+
+ for(len = 0; str->buffer[len] != 0; len++)
+ ;
+
+ q = prs_mem_get(ps, (len+1)*2);
+ if (q == NULL)
+ return False;
+
+ start = (uint8*)q;
+
+ for(len = 0; str->buffer[len] != 0; len++)
+ {
+ if(ps->bigendian_data)
+ {
+ /* swap bytes - p is little endian, q is big endian. */
+ q[0] = (char)p[1];
+ q[1] = (char)p[0];
+ p += 2;
+ q += 2;
+ }
+ else
+ {
+ q[0] = (char)p[0];
+ q[1] = (char)p[1];
+ p += 2;
+ q += 2;
+ }
+ }
+
+ /*
+ * even if the string is 'empty' (only an \0 char)
+ * at this point the leading \0 hasn't been parsed.
+ * so parse it now
+ */
+
+ q[0] = 0;
+ q[1] = 0;
+ q += 2;
+
+ len++;
+
+ dump_data(5+depth, (char *)start, len * 2);
+ }
+ else { /* unmarshalling */
+
+ uint32 alloc_len = 0;
+ q = prs_data_p(ps) + prs_offset(ps);
+
+ /*
+ * Work out how much space we need and talloc it.
+ */
+ max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
+
+ /* the test of the value of *ptr helps to catch the circumstance
+ where we have an emtpty (non-existent) string in the buffer */
+ for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++)
+ /* do nothing */
+ ;
+
+ /* should we allocate anything at all? */
+ str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16));
+ if ((str->buffer == NULL) && (alloc_len > 0))
+ return False;
+
+ p = (unsigned char *)str->buffer;
+
+ len = 0;
+ /* the (len < alloc_len) test is to prevent us from overwriting
+ memory that is not ours...if we get that far, we have a non-null
+ terminated string in the buffer and have messed up somewhere */
+ while ((len < alloc_len) && (*(uint16 *)q != 0))
+ {
+ if(ps->bigendian_data)
+ {
+ /* swap bytes - q is big endian, p is little endian. */
+ p[0] = (unsigned char)q[1];
+ p[1] = (unsigned char)q[0];
+ p += 2;
+ q += 2;
+ } else {
+
+ p[0] = (unsigned char)q[0];
+ p[1] = (unsigned char)q[1];
+ p += 2;
+ q += 2;
+ }
+
+ len++;
+ }
+ if (len < alloc_len)
+ {
+ /* NULL terminate the UNISTR */
+ str->buffer[len++] = '\0';
+ }
+ }
+
+ /* set the offset in the prs_struct; 'len' points to the
+ terminiating NULL in the UNISTR so we need to go one more
+ uint16 */
+ ps->data_offset += (len)*2;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Stream a null-terminated string. len is strlen, and therefore does
+ not include the null-termination character.
+ ********************************************************************/
+
+BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size)
+{
+ char *q;
+ int i;
+
+ len = MIN(len, (max_buf_size-1));
+
+ q = prs_mem_get(ps, len+1);
+ if (q == NULL)
+ return False;
+
+ for(i = 0; i < len; i++) {
+ if (UNMARSHALLING(ps))
+ str[i] = q[i];
+ else
+ q[i] = str[i];
+ }
+
+ /* The terminating null. */
+ str[i] = '\0';
+
+ if (MARSHALLING(ps)) {
+ q[i] = '\0';
+ }
+
+ ps->data_offset += len+1;
+
+ dump_data(5+depth, q, len);
+
+ return True;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. Call this and it sets up a pointer to where the
+ uint16 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+BOOL prs_uint16_pre(char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
+{
+ *offset = ps->data_offset;
+ if (UNMARSHALLING(ps)) {
+ /* reading. */
+ return prs_uint16(name, ps, depth, data16);
+ } else {
+ char *q = prs_mem_get(ps, sizeof(uint16));
+ if(q ==NULL)
+ return False;
+ ps->data_offset += sizeof(uint16);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint16 wrapper. call this and it retrospectively stores the size.
+ does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
+ uint32 ptr_uint16, uint32 start_offset)
+{
+ if (MARSHALLING(ps)) {
+ /*
+ * Writing - temporarily move the offset pointer.
+ */
+ uint16 data_size = ps->data_offset - start_offset;
+ uint32 old_offset = ps->data_offset;
+
+ ps->data_offset = ptr_uint16;
+ if(!prs_uint16(name, ps, depth, &data_size)) {
+ ps->data_offset = old_offset;
+ return False;
+ }
+ ps->data_offset = old_offset;
+ } else {
+ ps->data_offset = start_offset + (uint32)(*data16);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint32 wrapper. Call this and it sets up a pointer to where the
+ uint32 should be stored, or gets the size if reading.
+ ********************************************************************/
+
+BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
+{
+ *offset = ps->data_offset;
+ if (UNMARSHALLING(ps) && (data32 != NULL)) {
+ /* reading. */
+ return prs_uint32(name, ps, depth, data32);
+ } else {
+ ps->data_offset += sizeof(uint32);
+ }
+ return True;
+}
+
+/*******************************************************************
+ prs_uint32 wrapper. call this and it retrospectively stores the size.
+ does nothing on reading, as that is already handled by ...._pre()
+ ********************************************************************/
+
+BOOL prs_uint32_post(char *name, prs_struct *ps, int depth, uint32 *data32,
+ uint32 ptr_uint32, uint32 data_size)
+{
+ if (MARSHALLING(ps)) {
+ /*
+ * Writing - temporarily move the offset pointer.
+ */
+ uint32 old_offset = ps->data_offset;
+ ps->data_offset = ptr_uint32;
+ if(!prs_uint32(name, ps, depth, &data_size)) {
+ ps->data_offset = old_offset;
+ return False;
+ }
+ ps->data_offset = old_offset;
+ }
+ return True;
+}
+
+/* useful function to store a structure in rpc wire format */
+int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
+{
+ TDB_DATA kbuf, dbuf;
+ kbuf.dptr = keystr;
+ kbuf.dsize = strlen(keystr)+1;
+ dbuf.dptr = prs_data_p(ps);
+ dbuf.dsize = prs_offset(ps);
+ return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+}
+
+/* useful function to fetch a structure into rpc wire format */
+int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx)
+{
+ TDB_DATA kbuf, dbuf;
+ kbuf.dptr = keystr;
+ kbuf.dsize = strlen(keystr)+1;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr) return -1;
+
+ ZERO_STRUCTP(ps);
+ prs_init(ps, 0, mem_ctx, UNMARSHALL);
+ prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
+
+ return 0;
+}
+
+/*******************************************************************
+ hash a stream.
+ ********************************************************************/
+BOOL prs_hash1(prs_struct *ps, uint32 offset, uint8 sess_key[16])
+{
+ char *q;
+
+ q = prs_data_p(ps);
+ q = &q[offset];
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("prs_hash1\n"));
+ dump_data(100, sess_key, 16);
+ dump_data(100, q, 68);
+#endif
+ SamOEMhash((uchar *) q, sess_key, 68);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, q, 68);
+#endif
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_reg.c b/source/rpc_parse/parse_reg.c
new file mode 100644
index 00000000000..181a3855926
--- /dev/null
+++ b/source/rpc_parse/parse_reg.c
@@ -0,0 +1,1680 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Marc Jacobsen 1999.
+ * Copyright (C) Simo Sorce 2000.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_open_hkcr(REG_Q_OPEN_HKCR *q_o,
+ uint16 unknown_0, uint32 level)
+{
+ q_o->ptr = 1;
+ q_o->unknown_0 = unknown_0;
+ q_o->unknown_1 = 0x0; /* random - changes */
+ q_o->level = level;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_open_hkcr(char *desc, REG_Q_OPEN_HKCR *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_open_hkcr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+
+ if (r_q->ptr != 0) {
+ if(!prs_uint16("unknown_0", ps, depth, &r_q->unknown_0))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &r_q->unknown_1))
+ return False;
+ if(!prs_uint32("level ", ps, depth, &r_q->level))
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_open_hkcr(char *desc, REG_R_OPEN_HKCR *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_hkcr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_r->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_open_hklm(REG_Q_OPEN_HKLM * q_o,
+ uint16 unknown_0, uint32 access_mask)
+{
+ q_o->ptr = 1;
+ q_o->unknown_0 = unknown_0;
+ q_o->unknown_1 = 0x0; /* random - changes */
+ q_o->access_mask = access_mask;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_q_open_hklm(char *desc, REG_Q_OPEN_HKLM * r_q, prs_struct *ps,
+ int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_open_hklm");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr ", ps, depth, &(r_q->ptr)))
+ return False;
+ if (r_q->ptr != 0)
+ {
+ if (!prs_uint16("unknown_0", ps, depth, &(r_q->unknown_0)))
+ return False;
+ if (!prs_uint16("unknown_1", ps, depth, &(r_q->unknown_1)))
+ return False;
+ if (!prs_uint32("access_mask", ps, depth, &(r_q->access_mask)))
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_r_open_hklm(char *desc, REG_R_OPEN_HKLM * r_r, prs_struct *ps,
+ int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_hklm");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("", &r_r->pol, ps, depth))
+ return False;
+
+ if (!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_flush_key(REG_Q_FLUSH_KEY *q_u, POLICY_HND *pol)
+{
+ memcpy(&q_u->pol, pol, sizeof(q_u->pol));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_flush_key(char *desc, REG_Q_FLUSH_KEY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_flush_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_flush_key(char *desc, REG_R_FLUSH_KEY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_flush_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes SEC_DESC_BUF and SEC_DATA structures.
+********************************************************************/
+
+static BOOL reg_io_hdrbuf_sec(uint32 ptr, uint32 *ptr3, BUFHDR *hdr_sec, SEC_DESC_BUF *data, prs_struct *ps, int depth)
+{
+ if (ptr != 0) {
+ uint32 hdr_offset;
+ uint32 old_offset;
+ if(!smb_io_hdrbuf_pre("hdr_sec", hdr_sec, ps, depth, &hdr_offset))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ if (ptr3 != NULL) {
+ if(!prs_uint32("ptr3", ps, depth, ptr3))
+ return False;
+ }
+
+ if (ptr3 == NULL || *ptr3 != 0) {
+ if(!sec_io_desc_buf("data ", &data, ps, depth)) /* JRA - this line is probably wrong... */
+ return False;
+ }
+
+ if(!smb_io_hdrbuf_post("hdr_sec", hdr_sec, ps, depth, hdr_offset,
+ data->max_len, data->len))
+ return False;
+ if(!prs_set_offset(ps, old_offset + data->len + sizeof(uint32) * ((ptr3 != NULL) ? 5 : 3)))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_create_key(REG_Q_CREATE_KEY *q_c, POLICY_HND *hnd,
+ char *name, char *class, SEC_ACCESS *sam_access,
+ SEC_DESC_BUF *sec_buf)
+{
+ int len_name = name != NULL ? strlen(name ) + 1: 0;
+ int len_class = class != NULL ? strlen(class) + 1: 0;
+
+ ZERO_STRUCTP(q_c);
+
+ memcpy(&q_c->pnt_pol, hnd, sizeof(q_c->pnt_pol));
+
+ init_uni_hdr(&q_c->hdr_name, len_name);
+ init_unistr2(&q_c->uni_name, name, len_name);
+
+ init_uni_hdr(&q_c->hdr_class, len_class);
+ init_unistr2(&q_c->uni_class, class, len_class);
+
+ q_c->reserved = 0x00000000;
+ memcpy(&q_c->sam_access, sam_access, sizeof(q_c->sam_access));
+
+ q_c->ptr1 = 1;
+ q_c->sec_info = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+
+ q_c->data = sec_buf;
+ q_c->ptr2 = 1;
+ init_buf_hdr(&q_c->hdr_sec, sec_buf->len, sec_buf->len);
+ q_c->ptr3 = 1;
+ q_c->unknown_2 = 0x00000000;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_create_key(char *desc, REG_Q_CREATE_KEY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_create_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pnt_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr ("", &r_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_name, r_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr ("", &r_q->hdr_class, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_class, r_q->hdr_class.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("reserved", ps, depth, &r_q->reserved))
+ return False;
+ if(!sec_io_access("sam_access", &r_q->sam_access, ps, depth))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &r_q->ptr1))
+ return False;
+
+ if (r_q->ptr1 != 0) {
+ if(!prs_uint32("sec_info", ps, depth, &r_q->sec_info))
+ return False;
+ }
+
+ if(!prs_uint32("ptr2", ps, depth, &r_q->ptr2))
+ return False;
+ if(!reg_io_hdrbuf_sec(r_q->ptr2, &r_q->ptr3, &r_q->hdr_sec, r_q->data, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown_2", ps, depth, &r_q->unknown_2))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_create_key(char *desc, REG_R_CREATE_KEY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_create_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_r->key_pol, ps, depth))
+ return False;
+ if(!prs_uint32("unknown", ps, depth, &r_r->unknown))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_delete_val(REG_Q_DELETE_VALUE *q_c, POLICY_HND *hnd,
+ char *name)
+{
+ int len_name = name != NULL ? strlen(name ) + 1: 0;
+ ZERO_STRUCTP(q_c);
+
+ memcpy(&q_c->pnt_pol, hnd, sizeof(q_c->pnt_pol));
+
+ init_uni_hdr(&q_c->hdr_name, len_name);
+ init_unistr2(&q_c->uni_name, name, len_name);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_delete_val(char *desc, REG_Q_DELETE_VALUE *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_delete_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pnt_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr ("", &r_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_name, r_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_delete_val(char *desc, REG_R_DELETE_VALUE *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_delete_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_delete_key(REG_Q_DELETE_KEY *q_c, POLICY_HND *hnd,
+ char *name)
+{
+ int len_name = name != NULL ? strlen(name ) + 1: 0;
+ ZERO_STRUCTP(q_c);
+
+ memcpy(&q_c->pnt_pol, hnd, sizeof(q_c->pnt_pol));
+
+ init_uni_hdr(&q_c->hdr_name, len_name);
+ init_unistr2(&q_c->uni_name, name, len_name);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_delete_key(char *desc, REG_Q_DELETE_KEY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_delete_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pnt_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr ("", &r_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_name, r_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_delete_key(char *desc, REG_R_DELETE_KEY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_delete_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_query_key(REG_Q_QUERY_KEY *q_o, POLICY_HND *hnd,
+ uint32 max_class_len)
+{
+ ZERO_STRUCTP(q_o);
+
+ memcpy(&q_o->pol, hnd, sizeof(q_o->pol));
+ init_uni_hdr(&q_o->hdr_class, max_class_len);
+ q_o->uni_class.uni_max_len = max_class_len;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_query_key(char *desc, REG_Q_QUERY_KEY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_query_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+ if(!smb_io_unihdr ("", &r_q->hdr_class, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_class, r_q->hdr_class.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_query_key(char *desc, REG_R_QUERY_KEY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_query_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr ("", &r_r->hdr_class, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_r->uni_class, r_r->hdr_class.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_subkeys ", ps, depth, &r_r->num_subkeys))
+ return False;
+ if(!prs_uint32("max_subkeylen ", ps, depth, &r_r->max_subkeylen))
+ return False;
+ if(!prs_uint32("mak_subkeysize", ps, depth, &r_r->max_subkeysize))
+ return False;
+ if(!prs_uint32("num_values ", ps, depth, &r_r->num_values))
+ return False;
+ if(!prs_uint32("max_valnamelen", ps, depth, &r_r->max_valnamelen))
+ return False;
+ if(!prs_uint32("max_valbufsize", ps, depth, &r_r->max_valbufsize))
+ return False;
+ if(!prs_uint32("sec_desc ", ps, depth, &r_r->sec_desc))
+ return False;
+ if(!smb_io_time("mod_time ", &r_r->mod_time, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_unk_1a(REG_Q_UNK_1A *q_o, POLICY_HND *hnd)
+{
+ memcpy(&q_o->pol, hnd, sizeof(q_o->pol));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_unk_1a(char *desc, REG_Q_UNK_1A *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_unk_1a");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_unk_1a(char *desc, REG_R_UNK_1A *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_unk_1a");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("unknown", ps, depth, &r_r->unknown))
+ return False;
+ if(!prs_ntstatus("status" , ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_q_open_hku(REG_Q_OPEN_HKU *q_o,
+ uint16 unknown_0, uint32 level)
+{
+ q_o->ptr = 1;
+ q_o->unknown_0 = unknown_0;
+ q_o->unknown_1 = 0x0; /* random - changes */
+ q_o->level = level;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_open_hku(char *desc, REG_Q_OPEN_HKU *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_open_hku");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+ if (r_q->ptr != 0) {
+ if(!prs_uint16("unknown_0", ps, depth, &r_q->unknown_0))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &r_q->unknown_1))
+ return False;
+ if(!prs_uint32("level ", ps, depth, &r_q->level))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_open_hku(char *desc, REG_R_OPEN_HKU *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_hku");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_r->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an REG_Q_CLOSE structure.
+********************************************************************/
+
+void init_reg_q_close(REG_Q_CLOSE *q_c, POLICY_HND *hnd)
+{
+ DEBUG(5,("init_reg_q_close\n"));
+
+ memcpy(&q_c->pol, hnd, sizeof(q_c->pol));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_close(char *desc, REG_Q_CLOSE *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_unknown_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &q_u->pol, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_close(char *desc, REG_R_CLOSE *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_unknown_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_u->pol, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_set_key_sec(REG_Q_SET_KEY_SEC *q_i, POLICY_HND *pol, SEC_DESC_BUF *sec_desc_buf)
+{
+ memcpy(&q_i->pol, pol, sizeof(q_i->pol));
+
+ q_i->sec_info = DACL_SECURITY_INFORMATION;
+
+ q_i->ptr = 1;
+ init_buf_hdr(&q_i->hdr_sec, sec_desc_buf->len, sec_desc_buf->len);
+ q_i->data = sec_desc_buf;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_set_key_sec(char *desc, REG_Q_SET_KEY_SEC *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_set_key_sec");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("sec_info", ps, depth, &r_q->sec_info))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+
+ if(!reg_io_hdrbuf_sec(r_q->ptr, NULL, &r_q->hdr_sec, r_q->data, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_set_key_sec(char *desc, REG_R_SET_KEY_SEC *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_set_key_sec");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_get_key_sec(REG_Q_GET_KEY_SEC *q_i, POLICY_HND *pol,
+ uint32 sec_buf_size, SEC_DESC_BUF *psdb)
+{
+ memcpy(&q_i->pol, pol, sizeof(q_i->pol));
+
+ q_i->sec_info = OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION;
+
+ q_i->ptr = psdb != NULL ? 1 : 0;
+ q_i->data = psdb;
+
+ init_buf_hdr(&q_i->hdr_sec, sec_buf_size, 0);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_get_key_sec(char *desc, REG_Q_GET_KEY_SEC *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_get_key_sec");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("sec_info", ps, depth, &r_q->sec_info))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+
+ if(!reg_io_hdrbuf_sec(r_q->ptr, NULL, &r_q->hdr_sec, r_q->data, ps, depth))
+ return False;
+
+ return True;
+}
+
+#if 0
+/*******************************************************************
+makes a structure.
+********************************************************************/
+ void init_reg_r_get_key_sec(REG_R_GET_KEY_SEC *r_i, POLICY_HND *pol,
+ uint32 buf_len, uint8 *buf,
+ NTSTATUS status)
+{
+ r_i->ptr = 1;
+ init_buf_hdr(&r_i->hdr_sec, buf_len, buf_len);
+ init_sec_desc_buf(r_i->data, buf_len, 1);
+
+ r_i->status = status; /* 0x0000 0000 or 0x0000 007a */
+}
+#endif
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_get_key_sec(char *desc, REG_R_GET_KEY_SEC *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_get_key_sec");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &r_q->ptr))
+ return False;
+
+ if (r_q->ptr != 0) {
+ if(!smb_io_hdrbuf("", &r_q->hdr_sec, ps, depth))
+ return False;
+ if(!sec_io_desc_buf("", &r_q->data, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+BOOL init_reg_q_info(REG_Q_INFO *q_i, POLICY_HND *pol, char* val_name)
+{
+ int len_type = val_name != NULL ? strlen(val_name) + 1 : 0;
+
+ if (q_i == NULL)
+ return False;
+
+ q_i->pol = *pol;
+
+ init_uni_hdr(&(q_i->hdr_type), len_type);
+ init_unistr2(&(q_i->uni_type), val_name, len_type);
+
+ q_i->ptr_reserved = 1;
+ q_i->ptr_buf = 1;
+
+ q_i->ptr_bufsize = 1;
+ q_i->bufsize = 0;
+ q_i->buf_unk = 0;
+
+ q_i->unk1 = 0;
+ q_i->ptr_buflen = 1;
+ q_i->buflen = 0;
+
+ q_i->ptr_buflen2 = 1;
+ q_i->buflen2 = 0;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_info(char *desc, REG_Q_INFO *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+ if(!smb_io_unihdr ("", &r_q->hdr_type, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_type, r_q->hdr_type.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_reserved", ps, depth, &(r_q->ptr_reserved)))
+ return False;
+
+ if(!prs_uint32("ptr_buf", ps, depth, &(r_q->ptr_buf)))
+ return False;
+
+ if(r_q->ptr_buf) {
+ if(!prs_uint32("ptr_bufsize", ps, depth, &(r_q->ptr_bufsize)))
+ return False;
+ if(!prs_uint32("bufsize", ps, depth, &(r_q->bufsize)))
+ return False;
+ if(!prs_uint32("buf_unk", ps, depth, &(r_q->buf_unk)))
+ return False;
+ }
+
+ if(!prs_uint32("unk1", ps, depth, &(r_q->unk1)))
+ return False;
+
+ if(!prs_uint32("ptr_buflen", ps, depth, &(r_q->ptr_buflen)))
+ return False;
+ if(!prs_uint32("buflen", ps, depth, &(r_q->buflen)))
+ return False;
+
+ if(!prs_uint32("ptr_buflen2", ps, depth, &(r_q->ptr_buflen2)))
+ return False;
+ if(!prs_uint32("buflen2", ps, depth, &(r_q->buflen2)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+BOOL init_reg_r_info(uint32 include_keyval, REG_R_INFO *r_r,
+ BUFFER2* buf, uint32 type, NTSTATUS status)
+{
+ if(r_r == NULL)
+ return False;
+
+
+ r_r->ptr_type = 1;
+ r_r->type = type;
+
+ /* if include_keyval is not set, don't send the key value, just
+ the buflen data. probably used by NT5 to allocate buffer space - SK */
+ r_r->ptr_uni_val = include_keyval ? 1:0;
+ r_r->uni_val = buf;
+
+ r_r->ptr_max_len = 1;
+ r_r->buf_max_len = r_r->uni_val->buf_max_len;
+
+ r_r->ptr_len = 1;
+ r_r->buf_len = r_r->uni_val->buf_len;
+
+ r_r->status = status;
+
+ return True;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_info(char *desc, REG_R_INFO *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_type", ps, depth, &(r_r->ptr_type)))
+ return False;
+
+ if (r_r->ptr_type != 0) {
+ if(!prs_uint32("type", ps, depth, &r_r->type))
+ return False;
+ }
+
+ if(!prs_uint32("ptr_uni_val", ps, depth, &(r_r->ptr_uni_val)))
+ return False;
+
+ if(r_r->ptr_uni_val != 0) {
+ if(!smb_io_buffer2("uni_val", r_r->uni_val, r_r->ptr_uni_val, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_max_len", ps, depth, &(r_r->ptr_max_len)))
+ return False;
+
+ if (r_r->ptr_max_len != 0) {
+ if(!prs_uint32("buf_max_len", ps, depth, &(r_r->buf_max_len)))
+ return False;
+ }
+
+ if(!prs_uint32("ptr_len", ps, depth, &(r_r->ptr_len)))
+ return False;
+ if (r_r->ptr_len != 0) {
+ if(!prs_uint32("buf_len", ps, depth, &(r_r->buf_len)))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_enum_val(REG_Q_ENUM_VALUE *q_i, POLICY_HND *pol,
+ uint32 val_idx, uint32 max_val_len,
+ uint32 max_buf_len)
+{
+ ZERO_STRUCTP(q_i);
+
+ memcpy(&q_i->pol, pol, sizeof(q_i->pol));
+
+ q_i->val_index = val_idx;
+ init_uni_hdr(&q_i->hdr_name, max_val_len);
+ q_i->uni_name.uni_max_len = max_val_len;
+
+ q_i->ptr_type = 1;
+ q_i->type = 0x0;
+
+ q_i->ptr_value = 1;
+ q_i->buf_value.buf_max_len = max_buf_len;
+
+ q_i->ptr1 = 1;
+ q_i->len_value1 = max_buf_len;
+
+ q_i->ptr2 = 1;
+ q_i->len_value2 = 0;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_enum_val(char *desc, REG_Q_ENUM_VALUE *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_enum_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("val_index", ps, depth, &q_q->val_index))
+ return False;
+ if(!smb_io_unihdr ("hdr_name", &q_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_name", &q_q->uni_name, q_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_type", ps, depth, &q_q->ptr_type))
+ return False;
+
+ if (q_q->ptr_type != 0) {
+ if(!prs_uint32("type", ps, depth, &q_q->type))
+ return False;
+ }
+
+ if(!prs_uint32("ptr_value", ps, depth, &q_q->ptr_value))
+ return False;
+ if(!smb_io_buffer2("buf_value", &q_q->buf_value, q_q->ptr_value, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &q_q->ptr1))
+ return False;
+ if (q_q->ptr1 != 0) {
+ if(!prs_uint32("len_value1", ps, depth, &q_q->len_value1))
+ return False;
+ }
+ if(!prs_uint32("ptr2", ps, depth, &q_q->ptr2))
+ return False;
+ if (q_q->ptr2 != 0) {
+ if(!prs_uint32("len_value2", ps, depth, &q_q->len_value2))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_enum_val(char *desc, REG_R_ENUM_VALUE *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_enum_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr ("hdr_name", &r_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_name", &r_q->uni_name, r_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_type", ps, depth, &r_q->ptr_type))
+ return False;
+
+ if (r_q->ptr_type != 0) {
+ if(!prs_uint32("type", ps, depth, &r_q->type))
+ return False;
+ }
+
+ if(!prs_uint32("ptr_value", ps, depth, &r_q->ptr_value))
+ return False;
+ if(!smb_io_buffer2("buf_value", r_q->buf_value, r_q->ptr_value, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &r_q->ptr1))
+ return False;
+ if (r_q->ptr1 != 0) {
+ if(!prs_uint32("len_value1", ps, depth, &r_q->len_value1))
+ return False;
+ }
+
+ if(!prs_uint32("ptr2", ps, depth, &r_q->ptr2))
+ return False;
+ if (r_q->ptr2 != 0) {
+ if(!prs_uint32("len_value2", ps, depth, &r_q->len_value2))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_create_val(REG_Q_CREATE_VALUE *q_i, POLICY_HND *pol,
+ char *val_name, uint32 type,
+ BUFFER3 *val)
+{
+ int val_len = strlen(val_name) + 1;
+
+ ZERO_STRUCTP(q_i);
+
+ memcpy(&q_i->pol, pol, sizeof(q_i->pol));
+
+ init_uni_hdr(&q_i->hdr_name, val_len);
+ init_unistr2(&q_i->uni_name, val_name, val_len);
+
+ q_i->type = type;
+ q_i->buf_value = val;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_create_val(char *desc, REG_Q_CREATE_VALUE *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_create_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr ("hdr_name", &q_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_name", &q_q->uni_name, q_q->hdr_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_q->type))
+ return False;
+ if(!smb_io_buffer3("buf_value", q_q->buf_value, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_create_val(char *desc, REG_R_CREATE_VALUE *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_create_val");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_enum_key(REG_Q_ENUM_KEY *q_i, POLICY_HND *pol, uint32 key_idx)
+{
+ memcpy(&q_i->pol, pol, sizeof(q_i->pol));
+
+ q_i->key_index = key_idx;
+ q_i->key_name_len = 0;
+ q_i->unknown_1 = 0x0414;
+
+ q_i->ptr1 = 1;
+ q_i->unknown_2 = 0x0000020A;
+ memset(q_i->pad1, 0, sizeof(q_i->pad1));
+
+ q_i->ptr2 = 1;
+ memset(q_i->pad2, 0, sizeof(q_i->pad2));
+
+ q_i->ptr3 = 1;
+ unix_to_nt_time(&q_i->time, 0); /* current time? */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_enum_key(char *desc, REG_Q_ENUM_KEY *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_enum_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &q_q->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("key_index", ps, depth, &q_q->key_index))
+ return False;
+ if(!prs_uint16("key_name_len", ps, depth, &q_q->key_name_len))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &q_q->unknown_1))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &q_q->ptr1))
+ return False;
+
+ if (q_q->ptr1 != 0) {
+ if(!prs_uint32("unknown_2", ps, depth, &q_q->unknown_2))
+ return False;
+ if(!prs_uint8s(False, "pad1", ps, depth, q_q->pad1, sizeof(q_q->pad1)))
+ return False;
+ }
+
+ if(!prs_uint32("ptr2", ps, depth, &q_q->ptr2))
+ return False;
+
+ if (q_q->ptr2 != 0) {
+ if(!prs_uint8s(False, "pad2", ps, depth, q_q->pad2, sizeof(q_q->pad2)))
+ return False;
+ }
+
+ if(!prs_uint32("ptr3", ps, depth, &q_q->ptr3))
+ return False;
+
+ if (q_q->ptr3 != 0) {
+ if(!smb_io_time("", &q_q->time, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_enum_key(char *desc, REG_R_ENUM_KEY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_enum_key");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("key_name_len", ps, depth, &r_q->key_name_len))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &r_q->unknown_1))
+ return False;
+
+ if(!prs_uint32("ptr1", ps, depth, &r_q->ptr1))
+ return False;
+
+ if (r_q->ptr1 != 0) {
+ if(!prs_uint32("unknown_2", ps, depth, &r_q->unknown_2))
+ return False;
+ if(!prs_uint32("unknown_3", ps, depth, &r_q->unknown_3))
+ return False;
+ if(!smb_io_unistr3("key_name", &r_q->key_name, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ if(!prs_uint32("ptr2", ps, depth, &r_q->ptr2))
+ return False;
+
+ if (r_q->ptr2 != 0) {
+ if(!prs_uint8s(False, "pad2", ps, depth, r_q->pad2, sizeof(r_q->pad2)))
+ return False;
+ }
+
+ if(!prs_uint32("ptr3", ps, depth, &r_q->ptr3))
+ return False;
+
+ if (r_q->ptr3 != 0) {
+ if(!smb_io_time("", &r_q->time, ps, depth))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_q->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+makes a structure.
+********************************************************************/
+
+void init_reg_q_open_entry(REG_Q_OPEN_ENTRY *r_q, POLICY_HND *pol,
+ char *key_name, uint32 unk)
+{
+ int len_name = strlen(key_name)+1;
+
+ memcpy(&r_q->pol, pol, sizeof(r_q->pol));
+
+ init_uni_hdr(&r_q->hdr_name, len_name);
+ init_unistr2(&r_q->uni_name, key_name, len_name);
+
+ r_q->unknown_0 = 0x00000000;
+ r_q->unknown_1 = unk;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_q_open_entry(char *desc, REG_Q_OPEN_ENTRY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_entry");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_q->pol, ps, depth))
+ return False;
+ if(!smb_io_unihdr ("", &r_q->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &r_q->uni_name, r_q->hdr_name.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("unknown_0", ps, depth, &r_q->unknown_0))
+ return False;
+ if(!prs_uint32("unknown_1", ps, depth, &r_q->unknown_1))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a structure.
+********************************************************************/
+
+void init_reg_r_open_entry(REG_R_OPEN_ENTRY *r_r,
+ POLICY_HND *pol, NTSTATUS status)
+{
+ memcpy(&r_r->pol, pol, sizeof(r_r->pol));
+ r_r->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL reg_io_r_open_entry(char *desc, REG_R_OPEN_ENTRY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_entry");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("", &r_r->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_r->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+Inits a structure.
+********************************************************************/
+void init_reg_q_shutdown(REG_Q_SHUTDOWN * q_s,
+ const char *msg, uint32 timeout, uint16 flags)
+{
+ int msg_len;
+ msg_len = strlen(msg);
+
+ q_s->ptr_0 = 1;
+ q_s->ptr_1 = 1;
+ q_s->ptr_2 = 1;
+
+ init_uni_hdr(&(q_s->hdr_msg), msg_len);
+ init_unistr2(&(q_s->uni_msg), msg, msg_len);
+
+ q_s->timeout = timeout;
+ q_s->flags = flags;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_q_shutdown(char *desc, REG_Q_SHUTDOWN * q_s, prs_struct *ps,
+ int depth)
+{
+ if (q_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_shutdown");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr_0", ps, depth, &(q_s->ptr_0)))
+ return False;
+ if (!prs_uint32("ptr_1", ps, depth, &(q_s->ptr_1)))
+ return False;
+ if (!prs_uint32("ptr_2", ps, depth, &(q_s->ptr_2)))
+ return False;
+
+ if (!smb_io_unihdr("hdr_msg", &(q_s->hdr_msg), ps, depth))
+ return False;
+ if (!smb_io_unistr2("uni_msg", &(q_s->uni_msg), q_s->hdr_msg.buffer, ps, depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("timeout", ps, depth, &(q_s->timeout)))
+ return False;
+ if (!prs_uint16("flags ", ps, depth, &(q_s->flags)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_r_shutdown(char *desc, REG_R_SHUTDOWN * r_s, prs_struct *ps,
+ int depth)
+{
+ if (r_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_shutdown");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_s->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+Inits a structure.
+********************************************************************/
+void init_reg_q_abort_shutdown(REG_Q_ABORT_SHUTDOWN * q_s)
+{
+
+ q_s->ptr_server = 0;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_q_abort_shutdown(char *desc, REG_Q_ABORT_SHUTDOWN * q_s,
+ prs_struct *ps, int depth)
+{
+ if (q_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_q_abort_shutdown");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr_server", ps, depth, &(q_s->ptr_server)))
+ return False;
+ if (q_s->ptr_server != 0)
+ if (!prs_uint16("server", ps, depth, &(q_s->server)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL reg_io_r_abort_shutdown(char *desc, REG_R_ABORT_SHUTDOWN * r_s,
+ prs_struct *ps, int depth)
+{
+ if (r_s == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "reg_io_r_abort_shutdown");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_ntstatus("status", ps, depth, &r_s->status))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_rpc.c b/source/rpc_parse/parse_rpc.c
new file mode 100644
index 00000000000..f4a84adee39
--- /dev/null
+++ b/source/rpc_parse/parse_rpc.c
@@ -0,0 +1,1089 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+interface/version dce/rpc pipe identification
+********************************************************************/
+
+#define TRANS_SYNT_V2 \
+{ \
+ { \
+ 0x8a885d04, 0x1ceb, 0x11c9, \
+ { 0x9f, 0xe8, 0x08, 0x00, \
+ 0x2b, 0x10, 0x48, 0x60 } \
+ }, 0x02 \
+}
+
+#define SYNT_NETLOGON_V2 \
+{ \
+ { \
+ 0x8a885d04, 0x1ceb, 0x11c9, \
+ { 0x9f, 0xe8, 0x08, 0x00, \
+ 0x2b, 0x10, 0x48, 0x60 } \
+ }, 0x02 \
+}
+
+#define SYNT_WKSSVC_V1 \
+{ \
+ { \
+ 0x6bffd098, 0xa112, 0x3610, \
+ { 0x98, 0x33, 0x46, 0xc3, \
+ 0xf8, 0x7e, 0x34, 0x5a } \
+ }, 0x01 \
+}
+
+#define SYNT_SRVSVC_V3 \
+{ \
+ { \
+ 0x4b324fc8, 0x1670, 0x01d3, \
+ { 0x12, 0x78, 0x5a, 0x47, \
+ 0xbf, 0x6e, 0xe1, 0x88 } \
+ }, 0x03 \
+}
+
+#define SYNT_LSARPC_V0 \
+{ \
+ { \
+ 0x12345778, 0x1234, 0xabcd, \
+ { 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0x89, 0xab } \
+ }, 0x00 \
+}
+
+#define SYNT_SAMR_V1 \
+{ \
+ { \
+ 0x12345778, 0x1234, 0xabcd, \
+ { 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0x89, 0xac } \
+ }, 0x01 \
+}
+
+#define SYNT_NETLOGON_V1 \
+{ \
+ { \
+ 0x12345678, 0x1234, 0xabcd, \
+ { 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0xcf, 0xfb } \
+ }, 0x01 \
+}
+
+#define SYNT_WINREG_V1 \
+{ \
+ { \
+ 0x338cd001, 0x2244, 0x31f1, \
+ { 0xaa, 0xaa, 0x90, 0x00, \
+ 0x38, 0x00, 0x10, 0x03 } \
+ }, 0x01 \
+}
+
+#define SYNT_SPOOLSS_V1 \
+{ \
+ { \
+ 0x12345678, 0x1234, 0xabcd, \
+ { 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0x89, 0xab } \
+ }, 0x01 \
+}
+
+#define SYNT_NONE_V0 \
+{ \
+ { \
+ 0x0, 0x0, 0x0, \
+ { 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00 } \
+ }, 0x00 \
+}
+
+#define SYNT_NETDFS_V3 \
+{ \
+ { \
+ 0x4fc742e0, 0x4a10, 0x11cf, \
+ { 0x82, 0x73, 0x00, 0xaa, \
+ 0x00, 0x4a, 0xe6, 0x73 } \
+ }, 0x03 \
+}
+
+struct pipe_id_info pipe_names [] =
+{
+ /* client pipe , abstract syntax , server pipe , transfer syntax */
+ { PIPE_LSARPC , SYNT_LSARPC_V0 , PIPE_LSASS , TRANS_SYNT_V2 },
+ { PIPE_SAMR , SYNT_SAMR_V1 , PIPE_LSASS , TRANS_SYNT_V2 },
+ { PIPE_NETLOGON, SYNT_NETLOGON_V1, PIPE_LSASS , TRANS_SYNT_V2 },
+ { PIPE_SRVSVC , SYNT_SRVSVC_V3 , PIPE_NTSVCS , TRANS_SYNT_V2 },
+ { PIPE_WKSSVC , SYNT_WKSSVC_V1 , PIPE_NTSVCS , TRANS_SYNT_V2 },
+ { PIPE_WINREG , SYNT_WINREG_V1 , PIPE_WINREG , TRANS_SYNT_V2 },
+ { PIPE_SPOOLSS , SYNT_SPOOLSS_V1 , PIPE_SPOOLSS , TRANS_SYNT_V2 },
+ { PIPE_NETDFS , SYNT_NETDFS_V3 , PIPE_NETDFS , TRANS_SYNT_V2 },
+ { NULL , SYNT_NONE_V0 , NULL , SYNT_NONE_V0 }
+};
+
+/*******************************************************************
+ Inits an RPC_HDR structure.
+********************************************************************/
+
+void init_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
+ uint32 call_id, int data_len, int auth_len)
+{
+ hdr->major = 5; /* RPC version 5 */
+ hdr->minor = 0; /* minor version 0 */
+ hdr->pkt_type = pkt_type; /* RPC packet type */
+ hdr->flags = flags; /* dce/rpc flags */
+ hdr->pack_type[0] = 0x10; /* little-endian data representation */
+ hdr->pack_type[1] = 0; /* packed data representation */
+ hdr->pack_type[2] = 0; /* packed data representation */
+ hdr->pack_type[3] = 0; /* packed data representation */
+ hdr->frag_len = data_len; /* fragment length, fill in later */
+ hdr->auth_len = auth_len; /* authentication length */
+ hdr->call_id = call_id; /* call identifier - match incoming RPC */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr(char *desc, RPC_HDR *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr");
+ depth++;
+
+ if(!prs_uint8 ("major ", ps, depth, &rpc->major))
+ return False;
+
+ if(!prs_uint8 ("minor ", ps, depth, &rpc->minor))
+ return False;
+ if(!prs_uint8 ("pkt_type ", ps, depth, &rpc->pkt_type))
+ return False;
+ if(!prs_uint8 ("flags ", ps, depth, &rpc->flags))
+ return False;
+
+ /* We always marshall in little endian format. */
+ if (MARSHALLING(ps))
+ rpc->pack_type[0] = 0x10;
+
+ if(!prs_uint8("pack_type0", ps, depth, &rpc->pack_type[0]))
+ return False;
+ if(!prs_uint8("pack_type1", ps, depth, &rpc->pack_type[1]))
+ return False;
+ if(!prs_uint8("pack_type2", ps, depth, &rpc->pack_type[2]))
+ return False;
+ if(!prs_uint8("pack_type3", ps, depth, &rpc->pack_type[3]))
+ return False;
+
+ /*
+ * If reading and pack_type[0] == 0 then the data is in big-endian
+ * format. Set the flag in the prs_struct to specify reverse-endainness.
+ */
+
+ if (UNMARSHALLING(ps) && rpc->pack_type[0] == 0) {
+ DEBUG(10,("smb_io_rpc_hdr: PDU data format is big-endian. Setting flag.\n"));
+ prs_set_endian_data(ps, RPC_BIG_ENDIAN);
+ }
+
+ if(!prs_uint16("frag_len ", ps, depth, &rpc->frag_len))
+ return False;
+ if(!prs_uint16("auth_len ", ps, depth, &rpc->auth_len))
+ return False;
+ if(!prs_uint32("call_id ", ps, depth, &rpc->call_id))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_IFACE structure.
+********************************************************************/
+
+static BOOL smb_io_rpc_iface(char *desc, RPC_IFACE *ifc, prs_struct *ps, int depth)
+{
+ if (ifc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_iface");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32 ("data ", ps, depth, &ifc->uuid.time_low))
+ return False;
+ if(!prs_uint16 ("data ", ps, depth, &ifc->uuid.time_mid))
+ return False;
+ if(!prs_uint16 ("data ", ps, depth, &ifc->uuid.time_hi_and_version))
+ return False;
+
+ if(!prs_uint8s (False, "data ", ps, depth, ifc->uuid.remaining, sizeof(ifc->uuid.remaining)))
+ return False;
+ if(!prs_uint32 ( "version", ps, depth, &ifc->version))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_ADDR_STR structure.
+********************************************************************/
+
+static void init_rpc_addr_str(RPC_ADDR_STR *str, char *name)
+{
+ str->len = strlen(name) + 1;
+ fstrcpy(str->str, name);
+}
+
+/*******************************************************************
+ Reads or writes an RPC_ADDR_STR structure.
+********************************************************************/
+
+static BOOL smb_io_rpc_addr_str(char *desc, RPC_ADDR_STR *str, prs_struct *ps, int depth)
+{
+ if (str == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_addr_str");
+ depth++;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16 ( "len", ps, depth, &str->len))
+ return False;
+ if(!prs_uint8s (True, "str", ps, depth, (uchar*)str->str, MIN(str->len, sizeof(str->str)) ))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_BBA structure.
+********************************************************************/
+
+static void init_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
+{
+ bba->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
+ bba->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
+ bba->assoc_gid = assoc_gid; /* associated group id (0x0) */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_BBA structure.
+********************************************************************/
+
+static BOOL smb_io_rpc_hdr_bba(char *desc, RPC_HDR_BBA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_bba");
+ depth++;
+
+ if(!prs_uint16("max_tsize", ps, depth, &rpc->max_tsize))
+ return False;
+ if(!prs_uint16("max_rsize", ps, depth, &rpc->max_rsize))
+ return False;
+ if(!prs_uint32("assoc_gid", ps, depth, &rpc->assoc_gid))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_RB structure.
+********************************************************************/
+
+void init_rpc_hdr_rb(RPC_HDR_RB *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ uint32 num_elements, uint16 context_id, uint8 num_syntaxes,
+ RPC_IFACE *abstract, RPC_IFACE *transfer)
+{
+ init_rpc_hdr_bba(&rpc->bba, max_tsize, max_rsize, assoc_gid);
+
+ rpc->num_elements = num_elements ; /* the number of elements (0x1) */
+ rpc->context_id = context_id ; /* presentation context identifier (0x0) */
+ rpc->num_syntaxes = num_syntaxes ; /* the number of syntaxes (has always been 1?)(0x1) */
+
+ /* num and vers. of interface client is using */
+ rpc->abstract = *abstract;
+
+ /* num and vers. of interface to use for replies */
+ rpc->transfer = *transfer;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_RB structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_rb(char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_rb");
+ depth++;
+
+ if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
+ return False;
+
+ if(!prs_uint32("num_elements", ps, depth, &rpc->num_elements))
+ return False;
+ if(!prs_uint16("context_id ", ps, depth, &rpc->context_id ))
+ return False;
+ if(!prs_uint8 ("num_syntaxes", ps, depth, &rpc->num_syntaxes))
+ return False;
+
+ if(!smb_io_rpc_iface("", &rpc->abstract, ps, depth))
+ return False;
+ if(!smb_io_rpc_iface("", &rpc->transfer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_RESULTS structure.
+
+ lkclXXXX only one reason at the moment!
+********************************************************************/
+
+static void init_rpc_results(RPC_RESULTS *res,
+ uint8 num_results, uint16 result, uint16 reason)
+{
+ res->num_results = num_results; /* the number of results (0x01) */
+ res->result = result ; /* result (0x00 = accept) */
+ res->reason = reason ; /* reason (0x00 = no reason specified) */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_RESULTS structure.
+
+ lkclXXXX only one reason at the moment!
+********************************************************************/
+
+static BOOL smb_io_rpc_results(char *desc, RPC_RESULTS *res, prs_struct *ps, int depth)
+{
+ if (res == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_results");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8 ("num_results", ps, depth, &res->num_results))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("result ", ps, depth, &res->result))
+ return False;
+ if(!prs_uint16("reason ", ps, depth, &res->reason))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Init an RPC_HDR_BA structure.
+
+ lkclXXXX only one reason at the moment!
+
+********************************************************************/
+
+void init_rpc_hdr_ba(RPC_HDR_BA *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ char *pipe_addr,
+ uint8 num_results, uint16 result, uint16 reason,
+ RPC_IFACE *transfer)
+{
+ init_rpc_hdr_bba (&rpc->bba, max_tsize, max_rsize, assoc_gid);
+ init_rpc_addr_str(&rpc->addr, pipe_addr);
+ init_rpc_results (&rpc->res, num_results, result, reason);
+
+ /* the transfer syntax from the request */
+ memcpy(&rpc->transfer, transfer, sizeof(rpc->transfer));
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_BA structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_ba(char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_ba");
+ depth++;
+
+ if(!smb_io_rpc_hdr_bba("", &rpc->bba, ps, depth))
+ return False;
+ if(!smb_io_rpc_addr_str("", &rpc->addr, ps, depth))
+ return False;
+ if(!smb_io_rpc_results("", &rpc->res, ps, depth))
+ return False;
+ if(!smb_io_rpc_iface("", &rpc->transfer, ps, depth))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Init an RPC_HDR_REQ structure.
+********************************************************************/
+
+void init_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 alloc_hint, uint16 opnum)
+{
+ hdr->alloc_hint = alloc_hint; /* allocation hint */
+ hdr->context_id = 0; /* presentation context identifier */
+ hdr->opnum = opnum; /* opnum */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_REQ structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_req(char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_req");
+ depth++;
+
+ if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
+ return False;
+ if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
+ return False;
+ if(!prs_uint16("opnum ", ps, depth, &rpc->opnum))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_RESP structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_resp(char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_resp");
+ depth++;
+
+ if(!prs_uint32("alloc_hint", ps, depth, &rpc->alloc_hint))
+ return False;
+ if(!prs_uint16("context_id", ps, depth, &rpc->context_id))
+ return False;
+ if(!prs_uint8 ("cancel_ct ", ps, depth, &rpc->cancel_count))
+ return False;
+ if(!prs_uint8 ("reserved ", ps, depth, &rpc->reserved))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_FAULT structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_fault(char *desc, RPC_HDR_FAULT *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_fault");
+ depth++;
+
+ if(!prs_ntstatus("status ", ps, depth, &rpc->status))
+ return False;
+ if(!prs_uint32("reserved", ps, depth, &rpc->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Init an RPC_HDR_AUTHA structure.
+********************************************************************/
+
+void init_rpc_hdr_autha(RPC_HDR_AUTHA *rai,
+ uint16 max_tsize, uint16 max_rsize,
+ uint8 auth_type, uint8 auth_level,
+ uint8 stub_type_len)
+{
+ rai->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
+ rai->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
+
+ rai->auth_type = auth_type; /* nt lm ssp 0x0a */
+ rai->auth_level = auth_level; /* 0x06 */
+ rai->stub_type_len = stub_type_len; /* 0x00 */
+ rai->padding = 0; /* padding 0x00 */
+
+ rai->unknown = 0x0014a0c0; /* non-zero pointer to something */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_AUTHA structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_autha(char *desc, RPC_HDR_AUTHA *rai, prs_struct *ps, int depth)
+{
+ if (rai == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_autha");
+ depth++;
+
+ if(!prs_uint16("max_tsize ", ps, depth, &rai->max_tsize))
+ return False;
+ if(!prs_uint16("max_rsize ", ps, depth, &rai->max_rsize))
+ return False;
+
+ if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) /* 0x0a nt lm ssp */
+ return False;
+ if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) /* 0x06 */
+ return False;
+ if(!prs_uint8 ("stub_type_len", ps, depth, &rai->stub_type_len))
+ return False;
+ if(!prs_uint8 ("padding ", ps, depth, &rai->padding))
+ return False;
+
+ if(!prs_uint32("unknown ", ps, depth, &rai->unknown)) /* 0x0014a0c0 */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Checks an RPC_HDR_AUTH structure.
+********************************************************************/
+
+BOOL rpc_hdr_auth_chk(RPC_HDR_AUTH *rai)
+{
+ return (rai->auth_type == NTLMSSP_AUTH_TYPE && rai->auth_level == NTLMSSP_AUTH_LEVEL);
+}
+
+/*******************************************************************
+ Inits an RPC_HDR_AUTH structure.
+********************************************************************/
+
+void init_rpc_hdr_auth(RPC_HDR_AUTH *rai,
+ uint8 auth_type, uint8 auth_level,
+ uint8 stub_type_len,
+ uint32 ptr)
+{
+ rai->auth_type = auth_type; /* nt lm ssp 0x0a */
+ rai->auth_level = auth_level; /* 0x06 */
+ rai->stub_type_len = stub_type_len; /* 0x00 */
+ rai->padding = 0; /* padding 0x00 */
+
+ rai->unknown = ptr; /* non-zero pointer to something */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_HDR_AUTH structure.
+********************************************************************/
+
+BOOL smb_io_rpc_hdr_auth(char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth)
+{
+ if (rai == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) /* 0x0a nt lm ssp */
+ return False;
+ if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) /* 0x06 */
+ return False;
+ if(!prs_uint8 ("stub_type_len", ps, depth, &rai->stub_type_len))
+ return False;
+ if(!prs_uint8 ("padding ", ps, depth, &rai->padding))
+ return False;
+
+ if(!prs_uint32("unknown ", ps, depth, &rai->unknown)) /* 0x0014a0c0 */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Checks an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+BOOL rpc_auth_verifier_chk(RPC_AUTH_VERIFIER *rav,
+ char *signature, uint32 msg_type)
+{
+ return (strequal(rav->signature, signature) && rav->msg_type == msg_type);
+}
+
+/*******************************************************************
+ Inits an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+void init_rpc_auth_verifier(RPC_AUTH_VERIFIER *rav,
+ char *signature, uint32 msg_type)
+{
+ fstrcpy(rav->signature, signature); /* "NTLMSSP" */
+ rav->msg_type = msg_type; /* NTLMSSP_MESSAGE_TYPE */
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_VERIFIER structure.
+********************************************************************/
+
+BOOL smb_io_rpc_auth_verifier(char *desc, RPC_AUTH_VERIFIER *rav, prs_struct *ps, int depth)
+{
+ if (rav == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_verifier");
+ depth++;
+
+ /* "NTLMSSP" */
+ if(!prs_string("signature", ps, depth, rav->signature, strlen("NTLMSSP"),
+ sizeof(rav->signature)))
+ return False;
+ if(!prs_uint32("msg_type ", ps, depth, &rav->msg_type)) /* NTLMSSP_MESSAGE_TYPE */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_AUTH_NTLMSSP_NEG structure.
+********************************************************************/
+
+void init_rpc_auth_ntlmssp_neg(RPC_AUTH_NTLMSSP_NEG *neg,
+ uint32 neg_flgs,
+ fstring myname, fstring domain)
+{
+ int len_myname = strlen(myname);
+ int len_domain = strlen(domain);
+
+ neg->neg_flgs = neg_flgs ; /* 0x00b2b3 */
+
+ init_str_hdr(&neg->hdr_domain, len_domain, len_domain, 0x20 + len_myname);
+ init_str_hdr(&neg->hdr_myname, len_myname, len_myname, 0x20);
+
+ fstrcpy(neg->myname, myname);
+ fstrcpy(neg->domain, domain);
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_NTLMSSP_NEG structure.
+
+ *** lkclXXXX HACK ALERT! ***
+********************************************************************/
+
+BOOL smb_io_rpc_auth_ntlmssp_neg(char *desc, RPC_AUTH_NTLMSSP_NEG *neg, prs_struct *ps, int depth)
+{
+ uint32 start_offset = prs_offset(ps);
+ if (neg == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_neg");
+ depth++;
+
+ if(!prs_uint32("neg_flgs ", ps, depth, &neg->neg_flgs))
+ return False;
+
+ if (ps->io) {
+ uint32 old_offset;
+ uint32 old_neg_flags = neg->neg_flgs;
+
+ /* reading */
+
+ ZERO_STRUCTP(neg);
+
+ neg->neg_flgs = old_neg_flags;
+
+ if(!smb_io_strhdr("hdr_domain", &neg->hdr_domain, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_myname", &neg->hdr_myname, ps, depth))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ if(!prs_set_offset(ps, neg->hdr_myname.buffer + start_offset - 12))
+ return False;
+
+ if(!prs_uint8s(True, "myname", ps, depth, (uint8*)neg->myname,
+ MIN(neg->hdr_myname.str_str_len, sizeof(neg->myname))))
+ return False;
+
+ old_offset += neg->hdr_myname.str_str_len;
+
+ if(!prs_set_offset(ps, neg->hdr_domain.buffer + start_offset - 12))
+ return False;
+
+ if(!prs_uint8s(True, "domain", ps, depth, (uint8*)neg->domain,
+ MIN(neg->hdr_domain.str_str_len, sizeof(neg->domain ))))
+ return False;
+
+ old_offset += neg->hdr_domain .str_str_len;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ } else {
+ /* writing */
+ if(!smb_io_strhdr("hdr_domain", &neg->hdr_domain, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_myname", &neg->hdr_myname, ps, depth))
+ return False;
+
+ if(!prs_uint8s(True, "myname", ps, depth, (uint8*)neg->myname,
+ MIN(neg->hdr_myname.str_str_len, sizeof(neg->myname))))
+ return False;
+ if(!prs_uint8s(True, "domain", ps, depth, (uint8*)neg->domain,
+ MIN(neg->hdr_domain.str_str_len, sizeof(neg->domain ))))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+creates an RPC_AUTH_NTLMSSP_CHAL structure.
+********************************************************************/
+
+void init_rpc_auth_ntlmssp_chal(RPC_AUTH_NTLMSSP_CHAL *chl,
+ uint32 neg_flags,
+ uint8 challenge[8])
+{
+ chl->unknown_1 = 0x0;
+ chl->unknown_2 = 0x00000028;
+ chl->neg_flags = neg_flags; /* 0x0082b1 */
+
+ memcpy(chl->challenge, challenge, sizeof(chl->challenge));
+ memset((char *)chl->reserved , '\0', sizeof(chl->reserved));
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_NTLMSSP_CHAL structure.
+********************************************************************/
+
+BOOL smb_io_rpc_auth_ntlmssp_chal(char *desc, RPC_AUTH_NTLMSSP_CHAL *chl, prs_struct *ps, int depth)
+{
+ if (chl == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_chal");
+ depth++;
+
+ if(!prs_uint32("unknown_1", ps, depth, &chl->unknown_1)) /* 0x0000 0000 */
+ return False;
+ if(!prs_uint32("unknown_2", ps, depth, &chl->unknown_2)) /* 0x0000 b2b3 */
+ return False;
+ if(!prs_uint32("neg_flags", ps, depth, &chl->neg_flags)) /* 0x0000 82b1 */
+ return False;
+
+ if(!prs_uint8s (False, "challenge", ps, depth, chl->challenge, sizeof(chl->challenge)))
+ return False;
+ if(!prs_uint8s (False, "reserved ", ps, depth, chl->reserved , sizeof(chl->reserved )))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_AUTH_NTLMSSP_RESP structure.
+
+ *** lkclXXXX FUDGE! HAVE TO MANUALLY SPECIFY OFFSET HERE (0x1c bytes) ***
+ *** lkclXXXX the actual offset is at the start of the auth verifier ***
+********************************************************************/
+
+void init_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp,
+ uchar lm_resp[24], uchar nt_resp[24],
+ char *domain, char *user, char *wks,
+ uint32 neg_flags)
+{
+ uint32 offset;
+ int dom_len = strlen(domain);
+ int wks_len = strlen(wks);
+ int usr_len = strlen(user);
+ int lm_len = (lm_resp != NULL) ? 24 : 0;
+ int nt_len = (nt_resp != NULL) ? 24 : 0;
+
+ DEBUG(5,("make_rpc_auth_ntlmssp_resp\n"));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm_resp\n"));
+ dump_data(100, (char *)lm_resp, 24);
+ DEBUG(100,("nt_resp\n"));
+ dump_data(100, (char *)nt_resp, 24);
+#endif
+
+ DEBUG(6,("dom: %s user: %s wks: %s neg_flgs: 0x%x\n",
+ domain, user, wks, neg_flags));
+
+ offset = 0x40;
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ dom_len *= 2;
+ wks_len *= 2;
+ usr_len *= 2;
+ }
+
+ init_str_hdr(&rsp->hdr_domain, dom_len, dom_len, offset);
+ offset += dom_len;
+
+ init_str_hdr(&rsp->hdr_usr, usr_len, usr_len, offset);
+ offset += usr_len;
+
+ init_str_hdr(&rsp->hdr_wks, wks_len, wks_len, offset);
+ offset += wks_len;
+
+ init_str_hdr(&rsp->hdr_lm_resp, lm_len, lm_len, offset);
+ offset += lm_len;
+
+ init_str_hdr(&rsp->hdr_nt_resp, nt_len, nt_len, offset);
+ offset += nt_len;
+
+ init_str_hdr(&rsp->hdr_sess_key, 0, 0, offset);
+
+ rsp->neg_flags = neg_flags;
+
+ memcpy(rsp->lm_resp, lm_resp, 24);
+ memcpy(rsp->nt_resp, nt_resp, 24);
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ rpcstr_push(rsp->domain, domain, sizeof(rsp->domain), 0);
+ rpcstr_push(rsp->user, user, sizeof(rsp->user), 0);
+ rpcstr_push(rsp->wks, wks, sizeof(rsp->wks), 0);
+ } else {
+ fstrcpy(rsp->domain, domain);
+ fstrcpy(rsp->user, user);
+ fstrcpy(rsp->wks, wks);
+ }
+
+ rsp->sess_key[0] = 0;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_NTLMSSP_RESP structure.
+
+ *** lkclXXXX FUDGE! HAVE TO MANUALLY SPECIFY OFFSET HERE (0x1c bytes) ***
+ *** lkclXXXX the actual offset is at the start of the auth verifier ***
+********************************************************************/
+
+BOOL smb_io_rpc_auth_ntlmssp_resp(char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_struct *ps, int depth)
+{
+ if (rsp == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_resp");
+ depth++;
+
+ if (ps->io) {
+ uint32 old_offset;
+
+ /* reading */
+
+ ZERO_STRUCTP(rsp);
+
+ if(!smb_io_strhdr("hdr_lm_resp ", &rsp->hdr_lm_resp, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_nt_resp ", &rsp->hdr_nt_resp, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_domain ", &rsp->hdr_domain, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_user ", &rsp->hdr_usr, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_wks ", &rsp->hdr_wks, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_sess_key", &rsp->hdr_sess_key, ps, depth))
+ return False;
+
+ if(!prs_uint32("neg_flags", ps, depth, &rsp->neg_flags)) /* 0x0000 82b1 */
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ if(!prs_set_offset(ps, rsp->hdr_domain.buffer + 0xc))
+ return False;
+
+ if(!prs_uint8s(True , "domain ", ps, depth, (uint8*)rsp->domain,
+ MIN(rsp->hdr_domain.str_str_len, sizeof(rsp->domain))))
+ return False;
+
+ old_offset += rsp->hdr_domain.str_str_len;
+
+ if(!prs_set_offset(ps, rsp->hdr_usr.buffer + 0xc))
+ return False;
+
+ if(!prs_uint8s(True , "user ", ps, depth, (uint8*)rsp->user,
+ MIN(rsp->hdr_usr.str_str_len, sizeof(rsp->user))))
+ return False;
+
+ old_offset += rsp->hdr_usr.str_str_len;
+
+ if(!prs_set_offset(ps, rsp->hdr_wks.buffer + 0xc))
+ return False;
+
+ if(!prs_uint8s(True, "wks ", ps, depth, (uint8*)rsp->wks,
+ MIN(rsp->hdr_wks.str_str_len, sizeof(rsp->wks))))
+ return False;
+
+ old_offset += rsp->hdr_wks.str_str_len;
+
+ if(!prs_set_offset(ps, rsp->hdr_lm_resp.buffer + 0xc))
+ return False;
+
+ if(!prs_uint8s(False, "lm_resp ", ps, depth, (uint8*)rsp->lm_resp,
+ MIN(rsp->hdr_lm_resp.str_str_len, sizeof(rsp->lm_resp ))))
+ return False;
+
+ old_offset += rsp->hdr_lm_resp.str_str_len;
+
+ if(!prs_set_offset(ps, rsp->hdr_nt_resp.buffer + 0xc))
+ return False;
+
+ if(!prs_uint8s(False, "nt_resp ", ps, depth, (uint8*)rsp->nt_resp,
+ MIN(rsp->hdr_nt_resp.str_str_len, sizeof(rsp->nt_resp ))))
+ return False;
+
+ old_offset += rsp->hdr_nt_resp.str_str_len;
+
+ if (rsp->hdr_sess_key.str_str_len != 0) {
+
+ if(!prs_set_offset(ps, rsp->hdr_sess_key.buffer + 0x10))
+ return False;
+
+ old_offset += rsp->hdr_sess_key.str_str_len;
+
+ if(!prs_uint8s(False, "sess_key", ps, depth, (uint8*)rsp->sess_key,
+ MIN(rsp->hdr_sess_key.str_str_len, sizeof(rsp->sess_key))))
+ return False;
+ }
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ } else {
+ /* writing */
+ if(!smb_io_strhdr("hdr_lm_resp ", &rsp->hdr_lm_resp, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_nt_resp ", &rsp->hdr_nt_resp, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_domain ", &rsp->hdr_domain, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_user ", &rsp->hdr_usr, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_wks ", &rsp->hdr_wks, ps, depth))
+ return False;
+ if(!smb_io_strhdr("hdr_sess_key", &rsp->hdr_sess_key, ps, depth))
+ return False;
+
+ if(!prs_uint32("neg_flags", ps, depth, &rsp->neg_flags)) /* 0x0000 82b1 */
+ return False;
+
+ if(!prs_uint8s(True , "domain ", ps, depth, (uint8*)rsp->domain,
+ MIN(rsp->hdr_domain.str_str_len, sizeof(rsp->domain))))
+ return False;
+
+ if(!prs_uint8s(True , "user ", ps, depth, (uint8*)rsp->user,
+ MIN(rsp->hdr_usr.str_str_len, sizeof(rsp->user))))
+ return False;
+
+ if(!prs_uint8s(True , "wks ", ps, depth, (uint8*)rsp->wks,
+ MIN(rsp->hdr_wks.str_str_len, sizeof(rsp->wks))))
+ return False;
+ if(!prs_uint8s(False, "lm_resp ", ps, depth, (uint8*)rsp->lm_resp,
+ MIN(rsp->hdr_lm_resp .str_str_len, sizeof(rsp->lm_resp))))
+ return False;
+ if(!prs_uint8s(False, "nt_resp ", ps, depth, (uint8*)rsp->nt_resp,
+ MIN(rsp->hdr_nt_resp .str_str_len, sizeof(rsp->nt_resp ))))
+ return False;
+ if(!prs_uint8s(False, "sess_key", ps, depth, (uint8*)rsp->sess_key,
+ MIN(rsp->hdr_sess_key.str_str_len, sizeof(rsp->sess_key))))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Checks an RPC_AUTH_NTLMSSP_CHK structure.
+********************************************************************/
+
+BOOL rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 crc32, uint32 seq_num)
+{
+ if (chk == NULL)
+ return False;
+
+ if (chk->crc32 != crc32 ||
+ chk->ver != NTLMSSP_SIGN_VERSION ||
+ chk->seq_num != seq_num)
+ {
+ DEBUG(5,("verify failed - crc %x ver %x seq %d\n",
+ crc32, NTLMSSP_SIGN_VERSION, seq_num));
+ DEBUG(5,("verify expect - crc %x ver %x seq %d\n",
+ chk->crc32, chk->ver, chk->seq_num));
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Inits an RPC_AUTH_NTLMSSP_CHK structure.
+********************************************************************/
+
+void init_rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk,
+ uint32 ver, uint32 crc32, uint32 seq_num)
+{
+ chk->ver = ver;
+ chk->reserved = 0x0;
+ chk->crc32 = crc32;
+ chk->seq_num = seq_num;
+}
+
+/*******************************************************************
+ Reads or writes an RPC_AUTH_NTLMSSP_CHK structure.
+********************************************************************/
+
+BOOL smb_io_rpc_auth_ntlmssp_chk(char *desc, RPC_AUTH_NTLMSSP_CHK *chk, prs_struct *ps, int depth)
+{
+ if (chk == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_chk");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ver ", ps, depth, &chk->ver))
+ return False;
+ if(!prs_uint32("reserved", ps, depth, &chk->reserved))
+ return False;
+ if(!prs_uint32("crc32 ", ps, depth, &chk->crc32))
+ return False;
+ if(!prs_uint32("seq_num ", ps, depth, &chk->seq_num))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c
new file mode 100644
index 00000000000..bfca4958933
--- /dev/null
+++ b/source/rpc_parse/parse_samr.c
@@ -0,0 +1,7218 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Paul Ashton 1997-2000,
+ * Copyright (C) Elrond 2000,
+ * Copyright (C) Jeremy Allison 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "rpc_parse.h"
+#include "nterr.h"
+
+/*******************************************************************
+inits a SAMR_Q_CLOSE_HND structure.
+********************************************************************/
+
+void init_samr_q_close_hnd(SAMR_Q_CLOSE_HND * q_c, POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_close_hnd\n"));
+
+ q_c->pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_close_hnd(char *desc, SAMR_Q_CLOSE_HND * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_close_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ return smb_io_pol_hnd("pol", &q_u->pol, ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_close_hnd(char *desc, SAMR_R_CLOSE_HND * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_close_hnd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_LOOKUP_DOMAIN structure.
+********************************************************************/
+
+void init_samr_q_lookup_domain(SAMR_Q_LOOKUP_DOMAIN * q_u,
+ POLICY_HND *pol, char *dom_name)
+{
+ int len_name = strlen(dom_name);
+
+ DEBUG(5, ("init_samr_q_lookup_domain\n"));
+
+ q_u->connect_pol = *pol;
+
+ init_uni_hdr(&q_u->hdr_domain, len_name);
+ init_unistr2(&q_u->uni_domain, dom_name, len_name);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+BOOL samr_io_q_lookup_domain(char *desc, SAMR_Q_LOOKUP_DOMAIN * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_lookup_domain");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("connect_pol", &q_u->connect_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_domain", &q_u->hdr_domain, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_domain", &q_u->uni_domain, q_u->hdr_domain.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_LOOKUP_DOMAIN structure.
+********************************************************************/
+
+void init_samr_r_lookup_domain(SAMR_R_LOOKUP_DOMAIN * r_u,
+ DOM_SID *dom_sid, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_lookup_domain\n"));
+
+ r_u->status = status;
+ r_u->ptr_sid = 0;
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->ptr_sid = 1;
+ init_dom_sid2(&r_u->dom_sid, dom_sid);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_lookup_domain(char *desc, SAMR_R_LOOKUP_DOMAIN * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_lookup_domain");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr_sid))
+ return False;
+
+ if (r_u->ptr_sid != 0) {
+ if(!smb_io_dom_sid2("sid", &r_u->dom_sid, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_unknown_2d(SAMR_Q_UNKNOWN_2D * q_u, POLICY_HND *dom_pol, DOM_SID *sid)
+{
+ DEBUG(5, ("samr_init_samr_q_unknown_2d\n"));
+
+ q_u->dom_pol = *dom_pol;
+ init_dom_sid2(&q_u->sid, sid);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_unknown_2d(char *desc, SAMR_Q_UNKNOWN_2D * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_2d");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->dom_pol, ps, depth))
+ return False;
+
+ if(!smb_io_dom_sid2("sid", &q_u->sid, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_unknown_2d(char *desc, SAMR_R_UNKNOWN_2D * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_2d");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_open_domain(SAMR_Q_OPEN_DOMAIN * q_u,
+ POLICY_HND *pol, uint32 flags,
+ const DOM_SID *sid)
+{
+ DEBUG(5, ("samr_init_samr_q_open_domain\n"));
+
+ q_u->pol = *pol;
+ q_u->flags = flags;
+ init_dom_sid2(&q_u->dom_sid, sid);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_open_domain(char *desc, SAMR_Q_OPEN_DOMAIN * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_domain");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("flags", ps, depth, &q_u->flags))
+ return False;
+
+ if(!smb_io_dom_sid2("sid", &q_u->dom_sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_open_domain(char *desc, SAMR_R_OPEN_DOMAIN * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_domain");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &r_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_get_usrdom_pwinfo(SAMR_Q_GET_USRDOM_PWINFO * q_u,
+ POLICY_HND *user_pol)
+{
+ DEBUG(5, ("samr_init_samr_q_get_usrdom_pwinfo\n"));
+
+ q_u->user_pol = *user_pol;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_get_usrdom_pwinfo(char *desc, SAMR_Q_GET_USRDOM_PWINFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_get_usrdom_pwinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ return smb_io_pol_hnd("user_pol", &q_u->user_pol, ps, depth);
+}
+
+/*******************************************************************
+ Init.
+********************************************************************/
+
+void init_samr_r_get_usrdom_pwinfo(SAMR_R_GET_USRDOM_PWINFO *r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_get_usrdom_pwinfo\n"));
+
+ r_u->unknown_0 = 0x0000;
+
+ /*
+ * used to be
+ * r_u->unknown_1 = 0x0015;
+ * but for trusts.
+ */
+ r_u->unknown_1 = 0x01D1;
+ r_u->unknown_1 = 0x0015;
+
+ r_u->unknown_2 = 0x00000000;
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_get_usrdom_pwinfo(char *desc, SAMR_R_GET_USRDOM_PWINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_get_usrdom_pwinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("unknown_0", ps, depth, &r_u->unknown_0))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &r_u->unknown_1))
+ return False;
+ if(!prs_uint32("unknown_2", ps, depth, &r_u->unknown_2))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_query_sec_obj(SAMR_Q_QUERY_SEC_OBJ * q_u,
+ POLICY_HND *user_pol, uint32 sec_info)
+{
+ DEBUG(5, ("samr_init_samr_q_query_sec_obj\n"));
+
+ q_u->user_pol = *user_pol;
+ q_u->sec_info = sec_info;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_sec_obj(char *desc, SAMR_Q_QUERY_SEC_OBJ * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_sec_obj");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("user_pol", &q_u->user_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("sec_info", ps, depth, &q_u->sec_info))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_query_dom_info(SAMR_Q_QUERY_DOMAIN_INFO * q_u,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ DEBUG(5, ("samr_init_samr_q_query_dom_info\n"));
+
+ q_u->domain_pol = *domain_pol;
+ q_u->switch_value = switch_value;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_dom_info(char *desc, SAMR_Q_QUERY_DOMAIN_INFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_dom_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+
+void init_unk_info3(SAM_UNK_INFO_3 *u_3, NTTIME nt_logout)
+{
+ u_3->logout.low = nt_logout.low;
+ u_3->logout.high = nt_logout.high;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info3(char *desc, SAM_UNK_INFO_3 * u_3,
+ prs_struct *ps, int depth)
+{
+ if (u_3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info3");
+ depth++;
+
+ if(!smb_io_time("logout", &u_3->logout, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+
+void init_unk_info6(SAM_UNK_INFO_6 * u_6)
+{
+ u_6->unknown_0 = 0x00000000;
+ u_6->ptr_0 = 1;
+ memset(u_6->padding, 0, sizeof(u_6->padding)); /* 12 bytes zeros */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info6(char *desc, SAM_UNK_INFO_6 * u_6,
+ prs_struct *ps, int depth)
+{
+ if (u_6 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info6");
+ depth++;
+
+ if(!prs_uint32("unknown_0", ps, depth, &u_6->unknown_0)) /* 0x0000 0000 */
+ return False;
+ if(!prs_uint32("ptr_0", ps, depth, &u_6->ptr_0)) /* pointer to unknown structure */
+ return False;
+ if(!prs_uint8s(False, "padding", ps, depth, u_6->padding, sizeof(u_6->padding))) /* 12 bytes zeros */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+
+void init_unk_info7(SAM_UNK_INFO_7 * u_7)
+{
+ u_7->unknown_0 = 0x0003;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info7(char *desc, SAM_UNK_INFO_7 * u_7,
+ prs_struct *ps, int depth)
+{
+ if (u_7 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info7");
+ depth++;
+
+ if(!prs_uint16("unknown_0", ps, depth, &u_7->unknown_0)) /* 0x0003 */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+
+void init_unk_info12(SAM_UNK_INFO_12 * u_12, NTTIME nt_lock_duration, NTTIME nt_reset_time, uint16 lockout)
+{
+ u_12->duration.low = nt_lock_duration.low;
+ u_12->duration.high = nt_lock_duration.high;
+ u_12->reset_count.low = nt_reset_time.low;
+ u_12->reset_count.high = nt_reset_time.high;
+
+ u_12->bad_attempt_lockout = lockout;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info12(char *desc, SAM_UNK_INFO_12 * u_12,
+ prs_struct *ps, int depth)
+{
+ if (u_12 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info12");
+ depth++;
+
+ if(!smb_io_time("duration", &u_12->duration, ps, depth))
+ return False;
+ if(!smb_io_time("reset_count", &u_12->reset_count, ps, depth))
+ return False;
+ if(!prs_uint16("bad_attempt_lockout", ps, depth, &u_12->bad_attempt_lockout))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+void init_unk_info5(SAM_UNK_INFO_5 * u_5,char *server)
+{
+ int len_server = strlen(server);
+
+ init_uni_hdr(&u_5->hdr_server, len_server);
+
+ init_unistr2(&u_5->uni_server, server, len_server);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info5(char *desc, SAM_UNK_INFO_5 * u_5,
+ prs_struct *ps, int depth)
+{
+ if (u_5 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info5");
+ depth++;
+
+ if(!smb_io_unihdr("hdr_server", &u_5->hdr_server, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_server", &u_5->uni_server, u_5->hdr_server.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+void init_unk_info2(SAM_UNK_INFO_2 * u_2,
+ char *domain, char *server,
+ uint32 seq_num)
+{
+ int len_domain = strlen(domain);
+ int len_server = strlen(server);
+
+ u_2->unknown_0 = 0x00000000;
+ u_2->unknown_1 = 0x80000000;
+ u_2->unknown_2 = 0x00000000;
+
+ u_2->ptr_0 = 1;
+ init_uni_hdr(&u_2->hdr_domain, len_domain);
+ init_uni_hdr(&u_2->hdr_server, len_server);
+
+ u_2->seq_num = seq_num;
+ u_2->unknown_3 = 0x00000000;
+
+ u_2->unknown_4 = 0x00000001;
+ u_2->unknown_5 = 0x00000003;
+ u_2->unknown_6 = 0x00000001;
+ u_2->num_domain_usrs = MAX_SAM_ENTRIES;
+ u_2->num_domain_grps = MAX_SAM_ENTRIES;
+ u_2->num_local_grps = MAX_SAM_ENTRIES;
+
+ memset(u_2->padding, 0, sizeof(u_2->padding)); /* 12 bytes zeros */
+
+ init_unistr2(&u_2->uni_domain, domain, len_domain);
+ init_unistr2(&u_2->uni_server, server, len_server);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info2(char *desc, SAM_UNK_INFO_2 * u_2,
+ prs_struct *ps, int depth)
+{
+ if (u_2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info2");
+ depth++;
+
+ if(!prs_uint32("unknown_0", ps, depth, &u_2->unknown_0)) /* 0x0000 0000 */
+ return False;
+ if(!prs_uint32("unknown_1", ps, depth, &u_2->unknown_1)) /* 0x8000 0000 */
+ return False;
+ if(!prs_uint32("unknown_2", ps, depth, &u_2->unknown_2)) /* 0x0000 0000 */
+ return False;
+
+ if(!prs_uint32("ptr_0", ps, depth, &u_2->ptr_0))
+ return False;
+ if(!smb_io_unihdr("hdr_domain", &u_2->hdr_domain, ps, depth))
+ return False;
+ if(!smb_io_unihdr("hdr_server", &u_2->hdr_server, ps, depth))
+ return False;
+
+ /* put all the data in here, at the moment, including what the above
+ pointer is referring to
+ */
+
+ if(!prs_uint32("seq_num ", ps, depth, &u_2->seq_num)) /* 0x0000 0099 or 0x1000 0000 */
+ return False;
+ if(!prs_uint32("unknown_3 ", ps, depth, &u_2->unknown_3)) /* 0x0000 0000 */
+ return False;
+
+ if(!prs_uint32("unknown_4 ", ps, depth, &u_2->unknown_4)) /* 0x0000 0001 */
+ return False;
+ if(!prs_uint32("unknown_5 ", ps, depth, &u_2->unknown_5)) /* 0x0000 0003 */
+ return False;
+ if(!prs_uint32("unknown_6 ", ps, depth, &u_2->unknown_6)) /* 0x0000 0001 */
+ return False;
+ if(!prs_uint32("num_domain_usrs ", ps, depth, &u_2->num_domain_usrs))
+ return False;
+ if(!prs_uint32("num_domain_grps", ps, depth, &u_2->num_domain_grps))
+ return False;
+ if(!prs_uint32("num_local_grps", ps, depth, &u_2->num_local_grps))
+ return False;
+
+ if(!prs_uint8s(False, "padding", ps, depth, u_2->padding,sizeof(u_2->padding)))
+ return False;
+
+ if(!smb_io_unistr2("uni_domain", &u_2->uni_domain, u_2->hdr_domain.buffer, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_server", &u_2->uni_server, u_2->hdr_server.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a structure.
+********************************************************************/
+
+void init_unk_info1(SAM_UNK_INFO_1 *u_1, uint16 min_pass_len, uint16 pass_hist,
+ uint32 flag, NTTIME nt_expire, NTTIME nt_min_age)
+{
+ u_1->min_length_password = min_pass_len;
+ u_1->password_history = pass_hist;
+ u_1->flag = flag;
+
+ /* password never expire */
+ u_1->expire.high = nt_expire.high;
+ u_1->expire.low = nt_expire.low;
+
+ /* can change the password now */
+ u_1->min_passwordage.high = nt_min_age.high;
+ u_1->min_passwordage.low = nt_min_age.low;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_unk_info1(char *desc, SAM_UNK_INFO_1 * u_1,
+ prs_struct *ps, int depth)
+{
+ if (u_1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_unk_info1");
+ depth++;
+
+ if(!prs_uint16("min_length_password", ps, depth, &u_1->min_length_password))
+ return False;
+ if(!prs_uint16("password_history", ps, depth, &u_1->password_history))
+ return False;
+ if(!prs_uint32("flag", ps, depth, &u_1->flag))
+ return False;
+ if(!smb_io_time("expire", &u_1->expire, ps, depth))
+ return False;
+ if(!smb_io_time("min_passwordage", &u_1->min_passwordage, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_DOMAIN_INFO structure.
+********************************************************************/
+
+void init_samr_r_query_dom_info(SAMR_R_QUERY_DOMAIN_INFO * r_u,
+ uint16 switch_value, SAM_UNK_CTR * ctr,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_dom_info\n"));
+
+ r_u->ptr_0 = 0;
+ r_u->switch_value = 0;
+ r_u->status = status; /* return status */
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->switch_value = switch_value;
+ r_u->ptr_0 = 1;
+ r_u->ctr = ctr;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_dom_info(char *desc, SAMR_R_QUERY_DOMAIN_INFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_dom_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_0 ", ps, depth, &r_u->ptr_0))
+ return False;
+
+ if (r_u->ptr_0 != 0 && r_u->ctr != NULL) {
+ if(!prs_uint16("switch_value", ps, depth, &r_u->switch_value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ switch (r_u->switch_value) {
+ case 0x0c:
+ if(!sam_io_unk_info12("unk_inf12", &r_u->ctr->info.inf12, ps, depth))
+ return False;
+ break;
+ case 0x07:
+ if(!sam_io_unk_info7("unk_inf7",&r_u->ctr->info.inf7, ps,depth))
+ return False;
+ break;
+ case 0x06:
+ if(!sam_io_unk_info6("unk_inf6",&r_u->ctr->info.inf6, ps,depth))
+ return False;
+ break;
+ case 0x05:
+ if(!sam_io_unk_info5("unk_inf5",&r_u->ctr->info.inf5, ps,depth))
+ return False;
+ break;
+ case 0x03:
+ if(!sam_io_unk_info3("unk_inf3",&r_u->ctr->info.inf3, ps,depth))
+ return False;
+ break;
+ case 0x02:
+ if(!sam_io_unk_info2("unk_inf2",&r_u->ctr->info.inf2, ps,depth))
+ return False;
+ break;
+ case 0x01:
+ if(!sam_io_unk_info1("unk_inf1",&r_u->ctr->info.inf1, ps,depth))
+ return False;
+ break;
+ default:
+ DEBUG(0, ("samr_io_r_query_dom_info: unknown switch level 0x%x\n",
+ r_u->switch_value));
+ r_u->status = NT_STATUS_INVALID_INFO_CLASS;
+ return False;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a SAMR_R_QUERY_SEC_OBJ structure.
+********************************************************************/
+
+BOOL samr_io_r_query_sec_obj(char *desc, SAMR_R_QUERY_SEC_OBJ * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_sec_obj");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+ if (r_u->ptr != 0) {
+ if(!sec_io_desc_buf("sec", &r_u->buf, ps, depth))
+ return False;
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a SAM_STR1 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_str1(char *desc, SAM_STR1 * sam, uint32 acct_buf,
+ uint32 name_buf, uint32 desc_buf,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("name", &sam->uni_acct_name, acct_buf, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("desc", &sam->uni_acct_desc, desc_buf, ps, depth))
+ return False;
+
+ if (!smb_io_unistr2("full", &sam->uni_full_name, name_buf, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY1 structure.
+********************************************************************/
+
+static void init_sam_entry1(SAM_ENTRY1 * sam, uint32 user_idx,
+ uint32 len_sam_name, uint32 len_sam_full,
+ uint32 len_sam_desc, uint32 rid_user,
+ uint16 acb_info)
+{
+ DEBUG(5, ("init_sam_entry1\n"));
+
+ ZERO_STRUCTP(sam);
+
+ sam->user_idx = user_idx;
+ sam->rid_user = rid_user;
+ sam->acb_info = acb_info;
+ sam->pad = 0;
+
+ init_uni_hdr(&sam->hdr_acct_name, len_sam_name);
+ init_uni_hdr(&sam->hdr_user_name, len_sam_full);
+ init_uni_hdr(&sam->hdr_user_desc, len_sam_desc);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY1 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry1(char *desc, SAM_ENTRY1 * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("user_idx ", ps, depth, &sam->user_idx))
+ return False;
+
+ if(!prs_uint32("rid_user ", ps, depth, &sam->rid_user))
+ return False;
+ if(!prs_uint16("acb_info ", ps, depth, &sam->acb_info))
+ return False;
+ if(!prs_uint16("pad ", ps, depth, &sam->pad))
+ return False;
+
+ if (!smb_io_unihdr("hdr_acct_name", &sam->hdr_acct_name, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_user_desc", &sam->hdr_user_desc, ps, depth))
+ return False;
+ if (!smb_io_unihdr("hdr_user_name", &sam->hdr_user_name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a SAM_STR2 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_str2(char *desc, SAM_STR2 * sam, uint32 acct_buf,
+ uint32 desc_buf, prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("uni_srv_name", &sam->uni_srv_name, acct_buf, ps, depth)) /* account name unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_srv_desc", &sam->uni_srv_desc, desc_buf, ps, depth)) /* account desc unicode string */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY2 structure.
+********************************************************************/
+static void init_sam_entry2(SAM_ENTRY2 * sam, uint32 user_idx,
+ uint32 len_sam_name, uint32 len_sam_desc,
+ uint32 rid_user, uint16 acb_info)
+{
+ DEBUG(5, ("init_sam_entry2\n"));
+
+ sam->user_idx = user_idx;
+ sam->rid_user = rid_user;
+ sam->acb_info = acb_info;
+ sam->pad = 0;
+
+ init_uni_hdr(&sam->hdr_srv_name, len_sam_name);
+ init_uni_hdr(&sam->hdr_srv_desc, len_sam_desc);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY2 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry2(char *desc, SAM_ENTRY2 * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("user_idx ", ps, depth, &sam->user_idx))
+ return False;
+
+ if(!prs_uint32("rid_user ", ps, depth, &sam->rid_user))
+ return False;
+ if(!prs_uint16("acb_info ", ps, depth, &sam->acb_info))
+ return False;
+ if(!prs_uint16("pad ", ps, depth, &sam->pad))
+ return False;
+
+ if(!smb_io_unihdr("unihdr", &sam->hdr_srv_name, ps, depth)) /* account name unicode string header */
+ return False;
+ if(!smb_io_unihdr("unihdr", &sam->hdr_srv_desc, ps, depth)) /* account name unicode string header */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a SAM_STR3 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_str3(char *desc, SAM_STR3 * sam, uint32 acct_buf,
+ uint32 desc_buf, prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("uni_grp_name", &sam->uni_grp_name, acct_buf, ps, depth)) /* account name unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_grp_desc", &sam->uni_grp_desc, desc_buf, ps, depth)) /* account desc unicode string */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY3 structure.
+********************************************************************/
+
+static void init_sam_entry3(SAM_ENTRY3 * sam, uint32 grp_idx,
+ uint32 len_grp_name, uint32 len_grp_desc,
+ uint32 rid_grp)
+{
+ DEBUG(5, ("init_sam_entry3\n"));
+
+ sam->grp_idx = grp_idx;
+ sam->rid_grp = rid_grp;
+ sam->attr = 0x07; /* group rid attributes - gets ignored by nt 4.0 */
+
+ init_uni_hdr(&sam->hdr_grp_name, len_grp_name);
+ init_uni_hdr(&sam->hdr_grp_desc, len_grp_desc);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY3 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry3(char *desc, SAM_ENTRY3 * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("grp_idx", ps, depth, &sam->grp_idx))
+ return False;
+
+ if(!prs_uint32("rid_grp", ps, depth, &sam->rid_grp))
+ return False;
+ if(!prs_uint32("attr ", ps, depth, &sam->attr))
+ return False;
+
+ if(!smb_io_unihdr("unihdr", &sam->hdr_grp_name, ps, depth)) /* account name unicode string header */
+ return False;
+ if(!smb_io_unihdr("unihdr", &sam->hdr_grp_desc, ps, depth)) /* account name unicode string header */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY4 structure.
+********************************************************************/
+
+static void init_sam_entry4(SAM_ENTRY4 * sam, uint32 user_idx,
+ uint32 len_acct_name)
+{
+ DEBUG(5, ("init_sam_entry4\n"));
+
+ sam->user_idx = user_idx;
+ init_str_hdr(&sam->hdr_acct_name, len_acct_name+1, len_acct_name, len_acct_name != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY4 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry4(char *desc, SAM_ENTRY4 * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry4");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("user_idx", ps, depth, &sam->user_idx))
+ return False;
+ if(!smb_io_strhdr("strhdr", &sam->hdr_acct_name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY5 structure.
+********************************************************************/
+
+static void init_sam_entry5(SAM_ENTRY5 * sam, uint32 grp_idx,
+ uint32 len_grp_name)
+{
+ DEBUG(5, ("init_sam_entry5\n"));
+
+ sam->grp_idx = grp_idx;
+ init_str_hdr(&sam->hdr_grp_name, len_grp_name, len_grp_name,
+ len_grp_name != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY5 structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry5(char *desc, SAM_ENTRY5 * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry5");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("grp_idx", ps, depth, &sam->grp_idx))
+ return False;
+ if(!smb_io_strhdr("strhdr", &sam->hdr_grp_name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_ENTRY structure.
+********************************************************************/
+
+void init_sam_entry(SAM_ENTRY * sam, uint32 len_sam_name, uint32 rid)
+{
+ DEBUG(10, ("init_sam_entry: %d %d\n", len_sam_name, rid));
+
+ sam->rid = rid;
+ init_uni_hdr(&sam->hdr_name, len_sam_name);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY structure.
+********************************************************************/
+
+static BOOL sam_io_sam_entry(char *desc, SAM_ENTRY * sam,
+ prs_struct *ps, int depth)
+{
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("rid", ps, depth, &sam->rid))
+ return False;
+ if(!smb_io_unihdr("unihdr", &sam->hdr_name, ps, depth)) /* account name unicode string header */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ENUM_DOM_USERS structure.
+********************************************************************/
+
+void init_samr_q_enum_dom_users(SAMR_Q_ENUM_DOM_USERS * q_e, POLICY_HND *pol,
+ uint32 start_idx,
+ uint16 acb_mask, uint16 unk_1, uint32 size)
+{
+ DEBUG(5, ("init_samr_q_enum_dom_users\n"));
+
+ q_e->pol = *pol;
+
+ q_e->start_idx = start_idx; /* zero indicates lots */
+ q_e->acb_mask = acb_mask;
+ q_e->unknown_1 = unk_1;
+ q_e->max_size = size;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_enum_dom_users(char *desc, SAMR_Q_ENUM_DOM_USERS * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_users");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("start_idx", ps, depth, &q_e->start_idx))
+ return False;
+ if(!prs_uint16("acb_mask ", ps, depth, &q_e->acb_mask))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &q_e->unknown_1))
+ return False;
+
+ if(!prs_uint32("max_size ", ps, depth, &q_e->max_size))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+inits a SAMR_R_ENUM_DOM_USERS structure.
+********************************************************************/
+
+void init_samr_r_enum_dom_users(SAMR_R_ENUM_DOM_USERS * r_u,
+ uint32 next_idx, uint32 num_sam_entries)
+{
+ DEBUG(5, ("init_samr_r_enum_dom_users\n"));
+
+ r_u->next_idx = next_idx;
+
+ if (num_sam_entries != 0) {
+ r_u->ptr_entries1 = 1;
+ r_u->ptr_entries2 = 1;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->num_entries3 = num_sam_entries;
+
+ r_u->num_entries4 = num_sam_entries;
+ } else {
+ r_u->ptr_entries1 = 0;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->ptr_entries2 = 1;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_enum_dom_users(char *desc, SAMR_R_ENUM_DOM_USERS * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_users");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("next_idx ", ps, depth, &r_u->next_idx))
+ return False;
+ if(!prs_uint32("ptr_entries1", ps, depth, &r_u->ptr_entries1))
+ return False;
+
+ if (r_u->ptr_entries1 != 0) {
+ if(!prs_uint32("num_entries2", ps, depth, &r_u->num_entries2))
+ return False;
+ if(!prs_uint32("ptr_entries2", ps, depth, &r_u->ptr_entries2))
+ return False;
+ if(!prs_uint32("num_entries3", ps, depth, &r_u->num_entries3))
+ return False;
+
+ if (UNMARSHALLING(ps) && (r_u->num_entries2 != 0)) {
+ r_u->sam = (SAM_ENTRY *)prs_alloc_mem(ps,sizeof(SAM_ENTRY)*r_u->num_entries2);
+ r_u->uni_acct_name = (UNISTR2 *)prs_alloc_mem(ps,sizeof(UNISTR2)*r_u->num_entries2);
+ }
+
+ if ((r_u->sam == NULL || r_u->uni_acct_name == NULL) && r_u->num_entries2 != 0) {
+ DEBUG(0,("NULL pointers in SAMR_R_ENUM_DOM_USERS\n"));
+ r_u->num_entries4 = 0;
+ r_u->status = NT_STATUS_MEMORY_NOT_ALLOCATED;
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!sam_io_sam_entry("", &r_u->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!smb_io_unistr2("", &r_u->uni_acct_name[i],r_u->sam[i].hdr_name.buffer, ps,depth))
+ return False;
+ }
+
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries4", ps, depth, &r_u->num_entries4))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_DISPINFO structure.
+********************************************************************/
+
+void init_samr_q_query_dispinfo(SAMR_Q_QUERY_DISPINFO * q_e, POLICY_HND *pol,
+ uint16 switch_level, uint32 start_idx,
+ uint32 max_entries)
+{
+ DEBUG(5, ("init_samr_q_query_dispinfo\n"));
+
+ q_e->domain_pol = *pol;
+
+ q_e->switch_level = switch_level;
+
+ q_e->start_idx = start_idx;
+ q_e->max_entries = max_entries;
+ q_e->max_size = 0xffff; /* Not especially useful */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_dispinfo(char *desc, SAMR_Q_QUERY_DISPINFO * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_dispinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_e->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_level", ps, depth, &q_e->switch_level))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("start_idx ", ps, depth, &q_e->start_idx))
+ return False;
+ if(!prs_uint32("max_entries ", ps, depth, &q_e->max_entries))
+ return False;
+ if(!prs_uint32("max_size ", ps, depth, &q_e->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_DISPINFO_1 structure.
+********************************************************************/
+
+NTSTATUS init_sam_dispinfo_1(TALLOC_CTX *ctx, SAM_DISPINFO_1 *sam, uint32 *num_entries,
+ uint32 *data_size, uint32 start_idx,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+{
+ uint32 len_sam_name, len_sam_full, len_sam_desc;
+ uint32 max_entries, max_data_size;
+ uint32 dsize = 0;
+ uint32 i;
+
+ ZERO_STRUCTP(sam);
+
+ max_entries = *num_entries;
+ max_data_size = *data_size;
+
+ DEBUG(5, ("init_sam_dispinfo_1: max_entries: %d max_dsize: 0x%x\n",
+ max_entries, max_data_size));
+
+ if (max_entries==0)
+ return NT_STATUS_OK;
+
+ sam->sam=(SAM_ENTRY1 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY1));
+ if (!sam->sam)
+ return NT_STATUS_NO_MEMORY;
+
+ sam->str=(SAM_STR1 *)talloc(ctx, max_entries*sizeof(SAM_STR1));
+ if (!sam->str)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(sam->sam);
+ ZERO_STRUCTP(sam->str);
+
+ for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+ DEBUG(5, ("init_sam_dispinfo_1: entry: %d\n",i));
+ len_sam_name = pass[i].uni_user_name.uni_str_len;
+ len_sam_full = pass[i].uni_full_name.uni_str_len;
+ len_sam_desc = pass[i].uni_acct_desc.uni_str_len;
+
+ init_sam_entry1(&sam->sam[i], start_idx + i + 1,
+ len_sam_name, len_sam_full, len_sam_desc,
+ pass[i].user_rid, pass[i].acb_info);
+
+ ZERO_STRUCTP(&sam->str[i].uni_acct_name);
+ ZERO_STRUCTP(&sam->str[i].uni_full_name);
+ ZERO_STRUCTP(&sam->str[i].uni_acct_desc);
+
+ copy_unistr2(&sam->str[i].uni_acct_name, &pass[i].uni_user_name);
+ copy_unistr2(&sam->str[i].uni_full_name, &pass[i].uni_full_name);
+ copy_unistr2(&sam->str[i].uni_acct_desc, &pass[i].uni_acct_desc);
+
+ dsize += sizeof(SAM_ENTRY1);
+ dsize += len_sam_name + len_sam_full + len_sam_desc;
+ }
+
+ *num_entries = i;
+ *data_size = dsize;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_sam_dispinfo_1(char *desc, SAM_DISPINFO_1 * sam,
+ uint32 num_entries,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_dispinfo_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (UNMARSHALLING(ps) && num_entries > 0) {
+
+ if ((sam->sam = (SAM_ENTRY1 *)
+ prs_alloc_mem(ps, sizeof(SAM_ENTRY1) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_ENTRY1\n"));
+ return False;
+ }
+
+ if ((sam->str = (SAM_STR1 *)
+ prs_alloc_mem(ps, sizeof(SAM_STR1) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_STR1\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_entry1("", &sam->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_str1("", &sam->str[i],
+ sam->sam[i].hdr_acct_name.buffer,
+ sam->sam[i].hdr_user_name.buffer,
+ sam->sam[i].hdr_user_desc.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_DISPINFO_2 structure.
+********************************************************************/
+
+NTSTATUS init_sam_dispinfo_2(TALLOC_CTX *ctx, SAM_DISPINFO_2 *sam, uint32 *num_entries,
+ uint32 *data_size, uint32 start_idx,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+{
+ uint32 len_sam_name, len_sam_desc;
+ uint32 max_entries, max_data_size;
+ uint32 dsize = 0;
+ uint32 i;
+
+ DEBUG(5, ("init_sam_dispinfo_2\n"));
+
+ ZERO_STRUCTP(sam);
+
+ max_entries = *num_entries;
+ max_data_size = *data_size;
+
+ if (max_entries==0)
+ return NT_STATUS_OK;
+
+ if (!(sam->sam=(SAM_ENTRY2 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY2))))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(sam->str=(SAM_STR2 *)talloc(ctx, max_entries*sizeof(SAM_STR2))))
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(sam->sam);
+ ZERO_STRUCTP(sam->str);
+
+ for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+ len_sam_name = pass[i].uni_user_name.uni_str_len;
+ len_sam_desc = pass[i].uni_acct_desc.uni_str_len;
+
+ init_sam_entry2(&sam->sam[i], start_idx + i + 1,
+ len_sam_name, len_sam_desc,
+ pass[i].user_rid, pass[i].acb_info);
+
+ ZERO_STRUCTP(&sam->str[i].uni_srv_name);
+ ZERO_STRUCTP(&sam->str[i].uni_srv_desc);
+
+ copy_unistr2(&sam->str[i].uni_srv_name, &pass[i].uni_user_name);
+ copy_unistr2(&sam->str[i].uni_srv_desc, &pass[i].uni_acct_desc);
+
+ dsize += sizeof(SAM_ENTRY2);
+ dsize += len_sam_name + len_sam_desc;
+ }
+
+ *num_entries = i;
+ *data_size = dsize;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_sam_dispinfo_2(char *desc, SAM_DISPINFO_2 * sam,
+ uint32 num_entries,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_dispinfo_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (UNMARSHALLING(ps) && num_entries > 0) {
+
+ if ((sam->sam = (SAM_ENTRY2 *)
+ prs_alloc_mem(ps, sizeof(SAM_ENTRY2) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_ENTRY2\n"));
+ return False;
+ }
+
+ if ((sam->str = (SAM_STR2 *)
+ prs_alloc_mem(ps, sizeof(SAM_STR2) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_STR2\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_entry2("", &sam->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_str2("", &sam->str[i],
+ sam->sam[i].hdr_srv_name.buffer,
+ sam->sam[i].hdr_srv_desc.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_DISPINFO_3 structure.
+********************************************************************/
+
+NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 *sam, uint32 *num_entries,
+ uint32 *data_size, uint32 start_idx,
+ DOMAIN_GRP * grp)
+{
+ uint32 len_sam_name, len_sam_desc;
+ uint32 max_entries, max_data_size;
+ uint32 dsize = 0;
+ uint32 i;
+
+ DEBUG(5, ("init_sam_dispinfo_3\n"));
+
+ ZERO_STRUCTP(sam);
+
+ max_entries = *num_entries;
+ max_data_size = *data_size;
+
+ if (max_entries==0)
+ return NT_STATUS_OK;
+
+ if (!(sam->sam=(SAM_ENTRY3 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY3))))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(sam->str=(SAM_STR3 *)talloc(ctx, max_entries*sizeof(SAM_STR3))))
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(sam->sam);
+ ZERO_STRUCTP(sam->str);
+
+ for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+ len_sam_name = strlen(grp[i].name);
+ len_sam_desc = strlen(grp[i].comment);
+
+ init_sam_entry3(&sam->sam[i], start_idx + i + 1, len_sam_name, len_sam_desc, grp[i].rid);
+
+ init_unistr2(&sam->str[i].uni_grp_name, grp[i].name, len_sam_name);
+ init_unistr2(&sam->str[i].uni_grp_desc, grp[i].comment, len_sam_desc);
+
+ dsize += sizeof(SAM_ENTRY3);
+ dsize += (len_sam_name + len_sam_desc) * 2;
+ dsize += 14;
+ }
+
+ *num_entries = i;
+ *data_size = dsize;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_sam_dispinfo_3(char *desc, SAM_DISPINFO_3 * sam,
+ uint32 num_entries,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_dispinfo_3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (UNMARSHALLING(ps) && num_entries > 0) {
+
+ if ((sam->sam = (SAM_ENTRY3 *)
+ prs_alloc_mem(ps, sizeof(SAM_ENTRY3) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_ENTRY3\n"));
+ return False;
+ }
+
+ if ((sam->str = (SAM_STR3 *)
+ prs_alloc_mem(ps, sizeof(SAM_STR3) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_STR3\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_entry3("", &sam->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_str3("", &sam->str[i],
+ sam->sam[i].hdr_grp_name.buffer,
+ sam->sam[i].hdr_grp_desc.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_DISPINFO_4 structure.
+********************************************************************/
+
+NTSTATUS init_sam_dispinfo_4(TALLOC_CTX *ctx, SAM_DISPINFO_4 *sam, uint32 *num_entries,
+ uint32 *data_size, uint32 start_idx,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+{
+ fstring sam_name;
+ uint32 len_sam_name;
+ uint32 max_entries, max_data_size;
+ uint32 dsize = 0;
+ uint32 i;
+
+ DEBUG(5, ("init_sam_dispinfo_4\n"));
+
+ ZERO_STRUCTP(sam);
+
+ max_entries = *num_entries;
+ max_data_size = *data_size;
+
+ if (max_entries==0)
+ return NT_STATUS_OK;
+
+ if (!(sam->sam=(SAM_ENTRY4 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY4))))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(sam->str=(SAM_STR4 *)talloc(ctx, max_entries*sizeof(SAM_STR4))))
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(sam->sam);
+ ZERO_STRUCTP(sam->str);
+
+ for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+ len_sam_name = pass[i].uni_user_name.uni_str_len;
+
+ init_sam_entry4(&sam->sam[i], start_idx + i + 1, len_sam_name);
+
+ unistr2_to_ascii(sam_name, &pass[i].uni_user_name, sizeof(sam_name));
+ init_string2(&sam->str[i].acct_name, sam_name, len_sam_name+1, len_sam_name);
+
+ dsize += sizeof(SAM_ENTRY4);
+ dsize += len_sam_name;
+ }
+
+ *num_entries = i;
+ *data_size = dsize;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_sam_dispinfo_4(char *desc, SAM_DISPINFO_4 * sam,
+ uint32 num_entries,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_dispinfo_4");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (UNMARSHALLING(ps) && num_entries > 0) {
+
+ if ((sam->sam = (SAM_ENTRY4 *)
+ prs_alloc_mem(ps, sizeof(SAM_ENTRY4) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_ENTRY4\n"));
+ return False;
+ }
+
+ if ((sam->str = (SAM_STR4 *)
+ prs_alloc_mem(ps, sizeof(SAM_STR4) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_STR4\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_entry4("", &sam->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!smb_io_string2("acct_name", &sam->str[i].acct_name,
+ sam->sam[i].hdr_acct_name.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_DISPINFO_5 structure.
+********************************************************************/
+
+NTSTATUS init_sam_dispinfo_5(TALLOC_CTX *ctx, SAM_DISPINFO_5 *sam, uint32 *num_entries,
+ uint32 *data_size, uint32 start_idx,
+ DOMAIN_GRP * grp)
+{
+ uint32 len_sam_name;
+ uint32 max_entries, max_data_size;
+ uint32 dsize = 0;
+ uint32 i;
+
+ DEBUG(5, ("init_sam_dispinfo_5\n"));
+
+ ZERO_STRUCTP(sam);
+
+ max_entries = *num_entries;
+ max_data_size = *data_size;
+
+ if (max_entries==0)
+ return NT_STATUS_OK;
+
+ if (!(sam->sam=(SAM_ENTRY5 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY5))))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(sam->str=(SAM_STR5 *)talloc(ctx, max_entries*sizeof(SAM_STR5))))
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(sam->sam);
+ ZERO_STRUCTP(sam->str);
+
+ for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+ len_sam_name = strlen(grp[i].name);
+
+ init_sam_entry5(&sam->sam[i], start_idx + i + 1, len_sam_name);
+ init_string2(&sam->str[i].grp_name, grp[i].name, len_sam_name+1, len_sam_name);
+
+ dsize += sizeof(SAM_ENTRY5);
+ dsize += len_sam_name;
+ }
+
+ *num_entries = i;
+ *data_size = dsize;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_sam_dispinfo_5(char *desc, SAM_DISPINFO_5 * sam,
+ uint32 num_entries,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (sam == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_dispinfo_5");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (UNMARSHALLING(ps) && num_entries > 0) {
+
+ if ((sam->sam = (SAM_ENTRY5 *)
+ prs_alloc_mem(ps, sizeof(SAM_ENTRY5) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_ENTRY5\n"));
+ return False;
+ }
+
+ if ((sam->str = (SAM_STR5 *)
+ prs_alloc_mem(ps, sizeof(SAM_STR5) *
+ num_entries)) == NULL) {
+ DEBUG(0, ("out of memory allocating SAM_STR5\n"));
+ return False;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!sam_io_sam_entry5("", &sam->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!smb_io_string2("grp_name", &sam->str[i].grp_name,
+ sam->sam[i].hdr_grp_name.buffer, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_DISPINFO structure.
+********************************************************************/
+
+void init_samr_r_query_dispinfo(SAMR_R_QUERY_DISPINFO * r_u,
+ uint32 num_entries, uint32 data_size,
+ uint16 switch_level, SAM_DISPINFO_CTR * ctr,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_dispinfo: level %d\n", switch_level));
+
+ if (switch_level==4)
+ r_u->total_size = 0; /* not calculated */
+ else
+ r_u->total_size = data_size; /* not calculated */
+
+ r_u->data_size = data_size;
+
+ r_u->switch_level = switch_level;
+ r_u->num_entries = num_entries;
+
+ if (num_entries==0)
+ r_u->ptr_entries = 0;
+ else
+ r_u->ptr_entries = 1;
+
+ r_u->num_entries2 = num_entries;
+ r_u->ctr = ctr;
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_dispinfo(char *desc, SAMR_R_QUERY_DISPINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_dispinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("total_size ", ps, depth, &r_u->total_size))
+ return False;
+ if(!prs_uint32("data_size ", ps, depth, &r_u->data_size))
+ return False;
+ if(!prs_uint16("switch_level", ps, depth, &r_u->switch_level))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries ", ps, depth, &r_u->num_entries))
+ return False;
+ if(!prs_uint32("ptr_entries ", ps, depth, &r_u->ptr_entries))
+ return False;
+
+ if (r_u->ptr_entries==0) {
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+ }
+
+ if(!prs_uint32("num_entries2", ps, depth, &r_u->num_entries2))
+ return False;
+
+ switch (r_u->switch_level) {
+ case 0x1:
+ if(!sam_io_sam_dispinfo_1("users", r_u->ctr->sam.info1,
+ r_u->num_entries, ps, depth))
+ return False;
+ break;
+ case 0x2:
+ if(!sam_io_sam_dispinfo_2("servers", r_u->ctr->sam.info2,
+ r_u->num_entries, ps, depth))
+ return False;
+ break;
+ case 0x3:
+ if(!sam_io_sam_dispinfo_3("groups", r_u->ctr->sam.info3,
+ r_u->num_entries, ps, depth))
+ return False;
+ break;
+ case 0x4:
+ if(!sam_io_sam_dispinfo_4("user list",
+ r_u->ctr->sam.info4,
+ r_u->num_entries, ps, depth))
+ return False;
+ break;
+ case 0x5:
+ if(!sam_io_sam_dispinfo_5("group list",
+ r_u->ctr->sam.info5,
+ r_u->num_entries, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(0,("samr_io_r_query_dispinfo: unknown switch value\n"));
+ break;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_OPEN_GROUP structure.
+********************************************************************/
+
+void init_samr_q_open_group(SAMR_Q_OPEN_GROUP * q_c,
+ POLICY_HND *hnd,
+ uint32 access_mask, uint32 rid)
+{
+ DEBUG(5, ("init_samr_q_open_group\n"));
+
+ q_c->domain_pol = *hnd;
+ q_c->access_mask = access_mask;
+ q_c->rid_group = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_open_group(char *desc, SAMR_Q_OPEN_GROUP * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+ if(!prs_uint32("rid_group", ps, depth, &q_u->rid_group))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_open_group(char *desc, SAMR_R_OPEN_GROUP * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a GROUP_INFO1 structure.
+********************************************************************/
+
+void init_samr_group_info1(GROUP_INFO1 * gr1,
+ char *acct_name, char *acct_desc,
+ uint32 num_members)
+{
+ int desc_len = acct_desc != NULL ? strlen(acct_desc) : 0;
+ int acct_len = acct_name != NULL ? strlen(acct_name) : 0;
+
+ DEBUG(5, ("init_samr_group_info1\n"));
+
+ init_uni_hdr(&gr1->hdr_acct_name, acct_len);
+
+ gr1->unknown_1 = 0x3;
+ gr1->num_members = num_members;
+
+ init_uni_hdr(&gr1->hdr_acct_desc, desc_len);
+
+ init_unistr2(&gr1->uni_acct_name, acct_name, acct_len);
+ init_unistr2(&gr1->uni_acct_desc, acct_desc, desc_len);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_group_info1(char *desc, GROUP_INFO1 * gr1,
+ prs_struct *ps, int depth)
+{
+ if (gr1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_group_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_name", &gr1->hdr_acct_name, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown_1", ps, depth, &gr1->unknown_1))
+ return False;
+ if(!prs_uint32("num_members", ps, depth, &gr1->num_members))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_desc", &gr1->hdr_acct_desc, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_name", &gr1->uni_acct_name,
+ gr1->hdr_acct_name.buffer, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_desc", &gr1->uni_acct_desc,
+ gr1->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a GROUP_INFO3 structure.
+********************************************************************/
+
+void init_samr_group_info3(GROUP_INFO3 *gr3)
+{
+ DEBUG(5, ("init_samr_group_info3\n"));
+
+ gr3->unknown_1 = 0x3;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_group_info3(char *desc, GROUP_INFO3 *gr3, prs_struct *ps, int depth)
+{
+ if (gr3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_group_info3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("unknown_1", ps, depth, &gr3->unknown_1))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a GROUP_INFO4 structure.
+********************************************************************/
+
+void init_samr_group_info4(GROUP_INFO4 * gr4, char *acct_desc)
+{
+ int acct_len = acct_desc != NULL ? strlen(acct_desc) : 0;
+
+ DEBUG(5, ("init_samr_group_info4\n"));
+
+ init_uni_hdr(&gr4->hdr_acct_desc, acct_len);
+ init_unistr2(&gr4->uni_acct_desc, acct_desc, acct_len);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_group_info4(char *desc, GROUP_INFO4 * gr4,
+ prs_struct *ps, int depth)
+{
+ if (gr4 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_group_info4");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_desc", &gr4->hdr_acct_desc, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_acct_desc", &gr4->uni_acct_desc,
+ gr4->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL samr_group_info_ctr(char *desc, GROUP_INFO_CTR **ctr,
+ prs_struct *ps, int depth)
+{
+ if (UNMARSHALLING(ps))
+ *ctr = (GROUP_INFO_CTR *)prs_alloc_mem(ps,sizeof(GROUP_INFO_CTR));
+
+ if (*ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_group_info_ctr");
+ depth++;
+
+ if(!prs_uint16("switch_value1", ps, depth, &(*ctr)->switch_value1))
+ return False;
+
+ switch ((*ctr)->switch_value1) {
+ case 1:
+ if(!samr_io_group_info1("group_info1", &(*ctr)->group.info1, ps, depth))
+ return False;
+ break;
+ case 3:
+ if(!samr_io_group_info3("group_info3", &(*ctr)->group.info3, ps, depth))
+ return False;
+ break;
+ case 4:
+ if(!samr_io_group_info4("group_info4", &(*ctr)->group.info4, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(0,("samr_group_info_ctr: unsupported switch level\n"));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_CREATE_DOM_GROUP structure.
+********************************************************************/
+
+void init_samr_q_create_dom_group(SAMR_Q_CREATE_DOM_GROUP * q_e,
+ POLICY_HND *pol, char *acct_desc,
+ uint32 access_mask)
+{
+ int acct_len = acct_desc != NULL ? strlen(acct_desc) : 0;
+
+ DEBUG(5, ("init_samr_q_create_dom_group\n"));
+
+ q_e->pol = *pol;
+
+ init_uni_hdr(&q_e->hdr_acct_desc, acct_len);
+ init_unistr2(&q_e->uni_acct_desc, acct_desc, acct_len);
+
+ q_e->access_mask = access_mask;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_create_dom_group(char *desc, SAMR_Q_CREATE_DOM_GROUP * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_create_dom_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_desc", &q_e->hdr_acct_desc, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_acct_desc", &q_e->uni_acct_desc,
+ q_e->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("access", ps, depth, &q_e->access_mask))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_create_dom_group(char *desc, SAMR_R_CREATE_DOM_GROUP * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_create_dom_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("rid ", ps, depth, &r_u->rid))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_DELETE_DOM_GROUP structure.
+********************************************************************/
+
+void init_samr_q_delete_dom_group(SAMR_Q_DELETE_DOM_GROUP * q_c,
+ POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_delete_dom_group\n"));
+
+ q_c->group_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_delete_dom_group(char *desc, SAMR_Q_DELETE_DOM_GROUP * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_delete_dom_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("group_pol", &q_u->group_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_delete_dom_group(char *desc, SAMR_R_DELETE_DOM_GROUP * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_delete_dom_group");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_DEL_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_q_del_groupmem(SAMR_Q_DEL_GROUPMEM * q_e,
+ POLICY_HND *pol, uint32 rid)
+{
+ DEBUG(5, ("init_samr_q_del_groupmem\n"));
+
+ q_e->pol = *pol;
+ q_e->rid = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_del_groupmem(char *desc, SAMR_Q_DEL_GROUPMEM * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_del_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("rid", ps, depth, &q_e->rid))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_DEL_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_r_del_groupmem(SAMR_R_DEL_GROUPMEM * r_u, POLICY_HND *pol,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_del_groupmem\n"));
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_del_groupmem(char *desc, SAMR_R_DEL_GROUPMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_del_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ADD_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_q_add_groupmem(SAMR_Q_ADD_GROUPMEM * q_e,
+ POLICY_HND *pol, uint32 rid)
+{
+ DEBUG(5, ("init_samr_q_add_groupmem\n"));
+
+ q_e->pol = *pol;
+ q_e->rid = rid;
+ q_e->unknown = 0x0005;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_add_groupmem(char *desc, SAMR_Q_ADD_GROUPMEM * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_add_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("rid ", ps, depth, &q_e->rid))
+ return False;
+ if(!prs_uint32("unknown", ps, depth, &q_e->unknown))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_ADD_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_r_add_groupmem(SAMR_R_ADD_GROUPMEM * r_u, POLICY_HND *pol,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_add_groupmem\n"));
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_add_groupmem(char *desc, SAMR_R_ADD_GROUPMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_add_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_SET_GROUPINFO structure.
+********************************************************************/
+
+void init_samr_q_set_groupinfo(SAMR_Q_SET_GROUPINFO * q_e,
+ POLICY_HND *pol, GROUP_INFO_CTR * ctr)
+{
+ DEBUG(5, ("init_samr_q_set_groupinfo\n"));
+
+ q_e->pol = *pol;
+ q_e->ctr = ctr;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_set_groupinfo(char *desc, SAMR_Q_SET_GROUPINFO * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_set_groupinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!samr_group_info_ctr("ctr", &q_e->ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_SET_GROUPINFO structure.
+********************************************************************/
+
+void init_samr_r_set_groupinfo(SAMR_R_SET_GROUPINFO * r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_set_groupinfo\n"));
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_set_groupinfo(char *desc, SAMR_R_SET_GROUPINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_set_groupinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_GROUPINFO structure.
+********************************************************************/
+
+void init_samr_q_query_groupinfo(SAMR_Q_QUERY_GROUPINFO * q_e,
+ POLICY_HND *pol, uint16 switch_level)
+{
+ DEBUG(5, ("init_samr_q_query_groupinfo\n"));
+
+ q_e->pol = *pol;
+
+ q_e->switch_level = switch_level;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_groupinfo(char *desc, SAMR_Q_QUERY_GROUPINFO * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_groupinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_level", ps, depth, &q_e->switch_level))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_GROUPINFO structure.
+********************************************************************/
+
+void init_samr_r_query_groupinfo(SAMR_R_QUERY_GROUPINFO * r_u,
+ GROUP_INFO_CTR * ctr, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_groupinfo\n"));
+
+ r_u->ptr = (NT_STATUS_IS_OK(status) && ctr != NULL) ? 1 : 0;
+ r_u->ctr = ctr;
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_groupinfo(char *desc, SAMR_R_QUERY_GROUPINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_groupinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if(!samr_group_info_ctr("ctr", &r_u->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_q_query_groupmem(SAMR_Q_QUERY_GROUPMEM * q_c, POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_query_groupmem\n"));
+
+ q_c->group_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_groupmem(char *desc, SAMR_Q_QUERY_GROUPMEM * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("group_pol", &q_u->group_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_GROUPMEM structure.
+********************************************************************/
+
+void init_samr_r_query_groupmem(SAMR_R_QUERY_GROUPMEM * r_u,
+ uint32 num_entries, uint32 *rid,
+ uint32 *attr, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_groupmem\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->ptr = 1;
+ r_u->num_entries = num_entries;
+
+ r_u->ptr_attrs = attr != NULL ? 1 : 0;
+ r_u->ptr_rids = rid != NULL ? 1 : 0;
+
+ r_u->num_rids = num_entries;
+ r_u->rid = rid;
+
+ r_u->num_attrs = num_entries;
+ r_u->attr = attr;
+ } else {
+ r_u->ptr = 0;
+ r_u->num_entries = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_groupmem(char *desc, SAMR_R_QUERY_GROUPMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (r_u == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(r_u);
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_groupmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+ if(!prs_uint32("num_entries ", ps, depth, &r_u->num_entries))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if(!prs_uint32("ptr_rids ", ps, depth, &r_u->ptr_rids))
+ return False;
+ if(!prs_uint32("ptr_attrs", ps, depth, &r_u->ptr_attrs))
+ return False;
+
+ if (r_u->ptr_rids != 0) {
+ if(!prs_uint32("num_rids", ps, depth, &r_u->num_rids))
+ return False;
+ if (UNMARSHALLING(ps) && r_u->num_rids != 0) {
+ r_u->rid = (uint32 *)prs_alloc_mem(ps,sizeof(r_u->rid[0])*r_u->num_rids);
+ if (r_u->rid == NULL)
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_rids; i++) {
+ if(!prs_uint32("", ps, depth, &r_u->rid[i]))
+ return False;
+ }
+ }
+
+ if (r_u->ptr_attrs != 0) {
+ if(!prs_uint32("num_attrs", ps, depth, &r_u->num_attrs))
+ return False;
+
+ if (UNMARSHALLING(ps) && r_u->num_attrs != 0) {
+ r_u->attr = (uint32 *)prs_alloc_mem(ps,sizeof(r_u->attr[0])*r_u->num_attrs);
+ if (r_u->attr == NULL)
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_attrs; i++) {
+ if(!prs_uint32("", ps, depth, &r_u->attr[i]))
+ return False;
+ }
+ }
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_USERGROUPS structure.
+********************************************************************/
+
+void init_samr_q_query_usergroups(SAMR_Q_QUERY_USERGROUPS * q_u,
+ POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_query_usergroups\n"));
+
+ q_u->pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_usergroups(char *desc, SAMR_Q_QUERY_USERGROUPS * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_usergroups");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_USERGROUPS structure.
+********************************************************************/
+
+void init_samr_r_query_usergroups(SAMR_R_QUERY_USERGROUPS * r_u,
+ uint32 num_gids, DOM_GID * gid,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_usergroups\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->ptr_0 = 1;
+ r_u->num_entries = num_gids;
+ r_u->ptr_1 = (num_gids != 0) ? 1 : 0;
+ r_u->num_entries2 = num_gids;
+
+ r_u->gid = gid;
+ } else {
+ r_u->ptr_0 = 0;
+ r_u->num_entries = 0;
+ r_u->ptr_1 = 0;
+ r_u->gid = NULL;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_gids(char *desc, uint32 *num_gids, DOM_GID ** gid,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ if (gid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_gids");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_gids", ps, depth, num_gids))
+ return False;
+
+ if ((*num_gids) != 0) {
+ if (UNMARSHALLING(ps)) {
+ (*gid) = (DOM_GID *)prs_alloc_mem(ps,sizeof(DOM_GID)*(*num_gids));
+ }
+
+ if ((*gid) == NULL) {
+ return False;
+ }
+
+ for (i = 0; i < (*num_gids); i++) {
+ if(!smb_io_gid("gids", &(*gid)[i], ps, depth))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_usergroups(char *desc, SAMR_R_QUERY_USERGROUPS * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_usergroups");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_0 ", ps, depth, &r_u->ptr_0))
+ return False;
+
+ if (r_u->ptr_0 != 0) {
+ if(!prs_uint32("num_entries ", ps, depth, &r_u->num_entries))
+ return False;
+ if(!prs_uint32("ptr_1 ", ps, depth, &r_u->ptr_1))
+ return False;
+
+ if (r_u->num_entries != 0 && r_u->ptr_1 != 0) {
+ if(!samr_io_gids("gids", &r_u->num_entries2, &r_u->gid, ps, depth))
+ return False;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ENUM_DOMAINS structure.
+********************************************************************/
+
+void init_samr_q_enum_domains(SAMR_Q_ENUM_DOMAINS * q_e,
+ POLICY_HND *pol,
+ uint32 start_idx, uint32 size)
+{
+ DEBUG(5, ("init_samr_q_enum_domains\n"));
+
+ q_e->pol = *pol;
+
+ q_e->start_idx = start_idx;
+ q_e->max_size = size;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_enum_domains(char *desc, SAMR_Q_ENUM_DOMAINS * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_domains");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("start_idx", ps, depth, &q_e->start_idx))
+ return False;
+ if(!prs_uint32("max_size ", ps, depth, &q_e->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_ENUM_DOMAINS structure.
+********************************************************************/
+
+void init_samr_r_enum_domains(SAMR_R_ENUM_DOMAINS * r_u,
+ uint32 next_idx, uint32 num_sam_entries)
+{
+ DEBUG(5, ("init_samr_r_enum_domains\n"));
+
+ r_u->next_idx = next_idx;
+
+ if (num_sam_entries != 0) {
+ r_u->ptr_entries1 = 1;
+ r_u->ptr_entries2 = 1;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->num_entries3 = num_sam_entries;
+
+ r_u->num_entries4 = num_sam_entries;
+ } else {
+ r_u->ptr_entries1 = 0;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->ptr_entries2 = 1;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_enum_domains(char *desc, SAMR_R_ENUM_DOMAINS * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_domains");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("next_idx ", ps, depth, &r_u->next_idx))
+ return False;
+ if(!prs_uint32("ptr_entries1", ps, depth, &r_u->ptr_entries1))
+ return False;
+
+ if (r_u->ptr_entries1 != 0) {
+ if(!prs_uint32("num_entries2", ps, depth, &r_u->num_entries2))
+ return False;
+ if(!prs_uint32("ptr_entries2", ps, depth, &r_u->ptr_entries2))
+ return False;
+ if(!prs_uint32("num_entries3", ps, depth, &r_u->num_entries3))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ r_u->sam = (SAM_ENTRY *)prs_alloc_mem(ps,sizeof(SAM_ENTRY)*r_u->num_entries2);
+ r_u->uni_dom_name = (UNISTR2 *)prs_alloc_mem(ps,sizeof(UNISTR2)*r_u->num_entries2);
+ }
+
+ if ((r_u->sam == NULL || r_u->uni_dom_name == NULL) && r_u->num_entries2 != 0) {
+ DEBUG(0, ("NULL pointers in SAMR_R_ENUM_DOMAINS\n"));
+ r_u->num_entries4 = 0;
+ r_u->status = NT_STATUS_MEMORY_NOT_ALLOCATED;
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp) - 1, "dom[%d]", i);
+ if(!sam_io_sam_entry(tmp, &r_u->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp) - 1, "dom[%d]", i);
+ if(!smb_io_unistr2(tmp, &r_u->uni_dom_name[i],
+ r_u->sam[i].hdr_name.buffer, ps,
+ depth))
+ return False;
+ }
+
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_entries4", ps, depth, &r_u->num_entries4))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ENUM_DOM_GROUPS structure.
+********************************************************************/
+
+void init_samr_q_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS * q_e,
+ POLICY_HND *pol,
+ uint32 start_idx, uint32 size)
+{
+ DEBUG(5, ("init_samr_q_enum_dom_groups\n"));
+
+ q_e->pol = *pol;
+
+ q_e->start_idx = start_idx;
+ q_e->max_size = size;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_enum_dom_groups(char *desc, SAMR_Q_ENUM_DOM_GROUPS * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_groups");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &(q_e->pol), ps, depth))
+ return False;
+
+ if(!prs_uint32("start_idx", ps, depth, &q_e->start_idx))
+ return False;
+ if(!prs_uint32("max_size ", ps, depth, &q_e->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_ENUM_DOM_GROUPS structure.
+********************************************************************/
+
+void init_samr_r_enum_dom_groups(SAMR_R_ENUM_DOM_GROUPS * r_u,
+ uint32 next_idx, uint32 num_sam_entries)
+{
+ DEBUG(5, ("init_samr_r_enum_dom_groups\n"));
+
+ r_u->next_idx = next_idx;
+
+ if (num_sam_entries != 0) {
+ r_u->ptr_entries1 = 1;
+ r_u->ptr_entries2 = 1;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->num_entries3 = num_sam_entries;
+
+ r_u->num_entries4 = num_sam_entries;
+ } else {
+ r_u->ptr_entries1 = 0;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->ptr_entries2 = 1;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_enum_dom_groups(char *desc, SAMR_R_ENUM_DOM_GROUPS * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_groups");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("next_idx ", ps, depth, &r_u->next_idx))
+ return False;
+ if(!prs_uint32("ptr_entries1", ps, depth, &r_u->ptr_entries1))
+ return False;
+
+ if (r_u->ptr_entries1 != 0) {
+ if(!prs_uint32("num_entries2", ps, depth, &r_u->num_entries2))
+ return False;
+ if(!prs_uint32("ptr_entries2", ps, depth, &r_u->ptr_entries2))
+ return False;
+ if(!prs_uint32("num_entries3", ps, depth, &r_u->num_entries3))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ r_u->sam = (SAM_ENTRY *)prs_alloc_mem(ps,sizeof(SAM_ENTRY)*r_u->num_entries2);
+ r_u->uni_grp_name = (UNISTR2 *)prs_alloc_mem(ps,sizeof(UNISTR2)*r_u->num_entries2);
+ }
+
+ if ((r_u->sam == NULL || r_u->uni_grp_name == NULL) && r_u->num_entries2 != 0) {
+ DEBUG(0,
+ ("NULL pointers in SAMR_R_ENUM_DOM_GROUPS\n"));
+ r_u->num_entries4 = 0;
+ r_u->status = NT_STATUS_MEMORY_NOT_ALLOCATED;
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!sam_io_sam_entry("", &r_u->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!smb_io_unistr2("", &r_u->uni_grp_name[i],
+ r_u->sam[i].hdr_name.buffer, ps, depth))
+ return False;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_entries4", ps, depth, &r_u->num_entries4))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ENUM_DOM_ALIASES structure.
+********************************************************************/
+
+void init_samr_q_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES * q_e,
+ POLICY_HND *pol, uint32 start_idx,
+ uint32 size)
+{
+ DEBUG(5, ("init_samr_q_enum_dom_aliases\n"));
+
+ q_e->pol = *pol;
+
+ q_e->start_idx = start_idx;
+ q_e->max_size = size;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_enum_dom_aliases(char *desc, SAMR_Q_ENUM_DOM_ALIASES * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_aliases");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_e->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("start_idx", ps, depth, &q_e->start_idx))
+ return False;
+ if(!prs_uint32("max_size ", ps, depth, &q_e->max_size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_ENUM_DOM_ALIASES structure.
+********************************************************************/
+
+void init_samr_r_enum_dom_aliases(SAMR_R_ENUM_DOM_ALIASES *r_u, uint32 next_idx, uint32 num_sam_entries)
+{
+ DEBUG(5, ("init_samr_r_enum_dom_aliases\n"));
+
+ r_u->next_idx = next_idx;
+
+ if (num_sam_entries != 0) {
+ r_u->ptr_entries1 = 1;
+ r_u->ptr_entries2 = 1;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->num_entries3 = num_sam_entries;
+
+ r_u->num_entries4 = num_sam_entries;
+ } else {
+ r_u->ptr_entries1 = 0;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->ptr_entries2 = 1;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_enum_dom_aliases(char *desc, SAMR_R_ENUM_DOM_ALIASES * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_aliases");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("next_idx ", ps, depth, &r_u->next_idx))
+ return False;
+ if(!prs_uint32("ptr_entries1", ps, depth, &r_u->ptr_entries1))
+ return False;
+
+ if (r_u->ptr_entries1 != 0) {
+ if(!prs_uint32("num_entries2", ps, depth, &r_u->num_entries2))
+ return False;
+ if(!prs_uint32("ptr_entries2", ps, depth, &r_u->ptr_entries2))
+ return False;
+ if(!prs_uint32("num_entries3", ps, depth, &r_u->num_entries3))
+ return False;
+
+ if (UNMARSHALLING(ps) && (r_u->num_entries2 > 0)) {
+ r_u->sam = (SAM_ENTRY *)prs_alloc_mem(ps,sizeof(SAM_ENTRY)*r_u->num_entries2);
+ r_u->uni_grp_name = (UNISTR2 *)prs_alloc_mem(ps,sizeof(UNISTR2)*r_u->num_entries2);
+ }
+
+ if (r_u->num_entries2 != 0 &&
+ (r_u->sam == NULL || r_u->uni_grp_name == NULL)) {
+ DEBUG(0,("NULL pointers in SAMR_R_ENUM_DOM_ALIASES\n"));
+ r_u->num_entries4 = 0;
+ r_u->status = NT_STATUS_MEMORY_NOT_ALLOCATED;
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!sam_io_sam_entry("", &r_u->sam[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_entries2; i++) {
+ if(!smb_io_unistr2("", &r_u->uni_grp_name[i],
+ r_u->sam[i].hdr_name.buffer, ps,
+ depth))
+ return False;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_entries4", ps, depth, &r_u->num_entries4))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a ALIAS_INFO1 structure.
+********************************************************************/
+
+void init_samr_alias_info1(ALIAS_INFO1 * al1, char *acct_name, uint32 num_member, char *acct_desc)
+{
+ int acct_len_name = acct_name != NULL ? strlen(acct_name) : 0;
+ int acct_len_desc = acct_desc != NULL ? strlen(acct_desc) : 0;
+
+ DEBUG(5, ("init_samr_alias_info1\n"));
+
+ init_uni_hdr(&al1->hdr_acct_name, acct_len_name);
+ init_unistr2(&al1->uni_acct_name, acct_name, acct_len_name);
+
+ al1->num_member=num_member;
+
+ init_uni_hdr(&al1->hdr_acct_desc, acct_len_desc);
+ init_unistr2(&al1->uni_acct_desc, acct_desc, acct_len_desc);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_alias_info1(char *desc, ALIAS_INFO1 * al1,
+ prs_struct *ps, int depth)
+{
+ if (al1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_alias_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_name", &al1->hdr_acct_name, ps, depth))
+ return False;
+ if(!prs_uint32("num_member", ps, depth, &al1->num_member))
+ return False;
+ if(!smb_io_unihdr("hdr_acct_desc", &al1->hdr_acct_desc, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_name", &al1->uni_acct_name,
+ al1->hdr_acct_name.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_desc", &al1->uni_acct_desc,
+ al1->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a ALIAS_INFO3 structure.
+********************************************************************/
+
+void init_samr_alias_info3(ALIAS_INFO3 * al3, char *acct_desc)
+{
+ int acct_len = acct_desc != NULL ? strlen(acct_desc) : 0;
+
+ DEBUG(5, ("init_samr_alias_info3\n"));
+
+ init_uni_hdr(&al3->hdr_acct_desc, acct_len);
+ init_unistr2(&al3->uni_acct_desc, acct_desc, acct_len);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_alias_info3(char *desc, ALIAS_INFO3 * al3,
+ prs_struct *ps, int depth)
+{
+ if (al3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_alias_info3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_desc", &al3->hdr_acct_desc, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_acct_desc", &al3->uni_acct_desc,
+ al3->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_alias_info_ctr(char *desc, ALIAS_INFO_CTR * ctr,
+ prs_struct *ps, int depth)
+{
+ if (ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_alias_info_ctr");
+ depth++;
+
+ if(!prs_uint16("switch_value1", ps, depth, &ctr->switch_value1))
+ return False;
+ if(!prs_uint16("switch_value2", ps, depth, &ctr->switch_value2))
+ return False;
+
+ switch (ctr->switch_value1) {
+ case 1:
+ if(!samr_io_alias_info1("alias_info1", &ctr->alias.info1, ps, depth))
+ return False;
+ break;
+ case 3:
+ if(!samr_io_alias_info3("alias_info3", &ctr->alias.info3, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(0,("samr_alias_info_ctr: unsupported switch level\n"));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_ALIASINFO structure.
+********************************************************************/
+
+void init_samr_q_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO * q_e,
+ POLICY_HND *pol, uint16 switch_level)
+{
+ DEBUG(5, ("init_samr_q_query_aliasinfo\n"));
+
+ q_e->pol = *pol;
+ q_e->switch_level = switch_level;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_aliasinfo(char *desc, SAMR_Q_QUERY_ALIASINFO * q_e,
+ prs_struct *ps, int depth)
+{
+ if (q_e == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_aliasinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &(q_e->pol), ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_level", ps, depth, &q_e->switch_level))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_ALIASINFO structure.
+********************************************************************/
+
+void init_samr_r_query_aliasinfo(SAMR_R_QUERY_ALIASINFO * r_u,
+ ALIAS_INFO_CTR * ctr, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_aliasinfo\n"));
+
+ r_u->ptr = (NT_STATUS_IS_OK(status) && ctr != NULL) ? 1 : 0;
+ r_u->ctr = *ctr;
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_aliasinfo(char *desc, SAMR_R_QUERY_ALIASINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_aliasinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if(!samr_alias_info_ctr("ctr", &r_u->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_SET_ALIASINFO structure.
+********************************************************************/
+
+void init_samr_q_set_aliasinfo(SAMR_Q_SET_ALIASINFO * q_u,
+ POLICY_HND *hnd, ALIAS_INFO_CTR * ctr)
+{
+ DEBUG(5, ("init_samr_q_set_aliasinfo\n"));
+
+ q_u->alias_pol = *hnd;
+ q_u->ctr = *ctr;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_set_aliasinfo(char *desc, SAMR_Q_SET_ALIASINFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_set_aliasinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+ if(!samr_alias_info_ctr("ctr", &q_u->ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_set_aliasinfo(char *desc, SAMR_R_SET_ALIASINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_set_aliasinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_USERALIASES structure.
+********************************************************************/
+
+void init_samr_q_query_useraliases(SAMR_Q_QUERY_USERALIASES * q_u,
+ POLICY_HND *hnd,
+ uint32 num_sids,
+ uint32 *ptr_sid, DOM_SID2 * sid)
+{
+ DEBUG(5, ("init_samr_q_query_useraliases\n"));
+
+ q_u->pol = *hnd;
+
+ q_u->num_sids1 = num_sids;
+ q_u->ptr = 1;
+ q_u->num_sids2 = num_sids;
+
+ q_u->ptr_sid = ptr_sid;
+ q_u->sid = sid;
+}
+
+/*******************************************************************
+reads or writes a SAMR_Q_QUERY_USERALIASES structure.
+********************************************************************/
+
+BOOL samr_io_q_query_useraliases(char *desc, SAMR_Q_QUERY_USERALIASES * q_u,
+ prs_struct *ps, int depth)
+{
+ fstring tmp;
+ uint32 i;
+
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_useraliases");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("num_sids1", ps, depth, &q_u->num_sids1))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &q_u->ptr))
+ return False;
+
+ if (q_u->ptr==0)
+ return True;
+
+ if(!prs_uint32("num_sids2", ps, depth, &q_u->num_sids2))
+ return False;
+
+ if (UNMARSHALLING(ps) && (q_u->num_sids2 != 0)) {
+ q_u->ptr_sid = (uint32 *)prs_alloc_mem(ps,sizeof(q_u->ptr_sid[0])*q_u->num_sids2);
+ if (q_u->ptr_sid == NULL)
+ return False;
+
+ q_u->sid = (DOM_SID2 *)prs_alloc_mem(ps, sizeof(q_u->sid[0]) * q_u->num_sids2);
+ if (q_u->sid == NULL)
+ return False;
+ }
+
+ for (i = 0; i < q_u->num_sids2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "ptr[%02d]", i);
+ if(!prs_uint32(tmp, ps, depth, &q_u->ptr_sid[i]))
+ return False;
+ }
+
+ for (i = 0; i < q_u->num_sids2; i++) {
+ if (q_u->ptr_sid[i] != 0) {
+ slprintf(tmp, sizeof(tmp) - 1, "sid[%02d]", i);
+ if(!smb_io_dom_sid2(tmp, &q_u->sid[i], ps, depth))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_USERALIASES structure.
+********************************************************************/
+
+void init_samr_r_query_useraliases(SAMR_R_QUERY_USERALIASES * r_u,
+ uint32 num_rids, uint32 *rid,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_useraliases\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->num_entries = num_rids;
+ r_u->ptr = 1;
+ r_u->num_entries2 = num_rids;
+
+ r_u->rid = rid;
+ } else {
+ r_u->num_entries = 0;
+ r_u->ptr = 0;
+ r_u->num_entries2 = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_rids(char *desc, uint32 *num_rids, uint32 **rid,
+ prs_struct *ps, int depth)
+{
+ fstring tmp;
+ uint32 i;
+ if (rid == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_rids");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_rids", ps, depth, num_rids))
+ return False;
+
+ if ((*num_rids) != 0) {
+ if (UNMARSHALLING(ps)) {
+ /* reading */
+ (*rid) = (uint32 *)prs_alloc_mem(ps,sizeof(uint32)*(*num_rids));
+ }
+ if ((*rid) == NULL)
+ return False;
+
+ for (i = 0; i < (*num_rids); i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "rid[%02d]", i);
+ if(!prs_uint32(tmp, ps, depth, &((*rid)[i])))
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_useraliases(char *desc, SAMR_R_QUERY_USERALIASES * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_useraliases");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries", ps, depth, &r_u->num_entries))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if(!samr_io_rids("rids", &r_u->num_entries2, &r_u->rid, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_OPEN_ALIAS structure.
+********************************************************************/
+
+void init_samr_q_open_alias(SAMR_Q_OPEN_ALIAS * q_u, POLICY_HND *pol,
+ uint32 access_mask, uint32 rid)
+{
+ DEBUG(5, ("init_samr_q_open_alias\n"));
+
+ q_u->dom_pol = *pol;
+ q_u->access_mask = access_mask;
+ q_u->rid_alias = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_open_alias(char *desc, SAMR_Q_OPEN_ALIAS * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->dom_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+ if(!prs_uint32("rid_alias", ps, depth, &q_u->rid_alias))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_open_alias(char *desc, SAMR_R_OPEN_ALIAS * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_LOOKUP_RIDS structure.
+********************************************************************/
+
+void init_samr_q_lookup_rids(TALLOC_CTX *ctx, SAMR_Q_LOOKUP_RIDS * q_u,
+ POLICY_HND *pol, uint32 flags,
+ uint32 num_rids, uint32 *rid)
+{
+ DEBUG(5, ("init_samr_q_lookup_rids\n"));
+
+ q_u->pol = *pol;
+
+ q_u->num_rids1 = num_rids;
+ q_u->flags = flags;
+ q_u->ptr = 0;
+ q_u->num_rids2 = num_rids;
+ q_u->rid = (uint32 *)talloc_zero(ctx, num_rids * sizeof(q_u->rid[0]));
+ if (q_u->rid == NULL) {
+ q_u->num_rids1 = 0;
+ q_u->num_rids2 = 0;
+ } else {
+ memcpy(q_u->rid, rid, num_rids * sizeof(q_u->rid[0]));
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_lookup_rids(char *desc, SAMR_Q_LOOKUP_RIDS * q_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_lookup_rids");
+ depth++;
+
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(q_u);
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("num_rids1", ps, depth, &q_u->num_rids1))
+ return False;
+ if(!prs_uint32("flags ", ps, depth, &q_u->flags))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &q_u->ptr))
+ return False;
+ if(!prs_uint32("num_rids2", ps, depth, &q_u->num_rids2))
+ return False;
+
+ if (UNMARSHALLING(ps) && (q_u->num_rids2 != 0)) {
+ q_u->rid = (uint32 *)prs_alloc_mem(ps, sizeof(q_u->rid[0])*q_u->num_rids2);
+ if (q_u->rid == NULL)
+ return False;
+ }
+
+ for (i = 0; i < q_u->num_rids2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "rid[%02d] ", i);
+ if(!prs_uint32(tmp, ps, depth, &q_u->rid[i]))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_LOOKUP_RIDS structure.
+********************************************************************/
+
+void init_samr_r_lookup_rids(SAMR_R_LOOKUP_RIDS * r_u,
+ uint32 num_names, UNIHDR * hdr_name,
+ UNISTR2 *uni_name, uint32 *type)
+{
+ DEBUG(5, ("init_samr_r_lookup_rids\n"));
+
+ r_u->hdr_name = NULL;
+ r_u->uni_name = NULL;
+ r_u->type = NULL;
+
+ if (num_names != 0) {
+ r_u->num_names1 = num_names;
+ r_u->ptr_names = 1;
+ r_u->num_names2 = num_names;
+
+ r_u->num_types1 = num_names;
+ r_u->ptr_types = 1;
+ r_u->num_types2 = num_names;
+
+ r_u->hdr_name = hdr_name;
+ r_u->uni_name = uni_name;
+ r_u->type = type;
+ } else {
+ r_u->num_names1 = num_names;
+ r_u->ptr_names = 0;
+ r_u->num_names2 = num_names;
+
+ r_u->num_types1 = num_names;
+ r_u->ptr_types = 0;
+ r_u->num_types2 = num_names;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_lookup_rids(char *desc, SAMR_R_LOOKUP_RIDS * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_lookup_rids");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_names1", ps, depth, &r_u->num_names1))
+ return False;
+ if(!prs_uint32("ptr_names ", ps, depth, &r_u->ptr_names))
+ return False;
+
+ if (r_u->ptr_names != 0) {
+
+ if(!prs_uint32("num_names2", ps, depth, &r_u->num_names2))
+ return False;
+
+
+ if (UNMARSHALLING(ps) && (r_u->num_names2 != 0)) {
+ r_u->hdr_name = (UNIHDR *) prs_alloc_mem(ps, r_u->num_names2 * sizeof(r_u->hdr_name[0]));
+ if (r_u->hdr_name == NULL)
+ return False;
+
+ r_u->uni_name = (UNISTR2 *)prs_alloc_mem(ps, r_u->num_names2 * sizeof(r_u->uni_name[0]));
+ if (r_u->uni_name == NULL)
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_names2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "hdr[%02d] ", i);
+ if(!smb_io_unihdr("", &r_u->hdr_name[i], ps, depth))
+ return False;
+ }
+ for (i = 0; i < r_u->num_names2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "str[%02d] ", i);
+ if(!smb_io_unistr2("", &r_u->uni_name[i], r_u->hdr_name[i].buffer, ps, depth))
+ return False;
+ }
+
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("num_types1", ps, depth, &r_u->num_types1))
+ return False;
+ if(!prs_uint32("ptr_types ", ps, depth, &r_u->ptr_types))
+ return False;
+
+ if (r_u->ptr_types != 0) {
+
+ if(!prs_uint32("num_types2", ps, depth, &r_u->num_types2))
+ return False;
+
+ if (UNMARSHALLING(ps) && (r_u->num_types2 != 0)) {
+ r_u->type = (uint32 *)prs_alloc_mem(ps, r_u->num_types2 * sizeof(r_u->type[0]));
+ if (r_u->type == NULL)
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_types2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "type[%02d] ", i);
+ if(!prs_uint32(tmp, ps, depth, &r_u->type[i]))
+ return False;
+ }
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_OPEN_ALIAS structure.
+********************************************************************/
+
+void init_samr_q_delete_alias(SAMR_Q_DELETE_DOM_ALIAS * q_u, POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_delete_alias\n"));
+
+ q_u->alias_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_delete_alias(char *desc, SAMR_Q_DELETE_DOM_ALIAS * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_delete_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_delete_alias(char *desc, SAMR_R_DELETE_DOM_ALIAS * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_delete_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_CREATE_DOM_ALIAS structure.
+********************************************************************/
+
+void init_samr_q_create_dom_alias(SAMR_Q_CREATE_DOM_ALIAS * q_u,
+ POLICY_HND *hnd, char *acct_desc)
+{
+ int acct_len = acct_desc != NULL ? strlen(acct_desc) : 0;
+
+ DEBUG(5, ("init_samr_q_create_dom_alias\n"));
+
+ q_u->dom_pol = *hnd;
+
+ init_uni_hdr(&q_u->hdr_acct_desc, acct_len);
+ init_unistr2(&q_u->uni_acct_desc, acct_desc, acct_len);
+
+ q_u->access_mask = 0x001f000f;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_create_dom_alias(char *desc, SAMR_Q_CREATE_DOM_ALIAS * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_create_dom_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("dom_pol", &q_u->dom_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_desc", &q_u->hdr_acct_desc, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_acct_desc", &q_u->uni_acct_desc,
+ q_u->hdr_acct_desc.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_create_dom_alias(char *desc, SAMR_R_CREATE_DOM_ALIAS * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_create_dom_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &r_u->alias_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("rid", ps, depth, &r_u->rid))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_ADD_ALIASMEM structure.
+********************************************************************/
+
+void init_samr_q_add_aliasmem(SAMR_Q_ADD_ALIASMEM * q_u, POLICY_HND *hnd,
+ DOM_SID *sid)
+{
+ DEBUG(5, ("init_samr_q_add_aliasmem\n"));
+
+ q_u->alias_pol = *hnd;
+ init_dom_sid2(&q_u->sid, sid);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_add_aliasmem(char *desc, SAMR_Q_ADD_ALIASMEM * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_add_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+ if(!smb_io_dom_sid2("sid ", &q_u->sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_add_aliasmem(char *desc, SAMR_R_ADD_ALIASMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_add_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_DEL_ALIASMEM structure.
+********************************************************************/
+
+void init_samr_q_del_aliasmem(SAMR_Q_DEL_ALIASMEM * q_u, POLICY_HND *hnd,
+ DOM_SID *sid)
+{
+ DEBUG(5, ("init_samr_q_del_aliasmem\n"));
+
+ q_u->alias_pol = *hnd;
+ init_dom_sid2(&q_u->sid, sid);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_del_aliasmem(char *desc, SAMR_Q_DEL_ALIASMEM * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_del_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+ if(!smb_io_dom_sid2("sid ", &q_u->sid, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_del_aliasmem(char *desc, SAMR_R_DEL_ALIASMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_del_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_DELETE_DOM_ALIAS structure.
+********************************************************************/
+
+void init_samr_q_delete_dom_alias(SAMR_Q_DELETE_DOM_ALIAS * q_c,
+ POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_delete_dom_alias\n"));
+
+ q_c->alias_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_delete_dom_alias(char *desc, SAMR_Q_DELETE_DOM_ALIAS * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_delete_dom_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_DELETE_DOM_ALIAS structure.
+********************************************************************/
+
+void init_samr_r_delete_dom_alias(SAMR_R_DELETE_DOM_ALIAS * r_u,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_delete_dom_alias\n"));
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_delete_dom_alias(char *desc, SAMR_R_DELETE_DOM_ALIAS * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_delete_dom_alias");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_ALIASMEM structure.
+********************************************************************/
+
+void init_samr_q_query_aliasmem(SAMR_Q_QUERY_ALIASMEM * q_c,
+ POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_query_aliasmem\n"));
+
+ q_c->alias_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_aliasmem(char *desc, SAMR_Q_QUERY_ALIASMEM * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("alias_pol", &q_u->alias_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_ALIASMEM structure.
+********************************************************************/
+
+void init_samr_r_query_aliasmem(SAMR_R_QUERY_ALIASMEM * r_u,
+ uint32 num_sids, DOM_SID2 * sid,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_aliasmem\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->num_sids = num_sids;
+ r_u->ptr = (num_sids != 0) ? 1 : 0;
+ r_u->num_sids1 = num_sids;
+
+ r_u->sid = sid;
+ } else {
+ r_u->ptr = 0;
+ r_u->num_sids = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_aliasmem(char *desc, SAMR_R_QUERY_ALIASMEM * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ uint32 ptr_sid[MAX_LOOKUP_SIDS];
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_aliasmem");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_sids ", ps, depth, &r_u->num_sids))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ SMB_ASSERT_ARRAY(ptr_sid, r_u->num_sids);
+
+ if (r_u->num_sids != 0) {
+ if(!prs_uint32("num_sids1", ps, depth, &r_u->num_sids1))
+ return False;
+
+ for (i = 0; i < r_u->num_sids1; i++) {
+ ptr_sid[i] = 1;
+ if(!prs_uint32("", ps, depth, &ptr_sid[i]))
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_sids1; i++) {
+ if (ptr_sid[i] != 0) {
+ if(!smb_io_dom_sid2("", &r_u->sid[i], ps, depth))
+ return False;
+ }
+ }
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_LOOKUP_NAMES structure.
+********************************************************************/
+
+NTSTATUS init_samr_q_lookup_names(TALLOC_CTX *ctx, SAMR_Q_LOOKUP_NAMES * q_u,
+ POLICY_HND *pol, uint32 flags,
+ uint32 num_names, char **name)
+{
+ uint32 i;
+
+ DEBUG(5, ("init_samr_q_lookup_names\n"));
+
+ q_u->pol = *pol;
+
+ q_u->num_names1 = num_names;
+ q_u->flags = flags;
+ q_u->ptr = 0;
+ q_u->num_names2 = num_names;
+
+ if (!(q_u->hdr_name = (UNIHDR *)talloc_zero(ctx, num_names * sizeof(UNIHDR))))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!(q_u->uni_name = (UNISTR2 *)talloc_zero(ctx, num_names * sizeof(UNISTR2))))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_names; i++) {
+ int len_name = name[i] != NULL ? strlen(name[i]) : 0;
+ init_uni_hdr(&q_u->hdr_name[i], len_name); /* unicode header for user_name */
+ init_unistr2(&q_u->uni_name[i], name[i], len_name); /* unicode string for machine account */
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_lookup_names(char *desc, SAMR_Q_LOOKUP_NAMES * q_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_lookup_names");
+ depth++;
+
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(q_u);
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("num_names1", ps, depth, &q_u->num_names1))
+ return False;
+ if(!prs_uint32("flags ", ps, depth, &q_u->flags))
+ return False;
+ if(!prs_uint32("ptr ", ps, depth, &q_u->ptr))
+ return False;
+ if(!prs_uint32("num_names2", ps, depth, &q_u->num_names2))
+ return False;
+
+ if (UNMARSHALLING(ps) && (q_u->num_names2 != 0)) {
+ q_u->hdr_name = (UNIHDR *)prs_alloc_mem(ps, sizeof(UNIHDR) *
+ q_u->num_names2);
+ q_u->uni_name = (UNISTR2 *)prs_alloc_mem(ps, sizeof(UNISTR2) *
+ q_u->num_names2);
+ if (!q_u->hdr_name || !q_u->uni_name)
+ return False;
+ }
+
+ for (i = 0; i < q_u->num_names2; i++) {
+ if(!smb_io_unihdr("", &q_u->hdr_name[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < q_u->num_names2; i++) {
+ if(!smb_io_unistr2("", &q_u->uni_name[i], q_u->hdr_name[i].buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_LOOKUP_NAMES structure.
+********************************************************************/
+
+NTSTATUS init_samr_r_lookup_names(TALLOC_CTX *ctx, SAMR_R_LOOKUP_NAMES * r_u,
+ uint32 num_rids,
+ uint32 *rid, uint32 *type,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_lookup_names\n"));
+
+ if (NT_STATUS_IS_OK(status) && (num_rids != 0)) {
+ uint32 i;
+
+ r_u->num_types1 = num_rids;
+ r_u->ptr_types = 1;
+ r_u->num_types2 = num_rids;
+
+ r_u->num_rids1 = num_rids;
+ r_u->ptr_rids = 1;
+ r_u->num_rids2 = num_rids;
+
+ if (!(r_u->rids = (uint32 *)talloc_zero(ctx, sizeof(uint32)*num_rids)))
+ return NT_STATUS_NO_MEMORY;
+ if (!(r_u->types = (uint32 *)talloc_zero(ctx, sizeof(uint32)*num_rids)))
+ return NT_STATUS_NO_MEMORY;
+
+ if (!r_u->rids || !r_u->types)
+ goto empty;
+
+ for (i = 0; i < num_rids; i++) {
+ r_u->rids[i] = rid[i];
+ r_u->types[i] = type[i];
+ }
+ } else {
+
+ empty:
+ r_u->num_types1 = 0;
+ r_u->ptr_types = 0;
+ r_u->num_types2 = 0;
+
+ r_u->num_rids1 = 0;
+ r_u->ptr_rids = 0;
+ r_u->num_rids2 = 0;
+
+ r_u->rids = NULL;
+ r_u->types = NULL;
+ }
+
+ r_u->status = status;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_lookup_names(char *desc, SAMR_R_LOOKUP_NAMES * r_u,
+ prs_struct *ps, int depth)
+{
+ uint32 i;
+ fstring tmp;
+
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_lookup_names");
+ depth++;
+
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(r_u);
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_rids1", ps, depth, &r_u->num_rids1))
+ return False;
+ if(!prs_uint32("ptr_rids ", ps, depth, &r_u->ptr_rids))
+ return False;
+
+ if (r_u->ptr_rids != 0) {
+ if(!prs_uint32("num_rids2", ps, depth, &r_u->num_rids2))
+ return False;
+
+ if (r_u->num_rids2 != r_u->num_rids1) {
+ /* RPC fault */
+ return False;
+ }
+
+ if (UNMARSHALLING(ps))
+ r_u->rids = (uint32 *)prs_alloc_mem(ps, sizeof(uint32)*r_u->num_rids2);
+
+ if (!r_u->rids) {
+ DEBUG(0, ("NULL rids in samr_io_r_lookup_names\n"));
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_rids2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "rid[%02d] ", i);
+ if(!prs_uint32(tmp, ps, depth, &r_u->rids[i]))
+ return False;
+ }
+ }
+
+ if(!prs_uint32("num_types1", ps, depth, &r_u->num_types1))
+ return False;
+ if(!prs_uint32("ptr_types ", ps, depth, &r_u->ptr_types))
+ return False;
+
+ if (r_u->ptr_types != 0) {
+ if(!prs_uint32("num_types2", ps, depth, &r_u->num_types2))
+ return False;
+
+ if (r_u->num_types2 != r_u->num_types1) {
+ /* RPC fault */
+ return False;
+ }
+
+ if (UNMARSHALLING(ps))
+ r_u->types = (uint32 *)prs_alloc_mem(ps, sizeof(uint32)*r_u->num_types2);
+
+ if (!r_u->types) {
+ DEBUG(0, ("NULL types in samr_io_r_lookup_names\n"));
+ return False;
+ }
+
+ for (i = 0; i < r_u->num_types2; i++) {
+ slprintf(tmp, sizeof(tmp) - 1, "type[%02d] ", i);
+ if(!prs_uint32(tmp, ps, depth, &r_u->types[i]))
+ return False;
+ }
+ }
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_DELETE_DOM_USER structure.
+********************************************************************/
+
+void init_samr_q_delete_dom_user(SAMR_Q_DELETE_DOM_USER * q_c,
+ POLICY_HND *hnd)
+{
+ DEBUG(5, ("init_samr_q_delete_dom_user\n"));
+
+ q_c->user_pol = *hnd;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_delete_dom_user(char *desc, SAMR_Q_DELETE_DOM_USER * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_delete_dom_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("user_pol", &q_u->user_pol, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_delete_dom_user(char *desc, SAMR_R_DELETE_DOM_USER * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_delete_dom_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_open_user(SAMR_Q_OPEN_USER * q_u,
+ POLICY_HND *pol,
+ uint32 access_mask, uint32 rid)
+{
+ DEBUG(5, ("samr_init_samr_q_open_user\n"));
+
+ q_u->domain_pol = *pol;
+ q_u->access_mask = access_mask;
+ q_u->user_rid = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_open_user(char *desc, SAMR_Q_OPEN_USER * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+ if(!prs_uint32("user_rid ", ps, depth, &q_u->user_rid))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_open_user(char *desc, SAMR_R_OPEN_USER * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("user_pol", &r_u->user_pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_create_user(SAMR_Q_CREATE_USER * q_u,
+ POLICY_HND *pol,
+ const char *name,
+ uint32 acb_info, uint32 access_mask)
+{
+ int len_name;
+ len_name = strlen(name);
+
+ DEBUG(5, ("samr_init_samr_q_create_user\n"));
+
+ q_u->domain_pol = *pol;
+
+ init_uni_hdr(&q_u->hdr_name, len_name);
+ init_unistr2(&q_u->uni_name, name, len_name);
+
+ q_u->acb_info = acb_info;
+ q_u->access_mask = access_mask;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_create_user(char *desc, SAMR_Q_CREATE_USER * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_create_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_name", &q_u->hdr_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_name", &q_u->uni_name, q_u->hdr_name.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("acb_info ", ps, depth, &q_u->acb_info))
+ return False;
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_create_user(char *desc, SAMR_R_CREATE_USER * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_create_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("user_pol", &r_u->user_pol, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown_0", ps, depth, &r_u->unknown_0))
+ return False;
+ if(!prs_uint32("user_rid ", ps, depth, &r_u->user_rid))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_QUERY_USERINFO structure.
+********************************************************************/
+
+void init_samr_q_query_userinfo(SAMR_Q_QUERY_USERINFO * q_u,
+ POLICY_HND *hnd, uint16 switch_value)
+{
+ DEBUG(5, ("init_samr_q_query_userinfo\n"));
+
+ q_u->pol = *hnd;
+ q_u->switch_value = switch_value;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_query_userinfo(char *desc, SAMR_Q_QUERY_USERINFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_userinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value)) /* 0x0015 or 0x0011 */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a LOGON_HRS structure.
+********************************************************************/
+
+static BOOL sam_io_logon_hrs(char *desc, LOGON_HRS * hrs,
+ prs_struct *ps, int depth)
+{
+ if (hrs == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_logon_hrs");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("len ", ps, depth, &hrs->len))
+ return False;
+
+ if (hrs->len > sizeof(hrs->hours)) {
+ DEBUG(3, ("sam_io_logon_hrs: truncating length from %d\n", hrs->len));
+ hrs->len = sizeof(hrs->hours);
+ }
+
+ if(!prs_uint8s(False, "hours", ps, depth, hrs->hours, hrs->len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_USER_INFO_12 structure.
+********************************************************************/
+
+void init_sam_user_info12(SAM_USER_INFO_12 * usr,
+ const uint8 lm_pwd[16], const uint8 nt_pwd[16])
+{
+ DEBUG(5, ("init_sam_user_info12\n"));
+
+ usr->lm_pwd_active =
+ memcpy(usr->lm_pwd, lm_pwd, sizeof(usr->lm_pwd)) ? 1 : 0;
+ usr->nt_pwd_active =
+ memcpy(usr->nt_pwd, nt_pwd, sizeof(usr->nt_pwd)) ? 1 : 0;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info12(char *desc, SAM_USER_INFO_12 * u,
+ prs_struct *ps, int depth)
+{
+ if (u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_user_info12");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s(False, "lm_pwd", ps, depth, u->lm_pwd, sizeof(u->lm_pwd)))
+ return False;
+ if(!prs_uint8s(False, "nt_pwd", ps, depth, u->nt_pwd, sizeof(u->nt_pwd)))
+ return False;
+
+ if(!prs_uint8("lm_pwd_active", ps, depth, &u->lm_pwd_active))
+ return False;
+ if(!prs_uint8("nt_pwd_active", ps, depth, &u->nt_pwd_active))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_USER_INFO_10 structure.
+********************************************************************/
+
+void init_sam_user_info10(SAM_USER_INFO_10 * usr, uint32 acb_info)
+{
+ DEBUG(5, ("init_sam_user_info10\n"));
+
+ usr->acb_info = acb_info;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info10(char *desc, SAM_USER_INFO_10 * usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_user_info10");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("acb_info", ps, depth, &usr->acb_info))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_USER_INFO_11 structure.
+********************************************************************/
+
+void init_sam_user_info11(SAM_USER_INFO_11 * usr,
+ NTTIME * expiry,
+ char *mach_acct,
+ uint32 rid_user, uint32 rid_group, uint16 acct_ctrl)
+{
+ int len_mach_acct;
+
+ DEBUG(5, ("init_sam_user_info11\n"));
+
+ len_mach_acct = strlen(mach_acct);
+
+ memcpy(&(usr->expiry), expiry, sizeof(usr->expiry)); /* expiry time or something? */
+ ZERO_STRUCT(usr->padding_1); /* 0 - padding 24 bytes */
+
+ init_uni_hdr(&usr->hdr_mach_acct, len_mach_acct); /* unicode header for machine account */
+ usr->padding_2 = 0; /* 0 - padding 4 bytes */
+
+ usr->ptr_1 = 1; /* pointer */
+ ZERO_STRUCT(usr->padding_3); /* 0 - padding 32 bytes */
+ usr->padding_4 = 0; /* 0 - padding 4 bytes */
+
+ usr->ptr_2 = 1; /* pointer */
+ usr->padding_5 = 0; /* 0 - padding 4 bytes */
+
+ usr->ptr_3 = 1; /* pointer */
+ ZERO_STRUCT(usr->padding_6); /* 0 - padding 32 bytes */
+
+ usr->rid_user = rid_user;
+ usr->rid_group = rid_group;
+
+ usr->acct_ctrl = acct_ctrl;
+ usr->unknown_3 = 0x0000;
+
+ usr->unknown_4 = 0x003f; /* 0x003f - 16 bit unknown */
+ usr->unknown_5 = 0x003c; /* 0x003c - 16 bit unknown */
+
+ ZERO_STRUCT(usr->padding_7); /* 0 - padding 16 bytes */
+ usr->padding_8 = 0; /* 0 - padding 4 bytes */
+
+ init_unistr2(&usr->uni_mach_acct, mach_acct, len_mach_acct); /* unicode string for machine account */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info11(char *desc, SAM_USER_INFO_11 * usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_11");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s(False, "padding_0", ps, depth, usr->padding_0, sizeof(usr->padding_0)))
+ return False;
+
+ if(!smb_io_time("time", &usr->expiry, ps, depth))
+ return False;
+
+ if(!prs_uint8s(False, "padding_1", ps, depth, usr->padding_1, sizeof(usr->padding_1)))
+ return False;
+
+ if(!smb_io_unihdr("unihdr", &usr->hdr_mach_acct, ps, depth))
+ return False;
+
+ if(!prs_uint32("padding_2", ps, depth, &usr->padding_2))
+ return False;
+
+ if(!prs_uint32("ptr_1 ", ps, depth, &usr->ptr_1))
+ return False;
+ if(!prs_uint8s(False, "padding_3", ps, depth, usr->padding_3, sizeof(usr->padding_3)))
+ return False;
+
+ if(!prs_uint32("padding_4", ps, depth, &usr->padding_4))
+ return False;
+
+ if(!prs_uint32("ptr_2 ", ps, depth, &usr->ptr_2))
+ return False;
+ if(!prs_uint32("padding_5", ps, depth, &usr->padding_5))
+ return False;
+
+ if(!prs_uint32("ptr_3 ", ps, depth, &usr->ptr_3))
+ return False;
+ if(!prs_uint8s(False, "padding_6", ps, depth, usr->padding_6,sizeof(usr->padding_6)))
+ return False;
+
+ if(!prs_uint32("rid_user ", ps, depth, &usr->rid_user))
+ return False;
+ if(!prs_uint32("rid_group", ps, depth, &usr->rid_group))
+ return False;
+ if(!prs_uint16("acct_ctrl", ps, depth, &usr->acct_ctrl))
+ return False;
+ if(!prs_uint16("unknown_3", ps, depth, &usr->unknown_3))
+ return False;
+ if(!prs_uint16("unknown_4", ps, depth, &usr->unknown_4))
+ return False;
+ if(!prs_uint16("unknown_5", ps, depth, &usr->unknown_5))
+ return False;
+
+ if(!prs_uint8s(False, "padding_7", ps, depth, usr->padding_7, sizeof(usr->padding_7)))
+ return False;
+
+ if(!prs_uint32("padding_8", ps, depth, &(usr->padding_8)))
+ return False;
+
+ if(!smb_io_unistr2("unistr2", &usr->uni_mach_acct, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s(False, "padding_9", ps, depth, usr->padding_9, sizeof(usr->padding_9)))
+ return False;
+
+ return True;
+}
+
+/*************************************************************************
+ init_sam_user_infoa
+
+ unknown_3 = 0x09f8 27fa
+ unknown_5 = 0x0001 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+
+void init_sam_user_info24(SAM_USER_INFO_24 * usr, char newpass[516], uint16 pw_len)
+{
+ DEBUG(10, ("init_sam_user_info24:\n"));
+ memcpy(usr->pass, newpass, sizeof(usr->pass));
+ usr->pw_len = pw_len;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info24(char *desc, SAM_USER_INFO_24 * usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_user_info24");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint8s(False, "password", ps, depth, usr->pass,
+ sizeof(usr->pass)))
+ return False;
+
+ if (MARSHALLING(ps) && (usr->pw_len != 0)) {
+ if (!prs_uint16("pw_len", ps, depth, &usr->pw_len))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*************************************************************************
+ init_sam_user_info23
+
+ unknown_3 = 0x09f8 27fa
+ unknown_5 = 0x0001 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+
+void init_sam_user_info23W(SAM_USER_INFO_23 * usr, NTTIME * logon_time, /* all zeros */
+ NTTIME * logoff_time, /* all zeros */
+ NTTIME * kickoff_time, /* all zeros */
+ NTTIME * pass_last_set_time, /* all zeros */
+ NTTIME * pass_can_change_time, /* all zeros */
+ NTTIME * pass_must_change_time, /* all zeros */
+ UNISTR2 *user_name,
+ UNISTR2 *full_name,
+ UNISTR2 *home_dir,
+ UNISTR2 *dir_drive,
+ UNISTR2 *log_scr,
+ UNISTR2 *prof_path,
+ UNISTR2 *desc,
+ UNISTR2 *wkstas,
+ UNISTR2 *unk_str,
+ UNISTR2 *mung_dial,
+ uint32 user_rid, /* 0x0000 0000 */
+ uint32 group_rid,
+ uint32 acb_info,
+ uint32 unknown_3,
+ uint16 logon_divs,
+ LOGON_HRS * hrs,
+ uint32 unknown_5,
+ char newpass[516], uint32 unknown_6)
+{
+ int len_user_name = user_name != NULL ? user_name->uni_str_len : 0;
+ int len_full_name = full_name != NULL ? full_name->uni_str_len : 0;
+ int len_home_dir = home_dir != NULL ? home_dir->uni_str_len : 0;
+ int len_dir_drive = dir_drive != NULL ? dir_drive->uni_str_len : 0;
+ int len_logon_script = log_scr != NULL ? log_scr->uni_str_len : 0;
+ int len_profile_path = prof_path != NULL ? prof_path->uni_str_len : 0;
+ int len_description = desc != NULL ? desc->uni_str_len : 0;
+ int len_workstations = wkstas != NULL ? wkstas->uni_str_len : 0;
+ int len_unknown_str = unk_str != NULL ? unk_str->uni_str_len : 0;
+ int len_munged_dial = mung_dial != NULL ? mung_dial->uni_str_len : 0;
+
+ usr->logon_time = *logon_time; /* all zeros */
+ usr->logoff_time = *logoff_time; /* all zeros */
+ usr->kickoff_time = *kickoff_time; /* all zeros */
+ usr->pass_last_set_time = *pass_last_set_time; /* all zeros */
+ usr->pass_can_change_time = *pass_can_change_time; /* all zeros */
+ usr->pass_must_change_time = *pass_must_change_time; /* all zeros */
+
+ init_uni_hdr(&usr->hdr_user_name, len_user_name); /* NULL */
+ init_uni_hdr(&usr->hdr_full_name, len_full_name);
+ init_uni_hdr(&usr->hdr_home_dir, len_home_dir);
+ init_uni_hdr(&usr->hdr_dir_drive, len_dir_drive);
+ init_uni_hdr(&usr->hdr_logon_script, len_logon_script);
+ init_uni_hdr(&usr->hdr_profile_path, len_profile_path);
+ init_uni_hdr(&usr->hdr_acct_desc, len_description);
+ init_uni_hdr(&usr->hdr_workstations, len_workstations);
+ init_uni_hdr(&usr->hdr_unknown_str, len_unknown_str);
+ init_uni_hdr(&usr->hdr_munged_dial, len_munged_dial);
+
+ ZERO_STRUCT(usr->nt_pwd);
+ ZERO_STRUCT(usr->lm_pwd);
+
+ usr->user_rid = user_rid; /* 0x0000 0000 */
+ usr->group_rid = group_rid;
+ usr->acb_info = acb_info;
+ usr->unknown_3 = unknown_3; /* 09f8 27fa */
+
+ usr->logon_divs = logon_divs; /* should be 168 (hours/week) */
+ usr->ptr_logon_hrs = hrs ? 1 : 0;
+
+ ZERO_STRUCT(usr->padding1);
+
+ usr->unknown_5 = unknown_5; /* 0x0001 0000 */
+
+ memcpy(usr->pass, newpass, sizeof(usr->pass));
+
+ copy_unistr2(&usr->uni_user_name, user_name);
+ copy_unistr2(&usr->uni_full_name, full_name);
+ copy_unistr2(&usr->uni_home_dir, home_dir);
+ copy_unistr2(&usr->uni_dir_drive, dir_drive);
+ copy_unistr2(&usr->uni_logon_script, log_scr);
+ copy_unistr2(&usr->uni_profile_path, prof_path);
+ copy_unistr2(&usr->uni_acct_desc, desc);
+ copy_unistr2(&usr->uni_workstations, wkstas);
+ copy_unistr2(&usr->uni_unknown_str, unk_str);
+ copy_unistr2(&usr->uni_munged_dial, mung_dial);
+
+ usr->unknown_6 = unknown_6; /* 0x0000 04ec */
+ usr->padding4 = 0;
+
+ memcpy(&usr->logon_hrs, hrs, sizeof(usr->logon_hrs));
+}
+
+/*************************************************************************
+ init_sam_user_info23
+
+ unknown_3 = 0x09f8 27fa
+ unknown_5 = 0x0001 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+
+void init_sam_user_info23A(SAM_USER_INFO_23 * usr, NTTIME * logon_time, /* all zeros */
+ NTTIME * logoff_time, /* all zeros */
+ NTTIME * kickoff_time, /* all zeros */
+ NTTIME * pass_last_set_time, /* all zeros */
+ NTTIME * pass_can_change_time, /* all zeros */
+ NTTIME * pass_must_change_time, /* all zeros */
+ char *user_name, /* NULL */
+ char *full_name,
+ char *home_dir, char *dir_drive, char *log_scr,
+ char *prof_path, char *desc, char *wkstas,
+ char *unk_str, char *mung_dial, uint32 user_rid, /* 0x0000 0000 */
+ uint32 group_rid, uint32 acb_info,
+ uint32 unknown_3, uint16 logon_divs,
+ LOGON_HRS * hrs, uint32 unknown_5,
+ char newpass[516], uint32 unknown_6)
+{
+ int len_user_name = user_name != NULL ? strlen(user_name) : 0;
+ int len_full_name = full_name != NULL ? strlen(full_name) : 0;
+ int len_home_dir = home_dir != NULL ? strlen(home_dir) : 0;
+ int len_dir_drive = dir_drive != NULL ? strlen(dir_drive) : 0;
+ int len_logon_script = log_scr != NULL ? strlen(log_scr) : 0;
+ int len_profile_path = prof_path != NULL ? strlen(prof_path) : 0;
+ int len_description = desc != NULL ? strlen(desc) : 0;
+ int len_workstations = wkstas != NULL ? strlen(wkstas) : 0;
+ int len_unknown_str = unk_str != NULL ? strlen(unk_str) : 0;
+ int len_munged_dial = mung_dial != NULL ? strlen(mung_dial) : 0;
+
+ usr->logon_time = *logon_time; /* all zeros */
+ usr->logoff_time = *logoff_time; /* all zeros */
+ usr->kickoff_time = *kickoff_time; /* all zeros */
+ usr->pass_last_set_time = *pass_last_set_time; /* all zeros */
+ usr->pass_can_change_time = *pass_can_change_time; /* all zeros */
+ usr->pass_must_change_time = *pass_must_change_time; /* all zeros */
+
+ init_uni_hdr(&usr->hdr_user_name, len_user_name); /* NULL */
+ init_uni_hdr(&usr->hdr_full_name, len_full_name);
+ init_uni_hdr(&usr->hdr_home_dir, len_home_dir);
+ init_uni_hdr(&usr->hdr_dir_drive, len_dir_drive);
+ init_uni_hdr(&usr->hdr_logon_script, len_logon_script);
+ init_uni_hdr(&usr->hdr_profile_path, len_profile_path);
+ init_uni_hdr(&usr->hdr_acct_desc, len_description);
+ init_uni_hdr(&usr->hdr_workstations, len_workstations);
+ init_uni_hdr(&usr->hdr_unknown_str, len_unknown_str);
+ init_uni_hdr(&usr->hdr_munged_dial, len_munged_dial);
+
+ ZERO_STRUCT(usr->nt_pwd);
+ ZERO_STRUCT(usr->lm_pwd);
+
+ usr->user_rid = user_rid; /* 0x0000 0000 */
+ usr->group_rid = group_rid;
+ usr->acb_info = acb_info;
+ usr->unknown_3 = unknown_3; /* 09f8 27fa */
+
+ usr->logon_divs = logon_divs; /* should be 168 (hours/week) */
+ usr->ptr_logon_hrs = hrs ? 1 : 0;
+
+ ZERO_STRUCT(usr->padding1);
+
+ usr->unknown_5 = unknown_5; /* 0x0001 0000 */
+
+ memcpy(usr->pass, newpass, sizeof(usr->pass));
+
+ init_unistr2(&usr->uni_user_name, user_name, len_user_name); /* NULL */
+ init_unistr2(&usr->uni_full_name, full_name, len_full_name);
+ init_unistr2(&usr->uni_home_dir, home_dir, len_home_dir);
+ init_unistr2(&usr->uni_dir_drive, dir_drive, len_dir_drive);
+ init_unistr2(&usr->uni_logon_script, log_scr, len_logon_script);
+ init_unistr2(&usr->uni_profile_path, prof_path, len_profile_path);
+ init_unistr2(&usr->uni_acct_desc, desc, len_description);
+ init_unistr2(&usr->uni_workstations, wkstas, len_workstations);
+ init_unistr2(&usr->uni_unknown_str, unk_str, len_unknown_str);
+ init_unistr2(&usr->uni_munged_dial, mung_dial, len_munged_dial);
+
+ usr->unknown_6 = unknown_6; /* 0x0000 04ec */
+ usr->padding4 = 0;
+
+ memcpy(&usr->logon_hrs, hrs, sizeof(usr->logon_hrs));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info23(char *desc, SAM_USER_INFO_23 * usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_user_info23");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_time("logon_time ", &usr->logon_time, ps, depth))
+ return False;
+ if(!smb_io_time("logoff_time ", &usr->logoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("kickoff_time ", &usr->kickoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_last_set_time ", &usr->pass_last_set_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_can_change_time ", &usr->pass_can_change_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_must_change_time", &usr->pass_must_change_time, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_user_name ", &usr->hdr_user_name, ps, depth)) /* username unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_full_name ", &usr->hdr_full_name, ps, depth)) /* user's full name unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_home_dir ", &usr->hdr_home_dir, ps, depth)) /* home directory unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_dir_drive ", &usr->hdr_dir_drive, ps, depth)) /* home directory drive */
+ return False;
+ if(!smb_io_unihdr("hdr_logon_script", &usr->hdr_logon_script, ps, depth)) /* logon script unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_profile_path", &usr->hdr_profile_path, ps, depth)) /* profile path unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_acct_desc ", &usr->hdr_acct_desc, ps, depth)) /* account desc */
+ return False;
+ if(!smb_io_unihdr("hdr_workstations", &usr->hdr_workstations, ps, depth)) /* wkstas user can log on from */
+ return False;
+ if(!smb_io_unihdr("hdr_unknown_str ", &usr->hdr_unknown_str, ps, depth)) /* unknown string */
+ return False;
+ if(!smb_io_unihdr("hdr_munged_dial ", &usr->hdr_munged_dial, ps, depth)) /* wkstas user can log on from */
+ return False;
+
+ if(!prs_uint8s(False, "lm_pwd ", ps, depth, usr->lm_pwd, sizeof(usr->lm_pwd)))
+ return False;
+ if(!prs_uint8s(False, "nt_pwd ", ps, depth, usr->nt_pwd, sizeof(usr->nt_pwd)))
+ return False;
+
+ if(!prs_uint32("user_rid ", ps, depth, &usr->user_rid)) /* User ID */
+ return False;
+ if(!prs_uint32("group_rid ", ps, depth, &usr->group_rid)) /* Group ID */
+ return False;
+ if(!prs_uint32("acb_info ", ps, depth, &usr->acb_info))
+ return False;
+
+ if(!prs_uint32("unknown_3 ", ps, depth, &usr->unknown_3))
+ return False;
+ if(!prs_uint16("logon_divs ", ps, depth, &usr->logon_divs)) /* logon divisions per week */
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("ptr_logon_hrs ", ps, depth, &usr->ptr_logon_hrs))
+ return False;
+ if(!prs_uint8s(False, "padding1 ", ps, depth, usr->padding1, sizeof(usr->padding1)))
+ return False;
+ if(!prs_uint32("unknown_5 ", ps, depth, &usr->unknown_5))
+ return False;
+
+ if(!prs_uint8s(False, "password ", ps, depth, usr->pass, sizeof(usr->pass)))
+ return False;
+
+ /* here begins pointed-to data */
+
+ if(!smb_io_unistr2("uni_user_name ", &usr->uni_user_name, usr->hdr_user_name.buffer, ps, depth)) /* username unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_full_name ", &usr->uni_full_name, usr->hdr_full_name.buffer, ps, depth)) /* user's full name unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_home_dir ", &usr->uni_home_dir, usr->hdr_home_dir.buffer, ps, depth)) /* home directory unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_dir_drive ", &usr->uni_dir_drive, usr->hdr_dir_drive.buffer, ps, depth)) /* home directory drive unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_logon_script", &usr->uni_logon_script, usr->hdr_logon_script.buffer, ps, depth)) /* logon script unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_profile_path", &usr->uni_profile_path, usr->hdr_profile_path.buffer, ps, depth)) /* profile path unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_desc ", &usr->uni_acct_desc, usr->hdr_acct_desc.buffer, ps, depth)) /* user desc unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_workstations", &usr->uni_workstations, usr->hdr_workstations.buffer, ps, depth)) /* worksations user can log on from */
+ return False;
+
+ if(!smb_io_unistr2("uni_unknown_str ", &usr->uni_unknown_str, usr->hdr_unknown_str.buffer, ps, depth)) /* unknown string */
+ return False;
+
+ if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial, usr->hdr_munged_dial.buffer, ps, depth))
+ return False;
+
+ /* ok, this is only guess-work (as usual) */
+ if (usr->ptr_logon_hrs) {
+ if(!prs_uint32("unknown_6 ", ps, depth, &usr->unknown_6))
+ return False;
+ if(!prs_uint32("padding4 ", ps, depth, &usr->padding4))
+ return False;
+ if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth))
+ return False;
+ } else if (UNMARSHALLING(ps)) {
+ usr->unknown_6 = 0;
+ usr->padding4 = 0;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ reads or writes a structure.
+ NB. This structure is *definately* incorrect. It's my best guess
+ currently for W2K SP2. The password field is encrypted in a different
+ way than normal... And there are definately other problems. JRA.
+********************************************************************/
+
+static BOOL sam_io_user_info25(char *desc, SAM_USER_INFO_25 * usr, prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_user_info23");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_time("logon_time ", &usr->logon_time, ps, depth))
+ return False;
+ if(!smb_io_time("logoff_time ", &usr->logoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("kickoff_time ", &usr->kickoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_last_set_time ", &usr->pass_last_set_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_can_change_time ", &usr->pass_can_change_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_must_change_time", &usr->pass_must_change_time, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_user_name ", &usr->hdr_user_name, ps, depth)) /* username unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_full_name ", &usr->hdr_full_name, ps, depth)) /* user's full name unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_home_dir ", &usr->hdr_home_dir, ps, depth)) /* home directory unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_dir_drive ", &usr->hdr_dir_drive, ps, depth)) /* home directory drive */
+ return False;
+ if(!smb_io_unihdr("hdr_logon_script", &usr->hdr_logon_script, ps, depth)) /* logon script unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_profile_path", &usr->hdr_profile_path, ps, depth)) /* profile path unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_acct_desc ", &usr->hdr_acct_desc, ps, depth)) /* account desc */
+ return False;
+ if(!smb_io_unihdr("hdr_workstations", &usr->hdr_workstations, ps, depth)) /* wkstas user can log on from */
+ return False;
+ if(!smb_io_unihdr("hdr_unknown_str ", &usr->hdr_unknown_str, ps, depth)) /* unknown string */
+ return False;
+ if(!smb_io_unihdr("hdr_munged_dial ", &usr->hdr_munged_dial, ps, depth)) /* wkstas user can log on from */
+ return False;
+
+ if(!prs_uint8s(False, "lm_pwd ", ps, depth, usr->lm_pwd, sizeof(usr->lm_pwd)))
+ return False;
+ if(!prs_uint8s(False, "nt_pwd ", ps, depth, usr->nt_pwd, sizeof(usr->nt_pwd)))
+ return False;
+
+ if(!prs_uint32("user_rid ", ps, depth, &usr->user_rid)) /* User ID */
+ return False;
+ if(!prs_uint32("group_rid ", ps, depth, &usr->group_rid)) /* Group ID */
+ return False;
+ if(!prs_uint32("acb_info ", ps, depth, &usr->acb_info))
+ return False;
+
+ if(!prs_uint32s(False, "unknown_6 ", ps, depth, usr->unknown_6, 6))
+ return False;
+
+ if(!prs_uint8s(False, "password ", ps, depth, usr->pass, sizeof(usr->pass)))
+ return False;
+
+ /* here begins pointed-to data */
+
+ if(!smb_io_unistr2("uni_user_name ", &usr->uni_user_name, usr->hdr_user_name.buffer, ps, depth)) /* username unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_full_name ", &usr->uni_full_name, usr->hdr_full_name.buffer, ps, depth)) /* user's full name unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_home_dir ", &usr->uni_home_dir, usr->hdr_home_dir.buffer, ps, depth)) /* home directory unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_dir_drive ", &usr->uni_dir_drive, usr->hdr_dir_drive.buffer, ps, depth)) /* home directory drive unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_logon_script", &usr->uni_logon_script, usr->hdr_logon_script.buffer, ps, depth)) /* logon script unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_profile_path", &usr->uni_profile_path, usr->hdr_profile_path.buffer, ps, depth)) /* profile path unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_acct_desc ", &usr->uni_acct_desc, usr->hdr_acct_desc.buffer, ps, depth)) /* user desc unicode string */
+ return False;
+
+ if(!smb_io_unistr2("uni_workstations", &usr->uni_workstations, usr->hdr_workstations.buffer, ps, depth)) /* worksations user can log on from */
+ return False;
+
+ if(!smb_io_unistr2("uni_unknown_str ", &usr->uni_unknown_str, usr->hdr_unknown_str.buffer, ps, depth)) /* unknown string */
+ return False;
+
+ if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial, usr->hdr_munged_dial.buffer, ps, depth))
+ return False;
+
+#if 0 /* JRA - unknown... */
+ /* ok, this is only guess-work (as usual) */
+ if (usr->ptr_logon_hrs) {
+ if(!prs_uint32("unknown_6 ", ps, depth, &usr->unknown_6))
+ return False;
+ if(!prs_uint32("padding4 ", ps, depth, &usr->padding4))
+ return False;
+ if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth))
+ return False;
+ } else if (UNMARSHALLING(ps)) {
+ usr->unknown_6 = 0;
+ usr->padding4 = 0;
+ }
+#endif
+
+ return True;
+}
+
+
+/*************************************************************************
+ init_sam_user_info21W
+
+ unknown_3 = 0x00ff ffff
+ unknown_5 = 0x0002 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+
+void init_sam_user_info21W(SAM_USER_INFO_21 * usr,
+ NTTIME * logon_time,
+ NTTIME * logoff_time,
+ NTTIME * kickoff_time,
+ NTTIME * pass_last_set_time,
+ NTTIME * pass_can_change_time,
+ NTTIME * pass_must_change_time,
+ UNISTR2 *user_name,
+ UNISTR2 *full_name,
+ UNISTR2 *home_dir,
+ UNISTR2 *dir_drive,
+ UNISTR2 *log_scr,
+ UNISTR2 *prof_path,
+ UNISTR2 *desc,
+ UNISTR2 *wkstas,
+ UNISTR2 *unk_str,
+ UNISTR2 *mung_dial,
+ uchar lm_pwd[16],
+ uchar nt_pwd[16],
+ uint32 user_rid,
+ uint32 group_rid,
+ uint32 acb_info,
+ uint32 unknown_3,
+ uint16 logon_divs,
+ LOGON_HRS * hrs,
+ uint32 unknown_5, uint32 unknown_6)
+{
+ int len_user_name = user_name != NULL ? user_name->uni_str_len : 0;
+ int len_full_name = full_name != NULL ? full_name->uni_str_len : 0;
+ int len_home_dir = home_dir != NULL ? home_dir->uni_str_len : 0;
+ int len_dir_drive = dir_drive != NULL ? dir_drive->uni_str_len : 0;
+ int len_logon_script = log_scr != NULL ? log_scr->uni_str_len : 0;
+ int len_profile_path = prof_path != NULL ? prof_path->uni_str_len : 0;
+ int len_description = desc != NULL ? desc->uni_str_len : 0;
+ int len_workstations = wkstas != NULL ? wkstas->uni_str_len : 0;
+ int len_unknown_str = unk_str != NULL ? unk_str->uni_str_len : 0;
+ int len_munged_dial = mung_dial != NULL ? mung_dial->uni_str_len : 0;
+
+ usr->logon_time = *logon_time;
+ usr->logoff_time = *logoff_time;
+ usr->kickoff_time = *kickoff_time;
+ usr->pass_last_set_time = *pass_last_set_time;
+ usr->pass_can_change_time = *pass_can_change_time;
+ usr->pass_must_change_time = *pass_must_change_time;
+
+ init_uni_hdr(&usr->hdr_user_name, len_user_name);
+ init_uni_hdr(&usr->hdr_full_name, len_full_name);
+ init_uni_hdr(&usr->hdr_home_dir, len_home_dir);
+ init_uni_hdr(&usr->hdr_dir_drive, len_dir_drive);
+ init_uni_hdr(&usr->hdr_logon_script, len_logon_script);
+ init_uni_hdr(&usr->hdr_profile_path, len_profile_path);
+ init_uni_hdr(&usr->hdr_acct_desc, len_description);
+ init_uni_hdr(&usr->hdr_workstations, len_workstations);
+ init_uni_hdr(&usr->hdr_unknown_str, len_unknown_str);
+ init_uni_hdr(&usr->hdr_munged_dial, len_munged_dial);
+
+ memcpy(usr->lm_pwd, lm_pwd, sizeof(usr->lm_pwd));
+ memcpy(usr->nt_pwd, nt_pwd, sizeof(usr->nt_pwd));
+
+ usr->user_rid = user_rid;
+ usr->group_rid = group_rid;
+ usr->acb_info = acb_info;
+ usr->unknown_3 = unknown_3; /* 0x00ff ffff */
+
+ usr->logon_divs = logon_divs; /* should be 168 (hours/week) */
+ usr->ptr_logon_hrs = hrs ? 1 : 0;
+ usr->unknown_5 = unknown_5; /* 0x0002 0000 */
+
+ ZERO_STRUCT(usr->padding1);
+
+ copy_unistr2(&usr->uni_user_name, user_name);
+ copy_unistr2(&usr->uni_full_name, full_name);
+ copy_unistr2(&usr->uni_home_dir, home_dir);
+ copy_unistr2(&usr->uni_dir_drive, dir_drive);
+ copy_unistr2(&usr->uni_logon_script, log_scr);
+ copy_unistr2(&usr->uni_profile_path, prof_path);
+ copy_unistr2(&usr->uni_acct_desc, desc);
+ copy_unistr2(&usr->uni_workstations, wkstas);
+ copy_unistr2(&usr->uni_unknown_str, unk_str);
+ copy_unistr2(&usr->uni_munged_dial, mung_dial);
+
+ usr->unknown_6 = unknown_6; /* 0x0000 04ec */
+ usr->padding4 = 0;
+
+ memcpy(&usr->logon_hrs, hrs, sizeof(usr->logon_hrs));
+}
+
+/*************************************************************************
+ init_sam_user_info21
+
+ unknown_3 = 0x00ff ffff
+ unknown_5 = 0x0002 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+
+void init_sam_user_info21A(SAM_USER_INFO_21 *usr, SAM_ACCOUNT *pw)
+{
+ NTTIME logon_time, logoff_time, kickoff_time,
+ pass_last_set_time, pass_can_change_time,
+ pass_must_change_time;
+
+ int len_user_name, len_full_name, len_home_dir,
+ len_dir_drive, len_logon_script, len_profile_path,
+ len_description, len_workstations, len_unknown_str,
+ len_munged_dial;
+
+ const char* user_name = pdb_get_username(pw);
+ const char* full_name = pdb_get_fullname(pw);
+ const char* home_dir = pdb_get_homedir(pw);
+ const char* dir_drive = pdb_get_dirdrive(pw);
+ const char* logon_script = pdb_get_logon_script(pw);
+ const char* profile_path = pdb_get_profile_path(pw);
+ const char* description = pdb_get_acct_desc(pw);
+ const char* workstations = pdb_get_workstations(pw);
+ const char* munged_dial = pdb_get_munged_dial(pw);
+
+ len_user_name = user_name != NULL ? strlen(user_name )+1 : 0;
+ len_full_name = full_name != NULL ? strlen(full_name )+1 : 0;
+ len_home_dir = home_dir != NULL ? strlen(home_dir )+1 : 0;
+ len_dir_drive = dir_drive != NULL ? strlen(dir_drive )+1 : 0;
+ len_logon_script = logon_script != NULL ? strlen(logon_script)+1 : 0;
+ len_profile_path = profile_path != NULL ? strlen(profile_path)+1 : 0;
+ len_description = description != NULL ? strlen(description )+1 : 0;
+ len_workstations = workstations != NULL ? strlen(workstations)+1 : 0;
+ len_unknown_str = 0;
+ len_munged_dial = munged_dial != NULL ? strlen(munged_dial )+1 : 0;
+
+
+ /* Create NTTIME structs */
+ unix_to_nt_time (&logon_time, pdb_get_logon_time(pw));
+ unix_to_nt_time (&logoff_time, pdb_get_logoff_time(pw));
+ unix_to_nt_time (&kickoff_time, pdb_get_kickoff_time(pw));
+ unix_to_nt_time (&pass_last_set_time, pdb_get_pass_last_set_time(pw));
+ unix_to_nt_time (&pass_can_change_time, pdb_get_pass_can_change_time(pw));
+ unix_to_nt_time (&pass_must_change_time,pdb_get_pass_must_change_time(pw));
+
+ /* structure assignment */
+ usr->logon_time = logon_time;
+ usr->logoff_time = logoff_time;
+ usr->kickoff_time = kickoff_time;
+ usr->pass_last_set_time = pass_last_set_time;
+ usr->pass_can_change_time = pass_can_change_time;
+ usr->pass_must_change_time = pass_must_change_time;
+
+ init_uni_hdr(&usr->hdr_user_name, len_user_name);
+ init_uni_hdr(&usr->hdr_full_name, len_full_name);
+ init_uni_hdr(&usr->hdr_home_dir, len_home_dir);
+ init_uni_hdr(&usr->hdr_dir_drive, len_dir_drive);
+ init_uni_hdr(&usr->hdr_logon_script, len_logon_script);
+ init_uni_hdr(&usr->hdr_profile_path, len_profile_path);
+ init_uni_hdr(&usr->hdr_acct_desc, len_description);
+ init_uni_hdr(&usr->hdr_workstations, len_workstations);
+ init_uni_hdr(&usr->hdr_unknown_str, len_unknown_str);
+ init_uni_hdr(&usr->hdr_munged_dial, len_munged_dial);
+
+ ZERO_STRUCT(usr->nt_pwd);
+ ZERO_STRUCT(usr->lm_pwd);
+
+ usr->user_rid = pdb_get_user_rid(pw);
+ usr->group_rid = pdb_get_group_rid(pw);
+ usr->acb_info = pdb_get_acct_ctrl(pw);
+ usr->unknown_3 = pdb_get_unknown3(pw);
+
+ usr->logon_divs = pdb_get_logon_divs(pw);
+ usr->ptr_logon_hrs = pdb_get_hours(pw) ? 1 : 0;
+ usr->unknown_5 = pdb_get_unknown5(pw); /* 0x0002 0000 */
+
+ ZERO_STRUCT(usr->padding1);
+
+ init_unistr2(&usr->uni_user_name, user_name, len_user_name);
+ init_unistr2(&usr->uni_full_name, full_name, len_full_name);
+ init_unistr2(&usr->uni_home_dir, home_dir, len_home_dir);
+ init_unistr2(&usr->uni_dir_drive, dir_drive, len_dir_drive);
+ init_unistr2(&usr->uni_logon_script, logon_script, len_logon_script);
+ init_unistr2(&usr->uni_profile_path, profile_path, len_profile_path);
+ init_unistr2(&usr->uni_acct_desc, description, len_description);
+ init_unistr2(&usr->uni_workstations, workstations, len_workstations);
+ init_unistr2(&usr->uni_unknown_str, NULL, len_unknown_str);
+ init_unistr2(&usr->uni_munged_dial, munged_dial, len_munged_dial);
+
+ usr->unknown_6 = pdb_get_unknown6(pw);
+ usr->padding4 = 0;
+
+ if (pdb_get_hours(pw)) {
+ usr->logon_hrs.len = pdb_get_hours_len(pw);
+ memcpy(&usr->logon_hrs.hours, pdb_get_hours(pw), MAX_HOURS_LEN);
+ } else
+ memset(&usr->logon_hrs, 0xff, sizeof(usr->logon_hrs));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info21(char *desc, SAM_USER_INFO_21 * usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_user_info21");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_time("logon_time ", &usr->logon_time, ps, depth))
+ return False;
+ if(!smb_io_time("logoff_time ", &usr->logoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_last_set_time ", &usr->pass_last_set_time, ps,depth))
+ return False;
+ if(!smb_io_time("kickoff_time ", &usr->kickoff_time, ps, depth))
+ return False;
+ if(!smb_io_time("pass_can_change_time ", &usr->pass_can_change_time, ps,depth))
+ return False;
+ if(!smb_io_time("pass_must_change_time", &usr->pass_must_change_time, ps, depth))
+ return False;
+
+ if(!smb_io_unihdr("hdr_user_name ", &usr->hdr_user_name, ps, depth)) /* username unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_full_name ", &usr->hdr_full_name, ps, depth)) /* user's full name unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_home_dir ", &usr->hdr_home_dir, ps, depth)) /* home directory unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_dir_drive ", &usr->hdr_dir_drive, ps, depth)) /* home directory drive */
+ return False;
+ if(!smb_io_unihdr("hdr_logon_script", &usr->hdr_logon_script, ps, depth)) /* logon script unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_profile_path", &usr->hdr_profile_path, ps, depth)) /* profile path unicode string header */
+ return False;
+ if(!smb_io_unihdr("hdr_acct_desc ", &usr->hdr_acct_desc, ps, depth)) /* account desc */
+ return False;
+ if(!smb_io_unihdr("hdr_workstations", &usr->hdr_workstations, ps, depth)) /* wkstas user can log on from */
+ return False;
+ if(!smb_io_unihdr("hdr_unknown_str ", &usr->hdr_unknown_str, ps, depth)) /* unknown string */
+ return False;
+ if(!smb_io_unihdr("hdr_munged_dial ", &usr->hdr_munged_dial, ps, depth)) /* wkstas user can log on from */
+ return False;
+
+ if(!prs_uint8s(False, "lm_pwd ", ps, depth, usr->lm_pwd, sizeof(usr->lm_pwd)))
+ return False;
+ if(!prs_uint8s(False, "nt_pwd ", ps, depth, usr->nt_pwd, sizeof(usr->nt_pwd)))
+ return False;
+
+ if(!prs_uint32("user_rid ", ps, depth, &usr->user_rid)) /* User ID */
+ return False;
+ if(!prs_uint32("group_rid ", ps, depth, &usr->group_rid)) /* Group ID */
+ return False;
+ if(!prs_uint32("acb_info ", ps, depth, &usr->acb_info))
+ return False;
+
+ if(!prs_uint32("unknown_3 ", ps, depth, &usr->unknown_3))
+ return False;
+ if(!prs_uint16("logon_divs ", ps, depth, &usr->logon_divs)) /* logon divisions per week */
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("ptr_logon_hrs ", ps, depth, &usr->ptr_logon_hrs))
+ return False;
+ if(!prs_uint32("unknown_5 ", ps, depth, &usr->unknown_5))
+ return False;
+
+ if(!prs_uint8s(False, "padding1 ", ps, depth, usr->padding1, sizeof(usr->padding1)))
+ return False;
+
+ /* here begins pointed-to data */
+
+ if(!smb_io_unistr2("uni_user_name ", &usr->uni_user_name,usr->hdr_user_name.buffer, ps, depth)) /* username unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_full_name ", &usr->uni_full_name, usr->hdr_full_name.buffer, ps, depth)) /* user's full name unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_home_dir ", &usr->uni_home_dir, usr->hdr_home_dir.buffer, ps, depth)) /* home directory unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_dir_drive ", &usr->uni_dir_drive, usr->hdr_dir_drive.buffer, ps, depth)) /* home directory drive unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_logon_script", &usr->uni_logon_script, usr->hdr_logon_script.buffer, ps, depth)) /* logon script unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_profile_path", &usr->uni_profile_path, usr->hdr_profile_path.buffer, ps, depth)) /* profile path unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_acct_desc ", &usr->uni_acct_desc, usr->hdr_acct_desc.buffer, ps, depth)) /* user desc unicode string */
+ return False;
+ if(!smb_io_unistr2("uni_workstations", &usr->uni_workstations, usr->hdr_workstations.buffer, ps, depth)) /* worksations user can log on from */
+ return False;
+ if(!smb_io_unistr2("uni_unknown_str ", &usr->uni_unknown_str, usr->hdr_unknown_str.buffer, ps, depth)) /* unknown string */
+ return False;
+ if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial,usr->hdr_munged_dial.buffer, ps, depth)) /* worksations user can log on from */
+ return False;
+
+ /* ok, this is only guess-work (as usual) */
+ if (usr->ptr_logon_hrs) {
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("unknown_6 ", ps, depth, &usr->unknown_6))
+ return False;
+ if(!prs_uint32("padding4 ", ps, depth, &usr->padding4))
+ return False;
+ if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth))
+ return False;
+ } else if (UNMARSHALLING(ps)) {
+ usr->unknown_6 = 0;
+ usr->padding4 = 0;
+ }
+
+ return True;
+}
+
+void init_sam_user_info20A(SAM_USER_INFO_20 *usr, SAM_ACCOUNT *pw)
+{
+ int len_munged_dial;
+ const char* munged_dial = pdb_get_munged_dial(pw);
+
+ len_munged_dial = munged_dial != NULL ? strlen(munged_dial )+1 : 0;
+ init_uni_hdr(&usr->hdr_munged_dial, len_munged_dial);
+ init_unistr2(&usr->uni_munged_dial, munged_dial, len_munged_dial);
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL sam_io_user_info20(char *desc, SAM_USER_INFO_20 *usr,
+ prs_struct *ps, int depth)
+{
+ if (usr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sam_io_user_info20");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unihdr("hdr_munged_dial ", &usr->hdr_munged_dial, ps, depth)) /* wkstas user can log on from */
+ return False;
+
+ if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial,usr->hdr_munged_dial.buffer, ps, depth)) /* worksations user can log on from */
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAM_USERINFO_CTR structure.
+********************************************************************/
+
+NTSTATUS make_samr_userinfo_ctr_usr21(TALLOC_CTX *ctx, SAM_USERINFO_CTR * ctr,
+ uint16 switch_value,
+ SAM_USER_INFO_21 * usr)
+{
+ DEBUG(5, ("init_samr_userinfo_ctr\n"));
+
+ ctr->switch_value = switch_value;
+ ctr->info.id = NULL;
+
+ switch (switch_value) {
+ case 0x10:
+ ctr->info.id10 = (SAM_USER_INFO_10 *)talloc_zero(ctx,sizeof(SAM_USER_INFO_10));
+ if (ctr->info.id10 == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ init_sam_user_info10(ctr->info.id10, usr->acb_info);
+ break;
+#if 0
+/* whoops - got this wrong. i think. or don't understand what's happening. */
+ case 0x11:
+ {
+ NTTIME expire;
+ info = (void *)&id11;
+
+ expire.low = 0xffffffff;
+ expire.high = 0x7fffffff;
+
+ ctr->info.id = (SAM_USER_INFO_11 *) talloc_zero(ctx,sizeof(*ctr->info.id11));
+ init_sam_user_info11(ctr->info.id11, &expire,
+ "BROOKFIELDS$", /* name */
+ 0x03ef, /* user rid */
+ 0x201, /* group rid */
+ 0x0080); /* acb info */
+
+ break;
+ }
+#endif
+ case 0x12:
+ ctr->info.id12 = (SAM_USER_INFO_12 *)talloc_zero(ctx,sizeof(SAM_USER_INFO_12));
+ if (ctr->info.id12 == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ init_sam_user_info12(ctr->info.id12, usr->lm_pwd, usr->nt_pwd);
+ break;
+ case 21:
+ {
+ SAM_USER_INFO_21 *cusr;
+ cusr = (SAM_USER_INFO_21 *)talloc_zero(ctx,sizeof(SAM_USER_INFO_21));
+ ctr->info.id21 = cusr;
+ if (ctr->info.id21 == NULL)
+ return NT_STATUS_NO_MEMORY;
+ memcpy(cusr, usr, sizeof(*usr));
+ memset(cusr->lm_pwd, 0, sizeof(cusr->lm_pwd));
+ memset(cusr->nt_pwd, 0, sizeof(cusr->nt_pwd));
+ break;
+ }
+ default:
+ DEBUG(4,("make_samr_userinfo_ctr: unsupported info\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+inits a SAM_USERINFO_CTR structure.
+********************************************************************/
+
+void init_samr_userinfo_ctr(SAM_USERINFO_CTR * ctr, uchar * sess_key,
+ uint16 switch_value, void *info)
+{
+ DEBUG(5, ("init_samr_userinfo_ctr\n"));
+
+ ctr->switch_value = switch_value;
+ ctr->info.id = info;
+
+ switch (switch_value) {
+ case 0x18:
+ SamOEMhash(ctr->info.id24->pass, sess_key, 516);
+ dump_data(100, (char *)sess_key, 16);
+ dump_data(100, (char *)ctr->info.id24->pass, 516);
+ break;
+ case 0x17:
+ SamOEMhash(ctr->info.id23->pass, sess_key, 516);
+ dump_data(100, (char *)sess_key, 16);
+ dump_data(100, (char *)ctr->info.id23->pass, 516);
+ break;
+ default:
+ DEBUG(4,("init_samr_userinfo_ctr: unsupported switch level\n"));
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL samr_io_userinfo_ctr(char *desc, SAM_USERINFO_CTR **ppctr,
+ prs_struct *ps, int depth)
+{
+ BOOL ret;
+ SAM_USERINFO_CTR *ctr;
+
+ prs_debug(ps, depth, desc, "samr_io_userinfo_ctr");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ ctr = (SAM_USERINFO_CTR *)prs_alloc_mem(ps,sizeof(SAM_USERINFO_CTR));
+ if (ctr == NULL)
+ return False;
+ *ppctr = ctr;
+ } else {
+ ctr = *ppctr;
+ }
+
+ /* lkclXXXX DO NOT ALIGN BEFORE READING SWITCH VALUE! */
+
+ if(!prs_uint16("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ ret = False;
+
+ switch (ctr->switch_value) {
+ case 0x10:
+ if (UNMARSHALLING(ps))
+ ctr->info.id10 = (SAM_USER_INFO_10 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_10));
+ if (ctr->info.id10 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info10("", ctr->info.id10, ps, depth);
+ break;
+ case 0x11:
+ if (UNMARSHALLING(ps))
+ ctr->info.id11 = (SAM_USER_INFO_11 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_11));
+
+ if (ctr->info.id11 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info11("", ctr->info.id11, ps, depth);
+ break;
+ case 0x12:
+ if (UNMARSHALLING(ps))
+ ctr->info.id12 = (SAM_USER_INFO_12 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_12));
+
+ if (ctr->info.id12 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info12("", ctr->info.id12, ps, depth);
+ break;
+ case 20:
+ if (UNMARSHALLING(ps))
+ ctr->info.id20 = (SAM_USER_INFO_20 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_20));
+
+ if (ctr->info.id20 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info20("", ctr->info.id20, ps, depth);
+ break;
+ case 21:
+ if (UNMARSHALLING(ps))
+ ctr->info.id21 = (SAM_USER_INFO_21 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_21));
+
+ if (ctr->info.id21 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info21("", ctr->info.id21, ps, depth);
+ break;
+ case 23:
+ if (UNMARSHALLING(ps))
+ ctr->info.id23 = (SAM_USER_INFO_23 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_23));
+
+ if (ctr->info.id23 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info23("", ctr->info.id23, ps, depth);
+ break;
+ case 24:
+ if (UNMARSHALLING(ps))
+ ctr->info.id24 = (SAM_USER_INFO_24 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_24));
+
+ if (ctr->info.id24 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info24("", ctr->info.id24, ps, depth);
+ break;
+ case 25:
+ if (UNMARSHALLING(ps))
+ ctr->info.id25 = (SAM_USER_INFO_25 *)prs_alloc_mem(ps,sizeof(SAM_USER_INFO_25));
+
+ if (ctr->info.id25 == NULL) {
+ DEBUG(2,("samr_io_userinfo_ctr: info pointer not initialised\n"));
+ return False;
+ }
+ ret = sam_io_user_info25("", ctr->info.id25, ps, depth);
+ break;
+ default:
+ DEBUG(2, ("samr_io_userinfo_ctr: unknown switch level 0x%x\n", ctr->switch_value));
+ ret = False;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_USERINFO structure.
+********************************************************************/
+
+void init_samr_r_query_userinfo(SAMR_R_QUERY_USERINFO * r_u,
+ SAM_USERINFO_CTR * ctr, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_query_userinfo\n"));
+
+ r_u->ptr = 0;
+ r_u->ctr = NULL;
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->ptr = 1;
+ r_u->ctr = ctr;
+ }
+
+ r_u->status = status; /* return status */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_query_userinfo(char *desc, SAMR_R_QUERY_USERINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_userinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &r_u->ptr))
+ return False;
+
+ if (r_u->ptr != 0) {
+ if(!samr_io_userinfo_ctr("ctr", &r_u->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_SET_USERINFO structure.
+********************************************************************/
+
+void init_samr_q_set_userinfo(SAMR_Q_SET_USERINFO * q_u,
+ POLICY_HND *hnd, unsigned char sess_key[16],
+ uint16 switch_value, void *info)
+{
+ DEBUG(5, ("init_samr_q_set_userinfo\n"));
+
+ q_u->pol = *hnd;
+ q_u->switch_value = switch_value;
+ init_samr_userinfo_ctr(q_u->ctr, sess_key, switch_value, info);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_set_userinfo(char *desc, SAMR_Q_SET_USERINFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_set_userinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+ if(!samr_io_userinfo_ctr("ctr", &q_u->ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_SET_USERINFO structure.
+********************************************************************/
+
+void init_samr_r_set_userinfo(SAMR_R_SET_USERINFO * r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_set_userinfo\n"));
+
+ r_u->status = status; /* return status */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_set_userinfo(char *desc, SAMR_R_SET_USERINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_set_userinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_SET_USERINFO2 structure.
+********************************************************************/
+
+void init_samr_q_set_userinfo2(SAMR_Q_SET_USERINFO2 * q_u,
+ POLICY_HND *hnd, unsigned char sess_key[16],
+ uint16 switch_value, SAM_USERINFO_CTR * ctr)
+{
+ DEBUG(5, ("init_samr_q_set_userinfo2\n"));
+
+ q_u->pol = *hnd;
+ q_u->switch_value = switch_value;
+ q_u->ctr = ctr;
+
+ if (q_u->ctr != NULL)
+ q_u->ctr->switch_value = switch_value;
+
+ switch (switch_value) {
+ case 0x12:
+ SamOEMhash(ctr->info.id12->lm_pwd, sess_key, 16);
+ SamOEMhash(ctr->info.id12->nt_pwd, sess_key, 16);
+ dump_data(100, (char *)sess_key, 16);
+ dump_data(100, (char *)ctr->info.id12->lm_pwd, 16);
+ dump_data(100, (char *)ctr->info.id12->nt_pwd, 16);
+ break;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_set_userinfo2(char *desc, SAMR_Q_SET_USERINFO2 * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_set_userinfo2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("pol", &q_u->pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+ if(!samr_io_userinfo_ctr("ctr", &q_u->ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_SET_USERINFO2 structure.
+********************************************************************/
+
+void init_samr_r_set_userinfo2(SAMR_R_SET_USERINFO2 * r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_set_userinfo2\n"));
+
+ r_u->status = status; /* return status */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_set_userinfo2(char *desc, SAMR_R_SET_USERINFO2 * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_set_userinfo2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_CONNECT structure.
+********************************************************************/
+
+void init_samr_q_connect(SAMR_Q_CONNECT * q_u,
+ char *srv_name, uint32 access_mask)
+{
+ int len_srv_name = strlen(srv_name);
+
+ DEBUG(5, ("init_samr_q_connect\n"));
+
+ /* make PDC server name \\server */
+ q_u->ptr_srv_name = len_srv_name > 0 ? 1 : 0;
+ init_unistr2(&q_u->uni_srv_name, srv_name, len_srv_name + 1);
+
+ /* example values: 0x0000 0002 */
+ q_u->access_mask = access_mask;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_connect(char *desc, SAMR_Q_CONNECT * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_connect");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_u->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_u->uni_srv_name, q_u->ptr_srv_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_connect(char *desc, SAMR_R_CONNECT * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_connect");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("connect_pol", &r_u->connect_pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_CONNECT_ANON structure.
+********************************************************************/
+
+void init_samr_q_connect_anon(SAMR_Q_CONNECT_ANON * q_u)
+{
+ DEBUG(5, ("init_samr_q_connect_anon\n"));
+
+ q_u->ptr = 1;
+ q_u->unknown_0 = 0x5c; /* server name (?!!) */
+ q_u->unknown_1 = 0x01;
+ q_u->access_mask = 0x20;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_connect_anon(char *desc, SAMR_Q_CONNECT_ANON * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_connect_anon");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &q_u->ptr))
+ return False;
+ if(!prs_uint16("unknown_0", ps, depth, &q_u->unknown_0))
+ return False;
+ if(!prs_uint16("unknown_1", ps, depth, &q_u->unknown_1))
+ return False;
+ if(!prs_uint32("access_mask", ps, depth, &q_u->access_mask))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_connect_anon(char *desc, SAMR_R_CONNECT_ANON * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_connect_anon");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("connect_pol", &r_u->connect_pol, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_Q_GET_DOM_PWINFO structure.
+********************************************************************/
+
+void init_samr_q_get_dom_pwinfo(SAMR_Q_GET_DOM_PWINFO * q_u,
+ char *srv_name)
+{
+ int len_srv_name = strlen(srv_name);
+
+ DEBUG(5, ("init_samr_q_get_dom_pwinfo\n"));
+
+ q_u->ptr = 1;
+ init_uni_hdr(&q_u->hdr_srv_name, len_srv_name);
+ init_unistr2(&q_u->uni_srv_name, srv_name, len_srv_name);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_get_dom_pwinfo(char *desc, SAMR_Q_GET_DOM_PWINFO * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_get_dom_pwinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &q_u->ptr))
+ return False;
+ if (q_u->ptr != 0) {
+ if(!smb_io_unihdr("", &q_u->hdr_srv_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->uni_srv_name, q_u->hdr_srv_name.buffer, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_get_dom_pwinfo(char *desc, SAMR_R_GET_DOM_PWINFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_get_dom_pwinfo");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("unk_0", ps, depth, &r_u->unk_0))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("unk_1", ps, depth, &r_u->unk_1))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("unk_2", ps, depth, &r_u->unk_2))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+make a SAMR_ENC_PASSWD structure.
+********************************************************************/
+
+void init_enc_passwd(SAMR_ENC_PASSWD * pwd, char pass[512])
+{
+ ZERO_STRUCTP(pwd);
+
+ if (pass == NULL) {
+ pwd->ptr = 0;
+ } else {
+ pwd->ptr = 1;
+ memcpy(pwd->pass, pass, sizeof(pwd->pass));
+ }
+}
+
+/*******************************************************************
+reads or writes a SAMR_ENC_PASSWD structure.
+********************************************************************/
+
+BOOL samr_io_enc_passwd(char *desc, SAMR_ENC_PASSWD * pwd,
+ prs_struct *ps, int depth)
+{
+ if (pwd == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_enc_passwd");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr", ps, depth, &pwd->ptr))
+ return False;
+
+ if (pwd->ptr != 0) {
+ if(!prs_uint8s(False, "pwd", ps, depth, pwd->pass, sizeof(pwd->pass)))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_ENC_HASH structure.
+********************************************************************/
+
+void init_enc_hash(SAMR_ENC_HASH * hsh, uchar hash[16])
+{
+ ZERO_STRUCTP(hsh);
+
+ if (hash == NULL) {
+ hsh->ptr = 0;
+ } else {
+ hsh->ptr = 1;
+ memcpy(hsh->hash, hash, sizeof(hsh->hash));
+ }
+}
+
+/*******************************************************************
+reads or writes a SAMR_ENC_HASH structure.
+********************************************************************/
+
+BOOL samr_io_enc_hash(char *desc, SAMR_ENC_HASH * hsh,
+ prs_struct *ps, int depth)
+{
+ if (hsh == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_enc_hash");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr ", ps, depth, &hsh->ptr))
+ return False;
+ if (hsh->ptr != 0) {
+ if(!prs_uint8s(False, "hash", ps, depth, hsh->hash,sizeof(hsh->hash)))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_GET_DOM_PWINFO structure.
+********************************************************************/
+
+void init_samr_q_chgpasswd_user(SAMR_Q_CHGPASSWD_USER * q_u,
+ char *dest_host, char *user_name,
+ char nt_newpass[516],
+ uchar nt_oldhash[16],
+ char lm_newpass[516],
+ uchar lm_oldhash[16])
+{
+ int len_dest_host = strlen(dest_host);
+ int len_user_name = strlen(user_name);
+
+ DEBUG(5, ("init_samr_q_chgpasswd_user\n"));
+
+ q_u->ptr_0 = 1;
+ init_uni_hdr(&q_u->hdr_dest_host, len_dest_host);
+ init_unistr2(&q_u->uni_dest_host, dest_host, len_dest_host);
+ init_uni_hdr(&q_u->hdr_user_name, len_user_name);
+ init_unistr2(&q_u->uni_user_name, user_name, len_user_name);
+
+ init_enc_passwd(&q_u->nt_newpass, nt_newpass);
+ init_enc_hash(&q_u->nt_oldhash, nt_oldhash);
+
+ q_u->unknown = 0x01;
+
+ init_enc_passwd(&q_u->lm_newpass, lm_newpass);
+ init_enc_hash(&q_u->lm_oldhash, lm_oldhash);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_chgpasswd_user(char *desc, SAMR_Q_CHGPASSWD_USER * q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_chgpasswd_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_0", ps, depth, &q_u->ptr_0))
+ return False;
+
+ if(!smb_io_unihdr("", &q_u->hdr_dest_host, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->uni_dest_host, q_u->hdr_dest_host.buffer, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unihdr("", &q_u->hdr_user_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->uni_user_name, q_u->hdr_user_name.buffer,ps, depth))
+ return False;
+
+ if(!samr_io_enc_passwd("nt_newpass", &q_u->nt_newpass, ps, depth))
+ return False;
+ if(!samr_io_enc_hash("nt_oldhash", &q_u->nt_oldhash, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown", ps, depth, &q_u->unknown))
+ return False;
+
+ if(!samr_io_enc_passwd("lm_newpass", &q_u->lm_newpass, ps, depth))
+ return False;
+ if(!samr_io_enc_hash("lm_oldhash", &q_u->lm_oldhash, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_CHGPASSWD_USER structure.
+********************************************************************/
+
+void init_samr_r_chgpasswd_user(SAMR_R_CHGPASSWD_USER * r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_r_chgpasswd_user\n"));
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_chgpasswd_user(char *desc, SAMR_R_CHGPASSWD_USER * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_chgpasswd_user");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_unknown_2e(SAMR_Q_UNKNOWN_2E *q_u,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ DEBUG(5, ("init_samr_q_unknown_2e\n"));
+
+ q_u->domain_pol = *domain_pol;
+ q_u->switch_value = switch_value;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_unknown_2e(char *desc, SAMR_Q_UNKNOWN_2E *q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_2e");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_DOMAIN_INFO structure.
+********************************************************************/
+
+void init_samr_r_samr_unknown_2e(SAMR_R_UNKNOWN_2E * r_u,
+ uint16 switch_value, SAM_UNK_CTR * ctr,
+ NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_samr_unknown_2e\n"));
+
+ r_u->ptr_0 = 0;
+ r_u->switch_value = 0;
+ r_u->status = status; /* return status */
+
+ if (NT_STATUS_IS_OK(status)) {
+ r_u->switch_value = switch_value;
+ r_u->ptr_0 = 1;
+ r_u->ctr = ctr;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_samr_unknown_2e(char *desc, SAMR_R_UNKNOWN_2E * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_samr_unknown_2e");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_0 ", ps, depth, &r_u->ptr_0))
+ return False;
+
+ if (r_u->ptr_0 != 0 && r_u->ctr != NULL) {
+ if(!prs_uint16("switch_value", ps, depth, &r_u->switch_value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ switch (r_u->switch_value) {
+ case 0x0c:
+ if(!sam_io_unk_info12("unk_inf12", &r_u->ctr->info.inf12, ps, depth))
+ return False;
+ break;
+ case 0x07:
+ if(!sam_io_unk_info7("unk_inf7",&r_u->ctr->info.inf7, ps,depth))
+ return False;
+ break;
+ case 0x06:
+ if(!sam_io_unk_info6("unk_inf6",&r_u->ctr->info.inf6, ps,depth))
+ return False;
+ break;
+ case 0x05:
+ if(!sam_io_unk_info5("unk_inf5",&r_u->ctr->info.inf5, ps,depth))
+ return False;
+ break;
+ case 0x03:
+ if(!sam_io_unk_info3("unk_inf3",&r_u->ctr->info.inf3, ps,depth))
+ return False;
+ break;
+ case 0x02:
+ if(!sam_io_unk_info2("unk_inf2",&r_u->ctr->info.inf2, ps,depth))
+ return False;
+ break;
+ case 0x01:
+ if(!sam_io_unk_info1("unk_inf1",&r_u->ctr->info.inf1, ps,depth))
+ return False;
+ break;
+ default:
+ DEBUG(0, ("samr_io_r_samr_unknown_2e: unknown switch level 0x%x\n",
+ r_u->switch_value));
+ r_u->status = NT_STATUS_INVALID_INFO_CLASS;
+ return False;
+ }
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+void init_samr_q_set_domain_info(SAMR_Q_SET_DOMAIN_INFO *q_u,
+ POLICY_HND *domain_pol, uint16 switch_value, SAM_UNK_CTR *ctr)
+{
+ DEBUG(5, ("init_samr_q_set_domain_info\n"));
+
+ q_u->domain_pol = *domain_pol;
+ q_u->switch_value0 = switch_value;
+
+ q_u->switch_value = switch_value;
+ q_u->ctr = ctr;
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_q_set_domain_info(char *desc, SAMR_Q_SET_DOMAIN_INFO *q_u,
+ prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_q_set_domain_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("domain_pol", &q_u->domain_pol, ps, depth))
+ return False;
+
+ if(!prs_uint16("switch_value0", ps, depth, &q_u->switch_value0))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if ((q_u->ctr = (SAM_UNK_CTR *)prs_alloc_mem(ps, sizeof(SAM_UNK_CTR))) == NULL)
+ return False;
+
+ switch (q_u->switch_value) {
+
+ case 0x0c:
+ if(!sam_io_unk_info12("unk_inf12", &q_u->ctr->info.inf12, ps, depth))
+ return False;
+ break;
+ case 0x07:
+ if(!sam_io_unk_info7("unk_inf7",&q_u->ctr->info.inf7, ps,depth))
+ return False;
+ break;
+ case 0x06:
+ if(!sam_io_unk_info6("unk_inf6",&q_u->ctr->info.inf6, ps,depth))
+ return False;
+ break;
+ case 0x05:
+ if(!sam_io_unk_info5("unk_inf5",&q_u->ctr->info.inf5, ps,depth))
+ return False;
+ break;
+ case 0x03:
+ if(!sam_io_unk_info3("unk_inf3",&q_u->ctr->info.inf3, ps,depth))
+ return False;
+ break;
+ case 0x02:
+ if(!sam_io_unk_info2("unk_inf2",&q_u->ctr->info.inf2, ps,depth))
+ return False;
+ break;
+ case 0x01:
+ if(!sam_io_unk_info1("unk_inf1",&q_u->ctr->info.inf1, ps,depth))
+ return False;
+ break;
+ default:
+ DEBUG(0, ("samr_io_r_samr_unknown_2e: unknown switch level 0x%x\n",
+ q_u->switch_value));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+inits a SAMR_R_QUERY_DOMAIN_INFO structure.
+********************************************************************/
+
+void init_samr_r_set_domain_info(SAMR_R_SET_DOMAIN_INFO * r_u, NTSTATUS status)
+{
+ DEBUG(5, ("init_samr_r_set_domain_info\n"));
+
+ r_u->status = status; /* return status */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_r_set_domain_info(char *desc, SAMR_R_SET_DOMAIN_INFO * r_u,
+ prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_r_samr_unknown_2e");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_sec.c b/source/rpc_parse/parse_sec.c
new file mode 100644
index 00000000000..0e6f9e28794
--- /dev/null
+++ b/source/rpc_parse/parse_sec.c
@@ -0,0 +1,806 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-1998
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#define SD_HEADER_SIZE 0x14
+
+/*******************************************************************
+ Sets up a SEC_ACCESS structure.
+********************************************************************/
+
+void init_sec_access(SEC_ACCESS *t, uint32 mask)
+{
+ t->mask = mask;
+}
+
+/*******************************************************************
+ Reads or writes a SEC_ACCESS structure.
+********************************************************************/
+
+BOOL sec_io_access(char *desc, SEC_ACCESS *t, prs_struct *ps, int depth)
+{
+ if (t == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sec_io_access");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("mask", ps, depth, &(t->mask)))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Sets up a SEC_ACE structure.
+********************************************************************/
+
+void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
+{
+ t->type = type;
+ t->flags = flag;
+ t->size = sid_size(sid) + 8;
+ t->info = mask;
+
+ ZERO_STRUCTP(&t->trustee);
+ sid_copy(&t->trustee, sid);
+}
+
+/*******************************************************************
+ Reads or writes a SEC_ACE structure.
+********************************************************************/
+
+BOOL sec_io_ace(char *desc, SEC_ACE *psa, prs_struct *ps, int depth)
+{
+ uint32 old_offset;
+ uint32 offset_ace_size;
+
+ if (psa == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "sec_io_ace");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ if(!prs_uint8("type ", ps, depth, &psa->type))
+ return False;
+
+ if(!prs_uint8("flags", ps, depth, &psa->flags))
+ return False;
+
+ if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
+ return False;
+
+ if(!sec_io_access("info ", &psa->info, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_dom_sid("trustee ", &psa->trustee , ps, depth))
+ return False;
+
+ if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Create a SEC_ACL structure.
+********************************************************************/
+
+SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, uint16 revision, int num_aces, SEC_ACE *ace_list)
+{
+ SEC_ACL *dst;
+ int i;
+
+ if((dst = (SEC_ACL *)talloc_zero(ctx,sizeof(SEC_ACL))) == NULL)
+ return NULL;
+
+ dst->revision = revision;
+ dst->num_aces = num_aces;
+ dst->size = 8;
+
+ /* Now we need to return a non-NULL address for the ace list even
+ if the number of aces required is zero. This is because there
+ is a distinct difference between a NULL ace and an ace with zero
+ entries in it. This is achieved by checking that num_aces is a
+ positive number. */
+
+ if ((num_aces) &&
+ ((dst->ace = (SEC_ACE *)talloc(ctx, sizeof(SEC_ACE) * num_aces))
+ == NULL)) {
+ return NULL;
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ dst->ace[i] = ace_list[i]; /* Structure copy. */
+ dst->size += ace_list[i].size;
+ }
+
+ return dst;
+}
+
+/*******************************************************************
+ Duplicate a SEC_ACL structure.
+********************************************************************/
+
+SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
+{
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_acl(ctx, src->revision, src->num_aces, src->ace);
+}
+
+/*******************************************************************
+ Reads or writes a SEC_ACL structure.
+
+ First of the xx_io_xx functions that allocates its data structures
+ for you as it reads them.
+********************************************************************/
+
+BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
+{
+ int i;
+ uint32 old_offset;
+ uint32 offset_acl_size;
+ SEC_ACL *psa;
+
+ if (ppsa == NULL)
+ return False;
+
+ psa = *ppsa;
+
+ if(UNMARSHALLING(ps) && psa == NULL) {
+ /*
+ * This is a read and we must allocate the stuct to read into.
+ */
+ if((psa = (SEC_ACL *)prs_alloc_mem(ps, sizeof(SEC_ACL))) == NULL)
+ return False;
+ *ppsa = psa;
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_acl");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ if(!prs_uint16("revision", ps, depth, &psa->revision))
+ return False;
+
+ if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size))
+ return False;
+
+ if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ /*
+ * Even if the num_aces is zero, allocate memory as there's a difference
+ * between a non-present DACL (allow all access) and a DACL with no ACE's
+ * (allow no access).
+ */
+ if((psa->ace = (SEC_ACE *)prs_alloc_mem(ps,sizeof(psa->ace[0]) * (psa->num_aces+1))) == NULL)
+ return False;
+ }
+
+ for (i = 0; i < psa->num_aces; i++) {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
+ if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Works out the linearization size of a SEC_DESC.
+********************************************************************/
+
+size_t sec_desc_size(SEC_DESC *psd)
+{
+ size_t offset;
+
+ if (!psd) return 0;
+
+ offset = SD_HEADER_SIZE;
+
+ if (psd->owner_sid != NULL)
+ offset += ((sid_size(psd->owner_sid) + 3) & ~3);
+
+ if (psd->grp_sid != NULL)
+ offset += ((sid_size(psd->grp_sid) + 3) & ~3);
+
+ if (psd->sacl != NULL)
+ offset += ((psd->sacl->size + 3) & ~3);
+
+ if (psd->dacl != NULL)
+ offset += ((psd->dacl->size + 3) & ~3);
+
+ return offset;
+}
+
+/*******************************************************************
+ Compares two SEC_ACE structures
+********************************************************************/
+
+BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
+{
+ /* Trivial case */
+
+ if (!s1 && !s2) return True;
+
+ /* Check top level stuff */
+
+ if (s1->type != s2->type || s1->flags != s2->flags ||
+ s1->info.mask != s2->info.mask) {
+ return False;
+ }
+
+ /* Check SID */
+
+ if (!sid_equal(&s1->trustee, &s2->trustee)) {
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Compares two SEC_ACL structures
+********************************************************************/
+
+BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
+{
+ int i, j;
+
+ /* Trivial cases */
+
+ if (!s1 && !s2) return True;
+ if (!s1 || !s2) return False;
+
+ /* Check top level stuff */
+
+ if (s1->revision != s2->revision) {
+ DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ if (s1->num_aces != s2->num_aces) {
+ DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ /* The ACEs could be in any order so check each ACE in s1 against
+ each ACE in s2. */
+
+ for (i = 0; i < s1->num_aces; i++) {
+ BOOL found = False;
+
+ for (j = 0; j < s2->num_aces; j++) {
+ if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Compares two SEC_DESC structures
+********************************************************************/
+
+BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
+{
+ /* Trivial case */
+
+ if (!s1 && !s2) {
+ goto done;
+ }
+
+ /* Check top level stuff */
+
+ if (s1->revision != s2->revision) {
+ DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
+ s1->revision, s2->revision));
+ return False;
+ }
+
+ if (s1->type!= s2->type) {
+ DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
+ s1->type, s2->type));
+ return False;
+ }
+
+ /* Check owner and group */
+
+ if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
+ fstring str1, str2;
+
+ sid_to_string(str1, s1->owner_sid);
+ sid_to_string(str2, s2->owner_sid);
+
+ DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
+ str1, str2));
+ return False;
+ }
+
+ if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
+ fstring str1, str2;
+
+ sid_to_string(str1, s1->grp_sid);
+ sid_to_string(str2, s2->grp_sid);
+
+ DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
+ str1, str2));
+ return False;
+ }
+
+ /* Check ACLs present in one but not the other */
+
+ if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
+ (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
+ DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
+ return False;
+ }
+
+ /* Sigh - we have to do it the hard way by iterating over all
+ the ACEs in the ACLs */
+
+ if (!sec_acl_equal(s1->dacl, s2->dacl) ||
+ !sec_acl_equal(s1->sacl, s2->sacl)) {
+ DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
+ return False;
+ }
+
+ done:
+ DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
+ return True;
+}
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+
+SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
+{
+ DOM_SID *owner_sid, *group_sid;
+ SEC_DESC_BUF *return_sdb;
+ SEC_ACL *dacl, *sacl;
+ SEC_DESC *psd = NULL;
+ uint16 secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
+ old_sdb->sec->owner_sid;
+
+ group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
+ old_sdb->sec->grp_sid;
+
+ secdesc_type = new_sdb->sec->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->sec->dacl;
+ } else {
+ dacl = old_sdb->sec->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+
+ psd = make_sec_desc(ctx, new_sdb->sec->revision,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
+
+ return(return_sdb);
+}
+
+/*******************************************************************
+ Tallocs a duplicate SID.
+********************************************************************/
+
+static DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, DOM_SID *src)
+{
+ DOM_SID *dst;
+
+ if(!src)
+ return NULL;
+
+ if((dst = talloc_zero(ctx, sizeof(DOM_SID))) != NULL) {
+ sid_copy( dst, src);
+ }
+
+ return dst;
+}
+
+/*******************************************************************
+ Creates a SEC_DESC structure
+********************************************************************/
+
+SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision,
+ DOM_SID *owner_sid, DOM_SID *grp_sid,
+ SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
+{
+ SEC_DESC *dst;
+ uint32 offset;
+
+ *sd_size = 0;
+
+ if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
+ return NULL;
+
+ dst->revision = revision;
+ dst->type = SEC_DESC_SELF_RELATIVE;
+
+ if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
+ if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
+
+ dst->off_owner_sid = 0;
+ dst->off_grp_sid = 0;
+ dst->off_sacl = 0;
+ dst->off_dacl = 0;
+
+ if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
+ goto error_exit;
+
+ if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
+ goto error_exit;
+
+ if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
+ goto error_exit;
+
+ if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
+ goto error_exit;
+
+ offset = 0;
+
+ /*
+ * Work out the linearization sizes.
+ */
+
+ if (dst->owner_sid != NULL) {
+
+ if (offset == 0)
+ offset = SD_HEADER_SIZE;
+
+ dst->off_owner_sid = offset;
+ offset += ((sid_size(dst->owner_sid) + 3) & ~3);
+ }
+
+ if (dst->grp_sid != NULL) {
+
+ if (offset == 0)
+ offset = SD_HEADER_SIZE;
+
+ dst->off_grp_sid = offset;
+ offset += ((sid_size(dst->grp_sid) + 3) & ~3);
+ }
+
+ if (dst->sacl != NULL) {
+
+ if (offset == 0)
+ offset = SD_HEADER_SIZE;
+
+ dst->off_sacl = offset;
+ offset += ((dst->sacl->size + 3) & ~3);
+ }
+
+ if (dst->dacl != NULL) {
+
+ if (offset == 0)
+ offset = SD_HEADER_SIZE;
+
+ dst->off_dacl = offset;
+ offset += ((dst->dacl->size + 3) & ~3);
+ }
+
+ *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
+ return dst;
+
+error_exit:
+
+ *sd_size = 0;
+ return NULL;
+}
+
+/*******************************************************************
+ Duplicate a SEC_DESC structure.
+********************************************************************/
+
+SEC_DESC *dup_sec_desc( TALLOC_CTX *ctx, SEC_DESC *src)
+{
+ size_t dummy;
+
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_desc( ctx, src->revision,
+ src->owner_sid, src->grp_sid, src->sacl,
+ src->dacl, &dummy);
+}
+
+/*******************************************************************
+ Creates a SEC_DESC structure with typical defaults.
+********************************************************************/
+
+SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
+ SEC_ACL *dacl, size_t *sd_size)
+{
+ return make_sec_desc(ctx, SEC_DESC_REVISION,
+ owner_sid, grp_sid, NULL, dacl, sd_size);
+}
+
+/*******************************************************************
+ Reads or writes a SEC_DESC structure.
+ If reading and the *ppsd = NULL, allocates the structure.
+********************************************************************/
+
+BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
+{
+ uint32 old_offset;
+ uint32 max_offset = 0; /* after we're done, move offset to end */
+ SEC_DESC *psd;
+
+ if (ppsd == NULL)
+ return False;
+
+ psd = *ppsd;
+
+ if (psd == NULL) {
+ if(UNMARSHALLING(ps)) {
+ if((psd = (SEC_DESC *)prs_alloc_mem(ps,sizeof(SEC_DESC))) == NULL)
+ return False;
+ *ppsd = psd;
+ } else {
+ /* Marshalling - just ignore. */
+ return True;
+ }
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_desc");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ /* start of security descriptor stored for back-calc offset purposes */
+ old_offset = prs_offset(ps);
+
+ if(!prs_uint16("revision ", ps, depth, &psd->revision))
+ return False;
+
+ if(!prs_uint16("type ", ps, depth, &psd->type))
+ return False;
+
+ if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
+ return False;
+
+ if(!prs_uint32("off_grp_sid ", ps, depth, &psd->off_grp_sid))
+ return False;
+
+ if(!prs_uint32("off_sacl ", ps, depth, &psd->off_sacl))
+ return False;
+
+ if(!prs_uint32("off_dacl ", ps, depth, &psd->off_dacl))
+ return False;
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if (psd->off_owner_sid != 0) {
+
+ if (UNMARSHALLING(ps)) {
+ if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
+ return False;
+ /* reading */
+ if((psd->owner_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->owner_sid))) == NULL)
+ return False;
+ }
+
+ if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if (psd->off_grp_sid != 0) {
+
+ if (UNMARSHALLING(ps)) {
+ /* reading */
+ if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
+ return False;
+ if((psd->grp_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->grp_sid))) == NULL)
+ return False;
+ }
+
+ if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
+ if(!prs_set_offset(ps, old_offset + psd->off_sacl))
+ return False;
+ if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
+ if(!prs_set_offset(ps, old_offset + psd->off_dacl))
+ return False;
+ if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+
+ max_offset = MAX(max_offset, prs_offset(ps));
+
+ if(!prs_set_offset(ps, max_offset))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+ Creates a SEC_DESC_BUF structure.
+********************************************************************/
+
+SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
+{
+ SEC_DESC_BUF *dst;
+
+ if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
+ return NULL;
+
+ /* max buffer size (allocated size) */
+ dst->max_len = (uint32)len;
+ dst->len = (uint32)len;
+
+ if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
+ return NULL;
+ }
+
+ dst->ptr = 0x1;
+
+ return dst;
+}
+
+/*******************************************************************
+ Duplicates a SEC_DESC_BUF structure.
+********************************************************************/
+
+SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
+{
+ if(src == NULL)
+ return NULL;
+
+ return make_sec_desc_buf( ctx, src->len, src->sec);
+}
+
+/*******************************************************************
+ Reads or writes a SEC_DESC_BUF structure.
+********************************************************************/
+
+BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
+{
+ uint32 off_len;
+ uint32 off_max_len;
+ uint32 old_offset;
+ uint32 size;
+ SEC_DESC_BUF *psdb;
+
+ if (ppsdb == NULL)
+ return False;
+
+ psdb = *ppsdb;
+
+ if (UNMARSHALLING(ps) && psdb == NULL) {
+ if((psdb = (SEC_DESC_BUF *)prs_alloc_mem(ps,sizeof(SEC_DESC_BUF))) == NULL)
+ return False;
+ *ppsdb = psdb;
+ }
+
+ prs_debug(ps, depth, desc, "sec_io_desc_buf");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
+ return False;
+
+ if(!prs_uint32 ("ptr ", ps, depth, &psdb->ptr))
+ return False;
+
+ if(!prs_uint32_pre("len ", ps, depth, &psdb->len, &off_len))
+ return False;
+
+ old_offset = prs_offset(ps);
+
+ /* reading, length is non-zero; writing, descriptor is non-NULL */
+ if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
+ if(!sec_io_desc("sec ", &psdb->sec, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ size = prs_offset(ps) - old_offset;
+ if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
+ return False;
+
+ if(!prs_uint32_post("len ", ps, depth, &psdb->len, off_len, size))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_spoolss.c b/source/rpc_parse/parse_spoolss.c
new file mode 100644
index 00000000000..14e22c4195b
--- /dev/null
+++ b/source/rpc_parse/parse_spoolss.c
@@ -0,0 +1,6579 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000,
+ * Copyright (C) Gerald Carter 2000,
+ * Copyright (C) Tim Potter 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+return the length of a UNISTR string.
+********************************************************************/
+
+static uint32 str_len_uni(UNISTR *source)
+{
+ uint32 i=0;
+
+ if (!source->buffer)
+ return 0;
+
+ while (source->buffer[i])
+ i++;
+
+ return i;
+}
+
+/*******************************************************************
+This should be moved in a more generic lib.
+********************************************************************/
+
+static BOOL spoolss_io_system_time(char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime)
+{
+ if(!prs_uint16("year", ps, depth, &(systime->year)))
+ return False;
+ if(!prs_uint16("month", ps, depth, &(systime->month)))
+ return False;
+ if(!prs_uint16("dayofweek", ps, depth, &(systime->dayofweek)))
+ return False;
+ if(!prs_uint16("day", ps, depth, &(systime->day)))
+ return False;
+ if(!prs_uint16("hour", ps, depth, &(systime->hour)))
+ return False;
+ if(!prs_uint16("minute", ps, depth, &(systime->minute)))
+ return False;
+ if(!prs_uint16("second", ps, depth, &(systime->second)))
+ return False;
+ if(!prs_uint16("milliseconds", ps, depth, &(systime->milliseconds)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL make_systemtime(SYSTEMTIME *systime, struct tm *unixtime)
+{
+ systime->year=unixtime->tm_year+1900;
+ systime->month=unixtime->tm_mon+1;
+ systime->dayofweek=unixtime->tm_wday;
+ systime->day=unixtime->tm_mday;
+ systime->hour=unixtime->tm_hour;
+ systime->minute=unixtime->tm_min;
+ systime->second=unixtime->tm_sec;
+ systime->milliseconds=0;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO structure.
+********************************************************************/
+
+static BOOL smb_io_doc_info_1(char *desc, DOC_INFO_1 *info_1, prs_struct *ps, int depth)
+{
+ if (info_1 == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("p_docname", ps, depth, &info_1->p_docname))
+ return False;
+ if(!prs_uint32("p_outputfile", ps, depth, &info_1->p_outputfile))
+ return False;
+ if(!prs_uint32("p_datatype", ps, depth, &info_1->p_datatype))
+ return False;
+
+ if(!smb_io_unistr2("", &info_1->docname, info_1->p_docname, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &info_1->outputfile, info_1->p_outputfile, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &info_1->datatype, info_1->p_datatype, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO structure.
+********************************************************************/
+
+static BOOL smb_io_doc_info(char *desc, DOC_INFO *info, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0;
+
+ if (info == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &info->switch_value))
+ return False;
+
+ if(!prs_uint32("doc_info_X ptr", ps, depth, &useless_ptr))
+ return False;
+
+ switch (info->switch_value)
+ {
+ case 1:
+ if(!smb_io_doc_info_1("",&info->doc_info_1, ps, depth))
+ return False;
+ break;
+ case 2:
+ /*
+ this is just a placeholder
+
+ MSDN July 1998 says doc_info_2 is only on
+ Windows 95, and as Win95 doesn't do RPC to print
+ this case is nearly impossible
+
+ Maybe one day with Windows for dishwasher 2037 ...
+
+ */
+ /* smb_io_doc_info_2("",&info->doc_info_2, ps, depth); */
+ break;
+ default:
+ DEBUG(0,("Something is obviously wrong somewhere !\n"));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an DOC_INFO_CONTAINER structure.
+********************************************************************/
+
+static BOOL smb_io_doc_info_container(char *desc, DOC_INFO_CONTAINER *cont, prs_struct *ps, int depth)
+{
+ if (cont == NULL) return False;
+
+ prs_debug(ps, depth, desc, "smb_io_doc_info_container");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &cont->level))
+ return False;
+
+ if(!smb_io_doc_info("",&cont->docinfo, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION TYPE structure.
+********************************************************************/
+
+/* NOTIFY_OPTION_TYPE and NOTIFY_OPTION_TYPE_DATA are really one
+ structure. The _TYPE structure is really the deferred referrants (i.e
+ the notify fields array) of the _TYPE structure. -tpot */
+
+static BOOL smb_io_notify_option_type(char *desc, SPOOL_NOTIFY_OPTION_TYPE *type, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("type", ps, depth, &type->type))
+ return False;
+ if(!prs_uint16("reserved0", ps, depth, &type->reserved0))
+ return False;
+ if(!prs_uint32("reserved1", ps, depth, &type->reserved1))
+ return False;
+ if(!prs_uint32("reserved2", ps, depth, &type->reserved2))
+ return False;
+ if(!prs_uint32("count", ps, depth, &type->count))
+ return False;
+ if(!prs_uint32("fields_ptr", ps, depth, &type->fields_ptr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION TYPE DATA.
+********************************************************************/
+
+static BOOL smb_io_notify_option_type_data(char *desc, SPOOL_NOTIFY_OPTION_TYPE *type, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type_data");
+ depth++;
+
+ /* if there are no fields just return */
+ if (type->fields_ptr==0)
+ return True;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count2", ps, depth, &type->count2))
+ return False;
+
+ if (type->count2 != type->count)
+ DEBUG(4,("What a mess, count was %x now is %x !\n", type->count, type->count2));
+
+ /* parse the option type data */
+ for(i=0;i<type->count2;i++)
+ if(!prs_uint16("fields",ps,depth,&type->fields[i]))
+ return False;
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION structure.
+********************************************************************/
+
+static BOOL smb_io_notify_option_type_ctr(char *desc, SPOOL_NOTIFY_OPTION_TYPE_CTR *ctr , prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_option_type_ctr");
+ depth++;
+
+ if(!prs_uint32("count", ps, depth, &ctr->count))
+ return False;
+
+ /* reading */
+ if (UNMARSHALLING(ps))
+ if((ctr->type=(SPOOL_NOTIFY_OPTION_TYPE *)prs_alloc_mem(ps,ctr->count*sizeof(SPOOL_NOTIFY_OPTION_TYPE))) == NULL)
+ return False;
+
+ /* the option type struct */
+ for(i=0;i<ctr->count;i++)
+ if(!smb_io_notify_option_type("", &ctr->type[i] , ps, depth))
+ return False;
+
+ /* the type associated with the option type struct */
+ for(i=0;i<ctr->count;i++)
+ if(!smb_io_notify_option_type_data("", &ctr->type[i] , ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY OPTION structure.
+********************************************************************/
+
+static BOOL smb_io_notify_option(char *desc, SPOOL_NOTIFY_OPTION *option, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "smb_io_notify_option");
+ depth++;
+
+ if(!prs_uint32("version", ps, depth, &option->version))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &option->flags))
+ return False;
+ if(!prs_uint32("count", ps, depth, &option->count))
+ return False;
+ if(!prs_uint32("option_type_ptr", ps, depth, &option->option_type_ptr))
+ return False;
+
+ /* marshalling or unmarshalling, that would work */
+ if (option->option_type_ptr!=0) {
+ if(!smb_io_notify_option_type_ctr("", &option->ctr ,ps, depth))
+ return False;
+ }
+ else {
+ option->ctr.type=NULL;
+ option->ctr.count=0;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO DATA structure.
+********************************************************************/
+
+static BOOL smb_io_notify_info_data(char *desc,SPOOL_NOTIFY_INFO_DATA *data, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0xADDE0FF0;
+
+ uint32 how_many_words;
+ BOOL isvalue;
+ uint32 x;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_info_data");
+ depth++;
+
+ how_many_words=data->size;
+ if (how_many_words==POINTER) {
+ how_many_words=TWO_VALUE;
+ }
+
+ isvalue=data->enc_type;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint16("type", ps, depth, &data->type))
+ return False;
+ if(!prs_uint16("field", ps, depth, &data->field))
+ return False;
+ /*prs_align(ps);*/
+
+ if(!prs_uint32("how many words", ps, depth, &how_many_words))
+ return False;
+ if(!prs_uint32("id", ps, depth, &data->id))
+ return False;
+ if(!prs_uint32("how many words", ps, depth, &how_many_words))
+ return False;
+
+
+ /*prs_align(ps);*/
+
+ if (isvalue==True) {
+ if(!prs_uint32("value[0]", ps, depth, &data->notify_data.value[0]))
+ return False;
+ if(!prs_uint32("value[1]", ps, depth, &data->notify_data.value[1]))
+ return False;
+ /*prs_align(ps);*/
+ } else {
+ /* it's a string */
+ /* length in ascii including \0 */
+ x=2*(data->notify_data.data.length+1);
+ if(!prs_uint32("string length", ps, depth, &x ))
+ return False;
+ if(!prs_uint32("pointer", ps, depth, &useless_ptr))
+ return False;
+ /*prs_align(ps);*/
+ }
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO DATA structure.
+********************************************************************/
+
+BOOL smb_io_notify_info_data_strings(char *desc,SPOOL_NOTIFY_INFO_DATA *data,
+ prs_struct *ps, int depth)
+{
+ uint32 x;
+ BOOL isvalue;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_info_data_strings");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ isvalue=data->enc_type;
+
+ if (isvalue==False) {
+ /* length of string in unicode include \0 */
+ x=data->notify_data.data.length+1;
+ if(!prs_uint32("string length", ps, depth, &x ))
+ return False;
+ if (MARSHALLING(ps)) {
+ /* These are already in little endian format. Don't byte swap. */
+ if (x == 1) {
+
+ /* No memory allocated for this string
+ therefore following the data.string
+ pointer is a bad idea. Use a pointer to
+ the uint32 length union member to
+ provide a source for a unicode NULL */
+
+ if(!prs_uint8s(True,"string",ps,depth, (uint8 *)&data->notify_data.data.length,x*2))
+ return False;
+ } else {
+ if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
+ return False;
+ }
+ } else {
+
+ /* Tallocate memory for string */
+
+ data->notify_data.data.string = (uint16 *)prs_alloc_mem(ps, x * 2);
+ if (!data->notify_data.data.string)
+ return False;
+
+ if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
+ return False;
+ }
+ }
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+reads or writes an NOTIFY INFO structure.
+********************************************************************/
+
+static BOOL smb_io_notify_info(char *desc, SPOOL_NOTIFY_INFO *info, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_notify_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("count", ps, depth, &info->count))
+ return False;
+ if(!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &info->flags))
+ return False;
+ if(!prs_uint32("count", ps, depth, &info->count))
+ return False;
+
+ for (i=0;i<info->count;i++) {
+ if(!smb_io_notify_info_data(desc, &info->data[i], ps, depth))
+ return False;
+ }
+
+ /* now do the strings at the end of the stream */
+ for (i=0;i<info->count;i++) {
+ if(!smb_io_notify_info_data_strings(desc, &info->data[i], ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static BOOL spool_io_user_level_1(char *desc, SPOOL_USER_1 *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps))
+ ZERO_STRUCTP(q_u);
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+ if (!prs_uint32("client_name_ptr", ps, depth, &q_u->client_name_ptr))
+ return False;
+ if (!prs_uint32("user_name_ptr", ps, depth, &q_u->user_name_ptr))
+ return False;
+ if (!prs_uint32("build", ps, depth, &q_u->build))
+ return False;
+ if (!prs_uint32("major", ps, depth, &q_u->major))
+ return False;
+ if (!prs_uint32("minor", ps, depth, &q_u->minor))
+ return False;
+ if (!prs_uint32("processor", ps, depth, &q_u->processor))
+ return False;
+
+ if (!smb_io_unistr2("", &q_u->client_name, q_u->client_name_ptr, ps, depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("", &q_u->user_name, q_u->user_name_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static BOOL spool_io_user_level(char *desc, SPOOL_USER_CTR *q_u, prs_struct *ps, int depth)
+{
+ if (q_u==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spool_io_user_level");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if (!prs_uint32("ptr", ps, depth, &q_u->ptr))
+ return False;
+
+ switch (q_u->level) {
+ case 1:
+ if (!spool_io_user_level_1("", &q_u->user1, ps, depth))
+ return False;
+ break;
+ default:
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * read or write a DEVICEMODE struct.
+ * on reading allocate memory for the private member
+ ********************************************************************/
+
+BOOL spoolss_io_devmode(char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_devmode");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ devmode->devicename.buffer = (uint16 *)prs_alloc_mem(ps, 32 * sizeof(uint16) );
+ if (devmode->devicename.buffer == NULL)
+ return False;
+ }
+
+ if (!prs_uint16uni(True,"devicename", ps, depth, devmode->devicename.buffer, 32))
+ return False;
+ if (!prs_uint16("specversion", ps, depth, &devmode->specversion))
+ return False;
+ if (!prs_uint16("driverversion", ps, depth, &devmode->driverversion))
+ return False;
+ if (!prs_uint16("size", ps, depth, &devmode->size))
+ return False;
+ if (!prs_uint16("driverextra", ps, depth, &devmode->driverextra))
+ return False;
+ if (!prs_uint32("fields", ps, depth, &devmode->fields))
+ return False;
+ if (!prs_uint16("orientation", ps, depth, &devmode->orientation))
+ return False;
+ if (!prs_uint16("papersize", ps, depth, &devmode->papersize))
+ return False;
+ if (!prs_uint16("paperlength", ps, depth, &devmode->paperlength))
+ return False;
+ if (!prs_uint16("paperwidth", ps, depth, &devmode->paperwidth))
+ return False;
+ if (!prs_uint16("scale", ps, depth, &devmode->scale))
+ return False;
+ if (!prs_uint16("copies", ps, depth, &devmode->copies))
+ return False;
+ if (!prs_uint16("defaultsource", ps, depth, &devmode->defaultsource))
+ return False;
+ if (!prs_uint16("printquality", ps, depth, &devmode->printquality))
+ return False;
+ if (!prs_uint16("color", ps, depth, &devmode->color))
+ return False;
+ if (!prs_uint16("duplex", ps, depth, &devmode->duplex))
+ return False;
+ if (!prs_uint16("yresolution", ps, depth, &devmode->yresolution))
+ return False;
+ if (!prs_uint16("ttoption", ps, depth, &devmode->ttoption))
+ return False;
+ if (!prs_uint16("collate", ps, depth, &devmode->collate))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ devmode->formname.buffer = (uint16 *)prs_alloc_mem(ps, 32 * sizeof(uint16) );
+ if (devmode->formname.buffer == NULL)
+ return False;
+ }
+
+ if (!prs_uint16uni(True, "formname", ps, depth, devmode->formname.buffer, 32))
+ return False;
+ if (!prs_uint16("logpixels", ps, depth, &devmode->logpixels))
+ return False;
+ if (!prs_uint32("bitsperpel", ps, depth, &devmode->bitsperpel))
+ return False;
+ if (!prs_uint32("pelswidth", ps, depth, &devmode->pelswidth))
+ return False;
+ if (!prs_uint32("pelsheight", ps, depth, &devmode->pelsheight))
+ return False;
+ if (!prs_uint32("displayflags", ps, depth, &devmode->displayflags))
+ return False;
+ if (!prs_uint32("displayfrequency", ps, depth, &devmode->displayfrequency))
+ return False;
+ if (!prs_uint32("icmmethod", ps, depth, &devmode->icmmethod))
+ return False;
+ if (!prs_uint32("icmintent", ps, depth, &devmode->icmintent))
+ return False;
+ if (!prs_uint32("mediatype", ps, depth, &devmode->mediatype))
+ return False;
+ if (!prs_uint32("dithertype", ps, depth, &devmode->dithertype))
+ return False;
+ if (!prs_uint32("reserved1", ps, depth, &devmode->reserved1))
+ return False;
+ if (!prs_uint32("reserved2", ps, depth, &devmode->reserved2))
+ return False;
+ if (!prs_uint32("panningwidth", ps, depth, &devmode->panningwidth))
+ return False;
+ if (!prs_uint32("panningheight", ps, depth, &devmode->panningheight))
+ return False;
+
+ if (devmode->driverextra!=0) {
+ if (UNMARSHALLING(ps)) {
+ devmode->private=(uint8 *)prs_alloc_mem(ps, devmode->driverextra*sizeof(uint8));
+ if(devmode->private == NULL)
+ return False;
+ DEBUG(7,("spoolss_io_devmode: allocated memory [%d] for private\n",devmode->driverextra));
+ }
+
+ DEBUG(7,("spoolss_io_devmode: parsing [%d] bytes of private\n",devmode->driverextra));
+ if (!prs_uint8s(False, "private", ps, depth,
+ devmode->private, devmode->driverextra))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Read or write a DEVICEMODE container
+********************************************************************/
+
+static BOOL spoolss_io_devmode_cont(char *desc, DEVMODE_CTR *dm_c, prs_struct *ps, int depth)
+{
+ if (dm_c==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_devmode_cont");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size", ps, depth, &dm_c->size))
+ return False;
+
+ if (!prs_uint32("devmode_ptr", ps, depth, &dm_c->devmode_ptr))
+ return False;
+
+ if (dm_c->size==0 || dm_c->devmode_ptr==0) {
+ if (UNMARSHALLING(ps))
+ /* if while reading there is no DEVMODE ... */
+ dm_c->devmode=NULL;
+ return True;
+ }
+
+ /* so we have a DEVICEMODE to follow */
+ if (UNMARSHALLING(ps)) {
+ DEBUG(9,("Allocating memory for spoolss_io_devmode\n"));
+ dm_c->devmode=(DEVICEMODE *)prs_alloc_mem(ps,sizeof(DEVICEMODE));
+ if(dm_c->devmode == NULL)
+ return False;
+ }
+
+ /* this is bad code, shouldn't be there */
+ if (!prs_uint32("size", ps, depth, &dm_c->size))
+ return False;
+
+ if (!spoolss_io_devmode(desc, ps, depth, dm_c->devmode))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static BOOL spoolss_io_printer_default(char *desc, PRINTER_DEFAULT *pd, prs_struct *ps, int depth)
+{
+ if (pd==NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_printer_default");
+ depth++;
+
+ if (!prs_uint32("datatype_ptr", ps, depth, &pd->datatype_ptr))
+ return False;
+
+ if (!smb_io_unistr2("datatype", &pd->datatype, pd->datatype_ptr, ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_devmode_cont("", &pd->devmode_cont, ps, depth))
+ return False;
+
+ if (!prs_uint32("access_required", ps, depth, &pd->access_required))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
+ const fstring printername,
+ const fstring datatype,
+ uint32 access_required,
+ const fstring clientname,
+ const fstring user_name)
+{
+ DEBUG(5,("make_spoolss_q_open_printer_ex\n"));
+ q_u->printername_ptr = (printername!=NULL)?1:0;
+ init_unistr2(&q_u->printername, printername, strlen(printername)+1);
+
+ q_u->printer_default.datatype_ptr = 0;
+/*
+ q_u->printer_default.datatype_ptr = (datatype!=NULL)?1:0;
+ init_unistr2(&q_u->printer_default.datatype, datatype, strlen(datatype));
+*/
+ q_u->printer_default.devmode_cont.size=0;
+ q_u->printer_default.devmode_cont.devmode_ptr=0;
+ q_u->printer_default.devmode_cont.devmode=NULL;
+ q_u->printer_default.access_required=access_required;
+ q_u->user_switch=1;
+ q_u->user_ctr.level=1;
+ q_u->user_ctr.ptr=1;
+ q_u->user_ctr.user1.size=strlen(clientname)+strlen(user_name)+10;
+ q_u->user_ctr.user1.client_name_ptr = (clientname!=NULL)?1:0;
+ q_u->user_ctr.user1.user_name_ptr = (user_name!=NULL)?1:0;
+ q_u->user_ctr.user1.build=1381;
+ q_u->user_ctr.user1.major=2;
+ q_u->user_ctr.user1.minor=0;
+ q_u->user_ctr.user1.processor=0;
+ init_unistr2(&q_u->user_ctr.user1.client_name, clientname, strlen(clientname)+1);
+ init_unistr2(&q_u->user_ctr.user1.user_name, user_name, strlen(user_name)+1);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_addprinterex(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_ADDPRINTEREX *q_u,
+ const char *srv_name,
+ const char* clientname,
+ const char* user_name,
+ uint32 level,
+ PRINTER_INFO_CTR *ctr)
+{
+ DEBUG(5,("make_spoolss_q_addprinterex\n"));
+
+ if (!ctr) return False;
+
+ q_u->server_name_ptr = (srv_name!=NULL)?1:0;
+ init_unistr2(&q_u->server_name, srv_name, strlen(srv_name));
+
+ q_u->level = level;
+
+ q_u->info.level = level;
+ q_u->info.info_ptr = (ctr->printers_2!=NULL)?1:0;
+ switch (level)
+ {
+ case 2:
+ /* init q_u->info.info2 from *info */
+ if (!make_spoolss_printer_info_2(mem_ctx, &q_u->info.info_2, ctr->printers_2))
+ {
+ DEBUG(0,("make_spoolss_q_addprinterex: Unable to fill SPOOL_Q_ADDPRINTEREX struct!\n"));
+ return False;
+ }
+ break;
+ default :
+ break;
+ }
+
+ q_u->unk0 = q_u->unk1 = q_u->unk2 = q_u->unk3 = 0;
+
+ q_u->user_switch=1;
+
+ q_u->user_ctr.level=1;
+ q_u->user_ctr.ptr=1;
+ q_u->user_ctr.user1.client_name_ptr = (clientname!=NULL)?1:0;
+ q_u->user_ctr.user1.user_name_ptr = (user_name!=NULL)?1:0;
+ q_u->user_ctr.user1.build=1381;
+ q_u->user_ctr.user1.major=2;
+ q_u->user_ctr.user1.minor=0;
+ q_u->user_ctr.user1.processor=0;
+ init_unistr2(&q_u->user_ctr.user1.client_name, clientname, strlen(clientname)+1);
+ init_unistr2(&q_u->user_ctr.user1.user_name, user_name, strlen(user_name)+1);
+ q_u->user_ctr.user1.size=q_u->user_ctr.user1.user_name.uni_str_len +
+ q_u->user_ctr.user1.client_name.uni_str_len + 2;
+
+ return True;
+}
+
+/*******************************************************************
+create a SPOOL_PRINTER_INFO_2 stuct from a PRINTER_INFO_2 struct
+*******************************************************************/
+
+BOOL make_spoolss_printer_info_2(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_PRINTER_INFO_LEVEL_2 **spool_info2,
+ PRINTER_INFO_2 *info
+)
+{
+
+ SPOOL_PRINTER_INFO_LEVEL_2 *inf;
+
+ /* allocate the necessary memory */
+ if (!(inf=(SPOOL_PRINTER_INFO_LEVEL_2*)talloc(mem_ctx, sizeof(SPOOL_PRINTER_INFO_LEVEL_2))))
+ {
+ DEBUG(0,("make_spoolss_printer_info_2: Unable to allocate SPOOL_PRINTER_INFO_LEVEL_2 sruct!\n"));
+ return False;
+ }
+
+ inf->servername_ptr = (info->servername.buffer!=NULL)?1:0;
+ inf->printername_ptr = (info->printername.buffer!=NULL)?1:0;
+ inf->sharename_ptr = (info->sharename.buffer!=NULL)?1:0;
+ inf->portname_ptr = (info->portname.buffer!=NULL)?1:0;
+ inf->drivername_ptr = (info->drivername.buffer!=NULL)?1:0;
+ inf->comment_ptr = (info->comment.buffer!=NULL)?1:0;
+ inf->location_ptr = (info->location.buffer!=NULL)?1:0;
+ inf->devmode_ptr = (info->devmode!=NULL)?1:0;
+ inf->sepfile_ptr = (info->sepfile.buffer!=NULL)?1:0;
+ inf->printprocessor_ptr = (info->printprocessor.buffer!=NULL)?1:0;
+ inf->datatype_ptr = (info->datatype.buffer!=NULL)?1:0;
+ inf->parameters_ptr = (info->parameters.buffer!=NULL)?1:0;
+ inf->secdesc_ptr = (info->secdesc!=NULL)?1:0;
+ inf->attributes = info->attributes;
+ inf->priority = info->priority;
+ inf->default_priority = info->defaultpriority;
+ inf->starttime = info->starttime;
+ inf->untiltime = info->untiltime;
+ inf->cjobs = info->cjobs;
+ inf->averageppm = info->averageppm;
+ init_unistr2_from_unistr(&inf->servername, &info->servername);
+ init_unistr2_from_unistr(&inf->printername, &info->printername);
+ init_unistr2_from_unistr(&inf->sharename, &info->sharename);
+ init_unistr2_from_unistr(&inf->portname, &info->portname);
+ init_unistr2_from_unistr(&inf->drivername, &info->drivername);
+ init_unistr2_from_unistr(&inf->comment, &info->comment);
+ init_unistr2_from_unistr(&inf->location, &info->location);
+ init_unistr2_from_unistr(&inf->sepfile, &info->sepfile);
+ init_unistr2_from_unistr(&inf->printprocessor, &info->printprocessor);
+ init_unistr2_from_unistr(&inf->datatype, &info->datatype);
+ init_unistr2_from_unistr(&inf->parameters, &info->parameters);
+ init_unistr2_from_unistr(&inf->datatype, &info->datatype);
+ inf->secdesc = inf->secdesc;
+
+ *spool_info2 = inf;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_open_printer_ex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_open_printer_ex(char *desc, SPOOL_Q_OPEN_PRINTER_EX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_open_printer_ex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("printername_ptr", ps, depth, &q_u->printername_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->printername, q_u->printername_ptr, ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_printer_default("", &q_u->printer_default, ps, depth))
+ return False;
+
+ if (!prs_uint32("user_switch", ps, depth, &q_u->user_switch))
+ return False;
+ if (!spool_io_user_level("", &q_u->user_ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_deleteprinterdriver(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_DELETEPRINTERDRIVER *q_u,
+ const char *server,
+ const char* arch,
+ const char* driver
+)
+{
+ DEBUG(5,("make_spoolss_q_deleteprinterdriver\n"));
+
+ q_u->server_ptr = (server!=NULL)?1:0;
+
+ /* these must be NULL terminated or else NT4 will
+ complain about invalid parameters --jerry */
+ init_unistr2(&q_u->server, server, strlen(server)+1);
+ init_unistr2(&q_u->arch, arch, strlen(arch)+1);
+ init_unistr2(&q_u->driver, driver, strlen(driver)+1);
+
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_open_printer_ex (srv_spoolss.c)
+ * called from spoolss_open_printer_ex (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_open_printer_ex(char *desc, SPOOL_R_OPEN_PRINTER_EX *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_open_printer_ex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&(r_u->handle),ps,depth))
+ return False;
+
+ if (!prs_werror("status code", ps, depth, &(r_u->status)))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * make a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_getprinterdata(SPOOL_Q_GETPRINTERDATA *q_u,
+ const POLICY_HND *handle,
+ UNISTR2 *valuename, uint32 size)
+{
+ if (q_u == NULL) return False;
+
+ DEBUG(5,("make_spoolss_q_getprinterdata\n"));
+
+ q_u->handle = *handle;
+ copy_unistr2(&q_u->valuename, valuename);
+ q_u->size = size;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_getprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_getprinterdata(char *desc, SPOOL_Q_GETPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_deleteprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_deleteprinterdata(char *desc, SPOOL_Q_DELETEPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_deleteprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_deleteprinterdata(char *desc, SPOOL_R_DELETEPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdata");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_getprinterdata (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_getprinterdata(char *desc, SPOOL_R_GETPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdata");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+ if (!prs_uint32("size", ps, depth, &r_u->size))
+ return False;
+
+ if (!prs_uint8s(False,"data", ps, depth, r_u->data, r_u->size))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * make a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_closeprinter(SPOOL_Q_CLOSEPRINTER *q_u, POLICY_HND *hnd)
+{
+ if (q_u == NULL) return False;
+
+ DEBUG(5,("make_spoolss_q_closeprinter\n"));
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_abortprinter (srv_spoolss.c)
+ * called from spoolss_abortprinter (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_abortprinter(char *desc, SPOOL_Q_ABORTPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_abortprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_abortprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_abortprinter(char *desc, SPOOL_R_ABORTPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_abortprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_deleteprinter (srv_spoolss.c)
+ * called from spoolss_deleteprinter (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_deleteprinter(char *desc, SPOOL_Q_DELETEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_deleteprinter (srv_spoolss.c)
+ * called from spoolss_deleteprinter (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_deleteprinter(char *desc, SPOOL_R_DELETEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ * called from api_spoolss_deleteprinterdriver (srv_spoolss.c)
+ * called from spoolss_deleteprinterdriver (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_deleteprinterdriver(char *desc, SPOOL_Q_DELETEPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteprinterdriver");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_ptr", ps, depth, &q_u->server_ptr))
+ return False;
+ if(!smb_io_unistr2("server", &q_u->server, q_u->server_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("arch", &q_u->arch, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("driver", &q_u->driver, True, ps, depth))
+ return False;
+
+
+ return True;
+}
+
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+BOOL spoolss_io_r_deleteprinterdriver(char *desc, SPOOL_R_DELETEPRINTERDRIVER *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteprinterdriver");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+
+/*******************************************************************
+ * read a structure.
+ * called from static spoolss_q_closeprinter (srv_spoolss.c)
+ * called from spoolss_closeprinter (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_closeprinter(char *desc, SPOOL_Q_CLOSEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_closeprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from static spoolss_r_closeprinter (srv_spoolss.c)
+ * called from spoolss_closeprinter (cli_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_closeprinter(char *desc, SPOOL_R_CLOSEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_closeprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_startdocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_startdocprinter(char *desc, SPOOL_Q_STARTDOCPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_startdocprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if(!smb_io_doc_info_container("",&q_u->doc_info_container, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_startdocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_startdocprinter(char *desc, SPOOL_R_STARTDOCPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_startdocprinter");
+ depth++;
+ if(!prs_uint32("jobid", ps, depth, &r_u->jobid))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_enddocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_enddocprinter(char *desc, SPOOL_Q_ENDDOCPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enddocprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_enddocprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_enddocprinter(char *desc, SPOOL_R_ENDDOCPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enddocprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_startpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_startpageprinter(char *desc, SPOOL_Q_STARTPAGEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_startpageprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_startpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_startpageprinter(char *desc, SPOOL_R_STARTPAGEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_startpageprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_endpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_endpageprinter(char *desc, SPOOL_Q_ENDPAGEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_endpageprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_endpageprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_endpageprinter(char *desc, SPOOL_R_ENDPAGEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_endpageprinter");
+ depth++;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_writeprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_writeprinter(char *desc, SPOOL_Q_WRITEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_writeprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+ return False;
+
+ if (q_u->buffer_size!=0)
+ {
+ if (UNMARSHALLING(ps))
+ q_u->buffer=(uint8 *)prs_alloc_mem(ps,q_u->buffer_size*sizeof(uint8));
+ if(q_u->buffer == NULL)
+ return False;
+ if(!prs_uint8s(True, "buffer", ps, depth, q_u->buffer, q_u->buffer_size))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("buffer_size2", ps, depth, &q_u->buffer_size2))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_writeprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_writeprinter(char *desc, SPOOL_R_WRITEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_writeprinter");
+ depth++;
+ if(!prs_uint32("buffer_written", ps, depth, &r_u->buffer_written))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_rffpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_rffpcnex(char *desc, SPOOL_Q_RFFPCNEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_rffpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("flags", ps, depth, &q_u->flags))
+ return False;
+ if(!prs_uint32("options", ps, depth, &q_u->options))
+ return False;
+ if(!prs_uint32("localmachine_ptr", ps, depth, &q_u->localmachine_ptr))
+ return False;
+ if(!smb_io_unistr2("localmachine", &q_u->localmachine, q_u->localmachine_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("printerlocal", ps, depth, &q_u->printerlocal))
+ return False;
+
+ if(!prs_uint32("option_ptr", ps, depth, &q_u->option_ptr))
+ return False;
+
+ if (q_u->option_ptr!=0) {
+
+ if (UNMARSHALLING(ps))
+ if((q_u->option=(SPOOL_NOTIFY_OPTION *)prs_alloc_mem(ps,sizeof(SPOOL_NOTIFY_OPTION))) == NULL)
+ return False;
+
+ if(!smb_io_notify_option("notify option", q_u->option, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_rffpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_rffpcnex(char *desc, SPOOL_R_RFFPCNEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_rffpcnex");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_rfnpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_rfnpcnex(char *desc, SPOOL_Q_RFNPCNEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_rfnpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if(!prs_uint32("change", ps, depth, &q_u->change))
+ return False;
+
+ if(!prs_uint32("option_ptr", ps, depth, &q_u->option_ptr))
+ return False;
+
+ if (q_u->option_ptr!=0) {
+
+ if (UNMARSHALLING(ps))
+ if((q_u->option=(SPOOL_NOTIFY_OPTION *)prs_alloc_mem(ps,sizeof(SPOOL_NOTIFY_OPTION))) == NULL)
+ return False;
+
+ if(!smb_io_notify_option("notify option", q_u->option, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_rfnpcnex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_rfnpcnex(char *desc, SPOOL_R_RFNPCNEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_rfnpcnex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("info_ptr", ps, depth, &r_u->info_ptr))
+ return False;
+
+ if(!smb_io_notify_info("notify info", &r_u->info ,ps,depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * return the length of a uint16 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_uint16(uint16 *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_uint32(uint32 *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a NTTIME (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_nttime(NTTIME *value)
+{
+ return (sizeof(*value));
+}
+
+/*******************************************************************
+ * return the length of a UNICODE string in number of char, includes:
+ * - the leading zero
+ * - the relative pointer size
+ ********************************************************************/
+
+static uint32 size_of_relative_string(UNISTR *string)
+{
+ uint32 size=0;
+
+ size=str_len_uni(string); /* the string length */
+ size=size+1; /* add the leading zero */
+ size=size*2; /* convert in char */
+ /* Ensure size is 4 byte multiple (prs_align is being called...). */
+ size += ((4 - (size & 3)) & 3);
+ size=size+4; /* add the size of the ptr */
+
+ return size;
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_device_mode(DEVICEMODE *devmode)
+{
+ if (devmode==NULL)
+ return (4);
+ else
+ return (4+devmode->size+devmode->driverextra);
+}
+
+/*******************************************************************
+ * return the length of a uint32 (obvious, but the code is clean)
+ ********************************************************************/
+
+static uint32 size_of_systemtime(SYSTEMTIME *systime)
+{
+ if (systime==NULL)
+ return (4);
+ else
+ return (sizeof(SYSTEMTIME) +4);
+}
+
+/*******************************************************************
+ * write a UNICODE string.
+ * used by all the RPC structs passing a buffer
+ ********************************************************************/
+
+static BOOL spoolss_smb_io_unistr(char *desc, UNISTR *uni, prs_struct *ps, int depth)
+{
+ if (uni == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_smb_io_unistr");
+ depth++;
+
+ /* there should be no align here as it can mess up
+ parsing a NEW_BUFFER->prs */
+#if 0 /* JERRY */
+ if (!prs_align(ps))
+ return False;
+#endif
+
+ if (!prs_unistr("unistr", ps, depth, uni))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a UNICODE string and its relative pointer.
+ * used by all the RPC structs passing a buffer
+ *
+ * As I'm a nice guy, I'm forcing myself to explain this code.
+ * MS did a good job in the overall spoolss code except in some
+ * functions where they are passing the API buffer directly in the
+ * RPC request/reply. That's to maintain compatiility at the API level.
+ * They could have done it the good way the first time.
+ *
+ * So what happen is: the strings are written at the buffer's end,
+ * in the reverse order of the original structure. Some pointers to
+ * the strings are also in the buffer. Those are relative to the
+ * buffer's start.
+ *
+ * If you don't understand or want to change that function,
+ * first get in touch with me: jfm@samba.org
+ *
+ ********************************************************************/
+
+static BOOL smb_io_relstr(char *desc, NEW_BUFFER *buffer, int depth, UNISTR *string)
+{
+ prs_struct *ps=&buffer->prs;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ buffer->string_at_end -= (size_of_relative_string(string) - 4);
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ buffer->string_at_end = prs_offset(ps);
+
+ /* write the string */
+ if (!smb_io_unistr(desc, string, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ }
+ else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &(buffer->string_at_end)))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end+buffer->struct_start))
+ return False;
+
+ /* read the string */
+ if (!spoolss_smb_io_unistr(desc, string, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ * write a array of UNICODE strings and its relative pointer.
+ * used by 2 RPC structs
+ ********************************************************************/
+
+static BOOL smb_io_relarraystr(char *desc, NEW_BUFFER *buffer, int depth, uint16 **string)
+{
+ UNISTR chaine;
+
+ prs_struct *ps=&buffer->prs;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+ uint16 *p;
+ uint16 *q;
+ uint16 zero=0;
+ p=*string;
+ q=*string;
+
+ /* first write the last 0 */
+ buffer->string_at_end -= 2;
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+
+ if(!prs_uint16("leading zero", ps, depth, &zero))
+ return False;
+
+ while (p && (*p!=0)) {
+ while (*q!=0)
+ q++;
+
+ /* Yes this should be malloc not talloc. Don't change. */
+
+ chaine.buffer = malloc((q-p+1)*sizeof(uint16));
+ if (chaine.buffer == NULL)
+ return False;
+
+ memcpy(chaine.buffer, p, (q-p+1)*sizeof(uint16));
+
+ buffer->string_at_end -= (q-p+1)*sizeof(uint16);
+
+ if(!prs_set_offset(ps, buffer->string_at_end)) {
+ SAFE_FREE(chaine.buffer);
+ return False;
+ }
+
+ /* write the string */
+ if (!spoolss_smb_io_unistr(desc, &chaine, ps, depth)) {
+ SAFE_FREE(chaine.buffer);
+ return False;
+ }
+ q++;
+ p=q;
+
+ SAFE_FREE(chaine.buffer);
+ }
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+
+ } else {
+
+ /* UNMARSHALLING */
+
+ uint32 old_offset;
+ uint16 *chaine2=NULL;
+ int l_chaine=0;
+ int l_chaine2=0;
+ size_t realloc_size = 0;
+
+ *string=NULL;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ do {
+ if (!spoolss_smb_io_unistr(desc, &chaine, ps, depth))
+ return False;
+
+ l_chaine=str_len_uni(&chaine);
+
+ /* we're going to add two more bytes here in case this
+ is the last string in the array and we need to add
+ an extra NULL for termination */
+ if (l_chaine > 0)
+ {
+ uint16 *tc2;
+
+ realloc_size = (l_chaine2+l_chaine+2)*sizeof(uint16);
+
+ /* Yes this should be realloc - it's freed below. JRA */
+
+ if((tc2=(uint16 *)Realloc(chaine2, realloc_size)) == NULL) {
+ SAFE_FREE(chaine2);
+ return False;
+ }
+ else chaine2 = tc2;
+ memcpy(chaine2+l_chaine2, chaine.buffer, (l_chaine+1)*sizeof(uint16));
+ l_chaine2+=l_chaine+1;
+ }
+
+ } while(l_chaine!=0);
+
+ /* the end should be bould NULL terminated so add
+ the second one here */
+ if (chaine2)
+ {
+ chaine2[l_chaine2] = '\0';
+ *string=(uint16 *)talloc_memdup(prs_get_mem_context(ps),chaine2,realloc_size);
+ SAFE_FREE(chaine2);
+ }
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Parse a DEVMODE structure and its relative pointer.
+********************************************************************/
+
+static BOOL smb_io_relsecdesc(char *desc, NEW_BUFFER *buffer, int depth, SEC_DESC **secdesc)
+{
+ prs_struct *ps= &buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_relsecdesc");
+ depth++;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ if (! *secdesc) {
+ relative_offset = 0;
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ return True;
+ }
+
+ if (*secdesc != NULL) {
+ buffer->string_at_end -= sec_desc_size(*secdesc);
+
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+ /* write the secdesc */
+ if (!sec_io_desc(desc, secdesc, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+ }
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ } else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ /* read the sd */
+ if (!sec_io_desc(desc, secdesc, ps, depth))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Parse a DEVMODE structure and its relative pointer.
+********************************************************************/
+
+static BOOL smb_io_reldevmode(char *desc, NEW_BUFFER *buffer, int depth, DEVICEMODE **devmode)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_reldevmode");
+ depth++;
+
+ if (MARSHALLING(ps)) {
+ uint32 struct_offset = prs_offset(ps);
+ uint32 relative_offset;
+
+ if (*devmode == NULL) {
+ relative_offset=0;
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ DEBUG(8, ("boing, the devmode was NULL\n"));
+
+ return True;
+ }
+
+ buffer->string_at_end -= ((*devmode)->size + (*devmode)->driverextra);
+
+ if(!prs_set_offset(ps, buffer->string_at_end))
+ return False;
+
+ /* write the DEVMODE */
+ if (!spoolss_io_devmode(desc, ps, depth, *devmode))
+ return False;
+
+ if(!prs_set_offset(ps, struct_offset))
+ return False;
+
+ relative_offset=buffer->string_at_end - buffer->struct_start;
+ /* write its offset */
+ if (!prs_uint32("offset", ps, depth, &relative_offset))
+ return False;
+ }
+ else {
+ uint32 old_offset;
+
+ /* read the offset */
+ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
+ return False;
+
+ old_offset = prs_offset(ps);
+ if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
+ return False;
+
+ /* read the string */
+ if((*devmode=(DEVICEMODE *)prs_alloc_mem(ps,sizeof(DEVICEMODE))) == NULL)
+ return False;
+ if (!spoolss_io_devmode(desc, ps, depth, *devmode))
+ return False;
+
+ if(!prs_set_offset(ps, old_offset))
+ return False;
+ }
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_0 structure.
+********************************************************************/
+
+BOOL smb_io_printer_info_0(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_0 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_0");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("servername", buffer, depth, &info->servername))
+ return False;
+
+ if(!prs_uint32("cjobs", ps, depth, &info->cjobs))
+ return False;
+ if(!prs_uint32("total_jobs", ps, depth, &info->total_jobs))
+ return False;
+ if(!prs_uint32("total_bytes", ps, depth, &info->total_bytes))
+ return False;
+
+ if(!prs_uint16("year", ps, depth, &info->year))
+ return False;
+ if(!prs_uint16("month", ps, depth, &info->month))
+ return False;
+ if(!prs_uint16("dayofweek", ps, depth, &info->dayofweek))
+ return False;
+ if(!prs_uint16("day", ps, depth, &info->day))
+ return False;
+ if(!prs_uint16("hour", ps, depth, &info->hour))
+ return False;
+ if(!prs_uint16("minute", ps, depth, &info->minute))
+ return False;
+ if(!prs_uint16("second", ps, depth, &info->second))
+ return False;
+ if(!prs_uint16("milliseconds", ps, depth, &info->milliseconds))
+ return False;
+
+ if(!prs_uint32("global_counter", ps, depth, &info->global_counter))
+ return False;
+ if(!prs_uint32("total_pages", ps, depth, &info->total_pages))
+ return False;
+
+ if(!prs_uint16("major_version", ps, depth, &info->major_version))
+ return False;
+ if(!prs_uint16("build_version", ps, depth, &info->build_version))
+ return False;
+ if(!prs_uint32("unknown7", ps, depth, &info->unknown7))
+ return False;
+ if(!prs_uint32("unknown8", ps, depth, &info->unknown8))
+ return False;
+ if(!prs_uint32("unknown9", ps, depth, &info->unknown9))
+ return False;
+ if(!prs_uint32("session_counter", ps, depth, &info->session_counter))
+ return False;
+ if(!prs_uint32("unknown11", ps, depth, &info->unknown11))
+ return False;
+ if(!prs_uint32("printer_errors", ps, depth, &info->printer_errors))
+ return False;
+ if(!prs_uint32("unknown13", ps, depth, &info->unknown13))
+ return False;
+ if(!prs_uint32("unknown14", ps, depth, &info->unknown14))
+ return False;
+ if(!prs_uint32("unknown15", ps, depth, &info->unknown15))
+ return False;
+ if(!prs_uint32("unknown16", ps, depth, &info->unknown16))
+ return False;
+ if(!prs_uint32("change_id", ps, depth, &info->change_id))
+ return False;
+ if(!prs_uint32("unknown18", ps, depth, &info->unknown18))
+ return False;
+ if(!prs_uint32("status" , ps, depth, &info->status))
+ return False;
+ if(!prs_uint32("unknown20", ps, depth, &info->unknown20))
+ return False;
+ if(!prs_uint32("c_setprinter", ps, depth, &info->c_setprinter))
+ return False;
+ if(!prs_uint16("unknown22", ps, depth, &info->unknown22))
+ return False;
+ if(!prs_uint16("unknown23", ps, depth, &info->unknown23))
+ return False;
+ if(!prs_uint16("unknown24", ps, depth, &info->unknown24))
+ return False;
+ if(!prs_uint16("unknown25", ps, depth, &info->unknown25))
+ return False;
+ if(!prs_uint16("unknown26", ps, depth, &info->unknown26))
+ return False;
+ if(!prs_uint16("unknown27", ps, depth, &info->unknown27))
+ return False;
+ if(!prs_uint16("unknown28", ps, depth, &info->unknown28))
+ return False;
+ if(!prs_uint16("unknown29", ps, depth, &info->unknown29))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_1 structure.
+********************************************************************/
+
+BOOL smb_io_printer_info_1(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("flags", ps, depth, &info->flags))
+ return False;
+ if (!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("comment", buffer, depth, &info->comment))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_2 structure.
+********************************************************************/
+
+BOOL smb_io_printer_info_2(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("servername", buffer, depth, &info->servername))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("sharename", buffer, depth, &info->sharename))
+ return False;
+ if (!smb_io_relstr("portname", buffer, depth, &info->portname))
+ return False;
+ if (!smb_io_relstr("drivername", buffer, depth, &info->drivername))
+ return False;
+ if (!smb_io_relstr("comment", buffer, depth, &info->comment))
+ return False;
+ if (!smb_io_relstr("location", buffer, depth, &info->location))
+ return False;
+
+ /* NT parses the DEVMODE at the end of the struct */
+ if (!smb_io_reldevmode("devmode", buffer, depth, &info->devmode))
+ return False;
+
+ if (!smb_io_relstr("sepfile", buffer, depth, &info->sepfile))
+ return False;
+ if (!smb_io_relstr("printprocessor", buffer, depth, &info->printprocessor))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+ if (!smb_io_relstr("parameters", buffer, depth, &info->parameters))
+ return False;
+
+ if (!smb_io_relsecdesc("secdesc", buffer, depth, &info->secdesc))
+ return False;
+
+ if (!prs_uint32("attributes", ps, depth, &info->attributes))
+ return False;
+ if (!prs_uint32("priority", ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("defpriority", ps, depth, &info->defaultpriority))
+ return False;
+ if (!prs_uint32("starttime", ps, depth, &info->starttime))
+ return False;
+ if (!prs_uint32("untiltime", ps, depth, &info->untiltime))
+ return False;
+ if (!prs_uint32("status", ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("jobs", ps, depth, &info->cjobs))
+ return False;
+ if (!prs_uint32("averageppm", ps, depth, &info->averageppm))
+ return False;
+
+#if 0 /* JFMTEST */
+ if (!prs_uint32_post("secdesc_ptr", ps, depth, NULL, sec_offset, info->secdesc ? prs_offset(ps)-buffer->struct_start : 0 ))
+ return False;
+
+ if (!sec_io_desc("secdesc", &info->secdesc, ps, depth))
+ return False;
+#endif
+ return True;
+}
+
+/*******************************************************************
+ Parse a PRINTER_INFO_3 structure.
+********************************************************************/
+
+BOOL smb_io_printer_info_3(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_3 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_info_3");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("flags", ps, depth, &info->flags))
+ return False;
+ if (!sec_io_desc("sec_desc", &info->secdesc, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_1 structure.
+********************************************************************/
+
+BOOL smb_io_port_info_1(char *desc, NEW_BUFFER *buffer, PORT_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_2 structure.
+********************************************************************/
+
+BOOL smb_io_port_info_2(char *desc, NEW_BUFFER *buffer, PORT_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+ if (!smb_io_relstr("monitor_name", buffer, depth, &info->monitor_name))
+ return False;
+ if (!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if (!prs_uint32("port_type", ps, depth, &info->port_type))
+ return False;
+ if (!prs_uint32("reserved", ps, depth, &info->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_1 structure.
+********************************************************************/
+
+BOOL smb_io_printer_driver_info_1(char *desc, NEW_BUFFER *buffer, DRIVER_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_2 structure.
+********************************************************************/
+
+BOOL smb_io_printer_driver_info_2(char *desc, NEW_BUFFER *buffer, DRIVER_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_3 structure.
+********************************************************************/
+
+BOOL smb_io_printer_driver_info_3(char *desc, NEW_BUFFER *buffer, DRIVER_INFO_3 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_3");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+ if (!smb_io_relstr("helpfile", buffer, depth, &info->helpfile))
+ return False;
+
+ if (!smb_io_relarraystr("dependentfiles", buffer, depth, &info->dependentfiles))
+ return False;
+
+ if (!smb_io_relstr("monitorname", buffer, depth, &info->monitorname))
+ return False;
+ if (!smb_io_relstr("defaultdatatype", buffer, depth, &info->defaultdatatype))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a DRIVER_INFO_6 structure.
+********************************************************************/
+
+BOOL smb_io_printer_driver_info_6(char *desc, NEW_BUFFER *buffer, DRIVER_INFO_6 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printer_driver_info_6");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("version", ps, depth, &info->version))
+ return False;
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("architecture", buffer, depth, &info->architecture))
+ return False;
+ if (!smb_io_relstr("driverpath", buffer, depth, &info->driverpath))
+ return False;
+ if (!smb_io_relstr("datafile", buffer, depth, &info->datafile))
+ return False;
+ if (!smb_io_relstr("configfile", buffer, depth, &info->configfile))
+ return False;
+ if (!smb_io_relstr("helpfile", buffer, depth, &info->helpfile))
+ return False;
+
+ if (!smb_io_relarraystr("dependentfiles", buffer, depth, &info->dependentfiles))
+ return False;
+
+ if (!smb_io_relstr("monitorname", buffer, depth, &info->monitorname))
+ return False;
+ if (!smb_io_relstr("defaultdatatype", buffer, depth, &info->defaultdatatype))
+ return False;
+
+ if (!smb_io_relarraystr("previousdrivernames", buffer, depth, &info->previousdrivernames))
+ return False;
+
+ if (!prs_uint32("date.low", ps, depth, &info->driver_date.low))
+ return False;
+ if (!prs_uint32("date.high", ps, depth, &info->driver_date.high))
+ return False;
+
+ if (!prs_uint32("padding", ps, depth, &info->padding))
+ return False;
+
+ if (!prs_uint32("driver_version_low", ps, depth, &info->driver_version_low))
+ return False;
+
+ if (!prs_uint32("driver_version_high", ps, depth, &info->driver_version_high))
+ return False;
+
+ if (!smb_io_relstr("mfgname", buffer, depth, &info->mfgname))
+ return False;
+ if (!smb_io_relstr("oem_url", buffer, depth, &info->oem_url))
+ return False;
+ if (!smb_io_relstr("hardware_id", buffer, depth, &info->hardware_id))
+ return False;
+ if (!smb_io_relstr("provider", buffer, depth, &info->provider))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a JOB_INFO_1 structure.
+********************************************************************/
+
+BOOL smb_io_job_info_1(char *desc, NEW_BUFFER *buffer, JOB_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_job_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("jobid", ps, depth, &info->jobid))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("machinename", buffer, depth, &info->machinename))
+ return False;
+ if (!smb_io_relstr("username", buffer, depth, &info->username))
+ return False;
+ if (!smb_io_relstr("document", buffer, depth, &info->document))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+ if (!smb_io_relstr("text_status", buffer, depth, &info->text_status))
+ return False;
+ if (!prs_uint32("status", ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("priority", ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("position", ps, depth, &info->position))
+ return False;
+ if (!prs_uint32("totalpages", ps, depth, &info->totalpages))
+ return False;
+ if (!prs_uint32("pagesprinted", ps, depth, &info->pagesprinted))
+ return False;
+ if (!spoolss_io_system_time("submitted", ps, depth, &info->submitted))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a JOB_INFO_2 structure.
+********************************************************************/
+
+BOOL smb_io_job_info_2(char *desc, NEW_BUFFER *buffer, JOB_INFO_2 *info, int depth)
+{
+ uint32 pipo=0;
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_job_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("jobid",ps, depth, &info->jobid))
+ return False;
+ if (!smb_io_relstr("printername", buffer, depth, &info->printername))
+ return False;
+ if (!smb_io_relstr("machinename", buffer, depth, &info->machinename))
+ return False;
+ if (!smb_io_relstr("username", buffer, depth, &info->username))
+ return False;
+ if (!smb_io_relstr("document", buffer, depth, &info->document))
+ return False;
+ if (!smb_io_relstr("notifyname", buffer, depth, &info->notifyname))
+ return False;
+ if (!smb_io_relstr("datatype", buffer, depth, &info->datatype))
+ return False;
+
+ if (!smb_io_relstr("printprocessor", buffer, depth, &info->printprocessor))
+ return False;
+ if (!smb_io_relstr("parameters", buffer, depth, &info->parameters))
+ return False;
+ if (!smb_io_relstr("drivername", buffer, depth, &info->drivername))
+ return False;
+ if (!smb_io_reldevmode("devmode", buffer, depth, &info->devmode))
+ return False;
+ if (!smb_io_relstr("text_status", buffer, depth, &info->text_status))
+ return False;
+
+/* SEC_DESC sec_desc;*/
+ if (!prs_uint32("Hack! sec desc", ps, depth, &pipo))
+ return False;
+
+ if (!prs_uint32("status",ps, depth, &info->status))
+ return False;
+ if (!prs_uint32("priority",ps, depth, &info->priority))
+ return False;
+ if (!prs_uint32("position",ps, depth, &info->position))
+ return False;
+ if (!prs_uint32("starttime",ps, depth, &info->starttime))
+ return False;
+ if (!prs_uint32("untiltime",ps, depth, &info->untiltime))
+ return False;
+ if (!prs_uint32("totalpages",ps, depth, &info->totalpages))
+ return False;
+ if (!prs_uint32("size",ps, depth, &info->size))
+ return False;
+ if (!spoolss_io_system_time("submitted", ps, depth, &info->submitted) )
+ return False;
+ if (!prs_uint32("timeelapsed",ps, depth, &info->timeelapsed))
+ return False;
+ if (!prs_uint32("pagesprinted",ps, depth, &info->pagesprinted))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL smb_io_form_1(char *desc, NEW_BUFFER *buffer, FORM_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_form_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!prs_uint32("flag", ps, depth, &info->flag))
+ return False;
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ if (!prs_uint32("width", ps, depth, &info->width))
+ return False;
+ if (!prs_uint32("length", ps, depth, &info->length))
+ return False;
+ if (!prs_uint32("left", ps, depth, &info->left))
+ return False;
+ if (!prs_uint32("top", ps, depth, &info->top))
+ return False;
+ if (!prs_uint32("right", ps, depth, &info->right))
+ return False;
+ if (!prs_uint32("bottom", ps, depth, &info->bottom))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Read/write a BUFFER struct.
+********************************************************************/
+
+static BOOL spoolss_io_buffer(char *desc, prs_struct *ps, int depth, NEW_BUFFER **pp_buffer)
+{
+ NEW_BUFFER *buffer = *pp_buffer;
+
+ prs_debug(ps, depth, desc, "spoolss_io_buffer");
+ depth++;
+
+ if (UNMARSHALLING(ps))
+ buffer = *pp_buffer = (NEW_BUFFER *)prs_alloc_mem(ps, sizeof(NEW_BUFFER));
+
+ if (buffer == NULL)
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &buffer->ptr))
+ return False;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ buffer->size=0;
+ buffer->string_at_end=0;
+
+ if (buffer->ptr==0) {
+ /*
+ * JRA. I'm not sure if the data in here is in big-endian format if
+ * the client is big-endian. Leave as default (little endian) for now.
+ */
+
+ if (!prs_init(&buffer->prs, 0, prs_get_mem_context(ps), UNMARSHALL))
+ return False;
+ return True;
+ }
+
+ if (!prs_uint32("size", ps, depth, &buffer->size))
+ return False;
+
+ /*
+ * JRA. I'm not sure if the data in here is in big-endian format if
+ * the client is big-endian. Leave as default (little endian) for now.
+ */
+
+ if (!prs_init(&buffer->prs, buffer->size, prs_get_mem_context(ps), UNMARSHALL))
+ return False;
+
+ if (!prs_append_some_prs_data(&buffer->prs, ps, prs_offset(ps), buffer->size))
+ return False;
+
+ if (!prs_set_offset(&buffer->prs, 0))
+ return False;
+
+ if (!prs_set_offset(ps, buffer->size+prs_offset(ps)))
+ return False;
+
+ buffer->string_at_end=buffer->size;
+
+ return True;
+ }
+ else {
+ BOOL ret = False;
+
+ /* writing */
+ if (buffer->ptr==0) {
+ /* We have finished with the data in buffer->prs - free it. */
+ prs_mem_free(&buffer->prs);
+ return True;
+ }
+
+ if (!prs_uint32("size", ps, depth, &buffer->size))
+ goto out;
+
+ if (!prs_append_some_prs_data(ps, &buffer->prs, 0, buffer->size))
+ goto out;
+
+ ret = True;
+ out:
+
+ /* We have finished with the data in buffer->prs - free it. */
+ prs_mem_free(&buffer->prs);
+
+ return ret;
+ }
+}
+
+/*******************************************************************
+ move a BUFFER from the query to the reply.
+ As the data pointers in NEW_BUFFER are malloc'ed, not talloc'ed,
+ this is ok. This is an OPTIMIZATION and is not strictly neccessary.
+********************************************************************/
+
+void spoolss_move_buffer(NEW_BUFFER *src, NEW_BUFFER **dest)
+{
+ prs_switch_type(&src->prs, MARSHALL);
+ if(!prs_set_offset(&src->prs, 0))
+ return;
+ prs_force_dynamic(&(src->prs));
+
+ *dest=src;
+}
+
+/*******************************************************************
+ Get the size of a BUFFER struct.
+********************************************************************/
+
+uint32 new_get_buffer_size(NEW_BUFFER *buffer)
+{
+ return (buffer->size);
+}
+
+/*******************************************************************
+ Parse a DRIVER_DIRECTORY_1 structure.
+********************************************************************/
+
+BOOL smb_io_driverdir_1(char *desc, NEW_BUFFER *buffer, DRIVER_DIRECTORY_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_driverdir_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_unistr(desc, &info->name, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_1 structure.
+********************************************************************/
+
+BOOL smb_io_port_1(char *desc, NEW_BUFFER *buffer, PORT_INFO_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if(!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a PORT_INFO_2 structure.
+********************************************************************/
+
+BOOL smb_io_port_2(char *desc, NEW_BUFFER *buffer, PORT_INFO_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_port_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if(!smb_io_relstr("port_name", buffer, depth, &info->port_name))
+ return False;
+ if(!smb_io_relstr("monitor_name", buffer, depth, &info->monitor_name))
+ return False;
+ if(!smb_io_relstr("description", buffer, depth, &info->description))
+ return False;
+ if(!prs_uint32("port_type", ps, depth, &info->port_type))
+ return False;
+ if(!prs_uint32("reserved", ps, depth, &info->reserved))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL smb_io_printprocessor_info_1(char *desc, NEW_BUFFER *buffer, PRINTPROCESSOR_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocessor_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL smb_io_printprocdatatype_info_1(char *desc, NEW_BUFFER *buffer, PRINTPROCDATATYPE_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocdatatype_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL smb_io_printmonitor_info_1(char *desc, NEW_BUFFER *buffer, PRINTMONITOR_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printmonitor_info_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL smb_io_printmonitor_info_2(char *desc, NEW_BUFFER *buffer, PRINTMONITOR_2 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printmonitor_info_2");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_relstr("name", buffer, depth, &info->name))
+ return False;
+ if (!smb_io_relstr("environment", buffer, depth, &info->environment))
+ return False;
+ if (!smb_io_relstr("dll_name", buffer, depth, &info->dll_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_0(PRINTER_INFO_0 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->servername );
+
+ size+=size_of_uint32( &info->cjobs);
+ size+=size_of_uint32( &info->total_jobs);
+ size+=size_of_uint32( &info->total_bytes);
+
+ size+=size_of_uint16( &info->year);
+ size+=size_of_uint16( &info->month);
+ size+=size_of_uint16( &info->dayofweek);
+ size+=size_of_uint16( &info->day);
+ size+=size_of_uint16( &info->hour);
+ size+=size_of_uint16( &info->minute);
+ size+=size_of_uint16( &info->second);
+ size+=size_of_uint16( &info->milliseconds);
+
+ size+=size_of_uint32( &info->global_counter);
+ size+=size_of_uint32( &info->total_pages);
+
+ size+=size_of_uint16( &info->major_version);
+ size+=size_of_uint16( &info->build_version);
+
+ size+=size_of_uint32( &info->unknown7);
+ size+=size_of_uint32( &info->unknown8);
+ size+=size_of_uint32( &info->unknown9);
+ size+=size_of_uint32( &info->session_counter);
+ size+=size_of_uint32( &info->unknown11);
+ size+=size_of_uint32( &info->printer_errors);
+ size+=size_of_uint32( &info->unknown13);
+ size+=size_of_uint32( &info->unknown14);
+ size+=size_of_uint32( &info->unknown15);
+ size+=size_of_uint32( &info->unknown16);
+ size+=size_of_uint32( &info->change_id);
+ size+=size_of_uint32( &info->unknown18);
+ size+=size_of_uint32( &info->status);
+ size+=size_of_uint32( &info->unknown20);
+ size+=size_of_uint32( &info->c_setprinter);
+
+ size+=size_of_uint16( &info->unknown22);
+ size+=size_of_uint16( &info->unknown23);
+ size+=size_of_uint16( &info->unknown24);
+ size+=size_of_uint16( &info->unknown25);
+ size+=size_of_uint16( &info->unknown26);
+ size+=size_of_uint16( &info->unknown27);
+ size+=size_of_uint16( &info->unknown28);
+ size+=size_of_uint16( &info->unknown29);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_1(PRINTER_INFO_1 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->flags );
+ size+=size_of_relative_string( &info->description );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->comment );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_2(PRINTER_INFO_2 *info)
+{
+ uint32 size=0;
+
+ size += 4;
+ /* JRA !!!! TESTME - WHAT ABOUT prs_align.... !!! */
+ size += sec_desc_size( info->secdesc );
+
+ size+=size_of_device_mode( info->devmode );
+
+ size+=size_of_relative_string( &info->servername );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->sharename );
+ size+=size_of_relative_string( &info->portname );
+ size+=size_of_relative_string( &info->drivername );
+ size+=size_of_relative_string( &info->comment );
+ size+=size_of_relative_string( &info->location );
+
+ size+=size_of_relative_string( &info->sepfile );
+ size+=size_of_relative_string( &info->printprocessor );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->parameters );
+
+ size+=size_of_uint32( &info->attributes );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->defaultpriority );
+ size+=size_of_uint32( &info->starttime );
+ size+=size_of_uint32( &info->untiltime );
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->cjobs );
+ size+=size_of_uint32( &info->averageppm );
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_3(PRINTER_INFO_3 *info)
+{
+ /* The 4 is for the self relative pointer.. */
+ /* JRA !!!! TESTME - WHAT ABOUT prs_align.... !!! */
+ return 4 + (uint32)sec_desc_size( info->secdesc );
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_1(DRIVER_INFO_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_2(DRIVER_INFO_2 *info)
+{
+ int size=0;
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a string array.
+********************************************************************/
+
+uint32 spoolss_size_string_array(uint16 *string)
+{
+ uint32 i = 0;
+
+ if (string) {
+ for (i=0; (string[i]!=0x0000) || (string[i+1]!=0x0000); i++);
+ }
+ i=i+2; /* to count all chars including the leading zero */
+ i=2*i; /* because we need the value in bytes */
+ i=i+4; /* the offset pointer size */
+
+ return i;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_3(DRIVER_INFO_3 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+ size+=size_of_relative_string( &info->helpfile );
+ size+=size_of_relative_string( &info->monitorname );
+ size+=size_of_relative_string( &info->defaultdatatype );
+
+ size+=spoolss_size_string_array(info->dependentfiles);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_driver_info_6(DRIVER_INFO_6 *info)
+{
+ uint32 size=0;
+
+ size+=size_of_uint32( &info->version );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_relative_string( &info->architecture );
+ size+=size_of_relative_string( &info->driverpath );
+ size+=size_of_relative_string( &info->datafile );
+ size+=size_of_relative_string( &info->configfile );
+ size+=size_of_relative_string( &info->helpfile );
+
+ size+=spoolss_size_string_array(info->dependentfiles);
+
+ size+=size_of_relative_string( &info->monitorname );
+ size+=size_of_relative_string( &info->defaultdatatype );
+
+ size+=spoolss_size_string_array(info->previousdrivernames);
+
+ size+=size_of_nttime(&info->driver_date);
+ size+=size_of_uint32( &info->padding );
+ size+=size_of_uint32( &info->driver_version_low );
+ size+=size_of_uint32( &info->driver_version_high );
+ size+=size_of_relative_string( &info->mfgname );
+ size+=size_of_relative_string( &info->oem_url );
+ size+=size_of_relative_string( &info->hardware_id );
+ size+=size_of_relative_string( &info->provider );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_job_info_1(JOB_INFO_1 *info)
+{
+ int size=0;
+ size+=size_of_uint32( &info->jobid );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->machinename );
+ size+=size_of_relative_string( &info->username );
+ size+=size_of_relative_string( &info->document );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->text_status );
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->position );
+ size+=size_of_uint32( &info->totalpages );
+ size+=size_of_uint32( &info->pagesprinted );
+ size+=size_of_systemtime( &info->submitted );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_job_info_2(JOB_INFO_2 *info)
+{
+ int size=0;
+
+ size+=4; /* size of sec desc ptr */
+
+ size+=size_of_uint32( &info->jobid );
+ size+=size_of_relative_string( &info->printername );
+ size+=size_of_relative_string( &info->machinename );
+ size+=size_of_relative_string( &info->username );
+ size+=size_of_relative_string( &info->document );
+ size+=size_of_relative_string( &info->notifyname );
+ size+=size_of_relative_string( &info->datatype );
+ size+=size_of_relative_string( &info->printprocessor );
+ size+=size_of_relative_string( &info->parameters );
+ size+=size_of_relative_string( &info->drivername );
+ size+=size_of_device_mode( info->devmode );
+ size+=size_of_relative_string( &info->text_status );
+/* SEC_DESC sec_desc;*/
+ size+=size_of_uint32( &info->status );
+ size+=size_of_uint32( &info->priority );
+ size+=size_of_uint32( &info->position );
+ size+=size_of_uint32( &info->starttime );
+ size+=size_of_uint32( &info->untiltime );
+ size+=size_of_uint32( &info->totalpages );
+ size+=size_of_uint32( &info->size );
+ size+=size_of_systemtime( &info->submitted );
+ size+=size_of_uint32( &info->timeelapsed );
+ size+=size_of_uint32( &info->pagesprinted );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_form_1(FORM_1 *info)
+{
+ int size=0;
+
+ size+=size_of_uint32( &info->flag );
+ size+=size_of_relative_string( &info->name );
+ size+=size_of_uint32( &info->width );
+ size+=size_of_uint32( &info->length );
+ size+=size_of_uint32( &info->left );
+ size+=size_of_uint32( &info->top );
+ size+=size_of_uint32( &info->right );
+ size+=size_of_uint32( &info->bottom );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_port_info_1(PORT_INFO_1 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->port_name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_driverdir_info_1(DRIVER_DIRECTORY_1 *info)
+{
+ int size=0;
+
+ size=str_len_uni(&info->name); /* the string length */
+ size=size+1; /* add the leading zero */
+ size=size*2; /* convert in char */
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocessordirectory_info_1(PRINTPROCESSOR_DIRECTORY_1 *info)
+{
+ int size=0;
+
+ size=str_len_uni(&info->name); /* the string length */
+ size=size+1; /* add the leading zero */
+ size=size*2; /* convert in char */
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_port_info_2(PORT_INFO_2 *info)
+{
+ int size=0;
+
+ size+=size_of_relative_string( &info->port_name );
+ size+=size_of_relative_string( &info->monitor_name );
+ size+=size_of_relative_string( &info->description );
+
+ size+=size_of_uint32( &info->port_type );
+ size+=size_of_uint32( &info->reserved );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocessor_info_1(PRINTPROCESSOR_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printprocdatatype_info_1(PRINTPROCDATATYPE_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+uint32 spoolss_size_printer_enum_values(PRINTER_ENUM_VALUES *p)
+{
+ uint32 size = 0;
+
+ if (!p)
+ return 0;
+
+ /* uint32(offset) + uint32(length) + length) */
+ size += (size_of_uint32(&p->value_len)*2) + p->value_len;
+ size += (size_of_uint32(&p->data_len)*2) + p->data_len;
+
+ size += size_of_uint32(&p->type);
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printmonitor_info_1(PRINTMONITOR_1 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name );
+
+ return size;
+}
+
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printmonitor_info_2(PRINTMONITOR_2 *info)
+{
+ int size=0;
+ size+=size_of_relative_string( &info->name);
+ size+=size_of_relative_string( &info->environment);
+ size+=size_of_relative_string( &info->dll_name);
+
+ return size;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_getprinterdriver2(SPOOL_Q_GETPRINTERDRIVER2 *q_u,
+ const POLICY_HND *hnd,
+ const fstring architecture,
+ uint32 level, uint32 clientmajor, uint32 clientminor,
+ NEW_BUFFER *buffer, uint32 offered)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ init_buf_unistr2(&q_u->architecture, &q_u->architecture_ptr, architecture);
+
+ q_u->level=level;
+ q_u->clientmajorversion=clientmajor;
+ q_u->clientminorversion=clientminor;
+
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinterdriver2 (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_getprinterdriver2(char *desc, SPOOL_Q_GETPRINTERDRIVER2 *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdriver2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("architecture_ptr", ps, depth, &q_u->architecture_ptr))
+ return False;
+ if(!smb_io_unistr2("architecture", &q_u->architecture, q_u->architecture_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ if(!prs_uint32("clientmajorversion", ps, depth, &q_u->clientmajorversion))
+ return False;
+ if(!prs_uint32("clientminorversion", ps, depth, &q_u->clientminorversion))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinterdriver2 (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_getprinterdriver2(char *desc, SPOOL_R_GETPRINTERDRIVER2 *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdriver2");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_uint32("servermajorversion", ps, depth, &r_u->servermajorversion))
+ return False;
+ if (!prs_uint32("serverminorversion", ps, depth, &r_u->serverminorversion))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_enumprinters(
+ SPOOL_Q_ENUMPRINTERS *q_u,
+ uint32 flags,
+ fstring servername,
+ uint32 level,
+ NEW_BUFFER *buffer,
+ uint32 offered
+)
+{
+ q_u->flags=flags;
+
+ q_u->servername_ptr = (servername != NULL) ? 1 : 0;
+ init_buf_unistr2(&q_u->servername, &q_u->servername_ptr, servername);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_enumports(SPOOL_Q_ENUMPORTS *q_u,
+ fstring servername, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered)
+{
+ q_u->name_ptr = (servername != NULL) ? 1 : 0;
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, servername);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_enumprinters (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_enumprinters(char *desc, SPOOL_Q_ENUMPRINTERS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinters");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("flags", ps, depth, &q_u->flags))
+ return False;
+ if (!prs_uint32("servername_ptr", ps, depth, &q_u->servername_ptr))
+ return False;
+
+ if (!smb_io_unistr2("", &q_u->servername, q_u->servername_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPRINTERS structure.
+ ********************************************************************/
+
+BOOL spoolss_io_r_enumprinters(char *desc, SPOOL_R_ENUMPRINTERS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinters");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_enum_printers (srv_spoolss.c)
+ *
+ ********************************************************************/
+
+BOOL spoolss_io_r_getprinter(char *desc, SPOOL_R_GETPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_getprinter (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_getprinter(char *desc, SPOOL_Q_GETPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_getprinter(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_GETPRINTER *q_u,
+ const POLICY_HND *hnd,
+ uint32 level,
+ NEW_BUFFER *buffer,
+ uint32 offered
+)
+{
+ if (q_u == NULL)
+ {
+ return False;
+ }
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_setprinter(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_SETPRINTER *q_u,
+ const POLICY_HND *hnd,
+ uint32 level,
+ PRINTER_INFO_CTR *info,
+ uint32 command
+)
+{
+ SEC_DESC *secdesc;
+ DEVICEMODE *devmode;
+
+ if (q_u == NULL)
+ {
+ return False;
+ }
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->level = level;
+ q_u->info.level = level;
+ q_u->info.info_ptr = (info != NULL) ? 1 : 0;
+ switch (level)
+ {
+ case 2:
+ secdesc = info->printers_2->secdesc;
+ devmode = info->printers_2->devmode;
+
+ /* FIXMEE!! HACK ALERT!!! --jerry */
+ info->printers_2->devmode = NULL;
+ info->printers_2->secdesc = NULL;
+
+ make_spoolss_printer_info_2 (mem_ctx, &q_u->info.info_2, info->printers_2);
+#if 0 /* JERRY TEST */
+ q_u->secdesc_ctr = (SEC_DESC_BUF*)malloc(sizeof(SEC_DESC_BUF));
+ if (!q_u->secdesc_ctr)
+ return False;
+ q_u->secdesc_ctr->ptr = (secdesc != NULL) ? 1: 0;
+ q_u->secdesc_ctr->max_len = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0;
+ q_u->secdesc_ctr->len = (secdesc) ? sizeof(SEC_DESC) + (2*sizeof(uint32)) : 0;
+ q_u->secdesc_ctr->sec = secdesc;
+
+ q_u->devmode_ctr.devmode_ptr = (devmode != NULL) ? 1 : 0;
+ q_u->devmode_ctr.size = sizeof(DEVICEMODE) + (3*sizeof(uint32));
+ q_u->devmode_ctr.devmode = devmode;
+#else
+ q_u->secdesc_ctr = NULL;
+
+ q_u->devmode_ctr.devmode_ptr = 0;
+ q_u->devmode_ctr.size = 0;
+ q_u->devmode_ctr.devmode = NULL;
+#endif
+ break;
+ default:
+ DEBUG(0,("make_spoolss_q_setprinter: Unknown info level [%d]\n", level));
+ break;
+ }
+
+
+ q_u->command = command;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_setprinter(char *desc, SPOOL_R_SETPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Marshall/unmarshall a SPOOL_Q_SETPRINTER struct.
+********************************************************************/
+
+BOOL spoolss_io_q_setprinter(char *desc, SPOOL_Q_SETPRINTER *q_u, prs_struct *ps, int depth)
+{
+ uint32 ptr_sec_desc = 0;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle ,ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ if (!spoolss_io_devmode_cont(desc, &q_u->devmode_ctr, ps, depth))
+ return False;
+
+ switch (q_u->level)
+ {
+ case 2:
+ {
+ ptr_sec_desc = q_u->info.info_2->secdesc_ptr;
+ break;
+ }
+ case 3:
+ {
+ ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+ break;
+ }
+ }
+ if (ptr_sec_desc)
+ {
+ if (!sec_io_desc_buf(desc, &q_u->secdesc_ctr, ps, depth))
+ return False;
+ } else {
+ uint32 dummy;
+
+ /* Parse a NULL security descriptor. This should really
+ happen inside the sec_io_desc_buf() function. */
+
+ prs_debug(ps, depth, "", "sec_io_desc_buf");
+ if (!prs_uint32("size", ps, depth + 1, &dummy)) return False;
+ if (!prs_uint32("ptr", ps, depth + 1, &dummy)) return
+ False;
+ }
+
+ if(!prs_uint32("command", ps, depth, &q_u->command))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_fcpn(char *desc, SPOOL_R_FCPN *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_fcpn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_fcpn(char *desc, SPOOL_Q_FCPN *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_fcpn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_addjob(char *desc, SPOOL_R_ADDJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_addjob(char *desc, SPOOL_Q_ADDJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumjobs(char *desc, SPOOL_R_ENUMJOBS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumjobs");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL make_spoolss_q_enumjobs(SPOOL_Q_ENUMJOBS *q_u, const POLICY_HND *hnd,
+ uint32 firstjob,
+ uint32 numofjobs,
+ uint32 level,
+ NEW_BUFFER *buffer,
+ uint32 offered)
+{
+ if (q_u == NULL)
+ {
+ return False;
+ }
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->firstjob = firstjob;
+ q_u->numofjobs = numofjobs;
+ q_u->level = level;
+ q_u->buffer= buffer;
+ q_u->offered = offered;
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumjobs(char *desc, SPOOL_Q_ENUMJOBS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumjobs");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle, ps, depth))
+ return False;
+
+ if (!prs_uint32("firstjob", ps, depth, &q_u->firstjob))
+ return False;
+ if (!prs_uint32("numofjobs", ps, depth, &q_u->numofjobs))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_schedulejob(char *desc, SPOOL_R_SCHEDULEJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_schedulejob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_schedulejob(char *desc, SPOOL_Q_SCHEDULEJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_schedulejob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_setjob(char *desc, SPOOL_R_SETJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setjob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_setjob(char *desc, SPOOL_Q_SETJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setjob");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+ /*
+ * level is usually 0. If (level!=0) then I'm in trouble !
+ * I will try to generate setjob command with level!=0, one day.
+ */
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("command", ps, depth, &q_u->command))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPRINTERDRIVERS structure.
+********************************************************************/
+
+BOOL spoolss_io_r_enumprinterdrivers(char *desc, SPOOL_R_ENUMPRINTERDRIVERS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdrivers");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_enumprinterdrivers(SPOOL_Q_ENUMPRINTERDRIVERS *q_u,
+ const char *name,
+ const char *environment,
+ uint32 level,
+ NEW_BUFFER *buffer, uint32 offered)
+{
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, name);
+ init_buf_unistr2(&q_u->environment, &q_u->environment_ptr, environment);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_ENUMPRINTERDRIVERS structure.
+********************************************************************/
+
+BOOL spoolss_io_q_enumprinterdrivers(char *desc, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdrivers");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->name, q_u->name_ptr,ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("environment_ptr", ps, depth, &q_u->environment_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumforms(char *desc, SPOOL_Q_ENUMFORMS *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumforms");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumforms(char *desc, SPOOL_R_ENUMFORMS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumforms");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size of buffer needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("numofforms", ps, depth, &r_u->numofforms))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_getform(char *desc, SPOOL_Q_GETFORM *q_u, prs_struct *ps, int depth)
+{
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getform");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!smb_io_unistr2("", &q_u->formname,True,ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_getform(char *desc, SPOOL_R_GETFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getform");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("size of buffer needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_ENUMPORTS structure.
+********************************************************************/
+
+BOOL spoolss_io_r_enumports(char *desc, SPOOL_R_ENUMPORTS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumports");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumports(char *desc, SPOOL_Q_ENUMPORTS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->name,True,ps,depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_1 structure.
+********************************************************************/
+
+BOOL spool_io_printer_info_level_1(char *desc, SPOOL_PRINTER_INFO_LEVEL_1 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("flags", ps, depth, &il->flags))
+ return False;
+ if(!prs_uint32("description_ptr", ps, depth, &il->description_ptr))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &il->name_ptr))
+ return False;
+ if(!prs_uint32("comment_ptr", ps, depth, &il->comment_ptr))
+ return False;
+
+ if(!smb_io_unistr2("description", &il->description, il->description_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("comment", &il->comment, il->comment_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_3 structure.
+********************************************************************/
+
+BOOL spool_io_printer_info_level_3(char *desc, SPOOL_PRINTER_INFO_LEVEL_3 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("secdesc_ptr", ps, depth, &il->secdesc_ptr))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_PRINTER_INFO_LEVEL_2 structure.
+********************************************************************/
+
+BOOL spool_io_printer_info_level_2(char *desc, SPOOL_PRINTER_INFO_LEVEL_2 *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level_2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("servername_ptr", ps, depth, &il->servername_ptr))
+ return False;
+ if(!prs_uint32("printername_ptr", ps, depth, &il->printername_ptr))
+ return False;
+ if(!prs_uint32("sharename_ptr", ps, depth, &il->sharename_ptr))
+ return False;
+ if(!prs_uint32("portname_ptr", ps, depth, &il->portname_ptr))
+ return False;
+
+ if(!prs_uint32("drivername_ptr", ps, depth, &il->drivername_ptr))
+ return False;
+ if(!prs_uint32("comment_ptr", ps, depth, &il->comment_ptr))
+ return False;
+ if(!prs_uint32("location_ptr", ps, depth, &il->location_ptr))
+ return False;
+ if(!prs_uint32("devmode_ptr", ps, depth, &il->devmode_ptr))
+ return False;
+ if(!prs_uint32("sepfile_ptr", ps, depth, &il->sepfile_ptr))
+ return False;
+ if(!prs_uint32("printprocessor_ptr", ps, depth, &il->printprocessor_ptr))
+ return False;
+ if(!prs_uint32("datatype_ptr", ps, depth, &il->datatype_ptr))
+ return False;
+ if(!prs_uint32("parameters_ptr", ps, depth, &il->parameters_ptr))
+ return False;
+ if(!prs_uint32("secdesc_ptr", ps, depth, &il->secdesc_ptr))
+ return False;
+
+ if(!prs_uint32("attributes", ps, depth, &il->attributes))
+ return False;
+ if(!prs_uint32("priority", ps, depth, &il->priority))
+ return False;
+ if(!prs_uint32("default_priority", ps, depth, &il->default_priority))
+ return False;
+ if(!prs_uint32("starttime", ps, depth, &il->starttime))
+ return False;
+ if(!prs_uint32("untiltime", ps, depth, &il->untiltime))
+ return False;
+ if(!prs_werror("status", ps, depth, &il->status))
+ return False;
+ if(!prs_uint32("cjobs", ps, depth, &il->cjobs))
+ return False;
+ if(!prs_uint32("averageppm", ps, depth, &il->averageppm))
+ return False;
+
+ if(!smb_io_unistr2("servername", &il->servername, il->servername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("printername", &il->printername, il->printername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("sharename", &il->sharename, il->sharename_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("portname", &il->portname, il->portname_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("drivername", &il->drivername, il->drivername_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("comment", &il->comment, il->comment_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("location", &il->location, il->location_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("sepfile", &il->sepfile, il->sepfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("printprocessor", &il->printprocessor, il->printprocessor_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("datatype", &il->datatype, il->datatype_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("parameters", &il->parameters, il->parameters_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spool_io_printer_info_level(char *desc, SPOOL_PRINTER_INFO_LEVEL *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_info_level");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &il->level))
+ return False;
+ if(!prs_uint32("info_ptr", ps, depth, &il->info_ptr))
+ return False;
+
+ /* if no struct inside just return */
+ if (il->info_ptr==0) {
+ if (UNMARSHALLING(ps)) {
+ il->info_1=NULL;
+ il->info_2=NULL;
+ }
+ return True;
+ }
+
+ switch (il->level) {
+ /*
+ * level 0 is used by setprinter when managing the queue
+ * (hold, stop, start a queue)
+ */
+ case 0:
+ break;
+ /* DOCUMENT ME!!! What is level 1 used for? */
+ case 1:
+ {
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_1=(SPOOL_PRINTER_INFO_LEVEL_1 *)prs_alloc_mem(ps,sizeof(SPOOL_PRINTER_INFO_LEVEL_1))) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_1("", il->info_1, ps, depth))
+ return False;
+ break;
+ }
+ /*
+ * level 2 is used by addprinter
+ * and by setprinter when updating printer's info
+ */
+ case 2:
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_2=(SPOOL_PRINTER_INFO_LEVEL_2 *)prs_alloc_mem(ps,sizeof(SPOOL_PRINTER_INFO_LEVEL_2))) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_2("", il->info_2, ps, depth))
+ return False;
+ break;
+ /* DOCUMENT ME!!! What is level 3 used for? */
+ case 3:
+ {
+ if (UNMARSHALLING(ps)) {
+ if ((il->info_3=(SPOOL_PRINTER_INFO_LEVEL_3 *)prs_alloc_mem(ps,sizeof(SPOOL_PRINTER_INFO_LEVEL_3))) == NULL)
+ return False;
+ }
+ if (!spool_io_printer_info_level_3("", il->info_3, ps, depth))
+ return False;
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_addprinterex(char *desc, SPOOL_Q_ADDPRINTEREX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprinterex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("", ps, depth, &q_u->server_name_ptr))
+ return False;
+ if(!smb_io_unistr2("", &q_u->server_name, q_u->server_name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ /* the 4 unknown are all 0 */
+
+ /*
+ * en fait ils sont pas inconnu
+ * par recoupement avec rpcSetPrinter
+ * c'est le devicemode
+ * et le security descriptor.
+ */
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("unk0", ps, depth, &q_u->unk0))
+ return False;
+ if(!prs_uint32("unk1", ps, depth, &q_u->unk1))
+ return False;
+ if(!prs_uint32("unk2", ps, depth, &q_u->unk2))
+ return False;
+ if(!prs_uint32("unk3", ps, depth, &q_u->unk3))
+ return False;
+
+ if(!prs_uint32("user_switch", ps, depth, &q_u->user_switch))
+ return False;
+ if(!spool_io_user_level("", &q_u->user_ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_addprinterex(char *desc, SPOOL_R_ADDPRINTEREX *r_u,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprinterex");
+ depth++;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spool_io_printer_driver_info_level_3(char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **q_u,
+ prs_struct *ps, int depth)
+{
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *il;
+
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level_3");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ il=(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *)prs_alloc_mem(ps,sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3));
+ if(il == NULL)
+ return False;
+ *q_u=il;
+ }
+ else {
+ il=*q_u;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("cversion", ps, depth, &il->cversion))
+ return False;
+ if(!prs_uint32("name", ps, depth, &il->name_ptr))
+ return False;
+ if(!prs_uint32("environment", ps, depth, &il->environment_ptr))
+ return False;
+ if(!prs_uint32("driverpath", ps, depth, &il->driverpath_ptr))
+ return False;
+ if(!prs_uint32("datafile", ps, depth, &il->datafile_ptr))
+ return False;
+ if(!prs_uint32("configfile", ps, depth, &il->configfile_ptr))
+ return False;
+ if(!prs_uint32("helpfile", ps, depth, &il->helpfile_ptr))
+ return False;
+ if(!prs_uint32("monitorname", ps, depth, &il->monitorname_ptr))
+ return False;
+ if(!prs_uint32("defaultdatatype", ps, depth, &il->defaultdatatype_ptr))
+ return False;
+ if(!prs_uint32("dependentfilessize", ps, depth, &il->dependentfilessize))
+ return False;
+ if(!prs_uint32("dependentfiles", ps, depth, &il->dependentfiles_ptr))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("environment", &il->environment, il->environment_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("driverpath", &il->driverpath, il->driverpath_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("datafile", &il->datafile, il->datafile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("configfile", &il->configfile, il->configfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("helpfile", &il->helpfile, il->helpfile_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("monitorname", &il->monitorname, il->monitorname_ptr, ps, depth))
+ return False;
+ if(!smb_io_unistr2("defaultdatatype", &il->defaultdatatype, il->defaultdatatype_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (il->dependentfiles_ptr)
+ smb_io_buffer5("", &il->dependentfiles, ps, depth);
+
+ return True;
+}
+
+/*******************************************************************
+parse a SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 structure
+********************************************************************/
+
+BOOL spool_io_printer_driver_info_level_6(char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 **q_u,
+ prs_struct *ps, int depth)
+{
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *il;
+
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level_6");
+ depth++;
+
+ /* reading */
+ if (UNMARSHALLING(ps)) {
+ il=(SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *)prs_alloc_mem(ps,sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL_6));
+ if(il == NULL)
+ return False;
+ *q_u=il;
+ }
+ else {
+ il=*q_u;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+
+ /* parse the main elements the packet */
+
+ if(!prs_uint32("version", ps, depth, &il->version))
+ return False;
+
+ if(!prs_uint32("name_ptr", ps, depth, &il->name_ptr))
+ return False;
+ /*
+ * If name_ptr is NULL then the next 4 bytes are the name_ptr. A driver
+ * with a NULL name just isn't a driver For example: "HP LaserJet 4si"
+ * from W2K CDROM (which uses unidriver). JohnR 010205
+ */
+ if (!il->name_ptr) {
+ DEBUG(5,("spool_io_printer_driver_info_level_6: name_ptr is NULL! Get next value\n"));
+ if(!prs_uint32("name_ptr", ps, depth, &il->name_ptr))
+ return False;
+ }
+
+ if(!prs_uint32("environment_ptr", ps, depth, &il->environment_ptr))
+ return False;
+ if(!prs_uint32("driverpath_ptr", ps, depth, &il->driverpath_ptr))
+ return False;
+ if(!prs_uint32("datafile_ptr", ps, depth, &il->datafile_ptr))
+ return False;
+ if(!prs_uint32("configfile_ptr", ps, depth, &il->configfile_ptr))
+ return False;
+ if(!prs_uint32("helpfile_ptr", ps, depth, &il->helpfile_ptr))
+ return False;
+ if(!prs_uint32("monitorname_ptr", ps, depth, &il->monitorname_ptr))
+ return False;
+ if(!prs_uint32("defaultdatatype_ptr", ps, depth, &il->defaultdatatype_ptr))
+ return False;
+ if(!prs_uint32("dependentfiles_len", ps, depth, &il->dependentfiles_len))
+ return False;
+ if(!prs_uint32("dependentfiles_ptr", ps, depth, &il->dependentfiles_ptr))
+ return False;
+ if(!prs_uint32("previousnames_len", ps, depth, &il->previousnames_len))
+ return False;
+ if(!prs_uint32("previousnames_ptr", ps, depth, &il->previousnames_ptr))
+ return False;
+ if(!smb_io_time("driverdate", &il->driverdate, ps, depth))
+ return False;
+ if(!prs_uint32("dummy4", ps, depth, &il->dummy4))
+ return False;
+ if(!prs_uint64("driverversion", ps, depth, &il->driverversion))
+ return False;
+ if(!prs_uint32("mfgname_ptr", ps, depth, &il->mfgname_ptr))
+ return False;
+ if(!prs_uint32("oemurl_ptr", ps, depth, &il->oemurl_ptr))
+ return False;
+ if(!prs_uint32("hardwareid_ptr", ps, depth, &il->hardwareid_ptr))
+ return False;
+ if(!prs_uint32("provider_ptr", ps, depth, &il->provider_ptr))
+ return False;
+
+ /* parse the structures in the packet */
+
+ if(!smb_io_unistr2("name", &il->name, il->name_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("environment", &il->environment, il->environment_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("driverpath", &il->driverpath, il->driverpath_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("datafile", &il->datafile, il->datafile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("configfile", &il->configfile, il->configfile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("helpfile", &il->helpfile, il->helpfile_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("monitorname", &il->monitorname, il->monitorname_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("defaultdatatype", &il->defaultdatatype, il->defaultdatatype_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if (il->dependentfiles_ptr) {
+ if(!smb_io_buffer5("dependentfiles", &il->dependentfiles, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ if (il->previousnames_ptr) {
+ if(!smb_io_buffer5("previousnames", &il->previousnames, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ }
+ if(!smb_io_unistr2("mfgname", &il->mfgname, il->mfgname_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("oemurl", &il->oemurl, il->oemurl_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("hardwareid", &il->hardwareid, il->hardwareid_ptr, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("provider", &il->provider, il->provider_ptr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ convert a buffer of UNICODE strings null terminated
+ the buffer is terminated by a NULL
+
+ convert to an dos codepage array (null terminated)
+
+ dynamically allocate memory
+
+********************************************************************/
+static BOOL uniarray_2_dosarray(BUFFER5 *buf5, fstring **ar)
+{
+ fstring f, *tar;
+ int n = 0;
+ char *src;
+
+ if (buf5==NULL)
+ return False;
+
+ src = (char *)buf5->buffer;
+ *ar = NULL;
+
+ while (src < ((char *)buf5->buffer) + buf5->buf_len*2) {
+ rpcstr_pull(f, src, sizeof(f)-1, -1, 0);
+ src = skip_unibuf(src, 2*buf5->buf_len - PTR_DIFF(src,buf5->buffer));
+ tar = (fstring *)Realloc(*ar, sizeof(fstring)*(n+2));
+ if (!tar)
+ return False;
+ else
+ *ar = tar;
+ fstrcpy((*ar)[n], f);
+ n++;
+ }
+ fstrcpy((*ar)[n], "");
+
+ return True;
+}
+
+
+
+
+/*******************************************************************
+ read a UNICODE array with null terminated strings
+ and null terminated array
+ and size of array at beginning
+********************************************************************/
+
+BOOL smb_io_unibuffer(char *desc, UNISTR2 *buffer, prs_struct *ps, int depth)
+{
+ if (buffer==NULL) return False;
+
+ buffer->undoc=0;
+ buffer->uni_str_len=buffer->uni_max_len;
+
+ if(!prs_uint32("buffer_size", ps, depth, &buffer->uni_max_len))
+ return False;
+
+ if(!prs_unistr2(True, "buffer ", ps, depth, buffer))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spool_io_printer_driver_info_level(char *desc, SPOOL_PRINTER_DRIVER_INFO_LEVEL *il, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spool_io_printer_driver_info_level");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("level", ps, depth, &il->level))
+ return False;
+ if(!prs_uint32("ptr", ps, depth, &il->ptr))
+ return False;
+
+ if (il->ptr==0)
+ return True;
+
+ switch (il->level) {
+ case 3:
+ if(!spool_io_printer_driver_info_level_3("", &il->info_3, ps, depth))
+ return False;
+ break;
+ case 6:
+ if(!spool_io_printer_driver_info_level_6("", &il->info_6, ps, depth))
+ return False;
+ break;
+ default:
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ init a SPOOL_Q_ADDPRINTERDRIVER struct
+ ******************************************************************/
+
+BOOL make_spoolss_q_addprinterdriver(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_Q_ADDPRINTERDRIVER *q_u,
+ const char* srv_name,
+ uint32 level,
+ PRINTER_DRIVER_CTR *info)
+{
+ DEBUG(5,("make_spoolss_q_addprinterdriver\n"));
+
+ q_u->server_name_ptr = (srv_name!=NULL)?1:0;
+ init_unistr2(&q_u->server_name, srv_name, strlen(srv_name)+1);
+
+ q_u->level = level;
+
+ q_u->info.level = level;
+ q_u->info.ptr = (info!=NULL)?1:0;
+ switch (level)
+ {
+ /* info level 3 is supported by Windows 95/98, WinNT and Win2k */
+ case 3 :
+ make_spoolss_driver_info_3(mem_ctx, &q_u->info.info_3, info->info3);
+ break;
+
+ /* info level 6 is supported by WinME and Win2k */
+ case 6:
+ /* WRITEME!! will add later --jerry */
+ break;
+
+ default:
+ DEBUG(0,("make_spoolss_q_addprinterdriver: Unknown info level [%d]\n", level));
+ break;
+ }
+
+ return True;
+}
+
+BOOL make_spoolss_driver_info_3(
+ TALLOC_CTX *mem_ctx,
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 **spool_drv_info,
+ DRIVER_INFO_3 *info3
+)
+{
+ uint32 len = 0;
+ uint16 *ptr = info3->dependentfiles;
+ BOOL done = False;
+ BOOL null_char = False;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *inf;
+
+ if (!(inf=(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3*)talloc_zero(mem_ctx, sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3))))
+ return False;
+
+ inf->cversion = info3->version;
+ inf->name_ptr = (info3->name.buffer!=NULL)?1:0;
+ inf->environment_ptr = (info3->architecture.buffer!=NULL)?1:0;
+ inf->driverpath_ptr = (info3->driverpath.buffer!=NULL)?1:0;
+ inf->datafile_ptr = (info3->datafile.buffer!=NULL)?1:0;
+ inf->configfile_ptr = (info3->configfile.buffer!=NULL)?1:0;
+ inf->helpfile_ptr = (info3->helpfile.buffer!=NULL)?1:0;
+ inf->monitorname_ptr = (info3->monitorname.buffer!=NULL)?1:0;
+ inf->defaultdatatype_ptr = (info3->defaultdatatype.buffer!=NULL)?1:0;
+
+ init_unistr2_from_unistr(&inf->name, &info3->name);
+ init_unistr2_from_unistr(&inf->environment, &info3->architecture);
+ init_unistr2_from_unistr(&inf->driverpath, &info3->driverpath);
+ init_unistr2_from_unistr(&inf->datafile, &info3->datafile);
+ init_unistr2_from_unistr(&inf->configfile, &info3->configfile);
+ init_unistr2_from_unistr(&inf->helpfile, &info3->helpfile);
+ init_unistr2_from_unistr(&inf->monitorname, &info3->monitorname);
+ init_unistr2_from_unistr(&inf->defaultdatatype, &info3->defaultdatatype);
+
+ while (!done)
+ {
+ switch (*ptr)
+ {
+ case 0:
+ /* the null_char BOOL is used to help locate
+ two '\0's back to back */
+ if (null_char)
+ done = True;
+ else
+ null_char = True;
+ break;
+
+ default:
+ null_char = False;
+ ;;
+ break;
+ }
+ len++;
+ ptr++;
+ }
+ inf->dependentfiles_ptr = (info3->dependentfiles != NULL) ? 1 : 0;
+ inf->dependentfilessize = len;
+ if(!make_spoolss_buffer5(mem_ctx, &inf->dependentfiles, len, info3->dependentfiles))
+ {
+ SAFE_FREE(inf);
+ return False;
+ }
+
+ *spool_drv_info = inf;
+
+ return True;
+}
+
+/*******************************************************************
+ make a BUFFER5 struct from a uint16*
+ ******************************************************************/
+BOOL make_spoolss_buffer5(TALLOC_CTX *mem_ctx, BUFFER5 *buf5, uint32 len, uint16 *src)
+{
+
+ buf5->buf_len = len;
+ if((buf5->buffer=(uint16*)talloc_memdup(mem_ctx, src, sizeof(uint16)*len)) == NULL)
+ {
+ DEBUG(0,("make_spoolss_buffer5: Unable to malloc memory for buffer!\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ fill in the prs_struct for a ADDPRINTERDRIVER request PDU
+ ********************************************************************/
+
+BOOL spoolss_io_q_addprinterdriver(char *desc, SPOOL_Q_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprinterdriver");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("server_name_ptr", ps, depth, &q_u->server_name_ptr))
+ return False;
+ if(!smb_io_unistr2("server_name", &q_u->server_name, q_u->server_name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("info_level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spool_io_printer_driver_info_level("", &q_u->info, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_addprinterdriver(char *desc, SPOOL_R_ADDPRINTERDRIVER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprinterdriver");
+ depth++;
+
+ if(!prs_werror("status", ps, depth, &q_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL uni_2_asc_printer_driver_3(SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 **asc)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 *d;
+
+ DEBUG(7,("uni_2_asc_printer_driver_3: Converting from UNICODE to ASCII\n"));
+
+ if (*asc==NULL)
+ {
+ *asc=(NT_PRINTER_DRIVER_INFO_LEVEL_3 *)malloc(sizeof(NT_PRINTER_DRIVER_INFO_LEVEL_3));
+ if(*asc == NULL)
+ return False;
+ ZERO_STRUCTP(*asc);
+ }
+
+ d=*asc;
+
+ d->cversion=uni->cversion;
+
+ unistr2_to_ascii(d->name, &uni->name, sizeof(d->name)-1);
+ unistr2_to_ascii(d->environment, &uni->environment, sizeof(d->environment)-1);
+ unistr2_to_ascii(d->driverpath, &uni->driverpath, sizeof(d->driverpath)-1);
+ unistr2_to_ascii(d->datafile, &uni->datafile, sizeof(d->datafile)-1);
+ unistr2_to_ascii(d->configfile, &uni->configfile, sizeof(d->configfile)-1);
+ unistr2_to_ascii(d->helpfile, &uni->helpfile, sizeof(d->helpfile)-1);
+ unistr2_to_ascii(d->monitorname, &uni->monitorname, sizeof(d->monitorname)-1);
+ unistr2_to_ascii(d->defaultdatatype, &uni->defaultdatatype, sizeof(d->defaultdatatype)-1);
+
+ DEBUGADD(8,( "version: %d\n", d->cversion));
+ DEBUGADD(8,( "name: %s\n", d->name));
+ DEBUGADD(8,( "environment: %s\n", d->environment));
+ DEBUGADD(8,( "driverpath: %s\n", d->driverpath));
+ DEBUGADD(8,( "datafile: %s\n", d->datafile));
+ DEBUGADD(8,( "configfile: %s\n", d->configfile));
+ DEBUGADD(8,( "helpfile: %s\n", d->helpfile));
+ DEBUGADD(8,( "monitorname: %s\n", d->monitorname));
+ DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+ if (uniarray_2_dosarray(&uni->dependentfiles, &d->dependentfiles ))
+ return True;
+
+ SAFE_FREE(*asc);
+ return False;
+}
+
+/*******************************************************************
+********************************************************************/
+BOOL uni_2_asc_printer_driver_6(SPOOL_PRINTER_DRIVER_INFO_LEVEL_6 *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 **asc)
+{
+ NT_PRINTER_DRIVER_INFO_LEVEL_6 *d;
+
+ DEBUG(7,("uni_2_asc_printer_driver_6: Converting from UNICODE to ASCII\n"));
+
+ if (*asc==NULL)
+ {
+ *asc=(NT_PRINTER_DRIVER_INFO_LEVEL_6 *)malloc(sizeof(NT_PRINTER_DRIVER_INFO_LEVEL_6));
+ if(*asc == NULL)
+ return False;
+ ZERO_STRUCTP(*asc);
+ }
+
+ d=*asc;
+
+ d->version=uni->version;
+
+ unistr2_to_ascii(d->name, &uni->name, sizeof(d->name)-1);
+ unistr2_to_ascii(d->environment, &uni->environment, sizeof(d->environment)-1);
+ unistr2_to_ascii(d->driverpath, &uni->driverpath, sizeof(d->driverpath)-1);
+ unistr2_to_ascii(d->datafile, &uni->datafile, sizeof(d->datafile)-1);
+ unistr2_to_ascii(d->configfile, &uni->configfile, sizeof(d->configfile)-1);
+ unistr2_to_ascii(d->helpfile, &uni->helpfile, sizeof(d->helpfile)-1);
+ unistr2_to_ascii(d->monitorname, &uni->monitorname, sizeof(d->monitorname)-1);
+ unistr2_to_ascii(d->defaultdatatype, &uni->defaultdatatype, sizeof(d->defaultdatatype)-1);
+
+ DEBUGADD(8,( "version: %d\n", d->version));
+ DEBUGADD(8,( "name: %s\n", d->name));
+ DEBUGADD(8,( "environment: %s\n", d->environment));
+ DEBUGADD(8,( "driverpath: %s\n", d->driverpath));
+ DEBUGADD(8,( "datafile: %s\n", d->datafile));
+ DEBUGADD(8,( "configfile: %s\n", d->configfile));
+ DEBUGADD(8,( "helpfile: %s\n", d->helpfile));
+ DEBUGADD(8,( "monitorname: %s\n", d->monitorname));
+ DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+ if (!uniarray_2_dosarray(&uni->dependentfiles, &d->dependentfiles ))
+ goto error;
+ if (!uniarray_2_dosarray(&uni->previousnames, &d->previousnames ))
+ goto error;
+
+ return True;
+
+error:
+ SAFE_FREE(*asc);
+ return False;
+}
+
+BOOL uni_2_asc_printer_info_2(const SPOOL_PRINTER_INFO_LEVEL_2 *uni,
+ NT_PRINTER_INFO_LEVEL_2 **asc)
+{
+ NT_PRINTER_INFO_LEVEL_2 *d;
+ time_t time_unix;
+
+ DEBUG(7,("Converting from UNICODE to ASCII\n"));
+ time_unix=time(NULL);
+
+ if (*asc==NULL) {
+ DEBUGADD(8,("allocating memory\n"));
+
+ *asc=(NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2));
+ if(*asc == NULL)
+ return False;
+ ZERO_STRUCTP(*asc);
+
+ /* we allocate memory iff called from
+ * addprinter(ex) so we can do one time stuff here.
+ */
+ (*asc)->setuptime=time_unix;
+
+ }
+ DEBUGADD(8,("start converting\n"));
+
+ d=*asc;
+
+ d->attributes=uni->attributes;
+ d->priority=uni->priority;
+ d->default_priority=uni->default_priority;
+ d->starttime=uni->starttime;
+ d->untiltime=uni->untiltime;
+ d->status=uni->status;
+ d->cjobs=uni->cjobs;
+
+ unistr2_to_ascii(d->servername, &uni->servername, sizeof(d->servername)-1);
+ unistr2_to_ascii(d->printername, &uni->printername, sizeof(d->printername)-1);
+ unistr2_to_ascii(d->sharename, &uni->sharename, sizeof(d->sharename)-1);
+ unistr2_to_ascii(d->portname, &uni->portname, sizeof(d->portname)-1);
+ unistr2_to_ascii(d->drivername, &uni->drivername, sizeof(d->drivername)-1);
+ unistr2_to_ascii(d->comment, &uni->comment, sizeof(d->comment)-1);
+ unistr2_to_ascii(d->location, &uni->location, sizeof(d->location)-1);
+ unistr2_to_ascii(d->sepfile, &uni->sepfile, sizeof(d->sepfile)-1);
+ unistr2_to_ascii(d->printprocessor, &uni->printprocessor, sizeof(d->printprocessor)-1);
+ unistr2_to_ascii(d->datatype, &uni->datatype, sizeof(d->datatype)-1);
+ unistr2_to_ascii(d->parameters, &uni->parameters, sizeof(d->parameters)-1);
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_getprinterdriverdir(SPOOL_Q_GETPRINTERDRIVERDIR *q_u,
+ fstring servername, fstring env_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered)
+{
+ init_buf_unistr2(&q_u->name, &q_u->name_ptr, servername);
+ init_buf_unistr2(&q_u->environment, &q_u->environment_ptr, env_name);
+
+ q_u->level=level;
+ q_u->buffer=buffer;
+ q_u->offered=offered;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_GETPRINTERDRIVERDIR structure.
+********************************************************************/
+
+BOOL spoolss_io_q_getprinterdriverdir(char *desc, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdriverdir");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if(!smb_io_unistr2("", &q_u->name, q_u->name_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("", ps, depth, &q_u->environment_ptr))
+ return False;
+ if(!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_GETPRINTERDRIVERDIR structure.
+********************************************************************/
+
+BOOL spoolss_io_r_getprinterdriverdir(char *desc, SPOOL_R_GETPRINTERDRIVERDIR *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdriverdir");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumprintprocessors(char *desc, SPOOL_R_ENUMPRINTPROCESSORS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintprocessors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumprintprocessors(char *desc, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintprocessors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("", ps, depth, &q_u->environment_ptr))
+ return False;
+ if (!smb_io_unistr2("", &q_u->environment, q_u->environment_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_addprintprocessor(char *desc, SPOOL_Q_ADDPRINTPROCESSOR *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_addprintprocessor");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("server_ptr", ps, depth, &q_u->server_ptr))
+ return False;
+ if (!smb_io_unistr2("server", &q_u->server, q_u->server_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("environment", &q_u->environment, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("path", &q_u->path, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_addprintprocessor(char *desc, SPOOL_R_ADDPRINTPROCESSOR *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addprintproicessor");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumprintprocdatatypes(char *desc, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintprocdatatypes");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumprintprocdatatypes(char *desc, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintprocdatatypes");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("processor_ptr", ps, depth, &q_u->processor_ptr))
+ return False;
+ if (!smb_io_unistr2("processor", &q_u->processor, q_u->processor_ptr, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("buffer", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_ENUMPRINTMONITORS structure.
+********************************************************************/
+
+BOOL spoolss_io_q_enumprintmonitors(char *desc, SPOOL_Q_ENUMPRINTMONITORS *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprintmonitors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("name_ptr", ps, depth, &q_u->name_ptr))
+ return False;
+ if (!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumprintmonitors(char *desc, SPOOL_R_ENUMPRINTMONITORS *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprintmonitors");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_enumprinterdata(char *desc, SPOOL_R_ENUMPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_uint32("valuesize", ps, depth, &r_u->valuesize))
+ return False;
+
+ if(!prs_uint16uni(False, "value", ps, depth, r_u->value, r_u->valuesize ))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("realvaluesize", ps, depth, &r_u->realvaluesize))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+
+ if(!prs_uint32("datasize", ps, depth, &r_u->datasize))
+ return False;
+ if(!prs_uint8s(False, "data", ps, depth, r_u->data, r_u->datasize))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("realdatasize", ps, depth, &r_u->realdatasize))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_enumprinterdata(char *desc, SPOOL_Q_ENUMPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("index", ps, depth, &q_u->index))
+ return False;
+ if(!prs_uint32("valuesize", ps, depth, &q_u->valuesize))
+ return False;
+ if(!prs_uint32("datasize", ps, depth, &q_u->datasize))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL make_spoolss_q_enumprinterdata(SPOOL_Q_ENUMPRINTERDATA *q_u,
+ const POLICY_HND *hnd,
+ uint32 idx, uint32 valuelen, uint32 datalen)
+{
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+ q_u->index=idx;
+ q_u->valuesize=valuelen;
+ q_u->datasize=datalen;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_setprinterdata(char *desc, SPOOL_Q_SETPRINTERDATA *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->value, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("max_len", ps, depth, &q_u->max_len))
+ return False;
+
+ switch (q_u->type)
+ {
+ case REG_SZ:
+ case REG_BINARY:
+ case REG_DWORD:
+ case REG_MULTI_SZ:
+ if (q_u->max_len) {
+ if (UNMARSHALLING(ps))
+ q_u->data=(uint8 *)prs_alloc_mem(ps, q_u->max_len * sizeof(uint8));
+ if(q_u->data == NULL)
+ return False;
+ if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ break;
+ }
+
+ if(!prs_uint32("real_len", ps, depth, &q_u->real_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_setprinterdata(char *desc, SPOOL_R_SETPRINTERDATA *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinterdata");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL convert_specific_param(NT_PRINTER_PARAM **param, const UNISTR2 *value,
+ uint32 type, const uint8 *data, uint32 len)
+{
+ DEBUG(5,("converting a specific param struct\n"));
+
+ if (*param == NULL)
+ {
+ *param=(NT_PRINTER_PARAM *)malloc(sizeof(NT_PRINTER_PARAM));
+ if(*param == NULL)
+ return False;
+ memset((char *)*param, '\0', sizeof(NT_PRINTER_PARAM));
+ DEBUGADD(6,("Allocated a new PARAM struct\n"));
+ }
+ unistr2_to_ascii((*param)->value, value, sizeof((*param)->value)-1);
+ (*param)->type = type;
+
+ /* le champ data n'est pas NULL termine */
+ /* on stocke donc la longueur */
+
+ (*param)->data_len=len;
+
+ if (len) {
+ (*param)->data=(uint8 *)malloc(len * sizeof(uint8));
+ if((*param)->data == NULL)
+ return False;
+ memcpy((*param)->data, data, len);
+ }
+
+ DEBUGADD(6,("\tvalue:[%s], len:[%d]\n",(*param)->value, (*param)->data_len));
+ dump_data(10, (char *)(*param)->data, (*param)->data_len);
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static BOOL spoolss_io_addform(char *desc, FORM *f, uint32 ptr, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_addform");
+ depth++;
+ if(!prs_align(ps))
+ return False;
+
+ if (ptr!=0)
+ {
+ if(!prs_uint32("flags", ps, depth, &f->flags))
+ return False;
+ if(!prs_uint32("name_ptr", ps, depth, &f->name_ptr))
+ return False;
+ if(!prs_uint32("size_x", ps, depth, &f->size_x))
+ return False;
+ if(!prs_uint32("size_y", ps, depth, &f->size_y))
+ return False;
+ if(!prs_uint32("left", ps, depth, &f->left))
+ return False;
+ if(!prs_uint32("top", ps, depth, &f->top))
+ return False;
+ if(!prs_uint32("right", ps, depth, &f->right))
+ return False;
+ if(!prs_uint32("bottom", ps, depth, &f->bottom))
+ return False;
+
+ if(!smb_io_unistr2("", &f->name, f->name_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_deleteform(char *desc, SPOOL_Q_DELETEFORM *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_deleteform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("form name", &q_u->name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_deleteform(char *desc, SPOOL_R_DELETEFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_deleteform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_addform(char *desc, SPOOL_Q_ADDFORM *q_u, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0;
+ prs_debug(ps, depth, desc, "spoolss_io_q_addform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &q_u->level2))
+ return False;
+
+ if (q_u->level==1)
+ {
+ if(!prs_uint32("useless_ptr", ps, depth, &useless_ptr))
+ return False;
+ if(!spoolss_io_addform("", &q_u->form, useless_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_addform(char *desc, SPOOL_R_ADDFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_addform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_q_setform(char *desc, SPOOL_Q_SETFORM *q_u, prs_struct *ps, int depth)
+{
+ uint32 useless_ptr=0;
+ prs_debug(ps, depth, desc, "spoolss_io_q_setform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+ if(!prs_uint32("level2", ps, depth, &q_u->level2))
+ return False;
+
+ if (q_u->level==1)
+ {
+ if(!prs_uint32("useless_ptr", ps, depth, &useless_ptr))
+ return False;
+ if(!spoolss_io_addform("", &q_u->form, useless_ptr, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL spoolss_io_r_setform(char *desc, SPOOL_R_SETFORM *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setform");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_GETJOB structure.
+********************************************************************/
+
+BOOL spoolss_io_r_getjob(char *desc, SPOOL_R_GETJOB *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getjob");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_GETJOB structure.
+********************************************************************/
+
+BOOL spoolss_io_q_getjob(char *desc, SPOOL_Q_GETJOB *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if(!prs_uint32("jobid", ps, depth, &q_u->jobid))
+ return False;
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+void free_devmode(DEVICEMODE *devmode)
+{
+ if (devmode!=NULL) {
+ SAFE_FREE(devmode->private);
+ SAFE_FREE(devmode);
+ }
+}
+
+void free_printer_info_1(PRINTER_INFO_1 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_printer_info_2(PRINTER_INFO_2 *printer)
+{
+ if (printer!=NULL) {
+ free_devmode(printer->devmode);
+ printer->devmode = NULL;
+ SAFE_FREE(printer);
+ }
+}
+
+void free_printer_info_3(PRINTER_INFO_3 *printer)
+{
+ SAFE_FREE(printer);
+}
+
+void free_job_info_2(JOB_INFO_2 *job)
+{
+ if (job!=NULL)
+ free_devmode(job->devmode);
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_replyopenprinter(SPOOL_Q_REPLYOPENPRINTER *q_u,
+ const fstring string, uint32 printer, uint32 type)
+{
+ if (q_u == NULL)
+ return False;
+
+ init_unistr2(&q_u->string, string, strlen(string)+1);
+
+ q_u->printer=printer;
+ q_u->type=type;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLYOPENPRINTER structure.
+********************************************************************/
+
+BOOL spoolss_io_q_replyopenprinter(char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_replyopenprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->string, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("printer", ps, depth, &q_u->printer))
+ return False;
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+ if(!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLYOPENPRINTER structure.
+********************************************************************/
+
+BOOL spoolss_io_r_replyopenprinter(char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replyopenprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_reply_closeprinter(SPOOL_Q_REPLYCLOSEPRINTER *q_u, POLICY_HND *hnd)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLYCLOSEPRINTER structure.
+********************************************************************/
+
+BOOL spoolss_io_q_replycloseprinter(char *desc, SPOOL_Q_REPLYCLOSEPRINTER *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_replycloseprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLYCLOSEPRINTER structure.
+********************************************************************/
+
+BOOL spoolss_io_r_replycloseprinter(char *desc, SPOOL_R_REPLYCLOSEPRINTER *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replycloseprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&r_u->handle,ps,depth))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+
+BOOL make_spoolss_q_reply_rrpcn(SPOOL_Q_REPLY_RRPCN *q_u, POLICY_HND *hnd,
+ uint32 change_low, uint32 change_high)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->change_low=change_low;
+ q_u->change_high=change_high;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ q_u->info_ptr=1;
+
+ q_u->info.version=2;
+ q_u->info.flags=PRINTER_NOTIFY_INFO_DISCARDED;
+ q_u->info.count=0;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLY_RRPCN structure.
+********************************************************************/
+
+BOOL spoolss_io_q_reply_rrpcn(char *desc, SPOOL_Q_REPLY_RRPCN *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_reply_rrpcn");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if (!prs_uint32("change_low", ps, depth, &q_u->change_low))
+ return False;
+
+ if (!prs_uint32("change_high", ps, depth, &q_u->change_high))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+
+ if (!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ if (!prs_uint32("info_ptr", ps, depth, &q_u->info_ptr))
+ return False;
+
+ if(q_u->info_ptr!=0)
+ if(!smb_io_notify_info(desc, &q_u->info, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLY_RRPCN structure.
+********************************************************************/
+
+BOOL spoolss_io_r_reply_rrpcn(char *desc, SPOOL_R_REPLY_RRPCN *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replycloseprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &r_u->unknown0))
+ return False;
+
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ * called from spoolss_q_getprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_q_getprinterdataex(char *desc, SPOOL_Q_GETPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprinterdataex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("keyname", &q_u->keyname,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!smb_io_unistr2("valuename", &q_u->valuename,True,ps,depth))
+ return False;
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ * called from spoolss_r_getprinterdataex (srv_spoolss.c)
+ ********************************************************************/
+
+BOOL spoolss_io_r_getprinterdataex(char *desc, SPOOL_R_GETPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprinterdataex");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+ if (!prs_uint32("type", ps, depth, &r_u->type))
+ return False;
+ if (!prs_uint32("size", ps, depth, &r_u->size))
+ return False;
+
+ if (!prs_uint8s(False,"data", ps, depth, r_u->data, r_u->size))
+ return False;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+ if (!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_q_setprinterdataex(char *desc, SPOOL_Q_SETPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_setprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->value, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_u->type))
+ return False;
+
+ if(!prs_uint32("max_len", ps, depth, &q_u->max_len))
+ return False;
+
+ switch (q_u->type)
+ {
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ case 0x7:
+ if (q_u->max_len) {
+ if (UNMARSHALLING(ps))
+ q_u->data=(uint8 *)prs_alloc_mem(ps, q_u->max_len * sizeof(uint8));
+ if(q_u->data == NULL)
+ return False;
+ if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
+ return False;
+ }
+ if(!prs_align(ps))
+ return False;
+ break;
+ }
+
+ if(!prs_uint32("real_len", ps, depth, &q_u->real_len))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_r_setprinterdataex(char *desc, SPOOL_R_SETPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_setprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_q_enumprinterkey(char *desc, SPOOL_Q_ENUMPRINTERKEY *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_r_enumprinterkey(char *desc, SPOOL_R_ENUMPRINTERKEY *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterkey");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!smb_io_buffer5("", &r_u->keys, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * read a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_q_enumprinterdataex(char *desc, SPOOL_Q_ENUMPRINTERDATAEX *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("size", ps, depth, &q_u->size))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+********************************************************************/
+static BOOL spoolss_io_printer_enum_values_ctr(char *desc, prs_struct *ps,
+ PRINTER_ENUM_VALUES_CTR *ctr, int depth)
+{
+ int i;
+ uint32 valuename_offset,
+ data_offset,
+ current_offset;
+ const uint32 basic_unit = 20; /* size of static portion of enum_values */
+
+ prs_debug(ps, depth, desc, "spoolss_io_printer_enum_values_ctr");
+ depth++;
+
+ if (!prs_uint32("size", ps, depth, &ctr->size))
+ return False;
+
+ /* offset data begins at 20 bytes per structure * size_of_array. */
+
+ current_offset = basic_unit * ctr->size_of_array;
+
+ /* first loop to write basic enum_value information */
+
+ for (i=0; i<ctr->size_of_array; i++)
+ {
+ valuename_offset = current_offset;
+ if (!prs_uint32("valuename_offset", ps, depth, &valuename_offset))
+ return False;
+
+ if (!prs_uint32("value_len", ps, depth, &ctr->values[i].value_len))
+ return False;
+
+ if (!prs_uint32("type", ps, depth, &ctr->values[i].type))
+ return False;
+
+ data_offset = ctr->values[i].value_len + valuename_offset;
+ if (!prs_uint32("data_offset", ps, depth, &data_offset))
+ return False;
+
+ if (!prs_uint32("data_len", ps, depth, &ctr->values[i].data_len))
+ return False;
+
+ current_offset = data_offset + ctr->values[i].data_len - basic_unit;
+
+ }
+
+ /* loop #2 for writing the dynamically size objects
+ while viewing conversations between Win2k -> Win2k,
+ 4-byte alignment does not seem to matter here --jerry */
+
+ for (i=0; i<ctr->size_of_array; i++)
+ {
+
+ if (!prs_unistr("valuename", ps, depth, &ctr->values[i].valuename))
+ return False;
+
+ if (!prs_uint8s(False, "data", ps, depth, ctr->values[i].data, ctr->values[i].data_len))
+ return False;
+ }
+
+
+
+ return True;
+}
+
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_r_enumprinterdataex(char *desc, SPOOL_R_ENUMPRINTERDATAEX *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdataex");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!spoolss_io_printer_enum_values_ctr("", ps, &r_u->ctr, depth ))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_uint32("returned", ps, depth, &r_u->returned))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+/*
+ uint32 GetPrintProcessorDirectory(
+ [in] unistr2 *name,
+ [in] unistr2 *environment,
+ [in] uint32 level,
+ [in,out] NEW_BUFFER buffer,
+ [in] uint32 offered,
+ [out] uint32 needed,
+ [out] uint32 returned
+ );
+
+*/
+
+BOOL make_spoolss_q_getprintprocessordirectory(SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, const char *name, char *environment, int level, NEW_BUFFER *buffer, uint32 offered)
+{
+ DEBUG(5,("make_spoolss_q_getprintprocessordirectory\n"));
+
+ init_unistr2(&q_u->name, name, strlen(name)+1);
+ init_unistr2(&q_u->environment, environment, strlen(environment)+1);
+
+ q_u->level = level;
+
+ q_u->buffer = buffer;
+ q_u->offered = offered;
+
+ return True;
+}
+
+BOOL spoolss_io_q_getprintprocessordirectory(char *desc, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, prs_struct *ps, int depth)
+{
+ uint32 ptr;
+
+ prs_debug(ps, depth, desc, "spoolss_io_q_getprintprocessordirectory");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &ptr))
+ return False;
+
+ if (ptr) {
+ if(!smb_io_unistr2("name", &q_u->name, True, ps, depth))
+ return False;
+ }
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("ptr", ps, depth, &ptr))
+ return False;
+
+ if (ptr) {
+ if(!smb_io_unistr2("environment", &q_u->environment, True,
+ ps, depth))
+ return False;
+ }
+
+ if (!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_u->level))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &q_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("offered", ps, depth, &q_u->offered))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ * write a structure.
+ ********************************************************************/
+
+BOOL spoolss_io_r_getprintprocessordirectory(char *desc, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_getprintprocessordirectory");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!spoolss_io_buffer("", ps, depth, &r_u->buffer))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("needed", ps, depth, &r_u->needed))
+ return False;
+
+ if(!prs_werror("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
+
+BOOL smb_io_printprocessordirectory_1(char *desc, NEW_BUFFER *buffer, PRINTPROCESSOR_DIRECTORY_1 *info, int depth)
+{
+ prs_struct *ps=&buffer->prs;
+
+ prs_debug(ps, depth, desc, "smb_io_printprocessordirectory_1");
+ depth++;
+
+ buffer->struct_start=prs_offset(ps);
+
+ if (!smb_io_unistr(desc, &info->name, ps, depth))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_srv.c b/source/rpc_parse/parse_srv.c
new file mode 100644
index 00000000000..fa52b244956
--- /dev/null
+++ b/source/rpc_parse/parse_srv.c
@@ -0,0 +1,2795 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Inits a SH_INFO_1_STR structure
+********************************************************************/
+
+void init_srv_share_info1_str(SH_INFO_1_STR *sh1, char *net_name, char *remark)
+{
+ DEBUG(5,("init_srv_share_info1_str\n"));
+
+ init_unistr2(&sh1->uni_netname, net_name, strlen(net_name)+1);
+ init_unistr2(&sh1->uni_remark, remark, strlen(remark)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info1_str(char *desc, SH_INFO_1_STR *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh1->uni_netname, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh1->uni_remark, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ makes a SH_INFO_1 structure
+********************************************************************/
+
+void init_srv_share_info1(SH_INFO_1 *sh1, char *net_name, uint32 type, char *remark)
+{
+ DEBUG(5,("init_srv_share_info1: %s %8x %s\n", net_name, type, remark));
+
+ sh1->ptr_netname = (net_name != NULL) ? 1 : 0;
+ sh1->type = type;
+ sh1->ptr_remark = (remark != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info1(char *desc, SH_INFO_1 *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_netname", ps, depth, &sh1->ptr_netname))
+ return False;
+ if(!prs_uint32("type ", ps, depth, &sh1->type))
+ return False;
+ if(!prs_uint32("ptr_remark ", ps, depth, &sh1->ptr_remark))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SH_INFO_2_STR structure
+********************************************************************/
+
+void init_srv_share_info2_str(SH_INFO_2_STR *sh2,
+ char *net_name, char *remark,
+ char *path, char *passwd)
+{
+ DEBUG(5,("init_srv_share_info2_str\n"));
+
+ init_unistr2(&sh2->uni_netname, net_name, strlen(net_name)+1);
+ init_unistr2(&sh2->uni_remark, remark, strlen(remark)+1);
+ init_unistr2(&sh2->uni_path, path, strlen(path)+1);
+ init_unistr2(&sh2->uni_passwd, passwd, strlen(passwd)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info2_str(char *desc, SH_INFO_2_STR *sh2, prs_struct *ps, int depth)
+{
+ if (sh2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info2_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh2->uni_netname, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh2->uni_remark, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh2->uni_path, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("", &sh2->uni_passwd, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SH_INFO_2 structure
+********************************************************************/
+
+void init_srv_share_info2(SH_INFO_2 *sh2,
+ char *net_name, uint32 type, char *remark,
+ uint32 perms, uint32 max_uses, uint32 num_uses,
+ char *path, char *passwd)
+{
+ DEBUG(5,("init_srv_share_info2: %s %8x %s\n", net_name, type, remark));
+
+ sh2->ptr_netname = (net_name != NULL) ? 1 : 0;
+ sh2->type = type;
+ sh2->ptr_remark = (remark != NULL) ? 1 : 0;
+ sh2->perms = perms;
+ sh2->max_uses = max_uses;
+ sh2->num_uses = num_uses;
+ sh2->type = type;
+ sh2->ptr_path = (path != NULL) ? 1 : 0;
+ sh2->ptr_passwd = (passwd != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info2(char *desc, SH_INFO_2 *sh2, prs_struct *ps, int depth)
+{
+ if (sh2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info2");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_netname", ps, depth, &sh2->ptr_netname))
+ return False;
+ if(!prs_uint32("type ", ps, depth, &sh2->type))
+ return False;
+ if(!prs_uint32("ptr_remark ", ps, depth, &sh2->ptr_remark))
+ return False;
+ if(!prs_uint32("perms ", ps, depth, &sh2->perms))
+ return False;
+ if(!prs_uint32("max_uses ", ps, depth, &sh2->max_uses))
+ return False;
+ if(!prs_uint32("num_uses ", ps, depth, &sh2->num_uses))
+ return False;
+ if(!prs_uint32("ptr_path ", ps, depth, &sh2->ptr_path))
+ return False;
+ if(!prs_uint32("ptr_passwd ", ps, depth, &sh2->ptr_passwd))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SH_INFO_502 structure
+********************************************************************/
+
+void init_srv_share_info502(SH_INFO_502 *sh502,
+ char *net_name, uint32 type, char *remark,
+ uint32 perms, uint32 max_uses, uint32 num_uses,
+ char *path, char *passwd, SEC_DESC *psd, size_t sd_size)
+{
+ DEBUG(5,("init_srv_share_info502: %s %8x %s\n", net_name, type, remark));
+
+ ZERO_STRUCTP(sh502);
+
+ sh502->ptr_netname = (net_name != NULL) ? 1 : 0;
+ sh502->type = type;
+ sh502->ptr_remark = (remark != NULL) ? 1 : 0;
+ sh502->perms = perms;
+ sh502->max_uses = max_uses;
+ sh502->num_uses = num_uses;
+ sh502->type = type;
+ sh502->ptr_path = (path != NULL) ? 1 : 0;
+ sh502->ptr_passwd = (passwd != NULL) ? 1 : 0;
+ sh502->sd_size = (uint32)sd_size;
+ sh502->ptr_sd = (psd != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info502(char *desc, SH_INFO_502 *sh502, prs_struct *ps, int depth)
+{
+ if (sh502 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info502");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_netname", ps, depth, &sh502->ptr_netname))
+ return False;
+ if(!prs_uint32("type ", ps, depth, &sh502->type))
+ return False;
+ if(!prs_uint32("ptr_remark ", ps, depth, &sh502->ptr_remark))
+ return False;
+ if(!prs_uint32("perms ", ps, depth, &sh502->perms))
+ return False;
+ if(!prs_uint32("max_uses ", ps, depth, &sh502->max_uses))
+ return False;
+ if(!prs_uint32("num_uses ", ps, depth, &sh502->num_uses))
+ return False;
+ if(!prs_uint32("ptr_path ", ps, depth, &sh502->ptr_path))
+ return False;
+ if(!prs_uint32("ptr_passwd ", ps, depth, &sh502->ptr_passwd))
+ return False;
+ if(!prs_uint32("sd_size ", ps, depth, &sh502->sd_size))
+ return False;
+ if(!prs_uint32("ptr_sd ", ps, depth, &sh502->ptr_sd))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SH_INFO_502_STR structure
+********************************************************************/
+
+void init_srv_share_info502_str(SH_INFO_502_STR *sh502str,
+ SH_INFO_502 *ptrs,
+ char *net_name, char *remark,
+ char *path, char *passwd, SEC_DESC *psd, size_t sd_size)
+{
+ DEBUG(5,("init_srv_share_info502_str\n"));
+
+ sh502str->ptrs = ptrs;
+
+ if(sh502str->ptrs->ptr_netname)
+ init_unistr2(&sh502str->uni_netname, net_name, strlen(net_name)+1);
+ if(sh502str->ptrs->ptr_remark)
+ init_unistr2(&sh502str->uni_remark, remark, strlen(remark)+1);
+ if(sh502str->ptrs->ptr_path)
+ init_unistr2(&sh502str->uni_path, path, strlen(path)+1);
+ if(sh502str->ptrs->ptr_passwd)
+ init_unistr2(&sh502str->uni_passwd, passwd, strlen(passwd)+1);
+ if(sh502str->ptrs->ptr_sd) {
+ sh502str->sd = psd;
+ sh502str->sd_size = sd_size;
+ }
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info502_str(char *desc, SH_INFO_502_STR *sh502, prs_struct *ps, int depth)
+{
+ if (sh502 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info502_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(sh502->ptrs->ptr_netname) {
+ if(!smb_io_unistr2("", &sh502->uni_netname, True, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(sh502->ptrs->ptr_remark) {
+ if(!smb_io_unistr2("", &sh502->uni_remark, True, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(sh502->ptrs->ptr_path) {
+ if(!smb_io_unistr2("", &sh502->uni_path, True, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(sh502->ptrs->ptr_passwd) {
+ if(!smb_io_unistr2("", &sh502->uni_passwd, True, ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(sh502->ptrs->ptr_sd) {
+ if(!prs_uint32("sd_size ", ps, depth, &sh502->sd_size))
+ return False;
+ if (!sec_io_desc(desc, &sh502->sd, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info1005(char* desc, SRV_SHARE_INFO_1005* sh1005,
+ prs_struct* ps, int depth)
+{
+ if(sh1005 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1005");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("dfs_root_flag", ps, depth, &sh1005->dfs_root_flag))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_share_info1501(char* desc, SRV_SHARE_INFO_1501* sh1501,
+ prs_struct* ps, int depth)
+{
+ if(sh1501 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1501");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if (!sec_io_desc_buf(desc, &sh1501->sdb, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_share_ctr(char *desc, SRV_SHARE_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_share_ctr");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ memset(ctr, '\0', sizeof(SRV_SHARE_INFO_CTR));
+ }
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &ctr->info_level))
+ return False;
+
+ if (ctr->info_level == 0)
+ return True;
+
+ if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_share_info", ps, depth, &ctr->ptr_share_info))
+ return False;
+
+ if (ctr->ptr_share_info == 0)
+ return True;
+
+ if(!prs_uint32("num_entries", ps, depth, &ctr->num_entries))
+ return False;
+ if(!prs_uint32("ptr_entries", ps, depth, &ctr->ptr_entries))
+ return False;
+
+ if (ctr->ptr_entries == 0) {
+ if (ctr->num_entries == 0)
+ return True;
+ else
+ return False;
+ }
+
+ if(!prs_uint32("num_entries2", ps, depth, &ctr->num_entries2))
+ return False;
+
+ if (ctr->num_entries2 != ctr->num_entries)
+ return False;
+
+ switch (ctr->switch_value) {
+ case 1:
+ {
+ SRV_SHARE_INFO_1 *info1 = ctr->share.info1;
+ int num_entries = ctr->num_entries;
+ int i;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(info1 = (SRV_SHARE_INFO_1 *)prs_alloc_mem(ps, num_entries * sizeof(SRV_SHARE_INFO_1))))
+ return False;
+ ctr->share.info1 = info1;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_share_info1("", &info1[i].info_1, ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_share_info1_str("", &info1[i].info_1_str, ps, depth))
+ return False;
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ SRV_SHARE_INFO_2 *info2 = ctr->share.info2;
+ int num_entries = ctr->num_entries;
+ int i;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(info2 = (SRV_SHARE_INFO_2 *)prs_alloc_mem(ps,num_entries * sizeof(SRV_SHARE_INFO_2))))
+ return False;
+ ctr->share.info2 = info2;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_share_info2("", &info2[i].info_2, ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_share_info2_str("", &info2[i].info_2_str, ps, depth))
+ return False;
+ }
+
+ break;
+ }
+
+ case 502:
+ {
+ SRV_SHARE_INFO_502 *info502 = ctr->share.info502;
+ int num_entries = ctr->num_entries;
+ int i;
+
+ if (UNMARSHALLING(ps)) {
+ if (!(info502 = (SRV_SHARE_INFO_502 *)prs_alloc_mem(ps,num_entries * sizeof(SRV_SHARE_INFO_502))))
+ return False;
+ ctr->share.info502 = info502;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_share_info502("", &info502[i].info_502, ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ info502[i].info_502_str.ptrs = &info502[i].info_502;
+ if(!srv_io_share_info502_str("", &info502[i].info_502_str, ps, depth))
+ return False;
+ }
+
+ break;
+ }
+
+ default:
+ DEBUG(5,("%s no share info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_Q_NET_SHARE_ENUM structure.
+********************************************************************/
+
+void init_srv_q_net_share_enum(SRV_Q_NET_SHARE_ENUM *q_n,
+ char *srv_name, uint32 info_level,
+ uint32 preferred_len, ENUM_HND *hnd)
+{
+
+ DEBUG(5,("init_q_net_share_enum\n"));
+
+ init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name);
+
+ q_n->ctr.info_level = q_n->ctr.switch_value = info_level;
+ q_n->ctr.ptr_share_info = 0;
+ q_n->preferred_len = preferred_len;
+
+ memcpy(&q_n->enum_hnd, hnd, sizeof(*hnd));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_share_enum(char *desc, SRV_Q_NET_SHARE_ENUM *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!srv_io_srv_share_ctr("share_ctr", &q_n->ctr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len))
+ return False;
+
+ if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_share_enum(char *desc, SRV_R_NET_SHARE_ENUM *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_enum");
+ depth++;
+
+ if(!srv_io_srv_share_ctr("share_ctr", &r_n->ctr, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("total_entries", ps, depth, &r_n->total_entries))
+ return False;
+ if(!smb_io_enum_hnd("enum_hnd", &r_n->enum_hnd, ps, depth))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_share_get_info(char *desc, SRV_Q_NET_SHARE_GET_INFO *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_get_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_share_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &q_n->info_level))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_share_info(char *desc, prs_struct *ps, int depth, SRV_SHARE_INFO *r_n)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_share_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &r_n->switch_value ))
+ return False;
+
+ if(!prs_uint32("ptr_share_ctr", ps, depth, &r_n->ptr_share_ctr))
+ return False;
+
+ if (r_n->ptr_share_ctr != 0) {
+ switch (r_n->switch_value) {
+ case 1:
+ if(!srv_io_share_info1("", &r_n->share.info1.info_1, ps, depth))
+ return False;
+
+ if(!srv_io_share_info1_str("", &r_n->share.info1.info_1_str, ps, depth))
+ return False;
+
+ break;
+ case 2:
+ if(!srv_io_share_info2("", &r_n->share.info2.info_2, ps, depth))
+ return False;
+
+ if(!srv_io_share_info2_str("", &r_n->share.info2.info_2_str, ps, depth))
+ return False;
+
+ break;
+ case 502:
+ if(!srv_io_share_info502("", &r_n->share.info502.info_502, ps, depth))
+ return False;
+
+ /*allow access to pointers in the str part. */
+ r_n->share.info502.info_502_str.ptrs = &r_n->share.info502.info_502;
+
+ if(!srv_io_share_info502_str("", &r_n->share.info502.info_502_str, ps, depth))
+ return False;
+ break;
+ case 1005:
+ if(!srv_io_share_info1005("", &r_n->share.info1005, ps, depth))
+ return False;
+ break;
+ case 1501:
+ if (!srv_io_share_info1501("", &r_n->share.info1501, ps, depth))
+ return False;
+ default:
+ DEBUG(5,("%s no share info at switch_value %d\n",
+ tab_depth(depth), r_n->switch_value));
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_share_get_info(char *desc, SRV_R_NET_SHARE_GET_INFO *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_get_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!srv_io_srv_share_info("info ", ps, depth, &r_n->info))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_share_set_info(char *desc, SRV_Q_NET_SHARE_SET_INFO *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_set_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_share_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &q_n->info_level))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!srv_io_srv_share_info("info ", ps, depth, &q_n->info))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_share_set_info(char *desc, SRV_R_NET_SHARE_SET_INFO *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_set_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &q_n->switch_value))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &q_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_share_add(char *desc, SRV_Q_NET_SHARE_ADD *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_add");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("info_level", ps, depth, &q_n->info_level))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!srv_io_srv_share_info("info ", ps, depth, &q_n->info))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_share_add(char *desc, SRV_R_NET_SHARE_ADD *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_add");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &q_n->switch_value))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &q_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_share_del(char *desc, SRV_Q_NET_SHARE_DEL *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_del");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_share_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_share_del(char *desc, SRV_R_NET_SHARE_DEL *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_del");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &q_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SESS_INFO_0_STR structure
+********************************************************************/
+
+void init_srv_sess_info0_str(SESS_INFO_0_STR *ss0, char *name)
+{
+ DEBUG(5,("init_srv_sess_info0_str\n"));
+
+ init_unistr2(&ss0->uni_name, name, strlen(name)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_sess_info0_str(char *desc, SESS_INFO_0_STR *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info0_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &ss0->uni_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SESS_INFO_0 structure
+********************************************************************/
+
+void init_srv_sess_info0(SESS_INFO_0 *ss0, char *name)
+{
+ DEBUG(5,("init_srv_sess_info0: %s\n", name));
+
+ ss0->ptr_name = (name != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_sess_info0(char *desc, SESS_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info0");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_name", ps, depth, &ss0->ptr_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_sess_info_0(char *desc, SRV_SESS_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_info_0");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries_read", ps, depth, &ss0->num_entries_read))
+ return False;
+ if(!prs_uint32("ptr_sess_info", ps, depth, &ss0->ptr_sess_info))
+ return False;
+
+ if (ss0->ptr_sess_info != 0) {
+ int i;
+ int num_entries = ss0->num_entries_read;
+
+ if (num_entries > MAX_SESS_ENTRIES) {
+ num_entries = MAX_SESS_ENTRIES; /* report this! */
+ }
+
+ if(!prs_uint32("num_entries_read2", ps, depth, &ss0->num_entries_read2))
+ return False;
+
+ SMB_ASSERT_ARRAY(ss0->info_0, num_entries);
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_sess_info0("", &ss0->info_0[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_sess_info0_str("", &ss0->info_0_str[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SESS_INFO_1_STR structure
+********************************************************************/
+
+void init_srv_sess_info1_str(SESS_INFO_1_STR *ss1, char *name, char *user)
+{
+ DEBUG(5,("init_srv_sess_info1_str\n"));
+
+ init_unistr2(&ss1->uni_name, name, strlen(name)+1);
+ init_unistr2(&ss1->uni_user, name, strlen(user)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_sess_info1_str(char *desc, SESS_INFO_1_STR *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info1_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &ss1->uni_name, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &(ss1->uni_user), True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SESS_INFO_1 structure
+********************************************************************/
+
+void init_srv_sess_info1(SESS_INFO_1 *ss1,
+ char *name, char *user,
+ uint32 num_opens, uint32 open_time, uint32 idle_time,
+ uint32 user_flags)
+{
+ DEBUG(5,("init_srv_sess_info1: %s\n", name));
+
+ ss1->ptr_name = (name != NULL) ? 1 : 0;
+ ss1->ptr_user = (user != NULL) ? 1 : 0;
+
+ ss1->num_opens = num_opens;
+ ss1->open_time = open_time;
+ ss1->idle_time = idle_time;
+ ss1->user_flags = user_flags;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_sess_info1(char *desc, SESS_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_name ", ps, depth, &ss1->ptr_name))
+ return False;
+ if(!prs_uint32("ptr_user ", ps, depth, &ss1->ptr_user))
+ return False;
+
+ if(!prs_uint32("num_opens ", ps, depth, &ss1->num_opens))
+ return False;
+ if(!prs_uint32("open_time ", ps, depth, &ss1->open_time))
+ return False;
+ if(!prs_uint32("idle_time ", ps, depth, &ss1->idle_time))
+ return False;
+ if(!prs_uint32("user_flags", ps, depth, &ss1->user_flags))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_sess_info_1(char *desc, SRV_SESS_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_info_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries_read", ps, depth, &ss1->num_entries_read))
+ return False;
+ if(!prs_uint32("ptr_sess_info", ps, depth, &ss1->ptr_sess_info))
+ return False;
+
+ if (ss1->ptr_sess_info != 0) {
+ int i;
+ int num_entries = ss1->num_entries_read;
+
+ if (num_entries > MAX_SESS_ENTRIES) {
+ num_entries = MAX_SESS_ENTRIES; /* report this! */
+ }
+
+ if(!prs_uint32("num_entries_read2", ps, depth, &ss1->num_entries_read2))
+ return False;
+
+ SMB_ASSERT_ARRAY(ss1->info_1, num_entries);
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_sess_info1("", &ss1->info_1[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_sess_info1_str("", &ss1->info_1_str[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_sess_ctr(char *desc, SRV_SESS_INFO_CTR **pp_ctr, prs_struct *ps, int depth)
+{
+ SRV_SESS_INFO_CTR *ctr = *pp_ctr;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_ctr");
+ depth++;
+
+ if(UNMARSHALLING(ps)) {
+ ctr = *pp_ctr = (SRV_SESS_INFO_CTR *)prs_alloc_mem(ps, sizeof(SRV_SESS_INFO_CTR));
+ if (ctr == NULL)
+ return False;
+ }
+
+ if (ctr == NULL)
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_sess_ctr", ps, depth, &ctr->ptr_sess_ctr))
+ return False;
+
+ if (ctr->ptr_sess_ctr != 0) {
+ switch (ctr->switch_value) {
+ case 0:
+ if(!srv_io_srv_sess_info_0("", &ctr->sess.info0, ps, depth))
+ return False;
+ break;
+ case 1:
+ if(!srv_io_srv_sess_info_1("", &ctr->sess.info1, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(5,("%s no session info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_Q_NET_SESS_ENUM structure.
+********************************************************************/
+
+void init_srv_q_net_sess_enum(SRV_Q_NET_SESS_ENUM *q_n,
+ char *srv_name, char *qual_name,
+ uint32 sess_level, SRV_SESS_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ q_n->ctr = ctr;
+
+ DEBUG(5,("init_q_net_sess_enum\n"));
+
+ init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name);
+ init_buf_unistr2(&q_n->uni_qual_name, &q_n->ptr_qual_name, qual_name);
+
+ q_n->sess_level = sess_level;
+ q_n->preferred_len = preferred_len;
+
+ memcpy(&q_n->enum_hnd, hnd, sizeof(*hnd));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_sess_enum(char *desc, SRV_Q_NET_SESS_ENUM *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_sess_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_qual_name, q_n->ptr_qual_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("sess_level", ps, depth, &q_n->sess_level))
+ return False;
+
+ if (q_n->sess_level != -1) {
+ if(!srv_io_srv_sess_ctr("sess_ctr", &q_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len))
+ return False;
+
+ if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_sess_enum(char *desc, SRV_R_NET_SESS_ENUM *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_sess_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("sess_level", ps, depth, &r_n->sess_level))
+ return False;
+
+ if (r_n->sess_level != -1) {
+ if(!srv_io_srv_sess_ctr("sess_ctr", &r_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("total_entries", ps, depth, &r_n->total_entries))
+ return False;
+ if(!smb_io_enum_hnd("enum_hnd", &r_n->enum_hnd, ps, depth))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a CONN_INFO_0 structure
+********************************************************************/
+
+void init_srv_conn_info0(CONN_INFO_0 *ss0, uint32 id)
+{
+ DEBUG(5,("init_srv_conn_info0\n"));
+
+ ss0->id = id;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_conn_info0(char *desc, CONN_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info0");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("id", ps, depth, &ss0->id))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_conn_info_0(char *desc, SRV_CONN_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_info_0");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries_read", ps, depth, &ss0->num_entries_read))
+ return False;
+ if(!prs_uint32("ptr_conn_info", ps, depth, &ss0->ptr_conn_info))
+ return False;
+
+ if (ss0->ptr_conn_info != 0) {
+ int i;
+ int num_entries = ss0->num_entries_read;
+
+ if (num_entries > MAX_CONN_ENTRIES) {
+ num_entries = MAX_CONN_ENTRIES; /* report this! */
+ }
+
+ if(!prs_uint32("num_entries_read2", ps, depth, &ss0->num_entries_read2))
+ return False;
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_conn_info0("", &ss0->info_0[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a CONN_INFO_1_STR structure
+********************************************************************/
+
+void init_srv_conn_info1_str(CONN_INFO_1_STR *ss1, char *usr_name, char *net_name)
+{
+ DEBUG(5,("init_srv_conn_info1_str\n"));
+
+ init_unistr2(&ss1->uni_usr_name, usr_name, strlen(usr_name)+1);
+ init_unistr2(&ss1->uni_net_name, net_name, strlen(net_name)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_conn_info1_str(char *desc, CONN_INFO_1_STR *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info1_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &ss1->uni_usr_name, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &ss1->uni_net_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a CONN_INFO_1 structure
+********************************************************************/
+
+void init_srv_conn_info1(CONN_INFO_1 *ss1,
+ uint32 id, uint32 type,
+ uint32 num_opens, uint32 num_users, uint32 open_time,
+ char *usr_name, char *net_name)
+{
+ DEBUG(5,("init_srv_conn_info1: %s %s\n", usr_name, net_name));
+
+ ss1->id = id ;
+ ss1->type = type ;
+ ss1->num_opens = num_opens ;
+ ss1->num_users = num_users;
+ ss1->open_time = open_time;
+
+ ss1->ptr_usr_name = (usr_name != NULL) ? 1 : 0;
+ ss1->ptr_net_name = (net_name != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_conn_info1(char *desc, CONN_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("id ", ps, depth, &ss1->id))
+ return False;
+ if(!prs_uint32("type ", ps, depth, &ss1->type))
+ return False;
+ if(!prs_uint32("num_opens ", ps, depth, &ss1->num_opens))
+ return False;
+ if(!prs_uint32("num_users ", ps, depth, &ss1->num_users))
+ return False;
+ if(!prs_uint32("open_time ", ps, depth, &ss1->open_time))
+ return False;
+
+ if(!prs_uint32("ptr_usr_name", ps, depth, &ss1->ptr_usr_name))
+ return False;
+ if(!prs_uint32("ptr_net_name", ps, depth, &ss1->ptr_net_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_conn_info_1(char *desc, SRV_CONN_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_info_1");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries_read", ps, depth, &ss1->num_entries_read))
+ return False;
+ if(!prs_uint32("ptr_conn_info", ps, depth, &ss1->ptr_conn_info))
+ return False;
+
+ if (ss1->ptr_conn_info != 0) {
+ int i;
+ int num_entries = ss1->num_entries_read;
+
+ if (num_entries > MAX_CONN_ENTRIES) {
+ num_entries = MAX_CONN_ENTRIES; /* report this! */
+ }
+
+ if(!prs_uint32("num_entries_read2", ps, depth, &ss1->num_entries_read2))
+ return False;
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_conn_info1("", &ss1->info_1[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_conn_info1_str("", &ss1->info_1_str[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_conn_ctr(char *desc, SRV_CONN_INFO_CTR **pp_ctr, prs_struct *ps, int depth)
+{
+ SRV_CONN_INFO_CTR *ctr = *pp_ctr;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_ctr");
+ depth++;
+
+ if (UNMARSHALLING(ps)) {
+ ctr = *pp_ctr = (SRV_CONN_INFO_CTR *)prs_alloc_mem(ps, sizeof(SRV_CONN_INFO_CTR));
+ if (ctr == NULL)
+ return False;
+ }
+
+ if (ctr == NULL)
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_conn_ctr", ps, depth, &ctr->ptr_conn_ctr))
+ return False;
+
+ if (ctr->ptr_conn_ctr != 0) {
+ switch (ctr->switch_value) {
+ case 0:
+ if(!srv_io_srv_conn_info_0("", &ctr->conn.info0, ps, depth))
+ return False;
+ break;
+ case 1:
+ if(!srv_io_srv_conn_info_1("", &ctr->conn.info1, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(5,("%s no connection info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+void init_srv_q_net_conn_enum(SRV_Q_NET_CONN_ENUM *q_n,
+ char *srv_name, char *qual_name,
+ uint32 conn_level, SRV_CONN_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ DEBUG(5,("init_q_net_conn_enum\n"));
+
+ q_n->ctr = ctr;
+
+ init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name );
+ init_buf_unistr2(&q_n->uni_qual_name, &q_n->ptr_qual_name, qual_name);
+
+ q_n->conn_level = conn_level;
+ q_n->preferred_len = preferred_len;
+
+ memcpy(&q_n->enum_hnd, hnd, sizeof(*hnd));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_conn_enum(char *desc, SRV_Q_NET_CONN_ENUM *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_conn_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name ", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, q_n->ptr_srv_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_qual_name, q_n->ptr_qual_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("conn_level", ps, depth, &q_n->conn_level))
+ return False;
+
+ if (q_n->conn_level != -1) {
+ if(!srv_io_srv_conn_ctr("conn_ctr", &q_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len))
+ return False;
+
+ if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_conn_enum(char *desc, SRV_R_NET_CONN_ENUM *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_conn_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("conn_level", ps, depth, &r_n->conn_level))
+ return False;
+
+ if (r_n->conn_level != -1) {
+ if(!srv_io_srv_conn_ctr("conn_ctr", &r_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("total_entries", ps, depth, &r_n->total_entries))
+ return False;
+ if(!smb_io_enum_hnd("enum_hnd", &r_n->enum_hnd, ps, depth))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a FILE_INFO_3_STR structure
+********************************************************************/
+
+void init_srv_file_info3_str(FILE_INFO_3_STR *fi3, char *user_name, char *path_name)
+{
+ DEBUG(5,("init_srv_file_info3_str\n"));
+
+ init_unistr2(&fi3->uni_path_name, path_name, strlen(path_name)+1);
+ init_unistr2(&fi3->uni_user_name, user_name, strlen(user_name)+1);
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_file_info3_str(char *desc, FILE_INFO_3_STR *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_file_info3_str");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &sh1->uni_path_name, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("", &sh1->uni_user_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a FILE_INFO_3 structure
+********************************************************************/
+
+void init_srv_file_info3(FILE_INFO_3 *fl3,
+ uint32 id, uint32 perms, uint32 num_locks,
+ char *path_name, char *user_name)
+{
+ DEBUG(5,("init_srv_file_info3: %s %s\n", path_name, user_name));
+
+ fl3->id = id;
+ fl3->perms = perms;
+ fl3->num_locks = num_locks;
+
+ fl3->ptr_path_name = (path_name != NULL) ? 1 : 0;
+ fl3->ptr_user_name = (user_name != NULL) ? 1 : 0;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_file_info3(char *desc, FILE_INFO_3 *fl3, prs_struct *ps, int depth)
+{
+ if (fl3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_file_info3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("id ", ps, depth, &fl3->id))
+ return False;
+ if(!prs_uint32("perms ", ps, depth, &fl3->perms))
+ return False;
+ if(!prs_uint32("num_locks ", ps, depth, &fl3->num_locks))
+ return False;
+ if(!prs_uint32("ptr_path_name", ps, depth, &fl3->ptr_path_name))
+ return False;
+ if(!prs_uint32("ptr_user_name", ps, depth, &fl3->ptr_user_name))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_file_info_3(char *desc, SRV_FILE_INFO_3 *fl3, prs_struct *ps, int depth)
+{
+ if (fl3 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_file_3_fl3");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("num_entries_read", ps, depth, &fl3->num_entries_read))
+ return False;
+ if(!prs_uint32("ptr_file_fl3", ps, depth, &fl3->ptr_file_info))
+ return False;
+
+ if (fl3->ptr_file_info != 0) {
+ int i;
+ int num_entries = fl3->num_entries_read;
+
+ if (num_entries > MAX_FILE_ENTRIES) {
+ num_entries = MAX_FILE_ENTRIES; /* report this! */
+ }
+
+ if(!prs_uint32("num_entries_read2", ps, depth, &fl3->num_entries_read2))
+ return False;
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_file_info3("", &fl3->info_3[i], ps, depth))
+ return False;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if(!srv_io_file_info3_str("", &fl3->info_3_str[i], ps, depth))
+ return False;
+ }
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+static BOOL srv_io_srv_file_ctr(char *desc, SRV_FILE_INFO_CTR **pp_ctr, prs_struct *ps, int depth)
+{
+ SRV_FILE_INFO_CTR *ctr = *pp_ctr;
+
+ if (UNMARSHALLING(ps)) {
+ ctr = *pp_ctr = (SRV_FILE_INFO_CTR *)prs_alloc_mem(ps, sizeof(SRV_FILE_INFO_CTR));
+ if (ctr == NULL)
+ return False;
+ }
+
+ if (ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_file_ctr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_file_ctr", ps, depth, &ctr->ptr_file_ctr))
+ return False;
+
+ if (ctr->ptr_file_ctr != 0) {
+ switch (ctr->switch_value) {
+ case 3:
+ if(!srv_io_srv_file_info_3("", &ctr->file.info3, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(5,("%s no file info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_Q_NET_FILE_ENUM structure.
+********************************************************************/
+
+void init_srv_q_net_file_enum(SRV_Q_NET_FILE_ENUM *q_n,
+ char *srv_name, char *qual_name,
+ uint32 file_level, SRV_FILE_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ DEBUG(5,("init_q_net_file_enum\n"));
+
+ q_n->ctr = ctr;
+
+ init_buf_unistr2(&q_n->uni_srv_name, &q_n->ptr_srv_name, srv_name);
+ init_buf_unistr2(&q_n->uni_qual_name, &q_n->ptr_qual_name, qual_name);
+
+ q_n->file_level = file_level;
+ q_n->preferred_len = preferred_len;
+
+ memcpy(&q_n->enum_hnd, hnd, sizeof(*hnd));
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_file_enum(char *desc, SRV_Q_NET_FILE_ENUM *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_file_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_qual_name, q_n->ptr_qual_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("file_level", ps, depth, &q_n->file_level))
+ return False;
+
+ if (q_n->file_level != -1) {
+ if(!srv_io_srv_file_ctr("file_ctr", &q_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len))
+ return False;
+
+ if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_file_enum(char *desc, SRV_R_NET_FILE_ENUM *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_file_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("file_level", ps, depth, &r_n->file_level))
+ return False;
+
+ if (r_n->file_level != 0) {
+ if(!srv_io_srv_file_ctr("file_ctr", &r_n->ctr, ps, depth))
+ return False;
+ }
+
+ if(!prs_uint32("total_entries", ps, depth, &r_n->total_entries))
+ return False;
+ if(!smb_io_enum_hnd("enum_hnd", &r_n->enum_hnd, ps, depth))
+ return False;
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_INFO_100 structure.
+ ********************************************************************/
+
+void init_srv_info_100(SRV_INFO_100 *sv100, uint32 platform_id, char *name)
+{
+ DEBUG(5,("init_srv_info_100\n"));
+
+ sv100->platform_id = platform_id;
+ init_buf_unistr2(&sv100->uni_name, &sv100->ptr_name, name);
+}
+
+/*******************************************************************
+ Reads or writes a SRV_INFO_101 structure.
+ ********************************************************************/
+
+static BOOL srv_io_info_100(char *desc, SRV_INFO_100 *sv100, prs_struct *ps, int depth)
+{
+ if (sv100 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_info_100");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("platform_id ", ps, depth, &sv100->platform_id))
+ return False;
+ if(!prs_uint32("ptr_name ", ps, depth, &sv100->ptr_name))
+ return False;
+
+ if(!smb_io_unistr2("uni_name ", &sv100->uni_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ Inits a SRV_INFO_101 structure.
+ ********************************************************************/
+
+void init_srv_info_101(SRV_INFO_101 *sv101, uint32 platform_id, char *name,
+ uint32 ver_major, uint32 ver_minor,
+ uint32 srv_type, char *comment)
+{
+ DEBUG(5,("init_srv_info_101\n"));
+
+ sv101->platform_id = platform_id;
+ init_buf_unistr2(&sv101->uni_name, &sv101->ptr_name, name);
+ sv101->ver_major = ver_major;
+ sv101->ver_minor = ver_minor;
+ sv101->srv_type = srv_type;
+ init_buf_unistr2(&sv101->uni_comment, &sv101->ptr_comment, comment);
+}
+
+/*******************************************************************
+ Reads or writes a SRV_INFO_101 structure.
+ ********************************************************************/
+
+static BOOL srv_io_info_101(char *desc, SRV_INFO_101 *sv101, prs_struct *ps, int depth)
+{
+ if (sv101 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_info_101");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("platform_id ", ps, depth, &sv101->platform_id))
+ return False;
+ if(!prs_uint32("ptr_name ", ps, depth, &sv101->ptr_name))
+ return False;
+ if(!prs_uint32("ver_major ", ps, depth, &sv101->ver_major))
+ return False;
+ if(!prs_uint32("ver_minor ", ps, depth, &sv101->ver_minor))
+ return False;
+ if(!prs_uint32("srv_type ", ps, depth, &sv101->srv_type))
+ return False;
+ if(!prs_uint32("ptr_comment ", ps, depth, &sv101->ptr_comment))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("uni_name ", &sv101->uni_name, True, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_comment ", &sv101->uni_comment, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_INFO_102 structure.
+ ********************************************************************/
+
+void init_srv_info_102(SRV_INFO_102 *sv102, uint32 platform_id, char *name,
+ char *comment, uint32 ver_major, uint32 ver_minor,
+ uint32 srv_type, uint32 users, uint32 disc, uint32 hidden,
+ uint32 announce, uint32 ann_delta, uint32 licenses,
+ char *usr_path)
+{
+ DEBUG(5,("init_srv_info_102\n"));
+
+ sv102->platform_id = platform_id;
+ init_buf_unistr2(&sv102->uni_name, &sv102->ptr_name, name);
+ sv102->ver_major = ver_major;
+ sv102->ver_minor = ver_minor;
+ sv102->srv_type = srv_type;
+ init_buf_unistr2(&sv102->uni_comment, &sv102->ptr_comment, comment);
+
+ /* same as 101 up to here */
+
+ sv102->users = users;
+ sv102->disc = disc;
+ sv102->hidden = hidden;
+ sv102->announce = announce;
+ sv102->ann_delta =ann_delta;
+ sv102->licenses = licenses;
+ init_buf_unistr2(&sv102->uni_usr_path, &sv102->ptr_usr_path, usr_path);
+}
+
+
+/*******************************************************************
+ Reads or writes a SRV_INFO_102 structure.
+ ********************************************************************/
+
+static BOOL srv_io_info_102(char *desc, SRV_INFO_102 *sv102, prs_struct *ps, int depth)
+{
+ if (sv102 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_info102");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("platform_id ", ps, depth, &sv102->platform_id))
+ return False;
+ if(!prs_uint32("ptr_name ", ps, depth, &sv102->ptr_name))
+ return False;
+ if(!prs_uint32("ver_major ", ps, depth, &sv102->ver_major))
+ return False;
+ if(!prs_uint32("ver_minor ", ps, depth, &sv102->ver_minor))
+ return False;
+ if(!prs_uint32("srv_type ", ps, depth, &sv102->srv_type))
+ return False;
+ if(!prs_uint32("ptr_comment ", ps, depth, &sv102->ptr_comment))
+ return False;
+
+ /* same as 101 up to here */
+
+ if(!prs_uint32("users ", ps, depth, &sv102->users))
+ return False;
+ if(!prs_uint32("disc ", ps, depth, &sv102->disc))
+ return False;
+ if(!prs_uint32("hidden ", ps, depth, &sv102->hidden))
+ return False;
+ if(!prs_uint32("announce ", ps, depth, &sv102->announce))
+ return False;
+ if(!prs_uint32("ann_delta ", ps, depth, &sv102->ann_delta))
+ return False;
+ if(!prs_uint32("licenses ", ps, depth, &sv102->licenses))
+ return False;
+ if(!prs_uint32("ptr_usr_path", ps, depth, &sv102->ptr_usr_path))
+ return False;
+
+ if(!smb_io_unistr2("uni_name ", &sv102->uni_name, True, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("uni_comment ", &sv102->uni_comment, True, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+ if(!smb_io_unistr2("uni_usr_path", &sv102->uni_usr_path, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a SRV_INFO_102 structure.
+ ********************************************************************/
+
+static BOOL srv_io_info_ctr(char *desc, SRV_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_info_ctr");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value", ps, depth, &ctr->switch_value))
+ return False;
+ if(!prs_uint32("ptr_srv_ctr ", ps, depth, &ctr->ptr_srv_ctr))
+ return False;
+
+ if (ctr->ptr_srv_ctr != 0 && ctr->switch_value != 0 && ctr != NULL) {
+ switch (ctr->switch_value) {
+ case 100:
+ if(!srv_io_info_100("sv100", &ctr->srv.sv100, ps, depth))
+ return False;
+ break;
+ case 101:
+ if(!srv_io_info_101("sv101", &ctr->srv.sv101, ps, depth))
+ return False;
+ break;
+ case 102:
+ if(!srv_io_info_102("sv102", &ctr->srv.sv102, ps, depth))
+ return False;
+ break;
+ default:
+ DEBUG(5,("%s no server info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ if(!prs_align(ps))
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_Q_NET_SRV_GET_INFO structure.
+ ********************************************************************/
+
+void init_srv_q_net_srv_get_info(SRV_Q_NET_SRV_GET_INFO *srv,
+ char *server_name, uint32 switch_value)
+{
+ DEBUG(5,("init_srv_q_net_srv_get_info\n"));
+
+ init_buf_unistr2(&srv->uni_srv_name, &srv->ptr_srv_name, server_name);
+
+ srv->switch_value = switch_value;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_srv_get_info(char *desc, SRV_Q_NET_SRV_GET_INFO *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_srv_get_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name ", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &q_n->switch_value))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_R_NET_SRV_GET_INFO structure.
+ ********************************************************************/
+
+void init_srv_r_net_srv_get_info(SRV_R_NET_SRV_GET_INFO *srv,
+ uint32 switch_value, SRV_INFO_CTR *ctr, NTSTATUS status)
+{
+ DEBUG(5,("init_srv_r_net_srv_get_info\n"));
+
+ srv->ctr = ctr;
+
+ if (NT_STATUS_IS_OK(status)) {
+ srv->ctr->switch_value = switch_value;
+ srv->ctr->ptr_srv_ctr = 1;
+ } else {
+ srv->ctr->switch_value = 0;
+ srv->ctr->ptr_srv_ctr = 0;
+ }
+
+ srv->status = status;
+}
+
+/*******************************************************************
+ Inits a SRV_R_NET_SRV_SET_INFO structure.
+ ********************************************************************/
+
+void init_srv_r_net_srv_set_info(SRV_R_NET_SRV_SET_INFO *srv,
+ uint32 switch_value, NTSTATUS status)
+{
+ DEBUG(5,("init_srv_r_net_srv_set_info\n"));
+
+ srv->switch_value = switch_value;
+ srv->status = status;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_srv_set_info(char *desc, SRV_Q_NET_SRV_SET_INFO *q_n,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "srv_io_q_net_srv_set_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name ", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &q_n->switch_value))
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ q_n->ctr = (SRV_INFO_CTR *)
+ prs_alloc_mem(ps, sizeof(SRV_INFO_CTR));
+
+ if (!q_n->ctr)
+ return False;
+ }
+
+ if(!srv_io_info_ctr("ctr", q_n->ctr, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_r_net_srv_get_info(char *desc, SRV_R_NET_SRV_GET_INFO *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_srv_get_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!srv_io_info_ctr("ctr", r_n->ctr, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_r_net_srv_set_info(char *desc, SRV_R_NET_SRV_SET_INFO *r_n,
+ prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "srv_io_r_net_srv_set_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("switch_value ", ps, depth, &r_n->switch_value))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_q_net_remote_tod(char *desc, SRV_Q_NET_REMOTE_TOD *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_remote_tod");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name ", ps, depth, &q_n->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a TIME_OF_DAY_INFO structure.
+ ********************************************************************/
+
+static BOOL srv_io_time_of_day_info(char *desc, TIME_OF_DAY_INFO *tod, prs_struct *ps, int depth)
+{
+ if (tod == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_time_of_day_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("elapsedt ", ps, depth, &tod->elapsedt))
+ return False;
+ if(!prs_uint32("msecs ", ps, depth, &tod->msecs))
+ return False;
+ if(!prs_uint32("hours ", ps, depth, &tod->hours))
+ return False;
+ if(!prs_uint32("mins ", ps, depth, &tod->mins))
+ return False;
+ if(!prs_uint32("secs ", ps, depth, &tod->secs))
+ return False;
+ if(!prs_uint32("hunds ", ps, depth, &tod->hunds))
+ return False;
+ if(!prs_uint32("timezone ", ps, depth, &tod->zone))
+ return False;
+ if(!prs_uint32("tintervals ", ps, depth, &tod->tintervals))
+ return False;
+ if(!prs_uint32("day ", ps, depth, &tod->day))
+ return False;
+ if(!prs_uint32("month ", ps, depth, &tod->month))
+ return False;
+ if(!prs_uint32("year ", ps, depth, &tod->year))
+ return False;
+ if(!prs_uint32("weekday ", ps, depth, &tod->weekday))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a TIME_OF_DAY_INFO structure.
+ ********************************************************************/
+
+void init_time_of_day_info(TIME_OF_DAY_INFO *tod, uint32 elapsedt, uint32 msecs,
+ uint32 hours, uint32 mins, uint32 secs, uint32 hunds,
+ uint32 zone, uint32 tintervals, uint32 day,
+ uint32 month, uint32 year, uint32 weekday)
+{
+ DEBUG(5,("init_time_of_day_info\n"));
+
+ tod->elapsedt = elapsedt;
+ tod->msecs = msecs;
+ tod->hours = hours;
+ tod->mins = mins;
+ tod->secs = secs;
+ tod->hunds = hunds;
+ tod->zone = zone;
+ tod->tintervals = tintervals;
+ tod->day = day;
+ tod->month = month;
+ tod->year = year;
+ tod->weekday = weekday;
+}
+
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_r_net_remote_tod(char *desc, SRV_R_NET_REMOTE_TOD *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_remote_tod");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_tod ", ps, depth, &r_n->ptr_srv_tod))
+ return False;
+
+ if(!srv_io_time_of_day_info("tod", r_n->tod, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_q_net_disk_enum(char *desc, SRV_Q_NET_DISK_ENUM *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_disk_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("level", ps, depth, &q_n->disk_enum_ctr.level))
+ return False;
+
+ if(!prs_uint32("entries_read", ps, depth, &q_n->disk_enum_ctr.entries_read))
+ return False;
+
+ if(!prs_uint32("buffer", ps, depth, &q_n->disk_enum_ctr.disk_info_ptr))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("preferred_len", ps, depth, &q_n->preferred_len))
+ return False;
+ if(!smb_io_enum_hnd("enum_hnd", &q_n->enum_hnd, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_r_net_disk_enum(char *desc, SRV_R_NET_DISK_ENUM *r_n, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_disk_enum");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("entries_read", ps, depth, &r_n->disk_enum_ctr.entries_read))
+ return False;
+ if(!prs_uint32("ptr_disk_info", ps, depth, &r_n->disk_enum_ctr.disk_info_ptr))
+ return False;
+
+ /*this may be max, unknown, actual?*/
+
+ if(!prs_uint32("max_elements", ps, depth, &r_n->disk_enum_ctr.entries_read))
+ return False;
+ if(!prs_uint32("unknown", ps, depth, &r_n->disk_enum_ctr.unknown))
+ return False;
+ if(!prs_uint32("actual_elements", ps, depth, &r_n->disk_enum_ctr.entries_read))
+ return False;
+
+ for(i=0; i < r_n->disk_enum_ctr.entries_read; i++) {
+
+ if(!prs_uint32("unknown", ps, depth, &r_n->disk_enum_ctr.disk_info[i].unknown))
+ return False;
+
+ if(!smb_io_unistr3("disk_name", &r_n->disk_enum_ctr.disk_info[i].disk_name, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+ }
+
+ if(!prs_uint32("total_entries", ps, depth, &r_n->total_entries))
+ return False;
+
+ if(!smb_io_enum_hnd("enum_hnd", &r_n->enum_hnd, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_q_net_name_validate(char *desc, SRV_Q_NET_NAME_VALIDATE *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_name_validate");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("type", ps, depth, &q_n->type))
+ return False;
+
+ if(!prs_uint32("flags", ps, depth, &q_n->flags))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+ ********************************************************************/
+
+BOOL srv_io_r_net_name_validate(char *desc, SRV_R_NET_NAME_VALIDATE *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_name_validate");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_file_query_secdesc(char *desc, SRV_Q_NET_FILE_QUERY_SECDESC *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_file_query_secdesc");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_qual_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_file_name, True, ps, depth))
+ return False;
+
+ if(!prs_uint32("unknown1", ps, depth, &q_n->unknown1))
+ return False;
+
+ if(!prs_uint32("unknown2", ps, depth, &q_n->unknown2))
+ return False;
+
+ if(!prs_uint32("unknown3", ps, depth, &q_n->unknown3))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_file_query_secdesc(char *desc, SRV_R_NET_FILE_QUERY_SECDESC *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_file_query_secdesc");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_response", ps, depth, &r_n->ptr_response))
+ return False;
+
+ if(!prs_uint32("size_response", ps, depth, &r_n->size_response))
+ return False;
+
+ if(!prs_uint32("ptr_secdesc", ps, depth, &r_n->ptr_secdesc))
+ return False;
+
+ if(!prs_uint32("size_secdesc", ps, depth, &r_n->size_secdesc))
+ return False;
+
+ if(!sec_io_desc("sec_desc", &r_n->sec_desc, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_q_net_file_set_secdesc(char *desc, SRV_Q_NET_FILE_SET_SECDESC *q_n, prs_struct *ps, int depth)
+{
+ if (q_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_file_set_secdesc");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_n->ptr_srv_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_srv_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_qual_name", ps, depth, &q_n->ptr_qual_name))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_qual_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &q_n->uni_file_name, True, ps, depth))
+ return False;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("sec_info", ps, depth, &q_n->sec_info))
+ return False;
+
+ if(!prs_uint32("size_set", ps, depth, &q_n->size_set))
+ return False;
+
+ if(!prs_uint32("ptr_secdesc", ps, depth, &q_n->ptr_secdesc))
+ return False;
+
+ if(!prs_uint32("size_secdesc", ps, depth, &q_n->size_secdesc))
+ return False;
+
+ if(!sec_io_desc("sec_desc", &q_n->sec_desc, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL srv_io_r_net_file_set_secdesc(char *desc, SRV_R_NET_FILE_SET_SECDESC *r_n, prs_struct *ps, int depth)
+{
+ if (r_n == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_file_set_secdesc");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_ntstatus("status", ps, depth, &r_n->status))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_parse/parse_wks.c b/source/rpc_parse/parse_wks.c
new file mode 100644
index 00000000000..ecd4a201ae4
--- /dev/null
+++ b/source/rpc_parse/parse_wks.c
@@ -0,0 +1,176 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ Init
+ ********************************************************************/
+
+void init_wks_q_query_info(WKS_Q_QUERY_INFO *q_u,
+ char *server, uint16 switch_value)
+{
+ DEBUG(5,("init_wks_q_query_info\n"));
+
+ init_buf_unistr2(&q_u->uni_srv_name, &q_u->ptr_srv_name, server);
+ q_u->switch_value = switch_value;
+}
+
+/*******************************************************************
+ Reads or writes a WKS_Q_QUERY_INFO structure.
+********************************************************************/
+
+BOOL wks_io_q_query_info(char *desc, WKS_Q_QUERY_INFO *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "wks_io_q_query_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_srv_name", ps, depth, &q_u->ptr_srv_name))
+ return False;
+ if(!smb_io_unistr2("", &q_u->uni_srv_name, q_u->ptr_srv_name, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &q_u->switch_value))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ wks_info_100
+ ********************************************************************/
+
+void init_wks_info_100(WKS_INFO_100 *inf,
+ uint32 platform_id, uint32 ver_major, uint32 ver_minor,
+ char *my_name, char *domain_name)
+{
+ DEBUG(5,("Init WKS_INFO_100: %d\n", __LINE__));
+
+ inf->platform_id = platform_id; /* 0x0000 01f4 - unknown */
+ inf->ver_major = ver_major; /* os major version */
+ inf->ver_minor = ver_minor; /* os minor version */
+
+ init_buf_unistr2(&inf->uni_compname, &inf->ptr_compname, my_name );
+ init_buf_unistr2(&inf->uni_lan_grp, &inf->ptr_lan_grp, domain_name);
+}
+
+/*******************************************************************
+ Reads or writes a WKS_INFO_100 structure.
+********************************************************************/
+
+static BOOL wks_io_wks_info_100(char *desc, WKS_INFO_100 *inf, prs_struct *ps, int depth)
+{
+ if (inf == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "wks_io_wks_info_100");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("platform_id ", ps, depth, &inf->platform_id)) /* 0x0000 01f4 - unknown */
+ return False;
+ if(!prs_uint32("ptr_compname", ps, depth, &inf->ptr_compname)) /* pointer to computer name */
+ return False;
+ if(!prs_uint32("ptr_lan_grp ", ps, depth, &inf->ptr_lan_grp)) /* pointer to LAN group name */
+ return False;
+ if(!prs_uint32("ver_major ", ps, depth, &inf->ver_major)) /* 4 - major os version */
+ return False;
+ if(!prs_uint32("ver_minor ", ps, depth, &inf->ver_minor)) /* 0 - minor os version */
+ return False;
+
+ if(!smb_io_unistr2("", &inf->uni_compname, inf->ptr_compname, ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_unistr2("", &inf->uni_lan_grp, inf->ptr_lan_grp , ps, depth))
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Inits WKS_R_QUERY_INFO.
+
+ only supports info level 100 at the moment.
+
+ ********************************************************************/
+
+void init_wks_r_query_info(WKS_R_QUERY_INFO *r_u,
+ uint32 switch_value, WKS_INFO_100 *wks100,
+ NTSTATUS status)
+{
+ DEBUG(5,("init_wks_r_unknown_0: %d\n", __LINE__));
+
+ r_u->switch_value = switch_value; /* same as in request */
+
+ r_u->ptr_1 = 1; /* pointer 1 */
+ r_u->wks100 = wks100;
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+ Reads or writes a structure.
+********************************************************************/
+
+BOOL wks_io_r_query_info(char *desc, WKS_R_QUERY_INFO *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "wks_io_r_query_info");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint16("switch_value", ps, depth, &r_u->switch_value)) /* level 100 (0x64) */
+ return False;
+ if(!prs_align(ps))
+ return False;
+
+ if(!prs_uint32("ptr_1 ", ps, depth, &r_u->ptr_1)) /* pointer 1 */
+ return False;
+ if(!wks_io_wks_info_100("inf", r_u->wks100, ps, depth))
+ return False;
+
+ if(!prs_ntstatus("status ", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
diff --git a/source/rpc_server/.cvsignore b/source/rpc_server/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/rpc_server/.cvsignore
diff --git a/source/rpc_server/srv_dfs.c b/source/rpc_server/srv_dfs.c
new file mode 100644
index 00000000000..00a0f58df55
--- /dev/null
+++ b/source/rpc_server/srv_dfs.c
@@ -0,0 +1,177 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines for Dfs
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Shirish Kalele 2000.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface to the dfs pipe. */
+
+#include "includes.h"
+#include "nterr.h"
+
+#define MAX_MSDFS_JUNCTIONS 256
+
+extern pstring global_myname;
+
+/**********************************************************************
+ api_dfs_exist
+ **********************************************************************/
+
+static BOOL api_dfs_exist(pipes_struct *p)
+{
+ DFS_Q_DFS_EXIST q_u;
+ DFS_R_DFS_EXIST r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ if(!dfs_io_q_dfs_exist("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _dfs_exist(p, &q_u, &r_u);
+
+ if (!dfs_io_r_dfs_exist("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*****************************************************************
+ api_dfs_add
+ *****************************************************************/
+
+static BOOL api_dfs_add(pipes_struct *p)
+{
+ DFS_Q_DFS_ADD q_u;
+ DFS_R_DFS_ADD r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!dfs_io_q_dfs_add("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _dfs_add(p, &q_u, &r_u);
+
+ if (!dfs_io_r_dfs_add("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*****************************************************************
+ api_dfs_remove
+ *****************************************************************/
+
+static BOOL api_dfs_remove(pipes_struct *p)
+{
+ DFS_Q_DFS_REMOVE q_u;
+ DFS_R_DFS_REMOVE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!dfs_io_q_dfs_remove("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _dfs_remove(p, &q_u, &r_u);
+
+ if (!dfs_io_r_dfs_remove("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_dfs_get_info
+ *******************************************************************/
+
+static BOOL api_dfs_get_info(pipes_struct *p)
+{
+ DFS_Q_DFS_GET_INFO q_u;
+ DFS_R_DFS_GET_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!dfs_io_q_dfs_get_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _dfs_get_info(p, &q_u, &r_u);
+
+ if(!dfs_io_r_dfs_get_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_dfs_enum
+ *******************************************************************/
+
+static BOOL api_dfs_enum(pipes_struct *p)
+{
+ DFS_Q_DFS_ENUM q_u;
+ DFS_R_DFS_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!dfs_io_q_dfs_enum("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _dfs_enum(p, &q_u, &r_u);
+
+ if(!dfs_io_r_dfs_enum("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+\pipe\netdfs commands
+********************************************************************/
+
+struct api_struct api_netdfs_cmds[] =
+{
+ {"DFS_EXIST", DFS_EXIST, api_dfs_exist },
+ {"DFS_ADD", DFS_ADD, api_dfs_add },
+ {"DFS_REMOVE", DFS_REMOVE, api_dfs_remove },
+ {"DFS_GET_INFO", DFS_GET_INFO, api_dfs_get_info },
+ {"DFS_ENUM", DFS_ENUM, api_dfs_enum },
+ {NULL, 0, NULL }
+};
+
+/*******************************************************************
+receives a netdfs pipe and responds.
+********************************************************************/
+
+BOOL api_netdfs_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_netdfs_rpc", api_netdfs_cmds);
+}
diff --git a/source/rpc_server/srv_dfs_nt.c b/source/rpc_server/srv_dfs_nt.c
new file mode 100644
index 00000000000..e62334c3774
--- /dev/null
+++ b/source/rpc_server/srv_dfs_nt.c
@@ -0,0 +1,367 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines for Dfs
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Shirish Kalele 2000.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the implementation of the dfs pipe. */
+
+#include "includes.h"
+#include "nterr.h"
+
+extern pstring global_myname;
+
+#define MAX_MSDFS_JUNCTIONS 256
+
+/* This function does not return a WERROR or NTSTATUS code but rather 1 if
+ dfs exists, or 0 otherwise. */
+
+uint32 _dfs_exist(pipes_struct *p, DFS_Q_DFS_EXIST *q_u, DFS_R_DFS_EXIST *r_u)
+{
+ if(lp_host_msdfs())
+ return 1;
+ else
+ return 0;
+}
+
+WERROR _dfs_add(pipes_struct *p, DFS_Q_DFS_ADD* q_u, DFS_R_DFS_ADD *r_u)
+{
+ struct current_user user;
+ struct junction_map jn;
+ struct referral* old_referral_list = NULL;
+ BOOL exists = False;
+
+ pstring dfspath, servername, sharename;
+ pstring altpath;
+
+ get_current_user(&user,p);
+
+ if (user.uid != 0) {
+ DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1);
+ unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1);
+ unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1);
+
+ DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
+ dfspath, servername, sharename));
+
+ pstrcpy(altpath, servername);
+ pstrcat(altpath, "\\");
+ pstrcat(altpath, sharename);
+
+ if(!create_junction(dfspath, &jn))
+ return WERR_DFS_NO_SUCH_SERVER;
+
+ if(get_referred_path(&jn))
+ {
+ exists = True;
+ jn.referral_count += 1;
+ old_referral_list = jn.referral_list;
+ }
+ else
+ jn.referral_count = 1;
+
+ jn.referral_list = (struct referral*) talloc(p->mem_ctx, jn.referral_count
+ * sizeof(struct referral));
+
+ if(jn.referral_list == NULL)
+ {
+ DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
+ return WERR_DFS_INTERNAL_ERROR;
+ }
+
+ if(old_referral_list)
+ {
+ memcpy(jn.referral_list, old_referral_list,
+ sizeof(struct referral)*jn.referral_count-1);
+ SAFE_FREE(old_referral_list);
+ }
+
+ jn.referral_list[jn.referral_count-1].proximity = 0;
+ jn.referral_list[jn.referral_count-1].ttl = REFERRAL_TTL;
+
+ pstrcpy(jn.referral_list[jn.referral_count-1].alternate_path, altpath);
+
+ if(!create_msdfs_link(&jn, exists))
+ return WERR_DFS_CANT_CREATE_JUNCT;
+
+ return WERR_OK;
+}
+
+WERROR _dfs_remove(pipes_struct *p, DFS_Q_DFS_REMOVE *q_u,
+ DFS_R_DFS_REMOVE *r_u)
+{
+ struct current_user user;
+ struct junction_map jn;
+ BOOL found = False;
+
+ pstring dfspath, servername, sharename;
+ pstring altpath;
+
+ get_current_user(&user,p);
+
+ if (user.uid != 0) {
+ DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ unistr2_to_ascii(dfspath, &q_u->DfsEntryPath, sizeof(dfspath)-1);
+ if(q_u->ptr_ServerName)
+ unistr2_to_ascii(servername, &q_u->ServerName, sizeof(servername)-1);
+
+ if(q_u->ptr_ShareName)
+ unistr2_to_ascii(sharename, &q_u->ShareName, sizeof(sharename)-1);
+
+ if(q_u->ptr_ServerName && q_u->ptr_ShareName)
+ {
+ pstrcpy(altpath, servername);
+ pstrcat(altpath, "\\");
+ pstrcat(altpath, sharename);
+ }
+
+ DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
+ dfspath, servername, sharename));
+
+ if(!create_junction(dfspath, &jn))
+ return WERR_DFS_NO_SUCH_SERVER;
+
+ if(!get_referred_path(&jn))
+ return WERR_DFS_NO_SUCH_VOL;
+
+ /* if no server-share pair given, remove the msdfs link completely */
+ if(!q_u->ptr_ServerName && !q_u->ptr_ShareName)
+ {
+ if(!remove_msdfs_link(&jn))
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+ else
+ {
+ int i=0;
+ /* compare each referral in the list with the one to remove */
+ for(i=0;i<jn.referral_count;i++)
+ {
+ pstring refpath;
+ pstrcpy(refpath,jn.referral_list[i].alternate_path);
+ trim_string(refpath, "\\", "\\");
+ if(strequal(refpath, altpath))
+ {
+ *(jn.referral_list[i].alternate_path)='\0';
+ found = True;
+ }
+ }
+ if(!found)
+ return WERR_DFS_NO_SUCH_SHARE;
+
+ /* Only one referral, remove it */
+ if(jn.referral_count == 1)
+ {
+ if(!remove_msdfs_link(&jn))
+ return WERR_DFS_NO_SUCH_VOL;
+ }
+ else
+ {
+ if(!create_msdfs_link(&jn, True))
+ return WERR_DFS_CANT_CREATE_JUNCT;
+ }
+ }
+
+ return WERR_OK;
+}
+
+static BOOL init_reply_dfs_info_1(struct junction_map* j, DFS_INFO_1* dfs1, int num_j)
+{
+ int i=0;
+ for(i=0;i<num_j;i++)
+ {
+ pstring str;
+ dfs1[i].ptr_entrypath = 1;
+ slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname,
+ j[i].service_name, j[i].volume_name);
+ DEBUG(5,("init_reply_dfs_info_1: %d) initing entrypath: %s\n",i,str));
+ init_unistr2(&dfs1[i].entrypath,str,strlen(str)+1);
+ }
+ return True;
+}
+
+static BOOL init_reply_dfs_info_2(struct junction_map* j, DFS_INFO_2* dfs2, int num_j)
+{
+ int i=0;
+ for(i=0;i<num_j;i++)
+ {
+ pstring str;
+ dfs2[i].ptr_entrypath = 1;
+ slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname,
+ j[i].service_name, j[i].volume_name);
+ init_unistr2(&dfs2[i].entrypath, str, strlen(str)+1);
+ dfs2[i].ptr_comment = 0;
+ dfs2[i].state = 1; /* set up state of dfs junction as OK */
+ dfs2[i].num_storages = j[i].referral_count;
+ }
+ return True;
+}
+
+static BOOL init_reply_dfs_info_3(TALLOC_CTX *ctx, struct junction_map* j, DFS_INFO_3* dfs3, int num_j)
+{
+ int i=0,ii=0;
+ for(i=0;i<num_j;i++)
+ {
+ pstring str;
+ dfs3[i].ptr_entrypath = 1;
+ slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname,
+ j[i].service_name, j[i].volume_name);
+ init_unistr2(&dfs3[i].entrypath, str, strlen(str)+1);
+ dfs3[i].ptr_comment = 1;
+ init_unistr2(&dfs3[i].comment, "", 1);
+ dfs3[i].state = 1;
+ dfs3[i].num_storages = dfs3[i].num_storage_infos = j[i].referral_count;
+ dfs3[i].ptr_storages = 1;
+
+ /* also enumerate the storages */
+ dfs3[i].storages = (DFS_STORAGE_INFO*) talloc(ctx, j[i].referral_count *
+ sizeof(DFS_STORAGE_INFO));
+ if (!dfs3[i].storages)
+ return False;
+
+ memset(dfs3[i].storages, '\0', j[i].referral_count * sizeof(DFS_STORAGE_INFO));
+
+ for(ii=0;ii<j[i].referral_count;ii++)
+ {
+ char* p;
+ pstring path;
+ DFS_STORAGE_INFO* stor = &(dfs3[i].storages[ii]);
+ struct referral* ref = &(j[i].referral_list[ii]);
+
+ pstrcpy(path, ref->alternate_path);
+ trim_string(path,"\\","");
+ p = strrchr_m(path,'\\');
+ if(p==NULL)
+ {
+ DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path));
+ continue;
+ }
+ *p = '\0';
+ DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1));
+ stor->state = 2; /* set all storages as ONLINE */
+ init_unistr2(&stor->servername, path, strlen(path)+1);
+ init_unistr2(&stor->sharename, p+1, strlen(p+1)+1);
+ stor->ptr_servername = stor->ptr_sharename = 1;
+ }
+ }
+ return True;
+}
+
+static WERROR init_reply_dfs_ctr(TALLOC_CTX *ctx, uint32 level,
+ DFS_INFO_CTR* ctr, struct junction_map* jn,
+ int num_jn)
+{
+ /* do the levels */
+ switch(level)
+ {
+ case 1:
+ {
+ DFS_INFO_1* dfs1;
+ dfs1 = (DFS_INFO_1*) talloc(ctx, num_jn * sizeof(DFS_INFO_1));
+ if (!dfs1)
+ return WERR_NOMEM;
+ init_reply_dfs_info_1(jn, dfs1, num_jn);
+ ctr->dfs.info1 = dfs1;
+ break;
+ }
+ case 2:
+ {
+ DFS_INFO_2* dfs2;
+ dfs2 = (DFS_INFO_2*) talloc(ctx, num_jn * sizeof(DFS_INFO_2));
+ if (!dfs2)
+ return WERR_NOMEM;
+ init_reply_dfs_info_2(jn, dfs2, num_jn);
+ ctr->dfs.info2 = dfs2;
+ break;
+ }
+ case 3:
+ {
+ DFS_INFO_3* dfs3;
+ dfs3 = (DFS_INFO_3*) talloc(ctx, num_jn * sizeof(DFS_INFO_3));
+ if (!dfs3)
+ return WERR_NOMEM;
+ init_reply_dfs_info_3(ctx, jn, dfs3, num_jn);
+ ctr->dfs.info3 = dfs3;
+ break;
+ }
+ default:
+ return WERR_INVALID_PARAM;
+ }
+ return WERR_OK;
+}
+
+WERROR _dfs_enum(pipes_struct *p, DFS_Q_DFS_ENUM *q_u, DFS_R_DFS_ENUM *r_u)
+{
+ uint32 level = q_u->level;
+ struct junction_map jn[MAX_MSDFS_JUNCTIONS];
+ int num_jn = 0;
+
+ num_jn = enum_msdfs_links(jn);
+
+ DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n", num_jn, level));
+
+ r_u->ptr_buffer = level;
+ r_u->level = r_u->level2 = level;
+ r_u->ptr_num_entries = r_u->ptr_num_entries2 = 1;
+ r_u->num_entries = r_u->num_entries2 = num_jn;
+ r_u->reshnd.ptr_hnd = 1;
+ r_u->reshnd.handle = num_jn;
+
+ r_u->ctr = (DFS_INFO_CTR*)talloc(p->mem_ctx, sizeof(DFS_INFO_CTR));
+ if (!r_u->ctr)
+ return WERR_NOMEM;
+ ZERO_STRUCTP(r_u->ctr);
+ r_u->ctr->switch_value = level;
+ r_u->ctr->num_entries = num_jn;
+ r_u->ctr->ptr_dfs_ctr = 1;
+
+ r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, r_u->ctr, jn, num_jn);
+
+ return r_u->status;
+}
+
+WERROR _dfs_get_info(pipes_struct *p, DFS_Q_DFS_GET_INFO *q_u,
+ DFS_R_DFS_GET_INFO *r_u)
+{
+ UNISTR2* uni_path = &q_u->uni_path;
+ uint32 level = q_u->level;
+ pstring path;
+ struct junction_map jn;
+
+ unistr2_to_ascii(path, uni_path, sizeof(path)-1);
+ if(!create_junction(path, &jn))
+ return WERR_DFS_NO_SUCH_SERVER;
+
+ if(!get_referred_path(&jn))
+ return WERR_DFS_NO_SUCH_VOL;
+
+ r_u->level = level;
+ r_u->ptr_ctr = 1;
+ r_u->status = init_reply_dfs_ctr(p->mem_ctx, level, &r_u->ctr, &jn, 1);
+
+ return r_u->status;
+}
diff --git a/source/rpc_server/srv_lsa.c b/source/rpc_server/srv_lsa.c
new file mode 100644
index 00000000000..b05fb972bef
--- /dev/null
+++ b/source/rpc_server/srv_lsa.c
@@ -0,0 +1,642 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface to the lsa server code. */
+
+#include "includes.h"
+
+/***************************************************************************
+ api_lsa_open_policy2
+ ***************************************************************************/
+
+static BOOL api_lsa_open_policy2(pipes_struct *p)
+{
+ LSA_Q_OPEN_POL2 q_u;
+ LSA_R_OPEN_POL2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the server, object attributes and desired access flag...*/
+ if(!lsa_io_q_open_pol2("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_open_policy2: unable to unmarshall LSA_Q_OPEN_POL2.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_open_policy2(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_open_pol2("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_open_policy2: unable to marshall LSA_R_OPEN_POL2.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+api_lsa_open_policy
+ ***************************************************************************/
+
+static BOOL api_lsa_open_policy(pipes_struct *p)
+{
+ LSA_Q_OPEN_POL q_u;
+ LSA_R_OPEN_POL r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the server, object attributes and desired access flag...*/
+ if(!lsa_io_q_open_pol("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_open_policy: unable to unmarshall LSA_Q_OPEN_POL.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_open_policy(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_open_pol("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_open_policy: unable to marshall LSA_R_OPEN_POL.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_enum_trust_dom
+ ***************************************************************************/
+
+static BOOL api_lsa_enum_trust_dom(pipes_struct *p)
+{
+ LSA_Q_ENUM_TRUST_DOM q_u;
+ LSA_R_ENUM_TRUST_DOM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the enum trust domain context etc. */
+ if(!lsa_io_q_enum_trust_dom("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _lsa_enum_trust_dom(p, &q_u, &r_u);
+
+ if(!lsa_io_r_enum_trust_dom("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_query_info
+ ***************************************************************************/
+
+static BOOL api_lsa_query_info(pipes_struct *p)
+{
+ LSA_Q_QUERY_INFO q_u;
+ LSA_R_QUERY_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the info class and policy handle */
+ if(!lsa_io_q_query("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_query_info: failed to unmarshall LSA_Q_QUERY_INFO.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_query_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_query("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_query_info: failed to marshall LSA_R_QUERY_INFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_lookup_sids
+ ***************************************************************************/
+
+static BOOL api_lsa_lookup_sids(pipes_struct *p)
+{
+ LSA_Q_LOOKUP_SIDS q_u;
+ LSA_R_LOOKUP_SIDS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the info class and policy handle */
+ if(!lsa_io_q_lookup_sids("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_lookup_sids: failed to unmarshall LSA_Q_LOOKUP_SIDS.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_lookup_sids(p, &q_u, &r_u);
+
+ if(!lsa_io_r_lookup_sids("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_lookup_sids: Failed to marshall LSA_R_LOOKUP_SIDS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_lookup_names
+ ***************************************************************************/
+
+static BOOL api_lsa_lookup_names(pipes_struct *p)
+{
+ LSA_Q_LOOKUP_NAMES q_u;
+ LSA_R_LOOKUP_NAMES r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the info class and policy handle */
+ if(!lsa_io_q_lookup_names("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_lookup_names: failed to unmarshall LSA_Q_LOOKUP_NAMES.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_lookup_names(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_lookup_names("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_lookup_names: Failed to marshall LSA_R_LOOKUP_NAMES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_close.
+ ***************************************************************************/
+
+static BOOL api_lsa_close(pipes_struct *p)
+{
+ LSA_Q_CLOSE q_u;
+ LSA_R_CLOSE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!lsa_io_q_close("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_close: lsa_io_q_close failed.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_close(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if (!lsa_io_r_close("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_close: lsa_io_r_close failed.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_open_secret.
+ ***************************************************************************/
+
+static BOOL api_lsa_open_secret(pipes_struct *p)
+{
+ LSA_Q_OPEN_SECRET q_u;
+ LSA_R_OPEN_SECRET r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_open_secret("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_open_secret: failed to unmarshall LSA_Q_OPEN_SECRET.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_open_secret(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_open_secret("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_open_secret: Failed to marshall LSA_R_OPEN_SECRET.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_open_secret.
+ ***************************************************************************/
+
+static BOOL api_lsa_enum_privs(pipes_struct *p)
+{
+ LSA_Q_ENUM_PRIVS q_u;
+ LSA_R_ENUM_PRIVS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_enum_privs("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_enum_privs: failed to unmarshall LSA_Q_ENUM_PRIVS.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_enum_privs(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_enum_privs("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_enum_privs: Failed to marshall LSA_R_ENUM_PRIVS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_open_secret.
+ ***************************************************************************/
+
+static BOOL api_lsa_priv_get_dispname(pipes_struct *p)
+{
+ LSA_Q_PRIV_GET_DISPNAME q_u;
+ LSA_R_PRIV_GET_DISPNAME r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_priv_get_dispname("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_priv_get_dispname: failed to unmarshall LSA_Q_PRIV_GET_DISPNAME.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_priv_get_dispname(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_priv_get_dispname("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_priv_get_dispname: Failed to marshall LSA_R_PRIV_GET_DISPNAME.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_open_secret.
+ ***************************************************************************/
+
+static BOOL api_lsa_enum_accounts(pipes_struct *p)
+{
+ LSA_Q_ENUM_ACCOUNTS q_u;
+ LSA_R_ENUM_ACCOUNTS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_enum_accounts("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_enum_accounts: failed to unmarshall LSA_Q_ENUM_ACCOUNTS.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_enum_accounts(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_enum_accounts("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_enum_accounts: Failed to marshall LSA_R_ENUM_ACCOUNTS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_UNK_GET_CONNUSER
+ ***************************************************************************/
+
+static BOOL api_lsa_unk_get_connuser(pipes_struct *p)
+{
+ LSA_Q_UNK_GET_CONNUSER q_u;
+ LSA_R_UNK_GET_CONNUSER r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_unk_get_connuser("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_unk_get_connuser: failed to unmarshall LSA_Q_UNK_GET_CONNUSER.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_unk_get_connuser(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_unk_get_connuser("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_unk_get_connuser: Failed to marshall LSA_R_UNK_GET_CONNUSER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_open_user
+ ***************************************************************************/
+
+static BOOL api_lsa_open_account(pipes_struct *p)
+{
+ LSA_Q_OPENACCOUNT q_u;
+ LSA_R_OPENACCOUNT r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_open_account("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_open_account: failed to unmarshall LSA_Q_OPENACCOUNT.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_open_account(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_open_account("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_open_account: Failed to marshall LSA_R_OPENACCOUNT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_get_privs
+ ***************************************************************************/
+
+static BOOL api_lsa_enum_privsaccount(pipes_struct *p)
+{
+ LSA_Q_ENUMPRIVSACCOUNT q_u;
+ LSA_R_ENUMPRIVSACCOUNT r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_enum_privsaccount("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_enum_privsaccount: failed to unmarshall LSA_Q_ENUMPRIVSACCOUNT.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_enum_privsaccount(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_enum_privsaccount("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_enum_privsaccount: Failed to marshall LSA_R_ENUMPRIVSACCOUNT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_getsystemaccount
+ ***************************************************************************/
+
+static BOOL api_lsa_getsystemaccount(pipes_struct *p)
+{
+ LSA_Q_GETSYSTEMACCOUNT q_u;
+ LSA_R_GETSYSTEMACCOUNT r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_getsystemaccount("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_getsystemaccount: failed to unmarshall LSA_Q_GETSYSTEMACCOUNT.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_getsystemaccount(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_getsystemaccount("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_getsystemaccount: Failed to marshall LSA_R_GETSYSTEMACCOUNT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/***************************************************************************
+ api_lsa_setsystemaccount
+ ***************************************************************************/
+
+static BOOL api_lsa_setsystemaccount(pipes_struct *p)
+{
+ LSA_Q_SETSYSTEMACCOUNT q_u;
+ LSA_R_SETSYSTEMACCOUNT r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_setsystemaccount("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_setsystemaccount: failed to unmarshall LSA_Q_SETSYSTEMACCOUNT.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_setsystemaccount(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_setsystemaccount("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_setsystemaccount: Failed to marshall LSA_R_SETSYSTEMACCOUNT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_addprivs
+ ***************************************************************************/
+
+static BOOL api_lsa_addprivs(pipes_struct *p)
+{
+ LSA_Q_ADDPRIVS q_u;
+ LSA_R_ADDPRIVS r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_addprivs("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_addprivs: failed to unmarshall LSA_Q_ADDPRIVS.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_addprivs(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_addprivs("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_addprivs: Failed to marshall LSA_R_ADDPRIVS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_removeprivs
+ ***************************************************************************/
+
+static BOOL api_lsa_removeprivs(pipes_struct *p)
+{
+ LSA_Q_REMOVEPRIVS q_u;
+ LSA_R_REMOVEPRIVS r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_removeprivs("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_removeprivs: failed to unmarshall LSA_Q_REMOVEPRIVS.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_removeprivs(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_removeprivs("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_removeprivs: Failed to marshall LSA_R_REMOVEPRIVS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ api_lsa_query_secobj
+ ***************************************************************************/
+
+static BOOL api_lsa_query_secobj(pipes_struct *p)
+{
+ LSA_Q_QUERY_SEC_OBJ q_u;
+ LSA_R_QUERY_SEC_OBJ r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!lsa_io_q_query_sec_obj("", &q_u, data, 0)) {
+ DEBUG(0,("api_lsa_query_secobj: failed to unmarshall LSA_Q_QUERY_SEC_OBJ.\n"));
+ return False;
+ }
+
+ r_u.status = _lsa_query_secobj(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!lsa_io_r_query_sec_obj("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_lsa_query_secobj: Failed to marshall LSA_R_QUERY_SEC_OBJ.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ \PIPE\ntlsa commands
+ ***************************************************************************/
+
+static struct api_struct api_lsa_cmds[] =
+{
+ { "LSA_OPENPOLICY2" , LSA_OPENPOLICY2 , api_lsa_open_policy2 },
+ { "LSA_OPENPOLICY" , LSA_OPENPOLICY , api_lsa_open_policy },
+ { "LSA_QUERYINFOPOLICY" , LSA_QUERYINFOPOLICY , api_lsa_query_info },
+ { "LSA_ENUMTRUSTDOM" , LSA_ENUMTRUSTDOM , api_lsa_enum_trust_dom },
+ { "LSA_CLOSE" , LSA_CLOSE , api_lsa_close },
+ { "LSA_OPENSECRET" , LSA_OPENSECRET , api_lsa_open_secret },
+ { "LSA_LOOKUPSIDS" , LSA_LOOKUPSIDS , api_lsa_lookup_sids },
+ { "LSA_LOOKUPNAMES" , LSA_LOOKUPNAMES , api_lsa_lookup_names },
+ { "LSA_ENUM_PRIVS" , LSA_ENUM_PRIVS , api_lsa_enum_privs },
+ { "LSA_PRIV_GET_DISPNAME",LSA_PRIV_GET_DISPNAME,api_lsa_priv_get_dispname},
+ { "LSA_ENUM_ACCOUNTS" , LSA_ENUM_ACCOUNTS , api_lsa_enum_accounts },
+ { "LSA_UNK_GET_CONNUSER", LSA_UNK_GET_CONNUSER, api_lsa_unk_get_connuser },
+ { "LSA_OPENACCOUNT" , LSA_OPENACCOUNT , api_lsa_open_account },
+ { "LSA_ENUMPRIVSACCOUNT", LSA_ENUMPRIVSACCOUNT, api_lsa_enum_privsaccount},
+ { "LSA_GETSYSTEMACCOUNT", LSA_GETSYSTEMACCOUNT, api_lsa_getsystemaccount },
+ { "LSA_SETSYSTEMACCOUNT", LSA_SETSYSTEMACCOUNT, api_lsa_setsystemaccount },
+ { "LSA_ADDPRIVS" , LSA_ADDPRIVS , api_lsa_addprivs },
+ { "LSA_REMOVEPRIVS" , LSA_REMOVEPRIVS , api_lsa_removeprivs },
+ { "LSA_QUERYSECOBJ" , LSA_QUERYSECOBJ , api_lsa_query_secobj },
+ { NULL , 0 , NULL }
+};
+
+/***************************************************************************
+ api_ntLsarpcTNP
+ ***************************************************************************/
+BOOL api_ntlsa_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_ntlsa_rpc", api_lsa_cmds);
+}
diff --git a/source/rpc_server/srv_lsa_hnd.c b/source/rpc_server/srv_lsa_hnd.c
new file mode 100644
index 00000000000..d5f9a52e2fe
--- /dev/null
+++ b/source/rpc_server/srv_lsa_hnd.c
@@ -0,0 +1,221 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/* This is the max handles across all instances of a pipe name. */
+#ifndef MAX_OPEN_POLS
+#define MAX_OPEN_POLS 1024
+#endif
+
+/****************************************************************************
+ Initialise a policy handle list on a pipe. Handle list is shared between all
+ pipes of the same name.
+****************************************************************************/
+
+BOOL init_pipe_handle_list(pipes_struct *p, char *pipe_name)
+{
+ pipes_struct *plist = get_first_pipe();
+ struct handle_list *hl = NULL;
+
+ for (plist = get_first_pipe(); plist; plist = get_next_pipe(plist)) {
+ if (strequal( plist->name, pipe_name)) {
+ if (!plist->pipe_handles) {
+ pstring msg;
+ slprintf(msg, sizeof(msg)-1, "init_pipe_handles: NULL pipe_handle pointer in pipe %s",
+ pipe_name );
+ smb_panic(msg);
+ }
+ hl = plist->pipe_handles;
+ break;
+ }
+ }
+
+ if (!hl) {
+ /*
+ * No handle list for this pipe (first open of pipe).
+ * Create list.
+ */
+
+ if ((hl = (struct handle_list *)malloc(sizeof(struct handle_list))) == NULL)
+ return False;
+ ZERO_STRUCTP(hl);
+
+ DEBUG(10,("init_pipe_handles: created handle list for pipe %s\n", pipe_name ));
+ }
+
+ /*
+ * One more pipe is using this list.
+ */
+
+ hl->pipe_ref_count++;
+
+ /*
+ * Point this pipe at this list.
+ */
+
+ p->pipe_handles = hl;
+
+ DEBUG(10,("init_pipe_handles: pipe_handles ref count = %u for pipe %s\n",
+ p->pipe_handles->pipe_ref_count, pipe_name ));
+
+ return True;
+}
+
+/****************************************************************************
+ find first available policy slot. creates a policy handle for you.
+****************************************************************************/
+
+BOOL create_policy_hnd(pipes_struct *p, POLICY_HND *hnd, void (*free_fn)(void *), void *data_ptr)
+{
+ static uint32 pol_hnd_low = 0;
+ static uint32 pol_hnd_high = 0;
+
+ struct policy *pol;
+
+ if (p->pipe_handles->count > MAX_OPEN_POLS) {
+ DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
+ (int)p->pipe_handles->count));
+ return False;
+ }
+
+ pol = (struct policy *)malloc(sizeof(*p));
+ if (!pol) {
+ DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pol);
+
+ pol->data_ptr = data_ptr;
+ pol->free_fn = free_fn;
+
+ pol_hnd_low++;
+ if (pol_hnd_low == 0) (pol_hnd_high)++;
+
+ SIVAL(&pol->pol_hnd.data1, 0 , 0); /* first bit must be null */
+ SIVAL(&pol->pol_hnd.data2, 0 , pol_hnd_low ); /* second bit is incrementing */
+ SSVAL(&pol->pol_hnd.data3, 0 , pol_hnd_high); /* second bit is incrementing */
+ SSVAL(&pol->pol_hnd.data4, 0 , (pol_hnd_high>>16)); /* second bit is incrementing */
+ SIVAL(pol->pol_hnd.data5, 0, time(NULL)); /* something random */
+ SIVAL(pol->pol_hnd.data5, 4, sys_getpid()); /* something more random */
+
+ DLIST_ADD(p->pipe_handles->Policy, pol);
+ p->pipe_handles->count++;
+
+ *hnd = pol->pol_hnd;
+
+ DEBUG(4,("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
+ dump_data(4, (char *)hnd, sizeof(*hnd));
+
+ return True;
+}
+
+/****************************************************************************
+ find policy by handle - internal version.
+****************************************************************************/
+
+static struct policy *find_policy_by_hnd_internal(pipes_struct *p, POLICY_HND *hnd, void **data_p)
+{
+ struct policy *pol;
+ size_t i;
+
+ if (data_p)
+ *data_p = NULL;
+
+ for (i = 0, pol=p->pipe_handles->Policy;pol;pol=pol->next, i++) {
+ if (memcmp(&pol->pol_hnd, hnd, sizeof(*hnd)) == 0) {
+ DEBUG(4,("Found policy hnd[%d] ", (int)i));
+ dump_data(4, (char *)hnd, sizeof(*hnd));
+ if (data_p)
+ *data_p = pol->data_ptr;
+ return pol;
+ }
+ }
+
+ DEBUG(4,("Policy not found: "));
+ dump_data(4, (char *)hnd, sizeof(*hnd));
+
+ return NULL;
+}
+
+/****************************************************************************
+ find policy by handle
+****************************************************************************/
+
+BOOL find_policy_by_hnd(pipes_struct *p, POLICY_HND *hnd, void **data_p)
+{
+ return find_policy_by_hnd_internal(p, hnd, data_p) == NULL ? False : True;
+}
+
+/****************************************************************************
+ Close a policy.
+****************************************************************************/
+
+BOOL close_policy_hnd(pipes_struct *p, POLICY_HND *hnd)
+{
+ struct policy *pol = find_policy_by_hnd_internal(p, hnd, NULL);
+
+ if (!pol) {
+ DEBUG(3,("Error closing policy\n"));
+ return False;
+ }
+
+ DEBUG(3,("Closed policy\n"));
+
+ if (pol->free_fn && pol->data_ptr)
+ (*pol->free_fn)(pol->data_ptr);
+
+ p->pipe_handles->count--;
+
+ DLIST_REMOVE(p->pipe_handles->Policy, pol);
+
+ ZERO_STRUCTP(pol);
+
+ SAFE_FREE(pol);
+
+ return True;
+}
+
+/****************************************************************************
+ Close a pipe - free the handle list if it was the last pipe reference.
+****************************************************************************/
+
+void close_policy_by_pipe(pipes_struct *p)
+{
+ p->pipe_handles->pipe_ref_count--;
+
+ if (p->pipe_handles->pipe_ref_count == 0) {
+ /*
+ * Last pipe open on this list - free the list.
+ */
+ while (p->pipe_handles->Policy)
+ close_policy_hnd(p, &p->pipe_handles->Policy->pol_hnd);
+
+ p->pipe_handles->Policy = NULL;
+ p->pipe_handles->count = 0;
+
+ SAFE_FREE(p->pipe_handles);
+ DEBUG(10,("close_policy_by_pipe: deleted handle list for pipe %s\n", p->name ));
+ }
+}
diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c
new file mode 100644
index 00000000000..432f20a40c9
--- /dev/null
+++ b/source/rpc_server/srv_lsa_nt.c
@@ -0,0 +1,1127 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the implementation of the lsa server code. */
+
+#include "includes.h"
+
+extern DOM_SID global_sam_sid;
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+extern PRIVS privs[];
+
+struct lsa_info {
+ DOM_SID sid;
+ uint32 access;
+};
+
+struct generic_mapping lsa_generic_mapping = {
+ POLICY_READ,
+ POLICY_WRITE,
+ POLICY_EXECUTE,
+ POLICY_ALL_ACCESS
+};
+
+/*******************************************************************
+ Function to free the per handle data.
+ ********************************************************************/
+
+static void free_lsa_info(void *ptr)
+{
+ struct lsa_info *lsa = (struct lsa_info *)ptr;
+
+ SAFE_FREE(lsa);
+}
+
+/***************************************************************************
+Init dom_query
+ ***************************************************************************/
+
+static void init_dom_query(DOM_QUERY *d_q, char *dom_name, DOM_SID *dom_sid)
+{
+ int domlen = (dom_name != NULL) ? strlen(dom_name) : 0;
+
+ /*
+ * I'm not sure why this really odd combination of length
+ * values works, but it does appear to. I need to look at
+ * this *much* more closely - but at the moment leave alone
+ * until it's understood. This allows a W2k client to join
+ * a domain with both odd and even length names... JRA.
+ */
+
+ d_q->uni_dom_str_len = domlen ? ((domlen + 1) * 2) : 0;
+ d_q->uni_dom_max_len = domlen * 2;
+ d_q->buffer_dom_name = domlen != 0 ? 1 : 0; /* domain buffer pointer */
+ d_q->buffer_dom_sid = dom_sid != NULL ? 1 : 0; /* domain sid pointer */
+
+ /* this string is supposed to be character short */
+ init_unistr2(&d_q->uni_domain_name, dom_name, domlen);
+ d_q->uni_domain_name.uni_max_len++;
+
+ if (dom_sid != NULL)
+ init_dom_sid2(&d_q->dom_sid, dom_sid);
+}
+
+/***************************************************************************
+ init_dom_ref - adds a domain if it's not already in, returns the index.
+***************************************************************************/
+
+static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid)
+{
+ int num = 0;
+ int len;
+
+ if (dom_name != NULL) {
+ for (num = 0; num < ref->num_ref_doms_1; num++) {
+ fstring domname;
+ rpcstr_pull(domname, &ref->ref_dom[num].uni_dom_name, sizeof(domname), -1, 0);
+ if (strequal(domname, dom_name))
+ return num;
+ }
+ } else {
+ num = ref->num_ref_doms_1;
+ }
+
+ if (num >= MAX_REF_DOMAINS) {
+ /* index not found, already at maximum domain limit */
+ return -1;
+ }
+
+ ref->num_ref_doms_1 = num+1;
+ ref->ptr_ref_dom = 1;
+ ref->max_entries = MAX_REF_DOMAINS;
+ ref->num_ref_doms_2 = num+1;
+
+ len = (dom_name != NULL) ? strlen(dom_name) : 0;
+ if(dom_name != NULL && len == 0)
+ len = 1;
+
+ init_uni_hdr(&ref->hdr_ref_dom[num].hdr_dom_name, len);
+ ref->hdr_ref_dom[num].ptr_dom_sid = dom_sid != NULL ? 1 : 0;
+
+ init_unistr2(&ref->ref_dom[num].uni_dom_name, dom_name, len);
+ init_dom_sid2(&ref->ref_dom[num].ref_dom, dom_sid );
+
+ return num;
+}
+
+/***************************************************************************
+ init_lsa_rid2s
+ ***************************************************************************/
+
+static void init_lsa_rid2s(DOM_R_REF *ref, DOM_RID2 *rid2,
+ int num_entries, UNISTR2 *name,
+ uint32 *mapped_count, BOOL endian)
+{
+ int i;
+ int total = 0;
+ *mapped_count = 0;
+
+ SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS);
+
+ for (i = 0; i < num_entries; i++) {
+ BOOL status = False;
+ DOM_SID sid;
+ uint32 rid = 0xffffffff;
+ int dom_idx = -1;
+ pstring full_name;
+ fstring dom_name, user;
+ enum SID_NAME_USE name_type = SID_NAME_UNKNOWN;
+
+ /* Split name into domain and user component */
+
+ unistr2_to_ascii(full_name, &name[i], sizeof(full_name));
+ split_domain_name(full_name, dom_name, user);
+
+ /* Lookup name */
+
+ DEBUG(5, ("init_lsa_rid2s: looking up name %s\n", full_name));
+
+ status = lookup_name(full_name, &sid, &name_type);
+
+ DEBUG(5, ("init_lsa_rid2s: %s\n", status ? "found" :
+ "not found"));
+
+ if (status) {
+ sid_split_rid(&sid, &rid);
+ dom_idx = init_dom_ref(ref, dom_name, &sid);
+ (*mapped_count)++;
+ } else {
+ dom_idx = -1;
+ rid = 0xffffffff;
+ name_type = SID_NAME_UNKNOWN;
+ }
+
+ init_dom_rid2(&rid2[total], rid, name_type, dom_idx);
+ total++;
+ }
+}
+
+/***************************************************************************
+ init_reply_lookup_names
+ ***************************************************************************/
+
+static void init_reply_lookup_names(LSA_R_LOOKUP_NAMES *r_l,
+ DOM_R_REF *ref, uint32 num_entries,
+ DOM_RID2 *rid2, uint32 mapped_count)
+{
+ r_l->ptr_dom_ref = 1;
+ r_l->dom_ref = ref;
+
+ r_l->num_entries = num_entries;
+ r_l->ptr_entries = 1;
+ r_l->num_entries2 = num_entries;
+ r_l->dom_rid = rid2;
+
+ r_l->mapped_count = mapped_count;
+
+ if (mapped_count == 0)
+ r_l->status = NT_STATUS_NONE_MAPPED;
+ else
+ r_l->status = NT_STATUS_OK;
+}
+
+/***************************************************************************
+ Init lsa_trans_names.
+ ***************************************************************************/
+
+static void init_lsa_trans_names(TALLOC_CTX *ctx, DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *trn,
+ int num_entries, DOM_SID2 *sid,
+ uint32 *mapped_count)
+{
+ int i;
+ int total = 0;
+ *mapped_count = 0;
+
+ /* Allocate memory for list of names */
+
+ if (num_entries > 0) {
+ if (!(trn->name = (LSA_TRANS_NAME *)talloc(ctx, sizeof(LSA_TRANS_NAME) *
+ num_entries))) {
+ DEBUG(0, ("init_lsa_trans_names(): out of memory\n"));
+ return;
+ }
+
+ if (!(trn->uni_name = (UNISTR2 *)talloc(ctx, sizeof(UNISTR2) *
+ num_entries))) {
+ DEBUG(0, ("init_lsa_trans_names(): out of memory\n"));
+ return;
+ }
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ BOOL status = False;
+ DOM_SID find_sid = sid[i].sid;
+ uint32 rid = 0xffffffff;
+ int dom_idx = -1;
+ fstring name, dom_name;
+ enum SID_NAME_USE sid_name_use = (enum SID_NAME_USE)0;
+
+ sid_to_string(name, &find_sid);
+ DEBUG(5, ("init_lsa_trans_names: looking up sid %s\n", name));
+
+ /* Lookup sid from winbindd */
+
+ memset(dom_name, '\0', sizeof(dom_name));
+ memset(name, '\0', sizeof(name));
+
+ status = lookup_sid(&find_sid, dom_name, name, &sid_name_use);
+
+ DEBUG(5, ("init_lsa_trans_names: %s\n", status ? "found" :
+ "not found"));
+
+ if (!status) {
+ sid_name_use = SID_NAME_UNKNOWN;
+ }
+
+ /* Store domain sid in ref array */
+
+ if (find_sid.num_auths == 5) {
+ sid_split_rid(&find_sid, &rid);
+ }
+
+ dom_idx = init_dom_ref(ref, dom_name, &find_sid);
+
+ DEBUG(10,("init_lsa_trans_names: added user '%s\\%s' to "
+ "referenced list.\n", dom_name, name ));
+
+ (*mapped_count)++;
+
+ init_lsa_trans_name(&trn->name[total], &trn->uni_name[total],
+ sid_name_use, name, dom_idx);
+ total++;
+ }
+
+ trn->num_entries = total;
+ trn->ptr_trans_names = 1;
+ trn->num_entries2 = total;
+}
+
+/***************************************************************************
+ Init_reply_lookup_sids.
+ ***************************************************************************/
+
+static void init_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
+ DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *names,
+ uint32 mapped_count)
+{
+ r_l->ptr_dom_ref = 1;
+ r_l->dom_ref = ref;
+ r_l->names = names;
+ r_l->mapped_count = mapped_count;
+
+ if (mapped_count == 0)
+ r_l->status = NT_STATUS_NONE_MAPPED;
+ else
+ r_l->status = NT_STATUS_OK;
+}
+
+static NTSTATUS lsa_get_generic_sd(TALLOC_CTX *mem_ctx, SEC_DESC **sd, size_t *sd_size)
+{
+ extern DOM_SID global_sid_World;
+ extern DOM_SID global_sid_Builtin;
+ DOM_SID local_adm_sid;
+ DOM_SID adm_sid;
+
+ SEC_ACE ace[3];
+ SEC_ACCESS mask;
+
+ SEC_ACL *psa = NULL;
+
+ init_sec_access(&mask, POLICY_EXECUTE);
+ init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ sid_copy(&adm_sid, &global_sam_sid);
+ sid_append_rid(&adm_sid, DOMAIN_GROUP_RID_ADMINS);
+ init_sec_access(&mask, POLICY_ALL_ACCESS);
+ init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ sid_copy(&local_adm_sid, &global_sid_Builtin);
+ sid_append_rid(&local_adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+ init_sec_access(&mask, POLICY_ALL_ACCESS);
+ init_sec_ace(&ace[2], &local_adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ if((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if((*sd = make_sec_desc(mem_ctx, SEC_DESC_REVISION, &adm_sid, NULL, NULL, psa, sd_size)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_open_policy2.
+ ***************************************************************************/
+
+NTSTATUS _lsa_open_policy2(pipes_struct *p, LSA_Q_OPEN_POL2 *q_u, LSA_R_OPEN_POL2 *r_u)
+{
+ struct lsa_info *info;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ uint32 des_access=q_u->des_access;
+ uint32 acc_granted;
+ NTSTATUS status;
+
+
+ /* map the generic bits to the lsa policy ones */
+ se_map_generic(&des_access, &lsa_generic_mapping);
+
+ /* get the generic lsa policy SD until we store it */
+ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+
+ if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status))
+ return status;
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = global_sam_sid;
+ info->access = acc_granted;
+
+ /* set up the LSA QUERY INFO response */
+ if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_open_policy
+ ***************************************************************************/
+
+NTSTATUS _lsa_open_policy(pipes_struct *p, LSA_Q_OPEN_POL *q_u, LSA_R_OPEN_POL *r_u)
+{
+ struct lsa_info *info;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ uint32 des_access=q_u->des_access;
+ uint32 acc_granted;
+ NTSTATUS status;
+
+
+ /* map the generic bits to the lsa policy ones */
+ se_map_generic(&des_access, &lsa_generic_mapping);
+
+ /* get the generic lsa policy SD until we store it */
+ lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+
+ if(!se_access_check(psd, p->pipe_user.nt_user_token, des_access, &acc_granted, &status))
+ return status;
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = global_sam_sid;
+ info->access = acc_granted;
+
+ /* set up the LSA QUERY INFO response */
+ if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ _lsa_enum_trust_dom - this needs fixing to do more than return NULL ! JRA.
+ ***************************************************************************/
+
+NTSTATUS _lsa_enum_trust_dom(pipes_struct *p, LSA_Q_ENUM_TRUST_DOM *q_u, LSA_R_ENUM_TRUST_DOM *r_u)
+{
+ struct lsa_info *info;
+ uint32 enum_context = 0;
+ char *dom_name = NULL;
+ DOM_SID *dom_sid = NULL;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+ if (!(info->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* set up the LSA QUERY INFO response */
+ init_r_enum_trust_dom(p->mem_ctx, r_u, enum_context, dom_name, dom_sid,
+ dom_name != NULL ? NT_STATUS_OK : NT_STATUS_NO_MORE_ENTRIES);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ _lsa_query_info. See the POLICY_INFOMATION_CLASS docs at msdn.
+ ***************************************************************************/
+
+NTSTATUS _lsa_query_info(pipes_struct *p, LSA_Q_QUERY_INFO *q_u, LSA_R_QUERY_INFO *r_u)
+{
+ extern DOM_SID global_sid_nonexistent;
+ struct lsa_info *handle;
+ LSA_INFO_UNION *info = &r_u->dom;
+ DOM_SID domain_sid;
+ char *name = NULL;
+ DOM_SID *sid = NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ switch (q_u->info_class) {
+ case 0x02:
+ {
+ unsigned int i;
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_VIEW_AUDIT_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* fake info: We audit everything. ;) */
+ info->id2.auditing_enabled = 1;
+ info->id2.count1 = 7;
+ info->id2.count2 = 7;
+ if ((info->id2.auditsettings = (uint32 *)talloc(p->mem_ctx,7*sizeof(uint32))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ for (i = 0; i < 7; i++)
+ info->id2.auditsettings[i] = 3;
+ break;
+ }
+ case 0x03:
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Request PolicyPrimaryDomainInformation. */
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ name = global_myworkgroup;
+ sid = &global_sam_sid;
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ name = global_myworkgroup;
+ /* We need to return the Domain SID here. */
+ if (secrets_fetch_domain_sid(global_myworkgroup,
+ &domain_sid))
+ sid = &domain_sid;
+ else
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ break;
+ case ROLE_STANDALONE:
+ name = global_myworkgroup;
+ sid = &global_sid_nonexistent;
+ break;
+ default:
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ init_dom_query(&r_u->dom.id3, name, sid);
+ break;
+ case 0x05:
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Request PolicyAccountDomainInformation. */
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ name = global_myworkgroup;
+ sid = &global_sam_sid;
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ name = global_myname;
+ sid = &global_sam_sid;
+ break;
+ case ROLE_STANDALONE:
+ name = global_myname;
+ sid = &global_sam_sid;
+ break;
+ default:
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+ init_dom_query(&r_u->dom.id5, name, sid);
+ break;
+ case 0x06:
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_BDC:
+ /*
+ * only a BDC is a backup controller
+ * of the domain, it controls.
+ */
+ info->id6.server_role = 2;
+ break;
+ default:
+ /*
+ * any other role is a primary
+ * of the domain, it controls.
+ */
+ info->id6.server_role = 3;
+ break;
+ }
+ break;
+ default:
+ DEBUG(0,("_lsa_query_info: unknown info level in Lsa Query: %d\n", q_u->info_class));
+ r_u->status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ if (NT_STATUS_IS_OK(r_u->status)) {
+ r_u->undoc_buffer = 0x22000000; /* bizarre */
+ r_u->info_class = q_u->info_class;
+ }
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ _lsa_lookup_sids
+ ***************************************************************************/
+
+NTSTATUS _lsa_lookup_sids(pipes_struct *p, LSA_Q_LOOKUP_SIDS *q_u, LSA_R_LOOKUP_SIDS *r_u)
+{
+ struct lsa_info *handle;
+ DOM_SID2 *sid = q_u->sids.sid;
+ int num_entries = q_u->sids.num_entries;
+ DOM_R_REF *ref = NULL;
+ LSA_TRANS_NAME_ENUM *names = NULL;
+ uint32 mapped_count = 0;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_LOOKUP_NAMES))
+ return NT_STATUS_ACCESS_DENIED;
+
+ ref = (DOM_R_REF *)talloc_zero(p->mem_ctx, sizeof(DOM_R_REF));
+ names = (LSA_TRANS_NAME_ENUM *)talloc_zero(p->mem_ctx, sizeof(LSA_TRANS_NAME_ENUM));
+
+ if (!ref || !names)
+ return NT_STATUS_NO_MEMORY;
+
+ /* set up the LSA Lookup SIDs response */
+ init_lsa_trans_names(p->mem_ctx, ref, names, num_entries, sid, &mapped_count);
+ init_reply_lookup_sids(r_u, ref, names, mapped_count);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+lsa_reply_lookup_names
+ ***************************************************************************/
+
+NTSTATUS _lsa_lookup_names(pipes_struct *p,LSA_Q_LOOKUP_NAMES *q_u, LSA_R_LOOKUP_NAMES *r_u)
+{
+ struct lsa_info *handle;
+ UNISTR2 *names = q_u->uni_name;
+ int num_entries = q_u->num_entries;
+ DOM_R_REF *ref;
+ DOM_RID2 *rids;
+ uint32 mapped_count = 0;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_LOOKUP_NAMES))
+ return NT_STATUS_ACCESS_DENIED;
+
+ ref = (DOM_R_REF *)talloc_zero(p->mem_ctx, sizeof(DOM_R_REF));
+ rids = (DOM_RID2 *)talloc_zero(p->mem_ctx, sizeof(DOM_RID2)*MAX_LOOKUP_SIDS);
+
+ if (!ref || !rids)
+ return NT_STATUS_NO_MEMORY;
+
+ /* set up the LSA Lookup RIDs response */
+ init_lsa_rid2s(ref, rids, num_entries, names, &mapped_count, p->endian);
+ init_reply_lookup_names(r_u, ref, num_entries, rids, mapped_count);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ _lsa_close. Also weird - needs to check if lsa handle is correct. JRA.
+ ***************************************************************************/
+
+NTSTATUS _lsa_close(pipes_struct *p, LSA_Q_CLOSE *q_u, LSA_R_CLOSE *r_u)
+{
+ if (!find_policy_by_hnd(p, &q_u->pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ close_policy_hnd(p, &q_u->pol);
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+ "No more secrets Marty...." :-).
+ ***************************************************************************/
+
+NTSTATUS _lsa_open_secret(pipes_struct *p, LSA_Q_OPEN_SECRET *q_u, LSA_R_OPEN_SECRET *r_u)
+{
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/***************************************************************************
+_lsa_enum_privs.
+ ***************************************************************************/
+
+NTSTATUS _lsa_enum_privs(pipes_struct *p, LSA_Q_ENUM_PRIVS *q_u, LSA_R_ENUM_PRIVS *r_u)
+{
+ struct lsa_info *handle;
+ uint32 i;
+
+ uint32 enum_context=q_u->enum_context;
+ LSA_PRIV_ENTRY *entry;
+ LSA_PRIV_ENTRY *entries=NULL;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (enum_context >= PRIV_ALL_INDEX)
+ return NT_STATUS_NO_MORE_ENTRIES;
+
+ entries = (LSA_PRIV_ENTRY *)talloc_zero(p->mem_ctx, sizeof(LSA_PRIV_ENTRY) * (PRIV_ALL_INDEX));
+ if (entries==NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ entry = entries;
+
+ DEBUG(10,("_lsa_enum_privs: enum_context:%d total entries:%d\n", enum_context, PRIV_ALL_INDEX));
+
+ for (i = 0; i < PRIV_ALL_INDEX; i++, entry++) {
+ if( i<enum_context) {
+ init_uni_hdr(&entry->hdr_name, 0);
+ init_unistr2(&entry->name, NULL, 0 );
+ entry->luid_low = 0;
+ entry->luid_high = 0;
+ } else {
+ init_uni_hdr(&entry->hdr_name, strlen(privs[i+1].priv));
+ init_unistr2(&entry->name, privs[i+1].priv, strlen(privs[i+1].priv) );
+ entry->luid_low = privs[i+1].se_priv;
+ entry->luid_high = 0;
+ }
+ }
+
+ enum_context = PRIV_ALL_INDEX;
+ init_lsa_r_enum_privs(r_u, enum_context, PRIV_ALL_INDEX, entries);
+
+ return NT_STATUS_OK;
+}
+
+/***************************************************************************
+_lsa_priv_get_dispname.
+ ***************************************************************************/
+
+NTSTATUS _lsa_priv_get_dispname(pipes_struct *p, LSA_Q_PRIV_GET_DISPNAME *q_u, LSA_R_PRIV_GET_DISPNAME *r_u)
+{
+ struct lsa_info *handle;
+ fstring name_asc;
+ int i=1;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ unistr2_to_ascii(name_asc, &q_u->name, sizeof(name_asc));
+
+ DEBUG(10,("_lsa_priv_get_dispname: %s", name_asc));
+
+ while (privs[i].se_priv!=SE_PRIV_ALL && strcmp(name_asc, privs[i].priv))
+ i++;
+
+ if (privs[i].se_priv!=SE_PRIV_ALL) {
+ DEBUG(10,(": %s\n", privs[i].description));
+ init_uni_hdr(&r_u->hdr_desc, strlen(privs[i].description));
+ init_unistr2(&r_u->desc, privs[i].description, strlen(privs[i].description) );
+
+ r_u->ptr_info=0xdeadbeef;
+ r_u->lang_id=q_u->lang_id;
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(10,("_lsa_priv_get_dispname: doesn't exist\n"));
+ r_u->ptr_info=0;
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+}
+
+/***************************************************************************
+_lsa_enum_accounts.
+ ***************************************************************************/
+
+NTSTATUS _lsa_enum_accounts(pipes_struct *p, LSA_Q_ENUM_ACCOUNTS *q_u, LSA_R_ENUM_ACCOUNTS *r_u)
+{
+ struct lsa_info *handle;
+ GROUP_MAP *map=NULL;
+ int num_entries=0;
+ LSA_SID_ENUM *sids=&r_u->sids;
+ int i=0,j=0;
+
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* get the list of mapped groups (domain, local, builtin) */
+ if(!enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_OK;
+
+ if (q_u->enum_context >= num_entries)
+ return NT_STATUS_NO_MORE_ENTRIES;
+
+ sids->ptr_sid = (uint32 *)talloc_zero(p->mem_ctx, (num_entries-q_u->enum_context)*sizeof(uint32));
+ sids->sid = (DOM_SID2 *)talloc_zero(p->mem_ctx, (num_entries-q_u->enum_context)*sizeof(DOM_SID2));
+
+ if (sids->ptr_sid==NULL || sids->sid==NULL) {
+ SAFE_FREE(map);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=q_u->enum_context, j=0; i<num_entries; i++) {
+ init_dom_sid2( &(*sids).sid[j], &map[i].sid);
+ (*sids).ptr_sid[j]=1;
+ j++;
+ }
+
+ SAFE_FREE(map);
+
+ init_lsa_r_enum_accounts(r_u, j);
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS _lsa_unk_get_connuser(pipes_struct *p, LSA_Q_UNK_GET_CONNUSER *q_u, LSA_R_UNK_GET_CONNUSER *r_u)
+{
+ fstring username, domname;
+ int ulen, dlen;
+ user_struct *vuser = get_valid_user_struct(p->vuid);
+
+ if (vuser == NULL)
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+
+ fstrcpy(username, vuser->user.smb_name);
+ fstrcpy(domname, vuser->user.domain);
+
+ ulen = strlen(username) + 1;
+ dlen = strlen(domname) + 1;
+
+ init_uni_hdr(&r_u->hdr_user_name, ulen);
+ r_u->ptr_user_name = 1;
+ init_unistr2(&r_u->uni2_user_name, username, ulen);
+
+ r_u->unk1 = 1;
+
+ init_uni_hdr(&r_u->hdr_dom_name, dlen);
+ r_u->ptr_dom_name = 1;
+ init_unistr2(&r_u->uni2_dom_name, domname, dlen);
+
+ r_u->status = NT_STATUS_OK;
+
+ return r_u->status;
+}
+
+/***************************************************************************
+
+ ***************************************************************************/
+
+NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENACCOUNT *r_u)
+{
+ struct lsa_info *handle;
+ struct lsa_info *info;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+
+ /*
+ * I don't know if it's the right one. not documented.
+ * but guessed with rpcclient.
+ */
+ if (!(handle->access & POLICY_GET_PRIVATE_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* associate the user/group SID with the (unique) handle. */
+ if ((info = (struct lsa_info *)malloc(sizeof(struct lsa_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = q_u->sid.sid;
+ info->access = q_u->access;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ For a given SID, enumerate all the privilege this account has.
+ ***************************************************************************/
+
+NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, LSA_Q_ENUMPRIVSACCOUNT *q_u, LSA_R_ENUMPRIVSACCOUNT *r_u)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+ int i=0;
+
+ LUID_ATTR *set=NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_group_map_from_sid(info->sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ DEBUG(10,("_lsa_enum_privsaccount: %d privileges\n", map.priv_set.count));
+ if (map.priv_set.count!=0) {
+
+ set=(LUID_ATTR *)talloc(p->mem_ctx, map.priv_set.count*sizeof(LUID_ATTR));
+ if (set == NULL) {
+ free_privilege(&map.priv_set);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<map.priv_set.count; i++) {
+ set[i].luid.low=map.priv_set.set[i].luid.low;
+ set[i].luid.high=map.priv_set.set[i].luid.high;
+ set[i].attr=map.priv_set.set[i].attr;
+ DEBUG(10,("_lsa_enum_privsaccount: priv %d: %d:%d:%d\n", i,
+ set[i].luid.high, set[i].luid.low, set[i].attr));
+ }
+ }
+
+ init_lsa_r_enum_privsaccount(r_u, set, map.priv_set.count, 0);
+ free_privilege(&map.priv_set);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+
+ ***************************************************************************/
+
+NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA_R_GETSYSTEMACCOUNT *r_u)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_group_map_from_sid(info->sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /*
+ 0x01 -> Log on locally
+ 0x02 -> Access this computer from network
+ 0x04 -> Log on as a batch job
+ 0x10 -> Log on as a service
+
+ they can be ORed together
+ */
+
+ r_u->access=map.systemaccount;
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ update the systemaccount information
+ ***************************************************************************/
+
+NTSTATUS _lsa_setsystemaccount(pipes_struct *p, LSA_Q_SETSYSTEMACCOUNT *q_u, LSA_R_SETSYSTEMACCOUNT *r_u)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_group_map_from_sid(info->sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ map.systemaccount=q_u->access;
+
+ if(!add_mapping_entry(&map, TDB_REPLACE))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ free_privilege(&map.priv_set);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ For a given SID, add some privileges.
+ ***************************************************************************/
+
+NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+ int i=0;
+
+ LUID_ATTR *luid_attr=NULL;
+ PRIVILEGE_SET *set=NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_group_map_from_sid(info->sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ set=&q_u->set;
+
+ for (i=0; i<set->count; i++) {
+ luid_attr=&set->set[i];
+
+ /* check if the privilege is already there */
+ if (check_priv_in_privilege(&map.priv_set, *luid_attr)){
+ free_privilege(&map.priv_set);
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ add_privilege(&map.priv_set, *luid_attr);
+ }
+
+ if(!add_mapping_entry(&map, TDB_REPLACE))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ free_privilege(&map.priv_set);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ For a given SID, remove some privileges.
+ ***************************************************************************/
+
+NTSTATUS _lsa_removeprivs(pipes_struct *p, LSA_Q_REMOVEPRIVS *q_u, LSA_R_REMOVEPRIVS *r_u)
+{
+ struct lsa_info *info=NULL;
+ GROUP_MAP map;
+ int i=0;
+
+ LUID_ATTR *luid_attr=NULL;
+ PRIVILEGE_SET *set=NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_group_map_from_sid(info->sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if (q_u->allrights!=0) {
+ /* log it and return, until I see one myself don't do anything */
+ DEBUG(5,("_lsa_removeprivs: trying to remove all privileges ?\n"));
+ return NT_STATUS_OK;
+ }
+
+ if (q_u->ptr==0) {
+ /* log it and return, until I see one myself don't do anything */
+ DEBUG(5,("_lsa_removeprivs: no privileges to remove ?\n"));
+ return NT_STATUS_OK;
+ }
+
+ set=&q_u->set;
+
+ for (i=0; i<set->count; i++) {
+ luid_attr=&set->set[i];
+
+ /* if we don't have the privilege, we're trying to remove, give up */
+ /* what else can we do ??? JFM. */
+ if (!check_priv_in_privilege(&map.priv_set, *luid_attr)){
+ free_privilege(&map.priv_set);
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ remove_privilege(&map.priv_set, *luid_attr);
+ }
+
+ if(!add_mapping_entry(&map, TDB_REPLACE))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ free_privilege(&map.priv_set);
+
+ return r_u->status;
+}
+
+/***************************************************************************
+ For a given SID, remove some privileges.
+ ***************************************************************************/
+
+NTSTATUS _lsa_query_secobj(pipes_struct *p, LSA_Q_QUERY_SEC_OBJ *q_u, LSA_R_QUERY_SEC_OBJ *r_u)
+{
+ struct lsa_info *handle=NULL;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ NTSTATUS status;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* check if the user have enough rights */
+ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION))
+ return NT_STATUS_ACCESS_DENIED;
+
+
+ switch (q_u->sec_info) {
+ case 1:
+ /* SD contains only the owner */
+
+ status=lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+ if(!NT_STATUS_IS_OK(status))
+ return NT_STATUS_NO_MEMORY;
+
+
+ if((r_u->buf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ break;
+ case 4:
+ /* SD contains only the ACL */
+
+ status=lsa_get_generic_sd(p->mem_ctx, &psd, &sd_size);
+ if(!NT_STATUS_IS_OK(status))
+ return NT_STATUS_NO_MEMORY;
+
+ if((r_u->buf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ r_u->ptr=1;
+
+ return r_u->status;
+}
+
+
diff --git a/source/rpc_server/srv_netlog.c b/source/rpc_server/srv_netlog.c
new file mode 100644
index 00000000000..06e2f75ead4
--- /dev/null
+++ b/source/rpc_server/srv_netlog.c
@@ -0,0 +1,341 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface to the netlogon pipe. */
+
+#include "includes.h"
+
+/*************************************************************************
+ api_net_req_chal:
+ *************************************************************************/
+
+static BOOL api_net_req_chal(pipes_struct *p)
+{
+ NET_Q_REQ_CHAL q_u;
+ NET_R_REQ_CHAL r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the challenge... */
+ if(!net_io_q_req_chal("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_req_chal: Failed to unmarshall NET_Q_REQ_CHAL.\n"));
+ return False;
+ }
+
+ r_u.status = _net_req_chal(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_req_chal("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_req_chal: Failed to marshall NET_R_REQ_CHAL.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_auth:
+ *************************************************************************/
+
+static BOOL api_net_auth(pipes_struct *p)
+{
+ NET_Q_AUTH q_u;
+ NET_R_AUTH r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the challenge... */
+ if(!net_io_q_auth("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_auth: Failed to unmarshall NET_Q_AUTH.\n"));
+ return False;
+ }
+
+ r_u.status = _net_auth(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_auth("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_auth: Failed to marshall NET_R_AUTH.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_auth_2:
+ *************************************************************************/
+
+static BOOL api_net_auth_2(pipes_struct *p)
+{
+ NET_Q_AUTH_2 q_u;
+ NET_R_AUTH_2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the challenge... */
+ if(!net_io_q_auth_2("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_auth_2: Failed to unmarshall NET_Q_AUTH_2.\n"));
+ return False;
+ }
+
+ r_u.status = _net_auth_2(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_auth_2("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_auth_2: Failed to marshall NET_R_AUTH_2.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_srv_pwset:
+ *************************************************************************/
+
+static BOOL api_net_srv_pwset(pipes_struct *p)
+{
+ NET_Q_SRV_PWSET q_u;
+ NET_R_SRV_PWSET r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the challenge and encrypted password ... */
+ if(!net_io_q_srv_pwset("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_srv_pwset: Failed to unmarshall NET_Q_SRV_PWSET.\n"));
+ return False;
+ }
+
+ r_u.status = _net_srv_pwset(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_srv_pwset("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_srv_pwset: Failed to marshall NET_R_SRV_PWSET.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_sam_logoff:
+ *************************************************************************/
+
+static BOOL api_net_sam_logoff(pipes_struct *p)
+{
+ NET_Q_SAM_LOGOFF q_u;
+ NET_R_SAM_LOGOFF r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!net_io_q_sam_logoff("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_sam_logoff: Failed to unmarshall NET_Q_SAM_LOGOFF.\n"));
+ return False;
+ }
+
+ r_u.status = _net_sam_logoff(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_sam_logoff("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_sam_logoff: Failed to marshall NET_R_SAM_LOGOFF.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_sam_logon:
+ *************************************************************************/
+
+static BOOL api_net_sam_logon(pipes_struct *p)
+{
+ NET_Q_SAM_LOGON q_u;
+ NET_R_SAM_LOGON r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!net_io_q_sam_logon("", &q_u, data, 0)) {
+ DEBUG(0, ("api_net_sam_logon: Failed to unmarshall NET_Q_SAM_LOGON.\n"));
+ return False;
+ }
+
+ r_u.status = _net_sam_logon(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_sam_logon("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_net_sam_logon: Failed to marshall NET_R_SAM_LOGON.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_trust_dom_list:
+ *************************************************************************/
+
+static BOOL api_net_trust_dom_list(pipes_struct *p)
+{
+ NET_Q_TRUST_DOM_LIST q_u;
+ NET_R_TRUST_DOM_LIST r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
+
+ /* grab the lsa trusted domain list query... */
+ if(!net_io_q_trust_dom("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n"));
+ return False;
+ }
+
+ /* construct reply. */
+ r_u.status = _net_trust_dom_list(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!net_io_r_trust_dom("", &r_u, rdata, 0)) {
+ DEBUG(0,("net_reply_trust_dom_list: Failed to marshall NET_R_TRUST_DOM_LIST.\n"));
+ return False;
+ }
+
+ DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_logon_ctrl2:
+ *************************************************************************/
+
+static BOOL api_net_logon_ctrl2(pipes_struct *p)
+{
+ NET_Q_LOGON_CTRL2 q_u;
+ NET_R_LOGON_CTRL2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
+
+ /* grab the lsa netlogon ctrl2 query... */
+ if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_logon_ctrl2: Failed to unmarshall NET_Q_LOGON_CTRL2.\n"));
+ return False;
+ }
+
+ r_u.status = _net_logon_ctrl2(p, &q_u, &r_u);
+
+ if(!net_io_r_logon_ctrl2("", &r_u, rdata, 0)) {
+ DEBUG(0,("net_reply_logon_ctrl2: Failed to marshall NET_R_LOGON_CTRL2.\n"));
+ return False;
+ }
+
+ DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
+
+ return True;
+}
+
+/*************************************************************************
+ api_net_logon_ctrl:
+ *************************************************************************/
+
+static BOOL api_net_logon_ctrl(pipes_struct *p)
+{
+ NET_Q_LOGON_CTRL q_u;
+ NET_R_LOGON_CTRL r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__));
+
+ /* grab the lsa netlogon ctrl query... */
+ if(!net_io_q_logon_ctrl("", &q_u, data, 0)) {
+ DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n"));
+ return False;
+ }
+
+ r_u.status = _net_logon_ctrl(p, &q_u, &r_u);
+
+ if(!net_io_r_logon_ctrl("", &r_u, rdata, 0)) {
+ DEBUG(0,("net_reply_logon_ctrl2: Failed to marshall NET_R_LOGON_CTRL2.\n"));
+ return False;
+ }
+
+ DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
+
+ return True;
+}
+
+/*******************************************************************
+ array of \PIPE\NETLOGON operations
+ ********************************************************************/
+static struct api_struct api_net_cmds [] =
+{
+ { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
+ { "NET_AUTH" , NET_AUTH , api_net_auth },
+ { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 },
+ { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset },
+ { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon },
+ { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff },
+ { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 },
+ { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list },
+ { "NET_LOGON_CTRL" , NET_LOGON_CTRL , api_net_logon_ctrl },
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+ receives a netlogon pipe and responds.
+ ********************************************************************/
+
+BOOL api_netlog_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds);
+}
diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c
new file mode 100644
index 00000000000..80924886522
--- /dev/null
+++ b/source/rpc_server/srv_netlog_nt.c
@@ -0,0 +1,682 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998-2001.
+ * Copyirht (C) Andrew Bartlett 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the implementation of the netlogon pipe. */
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern DOM_SID global_sam_sid;
+
+/*************************************************************************
+ init_net_r_req_chal:
+ *************************************************************************/
+
+static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
+ DOM_CHAL *srv_chal, NTSTATUS status)
+{
+ DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
+ memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
+ r_c->status = status;
+}
+
+/*************************************************************************
+ error messages cropping up when using nltest.exe...
+ *************************************************************************/
+
+#define ERROR_NO_SUCH_DOMAIN 0x54b
+#define ERROR_NO_LOGON_SERVERS 0x51f
+
+/*************************************************************************
+ net_reply_logon_ctrl:
+ *************************************************************************/
+
+/* Some flag values reverse engineered from NLTEST.EXE */
+
+#define LOGON_CTRL_IN_SYNC 0x00
+#define LOGON_CTRL_REPL_NEEDED 0x01
+#define LOGON_CTRL_REPL_IN_PROGRESS 0x02
+
+NTSTATUS _net_logon_ctrl(pipes_struct *p, NET_Q_LOGON_CTRL *q_u,
+ NET_R_LOGON_CTRL *r_u)
+{
+ uint32 flags = 0x0;
+ uint32 pdc_connection_status = 0x00; /* Maybe a win32 error code? */
+
+ /* Setup the Logon Control response */
+
+ init_net_r_logon_ctrl(r_u, q_u->query_level, flags,
+ pdc_connection_status);
+
+ return r_u->status;
+}
+
+/****************************************************************************
+Send a message to smbd to do a sam synchronisation
+**************************************************************************/
+static void send_sync_message(void)
+{
+ TDB_CONTEXT *tdb;
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0,
+ TDB_DEFAULT, O_RDONLY, 0);
+
+ if (!tdb) {
+ DEBUG(3, ("send_sync_message(): failed to open connections "
+ "database\n"));
+ return;
+ }
+
+ DEBUG(3, ("sending sam synchronisation message\n"));
+
+ message_send_all(tdb, MSG_SMB_SAM_SYNC, NULL, 0, False);
+
+ tdb_close(tdb);
+}
+
+/*************************************************************************
+ net_reply_logon_ctrl2:
+ *************************************************************************/
+
+NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
+{
+ uint32 flags = 0x0;
+ uint32 pdc_connection_status = 0x0;
+ uint32 logon_attempts = 0x0;
+ uint32 tc_status = ERROR_NO_LOGON_SERVERS;
+ char *trusted_domain = "test_domain";
+
+ DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n",
+ q_u->function_code, q_u->query_level, q_u->switch_value));
+
+ DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
+
+
+ /* set up the Logon Control2 response */
+ init_net_r_logon_ctrl2(r_u, q_u->query_level,
+ flags, pdc_connection_status, logon_attempts,
+ tc_status, trusted_domain);
+
+ if (lp_server_role() == ROLE_DOMAIN_BDC)
+ send_sync_message();
+
+ DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*************************************************************************
+ net_reply_trust_dom_list:
+ *************************************************************************/
+
+NTSTATUS _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
+{
+ char *trusted_domain = "test_domain";
+ uint32 num_trust_domains = 1;
+
+ DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
+
+ /* set up the Trusted Domain List response */
+ init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
+
+ DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/***********************************************************************************
+ init_net_r_srv_pwset:
+ ***********************************************************************************/
+
+static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
+ DOM_CRED *srv_cred, NTSTATUS status)
+{
+ DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
+
+ memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
+ r_s->status = status;
+
+ DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
+}
+
+/******************************************************************
+ gets a machine password entry. checks access rights of the host.
+ ******************************************************************/
+
+static BOOL get_md4pw(char *md4pw, char *mach_acct)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ const uint8 *pass;
+ BOOL ret;
+
+#if 0
+ /*
+ * Currently this code is redundent as we already have a filter
+ * by hostname list. What this code really needs to do is to
+ * get a hosts allowed/hosts denied list from the SAM database
+ * on a per user basis, and make the access decision there.
+ * I will leave this code here for now as a reminder to implement
+ * this at a later date. JRA.
+ */
+
+ if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
+ client_name(), client_addr()))
+ {
+ DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
+ return False;
+ }
+#endif /* 0 */
+
+ if(!pdb_init_sam(&sampass))
+ return False;
+
+ /* JRA. This is ok as it is only used for generating the challenge. */
+ become_root();
+ ret=pdb_getsampwnam(sampass, mach_acct);
+ unbecome_root();
+
+ if (ret==False) {
+ DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ if (!(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) && ((pass=pdb_get_nt_passwd(sampass)) != NULL)) {
+ memcpy(md4pw, pass, 16);
+ dump_data(5, md4pw, 16);
+ pdb_free_sam(&sampass);
+ return True;
+ }
+
+ DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
+ pdb_free_sam(&sampass);
+ return False;
+
+}
+
+/*************************************************************************
+ _net_req_chal
+ *************************************************************************/
+
+NTSTATUS _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ fstring mach_acct;
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ rpcstr_pull(mach_acct,q_u->uni_logon_clnt.buffer,sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
+
+ strlower(mach_acct);
+ fstrcat(mach_acct, "$");
+
+ if (get_md4pw((char *)p->dc.md4pw, mach_acct)) {
+ /* copy the client credentials */
+ memcpy(p->dc.clnt_chal.data , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+
+ /* create a server challenge for the client */
+ /* Set these to random values. */
+ generate_random_buffer(p->dc.srv_chal.data, 8, False);
+
+ memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
+
+ memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
+
+ /* from client / server challenges and md4 password, generate sess key */
+ cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
+ (char *)p->dc.md4pw, p->dc.sess_key);
+
+ /* Save the machine account name. */
+ fstrcpy(p->dc.mach_acct, mach_acct);
+
+ } else {
+ /* lkclXXXX take a guess at a good error message to return :-) */
+ status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
+ }
+
+ /* set up the LSA REQUEST CHALLENGE response */
+ init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
+
+ return r_u->status;
+}
+
+/*************************************************************************
+ init_net_r_auth:
+ *************************************************************************/
+
+static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, NTSTATUS status)
+{
+ memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
+ r_a->status = status;
+}
+
+/*************************************************************************
+ _net_auth
+ *************************************************************************/
+
+NTSTATUS _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DOM_CHAL srv_cred;
+ UTIME srv_time;
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ srv_time.time = 0;
+
+ /* check that the client credentials are valid */
+ if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
+
+ /* create server challenge for inclusion in the reply */
+ cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
+
+ /* copy the received client credentials for use next time */
+ memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ } else {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* set up the LSA AUTH 2 response */
+ init_net_r_auth(r_u, &srv_cred, status);
+
+ return r_u->status;
+}
+
+/*************************************************************************
+ init_net_r_auth_2:
+ *************************************************************************/
+
+static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
+ DOM_CHAL *resp_cred, NEG_FLAGS *flgs, NTSTATUS status)
+{
+ memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
+ memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
+ r_a->status = status;
+}
+
+/*************************************************************************
+ _net_auth_2
+ *************************************************************************/
+
+NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DOM_CHAL srv_cred;
+ UTIME srv_time;
+ NEG_FLAGS srv_flgs;
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ srv_time.time = 0;
+
+ /* check that the client credentials are valid */
+ if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
+
+ /* create server challenge for inclusion in the reply */
+ cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
+
+ /* copy the received client credentials for use next time */
+ memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ } else {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ srv_flgs.neg_flags = 0x000001ff;
+
+ /* set up the LSA AUTH 2 response */
+ init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
+
+ return r_u->status;
+}
+
+/*************************************************************************
+ _net_srv_pwset
+ *************************************************************************/
+
+NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
+{
+ NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
+ DOM_CRED srv_cred;
+ pstring mach_acct;
+ SAM_ACCOUNT *sampass=NULL;
+ BOOL ret = False;
+ unsigned char pwd[16];
+ int i;
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
+ return NT_STATUS_INVALID_HANDLE;
+
+ memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
+
+ DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
+
+ rpcstr_pull(mach_acct,q_u->clnt_id.login.uni_acct_name.buffer,
+ sizeof(mach_acct),q_u->clnt_id.login.uni_acct_name.uni_str_len*2,0);
+
+ DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
+
+ /*
+ * Check the machine account name we're changing is the same
+ * as the one we've authenticated from. This prevents arbitrary
+ * machines changing other machine account passwords.
+ */
+
+ if (!strequal(mach_acct, p->dc.mach_acct)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret=pdb_getsampwnam(sampass, mach_acct);
+ unbecome_root();
+
+ /* Ensure the account exists and is a machine account. */
+
+ if (ret==False || !(pdb_get_acct_ctrl(sampass) & ACB_WSTRUST)) {
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ DEBUG(100,("Server password set : new given value was :\n"));
+ for(i = 0; i < 16; i++)
+ DEBUG(100,("%02X ", q_u->pwd[i]));
+ DEBUG(100,("\n"));
+
+ cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
+
+ /* lies! nt and lm passwords are _not_ the same: don't care */
+ if (!pdb_set_lanman_passwd (sampass, pwd)) {
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_nt_passwd (sampass, pwd)) {
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_acct_ctrl (sampass, ACB_WSTRUST)) {
+ pdb_free_sam(&sampass);
+ /* Not quite sure what this one qualifies as, but this will do */
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!pdb_set_pass_changed_now (sampass)) {
+ pdb_free_sam(&sampass);
+ /* Not quite sure what this one qualifies as, but this will do */
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_update_sam_account (sampass,False);
+ unbecome_root();
+
+ if (ret)
+ status = NT_STATUS_OK;
+
+ /* set up the LSA Server Password Set response */
+ init_net_r_srv_pwset(r_u, &srv_cred, status);
+
+ pdb_free_sam(&sampass);
+ return r_u->status;
+}
+
+
+/*************************************************************************
+ _net_sam_logoff:
+ *************************************************************************/
+
+NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
+{
+ DOM_CRED srv_cred;
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred,
+ &q_u->sam_id.client.cred, &srv_cred))
+ return NT_STATUS_INVALID_HANDLE;
+
+ memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
+
+ /* XXXX maybe we want to say 'no', reject the client's credentials */
+ r_u->buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
+
+ r_u->status = NT_STATUS_OK;
+
+ return r_u->status;
+}
+
+
+/*************************************************************************
+ _net_sam_logon
+ *************************************************************************/
+
+NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ NET_USER_INFO_3 *usr_info = NULL;
+ NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr;
+ DOM_CRED srv_cred;
+ UNISTR2 *uni_samlogon_user = NULL;
+ UNISTR2 *uni_samlogon_domain = NULL;
+ UNISTR2 *uni_samlogon_workstation = NULL;
+ fstring nt_username, nt_domain, nt_workstation;
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+ extern userdom_struct current_user_info;
+
+ usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
+ if (!usr_info)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(usr_info);
+
+ if (!get_valid_user_struct(p->vuid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
+ return NT_STATUS_INVALID_HANDLE;
+ else
+ memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
+
+ r_u->buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
+
+ /* store the user information, if there is any. */
+ r_u->user = usr_info;
+ r_u->switch_value = 0; /* indicates no info */
+ r_u->auth_resp = 1; /* authoritative response */
+ r_u->switch_value = 3; /* indicates type of validation user info */
+
+ /* find the username */
+
+ switch (q_u->sam_id.logon_level) {
+ case INTERACTIVE_LOGON_TYPE:
+ uni_samlogon_user = &ctr->auth.id1.uni_user_name;
+ uni_samlogon_domain = &ctr->auth.id1.uni_domain_name;
+
+ uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name;
+
+ DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
+ break;
+ case NET_LOGON_TYPE:
+ uni_samlogon_user = &ctr->auth.id2.uni_user_name;
+ uni_samlogon_domain = &ctr->auth.id2.uni_domain_name;
+ uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name;
+
+ DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
+ break;
+ default:
+ DEBUG(2,("SAM Logon: unsupported switch value\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ } /* end switch */
+
+ /* check username exists */
+
+ rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0);
+ rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
+ rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);
+
+ DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username,
+ nt_workstation, nt_domain));
+
+ pstrcpy(current_user_info.smb_name, nt_username);
+
+ /*
+ * Convert to a UNIX username.
+ */
+
+ DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username));
+
+ switch (ctr->switch_value) {
+ case NET_LOGON_TYPE:
+ {
+ auth_authsupplied_info *auth_info = NULL;
+ make_auth_info_fixed(&auth_info, ctr->auth.id2.lm_chal);
+ /* Standard challenge/response authenticaion */
+ make_user_info_netlogon_network(&user_info,
+ nt_username, nt_domain,
+ nt_workstation,
+ ctr->auth.id2.lm_chal_resp.buffer,
+ ctr->auth.id2.lm_chal_resp.str_str_len,
+ ctr->auth.id2.nt_chal_resp.buffer,
+ ctr->auth.id2.nt_chal_resp.str_str_len);
+
+ status = check_password(user_info, auth_info, &server_info);
+ free_auth_info(&auth_info);
+
+ break;
+ }
+ case INTERACTIVE_LOGON_TYPE:
+ /* 'Interactive' autheticaion, supplies the password in its
+ MD4 form, encrypted with the session key. We will
+ convert this to chellange/responce for the auth
+ subsystem to chew on */
+ {
+ auth_authsupplied_info *auth_info = NULL;
+ DATA_BLOB chal;
+ if (!make_auth_info_subsystem(&auth_info)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ chal = auth_get_challenge(auth_info);
+
+ make_user_info_netlogon_interactive(&user_info,
+ nt_username, nt_domain,
+ nt_workstation, chal.data,
+ ctr->auth.id1.lm_owf.data,
+ ctr->auth.id1.nt_owf.data,
+ p->dc.sess_key);
+ status = check_password(user_info, auth_info, &server_info);
+ data_blob_free(&chal);
+ free_auth_info(&auth_info);
+
+ break;
+ }
+ default:
+ DEBUG(2,("SAM Logon: unsupported switch value\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ } /* end switch */
+
+ free_user_info(&user_info);
+
+ DEBUG(5, ("_net_sam_logon: check_password returned status %s\n",
+ get_nt_error_msg(status)));
+
+ /* Check account and password */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ free_server_info(&server_info);
+ return status;
+ }
+
+ if (server_info->guest) {
+ /* We don't like guest domain logons... */
+ DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n"));
+ free_server_info(&server_info);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ /* This is the point at which, if the login was successful, that
+ the SAM Local Security Authority should record that the user is
+ logged in to the domain. */
+
+ {
+ DOM_GID *gids = NULL;
+ int num_gids = 0;
+ pstring my_name;
+ pstring my_workgroup;
+
+ /* set up pointer indicating user/password failed to be found */
+ usr_info->ptr_user_info = 0;
+
+ pstrcpy(my_workgroup, lp_workgroup());
+ pstrcpy(my_name, global_myname);
+ strupper(my_name);
+
+ /*
+ * This is the point at which we get the group
+ * database - we should be getting the gid_t list
+ * from /etc/group and then turning the uids into
+ * rids and then into machine sids for this user.
+ * JRA.
+ */
+
+ gids = NULL;
+ get_domain_user_groups(p->mem_ctx, &num_gids, &gids, server_info->sam_account);
+
+ init_net_user_info3(p->mem_ctx, usr_info, server_info->sam_account,
+ 0, /* logon_count */
+ 0, /* bad_pw_count */
+ num_gids, /* uint32 num_groups */
+ gids , /* DOM_GID *gids */
+ 0x20 , /* uint32 user_flgs (?) */
+ NULL, /* uchar sess_key[16] */
+ my_name , /* char *logon_srv */
+ my_workgroup, /* char *logon_dom */
+ &global_sam_sid, /* DOM_SID *dom_sid */
+ NULL); /* char *other_sids */
+
+ }
+ free_server_info(&server_info);
+ return status;
+}
+
+
diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c
new file mode 100644
index 00000000000..4b3140b3504
--- /dev/null
+++ b/source/rpc_server/srv_pipe.c
@@ -0,0 +1,1217 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this module apparently provides an implementation of DCE/RPC over a
+ * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC
+ * documentation are available (in on-line form) from the X-Open group.
+ *
+ * this module should provide a level of abstraction between SMB
+ * and DCE/RPC, while minimising the amount of mallocs, unnecessary
+ * data copies, and network traffic.
+ *
+ * in this version, which takes a "let's learn what's going on and
+ * get something running" approach, there is additional network
+ * traffic generated, but the code should be easier to understand...
+ *
+ * ... if you read the docs. or stare at packets for weeks on end.
+ *
+ */
+
+#include "includes.h"
+
+static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len)
+{
+ unsigned char *hash = p->ntlmssp_hash;
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ int ind;
+
+ for( ind = 0; ind < len; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = data[ind] ^ hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+ We cheat here as this function doesn't handle the special auth
+ footers of the authenticated bind response reply.
+ ********************************************************************/
+
+BOOL create_next_pdu(pipes_struct *p)
+{
+ RPC_HDR_RESP hdr_resp;
+ BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0);
+ uint32 data_len;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ prs_struct outgoing_pdu;
+ char *data;
+ char *data_from;
+ uint32 data_pos;
+
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
+
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ return True;
+ }
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
+
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0)
+ p->hdr.flags = RPC_FLG_FIRST;
+ else
+ p->hdr.flags = 0;
+
+ /*
+ * Work out how much we can fit in a single PDU.
+ */
+
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
+ if(p->ntlmssp_auth_validated)
+ data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN);
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
+ /*
+ * Ensure there really is data left to send.
+ */
+
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu: no data left to send !\n"));
+ return False;
+ }
+
+ data_len = MIN(data_len_left, data_space_available);
+
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
+
+ /*
+ * Set up the header lengths.
+ */
+
+ if (p->ntlmssp_auth_validated) {
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len +
+ RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN;
+ p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
+ } else {
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len;
+ p->hdr.auth_len = 0;
+ }
+
+ /*
+ * Work out if this PDU will be the last.
+ */
+
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata))
+ p->hdr.flags |= RPC_FLG_LAST;
+
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Store the current offset. */
+ data_pos = prs_offset(&outgoing_pdu);
+
+ /* Copy the data into the PDU. */
+ data_from = prs_data_p(&p->out_data.rdata) + p->out_data.data_sent_length;
+
+ if(!prs_append_data(&outgoing_pdu, data_from, data_len)) {
+ DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /*
+ * Set data to point to where we copied the data into.
+ */
+
+ data = prs_data_p(&outgoing_pdu) + data_pos;
+
+ if (p->hdr.auth_len > 0) {
+ uint32 crc32 = 0;
+
+ DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n",
+ BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, p->hdr.auth_len));
+
+ if (auth_seal) {
+ crc32 = crc32_calc_buffer(data, data_len);
+ NTLMSSPcalc_p(p, (uchar*)data, data_len);
+ }
+
+ if (auth_seal || auth_verify) {
+ RPC_HDR_AUTH auth_info;
+
+ init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL,
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0));
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ }
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK ntlmssp_chk;
+ char *auth_data = prs_data_p(&outgoing_pdu);
+
+ p->ntlmssp_seq_num++;
+ init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION,
+ crc32, p->ntlmssp_seq_num++);
+ auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4;
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+ NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ }
+ }
+
+ /*
+ * Setup the counts for this PDU.
+ */
+
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Process an NTLMSSP authentication response.
+ If this function succeeds, the user has been authenticated
+ and their domain, name and calling workstation stored in
+ the pipe struct.
+ The initial challenge is stored in p->challenge.
+ *******************************************************************/
+
+static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlmssp_resp)
+{
+ uchar lm_owf[24];
+ uchar nt_owf[128];
+ int nt_pw_len;
+ int lm_pw_len;
+ fstring user_name;
+ fstring domain;
+ fstring wks;
+
+ NTSTATUS nt_status;
+
+ auth_usersupplied_info *user_info = NULL;
+ auth_authsupplied_info *auth_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+
+ uid_t *puid;
+ uid_t *pgid;
+
+ DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n"));
+
+ memset(p->user_name, '\0', sizeof(p->user_name));
+ memset(p->pipe_user_name, '\0', sizeof(p->pipe_user_name));
+ memset(p->domain, '\0', sizeof(p->domain));
+ memset(p->wks, '\0', sizeof(p->wks));
+
+ /* Set up for non-authenticated user. */
+ delete_nt_token(&p->pipe_user.nt_user_token);
+ p->pipe_user.ngroups = 0;
+ SAFE_FREE( p->pipe_user.groups);
+
+ /*
+ * Setup an empty password for a guest user.
+ */
+
+ /*
+ * We always negotiate UNICODE.
+ */
+
+ if (p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ rpcstr_pull(user_name, ntlmssp_resp->user, sizeof(fstring), ntlmssp_resp->hdr_usr.str_str_len*2, 0 );
+ rpcstr_pull(domain, ntlmssp_resp->domain, sizeof(fstring), ntlmssp_resp->hdr_domain.str_str_len*2, 0);
+ rpcstr_pull(wks, ntlmssp_resp->wks, sizeof(fstring), ntlmssp_resp->hdr_wks.str_str_len*2, 0);
+ } else {
+ pull_ascii_fstring(user_name, ntlmssp_resp->user);
+ pull_ascii_fstring(domain, ntlmssp_resp->domain);
+ pull_ascii_fstring(wks, ntlmssp_resp->wks);
+ }
+
+ DEBUG(5,("user: %s domain: %s wks: %s\n", user_name, domain, wks));
+
+ nt_pw_len = MIN(sizeof(nt_owf), ntlmssp_resp->hdr_nt_resp.str_str_len);
+ lm_pw_len = MIN(sizeof(lm_owf), ntlmssp_resp->hdr_lm_resp.str_str_len);
+
+ memcpy(lm_owf, ntlmssp_resp->lm_resp, sizeof(lm_owf));
+ memcpy(nt_owf, ntlmssp_resp->nt_resp, nt_pw_len);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm, nt owfs, chal\n"));
+ dump_data(100, (char *)lm_owf, sizeof(lm_owf));
+ dump_data(100, (char *)nt_owf, nt_pw_len);
+ dump_data(100, (char *)p->challenge, 8);
+#endif
+
+ /*
+ * Allow guest access. Patch from Shirish Kalele <kalele@veritas.com>.
+ */
+
+ if (*user_name) {
+
+ /*
+ * Do the length checking only if user is not NULL.
+ */
+
+ if (ntlmssp_resp->hdr_lm_resp.str_str_len == 0)
+ return False;
+ if (ntlmssp_resp->hdr_nt_resp.str_str_len == 0)
+ return False;
+ if (ntlmssp_resp->hdr_usr.str_str_len == 0)
+ return False;
+ if (ntlmssp_resp->hdr_domain.str_str_len == 0)
+ return False;
+ if (ntlmssp_resp->hdr_wks.str_str_len == 0)
+ return False;
+
+ }
+
+ make_auth_info_fixed(&auth_info, (uchar*)p->challenge);
+
+ if (!make_user_info_netlogon_network(&user_info,
+ user_name, domain, wks,
+ lm_owf, lm_pw_len,
+ nt_owf, nt_pw_len)) {
+ DEBUG(0,("make_user_info_netlogon_network failed! Failing authenticaion.\n"));
+ return False;
+ }
+
+ nt_status = check_password(user_info, auth_info, &server_info);
+
+ free_auth_info(&auth_info);
+ free_user_info(&user_info);
+
+ p->ntlmssp_auth_validated = NT_STATUS_IS_OK(nt_status);
+
+ if (!p->ntlmssp_auth_validated) {
+ DEBUG(1,("api_pipe_ntlmssp_verify: User [%s]\\[%s] from machine %s \
+failed authentication on named pipe %s.\n", domain, user_name, wks, p->name ));
+ free_server_info(&server_info);
+ return False;
+ }
+
+ /*
+ * Set up the sign/seal data.
+ */
+
+ {
+ uchar p24[24];
+ NTLMSSPOWFencrypt(server_info->first_8_lm_hash, lm_owf, p24);
+ {
+ unsigned char j = 0;
+ int ind;
+
+ unsigned char k2[8];
+
+ memcpy(k2, p24, 5);
+ k2[5] = 0xe5;
+ k2[6] = 0x38;
+ k2[7] = 0xb0;
+
+ for (ind = 0; ind < 256; ind++)
+ p->ntlmssp_hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (p->ntlmssp_hash[ind] + k2[ind%8]);
+
+ tc = p->ntlmssp_hash[ind];
+ p->ntlmssp_hash[ind] = p->ntlmssp_hash[j];
+ p->ntlmssp_hash[j] = tc;
+ }
+
+ p->ntlmssp_hash[256] = 0;
+ p->ntlmssp_hash[257] = 0;
+ }
+/* NTLMSSPhash(p->ntlmssp_hash, p24); */
+ p->ntlmssp_seq_num = 0;
+
+ }
+
+ fstrcpy(p->user_name, user_name);
+ fstrcpy(p->pipe_user_name, pdb_get_username(server_info->sam_account));
+ fstrcpy(p->domain, domain);
+ fstrcpy(p->wks, wks);
+
+ /*
+ * Store the UNIX credential data (uid/gid pair) in the pipe structure.
+ */
+
+ puid = pdb_get_uid(server_info->sam_account);
+ pgid = pdb_get_gid(server_info->sam_account);
+
+ if (!puid || !pgid) {
+ DEBUG(0,("Attempted authenticated pipe with invalid user. No uid/gid in SAM_ACCOUNT\n"));
+ free_server_info(&server_info);
+ return False;
+ }
+
+ p->pipe_user.uid = *puid;
+ p->pipe_user.gid = *pgid;
+
+ /* Set up pipe user group membership. */
+ initialise_groups(p->pipe_user_name, p->pipe_user.uid, p->pipe_user.gid);
+ get_current_groups( &p->pipe_user.ngroups, &p->pipe_user.groups);
+
+ if (server_info->ptok)
+ add_supplementary_nt_login_groups(&p->pipe_user.ngroups, &p->pipe_user.groups, &server_info->ptok);
+
+ /* Create an NT_USER_TOKEN struct for this user. */
+ p->pipe_user.nt_user_token = create_nt_token(p->pipe_user.uid,p->pipe_user.gid,
+ p->pipe_user.ngroups, p->pipe_user.groups,
+ server_info->guest, server_info->ptok);
+
+ p->ntlmssp_auth_validated = True;
+
+ pdb_free_sam(&server_info->sam_account);
+ return True;
+}
+
+/*******************************************************************
+ The switch table for the pipe names and the functions to handle them.
+ *******************************************************************/
+
+struct api_cmd
+{
+ char * pipe_clnt_name;
+ char * pipe_srv_name;
+ BOOL (*fn) (pipes_struct *);
+};
+
+static struct api_cmd api_fd_commands[] =
+{
+ { "lsarpc", "lsass", api_ntlsa_rpc },
+ { "samr", "lsass", api_samr_rpc },
+ { "srvsvc", "ntsvcs", api_srvsvc_rpc },
+ { "wkssvc", "ntsvcs", api_wkssvc_rpc },
+ { "NETLOGON", "lsass", api_netlog_rpc },
+ { "winreg", "winreg", api_reg_rpc },
+ { "spoolss", "spoolss", api_spoolss_rpc },
+ { "netdfs", "netdfs" , api_netdfs_rpc },
+ { NULL, NULL, NULL }
+};
+
+/*******************************************************************
+ This is the client reply to our challenge for an authenticated
+ bind request. The challenge we sent is in p->challenge.
+*******************************************************************/
+
+BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_AUTHA autha_info;
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
+
+ DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__));
+
+ if (p->hdr.auth_len == 0) {
+ DEBUG(0,("api_pipe_bind_auth_resp: No auth field sent !\n"));
+ return False;
+ }
+
+ /*
+ * Decode the authentication verifier response.
+ */
+
+ if(!smb_io_rpc_hdr_autha("", &autha_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_HDR_AUTHA failed.\n"));
+ return False;
+ }
+
+ if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != NTLMSSP_AUTH_LEVEL) {
+ DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n",
+ (int)autha_info.auth_type, (int)autha_info.auth_level ));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_AUTH_VERIFIER failed.\n"));
+ return False;
+ }
+
+ /*
+ * Ensure this is a NTLMSSP_AUTH packet type.
+ */
+
+ if (!rpc_auth_verifier_chk(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH)) {
+ DEBUG(0,("api_pipe_bind_auth_resp: rpc_auth_verifier_chk failed.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_resp("", &ntlmssp_resp, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_auth_resp: Failed to unmarshall RPC_AUTH_NTLMSSP_RESP.\n"));
+ return False;
+ }
+
+ /*
+ * The following call actually checks the challenge/response data.
+ * for correctness against the given DOMAIN\user name.
+ */
+
+ if (!api_pipe_ntlmssp_verify(p, &ntlmssp_resp))
+ return False;
+
+ p->pipe_bound = True
+;
+ return True;
+}
+
+/*******************************************************************
+ Marshall a bind_nak pdu.
+*******************************************************************/
+
+static BOOL setup_bind_nak(pipes_struct *p)
+{
+ prs_struct outgoing_rpc;
+ RPC_HDR nak_hdr;
+ uint16 zero = 0;
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&p->out_data.rdata);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+
+ /*
+ * Initialize a bind_nak header.
+ */
+
+ init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &nak_hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("setup_bind_nak: marshalling of RPC_HDR failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ /*
+ * Now add the reject reason.
+ */
+
+ if(!prs_uint16("reject code", &outgoing_rpc, 0, &zero)) {
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ p->pipe_bound = False;
+
+ return True;
+}
+
+/*******************************************************************
+ Marshall a fault pdu.
+*******************************************************************/
+
+BOOL setup_fault_pdu(pipes_struct *p, NTSTATUS status)
+{
+ prs_struct outgoing_pdu;
+ RPC_HDR fault_hdr;
+ RPC_HDR_RESP hdr_resp;
+ RPC_HDR_FAULT fault_resp;
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&p->out_data.rdata);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Initialize a fault header.
+ */
+
+ init_rpc_hdr(&fault_hdr, RPC_FAULT, RPC_FLG_FIRST | RPC_FLG_LAST | RPC_FLG_NOCALL,
+ p->hdr.call_id, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_FAULT_LEN, 0);
+
+ /*
+ * Initialize the HDR_RESP and FAULT parts of the PDU.
+ */
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ fault_resp.status = status;
+ fault_resp.reserved = 0;
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &fault_hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: marshalling of RPC_HDR failed.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_fault("fault", &fault_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("setup_fault_pdu: failed to marshall RPC_HDR_FAULT.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_pdu);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Ensure a bind request has the correct abstract & transfer interface.
+ Used to reject unknown binds from Win2k.
+*******************************************************************/
+
+BOOL check_bind_req(char* pipe_name, RPC_IFACE* abstract,
+ RPC_IFACE* transfer)
+{
+ extern struct pipe_id_info pipe_names[];
+ int i=0;
+ fstring pname;
+ fstrcpy(pname,"\\PIPE\\");
+ fstrcat(pname,pipe_name);
+
+ for(i=0;pipe_names[i].client_pipe; i++) {
+ if(strequal(pipe_names[i].client_pipe, pname))
+ break;
+ }
+
+ if(pipe_names[i].client_pipe == NULL)
+ return False;
+
+ /* check the abstract interface */
+ if((abstract->version != pipe_names[i].abstr_syntax.version) ||
+ (memcmp(&abstract->uuid, &pipe_names[i].abstr_syntax.uuid,
+ sizeof(RPC_UUID)) != 0))
+ return False;
+
+ /* check the transfer interface */
+ if((transfer->version != pipe_names[i].trans_syntax.version) ||
+ (memcmp(&transfer->uuid, &pipe_names[i].trans_syntax.uuid,
+ sizeof(RPC_UUID)) != 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Respond to a pipe bind request.
+*******************************************************************/
+
+BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_BA hdr_ba;
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR_AUTH auth_info;
+ uint16 assoc_gid;
+ fstring ack_pipe_name;
+ prs_struct out_hdr_ba;
+ prs_struct out_auth;
+ prs_struct outgoing_rpc;
+ int i = 0;
+ int auth_len = 0;
+ enum RPC_PKT_TYPE reply_pkt_type;
+
+ p->ntlmssp_auth_requested = False;
+
+ DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
+
+ /*
+ * Try and find the correct pipe name to ensure
+ * that this is a pipe name we support.
+ */
+
+ for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) {
+ if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
+ api_fd_commands[i].fn != NULL) {
+ DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+ api_fd_commands[i].pipe_clnt_name,
+ api_fd_commands[i].pipe_srv_name));
+ fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name);
+ break;
+ }
+ }
+
+ if (api_fd_commands[i].fn == NULL) {
+ DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n",
+ p->name ));
+ if(!setup_bind_nak(p))
+ return False;
+ return True;
+ }
+
+ /* decode the bind request */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_RB struct.\n"));
+ return False;
+ }
+
+ /*
+ * Check if this is an authenticated request.
+ */
+
+ if (p->hdr.auth_len != 0) {
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
+
+ /*
+ * Decode the authentication verifier.
+ */
+
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+ return False;
+ }
+
+ /*
+ * We only support NTLMSSP_AUTH_TYPE requests.
+ */
+
+ if(auth_info.auth_type != NTLMSSP_AUTH_TYPE) {
+ DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n",
+ auth_info.auth_type ));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+ return False;
+ }
+
+ if(!strequal(auth_verifier.signature, "NTLMSSP")) {
+ DEBUG(0,("api_pipe_bind_req: auth_verifier.signature != NTLMSSP\n"));
+ return False;
+ }
+
+ if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) {
+ DEBUG(0,("api_pipe_bind_req: auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n",
+ auth_verifier.msg_type));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_req: Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n"));
+ return False;
+ }
+
+ p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS;
+ p->ntlmssp_auth_requested = True;
+ }
+
+ switch(p->hdr.pkt_type) {
+ case RPC_BIND:
+ /* name has to be \PIPE\xxxxx */
+ fstrcpy(ack_pipe_name, "\\PIPE\\");
+ fstrcat(ack_pipe_name, p->pipe_srv_name);
+ reply_pkt_type = RPC_BINDACK;
+ break;
+ case RPC_ALTCONT:
+ /* secondary address CAN be NULL
+ * as the specs say it's ignored.
+ * It MUST NULL to have the spoolss working.
+ */
+ fstrcpy(ack_pipe_name,"");
+ reply_pkt_type = RPC_ALTCONTRESP;
+ break;
+ default:
+ return False;
+ }
+
+ DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /*
+ * Setup the memory to marshall the ba header, and the
+ * auth footers.
+ */
+
+ if(!prs_init(&out_hdr_ba, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ if(!prs_init(&out_auth, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("pi_pipe_bind_req: malloc out_auth failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ return False;
+ }
+
+ if (p->ntlmssp_auth_requested)
+ assoc_gid = 0x7a77;
+ else
+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
+
+ /*
+ * Create the bind response struct.
+ */
+
+ /* If the requested abstract synt uuid doesn't match our client pipe,
+ reject the bind_ack & set the transfer interface synt to all 0's,
+ ver 0 (observed when NT5 attempts to bind to abstract interfaces
+ unknown to NT4)
+ Needed when adding entries to a DACL from NT5 - SK */
+
+ if(check_bind_req(p->name, &hdr_rb.abstract, &hdr_rb.transfer)) {
+ init_rpc_hdr_ba(&hdr_ba,
+ MAX_PDU_FRAG_LEN,
+ MAX_PDU_FRAG_LEN,
+ assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &hdr_rb.transfer);
+ } else {
+ RPC_IFACE null_interface;
+ ZERO_STRUCT(null_interface);
+ /* Rejection reason: abstract syntax not supported */
+ init_rpc_hdr_ba(&hdr_ba, MAX_PDU_FRAG_LEN,
+ MAX_PDU_FRAG_LEN, assoc_gid,
+ ack_pipe_name, 0x1, 0x2, 0x1,
+ &null_interface);
+ }
+
+ /*
+ * and marshall it.
+ */
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Now the authentication.
+ */
+
+ if (p->ntlmssp_auth_requested) {
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_CHAL ntlmssp_chal;
+
+ generate_random_buffer(p->challenge, 8, False);
+
+ /*** Authentication info ***/
+
+ init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err_exit;
+ }
+
+ /*** NTLMSSP verifier ***/
+
+ init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_CHALLENGE);
+ if(!smb_io_rpc_auth_verifier("", &auth_verifier, &out_auth, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n"));
+ goto err_exit;
+ }
+
+ /* NTLMSSP challenge ***/
+
+ init_rpc_auth_ntlmssp_chal(&ntlmssp_chal, p->ntlmssp_chal_flags, p->challenge);
+ if(!smb_io_rpc_auth_ntlmssp_chal("", &ntlmssp_chal, &out_auth, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_NTLMSSP_CHAL failed.\n"));
+ goto err_exit;
+ }
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
+ }
+
+ /*
+ * Create the header, now we know the length.
+ */
+
+ init_rpc_hdr(&p->hdr, reply_pkt_type, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id,
+ RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
+ auth_len);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("pi_pipe_bind_req: marshalling of RPC_HDR failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Now add the RPC_HDR_BA and any auth needed.
+ */
+
+ if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) {
+ DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ if(p->ntlmssp_auth_requested && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
+ DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
+ goto err_exit;
+ }
+
+ if(!p->ntlmssp_auth_requested)
+ p->pipe_bound = True;
+
+ /*
+ * Setup the lengths for the initial reply.
+ */
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
+ return True;
+
+ err_exit:
+
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+ return False;
+}
+
+/****************************************************************************
+ Deal with sign & seal processing on an RPC request.
+****************************************************************************/
+
+BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in)
+{
+ /*
+ * We always negotiate the following two bits....
+ */
+ BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0);
+ int data_len;
+ int auth_len;
+ uint32 old_offset;
+ uint32 crc32 = 0;
+
+ auth_len = p->hdr.auth_len;
+
+ if ((auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) && auth_verify) {
+ DEBUG(0,("api_pipe_auth_process: Incorrect auth_len %d.\n", auth_len ));
+ return False;
+ }
+
+ /*
+ * The following is that length of the data we must verify or unseal.
+ * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
+ * preceeding the auth_data.
+ */
+
+ data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len;
+
+ DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n",
+ BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len));
+
+ if (auth_seal) {
+ /*
+ * The data in rpc_in doesn't contain the RPC_HEADER as this
+ * has already been consumed.
+ */
+ char *data = prs_data_p(rpc_in) + RPC_HDR_REQ_LEN;
+ NTLMSSPcalc_p(p, (uchar*)data, data_len);
+ crc32 = crc32_calc_buffer(data, data_len);
+ }
+
+ old_offset = prs_offset(rpc_in);
+
+ if (auth_seal || auth_verify) {
+ RPC_HDR_AUTH auth_info;
+
+ if(!prs_set_offset(rpc_in, old_offset + data_len)) {
+ DEBUG(0,("api_pipe_auth_process: cannot move offset to %u.\n",
+ (unsigned int)old_offset + data_len ));
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
+ DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+ }
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK ntlmssp_chk;
+ char *req_data = prs_data_p(rpc_in) + prs_offset(rpc_in) + 4;
+
+ DEBUG(5,("api_pipe_auth_process: auth %d\n", prs_offset(rpc_in) + 4));
+
+ /*
+ * Ensure we have RPC_AUTH_NTLMSSP_CHK_LEN - 4 more bytes in the
+ * incoming buffer.
+ */
+ if(prs_mem_get(rpc_in, RPC_AUTH_NTLMSSP_CHK_LEN - 4) == NULL) {
+ DEBUG(0,("api_pipe_auth_process: missing %d bytes in buffer.\n",
+ RPC_AUTH_NTLMSSP_CHK_LEN - 4 ));
+ return False;
+ }
+
+ NTLMSSPcalc_p(p, (uchar*)req_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, rpc_in, 0)) {
+ DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_AUTH_NTLMSSP_CHK.\n"));
+ return False;
+ }
+
+ if (!rpc_auth_ntlmssp_chk(&ntlmssp_chk, crc32, p->ntlmssp_seq_num)) {
+ DEBUG(0,("api_pipe_auth_process: NTLMSSP check failed.\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Return the current pointer to the data offset.
+ */
+
+ if(!prs_set_offset(rpc_in, old_offset)) {
+ DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n",
+ (unsigned int)old_offset ));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Return a user struct for a pipe user.
+****************************************************************************/
+
+struct current_user *get_current_user(struct current_user *user, pipes_struct *p)
+{
+ if (p->ntlmssp_auth_validated) {
+ memcpy(user, &p->pipe_user, sizeof(struct current_user));
+ } else {
+ extern struct current_user current_user;
+ memcpy(user, &current_user, sizeof(struct current_user));
+ }
+
+ return user;
+}
+
+/****************************************************************************
+ Find the correct RPC function to call for this request.
+ If the pipe is authenticated then become the correct UNIX user
+ before doing the call.
+****************************************************************************/
+
+BOOL api_pipe_request(pipes_struct *p)
+{
+ int i = 0;
+ BOOL ret = False;
+
+ if (p->ntlmssp_auth_validated) {
+
+ if(!become_authenticated_pipe_user(p)) {
+ prs_mem_free(&p->out_data.rdata);
+ return False;
+ }
+ }
+
+ for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) {
+ if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
+ api_fd_commands[i].fn != NULL) {
+ DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name));
+ set_current_rpc_talloc(p->mem_ctx);
+ ret = api_fd_commands[i].fn(p);
+ set_current_rpc_talloc(NULL);
+ }
+ }
+
+ if(p->ntlmssp_auth_validated)
+ unbecome_authenticated_pipe_user();
+
+ return ret;
+}
+
+/*******************************************************************
+ Calls the underlying RPC function for a named pipe.
+ ********************************************************************/
+
+BOOL api_rpcTNP(pipes_struct *p, char *rpc_name,
+ struct api_struct *api_rpc_cmds)
+{
+ int fn_num;
+ fstring name;
+ uint32 offset1, offset2;
+
+ /* interpret the command */
+ DEBUG(4,("api_rpcTNP: %s op 0x%x - ", rpc_name, p->hdr_req.opnum));
+
+ slprintf(name, sizeof(name)-1, "in_%s", rpc_name);
+ prs_dump(name, p->hdr_req.opnum, &p->in_data.data);
+
+ for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) {
+ if (api_rpc_cmds[fn_num].opnum == p->hdr_req.opnum && api_rpc_cmds[fn_num].fn != NULL) {
+ DEBUG(3,("api_rpcTNP: rpc command: %s\n", api_rpc_cmds[fn_num].name));
+ break;
+ }
+ }
+
+ if (api_rpc_cmds[fn_num].name == NULL) {
+ /*
+ * For an unknown RPC just return a fault PDU but
+ * return True to allow RPC's on the pipe to continue
+ * and not put the pipe into fault state. JRA.
+ */
+ DEBUG(4, ("unknown\n"));
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ return True;
+ }
+
+ offset1 = prs_offset(&p->out_data.rdata);
+
+ /* do the actual command */
+ if(!api_rpc_cmds[fn_num].fn(p)) {
+ DEBUG(0,("api_rpcTNP: %s: %s failed.\n", rpc_name, api_rpc_cmds[fn_num].name));
+ prs_mem_free(&p->out_data.rdata);
+ return False;
+ }
+
+ slprintf(name, sizeof(name)-1, "out_%s", rpc_name);
+ offset2 = prs_offset(&p->out_data.rdata);
+ prs_set_offset(&p->out_data.rdata, offset1);
+ prs_dump(name, p->hdr_req.opnum, &p->out_data.rdata);
+ prs_set_offset(&p->out_data.rdata, offset2);
+
+ DEBUG(5,("api_rpcTNP: called %s successfully\n", rpc_name));
+
+ /* Check for buffer underflow in rpc parsing */
+
+ if ((DEBUGLEVEL >= 10) &&
+ (p->in_data.data.data_offset != p->in_data.data.buffer_size)) {
+ int data_len = p->in_data.data.buffer_size -
+ p->in_data.data.data_offset;
+ char *data;
+
+ data = malloc(data_len);
+
+ DEBUG(10, ("api_rpcTNP: rpc input buffer underflow (parse error?)\n"));
+ if (data) {
+ prs_uint8s(False, "", &p->in_data.data, 0, (unsigned char *)data,
+ data_len);
+ SAFE_FREE(data);
+ }
+
+ }
+
+ return True;
+}
diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c
new file mode 100644
index 00000000000..cc6415cce7c
--- /dev/null
+++ b/source/rpc_server/srv_pipe_hnd.c
@@ -0,0 +1,968 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+static pipes_struct *chain_p;
+static int pipes_open;
+
+#ifndef MAX_OPEN_PIPES
+#define MAX_OPEN_PIPES 2048
+#endif
+
+static pipes_struct *Pipes;
+static struct bitmap *bmap;
+
+/****************************************************************************
+ Pipe iterator functions.
+****************************************************************************/
+
+pipes_struct *get_first_pipe(void)
+{
+ return Pipes;
+}
+
+pipes_struct *get_next_pipe(pipes_struct *p)
+{
+ return p->next;
+}
+
+/* this must be larger than the sum of the open files and directories */
+static int pipe_handle_offset;
+
+/****************************************************************************
+ Set the pipe_handle_offset. Called from smbd/files.c
+****************************************************************************/
+
+void set_pipe_handle_offset(int max_open_files)
+{
+ if(max_open_files < 0x7000)
+ pipe_handle_offset = 0x7000;
+ else
+ pipe_handle_offset = max_open_files + 10; /* For safety. :-) */
+}
+
+/****************************************************************************
+ Reset pipe chain handle number.
+****************************************************************************/
+void reset_chain_p(void)
+{
+ chain_p = NULL;
+}
+
+/****************************************************************************
+ Initialise pipe handle states.
+****************************************************************************/
+
+void init_rpc_pipe_hnd(void)
+{
+ bmap = bitmap_allocate(MAX_OPEN_PIPES);
+ if (!bmap)
+ exit_server("out of memory in init_rpc_pipe_hnd");
+}
+
+/****************************************************************************
+ Initialise an outgoing packet.
+****************************************************************************/
+
+static BOOL pipe_init_outgoing_data(pipes_struct *p)
+{
+ output_data *o_data = &p->out_data;
+
+ /* Reset the offset counters. */
+ o_data->data_sent_length = 0;
+ o_data->current_pdu_len = 0;
+ o_data->current_pdu_sent = 0;
+
+ memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu));
+
+ /* Free any memory in the current return data buffer. */
+ prs_mem_free(&o_data->rdata);
+
+ /*
+ * Initialize the outgoing RPC data buffer.
+ * we will use this as the raw data area for replying to rpc requests.
+ */
+ if(!prs_init(&o_data->rdata, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Find first available pipe slot.
+****************************************************************************/
+
+pipes_struct *open_rpc_pipe_p(char *pipe_name,
+ connection_struct *conn, uint16 vuid)
+{
+ int i;
+ pipes_struct *p;
+ static int next_pipe;
+
+ DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
+ pipe_name, pipes_open));
+
+
+ /* not repeating pipe numbers makes it easier to track things in
+ log files and prevents client bugs where pipe numbers are reused
+ over connection restarts */
+ if (next_pipe == 0)
+ next_pipe = (sys_getpid() ^ time(NULL)) % MAX_OPEN_PIPES;
+
+ i = bitmap_find(bmap, next_pipe);
+
+ if (i == -1) {
+ DEBUG(0,("ERROR! Out of pipe structures\n"));
+ return NULL;
+ }
+
+ next_pipe = (i+1) % MAX_OPEN_PIPES;
+
+ for (p = Pipes; p; p = p->next)
+ DEBUG(5,("open_rpc_pipe_p: name %s pnum=%x\n", p->name, p->pnum));
+
+ p = (pipes_struct *)malloc(sizeof(*p));
+
+ if (!p)
+ return NULL;
+
+ ZERO_STRUCTP(p);
+
+ if ((p->mem_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+ if (!init_pipe_handle_list(p, pipe_name)) {
+ DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
+ talloc_destroy(p->mem_ctx);
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+
+ DLIST_ADD(Pipes, p);
+
+ /*
+ * Initialize the incoming RPC data buffer with one PDU worth of memory.
+ * We cheat here and say we're marshalling, as we intend to add incoming
+ * data directly into the prs_struct and we want it to auto grow. We will
+ * change the type to UNMARSALLING before processing the stream.
+ */
+
+ if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
+ return NULL;
+ }
+
+ bitmap_set(bmap, i);
+ i += pipe_handle_offset;
+
+ pipes_open++;
+
+ p->pnum = i;
+
+ p->open = True;
+ p->device_state = 0;
+ p->priority = 0;
+ p->conn = conn;
+ p->vuid = vuid;
+
+ p->max_trans_reply = 0;
+
+ p->ntlmssp_chal_flags = 0;
+ p->ntlmssp_auth_validated = False;
+ p->ntlmssp_auth_requested = False;
+
+ p->pipe_bound = False;
+ p->fault_state = False;
+ p->endian = RPC_LITTLE_ENDIAN;
+
+ /*
+ * Initialize the incoming RPC struct.
+ */
+
+ p->in_data.pdu_needed_len = 0;
+ p->in_data.pdu_received_len = 0;
+
+ /*
+ * Initialize the outgoing RPC struct.
+ */
+
+ p->out_data.current_pdu_len = 0;
+ p->out_data.current_pdu_sent = 0;
+ p->out_data.data_sent_length = 0;
+
+ /*
+ * Initialize the outgoing RPC data buffer with no memory.
+ */
+ prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL);
+
+ ZERO_STRUCT(p->pipe_user);
+
+ p->pipe_user.uid = (uid_t)-1;
+ p->pipe_user.gid = (gid_t)-1;
+
+ fstrcpy(p->name, pipe_name);
+
+ DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n",
+ pipe_name, i, pipes_open));
+
+ chain_p = p;
+
+ /* OVERWRITE p as a temp variable, to display all open pipes */
+ for (p = Pipes; p; p = p->next)
+ DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));
+
+ return chain_p;
+}
+
+/****************************************************************************
+ Sets the fault state on incoming packets.
+****************************************************************************/
+
+static void set_incoming_fault(pipes_struct *p)
+{
+ prs_mem_free(&p->in_data.data);
+ p->in_data.pdu_needed_len = 0;
+ p->in_data.pdu_received_len = 0;
+ p->fault_state = True;
+ DEBUG(10,("set_incoming_fault: Setting fault state on pipe %s : pnum = 0x%x\n",
+ p->name, p->pnum ));
+}
+
+/****************************************************************************
+ Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer.
+****************************************************************************/
+
+static ssize_t fill_rpc_header(pipes_struct *p, char *data, size_t data_to_copy)
+{
+ size_t len_needed_to_complete_hdr = MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu_received_len);
+
+ DEBUG(10,("fill_rpc_header: data_to_copy = %u, len_needed_to_complete_hdr = %u, receive_len = %u\n",
+ (unsigned int)data_to_copy, (unsigned int)len_needed_to_complete_hdr,
+ (unsigned int)p->in_data.pdu_received_len ));
+
+ memcpy((char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, len_needed_to_complete_hdr);
+ p->in_data.pdu_received_len += len_needed_to_complete_hdr;
+
+ return (ssize_t)len_needed_to_complete_hdr;
+}
+
+/****************************************************************************
+ Unmarshalls a new PDU header. Assumes the raw header data is in current_in_pdu.
+****************************************************************************/
+
+static ssize_t unmarshall_rpc_header(pipes_struct *p)
+{
+ /*
+ * Unmarshall the header to determine the needed length.
+ */
+
+ prs_struct rpc_in;
+
+ if(p->in_data.pdu_received_len != RPC_HEADER_LEN) {
+ DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n"));
+ set_incoming_fault(p);
+ return -1;
+ }
+
+ prs_init( &rpc_in, 0, p->mem_ctx, UNMARSHALL);
+ prs_set_endian_data( &rpc_in, p->endian);
+
+ prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0],
+ p->in_data.pdu_received_len, False);
+
+ /*
+ * Unmarshall the header as this will tell us how much
+ * data we need to read to get the complete pdu.
+ * This also sets the endian flag in rpc_in.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) {
+ DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * Validate the RPC header.
+ */
+
+ if(p->hdr.major != 5 && p->hdr.minor != 0) {
+ DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * If there's not data in the incoming buffer this should be the start of a new RPC.
+ */
+
+ if(prs_offset(&p->in_data.data) == 0) {
+
+ /*
+ * AS/U doesn't set FIRST flag in a BIND packet it seems.
+ */
+
+ if ((p->hdr.pkt_type == RPC_REQUEST) && !(p->hdr.flags & RPC_FLG_FIRST)) {
+ /*
+ * Ensure that the FIRST flag is set. If not then we have
+ * a stream missmatch.
+ */
+
+ DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ /*
+ * If this is the first PDU then set the endianness
+ * flag in the pipe. We will need this when parsing all
+ * data in this RPC.
+ */
+
+ p->endian = rpc_in.bigendian_data;
+
+ DEBUG(5,("unmarshall_rpc_header: using %sendian RPC\n",
+ p->endian == RPC_LITTLE_ENDIAN ? "little-" : "big-" ));
+
+ } else {
+
+ /*
+ * If this is *NOT* the first PDU then check the endianness
+ * flag in the pipe is the same as that in the PDU.
+ */
+
+ if (p->endian != rpc_in.bigendian_data) {
+ DEBUG(0,("unmarshall_rpc_header: FIRST endianness flag (%d) different in next PDU !\n", (int)p->endian));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+ }
+
+ /*
+ * Ensure that the pdu length is sane.
+ */
+
+ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) {
+ DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n"));
+ set_incoming_fault(p);
+ prs_mem_free(&rpc_in);
+ return -1;
+ }
+
+ DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type,
+ (unsigned int)p->hdr.flags ));
+
+ /*
+ * Adjust for the header we just ate.
+ */
+ p->in_data.pdu_received_len = 0;
+ p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN;
+
+ /*
+ * Null the data we just ate.
+ */
+
+ memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN);
+
+ prs_mem_free(&rpc_in);
+
+ return 0; /* No extra data processed. */
+}
+
+/****************************************************************************
+ Call this to free any talloc'ed memory. Do this before and after processing
+ a complete PDU.
+****************************************************************************/
+
+void free_pipe_context(pipes_struct *p)
+{
+ if (p->mem_ctx) {
+ DEBUG(3,("free_pipe_context: destroying talloc pool of size %u\n", talloc_pool_size(p->mem_ctx) ));
+ talloc_destroy_pool(p->mem_ctx);
+ } else {
+ p->mem_ctx = talloc_init();
+ if (p->mem_ctx == NULL)
+ p->fault_state = True;
+ }
+}
+
+/****************************************************************************
+ Processes a request pdu. This will do auth processing if needed, and
+ appends the data into the complete stream if the LAST flag is not set.
+****************************************************************************/
+
+static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
+
+ if(!p->pipe_bound) {
+ DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Check if we need to do authentication processing.
+ * This is only done on requests, not binds.
+ */
+
+ /*
+ * Read the RPC request header.
+ */
+
+ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) {
+ DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) {
+ DEBUG(0,("process_request_pdu: failed to do auth processing.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) {
+
+ /*
+ * Authentication _was_ requested and it already failed.
+ */
+
+ DEBUG(0,("process_request_pdu: RPC request received on pipe %s where \
+authentication failed. Denying the request.\n", p->name));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Check the data length doesn't go over the 10Mb limit.
+ */
+
+ if(prs_data_size(&p->in_data.data) + data_len > 10*1024*1024) {
+ DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n",
+ (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len ));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Append the data portion into the buffer and return.
+ */
+
+ {
+ char *data_from = prs_data_p(rpc_in_p) + prs_offset(rpc_in_p);
+
+ if(!prs_append_data(&p->in_data.data, data_from, data_len)) {
+ DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n",
+ (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) ));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ }
+
+ if(p->hdr.flags & RPC_FLG_LAST) {
+ BOOL ret = False;
+ /*
+ * Ok - we finally have a complete RPC stream.
+ * Call the rpc command to process it.
+ */
+
+ /*
+ * Ensure the internal prs buffer size is *exactly* the same
+ * size as the current offset.
+ */
+
+ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data)))
+ {
+ DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+
+ /*
+ * Set the parse offset to the start of the data and set the
+ * prs_struct to UNMARSHALL.
+ */
+
+ prs_set_offset(&p->in_data.data, 0);
+ prs_switch_type(&p->in_data.data, UNMARSHALL);
+
+ /*
+ * Process the complete data stream here.
+ */
+
+ free_pipe_context(p);
+
+ if(pipe_init_outgoing_data(p))
+ ret = api_pipe_request(p);
+
+ free_pipe_context(p);
+
+ /*
+ * We have consumed the whole data stream. Set back to
+ * marshalling and set the offset back to the start of
+ * the buffer to re-use it (we could also do a prs_mem_free()
+ * and then re_init on the next start of PDU. Not sure which
+ * is best here.... JRA.
+ */
+
+ prs_switch_type(&p->in_data.data, MARSHALL);
+ prs_set_offset(&p->in_data.data, 0);
+ return ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Processes a finished PDU stored in current_in_pdu. The RPC_HEADER has
+ already been parsed and stored in p->hdr.
+****************************************************************************/
+
+static ssize_t process_complete_pdu(pipes_struct *p)
+{
+ prs_struct rpc_in;
+ size_t data_len = p->in_data.pdu_received_len;
+ char *data_p = (char *)&p->in_data.current_in_pdu[0];
+ BOOL reply = False;
+
+ if(p->fault_state) {
+ DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n",
+ p->name ));
+ set_incoming_fault(p);
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ return (ssize_t)data_len;
+ }
+
+ prs_init( &rpc_in, 0, p->mem_ctx, UNMARSHALL);
+
+ /*
+ * Ensure we're using the corrent endianness for both the
+ * RPC header flags and the raw data we will be reading from.
+ */
+
+ prs_set_endian_data( &rpc_in, p->endian);
+ prs_set_endian_data( &p->in_data.data, p->endian);
+
+ prs_give_memory( &rpc_in, data_p, (uint32)data_len, False);
+
+ DEBUG(10,("process_complete_pdu: processing packet type %u\n",
+ (unsigned int)p->hdr.pkt_type ));
+
+ switch (p->hdr.pkt_type) {
+ case RPC_BIND:
+ case RPC_ALTCONT:
+ /*
+ * We assume that a pipe bind is only in one pdu.
+ */
+ if(pipe_init_outgoing_data(p))
+ reply = api_pipe_bind_req(p, &rpc_in);
+ break;
+ case RPC_BINDRESP:
+ /*
+ * We assume that a pipe bind_resp is only in one pdu.
+ */
+ if(pipe_init_outgoing_data(p))
+ reply = api_pipe_bind_auth_resp(p, &rpc_in);
+ break;
+ case RPC_REQUEST:
+ reply = process_request_pdu(p, &rpc_in);
+ break;
+ default:
+ DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type ));
+ break;
+ }
+
+ /* Reset to little endian. Probably don't need this but it won't hurt. */
+ prs_set_endian_data( &p->in_data.data, RPC_LITTLE_ENDIAN);
+
+ if (!reply) {
+ DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name));
+ set_incoming_fault(p);
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ prs_mem_free(&rpc_in);
+ } else {
+ /*
+ * Reset the lengths. We're ready for a new pdu.
+ */
+ p->in_data.pdu_needed_len = 0;
+ p->in_data.pdu_received_len = 0;
+ }
+
+ prs_mem_free(&rpc_in);
+ return (ssize_t)data_len;
+}
+
+/****************************************************************************
+ Accepts incoming data on an rpc pipe. Processes the data in pdu sized units.
+****************************************************************************/
+
+static ssize_t process_incoming_data(pipes_struct *p, char *data, size_t n)
+{
+ size_t data_to_copy = MIN(n, MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len);
+
+ DEBUG(10,("process_incoming_data: Start: pdu_received_len = %u, pdu_needed_len = %u, incoming data = %u\n",
+ (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len,
+ (unsigned int)n ));
+
+ if(data_to_copy == 0) {
+ /*
+ * This is an error - data is being received and there is no
+ * space in the PDU. Free the received data and go into the fault state.
+ */
+ DEBUG(0,("process_incoming_data: No space in incoming pdu buffer. Current size = %u \
+incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned int)n ));
+ set_incoming_fault(p);
+ return -1;
+ }
+
+ /*
+ * If we have no data already, wait until we get at least a RPC_HEADER_LEN
+ * number of bytes before we can do anything.
+ */
+
+ if((p->in_data.pdu_needed_len == 0) && (p->in_data.pdu_received_len < RPC_HEADER_LEN)) {
+ /*
+ * Always return here. If we have more data then the RPC_HEADER
+ * will be processed the next time around the loop.
+ */
+ return fill_rpc_header(p, data, data_to_copy);
+ }
+
+ /*
+ * At this point we know we have at least an RPC_HEADER_LEN amount of data
+ * stored in current_in_pdu.
+ */
+
+ /*
+ * If pdu_needed_len is zero this is a new pdu.
+ * Unmarshall the header so we know how much more
+ * data we need, then loop again.
+ */
+
+ if(p->in_data.pdu_needed_len == 0)
+ return unmarshall_rpc_header(p);
+
+ /*
+ * Ok - at this point we have a valid RPC_HEADER in p->hdr.
+ * Keep reading until we have a full pdu.
+ */
+
+ data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len);
+
+ /*
+ * Copy as much of the data as we need into the current_in_pdu buffer.
+ */
+
+ memcpy( (char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, data_to_copy);
+ p->in_data.pdu_received_len += data_to_copy;
+
+ /*
+ * Do we have a complete PDU ?
+ */
+
+ if(p->in_data.pdu_received_len == p->in_data.pdu_needed_len)
+ return process_complete_pdu(p);
+
+ DEBUG(10,("process_incoming_data: not a complete PDU yet. pdu_received_len = %u, pdu_needed_len = %u\n",
+ (unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len ));
+
+ return (ssize_t)data_to_copy;
+
+}
+
+/****************************************************************************
+ Accepts incoming data on an rpc pipe.
+****************************************************************************/
+
+ssize_t write_to_pipe(pipes_struct *p, char *data, size_t n)
+{
+ size_t data_left = n;
+
+ DEBUG(6,("write_to_pipe: %x", p->pnum));
+
+ DEBUG(6,(" name: %s open: %s len: %d\n",
+ p->name, BOOLSTR(p->open), (int)n));
+
+ dump_data(50, data, n);
+
+ while(data_left) {
+ ssize_t data_used;
+
+ DEBUG(10,("write_to_pipe: data_left = %u\n", (unsigned int)data_left ));
+
+ data_used = process_incoming_data(p, data, data_left);
+
+ DEBUG(10,("write_to_pipe: data_used = %d\n", (int)data_used ));
+
+ if(data_used < 0)
+ return -1;
+
+ data_left -= data_used;
+ data += data_used;
+ }
+
+ return n;
+}
+
+/****************************************************************************
+ Replies to a request to read data from a pipe.
+
+ Headers are interspersed with the data at PDU intervals. By the time
+ this function is called, the start of the data could possibly have been
+ read by an SMBtrans (file_offset != 0).
+
+ Calling create_rpc_reply() here is a hack. The data should already
+ have been prepared into arrays of headers + data stream sections.
+****************************************************************************/
+
+ssize_t read_from_pipe(pipes_struct *p, char *data, size_t n)
+{
+ uint32 pdu_remaining = 0;
+ ssize_t data_returned = 0;
+
+ if (!p || !p->open) {
+ DEBUG(0,("read_from_pipe: pipe not open\n"));
+ return -1;
+ }
+
+ DEBUG(6,("read_from_pipe: %x", p->pnum));
+
+ DEBUG(6,(" name: %s len: %u\n", p->name, (unsigned int)n));
+
+ /*
+ * We cannot return more than one PDU length per
+ * read request.
+ */
+
+ /*
+ * This condition should result in the connection being closed.
+ * Netapp filers seem to set it to 0xffff which results in domain
+ * authentications failing. Just ignore it so things work.
+ */
+
+ if(n > MAX_PDU_FRAG_LEN) {
+ DEBUG(5,("read_from_pipe: too large read (%u) requested on \
+pipe %s. We can only service %d sized reads.\n", (unsigned int)n, p->name, MAX_PDU_FRAG_LEN ));
+ }
+
+ /*
+ * Determine if there is still data to send in the
+ * pipe PDU buffer. Always send this first. Never
+ * send more than is left in the current PDU. The
+ * client should send a new read request for a new
+ * PDU.
+ */
+
+ if((pdu_remaining = p->out_data.current_pdu_len - p->out_data.current_pdu_sent) > 0) {
+ data_returned = (ssize_t)MIN(n, pdu_remaining);
+
+ DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, current_pdu_sent = %u \
+returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len,
+ (unsigned int)p->out_data.current_pdu_sent, (int)data_returned));
+
+ memcpy( data, &p->out_data.current_pdu[p->out_data.current_pdu_sent], (size_t)data_returned);
+ p->out_data.current_pdu_sent += (uint32)data_returned;
+ goto out;
+ }
+
+ /*
+ * At this point p->current_pdu_len == p->current_pdu_sent (which
+ * may of course be zero if this is the first return fragment.
+ */
+
+ DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length \
+= %u, prs_offset(&p->out_data.rdata) = %u.\n",
+ p->name, (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) ));
+
+ if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) {
+ /*
+ * We have sent all possible data, return 0.
+ */
+ data_returned = 0;
+ goto out;
+ }
+
+ /*
+ * We need to create a new PDU from the data left in p->rdata.
+ * Create the header/data/footers. This also sets up the fields
+ * p->current_pdu_len, p->current_pdu_sent, p->data_sent_length
+ * and stores the outgoing PDU in p->current_pdu.
+ */
+
+ if(!create_next_pdu(p)) {
+ DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n", p->name));
+ return -1;
+ }
+
+ data_returned = MIN(n, p->out_data.current_pdu_len);
+
+ memcpy( data, p->out_data.current_pdu, (size_t)data_returned);
+ p->out_data.current_pdu_sent += (uint32)data_returned;
+
+ out:
+
+ return data_returned;
+}
+
+/****************************************************************************
+ Wait device state on a pipe. Exactly what this is for is unknown...
+****************************************************************************/
+
+BOOL wait_rpc_pipe_hnd_state(pipes_struct *p, uint16 priority)
+{
+ if (p == NULL)
+ return False;
+
+ if (p->open) {
+ DEBUG(3,("wait_rpc_pipe_hnd_state: Setting pipe wait state priority=%x on pipe (name=%s)\n",
+ priority, p->name));
+
+ p->priority = priority;
+
+ return True;
+ }
+
+ DEBUG(3,("wait_rpc_pipe_hnd_state: Error setting pipe wait state priority=%x (name=%s)\n",
+ priority, p->name));
+ return False;
+}
+
+
+/****************************************************************************
+ Set device state on a pipe. Exactly what this is for is unknown...
+****************************************************************************/
+
+BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state)
+{
+ if (p == NULL)
+ return False;
+
+ if (p->open) {
+ DEBUG(3,("set_rpc_pipe_hnd_state: Setting pipe device state=%x on pipe (name=%s)\n",
+ device_state, p->name));
+
+ p->device_state = device_state;
+
+ return True;
+ }
+
+ DEBUG(3,("set_rpc_pipe_hnd_state: Error setting pipe device state=%x (name=%s)\n",
+ device_state, p->name));
+ return False;
+}
+
+
+/****************************************************************************
+ Close an rpc pipe.
+****************************************************************************/
+
+BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn)
+{
+ if (!p) {
+ DEBUG(0,("Invalid pipe in close_rpc_pipe_hnd\n"));
+ return False;
+ }
+
+ prs_mem_free(&p->out_data.rdata);
+ prs_mem_free(&p->in_data.data);
+
+ if (p->mem_ctx)
+ talloc_destroy(p->mem_ctx);
+
+ /* Free the handles database. */
+ close_policy_by_pipe(p);
+
+ bitmap_clear(bmap, p->pnum - pipe_handle_offset);
+
+ pipes_open--;
+
+ DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n",
+ p->name, p->pnum, pipes_open));
+
+ DLIST_REMOVE(Pipes, p);
+
+ delete_nt_token(&p->pipe_user.nt_user_token);
+ SAFE_FREE(p->pipe_user.groups);
+
+ ZERO_STRUCTP(p);
+
+ SAFE_FREE(p);
+
+ return True;
+}
+
+/****************************************************************************
+ Find an rpc pipe given a pipe handle in a buffer and an offset.
+****************************************************************************/
+
+pipes_struct *get_rpc_pipe_p(char *buf, int where)
+{
+ int pnum = SVAL(buf,where);
+
+ if (chain_p)
+ return chain_p;
+
+ return get_rpc_pipe(pnum);
+}
+
+/****************************************************************************
+ Find an rpc pipe given a pipe handle.
+****************************************************************************/
+
+pipes_struct *get_rpc_pipe(int pnum)
+{
+ pipes_struct *p;
+
+ DEBUG(4,("search for pipe pnum=%x\n", pnum));
+
+ for (p=Pipes;p;p=p->next)
+ DEBUG(5,("pipe name %s pnum=%x (pipes_open=%d)\n",
+ p->name, p->pnum, pipes_open));
+
+ for (p=Pipes;p;p=p->next) {
+ if (p->pnum == pnum) {
+ chain_p = p;
+ return p;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/rpc_server/srv_reg.c b/source/rpc_server/srv_reg.c
new file mode 100644
index 00000000000..1280dc4aa9d
--- /dev/null
+++ b/source/rpc_server/srv_reg.c
@@ -0,0 +1,209 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Marc Jacobsen 2000.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface for the registry functions. */
+
+#include "includes.h"
+
+/*******************************************************************
+ api_reg_close
+ ********************************************************************/
+
+static BOOL api_reg_close(pipes_struct *p)
+{
+ REG_Q_CLOSE q_u;
+ REG_R_CLOSE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg unknown 1 */
+ if(!reg_io_q_close("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_close(p, &q_u, &r_u);
+
+ if(!reg_io_r_close("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_open
+ ********************************************************************/
+
+static BOOL api_reg_open(pipes_struct *p)
+{
+ REG_Q_OPEN_HKLM q_u;
+ REG_R_OPEN_HKLM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg open */
+ if(!reg_io_q_open_hklm("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_open(p, &q_u, &r_u);
+
+ if(!reg_io_r_open_hklm("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_open_entry
+ ********************************************************************/
+
+static BOOL api_reg_open_entry(pipes_struct *p)
+{
+ REG_Q_OPEN_ENTRY q_u;
+ REG_R_OPEN_ENTRY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg open entry */
+ if(!reg_io_q_open_entry("", &q_u, data, 0))
+ return False;
+
+ /* construct reply. */
+ r_u.status = _reg_open_entry(p, &q_u, &r_u);
+
+ if(!reg_io_r_open_entry("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_info
+ ********************************************************************/
+
+static BOOL api_reg_info(pipes_struct *p)
+{
+ REG_Q_INFO q_u;
+ REG_R_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg unknown 0x11*/
+ if(!reg_io_q_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_info(p, &q_u, &r_u);
+
+ if(!reg_io_r_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_shutdown
+ ********************************************************************/
+
+static BOOL api_reg_shutdown(pipes_struct *p)
+{
+ REG_Q_SHUTDOWN q_u;
+ REG_R_SHUTDOWN r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg shutdown */
+ if(!reg_io_q_shutdown("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_shutdown(p, &q_u, &r_u);
+
+ if(!reg_io_r_shutdown("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_abort_shutdown
+ ********************************************************************/
+
+static BOOL api_reg_abort_shutdown(pipes_struct *p)
+{
+ REG_Q_ABORT_SHUTDOWN q_u;
+ REG_R_ABORT_SHUTDOWN r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg shutdown */
+ if(!reg_io_q_abort_shutdown("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_abort_shutdown(p, &q_u, &r_u);
+
+ if(!reg_io_r_abort_shutdown("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ array of \PIPE\reg operations
+ ********************************************************************/
+static struct api_struct api_reg_cmds[] =
+{
+ { "REG_CLOSE" , REG_CLOSE , api_reg_close },
+ { "REG_OPEN_ENTRY" , REG_OPEN_ENTRY , api_reg_open_entry },
+ { "REG_OPEN" , REG_OPEN_HKLM , api_reg_open },
+ { "REG_INFO" , REG_INFO , api_reg_info },
+ { "REG_SHUTDOWN" , REG_SHUTDOWN , api_reg_shutdown },
+ { "REG_ABORT_SHUTDOWN", REG_ABORT_SHUTDOWN, api_reg_abort_shutdown },
+ { NULL, 0 , NULL }
+};
+
+/*******************************************************************
+ receives a reg pipe and responds.
+ ********************************************************************/
+
+BOOL api_reg_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_reg_rpc", api_reg_cmds);
+}
diff --git a/source/rpc_server/srv_reg_nt.c b/source/rpc_server/srv_reg_nt.c
new file mode 100644
index 00000000000..d934083e6bd
--- /dev/null
+++ b/source/rpc_server/srv_reg_nt.c
@@ -0,0 +1,238 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Hewlett-Packard Company 1999.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Implementation of registry functions. */
+
+#include "includes.h"
+
+struct reg_info
+{
+ /* for use by \PIPE\winreg */
+ fstring name; /* name of registry key */
+};
+
+static void free_reg_info(void *ptr)
+{
+ struct reg_info *info = (struct reg_info *)ptr;
+
+ SAFE_FREE(info);
+}
+
+/*******************************************************************
+ reg_reply_unknown_1
+ ********************************************************************/
+
+NTSTATUS _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
+{
+ /* set up the REG unknown_1 response */
+ ZERO_STRUCT(r_u->pol);
+
+ /* close the policy handle */
+ if (!close_policy_hnd(p, &q_u->pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ reg_reply_open
+ ********************************************************************/
+
+NTSTATUS _reg_open(pipes_struct *p, REG_Q_OPEN_HKLM *q_u, REG_R_OPEN_HKLM *r_u)
+{
+ if (!create_policy_hnd(p, &r_u->pol, free_reg_info, NULL))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ reg_reply_open_entry
+ ********************************************************************/
+
+NTSTATUS _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
+{
+ POLICY_HND pol;
+ fstring name;
+ struct reg_info *info = NULL;
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+
+ if (!find_policy_by_hnd(p, &q_u->pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ rpcstr_pull(name,q_u->uni_name.buffer,sizeof(name),q_u->uni_name.uni_str_len*2,0);
+
+ DEBUG(5,("reg_open_entry: %s\n", name));
+
+ /* lkcl XXXX do a check on the name, here */
+ if (!strequal(name, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions") &&
+ !strequal(name, "System\\CurrentControlSet\\services\\Netlogon\\parameters\\"))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if ((info = (struct reg_info *)malloc(sizeof(struct reg_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ fstrcpy(info->name, name);
+
+ if (!create_policy_hnd(p, &pol, free_reg_info, (void *)info))
+ return NT_STATUS_TOO_MANY_SECRETS; /* ha ha very droll */
+
+ init_reg_r_open_entry(r_u, &pol, NT_STATUS_OK);
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ reg_reply_info
+ ********************************************************************/
+
+NTSTATUS _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ char *key = NULL;
+ uint32 type=0x1; /* key type: REG_SZ */
+
+ UNISTR2 *uni_key = NULL;
+ BUFFER2 *buf = NULL;
+ fstring name;
+
+ DEBUG(5,("_reg_info: %d\n", __LINE__));
+
+ if (find_policy_by_hnd(p, &q_u->pol, NULL) == -1)
+ return NT_STATUS_INVALID_HANDLE;
+
+ rpcstr_pull(name, q_u->uni_type.buffer, sizeof(name), q_u->uni_type.uni_str_len*2, 0);
+
+ DEBUG(5,("reg_info: checking key: %s\n", name));
+
+ uni_key = (UNISTR2 *)talloc_zero(p->mem_ctx, sizeof(UNISTR2));
+ buf = (BUFFER2 *)talloc_zero(p->mem_ctx, sizeof(BUFFER2));
+
+ if (!uni_key || !buf)
+ return NT_STATUS_NO_MEMORY;
+
+ if ( strequal(name, "RefusePasswordChange") ) {
+ type=0xF770;
+ status = NT_STATUS_NO_SUCH_FILE;
+ init_unistr2(uni_key, "", 0);
+ init_buffer2(buf, (uint8*) uni_key->buffer, uni_key->uni_str_len*2);
+
+ buf->buf_max_len=4;
+
+ goto out;
+ }
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ key = "LanmanNT";
+ break;
+ case ROLE_STANDALONE:
+ key = "ServerNT";
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ key = "WinNT";
+ break;
+ }
+
+ /* This makes the server look like a member server to clients */
+ /* which tells clients that we have our own local user and */
+ /* group databases and helps with ACL support. */
+
+ init_unistr2(uni_key, key, strlen(key)+1);
+ init_buffer2(buf, (uint8*)uni_key->buffer, uni_key->uni_str_len*2);
+
+ out:
+ init_reg_r_info(q_u->ptr_buf, r_u, buf, type, status);
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+
+ return status;
+}
+
+/*******************************************************************
+ reg_shutdwon
+ ********************************************************************/
+
+#define SHUTDOWN_R_STRING "-r"
+#define SHUTDOWN_F_STRING "-f"
+
+
+NTSTATUS _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ pstring shutdown_script;
+ UNISTR2 unimsg = q_u->uni_msg;
+ pstring message;
+ pstring chkmsg;
+ fstring timeout;
+ fstring r;
+ fstring f;
+
+ /* message */
+ rpcstr_pull (message, unimsg.buffer, sizeof(message), unimsg.uni_str_len*2,0);
+ /* security check */
+ alpha_strcpy (chkmsg, message, NULL, sizeof(message));
+ /* timeout */
+ snprintf(timeout, sizeof(timeout), "%d", q_u->timeout);
+ /* reboot */
+ snprintf(r, sizeof(r), (q_u->flags & 0x100)?SHUTDOWN_R_STRING:"");
+ /* force */
+ snprintf(f, sizeof(f), (q_u->flags & 0x001)?SHUTDOWN_F_STRING:"");
+
+ pstrcpy(shutdown_script, lp_shutdown_script());
+
+ if(*shutdown_script) {
+ int shutdown_ret;
+ all_string_sub(shutdown_script, "%m", chkmsg, sizeof(shutdown_script));
+ all_string_sub(shutdown_script, "%t", timeout, sizeof(shutdown_script));
+ all_string_sub(shutdown_script, "%r", r, sizeof(shutdown_script));
+ all_string_sub(shutdown_script, "%f", f, sizeof(shutdown_script));
+ shutdown_ret = smbrun(shutdown_script,NULL);
+ DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script,shutdown_ret));
+ }
+
+ return status;
+}
+
+NTSTATUS _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ pstring abort_shutdown_script;
+
+ pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
+
+ if(*abort_shutdown_script) {
+ int abort_shutdown_ret;
+ abort_shutdown_ret = smbrun(abort_shutdown_script,NULL);
+ DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script,abort_shutdown_ret));
+ }
+
+ return status;
+}
diff --git a/source/rpc_server/srv_samr.c b/source/rpc_server/srv_samr.c
new file mode 100644
index 00000000000..177ee51d25e
--- /dev/null
+++ b/source/rpc_server/srv_samr.c
@@ -0,0 +1,1442 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Marc Jacobsen 1999.
+ *
+ * Split into interface and implementation modules by,
+ *
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This is the interface to the SAMR code.
+ */
+
+#include "includes.h"
+
+/*******************************************************************
+ api_samr_close_hnd
+ ********************************************************************/
+
+static BOOL api_samr_close_hnd(pipes_struct *p)
+{
+ SAMR_Q_CLOSE_HND q_u;
+ SAMR_R_CLOSE_HND r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_close_hnd("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_close_hnd: unable to unmarshall SAMR_Q_CLOSE_HND.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_close_hnd(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_close_hnd("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_close_hnd: unable to marshall SAMR_R_CLOSE_HND.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_open_domain
+ ********************************************************************/
+
+static BOOL api_samr_open_domain(pipes_struct *p)
+{
+ SAMR_Q_OPEN_DOMAIN q_u;
+ SAMR_R_OPEN_DOMAIN r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_open_domain("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_open_domain: unable to unmarshall SAMR_Q_OPEN_DOMAIN.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_open_domain(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_open_domain("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_open_domain: unable to marshall SAMR_R_OPEN_DOMAIN.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_get_usrdom_pwinfo
+ ********************************************************************/
+
+static BOOL api_samr_get_usrdom_pwinfo(pipes_struct *p)
+{
+ SAMR_Q_GET_USRDOM_PWINFO q_u;
+ SAMR_R_GET_USRDOM_PWINFO r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_get_usrdom_pwinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_get_usrdom_pwinfo: unable to unmarshall SAMR_Q_GET_USRDOM_PWINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_get_usrdom_pwinfo(p, &q_u, &r_u);
+
+ if(!samr_io_r_get_usrdom_pwinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_get_usrdom_pwinfo: unable to marshall SAMR_R_GET_USRDOM_PWINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_sec_obj
+ ********************************************************************/
+
+static BOOL api_samr_query_sec_obj(pipes_struct *p)
+{
+ SAMR_Q_QUERY_SEC_OBJ q_u;
+ SAMR_R_QUERY_SEC_OBJ r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_query_sec_obj("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_sec_obj: unable to unmarshall SAMR_Q_QUERY_SEC_OBJ.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_sec_obj(p, &q_u, &r_u);
+
+ if(!samr_io_r_query_sec_obj("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_sec_obj: unable to marshall SAMR_R_QUERY_SEC_OBJ.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_enum_dom_users
+ ********************************************************************/
+
+static BOOL api_samr_enum_dom_users(pipes_struct *p)
+{
+ SAMR_Q_ENUM_DOM_USERS q_u;
+ SAMR_R_ENUM_DOM_USERS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open */
+ if(!samr_io_q_enum_dom_users("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_enum_dom_users: unable to unmarshall SAMR_Q_ENUM_DOM_USERS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_enum_dom_users(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_enum_dom_users("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_enum_dom_users: unable to marshall SAMR_R_ENUM_DOM_USERS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_enum_dom_groups
+ ********************************************************************/
+
+static BOOL api_samr_enum_dom_groups(pipes_struct *p)
+{
+ SAMR_Q_ENUM_DOM_GROUPS q_u;
+ SAMR_R_ENUM_DOM_GROUPS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open */
+ if(!samr_io_q_enum_dom_groups("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_enum_dom_groups: unable to unmarshall SAMR_Q_ENUM_DOM_GROUPS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_enum_dom_groups(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_enum_dom_groups("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_enum_dom_groups: unable to marshall SAMR_R_ENUM_DOM_GROUPS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_enum_dom_aliases
+ ********************************************************************/
+
+static BOOL api_samr_enum_dom_aliases(pipes_struct *p)
+{
+ SAMR_Q_ENUM_DOM_ALIASES q_u;
+ SAMR_R_ENUM_DOM_ALIASES r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open */
+ if(!samr_io_q_enum_dom_aliases("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_enum_dom_aliases: unable to unmarshall SAMR_Q_ENUM_DOM_ALIASES.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_enum_dom_aliases(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_enum_dom_aliases("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_enum_dom_aliases: unable to marshall SAMR_R_ENUM_DOM_ALIASES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_dispinfo
+ ********************************************************************/
+
+static BOOL api_samr_query_dispinfo(pipes_struct *p)
+{
+ SAMR_Q_QUERY_DISPINFO q_u;
+ SAMR_R_QUERY_DISPINFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_query_dispinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_dispinfo: unable to unmarshall SAMR_Q_QUERY_DISPINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_dispinfo(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_query_dispinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_dispinfo: unable to marshall SAMR_R_QUERY_DISPINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_aliasinfo
+ ********************************************************************/
+
+static BOOL api_samr_query_aliasinfo(pipes_struct *p)
+{
+ SAMR_Q_QUERY_ALIASINFO q_u;
+ SAMR_R_QUERY_ALIASINFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open */
+ if(!samr_io_q_query_aliasinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_aliasinfo: unable to unmarshall SAMR_Q_QUERY_ALIASINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_aliasinfo(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_query_aliasinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_aliasinfo: unable to marshall SAMR_R_QUERY_ALIASINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_lookup_names
+ ********************************************************************/
+
+static BOOL api_samr_lookup_names(pipes_struct *p)
+{
+ SAMR_Q_LOOKUP_NAMES q_u;
+ SAMR_R_LOOKUP_NAMES r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr lookup names */
+ if(!samr_io_q_lookup_names("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_lookup_names: unable to unmarshall SAMR_Q_LOOKUP_NAMES.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_lookup_names(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_lookup_names("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_lookup_names: unable to marshall SAMR_R_LOOKUP_NAMES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_chgpasswd_user
+ ********************************************************************/
+
+static BOOL api_samr_chgpasswd_user(pipes_struct *p)
+{
+ SAMR_Q_CHGPASSWD_USER q_u;
+ SAMR_R_CHGPASSWD_USER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* unknown 38 command */
+ if (!samr_io_q_chgpasswd_user("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_chgpasswd_user: Failed to unmarshall SAMR_Q_CHGPASSWD_USER.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_chgpasswd_user(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_chgpasswd_user("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_chgpasswd_user: Failed to marshall SAMR_R_CHGPASSWD_USER.\n" ));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_lookup_rids
+ ********************************************************************/
+
+static BOOL api_samr_lookup_rids(pipes_struct *p)
+{
+ SAMR_Q_LOOKUP_RIDS q_u;
+ SAMR_R_LOOKUP_RIDS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr lookup names */
+ if(!samr_io_q_lookup_rids("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_lookup_rids: unable to unmarshall SAMR_Q_LOOKUP_RIDS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_lookup_rids(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_lookup_rids("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_lookup_rids: unable to marshall SAMR_R_LOOKUP_RIDS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_open_user
+ ********************************************************************/
+
+static BOOL api_samr_open_user(pipes_struct *p)
+{
+ SAMR_Q_OPEN_USER q_u;
+ SAMR_R_OPEN_USER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 22 */
+ if(!samr_io_q_open_user("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_open_user: unable to unmarshall SAMR_Q_OPEN_USER.\n"));
+ return False;
+ }
+
+ r_u.status = _api_samr_open_user(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_open_user("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_open_user: unable to marshall SAMR_R_OPEN_USER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_userinfo
+ ********************************************************************/
+
+static BOOL api_samr_query_userinfo(pipes_struct *p)
+{
+ SAMR_Q_QUERY_USERINFO q_u;
+ SAMR_R_QUERY_USERINFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 24 */
+ if(!samr_io_q_query_userinfo("", &q_u, data, 0)){
+ DEBUG(0,("api_samr_query_userinfo: unable to unmarshall SAMR_Q_QUERY_USERINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_userinfo(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_query_userinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_userinfo: unable to marshall SAMR_R_QUERY_USERINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_usergroups
+ ********************************************************************/
+
+static BOOL api_samr_query_usergroups(pipes_struct *p)
+{
+ SAMR_Q_QUERY_USERGROUPS q_u;
+ SAMR_R_QUERY_USERGROUPS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 32 */
+ if(!samr_io_q_query_usergroups("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_usergroups: unable to unmarshall SAMR_Q_QUERY_USERGROUPS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_usergroups(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_query_usergroups("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_usergroups: unable to marshall SAMR_R_QUERY_USERGROUPS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_dom_info
+ ********************************************************************/
+
+static BOOL api_samr_query_dom_info(pipes_struct *p)
+{
+ SAMR_Q_QUERY_DOMAIN_INFO q_u;
+ SAMR_R_QUERY_DOMAIN_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 8 command */
+ if(!samr_io_q_query_dom_info("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_dom_info: unable to unmarshall SAMR_Q_QUERY_DOMAIN_INFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_dom_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_query_dom_info("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_dom_info: unable to marshall SAMR_R_QUERY_DOMAIN_INFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_create_user
+ ********************************************************************/
+
+static BOOL api_samr_create_user(pipes_struct *p)
+{
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ SAMR_Q_CREATE_USER q_u;
+ SAMR_R_CREATE_USER r_u;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr create user */
+ if (!samr_io_q_create_user("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_create_user: Unable to unmarshall SAMR_Q_CREATE_USER.\n"));
+ return False;
+ }
+
+ r_u.status=_api_samr_create_user(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_create_user("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_create_user: Unable to marshall SAMR_R_CREATE_USER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_connect_anon
+ ********************************************************************/
+
+static BOOL api_samr_connect_anon(pipes_struct *p)
+{
+ SAMR_Q_CONNECT_ANON q_u;
+ SAMR_R_CONNECT_ANON r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open policy */
+ if(!samr_io_q_connect_anon("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_connect_anon: unable to unmarshall SAMR_Q_CONNECT_ANON.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_connect_anon(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_connect_anon("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_connect_anon: unable to marshall SAMR_R_CONNECT_ANON.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_connect
+ ********************************************************************/
+
+static BOOL api_samr_connect(pipes_struct *p)
+{
+ SAMR_Q_CONNECT q_u;
+ SAMR_R_CONNECT r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open policy */
+ if(!samr_io_q_connect("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_connect: unable to unmarshall SAMR_Q_CONNECT.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_connect(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_connect("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_connect: unable to marshall SAMR_R_CONNECT.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/**********************************************************************
+ api_samr_lookup_domain
+ **********************************************************************/
+
+static BOOL api_samr_lookup_domain(pipes_struct *p)
+{
+ SAMR_Q_LOOKUP_DOMAIN q_u;
+ SAMR_R_LOOKUP_DOMAIN r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_lookup_domain("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_lookup_domain: Unable to unmarshall SAMR_Q_LOOKUP_DOMAIN.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_lookup_domain(p, &q_u, &r_u);
+
+ if(!samr_io_r_lookup_domain("", &r_u, rdata, 0)){
+ DEBUG(0,("api_samr_lookup_domain: Unable to marshall SAMR_R_LOOKUP_DOMAIN.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/**********************************************************************
+ api_samr_enum_domains
+ **********************************************************************/
+
+static BOOL api_samr_enum_domains(pipes_struct *p)
+{
+ SAMR_Q_ENUM_DOMAINS q_u;
+ SAMR_R_ENUM_DOMAINS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_enum_domains("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_enum_domains: Unable to unmarshall SAMR_Q_ENUM_DOMAINS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_enum_domains(p, &q_u, &r_u);
+
+ if(!samr_io_r_enum_domains("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_enum_domains: Unable to marshall SAMR_R_ENUM_DOMAINS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_open_alias
+ ********************************************************************/
+
+static BOOL api_samr_open_alias(pipes_struct *p)
+{
+ SAMR_Q_OPEN_ALIAS q_u;
+ SAMR_R_OPEN_ALIAS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr open policy */
+ if(!samr_io_q_open_alias("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_open_alias: Unable to unmarshall SAMR_Q_OPEN_ALIAS.\n"));
+ return False;
+ }
+
+ r_u.status=_api_samr_open_alias(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_open_alias("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_open_alias: Unable to marshall SAMR_R_OPEN_ALIAS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_set_userinfo
+ ********************************************************************/
+
+static BOOL api_samr_set_userinfo(pipes_struct *p)
+{
+ SAMR_Q_SET_USERINFO q_u;
+ SAMR_R_SET_USERINFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_set_userinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_set_userinfo: Unable to unmarshall SAMR_Q_SET_USERINFO.\n"));
+ /* Fix for W2K SP2 */
+ if (q_u.switch_value == 0x1a) {
+ setup_fault_pdu(p, NT_STATUS(0x1c000006));
+ return True;
+ }
+ return False;
+ }
+
+ r_u.status = _samr_set_userinfo(p, &q_u, &r_u);
+
+ if(!samr_io_r_set_userinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_set_userinfo: Unable to marshall SAMR_R_SET_USERINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_set_userinfo2
+ ********************************************************************/
+
+static BOOL api_samr_set_userinfo2(pipes_struct *p)
+{
+ SAMR_Q_SET_USERINFO2 q_u;
+ SAMR_R_SET_USERINFO2 r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_set_userinfo2("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_set_userinfo2: Unable to unmarshall SAMR_Q_SET_USERINFO2.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_set_userinfo2(p, &q_u, &r_u);
+
+ if(!samr_io_r_set_userinfo2("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_set_userinfo2: Unable to marshall SAMR_R_SET_USERINFO2.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_useraliases
+ ********************************************************************/
+
+static BOOL api_samr_query_useraliases(pipes_struct *p)
+{
+ SAMR_Q_QUERY_USERALIASES q_u;
+ SAMR_R_QUERY_USERALIASES r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_query_useraliases("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_useraliases: Unable to unmarshall SAMR_Q_QUERY_USERALIASES.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_useraliases(p, &q_u, &r_u);
+
+ if (! samr_io_r_query_useraliases("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_useraliases: Unable to nmarshall SAMR_R_QUERY_USERALIASES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_aliasmem
+ ********************************************************************/
+
+static BOOL api_samr_query_aliasmem(pipes_struct *p)
+{
+ SAMR_Q_QUERY_ALIASMEM q_u;
+ SAMR_R_QUERY_ALIASMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_query_aliasmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_aliasmem: unable to unmarshall SAMR_Q_QUERY_ALIASMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_aliasmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_query_aliasmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_aliasmem: unable to marshall SAMR_R_QUERY_ALIASMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_groupmem
+ ********************************************************************/
+
+static BOOL api_samr_query_groupmem(pipes_struct *p)
+{
+ SAMR_Q_QUERY_GROUPMEM q_u;
+ SAMR_R_QUERY_GROUPMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_query_groupmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_groupmem: unable to unmarshall SAMR_Q_QUERY_GROUPMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_groupmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_query_groupmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_groupmem: unable to marshall SAMR_R_QUERY_GROUPMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_add_aliasmem
+ ********************************************************************/
+
+static BOOL api_samr_add_aliasmem(pipes_struct *p)
+{
+ SAMR_Q_ADD_ALIASMEM q_u;
+ SAMR_R_ADD_ALIASMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_add_aliasmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_add_aliasmem: unable to unmarshall SAMR_Q_ADD_ALIASMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_add_aliasmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_add_aliasmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_add_aliasmem: unable to marshall SAMR_R_ADD_ALIASMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_del_aliasmem
+ ********************************************************************/
+
+static BOOL api_samr_del_aliasmem(pipes_struct *p)
+{
+ SAMR_Q_DEL_ALIASMEM q_u;
+ SAMR_R_DEL_ALIASMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_del_aliasmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_del_aliasmem: unable to unmarshall SAMR_Q_DEL_ALIASMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_del_aliasmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_del_aliasmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_del_aliasmem: unable to marshall SAMR_R_DEL_ALIASMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_add_groupmem
+ ********************************************************************/
+
+static BOOL api_samr_add_groupmem(pipes_struct *p)
+{
+ SAMR_Q_ADD_GROUPMEM q_u;
+ SAMR_R_ADD_GROUPMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_add_groupmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_add_groupmem: unable to unmarshall SAMR_Q_ADD_GROUPMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_add_groupmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_add_groupmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_add_groupmem: unable to marshall SAMR_R_ADD_GROUPMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_del_groupmem
+ ********************************************************************/
+
+static BOOL api_samr_del_groupmem(pipes_struct *p)
+{
+ SAMR_Q_DEL_GROUPMEM q_u;
+ SAMR_R_DEL_GROUPMEM r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_del_groupmem("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_del_groupmem: unable to unmarshall SAMR_Q_DEL_GROUPMEM.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_del_groupmem(p, &q_u, &r_u);
+
+ if (!samr_io_r_del_groupmem("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_del_groupmem: unable to marshall SAMR_R_DEL_GROUPMEM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_delete_dom_user
+ ********************************************************************/
+
+static BOOL api_samr_delete_dom_user(pipes_struct *p)
+{
+ SAMR_Q_DELETE_DOM_USER q_u;
+ SAMR_R_DELETE_DOM_USER r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_delete_dom_user("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_delete_dom_user: unable to unmarshall SAMR_Q_DELETE_DOM_USER.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_delete_dom_user(p, &q_u, &r_u);
+
+ if (!samr_io_r_delete_dom_user("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_delete_dom_user: unable to marshall SAMR_R_DELETE_DOM_USER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_delete_dom_group
+ ********************************************************************/
+
+static BOOL api_samr_delete_dom_group(pipes_struct *p)
+{
+ SAMR_Q_DELETE_DOM_GROUP q_u;
+ SAMR_R_DELETE_DOM_GROUP r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_delete_dom_group("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_delete_dom_group: unable to unmarshall SAMR_Q_DELETE_DOM_GROUP.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_delete_dom_group(p, &q_u, &r_u);
+
+ if (!samr_io_r_delete_dom_group("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_delete_dom_group: unable to marshall SAMR_R_DELETE_DOM_GROUP.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_delete_dom_alias
+ ********************************************************************/
+
+static BOOL api_samr_delete_dom_alias(pipes_struct *p)
+{
+ SAMR_Q_DELETE_DOM_ALIAS q_u;
+ SAMR_R_DELETE_DOM_ALIAS r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_delete_dom_alias("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_delete_dom_alias: unable to unmarshall SAMR_Q_DELETE_DOM_ALIAS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_delete_dom_alias(p, &q_u, &r_u);
+
+ if (!samr_io_r_delete_dom_alias("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_delete_dom_alias: unable to marshall SAMR_R_DELETE_DOM_ALIAS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_create_dom_group
+ ********************************************************************/
+
+static BOOL api_samr_create_dom_group(pipes_struct *p)
+{
+ SAMR_Q_CREATE_DOM_GROUP q_u;
+ SAMR_R_CREATE_DOM_GROUP r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_create_dom_group("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_create_dom_group: unable to unmarshall SAMR_Q_CREATE_DOM_GROUP.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_create_dom_group(p, &q_u, &r_u);
+
+ if (!samr_io_r_create_dom_group("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_create_dom_group: unable to marshall SAMR_R_CREATE_DOM_GROUP.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_create_dom_alias
+ ********************************************************************/
+
+static BOOL api_samr_create_dom_alias(pipes_struct *p)
+{
+ SAMR_Q_CREATE_DOM_ALIAS q_u;
+ SAMR_R_CREATE_DOM_ALIAS r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_create_dom_alias("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_create_dom_alias: unable to unmarshall SAMR_Q_CREATE_DOM_ALIAS.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_create_dom_alias(p, &q_u, &r_u);
+
+ if (!samr_io_r_create_dom_alias("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_create_dom_alias: unable to marshall SAMR_R_CREATE_DOM_ALIAS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_groupinfo
+ ********************************************************************/
+
+static BOOL api_samr_query_groupinfo(pipes_struct *p)
+{
+ SAMR_Q_QUERY_GROUPINFO q_u;
+ SAMR_R_QUERY_GROUPINFO r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_query_groupinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_query_groupinfo: unable to unmarshall SAMR_Q_QUERY_GROUPINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_query_groupinfo(p, &q_u, &r_u);
+
+ if (!samr_io_r_query_groupinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_query_groupinfo: unable to marshall SAMR_R_QUERY_GROUPINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_set_groupinfo
+ ********************************************************************/
+
+static BOOL api_samr_set_groupinfo(pipes_struct *p)
+{
+ SAMR_Q_SET_GROUPINFO q_u;
+ SAMR_R_SET_GROUPINFO r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_set_groupinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_set_groupinfo: unable to unmarshall SAMR_Q_SET_GROUPINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_set_groupinfo(p, &q_u, &r_u);
+
+ if (!samr_io_r_set_groupinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_set_groupinfo: unable to marshall SAMR_R_SET_GROUPINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_set_aliasinfo
+ ********************************************************************/
+
+static BOOL api_samr_set_aliasinfo(pipes_struct *p)
+{
+ SAMR_Q_SET_ALIASINFO q_u;
+ SAMR_R_SET_ALIASINFO r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_set_aliasinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_set_aliasinfo: unable to unmarshall SAMR_Q_SET_ALIASINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_set_aliasinfo(p, &q_u, &r_u);
+
+ if (!samr_io_r_set_aliasinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_set_aliasinfo: unable to marshall SAMR_R_SET_ALIASINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_get_dom_pwinfo
+ ********************************************************************/
+
+static BOOL api_samr_get_dom_pwinfo(pipes_struct *p)
+{
+ SAMR_Q_GET_DOM_PWINFO q_u;
+ SAMR_R_GET_DOM_PWINFO r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_get_dom_pwinfo("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_get_dom_pwinfo: unable to unmarshall SAMR_Q_GET_DOM_PWINFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_get_dom_pwinfo(p, &q_u, &r_u);
+
+ if (!samr_io_r_get_dom_pwinfo("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_get_dom_pwinfo: unable to marshall SAMR_R_GET_DOM_PWINFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_open_group
+ ********************************************************************/
+
+static BOOL api_samr_open_group(pipes_struct *p)
+{
+ SAMR_Q_OPEN_GROUP q_u;
+ SAMR_R_OPEN_GROUP r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_open_group("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_open_group: unable to unmarshall SAMR_Q_OPEN_GROUP.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_open_group(p, &q_u, &r_u);
+
+ if (!samr_io_r_open_group("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_open_group: unable to marshall SAMR_R_OPEN_GROUP.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_unknown_2d
+ ********************************************************************/
+
+static BOOL api_samr_unknown_2d(pipes_struct *p)
+{
+ SAMR_Q_UNKNOWN_2D q_u;
+ SAMR_R_UNKNOWN_2D r_u;
+
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!samr_io_q_unknown_2d("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_unknown_2d: unable to unmarshall SAMR_Q_UNKNOWN_2D.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_unknown_2d(p, &q_u, &r_u);
+
+ if (!samr_io_r_unknown_2d("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_unknown_2d: unable to marshall SAMR_R_UNKNOWN_2D.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_query_dom_info
+ ********************************************************************/
+
+static BOOL api_samr_unknown_2e(pipes_struct *p)
+{
+ SAMR_Q_UNKNOWN_2E q_u;
+ SAMR_R_UNKNOWN_2E r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 8 command */
+ if(!samr_io_q_unknown_2e("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_unknown_2e: unable to unmarshall SAMR_Q_UNKNOWN_2E.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_unknown_2e(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_samr_unknown_2e("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_unknown_2e: unable to marshall SAMR_R_UNKNOWN_2E.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_samr_set_dom_info
+ ********************************************************************/
+
+static BOOL api_samr_set_dom_info(pipes_struct *p)
+{
+ SAMR_Q_SET_DOMAIN_INFO q_u;
+ SAMR_R_SET_DOMAIN_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the samr unknown 8 command */
+ if(!samr_io_q_set_domain_info("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_set_dom_info: unable to unmarshall SAMR_Q_SET_DOMAIN_INFO.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_set_dom_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_set_domain_info("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_set_dom_info: unable to marshall SAMR_R_SET_DOMAIN_INFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ array of \PIPE\samr operations
+ ********************************************************************/
+
+static struct api_struct api_samr_cmds [] =
+{
+ {"SAMR_CLOSE_HND" , SAMR_CLOSE_HND , api_samr_close_hnd },
+ {"SAMR_CONNECT" , SAMR_CONNECT , api_samr_connect },
+ {"SAMR_CONNECT_ANON" , SAMR_CONNECT_ANON , api_samr_connect_anon },
+ {"SAMR_ENUM_DOMAINS" , SAMR_ENUM_DOMAINS , api_samr_enum_domains },
+ {"SAMR_ENUM_DOM_USERS" , SAMR_ENUM_DOM_USERS , api_samr_enum_dom_users },
+
+ {"SAMR_ENUM_DOM_GROUPS" , SAMR_ENUM_DOM_GROUPS , api_samr_enum_dom_groups },
+ {"SAMR_ENUM_DOM_ALIASES" , SAMR_ENUM_DOM_ALIASES , api_samr_enum_dom_aliases },
+ {"SAMR_QUERY_USERALIASES" , SAMR_QUERY_USERALIASES, api_samr_query_useraliases},
+ {"SAMR_QUERY_ALIASMEM" , SAMR_QUERY_ALIASMEM , api_samr_query_aliasmem },
+ {"SAMR_QUERY_GROUPMEM" , SAMR_QUERY_GROUPMEM , api_samr_query_groupmem },
+ {"SAMR_ADD_ALIASMEM" , SAMR_ADD_ALIASMEM , api_samr_add_aliasmem },
+ {"SAMR_DEL_ALIASMEM" , SAMR_DEL_ALIASMEM , api_samr_del_aliasmem },
+ {"SAMR_ADD_GROUPMEM" , SAMR_ADD_GROUPMEM , api_samr_add_groupmem },
+ {"SAMR_DEL_GROUPMEM" , SAMR_DEL_GROUPMEM , api_samr_del_groupmem },
+
+ {"SAMR_DELETE_DOM_USER" , SAMR_DELETE_DOM_USER , api_samr_delete_dom_user },
+ {"SAMR_DELETE_DOM_GROUP" , SAMR_DELETE_DOM_GROUP , api_samr_delete_dom_group },
+ {"SAMR_DELETE_DOM_ALIAS" , SAMR_DELETE_DOM_ALIAS , api_samr_delete_dom_alias },
+ {"SAMR_CREATE_DOM_GROUP" , SAMR_CREATE_DOM_GROUP , api_samr_create_dom_group },
+ {"SAMR_CREATE_DOM_ALIAS" , SAMR_CREATE_DOM_ALIAS , api_samr_create_dom_alias },
+ {"SAMR_LOOKUP_NAMES" , SAMR_LOOKUP_NAMES , api_samr_lookup_names },
+ {"SAMR_OPEN_USER" , SAMR_OPEN_USER , api_samr_open_user },
+ {"SAMR_QUERY_USERINFO" , SAMR_QUERY_USERINFO , api_samr_query_userinfo },
+ {"SAMR_SET_USERINFO" , SAMR_SET_USERINFO , api_samr_set_userinfo },
+ {"SAMR_SET_USERINFO2" , SAMR_SET_USERINFO2 , api_samr_set_userinfo2 },
+
+ {"SAMR_QUERY_DOMAIN_INFO" , SAMR_QUERY_DOMAIN_INFO, api_samr_query_dom_info },
+ {"SAMR_QUERY_USERGROUPS" , SAMR_QUERY_USERGROUPS , api_samr_query_usergroups },
+ {"SAMR_QUERY_DISPINFO" , SAMR_QUERY_DISPINFO , api_samr_query_dispinfo },
+ {"SAMR_QUERY_DISPINFO3" , SAMR_QUERY_DISPINFO3 , api_samr_query_dispinfo },
+ {"SAMR_QUERY_DISPINFO4" , SAMR_QUERY_DISPINFO4 , api_samr_query_dispinfo },
+
+ {"SAMR_QUERY_ALIASINFO" , SAMR_QUERY_ALIASINFO , api_samr_query_aliasinfo },
+ {"SAMR_QUERY_GROUPINFO" , SAMR_QUERY_GROUPINFO , api_samr_query_groupinfo },
+ {"SAMR_SET_GROUPINFO" , SAMR_SET_GROUPINFO , api_samr_set_groupinfo },
+ {"SAMR_SET_ALIASINFO" , SAMR_SET_ALIASINFO , api_samr_set_aliasinfo },
+ {"SAMR_CREATE_USER" , SAMR_CREATE_USER , api_samr_create_user },
+ {"SAMR_LOOKUP_RIDS" , SAMR_LOOKUP_RIDS , api_samr_lookup_rids },
+ {"SAMR_GET_DOM_PWINFO" , SAMR_GET_DOM_PWINFO , api_samr_get_dom_pwinfo },
+ {"SAMR_CHGPASSWD_USER" , SAMR_CHGPASSWD_USER , api_samr_chgpasswd_user },
+ {"SAMR_OPEN_ALIAS" , SAMR_OPEN_ALIAS , api_samr_open_alias },
+ {"SAMR_OPEN_GROUP" , SAMR_OPEN_GROUP , api_samr_open_group },
+ {"SAMR_OPEN_DOMAIN" , SAMR_OPEN_DOMAIN , api_samr_open_domain },
+ {"SAMR_UNKNOWN_2D" , SAMR_UNKNOWN_2D , api_samr_unknown_2d },
+ {"SAMR_LOOKUP_DOMAIN" , SAMR_LOOKUP_DOMAIN , api_samr_lookup_domain },
+
+ {"SAMR_QUERY_SEC_OBJECT" , SAMR_QUERY_SEC_OBJECT , api_samr_query_sec_obj },
+ {"SAMR_GET_USRDOM_PWINFO" , SAMR_GET_USRDOM_PWINFO, api_samr_get_usrdom_pwinfo},
+ {"SAMR_UNKNOWN_2E" , SAMR_UNKNOWN_2E , api_samr_unknown_2e },
+ {"SAMR_SET_DOMAIN_INFO" , SAMR_SET_DOMAIN_INFO , api_samr_set_dom_info },
+ {NULL , 0 , NULL }
+};
+
+/*******************************************************************
+ receives a samr pipe and responds.
+ ********************************************************************/
+BOOL api_samr_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_samr_rpc", api_samr_cmds);
+}
diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c
new file mode 100644
index 00000000000..b918b4dca18
--- /dev/null
+++ b/source/rpc_server/srv_samr_nt.c
@@ -0,0 +1,3787 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Marc Jacobsen 1999.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This is the implementation of the SAMR code.
+ */
+
+#include "includes.h"
+
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+extern DOM_SID global_sam_sid;
+extern DOM_SID global_sid_Builtin;
+
+extern rid_name domain_group_rids[];
+extern rid_name domain_alias_rids[];
+extern rid_name builtin_alias_rids[];
+
+struct samr_info {
+ /* for use by the \PIPE\samr policy */
+ DOM_SID sid;
+ uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */
+};
+
+/*******************************************************************
+ Function to free the per handle data.
+ ********************************************************************/
+
+static void free_samr_info(void *ptr)
+{
+ SAFE_FREE(ptr);
+}
+
+/*******************************************************************
+ Ensure password info is never given out. Paranioa... JRA.
+ ********************************************************************/
+
+static void samr_clear_passwd_fields( SAM_USER_INFO_21 *pass, int num_entries)
+{
+ int i;
+
+ if (!pass)
+ return;
+
+ for (i = 0; i < num_entries; i++) {
+ memset(&pass[i].lm_pwd, '\0', sizeof(pass[i].lm_pwd));
+ memset(&pass[i].nt_pwd, '\0', sizeof(pass[i].nt_pwd));
+ }
+}
+
+static void samr_clear_sam_passwd(SAM_ACCOUNT *sam_pass)
+{
+ if (!sam_pass)
+ return;
+
+ if (sam_pass->lm_pw) memset(sam_pass->lm_pw, '\0', 16);
+ if (sam_pass->nt_pw) memset(sam_pass->nt_pw, '\0', 16);
+}
+
+/*******************************************************************
+ This next function should be replaced with something that
+ dynamically returns the correct user info..... JRA.
+ ********************************************************************/
+
+static NTSTATUS get_sampwd_entries(SAM_USER_INFO_21 *pw_buf, int start_idx,
+ int *total_entries, int *num_entries,
+ int max_num_entries, uint16 acb_mask)
+{
+ SAM_ACCOUNT *pwd = NULL;
+ BOOL not_finished = True;
+
+ (*num_entries) = 0;
+ (*total_entries) = 0;
+
+ if (pw_buf == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ pdb_init_sam(&pwd);
+
+ if (!pdb_setsampwent(False)) {
+ DEBUG(0, ("get_sampwd_entries: Unable to open passdb.\n"));
+ pdb_free_sam(&pwd);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ while (((not_finished = pdb_getsampwent(pwd)) != False)
+ && (*num_entries) < max_num_entries)
+ {
+ int user_name_len;
+
+ if (start_idx > 0) {
+
+ pdb_reset_sam(pwd);
+
+ /* skip the requested number of entries.
+ not very efficient, but hey... */
+ start_idx--;
+ continue;
+ }
+
+ user_name_len = strlen(pdb_get_username(pwd))+1;
+ init_unistr2(&pw_buf[(*num_entries)].uni_user_name, pdb_get_username(pwd), user_name_len);
+ init_uni_hdr(&pw_buf[(*num_entries)].hdr_user_name, user_name_len);
+ pw_buf[(*num_entries)].user_rid = pwd->user_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ /* Now check if the NT compatible password is available. */
+ if (pdb_get_nt_passwd(pwd))
+ memcpy( pw_buf[(*num_entries)].nt_pwd , pdb_get_nt_passwd(pwd), 16);
+
+ pw_buf[(*num_entries)].acb_info = pdb_get_acct_ctrl(pwd);
+
+ DEBUG(5, ("entry idx: %d user %s, rid 0x%x, acb %x",
+ (*num_entries), pdb_get_username(pwd), pdb_get_user_rid(pwd), pdb_get_acct_ctrl(pwd) ));
+
+ if (acb_mask == 0 || (pwd->acct_ctrl & acb_mask)) {
+ DEBUG(5,(" acb_mask %x accepts\n", acb_mask));
+ (*num_entries)++;
+ } else {
+ DEBUG(5,(" acb_mask %x rejects\n", acb_mask));
+ }
+
+ (*total_entries)++;
+
+ pdb_reset_sam(pwd);
+
+ }
+
+ pdb_endsampwent();
+ pdb_free_sam(&pwd);
+
+ if (not_finished)
+ return STATUS_MORE_ENTRIES;
+ else
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS jf_get_sampwd_entries(SAM_USER_INFO_21 *pw_buf, int start_idx,
+ int *total_entries, uint32 *num_entries,
+ int max_num_entries, uint16 acb_mask)
+{
+ SAM_ACCOUNT *pwd = NULL;
+ BOOL not_finished = True;
+
+ *num_entries = 0;
+ *total_entries = 0;
+
+ if (pw_buf == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ DEBUG(10,("jf_get_sampwd_entries: start index:%d, max entries:%d, mask:%d\n",
+ start_idx, max_num_entries, acb_mask));
+
+ if (!pdb_setsampwent(False)) {
+ DEBUG(0, ("jf_get_sampwd_entries: Unable to open passdb.\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ pdb_init_sam(&pwd);
+
+ while (((not_finished = pdb_getsampwent(pwd)) != False) && (*num_entries) < max_num_entries) {
+ int user_name_len;
+ int full_name_len;
+
+ if (acb_mask != 0 && !(pdb_get_acct_ctrl(pwd) & acb_mask)) {
+ pdb_reset_sam(pwd);
+ continue;
+ }
+
+ if (start_idx > 0) {
+ /* skip the requested number of entries.
+ not very efficient, but hey...
+ */
+ start_idx--;
+ pdb_reset_sam(pwd);
+ continue;
+ }
+
+ ZERO_STRUCTP(&pw_buf[(*num_entries)]);
+
+ user_name_len = strlen(pdb_get_username(pwd));
+ init_unistr2(&pw_buf[(*num_entries)].uni_user_name, pdb_get_username(pwd), user_name_len);
+ init_uni_hdr(&pw_buf[(*num_entries)].hdr_user_name, user_name_len);
+
+ full_name_len = strlen(pdb_get_fullname(pwd));
+ init_unistr2(&pw_buf[(*num_entries)].uni_full_name, pdb_get_fullname(pwd), full_name_len);
+ init_uni_hdr(&pw_buf[(*num_entries)].hdr_full_name, full_name_len);
+
+ pw_buf[(*num_entries)].user_rid = pdb_get_user_rid(pwd);
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ /* Now check if the NT compatible password is available. */
+ if (pdb_get_nt_passwd(pwd))
+ memcpy( pw_buf[(*num_entries)].nt_pwd , pdb_get_nt_passwd(pwd), 16);
+
+ pw_buf[(*num_entries)].acb_info = pdb_get_acct_ctrl(pwd);
+
+ DEBUG(5, ("entry idx: %d user %s, rid 0x%x, acb %x\n", (*num_entries),
+ pdb_get_username(pwd), pdb_get_user_rid(pwd), pdb_get_acct_ctrl(pwd) ));
+
+ (*num_entries)++;
+
+ pdb_reset_sam(pwd);
+ }
+
+ pdb_endsampwent();
+
+ *total_entries = *num_entries;
+
+ pdb_free_sam(&pwd);
+
+ if (not_finished)
+ return STATUS_MORE_ENTRIES;
+ else
+ return NT_STATUS_OK;
+}
+
+#if 0 /* This function appears to be unused! */
+
+/*******************************************************************
+ This function uses the username map file and tries to map a UNIX
+ user name to an DOS name. (Sort of the reverse of the
+ map_username() function.) Since more than one DOS name can map
+ to the UNIX name, to reverse the mapping you have to specify
+ which corresponding DOS name you want; that's where the name_idx
+ parameter comes in. Returns the string requested or NULL if it
+ fails or can't complete the request for any reason. This doesn't
+ handle group names (starting with '@') or names starting with
+ '+' or '&'. If they are encountered, they are skipped.
+********************************************************************/
+
+static char *unmap_unixname(char *unix_user_name, int name_idx)
+{
+ char *mapfile = lp_username_map();
+ char **lines;
+ static pstring tok;
+ int i;
+
+ if (!*unix_user_name) return NULL;
+ if (!*mapfile) return NULL;
+
+ lines = file_lines_load(mapfile, NULL);
+ if (!lines) {
+ DEBUG(0,("unmap_unixname: can't open username map %s\n", mapfile));
+ return NULL;
+ }
+
+ DEBUG(5,("unmap_unixname: scanning username map %s, index: %d\n", mapfile, name_idx));
+
+ for (i=0; lines[i]; i++) {
+ char *unixname = lines[i];
+ char *dosname = strchr_m(unixname,'=');
+
+ if (!dosname)
+ continue;
+
+ *dosname++ = 0;
+
+ while (isspace(*unixname))
+ unixname++;
+ if ('!' == *unixname) {
+ unixname++;
+ while (*unixname && isspace(*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr_m("#;",*unixname))
+ continue;
+
+ if (strncmp(unixname, unix_user_name, strlen(unix_user_name)))
+ continue;
+
+ /* We have matched the UNIX user name */
+
+ while(next_token(&dosname, tok, LIST_SEP, sizeof(tok))) {
+ if (!strchr_m("@&+", *tok)) {
+ name_idx--;
+ if (name_idx < 0 ) {
+ break;
+ }
+ }
+ }
+
+ if (name_idx >= 0) {
+ DEBUG(0,("unmap_unixname: index too high - not that many DOS names\n"));
+ file_lines_free(lines);
+ return NULL;
+ } else {
+ file_lines_free(lines);
+ return tok;
+ }
+ }
+
+ DEBUG(0,("unmap_unixname: Couldn't find the UNIX user name\n"));
+ file_lines_free(lines);
+ return NULL;
+}
+
+#endif /* Unused function */
+
+#if 0 /* This function seems to be not used anywhere! */
+
+/*******************************************************************
+ This function sets up a list of users taken from the list of
+ users that UNIX knows about, as well as all the user names that
+ Samba maps to a valid UNIX user name. (This should work with
+ /etc/passwd or NIS.)
+********************************************************************/
+
+static BOOL get_passwd_entries(SAM_USER_INFO_21 *pw_buf,
+ int start_idx,
+ int *total_entries, int *num_entries,
+ int max_num_entries,
+ uint16 acb_mask)
+{
+ static struct passwd *pwd = NULL;
+ static uint32 pw_rid;
+ static BOOL orig_done = False;
+ static int current_idx = 0;
+ static int mapped_idx = 0;
+ char *sep;
+
+ DEBUG(5, ("get_passwd_entries: retrieving a list of UNIX users\n"));
+
+ (*num_entries) = 0;
+ (*total_entries) = 0;
+
+ /* Skip all this stuff if we're in appliance mode */
+
+ if (lp_hide_local_users()) goto done;
+
+ if (pw_buf == NULL) return False;
+
+ if (current_idx == 0) {
+ sys_setpwent();
+ }
+
+ /* These two cases are inefficient, but should be called very rarely */
+ /* they are the cases where the starting index isn't picking up */
+ /* where we left off last time. It is efficient when it starts over */
+ /* at zero though. */
+ if (start_idx > current_idx) {
+ /* We aren't far enough; advance to start_idx */
+ while (current_idx <= start_idx) {
+ char *unmap_name;
+
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+ current_idx++;
+ orig_done = True;
+ }
+
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (current_idx < start_idx)) {
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+ } else if (start_idx < current_idx) {
+ /* We are already too far; start over and advance to start_idx */
+ sys_endpwent();
+ sys_setpwent();
+ current_idx = 0;
+ mapped_idx = 0;
+ orig_done = False;
+ while (current_idx < start_idx) {
+ char *unmap_name;
+
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+ current_idx++;
+ orig_done = True;
+ }
+
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (current_idx < start_idx)) {
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+ }
+
+ sep = lp_winbind_separator();
+
+ /* now current_idx == start_idx */
+ while ((*num_entries) < max_num_entries) {
+ int user_name_len;
+ char *unmap_name;
+
+ /* This does the original UNIX user itself */
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+
+ /* Don't enumerate winbind users as they are not local */
+
+ if (strchr_m(pwd->pw_name, *sep) != NULL) {
+ continue;
+ }
+
+ user_name_len = strlen(pwd->pw_name);
+
+ /* skip the trust account stored in the /etc/passwd file */
+ if (pwd->pw_name[user_name_len-1]=='$')
+ continue;
+
+ pw_rid = pdb_uid_to_user_rid(pwd->pw_uid);
+ ZERO_STRUCTP(&pw_buf[(*num_entries)]);
+ init_unistr2(&pw_buf[(*num_entries)].uni_user_name, pwd->pw_name, user_name_len);
+ init_uni_hdr(&pw_buf[(*num_entries)].hdr_user_name, user_name_len);
+ pw_buf[(*num_entries)].user_rid = pw_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ pw_buf[(*num_entries)].acb_info = ACB_NORMAL;
+
+ DEBUG(5, ("get_passwd_entries: entry idx %d user %s, rid 0x%x\n", (*num_entries), pwd->pw_name, pw_rid));
+
+ (*num_entries)++;
+ (*total_entries)++;
+ current_idx++;
+ orig_done = True;
+ }
+
+ /* This does all the user names that map to the UNIX user */
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (*num_entries < max_num_entries)) {
+ user_name_len = strlen(unmap_name);
+ ZERO_STRUCTP(&pw_buf[(*num_entries)]);
+ init_unistr2(&pw_buf[(*num_entries)].uni_user_name, unmap_name, user_name_len);
+ init_uni_hdr(&pw_buf[(*num_entries)].hdr_user_name, user_name_len);
+ pw_buf[(*num_entries)].user_rid = pw_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ pw_buf[(*num_entries)].acb_info = ACB_NORMAL;
+
+ DEBUG(5, ("get_passwd_entries: entry idx %d user %s, rid 0x%x\n", (*num_entries), pwd->pw_name, pw_rid));
+
+ (*num_entries)++;
+ (*total_entries)++;
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ /* done with 'aliases', go on to next UNIX user */
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+
+ if (pwd == NULL) {
+ /* totally done, reset everything */
+ sys_endpwent();
+ current_idx = 0;
+ mapped_idx = 0;
+ }
+
+done:
+ return (*num_entries) > 0;
+}
+
+#endif /* Unused function */
+
+/*******************************************************************
+ _samr_close_hnd
+ ********************************************************************/
+
+NTSTATUS _samr_close_hnd(pipes_struct *p, SAMR_Q_CLOSE_HND *q_u, SAMR_R_CLOSE_HND *r_u)
+{
+ r_u->status = NT_STATUS_OK;
+
+ /* close the policy handle */
+ if (!close_policy_hnd(p, &q_u->pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_open_domain
+ ********************************************************************/
+
+NTSTATUS _samr_open_domain(pipes_struct *p, SAMR_Q_OPEN_DOMAIN *q_u, SAMR_R_OPEN_DOMAIN *r_u)
+{
+ struct samr_info *info;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the connection policy handle. */
+ if (!find_policy_by_hnd(p, &q_u->pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* associate the domain SID with the (unique) handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = q_u->dom_sid.sid;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->domain_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("samr_open_domain: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _samr_get_usrdom_pwinfo
+ ********************************************************************/
+
+NTSTATUS _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u, SAMR_R_GET_USRDOM_PWINFO *r_u)
+{
+ struct samr_info *info = NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->user_pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_in_our_domain(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ init_samr_r_get_usrdom_pwinfo(r_u, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_get_usrdom_pwinfo: %d\n", __LINE__));
+
+ /*
+ * NT sometimes return NT_STATUS_ACCESS_DENIED
+ * I don't know yet why.
+ */
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_make_usr_obj_sd
+ ********************************************************************/
+
+static NTSTATUS samr_make_usr_obj_sd(TALLOC_CTX *ctx, SEC_DESC_BUF **buf, DOM_SID *usr_sid)
+{
+ extern DOM_SID global_sid_World;
+ DOM_SID adm_sid;
+ DOM_SID act_sid;
+
+ SEC_ACE ace[4];
+ SEC_ACCESS mask;
+
+ SEC_ACL *psa = NULL;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+
+ sid_copy(&adm_sid, &global_sid_Builtin);
+ sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
+
+ sid_copy(&act_sid, &global_sid_Builtin);
+ sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
+
+ init_sec_access(&mask, 0x2035b);
+ init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ init_sec_access(&mask, 0xf07ff);
+ init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+ init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ init_sec_access(&mask,0x20044);
+ init_sec_ace(&ace[3], usr_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+
+ if((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 4, ace)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if((psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, &sd_size)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if((*buf = make_sec_desc_buf(ctx, sd_size, psd)) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+static BOOL get_lsa_policy_samr_sid(pipes_struct *p, POLICY_HND *pol, DOM_SID *sid)
+{
+ struct samr_info *info = NULL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, pol, (void **)&info))
+ return False;
+
+ if (!info)
+ return False;
+
+ *sid = info->sid;
+ return True;
+}
+
+/*******************************************************************
+ _samr_query_sec_obj
+ ********************************************************************/
+
+NTSTATUS _samr_query_sec_obj(pipes_struct *p, SAMR_Q_QUERY_SEC_OBJ *q_u, SAMR_R_QUERY_SEC_OBJ *r_u)
+{
+ DOM_SID pol_sid;
+ fstring str_sid;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* Get the SID. */
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->user_pol, &pol_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(10,("_samr_query_sec_obj: querying security on SID: %s\n", sid_to_string(str_sid, &pol_sid)));
+
+ r_u->status = samr_make_usr_obj_sd(p->mem_ctx, &r_u->buf, &pol_sid);
+
+ if (NT_STATUS_IS_OK(r_u->status))
+ r_u->ptr = 1;
+
+ return r_u->status;
+}
+
+/*******************************************************************
+makes a SAM_ENTRY / UNISTR2* structure from a user list.
+********************************************************************/
+
+static void make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp,
+ uint32 num_sam_entries, SAM_USER_INFO_21 *pass)
+{
+ uint32 i;
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_name;
+
+ *sam_pp = NULL;
+ *uni_name_pp = NULL;
+
+ if (num_sam_entries == 0)
+ return;
+
+ sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_sam_entries);
+
+ uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_sam_entries);
+
+ if (sam == NULL || uni_name == NULL) {
+ DEBUG(0, ("NULL pointers in SAMR_R_QUERY_DISPINFO\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(sam);
+ ZERO_STRUCTP(uni_name);
+
+ for (i = 0; i < num_sam_entries; i++) {
+ int len = pass[i].uni_user_name.uni_str_len;
+
+ init_sam_entry(&sam[i], len, pass[i].user_rid);
+ copy_unistr2(&uni_name[i], &pass[i].uni_user_name);
+ }
+
+ *sam_pp = sam;
+ *uni_name_pp = uni_name;
+}
+
+/*******************************************************************
+ samr_reply_enum_dom_users
+ ********************************************************************/
+
+NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, SAMR_R_ENUM_DOM_USERS *r_u)
+{
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries = 0;
+ int total_entries = 0;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
+
+ become_root();
+ r_u->status = get_sampwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
+ MAX_SAM_ENTRIES, q_u->acb_mask);
+ unbecome_root();
+
+ if (NT_STATUS_IS_ERR(r_u->status))
+ return r_u->status;
+
+ samr_clear_passwd_fields(pass, num_entries);
+
+ /*
+ * Note from JRA. total_entries is not being used here. Currently if there is a
+ * large user base then it looks like NT will enumerate until get_sampwd_entries
+ * returns False due to num_entries being zero. This will cause an access denied
+ * return. I don't think this is right and needs further investigation. Note that
+ * this is also the same in the TNG code (I don't think that has been tested with
+ * a very large user list as MAX_SAM_ENTRIES is set to 600).
+ *
+ * I also think that one of the 'num_entries' return parameters is probably
+ * the "max entries" parameter - but in the TNG code they're all currently set to the same
+ * value (again I think this is wrong).
+ */
+
+ make_user_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_acct_name, num_entries, pass);
+
+ init_samr_r_enum_dom_users(r_u, q_u->start_idx + num_entries, num_entries);
+
+ DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+makes a SAM_ENTRY / UNISTR2* structure from a group list.
+********************************************************************/
+
+static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp,
+ uint32 num_sam_entries, DOMAIN_GRP *grp)
+{
+ uint32 i;
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_name;
+
+ *sam_pp = NULL;
+ *uni_name_pp = NULL;
+
+ if (num_sam_entries == 0)
+ return;
+
+ sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_sam_entries);
+
+ uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_sam_entries);
+
+ if (sam == NULL || uni_name == NULL) {
+ DEBUG(0, ("NULL pointers in SAMR_R_QUERY_DISPINFO\n"));
+ return;
+ }
+
+ for (i = 0; i < num_sam_entries; i++) {
+ /*
+ * JRA. I think this should include the null. TNG does not.
+ */
+ int len = strlen(grp[i].name)+1;
+
+ init_sam_entry(&sam[i], len, grp[i].rid);
+ init_unistr2(&uni_name[i], grp[i].name, len);
+ }
+
+ *sam_pp = sam;
+ *uni_name_pp = uni_name;
+}
+
+/*******************************************************************
+ Get the group entries - similar to get_sampwd_entries().
+ ********************************************************************/
+
+static NTSTATUS get_group_alias_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx,
+ uint32 *p_num_entries, uint32 max_entries)
+{
+ fstring sid_str;
+ uint32 num_entries = 0;
+ int i;
+ GROUP_MAP smap;
+ GROUP_MAP *map;
+
+ sid_to_string(sid_str, sid);
+ DEBUG(5, ("get_group_alias_entries: enumerating aliases on SID: %s\n", sid_str));
+
+ *p_num_entries = 0;
+
+ /* well-known aliases */
+ if (sid_equal(sid, &global_sid_Builtin) && !lp_hide_local_users()) {
+
+ enum_group_mapping(SID_NAME_ALIAS, &map, (int *)&num_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV);
+
+ if (num_entries != 0) {
+ *d_grp=(DOMAIN_GRP *)talloc_zero(ctx, num_entries*sizeof(DOMAIN_GRP));
+ if (*d_grp==NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ for(i=0; i<num_entries && i<max_entries; i++) {
+ fstrcpy((*d_grp)[i].name, map[i+start_idx].nt_name);
+ sid_split_rid(&map[i+start_idx].sid, &(*d_grp)[i].rid);
+
+ }
+ }
+ SAFE_FREE(map);
+
+ } else if (sid_equal(sid, &global_sam_sid) && !lp_hide_local_users()) {
+ char *sep;
+ struct sys_grent *glist;
+ struct sys_grent *grp;
+
+ sep = lp_winbind_separator();
+
+ /* local aliases */
+ /* we return the UNIX groups here. This seems to be the right */
+ /* thing to do, since NT member servers return their local */
+ /* groups in the same situation. */
+
+ /* use getgrent_list() to retrieve the list of groups to avoid
+ * problems with getgrent possible infinite loop by internal
+ * libc grent structures overwrites by called functions */
+ grp = glist = getgrent_list();
+ if (grp == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ for (; (num_entries < max_entries) && (grp != NULL); grp = grp->next) {
+ uint32 trid;
+
+ if(!get_group_from_gid(grp->gr_gid, &smap, MAPPING_WITHOUT_PRIV))
+ continue;
+
+ if (smap.sid_name_use!=SID_NAME_ALIAS) {
+ continue;
+ }
+
+ sid_split_rid(&smap.sid, &trid);
+
+ if (!sid_equal(sid, &smap.sid))
+ continue;
+
+ /* Don't return winbind groups as they are not local! */
+ if (strchr_m(smap.nt_name, *sep) != NULL) {
+ DEBUG(10,("get_group_alias_entries: not returing %s, not local.\n", smap.nt_name ));
+ continue;
+ }
+
+ /* Don't return user private groups... */
+ if (Get_Pwnam(smap.nt_name) != 0) {
+ DEBUG(10,("get_group_alias_entries: not returing %s, clashes with user.\n", smap.nt_name ));
+ continue;
+ }
+
+ for( i = 0; i < num_entries; i++)
+ if ( (*d_grp)[i].rid == trid )
+ break;
+
+ if ( i < num_entries ) {
+ continue; /* rid was there, dup! */
+ }
+
+ /* JRA - added this for large group db enumeration... */
+
+ if (start_idx > 0) {
+ /* skip the requested number of entries.
+ not very efficient, but hey...
+ */
+ start_idx--;
+ continue;
+ }
+
+ *d_grp=talloc_realloc(ctx,*d_grp, (num_entries+1)*sizeof(DOMAIN_GRP));
+ if (*d_grp==NULL) {
+ grent_free(glist);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fstrcpy((*d_grp)[num_entries].name, smap.nt_name);
+ (*d_grp)[num_entries].rid = trid;
+ num_entries++;
+ DEBUG(10,("get_group_alias_entries: added entry %d, rid:%d\n", num_entries, trid));
+ }
+
+ grent_free(glist);
+ }
+
+ *p_num_entries = num_entries;
+
+ DEBUG(10,("get_group_alias_entries: returning %d entries\n", *p_num_entries));
+
+ if (num_entries >= max_entries)
+ return STATUS_MORE_ENTRIES;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Get the group entries - similar to get_sampwd_entries().
+ ********************************************************************/
+
+static NTSTATUS get_group_domain_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx,
+ uint32 *p_num_entries, uint32 max_entries)
+{
+ GROUP_MAP *map=NULL;
+ int i;
+ uint32 group_entries = 0;
+ uint32 num_entries = 0;
+
+ *p_num_entries = 0;
+
+ enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV);
+
+ num_entries=group_entries-start_idx;
+
+ /* limit the number of entries */
+ if (num_entries>max_entries) {
+ DEBUG(5,("Limiting to %d entries\n", max_entries));
+ num_entries=max_entries;
+ }
+
+ *d_grp=(DOMAIN_GRP *)talloc_zero(ctx, num_entries*sizeof(DOMAIN_GRP));
+ if (num_entries!=0 && *d_grp==NULL){
+ SAFE_FREE(map);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ fstrcpy((*d_grp)[i].name, map[i+start_idx].nt_name);
+ fstrcpy((*d_grp)[i].comment, map[i+start_idx].comment);
+ sid_split_rid(&map[i+start_idx].sid, &(*d_grp)[i].rid);
+ (*d_grp)[i].attr=SID_NAME_DOM_GRP;
+ }
+
+ SAFE_FREE(map);
+
+ *p_num_entries = num_entries;
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_reply_enum_dom_groups
+ Only reply with one group - domain admins. This must be fixed for
+ a real PDC. JRA.
+ ********************************************************************/
+
+NTSTATUS _samr_enum_dom_groups(pipes_struct *p, SAMR_Q_ENUM_DOM_GROUPS *q_u, SAMR_R_ENUM_DOM_GROUPS *r_u)
+{
+ DOMAIN_GRP *grp=NULL;
+ uint32 num_entries;
+ DOM_SID sid;
+
+ r_u->status = NT_STATUS_OK;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__));
+
+ /* the domain group array is being allocated in the function below */
+ get_group_domain_entries(p->mem_ctx, &grp, &sid, q_u->start_idx, &num_entries, MAX_SAM_ENTRIES);
+
+ make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp);
+
+ init_samr_r_enum_dom_groups(r_u, q_u->start_idx, num_entries);
+
+ DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+
+/*******************************************************************
+ samr_reply_enum_dom_aliases
+ ********************************************************************/
+
+NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, SAMR_R_ENUM_DOM_ALIASES *r_u)
+{
+ DOMAIN_GRP *grp=NULL;
+ uint32 num_entries = 0;
+ fstring sid_str;
+ DOM_SID sid;
+ NTSTATUS status;
+
+ r_u->status = NT_STATUS_OK;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_to_string(sid_str, &sid);
+ DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str));
+
+ status = get_group_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx,
+ &num_entries, MAX_SAM_ENTRIES);
+ if (NT_STATUS_IS_ERR(status)) return status;
+
+ make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp);
+
+ /*safe_free(grp);*/
+
+ init_samr_r_enum_dom_aliases(r_u, q_u->start_idx + num_entries, num_entries);
+
+ DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_query_dispinfo
+ ********************************************************************/
+
+NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, SAMR_R_QUERY_DISPINFO *r_u)
+{
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ DOMAIN_GRP *grps=NULL;
+ uint16 acb_mask = ACB_NORMAL;
+ uint32 num_entries = 0;
+ int orig_num_entries = 0;
+ int total_entries = 0;
+ uint32 data_size = 0;
+ DOM_SID sid;
+ NTSTATUS disp_ret;
+ SAM_DISPINFO_CTR *ctr;
+
+ DEBUG(5, ("samr_reply_query_dispinfo: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_OK;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->domain_pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* decide how many entries to get depending on the max_entries
+ and max_size passed by client */
+
+ DEBUG(5, ("samr_reply_query_dispinfo: max_entries before %d\n", q_u->max_entries));
+
+ if(q_u->max_entries > MAX_SAM_ENTRIES)
+ q_u->max_entries = MAX_SAM_ENTRIES;
+
+ DEBUG(5, ("samr_reply_query_dispinfo: max_entries after %d\n", q_u->max_entries));
+
+ /* Get what we need from the password database */
+ switch (q_u->switch_level) {
+ case 0x2:
+ acb_mask = ACB_WSTRUST;
+ /* Fall through */
+ case 0x1:
+ case 0x4:
+ become_root();
+#if 0
+ r_u->status = get_passwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
+ MAX_SAM_ENTRIES, acb_mask);
+#endif
+#if 0
+ /*
+ * Which should we use here ? JRA.
+ */
+ r_u->status = get_sampwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
+ MAX_SAM_ENTRIES, acb_mask);
+#endif
+#if 1
+ r_u->status = jf_get_sampwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
+ MAX_SAM_ENTRIES, acb_mask);
+#endif
+ unbecome_root();
+ if (NT_STATUS_IS_ERR(r_u->status)) {
+ DEBUG(5, ("get_sampwd_entries: failed\n"));
+ return r_u->status;
+ }
+ break;
+ case 0x3:
+ case 0x5:
+ r_u->status = get_group_domain_entries(p->mem_ctx, &grps, &sid, q_u->start_idx, &num_entries, MAX_SAM_ENTRIES);
+ if (NT_STATUS_IS_ERR(r_u->status))
+ return r_u->status;
+ break;
+ default:
+ DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level ));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ orig_num_entries = num_entries;
+
+ if (num_entries > q_u->max_entries)
+ num_entries = q_u->max_entries;
+
+ if (num_entries > MAX_SAM_ENTRIES) {
+ num_entries = MAX_SAM_ENTRIES;
+ DEBUG(5, ("limiting number of entries to %d\n", num_entries));
+ }
+
+ /* Ensure password info is never given out here. PARANOIA... JRA */
+ samr_clear_passwd_fields(pass, num_entries);
+
+ data_size = q_u->max_size;
+
+ if (!(ctr = (SAM_DISPINFO_CTR *)talloc_zero(p->mem_ctx,sizeof(SAM_DISPINFO_CTR))))
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(ctr);
+
+ /* Now create reply structure */
+ switch (q_u->switch_level) {
+ case 0x1:
+ if (num_entries) {
+ if (!(ctr->sam.info1 = (SAM_DISPINFO_1 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_1))))
+ return NT_STATUS_NO_MEMORY;
+ }
+ disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, &num_entries, &data_size, q_u->start_idx, pass);
+ if (NT_STATUS_IS_ERR(disp_ret))
+ return disp_ret;
+ break;
+ case 0x2:
+ if (num_entries) {
+ if (!(ctr->sam.info2 = (SAM_DISPINFO_2 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_2))))
+ return NT_STATUS_NO_MEMORY;
+ }
+ disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, &num_entries, &data_size, q_u->start_idx, pass);
+ if (NT_STATUS_IS_ERR(disp_ret))
+ return disp_ret;
+ break;
+ case 0x3:
+ if (num_entries) {
+ if (!(ctr->sam.info3 = (SAM_DISPINFO_3 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_3))))
+ return NT_STATUS_NO_MEMORY;
+ }
+ disp_ret = init_sam_dispinfo_3(p->mem_ctx, ctr->sam.info3, &num_entries, &data_size, q_u->start_idx, grps);
+ if (NT_STATUS_IS_ERR(disp_ret))
+ return disp_ret;
+ break;
+ case 0x4:
+ if (num_entries) {
+ if (!(ctr->sam.info4 = (SAM_DISPINFO_4 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_4))))
+ return NT_STATUS_NO_MEMORY;
+ }
+ disp_ret = init_sam_dispinfo_4(p->mem_ctx, ctr->sam.info4, &num_entries, &data_size, q_u->start_idx, pass);
+ if (NT_STATUS_IS_ERR(disp_ret))
+ return disp_ret;
+ break;
+ case 0x5:
+ if (num_entries) {
+ if (!(ctr->sam.info5 = (SAM_DISPINFO_5 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_5))))
+ return NT_STATUS_NO_MEMORY;
+ }
+ disp_ret = init_sam_dispinfo_5(p->mem_ctx, ctr->sam.info5, &num_entries, &data_size, q_u->start_idx, grps);
+ if (NT_STATUS_IS_ERR(disp_ret))
+ return disp_ret;
+ break;
+ default:
+ ctr->sam.info = NULL;
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ DEBUG(5, ("_samr_query_dispinfo: %d\n", __LINE__));
+
+ if (num_entries < orig_num_entries)
+ return STATUS_MORE_ENTRIES;
+
+ init_samr_r_query_dispinfo(r_u, num_entries, data_size, q_u->switch_level, ctr, r_u->status);
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_query_aliasinfo
+ ********************************************************************/
+
+NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAMR_R_QUERY_ALIASINFO *r_u)
+{
+ struct samr_info *info = NULL;
+ GROUP_MAP map;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_query_aliasinfo: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_in_our_domain(&info->sid) &&
+ !sid_check_is_in_builtin(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ if(!get_local_group_from_sid(info->sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ switch (q_u->switch_level) {
+ case 1:
+ r_u->ptr = 1;
+ r_u->ctr.switch_value1 = 1;
+ init_samr_alias_info1(&r_u->ctr.alias.info1, map.nt_name, 1, map.comment);
+ break;
+ case 3:
+ r_u->ptr = 1;
+ r_u->ctr.switch_value1 = 3;
+ init_samr_alias_info3(&r_u->ctr.alias.info3, map.comment);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ DEBUG(5,("_samr_query_aliasinfo: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+#if 0
+/*******************************************************************
+ samr_reply_lookup_ids
+ ********************************************************************/
+
+ uint32 _samr_lookup_ids(pipes_struct *p, SAMR_Q_LOOKUP_IDS *q_u, SAMR_R_LOOKUP_IDS *r_u)
+{
+ uint32 rid[MAX_SAM_ENTRIES];
+ int num_rids = q_u->num_sids1;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__));
+
+ if (num_rids > MAX_SAM_ENTRIES) {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("_samr_lookup_ids: truncating entries to %d\n", num_rids));
+ }
+
+#if 0
+ int i;
+ SMB_ASSERT_ARRAY(q_u->uni_user_name, num_rids);
+
+ for (i = 0; i < num_rids && status == 0; i++)
+ {
+ struct sam_passwd *sam_pass;
+ fstring user_name;
+
+
+ fstrcpy(user_name, unistrn2(q_u->uni_user_name[i].buffer,
+ q_u->uni_user_name[i].uni_str_len));
+
+ /* find the user account */
+ become_root();
+ sam_pass = get_smb21pwd_entry(user_name, 0);
+ unbecome_root();
+
+ if (sam_pass == NULL)
+ {
+ status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ rid[i] = 0;
+ }
+ else
+ {
+ rid[i] = sam_pass->user_rid;
+ }
+ }
+#endif
+
+ num_rids = 1;
+ rid[0] = BUILTIN_ALIAS_RID_USERS;
+
+ init_samr_r_lookup_ids(&r_u, num_rids, rid, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_lookup_ids: %d\n", __LINE__));
+
+ return r_u->status;
+}
+#endif
+
+/*******************************************************************
+ _samr_lookup_names
+ ********************************************************************/
+
+NTSTATUS _samr_lookup_names(pipes_struct *p, SAMR_Q_LOOKUP_NAMES *q_u, SAMR_R_LOOKUP_NAMES *r_u)
+{
+ uint32 rid[MAX_SAM_ENTRIES];
+ uint32 local_rid;
+ enum SID_NAME_USE type[MAX_SAM_ENTRIES];
+ enum SID_NAME_USE local_type;
+ int i;
+ int num_rids = q_u->num_names2;
+ DOM_SID pol_sid;
+ fstring sid_str;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_lookup_names: %d\n", __LINE__));
+
+ ZERO_ARRAY(rid);
+ ZERO_ARRAY(type);
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &pol_sid)) {
+ init_samr_r_lookup_names(p->mem_ctx, r_u, 0, NULL, NULL, NT_STATUS_OBJECT_TYPE_MISMATCH);
+ return r_u->status;
+ }
+
+ if (num_rids > MAX_SAM_ENTRIES) {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("_samr_lookup_names: truncating entries to %d\n", num_rids));
+ }
+
+ DEBUG(5,("_samr_lookup_names: looking name on SID %s\n", sid_to_string(sid_str, &pol_sid)));
+
+ for (i = 0; i < num_rids; i++) {
+ fstring name;
+ DOM_SID sid;
+
+ r_u->status = NT_STATUS_NONE_MAPPED;
+
+ rid [i] = 0xffffffff;
+ type[i] = SID_NAME_UNKNOWN;
+
+ rpcstr_pull(name, q_u->uni_name[i].buffer, sizeof(name), q_u->uni_name[i].uni_str_len*2, 0);
+
+ /*
+ * we are only looking for a name
+ * the SID we get back can be outside
+ * the scope of the pol_sid
+ *
+ * in clear: it prevents to reply to domain\group: yes
+ * when only builtin\group exists.
+ *
+ * a cleaner code is to add the sid of the domain we're looking in
+ * to the local_lookup_name function.
+ */
+ if(local_lookup_name(global_myname, name, &sid, &local_type)) {
+ sid_split_rid(&sid, &local_rid);
+
+ if (sid_equal(&sid, &pol_sid)) {
+ rid[i]=local_rid;
+ type[i]=local_type;
+ r_u->status = NT_STATUS_OK;
+ }
+ }
+ }
+
+ init_samr_r_lookup_names(p->mem_ctx, r_u, num_rids, rid, (uint32 *)type, r_u->status);
+
+ DEBUG(5,("_samr_lookup_names: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _samr_chgpasswd_user
+ ********************************************************************/
+
+NTSTATUS _samr_chgpasswd_user(pipes_struct *p, SAMR_Q_CHGPASSWD_USER *q_u, SAMR_R_CHGPASSWD_USER *r_u)
+{
+ fstring user_name;
+ fstring wks;
+
+ DEBUG(5,("_samr_chgpasswd_user: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_OK;
+
+ rpcstr_pull(user_name, q_u->uni_user_name.buffer, sizeof(user_name), q_u->uni_user_name.uni_str_len*2, 0);
+ rpcstr_pull(wks, q_u->uni_dest_host.buffer, sizeof(wks), q_u->uni_dest_host.uni_str_len*2,0);
+
+ DEBUG(5,("samr_chgpasswd_user: user: %s wks: %s\n", user_name, wks));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user_name);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam_Modify( user_name);
+
+ if (!pass_oem_change(user_name, q_u->lm_newpass.pass, q_u->lm_oldhash.hash,
+ q_u->nt_newpass.pass, q_u->nt_oldhash.hash))
+ r_u->status = NT_STATUS_WRONG_PASSWORD;
+
+ init_samr_r_chgpasswd_user(r_u, r_u->status);
+
+ DEBUG(5,("_samr_chgpasswd_user: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+makes a SAMR_R_LOOKUP_RIDS structure.
+********************************************************************/
+
+static BOOL make_samr_lookup_rids(TALLOC_CTX *ctx, uint32 num_names, fstring names[],
+ UNIHDR **pp_hdr_name, UNISTR2 **pp_uni_name)
+{
+ uint32 i;
+ UNIHDR *hdr_name=NULL;
+ UNISTR2 *uni_name=NULL;
+
+ *pp_uni_name = NULL;
+ *pp_hdr_name = NULL;
+
+ if (num_names != 0) {
+ hdr_name = (UNIHDR *)talloc_zero(ctx, sizeof(UNIHDR)*num_names);
+ if (hdr_name == NULL)
+ return False;
+
+ uni_name = (UNISTR2 *)talloc_zero(ctx,sizeof(UNISTR2)*num_names);
+ if (uni_name == NULL)
+ return False;
+ }
+
+ for (i = 0; i < num_names; i++) {
+ int len = names[i] != NULL ? strlen(names[i]) : 0;
+ DEBUG(10, ("names[%d]:%s\n", i, names[i]));
+ init_uni_hdr(&hdr_name[i], len);
+ init_unistr2(&uni_name[i], names[i], len);
+ }
+
+ *pp_uni_name = uni_name;
+ *pp_hdr_name = hdr_name;
+
+ return True;
+}
+
+/*******************************************************************
+ _samr_lookup_rids
+ ********************************************************************/
+
+NTSTATUS _samr_lookup_rids(pipes_struct *p, SAMR_Q_LOOKUP_RIDS *q_u, SAMR_R_LOOKUP_RIDS *r_u)
+{
+ fstring group_names[MAX_SAM_ENTRIES];
+ uint32 *group_attrs = NULL;
+ UNIHDR *hdr_name = NULL;
+ UNISTR2 *uni_name = NULL;
+ DOM_SID pol_sid;
+ int num_rids = q_u->num_rids1;
+ int i;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_lookup_rids: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &pol_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (num_rids > MAX_SAM_ENTRIES) {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("_samr_lookup_rids: truncating entries to %d\n", num_rids));
+ }
+
+ if (num_rids) {
+ if ((group_attrs = (uint32 *)talloc_zero(p->mem_ctx, num_rids * sizeof(uint32))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r_u->status = NT_STATUS_NONE_MAPPED;
+
+ for (i = 0; i < num_rids; i++) {
+ fstring tmpname;
+ fstring domname;
+ DOM_SID sid;
+ enum SID_NAME_USE type;
+
+ group_attrs[i] = SID_NAME_UNKNOWN;
+ *group_names[i] = '\0';
+
+ if (sid_equal(&pol_sid, &global_sam_sid)) {
+ sid_copy(&sid, &pol_sid);
+ sid_append_rid(&sid, q_u->rid[i]);
+
+ if (lookup_sid(&sid, domname, tmpname, &type)) {
+ r_u->status = NT_STATUS_OK;
+ group_attrs[i] = (uint32)type;
+ fstrcpy(group_names[i],tmpname);
+ DEBUG(5,("_samr_lookup_rids: %s:%d\n", group_names[i], group_attrs[i]));
+ }
+ }
+ }
+
+ if(!make_samr_lookup_rids(p->mem_ctx, num_rids, group_names, &hdr_name, &uni_name))
+ return NT_STATUS_NO_MEMORY;
+
+ init_samr_r_lookup_rids(r_u, num_rids, hdr_name, uni_name, group_attrs);
+
+ DEBUG(5,("_samr_lookup_rids: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _api_samr_open_user. Safe - gives out no passwd info.
+ ********************************************************************/
+
+NTSTATUS _api_samr_open_user(pipes_struct *p, SAMR_Q_OPEN_USER *q_u, SAMR_R_OPEN_USER *r_u)
+{
+ SAM_ACCOUNT *sampass=NULL;
+ DOM_SID sid;
+ POLICY_HND domain_pol = q_u->domain_pol;
+ uint32 user_rid = q_u->user_rid;
+ POLICY_HND *user_pol = &r_u->user_pol;
+ struct samr_info *info = NULL;
+ BOOL ret;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the domain policy handle. */
+ if (!find_policy_by_hnd(p, &domain_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret=pdb_getsampwrid(sampass, user_rid);
+ unbecome_root();
+
+ /* check that the RID exists in our domain. */
+ if (ret == False) {
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ samr_clear_sam_passwd(sampass);
+ pdb_free_sam(&sampass);
+
+ /* Get the domain SID stored in the domain policy */
+ if(!get_lsa_policy_samr_sid(p, &domain_pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* append the user's RID to it */
+ if(!sid_append_rid(&sid, user_rid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /* associate the user's SID with the new handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = sid;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, user_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return r_u->status;
+}
+
+/*************************************************************************
+ get_user_info_10. Safe. Only gives out acb bits.
+ *************************************************************************/
+
+static BOOL get_user_info_10(SAM_USER_INFO_10 *id10, uint32 user_rid)
+{
+ SAM_ACCOUNT *smbpass=NULL;
+ BOOL ret;
+
+ if (!pdb_rid_is_user(user_rid)) {
+ DEBUG(4,("RID 0x%x is not a user RID\n", user_rid));
+ return False;
+ }
+
+ pdb_init_sam(&smbpass);
+
+ become_root();
+ ret = pdb_getsampwrid(smbpass, user_rid);
+ unbecome_root();
+
+ if (ret==False) {
+ DEBUG(4,("User 0x%x not found\n", user_rid));
+ pdb_free_sam(&smbpass);
+ return False;
+ }
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(smbpass) ));
+
+ ZERO_STRUCTP(id10);
+ init_sam_user_info10(id10, pdb_get_acct_ctrl(smbpass) );
+
+ samr_clear_sam_passwd(smbpass);
+ pdb_free_sam(&smbpass);
+
+ return True;
+}
+
+/*************************************************************************
+ get_user_info_12. OK - this is the killer as it gives out password info.
+ Ensure that this is only allowed on an encrypted connection with a root
+ user. JRA.
+ *************************************************************************/
+
+static NTSTATUS get_user_info_12(pipes_struct *p, SAM_USER_INFO_12 * id12, uint32 user_rid)
+{
+ SAM_ACCOUNT *smbpass=NULL;
+ BOOL ret;
+
+ if (!p->ntlmssp_auth_validated)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!(p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) || !(p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /*
+ * Do *NOT* do become_root()/unbecome_root() here ! JRA.
+ */
+ pdb_init_sam(&smbpass);
+
+ ret = pdb_getsampwrid(smbpass, user_rid);
+
+ if (ret == False) {
+ DEBUG(4, ("User 0x%x not found\n", user_rid));
+ pdb_free_sam(&smbpass);
+ return (geteuid() == (uid_t)0) ? NT_STATUS_NO_SUCH_USER : NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(3,("User:[%s] 0x%x\n", pdb_get_username(smbpass), pdb_get_acct_ctrl(smbpass) ));
+
+ if ( pdb_get_acct_ctrl(smbpass) & ACB_DISABLED) {
+ pdb_free_sam(&smbpass);
+ return NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ ZERO_STRUCTP(id12);
+ init_sam_user_info12(id12, pdb_get_lanman_passwd(smbpass), pdb_get_nt_passwd(smbpass));
+
+ pdb_free_sam(&smbpass);
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************************
+ get_user_info_20
+ *************************************************************************/
+
+static BOOL get_user_info_20(SAM_USER_INFO_20 *id20, uint32 user_rid)
+{
+ SAM_ACCOUNT *sampass=NULL;
+ BOOL ret;
+
+ if (!pdb_rid_is_user(user_rid)) {
+ DEBUG(4,("RID 0x%x is not a user RID\n", user_rid));
+ return False;
+ }
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwrid(sampass, user_rid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User 0x%x not found\n", user_rid));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ samr_clear_sam_passwd(sampass);
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+
+ ZERO_STRUCTP(id20);
+ init_sam_user_info20A(id20, sampass);
+
+ pdb_free_sam(&sampass);
+
+ return True;
+}
+
+/*************************************************************************
+ get_user_info_21
+ *************************************************************************/
+
+static BOOL get_user_info_21(SAM_USER_INFO_21 *id21, uint32 user_rid)
+{
+ SAM_ACCOUNT *sampass=NULL;
+ BOOL ret;
+
+ if (!pdb_rid_is_user(user_rid)) {
+ DEBUG(4,("RID 0x%x is not a user RID\n", user_rid));
+ return False;
+ }
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwrid(sampass, user_rid);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(4,("User 0x%x not found\n", user_rid));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ samr_clear_sam_passwd(sampass);
+
+ DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+
+ ZERO_STRUCTP(id21);
+ init_sam_user_info21A(id21, sampass);
+
+ pdb_free_sam(&sampass);
+
+ return True;
+}
+
+/*******************************************************************
+ _samr_query_userinfo
+ ********************************************************************/
+
+NTSTATUS _samr_query_userinfo(pipes_struct *p, SAMR_Q_QUERY_USERINFO *q_u, SAMR_R_QUERY_USERINFO *r_u)
+{
+ SAM_USERINFO_CTR *ctr;
+ uint32 rid = 0;
+ struct samr_info *info = NULL;
+
+ r_u->status=NT_STATUS_OK;
+
+ /* search for the handle */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_in_our_domain(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ sid_peek_rid(&info->sid, &rid);
+
+ DEBUG(5,("_samr_query_userinfo: rid:0x%x\n", rid));
+
+ ctr = (SAM_USERINFO_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_USERINFO_CTR));
+ if (!ctr)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(ctr);
+
+ /* ok! user info levels (lots: see MSDEV help), off we go... */
+ ctr->switch_value = q_u->switch_value;
+
+ switch (q_u->switch_value) {
+ case 0x10:
+ ctr->info.id10 = (SAM_USER_INFO_10 *)talloc_zero(p->mem_ctx, sizeof(SAM_USER_INFO_10));
+ if (ctr->info.id10 == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!get_user_info_10(ctr->info.id10, rid))
+ return NT_STATUS_NO_SUCH_USER;
+ break;
+
+#if 0
+/* whoops - got this wrong. i think. or don't understand what's happening. */
+ case 0x11:
+ {
+ NTTIME expire;
+ info = (void *)&id11;
+
+ expire.low = 0xffffffff;
+ expire.high = 0x7fffffff;
+
+ ctr->info.id = (SAM_USER_INFO_11 *)talloc_zero(p->mem_ctx,
+ sizeof
+ (*ctr->
+ info.
+ id11));
+ ZERO_STRUCTP(ctr->info.id11);
+ init_sam_user_info11(ctr->info.id11, &expire,
+ "BROOKFIELDS$", /* name */
+ 0x03ef, /* user rid */
+ 0x201, /* group rid */
+ 0x0080); /* acb info */
+
+ break;
+ }
+#endif
+
+ case 0x12:
+ ctr->info.id12 = (SAM_USER_INFO_12 *)talloc_zero(p->mem_ctx, sizeof(SAM_USER_INFO_12));
+ if (ctr->info.id12 == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (NT_STATUS_IS_ERR(r_u->status = get_user_info_12(p, ctr->info.id12, rid)))
+ return r_u->status;
+ break;
+
+ case 20:
+ ctr->info.id20 = (SAM_USER_INFO_20 *)talloc_zero(p->mem_ctx,sizeof(SAM_USER_INFO_20));
+ if (ctr->info.id20 == NULL)
+ return NT_STATUS_NO_MEMORY;
+ if (!get_user_info_20(ctr->info.id20, rid))
+ return NT_STATUS_NO_SUCH_USER;
+ break;
+
+ case 21:
+ ctr->info.id21 = (SAM_USER_INFO_21 *)talloc_zero(p->mem_ctx,sizeof(SAM_USER_INFO_21));
+ if (ctr->info.id21 == NULL)
+ return NT_STATUS_NO_MEMORY;
+ if (!get_user_info_21(ctr->info.id21, rid))
+ return NT_STATUS_NO_SUCH_USER;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_samr_r_query_userinfo(r_u, ctr, r_u->status);
+
+ DEBUG(5,("_samr_query_userinfo: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_query_usergroups
+ ********************************************************************/
+
+NTSTATUS _samr_query_usergroups(pipes_struct *p, SAMR_Q_QUERY_USERGROUPS *q_u, SAMR_R_QUERY_USERGROUPS *r_u)
+{
+ SAM_ACCOUNT *sam_pass=NULL;
+ DOM_GID *gids = NULL;
+ int num_groups = 0;
+ uint32 rid;
+ struct samr_info *info = NULL;
+ BOOL ret;
+
+ /*
+ * from the SID in the request:
+ * we should send back the list of DOMAIN GROUPS
+ * the user is a member of
+ *
+ * and only the DOMAIN GROUPS
+ * no ALIASES !!! neither aliases of the domain
+ * nor aliases of the builtin SID
+ *
+ * JFM, 12/2/2001
+ */
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_query_usergroups: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_in_our_domain(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ sid_peek_rid(&info->sid, &rid);
+
+ pdb_init_sam(&sam_pass);
+
+ become_root();
+ ret = pdb_getsampwrid(sam_pass, rid);
+ unbecome_root();
+
+ if (ret == False) {
+ samr_clear_sam_passwd(sam_pass);
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if(!get_domain_user_groups(p->mem_ctx, &num_groups, &gids, sam_pass)) {
+ samr_clear_sam_passwd(sam_pass);
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ /* construct the response. lkclXXXX: gids are not copied! */
+ init_samr_r_query_usergroups(r_u, num_groups, gids, r_u->status);
+
+ DEBUG(5,("_samr_query_usergroups: %d\n", __LINE__));
+
+ samr_clear_sam_passwd(sam_pass);
+ pdb_free_sam(&sam_pass);
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _samr_query_dom_info
+ ********************************************************************/
+
+NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SAMR_R_QUERY_DOMAIN_INFO *r_u)
+{
+ SAM_UNK_CTR *ctr;
+ uint32 min_pass_len,pass_hist,flag;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+
+ time_t u_lock_duration, u_reset_time;
+ NTTIME nt_lock_duration, nt_reset_time;
+ uint32 lockout;
+
+ time_t u_logout;
+ NTTIME nt_logout;
+
+
+ if ((ctr = (SAM_UNK_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_UNK_CTR))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(ctr);
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_query_dom_info: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->domain_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ switch (q_u->switch_value) {
+ case 0x01:
+ account_policy_get(AP_MIN_PASSWORD_LEN, &min_pass_len);
+ account_policy_get(AP_PASSWORD_HISTORY, &pass_hist);
+ account_policy_get(AP_USER_MUST_LOGON_TO_CHG_PASS, &flag);
+ account_policy_get(AP_MAX_PASSWORD_AGE, (int *)&u_expire);
+ account_policy_get(AP_MIN_PASSWORD_AGE, (int *)&u_min_age);
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ init_unk_info1(&ctr->info.inf1, (uint16)min_pass_len, (uint16)pass_hist,
+ flag, nt_expire, nt_min_age);
+ break;
+ case 0x02:
+ /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */
+ init_unk_info2(&ctr->info.inf2, global_myworkgroup, global_myname, (uint32) time(NULL));
+ break;
+ case 0x03:
+ account_policy_get(AP_TIME_TO_LOGOUT, (int *)&u_logout);
+ unix_to_nt_time_abs(&nt_logout, u_logout);
+
+ init_unk_info3(&ctr->info.inf3, nt_logout);
+ break;
+ case 0x05:
+ init_unk_info5(&ctr->info.inf5, global_myname);
+ break;
+ case 0x06:
+ init_unk_info6(&ctr->info.inf6);
+ break;
+ case 0x07:
+ init_unk_info7(&ctr->info.inf7);
+ break;
+ case 0x0c:
+ account_policy_get(AP_LOCK_ACCOUNT_DURATION, (int *)&u_lock_duration);
+ account_policy_get(AP_RESET_COUNT_TIME, (int *)&u_reset_time);
+ account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &lockout);
+
+ unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
+ unix_to_nt_time_abs(&nt_reset_time, u_reset_time);
+
+ init_unk_info12(&ctr->info.inf12, nt_lock_duration, nt_reset_time, (uint16)lockout);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_samr_r_query_dom_info(r_u, q_u->switch_value, ctr, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_query_dom_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _api_samr_create_user
+ Create an account, can be either a normal user or a machine.
+ This funcion will need to be updated for bdc/domain trusts.
+ ********************************************************************/
+
+NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREATE_USER *r_u)
+{
+ SAM_ACCOUNT *sam_pass=NULL;
+ fstring account;
+ pstring err_str;
+ pstring msg_str;
+ int local_flags=0;
+ DOM_SID sid;
+ pstring add_script;
+ POLICY_HND dom_pol = q_u->domain_pol;
+ UNISTR2 user_account = q_u->uni_name;
+ uint16 acb_info = q_u->acb_info;
+ POLICY_HND *user_pol = &r_u->user_pol;
+ struct samr_info *info = NULL;
+ BOOL ret;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &dom_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* find the account: tell the caller if it exists.
+ lkclXXXX i have *no* idea if this is a problem or not
+ or even if you are supposed to construct a different
+ reply if the account already exists...
+ */
+
+ rpcstr_pull(account, user_account.buffer, sizeof(account), user_account.uni_str_len*2, 0);
+ strlower(account);
+
+ pdb_init_sam(&sam_pass);
+
+ become_root();
+ ret = pdb_getsampwnam(sam_pass, account);
+ unbecome_root();
+ if (ret == True) {
+ /* this account exists: say so */
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_USER_EXISTS;
+ }
+
+ local_flags=LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_SET_NO_PASSWORD;
+ local_flags|= (acb_info & ACB_WSTRUST) ? LOCAL_TRUST_ACCOUNT:0;
+
+ /*
+ * NB. VERY IMPORTANT ! This call must be done as the current pipe user,
+ * *NOT* surrounded by a become_root()/unbecome_root() call. This ensures
+ * that only people with write access to the smbpasswd file will be able
+ * to create a user. JRA.
+ */
+
+ /*
+ * add the user in the /etc/passwd file or the unix authority system.
+ * We don't check if the smb_create_user() function succed or not for 2 reasons:
+ * a) local_password_change() checks for us if the /etc/passwd account really exists
+ * b) smb_create_user() would return an error if the account already exists
+ * and as it could return an error also if it can't create the account, it would be tricky.
+ *
+ * So we go the easy way, only check after if the account exists.
+ * JFM (2/3/2001), to clear any possible bad understanding (-:
+ *
+ * We now have seperate script paramaters for adding users/machines so we
+ * now have some sainity-checking to match.
+ */
+
+ DEBUG(10,("checking account %s at pos %d for $ termination\n",account, strlen(account)-1));
+#if 0
+ if ((acb_info & ACB_WSTRUST) && (account[strlen(account)-1] == '$')) {
+ pstrcpy(add_script, lp_addmachine_script());
+ } else if ((!(acb_info & ACB_WSTRUST)) && (account[strlen(account)-1] != '$')) {
+ pstrcpy(add_script, lp_adduser_script());
+ } else {
+ DEBUG(0, ("_api_samr_create_user: mismatch between trust flags and $ termination\n"));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ /*
+ * we can't check both the ending $ and the acb_info.
+ *
+ * UserManager creates trust accounts (ending in $,
+ * normal that hidden accounts) with the acb_info equals to ACB_NORMAL.
+ * JFM, 11/29/2001
+ */
+ if (account[strlen(account)-1] == '$')
+ pstrcpy(add_script, lp_addmachine_script());
+ else
+ pstrcpy(add_script, lp_adduser_script());
+
+ if(*add_script) {
+ int add_ret;
+ all_string_sub(add_script, "%u", account, sizeof(account));
+ add_ret = smbrun(add_script,NULL);
+ DEBUG(3,("_api_samr_create_user: Running the command `%s' gave %d\n",add_script,add_ret));
+ }
+
+ /* add the user in the smbpasswd file or the Samba authority database */
+ if (!local_password_change(account, local_flags, NULL, err_str,
+ sizeof(err_str), msg_str, sizeof(msg_str))) {
+ DEBUG(0, ("%s\n", err_str));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sam_pass, account);
+ unbecome_root();
+ if (ret == False) {
+ /* account doesn't exist: say so */
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Get the domain SID stored in the domain policy */
+ if(!get_lsa_policy_samr_sid(p, &dom_pol, &sid)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* append the user's RID to it */
+ if(!sid_append_rid(&sid, pdb_get_user_rid(sam_pass) )) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* associate the user's SID with the new handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(info);
+ info->sid = sid;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, user_pol, free_samr_info, (void *)info)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ r_u->user_rid=sam_pass->user_rid;
+ r_u->unknown_0 = 0x000703ff;
+
+ pdb_free_sam(&sam_pass);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ samr_reply_connect_anon
+ ********************************************************************/
+
+NTSTATUS _samr_connect_anon(pipes_struct *p, SAMR_Q_CONNECT_ANON *q_u, SAMR_R_CONNECT_ANON *r_u)
+{
+ struct samr_info *info = NULL;
+
+ /* set up the SAMR connect_anon response */
+
+ r_u->status = NT_STATUS_OK;
+
+ /* associate the user's SID with the new handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->status = q_u->unknown_0;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->connect_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_connect
+ ********************************************************************/
+
+NTSTATUS _samr_connect(pipes_struct *p, SAMR_Q_CONNECT *q_u, SAMR_R_CONNECT *r_u)
+{
+ struct samr_info *info = NULL;
+
+ DEBUG(5,("_samr_connect: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_OK;
+
+ /* associate the user's SID with the new handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->status = q_u->access_mask;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->connect_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ DEBUG(5,("_samr_connect: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/**********************************************************************
+ api_samr_lookup_domain
+ **********************************************************************/
+
+NTSTATUS _samr_lookup_domain(pipes_struct *p, SAMR_Q_LOOKUP_DOMAIN *q_u, SAMR_R_LOOKUP_DOMAIN *r_u)
+{
+ r_u->status = NT_STATUS_OK;
+
+ if (!find_policy_by_hnd(p, &q_u->connect_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* assume the domain name sent is our global_myname and
+ send global_sam_sid */
+ init_samr_r_lookup_domain(r_u, &global_sam_sid, r_u->status);
+
+ return r_u->status;
+}
+
+/******************************************************************
+makes a SAMR_R_ENUM_DOMAINS structure.
+********************************************************************/
+
+static BOOL make_enum_domains(TALLOC_CTX *ctx, SAM_ENTRY **pp_sam,
+ UNISTR2 **pp_uni_name, uint32 num_sam_entries, fstring doms[])
+{
+ uint32 i;
+ SAM_ENTRY *sam;
+ UNISTR2 *uni_name;
+
+ DEBUG(5, ("make_enum_domains\n"));
+
+ *pp_sam = NULL;
+ *pp_uni_name = NULL;
+
+ if (num_sam_entries == 0)
+ return True;
+
+ sam = (SAM_ENTRY *)talloc_zero(ctx, sizeof(SAM_ENTRY)*num_sam_entries);
+ uni_name = (UNISTR2 *)talloc_zero(ctx, sizeof(UNISTR2)*num_sam_entries);
+
+ if (sam == NULL || uni_name == NULL)
+ return False;
+
+ for (i = 0; i < num_sam_entries; i++) {
+ int len = doms[i] != NULL ? strlen(doms[i]) : 0;
+
+ init_sam_entry(&sam[i], len, 0);
+ init_unistr2(&uni_name[i], doms[i], len);
+ }
+
+ *pp_sam = sam;
+ *pp_uni_name = uni_name;
+
+ return True;
+}
+
+/**********************************************************************
+ api_samr_enum_domains
+ **********************************************************************/
+
+NTSTATUS _samr_enum_domains(pipes_struct *p, SAMR_Q_ENUM_DOMAINS *q_u, SAMR_R_ENUM_DOMAINS *r_u)
+{
+ uint32 num_entries = 2;
+ fstring dom[2];
+
+ r_u->status = NT_STATUS_OK;
+
+ fstrcpy(dom[0],global_myworkgroup);
+ fstrcpy(dom[1],"Builtin");
+
+ if (!make_enum_domains(p->mem_ctx, &r_u->sam, &r_u->uni_dom_name, num_entries, dom))
+ return NT_STATUS_NO_MEMORY;
+
+ init_samr_r_enum_domains(r_u, q_u->start_idx + num_entries, num_entries);
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ api_samr_open_alias
+ ********************************************************************/
+
+NTSTATUS _api_samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_ALIAS *r_u)
+{
+ DOM_SID sid;
+ POLICY_HND domain_pol = q_u->dom_pol;
+ uint32 alias_rid = q_u->rid_alias;
+ POLICY_HND *alias_pol = &r_u->pol;
+ struct samr_info *info = NULL;
+
+ r_u->status = NT_STATUS_OK;
+
+ /* get the domain policy. */
+ if (!find_policy_by_hnd(p, &domain_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* Get the domain SID stored in the domain policy */
+ if(!get_lsa_policy_samr_sid(p, &domain_pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* append the alias' RID to it */
+ if(!sid_append_rid(&sid, alias_rid))
+ return NT_STATUS_NO_SUCH_USER;
+
+ /*
+ * we should check if the rid really exist !!!
+ * JFM.
+ */
+
+ /* associate the user's SID with the new handle. */
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+ info->sid = sid;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, alias_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ set_user_info_10
+ ********************************************************************/
+
+static BOOL set_user_info_10(const SAM_USER_INFO_10 *id10, uint32 rid)
+{
+ SAM_ACCOUNT *pwd =NULL;
+ BOOL ret;
+
+ pdb_init_sam(&pwd);
+
+ ret = pdb_getsampwrid(pwd, rid);
+
+ if(ret==False) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (id10 == NULL) {
+ DEBUG(5, ("set_user_info_10: NULL id10\n"));
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (!pdb_set_acct_ctrl(pwd, id10->acb_info)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if(!pdb_update_sam_account(pwd, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ pdb_free_sam(&pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_12
+ ********************************************************************/
+
+static BOOL set_user_info_12(SAM_USER_INFO_12 *id12, uint32 rid)
+{
+ SAM_ACCOUNT *pwd = NULL;
+
+ pdb_init_sam(&pwd);
+
+ if(!pdb_getsampwrid(pwd, rid)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (id12 == NULL) {
+ DEBUG(2, ("set_user_info_12: id12 is NULL\n"));
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (!pdb_set_lanman_passwd (pwd, id12->lm_pwd)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+ if (!pdb_set_nt_passwd (pwd, id12->nt_pwd)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+ if (!pdb_set_pass_changed_now (pwd)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if(!pdb_update_sam_account(pwd, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ pdb_free_sam(&pwd);
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_21
+ ********************************************************************/
+
+static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, uint32 rid)
+{
+ SAM_ACCOUNT *pwd = NULL;
+
+ if (id21 == NULL) {
+ DEBUG(5, ("set_user_info_21: NULL id21\n"));
+ return False;
+ }
+
+ pdb_init_sam(&pwd);
+
+ if (!pdb_getsampwrid(pwd, rid)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ copy_id21_to_sam_passwd(pwd, id21);
+
+ /*
+ * The funny part about the previous two calls is
+ * that pwd still has the password hashes from the
+ * passdb entry. These have not been updated from
+ * id21. I don't know if they need to be set. --jerry
+ */
+
+ /* write the change out */
+ if(!pdb_update_sam_account(pwd, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ pdb_free_sam(&pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_23
+ ********************************************************************/
+
+static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, uint32 rid)
+{
+ SAM_ACCOUNT *pwd = NULL;
+ pstring plaintext_buf;
+ uint32 len;
+ uint16 acct_ctrl;
+
+ if (id23 == NULL) {
+ DEBUG(5, ("set_user_info_23: NULL id23\n"));
+ return False;
+ }
+
+ pdb_init_sam(&pwd);
+
+ if (!pdb_getsampwrid(pwd, rid)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(pwd);
+
+ copy_id23_to_sam_passwd(pwd, id23);
+
+ if (!decode_pw_buffer((char*)id23->pass, plaintext_buf, 256, &len)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ /* if it's a trust account, don't update /etc/passwd */
+ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) ||
+ ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) ||
+ ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) {
+ DEBUG(5, ("Changing trust account password, not updating /etc/passwd\n"));
+ } else {
+ /* update the UNIX password */
+ if (lp_unix_password_sync() )
+ if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+ }
+
+ ZERO_STRUCT(plaintext_buf);
+
+ if(!pdb_update_sam_account(pwd, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ pdb_free_sam(&pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ set_user_info_pw
+ ********************************************************************/
+
+static BOOL set_user_info_pw(char *pass, uint32 rid)
+{
+ SAM_ACCOUNT *pwd = NULL;
+ uint32 len;
+ pstring plaintext_buf;
+ uint16 acct_ctrl;
+
+ pdb_init_sam(&pwd);
+
+ if (!pdb_getsampwrid(pwd, rid)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(pwd);
+
+ ZERO_STRUCT(plaintext_buf);
+
+ if (!decode_pw_buffer(pass, plaintext_buf, 256, &len)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ /* if it's a trust account, don't update /etc/passwd */
+ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) ||
+ ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) ||
+ ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) {
+ DEBUG(5, ("Changing trust account password, not updating /etc/passwd\n"));
+ } else {
+ /* update the UNIX password */
+ if (lp_unix_password_sync())
+ if(!chgpasswd(pdb_get_username(pwd), "", plaintext_buf, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+ }
+
+ ZERO_STRUCT(plaintext_buf);
+
+ DEBUG(5,("set_user_info_pw: pdb_update_sam_account()\n"));
+
+ /* update the SAMBA password */
+ if(!pdb_update_sam_account(pwd, True)) {
+ pdb_free_sam(&pwd);
+ return False;
+ }
+
+ pdb_free_sam(&pwd);
+
+ return True;
+}
+
+/*******************************************************************
+ samr_reply_set_userinfo
+ ********************************************************************/
+
+NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SET_USERINFO *r_u)
+{
+ uint32 rid = 0x0;
+ DOM_SID sid;
+ struct current_user user;
+ SAM_ACCOUNT *sam_pass=NULL;
+ unsigned char sess_key[16];
+ POLICY_HND *pol = &q_u->pol;
+ uint16 switch_value = q_u->switch_value;
+ SAM_USERINFO_CTR *ctr = q_u->ctr;
+ BOOL ret;
+
+ DEBUG(5, ("_samr_set_userinfo: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_OK;
+
+ if (p->ntlmssp_auth_validated) {
+ memcpy(&user, &p->pipe_user, sizeof(user));
+ } else {
+ extern struct current_user current_user;
+ memcpy(&user, &current_user, sizeof(user));
+ }
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_split_rid(&sid, &rid);
+
+ DEBUG(5, ("_samr_set_userinfo: rid:0x%x, level:%d\n", rid, switch_value));
+
+ if (ctr == NULL) {
+ DEBUG(5, ("_samr_set_userinfo: NULL info level\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+
+ pdb_init_sam(&sam_pass);
+
+ /*
+ * We need the NT hash of the user who is changing the user's password.
+ * This NT hash is used to generate a "user session key"
+ * This "user session key" is in turn used to encrypt/decrypt the user's password.
+ */
+
+ become_root();
+ ret = pdb_getsampwuid(sam_pass, user.uid);
+ unbecome_root();
+ if(ret == False) {
+ DEBUG(0,("_samr_set_userinfo: Unable to get smbpasswd entry for uid %u\n", (unsigned int)user.uid ));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memset(sess_key, '\0', 16);
+ mdfour(sess_key, pdb_get_nt_passwd(sam_pass), 16);
+
+ pdb_free_sam(&sam_pass);
+
+ /* ok! user info levels (lots: see MSDEV help), off we go... */
+ switch (switch_value) {
+ case 0x12:
+ if (!set_user_info_12(ctr->info.id12, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+
+ case 24:
+ SamOEMhash(ctr->info.id24->pass, sess_key, 516);
+
+ dump_data(100, (char *)ctr->info.id24->pass, 516);
+
+ if (!set_user_info_pw((char *)ctr->info.id24->pass, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+
+ case 25:
+#if 0
+ /*
+ * Currently we don't really know how to unmarshall
+ * the level 25 struct, and the password encryption
+ * is different. This is a placeholder for when we
+ * do understand it. In the meantime just return INVALID
+ * info level and W2K SP2 drops down to level 23... JRA.
+ */
+
+ SamOEMhash(ctr->info.id25->pass, sess_key, 532);
+
+ dump_data(100, (char *)ctr->info.id25->pass, 532);
+
+ if (!set_user_info_pw(ctr->info.id25->pass, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+#endif
+ return NT_STATUS_INVALID_INFO_CLASS;
+
+ case 23:
+ SamOEMhash(ctr->info.id23->pass, sess_key, 516);
+
+ dump_data(100, (char *)ctr->info.id23->pass, 516);
+
+ if (!set_user_info_23(ctr->info.id23, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ samr_reply_set_userinfo2
+ ********************************************************************/
+
+NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_SET_USERINFO2 *r_u)
+{
+ DOM_SID sid;
+ uint32 rid = 0x0;
+ SAM_USERINFO_CTR *ctr = q_u->ctr;
+ POLICY_HND *pol = &q_u->pol;
+ uint16 switch_value = q_u->switch_value;
+
+ DEBUG(5, ("samr_reply_set_userinfo2: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_OK;
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_split_rid(&sid, &rid);
+
+ DEBUG(5, ("samr_reply_set_userinfo2: rid:0x%x\n", rid));
+
+ if (ctr == NULL) {
+ DEBUG(5, ("samr_reply_set_userinfo2: NULL info level\n"));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ switch_value=ctr->switch_value;
+
+ /* ok! user info levels (lots: see MSDEV help), off we go... */
+ switch (switch_value) {
+ case 21:
+ if (!set_user_info_21(ctr->info.id21, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+ case 16:
+ if (!set_user_info_10(ctr->info.id10, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+ case 18:
+ /* Used by AS/U JRA. */
+ if (!set_user_info_12(ctr->info.id12, rid))
+ return NT_STATUS_ACCESS_DENIED;
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return r_u->status;
+}
+
+/*********************************************************************
+ _samr_query_aliasmem
+*********************************************************************/
+
+NTSTATUS _samr_query_useraliases(pipes_struct *p, SAMR_Q_QUERY_USERALIASES *q_u, SAMR_R_QUERY_USERALIASES *r_u)
+{
+ int num_groups = 0, tmp_num_groups=0;
+ uint32 *rids=NULL, *new_rids=NULL, *tmp_rids=NULL;
+ struct samr_info *info = NULL;
+ int i,j;
+ /* until i see a real useraliases query, we fack one up */
+
+ /* I have seen one, JFM 2/12/2001 */
+ /*
+ * Explanation of what this call does:
+ * for all the SID given in the request:
+ * return a list of alias (local groups)
+ * that have those SID as members.
+ *
+ * and that's the alias in the domain specified
+ * in the policy_handle
+ *
+ * if the policy handle is on an incorrect sid
+ * for example a user's sid
+ * we should reply NT_STATUS_OBJECT_TYPE_MISMATCH
+ */
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_query_useraliases: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_domain(&info->sid) &&
+ !sid_check_is_builtin(&info->sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+
+ for (i=0; i<q_u->num_sids1; i++) {
+
+ r_u->status=get_alias_user_groups(p->mem_ctx, &info->sid, &tmp_num_groups, &tmp_rids, &(q_u->sid[i].sid));
+
+ /*
+ * if there is an error, we just continue as
+ * it can be an unfound user or group
+ */
+ if (NT_STATUS_IS_ERR(r_u->status)) {
+ DEBUG(10,("_samr_query_useraliases: an error occured while getting groups\n"));
+ continue;
+ }
+
+ if (tmp_num_groups==0) {
+ DEBUG(10,("_samr_query_useraliases: no groups found\n"));
+ continue;
+ }
+
+ new_rids=(uint32 *)talloc_realloc(p->mem_ctx, rids, (num_groups+tmp_num_groups)*sizeof(uint32));
+ if (new_rids==NULL) {
+ DEBUG(0,("_samr_query_useraliases: could not realloc memory\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ rids=new_rids;
+
+ for (j=0; j<tmp_num_groups; j++)
+ rids[j+num_groups]=tmp_rids[j];
+
+ safe_free(tmp_rids);
+
+ num_groups+=tmp_num_groups;
+ }
+
+ init_samr_r_query_useraliases(r_u, num_groups, rids, NT_STATUS_OK);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_query_aliasmem
+*********************************************************************/
+
+NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_R_QUERY_ALIASMEM *r_u)
+{
+ int i;
+
+ GROUP_MAP map;
+ int num_uids = 0;
+ DOM_SID2 *sid;
+ uid_t *uid=NULL;
+
+ DOM_SID alias_sid;
+ DOM_SID als_sid;
+ uint32 alias_rid;
+ fstring alias_sid_str;
+ DOM_SID temp_sid;
+
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_copy(&als_sid, &alias_sid);
+ sid_to_string(alias_sid_str, &alias_sid);
+ sid_split_rid(&alias_sid, &alias_rid);
+
+ DEBUG(10, ("sid is %s\n", alias_sid_str));
+
+ if (sid_equal(&alias_sid, &global_sid_Builtin)) {
+ DEBUG(10, ("lookup on Builtin SID (S-1-5-32)\n"));
+ if(!get_local_group_from_sid(als_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+ } else {
+ if (sid_equal(&alias_sid, &global_sam_sid)) {
+ DEBUG(10, ("lookup on Server SID\n"));
+ if(!get_local_group_from_sid(als_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+ }
+
+ if(!get_uid_list_of_group(map.gid, &uid, &num_uids))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ DEBUG(10, ("sid is %s\n", alias_sid_str));
+ sid = (DOM_SID2 *)talloc_zero(p->mem_ctx, sizeof(DOM_SID2) * num_uids);
+ if (num_uids!=0 && sid == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_uids; i++) {
+ sid_copy(&temp_sid, &global_sam_sid);
+ sid_append_rid(&temp_sid, pdb_uid_to_user_rid(uid[i]));
+
+ init_dom_sid2(&sid[i], &temp_sid);
+ }
+
+ DEBUG(10, ("sid is %s\n", alias_sid_str));
+ init_samr_r_query_aliasmem(r_u, num_uids, sid, NT_STATUS_OK);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_query_groupmem
+*********************************************************************/
+
+NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_R_QUERY_GROUPMEM *r_u)
+{
+ int num_uids = 0;
+ int i;
+ DOM_SID group_sid;
+ uint32 group_rid;
+ fstring group_sid_str;
+ uid_t *uid=NULL;
+
+ GROUP_MAP map;
+
+ uint32 *rid=NULL;
+ uint32 *attr=NULL;
+
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->group_pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* todo: change to use sid_compare_front */
+
+ sid_split_rid(&group_sid, &group_rid);
+ sid_to_string(group_sid_str, &group_sid);
+ DEBUG(10, ("sid is %s\n", group_sid_str));
+
+ /* can we get a query for an SID outside our domain ? */
+ if (!sid_equal(&group_sid, &global_sam_sid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ sid_append_rid(&group_sid, group_rid);
+ DEBUG(10, ("lookup on Domain SID\n"));
+
+ if(!get_domain_group_from_sid(group_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if(!get_uid_list_of_group(map.gid, &uid, &num_uids))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ rid=talloc_zero(p->mem_ctx, sizeof(uint32)*num_uids);
+ attr=talloc_zero(p->mem_ctx, sizeof(uint32)*num_uids);
+
+ if (num_uids!=0 && (rid==NULL || attr==NULL))
+ return NT_STATUS_NO_MEMORY;
+
+ for (i=0; i<num_uids; i++) {
+ rid[i]=pdb_uid_to_user_rid(uid[i]);
+ attr[i] = SID_NAME_USER;
+ }
+
+ init_samr_r_query_groupmem(r_u, num_uids, rid, attr, NT_STATUS_OK);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_add_aliasmem
+*********************************************************************/
+
+NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_ADD_ALIASMEM *r_u)
+{
+ DOM_SID alias_sid;
+ fstring alias_sid_str;
+ uid_t uid;
+ struct passwd *pwd;
+ struct group *grp;
+ fstring grp_name;
+ uint32 rid;
+ GROUP_MAP map;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_to_string(alias_sid_str, &alias_sid);
+ DEBUG(10, ("sid is %s\n", alias_sid_str));
+
+ if (sid_compare(&alias_sid, &global_sam_sid)>0) {
+ DEBUG(10, ("adding member on Server SID\n"));
+ if(!get_local_group_from_sid(alias_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ } else {
+ if (sid_compare(&alias_sid, &global_sid_Builtin)>0) {
+ DEBUG(10, ("adding member on BUILTIN SID\n"));
+ if( !get_local_group_from_sid(alias_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ } else
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ sid_split_rid(&q_u->sid.sid, &rid);
+ uid=pdb_user_rid_to_uid(rid);
+
+ if ((pwd=getpwuid(uid)) == NULL)
+ return NT_STATUS_NO_SUCH_USER;
+
+ if ((grp=getgrgid(map.gid)) == NULL)
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ /* we need to copy the name otherwise it's overloaded in user_in_group_list */
+ fstrcpy(grp_name, grp->gr_name);
+
+ /* if the user is already in the group */
+ if(user_in_group_list(pwd->pw_name, grp_name))
+ return NT_STATUS_MEMBER_IN_ALIAS;
+
+ /*
+ * ok, the group exist, the user exist, the user is not in the group,
+ * we can (finally) add it to the group !
+ */
+ smb_add_user_group(grp_name, pwd->pw_name);
+
+ /* check if the user has been added then ... */
+ if(!user_in_group_list(pwd->pw_name, grp_name))
+ return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_del_aliasmem
+*********************************************************************/
+
+NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DEL_ALIASMEM *r_u)
+{
+ DOM_SID alias_sid;
+ fstring alias_sid_str;
+ struct group *grp;
+ fstring grp_name;
+ uint32 rid;
+ GROUP_MAP map;
+ SAM_ACCOUNT *sam_pass=NULL;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_to_string(alias_sid_str, &alias_sid);
+ DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", alias_sid_str));
+
+ if (!sid_check_is_in_our_domain(&alias_sid) &&
+ !sid_check_is_in_builtin(&alias_sid)) {
+ DEBUG(10, ("_samr_del_aliasmem:invalid alias group\n"));
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if( !get_local_group_from_sid(alias_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ((grp=getgrgid(map.gid)) == NULL)
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ /* we need to copy the name otherwise it's overloaded in user_in_group_list */
+ fstrcpy(grp_name, grp->gr_name);
+
+ sid_peek_rid(&q_u->sid.sid, &rid);
+
+ /* check if the user exists before trying to remove it from the group */
+ pdb_init_sam(&sam_pass);
+ if(!pdb_getsampwrid(sam_pass, rid)) {
+ DEBUG(5,("_samr_del_aliasmem:User %s doesn't exist.\n", sam_pass->username));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* if the user is not in the group */
+ if(!user_in_group_list(sam_pass->username, grp_name)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_MEMBER_IN_ALIAS;
+ }
+
+ smb_delete_user_group(grp_name, sam_pass->username);
+
+ /* check if the user has been removed then ... */
+ if(user_in_group_list(sam_pass->username, grp_name)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */
+ }
+
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_add_groupmem
+*********************************************************************/
+
+NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_ADD_GROUPMEM *r_u)
+{
+ DOM_SID group_sid;
+ fstring group_sid_str;
+ struct passwd *pwd;
+ struct group *grp;
+ fstring grp_name;
+ GROUP_MAP map;
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_to_string(group_sid_str, &group_sid);
+ DEBUG(10, ("sid is %s\n", group_sid_str));
+
+ if (sid_compare(&group_sid, &global_sam_sid)<=0)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ DEBUG(10, ("lookup on Domain SID\n"));
+
+ if(!get_domain_group_from_sid(group_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if ((pwd=getpwuid(pdb_user_rid_to_uid(q_u->rid))) ==NULL)
+ return NT_STATUS_NO_SUCH_USER;
+
+ if ((grp=getgrgid(map.gid)) == NULL)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /* we need to copy the name otherwise it's overloaded in user_in_group_list */
+ fstrcpy(grp_name, grp->gr_name);
+
+ /* if the user is already in the group */
+ if(user_in_group_list(pwd->pw_name, grp_name))
+ return NT_STATUS_MEMBER_IN_GROUP;
+
+ /*
+ * ok, the group exist, the user exist, the user is not in the group,
+ *
+ * we can (finally) add it to the group !
+ */
+
+ smb_add_user_group(grp_name, pwd->pw_name);
+
+ /* check if the user has been added then ... */
+ if(!user_in_group_list(pwd->pw_name, grp_name))
+ return NT_STATUS_MEMBER_NOT_IN_GROUP; /* don't know what to reply else */
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_del_groupmem
+*********************************************************************/
+
+NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DEL_GROUPMEM *r_u)
+{
+ DOM_SID group_sid;
+ SAM_ACCOUNT *sam_pass=NULL;
+ uint32 rid;
+ GROUP_MAP map;
+ fstring grp_name;
+ struct group *grp;
+
+ /*
+ * delete the group member named q_u->rid
+ * who is a member of the sid associated with the handle
+ * the rid is a user's rid as the group is a domain group.
+ */
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if(!sid_check_is_in_our_domain(&group_sid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ rid=q_u->rid;
+
+ if(!get_domain_group_from_sid(group_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if ((grp=getgrgid(map.gid)) == NULL)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /* we need to copy the name otherwise it's overloaded in user_in_group_list */
+ fstrcpy(grp_name, grp->gr_name);
+
+ /* check if the user exists before trying to remove it from the group */
+ pdb_init_sam(&sam_pass);
+ if(!pdb_getsampwrid(sam_pass, rid)) {
+ DEBUG(5,("User %s doesn't exist.\n", sam_pass->username));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* if the user is not in the group */
+ if(!user_in_group_list(sam_pass->username, grp_name)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_MEMBER_NOT_IN_GROUP;
+ }
+
+ smb_delete_user_group(grp_name, sam_pass->username);
+
+ /* check if the user has been removed then ... */
+ if(user_in_group_list(sam_pass->username, grp_name)) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_ACCESS_DENIED; /* don't know what to reply else */
+ }
+
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_OK;
+
+}
+
+/*********************************************************************
+ _samr_delete_dom_user
+*********************************************************************/
+
+NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAMR_R_DELETE_DOM_USER *r_u )
+{
+ DOM_SID user_sid;
+ SAM_ACCOUNT *sam_pass=NULL;
+ uint32 rid;
+
+ DEBUG(5, ("_samr_delete_dom_user: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->user_pol, &user_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_check_is_in_our_domain(&user_sid))
+ return NT_STATUS_CANNOT_DELETE;
+
+ sid_peek_rid(&user_sid, &rid);
+
+ /* check if the user exists before trying to delete */
+ pdb_init_sam(&sam_pass);
+ if(!pdb_getsampwrid(sam_pass, rid)) {
+ DEBUG(5,("_samr_delete_dom_user:User %s doesn't exist.\n", sam_pass->username));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* delete the unix side */
+ /*
+ * note: we don't check if the delete really happened
+ * as the script is not necessary present
+ * and maybe the sysadmin doesn't want to delete the unix side
+ */
+ smb_delete_user(sam_pass->username);
+
+ /* and delete the samba side */
+ if (!pdb_delete_sam_account(sam_pass->username)) {
+ DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", sam_pass->username));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_CANNOT_DELETE;
+ }
+
+ pdb_free_sam(&sam_pass);
+
+ if (!close_policy_hnd(p, &q_u->user_pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_delete_dom_group
+*********************************************************************/
+
+NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, SAMR_R_DELETE_DOM_GROUP *r_u)
+{
+ DOM_SID group_sid;
+ DOM_SID dom_sid;
+ uint32 group_rid;
+ fstring group_sid_str;
+ gid_t gid;
+ struct group *grp;
+ GROUP_MAP map;
+
+ DEBUG(5, ("samr_delete_dom_group: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->group_pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_copy(&dom_sid, &group_sid);
+ sid_to_string(group_sid_str, &dom_sid);
+ sid_split_rid(&dom_sid, &group_rid);
+
+ DEBUG(10, ("sid is %s\n", group_sid_str));
+
+ /* we check if it's our SID before deleting */
+ if (!sid_equal(&dom_sid, &global_sam_sid))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ DEBUG(10, ("lookup on Domain SID\n"));
+
+ if(!get_domain_group_from_sid(group_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ gid=map.gid;
+
+ /* check if group really exists */
+ if ( (grp=getgrgid(gid)) == NULL)
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /* we can delete the UNIX group */
+ smb_delete_group(grp->gr_name);
+
+ /* check if the group has been successfully deleted */
+ if ( (grp=getgrgid(gid)) != NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if(!group_map_remove(group_sid))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!close_policy_hnd(p, &q_u->group_pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_delete_dom_alias
+*********************************************************************/
+
+NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, SAMR_R_DELETE_DOM_ALIAS *r_u)
+{
+ DOM_SID alias_sid;
+ DOM_SID dom_sid;
+ uint32 alias_rid;
+ fstring alias_sid_str;
+ gid_t gid;
+ struct group *grp;
+ GROUP_MAP map;
+
+ DEBUG(5, ("_samr_delete_dom_alias: %d\n", __LINE__));
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_copy(&dom_sid, &alias_sid);
+ sid_to_string(alias_sid_str, &dom_sid);
+ sid_split_rid(&dom_sid, &alias_rid);
+
+ DEBUG(10, ("sid is %s\n", alias_sid_str));
+
+ /* we check if it's our SID before deleting */
+ if (!sid_equal(&dom_sid, &global_sam_sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ DEBUG(10, ("lookup on Local SID\n"));
+
+ if(!get_local_group_from_sid(alias_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ gid=map.gid;
+
+ /* check if group really exists */
+ if ( (grp=getgrgid(gid)) == NULL)
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ /* we can delete the UNIX group */
+ smb_delete_group(grp->gr_name);
+
+ /* check if the group has been successfully deleted */
+ if ( (grp=getgrgid(gid)) != NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* don't check if we removed it as it could be an un-mapped group */
+ group_map_remove(alias_sid);
+
+ if (!close_policy_hnd(p, &q_u->alias_pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_create_dom_group
+*********************************************************************/
+
+NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, SAMR_R_CREATE_DOM_GROUP *r_u)
+{
+ DOM_SID dom_sid;
+ DOM_SID info_sid;
+ fstring name;
+ fstring sid_string;
+ struct group *grp;
+ struct samr_info *info;
+ PRIVILEGE_SET priv_set;
+
+ init_privilege(&priv_set);
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &dom_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_equal(&dom_sid, &global_sam_sid))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* TODO: check if allowed to create group and add a become_root/unbecome_root pair.*/
+
+ unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1);
+
+ /* check if group already exist */
+ if ((grp=getgrnam(name)) != NULL)
+ return NT_STATUS_GROUP_EXISTS;
+
+ /* we can create the UNIX group */
+ smb_create_group(name);
+
+ /* check if the group has been successfully created */
+ if ((grp=getgrnam(name)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ r_u->rid=pdb_gid_to_group_rid(grp->gr_gid);
+
+ /* add the group to the mapping table */
+ if(!add_initial_entry(grp->gr_gid, sid_string, SID_NAME_DOM_GRP, name, NULL, priv_set, PR_ACCESS_FROM_NETWORK))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+
+ sid_copy(&info_sid, &global_sam_sid);
+ sid_append_rid(&info->sid, r_u->rid);
+ sid_to_string(sid_string, &info->sid);
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_create_dom_alias
+*********************************************************************/
+
+NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, SAMR_R_CREATE_DOM_ALIAS *r_u)
+{
+ DOM_SID dom_sid;
+ fstring name;
+ fstring sid_string;
+ struct group *grp;
+ struct samr_info *info;
+ PRIVILEGE_SET priv_set;
+
+ init_privilege(&priv_set);
+
+ /* Find the policy handle. Open a policy on it. */
+ if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &dom_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!sid_equal(&dom_sid, &global_sam_sid))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* TODO: check if allowed to create group and add a become_root/unbecome_root pair.*/
+
+ unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1);
+
+ /* check if group already exists */
+ if ( (grp=getgrnam(name)) != NULL)
+ return NT_STATUS_GROUP_EXISTS;
+
+ /* we can create the UNIX group */
+ smb_create_group(name);
+
+ /* check if the group has been successfully created */
+ if ((grp=getgrnam(name)) == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ r_u->rid=pdb_gid_to_group_rid(grp->gr_gid);
+
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+
+ sid_copy(&info->sid, &global_sam_sid);
+ sid_append_rid(&info->sid, r_u->rid);
+ sid_to_string(sid_string, &info->sid);
+
+ /* add the group to the mapping table */
+ if(!add_initial_entry(grp->gr_gid, sid_string, SID_NAME_ALIAS, name, NULL, priv_set, PR_ACCESS_FROM_NETWORK))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->alias_pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_query_groupinfo
+
+sends the name/comment pair of a domain group
+level 1 send also the number of users of that group
+*********************************************************************/
+
+NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAMR_R_QUERY_GROUPINFO *r_u)
+{
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ uid_t *uid=NULL;
+ int num_uids=0;
+ GROUP_INFO_CTR *ctr;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_domain_group_from_sid(group_sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_INVALID_HANDLE;
+
+ ctr=(GROUP_INFO_CTR *)talloc_zero(p->mem_ctx, sizeof(GROUP_INFO_CTR));
+ if (ctr==NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ switch (q_u->switch_level) {
+ case 1:
+ ctr->switch_value1 = 1;
+ if(!get_uid_list_of_group(map.gid, &uid, &num_uids))
+ return NT_STATUS_NO_SUCH_GROUP;
+ init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num_uids);
+ SAFE_FREE(uid);
+ break;
+ case 3:
+ ctr->switch_value1 = 3;
+ init_samr_group_info3(&ctr->group.info3);
+ break;
+ case 4:
+ ctr->switch_value1 = 4;
+ init_samr_group_info4(&ctr->group.info4, map.comment);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_samr_r_query_groupinfo(r_u, ctr, NT_STATUS_OK);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_set_groupinfo
+
+ update a domain group's comment.
+*********************************************************************/
+
+NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_SET_GROUPINFO *r_u)
+{
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ GROUP_INFO_CTR *ctr;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_domain_group_from_sid(group_sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ ctr=q_u->ctr;
+
+ switch (ctr->switch_value1) {
+ case 1:
+ unistr2_to_ascii(map.comment, &(ctr->group.info1.uni_acct_desc), sizeof(map.comment)-1);
+ break;
+ case 4:
+ unistr2_to_ascii(map.comment, &(ctr->group.info4.uni_acct_desc), sizeof(map.comment)-1);
+ break;
+ default:
+ free_privilege(&map.priv_set);
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if(!add_mapping_entry(&map, TDB_REPLACE)) {
+ free_privilege(&map.priv_set);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ free_privilege(&map.priv_set);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_set_groupinfo
+
+ update a domain group's comment.
+*********************************************************************/
+
+NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_SET_ALIASINFO *r_u)
+{
+ DOM_SID group_sid;
+ GROUP_MAP map;
+ ALIAS_INFO_CTR *ctr;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &group_sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!get_local_group_from_sid(group_sid, &map, MAPPING_WITH_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ ctr=&q_u->ctr;
+
+ switch (ctr->switch_value1) {
+ case 3:
+ unistr2_to_ascii(map.comment, &(ctr->alias.info3.uni_acct_desc), sizeof(map.comment)-1);
+ break;
+ default:
+ free_privilege(&map.priv_set);
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if(!add_mapping_entry(&map, TDB_REPLACE)) {
+ free_privilege(&map.priv_set);
+ return NT_STATUS_NO_SUCH_GROUP;
+ }
+
+ free_privilege(&map.priv_set);
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_get_dom_pwinfo
+*********************************************************************/
+
+NTSTATUS _samr_get_dom_pwinfo(pipes_struct *p, SAMR_Q_GET_DOM_PWINFO *q_u, SAMR_R_GET_DOM_PWINFO *r_u)
+{
+ /* Actually, returning zeros here works quite well :-). */
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_open_group
+*********************************************************************/
+
+NTSTATUS _samr_open_group(pipes_struct *p, SAMR_Q_OPEN_GROUP *q_u, SAMR_R_OPEN_GROUP *r_u)
+{
+ DOM_SID sid;
+ GROUP_MAP map;
+ struct samr_info *info;
+ fstring sid_string;
+
+ if (!get_lsa_policy_samr_sid(p, &q_u->domain_pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* this should not be hard-coded like this */
+ if (!sid_equal(&sid, &global_sam_sid))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if ((info = (struct samr_info *)malloc(sizeof(struct samr_info))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(info);
+
+ sid_copy(&info->sid, &global_sam_sid);
+ sid_append_rid(&info->sid, q_u->rid_group);
+ sid_to_string(sid_string, &info->sid);
+
+ DEBUG(10, ("_samr_open_group:Opening SID: %s\n", sid_string));
+
+ /* check if that group really exists */
+ if (!get_domain_group_from_sid(info->sid, &map, MAPPING_WITHOUT_PRIV))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!create_policy_hnd(p, &r_u->pol, free_samr_info, (void *)info))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ _samr_unknown_2d
+*********************************************************************/
+
+NTSTATUS _samr_unknown_2d(pipes_struct *p, SAMR_Q_UNKNOWN_2D *q_u, SAMR_R_UNKNOWN_2D *r_u)
+{
+ DEBUG(0,("_samr_unknown_2d: Not yet implemented.\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/*******************************************************************
+ _samr_unknown_2e
+ ********************************************************************/
+
+NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOWN_2E *r_u)
+{
+ SAM_UNK_CTR *ctr;
+ uint32 min_pass_len,pass_hist,flag;
+ time_t u_expire, u_min_age;
+ NTTIME nt_expire, nt_min_age;
+
+ time_t u_lock_duration, u_reset_time;
+ NTTIME nt_lock_duration, nt_reset_time;
+ uint32 lockout;
+
+ time_t u_logout;
+ NTTIME nt_logout;
+
+ if ((ctr = (SAM_UNK_CTR *)talloc_zero(p->mem_ctx, sizeof(SAM_UNK_CTR))) == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(ctr);
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_unknown_2e: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->domain_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ switch (q_u->switch_value) {
+ case 0x01:
+ account_policy_get(AP_MIN_PASSWORD_LEN, &min_pass_len);
+ account_policy_get(AP_PASSWORD_HISTORY, &pass_hist);
+ account_policy_get(AP_USER_MUST_LOGON_TO_CHG_PASS, &flag);
+ account_policy_get(AP_MAX_PASSWORD_AGE, (int *)&u_expire);
+ account_policy_get(AP_MIN_PASSWORD_AGE, (int *)&u_min_age);
+
+ unix_to_nt_time_abs(&nt_expire, u_expire);
+ unix_to_nt_time_abs(&nt_min_age, u_min_age);
+
+ init_unk_info1(&ctr->info.inf1, (uint16)min_pass_len, (uint16)pass_hist,
+ flag, nt_expire, nt_min_age);
+ break;
+ case 0x02:
+ /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */
+ init_unk_info2(&ctr->info.inf2, global_myworkgroup, global_myname, (uint32) time(NULL));
+ break;
+ case 0x03:
+ account_policy_get(AP_TIME_TO_LOGOUT, (int *)&u_logout);
+ unix_to_nt_time_abs(&nt_logout, u_logout);
+
+ init_unk_info3(&ctr->info.inf3, nt_logout);
+ break;
+ case 0x05:
+ init_unk_info5(&ctr->info.inf5, global_myname);
+ break;
+ case 0x06:
+ init_unk_info6(&ctr->info.inf6);
+ break;
+ case 0x07:
+ init_unk_info7(&ctr->info.inf7);
+ break;
+ case 0x0c:
+ account_policy_get(AP_LOCK_ACCOUNT_DURATION, (int *)&u_lock_duration);
+ account_policy_get(AP_RESET_COUNT_TIME, (int *)&u_reset_time);
+ account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &lockout);
+
+ unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
+ unix_to_nt_time_abs(&nt_reset_time, u_reset_time);
+
+ init_unk_info12(&ctr->info.inf12, nt_lock_duration, nt_reset_time, (uint16)lockout);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_samr_r_samr_unknown_2e(r_u, q_u->switch_value, ctr, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_unknown_2e: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ _samr_
+ ********************************************************************/
+
+NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R_SET_DOMAIN_INFO *r_u)
+{
+ time_t u_expire, u_min_age;
+ time_t u_logout;
+ time_t u_lock_duration, u_reset_time;
+
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_samr_set_dom_info: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->domain_pol, NULL))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("_samr_set_dom_info: switch_value: %d\n", q_u->switch_value));
+
+ switch (q_u->switch_value) {
+ case 0x01:
+ u_expire=nt_time_to_unix_abs(&q_u->ctr->info.inf1.expire);
+ u_min_age=nt_time_to_unix_abs(&q_u->ctr->info.inf1.min_passwordage);
+
+ account_policy_set(AP_MIN_PASSWORD_LEN, (uint32)q_u->ctr->info.inf1.min_length_password);
+ account_policy_set(AP_PASSWORD_HISTORY, (uint32)q_u->ctr->info.inf1.password_history);
+ account_policy_set(AP_USER_MUST_LOGON_TO_CHG_PASS, (uint32)q_u->ctr->info.inf1.flag);
+ account_policy_set(AP_MAX_PASSWORD_AGE, (int)u_expire);
+ account_policy_set(AP_MIN_PASSWORD_AGE, (int)u_min_age);
+ break;
+ case 0x02:
+ break;
+ case 0x03:
+ u_logout=nt_time_to_unix_abs(&q_u->ctr->info.inf3.logout);
+ account_policy_set(AP_TIME_TO_LOGOUT, (int)u_logout);
+ break;
+ case 0x05:
+ break;
+ case 0x06:
+ break;
+ case 0x07:
+ break;
+ case 0x0c:
+ u_lock_duration=nt_time_to_unix_abs(&q_u->ctr->info.inf12.duration);
+ u_reset_time=nt_time_to_unix_abs(&q_u->ctr->info.inf12.reset_count);
+
+ account_policy_set(AP_LOCK_ACCOUNT_DURATION, (int)u_lock_duration);
+ account_policy_set(AP_RESET_COUNT_TIME, (int)u_reset_time);
+ account_policy_set(AP_BAD_ATTEMPT_LOCKOUT, (uint32)q_u->ctr->info.inf12.bad_attempt_lockout);
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_samr_r_set_domain_info(r_u, NT_STATUS_OK);
+
+ DEBUG(5,("_samr_set_dom_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
diff --git a/source/rpc_server/srv_spoolss.c b/source/rpc_server/srv_spoolss.c
new file mode 100755
index 00000000000..e71bcd36a9a
--- /dev/null
+++ b/source/rpc_server/srv_spoolss.c
@@ -0,0 +1,1418 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/********************************************************************
+ * api_spoolss_open_printer_ex
+ ********************************************************************/
+
+static BOOL api_spoolss_open_printer_ex(pipes_struct *p)
+{
+ SPOOL_Q_OPEN_PRINTER_EX q_u;
+ SPOOL_R_OPEN_PRINTER_EX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_open_printer_ex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_open_printer_ex: unable to unmarshall SPOOL_Q_OPEN_PRINTER_EX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_open_printer_ex( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_open_printer_ex("",&r_u,rdata,0)){
+ DEBUG(0,("spoolss_io_r_open_printer_ex: unable to marshall SPOOL_R_OPEN_PRINTER_EX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinterdata
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_getprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDATA q_u;
+ SPOOL_R_GETPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_getprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdata: unable to unmarshall SPOOL_Q_GETPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdata( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdata: unable to marshall SPOOL_R_GETPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinterdata
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_deleteprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDATA q_u;
+ SPOOL_R_DELETEPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_deleteprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdata: unable to unmarshall SPOOL_Q_DELETEPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdata( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinterdata: unable to marshall SPOOL_R_DELETEPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_closeprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_closeprinter(pipes_struct *p)
+{
+ SPOOL_Q_CLOSEPRINTER q_u;
+ SPOOL_R_CLOSEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_closeprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_closeprinter: unable to unmarshall SPOOL_Q_CLOSEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_closeprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_closeprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_closeprinter: unable to marshall SPOOL_R_CLOSEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_abortprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_abortprinter(pipes_struct *p)
+{
+ SPOOL_Q_ABORTPRINTER q_u;
+ SPOOL_R_ABORTPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_abortprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_abortprinter: unable to unmarshall SPOOL_Q_ABORTPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_abortprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_abortprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_abortprinter: unable to marshall SPOOL_R_ABORTPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinter
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_deleteprinter(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTER q_u;
+ SPOOL_R_DELETEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_deleteprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinter: unable to unmarshall SPOOL_Q_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinter(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinter: unable to marshall SPOOL_R_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_deleteprinterdriver
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_deleteprinterdriver(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDRIVER q_u;
+ SPOOL_R_DELETEPRINTERDRIVER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_deleteprinterdriver("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdriver: unable to unmarshall SPOOL_Q_DELETEPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdriver(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinterdriver("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinter: unable to marshall SPOOL_R_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_rffpcnex
+ * ReplyFindFirstPrinterChangeNotifyEx
+ ********************************************************************/
+
+static BOOL api_spoolss_rffpcnex(pipes_struct *p)
+{
+ SPOOL_Q_RFFPCNEX q_u;
+ SPOOL_R_RFFPCNEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_rffpcnex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_rffpcnex: unable to unmarshall SPOOL_Q_RFFPCNEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_rffpcnex(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_rffpcnex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_rffpcnex: unable to marshall SPOOL_R_RFFPCNEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_rfnpcnex
+ * ReplyFindNextPrinterChangeNotifyEx
+ * called from the spoolss dispatcher
+
+ * Note - this is the *ONLY* function that breaks the RPC call
+ * symmetry in all the other calls. We need to do this to fix
+ * the massive memory allocation problem with thousands of jobs...
+ * JRA.
+ ********************************************************************/
+
+static BOOL api_spoolss_rfnpcnex(pipes_struct *p)
+{
+ SPOOL_Q_RFNPCNEX q_u;
+ SPOOL_R_RFNPCNEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_rfnpcnex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_rfnpcnex: unable to unmarshall SPOOL_Q_RFNPCNEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_rfnpcnex(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_rfnpcnex("", &r_u, rdata, 0)) {
+ SAFE_FREE(r_u.info.data);
+ DEBUG(0,("spoolss_io_r_rfnpcnex: unable to marshall SPOOL_R_RFNPCNEX.\n"));
+ return False;
+ }
+
+ SAFE_FREE(r_u.info.data);
+
+ return True;
+}
+
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static BOOL api_spoolss_enumprinters(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERS q_u;
+ SPOOL_R_ENUMPRINTERS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprinters("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinters: unable to unmarshall SPOOL_Q_ENUMPRINTERS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinters( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprinters("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinters: unable to marshall SPOOL_R_ENUMPRINTERS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static BOOL api_spoolss_getprinter(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTER q_u;
+ SPOOL_R_GETPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinter: unable to unmarshall SPOOL_Q_GETPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getprinter: unable to marshall SPOOL_R_GETPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static BOOL api_spoolss_getprinterdriver2(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDRIVER2 q_u;
+ SPOOL_R_GETPRINTERDRIVER2 r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinterdriver2("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdriver2: unable to unmarshall SPOOL_Q_GETPRINTERDRIVER2.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdriver2(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinterdriver2("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdriver2: unable to marshall SPOOL_R_GETPRINTERDRIVER2.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static BOOL api_spoolss_startpageprinter(pipes_struct *p)
+{
+ SPOOL_Q_STARTPAGEPRINTER q_u;
+ SPOOL_R_STARTPAGEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_startpageprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_startpageprinter: unable to unmarshall SPOOL_Q_STARTPAGEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_startpageprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_startpageprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_startpageprinter: unable to marshall SPOOL_R_STARTPAGEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+static BOOL api_spoolss_endpageprinter(pipes_struct *p)
+{
+ SPOOL_Q_ENDPAGEPRINTER q_u;
+ SPOOL_R_ENDPAGEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_endpageprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_endpageprinter: unable to unmarshall SPOOL_Q_ENDPAGEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_endpageprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_endpageprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_endpageprinter: unable to marshall SPOOL_R_ENDPAGEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static BOOL api_spoolss_startdocprinter(pipes_struct *p)
+{
+ SPOOL_Q_STARTDOCPRINTER q_u;
+ SPOOL_R_STARTDOCPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_startdocprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_startdocprinter: unable to unmarshall SPOOL_Q_STARTDOCPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_startdocprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_startdocprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_startdocprinter: unable to marshall SPOOL_R_STARTDOCPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static BOOL api_spoolss_enddocprinter(pipes_struct *p)
+{
+ SPOOL_Q_ENDDOCPRINTER q_u;
+ SPOOL_R_ENDDOCPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enddocprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enddocprinter: unable to unmarshall SPOOL_Q_ENDDOCPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enddocprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enddocprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enddocprinter: unable to marshall SPOOL_R_ENDDOCPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static BOOL api_spoolss_writeprinter(pipes_struct *p)
+{
+ SPOOL_Q_WRITEPRINTER q_u;
+ SPOOL_R_WRITEPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_writeprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_writeprinter: unable to unmarshall SPOOL_Q_WRITEPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_writeprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_writeprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_writeprinter: unable to marshall SPOOL_R_WRITEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+
+****************************************************************************/
+
+static BOOL api_spoolss_setprinter(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTER q_u;
+ SPOOL_R_SETPRINTER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinter("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinter: unable to unmarshall SPOOL_Q_SETPRINTER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinter(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinter("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_setprinter: unable to marshall SPOOL_R_SETPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_fcpn(pipes_struct *p)
+{
+ SPOOL_Q_FCPN q_u;
+ SPOOL_R_FCPN r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_fcpn("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_fcpn: unable to unmarshall SPOOL_Q_FCPN.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_fcpn(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_fcpn("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_fcpn: unable to marshall SPOOL_R_FCPN.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_addjob(pipes_struct *p)
+{
+ SPOOL_Q_ADDJOB q_u;
+ SPOOL_R_ADDJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addjob: unable to unmarshall SPOOL_Q_ADDJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_addjob: unable to marshall SPOOL_R_ADDJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumjobs(pipes_struct *p)
+{
+ SPOOL_Q_ENUMJOBS q_u;
+ SPOOL_R_ENUMJOBS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumjobs("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumjobs: unable to unmarshall SPOOL_Q_ENUMJOBS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumjobs(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumjobs("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumjobs: unable to marshall SPOOL_R_ENUMJOBS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_schedulejob(pipes_struct *p)
+{
+ SPOOL_Q_SCHEDULEJOB q_u;
+ SPOOL_R_SCHEDULEJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_schedulejob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_schedulejob: unable to unmarshall SPOOL_Q_SCHEDULEJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_schedulejob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_schedulejob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_schedulejob: unable to marshall SPOOL_R_SCHEDULEJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_setjob(pipes_struct *p)
+{
+ SPOOL_Q_SETJOB q_u;
+ SPOOL_R_SETJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setjob: unable to unmarshall SPOOL_Q_SETJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_setjob: unable to marshall SPOOL_R_SETJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprinterdrivers(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDRIVERS q_u;
+ SPOOL_R_ENUMPRINTERDRIVERS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprinterdrivers("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdrivers: unable to unmarshall SPOOL_Q_ENUMPRINTERDRIVERS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdrivers(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprinterdrivers("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdrivers: unable to marshall SPOOL_R_ENUMPRINTERDRIVERS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_getform(pipes_struct *p)
+{
+ SPOOL_Q_GETFORM q_u;
+ SPOOL_R_GETFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_getform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getform: unable to unmarshall SPOOL_Q_GETFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getform(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getform("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getform: unable to marshall SPOOL_R_GETFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumforms(pipes_struct *p)
+{
+ SPOOL_Q_ENUMFORMS q_u;
+ SPOOL_R_ENUMFORMS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumforms("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumforms: unable to unmarshall SPOOL_Q_ENUMFORMS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumforms(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumforms("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumforms: unable to marshall SPOOL_R_ENUMFORMS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumports(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPORTS q_u;
+ SPOOL_R_ENUMPORTS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumports("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumports: unable to unmarshall SPOOL_Q_ENUMPORTS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumports(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumports("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_enumports: unable to marshall SPOOL_R_ENUMPORTS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_addprinterex(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTEREX q_u;
+ SPOOL_R_ADDPRINTEREX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprinterex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addprinterex: unable to unmarshall SPOOL_Q_ADDPRINTEREX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addprinterex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addprinterex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprinterex: unable to marshall SPOOL_R_ADDPRINTEREX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_addprinterdriver(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTERDRIVER q_u;
+ SPOOL_R_ADDPRINTERDRIVER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprinterdriver("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addprinterdriver: unable to unmarshall SPOOL_Q_ADDPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addprinterdriver(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addprinterdriver("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprinterdriver: unable to marshall SPOOL_R_ADDPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_getprinterdriverdirectory(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDRIVERDIR q_u;
+ SPOOL_R_GETPRINTERDRIVERDIR r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprinterdriverdir("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdriverdir: unable to unmarshall SPOOL_Q_GETPRINTERDRIVERDIR.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdriverdirectory(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprinterdriverdir("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdriverdir: unable to marshall SPOOL_R_GETPRINTERDRIVERDIR.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDATA q_u;
+ SPOOL_R_ENUMPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdata: unable to unmarshall SPOOL_Q_ENUMPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdata(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdata: unable to marshall SPOOL_R_ENUMPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_setprinterdata(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTERDATA q_u;
+ SPOOL_R_SETPRINTERDATA r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinterdata("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterdata: unable to unmarshall SPOOL_Q_SETPRINTERDATA.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinterdata(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinterdata("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setprinterdata: unable to marshall SPOOL_R_SETPRINTERDATA.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_addform(pipes_struct *p)
+{
+ SPOOL_Q_ADDFORM q_u;
+ SPOOL_R_ADDFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addform: unable to unmarshall SPOOL_Q_ADDFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_addform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_addform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addform: unable to marshall SPOOL_R_ADDFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_deleteform(pipes_struct *p)
+{
+ SPOOL_Q_DELETEFORM q_u;
+ SPOOL_R_DELETEFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_deleteform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteform: unable to unmarshall SPOOL_Q_DELETEFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_deleteform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_deleteform: unable to marshall SPOOL_R_DELETEFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_setform(pipes_struct *p)
+{
+ SPOOL_Q_SETFORM q_u;
+ SPOOL_R_SETFORM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setform("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setform: unable to unmarshall SPOOL_Q_SETFORM.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setform(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setform("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setform: unable to marshall SPOOL_R_SETFORM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprintprocessors(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTPROCESSORS q_u;
+ SPOOL_R_ENUMPRINTPROCESSORS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprintprocessors("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintprocessors: unable to unmarshall SPOOL_Q_ENUMPRINTPROCESSORS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintprocessors(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprintprocessors("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintprocessors: unable to marshall SPOOL_R_ENUMPRINTPROCESSORS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_addprintprocessor(pipes_struct *p)
+{
+ SPOOL_Q_ADDPRINTPROCESSOR q_u;
+ SPOOL_R_ADDPRINTPROCESSOR r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_addprintprocessor("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_addprintprocessor: unable to unmarshall SPOOL_Q_ADDPRINTPROCESSOR.\n"));
+ return False;
+ }
+
+ /* for now, just indicate success and ignore the add. We'll
+ automatically set the winprint processor for printer
+ entries later. Used to debug the LexMark Optra S 1855 PCL
+ driver --jerry */
+ r_u.status = WERR_OK;
+
+ if(!spoolss_io_r_addprintprocessor("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_addprintprocessor: unable to marshall SPOOL_R_ADDPRINTPROCESSOR.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprintprocdatatypes(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTPROCDATATYPES q_u;
+ SPOOL_R_ENUMPRINTPROCDATATYPES r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprintprocdatatypes("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintprocdatatypes: unable to unmarshall SPOOL_Q_ENUMPRINTPROCDATATYPES.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintprocdatatypes(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprintprocdatatypes("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintprocdatatypes: unable to marshall SPOOL_R_ENUMPRINTPROCDATATYPES.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprintmonitors(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTMONITORS q_u;
+ SPOOL_R_ENUMPRINTMONITORS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_enumprintmonitors("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprintmonitors: unable to unmarshall SPOOL_Q_ENUMPRINTMONITORS.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprintmonitors(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_enumprintmonitors("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprintmonitors: unable to marshall SPOOL_R_ENUMPRINTMONITORS.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_getjob(pipes_struct *p)
+{
+ SPOOL_Q_GETJOB q_u;
+ SPOOL_R_GETJOB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ if(!spoolss_io_q_getjob("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getjob: unable to unmarshall SPOOL_Q_GETJOB.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getjob(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getjob("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_getjob: unable to marshall SPOOL_R_GETJOB.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/********************************************************************
+ * api_spoolss_getprinterdataex
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_getprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTERDATAEX q_u;
+ SPOOL_R_GETPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* read the stream and fill the struct */
+ if (!spoolss_io_q_getprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprinterdataex: unable to unmarshall SPOOL_Q_GETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprinterdataex( p, &q_u, &r_u);
+
+ if (!spoolss_io_r_getprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprinterdataex: unable to marshall SPOOL_R_GETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_setprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_SETPRINTERDATAEX q_u;
+ SPOOL_R_SETPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_setprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterdataex: unable to unmarshall SPOOL_Q_SETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_setprinterdataex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_setprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_setprinterdataex: unable to marshall SPOOL_R_SETPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprinterkey(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERKEY q_u;
+ SPOOL_R_ENUMPRINTERKEY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterkey("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_setprinterkey: unable to unmarshall SPOOL_Q_ENUMPRINTERKEY.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterkey(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterkey("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterkey: unable to marshall SPOOL_R_ENUMPRINTERKEY.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL api_spoolss_enumprinterdataex(pipes_struct *p)
+{
+ SPOOL_Q_ENUMPRINTERDATAEX q_u;
+ SPOOL_R_ENUMPRINTERDATAEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_enumprinterdataex("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_enumprinterdataex: unable to unmarshall SPOOL_Q_ENUMPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_enumprinterdataex(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_enumprinterdataex("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_enumprinterdataex: unable to marshall SPOOL_R_ENUMPRINTERDATAEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+/* Disabled because it doesn't fix the bug I am looking at but it would be
+ a shame to throw away the code. -tpot */
+
+#if 0
+
+static BOOL api_spoolss_getprintprocessordirectory(pipes_struct *p)
+{
+ SPOOL_Q_GETPRINTPROCESSORDIRECTORY q_u;
+ SPOOL_R_GETPRINTPROCESSORDIRECTORY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!spoolss_io_q_getprintprocessordirectory("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_getprintprocessordirectory: unable to unmarshall SPOOL_Q_GETPRINTPROCESSORDIRECTORY.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_getprintprocessordirectory(p, &q_u, &r_u);
+
+ if(!spoolss_io_r_getprintprocessordirectory("", &r_u, rdata, 0)) {
+ DEBUG(0,("spoolss_io_r_getprintprocessordirectory: unable to marshall SPOOL_R_GETPRINTPROCESSORDIRECTORY.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+#endif
+
+/*******************************************************************
+\pipe\spoolss commands
+********************************************************************/
+
+struct api_struct api_spoolss_cmds[] =
+{
+ {"SPOOLSS_OPENPRINTEREX", SPOOLSS_OPENPRINTEREX, api_spoolss_open_printer_ex },
+ {"SPOOLSS_GETPRINTERDATA", SPOOLSS_GETPRINTERDATA, api_spoolss_getprinterdata },
+ {"SPOOLSS_CLOSEPRINTER", SPOOLSS_CLOSEPRINTER, api_spoolss_closeprinter },
+ {"SPOOLSS_DELETEPRINTER", SPOOLSS_DELETEPRINTER, api_spoolss_deleteprinter },
+ {"SPOOLSS_ABORTPRINTER", SPOOLSS_ABORTPRINTER, api_spoolss_abortprinter },
+ {"SPOOLSS_RFFPCNEX", SPOOLSS_RFFPCNEX, api_spoolss_rffpcnex },
+ {"SPOOLSS_RFNPCNEX", SPOOLSS_RFNPCNEX, api_spoolss_rfnpcnex },
+ {"SPOOLSS_ENUMPRINTERS", SPOOLSS_ENUMPRINTERS, api_spoolss_enumprinters },
+ {"SPOOLSS_GETPRINTER", SPOOLSS_GETPRINTER, api_spoolss_getprinter },
+ {"SPOOLSS_GETPRINTERDRIVER2", SPOOLSS_GETPRINTERDRIVER2, api_spoolss_getprinterdriver2 },
+ {"SPOOLSS_STARTPAGEPRINTER", SPOOLSS_STARTPAGEPRINTER, api_spoolss_startpageprinter },
+ {"SPOOLSS_ENDPAGEPRINTER", SPOOLSS_ENDPAGEPRINTER, api_spoolss_endpageprinter },
+ {"SPOOLSS_STARTDOCPRINTER", SPOOLSS_STARTDOCPRINTER, api_spoolss_startdocprinter },
+ {"SPOOLSS_ENDDOCPRINTER", SPOOLSS_ENDDOCPRINTER, api_spoolss_enddocprinter },
+ {"SPOOLSS_WRITEPRINTER", SPOOLSS_WRITEPRINTER, api_spoolss_writeprinter },
+ {"SPOOLSS_SETPRINTER", SPOOLSS_SETPRINTER, api_spoolss_setprinter },
+ {"SPOOLSS_FCPN", SPOOLSS_FCPN, api_spoolss_fcpn },
+ {"SPOOLSS_ADDJOB", SPOOLSS_ADDJOB, api_spoolss_addjob },
+ {"SPOOLSS_ENUMJOBS", SPOOLSS_ENUMJOBS, api_spoolss_enumjobs },
+ {"SPOOLSS_SCHEDULEJOB", SPOOLSS_SCHEDULEJOB, api_spoolss_schedulejob },
+ {"SPOOLSS_SETJOB", SPOOLSS_SETJOB, api_spoolss_setjob },
+ {"SPOOLSS_ENUMFORMS", SPOOLSS_ENUMFORMS, api_spoolss_enumforms },
+ {"SPOOLSS_ENUMPORTS", SPOOLSS_ENUMPORTS, api_spoolss_enumports },
+ {"SPOOLSS_ENUMPRINTERDRIVERS", SPOOLSS_ENUMPRINTERDRIVERS, api_spoolss_enumprinterdrivers },
+ {"SPOOLSS_ADDPRINTEREX", SPOOLSS_ADDPRINTEREX, api_spoolss_addprinterex },
+ {"SPOOLSS_ADDPRINTERDRIVER", SPOOLSS_ADDPRINTERDRIVER, api_spoolss_addprinterdriver },
+ {"SPOOLSS_DELETEPRINTERDRIVER", SPOOLSS_DELETEPRINTERDRIVER, api_spoolss_deleteprinterdriver },
+ {"SPOOLSS_GETPRINTERDRIVERDIRECTORY", SPOOLSS_GETPRINTERDRIVERDIRECTORY, api_spoolss_getprinterdriverdirectory },
+ {"SPOOLSS_ENUMPRINTERDATA", SPOOLSS_ENUMPRINTERDATA, api_spoolss_enumprinterdata },
+ {"SPOOLSS_SETPRINTERDATA", SPOOLSS_SETPRINTERDATA, api_spoolss_setprinterdata },
+ {"SPOOLSS_DELETEPRINTERDATA", SPOOLSS_DELETEPRINTERDATA, api_spoolss_deleteprinterdata },
+ {"SPOOLSS_ADDFORM", SPOOLSS_ADDFORM, api_spoolss_addform },
+ {"SPOOLSS_DELETEFORM", SPOOLSS_DELETEFORM, api_spoolss_deleteform },
+ {"SPOOLSS_GETFORM", SPOOLSS_GETFORM, api_spoolss_getform },
+ {"SPOOLSS_SETFORM", SPOOLSS_SETFORM, api_spoolss_setform },
+ {"SPOOLSS_ADDPRINTPROCESSOR", SPOOLSS_ADDPRINTPROCESSOR, api_spoolss_addprintprocessor },
+ {"SPOOLSS_ENUMPRINTPROCESSORS", SPOOLSS_ENUMPRINTPROCESSORS, api_spoolss_enumprintprocessors },
+ {"SPOOLSS_ENUMMONITORS", SPOOLSS_ENUMMONITORS, api_spoolss_enumprintmonitors },
+ {"SPOOLSS_GETJOB", SPOOLSS_GETJOB, api_spoolss_getjob },
+ {"SPOOLSS_ENUMPRINTPROCDATATYPES", SPOOLSS_ENUMPRINTPROCDATATYPES, api_spoolss_enumprintprocdatatypes },
+ {"SPOOLSS_GETPRINTERDATAEX", SPOOLSS_GETPRINTERDATAEX, api_spoolss_getprinterdataex },
+ {"SPOOLSS_SETPRINTERDATAEX", SPOOLSS_SETPRINTERDATAEX, api_spoolss_setprinterdataex },
+ {"SPOOLSS_ENUMPRINTERKEY", SPOOLSS_ENUMPRINTERKEY, api_spoolss_enumprinterkey },
+ {"SPOOLSS_ENUMPRINTERDATAEX", SPOOLSS_ENUMPRINTERDATAEX, api_spoolss_enumprinterdataex },
+#if 0
+ /* Disabled because it doesn't fix the bug I am looking at but it would be
+ a shame to throw away the code. -tpot */
+ {"SPOOLSS_GETPRINTPROCESSORDIRECTORY",SPOOLSS_GETPRINTPROCESSORDIRECTORY,api_spoolss_getprintprocessordirectory},
+#endif
+ { NULL, 0, NULL }
+};
+
+/*******************************************************************
+receives a spoolss pipe and responds.
+********************************************************************/
+BOOL api_spoolss_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_spoolss_rpc", api_spoolss_cmds);
+}
diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c
new file mode 100644
index 00000000000..5794f1de048
--- /dev/null
+++ b/source/rpc_server/srv_spoolss_nt.c
@@ -0,0 +1,7171 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Jean François Micouleau 1998-2000.
+ * Copyright (C) Jeremy Allison 2001.
+ * Copyright (C) Gerald Carter 2000-2001.
+ * Copyright (C) Tim Potter 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped
+ up, all the errors returned are DOS errors, not NT status codes. */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+#ifndef MAX_OPEN_PRINTER_EXS
+#define MAX_OPEN_PRINTER_EXS 50
+#endif
+
+#define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
+#define PRINTER_HANDLE_IS_PRINTER 0
+#define PRINTER_HANDLE_IS_PRINTSERVER 1
+
+struct table_node {
+ char *long_archi;
+ char *short_archi;
+ int version;
+};
+
+
+/* structure to store the printer handles */
+/* and a reference to what it's pointing to */
+/* and the notify info asked about */
+/* that's the central struct */
+typedef struct _Printer{
+ BOOL document_started;
+ BOOL page_started;
+ int jobid; /* jobid in printing backend */
+ BOOL printer_type;
+ union {
+ fstring handlename;
+ fstring printerservername;
+ } dev;
+ uint32 type;
+ uint32 access;
+ struct {
+ uint32 flags;
+ uint32 options;
+ fstring localmachine;
+ uint32 printerlocal;
+ SPOOL_NOTIFY_OPTION *option;
+ POLICY_HND client_hnd;
+ uint32 client_connected;
+ } notify;
+ struct {
+ fstring machine;
+ fstring user;
+ } client;
+} Printer_entry;
+
+typedef struct _counter_printer_0 {
+ ubi_dlNode Next;
+ ubi_dlNode Prev;
+
+ int snum;
+ uint32 counter;
+} counter_printer_0;
+
+static ubi_dlList counter_list;
+
+static struct cli_state cli;
+static uint32 smb_connections=0;
+
+#define OUR_HANDLE(hnd) ((hnd==NULL)?"NULL":(IVAL(hnd->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER"))
+
+/* translate between internal status numbers and NT status numbers */
+static int nt_printj_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return 0;
+ case LPQ_PAUSED:
+ return JOB_STATUS_PAUSED;
+ case LPQ_SPOOLING:
+ return JOB_STATUS_SPOOLING;
+ case LPQ_PRINTING:
+ return JOB_STATUS_PRINTING;
+ case LPQ_ERROR:
+ return JOB_STATUS_ERROR;
+ case LPQ_DELETING:
+ return JOB_STATUS_DELETING;
+ case LPQ_OFFLINE:
+ return JOB_STATUS_OFFLINE;
+ case LPQ_PAPEROUT:
+ return JOB_STATUS_PAPEROUT;
+ case LPQ_PRINTED:
+ return JOB_STATUS_PRINTED;
+ case LPQ_DELETED:
+ return JOB_STATUS_DELETED;
+ case LPQ_BLOCKED:
+ return JOB_STATUS_BLOCKED;
+ case LPQ_USER_INTERVENTION:
+ return JOB_STATUS_USER_INTERVENTION;
+ }
+ return 0;
+}
+
+static int nt_printq_status(int v)
+{
+ switch (v) {
+ case LPQ_PAUSED:
+ return PRINTER_STATUS_PAUSED;
+ case LPQ_QUEUED:
+ case LPQ_SPOOLING:
+ case LPQ_PRINTING:
+ return 0;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
+****************************************************************************/
+
+static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
+{
+ if (*pp == NULL)
+ return;
+
+ SAFE_FREE((*pp)->ctr.type);
+ SAFE_FREE(*pp);
+}
+
+/***************************************************************************
+ Disconnect from the client
+****************************************************************************/
+
+static void srv_spoolss_replycloseprinter(POLICY_HND *handle)
+{
+ WERROR status;
+
+ /* weird if the test succeds !!! */
+ if (smb_connections==0) {
+ DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
+ return;
+ }
+
+ if(!cli_spoolss_reply_close_printer(&cli, handle, &status))
+ DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed.\n"));
+
+ /* if it's the last connection, deconnect the IPC$ share */
+ if (smb_connections==1) {
+ if(!spoolss_disconnect_from_client(&cli))
+ return;
+
+ message_deregister(MSG_PRINTER_NOTIFY);
+ }
+
+ smb_connections--;
+}
+
+/****************************************************************************
+ Functions to free a printer entry datastruct.
+****************************************************************************/
+
+static void free_printer_entry(void *ptr)
+{
+ Printer_entry *Printer = (Printer_entry *)ptr;
+
+ if (Printer->notify.client_connected==True)
+ srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+
+ Printer->notify.flags=0;
+ Printer->notify.options=0;
+ Printer->notify.localmachine[0]='\0';
+ Printer->notify.printerlocal=0;
+ free_spool_notify_option(&Printer->notify.option);
+ Printer->notify.option=NULL;
+ Printer->notify.client_connected=False;
+
+ SAFE_FREE(Printer);
+}
+
+/****************************************************************************
+ Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
+****************************************************************************/
+
+SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
+{
+ SPOOL_NOTIFY_OPTION *new_sp = NULL;
+
+ if (!sp)
+ return NULL;
+
+ new_sp = (SPOOL_NOTIFY_OPTION *)malloc(sizeof(SPOOL_NOTIFY_OPTION));
+ if (!new_sp)
+ return NULL;
+
+ *new_sp = *sp;
+
+ if (sp->ctr.count) {
+ new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count);
+
+ if (!new_sp->ctr.type) {
+ SAFE_FREE(new_sp);
+ return NULL;
+ }
+ }
+
+ return new_sp;
+}
+
+/****************************************************************************
+ find printer index by handle
+****************************************************************************/
+
+static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *find_printer = NULL;
+
+ if(!find_policy_by_hnd(p,hnd,(void **)&find_printer)) {
+ DEBUG(3,("find_printer_index_by_hnd: Printer handle not found: "));
+ return NULL;
+ }
+
+ return find_printer;
+}
+
+/****************************************************************************
+ close printer index by handle
+****************************************************************************/
+
+static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(0,("close_printer_handle: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ close_policy_hnd(p, hnd);
+
+ return True;
+}
+
+/****************************************************************************
+ delete a printer given a handle
+****************************************************************************/
+static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(0,("delete_printer_handle: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+ return WERR_BADFID;
+ }
+
+ if (del_a_printer(Printer->dev.handlename) != 0) {
+ DEBUG(3,("Error deleting printer %s\n", Printer->dev.handlename));
+ return WERR_BADFID;
+ }
+
+ /* Check calling user has permission to delete printer. Note that
+ since we set the snum parameter to -1 only administrators can
+ delete the printer. This stops people with the Full Control
+ permission from deleting the printer. */
+
+ if (!print_access_check(NULL, -1, PRINTER_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("printer delete denied by security descriptor\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ if (*lp_deleteprinter_cmd()) {
+
+ char *cmd = lp_deleteprinter_cmd();
+ pstring command;
+ int ret;
+ int i;
+
+ /* Printer->dev.handlename equals portname equals sharename */
+ slprintf(command, sizeof(command)-1, "%s \"%s\"", cmd,
+ Printer->dev.handlename);
+
+ DEBUG(10,("Running [%s]\n", command));
+ ret = smbrun(command, NULL);
+ if (ret != 0) {
+ return WERR_BADFID; /* What to return here? */
+ }
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ /* Send SIGHUP to process group... is there a better way? */
+ kill(0, SIGHUP);
+
+ if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) >= 0 ) {
+ lp_killservice( i );
+ return WERR_OK;
+ } else
+ return WERR_ACCESS_DENIED;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ return the snum of a printer corresponding to an handle
+****************************************************************************/
+static BOOL get_printer_snum(pipes_struct *p, POLICY_HND *hnd, int *number)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(0,("get_printer_snum: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ switch (Printer->printer_type) {
+ case PRINTER_HANDLE_IS_PRINTER:
+ DEBUG(4,("short name:%s\n", Printer->dev.handlename));
+ *number = print_queue_snum(Printer->dev.handlename);
+ return (*number != -1);
+ case PRINTER_HANDLE_IS_PRINTSERVER:
+ return False;
+ default:
+ return False;
+ }
+}
+
+/****************************************************************************
+ set printer handle type.
+****************************************************************************/
+static BOOL set_printer_hnd_accesstype(pipes_struct *p, POLICY_HND *hnd, uint32 access_required)
+{
+ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
+
+ if (!Printer) {
+ DEBUG(0,("set_printer_hnd_accesstype: Invalid handle (%s)", OUR_HANDLE(hnd)));
+ return False;
+ }
+
+ DEBUG(4,("Setting printer access=%x\n", access_required));
+ Printer->access = access_required;
+ return True;
+}
+
+/****************************************************************************
+ Set printer handle type.
+ Check if it's \\server or \\server\printer
+****************************************************************************/
+
+static BOOL set_printer_hnd_printertype(Printer_entry *Printer, char *handlename)
+{
+ DEBUG(3,("Setting printer type=%s\n", handlename));
+
+ if ( strlen(handlename) < 3 ) {
+ DEBUGADD(4,("A print server must have at least 1 char ! %s\n", handlename));
+ return False;
+ }
+
+ /* it's a print server */
+ if (*handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) {
+ DEBUGADD(4,("Printer is a print server\n"));
+ Printer->printer_type = PRINTER_HANDLE_IS_PRINTSERVER;
+ }
+ /* it's a printer */
+ else {
+ DEBUGADD(4,("Printer is a printer\n"));
+ Printer->printer_type = PRINTER_HANDLE_IS_PRINTER;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set printer handle name.
+****************************************************************************/
+
+static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum;
+ int n_services=lp_numservices();
+ char *aprinter;
+ BOOL found=False;
+
+ DEBUG(4,("Setting printer name=%s (len=%d)\n", handlename, strlen(handlename)));
+
+ if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTSERVER) {
+ ZERO_STRUCT(Printer->dev.printerservername);
+ strncpy(Printer->dev.printerservername, handlename, strlen(handlename));
+ return True;
+ }
+
+ if (Printer->printer_type!=PRINTER_HANDLE_IS_PRINTER)
+ return False;
+
+ if (*handlename=='\\') {
+ aprinter=strchr_m(handlename+2, '\\');
+ aprinter++;
+ }
+ else {
+ aprinter=handlename;
+ }
+
+ DEBUGADD(5,("searching for [%s] (len=%d)\n", aprinter, strlen(aprinter)));
+
+ /*
+ * store the Samba share name in it
+ * in back we have the long printer name
+ * need to iterate all the snum and do a
+ * get_a_printer each time to find the printer
+ * faster to do it here than later.
+ */
+
+ for (snum=0;snum<n_services && found==False;snum++) {
+ char *printername;
+
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
+ continue;
+
+ DEBUGADD(5,("share:%s\n",lp_servicename(snum)));
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ continue;
+
+ printername=strchr_m(printer->info_2->printername+2, '\\');
+ printername++;
+
+ DEBUG(10,("set_printer_hnd_name: name [%s], aprinter [%s]\n",
+ printer->info_2->printername, aprinter ));
+
+ if ( strlen(printername) != strlen(aprinter) ) {
+ free_a_printer(&printer, 2);
+ continue;
+ }
+
+ if ( strncasecmp(printername, aprinter, strlen(aprinter))) {
+ free_a_printer(&printer, 2);
+ continue;
+ }
+
+ found=True;
+ }
+
+ /*
+ * if we haven't found a printer with the given handlename
+ * then it can be a share name as you can open both \\server\printer and
+ * \\server\share
+ */
+
+ /*
+ * we still check if the printer description file exists as NT won't be happy
+ * if we reply OK in the openprinter call and can't reply in the subsequent RPC calls
+ */
+
+ if (found==False) {
+ DEBUGADD(5,("Printer not found, checking for share now\n"));
+
+ for (snum=0;snum<n_services && found==False;snum++) {
+
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
+ continue;
+
+ DEBUGADD(5,("set_printer_hnd_name: share:%s\n",lp_servicename(snum)));
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ continue;
+
+ DEBUG(10,("set_printer_hnd_name: printername [%s], aprinter [%s]\n",
+ printer->info_2->printername, aprinter ));
+
+ if ( strlen(lp_servicename(snum)) != strlen(aprinter) ) {
+ free_a_printer(&printer, 2);
+ continue;
+ }
+
+ if ( strncasecmp(lp_servicename(snum), aprinter, strlen(aprinter))) {
+ free_a_printer(&printer, 2);
+ continue;
+ }
+
+ found=True;
+ }
+ }
+
+ if (found==False) {
+ DEBUGADD(4,("Printer not found\n"));
+ return False;
+ }
+
+ snum--;
+ DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s[%x]\n",
+ printer->info_2->printername, lp_servicename(snum),snum));
+
+ ZERO_STRUCT(Printer->dev.handlename);
+ strncpy(Printer->dev.handlename, lp_servicename(snum), strlen(lp_servicename(snum)));
+
+ free_a_printer(&printer, 2);
+
+ return True;
+}
+
+/****************************************************************************
+ find first available printer slot. creates a printer handle for you.
+ ****************************************************************************/
+
+static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name)
+{
+ Printer_entry *new_printer;
+
+ DEBUG(10,("open_printer_hnd: name [%s]\n", name));
+
+ if((new_printer=(Printer_entry *)malloc(sizeof(Printer_entry))) == NULL)
+ return False;
+
+ ZERO_STRUCTP(new_printer);
+
+ new_printer->notify.option=NULL;
+
+ if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
+ SAFE_FREE(new_printer);
+ return False;
+ }
+
+ if (!set_printer_hnd_printertype(new_printer, name)) {
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
+ if (!set_printer_hnd_name(new_printer, name)) {
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
+ DEBUG(5, ("%d printer handles active\n", (int)p->pipe_handles->count ));
+
+ return True;
+}
+
+/********************************************************************
+ Return True is the handle is a print server.
+ ********************************************************************/
+
+static BOOL handle_is_printserver(pipes_struct *p, POLICY_HND *handle)
+{
+ Printer_entry *Printer=find_printer_index_by_hnd(p,handle);
+
+ if (!Printer)
+ return False;
+
+ if (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER)
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+ allocate more memory for a BUFFER.
+****************************************************************************/
+static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
+{
+ prs_struct *ps;
+ uint32 extra_space;
+ uint32 old_offset;
+
+ ps= &buffer->prs;
+
+ /* damn, I'm doing the reverse operation of prs_grow() :) */
+ if (buffer_size < prs_data_size(ps))
+ extra_space=0;
+ else
+ extra_space = buffer_size - prs_data_size(ps);
+
+ /*
+ * save the offset and move to the end of the buffer
+ * prs_grow() checks the extra_space against the offset
+ */
+ old_offset=prs_offset(ps);
+ prs_set_offset(ps, prs_data_size(ps));
+
+ if (!prs_grow(ps, extra_space))
+ return False;
+
+ prs_set_offset(ps, old_offset);
+
+ buffer->string_at_end=prs_data_size(ps);
+
+ return True;
+}
+
+/***************************************************************************
+ receive the notify message
+****************************************************************************/
+
+static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ fstring printer;
+ WERROR status;
+ struct pipes_struct *p;
+ struct policy *pol;
+ struct handle_list *hl;
+
+ *printer = '\0';
+ fstrcpy(printer,buf);
+
+ if (len == 0) {
+ DEBUG(0,("srv_spoolss_receive_message: got null message !\n"));
+ return;
+ }
+
+ DEBUG(10,("srv_spoolss_receive_message: Got message about printer %s\n", printer ));
+
+ /*
+ * We need to enumerate all printers. The handle list is shared
+ * across pipes of the same name, so just find the first open
+ * spoolss pipe.
+ */
+
+ hl = NULL;
+ for ( p = get_first_pipe(); p; get_next_pipe(p)) {
+ if (strequal(p->name, "spoolss")) {
+ hl = p->pipe_handles;
+ break;
+ }
+ }
+
+ if (!hl) {
+ DEBUG(0,("srv_spoolss_receive_message: no handle list on spoolss pipe !\n"));
+ return;
+ }
+
+ /* Iterate the printer list on this pipe. */
+ for (pol = hl->Policy; pol; pol = pol->next ) {
+ Printer_entry *find_printer = (Printer_entry *)pol->data_ptr;
+
+ if (!find_printer)
+ continue;
+
+ /*
+ * if the entry is the given printer or if it's a printerserver
+ * we send the message
+ */
+
+ if (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
+ if (strcmp(find_printer->dev.handlename, printer))
+ continue;
+
+ if (find_printer->notify.client_connected==True)
+ cli_spoolss_reply_rrpcn(&cli, &find_printer->notify.client_hnd, PRINTER_CHANGE_ALL, 0x0, &status);
+ }
+}
+
+/***************************************************************************
+ send a notify event
+****************************************************************************/
+static BOOL srv_spoolss_sendnotify(pipes_struct *p, POLICY_HND *handle)
+{
+ fstring printer;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("srv_spoolss_sendnotify: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return False;
+ }
+
+ if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
+ fstrcpy(printer, Printer->dev.handlename);
+ else
+ fstrcpy(printer, "");
+
+ /*srv_spoolss_receive_message(printer);*/
+ DEBUG(10,("srv_spoolss_sendnotify: Sending message about printer %s\n", printer ));
+
+ message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer, strlen(printer) + 1, False); /* Null terminate... */
+
+ return True;
+}
+
+/********************************************************************
+ * spoolss_open_printer
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u)
+{
+#if 0
+ WERROR result = WERR_OK;
+#endif
+
+ UNISTR2 *printername = NULL;
+ PRINTER_DEFAULT *printer_default = &q_u->printer_default;
+/* uint32 user_switch = q_u->user_switch; - notused */
+/* SPOOL_USER_CTR user_ctr = q_u->user_ctr; - notused */
+ POLICY_HND *handle = &r_u->handle;
+
+ fstring name;
+ int snum;
+ struct current_user user;
+
+ if (q_u->printername_ptr != 0)
+ printername = &q_u->printername;
+
+ if (printername == NULL)
+ return WERR_INVALID_PRINTER_NAME;
+
+ /* some sanity check because you can open a printer or a print server */
+ /* aka: \\server\printer or \\server */
+ unistr2_to_ascii(name, printername, sizeof(name)-1);
+
+ DEBUGADD(3,("checking name: %s\n",name));
+
+ if (!open_printer_hnd(p, handle, name))
+ return WERR_INVALID_PRINTER_NAME;
+
+/*
+ if (printer_default->datatype_ptr != NULL)
+ {
+ unistr2_to_ascii(datatype, printer_default->datatype, sizeof(datatype)-1);
+ set_printer_hnd_datatype(handle, datatype);
+ }
+ else
+ set_printer_hnd_datatype(handle, "");
+*/
+
+ if (!set_printer_hnd_accesstype(p, handle, printer_default->access_required)) {
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /*
+ First case: the user is opening the print server:
+
+ Disallow MS AddPrinterWizard if parameter disables it. A Win2k
+ client 1st tries an OpenPrinterEx with access==0, MUST be allowed.
+
+ Then both Win2k and WinNT clients try an OpenPrinterEx with
+ SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0)
+ or if the user is listed in the smb.conf printer admin parameter.
+
+ Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the
+ client view printer folder, but does not show the MSAPW.
+
+ Note: this test needs code to check access rights here too. Jeremy
+ could you look at this?
+
+
+ Second case: the user is opening a printer:
+ NT doesn't let us connect to a printer if the connecting user
+ doesn't have print permission.
+
+ */
+
+ get_current_user(&user, p);
+
+ if (handle_is_printserver(p, handle)) {
+ if (printer_default->access_required == 0) {
+ return WERR_OK;
+ }
+ else if ((printer_default->access_required & SERVER_ACCESS_ADMINISTER ) == SERVER_ACCESS_ADMINISTER) {
+
+ /* Printserver handles use global struct... */
+ snum = -1;
+
+ if (!lp_ms_add_printer_wizard()) {
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+ else if (user.uid == 0 || user_in_list(uidtoname(user.uid), lp_printer_admin(snum))) {
+ return WERR_OK;
+ }
+ else {
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+ }
+ }
+ else
+ {
+ /* NT doesn't let us connect to a printer if the connecting user
+ doesn't have print permission. */
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ /* map an empty access mask to the minimum access mask */
+ if (printer_default->access_required == 0x0)
+ printer_default->access_required = PRINTER_ACCESS_USE;
+
+
+ /*
+ * If we are not serving the printer driver for this printer,
+ * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE. This
+ * will keep NT clients happy --jerry
+ */
+
+ if (lp_use_client_driver(snum)
+ && (printer_default->access_required & PRINTER_ACCESS_ADMINISTER))
+ {
+ printer_default->access_required = PRINTER_ACCESS_USE;
+ }
+
+ if (!print_access_check(&user, snum, printer_default->access_required)) {
+ DEBUG(3, ("access DENIED for printer open\n"));
+ close_printer_handle(p, handle);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /*
+ * If we have a default device pointer in the
+ * printer_default struct, then we need to get
+ * the printer info from the tdb and if there is
+ * no default devicemode there then we do a *SET*
+ * here ! This is insanity.... JRA.
+ */
+
+ /*
+ * If the openprinterex rpc call contains a devmode,
+ * it's a per-user one. This per-user devmode is derivated
+ * from the global devmode. Openprinterex() contains a per-user
+ * devmode for when you do EMF printing and spooling.
+ * In the EMF case, the NT workstation is only doing half the job
+ * of rendering the page. The other half is done by running the printer
+ * driver on the server.
+ * The EMF file doesn't contain the page description (paper size, orientation, ...).
+ * The EMF file only contains what is to be printed on the page.
+ * So in order for the server to know how to print, the NT client sends
+ * a devicemode attached to the openprinterex call.
+ * But this devicemode is short lived, it's only valid for the current print job.
+ *
+ * If Samba would have supported EMF spooling, this devicemode would
+ * have been attached to the handle, to sent it to the driver to correctly
+ * rasterize the EMF file.
+ *
+ * As Samba only supports RAW spooling, we only receive a ready-to-print file,
+ * we just act as a pass-thru between windows and the printer.
+ *
+ * In order to know that Samba supports only RAW spooling, NT has to call
+ * getprinter() at level 2 (attribute field) or NT has to call startdoc()
+ * and until NT sends a RAW job, we refuse it.
+ *
+ * But to call getprinter() or startdoc(), you first need a valid handle,
+ * and to get an handle you have to call openprintex(). Hence why you have
+ * a devicemode in the openprinterex() call.
+ *
+ *
+ * Differences between NT4 and NT 2000.
+ * NT4:
+ * ---
+ * On NT4, you only have a global devicemode. This global devicemode can be changed
+ * by the administrator (or by a user with enough privs). Everytime a user
+ * wants to print, the devicemode is resetted to the default. In Word, everytime
+ * you print, the printer's characteristics are always reset to the global devicemode.
+ *
+ * NT 2000:
+ * -------
+ * In W2K, there is the notion of per-user devicemode. The first time you use
+ * a printer, a per-user devicemode is build from the global devicemode.
+ * If you change your per-user devicemode, it is saved in the registry, under the
+ * H_KEY_CURRENT_KEY sub_tree. So that everytime you print, you have your default
+ * printer preferences available.
+ *
+ * To change the per-user devicemode: it's the "Printing Preferences ..." button
+ * on the General Tab of the printer properties windows.
+ *
+ * To change the global devicemode: it's the "Printing Defaults..." button
+ * on the Advanced Tab of the printer properties window.
+ *
+ * JFM.
+ */
+
+
+
+#if 0
+ if (printer_default->devmode_cont.devmode != NULL) {
+ result = printer_write_default_dev( snum, printer_default);
+ if (result != 0) {
+ close_printer_handle(p, handle);
+ return result;
+ }
+ }
+#endif
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static BOOL convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni,
+ NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+{
+ BOOL ret = True;
+
+ switch (level) {
+ case 2:
+ ret = uni_2_asc_printer_info_2(uni->info_2, &printer->info_2);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static BOOL convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni,
+ NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level)
+{
+ BOOL result = True;
+
+ switch (level) {
+ case 3:
+ printer->info_3=NULL;
+ if (!uni_2_asc_printer_driver_3(uni->info_3, &printer->info_3))
+ result = False;
+ break;
+ case 6:
+ printer->info_6=NULL;
+ if (!uni_2_asc_printer_driver_6(uni->info_6, &printer->info_6))
+ result = False;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+BOOL convert_devicemode(char *printername, const DEVICEMODE *devmode,
+ NT_DEVICEMODE **pp_nt_devmode)
+{
+ NT_DEVICEMODE *nt_devmode = *pp_nt_devmode;
+
+ /*
+ * Ensure nt_devmode is a valid pointer
+ * as we will be overwriting it.
+ */
+
+ if (nt_devmode == NULL) {
+ DEBUG(5, ("convert_devicemode: allocating a generic devmode\n"));
+ if ((nt_devmode = construct_nt_devicemode(printername)) == NULL)
+ return False;
+ }
+
+ rpcstr_pull(nt_devmode->devicename,devmode->devicename.buffer, 31, -1, 0);
+ rpcstr_pull(nt_devmode->formname,devmode->formname.buffer, 31, -1, 0);
+
+ nt_devmode->specversion=devmode->specversion;
+ nt_devmode->driverversion=devmode->driverversion;
+ nt_devmode->size=devmode->size;
+ nt_devmode->fields=devmode->fields;
+ nt_devmode->orientation=devmode->orientation;
+ nt_devmode->papersize=devmode->papersize;
+ nt_devmode->paperlength=devmode->paperlength;
+ nt_devmode->paperwidth=devmode->paperwidth;
+ nt_devmode->scale=devmode->scale;
+ nt_devmode->copies=devmode->copies;
+ nt_devmode->defaultsource=devmode->defaultsource;
+ nt_devmode->printquality=devmode->printquality;
+ nt_devmode->color=devmode->color;
+ nt_devmode->duplex=devmode->duplex;
+ nt_devmode->yresolution=devmode->yresolution;
+ nt_devmode->ttoption=devmode->ttoption;
+ nt_devmode->collate=devmode->collate;
+
+ nt_devmode->logpixels=devmode->logpixels;
+ nt_devmode->bitsperpel=devmode->bitsperpel;
+ nt_devmode->pelswidth=devmode->pelswidth;
+ nt_devmode->pelsheight=devmode->pelsheight;
+ nt_devmode->displayflags=devmode->displayflags;
+ nt_devmode->displayfrequency=devmode->displayfrequency;
+ nt_devmode->icmmethod=devmode->icmmethod;
+ nt_devmode->icmintent=devmode->icmintent;
+ nt_devmode->mediatype=devmode->mediatype;
+ nt_devmode->dithertype=devmode->dithertype;
+ nt_devmode->reserved1=devmode->reserved1;
+ nt_devmode->reserved2=devmode->reserved2;
+ nt_devmode->panningwidth=devmode->panningwidth;
+ nt_devmode->panningheight=devmode->panningheight;
+
+ /*
+ * Only change private and driverextra if the incoming devmode
+ * has a new one. JRA.
+ */
+
+ if ((devmode->driverextra != 0) && (devmode->private != NULL)) {
+ SAFE_FREE(nt_devmode->private);
+ nt_devmode->driverextra=devmode->driverextra;
+ if((nt_devmode->private=(uint8 *)malloc(nt_devmode->driverextra * sizeof(uint8))) == NULL)
+ return False;
+ memcpy(nt_devmode->private, devmode->private, nt_devmode->driverextra);
+ }
+
+ *pp_nt_devmode = nt_devmode;
+
+ return True;
+}
+
+/********************************************************************
+ * _spoolss_enddocprinter_internal.
+ ********************************************************************/
+
+static WERROR _spoolss_enddocprinter_internal(pipes_struct *p, POLICY_HND *handle)
+{
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_enddocprinter_internal: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ Printer->document_started=False;
+ print_job_end(Printer->jobid,True);
+ /* error codes unhandled so far ... */
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_closeprinter
+ ********************************************************************/
+
+WERROR _spoolss_closeprinter(pipes_struct *p, SPOOL_Q_CLOSEPRINTER *q_u, SPOOL_R_CLOSEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (Printer && Printer->document_started)
+ _spoolss_enddocprinter_internal(p, handle); /* print job was not closed */
+
+ memcpy(&r_u->handle, &q_u->handle, sizeof(r_u->handle));
+
+ if (!close_printer_handle(p, handle))
+ return WERR_BADFID;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_deleteprinter
+
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL_R_DELETEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ WERROR result;
+
+ if (Printer && Printer->document_started)
+ _spoolss_enddocprinter_internal(p, handle); /* print job was not closed */
+
+ memcpy(&r_u->handle, &q_u->handle, sizeof(r_u->handle));
+
+ result = delete_printer_handle(p, handle);
+
+ if (W_ERROR_IS_OK(result)) {
+ srv_spoolss_sendnotify(p, handle);
+ }
+
+ return result;
+}
+
+/*******************************************************************
+ * static function to lookup the version id corresponding to an
+ * long architecture string
+ ******************************************************************/
+static int get_version_id (char * arch)
+{
+ int i;
+ struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {NULL, "", -1 }
+ };
+
+ for (i=0; archi_table[i].long_archi != NULL; i++)
+ {
+ if (strcmp(arch, archi_table[i].long_archi) == 0)
+ return (archi_table[i].version);
+ }
+
+ return -1;
+}
+
+/********************************************************************
+ * _spoolss_deleteprinterdriver
+ *
+ * We currently delete the driver for the architecture only.
+ * This can leave the driver for other archtectures. However,
+ * since every printer associates a "Windows NT x86" driver name
+ * and we cannot delete that one while it is in use, **and** since
+ * it is impossible to assign a driver to a Samba printer without
+ * having the "Windows NT x86" driver installed,...
+ *
+ * ....we should not get into trouble here.
+ *
+ * --jerry
+ ********************************************************************/
+
+WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER *q_u,
+ SPOOL_R_DELETEPRINTERDRIVER *r_u)
+{
+ fstring driver;
+ fstring arch;
+ NT_PRINTER_DRIVER_INFO_LEVEL info;
+ int version;
+
+ unistr2_to_ascii(driver, &q_u->driver, sizeof(driver)-1 );
+ unistr2_to_ascii(arch, &q_u->arch, sizeof(arch)-1 );
+
+ /* check that we have a valid driver name first */
+ if ((version=get_version_id(arch)) == -1) {
+ /* this is what NT returns */
+ return WERR_INVALID_ENVIRONMENT;
+ }
+
+ ZERO_STRUCT(info);
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+
+ if (printer_driver_in_use(arch, driver))
+ {
+ return WERR_PRINTER_DRIVER_IN_USE;
+ }
+
+ return delete_printer_driver(info.info_3);
+}
+
+
+/********************************************************************
+ GetPrinterData on a printer server Handle.
+********************************************************************/
+static BOOL getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size)
+{
+ int i;
+
+ DEBUG(8,("getprinterdata_printer_server:%s\n", value));
+
+ if (!strcmp(value, "BeepEnabled")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return False;
+ SIVAL(*data, 0, 0x01);
+ *needed = 0x4;
+ return True;
+ }
+
+ if (!strcmp(value, "EventLog")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return False;
+ SIVAL(*data, 0, 0x1B);
+ *needed = 0x4;
+ return True;
+ }
+
+ if (!strcmp(value, "NetPopup")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return False;
+ SIVAL(*data, 0, 0x01);
+ *needed = 0x4;
+ return True;
+ }
+
+ if (!strcmp(value, "MajorVersion")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return False;
+ SIVAL(*data, 0, 0x02);
+ *needed = 0x4;
+ return True;
+ }
+
+ if (!strcmp(value, "DefaultSpoolDirectory")) {
+ pstring string="You are using a Samba server";
+ *type = 0x1;
+ *needed = 2*(strlen(string)+1);
+ if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
+ return False;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+
+ /* it's done by hand ready to go on the wire */
+ for (i=0; i<strlen(string); i++) {
+ (*data)[2*i]=string[i];
+ (*data)[2*i+1]='\0';
+ }
+ return True;
+ }
+
+ if (!strcmp(value, "Architecture")) {
+ pstring string="Windows NT x86";
+ *type = 0x1;
+ *needed = 2*(strlen(string)+1);
+ if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
+ return False;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+ for (i=0; i<strlen(string); i++) {
+ (*data)[2*i]=string[i];
+ (*data)[2*i+1]='\0';
+ }
+ return True;
+ }
+
+ return False;
+}
+
+/********************************************************************
+ GetPrinterData on a printer Handle.
+********************************************************************/
+static BOOL getprinterdata_printer(pipes_struct *p, TALLOC_CTX *ctx, POLICY_HND *handle,
+ fstring value, uint32 *type,
+ uint8 **data, uint32 *needed, uint32 in_size )
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ int snum=0;
+ uint8 *idata=NULL;
+ uint32 len;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("getprinterdata_printer\n"));
+
+ if (!Printer) {
+ DEBUG(0,("getprinterdata_printer: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return False;
+ }
+
+ if(!get_printer_snum(p, handle, &snum))
+ return False;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return False;
+
+ if (!get_specific_param(*printer, 2, value, &idata, type, &len)) {
+ free_a_printer(&printer, 2);
+ return False;
+ }
+
+ free_a_printer(&printer, 2);
+
+ DEBUG(5,("getprinterdata_printer:allocating %d\n", in_size));
+
+ if (in_size) {
+ if((*data = (uint8 *)talloc(ctx, in_size *sizeof(uint8) )) == NULL) {
+ return False;
+ }
+
+ memset(*data, 0, in_size *sizeof(uint8));
+ /* copy the min(in_size, len) */
+ memcpy(*data, idata, (len>in_size)?in_size:len *sizeof(uint8));
+ } else {
+ *data = NULL;
+ }
+
+ *needed = len;
+
+ DEBUG(5,("getprinterdata_printer:copy done\n"));
+
+ SAFE_FREE(idata);
+
+ return True;
+}
+
+/********************************************************************
+ * spoolss_getprinterdata
+ ********************************************************************/
+
+WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *valuename = &q_u->valuename;
+ uint32 in_size = q_u->size;
+ uint32 *type = &r_u->type;
+ uint32 *out_size = &r_u->size;
+ uint8 **data = &r_u->data;
+ uint32 *needed = &r_u->needed;
+
+ fstring value;
+ BOOL found=False;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ /*
+ * Reminder: when it's a string, the length is in BYTES
+ * even if UNICODE is negociated.
+ *
+ * JFM, 4/19/1999
+ */
+
+ *out_size=in_size;
+
+ /* in case of problem, return some default values */
+ *needed=0;
+ *type=0;
+
+ DEBUG(4,("_spoolss_getprinterdata\n"));
+
+ if (!Printer) {
+ if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+ DEBUG(0,("_spoolss_getprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ unistr2_to_ascii(value, valuename, sizeof(value)-1);
+
+ if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+ found=getprinterdata_printer_server(p->mem_ctx, value, type, data, needed, *out_size);
+ else
+ found= getprinterdata_printer(p, p->mem_ctx, handle, value, type, data, needed, *out_size);
+
+ if (found==False) {
+ DEBUG(5, ("value not found, allocating %d\n", *out_size));
+ /* reply this param doesn't exist */
+ if (*out_size) {
+ if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+ } else {
+ *data = NULL;
+ }
+
+ return WERR_INVALID_PARAM;
+ }
+
+ if (*needed > *out_size)
+ return WERR_STATUS_MORE_ENTRIES;
+ else
+ return WERR_OK;
+}
+
+/***************************************************************************
+ connect to the client
+****************************************************************************/
+static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle)
+{
+ WERROR status;
+
+ /*
+ * If it's the first connection, contact the client
+ * and connect to the IPC$ share anonumously
+ */
+ if (smb_connections==0) {
+ fstring unix_printer;
+
+ fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
+
+ if(!spoolss_connect_to_client(&cli, unix_printer))
+ return False;
+ message_register(MSG_PRINTER_NOTIFY, srv_spoolss_receive_message);
+
+ }
+
+ smb_connections++;
+
+ if(!cli_spoolss_reply_open_printer(&cli, printer, localprinter, type, &status, handle))
+ return False;
+
+ return True;
+}
+
+/********************************************************************
+ * _spoolss_rffpcnex
+ * ReplyFindFirstPrinterChangeNotifyEx
+ *
+ * jfmxxxx: before replying OK: status=0
+ * should do a rpc call to the workstation asking ReplyOpenPrinter
+ * have to code it, later.
+ *
+ * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
+ * called from api_spoolss_rffpcnex
+ ********************************************************************/
+
+WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 flags = q_u->flags;
+ uint32 options = q_u->options;
+ UNISTR2 *localmachine = &q_u->localmachine;
+ uint32 printerlocal = q_u->printerlocal;
+ SPOOL_NOTIFY_OPTION *option = q_u->option;
+
+ /* store the notify value in the printer struct */
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_rffpcnex: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ Printer->notify.flags=flags;
+ Printer->notify.options=options;
+ Printer->notify.printerlocal=printerlocal;
+
+ if (Printer->notify.option)
+ free_spool_notify_option(&Printer->notify.option);
+
+ Printer->notify.option=dup_spool_notify_option(option);
+
+ unistr2_to_ascii(Printer->notify.localmachine, localmachine, sizeof(Printer->notify.localmachine)-1);
+
+ /* connect to the client machine and send a ReplyOpenPrinter */
+ if(srv_spoolss_replyopenprinter(Printer->notify.localmachine,
+ Printer->notify.printerlocal, 1,
+ &Printer->notify.client_hnd))
+ Printer->notify.client_connected=True;
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the servername
+ ********************************************************************/
+
+static void spoolss_notify_server_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp_name, temp;
+ uint32 len;
+
+ slprintf(temp_name, sizeof(temp_name)-1, "\\\\%s", global_myname);
+
+ len = rpcstr_push(temp, temp_name, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the printername (not including the servername).
+ ********************************************************************/
+static void spoolss_notify_printer_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ /* the notify name should not contain the \\server\ part */
+ char *p = strrchr_m(printer->info_2->printername, '\\');
+
+ if (!p) {
+ p = printer->info_2->printername;
+ } else {
+ p++;
+ }
+
+ len = rpcstr_push(temp, p, sizeof(temp)-2, STR_TERMINATE);
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the servicename
+ ********************************************************************/
+static void spoolss_notify_share_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, lp_servicename(snum), sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the port name
+ ********************************************************************/
+static void spoolss_notify_port_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ /* even if it's strange, that's consistant in all the code */
+
+ len = rpcstr_push(temp, printer->info_2->portname, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the printername
+ * jfmxxxx: it's incorrect, should be lp_printerdrivername()
+ * but it doesn't exist, have to see what to do
+ ********************************************************************/
+static void spoolss_notify_driver_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->drivername, sizeof(temp)-2, STR_TERMINATE);
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the comment
+ ********************************************************************/
+static void spoolss_notify_comment(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ if (*printer->info_2->comment == '\0')
+ len = rpcstr_push(temp, lp_comment(snum), sizeof(temp)-2, STR_TERMINATE);
+
+ else
+ len = rpcstr_push(temp, printer->info_2->comment, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the comment
+ * jfm:xxxx incorrect, have to create a new smb.conf option
+ * location = "Room 1, floor 2, building 3"
+ ********************************************************************/
+static void spoolss_notify_location(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->location,sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the device mode
+ * jfm:xxxx don't to it for know but that's a real problem !!!
+ ********************************************************************/
+static void spoolss_notify_devmode(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the separator file name
+ * jfm:xxxx just return no file could add an option to smb.conf
+ * separator file = "separator.txt"
+ ********************************************************************/
+static void spoolss_notify_sepfile(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->sepfile, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the print processor
+ * jfm:xxxx return always winprint to indicate we don't do anything to it
+ ********************************************************************/
+static void spoolss_notify_print_processor(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->printprocessor, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the print processor options
+ * jfm:xxxx send an empty string
+ ********************************************************************/
+static void spoolss_notify_parameters(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->parameters, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the data type
+ * jfm:xxxx always send RAW as data type
+ ********************************************************************/
+static void spoolss_notify_datatype(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, printer->info_2->datatype, sizeof(pstring)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the security descriptor
+ * jfm:xxxx send an null pointer to say no security desc
+ * have to implement security before !
+ ********************************************************************/
+static void spoolss_notify_security_desc(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.data.length=0;
+ data->notify_data.data.string = NULL;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the attributes
+ * jfm:xxxx a samba printer is always shared
+ ********************************************************************/
+static void spoolss_notify_attributes(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->attributes;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the priority
+ ********************************************************************/
+static void spoolss_notify_priority(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->priority;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the default priority
+ ********************************************************************/
+static void spoolss_notify_default_priority(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->default_priority;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the start time
+ ********************************************************************/
+static void spoolss_notify_start_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->starttime;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the until time
+ ********************************************************************/
+static void spoolss_notify_until_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = printer->info_2->untiltime;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the status
+ ********************************************************************/
+static void spoolss_notify_status(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ print_status_struct status;
+
+ print_queue_length(snum, &status);
+ data->notify_data.value[0]=(uint32) status.status;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the number of jobs queued
+ ********************************************************************/
+static void spoolss_notify_cjobs(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0] = print_queue_length(snum, NULL);
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with the average ppm
+ ********************************************************************/
+static void spoolss_notify_average_ppm(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ /* always respond 8 pages per minutes */
+ /* a little hard ! */
+ data->notify_data.value[0] = printer->info_2->averageppm;
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with username
+ ********************************************************************/
+static void spoolss_notify_username(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, queue->user, sizeof(temp)-2, STR_TERMINATE);
+
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job status
+ ********************************************************************/
+static void spoolss_notify_job_status(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=nt_printj_status(queue->status);
+ data->notify_data.value[1] = 0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job name
+ ********************************************************************/
+static void spoolss_notify_job_name(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ pstring temp;
+ uint32 len;
+
+ len = rpcstr_push(temp, queue->file, sizeof(temp)-2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job status
+ ********************************************************************/
+static void spoolss_notify_job_status_string(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ /*
+ * Now we're returning job status codes we just return a "" here. JRA.
+ */
+
+ char *p = "";
+ pstring temp;
+ uint32 len;
+
+#if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */
+ p = "unknown";
+
+ switch (queue->status) {
+ case LPQ_QUEUED:
+ p = "Queued";
+ break;
+ case LPQ_PAUSED:
+ p = ""; /* NT provides the paused string */
+ break;
+ case LPQ_SPOOLING:
+ p = "Spooling";
+ break;
+ case LPQ_PRINTING:
+ p = "Printing";
+ break;
+ }
+#endif /* NO LONGER NEEDED. */
+
+ len = rpcstr_push(temp, p, sizeof(temp) - 2, STR_TERMINATE);
+
+ data->notify_data.data.length = len / 2;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ memcpy(data->notify_data.data.string, temp, len);
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job time
+ ********************************************************************/
+static void spoolss_notify_job_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=0x0;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job size
+ ********************************************************************/
+static void spoolss_notify_job_size(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=queue->size;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with job position
+ ********************************************************************/
+static void spoolss_notify_job_position(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ data->notify_data.value[0]=queue->job;
+ data->notify_data.value[1]=0;
+}
+
+/*******************************************************************
+ * fill a notify_info_data with submitted time
+ ********************************************************************/
+static void spoolss_notify_submitted_time(int snum,
+ SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tm *t;
+ uint32 len;
+ SYSTEMTIME st;
+
+ t=gmtime(&queue->time);
+
+ len = sizeof(SYSTEMTIME);
+
+ data->notify_data.data.length = len;
+ data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
+
+ if (!data->notify_data.data.string) {
+ data->notify_data.data.length = 0;
+ return;
+ }
+
+ make_systemtime(&st, t);
+ memcpy(data->notify_data.data.string,&st,len);
+}
+
+#define END 65535
+
+struct s_notify_info_data_table
+{
+ uint16 type;
+ uint16 field;
+ char *name;
+ uint32 size;
+ void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
+ print_queue_struct *queue,
+ NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
+};
+
+struct s_notify_info_data_table notify_info_data_table[] =
+{
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME, "PRINTER_NOTIFY_SERVER_NAME", POINTER, spoolss_notify_server_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME, "PRINTER_NOTIFY_PRINTER_NAME", POINTER, spoolss_notify_printer_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME, "PRINTER_NOTIFY_SHARE_NAME", POINTER, spoolss_notify_share_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME, "PRINTER_NOTIFY_PORT_NAME", POINTER, spoolss_notify_port_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME, "PRINTER_NOTIFY_DRIVER_NAME", POINTER, spoolss_notify_driver_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT, "PRINTER_NOTIFY_COMMENT", POINTER, spoolss_notify_comment },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION, "PRINTER_NOTIFY_LOCATION", POINTER, spoolss_notify_location },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE, "PRINTER_NOTIFY_DEVMODE", POINTER, spoolss_notify_devmode },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE, "PRINTER_NOTIFY_SEPFILE", POINTER, spoolss_notify_sepfile },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR, "PRINTER_NOTIFY_PRINT_PROCESSOR", POINTER, spoolss_notify_print_processor },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS, "PRINTER_NOTIFY_PARAMETERS", POINTER, spoolss_notify_parameters },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE, "PRINTER_NOTIFY_DATATYPE", POINTER, spoolss_notify_datatype },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", POINTER, spoolss_notify_security_desc },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES, "PRINTER_NOTIFY_ATTRIBUTES", ONE_VALUE, spoolss_notify_attributes },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY, "PRINTER_NOTIFY_PRIORITY", ONE_VALUE, spoolss_notify_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEFAULT_PRIORITY, "PRINTER_NOTIFY_DEFAULT_PRIORITY", ONE_VALUE, spoolss_notify_default_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_START_TIME, "PRINTER_NOTIFY_START_TIME", ONE_VALUE, spoolss_notify_start_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_UNTIL_TIME, "PRINTER_NOTIFY_UNTIL_TIME", ONE_VALUE, spoolss_notify_until_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS, "PRINTER_NOTIFY_STATUS", ONE_VALUE, spoolss_notify_status },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS_STRING, "PRINTER_NOTIFY_STATUS_STRING", POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_CJOBS, "PRINTER_NOTIFY_CJOBS", ONE_VALUE, spoolss_notify_cjobs },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_AVERAGE_PPM, "PRINTER_NOTIFY_AVERAGE_PPM", ONE_VALUE, spoolss_notify_average_ppm },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_PAGES, "PRINTER_NOTIFY_TOTAL_PAGES", POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED, "PRINTER_NOTIFY_PAGES_PRINTED", POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES, "PRINTER_NOTIFY_TOTAL_BYTES", POINTER, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED, "PRINTER_NOTIFY_BYTES_PRINTED", POINTER, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRINTER_NAME, "JOB_NOTIFY_PRINTER_NAME", POINTER, spoolss_notify_printer_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_MACHINE_NAME, "JOB_NOTIFY_MACHINE_NAME", POINTER, spoolss_notify_server_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PORT_NAME, "JOB_NOTIFY_PORT_NAME", POINTER, spoolss_notify_port_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME, "JOB_NOTIFY_USER_NAME", POINTER, spoolss_notify_username },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_NOTIFY_NAME, "JOB_NOTIFY_NOTIFY_NAME", POINTER, spoolss_notify_username },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DATATYPE, "JOB_NOTIFY_DATATYPE", POINTER, spoolss_notify_datatype },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRINT_PROCESSOR, "JOB_NOTIFY_PRINT_PROCESSOR", POINTER, spoolss_notify_print_processor },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PARAMETERS, "JOB_NOTIFY_PARAMETERS", POINTER, spoolss_notify_parameters },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DRIVER_NAME, "JOB_NOTIFY_DRIVER_NAME", POINTER, spoolss_notify_driver_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DEVMODE, "JOB_NOTIFY_DEVMODE", POINTER, spoolss_notify_devmode },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_STATUS, "JOB_NOTIFY_STATUS", ONE_VALUE, spoolss_notify_job_status },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_STATUS_STRING, "JOB_NOTIFY_STATUS_STRING", POINTER, spoolss_notify_job_status_string },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_SECURITY_DESCRIPTOR, "JOB_NOTIFY_SECURITY_DESCRIPTOR", POINTER, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT, "JOB_NOTIFY_DOCUMENT", POINTER, spoolss_notify_job_name },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PRIORITY, "JOB_NOTIFY_PRIORITY", ONE_VALUE, spoolss_notify_priority },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_POSITION, "JOB_NOTIFY_POSITION", ONE_VALUE, spoolss_notify_job_position },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED, "JOB_NOTIFY_SUBMITTED", POINTER, spoolss_notify_submitted_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_START_TIME, "JOB_NOTIFY_START_TIME", ONE_VALUE, spoolss_notify_start_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_UNTIL_TIME, "JOB_NOTIFY_UNTIL_TIME", ONE_VALUE, spoolss_notify_until_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TIME, "JOB_NOTIFY_TIME", ONE_VALUE, spoolss_notify_job_time },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TOTAL_PAGES, "JOB_NOTIFY_TOTAL_PAGES", ONE_VALUE, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_PAGES_PRINTED, "JOB_NOTIFY_PAGES_PRINTED", ONE_VALUE, NULL },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_TOTAL_BYTES, "JOB_NOTIFY_TOTAL_BYTES", ONE_VALUE, spoolss_notify_job_size },
+{ JOB_NOTIFY_TYPE, JOB_NOTIFY_BYTES_PRINTED, "JOB_NOTIFY_BYTES_PRINTED", ONE_VALUE, NULL },
+{ END, END, "", END, NULL }
+};
+
+/*******************************************************************
+return the size of info_data structure
+********************************************************************/
+static uint32 size_of_notify_info_data(uint16 type, uint16 field)
+{
+ int i=0;
+
+ while (notify_info_data_table[i].type != END)
+ {
+ if ( (notify_info_data_table[i].type == type ) &&
+ (notify_info_data_table[i].field == field ) )
+ {
+ return (notify_info_data_table[i].size);
+ }
+ i++;
+ }
+ return (65535);
+}
+
+/*******************************************************************
+return the type of notify_info_data
+********************************************************************/
+static BOOL type_of_notify_info_data(uint16 type, uint16 field)
+{
+ int i=0;
+
+ while (notify_info_data_table[i].type != END)
+ {
+ if ( (notify_info_data_table[i].type == type ) &&
+ (notify_info_data_table[i].field == field ) )
+ {
+ if (notify_info_data_table[i].size == POINTER)
+ {
+ return (False);
+ }
+ else
+ {
+ return (True);
+ }
+ }
+ i++;
+ }
+ return (False);
+}
+
+/****************************************************************************
+****************************************************************************/
+static int search_notify(uint16 type, uint16 field, int *value)
+{
+ int j;
+ BOOL found;
+
+ for (j=0, found=False; found==False && notify_info_data_table[j].type != END ; j++)
+ {
+ if ( (notify_info_data_table[j].type == type ) &&
+ (notify_info_data_table[j].field == field ) )
+ found=True;
+ }
+ *value=--j;
+
+ if ( found && (notify_info_data_table[j].fn != NULL) )
+ return True;
+ else
+ return False;
+}
+
+/****************************************************************************
+****************************************************************************/
+static void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id)
+{
+ info_data->type = type;
+ info_data->field = field;
+ info_data->reserved = 0;
+ info_data->id = id;
+ info_data->size = size_of_notify_info_data(type, field);
+ info_data->enc_type = type_of_notify_info_data(type, field);
+}
+
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
+ snum, SPOOL_NOTIFY_OPTION_TYPE
+ *option_type, uint32 id,
+ TALLOC_CTX *mem_ctx)
+{
+ int field_num,j;
+ uint16 type;
+ uint16 field;
+
+ SPOOL_NOTIFY_INFO_DATA *current_data, *tid;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ print_queue_struct *queue=NULL;
+
+ type=option_type->type;
+
+ DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
+ (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+ option_type->count, lp_servicename(snum)));
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return False;
+
+ for(field_num=0; field_num<option_type->count; field_num++) {
+ field = option_type->fields[field_num];
+ DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
+
+ if (!search_notify(type, field, &j) )
+ continue;
+
+ if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
+ DEBUG(0,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
+ return False;
+ }
+ else info->data = tid;
+
+ current_data=&info->data[info->count];
+
+ construct_info_data(current_data, type, field, id);
+
+ DEBUG(10,("construct_notify_printer_info: calling [%s] snum=%d printername=[%s])\n",
+ notify_info_data_table[j].name, snum, printer->info_2->printername ));
+
+ notify_info_data_table[j].fn(snum, current_data, queue,
+ printer, mem_ctx);
+
+ info->count++;
+ }
+
+ free_a_printer(&printer, 2);
+ return True;
+}
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+static BOOL construct_notify_jobs_info(print_queue_struct *queue,
+ SPOOL_NOTIFY_INFO *info,
+ NT_PRINTER_INFO_LEVEL *printer,
+ int snum, SPOOL_NOTIFY_OPTION_TYPE
+ *option_type, uint32 id,
+ TALLOC_CTX *mem_ctx)
+{
+ int field_num,j;
+ uint16 type;
+ uint16 field;
+
+ SPOOL_NOTIFY_INFO_DATA *current_data, *tid;
+
+ DEBUG(4,("construct_notify_jobs_info\n"));
+
+ type = option_type->type;
+
+ DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
+ (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+ option_type->count));
+
+ for(field_num=0; field_num<option_type->count; field_num++) {
+ field = option_type->fields[field_num];
+
+ if (!search_notify(type, field, &j) )
+ continue;
+
+ if((tid=Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
+ DEBUG(0,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
+ return False;
+ }
+ else info->data = tid;
+
+ current_data=&(info->data[info->count]);
+
+ construct_info_data(current_data, type, field, id);
+ notify_info_data_table[j].fn(snum, current_data, queue,
+ printer, mem_ctx);
+ info->count++;
+ }
+
+ return True;
+}
+
+/*
+ * JFM: The enumeration is not that simple, it's even non obvious.
+ *
+ * let's take an example: I want to monitor the PRINTER SERVER for
+ * the printer's name and the number of jobs currently queued.
+ * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure.
+ * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS.
+ *
+ * I have 3 printers on the back of my server.
+ *
+ * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA
+ * structures.
+ * Number Data Id
+ * 1 printer 1 name 1
+ * 2 printer 1 cjob 1
+ * 3 printer 2 name 2
+ * 4 printer 2 cjob 2
+ * 5 printer 3 name 3
+ * 6 printer 3 name 3
+ *
+ * that's the print server case, the printer case is even worse.
+ */
+
+/*******************************************************************
+ *
+ * enumerate all printers on the printserver
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+
+static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
+ SPOOL_NOTIFY_INFO *info,
+ TALLOC_CTX *mem_ctx)
+{
+ int snum;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
+ int n_services=lp_numservices();
+ int i;
+ uint32 id;
+ SPOOL_NOTIFY_OPTION *option;
+ SPOOL_NOTIFY_OPTION_TYPE *option_type;
+
+ DEBUG(4,("printserver_notify_info\n"));
+
+ option=Printer->notify.option;
+ id=1;
+ info->version=2;
+ info->data=NULL;
+ info->count=0;
+
+ for (i=0; i<option->count; i++) {
+ option_type=&(option->ctr.type[i]);
+
+ if (option_type->type!=PRINTER_NOTIFY_TYPE)
+ continue;
+
+ for (snum=0; snum<n_services; snum++)
+ if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
+ if (construct_notify_printer_info
+ (info, snum, option_type, id, mem_ctx))
+ id++;
+ }
+
+ /*
+ * Debugging information, don't delete.
+ */
+ /*
+ DEBUG(1,("dumping the NOTIFY_INFO\n"));
+ DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+ DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+
+ for (i=0; i<info->count; i++) {
+ DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+ i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+ info->data[i].id, info->data[i].size, info->data[i].enc_type));
+ }
+ */
+
+ return WERR_OK;
+}
+
+/*******************************************************************
+ *
+ * fill a notify_info struct with info asked
+ *
+ ********************************************************************/
+static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info,
+ TALLOC_CTX *mem_ctx)
+{
+ int snum;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
+ int i;
+ uint32 id;
+ SPOOL_NOTIFY_OPTION *option;
+ SPOOL_NOTIFY_OPTION_TYPE *option_type;
+ int count,j;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+
+ DEBUG(4,("printer_notify_info\n"));
+
+ option=Printer->notify.option;
+ id=0xffffffff;
+ info->version=2;
+ info->data=NULL;
+ info->count=0;
+
+ get_printer_snum(p, hnd, &snum);
+
+ for (i=0; i<option->count; i++) {
+ option_type=&option->ctr.type[i];
+
+ switch ( option_type->type ) {
+ case PRINTER_NOTIFY_TYPE:
+ if(construct_notify_printer_info(info, snum,
+ option_type, id,
+ mem_ctx))
+ id--;
+ break;
+
+ case JOB_NOTIFY_TYPE: {
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ count = print_queue_status(snum, &queue, &status);
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2,
+ lp_servicename(snum))))
+ goto done;
+
+ for (j=0; j<count; j++) {
+ construct_notify_jobs_info(&queue[j], info,
+ printer, snum,
+ option_type,
+ queue[j].job,
+ mem_ctx);
+ }
+
+ free_a_printer(&printer, 2);
+
+ done:
+ SAFE_FREE(queue);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Debugging information, don't delete.
+ */
+ /*
+ DEBUG(1,("dumping the NOTIFY_INFO\n"));
+ DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+ DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+
+ for (i=0; i<info->count; i++) {
+ DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+ i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+ info->data[i].id, info->data[i].size, info->data[i].enc_type));
+ }
+ */
+ return WERR_OK;
+}
+
+/********************************************************************
+ * spoolss_rfnpcnex
+ ********************************************************************/
+
+WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+/* uint32 change = q_u->change; - notused. */
+/* SPOOL_NOTIFY_OPTION *option = q_u->option; - notused. */
+ SPOOL_NOTIFY_INFO *info = &r_u->info;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+ WERROR result = WERR_BADFID;
+
+ /* we always have a NOTIFY_INFO struct */
+ r_u->info_ptr=0x1;
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_rfnpcnex: Invalid handle (%s).\n",
+ OUR_HANDLE(handle)));
+ goto done;
+ }
+
+ DEBUG(4,("Printer type %x\n",Printer->printer_type));
+
+ /* jfm: the change value isn't used right now.
+ * we will honour it when
+ * a) we'll be able to send notification to the client
+ * b) we'll have a way to communicate between the spoolss process.
+ *
+ * same thing for option->flags
+ * I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as
+ * I don't have a global notification system, I'm sending back all the
+ * informations even when _NOTHING_ has changed.
+ */
+
+ /* just ignore the SPOOL_NOTIFY_OPTION */
+
+ switch (Printer->printer_type) {
+ case PRINTER_HANDLE_IS_PRINTSERVER:
+ result = printserver_notify_info(p, handle, info, p->mem_ctx);
+ break;
+
+ case PRINTER_HANDLE_IS_PRINTER:
+ result = printer_notify_info(p, handle, info, p->mem_ctx);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+/********************************************************************
+ * construct_printer_info_0
+ * fill a printer_info_0 struct
+ ********************************************************************/
+static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
+{
+ pstring chaine;
+ int count;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ counter_printer_0 *session_counter;
+ uint32 global_counter;
+ struct tm *t;
+ time_t setuptime;
+ print_status_struct status;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ return False;
+
+ count = print_queue_length(snum, &status);
+
+ /* check if we already have a counter for this printer */
+ session_counter = (counter_printer_0 *)ubi_dlFirst(&counter_list);
+
+ for(; session_counter; session_counter = (counter_printer_0 *)ubi_dlNext(session_counter)) {
+ if (session_counter->snum == snum)
+ break;
+ }
+
+ /* it's the first time, add it to the list */
+ if (session_counter==NULL) {
+ if((session_counter=(counter_printer_0 *)malloc(sizeof(counter_printer_0))) == NULL) {
+ free_a_printer(&ntprinter, 2);
+ return False;
+ }
+ ZERO_STRUCTP(session_counter);
+ session_counter->snum=snum;
+ session_counter->counter=0;
+ ubi_dlAddHead( &counter_list, (ubi_dlNode *)session_counter);
+ }
+
+ /* increment it */
+ session_counter->counter++;
+
+ /* JFM:
+ * the global_counter should be stored in a TDB as it's common to all the clients
+ * and should be zeroed on samba startup
+ */
+ global_counter=session_counter->counter;
+
+ pstrcpy(chaine,ntprinter->info_2->printername);
+
+ init_unistr(&printer->printername, chaine);
+
+ slprintf(chaine,sizeof(chaine)-1,"\\\\%s", global_myname);
+ init_unistr(&printer->servername, chaine);
+
+ printer->cjobs = count;
+ printer->total_jobs = 0;
+ printer->total_bytes = 0;
+
+ setuptime = (time_t)ntprinter->info_2->setuptime;
+ t=gmtime(&setuptime);
+
+ printer->year = t->tm_year+1900;
+ printer->month = t->tm_mon+1;
+ printer->dayofweek = t->tm_wday;
+ printer->day = t->tm_mday;
+ printer->hour = t->tm_hour;
+ printer->minute = t->tm_min;
+ printer->second = t->tm_sec;
+ printer->milliseconds = 0;
+
+ printer->global_counter = global_counter;
+ printer->total_pages = 0;
+ printer->major_version = 0x0004; /* NT 4 */
+ printer->build_version = 0x0565; /* build 1381 */
+ printer->unknown7 = 0x1;
+ printer->unknown8 = 0x0;
+ printer->unknown9 = 0x0;
+ printer->session_counter = session_counter->counter;
+ printer->unknown11 = 0x0;
+ printer->printer_errors = 0x0; /* number of print failure */
+ printer->unknown13 = 0x0;
+ printer->unknown14 = 0x1;
+ printer->unknown15 = 0x024a; /* 586 Pentium ? */
+ printer->unknown16 = 0x0;
+ printer->change_id = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
+ printer->unknown18 = 0x0;
+ printer->status = nt_printq_status(status.status);
+ printer->unknown20 = 0x0;
+ printer->c_setprinter = ntprinter->info_2->c_setprinter; /* how many times setprinter has been called */
+ printer->unknown22 = 0x0;
+ printer->unknown23 = 0x6; /* 6 ???*/
+ printer->unknown24 = 0; /* unknown 24 to 26 are always 0 */
+ printer->unknown25 = 0;
+ printer->unknown26 = 0;
+ printer->unknown27 = 0;
+ printer->unknown28 = 0;
+ printer->unknown29 = 0;
+
+ free_a_printer(&ntprinter,2);
+ return (True);
+}
+
+/********************************************************************
+ * construct_printer_info_1
+ * fill a printer_info_1 struct
+ ********************************************************************/
+static BOOL construct_printer_info_1(uint32 flags, PRINTER_INFO_1 *printer, int snum)
+{
+ pstring chaine;
+ pstring chaine2;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ return False;
+
+ printer->flags=flags;
+
+ if (*ntprinter->info_2->comment == '\0') {
+ init_unistr(&printer->comment, lp_comment(snum));
+ slprintf(chaine,sizeof(chaine)-1,"%s%s,%s,%s",global_myname, ntprinter->info_2->printername,
+ ntprinter->info_2->drivername, lp_comment(snum));
+ }
+ else {
+ init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
+ slprintf(chaine,sizeof(chaine)-1,"%s%s,%s,%s",global_myname, ntprinter->info_2->printername,
+ ntprinter->info_2->drivername, ntprinter->info_2->comment);
+ }
+
+ slprintf(chaine2,sizeof(chaine)-1,"%s", ntprinter->info_2->printername);
+
+ init_unistr(&printer->description, chaine);
+ init_unistr(&printer->name, chaine2);
+
+ free_a_printer(&ntprinter,2);
+
+ return True;
+}
+
+/****************************************************************************
+ Free a DEVMODE struct.
+****************************************************************************/
+
+static void free_dev_mode(DEVICEMODE *dev)
+{
+ if (dev == NULL)
+ return;
+
+ SAFE_FREE(dev->private);
+ SAFE_FREE(dev);
+}
+
+/****************************************************************************
+ Create a DEVMODE struct. Returns malloced memory.
+****************************************************************************/
+
+static DEVICEMODE *construct_dev_mode(int snum)
+{
+ char adevice[32];
+ char aform[32];
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_DEVICEMODE *ntdevmode = NULL;
+ DEVICEMODE *devmode = NULL;
+
+ DEBUG(7,("construct_dev_mode\n"));
+
+ DEBUGADD(8,("getting printer characteristics\n"));
+
+ if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
+ DEBUG(0,("construct_dev_mode: malloc fail.\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(devmode);
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ goto fail;
+
+ if (printer->info_2->devmode)
+ ntdevmode = dup_nt_devicemode(printer->info_2->devmode);
+
+ if (ntdevmode == NULL)
+ goto fail;
+
+ DEBUGADD(8,("loading DEVICEMODE\n"));
+
+ slprintf(adevice, sizeof(adevice)-1, printer->info_2->printername);
+ init_unistr(&devmode->devicename, adevice);
+
+ slprintf(aform, sizeof(aform)-1, ntdevmode->formname);
+ init_unistr(&devmode->formname, aform);
+
+ devmode->specversion = ntdevmode->specversion;
+ devmode->driverversion = ntdevmode->driverversion;
+ devmode->size = ntdevmode->size;
+ devmode->driverextra = ntdevmode->driverextra;
+ devmode->fields = ntdevmode->fields;
+
+ devmode->orientation = ntdevmode->orientation;
+ devmode->papersize = ntdevmode->papersize;
+ devmode->paperlength = ntdevmode->paperlength;
+ devmode->paperwidth = ntdevmode->paperwidth;
+ devmode->scale = ntdevmode->scale;
+ devmode->copies = ntdevmode->copies;
+ devmode->defaultsource = ntdevmode->defaultsource;
+ devmode->printquality = ntdevmode->printquality;
+ devmode->color = ntdevmode->color;
+ devmode->duplex = ntdevmode->duplex;
+ devmode->yresolution = ntdevmode->yresolution;
+ devmode->ttoption = ntdevmode->ttoption;
+ devmode->collate = ntdevmode->collate;
+ devmode->icmmethod = ntdevmode->icmmethod;
+ devmode->icmintent = ntdevmode->icmintent;
+ devmode->mediatype = ntdevmode->mediatype;
+ devmode->dithertype = ntdevmode->dithertype;
+
+ if (ntdevmode->private != NULL) {
+ if ((devmode->private=(uint8 *)memdup(ntdevmode->private, ntdevmode->driverextra)) == NULL)
+ goto fail;
+ }
+
+ free_nt_devicemode(&ntdevmode);
+ free_a_printer(&printer,2);
+
+ return devmode;
+
+ fail:
+
+ if (ntdevmode)
+ free_nt_devicemode(&ntdevmode);
+ if (printer)
+ free_a_printer(&printer,2);
+ free_dev_mode(devmode);
+
+ return NULL;
+}
+
+/********************************************************************
+ * construct_printer_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+
+static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum)
+{
+ int count;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+
+ print_status_struct status;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ return False;
+
+ count = print_queue_length(snum, &status);
+
+ init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
+ init_unistr(&printer->printername, ntprinter->info_2->printername); /* printername*/
+ init_unistr(&printer->sharename, lp_servicename(snum)); /* sharename */
+ init_unistr(&printer->portname, ntprinter->info_2->portname); /* port */
+ init_unistr(&printer->drivername, ntprinter->info_2->drivername); /* drivername */
+
+ if (*ntprinter->info_2->comment == '\0')
+ init_unistr(&printer->comment, lp_comment(snum)); /* comment */
+ else
+ init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
+
+ init_unistr(&printer->location, ntprinter->info_2->location); /* location */
+ init_unistr(&printer->sepfile, ntprinter->info_2->sepfile); /* separator file */
+ init_unistr(&printer->printprocessor, ntprinter->info_2->printprocessor);/* print processor */
+ init_unistr(&printer->datatype, ntprinter->info_2->datatype); /* datatype */
+ init_unistr(&printer->parameters, ntprinter->info_2->parameters); /* parameters (of print processor) */
+
+ printer->attributes = ntprinter->info_2->attributes;
+
+ printer->priority = ntprinter->info_2->priority; /* priority */
+ printer->defaultpriority = ntprinter->info_2->default_priority; /* default priority */
+ printer->starttime = ntprinter->info_2->starttime; /* starttime */
+ printer->untiltime = ntprinter->info_2->untiltime; /* untiltime */
+ printer->status = nt_printq_status(status.status); /* status */
+ printer->cjobs = count; /* jobs */
+ printer->averageppm = ntprinter->info_2->averageppm; /* average pages per minute */
+
+ if((printer->devmode = construct_dev_mode(snum)) == NULL) {
+ DEBUG(8, ("Returning NULL Devicemode!\n"));
+ }
+
+ if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->len != 0) {
+ /* steal the printer info sec_desc structure. [badly done]. */
+ printer->secdesc = ntprinter->info_2->secdesc_buf->sec;
+ ntprinter->info_2->secdesc_buf->sec = NULL; /* Stolen memory. */
+ ntprinter->info_2->secdesc_buf->len = 0; /* Stolen memory. */
+ ntprinter->info_2->secdesc_buf->max_len = 0; /* Stolen memory. */
+ }
+ else {
+ printer->secdesc = NULL;
+ }
+
+ free_a_printer(&ntprinter, 2);
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+static BOOL construct_printer_info_3(PRINTER_INFO_3 **pp_printer, int snum)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ PRINTER_INFO_3 *printer = NULL;
+
+ if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ return False;
+
+ *pp_printer = NULL;
+ if ((printer = (PRINTER_INFO_3 *)malloc(sizeof(PRINTER_INFO_3))) == NULL) {
+ DEBUG(0,("construct_printer_info_3: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(printer);
+
+ printer->flags = 4; /* These are the components of the SD we are returning. */
+ if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->len != 0) {
+ /* steal the printer info sec_desc structure. [badly done]. */
+ printer->secdesc = ntprinter->info_2->secdesc_buf->sec;
+
+#if 0
+ /*
+ * Set the flags for the components we are returning.
+ */
+
+ if (printer->secdesc->owner_sid)
+ printer->flags |= OWNER_SECURITY_INFORMATION;
+
+ if (printer->secdesc->grp_sid)
+ printer->flags |= GROUP_SECURITY_INFORMATION;
+
+ if (printer->secdesc->dacl)
+ printer->flags |= DACL_SECURITY_INFORMATION;
+
+ if (printer->secdesc->sacl)
+ printer->flags |= SACL_SECURITY_INFORMATION;
+#endif
+
+ ntprinter->info_2->secdesc_buf->sec = NULL; /* Stolen the malloced memory. */
+ ntprinter->info_2->secdesc_buf->len = 0; /* Stolen the malloced memory. */
+ ntprinter->info_2->secdesc_buf->max_len = 0; /* Stolen the malloced memory. */
+ }
+
+ free_a_printer(&ntprinter, 2);
+
+ *pp_printer = printer;
+ return True;
+}
+
+/********************************************************************
+ Spoolss_enumprinters.
+********************************************************************/
+static WERROR enum_all_printers_info_1(uint32 flags, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int snum;
+ int i;
+ int n_services=lp_numservices();
+ PRINTER_INFO_1 *tp, *printers=NULL;
+ PRINTER_INFO_1 current_prt;
+
+ DEBUG(4,("enum_all_printers_info_1\n"));
+
+ for (snum=0; snum<n_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+ DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+
+ if (construct_printer_info_1(flags, &current_prt, snum)) {
+ if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_1))) == NULL) {
+ DEBUG(0,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
+ SAFE_FREE(printers);
+ *returned=0;
+ return WERR_NOMEM;
+ }
+ else printers = tp;
+ DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));
+ memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
+ (*returned)++;
+ }
+ }
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_printer_info_1(&printers[i]);
+
+ if (!alloc_buffer_size(buffer, *needed))
+ return WERR_INSUFFICIENT_BUFFER;
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_printer_info_1("", buffer, &printers[i], 0);
+
+ /* clear memory */
+ SAFE_FREE(printers);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ else
+ return WERR_OK;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_local.
+*********************************************************************/
+static WERROR enum_all_printers_info_1_local(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ DEBUG(4,("enum_all_printers_info_1_local\n"));
+
+ return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+}
+
+/********************************************************************
+ enum_all_printers_info_1_name.
+*********************************************************************/
+static WERROR enum_all_printers_info_1_name(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ char *s = name;
+
+ DEBUG(4,("enum_all_printers_info_1_name\n"));
+
+ if ((name[0] == '\\') && (name[1] == '\\'))
+ s = name + 2;
+
+ if (is_myname_or_ipaddr(s)) {
+ return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+ }
+ else
+ return WERR_INVALID_NAME;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_remote.
+*********************************************************************/
+static WERROR enum_all_printers_info_1_remote(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTER_INFO_1 *printer;
+ fstring printername;
+ fstring desc;
+ fstring comment;
+ DEBUG(4,("enum_all_printers_info_1_remote\n"));
+
+ /* JFM: currently it's more a place holder than anything else.
+ * In the spooler world there is a notion of server registration.
+ * the print servers are registring (sp ?) on the PDC (in the same domain)
+ *
+ * We should have a TDB here. The registration is done thru an undocumented RPC call.
+ */
+
+ if((printer=(PRINTER_INFO_1 *)malloc(sizeof(PRINTER_INFO_1))) == NULL)
+ return WERR_NOMEM;
+
+ *returned=1;
+
+ slprintf(printername, sizeof(printername)-1,"Windows NT Remote Printers!!\\\\%s", global_myname);
+ slprintf(desc, sizeof(desc)-1,"%s", global_myname);
+ slprintf(comment, sizeof(comment)-1, "Logged on Domain");
+
+ init_unistr(&printer->description, desc);
+ init_unistr(&printer->name, printername);
+ init_unistr(&printer->comment, comment);
+ printer->flags=PRINTER_ENUM_ICON3|PRINTER_ENUM_CONTAINER;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_1(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_1("", buffer, printer, 0);
+
+ /* clear memory */
+ SAFE_FREE(printer);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ else
+ return WERR_OK;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_network.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_network(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ DEBUG(4,("enum_all_printers_info_1_network\n"));
+
+ return enum_all_printers_info_1(PRINTER_ENUM_UNKNOWN_8, buffer, offered, needed, returned);
+}
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ *
+ * called from api_spoolss_enumprinters (see this to understand)
+ ********************************************************************/
+
+static WERROR enum_all_printers_info_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int snum;
+ int i;
+ int n_services=lp_numservices();
+ PRINTER_INFO_2 *tp, *printers=NULL;
+ PRINTER_INFO_2 current_prt;
+
+ for (snum=0; snum<n_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+ DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+
+ if (construct_printer_info_2(&current_prt, snum)) {
+ if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_2))) == NULL) {
+ DEBUG(0,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
+ SAFE_FREE(printers);
+ *returned = 0;
+ return WERR_NOMEM;
+ }
+ else printers = tp;
+ DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned));
+ memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_2));
+ (*returned)++;
+ }
+ }
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_printer_info_2(&printers[i]);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ for (i=0; i<*returned; i++) {
+ free_devmode(printers[i].devmode);
+ }
+ SAFE_FREE(printers);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_printer_info_2("", buffer, &(printers[i]), 0);
+
+ /* clear memory */
+ for (i=0; i<*returned; i++) {
+ free_devmode(printers[i].devmode);
+ }
+ SAFE_FREE(printers);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ else
+ return WERR_OK;
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 1
+ ********************************************************************/
+static WERROR enumprinters_level1( uint32 flags, fstring name,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ /* Not all the flags are equals */
+
+ if (flags & PRINTER_ENUM_LOCAL)
+ return enum_all_printers_info_1_local(buffer, offered, needed, returned);
+
+ if (flags & PRINTER_ENUM_NAME)
+ return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
+
+ if (flags & PRINTER_ENUM_REMOTE)
+ return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
+
+ if (flags & PRINTER_ENUM_NETWORK)
+ return enum_all_printers_info_1_network(buffer, offered, needed, returned);
+
+ return WERR_OK; /* NT4sp5 does that */
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 2
+ ********************************************************************/
+static WERROR enumprinters_level2( uint32 flags, fstring servername,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ char *s = servername;
+
+ if (flags & PRINTER_ENUM_LOCAL) {
+ return enum_all_printers_info_2(buffer, offered, needed, returned);
+ }
+
+ if (flags & PRINTER_ENUM_NAME) {
+ if ((servername[0] == '\\') && (servername[1] == '\\'))
+ s = servername + 2;
+ if (is_myname_or_ipaddr(s))
+ return enum_all_printers_info_2(buffer, offered, needed, returned);
+ else
+ return WERR_INVALID_NAME;
+ }
+
+ if (flags & PRINTER_ENUM_REMOTE)
+ return WERR_UNKNOWN_LEVEL;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * handle enumeration of printers at level 5
+ ********************************************************************/
+static WERROR enumprinters_level5( uint32 flags, fstring servername,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+/* return enum_all_printers_info_5(buffer, offered, needed, returned);*/
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_enumprinters
+ *
+ * called from api_spoolss_enumprinters (see this to understand)
+ ********************************************************************/
+
+WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u)
+{
+ uint32 flags = q_u->flags;
+ UNISTR2 *servername = &q_u->servername;
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ fstring name;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumprinters\n"));
+
+ *needed=0;
+ *returned=0;
+
+ /*
+ * Level 1:
+ * flags==PRINTER_ENUM_NAME
+ * if name=="" then enumerates all printers
+ * if name!="" then enumerate the printer
+ * flags==PRINTER_ENUM_REMOTE
+ * name is NULL, enumerate printers
+ * Level 2: name!="" enumerates printers, name can't be NULL
+ * Level 3: doesn't exist
+ * Level 4: does a local registry lookup
+ * Level 5: same as Level 2
+ */
+
+ unistr2_to_ascii(name, servername, sizeof(name)-1);
+ strupper(name);
+
+ switch (level) {
+ case 1:
+ return enumprinters_level1(flags, name, buffer, offered, needed, returned);
+ case 2:
+ return enumprinters_level2(flags, name, buffer, offered, needed, returned);
+ case 5:
+ return enumprinters_level5(flags, name, buffer, offered, needed, returned);
+ case 3:
+ case 4:
+ break;
+ }
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinter_level_0(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_0 *printer=NULL;
+
+ if((printer=(PRINTER_INFO_0*)malloc(sizeof(PRINTER_INFO_0))) == NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_0(printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_0(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_0("", buffer, printer, 0);
+
+ /* clear memory */
+ SAFE_FREE(printer);
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinter_level_1(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_1 *printer=NULL;
+
+ if((printer=(PRINTER_INFO_1*)malloc(sizeof(PRINTER_INFO_1))) == NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_1(PRINTER_ENUM_ICON8, printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_1(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_1("", buffer, printer, 0);
+
+ /* clear memory */
+ SAFE_FREE(printer);
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinter_level_2(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_2 *printer=NULL;
+
+ if((printer=(PRINTER_INFO_2*)malloc(sizeof(PRINTER_INFO_2)))==NULL)
+ return WERR_NOMEM;
+
+ construct_printer_info_2(printer, snum);
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_2(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ free_printer_info_2(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ if (!smb_io_printer_info_2("", buffer, printer, 0)) {
+ free_printer_info_2(printer);
+ return WERR_NOMEM;
+ }
+
+ /* clear memory */
+ free_printer_info_2(printer);
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinter_level_3(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_3 *printer=NULL;
+
+ if (!construct_printer_info_3(&printer, snum))
+ return WERR_NOMEM;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_3(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ free_printer_info_3(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_3("", buffer, printer, 0);
+
+ /* clear memory */
+ free_printer_info_3(printer);
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ int snum;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ *needed=0;
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ switch (level) {
+ case 0:
+ return getprinter_level_0(snum, buffer, offered, needed);
+ case 1:
+ return getprinter_level_1(snum, buffer, offered, needed);
+ case 2:
+ return getprinter_level_2(snum, buffer, offered, needed);
+ case 3:
+ return getprinter_level_3(snum, buffer, offered, needed);
+ }
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/********************************************************************
+ * fill a DRIVER_INFO_1 struct
+ ********************************************************************/
+static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, fstring servername, fstring architecture)
+{
+ init_unistr( &info->name, driver.info_3->name);
+}
+
+/********************************************************************
+ * construct_printer_driver_info_1
+ ********************************************************************/
+static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, fstring servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+
+ ZERO_STRUCT(driver);
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return WERR_INVALID_PRINTER_NAME;
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+
+ fill_printer_driver_info_1(info, driver, servername, architecture);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, fstring servername)
+{
+ pstring temp;
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+
+ if (strlen(driver.info_3->driverpath)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else
+ init_unistr( &info->driverpath, "" );
+
+ if (strlen(driver.info_3->datafile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ if (strlen(driver.info_3->configfile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, fstring servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+
+ ZERO_STRUCT(printer);
+ ZERO_STRUCT(driver);
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return WERR_INVALID_PRINTER_NAME;
+
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+
+ fill_printer_driver_info_2(info, driver, servername);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * copy a strings array and convert to UNICODE
+ *
+ * convert an array of ascii string to a UNICODE string
+ ********************************************************************/
+static void init_unistr_array(uint16 **uni_array, fstring *char_array, char *servername)
+{
+ int i=0;
+ int j=0;
+ char *v;
+ pstring line;
+ uint16 *tuary;
+
+ DEBUG(6,("init_unistr_array\n"));
+ *uni_array=NULL;
+
+ while (1) {
+ if (char_array == NULL)
+ v = "";
+ else {
+ v = char_array[i];
+ if (!v) v = ""; /* hack to handle null lists */
+ }
+ if (strlen(v) == 0) break;
+ slprintf(line, sizeof(line)-1, "\\\\%s%s", servername, v);
+ DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line)));
+ if((tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL) {
+ DEBUG(0,("init_unistr_array: Realloc error\n" ));
+ return;
+ }
+ else *uni_array = tuary;
+ j += (rpcstr_push((*uni_array+j), line, sizeof(uint16)*strlen(line)+2, 0)/ sizeof(uint16));
+ i++;
+ }
+
+ if (*uni_array) {
+ (*uni_array)[j]=0x0000;
+ }
+
+ DEBUGADD(6,("last one:done\n"));
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, fstring servername)
+{
+ pstring temp;
+
+ ZERO_STRUCTP(info);
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+ if (strlen(driver.info_3->driverpath)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else
+ init_unistr( &info->driverpath, "" );
+
+ if (strlen(driver.info_3->datafile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ if (strlen(driver.info_3->configfile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+
+ if (strlen(driver.info_3->helpfile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->helpfile);
+ init_unistr( &info->helpfile, temp );
+ } else
+ init_unistr( &info->helpfile, "" );
+
+ init_unistr( &info->monitorname, driver.info_3->monitorname );
+ init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
+
+ info->dependentfiles=NULL;
+ init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, servername);
+}
+
+/********************************************************************
+ * construct_printer_info_3
+ * fill a printer_info_3 struct
+ ********************************************************************/
+static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, fstring servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR status;
+ ZERO_STRUCT(driver);
+
+ status=get_a_printer(&printer, 2, lp_servicename(snum) );
+ DEBUG(8,("construct_printer_driver_info_3: status: %s\n", werror_str(status)));
+ if (!W_ERROR_IS_OK(status))
+ return WERR_INVALID_PRINTER_NAME;
+
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_3: status: %s\n", werror_str(status)));
+ if (!W_ERROR_IS_OK(status)) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ fill_printer_driver_info_3(info, driver, servername);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct - we know that driver is really level 3. This sucks. JRA.
+ ********************************************************************/
+
+static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, fstring servername)
+{
+ pstring temp;
+ fstring nullstr;
+
+ ZERO_STRUCTP(info);
+ memset(&nullstr, '\0', sizeof(fstring));
+
+ info->version=driver.info_3->cversion;
+
+ init_unistr( &info->name, driver.info_3->name );
+ init_unistr( &info->architecture, driver.info_3->environment );
+
+ if (strlen(driver.info_3->driverpath)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->driverpath);
+ init_unistr( &info->driverpath, temp );
+ } else
+ init_unistr( &info->driverpath, "" );
+
+ if (strlen(driver.info_3->datafile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->datafile);
+ init_unistr( &info->datafile, temp );
+ } else
+ init_unistr( &info->datafile, "" );
+
+ if (strlen(driver.info_3->configfile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->configfile);
+ init_unistr( &info->configfile, temp );
+ } else
+ init_unistr( &info->configfile, "" );
+
+ if (strlen(driver.info_3->helpfile)) {
+ slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->helpfile);
+ init_unistr( &info->helpfile, temp );
+ } else
+ init_unistr( &info->helpfile, "" );
+
+ init_unistr( &info->monitorname, driver.info_3->monitorname );
+ init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
+
+ info->dependentfiles=NULL;
+ init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, servername);
+
+ info->previousdrivernames=NULL;
+ init_unistr_array(&info->previousdrivernames, &nullstr, servername);
+
+ info->driver_date.low=0;
+ info->driver_date.high=0;
+
+ info->padding=0;
+ info->driver_version_low=0;
+ info->driver_version_high=0;
+
+ init_unistr( &info->mfgname, "");
+ init_unistr( &info->oem_url, "");
+ init_unistr( &info->hardware_id, "");
+ init_unistr( &info->provider, "");
+}
+
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct
+ ********************************************************************/
+static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum, fstring servername, fstring architecture, uint32 version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR status;
+ ZERO_STRUCT(driver);
+
+ status=get_a_printer(&printer, 2, lp_servicename(snum) );
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", werror_str(status)));
+ if (!W_ERROR_IS_OK(status))
+ return WERR_INVALID_PRINTER_NAME;
+
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", werror_str(status)));
+ if (!W_ERROR_IS_OK(status)) {
+ /*
+ * Is this a W2k client ?
+ */
+
+ if (version < 3) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* Yes - try again with a WinNT driver. */
+ version = 2;
+ status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n", werror_str(status)));
+ if (!W_ERROR_IS_OK(status)) {
+ free_a_printer(&printer,2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+ }
+
+ fill_printer_driver_info_6(info, driver, servername);
+
+ free_a_printer(&printer,2);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void free_printer_driver_info_3(DRIVER_INFO_3 *info)
+{
+ SAFE_FREE(info->dependentfiles);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void free_printer_driver_info_6(DRIVER_INFO_6 *info)
+{
+ SAFE_FREE(info->dependentfiles);
+
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinterdriver2_level1(fstring servername, fstring architecture, uint32 version, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_1 *info=NULL;
+ WERROR status;
+
+ if((info=(DRIVER_INFO_1 *)malloc(sizeof(DRIVER_INFO_1))) == NULL)
+ return WERR_NOMEM;
+
+ status=construct_printer_driver_info_1(info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(info);
+ return status;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_1(info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_1("", buffer, info, 0);
+
+ /* clear memory */
+ SAFE_FREE(info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinterdriver2_level2(fstring servername, fstring architecture, uint32 version, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_2 *info=NULL;
+ WERROR status;
+
+ if((info=(DRIVER_INFO_2 *)malloc(sizeof(DRIVER_INFO_2))) == NULL)
+ return WERR_NOMEM;
+
+ status=construct_printer_driver_info_2(info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(info);
+ return status;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_2(info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_2("", buffer, info, 0);
+
+ /* clear memory */
+ SAFE_FREE(info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinterdriver2_level3(fstring servername, fstring architecture, uint32 version, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_3 info;
+ WERROR status;
+
+ ZERO_STRUCT(info);
+
+ status=construct_printer_driver_info_3(&info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ return status;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_3(&info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ free_printer_driver_info_3(&info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_3("", buffer, &info, 0);
+
+ free_printer_driver_info_3(&info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinterdriver2_level6(fstring servername, fstring architecture, uint32 version, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ DRIVER_INFO_6 info;
+ WERROR status;
+
+ ZERO_STRUCT(info);
+
+ status=construct_printer_driver_info_6(&info, snum, servername, architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ return status;
+ }
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_driver_info_6(&info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ free_printer_driver_info_6(&info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_driver_info_6("", buffer, &info, 0);
+
+ free_printer_driver_info_6(&info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *uni_arch = &q_u->architecture;
+ uint32 level = q_u->level;
+ uint32 clientmajorversion = q_u->clientmajorversion;
+/* uint32 clientminorversion = q_u->clientminorversion; - notused. */
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *servermajorversion = &r_u->servermajorversion;
+ uint32 *serverminorversion = &r_u->serverminorversion;
+
+ fstring servername;
+ fstring architecture;
+ int snum;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_getprinterdriver2\n"));
+
+ *needed=0;
+ *servermajorversion=0;
+ *serverminorversion=0;
+
+ pstrcpy(servername, global_myname);
+ unistr2_to_ascii(architecture, uni_arch, sizeof(architecture)-1);
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ switch (level) {
+ case 1:
+ return getprinterdriver2_level1(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 2:
+ return getprinterdriver2_level2(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 3:
+ return getprinterdriver2_level3(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ case 6:
+ return getprinterdriver2_level6(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_startpageprinter(pipes_struct *p, SPOOL_Q_STARTPAGEPRINTER *q_u, SPOOL_R_STARTPAGEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (Printer) {
+ Printer->page_started=True;
+ return WERR_OK;
+ }
+
+ DEBUG(3,("Error in startpageprinter printer handle\n"));
+ return WERR_BADFID;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_endpageprinter(pipes_struct *p, SPOOL_Q_ENDPAGEPRINTER *q_u, SPOOL_R_ENDPAGEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_endpageprinter: Invalid handle (%s).\n",OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ Printer->page_started=False;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, SPOOL_R_STARTDOCPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+/* uint32 level = q_u->doc_info_container.level; - notused. */
+ DOC_INFO *docinfo = &q_u->doc_info_container.docinfo;
+ uint32 *jobid = &r_u->jobid;
+
+ DOC_INFO_1 *info_1 = &docinfo->doc_info_1;
+ int snum;
+ pstring jobname;
+ fstring datatype;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ struct current_user user;
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_startdocprinter: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ get_current_user(&user, p);
+
+ /*
+ * a nice thing with NT is it doesn't listen to what you tell it.
+ * when asked to send _only_ RAW datas, it tries to send datas
+ * in EMF format.
+ *
+ * So I add checks like in NT Server ...
+ *
+ * lkclXXXX jean-francois, i love this kind of thing. oh, well,
+ * there's a bug in NT client-side code, so we'll fix it in the
+ * server-side code. *nnnnnggggh!*
+ */
+
+ if (info_1->p_datatype != 0) {
+ unistr2_to_ascii(datatype, &info_1->datatype, sizeof(datatype));
+ if (strcmp(datatype, "RAW") != 0) {
+ (*jobid)=0;
+ return WERR_INVALID_DATATYPE;
+ }
+ }
+
+ /* get the share number of the printer */
+ if (!get_printer_snum(p, handle, &snum)) {
+ return WERR_BADFID;
+ }
+
+ unistr2_to_ascii(jobname, &info_1->docname, sizeof(jobname));
+
+ Printer->jobid = print_job_start(&user, snum, jobname);
+
+ /* An error occured in print_job_start() so return an appropriate
+ NT error code. */
+
+ if (Printer->jobid == -1) {
+ return map_werror_from_unix(errno);
+ }
+
+ Printer->document_started=True;
+ (*jobid) = Printer->jobid;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+
+WERROR _spoolss_enddocprinter(pipes_struct *p, SPOOL_Q_ENDDOCPRINTER *q_u, SPOOL_R_ENDDOCPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ return _spoolss_enddocprinter_internal(p, handle);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R_WRITEPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 buffer_size = q_u->buffer_size;
+ uint8 *buffer = q_u->buffer;
+ uint32 *buffer_written = &q_u->buffer_size2;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_writeprinter: Invalid handle (%s)\n",OUR_HANDLE(handle)));
+ r_u->buffer_written = q_u->buffer_size2;
+ return WERR_BADFID;
+ }
+
+ (*buffer_written) = print_job_write(Printer->jobid, (char *)buffer, buffer_size);
+
+
+ r_u->buffer_written = q_u->buffer_size2;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * api_spoolss_getprinter
+ * called from the spoolss dispatcher
+ *
+ ********************************************************************/
+static WERROR control_printer(POLICY_HND *handle, uint32 command,
+ pipes_struct *p)
+{
+ struct current_user user;
+ int snum;
+ WERROR errcode = WERR_BADFUNC;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ get_current_user(&user, p);
+
+ if (!Printer) {
+ DEBUG(0,("control_printer: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ switch (command) {
+ case PRINTER_CONTROL_PAUSE:
+ if (print_queue_pause(&user, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case PRINTER_CONTROL_RESUME:
+ case PRINTER_CONTROL_UNPAUSE:
+ if (print_queue_resume(&user, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case PRINTER_CONTROL_PURGE:
+ if (print_queue_purge(&user, snum, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return errcode;
+}
+
+/********************************************************************
+ * api_spoolss_abortprinter
+ ********************************************************************/
+
+WERROR _spoolss_abortprinter(pipes_struct *p, SPOOL_Q_ABORTPRINTER *q_u, SPOOL_R_ABORTPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ return control_printer(handle, PRINTER_CONTROL_PURGE, p);
+}
+
+/********************************************************************
+ * called by spoolss_api_setprinter
+ * when updating a printer description
+ ********************************************************************/
+static WERROR update_printer_sec(POLICY_HND *handle, uint32 level,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ pipes_struct *p, SEC_DESC_BUF *secdesc_ctr)
+{
+ SEC_DESC_BUF *new_secdesc_ctr = NULL, *old_secdesc_ctr = NULL;
+ struct current_user user;
+ WERROR result;
+ int snum;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer || !get_printer_snum(p, handle, &snum)) {
+ DEBUG(0,("update_printer_sec: Invalid handle (%s)\n",
+ OUR_HANDLE(handle)));
+
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ /* NT seems to like setting the security descriptor even though
+ nothing may have actually changed. This causes annoying
+ dialog boxes when the user doesn't have permission to change
+ the security descriptor. */
+
+ nt_printing_getsec(p->mem_ctx, Printer->dev.handlename, &old_secdesc_ctr);
+
+ if (DEBUGLEVEL >= 10) {
+ SEC_ACL *the_acl;
+ int i;
+
+ the_acl = old_secdesc_ctr->sec->dacl;
+ DEBUG(10, ("old_secdesc_ctr for %s has %d aces:\n",
+ PRINTERNAME(snum), the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &the_acl->ace[i].trustee);
+
+ DEBUG(10, ("%s 0x%08x\n", sid_str,
+ the_acl->ace[i].info.mask));
+ }
+
+ the_acl = secdesc_ctr->sec->dacl;
+
+ if (the_acl) {
+ DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
+ PRINTERNAME(snum), the_acl->num_aces));
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &the_acl->ace[i].trustee);
+
+ DEBUG(10, ("%s 0x%08x\n", sid_str,
+ the_acl->ace[i].info.mask));
+ }
+ } else {
+ DEBUG(10, ("dacl for secdesc_ctr is NULL\n"));
+ }
+ }
+
+ new_secdesc_ctr = sec_desc_merge(p->mem_ctx, secdesc_ctr, old_secdesc_ctr);
+
+ if (sec_desc_equal(new_secdesc_ctr->sec, old_secdesc_ctr->sec)) {
+ result = WERR_OK;
+ goto done;
+ }
+
+ /* Work out which user is performing the operation */
+
+ get_current_user(&user, p);
+
+ /* Check the user has permissions to change the security
+ descriptor. By experimentation with two NT machines, the user
+ requires Full Access to the printer to change security
+ information. */
+
+ if (!print_access_check(&user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ result = nt_printing_setsec(Printer->dev.handlename, new_secdesc_ctr);
+
+ done:
+
+ return result;
+}
+
+/********************************************************************
+ Do Samba sanity checks on a printer info struct.
+ this has changed purpose: it now "canonicalises" printer
+ info from a client rather than just checking it is correct
+ ********************************************************************/
+
+static BOOL check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
+{
+ DEBUG(5,("check_printer_ok: servername=%s printername=%s sharename=%s portname=%s drivername=%s comment=%s location=%s\n",
+ info->servername, info->printername, info->sharename, info->portname, info->drivername, info->comment, info->location));
+
+ /* we force some elements to "correct" values */
+ slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", global_myname);
+ slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
+ global_myname, lp_servicename(snum));
+ fstrcpy(info->sharename, lp_servicename(snum));
+ info->attributes = PRINTER_ATTRIBUTE_SHARED \
+ | PRINTER_ATTRIBUTE_LOCAL \
+ | PRINTER_ATTRIBUTE_RAW_ONLY \
+ | PRINTER_ATTRIBUTE_QUEUED ;
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
+{
+ char *cmd = lp_addprinter_cmd();
+ char **qlines;
+ pstring command;
+ pstring driverlocation;
+ int numlines;
+ int ret;
+ int fd;
+
+ /* build driver path... only 9X architecture is needed for legacy reasons */
+ slprintf(driverlocation, sizeof(driverlocation)-1, "\\\\%s\\print$\\WIN40\\0",
+ global_myname);
+ /* change \ to \\ for the shell */
+ all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
+
+ slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
+ cmd, printer->info_2->printername, printer->info_2->sharename,
+ printer->info_2->portname, printer->info_2->drivername,
+ printer->info_2->location, driverlocation);
+
+ DEBUG(10,("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10,("returned [%d]\n", ret));
+
+ if ( ret != 0 ) {
+ if (fd != -1)
+ close(fd);
+ return False;
+ }
+
+ numlines = 0;
+ /* Get lines and convert them back to dos-codepage */
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ if(numlines) {
+ /* Set the portname to what the script says the portname should be. */
+ strncpy(printer->info_2->portname, qlines[0], sizeof(printer->info_2->portname));
+ DEBUGADD(6,("Line[0] = [%s]\n", qlines[0]));
+
+ /* Send SIGHUP to process group... is there a better way? */
+ kill(0, SIGHUP);
+ add_all_printers();
+ }
+
+ file_lines_free(qlines);
+ return True;
+}
+
+/* Return true if two devicemodes are equal */
+
+#define DEVMODE_CHECK_INT(field) \
+ if (d1->field != d2->field) { \
+ DEBUG(10, ("nt_devicemode_equal(): " #field " not equal (%d != %d)\n", \
+ d1->field, d2->field)); \
+ return False; \
+ }
+
+static BOOL nt_devicemode_equal(NT_DEVICEMODE *d1, NT_DEVICEMODE *d2)
+{
+ if (!d1 && !d2) goto equal; /* if both are NULL they are equal */
+
+ if (!d1 ^ !d2) {
+ DEBUG(10, ("nt_devicemode_equal(): pointers not equal\n"));
+ return False; /* if either is exclusively NULL are not equal */
+ }
+
+ if (!strequal(d1->devicename, d2->devicename)) {
+ DEBUG(10, ("nt_devicemode_equal(): device not equal (%s != %s)\n", d1->devicename, d2->devicename));
+ return False;
+ }
+
+ if (!strequal(d1->formname, d2->formname)) {
+ DEBUG(10, ("nt_devicemode_equal(): formname not equal (%s != %s)\n", d1->formname, d2->formname));
+ return False;
+ }
+
+ DEVMODE_CHECK_INT(specversion);
+ DEVMODE_CHECK_INT(driverversion);
+ DEVMODE_CHECK_INT(driverextra);
+ DEVMODE_CHECK_INT(orientation);
+ DEVMODE_CHECK_INT(papersize);
+ DEVMODE_CHECK_INT(paperlength);
+ DEVMODE_CHECK_INT(paperwidth);
+ DEVMODE_CHECK_INT(scale);
+ DEVMODE_CHECK_INT(copies);
+ DEVMODE_CHECK_INT(defaultsource);
+ DEVMODE_CHECK_INT(printquality);
+ DEVMODE_CHECK_INT(color);
+ DEVMODE_CHECK_INT(duplex);
+ DEVMODE_CHECK_INT(yresolution);
+ DEVMODE_CHECK_INT(ttoption);
+ DEVMODE_CHECK_INT(collate);
+ DEVMODE_CHECK_INT(logpixels);
+
+ DEVMODE_CHECK_INT(fields);
+ DEVMODE_CHECK_INT(bitsperpel);
+ DEVMODE_CHECK_INT(pelswidth);
+ DEVMODE_CHECK_INT(pelsheight);
+ DEVMODE_CHECK_INT(displayflags);
+ DEVMODE_CHECK_INT(displayfrequency);
+ DEVMODE_CHECK_INT(icmmethod);
+ DEVMODE_CHECK_INT(icmintent);
+ DEVMODE_CHECK_INT(mediatype);
+ DEVMODE_CHECK_INT(dithertype);
+ DEVMODE_CHECK_INT(reserved1);
+ DEVMODE_CHECK_INT(reserved2);
+ DEVMODE_CHECK_INT(panningwidth);
+ DEVMODE_CHECK_INT(panningheight);
+
+ /* compare the private data if it exists */
+ if (!d1->driverextra && !d2->driverextra) goto equal;
+
+
+ DEVMODE_CHECK_INT(driverextra);
+
+ if (memcmp(d1->private, d2->private, d1->driverextra)) {
+ DEBUG(10, ("nt_devicemode_equal(): private data not equal\n"));
+ return False;
+ }
+
+ equal:
+ DEBUG(10, ("nt_devicemode_equal(): devicemodes identical\n"));
+ return True;
+}
+
+/* Return true if two NT_PRINTER_PARAM structures are equal */
+
+static BOOL nt_printer_param_equal(NT_PRINTER_PARAM *p1,
+ NT_PRINTER_PARAM *p2)
+{
+ if (!p1 && !p2) goto equal;
+
+ if ((!p1 && p2) || (p1 && !p2)) {
+ DEBUG(10, ("nt_printer_param_equal(): pointers differ\n"));
+ return False;
+ }
+
+ /* Compare lists of printer parameters */
+
+ while (p1) {
+ BOOL found = False;
+ NT_PRINTER_PARAM *q = p1;
+
+ /* Find the parameter in the second structure */
+
+ while(q) {
+
+ if (strequal(p1->value, q->value)) {
+
+ if (p1->type != q->type) {
+ DEBUG(10, ("nt_printer_param_equal():"
+ "types for %s differ (%d != %d)\n",
+ p1->value, p1->type,
+ q->type));
+ break;
+ }
+
+ if (p1->data_len != q->data_len) {
+ DEBUG(10, ("nt_printer_param_equal():"
+ "len for %s differs (%d != %d)\n",
+ p1->value, p1->data_len,
+ q->data_len));
+ break;
+ }
+
+ if (memcmp(p1->data, q->data, p1->data_len) == 0) {
+ found = True;
+ } else {
+ DEBUG(10, ("nt_printer_param_equal():"
+ "data for %s differs\n", p1->value));
+ }
+
+ break;
+ }
+
+ q = q->next;
+ }
+
+ if (!found) {
+ DEBUG(10, ("nt_printer_param_equal(): param %s "
+ "does not exist\n", p1->value));
+ return False;
+ }
+
+ p1 = p1->next;
+ }
+
+ equal:
+
+ DEBUG(10, ("nt_printer_param_equal(): printer params identical\n"));
+ return True;
+}
+
+/********************************************************************
+ * Called by update_printer when trying to work out whether to
+ * actually update printer info.
+ ********************************************************************/
+
+#define PI_CHECK_INT(field) \
+ if (pi1->field != pi2->field) { \
+ DEBUG(10, ("nt_printer_info_level_equal(): " #field " not equal (%d != %d)\n", \
+ pi1->field, pi2->field)); \
+ return False; \
+ }
+
+#define PI_CHECK_STR(field) \
+ if (!strequal(pi1->field, pi2->field)) { \
+ DEBUG(10, ("nt_printer_info_level_equal(): " #field " not equal (%s != %s)\n", \
+ pi1->field, pi2->field)); \
+ return False; \
+ }
+
+static BOOL nt_printer_info_level_equal(NT_PRINTER_INFO_LEVEL *p1,
+ NT_PRINTER_INFO_LEVEL *p2)
+{
+ NT_PRINTER_INFO_LEVEL_2 *pi1, *pi2;
+
+ /* Trivial conditions */
+
+ if ((!p1 && !p2) || (!p1->info_2 && !p2->info_2)) {
+ goto equal;
+ }
+
+ if ((!p1 && p2) || (p1 && !p2) ||
+ (!p1->info_2 && p2->info_2) ||
+ (p1->info_2 && !p2->info_2)) {
+ DEBUG(10, ("nt_printer_info_level_equal(): info levels "
+ "differ\n"));
+ return False;
+ }
+
+ /* Compare two nt_printer_info_level structures. Don't compare
+ status or cjobs as they seem to have something to do with the
+ printer queue. */
+
+ pi1 = p1->info_2;
+ pi2 = p2->info_2;
+
+ /* Don't check the attributes as we stomp on the value in
+ check_printer_ok() anyway. */
+
+#if 0
+ PI_CHECK_INT(attributes);
+#endif
+
+ PI_CHECK_INT(priority);
+ PI_CHECK_INT(default_priority);
+ PI_CHECK_INT(starttime);
+ PI_CHECK_INT(untiltime);
+ PI_CHECK_INT(averageppm);
+
+ /* Yuck - don't check the printername or servername as the
+ add_a_printer() code plays games with them. You can't
+ change the printername or the sharename through this interface
+ in Samba. */
+
+ PI_CHECK_STR(sharename);
+ PI_CHECK_STR(portname);
+ PI_CHECK_STR(drivername);
+ PI_CHECK_STR(comment);
+ PI_CHECK_STR(location);
+
+ if (!nt_devicemode_equal(pi1->devmode, pi2->devmode)) {
+ return False;
+ }
+
+ PI_CHECK_STR(sepfile);
+ PI_CHECK_STR(printprocessor);
+ PI_CHECK_STR(datatype);
+ PI_CHECK_STR(parameters);
+
+ if (!nt_printer_param_equal(pi1->specific, pi2->specific)) {
+ return False;
+ }
+
+ if (!sec_desc_equal(pi1->secdesc_buf->sec, pi2->secdesc_buf->sec)) {
+ return False;
+ }
+
+ PI_CHECK_INT(changeid);
+ PI_CHECK_INT(c_setprinter);
+ PI_CHECK_INT(setuptime);
+
+ equal:
+ DEBUG(10, ("nt_printer_info_level_equal(): infos are identical\n"));
+ return True;
+}
+
+/********************************************************************
+ * called by spoolss_api_setprinter
+ * when updating a printer description
+ ********************************************************************/
+
+static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ DEVICEMODE *devmode)
+{
+ int snum;
+ NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ WERROR result;
+
+ DEBUG(8,("update_printer\n"));
+
+ result = WERR_OK;
+
+ if (level!=2) {
+ DEBUG(0,("Send a mail to samba@samba.org\n"));
+ DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
+ result = WERR_UNKNOWN_LEVEL;
+ goto done;
+ }
+
+ if (!Printer) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (!get_printer_snum(p, handle, &snum)) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) ||
+ (!W_ERROR_IS_OK(get_a_printer(&old_printer, 2, lp_servicename(snum))))) {
+ result = WERR_BADFID;
+ goto done;
+ }
+
+ DEBUGADD(8,("Converting info_2 struct\n"));
+
+ /*
+ * convert_printer_info converts the incoming
+ * info from the client and overwrites the info
+ * just read from the tdb in the pointer 'printer'.
+ */
+
+ if (!convert_printer_info(info, printer, level)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if (info->info_2->devmode_ptr != 0) {
+ /* we have a valid devmode
+ convert it and link it*/
+
+ DEBUGADD(8,("Converting the devicemode struct\n"));
+ if (!convert_devicemode(printer->info_2->printername, devmode,
+ &printer->info_2->devmode)) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+ }
+
+ /* Do sanity check on the requested changes for Samba */
+
+ if (!check_printer_ok(printer->info_2, snum)) {
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* NT likes to call this function even though nothing has actually
+ changed. Check this so the user doesn't end up with an
+ annoying permission denied dialog box. */
+
+ if (nt_printer_info_level_equal(printer, old_printer)) {
+ DEBUG(3, ("printer info has not changed\n"));
+ result = WERR_OK;
+ goto done;
+ }
+
+ /* Check calling user has permission to update printer description */
+
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("printer property change denied by security "
+ "descriptor\n"));
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Call addprinter hook */
+
+ if (*lp_addprinter_cmd()) {
+ if (!add_printer_hook(printer)) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ /* Update printer info */
+ result = add_a_printer(*printer, 2);
+
+ done:
+ free_a_printer(&printer, 2);
+ free_a_printer(&old_printer, 2);
+
+ srv_spoolss_sendnotify(p, handle);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SETPRINTER *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
+ DEVMODE_CTR devmode_ctr = q_u->devmode_ctr;
+ SEC_DESC_BUF *secdesc_ctr = q_u->secdesc_ctr;
+ uint32 command = q_u->command;
+
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_setprinter: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* check the level */
+ switch (level) {
+ case 0:
+ return control_printer(handle, command, p);
+ case 2:
+ return update_printer(p, handle, level, info, devmode_ctr.devmode);
+ case 3:
+ return update_printer_sec(handle, level, info, p,
+ secdesc_ctr);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+
+ Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_fcpn: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (Printer->notify.client_connected==True)
+ srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+
+ Printer->notify.flags=0;
+ Printer->notify.options=0;
+ Printer->notify.localmachine[0]='\0';
+ Printer->notify.printerlocal=0;
+ if (Printer->notify.option)
+ free_spool_notify_option(&Printer->notify.option);
+ Printer->notify.client_connected=False;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addjob(pipes_struct *p, SPOOL_Q_ADDJOB *q_u, SPOOL_R_ADDJOB *r_u)
+{
+ /* that's an [in out] buffer (despite appearences to the contrary) */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+
+ r_u->needed = 0;
+ return WERR_INVALID_PARAM; /* this is what a NT server
+ returns for AddJob. AddJob
+ must fail on non-local
+ printers */
+}
+
+/****************************************************************************
+****************************************************************************/
+static void fill_job_info_1(JOB_INFO_1 *job_info, print_queue_struct *queue,
+ int position, int snum)
+{
+ pstring temp_name;
+
+ struct tm *t;
+
+ t=gmtime(&queue->time);
+ slprintf(temp_name, sizeof(temp_name)-1, "\\\\%s", global_myname);
+
+ job_info->jobid=queue->job;
+ init_unistr(&job_info->printername, lp_servicename(snum));
+ init_unistr(&job_info->machinename, temp_name);
+ init_unistr(&job_info->username, queue->user);
+ init_unistr(&job_info->document, queue->file);
+ init_unistr(&job_info->datatype, "RAW");
+ init_unistr(&job_info->text_status, "");
+ job_info->status=nt_printj_status(queue->status);
+ job_info->priority=queue->priority;
+ job_info->position=position;
+ job_info->totalpages=0;
+ job_info->pagesprinted=0;
+
+ make_systemtime(&job_info->submitted, t);
+}
+
+/****************************************************************************
+****************************************************************************/
+static BOOL fill_job_info_2(JOB_INFO_2 *job_info, print_queue_struct *queue,
+ int position, int snum,
+ NT_PRINTER_INFO_LEVEL *ntprinter)
+{
+ pstring temp_name;
+ pstring chaine;
+ struct tm *t;
+
+ t=gmtime(&queue->time);
+ slprintf(temp_name, sizeof(temp_name)-1, "\\\\%s", global_myname);
+
+ job_info->jobid=queue->job;
+
+ slprintf(chaine, sizeof(chaine)-1, "\\\\%s\\%s", global_myname, ntprinter->info_2->printername);
+
+ init_unistr(&job_info->printername, chaine);
+
+ init_unistr(&job_info->machinename, temp_name);
+ init_unistr(&job_info->username, queue->user);
+ init_unistr(&job_info->document, queue->file);
+ init_unistr(&job_info->notifyname, queue->user);
+ init_unistr(&job_info->datatype, "RAW");
+ init_unistr(&job_info->printprocessor, "winprint");
+ init_unistr(&job_info->parameters, "");
+ init_unistr(&job_info->drivername, ntprinter->info_2->drivername);
+ init_unistr(&job_info->text_status, "");
+
+/* and here the security descriptor */
+
+ job_info->status=nt_printj_status(queue->status);
+ job_info->priority=queue->priority;
+ job_info->position=position;
+ job_info->starttime=0;
+ job_info->untiltime=0;
+ job_info->totalpages=0;
+ job_info->size=queue->size;
+ make_systemtime(&(job_info->submitted), t);
+ job_info->timeelapsed=0;
+ job_info->pagesprinted=0;
+
+ if((job_info->devmode = construct_dev_mode(snum)) == NULL) {
+ return False;
+ }
+
+ return (True);
+}
+
+/****************************************************************************
+ Enumjobs at level 1.
+****************************************************************************/
+static WERROR enumjobs_level1(print_queue_struct *queue, int snum,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ JOB_INFO_1 *info;
+ int i;
+
+ info=(JOB_INFO_1 *)malloc(*returned*sizeof(JOB_INFO_1));
+ if (info==NULL) {
+ SAFE_FREE(queue);
+ *returned=0;
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<*returned; i++)
+ fill_job_info_1(&info[i], &queue[i], i, snum);
+
+ SAFE_FREE(queue);
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_job_info_1(&info[i]);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_job_info_1("", buffer, &info[i], 0);
+
+ /* clear memory */
+ SAFE_FREE(info);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Enumjobs at level 2.
+****************************************************************************/
+static WERROR enumjobs_level2(print_queue_struct *queue, int snum,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ JOB_INFO_2 *info;
+ int i;
+ WERROR result;
+
+ info=(JOB_INFO_2 *)malloc(*returned*sizeof(JOB_INFO_2));
+ if (info==NULL) {
+ *returned=0;
+ return WERR_NOMEM;
+ }
+
+ result = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(result)) {
+ *returned = 0;
+ return result;
+ }
+
+ for (i=0; i<*returned; i++)
+ fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter);
+
+ free_a_printer(&ntprinter, 2);
+ SAFE_FREE(queue);
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++)
+ (*needed) += spoolss_size_job_info_2(&info[i]);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ for (i=0; i<*returned; i++)
+ smb_io_job_info_2("", buffer, &info[i], 0);
+
+ /* clear memory */
+ for (i = 0; i < *returned; i++)
+ free_job_info_2(&info[i]);
+
+ SAFE_FREE(info);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Enumjobs.
+****************************************************************************/
+
+WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+/* uint32 firstjob = q_u->firstjob; - notused. */
+/* uint32 numofjobs = q_u->numofjobs; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ int snum;
+ print_status_struct prt_status;
+ print_queue_struct *queue=NULL;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumjobs\n"));
+
+ *needed=0;
+ *returned=0;
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ *returned = print_queue_status(snum, &queue, &prt_status);
+ DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
+
+ if (*returned == 0) {
+ SAFE_FREE(queue);
+ return WERR_OK;
+ }
+
+ switch (level) {
+ case 1:
+ return enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+ case 2:
+ return enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+ default:
+ SAFE_FREE(queue);
+ *returned=0;
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_schedulejob( pipes_struct *p, SPOOL_Q_SCHEDULEJOB *q_u, SPOOL_R_SCHEDULEJOB *r_u)
+{
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setjob(pipes_struct *p, SPOOL_Q_SETJOB *q_u, SPOOL_R_SETJOB *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 jobid = q_u->jobid;
+/* uint32 level = q_u->level; - notused. */
+/* JOB_INFO *ctr = &q_u->ctr; - notused. */
+ uint32 command = q_u->command;
+
+ struct current_user user;
+ int snum;
+ WERROR errcode = WERR_BADFUNC;
+
+ if (!get_printer_snum(p, handle, &snum)) {
+ return WERR_BADFID;
+ }
+
+ if (!print_job_exists(jobid)) {
+ return WERR_INVALID_PRINTER_NAME;
+ }
+
+ get_current_user(&user, p);
+
+ switch (command) {
+ case JOB_CONTROL_CANCEL:
+ case JOB_CONTROL_DELETE:
+ if (print_job_delete(&user, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case JOB_CONTROL_PAUSE:
+ if (print_job_pause(&user, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ case JOB_CONTROL_RESTART:
+ case JOB_CONTROL_RESUME:
+ if (print_job_resume(&user, jobid, &errcode)) {
+ errcode = WERR_OK;
+ }
+ break;
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return errcode;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 1.
+****************************************************************************/
+static WERROR enumprinterdrivers_level1(fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ DRIVER_INFO_1 *tdi1, *driver_info_1=NULL;
+
+ *returned=0;
+
+#define MAX_VERSION 4
+
+ for (version=0; version<MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1)
+ return WERR_NOMEM;
+
+ if(ndrivers != 0) {
+ if((tdi1=(DRIVER_INFO_1 *)Realloc(driver_info_1, (*returned+ndrivers) * sizeof(DRIVER_INFO_1))) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level1: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(driver_info_1);
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ else driver_info_1 = tdi1;
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ return status;
+ }
+ fill_printer_driver_info_1(&driver_info_1[*returned+i], driver, servername, architecture );
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_1(&driver_info_1[i]);
+ }
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(driver_info_1);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the driver structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_1("", buffer, &driver_info_1[i], 0);
+ }
+
+ SAFE_FREE(driver_info_1);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 2.
+****************************************************************************/
+static WERROR enumprinterdrivers_level2(fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ DRIVER_INFO_2 *tdi2, *driver_info_2=NULL;
+
+ *returned=0;
+
+#define MAX_VERSION 4
+
+ for (version=0; version<MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1)
+ return WERR_NOMEM;
+
+ if(ndrivers != 0) {
+ if((tdi2=(DRIVER_INFO_2 *)Realloc(driver_info_2, (*returned+ndrivers) * sizeof(DRIVER_INFO_2))) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level2: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(driver_info_2);
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ else driver_info_2 = tdi2;
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ return status;
+ }
+ fill_printer_driver_info_2(&driver_info_2[*returned+i], driver, servername);
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_2(&(driver_info_2[i]));
+ }
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(driver_info_2);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the form structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
+ }
+
+ SAFE_FREE(driver_info_2);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 3.
+****************************************************************************/
+static WERROR enumprinterdrivers_level3(fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ int i;
+ int ndrivers;
+ uint32 version;
+ fstring *list = NULL;
+
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ DRIVER_INFO_3 *tdi3, *driver_info_3=NULL;
+
+ *returned=0;
+
+#define MAX_VERSION 4
+
+ for (version=0; version<MAX_VERSION; version++) {
+ list=NULL;
+ ndrivers=get_ntdrivers(&list, architecture, version);
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+
+ if(ndrivers == -1)
+ return WERR_NOMEM;
+
+ if(ndrivers != 0) {
+ if((tdi3=(DRIVER_INFO_3 *)Realloc(driver_info_3, (*returned+ndrivers) * sizeof(DRIVER_INFO_3))) == NULL) {
+ DEBUG(0,("enumprinterdrivers_level3: failed to enlarge driver info buffer!\n"));
+ SAFE_FREE(driver_info_3);
+ SAFE_FREE(list);
+ return WERR_NOMEM;
+ }
+ else driver_info_3 = tdi3;
+ }
+
+ for (i=0; i<ndrivers; i++) {
+ WERROR status;
+
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ ZERO_STRUCT(driver);
+ status = get_a_printer_driver(&driver, 3, list[i],
+ architecture, version);
+ if (!W_ERROR_IS_OK(status)) {
+ SAFE_FREE(list);
+ return status;
+ }
+ fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);
+ free_a_printer_driver(driver, 3);
+ }
+
+ *returned+=ndrivers;
+ SAFE_FREE(list);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d]'s size\n",i));
+ *needed += spoolss_size_printer_driver_info_3(&driver_info_3[i]);
+ }
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(driver_info_3);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the driver structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+ smb_io_printer_driver_info_3("", buffer, &driver_info_3[i], 0);
+ }
+
+ for (i=0; i<*returned; i++)
+ SAFE_FREE(driver_info_3[i].dependentfiles);
+
+ SAFE_FREE(driver_info_3);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers.
+****************************************************************************/
+
+WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u)
+{
+/* UNISTR2 *name = &q_u->name; - notused. */
+ UNISTR2 *environment = &q_u->environment;
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ fstring *list = NULL;
+ fstring servername;
+ fstring architecture;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumprinterdrivers\n"));
+ fstrcpy(servername, global_myname);
+ *needed=0;
+ *returned=0;
+
+ unistr2_to_ascii(architecture, environment, sizeof(architecture)-1);
+
+ switch (level) {
+ case 1:
+ return enumprinterdrivers_level1(servername, architecture, buffer, offered, needed, returned);
+ case 2:
+ return enumprinterdrivers_level2(servername, architecture, buffer, offered, needed, returned);
+ case 3:
+ return enumprinterdrivers_level3(servername, architecture, buffer, offered, needed, returned);
+ default:
+ *returned=0;
+ SAFE_FREE(list);
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static void fill_form_1(FORM_1 *form, nt_forms_struct *list)
+{
+ form->flag=list->flag;
+ init_unistr(&form->name, list->name);
+ form->width=list->width;
+ form->length=list->length;
+ form->left=list->left;
+ form->top=list->top;
+ form->right=list->right;
+ form->bottom=list->bottom;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u)
+{
+/* POLICY_HND *handle = &q_u->handle; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *numofforms = &r_u->numofforms;
+ uint32 numbuiltinforms;
+
+ nt_forms_struct *list=NULL;
+ nt_forms_struct *builtinlist=NULL;
+ FORM_1 *forms_1;
+ int buffer_size=0;
+ int i;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumforms\n"));
+ DEBUGADD(5,("Offered buffer size [%d]\n", offered));
+ DEBUGADD(5,("Info level [%d]\n", level));
+
+ numbuiltinforms = get_builtin_ntforms(&builtinlist);
+ DEBUGADD(5,("Number of builtin forms [%d]\n", numbuiltinforms));
+ *numofforms = get_ntforms(&list);
+ DEBUGADD(5,("Number of user forms [%d]\n", *numofforms));
+ *numofforms += numbuiltinforms;
+
+ if (*numofforms == 0) return WERR_NO_MORE_ITEMS;
+
+ switch (level) {
+ case 1:
+ if ((forms_1=(FORM_1 *)malloc(*numofforms * sizeof(FORM_1))) == NULL) {
+ *numofforms=0;
+ return WERR_NOMEM;
+ }
+
+ /* construct the list of form structures */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("Filling form number [%d]\n",i));
+ fill_form_1(&forms_1[i], &builtinlist[i]);
+ }
+
+ SAFE_FREE(builtinlist);
+
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("Filling form number [%d]\n",i));
+ fill_form_1(&forms_1[i], &list[i-numbuiltinforms]);
+ }
+
+ SAFE_FREE(list);
+
+ /* check the required size. */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("adding form [%d]'s size\n",i));
+ buffer_size += spoolss_size_form_1(&forms_1[i]);
+ }
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("adding form [%d]'s size\n",i));
+ buffer_size += spoolss_size_form_1(&forms_1[i]);
+ }
+
+ *needed=buffer_size;
+
+ if (!alloc_buffer_size(buffer, buffer_size)){
+ SAFE_FREE(forms_1);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the form structures */
+ for (i=0; i<numbuiltinforms; i++) {
+ DEBUGADD(6,("adding form [%d] to buffer\n",i));
+ smb_io_form_1("", buffer, &forms_1[i], 0);
+ }
+ for (; i<*numofforms; i++) {
+ DEBUGADD(6,("adding form [%d] to buffer\n",i));
+ smb_io_form_1("", buffer, &forms_1[i], 0);
+ }
+
+ SAFE_FREE(forms_1);
+
+ if (*needed > offered) {
+ *numofforms=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ else
+ return WERR_OK;
+
+ default:
+ SAFE_FREE(list);
+ SAFE_FREE(builtinlist);
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getform(pipes_struct *p, SPOOL_Q_GETFORM *q_u, SPOOL_R_GETFORM *r_u)
+{
+/* POLICY_HND *handle = &q_u->handle; - notused. */
+ uint32 level = q_u->level;
+ UNISTR2 *uni_formname = &q_u->formname;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ nt_forms_struct *list=NULL;
+ nt_forms_struct builtin_form;
+ BOOL foundBuiltin;
+ FORM_1 form_1;
+ fstring form_name;
+ int buffer_size=0;
+ int numofforms=0, i=0;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
+
+ DEBUG(4,("_spoolss_getform\n"));
+ DEBUGADD(5,("Offered buffer size [%d]\n", offered));
+ DEBUGADD(5,("Info level [%d]\n", level));
+
+ foundBuiltin = get_a_builtin_ntform(uni_formname,&builtin_form);
+ if (!foundBuiltin) {
+ numofforms = get_ntforms(&list);
+ DEBUGADD(5,("Number of forms [%d]\n", numofforms));
+
+ if (numofforms == 0)
+ return WERR_BADFID;
+ }
+
+ switch (level) {
+ case 1:
+ if (foundBuiltin) {
+ fill_form_1(&form_1, &builtin_form);
+ } else {
+
+ /* Check if the requested name is in the list of form structures */
+ for (i=0; i<numofforms; i++) {
+
+ DEBUG(4,("_spoolss_getform: checking form %s (want %s)\n", list[i].name, form_name));
+
+ if (strequal(form_name, list[i].name)) {
+ DEBUGADD(6,("Found form %s number [%d]\n", form_name, i));
+ fill_form_1(&form_1, &list[i]);
+ break;
+ }
+ }
+
+ SAFE_FREE(list);
+ if (i == numofforms) {
+ return WERR_BADFID;
+ }
+ }
+ /* check the required size. */
+
+ *needed=spoolss_size_form_1(&form_1);
+
+ if (!alloc_buffer_size(buffer, buffer_size)){
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the form structures */
+ DEBUGADD(6,("adding form %s [%d] to buffer\n", form_name, i));
+ smb_io_form_1("", buffer, &form_1, 0);
+
+ return WERR_OK;
+
+ default:
+ SAFE_FREE(list);
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+static void fill_port_1(PORT_INFO_1 *port, char *name)
+{
+ init_unistr(&port->port_name, name);
+}
+
+/****************************************************************************
+****************************************************************************/
+static void fill_port_2(PORT_INFO_2 *port, char *name)
+{
+ init_unistr(&port->port_name, name);
+ init_unistr(&port->monitor_name, "Local Monitor");
+ init_unistr(&port->description, "Local Port");
+#define PORT_TYPE_WRITE 1
+ port->port_type=PORT_TYPE_WRITE;
+ port->reserved=0x0;
+}
+
+/****************************************************************************
+ enumports level 1.
+****************************************************************************/
+static WERROR enumports_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PORT_INFO_1 *ports=NULL;
+ int i=0;
+
+ if (*lp_enumports_cmd()) {
+ char *cmd = lp_enumports_cmd();
+ char **qlines;
+ pstring command;
+ int numlines;
+ int ret;
+ int fd;
+
+ slprintf(command, sizeof(command)-1, "%s \"%d\"", cmd, 1);
+
+ DEBUG(10,("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUG(10,("Returned [%d]\n", ret));
+ if (ret != 0) {
+ if (fd != -1)
+ close(fd);
+ /* Is this the best error to return here? */
+ return WERR_ACCESS_DENIED;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ if(numlines) {
+ if((ports=(PORT_INFO_1 *)malloc( numlines * sizeof(PORT_INFO_1) )) == NULL) {
+ DEBUG(10,("Returning WERR_NOMEM [%s]\n",
+ werror_str(WERR_NOMEM)));
+ file_lines_free(qlines);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<numlines; i++) {
+ DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+ fill_port_1(&ports[i], qlines[i]);
+ }
+
+ file_lines_free(qlines);
+ }
+
+ *returned = numlines;
+
+ } else {
+ *returned = 1; /* Sole Samba port returned. */
+
+ if((ports=(PORT_INFO_1 *)malloc( sizeof(PORT_INFO_1) )) == NULL)
+ return WERR_NOMEM;
+
+ DEBUG(10,("enumports_level_1: port name %s\n", SAMBA_PRINTER_PORT_NAME));
+
+ fill_port_1(&ports[0], SAMBA_PRINTER_PORT_NAME);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d]'s size\n", i));
+ *needed += spoolss_size_port_info_1(&ports[i]);
+ }
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(ports);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the ports structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d] to buffer\n", i));
+ smb_io_port_1("", buffer, &ports[i], 0);
+ }
+
+ SAFE_FREE(ports);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ enumports level 2.
+****************************************************************************/
+
+static WERROR enumports_level_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PORT_INFO_2 *ports=NULL;
+ int i=0;
+
+ if (*lp_enumports_cmd()) {
+ char *cmd = lp_enumports_cmd();
+ char *path;
+ char **qlines;
+ pstring tmp_file;
+ pstring command;
+ int numlines;
+ int ret;
+ int fd;
+
+ if (*lp_pathname(lp_servicenumber(PRINTERS_NAME)))
+ path = lp_pathname(lp_servicenumber(PRINTERS_NAME));
+ else
+ path = lp_lockdir();
+
+ slprintf(tmp_file, sizeof(tmp_file)-1, "%s/smbcmd.%u.", path, (unsigned int)sys_getpid());
+ slprintf(command, sizeof(command)-1, "%s \"%d\"", cmd, 2);
+
+ unlink(tmp_file);
+ DEBUG(10,("Running [%s > %s]\n", command,tmp_file));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10,("returned [%d]\n", ret));
+ if (ret != 0) {
+ if (fd != -1)
+ close(fd);
+ /* Is this the best error to return here? */
+ return WERR_ACCESS_DENIED;
+ }
+
+ numlines = 0;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ if(numlines) {
+ if((ports=(PORT_INFO_2 *)malloc( numlines * sizeof(PORT_INFO_2) )) == NULL) {
+ file_lines_free(qlines);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<numlines; i++) {
+ DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+ fill_port_2(&(ports[i]), qlines[i]);
+ }
+
+ file_lines_free(qlines);
+ }
+
+ *returned = numlines;
+
+ } else {
+
+ *returned = 1;
+
+ if((ports=(PORT_INFO_2 *)malloc( sizeof(PORT_INFO_2) )) == NULL)
+ return WERR_NOMEM;
+
+ DEBUG(10,("enumports_level_2: port name %s\n", SAMBA_PRINTER_PORT_NAME));
+
+ fill_port_2(&ports[0], SAMBA_PRINTER_PORT_NAME);
+ }
+
+ /* check the required size. */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d]'s size\n", i));
+ *needed += spoolss_size_port_info_2(&ports[i]);
+ }
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(ports);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the ports structures */
+ for (i=0; i<*returned; i++) {
+ DEBUGADD(6,("adding port [%d] to buffer\n", i));
+ smb_io_port_2("", buffer, &ports[i], 0);
+ }
+
+ SAFE_FREE(ports);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ enumports.
+****************************************************************************/
+
+WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u)
+{
+/* UNISTR2 *name = &q_u->name; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_enumports\n"));
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumports_level_1(buffer, offered, needed, returned);
+ case 2:
+ return enumports_level_2(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_srv_name,
+ const SPOOL_PRINTER_INFO_LEVEL *info,
+ uint32 unk0, uint32 unk1, uint32 unk2, uint32 unk3,
+ uint32 user_switch, const SPOOL_USER_CTR *user,
+ POLICY_HND *handle)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ fstring name;
+ int snum;
+ WERROR err = WERR_OK;
+
+ if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
+ DEBUG(0,("spoolss_addprinterex_level_2: malloc fail.\n"));
+ return WERR_NOMEM;
+ }
+
+ ZERO_STRUCTP(printer);
+
+ /* convert from UNICODE to ASCII - this allocates the info_2 struct inside *printer.*/
+ if (!convert_printer_info(info, printer, 2)) {
+ free_a_printer(&printer, 2);
+ return WERR_NOMEM;
+ }
+
+ /* check to see if the printer already exists */
+
+ if ((snum = print_queue_snum(printer->info_2->sharename)) != -1) {
+ DEBUG(5, ("_spoolss_addprinterex: Attempted to add a printer named [%s] when one already existed!\n",
+ printer->info_2->sharename));
+ free_a_printer(&printer, 2);
+ return WERR_PRINTER_ALREADY_EXISTS;
+ }
+
+ if (*lp_addprinter_cmd() )
+ if ( !add_printer_hook(printer) ) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname,
+ printer->info_2->sharename);
+
+ if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /* you must be a printer admin to add a new printer */
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ /*
+ * Do sanity check on the requested changes for Samba.
+ */
+
+ if (!check_printer_ok(printer->info_2, snum)) {
+ free_a_printer(&printer,2);
+ return WERR_INVALID_PARAM;
+ }
+
+ /*
+ * When a printer is created, the drivername bound to the printer is used
+ * to lookup previously saved driver initialization info, which is then
+ * bound to the new printer, simulating what happens in the Windows arch.
+ */
+ set_driver_init(printer, 2);
+
+ /* write the ASCII on disk */
+ err = add_a_printer(*printer, 2);
+ if (!W_ERROR_IS_OK(err)) {
+ free_a_printer(&printer,2);
+ return err;
+ }
+
+ if (!open_printer_hnd(p, handle, name)) {
+ /* Handle open failed - remove addition. */
+ del_a_printer(printer->info_2->sharename);
+ free_a_printer(&printer,2);
+ return WERR_ACCESS_DENIED;
+ }
+
+ free_a_printer(&printer,2);
+
+ srv_spoolss_sendnotify(p, handle);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u)
+{
+ UNISTR2 *uni_srv_name = &q_u->server_name;
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
+ uint32 unk0 = q_u->unk0;
+ uint32 unk1 = q_u->unk1;
+ uint32 unk2 = q_u->unk2;
+ uint32 unk3 = q_u->unk3;
+ uint32 user_switch = q_u->user_switch;
+ SPOOL_USER_CTR *user = &q_u->user_ctr;
+ POLICY_HND *handle = &r_u->handle;
+
+ switch (level) {
+ case 1:
+ /* we don't handle yet */
+ /* but I know what to do ... */
+ return WERR_UNKNOWN_LEVEL;
+ case 2:
+ return spoolss_addprinterex_level_2(p, uni_srv_name, info,
+ unk0, unk1, unk2, unk3,
+ user_switch, user, handle);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, SPOOL_R_ADDPRINTERDRIVER *r_u)
+{
+/* UNISTR2 *server_name = &q_u->server_name; - notused. */
+ uint32 level = q_u->level;
+ SPOOL_PRINTER_DRIVER_INFO_LEVEL *info = &q_u->info;
+ WERROR err = WERR_OK;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ struct current_user user;
+
+ ZERO_STRUCT(driver);
+
+ get_current_user(&user, p);
+
+ if (!convert_printer_driver_info(info, &driver, level)) {
+ err = WERR_NOMEM;
+ goto done;
+ }
+
+ DEBUG(5,("Cleaning driver's information\n"));
+ err = clean_up_driver_struct(driver, level, &user);
+ if (!W_ERROR_IS_OK(err))
+ goto done;
+
+ DEBUG(5,("Moving driver to final destination\n"));
+ if(!move_driver_to_download_area(driver, level, &user, &err)) {
+ if (W_ERROR_IS_OK(err))
+ err = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ if (add_a_printer_driver(driver, level)!=0) {
+ err = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ done:
+ free_a_printer_driver(driver, level);
+ return err;
+}
+
+/****************************************************************************
+****************************************************************************/
+static void fill_driverdir_1(DRIVER_DIRECTORY_1 *info, char *name)
+{
+ init_unistr(&info->name, name);
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environment, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ pstring path;
+ pstring long_archi;
+ pstring short_archi;
+ DRIVER_DIRECTORY_1 *info=NULL;
+
+ unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
+
+ if (get_short_archi(short_archi, long_archi)==False)
+ return WERR_INVALID_ENVIRONMENT;
+
+ if((info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1))) == NULL)
+ return WERR_NOMEM;
+
+ slprintf(path, sizeof(path)-1, "\\\\%s\\print$\\%s", global_myname, short_archi);
+
+ DEBUG(4,("printer driver directory: [%s]\n", path));
+
+ fill_driverdir_1(info, path);
+
+ *needed += spoolss_size_driverdir_info_1(info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ smb_io_driverdir_1("", buffer, info, 0);
+
+ SAFE_FREE(info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, SPOOL_R_GETPRINTERDRIVERDIR *r_u)
+{
+ UNISTR2 *name = &q_u->name;
+ UNISTR2 *uni_environment = &q_u->environment;
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(4,("_spoolss_getprinterdriverdirectory\n"));
+
+ *needed=0;
+
+ switch(level) {
+ case 1:
+ return getprinterdriverdir_level_1(name, uni_environment, buffer, offered, needed);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 idx = q_u->index;
+ uint32 in_value_len = q_u->valuesize;
+ uint32 in_data_len = q_u->datasize;
+ uint32 *out_max_value_len = &r_u->valuesize;
+ uint16 **out_value = &r_u->value;
+ uint32 *out_value_len = &r_u->realvaluesize;
+ uint32 *out_type = &r_u->type;
+ uint32 *out_max_data_len = &r_u->datasize;
+ uint8 **data_out = &r_u->data;
+ uint32 *out_data_len = &r_u->realdatasize;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+ fstring value;
+
+ uint32 param_index;
+ uint32 biggest_valuesize;
+ uint32 biggest_datasize;
+ uint32 data_len;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ uint8 *data=NULL;
+ uint32 type;
+ WERROR result;
+
+ ZERO_STRUCT(printer);
+
+ *out_type=0;
+
+ *out_max_data_len=0;
+ *data_out=NULL;
+ *out_data_len=0;
+
+ DEBUG(5,("spoolss_enumprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_enumprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p,handle, &snum))
+ return WERR_BADFID;
+
+ result = get_a_printer(&printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(result))
+ return result;
+
+ /*
+ * The NT machine wants to know the biggest size of value and data
+ *
+ * cf: MSDN EnumPrinterData remark section
+ */
+ if ( (in_value_len==0) && (in_data_len==0) ) {
+ DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
+
+#if 0
+ /*
+ * NT can ask for a specific parameter size - we need to return NO_MORE_ITEMS
+ * if this parameter size doesn't exist.
+ * Ok - my opinion here is that the client is not asking for the greatest
+ * possible size of all the parameters, but is asking specifically for the size needed
+ * for this specific parameter. In that case we can remove the loop below and
+ * simplify this lookup code considerably. JF - comments welcome. JRA.
+ */
+
+ if (!get_specific_param_by_index(*printer, 2, idx, value, &data, &type, &data_len)) {
+ SAFE_FREE(data);
+ free_a_printer(&printer, 2);
+ return WERR_NO_MORE_ITEMS;
+ }
+#endif
+
+ SAFE_FREE(data);
+
+ param_index=0;
+ biggest_valuesize=0;
+ biggest_datasize=0;
+
+ while (get_specific_param_by_index(*printer, 2, param_index, value, &data, &type, &data_len)) {
+ if (strlen(value) > biggest_valuesize) biggest_valuesize=strlen(value);
+ if (data_len > biggest_datasize) biggest_datasize=data_len;
+
+ DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, biggest_datasize));
+
+ SAFE_FREE(data);
+ param_index++;
+ }
+
+ /* the value is an UNICODE string but realvaluesize is the length in bytes including the leading 0 */
+ *out_value_len=2*(1+biggest_valuesize);
+ *out_data_len=biggest_datasize;
+
+ DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
+
+ free_a_printer(&printer, 2);
+ return WERR_OK;
+ }
+
+ /*
+ * the value len is wrong in NT sp3
+ * that's the number of bytes not the number of unicode chars
+ */
+
+ if (!get_specific_param_by_index(*printer, 2, idx, value, &data, &type, &data_len)) {
+
+ SAFE_FREE(data);
+ free_a_printer(&printer, 2);
+
+ /* out_value should default to "" or else NT4 has
+ problems unmarshalling the response */
+
+ *out_max_value_len=(in_value_len/sizeof(uint16));
+ if((*out_value=(uint16 *)malloc(in_value_len*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+
+ ZERO_STRUCTP(*out_value);
+ *out_value_len = rpcstr_push((char *)*out_value, "", in_value_len, 0);
+
+ /* the data is counted in bytes */
+ *out_max_data_len = in_data_len;
+ *out_data_len = in_data_len;
+ if((*data_out=(uint8 *)malloc(in_data_len*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+
+ memset(*data_out,'\0',in_data_len);
+
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ free_a_printer(&printer, 2);
+
+ /*
+ * the value is:
+ * - counted in bytes in the request
+ * - counted in UNICODE chars in the max reply
+ * - counted in bytes in the real size
+ *
+ * take a pause *before* coding not *during* coding
+ */
+
+ *out_max_value_len=(in_value_len/sizeof(uint16));
+ if((*out_value=(uint16 *)talloc_zero(p->mem_ctx,in_value_len*sizeof(uint8))) == NULL) {
+ SAFE_FREE(data);
+ return WERR_NOMEM;
+ }
+
+ *out_value_len = rpcstr_push((char *)*out_value,value, in_value_len, 0);
+
+ *out_type=type;
+
+ /* the data is counted in bytes */
+ *out_max_data_len=in_data_len;
+ if((*data_out=(uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) {
+ SAFE_FREE(data);
+ return WERR_NOMEM;
+ }
+
+ memcpy(*data_out, data, (size_t)data_len);
+ *out_data_len=data_len;
+
+ SAFE_FREE(data);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *value = &q_u->value;
+ uint32 type = q_u->type;
+/* uint32 max_len = q_u->max_len; - notused. */
+ uint8 *data = q_u->data;
+ uint32 real_len = q_u->real_len;
+/* uint32 numeric_data = q_u->numeric_data; - notused. */
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_PARAM *param = NULL, old_param;
+ int snum=0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_setprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_setprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p,handle, &snum))
+ return WERR_BADFID;
+
+ ZERO_STRUCT(old_param);
+
+ /*
+ * Access check : NT returns "access denied" if you make a
+ * SetPrinterData call without the necessary privildge.
+ * we were originally returning OK if nothing changed
+ * which made Win2k issue **a lot** of SetPrinterData
+ * when connecting to a printer --jerry
+ */
+
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("security descriptor change denied by existing "
+ "security descriptor\n"));
+ status = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* Check if we are making any changes or not. Return true if
+ nothing is actually changing. This is not needed anymore but
+ has been left in as an optimization to keep from from
+ writing to disk as often --jerry */
+
+ status = get_a_printer(&printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ convert_specific_param(&param, value , type, data, real_len);
+
+
+ if (get_specific_param(*printer, 2, param->value, &old_param.data,
+ &old_param.type, (uint32 *)&old_param.data_len)) {
+
+ if (param->type == old_param.type &&
+ param->data_len == old_param.data_len &&
+ memcmp(param->data, old_param.data,
+ old_param.data_len) == 0) {
+
+ DEBUG(3, ("setprinterdata hasn't changed\n"));
+ status = WERR_OK;
+ goto done;
+ }
+ }
+
+ unlink_specific_param_if_exist(printer->info_2, param);
+
+ /*
+ * When client side code sets a magic printer data key, detect it and save
+ * the current printer data and the magic key's data (its the DEVMODE) for
+ * future printer/driver initializations.
+ */
+ if (param->type==3 && !strcmp( param->value, PHANTOM_DEVMODE_KEY)) {
+ /*
+ * Set devmode and printer initialization info
+ */
+ status = save_driver_init(printer, 2, param);
+ }
+ else {
+ add_a_specific_param(printer->info_2, &param);
+ status = mod_a_printer(*printer, 2);
+ }
+
+ done:
+ free_a_printer(&printer, 2);
+ if (param)
+ free_nt_printer_param(&param);
+ SAFE_FREE(old_param.data);
+
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_u, SPOOL_R_DELETEPRINTERDATA *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *value = &q_u->valuename;
+
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_PARAM param;
+ int snum=0;
+ WERROR status = WERR_OK;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_deleteprinterdata\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_deleteprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+ DEBUG(3, ("_spoolss_deleteprinterdata: printer properties "
+ "change denied by existing security descriptor\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ status = get_a_printer(&printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(status))
+ return status;
+
+ ZERO_STRUCTP(&param);
+ unistr2_to_ascii(param.value, value, sizeof(param.value)-1);
+
+ if(!unlink_specific_param_if_exist(printer->info_2, &param))
+ status = WERR_INVALID_PARAM;
+ else
+ status = mod_a_printer(*printer, 2);
+
+ free_a_printer(&printer, 2);
+ return status;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+/* uint32 level = q_u->level; - notused. */
+ FORM *form = &q_u->form;
+ nt_forms_struct tmpForm;
+
+ int count=0;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_addform\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_addform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /*
+ * FIXME!! Feels like there should be an access check here, but haven't
+ * had time to verify. --jerry
+ */
+
+ /* can't add if builtin */
+ if (get_a_builtin_ntform(&form->name,&tmpForm)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ count=get_ntforms(&list);
+ if(!add_a_form(&list, form, &count))
+ return WERR_NOMEM;
+ write_ntforms(&list, count);
+
+ SAFE_FREE(list);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DELETEFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ UNISTR2 *form_name = &q_u->name;
+ nt_forms_struct tmpForm;
+ int count=0;
+ WERROR ret = WERR_OK;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_deleteform\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_deleteform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+ /* can't delete if builtin */
+ if (get_a_builtin_ntform(form_name,&tmpForm)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ count = get_ntforms(&list);
+ if(!delete_a_form(&list, form_name, &count, &ret))
+ return WERR_INVALID_PARAM;
+
+ SAFE_FREE(list);
+
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+/* UNISTR2 *uni_name = &q_u->name; - notused. */
+/* uint32 level = q_u->level; - notused. */
+ FORM *form = &q_u->form;
+ nt_forms_struct tmpForm;
+
+ int count=0;
+ nt_forms_struct *list=NULL;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+
+ DEBUG(5,("spoolss_setform\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_setform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+ /* can't set if builtin */
+ if (get_a_builtin_ntform(&form->name,&tmpForm)) {
+ return WERR_INVALID_PARAM;
+ }
+
+ count=get_ntforms(&list);
+ update_a_form(&list, form, count);
+ write_ntforms(&list, count);
+
+ SAFE_FREE(list);
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ enumprintprocessors level 1.
+****************************************************************************/
+static WERROR enumprintprocessors_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTPROCESSOR_1 *info_1=NULL;
+
+ if((info_1 = (PRINTPROCESSOR_1 *)malloc(sizeof(PRINTPROCESSOR_1))) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_1->name, "winprint");
+
+ *needed += spoolss_size_printprocessor_info_1(info_1);
+
+ if (!alloc_buffer_size(buffer, *needed))
+ return WERR_INSUFFICIENT_BUFFER;
+
+ smb_io_printprocessor_info_1("", buffer, info_1, 0);
+
+ SAFE_FREE(info_1);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u)
+{
+/* UNISTR2 *name = &q_u->name; - notused. */
+/* UNISTR2 *environment = &q_u->environment; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_enumprintprocessors\n"));
+
+ /*
+ * Enumerate the print processors ...
+ *
+ * Just reply with "winprint", to keep NT happy
+ * and I can use my nice printer checker.
+ */
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintprocessors_level_1(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+ enumprintprocdatatypes level 1.
+****************************************************************************/
+static WERROR enumprintprocdatatypes_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTPROCDATATYPE_1 *info_1=NULL;
+
+ if((info_1 = (PRINTPROCDATATYPE_1 *)malloc(sizeof(PRINTPROCDATATYPE_1))) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_1->name, "RAW");
+
+ *needed += spoolss_size_printprocdatatype_info_1(info_1);
+
+ if (!alloc_buffer_size(buffer, *needed))
+ return WERR_INSUFFICIENT_BUFFER;
+
+ smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
+
+ SAFE_FREE(info_1);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u)
+{
+/* UNISTR2 *name = &q_u->name; - notused. */
+/* UNISTR2 *processor = &q_u->processor; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("_spoolss_enumprintprocdatatypes\n"));
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+ enumprintmonitors level 1.
+****************************************************************************/
+
+static WERROR enumprintmonitors_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTMONITOR_1 *info_1=NULL;
+
+ if((info_1 = (PRINTMONITOR_1 *)malloc(sizeof(PRINTMONITOR_1))) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_1->name, "Local Port");
+
+ *needed += spoolss_size_printmonitor_info_1(info_1);
+
+ if (!alloc_buffer_size(buffer, *needed))
+ return WERR_INSUFFICIENT_BUFFER;
+
+ smb_io_printmonitor_info_1("", buffer, info_1, 0);
+
+ SAFE_FREE(info_1);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+ enumprintmonitors level 2.
+****************************************************************************/
+static WERROR enumprintmonitors_level_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+ PRINTMONITOR_2 *info_2=NULL;
+
+ if((info_2 = (PRINTMONITOR_2 *)malloc(sizeof(PRINTMONITOR_2))) == NULL)
+ return WERR_NOMEM;
+
+ (*returned) = 0x1;
+
+ init_unistr(&info_2->name, "Local Port");
+ init_unistr(&info_2->environment, "Windows NT X86");
+ init_unistr(&info_2->dll_name, "localmon.dll");
+
+ *needed += spoolss_size_printmonitor_info_2(info_2);
+
+ if (!alloc_buffer_size(buffer, *needed))
+ return WERR_INSUFFICIENT_BUFFER;
+
+ smb_io_printmonitor_info_2("", buffer, info_2, 0);
+
+ SAFE_FREE(info_2);
+
+ if (*needed > offered) {
+ *returned=0;
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u)
+{
+/* UNISTR2 *name = &q_u->name; - notused. */
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+ uint32 *returned = &r_u->returned;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_enumprintmonitors\n"));
+
+ /*
+ * Enumerate the print monitors ...
+ *
+ * Just reply with "Local Port", to keep NT happy
+ * and I can use my nice printer checker.
+ */
+
+ *returned=0;
+ *needed=0;
+
+ switch (level) {
+ case 1:
+ return enumprintmonitors_level_1(buffer, offered, needed, returned);
+ case 2:
+ return enumprintmonitors_level_2(buffer, offered, needed, returned);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ int i=0;
+ BOOL found=False;
+ JOB_INFO_1 *info_1=NULL;
+
+ info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
+
+ if (info_1 == NULL) {
+ SAFE_FREE(queue);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<count && found==False; i++) {
+ if (queue[i].job==(int)jobid)
+ found=True;
+ }
+
+ if (found==False) {
+ SAFE_FREE(queue);
+ SAFE_FREE(info_1);
+ /* NT treats not found as bad param... yet another bad choice */
+ return WERR_INVALID_PARAM;
+ }
+
+ fill_job_info_1(info_1, &(queue[i-1]), i, snum);
+
+ SAFE_FREE(queue);
+
+ *needed += spoolss_size_job_info_1(info_1);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info_1);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ smb_io_job_info_1("", buffer, info_1, 0);
+
+ SAFE_FREE(info_1);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ int i=0;
+ BOOL found=False;
+ JOB_INFO_2 *info_2;
+ NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+ WERROR ret;
+
+ info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
+
+ ZERO_STRUCTP(info_2);
+
+ if (info_2 == NULL) {
+ SAFE_FREE(queue);
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i<count && found==False; i++) {
+ if (queue[i].job==(int)jobid)
+ found=True;
+ }
+
+ if (found==False) {
+ SAFE_FREE(queue);
+ SAFE_FREE(info_2);
+ /* NT treats not found as bad param... yet another bad choice */
+ return WERR_INVALID_PARAM;
+ }
+
+ ret = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(ret)) {
+ SAFE_FREE(queue);
+ return ret;
+ }
+
+ fill_job_info_2(info_2, &(queue[i-1]), i, snum, ntprinter);
+
+ free_a_printer(&ntprinter, 2);
+ SAFE_FREE(queue);
+
+ *needed += spoolss_size_job_info_2(info_2);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ SAFE_FREE(info_2);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ smb_io_job_info_2("", buffer, info_2, 0);
+
+ free_job_info_2(info_2);
+ SAFE_FREE(info_2);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+
+ return WERR_OK;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 jobid = q_u->jobid;
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ int snum;
+ int count;
+ print_queue_struct *queue=NULL;
+ print_status_struct prt_status;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("spoolss_getjob\n"));
+
+ *needed=0;
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ count = print_queue_status(snum, &queue, &prt_status);
+
+ DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
+ count, prt_status.status, prt_status.message));
+
+ switch (level) {
+ case 1:
+ return getjob_level_1(queue, count, snum, jobid, buffer, offered, needed);
+ case 2:
+ return getjob_level_2(queue, count, snum, jobid, buffer, offered, needed);
+ default:
+ SAFE_FREE(queue);
+ return WERR_UNKNOWN_LEVEL;
+ }
+}
+
+/********************************************************************
+ * spoolss_getprinterdataex
+ ********************************************************************/
+
+WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 in_size = q_u->size;
+ uint32 *type = &r_u->type;
+ uint32 *out_size = &r_u->size;
+ uint8 **data = &r_u->data;
+ uint32 *needed = &r_u->needed;
+
+ fstring key, value;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ BOOL found = False;
+
+ DEBUG(4,("_spoolss_getprinterdataex\n"));
+
+ unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1);
+ unistr2_to_ascii(value, &q_u->valuename, sizeof(value) - 1);
+
+ /* in case of problem, return some default values */
+ *needed=0;
+ *type=0;
+ *out_size=0;
+
+
+ if (!Printer) {
+ if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+ DEBUG(0,("_spoolss_getprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+
+ /* Is the handle to a printer or to the server? */
+
+ if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+ {
+ DEBUG(10,("_spoolss_getprinterdatex: Not implemented for server handles yet\n"));
+ return WERR_INVALID_PARAM;
+ }
+ else
+ {
+ /*
+ * From MSDN documentation of GetPrinterDataEx: pass request
+ * to GetPrinterData if key is "PrinterDriverData". This is
+ * the only key we really support. Other keys to implement:
+ * (a) DsDriver
+ * (b) DsSpooler
+ * (c) PnPData
+ */
+
+ if (strcmp(key, "PrinterDriverData") != 0)
+ return WERR_INVALID_PARAM;
+
+ DEBUG(10, ("_spoolss_getprinterdataex: pass me to getprinterdata\n"));
+ found = getprinterdata_printer(p, p->mem_ctx, handle, value,
+ type, data, needed, in_size);
+
+ }
+
+ if (!found) {
+ DEBUG(5, ("value not found, allocating %d\n", *out_size));
+
+ /* reply this param doesn't exist */
+ if (*out_size) {
+ if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+ } else {
+ *data = NULL;
+ }
+
+ return WERR_INVALID_PARAM;
+ }
+
+ if (*needed > *out_size)
+ return WERR_MORE_DATA;
+ else
+ return WERR_OK;
+}
+
+/********************************************************************
+ * spoolss_setprinterdata
+ ********************************************************************/
+
+WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u)
+{
+ SPOOL_Q_SETPRINTERDATA q_u_local;
+ SPOOL_R_SETPRINTERDATA r_u_local;
+ fstring key;
+
+ DEBUG(4,("_spoolss_setprinterdataex\n"));
+
+ /* From MSDN documentation of SetPrinterDataEx: pass request to
+ SetPrinterData if key is "PrinterDriverData" */
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+
+ if (strcmp(key, "PrinterDriverData") == 0)
+ return WERR_INVALID_PARAM;
+
+ ZERO_STRUCT(q_u_local);
+ ZERO_STRUCT(r_u_local);
+
+ /* make a copy to call _spoolss_setprinterdata() */
+
+ memcpy(&q_u_local.handle, &q_u->handle, sizeof(POLICY_HND));
+ copy_unistr2(&q_u_local.value, &q_u->value);
+ q_u_local.type = q_u->type;
+ q_u_local.max_len = q_u->max_len;
+ q_u_local.data = q_u->data;
+ q_u_local.real_len = q_u->real_len;
+ q_u_local.numeric_data = q_u->numeric_data;
+
+ return _spoolss_setprinterdata(p, &q_u_local, &r_u_local);
+}
+
+/********************************************************************
+ * spoolss_enumprinterkey
+ ********************************************************************/
+
+/* constants for EnumPrinterKey() */
+#define ENUMERATED_KEY_SIZE 19
+
+WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u)
+{
+ fstring key;
+ uint16 enumkeys[ENUMERATED_KEY_SIZE+1];
+ char* ptr = NULL;
+ int i;
+ char *PrinterKey = "PrinterDriverData";
+
+ DEBUG(4,("_spoolss_enumprinterkey\n"));
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+
+ /*
+ * we only support enumating all keys (key == "")
+ * Of course, the only key we support is the "PrinterDriverData"
+ * key
+ */
+ if (strlen(key) == 0)
+ {
+ r_u->needed = ENUMERATED_KEY_SIZE *2;
+ if (q_u->size < r_u->needed)
+ return WERR_MORE_DATA;
+
+ ptr = PrinterKey;
+ for (i=0; i<ENUMERATED_KEY_SIZE-2; i++)
+ {
+ enumkeys[i] = (uint16)(*ptr);
+ ptr++;
+ }
+
+ /* tag of with 2 '\0's */
+ enumkeys[i++] = '\0';
+ enumkeys[i] = '\0';
+
+ if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, ENUMERATED_KEY_SIZE, enumkeys))
+ return WERR_BADFILE;
+
+ return WERR_OK;
+ }
+
+ /* The "PrinterDriverData" key should have no subkeys */
+ if (strcmp(key, PrinterKey) == 0)
+ {
+ r_u-> needed = 2;
+ if (q_u->size < r_u->needed)
+ return WERR_MORE_DATA;
+ enumkeys[0] = 0x0;
+ if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, 1, enumkeys))
+ return WERR_BADFILE;
+
+ return WERR_OK;
+ }
+
+
+ /* The return value for an unknown key is documented in MSDN
+ EnumPrinterKey description */
+ return WERR_BADFILE;
+}
+
+/********************************************************************
+ * spoolss_enumprinterdataex
+ ********************************************************************/
+
+WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_u, SPOOL_R_ENUMPRINTERDATAEX *r_u)
+{
+ POLICY_HND *handle = &q_u->handle;
+ uint32 in_size = q_u->size;
+ uint32 num_entries,
+ needed;
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ PRINTER_ENUM_VALUES *enum_values = NULL;
+ fstring key, value;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ int snum;
+ uint32 param_index,
+ data_len,
+ type;
+ WERROR result;
+ uint8 *data=NULL;
+
+
+ DEBUG(4,("_spoolss_enumprinterdataex\n"));
+
+ if (!Printer) {
+ DEBUG(0,("_spoolss_enumprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return WERR_BADFID;
+ }
+
+
+ /*
+ * The only key we support is "PrinterDriverData". This should return
+ > an array of all the key/value pairs returned by EnumPrinterDataSee
+ * _spoolss_getprinterdataex() for details --jerry
+ */
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+ if (strcmp(key, "PrinterDriverData") != 0)
+ {
+ DEBUG(10,("_spoolss_enumprinterdataex: Unknown keyname [%s]\n", key));
+ return WERR_INVALID_PARAM;
+ }
+
+
+ if (!get_printer_snum(p,handle, &snum))
+ return WERR_BADFID;
+
+ ZERO_STRUCT(printer);
+ result = get_a_printer(&printer, 2, lp_servicename(snum));
+ if (!W_ERROR_IS_OK(result))
+ return result;
+
+
+ /*
+ * loop through all params and build the array to pass
+ * back to the client
+ */
+ result = WERR_OK;
+ param_index = 0;
+ needed = 0;
+ num_entries = 0;
+
+ while (get_specific_param_by_index(*printer, 2, param_index, value, &data, &type, &data_len))
+ {
+ PRINTER_ENUM_VALUES *ptr;
+ uint32 add_len = 0;
+
+ DEBUG(10,("retrieved value number [%d] [%s]\n", num_entries, value));
+
+ if ((ptr=talloc_realloc(p->mem_ctx, enum_values, (num_entries+1) * sizeof(PRINTER_ENUM_VALUES))) == NULL)
+ {
+ DEBUG(0,("talloc_realloc failed to allocate more memory!\n"));
+ result = WERR_NOMEM;
+ goto done;
+ }
+ enum_values = ptr;
+
+ /* copy the data */
+ init_unistr(&enum_values[num_entries].valuename, value);
+ enum_values[num_entries].value_len = (strlen(value)+1) * 2;
+ enum_values[num_entries].type = type;
+
+ /*
+ * NULL terminate REG_SZ
+ * FIXME!!! We should not be correctly problems in the way
+ * we store PrinterData here. Need to investogate
+ * SetPrinterData[Ex] --jerry
+ */
+
+ if (type == REG_SZ) {
+ /* fix alignment if the string was stored
+ in a bizarre fashion */
+ if ((data_len % 2) == 0)
+ add_len = 2;
+ else
+ add_len = data_len % 2;
+ }
+
+ if (!(enum_values[num_entries].data=talloc_zero(p->mem_ctx, data_len+add_len))) {
+ DEBUG(0,("talloc_realloc failed to allocate more memory for data!\n"));
+ result = WERR_NOMEM;
+ goto done;
+ }
+ memcpy(enum_values[num_entries].data, data, data_len);
+ enum_values[num_entries].data_len = data_len + add_len;
+
+ /* keep track of the size of the array in bytes */
+
+ needed += spoolss_size_printer_enum_values(&enum_values[num_entries]);
+
+ num_entries++;
+ param_index++;
+ }
+
+ r_u->needed = needed;
+ r_u->returned = num_entries;
+
+ if (needed > in_size) {
+ result = WERR_MORE_DATA;
+ goto done;
+ }
+
+ /* copy data into the reply */
+
+ r_u->ctr.size = r_u->needed;
+ r_u->ctr.size_of_array = r_u->returned;
+ r_u->ctr.values = enum_values;
+
+
+
+done:
+ free_a_printer(&printer, 2);
+
+ return result;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+/* Disabled because it doesn't fix the bug I am looking at but it would be
+ a shame to throw away the code. -tpot */
+
+#if 0
+
+static void fill_printprocessordirectory_1(PRINTPROCESSOR_DIRECTORY_1 *info, char *name)
+{
+ init_unistr(&info->name, name);
+}
+
+static WERROR getprintprocessordirectory_level_1(UNISTR2 *name,
+ UNISTR2 *environment,
+ NEW_BUFFER *buffer,
+ uint32 offered,
+ uint32 *needed)
+{
+ pstring path;
+ pstring long_archi;
+ pstring short_archi;
+ PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
+
+ unistr2_to_ascii(long_archi, environment, sizeof(long_archi)-1);
+
+ if (get_short_archi(short_archi, long_archi)==False)
+ return WERR_INVALID_ENVIRONMENT;
+
+ if((info=(PRINTPROCESSOR_DIRECTORY_1 *)malloc(sizeof(PRINTPROCESSOR_DIRECTORY_1))) == NULL)
+ return WERR_NOMEM;
+
+ /* Not sure what to return here - are UNC names valid here?.
+ Windows returns the string: C:\WINNT\System32\spool\PRTPROCS\W32X86
+ which is pretty bogus for a RPC. */
+
+ slprintf(path, sizeof(path)-1, "\\\\%s\\print$\\%s", global_myname, short_archi);
+
+ DEBUG(4,("print processor directory: [%s]\n", path));
+
+ fill_printprocessordirectory_1(info, path);
+
+ *needed += spoolss_size_printprocessordirectory_info_1(info);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ safe_free(info);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ smb_io_printprocessordirectory_1("", buffer, info, 0);
+
+ safe_free(info);
+
+ if (*needed > offered)
+ return WERR_INSUFFICIENT_BUFFER;
+ else
+ return WERR_OK;
+}
+
+WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u)
+{
+ uint32 level = q_u->level;
+ NEW_BUFFER *buffer = NULL;
+ uint32 offered = q_u->offered;
+ uint32 *needed = &r_u->needed;
+
+ /* that's an [in out] buffer */
+ spoolss_move_buffer(q_u->buffer, &r_u->buffer);
+ buffer = r_u->buffer;
+
+ DEBUG(5,("_spoolss_getprintprocessordirectory\n"));
+
+ *needed=0;
+
+ switch(level) {
+ case 1:
+ return getprintprocessordirectory_level_1
+ (&q_u->name, &q_u->environment, buffer, offered, needed);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_ACCESS_DENIED;
+}
+
+#endif
diff --git a/source/rpc_server/srv_srvsvc.c b/source/rpc_server/srv_srvsvc.c
new file mode 100644
index 00000000000..35bacc3458d
--- /dev/null
+++ b/source/rpc_server/srv_srvsvc.c
@@ -0,0 +1,523 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface to the srvsvc pipe. */
+
+#include "includes.h"
+
+/*******************************************************************
+ api_srv_net_srv_get_info
+********************************************************************/
+
+static BOOL api_srv_net_srv_get_info(pipes_struct *p)
+{
+ SRV_Q_NET_SRV_GET_INFO q_u;
+ SRV_R_NET_SRV_GET_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net server get info */
+ if (!srv_io_q_net_srv_get_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _srv_net_srv_get_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if (!srv_io_r_net_srv_get_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_srv_net_srv_get_info
+********************************************************************/
+
+static BOOL api_srv_net_srv_set_info(pipes_struct *p)
+{
+ SRV_Q_NET_SRV_SET_INFO q_u;
+ SRV_R_NET_SRV_SET_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net server set info */
+ if (!srv_io_q_net_srv_set_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _srv_net_srv_set_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if (!srv_io_r_net_srv_set_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_srv_net_file_enum
+********************************************************************/
+
+static BOOL api_srv_net_file_enum(pipes_struct *p)
+{
+ SRV_Q_NET_FILE_ENUM q_u;
+ SRV_R_NET_FILE_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net file enum */
+ if (!srv_io_q_net_file_enum("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _srv_net_file_enum(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!srv_io_r_net_file_enum("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_srv_net_conn_enum
+********************************************************************/
+
+static BOOL api_srv_net_conn_enum(pipes_struct *p)
+{
+ SRV_Q_NET_CONN_ENUM q_u;
+ SRV_R_NET_CONN_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net server get enum */
+ if (!srv_io_q_net_conn_enum("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _srv_net_conn_enum(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if (!srv_io_r_net_conn_enum("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Enumerate sessions.
+********************************************************************/
+
+static BOOL api_srv_net_sess_enum(pipes_struct *p)
+{
+ SRV_Q_NET_SESS_ENUM q_u;
+ SRV_R_NET_SESS_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net server get enum */
+ if (!srv_io_q_net_sess_enum("", &q_u, data, 0))
+ return False;
+
+ /* construct reply. always indicate success */
+ r_u.status = _srv_net_sess_enum(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if (!srv_io_r_net_sess_enum("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to enumerate shares.
+********************************************************************/
+
+static BOOL api_srv_net_share_enum_all(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_ENUM q_u;
+ SRV_R_NET_SHARE_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server get enum. */
+ if(!srv_io_q_net_share_enum("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_enum_all: Failed to unmarshall SRV_Q_NET_SHARE_ENUM.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_enum_all(p, &q_u, &r_u);
+
+ if (!srv_io_r_net_share_enum("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_enum_all: Failed to marshall SRV_R_NET_SHARE_ENUM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to enumerate shares.
+********************************************************************/
+
+static BOOL api_srv_net_share_enum(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_ENUM q_u;
+ SRV_R_NET_SHARE_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server get enum. */
+ if(!srv_io_q_net_share_enum("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_enum: Failed to unmarshall SRV_Q_NET_SHARE_ENUM.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_enum(p, &q_u, &r_u);
+
+ if (!srv_io_r_net_share_enum("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_enum: Failed to marshall SRV_R_NET_SHARE_ENUM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to return share information.
+********************************************************************/
+
+static BOOL api_srv_net_share_get_info(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_GET_INFO q_u;
+ SRV_R_NET_SHARE_GET_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server get info. */
+ if(!srv_io_q_net_share_get_info("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_get_info: Failed to unmarshall SRV_Q_NET_SHARE_GET_INFO.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_get_info(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_share_get_info("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_get_info: Failed to marshall SRV_R_NET_SHARE_GET_INFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to set share information.
+********************************************************************/
+
+static BOOL api_srv_net_share_set_info(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_SET_INFO q_u;
+ SRV_R_NET_SHARE_SET_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server set info. */
+ if(!srv_io_q_net_share_set_info("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_set_info: Failed to unmarshall SRV_Q_NET_SHARE_SET_INFO.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_set_info(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_share_set_info("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_set_info: Failed to marshall SRV_R_NET_SHARE_SET_INFO.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to add share information.
+********************************************************************/
+
+static BOOL api_srv_net_share_add(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_ADD q_u;
+ SRV_R_NET_SHARE_ADD r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server add info. */
+ if(!srv_io_q_net_share_add("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_add: Failed to unmarshall SRV_Q_NET_SHARE_ADD.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_add(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_share_add("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_add: Failed to marshall SRV_R_NET_SHARE_ADD.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to delete share information.
+********************************************************************/
+
+static BOOL api_srv_net_share_del(pipes_struct *p)
+{
+ SRV_Q_NET_SHARE_DEL q_u;
+ SRV_R_NET_SHARE_DEL r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server del info. */
+ if(!srv_io_q_net_share_del("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_share_del: Failed to unmarshall SRV_Q_NET_SHARE_DEL.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_share_del(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_share_del("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_share_del: Failed to marshall SRV_R_NET_SHARE_DEL.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ api_srv_net_remote_tod
+********************************************************************/
+
+static BOOL api_srv_net_remote_tod(pipes_struct *p)
+{
+ SRV_Q_NET_REMOTE_TOD q_u;
+ SRV_R_NET_REMOTE_TOD r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net server get enum */
+ if(!srv_io_q_net_remote_tod("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _srv_net_remote_tod(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!srv_io_r_net_remote_tod("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ RPC to enumerate disks available on a server e.g. C:, D: ...
+*******************************************************************/
+
+static BOOL api_srv_net_disk_enum(pipes_struct *p)
+{
+ SRV_Q_NET_DISK_ENUM q_u;
+ SRV_R_NET_DISK_ENUM r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server disk enum. */
+ if(!srv_io_q_net_disk_enum("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_disk_enum: Failed to unmarshall SRV_Q_NET_DISK_ENUM.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_disk_enum(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_disk_enum("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_disk_enum: Failed to marshall SRV_R_NET_DISK_ENUM.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ NetValidateName (opnum 0x21)
+*******************************************************************/
+
+static BOOL api_srv_net_name_validate(pipes_struct *p)
+{
+ SRV_Q_NET_NAME_VALIDATE q_u;
+ SRV_R_NET_NAME_VALIDATE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net server disk enum. */
+ if(!srv_io_q_net_name_validate("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_name_validate: Failed to unmarshall SRV_Q_NET_NAME_VALIDATE.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_name_validate(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_name_validate("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_name_validate: Failed to marshall SRV_R_NET_NAME_VALIDATE.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ NetFileQuerySecdesc (opnum 0x27)
+*******************************************************************/
+
+static BOOL api_srv_net_file_query_secdesc(pipes_struct *p)
+{
+ SRV_Q_NET_FILE_QUERY_SECDESC q_u;
+ SRV_R_NET_FILE_QUERY_SECDESC r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net file get info from Win9x */
+ if(!srv_io_q_net_file_query_secdesc("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_file_query_secdesc: Failed to unmarshall SRV_Q_NET_FILE_QUERY_SECDESC.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_file_query_secdesc(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_file_query_secdesc("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_file_query_secdesc: Failed to marshall SRV_R_NET_FILE_QUERY_SECDESC.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ NetFileSetSecdesc (opnum 0x28)
+*******************************************************************/
+
+static BOOL api_srv_net_file_set_secdesc(pipes_struct *p)
+{
+ SRV_Q_NET_FILE_SET_SECDESC q_u;
+ SRV_R_NET_FILE_SET_SECDESC r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* Unmarshall the net file set info from Win9x */
+ if(!srv_io_q_net_file_set_secdesc("", &q_u, data, 0)) {
+ DEBUG(0,("api_srv_net_file_set_secdesc: Failed to unmarshall SRV_Q_NET_FILE_SET_SECDESC.\n"));
+ return False;
+ }
+
+ r_u.status = _srv_net_file_set_secdesc(p, &q_u, &r_u);
+
+ if(!srv_io_r_net_file_set_secdesc("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_srv_net_file_set_secdesc: Failed to marshall SRV_R_NET_FILE_SET_SECDESC.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+\PIPE\srvsvc commands
+********************************************************************/
+
+struct api_struct api_srv_cmds[] =
+{
+ { "SRV_NETCONNENUM" , SRV_NETCONNENUM , api_srv_net_conn_enum },
+ { "SRV_NETSESSENUM" , SRV_NETSESSENUM , api_srv_net_sess_enum },
+ { "SRV_NETSHAREENUM_ALL" , SRV_NETSHAREENUM_ALL , api_srv_net_share_enum_all },
+ { "SRV_NETSHAREENUM" , SRV_NETSHAREENUM , api_srv_net_share_enum },
+ { "SRV_NET_SHARE_ADD" , SRV_NET_SHARE_ADD , api_srv_net_share_add },
+ { "SRV_NET_SHARE_DEL" , SRV_NET_SHARE_DEL , api_srv_net_share_del },
+ { "SRV_NET_SHARE_GET_INFO", SRV_NET_SHARE_GET_INFO, api_srv_net_share_get_info },
+ { "SRV_NET_SHARE_SET_INFO", SRV_NET_SHARE_SET_INFO, api_srv_net_share_set_info },
+ { "SRV_NETFILEENUM" , SRV_NETFILEENUM , api_srv_net_file_enum },
+ { "SRV_NET_SRV_GET_INFO" , SRV_NET_SRV_GET_INFO , api_srv_net_srv_get_info },
+ { "SRV_NET_SRV_SET_INFO" , SRV_NET_SRV_SET_INFO , api_srv_net_srv_set_info },
+ { "SRV_NET_REMOTE_TOD" , SRV_NET_REMOTE_TOD , api_srv_net_remote_tod },
+ { "SRV_NET_DISK_ENUM" , SRV_NET_DISK_ENUM , api_srv_net_disk_enum },
+ { "SRV_NET_NAME_VALIDATE" , SRV_NET_NAME_VALIDATE , api_srv_net_name_validate},
+ { "SRV_NETFILEQUERYSECDESC",SRV_NETFILEQUERYSECDESC,api_srv_net_file_query_secdesc},
+ { "SRV_NETFILESETSECDESC" , SRV_NETFILESETSECDESC , api_srv_net_file_set_secdesc},
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+receives a srvsvc pipe and responds.
+********************************************************************/
+BOOL api_srvsvc_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_srvsvc_rpc", api_srv_cmds);
+}
diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c
new file mode 100644
index 00000000000..9fadba17dd0
--- /dev/null
+++ b/source/rpc_server/srv_srvsvc_nt.c
@@ -0,0 +1,1880 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the implementation of the srvsvc pipe. */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*******************************************************************
+ Fill in a share info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_1(pipes_struct *p, SRV_SHARE_INFO_1 *sh1, int snum)
+{
+ int len_net_name;
+ pstring net_name;
+ pstring remark;
+ uint32 type;
+
+ pstrcpy(net_name, lp_servicename(snum));
+ pstrcpy(remark, lp_comment(snum));
+ standard_sub_conn(p->conn, remark);
+ len_net_name = strlen(net_name);
+
+ /* work out the share type */
+ type = STYPE_DISKTREE;
+
+ if (lp_print_ok(snum))
+ type = STYPE_PRINTQ;
+ if (strequal("IPC$", net_name) || strequal("ADMIN$", net_name))
+ type = STYPE_IPC;
+ if (net_name[len_net_name] == '$')
+ type |= STYPE_HIDDEN;
+
+ init_srv_share_info1(&sh1->info_1, net_name, type, remark);
+ init_srv_share_info1_str(&sh1->info_1_str, net_name, remark);
+}
+
+/*******************************************************************
+ Fill in a share info level 2 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_2(pipes_struct *p, SRV_SHARE_INFO_2 *sh2, int snum)
+{
+ int len_net_name;
+ pstring net_name;
+ pstring remark;
+ pstring path;
+ pstring passwd;
+ uint32 type;
+
+ pstrcpy(net_name, lp_servicename(snum));
+ pstrcpy(remark, lp_comment(snum));
+ standard_sub_conn(p->conn, remark);
+ pstrcpy(path, "C:");
+ pstrcat(path, lp_pathname(snum));
+
+ /*
+ * Change / to \\ so that win2k will see it as a valid path. This was added to
+ * enable use of browsing in win2k add share dialog.
+ */
+
+ string_replace(path, '/', '\\');
+
+ pstrcpy(passwd, "");
+ len_net_name = strlen(net_name);
+
+ /* work out the share type */
+ type = STYPE_DISKTREE;
+
+ if (lp_print_ok(snum))
+ type = STYPE_PRINTQ;
+ if (strequal("IPC$", net_name) || strequal("ADMIN$", net_name))
+ type = STYPE_IPC;
+ if (net_name[len_net_name] == '$')
+ type |= STYPE_HIDDEN;
+
+ init_srv_share_info2(&sh2->info_2, net_name, type, remark, 0, 0xffffffff, 1, path, passwd);
+ init_srv_share_info2_str(&sh2->info_2_str, net_name, remark, path, passwd);
+}
+
+/*******************************************************************
+ What to do when smb.conf is updated.
+ ********************************************************************/
+
+static void smb_conf_updated(int msg_type, pid_t src, void *buf, size_t len)
+{
+ DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n"));
+ reload_services(False);
+}
+
+/*******************************************************************
+ Create the share security tdb.
+ ********************************************************************/
+
+static TDB_CONTEXT *share_tdb; /* used for share security descriptors */
+#define SHARE_DATABASE_VERSION 1
+
+BOOL share_info_db_init(void)
+{
+ static pid_t local_pid;
+ char *vstring = "INFO/version";
+
+ if (share_tdb && local_pid == sys_getpid()) return True;
+ share_tdb = tdb_open_log(lock_path("share_info.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!share_tdb) {
+ DEBUG(0,("Failed to open share info database %s (%s)\n",
+ lock_path("share_info.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(share_tdb, vstring);
+ if (tdb_fetch_int(share_tdb, vstring) != SHARE_DATABASE_VERSION) {
+ tdb_traverse(share_tdb, (tdb_traverse_func)tdb_delete, NULL);
+ tdb_store_int(share_tdb, vstring, SHARE_DATABASE_VERSION);
+ }
+ tdb_unlock_bystring(share_tdb, vstring);
+
+ message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated);
+
+ return True;
+}
+
+/*******************************************************************
+ Fake up a Everyone, full access as a default.
+ ********************************************************************/
+
+static SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, int snum, size_t *psize)
+{
+ extern DOM_SID global_sid_World;
+ extern struct generic_mapping file_generic_mapping;
+ SEC_ACCESS sa;
+ SEC_ACE ace;
+ SEC_ACL *psa = NULL;
+ SEC_DESC *psd = NULL;
+ uint32 def_access = GENERIC_ALL_ACCESS;
+
+ se_map_generic(&def_access, &file_generic_mapping);
+
+ init_sec_access(&sa, GENERIC_ALL_ACCESS | def_access );
+ init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
+
+ if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &ace)) != NULL) {
+ psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, psize);
+ }
+
+ if (!psd) {
+ DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n"));
+ return NULL;
+ }
+
+ return psd;
+}
+
+/*******************************************************************
+ Pull a security descriptor from the share tdb.
+ ********************************************************************/
+
+static SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize)
+{
+ prs_struct ps;
+ fstring key;
+ SEC_DESC *psd = NULL;
+
+ *psize = 0;
+
+ /* Fetch security descriptor from tdb */
+
+ slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum));
+
+ if (tdb_prs_fetch(share_tdb, key, &ps, ctx)!=0 ||
+ !sec_io_desc("get_share_security", &psd, &ps, 1)) {
+
+ DEBUG(4,("get_share_security: using default secdesc for %s\n", lp_servicename(snum) ));
+
+ return get_share_security_default(ctx, snum, psize);
+ }
+
+ if (psd)
+ *psize = sec_desc_size(psd);
+
+ prs_mem_free(&ps);
+ return psd;
+}
+
+/*******************************************************************
+ Store a security descriptor in the share db.
+ ********************************************************************/
+
+static BOOL set_share_security(TALLOC_CTX *ctx, const char *share_name, SEC_DESC *psd)
+{
+ prs_struct ps;
+ TALLOC_CTX *mem_ctx = NULL;
+ fstring key;
+ BOOL ret = False;
+
+ mem_ctx = talloc_init();
+ if (mem_ctx == NULL)
+ return False;
+
+ prs_init(&ps, (uint32)sec_desc_size(psd), mem_ctx, MARSHALL);
+
+ if (!sec_io_desc("share_security", &psd, &ps, 1)) {
+ goto out;
+ }
+
+ slprintf(key, sizeof(key)-1, "SECDESC/%s", share_name);
+
+ if (tdb_prs_store(share_tdb, key, &ps)==0) {
+ ret = True;
+ DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name ));
+ } else {
+ DEBUG(1,("set_share_security: Failed to store secdesc for %s\n", share_name ));
+ }
+
+ /* Free malloc'ed memory */
+
+ out:
+
+ prs_mem_free(&ps);
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return ret;
+}
+
+/*******************************************************************
+ Delete a security descriptor.
+********************************************************************/
+
+static BOOL delete_share_security(int snum)
+{
+ TDB_DATA kbuf;
+ fstring key;
+
+ slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum));
+ kbuf.dptr = key;
+ kbuf.dsize = strlen(key)+1;
+
+ if (tdb_delete(share_tdb, kbuf) != 0) {
+ DEBUG(0,("delete_share_security: Failed to delete entry for share %s\n",
+ lp_servicename(snum) ));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Map any generic bits to file specific bits.
+********************************************************************/
+
+void map_generic_share_sd_bits(SEC_DESC *psd)
+{
+ extern struct generic_mapping file_generic_mapping;
+ int i;
+ SEC_ACL *ps_dacl = NULL;
+
+ if (!psd)
+ return;
+
+ ps_dacl = psd->dacl;
+ if (!ps_dacl)
+ return;
+
+ for (i = 0; i < ps_dacl->num_aces; i++) {
+ SEC_ACE *psa = &ps_dacl->ace[i];
+ uint32 orig_mask = psa->info.mask;
+
+ se_map_generic(&psa->info.mask, &file_generic_mapping);
+ psa->info.mask |= orig_mask;
+ }
+}
+
+/*******************************************************************
+ Can this user access with share with the required permissions ?
+********************************************************************/
+
+BOOL share_access_check(connection_struct *conn, int snum, uint16 vuid, uint32 desired_access)
+{
+ uint32 granted;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ NT_USER_TOKEN *token = NULL;
+ user_struct *vuser = get_valid_user_struct(vuid);
+ BOOL ret = True;
+
+ mem_ctx = talloc_init();
+ if (mem_ctx == NULL)
+ return False;
+
+ psd = get_share_security(mem_ctx, snum, &sd_size);
+
+ if (!psd)
+ goto out;
+
+ if (vuser)
+ token = vuser->nt_user_token;
+ else
+ token = conn->nt_user_token;
+
+ ret = se_access_check(psd, token, desired_access, &granted, &status);
+
+ out:
+
+ talloc_destroy(mem_ctx);
+
+ return ret;
+}
+
+/*******************************************************************
+ Fill in a share info level 502 structure.
+ ********************************************************************/
+
+static void init_srv_share_info_502(pipes_struct *p, SRV_SHARE_INFO_502 *sh502, int snum)
+{
+ int len_net_name;
+ pstring net_name;
+ pstring remark;
+ pstring path;
+ pstring passwd;
+ uint32 type;
+ SEC_DESC *sd;
+ size_t sd_size;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+
+ ZERO_STRUCTP(sh502);
+
+ pstrcpy(net_name, lp_servicename(snum));
+ pstrcpy(remark, lp_comment(snum));
+ standard_sub_conn(p->conn, remark);
+ pstrcpy(path, "C:");
+ pstrcat(path, lp_pathname(snum));
+
+ /*
+ * Change / to \\ so that win2k will see it as a valid path. This was added to
+ * enable use of browsing in win2k add share dialog.
+ */
+
+ string_replace(path, '/', '\\');
+
+ pstrcpy(passwd, "");
+ len_net_name = strlen(net_name);
+
+ /* work out the share type */
+ type = STYPE_DISKTREE;
+
+ if (lp_print_ok(snum))
+ type = STYPE_PRINTQ;
+ if (strequal("IPC$", net_name))
+ type = STYPE_IPC;
+ if (net_name[len_net_name] == '$')
+ type |= STYPE_HIDDEN;
+
+ sd = get_share_security(ctx, snum, &sd_size);
+
+ init_srv_share_info502(&sh502->info_502, net_name, type, remark, 0, 0xffffffff, 1, path, passwd, sd, sd_size);
+ init_srv_share_info502_str(&sh502->info_502_str, &sh502->info_502, net_name, remark, path, passwd, sd, sd_size);
+}
+
+/***************************************************************************
+ Fill in a share info level 1005 structure.
+ ***************************************************************************/
+
+static void init_srv_share_info_1005(SRV_SHARE_INFO_1005* sh1005, int snum)
+{
+ sh1005->dfs_root_flag = 0;
+
+ if(lp_host_msdfs() && lp_msdfs_root(snum))
+ sh1005->dfs_root_flag = 3;
+}
+
+/*******************************************************************
+ True if it ends in '$'.
+ ********************************************************************/
+
+static BOOL is_admin_share(int snum)
+{
+ pstring net_name;
+
+ pstrcpy(net_name, lp_servicename(snum));
+ return (net_name[strlen(net_name)] == '$') ? True : False;
+}
+
+/*******************************************************************
+ Fill in a share info structure.
+ ********************************************************************/
+
+static BOOL init_srv_share_info_ctr(pipes_struct *p, SRV_SHARE_INFO_CTR *ctr,
+ uint32 info_level, uint32 *resume_hnd, uint32 *total_entries, BOOL all_shares)
+{
+ int num_entries = 0;
+ int num_services = lp_numservices();
+ int snum;
+ TALLOC_CTX *ctx = p->mem_ctx;
+
+ DEBUG(5,("init_srv_share_info_ctr\n"));
+
+ ZERO_STRUCTPN(ctr);
+
+ ctr->info_level = ctr->switch_value = info_level;
+ *resume_hnd = 0;
+
+ /* Count the number of entries. */
+ for (snum = 0; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_admin_share(snum)) )
+ num_entries++;
+ }
+
+ *total_entries = num_entries;
+ ctr->num_entries2 = ctr->num_entries = num_entries;
+ ctr->ptr_share_info = ctr->ptr_entries = 1;
+
+ if (!num_entries)
+ return True;
+
+ switch (info_level) {
+ case 1:
+ {
+ SRV_SHARE_INFO_1 *info1;
+ int i = 0;
+
+ info1 = talloc(ctx, num_entries * sizeof(SRV_SHARE_INFO_1));
+
+ for (snum = *resume_hnd; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_admin_share(snum)) ) {
+ init_srv_share_info_1(p, &info1[i++], snum);
+ }
+ }
+
+ ctr->share.info1 = info1;
+ break;
+ }
+
+ case 2:
+ {
+ SRV_SHARE_INFO_2 *info2;
+ int i = 0;
+
+ info2 = talloc(ctx, num_entries * sizeof(SRV_SHARE_INFO_2));
+
+ for (snum = *resume_hnd; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_admin_share(snum)) ) {
+ init_srv_share_info_2(p, &info2[i++], snum);
+ }
+ }
+
+ ctr->share.info2 = info2;
+ break;
+ }
+
+ case 502:
+ {
+ SRV_SHARE_INFO_502 *info502;
+ int i = 0;
+
+ info502 = talloc(ctx, num_entries * sizeof(SRV_SHARE_INFO_502));
+
+ for (snum = *resume_hnd; snum < num_services; snum++) {
+ if (lp_browseable(snum) && lp_snum_ok(snum) && (all_shares || !is_admin_share(snum)) ) {
+ init_srv_share_info_502(p, &info502[i++], snum);
+ }
+ }
+
+ ctr->share.info502 = info502;
+ break;
+ }
+
+ default:
+ DEBUG(5,("init_srv_share_info_ctr: unsupported switch value %d\n", info_level));
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Inits a SRV_R_NET_SHARE_ENUM structure.
+********************************************************************/
+
+static void init_srv_r_net_share_enum(pipes_struct *p, SRV_R_NET_SHARE_ENUM *r_n,
+ uint32 info_level, uint32 resume_hnd, BOOL all)
+{
+ DEBUG(5,("init_srv_r_net_share_enum: %d\n", __LINE__));
+
+ if (init_srv_share_info_ctr(p, &r_n->ctr, info_level,
+ &resume_hnd, &r_n->total_entries, all)) {
+ r_n->status = NT_STATUS_OK;
+ } else {
+ r_n->status = NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ init_enum_hnd(&r_n->enum_hnd, resume_hnd);
+}
+
+/*******************************************************************
+ Inits a SRV_R_NET_SHARE_GET_INFO structure.
+********************************************************************/
+
+static void init_srv_r_net_share_get_info(pipes_struct *p, SRV_R_NET_SHARE_GET_INFO *r_n,
+ char *share_name, uint32 info_level)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ int snum;
+
+ DEBUG(5,("init_srv_r_net_share_get_info: %d\n", __LINE__));
+
+ r_n->info.switch_value = info_level;
+
+ snum = find_service(share_name);
+
+ if (snum >= 0) {
+ switch (info_level) {
+ case 1:
+ init_srv_share_info_1(p, &r_n->info.share.info1, snum);
+ break;
+ case 2:
+ init_srv_share_info_2(p, &r_n->info.share.info2, snum);
+ break;
+ case 502:
+ init_srv_share_info_502(p, &r_n->info.share.info502, snum);
+ break;
+ case 1005:
+ init_srv_share_info_1005(&r_n->info.share.info1005, snum);
+ break;
+ default:
+ DEBUG(5,("init_srv_net_share_get_info: unsupported switch value %d\n", info_level));
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ } else {
+ status = NT_STATUS_BAD_NETWORK_NAME;
+ }
+
+ r_n->info.ptr_share_ctr = NT_STATUS_IS_OK(status) ? 1 : 0;
+ r_n->status = status;
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_sess_0_info(SESS_INFO_0 *se0, SESS_INFO_0_STR *str0, char *name)
+{
+ init_srv_sess_info0(se0, name);
+ init_srv_sess_info0_str(str0, name);
+}
+
+/*******************************************************************
+ fill in a sess info level 0 structure.
+ ********************************************************************/
+
+static void init_srv_sess_info_0(SRV_SESS_INFO_0 *ss0, uint32 *snum, uint32 *stot)
+{
+ uint32 num_entries = 0;
+ (*stot) = 1;
+
+ if (ss0 == NULL) {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("init_srv_sess_0_ss0\n"));
+
+ if (snum) {
+ for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) {
+ init_srv_sess_0_info(&ss0->info_0[num_entries],
+ &ss0->info_0_str[num_entries], "MACHINE");
+
+ /* move on to creating next session */
+ /* move on to creating next sess */
+ num_entries++;
+ }
+
+ ss0->num_entries_read = num_entries;
+ ss0->ptr_sess_info = num_entries > 0 ? 1 : 0;
+ ss0->num_entries_read2 = num_entries;
+
+ if ((*snum) >= (*stot)) {
+ (*snum) = 0;
+ }
+
+ } else {
+ ss0->num_entries_read = 0;
+ ss0->ptr_sess_info = 0;
+ ss0->num_entries_read2 = 0;
+ }
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_sess_1_info(SESS_INFO_1 *se1, SESS_INFO_1_STR *str1,
+ char *name, char *user,
+ uint32 num_opens,
+ uint32 open_time, uint32 idle_time,
+ uint32 usr_flgs)
+{
+ init_srv_sess_info1(se1 , name, user, num_opens, open_time, idle_time, usr_flgs);
+ init_srv_sess_info1_str(str1, name, user);
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_sess_info_1(SRV_SESS_INFO_1 *ss1, uint32 *snum, uint32 *stot)
+{
+ uint32 num_entries = 0;
+ (*stot) = 1;
+
+ if (ss1 == NULL) {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("init_srv_sess_1_ss1\n"));
+
+ if (snum) {
+ for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) {
+ init_srv_sess_1_info(&ss1->info_1[num_entries],
+ &ss1->info_1_str[num_entries],
+ "MACHINE", "dummy_user", 1, 10, 5, 0);
+
+ /* move on to creating next session */
+ /* move on to creating next sess */
+ num_entries++;
+ }
+
+ ss1->num_entries_read = num_entries;
+ ss1->ptr_sess_info = num_entries > 0 ? 1 : 0;
+ ss1->num_entries_read2 = num_entries;
+
+ if ((*snum) >= (*stot)) {
+ (*snum) = 0;
+ }
+
+ } else {
+ ss1->num_entries_read = 0;
+ ss1->ptr_sess_info = 0;
+ ss1->num_entries_read2 = 0;
+
+ (*stot) = 0;
+ }
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SESS_ENUM structure.
+********************************************************************/
+
+static NTSTATUS init_srv_sess_info_ctr(SRV_SESS_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DEBUG(5,("init_srv_sess_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value) {
+ case 0:
+ init_srv_sess_info_0(&(ctr->sess.info0), resume_hnd, total_entries);
+ ctr->ptr_sess_ctr = 1;
+ break;
+ case 1:
+ init_srv_sess_info_1(&(ctr->sess.info1), resume_hnd, total_entries);
+ ctr->ptr_sess_ctr = 1;
+ break;
+ default:
+ DEBUG(5,("init_srv_sess_info_ctr: unsupported switch value %d\n", switch_value));
+ (*resume_hnd) = 0;
+ (*total_entries) = 0;
+ ctr->ptr_sess_ctr = 0;
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SESS_ENUM structure.
+********************************************************************/
+
+static void init_srv_r_net_sess_enum(SRV_R_NET_SESS_ENUM *r_n,
+ uint32 resume_hnd, int sess_level, int switch_value)
+{
+ DEBUG(5,("init_srv_r_net_sess_enum: %d\n", __LINE__));
+
+ r_n->sess_level = sess_level;
+
+ if (sess_level == -1)
+ r_n->status = NT_STATUS_INVALID_INFO_CLASS;
+ else
+ r_n->status = init_srv_sess_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries);
+
+ if (NT_STATUS_IS_ERR(r_n->status))
+ resume_hnd = 0;
+
+ init_enum_hnd(&r_n->enum_hnd, resume_hnd);
+}
+
+/*******************************************************************
+ fill in a conn info level 0 structure.
+ ********************************************************************/
+
+static void init_srv_conn_info_0(SRV_CONN_INFO_0 *ss0, uint32 *snum, uint32 *stot)
+{
+ uint32 num_entries = 0;
+ (*stot) = 1;
+
+ if (ss0 == NULL) {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("init_srv_conn_0_ss0\n"));
+
+ if (snum) {
+ for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++) {
+
+ init_srv_conn_info0(&ss0->info_0[num_entries], (*stot));
+
+ /* move on to creating next connection */
+ /* move on to creating next conn */
+ num_entries++;
+ }
+
+ ss0->num_entries_read = num_entries;
+ ss0->ptr_conn_info = num_entries > 0 ? 1 : 0;
+ ss0->num_entries_read2 = num_entries;
+
+ if ((*snum) >= (*stot)) {
+ (*snum) = 0;
+ }
+
+ } else {
+ ss0->num_entries_read = 0;
+ ss0->ptr_conn_info = 0;
+ ss0->num_entries_read2 = 0;
+
+ (*stot) = 0;
+ }
+}
+
+/*******************************************************************
+ fill in a conn info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_conn_1_info(CONN_INFO_1 *se1, CONN_INFO_1_STR *str1,
+ uint32 id, uint32 type,
+ uint32 num_opens, uint32 num_users, uint32 open_time,
+ char *usr_name, char *net_name)
+{
+ init_srv_conn_info1(se1 , id, type, num_opens, num_users, open_time, usr_name, net_name);
+ init_srv_conn_info1_str(str1, usr_name, net_name);
+}
+
+/*******************************************************************
+ fill in a conn info level 1 structure.
+ ********************************************************************/
+
+static void init_srv_conn_info_1(SRV_CONN_INFO_1 *ss1, uint32 *snum, uint32 *stot)
+{
+ uint32 num_entries = 0;
+ (*stot) = 1;
+
+ if (ss1 == NULL) {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("init_srv_conn_1_ss1\n"));
+
+ if (snum) {
+ for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++) {
+ init_srv_conn_1_info(&ss1->info_1[num_entries],
+ &ss1->info_1_str[num_entries],
+ (*stot), 0x3, 1, 1, 3,"dummy_user", "IPC$");
+
+ /* move on to creating next connection */
+ /* move on to creating next conn */
+ num_entries++;
+ }
+
+ ss1->num_entries_read = num_entries;
+ ss1->ptr_conn_info = num_entries > 0 ? 1 : 0;
+ ss1->num_entries_read2 = num_entries;
+
+
+ if ((*snum) >= (*stot)) {
+ (*snum) = 0;
+ }
+
+ } else {
+ ss1->num_entries_read = 0;
+ ss1->ptr_conn_info = 0;
+ ss1->num_entries_read2 = 0;
+
+ (*stot) = 0;
+ }
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_CONN_ENUM structure.
+********************************************************************/
+
+static NTSTATUS init_srv_conn_info_ctr(SRV_CONN_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DEBUG(5,("init_srv_conn_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value) {
+ case 0:
+ init_srv_conn_info_0(&ctr->conn.info0, resume_hnd, total_entries);
+ ctr->ptr_conn_ctr = 1;
+ break;
+ case 1:
+ init_srv_conn_info_1(&ctr->conn.info1, resume_hnd, total_entries);
+ ctr->ptr_conn_ctr = 1;
+ break;
+ default:
+ DEBUG(5,("init_srv_conn_info_ctr: unsupported switch value %d\n", switch_value));
+ (*resume_hnd = 0);
+ (*total_entries) = 0;
+ ctr->ptr_conn_ctr = 0;
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_CONN_ENUM structure.
+********************************************************************/
+
+static void init_srv_r_net_conn_enum(SRV_R_NET_CONN_ENUM *r_n,
+ uint32 resume_hnd, int conn_level, int switch_value)
+{
+ DEBUG(5,("init_srv_r_net_conn_enum: %d\n", __LINE__));
+
+ r_n->conn_level = conn_level;
+ if (conn_level == -1)
+ r_n->status = NT_STATUS_INVALID_INFO_CLASS;
+ else
+ r_n->status = init_srv_conn_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries);
+
+ if (NT_STATUS_IS_ERR(r_n->status))
+ resume_hnd = 0;
+
+ init_enum_hnd(&r_n->enum_hnd, resume_hnd);
+}
+
+/*******************************************************************
+ fill in a file info level 3 structure.
+ ********************************************************************/
+
+static void init_srv_file_3_info(FILE_INFO_3 *fl3, FILE_INFO_3_STR *str3,
+ uint32 fnum, uint32 perms, uint32 num_locks,
+ char *path_name, char *user_name)
+{
+ init_srv_file_info3(fl3 , fnum, perms, num_locks, path_name, user_name);
+ init_srv_file_info3_str(str3, path_name, user_name);
+}
+
+/*******************************************************************
+ fill in a file info level 3 structure.
+ ********************************************************************/
+
+static void init_srv_file_info_3(SRV_FILE_INFO_3 *fl3, uint32 *fnum, uint32 *ftot)
+{
+ uint32 num_entries = 0;
+ (*ftot) = 1;
+
+ if (fl3 == NULL) {
+ (*fnum) = 0;
+ return;
+ }
+
+ DEBUG(5,("init_srv_file_3_fl3\n"));
+
+ for (; (*fnum) < (*ftot) && num_entries < MAX_FILE_ENTRIES; (*fnum)++) {
+ init_srv_file_3_info(&fl3->info_3[num_entries],
+ &fl3->info_3_str[num_entries],
+ (*fnum), 0x35, 0, "\\PIPE\\samr", "dummy user");
+
+ /* move on to creating next file */
+ num_entries++;
+ }
+
+ fl3->num_entries_read = num_entries;
+ fl3->ptr_file_info = num_entries > 0 ? 1 : 0;
+ fl3->num_entries_read2 = num_entries;
+
+ if ((*fnum) >= (*ftot)) {
+ (*fnum) = 0;
+ }
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_FILE_ENUM structure.
+********************************************************************/
+
+static NTSTATUS init_srv_file_info_ctr(SRV_FILE_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ DEBUG(5,("init_srv_file_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value) {
+ case 3:
+ init_srv_file_info_3(&ctr->file.info3, resume_hnd, total_entries);
+ ctr->ptr_file_ctr = 1;
+ break;
+ default:
+ DEBUG(5,("init_srv_file_info_ctr: unsupported switch value %d\n", switch_value));
+ (*resume_hnd = 0);
+ (*total_entries) = 0;
+ ctr->ptr_file_ctr = 0;
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_FILE_ENUM structure.
+********************************************************************/
+
+static void init_srv_r_net_file_enum(SRV_R_NET_FILE_ENUM *r_n,
+ uint32 resume_hnd, int file_level, int switch_value)
+{
+ DEBUG(5,("init_srv_r_net_file_enum: %d\n", __LINE__));
+
+ r_n->file_level = file_level;
+ if (file_level == 0)
+ r_n->status = NT_STATUS_INVALID_INFO_CLASS;
+ else
+ r_n->status = init_srv_file_info_ctr(r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries));
+
+ if (NT_STATUS_IS_ERR(r_n->status))
+ resume_hnd = 0;
+
+ init_enum_hnd(&r_n->enum_hnd, resume_hnd);
+}
+
+/*******************************************************************
+net server get info
+********************************************************************/
+
+NTSTATUS _srv_net_srv_get_info(pipes_struct *p, SRV_Q_NET_SRV_GET_INFO *q_u, SRV_R_NET_SRV_GET_INFO *r_u)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ SRV_INFO_CTR *ctr = (SRV_INFO_CTR *)talloc(p->mem_ctx, sizeof(SRV_INFO_CTR));
+
+ if (!ctr)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(ctr);
+
+ DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__));
+
+ switch (q_u->switch_value) {
+ case 102:
+ init_srv_info_102(&ctr->srv.sv102,
+ 500, global_myname,
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH),
+ lp_major_announce_version(), lp_minor_announce_version(),
+ lp_default_server_announce(),
+ 0xffffffff, /* users */
+ 0xf, /* disc */
+ 0, /* hidden */
+ 240, /* announce */
+ 3000, /* announce delta */
+ 100000, /* licenses */
+ "c:\\"); /* user path */
+ break;
+ case 101:
+ init_srv_info_101(&ctr->srv.sv101,
+ 500, global_myname,
+ lp_major_announce_version(), lp_minor_announce_version(),
+ lp_default_server_announce(),
+ string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ break;
+ case 100:
+ init_srv_info_100(&ctr->srv.sv100, 500, global_myname);
+ break;
+ default:
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ /* set up the net server get info structure */
+ init_srv_r_net_srv_get_info(r_u, q_u->switch_value, ctr, status);
+
+ DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+net server set info
+********************************************************************/
+
+NTSTATUS _srv_net_srv_set_info(pipes_struct *p, SRV_Q_NET_SRV_SET_INFO *q_u, SRV_R_NET_SRV_SET_INFO *r_u)
+{
+ /* NT gives "Windows NT error 0xc00000022" if we return
+ NT_STATUS_ACCESS_DENIED here so just pretend everything is OK. */
+
+ NTSTATUS status = NT_STATUS_OK;
+
+ DEBUG(5,("srv_net_srv_set_info: %d\n", __LINE__));
+
+ /* Set up the net server set info structure. */
+
+ init_srv_r_net_srv_set_info(r_u, 0x0, status);
+
+ DEBUG(5,("srv_net_srv_set_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+net file enum
+********************************************************************/
+
+NTSTATUS _srv_net_file_enum(pipes_struct *p, SRV_Q_NET_FILE_ENUM *q_u, SRV_R_NET_FILE_ENUM *r_u)
+{
+ r_u->ctr = (SRV_FILE_INFO_CTR *)talloc(p->mem_ctx, sizeof(SRV_FILE_INFO_CTR));
+ if (!r_u->ctr)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(r_u->ctr);
+
+ DEBUG(5,("srv_net_file_enum: %d\n", __LINE__));
+
+ /* set up the */
+ init_srv_r_net_file_enum(r_u,
+ get_enum_hnd(&q_u->enum_hnd),
+ q_u->file_level,
+ q_u->ctr->switch_value);
+
+ DEBUG(5,("srv_net_file_enum: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+net conn enum
+********************************************************************/
+
+NTSTATUS _srv_net_conn_enum(pipes_struct *p, SRV_Q_NET_CONN_ENUM *q_u, SRV_R_NET_CONN_ENUM *r_u)
+{
+ DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__));
+
+ r_u->ctr = (SRV_CONN_INFO_CTR *)talloc(p->mem_ctx, sizeof(SRV_CONN_INFO_CTR));
+ if (!r_u->ctr)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(r_u->ctr);
+
+ /* set up the */
+ init_srv_r_net_conn_enum(r_u,
+ get_enum_hnd(&q_u->enum_hnd),
+ q_u->conn_level,
+ q_u->ctr->switch_value);
+
+ DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+net sess enum
+********************************************************************/
+
+NTSTATUS _srv_net_sess_enum(pipes_struct *p, SRV_Q_NET_SESS_ENUM *q_u, SRV_R_NET_SESS_ENUM *r_u)
+{
+ DEBUG(5,("_srv_net_sess_enum: %d\n", __LINE__));
+
+ r_u->ctr = (SRV_SESS_INFO_CTR *)talloc(p->mem_ctx, sizeof(SRV_SESS_INFO_CTR));
+ if (!r_u->ctr)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(r_u->ctr);
+
+ /* set up the */
+ init_srv_r_net_sess_enum(r_u,
+ get_enum_hnd(&q_u->enum_hnd),
+ q_u->sess_level,
+ q_u->ctr->switch_value);
+
+ DEBUG(5,("_srv_net_sess_enum: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ Net share enum all.
+********************************************************************/
+
+NTSTATUS _srv_net_share_enum_all(pipes_struct *p, SRV_Q_NET_SHARE_ENUM *q_u, SRV_R_NET_SHARE_ENUM *r_u)
+{
+ DEBUG(5,("_srv_net_share_enum: %d\n", __LINE__));
+
+ /* Create the list of shares for the response. */
+ init_srv_r_net_share_enum(p, r_u,
+ q_u->ctr.info_level,
+ get_enum_hnd(&q_u->enum_hnd), True);
+
+ DEBUG(5,("_srv_net_share_enum: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ Net share enum.
+********************************************************************/
+
+NTSTATUS _srv_net_share_enum(pipes_struct *p, SRV_Q_NET_SHARE_ENUM *q_u, SRV_R_NET_SHARE_ENUM *r_u)
+{
+ DEBUG(5,("_srv_net_share_enum: %d\n", __LINE__));
+
+ /* Create the list of shares for the response. */
+ init_srv_r_net_share_enum(p, r_u,
+ q_u->ctr.info_level,
+ get_enum_hnd(&q_u->enum_hnd), False);
+
+ DEBUG(5,("_srv_net_share_enum: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ Net share get info.
+********************************************************************/
+
+NTSTATUS _srv_net_share_get_info(pipes_struct *p, SRV_Q_NET_SHARE_GET_INFO *q_u, SRV_R_NET_SHARE_GET_INFO *r_u)
+{
+ fstring share_name;
+
+ DEBUG(5,("_srv_net_share_get_info: %d\n", __LINE__));
+
+ /* Create the list of shares for the response. */
+ unistr2_to_ascii(share_name, &q_u->uni_share_name, sizeof(share_name));
+ init_srv_r_net_share_get_info(p, r_u, share_name, q_u->info_level);
+
+ DEBUG(5,("_srv_net_share_get_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/*******************************************************************
+ Check a given DOS pathname is valid for a share.
+********************************************************************/
+
+static char *valid_share_pathname(char *dos_pathname)
+{
+ pstring saved_pathname;
+ pstring unix_pathname;
+ char *ptr;
+ int ret;
+
+ /* Convert any '\' paths to '/' */
+ unix_format(dos_pathname);
+ unix_clean_name(dos_pathname);
+
+ /* NT is braindead - it wants a C: prefix to a pathname ! So strip it. */
+ ptr = dos_pathname;
+ if (strlen(dos_pathname) > 2 && ptr[1] == ':' && ptr[0] != '/')
+ ptr += 2;
+
+ /* Only abolute paths allowed. */
+ if (*ptr != '/')
+ return NULL;
+
+ /* Can we cd to it ? */
+
+ /* First save our current directory. */
+ if (getcwd(saved_pathname, sizeof(saved_pathname)) == NULL)
+ return False;
+
+ pstrcpy(unix_pathname, ptr);
+
+ ret = chdir(unix_pathname);
+
+ /* We *MUST* be able to chdir back. Abort if we can't. */
+ if (chdir(saved_pathname) == -1)
+ smb_panic("valid_share_pathname: Unable to restore current directory.\n");
+
+ return (ret != -1) ? ptr : NULL;
+}
+
+/*******************************************************************
+ Net share set info. Modify share details.
+********************************************************************/
+
+NTSTATUS _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, SRV_R_NET_SHARE_SET_INFO *r_u)
+{
+ struct current_user user;
+ pstring command;
+ fstring share_name;
+ fstring comment;
+ pstring pathname;
+ int type;
+ int snum;
+ int ret;
+ char *ptr;
+ SEC_DESC *psd = NULL;
+
+ DEBUG(5,("_srv_net_share_set_info: %d\n", __LINE__));
+
+ unistr2_to_ascii(share_name, &q_u->uni_share_name, sizeof(share_name));
+
+ r_u->switch_value = 0;
+
+ if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global"))
+ return NT_STATUS_ACCESS_DENIED;
+
+ snum = find_service(share_name);
+
+ /* Does this share exist ? */
+ if (snum < 0)
+ return NT_STATUS_BAD_NETWORK_NAME;
+
+ /* No change to printer shares. */
+ if (lp_print_ok(snum))
+ return NT_STATUS_ACCESS_DENIED;
+
+ get_current_user(&user,p);
+
+ if (user.uid != 0)
+ return NT_STATUS_ACCESS_DENIED;
+
+ switch (q_u->info_level) {
+ case 1:
+ /* Not enough info in a level 1 to do anything. */
+ return NT_STATUS_ACCESS_DENIED;
+ case 2:
+ unistr2_to_ascii(comment, &q_u->info.share.info2.info_2_str.uni_remark, sizeof(share_name));
+ unistr2_to_ascii(pathname, &q_u->info.share.info2.info_2_str.uni_path, sizeof(share_name));
+ type = q_u->info.share.info2.info_2.type;
+ psd = NULL;
+ break;
+ case 502:
+ unistr2_to_ascii(comment, &q_u->info.share.info502.info_502_str.uni_remark, sizeof(share_name));
+ unistr2_to_ascii(pathname, &q_u->info.share.info502.info_502_str.uni_path, sizeof(share_name));
+ type = q_u->info.share.info502.info_502.type;
+ psd = q_u->info.share.info502.info_502_str.sd;
+ map_generic_share_sd_bits(psd);
+ break;
+ case 1005:
+ return NT_STATUS_ACCESS_DENIED;
+ case 1501:
+ fstrcpy(pathname, lp_pathname(snum));
+ fstrcpy(comment, lp_comment(snum));
+ psd = q_u->info.share.info1501.sdb->sec;
+ map_generic_share_sd_bits(psd);
+ type = STYPE_DISKTREE;
+ break;
+ default:
+ DEBUG(5,("_srv_net_share_set_info: unsupported switch value %d\n", q_u->info_level));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* We can only modify disk shares. */
+ if (type != STYPE_DISKTREE)
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Check if the pathname is valid. */
+ if (!(ptr = valid_share_pathname( pathname )))
+ return NT_STATUS_OBJECT_PATH_INVALID;
+
+ /* Ensure share name, pathname and comment don't contain '"' characters. */
+ string_replace(share_name, '"', ' ');
+ string_replace(ptr, '"', ' ');
+ string_replace(comment, '"', ' ');
+
+ DEBUG(10,("_srv_net_share_set_info: change share command = %s\n",
+ lp_change_share_cmd() ? lp_change_share_cmd() : "NULL" ));
+
+ /* Only call modify function if something changed. */
+
+ if (strcmp(ptr, lp_pathname(snum)) || strcmp(comment, lp_comment(snum)) ) {
+ if (!lp_change_share_cmd() || !*lp_change_share_cmd())
+ return NT_STATUS_ACCESS_DENIED;
+
+ slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
+ lp_change_share_cmd(), dyn_CONFIGFILE, share_name, ptr, comment);
+
+ DEBUG(10,("_srv_net_share_set_info: Running [%s]\n", command ));
+ if ((ret = smbrun(command, NULL)) != 0) {
+ DEBUG(0,("_srv_net_share_set_info: Running [%s] returned (%d)\n", command, ret ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False);
+
+ } else {
+ DEBUG(10,("_srv_net_share_set_info: No change to share name (%s)\n", share_name ));
+ }
+
+ /* Replace SD if changed. */
+ if (psd) {
+ SEC_DESC *old_sd;
+ size_t sd_size;
+
+ old_sd = get_share_security(p->mem_ctx, snum, &sd_size);
+
+ if (old_sd && !sec_desc_equal(old_sd, psd)) {
+ if (!set_share_security(p->mem_ctx, share_name, psd))
+ DEBUG(0,("_srv_net_share_set_info: Failed to change security info in share %s.\n",
+ share_name ));
+ }
+ }
+
+ DEBUG(5,("_srv_net_share_set_info: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Net share add. Call 'add_share_command "sharename" "pathname" "comment" "read only = xxx"'
+********************************************************************/
+
+NTSTATUS _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_SHARE_ADD *r_u)
+{
+ struct current_user user;
+ pstring command;
+ fstring share_name;
+ fstring comment;
+ pstring pathname;
+ int type;
+ int snum;
+ int ret;
+ char *ptr;
+ SEC_DESC *psd = NULL;
+
+ DEBUG(5,("_srv_net_share_add: %d\n", __LINE__));
+
+ r_u->switch_value = 0;
+
+ get_current_user(&user,p);
+
+ if (user.uid != 0) {
+ DEBUG(10,("_srv_net_share_add: uid != 0. Access denied.\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!lp_add_share_cmd() || !*lp_add_share_cmd()) {
+ DEBUG(10,("_srv_net_share_add: No add share command\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ switch (q_u->info_level) {
+ case 1:
+ /* Not enough info in a level 1 to do anything. */
+ return NT_STATUS_ACCESS_DENIED;
+ case 2:
+ unistr2_to_ascii(share_name, &q_u->info.share.info2.info_2_str.uni_netname, sizeof(share_name));
+ unistr2_to_ascii(comment, &q_u->info.share.info2.info_2_str.uni_remark, sizeof(share_name));
+ unistr2_to_ascii(pathname, &q_u->info.share.info2.info_2_str.uni_path, sizeof(share_name));
+ type = q_u->info.share.info2.info_2.type;
+ break;
+ case 502:
+ unistr2_to_ascii(share_name, &q_u->info.share.info502.info_502_str.uni_netname, sizeof(share_name));
+ unistr2_to_ascii(comment, &q_u->info.share.info502.info_502_str.uni_remark, sizeof(share_name));
+ unistr2_to_ascii(pathname, &q_u->info.share.info502.info_502_str.uni_path, sizeof(share_name));
+ type = q_u->info.share.info502.info_502.type;
+ psd = q_u->info.share.info502.info_502_str.sd;
+ map_generic_share_sd_bits(psd);
+ break;
+ case 1005:
+ /* DFS only level. */
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ DEBUG(5,("_srv_net_share_add: unsupported switch value %d\n", q_u->info_level));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global"))
+ return NT_STATUS_ACCESS_DENIED;
+
+ snum = find_service(share_name);
+
+ /* Share already exists. */
+ if (snum >= 0)
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+
+ /* We can only add disk shares. */
+ if (type != STYPE_DISKTREE)
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* Check if the pathname is valid. */
+ if (!(ptr = valid_share_pathname( pathname )))
+ return NT_STATUS_OBJECT_PATH_INVALID;
+
+ /* Ensure share name, pathname and comment don't contain '"' characters. */
+ string_replace(share_name, '"', ' ');
+ string_replace(ptr, '"', ' ');
+ string_replace(comment, '"', ' ');
+
+ slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
+ lp_add_share_cmd(), dyn_CONFIGFILE, share_name, ptr, comment);
+
+ DEBUG(10,("_srv_net_share_add: Running [%s]\n", command ));
+ if ((ret = smbrun(command, NULL)) != 0) {
+ DEBUG(0,("_srv_net_share_add: Running [%s] returned (%d)\n", command, ret ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (psd) {
+ if (!set_share_security(p->mem_ctx, share_name, psd))
+ DEBUG(0,("_srv_net_share_add: Failed to add security info to share %s.\n",
+ share_name ));
+ }
+
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False);
+
+ /*
+ * We don't call reload_services() here, the message will
+ * cause this to be done before the next packet is read
+ * from the client. JRA.
+ */
+
+ DEBUG(5,("_srv_net_share_add: %d\n", __LINE__));
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Net share delete. Call "delete share command" with the share name as
+ a parameter.
+********************************************************************/
+
+NTSTATUS _srv_net_share_del(pipes_struct *p, SRV_Q_NET_SHARE_DEL *q_u, SRV_R_NET_SHARE_DEL *r_u)
+{
+ struct current_user user;
+ pstring command;
+ fstring share_name;
+ int ret;
+ int snum;
+
+ DEBUG(5,("_srv_net_share_del: %d\n", __LINE__));
+
+ unistr2_to_ascii(share_name, &q_u->uni_share_name, sizeof(share_name));
+
+ if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global"))
+ return NT_STATUS_ACCESS_DENIED;
+
+ snum = find_service(share_name);
+
+ if (snum < 0)
+ return NT_STATUS_BAD_NETWORK_NAME;
+
+ /* No change to printer shares. */
+ if (lp_print_ok(snum))
+ return NT_STATUS_ACCESS_DENIED;
+
+ get_current_user(&user,p);
+
+ if (user.uid != 0)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!lp_delete_share_cmd() || !*lp_delete_share_cmd())
+ return NT_STATUS_ACCESS_DENIED;
+
+ slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
+ lp_delete_share_cmd(), dyn_CONFIGFILE, lp_servicename(snum));
+
+ DEBUG(10,("_srv_net_share_del: Running [%s]\n", command ));
+ if ((ret = smbrun(command, NULL)) != 0) {
+ DEBUG(0,("_srv_net_share_del: Running [%s] returned (%d)\n", command, ret ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Delete the SD in the database. */
+ delete_share_security(snum);
+
+ /* Tell everyone we updated smb.conf. */
+ message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False);
+
+ lp_killservice(snum);
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+time of day
+********************************************************************/
+
+NTSTATUS _srv_net_remote_tod(pipes_struct *p, SRV_Q_NET_REMOTE_TOD *q_u, SRV_R_NET_REMOTE_TOD *r_u)
+{
+ TIME_OF_DAY_INFO *tod;
+ struct tm *t;
+ time_t unixdate = time(NULL);
+
+ tod = (TIME_OF_DAY_INFO *)talloc(p->mem_ctx, sizeof(TIME_OF_DAY_INFO));
+ if (!tod)
+ return NT_STATUS_NO_MEMORY;
+
+ ZERO_STRUCTP(tod);
+
+ r_u->tod = tod;
+ r_u->ptr_srv_tod = 0x1;
+ r_u->status = NT_STATUS_OK;
+
+ DEBUG(5,("_srv_net_remote_tod: %d\n", __LINE__));
+
+ t = gmtime(&unixdate);
+
+ /* set up the */
+ init_time_of_day_info(tod,
+ unixdate,
+ 0,
+ t->tm_hour,
+ t->tm_min,
+ t->tm_sec,
+ 0,
+ TimeDiff(unixdate)/60,
+ 10000,
+ t->tm_mday,
+ t->tm_mon + 1,
+ 1900+t->tm_year,
+ t->tm_wday);
+
+ DEBUG(5,("_srv_net_remote_tod: %d\n", __LINE__));
+
+ return r_u->status;
+}
+
+/***********************************************************************************
+ Win9x NT tools get security descriptor.
+***********************************************************************************/
+
+NTSTATUS _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC *q_u,
+ SRV_R_NET_FILE_QUERY_SECDESC *r_u)
+{
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ DATA_BLOB null_pw;
+ pstring filename;
+ pstring qualname;
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ BOOL bad_path;
+ int access_mode;
+ int action;
+ NTSTATUS nt_status;
+ struct current_user user;
+ connection_struct *conn = NULL;
+ BOOL became_user = False;
+
+ ZERO_STRUCT(st);
+
+ r_u->status = NT_STATUS_OK;
+
+ unistr2_to_ascii(qualname, &q_u->uni_qual_name, sizeof(qualname));
+
+ /* Null password is ok - we are already an authenticated user... */
+ null_pw = data_blob(NULL, 0);
+
+ get_current_user(&user, p);
+
+ become_root();
+ conn = make_connection(qualname, null_pw, "A:", user.vuid, &nt_status);
+ unbecome_root();
+
+ if (conn == NULL) {
+ DEBUG(3,("_srv_net_file_query_secdesc: Unable to connect to %s\n", qualname));
+ r_u->status = nt_status;
+ goto error_exit;
+ }
+
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("_srv_net_file_query_secdesc: Can't become connected user!\n"));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+ became_user = True;
+
+ unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
+ unix_convert(filename, conn, NULL, &bad_path, &st);
+
+ fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &action);
+
+ if (!fsp) {
+ /* Perhaps it is a directory */
+ if (errno == EISDIR)
+ fsp = open_directory(conn, filename, &st,0,
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);
+
+ if (!fsp) {
+ DEBUG(3,("_srv_net_file_query_secdesc: Unable to open file %s\n", filename));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+ }
+
+ sd_size = conn->vfs_ops.get_nt_acl(fsp, fsp->fsp_name, &psd);
+
+ if (sd_size == 0) {
+ DEBUG(3,("_srv_net_file_query_secdesc: Unable to get NT ACL for file %s\n", filename));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ r_u->ptr_response = 1;
+ r_u->size_response = sd_size;
+ r_u->ptr_secdesc = 1;
+ r_u->size_secdesc = sd_size;
+ r_u->sec_desc = psd;
+
+ psd->dacl->revision = (uint16) NT4_ACL_REVISION;
+
+ close_file(fsp, True);
+ unbecome_user();
+ close_cnum(conn, user.vuid);
+ return r_u->status;
+
+ error_exit:
+
+ if(fsp) {
+ close_file(fsp, True);
+ }
+
+ if (became_user)
+ unbecome_user();
+
+ if (conn)
+ close_cnum(conn, user.vuid);
+
+ return r_u->status;
+}
+
+/***********************************************************************************
+ Win9x NT tools set security descriptor.
+***********************************************************************************/
+
+NTSTATUS _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_u,
+ SRV_R_NET_FILE_SET_SECDESC *r_u)
+{
+ BOOL ret;
+ DATA_BLOB null_pw;
+ pstring filename;
+ pstring qualname;
+ files_struct *fsp = NULL;
+ SMB_STRUCT_STAT st;
+ BOOL bad_path;
+ int access_mode;
+ int action;
+ NTSTATUS nt_status;
+ struct current_user user;
+ connection_struct *conn = NULL;
+ BOOL became_user = False;
+
+ ZERO_STRUCT(st);
+
+ r_u->status = NT_STATUS_OK;
+
+ unistr2_to_ascii(qualname, &q_u->uni_qual_name, sizeof(qualname));
+
+ /* Null password is ok - we are already an authenticated user... */
+ null_pw = data_blob(NULL, 0);
+
+ get_current_user(&user, p);
+
+ become_root();
+ conn = make_connection(qualname, null_pw, "A:", user.vuid, &nt_status);
+ unbecome_root();
+
+ if (conn == NULL) {
+ DEBUG(3,("_srv_net_file_set_secdesc: Unable to connect to %s\n", qualname));
+ r_u->status = nt_status;
+ goto error_exit;
+ }
+
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("_srv_net_file_set_secdesc: Can't become connected user!\n"));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+ became_user = True;
+
+ unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
+ unix_convert(filename, conn, NULL, &bad_path, &st);
+
+ fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &action);
+
+ if (!fsp) {
+ /* Perhaps it is a directory */
+ if (errno == EISDIR)
+ fsp = open_directory(conn, filename, &st,0,
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);
+
+ if (!fsp) {
+ DEBUG(3,("_srv_net_file_set_secdesc: Unable to open file %s\n", filename));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+ }
+
+ ret = conn->vfs_ops.set_nt_acl(fsp, fsp->fsp_name, q_u->sec_info, q_u->sec_desc);
+
+ if (ret == False) {
+ DEBUG(3,("_srv_net_file_set_secdesc: Unable to set NT ACL on file %s\n", filename));
+ r_u->status = NT_STATUS_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ close_file(fsp, True);
+ unbecome_user();
+ close_cnum(conn, user.vuid);
+ return r_u->status;
+
+ error_exit:
+
+ if(fsp) {
+ close_file(fsp, True);
+ }
+
+ if (became_user)
+ unbecome_user();
+
+ if (conn)
+ close_cnum(conn, user.vuid);
+
+ return r_u->status;
+}
+
+/***********************************************************************************
+ It may be that we want to limit users to creating shares on certain areas of the UNIX file area.
+ We could define areas by mapping Windows style disks to points on the UNIX directory hierarchy.
+ These disks would the disks listed by this function.
+ Users could then create shares relative to these disks. Watch out for moving these disks around.
+ "Nigel Williams" <nigel@veritas.com>.
+***********************************************************************************/
+
+const char *server_disks[] = {"C:"};
+
+static uint32 get_server_disk_count(void)
+{
+ return sizeof(server_disks)/sizeof(server_disks[0]);
+}
+
+static uint32 init_server_disk_enum(uint32 *resume)
+{
+ uint32 server_disk_count = get_server_disk_count();
+
+ /*resume can be an offset into the list for now*/
+
+ if(*resume & 0x80000000)
+ *resume = 0;
+
+ if(*resume > server_disk_count)
+ *resume = server_disk_count;
+
+ return server_disk_count - *resume;
+}
+
+static const char *next_server_disk_enum(uint32 *resume)
+{
+ const char *disk;
+
+ if(init_server_disk_enum(resume) == 0)
+ return NULL;
+
+ disk = server_disks[*resume];
+
+ (*resume)++;
+
+ DEBUG(10, ("next_server_disk_enum: reporting disk %s. resume handle %d.\n", disk, *resume));
+
+ return disk;
+}
+
+NTSTATUS _srv_net_disk_enum(pipes_struct *p, SRV_Q_NET_DISK_ENUM *q_u, SRV_R_NET_DISK_ENUM *r_u)
+{
+ uint32 i;
+ const char *disk_name;
+ uint32 resume=get_enum_hnd(&q_u->enum_hnd);
+
+ r_u->status=NT_STATUS_OK;
+
+ r_u->total_entries = init_server_disk_enum(&resume);
+
+ r_u->disk_enum_ctr.unknown = 0;
+
+ r_u->disk_enum_ctr.disk_info_ptr = (uint32) r_u->disk_enum_ctr.disk_info;
+
+ /*allow one DISK_INFO for null terminator*/
+
+ for(i = 0; i < MAX_SERVER_DISK_ENTRIES -1 && (disk_name = next_server_disk_enum(&resume)); i++) {
+
+ r_u->disk_enum_ctr.entries_read++;
+
+ /*copy disk name into a unicode string*/
+
+ init_unistr3(&r_u->disk_enum_ctr.disk_info[i].disk_name, disk_name);
+ }
+
+ /*add a terminating null string. Is this there if there is more data to come?*/
+
+ r_u->disk_enum_ctr.entries_read++;
+
+ init_unistr3(&r_u->disk_enum_ctr.disk_info[i].disk_name, "");
+
+ init_enum_hnd(&r_u->enum_hnd, resume);
+
+ return r_u->status;
+}
+
+NTSTATUS _srv_net_name_validate(pipes_struct *p, SRV_Q_NET_NAME_VALIDATE *q_u, SRV_R_NET_NAME_VALIDATE *r_u)
+{
+ int snum;
+ fstring share_name;
+
+ r_u->status=NT_STATUS_OK;
+
+ switch(q_u->type) {
+
+ case 0x9:
+
+ /*check if share name is ok*/
+ /*also check if we already have a share with this name*/
+
+ unistr2_to_ascii(share_name, &q_u->uni_name, sizeof(share_name));
+ snum = find_service(share_name);
+
+ /* Share already exists. */
+ if (snum >= 0)
+ r_u->status = NT_STATUS_OBJECT_NAME_INVALID;
+ break;
+
+ default:
+ /*unsupported type*/
+ r_u->status = NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return r_u->status;
+}
diff --git a/source/rpc_server/srv_util.c b/source/rpc_server/srv_util.c
new file mode 100644
index 00000000000..5c781c20ae7
--- /dev/null
+++ b/source/rpc_server/srv_util.c
@@ -0,0 +1,515 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this module apparently provides an implementation of DCE/RPC over a
+ * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC
+ * documentation are available (in on-line form) from the X-Open group.
+ *
+ * this module should provide a level of abstraction between SMB
+ * and DCE/RPC, while minimising the amount of mallocs, unnecessary
+ * data copies, and network traffic.
+ *
+ * in this version, which takes a "let's learn what's going on and
+ * get something running" approach, there is additional network
+ * traffic generated, but the code should be easier to understand...
+ *
+ * ... if you read the docs. or stare at packets for weeks on end.
+ *
+ */
+
+#include "includes.h"
+
+/*
+ * A list of the rids of well known BUILTIN and Domain users
+ * and groups.
+ */
+
+rid_name builtin_alias_rids[] =
+{
+ { BUILTIN_ALIAS_RID_ADMINS , "Administrators" },
+ { BUILTIN_ALIAS_RID_USERS , "Users" },
+ { BUILTIN_ALIAS_RID_GUESTS , "Guests" },
+ { BUILTIN_ALIAS_RID_POWER_USERS , "Power Users" },
+
+ { BUILTIN_ALIAS_RID_ACCOUNT_OPS , "Account Operators" },
+ { BUILTIN_ALIAS_RID_SYSTEM_OPS , "System Operators" },
+ { BUILTIN_ALIAS_RID_PRINT_OPS , "Print Operators" },
+ { BUILTIN_ALIAS_RID_BACKUP_OPS , "Backup Operators" },
+ { BUILTIN_ALIAS_RID_REPLICATOR , "Replicator" },
+ { 0 , NULL }
+};
+
+/* array lookup of well-known Domain RID users. */
+rid_name domain_user_rids[] =
+{
+ { DOMAIN_USER_RID_ADMIN , "Administrator" },
+ { DOMAIN_USER_RID_GUEST , "Guest" },
+ { 0 , NULL }
+};
+
+/* array lookup of well-known Domain RID groups. */
+rid_name domain_group_rids[] =
+{
+ { DOMAIN_GROUP_RID_ADMINS , "Domain Admins" },
+ { DOMAIN_GROUP_RID_USERS , "Domain Users" },
+ { DOMAIN_GROUP_RID_GUESTS , "Domain Guests" },
+ { 0 , NULL }
+};
+
+/*******************************************************************
+ gets a domain user's groups
+ ********************************************************************/
+NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, uint32 **prids, DOM_SID *q_sid)
+{
+ SAM_ACCOUNT *sam_pass=NULL;
+ char *sep;
+ struct sys_grent *glist;
+ struct sys_grent *grp;
+ int i, num, cur_rid=0;
+ gid_t *gid;
+ GROUP_MAP map;
+ DOM_SID tmp_sid;
+ fstring user_name;
+ fstring str_domsid, str_qsid;
+ uint32 rid,grid;
+ uint32 *rids=NULL, *new_rids=NULL;
+ BOOL ret;
+
+ /*
+ * this code is far from perfect.
+ * first it enumerates the full /etc/group and that can be slow.
+ * second, it works only with users' SIDs
+ * whereas the day we support nested groups, it will have to
+ * support both users's SIDs and domain groups' SIDs
+ *
+ * having our own ldap backend would be so much faster !
+ * we're far from that, but hope one day ;-) JFM.
+ */
+
+ *prids=NULL;
+ *numgroups=0;
+
+ sep = lp_winbind_separator();
+
+
+ DEBUG(10,("get_alias_user_groups: looking if SID %s is a member of groups in the SID domain %s\n",
+ sid_to_string(str_qsid, q_sid), sid_to_string(str_domsid, sid)));
+
+ sid_peek_rid(q_sid, &rid);
+
+ pdb_init_sam(&sam_pass);
+ become_root();
+ ret = pdb_getsampwrid(sam_pass, rid);
+ unbecome_root();
+ if (ret == False) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ fstrcpy(user_name, pdb_get_username(sam_pass));
+ grid=pdb_get_group_rid(sam_pass);
+ gid=pdb_get_gid(sam_pass);
+
+ grp = glist = getgrent_list();
+ if (grp == NULL) {
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (; grp != NULL; grp = grp->next) {
+ if(!get_group_from_gid(grp->gr_gid, &map, MAPPING_WITHOUT_PRIV)) {
+ DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)grp->gr_gid));
+ continue;
+ }
+
+ /* if it's not an alias, continue */
+ if (map.sid_name_use!=SID_NAME_ALIAS) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
+ continue;
+ }
+
+ sid_copy(&tmp_sid, &map.sid);
+ sid_split_rid(&tmp_sid, &rid);
+
+ /* if the sid is not in the correct domain, continue */
+ if (!sid_equal(&tmp_sid, sid)) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
+ continue;
+ }
+
+ /* Don't return winbind groups as they are not local! */
+ if (strchr_m(map.nt_name, *sep) != NULL) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name));
+ continue;
+ }
+
+ /* Don't return user private groups... */
+ if (Get_Pwnam(map.nt_name) != 0) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name));
+ continue;
+ }
+
+ /* the group is fine, we can check if there is the user we're looking for */
+ DEBUG(10,("get_alias_user_groups: checking if the user is a member of %s.\n", map.nt_name));
+
+ for(num=0; grp->gr_mem[num]!=NULL; num++) {
+ if(strcmp(grp->gr_mem[num], user_name)==0) {
+ /* we found the user, add the group to the list */
+
+ new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
+ if (new_rids==NULL) {
+ DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_MEMORY;
+ }
+ rids=new_rids;
+
+ sid_peek_rid(&map.sid, &(rids[cur_rid]));
+ DEBUG(10,("get_alias_user_groups: user found in group %s\n", map.nt_name));
+ cur_rid++;
+ break;
+ }
+ }
+ }
+
+ grent_free(glist);
+
+ /* now check for the user's gid (the primary group rid) */
+ for (i=0; i<cur_rid && grid!=rids[i]; i++)
+ ;
+
+ /* the user's gid is already there */
+ if (i!=cur_rid) {
+ DEBUG(10,("get_alias_user_groups: user is already in the list. good.\n"));
+ goto done;
+ }
+
+ DEBUG(10,("get_alias_user_groups: looking for gid %d of user %s\n", (int)*gid, user_name));
+
+ if(!get_group_from_gid(*gid, &map, MAPPING_WITHOUT_PRIV)) {
+ DEBUG(0,("get_alias_user_groups: gid of user %s doesn't exist. Check your /etc/passwd and /etc/group files\n", user_name));
+ goto done;
+ }
+
+ /* the primary group isn't an alias */
+ if (map.sid_name_use!=SID_NAME_ALIAS) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
+ goto done;
+ }
+
+ sid_copy(&tmp_sid, &map.sid);
+ sid_split_rid(&tmp_sid, &rid);
+
+ /* if the sid is not in the correct domain, continue */
+ if (!sid_equal(&tmp_sid, sid)) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
+ goto done;
+ }
+
+ /* Don't return winbind groups as they are not local! */
+ if (strchr_m(map.nt_name, *sep) != NULL) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name ));
+ goto done;
+ }
+
+ /* Don't return user private groups... */
+ if (Get_Pwnam(map.nt_name) != 0) {
+ DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name ));
+ goto done;
+ }
+
+ new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
+ if (new_rids==NULL) {
+ DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
+ pdb_free_sam(&sam_pass);
+ return NT_STATUS_NO_MEMORY;
+ }
+ rids=new_rids;
+
+ sid_peek_rid(&map.sid, &(rids[cur_rid]));
+ cur_rid++;
+
+done:
+ *prids=rids;
+ *numgroups=cur_rid;
+ pdb_free_sam(&sam_pass);
+
+ return NT_STATUS_OK;
+}
+
+
+/*******************************************************************
+ gets a domain user's groups
+ ********************************************************************/
+BOOL get_domain_user_groups(TALLOC_CTX *ctx, int *numgroups, DOM_GID **pgids, SAM_ACCOUNT *sam_pass)
+{
+ GROUP_MAP *map=NULL;
+ int i, num, num_entries, cur_gid=0;
+ struct group *grp;
+ DOM_GID *gids;
+ fstring user_name;
+ uint32 grid;
+ uint32 tmp_rid;
+
+ *numgroups=0;
+
+ fstrcpy(user_name, pdb_get_username(sam_pass));
+ grid=pdb_get_group_rid(sam_pass);
+
+ DEBUG(10,("get_domain_user_groups: searching domain groups [%s] is a member of\n", user_name));
+
+ /* first get the list of the domain groups */
+ if (!enum_group_mapping(SID_NAME_DOM_GRP, &map, &num_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV))
+ return False;
+ DEBUG(10,("get_domain_user_groups: there are %d mapped groups\n", num_entries));
+
+ /*
+ * alloc memory. In the worse case, we alloc memory for nothing.
+ * but I prefer to alloc for nothing
+ * than reallocing everytime.
+ */
+ gids = (DOM_GID *)talloc(ctx, sizeof(DOM_GID) * num_entries);
+
+ /* for each group, check if the user is a member of*/
+ for(i=0; i<num_entries; i++) {
+ if ((grp=getgrgid(map[i].gid)) == NULL) {
+ /* very weird !!! */
+ DEBUG(5,("get_domain_user_groups: gid %d doesn't exist anymore !\n", (int)map[i].gid));
+ continue;
+ }
+
+ for(num=0; grp->gr_mem[num]!=NULL; num++) {
+ if(strcmp(grp->gr_mem[num], user_name)==0) {
+ /* we found the user, add the group to the list */
+ sid_peek_rid(&map[i].sid, &(gids[cur_gid].g_rid));
+ gids[cur_gid].attr=7;
+ DEBUG(10,("get_domain_user_groups: user found in group %s\n", map[i].nt_name));
+ cur_gid++;
+ break;
+ }
+ }
+ }
+
+ /* we have checked the groups */
+ /* we must now check the gid of the user or the primary group rid, that's the same */
+ for (i=0; i<cur_gid && grid!=gids[i].g_rid; i++)
+ ;
+
+ /* the user's gid is already there */
+ if (i!=cur_gid) {
+ /*
+ * the primary group of the user but be the first one in the list
+ * don't ask ! JFM.
+ */
+ gids[i].g_rid=gids[0].g_rid;
+ gids[0].g_rid=grid;
+ goto done;
+ }
+
+ for(i=0; i<num_entries; i++) {
+ sid_peek_rid(&map[i].sid, &tmp_rid);
+ if (tmp_rid==grid) {
+ /*
+ * the primary group of the user but be the first one in the list
+ * don't ask ! JFM.
+ */
+ gids[cur_gid].g_rid=gids[0].g_rid;
+ gids[0].g_rid=tmp_rid;
+ gids[cur_gid].attr=7;
+ DEBUG(10,("get_domain_user_groups: primary gid of user found in group %s\n", map[i].nt_name));
+ cur_gid++;
+ goto done; /* leave the loop early */
+ }
+ }
+
+ DEBUG(0,("get_domain_user_groups: primary gid of user [%s] is not a Domain group !\n", user_name));
+ DEBUGADD(0,("get_domain_user_groups: You should fix it, NT doesn't like that\n"));
+
+ done:
+ *pgids=gids;
+ *numgroups=cur_gid;
+ safe_free(map);
+
+ return True;
+}
+
+/*******************************************************************
+ Look up a local (domain) rid and return a name and type.
+ ********************************************************************/
+NTSTATUS local_lookup_group_name(uint32 rid, char *group_name, uint32 *type)
+{
+ int i = 0;
+ (*type) = SID_NAME_DOM_GRP;
+
+ DEBUG(5,("lookup_group_name: rid: %d", rid));
+
+ while (domain_group_rids[i].rid != rid && domain_group_rids[i].rid != 0)
+ {
+ i++;
+ }
+
+ if (domain_group_rids[i].rid != 0)
+ {
+ fstrcpy(group_name, domain_group_rids[i].name);
+ DEBUG(5,(" = %s\n", group_name));
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ return NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ Look up a local alias rid and return a name and type.
+ ********************************************************************/
+NTSTATUS local_lookup_alias_name(uint32 rid, char *alias_name, uint32 *type)
+{
+ int i = 0;
+ (*type) = SID_NAME_WKN_GRP;
+
+ DEBUG(5,("lookup_alias_name: rid: %d", rid));
+
+ while (builtin_alias_rids[i].rid != rid && builtin_alias_rids[i].rid != 0)
+ {
+ i++;
+ }
+
+ if (builtin_alias_rids[i].rid != 0)
+ {
+ fstrcpy(alias_name, builtin_alias_rids[i].name);
+ DEBUG(5,(" = %s\n", alias_name));
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ return NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ Look up a local user rid and return a name and type.
+ ********************************************************************/
+NTSTATUS local_lookup_user_name(uint32 rid, char *user_name, uint32 *type)
+{
+ SAM_ACCOUNT *sampwd=NULL;
+ int i = 0;
+ BOOL ret;
+
+ (*type) = SID_NAME_USER;
+
+ DEBUG(5,("lookup_user_name: rid: %d", rid));
+
+ /* look up the well-known domain user rids first */
+ while (domain_user_rids[i].rid != rid && domain_user_rids[i].rid != 0)
+ {
+ i++;
+ }
+
+ if (domain_user_rids[i].rid != 0) {
+ fstrcpy(user_name, domain_user_rids[i].name);
+ DEBUG(5,(" = %s\n", user_name));
+ return NT_STATUS_OK;
+ }
+
+ pdb_init_sam(&sampwd);
+
+ /* ok, it's a user. find the user account */
+ become_root();
+ ret = pdb_getsampwrid(sampwd, rid);
+ unbecome_root();
+
+ if (ret == True) {
+ fstrcpy(user_name, pdb_get_username(sampwd) );
+ DEBUG(5,(" = %s\n", user_name));
+ pdb_free_sam(&sampwd);
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ pdb_free_sam(&sampwd);
+ return NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ Look up a local (domain) group name and return a rid
+ ********************************************************************/
+NTSTATUS local_lookup_group_rid(char *group_name, uint32 *rid)
+{
+ char *grp_name;
+ int i = -1; /* start do loop at -1 */
+
+ do /* find, if it exists, a group rid for the group name*/
+ {
+ i++;
+ (*rid) = domain_group_rids[i].rid;
+ grp_name = domain_group_rids[i].name;
+
+ } while (grp_name != NULL && !strequal(grp_name, group_name));
+
+ return (grp_name != NULL) ? NT_STATUS_OK : NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ Look up a local (BUILTIN) alias name and return a rid
+ ********************************************************************/
+NTSTATUS local_lookup_alias_rid(char *alias_name, uint32 *rid)
+{
+ char *als_name;
+ int i = -1; /* start do loop at -1 */
+
+ do /* find, if it exists, a alias rid for the alias name*/
+ {
+ i++;
+ (*rid) = builtin_alias_rids[i].rid;
+ als_name = builtin_alias_rids[i].name;
+
+ } while (als_name != NULL && !strequal(als_name, alias_name));
+
+ return (als_name != NULL) ? NT_STATUS_OK : NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ Look up a local user name and return a rid
+ ********************************************************************/
+NTSTATUS local_lookup_user_rid(char *user_name, uint32 *rid)
+{
+ SAM_ACCOUNT *sampass=NULL;
+ BOOL ret;
+
+ (*rid) = 0;
+
+ pdb_init_sam(&sampass);
+
+ /* find the user account */
+ become_root();
+ ret = pdb_getsampwnam(sampass, user_name);
+ unbecome_root();
+
+ if (ret == True) {
+ (*rid) = pdb_get_user_rid(sampass);
+ pdb_free_sam(&sampass);
+ return NT_STATUS_OK;
+ }
+
+ pdb_free_sam(&sampass);
+ return NT_STATUS_NONE_MAPPED;
+}
diff --git a/source/rpc_server/srv_wkssvc.c b/source/rpc_server/srv_wkssvc.c
new file mode 100644
index 00000000000..3661824da17
--- /dev/null
+++ b/source/rpc_server/srv_wkssvc.c
@@ -0,0 +1,71 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the interface to the wks pipe. */
+
+#include "includes.h"
+
+/*******************************************************************
+ api_wks_query_info
+ ********************************************************************/
+
+static BOOL api_wks_query_info(pipes_struct *p)
+{
+ WKS_Q_QUERY_INFO q_u;
+ WKS_R_QUERY_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the net share enum */
+ if(!wks_io_q_query_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _wks_query_info(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!wks_io_r_query_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ \PIPE\wkssvc commands
+ ********************************************************************/
+struct api_struct api_wks_cmds[] =
+{
+ { "WKS_Q_QUERY_INFO", WKS_QUERY_INFO, api_wks_query_info },
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+ receives a wkssvc pipe and responds.
+ ********************************************************************/
+BOOL api_wkssvc_rpc(pipes_struct *p)
+{
+ return api_rpcTNP(p, "api_wkssvc_rpc", api_wks_cmds);
+}
diff --git a/source/rpc_server/srv_wkssvc_nt.c b/source/rpc_server/srv_wkssvc_nt.c
new file mode 100644
index 00000000000..f618531b5f9
--- /dev/null
+++ b/source/rpc_server/srv_wkssvc_nt.c
@@ -0,0 +1,79 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This is the implementation of the wks interface. */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*******************************************************************
+ create_wks_info_100
+ ********************************************************************/
+
+static void create_wks_info_100(WKS_INFO_100 *inf)
+{
+ pstring my_name;
+ pstring domain;
+
+ DEBUG(5,("create_wks_info_100: %d\n", __LINE__));
+
+ pstrcpy (my_name, global_myname);
+ strupper(my_name);
+
+ pstrcpy (domain, lp_workgroup());
+ strupper(domain);
+
+ init_wks_info_100(inf,
+ 0x000001f4, /* platform id info */
+ lp_major_announce_version(),
+ lp_minor_announce_version(),
+ my_name, domain);
+}
+
+/*******************************************************************
+ wks_reply_query_info
+
+ only supports info level 100 at the moment.
+
+ ********************************************************************/
+
+NTSTATUS _wks_query_info(pipes_struct *p, WKS_Q_QUERY_INFO *q_u, WKS_R_QUERY_INFO *r_u)
+{
+ WKS_INFO_100 *wks100 = NULL;
+
+ DEBUG(5,("_wks_query_info: %d\n", __LINE__));
+
+ wks100 = (WKS_INFO_100 *)talloc_zero(p->mem_ctx, sizeof(WKS_INFO_100));
+
+ if (!wks100)
+ return NT_STATUS_NO_MEMORY;
+
+ create_wks_info_100(wks100);
+ init_wks_r_query_info(r_u, q_u->switch_value, wks100, NT_STATUS_OK);
+
+ DEBUG(5,("_wks_query_info: %d\n", __LINE__));
+
+ return r_u->status;
+}
diff --git a/source/rpcclient/cmd_dfs.c b/source/rpcclient/cmd_dfs.c
new file mode 100644
index 00000000000..78f68dcc86b
--- /dev/null
+++ b/source/rpcclient/cmd_dfs.c
@@ -0,0 +1,238 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Check DFS is supported by the remote server */
+
+static NTSTATUS cmd_dfs_exist(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ BOOL dfs_exists;
+ NTSTATUS result;
+
+ if (argc != 1) {
+ printf("Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_dfs_exist(cli, mem_ctx, &dfs_exists);
+
+ if (NT_STATUS_IS_OK(result))
+ printf("dfs is %spresent\n", dfs_exists ? "" : "not ");
+
+ return result;
+}
+
+static NTSTATUS cmd_dfs_add(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ char *entrypath, *servername, *sharename, *comment;
+ uint32 flags = 0;
+
+ if (argc != 5) {
+ printf("Usage: %s entrypath servername sharename comment\n",
+ argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ entrypath = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+ comment = argv[4];
+
+ result = cli_dfs_add(cli, mem_ctx, entrypath, servername,
+ sharename, comment, flags);
+
+ return result;
+}
+
+static NTSTATUS cmd_dfs_remove(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ char *entrypath, *servername, *sharename;
+
+ if (argc != 4) {
+ printf("Usage: %s entrypath servername sharename\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ entrypath = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+
+ result = cli_dfs_remove(cli, mem_ctx, entrypath, servername,
+ sharename);
+
+ return result;
+}
+
+/* Display a DFS_INFO_1 structure */
+
+static void display_dfs_info_1(DFS_INFO_1 *info1)
+{
+ fstring temp;
+
+ unistr2_to_ascii(temp, &info1->entrypath, sizeof(temp) - 1);
+ printf("entrypath: %s\n", temp);
+}
+
+/* Display a DFS_INFO_2 structure */
+
+static void display_dfs_info_2(DFS_INFO_2 *info2)
+{
+ fstring temp;
+
+ unistr2_to_ascii(temp, &info2->entrypath, sizeof(temp) - 1);
+ printf("entrypath: %s\n", temp);
+
+ unistr2_to_ascii(temp, &info2->comment, sizeof(temp) - 1);
+ printf("\tcomment: %s\n", temp);
+
+ printf("\tstate: %d\n", info2->state);
+ printf("\tnum_storages: %d\n", info2->num_storages);
+}
+
+/* Display a DFS_INFO_3 structure */
+
+static void display_dfs_info_3(DFS_INFO_3 *info3)
+{
+ fstring temp;
+ int i;
+
+ unistr2_to_ascii(temp, &info3->entrypath, sizeof(temp) - 1);
+ printf("entrypath: %s\n", temp);
+
+ unistr2_to_ascii(temp, &info3->comment, sizeof(temp) - 1);
+ printf("\tcomment: %s\n", temp);
+
+ printf("\tstate: %d\n", info3->state);
+ printf("\tnum_storages: %d\n", info3->num_storages);
+
+ for (i = 0; i < info3->num_storages; i++) {
+ DFS_STORAGE_INFO *dsi = &info3->storages[i];
+
+ unistr2_to_ascii(temp, &dsi->servername, sizeof(temp) - 1);
+ printf("\t\tstorage[%d] servername: %s\n", i, temp);
+
+ unistr2_to_ascii(temp, &dsi->sharename, sizeof(temp) - 1);
+ printf("\t\tstorage[%d] sharename: %s\n", i, temp);
+ }
+}
+
+/* Display a DFS_INFO_CTR structure */
+
+static void display_dfs_info_ctr(DFS_INFO_CTR *ctr)
+{
+ int i;
+
+ for (i = 0; i < ctr->num_entries; i++) {
+ switch (ctr->switch_value) {
+ case 0x01:
+ display_dfs_info_1(&ctr->dfs.info1[i]);
+ break;
+ case 0x02:
+ display_dfs_info_2(&ctr->dfs.info2[i]);
+ break;
+ case 0x03:
+ display_dfs_info_3(&ctr->dfs.info3[i]);
+ break;
+ default:
+ printf("unsupported info level %d\n",
+ ctr->switch_value);
+ break;
+ }
+ }
+}
+
+/* Enumerate dfs shares */
+
+static NTSTATUS cmd_dfs_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ DFS_INFO_CTR ctr;
+ NTSTATUS result;
+ uint32 info_level = 1;
+
+ if (argc > 2) {
+ printf("Usage: %s [info_level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ result = cli_dfs_enum(cli, mem_ctx, info_level, &ctr);
+
+ if (NT_STATUS_IS_OK(result))
+ display_dfs_info_ctr(&ctr);
+
+ return result;
+}
+
+static NTSTATUS cmd_dfs_getinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ char *entrypath, *servername, *sharename;
+ uint32 info_level = 1;
+ DFS_INFO_CTR ctr;
+
+ if (argc < 4 || argc > 5) {
+ printf("Usage: %s entrypath servername sharename "
+ "[info_level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ entrypath = argv[1];
+ servername = argv[2];
+ sharename = argv[3];
+
+ if (argc == 5)
+ info_level = atoi(argv[4]);
+
+ result = cli_dfs_get_info(cli, mem_ctx, entrypath, servername,
+ sharename, info_level, &ctr);
+
+ if (NT_STATUS_IS_OK(result))
+ display_dfs_info_ctr(&ctr);
+
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set dfs_commands[] = {
+
+ { "DFS" },
+
+ { "dfsexist", cmd_dfs_exist, PIPE_NETDFS, "Query DFS support", "" },
+ { "dfsadd", cmd_dfs_add, PIPE_NETDFS, "Add a DFS share", "" },
+ { "dfsremove", cmd_dfs_remove, PIPE_NETDFS, "Remove a DFS share", "" },
+ { "dfsgetinfo", cmd_dfs_getinfo, PIPE_NETDFS, "Query DFS share info", "" },
+ { "dfsenum", cmd_dfs_enum, PIPE_NETDFS, "Enumerate dfs shares", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_lsarpc.c b/source/rpcclient/cmd_lsarpc.c
new file mode 100644
index 00000000000..528987d3e20
--- /dev/null
+++ b/source/rpcclient/cmd_lsarpc.c
@@ -0,0 +1,510 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Look up domain related information on a remote host */
+
+static NTSTATUS cmd_lsa_query_info_policy(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID dom_sid;
+ fstring sid_str, domain_name;
+ uint32 info_class = 3;
+
+ if (argc > 2) {
+ printf("Usage: %s [info_class]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ info_class = atoi(argv[1]);
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Lookup info policy */
+
+ result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class,
+ domain_name, &dom_sid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ sid_to_string(sid_str, &dom_sid);
+
+ if (domain_name[0])
+ printf("domain %s has sid %s\n", domain_name, sid_str);
+ else
+ printf("could not query info for level %d\n", info_class);
+
+ done:
+ return result;
+}
+
+/* Resolve a list of names to a list of sids */
+
+static NTSTATUS cmd_lsa_lookup_names(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ uint32 *types;
+ int num_names, i;
+
+ if (argc == 1) {
+ printf("Usage: %s [name1 [name2 [...]]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Lookup the names */
+
+ result = cli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 1,
+ (const char **)&argv[1], &sids,
+ &types, &num_names);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ for (i = 0; i < num_names; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sids[i]);
+ printf("%s %s (%d)\n", argv[i + 1], sid_str,
+ types[i]);
+ }
+
+ done:
+ return result;
+}
+
+/* Resolve a list of SIDs to a list of names */
+
+static NTSTATUS cmd_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *sids;
+ char **names;
+ uint32 *types;
+ int num_names, i;
+
+ if (argc == 1) {
+ printf("Usage: %s [sid1 [sid2 [...]]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Convert arguments to sids */
+
+ sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * (argc - 1));
+
+ if (!sids) {
+ printf("could not allocate memory for %d sids\n", argc - 1);
+ goto done;
+ }
+
+ for (i = 0; i < argc - 1; i++)
+ string_to_sid(&sids[i], argv[i + 1]);
+
+ /* Lookup the SIDs */
+
+ result = cli_lsa_lookup_sids(cli, mem_ctx, &pol, argc - 1, sids,
+ &names, &types, &num_names);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ for (i = 0; i < num_names; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sids[i]);
+ printf("%s %s (%d)\n", sid_str, names[i] ? names[i] :
+ "*unknown*", types[i]);
+ }
+
+ done:
+ return result;
+}
+
+/* Enumerate list of trusted domains */
+
+static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_SID *domain_sids;
+ char **domain_names;
+ uint32 enum_ctx = 0;
+ uint32 num_domains;
+ int i;
+
+ if (argc != 1) {
+ printf("Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Lookup list of trusted domains */
+
+ result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
+ &num_domains, &domain_names,
+ &domain_sids);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ for (i = 0; i < num_domains; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &domain_sids[i]);
+ printf("%s %s\n", domain_names[i] ? domain_names[i] :
+ "*unknown*", sid_str);
+ }
+
+ done:
+ return result;
+}
+
+/* Enumerates privileges */
+
+static NTSTATUS cmd_lsa_enum_privilege(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ uint32 count=0;
+ char **privs_name;
+ uint32 *privs_high;
+ uint32 *privs_low;
+ int i;
+
+ if (argc > 3) {
+ printf("Usage: %s [enum context] [max length]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc>=2)
+ enum_context=atoi(argv[1]);
+
+ if (argc==3)
+ pref_max_length=atoi(argv[2]);
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_enum_privilege(cli, mem_ctx, &pol, &enum_context, pref_max_length,
+ &count, &privs_name, &privs_high, &privs_low);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d privileges\n\n", count);
+
+ for (i = 0; i < count; i++) {
+ printf("%s \t\t%d:%d (0x%x:0x%x)\n", privs_name[i] ? privs_name[i] : "*unknown*",
+ privs_high[i], privs_low[i], privs_high[i], privs_low[i]);
+ }
+
+ done:
+ return result;
+}
+
+/* Get privilege name */
+
+static NTSTATUS cmd_lsa_get_dispname(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ uint16 lang_id=0;
+ uint16 lang_id_sys=0;
+ uint16 lang_id_desc;
+ fstring description;
+
+ if (argc != 2) {
+ printf("Usage: %s privilege name\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_get_dispname(cli, mem_ctx, &pol, argv[1], lang_id, lang_id_sys, description, &lang_id_desc);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("%s -> %s (language: 0x%x)\n", argv[1], description, lang_id_desc);
+
+ done:
+ return result;
+}
+
+/* Enumerate the LSA SIDS */
+
+static NTSTATUS cmd_lsa_enum_sids(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ uint32 enum_context=0;
+ uint32 pref_max_length=0x1000;
+ DOM_SID *sids;
+ uint32 count=0;
+ int i;
+
+ if (argc > 3) {
+ printf("Usage: %s [enum context] [max length]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc>=2)
+ enum_context=atoi(argv[1]);
+
+ if (argc==3)
+ pref_max_length=atoi(argv[2]);
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_enum_sids(cli, mem_ctx, &pol, &enum_context, pref_max_length,
+ &count, &sids);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d SIDs\n\n", count);
+
+ for (i = 0; i < count; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &sids[i]);
+ printf("%s\n", sid_str);
+ }
+
+ done:
+ return result;
+}
+
+/* Enumerate the privileges of an SID */
+
+static NTSTATUS cmd_lsa_enum_privsaccounts(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND dom_pol;
+ POLICY_HND user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 access_desired = 0x000f000f;
+
+ DOM_SID sid;
+ uint32 count=0;
+ LUID_ATTR *set;
+ int i;
+
+ if (argc != 2 ) {
+ printf("Usage: %s SID\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ string_to_sid(&sid, argv[1]);
+
+ result = cli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &dom_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_open_account(cli, mem_ctx, &dom_pol, &sid, access_desired, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_enum_privsaccount(cli, mem_ctx, &user_pol, &count, &set);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("found %d privileges for SID %s\n\n", count, argv[1]);
+ printf("high\tlow\tattribute\n");
+
+ for (i = 0; i < count; i++) {
+ printf("%u\t%u\t%u\n", set[i].luid.high, set[i].luid.low, set[i].attr);
+ }
+
+ done:
+ return result;
+}
+
+/* Get a privilege value given its name */
+
+static NTSTATUS cmd_lsa_lookupprivvalue(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ LUID luid;
+
+ if (argc != 2 ) {
+ printf("Usage: %s name\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_lookupprivvalue(cli, mem_ctx, &pol, argv[1], &luid);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+ printf("%u:%u (0x%x:0x%x)\n", luid.high, luid.low, luid.high, luid.low);
+
+ done:
+ return result;
+}
+
+/* Query LSA security object */
+
+static NTSTATUS cmd_lsa_query_secobj(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ SEC_DESC_BUF *sdb;
+ uint32 sec_info = 0x00000004; /* ??? */
+
+ if (argc != 1 ) {
+ printf("Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_lsa_open_policy2(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_lsa_query_secobj(cli, mem_ctx, &pol, sec_info, &sdb);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Print results */
+
+ display_sec_desc(sdb->sec);
+
+ done:
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set lsarpc_commands[] = {
+
+ { "LSARPC" },
+
+ { "lsaquery", cmd_lsa_query_info_policy, PIPE_LSARPC, "Query info policy", "" },
+ { "lookupsids", cmd_lsa_lookup_sids, PIPE_LSARPC, "Convert SIDs to names", "" },
+ { "lookupnames", cmd_lsa_lookup_names, PIPE_LSARPC, "Convert names to SIDs", "" },
+ { "enumtrust", cmd_lsa_enum_trust_dom, PIPE_LSARPC, "Enumerate trusted domains", "" },
+ { "enumprivs", cmd_lsa_enum_privilege, PIPE_LSARPC, "Enumerate privileges", "" },
+ { "getdispname", cmd_lsa_get_dispname, PIPE_LSARPC, "Get the privilege name", "" },
+ { "lsaenumsid", cmd_lsa_enum_sids, PIPE_LSARPC, "Enumerate the LSA SIDS", "" },
+ { "lsaenumprivsaccount", cmd_lsa_enum_privsaccounts, PIPE_LSARPC, "Enumerate the privileges of an SID", "" },
+ { "lsalookupprivvalue", cmd_lsa_lookupprivvalue, PIPE_LSARPC, "Get a privilege value given its name", "" },
+ { "lsaquerysecobj", cmd_lsa_query_secobj, PIPE_LSARPC, "Query LSA security object", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_netlogon.c b/source/rpcclient/cmd_netlogon.c
new file mode 100644
index 00000000000..e98573da0c6
--- /dev/null
+++ b/source/rpcclient/cmd_netlogon.c
@@ -0,0 +1,335 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+static NTSTATUS cmd_netlogon_logon_ctrl2(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ uint32 query_level = 1;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 1) {
+ fprintf(stderr, "Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ result = cli_netlogon_logon_ctrl2(cli, mem_ctx, query_level);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ done:
+ return result;
+}
+
+static NTSTATUS cmd_netlogon_logon_ctrl(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+#if 0
+ uint32 query_level = 1;
+#endif
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 1) {
+ fprintf(stderr, "Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+#if 0
+ result = cli_netlogon_logon_ctrl(cli, mem_ctx, query_level);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+#endif
+
+ /* Display results */
+
+ return result;
+}
+
+/* Display sam synchronisation information */
+
+static void display_sam_sync(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas,
+ SAM_DELTA_CTR *deltas)
+{
+ fstring name;
+ uint32 i, j;
+
+ for (i = 0; i < num_deltas; i++) {
+ switch (hdr_deltas[i].type) {
+ case SAM_DELTA_DOMAIN_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].domain_info.uni_dom_name,
+ sizeof(name) - 1);
+ printf("Domain: %s\n", name);
+ break;
+ case SAM_DELTA_GROUP_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].group_info.uni_grp_name,
+ sizeof(name) - 1);
+ printf("Group: %s\n", name);
+ break;
+ case SAM_DELTA_ACCOUNT_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].account_info.uni_acct_name,
+ sizeof(name) - 1);
+ printf("Account: %s\n", name);
+ break;
+ case SAM_DELTA_ALIAS_INFO:
+ unistr2_to_ascii(name,
+ &deltas[i].alias_info.uni_als_name,
+ sizeof(name) - 1);
+ printf("Alias: %s\n", name);
+ break;
+ case SAM_DELTA_ALIAS_MEM: {
+ SAM_ALIAS_MEM_INFO *alias = &deltas[i].als_mem_info;
+
+ for (j = 0; j < alias->num_members; j++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &alias->sids[j].sid);
+
+ printf("%s\n", sid_str);
+ }
+ break;
+ }
+ case SAM_DELTA_GROUP_MEM: {
+ SAM_GROUP_MEM_INFO *group = &deltas[i].grp_mem_info;
+
+ for (j = 0; j < group->num_members; j++)
+ printf("rid 0x%x, attrib 0x%08x\n",
+ group->rids[j], group->attribs[j]);
+ break;
+ }
+ case SAM_DELTA_SAM_STAMP: {
+ SAM_DELTA_STAMP *stamp = &deltas[i].stamp;
+
+ printf("sam sequence update: 0x%04x\n",
+ stamp->seqnum);
+ break;
+ }
+ default:
+ printf("unknown delta type 0x%02x\n",
+ hdr_deltas[i].type);
+ break;
+ }
+ }
+}
+
+/* Perform sam synchronisation */
+
+static NTSTATUS cmd_netlogon_sam_sync(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ unsigned char trust_passwd[16];
+ uint32 database_id = 0, num_deltas;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+ DOM_CRED ret_creds;
+
+ if (argc > 2) {
+ fprintf(stderr, "Usage: %s [database_id]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ database_id = atoi(argv[1]);
+
+ if (!secrets_init()) {
+ fprintf(stderr, "Unable to initialise secrets database\n");
+ return result;
+ }
+
+ /* Initialise session credentials */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ fprintf(stderr, "could not fetch trust account password\n");
+ goto done;
+ }
+
+ result = cli_nt_setup_creds(cli, trust_passwd);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "Error initialising session creds\n");
+ goto done;
+ }
+
+ /* on first call the returnAuthenticator is empty */
+ memset(&ret_creds, 0, sizeof(ret_creds));
+
+ /* Synchronise sam database */
+
+ result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, database_id,
+ &num_deltas, &hdr_deltas, &deltas);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ display_sam_sync(num_deltas, hdr_deltas, deltas);
+
+ done:
+ return result;
+}
+
+/* Perform sam delta synchronisation */
+
+static NTSTATUS cmd_netlogon_sam_deltas(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ unsigned char trust_passwd[16];
+ uint32 database_id, num_deltas, tmp;
+ SAM_DELTA_HDR *hdr_deltas;
+ SAM_DELTA_CTR *deltas;
+ UINT64_S seqnum;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s database_id seqnum\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ database_id = atoi(argv[1]);
+ tmp = atoi(argv[2]);
+
+ seqnum.low = tmp & 0xffff;
+ seqnum.high = 0;
+
+ if (!secrets_init()) {
+ fprintf(stderr, "Unable to initialise secrets database\n");
+ goto done;
+ }
+
+ /* Initialise session credentials */
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ fprintf(stderr, "could not fetch trust account password\n");
+ goto done;
+ }
+
+ result = cli_nt_setup_creds(cli, trust_passwd);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "Error initialising session creds\n");
+ goto done;
+ }
+
+ /* Synchronise sam database */
+
+ result = cli_netlogon_sam_deltas(cli, mem_ctx, database_id,
+ seqnum, &num_deltas,
+ &hdr_deltas, &deltas);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Display results */
+
+ display_sam_sync(num_deltas, hdr_deltas, deltas);
+
+ done:
+ return result;
+}
+
+/* Log on a domain user */
+
+static NTSTATUS cmd_netlogon_sam_logon(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ unsigned char trust_passwd[16];
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int logon_type = NET_LOGON_TYPE;
+ char *username, *password;
+
+ /* Check arguments */
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "Usage: samlogon <username> <password> "
+ "[logon_type]\n");
+ return NT_STATUS_OK;
+ }
+
+ username = argv[1];
+ password = argv[2];
+
+ if (argc == 4)
+ sscanf(argv[3], "%i", &logon_type);
+
+ /* Authenticate ourselves with the domain controller */
+
+ if (!secrets_init()) {
+ fprintf(stderr, "Unable to initialise secrets database\n");
+ return result;
+ }
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ fprintf(stderr, "could not fetch trust account password\n");
+ goto done;
+ }
+
+ result = cli_nt_setup_creds(cli, trust_passwd);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "Error initialising session creds\n");
+ goto done;
+ }
+
+ /* Perform the sam logon */
+
+ result = cli_netlogon_sam_logon(cli, mem_ctx, username, password,
+ logon_type);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ done:
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set netlogon_commands[] = {
+
+ { "NETLOGON" },
+
+ { "logonctrl2", cmd_netlogon_logon_ctrl2, PIPE_NETLOGON, "Logon Control 2", "" },
+ { "logonctrl", cmd_netlogon_logon_ctrl, PIPE_NETLOGON, "Logon Control", "" },
+ { "samsync", cmd_netlogon_sam_sync, PIPE_NETLOGON, "Sam Synchronisation", "" },
+ { "samdeltas", cmd_netlogon_sam_deltas, PIPE_NETLOGON, "Query Sam Deltas", "" },
+ { "samlogon", cmd_netlogon_sam_logon, PIPE_NETLOGON, "Sam Logon", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_reg.c b/source/rpcclient/cmd_reg.c
new file mode 100644
index 00000000000..991d76b3a32
--- /dev/null
+++ b/source/rpcclient/cmd_reg.c
@@ -0,0 +1,1029 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/*
+ * keys. of the form:
+ * ----
+ *
+ * [HKLM]|[HKU]\[parent_keyname_components]\[subkey]|[value]
+ *
+ * reg_getsubkey() splits this down into:
+ * [HKLM]|[HKU]\[parent_keyname_components] and [subkey]|[value]
+ *
+ * do_reg_connect() splits the left side down further into:
+ * [HKLM]|[HKU] and [parent_keyname_components].
+ *
+ * HKLM is short for HKEY_LOCAL_MACHINE
+ * HKU is short for HKEY_USERS
+ *
+ * oh, and HKEY stands for "Hive Key".
+ *
+ */
+
+#if 0 /* Simo: reg functions need to be updated to the new cmd interface */
+
+/****************************************************************************
+nt registry enum
+****************************************************************************/
+static void cmd_reg_enum(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res1 = True;
+ BOOL res2 = True;
+ int i;
+
+ POLICY_HND key_pol;
+ fstring full_keyname;
+ fstring key_name;
+
+ /*
+ * query key info
+ */
+
+ fstring key_class;
+ uint32 max_class_len = 0;
+ uint32 num_subkeys;
+ uint32 max_subkeylen;
+ uint32 max_subkeysize;
+ uint32 num_values;
+ uint32 max_valnamelen;
+ uint32 max_valbufsize;
+ uint32 sec_desc;
+ NTTIME mod_time;
+
+ /*
+ * unknown 0x1a request
+ */
+
+ uint32 unk_1a_response;
+
+ DEBUG(5, ("cmd_reg_enum: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regenum <key_name>\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, full_keyname, key_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*key_name) != 0)
+ {
+ /* open an entry */
+ res1 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+ }
+ else
+ {
+ memcpy(&key_pol, &info->dom.reg_pol_connect, sizeof(key_pol));
+ }
+
+ res1 = res1 ? do_reg_query_key(smb_cli,
+ &key_pol,
+ key_class, &max_class_len,
+ &num_subkeys, &max_subkeylen, &max_subkeysize,
+ &num_values, &max_valnamelen, &max_valbufsize,
+ &sec_desc, &mod_time) : False;
+
+ if (res1 && num_subkeys > 0)
+ {
+ fprintf(out_hnd,"Subkeys\n");
+ fprintf(out_hnd,"-------\n");
+ }
+
+ for (i = 0; i < num_subkeys; i++)
+ {
+ /*
+ * enumerate key
+ */
+
+ fstring enum_name;
+ uint32 enum_unk1;
+ uint32 enum_unk2;
+ time_t key_mod_time;
+
+ /* unknown 1a it */
+ res2 = res1 ? do_reg_unknown_1a(smb_cli, &key_pol,
+ &unk_1a_response) : False;
+
+ if (res2 && unk_1a_response != 5)
+ {
+ fprintf(out_hnd,"Unknown 1a response: %x\n", unk_1a_response);
+ }
+
+ /* enum key */
+ res2 = res2 ? do_reg_enum_key(smb_cli, &key_pol,
+ i, enum_name,
+ &enum_unk1, &enum_unk2,
+ &key_mod_time) : False;
+
+ if (res2)
+ {
+ display_reg_key_info(out_hnd, ACTION_HEADER , enum_name, key_mod_time);
+ display_reg_key_info(out_hnd, ACTION_ENUMERATE, enum_name, key_mod_time);
+ display_reg_key_info(out_hnd, ACTION_FOOTER , enum_name, key_mod_time);
+ }
+
+ }
+
+ if (num_values > 0)
+ {
+ fprintf(out_hnd,"Key Values\n");
+ fprintf(out_hnd,"----------\n");
+ }
+
+ for (i = 0; i < num_values; i++)
+ {
+ /*
+ * enumerate key
+ */
+
+ uint32 val_type;
+ BUFFER2 value;
+ fstring val_name;
+
+ /* unknown 1a it */
+ res2 = res1 ? do_reg_unknown_1a(smb_cli, &key_pol,
+ &unk_1a_response) : False;
+
+ if (res2 && unk_1a_response != 5)
+ {
+ fprintf(out_hnd,"Unknown 1a response: %x\n", unk_1a_response);
+ }
+
+ /* enum key */
+ res2 = res2 ? do_reg_enum_val(smb_cli, &key_pol,
+ i, max_valnamelen, max_valbufsize,
+ val_name, &val_type, &value) : False;
+
+ if (res2)
+ {
+ display_reg_value_info(out_hnd, ACTION_HEADER , val_name, val_type, &value);
+ display_reg_value_info(out_hnd, ACTION_ENUMERATE, val_name, val_type, &value);
+ display_reg_value_info(out_hnd, ACTION_FOOTER , val_name, val_type, &value);
+ }
+ }
+
+ /* close the handles */
+ if ((*key_name) != 0)
+ {
+ res1 = res1 ? do_reg_close(smb_cli, &key_pol) : False;
+ }
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res1 && res2)
+ {
+ DEBUG(5,("cmd_reg_enum: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_enum: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry query key
+****************************************************************************/
+static void cmd_reg_query_key(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res1 = True;
+
+ POLICY_HND key_pol;
+ fstring full_keyname;
+ fstring key_name;
+
+ /*
+ * query key info
+ */
+
+ fstring key_class;
+ uint32 key_class_len = 0;
+ uint32 num_subkeys;
+ uint32 max_subkeylen;
+ uint32 max_subkeysize;
+ uint32 num_values;
+ uint32 max_valnamelen;
+ uint32 max_valbufsize;
+ uint32 sec_desc;
+ NTTIME mod_time;
+
+ DEBUG(5, ("cmd_reg_enum: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regquery key_name\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, full_keyname, key_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*key_name) != 0)
+ {
+ /* open an entry */
+ res1 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+ }
+ else
+ {
+ memcpy(&key_pol, &info->dom.reg_pol_connect, sizeof(key_pol));
+ }
+
+ res1 = res1 ? do_reg_query_key(smb_cli,
+ &key_pol,
+ key_class, &key_class_len,
+ &num_subkeys, &max_subkeylen, &max_subkeysize,
+ &num_values, &max_valnamelen, &max_valbufsize,
+ &sec_desc, &mod_time) : False;
+
+ if (res1 && key_class_len != 0)
+ {
+ res1 = res1 ? do_reg_query_key(smb_cli,
+ &key_pol,
+ key_class, &key_class_len,
+ &num_subkeys, &max_subkeylen, &max_subkeysize,
+ &num_values, &max_valnamelen, &max_valbufsize,
+ &sec_desc, &mod_time) : False;
+ }
+
+ if (res1)
+ {
+ fprintf(out_hnd,"Registry Query Info Key\n");
+ fprintf(out_hnd,"key class: %s\n", key_class);
+ fprintf(out_hnd,"subkeys, max_len, max_size: %d %d %d\n", num_subkeys, max_subkeylen, max_subkeysize);
+ fprintf(out_hnd,"vals, max_len, max_size: 0x%x 0x%x 0x%x\n", num_values, max_valnamelen, max_valbufsize);
+ fprintf(out_hnd,"sec desc: 0x%x\n", sec_desc);
+ fprintf(out_hnd,"mod time: %s\n", http_timestring(nt_time_to_unix(&mod_time)));
+ }
+
+ /* close the handles */
+ if ((*key_name) != 0)
+ {
+ res1 = res1 ? do_reg_close(smb_cli, &key_pol) : False;
+ }
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res1)
+ {
+ DEBUG(5,("cmd_reg_query: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_query: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry create value
+****************************************************************************/
+static void cmd_reg_create_val(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND parent_pol;
+ fstring full_keyname;
+ fstring keyname;
+ fstring parent_name;
+ fstring val_name;
+ fstring tmp;
+ uint32 val_type;
+ BUFFER3 value;
+
+#if 0
+ uint32 unk_0;
+ uint32 unk_1;
+ /* query it */
+ res1 = res1 ? do_reg_query_info(smb_cli, &val_pol,
+ val_name, *val_type) : False;
+#endif
+
+ DEBUG(5, ("cmd_reg_create_val: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regcreate <val_name> <val_type> <val>\n");
+ return;
+ }
+
+ reg_get_subkey(full_keyname, keyname, val_name);
+
+ if (keyname[0] == 0 || val_name[0] == 0)
+ {
+ fprintf(out_hnd, "invalid key name\n");
+ return;
+ }
+
+ if (!next_token_nr(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ fprintf(out_hnd, "regcreate <val_name> <val_type (1|4)> <val>\n");
+ return;
+ }
+
+ val_type = atoi(tmp);
+
+ if (val_type != 1 && val_type != 3 && val_type != 4)
+ {
+ fprintf(out_hnd, "val_type 1=UNISTR, 3=BYTES, 4=DWORD supported\n");
+ return;
+ }
+
+ if (!next_token_nr(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ fprintf(out_hnd, "regcreate <val_name> <val_type (1|4)> <val>\n");
+ return;
+ }
+
+ switch (val_type)
+ {
+ case 0x01: /* UNISTR */
+ {
+ init_buffer3_str(&value, tmp, strlen(tmp)+1);
+ break;
+ }
+ case 0x03: /* BYTES */
+ {
+ init_buffer3_hex(&value, tmp);
+ break;
+ }
+ case 0x04: /* DWORD */
+ {
+ uint32 tmp_val;
+ if (strnequal(tmp, "0x", 2))
+ {
+ tmp_val = strtol(tmp, (char**)NULL, 16);
+ }
+ else
+ {
+ tmp_val = strtol(tmp, (char**)NULL, 10);
+ }
+ init_buffer3_uint32(&value, tmp_val);
+ break;
+ }
+ default:
+ {
+ fprintf(out_hnd, "i told you i only deal with UNISTR, DWORD and BYTES!\n");
+ return;
+ }
+ }
+
+ DEBUG(10,("key data:\n"));
+ dump_data(10, (char *)value.buffer, value.buf_len);
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, keyname, parent_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*val_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ parent_name, 0x02000000, &parent_pol) : False;
+ }
+ else
+ {
+ memcpy(&parent_pol, &info->dom.reg_pol_connect, sizeof(parent_pol));
+ }
+
+ /* create an entry */
+ res4 = res3 ? do_reg_create_val(smb_cli, &parent_pol,
+ val_name, val_type, &value) : False;
+
+ /* flush the modified key */
+ res4 = res4 ? do_reg_flush_key(smb_cli, &parent_pol) : False;
+
+ /* close the val handle */
+ if ((*val_name) != 0)
+ {
+ res3 = res3 ? do_reg_close(smb_cli, &parent_pol) : False;
+ }
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_create_val: query succeeded\n"));
+ fprintf(out_hnd,"OK\n");
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_create_val: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry delete value
+****************************************************************************/
+static void cmd_reg_delete_val(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND parent_pol;
+ fstring full_keyname;
+ fstring keyname;
+ fstring parent_name;
+ fstring val_name;
+
+ DEBUG(5, ("cmd_reg_delete_val: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regdelete <val_name>\n");
+ return;
+ }
+
+ reg_get_subkey(full_keyname, keyname, val_name);
+
+ if (keyname[0] == 0 || val_name[0] == 0)
+ {
+ fprintf(out_hnd, "invalid key name\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, keyname, parent_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*val_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ parent_name, 0x02000000, &parent_pol) : False;
+ }
+ else
+ {
+ memcpy(&parent_pol, &info->dom.reg_pol_connect, sizeof(parent_pol));
+ }
+
+ /* delete an entry */
+ res4 = res3 ? do_reg_delete_val(smb_cli, &parent_pol, val_name) : False;
+
+ /* flush the modified key */
+ res4 = res4 ? do_reg_flush_key(smb_cli, &parent_pol) : False;
+
+ /* close the key handle */
+ res3 = res3 ? do_reg_close(smb_cli, &parent_pol) : False;
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_delete_val: query succeeded\n"));
+ fprintf(out_hnd,"OK\n");
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_delete_val: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry delete key
+****************************************************************************/
+static void cmd_reg_delete_key(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND parent_pol;
+ fstring full_keyname;
+ fstring parent_name;
+ fstring key_name;
+ fstring subkey_name;
+
+ DEBUG(5, ("cmd_reg_delete_key: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regdeletekey <key_name>\n");
+ return;
+ }
+
+ reg_get_subkey(full_keyname, parent_name, subkey_name);
+
+ if (parent_name[0] == 0 || subkey_name[0] == 0)
+ {
+ fprintf(out_hnd, "invalid key name\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, parent_name, key_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*key_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &parent_pol) : False;
+ }
+ else
+ {
+ memcpy(&parent_pol, &info->dom.reg_pol_connect, sizeof(parent_pol));
+ }
+
+ /* create an entry */
+ res4 = res3 ? do_reg_delete_key(smb_cli, &parent_pol, subkey_name) : False;
+
+ /* flush the modified key */
+ res4 = res4 ? do_reg_flush_key(smb_cli, &parent_pol) : False;
+
+ /* close the key handle */
+ if ((*key_name) != 0)
+ {
+ res3 = res3 ? do_reg_close(smb_cli, &parent_pol) : False;
+ }
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_delete_key: query succeeded\n"));
+ fprintf(out_hnd,"OK\n");
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_delete_key: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry create key
+****************************************************************************/
+static void cmd_reg_create_key(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND parent_pol;
+ POLICY_HND key_pol;
+ fstring full_keyname;
+ fstring parent_key;
+ fstring parent_name;
+ fstring key_name;
+ fstring key_class;
+ SEC_ACCESS sam_access;
+
+ DEBUG(5, ("cmd_reg_create_key: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "regcreate <key_name> [key_class]\n");
+ return;
+ }
+
+ reg_get_subkey(full_keyname, parent_key, key_name);
+
+ if (parent_key[0] == 0 || key_name[0] == 0)
+ {
+ fprintf(out_hnd, "invalid key name\n");
+ return;
+ }
+
+ if (!next_token_nr(NULL, key_class, NULL, sizeof(key_class)))
+ {
+ memset(key_class, 0, sizeof(key_class));
+ }
+
+ /* set access permissions */
+ sam_access.mask = SEC_RIGHTS_READ;
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, parent_key, parent_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*parent_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ parent_name, 0x02000000, &parent_pol) : False;
+ }
+ else
+ {
+ memcpy(&parent_pol, &info->dom.reg_pol_connect, sizeof(parent_pol));
+ }
+
+ /* create an entry */
+ res4 = res3 ? do_reg_create_key(smb_cli, &parent_pol,
+ key_name, key_class, &sam_access, &key_pol) : False;
+
+ /* flush the modified key */
+ res4 = res4 ? do_reg_flush_key(smb_cli, &parent_pol) : False;
+
+ /* close the key handle */
+ res4 = res4 ? do_reg_close(smb_cli, &key_pol) : False;
+
+ /* close the key handle */
+ if ((*parent_name) != 0)
+ {
+ res3 = res3 ? do_reg_close(smb_cli, &parent_pol) : False;
+ }
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_create_key: query succeeded\n"));
+ fprintf(out_hnd,"OK\n");
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_create_key: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry security info
+****************************************************************************/
+static void cmd_reg_test_key_sec(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND key_pol;
+ fstring full_keyname;
+ fstring key_name;
+
+ /*
+ * security info
+ */
+
+ uint32 sec_buf_size;
+ SEC_DESC_BUF *psdb;
+
+ DEBUG(5, ("cmd_reg_get_key_sec: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "reggetsec <key_name>\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, full_keyname, key_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*key_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+ }
+ else
+ {
+ memcpy(&key_pol, &info->dom.reg_pol_connect, sizeof(key_pol));
+ }
+
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+
+ /* query key sec info. first call sets sec_buf_size. */
+
+ sec_buf_size = 0;
+ res4 = res3 ? do_reg_get_key_sec(smb_cli, &key_pol,
+ &sec_buf_size, &psdb) : False;
+
+ free_sec_desc_buf(&psdb);
+
+ res4 = res4 ? do_reg_get_key_sec(smb_cli, &key_pol,
+ &sec_buf_size, &psdb) : False;
+
+ if (res4 && psdb->len > 0 && psdb->sec != NULL)
+ {
+ display_sec_desc(out_hnd, ACTION_HEADER , psdb->sec);
+ display_sec_desc(out_hnd, ACTION_ENUMERATE, psdb->sec);
+ display_sec_desc(out_hnd, ACTION_FOOTER , psdb->sec);
+
+ res4 = res4 ? do_reg_set_key_sec(smb_cli, &key_pol, psdb) : False;
+ }
+
+ free_sec_desc_buf(&psdb);
+
+ /* close the key handle */
+ if ((*key_name) != 0)
+ {
+ res3 = res3 ? do_reg_close(smb_cli, &key_pol) : False;
+ }
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_test2: query succeeded\n"));
+ fprintf(out_hnd,"Registry Test2\n");
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_test2: query failed\n"));
+ }
+}
+
+/****************************************************************************
+nt registry security info
+****************************************************************************/
+static void cmd_reg_get_key_sec(struct client_info *info)
+{
+ BOOL res = True;
+ BOOL res3 = True;
+ BOOL res4 = True;
+
+ POLICY_HND key_pol;
+ fstring full_keyname;
+ fstring key_name;
+
+ /*
+ * security info
+ */
+
+ uint32 sec_buf_size;
+ SEC_DESC_BUF *psdb;
+
+ DEBUG(5, ("cmd_reg_get_key_sec: smb_cli->fd:%d\n", smb_cli->fd));
+
+ if (!next_token_nr(NULL, full_keyname, NULL, sizeof(full_keyname)))
+ {
+ fprintf(out_hnd, "reggetsec <key_name>\n");
+ return;
+ }
+
+ /* open WINREG session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+ /* open registry receive a policy handle */
+ res = res ? do_reg_connect(smb_cli, full_keyname, key_name,
+ &info->dom.reg_pol_connect) : False;
+
+ if ((*key_name) != 0)
+ {
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+ }
+ else
+ {
+ memcpy(&key_pol, &info->dom.reg_pol_connect, sizeof(key_pol));
+ }
+
+ /* open an entry */
+ res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+ key_name, 0x02000000, &key_pol) : False;
+
+ /* Get the size. */
+ sec_buf_size = 0;
+ res4 = res3 ? do_reg_get_key_sec(smb_cli, &key_pol,
+ &sec_buf_size, &psdb) : False;
+
+ free_sec_desc_buf(&psdb);
+
+ res4 = res4 ? do_reg_get_key_sec(smb_cli, &key_pol,
+ &sec_buf_size, &psdb) : False;
+
+ if (res4 && psdb->len > 0 && psdb->sec != NULL)
+ {
+ display_sec_desc(out_hnd, ACTION_HEADER , psdb->sec);
+ display_sec_desc(out_hnd, ACTION_ENUMERATE, psdb->sec);
+ display_sec_desc(out_hnd, ACTION_FOOTER , psdb->sec);
+ }
+
+ free_sec_desc_buf(&psdb);
+
+ /* close the key handle */
+ if ((*key_name) != 0)
+ {
+ res3 = res3 ? do_reg_close(smb_cli, &key_pol) : False;
+ }
+
+ /* close the registry handles */
+ res = res ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res && res3 && res4)
+ {
+ DEBUG(5,("cmd_reg_get_key_sec: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_reg_get_key_sec: query failed\n"));
+ }
+}
+
+#endif /* 0 */
+
+/****************************************************************************
+nt registry shutdown
+****************************************************************************/
+static NTSTATUS cmd_reg_shutdown(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring msg;
+ uint32 timeout = 20;
+ uint16 flgs = 0;
+ int opt;
+ int ret;
+ char *srv_name;
+
+ ret = asprintf (&srv_name, "\\\\%s", cli->desthost);
+ if (ret < 0) {
+ DEBUG(0,("cmd_reg_shutdown: Not enough memory!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ strupper(srv_name);
+
+ *msg = 0;
+ optind = 0; /* TODO: test if this hack works on other systems too --simo */
+
+ while ((opt = getopt(argc, argv, "m:t:rf")) != EOF)
+ {
+ fprintf (stderr, "[%s]\n", argv[argc-1]);
+
+ switch (opt)
+ {
+ case 'm':
+ {
+ safe_strcpy(msg, optarg, sizeof(msg)-1);
+ fprintf (stderr, "[%s|%s]\n", optarg, msg);
+ break;
+ }
+ case 't':
+ {
+ timeout = atoi(optarg);
+ fprintf (stderr, "[%s|%d]\n", optarg, timeout);
+ break;
+ }
+ case 'r':
+ {
+ flgs |= 0x100;
+ break;
+ }
+ case 'f':
+ {
+ flgs |= 0x001;
+ break;
+ }
+ }
+ }
+
+ /* create an entry */
+ result = cli_reg_shutdown(cli, mem_ctx, srv_name, msg, timeout, flgs);
+
+ if (NT_STATUS_IS_OK(result))
+ DEBUG(5,("cmd_reg_shutdown: query succeeded\n"));
+ else
+ DEBUG(5,("cmd_reg_shutdown: query failed\n"));
+
+ return result;
+}
+
+/****************************************************************************
+abort a shutdown
+****************************************************************************/
+static NTSTATUS cmd_reg_abort_shutdown(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc,
+ char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int ret;
+ char *srv_name;
+
+ ret = asprintf(&srv_name, "\\\\%s", cli->desthost);
+ if (ret < 0) {
+ DEBUG(0,("cmd_reg_shutdown: Not enough memory!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ strupper(srv_name);
+
+ result = cli_reg_abort_shutdown(cli, mem_ctx, srv_name);
+
+ if (NT_STATUS_IS_OK(result))
+ DEBUG(5,("cmd_reg_abort_shutdown: query succeeded\n"));
+ else
+ DEBUG(5,("cmd_reg_abort_shutdown: query failed\n"));
+
+ return result;
+}
+
+
+/* List of commands exported by this module */
+struct cmd_set reg_commands[] = {
+
+ { "REG" },
+
+ { "shutdown", cmd_reg_shutdown, PIPE_WINREG, "Remote Shutdown",
+ "[-m message] [-t timeout] [-r] [-f] (-r == reboot, -f == force)" },
+
+ { "abortshutdown", cmd_reg_abort_shutdown, PIPE_WINREG, "Abort Shutdown",
+ "" },
+/*
+ { "regenum", cmd_reg_enum, "Registry Enumeration",
+ "<keyname>" },
+
+ { "regdeletekey", cmd_reg_delete_key, "Registry Key Delete",
+ "<keyname>" },
+
+ { "regcreatekey", cmd_reg_create_key, "Registry Key Create",
+ "<keyname> [keyclass]" },
+
+ { "regqueryval", cmd_reg_query_info, "Registry Value Query",
+ "<valname>" },
+
+ { "regquerykey", cmd_reg_query_key, "Registry Key Query",
+ "<keyname>" },
+
+ { "regdeleteval", cmd_reg_delete_val, "Registry Value Delete",
+ "<valname>" },
+
+ { "regcreateval", cmd_reg_create_val, "Registry Key Create",
+ "<valname> <valtype> <value>" },
+
+ { "reggetsec", cmd_reg_get_key_sec, "Registry Key Security",
+ "<keyname>" },
+
+ { "regtestsec", cmd_reg_test_key_sec, "Test Registry Key Security",
+ "<keyname>" },
+*/
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_samr.c b/source/rpcclient/cmd_samr.c
new file mode 100644
index 00000000000..c31127be4e2
--- /dev/null
+++ b/source/rpcclient/cmd_samr.c
@@ -0,0 +1,1205 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Andrew Tridgell 1992-2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ Copyright (C) Elrond 2000,
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+extern DOM_SID domain_sid;
+
+/****************************************************************************
+ display sam_user_info_21 structure
+ ****************************************************************************/
+static void display_sam_user_info_21(SAM_USER_INFO_21 *usr)
+{
+ fstring temp;
+
+ unistr2_to_ascii(temp, &usr->uni_user_name, sizeof(temp)-1);
+ printf("\tUser Name :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_full_name, sizeof(temp)-1);
+ printf("\tFull Name :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_home_dir, sizeof(temp)-1);
+ printf("\tHome Drive :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_dir_drive, sizeof(temp)-1);
+ printf("\tDir Drive :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_profile_path, sizeof(temp)-1);
+ printf("\tProfile Path:\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_logon_script, sizeof(temp)-1);
+ printf("\tLogon Script:\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_acct_desc, sizeof(temp)-1);
+ printf("\tDescription :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_workstations, sizeof(temp)-1);
+ printf("\tWorkstations:\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_unknown_str, sizeof(temp)-1);
+ printf("\tUnknown Str :\t%s\n", temp);
+
+ unistr2_to_ascii(temp, &usr->uni_munged_dial, sizeof(temp)-1);
+ printf("\tRemote Dial :\t%s\n", temp);
+
+ printf("\tLogon Time :\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->logon_time)));
+ printf("\tLogoff Time :\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->logoff_time)));
+ printf("\tKickoff Time :\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->kickoff_time)));
+ printf("\tPassword last set Time :\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->pass_last_set_time)));
+ printf("\tPassword can change Time :\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->pass_can_change_time)));
+ printf("\tPassword must change Time:\t%s\n",
+ http_timestring(nt_time_to_unix(&usr->pass_must_change_time)));
+
+ printf("\tunknown_2[0..31]...\n"); /* user passwords? */
+
+ printf("\tuser_rid :\t%x\n" , usr->user_rid ); /* User ID */
+ printf("\tgroup_rid:\t%x\n" , usr->group_rid); /* Group ID */
+ printf("\tacb_info :\t%04x\n", usr->acb_info ); /* Account Control Info */
+
+ printf("\tunknown_3:\t%08x\n", usr->unknown_3); /* 0x00ff ffff */
+ printf("\tlogon_divs:\t%d\n", usr->logon_divs); /* 0x0000 00a8 which is 168 which is num hrs in a week */
+ printf("\tunknown_5:\t%08x\n", usr->unknown_5); /* 0x0002 0000 */
+
+ printf("\tpadding1[0..7]...\n");
+
+ if (usr->ptr_logon_hrs) {
+ printf("\tlogon_hrs[0..%d]...\n", usr->logon_hrs.len);
+ }
+}
+
+static char *display_time(NTTIME nttime)
+{
+ static fstring string;
+
+ float high;
+ float low;
+ int sec;
+ int days, hours, mins, secs;
+
+ if (nttime.high==0 && nttime.low==0)
+ return "Now";
+
+ if (nttime.high==0x80000000 && nttime.low==0)
+ return "Never";
+
+ high = 65536;
+ high = high/10000;
+ high = high*65536;
+ high = high/1000;
+ high = high * (~nttime.high);
+
+ low = ~nttime.low;
+ low = low/(1000*1000*10);
+
+ sec=high+low;
+
+ days=sec/(60*60*24);
+ hours=(sec - (days*60*60*24)) / (60*60);
+ mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60;
+ secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60);
+
+ snprintf(string, sizeof(string)-1, "%u days, %u hours, %u minutes, %u seconds", days, hours, mins, secs);
+ return (string);
+}
+
+static void display_sam_unk_info_1(SAM_UNK_INFO_1 *info1)
+{
+
+ printf("Minimum password length: %d\n", info1->min_length_password);
+ printf("Password uniqueness (remember x passwords): %d\n", info1->password_history);
+ printf("flag: ");
+ if(info1->flag&&2==2) printf("users must open a session to change password ");
+ printf("\n");
+
+ printf("password expire in: %s\n", display_time(info1->expire));
+ printf("Min password age (allow changing in x days): %s\n", display_time(info1->min_passwordage));
+}
+
+static void display_sam_unk_info_2(SAM_UNK_INFO_2 *info2)
+{
+ fstring name;
+
+ unistr2_to_ascii(name, &info2->uni_domain, sizeof(name) - 1);
+ printf("Domain:\t%s\n", name);
+
+ unistr2_to_ascii(name, &info2->uni_server, sizeof(name) - 1);
+ printf("Server:\t%s\n", name);
+
+ printf("Total Users:\t%d\n", info2->num_domain_usrs);
+ printf("Total Groups:\t%d\n", info2->num_domain_grps);
+ printf("Total Aliases:\t%d\n", info2->num_local_grps);
+
+ printf("Sequence No:\t%d\n", info2->seq_num);
+
+ printf("Unknown 0:\t0x%x\n", info2->unknown_0);
+ printf("Unknown 1:\t0x%x\n", info2->unknown_1);
+ printf("Unknown 2:\t0x%x\n", info2->unknown_2);
+ printf("Unknown 3:\t0x%x\n", info2->unknown_3);
+ printf("Unknown 4:\t0x%x\n", info2->unknown_4);
+ printf("Unknown 5:\t0x%x\n", info2->unknown_5);
+ printf("Unknown 6:\t0x%x\n", info2->unknown_6);
+}
+
+void display_sam_info_1(SAM_ENTRY1 *e1, SAM_STR1 *s1)
+{
+ fstring tmp;
+
+ printf("RID: 0x%x ", e1->rid_user);
+
+ unistr2_to_ascii(tmp, &s1->uni_acct_name, sizeof(tmp)-1);
+ printf("Account: %s\t", tmp);
+
+ unistr2_to_ascii(tmp, &s1->uni_full_name, sizeof(tmp)-1);
+ printf("Name: %s\t", tmp);
+
+ unistr2_to_ascii(tmp, &s1->uni_acct_desc, sizeof(tmp)-1);
+ printf("Desc: %s\n", tmp);
+}
+
+void display_sam_info_4(SAM_ENTRY4 *e4, SAM_STR4 *s4)
+{
+ int i;
+
+ printf("index: %d ", e4->user_idx);
+
+ printf("Account: ");
+ for (i=0; i<s4->acct_name.str_str_len; i++)
+ printf("%c", s4->acct_name.buffer[i]);
+ printf("\n");
+
+}
+/**********************************************************************
+ * Query user information
+ */
+static NTSTATUS cmd_samr_query_user(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 21;
+ SAM_USERINFO_CTR *user_ctr;
+ fstring server;
+ uint32 user_rid;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &user_rid);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rid, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ ZERO_STRUCT(user_ctr);
+
+ result = cli_samr_query_userinfo(cli, mem_ctx, &user_pol,
+ info_level, &user_ctr);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ display_sam_user_info_21(user_ctr->info.id21);
+
+done:
+ return result;
+}
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info1(GROUP_INFO1 *info1)
+{
+ fstring temp;
+
+ unistr2_to_ascii(temp, &info1->uni_acct_name, sizeof(temp)-1);
+ printf("\tGroup Name:\t%s\n", temp);
+ unistr2_to_ascii(temp, &info1->uni_acct_desc, sizeof(temp)-1);
+ printf("\tDescription:\t%s\n", temp);
+ printf("\tunk1:%d\n", info1->unknown_1);
+ printf("\tNum Members:%d\n", info1->num_members);
+}
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info4(GROUP_INFO4 *info4)
+{
+ fstring desc;
+
+ unistr2_to_ascii(desc, &info4->uni_acct_desc, sizeof(desc)-1);
+ printf("\tGroup Description:%s\n", desc);
+}
+
+/****************************************************************************
+ display sam sync structure
+ ****************************************************************************/
+static void display_group_info_ctr(GROUP_INFO_CTR *ctr)
+{
+ switch (ctr->switch_value1) {
+ case 1: {
+ display_group_info1(&ctr->group.info1);
+ break;
+ }
+ case 4: {
+ display_group_info4(&ctr->group.info4);
+ break;
+ }
+ }
+}
+
+/***********************************************************************
+ * Query group information
+ */
+static NTSTATUS cmd_samr_query_group(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 1;
+ GROUP_INFO_CTR group_ctr;
+ fstring server;
+ uint32 group_rid;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &group_rid);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ result = cli_samr_open_group(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rid, &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ ZERO_STRUCT(group_ctr);
+
+ result = cli_samr_query_groupinfo(cli, mem_ctx, &group_pol,
+ info_level, &group_ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ display_group_info_ctr(&group_ctr);
+
+done:
+ return result;
+}
+
+/* Query groups a user is a member of */
+
+static NTSTATUS cmd_samr_query_usergroups(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol,
+ domain_pol,
+ user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 num_groups,
+ user_rid;
+ DOM_GID *user_gids;
+ int i;
+ fstring server;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &user_rid);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rid, &user_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_query_usergroups(cli, mem_ctx, &user_pol,
+ &num_groups, &user_gids);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ printf("\tgroup rid:[0x%x] attr:[0x%x]\n",
+ user_gids[i].g_rid, user_gids[i].attr);
+ }
+
+ done:
+ return result;
+}
+
+/* Query aliases a user is a member of */
+
+static NTSTATUS cmd_samr_query_useraliases(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 user_rid, num_aliases, *alias_rids;
+ int i;
+ fstring server;
+ DOM_SID tmp_sid;
+ DOM_SID2 sid;
+ DOM_SID global_sid_Builtin;
+
+ string_to_sid(&global_sid_Builtin, "S-1-5-32");
+
+ if (argc != 3) {
+ printf("Usage: %s builtin|domain rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[2], "%i", &user_rid);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &global_sid_Builtin, &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ sid_copy(&tmp_sid, &domain_sid);
+ sid_append_rid(&tmp_sid, user_rid);
+ init_dom_sid2(&sid, &tmp_sid);
+
+ result = cli_samr_query_useraliases(cli, mem_ctx, &domain_pol, 1, &sid, &num_aliases, &alias_rids);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i = 0; i < num_aliases; i++) {
+ printf("\tgroup rid:[0x%x]\n", alias_rids[i]);
+ }
+
+ done:
+ return result;
+}
+
+/* Query members of a group */
+
+static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 num_members, *group_rids, *group_attrs, group_rid;
+ int i;
+ fstring server;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &group_rid);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_group(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ group_rid, &group_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_query_groupmem(cli, mem_ctx, &group_pol,
+ &num_members, &group_rids,
+ &group_attrs);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i = 0; i < num_members; i++) {
+ printf("\trid:[0x%x] attr:[0x%x]\n", group_rids[i],
+ group_attrs[i]);
+ }
+
+ done:
+ return result;
+}
+
+/* Enumerate domain groups */
+
+static NTSTATUS cmd_samr_enum_dom_groups(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_dom_groups, i;
+ struct acct_info *dom_groups;
+
+ if (argc != 1) {
+ printf("Usage: %s\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Enumerate domain groups */
+
+ start_idx = 0;
+ size = 0xffff;
+
+ result = cli_samr_enum_dom_groups(cli, mem_ctx, &domain_pol,
+ &start_idx, size,
+ &dom_groups, &num_dom_groups);
+
+ for (i = 0; i < num_dom_groups; i++)
+ printf("group:[%s] rid:[0x%x]\n", dom_groups[i].acct_name,
+ dom_groups[i].rid);
+
+ done:
+ return result;
+}
+
+/* Enumerate domain groups */
+
+static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx, size, num_dom_groups, i;
+ struct acct_info *dom_groups;
+ DOM_SID global_sid_Builtin;
+
+ string_to_sid(&global_sid_Builtin, "S-1-5-32");
+
+ if (argc != 2) {
+ printf("Usage: %s builtin|domain\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &global_sid_Builtin, &domain_pol);
+ else
+ return NT_STATUS_OK;
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Enumerate domain groups */
+
+ start_idx = 0;
+ size = 0xffff;
+
+ result = cli_samr_enum_als_groups(cli, mem_ctx, &domain_pol,
+ &start_idx, size,
+ &dom_groups, &num_dom_groups);
+
+ for (i = 0; i < num_dom_groups; i++)
+ printf("group:[%s] rid:[0x%x]\n", dom_groups[i].acct_name,
+ dom_groups[i].rid);
+
+ done:
+ return result;
+}
+
+/* Query alias membership */
+
+static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, alias_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 alias_rid, num_members, i;
+ DOM_SID *alias_sids;
+
+ if (argc != 2) {
+ printf("Usage: %s rid\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ sscanf(argv[1], "%i", &alias_rid);
+
+ /* Open SAMR handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Open handle on domain */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Open handle on alias */
+
+ result = cli_samr_open_alias(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ alias_rid, &alias_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_query_aliasmem(cli, mem_ctx, &alias_pol,
+ &num_members, &alias_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ for (i = 0; i < num_members; i++) {
+ fstring sid_str;
+
+ sid_to_string(sid_str, &alias_sids[i]);
+ printf("\tsid:[%s]\n", sid_str);
+ }
+
+ done:
+ return result;
+}
+
+/* Query display info */
+
+static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 start_idx=0, max_entries=250, num_entries, i;
+ int info_level = 1;
+ SAM_DISPINFO_CTR ctr;
+ SAM_DISPINFO_1 info1;
+
+ if (argc > 4) {
+ printf("Usage: %s [info level] [start index] [max entries]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc >= 2)
+ sscanf(argv[1], "%i", &info_level);
+
+ if (argc >= 3)
+ sscanf(argv[2], "%i", &start_idx);
+
+ if (argc >= 4)
+ sscanf(argv[3], "%i", &max_entries);
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Query display info */
+
+ ZERO_STRUCT(ctr);
+ ZERO_STRUCT(info1);
+
+ ctr.sam.info1 = &info1;
+
+ result = cli_samr_query_dispinfo(cli, mem_ctx, &domain_pol,
+ &start_idx, info_level,
+ &num_entries, max_entries, &ctr);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ for (i = 0; i < num_entries; i++) {
+ switch (info_level) {
+ case 1:
+ display_sam_info_1(&ctr.sam.info1->sam[i], &ctr.sam.info1->str[i]);
+ break;
+ case 4:
+ display_sam_info_4(&ctr.sam.info4->sam[i], &ctr.sam.info4->str[i]);
+ break;
+ }
+ }
+
+ done:
+ return result;
+}
+
+/* Query domain info */
+
+static NTSTATUS cmd_samr_query_dominfo(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ int switch_value = 2;
+ SAM_UNK_CTR ctr;
+
+ if (argc > 2) {
+ printf("Usage: %s [infolevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ sscanf(argv[1], "%i", &switch_value);
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Query domain info */
+
+ result = cli_samr_query_dom_info(cli, mem_ctx, &domain_pol,
+ switch_value, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display domain info */
+
+ switch (switch_value) {
+ case 1:
+ display_sam_unk_info_1(&ctr.info.inf1);
+ break;
+ case 2:
+ display_sam_unk_info_2(&ctr.info.inf2);
+ break;
+ default:
+ printf("cannot display domain info for switch value %d\n",
+ switch_value);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+/* Create domain user */
+
+static NTSTATUS cmd_samr_create_dom_user(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ uint16 acb_info;
+ uint32 unknown, user_rid;
+
+ if (argc != 2) {
+ printf("Usage: %s username\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ acct_name = argv[1];
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Create domain user */
+
+ acb_info = ACB_NORMAL;
+ unknown = 0xe005000b; /* No idea what this is - a permission mask? */
+
+ result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
+ acct_name, acb_info, unknown,
+ &user_pol, &user_rid);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+/* Lookup sam names */
+
+static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol;
+ uint32 flags = 0x000003e8; /* Unknown */
+ uint32 num_rids, num_names, *name_types, *rids;
+ char **names;
+ int i;
+ DOM_SID global_sid_Builtin;
+
+ string_to_sid(&global_sid_Builtin, "S-1-5-32");
+
+ if (argc < 3) {
+ printf("Usage: %s domain|builtin name1 [name2 [name3] [...]]\n", argv[0]);
+ printf("check on the domain SID: S-1-5-21-x-y-z\n");
+ printf("or check on the builtin SID: S-1-5-32\n");
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy and domain handles */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ if (StrCaseCmp(argv[1], "domain")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+ else if (StrCaseCmp(argv[1], "builtin")==0)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &global_sid_Builtin, &domain_pol);
+ else
+ return NT_STATUS_OK;
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Look up names */
+
+ num_names = argc - 2;
+ names = (char **)talloc(mem_ctx, sizeof(char *) * num_names);
+
+ for (i = 0; i < argc - 2; i++)
+ names[i] = argv[i + 2];
+
+ result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+ flags, num_names, names,
+ &num_rids, &rids, &name_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ for (i = 0; i < num_names; i++)
+ printf("name %s: 0x%x (%d)\n", names[i], rids[i],
+ name_types[i]);
+
+ done:
+ return result;
+}
+
+/* Lookup sam rids */
+
+static NTSTATUS cmd_samr_lookup_rids(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol;
+ uint32 flags = 0x000003e8; /* Unknown */
+ uint32 num_rids, num_names, *rids, *name_types;
+ char **names;
+ int i;
+
+ if (argc < 2) {
+ printf("Usage: %s rid1 [rid2 [rid3] [...]]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy and domain handles */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Look up rids */
+
+ num_rids = argc - 1;
+ rids = (uint32 *)talloc(mem_ctx, sizeof(uint32) * num_rids);
+
+ for (i = 0; i < argc - 1; i++)
+ sscanf(argv[i + 1], "%i", &rids[i]);
+
+ result = cli_samr_lookup_rids(cli, mem_ctx, &domain_pol,
+ flags, num_rids, rids,
+ &num_names, &names, &name_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ for (i = 0; i < num_names; i++)
+ printf("rid 0x%x: %s (%d)\n", rids[i], names[i], name_types[i]);
+
+ done:
+ return result;
+}
+
+/* Delete domain user */
+
+static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ POLICY_HND connect_pol, domain_pol, user_pol;
+
+ if (argc != 2) {
+ printf("Usage: %s username\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Get sam policy and domain handles */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get handle on user */
+
+ {
+ uint32 *user_rids, num_rids, *name_types;
+ uint32 flags = 0x000003e8; /* Unknown */
+
+ result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+ flags, 1, &argv[1],
+ &num_rids, &user_rids,
+ &name_types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rids[0], &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+ }
+
+ /* Delete user */
+
+ result = cli_samr_delete_dom_user(cli, mem_ctx, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ done:
+ return result;
+}
+
+/**********************************************************************
+ * Query user security object
+ */
+static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND connect_pol, domain_pol, user_pol, *pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 4;
+ fstring server;
+ uint32 user_rid = 0;
+ TALLOC_CTX *ctx = NULL;
+ SEC_DESC_BUF *sec_desc_buf=NULL;
+ BOOL domain = False;
+
+ ctx=talloc_init();
+
+ if (argc > 2) {
+ printf("Usage: %s [rid|-d]\n", argv[0]);
+ printf("\tSpecify rid for security on user, -d for security on domain\n");
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "-d") == 0)
+ domain = True;
+ else
+ sscanf(argv[1], "%i", &user_rid);
+ }
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (domain || user_rid)
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ &domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ if (user_rid)
+ result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ user_rid, &user_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Pick which query pol to use */
+
+ pol = &connect_pol;
+
+ if (domain)
+ pol = &domain_pol;
+
+ if (user_rid)
+ pol = &user_pol;
+
+ /* Query SAM security object */
+
+ result = cli_samr_query_sec_obj(cli, mem_ctx, pol, info_level, ctx,
+ &sec_desc_buf);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ display_sec_desc(sec_desc_buf->sec);
+
+done:
+ talloc_destroy(ctx);
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set samr_commands[] = {
+
+ { "SAMR" },
+
+ { "queryuser", cmd_samr_query_user, PIPE_SAMR, "Query user info", "" },
+ { "querygroup", cmd_samr_query_group, PIPE_SAMR, "Query group info", "" },
+ { "queryusergroups", cmd_samr_query_usergroups, PIPE_SAMR, "Query user groups", "" },
+ { "queryuseraliases", cmd_samr_query_useraliases, PIPE_SAMR, "Query user aliases", "" },
+ { "querygroupmem", cmd_samr_query_groupmem, PIPE_SAMR, "Query group membership", "" },
+ { "queryaliasmem", cmd_samr_query_aliasmem, PIPE_SAMR, "Query alias membership", "" },
+ { "querydispinfo", cmd_samr_query_dispinfo, PIPE_SAMR, "Query display info", "" },
+ { "querydominfo", cmd_samr_query_dominfo, PIPE_SAMR, "Query domain info", "" },
+ { "enumdomgroups", cmd_samr_enum_dom_groups, PIPE_SAMR, "Enumerate domain groups", "" },
+ { "enumalsgroups", cmd_samr_enum_als_groups, PIPE_SAMR, "Enumerate alias groups", "" },
+
+ { "createdomuser", cmd_samr_create_dom_user, PIPE_SAMR, "Create domain user", "" },
+ { "samlookupnames", cmd_samr_lookup_names, PIPE_SAMR, "Look up names", "" },
+ { "samlookuprids", cmd_samr_lookup_rids, PIPE_SAMR, "Look up names", "" },
+ { "deletedomuser", cmd_samr_delete_dom_user, PIPE_SAMR, "Delete domain user", "" },
+ { "samquerysecobj", cmd_samr_query_sec_obj, PIPE_SAMR, "Query SAMR security object", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_spoolss.c b/source/rpcclient/cmd_spoolss.c
new file mode 100644
index 00000000000..1e521473d40
--- /dev/null
+++ b/source/rpcclient/cmd_spoolss.c
@@ -0,0 +1,1154 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+struct table_node {
+ char *long_archi;
+ char *short_archi;
+ int version;
+};
+
+struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {NULL, "", -1 }
+};
+
+/****************************************************************************
+function to do the mapping between the long architecture name and
+the short one.
+****************************************************************************/
+BOOL get_short_archi(char *short_archi, char *long_archi)
+{
+ int i=-1;
+
+ DEBUG(107,("Getting architecture dependant directory\n"));
+ do {
+ i++;
+ } while ( (archi_table[i].long_archi!=NULL ) &&
+ StrCaseCmp(long_archi, archi_table[i].long_archi) );
+
+ if (archi_table[i].long_archi==NULL) {
+ DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
+ return False;
+ }
+
+ StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
+
+ DEBUGADD(108,("index: [%d]\n", i));
+ DEBUGADD(108,("long architecture: [%s]\n", long_archi));
+ DEBUGADD(108,("short architecture: [%s]\n", short_archi));
+
+ return True;
+}
+
+
+/**********************************************************************
+ * dummy function -- placeholder
+ */
+static NTSTATUS cmd_spoolss_not_implemented(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ printf ("(*) This command is not currently implemented.\n");
+ return NT_STATUS_OK;
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static NTSTATUS cmd_spoolss_open_printer_ex(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ pstring printername;
+ fstring servername, user;
+ POLICY_HND hnd;
+
+ if (argc != 2) {
+ printf("Usage: %s <printername>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (!cli)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+ fstrcpy (user, cli->user_name);
+ fstrcpy (printername, argv[1]);
+
+ /* Open the printer handle */
+ result = cli_spoolss_open_printer_ex (cli, mem_ctx, printername, "",
+ MAXIMUM_ALLOWED_ACCESS, servername, user, &hnd);
+
+ if (NT_STATUS_IS_OK(result)) {
+ printf ("Printer %s opened successfully\n", printername);
+ result = cli_spoolss_close_printer (cli, mem_ctx, &hnd);
+ if (!NT_STATUS_IS_OK(result)) {
+ printf ("Error closing printer handle! (%s)\n", get_nt_error_msg(result));
+ }
+ }
+
+ return result;
+}
+
+
+/****************************************************************************
+printer info level 0 display function
+****************************************************************************/
+static void display_print_info_0(PRINTER_INFO_0 *i1)
+{
+ fstring name;
+ fstring servername;
+
+ rpcstr_pull(name, i1->printername.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(servername, i1->servername.buffer, sizeof(servername), 0,STR_TERMINATE);
+
+ printf("\tprintername:[%s]\n", name);
+ printf("\tservername:[%s]\n", servername);
+ printf("\tcjobs:[0x%x]\n", i1->cjobs);
+ printf("\ttotal_jobs:[0x%x]\n", i1->total_jobs);
+
+ printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i1->year, i1->month,
+ i1->day, i1->dayofweek);
+ printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i1->hour, i1->minute,
+ i1->second, i1->milliseconds);
+
+ printf("\tglobal_counter:[0x%x]\n", i1->global_counter);
+ printf("\ttotal_pages:[0x%x]\n", i1->total_pages);
+
+ printf("\tmajorversion:[0x%x]\n", i1->major_version);
+ printf("\tbuildversion:[0x%x]\n", i1->build_version);
+
+ printf("\tunknown7:[0x%x]\n", i1->unknown7);
+ printf("\tunknown8:[0x%x]\n", i1->unknown8);
+ printf("\tunknown9:[0x%x]\n", i1->unknown9);
+ printf("\tsession_counter:[0x%x]\n", i1->session_counter);
+ printf("\tunknown11:[0x%x]\n", i1->unknown11);
+ printf("\tprinter_errors:[0x%x]\n", i1->printer_errors);
+ printf("\tunknown13:[0x%x]\n", i1->unknown13);
+ printf("\tunknown14:[0x%x]\n", i1->unknown14);
+ printf("\tunknown15:[0x%x]\n", i1->unknown15);
+ printf("\tunknown16:[0x%x]\n", i1->unknown16);
+ printf("\tchange_id:[0x%x]\n", i1->change_id);
+ printf("\tunknown18:[0x%x]\n", i1->unknown18);
+ printf("\tstatus:[0x%x]\n", i1->status);
+ printf("\tunknown20:[0x%x]\n", i1->unknown20);
+ printf("\tc_setprinter:[0x%x]\n", i1->c_setprinter);
+ printf("\tunknown22:[0x%x]\n", i1->unknown22);
+ printf("\tunknown23:[0x%x]\n", i1->unknown23);
+ printf("\tunknown24:[0x%x]\n", i1->unknown24);
+ printf("\tunknown25:[0x%x]\n", i1->unknown25);
+ printf("\tunknown26:[0x%x]\n", i1->unknown26);
+ printf("\tunknown27:[0x%x]\n", i1->unknown27);
+ printf("\tunknown28:[0x%x]\n", i1->unknown28);
+ printf("\tunknown29:[0x%x]\n", i1->unknown29);
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_print_info_1(PRINTER_INFO_1 *i1)
+{
+ fstring desc;
+ fstring name;
+ fstring comm;
+
+ rpcstr_pull(desc, i1->description.buffer, sizeof(desc), 0, STR_TERMINATE);
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), 0, STR_TERMINATE);
+
+ printf("\tflags:[0x%x]\n", i1->flags);
+ printf("\tname:[%s]\n", name);
+ printf("\tdescription:[%s]\n", desc);
+ printf("\tcomment:[%s]\n\n", comm);
+}
+
+/****************************************************************************
+printer info level 2 display function
+****************************************************************************/
+static void display_print_info_2(PRINTER_INFO_2 *i2)
+{
+ fstring servername;
+ fstring printername;
+ fstring sharename;
+ fstring portname;
+ fstring drivername;
+ fstring comment;
+ fstring location;
+ fstring sepfile;
+ fstring printprocessor;
+ fstring datatype;
+ fstring parameters;
+
+ rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), 0, STR_TERMINATE);
+ rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), 0, STR_TERMINATE);
+ rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), 0, STR_TERMINATE);
+ rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), 0, STR_TERMINATE);
+ rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), 0, STR_TERMINATE);
+ rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), 0, STR_TERMINATE);
+ rpcstr_pull(location, i2->location.buffer,sizeof(location), 0, STR_TERMINATE);
+ rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), 0, STR_TERMINATE);
+ rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), 0, STR_TERMINATE);
+ rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), 0, STR_TERMINATE);
+ rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), 0, STR_TERMINATE);
+
+ printf("\tservername:[%s]\n", servername);
+ printf("\tprintername:[%s]\n", printername);
+ printf("\tsharename:[%s]\n", sharename);
+ printf("\tportname:[%s]\n", portname);
+ printf("\tdrivername:[%s]\n", drivername);
+ printf("\tcomment:[%s]\n", comment);
+ printf("\tlocation:[%s]\n", location);
+ printf("\tsepfile:[%s]\n", sepfile);
+ printf("\tprintprocessor:[%s]\n", printprocessor);
+ printf("\tdatatype:[%s]\n", datatype);
+ printf("\tparameters:[%s]\n", parameters);
+ printf("\tattributes:[0x%x]\n", i2->attributes);
+ printf("\tpriority:[0x%x]\n", i2->priority);
+ printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
+ printf("\tstarttime:[0x%x]\n", i2->starttime);
+ printf("\tuntiltime:[0x%x]\n", i2->untiltime);
+ printf("\tstatus:[0x%x]\n", i2->status);
+ printf("\tcjobs:[0x%x]\n", i2->cjobs);
+ printf("\taverageppm:[0x%x]\n", i2->averageppm);
+
+ if (i2->secdesc) display_sec_desc(i2->secdesc);
+}
+
+/****************************************************************************
+printer info level 3 display function
+****************************************************************************/
+static void display_print_info_3(PRINTER_INFO_3 *i3)
+{
+ printf("\tflags:[0x%x]\n", i3->flags);
+
+ display_sec_desc(i3->secdesc);
+}
+
+/* Enumerate printers */
+
+static NTSTATUS cmd_spoolss_enum_printers(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 1;
+ PRINTER_INFO_CTR ctr;
+ int returned;
+ uint32 i = 0;
+
+ if (argc > 2)
+ {
+ printf("Usage: %s [level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ info_level = atoi(argv[1]);
+ }
+
+ /* Enumerate printers -- Should we enumerate types other
+ than PRINTER_ENUM_LOCAL? Maybe accept as a parameter? --jerry */
+ ZERO_STRUCT(ctr);
+ result = cli_spoolss_enum_printers(cli, mem_ctx, PRINTER_ENUM_LOCAL,
+ info_level, &returned, &ctr);
+
+ if (NT_STATUS_IS_OK(result))
+ {
+ if (!returned)
+ printf ("No Printers printers returned.\n");
+
+ switch(info_level) {
+ case 0:
+ for (i=0; i<returned; i++) {
+ display_print_info_0(&(ctr.printers_0[i]));
+ }
+ break;
+ case 1:
+ for (i=0; i<returned; i++) {
+ display_print_info_1(&(ctr.printers_1[i]));
+ }
+ break;
+ case 2:
+ for (i=0; i<returned; i++) {
+ display_print_info_2(&(ctr.printers_2[i]));
+ }
+ break;
+ case 3:
+ for (i=0; i<returned; i++) {
+ display_print_info_3(&(ctr.printers_3[i]));
+ }
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+
+ return result;
+}
+
+/****************************************************************************
+port info level 1 display function
+****************************************************************************/
+static void display_port_info_1(PORT_INFO_1 *i1)
+{
+ fstring buffer;
+
+ rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
+ printf("\tPort Name:\t[%s]\n", buffer);
+}
+
+/****************************************************************************
+port info level 2 display function
+****************************************************************************/
+static void display_port_info_2(PORT_INFO_2 *i2)
+{
+ fstring buffer;
+
+ rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
+ printf("\tPort Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
+
+ printf("\tMonitor Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), 0, STR_TERMINATE);
+
+ printf("\tDescription:\t[%s]\n", buffer);
+ printf("\tPort Type:\t[%d]\n", i2->port_type);
+ printf("\tReserved:\t[%d]\n", i2->reserved);
+ printf("\n");
+}
+
+/* Enumerate ports */
+
+static NTSTATUS cmd_spoolss_enum_ports(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 info_level = 1;
+ PORT_INFO_CTR ctr;
+ int returned;
+
+ if (argc > 2) {
+ printf("Usage: %s [level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ info_level = atoi(argv[1]);
+ }
+
+ /* Enumerate ports */
+ ZERO_STRUCT(ctr);
+
+ result = cli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
+
+ if (NT_STATUS_IS_OK(result)) {
+ int i;
+
+ for (i = 0; i < returned; i++) {
+ switch (info_level) {
+ case 1:
+ display_port_info_1(&ctr.port.info_1[i]);
+ break;
+ case 2:
+ display_port_info_2(&ctr.port.info_2[i]);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static NTSTATUS cmd_spoolss_getprinter(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result;
+ uint32 info_level = 1;
+ BOOL opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ fstring printername,
+ servername,
+ user;
+
+ if (argc == 1 || argc > 3) {
+ printf("Usage: %s <printername> [level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Open a printer handle */
+ if (argc == 3) {
+ info_level = atoi(argv[2]);
+ }
+
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+ slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy (user, cli->user_name);
+
+ /* get a printer handle */
+ result = cli_spoolss_open_printer_ex(
+ cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, servername,
+ user, &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ opened_hnd = True;
+
+ /* Get printer info */
+ result = cli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display printer info */
+
+ switch (info_level) {
+ case 0:
+ display_print_info_0(ctr.printers_0);
+ break;
+ case 1:
+ display_print_info_1(ctr.printers_1);
+ break;
+ case 2:
+ display_print_info_2(ctr.printers_2);
+ break;
+ case 3:
+ display_print_info_3(ctr.printers_3);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ if (opened_hnd)
+ cli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/****************************************************************************
+printer info level 0 display function
+****************************************************************************/
+static void display_print_driver_1(DRIVER_INFO_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+
+ printf ("Printer Driver Info 1:\n");
+ printf ("\tDriver Name: [%s]\n\n", name);
+
+ return;
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_print_driver_2(DRIVER_INFO_2 *i1)
+{
+ fstring name;
+ fstring architecture;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
+
+ printf ("Printer Driver Info 2:\n");
+ printf ("\tVersion: [%x]\n", i1->version);
+ printf ("\tDriver Name: [%s]\n", name);
+ printf ("\tArchitecture: [%s]\n", architecture);
+ printf ("\tDriver Path: [%s]\n", driverpath);
+ printf ("\tDatafile: [%s]\n", datafile);
+ printf ("\tConfigfile: [%s]\n\n", configfile);
+
+ return;
+}
+
+/****************************************************************************
+printer info level 2 display function
+****************************************************************************/
+static void display_print_driver_3(DRIVER_INFO_3 *i1)
+{
+ fstring name;
+ fstring architecture;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring dependentfiles;
+ fstring monitorname;
+ fstring defaultdatatype;
+
+ int length=0;
+ BOOL valid = True;
+
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
+ rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), 0, STR_TERMINATE);
+ rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), 0, STR_TERMINATE);
+ rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), 0, STR_TERMINATE);
+
+ printf ("Printer Driver Info 3:\n");
+ printf ("\tVersion: [%x]\n", i1->version);
+ printf ("\tDriver Name: [%s]\n",name);
+ printf ("\tArchitecture: [%s]\n", architecture);
+ printf ("\tDriver Path: [%s]\n", driverpath);
+ printf ("\tDatafile: [%s]\n", datafile);
+ printf ("\tConfigfile: [%s]\n", configfile);
+ printf ("\tHelpfile: [%s]\n\n", helpfile);
+
+ while (valid)
+ {
+ rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), 0, STR_TERMINATE);
+
+ length+=strlen(dependentfiles)+1;
+
+ if (strlen(dependentfiles) > 0)
+ {
+ printf ("\tDependentfiles: [%s]\n", dependentfiles);
+ }
+ else
+ {
+ valid = False;
+ }
+ }
+
+ printf ("\n");
+
+ printf ("\tMonitorname: [%s]\n", monitorname);
+ printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
+
+ return;
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static NTSTATUS cmd_spoolss_getdriver(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result;
+ uint32 info_level = 3;
+ BOOL opened_hnd = False;
+ PRINTER_DRIVER_CTR ctr;
+ fstring printername,
+ servername,
+ user;
+ uint32 i;
+
+ if ((argc == 1) || (argc > 3))
+ {
+ printf("Usage: %s <printername> [level]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* get the arguments need to open the printer handle */
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+ fstrcpy (user, cli->user_name);
+ fstrcpy (printername, argv[1]);
+ if (argc == 3)
+ info_level = atoi(argv[2]);
+
+ /* Open a printer handle */
+ result=cli_spoolss_open_printer_ex (cli, mem_ctx, printername, "",
+ MAXIMUM_ALLOWED_ACCESS, servername, user, &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ printf ("Error opening printer handle for %s!\n", printername);
+ return result;
+ }
+
+ opened_hnd = True;
+
+ /* loop through and print driver info level for each architecture */
+ for (i=0; archi_table[i].long_archi!=NULL; i++)
+ {
+ result = cli_spoolss_getprinterdriver(cli, mem_ctx, &pol, info_level,
+ archi_table[i].long_archi, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ continue;
+ }
+
+
+ printf ("\n[%s]\n", archi_table[i].long_archi);
+ switch (info_level)
+ {
+
+ case 1:
+ display_print_driver_1 (ctr.info1);
+ break;
+ case 2:
+ display_print_driver_2 (ctr.info2);
+ break;
+ case 3:
+ display_print_driver_3 (ctr.info3);
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+
+ /* cleanup */
+ if (opened_hnd)
+ cli_spoolss_close_printer (cli, mem_ctx, &pol);
+
+ return result;
+
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static NTSTATUS cmd_spoolss_enum_drivers(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_OK;
+ uint32 info_level = 1;
+ PRINTER_DRIVER_CTR ctr;
+ fstring servername;
+ uint32 i, j,
+ returned;
+
+ if (argc > 2)
+ {
+ printf("Usage: enumdrivers [level]\n");
+ return NT_STATUS_OK;
+ }
+
+ /* get the arguments need to open the printer handle */
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+
+ /* loop through and print driver info level for each architecture */
+ for (i=0; archi_table[i].long_archi!=NULL; i++)
+ {
+ returned = 0;
+ result = cli_spoolss_enumprinterdrivers (cli, mem_ctx, info_level,
+ archi_table[i].long_archi, &returned, &ctr);
+
+ if (returned == 0)
+ continue;
+
+
+ if (!NT_STATUS_IS_OK(result))
+ {
+ printf ("Error getting driver for environment [%s] - %s\n",
+ archi_table[i].long_archi, get_nt_error_msg(result));
+ continue;
+ }
+
+ printf ("\n[%s]\n", archi_table[i].long_archi);
+ switch (info_level)
+ {
+
+ case 1:
+ for (j=0; j < returned; j++) {
+ display_print_driver_1 (&(ctr.info1[j]));
+ }
+ break;
+ case 2:
+ for (j=0; j < returned; j++) {
+ display_print_driver_2 (&(ctr.info2[j]));
+ }
+ break;
+ case 3:
+ for (j=0; j < returned; j++) {
+ display_print_driver_3 (&(ctr.info3[j]));
+ }
+ break;
+ default:
+ printf("unknown info level %d\n", info_level);
+ break;
+ }
+ }
+
+ return result;
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+
+ printf ("\tDirectory Name:[%s]\n", name);
+}
+
+/***********************************************************************
+ * Get printer driver directory information
+ */
+static NTSTATUS cmd_spoolss_getdriverdir(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ fstring env;
+ DRIVER_DIRECTORY_CTR ctr;
+
+ if (argc > 2)
+ {
+ printf("Usage: %s [environment]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* get the arguments need to open the printer handle */
+ if (argc == 2)
+ fstrcpy (env, argv[1]);
+ else
+ fstrcpy (env, "Windows NT x86");
+
+ /* Get the directory. Only use Info level 1 */
+ result = cli_spoolss_getprinterdriverdir (cli, mem_ctx, 1, env, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+
+ display_printdriverdir_1 (ctr.info1);
+
+ return result;
+}
+
+/*******************************************************************************
+ set the version and environment fields of a DRIVER_INFO_3 struct
+ ******************************************************************************/
+void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
+{
+
+ int i;
+
+ for (i=0; archi_table[i].long_archi != NULL; i++)
+ {
+ if (strcmp(arch, archi_table[i].short_archi) == 0)
+ {
+ info->version = archi_table[i].version;
+ init_unistr (&info->architecture, archi_table[i].long_archi);
+ break;
+ }
+ }
+
+ if (archi_table[i].long_archi == NULL)
+ {
+ DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
+ }
+
+ return;
+}
+
+
+/**************************************************************************
+ wrapper for strtok to get the next parameter from a delimited list.
+ Needed to handle the empty parameter string denoted by "NULL"
+ *************************************************************************/
+static char* get_driver_3_param (char* str, char* delim, UNISTR* dest)
+{
+ char *ptr;
+
+ /* get the next token */
+ ptr = strtok(str, delim);
+
+ /* a string of 'NULL' is used to represent an empty
+ parameter because two consecutive delimiters
+ will not return an empty string. See man strtok(3)
+ for details */
+ if (StrCaseCmp(ptr, "NULL") == 0)
+ ptr = NULL;
+
+ if (dest != NULL)
+ init_unistr(dest, ptr);
+
+ return ptr;
+}
+
+/********************************************************************************
+ fill in the members of a DRIVER_INFO_3 struct using a character
+ string in the form of
+ <Long Printer Name>:<Driver File Name>:<Data File Name>:\
+ <Config File Name>:<Help File Name>:<Language Monitor Name>:\
+ <Default Data Type>:<Comma Separated list of Files>
+ *******************************************************************************/
+static BOOL init_drv_info_3_members (
+ TALLOC_CTX *mem_ctx,
+ DRIVER_INFO_3 *info,
+ char *args
+)
+{
+ char *str, *str2;
+ uint32 len, i;
+
+ /* fill in the UNISTR fields */
+ str = get_driver_3_param (args, ":", &info->name);
+ str = get_driver_3_param (NULL, ":", &info->driverpath);
+ str = get_driver_3_param (NULL, ":", &info->datafile);
+ str = get_driver_3_param (NULL, ":", &info->configfile);
+ str = get_driver_3_param (NULL, ":", &info->helpfile);
+ str = get_driver_3_param (NULL, ":", &info->monitorname);
+ str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
+
+ /* <Comma Separated List of Dependent Files> */
+ str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
+ str = str2;
+
+ /* begin to strip out each filename */
+ str = strtok(str, ",");
+ len = 0;
+ while (str != NULL)
+ {
+ /* keep a cumlative count of the str lengths */
+ len += strlen(str)+1;
+ str = strtok(NULL, ",");
+ }
+
+ /* allocate the space; add one extra slot for a terminating NULL.
+ Each filename is NULL terminated and the end contains a double
+ NULL */
+ if ((info->dependentfiles=(uint16*)talloc(mem_ctx, (len+1)*sizeof(uint16))) == NULL)
+ {
+ DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
+ return False;
+ }
+ for (i=0; i<len; i++)
+ {
+ info->dependentfiles[i] = (uint16)str2[i];
+ }
+ info->dependentfiles[len] = '\0';
+
+ return True;
+}
+
+
+static NTSTATUS cmd_spoolss_addprinterdriver(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ uint32 level = 3;
+ PRINTER_DRIVER_CTR ctr;
+ DRIVER_INFO_3 info3;
+ fstring arch;
+ fstring driver_name;
+
+ /* parse the command arguements */
+ if (argc != 3)
+ {
+ printf ("Usage: %s <Environment>\\\n", argv[0]);
+ printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
+ printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
+ printf ("\t<Default Data Type>:<Comma Separated list of Files>\n");
+
+ return NT_STATUS_OK;
+ }
+
+ /* Fill in the DRIVER_INFO_3 struct */
+ ZERO_STRUCT(info3);
+ if (!get_short_archi(arch, argv[1]))
+ {
+ printf ("Error Unknown architechture [%s]\n", argv[1]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ else
+ set_drv_info_3_env(&info3, arch);
+
+ if (!init_drv_info_3_members(mem_ctx, &info3, argv[2]))
+ {
+ printf ("Error Invalid parameter list - %s.\n", argv[2]);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+
+ ctr.info3 = &info3;
+ result = cli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ rpcstr_pull(driver_name, info3.name.buffer, sizeof(driver_name), 0, STR_TERMINATE);
+ printf ("Printer Driver %s successfully installed.\n", driver_name);
+
+ return result;
+}
+
+
+static NTSTATUS cmd_spoolss_addprinterex(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result;
+ uint32 level = 2;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ fstring servername;
+
+ /* parse the command arguements */
+ if (argc != 5)
+ {
+ printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+
+ /* Fill in the DRIVER_INFO_3 struct */
+ ZERO_STRUCT(info2);
+#if 0 /* JERRY */
+ init_unistr( &info2.servername, servername);
+#endif
+ init_unistr( &info2.printername, argv[1]);
+ init_unistr( &info2.sharename, argv[2]);
+ init_unistr( &info2.drivername, argv[3]);
+ init_unistr( &info2.portname, argv[4]);
+ init_unistr( &info2.comment, "Created by rpcclient");
+ init_unistr( &info2.printprocessor, "winprint");
+ init_unistr( &info2.datatype, "RAW");
+ info2.devmode = NULL;
+ info2.secdesc = NULL;
+ info2.attributes = PRINTER_ATTRIBUTE_SHARED;
+ info2.priority = 0;
+ info2.defaultpriority = 0;
+ info2.starttime = 0;
+ info2.untiltime = 0;
+
+ /* These three fields must not be used by AddPrinter()
+ as defined in the MS Platform SDK documentation..
+ --jerry
+ info2.status = 0;
+ info2.cjobs = 0;
+ info2.averageppm = 0;
+ */
+
+ ctr.printers_2 = &info2;
+ result = cli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ printf ("Printer %s successfully installed.\n", argv[1]);
+
+ return result;
+}
+
+static NTSTATUS cmd_spoolss_setdriver(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ POLICY_HND pol;
+ NTSTATUS result;
+ uint32 level = 2;
+ BOOL opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ PRINTER_INFO_2 info2;
+ fstring servername,
+ printername,
+ user;
+
+ /* parse the command arguements */
+ if (argc != 3)
+ {
+ printf ("Usage: %s <printer> <driver>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+ slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
+ fstrcpy (user, cli->user_name);
+
+ /* get a printer handle */
+ result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ MAXIMUM_ALLOWED_ACCESS, servername, user, &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ opened_hnd = True;
+
+ /* Get printer info */
+ ZERO_STRUCT (info2);
+ ctr.printers_2 = &info2;
+ result = cli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
+ if (!NT_STATUS_IS_OK(result)) {
+ printf ("Unable to retrieve printer information!\n");
+ goto done;
+ }
+
+ /* set the printer driver */
+ init_unistr(&ctr.printers_2->drivername, argv[2]);
+ result = cli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
+ if (!NT_STATUS_IS_OK(result)) {
+ printf ("SetPrinter call failed!\n");
+ goto done;;
+ }
+ printf ("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
+
+
+done:
+ /* cleanup */
+ if (opened_hnd)
+ cli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+
+static NTSTATUS cmd_spoolss_deletedriver(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring servername;
+ int i;
+
+ /* parse the command arguements */
+ if (argc != 2)
+ {
+ printf ("Usage: %s <driver>\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (servername);
+
+ /* delete the driver for all architectures */
+ for (i=0; archi_table[i].long_archi; i++)
+ {
+ /* make the call to remove the driver */
+ result = cli_spoolss_deleteprinterdriver(cli, mem_ctx,
+ archi_table[i].long_archi, argv[1]);
+ if (!NT_STATUS_IS_OK(result)) {
+ printf ("Failed to remove driver %s for arch [%s] - error %s!\n",
+ argv[1], archi_table[i].long_archi, get_nt_error_msg(result));
+ }
+ else
+ printf ("Driver %s removed for arch [%s].\n", argv[1], archi_table[i].long_archi);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_spoolss_getprintprocdir(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ char *servername = NULL, *environment = NULL;
+ fstring procdir;
+
+ /* parse the command arguements */
+ if (argc < 2 || argc > 3) {
+ printf ("Usage: %s <server> [environment]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ asprintf(&servername, "\\\\%s", cli->desthost);
+ strupper(servername);
+
+ asprintf(&environment, "%s", (argc == 3) ? argv[2] :
+ PRINTER_DRIVER_ARCHITECTURE);
+
+ result = cli_spoolss_getprintprocessordirectory(
+ cli, mem_ctx, servername, environment, procdir);
+
+ if (NT_STATUS_IS_OK(result))
+ printf("%s", procdir);
+
+ SAFE_FREE(servername);
+ SAFE_FREE(environment);
+
+ return result;
+}
+
+/* List of commands exported by this module */
+struct cmd_set spoolss_commands[] = {
+
+ { "SPOOLSS" },
+
+ { "adddriver", cmd_spoolss_addprinterdriver, PIPE_SPOOLSS, "Add a print driver", "" },
+ { "addprinter", cmd_spoolss_addprinterex, PIPE_SPOOLSS, "Add a printer", "" },
+ { "deldriver", cmd_spoolss_deletedriver, PIPE_SPOOLSS, "Delete a printer driver", "" },
+ { "enumdata", cmd_spoolss_not_implemented, PIPE_SPOOLSS, "Enumerate printer data (*)", "" },
+ { "enumjobs", cmd_spoolss_not_implemented, PIPE_SPOOLSS, "Enumerate print jobs (*)", "" },
+ { "enumports", cmd_spoolss_enum_ports, PIPE_SPOOLSS, "Enumerate printer ports", "" },
+ { "enumdrivers", cmd_spoolss_enum_drivers, PIPE_SPOOLSS, "Enumerate installed printer drivers", "" },
+ { "enumprinters", cmd_spoolss_enum_printers, PIPE_SPOOLSS, "Enumerate printers", "" },
+ { "getdata", cmd_spoolss_not_implemented, PIPE_SPOOLSS, "Get print driver data (*)", "" },
+ { "getdriver", cmd_spoolss_getdriver, PIPE_SPOOLSS, "Get print driver information", "" },
+ { "getdriverdir", cmd_spoolss_getdriverdir, PIPE_SPOOLSS, "Get print driver upload directory", "" },
+ { "getprinter", cmd_spoolss_getprinter, PIPE_SPOOLSS, "Get printer info", "" },
+ { "openprinter", cmd_spoolss_open_printer_ex, PIPE_SPOOLSS, "Open printer handle", "" },
+ { "setdriver", cmd_spoolss_setdriver, PIPE_SPOOLSS, "Set printer driver", "" },
+ { "getprintprocdir", cmd_spoolss_getprintprocdir, PIPE_SPOOLSS, "Get print processor directory", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_srvsvc.c b/source/rpcclient/cmd_srvsvc.c
new file mode 100644
index 00000000000..f4ff11adf13
--- /dev/null
+++ b/source/rpcclient/cmd_srvsvc.c
@@ -0,0 +1,234 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/* Display server query info */
+
+static char *get_server_type_str(uint32 type)
+{
+ static fstring typestr;
+ int i;
+
+ if (type == SV_TYPE_ALL) {
+ fstrcpy(typestr, "All");
+ return typestr;
+ }
+
+ typestr[0] = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (type & (1 << i)) {
+ switch (1 << i) {
+ case SV_TYPE_WORKSTATION:
+ fstrcat(typestr, "Wk ");
+ break;
+ case SV_TYPE_SERVER:
+ fstrcat(typestr, "Sv ");
+ break;
+ case SV_TYPE_SQLSERVER:
+ fstrcat(typestr, "Sql ");
+ break;
+ case SV_TYPE_DOMAIN_CTRL:
+ fstrcat(typestr, "PDC ");
+ break;
+ case SV_TYPE_DOMAIN_BAKCTRL:
+ fstrcat(typestr, "BDC ");
+ break;
+ case SV_TYPE_TIME_SOURCE:
+ fstrcat(typestr, "Tim ");
+ break;
+ case SV_TYPE_AFP:
+ fstrcat(typestr, "AFP ");
+ break;
+ case SV_TYPE_NOVELL:
+ fstrcat(typestr, "Nov ");
+ break;
+ case SV_TYPE_DOMAIN_MEMBER:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_PRINTQ_SERVER:
+ fstrcat(typestr, "PrQ ");
+ break;
+ case SV_TYPE_DIALIN_SERVER:
+ fstrcat(typestr, "Din ");
+ break;
+ case SV_TYPE_SERVER_UNIX:
+ fstrcat(typestr, "Unx ");
+ break;
+ case SV_TYPE_NT:
+ fstrcat(typestr, "NT ");
+ break;
+ case SV_TYPE_WFW:
+ fstrcat(typestr, "Wfw ");
+ break;
+ case SV_TYPE_SERVER_MFPN:
+ fstrcat(typestr, "Mfp ");
+ break;
+ case SV_TYPE_SERVER_NT:
+ fstrcat(typestr, "SNT ");
+ break;
+ case SV_TYPE_POTENTIAL_BROWSER:
+ fstrcat(typestr, "PtB ");
+ break;
+ case SV_TYPE_BACKUP_BROWSER:
+ fstrcat(typestr, "BMB ");
+ break;
+ case SV_TYPE_MASTER_BROWSER:
+ fstrcat(typestr, "LMB ");
+ break;
+ case SV_TYPE_DOMAIN_MASTER:
+ fstrcat(typestr, "DMB ");
+ break;
+ case SV_TYPE_SERVER_OSF:
+ fstrcat(typestr, "OSF ");
+ break;
+ case SV_TYPE_SERVER_VMS:
+ fstrcat(typestr, "VMS ");
+ break;
+ case SV_TYPE_WIN95_PLUS:
+ fstrcat(typestr, "W95 ");
+ break;
+ case SV_TYPE_ALTERNATE_XPORT:
+ fstrcat(typestr, "Xpt ");
+ break;
+ case SV_TYPE_LOCAL_LIST_ONLY:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_DOMAIN_ENUM:
+ fstrcat(typestr, "Loc ");
+ break;
+ }
+ }
+ }
+
+ i = strlen(typestr) - 1;
+
+ if (typestr[i] == ' ')
+ typestr[i] = 0;
+
+ return typestr;
+}
+
+static void display_server(char *sname, uint32 type, const char *comment)
+{
+ printf("\t%-15.15s%-20s %s\n", sname, get_server_type_str(type),
+ comment);
+}
+
+static void display_srv_info_101(SRV_INFO_101 *sv101)
+{
+ fstring name;
+ fstring comment;
+
+ unistr2_to_ascii(name, &sv101->uni_name, sizeof(name) - 1);
+ unistr2_to_ascii(comment, &sv101->uni_comment, sizeof(comment) - 1);
+
+ display_server(name, sv101->srv_type, comment);
+
+ printf("\tplatform_id :\t%d\n", sv101->platform_id);
+ printf("\tos version :\t%d.%d\n", sv101->ver_major,
+ sv101->ver_minor);
+
+ printf("\tserver type :\t0x%x\n", sv101->srv_type);
+}
+
+static void display_srv_info_102(SRV_INFO_102 *sv102)
+{
+ fstring name;
+ fstring comment;
+ fstring usr_path;
+
+ unistr2_to_ascii(name, &sv102->uni_name, sizeof(name) - 1);
+ unistr2_to_ascii(comment, &sv102->uni_comment, sizeof(comment) - 1);
+ unistr2_to_ascii(usr_path, &sv102->uni_usr_path, sizeof(usr_path) - 1);
+
+ display_server(name, sv102->srv_type, comment);
+
+ printf("\tplatform_id :\t%d\n", sv102->platform_id);
+ printf("\tos version :\t%d.%d\n", sv102->ver_major,
+ sv102->ver_minor);
+
+ printf("\tusers :\t%x\n", sv102->users);
+ printf("\tdisc, hidden :\t%x, %x\n", sv102->disc, sv102->hidden);
+ printf("\tannounce, delta :\t%d, %d\n", sv102->announce,
+ sv102->ann_delta);
+ printf("\tlicenses :\t%d\n", sv102->licenses);
+ printf("\tuser path :\t%s\n", usr_path);
+}
+
+/* Server query info */
+
+static NTSTATUS cmd_srvsvc_srv_query_info(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ uint32 info_level = 101;
+ SRV_INFO_CTR ctr;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 2) {
+ printf("Usage: %s [infolevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ result = cli_srvsvc_net_srv_get_info(cli, mem_ctx, info_level,
+ &ctr);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ switch (info_level) {
+ case 101:
+ display_srv_info_101(&ctr.srv.sv101);
+ break;
+ case 102:
+ display_srv_info_102(&ctr.srv.sv102);
+ break;
+ default:
+ printf("unsupported info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set srvsvc_commands[] = {
+
+ { "SRVSVC" },
+
+ { "srvinfo", cmd_srvsvc_srv_query_info, PIPE_SRVSVC, "Server query info", "" },
+
+ { NULL }
+};
diff --git a/source/rpcclient/cmd_wkssvc.c b/source/rpcclient/cmd_wkssvc.c
new file mode 100644
index 00000000000..52c110dbd56
--- /dev/null
+++ b/source/rpcclient/cmd_wkssvc.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define DEBUG_TESTING
+
+extern struct cli_state *smb_cli;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+workstation get info query
+****************************************************************************/
+void cmd_wks_query_info(struct client_info *info)
+{
+ fstring dest_wks;
+ fstring tmp;
+ WKS_INFO_100 ctr;
+ uint32 info_level = 100;
+
+ BOOL res = True;
+
+ memset((char *)&ctr, '\0', sizeof(ctr));
+
+ fstrcpy(dest_wks, "\\\\");
+ fstrcat(dest_wks, info->dest_host);
+ strupper(dest_wks);
+
+ if (next_token_nr(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ info_level = (uint32)strtol(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_wks_query_info: server:%s info level: %d\n",
+ dest_wks, info_level));
+
+ DEBUG(5, ("cmd_wks_query_info: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open LSARPC session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_WKSSVC) : False;
+
+ /* send info level: receive requested info. hopefully. */
+ res = res ? do_wks_query_info(smb_cli,
+ dest_wks, info_level, &ctr) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_wks_query_info: query succeeded\n"));
+
+#if 0
+ display_wks_info_100(out_hnd, ACTION_HEADER , &ctr);
+ display_wks_info_100(out_hnd, ACTION_ENUMERATE, &ctr);
+ display_wks_info_100(out_hnd, ACTION_FOOTER , &ctr);
+#endif
+
+ }
+ else
+ {
+ DEBUG(5,("cmd_wks_query_info: query failed\n"));
+ }
+}
diff --git a/source/rpcclient/display.c b/source/rpcclient/display.c
new file mode 100644
index 00000000000..345ed7d49af
--- /dev/null
+++ b/source/rpcclient/display.c
@@ -0,0 +1,1339 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/****************************************************************************
+convert a share mode to a string
+****************************************************************************/
+char *get_file_mode_str(uint32 share_mode)
+{
+ static fstring mode;
+
+ switch (GET_DENY_MODE(share_mode))
+ {
+ case DENY_NONE : fstrcpy(mode, "DENY_NONE "); break;
+ case DENY_ALL : fstrcpy(mode, "DENY_ALL "); break;
+ case DENY_DOS : fstrcpy(mode, "DENY_DOS "); break;
+ case DENY_READ : fstrcpy(mode, "DENY_READ "); break;
+ case DENY_WRITE: fstrcpy(mode, "DENY_WRITE "); break;
+ case DENY_FCB: fstrcpy(mode, "DENY_FCB "); break;
+ default : fstrcpy(mode, "DENY_???? "); break;
+ }
+
+ switch (share_mode & 0xF)
+ {
+ case 0 : fstrcat(mode, "RDONLY"); break;
+ case 1 : fstrcat(mode, "WRONLY"); break;
+ case 2 : fstrcat(mode, "RDWR "); break;
+ default: fstrcat(mode, "R??W??"); break;
+ }
+
+ return mode;
+}
+
+/****************************************************************************
+convert an oplock mode to a string
+****************************************************************************/
+char *get_file_oplock_str(uint32 op_type)
+{
+ static fstring oplock;
+ BOOL excl = ((op_type & EXCLUSIVE_OPLOCK) != 0);
+ BOOL batch = ((op_type & BATCH_OPLOCK ) != 0);
+
+ oplock[0] = 0;
+
+ if (excl ) fstrcat(oplock, "EXCLUSIVE");
+ if (excl && batch) fstrcat(oplock, "+");
+ if ( batch) fstrcat(oplock, "BATCH");
+ if (!excl && !batch) fstrcat(oplock, "NONE");
+
+ return oplock;
+}
+
+/****************************************************************************
+convert a share type enum to a string
+****************************************************************************/
+char *get_share_type_str(uint32 type)
+{
+ static fstring typestr;
+
+ switch (type)
+ {
+ case STYPE_DISKTREE: fstrcpy(typestr, "Disk" ); break;
+ case STYPE_PRINTQ : fstrcpy(typestr, "Printer"); break;
+ case STYPE_DEVICE : fstrcpy(typestr, "Device" ); break;
+ case STYPE_IPC : fstrcpy(typestr, "IPC" ); break;
+ default : fstrcpy(typestr, "????" ); break;
+ }
+ return typestr;
+}
+
+/****************************************************************************
+convert a server type enum to a string
+****************************************************************************/
+char *get_server_type_str(uint32 type)
+{
+ static fstring typestr;
+
+ if (type == SV_TYPE_ALL)
+ {
+ fstrcpy(typestr, "All");
+ }
+ else
+ {
+ int i;
+ typestr[0] = 0;
+ for (i = 0; i < 32; i++)
+ {
+ if (type & (1 << i))
+ {
+ switch (((unsigned)1) << i)
+ {
+ case SV_TYPE_WORKSTATION : fstrcat(typestr, "Wk " ); break;
+ case SV_TYPE_SERVER : fstrcat(typestr, "Sv " ); break;
+ case SV_TYPE_SQLSERVER : fstrcat(typestr, "Sql "); break;
+ case SV_TYPE_DOMAIN_CTRL : fstrcat(typestr, "PDC "); break;
+ case SV_TYPE_DOMAIN_BAKCTRL : fstrcat(typestr, "BDC "); break;
+ case SV_TYPE_TIME_SOURCE : fstrcat(typestr, "Tim "); break;
+ case SV_TYPE_AFP : fstrcat(typestr, "AFP "); break;
+ case SV_TYPE_NOVELL : fstrcat(typestr, "Nov "); break;
+ case SV_TYPE_DOMAIN_MEMBER : fstrcat(typestr, "Dom "); break;
+ case SV_TYPE_PRINTQ_SERVER : fstrcat(typestr, "PrQ "); break;
+ case SV_TYPE_DIALIN_SERVER : fstrcat(typestr, "Din "); break;
+ case SV_TYPE_SERVER_UNIX : fstrcat(typestr, "Unx "); break;
+ case SV_TYPE_NT : fstrcat(typestr, "NT " ); break;
+ case SV_TYPE_WFW : fstrcat(typestr, "Wfw "); break;
+ case SV_TYPE_SERVER_MFPN : fstrcat(typestr, "Mfp "); break;
+ case SV_TYPE_SERVER_NT : fstrcat(typestr, "SNT "); break;
+ case SV_TYPE_POTENTIAL_BROWSER: fstrcat(typestr, "PtB "); break;
+ case SV_TYPE_BACKUP_BROWSER : fstrcat(typestr, "BMB "); break;
+ case SV_TYPE_MASTER_BROWSER : fstrcat(typestr, "LMB "); break;
+ case SV_TYPE_DOMAIN_MASTER : fstrcat(typestr, "DMB "); break;
+ case SV_TYPE_SERVER_OSF : fstrcat(typestr, "OSF "); break;
+ case SV_TYPE_SERVER_VMS : fstrcat(typestr, "VMS "); break;
+ case SV_TYPE_WIN95_PLUS : fstrcat(typestr, "W95 "); break;
+ case SV_TYPE_ALTERNATE_XPORT : fstrcat(typestr, "Xpt "); break;
+ case SV_TYPE_LOCAL_LIST_ONLY : fstrcat(typestr, "Dom "); break;
+ case SV_TYPE_DOMAIN_ENUM : fstrcat(typestr, "Loc "); break;
+ }
+ }
+ }
+ i = strlen(typestr)-1;
+ if (typestr[i] == ' ') typestr[i] = 0;
+
+ }
+ return typestr;
+}
+
+/****************************************************************************
+server info level 101 display function
+****************************************************************************/
+void display_srv_info_101(FILE *out_hnd, enum action_type action,
+ SRV_INFO_101 *sv101)
+{
+ if (sv101 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Server Info Level 101:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring name;
+ fstring comment;
+
+ rpcstr_pull(name, sv101->uni_name.buffer, sizeof(name), sv101->uni_name.uni_str_len*2, 0);
+ rpcstr_pull(comment, sv101->uni_comment.buffer, sizeof(comment), sv101->uni_comment.uni_str_len*2, 0);
+
+ display_server(out_hnd, action, name, sv101->srv_type, comment);
+
+ fprintf(out_hnd, "\tplatform_id : %d\n" , sv101->platform_id);
+ fprintf(out_hnd, "\tos version : %d.%d\n" , sv101->ver_major, sv101->ver_minor);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+server info level 102 display function
+****************************************************************************/
+void display_srv_info_102(FILE *out_hnd, enum action_type action,SRV_INFO_102 *sv102)
+{
+ if (sv102 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Server Info Level 102:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring name;
+ fstring comment;
+ fstring usr_path;
+
+ rpcstr_pull(name, sv102->uni_name.buffer, sizeof(name), sv102->uni_name.uni_str_len*2, 0);
+ rpcstr_pull(comment, sv102->uni_comment.buffer, sizeof(comment), sv102->uni_comment.uni_str_len*2, 0);
+ rpcstr_pull(usr_path, sv102->uni_usr_path.buffer, sizeof(usr_path), sv102->uni_usr_path.uni_str_len*2, 0);
+
+ display_server(out_hnd, action, name, sv102->srv_type, comment);
+
+ fprintf(out_hnd, "\tplatform_id : %d\n" , sv102->platform_id);
+ fprintf(out_hnd, "\tos version : %d.%d\n" , sv102->ver_major, sv102->ver_minor);
+
+ fprintf(out_hnd, "\tusers : %x\n" , sv102->users );
+ fprintf(out_hnd, "\tdisc, hidden : %x,%x\n" , sv102->disc , sv102->hidden );
+ fprintf(out_hnd, "\tannounce, delta : %d, %d\n", sv102->announce , sv102->ann_delta);
+ fprintf(out_hnd, "\tlicenses : %d\n" , sv102->licenses );
+ fprintf(out_hnd, "\tuser path : %s\n" , usr_path);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+server info container display function
+****************************************************************************/
+void display_srv_info_ctr(FILE *out_hnd, enum action_type action,SRV_INFO_CTR *ctr)
+{
+ if (ctr == NULL || ctr->ptr_srv_ctr == 0)
+ {
+ fprintf(out_hnd, "Server Information: unavailable due to an error\n");
+ return;
+ }
+
+ switch (ctr->switch_value)
+ {
+ case 101:
+ {
+ display_srv_info_101(out_hnd, action, &(ctr->srv.sv101));
+ break;
+ }
+ case 102:
+ {
+ display_srv_info_102(out_hnd, action, &(ctr->srv.sv102));
+ break;
+ }
+ default:
+ {
+ fprintf(out_hnd, "Server Information: Unknown Info Level\n");
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+connection info level 0 display function
+****************************************************************************/
+void display_conn_info_0(FILE *out_hnd, enum action_type action,
+ CONN_INFO_0 *info0)
+{
+ if (info0 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Connection Info Level 0:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\tid: %d\n", info0->id);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+connection info level 1 display function
+****************************************************************************/
+void display_conn_info_1(FILE *out_hnd, enum action_type action,
+ CONN_INFO_1 *info1, CONN_INFO_1_STR *str1)
+{
+ if (info1 == NULL || str1 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Connection Info Level 1:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring usr_name;
+ fstring net_name;
+
+ rpcstr_pull(usr_name, str1->uni_usr_name.buffer, sizeof(usr_name), str1->uni_usr_name.uni_str_len*2,0);
+ rpcstr_pull(net_name, str1->uni_net_name.buffer, sizeof(net_name), str1->uni_net_name.uni_str_len*2,0);
+
+ fprintf(out_hnd, "\tid : %d\n", info1->id);
+ fprintf(out_hnd, "\ttype : %s\n", get_share_type_str(info1->type));
+ fprintf(out_hnd, "\tnum_opens: %d\n", info1->num_opens);
+ fprintf(out_hnd, "\tnum_users: %d\n", info1->num_users);
+ fprintf(out_hnd, "\topen_time: %d\n", info1->open_time);
+
+ fprintf(out_hnd, "\tuser name: %s\n", usr_name);
+ fprintf(out_hnd, "\tnet name: %s\n", net_name);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+connection info level 0 container display function
+****************************************************************************/
+void display_srv_conn_info_0_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_0 *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_conn_info_0_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < ctr->num_entries_read; i++)
+ {
+ display_conn_info_0(out_hnd, ACTION_HEADER , &(ctr->info_0[i]));
+ display_conn_info_0(out_hnd, ACTION_ENUMERATE, &(ctr->info_0[i]));
+ display_conn_info_0(out_hnd, ACTION_FOOTER , &(ctr->info_0[i]));
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+connection info level 1 container display function
+****************************************************************************/
+void display_srv_conn_info_1_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_1 *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_conn_info_1_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < ctr->num_entries_read; i++)
+ {
+ display_conn_info_1(out_hnd, ACTION_HEADER , &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ display_conn_info_1(out_hnd, ACTION_ENUMERATE, &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ display_conn_info_1(out_hnd, ACTION_FOOTER , &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_srv_conn_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_CTR *ctr)
+{
+ if (ctr == NULL || ctr->ptr_conn_ctr == 0)
+ {
+ fprintf(out_hnd, "display_srv_conn_info_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (ctr->switch_value)
+ {
+ case 0:
+ {
+ display_srv_conn_info_0_ctr(out_hnd, action,
+ &(ctr->conn.info0));
+ break;
+ }
+ case 1:
+ {
+ display_srv_conn_info_1_ctr(out_hnd, action,
+ &(ctr->conn.info1));
+ break;
+ }
+ default:
+ {
+ fprintf(out_hnd, "display_srv_conn_info_ctr: Unknown Info Level\n");
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+share info level 1 display function
+****************************************************************************/
+void display_share_info_1(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_1 *info1)
+{
+ if (info1 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Share Info Level 1:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring remark ;
+ fstring net_name;
+
+ rpcstr_pull(net_name, info1->info_1_str.uni_netname.buffer, sizeof(net_name), info1->info_1_str.uni_netname.uni_str_len*2, 0);
+ rpcstr_pull(remark, info1->info_1_str.uni_remark.buffer, sizeof(remark), info1->info_1_str.uni_remark.uni_str_len*2, 0);
+
+ display_share(out_hnd, action, net_name, info1->info_1.type, remark);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+share info level 2 display function
+****************************************************************************/
+void display_share_info_2(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_2 *info2)
+{
+ if (info2 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Share Info Level 2:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring remark ;
+ fstring net_name;
+ fstring path ;
+ fstring passwd ;
+
+ rpcstr_pull(net_name, info2->info_2_str.uni_netname.buffer, sizeof(net_name), info2->info_2_str.uni_netname.uni_str_len*2, 0);
+ rpcstr_pull(remark, info2->info_2_str.uni_remark.buffer, sizeof(remark), info2->info_2_str.uni_remark.uni_str_len*2, 0);
+ rpcstr_pull(path, info2->info_2_str.uni_path.buffer, sizeof(path), info2->info_2_str.uni_path.uni_str_len*2, 0);
+ rpcstr_pull(passwd, info2->info_2_str.uni_passwd.buffer, sizeof(passwd), info2->info_2_str.uni_passwd.uni_str_len*2, 0);
+
+ display_share2(out_hnd, action, net_name,
+ info2->info_2.type, remark, info2->info_2.perms,
+ info2->info_2.max_uses, info2->info_2.num_uses,
+ path, passwd);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+share info container display function
+****************************************************************************/
+void display_srv_share_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_CTR *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_share_info_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < ctr->num_entries; i++)
+ {
+ switch (ctr->info_level) {
+ case 1:
+ display_share_info_1(out_hnd, ACTION_HEADER , &(ctr->share.info1[i]));
+ display_share_info_1(out_hnd, ACTION_ENUMERATE, &(ctr->share.info1[i]));
+ display_share_info_1(out_hnd, ACTION_FOOTER , &(ctr->share.info1[i]));
+ break;
+ case 2:
+ display_share_info_2(out_hnd, ACTION_HEADER , &(ctr->share.info2[i]));
+ display_share_info_2(out_hnd, ACTION_ENUMERATE, &(ctr->share.info2[i]));
+ display_share_info_2(out_hnd, ACTION_FOOTER , &(ctr->share.info2[i]));
+ break;
+ default:
+ fprintf(out_hnd, "display_srv_share_info_ctr: Unknown Info Level\n");
+ break;
+ }
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+file info level 3 display function
+****************************************************************************/
+void display_file_info_3(FILE *out_hnd, enum action_type action,
+ FILE_INFO_3 *info3, FILE_INFO_3_STR *str3)
+{
+ if (info3 == NULL || str3 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "File Info Level 3:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring path_name;
+ fstring user_name;
+
+ rpcstr_pull(path_name, str3->uni_path_name.buffer, sizeof(path_name), str3->uni_path_name.uni_str_len*2, 0);
+ rpcstr_pull(user_name, str3->uni_user_name.buffer, sizeof(user_name), str3->uni_user_name.uni_str_len*2, 0);
+
+ fprintf(out_hnd, "\tid : %d\n", info3->id);
+ fprintf(out_hnd, "\tperms : %s\n", get_file_mode_str(info3->perms));
+ fprintf(out_hnd, "\tnum_locks: %d\n", info3->num_locks);
+
+ fprintf(out_hnd, "\tpath name: %s\n", path_name);
+ fprintf(out_hnd, "\tuser name: %s\n", user_name);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+file info level 3 container display function
+****************************************************************************/
+void display_srv_file_info_3_ctr(FILE *out_hnd, enum action_type action,
+ SRV_FILE_INFO_3 *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_file_info_3_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < ctr->num_entries_read; i++)
+ {
+ display_file_info_3(out_hnd, ACTION_HEADER , &(ctr->info_3[i]), &(ctr->info_3_str[i]));
+ display_file_info_3(out_hnd, ACTION_ENUMERATE, &(ctr->info_3[i]), &(ctr->info_3_str[i]));
+ display_file_info_3(out_hnd, ACTION_FOOTER , &(ctr->info_3[i]), &(ctr->info_3_str[i]));
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+file info container display function
+****************************************************************************/
+void display_srv_file_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_FILE_INFO_CTR *ctr)
+{
+ if (ctr == NULL || ctr->ptr_file_ctr == 0)
+ {
+ fprintf(out_hnd, "display_srv_file_info_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (ctr->switch_value)
+ {
+ case 3:
+ {
+ display_srv_file_info_3_ctr(out_hnd, action,
+ &(ctr->file.info3));
+ break;
+ }
+ default:
+ {
+ fprintf(out_hnd, "display_srv_file_info_ctr: Unknown Info Level\n");
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ print browse connection on a host
+ ****************************************************************************/
+void display_server(FILE *out_hnd, enum action_type action,
+ char *sname, uint32 type, char *comment)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t%-15.15s%-20s %s\n",
+ sname, get_server_type_str(type), comment);
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+print shares on a host
+****************************************************************************/
+void display_share(FILE *out_hnd, enum action_type action,
+ char *sname, uint32 type, char *comment)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t%-15.15s%-10.10s%s\n",
+ sname, get_share_type_str(type), comment);
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+print shares on a host, level 2
+****************************************************************************/
+void display_share2(FILE *out_hnd, enum action_type action,
+ char *sname, uint32 type, char *comment,
+ uint32 perms, uint32 max_uses, uint32 num_uses,
+ char *path, char *passwd)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t%-15.15s%-10.10s%s %x %x %x %s %s\n",
+ sname, get_share_type_str(type), comment,
+ perms, max_uses, num_uses, path, passwd);
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+print name info
+****************************************************************************/
+void display_name(FILE *out_hnd, enum action_type action,
+ char *sname)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t%-21.21s\n", sname);
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ display group rid info
+ ****************************************************************************/
+void display_group_rid_info(FILE *out_hnd, enum action_type action,
+ uint32 num_gids, DOM_GID *gid)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ if (num_gids == 0)
+ {
+ fprintf(out_hnd, "\tNo Groups\n");
+ }
+ else
+ {
+ fprintf(out_hnd, "\tGroup Info\n");
+ fprintf(out_hnd, "\t----------\n");
+ }
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < num_gids; i++)
+ {
+ fprintf(out_hnd, "\tGroup RID: %8x attr: %x\n",
+ gid[i].g_rid, gid[i].attr);
+ }
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ display alias name info
+ ****************************************************************************/
+void display_alias_name_info(FILE *out_hnd, enum action_type action,
+ uint32 num_aliases, fstring *alias_name, uint32 *num_als_usrs)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ if (num_aliases == 0)
+ {
+ fprintf(out_hnd, "\tNo Aliases\n");
+ }
+ else
+ {
+ fprintf(out_hnd, "\tAlias Names\n");
+ fprintf(out_hnd, "\t----------- \n");
+ }
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < num_aliases; i++)
+ {
+ fprintf(out_hnd, "\tAlias Name: %s Attributes: %3d\n",
+ alias_name[i], num_als_usrs[i]);
+ }
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ display sam_user_info_21 structure
+ ****************************************************************************/
+void display_sam_user_info_21(FILE *out_hnd, enum action_type action, SAM_USER_INFO_21 *usr)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "\tUser Info, Level 0x15\n");
+ fprintf(out_hnd, "\t---------------------\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ pstring tmp;
+ rpcstr_pull(tmp, usr->uni_user_name.buffer, sizeof(tmp),usr->uni_user_name.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tUser Name : %s\n", tmp); /* username unicode string */
+ rpcstr_pull(tmp, usr->uni_full_name.buffer, sizeof(tmp),usr->uni_full_name.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tFull Name : %s\n", tmp); /* user's full name unicode string */
+ rpcstr_pull(tmp, usr->uni_home_dir.buffer, sizeof(tmp),usr->uni_home_dir.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tHome Drive : %s\n", tmp); /* home directory unicode string */
+ rpcstr_pull(tmp, usr->uni_dir_drive.buffer, sizeof(tmp),usr->uni_dir_drive.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tDir Drive : %s\n", tmp); /* home directory drive unicode string */
+ rpcstr_pull(tmp, usr->uni_profile_path.buffer, sizeof(tmp),usr->uni_profile_path.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tProfile Path: %s\n", tmp); /* profile path unicode string */
+ rpcstr_pull(tmp, usr->uni_logon_script.buffer, sizeof(tmp),usr->uni_logon_script.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tLogon Script: %s\n", tmp); /* logon script unicode string */
+ rpcstr_pull(tmp, usr->uni_acct_desc.buffer, sizeof(tmp),usr->uni_acct_desc.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tDescription : %s\n", tmp); /* user description unicode string */
+ rpcstr_pull(tmp, usr->uni_workstations.buffer, sizeof(tmp),usr->uni_workstations.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tWorkstations: %s\n", tmp); /* workstaions unicode string */
+ rpcstr_pull(tmp, usr->uni_unknows_str.buffer, sizeof(tmp),usr->uni_unknown_str.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tUnknown Str : %s\n", tmp); /* unknown string unicode string */
+ rpcstr_pull(tmp, usr->uni_munged_dial.buffer, sizeof(tmp),usr->uni_munged_dial.uni_str_len*2, 0);
+ fprintf(out_hnd, "\t\tRemote Dial : %s\n", tmp); /* munged remote access unicode string */
+
+ fprintf(out_hnd, "\t\tLogon Time : %s\n", http_timestring(nt_time_to_unix(&(usr->logon_time ))));
+ fprintf(out_hnd, "\t\tLogoff Time : %s\n", http_timestring(nt_time_to_unix(&(usr->logoff_time ))));
+ fprintf(out_hnd, "\t\tKickoff Time : %s\n", http_timestring(nt_time_to_unix(&(usr->kickoff_time ))));
+ fprintf(out_hnd, "\t\tPassword last set Time : %s\n", http_timestring(nt_time_to_unix(&(usr->pass_last_set_time ))));
+ fprintf(out_hnd, "\t\tPassword can change Time : %s\n", http_timestring(nt_time_to_unix(&(usr->pass_can_change_time ))));
+ fprintf(out_hnd, "\t\tPassword must change Time: %s\n", http_timestring(nt_time_to_unix(&(usr->pass_must_change_time))));
+
+ fprintf(out_hnd, "\t\tunknown_2[0..31]...\n"); /* user passwords? */
+
+ fprintf(out_hnd, "\t\tuser_rid : %x\n" , usr->user_rid ); /* User ID */
+ fprintf(out_hnd, "\t\tgroup_rid: %x\n" , usr->group_rid); /* Group ID */
+ fprintf(out_hnd, "\t\tacb_info : %04x\n", usr->acb_info ); /* Account Control Info */
+
+ fprintf(out_hnd, "\t\tunknown_3: %08x\n", usr->unknown_3); /* 0x00ff ffff */
+ fprintf(out_hnd, "\t\tlogon_divs: %d\n", usr->logon_divs); /* 0x0000 00a8 which is 168 which is num hrs in a week */
+ fprintf(out_hnd, "\t\tunknown_5: %08x\n", usr->unknown_5); /* 0x0002 0000 */
+
+ fprintf(out_hnd, "\t\tpadding1[0..7]...\n");
+
+ if (usr->ptr_logon_hrs)
+ {
+ fprintf(out_hnd, "\t\tlogon_hrs[0..%d]...\n", usr->logon_hrs.len);
+ }
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+char *get_sec_mask_str(uint32 type)
+{
+ static fstring typestr;
+ int i;
+
+ switch (type)
+ {
+ case SEC_RIGHTS_FULL_CONTROL:
+ {
+ fstrcpy(typestr, "Full Control");
+ return typestr;
+ }
+
+ case SEC_RIGHTS_READ:
+ {
+ fstrcpy(typestr, "Read");
+ return typestr;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ typestr[0] = 0;
+ for (i = 0; i < 32; i++)
+ {
+ if (type & (1 << i))
+ {
+ switch (((unsigned)1) << i)
+ {
+ case SEC_RIGHTS_QUERY_VALUE : fstrcat(typestr, "Query " ); break;
+ case SEC_RIGHTS_SET_VALUE : fstrcat(typestr, "Set " ); break;
+ case SEC_RIGHTS_CREATE_SUBKEY : fstrcat(typestr, "Create "); break;
+ case SEC_RIGHTS_ENUM_SUBKEYS : fstrcat(typestr, "Enum "); break;
+ case SEC_RIGHTS_NOTIFY : fstrcat(typestr, "Notify "); break;
+ case SEC_RIGHTS_CREATE_LINK : fstrcat(typestr, "CreateLink "); break;
+ case SEC_RIGHTS_DELETE : fstrcat(typestr, "Delete "); break;
+ case SEC_RIGHTS_READ_CONTROL : fstrcat(typestr, "ReadControl "); break;
+ case SEC_RIGHTS_WRITE_DAC : fstrcat(typestr, "WriteDAC "); break;
+ case SEC_RIGHTS_WRITE_OWNER : fstrcat(typestr, "WriteOwner "); break;
+ }
+ type &= ~(1 << i);
+ }
+ }
+
+ /* remaining bits get added on as-is */
+ if (type != 0)
+ {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp)-1, "[%08x]", type);
+ fstrcat(typestr, tmp);
+ }
+
+ /* remove last space */
+ i = strlen(typestr)-1;
+ if (typestr[i] == ' ') typestr[i] = 0;
+
+ return typestr;
+}
+
+/****************************************************************************
+ display sec_access structure
+ ****************************************************************************/
+void display_sec_access(FILE *out_hnd, enum action_type action, SEC_ACCESS *info)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t\tPermissions: %s\n",
+ get_sec_mask_str(info->mask));
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ display sec_ace structure
+ ****************************************************************************/
+void display_sec_ace(FILE *out_hnd, enum action_type action, SEC_ACE *ace)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "\tACE\n");
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring sid_str;
+
+ display_sec_access(out_hnd, ACTION_HEADER , &ace->info);
+ display_sec_access(out_hnd, ACTION_ENUMERATE, &ace->info);
+ display_sec_access(out_hnd, ACTION_FOOTER , &ace->info);
+
+ sid_to_string(sid_str, &ace->sid);
+ fprintf(out_hnd, "\t\tSID: %s\n", sid_str);
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ display sec_acl structure
+ ****************************************************************************/
+void display_sec_acl(FILE *out_hnd, enum action_type action, SEC_ACL *sec_acl)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "\tACL\tNum ACEs:\t%d\trevision:\t%x\n",
+ sec_acl->num_aces, sec_acl->revision);
+ fprintf(out_hnd, "\t---\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ if (sec_acl->size != 0 && sec_acl->num_aces != 0)
+ {
+ int i;
+ for (i = 0; i < sec_acl->num_aces; i++)
+ {
+ display_sec_ace(out_hnd, ACTION_HEADER , &sec_acl->ace[i]);
+ display_sec_ace(out_hnd, ACTION_ENUMERATE, &sec_acl->ace[i]);
+ display_sec_ace(out_hnd, ACTION_FOOTER , &sec_acl->ace[i]);
+ }
+ }
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ display sec_desc structure
+ ****************************************************************************/
+void display_sec_desc(FILE *out_hnd, enum action_type action, SEC_DESC *sec)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "\tSecurity Descriptor\trevision:\t%x\ttype:\t%x\n",
+ sec->revision, sec->type);
+ fprintf(out_hnd, "\t-------------------\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring sid_str;
+
+ if (sec->off_sacl != 0)
+ {
+ display_sec_acl(out_hnd, ACTION_HEADER , sec->sacl);
+ display_sec_acl(out_hnd, ACTION_ENUMERATE, sec->sacl);
+ display_sec_acl(out_hnd, ACTION_FOOTER , sec->sacl);
+ }
+ if (sec->off_dacl != 0)
+ {
+ display_sec_acl(out_hnd, ACTION_HEADER , sec->dacl);
+ display_sec_acl(out_hnd, ACTION_ENUMERATE, sec->dacl);
+ display_sec_acl(out_hnd, ACTION_FOOTER , sec->dacl);
+ }
+ if (sec->off_owner_sid != 0)
+ {
+ sid_to_string(sid_str, sec->owner_sid);
+ fprintf(out_hnd, "\tOwner SID:\t%s\n", sid_str);
+ }
+ if (sec->off_grp_sid != 0)
+ {
+ sid_to_string(sid_str, sec->grp_sid);
+ fprintf(out_hnd, "\tParent SID:\t%s\n", sid_str);
+ }
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+char *get_reg_val_type_str(uint32 type)
+{
+ static fstring typestr;
+
+ switch (type)
+ {
+ case 0x01:
+ {
+ fstrcpy(typestr, "string");
+ return typestr;
+ }
+
+ case 0x03:
+ {
+ fstrcpy(typestr, "bytes");
+ return typestr;
+ }
+
+ case 0x04:
+ {
+ fstrcpy(typestr, "uint32");
+ return typestr;
+ }
+
+ case 0x07:
+ {
+ fstrcpy(typestr, "multi");
+ return typestr;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ slprintf(typestr, sizeof(typestr)-1, "[%d]", type);
+ return typestr;
+}
+
+
+static void print_reg_value(FILE *out_hnd, char *val_name, uint32 val_type, BUFFER2 *value)
+{
+ fstring type;
+ pstring intvalue;
+ fstrcpy(type, get_reg_val_type_str(val_type));
+
+ switch (val_type)
+ {
+ case 0x01: /* unistr */
+ {
+ rpcstr_pull(intvalue, value->buffer, sizeof(intvalue), value->buf_len, 0);
+ /*fprintf(out_hnd,"\t%s:\t%s:\t%s\n", val_name, type, dos_buffer2_to_str(value));*/
+ fprintf(out_hnd,"\t%s:\t%s:\t%s\n", val_name, type, value);
+ break;
+ }
+
+ default: /* unknown */
+ case 0x03: /* bytes */
+ {
+ if (value->buf_len <= 8)
+ {
+ fprintf(out_hnd,"\t%s:\t%s:\t", val_name, type);
+ out_data(out_hnd, (char*)value->buffer, value->buf_len, 8);
+ }
+ else
+ {
+ fprintf(out_hnd,"\t%s:\t%s:\n", val_name, type);
+ out_data(out_hnd, (char*)value->buffer, value->buf_len, 16);
+ }
+ break;
+ }
+
+ case 0x04: /* uint32 */
+ {
+ fprintf(out_hnd,"\t%s:\t%s: 0x%08x\n", val_name, type, buffer2_to_uint32(value));
+ break;
+ }
+
+ case 0x07: /* multiunistr */
+ {
+ fprintf(out_hnd,"\t%s:\t%s:\t%s\n", val_name, type, dos_buffer2_to_multistr(value));
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ display structure
+ ****************************************************************************/
+void display_reg_value_info(FILE *out_hnd, enum action_type action,
+ char *val_name, uint32 val_type, BUFFER2 *value)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ print_reg_value(out_hnd, val_name, val_type, value);
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ display structure
+ ****************************************************************************/
+void display_reg_key_info(FILE *out_hnd, enum action_type action,
+ char *key_name, time_t key_mod_time)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fprintf(out_hnd, "\t%s\t(%s)\n",
+ key_name, http_timestring(key_mod_time));
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+#if COPY_THIS_TEMPLATE
+/****************************************************************************
+ display structure
+ ****************************************************************************/
+ void display_(FILE *out_hnd, enum action_type action, *)
+{
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "\t\n");
+ fprintf(out_hnd, "\t-------------------\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+}
+
+#endif
diff --git a/source/rpcclient/display_sec.c b/source/rpcclient/display_sec.c
new file mode 100644
index 00000000000..277d26f1cf6
--- /dev/null
+++ b/source/rpcclient/display_sec.c
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+char *get_sec_mask_str(uint32 type)
+{
+ static fstring typestr="";
+
+ typestr[0] = 0;
+
+ if (type & GENERIC_ALL_ACCESS)
+ fstrcat(typestr, "Generic all access ");
+ if (type & GENERIC_EXECUTE_ACCESS)
+ fstrcat(typestr, "Generic execute access ");
+ if (type & GENERIC_WRITE_ACCESS)
+ fstrcat(typestr, "Generic write access ");
+ if (type & GENERIC_READ_ACCESS)
+ fstrcat(typestr, "Generic read access ");
+ if (type & MAXIMUM_ALLOWED_ACCESS)
+ fstrcat(typestr, "MAXIMUM_ALLOWED_ACCESS ");
+ if (type & SYSTEM_SECURITY_ACCESS)
+ fstrcat(typestr, "SYSTEM_SECURITY_ACCESS ");
+ if (type & SYNCHRONIZE_ACCESS)
+ fstrcat(typestr, "SYNCHRONIZE_ACCESS ");
+ if (type & WRITE_OWNER_ACCESS)
+ fstrcat(typestr, "WRITE_OWNER_ACCESS ");
+ if (type & WRITE_DAC_ACCESS)
+ fstrcat(typestr, "WRITE_DAC_ACCESS ");
+ if (type & READ_CONTROL_ACCESS)
+ fstrcat(typestr, "READ_CONTROL_ACCESS ");
+ if (type & DELETE_ACCESS)
+ fstrcat(typestr, "DELETE_ACCESS ");
+
+ printf("\t\tSpecific bits: 0x%lx\n", type&SPECIFIC_RIGHTS_MASK);
+
+ return typestr;
+}
+
+/****************************************************************************
+ display sec_access structure
+ ****************************************************************************/
+void display_sec_access(SEC_ACCESS *info)
+{
+ printf("\t\tPermissions: 0x%x: %s\n", info->mask, get_sec_mask_str(info->mask));
+}
+
+/****************************************************************************
+ display sec_ace structure
+ ****************************************************************************/
+void display_sec_ace(SEC_ACE *ace)
+{
+ fstring sid_str;
+
+ printf("\tACE\n\t\ttype: ");
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ printf("ACCESS ALLOWED");
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ printf("ACCESS DENIED");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ printf("SYSTEM AUDIT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ printf("SYSTEM ALARM");
+ break;
+ default:
+ printf("????");
+ break;
+ }
+ printf(" (%d) flags: %d\n", ace->type, ace->flags);
+ display_sec_access(&ace->info);
+ sid_to_string(sid_str, &ace->trustee);
+ printf("\t\tSID: %s\n\n", sid_str);
+}
+
+/****************************************************************************
+ display sec_acl structure
+ ****************************************************************************/
+void display_sec_acl(SEC_ACL *sec_acl)
+{
+ int i;
+
+ printf("\tACL\tNum ACEs:\t%d\trevision:\t%x\n",
+ sec_acl->num_aces, sec_acl->revision);
+ printf("\t---\n");
+
+ if (sec_acl->size != 0 && sec_acl->num_aces != 0)
+ for (i = 0; i < sec_acl->num_aces; i++)
+ display_sec_ace(&sec_acl->ace[i]);
+
+}
+
+/****************************************************************************
+ display sec_desc structure
+ ****************************************************************************/
+void display_sec_desc(SEC_DESC *sec)
+{
+ fstring sid_str;
+
+ if (sec->off_sacl != 0) {
+ printf("S-ACL\n");
+ display_sec_acl(sec->sacl);
+ }
+
+ if (sec->off_dacl != 0) {
+ printf("D-ACL\n");
+ display_sec_acl(sec->dacl);
+ }
+
+ if (sec->off_owner_sid != 0) {
+ sid_to_string(sid_str, sec->owner_sid);
+ printf("\tOwner SID:\t%s\n", sid_str);
+ }
+
+ if (sec->off_grp_sid != 0) {
+ sid_to_string(sid_str, sec->grp_sid);
+ printf("\tParent SID:\t%s\n", sid_str);
+ }
+}
diff --git a/source/rpcclient/display_spool.c b/source/rpcclient/display_spool.c
new file mode 100644
index 00000000000..cdca0c393dd
--- /dev/null
+++ b/source/rpcclient/display_spool.c
@@ -0,0 +1,928 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+printer info level 0 display function
+****************************************************************************/
+static void display_print_info_0(FILE *out_hnd, PRINTER_INFO_0 *i1)
+{
+ fstring name;
+ fstring server;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->printername.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(server, i1->servername.buffer, sizeof(server), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tprintername:[%s]\n", name);
+ report(out_hnd, "\tservername:[%s]\n", server);
+ report(out_hnd, "\tcjobs:[%x]\n", i1->cjobs);
+ report(out_hnd, "\ttotal_jobs:[%x]\n", i1->total_jobs);
+
+ report(out_hnd, "\t:date: [%d]-[%d]-[%d] (%d)\n", i1->year, i1->month, i1->day, i1->dayofweek);
+ report(out_hnd, "\t:time: [%d]-[%d]-[%d]-[%d]\n", i1->hour, i1->minute, i1->second, i1->milliseconds);
+
+ report(out_hnd, "\tglobal_counter:[%x]\n", i1->global_counter);
+ report(out_hnd, "\ttotal_pages:[%x]\n", i1->total_pages);
+
+ report(out_hnd, "\tmajorversion:[%x]\n", i1->major_version);
+ report(out_hnd, "\tbuildversion:[%x]\n", i1->build_version);
+
+ report(out_hnd, "\tunknown7:[%x]\n", i1->unknown7);
+ report(out_hnd, "\tunknown8:[%x]\n", i1->unknown8);
+ report(out_hnd, "\tunknown9:[%x]\n", i1->unknown9);
+ report(out_hnd, "\tsession_counter:[%x]\n", i1->session_counter);
+ report(out_hnd, "\tunknown11:[%x]\n", i1->unknown11);
+ report(out_hnd, "\tprinter_errors:[%x]\n", i1->printer_errors);
+ report(out_hnd, "\tunknown13:[%x]\n", i1->unknown13);
+ report(out_hnd, "\tunknown14:[%x]\n", i1->unknown14);
+ report(out_hnd, "\tunknown15:[%x]\n", i1->unknown15);
+ report(out_hnd, "\tunknown16:[%x]\n", i1->unknown16);
+ report(out_hnd, "\tchange_id:[%x]\n", i1->change_id);
+ report(out_hnd, "\tunknown18:[%x]\n", i1->unknown18);
+ report(out_hnd, "\tstatus:[%x]\n", i1->status);
+ report(out_hnd, "\tunknown20:[%x]\n", i1->unknown20);
+ report(out_hnd, "\tc_setprinter:[%x]\n", i1->c_setprinter);
+ report(out_hnd, "\tunknown22:[%x]\n", i1->unknown22);
+ report(out_hnd, "\tunknown23:[%x]\n", i1->unknown23);
+ report(out_hnd, "\tunknown24:[%x]\n", i1->unknown24);
+ report(out_hnd, "\tunknown25:[%x]\n", i1->unknown25);
+ report(out_hnd, "\tunknown26:[%x]\n", i1->unknown26);
+ report(out_hnd, "\tunknown27:[%x]\n", i1->unknown27);
+ report(out_hnd, "\tunknown28:[%x]\n", i1->unknown28);
+ report(out_hnd, "\tunknown29:[%x]\n", i1->unknown29);
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_print_info_1(FILE *out_hnd, PRINTER_INFO_1 *i1)
+{
+ fstring desc;
+ fstring name;
+ fstring comm;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(desc, i1->description.buffer, sizeof(desc), 0, STR_TERMINATE);
+ rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tflags:[%x]\n", i1->flags);
+ report(out_hnd, "\tname:[%s]\n", name);
+ report(out_hnd, "\tdescription:[%s]\n", desc);
+ report(out_hnd, "\tcomment:[%s]\n\n", comm);
+}
+
+/****************************************************************************
+printer info level 2 display function
+****************************************************************************/
+static void display_print_info_2(FILE *out_hnd, PRINTER_INFO_2 *i2)
+{
+ fstring servername;
+ fstring printername;
+ fstring sharename;
+ fstring portname;
+ fstring drivername;
+ fstring comment;
+ fstring location;
+ fstring sepfile;
+ fstring printprocessor;
+ fstring datatype;
+ fstring parameters;
+
+ if (i2 == NULL)
+ return;
+
+ rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), 0, STR_TERMINATE);
+ rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), 0, STR_TERMINATE);
+ rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), 0, STR_TERMINATE);
+ rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), 0, STR_TERMINATE);
+ rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), 0, STR_TERMINATE);
+ rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), 0, STR_TERMINATE);
+ rpcstr_pull(location, i2->location.buffer,sizeof(location), 0, STR_TERMINATE);
+ rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), 0, STR_TERMINATE);
+ rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), 0, STR_TERMINATE);
+ rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), 0, STR_TERMINATE);
+ rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tservername:[%s]\n", servername);
+ report(out_hnd, "\tprintername:[%s]\n", printername);
+ report(out_hnd, "\tsharename:[%s]\n", sharename);
+ report(out_hnd, "\tportname:[%s]\n", portname);
+ report(out_hnd, "\tdrivername:[%s]\n", drivername);
+ report(out_hnd, "\tcomment:[%s]\n", comment);
+ report(out_hnd, "\tlocation:[%s]\n", location);
+ report(out_hnd, "\tsepfile:[%s]\n", sepfile);
+ report(out_hnd, "\tprintprocessor:[%s]\n", printprocessor);
+ report(out_hnd, "\tdatatype:[%s]\n", datatype);
+ report(out_hnd, "\tparameters:[%s]\n", parameters);
+ report(out_hnd, "\tattributes:[%x]\n", i2->attributes);
+ report(out_hnd, "\tpriority:[%x]\n", i2->priority);
+ report(out_hnd, "\tdefaultpriority:[%x]\n", i2->defaultpriority);
+ report(out_hnd, "\tstarttime:[%x]\n", i2->starttime);
+ report(out_hnd, "\tuntiltime:[%x]\n", i2->untiltime);
+ report(out_hnd, "\tstatus:[%x]\n", i2->status);
+ report(out_hnd, "\tcjobs:[%x]\n", i2->cjobs);
+ report(out_hnd, "\taverageppm:[%x]\n\n", i2->averageppm);
+
+ if (i2->secdesc != NULL)
+ {
+ display_sec_desc(out_hnd, ACTION_HEADER , i2->secdesc);
+ display_sec_desc(out_hnd, ACTION_ENUMERATE, i2->secdesc);
+ display_sec_desc(out_hnd, ACTION_FOOTER , i2->secdesc);
+ }
+}
+
+/****************************************************************************
+printer info level 3 display function
+****************************************************************************/
+static void display_print_info_3(FILE *out_hnd, PRINTER_INFO_3 *i3)
+{
+ if (i3 == NULL)
+ return;
+
+ report(out_hnd, "\tflags:[%x]\n", i3->flags);
+
+ display_sec_desc(out_hnd, ACTION_HEADER , i3->secdesc);
+ display_sec_desc(out_hnd, ACTION_ENUMERATE, i3->secdesc);
+ display_sec_desc(out_hnd, ACTION_FOOTER , i3->secdesc);
+}
+
+/****************************************************************************
+connection info level 0 container display function
+****************************************************************************/
+static void display_printer_info_0_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_INFO_CTR ctr)
+{
+ int i;
+ PRINTER_INFO_0 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer Info Level 0:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.printers_0;
+ display_print_info_0(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 1 container display function
+****************************************************************************/
+static void display_printer_info_1_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_INFO_CTR ctr)
+{
+ int i;
+ PRINTER_INFO_1 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer Info Level 1:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.printers_1;
+ display_print_info_1(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 2 container display function
+****************************************************************************/
+static void display_printer_info_2_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_INFO_CTR ctr)
+{
+ int i;
+ PRINTER_INFO_2 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer Info Level 2:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.printers_2;
+ display_print_info_2(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 3 container display function
+****************************************************************************/
+static void display_printer_info_3_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_INFO_CTR ctr)
+{
+ int i;
+ PRINTER_INFO_3 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer Info Level 3:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.printers_3;
+ display_print_info_3(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_printer_info_ctr(FILE *out_hnd, enum action_type action, uint32 level,
+ uint32 count, PRINTER_INFO_CTR ctr)
+{
+ switch (level) {
+ case 0:
+ display_printer_info_0_ctr(out_hnd, action, count, ctr);
+ break;
+ case 1:
+ display_printer_info_1_ctr(out_hnd, action, count, ctr);
+ break;
+ case 2:
+ display_printer_info_2_ctr(out_hnd, action, count, ctr);
+ break;
+ case 3:
+ display_printer_info_3_ctr(out_hnd, action, count, ctr);
+ break;
+ default:
+ report(out_hnd, "display_printer_info_ctr: Unknown Info Level\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 3 container display function
+****************************************************************************/
+static void display_port_info_1_ctr(FILE *out_hnd, enum action_type action,
+ uint32 count, PORT_INFO_CTR *ctr)
+{
+ uint32 i = 0;
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Port Info Level 1:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i=0; i<count; i++)
+ display_port_info_1(out_hnd, action, &ctr->port.info_1[i]);
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 3 container display function
+****************************************************************************/
+static void display_port_info_2_ctr(FILE *out_hnd, enum action_type action,
+ uint32 count, PORT_INFO_CTR *ctr)
+{
+ uint32 i = 0;
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Port Info Level 2:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i=0; i<count; i++)
+ display_port_info_2(out_hnd, action, &ctr->port.info_2[i]);
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_port_info_ctr(FILE *out_hnd, enum action_type action, uint32 level,
+ uint32 count, PORT_INFO_CTR *ctr)
+{
+ switch (level) {
+ case 1:
+ display_port_info_1_ctr(out_hnd, action, count, ctr);
+ break;
+ case 2:
+ display_port_info_2_ctr(out_hnd, action, count, ctr);
+ break;
+ default:
+ report(out_hnd, "display_port_info_ctr: Unknown Info Level\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_port_info_1(FILE *out_hnd, enum action_type action, PORT_INFO_1 *i1)
+{
+ fstring buffer;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Port:\n");
+ break;
+ case ACTION_ENUMERATE:
+ rpcstr_pull(buffer, i1->port_name.buffer, sizeof(bufferi), 0, STR_TERMINATE);
+ fprintf (out_hnd, "\tPort Name:\t[%s]\n\n", buffer);
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_port_info_2(FILE *out_hnd, enum action_type action, PORT_INFO_2 *i2)
+{
+ fstring buffer;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Port:\n");
+ break;
+ case ACTION_ENUMERATE:
+ rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
+ fprintf (out_hnd, "\tPort Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
+
+ fprintf (out_hnd, "\tMonitor Name:\t[%s]\n", buffer);
+ rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), 0, STR_TERMINATE);
+ fprintf (out_hnd, "\tDescription:\t[%s]\n", buffer);
+ fprintf (out_hnd, "\tPort Type:\t[%d]\n", i2->port_type);
+ fprintf (out_hnd, "\tReserved:\t[%d]\n", i2->reserved);
+ fprintf (out_hnd, "\n");
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_printer_enumdata(FILE *out_hnd, enum action_type action, uint32 idx,
+ uint32 valuelen, uint16 *value, uint32 rvaluelen,
+ uint32 type,
+ uint32 datalen, uint8 *data, uint32 rdatalen)
+{
+ fstring buffer;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer enum data:\n");
+ report(out_hnd, "index\tvaluelen\tvalue\t\trvaluelen");
+ report(out_hnd, "\ttype\tdatalen\tdata\trdatalen\n");
+ break;
+ case ACTION_ENUMERATE:
+ report(out_hnd, "[%d]", idx);
+ report(out_hnd, "\t[%d]", valuelen);
+ rpcstr_pull(buffer, value, sizeof(buffer), 0, STR_TERMINATE);
+ report(out_hnd, "\t[%s]", buffer);
+ report(out_hnd, "\t[%d]", rvaluelen);
+ report(out_hnd, "\t\t[%d]", type);
+ report(out_hnd, "\t[%d]", datalen);
+/* report(out_hnd, "\t[%s]", data);*/
+ report(out_hnd, "\t[%d]\n", rdatalen);
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+job info level 2 display function
+****************************************************************************/
+void display_job_info_2(FILE *out_hnd, enum action_type action,
+ JOB_INFO_2 *const i2)
+{
+ if (i2 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ report(out_hnd, "Job Info Level 2:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring tmp;
+
+ report(out_hnd, "\tjob id:\t%d\n", i2->jobid);
+ rpcstr_pull(tmp, i2->printername.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tprinter name:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->machinename.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tmachine name:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->username.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tusername:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->document.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tdocument:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->notifyname.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tnotify name:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->datatype.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tdata type:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->printprocessor.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tprint processor:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->parameters.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tparameters:\t%s\n", tmp);
+ rpcstr_pull(tmp, i2->drivername.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tdriver name:\t%s\n", tmp);
+ report(out_hnd, "\tDevice Mode:\tNOT DISPLAYED YET\n");
+
+ rpcstr_pull(tmp, i2->text_status.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\ttext status:\t%s\n", tmp);
+ /* SEC_DESC sec_desc;*/
+ report(out_hnd, "\tstatus:\t%d\n", i2->status);
+ report(out_hnd, "\tpriority:\t%d\n", i2->priority);
+ report(out_hnd, "\tposition:\t%d\n", i2->position);
+ report(out_hnd, "\tstarttime:\t%d\n", i2->starttime);
+ report(out_hnd, "\tuntiltime:\t%d\n", i2->untiltime);
+ report(out_hnd, "\ttotalpages:\t%d\n", i2->totalpages);
+ report(out_hnd, "\tsize:\t%d\n", i2->size);
+/*
+ SYSTEMTIME submitted;
+*/
+ report(out_hnd, "\tsubmitted:\tNOT DISPLAYED YET\n");
+ report(out_hnd, "\ttimeelapsed:\t%d\n", i2->timeelapsed);
+ report(out_hnd, "\tpagesprinted:\t%d\n", i2->pagesprinted);
+ }
+ case ACTION_FOOTER:
+ {
+ report(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+job info level 1 display function
+****************************************************************************/
+void display_job_info_1(FILE *out_hnd, enum action_type action,
+ JOB_INFO_1 *const i1)
+{
+ if (i1 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ report(out_hnd, "Job Info Level 1:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring tmp;
+
+ report(out_hnd, "\tjob id:\t%d\n", i1->jobid);
+ rpcstr_pull(tmp, i1->printername.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tprinter name:\t%s\n", tmp);
+ rpcstr_pull(tmp, i1->machinename.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tmachine name:\t%s\n", tmp);
+ rpcstr_pull(tmp, i1->username.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tusername:\t%s\n", tmp);
+ rpcstr_pull(tmp, i1->document.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tdocument:\t%s\n", tmp);
+ rpcstr_pull(tmp, i1->datatype.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\tdata type:\t%s\n", tmp);
+ rpcstr_pull(tmp, i1->text_status.buffer, sizeof(tmp), 0, STR_TERMINATE);
+ report(out_hnd, "\ttext status:\t%s\n", tmp);
+ report(out_hnd, "\tstatus:\t%d\n", i1->status);
+ report(out_hnd, "\tpriority:\t%d\n", i1->priority);
+ report(out_hnd, "\tposition:\t%d\n", i1->position);
+ report(out_hnd, "\ttotalpages:\t%d\n", i1->totalpages);
+/*
+ SYSTEMTIME submitted;
+*/
+ report(out_hnd, "\tsubmitted:\tNOT DISPLAYED YET\n");
+ report(out_hnd, "\tpagesprinted:\t%d\n", i1->pagesprinted);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ report(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+connection info level 2 container display function
+****************************************************************************/
+void display_job_info_2_ctr(FILE *out_hnd, enum action_type action,
+ uint32 count, JOB_INFO_2 *const *const ctr)
+{
+ if (ctr == NULL)
+ {
+ report(out_hnd, "display_job_info_2_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ display_job_info_2(out_hnd, ACTION_HEADER , ctr[i]);
+ display_job_info_2(out_hnd, ACTION_ENUMERATE, ctr[i]);
+ display_job_info_2(out_hnd, ACTION_FOOTER , ctr[i]);
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+connection info level 1 container display function
+****************************************************************************/
+void display_job_info_1_ctr(FILE *out_hnd, enum action_type action,
+ uint32 count, JOB_INFO_1 *const *const ctr)
+{
+ if (ctr == NULL)
+ {
+ report(out_hnd, "display_job_info_1_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ display_job_info_1(out_hnd, ACTION_HEADER , ctr[i]);
+ display_job_info_1(out_hnd, ACTION_ENUMERATE, ctr[i]);
+ display_job_info_1(out_hnd, ACTION_FOOTER , ctr[i]);
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_job_info_ctr(FILE *out_hnd, enum action_type action,
+ uint32 level, uint32 count,
+ void *const *const ctr)
+{
+ if (ctr == NULL)
+ {
+ report(out_hnd, "display_job_info_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (level)
+ {
+ case 1:
+ {
+ display_job_info_1_ctr(out_hnd, action,
+ count, (JOB_INFO_1*const*const)ctr);
+ break;
+ }
+ case 2:
+ {
+ display_job_info_2_ctr(out_hnd, action,
+ count, (JOB_INFO_2*const*const)ctr);
+ break;
+ }
+ default:
+ {
+ report(out_hnd, "display_job_info_ctr: Unknown Info Level\n");
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+printer info level 0 display function
+****************************************************************************/
+static void display_print_driver_1(FILE *out_hnd, DRIVER_INFO_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tname:[%s]\n", name);
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_print_driver_2(FILE *out_hnd, DRIVER_INFO_2 *i1)
+{
+ fstring name;
+ fstring architecture;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->conigfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tversion:[%x]\n", i1->version);
+ report(out_hnd, "\tname:[%s]\n", name);
+ report(out_hnd, "\tarchitecture:[%s]\n", architecture);
+ report(out_hnd, "\tdriverpath:[%s]\n", driverpath);
+ report(out_hnd, "\tdatafile:[%s]\n", datafile);
+ report(out_hnd, "\tconfigfile:[%s]\n", configfile);
+}
+
+/****************************************************************************
+printer info level 2 display function
+****************************************************************************/
+static void display_print_driver_3(FILE *out_hnd, DRIVER_INFO_3 *i1)
+{
+ fstring name;
+ fstring architecture;
+ fstring driverpath;
+ fstring datafile;
+ fstring configfile;
+ fstring helpfile;
+ fstring dependentfiles;
+ fstring monitorname;
+ fstring defaultdatatype;
+
+ int length=0;
+ BOOL valid = True;
+
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+ rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
+ rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
+ rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
+ rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
+ rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), 0, STR_TERMINATE);
+ rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), 0, STR_TERMINATE);
+ rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tversion:[%x]\n", i1->version);
+ report(out_hnd, "\tname:[%s]\n",name);
+ report(out_hnd, "\tarchitecture:[%s]\n", architecture);
+ report(out_hnd, "\tdriverpath:[%s]\n", driverpath);
+ report(out_hnd, "\tdatafile:[%s]\n", datafile);
+ report(out_hnd, "\tconfigfile:[%s]\n", configfile);
+ report(out_hnd, "\thelpfile:[%s]\n\n", helpfile);
+
+ while (valid)
+ {
+ rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), 0, STR_TERMINATE);
+ length+=strlen(dependentfiles)+1;
+
+ if (strlen(dependentfiles) > 0)
+ {
+ report(out_hnd, "\tdependentfiles:[%s]\n", dependentfiles);
+ }
+ else
+ {
+ valid = False;
+ }
+ }
+
+ report(out_hnd, "\n\tmonitorname:[%s]\n", monitorname);
+ report(out_hnd, "\tdefaultdatatype:[%s]\n", defaultdatatype);
+
+}
+
+/****************************************************************************
+connection info level 1 container display function
+****************************************************************************/
+static void display_printer_driver_1_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_DRIVER_CTR ctr)
+{
+ int i;
+ DRIVER_INFO_1 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer driver Level 1:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.info1;
+ display_print_driver_1(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 2 container display function
+****************************************************************************/
+static void display_printer_driver_2_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_DRIVER_CTR ctr)
+{
+ int i;
+ DRIVER_INFO_2 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer driver Level 2:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.info2;
+ display_print_driver_2(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info level 3 container display function
+****************************************************************************/
+static void display_printer_driver_3_ctr(FILE *out_hnd, enum action_type action, uint32 count, PRINTER_DRIVER_CTR ctr)
+{
+ int i;
+ DRIVER_INFO_3 *in;
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer driver Level 3:\n");
+ break;
+ case ACTION_ENUMERATE:
+ for (i = 0; i < count; i++) {
+ in=ctr.info3;
+ display_print_driver_3(out_hnd, &(in[i]) );
+ }
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_printer_driver_ctr(FILE *out_hnd, enum action_type action, uint32 level,
+ uint32 count, PRINTER_DRIVER_CTR ctr)
+{
+ switch (level) {
+ case 1:
+ display_printer_driver_1_ctr(out_hnd, action, count, ctr);
+ break;
+ case 2:
+ display_printer_driver_2_ctr(out_hnd, action, count, ctr);
+ break;
+ case 3:
+ display_printer_driver_3_ctr(out_hnd, action, count, ctr);
+ break;
+ default:
+ report(out_hnd, "display_printer_driver_ctr: Unknown Info Level\n");
+ break;
+ }
+}
+
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_printdriverdir_info_1(FILE *out_hnd, DRIVER_DIRECTORY_1 *i1)
+{
+ fstring name;
+ if (i1 == NULL)
+ return;
+
+ rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
+
+ report(out_hnd, "\tname:[%s]\n", name);
+}
+
+/****************************************************************************
+connection info level 1 container display function
+****************************************************************************/
+static void display_printerdriverdir_info_1_ctr(FILE *out_hnd, enum action_type action, DRIVER_DIRECTORY_CTR ctr)
+{
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ report(out_hnd, "Printer driver dir Info Level 1:\n");
+ break;
+ case ACTION_ENUMERATE:
+ display_printdriverdir_info_1(out_hnd, &(ctr.driver.info_1) );
+ break;
+ case ACTION_FOOTER:
+ report(out_hnd, "\n");
+ break;
+ }
+}
+
+/****************************************************************************
+connection info container display function
+****************************************************************************/
+void display_printerdriverdir_info_ctr(FILE *out_hnd, enum action_type action, uint32 level,
+ DRIVER_DIRECTORY_CTR ctr)
+{
+ switch (level) {
+ case 1:
+ display_printerdriverdir_info_1_ctr(out_hnd, action, ctr);
+ break;
+ default:
+ report(out_hnd, "display_printerdriverdir_info_ctr: Unknown Info Level\n");
+ break;
+ }
+}
diff --git a/source/rpcclient/rpcclient.c b/source/rpcclient/rpcclient.c
new file mode 100644
index 00000000000..f57b4f2e483
--- /dev/null
+++ b/source/rpcclient/rpcclient.c
@@ -0,0 +1,733 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpcclient.h"
+
+DOM_SID domain_sid;
+
+/* List to hold groups of commands */
+
+static struct cmd_list {
+ struct cmd_list *prev, *next;
+ struct cmd_set *cmd_set;
+} *cmd_list;
+
+/****************************************************************************
+handle completion of commands for readline
+****************************************************************************/
+static char **completion_fn(char *text, int start, int end)
+{
+#define MAX_COMPLETIONS 100
+ char **matches;
+ int i, count=0;
+ struct cmd_list *commands = cmd_list;
+
+#if 0 /* JERRY */
+ /* FIXME!!! -- what to do when completing argument? */
+ /* for words not at the start of the line fallback
+ to filename completion */
+ if (start)
+ return NULL;
+#endif
+
+ /* make sure we have a list of valid commands */
+ if (!commands)
+ return NULL;
+
+ matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
+ if (!matches) return NULL;
+
+ matches[count++] = strdup(text);
+ if (!matches[0]) return NULL;
+
+ while (commands && count < MAX_COMPLETIONS-1)
+ {
+ if (!commands->cmd_set)
+ break;
+
+ for (i=0; commands->cmd_set[i].name; i++)
+ {
+ if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
+ commands->cmd_set[i].fn)
+ {
+ matches[count] = strdup(commands->cmd_set[i].name);
+ if (!matches[count])
+ return NULL;
+ count++;
+ }
+ }
+
+ commands = commands->next;
+
+ }
+
+ if (count == 2) {
+ SAFE_FREE(matches[0]);
+ matches[0] = strdup(matches[1]);
+ }
+ matches[count] = NULL;
+ return matches;
+}
+
+/***********************************************************************
+ * read in username/password credentials from a file
+ */
+static void read_authfile (
+ char *filename,
+ char* username,
+ char* password,
+ char* domain
+)
+{
+ FILE *auth;
+ fstring buf;
+ uint16 len = 0;
+ char *ptr, *val, *param;
+
+ if ((auth=sys_fopen(filename, "r")) == NULL)
+ {
+ printf ("ERROR: Unable to open credentials file!\n");
+ return;
+ }
+
+ while (!feof(auth))
+ {
+ /* get a line from the file */
+ if (!fgets (buf, sizeof(buf), auth))
+ continue;
+
+ len = strlen(buf);
+
+ /* skip empty lines */
+ if ((len) && (buf[len-1]=='\n'))
+ {
+ buf[len-1] = '\0';
+ len--;
+ }
+ if (len == 0)
+ continue;
+
+ /* break up the line into parameter & value.
+ will need to eat a little whitespace possibly */
+ param = buf;
+ if (!(ptr = strchr_m(buf, '=')))
+ continue;
+ val = ptr+1;
+ *ptr = '\0';
+
+ /* eat leading white space */
+ while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
+ val++;
+
+ if (strwicmp("password", param) == 0)
+ fstrcpy (password, val);
+ else if (strwicmp("username", param) == 0)
+ fstrcpy (username, val);
+ else if (strwicmp("domain", param) == 0)
+ fstrcpy (domain, val);
+
+ memset(buf, 0, sizeof(buf));
+ }
+ fclose(auth);
+
+ return;
+}
+
+static char* next_command (char** cmdstr)
+{
+ static pstring command;
+ char *p;
+
+ if (!cmdstr || !(*cmdstr))
+ return NULL;
+
+ p = strchr_m(*cmdstr, ';');
+ if (p)
+ *p = '\0';
+ pstrcpy(command, *cmdstr);
+ *cmdstr = p;
+
+ return command;
+}
+
+static void get_username (char *username)
+{
+ if (getenv("USER"))
+ pstrcpy(username,getenv("USER"));
+
+ if (*username == 0 && getenv("LOGNAME"))
+ pstrcpy(username,getenv("LOGNAME"));
+
+ if (*username == 0) {
+ pstrcpy(username,"GUEST");
+ }
+
+ return;
+}
+
+/* Fetch the SID for this computer */
+
+void fetch_machine_sid(struct cli_state *cli)
+{
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_OK;
+ uint32 info_class = 5;
+ fstring domain_name;
+ static BOOL got_domain_sid;
+ TALLOC_CTX *mem_ctx;
+
+ if (got_domain_sid) return;
+
+ if (!(mem_ctx=talloc_init()))
+ {
+ DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n"));
+ goto error;
+ }
+
+
+ if (!cli_nt_session_open (cli, PIPE_LSARPC)) {
+ fprintf(stderr, "could not initialise lsa pipe\n");
+ goto error;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class,
+ domain_name, &domain_sid);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ got_domain_sid = True;
+
+ cli_lsa_close(cli, mem_ctx, &pol);
+ cli_nt_session_close(cli);
+ talloc_destroy(mem_ctx);
+
+ return;
+
+ error:
+ fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "error: %s\n", get_nt_error_msg(result));
+ }
+
+ exit(1);
+}
+
+
+/* Display help on commands */
+
+static NTSTATUS cmd_help(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ struct cmd_list *tmp;
+ struct cmd_set *tmp_set;
+
+ /* Usage */
+
+ if (argc > 2) {
+ printf("Usage: %s [command]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ /* Help on one command */
+
+ if (argc == 2) {
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+ if (strequal(argv[1], tmp_set->name)) {
+ if (tmp_set->usage &&
+ tmp_set->usage[0])
+ printf("%s\n", tmp_set->usage);
+ else
+ printf("No help for %s\n", tmp_set->name);
+
+ return NT_STATUS_OK;
+ }
+
+ tmp_set++;
+ }
+ }
+
+ printf("No such command: %s\n", argv[1]);
+ return NT_STATUS_OK;
+ }
+
+ /* List all commands */
+
+ for (tmp = cmd_list; tmp; tmp = tmp->next) {
+
+ tmp_set = tmp->cmd_set;
+
+ while(tmp_set->name) {
+
+ printf("%15s\t\t%s\n", tmp_set->name,
+ tmp_set->description);
+
+ tmp_set++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Change the debug level */
+
+static NTSTATUS cmd_debuglevel(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ if (argc > 2) {
+ printf("Usage: %s [debuglevel]\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ if (argc == 2) {
+ DEBUGLEVEL = atoi(argv[1]);
+ }
+
+ printf("debuglevel is %d\n", DEBUGLEVEL);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, char **argv)
+{
+ exit(0);
+ return NT_STATUS_OK; /* NOTREACHED */
+}
+
+/* Build in rpcclient commands */
+
+static struct cmd_set rpcclient_commands[] = {
+
+ { "GENERAL OPTIONS" },
+
+ { "help", cmd_help, NULL, "Get help on commands", "[command]" },
+ { "?", cmd_help, NULL, "Get help on commands", "[command]" },
+ { "debuglevel", cmd_debuglevel, NULL, "Set debug level", "level" },
+ { "exit", cmd_quit, NULL, "Exit program", "" },
+ { "quit", cmd_quit, NULL, "Exit program", "" },
+
+ { NULL }
+};
+
+static struct cmd_set separator_command[] = {
+ { "---------------", NULL, NULL, "----------------------" },
+ { NULL }
+};
+
+
+/* Various pipe commands */
+
+extern struct cmd_set lsarpc_commands[];
+extern struct cmd_set samr_commands[];
+extern struct cmd_set spoolss_commands[];
+extern struct cmd_set netlogon_commands[];
+extern struct cmd_set srvsvc_commands[];
+extern struct cmd_set dfs_commands[];
+extern struct cmd_set reg_commands[];
+
+static struct cmd_set *rpcclient_command_list[] = {
+ rpcclient_commands,
+ lsarpc_commands,
+ samr_commands,
+ spoolss_commands,
+ netlogon_commands,
+ srvsvc_commands,
+ dfs_commands,
+ reg_commands,
+ NULL
+};
+
+static void add_command_set(struct cmd_set *cmd_set)
+{
+ struct cmd_list *entry;
+
+ if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
+ DEBUG(0, ("out of memory\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(entry);
+
+ entry->cmd_set = cmd_set;
+ DLIST_ADD(cmd_list, entry);
+}
+
+static NTSTATUS do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry,
+ char *cmd)
+{
+ char *p = cmd, **argv = NULL;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ pstring buf;
+ int argc = 0, i;
+
+ /* Count number of arguments first time through the loop then
+ allocate memory and strdup them. */
+
+ again:
+ while(next_token(&p, buf, " ", sizeof(buf))) {
+ if (argv) {
+ argv[argc] = strdup(buf);
+ }
+
+ argc++;
+ }
+
+ if (!argv) {
+
+ /* Create argument list */
+
+ argv = (char **)malloc(sizeof(char *) * argc);
+ memset(argv, 0, sizeof(char *) * argc);
+
+ if (!argv) {
+ fprintf(stderr, "out of memory\n");
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p = cmd;
+ argc = 0;
+
+ goto again;
+ }
+
+ /* Call the function */
+
+ if (cmd_entry->fn) {
+ TALLOC_CTX *mem_ctx;
+
+ /* Create mem_ctx */
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ goto done;
+ }
+
+ /* Open pipe */
+
+ if (cmd_entry->pipe)
+ if (!cli_nt_session_open(cli, cmd_entry->pipe)) {
+ DEBUG(0, ("Could not initialise %s\n",
+ cmd_entry->pipe));
+ goto done;
+ }
+
+ /* Run command */
+
+ result = cmd_entry->fn(cli, mem_ctx, argc, argv);
+
+ /* Cleanup */
+
+ if (cmd_entry->pipe)
+ cli_nt_session_close(cli);
+
+ talloc_destroy(mem_ctx);
+
+ } else {
+ fprintf (stderr, "Invalid command\n");
+ goto done;
+ }
+
+ done:
+
+ /* Cleanup */
+
+ if (argv) {
+ for (i = 0; i < argc; i++)
+ SAFE_FREE(argv[i]);
+
+ SAFE_FREE(argv);
+ }
+
+ return result;
+}
+
+/* Process a command entered at the prompt or as part of -c */
+
+static NTSTATUS process_cmd(struct cli_state *cli, char *cmd)
+{
+ struct cmd_list *temp_list;
+ BOOL found = False;
+ pstring buf;
+ char *p = cmd;
+ NTSTATUS result = NT_STATUS_OK;
+ int len = 0;
+
+ if (cmd[strlen(cmd) - 1] == '\n')
+ cmd[strlen(cmd) - 1] = '\0';
+
+ if (!next_token(&p, buf, " ", sizeof(buf))) {
+ return NT_STATUS_OK;
+ }
+
+ /* strip the trainly \n if it exsists */
+ len = strlen(buf);
+ if (buf[len-1] == '\n')
+ buf[len-1] = '\0';
+
+ /* Search for matching commands */
+
+ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
+ struct cmd_set *temp_set = temp_list->cmd_set;
+
+ while(temp_set->name) {
+ if (strequal(buf, temp_set->name)) {
+ found = True;
+ result = do_cmd(cli, temp_set, cmd);
+
+ goto done;
+ }
+ temp_set++;
+ }
+ }
+
+ done:
+ if (!found && buf[0]) {
+ printf("command not found: %s\n", buf);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(result)) {
+ printf("result was %s\n", get_nt_error_msg(result));
+ }
+
+ return result;
+}
+
+
+/* Print usage information */
+static void usage(void)
+{
+ printf("Usage: rpcclient server [options]\n");
+
+ printf("\t-A authfile file containing user credentials\n");
+ printf("\t-c \"command string\" execute semicolon separated cmds\n");
+ printf("\t-d debuglevel set the debuglevel\n");
+ printf("\t-l logfile name of logfile to use as opposed to stdout\n");
+ printf("\t-h Print this help message.\n");
+ printf("\t-N don't ask for a password\n");
+ printf("\t-s configfile specify an alternative config file\n");
+ printf("\t-U username set the network username\n");
+ printf("\t-W domain set the domain name for user account\n");
+ printf("\n");
+}
+
+/* Main function */
+
+ int main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ extern pstring global_myname;
+ BOOL got_pass = False;
+ BOOL interactive = True;
+ int opt;
+ int olddebug;
+ pstring cmdstr = "";
+ struct cli_state *cli;
+ fstring password="",
+ username="",
+ domain="",
+ server="";
+ struct cmd_set **cmd_set;
+ struct in_addr server_ip;
+ NTSTATUS nt_status;
+
+ setlinebuf(stdout);
+
+ DEBUGLEVEL = 1;
+
+ while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:h")) != EOF) {
+ switch (opt) {
+ case 'A':
+ /* only get the username, password, and domain from the file */
+ read_authfile (optarg, username, password, domain);
+ if (strlen (password))
+ got_pass = True;
+ break;
+
+ case 'c':
+ pstrcpy(cmdstr, optarg);
+ break;
+
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+
+ case 'N':
+ got_pass = True;
+ break;
+
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+
+ case 'U': {
+ char *lp;
+ pstrcpy(username,optarg);
+ if ((lp=strchr_m(username,'%'))) {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr_m(optarg,'%')+1,'X',strlen(password));
+ }
+ break;
+ }
+
+ case 'W':
+ pstrcpy(domain, optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ /* Parse options */
+ if (argc == 0) {
+ usage();
+ return 0;
+ }
+
+ if (strncmp("//", argv[0], 2) == 0 || strncmp("\\\\", argv[0], 2) == 0)
+ argv[0] += 2;
+
+ pstrcpy(server, argv[0]);
+
+ /* the following functions are part of the Samba debugging
+ facilities. See lib/debug.c */
+ setup_logging("rpcclient", interactive);
+ if (!interactive)
+ reopen_logs();
+
+ /* Load smb.conf file */
+ /* FIXME! How to get this DEBUGLEVEL to last over lp_load()? */
+ olddebug = DEBUGLEVEL;
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
+ }
+ DEBUGLEVEL = olddebug;
+
+ load_interfaces();
+
+ get_myname((*global_myname)?NULL:global_myname);
+ strupper(global_myname);
+
+
+ /* resolve the IP address */
+ if (!resolve_name(server, &server_ip, 0x20)) {
+ DEBUG(1,("Unable to resolve server name\n"));
+ return 1;
+ }
+
+ /*
+ * Get password
+ * from stdin if necessary
+ */
+
+ if (!got_pass) {
+ char *pass = getpass("Password:");
+ if (pass) {
+ fstrcpy(password, pass);
+ }
+ }
+
+ if (!strlen(username) && !got_pass)
+ get_username(username);
+
+ nt_status = cli_full_connection(&cli, global_myname, server,
+ &server_ip, 0,
+ "IPC$", "IPC",
+ username, domain,
+ password, strlen(password));
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("Cannot connect to server. Error was %s\n", get_nt_error_msg(nt_status)));
+ return 1;
+ }
+
+ memset(password,'X',sizeof(password));
+
+ /* Load command lists */
+
+ cmd_set = rpcclient_command_list;
+
+ while(*cmd_set) {
+ add_command_set(*cmd_set);
+ add_command_set(separator_command);
+ cmd_set++;
+ }
+
+ fetch_machine_sid(cli);
+
+ /* Do anything specified with -c */
+ if (cmdstr[0]) {
+ char *cmd;
+ char *p = cmdstr;
+
+ while((cmd=next_command(&p)) != NULL) {
+ process_cmd(cli, cmd);
+ }
+
+ cli_shutdown(cli);
+ return 0;
+ }
+
+ /* Loop around accepting commands */
+
+ while(1) {
+ pstring prompt;
+ char *line;
+
+ slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> ");
+
+ line = smb_readline(prompt, NULL, completion_fn);
+
+ if (line == NULL)
+ break;
+
+ if (line[0] != '\n')
+ process_cmd(cli, line);
+ }
+
+ cli_shutdown(cli);
+ return 0;
+}
diff --git a/source/rpcclient/rpcclient.h b/source/rpcclient/rpcclient.h
new file mode 100644
index 00000000000..588d10b3e6b
--- /dev/null
+++ b/source/rpcclient/rpcclient.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef RPCCLIENT_H
+#define RPCCLIENT_H
+
+struct cmd_set {
+ char *name;
+ NTSTATUS (*fn)(struct cli_state*, TALLOC_CTX *mem_ctx, int argc,
+ char **argv);
+ char *pipe;
+ char *description;
+ char *usage;
+};
+
+#endif /* RPCCLIENT_H */
diff --git a/source/rpcclient/samsync.c b/source/rpcclient/samsync.c
new file mode 100644
index 00000000000..532517f2efa
--- /dev/null
+++ b/source/rpcclient/samsync.c
@@ -0,0 +1,620 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static void decode_domain_info(SAM_DOMAIN_INFO *a)
+{
+ fstring temp;
+ printf("Domain Information\n");
+ printf("------------------\n");
+
+ unistr2_to_ascii(temp, &a->uni_dom_name, sizeof(temp)-1);
+ printf("\tDomain :%s\n", temp);
+ printf("\tMin password len :%d\n", a->min_pwd_len);
+ printf("\tpassword history len:%d\n", a->pwd_history_len);
+ printf("\tcreation time :%s\n", http_timestring(nt_time_to_unix(&a->creation_time)));
+}
+
+static void decode_sam_group_info(SAM_GROUP_INFO *a)
+{
+ fstring temp;
+ printf("\nDomain Group Information\n");
+ printf("------------------------\n");
+
+ unistr2_to_ascii(temp, &a->uni_grp_name, sizeof(temp)-1);
+ printf("\tGroup name :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_grp_desc, sizeof(temp)-1);
+ printf("\tGroup description :%s\n", temp);
+ printf("\trid :%d\n", a->gid.g_rid);
+ printf("\tattribute :%d\n", a->gid.attr);
+}
+
+static void decode_sam_account_info(SAM_ACCOUNT_INFO *a)
+{
+ fstring temp;
+ printf("\nUser Information\n");
+ printf("----------------\n");
+
+ unistr2_to_ascii(temp, &a->uni_acct_name, sizeof(temp)-1);
+ printf("\tUser name :%s\n", temp);
+ printf("\tuser's rid :%d\n", a->user_rid);
+ printf("\tuser's primary gid :%d\n", a->group_rid);
+ unistr2_to_ascii(temp, &a->uni_full_name, sizeof(temp)-1);
+ printf("\tfull name :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_home_dir, sizeof(temp)-1);
+ printf("\thome directory :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_dir_drive, sizeof(temp)-1);
+ printf("\tdrive :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_logon_script, sizeof(temp)-1);
+ printf("\tlogon script :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_acct_desc, sizeof(temp)-1);
+ printf("\tdescription :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_workstations, sizeof(temp)-1);
+ printf("\tworkstations :%s\n", temp);
+}
+
+static void decode_sam_grp_mem_info(SAM_GROUP_MEM_INFO *a)
+{
+ int i;
+ printf("\nGroup members information\n");
+ printf("-------------------------\n");
+ printf("\tnum members :%d\n", a->num_members);
+
+ for (i=0; i<a->num_members; i++) {
+ printf("\trid, attr:%d, %d\n", a->rids[i], a->attribs[i]);
+ }
+}
+
+static void decode_sam_alias_info(SAM_ALIAS_INFO *a)
+{
+ fstring temp;
+ printf("\nAlias Information\n");
+ printf("-----------------\n");
+
+ unistr2_to_ascii(temp, &a->uni_als_name, sizeof(temp)-1);
+ printf("\tname :%s\n", temp);
+ unistr2_to_ascii(temp, &a->uni_als_desc, sizeof(temp)-1);
+ printf("\tdescription :%s\n", temp);
+ printf("\trid :%d\n", a->als_rid);
+}
+
+static void decode_sam_als_mem_info(SAM_ALIAS_MEM_INFO *a)
+{
+ int i;
+ fstring temp;
+ printf("\nAlias members Information\n");
+ printf("-------------------------\n");
+ printf("\tnum members :%d\n", a->num_members);
+ printf("\tnum sids :%d\n", a->num_sids);
+ for (i=0; i<a->num_sids; i++) {
+ printf("\tsid :%s\n", sid_to_string(temp, &a->sids[i].sid));
+ }
+
+
+}
+
+static void decode_sam_dom_info(SAM_DELTA_DOM *a)
+{
+ fstring temp;
+ printf("\nDomain information\n");
+ printf("------------------\n");
+
+ unistr2_to_ascii(temp, &a->domain_name, sizeof(temp)-1);
+ printf("\tdomain name :%s\n", temp);
+ printf("\tsid :%s\n", sid_to_string(temp, &a->domain_sid.sid));
+}
+
+static void decode_sam_unk0e_info(SAM_DELTA_UNK0E *a)
+{
+ fstring temp;
+ printf("\nTrust information\n");
+ printf("-----------------\n");
+
+ unistr2_to_ascii(temp, &a->domain, sizeof(temp)-1);
+ printf("\tdomain name :%s\n", temp);
+ printf("\tsid :%s\n", sid_to_string(temp, &a->sid.sid));
+ display_sec_desc(a->sec_desc);
+}
+
+static void decode_sam_privs_info(SAM_DELTA_PRIVS *a)
+{
+ int i;
+ fstring temp;
+ printf("\nSID and privileges information\n");
+ printf("------------------------------\n");
+ printf("\tsid :%s\n", sid_to_string(temp, &a->sid.sid));
+ display_sec_desc(a->sec_desc);
+ printf("\tprivileges count :%d\n", a->privlist_count);
+ for (i=0; i<a->privlist_count; i++) {
+ unistr2_to_ascii(temp, &a->uni_privslist[i], sizeof(temp)-1);
+ printf("\tprivilege name :%s\n", temp);
+ printf("\tattribute :%d\n", a->attributes[i]);
+ }
+}
+
+static void decode_sam_unk12_info(SAM_DELTA_UNK12 *a)
+{
+ fstring temp;
+ printf("\nTrusted information\n");
+ printf("-------------------\n");
+
+ unistr2_to_ascii(temp, &a->secret, sizeof(temp)-1);
+ printf("\tsecret name :%s\n", temp);
+ display_sec_desc(a->sec_desc);
+
+ printf("\ttime 1 :%s\n", http_timestring(nt_time_to_unix(&a->time1)));
+ printf("\ttime 2 :%s\n", http_timestring(nt_time_to_unix(&a->time2)));
+
+ display_sec_desc(a->sec_desc2);
+}
+
+static void decode_sam_stamp(SAM_DELTA_STAMP *a)
+{
+ printf("\nStamp information\n");
+ printf("-----------------\n");
+ printf("\tsequence number :%d\n", a->seqnum);
+}
+
+static void decode_sam_deltas(uint32 num_deltas, SAM_DELTA_HDR *hdr_deltas, SAM_DELTA_CTR *deltas)
+{
+ int i;
+ for (i = 0; i < num_deltas; i++) {
+ switch (hdr_deltas[i].type) {
+ case SAM_DELTA_DOMAIN_INFO: {
+ SAM_DOMAIN_INFO *a;
+ a = &deltas[i].domain_info;
+ decode_domain_info(a);
+ break;
+ }
+ case SAM_DELTA_GROUP_INFO: {
+ SAM_GROUP_INFO *a;
+ a = &deltas[i].group_info;
+ decode_sam_group_info(a);
+ break;
+ }
+ case SAM_DELTA_ACCOUNT_INFO: {
+ SAM_ACCOUNT_INFO *a;
+ a = &deltas[i].account_info;
+ decode_sam_account_info(a);
+ break;
+ }
+ case SAM_DELTA_GROUP_MEM: {
+ SAM_GROUP_MEM_INFO *a;
+ a = &deltas[i].grp_mem_info;
+ decode_sam_grp_mem_info(a);
+ break;
+ }
+ case SAM_DELTA_ALIAS_INFO: {
+ SAM_ALIAS_INFO *a;
+ a = &deltas[i].alias_info;
+ decode_sam_alias_info(a);
+ break;
+ }
+ case SAM_DELTA_ALIAS_MEM: {
+ SAM_ALIAS_MEM_INFO *a;
+ a = &deltas[i].als_mem_info;
+ decode_sam_als_mem_info(a);
+ break;
+ }
+ case SAM_DELTA_DOM_INFO: {
+ SAM_DELTA_DOM *a;
+ a = &deltas[i].dom_info;
+ decode_sam_dom_info(a);
+ break;
+ }
+ case SAM_DELTA_UNK0E_INFO: {
+ SAM_DELTA_UNK0E *a;
+ a = &deltas[i].unk0e_info;
+ decode_sam_unk0e_info(a);
+ break;
+ }
+ case SAM_DELTA_PRIVS_INFO: {
+ SAM_DELTA_PRIVS *a;
+ a = &deltas[i].privs_info;
+ decode_sam_privs_info(a);
+ break;
+ }
+ case SAM_DELTA_UNK12_INFO: {
+ SAM_DELTA_UNK12 *a;
+ a = &deltas[i].unk12_info;
+ decode_sam_unk12_info(a);
+ break;
+ }
+ case SAM_DELTA_SAM_STAMP: {
+ SAM_DELTA_STAMP *a;
+ a = &deltas[i].stamp;
+ decode_sam_stamp(a);
+ break;
+ }
+ default:
+ DEBUG(0,("unknown delta type: %d\n", hdr_deltas[i].type));
+ break;
+ }
+ }
+}
+
+/* Synchronise sam database */
+
+static NTSTATUS sam_sync(struct cli_state *cli, unsigned char trust_passwd[16],
+ BOOL do_smbpasswd_output, BOOL verbose)
+{
+ TALLOC_CTX *mem_ctx;
+ SAM_DELTA_HDR *hdr_deltas_0, *hdr_deltas_1, *hdr_deltas_2;
+ SAM_DELTA_CTR *deltas_0, *deltas_1, *deltas_2;
+ uint32 num_deltas_0, num_deltas_1, num_deltas_2;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ DOM_CRED ret_creds;
+ /* Initialise */
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("talloc_init failed\n"));
+ return result;
+ }
+
+ if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Could not initialize netlogon pipe!\n"));
+ goto done;
+ }
+
+ /* Request a challenge */
+
+ if (!NT_STATUS_IS_OK(new_cli_nt_setup_creds(cli, trust_passwd))) {
+ DEBUG(0, ("Error initialising session creds\n"));
+ goto done;
+ }
+
+ /* on first call the returnAuthenticator is empty */
+ memset(&ret_creds, 0, sizeof(ret_creds));
+
+ /* Do sam synchronisation on the SAM database*/
+
+ result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 0, &num_deltas_0, &hdr_deltas_0, &deltas_0);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* verbose mode */
+ if (verbose)
+ decode_sam_deltas(num_deltas_0, hdr_deltas_0, deltas_0);
+
+
+ /*
+ * we can't yet do several sam_sync in a raw, it's a credential problem
+ * we must chain the credentials
+ */
+
+#if 1
+ /* Do sam synchronisation on the LSA database */
+
+ result = cli_netlogon_sam_sync(cli, mem_ctx, &ret_creds, 2, &num_deltas_2, &hdr_deltas_2, &deltas_2);
+
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* verbose mode */
+ if (verbose)
+ decode_sam_deltas(num_deltas_2, hdr_deltas_2, deltas_2);
+#endif
+
+ /* Produce smbpasswd output - good for migrating from NT! */
+
+ if (do_smbpasswd_output) {
+ int i;
+
+ for (i = 0; i < num_deltas_0; i++) {
+ SAM_ACCOUNT_INFO *a;
+ fstring acct_name, hex_nt_passwd, hex_lm_passwd;
+ uchar lm_passwd[16], nt_passwd[16];
+
+ /* Skip non-user accounts */
+
+ if (hdr_deltas_0[i].type != SAM_DELTA_ACCOUNT_INFO)
+ continue;
+
+ a = &deltas_0[i].account_info;
+
+ unistr2_to_ascii(acct_name, &a->uni_acct_name,
+ sizeof(acct_name) - 1);
+
+ /* Decode hashes from password hash */
+
+ sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd,
+ lm_passwd, 0);
+ sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd,
+ nt_passwd, 0);
+
+ /* Encode as strings */
+
+ smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd,
+ a->acb_info);
+ smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd,
+ a->acb_info);
+
+ /* Display user info */
+
+ printf("%s:%d:%s:%s:%s:LCT-0\n", acct_name,
+ a->user_rid, hex_lm_passwd, hex_nt_passwd,
+ smbpasswd_encode_acb_info(a->acb_info));
+ }
+
+ goto done;
+ }
+
+ /* Update sam tdb */
+
+ done:
+ cli_nt_session_close(cli);
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+/* Replicate sam deltas */
+
+static NTSTATUS sam_repl(struct cli_state *cli, unsigned char trust_passwde[16],
+ uint32 low_serial)
+{
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ return result;
+}
+
+/* Print usage information */
+
+static void usage(void)
+{
+ printf("Usage: samsync [options]\n");
+
+ printf("\t-d debuglevel set the debuglevel\n");
+ printf("\t-h Print this help message.\n");
+ printf("\t-s configfile specify an alternative config file\n");
+ printf("\t-S synchronise sam database\n");
+ printf("\t-R replicate sam deltas\n");
+ printf("\t-U username username and password\n");
+ printf("\t-p produce smbpasswd output\n");
+ printf("\t-V verbose output\n");
+ printf("\n");
+}
+
+/* Initialise client credentials for authenticated pipe access */
+
+void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
+ char* domain, char* password)
+{
+ ZERO_STRUCTP(creds);
+
+ if (lp_encrypted_passwords()) {
+ pwd_make_lm_nt_16(&creds->pwd, password);
+ } else {
+ pwd_set_cleartext(&creds->pwd, password);
+ }
+
+ fstrcpy(creds->user_name, username);
+ fstrcpy(creds->domain, domain);
+
+ if (! *username) {
+ creds->pwd.null_pwd = True;
+ }
+}
+
+/* Connect to primary domain controller */
+
+static struct cli_state *init_connection(struct cli_state *cli,
+ char *username, char *domain,
+ char *password)
+{
+ struct ntuser_creds creds;
+ extern pstring global_myname;
+ struct in_addr *dest_ip;
+ struct nmb_name calling, called;
+ int count;
+ fstring dest_host;
+
+ /* Initialise cli_state information */
+
+ ZERO_STRUCTP(cli);
+
+ if (!cli_initialise(cli)) {
+ return NULL;
+ }
+
+ init_rpcclient_creds(&creds, username, domain, password);
+ cli_init_creds(cli, &creds);
+
+ /* Look up name of PDC controller */
+
+ if (!get_dc_list(True, lp_workgroup(), &dest_ip, &count)) {
+ DEBUG(0, ("Cannot find domain controller for domain %s\n",
+ lp_workgroup()));
+ return NULL;
+ }
+
+ if (!lookup_dc_name(global_myname, lp_workgroup(), dest_ip,
+ dest_host)) {
+ DEBUG(0, ("Could not lookup up PDC name for domain %s\n",
+ lp_workgroup()));
+ return NULL;
+ }
+
+ get_myname((*global_myname)?NULL:global_myname);
+ strupper(global_myname);
+
+ make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ /* Establish a SMB connection */
+
+ if (!cli_establish_connection(cli, dest_host, dest_ip, &calling,
+ &called, "IPC$", "IPC", False, True)) {
+ return NULL;
+ }
+
+ return cli;
+}
+
+/* Main function */
+
+ int main(int argc, char **argv)
+{
+ BOOL do_sam_sync = False, do_sam_repl = False;
+ struct cli_state cli;
+ NTSTATUS result;
+ int opt;
+ pstring logfile;
+ BOOL interactive = False, do_smbpasswd_output = False;
+ BOOL verbose = False;
+ uint32 low_serial = 0;
+ unsigned char trust_passwd[16];
+ fstring username, domain, password;
+
+ if (argc == 1) {
+ usage();
+ return 1;
+ }
+
+ ZERO_STRUCT(username);
+ ZERO_STRUCT(domain);
+ ZERO_STRUCT(password);
+
+ /* Parse command line options */
+
+ while((opt = getopt(argc, argv, "s:d:SR:hiU:W:pV")) != EOF) {
+ switch (opt) {
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'S':
+ do_sam_sync = 1;
+ break;
+ case 'R':
+ do_sam_repl = 1;
+ low_serial = atoi(optarg);
+ break;
+ case 'i':
+ interactive = True;
+ break;
+ case 'U': {
+ char *lp;
+
+ fstrcpy(username,optarg);
+ if ((lp=strchr_m(username,'%'))) {
+ *lp = 0;
+ fstrcpy(password,lp+1);
+ memset(strchr_m(optarg, '%') + 1, 'X',
+ strlen(password));
+ }
+ break;
+ }
+ case 'W':
+ pstrcpy(domain, optarg);
+ break;
+ case 'p':
+ do_smbpasswd_output = True;
+ break;
+ case 'V':
+ verbose = True;
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+
+ if (argc > 0) {
+ usage();
+ return 1;
+ }
+
+ /* Initialise samba */
+
+ slprintf(logfile, sizeof(logfile) - 1, "%s/log.%s", dyn_LOGFILEBASE,
+ "samsync");
+ lp_set_logfile(logfile);
+
+ setup_logging("samsync", interactive);
+
+ if (!interactive)
+ reopen_logs();
+
+ if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
+ fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
+ }
+
+ load_interfaces();
+
+ /* Check arguments make sense */
+
+ if (do_sam_sync && do_sam_repl) {
+ fprintf(stderr, "cannot specify both -S and -R\n");
+ return 1;
+
+ }
+
+ if (!do_sam_sync && !do_sam_repl) {
+ fprintf(stderr, "must specify either -S or -R\n");
+ return 1;
+ }
+
+ if (do_sam_repl && low_serial == 0) {
+ fprintf(stderr, "serial number must be positive\n");
+ return 1;
+ }
+
+ /* BDC operations require the machine account password */
+
+ if (!secrets_init()) {
+ DEBUG(0, ("Unable to initialise secrets database\n"));
+ return 1;
+ }
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(),
+ trust_passwd, NULL)) {
+ DEBUG(0, ("could not fetch trust account password\n"));
+ return 1;
+ }
+
+ /* Perform sync or replication */
+
+ if (!init_connection(&cli, username, domain, password))
+ return 1;
+
+ if (do_sam_sync)
+ result = sam_sync(&cli, trust_passwd, do_smbpasswd_output, verbose);
+
+ if (do_sam_repl)
+ result = sam_repl(&cli, trust_passwd, low_serial);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("%s\n", get_nt_error_msg(result)));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/source/rpcclient/spoolss_cmds.c b/source/rpcclient/spoolss_cmds.c
new file mode 100644
index 00000000000..b010aa4874c
--- /dev/null
+++ b/source/rpcclient/spoolss_cmds.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/****************************************************************************
+ This defines the commands supported by this client
+ ****************************************************************************/
+static const struct command_set spl_commands[] = {
+ /*
+ * printer testing
+ */
+
+ {"SPOOLSS", NULL, NULL, {NULL, NULL}},
+
+ {"spoolenum", cmd_spoolss_enum_printers,
+ "Enumerate Printers",
+ {NULL, NULL}},
+
+ {"spoolenumports", cmd_spoolss_enum_ports,
+ "<port info level> Enumerate Ports",
+ {NULL, NULL}},
+
+ {"spoolenumdatas", cmd_spoolss_enum_printerdata,
+ "<printer name> Enumerate Printer datas",
+ {NULL, NULL}},
+
+ {"spooljobs", cmd_spoolss_enum_jobs,
+ "<printer name> Enumerate Printer Jobs",
+ {NULL, NULL}},
+
+ {"spoolopen", cmd_spoolss_open_printer_ex,
+ "<printer name> Spool Printer Open Test",
+ {NULL, NULL}},
+
+ {"spoolgetdata", cmd_spoolss_getprinterdata,
+ "<printer name> <value name> Spool Get Printer Data test",
+ {NULL, NULL}},
+
+ {"spoolgetprinter", cmd_spoolss_getprinter,
+ "<printer name> Spool get printer",
+ {NULL, NULL}},
+
+ {"spoolgetprinterdriver", cmd_spoolss_getprinterdriver,
+ "<printer name> Spool get printer driver",
+ {NULL, NULL}},
+
+ {"spoolgetprinterdriverdir", cmd_spoolss_getprinterdriverdir,
+ "Spool get printer driver directory",
+ {NULL, NULL}},
+
+ {"spooladdprinter", cmd_spoolss_addprinterex,
+ "<name> <driver> Spool AddPrinterEx()",
+ {NULL, NULL}},
+
+ {"spooladdprinterdriver", cmd_spoolss_addprinterdriver,
+ "<driver> Spool AddPrinterDriver()",
+ {NULL, NULL}},
+
+ /*
+ * oop!
+ */
+ {"", NULL, NULL, {NULL, NULL}}
+};
+
+void add_spl_commands(void)
+{
+ add_command_set(spl_commands);
+}
diff --git a/source/script/.cvsignore b/source/script/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/script/.cvsignore
diff --git a/source/script/addtosmbpass b/source/script/addtosmbpass
index 42af518397c..bc82851c52d 100644
--- a/source/script/addtosmbpass
+++ b/source/script/addtosmbpass
@@ -41,18 +41,18 @@ BEGIN {
{
print $0;
for(name in names) {
- if($1 ~ name) {
+ if($1 == name) {
delete names[name];
}
}
}
END {
fmt = "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:";
- fmt = fmt "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n";
+ fmt = fmt "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[U ]:LCT-00000000:%s:\n";
for(name in names) {
while ((getline < pwdf) > 0) {
if ($1 == name) {
- printf(fmt, $1, $3, $5, $6, $7);
+ printf(fmt, $1, $3, $5);
close(pwdf);
notfound = "";
break;
@@ -65,7 +65,7 @@ END {
command = ypmatch " " name " passwd";
command | getline;
if (NF > 0) {
- printf(fmt, $1, $3, $5, $6, $7);
+ printf(fmt, $1, $3, $5);
}
close(command);
}
diff --git a/source/script/build_env.sh b/source/script/build_env.sh
new file mode 100755
index 00000000000..0000759f160
--- /dev/null
+++ b/source/script/build_env.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+uname=`uname -a`
+date=`date`
+srcdir=$1
+builddir=$2
+compiler=$3
+
+ if [ ! "x$USER" = "x" ]; then
+ whoami=$USER
+ else
+ if [ ! "x$LOGNAME" = "x" ]; then
+ whoami=$LOGNAME
+ else
+ whoami=`whoami || id -un`
+ fi
+ fi
+
+host=`hostname`
+
+cat <<EOF
+/* This file is automatically generated with "make build_env". DO NOT EDIT */
+
+#ifndef _BUILD_ENV_H
+#define _BUILD_ENV_H
+
+#define BUILD_ENV_UNAME "${uname}"
+#define BUILD_ENV_DATE "${date}"
+#define BUILD_ENV_SRCDIR "${srcdir}"
+#define BUILD_ENV_BUILDDIR "${builddir}"
+#define BUILD_ENV_USER "${whoami}"
+#define BUILD_ENV_HOST "${host}"
+#define BUILD_ENV_COMPILER "${compiler}"
+#endif /* _BUILD_ENV_H */
+EOF
diff --git a/source/script/convert_smbpasswd b/source/script/convert_smbpasswd
new file mode 100755
index 00000000000..edb775d3a67
--- /dev/null
+++ b/source/script/convert_smbpasswd
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# Convert a Samba 1.9.18 smbpasswd file format into
+# a Samba 2.0 smbpasswd file format.
+# Read from stdin and write to stdout for simplicity.
+# Set the last change time to 0x363F96AD to avoid problems
+# with trying to work out how to get the seconds since 1970
+# in awk or the shell. JRA.
+#
+nawk 'BEGIN {FS=":"}
+{
+ if( $0 ~ "^#" ) {
+ print $0
+ } else {
+ printf( "%s:%s:%s:%s:[U ]:LCT-363F96AD:\n", $1, $2, $3, $4);
+ }
+}'
diff --git a/source/script/extract_allparms.sh b/source/script/extract_allparms.sh
new file mode 100755
index 00000000000..f16068b3fdc
--- /dev/null
+++ b/source/script/extract_allparms.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+grep '{".*P_[GL]' param/loadparm.c | sed -e 's/&.*$//g' -e 's/",.*P_LOCAL.*$/ S/' -e 's/",.*P_GLOBAL.*$/ G/' -e 's/^ .*{"//g' | sort -f
diff --git a/source/script/installbin.sh b/source/script/installbin.sh
index 633e6cb5bb2..77bded6420f 100755
--- a/source/script/installbin.sh
+++ b/source/script/installbin.sh
@@ -1,4 +1,5 @@
#!/bin/sh
+
INSTALLPERMS=$1
BASEDIR=$2
BINDIR=$3
@@ -10,7 +11,7 @@ shift
shift
shift
-for d in $BASEDIR $BINDIR $LIBDIR $VARDIR; do
+for d in $BASEDIR $BINDIR $LIBDIR $VARDIR $BASEDIR/private; do
if [ ! -d $d ]; then
mkdir $d
if [ ! -d $d ]; then
@@ -22,21 +23,29 @@ done
for p in $*; do
- echo Installing $p as $BINDIR/$p
- if [ -f $BINDIR/$p ]; then
- mv $BINDIR/$p $BINDIR/$p.old
+ p2=`basename $p`
+ echo Installing $p as $BINDIR/$p2
+ if [ -f $BINDIR/$p2 ]; then
+ rm -f $BINDIR/$p2.old
+ mv $BINDIR/$p2 $BINDIR/$p2.old
+ fi
+ cp $p $BINDIR/
+ chmod $INSTALLPERMS $BINDIR/$p2
+
+ # this is a special case, mount needs this in a specific location
+ if [ $p2 = smbmount ]; then
+ ln -sf $BINDIR/$p2 /sbin/mount.smbfs
fi
- cp $p $BINDIR/$p
- chmod $INSTALLPERMS $BINDIR/$p
done
cat << EOF
======================================================================
The binaries are installed. You may restore the old binaries (if there
-were any) using the command "make revert"
+were any) using the command "make revert". You may uninstall the binaries
+using the command "make uninstallbin" or "make uninstall" to uninstall
+binaries, man pages and shell scripts.
======================================================================
EOF
exit 0
-
diff --git a/source/script/installcp.sh b/source/script/installcp.sh
new file mode 100755
index 00000000000..d0c5bf8ecc9
--- /dev/null
+++ b/source/script/installcp.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+srcdir=$1
+LIBDIR=$2
+CODEPAGEDIR=$3
+BINDIR=$4
+
+shift
+shift
+shift
+shift
+
+echo Installing codepage files in $CODEPAGEDIR
+for d in $LIBDIR $CODEPAGEDIR; do
+if [ ! -d $d ]; then
+mkdir $d
+if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ exit 1
+fi
+fi
+done
+
+for p in $*; do
+ if [ -f ${srcdir}/codepages/codepage_def.$p ]; then
+ echo Creating codepage file $CODEPAGEDIR/codepage.$p
+ $BINDIR/make_smbcodepage c $p ${srcdir}/codepages/codepage_def.$p $CODEPAGEDIR/codepage.$p
+ fi
+ if [ -f ${srcdir}/codepages/CP${p}.TXT ]; then
+ echo Creating unicode map $CODEPAGEDIR/unicode_map.$p
+ $BINDIR/make_unicodemap $p ${srcdir}/codepages/CP${p}.TXT $CODEPAGEDIR/unicode_map.$p
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The code pages have been installed. You may uninstall them using the
+command "make uninstallcp" or make "uninstall" to uninstall binaries,
+man pages, shell scripts and code pages.
+======================================================================
+EOF
+
+exit 0
+
diff --git a/source/script/installman.sh b/source/script/installman.sh
index a79d157c5f5..2329ed5425c 100755
--- a/source/script/installman.sh
+++ b/source/script/installman.sh
@@ -1,35 +1,71 @@
#!/bin/sh
-MANDIR=$1
-SRCDIR=$2
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+#
+# 13 Aug 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+# modified to accomodate international man pages (inspired
+# by Japanese edition's approach)
-echo Installing man pages in $MANDIR
+MANDIR=$1
+SRCDIR=$2/
+langs=$3
-for d in $MANDIR $MANDIR/man1 $MANDIR/man5 $MANDIR/man7 $MANDIR/man8; do
-if [ ! -d $d ]; then
-mkdir $d
-if [ ! -d $d ]; then
- echo Failed to make directory $d
- exit 1
-fi
+if [ $# -ge 4 ] ; then
+ GROFF=$4 # sh cmd line, including options
fi
+
+
+for lang in $langs; do
+ if [ "X$lang" = Xen ]; then
+ echo Installing default man pages in $MANDIR/
+ lang=.
+ else
+ echo Installing \"$lang\" man pages in $MANDIR/lang/$lang
+ fi
+
+ langdir=$MANDIR/lang/$lang
+ for d in $MANDIR $MANDIR/lang $langdir $langdir/man1 $langdir/man5 $langdir/man7 $langdir/man8; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d, does $USER have privileges?
+ exit 1
+ fi
+ fi
+ done
+
+ for sect in 1 5 7 8 ; do
+ for m in $langdir/man$sect ; do
+ for s in $SRCDIR../docs/manpages/$lang/*$sect; do
+ FNAME=$m/`basename $s`
+
+ # Test for writability. Involves
+ # blowing away existing files.
+
+ if (rm -f $FNAME && touch $FNAME); then
+ rm $FNAME
+ if [ "x$GROFF" = x ] ; then
+ cp $s $m # Copy raw nroff
+ else
+ echo "\t$FNAME" # groff'ing can be slow, give the user
+ # a warm fuzzy.
+ $GROFF $s > $FNAME # Process nroff, because man(1) (on
+ # this system) doesn't .
+ fi
+ chmod 0644 $FNAME
+ else
+ echo Cannot create $FNAME... does $USER have privileges?
+ fi
+ done
+ done
+ done
done
+cat << EOF
+======================================================================
+The man pages have been installed. You may uninstall them using the command
+the command "make uninstallman" or make "uninstall" to uninstall binaries,
+man pages and shell scripts.
+======================================================================
+EOF
-cp $SRCDIR../docs/*.1 $MANDIR/man1
-cp $SRCDIR../docs/*.5 $MANDIR/man5
-cp $SRCDIR../docs/*.8 $MANDIR/man8
-cp $SRCDIR../docs/*.7 $MANDIR/man7
-echo Setting permissions on man pages
-chmod 0644 $MANDIR/man1/smbstatus.1
-chmod 0644 $MANDIR/man1/smbclient.1
-chmod 0644 $MANDIR/man1/smbrun.1
-chmod 0644 $MANDIR/man1/testparm.1
-chmod 0644 $MANDIR/man1/testprns.1
-chmod 0644 $MANDIR/man1/smbtar.1
-chmod 0644 $MANDIR/man5/smb.conf.5
-chmod 0644 $MANDIR/man7/samba.7
-chmod 0644 $MANDIR/man8/smbd.8
-chmod 0644 $MANDIR/man8/nmbd.8
-
-echo Man pages installed
exit 0
diff --git a/source/script/installscripts.sh b/source/script/installscripts.sh
new file mode 100755
index 00000000000..bff5423e7cb
--- /dev/null
+++ b/source/script/installscripts.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# this script courtesy of James_K._Foote.PARC@xerox.com
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au Don't hardcode script names, get from Make
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+echo Installing scripts in $BINDIR
+
+for d in $BINDIR; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ echo Have you run installbin first?
+ exit 1
+ fi
+ fi
+done
+
+for p in $*; do
+ p2=`basename $p`
+ echo Installing $BINDIR/$p2
+ if [ -f $BINDIR/$p2 ]; then
+ rm -f $BINDIR/$p2.old
+ mv $BINDIR/$p2 $BINDIR/$p2.old
+ fi
+ cp $p $BINDIR/
+ chmod $INSTALLPERMS $BINDIR/$p2
+ if [ ! -f $BINDIR/$p2 ]; then
+ echo Cannot copy $p2... does $USER have privileges?
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been installed. You may uninstall them using
+the command "make uninstallscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover the previous version (if any
+by "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/installswat.sh b/source/script/installswat.sh
new file mode 100755
index 00000000000..c66604cdb84
--- /dev/null
+++ b/source/script/installswat.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+#fist version March 1998, Andrew Tridgell
+
+SWATDIR=$1
+SRCDIR=$2/
+BOOKDIR=$SWATDIR/using_samba
+
+echo Installing SWAT in $SWATDIR
+echo Installing the Samba Web Administration Tool
+
+LANGS=". `cd $SRCDIR../swat/; /bin/echo lang/??`"
+echo Installing langs are `cd $SRCDIR../swat/lang/; /bin/echo ??`
+
+for ln in $LANGS; do
+ SWATLANGDIR=$SWATDIR/$ln
+ for d in $SWATLANGDIR $SWATLANGDIR/help $SWATLANGDIR/images \
+ $SWATLANGDIR/include; do
+ if [ ! -d $d ]; then
+ mkdir -p $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d, does $USER have privileges?
+ exit 1
+ fi
+ fi
+ done
+done
+
+# Install images
+for ln in $LANGS; do
+
+for f in $SRCDIR../swat/$ln/images/*.gif; do
+ FNAME=$SWATDIR/$ln/images/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+# Install html help
+
+for f in $SRCDIR../swat/$ln/help/*.html; do
+ FNAME=$SWATDIR/$ln/help/`basename $f`
+ echo $FNAME
+ if [ "x$BOOKDIR" = "x" ]; then
+ cat $f | sed 's/@BOOKDIR@.*$//' > $f.tmp
+ else
+ cat $f | sed 's/@BOOKDIR@//' > $f.tmp
+ fi
+ f=$f.tmp
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ rm -f $f
+ chmod 0644 $FNAME
+done
+
+# Install html documentation
+
+for f in $SRCDIR../docs/htmldocs/*.html; do
+ FNAME=$SWATDIR/help/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+# Install "server-side" includes
+
+for f in $SRCDIR../swat/$ln/include/*.html; do
+ FNAME=$SWATDIR/$ln/include/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+done
+
+# Install Using Samba book
+
+if [ "x$BOOKDIR" != "x" ]; then
+
+ # Create directories
+
+ for d in $BOOKDIR $BOOKDIR/figs $BOOKDIR/gifs; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d, does $USER have privileges?
+ exit 1
+ fi
+ fi
+ done
+
+ # HTML files
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/*.html; do
+ FNAME=$BOOKDIR/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+
+ # Figures
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/figs/*.gif; do
+ FNAME=$BOOKDIR/figs/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+
+ # Gifs
+
+ for f in $SRCDIR../docs/htmldocs/using_samba/gifs/*.gif; do
+ FNAME=$BOOKDIR/gifs/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+
+fi
+
+cat << EOF
+======================================================================
+The SWAT files have been installed. Remember to read the swat/README
+for information on enabling and using SWAT
+======================================================================
+EOF
+
+exit 0
+
diff --git a/source/script/makeunicodecasemap.awk b/source/script/makeunicodecasemap.awk
new file mode 100644
index 00000000000..8424b6c6725
--- /dev/null
+++ b/source/script/makeunicodecasemap.awk
@@ -0,0 +1,59 @@
+function reset_vals() {
+ upperstr = "";
+ lowerstr = "";
+ flagstr = "0";
+}
+
+function print_val() {
+ upperstr = $13;
+ lowerstr = $14;
+ if ( upperstr == "" )
+ upperstr = strval;
+ if ( lowerstr == "" )
+ lowerstr = strval;
+
+ if ( $3 == "Lu" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_UPPER");
+ if ( $3 == "Ll" )
+ flagstr = sprintf("%s|%s", flagstr, "UNI_LOWER");
+ if ( val >= 48 && val <= 57)
+ flagstr = sprintf("%s|%s", flagstr, "UNI_DIGIT");
+ if ((val >= 48 && val <= 57) || (val >= 65 && val <= 70) || (val >=97 && val <= 102))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_XDIGIT");
+ if ( val == 32 || (val >=9 && val <= 13))
+ flagstr = sprintf("%s|%s", flagstr, "UNI_SPACE");
+ if( index(flagstr, "0|") == 1)
+ flagstr = substr(flagstr, 3, length(flagstr) - 2);
+ printf("{ 0x%s, 0x%s, %s }, \t\t\t/* %s %s */\n", lowerstr, upperstr, flagstr, strval, $2);
+ val++;
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+BEGIN {
+ val=0
+ FS=";"
+ strval=sprintf("%04X", val);
+ reset_vals();
+}
+
+{
+ if ( $1 == strval ) {
+ print_val();
+ } else {
+ while ( $1 != strval) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+ print_val();
+ }
+}
+
+END {
+ while ( val < 65536 ) {
+ printf("{ 0x%04X, 0x%04X, 0 }, \t\t\t/* %s NOMAP */\n", val, val, strval);
+ val++;
+ strval=sprintf("%04X", val);
+ }
+}
diff --git a/source/script/makeyodldocs.sh b/source/script/makeyodldocs.sh
new file mode 100755
index 00000000000..5b54df033e5
--- /dev/null
+++ b/source/script/makeyodldocs.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+SRCDIR=$1
+shift
+FILES=$@
+
+if test -z $FILES; then
+ FILES=*.yo
+fi
+
+YODLDIR=$SRCDIR/../docs/yodldocs
+MANPAGEDIR=$SRCDIR/../docs/manpages
+HTMLDIR=$SRCDIR/../docs/htmldocs
+
+echo "Re-creating man pages and HTML pages from YODL sources..."
+
+if [ ! -d $MANPAGEDIR ]; then
+ echo "directory $MANPAGEDIR does not exist, are we in the right place?"
+ exit 1
+fi
+
+if [ ! -d $HTMLDIR ]; then
+ echo "directory $HTMLDIR does not exist, are we in the right place?"
+ exit 1
+fi
+
+if [ ! -d $YODLDIR ]; then
+ echo "directory $YODLDIR does not exist, are we in the right place?"
+ exit 1
+fi
+
+cd $YODLDIR
+
+for d in $FILES
+do
+
+#
+# Create the basename from the YODL manpage
+#
+ bn=`echo $d | sed -e 's/\.yo//'`
+
+ case "$d"
+ in
+ *.[0-9].yo)
+ echo "Creating man pages..."
+ echo $d
+ rm -f $bn.man
+ yodl2man $d
+ if [ ! -f $bn.man ]; then
+ echo "Failed to make man page for $d"
+ exit 1
+ fi
+ cp $bn.man ../manpages/$bn || echo "Cannot create $YODLDIR/../manpages/$bn"
+ rm -f $bn.man
+
+ echo "Creating html versions of man pages..."
+ echo $d
+ rm -f $bn.html
+ yodl2html $d
+ if [ ! -f $bn.html ]; then
+ echo "Failed to make html page for $d"
+ exit 1
+ fi
+ cp $bn.html ../htmldocs || echo "Cannot create $YODLDIR/../htmldocs/$bn.html"
+ rm -f $bn.html
+ ;;
+ *)
+#
+# Non man-page YODL docs - just make html and text.
+#
+ echo $d
+ rm -f $bn.html
+ yodl2html $d
+ if [ ! -f $bn.html ]; then
+ echo "Failed to make html page for $d"
+ exit 1
+ fi
+ cp $bn.html ../htmldocs || echo "Cannot create $YODLDIR/../htmldocs/$bn.html"
+ rm -f $bn.html
+ rm -f $bn.txt
+ yodl2txt $d
+ if [ ! -f $bn.txt ]; then
+ echo "Failed to make text page for $d"
+ exit 1
+ fi
+ cp $bn.txt ../textdocs || echo "Cannot create $YODLDIR/../textdocs/$bn.txt"
+ rm -f $bn.txt
+ ;;
+ esac
+done
+
+echo "Remember to CVS check in your changes..."
+exit 0
diff --git a/source/script/mkinstalldirs b/source/script/mkinstalldirs
new file mode 100755
index 00000000000..5020c625548
--- /dev/null
+++ b/source/script/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2001/09/24 15:55:08 monyo Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/source/script/mknissmbpasswd.sh b/source/script/mknissmbpasswd.sh
new file mode 100755
index 00000000000..a94c963bdce
--- /dev/null
+++ b/source/script/mknissmbpasswd.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Copyright (C) 1998 Benny Holmgren
+#
+# Script to import smbpasswd file into the smbpasswd NIS+ table. Reads
+# from stdin the smbpasswd file.
+#
+while true
+do
+ read row
+ if [ -z "$row" ]
+ then
+ break
+ fi
+
+ if [ "`echo $row | cut -c1`" = "#" ]
+ then
+ continue
+ fi
+
+ nistbladm -a \
+ name=\"`echo $row | cut -d: -f1`\" \
+ uid=\"`echo $row | cut -d: -f2`\" \
+ lmpwd=\"`echo $row | cut -d: -f3`\" \
+ ntpwd=\"`echo $row | cut -d: -f4`\" \
+ acb=\"`echo $row | cut -d: -f5`\" \
+ pwdlset_t=\"`echo $row | cut -d: -f6`\" \
+ gcos=\"`echo $row | cut -d: -f7`\" \
+ home=\"`echo $row | cut -d: -f8`\" \
+ shell=\"`echo $row | cut -d: -f9`\" smbpasswd.org_dir.`nisdefaults -d`
+done
diff --git a/source/script/mknissmbpwdtbl.sh b/source/script/mknissmbpwdtbl.sh
new file mode 100755
index 00000000000..a9b34ff9a75
--- /dev/null
+++ b/source/script/mknissmbpwdtbl.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Copyright (C) 1998 Benny Holmgren
+#
+# Creates smbpasswd table and smb group in NIS+
+#
+
+nistbladm \
+ -D access=og=rmcd,nw= -c \
+ -s : smbpasswd_tbl \
+ name=S,nogw=r \
+ uid=S,nogw=r \
+ user_rid=S,nogw=r \
+ smb_grpid=,nw+r \
+ group_rid=,nw+r \
+ acb=,nw+r \
+ \
+ lmpwd=C,nw=,g=r,o=rm \
+ ntpwd=C,nw=,g=r,o=rm \
+ \
+ logon_t=,nw+r \
+ logoff_t=,nw+r \
+ kick_t=,nw+r \
+ pwdlset_t=,nw+r \
+ pwdlchg_t=,nw+r \
+ pwdmchg_t=,nw+r \
+ \
+ full_name=,nw+r \
+ home_dir=,nw+r \
+ dir_drive=,nw+r \
+ logon_script=,nw+r \
+ profile_path=,nw+r \
+ acct_desc=,nw+r \
+ workstations=,nw+r \
+ \
+ hours=,nw+r \
+ smbpasswd.org_dir.`nisdefaults -d`
+
+nisgrpadm -c smb.`nisdefaults -d`
+
+nischgrp smb.`nisdefaults -d` smbpasswd.org_dir.`nisdefaults -d`
+
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
new file mode 100644
index 00000000000..36f5b0afd12
--- /dev/null
+++ b/source/script/mkproto.awk
@@ -0,0 +1,153 @@
+BEGIN {
+ inheader=0;
+# use_ldap_define = 0;
+ current_file="";
+ if (headername=="") {
+ headername="_PROTO_H_";
+ }
+
+ print "#ifndef",headername
+ print "#define",headername
+ print "/* This file is automatically generated with \"make proto\". DO NOT EDIT */"
+ print ""
+}
+
+END {
+ print "#endif /* _PROTO_H_ */"
+}
+
+{
+ if (FILENAME!=current_file) {
+# if (use_ldap_define)
+# {
+# print "#endif /* USE_LDAP */"
+# use_ldap_define = 0;
+# }
+ print ""
+ print "/* The following definitions come from",FILENAME," */"
+ print ""
+ current_file=FILENAME
+ }
+ if (inheader) {
+ if (match($0,"[)][ \t]*$")) {
+ inheader = 0;
+ printf "%s;\n",$0;
+ } else {
+ printf "%s\n",$0;
+ }
+ next;
+ }
+}
+
+# special handling for code merge of TNG to head
+/^#define OLD_NTDOMAIN 1/ {
+ printf "#if OLD_NTDOMAIN\n"
+}
+/^#undef OLD_NTDOMAIN/ {
+ printf "#endif\n"
+}
+/^#define NEW_NTDOMAIN 1/ {
+ printf "#if NEW_NTDOMAIN\n"
+}
+/^#undef NEW_NTDOMAIN/ {
+ printf "#endif\n"
+}
+
+# we handle the loadparm.c fns separately
+
+/^FN_LOCAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_LIST/ {
+ split($0,a,"[,()]")
+ printf "char **%s(int );\n", a[2]
+}
+
+/^FN_LOCAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(int );\n", a[2]
+}
+
+/^FN_LOCAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_CHAR/ {
+ split($0,a,"[,()]")
+ printf "char %s(int );\n", a[2]
+}
+
+/^FN_GLOBAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_LIST/ {
+ split($0,a,"[,()]")
+ printf "char **%s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(void);\n", a[2]
+}
+
+/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
+ next;
+}
+
+#
+# We have to split up the start
+# matching as we now have so many start
+# types that it can cause some versions
+# of nawk/awk to choke and fail on
+# the full match. JRA.
+#
+
+{
+ gotstart = 0;
+ if( $0 ~ /^const|^connection_struct|^pipes_struct|^file_fd_struct|^files_struct|^connection_struct|^uid_t|^gid_t|^unsigned|^mode_t|^DIR|^user|^int|^pid_t|^ino_t|^off_t/ ) {
+ gotstart = 1;
+ }
+
+ if( $0 ~ /^vuser_key|^UNISTR2|^LOCAL_GRP|^DOMAIN_GRP|^SMB_STRUCT_DIRENT|^SEC_ACL|^SEC_DESC|^SEC_DESC_BUF|^DOM_SID|^RPC_HND_NODE|^BYTE/ ) {
+ gotstart = 1;
+ }
+
+ if( $0 ~ /^ADS_STRUCT|^ADS_STATUS|^DATA_BLOB|^ASN1_DATA|^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum.*\(|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) {
+ gotstart = 1;
+ }
+
+ if( $0 ~ /^smb_iconv_t|^long|^char|^uint|^NTSTATUS|^WERROR|^CLI_POLICY_HND|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^FILE|^XFILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT/ ) {
+ gotstart = 1;
+ }
+
+ if( $0 ~ /^SAM_ACCT_INFO_NODE|^SMB_ACL_T/ ) {
+ gotstart = 1;
+ }
+
+ if(!gotstart) {
+ next;
+ }
+}
+
+
+/[(].*[)][ \t]*$/ {
+ printf "%s;\n",$0;
+ next;
+}
+
+/[(]/ {
+ inheader=1;
+ printf "%s\n",$0;
+ next;
+}
+
diff --git a/source/script/mkproto.sh b/source/script/mkproto.sh
new file mode 100755
index 00000000000..4dbe4c204e7
--- /dev/null
+++ b/source/script/mkproto.sh
@@ -0,0 +1,41 @@
+#! /bin/sh
+
+LANG=C; export LANG
+LC_ALL=C; export LC_ALL
+LC_COLLATE=C; export LC_COLLATE
+
+if [ $# -lt 3 ]
+then
+ echo "Usage: $0 awk [-h headerdefine] outputheader proto_obj"
+ exit 1
+fi
+
+awk="$1"
+shift
+
+if [ x"$1" = x-h ]
+then
+ headeropt="-v headername=$2"
+ shift; shift;
+else
+ headeropt=""
+fi
+
+header="$1"
+shift
+headertmp="$header.$$.tmp~"
+
+proto_src="`echo $@ | tr ' ' '\n' | sed -e 's/\.o/\.c/g' | sort | uniq | egrep -v 'ubiqx/|wrapped'`"
+
+echo creating $header
+
+${awk} $headeropt \
+ -f script/mkproto.awk $proto_src > $headertmp
+
+if cmp -s $header $headertmp 2>/dev/null
+then
+ echo "$header unchanged"
+ rm $headertmp
+else
+ mv $headertmp $header
+fi
diff --git a/source/script/mksmbpasswd.sh b/source/script/mksmbpasswd.sh
index 6e592acd652..854e1bd1b57 100755
--- a/source/script/mksmbpasswd.sh
+++ b/source/script/mksmbpasswd.sh
@@ -2,5 +2,5 @@
awk 'BEGIN {FS=":"
printf("#\n# SMB password file.\n#\n")
}
-{ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }
+{ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:[U ]:LCT-00000000:%s\n", $1, $3, $5) }
'
diff --git a/source/script/revert.sh b/source/script/revert.sh
index 68b47bf39d0..8df5fd2fbde 100755
--- a/source/script/revert.sh
+++ b/source/script/revert.sh
@@ -3,11 +3,14 @@ BINDIR=$1
shift
for p in $*; do
- if [ -f $BINDIR/$p.old ]; then
- echo Restoring $BINDIR/$p.old as $BINDIR/$p
- mv $BINDIR/$p $BINDIR/$p.new
- mv $BINDIR/$p.old $BINDIR/$p
- rm -f $BINDIR/$p.new
+ p2=`basename $p`
+ if [ -f $BINDIR/$p2.old ]; then
+ echo Restoring $BINDIR/$p2.old
+ mv $BINDIR/$p2 $BINDIR/$p2.new
+ mv $BINDIR/$p2.old $BINDIR/$p2
+ rm -f $BINDIR/$p2.new
+ else
+ echo Not restoring $p
fi
done
diff --git a/source/script/scancvslog.pl b/source/script/scancvslog.pl
new file mode 100755
index 00000000000..c39f9111c10
--- /dev/null
+++ b/source/script/scancvslog.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+require"timelocal.pl";
+
+#
+# usage scancvslog.pl logfile starttime tag
+#
+# this will extract all entries from the specified cvs log file
+# that have a date later than or equal to starttime and a tag
+# value of tag. If starttime is not specified, all entries are
+# extracted. If tag is not specified then entries for all
+# branches are extracted. starttime must be specified as
+# "monthname day, year"
+#
+# Example to extract all entries for SAMBA_2_2 branch from the
+# log file named cvs.log
+#
+# scancvslog.pl cvs.log "" SAMBA_2_2
+#
+#
+# To extract all log entries after Jan 10, 1999 (Note month name
+# must be spelled out completely).
+#
+# scancvslog.pl cvs.log "January 10, 1999"
+#
+
+open(INFILE,@ARGV[0]) || die "Unable to open @ARGV[0]\n";
+
+%Monthnum = (
+ "January", 0,
+ "February", 1,
+ "March", 2,
+ "April", 3,
+ "May", 4,
+ "June", 5,
+ "July", 6,
+ "August", 7,
+ "September", 8,
+ "October", 9,
+ "November", 10,
+ "December", 11,
+ "Jan", 0,
+ "Feb", 1,
+ "Mar", 2,
+ "Apr", 3,
+ "May", 4,
+ "Jun", 5,
+ "Jul", 6,
+ "Aug", 7,
+ "Sep", 8,
+ "Oct", 9,
+ "Nov", 10,
+ "Dec", 11
+);
+
+$Starttime = (@ARGV[1]) ? &make_time(@ARGV[1]) : 0;
+$Tagvalue = @ARGV[2];
+
+while (&get_entry) {
+ $_=$Entry[0];
+# get rid of extra white space
+ s/\s+/ /g;
+# get rid of any time string in date
+ s/ \d\d:\d\d:\d\d/,/;
+ s/^Date:\s*\w*\s*(\w*)\s*(\w*),\s*(\w*).*/$1 $2 $3/;
+ $Testtime = &make_time($_);
+ $Testtag = &get_tag;
+ if (($Testtime >= $Starttime) && ($Tagvalue eq $Testtag)) {
+ print join("\n",@Entry),"\n";
+ }
+}
+close(INFILE);
+
+sub make_time {
+ $_ = @_[0];
+ s/,//;
+ ($month, $day, $year) = split(" ",$_);
+ if (($year < 1900)||($day < 1)||($day > 31)||not length($Monthnum{$month})) {
+ print "Bad date format @_[0]\n";
+ print "Date needs to be specified as \"Monthname day, year\"\n";
+ print "eg: \"January 10, 1999\"\n";
+ exit 1;
+ }
+ $year = ($year == 19100) ? 2000 : $year;
+ $month = $Monthnum{$month};
+ $Mytime=&timelocal((0,0,0,$day,$month,$year));
+}
+
+sub get_tag {
+ @Mytag = grep (/Tag:/,@Entry);
+ $_ = @Mytag[0];
+ s/^.*Tag:\s*(\w*).*/$1/;
+ return $_;
+}
+
+sub get_entry {
+ @Entry=();
+ if (not eof(INFILE)) {
+ while (not eof(INFILE)) {
+ $_ = <INFILE>;
+ chomp $_;
+ next if (not ($_));
+ if (/^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/) {
+ next if ($#Entry == -1);
+ push(Entry,$_);
+ return @Entry;
+ } else {
+ push(Entry,$_);
+ }
+ }
+ }
+ return @Entry;
+}
diff --git a/source/script/smbtar b/source/script/smbtar
index fc032ed41cd..cf3ff0ebe68 100644
--- a/source/script/smbtar
+++ b/source/script/smbtar
@@ -6,13 +6,19 @@
# and Ricky Poulten (ricky@logcam.co.uk)
#
# (May need to change shell to ksh for HPUX or OSF for better getopts)
+#
+# sandy nov 3 '98 added -a flag
+#
+# Richard Sharpe, added -c 'tarmode full' so that we back up all files to
+# fix a bug in clitar when a patch was added to stop system and hidden files
+# being backed up.
case $0 in
# when called by absolute path, assume smbclient is in the same directory
/*)
SMBCLIENT="`dirname $0`/smbclient";;
- *) # edit this to show where your smbclient is
- SMBCLIENT="./smbclient";;
+ *) # you may need to edit this to show where your smbclient is
+ SMBCLIENT="smbclient";;
esac
# These are the default values. You could fill them in if you know what
@@ -24,7 +30,10 @@ username=$LOGNAME # Default: same user name as in *nix
verbose="2>/dev/null" # Default: no echo to stdout
log="-d 2"
newer=""
+newerarg=""
blocksize=""
+blocksizearg=""
+clientargs="-c 'tarmode full'"
tarcmd="c"
tarargs=""
cdcmd="\\"
@@ -38,6 +47,7 @@ Function: backup/restore a Windows PC directories to a local tape file
Options: (Description) (Default)
-r Restore from tape file to PC Save from PC to tapefile
-i Incremental mode Full backup mode
+ -a Reset archive bit mode Don't reset archive bit
-v Verbose mode: echo command Don't echo anything
-s <server> Specify PC Server $server
-p <password> Specify PC Password $password
@@ -54,7 +64,17 @@ Options: (Description) (Default)
exit $ex
}
-while getopts rivl:b:d:N:s:p:x:u:Xt: c; do
+# echo Params count: $#
+
+# DEC OSF AKA Digital UNIX does not seem to return a value in OPTIND if
+# there are no command line params, so protect us against that ...
+if [ $# = 0 ]; then
+
+ Usage 2 "Please enter a command line parameter!"
+
+fi
+
+while getopts riavl:b:d:N:s:p:x:u:Xt: c; do
case $c in
r) # [r]estore to Windows (instead of the default "Save from Windows")
tarcmd="x"
@@ -62,6 +82,9 @@ while getopts rivl:b:d:N:s:p:x:u:Xt: c; do
i) # [i]ncremental
tarargs=${tarargs}g
;;
+ a) # [a]rchive
+ tarargs=${tarargs}a
+ ;;
l) # specify [l]og file
log="-d $OPTARG"
case "$OPTARG" in
@@ -76,7 +99,7 @@ while getopts rivl:b:d:N:s:p:x:u:Xt: c; do
N) # compare with a file, test if [n]ewer
if [ -f $OPTARG ]; then
newer=$OPTARG
- tarargs=${tarargs}N
+ newerarg="N"
else
echo >&2 $0: Warning, $OPTARG not found
fi
@@ -88,13 +111,13 @@ while getopts rivl:b:d:N:s:p:x:u:Xt: c; do
server="$OPTARG"
;;
b) # specify [b]locksize
- blocksize="blocksize $OPTARG"
+ blocksize="$OPTARG"
case "$OPTARG" in
[0-9]*) ;;
*) echo >&2 "$0: Error, block size not numeric: -b $OPTARG"
exit 1
esac
- tarargs=${tarargs}b
+ blocksizearg="b"
;;
p) # specify [p]assword to use
password="$OPTARG"
@@ -134,8 +157,8 @@ if [ -z "$verbose" ]; then
echo "blocksize is $blocksize"
fi
-eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
--E -N $log -D "'$cdcmd'" \
--T${tarcmd}${tarargs} $blocksize $newer $tapefile $* $verbose
-
+tarargs=${tarargs}${blocksizearg}${newerarg}
+eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
+-E -N $log -D "'$cdcmd'" ${clientargs} \
+-T${tarcmd}${tarargs} $blocksize $newer $tapefile '${1+"$@"}' $verbose
diff --git a/source/script/uninstallbin.sh b/source/script/uninstallbin.sh
new file mode 100755
index 00000000000..53775f89465
--- /dev/null
+++ b/source/script/uninstallbin.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+BASEDIR=$2
+BINDIR=$3
+LIBDIR=$4
+VARDIR=$5
+shift
+shift
+shift
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installbin" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ p2=`basename $p`
+ if [ -f $BINDIR/$p2 ]; then
+ echo Removing $BINDIR/$p2
+ rm -f $BINDIR/$p2
+ if [ -f $BINDIR/$p2 ]; then
+ echo Cannot remove $BINDIR/$p2 ... does $USER have privileges?
+ fi
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The binaries have been uninstalled. You may restore the binaries using
+the command "make installbin" or "make install" to install binaries,
+man pages and shell scripts. You can restore a previous version of the
+binaries (if there were any) using "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/uninstallcp.sh b/source/script/uninstallcp.sh
new file mode 100755
index 00000000000..2a9e9d509ab
--- /dev/null
+++ b/source/script/uninstallcp.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+CPDIR=$1
+shift
+
+if [ ! -d $CPDIR ]; then
+ echo Directory $CPDIR does not exist!
+ echo Do a "make installcp" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $CPDIR/unicode_map.$p ]; then
+ echo $CPDIR/unicode_map.$p does not exist!
+ else
+ echo Removing $CPDIR/unicode_map.$p
+ rm -f $CPDIR/unicode_map.$p
+ if [ -f $CPDIR/unicode_map.$p ]; then
+ echo Cannot remove $CPDIR/unicode_map.$p... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The code pages have been uninstalled. You may reinstall them using
+the command "make installcp" or "make install" to install binaries,
+man pages, shell scripts and code pages. You may recover a previous version
+(if any with "make revert").
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/uninstallman.sh b/source/script/uninstallman.sh
new file mode 100755
index 00000000000..3126709831f
--- /dev/null
+++ b/source/script/uninstallman.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+#
+# 13 Aug 2001 Rafal Szczesniak <mimir@spin.ict.pwr.wroc.pl>
+# modified to accomodate international man pages (inspired
+# by Japanese edition's approach)
+
+
+MANDIR=$1
+SRCDIR=$2
+langs=$3
+
+for lang in $langs; do
+ echo Uninstalling \"$lang\" man pages from $MANDIR/$lang
+
+ for sect in 1 5 7 8 ; do
+ for m in $MANDIR/$lang/man$sect ; do
+ for s in $SRCDIR/../docs/manpages/$lang/*$sect; do
+ FNAME=$m/`basename $s`
+ if test -f $FNAME; then
+ echo Deleting $FNAME
+ rm -f $FNAME
+ test -f $FNAME && echo Cannot remove $FNAME... does $USER have privileges?
+ fi
+ done
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been uninstalled. You may install them again using
+the command "make installman" or make "install" to install binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+exit 0
diff --git a/source/script/uninstallscripts.sh b/source/script/uninstallscripts.sh
new file mode 100755
index 00000000000..13104acedd8
--- /dev/null
+++ b/source/script/uninstallscripts.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au - almost identical to uninstallbin.sh
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installscripts" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ p2=`basename $p`
+ if [ -f $BINDIR/$p2 ]; then
+ echo Removing $BINDIR/$p2
+ rm -f $BINDIR/$p2
+ if [ -f $BINDIR/$p2 ]; then
+ echo Cannot remove $BINDIR/$p2 ... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been uninstalled. You may reinstall them using
+the command "make installscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover a previous version (if any
+with "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/smbadduser b/source/smbadduser
new file mode 100755
index 00000000000..e4e1b273d14
--- /dev/null
+++ b/source/smbadduser
@@ -0,0 +1,73 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+unalias *
+set path = ($path /usr/local/samba/bin)
+
+set smbpasswd = /usr/local/samba/private/smbpasswd
+set user_map = /usr/local/samba/lib/users.map
+#
+# Set to site specific passwd command
+#
+#set passwd = "cat /etc/passwd"
+#set passwd = "niscat passwd.org_dir"
+set passwd = "ypcat passwd"
+
+set line = "----------------------------------------------------------"
+if ($#argv == 0) then
+ echo $line
+ echo "Written: Mike Zakharoff email: michael.j.zakharoff@boeing.com"
+ echo ""
+ echo " 1) Updates $smbpasswd"
+ echo " 2) Updates $user_map"
+ echo " 3) Executes smbpasswd for each new user"
+ echo ""
+ echo "smbadduser unixid:ntid unixid:ntid ..."
+ echo ""
+ echo "Example: smbadduser zak:zakharoffm johns:smithj"
+ echo $line
+ exit 1
+endif
+
+touch $smbpasswd $user_map
+set new = ()
+foreach one ($argv)
+ echo $one | grep ':' >& /dev/null
+ if ($status != 0) then
+ echo "ERROR: Must use unixid:ntid like -> zak:zakharoffm"
+ continue
+ endif
+ set unix = `echo $one | awk -F: '{print $1}'`
+ set ntid = `echo $one | awk -F: '{print $2}'`
+
+ set usr = `eval $passwd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#usr != 1) then
+ echo "ERROR: $unix Not in passwd database SKIPPING..."
+ continue
+ endif
+ set tmp = `cat $smbpasswd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#tmp != 0) then
+ echo "ERROR: $unix is already in $smbpasswd SKIPPING..."
+ continue
+ endif
+
+ echo "Adding: $unix to $smbpasswd"
+ eval $passwd | \
+ awk -F: '$1==USR { \
+ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }' USR=$unix >> $smbpasswd
+ if ($unix != $ntid) then
+ echo "Adding: {$unix = $ntid} to $user_map"
+ echo "$unix = $ntid" >> $user_map
+ endif
+ set new = ($new $unix)
+end
+
+#
+# Enter password for new users
+#
+foreach one ($new)
+ echo $line
+ echo "ENTER password for $one"
+ smbpasswd $one
+end
diff --git a/source/smbd/.cvsignore b/source/smbd/.cvsignore
new file mode 100644
index 00000000000..5f2a5c4cf75
--- /dev/null
+++ b/source/smbd/.cvsignore
@@ -0,0 +1,2 @@
+*.po
+*.po32
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
new file mode 100644
index 00000000000..0d2a99b3f07
--- /dev/null
+++ b/source/smbd/blocking.c
@@ -0,0 +1,630 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Blocking Locking functions
+ Copyright (C) Jeremy Allison 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern char *OutBuffer;
+
+/****************************************************************************
+ This is the structure to queue to implement blocking locks.
+ notify. It consists of the requesting SMB and the expiry time.
+*****************************************************************************/
+
+typedef struct {
+ ubi_slNode msg_next;
+ int com_type;
+ files_struct *fsp;
+ time_t expire_time;
+ int lock_num;
+ char *inbuf;
+ int length;
+} blocking_lock_record;
+
+static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_queue, 0};
+
+/****************************************************************************
+ Destructor for the above structure.
+****************************************************************************/
+
+static void free_blocking_lock_record(blocking_lock_record *blr)
+{
+ SAFE_FREE(blr->inbuf);
+ SAFE_FREE(blr);
+}
+
+/****************************************************************************
+ Get the files_struct given a particular queued SMB.
+*****************************************************************************/
+
+static files_struct *get_fsp_from_pkt(char *inbuf)
+{
+ switch(CVAL(inbuf,smb_com)) {
+ case SMBlock:
+ case SMBlockread:
+ return file_fsp(inbuf,smb_vwv0);
+ case SMBlockingX:
+ return file_fsp(inbuf,smb_vwv2);
+ default:
+ DEBUG(0,("get_fsp_from_pkt: PANIC - unknown type on blocking lock queue - exiting.!\n"));
+ exit_server("PANIC - unknown type on blocking lock queue");
+ }
+ return NULL; /* Keep compiler happy. */
+}
+
+/****************************************************************************
+ Determine if this is a secondary element of a chained SMB.
+ **************************************************************************/
+
+static BOOL in_chained_smb(void)
+{
+ return (chain_size != 0);
+}
+
+/****************************************************************************
+ Function to push a blocking lock request onto the lock queue.
+****************************************************************************/
+
+BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num)
+{
+ blocking_lock_record *blr;
+
+ if(in_chained_smb() ) {
+ DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
+ return False;
+ }
+
+ /*
+ * Now queue an entry on the blocking lock queue. We setup
+ * the expiration time here.
+ */
+
+ if((blr = (blocking_lock_record *)malloc(sizeof(blocking_lock_record))) == NULL) {
+ DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
+ return False;
+ }
+
+ if((blr->inbuf = (char *)malloc(length)) == NULL) {
+ DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" ));
+ SAFE_FREE(blr);
+ return False;
+ }
+
+ blr->com_type = CVAL(inbuf,smb_com);
+ blr->fsp = get_fsp_from_pkt(inbuf);
+ blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
+ blr->lock_num = lock_num;
+ memcpy(blr->inbuf, inbuf, length);
+ blr->length = length;
+
+ ubi_slAddTail(&blocking_lock_queue, blr);
+
+
+ DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
+for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout,
+ blr->fsp->fnum, blr->fsp->fsp_name ));
+
+ return True;
+}
+
+/****************************************************************************
+ Return a smd with a given size.
+*****************************************************************************/
+
+static void send_blocking_reply(char *outbuf, int outsize)
+{
+ if(outsize > 4)
+ smb_setlen(outbuf,outsize - 4);
+
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_blocking_reply: send_smb failed.");
+}
+
+/****************************************************************************
+ Return a lockingX success SMB.
+*****************************************************************************/
+
+static void reply_lockingX_success(blocking_lock_record *blr)
+{
+ char *outbuf = OutBuffer;
+ int bufsize = BUFFER_SIZE;
+ char *inbuf = blr->inbuf;
+ int outsize = 0;
+
+ construct_reply_common(inbuf, outbuf);
+ set_message(outbuf,2,0,True);
+
+ /*
+ * As this message is a lockingX call we must handle
+ * any following chained message correctly.
+ * This is normally handled in construct_reply(),
+ * but as that calls switch_message, we can't use
+ * that here and must set up the chain info manually.
+ */
+
+ outsize = chain_reply(inbuf,outbuf,blr->length,bufsize);
+
+ outsize += chain_size;
+
+ send_blocking_reply(outbuf,outsize);
+}
+
+/****************************************************************************
+ Return a generic lock fail error blocking call.
+*****************************************************************************/
+
+static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ construct_reply_common(inbuf, outbuf);
+
+ ERROR_NT(status);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("generic_blocking_lock_error: send_smb failed.");
+}
+
+/****************************************************************************
+ Return a lock fail error for a lockingX call. Undo all the locks we have
+ obtained first.
+*****************************************************************************/
+
+static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ char *inbuf = blr->inbuf;
+ files_struct *fsp = blr->fsp;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0;
+ uint16 lock_pid;
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ int i;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+
+ for(i = blr->lock_num - 1; i >= 0; i--) {
+ BOOL err;
+
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+
+ do_unlock(fsp,conn,lock_pid,count,offset);
+ }
+
+ generic_blocking_lock_error(blr, status);
+}
+
+/****************************************************************************
+ Return a lock fail error.
+*****************************************************************************/
+
+static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
+{
+ switch(blr->com_type) {
+ case SMBlock:
+ case SMBlockread:
+ generic_blocking_lock_error(blr, status);
+ break;
+ case SMBlockingX:
+ reply_lockingX_error(blr, status);
+ break;
+ default:
+ DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
+ exit_server("PANIC - unknown type on blocking lock queue");
+ }
+}
+
+/****************************************************************************
+ Attempt to finish off getting all pending blocking locks for a lockread call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL process_lockread(blocking_lock_record *blr)
+{
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ ssize_t nread = -1;
+ char *data, *p;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ NTSTATUS status;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ files_struct *fsp = blr->fsp;
+
+ numtoread = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+
+ numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+ data = smb_buf(outbuf) + 3;
+
+ status = do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread,
+ (SMB_BIG_UINT)startpos, READ_LOCK);
+ if (NT_STATUS_V(status)) {
+ if ((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Send an error.
+ * Return True so we get dequeued.
+ */
+ generic_blocking_lock_error(blr, status);
+ return True;
+ }
+
+ /*
+ * Still waiting for lock....
+ */
+
+ DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n",
+ fsp->fsp_name));
+ return False;
+ }
+
+ nread = read_file(fsp,data,startpos,numtoread);
+
+ if (nread < 0) {
+ generic_blocking_lock_error(blr,NT_STATUS_ACCESS_DENIED);
+ return True;
+ }
+
+ construct_reply_common(inbuf, outbuf);
+ outsize = set_message(outbuf,5,0,True);
+
+ outsize += nread;
+ SSVAL(outbuf,smb_vwv0,nread);
+ SSVAL(outbuf,smb_vwv5,nread+3);
+ p = smb_buf(outbuf);
+ *p++ = 1;
+ SSVAL(p,0,nread); p += 2;
+ set_message_end(outbuf, p+nread);
+
+ DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n",
+ fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) );
+
+ send_blocking_reply(outbuf,outsize);
+ return True;
+}
+
+/****************************************************************************
+ Attempt to finish off getting all pending blocking locks for a lock call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL process_lock(blocking_lock_record *blr)
+{
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ int outsize;
+ SMB_OFF_T count = 0, offset = 0;
+ NTSTATUS status;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ files_struct *fsp = blr->fsp;
+
+ count = IVAL(inbuf,smb_vwv1);
+ offset = IVAL(inbuf,smb_vwv3);
+
+ errno = 0;
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count,
+ (SMB_BIG_UINT)offset, WRITE_LOCK);
+ if (NT_STATUS_IS_ERR(status)) {
+ if((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Send an error.
+ * Return True so we get dequeued.
+ */
+
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+ /*
+ * Still can't get the lock - keep waiting.
+ */
+ DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n",
+ fsp->fsp_name));
+ return False;
+ }
+
+ /*
+ * Success - we got the lock.
+ */
+
+ DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fsp_name, fsp->fnum, (double)offset, (double)count));
+
+ construct_reply_common(inbuf, outbuf);
+ outsize = set_message(outbuf,0,0,True);
+ send_blocking_reply(outbuf,outsize);
+ return True;
+}
+
+/****************************************************************************
+ Attempt to finish off getting all pending blocking locks for a lockingX call.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL process_lockingX(blocking_lock_record *blr)
+{
+ char *inbuf = blr->inbuf;
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ files_struct *fsp = blr->fsp;
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ uint16 num_locks = SVAL(inbuf,smb_vwv7);
+ SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
+ uint16 lock_pid;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ NTSTATUS status = NT_STATUS_OK;
+
+ data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /*
+ * Data now points at the beginning of the list
+ * of smb_lkrng structs.
+ */
+
+ for(; blr->lock_num < num_locks; blr->lock_num++) {
+ BOOL err;
+
+ lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
+ count = get_lock_count( data, blr->lock_num, large_file_format);
+ offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+ errno = 0;
+ status = do_lock(fsp,conn,lock_pid,count,offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ if (NT_STATUS_IS_ERR(status)) break;
+ }
+
+ if(blr->lock_num == num_locks) {
+ /*
+ * Success - we got all the locks.
+ */
+
+ DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n",
+ fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) );
+
+ reply_lockingX_success(blr);
+ return True;
+ } else if ((errno != EACCES) && (errno != EAGAIN)) {
+ /*
+ * We have other than a "can't get lock" POSIX
+ * error. Free any locks we had and return an error.
+ * Return True so we get dequeued.
+ */
+
+ blocking_lock_reply_error(blr, status);
+ return True;
+ }
+
+ /*
+ * Still can't get all the locks - keep waiting.
+ */
+
+ DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
+Waiting....\n",
+ blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum));
+
+ return False;
+}
+
+/****************************************************************************
+ Process a blocking lock SMB.
+ Returns True if we want to be removed from the list.
+*****************************************************************************/
+
+static BOOL blocking_lock_record_process(blocking_lock_record *blr)
+{
+ switch(blr->com_type) {
+ case SMBlock:
+ return process_lock(blr);
+ case SMBlockread:
+ return process_lockread(blr);
+ case SMBlockingX:
+ return process_lockingX(blr);
+ default:
+ DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
+ exit_server("PANIC - unknown type on blocking lock queue");
+ }
+ return False; /* Keep compiler happy. */
+}
+
+/****************************************************************************
+ Delete entries by fnum from the blocking lock pending queue.
+*****************************************************************************/
+
+void remove_pending_lock_requests_by_fid(files_struct *fsp)
+{
+ blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue );
+ blocking_lock_record *prev = NULL;
+
+ while(blr != NULL) {
+ if(blr->fsp->fnum == fsp->fnum) {
+
+ DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
+file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
+
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ continue;
+ }
+
+ prev = blr;
+ blr = (blocking_lock_record *)ubi_slNext(blr);
+ }
+}
+
+/****************************************************************************
+ Delete entries by mid from the blocking lock pending queue. Always send reply.
+*****************************************************************************/
+
+void remove_pending_lock_requests_by_mid(int mid)
+{
+ blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue );
+ blocking_lock_record *prev = NULL;
+
+ while(blr != NULL) {
+ if(SVAL(blr->inbuf,smb_mid) == mid) {
+ files_struct *fsp = blr->fsp;
+
+ DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
+file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
+
+ blocking_lock_reply_error(blr,NT_STATUS_CANCELLED);
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ continue;
+ }
+
+ prev = blr;
+ blr = (blocking_lock_record *)ubi_slNext(blr);
+ }
+}
+
+/****************************************************************************
+ Return True if the blocking lock queue has entries.
+*****************************************************************************/
+
+BOOL blocking_locks_pending(void)
+{
+ blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue );
+ return (blr == NULL ? False : True);
+}
+
+/****************************************************************************
+ Process the blocking lock queue. Note that this is only called as root.
+*****************************************************************************/
+
+void process_blocking_lock_queue(time_t t)
+{
+ blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue );
+ blocking_lock_record *prev = NULL;
+
+ if(blr == NULL)
+ return;
+
+ /*
+ * Go through the queue and see if we can get any of the locks.
+ */
+
+ while(blr != NULL) {
+ connection_struct *conn = NULL;
+ uint16 vuid;
+ files_struct *fsp = NULL;
+
+ /*
+ * Ensure we don't have any old chain_fsp values
+ * sitting around....
+ */
+ chain_size = 0;
+ file_chain_reset();
+ fsp = blr->fsp;
+
+ conn = conn_find(SVAL(blr->inbuf,smb_tid));
+ vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
+ SVAL(blr->inbuf,smb_uid);
+
+ DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n",
+ fsp->fnum, fsp->fsp_name ));
+
+ if((blr->expire_time != -1) && (blr->expire_time > t)) {
+ /*
+ * Lock expired - throw away all previously
+ * obtained locks and return lock error.
+ */
+ DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
+ fsp->fnum, fsp->fsp_name ));
+
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ continue;
+ }
+
+ if(!change_to_user(conn,vuid)) {
+ DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
+ vuid ));
+ /*
+ * Remove the entry and return an error to the client.
+ */
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ continue;
+ }
+
+ if(!set_current_service(conn,True)) {
+ DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ /*
+ * Remove the entry and return an error to the client.
+ */
+ blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ change_to_root_user();
+ continue;
+ }
+
+ /*
+ * Go through the remaining locks and try and obtain them.
+ * The call returns True if all locks were obtained successfully
+ * and False if we still need to wait.
+ */
+
+ if(blocking_lock_record_process(blr)) {
+ free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
+ blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
+ change_to_root_user();
+ continue;
+ }
+
+ change_to_root_user();
+
+ /*
+ * Move to the next in the list.
+ */
+ prev = blr;
+ blr = (blocking_lock_record *)ubi_slNext(blr);
+ }
+}
diff --git a/source/smbd/build_options.c b/source/smbd/build_options.c
new file mode 100644
index 00000000000..9e55a297446
--- /dev/null
+++ b/source/smbd/build_options.c
@@ -0,0 +1,537 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ Build Options for Samba Suite
+ Copyright (C) Vance Lankhaar <vlankhaar@hotmail.com> 2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "build_env.h"
+#include "dynconfig.h"
+
+static void output(BOOL screen, char *format, ...) PRINTF_ATTRIBUTE(2,3);
+
+/*
+#define OUTPUT(x) snprintf(outstring,sizeof(outstring),x); output(screen,outstring);
+*/
+/****************************************************************************
+helper function for build_options
+****************************************************************************/
+static void output(BOOL screen, char *format, ...)
+{
+ char *ptr;
+ va_list ap;
+
+ va_start(ap, format);
+ vasprintf(&ptr,format,ap);
+ va_end(ap);
+
+ if (screen) {
+ d_printf("%s", ptr);
+ } else {
+ DEBUG(4,("%s", ptr));
+ }
+
+ SAFE_FREE(ptr);
+}
+
+/****************************************************************************
+options set at build time for the samba suite
+****************************************************************************/
+void build_options(BOOL screen)
+{
+ if ((DEBUGLEVEL < 4) && (!screen)) {
+ return;
+ }
+
+#ifdef _BUILD_ENV_H
+ /* Output information about the build environment */
+ output(screen,"Build environment:\n");
+ output(screen," Built by: %s@%s\n",BUILD_ENV_USER,BUILD_ENV_HOST);
+ output(screen," Built on: %s\n",BUILD_ENV_DATE);
+
+ output(screen," Built using: %s\n",BUILD_ENV_COMPILER);
+ output(screen," Build host: %s\n",BUILD_ENV_UNAME);
+ output(screen," SRCDIR: %s\n",BUILD_ENV_SRCDIR);
+ output(screen," BUILDDIR: %s\n",BUILD_ENV_BUILDDIR);
+
+
+#endif
+
+ /* Output various options (most correspond to --with options) */
+ output(screen,"\nBuild options:\n");
+#ifdef WITH_SMBWRAPPER
+ output(screen," WITH_SMBWRAPPER\n");
+#endif
+#ifdef WITH_AFS
+ output(screen," WITH_AFS\n");
+#endif
+#ifdef WITH_DFS
+ output(screen," WITH_DFS\n");
+#endif
+#ifdef KRB4_AUTH
+ output(screen," KRB4_AUTH");
+#endif
+#ifdef HAVE_KRB5
+ output(screen," HAVE_KRB5");
+#endif
+#ifdef WITH_AUTOMOUNT
+ output(screen," WITH_AUTOMOUNT\n");
+#endif
+#ifdef WITH_SMBMOUNT
+ output(screen," WITH_SMBMOUNT\n");
+#endif
+#ifdef WITH_PAM
+ output(screen," WITH_PAM\n");
+#endif
+#ifdef WITH_TDB_SAM
+ output(screen," WITH_TDB_SAM\n");
+#endif
+#ifdef WITH_LDAP_SAM
+ output(screen," WITH_LDAP_SAM\n");
+#endif
+#ifdef WITH_SMBPASSWD_SAM
+ output(screen," WITH_SMBPASSWD_SAM\n");
+#endif
+#ifdef WITH_NISPLUS_SAM
+ output(screen," WITH_NISPLUS_SAM\n");
+#endif
+#ifdef WITH_NISPLUS_HOME
+ output(screen," WITH_NISPLUS_HOME\n");
+#endif
+#ifdef WITH_SSL
+ output(screen," WITH_SSL\n");
+#endif
+#ifdef SSL_DIR
+ output(screen," SSL_DIR: %s\n",SSL_DIR);
+#endif
+#ifdef WITH_SYSLOG
+ output(screen," WITH_SYSLOG\n");
+#endif
+#ifdef WITH_PROFILE
+ output(screen," WITH_PROFILE\n");
+#endif
+#ifdef WITH_QUOTAS
+ output(screen," WITH_QUOTAS\n");
+#endif
+#ifdef WITH_VFS
+ output(screen," WITH_VFS\n");
+#endif
+#ifdef USE_SPINLOCKS
+ output(screen," USE_SPINLOCKS\n");
+#endif
+#ifdef SPARC_SPINLOCKS
+ output(screen," SPARC_SPINLOCKS\n");
+#endif
+#ifdef INTEL_SPINLOCKS
+ output(screen," INTEL_SPINLOCKS\n");
+#endif
+#ifdef MIPS_SPINLOCKS
+ output(screen," MIPS_SPINLOCKS\n");
+#endif
+#ifdef POWERPC_SPINLOCKS
+ output(screen," POWERPC_SPINLOCKS\n");
+#endif
+#ifdef HAVE_UNIXWARE_ACLS
+ output(screen," HAVE_UNIXWARE_ACLS\n");
+#endif
+#ifdef HAVE_SOLARIS_ACLS
+ output(screen," HAVE_SOLARIS_ACLS\n");
+#endif
+#ifdef HAVE_IRIX_ACLS
+ output(screen," HAVE_IRIX_ACLS\n");
+#endif
+#ifdef HAVE_AIX_ACLS
+ output(screen," HAVE_AIX_ACLS\n");
+#endif
+#ifdef HAVE_POSIX_ACLS
+ output(screen," HAVE_POSIX_ACLS\n");
+#endif
+#ifdef HAVE_TRU64_ACLS
+ output(screen," HAVE_TRU64_ACLS\n");
+#endif
+
+#ifdef HAVE_ACL_GET_PERM_NP
+ output(screen," HAVE_ACL_GET_PERM_NP\n");
+#endif
+#ifdef HAVE_NO_ACLS
+ output(screen," HAVE_NO_ACLS\n");
+#endif
+#ifdef HAVE_LIBREADLINE
+ output(screen," HAVE_LIBREADLINE\n");
+#endif
+#ifdef WITH_LIBICONV
+ output(screen," WITH_LIBICONV: %s\n",WITH_LIBICONV);
+#endif
+
+
+ /* Output various paths to files and directories */
+ output(screen,"\nPaths:\n");
+ output(screen," CONFIGFILE: %s\n", dyn_CONFIGFILE);
+#ifdef PRIVATE_DIR
+ output(screen," PRIVATE_DIR: %s\n",PRIVATE_DIR);
+#endif
+#ifdef LMHOSTSFILE
+ output(screen," LMHOSTSFILE: %s\n",LMHOSTSFILE);
+#endif
+ output(screen," SBINDIR: %s\n", dyn_SBINDIR);
+ output(screen," BINDIR: %s\n", dyn_BINDIR);
+ output(screen," LOCKDIR: %s\n",dyn_LOCKDIR);
+ output(screen," DRIVERFILE: %s\n", dyn_DRIVERFILE);
+ output(screen," LOGFILEBASE: %s\n", dyn_LOGFILEBASE);
+
+ /*Output various other options (most map to defines in the configure script*/
+ output(screen,"\nOther Build Options:\n");
+#ifdef HAVE_VOLATILE
+ output(screen," HAVE_VOLATILE\n");
+#endif
+#ifdef HAVE_SHADOW_H
+ output(screen," HAVE_SHADOW_H\n");
+#endif
+#ifdef HAVE_CRYPT
+ output(screen," HAVE_CRYPT\n");
+#endif
+#ifdef USE_BOTH_CRYPT_CALLS
+ output(screen," USE_BOTH_CRYPT_CALLS\n");
+#endif
+#ifdef HAVE_TRUNCATED_SALT
+ output(screen," HAVE_TRUNCATED_SALT\n");
+#endif
+#ifdef HAVE_CUPS
+ output(screen," HAVE_CUPS\n");
+#endif
+#ifdef HAVE_CUPS_CUPS_H
+ output(screen," HAVE_CUPS_CUPS_H\n");
+#endif
+#ifdef HAVE_CUPS_LANGUAGE_H
+ output(screen," HAVE_CUPS_LANGUAGE_H\n");
+#endif
+#ifdef HAVE_LIBDL
+ output(screen," HAVE_LIBDL\n");
+#endif
+#ifdef HAVE_UNIXSOCKET
+ output(screen," HAVE_UNIXSOCKET\n");
+#endif
+#ifdef HAVE_SOCKLEN_T_TYPE
+ output(screen," HAVE_SOCKLEN_T_TYPE\n");
+#endif
+#ifdef HAVE_SIG_ATOMIC_T_TYPE
+ output(screen," HAVE_SIG_ATOMIC_T_TYPE\n");
+#endif
+#ifdef HAVE_SETRESUID
+ output(screen," HAVE_SETRESUID\n");
+#endif
+#ifdef HAVE_SETRESGID
+ output(screen," HAVE_SETRESGID\n");
+#endif
+#ifdef HAVE_CONNECT
+ output(screen," HAVE_CONNECT\n");
+#endif
+#ifdef HAVE_YP_GET_DEFAULT_DOMAIN
+ output(screen," HAVE_YP_GET_DEFAULT_DOMAIN\n");
+#endif
+#ifdef HAVE_STAT64
+ output(screen," HAVE_STAT64\n");
+#endif
+#ifdef HAVE_LSTAT64
+ output(screen," HAVE_LSTAT64\n");
+#endif
+#ifdef HAVE_FSTAT64
+ output(screen," HAVE_FSTAT64\n");
+#endif
+#ifdef HAVE_STRCASECMP
+ output(screen," HAVE_STRCASECMP\n");
+#endif
+#ifdef HAVE_MEMSET
+ output(screen," HAVE_MEMSET\n");
+#endif
+#ifdef HAVE_LONGLONG
+ output(screen," HAVE_LONGLONG\n");
+#endif
+#ifdef COMPILER_SUPPORTS_LL
+ output(screen," COMPILER_SUPPORTS_LL\n");
+#endif
+#ifdef SIZEOF_OFF_T
+ output(screen," SIZEOF_OFF_T: %d\n",SIZEOF_OFF_T);
+#endif
+#ifdef HAVE_OFF64_T
+ output(screen," HAVE_OFF64_T\n");
+#endif
+#ifdef SIZEOF_INO_T
+ output(screen," SIZEOF_INO_T: %d\n",SIZEOF_INO_T);
+#endif
+#ifdef HAVE_INO64_T
+ output(screen," HAVE_INO64_T\n");
+#endif
+#ifdef HAVE_STRUCT_DIRENT64
+ output(screen," HAVE_STRUCT_DIRENT64\n");
+#endif
+#ifdef HAVE_UNSIGNED_CHAR
+ output(screen," HAVE_UNSIGNED_CHAR\n");
+#endif
+#ifdef HAVE_SOCK_SIN_LEN
+ output(screen," HAVE_SOCK_SIN_LEN\n");
+#endif
+#ifdef SEEKDIR_RETURNS_VOID
+ output(screen," SEEKDIR_RETURNS_VOID\n");
+#endif
+#ifdef HAVE_FILE_MACRO
+ output(screen," HAVE_FILE_MACRO\n");
+#endif
+#ifdef HAVE_FUNCTION_MACRO
+ output(screen," HAVE_FUNCTION_MACRO\n");
+#endif
+#ifdef HAVE_GETTIMEOFDAY
+ output(screen," HAVE_GETTIMEOFDAY\n");
+#endif
+#ifdef HAVE_C99_VSNPRINTF
+ output(screen," HAVE_C99_VSNPRINTF\n");
+#endif
+#ifdef HAVE_BROKEN_READDIR
+ output(screen," HAVE_BROKEN_READDIR\n");
+#endif
+#ifdef HAVE_NATIVE_ICONV
+ output(screen," HAVE_NATIVE_ICONV\n");
+#endif
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
+ output(screen," HAVE_KERNEL_OPLOCKS_LINUX\n");
+#endif
+#ifdef HAVE_KERNEL_CHANGE_NOTIFY
+ output(screen," HAVE_KERNEL_CHANGE_NOTIFY\n");
+#endif
+#ifdef HAVE_KERNEL_SHARE_MODES
+ output(screen," HAVE_KERNEL_SHARE_MODES\n");
+#endif
+#ifdef HAVE_KERNEL_OPLOCKS_IRIX
+ output(screen," HAVE_KERNEL_OPLOCKS_IRIX\n");
+#endif
+#ifdef HAVE_IRIX_SPECIFIC_CAPABILITIES
+ output(screen," HAVE_IRIX_SPECIFIC_CAPABILITIES\n");
+#endif
+#ifdef HAVE_INT16_FROM_RPC_RPC_H
+ output(screen," HAVE_INT16_FROM_RPC_RPC_H\n");
+#endif
+#ifdef HAVE_UINT16_FROM_RPC_RPC_H
+ output(screen," HAVE_UINT16_FROM_RPC_RPC_H\n");
+#endif
+#ifdef HAVE_INT32_FROM_RPC_RPC_H
+ output(screen," HAVE_INT16_FROM_RPC_RPC_H\n");
+#endif
+#ifdef HAVE_UINT32_FROM_RPC_RPC_H
+ output(screen," HAVE_UINT32_FROM_RPC_RPC_H\n");
+#endif
+#ifdef HAVE_RPC_AUTH_ERROR_CONFLICT
+ output(screen," HAVE_RPC_AUTH_ERROR_CONFLICT\n");
+#endif
+#ifdef HAVE_FTRUNCATE_EXTEND
+ output(screen," HAVE_FTRUNCATE_EXTEND\n");
+#endif
+#ifdef HAVE_WORKING_AF_LOCAL
+ output(screen," HAVE_WORKING_AF_LOCAL\n");
+#endif
+#ifdef HAVE_BROKEN_GETGROUPS
+ output(screen," HAVE_BROKEN_GETGROUPS\n");
+#endif
+#ifdef REPLACE_GETPASS
+ output(screen," REPLACE_GETPASS\n");
+#endif
+#ifdef REPLACE_INET_NTOA
+ output(screen," REPLACE_INET_NTOA\n");
+#endif
+#ifdef HAVE_SECURE_MKSTEMP
+ output(screen," HAVE_SECURE_MKSTEMP\n");
+#endif
+#ifdef SYSCONF_SC_NGROUPS_MAX
+ output(screen," SYSCONF_SC_NGROUPS_MAX\n");
+#endif
+#ifdef HAVE_IFACE_AIX
+ output(screen," HAVE_IFACE_AIX\n");
+#endif
+#ifdef HAVE_IFACE_IFCONF
+ output(screen," HAVE_IFACE_IFCONF\n");
+#endif
+#ifdef HAVE_IFACE_IFREQ
+ output(screen," HAVE_IFACE_IFREQ\n");
+#endif
+#ifdef USE_SETRESUID
+ output(screen," USE_SETRESUID\n");
+#endif
+#ifdef USE_SETRESGID
+ output(screen," USE_SETREUID\n");
+#endif
+#ifdef USE_SETEUID
+ output(screen," USE_SETEUID\n");
+#endif
+#ifdef USE_SETUIDX
+ output(screen," USE_SETUIDX\n");
+#endif
+#ifdef HAVE_MMAP
+ output(screen," HAVE_MMAP\n");
+#endif
+#ifdef MMAP_BLACKLIST
+ output(screen," MMAP_BLACKLIST\n");
+#endif
+#ifdef FTRUNCATE_NEEDS_ROOT
+ output(screen," FTRUNCATE_NEEDS_ROOT\n");
+#endif
+#ifdef HAVE_FCNTL_LOCK
+ output(screen," HAVE_FCNTL_LOCK\n");
+#endif
+#ifdef HAVE_BROKEN_FCNTL64_LOCKS
+ output(screen," HAVE_BROKEN_FCNTL64_LOCKS\n");
+#endif
+#ifdef HAVE_STRUCT_FLOCK64
+ output(screen," HAVE_STRUCT_FLOCK64\n");
+#endif
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+ output(screen," BROKEN_NISPLUS_INCLUDE_FILES\n");
+#endif
+#ifdef HAVE_LIBPAM
+ output(screen," HAVE_LIBPAM\n");
+#endif
+#ifdef STAT_STATVFS64
+ output(screen," STAT_STATVFS64\n");
+#endif
+#ifdef STAT_STATVFS
+ output(screen," STAT_STATVFS\n");
+#endif
+#ifdef STAT_STATFS3_OSF1
+ output(screen," STAT_STATFS3_OSF1\n");
+#endif
+#ifdef STAT_STATFS2_BSIZE
+ output(screen," STAT_STATFS2_BSIZE\n");
+#endif
+#ifdef STAT_STATFS4
+ output(screen," STAT_STATFS4\n");
+#endif
+#ifdef STAT_STATFS2_FSIZE
+ output(screen," STAT_STATFS2_FSIZE\n");
+#endif
+#ifdef STAT_STATFS2_FS_DATA
+ output(screen," STAT_STATFS2_FS_DATA\n");
+#endif
+#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
+ output(screen," HAVE_EXPLICIT_LARGEFILE_SUPPORT\n");
+#endif
+
+#ifdef WITH_UTMP
+ /* Output UTMP Stuff */
+ output(screen,"\nUTMP Related:\n");
+ output(screen," WITH_UTMP\n");
+
+#ifdef HAVE_UTIMBUF
+ output(screen," HAVE_UTIMBUF\n");
+#endif
+#ifdef HAVE_UT_UT_NAME
+ output(screen," HAVE_UT_UT_NAME\n");
+#endif
+#ifdef HAVE_UT_UT_USER
+ output(screen," HAVE_UT_UT_USER\n");
+#endif
+#ifdef HAVE_UT_UT_ID
+ output(screen," HAVE_UT_UT_ID\n");
+#endif
+#ifdef HAVE_UT_UT_HOST
+ output(screen," HAVE_UT_UT_HOST\n");
+#endif
+#ifdef HAVE_UT_UT_TIME
+ output(screen," HAVE_UT_UT_TIME\n");
+#endif
+#ifdef HAVE_UT_UT_TV
+ output(screen," HAVE_UT_UT_TV\n");
+#endif
+#ifdef HAVE_UT_UT_TYPE
+ output(screen," HAVE_UT_UT_TYPE\n");
+#endif
+#ifdef HAVE_UT_UT_PID
+ output(screen," HAVE_UT_UT_PID\n");
+#endif
+#ifdef HAVE_UT_UT_EXIT
+ output(screen," HAVE_UT_UT_EXIT\n");
+#endif
+#ifdef HAVE_UT_UT_ADDR
+ output(screen," HAVE_UT_UT_ADDR\n");
+#endif
+#ifdef PUTUTLINE_RETURNS_UTMP
+ output(screen," PUTUTLINE_RETURNS_UTMP\n");
+#endif
+#ifdef HAVE_UX_UT_SYSLEN
+ output(screen," HAVE_UX_UT_SYSLEN\n");
+#endif
+#endif /* WITH_UTMP */
+
+ /* Output Build OS */
+ output(screen,"\nBuilt for host os:\n");
+#ifdef LINUX
+ output(screen," LINUX\n");
+#endif
+#ifdef SUNOS5
+ output(screen," SUNOS5\n");
+#endif
+#ifdef SUNOS4
+ output(screen," SUNOS4\n");
+#endif
+ /* BSD Isn't Defined in the configure script, but there is something about it in include/config.h.in (and I guess acconfig.h) */
+#ifdef BSD
+ output(screen," BSD\n");
+#endif
+#ifdef IRIX
+ output(screen," IRIX\n");
+#endif
+#ifdef IRIX6
+ output(screen," IRIX6\n");
+#endif
+#ifdef AIX
+ output(screen," AIX\n");
+#endif
+#ifdef HPUX
+ output(screen," HPUX\n");
+#endif
+#ifdef QNX
+ output(screen," QNX\n");
+#endif
+#ifdef OSF1
+ output(screen," OSF1\n");
+#endif
+#ifdef SCO
+ output(screen," SCO\n");
+#endif
+#ifdef UNIXWARE
+ output(screen," UNIXWARE\n");
+#endif
+#ifdef NEXT2
+ output(screen," NEXT2\n");
+#endif
+#ifdef RELIANTUNIX
+ output(screen," RELIANTUNIX\n");
+#endif
+
+ /* Output the sizes of the various types */
+ output(screen,"\nType sizes:\n");
+ output(screen," sizeof(char): %d\n",sizeof(char));
+ output(screen," sizeof(int): %d\n",sizeof(int));
+ output(screen," sizeof(long): %d\n",sizeof(long));
+ output(screen," sizeof(uint8): %d\n",sizeof(uint8));
+ output(screen," sizeof(uint16): %d\n",sizeof(uint16));
+ output(screen," sizeof(uint32): %d\n",sizeof(uint32));
+ output(screen," sizeof(short): %d\n",sizeof(short));
+ output(screen," sizeof(void*): %d\n",sizeof(void*));
+}
+
+
+
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index dc0514c1ed7..741f5ef0aa1 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -1,8 +1,29 @@
-/* fork a child process to exec passwd and write to its
-* tty to change a users password. This is running as the
-* user who is attempting to change the password.
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* fork a child process to exec passwd and write to its
+ * tty to change a users password. This is running as the
+ * user who is attempting to change the password.
+ */
+
/*
* This code was copied/borrowed and stolen from various sources.
* The primary source was the poppasswd.c from the authors of POPMail. This software
@@ -27,350 +48,936 @@
*/
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
+extern struct passdb_ops pdb_ops;
-#ifdef ALLOW_CHANGE_PASSWORD
+static BOOL check_oem_password(const char *user,
+ uchar * lmdata, const uchar * lmhash,
+ const uchar * ntdata, const uchar * nthash,
+ SAM_ACCOUNT **hnd, char *new_passwd,
+ int new_passwd_size);
-#define MINPASSWDLENGTH 5
-#define BUFSIZE 512
+#if ALLOW_CHANGE_PASSWORD
static int findpty(char **slave)
{
- int master;
-#ifdef SVR4
- extern char *ptsname();
-#else
- static char line[12] = "/dev/ptyXX";
- void *dirp;
- char *dpname;
-#endif
-
-#ifdef SVR4
- if ((master = open("/dev/ptmx", O_RDWR)) >= 1) {
- grantpt(master);
- unlockpt(master);
- *slave = ptsname(master);
- return (master);
- }
-#else
- dirp = OpenDir("/dev");
- if (!dirp) return(-1);
- while ((dpname = ReadDirName(dirp)) != NULL) {
- if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
- line[8] = dpname[3];
- line[9] = dpname[4];
- if ((master = open(line, O_RDWR)) >= 0) {
- line[5] = 't';
- *slave = line;
- CloseDir(dirp);
- return (master);
- }
- }
- }
- CloseDir(dirp);
-#endif
- return (-1);
+ int master;
+ static fstring line;
+ DIR *dirp;
+ char *dpname;
+
+#if defined(HAVE_GRANTPT)
+ /* Try to open /dev/ptmx. If that fails, fall through to old method. */
+ if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
+ {
+ grantpt(master);
+ unlockpt(master);
+ *slave = (char *)ptsname(master);
+ if (*slave == NULL)
+ {
+ DEBUG(0,
+ ("findpty: Unable to create master/slave pty pair.\n"));
+ /* Stop fd leak on error. */
+ close(master);
+ return -1;
+ }
+ else
+ {
+ DEBUG(10,
+ ("findpty: Allocated slave pty %s\n", *slave));
+ return (master);
+ }
+ }
+#endif /* HAVE_GRANTPT */
+
+ fstrcpy(line, "/dev/ptyXX");
+
+ dirp = opendir("/dev");
+ if (!dirp)
+ return (-1);
+ while ((dpname = readdirname(dirp)) != NULL)
+ {
+ if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
+ {
+ DEBUG(3,
+ ("pty: try to open %s, line was %s\n", dpname,
+ line));
+ line[8] = dpname[3];
+ line[9] = dpname[4];
+ if ((master = sys_open(line, O_RDWR, 0)) >= 0)
+ {
+ DEBUG(3, ("pty: opened %s\n", line));
+ line[5] = 't';
+ *slave = line;
+ closedir(dirp);
+ return (master);
+ }
+ }
+ }
+ closedir(dirp);
+ return (-1);
}
-static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
+static int dochild(int master, const char *slavedev, const struct passwd *pass,
+ const char *passwordprogram, BOOL as_root)
{
- int slave;
- struct termios stermios;
- struct passwd *pass = Get_Pwnam(name,True);
- int gid = pass->pw_gid;
- int uid = pass->pw_uid;
-
-#ifdef USE_SETRES
- setresuid(0,0,0);
-#else
- setuid(0);
-#endif
-
- /* Start new session - gets rid of controlling terminal. */
- if (setsid() < 0) {
- DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
- return(False);
- }
-
- /* Open slave pty and acquire as new controlling terminal. */
- if ((slave = open(slavedev, O_RDWR)) < 0) {
- DEBUG(3,("More weirdness, could not open %s\n",
- slavedev));
- return(False);
- }
-#ifdef SVR4
- ioctl(slave, I_PUSH, "ptem");
- ioctl(slave, I_PUSH, "ldterm");
-#else
- if (ioctl(slave,TIOCSCTTY,0) <0) {
- DEBUG(3,("Error in ioctl call for slave pty\n"));
- /* return(False); */
- }
-#endif
-
- /* Close master. */
- close(master);
-
- /* Make slave stdin/out/err of child. */
-
- if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
- DEBUG(3,("Could not re-direct stdin\n"));
- return(False);
- }
- if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
- DEBUG(3,("Could not re-direct stdout\n"));
- return(False);
- }
- if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
- DEBUG(3,("Could not re-direct stderr\n"));
- return(False);
- }
- if (slave > 2) close(slave);
-
- /* Set proper terminal attributes - no echo, canonical input processing,
- no map NL to CR/NL on output. */
-
- if (tcgetattr(0, &stermios) < 0) {
- DEBUG(3,("could not read default terminal attributes on pty\n"));
- return(False);
- }
- stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
- stermios.c_lflag |= ICANON;
- stermios.c_oflag &= ~(ONLCR);
- if (tcsetattr(0, TCSANOW, &stermios) < 0) {
- DEBUG(3,("could not set attributes of pty\n"));
- return(False);
- }
-
- /* make us completely into the right uid */
-#ifdef USE_SETRES
- setresgid(0,0,0);
- setresuid(0,0,0);
- setresgid(gid,gid,gid);
- setresuid(uid,uid,uid);
-#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
+ int slave;
+ struct termios stermios;
+ gid_t gid;
+ uid_t uid;
+
+ if (pass == NULL)
+ {
+ DEBUG(0,
+ ("dochild: user doesn't exist in the UNIX password database.\n"));
+ return False;
+ }
+
+ gid = pass->pw_gid;
+ uid = pass->pw_uid;
+
+ gain_root_privilege();
+
+ /* Start new session - gets rid of controlling terminal. */
+ if (setsid() < 0)
+ {
+ DEBUG(3,
+ ("Weirdness, couldn't let go of controlling terminal\n"));
+ return (False);
+ }
+
+ /* Open slave pty and acquire as new controlling terminal. */
+ if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
+ {
+ DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
+ return (False);
+ }
+#ifdef I_PUSH
+ ioctl(slave, I_PUSH, "ptem");
+ ioctl(slave, I_PUSH, "ldterm");
+#elif defined(TIOCSCTTY)
+ if (ioctl(slave, TIOCSCTTY, 0) < 0)
+ {
+ DEBUG(3, ("Error in ioctl call for slave pty\n"));
+ /* return(False); */
+ }
#endif
- /* execl() password-change application */
- if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) {
- DEBUG(3,("Bad status returned from %s\n",passwordprogram));
- return(False);
- }
- return(True);
+ /* Close master. */
+ close(master);
+
+ /* Make slave stdin/out/err of child. */
+
+ if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stdin\n"));
+ return (False);
+ }
+ if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stdout\n"));
+ return (False);
+ }
+ if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
+ {
+ DEBUG(3, ("Could not re-direct stderr\n"));
+ return (False);
+ }
+ if (slave > 2)
+ close(slave);
+
+ /* Set proper terminal attributes - no echo, canonical input processing,
+ no map NL to CR/NL on output. */
+
+ if (tcgetattr(0, &stermios) < 0)
+ {
+ DEBUG(3,
+ ("could not read default terminal attributes on pty\n"));
+ return (False);
+ }
+ stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ stermios.c_lflag |= ICANON;
+ stermios.c_oflag &= ~(ONLCR);
+ if (tcsetattr(0, TCSANOW, &stermios) < 0)
+ {
+ DEBUG(3, ("could not set attributes of pty\n"));
+ return (False);
+ }
+
+ /* make us completely into the right uid */
+ if (!as_root)
+ {
+ become_user_permanently(uid, gid);
+ }
+
+ DEBUG(10,
+ ("Invoking '%s' as password change program.\n",
+ passwordprogram));
+
+ /* execl() password-change application */
+ if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
+ {
+ DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
+ return (False);
+ }
+ return (True);
}
-static int expect(int master,char *expected,char *buf)
+static int expect(int master, char *issue, char *expected)
{
- int n, m;
-
- n = 0;
- buf[0] = 0;
- while (1) {
- if (n >= BUFSIZE-1) {
- return False;
- }
-
- /* allow 4 seconds for some output to appear */
- m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000, True);
- if (m < 0)
- return False;
-
- n += m;
- buf[n] = 0;
-
- {
- pstring s1,s2;
- strcpy(s1,buf);
- strcpy(s2,expected);
- if (do_match(s1, s2, False))
- return(True);
- }
- }
+ pstring buffer;
+ int attempts, timeout, nread, len;
+ BOOL match = False;
+
+ for (attempts = 0; attempts < 2; attempts++) {
+ if (!strequal(issue, ".")) {
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: sending [%s]\n", issue));
+
+ if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
+ DEBUG(2,("expect: (short) write returned %d\n", len ));
+ return False;
+ }
+ }
+
+ if (strequal(expected, "."))
+ return True;
+
+ timeout = 2000;
+ nread = 0;
+ buffer[nread] = 0;
+
+ while ((len = read_with_timeout(master, buffer + nread, 1,
+ sizeof(buffer) - nread - 1,
+ timeout)) > 0) {
+ nread += len;
+ buffer[nread] = 0;
+
+ {
+ /* Eat leading/trailing whitespace before match. */
+ pstring str;
+ pstrcpy( str, buffer);
+ trim_string( str, " ", " ");
+
+ if ((match = (unix_wild_match(expected, str) == 0)))
+ timeout = 200;
+ }
+ }
+
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
+ expected, buffer, match ? "yes" : "no" ));
+
+ if (match)
+ break;
+
+ if (len < 0) {
+ DEBUG(2, ("expect: %s\n", strerror(errno)));
+ return False;
+ }
+ }
+
+ DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
+ return match;
}
static void pwd_sub(char *buf)
{
- string_sub(buf,"\\n","\n");
- string_sub(buf,"\\r","\r");
- string_sub(buf,"\\s"," ");
- string_sub(buf,"\\t","\t");
+ all_string_sub(buf, "\\n", "\n", 0);
+ all_string_sub(buf, "\\r", "\r", 0);
+ all_string_sub(buf, "\\s", " ", 0);
+ all_string_sub(buf, "\\t", "\t", 0);
+}
+
+static int talktochild(int master, char *seq)
+{
+ int count = 0;
+ fstring issue, expected;
+
+ fstrcpy(issue, ".");
+
+ while (next_token(&seq, expected, NULL, sizeof(expected)))
+ {
+ pwd_sub(expected);
+ count++;
+
+ if (!expect(master, issue, expected))
+ {
+ DEBUG(3, ("Response %d incorrect\n", count));
+ return False;
+ }
+
+ if (!next_token(&seq, issue, NULL, sizeof(issue)))
+ fstrcpy(issue, ".");
+
+ pwd_sub(issue);
+ }
+ if (!strequal(issue, ".")) {
+ /* we have one final issue to send */
+ fstrcpy(expected, ".");
+ if (!expect(master, issue, expected))
+ return False;
+ }
+
+ return (count > 0);
}
-static void writestring(int fd,char *s)
+static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
+ char *chatsequence, BOOL as_root)
{
- int l;
-
- l = strlen (s);
- write (fd, s, l);
+ char *slavedev;
+ int master;
+ pid_t pid, wpid;
+ int wstat;
+ BOOL chstat = False;
+
+ if (pass == NULL)
+ {
+ DEBUG(0,
+ ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
+ return False;
+ }
+
+ /* allocate a pseudo-terminal device */
+ if ((master = findpty(&slavedev)) < 0)
+ {
+ DEBUG(3,
+ ("Cannot Allocate pty for password change: %s\n",
+ pass->pw_name));
+ return (False);
+ }
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid = sys_fork()) < 0)
+ {
+ DEBUG(3,
+ ("Cannot fork() child for password change: %s\n",
+ pass->pw_name));
+ close(master);
+ CatchChild();
+ return (False);
+ }
+
+ /* we now have a pty */
+ if (pid > 0)
+ { /* This is the parent process */
+ if ((chstat = talktochild(master, chatsequence)) == False)
+ {
+ DEBUG(3,
+ ("Child failed to change password: %s\n",
+ pass->pw_name));
+ kill(pid, SIGKILL); /* be sure to end this process */
+ }
+
+ while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
+ {
+ if (errno == EINTR)
+ {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ if (wpid < 0)
+ {
+ DEBUG(3, ("The process is no longer waiting!\n\n"));
+ close(master);
+ CatchChild();
+ return (False);
+ }
+
+ /*
+ * Go back to ignoring children.
+ */
+ CatchChild();
+
+ close(master);
+
+ if (pid != wpid)
+ {
+ DEBUG(3,
+ ("We were waiting for the wrong process ID\n"));
+ return (False);
+ }
+ if (WIFEXITED(wstat) == 0)
+ {
+ DEBUG(3,
+ ("The process exited while we were waiting\n"));
+ return (False);
+ }
+ if (WEXITSTATUS(wstat) != 0)
+ {
+ DEBUG(3,
+ ("The status of the process exiting was %d\n",
+ wstat));
+ return (False);
+ }
+
+ }
+ else
+ {
+ /* CHILD */
+
+ /*
+ * Lose any oplock capabilities.
+ */
+ oplock_set_capability(False, False);
+
+ /* make sure it doesn't freeze */
+ alarm(20);
+
+ if (as_root)
+ become_root();
+
+ DEBUG(3,
+ ("Dochild for user %s (uid=%d,gid=%d)\n", pass->pw_name,
+ (int)getuid(), (int)getgid()));
+ chstat =
+ dochild(master, slavedev, pass, passwordprogram,
+ as_root);
+
+ if (as_root)
+ unbecome_root();
+
+ /*
+ * The child should never return from dochild() ....
+ */
+
+ DEBUG(0,
+ ("chat_with_program: Error: dochild() returned %d\n",
+ chstat));
+ exit(1);
+ }
+
+ if (chstat)
+ DEBUG(3,
+ ("Password change %ssuccessful for user %s\n",
+ (chstat ? "" : "un"), pass->pw_name));
+ return (chstat);
}
-static int talktochild(int master, char *chatsequence)
+BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
{
- char buf[BUFSIZE];
- int count=0;
- char *ptr=chatsequence;
- fstring chatbuf;
+ pstring passwordprogram;
+ pstring chatsequence;
+ size_t i;
+ size_t len;
- *buf = 0;
- sleep(1);
+ struct passwd *pass;
- while (next_token(&ptr,chatbuf,NULL)) {
- BOOL ok=True;
- count++;
- pwd_sub(chatbuf);
- if (!strequal(chatbuf,"."))
- ok = expect(master,chatbuf,buf);
+ DEBUG(3, ("Password change for user: %s\n", name));
#if DEBUG_PASSWORD
- DEBUG(100,("chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
-#endif
-
- if (!ok) {
- DEBUG(3,("response %d incorrect\n",count));
- return(False);
- }
+ DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
+#endif
- if (!next_token(&ptr,chatbuf,NULL)) break;
- pwd_sub(chatbuf);
- if (!strequal(chatbuf,"."))
- writestring(master,chatbuf);
+ /* Take the passed information and test it for minimum criteria */
+ /* Minimum password length */
+ if (strlen(newpass) < lp_min_passwd_length()) {
+ /* too short, must be at least MINPASSWDLENGTH */
+ DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
+ name, lp_min_passwd_length()));
+ return (False); /* inform the user */
+ }
+
+ /* Password is same as old password */
+ if (strcmp(oldpass, newpass) == 0) {
+ /* don't allow same password */
+ DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
+ return (False); /* inform the user */
+ }
+
+ /*
+ * Check the old and new passwords don't contain any control
+ * characters.
+ */
+
+ len = strlen(oldpass);
+ for (i = 0; i < len; i++) {
+ if (iscntrl((int)oldpass[i])) {
+ DEBUG(0,
+ ("chat_with_program: oldpass contains control characters (disallowed).\n"));
+ return False;
+ }
+ }
+
+ len = strlen(newpass);
+ for (i = 0; i < len; i++) {
+ if (iscntrl((int)newpass[i])) {
+ DEBUG(0,
+ ("chat_with_program: newpass contains control characters (disallowed).\n"));
+ return False;
+ }
+ }
+
+ pass = Get_Pwnam(name);
+
+#ifdef WITH_PAM
+ if (lp_pam_password_change()) {
+ BOOL ret;
+
+ if (as_root)
+ become_root();
+
+ if (pass) {
+ ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
+ } else {
+ ret = smb_pam_passchange(name, oldpass, newpass);
+ }
+
+ if (as_root)
+ unbecome_root();
+
+ return ret;
+ }
+#endif
-#if DEBUG_PASSWORD
- DEBUG(100,("sendbuf=[%s]\n",chatbuf));
-#endif
- }
+ /* A non-PAM password change just doen't make sense without a valid local user */
+
+ if (pass == NULL)
+ {
+ DEBUG(0,
+ ("chgpasswd: user %s doesn't exist in the UNIX password database.\n",
+ name));
+ return False;
+ }
+
+ pstrcpy(passwordprogram, lp_passwd_program());
+ pstrcpy(chatsequence, lp_passwd_chat());
+
+ if (!*chatsequence) {
+ DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
+ return (False);
+ }
+
+ if (!*passwordprogram) {
+ DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
+ return (False);
+ }
+
+ if (as_root) {
+ /* The password program *must* contain the user name to work. Fail if not. */
+ if (strstr(passwordprogram, "%u") == NULL) {
+ DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
+the string %%u, and the given string %s does not.\n", passwordprogram ));
+ return False;
+ }
+ }
+
+ pstring_sub(passwordprogram, "%u", name);
+ /* note that we do NOT substitute the %o and %n in the password program
+ as this would open up a security hole where the user could use
+ a new password containing shell escape characters */
+
+ pstring_sub(chatsequence, "%u", name);
+ all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
+ all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
+ return (chat_with_program
+ (passwordprogram, pass, chatsequence, as_root));
+}
- if (count<1) return(False);
+#else /* ALLOW_CHANGE_PASSWORD */
- return (True);
+BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
+{
+ DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
+ return (False);
}
+#endif /* ALLOW_CHANGE_PASSWORD */
+/***********************************************************
+ Code to check the lanman hashed password.
+************************************************************/
-BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence)
+BOOL check_lanman_password(char *user, uchar * pass1,
+ uchar * pass2, SAM_ACCOUNT **hnd)
{
- char *slavedev;
- int master;
- pid_t pid, wpid;
- int wstat;
- BOOL chstat;
-
- /* allocate a pseudo-terminal device */
- if ((master = findpty (&slavedev)) < 0) {
- DEBUG(3,("Cannot Allocate pty for password change: %s",name));
- return(False);
- }
-
- if ((pid = fork()) < 0) {
- DEBUG(3,("Cannot fork() child for password change: %s",name));
- return(False);
- }
-
- /* we now have a pty */
- if (pid > 0){ /* This is the parent process */
- if ((chstat = talktochild(master, chatsequence)) == False) {
- DEBUG(3,("Child failed to change password: %s\n",name));
- kill(pid, SIGKILL); /* be sure to end this process */
- return(False);
- }
- if ((wpid = waitpid(pid, &wstat, 0)) < 0) {
- DEBUG(3,("The process is no longer waiting!\n\n"));
- return(False);
- }
- if (pid != wpid) {
- DEBUG(3,("We were waiting for the wrong process ID\n"));
- return(False);
- }
- if (WIFEXITED(wstat) == 0) {
- DEBUG(3,("The process exited while we were waiting\n"));
- return(False);
- }
- if (WEXITSTATUS(wstat) != 0) {
- DEBUG(3,("The status of the process exiting was %d\n", wstat));
- return(False);
- }
-
- } else {
- /* CHILD */
-
- /* make sure it doesn't freeze */
- alarm(20);
-
- DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,getuid(),getgid()));
- chstat = dochild(master, slavedev, name, passwordprogram);
- }
- DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name));
- return (chstat);
+ uchar unenc_new_pw[16];
+ uchar unenc_old_pw[16];
+ SAM_ACCOUNT *sampass = NULL;
+ uint16 acct_ctrl;
+ const uint8 *lanman_pw;
+ BOOL ret;
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl (sampass);
+ lanman_pw = pdb_get_lanman_passwd (sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ if (lanman_pw == NULL) {
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ /* this saves the pointer for the caller */
+ *hnd = sampass;
+ return True;
+ } else {
+ DEBUG(0, ("check_lanman_password: no lanman password !\n"));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+ }
+
+ /* Get the new lanman hash. */
+ D_P16(lanman_pw, pass2, unenc_new_pw);
+
+ /* Use this to get the old lanman hash. */
+ D_P16(unenc_new_pw, pass1, unenc_old_pw);
+
+ /* Check that the two old passwords match. */
+ if (memcmp(lanman_pw, unenc_old_pw, 16)) {
+ DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
+ pdb_free_sam(&sampass);
+ return False;
+ }
+
+ /* this saves the pointer for the caller */
+ *hnd = sampass;
+ return True;
}
+/***********************************************************
+ Code to change the lanman hashed password.
+ It nulls out the NT hashed password as it will
+ no longer be valid.
+************************************************************/
+
+BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
+ uchar * pass2)
+{
+ static uchar null_pw[16];
+ uchar unenc_new_pw[16];
+ BOOL ret;
+ uint16 acct_ctrl;
+ const uint8 *pwd;
+
+ if (sampass == NULL) {
+ DEBUG(0,("change_lanman_password: no smb password entry.\n"));
+ return False;
+ }
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+ pwd = pdb_get_lanman_passwd(sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("change_lanman_password: account %s disabled.\n",
+ pdb_get_username(sampass)));
+ return False;
+ }
+
+ if (pwd == NULL) {
+ if (acct_ctrl & ACB_PWNOTREQ) {
+ uchar no_pw[14];
+ memset(no_pw, '\0', 14);
+ E_P16(no_pw, null_pw);
+
+ /* Get the new lanman hash. */
+ D_P16(null_pw, pass2, unenc_new_pw);
+ } else {
+ DEBUG(0,("change_lanman_password: no lanman password !\n"));
+ return False;
+ }
+ } else {
+ /* Get the new lanman hash. */
+ D_P16(pwd, pass2, unenc_new_pw);
+ }
+
+ if (!pdb_set_lanman_passwd(sampass, unenc_new_pw)) {
+ return False;
+ }
+
+ if (!pdb_set_nt_passwd (sampass, NULL)) {
+ return False; /* We lose the NT hash. Sorry. */
+ }
+
+ if (!pdb_set_pass_changed_now (sampass)) {
+ pdb_free_sam(&sampass);
+ /* Not quite sure what this one qualifies as, but this will do */
+ return False;
+ }
+
+ /* Now flush the sam_passwd struct to persistent storage */
+ become_root();
+ ret = pdb_update_sam_account (sampass, False);
+ unbecome_root();
+
+ return ret;
+}
-BOOL chgpasswd(char *name,char *oldpass,char *newpass)
+/***********************************************************
+ Code to check and change the OEM hashed password.
+************************************************************/
+BOOL pass_oem_change(char *user,
+ uchar * lmdata, uchar * lmhash,
+ uchar * ntdata, uchar * nthash)
{
- pstring passwordprogram;
- pstring chatsequence;
+ fstring new_passwd;
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
+ &sampass, new_passwd, sizeof(new_passwd));
- strlower(name);
- DEBUG(3,("Password change for user: %s\n",name));
+ /*
+ * At this point we have the new case-sensitive plaintext
+ * password in the fstring new_passwd. If we wanted to synchronise
+ * with UNIX passwords we would call a UNIX password changing
+ * function here. However it would have to be done as root
+ * as the plaintext of the old users password is not
+ * available. JRA.
+ */
-#if DEBUG_PASSWORD
- DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass));
-#endif
+ if ((ret) && lp_unix_password_sync())
+ ret = chgpasswd(user, "", new_passwd, True);
- /* Take the passed information and test it for minimum criteria */
- /* Minimum password length */
- if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */
- {
- DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
- return (False); /* inform the user */
- }
-
- /* Password is same as old password */
- if (strcmp(oldpass,newpass) == 0) /* don't allow same password */
- {
- DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */
- return (False); /* inform the user */
- }
-
-#if (defined(PASSWD_PROGRAM) && defined(PASSWD_CHAT))
- strcpy(passwordprogram,PASSWD_PROGRAM);
- strcpy(chatsequence,PASSWD_CHAT);
-#else
- strcpy(passwordprogram,lp_passwd_program());
- strcpy(chatsequence,lp_passwd_chat());
-#endif
+ if (ret)
+ ret = change_oem_password(sampass, new_passwd);
+
+ memset(new_passwd, 0, sizeof(new_passwd));
- if (!*chatsequence) {
- DEBUG(2,("Null chat sequence - no password changing\n"));
- return(False);
- }
+ pdb_free_sam(&sampass);
- if (!*passwordprogram) {
- DEBUG(2,("Null password program - no password changing\n"));
- return(False);
- }
+ return ret;
+}
- string_sub(passwordprogram,"%u",name);
- string_sub(passwordprogram,"%o",oldpass);
- string_sub(passwordprogram,"%n",newpass);
+/***********************************************************
+ Code to check the OEM hashed password.
- string_sub(chatsequence,"%u",name);
- string_sub(chatsequence,"%o",oldpass);
- string_sub(chatsequence,"%n",newpass);
- return(chat_with_program(passwordprogram,name,chatsequence));
+ this function ignores the 516 byte nt OEM hashed password
+ but does use the lm OEM password to check the nt hashed-hash.
+
+************************************************************/
+static BOOL check_oem_password(const char *user,
+ uchar * lmdata, const uchar * lmhash,
+ const uchar * ntdata, const uchar * nthash,
+ SAM_ACCOUNT **hnd, char *new_passwd,
+ int new_passwd_size)
+{
+ static uchar null_pw[16];
+ static uchar null_ntpw[16];
+ SAM_ACCOUNT *sampass = NULL;
+ const uint8 *lanman_pw, *nt_pw;
+ uint16 acct_ctrl;
+ int new_pw_len;
+ uchar new_ntp16[16];
+ uchar unenc_old_ntpw[16];
+ uchar new_p16[16];
+ uchar unenc_old_pw[16];
+ char no_pw[2];
+ BOOL ret;
+
+ BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if (ret == False) {
+ DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
+ return False;
+ }
+
+ *hnd = sampass;
+
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+
+ if (acct_ctrl & ACB_DISABLED) {
+ DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
+ return False;
+ }
+
+ /* construct a null password (in case one is needed */
+ no_pw[0] = 0;
+ no_pw[1] = 0;
+ nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
+
+ /* save pointers to passwords so we don't have to keep looking them up */
+ lanman_pw = pdb_get_lanman_passwd(sampass);
+ nt_pw = pdb_get_nt_passwd (sampass);
+
+ /* check for null passwords */
+ if (lanman_pw == NULL) {
+ if (!(acct_ctrl & ACB_PWNOTREQ)) {
+ DEBUG(0,("check_oem_password: no lanman password !\n"));
+ return False;
+ }
+ }
+
+ if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
+ if (!(acct_ctrl & ACB_PWNOTREQ)) {
+ DEBUG(0,("check_oem_password: no ntlm password !\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Call the hash function to get the new password.
+ */
+ SamOEMhash( lmdata, lanman_pw, 516);
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+
+ new_pw_len = IVAL(lmdata, 512);
+ if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
+ DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
+ return False;
+ }
+
+ if (nt_pass_set) {
+ /*
+ * nt passwords are in unicode
+ */
+ pull_ucs2(NULL, new_passwd,
+ (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
+ new_passwd_size, new_pw_len, 0);
+ } else {
+ memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
+ new_passwd[new_pw_len] = 0;
+ }
+
+ /*
+ * To ensure we got the correct new password, hash it and
+ * use it as a key to test the passed old password.
+ */
+
+ nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
+
+ if (!nt_pass_set)
+ {
+ /*
+ * Now use new_p16 as the key to see if the old
+ * password matches.
+ */
+ D_P16(new_p16, lmhash, unenc_old_pw);
+
+ if (memcmp(lanman_pw, unenc_old_pw, 16))
+ {
+ DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
+ return False;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,
+ ("check_oem_password: password %s ok\n", new_passwd));
+#endif
+ return True;
+ }
+
+ /*
+ * Now use new_p16 as the key to see if the old
+ * password matches.
+ */
+ D_P16(new_ntp16, lmhash, unenc_old_pw);
+ D_P16(new_ntp16, nthash, unenc_old_ntpw);
+
+ if (memcmp(lanman_pw, unenc_old_pw, 16))
+ {
+ DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
+ return False;
+ }
+
+ if (memcmp(nt_pw, unenc_old_ntpw, 16))
+ {
+ DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
+ return False;
+ }
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
+#endif
+ return True;
}
-#else
-BOOL chgpasswd(char *name,char *oldpass,char *newpass)
+/***********************************************************
+ Code to change the oem password. Changes both the lanman
+ and NT hashes.
+************************************************************/
+
+BOOL change_oem_password(SAM_ACCOUNT *hnd, char *new_passwd)
{
- DEBUG(0,("Password changing not compiled in (user=%s)\n",name));
- return(False);
+ BOOL ret;
+
+ if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
+ return False;
+ }
+
+ /* Now write it into the file. */
+ become_root();
+ ret = pdb_update_sam_account (hnd, False);
+ unbecome_root();
+
+ return ret;
}
+
+/***********************************************************
+ Code to check a plaintext password against smbpasswd entries.
+***********************************************************/
+
+BOOL check_plaintext_password(char *user, char *old_passwd,
+ int old_passwd_size, SAM_ACCOUNT **hnd)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ uchar old_pw[16], old_ntpw[16];
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ *hnd = sampass;
+
+ if (ret == False)
+ {
+ DEBUG(0,("check_plaintext_password: getsmbpwnam returned NULL\n"));
+ return False;
+ }
+
+ if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED)
+ {
+ DEBUG(0,("check_plaintext_password: account %s disabled.\n", user));
+ return (False);
+ }
+
+ nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("check_plaintext_password: nt_passwd \n"));
+ dump_data(100, pdb_get_nt_passwd(sampass), 16);
+ DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
+ dump_data(100, old_ntpw, 16);
+ DEBUG(100, ("check_plaintext_password: lanman_passwd \n"));
+ dump_data(100, pdb_get_lanman_passwd(sampass), 16);
+ DEBUG(100, ("check_plaintext_password: old_pw\n"));
+ dump_data(100, old_pw, 16);
#endif
+
+ if (memcmp(pdb_get_nt_passwd(sampass), old_ntpw, 16)
+ && memcmp(pdb_get_lanman_passwd(sampass), old_pw, 16))
+ return (False);
+ else
+ return (True);
+}
diff --git a/source/smbd/close.c b/source/smbd/close.c
new file mode 100644
index 00000000000..b6b619dd8ae
--- /dev/null
+++ b/source/smbd/close.c
@@ -0,0 +1,291 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file closing
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+run a file if it is a magic script
+****************************************************************************/
+static void check_magic(files_struct *fsp,connection_struct *conn)
+{
+ if (!*lp_magicscript(SNUM(conn)))
+ return;
+
+ DEBUG(5,("checking magic for %s\n",fsp->fsp_name));
+
+ {
+ char *p;
+ if (!(p = strrchr_m(fsp->fsp_name,'/')))
+ p = fsp->fsp_name;
+ else
+ p++;
+
+ if (!strequal(lp_magicscript(SNUM(conn)),p))
+ return;
+ }
+
+ {
+ int ret;
+ pstring magic_output;
+ pstring fname;
+ SMB_STRUCT_STAT st;
+ int tmp_fd, outfd;
+
+ pstrcpy(fname,fsp->fsp_name);
+ if (*lp_magicoutput(SNUM(conn)))
+ pstrcpy(magic_output,lp_magicoutput(SNUM(conn)));
+ else
+ slprintf(magic_output,sizeof(fname)-1, "%s.out",fname);
+
+ chmod(fname,0755);
+ ret = smbrun(fname,&tmp_fd);
+ DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
+ unlink(fname);
+ if (ret != 0 || tmp_fd == -1) {
+ if (tmp_fd != -1)
+ close(tmp_fd);
+ return;
+ }
+ outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
+ if (outfd == -1) {
+ close(tmp_fd);
+ return;
+ }
+
+ if (sys_fstat(tmp_fd,&st) == -1) {
+ close(tmp_fd);
+ close(outfd);
+ return;
+ }
+
+ transfer_file(tmp_fd,outfd,st.st_size);
+ close(tmp_fd);
+ close(outfd);
+ }
+}
+
+/****************************************************************************
+ Common code to close a file or a directory.
+****************************************************************************/
+
+static int close_filestruct(files_struct *fsp)
+{
+ connection_struct *conn = fsp->conn;
+ int ret = 0;
+
+ if(flush_write_cache(fsp, CLOSE_FLUSH) == -1)
+ ret = -1;
+
+ delete_write_cache(fsp);
+
+ fsp->is_directory = False;
+ fsp->stat_open = False;
+
+ conn->num_files_open--;
+
+ return ret;
+}
+
+/****************************************************************************
+ Close a file.
+
+ If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+ operation otherwise it came as the result of some other operation such as
+ the closing of the connection. In the latter case printing and
+ magic scripts are not run.
+****************************************************************************/
+
+static int close_normal_file(files_struct *fsp, BOOL normal_close)
+{
+ share_mode_entry *share_entry = NULL;
+ size_t share_entry_count = 0;
+ BOOL delete_on_close = False;
+ connection_struct *conn = fsp->conn;
+ int err = 0;
+ int err1 = 0;
+
+ remove_pending_lock_requests_by_fid(fsp);
+
+ /*
+ * If we're flushing on a close we can get a write
+ * error here, we must remember this.
+ */
+
+ if (close_filestruct(fsp) == -1)
+ err1 = -1;
+
+ if (fsp->print_file) {
+ print_fsp_end(fsp, normal_close);
+ file_free(fsp);
+ return 0;
+ }
+
+ /*
+ * Lock the share entries, and determine if we should delete
+ * on close. If so delete whilst the lock is still in effect.
+ * This prevents race conditions with the file being created. JRA.
+ */
+
+ lock_share_entry_fsp(fsp);
+ share_entry_count = del_share_mode(fsp, &share_entry);
+
+ DEBUG(10,("close_normal_file: share_entry_count = %d for file %s\n",
+ share_entry_count, fsp->fsp_name ));
+
+ /*
+ * We delete on close if it's the last open, and the
+ * delete on close flag was set in the entry we just deleted.
+ */
+
+ if ((share_entry_count == 0) && share_entry &&
+ GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) )
+ delete_on_close = True;
+
+ SAFE_FREE(share_entry);
+
+ /*
+ * NT can set delete_on_close of the last open
+ * reference to a file.
+ */
+
+ if (normal_close && delete_on_close) {
+ DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
+ fsp->fsp_name));
+ if(fsp->conn->vfs_ops.unlink(conn,fsp->fsp_name) != 0) {
+ /*
+ * This call can potentially fail as another smbd may have
+ * had the file open with delete on close set and deleted
+ * it when its last reference to this file went away. Hence
+ * we log this but not at debug level zero.
+ */
+
+ DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
+with error %s\n", fsp->fsp_name, strerror(errno) ));
+ }
+ }
+
+ unlock_share_entry_fsp(fsp);
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ release_file_oplock(fsp);
+
+ locking_close_file(fsp);
+
+ err = fd_close(conn, fsp);
+
+ /* check for magic scripts */
+ if (normal_close) {
+ check_magic(fsp,conn);
+ }
+
+ /*
+ * Ensure pending modtime is set after close.
+ */
+
+ if(fsp->pending_modtime) {
+ int saved_errno = errno;
+ set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
+ errno = saved_errno;
+ }
+
+ DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
+ conn->user,fsp->fsp_name,
+ conn->num_files_open, err ? strerror(err) : ""));
+
+ if (fsp->fsp_name)
+ string_free(&fsp->fsp_name);
+
+ file_free(fsp);
+
+ if (err == -1 || err1 == -1)
+ return -1;
+ else
+ return 0;
+}
+
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+static int close_directory(files_struct *fsp, BOOL normal_close)
+{
+ remove_pending_change_notify_requests_by_fid(fsp);
+
+ /*
+ * NT can set delete_on_close of the last open
+ * reference to a directory also.
+ */
+
+ if (normal_close && fsp->directory_delete_on_close) {
+ BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name);
+ DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n",
+ fsp->fsp_name, ok ? "succeeded" : "failed" ));
+
+ /*
+ * Ensure we remove any change notify requests that would
+ * now fail as the directory has been deleted.
+ */
+
+ if(ok)
+ remove_pending_change_notify_requests_by_filename(fsp);
+ }
+
+ /*
+ * Do the code common to files and directories.
+ */
+ close_filestruct(fsp);
+
+ if (fsp->fsp_name)
+ string_free(&fsp->fsp_name);
+
+ file_free(fsp);
+
+ return 0;
+}
+
+/****************************************************************************
+ Close a file opened with null permissions in order to read permissions.
+****************************************************************************/
+
+static int close_statfile(files_struct *fsp, BOOL normal_close)
+{
+ close_filestruct(fsp);
+
+ if (fsp->fsp_name)
+ string_free(&fsp->fsp_name);
+
+ file_free(fsp);
+
+ return 0;
+}
+
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+int close_file(files_struct *fsp, BOOL normal_close)
+{
+ if(fsp->is_directory)
+ return close_directory(fsp, normal_close);
+ else if(fsp->stat_open)
+ return close_statfile(fsp, normal_close);
+ return close_normal_file(fsp, normal_close);
+}
diff --git a/source/smbd/conn.c b/source/smbd/conn.c
new file mode 100644
index 00000000000..f9d0ffc9bd1
--- /dev/null
+++ b/source/smbd/conn.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Manage connections_struct structures
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* set these to define the limits of the server. NOTE These are on a
+ per-client basis. Thus any one machine can't connect to more than
+ MAX_CONNECTIONS services, but any number of machines may connect at
+ one time. */
+#define MAX_CONNECTIONS 128
+
+static connection_struct *Connections;
+
+/* number of open connections */
+static struct bitmap *bmap;
+static int num_open;
+
+/****************************************************************************
+init the conn structures
+****************************************************************************/
+void conn_init(void)
+{
+ bmap = bitmap_allocate(MAX_CONNECTIONS);
+}
+
+/****************************************************************************
+return the number of open connections
+****************************************************************************/
+int conn_num_open(void)
+{
+ return num_open;
+}
+
+
+/****************************************************************************
+check if a snum is in use
+****************************************************************************/
+BOOL conn_snum_used(int snum)
+{
+ connection_struct *conn;
+ for (conn=Connections;conn;conn=conn->next) {
+ if (conn->service == snum) {
+ return(True);
+ }
+ }
+ return(False);
+}
+
+
+/****************************************************************************
+find a conn given a cnum
+****************************************************************************/
+connection_struct *conn_find(int cnum)
+{
+ int count=0;
+ connection_struct *conn;
+
+ for (conn=Connections;conn;conn=conn->next,count++) {
+ if (conn->cnum == cnum) {
+ if (count > 10) {
+ DLIST_PROMOTE(Connections, conn);
+ }
+ return conn;
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+ find first available connection slot, starting from a random position.
+The randomisation stops problems with the server dieing and clients
+thinking the server is still available.
+****************************************************************************/
+connection_struct *conn_new(void)
+{
+ connection_struct *conn;
+ int i;
+
+ i = bitmap_find(bmap, 1);
+
+ if (i == -1) {
+ DEBUG(1,("ERROR! Out of connection structures\n"));
+ return NULL;
+ }
+
+ conn = (connection_struct *)malloc(sizeof(*conn));
+ if (!conn) return NULL;
+
+ ZERO_STRUCTP(conn);
+ conn->cnum = i;
+
+ bitmap_set(bmap, i);
+
+ num_open++;
+
+ string_set(&conn->user,"");
+ string_set(&conn->dirpath,"");
+ string_set(&conn->connectpath,"");
+ string_set(&conn->origpath,"");
+
+ DLIST_ADD(Connections, conn);
+
+ return conn;
+}
+
+/****************************************************************************
+close all conn structures
+****************************************************************************/
+void conn_close_all(void)
+{
+ connection_struct *conn, *next;
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ close_cnum(conn, (uint16)-1);
+ }
+}
+
+/****************************************************************************
+idle inactive connections
+****************************************************************************/
+BOOL conn_idle_all(time_t t, int deadtime)
+{
+ BOOL allidle = True;
+ connection_struct *conn, *next;
+
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ /* close dirptrs on connections that are idle */
+ if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT)
+ dptr_idlecnum(conn);
+
+ if (conn->num_files_open > 0 ||
+ (t-conn->lastused)<deadtime)
+ allidle = False;
+ }
+
+ return allidle;
+}
+
+/****************************************************************************
+ Free a conn structure.
+****************************************************************************/
+
+void conn_free(connection_struct *conn)
+{
+ /* Free vfs_connection_struct */
+
+#ifdef HAVE_LIBDL
+ if (conn->dl_handle != NULL) {
+ /* Close dlopen() handle */
+ dlclose(conn->dl_handle);
+ }
+#endif /* HAVE_LIBDL */
+
+ DLIST_REMOVE(Connections, conn);
+
+ if (conn->ngroups && conn->groups) {
+ SAFE_FREE(conn->groups);
+ conn->ngroups = 0;
+ }
+
+ delete_nt_token(&conn->nt_user_token);
+ free_namearray(conn->veto_list);
+ free_namearray(conn->hide_list);
+ free_namearray(conn->veto_oplock_list);
+
+ string_free(&conn->user);
+ string_free(&conn->dirpath);
+ string_free(&conn->connectpath);
+ string_free(&conn->origpath);
+
+ bitmap_clear(bmap, conn->cnum);
+ num_open--;
+
+ ZERO_STRUCTP(conn);
+ SAFE_FREE(conn);
+}
+
+
+/****************************************************************************
+receive a smbcontrol message to forcibly unmount a share
+the message contains just a share name and all instances of that
+share are unmounted
+the special sharename '*' forces unmount of all shares
+****************************************************************************/
+void msg_force_tdis(int msg_type, pid_t pid, void *buf, size_t len)
+{
+ connection_struct *conn, *next;
+ fstring sharename;
+
+ fstrcpy(sharename, buf);
+
+ if (strcmp(sharename, "*") == 0) {
+ DEBUG(1,("Forcing close of all shares\n"));
+ conn_close_all();
+ return;
+ }
+
+ for (conn=Connections;conn;conn=next) {
+ next=conn->next;
+ if (strequal(lp_servicename(conn->service), sharename)) {
+ DEBUG(1,("Forcing close of share %s cnum=%d\n",
+ sharename, conn->cnum));
+ close_cnum(conn, (uint16)-1);
+ }
+ }
+}
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
new file mode 100644
index 00000000000..c0eaf8187db
--- /dev/null
+++ b/source/smbd/connection.c
@@ -0,0 +1,190 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ connection claim routines
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern fstring remote_machine;
+static TDB_CONTEXT *tdb;
+
+/****************************************************************************
+ Return the connection tdb context (used for message send all).
+****************************************************************************/
+
+TDB_CONTEXT *conn_tdb_ctx(void)
+{
+ return tdb;
+}
+
+/****************************************************************************
+ Delete a connection record.
+****************************************************************************/
+
+BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
+{
+ struct connections_key key;
+ TDB_DATA kbuf;
+
+ if (!tdb) return False;
+
+ DEBUG(3,("Yielding connection to %s\n",name));
+
+ ZERO_STRUCT(key);
+ key.pid = sys_getpid();
+ key.cnum = conn?conn->cnum:-1;
+ fstrcpy(key.name, name);
+
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+
+ if (tdb_delete(tdb, kbuf) != 0) {
+ int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0;
+ DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n",
+ name, tdb_errorstr(tdb) ));
+ return (False);
+ }
+
+ return(True);
+}
+
+struct count_stat {
+ pid_t mypid;
+ int curr_connections;
+ char *name;
+ BOOL Clear;
+};
+
+/****************************************************************************
+ Count the entries belonging to a service in the connection db.
+****************************************************************************/
+
+static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp)
+{
+ struct connections_data crec;
+ struct count_stat *cs = (struct count_stat *)udp;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum == -1)
+ return 0;
+
+ /* If the pid was not found delete the entry from connections.tdb */
+
+ if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) {
+ DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
+ (unsigned int)crec.pid, crec.cnum, crec.name));
+ if (tdb_delete(the_tdb, kbuf) != 0)
+ DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) ));
+ return 0;
+ }
+
+ if (strequal(crec.name, cs->name))
+ cs->curr_connections++;
+
+ return 0;
+}
+
+/****************************************************************************
+ Claim an entry in the connections database.
+****************************************************************************/
+
+BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
+{
+ struct connections_key key;
+ struct connections_data crec;
+ TDB_DATA kbuf, dbuf;
+
+ if (!tdb) {
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ }
+ if (!tdb)
+ return False;
+
+ /*
+ * Enforce the max connections parameter.
+ */
+
+ if (max_connections > 0) {
+ struct count_stat cs;
+
+ cs.mypid = sys_getpid();
+ cs.curr_connections = 0;
+ cs.name = lp_servicename(SNUM(conn));
+ cs.Clear = Clear;
+
+ /*
+ * This has a race condition, but locking the chain before hand is worse
+ * as it leads to deadlock.
+ */
+
+ if (tdb_traverse(tdb, count_fn, &cs) == -1) {
+ DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n",
+ tdb_errorstr(tdb) ));
+ return False;
+ }
+
+ if (cs.curr_connections >= max_connections) {
+ DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n",
+ max_connections, name ));
+ return False;
+ }
+ }
+
+ DEBUG(5,("claiming %s %d\n",name,max_connections));
+
+ ZERO_STRUCT(key);
+ key.pid = sys_getpid();
+ key.cnum = conn?conn->cnum:-1;
+ fstrcpy(key.name, name);
+
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+
+ /* fill in the crec */
+ ZERO_STRUCT(crec);
+ crec.magic = 0x280267;
+ crec.pid = sys_getpid();
+ crec.cnum = conn?conn->cnum:-1;
+ if (conn) {
+ crec.uid = conn->uid;
+ crec.gid = conn->gid;
+ StrnCpy(crec.name,
+ lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
+ }
+ crec.start = time(NULL);
+
+ StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
+ StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
+
+ dbuf.dptr = (char *)&crec;
+ dbuf.dsize = sizeof(crec);
+
+ if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+ DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
+ tdb_errorstr(tdb) ));
+ return False;
+ }
+
+ return True;
+}
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
new file mode 100644
index 00000000000..51f06149419
--- /dev/null
+++ b/source/smbd/dfree.c
@@ -0,0 +1,165 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+normalise for DOS usage
+****************************************************************************/
+static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ /* check if the disk is beyond the max disk size */
+ SMB_BIG_UINT maxdisksize = lp_maxdisksize();
+ if (maxdisksize) {
+ /* convert to blocks - and don't overflow */
+ maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
+ if (*dsize > maxdisksize) *dsize = maxdisksize;
+ if (*dfree > maxdisksize) *dfree = maxdisksize-1;
+ /* the -1 should stop applications getting div by 0
+ errors */
+ }
+
+ while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
+ *dfree /= 2;
+ *dsize /= 2;
+ *bsize *= 2;
+ if(small_query) {
+ /*
+ * Force max to fit in 16 bit fields.
+ */
+ if (*bsize > (WORDMAX*512)) {
+ *bsize = (WORDMAX*512);
+ if (*dsize > WORDMAX)
+ *dsize = WORDMAX;
+ if (*dfree > WORDMAX)
+ *dfree = WORDMAX;
+ break;
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+ return number of 1K blocks available on a path and total number
+****************************************************************************/
+
+static SMB_BIG_UINT disk_free(const char *path, BOOL small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ int dfree_retval;
+ SMB_BIG_UINT dfree_q = 0;
+ SMB_BIG_UINT bsize_q = 0;
+ SMB_BIG_UINT dsize_q = 0;
+ char *dfree_command;
+
+ (*dfree) = (*dsize) = 0;
+ (*bsize) = 512;
+
+ /*
+ * If external disk calculation specified, use it.
+ */
+
+ dfree_command = lp_dfree_command();
+ if (dfree_command && *dfree_command) {
+ char *p;
+ char **lines;
+ pstring syscmd;
+
+ slprintf(syscmd, sizeof(syscmd)-1, "%s %s", dfree_command, path);
+ DEBUG (3, ("disk_free: Running command %s\n", syscmd));
+
+ lines = file_lines_pload(syscmd, NULL);
+ if (lines) {
+ char *line = lines[0];
+
+ DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
+
+ *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10);
+ while (p && *p & isspace(*p))
+ p++;
+ if (p && *p)
+ *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10);
+ while (p && *p & isspace(*p))
+ p++;
+ if (p && *p)
+ *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10);
+ else
+ *bsize = 1024;
+ file_lines_free(lines);
+ DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
+ (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
+
+ if (!*dsize)
+ *dsize = 2048;
+ if (!*dfree)
+ *dfree = 1024;
+ } else {
+ DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
+ syscmd, strerror(errno) ));
+ sys_fsusage(path, dfree, dsize);
+ }
+ } else
+ sys_fsusage(path, dfree, dsize);
+
+ if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
+ (*bsize) = bsize_q;
+ (*dfree) = MIN(*dfree,dfree_q);
+ (*dsize) = MIN(*dsize,dsize_q);
+ }
+
+ /* FIXME : Any reason for this assumption ? */
+ if (*bsize < 256) {
+ DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
+ *bsize = 512;
+ }
+
+ if ((*dsize)<1) {
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: dfree is broken on this system\n"));
+ done=1;
+ }
+ *dsize = 20*1024*1024/(*bsize);
+ *dfree = MAX(1,*dfree);
+ }
+
+ disk_norm(small_query,bsize,dfree,dsize);
+
+ if ((*bsize) < 1024) {
+ dfree_retval = (*dfree)/(1024/(*bsize));
+ } else {
+ dfree_retval = ((*bsize)/1024)*(*dfree);
+ }
+
+ return(dfree_retval);
+}
+
+
+/****************************************************************************
+wrap it to get filenames right
+****************************************************************************/
+SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ return disk_free(path,small_query, bsize,dfree,dsize);
+}
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ac6f918b9da..faf5bca52d0 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Directory handling routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,351 +20,505 @@
*/
#include "includes.h"
-#include "loadparm.h"
-
-extern int DEBUGLEVEL;
-extern connection_struct Connections[];
/*
This module implements directory related functions for Samba.
*/
-
-
-uint32 dircounter = 0;
-
-
-#define NUMDIRPTRS 256
-
-
-static struct dptr_struct
-{
- int pid;
- int cnum;
- uint32 lastused;
- void *ptr;
- BOOL valid;
- BOOL finished;
- BOOL expect_close;
- char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */
- uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */
- char *path;
-}
-dirptrs[NUMDIRPTRS];
-
+typedef struct _dptr_struct {
+ struct _dptr_struct *next, *prev;
+ int dnum;
+ uint16 spid;
+ connection_struct *conn;
+ void *ptr;
+ BOOL expect_close;
+ char *wcard; /* Field only used for trans2_ searches */
+ uint16 attr; /* Field only used for trans2_ searches */
+ char *path;
+} dptr_struct;
+
+static struct bitmap *dptr_bmap;
+static dptr_struct *dirptrs;
static int dptrs_open = 0;
+#define INVALID_DPTR_KEY (-3)
+
/****************************************************************************
-initialise the dir array
+ Initialise the dir bitmap.
****************************************************************************/
+
void init_dptrs(void)
{
static BOOL dptrs_init=False;
- int i;
- if (dptrs_init) return;
- for (i=0;i<NUMDIRPTRS;i++)
- {
- dirptrs[i].valid = False;
- dirptrs[i].wcard = NULL;
- dirptrs[i].ptr = NULL;
- string_init(&dirptrs[i].path,"");
- }
+ if (dptrs_init)
+ return;
+
+ dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
+
+ if (!dptr_bmap)
+ exit_server("out of memory in init_dptrs");
+
dptrs_init = True;
}
/****************************************************************************
-idle a dptr - the directory is closed but the control info is kept
+ Idle a dptr - the directory is closed but the control info is kept.
****************************************************************************/
-static void dptr_idle(int key)
+
+static void dptr_idle(dptr_struct *dptr)
{
- if (dirptrs[key].valid && dirptrs[key].ptr) {
- DEBUG(4,("Idling dptr key %d\n",key));
+ if (dptr->ptr) {
+ DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
dptrs_open--;
- CloseDir(dirptrs[key].ptr);
- dirptrs[key].ptr = NULL;
- }
+ CloseDir(dptr->ptr);
+ dptr->ptr = NULL;
+ }
}
/****************************************************************************
-idle the oldest dptr
+ Idle the oldest dptr.
****************************************************************************/
+
static void dptr_idleoldest(void)
{
- int i;
- uint32 old=dircounter+1;
- int oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No dptrs available to idle ?\n"));
+ return;
+ }
+
+ /*
+ * Idle the oldest pointer.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if (dptr->ptr) {
+ dptr_idle(dptr);
+ return;
}
- if (oldi != -1)
- dptr_idle(oldi);
- else
- DEBUG(0,("No dptrs available to idle??\n"));
+ }
}
/****************************************************************************
-get the dir ptr for a dir index
+ Get the dptr_struct for a dir index.
****************************************************************************/
-static void *dptr_get(int key,uint32 lastused)
-{
- if (dirptrs[key].valid) {
- if (lastused) dirptrs[key].lastused = lastused;
- if (!dirptrs[key].ptr) {
- if (dptrs_open >= MAXDIR)
- dptr_idleoldest();
- DEBUG(4,("Reopening dptr key %d\n",key));
- if ((dirptrs[key].ptr = OpenDir(dirptrs[key].path)))
- dptrs_open++;
+
+static dptr_struct *dptr_get(int key, BOOL forclose)
+{
+ dptr_struct *dptr;
+
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if(dptr->dnum == key) {
+ if (!forclose && !dptr->ptr) {
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+ dptr_idleoldest();
+ DEBUG(4,("Reopening dptr key %d\n",key));
+ if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
+ dptrs_open++;
+ }
+ DLIST_PROMOTE(dirptrs,dptr);
+ return dptr;
}
- return(dirptrs[key].ptr);
}
return(NULL);
}
/****************************************************************************
-get the dir path for a dir index
+ Get the dptr ptr for a dir index.
****************************************************************************/
+
+static void *dptr_ptr(int key)
+{
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->ptr);
+ return(NULL);
+}
+
+/****************************************************************************
+ Get the dir path for a dir index.
+****************************************************************************/
+
char *dptr_path(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].path);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->path);
return(NULL);
}
/****************************************************************************
-get the dir wcard for a dir index (lanman2 specific)
+ Get the dir wcard for a dir index (lanman2 specific).
****************************************************************************/
+
char *dptr_wcard(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].wcard);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->wcard);
return(NULL);
}
/****************************************************************************
-set the dir wcard for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir wcard for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
****************************************************************************/
+
BOOL dptr_set_wcard(int key, char *wcard)
{
- if (dirptrs[key].valid) {
- dirptrs[key].wcard = wcard;
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr) {
+ dptr->wcard = wcard;
return True;
}
return False;
}
/****************************************************************************
-set the dir attrib for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir attrib for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
****************************************************************************/
+
BOOL dptr_set_attr(int key, uint16 attr)
{
- if (dirptrs[key].valid) {
- dirptrs[key].attr = attr;
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr) {
+ dptr->attr = attr;
return True;
}
return False;
}
/****************************************************************************
-get the dir attrib for a dir index (lanman2 specific)
+ Get the dir attrib for a dir index (lanman2 specific)
****************************************************************************/
+
uint16 dptr_attr(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].attr);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->attr);
return(0);
}
/****************************************************************************
-close a dptr
+ Close a dptr (internal func).
+****************************************************************************/
+
+static void dptr_close_internal(dptr_struct *dptr)
+{
+ DEBUG(4,("closing dptr key %d\n",dptr->dnum));
+
+ DLIST_REMOVE(dirptrs, dptr);
+
+ /*
+ * Free the dnum in the bitmap. Remember the dnum value is always
+ * biased by one with respect to the bitmap.
+ */
+
+ if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
+ DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
+ dptr->dnum ));
+ }
+
+ bitmap_clear(dptr_bmap, dptr->dnum - 1);
+
+ if (dptr->ptr) {
+ CloseDir(dptr->ptr);
+ dptrs_open--;
+ }
+
+ /* Lanman 2 specific code */
+ SAFE_FREE(dptr->wcard);
+ string_set(&dptr->path,"");
+ SAFE_FREE(dptr);
+}
+
+/****************************************************************************
+ Close a dptr given a key.
****************************************************************************/
-void dptr_close(int key)
+
+void dptr_close(int *key)
{
- if (dirptrs[key].valid) {
- DEBUG(4,("closing dptr key %d\n",key));
- if (dirptrs[key].ptr) {
- CloseDir(dirptrs[key].ptr);
- dptrs_open--;
+ dptr_struct *dptr;
+
+ if(*key == INVALID_DPTR_KEY)
+ return;
+
+ /* OS/2 seems to use -1 to indicate "close all directories" */
+ if (*key == -1) {
+ dptr_struct *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ dptr_close_internal(dptr);
}
- /* Lanman 2 specific code */
- if (dirptrs[key].wcard)
- free(dirptrs[key].wcard);
- dirptrs[key].valid = False;
- string_set(&dirptrs[key].path,"");
+ *key = INVALID_DPTR_KEY;
+ return;
}
+
+ dptr = dptr_get(*key, True);
+
+ if (!dptr) {
+ DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
+ return;
+ }
+
+ dptr_close_internal(dptr);
+
+ *key = INVALID_DPTR_KEY;
}
/****************************************************************************
-close all dptrs for a cnum
+ Close all dptrs for a cnum.
****************************************************************************/
-void dptr_closecnum(int cnum)
+
+void dptr_closecnum(connection_struct *conn)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].cnum == cnum)
- dptr_close(i);
+ dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (dptr->conn == conn)
+ dptr_close_internal(dptr);
+ }
}
/****************************************************************************
-idle all dptrs for a cnum
+ Idle all dptrs for a cnum.
****************************************************************************/
-void dptr_idlecnum(int cnum)
+
+void dptr_idlecnum(connection_struct *conn)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].cnum == cnum && dirptrs[i].ptr)
- dptr_idle(i);
+ dptr_struct *dptr;
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if (dptr->conn == conn && dptr->ptr)
+ dptr_idle(dptr);
+ }
}
/****************************************************************************
-close a dptr that matches a given path, only if it matches the pid also
+ Close a dptr that matches a given path, only if it matches the spid also.
****************************************************************************/
-void dptr_closepath(char *path,int pid)
+
+void dptr_closepath(char *path,uint16 spid)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && pid == dirptrs[i].pid &&
- strequal(dirptrs[i].path,path))
- dptr_close(i);
+ dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (spid == dptr->spid && strequal(dptr->path,path))
+ dptr_close_internal(dptr);
+ }
}
/****************************************************************************
- start a directory listing
+ Start a directory listing.
****************************************************************************/
-static BOOL start_dir(int cnum,char *directory)
+
+static BOOL start_dir(connection_struct *conn,char *directory)
{
- DEBUG(5,("start_dir cnum=%d dir=%s\n",cnum,directory));
+ DEBUG(5,("start_dir dir=%s\n",directory));
- if (!check_name(directory,cnum))
+ if (!check_name(directory,conn))
return(False);
if (! *directory)
directory = ".";
- Connections[cnum].dirptr = OpenDir(directory);
- if (Connections[cnum].dirptr) {
+ conn->dirptr = OpenDir(conn, directory, True);
+ if (conn->dirptr) {
dptrs_open++;
- string_set(&Connections[cnum].dirpath,directory);
+ string_set(&conn->dirpath,directory);
return(True);
}
return(False);
}
+/****************************************************************************
+ Try and close the oldest handle not marked for
+ expect close in the hope that the client has
+ finished with that one.
+****************************************************************************/
+
+static void dptr_close_oldest(BOOL old)
+{
+ dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No old dptrs available to close oldest ?\n"));
+ return;
+ }
+
+ /*
+ * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
+ * does not have expect_close set. If 'old' is false, close
+ * one of the new dnum handles.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
+ (!old && (dptr->dnum > 255))) {
+ dptr_close_internal(dptr);
+ return;
+ }
+ }
+}
/****************************************************************************
-create a new dir ptr
+ Create a new dir ptr. If the flag old_handle is true then we must allocate
+ from the bitmap range 0 - 255 as old SMBsearch directory handles are only
+ one byte long. If old_handle is false we allocate from the range
+ 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
+ a directory handle is never zero. All the above is folklore taught to
+ me at Andrew's knee.... :-) :-). JRA.
****************************************************************************/
-int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
+
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
{
- int i;
- uint32 old;
- int oldi;
+ dptr_struct *dptr;
- if (!start_dir(cnum,path))
- return(-1);
+ if (!start_dir(conn,path))
+ return(-2); /* Code to say use a unix error return code. */
- if (dptrs_open >= MAXDIR)
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
- for (i=0;i<NUMDIRPTRS;i++)
- if (!dirptrs[i].valid)
- break;
- if (i == NUMDIRPTRS) i = -1;
+ dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
+ if(!dptr) {
+ DEBUG(0,("malloc fail in dptr_create.\n"));
+ return -1;
+ }
+
+ ZERO_STRUCTP(dptr);
+
+ if(old_handle) {
+
+ /*
+ * This is an old-style SMBsearch request. Ensure the
+ * value we return will fit in the range 1-255.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+ /*
+ * Try and close the oldest handle not marked for
+ * expect close in the hope that the client has
+ * finished with that one.
+ */
- /* as a 2nd option, grab the oldest not marked for expect_close */
- if (i == -1) {
- old=dircounter+1;
- oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ dptr_close_oldest(True);
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+ DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
+ SAFE_FREE(dptr);
+ return -1;
}
- i = oldi;
- }
+ }
+ } else {
+
+ /*
+ * This is a new-style trans2 request. Allocate from
+ * a range that will return 256 - MAX_DIRECTORY_HANDLES.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
- /* a 3rd option - grab the oldest one */
- if (i == -1) {
- old=dircounter+1;
- oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
+
+ /*
+ * Try and close the oldest handle close in the hope that
+ * the client has finished with that one. This will only
+ * happen in the case of the Win98 client bug where it leaks
+ * directory handles.
+ */
+
+ dptr_close_oldest(False);
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
+ DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
+ SAFE_FREE(dptr);
+ return -1;
}
- i = oldi;
+ }
}
- if (i == -1) {
- DEBUG(0,("Error - all dirptrs in use??\n"));
- return(-1);
- }
+ bitmap_set(dptr_bmap, dptr->dnum);
+
+ dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
- if (dirptrs[i].valid)
- dptr_close(i);
+ dptr->ptr = conn->dirptr;
+ string_set(&dptr->path,path);
+ dptr->conn = conn;
+ dptr->spid = spid;
+ dptr->expect_close = expect_close;
+ dptr->wcard = NULL; /* Only used in lanman2 searches */
+ dptr->attr = 0; /* Only used in lanman2 searches */
- dirptrs[i].ptr = Connections[cnum].dirptr;
- string_set(&dirptrs[i].path,path);
- dirptrs[i].lastused = dircounter++;
- dirptrs[i].finished = False;
- dirptrs[i].cnum = cnum;
- dirptrs[i].pid = pid;
- dirptrs[i].expect_close = expect_close;
- dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
- dirptrs[i].attr = 0; /* Only used in lanman2 searches */
- dirptrs[i].valid = True;
+ DLIST_ADD(dirptrs, dptr);
DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
- i,path,expect_close));
+ dptr->dnum,path,expect_close));
- return(i);
+ return(dptr->dnum);
}
-#define DPTR_MASK ((uint32)(((uint32)1)<<31))
-
/****************************************************************************
-fill the 5 byte server reserved dptr field
+ Fill the 5 byte server reserved dptr field.
****************************************************************************/
+
BOOL dptr_fill(char *buf1,unsigned int key)
{
unsigned char *buf = (unsigned char *)buf1;
- void *p = dptr_get(key,0);
+ void *p = dptr_ptr(key);
uint32 offset;
if (!p) {
DEBUG(1,("filling null dirptr %d\n",key));
return(False);
}
offset = TellDir(p);
- DEBUG(6,("fill on key %d dirptr 0x%x now at %d\n",key,p,offset));
+ DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
+ (long)p,(int)offset));
buf[0] = key;
SIVAL(buf,1,offset | DPTR_MASK);
return(True);
}
-
/****************************************************************************
-return True is the offset is at zero
+ Fetch the dir ptr and seek it given the 5 byte server field.
****************************************************************************/
-BOOL dptr_zero(char *buf)
-{
- return((IVAL(buf,1)&~DPTR_MASK) == 0);
-}
-/****************************************************************************
-fetch the dir ptr and seek it given the 5 byte server field
-****************************************************************************/
void *dptr_fetch(char *buf,int *num)
{
unsigned int key = *(unsigned char *)buf;
- void *p = dptr_get(key,dircounter++);
+ void *p = dptr_ptr(key);
uint32 offset;
if (!p) {
DEBUG(3,("fetched null dirptr %d\n",key));
@@ -379,101 +533,117 @@ void *dptr_fetch(char *buf,int *num)
}
/****************************************************************************
-fetch the dir ptr and seek it given the lanman2 parameter block
+ Fetch the dir ptr.
****************************************************************************/
-void *dptr_fetch_lanman2(char *params,int dptr_num)
+
+void *dptr_fetch_lanman2(int dptr_num)
{
- void *p = dptr_get(dptr_num,dircounter++);
- uint32 resume_key = SVAL(params,6);
- BOOL uses_resume_key = BITSETW(params+10,2);
- BOOL continue_bit = BITSETW(params+10,3);
+ void *p = dptr_ptr(dptr_num);
if (!p) {
DEBUG(3,("fetched null dirptr %d\n",dptr_num));
return(NULL);
}
- if(uses_resume_key && !continue_bit)
- SeekDir(p,resume_key);
DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
return(p);
}
/****************************************************************************
- get a directory entry
+ Check a filetype for being valid.
+****************************************************************************/
+
+BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
+{
+ if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
+ return False;
+ return True;
+}
+
+/****************************************************************************
+ Get an 8.3 directory entry.
****************************************************************************/
-BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
+
+BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
+ SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
{
char *dname;
BOOL found = False;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
pstring path;
pstring pathreal;
BOOL isrootdir;
pstring filename;
- BOOL matched;
+ BOOL needslash;
*path = *pathreal = *filename = 0;
- isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
- strequal(Connections[cnum].dirpath,".") ||
- strequal(Connections[cnum].dirpath,"/"));
+ isrootdir = (strequal(conn->dirpath,"./") ||
+ strequal(conn->dirpath,".") ||
+ strequal(conn->dirpath,"/"));
- if (!Connections[cnum].dirptr)
+ needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+ if (!conn->dirptr)
return(False);
-
+
while (!found)
- {
- dname = ReadDirName(Connections[cnum].dirptr);
+ {
+ dname = ReadDirName(conn->dirptr);
- DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n",
- Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
+ DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
+ (long)conn->dirptr,TellDir(conn->dirptr)));
- if (dname == NULL)
- return(False);
+ if (dname == NULL)
+ return(False);
- matched = False;
-
- strcpy(filename,dname);
-
- if ((strcmp(filename,mask) == 0) ||
- (name_map_mangle(filename,True,SNUM(cnum)) &&
- mask_match(filename,mask,False,False)))
- {
- if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
- continue;
-
- strcpy(fname,filename);
- *path = 0;
- strcpy(path,Connections[cnum].dirpath);
- strcat(path,"/");
- strcpy(pathreal,path);
- strcat(path,fname);
- strcat(pathreal,dname);
- if (sys_stat(pathreal,&sbuf) != 0)
- {
- DEBUG(5,("Couldn't stat 1 [%s]\n",path));
- continue;
- }
+ pstrcpy(filename,dname);
+
+ /* notice the special *.* handling. This appears to be the only difference
+ between the wildcard handling in this routine and in the trans2 routines.
+ see masktest for a demo
+ */
+ if ((strcmp(mask,"*.*") == 0) ||
+ mask_match(filename,mask,False) ||
+ (name_map_mangle(filename,True,False,SNUM(conn)) &&
+ mask_match(filename,mask,False)))
+ {
+ if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
+ continue;
- if (check_descend &&
- !strequal(fname,".") && !strequal(fname,".."))
- continue;
+ if (!is_8_3(filename, False)) {
+ name_map_mangle(filename,True,False,SNUM(conn));
+ }
+
+ pstrcpy(fname,filename);
+ *path = 0;
+ pstrcpy(path,conn->dirpath);
+ if(needslash)
+ pstrcat(path,"/");
+ pstrcpy(pathreal,path);
+ pstrcat(path,fname);
+ pstrcat(pathreal,dname);
+ if (conn->vfs_ops.stat(conn, pathreal, &sbuf) != 0)
+ {
+ DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
+ continue;
+ }
- *mode = dos_mode(cnum,pathreal,&sbuf);
+ *mode = dos_mode(conn,pathreal,&sbuf);
- if (((*mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
- {
- DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
- continue;
- }
- *size = sbuf.st_size;
- *date = sbuf.st_mtime;
+ if (!dir_check_ftype(conn,*mode,&sbuf,dirtype))
+ {
+ DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
+ continue;
+ }
- DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
+ *size = sbuf.st_size;
+ *date = sbuf.st_mtime;
+
+ DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
- found = True;
- }
+ found = True;
}
+ }
return(found);
}
@@ -490,27 +660,114 @@ typedef struct
} Dir;
+
+/*******************************************************************
+check to see if a user can read a file. This is only approximate,
+it is used as part of the "hide unreadable" option. Don't
+use it for anything security sensitive
+********************************************************************/
+
+static BOOL user_can_read_file(connection_struct *conn, char *name)
+{
+ extern struct current_user current_user;
+ SMB_STRUCT_STAT ste;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ files_struct *fsp;
+ int smb_action;
+ NTSTATUS status;
+ uint32 access_granted;
+
+ ZERO_STRUCT(ste);
+
+ /* if we can't stat it does not show it */
+ if (vfs_stat(conn, name, &ste) != 0)
+ return False;
+
+ /* Pseudo-open the file (note - no fd's created). */
+
+ if(S_ISDIR(ste.st_mode))
+ fsp = open_directory(conn, name, &ste, SET_DENY_MODE(DENY_NONE), FILE_OPEN,
+ unix_mode(conn,aRONLY|aDIR, name), &smb_action);
+ else
+ fsp = open_file_stat(conn,name,&ste,DOS_OPEN_RDONLY,&smb_action);
+ if (!fsp)
+ return False;
+
+ /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
+ sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
+ close_file(fsp, True);
+
+ /* No access if SD get failed. */
+ if (!sd_size)
+ return False;
+
+ return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
+ &access_granted, &status);
+
+#if 0
+ /* Old - crappy check :-). JRA */
+
+ if (ste.st_uid == conn->uid) {
+ return (ste.st_mode & S_IRUSR) == S_IRUSR;
+ } else {
+ int i;
+ if (ste.st_gid == conn->gid) {
+ return (ste.st_mode & S_IRGRP) == S_IRGRP;
+ }
+ for (i=0; i<conn->ngroups; i++) {
+ if (conn->groups[i] == ste.st_gid) {
+ return (ste.st_mode & S_IRGRP) == S_IRGRP;
+ }
+ }
+ }
+
+ return (ste.st_mode & S_IROTH) == S_IROTH;
+#endif
+}
+
/*******************************************************************
-open a directory
+ Open a directory.
********************************************************************/
-void *OpenDir(char *name)
+
+void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
{
Dir *dirp;
char *n;
- void *p = sys_opendir(name);
+ DIR *p = conn->vfs_ops.opendir(conn,name);
int used=0;
if (!p) return(NULL);
dirp = (Dir *)malloc(sizeof(Dir));
if (!dirp) {
- closedir(p);
+ DEBUG(0,("Out of memory in OpenDir\n"));
+ conn->vfs_ops.closedir(conn,p);
return(NULL);
}
dirp->pos = dirp->numentries = dirp->mallocsize = 0;
dirp->data = dirp->current = NULL;
- while ((n = readdirname(p))) {
- int l = strlen(n)+1;
+ while ((n = vfs_readdirname(conn, p)))
+ {
+ int l;
+
+ l = strlen(n)+1;
+
+ /* If it's a vetoed file, pretend it doesn't even exist */
+ if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
+
+ /* Honour _hide unreadable_ option */
+ if (conn && lp_hideunreadable(SNUM(conn))) {
+ char *entry;
+ int ret=0;
+
+ if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
+ ret = user_can_read_file(conn, entry);
+ SAFE_FREE(entry);
+ }
+ if (!ret) continue;
+ }
+
if (used + l > dirp->mallocsize) {
int s = MAX(used+l,used+2000);
char *r;
@@ -523,30 +780,31 @@ void *OpenDir(char *name)
dirp->mallocsize = s;
dirp->current = dirp->data;
}
- strcpy(dirp->data+used,n);
+ pstrcpy(dirp->data+used,n);
used += l;
dirp->numentries++;
}
- closedir(p);
+ conn->vfs_ops.closedir(conn,p);
return((void *)dirp);
}
/*******************************************************************
-close a directory
+ Close a directory.
********************************************************************/
+
void CloseDir(void *p)
{
- Dir *dirp = (Dir *)p;
- if (!dirp) return;
- if (dirp->data) free(dirp->data);
- free(dirp);
+ if (!p) return;
+ SAFE_FREE(((Dir *)p)->data);
+ SAFE_FREE(p);
}
/*******************************************************************
-read from a directory
+ Read from a directory.
********************************************************************/
+
char *ReadDirName(void *p)
{
char *ret;
@@ -563,8 +821,9 @@ char *ReadDirName(void *p)
/*******************************************************************
-seek a dir
+ Seek a dir.
********************************************************************/
+
BOOL SeekDir(void *p,int pos)
{
Dir *dirp = (Dir *)p;
@@ -582,8 +841,9 @@ BOOL SeekDir(void *p,int pos)
}
/*******************************************************************
-tell a dir position
+ Tell a dir position.
********************************************************************/
+
int TellDir(void *p)
{
Dir *dirp = (Dir *)p;
@@ -593,363 +853,113 @@ int TellDir(void *p)
return(dirp->pos);
}
+/*******************************************************************************
+ This section manages a global directory cache.
+ (It should probably be split into a separate module. crh)
+********************************************************************************/
+
+typedef struct {
+ ubi_dlNode node;
+ char *path;
+ char *name;
+ char *dname;
+ int snum;
+} dir_cache_entry;
+
+static ubi_dlNewList( dir_cache );
+
+/*****************************************************************************
+ Add an entry to the directory cache.
+ Input: path -
+ name -
+ dname -
+ snum -
+ Output: None.
+*****************************************************************************/
+
+void DirCacheAdd( char *path, char *name, char *dname, int snum )
+{
+ int pathlen;
+ int namelen;
+ dir_cache_entry *entry;
+
+ /* Allocate the structure & string space in one go so that it can be freed
+ * in one call to free().
+ */
+ pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
+ namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
+ entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
+ + pathlen
+ + namelen
+ + strlen( dname ) +1 );
+ if( NULL == entry ) /* Not adding to the cache is not fatal, */
+ return; /* so just return as if nothing happened. */
+
+ /* Set pointers correctly and load values. */
+ entry->path = pstrcpy( (char *)&entry[1], path);
+ entry->name = pstrcpy( &(entry->path[pathlen]), name);
+ entry->dname = pstrcpy( &(entry->name[namelen]), dname);
+ entry->snum = snum;
+
+ /* Add the new entry to the linked list. */
+ (void)ubi_dlAddHead( dir_cache, entry );
+ DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
+
+ /* Free excess cache entries. */
+ while( DIRCACHESIZE < dir_cache->count )
+ safe_free( ubi_dlRemTail( dir_cache ) );
-static int dir_cache_size = 0;
-static struct dir_cache {
- struct dir_cache *next;
- struct dir_cache *prev;
- char *path;
- char *name;
- char *dname;
- int snum;
-} *dir_cache = NULL;
-
-/*******************************************************************
-add an entry to the directory cache
-********************************************************************/
-void DirCacheAdd(char *path,char *name,char *dname,int snum)
-{
- struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
- if (!entry) return;
- entry->path = strdup(path);
- entry->name = strdup(name);
- entry->dname = strdup(dname);
- entry->snum = snum;
- if (!entry->path || !entry->name || !entry->dname) return;
-
- entry->next = dir_cache;
- entry->prev = NULL;
- if (entry->next) entry->next->prev = entry;
- dir_cache = entry;
-
- DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
-
- if (dir_cache_size == DIRCACHESIZE) {
- for (entry=dir_cache; entry->next; entry=entry->next) ;
- free(entry->path);
- free(entry->name);
- free(entry->dname);
- if (entry->prev) entry->prev->next = entry->next;
- free(entry);
- } else {
- dir_cache_size++;
- }
}
+/*****************************************************************************
+ Search for an entry to the directory cache.
+ Input: path -
+ name -
+ snum -
+ Output: The dname string of the located entry, or NULL if the entry was
+ not found.
-/*******************************************************************
-check for an entry in the directory cache
-********************************************************************/
-char *DirCacheCheck(char *path,char *name,int snum)
+ Notes: This uses a linear search, which is is okay because of
+ the small size of the cache. Use a splay tree or hash
+ for large caches.
+*****************************************************************************/
+
+char *DirCacheCheck( char *path, char *name, int snum )
{
- struct dir_cache *entry;
+ dir_cache_entry *entry;
- for (entry=dir_cache; entry; entry=entry->next) {
- if (entry->snum == snum &&
- strcmp(path,entry->path) == 0 &&
- strcmp(name,entry->name) == 0) {
- DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
- return(entry->dname);
+ for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
+ NULL != entry;
+ entry = (dir_cache_entry *)ubi_dlNext( entry ) )
+ {
+ if( entry->snum == snum
+ && 0 == strcmp( name, entry->name )
+ && 0 == strcmp( path, entry->path ) )
+ {
+ DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
+ return( entry->dname );
+ }
}
- }
return(NULL);
}
-/*******************************************************************
-flush entries in the dir_cache
-********************************************************************/
+/*****************************************************************************
+ Remove all cache entries which have an snum that matches the input.
+ Input: snum -
+ Output: None.
+*****************************************************************************/
+
void DirCacheFlush(int snum)
{
- struct dir_cache *entry,*next;
-
- for (entry=dir_cache; entry; entry=next) {
- if (entry->snum == snum) {
- free(entry->path);
- free(entry->dname);
- free(entry->name);
- next = entry->next;
- if (entry->prev) entry->prev->next = entry->next;
- if (entry->next) entry->next->prev = entry->prev;
- if (dir_cache == entry) dir_cache = entry->next;
- free(entry);
- } else {
- next = entry->next;
- }
- }
-}
-
-
-#ifdef REPLACE_GETWD
-/* This is getcwd.c from bash. It is needed in Interactive UNIX. To
- * add support for another OS you need to determine which of the
- * conditional compilation macros you need to define. All the options
- * are defined for Interactive UNIX.
- */
-#ifdef ISC
-#define HAVE_UNISTD_H
-#define USGr3
-#define USG
-#endif
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#if defined (__STDC__)
-# define CONST const
-# define PTR void *
-#else /* !__STDC__ */
-# define CONST
-# define PTR char *
-#endif /* !__STDC__ */
-
-#if !defined (PATH_MAX)
-# if defined (MAXPATHLEN)
-# define PATH_MAX MAXPATHLEN
-# else /* !MAXPATHLEN */
-# define PATH_MAX 1024
-# endif /* !MAXPATHLEN */
-#endif /* !PATH_MAX */
-
-#if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
-# if !defined (HAVE_DIRENT)
-# define HAVE_DIRENT
-# endif /* !HAVE_DIRENT */
-#endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
-
-#if defined (HAVE_DIRENT)
-# define D_NAMLEN(d) (strlen ((d)->d_name))
-#else
-# define D_NAMLEN(d) ((d)->d_namlen)
-#endif /* ! (_POSIX_VERSION || USGr3) */
-
-#if defined (USG) || defined (USGr3)
-# define d_fileno d_ino
-#endif
-
-#if !defined (alloca)
-extern char *alloca ();
-#endif /* alloca */
-
-/* Get the pathname of the current working directory,
- and put it in SIZE bytes of BUF. Returns NULL if the
- directory couldn't be determined or SIZE was too small.
- If successful, returns BUF. In GNU, if BUF is NULL,
- an array is allocated with `malloc'; the array is SIZE
- bytes long, unless SIZE <= 0, in which case it is as
- big as necessary. */
-#if defined (__STDC__)
-char *
-getcwd (char *buf, size_t size)
-#else /* !__STDC__ */
-char *
-getcwd (buf, size)
- char *buf;
- int size;
-#endif /* !__STDC__ */
-{
- static CONST char dots[]
- = "../../../../../../../../../../../../../../../../../../../../../../../\
-../../../../../../../../../../../../../../../../../../../../../../../../../../\
-../../../../../../../../../../../../../../../../../../../../../../../../../..";
- CONST char *dotp, *dotlist;
- size_t dotsize;
- dev_t rootdev, thisdev;
- ino_t rootino, thisino;
- char path[PATH_MAX + 1];
- register char *pathp;
- char *pathbuf;
- size_t pathsize;
- struct stat st;
-
- if (buf != NULL && size == 0)
- {
- errno = EINVAL;
- return ((char *)NULL);
- }
-
- pathsize = sizeof (path);
- pathp = &path[pathsize];
- *--pathp = '\0';
- pathbuf = path;
-
- if (stat (".", &st) < 0)
- return ((char *)NULL);
- thisdev = st.st_dev;
- thisino = st.st_ino;
-
- if (stat ("/", &st) < 0)
- return ((char *)NULL);
- rootdev = st.st_dev;
- rootino = st.st_ino;
-
- dotsize = sizeof (dots) - 1;
- dotp = &dots[sizeof (dots)];
- dotlist = dots;
- while (!(thisdev == rootdev && thisino == rootino))
- {
- register DIR *dirstream;
- register struct dirent *d;
- dev_t dotdev;
- ino_t dotino;
- char mount_point;
- int namlen;
-
- /* Look at the parent directory. */
- if (dotp == dotlist)
- {
- /* My, what a deep directory tree you have, Grandma. */
- char *new;
- if (dotlist == dots)
- {
- new = malloc (dotsize * 2 + 1);
- if (new == NULL)
- goto lose;
- memcpy (new, dots, dotsize);
- }
- else
- {
- new = realloc ((PTR) dotlist, dotsize * 2 + 1);
- if (new == NULL)
- goto lose;
- }
- memcpy (&new[dotsize], new, dotsize);
- dotp = &new[dotsize];
- dotsize *= 2;
- new[dotsize] = '\0';
- dotlist = new;
- }
-
- dotp -= 3;
-
- /* Figure out if this directory is a mount point. */
- if (stat (dotp, &st) < 0)
- goto lose;
- dotdev = st.st_dev;
- dotino = st.st_ino;
- mount_point = dotdev != thisdev;
-
- /* Search for the last directory. */
- dirstream = opendir(dotp);
- if (dirstream == NULL)
- goto lose;
- while ((d = (struct dirent *)readdir(dirstream)) != NULL)
- {
- if (d->d_name[0] == '.' &&
- (d->d_name[1] == '\0' ||
- (d->d_name[1] == '.' && d->d_name[2] == '\0')))
- continue;
- if (mount_point || d->d_fileno == thisino)
- {
- char *name;
-
- namlen = D_NAMLEN(d);
- name = (char *)
- alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
- memcpy (name, dotp, dotlist + dotsize - dotp);
- name[dotlist + dotsize - dotp] = '/';
- memcpy (&name[dotlist + dotsize - dotp + 1],
- d->d_name, namlen + 1);
- if (lstat (name, &st) < 0)
- {
- int save = errno;
- closedir(dirstream);
- errno = save;
- goto lose;
- }
- if (st.st_dev == thisdev && st.st_ino == thisino)
- break;
- }
- }
- if (d == NULL)
- {
- int save = errno;
- closedir(dirstream);
- errno = save;
- goto lose;
+ dir_cache_entry *entry;
+ ubi_dlNodePtr next;
+
+ for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
+ NULL != entry; ) {
+ next = ubi_dlNext( entry );
+ if( entry->snum == snum )
+ safe_free( ubi_dlRemThis( dir_cache, entry ) );
+ entry = (dir_cache_entry *)next;
}
- else
- {
- size_t space;
-
- while ((space = pathp - pathbuf) <= namlen)
- {
- char *new;
-
- if (pathbuf == path)
- {
- new = malloc (pathsize * 2);
- if (!new)
- goto lose;
- }
- else
- {
- new = realloc ((PTR) pathbuf, (pathsize * 2));
- if (!new)
- goto lose;
- pathp = new + space;
- }
- (void) memcpy (new + pathsize + space, pathp, pathsize - space);
- pathp = new + pathsize + space;
- pathbuf = new;
- pathsize *= 2;
- }
-
- pathp -= namlen;
- (void) memcpy (pathp, d->d_name, namlen);
- *--pathp = '/';
- closedir(dirstream);
- }
-
- thisdev = dotdev;
- thisino = dotino;
- }
-
- if (pathp == &path[sizeof(path) - 1])
- *--pathp = '/';
-
- if (dotlist != dots)
- free ((PTR) dotlist);
-
- {
- size_t len = pathbuf + pathsize - pathp;
- if (buf == NULL)
- {
- if (len < (size_t) size)
- len = size;
- buf = (char *) malloc (len);
- if (buf == NULL)
- goto lose2;
- }
- else if ((size_t) size < len)
- {
- errno = ERANGE;
- goto lose2;
- }
- (void) memcpy((PTR) buf, (PTR) pathp, len);
- }
-
- if (pathbuf != path)
- free (pathbuf);
-
- return (buf);
-
- lose:
- if ((dotlist != dots) && dotlist)
- {
- int e = errno;
- free ((PTR) dotlist);
- errno = e;
- }
-
- lose2:
- if ((pathbuf != path) && pathbuf)
- {
- int e = errno;
- free ((PTR) pathbuf);
- errno = e;
- }
- return ((char *)NULL);
}
-#endif
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
new file mode 100644
index 00000000000..0f15ef25c24
--- /dev/null
+++ b/source/smbd/dosmode.c
@@ -0,0 +1,336 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ dos mode handling functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ change a dos mode to a unix mode
+ base permission for files:
+ if inheriting
+ apply read/write bits from parent directory.
+ else
+ everybody gets read bit set
+ dos readonly is represented in unix by removing everyone's write bit
+ dos archive is represented in unix by the user's execute bit
+ dos system is represented in unix by the group's execute bit
+ dos hidden is represented in unix by the other's execute bit
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
+ base permission for directories:
+ dos directory is represented in unix by unix's dir bit and the exec bit
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
+****************************************************************************/
+mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
+{
+ mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+ mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
+
+ if ( !IS_DOS_READONLY(dosmode) )
+ result |= (S_IWUSR | S_IWGRP | S_IWOTH);
+
+ if (fname && lp_inherit_perms(SNUM(conn))) {
+ char *dname;
+ SMB_STRUCT_STAT sbuf;
+
+ dname = parent_dirname(fname);
+ DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
+ if (vfs_stat(conn,dname,&sbuf) != 0) {
+ DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
+ return(0); /* *** shouldn't happen! *** */
+ }
+
+ /* Save for later - but explicitly remove setuid bit for safety. */
+ dir_mode = sbuf.st_mode & ~S_ISUID;
+ DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
+ /* Clear "result" */
+ result = 0;
+ }
+
+ if (IS_DOS_DIR(dosmode)) {
+ /* We never make directories read only for the owner as under DOS a user
+ can always create a file in a read-only directory. */
+ result |= (S_IFDIR | S_IWUSR);
+
+ if (dir_mode) {
+ /* Inherit mode of parent directory. */
+ result |= dir_mode;
+ } else {
+ /* Provisionally add all 'x' bits */
+ result |= (S_IXUSR | S_IXGRP | S_IXOTH);
+
+ /* Apply directory mask */
+ result &= lp_dir_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_dir_mode(SNUM(conn));
+ }
+ } else {
+ if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
+ result |= S_IXUSR;
+
+ if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
+ result |= S_IXGRP;
+
+ if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
+ result |= S_IXOTH;
+
+ if (dir_mode) {
+ /* Inherit 666 component of parent directory mode */
+ result |= dir_mode
+ & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+ } else {
+ /* Apply mode mask */
+ result &= lp_create_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_create_mode(SNUM(conn));
+ }
+ }
+
+ DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
+ return(result);
+}
+
+
+/****************************************************************************
+ change a unix mode to a dos mode
+****************************************************************************/
+int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
+{
+ int result = 0;
+
+ DEBUG(8,("dos_mode: %s\n", path));
+
+ if ((sbuf->st_mode & S_IWUSR) == 0)
+ result |= aRONLY;
+
+ if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
+ result |= aARCH;
+
+ if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
+ result |= aSYSTEM;
+
+ if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
+ result |= aHIDDEN;
+
+ if (S_ISDIR(sbuf->st_mode))
+ result = aDIR | (result & aRONLY);
+
+#ifdef S_ISLNK
+#if LINKS_READ_ONLY
+ if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
+ result |= aRONLY;
+#endif
+#endif
+
+ /* hide files with a name starting with a . */
+ if (lp_hide_dot_files(SNUM(conn)))
+ {
+ char *p = strrchr_m(path,'/');
+ if (p)
+ p++;
+ else
+ p = path;
+
+ if (p[0] == '.' && p[1] != '.' && p[1] != 0)
+ result |= aHIDDEN;
+ }
+
+ /* Optimization : Only call is_hidden_path if it's not already
+ hidden. */
+ if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path))
+ {
+ result |= aHIDDEN;
+ }
+
+ DEBUG(8,("dos_mode returning "));
+
+ if (result & aHIDDEN) DEBUG(8, ("h"));
+ if (result & aRONLY ) DEBUG(8, ("r"));
+ if (result & aSYSTEM) DEBUG(8, ("s"));
+ if (result & aDIR ) DEBUG(8, ("d"));
+ if (result & aARCH ) DEBUG(8, ("a"));
+
+ DEBUG(8,("\n"));
+
+ return(result);
+}
+
+/*******************************************************************
+chmod a file - but preserve some bits
+********************************************************************/
+int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st1;
+ int mask=0;
+ mode_t tmp;
+ mode_t unixmode;
+ int ret = -1;
+
+ if (!st) {
+ st = &st1;
+ if (vfs_stat(conn,fname,st))
+ return(-1);
+ }
+
+ if (S_ISDIR(st->st_mode))
+ dosmode |= aDIR;
+
+ if (dos_mode(conn,fname,st) == dosmode)
+ return(0);
+
+ unixmode = unix_mode(conn,dosmode,fname);
+
+ /* preserve the s bits */
+ mask |= (S_ISUID | S_ISGID);
+
+ /* preserve the t bit */
+#ifdef S_ISVTX
+ mask |= S_ISVTX;
+#endif
+
+ /* possibly preserve the x bits */
+ if (!MAP_ARCHIVE(conn))
+ mask |= S_IXUSR;
+ if (!MAP_SYSTEM(conn))
+ mask |= S_IXGRP;
+ if (!MAP_HIDDEN(conn))
+ mask |= S_IXOTH;
+
+ unixmode |= (st->st_mode & mask);
+
+ /* if we previously had any r bits set then leave them alone */
+ if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
+ unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
+ unixmode |= tmp;
+ }
+
+ /* if we previously had any w bits set then leave them alone
+ whilst adding in the new w bits, if the new mode is not rdonly */
+ if (!IS_DOS_READONLY(dosmode)) {
+ unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
+ }
+
+ if ((ret = vfs_chmod(conn,fname,unixmode)) == 0)
+ return 0;
+
+ if((errno != EPERM) && (errno != EACCES))
+ return -1;
+
+ if(!lp_dos_filemode(SNUM(conn)))
+ return -1;
+
+ /* We want DOS semantics, ie allow non owner with write permission to change the
+ bits on a file. Just like file_utime below.
+ */
+
+ /* Check if we have write access. */
+ if (CAN_WRITE(conn)) {
+ /*
+ * We need to open the file with write access whilst
+ * still in our current user context. This ensures we
+ * are not violating security in doing the fchmod.
+ * This file open does *not* break any oplocks we are
+ * holding. We need to review this.... may need to
+ * break batch oplocks open by others. JRA.
+ */
+ files_struct *fsp = open_file_fchmod(conn,fname,st);
+ if (!fsp)
+ return -1;
+ become_root();
+ ret = conn->vfs_ops.fchmod(fsp, fsp->fd, unixmode);
+ unbecome_root();
+ close_file_fchmod(fsp);
+ }
+
+ return( ret );
+}
+
+
+/*******************************************************************
+Wrapper around dos_utime that possibly allows DOS semantics rather
+than POSIX.
+*******************************************************************/
+int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
+{
+ extern struct current_user current_user;
+ SMB_STRUCT_STAT sb;
+ int ret = -1;
+
+ errno = 0;
+
+ if(conn->vfs_ops.utime(conn,fname, times) == 0)
+ return 0;
+
+ if((errno != EPERM) && (errno != EACCES))
+ return -1;
+
+ if(!lp_dos_filetimes(SNUM(conn)))
+ return -1;
+
+ /* We have permission (given by the Samba admin) to
+ break POSIX semantics and allow a user to change
+ the time on a file they don't own but can write to
+ (as DOS does).
+ */
+
+ if(vfs_stat(conn,fname,&sb) != 0)
+ return -1;
+
+ /* Check if we have write access. */
+ if (CAN_WRITE(conn)) {
+ if (((sb.st_mode & S_IWOTH) ||
+ conn->admin_user ||
+ ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
+ ((sb.st_mode & S_IWGRP) &&
+ in_group(sb.st_gid,current_user.gid,
+ current_user.ngroups,current_user.groups)))) {
+ /* We are allowed to become root and change the filetime. */
+ become_root();
+ ret = conn->vfs_ops.utime(conn,fname, times);
+ unbecome_root();
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+Change a filetime - possibly allowing DOS semantics.
+*******************************************************************/
+BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
+{
+ struct utimbuf times;
+
+ if (null_mtime(mtime)) return(True);
+
+ times.modtime = times.actime = mtime;
+
+ if (file_utime(conn, fname, &times)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ return False;
+ }
+
+ return(True);
+}
diff --git a/source/smbd/error.c b/source/smbd/error.c
new file mode 100644
index 00000000000..3c829deb09d
--- /dev/null
+++ b/source/smbd/error.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ error packet handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* these can be set by some functions to override the error codes */
+int unix_ERR_class=SMB_SUCCESS;
+int unix_ERR_code=0;
+
+/****************************************************************************
+ Create an error packet from a cached error.
+****************************************************************************/
+
+int cached_error_packet(char *outbuf,files_struct *fsp,int line,const char *file)
+{
+ write_bmpx_struct *wbmpx = fsp->wbmpx_ptr;
+
+ int32 eclass = wbmpx->wr_errclass;
+ int32 err = wbmpx->wr_error;
+
+ /* We can now delete the auxiliary struct */
+ free((char *)wbmpx);
+ fsp->wbmpx_ptr = NULL;
+ return error_packet(outbuf,NT_STATUS_OK,eclass,err,line,file);
+}
+
+struct
+{
+ int unixerror;
+ int smbclass;
+ int smbcode;
+} unix_smb_errmap[] =
+{
+ {EPERM,ERRDOS,ERRnoaccess},
+ {EACCES,ERRDOS,ERRnoaccess},
+ {ENOENT,ERRDOS,ERRbadfile},
+ {ENOTDIR,ERRDOS,ERRbadpath},
+ {EIO,ERRHRD,ERRgeneral},
+ {EBADF,ERRSRV,ERRsrverror},
+ {EINVAL,ERRSRV,ERRsrverror},
+ {EEXIST,ERRDOS,ERRfilexists},
+ {ENFILE,ERRDOS,ERRnofids},
+ {EMFILE,ERRDOS,ERRnofids},
+ {ENOSPC,ERRHRD,ERRdiskfull},
+#ifdef EDQUOT
+ {EDQUOT,ERRHRD,ERRdiskfull},
+#endif
+#ifdef ENOTEMPTY
+ {ENOTEMPTY,ERRDOS,ERRnoaccess},
+#endif
+#ifdef EXDEV
+ {EXDEV,ERRDOS,ERRdiffdevice},
+#endif
+ {EROFS,ERRHRD,ERRnowrite},
+ {0,0,0}
+};
+
+/****************************************************************************
+ create an error packet from errno
+****************************************************************************/
+int unix_error_packet(char *outbuf,int def_class,uint32 def_code,
+ int line, const char *file)
+{
+ int eclass=def_class;
+ int ecode=def_code;
+ int i=0;
+
+ if (unix_ERR_class != SMB_SUCCESS) {
+ eclass = unix_ERR_class;
+ ecode = unix_ERR_code;
+ unix_ERR_class = SMB_SUCCESS;
+ unix_ERR_code = 0;
+ } else {
+ while (unix_smb_errmap[i].smbclass != 0) {
+ if (unix_smb_errmap[i].unixerror == errno) {
+ eclass = unix_smb_errmap[i].smbclass;
+ ecode = unix_smb_errmap[i].smbcode;
+ break;
+ }
+ i++;
+ }
+ }
+
+ return error_packet(outbuf,NT_STATUS_OK,eclass,ecode,line,file);
+}
+
+
+/****************************************************************************
+ create an error packet. Normally called using the ERROR() macro
+****************************************************************************/
+int error_packet(char *outbuf,NTSTATUS ntstatus,
+ uint8 eclass,uint32 ecode,int line, const char *file)
+{
+ int outsize = set_message(outbuf,0,0,True);
+ extern uint32 global_client_caps;
+
+ if (errno != 0)
+ DEBUG(3,("error string = %s\n",strerror(errno)));
+
+ if (global_client_caps & CAP_STATUS32) {
+ if (NT_STATUS_V(ntstatus) == 0 && eclass) {
+ ntstatus = dos_to_ntstatus(eclass, ecode);
+ }
+ SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus));
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES);
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ get_nt_error_msg(ntstatus)));
+ return outsize;
+ }
+
+ if (eclass == 0 && NT_STATUS_V(ntstatus)) {
+ ntstatus_to_dos(ntstatus, &eclass, &ecode);
+ }
+
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES);
+ SSVAL(outbuf,smb_rcls,eclass);
+ SSVAL(outbuf,smb_err,ecode);
+
+ DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n",
+ file, line,
+ (int)CVAL(outbuf,smb_com),
+ smb_fn_name(CVAL(outbuf,smb_com)),
+ eclass,
+ ecode));
+
+ return outsize;
+}
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
new file mode 100644
index 00000000000..38da96b7410
--- /dev/null
+++ b/source/smbd/fileio.c
@@ -0,0 +1,598 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ read/write to a files_struct
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
+
+/****************************************************************************
+seek a file. Try to avoid the seek if possible
+****************************************************************************/
+
+SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos)
+{
+ SMB_OFF_T offset = 0;
+ SMB_OFF_T seek_ret;
+
+ if (fsp->print_file && lp_postscript(fsp->conn->service))
+ offset = 3;
+
+ seek_ret = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,pos+offset,SEEK_SET);
+
+ /*
+ * We want to maintain the fiction that we can seek
+ * on a fifo for file system purposes. This allows
+ * people to set up UNIX fifo's that feed data to Windows
+ * applications. JRA.
+ */
+
+ if((seek_ret == -1) && (errno == ESPIPE)) {
+ seek_ret = pos+offset;
+ errno = 0;
+ }
+
+ if((seek_ret == -1) || (seek_ret != pos+offset)) {
+ DEBUG(0,("seek_file: sys_lseek failed. Error was %s\n", strerror(errno) ));
+ fsp->pos = -1;
+ return -1;
+ }
+
+ fsp->pos = seek_ret - offset;
+
+ DEBUG(10,("seek_file: requested pos = %.0f, new pos = %.0f\n",
+ (double)(pos+offset), (double)fsp->pos ));
+
+ return(fsp->pos);
+}
+
+/****************************************************************************
+ Read from write cache if we can.
+****************************************************************************/
+
+
+BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
+{
+ write_cache *wcp = fsp->wcp;
+
+ if(!wcp)
+ return False;
+
+ if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size)
+ return False;
+
+ memcpy(data, wcp->data + (pos - wcp->offset), n);
+
+ DO_PROFILE_INC(writecache_read_hits);
+
+ return True;
+}
+
+/****************************************************************************
+read from a file
+****************************************************************************/
+
+ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
+{
+ ssize_t ret=0,readret;
+
+ /* you can't read from print files */
+ if (fsp->print_file)
+ return -1;
+
+ /*
+ * Serve from write cache if we can.
+ */
+
+ if(read_from_write_cache(fsp, data, pos, n))
+ return n;
+
+ flush_write_cache(fsp, READ_FLUSH);
+
+ if (seek_file(fsp,pos) == -1) {
+ DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
+ return(ret);
+ }
+
+ if (n > 0) {
+#ifdef DMF_FIX
+ int numretries = 3;
+tryagain:
+ readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
+ if (readret == -1) {
+ if ((errno == EAGAIN) && numretries) {
+ DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
+ (void)sleep(10);
+ --numretries;
+ goto tryagain;
+ }
+ return -1;
+ }
+#else /* NO DMF fix. */
+ readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
+ if (readret == -1)
+ return -1;
+#endif
+
+ if (readret > 0)
+ ret += readret;
+ }
+
+ return(ret);
+}
+
+/* how many write cache buffers have been allocated */
+static unsigned int allocated_write_caches;
+
+/****************************************************************************
+ *Really* write to a file.
+****************************************************************************/
+
+static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n)
+{
+ if ((pos != -1) && (seek_file(fsp,pos) == -1))
+ return -1;
+
+ return vfs_write_data(fsp,data,n);
+}
+
+/****************************************************************************
+write to a file
+****************************************************************************/
+
+ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
+{
+ write_cache *wcp = fsp->wcp;
+ ssize_t total_written = 0;
+ int write_path = -1;
+
+ if (fsp->print_file) {
+ return print_job_write(fsp->print_jobid, data, n);
+ }
+
+ if (!fsp->can_write) {
+ errno = EPERM;
+ return(0);
+ }
+
+ if (!fsp->modified) {
+ SMB_STRUCT_STAT st;
+ fsp->modified = True;
+
+ if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) {
+ int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
+ if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) {
+ file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
+ }
+
+ /*
+ * If this is the first write and we have an exclusive oplock then setup
+ * the write cache.
+ */
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
+ setup_write_cache(fsp, st.st_size);
+ wcp = fsp->wcp;
+ }
+ }
+ }
+
+#ifdef WITH_PROFILE
+ DO_PROFILE_INC(writecache_total_writes);
+ if (!fsp->oplock_type) {
+ DO_PROFILE_INC(writecache_non_oplock_writes);
+ }
+#endif
+
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ release_level_2_oplocks_on_change(fsp);
+
+#ifdef WITH_PROFILE
+ if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
+ DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
+nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
+ profile_p->writecache_init_writes,
+ profile_p->writecache_abutted_writes,
+ profile_p->writecache_total_writes,
+ profile_p->writecache_non_oplock_writes,
+ profile_p->writecache_allocated_write_caches,
+ profile_p->writecache_num_write_caches,
+ profile_p->writecache_direct_writes,
+ profile_p->writecache_num_perfect_writes,
+ profile_p->writecache_read_hits ));
+
+ DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
+ profile_p->writecache_flushed_writes[SEEK_FLUSH],
+ profile_p->writecache_flushed_writes[READ_FLUSH],
+ profile_p->writecache_flushed_writes[WRITE_FLUSH],
+ profile_p->writecache_flushed_writes[READRAW_FLUSH],
+ profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
+ profile_p->writecache_flushed_writes[CLOSE_FLUSH],
+ profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
+ }
+#endif
+
+ if(!wcp) {
+ DO_PROFILE_INC(writecache_direct_writes);
+ return real_write_file(fsp, data, pos, n);
+ }
+
+ DEBUG(9,("write_file(fd=%d pos=%d size=%d) wofs=%d wsize=%d\n",
+ fsp->fd, (int)pos, (int)n, (int)wcp->offset, (int)wcp->data_size));
+
+ /*
+ * If we have active cache and it isn't contiguous then we flush.
+ * NOTE: There is a small problem with running out of disk ....
+ */
+
+ if (wcp->data_size) {
+
+ BOOL cache_flush_needed = False;
+
+ if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
+
+ /*
+ * Start of write overlaps or abutts the existing data.
+ */
+
+ size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + data_used - wcp->offset;
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used)
+ return n;
+ else
+ cache_flush_needed = True;
+
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 1;
+
+ } else if ((pos < wcp->offset) && (pos + n > wcp->offset) &&
+ (pos + n <= wcp->offset + wcp->alloc_size)) {
+
+ /*
+ * End of write overlaps the existing data.
+ */
+
+ size_t data_used = pos + n - wcp->offset;
+
+ memcpy(wcp->data, data + n - data_used, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + n > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + n - wcp->offset;
+
+ /*
+ * We don't need to move the start of data, but we
+ * cut down the amount left by the amount used.
+ */
+
+ n -= data_used;
+
+ /*
+ * We cannot have used all the data here.
+ */
+
+ cache_flush_needed = True;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 2;
+
+ } else if ( (pos >= wcp->file_size) &&
+ (pos > wcp->offset + wcp->data_size) &&
+ (pos < wcp->offset + wcp->alloc_size) ) {
+
+ /*
+ * Non-contiguous write part of which fits within
+ * the cache buffer and is extending the file.
+ */
+
+ size_t data_used;
+
+ if(pos + n <= wcp->offset + wcp->alloc_size)
+ data_used = n;
+ else
+ data_used = wcp->offset + wcp->alloc_size - pos;
+
+ /*
+ * Fill in the non-continuous area with zeros.
+ */
+
+ memset(wcp->data + wcp->data_size, '\0',
+ pos - (wcp->offset + wcp->data_size) );
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + data_used - wcp->offset;
+
+ /*
+ * Update the known file length.
+ */
+
+ wcp->file_size = wcp->offset + wcp->data_size;
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used)
+ return n;
+ else
+ cache_flush_needed = True;
+
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ DO_PROFILE_INC(writecache_abutted_writes);
+ total_written = data_used;
+
+ write_path = 3;
+
+ } else {
+
+ /*
+ * Write is bigger than buffer, or there is no overlap on the
+ * low or high ends.
+ */
+
+ DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
+len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ /*
+ * Update the file size if needed.
+ */
+
+ if(pos + n > wcp->file_size)
+ wcp->file_size = pos + n;
+
+ /*
+ * If write would fit in the cache, and is larger than
+ * the data already in the cache, flush the cache and
+ * preferentially copy the data new data into it. Otherwise
+ * just write the data directly.
+ */
+
+ if ( n <= wcp->alloc_size && n > wcp->data_size) {
+ cache_flush_needed = True;
+ } else {
+ DO_PROFILE_INC(writecache_direct_writes);
+ return real_write_file(fsp, data, pos, n);
+ }
+
+ write_path = 4;
+
+ }
+
+ if(wcp->data_size > wcp->file_size)
+ wcp->file_size = wcp->data_size;
+
+ if (cache_flush_needed) {
+ DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
+n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
+ write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
+ (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ flush_write_cache(fsp, WRITE_FLUSH);
+ }
+ }
+
+ /*
+ * If the write request is bigger than the cache
+ * size, write it all out.
+ */
+
+ if (n > wcp->alloc_size ) {
+ if(real_write_file(fsp, data, pos, n) == -1)
+ return -1;
+ DO_PROFILE_INC(writecache_direct_writes);
+ return total_written + n;
+ }
+
+ /*
+ * If there's any data left, cache it.
+ */
+
+ if (n) {
+#ifdef WITH_PROFILE
+ if (wcp->data_size) {
+ DO_PROFILE_INC(writecache_abutted_writes);
+ } else {
+ DO_PROFILE_INC(writecache_init_writes);
+ }
+#endif
+ memcpy(wcp->data+wcp->data_size, data, n);
+ if (wcp->data_size == 0) {
+ wcp->offset = pos;
+ DO_PROFILE_INC(writecache_num_write_caches);
+ }
+ wcp->data_size += n;
+ DEBUG(9,("cache return %u\n", (unsigned int)n));
+ total_written += n;
+ return total_written; /* .... that's a write :) */
+ }
+
+ return total_written;
+}
+
+/****************************************************************************
+ Delete the write cache structure.
+****************************************************************************/
+
+void delete_write_cache(files_struct *fsp)
+{
+ write_cache *wcp;
+
+ if(!fsp)
+ return;
+
+ if(!(wcp = fsp->wcp))
+ return;
+
+ DO_PROFILE_DEC(writecache_allocated_write_caches);
+ allocated_write_caches--;
+
+ SMB_ASSERT(wcp->data_size == 0);
+
+ SAFE_FREE(wcp->data);
+ SAFE_FREE(fsp->wcp);
+
+ DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
+
+}
+
+/****************************************************************************
+ Setup the write cache structure.
+****************************************************************************/
+
+static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
+ write_cache *wcp;
+
+ if (allocated_write_caches >= MAX_WRITE_CACHES)
+ return False;
+
+ if(alloc_size == 0 || fsp->wcp)
+ return False;
+
+ if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail.\n"));
+ return False;
+ }
+
+ wcp->file_size = file_size;
+ wcp->offset = 0;
+ wcp->alloc_size = alloc_size;
+ wcp->data_size = 0;
+ if((wcp->data = malloc(wcp->alloc_size)) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
+ (unsigned int)wcp->alloc_size ));
+ SAFE_FREE(wcp);
+ return False;
+ }
+
+ fsp->wcp = wcp;
+ DO_PROFILE_INC(writecache_allocated_write_caches);
+ allocated_write_caches++;
+
+ DEBUG(10,("setup_write_cache: File %s allocated write cache size %u\n",
+ fsp->fsp_name, wcp->alloc_size ));
+
+ return True;
+}
+
+/****************************************************************************
+ Cope with a size change.
+****************************************************************************/
+
+void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ if(fsp->wcp) {
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ fsp->wcp->file_size = file_size;
+ }
+}
+
+/*******************************************************************
+ Flush a write cache struct to disk.
+********************************************************************/
+
+ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
+{
+ write_cache *wcp = fsp->wcp;
+ size_t data_size;
+
+ if(!wcp || !wcp->data_size)
+ return 0;
+
+ data_size = wcp->data_size;
+ wcp->data_size = 0;
+
+ DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
+
+ DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
+ fsp->fd, (double)wcp->offset, (unsigned int)data_size));
+
+#ifdef WITH_PROFILE
+ if(data_size == wcp->alloc_size)
+ DO_PROFILE_INC(writecache_num_perfect_writes);
+#endif
+
+ return real_write_file(fsp, wcp->data, wcp->offset, data_size);
+}
+
+/*******************************************************************
+sync a file
+********************************************************************/
+
+void sync_file(connection_struct *conn, files_struct *fsp)
+{
+ if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) {
+ flush_write_cache(fsp, SYNC_FLUSH);
+ conn->vfs_ops.fsync(fsp,fsp->fd);
+ }
+}
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
new file mode 100644
index 00000000000..f098950c441
--- /dev/null
+++ b/source/smbd/filename.c
@@ -0,0 +1,507 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ filename handling routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1999-200
+ Copyright (C) Ying Chen 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * New hash table stat cache code added by Ying Chen.
+ */
+
+#include "includes.h"
+
+extern BOOL case_sensitive;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
+extern fstring remote_machine;
+extern BOOL use_mangled_map;
+
+static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache);
+
+/****************************************************************************
+ Check if two filenames are equal.
+ This needs to be careful about whether we are case sensitive.
+****************************************************************************/
+static BOOL fname_equal(char *name1, char *name2)
+{
+ int l1 = strlen(name1);
+ int l2 = strlen(name2);
+
+ /* handle filenames ending in a single dot */
+ if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
+ {
+ BOOL ret;
+ name1[l1-1] = 0;
+ ret = fname_equal(name1,name2);
+ name1[l1-1] = '.';
+ return(ret);
+ }
+
+ if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
+ {
+ BOOL ret;
+ name2[l2-1] = 0;
+ ret = fname_equal(name1,name2);
+ name2[l2-1] = '.';
+ return(ret);
+ }
+
+ /* now normal filename handling */
+ if (case_sensitive)
+ return(strcmp(name1,name2) == 0);
+
+ return(strequal(name1,name2));
+}
+
+
+/****************************************************************************
+ Mangle the 2nd name and check if it is then equal to the first name.
+****************************************************************************/
+static BOOL mangled_equal(char *name1, char *name2)
+{
+ char *tmpname;
+ BOOL ret = False;
+
+ if (is_8_3(name2, True))
+ {
+ tmpname = dos_mangle(name2);
+ if(tmpname)
+ ret = strequal(name1,tmpname);
+ SAFE_FREE(tmpname);
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+This routine is called to convert names from the dos namespace to unix
+namespace. It needs to handle any case conversions, mangling, format
+changes etc.
+
+We assume that we have already done a chdir() to the right "root" directory
+for this service.
+
+The function will return False if some part of the name except for the last
+part cannot be resolved
+
+If the saved_last_component != 0, then the unmodified last component
+of the pathname is returned there. This is used in an exceptional
+case in reply_mv (so far). If saved_last_component == 0 then nothing
+is returned there.
+
+The bad_path arg is set to True if the filename walk failed. This is
+used to pick the correct error code to return between ENOENT and ENOTDIR
+as Windows applications depend on ERRbadpath being returned if a component
+of a pathname does not exist.
+
+On exit from unix_convert, if *pst was not null, then the file stat
+struct will be returned if the file exists and was found, if not this
+stat struct will be filled with zeros (and this can be detected by checking
+for nlinks = 0, which can never be true for any file).
+****************************************************************************/
+
+BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
+ BOOL *bad_path, SMB_STRUCT_STAT *pst)
+{
+ SMB_STRUCT_STAT st;
+ char *start, *end;
+ pstring dirpath;
+ pstring orig_path;
+ BOOL component_was_mangled = False;
+ BOOL name_has_wildcard = False;
+
+ ZERO_STRUCTP(pst);
+
+ *dirpath = 0;
+ *bad_path = False;
+ if(saved_last_component)
+ *saved_last_component = 0;
+
+ if (conn->printer) {
+ /* we don't ever use the filenames on a printer share as a
+ filename - so don't convert them */
+ return True;
+ }
+
+ DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
+
+ /*
+ * Convert to basic unix format - removing \ chars and cleaning it up.
+ */
+
+ unix_format(name);
+ unix_clean_name(name);
+
+ /*
+ * Names must be relative to the root of the service - trim any leading /.
+ * also trim trailing /'s.
+ */
+
+ trim_string(name,"/","/");
+
+ /*
+ * If we trimmed down to a single '\0' character
+ * then we should use the "." directory to avoid
+ * searching the cache, but not if we are in a
+ * printing share.
+ */
+
+ if (!*name) {
+ name[0] = '.';
+ name[1] = '\0';
+ }
+
+ /*
+ * Ensure saved_last_component is valid even if file exists.
+ */
+
+ if(saved_last_component) {
+ end = strrchr_m(name, '/');
+ if(end)
+ pstrcpy(saved_last_component, end + 1);
+ else
+ pstrcpy(saved_last_component, name);
+ }
+
+ if (!case_sensitive &&
+ (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
+ strnorm(name);
+
+ /*
+ * If we trimmed down to a single '\0' character
+ * then we will be using the "." directory.
+ * As we know this is valid we can return true here.
+ */
+
+ if(!*name)
+ return(True);
+
+ start = name;
+ while (strncmp(start,"./",2) == 0)
+ start += 2;
+
+ pstrcpy(orig_path, name);
+
+ if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
+ *pst = st;
+ return True;
+ }
+
+ /*
+ * stat the name - if it exists then we are all done!
+ */
+
+ if (vfs_stat(conn,name,&st) == 0) {
+ stat_cache_add(orig_path, name);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ *pst = st;
+ return(True);
+ }
+
+ DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
+ name, dirpath, start));
+
+ /*
+ * A special case - if we don't have any mangling chars and are case
+ * sensitive then searching won't help.
+ */
+
+ if (case_sensitive && !is_mangled(name) &&
+ !lp_strip_dot() && !use_mangled_map)
+ return(False);
+
+ name_has_wildcard = ms_has_wild(start);
+
+ /*
+ * is_mangled() was changed to look at an entire pathname, not
+ * just a component. JRA.
+ */
+
+ if(is_mangled(start))
+ component_was_mangled = True;
+
+ /*
+ * Now we need to recursively match the name against the real
+ * directory structure.
+ */
+
+ /*
+ * Match each part of the path name separately, trying the names
+ * as is first, then trying to scan the directory for matching names.
+ */
+
+ for (; start ; start = (end?end+1:(char *)NULL)) {
+ /*
+ * Pinpoint the end of this section of the filename.
+ */
+ end = strchr_m(start, '/');
+
+ /*
+ * Chop the name at this point.
+ */
+ if (end)
+ *end = 0;
+
+ if(saved_last_component != 0)
+ pstrcpy(saved_last_component, end ? end + 1 : start);
+
+ /*
+ * Check if the name exists up to this point.
+ */
+
+ if (vfs_stat(conn,name, &st) == 0) {
+ /*
+ * It exists. it must either be a directory or this must be
+ * the last part of the path for it to be OK.
+ */
+ if (end && !(st.st_mode & S_IFDIR)) {
+ /*
+ * An intermediate part of the name isn't a directory.
+ */
+ DEBUG(5,("Not a dir %s\n",start));
+ *end = '/';
+ return(False);
+ }
+
+ } else {
+ pstring rest;
+
+ /* Stat failed - ensure we don't use it. */
+ ZERO_STRUCT(st);
+ *rest = 0;
+
+ /*
+ * Remember the rest of the pathname so it can be restored
+ * later.
+ */
+
+ if (end)
+ pstrcpy(rest,end+1);
+
+ /*
+ * Try to find this part of the path in the directory.
+ */
+
+ if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) {
+ if (end) {
+ /*
+ * An intermediate part of the name can't be found.
+ */
+ DEBUG(5,("Intermediate not found %s\n",start));
+ *end = '/';
+
+ /*
+ * We need to return the fact that the intermediate
+ * name resolution failed. This is used to return an
+ * error of ERRbadpath rather than ERRbadfile. Some
+ * Windows applications depend on the difference between
+ * these two errors.
+ */
+ *bad_path = True;
+ return(False);
+ }
+
+ /*
+ * Just the last part of the name doesn't exist.
+ * We may need to strupper() or strlower() it in case
+ * this conversion is being used for file creation
+ * purposes. If the filename is of mixed case then
+ * don't normalise it.
+ */
+
+ if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))
+ strnorm(start);
+
+ /*
+ * check on the mangled stack to see if we can recover the
+ * base of the filename.
+ */
+
+ if (is_mangled(start)) {
+ check_mangled_cache( start );
+ }
+
+ DEBUG(5,("New file %s\n",start));
+ return(True);
+ }
+
+ /*
+ * Restore the rest of the string. If the string was mangled the size
+ * may have changed.
+ */
+ if (end) {
+ end = start + strlen(start);
+ pstrcat(start,"/");
+ pstrcat(start,rest);
+ *end = '\0';
+ }
+ } /* end else */
+
+ /*
+ * Add to the dirpath that we have resolved so far.
+ */
+ if (*dirpath)
+ pstrcat(dirpath,"/");
+
+ pstrcat(dirpath,start);
+
+ /*
+ * Don't cache a name with mangled or wildcard components
+ * as this can change the size.
+ */
+
+ if(!component_was_mangled && !name_has_wildcard)
+ stat_cache_add(orig_path, dirpath);
+
+ /*
+ * Restore the / that we wiped out earlier.
+ */
+ if (end)
+ *end = '/';
+ }
+
+ /*
+ * Don't cache a name with mangled or wildcard components
+ * as this can change the size.
+ */
+
+ if(!component_was_mangled && !name_has_wildcard)
+ stat_cache_add(orig_path, name);
+
+ /*
+ * If we ended up resolving the entire path then return a valid
+ * stat struct if we got one.
+ */
+
+ if (VALID_STAT(st) && (strlen(orig_path) == strlen(name)))
+ *pst = st;
+
+ /*
+ * The name has been resolved.
+ */
+
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ return(True);
+}
+
+
+/****************************************************************************
+check a filename - possibly caling reducename
+
+This is called by every routine before it allows an operation on a filename.
+It does any final confirmation necessary to ensure that the filename is
+a valid one for the user to access.
+****************************************************************************/
+BOOL check_name(char *name,connection_struct *conn)
+{
+ BOOL ret;
+
+ errno = 0;
+
+ if (IS_VETO_PATH(conn, name)) {
+ DEBUG(5,("file path name %s vetoed\n",name));
+ return(0);
+ }
+
+ ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
+
+ /* Check if we are allowing users to follow symlinks */
+ /* Patch from David Clerc <David.Clerc@cui.unige.ch>
+ University of Geneva */
+
+#ifdef S_ISLNK
+ if (!lp_symlinks(SNUM(conn))) {
+ SMB_STRUCT_STAT statbuf;
+ if ( (conn->vfs_ops.lstat(conn,name,&statbuf) != -1) &&
+ (S_ISLNK(statbuf.st_mode)) ) {
+ DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+ ret=0;
+ }
+ }
+#endif
+
+ if (!ret)
+ DEBUG(5,("check_name on %s failed\n",name));
+
+ return(ret);
+}
+
+
+/****************************************************************************
+scan a directory to find a filename, matching without case sensitivity
+
+If the name looks like a mangled name then try via the mangling functions
+****************************************************************************/
+static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
+{
+ void *cur_dir;
+ char *dname;
+ BOOL mangled;
+ pstring name2;
+
+ mangled = is_mangled(name);
+
+ /* handle null paths */
+ if (*path == 0)
+ path = ".";
+
+ if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
+ pstrcpy(name, dname);
+ return(True);
+ }
+
+ /*
+ * The incoming name can be mangled, and if we de-mangle it
+ * here it will not compare correctly against the filename (name2)
+ * read from the directory and then mangled by the name_map_mangle()
+ * call. We need to mangle both names or neither.
+ * (JRA).
+ */
+ if (mangled)
+ mangled = !check_mangled_cache( name );
+
+ /* open the directory */
+ if (!(cur_dir = OpenDir(conn, path, True))) {
+ DEBUG(3,("scan dir didn't open dir [%s]\n",path));
+ return(False);
+ }
+
+ /* now scan for matching names */
+ while ((dname = ReadDirName(cur_dir))) {
+ if (*dname == '.' && (strequal(dname,".") || strequal(dname,"..")))
+ continue;
+
+ pstrcpy(name2,dname);
+ if (!name_map_mangle(name2,False,True,SNUM(conn)))
+ continue;
+
+ if ((mangled && mangled_equal(name,name2)) || fname_equal(name, dname)) {
+ /* we've found the file, change it's name and return */
+ if (docache)
+ DirCacheAdd(path,name,dname,SNUM(conn));
+ pstrcpy(name, dname);
+ CloseDir(cur_dir);
+ return(True);
+ }
+ }
+
+ CloseDir(cur_dir);
+ return(False);
+}
diff --git a/source/smbd/files.c b/source/smbd/files.c
new file mode 100644
index 00000000000..3935a12442b
--- /dev/null
+++ b/source/smbd/files.c
@@ -0,0 +1,401 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Files[] structure handling
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static int real_max_open_files;
+
+#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files))
+
+#define FILE_HANDLE_OFFSET 0x1000
+
+static struct bitmap *file_bmap;
+
+static files_struct *Files;
+
+/* a fsp to use when chaining */
+static files_struct *chain_fsp = NULL;
+/* a fsp to use to save when breaking an oplock. */
+static files_struct *oplock_save_chain_fsp = NULL;
+
+static int files_used;
+
+/****************************************************************************
+ Return a unique number identifying this fsp over the life of this pid.
+****************************************************************************/
+
+static unsigned long get_gen_count(void)
+{
+ static unsigned long file_gen_counter;
+
+ if ((++file_gen_counter) == 0)
+ return ++file_gen_counter;
+ return file_gen_counter;
+}
+
+/****************************************************************************
+ Find first available file slot.
+****************************************************************************/
+
+files_struct *file_new(connection_struct *conn)
+{
+ int i;
+ static int first_file;
+ files_struct *fsp, *next;
+
+ /* we want to give out file handles differently on each new
+ connection because of a common bug in MS clients where they try to
+ reuse a file descriptor from an earlier smb connection. This code
+ increases the chance that the errant client will get an error rather
+ than causing corruption */
+ if (first_file == 0) {
+ first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
+ }
+
+ i = bitmap_find(file_bmap, first_file);
+ if (i == -1) {
+ /*
+ * Before we give up, go through the open files
+ * and see if there are any files opened with a
+ * batch oplock. If so break the oplock and then
+ * re-use that entry (if it becomes closed).
+ * This may help as NT/95 clients tend to keep
+ * files batch oplocked for quite a long time
+ * after they have finished with them.
+ */
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if (attempt_close_oplocked_file(fsp)) {
+ return file_new(conn);
+ }
+ }
+
+ DEBUG(0,("ERROR! Out of file structures\n"));
+ unix_ERR_class = ERRSRV;
+ unix_ERR_code = ERRnofids;
+ return NULL;
+ }
+
+ fsp = (files_struct *)malloc(sizeof(*fsp));
+ if (!fsp) {
+ unix_ERR_class = ERRSRV;
+ unix_ERR_code = ERRnofids;
+ return NULL;
+ }
+
+ ZERO_STRUCTP(fsp);
+ fsp->fd = -1;
+ fsp->conn = conn;
+ fsp->file_id = get_gen_count();
+ GetTimeOfDay(&fsp->open_time);
+
+ first_file = (i+1) % real_max_open_files;
+
+ bitmap_set(file_bmap, i);
+ files_used++;
+
+ fsp->fnum = i + FILE_HANDLE_OFFSET;
+ string_set(&fsp->fsp_name,"");
+
+ DLIST_ADD(Files, fsp);
+
+ DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
+ i, fsp->fnum, files_used));
+
+ chain_fsp = fsp;
+
+ return fsp;
+}
+
+/****************************************************************************
+ Close all open files for a connection.
+****************************************************************************/
+
+void file_close_conn(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next = fsp->next;
+ if (fsp->conn == conn) {
+ close_file(fsp,False);
+ }
+ }
+}
+
+/****************************************************************************
+ Initialise file structures.
+****************************************************************************/
+
+#define MAX_OPEN_FUDGEFACTOR 10
+
+void file_init(void)
+{
+ int request_max_open_files = lp_max_open_files();
+ int real_lim;
+
+ /*
+ * Set the max_open files to be the requested
+ * max plus a fudgefactor to allow for the extra
+ * fd's we need such as log files etc...
+ */
+ real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
+
+ real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
+
+ if(real_max_open_files != request_max_open_files) {
+ DEBUG(1,("file_init: Information only: requested %d \
+open files, %d are available.\n", request_max_open_files, real_max_open_files));
+ }
+
+ file_bmap = bitmap_allocate(real_max_open_files);
+
+ if (!file_bmap) {
+ exit_server("out of memory in file_init");
+ }
+
+ /*
+ * Ensure that pipe_handle_oppset is set correctly.
+ */
+ set_pipe_handle_offset(real_max_open_files);
+}
+
+/****************************************************************************
+ Close files open by a specified vuid.
+****************************************************************************/
+
+void file_close_user(int vuid)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if (fsp->vuid == vuid) {
+ close_file(fsp,False);
+ }
+ }
+}
+
+/****************************************************************************
+ Find a fsp given a file descriptor.
+****************************************************************************/
+
+files_struct *file_find_fd(int fd)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ if (fsp->fd == fd) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find a fsp given a device, inode and file_id.
+****************************************************************************/
+
+files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ if (fsp->fd != -1 &&
+ fsp->dev == dev &&
+ fsp->inode == inode &&
+ fsp->file_id == file_id ) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Check if an fsp still exists.
+****************************************************************************/
+
+files_struct *file_find_fsp(files_struct *orig_fsp)
+{
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if (fsp == orig_fsp)
+ return fsp;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find the first fsp given a device and inode.
+****************************************************************************/
+
+files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if ( fsp->fd != -1 &&
+ fsp->dev == dev &&
+ fsp->inode == inode )
+ return fsp;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find the next fsp having the same device and inode.
+****************************************************************************/
+
+files_struct *file_find_di_next(files_struct *start_fsp)
+{
+ files_struct *fsp;
+
+ for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
+ if ( fsp->fd != -1 &&
+ fsp->dev == start_fsp->dev &&
+ fsp->inode == start_fsp->inode )
+ return fsp;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Find a fsp that is open for printing.
+****************************************************************************/
+
+files_struct *file_find_print(void)
+{
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if (fsp->print_file) return fsp;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Sync open files on a connection.
+****************************************************************************/
+
+void file_sync_all(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if ((conn == fsp->conn) && (fsp->fd != -1)) {
+ sync_file(conn,fsp);
+ }
+ }
+}
+
+/****************************************************************************
+ Free up a fsp.
+****************************************************************************/
+
+void file_free(files_struct *fsp)
+{
+ DLIST_REMOVE(Files, fsp);
+
+ string_free(&fsp->fsp_name);
+
+ bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
+ files_used--;
+
+ DEBUG(5,("freed files structure %d (%d used)\n",
+ fsp->fnum, files_used));
+
+ /* this is paranoia, just in case someone tries to reuse the
+ information */
+ ZERO_STRUCTP(fsp);
+
+ if (fsp == chain_fsp) chain_fsp = NULL;
+
+ SAFE_FREE(fsp);
+}
+
+/****************************************************************************
+ Get a fsp from a packet given the offset of a 16 bit fnum.
+****************************************************************************/
+
+files_struct *file_fsp(char *buf, int where)
+{
+ int fnum, count=0;
+ files_struct *fsp;
+
+ if (chain_fsp)
+ return chain_fsp;
+
+ fnum = SVAL(buf, where);
+
+ for (fsp=Files;fsp;fsp=fsp->next, count++) {
+ if (fsp->fnum == fnum) {
+ chain_fsp = fsp;
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Reset the chained fsp - done at the start of a packet reply.
+****************************************************************************/
+
+void file_chain_reset(void)
+{
+ chain_fsp = NULL;
+}
+
+/****************************************************************************
+Save the chained fsp - done when about to do an oplock break.
+****************************************************************************/
+
+void file_chain_save(void)
+{
+ oplock_save_chain_fsp = chain_fsp;
+}
+
+/****************************************************************************
+Restore the chained fsp - done after an oplock break.
+****************************************************************************/
+
+void file_chain_restore(void)
+{
+ chain_fsp = oplock_save_chain_fsp;
+}
diff --git a/source/smbd/groupname.c b/source/smbd/groupname.c
new file mode 100644
index 00000000000..7d3dce131a4
--- /dev/null
+++ b/source/smbd/groupname.c
@@ -0,0 +1,239 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Groupname handling
+ Copyright (C) Jeremy Allison 1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef USING_GROUPNAME_MAP
+
+#include "includes.h"
+extern DOM_SID global_sam_sid;
+
+/**************************************************************************
+ Groupname map functionality. The code loads a groupname map file and
+ (currently) loads it into a linked list. This is slow and memory
+ hungry, but can be changed into a more efficient storage format
+ if the demands on it become excessive.
+***************************************************************************/
+
+typedef struct groupname_map {
+ ubi_slNode next;
+
+ char *windows_name;
+ DOM_SID windows_sid;
+ char *unix_name;
+ gid_t unix_gid;
+} groupname_map_entry;
+
+static ubi_slList groupname_map_list;
+
+/**************************************************************************
+ Delete all the entries in the groupname map list.
+***************************************************************************/
+
+static void delete_groupname_map_list(void)
+{
+ groupname_map_entry *gmep;
+
+ while((gmep = (groupname_map_entry *)ubi_slRemHead( &groupname_map_list )) != NULL) {
+ SAFE_FREE(gmep->windows_name);
+ SAFE_FREE(gmep->unix_name);
+ SAFE_FREE(gmep);
+ }
+}
+
+/**************************************************************************
+ Load a groupname map file. Sets last accessed timestamp.
+***************************************************************************/
+
+void load_groupname_map(void)
+{
+ static time_t groupmap_file_last_modified = (time_t)0;
+ static BOOL initialized = False;
+ char *groupname_map_file = lp_groupname_map();
+ SMB_STRUCT_STAT st;
+ char **lines;
+ int i;
+ groupname_map_entry *new_ep;
+
+ if(!initialized) {
+ ubi_slInitList( &groupname_map_list );
+ initialized = True;
+ }
+
+ if (!*groupname_map_file)
+ return;
+
+ if(sys_stat(groupname_map_file, &st) != 0) {
+ DEBUG(0, ("load_groupname_map: Unable to stat file %s. Error was %s\n",
+ groupname_map_file, strerror(errno) ));
+ return;
+ }
+
+ /*
+ * Check if file has changed.
+ */
+ if( st.st_mtime <= groupmap_file_last_modified)
+ return;
+
+ groupmap_file_last_modified = st.st_mtime;
+
+ /*
+ * Load the file.
+ */
+
+ lines = file_lines_load(groupname_map_file,NULL,False);
+ if (!lines) {
+ DEBUG(0,("load_groupname_map: can't open groupname map %s. Error was %s\n",
+ groupname_map_file, strerror(errno)));
+ return;
+ }
+ file_lines_slashcont(lines);
+
+ /*
+ * Throw away any previous list.
+ */
+ delete_groupname_map_list();
+
+ DEBUG(4,("load_groupname_map: Scanning groupname map %s\n",groupname_map_file));
+
+ for (i=0; lines[i]; i++) {
+ pstring unixname;
+ pstring windows_name;
+ gid_t gid;
+ DOM_SID tmp_sid;
+ char *s = lines[i];
+
+ DEBUG(10,("load_groupname_map: Read line |%s|\n", s));
+
+ if (!*s || strchr_m("#;",*s))
+ continue;
+
+ if(!next_token(&s,unixname, "\t\n\r=", sizeof(unixname)))
+ continue;
+
+ if(!next_token(&s,windows_name, "\t\n\r=", sizeof(windows_name)))
+ continue;
+
+ trim_string(unixname, " ", " ");
+ trim_string(windows_name, " ", " ");
+
+ if (!*windows_name)
+ continue;
+
+ if(!*unixname)
+ continue;
+
+ DEBUG(5,("load_groupname_map: unixname = %s, windowsname = %s.\n",
+ unixname, windows_name));
+
+ /*
+ * Attempt to get the unix gid_t for this name.
+ */
+
+ if ((gid = nametogid(unixname)) == (gid_t)-1)
+ DEBUG(0,("load_groupname_map: nametogid for group %s failed.\
+Error was %s.\n", unixname, strerror(errno) ));
+ continue;
+ }
+
+ /*
+ * Now map to an NT SID.
+ */
+
+ if(!lookup_wellknown_sid_from_name(windows_name, &tmp_sid)) {
+ /*
+ * It's not a well known name, convert the UNIX gid_t
+ * to a rid within this domain SID.
+ */
+ tmp_sid = global_sam_sid;
+ tmp_sid.sub_auths[tmp_sid.num_auths++] =
+ pdb_gid_to_group_rid(gid);
+ }
+
+ /*
+ * Create the list entry and add it onto the list.
+ */
+
+ if((new_ep = (groupname_map_entry *)malloc( sizeof(groupname_map_entry) ))== NULL) {
+ DEBUG(0,("load_groupname_map: malloc fail for groupname_map_entry.\n"));
+ fclose(fp);
+ return;
+ }
+
+ new_ep->unix_gid = gid;
+ new_ep->windows_sid = tmp_sid;
+ new_ep->windows_name = strdup( windows_name );
+ new_ep->unix_name = strdup( unixname );
+
+ if(new_ep->windows_name == NULL || new_ep->unix_name == NULL) {
+ DEBUG(0,("load_groupname_map: malloc fail for names in groupname_map_entry.\n"));
+ fclose(fp);
+ SAFE_FREE(new_ep->windows_name);
+ SAFE_FREE(new_ep->unix_name);
+ SAFE_FREE(new_ep);
+ file_lines_free(lines);
+ return;
+ }
+ memset((char *)&new_ep->next, '\0', sizeof(new_ep->next) );
+
+ ubi_slAddHead( &groupname_map_list, (ubi_slNode *)new_ep);
+ }
+
+ DEBUG(10,("load_groupname_map: Added %ld entries to groupname map.\n",
+ ubi_slCount(&groupname_map_list)));
+
+ file_lines_free(lines);
+}
+
+/***********************************************************
+ Lookup a SID entry by gid_t.
+************************************************************/
+
+void map_gid_to_sid( gid_t gid, DOM_SID *psid)
+{
+ groupname_map_entry *gmep;
+
+ /*
+ * Initialize and load if not already loaded.
+ */
+ load_groupname_map();
+
+ for( gmep = (groupname_map_entry *)ubi_slFirst( &groupname_map_list);
+ gmep; gmep = (groupname_map_entry *)ubi_slNext( gmep )) {
+
+ if( gmep->unix_gid == gid) {
+ *psid = gmep->windows_sid;
+ DEBUG(7,("map_gid_to_sid: Mapping unix group %s to windows group %s.\n",
+ gmep->unix_name, gmep->windows_name ));
+ return;
+ }
+ }
+
+ /*
+ * If there's no map, convert the UNIX gid_t
+ * to a rid within this domain SID.
+ */
+ *psid = global_sam_sid;
+ psid->sub_auths[psid->num_auths++] = pdb_gid_to_group_rid(gid);
+
+ return;
+}
+#else /* USING_GROUPNAME_MAP */
+ void load_groupname_map(void) {;}
+#endif /* USING_GROUPNAME_MAP */
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 8852e57e8b6..4047ffa8d70 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -2,7 +2,10 @@
Unix SMB/Netbios implementation.
Version 1.9.
Inter-process communication and named pipe handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,2756 +27,493 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
-
-#ifdef CHECK_TYPES
-#undef CHECK_TYPES
-#endif
-#define CHECK_TYPES 0
-extern int DEBUGLEVEL;
-extern int maxxmit;
-extern files_struct Files[];
-extern connection_struct Connections[];
+extern int max_send;
extern fstring local_machine;
-#define NERR_Success 0
-#define NERR_badpass 86
#define NERR_notsupported 50
-#define NERR_BASE (2100)
-#define NERR_BufTooSmall (NERR_BASE+23)
-#define NERR_JobNotFound (NERR_BASE+51)
-#define NERR_DestNotFound (NERR_BASE+52)
-#define ERROR_INVALID_LEVEL 124
-#define ERROR_MORE_DATA 234
-
-#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
-
-#define ACCESS_READ 0x01
-#define ACCESS_WRITE 0x02
-#define ACCESS_CREATE 0x04
-
-#define SHPWLEN 8 /* share password length */
-#define NNLEN 12 /* 8.3 net name length */
-#define SNLEN 15 /* service name length */
-#define QNLEN 12 /* queue name maximum length */
-
-extern int Client;
-
-static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
-{
- pstring buf;
- int l;
-
- if (!src || !dst || !n || !(*dst)) return(0);
-
- StrnCpy(buf,src,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
- standard_sub(cnum,buf);
- StrnCpy(*dst,buf,*n);
- l = strlen(*dst) + 1;
- (*dst) += l;
- (*n) -= l;
- return l;
-}
-
-static int CopyAndAdvance(char** dst, char* src, int* n)
-{
- int l;
- if (!src || !dst || !n || !(*dst)) return(0);
- StrnCpy(*dst,src,*n);
- l = strlen(*dst) + 1;
- (*dst) += l;
- (*n) -= l;
- return l;
-}
-
-static int StrlenExpanded(int cnum, int snum, char* s)
-{
- pstring buf;
- if (!s) return(0);
- StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
- standard_sub(cnum,buf);
- return strlen(buf) + 1;
-}
-
-static char* Expand(int cnum, int snum, char* s)
-{
- static pstring buf;
- if (!s) return(NULL);
- StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
- standard_sub(cnum,buf);
- return &buf[0];
-}
+extern int smb_read_error;
/*******************************************************************
- check a API string for validity when we only need to check the prefix
- ******************************************************************/
-static BOOL prefix_ok(char *str,char *prefix)
-{
- return(strncmp(str,prefix,strlen(prefix)) == 0);
-}
+ copies parameters and data, as needed, into the smb buffer
+ *both* the data and params sections should be aligned. this
+ is fudged in the rpc pipes by
+ at present, only the data section is. this may be a possible
+ cause of some of the ipc problems being experienced. lkcl26dec97
-/****************************************************************************
- send a trans reply
- ****************************************************************************/
-static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
- int ldata,int lparam,int lsetup)
-{
- int i;
- int this_ldata,this_lparam;
- int tot_data=0,tot_param=0;
- int align;
-
- this_lparam = MIN(lparam,maxxmit - (500+lsetup*SIZEOFWORD)); /* hack */
- this_ldata = MIN(ldata,maxxmit - (500+lsetup*SIZEOFWORD+this_lparam));
-
- align = (this_lparam%4);
-
- set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
- if (this_lparam)
- memcpy(smb_buf(outbuf),param,this_lparam);
- if (this_ldata)
- memcpy(smb_buf(outbuf)+this_lparam+align,data,this_ldata);
-
- SSVAL(outbuf,smb_vwv0,lparam);
- SSVAL(outbuf,smb_vwv1,ldata);
- SSVAL(outbuf,smb_vwv3,this_lparam);
- SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
- SSVAL(outbuf,smb_vwv5,0);
- SSVAL(outbuf,smb_vwv6,this_ldata);
- SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
- SSVAL(outbuf,smb_vwv8,0);
- SSVAL(outbuf,smb_vwv9,lsetup);
- for (i=0;i<lsetup;i++)
- SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
-
- show_msg(outbuf);
- send_smb(Client,outbuf);
-
- tot_data = this_ldata;
- tot_param = this_lparam;
-
- while (tot_data < ldata || tot_param < lparam)
- {
- this_lparam = MIN(lparam-tot_param,maxxmit - 500); /* hack */
- this_ldata = MIN(ldata-tot_data,maxxmit - (500+this_lparam));
-
- align = (this_lparam%4);
-
- set_message(outbuf,10,this_ldata+this_lparam+align,False);
- if (this_lparam)
- memcpy(smb_buf(outbuf),param+tot_param,this_lparam);
- if (this_ldata)
- memcpy(smb_buf(outbuf)+this_lparam+align,data+tot_data,this_ldata);
-
- SSVAL(outbuf,smb_vwv3,this_lparam);
- SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
- SSVAL(outbuf,smb_vwv5,tot_param);
- SSVAL(outbuf,smb_vwv6,this_ldata);
- SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
- SSVAL(outbuf,smb_vwv8,tot_data);
- SSVAL(outbuf,smb_vwv9,0);
-
- show_msg(outbuf);
- send_smb(Client,outbuf);
-
- tot_data += this_ldata;
- tot_param += this_lparam;
- }
-}
-
+ ******************************************************************/
-
-/****************************************************************************
- get a print queue
- ****************************************************************************/
-
-struct pack_desc {
- char* format; /* formatstring for structure */
- char* subformat; /* subformat for structure */
- char* base; /* baseaddress of buffer */
- int buflen; /* remaining size for fixed part; on init: length of base */
- int subcount; /* count of substructures */
- char* structbuf; /* pointer into buffer for remaining fixed part */
- int stringlen; /* remaining size for variable part */
- char* stringbuf; /* pointer into buffer for remaining variable part */
- int neededlen; /* total needed size */
- int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
- char* curpos; /* current position; pointer into format or subformat */
- int errcode;
-};
-
-static int get_counter(char** p)
+static void copy_trans_params_and_data(char *outbuf, int align,
+ char *rparam, int param_offset, int param_len,
+ char *rdata, int data_offset, int data_len)
{
- int i, n;
- if (!p || !(*p)) return(1);
- if (!isdigit(**p)) return 1;
- for (n = 0;;) {
- i = **p;
- if (isdigit(i))
- n = 10 * n + (i - '0');
- else
- return n;
- (*p)++;
- }
-}
+ char *copy_into = smb_buf(outbuf)+1;
-static int getlen(char* p)
-{
- int n = 0;
- if (!p) return(0);
- while (*p) {
- switch( *p++ ) {
- case 'W': /* word (2 byte) */
- n += 2;
- break;
- case 'N': /* count of substructures (word) at end */
- n += 2;
- break;
- case 'D': /* double word (4 byte) */
- case 'z': /* offset to zero terminated string (4 byte) */
- case 'l': /* offset to user data (4 byte) */
- n += 4;
- break;
- case 'b': /* offset to data (with counter) (4 byte) */
- n += 4;
- get_counter(&p);
- break;
- case 'B': /* byte (with optional counter) */
- n += get_counter(&p);
- break;
- }
- }
- return n;
-}
+ if(param_len < 0)
+ param_len = 0;
-static BOOL init_package(struct pack_desc* p, int count, int subcount)
-{
- int n = p->buflen;
- int i;
-
- if (!p->format || !p->base) return(False);
-
- i = count * getlen(p->format);
- if (p->subformat) i += subcount * getlen(p->subformat);
- p->structbuf = p->base;
- p->neededlen = 0;
- p->usedlen = 0;
- p->subcount = 0;
- p->curpos = p->format;
- if (i > n) {
- i = n = 0;
- p->errcode = NERR_BufTooSmall;
- }
-
- p->errcode = NERR_Success;
- p->buflen = i;
- n -= i;
- p->stringbuf = p->base + i;
- p->stringlen = n;
- return(p->errcode == NERR_Success);
-}
-
-#ifdef __STDC__
-static int package(struct pack_desc* p, ...)
-{
-#else
-static int package(va_alist)
-va_dcl
-{
- struct pack_desc* p;
-#endif
- va_list args;
- int needed=0, stringneeded;
- char* str=NULL;
- int is_string=0, stringused;
- int32 temp;
-
-#ifdef __STDC__
- va_start(args,p);
-#else
- va_start(args);
- p = va_arg(args,struct pack_desc *);
-#endif
-
- if (!*p->curpos) {
- if (!p->subcount)
- p->curpos = p->format;
- else {
- p->curpos = p->subformat;
- p->subcount--;
- }
- }
-#if CHECK_TYPES
- str = va_arg(args,char*);
- if (strncmp(str,p->curpos,strlen(str)) != 0) {
- DEBUG(2,("type error in package: %s instead of %*s\n",str,
- strlen(str),p->curpos));
- va_end(args);
-#if AJT
- ajt_panic();
-#endif
- return 0;
- }
-#endif
- stringneeded = -1;
-
- if (!p->curpos) return(0);
-
- switch( *p->curpos++ ) {
- case 'W': /* word (2 byte) */
- needed = 2;
- temp = va_arg(args,int);
- if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
- break;
- case 'N': /* count of substructures (word) at end */
- needed = 2;
- p->subcount = va_arg(args,int);
- if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
- break;
- case 'D': /* double word (4 byte) */
- needed = 4;
- temp = va_arg(args,int);
- if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
- break;
- case 'B': /* byte (with optional counter) */
- needed = get_counter(&p->curpos);
- {
- char *s = va_arg(args,char*);
- if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
- }
- break;
- case 'z': /* offset to zero terminated string (4 byte) */
- str = va_arg(args,char*);
- stringneeded = (str ? strlen(str)+1 : 0);
- is_string = 1;
- break;
- case 'l': /* offset to user data (4 byte) */
- str = va_arg(args,char*);
- stringneeded = va_arg(args,int);
- is_string = 0;
- break;
- case 'b': /* offset to data (with counter) (4 byte) */
- str = va_arg(args,char*);
- stringneeded = get_counter(&p->curpos);
- is_string = 0;
- break;
- }
- va_end(args);
- if (stringneeded >= 0) {
- needed = 4;
- if (p->buflen >= needed) {
- stringused = stringneeded;
- if (stringused > p->stringlen) {
- stringused = (is_string ? p->stringlen : 0);
- if (p->errcode == NERR_Success) p->errcode = ERROR_MORE_DATA;
- }
- if (!stringused)
- SIVAL(p->structbuf,0,0);
- else {
- SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
- memcpy(p->stringbuf,str?str:"",stringused);
- if (is_string) p->stringbuf[stringused-1] = '\0';
- p->stringbuf += stringused;
- p->stringlen -= stringused;
- p->usedlen += stringused;
- }
- }
- p->neededlen += stringneeded;
- }
- p->neededlen += needed;
- if (p->buflen >= needed) {
- p->structbuf += needed;
- p->buflen -= needed;
- p->usedlen += needed;
- }
- else {
- if (p->errcode == NERR_Success) p->errcode = NERR_BufTooSmall;
- }
- return 1;
-}
+ if(data_len < 0)
+ data_len = 0;
-#if CHECK_TYPES
-#define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
-#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
-#else
-#define PACK(desc,t,v) package(desc,v)
-#define PACKl(desc,t,v,l) package(desc,v,l)
-#endif
+ DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
+ param_offset, param_offset + param_len,
+ data_offset , data_offset + data_len));
-static void PACKI(struct pack_desc* desc,char *t,int v)
-{
- PACK(desc,t,v);
-}
+ if (param_len)
+ memcpy(copy_into, &rparam[param_offset], param_len);
-static void PACKS(struct pack_desc* desc,char *t,char *v)
-{
- PACK(desc,t,v);
-}
+ copy_into += param_len + align;
-static void PackDriverData(struct pack_desc* desc)
-{
- char drivdata[4+4+32];
- SIVAL(drivdata,0,sizeof drivdata); /* cb */
- SIVAL(drivdata,4,1000); /* lVersion */
- memset(drivdata+8,0,32); /* szDeviceName */
- strcpy(drivdata+8,"NULL");
- PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
+ if (data_len )
+ memcpy(copy_into, &rdata[data_offset], data_len);
}
-static int check_printq_info(struct pack_desc* desc,
- int uLevel, const char* id1, const char* id2)
-{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0:
- desc->format = "B13";
- break;
- case 1:
- desc->format = "B13BWWWzzzzzWW";
- break;
- case 2:
- desc->format = "B13BWWWzzzzzWN";
- desc->subformat = "WB21BB16B10zWWzDDz";
- break;
- case 3:
- desc->format = "zWWWWzzzzWWzzl";
- break;
- case 4:
- desc->format = "zWWWWzzzzWNzzl";
- desc->subformat = "WWzWWDDzz";
- break;
- case 5:
- desc->format = "z";
- break;
- default: return False;
- }
- if (strcmp(desc->format,id1) != 0) return False;
- if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
- return True;
-}
-
-static void fill_printjob_info(int cnum, int snum, int uLevel,
- struct pack_desc* desc,
- print_queue_struct* queue, int n)
-{
- time_t t = queue->time;
-
- /* the client expects localtime */
- t += GMT_TO_LOCAL*TimeDiff(t);
-
- PACKI(desc,"W",((snum%0xFF)<<8) | (queue->job%0xFF)); /* uJobId */
- if (uLevel == 1) {
- PACKS(desc,"B21",queue->user); /* szUserName */
- PACKS(desc,"B",""); /* pad */
- PACKS(desc,"B16",""); /* szNotifyName */
- PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
- PACKS(desc,"z",""); /* pszParms */
- PACKI(desc,"W",n+1); /* uPosition */
- PACKI(desc,"W",queue->status); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKI(desc,"D",queue->time); /* ulSubmitted */
- PACKI(desc,"D",queue->size); /* ulSize */
- PACKS(desc,"z",queue->file); /* pszComment */
- }
- if (uLevel == 2 || uLevel == 3) {
- PACKI(desc,"W",queue->priority); /* uPriority */
- PACKS(desc,"z",queue->user); /* pszUserName */
- PACKI(desc,"W",n+1); /* uPosition */
- PACKI(desc,"W",queue->status); /* fsStatus */
- PACKI(desc,"D",queue->time); /* ulSubmitted */
- PACKI(desc,"D",queue->size); /* ulSize */
- PACKS(desc,"z","Samba"); /* pszComment */
- PACKS(desc,"z",queue->file); /* pszDocument */
- if (uLevel == 3) {
- PACKS(desc,"z",""); /* pszNotifyName */
- PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
- PACKS(desc,"z",""); /* pszParms */
- PACKS(desc,"z",""); /* pszStatus */
- PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
- PACKS(desc,"z","lpd"); /* pszQProcName */
- PACKS(desc,"z",""); /* pszQProcParms */
- PACKS(desc,"z","NULL"); /* pszDriverName */
- PackDriverData(desc); /* pDriverData */
- PACKS(desc,"z",""); /* pszPrinterName */
- }
- }
-}
-
-static void fill_printq_info(int cnum, int snum, int uLevel,
- struct pack_desc* desc,
- int count, print_queue_struct* queue,
- print_status_struct* status)
-{
- if (uLevel < 3) {
- PACKS(desc,"B13",SERVICE(snum));
- } else {
- PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum)));
- }
- if (uLevel == 1 || uLevel == 2) {
- PACKS(desc,"B",""); /* alignment */
- PACKI(desc,"W",5); /* priority */
- PACKI(desc,"W",0); /* start time */
- PACKI(desc,"W",0); /* until time */
- PACKS(desc,"z",""); /* pSepFile */
- PACKS(desc,"z","lpd"); /* pPrProc */
- PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
- PACKS(desc,"z",""); /* pParms */
- if (snum < 0) {
- PACKS(desc,"z","UNKNOWN PRINTER");
- PACKI(desc,"W",LPSTAT_ERROR);
- }
- else if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum)));
- PACKI(desc,"W",LPSTAT_OK); /* status */
- } else {
- PACKS(desc,"z",status->message);
- PACKI(desc,"W",status->status); /* status */
- }
- PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
- }
- if (uLevel == 3 || uLevel == 4) {
- PACKI(desc,"W",5); /* uPriority */
- PACKI(desc,"W",0); /* uStarttime */
- PACKI(desc,"W",0); /* uUntiltime */
- PACKI(desc,"W",5); /* pad1 */
- PACKS(desc,"z",""); /* pszSepFile */
- PACKS(desc,"z","lpd"); /* pszPrProc */
- PACKS(desc,"z",""); /* pszParms */
- if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
- PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
- } else {
- PACKS(desc,"z",status->message); /* pszComment */
- PACKI(desc,"W",status->status); /* fsStatus */
- }
- PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
- PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
- PACKS(desc,"z","NULL"); /* pszDriverName */
- PackDriverData(desc); /* pDriverData */
- }
- if (uLevel == 2 || uLevel == 4) {
- int i;
- for (i=0;i<count;i++)
- fill_printjob_info(cnum,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
- }
-
- DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",SERVICE(snum),count));
-}
-
-static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char *QueueName = p;
- int uLevel,cbBuf;
- int count=0;
- int snum;
- char* str3;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
-
- bzero(&status,sizeof(status));
- bzero(&desc,sizeof(desc));
-
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
- str3 = p + 4;
-
- if ((p = strchr(QueueName,'%'))) *p = 0;
-
- DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"zWrLh")) return False;
- if (!check_printq_info(&desc,uLevel,str2,str3)) return False;
-
- snum = lp_servicenumber(QueueName);
- if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(QueueName,pnum);
- snum = lp_servicenumber(QueueName);
- }
- }
-
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
-
- count = get_printqueue(snum,cnum,&queue,&status);
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,count)) {
- desc.subcount = count;
- fill_printq_info(cnum,snum,uLevel,&desc,count,queue,&status);
- }
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
-
- if (queue) free(queue);
-
- return(True);
-}
-
-
/****************************************************************************
- view list of all print jobs on all queues
- ****************************************************************************/
-static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
- int mdrcnt, int mprcnt,
- char **rdata, char** rparam,
- int *rdata_len, int *rparam_len)
-{
- char *param_format = param+2;
- char *output_format1 = skip_string(param_format,1);
- char *p = skip_string(output_format1,1);
- int uLevel = SVAL(p,0);
- char *output_format2 = p + 4;
- int services = lp_numservices();
- int i, n;
- struct pack_desc desc;
- print_queue_struct **queue = NULL;
- print_status_struct *status = NULL;
- int* subcntarr = NULL;
- int queuecnt, subcnt=0, succnt=0;
-
- bzero(&desc,sizeof(desc));
-
- DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
-
- if (prefix_ok(param_format,"WrLeh")) return False;
- if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
- return False;
- queuecnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
- queuecnt++;
- if (uLevel > 0) {
- queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*));
- memset(queue,0,queuecnt*sizeof(print_queue_struct*));
- status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct));
- memset(status,0,queuecnt*sizeof(print_status_struct));
- subcntarr = (int*)malloc(queuecnt*sizeof(int));
- subcnt = 0;
- n = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- subcntarr[n] = get_printqueue(i,cnum,&queue[n],&status[n]);
- subcnt += subcntarr[n];
- n++;
- }
- }
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
-
- if (init_package(&desc,queuecnt,subcnt)) {
- n = 0;
- succnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- fill_printq_info(cnum,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
- n++;
- if (desc.errcode == NERR_Success) succnt = n;
- }
- }
-
- if (subcntarr) free(subcntarr);
-
- *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,queuecnt);
-
- for (i = 0; i < queuecnt; i++) {
- if (queue && queue[i]) free(queue[i]);
- }
-
- if (queue) free(queue);
- if (status) free(status);
-
- return True;
-}
+ Send a trans reply.
+ ****************************************************************************/
-/****************************************************************************
- get info level for a server list query
- ****************************************************************************/
-static BOOL check_server_info(int uLevel, char* id)
+void send_trans_reply(char *outbuf,
+ char *rparam, int rparam_len,
+ char *rdata, int rdata_len,
+ BOOL buffer_too_large)
{
- switch( uLevel ) {
- case 0:
- if (strcmp(id,"B16") != 0) return False;
- break;
- case 1:
- if (strcmp(id,"B16BBDz") != 0) return False;
- break;
- default:
- return False;
- }
- return True;
-}
+ int this_ldata,this_lparam;
+ int tot_data_sent = 0;
+ int tot_param_sent = 0;
+ int align;
-/* used for server information: client, nameserv and ipc */
-struct srv_info_struct
-{
- fstring name;
- uint32 type;
- fstring comment;
- fstring domain; /* used ONLY in ipc.c NOT namework.c */
- BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
-};
+ int ldata = rdata ? rdata_len : 0;
+ int lparam = rparam ? rparam_len : 0;
-/*******************************************************************
- filter out unwanted server info
- ******************************************************************/
-static BOOL filter_server_info(struct srv_info_struct *server,
- char *domain)
-{
- if (*domain)
- return(strequal(domain, server->domain));
-
- return (True); /* be indiscriminate: get all servers! */
-}
+ if (buffer_too_large)
+ DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
-/*******************************************************************
- find server in the files saved by nmbd. Return True if we find it.
- ******************************************************************/
-static BOOL find_server(struct srv_info_struct *servers, int num_servers,
- char *domain, char *name)
-{
- int count;
+ this_lparam = MIN(lparam,max_send - 500); /* hack */
+ this_ldata = MIN(ldata,max_send - (500+this_lparam));
- if (!servers || num_servers == 0) return (False);
+ align = ((this_lparam)%4);
- for (count = 0; count < num_servers; count++) {
- struct srv_info_struct *s;
+ if (buffer_too_large) {
+ ERROR_NT(STATUS_BUFFER_OVERFLOW);
+ }
- s = &servers[count];
+ set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
- if (strequal(name, s->name)) {
- StrnCpy(domain, s->domain, sizeof(pstring)-1);
- return (True);
- }
- }
- return (False);
-}
+ copy_trans_params_and_data(outbuf, align,
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, this_ldata);
+ SSVAL(outbuf,smb_vwv0,lparam);
+ SSVAL(outbuf,smb_vwv1,ldata);
+ SSVAL(outbuf,smb_vwv3,this_lparam);
+ SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
+ SSVAL(outbuf,smb_vwv5,0);
+ SSVAL(outbuf,smb_vwv6,this_ldata);
+ SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
+ SSVAL(outbuf,smb_vwv8,0);
+ SSVAL(outbuf,smb_vwv9,0);
-/*******************************************************************
- get server info lists from the files saved by nmbd. Return the
- number of entries
- ******************************************************************/
-static int get_server_info(uint32 servertype,
- struct srv_info_struct **servers)
-{
- FILE *f;
- pstring fname;
- int count=0;
- int alloced=0;
- pstring line;
-
- strcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
-
- f = fopen(fname,"r");
-
- if (!f) {
- DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
- return(0);
- }
- if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
-
- while (!feof(f))
- {
- fstring stype;
- struct srv_info_struct *s;
- char *ptr = line;
- *ptr = 0;
-
- fgets(line,sizeof(line)-1,f);
- if (!*line) continue;
-
- if (count == alloced) {
- alloced += 10;
- (*servers) = (struct srv_info_struct *)
- Realloc(*servers,sizeof(**servers)*alloced);
- if (!(*servers)) return(0);
- bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
- }
- s = &(*servers)[count];
-
- s->server_added = True;
-
- if (!next_token(&ptr,s->name , NULL)) continue;
- if (!next_token(&ptr,stype , NULL)) continue;
- if (!next_token(&ptr,s->comment, NULL)) continue;
- if (!next_token(&ptr,s->domain , NULL)) {
- /* this allows us to cop with an old nmbd */
- strcpy(s->domain,my_workgroup());
- }
-
- if (sscanf(stype,"%X",&s->type) != 1) continue;
-
- /* doesn't match up: don't want it */
- if (!(servertype & s->type)) continue;
-
- /* server entry is a domain, we haven't asked for domains: don't want it */
- if ((s->type&SV_TYPE_DOMAIN_ENUM) && !(servertype&SV_TYPE_DOMAIN_ENUM))
- continue;
-
- DEBUG(4,("Server %20s %8x %25s %15s\n",
- s->name, stype, s->comment, s->domain));
-
- count++;
- }
-
- fclose(f);
- return(count);
-}
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans_reply: send_smb failed.");
-/*******************************************************************
- fill in a server info structure
- ******************************************************************/
-static int fill_srv_info(struct srv_info_struct *service,
- int uLevel, char **buf, int *buflen,
- char **stringbuf, int *stringspace, char *baseaddr)
-{
- int struct_len;
- char* p;
- char* p2;
- int l2;
- int len;
-
- switch (uLevel) {
- case 0: struct_len = 16; break;
- case 1: struct_len = 26; break;
- default: return -1;
- }
-
- if (!buf)
- {
- len = 0;
- switch (uLevel)
- {
- case 1:
- len = strlen(service->comment)+1;
- break;
- }
-
- if (buflen) *buflen = struct_len;
- if (stringspace) *stringspace = len;
- return struct_len + len;
- }
-
- len = struct_len;
- p = *buf;
- if (*buflen < struct_len) return -1;
- if (stringbuf)
- {
- p2 = *stringbuf;
- l2 = *stringspace;
- }
- else
- {
- p2 = p + struct_len;
- l2 = *buflen - struct_len;
- }
- if (!baseaddr) baseaddr = p;
-
- switch (uLevel)
- {
- case 0:
- StrnCpy(p,service->name,15);
- break;
-
- case 1:
- StrnCpy(p,service->name,15);
- SIVAL(p,18,service->type);
- SIVAL(p,22,PTR_DIFF(p2,baseaddr));
- len += CopyAndAdvance(&p2,service->comment,&l2);
- break;
- }
-
- if (stringbuf)
- {
- *buf = p + struct_len;
- *buflen -= struct_len;
- *stringbuf = p2;
- *stringspace = l2;
- }
- else
- {
- *buf = p2;
- *buflen -= len;
- }
- return len;
-}
+ tot_data_sent = this_ldata;
+ tot_param_sent = this_lparam;
-
-/****************************************************************************
- view list of servers available (or possibly domains). The info is
- extracted from lists saved by nmbd on the local host
- ****************************************************************************/
-static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
- int mdrcnt, int mprcnt, char **rdata,
- char **rparam, int *rdata_len, int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- int buf_len = SVAL(p,2);
- uint32 servertype = IVAL(p,4);
- char *p2;
- int data_len, fixed_len, string_len;
- int f_len, s_len;
- struct srv_info_struct *servers=NULL;
- int counted=0,total=0;
- int i;
- fstring domain;
- BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) &&
- !(servertype == SV_TYPE_ALL);
-
- domain[0] = 0;
- p += 8;
-
- if (!prefix_ok(str1,"WrLehD")) return False;
- if (!check_server_info(uLevel,str2)) return False;
-
- DEBUG(4, ("server request level: %s\n", str2));
-
- if (strcmp(str1, "WrLehDO") == 0)
- {
- /* asking for servers. we will have to work out which workgroup was
- requested, as we maintain lists for multiple workgroups */
- }
- else if (strcmp(str1, "WrLehDz") == 0)
- {
- /* asking for a specific workgroup */
- StrnCpy(domain, p, sizeof(fstring)-1);
- }
-
- if (lp_browse_list())
- {
- total = get_server_info(servertype,&servers);
- }
-
- if (!domain[0] && !domain_request) {
- extern fstring remote_machine;
- /* must be a server request with an assumed domain. find a domain */
-
- if (find_server(servers, total, domain, remote_machine)) {
- DEBUG(4, ("No domain specified: using %s for %s\n",
- domain, remote_machine));
- } else {
- /* default to soemthing sensible */
- strcpy(domain,my_workgroup());
- }
- }
-
- data_len = fixed_len = string_len = 0;
-
- for (i=0;i<total;i++)
- if (filter_server_info(&servers[i],domain)) {
- data_len += fill_srv_info(&servers[i],uLevel,0,&f_len,0,&s_len,0);
- if (data_len <= buf_len)
+ while (tot_data_sent < ldata || tot_param_sent < lparam)
{
- counted++;
- fixed_len += f_len;
- string_len += s_len;
- }
- }
+ this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
+ this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
- *rdata_len = fixed_len + string_len;
- *rdata = REALLOC(*rdata,*rdata_len);
- bzero(*rdata,*rdata_len);
-
- p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
- p = *rdata;
- f_len = fixed_len;
- s_len = string_len;
-
- {
- int count2 = counted;
- for (i = 0; i < total && count2;i++) {
- if (filter_server_info(&servers[i],domain)) {
- fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata);
- count2--;
- }
- }
- }
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,total);
+ if(this_lparam < 0)
+ this_lparam = 0;
- if (servers) free(servers);
+ if(this_ldata < 0)
+ this_ldata = 0;
- DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
- domain,uLevel,counted,total));
-
- return(True);
-}
+ align = (this_lparam%4);
+ set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
-/****************************************************************************
- get info about a share
- ****************************************************************************/
-static BOOL check_share_info(int uLevel, char* id)
-{
- switch( uLevel ) {
- case 0:
- if (strcmp(id,"B13") != 0) return False;
- break;
- case 1:
- if (strcmp(id,"B13BWz") != 0) return False;
- break;
- case 2:
- if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
- break;
- case 91:
- if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
- break;
- default: return False;
- }
- return True;
-}
+ copy_trans_params_and_data(outbuf, align,
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, this_ldata);
-static int fill_share_info(int cnum, int snum, int uLevel,
- char** buf, int* buflen,
- char** stringbuf, int* stringspace, char* baseaddr)
-{
- int struct_len;
- char* p;
- char* p2;
- int l2;
- int len;
-
- switch( uLevel ) {
- case 0: struct_len = 13; break;
- case 1: struct_len = 20; break;
- case 2: struct_len = 40; break;
- case 91: struct_len = 68; break;
- default: return -1;
- }
-
-
- if (!buf)
- {
- len = 0;
- if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum));
- if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
- if (buflen) *buflen = struct_len;
- if (stringspace) *stringspace = len;
- return struct_len + len;
- }
-
- len = struct_len;
- p = *buf;
- if ((*buflen) < struct_len) return -1;
- if (stringbuf)
- {
- p2 = *stringbuf;
- l2 = *stringspace;
- }
- else
- {
- p2 = p + struct_len;
- l2 = (*buflen) - struct_len;
- }
- if (!baseaddr) baseaddr = p;
-
- StrnCpy(p,lp_servicename(snum),13);
-
- if (uLevel > 0)
- {
- int type;
- CVAL(p,13) = 0;
- type = STYPE_DISKTREE;
- if (lp_print_ok(snum)) type = STYPE_PRINTQ;
- if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
- SSVAL(p,14,type); /* device type */
- SIVAL(p,16,PTR_DIFF(p2,baseaddr));
- len += CopyExpanded(cnum,snum,&p2,lp_comment(snum),&l2);
- }
-
- if (uLevel > 1)
- {
- SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
- SSVALS(p,22,-1); /* max uses */
- SSVAL(p,24,1); /* current uses */
- SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
- len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
- memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
- }
-
- if (uLevel > 2)
- {
- memset(p+40,0,SHPWLEN+2);
- SSVAL(p,50,0);
- SIVAL(p,52,0);
- SSVAL(p,56,0);
- SSVAL(p,58,0);
- SIVAL(p,60,0);
- SSVAL(p,64,0);
- SSVAL(p,66,0);
- }
-
- if (stringbuf)
- {
- (*buf) = p + struct_len;
- (*buflen) -= struct_len;
- (*stringbuf) = p2;
- (*stringspace) = l2;
- }
- else
- {
- (*buf) = p2;
- (*buflen) -= len;
- }
- return len;
-}
+ SSVAL(outbuf,smb_vwv3,this_lparam);
+ SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
+ SSVAL(outbuf,smb_vwv5,tot_param_sent);
+ SSVAL(outbuf,smb_vwv6,this_ldata);
+ SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
+ SSVAL(outbuf,smb_vwv8,tot_data_sent);
+ SSVAL(outbuf,smb_vwv9,0);
-static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *netname = skip_string(str2,1);
- char *p = skip_string(netname,1);
- int uLevel = SVAL(p,0);
- int snum = find_service(netname);
-
- if (snum < 0) return False;
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"zWrLh")) return False;
- if (!check_share_info(uLevel,str2)) return False;
-
- *rdata = REALLOC(*rdata,mdrcnt);
- p = *rdata;
- *rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0);
- if (*rdata_len < 0) return False;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,*rdata_len);
-
- return(True);
-}
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans_reply: send_smb failed.");
-/****************************************************************************
- view list of shares available
- ****************************************************************************/
-static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- int buf_len = SVAL(p,2);
- char *p2;
- int count=lp_numservices();
- int total=0,counted=0;
- int i;
- int data_len, fixed_len, string_len;
- int f_len, s_len;
-
- if (!prefix_ok(str1,"WrLeh")) return False;
- if (!check_share_info(uLevel,str2)) return False;
-
- data_len = fixed_len = string_len = 0;
- for (i=0;i<count;i++)
- if (lp_browseable(i) && lp_snum_ok(i))
- {
- total++;
- data_len += fill_share_info(cnum,i,uLevel,0,&f_len,0,&s_len,0);
- if (data_len <= buf_len)
- {
- counted++;
- fixed_len += f_len;
- string_len += s_len;
- }
- }
- *rdata_len = fixed_len + string_len;
- *rdata = REALLOC(*rdata,*rdata_len);
- memset(*rdata,0,*rdata_len);
-
- p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
- p = *rdata;
- f_len = fixed_len;
- s_len = string_len;
- for (i = 0; i < count;i++)
- if (lp_browseable(i) && lp_snum_ok(i))
- if (fill_share_info(cnum,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
- break;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,total);
-
- DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
- counted,total,uLevel,
- buf_len,*rdata_len,mdrcnt));
- return(True);
+ tot_data_sent += this_ldata;
+ tot_param_sent += this_lparam;
+ }
}
-
-
/****************************************************************************
- get the time of day info
- ****************************************************************************/
-static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *p;
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 21;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
-
- p = *rdata;
-
- {
- struct tm *t;
- time_t unixdate = time(NULL);
-
- put_dos_date3(p,0,unixdate); /* this is the time that is looked at
- by NT in a "net time" operation,
- it seems to ignore the one below */
-
- /* the client expects to get localtime, not GMT, in this bit
- (I think, this needs testing) */
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
-
- SIVAL(p,4,0); /* msecs ? */
- CVAL(p,8) = t->tm_hour;
- CVAL(p,9) = t->tm_min;
- CVAL(p,10) = t->tm_sec;
- CVAL(p,11) = 0; /* hundredths of seconds */
- SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
- SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
- CVAL(p,16) = t->tm_mday;
- CVAL(p,17) = t->tm_mon + 1;
- SSVAL(p,18,1900+t->tm_year);
- CVAL(p,20) = t->tm_wday;
- }
-
-
- return(True);
-}
+ Start the first part of an RPC reply which began with an SMBtrans request.
+****************************************************************************/
-/****************************************************************************
- set the user password
- ****************************************************************************/
-static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
{
- char *p = skip_string(param+2,2);
- fstring user;
- fstring pass1,pass2;
-
- strcpy(user,p);
+ char *rdata = malloc(p->max_trans_reply);
+ int data_len;
- p = skip_string(p,1);
-
- StrnCpy(pass1,p,16);
- StrnCpy(pass2,p+16,16);
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ if(rdata == NULL) {
+ DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+ return False;
+ }
- DEBUG(3,("Set password for <%s>\n",user));
+ if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
+ SAFE_FREE(rdata);
+ return False;
+ }
- if (!password_ok(user,pass1,strlen(pass1),NULL,False) ||
- !chgpasswd(user,pass1,pass2))
- SSVAL(*rparam,0,NERR_badpass);
+ send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
- bzero(pass1,sizeof(fstring));
- bzero(pass2,sizeof(fstring));
-
- return(True);
+ SAFE_FREE(rdata);
+ return True;
}
/****************************************************************************
- delete a print job
- Form: <W> <>
- ****************************************************************************/
-static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- int function = SVAL(param,0);
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
- by the print queue api */
- int snum = (SVAL(p,0)>>8);
- int i, count;
-
-
- /* check it's a supported varient */
- if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
- return(False);
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_Success);
-
- if (snum >= 0 && VALID_SNUM(snum))
- {
- print_queue_struct *queue=NULL;
- lpq_reset(snum);
- count = get_printqueue(snum,cnum,&queue,NULL);
-
- for (i=0;i<count;i++)
- if ((queue[i].job%0xFF) == jobid)
- {
- switch (function) {
- case 81: /* delete */
- DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
- del_printqueue(cnum,snum,queue[i].job);
- break;
- case 82: /* pause */
- case 83: /* resume */
- DEBUG(3,("%s queue entry %d\n",
- (function==82?"pausing":"resuming"),queue[i].job));
- status_printjob(cnum,snum,queue[i].job,
- (function==82?LPQ_PAUSED:LPQ_QUEUED));
- break;
- }
- break;
- }
-
- if (i==count)
- SSVAL(*rparam,0,NERR_JobNotFound);
-
- if (queue) free(queue);
- }
-
- SSVAL(*rparam,2,0); /* converter word */
-
- return(True);
-}
+ WaitNamedPipeHandleState
+****************************************************************************/
-static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *QueueName = skip_string(str2,1);
- int snum;
-
- /* check it's a supported varient */
- if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
- return(False);
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
-
- snum = lp_servicenumber(QueueName);
- if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(QueueName,pnum);
- snum = lp_servicenumber(QueueName);
- }
- }
-
- if (snum >= 0 && VALID_SNUM(snum)) {
- print_queue_struct *queue=NULL;
- int i, count;
- lpq_reset(snum);
-
- count = get_printqueue(snum,cnum,&queue,NULL);
- for (i = 0; i < count; i++)
- del_printqueue(cnum,snum,queue[i].job);
-
- if (queue) free(queue);
- }
-
- DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
-
- return(True);
-}
+ uint16 priority;
+ if (!param || param_len < 2)
+ return False;
-/****************************************************************************
- set the property of a print job (undocumented?)
- ? function = 0xb -> set name of print job
- ? function = 0x6 -> move print job up/down
- Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
- or <WWsTP> <WB21BB16B10zWWzDDz>
-****************************************************************************/
-static int check_printjob_info(struct pack_desc* desc,
- int uLevel, char* id)
-{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0: desc->format = "W"; break;
- case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
- case 2: desc->format = "WWzWWDDzz"; break;
- case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
- default: return False;
- }
- if (strcmp(desc->format,id) != 0) return False;
- return True;
-}
+ priority = SVAL(param,0);
+ DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
-static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- struct pack_desc desc;
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
- by the print queue api */
- int snum = (SVAL(p,0)>>8);
- int uLevel = SVAL(p,2);
- int function = SVAL(p,4); /* what is this ?? */
- int i;
- char *s = data;
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- /* check it's a supported varient */
- if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
- return(False);
-
- switch (function) {
- case 0x6: /* change job place in the queue, data gives the new place */
- if (snum >= 0 && VALID_SNUM(snum))
- {
- print_queue_struct *queue=NULL;
- int count;
-
- lpq_reset(snum);
- count = get_printqueue(snum,cnum,&queue,NULL);
- for (i=0;i<count;i++) /* find job */
- if ((queue[i].job%0xFF) == jobid) break;
-
- if (i==count) {
- desc.errcode=NERR_JobNotFound;
- if (queue) free(queue);
+ if (wait_rpc_pipe_hnd_state(p, priority)) {
+ /* now send the reply */
+ send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
+ return True;
}
- else {
- desc.errcode=NERR_Success;
- i++;
-#if 0
- {
- int place= SVAL(data,0);
- /* we currently have no way of doing this. Can any unix do it? */
- if (i < place) /* move down */;
- else if (i > place ) /* move up */;
- }
-#endif
- desc.errcode=NERR_notsupported; /* not yet supported */
- if (queue) free(queue);
- }
- }
- else desc.errcode=NERR_JobNotFound;
- break;
- case 0xb: /* change print job name, data gives the name */
- /* jobid, snum should be zero */
- if (isalpha(*s))
- {
- pstring name;
- int l = 0;
- while (l<64 && *s)
- {
- if (isalnum(*s) || strchr("-._",*s))
- name[l++] = *s;
- s++;
- }
- name[l] = 0;
-
- DEBUG(3,("Setting print name to %s\n",name));
-
- for (i=0;i<MAX_OPEN_FILES;i++)
- if (Files[i].open && Files[i].print_file)
- {
- pstring wd;
- GetWd(wd);
- unbecome_user();
-
- if (!become_user(Files[i].cnum,uid) ||
- !become_service(Files[i].cnum,True))
- break;
-
- if (sys_rename(Files[i].name,name) == 0)
- string_set(&Files[i].name,name);
- break;
- }
- }
- desc.errcode=NERR_Success;
-
- break;
- default: /* not implemented */
- return False;
- }
-
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0); /* converter word */
-
- return(True);
+ return False;
}
/****************************************************************************
- get info about the server
- ****************************************************************************/
-static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- char *p2;
- int struct_len;
-
- DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"WrLh")) return False;
- switch( uLevel ) {
- case 0:
- if (strcmp(str2,"B16") != 0) return False;
- struct_len = 16;
- break;
- case 1:
- if (strcmp(str2,"B16BBDz") != 0) return False;
- struct_len = 26;
- break;
- case 2:
- if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
- != 0) return False;
- struct_len = 134;
- break;
- case 3:
- if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
- != 0) return False;
- struct_len = 144;
- break;
- case 20:
- if (strcmp(str2,"DN") != 0) return False;
- struct_len = 6;
- break;
- case 50:
- if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
- struct_len = 42;
- break;
- default: return False;
- }
-
- *rdata_len = mdrcnt;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- p = *rdata;
- p2 = p + struct_len;
- if (uLevel != 20) {
- StrnCpy(p,local_machine,16);
- strupper(p);
- }
- p += 16;
- if (uLevel > 0)
- {
- struct srv_info_struct *servers=NULL;
- int i,count;
- pstring comment;
- uint32 servertype=SV_TYPE_SERVER_UNIX|SV_TYPE_WORKSTATION|
- SV_TYPE_SERVER|SV_TYPE_TIME_SOURCE;
-
- strcpy(comment,lp_serverstring());
-
- if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) {
- for (i=0;i<count;i++)
- if (strequal(servers[i].name,local_machine)) {
- servertype = servers[i].type;
- strcpy(comment,servers[i].comment);
- }
- }
- if (servers) free(servers);
-
- SCVAL(p,0,2); /* version_major */
- SCVAL(p,1,0); /* version_minor */
- SIVAL(p,2,servertype);
- if (mdrcnt == struct_len) {
- SIVAL(p,6,0);
- } else {
- SIVAL(p,6,PTR_DIFF(p2,*rdata));
- standard_sub(cnum,comment);
- StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
- p2 = skip_string(p2,1);
- }
- }
- if (uLevel > 1)
- {
- return False; /* not yet implemented */
- }
-
- *rdata_len = PTR_DIFF(p2,*rdata);
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,*rdata_len);
-
- return(True);
-}
-
+ SetNamedPipeHandleState
+****************************************************************************/
-/****************************************************************************
- get info about the server
- ****************************************************************************/
-static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char *p2;
- extern pstring sesssetup_user;
- int level = SVAL(p,0);
-
- DEBUG(4,("NetWkstaGetInfo level %d\n",level));
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- /* check it's a supported varient */
- if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
- return(False);
+ uint16 id;
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ if (!param || param_len < 2)
+ return False;
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ id = SVAL(param,0);
+ DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
- p = *rdata;
- p2 = p + 22;
-
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,local_machine);
- p2 = skip_string(p2,1);
- p += 4;
-
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,sesssetup_user);
- p2 = skip_string(p2,1);
- p += 4;
-
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,my_workgroup());
- p2 = skip_string(p2,1);
- p += 4;
-
- SCVAL(p,0,2); /* major version?? */
- SCVAL(p,1,1); /* minor version?? */
- p += 2;
-
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,my_workgroup()); /* login domain?? */
- p2 = skip_string(p2,1);
- p += 4;
-
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,"");
- p2 = skip_string(p2,1);
- p += 4;
-
- *rdata_len = PTR_DIFF(p2,*rdata);
-
- SSVAL(*rparam,4,*rdata_len);
-
- return(True);
+ if (set_rpc_pipe_hnd_state(p, id)) {
+ /* now send the reply */
+ send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
+ return True;
+ }
+ return False;
}
/****************************************************************************
- get info about a user
- ****************************************************************************/
+ When no reply is generated, indicate unsupported.
+ ****************************************************************************/
-#define USER_PRIV_GUEST 0
-#define USER_PRIV_USER 1
-#define USER_PRIV_ADMIN 2
-
-static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *UserName = skip_string(str2,1);
- char *p = skip_string(UserName,1);
- int uLevel = SVAL(p,0);
- char *p2;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLh") != 0) return False;
- switch( uLevel ) {
- case 0: p2 = "B21"; break;
- case 1: p2 = "B21BB16DWzzWz"; break;
- case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
- case 10: p2 = "B21Bzzz"; break;
- case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
- default: return False;
- }
- if (strcmp(p2,str2) != 0) return False;
-
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
-
- p = *rdata;
- p2 = p + 86;
-
- memset(p,0,21);
- strcpy(p,UserName);
- if (uLevel > 0) {
- SCVAL(p,21,0);
- *p2 = 0;
- if (uLevel >= 10) {
- SIVAL(p,22,PTR_DIFF(p2,p)); /* comment */
- strcpy(p2,"<Comment>");
- p2 = skip_string(p2,1);
- SIVAL(p,26,PTR_DIFF(p2,p)); /* user_comment */
- strcpy(p2,"<UserComment>");
- p2 = skip_string(p2,1);
- SIVAL(p,30,PTR_DIFF(p2,p)); /* full name */
- strcpy(p2,"<FullName>");
- p2 = skip_string(p2,1);
- }
- if (uLevel == 11) { /* modelled after NTAS 3.51 reply */
- SSVAL(p,34,USER_PRIV_USER); /* user privilege */
- SIVAL(p,36,0); /* auth flags */
- SIVALS(p,40,-1); /* password age */
- SIVAL(p,44,PTR_DIFF(p2,p)); /* home dir */
- strcpy(p2,"\\\\%L\\HOMES");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SIVAL(p,48,PTR_DIFF(p2,p)); /* parms */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,52,0); /* last logon */
- SIVAL(p,56,0); /* last logoff */
- SSVALS(p,60,-1); /* bad pw counts */
- SSVALS(p,62,-1); /* num logons */
- SIVAL(p,64,PTR_DIFF(p2,p)); /* logon server */
- strcpy(p2,"\\\\*");
- p2 = skip_string(p2,1);
- SSVAL(p,68,0); /* country code */
-
- SIVAL(p,70,PTR_DIFF(p2,p)); /* workstations */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
-
- SIVALS(p,74,-1); /* max storage */
- SSVAL(p,78,168); /* units per week */
- SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */
- memset(p2,-1,21);
- SCVAL(p2,21,0); /* fix zero termination */
- p2 = skip_string(p2,1);
-
- SSVAL(p,84,0); /* code page */
- }
- if (uLevel == 1 || uLevel == 2) {
- memset(p+22,' ',16); /* password */
- SIVALS(p,38,-1); /* password age */
- SSVAL(p,42,USER_PRIV_ADMIN); /* user privilege */
- SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
- strcpy(p2,"\\\\%L\\HOMES");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
- *p2++ = 0;
- SSVAL(p,52,0); /* flags */
- SIVAL(p,54,0); /* script_path */
- if (uLevel == 2) {
- SIVAL(p,60,0); /* auth_flags */
- SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
- strcpy(p2,"<Full Name>");
- p2 = skip_string(p2,1);
- SIVAL(p,68,0); /* urs_comment */
- SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,76,0); /* workstations */
- SIVAL(p,80,0); /* last_logon */
- SIVAL(p,84,0); /* last_logoff */
- SIVALS(p,88,-1); /* acct_expires */
- SIVALS(p,92,-1); /* max_storage */
- SSVAL(p,96,168); /* units_per_week */
- SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
- memset(p2,-1,21);
- p2 += 21;
- SSVALS(p,102,-1); /* bad_pw_count */
- SSVALS(p,104,-1); /* num_logons */
- SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
- strcpy(p2,"\\\\%L");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SSVAL(p,110,49); /* country_code */
- SSVAL(p,112,860); /* code page */
- }
- }
- }
-
- *rdata_len = PTR_DIFF(p2,*rdata);
-
- SSVAL(*rparam,4,*rdata_len); /* is this right?? */
-
- return(True);
-}
-
-
-/*******************************************************************
- get groups that a user is a member of
- ******************************************************************/
-static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_no_reply(char *outbuf, int max_rdata_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *UserName = skip_string(str2,1);
- char *p = skip_string(UserName,1);
- int uLevel = SVAL(p,0);
- char *p2;
- int count=0;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLeh") != 0) return False;
- switch( uLevel ) {
- case 0: p2 = "B21"; break;
- default: return False;
- }
- if (strcmp(p2,str2) != 0) return False;
-
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ char rparam[4];
- p = *rdata;
+ /* unsupported */
+ SSVAL(rparam,0,NERR_notsupported);
+ SSVAL(rparam,2,0); /* converter word */
- /* XXXX we need a real SAM database some day */
- strcpy(p,"Users"); p += 21; count++;
- strcpy(p,"Domain Users"); p += 21; count++;
- strcpy(p,"Guests"); p += 21; count++;
- strcpy(p,"Domain Guests"); p += 21; count++;
+ DEBUG(3,("Unsupported API fd command\n"));
- *rdata_len = PTR_DIFF(p,*rdata);
+ /* now send the reply */
+ send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
- SSVAL(*rparam,4,count); /* is this right?? */
- SSVAL(*rparam,6,count); /* is this right?? */
-
- return(True);
+ return -1;
}
-
-static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- struct pack_desc desc;
- char* name;
-
- uLevel = SVAL(p,0);
- name = p + 2;
-
- bzero(&desc,sizeof(desc));
-
- DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
-
- /* check it's a supported varient */
- if (strcmp(str1,"OOWb54WrLh") != 0) return False;
- if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.subformat = NULL;
- desc.format = str2;
-
-
-
- if (init_package(&desc,1,0)) {
- PACKI(&desc,"W",0); /* code */
- PACKS(&desc,"B21",name); /* eff. name */
- PACKS(&desc,"B",""); /* pad */
- PACKI(&desc,"W",
- Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
- PACKI(&desc,"D",0); /* auth flags XXX */
- PACKI(&desc,"W",0); /* num logons */
- PACKI(&desc,"W",0); /* bad pw count */
- PACKI(&desc,"D",-1); /* last logon */
- PACKI(&desc,"D",-1); /* last logoff */
- PACKI(&desc,"D",-1); /* logoff time */
- PACKI(&desc,"D",-1); /* kickoff time */
- PACKI(&desc,"D",0); /* password age */
- PACKI(&desc,"D",0); /* password can change */
- PACKI(&desc,"D",-1); /* password must change */
- {
- fstring mypath;
- strcpy(mypath,"\\\\");
- strcat(mypath,local_machine);
- strupper(mypath);
- PACKS(&desc,"z",mypath); /* computer */
- }
- PACKS(&desc,"z",my_workgroup());/* domain */
- PACKS(&desc,"z",lp_logon_script()); /* script path */
- PACKI(&desc,"D",0); /* reserved */
- }
-
- *rdata_len = desc.usedlen;
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
- return(True);
-}
-
-
/****************************************************************************
- api_WAccessGetUserPerms
- ****************************************************************************/
-static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *user = skip_string(str2,1);
- char *resource = skip_string(user,1);
-
- DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
-
- /* check it's a supported varient */
- if (strcmp(str1,"zzh") != 0) return False;
- if (strcmp(str2,"") != 0) return False;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,0); /* errorcode */
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,0x7f); /* permission flags */
-
- return(True);
-}
-
-/****************************************************************************
- api_WPrintJobEnumerate
- ****************************************************************************/
-static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uJobId = SVAL(p,0);
- int uLevel,cbBuf;
- int count;
- int i;
- int snum;
- int job;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
-
- uLevel = SVAL(p,2);
- cbBuf = SVAL(p,4);
-
- bzero(&desc,sizeof(desc));
- bzero(&status,sizeof(status));
-
- DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,uJobId));
-
- /* check it's a supported varient */
- if (strcmp(str1,"WWrLh") != 0) return False;
- if (!check_printjob_info(&desc,uLevel,str2)) return False;
-
- snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
- job = uJobId & 0xFF;
-
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
-
- count = get_printqueue(snum,cnum,&queue,&status);
- for (i = 0; i < count; i++) {
- if ((queue[i].job % 0xFF) == job) break;
- }
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
-
- if (init_package(&desc,1,0)) {
- if (i < count) {
- fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
- *rdata_len = desc.usedlen;
- }
- else {
- desc.errcode = NERR_JobNotFound;
- *rdata_len = 0;
- }
- }
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- if (queue) free(queue);
-
- DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
- return(True);
-}
+ Handle remote api calls delivered to a named pipe already opened.
+ ****************************************************************************/
-static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
+ uint16 *setup,char *data,char *params,
+ int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char* name = p;
- int uLevel,cbBuf;
- int count;
- int i, succnt=0;
- int snum;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
-
- bzero(&desc,sizeof(desc));
- bzero(&status,sizeof(status));
-
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLeh") != 0) return False;
- if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
- if (!check_printjob_info(&desc,uLevel,str2)) return False;
-
- snum = lp_servicenumber(name);
- if (snum < 0 && pcap_printername_ok(name,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(name,pnum);
- snum = lp_servicenumber(name);
- }
- }
-
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
-
- count = get_printqueue(snum,cnum,&queue,&status);
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
-
- if (init_package(&desc,count,0)) {
- succnt = 0;
- for (i = 0; i < count; i++) {
- fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
- if (desc.errcode == NERR_Success) succnt = i+1;
- }
- }
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,count);
-
- if (queue) free(queue);
-
- DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
- return(True);
-}
-
-static int check_printdest_info(struct pack_desc* desc,
- int uLevel, char* id)
-{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0: desc->format = "B9"; break;
- case 1: desc->format = "B9B21WWzW"; break;
- case 2: desc->format = "z"; break;
- case 3: desc->format = "zzzWWzzzWW"; break;
- default: return False;
- }
- if (strcmp(desc->format,id) != 0) return False;
- return True;
-}
-
-static void fill_printdest_info(int cnum, int snum, int uLevel,
- struct pack_desc* desc)
-{
- char buf[100];
- strcpy(buf,SERVICE(snum));
- strupper(buf);
- if (uLevel <= 1) {
- PACKS(desc,"B9",buf); /* szName */
- if (uLevel == 1) {
- PACKS(desc,"B21",""); /* szUserName */
- PACKI(desc,"W",0); /* uJobId */
- PACKI(desc,"W",0); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKI(desc,"W",0); /* time */
- }
- }
- if (uLevel == 2 || uLevel == 3) {
- PACKS(desc,"z",buf); /* pszPrinterName */
- if (uLevel == 3) {
- PACKS(desc,"z",""); /* pszUserName */
- PACKS(desc,"z",""); /* pszLogAddr */
- PACKI(desc,"W",0); /* uJobId */
- PACKI(desc,"W",0); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKS(desc,"z",""); /* pszComment */
- PACKS(desc,"z","NULL"); /* pszDrivers */
- PACKI(desc,"W",0); /* time */
- PACKI(desc,"W",0); /* pad1 */
- }
- }
-}
-
-static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char* PrinterName = p;
- int uLevel,cbBuf;
- struct pack_desc desc;
- int snum;
-
- bzero(&desc,sizeof(desc));
-
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLh") != 0) return False;
- if (!check_printdest_info(&desc,uLevel,str2)) return False;
-
- snum = lp_servicenumber(PrinterName);
- if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(PrinterName,pnum);
- snum = lp_servicenumber(PrinterName);
- }
- }
-
- if (snum < 0) {
- *rdata_len = 0;
- desc.errcode = NERR_DestNotFound;
- desc.neededlen = 0;
- }
- else {
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,0)) {
- fill_printdest_info(cnum,snum,uLevel,&desc);
- }
- *rdata_len = desc.usedlen;
- }
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
- return(True);
-}
-
-static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel,cbBuf;
- int queuecnt;
- int i, n, succnt=0;
- struct pack_desc desc;
- int services = lp_numservices();
-
- bzero(&desc,sizeof(desc));
-
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
-
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (!check_printdest_info(&desc,uLevel,str2)) return False;
-
- queuecnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
- queuecnt++;
-
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,queuecnt,0)) {
- succnt = 0;
- n = 0;
- for (i = 0; i < services; i++) {
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- fill_printdest_info(cnum,i,uLevel,&desc);
- n++;
- if (desc.errcode == NERR_Success) succnt = n;
- }
- }
- }
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,queuecnt);
-
- DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
- return(True);
-}
-
-static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel,cbBuf;
- int succnt;
- struct pack_desc desc;
-
- bzero(&desc,sizeof(desc));
-
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
-
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
-
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B41","NULL");
- }
-
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
+ BOOL reply = False;
+ pipes_struct *p = NULL;
+ int pnum;
+ int subcommand;
- *rdata_len = desc.usedlen;
+ DEBUG(5,("api_fd_reply\n"));
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
-
- DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
- return(True);
-}
-
-static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel,cbBuf;
- int succnt;
- struct pack_desc desc;
-
- bzero(&desc,sizeof(desc));
-
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
+ /* First find out the name of this file. */
+ if (suwcnt != 2) {
+ DEBUG(0,("Unexpected named pipe transaction.\n"));
+ return(-1);
+ }
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
+ /* Get the file handle and hence the file name. */
+ /*
+ * NB. The setup array has already been transformed
+ * via SVAL and so is in gost byte order.
+ */
+ pnum = ((int)setup[1]) & 0xFFFF;
+ subcommand = ((int)setup[0]) & 0xFFFF;
+
+ if(!(p = get_rpc_pipe(pnum))) {
+ DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+ return api_no_reply(outbuf, mdrcnt);
+ }
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.format = str2;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B13","lpd");
- }
+ DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
+ /* record maximum data length that can be transmitted in an SMBtrans */
+ p->max_trans_reply = mdrcnt;
- *rdata_len = desc.usedlen;
+ DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
+ switch (subcommand) {
+ case 0x26:
+ /* dce/rpc command */
+ reply = write_to_pipe(p, data, tdscnt);
+ if (reply)
+ reply = api_rpc_trans_reply(outbuf, p);
+ break;
+ case 0x53:
+ /* Wait Named Pipe Handle state */
+ reply = api_WNPHS(outbuf, p, params, tpscnt);
+ break;
+ case 0x01:
+ /* Set Named Pipe Handle state */
+ reply = api_SNPHS(outbuf, p, params, tpscnt);
+ break;
+ }
- DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
- return(True);
-}
+ if (!reply)
+ return api_no_reply(outbuf, mdrcnt);
-static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel,cbBuf;
- int succnt;
- struct pack_desc desc;
-
- bzero(&desc,sizeof(desc));
-
- uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
-
- DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
-
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
-
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- bzero(&desc,sizeof(desc));
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.format = str2;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B13","lp0");
- }
-
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
-
- DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
- return(True);
+ return -1;
}
/****************************************************************************
- the buffer was too small
+ handle named pipe commands
****************************************************************************/
-static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
+ uint16 *setup,char *data,char *params,
+ int suwcnt,int tdscnt,int tpscnt,
+ int msrcnt,int mdrcnt,int mprcnt)
{
- *rparam_len = MIN(*rparam_len,mprcnt);
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_BufTooSmall);
+ DEBUG(3,("named pipe command on <%s> name\n", name));
- DEBUG(3,("Supplied buffer too small in API command\n"));
+ if (strequal(name,"LANMAN"))
+ return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
- return(True);
-}
-
-
-/****************************************************************************
- the request is not supported
- ****************************************************************************/
-static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
-{
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
+ if (strequal(name,"WKSSVC") ||
+ strequal(name,"SRVSVC") ||
+ strequal(name,"WINREG") ||
+ strequal(name,"SAMR") ||
+ strequal(name,"LSARPC"))
+ {
+ DEBUG(4,("named pipe command from Win95 (wow!)\n"));
+ return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
- SSVAL(*rparam,0,NERR_notsupported);
- SSVAL(*rparam,2,0); /* converter word */
+ if (strlen(name) < 1)
+ return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
- DEBUG(3,("Unsupported API command\n"));
+ if (setup)
+ DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
- return(True);
+ return 0;
}
-
-
-struct
-{
- char *name;
- int id;
- BOOL (*fn)();
- int flags;
-} api_commands[] = {
- {"RNetShareEnum", 0, api_RNetShareEnum,0},
- {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
- {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
- {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
- {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
- {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
- {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
- {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
- {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
- {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
- {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
- {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
- {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
- {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
- {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
- {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
- {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
- {"NetServerEnum", 104, api_RNetServerEnum,0},
- {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
- {"SetUserPassword", 115, api_SetUserPassword,0},
- {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
- {"PrintJobInfo", 147, api_PrintJobInfo,0},
- {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
- {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
- {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
- {NULL, -1, api_Unsupported,0}};
-
-
/****************************************************************************
- handle remote api calls
- ****************************************************************************/
-static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
- int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
-{
- int api_command = SVAL(params,0);
- char *rdata = NULL;
- char *rparam = NULL;
- int rdata_len = 0;
- int rparam_len = 0;
- BOOL reply=False;
- int i;
-
- DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
- api_command,params+2,skip_string(params+2,1),
- tdscnt,tpscnt,mdrcnt,mprcnt));
-
- for (i=0;api_commands[i].name;i++)
- if (api_commands[i].id == api_command && api_commands[i].fn)
- {
- DEBUG(3,("Doing %s\n",api_commands[i].name));
- break;
- }
-
- rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
- rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
-
- reply = api_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
- &rdata,&rparam,&rdata_len,&rparam_len);
-
-
- if (rdata_len > mdrcnt ||
- rparam_len > mprcnt)
- {
- reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
- &rdata,&rparam,&rdata_len,&rparam_len);
- }
-
-
- /* if we get False back then it's actually unsupported */
- if (!reply)
- api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
- &rdata,&rparam,&rdata_len,&rparam_len);
-
-
-
- /* now send the reply */
- send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
-
- if (rdata)
- free(rdata);
- if (rparam)
- free(rparam);
+ Reply to a SMBtrans.
+ ****************************************************************************/
+
+int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
+{
+ fstring name;
+ int name_offset = 0;
+ char *data=NULL,*params=NULL;
+ uint16 *setup=NULL;
+ int outsize = 0;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int tpscnt = SVAL(inbuf,smb_vwv0);
+ int tdscnt = SVAL(inbuf,smb_vwv1);
+ int mprcnt = SVAL(inbuf,smb_vwv2);
+ int mdrcnt = SVAL(inbuf,smb_vwv3);
+ int msrcnt = CVAL(inbuf,smb_vwv4);
+ BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+ BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
+ int pscnt = SVAL(inbuf,smb_vwv9);
+ int psoff = SVAL(inbuf,smb_vwv10);
+ int dscnt = SVAL(inbuf,smb_vwv11);
+ int dsoff = SVAL(inbuf,smb_vwv12);
+ int suwcnt = CVAL(inbuf,smb_vwv13);
+ START_PROFILE(SMBtrans);
+
+ memset(name, '\0',sizeof(name));
+ srvstr_pull(inbuf, name, smb_buf(inbuf), sizeof(name), -1, STR_TERMINATE);
+
+ if (dscnt > tdscnt || pscnt > tpscnt) {
+ exit_server("invalid trans parameters");
+ }
- return(-1);
-}
-
-/****************************************************************************
- handle named pipe commands
- ****************************************************************************/
-static int named_pipe(int cnum,int uid, char *outbuf,char *name,
- uint16 *setup,char *data,char *params,
- int suwcnt,int tdscnt,int tpscnt,
- int msrcnt,int mdrcnt,int mprcnt)
-{
+ if (tdscnt) {
+ if((data = (char *)malloc(tdscnt)) == NULL) {
+ DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ memcpy(data,smb_base(inbuf)+dsoff,dscnt);
+ }
- if (strequal(name,"LANMAN"))
- return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
+ if (tpscnt) {
+ if((params = (char *)malloc(tpscnt)) == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ memcpy(params,smb_base(inbuf)+psoff,pscnt);
+ }
- DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
- name,(int)setup[0],(int)setup[1]));
-
- return(0);
-}
+ if (suwcnt) {
+ int i;
+ if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
+ DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ for (i=0;i<suwcnt;i++)
+ setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
+ }
-/****************************************************************************
- reply to a SMBtrans
- ****************************************************************************/
-int reply_trans(char *inbuf,char *outbuf)
-{
- fstring name;
-
- char *data=NULL,*params=NULL;
- uint16 *setup=NULL;
-
- int outsize = 0;
- int cnum = SVAL(inbuf,smb_tid);
- int uid = SVAL(inbuf,smb_uid);
-
- int tpscnt = SVAL(inbuf,smb_vwv0);
- int tdscnt = SVAL(inbuf,smb_vwv1);
- int mprcnt = SVAL(inbuf,smb_vwv2);
- int mdrcnt = SVAL(inbuf,smb_vwv3);
- int msrcnt = CVAL(inbuf,smb_vwv4);
- BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
- BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
- int pscnt = SVAL(inbuf,smb_vwv9);
- int psoff = SVAL(inbuf,smb_vwv10);
- int dscnt = SVAL(inbuf,smb_vwv11);
- int dsoff = SVAL(inbuf,smb_vwv12);
- int suwcnt = CVAL(inbuf,smb_vwv13);
-
- StrnCpy(name,smb_buf(inbuf),sizeof(name)-1);
-
- if (tdscnt)
- {
- data = (char *)malloc(tdscnt);
- memcpy(data,smb_base(inbuf)+dsoff,dscnt);
- }
- if (tpscnt)
- {
- params = (char *)malloc(tpscnt);
- memcpy(params,smb_base(inbuf)+psoff,pscnt);
- }
-
- if (suwcnt)
- {
- int i;
- setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
- for (i=0;i<suwcnt;i++)
- setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
- }
-
-
- if (pscnt < tpscnt || dscnt < tdscnt)
- {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- show_msg(outbuf);
- send_smb(Client,outbuf);
- }
-
- /* receive the rest of the trans packet */
- while (pscnt < tpscnt || dscnt < tdscnt)
- {
- int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- receive_smb(Client,inbuf, 0);
- show_msg(inbuf);
-
- /* Ensure this is still a trans packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtrans)
- {
- DEBUG(2,("Invalid secondary trans2 packet\n"));
- if (params) free(params);
- if (data) free(data);
- if (setup) free(setup);
- return(ERROR(ERRSRV,ERRerror));
+ if (pscnt < tpscnt || dscnt < tdscnt) {
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_trans: send_smb failed.");
}
-
- tpscnt = SVAL(inbuf,smb_vwv0);
- tdscnt = SVAL(inbuf,smb_vwv1);
- pcnt = SVAL(inbuf,smb_vwv2);
- poff = SVAL(inbuf,smb_vwv3);
- pdisp = SVAL(inbuf,smb_vwv4);
+ /* receive the rest of the trans packet */
+ while (pscnt < tpscnt || dscnt < tdscnt) {
+ BOOL ret;
+ int pcnt,poff,dcnt,doff,pdisp,ddisp;
- dcnt = SVAL(inbuf,smb_vwv5);
- doff = SVAL(inbuf,smb_vwv6);
- ddisp = SVAL(inbuf,smb_vwv7);
+ ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+
+ if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
+ if(ret) {
+ DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
+ } else {
+ DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
+ (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
+ }
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ SAFE_FREE(setup);
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRSRV,ERRerror));
+ }
+
+ show_msg(inbuf);
- pscnt += pcnt;
- dscnt += dcnt;
-
- if (pcnt)
- memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
- if (dcnt)
- memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
- }
-
-
- DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
-
-
- if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
- outsize = named_pipe(cnum,uid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
- suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
-
-
- if (data) free(data);
- if (params) free(params);
- if (setup) free(setup);
-
- if (close_on_completion)
- close_cnum(cnum,uid);
+ tpscnt = SVAL(inbuf,smb_vwv0);
+ tdscnt = SVAL(inbuf,smb_vwv1);
+
+ pcnt = SVAL(inbuf,smb_vwv2);
+ poff = SVAL(inbuf,smb_vwv3);
+ pdisp = SVAL(inbuf,smb_vwv4);
+
+ dcnt = SVAL(inbuf,smb_vwv5);
+ doff = SVAL(inbuf,smb_vwv6);
+ ddisp = SVAL(inbuf,smb_vwv7);
+
+ pscnt += pcnt;
+ dscnt += dcnt;
+
+ if (dscnt > tdscnt || pscnt > tpscnt) {
+ exit_server("invalid trans parameters");
+ }
+
+ if (pcnt)
+ memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
+ if (dcnt)
+ memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
+ }
+
+
+ DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
+ name,tdscnt,tpscnt,suwcnt));
+
+ /*
+ * WinCE wierdness....
+ */
+
+ if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
+ (name[strlen(local_machine)+1] == '\\'))
+ name_offset = strlen(local_machine)+1;
+
+ if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
+ name_offset += strlen("\\PIPE");
+
+ /* Win9x weirdness. When talking to a unicode server Win9x
+ only sends \PIPE instead of \PIPE\ */
+
+ if (name[name_offset] == '\\')
+ name_offset++;
+
+ DEBUG(5,("calling named_pipe\n"));
+ outsize = named_pipe(conn,vuid,outbuf,
+ name+name_offset,setup,data,params,
+ suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
+ } else {
+ DEBUG(3,("invalid pipe name\n"));
+ outsize = 0;
+ }
- if (one_way)
- return(-1);
-
- if (outsize == 0)
- return(ERROR(ERRSRV,ERRnosupport));
+
+ SAFE_FREE(data);
+ SAFE_FREE(params);
+ SAFE_FREE(setup);
+
+ if (close_on_completion)
+ close_cnum(conn,vuid);
- return(outsize);
+ if (one_way) {
+ END_PROFILE(SMBtrans);
+ return(-1);
+ }
+
+ if (outsize == 0) {
+ END_PROFILE(SMBtrans);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBtrans);
+ return(outsize);
}
-
-
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
new file mode 100644
index 00000000000..34dcf6c2118
--- /dev/null
+++ b/source/smbd/lanman.c
@@ -0,0 +1,3682 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Inter-process communication and named pipe handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ This file handles the named pipe and mailslot calls
+ in the SMBtrans protocol
+ */
+
+#include "includes.h"
+
+#ifdef CHECK_TYPES
+#undef CHECK_TYPES
+#endif
+#define CHECK_TYPES 0
+
+extern fstring local_machine;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+#define NERR_Success 0
+#define NERR_badpass 86
+#define NERR_notsupported 50
+
+#define NERR_BASE (2100)
+#define NERR_BufTooSmall (NERR_BASE+23)
+#define NERR_JobNotFound (NERR_BASE+51)
+#define NERR_DestNotFound (NERR_BASE+52)
+
+#define ACCESS_READ 0x01
+#define ACCESS_WRITE 0x02
+#define ACCESS_CREATE 0x04
+
+#define SHPWLEN 8 /* share password length */
+
+static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+
+static int CopyExpanded(connection_struct *conn,
+ int snum, char** dst, char* src, int* n)
+{
+ pstring buf;
+ int l;
+
+ if (!src || !dst || !n || !(*dst)) return(0);
+
+ StrnCpy(buf,src,sizeof(buf)/2);
+ pstring_sub(buf,"%S",lp_servicename(snum));
+ standard_sub_conn(conn,buf);
+ l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
+ (*dst) += l;
+ (*n) -= l;
+ return l;
+}
+
+static int CopyAndAdvance(char** dst, char* src, int* n)
+{
+ int l;
+ if (!src || !dst || !n || !(*dst)) return(0);
+ l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
+ (*dst) += l;
+ (*n) -= l;
+ return l;
+}
+
+static int StrlenExpanded(connection_struct *conn, int snum, char* s)
+{
+ pstring buf;
+ if (!s) return(0);
+ StrnCpy(buf,s,sizeof(buf)/2);
+ pstring_sub(buf,"%S",lp_servicename(snum));
+ standard_sub_conn(conn,buf);
+ return strlen(buf) + 1;
+}
+
+static char* Expand(connection_struct *conn, int snum, char* s)
+{
+ static pstring buf;
+ if (!s) return(NULL);
+ StrnCpy(buf,s,sizeof(buf)/2);
+ pstring_sub(buf,"%S",lp_servicename(snum));
+ standard_sub_conn(conn,buf);
+ return &buf[0];
+}
+
+/*******************************************************************
+ check a API string for validity when we only need to check the prefix
+ ******************************************************************/
+static BOOL prefix_ok(char *str,char *prefix)
+{
+ return(strncmp(str,prefix,strlen(prefix)) == 0);
+}
+
+struct pack_desc {
+ char* format; /* formatstring for structure */
+ char* subformat; /* subformat for structure */
+ char* base; /* baseaddress of buffer */
+ int buflen; /* remaining size for fixed part; on init: length of base */
+ int subcount; /* count of substructures */
+ char* structbuf; /* pointer into buffer for remaining fixed part */
+ int stringlen; /* remaining size for variable part */
+ char* stringbuf; /* pointer into buffer for remaining variable part */
+ int neededlen; /* total needed size */
+ int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
+ char* curpos; /* current position; pointer into format or subformat */
+ int errcode;
+};
+
+static int get_counter(char** p)
+{
+ int i, n;
+ if (!p || !(*p)) return(1);
+ if (!isdigit((int)**p)) return 1;
+ for (n = 0;;) {
+ i = **p;
+ if (isdigit(i))
+ n = 10 * n + (i - '0');
+ else
+ return n;
+ (*p)++;
+ }
+}
+
+static int getlen(char* p)
+{
+ int n = 0;
+ if (!p) return(0);
+ while (*p) {
+ switch( *p++ ) {
+ case 'W': /* word (2 byte) */
+ n += 2;
+ break;
+ case 'K': /* status word? (2 byte) */
+ n += 2;
+ break;
+ case 'N': /* count of substructures (word) at end */
+ n += 2;
+ break;
+ case 'D': /* double word (4 byte) */
+ case 'z': /* offset to zero terminated string (4 byte) */
+ case 'l': /* offset to user data (4 byte) */
+ n += 4;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ n += 4;
+ get_counter(&p);
+ break;
+ case 'B': /* byte (with optional counter) */
+ n += get_counter(&p);
+ break;
+ }
+ }
+ return n;
+}
+
+static BOOL init_package(struct pack_desc* p, int count, int subcount)
+{
+ int n = p->buflen;
+ int i;
+
+ if (!p->format || !p->base) return(False);
+
+ i = count * getlen(p->format);
+ if (p->subformat) i += subcount * getlen(p->subformat);
+ p->structbuf = p->base;
+ p->neededlen = 0;
+ p->usedlen = 0;
+ p->subcount = 0;
+ p->curpos = p->format;
+ if (i > n) {
+ p->neededlen = i;
+ i = n = 0;
+#if 0
+ /*
+ * This is the old error code we used. Aparently
+ * WinNT/2k systems return ERRbuftoosmall (2123) and
+ * OS/2 needs this. I'm leaving this here so we can revert
+ * if needed. JRA.
+ */
+ p->errcode = ERRmoredata;
+#else
+ p->errcode = ERRbuftoosmall;
+#endif
+ }
+ else
+ p->errcode = NERR_Success;
+ p->buflen = i;
+ n -= i;
+ p->stringbuf = p->base + i;
+ p->stringlen = n;
+ return(p->errcode == NERR_Success);
+}
+
+static int package(struct pack_desc* p, ...)
+{
+ va_list args;
+ int needed=0, stringneeded;
+ char* str=NULL;
+ int is_string=0, stringused;
+ int32 temp;
+
+ va_start(args,p);
+
+ if (!*p->curpos) {
+ if (!p->subcount)
+ p->curpos = p->format;
+ else {
+ p->curpos = p->subformat;
+ p->subcount--;
+ }
+ }
+#if CHECK_TYPES
+ str = va_arg(args,char*);
+ SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
+#endif
+ stringneeded = -1;
+
+ if (!p->curpos) {
+ va_end(args);
+ return(0);
+ }
+
+ switch( *p->curpos++ ) {
+ case 'W': /* word (2 byte) */
+ needed = 2;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
+ break;
+ case 'K': /* status word? (2 byte) */
+ needed = 2;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
+ break;
+ case 'N': /* count of substructures (word) at end */
+ needed = 2;
+ p->subcount = va_arg(args,int);
+ if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
+ break;
+ case 'D': /* double word (4 byte) */
+ needed = 4;
+ temp = va_arg(args,int);
+ if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
+ break;
+ case 'B': /* byte (with optional counter) */
+ needed = get_counter(&p->curpos);
+ {
+ char *s = va_arg(args,char*);
+ if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
+ }
+ break;
+ case 'z': /* offset to zero terminated string (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = (str ? strlen(str)+1 : 0);
+ is_string = 1;
+ break;
+ case 'l': /* offset to user data (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = va_arg(args,int);
+ is_string = 0;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ str = va_arg(args,char*);
+ stringneeded = get_counter(&p->curpos);
+ is_string = 0;
+ break;
+ }
+ va_end(args);
+ if (stringneeded >= 0) {
+ needed = 4;
+ if (p->buflen >= needed) {
+ stringused = stringneeded;
+ if (stringused > p->stringlen) {
+ stringused = (is_string ? p->stringlen : 0);
+ if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
+ }
+ if (!stringused)
+ SIVAL(p->structbuf,0,0);
+ else {
+ SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
+ memcpy(p->stringbuf,str?str:"",stringused);
+ if (is_string) p->stringbuf[stringused-1] = '\0';
+ p->stringbuf += stringused;
+ p->stringlen -= stringused;
+ p->usedlen += stringused;
+ }
+ }
+ p->neededlen += stringneeded;
+ }
+ p->neededlen += needed;
+ if (p->buflen >= needed) {
+ p->structbuf += needed;
+ p->buflen -= needed;
+ p->usedlen += needed;
+ }
+ else {
+ if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
+ }
+ return 1;
+}
+
+#if CHECK_TYPES
+#define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
+#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
+#else
+#define PACK(desc,t,v) package(desc,v)
+#define PACKl(desc,t,v,l) package(desc,v,l)
+#endif
+
+static void PACKI(struct pack_desc* desc,char *t,int v)
+{
+ PACK(desc,t,v);
+}
+
+static void PACKS(struct pack_desc* desc,char *t,char *v)
+{
+ PACK(desc,t,v);
+}
+
+
+/****************************************************************************
+ get a print queue
+ ****************************************************************************/
+static void PackDriverData(struct pack_desc* desc)
+{
+ char drivdata[4+4+32];
+ SIVAL(drivdata,0,sizeof drivdata); /* cb */
+ SIVAL(drivdata,4,1000); /* lVersion */
+ memset(drivdata+8,0,32); /* szDeviceName */
+ push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
+ PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
+}
+
+static int check_printq_info(struct pack_desc* desc,
+ int uLevel, char *id1, char *id2)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0:
+ desc->format = "B13";
+ break;
+ case 1:
+ desc->format = "B13BWWWzzzzzWW";
+ break;
+ case 2:
+ desc->format = "B13BWWWzzzzzWN";
+ desc->subformat = "WB21BB16B10zWWzDDz";
+ break;
+ case 3:
+ desc->format = "zWWWWzzzzWWzzl";
+ break;
+ case 4:
+ desc->format = "zWWWWzzzzWNzzl";
+ desc->subformat = "WWzWWDDzz";
+ break;
+ case 5:
+ desc->format = "z";
+ break;
+ case 51:
+ desc->format = "K";
+ break;
+ case 52:
+ desc->format = "WzzzzzzzzN";
+ desc->subformat = "z";
+ break;
+ default: return False;
+ }
+ if (strcmp(desc->format,id1) != 0) return False;
+ if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
+ return True;
+}
+
+
+#define RAP_JOB_STATUS_QUEUED 0
+#define RAP_JOB_STATUS_PAUSED 1
+#define RAP_JOB_STATUS_SPOOLING 2
+#define RAP_JOB_STATUS_PRINTING 3
+#define RAP_JOB_STATUS_PRINTED 4
+
+#define RAP_QUEUE_STATUS_PAUSED 1
+#define RAP_QUEUE_STATUS_ERROR 2
+
+/* turn a print job status into a on the wire status
+*/
+static int printj_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return RAP_JOB_STATUS_QUEUED;
+ case LPQ_PAUSED:
+ return RAP_JOB_STATUS_PAUSED;
+ case LPQ_SPOOLING:
+ return RAP_JOB_STATUS_SPOOLING;
+ case LPQ_PRINTING:
+ return RAP_JOB_STATUS_PRINTING;
+ }
+ return 0;
+}
+
+/* turn a print queue status into a on the wire status
+*/
+static int printq_status(int v)
+{
+ switch (v) {
+ case LPQ_QUEUED:
+ return 0;
+ case LPQ_PAUSED:
+ return RAP_QUEUE_STATUS_PAUSED;
+ }
+ return RAP_QUEUE_STATUS_ERROR;
+}
+
+static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc,
+ print_queue_struct* queue, int n)
+{
+ time_t t = queue->time;
+
+ /* the client expects localtime */
+ t -= TimeDiff(t);
+
+ PACKI(desc,"W",queue->job); /* uJobId */
+ if (uLevel == 1) {
+ PACKS(desc,"B21",queue->user); /* szUserName */
+ PACKS(desc,"B",""); /* pad */
+ PACKS(desc,"B16",""); /* szNotifyName */
+ PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
+ PACKS(desc,"z",""); /* pszParms */
+ PACKI(desc,"W",n+1); /* uPosition */
+ PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"D",t); /* ulSubmitted */
+ PACKI(desc,"D",queue->size); /* ulSize */
+ PACKS(desc,"z",queue->file); /* pszComment */
+ }
+ if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
+ PACKI(desc,"W",queue->priority); /* uPriority */
+ PACKS(desc,"z",queue->user); /* pszUserName */
+ PACKI(desc,"W",n+1); /* uPosition */
+ PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
+ PACKI(desc,"D",t); /* ulSubmitted */
+ PACKI(desc,"D",queue->size); /* ulSize */
+ PACKS(desc,"z","Samba"); /* pszComment */
+ PACKS(desc,"z",queue->file); /* pszDocument */
+ if (uLevel == 3) {
+ PACKS(desc,"z",""); /* pszNotifyName */
+ PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
+ PACKS(desc,"z",""); /* pszParms */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
+ PACKS(desc,"z","lpd"); /* pszQProcName */
+ PACKS(desc,"z",""); /* pszQProcParms */
+ PACKS(desc,"z","NULL"); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ PACKS(desc,"z",""); /* pszPrinterName */
+ } else if (uLevel == 4) { /* OS2 */
+ PACKS(desc,"z",""); /* pszSpoolFileName */
+ PACKS(desc,"z",""); /* pszPortName */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"D",0); /* ulPagesSpooled */
+ PACKI(desc,"D",0); /* ulPagesSent */
+ PACKI(desc,"D",0); /* ulPagesPrinted */
+ PACKI(desc,"D",0); /* ulTimePrinted */
+ PACKI(desc,"D",0); /* ulExtendJobStatus */
+ PACKI(desc,"D",0); /* ulStartPage */
+ PACKI(desc,"D",0); /* ulEndPage */
+ }
+ }
+}
+
+/********************************************************************
+ Return a driver name given an snum.
+ Looks in a tdb first. Returns True if from tdb, False otherwise.
+ ********************************************************************/
+
+static BOOL get_driver_name(int snum, pstring drivername)
+{
+ NT_PRINTER_INFO_LEVEL *info = NULL;
+ BOOL in_tdb = False;
+
+ get_a_printer (&info, 2, lp_servicename(snum));
+ if (info != NULL) {
+ pstrcpy( drivername, info->info_2->drivername);
+ in_tdb = True;
+ free_a_printer(&info, 2);
+ } else {
+ pstrcpy( drivername, lp_printerdriver(snum));
+ }
+
+ return in_tdb;
+}
+
+/********************************************************************
+ Respond to the DosPrintQInfo command with a level of 52
+ This is used to get printer driver information for Win9x clients
+ ********************************************************************/
+static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc,
+ int count, print_queue_struct* queue,
+ print_status_struct* status)
+{
+ int i;
+ BOOL ok = False;
+ pstring tok,driver,datafile,langmon,helpfile,datatype;
+ char *p;
+ char **lines = NULL;
+ pstring gen_line;
+ BOOL in_tdb = False;
+ fstring location;
+ pstring drivername;
+
+ /*
+ * Check in the tdb *first* before checking the legacy
+ * files. This allows an NT upload to take precedence over
+ * the existing fileset. JRA.
+ *
+ * we need to lookup the driver name prior to making the call
+ * to get_a_printer_driver_9x_compatible() and not rely on the
+ * 'print driver' parameter --jerry
+ */
+
+
+ if ((get_driver_name(snum,drivername)) &&
+ ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
+ {
+ in_tdb = True;
+ p = gen_line;
+ DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
+ }
+ else
+ {
+ /* didn't find driver in tdb */
+
+ DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
+ snum, drivername, lp_driverfile(snum)));
+
+ lines = file_lines_load(lp_driverfile(snum),NULL);
+ if (!lines)
+ {
+ DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
+ strerror(errno)));
+ desc->errcode=NERR_notsupported;
+ goto done;
+ }
+
+ /* lookup the long printer driver name in the file description */
+ for (i=0;lines[i] && !ok;i++)
+ {
+ p = lines[i];
+ if (next_token(&p,tok,":",sizeof(tok)) &&
+ (strlen(drivername) == strlen(tok)) &&
+ (!strncmp(tok,drivername,strlen(drivername))))
+ {
+ ok = True;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ /* driver file name */
+ if (!next_token(&p,driver,":",sizeof(driver)))
+ goto err;
+
+ /* data file name */
+ if (!next_token(&p,datafile,":",sizeof(datafile)))
+ goto err;
+
+ /*
+ * for the next tokens - which may be empty - I have
+ * to check for empty tokens first because the
+ * next_token function will skip all empty token
+ * fields */
+
+ /* help file */
+ if (*p == ':')
+ {
+ *helpfile = '\0';
+ p++;
+ }
+ else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
+ goto err;
+
+ /* language monitor */
+ if (*p == ':')
+ {
+ *langmon = '\0';
+ p++;
+ }
+ else if (!next_token(&p,langmon,":",sizeof(langmon)))
+ goto err;
+
+ /* default data type */
+ if (!next_token(&p,datatype,":",sizeof(datatype)))
+ goto err;
+
+ PACKI(desc,"W",0x0400); /* don't know */
+ PACKS(desc,"z",drivername); /* long printer name */
+ PACKS(desc,"z",driver); /* Driverfile Name */
+ PACKS(desc,"z",datafile); /* Datafile name */
+ PACKS(desc,"z",langmon); /* language monitor */
+ if (in_tdb)
+ {
+ fstrcpy(location, "\\\\");
+ fstrcat(location, global_myname);
+ fstrcat(location, "\\print$\\WIN40\\0");
+ PACKS(desc,"z",location); /* share to retrieve files */
+ }
+ else
+ {
+ PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
+ }
+ PACKS(desc,"z",datatype); /* default data type */
+ PACKS(desc,"z",helpfile); /* helpfile name */
+ PACKS(desc,"z",driver); /* driver name */
+
+ DEBUG(3,("printerdriver:%s:\n",drivername));
+ DEBUG(3,("Driver:%s:\n",driver));
+ DEBUG(3,("Data File:%s:\n",datafile));
+ DEBUG(3,("Language Monitor:%s:\n",langmon));
+ if (in_tdb)
+ DEBUG(3,("lp_driverlocation:%s:\n",location));
+ else
+ DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
+ DEBUG(3,("Data Type:%s:\n",datatype));
+ DEBUG(3,("Help File:%s:\n",helpfile));
+ PACKI(desc,"N",count); /* number of files to copy */
+
+ for (i=0;i<count;i++)
+ {
+ /* no need to check return value here
+ * - it was already tested in
+ * get_printerdrivernumber */
+ next_token(&p,tok,",",sizeof(tok));
+ PACKS(desc,"z",tok); /* driver files to copy */
+ DEBUG(3,("file:%s:\n",tok));
+ }
+
+ DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
+ SERVICE(snum),count));
+
+ desc->errcode=NERR_Success;
+ goto done;
+ }
+
+ err:
+
+ DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
+ desc->errcode=NERR_notsupported;
+
+ done:
+ file_lines_free(lines);
+}
+
+
+static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc,
+ int count, print_queue_struct* queue,
+ print_status_struct* status)
+{
+ switch (uLevel) {
+ case 1:
+ case 2:
+ PACKS(desc,"B13",SERVICE(snum));
+ break;
+ case 3:
+ case 4:
+ case 5:
+ PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
+ break;
+ case 51:
+ PACKI(desc,"K",printq_status(status->status));
+ break;
+ }
+
+ if (uLevel == 1 || uLevel == 2) {
+ PACKS(desc,"B",""); /* alignment */
+ PACKI(desc,"W",5); /* priority */
+ PACKI(desc,"W",0); /* start time */
+ PACKI(desc,"W",0); /* until time */
+ PACKS(desc,"z",""); /* pSepFile */
+ PACKS(desc,"z","lpd"); /* pPrProc */
+ PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
+ PACKS(desc,"z",""); /* pParms */
+ if (snum < 0) {
+ PACKS(desc,"z","UNKNOWN PRINTER");
+ PACKI(desc,"W",LPSTAT_ERROR);
+ }
+ else if (!status || !status->message[0]) {
+ PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
+ PACKI(desc,"W",LPSTAT_OK); /* status */
+ } else {
+ PACKS(desc,"z",status->message);
+ PACKI(desc,"W",printq_status(status->status)); /* status */
+ }
+ PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
+ }
+
+ if (uLevel == 3 || uLevel == 4) {
+ pstring drivername;
+
+ PACKI(desc,"W",5); /* uPriority */
+ PACKI(desc,"W",0); /* uStarttime */
+ PACKI(desc,"W",0); /* uUntiltime */
+ PACKI(desc,"W",5); /* pad1 */
+ PACKS(desc,"z",""); /* pszSepFile */
+ PACKS(desc,"z","WinPrint"); /* pszPrProc */
+ PACKS(desc,"z",NULL); /* pszParms */
+ PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
+ /* "don't ask" that it's done this way to fix corrupted
+ Win9X/ME printer comments. */
+ if (!status) {
+ PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
+ } else {
+ PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
+ }
+ PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
+ PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
+ get_driver_name(snum,drivername);
+ PACKS(desc,"z",drivername); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ }
+
+ if (uLevel == 2 || uLevel == 4) {
+ int i;
+ for (i=0;i<count;i++)
+ fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
+ }
+
+ if (uLevel==52) {
+ fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
+ }
+}
+
+/* This function returns the number of files for a given driver */
+static int get_printerdrivernumber(int snum)
+{
+ int i, result = 0;
+ BOOL ok = False;
+ pstring tok;
+ char *p;
+ char **lines = NULL;
+ pstring gen_line;
+ pstring drivername;
+
+ /*
+ * Check in the tdb *first* before checking the legacy
+ * files. This allows an NT upload to take precedence over
+ * the existing fileset. JRA.
+ *
+ * we need to lookup the driver name prior to making the call
+ * to get_a_printer_driver_9x_compatible() and not rely on the
+ * 'print driver' parameter --jerry
+ */
+
+ if ((get_driver_name(snum,drivername)) &&
+ (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
+ {
+ p = gen_line;
+ DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
+ }
+ else
+ {
+ /* didn't find driver in tdb */
+
+ DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
+ snum, drivername, lp_driverfile(snum)));
+
+ lines = file_lines_load(lp_driverfile(snum), NULL);
+ if (!lines)
+ {
+ DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
+ goto done;
+ }
+
+ /* lookup the long printer driver name in the file description */
+ for (i=0;lines[i] && !ok;i++)
+ {
+ p = lines[i];
+ if (next_token(&p,tok,":",sizeof(tok)) &&
+ (strlen(drivername) == strlen(tok)) &&
+ (!strncmp(tok,drivername,strlen(drivername))))
+ {
+ ok = True;
+ }
+ }
+ }
+
+ if( ok )
+ {
+ /* skip 5 fields */
+ i = 5;
+ while (*p && i) {
+ if (*p++ == ':') i--;
+ }
+ if (!*p || i) {
+ DEBUG(3,("Can't determine number of printer driver files\n"));
+ goto done;
+ }
+
+ /* count the number of files */
+ while (next_token(&p,tok,",",sizeof(tok)))
+ i++;
+
+ result = i;
+ }
+
+ done:
+
+ file_lines_free(lines);
+
+ return result;
+}
+
+static BOOL api_DosPrintQGetInfo(connection_struct *conn,
+ uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ char *QueueName = p;
+ int uLevel;
+ int count=0;
+ int snum;
+ char* str3;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+ char* tmpdata=NULL;
+
+ memset((char *)&status,'\0',sizeof(status));
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ p = skip_string(p,1);
+ uLevel = SVAL(p,0);
+ str3 = p + 4;
+
+ /* remove any trailing username */
+ if ((p = strchr_m(QueueName,'%')))
+ *p = 0;
+
+ DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"zWrLh"))
+ return False;
+ if (!check_printq_info(&desc,uLevel,str2,str3)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,ERRunknownlevel);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
+
+ snum = lp_servicenumber(QueueName);
+ if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0) {
+ lp_add_printer(QueueName,pnum);
+ snum = lp_servicenumber(QueueName);
+ }
+ }
+
+ if (snum < 0 || !VALID_SNUM(snum))
+ return(False);
+
+ if (uLevel==52) {
+ count = get_printerdrivernumber(snum);
+ DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
+ } else {
+ count = print_queue_status(snum, &queue,&status);
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *) malloc (desc.buflen);
+ }
+
+ if (init_package(&desc,1,count)) {
+ desc.subcount = count;
+ fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
+ }
+
+ *rdata_len = desc.usedlen;
+
+ /*
+ * We must set the return code to ERRbuftoosmall
+ * in order to support lanman style printing with Win NT/2k
+ * clients --jerry
+ */
+ if (!mdrcnt && lp_disable_spoolss())
+ desc.errcode = ERRbuftoosmall;
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
+
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
+
+ return(True);
+}
+
+/****************************************************************************
+ View list of all print jobs on all queues.
+****************************************************************************/
+
+static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
+ int mdrcnt, int mprcnt,
+ char **rdata, char** rparam,
+ int *rdata_len, int *rparam_len)
+{
+ char *param_format = param+2;
+ char *output_format1 = skip_string(param_format,1);
+ char *p = skip_string(output_format1,1);
+ int uLevel = SVAL(p,0);
+ char *output_format2 = p + 4;
+ int services = lp_numservices();
+ int i, n;
+ struct pack_desc desc;
+ print_queue_struct **queue = NULL;
+ print_status_struct *status = NULL;
+ int* subcntarr = NULL;
+ int queuecnt, subcnt=0, succnt=0;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
+
+ if (!prefix_ok(param_format,"WrLeh")) return False;
+ if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,ERRunknownlevel);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
+
+ queuecnt = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
+ queuecnt++;
+ if (uLevel > 0) {
+ if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ memset(queue,0,queuecnt*sizeof(print_queue_struct*));
+ if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ memset(status,0,queuecnt*sizeof(print_status_struct));
+ if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
+ DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ subcnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
+ subcnt += subcntarr[n];
+ n++;
+ }
+ }
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+
+ if (init_package(&desc,queuecnt,subcnt)) {
+ n = 0;
+ succnt = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
+ n++;
+ if (desc.errcode == NERR_Success) succnt = n;
+ }
+ }
+
+ SAFE_FREE(subcntarr);
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,queuecnt);
+
+ for (i = 0; i < queuecnt; i++) {
+ if (queue) SAFE_FREE(queue[i]);
+ }
+
+ SAFE_FREE(queue);
+ SAFE_FREE(status);
+
+ return True;
+}
+
+/****************************************************************************
+ get info level for a server list query
+ ****************************************************************************/
+static BOOL check_server_info(int uLevel, char* id)
+{
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(id,"B16") != 0) return False;
+ break;
+ case 1:
+ if (strcmp(id,"B16BBDz") != 0) return False;
+ break;
+ default:
+ return False;
+ }
+ return True;
+}
+
+struct srv_info_struct
+{
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain;
+ BOOL server_added;
+};
+
+
+/*******************************************************************
+ get server info lists from the files saved by nmbd. Return the
+ number of entries
+ ******************************************************************/
+static int get_server_info(uint32 servertype,
+ struct srv_info_struct **servers,
+ char *domain)
+{
+ int count=0;
+ int alloced=0;
+ char **lines;
+ BOOL local_list_only;
+ int i;
+
+ lines = file_lines_load(lock_path(SERVER_LIST), NULL);
+ if (!lines) {
+ DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
+ return(0);
+ }
+
+ /* request for everything is code for request all servers */
+ if (servertype == SV_TYPE_ALL)
+ servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+
+ local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
+
+ DEBUG(4,("Servertype search: %8x\n",servertype));
+
+ for (i=0;lines[i];i++) {
+ fstring stype;
+ struct srv_info_struct *s;
+ char *ptr = lines[i];
+ BOOL ok = True;
+
+ if (!*ptr) continue;
+
+ if (count == alloced) {
+ struct srv_info_struct *ts;
+
+ alloced += 10;
+ ts = (struct srv_info_struct *)
+ Realloc(*servers,sizeof(**servers)*alloced);
+ if (!ts) {
+ DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
+ return(0);
+ }
+ else *servers = ts;
+ memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
+ }
+ s = &(*servers)[count];
+
+ if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
+ if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
+ if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
+ if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
+ /* this allows us to cope with an old nmbd */
+ pstrcpy(s->domain,global_myworkgroup);
+ }
+
+ if (sscanf(stype,"%X",&s->type) != 1) {
+ DEBUG(4,("r:host file "));
+ ok = False;
+ }
+
+ /* Filter the servers/domains we return based on what was asked for. */
+
+ /* Check to see if we are being asked for a local list only. */
+ if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
+ DEBUG(4,("r: local list only"));
+ ok = False;
+ }
+
+ /* doesn't match up: don't want it */
+ if (!(servertype & s->type)) {
+ DEBUG(4,("r:serv type "));
+ ok = False;
+ }
+
+ if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
+ (s->type & SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4,("s: dom mismatch "));
+ ok = False;
+ }
+
+ if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ {
+ ok = False;
+ }
+
+ /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
+ s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (ok)
+ {
+ DEBUG(4,("**SV** %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ s->server_added = True;
+ count++;
+ }
+ else
+ {
+ DEBUG(4,("%20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ }
+ }
+
+ file_lines_free(lines);
+ return(count);
+}
+
+
+/*******************************************************************
+ fill in a server info structure
+ ******************************************************************/
+static int fill_srv_info(struct srv_info_struct *service,
+ int uLevel, char **buf, int *buflen,
+ char **stringbuf, int *stringspace, char *baseaddr)
+{
+ int struct_len;
+ char* p;
+ char* p2;
+ int l2;
+ int len;
+
+ switch (uLevel) {
+ case 0: struct_len = 16; break;
+ case 1: struct_len = 26; break;
+ default: return -1;
+ }
+
+ if (!buf)
+ {
+ len = 0;
+ switch (uLevel)
+ {
+ case 1:
+ len = strlen(service->comment)+1;
+ break;
+ }
+
+ if (buflen) *buflen = struct_len;
+ if (stringspace) *stringspace = len;
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if (*buflen < struct_len) return -1;
+ if (stringbuf)
+ {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ }
+ else
+ {
+ p2 = p + struct_len;
+ l2 = *buflen - struct_len;
+ }
+ if (!baseaddr) baseaddr = p;
+
+ switch (uLevel)
+ {
+ case 0:
+ push_ascii(p,service->name, 15, STR_TERMINATE);
+ break;
+
+ case 1:
+ push_ascii(p,service->name,15, STR_TERMINATE);
+ SIVAL(p,18,service->type);
+ SIVAL(p,22,PTR_DIFF(p2,baseaddr));
+ len += CopyAndAdvance(&p2,service->comment,&l2);
+ break;
+ }
+
+ if (stringbuf)
+ {
+ *buf = p + struct_len;
+ *buflen -= struct_len;
+ *stringbuf = p2;
+ *stringspace = l2;
+ }
+ else
+ {
+ *buf = p2;
+ *buflen -= len;
+ }
+ return len;
+}
+
+
+static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+{
+ return(strcmp(s1->name,s2->name));
+}
+
+/****************************************************************************
+ view list of servers available (or possibly domains). The info is
+ extracted from lists saved by nmbd on the local host
+ ****************************************************************************/
+static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
+ int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ int buf_len = SVAL(p,2);
+ uint32 servertype = IVAL(p,4);
+ char *p2;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
+ struct srv_info_struct *servers=NULL;
+ int counted=0,total=0;
+ int i,missed;
+ fstring domain;
+ BOOL domain_request;
+ BOOL local_request;
+
+ /* If someone sets all the bits they don't really mean to set
+ DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
+ known servers. */
+
+ if (servertype == SV_TYPE_ALL)
+ servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+
+ /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
+ any other bit (they may just set this bit on it's own) they
+ want all the locally seen servers. However this bit can be
+ set on its own so set the requested servers to be
+ ALL - DOMAIN_ENUM. */
+
+ if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
+
+ domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
+ local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
+
+ p += 8;
+
+ if (!prefix_ok(str1,"WrLehD")) return False;
+ if (!check_server_info(uLevel,str2)) return False;
+
+ DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+ DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+ DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
+
+ if (strcmp(str1, "WrLehDz") == 0) {
+ pull_ascii_fstring(domain, p);
+ } else {
+ fstrcpy(domain, global_myworkgroup);
+ }
+
+ if (lp_browse_list())
+ total = get_server_info(servertype,&servers,domain);
+
+ data_len = fixed_len = string_len = 0;
+ missed = 0;
+
+ if (total > 0)
+ qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+
+ {
+ char *lastname=NULL;
+
+ for (i=0;i<total;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ if (data_len <= buf_len) {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ } else {
+ missed++;
+ }
+ }
+ }
+
+ *rdata_len = fixed_len + string_len;
+ *rdata = REALLOC(*rdata,*rdata_len);
+ memset(*rdata,'\0',*rdata_len);
+
+ p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+
+ {
+ char *lastname=NULL;
+ int count2 = counted;
+ for (i = 0; i < total && count2;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ count2--;
+ }
+ }
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,counted+missed);
+
+ SAFE_FREE(servers);
+
+ DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
+ domain,uLevel,counted,counted+missed));
+
+ return(True);
+}
+
+/****************************************************************************
+ command 0x34 - suspected of being a "Lookup Names" stub api
+ ****************************************************************************/
+static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
+ int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ int buf_len = SVAL(p,2);
+ int counted=0;
+ int missed=0;
+
+ DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
+ str1, str2, p, uLevel, buf_len));
+
+ if (!prefix_ok(str1,"zWrLeh")) return False;
+
+ *rdata_len = 0;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ SSVAL(*rparam,0,0x08AC); /* informational warning message */
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,counted+missed);
+
+ return(True);
+}
+
+/****************************************************************************
+ get info about a share
+ ****************************************************************************/
+static BOOL check_share_info(int uLevel, char* id)
+{
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(id,"B13") != 0) return False;
+ break;
+ case 1:
+ if (strcmp(id,"B13BWz") != 0) return False;
+ break;
+ case 2:
+ if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
+ break;
+ case 91:
+ if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
+ break;
+ default: return False;
+ }
+ return True;
+}
+
+static int fill_share_info(connection_struct *conn, int snum, int uLevel,
+ char** buf, int* buflen,
+ char** stringbuf, int* stringspace, char* baseaddr)
+{
+ int struct_len;
+ char* p;
+ char* p2;
+ int l2;
+ int len;
+
+ switch( uLevel ) {
+ case 0: struct_len = 13; break;
+ case 1: struct_len = 20; break;
+ case 2: struct_len = 40; break;
+ case 91: struct_len = 68; break;
+ default: return -1;
+ }
+
+
+ if (!buf)
+ {
+ len = 0;
+ if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
+ if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
+ if (buflen) *buflen = struct_len;
+ if (stringspace) *stringspace = len;
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if ((*buflen) < struct_len) return -1;
+ if (stringbuf)
+ {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ }
+ else
+ {
+ p2 = p + struct_len;
+ l2 = (*buflen) - struct_len;
+ }
+ if (!baseaddr) baseaddr = p;
+
+ push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
+
+ if (uLevel > 0)
+ {
+ int type;
+ CVAL(p,13) = 0;
+ type = STYPE_DISKTREE;
+ if (lp_print_ok(snum)) type = STYPE_PRINTQ;
+ if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
+ SSVAL(p,14,type); /* device type */
+ SIVAL(p,16,PTR_DIFF(p2,baseaddr));
+ len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
+ }
+
+ if (uLevel > 1)
+ {
+ SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
+ SSVALS(p,22,-1); /* max uses */
+ SSVAL(p,24,1); /* current uses */
+ SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
+ len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
+ memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
+ }
+
+ if (uLevel > 2)
+ {
+ memset(p+40,0,SHPWLEN+2);
+ SSVAL(p,50,0);
+ SIVAL(p,52,0);
+ SSVAL(p,56,0);
+ SSVAL(p,58,0);
+ SIVAL(p,60,0);
+ SSVAL(p,64,0);
+ SSVAL(p,66,0);
+ }
+
+ if (stringbuf)
+ {
+ (*buf) = p + struct_len;
+ (*buflen) -= struct_len;
+ (*stringbuf) = p2;
+ (*stringspace) = l2;
+ }
+ else
+ {
+ (*buf) = p2;
+ (*buflen) -= len;
+ }
+ return len;
+}
+
+static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *netname = skip_string(str2,1);
+ char *p = skip_string(netname,1);
+ int uLevel = SVAL(p,0);
+ int snum = find_service(netname);
+
+ if (snum < 0) return False;
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"zWrLh")) return False;
+ if (!check_share_info(uLevel,str2)) return False;
+
+ *rdata = REALLOC(*rdata,mdrcnt);
+ p = *rdata;
+ *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
+ if (*rdata_len < 0) return False;
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+
+ return(True);
+}
+
+/****************************************************************************
+ view list of shares available
+ ****************************************************************************/
+static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ int buf_len = SVAL(p,2);
+ char *p2;
+ int count=lp_numservices();
+ int total=0,counted=0;
+ BOOL missed = False;
+ int i;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
+
+ if (!prefix_ok(str1,"WrLeh")) return False;
+ if (!check_share_info(uLevel,str2)) return False;
+
+ data_len = fixed_len = string_len = 0;
+ for (i=0;i<count;i++)
+ if (lp_browseable(i) && lp_snum_ok(i))
+ {
+ total++;
+ data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
+ if (data_len <= buf_len)
+ {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ }
+ else
+ missed = True;
+ }
+ *rdata_len = fixed_len + string_len;
+ *rdata = REALLOC(*rdata,*rdata_len);
+ memset(*rdata,0,*rdata_len);
+
+ p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+ for (i = 0; i < count;i++)
+ if (lp_browseable(i) && lp_snum_ok(i))
+ if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
+ break;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,counted);
+ SSVAL(*rparam,6,total);
+
+ DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
+ counted,total,uLevel,
+ buf_len,*rdata_len,mdrcnt));
+ return(True);
+}
+
+/****************************************************************************
+ Add a share
+ ****************************************************************************/
+static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ fstring sharename;
+ fstring comment;
+ pstring pathname;
+ char *command, *cmdname;
+ uint offset;
+ int snum;
+ int res = ERRunsup;
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,RAP_WShareAdd_REQ)) return False;
+ if (!check_share_info(uLevel,str2)) return False;
+ if (uLevel != 2) return False;
+
+ pull_ascii_fstring(sharename,data);
+ snum = find_service(sharename);
+ if (snum >= 0) { /* already exists */
+ res = ERRfilexists;
+ goto error_exit;
+ }
+
+ /* only support disk share adds */
+ if (SVAL(data,14)!=STYPE_DISKTREE) return False;
+
+ offset = IVAL(data, 16);
+ if (offset >= mdrcnt) {
+ res = ERRinvalidparam;
+ goto error_exit;
+ }
+ pull_ascii_fstring(comment, offset? (data+offset) : "");
+
+ offset = IVAL(data, 26);
+ if (offset >= mdrcnt) {
+ res = ERRinvalidparam;
+ goto error_exit;
+ }
+ pull_ascii_pstring(pathname, offset? (data+offset) : "");
+
+ string_replace(sharename, '"', ' ');
+ string_replace(pathname, '"', ' ');
+ string_replace(comment, '"', ' ');
+
+ cmdname = lp_add_share_cmd();
+
+ if (!cmdname || *cmdname == '\0') return False;
+
+ asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
+ lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
+
+ if (command) {
+ DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
+ if ((res = smbrun(command, NULL)) != 0) {
+ DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
+ SAFE_FREE(command);
+ res = ERRnoaccess;
+ goto error_exit;
+ } else {
+ SAFE_FREE(command);
+ message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False);
+ }
+ } else return False;
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+ *rdata_len = 0;
+
+ return True;
+
+ error_exit:
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ *rdata_len = 0;
+ SSVAL(*rparam,0,res);
+ SSVAL(*rparam,2,0);
+ return True;
+
+}
+
+/****************************************************************************
+ view list of groups available
+ ****************************************************************************/
+static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
+ int count=0;
+
+ if (!prefix_ok(str1,"WrLeh")) return False;
+
+ /* check it's a supported variant */
+ switch( uLevel )
+ {
+ case 0:
+ p2 = "B21";
+ break;
+ default:
+ return False;
+ }
+
+ if (strcmp(p2,str2) != 0) return False;
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+
+ /* XXXX we need a real SAM database some day */
+ pstrcpy(p,"Users"); p += 21; count++;
+ pstrcpy(p,"Domain Users"); p += 21; count++;
+ pstrcpy(p,"Guests"); p += 21; count++;
+ pstrcpy(p,"Domain Guests"); p += 21; count++;
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ SSVAL(*rparam,4,count); /* is this right?? */
+ SSVAL(*rparam,6,count); /* is this right?? */
+
+ DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count));
+
+ return(True);
+}
+
+/****************************************************************************
+ view list of groups available
+ ****************************************************************************/
+static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
+ int count=0;
+
+ if (!prefix_ok(str1,"WrLeh")) return False;
+
+ /* check it's a supported variant */
+ switch( uLevel )
+ {
+ case 0:
+ p2 = "B21";
+ break;
+ default:
+ return False;
+ }
+
+ if (strcmp(p2,str2) != 0) return False;
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+
+ /* XXXX we need a real SAM database some day */
+ pstrcpy(p,"Users"); p += 21; count++;
+ pstrcpy(p,"Domain Users"); p += 21; count++;
+ pstrcpy(p,"Guests"); p += 21; count++;
+ pstrcpy(p,"Domain Guests"); p += 21; count++;
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ SSVAL(*rparam,4,count); /* is this right?? */
+ SSVAL(*rparam,6,count); /* is this right?? */
+
+ DEBUG(3,("api_RNetUserEnum gave %d entries\n", count));
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+ get the time of day info
+ ****************************************************************************/
+static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *p;
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 21;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+
+ {
+ struct tm *t;
+ time_t unixdate = time(NULL);
+
+ put_dos_date3(p,0,unixdate); /* this is the time that is looked at
+ by NT in a "net time" operation,
+ it seems to ignore the one below */
+
+ /* the client expects to get localtime, not GMT, in this bit
+ (I think, this needs testing) */
+ t = LocalTime(&unixdate);
+
+ SIVAL(p,4,0); /* msecs ? */
+ CVAL(p,8) = t->tm_hour;
+ CVAL(p,9) = t->tm_min;
+ CVAL(p,10) = t->tm_sec;
+ CVAL(p,11) = 0; /* hundredths of seconds */
+ SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
+ SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
+ CVAL(p,16) = t->tm_mday;
+ CVAL(p,17) = t->tm_mon + 1;
+ SSVAL(p,18,1900+t->tm_year);
+ CVAL(p,20) = t->tm_wday;
+ }
+
+
+ return(True);
+}
+
+/****************************************************************************
+ Set the user password.
+*****************************************************************************/
+
+static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *p = skip_string(param+2,2);
+ fstring user;
+ fstring pass1,pass2;
+
+ struct passwd *passwd;
+
+ pull_ascii_fstring(user,p);
+
+ p = skip_string(p,1);
+
+ memset(pass1,'\0',sizeof(pass1));
+ memset(pass2,'\0',sizeof(pass2));
+ memcpy(pass1,p,16);
+ memcpy(pass2,p+16,16);
+
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_badpass);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ DEBUG(3,("Set password for <%s>\n",user));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ passwd = Get_Pwnam_Modify( user );
+
+ /*
+ * Attempt to verify the old password against smbpasswd entries
+ * Win98 clients send old and new password in plaintext for this call.
+ */
+
+ {
+ fstring saved_pass2;
+ SAM_ACCOUNT *sampass=NULL;
+
+ /*
+ * Save the new password as change_oem_password overwrites it
+ * with zeros.
+ */
+
+ fstrcpy(saved_pass2, pass2);
+
+ if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
+ change_oem_password(sampass,pass2))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+
+ /*
+ * If unix password sync was requested, attempt to change
+ * the /etc/passwd database also. Return failure if this cannot
+ * be done.
+ */
+
+ if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
+ SSVAL(*rparam,0,NERR_badpass);
+ }
+ pdb_free_sam(&sampass);
+ }
+
+
+ /*
+ * If the above failed, attempt the plaintext password change.
+ * This tests against the /etc/passwd database only.
+ */
+
+ if(SVAL(*rparam,0) != NERR_Success)
+ {
+ if NT_STATUS_IS_OK(pass_check(passwd, user, pass1,
+ strlen(pass1), NULL, False))
+ {
+ if (chgpasswd(user,pass1,pass2,False)) {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+ }
+ }
+
+ /*
+ * If the plaintext change failed, attempt
+ * the old encrypted method. NT will generate this
+ * after trying the samr method. Note that this
+ * method is done as a last resort as this
+ * password change method loses the NT password hash
+ * and cannot change the UNIX password as no plaintext
+ * is received.
+ */
+
+ if(SVAL(*rparam,0) != NERR_Success)
+ {
+ SAM_ACCOUNT *hnd = NULL;
+
+ if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
+ change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+ pdb_free_sam(&hnd);
+ }
+
+
+ memset((char *)pass1,'\0',sizeof(fstring));
+ memset((char *)pass2,'\0',sizeof(fstring));
+
+ return(True);
+}
+
+/****************************************************************************
+ Set the user password (SamOEM version - gets plaintext).
+****************************************************************************/
+
+static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ fstring user;
+ char *p = param + 2;
+ *rparam_len = 2;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_badpass);
+
+ /*
+ * Check the parameter definition is correct.
+ */
+ if(!strequal(param + 2, "zsT")) {
+ DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
+ return False;
+ }
+ p = skip_string(p, 1);
+
+ if(!strequal(p, "B516B16")) {
+ DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
+ return False;
+ }
+ p = skip_string(p,1);
+
+ p += pull_ascii_fstring(user,p);
+
+ DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam_Modify( user );
+
+ if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ delete a print job
+ Form: <W> <>
+ ****************************************************************************/
+static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int function = SVAL(param,0);
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int jobid, errcode;
+ extern struct current_user current_user;
+ WERROR werr = WERR_OK;
+
+ jobid = SVAL(p,0);
+
+ /* check it's a supported varient */
+ if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
+ return(False);
+
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ *rdata_len = 0;
+
+ if (!print_job_exists(jobid)) {
+ errcode = NERR_JobNotFound;
+ goto out;
+ }
+
+ errcode = NERR_notsupported;
+
+ switch (function) {
+ case 81: /* delete */
+ if (print_job_delete(&current_user, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ case 82: /* pause */
+ if (print_job_pause(&current_user, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ case 83: /* resume */
+ if (print_job_resume(&current_user, jobid, &werr))
+ errcode = NERR_Success;
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(werr))
+ errcode = W_ERROR_V(werr);
+
+ out:
+ SSVAL(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+/****************************************************************************
+ Purge a print queue - or pause or resume it.
+ ****************************************************************************/
+static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ int function = SVAL(param,0);
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *QueueName = skip_string(str2,1);
+ int errcode = NERR_notsupported;
+ int snum;
+ WERROR werr = WERR_OK;
+ extern struct current_user current_user;
+
+ /* check it's a supported varient */
+ if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
+ return(False);
+
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ *rdata_len = 0;
+
+ snum = print_queue_snum(QueueName);
+
+ if (snum == -1) {
+ errcode = NERR_JobNotFound;
+ goto out;
+ }
+
+ switch (function) {
+ case 74: /* Pause queue */
+ if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
+ break;
+ case 75: /* Resume queue */
+ if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
+ break;
+ case 103: /* Purge */
+ if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
+
+ out:
+ SSVAL(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+
+/****************************************************************************
+ set the property of a print job (undocumented?)
+ ? function = 0xb -> set name of print job
+ ? function = 0x6 -> move print job up/down
+ Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
+ or <WWsTP> <WB21BB16B10zWWzDDz>
+****************************************************************************/
+static int check_printjob_info(struct pack_desc* desc,
+ int uLevel, char* id)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0: desc->format = "W"; break;
+ case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
+ case 2: desc->format = "WWzWWDDzz"; break;
+ case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
+ case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
+ default: return False;
+ }
+ if (strcmp(desc->format,id) != 0) return False;
+ return True;
+}
+
+static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ struct pack_desc desc;
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int jobid;
+ int uLevel = SVAL(p,2);
+ int function = SVAL(p,4);
+ int place, errcode;
+
+ jobid = SVAL(p,0);
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 0;
+
+ /* check it's a supported varient */
+ if ((strcmp(str1,"WWsTP")) ||
+ (!check_printjob_info(&desc,uLevel,str2)))
+ return(False);
+
+ if (!print_job_exists(jobid)) {
+ errcode=NERR_JobNotFound;
+ goto out;
+ }
+
+ errcode = NERR_notsupported;
+
+ switch (function) {
+ case 0x6:
+ /* change job place in the queue,
+ data gives the new place */
+ place = SVAL(data,0);
+ if (print_job_set_place(jobid, place)) {
+ errcode=NERR_Success;
+ }
+ break;
+
+ case 0xb:
+ /* change print job name, data gives the name */
+ if (print_job_set_name(jobid, data)) {
+ errcode=NERR_Success;
+ }
+ break;
+
+ default:
+ return False;
+ }
+
+ out:
+ SSVALS(*rparam,0,errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
+}
+
+
+/****************************************************************************
+ get info about the server
+ ****************************************************************************/
+static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
+ int struct_len;
+
+ DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1,"WrLh")) return False;
+ switch( uLevel ) {
+ case 0:
+ if (strcmp(str2,"B16") != 0) return False;
+ struct_len = 16;
+ break;
+ case 1:
+ if (strcmp(str2,"B16BBDz") != 0) return False;
+ struct_len = 26;
+ break;
+ case 2:
+ if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
+ != 0) return False;
+ struct_len = 134;
+ break;
+ case 3:
+ if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
+ != 0) return False;
+ struct_len = 144;
+ break;
+ case 20:
+ if (strcmp(str2,"DN") != 0) return False;
+ struct_len = 6;
+ break;
+ case 50:
+ if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
+ struct_len = 42;
+ break;
+ default: return False;
+ }
+
+ *rdata_len = mdrcnt;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ p = *rdata;
+ p2 = p + struct_len;
+ if (uLevel != 20) {
+ srvstr_push(NULL, p,local_machine,16,
+ STR_ASCII|STR_UPPER|STR_TERMINATE);
+ }
+ p += 16;
+ if (uLevel > 0)
+ {
+ struct srv_info_struct *servers=NULL;
+ int i,count;
+ pstring comment;
+ uint32 servertype= lp_default_server_announce();
+
+ pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+
+ if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
+ for (i=0;i<count;i++)
+ if (strequal(servers[i].name,local_machine))
+ {
+ servertype = servers[i].type;
+ pstrcpy(comment,servers[i].comment);
+ }
+ }
+ SAFE_FREE(servers);
+
+ SCVAL(p,0,lp_major_announce_version());
+ SCVAL(p,1,lp_minor_announce_version());
+ SIVAL(p,2,servertype);
+
+ if (mdrcnt == struct_len) {
+ SIVAL(p,6,0);
+ } else {
+ SIVAL(p,6,PTR_DIFF(p2,*rdata));
+ standard_sub_conn(conn,comment);
+ StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
+ p2 = skip_string(p2,1);
+ }
+ }
+ if (uLevel > 1)
+ {
+ return False; /* not yet implemented */
+ }
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,*rdata_len);
+
+ return(True);
+}
+
+
+/****************************************************************************
+ get info about the server
+ ****************************************************************************/
+static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ char *p2;
+ extern userdom_struct current_user_info;
+ int level = SVAL(p,0);
+
+ DEBUG(4,("NetWkstaGetInfo level %d\n",level));
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ /* check it's a supported varient */
+ if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
+ return(False);
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+ p2 = p + 22;
+
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
+ pstrcpy(p2,local_machine);
+ strupper(p2);
+ p2 = skip_string(p2,1);
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata));
+ pstrcpy(p2,current_user_info.smb_name);
+ p2 = skip_string(p2,1);
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
+ pstrcpy(p2,global_myworkgroup);
+ strupper(p2);
+ p2 = skip_string(p2,1);
+ p += 4;
+
+ SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
+ SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
+ p += 2;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata));
+ pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
+ p2 = skip_string(p2,1);
+ p += 4;
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
+ pstrcpy(p2,"");
+ p2 = skip_string(p2,1);
+ p += 4;
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ SSVAL(*rparam,4,*rdata_len);
+
+ return(True);
+}
+
+/****************************************************************************
+ get info about a user
+
+ struct user_info_11 {
+ char usri11_name[21]; 0-20
+ char usri11_pad; 21
+ char *usri11_comment; 22-25
+ char *usri11_usr_comment; 26-29
+ unsigned short usri11_priv; 30-31
+ unsigned long usri11_auth_flags; 32-35
+ long usri11_password_age; 36-39
+ char *usri11_homedir; 40-43
+ char *usri11_parms; 44-47
+ long usri11_last_logon; 48-51
+ long usri11_last_logoff; 52-55
+ unsigned short usri11_bad_pw_count; 56-57
+ unsigned short usri11_num_logons; 58-59
+ char *usri11_logon_server; 60-63
+ unsigned short usri11_country_code; 64-65
+ char *usri11_workstations; 66-69
+ unsigned long usri11_max_storage; 70-73
+ unsigned short usri11_units_per_week; 74-75
+ unsigned char *usri11_logon_hours; 76-79
+ unsigned short usri11_code_page; 80-81
+ };
+
+where:
+
+ usri11_name specifies the user name for which information is retireved
+
+ usri11_pad aligns the next data structure element to a word boundary
+
+ usri11_comment is a null terminated ASCII comment
+
+ usri11_user_comment is a null terminated ASCII comment about the user
+
+ usri11_priv specifies the level of the privilege assigned to the user.
+ The possible values are:
+
+Name Value Description
+USER_PRIV_GUEST 0 Guest privilege
+USER_PRIV_USER 1 User privilege
+USER_PRV_ADMIN 2 Administrator privilege
+
+ usri11_auth_flags specifies the account operator privileges. The
+ possible values are:
+
+Name Value Description
+AF_OP_PRINT 0 Print operator
+
+
+Leach, Naik [Page 28]
+
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+AF_OP_COMM 1 Communications operator
+AF_OP_SERVER 2 Server operator
+AF_OP_ACCOUNTS 3 Accounts operator
+
+
+ usri11_password_age specifies how many seconds have elapsed since the
+ password was last changed.
+
+ usri11_home_dir points to a null terminated ASCII string that contains
+ the path name of the user's home directory.
+
+ usri11_parms points to a null terminated ASCII string that is set
+ aside for use by applications.
+
+ usri11_last_logon specifies the time when the user last logged on.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970.
+
+ usri11_last_logoff specifies the time when the user last logged off.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970. A value of 0 means the last logoff
+ time is unknown.
+
+ usri11_bad_pw_count specifies the number of incorrect passwords
+ entered since the last successful logon.
+
+ usri11_log1_num_logons specifies the number of times this user has
+ logged on. A value of -1 means the number of logons is unknown.
+
+ usri11_logon_server points to a null terminated ASCII string that
+ contains the name of the server to which logon requests are sent.
+ A null string indicates logon requests should be sent to the
+ domain controller.
+
+ usri11_country_code specifies the country code for the user's language
+ of choice.
+
+ usri11_workstations points to a null terminated ASCII string that
+ contains the names of workstations the user may log on from.
+ There may be up to 8 workstations, with the names separated by
+ commas. A null strings indicates there are no restrictions.
+
+ usri11_max_storage specifies the maximum amount of disk space the user
+ can occupy. A value of 0xffffffff indicates there are no
+ restrictions.
+
+ usri11_units_per_week specifies the equal number of time units into
+ which a week is divided. This value must be equal to 168.
+
+ usri11_logon_hours points to a 21 byte (168 bits) string that
+ specifies the time during which the user can log on. Each bit
+ represents one unique hour in a week. The first bit (bit 0, word
+ 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
+
+
+
+Leach, Naik [Page 29]
+
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+ Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
+ are no restrictions.
+
+ usri11_code_page specifies the code page for the user's language of
+ choice
+
+All of the pointers in this data structure need to be treated
+specially. The pointer is a 32 bit pointer. The higher 16 bits need
+to be ignored. The converter word returned in the parameters section
+needs to be subtracted from the lower 16 bits to calculate an offset
+into the return buffer where this ASCII string resides.
+
+There is no auxiliary data in the response.
+
+ ****************************************************************************/
+
+#define usri11_name 0
+#define usri11_pad 21
+#define usri11_comment 22
+#define usri11_usr_comment 26
+#define usri11_full_name 30
+#define usri11_priv 34
+#define usri11_auth_flags 36
+#define usri11_password_age 40
+#define usri11_homedir 44
+#define usri11_parms 48
+#define usri11_last_logon 52
+#define usri11_last_logoff 56
+#define usri11_bad_pw_count 60
+#define usri11_num_logons 62
+#define usri11_logon_server 64
+#define usri11_country_code 68
+#define usri11_workstations 70
+#define usri11_max_storage 74
+#define usri11_units_per_week 78
+#define usri11_logon_hours 80
+#define usri11_code_page 84
+#define usri11_end 86
+
+#define USER_PRIV_GUEST 0
+#define USER_PRIV_USER 1
+#define USER_PRIV_ADMIN 2
+
+#define AF_OP_PRINT 0
+#define AF_OP_COMM 1
+#define AF_OP_SERVER 2
+#define AF_OP_ACCOUNTS 3
+
+
+static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *UserName = skip_string(str2,1);
+ char *p = skip_string(UserName,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
+
+ /* get NIS home of a previously validated user - simeon */
+ /* With share level security vuid will always be zero.
+ Don't depend on vuser being non-null !!. JRA */
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if(vuser != NULL)
+ DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
+ vuser->user.unix_name));
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
+
+ /* check it's a supported variant */
+ if (strcmp(str1,"zWrLh") != 0) return False;
+ switch( uLevel )
+ {
+ case 0: p2 = "B21"; break;
+ case 1: p2 = "B21BB16DWzzWz"; break;
+ case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
+ case 10: p2 = "B21Bzzz"; break;
+ case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
+ default: return False;
+ }
+
+ if (strcmp(p2,str2) != 0) return False;
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+ p2 = p + usri11_end;
+
+ memset(p,0,21);
+ fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
+
+ if (uLevel > 0)
+ {
+ SCVAL(p,usri11_pad,0); /* padding - 1 byte */
+ *p2 = 0;
+ }
+ if (uLevel >= 10)
+ {
+ SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
+ pstrcpy(p2,"Comment");
+ p2 = skip_string(p2,1);
+
+ SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
+ pstrcpy(p2,"UserComment");
+ p2 = skip_string(p2,1);
+
+ /* EEK! the cifsrap.txt doesn't have this in!!!! */
+ SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
+ pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
+ p2 = skip_string(p2,1);
+ }
+
+ if (uLevel == 11) /* modelled after NTAS 3.51 reply */
+ {
+ SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
+ SIVALS(p,usri11_password_age,-1); /* password age */
+ SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
+ pstrcpy(p2, lp_logon_home());
+ standard_sub_conn(conn, p2);
+ p2 = skip_string(p2,1);
+ SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
+ pstrcpy(p2,"");
+ p2 = skip_string(p2,1);
+ SIVAL(p,usri11_last_logon,0); /* last logon */
+ SIVAL(p,usri11_last_logoff,0); /* last logoff */
+ SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
+ SSVALS(p,usri11_num_logons,-1); /* num logons */
+ SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
+ pstrcpy(p2,"\\\\*");
+ p2 = skip_string(p2,1);
+ SSVAL(p,usri11_country_code,0); /* country code */
+
+ SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
+ pstrcpy(p2,"");
+ p2 = skip_string(p2,1);
+
+ SIVALS(p,usri11_max_storage,-1); /* max storage */
+ SSVAL(p,usri11_units_per_week,168); /* units per week */
+ SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
+
+ /* a simple way to get logon hours at all times. */
+ memset(p2,0xff,21);
+ SCVAL(p2,21,0); /* fix zero termination */
+ p2 = skip_string(p2,1);
+
+ SSVAL(p,usri11_code_page,0); /* code page */
+ }
+ if (uLevel == 1 || uLevel == 2)
+ {
+ memset(p+22,' ',16); /* password */
+ SIVALS(p,38,-1); /* password age */
+ SSVAL(p,42,
+ conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
+ pstrcpy(p2,lp_logon_home());
+ standard_sub_conn(conn, p2);
+ p2 = skip_string(p2,1);
+ SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
+ *p2++ = 0;
+ SSVAL(p,52,0); /* flags */
+ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
+ pstrcpy(p2,lp_logon_script());
+ standard_sub_conn( conn, p2 );
+ p2 = skip_string(p2,1);
+ if (uLevel == 2)
+ {
+ SIVAL(p,60,0); /* auth_flags */
+ SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
+ pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
+ p2 = skip_string(p2,1);
+ SIVAL(p,68,0); /* urs_comment */
+ SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
+ pstrcpy(p2,"");
+ p2 = skip_string(p2,1);
+ SIVAL(p,76,0); /* workstations */
+ SIVAL(p,80,0); /* last_logon */
+ SIVAL(p,84,0); /* last_logoff */
+ SIVALS(p,88,-1); /* acct_expires */
+ SIVALS(p,92,-1); /* max_storage */
+ SSVAL(p,96,168); /* units_per_week */
+ SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
+ memset(p2,-1,21);
+ p2 += 21;
+ SSVALS(p,102,-1); /* bad_pw_count */
+ SSVALS(p,104,-1); /* num_logons */
+ SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
+ pstrcpy(p2,"\\\\%L");
+ standard_sub_conn(conn, p2);
+ p2 = skip_string(p2,1);
+ SSVAL(p,110,49); /* country_code */
+ SSVAL(p,112,860); /* code page */
+ }
+ }
+
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+
+ return(True);
+}
+
+/*******************************************************************
+ get groups that a user is a member of
+ ******************************************************************/
+static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *UserName = skip_string(str2,1);
+ char *p = skip_string(UserName,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
+ int count=0;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zWrLeh") != 0) return False;
+ switch( uLevel ) {
+ case 0: p2 = "B21"; break;
+ default: return False;
+ }
+ if (strcmp(p2,str2) != 0) return False;
+
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ p = *rdata;
+
+ /* XXXX we need a real SAM database some day */
+ pstrcpy(p,"Users"); p += 21; count++;
+ pstrcpy(p,"Domain Users"); p += 21; count++;
+ pstrcpy(p,"Guests"); p += 21; count++;
+ pstrcpy(p,"Domain Guests"); p += 21; count++;
+
+ *rdata_len = PTR_DIFF(p,*rdata);
+
+ SSVAL(*rparam,4,count); /* is this right?? */
+ SSVAL(*rparam,6,count); /* is this right?? */
+
+ return(True);
+}
+
+
+static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ struct pack_desc desc;
+ char* name;
+
+ uLevel = SVAL(p,0);
+ name = p + 2;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"OOWb54WrLh") != 0) return False;
+ if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.subformat = NULL;
+ desc.format = str2;
+
+ if (init_package(&desc,1,0))
+ {
+ PACKI(&desc,"W",0); /* code */
+ PACKS(&desc,"B21",name); /* eff. name */
+ PACKS(&desc,"B",""); /* pad */
+ PACKI(&desc,"W",
+ conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ PACKI(&desc,"D",0); /* auth flags XXX */
+ PACKI(&desc,"W",0); /* num logons */
+ PACKI(&desc,"W",0); /* bad pw count */
+ PACKI(&desc,"D",0); /* last logon */
+ PACKI(&desc,"D",-1); /* last logoff */
+ PACKI(&desc,"D",-1); /* logoff time */
+ PACKI(&desc,"D",-1); /* kickoff time */
+ PACKI(&desc,"D",0); /* password age */
+ PACKI(&desc,"D",0); /* password can change */
+ PACKI(&desc,"D",-1); /* password must change */
+ {
+ fstring mypath;
+ fstrcpy(mypath,"\\\\");
+ fstrcat(mypath,local_machine);
+ strupper(mypath);
+ PACKS(&desc,"z",mypath); /* computer */
+ }
+ PACKS(&desc,"z",global_myworkgroup);/* domain */
+
+/* JHT - By calling lp_logon_script() and standard_sub() we have */
+/* made sure all macros are fully substituted and available */
+ {
+ pstring logon_script;
+ pstrcpy(logon_script,lp_logon_script());
+ standard_sub_conn( conn, logon_script );
+ PACKS(&desc,"z", logon_script); /* script path */
+ }
+/* End of JHT mods */
+
+ PACKI(&desc,"D",0x00000000); /* reserved */
+ }
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+
+/****************************************************************************
+ api_WAccessGetUserPerms
+ ****************************************************************************/
+static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *user = skip_string(str2,1);
+ char *resource = skip_string(user,1);
+
+ DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zzh") != 0) return False;
+ if (strcmp(str2,"") != 0) return False;
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,0); /* errorcode */
+ SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam,4,0x7f); /* permission flags */
+
+ return(True);
+}
+
+/****************************************************************************
+ api_WPrintJobEnumerate
+ ****************************************************************************/
+static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ int count;
+ int i;
+ int snum;
+ int job;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+ char *tmpdata=NULL;
+
+ uLevel = SVAL(p,2);
+
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
+
+ DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WWrLh") != 0) return False;
+ if (!check_printjob_info(&desc,uLevel,str2)) return False;
+
+ job = SVAL(p,0);
+ snum = print_job_snum(job);
+
+ if (snum < 0 || !VALID_SNUM(snum)) return(False);
+
+ count = print_queue_status(snum,&queue,&status);
+ for (i = 0; i < count; i++) {
+ if (queue[i].job == job) break;
+ }
+
+ if (mdrcnt > 0) {
+ *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *)malloc ( desc.buflen );
+ }
+
+ if (init_package(&desc,1,0)) {
+ if (i < count) {
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
+ *rdata_len = desc.usedlen;
+ }
+ else {
+ desc.errcode = NERR_JobNotFound;
+ *rdata_len = 0;
+ }
+ }
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ SAFE_FREE(queue);
+ SAFE_FREE(tmpdata);
+
+ DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ char* name = p;
+ int uLevel;
+ int count;
+ int i, succnt=0;
+ int snum;
+ struct pack_desc desc;
+ print_queue_struct *queue=NULL;
+ print_status_struct status;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
+
+ p = skip_string(p,1);
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zWrLeh") != 0) return False;
+ if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
+ if (!check_printjob_info(&desc,uLevel,str2)) return False;
+
+ snum = lp_servicenumber(name);
+ if (snum < 0 && pcap_printername_ok(name,NULL)) {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0) {
+ lp_add_printer(name,pnum);
+ snum = lp_servicenumber(name);
+ }
+ }
+
+ if (snum < 0 || !VALID_SNUM(snum)) return(False);
+
+ count = print_queue_status(snum,&queue,&status);
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+
+ if (init_package(&desc,count,0)) {
+ succnt = 0;
+ for (i = 0; i < count; i++) {
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
+ if (desc.errcode == NERR_Success) succnt = i+1;
+ }
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,count);
+
+ SAFE_FREE(queue);
+
+ DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+static int check_printdest_info(struct pack_desc* desc,
+ int uLevel, char* id)
+{
+ desc->subformat = NULL;
+ switch( uLevel ) {
+ case 0: desc->format = "B9"; break;
+ case 1: desc->format = "B9B21WWzW"; break;
+ case 2: desc->format = "z"; break;
+ case 3: desc->format = "zzzWWzzzWW"; break;
+ default: return False;
+ }
+ if (strcmp(desc->format,id) != 0) return False;
+ return True;
+}
+
+static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
+ struct pack_desc* desc)
+{
+ char buf[100];
+ strncpy(buf,SERVICE(snum),sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0;
+ strupper(buf);
+ if (uLevel <= 1) {
+ PACKS(desc,"B9",buf); /* szName */
+ if (uLevel == 1) {
+ PACKS(desc,"B21",""); /* szUserName */
+ PACKI(desc,"W",0); /* uJobId */
+ PACKI(desc,"W",0); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKI(desc,"W",0); /* time */
+ }
+ }
+ if (uLevel == 2 || uLevel == 3) {
+ PACKS(desc,"z",buf); /* pszPrinterName */
+ if (uLevel == 3) {
+ PACKS(desc,"z",""); /* pszUserName */
+ PACKS(desc,"z",""); /* pszLogAddr */
+ PACKI(desc,"W",0); /* uJobId */
+ PACKI(desc,"W",0); /* fsStatus */
+ PACKS(desc,"z",""); /* pszStatus */
+ PACKS(desc,"z",""); /* pszComment */
+ PACKS(desc,"z","NULL"); /* pszDrivers */
+ PACKI(desc,"W",0); /* time */
+ PACKI(desc,"W",0); /* pad1 */
+ }
+ }
+}
+
+static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ char* PrinterName = p;
+ int uLevel;
+ struct pack_desc desc;
+ int snum;
+ char *tmpdata=NULL;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ p = skip_string(p,1);
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"zWrLh") != 0) return False;
+ if (!check_printdest_info(&desc,uLevel,str2)) return False;
+
+ snum = lp_servicenumber(PrinterName);
+ if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0) {
+ lp_add_printer(PrinterName,pnum);
+ snum = lp_servicenumber(PrinterName);
+ }
+ }
+
+ if (snum < 0) {
+ *rdata_len = 0;
+ desc.errcode = NERR_DestNotFound;
+ desc.neededlen = 0;
+ }
+ else {
+ if (mdrcnt > 0) {
+ *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ } else {
+ /*
+ * Don't return data but need to get correct length
+ * init_package will return wrong size if buflen=0
+ */
+ desc.buflen = getlen(desc.format);
+ desc.base = tmpdata = (char *)malloc ( desc.buflen );
+ }
+ if (init_package(&desc,1,0)) {
+ fill_printdest_info(conn,snum,uLevel,&desc);
+ }
+ *rdata_len = desc.usedlen;
+ }
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,desc.neededlen);
+
+ DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
+ SAFE_FREE(tmpdata);
+ return(True);
+}
+
+static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ int queuecnt;
+ int i, n, succnt=0;
+ struct pack_desc desc;
+ int services = lp_numservices();
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) return False;
+ if (!check_printdest_info(&desc,uLevel,str2)) return False;
+
+ queuecnt = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
+ queuecnt++;
+
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc,queuecnt,0)) {
+ succnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++) {
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
+ fill_printdest_info(conn,i,uLevel,&desc);
+ n++;
+ if (desc.errcode == NERR_Success) succnt = n;
+ }
+ }
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,queuecnt);
+
+ DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) return False;
+ if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
+
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B41","NULL");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) return False;
+ if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
+
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B13","lpd");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,"WrLeh") != 0) return False;
+ if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
+
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ memset((char *)&desc,'\0',sizeof(desc));
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc,1,0)) {
+ PACKS(&desc,"B13","lp0");
+ }
+
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,succnt);
+ SSVAL(*rparam,6,1);
+
+ DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
+ return(True);
+}
+
+struct session_info {
+ char machine[31];
+ char username[24];
+ char clitype[24];
+ int opens;
+ int time;
+};
+
+struct sessions_info {
+ int count;
+ struct session_info *session_list;
+};
+
+static int gather_sessioninfo(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct sessions_info *sinfo = state;
+ struct session_info *curinfo = NULL;
+ struct sessionid *sessid = (struct sessionid *) dbuf.dptr;
+
+ sinfo->count += 1;
+ sinfo->session_list = REALLOC(sinfo->session_list, sinfo->count * sizeof(struct session_info));
+
+ curinfo = &(sinfo->session_list[sinfo->count - 1]);
+
+ safe_strcpy(curinfo->machine, sessid->remote_machine,
+ sizeof(curinfo->machine));
+ safe_strcpy(curinfo->username, uidtoname(sessid->uid),
+ sizeof(curinfo->username));
+ DEBUG(7,("gather_sessioninfo session from %s@%s\n",
+ curinfo->username, curinfo->machine));
+ return 0;
+}
+
+/****************************************************************************
+ List open sessions
+ ****************************************************************************/
+static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+
+{
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int uLevel;
+ struct pack_desc desc;
+ struct sessions_info sinfo;
+ int i;
+
+ memset((char *)&desc,'\0',sizeof(desc));
+
+ uLevel = SVAL(p,0);
+
+ DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
+ DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
+ DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
+
+ /* check it's a supported varient */
+ if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False;
+ if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False;
+
+ sinfo.count = 0;
+ sinfo.session_list = NULL;
+
+ if (!session_traverse(gather_sessioninfo, &sinfo)) {
+ DEBUG(4,("RNetSessionEnum session_traverse failed\n"));
+ return False;
+ }
+
+ if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+ memset((char *)&desc,'\0',sizeof(desc));
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (!init_package(&desc,sinfo.count,0)) {
+ return False;
+ }
+
+ for(i=0; i<sinfo.count; i++) {
+ PACKS(&desc, "z", sinfo.session_list[i].machine);
+ PACKS(&desc, "z", sinfo.session_list[i].username);
+ PACKI(&desc, "W", 1); /* num conns */
+ PACKI(&desc, "W", 0); /* num opens */
+ PACKI(&desc, "W", 1); /* num users */
+ PACKI(&desc, "D", 0); /* session time */
+ PACKI(&desc, "D", 0); /* idle time */
+ PACKI(&desc, "D", 0); /* flags */
+ PACKS(&desc, "z", "Unknown Client"); /* client type string */
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0); /* converter */
+ SSVAL(*rparam,4,sinfo.count); /* count */
+
+ DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
+ return True;
+}
+
+
+/****************************************************************************
+ The buffer was too small
+ ****************************************************************************/
+
+static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ *rparam_len = MIN(*rparam_len,mprcnt);
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_BufTooSmall);
+
+ DEBUG(3,("Supplied buffer too small in API command\n"));
+
+ return(True);
+}
+
+
+/****************************************************************************
+ The request is not supported
+ ****************************************************************************/
+
+static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam,0,NERR_notsupported);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ DEBUG(3,("Unsupported API command\n"));
+
+ return(True);
+}
+
+
+
+
+struct
+{
+ char *name;
+ int id;
+ BOOL (*fn)(connection_struct *,uint16,char *,char *,
+ int,int,char **,char **,int *,int *);
+ int flags;
+} api_commands[] = {
+ {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0},
+ {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0},
+ {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0},
+ {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum,0},
+ {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0},
+ {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0},
+ {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0},
+ {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0},
+ {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0},
+ {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0},
+ {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0},
+ {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0},
+ {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0},
+ {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0},
+ {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0},
+ {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0},
+ {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0},
+ {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0},
+ {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0},
+ {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0},
+ {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0},
+ {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0},
+ {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0},
+ {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0},
+ {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0},
+ {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
+ {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0},
+ {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0},
+ {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0},
+ {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0},
+ {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
+ {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0},
+ {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
+ {NULL, -1, api_Unsupported,0}};
+
+
+/****************************************************************************
+ Handle remote api calls
+ ****************************************************************************/
+
+int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
+ int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+{
+ int api_command;
+ char *rdata = NULL;
+ char *rparam = NULL;
+ int rdata_len = 0;
+ int rparam_len = 0;
+ BOOL reply=False;
+ int i;
+
+ if (!params) {
+ DEBUG(0,("ERROR: NULL params in api_reply()\n"));
+ return 0;
+ }
+
+ api_command = SVAL(params,0);
+
+ DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
+ api_command,
+ params+2,
+ skip_string(params+2,1),
+ tdscnt,tpscnt,mdrcnt,mprcnt));
+
+ for (i=0;api_commands[i].name;i++) {
+ if (api_commands[i].id == api_command && api_commands[i].fn) {
+ DEBUG(3,("Doing %s\n",api_commands[i].name));
+ break;
+ }
+ }
+
+ rdata = (char *)malloc(1024);
+ if (rdata)
+ memset(rdata,'\0',1024);
+
+ rparam = (char *)malloc(1024);
+ if (rparam)
+ memset(rparam,'\0',1024);
+
+ if(!rdata || !rparam) {
+ DEBUG(0,("api_reply: malloc fail !\n"));
+ return -1;
+ }
+
+ reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+
+
+ if (rdata_len > mdrcnt ||
+ rparam_len > mprcnt) {
+ reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+ }
+
+ /* if we get False back then it's actually unsupported */
+ if (!reply)
+ api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+
+ send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return -1;
+}
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..cfa27923959 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -1,8 +1,8 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
- Name mangling
- Copyright (C) Andrew Tridgell 1992-1995
+ Version 3.0
+ Name mangling with persistent tdb
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,592 +19,949 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/****************************************************************************
+ Rewritten from scrach in 2001 by Simo Sorce <idra@samba.org>
+ ****************************************************************************/
+
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
-extern int case_default;
-extern BOOL case_mangle;
-/****************************************************************************
-provide a checksum on a string
-****************************************************************************/
-int str_checksum(char *s)
+/* -------------------------------------------------------------------------- **
+ * External Variables...
+ */
+
+extern int case_default; /* Are conforming 8.3 names all upper or lower? */
+extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
+
+char magic_char = '~';
+
+/* -------------------------------------------------------------------- */
+
+#define MANGLE_TDB_VERSION "20010927"
+#define MANGLE_TDB_FILE_NAME "mangle.tdb"
+#define MANGLED_PREFIX "MANGLED_"
+#define LONG_PREFIX "LONG_"
+#define COUNTER_PREFIX "COUNTER_"
+#define MANGLE_COUNTER_MAX 99
+#define MANGLE_SUFFIX_SIZE 3 /* "~XX" */
+
+
+static TDB_CONTEXT *mangle_tdb;
+
+BOOL init_mangle_tdb(void)
{
- int res = 0;
- int c;
- int i=0;
- while (*s)
- {
- c = *s;
- res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
- s++; i++;
- }
- return(res);
+ char *tdbfile;
+
+ tdbfile = lock_path(MANGLE_TDB_FILE_NAME); /* this return a static pstring do not try to free it */
+
+ /* Open tdb */
+ if (!(mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
+ {
+ DEBUG(0, ("Unable to open Mangle TDB\n"));
+ return False;
+ }
+
+ return True;
}
-/****************************************************************************
-return True if a name is a special msdos reserved name
-****************************************************************************/
-static BOOL is_reserved_msdos(char *fname)
+/* trasform a unicode string into a dos charset string */
+static int ucs2_to_dos(char *dest, const smb_ucs2_t *src, int dest_len)
{
- char upperFname[13];
- char *p;
-
- StrnCpy (upperFname, fname, 12);
-
- /* lpt1.txt and con.txt etc are also illegal */
- p=strchr(upperFname,'.');
- if (p)
- *p='\0';
- strupper (upperFname);
- if ((strcmp(upperFname,"CLOCK$") == 0) ||
- (strcmp(upperFname,"CON") == 0) ||
- (strcmp(upperFname,"AUX") == 0) ||
- (strcmp(upperFname,"COM1") == 0) ||
- (strcmp(upperFname,"COM2") == 0) ||
- (strcmp(upperFname,"COM3") == 0) ||
- (strcmp(upperFname,"COM4") == 0) ||
- (strcmp(upperFname,"LPT1") == 0) ||
- (strcmp(upperFname,"LPT2") == 0) ||
- (strcmp(upperFname,"LPT3") == 0) ||
- (strcmp(upperFname,"NUL") == 0) ||
- (strcmp(upperFname,"PRN") == 0))
- return (True) ;
-
- return (False);
+ int src_len, ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ src_len = strlen_w(src)* sizeof(smb_ucs2_t);
+
+ ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return ret;
}
+/* trasform in a string that contain only valid chars for win filenames */
+static void strvalid(smb_ucs2_t *src)
+{
+ if (!src || !*src) return;
+
+ while (*src) {
+ if (!isvalid83_w(*src)) *src = UCS2_CHAR('_');
+ src++;
+ }
+}
-/****************************************************************************
-return True if a name is in 8.3 dos format
-****************************************************************************/
-BOOL is_8_3(char *fname)
+/* return False if something fail and
+ * return 2 alloced unicode strings that contain prefix and extension
+ */
+static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension)
{
- int len;
- char *dot_pos;
- char *slash_pos = strrchr(fname,'/');
- int l;
-
- if (slash_pos) fname = slash_pos+1;
- len = strlen(fname);
-
- dot_pos = strchr(fname,'.');
-
- DEBUG(5,("checking %s for 8.3\n",fname));
-
- if (case_mangle)
- switch (case_default)
- {
- case CASE_LOWER:
- if (strhasupper(fname)) return(False);
- break;
- case CASE_UPPER:
- if (strhaslower(fname)) return(False);
- break;
- }
-
- /* can't be longer than 12 chars */
- if (len == 0 || len > 12)
- return(False);
-
- /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
- if (is_reserved_msdos(fname))
- return(False);
-
- /* can't contain invalid dos chars */
- /* Windows use the ANSI charset.
- But filenames are translated in the PC charset.
- This Translation may be more or less relaxed depending
- the Windows application. */
-
- /* %%% A nice improvment to name mangling would be to translate
- filename to ANSI charset on the smb server host */
-
- {
- char *p = fname;
-#ifdef KANJI
- dot_pos = 0;
- while (*p)
- {
- if (is_shift_jis (*p)) {
- p += 2;
- } else if (is_kana (*p)) {
- p ++;
- } else {
- if (*p == '.' && !dot_pos)
- dot_pos = (char *) p;
- if (!isdoschar(*p))
- return(False);
- p++;
- }
- }
-#else
- while (*p)
- {
- if (!isdoschar(*p))
- return(False);
- p++;
- }
-#endif /* KANJI */
- }
-
- /* no dot and less than 9 means OK */
- if (!dot_pos)
- return(len <= 8);
-
- l = PTR_DIFF(dot_pos,fname);
-
- /* base must be at least 1 char except special cases . and .. */
- if (l == 0)
- return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0);
-
- /* base can't be greater than 8 */
- if (l > 8)
- return(False);
-
- if (lp_strip_dot() &&
- len - l == 1 &&
- !strchr(dot_pos+1,'.'))
- {
- *dot_pos = 0;
- return(True);
- }
-
- /* extension must be between 1 and 3 */
- if ( (len - l < 2 ) || (len - l > 4) )
- return(False);
-
- /* extension can't have a dot */
- if (strchr(dot_pos+1,'.'))
- return(False);
-
- /* must be in 8.3 format */
- return(True);
+ size_t ext_len;
+ smb_ucs2_t *p;
+
+ *extension = 0;
+ *prefix = strdup_w(ucs2_string);
+ if (!*prefix)
+ {
+ DEBUG(0,("mangle_get_prefix: out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ if ((p = strrchr_w(*prefix, UCS2_CHAR('.'))))
+ {
+ p++;
+ ext_len = strlen_w(p);
+ if ((ext_len > 0) && (ext_len < 4)
+ && (NT_STATUS_IS_OK(has_valid_chars(p)))) /* check extension */
+ {
+ *(p - 1) = 0;
+ *extension = strdup_w(p);
+ if (!*extension)
+ {
+ DEBUG(0,("mangle_get_prefix: out of memory!\n"));
+ SAFE_FREE(*prefix);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+ return NT_STATUS_OK;
}
+/* mangled must contain only the file name, not a path.
+ and MUST be ZERO terminated */
+smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
+{
+ TDB_DATA data, key;
+ fstring keystr;
+ fstring mufname;
+ smb_ucs2_t *pref, *ext, *retstr;
+ size_t long_len, ext_len, muf_len;
+
+ if (strlen_w(mangled) > 12) return NULL;
+ if (!strchr_w(mangled, UCS2_CHAR('~'))) return NULL;
+
+ /* if it is a path refuse to proceed */
+ if (strchr_w(mangled, UCS2_CHAR('/'))) {
+ DEBUG(10, ("unmangle: cannot unmangle a path\n"));
+ return NULL;
+ }
-/*
-keep a stack of name mangling results - just
-so file moves and copies have a chance of working
-*/
-fstring *mangled_stack = NULL;
-int mangled_stack_size = 0;
-int mangled_stack_len = 0;
+ if (NT_STATUS_IS_ERR(mangle_get_prefix(mangled, &pref, &ext)))
+ return NULL;
-/****************************************************************************
-create the mangled stack
-****************************************************************************/
-void create_mangled_stack(int size)
+ /* mangled names are stored lowercase only */
+ strlower_w(pref);
+ /* set search key */
+ muf_len = ucs2_to_dos(mufname, pref, sizeof(mufname));
+ SAFE_FREE(pref);
+ if (!muf_len) return NULL;
+
+ slprintf(keystr, sizeof(keystr) - 1, "%s%s", MANGLED_PREFIX, mufname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* get the record */
+ data = tdb_fetch(mangle_tdb, key);
+
+ if (!data.dptr) /* not found */
+ {
+ DEBUG(5,("unmangle: failed retrieve from db %s\n", tdb_errorstr(mangle_tdb)));
+ retstr = NULL;
+ goto done;
+ }
+
+ if (ext)
+ {
+ long_len = (data.dsize / 2) - 1;
+ ext_len = strlen_w(ext);
+ retstr = (smb_ucs2_t *)malloc((long_len + ext_len + 2)*sizeof(smb_ucs2_t));
+ if (!retstr)
+ {
+ DEBUG(0, ("unamngle: out of memory!\n"));
+ goto done;
+ }
+ strncpy_w(retstr, (smb_ucs2_t *)data.dptr, long_len);
+ retstr[long_len] = UCS2_CHAR('.');
+ retstr[long_len + 1] = 0;
+ strncat_w(retstr, ext, ext_len);
+ }
+ else
+ {
+ retstr = strdup_w((smb_ucs2_t *)data.dptr);
+ if (!retstr)
+ {
+ DEBUG(0, ("unamngle: out of memory!\n"));
+ goto done;
+ }
+
+ }
+
+done:
+ SAFE_FREE(data.dptr);
+ SAFE_FREE(pref);
+ SAFE_FREE(ext);
+
+ return retstr;
+}
+
+/* unmangled must contain only the file name, not a path.
+ and MUST be ZERO terminated.
+ return a new allocated string if the name is yet valid 8.3
+ or is mangled successfully.
+ return null on error.
+ */
+
+smb_ucs2_t *mangle(const smb_ucs2_t *unmangled)
{
- if (mangled_stack)
- {
- free(mangled_stack);
- mangled_stack_size = 0;
- mangled_stack_len = 0;
- }
- if (size > 0)
- mangled_stack = (fstring *)malloc(sizeof(fstring)*size);
- if (mangled_stack) mangled_stack_size = size;
+ TDB_DATA data, key, klock;
+ pstring keystr;
+ pstring longname;
+ fstring keylock;
+ fstring mufname;
+ fstring prefix;
+ BOOL tclock = False;
+ char suffix[7];
+ smb_ucs2_t *mangled = NULL;
+ smb_ucs2_t *umpref, *ext, *p = NULL;
+ size_t pref_len, ext_len, ud83_len;
+
+ /* if it is a path refuse to proceed */
+ if (strchr_w(unmangled, UCS2_CHAR('/'))) {
+ DEBUG(10, ("mangle: cannot mangle a path\n"));
+ return NULL;
+ }
+
+ /* if it is a valid 8_3 do not mangle again */
+ if (NT_STATUS_IS_OK(is_8_3_w(unmangled)))
+ return NULL;
+
+ if (NT_STATUS_IS_ERR(mangle_get_prefix(unmangled, &umpref, &ext)))
+ return NULL;
+
+ /* test if the same is yet mangled */
+
+ /* set search key */
+ pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ /* get the record */
+ data = tdb_fetch (mangle_tdb, key);
+ if (!data.dptr) /* not found */
+ {
+ smb_ucs2_t temp[9];
+ size_t c, pos;
+
+ if (tdb_error(mangle_tdb) != TDB_ERR_NOEXIST)
+ {
+ DEBUG(0, ("mangle: database retrieval error: %s\n",
+ tdb_errorstr(mangle_tdb)));
+ goto done;
+ }
+
+ /* if not find the first free possibile mangled name */
+
+ pos = strlen_w(umpref);
+ if ((8 - MANGLE_SUFFIX_SIZE) < pos)
+ pos = 8 - MANGLE_SUFFIX_SIZE;
+ pos++;
+ do
+ {
+ pos--;
+ if (pos == 0)
+ {
+ DEBUG(0, ("mangle: unable to mangle file name!\n"));
+ goto done;
+ }
+ strncpy_w(temp, umpref, pos);
+ temp[pos] = 0;
+ strlower_w(temp);
+
+ /* convert any invalid char into '_' */
+ strvalid(temp);
+ ud83_len = ucs2_to_dos(prefix, temp, sizeof(prefix));
+ if (!ud83_len) goto done;
+ }
+ while (ud83_len > 8 - MANGLE_SUFFIX_SIZE);
+
+ slprintf(keylock, sizeof(keylock)-1, "%s%s", COUNTER_PREFIX, prefix);
+ klock.dptr = keylock;
+ klock.dsize = strlen(keylock) + 1;
+
+ c = 0;
+ data.dptr = (char *)&c;
+ data.dsize = sizeof(uint32);
+ /* try to insert a new counter prefix, if it exist the call will
+ fail (correct) otherwise it will create a new entry with counter set
+ to 0
+ */
+ if(tdb_store(mangle_tdb, klock, data, TDB_INSERT) != TDB_SUCCESS)
+ {
+ if (tdb_error(mangle_tdb) != TDB_ERR_EXISTS)
+ {
+ DEBUG(0, ("mangle: database store error: %s\n",
+ tdb_errorstr(mangle_tdb)));
+ goto done;
+ }
+ }
+
+ /* lock the mangle counter for this prefix */
+ if (tdb_chainlock(mangle_tdb, klock))
+ {
+ DEBUG(0,("mangle: failed to lock database\n!"));
+ goto done;
+ }
+ tclock = True;
+
+ data = tdb_fetch(mangle_tdb, klock);
+ if (!data.dptr)
+ {
+ DEBUG(0, ("mangle: database retrieval error: %s\n",
+ tdb_errorstr(mangle_tdb)));
+ goto done;
+ }
+ c = *((uint32 *)data.dptr);
+ c++;
+
+ if (c > MANGLE_COUNTER_MAX)
+ {
+ DEBUG(0, ("mangle: error, counter overflow!\n"));
+ goto done;
+ }
+
+ temp[pos] = UCS2_CHAR('~');
+ temp[pos+1] = 0;
+ snprintf(suffix, 7, "%.6d", c);
+ strncat_wa(temp, &suffix[7 - MANGLE_SUFFIX_SIZE], MANGLE_SUFFIX_SIZE);
+
+ ud83_len = ucs2_to_dos(mufname, temp, sizeof(mufname));
+ if (!ud83_len) goto done;
+ if (ud83_len > 8)
+ {
+ DEBUG(0, ("mangle: darn, logic error aborting!\n"));
+ goto done;
+ }
+
+ /* store the long entry with mangled key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+ data.dsize = (strlen_w(umpref) + 1) * sizeof (smb_ucs2_t);
+ data.dptr = (void *)umpref;
+
+ if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
+ {
+ DEBUG(0, ("mangle: database store error: %s\n",
+ tdb_errorstr(mangle_tdb)));
+ goto done;
+ }
+
+ /* store the mangled entry with long key*/
+ pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+ data.dsize = strlen(mufname) + 1;
+ data.dptr = mufname;
+ if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
+ {
+ DEBUG(0, ("mangle: database store failed: %s\n",
+ tdb_errorstr(mangle_tdb)));
+
+ /* try to delete the mangled key entry to avoid later inconsistency */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+ if (!tdb_delete(mangle_tdb, key))
+ {
+ DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
+ }
+ goto done;
+ }
+
+ p = strdup_w(temp);
+ if (!p)
+ {
+ DEBUG(0,("mangle: out of memory!\n"));
+ goto done;
+ }
+
+ data.dptr = (char *)&c;
+ data.dsize = sizeof(uint32);
+ /* store the counter */
+ if(tdb_store(mangle_tdb, klock, data, TDB_REPLACE) != TDB_SUCCESS)
+ {
+ DEBUG(0, ("mangle: database store failed: %s\n",
+ tdb_errorstr(mangle_tdb)));
+ /* try to delete the mangled and long key entry to avoid later inconsistency */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+ if (!tdb_delete(mangle_tdb, key))
+ {
+ DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
+ }
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+ if (!tdb_delete(mangle_tdb, key))
+ {
+ DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
+ }
+ goto done;
+ }
+
+ tclock = False;
+ tdb_chainunlock(mangle_tdb, klock);
+ }
+ else /* FOUND */
+ {
+ p = acnv_dosu2(data.dptr);
+ if (!p)
+ {
+ DEBUG(0,("mangle: out of memory!\n"));
+ goto done;
+ }
+ }
+
+ if (ext)
+ {
+ pref_len = strlen_w(p);
+ ext_len = strlen_w(ext);
+ mangled = (smb_ucs2_t *)malloc((pref_len + ext_len + 2)*sizeof(smb_ucs2_t));
+ if (!mangled)
+ {
+ DEBUG(0,("mangle: out of memory!\n"));
+ goto done;
+ }
+ strncpy_w (mangled, p, pref_len);
+ mangled[pref_len] = UCS2_CHAR('.');
+ mangled[pref_len + 1] = 0;
+ strncat_w (mangled, ext, ext_len);
+ }
+ else
+ {
+ mangled = strdup_w(p);
+ if (!mangled)
+ {
+ DEBUG(0,("mangle: out of memory!\n"));
+ goto done;
+ }
+ }
+
+ /* mangled name are returned in upper or lower case depending on
+ case_default value */
+ strnorm_w(mangled);
+
+done:
+ if (tclock) tdb_chainunlock(mangle_tdb, klock);
+ SAFE_FREE(p);
+ SAFE_FREE(umpref);
+ SAFE_FREE(ext);
+
+ return mangled;
}
-/****************************************************************************
-push a mangled name onto the stack
-****************************************************************************/
-static void push_mangled_name(char *s)
+
+/* non unicode compatibility functions */
+
+char *dos_mangle(const char *dos_unmangled)
{
- int i;
- char *p;
-
- if (!mangled_stack)
- return;
-
- for (i=0;i<mangled_stack_len;i++)
- if (strcmp(s,mangled_stack[i]) == 0)
- {
- array_promote(mangled_stack[0],sizeof(fstring),i);
- return;
- }
-
- memmove(mangled_stack[1],mangled_stack[0],
- sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1));
- strcpy(mangled_stack[0],s);
- p = strrchr(mangled_stack[0],'.');
- if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4))
- *p = 0;
- mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1);
+ smb_ucs2_t *in, *out;
+ char *dos_mangled;
+
+ if (!dos_unmangled || !*dos_unmangled) return NULL;
+
+ in = acnv_dosu2(dos_unmangled);
+ if (!in)
+ {
+ DEBUG(0,("dos_mangle: out of memory!\n"));
+ return NULL;
+ }
+
+ out = mangle(in);
+ if (!out)
+ {
+ SAFE_FREE(in);
+ return NULL;
+ }
+
+ dos_mangled = acnv_u2dos(out);
+ if (!dos_mangled)
+ {
+ DEBUG(0,("dos_mangle: out of memory!\n"));
+ goto done;
+ }
+
+done:
+ SAFE_FREE(in);
+ SAFE_FREE(out);
+ return dos_mangled;
}
-/****************************************************************************
-check for a name on the mangled name stack
-****************************************************************************/
-BOOL check_mangled_stack(char *s)
+char *dos_unmangle(const char *dos_mangled)
{
- int i;
- pstring tmpname;
- char extension[5];
- char *p = strrchr(s,'.');
- BOOL check_extension = False;
-
- extension[0] = 0;
-
- if (!mangled_stack) return(False);
-
- if (p)
- {
- check_extension = True;
- StrnCpy(extension,p,4);
- strlower(extension); /* XXXXXXX */
- }
-
- for (i=0;i<mangled_stack_len;i++)
- {
- strcpy(tmpname,mangled_stack[i]);
- mangle_name_83(tmpname);
- if (strequal(tmpname,s))
+ smb_ucs2_t *in, *out;
+ char *dos_unmangled;
+
+ if (!dos_mangled || !*dos_mangled) return NULL;
+
+ in = acnv_dosu2(dos_mangled);
+ if (!in)
{
- strcpy(s,mangled_stack[i]);
- break;
+ DEBUG(0,("dos_unmangle: out of memory!\n"));
+ return NULL;
}
- if (check_extension && !strchr(mangled_stack[i],'.'))
+
+ out = mangle(in);
+ if (!out)
{
- strcpy(tmpname,mangled_stack[i]);
- strcat(tmpname,extension);
- mangle_name_83(tmpname);
- if (strequal(tmpname,s))
- {
- strcpy(s,mangled_stack[i]);
- strcat(s,extension);
- break;
- }
+ SAFE_FREE(in);
+ return NULL;
}
- }
- if (i < mangled_stack_len)
- {
- DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
- array_promote(mangled_stack[0],sizeof(fstring),i);
- return(True);
- }
+ dos_unmangled = acnv_u2dos(out);
+ if (!dos_unmangled)
+ {
+ DEBUG(0,("dos_unmangle: out of memory!\n"));
+ goto done;
+ }
- return(False);
-}
+done:
+ SAFE_FREE(in);
+ SAFE_FREE(out);
+ return dos_unmangled;
+}
-static char *map_filename(char *s, /* This is null terminated */
- char *pattern, /* This isn't. */
- int len) /* This is the length of pattern. */
+BOOL is_8_3(const char *fname, BOOL check_case)
{
- static pstring matching_bit; /* The bit of the string which matches */
- /* a * in pattern if indeed there is a * */
- char *sp; /* Pointer into s. */
- char *pp; /* Pointer into p. */
- char *match_start; /* Where the matching bit starts. */
- pstring pat;
-
- StrnCpy(pat, pattern, len); /* Get pattern into a proper string! */
- strcpy(matching_bit,""); /* Match but no star gets this. */
- pp = pat; /* Initialise the pointers. */
- sp = s;
- if ((len == 1) && (*pattern == '*')) {
- return NULL; /* Impossible, too ambiguous for */
- /* words! */
- }
-
- while ((*sp) /* Not the end of the string. */
- && (*pp) /* Not the end of the pattern. */
- && (*sp == *pp) /* The two match. */
- && (*pp != '*')) { /* No wildcard. */
- sp++; /* Keep looking. */
- pp++;
- }
- if (!*sp && !*pp) /* End of pattern. */
- return matching_bit; /* Simple match. Return empty string. */
- if (*pp == '*') {
- pp++; /* Always interrested in the chacter */
- /* after the '*' */
- if (!*pp) { /* It is at the end of the pattern. */
- StrnCpy(matching_bit, s, sp-s);
- return matching_bit;
- } else {
- /* The next character in pattern must match a character further */
- /* along s than sp so look for that character. */
- match_start = sp;
- while ((*sp) /* Not the end of s. */
- && (*sp != *pp)) /* Not the same */
- sp++; /* Keep looking. */
- if (!*sp) { /* Got to the end without a match. */
- return NULL;
- } else { /* Still hope for a match. */
- /* Now sp should point to a matching character. */
- StrnCpy(matching_bit, match_start, sp-match_start);
- /* Back to needing a stright match again. */
- while ((*sp) /* Not the end of the string. */
- && (*pp) /* Not the end of the pattern. */
- && (*sp == *pp)) { /* The two match. */
- sp++; /* Keep looking. */
- pp++;
- }
- if (!*sp && !*pp) /* Both at end so it matched */
- return matching_bit;
- else
- return NULL;
- }
- }
- }
- return NULL; /* No match. */
+ smb_ucs2_t *ucs2name;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if (!fname || !*fname) return False;
+
+ DEBUG(10,("is_8_3: testing [%s]\n", fname));
+
+ if (strlen(fname) > 12) return False;
+
+ ucs2name = acnv_uxu2(fname);
+ if (!ucs2name)
+ {
+ DEBUG(0,("is_8_3: out of memory!\n"));
+ goto done;
+ }
+
+ ret = is_8_3_w(ucs2name);
+
+done:
+ SAFE_FREE(ucs2name);
+
+ DEBUG(10,("is_8_3: returning -> %s\n", NT_STATUS_IS_OK(ret)?"True":"False"));
+
+ if (NT_STATUS_IS_ERR(ret)) return False;
+ else return True;
}
+NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
+{
+ smb_ucs2_t *pref = 0, *ext = 0;
+ size_t plen;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-/* this is the magic char used for mangling */
-char magic_char = '~';
+ if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
+ DEBUG(10,("is_8_3_w: testing\n")); /* [%s]\n", fname)); */
-/****************************************************************************
-determine whther is name could be a mangled name
-****************************************************************************/
-BOOL is_mangled(char *s)
+ if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL;
+
+ if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
+ return NT_STATUS_OK;
+
+ if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done;
+
+ if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done;
+ plen = strlen_w(pref);
+ if (plen < 1 || plen > 8) goto done;
+ if (ext) if (strlen_w(ext) > 3) goto done;
+
+ ret = NT_STATUS_OK;
+
+done:
+ SAFE_FREE(pref);
+ SAFE_FREE(ext);
+ return ret;
+}
+
+NTSTATUS has_valid_chars(const smb_ucs2_t *s)
{
- char *m = strchr(s,magic_char);
- if (!m) return(False);
+ NTSTATUS ret = NT_STATUS_OK;
+
+ if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
+
+ DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
+
+ /* CHECK: this should not be necessary if the ms wild chars
+ are not valid in valid.dat --- simo */
+ if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL;
- /* we use two base 36 chars efore the extension */
- if (m[1] == '.' || m[1] == 0 ||
- m[2] == '.' || m[2] == 0 ||
- (m[3] != '.' && m[3] != 0))
- return(is_mangled(m+1));
+ while (*s) {
+ if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL;
+ s++;
+ }
- /* it could be */
- return(True);
+ return ret;
}
+NTSTATUS is_valid_name(const smb_ucs2_t *fname)
+{
+ smb_ucs2_t *str, *p;
+ NTSTATUS ret = NT_STATUS_OK;
+ if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
-/****************************************************************************
-return a base 36 character. v must be from 0 to 35.
-****************************************************************************/
-static char base36(int v)
+ DEBUG(10,("is_valid_name: testing\n")); /* [%s]\n", s)); */
+
+ ret = has_valid_chars(fname);
+ if (NT_STATUS_IS_ERR(ret)) return ret;
+
+ str = strdup_w(fname);
+ p = strchr_w(str, UCS2_CHAR('.'));
+ if (p) *p = 0;
+ strupper_w(str);
+ p = &(str[1]);
+
+ switch(str[0])
+ {
+ case UCS2_CHAR('A'):
+ if(strcmp_wa(p, "UX") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('C'):
+ if((strcmp_wa(p, "LOCK$") == 0)
+ || (strcmp_wa(p, "ON") == 0)
+ || (strcmp_wa(p, "OM1") == 0)
+ || (strcmp_wa(p, "OM2") == 0)
+ || (strcmp_wa(p, "OM3") == 0)
+ || (strcmp_wa(p, "OM4") == 0)
+ )
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('L'):
+ if((strcmp_wa(p, "PT1") == 0)
+ || (strcmp_wa(p, "PT2") == 0)
+ || (strcmp_wa(p, "PT3") == 0)
+ )
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('N'):
+ if(strcmp_wa(p, "UL") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ case UCS2_CHAR('P'):
+ if(strcmp_wa(p, "RN") == 0)
+ ret = NT_STATUS_UNSUCCESSFUL;
+ break;
+ default:
+ break;
+ }
+
+ SAFE_FREE(str);
+ return ret;
+}
+
+BOOL is_mangled(const char *s)
{
- v = v % 36;
- if (v < 10)
- return('0'+v);
- else /* needed to work around a DEC C compiler bug */
- return('A' + (v-10));
+ smb_ucs2_t *u2, *res;
+ BOOL ret = False;
+
+ DEBUG(10,("is_mangled: testing [%s]\n", s));
+
+ if (!s || !*s) return False;
+ if ((strlen(s) > 12) || (!strchr(s, '~'))) return False;
+
+ u2 = acnv_dosu2(s);
+ if (!u2)
+ {
+ DEBUG(0,("is_mangled: out of memory!\n"));
+ return ret;
+ }
+
+ res = unmangle(u2);
+ if (res) ret = True;
+ SAFE_FREE(res);
+ SAFE_FREE(u2);
+ DEBUG(10,("is_mangled: returning [%s]\n", ret?"True":"False"));
+ return ret;
}
+NTSTATUS is_mangled_w(const smb_ucs2_t *s)
+{
+ smb_ucs2_t *res;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ res = unmangle(s);
+ if (res) ret = NT_STATUS_OK;
+ SAFE_FREE(res);
+ return ret;
+}
-static void do_fwd_mangled_map(char *s, char *MangledMap)
+NTSTATUS path_has_mangled(const smb_ucs2_t *s)
{
- /* MangledMap is a series of name pairs in () separated by spaces.
- * If s matches the first of the pair then the name given is the
- * second of the pair. A * means any number of any character and if
- * present in the second of the pair as well as the first the
- * matching part of the first string takes the place of the * in the
- * second.
- *
- * I wanted this so that we could have RCS files which can be used
- * by UNIX and DOS programs. My mapping string is (RCS rcs) which
- * converts the UNIX RCS file subdirectory to lowercase thus
- * preventing mangling.
- */
- char *start=MangledMap; /* Use this to search for mappings. */
- char *end; /* Used to find the end of strings. */
- char *match_string;
- pstring new_string; /* Make up the result here. */
- char *np; /* Points into new_string. */
-
- DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap));
- while (*start) {
- while ((*start) && (*start != '('))
- start++;
- start++; /* Skip the ( */
- if (!*start)
- continue; /* Always check for the end. */
- end = start; /* Search for the ' ' or a ')' */
- DEBUG(5,("Start of first in pair '%s'\n", start));
- while ((*end) && !((*end == ' ') || (*end == ')')))
- end++;
- if (!*end) {
- start = end;
- continue; /* Always check for the end. */
- }
- DEBUG(5,("End of first in pair '%s'\n", end));
- if ((match_string = map_filename(s, start, end-start))) {
- DEBUG(5,("Found a match\n"));
- /* Found a match. */
- start = end+1; /* Point to start of what it is to become. */
- DEBUG(5,("Start of second in pair '%s'\n", start));
- end = start;
- np = new_string;
- while ((*end) /* Not the end of string. */
- && (*end != ')') /* Not the end of the pattern. */
- && (*end != '*')) /* Not a wildcard. */
- *np++ = *end++;
- if (!*end) {
- start = end;
- continue; /* Always check for the end. */
- }
- if (*end == '*') {
- strcpy(np, match_string);
- np += strlen(match_string);
- end++; /* Skip the '*' */
- while ((*end) /* Not the end of string. */
- && (*end != ')') /* Not the end of the pattern. */
- && (*end != '*')) /* Not a wildcard. */
- *np++ = *end++;
- }
- if (!*end) {
- start = end;
- continue; /* Always check for the end. */
- }
- *np++ = '\0'; /* NULL terminate it. */
- DEBUG(5,("End of second in pair '%s'\n", end));
- strcpy(s, new_string); /* Substitute with the new name. */
- DEBUG(5,("s is now '%s'\n", s));
- }
- start = end; /* Skip a bit which cannot be wanted */
- /* anymore. */
- start++;
- }
+ smb_ucs2_t *p, *f, *b;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
+
+ p = strdup_w(s);
+ if (!p) return NT_STATUS_NO_MEMORY;
+ trim_string_wa(p, "/", "/");
+ f = b = p;
+ while (b) {
+ b = strchr_w(f, UCS2_CHAR('/'));
+ if (b) *b = 0;
+ if (NT_STATUS_IS_OK(is_mangled_w(f))) {
+ ret = NT_STATUS_OK;
+ goto done;
+ }
+ f = b + 1;
+ }
+done:
+ SAFE_FREE(p);
+ return ret;
}
-/****************************************************************************
-do the actual mangling to 8.3 format
-****************************************************************************/
-void mangle_name_83(char *s)
+/* backward compatibility functions */
+
+void reset_mangled_cache(void)
+{
+ DEBUG(10,("reset_mangled_cache: compatibility function, remove me!\n"));
+}
+
+BOOL check_mangled_cache(char *s)
{
- int csum = str_checksum(s);
- char *p;
- char extension[4];
- char base[9];
- int baselen = 0;
- int extlen = 0;
-
- extension[0]=0;
- base[0]=0;
-
- p = strrchr(s,'.');
- if (p && (strlen(p+1)<4) )
- {
- BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
- if (all_normal && p[1] != 0)
+ smb_ucs2_t *u2, *res;
+ BOOL ret = False;
+
+ DEBUG(10,("check_mangled_cache: I'm so ugly, please remove me!\n"));
+ DEBUG(10,("check_mangled_cache: testing -> [%s]\n", s));
+
+ if (!s || !*s) return False;
+
+ u2 = acnv_dosu2(s);
+ if (!u2)
{
- *p = 0;
- csum = str_checksum(s);
- *p = '.';
+ DEBUG(0,("check_mangled_cache: out of memory!\n"));
+ return ret;
}
- }
-
- strupper(s);
+ res = unmangle(u2);
+ if (res)
+ {
+
+ ucs2_to_dos (s, res, PSTRING_LEN);
+ /* We MUST change this brainded interface,
+ we do not know how many chars will be used
+ in dos so i guess they will be no more than
+ double the size of the unicode string
+ ---simo */
+ DEBUG(10,("check_mangled_cache: returning -> [%s]\n", s));
+ ret = True;
+ }
+ SAFE_FREE(res);
+ SAFE_FREE(u2);
+ DEBUG(10,("check_mangled_cache: returning -> %s\n", ret?"True":"False"));
+ return ret;
+}
+
+void mangle_name_83(char *s)
+{
+ smb_ucs2_t *u2, *res;
- DEBUG(5,("Mangling name %s to ",s));
+ DEBUG(10,("mangle_name_83: I'm so ugly, please remove me!\n"));
+ DEBUG(10,("mangle_name_83: testing -> [%s]\n", s));
- if (p)
- {
- if (p == s)
- strcpy(extension,"___");
- else
+ if (!s || !*s) return;
+
+ u2 = acnv_dosu2(s);
+ if (!u2)
{
- *p++ = 0;
- while (*p && extlen < 3)
- {
- if (isdoschar(*p) && *p != '.')
- extension[extlen++] = *p;
- p++;
- }
- extension[extlen] = 0;
+ DEBUG(0,("mangle_name_83: out of memory!\n"));
+ return;
}
- }
-
- p = s;
- while (*p && baselen < 5)
- {
- if (isdoschar(*p) && *p != '.')
- base[baselen++] = *p;
- p++;
- }
- base[baselen] = 0;
+ res = mangle(u2);
+ if (res) ucs2_to_dos (s, res, 13); /* ugly, but must be done this way */
+ DEBUG(10,("mangle_name_83: returning -> [%s]\n", s));
+ SAFE_FREE(res);
+ SAFE_FREE(u2);
+}
- csum = csum % (36*36);
+BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
+{
+ DEBUG(10,("name_map_mangle: I'm so ugly, please remove me!\n"));
- sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
+ if (!need83) return True;
+ /* if (is_8_3(OutName, True)) return True; */
+ /* Warning: we should check for invalid chars in file name and mangle
+ if invalid chars found --simo*/
- if (*extension)
- {
- strcat(s,".");
- strcat(s,extension);
- }
- DEBUG(5,("%s\n",s));
+ mangle_name_83(OutName);
+ return True;
}
-/*******************************************************************
- work out if a name is illegal, even for long names
- ******************************************************************/
-static BOOL illegal_name(char *name)
+#if 0 /* TEST_MANGLE_CODE */
+
+#define LONG "this_is_a_long_file_name"
+#define LONGM "this_~01"
+#define SHORT "short"
+#define SHORTM "short~01"
+#define EXT1 "ex1"
+#define EXT2 "e2"
+#define EXT3 "3"
+#define EXTFAIL "longext"
+#define EXTNULL ""
+
+static void unmangle_test (char *name, char *ext)
{
- static unsigned char illegal[256];
- static BOOL initialised=False;
- unsigned char *s;
-
- if (!initialised) {
- char *ill = "*\\/?<>|\":{}";
- initialised = True;
-
- bzero((char *)illegal,256);
- for (s = (unsigned char *)ill; *s; s++)
- illegal[*s] = True;
- }
-
-#ifdef KANJI
- for (s = (unsigned char *)name; *s;) {
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (illegal[*s]) {
- return(True);
- } else {
- s++;
- }
- }
-#else
- for (s = (unsigned char *)name;*s;s++)
- if (illegal[*s]) return(True);
-#endif
-
-
- return(False);
+ smb_ucs2_t ucs2_name[2048];
+ smb_ucs2_t *retstr;
+ pstring unix_name;
+
+ push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
+ if (ext)
+ {
+ strncat_wa(ucs2_name, ".", 1);
+ strncat_wa(ucs2_name, ext, strlen(ext) + 1);
+ }
+ retstr = unmangle(ucs2_name);
+ if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
+ else unix_name[0] = 0;
+ if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
+ else printf ("[%s] ---> [%s]\n", name, unix_name);
+ SAFE_FREE(retstr);
}
+static void mangle_test (char *name, char *ext)
+{
+ smb_ucs2_t ucs2_name[2048];
+ smb_ucs2_t *retstr;
+ pstring unix_name;
+
+ push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
+ if (ext)
+ {
+ strncat_wa(ucs2_name, ".", 1);
+ strncat_wa(ucs2_name, ext, strlen(ext) + 1);
+ }
+ retstr = mangle(ucs2_name);
+ if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
+ else unix_name[0] = 0;
+ if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
+ else printf ("[%s] ---> [%s]\n", name, unix_name);
+ SAFE_FREE(retstr);
+}
-/****************************************************************************
-convert a filename to DOS format. return True if successful.
-****************************************************************************/
-BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
+void mangle_test_code(void)
{
-#ifdef MANGLE_LONG_FILENAMES
- if (!need83 && illegal_name(OutName)) need83 = True;
-#endif
-
- /* apply any name mappings */
- {
- char *map = lp_mangled_map(snum);
- if (map && *map)
- do_fwd_mangled_map(OutName,map);
- }
-
- /* check if it's already in 8.3 format */
- if (need83 && !is_8_3(OutName)) {
- if (!lp_manglednames(snum)) return(False);
-
- /* mangle it into 8.3 */
- push_mangled_name(OutName);
- mangle_name_83(OutName);
- }
-
- return(True);
+ init_mangle_tdb();
+
+ /* unmangle every */
+ printf("Unmangle test 1:\n");
+
+ unmangle_test (LONG, NULL);
+ unmangle_test (LONG, EXT1);
+ unmangle_test (LONG, EXT2);
+ unmangle_test (LONG, EXT3);
+ unmangle_test (LONG, EXTFAIL);
+ unmangle_test (LONG, EXTNULL);
+
+ unmangle_test (LONGM, NULL);
+ unmangle_test (LONGM, EXT1);
+ unmangle_test (LONGM, EXT2);
+ unmangle_test (LONGM, EXT3);
+ unmangle_test (LONGM, EXTFAIL);
+ unmangle_test (LONGM, EXTNULL);
+
+ unmangle_test (SHORT, NULL);
+ unmangle_test (SHORT, EXT1);
+ unmangle_test (SHORT, EXT2);
+ unmangle_test (SHORT, EXT3);
+ unmangle_test (SHORT, EXTFAIL);
+ unmangle_test (SHORT, EXTNULL);
+
+ unmangle_test (SHORTM, NULL);
+ unmangle_test (SHORTM, EXT1);
+ unmangle_test (SHORTM, EXT2);
+ unmangle_test (SHORTM, EXT3);
+ unmangle_test (SHORTM, EXTFAIL);
+ unmangle_test (SHORTM, EXTNULL);
+
+ /* mangle every */
+ printf("Mangle test\n");
+
+ mangle_test (LONG, NULL);
+ mangle_test (LONG, EXT1);
+ mangle_test (LONG, EXT2);
+ mangle_test (LONG, EXT3);
+ mangle_test (LONG, EXTFAIL);
+ mangle_test (LONG, EXTNULL);
+
+ mangle_test (LONGM, NULL);
+ mangle_test (LONGM, EXT1);
+ mangle_test (LONGM, EXT2);
+ mangle_test (LONGM, EXT3);
+ mangle_test (LONGM, EXTFAIL);
+ mangle_test (LONGM, EXTNULL);
+
+ mangle_test (SHORT, NULL);
+ mangle_test (SHORT, EXT1);
+ mangle_test (SHORT, EXT2);
+ mangle_test (SHORT, EXT3);
+ mangle_test (SHORT, EXTFAIL);
+ mangle_test (SHORT, EXTNULL);
+
+ mangle_test (SHORTM, NULL);
+ mangle_test (SHORTM, EXT1);
+ mangle_test (SHORTM, EXT2);
+ mangle_test (SHORTM, EXT3);
+ mangle_test (SHORTM, EXTFAIL);
+ mangle_test (SHORTM, EXTNULL);
+
+ /* unmangle again every */
+ printf("Unmangle test 2:\n");
+
+ unmangle_test (LONG, NULL);
+ unmangle_test (LONG, EXT1);
+ unmangle_test (LONG, EXT2);
+ unmangle_test (LONG, EXT3);
+ unmangle_test (LONG, EXTFAIL);
+ unmangle_test (LONG, EXTNULL);
+
+ unmangle_test (LONGM, NULL);
+ unmangle_test (LONGM, EXT1);
+ unmangle_test (LONGM, EXT2);
+ unmangle_test (LONGM, EXT3);
+ unmangle_test (LONGM, EXTFAIL);
+ unmangle_test (LONGM, EXTNULL);
+
+ unmangle_test (SHORT, NULL);
+ unmangle_test (SHORT, EXT1);
+ unmangle_test (SHORT, EXT2);
+ unmangle_test (SHORT, EXT3);
+ unmangle_test (SHORT, EXTFAIL);
+ unmangle_test (SHORT, EXTNULL);
+
+ unmangle_test (SHORTM, NULL);
+ unmangle_test (SHORTM, EXT1);
+ unmangle_test (SHORTM, EXT2);
+ unmangle_test (SHORTM, EXT3);
+ unmangle_test (SHORTM, EXTFAIL);
+ unmangle_test (SHORTM, EXTNULL);
}
+#endif /* TEST_MANGLE_CODE */
diff --git a/source/smbd/message.c b/source/smbd/message.c
index 6a96b4c7a9c..a3625e37168 100644
--- a/source/smbd/message.c
+++ b/source/smbd/message.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB messaging
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,26 +25,23 @@
#include "includes.h"
-#include "loadparm.h"
-
-/* look in server.c for some explanation of these variables */
-extern int DEBUGLEVEL;
+extern userdom_struct current_user_info;
+/* look in server.c for some explanation of these variables */
static char msgbuf[1600];
-static int msgpos=0;
-static fstring msgfrom="";
-static fstring msgto="";
+static int msgpos;
+static fstring msgfrom;
+static fstring msgto;
/****************************************************************************
deliver the message
****************************************************************************/
static void msg_deliver(void)
{
- pstring s;
- fstring name;
- FILE *f;
+ pstring name;
int i;
+ int fd;
if (! (*lp_msg_command()))
{
@@ -54,34 +51,43 @@ static void msg_deliver(void)
}
/* put it in a temporary file */
- sprintf(s,"/tmp/msg.XXXXXX");
- strcpy(name,(char *)mktemp(s));
+ slprintf(name,sizeof(name)-1, "%s/msg.XXXXXX",tmpdir());
+ fd = smb_mkstemp(name);
- f = fopen(name,"w");
- if (!f)
- {
- DEBUG(1,("can't open message file %s\n",name));
- return;
- }
+ if (fd == -1) {
+ DEBUG(1,("can't open message file %s\n",name));
+ return;
+ }
- for (i=0;i<msgpos;)
- {
- if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n')
- i++;
- fputc(msgbuf[i++],f);
- }
+ /*
+ * Incoming message is in DOS codepage format. Convert to UNIX.
+ */
- fclose(f);
+ if(msgpos > 0) {
+ msgbuf[msgpos] = '\0'; /* Ensure null terminated. */
+ }
+
+ for (i=0;i<msgpos;) {
+ if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n') {
+ i++; continue;
+ }
+ write(fd,&msgbuf[i++],1);
+ }
+ close(fd);
/* run the command */
if (*lp_msg_command())
{
- strcpy(s,lp_msg_command());
- string_sub(s,"%s",name);
- string_sub(s,"%f",msgfrom);
- string_sub(s,"%t",msgto);
- standard_sub(-1,s);
+ fstring alpha_msgfrom;
+ fstring alpha_msgto;
+ pstring s;
+
+ pstrcpy(s,lp_msg_command());
+ pstring_sub(s,"%f",alpha_strcpy(alpha_msgfrom,msgfrom,NULL,sizeof(alpha_msgfrom)));
+ pstring_sub(s,"%t",alpha_strcpy(alpha_msgto,msgto,NULL,sizeof(alpha_msgto)));
+ standard_sub_basic(current_user_info.smb_name, s);
+ pstring_sub(s,"%s",name);
smbrun(s,NULL);
}
@@ -93,37 +99,42 @@ static void msg_deliver(void)
/****************************************************************************
reply to a sends
****************************************************************************/
-int reply_sends(char *inbuf,char *outbuf)
+int reply_sends(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int len;
- char *orig,*dest,*msg;
+ char *msg;
int outsize = 0;
+ char *p;
- msgpos = 0;
+ START_PROFILE(SMBsends);
+ msgpos = 0;
- if (! (*lp_msg_command()))
- return(ERROR(ERRSRV,ERRmsgoff));
+ if (! (*lp_msg_command())) {
+ END_PROFILE(SMBsends);
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
+ }
outsize = set_message(outbuf,0,0,True);
- orig = smb_buf(inbuf)+1;
- dest = skip_string(orig,1)+1;
- msg = skip_string(dest,1)+1;
+ p = smb_buf(inbuf)+1;
+ p += srvstr_pull(inbuf, msgfrom, p, sizeof(msgfrom), -1, STR_TERMINATE) + 1;
+ p += srvstr_pull(inbuf, msgto, p, sizeof(msgto), -1, STR_TERMINATE) + 1;
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ msg = p;
len = SVAL(msg,0);
- len = MIN(len,1600-msgpos);
+ len = MIN(len,sizeof(msgbuf)-msgpos);
+
+ memset(msgbuf,'\0',sizeof(msgbuf));
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
- DEBUG(3,("%s SMBsends (from %s to %s)\n",timestring(),orig,dest));
-
msg_deliver();
+ END_PROFILE(SMBsends);
return(outsize);
}
@@ -131,26 +142,31 @@ int reply_sends(char *inbuf,char *outbuf)
/****************************************************************************
reply to a sendstrt
****************************************************************************/
-int reply_sendstrt(char *inbuf,char *outbuf)
+int reply_sendstrt(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- char *orig,*dest;
int outsize = 0;
+ char *p;
- if (! (*lp_msg_command()))
- return(ERROR(ERRSRV,ERRmsgoff));
+ START_PROFILE(SMBsendstrt);
+
+ if (! (*lp_msg_command())) {
+ END_PROFILE(SMBsendstrt);
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
+ }
outsize = set_message(outbuf,1,0,True);
+ memset(msgbuf,'\0',sizeof(msgbuf));
msgpos = 0;
- orig = smb_buf(inbuf)+1;
- dest = skip_string(orig,1)+1;
-
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ p = smb_buf(inbuf)+1;
+ p += srvstr_pull(inbuf, msgfrom, p, sizeof(msgfrom), -1, STR_TERMINATE) + 1;
+ p += srvstr_pull(inbuf, msgto, p, sizeof(msgto), -1, STR_TERMINATE) + 1;
- DEBUG(3,("%s SMBsendstrt (from %s to %s)\n",timestring(),orig,dest));
+ DEBUG( 3, ( "SMBsendstrt (from %s to %s)\n", msgfrom, msgto ) );
+ END_PROFILE(SMBsendstrt);
return(outsize);
}
@@ -158,27 +174,32 @@ int reply_sendstrt(char *inbuf,char *outbuf)
/****************************************************************************
reply to a sendtxt
****************************************************************************/
-int reply_sendtxt(char *inbuf,char *outbuf)
+int reply_sendtxt(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int len;
int outsize = 0;
char *msg;
+ START_PROFILE(SMBsendtxt);
- if (! (*lp_msg_command()))
- return(ERROR(ERRSRV,ERRmsgoff));
+ if (! (*lp_msg_command())) {
+ END_PROFILE(SMBsendtxt);
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
+ }
outsize = set_message(outbuf,0,0,True);
msg = smb_buf(inbuf) + 1;
len = SVAL(msg,0);
- len = MIN(len,1600-msgpos);
+ len = MIN(len,sizeof(msgbuf)-msgpos);
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
- DEBUG(3,("%s SMBsendtxt\n",timestring()));
+ DEBUG( 3, ( "SMBsendtxt\n" ) );
+ END_PROFILE(SMBsendtxt);
return(outsize);
}
@@ -186,19 +207,23 @@ int reply_sendtxt(char *inbuf,char *outbuf)
/****************************************************************************
reply to a sendend
****************************************************************************/
-int reply_sendend(char *inbuf,char *outbuf)
+int reply_sendend(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
+ START_PROFILE(SMBsendend);
- if (! (*lp_msg_command()))
- return(ERROR(ERRSRV,ERRmsgoff));
+ if (! (*lp_msg_command())) {
+ END_PROFILE(SMBsendend);
+ return(ERROR_DOS(ERRSRV,ERRmsgoff));
+ }
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s SMBsendend\n",timestring()));
+ DEBUG(3,("SMBsendend\n"));
msg_deliver();
+ END_PROFILE(SMBsendend);
return(outsize);
}
-
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
new file mode 100644
index 00000000000..d3afa19d006
--- /dev/null
+++ b/source/smbd/negprot.c
@@ -0,0 +1,505 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ negprot reply code
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int Protocol;
+extern int max_recv;
+extern fstring global_myworkgroup;
+extern fstring remote_machine;
+BOOL global_encrypted_passwords_negotiated = False;
+BOOL global_spnego_negotiated = False;
+auth_authsupplied_info *negprot_global_auth_info = NULL;
+
+/****************************************************************************
+reply for the core protocol
+****************************************************************************/
+static int reply_corep(char *inbuf, char *outbuf)
+{
+ int outsize = set_message(outbuf,1,0,True);
+
+ Protocol = PROTOCOL_CORE;
+
+ return outsize;
+}
+
+
+/****************************************************************************
+reply for the coreplus protocol
+****************************************************************************/
+static int reply_coreplus(char *inbuf, char *outbuf)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int outsize = set_message(outbuf,13,0,True);
+ SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
+ readbraw and writebraw (possibly) */
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */
+
+ Protocol = PROTOCOL_COREPLUS;
+
+ return outsize;
+}
+
+
+/****************************************************************************
+reply for the lanman 1.0 protocol
+****************************************************************************/
+static int reply_lanman1(char *inbuf, char *outbuf)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int secword=0;
+ time_t t = time(NULL);
+ DATA_BLOB cryptkey;
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ if (lp_security()>=SEC_USER) secword |= 1;
+ if (global_encrypted_passwords_negotiated) secword |= 2;
+
+ set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
+ SSVAL(outbuf,smb_vwv1,secword);
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
+ smb_panic("cannot make_negprot_global_auth_info!\n");
+ }
+ cryptkey = auth_get_challenge(negprot_global_auth_info);
+ memcpy(smb_buf(outbuf), cryptkey.data, 8);
+ data_blob_free(&cryptkey);
+ }
+
+ Protocol = PROTOCOL_LANMAN1;
+
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(outbuf,smb_vwv2,max_recv);
+ SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
+ SSVAL(outbuf,smb_vwv4,1);
+ SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
+ readbraw writebraw (possibly) */
+ SIVAL(outbuf,smb_vwv6,sys_getpid());
+ SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
+
+ put_dos_date(outbuf,smb_vwv8,t);
+
+ return (smb_len(outbuf)+4);
+}
+
+
+/****************************************************************************
+reply for the lanman 2.0 protocol
+****************************************************************************/
+static int reply_lanman2(char *inbuf, char *outbuf)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int secword=0;
+ time_t t = time(NULL);
+ DATA_BLOB cryptkey;
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ if (lp_security()>=SEC_USER) secword |= 1;
+ if (global_encrypted_passwords_negotiated) secword |= 2;
+
+ set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
+ SSVAL(outbuf,smb_vwv1,secword);
+ SIVAL(outbuf,smb_vwv6,sys_getpid());
+
+ if (global_encrypted_passwords_negotiated) {
+ if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
+ smb_panic("cannot make_negprot_global_auth_info!\n");
+ }
+ cryptkey = auth_get_challenge(negprot_global_auth_info);
+ memcpy(smb_buf(outbuf), cryptkey.data, 8);
+ data_blob_free(&cryptkey);
+ }
+
+ Protocol = PROTOCOL_LANMAN2;
+
+ /* Reply, SMBlockread, SMBwritelock supported. */
+ SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(outbuf,smb_vwv2,max_recv);
+ SSVAL(outbuf,smb_vwv3,lp_maxmux());
+ SSVAL(outbuf,smb_vwv4,1);
+ SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
+ SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
+ put_dos_date(outbuf,smb_vwv8,t);
+
+ return (smb_len(outbuf)+4);
+}
+
+
+
+/*
+ generate the spnego negprot reply blob. Return the number of bytes used
+*/
+static int negprot_spnego(char *p)
+{
+ DATA_BLOB blob;
+ extern pstring global_myname;
+ uint8 guid[16];
+ const char *OIDs_krb5[] = {OID_NTLMSSP,
+ OID_KERBEROS5,
+ OID_KERBEROS5_OLD,
+ NULL};
+ const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
+ char *principal;
+ int len;
+
+ global_spnego_negotiated = True;
+
+ memset(guid, 0, 16);
+ safe_strcpy((char *)guid, global_myname, 16);
+ strlower((char *)guid);
+
+#if 0
+ /* strangely enough, NT does not sent the single OID NTLMSSP when
+ not a ADS member, it sends no OIDs at all
+
+ we can't do this until we teach our sesssion setup parser to know
+ about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
+ */
+ if (lp_security() != SEC_ADS) {
+ memcpy(p, guid, 16);
+ return 16;
+ }
+#endif
+ {
+ ADS_STRUCT *ads;
+ ads = ads_init(NULL, NULL, NULL, NULL);
+
+ /* win2000 uses host$@REALM, which we will probably use eventually,
+ but for now this works */
+ asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
+ blob = spnego_gen_negTokenInit(guid,
+ lp_security()==SEC_ADS ? OIDs_krb5 : OIDs_plain,
+ principal);
+ free(principal);
+ ads_destroy(&ads);
+ }
+ memcpy(p, blob.data, blob.length);
+ len = blob.length;
+ data_blob_free(&blob);
+ return len;
+}
+
+
+
+/****************************************************************************
+reply for the nt protocol
+****************************************************************************/
+static int reply_nt1(char *inbuf, char *outbuf)
+{
+ /* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+ CAP_LEVEL_II_OPLOCKS|CAP_STATUS32;
+
+ int secword=0;
+ time_t t = time(NULL);
+ DATA_BLOB cryptkey;
+ char *p, *q;
+ BOOL negotiate_spnego = False;
+
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
+ /* do spnego in user level security if the client
+ supports it and we can do encrypted passwords */
+
+ if (global_encrypted_passwords_negotiated &&
+ (lp_security() != SEC_SHARE) &&
+ lp_use_spnego() &&
+ (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
+ negotiate_spnego = True;
+ capabilities |= CAP_EXTENDED_SECURITY;
+ }
+
+ capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+
+ if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
+ capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
+ }
+
+ if (SMB_OFF_T_BITS == 64) {
+ capabilities |= CAP_LARGE_FILES;
+ }
+
+ if (lp_readraw() && lp_writeraw()) {
+ capabilities |= CAP_RAW_MODE;
+ }
+
+ /* allow for disabling unicode */
+ if (lp_unicode()) {
+ capabilities |= CAP_UNICODE;
+ }
+
+ if (lp_host_msdfs())
+ capabilities |= CAP_DFS;
+
+ if (lp_security() >= SEC_USER) secword |= 1;
+ if (global_encrypted_passwords_negotiated) secword |= 2;
+
+ set_message(outbuf,17,0,True);
+
+ CVAL(outbuf,smb_vwv1) = secword;
+
+ Protocol = PROTOCOL_NT1;
+
+ SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
+ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
+ SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
+ SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
+ SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
+ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
+ put_long_date(outbuf+smb_vwv11+1,t);
+ SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
+
+ p = q = smb_buf(outbuf);
+ if (!negotiate_spnego) {
+ if (global_encrypted_passwords_negotiated) {
+ if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
+ smb_panic("cannot make_negprot_global_auth_info!\n");
+ }
+ cryptkey = auth_get_challenge(negprot_global_auth_info);
+ memcpy(p, cryptkey.data, 8);
+ data_blob_free(&cryptkey);
+ }
+ SSVALS(outbuf,smb_vwv16+1,8);
+ p += 8;
+ p += srvstr_push(outbuf, p, global_myworkgroup, -1,
+ STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
+ DEBUG(3,("not using SPNEGO\n"));
+ } else {
+ int len = negprot_spnego(p);
+
+ SSVALS(outbuf,smb_vwv16+1,len);
+ p += len;
+ DEBUG(3,("using SPNEGO\n"));
+ }
+
+ SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
+ set_message_end(outbuf, p);
+
+ return (smb_len(outbuf)+4);
+}
+
+/* these are the protocol lists used for auto architecture detection:
+
+WinNT 3.51:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [MICROSOFT NETWORKS 1.03]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+Win95:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [MICROSOFT NETWORKS 1.03]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+Win2K:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
+OS/2:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [XENIX CORE]
+protocol [LANMAN1.0]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+*/
+
+/*
+ * Modified to recognize the architecture of the remote machine better.
+ *
+ * This appears to be the matrix of which protocol is used by which
+ * MS product.
+ Protocol WfWg Win95 WinNT Win2K OS/2
+ PC NETWORK PROGRAM 1.0 1 1 1 1 1
+ XENIX CORE 2 2
+ MICROSOFT NETWORKS 3.0 2 2
+ DOS LM1.2X002 3 3
+ MICROSOFT NETWORKS 1.03 3
+ DOS LANMAN2.1 4 4
+ LANMAN1.0 4 2 3
+ Windows for Workgroups 3.1a 5 5 5 3
+ LM1.2X002 6 4 4
+ LANMAN2.1 7 5 5
+ NT LM 0.12 6 8 6
+ *
+ * tim@fsg.com 09/29/95
+ * Win2K added by matty 17/7/99
+ */
+
+#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
+#define ARCH_WIN95 0x2
+#define ARCH_WINNT 0x4
+#define ARCH_WIN2K 0xC /* Win2K is like NT */
+#define ARCH_OS2 0x14 /* Again OS/2 is like NT */
+#define ARCH_SAMBA 0x20
+
+#define ARCH_ALL 0x3F
+
+/* List of supported protocols, most desired first */
+static struct {
+ char *proto_name;
+ char *short_name;
+ int (*proto_reply_fn)(char *, char *);
+ int protocol_level;
+} supported_protocols[] = {
+ {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
+ {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
+ {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
+ {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
+ {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
+ {NULL,NULL,NULL,0},
+};
+
+
+/****************************************************************************
+ reply to a negprot
+****************************************************************************/
+int reply_negprot(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ int outsize = set_message(outbuf,1,0,True);
+ int Index=0;
+ int choice= -1;
+ int protocol;
+ char *p;
+ int bcc = SVAL(smb_buf(inbuf),-2);
+ int arch = ARCH_ALL;
+ START_PROFILE(SMBnegprot);
+
+ p = smb_buf(inbuf)+1;
+ while (p < (smb_buf(inbuf) + bcc))
+ {
+ Index++;
+ DEBUG(3,("Requested protocol [%s]\n",p));
+ if (strcsequal(p,"Windows for Workgroups 3.1a"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
+ else if (strcsequal(p,"DOS LM1.2X002"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 );
+ else if (strcsequal(p,"DOS LANMAN2.1"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 );
+ else if (strcsequal(p,"NT LM 0.12"))
+ arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
+ else if (strcsequal(p,"LANMAN2.1"))
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
+ else if (strcsequal(p,"LM1.2X002"))
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
+ else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
+ arch &= ARCH_WINNT;
+ else if (strcsequal(p,"XENIX CORE"))
+ arch &= ( ARCH_WINNT | ARCH_OS2 );
+ else if (strcsequal(p,"Samba")) {
+ arch = ARCH_SAMBA;
+ break;
+ }
+
+ p += strlen(p) + 2;
+ }
+
+ switch ( arch ) {
+ case ARCH_SAMBA:
+ set_remote_arch(RA_SAMBA);
+ break;
+ case ARCH_WFWG:
+ set_remote_arch(RA_WFWG);
+ break;
+ case ARCH_WIN95:
+ set_remote_arch(RA_WIN95);
+ break;
+ case ARCH_WINNT:
+ if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
+ set_remote_arch(RA_WIN2K);
+ else
+ set_remote_arch(RA_WINNT);
+ break;
+ case ARCH_WIN2K:
+ set_remote_arch(RA_WIN2K);
+ break;
+ case ARCH_OS2:
+ set_remote_arch(RA_OS2);
+ break;
+ default:
+ set_remote_arch(RA_UNKNOWN);
+ break;
+ }
+
+ /* possibly reload - change of architecture */
+ reload_services(True);
+
+ /* Check for protocols, most desirable first */
+ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
+ {
+ p = smb_buf(inbuf)+1;
+ Index = 0;
+ if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
+ (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
+ while (p < (smb_buf(inbuf) + bcc))
+ {
+ if (strequal(p,supported_protocols[protocol].proto_name))
+ choice = Index;
+ Index++;
+ p += strlen(p) + 2;
+ }
+ if(choice != -1)
+ break;
+ }
+
+ SSVAL(outbuf,smb_vwv0,choice);
+ if(choice != -1) {
+ extern fstring remote_proto;
+ fstrcpy(remote_proto,supported_protocols[protocol].short_name);
+ reload_services(True);
+ outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
+ DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
+ }
+ else {
+ DEBUG(0,("No protocol supported !\n"));
+ }
+ SSVAL(outbuf,smb_vwv0,choice);
+
+ DEBUG( 5, ( "negprot index=%d\n", choice ) );
+
+ END_PROFILE(SMBnegprot);
+ return(outsize);
+}
+
diff --git a/source/smbd/noquotas.c b/source/smbd/noquotas.c
new file mode 100644
index 00000000000..a6951d97fc5
--- /dev/null
+++ b/source/smbd/noquotas.c
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ No support for quotas :-).
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * Needed for auto generation of proto.h.
+ */
+
+BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ (*bsize) = 512; /* This value should be ignored */
+
+ /* And just to be sure we set some values that hopefully */
+ /* will be larger that any possible real-world value */
+ (*dfree) = (SMB_BIG_UINT)-1;
+ (*dsize) = (SMB_BIG_UINT)-1;
+
+ /* As we have select not to use quotas, allways fail */
+ return False;
+}
diff --git a/source/smbd/notify.c b/source/smbd/notify.c
new file mode 100644
index 00000000000..52df3558aa7
--- /dev/null
+++ b/source/smbd/notify.c
@@ -0,0 +1,221 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ change notify handling
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static struct cnotify_fns *cnotify;
+
+/****************************************************************************
+ This is the structure to queue to implement NT change
+ notify. It consists of smb_size bytes stored from the
+ transact command (to keep the mid, tid etc around).
+ Plus the fid to examine and notify private data.
+*****************************************************************************/
+
+struct change_notify {
+ struct change_notify *next, *prev;
+ files_struct *fsp;
+ connection_struct *conn;
+ uint32 flags;
+ char request_buf[smb_size];
+ void *change_data;
+};
+
+static struct change_notify *change_notify_list;
+
+/****************************************************************************
+ Setup the common parts of the return packet and send it.
+*****************************************************************************/
+static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
+{
+ char outbuf[smb_size+38];
+
+ memset(outbuf, '\0', sizeof(outbuf));
+ construct_reply_common(inbuf, outbuf);
+
+ ERROR_NT(error_code);
+
+ /*
+ * Seems NT needs a transact command with an error code
+ * in it. This is a longer packet than a simple error.
+ */
+ set_message(outbuf,18,0,False);
+
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("change_notify_reply_packet: send_smb failed.");
+}
+
+/****************************************************************************
+ Remove an entry from the list and free it, also closing any
+ directory handle if necessary.
+*****************************************************************************/
+
+static void change_notify_remove(struct change_notify *cnbp)
+{
+ cnotify->remove_notify(cnbp->change_data);
+ DLIST_REMOVE(change_notify_list, cnbp);
+ ZERO_STRUCTP(cnbp);
+ SAFE_FREE(cnbp);
+}
+
+/****************************************************************************
+ Delete entries by fnum from the change notify pending queue.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
+{
+ struct change_notify *cnbp, *next;
+
+ for (cnbp=change_notify_list; cnbp; cnbp=next) {
+ next=cnbp->next;
+ if (cnbp->fsp->fnum == fsp->fnum) {
+ change_notify_remove(cnbp);
+ }
+ }
+}
+
+/****************************************************************************
+ Delete entries by mid from the change notify pending queue. Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_mid(int mid)
+{
+ struct change_notify *cnbp, *next;
+
+ for (cnbp=change_notify_list; cnbp; cnbp=next) {
+ next=cnbp->next;
+ if(SVAL(cnbp->request_buf,smb_mid) == mid) {
+ change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
+ change_notify_remove(cnbp);
+ }
+ }
+}
+
+/****************************************************************************
+ Delete entries by filename and cnum from the change notify pending queue.
+ Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
+{
+ struct change_notify *cnbp, *next;
+
+ for (cnbp=change_notify_list; cnbp; cnbp=next) {
+ next=cnbp->next;
+ /*
+ * We know it refers to the same directory if the connection number and
+ * the filename are identical.
+ */
+ if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
+ change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
+ change_notify_remove(cnbp);
+ }
+ }
+}
+
+/****************************************************************************
+ Return true if there are pending change notifies.
+****************************************************************************/
+
+int change_notify_timeout(void)
+{
+ return cnotify->select_time;
+}
+
+/****************************************************************************
+ Process the change notify queue. Note that this is only called as root.
+ Returns True if there are still outstanding change notify requests on the
+ queue.
+*****************************************************************************/
+
+BOOL process_pending_change_notify_queue(time_t t)
+{
+ struct change_notify *cnbp, *next;
+ uint16 vuid;
+
+ for (cnbp=change_notify_list; cnbp; cnbp=next) {
+ next=cnbp->next;
+
+ vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
+
+ if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) {
+ DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name ));
+ change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
+ change_notify_remove(cnbp);
+ }
+ }
+
+ return (change_notify_list != NULL);
+}
+
+/****************************************************************************
+ Now queue an entry on the notify change list.
+ We only need to save smb_size bytes from this incoming packet
+ as we will always by returning a 'read the directory yourself'
+ error.
+****************************************************************************/
+
+BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags)
+{
+ struct change_notify *cnbp;
+
+ if((cnbp = (struct change_notify *)malloc(sizeof(*cnbp))) == NULL) {
+ DEBUG(0,("call_nt_transact_notify_change: malloc fail !\n" ));
+ return -1;
+ }
+
+ ZERO_STRUCTP(cnbp);
+
+ memcpy(cnbp->request_buf, inbuf, smb_size);
+ cnbp->fsp = fsp;
+ cnbp->conn = conn;
+ cnbp->flags = flags;
+ cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags);
+
+ if (!cnbp->change_data) {
+ SAFE_FREE(cnbp);
+ return False;
+ }
+
+ DLIST_ADD(change_notify_list, cnbp);
+
+ return True;
+}
+
+/****************************************************************************
+ Initialise the change notify subsystem.
+****************************************************************************/
+
+BOOL init_change_notify(void)
+{
+#if HAVE_KERNEL_CHANGE_NOTIFY
+ cnotify = kernel_notify_init();
+#endif
+ if (!cnotify) cnotify = hash_notify_init();
+
+ if (!cnotify) {
+ DEBUG(0,("Failed to init change notify system\n"));
+ return False;
+ }
+
+ return True;
+}
diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c
new file mode 100644
index 00000000000..178dcecc823
--- /dev/null
+++ b/source/smbd/notify_hash.c
@@ -0,0 +1,226 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ change notify handling - hash based implementation
+ Copyright (C) Jeremy Allison 1994-1998
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct change_data {
+ time_t last_check_time; /* time we last checked this entry */
+ time_t modify_time; /* Info from the directory we're monitoring. */
+ time_t status_time; /* Info from the directory we're monitoring. */
+ time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
+ unsigned int num_entries; /* Zero or the number of files in the directory. */
+ unsigned int mode_sum;
+ unsigned char name_hash[16];
+};
+
+/****************************************************************************
+ Create the hash we will use to determine if the contents changed.
+*****************************************************************************/
+
+static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
+ struct change_data *data, struct change_data *old_data)
+{
+ SMB_STRUCT_STAT st;
+ pstring full_name;
+ char *p;
+ char *fname;
+ size_t remaining_len;
+ size_t fullname_len;
+ void *dp;
+
+ ZERO_STRUCTP(data);
+
+ if(vfs_stat(conn,path, &st) == -1)
+ return False;
+
+ data->modify_time = st.st_mtime;
+ data->status_time = st.st_ctime;
+
+ if (old_data) {
+ /*
+ * Shortcut to avoid directory scan if the time
+ * has changed - we always must return true then.
+ */
+ if (old_data->modify_time != data->modify_time ||
+ old_data->status_time != data->status_time ) {
+ return True;
+ }
+ }
+
+ /*
+ * If we are to watch for changes that are only stored
+ * in inodes of files, not in the directory inode, we must
+ * scan the directory and produce a unique identifier with
+ * which we can determine if anything changed. We use the
+ * modify and change times from all the files in the
+ * directory, added together (ignoring wrapping if it's
+ * larger than the max time_t value).
+ */
+
+ dp = OpenDir(conn, path, True);
+ if (dp == NULL)
+ return False;
+
+ data->num_entries = 0;
+
+ pstrcpy(full_name, path);
+ pstrcat(full_name, "/");
+
+ fullname_len = strlen(full_name);
+ remaining_len = sizeof(full_name) - fullname_len - 1;
+ p = &full_name[fullname_len];
+
+ while ((fname = ReadDirName(dp))) {
+ if(strequal(fname, ".") || strequal(fname, ".."))
+ continue;
+
+ data->num_entries++;
+ safe_strcpy(p, fname, remaining_len);
+
+ ZERO_STRUCT(st);
+
+ /*
+ * Do the stat - but ignore errors.
+ */
+ vfs_stat(conn,full_name, &st);
+
+ /*
+ * Always sum the times.
+ */
+
+ data->total_time += (st.st_mtime + st.st_ctime);
+
+ /*
+ * If requested hash the names.
+ */
+
+ if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) {
+ int i;
+ unsigned char tmp_hash[16];
+ mdfour(tmp_hash, (unsigned char *)fname, strlen(fname));
+ for (i=0;i<16;i++)
+ data->name_hash[i] ^= tmp_hash[i];
+ }
+
+ /*
+ * If requested sum the mode_t's.
+ */
+
+ if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY))
+ data->mode_sum = st.st_mode;
+ }
+
+ CloseDir(dp);
+
+ return True;
+}
+
+/****************************************************************************
+ Register a change notify request.
+*****************************************************************************/
+
+static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
+{
+ struct change_data data;
+
+ if (!notify_hash(conn, path, flags, &data, NULL))
+ return NULL;
+
+ data.last_check_time = time(NULL);
+
+ return (void *)memdup(&data, sizeof(data));
+}
+
+/****************************************************************************
+ Check if a change notify should be issued.
+ A time of zero means instantaneous check - don't modify the last check time.
+*****************************************************************************/
+
+static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
+{
+ struct change_data *data = (struct change_data *)datap;
+ struct change_data data2;
+
+ if (t && t < data->last_check_time + lp_change_notify_timeout())
+ return False;
+
+ if (!change_to_user(conn,vuid))
+ return True;
+ if (!set_current_service(conn,True)) {
+ change_to_root_user();
+ return True;
+ }
+
+ if (!notify_hash(conn, path, flags, &data2, data) ||
+ data2.modify_time != data->modify_time ||
+ data2.status_time != data->status_time ||
+ data2.total_time != data->total_time ||
+ data2.num_entries != data->num_entries ||
+ data2.mode_sum != data->mode_sum ||
+ memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) {
+ change_to_root_user();
+ return True;
+ }
+
+ if (t)
+ data->last_check_time = t;
+
+ change_to_root_user();
+
+ return False;
+}
+
+/****************************************************************************
+ Remove a change notify data structure.
+*****************************************************************************/
+
+static void hash_remove_notify(void *datap)
+{
+ free(datap);
+}
+
+/****************************************************************************
+ Setup hash based change notify.
+****************************************************************************/
+
+struct cnotify_fns *hash_notify_init(void)
+{
+ static struct cnotify_fns cnotify;
+
+ cnotify.register_notify = hash_register_notify;
+ cnotify.check_notify = hash_check_notify;
+ cnotify.remove_notify = hash_remove_notify;
+ cnotify.select_time = lp_change_notify_timeout();
+
+ return &cnotify;
+}
+
+/*
+ change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+ change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
+
+ chain_size = 0;
+ file_chain_reset();
+
+ uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
+ SVAL(cnbp->request_buf,smb_uid);
+*/
diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c
new file mode 100644
index 00000000000..f618700bf0f
--- /dev/null
+++ b/source/smbd/notify_kernel.c
@@ -0,0 +1,207 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ change notify handling - linux kernel based implementation
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if HAVE_KERNEL_CHANGE_NOTIFY
+
+static VOLATILE sig_atomic_t fd_pending;
+static VOLATILE sig_atomic_t signals_received;
+static VOLATILE sig_atomic_t signals_processed;
+
+#ifndef DN_ACCESS
+#define DN_ACCESS 0x00000001 /* File accessed in directory */
+#define DN_MODIFY 0x00000002 /* File modified in directory */
+#define DN_CREATE 0x00000004 /* File created in directory */
+#define DN_DELETE 0x00000008 /* File removed from directory */
+#define DN_RENAME 0x00000010 /* File renamed in directory */
+#define DN_ATTRIB 0x00000020 /* File changed attribute */
+#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
+#endif
+
+
+#ifndef RT_SIGNAL_NOTIFY
+#define RT_SIGNAL_NOTIFY 34
+#endif
+
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+
+/****************************************************************************
+ This is the structure to keep the information needed to
+ determine if a directory has changed.
+*****************************************************************************/
+struct change_data {
+ int directory_handle;
+};
+
+/****************************************************************************
+the signal handler for change notify
+*****************************************************************************/
+static void signal_handler(int sig, siginfo_t *info, void *unused)
+{
+ BlockSignals(True, sig);
+ fd_pending = (sig_atomic_t)info->si_fd;
+ signals_received++;
+ sys_select_signal();
+}
+
+
+
+/****************************************************************************
+ Check if a change notify should be issued.
+ time non-zero means timeout check (used for hash). Ignore this (async method
+ where time is zero will be used instead).
+*****************************************************************************/
+static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
+{
+ struct change_data *data = (struct change_data *)datap;
+
+ if (t)
+ return False;
+
+ if (data->directory_handle != (int)fd_pending) return False;
+
+ DEBUG(3,("kernel change notify on %s fd=%d\n", path, (int)fd_pending));
+
+ close((int)fd_pending);
+ fd_pending = (sig_atomic_t)-1;
+ data->directory_handle = -1;
+ signals_processed++;
+ BlockSignals(False, RT_SIGNAL_NOTIFY);
+ return True;
+}
+
+/****************************************************************************
+remove a change notify data structure
+*****************************************************************************/
+static void kernel_remove_notify(void *datap)
+{
+ struct change_data *data = (struct change_data *)datap;
+ int fd = data->directory_handle;
+ if (fd != -1) {
+ if (fd == (int)fd_pending) {
+ fd_pending = (sig_atomic_t)-1;
+ signals_processed++;
+ BlockSignals(False, RT_SIGNAL_NOTIFY);
+ }
+ close(fd);
+ }
+ SAFE_FREE(data);
+ DEBUG(3,("removed kernel change notify fd=%d\n", fd));
+}
+
+
+/****************************************************************************
+register a change notify request
+*****************************************************************************/
+static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags)
+{
+ struct change_data data;
+ int fd;
+ unsigned long kernel_flags;
+
+ fd = conn->vfs_ops.open(conn, path, O_RDONLY, 0);
+
+ if (fd == -1) {
+ DEBUG(3,("Failed to open directory %s for change notify\n", path));
+ return NULL;
+ }
+
+ if (fcntl(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) {
+ DEBUG(3,("Failed to set signal handler for change notify\n"));
+ return NULL;
+ }
+
+ kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion changes everything! */
+ if (flags & FILE_NOTIFY_CHANGE_FILE) kernel_flags |= DN_MODIFY;
+ if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
+ if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB;
+ if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY;
+ if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY;
+ if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS;
+ if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE;
+ if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB;
+ if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB;
+ if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
+
+ if (fcntl(fd, F_NOTIFY, kernel_flags) == -1) {
+ DEBUG(3,("Failed to set async flag for change notify\n"));
+ return NULL;
+ }
+
+ data.directory_handle = fd;
+
+ DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) fd=%d\n",
+ path, (int)flags, (int)kernel_flags, fd));
+
+ return (void *)memdup(&data, sizeof(data));
+}
+
+/****************************************************************************
+see if the kernel supports change notify
+****************************************************************************/
+static BOOL kernel_notify_available(void)
+{
+ int fd, ret;
+ fd = open("/tmp", O_RDONLY);
+ if (fd == -1) return False; /* uggh! */
+ ret = fcntl(fd, F_NOTIFY, 0);
+ close(fd);
+ return ret == 0;
+}
+
+
+/****************************************************************************
+setup kernel based change notify
+****************************************************************************/
+struct cnotify_fns *kernel_notify_init(void)
+{
+ static struct cnotify_fns cnotify;
+ struct sigaction act;
+
+ act.sa_handler = NULL;
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) {
+ DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n"));
+ return NULL;
+ }
+
+ if (!kernel_notify_available()) return NULL;
+
+ cnotify.register_notify = kernel_register_notify;
+ cnotify.check_notify = kernel_check_notify;
+ cnotify.remove_notify = kernel_remove_notify;
+ cnotify.select_time = -1;
+
+ return &cnotify;
+}
+
+
+#else
+ void notify_kernel_dummy(void) {}
+#endif /* HAVE_KERNEL_CHANGE_NOTIFY */
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
new file mode 100644
index 00000000000..7a6ea52aca1
--- /dev/null
+++ b/source/smbd/nttrans.c
@@ -0,0 +1,1880 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB NT transaction handling
+ Copyright (C) Jeremy Allison 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int Protocol;
+extern int smb_read_error;
+extern int global_oplock_break;
+extern BOOL case_sensitive;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
+
+static char *known_nt_pipes[] = {
+ "\\LANMAN",
+ "\\srvsvc",
+ "\\samr",
+ "\\wkssvc",
+ "\\NETLOGON",
+ "\\ntlsa",
+ "\\ntsvcs",
+ "\\lsass",
+ "\\lsarpc",
+ "\\winreg",
+ "\\spoolss",
+ "\\netdfs",
+ NULL
+};
+
+/* Map generic permissions to file object specific permissions */
+
+struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
+/****************************************************************************
+ Send the required number of replies back.
+ We assume all fields other than the data fields are
+ set correctly for the type of call.
+ HACK ! Always assumes smb_setup field is zero.
+****************************************************************************/
+
+static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params,
+ int paramsize, char *pdata, int datasize)
+{
+ extern int max_send;
+ int data_to_send = datasize;
+ int params_to_send = paramsize;
+ int useable_space;
+ char *pp = params;
+ char *pd = pdata;
+ int params_sent_thistime, data_sent_thistime, total_sent_thistime;
+ int alignment_offset = 3;
+ int data_alignment_offset = 0;
+
+ /*
+ * Initially set the wcnt area to be 18 - this is true for all
+ * transNT replies.
+ */
+
+ set_message(outbuf,18,0,True);
+
+ if (NT_STATUS_V(nt_error)) {
+ ERROR_NT(nt_error);
+ }
+
+ /*
+ * If there genuinely are no parameters or data to send just send
+ * the empty packet.
+ */
+
+ if(params_to_send == 0 && data_to_send == 0) {
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_nt_replies: send_smb failed.");
+ return 0;
+ }
+
+ /*
+ * When sending params and data ensure that both are nicely aligned.
+ * Only do this alignment when there is also data to send - else
+ * can cause NT redirector problems.
+ */
+
+ if (((params_to_send % 4) != 0) && (data_to_send != 0))
+ data_alignment_offset = 4 - (params_to_send % 4);
+
+ /*
+ * Space is bufsize minus Netbios over TCP header minus SMB header.
+ * The alignment_offset is to align the param bytes on a four byte
+ * boundary (2 bytes for data len, one byte pad).
+ * NT needs this to work correctly.
+ */
+
+ useable_space = bufsize - ((smb_buf(outbuf)+
+ alignment_offset+data_alignment_offset) -
+ outbuf);
+
+ /*
+ * useable_space can never be more than max_send minus the
+ * alignment offset.
+ */
+
+ useable_space = MIN(useable_space,
+ max_send - (alignment_offset+data_alignment_offset));
+
+
+ while (params_to_send || data_to_send) {
+
+ /*
+ * Calculate whether we will totally or partially fill this packet.
+ */
+
+ total_sent_thistime = params_to_send + data_to_send +
+ alignment_offset + data_alignment_offset;
+
+ /*
+ * We can never send more than useable_space.
+ */
+
+ total_sent_thistime = MIN(total_sent_thistime, useable_space);
+
+ set_message(outbuf, 18, total_sent_thistime, True);
+
+ /*
+ * Set total params and data to be sent.
+ */
+
+ SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize);
+ SIVAL(outbuf,smb_ntr_TotalDataCount,datasize);
+
+ /*
+ * Calculate how many parameters and data we can fit into
+ * this packet. Parameters get precedence.
+ */
+
+ params_sent_thistime = MIN(params_to_send,useable_space);
+ data_sent_thistime = useable_space - params_sent_thistime;
+ data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+
+ SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime);
+
+ if(params_sent_thistime == 0) {
+ SIVAL(outbuf,smb_ntr_ParameterOffset,0);
+ SIVAL(outbuf,smb_ntr_ParameterDisplacement,0);
+ } else {
+ /*
+ * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the
+ * parameter bytes, however the first 4 bytes of outbuf are
+ * the Netbios over TCP header. Thus use smb_base() to subtract
+ * them from the calculation.
+ */
+
+ SIVAL(outbuf,smb_ntr_ParameterOffset,
+ ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+ /*
+ * Absolute displacement of param bytes sent in this packet.
+ */
+
+ SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params);
+ }
+
+ /*
+ * Deal with the data portion.
+ */
+
+ SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime);
+
+ if(data_sent_thistime == 0) {
+ SIVAL(outbuf,smb_ntr_DataOffset,0);
+ SIVAL(outbuf,smb_ntr_DataDisplacement, 0);
+ } else {
+ /*
+ * The offset of the data bytes is the offset of the
+ * parameter bytes plus the number of parameters being sent this time.
+ */
+
+ SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) -
+ smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
+ SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata);
+ }
+
+ /*
+ * Copy the param bytes into the packet.
+ */
+
+ if(params_sent_thistime)
+ memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
+
+ /*
+ * Copy in the data bytes
+ */
+
+ if(data_sent_thistime)
+ memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
+ data_alignment_offset,pd,data_sent_thistime);
+
+ DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
+ params_sent_thistime, data_sent_thistime, useable_space));
+ DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
+ params_to_send, data_to_send, paramsize, datasize));
+
+ /* Send the packet */
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_nt_replies: send_smb failed.");
+
+ pp += params_sent_thistime;
+ pd += data_sent_thistime;
+
+ params_to_send -= params_sent_thistime;
+ data_to_send -= data_sent_thistime;
+
+ /*
+ * Sanity check
+ */
+
+ if(params_to_send < 0 || data_to_send < 0) {
+ DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!",
+ params_to_send, data_to_send));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Save case statics.
+****************************************************************************/
+
+static BOOL saved_case_sensitive;
+static BOOL saved_case_preserve;
+static BOOL saved_short_case_preserve;
+
+/****************************************************************************
+ Save case semantics.
+****************************************************************************/
+
+static void set_posix_case_semantics(uint32 file_attributes)
+{
+ if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+ return;
+
+ saved_case_sensitive = case_sensitive;
+ saved_case_preserve = case_preserve;
+ saved_short_case_preserve = short_case_preserve;
+
+ /* Set to POSIX. */
+ case_sensitive = True;
+ case_preserve = True;
+ short_case_preserve = True;
+}
+
+/****************************************************************************
+ Restore case semantics.
+****************************************************************************/
+
+static void restore_case_semantics(uint32 file_attributes)
+{
+ if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+ return;
+
+ case_sensitive = saved_case_sensitive;
+ case_preserve = saved_case_preserve;
+ short_case_preserve = saved_short_case_preserve;
+}
+
+/****************************************************************************
+ Utility function to map create disposition.
+****************************************************************************/
+
+static int map_create_disposition( uint32 create_disposition)
+{
+ int ret;
+
+ switch( create_disposition ) {
+ case FILE_CREATE:
+ /* create if not exist, fail if exist */
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL);
+ break;
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ /* create if not exist, trunc if exist */
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+ break;
+ case FILE_OPEN:
+ /* fail if not exist, open if exists */
+ ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+ break;
+ case FILE_OPEN_IF:
+ /* create if not exist, open if exists */
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+ break;
+ case FILE_OVERWRITE:
+ /* fail if not exist, truncate if exists */
+ ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+ break;
+ default:
+ DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
+ create_disposition ));
+ return -1;
+ }
+
+ DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n",
+ (unsigned long)create_disposition, ret ));
+
+ return ret;
+}
+
+/****************************************************************************
+ Utility function to map share modes.
+****************************************************************************/
+
+static int map_share_mode( BOOL *pstat_open_only, char *fname, uint32 create_options,
+ uint32 desired_access, uint32 share_access, uint32 file_attributes)
+{
+ int smb_open_mode = -1;
+
+ *pstat_open_only = False;
+
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&desired_access, &file_generic_mapping);
+
+ switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
+ case FILE_READ_DATA:
+ smb_open_mode = DOS_OPEN_RDONLY;
+ break;
+ case FILE_WRITE_DATA:
+ case FILE_APPEND_DATA:
+ case FILE_WRITE_DATA|FILE_APPEND_DATA:
+ smb_open_mode = DOS_OPEN_WRONLY;
+ break;
+ case FILE_READ_DATA|FILE_WRITE_DATA:
+ case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA:
+ case FILE_READ_DATA|FILE_APPEND_DATA:
+ smb_open_mode = DOS_OPEN_RDWR;
+ break;
+ }
+
+ /*
+ * NB. For DELETE_ACCESS we should really check the
+ * directory permissions, as that is what controls
+ * delete, and for WRITE_DAC_ACCESS we should really
+ * check the ownership, as that is what controls the
+ * chmod. Note that this is *NOT* a security hole (this
+ * note is for you, Andrew) as we are not *allowing*
+ * the access at this point, the actual unlink or
+ * chown or chmod call would do this. We are just helping
+ * clients out by telling them if they have a hope
+ * of any of this succeeding. POSIX acls may still
+ * deny the real call. JRA.
+ */
+
+ if (smb_open_mode == -1) {
+
+ if(desired_access == WRITE_DAC_ACCESS || desired_access == READ_CONTROL_ACCESS)
+ *pstat_open_only = True;
+
+ if(desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
+ FILE_EXECUTE|FILE_READ_ATTRIBUTES|
+ FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS|
+ FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) {
+ smb_open_mode = DOS_OPEN_RDONLY;
+ } else if(desired_access == 0) {
+
+ /*
+ * JRA - NT seems to sometimes send desired_access as zero. play it safe
+ * and map to a stat open.
+ */
+
+ *pstat_open_only = True;
+ smb_open_mode = DOS_OPEN_RDONLY;
+
+ } else {
+ DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n",
+ (unsigned long)desired_access, fname));
+ return -1;
+ }
+ }
+
+ /*
+ * Set the special bit that means allow share delete.
+ * This is held outside the normal share mode bits at 1<<15.
+ * JRA.
+ */
+
+ if(share_access & FILE_SHARE_DELETE) {
+ smb_open_mode |= ALLOW_SHARE_DELETE;
+ DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode));
+ }
+
+ /*
+ * We need to store the intent to open for Delete. This
+ * is what determines if a delete on close flag can be set.
+ * This is the wrong way (and place) to store this, but for 2.2 this
+ * is the only practical way. JRA.
+ */
+
+ if(desired_access & DELETE_ACCESS) {
+ smb_open_mode |= DELETE_ACCESS_REQUESTED;
+ DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode));
+ }
+
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ /* Implicit delete access requested... */
+ smb_open_mode |= DELETE_ACCESS_REQUESTED;
+ smb_open_mode |= DELETE_ON_CLOSE_FLAG;
+ DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode));
+ }
+
+ /* Add in the requested share mode. */
+ switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
+ case FILE_SHARE_READ:
+ smb_open_mode |= SET_DENY_MODE(DENY_WRITE);
+ break;
+ case FILE_SHARE_WRITE:
+ smb_open_mode |= SET_DENY_MODE(DENY_READ);
+ break;
+ case (FILE_SHARE_READ|FILE_SHARE_WRITE):
+ smb_open_mode |= SET_DENY_MODE(DENY_NONE);
+ break;
+ case FILE_SHARE_NONE:
+ smb_open_mode |= SET_DENY_MODE(DENY_ALL);
+ break;
+ }
+
+ /*
+ * Handle an O_SYNC request.
+ */
+
+ if(file_attributes & FILE_FLAG_WRITE_THROUGH)
+ smb_open_mode |= FILE_SYNC_OPENMODE;
+
+ DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \
+to open_mode 0x%x\n", (unsigned long)desired_access, (unsigned long)share_access,
+ (unsigned long)file_attributes, smb_open_mode ));
+
+ return smb_open_mode;
+}
+
+/****************************************************************************
+ Reply to an NT create and X call on a pipe.
+****************************************************************************/
+static int nt_open_pipe(char *fname, connection_struct *conn,
+ char *inbuf, char *outbuf, int *ppnum)
+{
+ pipes_struct *p = NULL;
+
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ int i;
+
+ DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname));
+
+ /* See if it is one we want to handle. */
+
+ if (lp_disable_spoolss() && strequal(fname, "\\spoolss"))
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+
+ for( i = 0; known_nt_pipes[i]; i++ )
+ if( strequal(fname,known_nt_pipes[i]))
+ break;
+
+ if ( known_nt_pipes[i] == NULL )
+ return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
+
+ /* Strip \\ off the name. */
+ fname++;
+
+ DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname));
+
+ p = open_rpc_pipe_p(fname, conn, vuid);
+ if (!p)
+ return(ERROR_DOS(ERRSRV,ERRnofids));
+
+ *ppnum = p->pnum;
+
+ return 0;
+}
+
+/****************************************************************************
+ Reply to an NT create and X call for pipes.
+****************************************************************************/
+
+static int do_ntcreate_pipe_open(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ pstring fname;
+ int ret;
+ int pnum = -1;
+ char *p = NULL;
+
+ srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+
+ if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+ return ret;
+
+ /*
+ * Deal with pipe return.
+ */
+
+ set_message(outbuf,34,0,True);
+
+ p = outbuf + smb_vwv2;
+ p++;
+ SSVAL(p,0,pnum);
+ p += 2;
+ SIVAL(p,0,FILE_WAS_OPENED);
+ p += 4;
+ p += 32;
+ SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
+ p += 20;
+ /* File type. */
+ SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
+ /* Device state. */
+ SSVAL(p,2, 0x5FF); /* ? */
+
+ DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ Reply to an NT create and X call.
+****************************************************************************/
+
+int reply_ntcreate_and_X(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ int result;
+ pstring fname;
+ uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
+ uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess);
+ uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes);
+ uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
+ uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
+ uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
+ uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid);
+ int smb_ofun;
+ int smb_open_mode;
+ int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ int oplock_request = 0;
+ mode_t unixmode;
+ int fmode=0,rmode=0;
+ SMB_OFF_T file_len = 0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp=NULL;
+ char *p = NULL;
+ BOOL stat_open_only = False;
+ time_t c_time;
+ START_PROFILE(SMBntcreateX);
+
+ /* If it's an IPC, use the pipe handler. */
+
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support()) {
+ END_PROFILE(SMBntcreateX);
+ return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize);
+ } else {
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadaccess));
+ }
+ }
+
+
+ /*
+ * We need to construct the open_and_X ofun value from the
+ * NT values, as that's what our code is structured to accept.
+ */
+
+ if((smb_ofun = map_create_disposition( create_disposition )) == -1) {
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadaccess));
+ }
+
+ /*
+ * Get the file name.
+ */
+
+ if(root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
+ files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
+ size_t dir_name_len;
+
+ if(!dir_fsp) {
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+ }
+
+ if(!dir_fsp->is_directory) {
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+
+ if( strchr_m(fname, ':')) {
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ END_PROFILE(SMBntcreateX);
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+ }
+
+ /*
+ * Copy in the base directory name.
+ */
+
+ pstrcpy( fname, dir_fsp->fsp_name );
+ dir_name_len = strlen(fname);
+
+ /*
+ * Ensure it ends in a '\'.
+ */
+
+ if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+ pstrcat(fname, "\\");
+ dir_name_len++;
+ }
+
+ srvstr_pull(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len,
+ -1, STR_TERMINATE);
+ } else {
+ srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+ }
+
+ /*
+ * Now contruct the smb_open_mode value from the filename,
+ * desired access and the share access.
+ */
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ if((smb_open_mode = map_share_mode(&stat_open_only, fname, create_options, desired_access,
+ share_access,
+ file_attributes)) == -1) {
+ END_PROFILE(SMBntcreateX);
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
+ /*
+ * Ordinary file or directory.
+ */
+
+ /*
+ * Check if POSIX semantics are wanted.
+ */
+
+ set_posix_case_semantics(file_attributes);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
+
+ /*
+ * If it's a request for a directory open, deal with it separately.
+ */
+
+ if(create_options & FILE_DIRECTORY_FILE) {
+ oplock_request = 0;
+
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
+
+ restore_case_semantics(file_attributes);
+
+ if(!fsp) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBntcreateX);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ /*
+ * Ordinary file case.
+ */
+
+ /* NB. We have a potential bug here. If we
+ * cause an oplock break to ourselves, then we
+ * could end up processing filename related
+ * SMB requests whilst we await the oplock
+ * break response. As we may have changed the
+ * filename case semantics to be POSIX-like,
+ * this could mean a filename request could
+ * fail when it should succeed. This is a rare
+ * condition, but eventually we must arrange
+ * to restore the correct case semantics
+ * before issuing an oplock break request to
+ * our client. JRA. */
+
+ fsp = open_file_shared(conn,fname,&sbuf,smb_open_mode,
+ smb_ofun,unixmode, oplock_request,&rmode,&smb_action);
+
+ if (!fsp) {
+ /* We cheat here. There are two cases we
+ * care about. One is a directory rename,
+ * where the NT client will attempt to
+ * open the source directory for
+ * DELETE access. Note that when the
+ * NT client does this it does *not*
+ * set the directory bit in the
+ * request packet. This is translated
+ * into a read/write open
+ * request. POSIX states that any open
+ * for write request on a directory
+ * will generate an EISDIR error, so
+ * we can catch this here and open a
+ * pseudo handle that is flagged as a
+ * directory. The second is an open
+ * for a permissions read only, which
+ * we handle in the open_file_stat case. JRA.
+ */
+
+ if(errno == EISDIR) {
+
+ /*
+ * Fail the open if it was explicitly a non-directory file.
+ */
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2,
+ SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+ }
+
+ oplock_request = 0;
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp) {
+ restore_case_semantics(file_attributes);
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBntcreateX);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+#ifdef EROFS
+ } else if (((errno == EACCES) || (errno == EROFS)) && stat_open_only) {
+#else /* !EROFS */
+ } else if (errno == EACCES && stat_open_only) {
+#endif
+ /*
+ * We couldn't open normally and all we want
+ * are the permissions. Try and do a stat open.
+ */
+
+ oplock_request = 0;
+
+ fsp = open_file_stat(conn,fname,&sbuf,smb_open_mode,&smb_action);
+
+ if(!fsp) {
+ restore_case_semantics(file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ } else {
+
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ restore_case_semantics(file_attributes);
+
+ END_PROFILE(SMBntcreateX);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+ }
+
+ restore_case_semantics(file_attributes);
+
+ file_len = sbuf.st_size;
+ fmode = dos_mode(conn,fname,&sbuf);
+ if(fmode == 0)
+ fmode = FILE_ATTRIBUTE_NORMAL;
+ if (!fsp->is_directory && (fmode & aDIR)) {
+ close_file(fsp,False);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ /*
+ * If the caller set the extended oplock request bit
+ * and we granted one (by whatever means) - set the
+ * correct bit for extended oplock reply.
+ */
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+#if 1 /* JRATEST */
+ /* W2K sends back 42 words here ! */
+ set_message(outbuf,42,0,True);
+#else
+ set_message(outbuf,34,0,True);
+#endif
+
+ p = outbuf + smb_vwv2;
+
+ /*
+ * Currently as we don't support level II oplocks we just report
+ * exclusive & batch here.
+ */
+
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
+ p++;
+ SSVAL(p,0,fsp->fnum);
+ p += 2;
+ SIVAL(p,0,smb_action);
+ p += 4;
+
+ /* Create time. */
+ c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ c_time &= ~1;
+ sbuf.st_atime &= ~1;
+ sbuf.st_mtime &= ~1;
+ sbuf.st_mtime &= ~1;
+ }
+
+ put_long_date(p,c_time);
+ p += 8;
+ put_long_date(p,sbuf.st_atime); /* access time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* write time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* change time */
+ p += 8;
+ SIVAL(p,0,fmode); /* File Attributes. */
+ p += 4;
+ SOFF_T(p, 0, file_len);
+ p += 8;
+ SOFF_T(p,0,file_len);
+ p += 12;
+ SCVAL(p,0,fsp->is_directory ? 1 : 0);
+
+ DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name));
+
+ result = chain_reply(inbuf,outbuf,length,bufsize);
+ END_PROFILE(SMBntcreateX);
+ return result;
+}
+
+/****************************************************************************
+ Reply to a NT_TRANSACT_CREATE call to open a pipe.
+****************************************************************************/
+
+static int do_nt_transact_create_pipe( connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **ppsetup, char **ppparams,
+ char **ppdata)
+{
+ pstring fname;
+ int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount);
+ char *params = *ppparams;
+ int ret;
+ int pnum = -1;
+ char *p = NULL;
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if(total_parameter_count < 54) {
+ DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+ srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE);
+
+ if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+ return ret;
+
+ /* Realloc the size of parameters and data we will return */
+ params = Realloc(*ppparams, 69);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+
+ *ppparams = params;
+
+ memset((char *)params,'\0',69);
+
+ p = params;
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
+ p += 2;
+ SSVAL(p,0,pnum);
+ p += 2;
+ SIVAL(p,0,FILE_WAS_OPENED);
+ p += 8;
+
+ p += 32;
+ SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
+ p += 20;
+ /* File type. */
+ SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
+ /* Device state. */
+ SSVAL(p,2, 0x5FF); /* ? */
+
+ DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
+
+ /* Send the required number of replies */
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+
+ return -1;
+}
+
+/****************************************************************************
+ Internal fn to set security descriptors.
+****************************************************************************/
+
+static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent, int *pdef_class,uint32 *pdef_code)
+{
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+ TALLOC_CTX *mem_ctx;
+ BOOL ret;
+
+ if (sd_len == 0) {
+ *pdef_class = ERRDOS;
+ *pdef_code = ERRbadaccess;
+ return False;
+ }
+
+ /*
+ * Init the parse struct we will unmarshall from.
+ */
+
+ if ((mem_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("set_sd: talloc_init failed.\n"));
+ *pdef_class = ERRDOS;
+ *pdef_code = ERRnomem;
+ return False;
+ }
+
+ prs_init(&pd, 0, mem_ctx, UNMARSHALL);
+
+ /*
+ * Setup the prs_struct to point at the memory we just
+ * allocated.
+ */
+
+ prs_give_memory( &pd, data, sd_len, False);
+
+ /*
+ * Finally, unmarshall from the data buffer.
+ */
+
+ if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+ DEBUG(0,("set_sd: Error in unmarshalling security descriptor.\n"));
+ /*
+ * Return access denied for want of a better error message..
+ */
+ talloc_destroy(mem_ctx);
+ *pdef_class = ERRDOS;
+ *pdef_code = ERRnomem;
+ return False;
+ }
+
+ if (psd->off_owner_sid==0)
+ security_info_sent &= ~OWNER_SECURITY_INFORMATION;
+ if (psd->off_grp_sid==0)
+ security_info_sent &= ~GROUP_SECURITY_INFORMATION;
+ if (psd->off_sacl==0)
+ security_info_sent &= ~SACL_SECURITY_INFORMATION;
+ if (psd->off_dacl==0)
+ security_info_sent &= ~DACL_SECURITY_INFORMATION;
+
+ ret = fsp->conn->vfs_ops.fset_nt_acl( fsp, fsp->fd, security_info_sent, psd);
+
+ if (!ret) {
+ talloc_destroy(mem_ctx);
+ *pdef_class = ERRDOS;
+ *pdef_code = ERRnoaccess;
+ return False;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ *pdef_class = 0;
+ *pdef_code = 0;
+ return True;
+}
+
+/****************************************************************************
+ Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
+****************************************************************************/
+
+static int call_nt_transact_create(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **ppsetup, char **ppparams,
+ char **ppdata)
+{
+ pstring fname;
+ char *params = *ppparams;
+ char *data = *ppdata;
+ int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount);
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ int oplock_request = 0;
+ mode_t unixmode;
+ int fmode=0,rmode=0;
+ SMB_OFF_T file_len = 0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp = NULL;
+ char *p = NULL;
+ BOOL stat_open_only = False;
+ uint32 flags;
+ uint32 desired_access;
+ uint32 file_attributes;
+ uint32 share_access;
+ uint32 create_disposition;
+ uint32 create_options;
+ uint32 sd_len;
+ uint16 root_dir_fid;
+ int smb_ofun;
+ int smb_open_mode;
+ int smb_attr;
+ int error_class;
+ uint32 error_code;
+ time_t c_time;
+
+ DEBUG(5,("call_nt_transact_create\n"));
+
+ /*
+ * If it's an IPC, use the pipe handler.
+ */
+
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support())
+ return do_nt_transact_create_pipe(conn, inbuf, outbuf, length,
+ bufsize, ppsetup, ppparams, ppdata);
+ else
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if(total_parameter_count < 54) {
+ DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+ flags = IVAL(params,0);
+ desired_access = IVAL(params,8);
+ file_attributes = IVAL(params,20);
+ share_access = IVAL(params,24);
+ create_disposition = IVAL(params,28);
+ create_options = IVAL(params,32);
+ sd_len = IVAL(params,36);
+ root_dir_fid = (uint16)IVAL(params,4);
+ smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
+
+ /*
+ * We need to construct the open_and_X ofun value from the
+ * NT values, as that's what our code is structured to accept.
+ */
+
+ if((smb_ofun = map_create_disposition( create_disposition )) == -1)
+ return ERROR_DOS(ERRDOS,ERRbadmem);
+
+ /*
+ * Get the file name.
+ */
+
+ if(root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
+
+ files_struct *dir_fsp = file_fsp(params,4);
+ size_t dir_name_len;
+
+ if(!dir_fsp)
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ if(!dir_fsp->is_directory) {
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE);
+
+ if( strchr_m(fname, ':')) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
+
+ /*
+ * Copy in the base directory name.
+ */
+
+ pstrcpy( fname, dir_fsp->fsp_name );
+ dir_name_len = strlen(fname);
+
+ /*
+ * Ensure it ends in a '\'.
+ */
+
+ if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
+ pstrcat(fname, "\\");
+ dir_name_len++;
+ }
+
+ srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len,
+ -1, STR_TERMINATE);
+ } else {
+ srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE);
+ }
+
+ /*
+ * Now contruct the smb_open_mode value from the desired access
+ * and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode( &stat_open_only, fname, create_options, desired_access,
+ share_access, file_attributes)) == -1)
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
+ /*
+ * Check if POSIX semantics are wanted.
+ */
+
+ set_posix_case_semantics(file_attributes);
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
+
+ /*
+ * If it's a request for a directory open, deal with it separately.
+ */
+
+ if(create_options & FILE_DIRECTORY_FILE) {
+
+ oplock_request = 0;
+
+ /*
+ * We will get a create directory here if the Win32
+ * app specified a security descriptor in the
+ * CreateDirectory() call.
+ */
+
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp) {
+ restore_case_semantics(file_attributes);
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ } else {
+
+ /*
+ * Ordinary file case.
+ */
+
+ fsp = open_file_shared(conn,fname,&sbuf,smb_open_mode,smb_ofun,unixmode,
+ oplock_request,&rmode,&smb_action);
+
+ if (!fsp) {
+
+ if(errno == EISDIR) {
+
+ /*
+ * Fail the open if it was explicitly a non-directory file.
+ */
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2,
+ SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+ return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+ }
+
+ oplock_request = 0;
+ fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp) {
+ restore_case_semantics(file_attributes);
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+#ifdef EROFS
+ } else if (((errno == EACCES) || (errno == EROFS)) && stat_open_only) {
+#else /* !EROFS */
+ } else if (errno == EACCES && stat_open_only) {
+#endif
+
+ /*
+ * We couldn't open normally and all we want
+ * are the permissions. Try and do a stat open.
+ */
+
+ oplock_request = 0;
+
+ fsp = open_file_stat(conn,fname,&sbuf,smb_open_mode,&smb_action);
+
+ if(!fsp) {
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ file_len = sbuf.st_size;
+ fmode = dos_mode(conn,fname,&sbuf);
+ if(fmode == 0)
+ fmode = FILE_ATTRIBUTE_NORMAL;
+
+ if (fmode & aDIR) {
+ close_file(fsp,False);
+ restore_case_semantics(file_attributes);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ /*
+ * If the caller set the extended oplock request bit
+ * and we granted one (by whatever means) - set the
+ * correct bit for extended oplock reply.
+ */
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ /*
+ * Now try and apply the desired SD.
+ */
+
+ if (!set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) {
+ close_file(fsp,False);
+ restore_case_semantics(file_attributes);
+ return ERROR_DOS(error_class, error_code);
+ }
+
+ restore_case_semantics(file_attributes);
+
+ /* Realloc the size of parameters and data we will return */
+ params = Realloc(*ppparams, 69);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+
+ *ppparams = params;
+
+ memset((char *)params,'\0',69);
+
+ p = params;
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
+ p += 2;
+ SSVAL(p,0,fsp->fnum);
+ p += 2;
+ SIVAL(p,0,smb_action);
+ p += 8;
+
+ /* Create time. */
+ c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ c_time &= ~1;
+ sbuf.st_atime &= ~1;
+ sbuf.st_mtime &= ~1;
+ sbuf.st_mtime &= ~1;
+ }
+
+ put_long_date(p,c_time);
+ p += 8;
+ put_long_date(p,sbuf.st_atime); /* access time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* write time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* change time */
+ p += 8;
+ SIVAL(p,0,fmode); /* File Attributes. */
+ p += 4;
+ SOFF_T(p,0,file_len);
+ p += 8;
+ SOFF_T(p,0,file_len);
+
+ DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
+
+ /* Send the required number of replies */
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+
+ return -1;
+}
+
+/****************************************************************************
+ Reply to a NT CANCEL request.
+****************************************************************************/
+int reply_ntcancel(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ /*
+ * Go through and cancel any pending change notifies.
+ */
+
+ int mid = SVAL(inbuf,smb_mid);
+ START_PROFILE(SMBntcancel);
+ remove_pending_change_notify_requests_by_mid(mid);
+ remove_pending_lock_requests_by_mid(mid);
+
+ DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", mid));
+
+ END_PROFILE(SMBntcancel);
+ return(-1);
+}
+
+/****************************************************************************
+ Reply to an unsolicited SMBNTtranss - just ignore it!
+****************************************************************************/
+int reply_nttranss(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ START_PROFILE(SMBnttranss);
+ DEBUG(4,("Ignoring nttranss of length %d\n",length));
+ END_PROFILE(SMBnttranss);
+ return(-1);
+}
+
+/****************************************************************************
+ Reply to a notify change - queue the request and
+ don't allow a directory to be opened.
+****************************************************************************/
+static int call_nt_transact_notify_change(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize,
+ char **ppsetup,
+ char **ppparams, char **ppdata)
+{
+ char *setup = *ppsetup;
+ files_struct *fsp;
+ uint32 flags;
+
+ fsp = file_fsp(setup,4);
+ flags = IVAL(setup, 0);
+
+ DEBUG(3,("call_nt_transact_notify_change\n"));
+
+ if(!fsp)
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ if((!fsp->is_directory) || (conn != fsp->conn))
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ if (!change_notify_set(inbuf, fsp, conn, flags)) {
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
+
+ DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
+name = %s\n", fsp->fsp_name ));
+
+ return -1;
+}
+
+/****************************************************************************
+ Reply to an NT transact rename command.
+****************************************************************************/
+
+static int call_nt_transact_rename(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize,
+ char **ppsetup, char **ppparams, char **ppdata)
+{
+ char *params = *ppparams;
+ pstring new_name;
+ files_struct *fsp = file_fsp(params, 0);
+ BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
+ NTSTATUS status;
+
+ CHECK_FSP(fsp, conn);
+ srvstr_pull(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE);
+
+ status = rename_internals(conn, fsp->fsp_name,
+ new_name, replace_if_exists);
+ if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+
+ /*
+ * Rename was successful.
+ */
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+
+ DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
+ fsp->fsp_name, new_name));
+
+ /*
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+
+ process_pending_change_notify_queue((time_t)0);
+
+ return -1;
+}
+
+/******************************************************************************
+ Fake up a completely empty SD.
+*******************************************************************************/
+
+static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
+{
+ extern DOM_SID global_sid_World;
+ size_t sd_size;
+
+ *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
+ if(!*ppsd) {
+ DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n"));
+ sd_size = 0;
+ }
+
+ return sd_size;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor - currently this is not implemented (it
+ is planned to be though). Right now it just returns the same thing NT would
+ when queried on a FAT filesystem. JRA.
+****************************************************************************/
+
+static int call_nt_transact_query_security_desc(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ char **ppsetup, char **ppparams, char **ppdata)
+{
+ uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+ char *params = *ppparams;
+ char *data = *ppdata;
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+ size_t sd_size;
+ TALLOC_CTX *mem_ctx;
+
+ files_struct *fsp = file_fsp(params,0);
+
+ if(!fsp)
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name ));
+
+ params = Realloc(*ppparams, 4);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+
+ *ppparams = params;
+
+ if ((mem_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n"));
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ /*
+ * Get the permissions to return.
+ */
+
+ if (!lp_nt_acl_support(SNUM(conn)))
+ sd_size = get_null_nt_acl(mem_ctx, &psd);
+ else
+ sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
+
+ if (sd_size == 0) {
+ talloc_destroy(mem_ctx);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size));
+
+ SIVAL(params,0,(uint32)sd_size);
+
+ if(max_data_count < sd_size) {
+
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
+ params, 4, *ppdata, 0);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ /*
+ * Allocate the data we will point this at.
+ */
+
+ data = Realloc(*ppdata, sd_size);
+ if(data == NULL) {
+ talloc_destroy(mem_ctx);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ *ppdata = data;
+
+ memset(data, '\0', sd_size);
+
+ /*
+ * Init the parse struct we will marshall into.
+ */
+
+ prs_init(&pd, 0, mem_ctx, MARSHALL);
+
+ /*
+ * Setup the prs_struct to point at the memory we just
+ * allocated.
+ */
+
+ prs_give_memory( &pd, data, (uint32)sd_size, False);
+
+ /*
+ * Finally, linearize into the outgoing buffer.
+ */
+
+ if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+ DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \
+security descriptor.\n"));
+ /*
+ * Return access denied for want of a better error message..
+ */
+ talloc_destroy(mem_ctx);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /*
+ * Now we can delete the security descriptor.
+ */
+
+ talloc_destroy(mem_ctx);
+
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size);
+ return -1;
+}
+
+/****************************************************************************
+ Reply to set a security descriptor. Map to UNIX perms.
+****************************************************************************/
+
+static int call_nt_transact_set_security_desc(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **ppsetup,
+ char **ppparams, char **ppdata)
+{
+ uint32 total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+ char *params= *ppparams;
+ char *data = *ppdata;
+ uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount);
+ files_struct *fsp = NULL;
+ uint32 security_info_sent = 0;
+ int error_class;
+ uint32 error_code;
+
+ if(total_parameter_count < 8)
+ return ERROR_DOS(ERRDOS,ERRbadfunc);
+
+ if((fsp = file_fsp(params,0)) == NULL)
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ if(!lp_nt_acl_support(SNUM(conn)))
+ goto done;
+
+ security_info_sent = IVAL(params,4);
+
+ DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
+ (unsigned int)security_info_sent ));
+
+ if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code))
+ return ERROR_DOS(error_class, error_code);
+
+ done:
+
+ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ return -1;
+}
+
+/****************************************************************************
+ Reply to IOCTL - not implemented - no plans.
+****************************************************************************/
+static int call_nt_transact_ioctl(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize,
+ char **ppsetup, char **ppparams, char **ppdata)
+{
+ static BOOL logged_message = False;
+
+ if(!logged_message) {
+ DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
+ logged_message = True; /* Only print this once... */
+ }
+ return ERROR_DOS(ERRSRV,ERRnosupport);
+}
+
+/****************************************************************************
+ Reply to a SMBNTtrans.
+****************************************************************************/
+int reply_nttrans(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ int outsize = 0;
+#if 0 /* Not used. */
+ uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
+ uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
+ uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+#endif /* Not used. */
+ uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
+ uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
+ uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
+ uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
+ uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
+ uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
+ uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
+ uint16 function_code = SVAL( inbuf, smb_nt_Function);
+ char *params = NULL, *data = NULL, *setup = NULL;
+ uint32 num_params_sofar, num_data_sofar;
+ START_PROFILE(SMBnttrans);
+
+ if(global_oplock_break && (function_code == NT_TRANSACT_CREATE)) {
+ /*
+ * Queue this open message as we are the process of an oplock break.
+ */
+
+ DEBUG(2,("reply_nttrans: queueing message NT_TRANSACT_CREATE \
+due to being in oplock break state.\n" ));
+
+ push_oplock_pending_smb_message( inbuf, length);
+ END_PROFILE(SMBnttrans);
+ return -1;
+ }
+
+ if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+
+ outsize = set_message(outbuf,0,0,True);
+
+ /*
+ * All nttrans messages we handle have smb_wct == 19 + setup_count.
+ * Ensure this is so as a sanity check.
+ */
+
+ if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
+ DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
+ CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+
+ /* Allocate the space for the setup, the maximum needed parameters and data */
+
+ if(setup_count > 0)
+ setup = (char *)malloc(setup_count);
+ if (total_parameter_count > 0)
+ params = (char *)malloc(total_parameter_count);
+ if (total_data_count > 0)
+ data = (char *)malloc(total_data_count);
+
+ if ((total_parameter_count && !params) || (total_data_count && !data) ||
+ (setup_count && !setup)) {
+ SAFE_FREE(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ /* Copy the param and data bytes sent with this request into
+ the params buffer */
+ num_params_sofar = parameter_count;
+ num_data_sofar = data_count;
+
+ if (parameter_count > total_parameter_count || data_count > total_data_count)
+ exit_server("reply_nttrans: invalid sizes in packet.");
+
+ if(setup) {
+ memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
+ DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
+ dump_data(10, setup, setup_count);
+ }
+ if(params) {
+ memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
+ DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
+ dump_data(10, params, parameter_count);
+ }
+ if(data) {
+ memcpy( data, smb_base(inbuf) + data_offset, data_count);
+ DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
+ dump_data(10, data, data_count);
+ }
+
+ if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_nttrans: send_smb failed.");
+
+ while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
+ BOOL ret;
+
+ ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+
+ if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
+ outsize = set_message(outbuf,0,0,True);
+ if(ret) {
+ DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
+ } else {
+ DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
+ (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
+ }
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ SAFE_FREE(setup);
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+
+ /* Revise total_params and total_data in case they have changed downwards */
+ total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+ total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
+ num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount));
+ num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount));
+ if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
+ exit_server("reply_nttrans2: data overflow in secondary nttrans packet");
+
+ memcpy( &params[ IVAL(inbuf, smb_nts_ParameterDisplacement)],
+ smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
+ memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)],
+ smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count);
+ }
+ }
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(function_code) {
+ case NT_TRANSACT_CREATE:
+ START_PROFILE_NESTED(NT_transact_create);
+ outsize = call_nt_transact_create(conn, inbuf, outbuf, length, bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_create);
+ break;
+ case NT_TRANSACT_IOCTL:
+ START_PROFILE_NESTED(NT_transact_ioctl);
+ outsize = call_nt_transact_ioctl(conn,
+ inbuf, outbuf, length, bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_ioctl);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_set_security_desc);
+ outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_set_security_desc);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ START_PROFILE_NESTED(NT_transact_notify_change);
+ outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_notify_change);
+ break;
+ case NT_TRANSACT_RENAME:
+ START_PROFILE_NESTED(NT_transact_rename);
+ outsize = call_nt_transact_rename(conn, inbuf, outbuf, length,
+ bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_rename);
+ break;
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ START_PROFILE_NESTED(NT_transact_query_security_desc);
+ outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ END_PROFILE_NESTED(NT_transact_query_security_desc);
+ break;
+ default:
+ /* Error in request */
+ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
+ SAFE_FREE(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+
+ /* As we do not know how many data packets will need to be
+ returned here the various call_nt_transact_xxxx calls
+ must send their own. Thus a call_nt_transact_xxxx routine only
+ returns a value other than -1 when it wants to send
+ an error packet.
+ */
+
+ SAFE_FREE(setup);
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBnttrans);
+ return outsize; /* If a correct response was needed the call_nt_transact_xxxx
+ calls have already sent it. If outsize != -1 then it is
+ returning an error packet. */
+}
diff --git a/source/smbd/open.c b/source/smbd/open.c
new file mode 100644
index 00000000000..72f73deb84b
--- /dev/null
+++ b/source/smbd/open.c
@@ -0,0 +1,1312 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file opening and share modes
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern userdom_struct current_user_info;
+extern uint16 global_oplock_port;
+extern BOOL global_client_failed_oplock_break;
+
+/****************************************************************************
+ fd support routines - attempt to do a dos_open.
+****************************************************************************/
+
+static int fd_open(struct connection_struct *conn, char *fname,
+ int flags, mode_t mode)
+{
+ int fd;
+#ifdef O_NONBLOCK
+ flags |= O_NONBLOCK;
+#endif
+ fd = conn->vfs_ops.open(conn,fname,flags,mode);
+
+ /* Fix for files ending in '.' */
+ if((fd == -1) && (errno == ENOENT) &&
+ (strchr_m(fname,'.')==NULL)) {
+ pstrcat(fname,".");
+ fd = conn->vfs_ops.open(conn,fname,flags,mode);
+ }
+
+ DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname,
+ flags, (int)mode, fd, (fd == -1) ? strerror(errno) : "" ));
+
+ return fd;
+}
+
+/****************************************************************************
+ Close the file associated with a fsp.
+****************************************************************************/
+
+int fd_close(struct connection_struct *conn, files_struct *fsp)
+{
+ if (fsp->fd == -1)
+ return -1;
+ return fd_close_posix(conn, fsp);
+}
+
+
+/****************************************************************************
+ Check a filename for the pipe string.
+****************************************************************************/
+
+static void check_for_pipe(char *fname)
+{
+ /* special case of pipe opens */
+ char s[10];
+ StrnCpy(s,fname,sizeof(s)-1);
+ strlower(s);
+ if (strstr(s,"pipe/")) {
+ DEBUG(3,("Rejecting named pipe open for %s\n",fname));
+ unix_ERR_class = ERRSRV;
+ unix_ERR_code = ERRaccess;
+ }
+}
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+static BOOL open_file(files_struct *fsp,connection_struct *conn,
+ char *fname1,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode)
+{
+ extern struct current_user current_user;
+ pstring fname;
+ int accmode = (flags & O_ACCMODE);
+ int local_flags = flags;
+
+ fsp->fd = -1;
+ fsp->oplock_type = NO_OPLOCK;
+ errno = EPERM;
+
+ pstrcpy(fname,fname1);
+
+ /* Check permissions */
+
+ /*
+ * This code was changed after seeing a client open request
+ * containing the open mode of (DENY_WRITE/read-only) with
+ * the 'create if not exist' bit set. The previous code
+ * would fail to open the file read only on a read-only share
+ * as it was checking the flags parameter directly against O_RDONLY,
+ * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+ * JRA.
+ */
+
+ if (!CAN_WRITE(conn)) {
+ /* It's a read-only share - fail if we wanted to write. */
+ if(accmode != O_RDONLY) {
+ DEBUG(3,("Permission denied opening %s\n",fname));
+ check_for_pipe(fname);
+ return False;
+ } else if(flags & O_CREAT) {
+ /* We don't want to write - but we must make sure that O_CREAT
+ doesn't create the file if we have write access into the
+ directory.
+ */
+ flags &= ~O_CREAT;
+ }
+ }
+
+ /*
+ * This little piece of insanity is inspired by the
+ * fact that an NT client can open a file for O_RDONLY,
+ * but set the create disposition to FILE_EXISTS_TRUNCATE.
+ * If the client *can* write to the file, then it expects to
+ * truncate the file, even though it is opening for readonly.
+ * Quicken uses this stupid trick in backup file creation...
+ * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net>
+ * for helping track this one down. It didn't bite us in 2.0.x
+ * as we always opened files read-write in that release. JRA.
+ */
+
+ if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC))
+ local_flags = (flags & ~O_ACCMODE)|O_RDWR;
+
+ /*
+ * We can't actually truncate here as the file may be locked.
+ * open_file_shared will take care of the truncate later. JRA.
+ */
+
+ local_flags &= ~O_TRUNC;
+
+ /* actually do the open */
+ fsp->fd = fd_open(conn, fname, local_flags, mode);
+
+ if (fsp->fd == -1) {
+ DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n",
+ fname,strerror(errno),local_flags,flags));
+ check_for_pipe(fname);
+ return False;
+ }
+
+ if (!VALID_STAT(*psbuf)) {
+ if (vfs_fstat(fsp,fsp->fd,psbuf) == -1) {
+ DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) ));
+ fd_close(conn, fsp);
+ return False;
+ }
+ }
+
+ /*
+ * POSIX allows read-only opens of directories. We don't
+ * want to do this (we use a different code path for this)
+ * so catch a directory open and return an EISDIR. JRA.
+ */
+
+ if(S_ISDIR(psbuf->st_mode)) {
+ fd_close(conn, fsp);
+ errno = EISDIR;
+ return False;
+ }
+
+ fsp->mode = psbuf->st_mode;
+ fsp->inode = psbuf->st_ino;
+ fsp->dev = psbuf->st_dev;
+ fsp->vuid = current_user.vuid;
+ fsp->size = psbuf->st_size;
+ fsp->pos = -1;
+ fsp->can_lock = True;
+ fsp->can_read = ((flags & O_WRONLY)==0);
+ fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
+ fsp->share_mode = 0;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ fsp->stat_open = False;
+ fsp->directory_delete_on_close = False;
+ fsp->conn = conn;
+ string_set(&fsp->fsp_name,fname);
+ fsp->wcp = NULL; /* Write cache pointer. */
+
+ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
+ *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name,
+ BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
+ conn->num_files_open + 1));
+
+ return True;
+}
+
+/****************************************************************************
+ C. Hoch 11/22/95
+ Helper for open_file_shared.
+ Truncate a file after checking locking; close file if locked.
+ **************************************************************************/
+
+static int truncate_unless_locked(struct connection_struct *conn, files_struct *fsp)
+{
+ SMB_BIG_UINT mask = (SMB_BIG_UINT)-1;
+
+ if (is_locked(fsp,fsp->conn,mask,0,WRITE_LOCK,True)){
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRlock;
+ return -1;
+ } else {
+ return conn->vfs_ops.ftruncate(fsp,fsp->fd,0);
+ }
+}
+
+/*******************************************************************
+return True if the filename is one of the special executable types
+********************************************************************/
+static BOOL is_executable(const char *fname)
+{
+ if ((fname = strrchr_m(fname,'.'))) {
+ if (strequal(fname,".com") ||
+ strequal(fname,".dll") ||
+ strequal(fname,".exe") ||
+ strequal(fname,".sym")) {
+ return True;
+ }
+ }
+ return False;
+}
+
+enum {AFAIL,AREAD,AWRITE,AALL};
+
+/*******************************************************************
+reproduce the share mode access table
+this is horrendoously complex, and really can't be justified on any
+rational grounds except that this is _exactly_ what NT does. See
+the DENY1 and DENY2 tests in smbtorture for a comprehensive set of
+test routines.
+********************************************************************/
+static int access_table(int new_deny,int old_deny,int old_mode,
+ BOOL same_pid, BOOL isexe)
+{
+ if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
+
+ if (same_pid) {
+ if (isexe && old_mode == DOS_OPEN_RDONLY &&
+ old_deny == DENY_DOS && new_deny == DENY_READ) {
+ return AFAIL;
+ }
+ if (!isexe && old_mode == DOS_OPEN_RDONLY &&
+ old_deny == DENY_DOS && new_deny == DENY_DOS) {
+ return AREAD;
+ }
+ if (new_deny == DENY_FCB && old_deny == DENY_DOS) {
+ if (isexe) return AFAIL;
+ if (old_mode == DOS_OPEN_RDONLY) return AFAIL;
+ return AALL;
+ }
+ if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) {
+ if (new_deny == DENY_FCB || new_deny == DENY_READ) {
+ if (isexe) return AREAD;
+ return AFAIL;
+ }
+ }
+ if (old_deny == DENY_FCB) {
+ if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL;
+ return AFAIL;
+ }
+ }
+
+ if (old_deny == DENY_DOS || new_deny == DENY_DOS ||
+ old_deny == DENY_FCB || new_deny == DENY_FCB) {
+ if (isexe) {
+ if (old_deny == DENY_FCB || new_deny == DENY_FCB) {
+ return AFAIL;
+ }
+ if (old_deny == DENY_DOS) {
+ if (new_deny == DENY_READ &&
+ (old_mode == DOS_OPEN_RDONLY ||
+ old_mode == DOS_OPEN_RDWR)) {
+ return AFAIL;
+ }
+ if (new_deny == DENY_WRITE &&
+ (old_mode == DOS_OPEN_WRONLY ||
+ old_mode == DOS_OPEN_RDWR)) {
+ return AFAIL;
+ }
+ return AALL;
+ }
+ if (old_deny == DENY_NONE) return AALL;
+ if (old_deny == DENY_READ) return AWRITE;
+ if (old_deny == DENY_WRITE) return AREAD;
+ }
+ /* it isn't a exe, dll, sym or com file */
+ if (old_deny == new_deny && same_pid)
+ return(AALL);
+
+ if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL;
+ if (old_mode == DOS_OPEN_RDONLY) return(AREAD);
+
+ return(AFAIL);
+ }
+
+ switch (new_deny)
+ {
+ case DENY_WRITE:
+ if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD);
+ if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE);
+ if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL);
+ return(AFAIL);
+ case DENY_READ:
+ if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD);
+ if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE);
+ if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL);
+ return(AFAIL);
+ case DENY_NONE:
+ if (old_deny==DENY_WRITE) return(AREAD);
+ if (old_deny==DENY_READ) return(AWRITE);
+ if (old_deny==DENY_NONE) return(AALL);
+ return(AFAIL);
+ }
+ return(AFAIL);
+}
+
+
+/****************************************************************************
+check if we can open a file with a share mode
+****************************************************************************/
+
+static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode,
+ const char *fname, BOOL fcbopen, int *flags)
+{
+ int deny_mode = GET_DENY_MODE(share_mode);
+ int old_open_mode = GET_OPEN_MODE(share->share_mode);
+ int old_deny_mode = GET_DENY_MODE(share->share_mode);
+
+ /*
+ * share modes = false means don't bother to check for
+ * DENY mode conflict. This is a *really* bad idea :-). JRA.
+ */
+
+ if(!lp_share_modes(SNUM(conn)))
+ return True;
+
+ /*
+ * Don't allow any opens once the delete on close flag has been
+ * set.
+ */
+
+ if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRnoaccess;
+ return False;
+ }
+
+ /*
+ * If delete access was requested and the existing share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share_mode) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
+ /*
+ * The inverse of the above.
+ * If delete access was granted and the new share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share->share_mode) && !GET_ALLOW_SHARE_DELETE(share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
+ {
+ int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
+ (share->pid == sys_getpid()),is_executable(fname));
+
+ if ((access_allowed == AFAIL) ||
+ (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
+ (access_allowed == AREAD && *flags != O_RDONLY) ||
+ (access_allowed == AWRITE && *flags != O_WRONLY)) {
+
+ DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
+ deny_mode,old_deny_mode,old_open_mode,
+ (int)share->pid,fname, fcbopen, *flags, access_allowed));
+
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
+ if (access_allowed == AREAD)
+ *flags = O_RDONLY;
+
+ if (access_allowed == AWRITE)
+ *flags = O_WRONLY;
+
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Deal with open deny mode and oplock break processing.
+ Invarient: Share mode must be locked on entry and exit.
+ Returns -1 on error, or number of share modes on success (may be zero).
+****************************************************************************/
+
+static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T dev,
+ SMB_INO_T inode, int share_mode, int *p_flags, int *p_oplock_request,
+ BOOL *p_all_current_opens_are_level_II)
+{
+ int i;
+ int num_share_modes;
+ int oplock_contention_count = 0;
+ share_mode_entry *old_shares = 0;
+ BOOL fcbopen = False;
+ BOOL broke_oplock;
+
+ if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB)
+ fcbopen = True;
+
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+
+ if(num_share_modes == 0)
+ return 0;
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ do {
+ share_mode_entry broken_entry;
+
+ broke_oplock = False;
+ *p_all_current_opens_are_level_II = True;
+
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &old_shares[i];
+
+ /*
+ * By observation of NetBench, oplocks are broken *before* share
+ * modes are checked. This allows a file to be closed by the client
+ * if the share mode would deny access and the client has an oplock.
+ * Check if someone has an oplock on this file. If so we must break
+ * it before continuing.
+ */
+
+ if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
+ (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) {
+
+ BOOL opb_ret;
+
+ DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \
+dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode));
+
+ /* Oplock break - unlock to request it. */
+ unlock_share_entry(conn, dev, inode);
+
+ opb_ret = request_oplock_break(share_entry);
+
+ /* Now relock. */
+ lock_share_entry(conn, dev, inode);
+
+ if(opb_ret == False) {
+ DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
+ SAFE_FREE(old_shares);
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return -1;
+ }
+
+ broke_oplock = True;
+ broken_entry = *share_entry;
+ break;
+
+ } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ *p_all_current_opens_are_level_II = False;
+ }
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+
+ if(check_share_mode(conn, share_entry, share_mode, fname, fcbopen, p_flags) == False) {
+ SAFE_FREE(old_shares);
+ errno = EACCES;
+ return -1;
+ }
+
+ } /* end for */
+
+ if(broke_oplock) {
+ SAFE_FREE(old_shares);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ oplock_contention_count++;
+
+ /* Paranoia check that this is no longer an exlusive entry. */
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &old_shares[i];
+
+ if (share_modes_identical(&broken_entry, share_entry) &&
+ EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) {
+
+ /*
+ * This should not happen. The target left this oplock
+ * as exlusive.... The process *must* be dead....
+ */
+
+ DEBUG(0,("open_mode_check: exlusive oplock left by process %d after break ! For file %s, \
+dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode));
+
+ if (process_exists(broken_entry.pid)) {
+ DEBUG(0,("open_mode_check: Existent process %d left active oplock.\n",
+ broken_entry.pid ));
+ }
+
+ if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return -1;
+ }
+
+ /*
+ * We must reload the share modes after deleting the
+ * other process's entry.
+ */
+
+ SAFE_FREE(old_shares);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ break;
+ }
+ } /* end for paranoia... */
+ } /* end if broke_oplock */
+
+ } while(broke_oplock);
+
+ if(old_shares != 0)
+ SAFE_FREE(old_shares);
+
+ /*
+ * Refuse to grant an oplock in case the contention limit is
+ * reached when going through the lock list multiple times.
+ */
+
+ if(oplock_contention_count >= lp_oplock_contention_limit(SNUM(conn))) {
+ *p_oplock_request = 0;
+ DEBUG(4,("open_mode_check: oplock contention = %d. Not granting oplock.\n",
+ oplock_contention_count ));
+ }
+
+ return num_share_modes;
+}
+
+/****************************************************************************
+set a kernel flock on a file for NFS interoperability
+this requires a patch to Linux
+****************************************************************************/
+static void kernel_flock(files_struct *fsp, int deny_mode)
+{
+#if HAVE_KERNEL_SHARE_MODES
+ int kernel_mode = 0;
+ if (deny_mode == DENY_READ) kernel_mode = LOCK_MAND|LOCK_WRITE;
+ else if (deny_mode == DENY_WRITE) kernel_mode = LOCK_MAND|LOCK_READ;
+ else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND;
+ if (kernel_mode) flock(fsp->fd, kernel_mode);
+#endif
+ ;;
+}
+
+
+/****************************************************************************
+ Open a file with a share mode. On output from this open we are guarenteeing
+ that
+****************************************************************************/
+files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf,
+ int share_mode,int ofun, mode_t mode,int oplock_request,
+ int *Access,int *action)
+{
+ int flags=0;
+ int flags2=0;
+ int deny_mode = GET_DENY_MODE(share_mode);
+ BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
+ BOOL delete_access_requested = GET_DELETE_ACCESS_REQUESTED(share_mode);
+ BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
+ BOOL file_existed = VALID_STAT(*psbuf);
+ BOOL fcbopen = False;
+ SMB_DEV_T dev = 0;
+ SMB_INO_T inode = 0;
+ int num_share_modes = 0;
+ BOOL all_current_opens_are_level_II = False;
+ BOOL fsp_open = False;
+ files_struct *fsp = NULL;
+ int open_mode=0;
+ uint16 port = 0;
+
+ if (conn->printer) {
+ /* printers are handled completely differently. Most of the passed parameters are
+ ignored */
+ *Access = DOS_OPEN_WRONLY;
+ *action = FILE_WAS_CREATED;
+ return print_fsp_open(conn);
+ }
+
+ fsp = file_new(conn);
+ if(!fsp)
+ return NULL;
+
+ DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
+ fname, share_mode, ofun, (int)mode, oplock_request ));
+
+ if (!check_name(fname,conn)) {
+ file_free(fsp);
+ return NULL;
+ }
+
+ /* ignore any oplock requests if oplocks are disabled */
+ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) {
+ oplock_request = 0;
+ }
+
+ /* this is for OS/2 EAs - try and say we don't support them */
+ if (strstr(fname,".+,;=[].")) {
+ unix_ERR_class = ERRDOS;
+ /* OS/2 Workplace shell fix may be main code stream in a later release. */
+#if 1 /* OS2_WPS_FIX - Recent versions of OS/2 need this. */
+ unix_ERR_code = ERRcannotopen;
+#else /* OS2_WPS_FIX */
+ unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
+#endif /* OS2_WPS_FIX */
+
+ DEBUG(5,("open_file_shared: OS/2 EA's are not supported.\n"));
+ file_free(fsp);
+ return NULL;
+ }
+
+ if ((GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) && file_existed) {
+ DEBUG(5,("open_file_shared: create new requested for file %s and file already exists.\n",
+ fname ));
+ file_free(fsp);
+ errno = EEXIST;
+ return NULL;
+ }
+
+ if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST))
+ flags2 |= O_CREAT;
+
+ if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE))
+ flags2 |= O_TRUNC;
+
+ if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL)
+ flags2 |= O_EXCL;
+
+ /* note that we ignore the append flag as
+ append does not mean the same thing under dos and unix */
+
+ switch (GET_OPEN_MODE(share_mode)) {
+ case DOS_OPEN_WRONLY:
+ flags = O_WRONLY;
+ break;
+ case DOS_OPEN_FCB:
+ fcbopen = True;
+ flags = O_RDWR;
+ break;
+ case DOS_OPEN_RDWR:
+ flags = O_RDWR;
+ break;
+ default:
+ flags = O_RDONLY;
+ break;
+ }
+
+#if defined(O_SYNC)
+ if (GET_FILE_SYNC_OPENMODE(share_mode)) {
+ flags2 |= O_SYNC;
+ }
+#endif /* O_SYNC */
+
+ if (flags != O_RDONLY && file_existed &&
+ (!CAN_WRITE(conn) || IS_DOS_READONLY(dos_mode(conn,fname,psbuf)))) {
+ if (!fcbopen) {
+ DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n",
+ fname, !CAN_WRITE(conn) ? "share" : "file" ));
+ file_free(fsp);
+ errno = EACCES;
+ return NULL;
+ }
+ flags = O_RDONLY;
+ }
+
+ if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
+ DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
+ file_free(fsp);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (file_existed) {
+
+ dev = psbuf->st_dev;
+ inode = psbuf->st_ino;
+
+ lock_share_entry(conn, dev, inode);
+
+ num_share_modes = open_mode_check(conn, fname, dev, inode, share_mode,
+ &flags, &oplock_request, &all_current_opens_are_level_II);
+ if(num_share_modes == -1) {
+
+ /*
+ * This next line is a subtlety we need for MS-Access. If a file open will
+ * fail due to share permissions and also for security (access)
+ * reasons, we need to return the access failed error, not the
+ * share error. This means we must attempt to open the file anyway
+ * in order to get the UNIX access error - even if we're going to
+ * fail the open for share reasons. This is bad, as we're burning
+ * another fd if there are existing locks but there's nothing else
+ * we can do. We also ensure we're not going to create or tuncate
+ * the file as we only want an access decision at this stage. JRA.
+ */
+ fsp_open = open_file(fsp,conn,fname,psbuf,flags|(flags2&~(O_TRUNC|O_CREAT)),mode);
+
+ DEBUG(4,("open_file_shared : share_mode deny - calling open_file with \
+flags=0x%X flags2=0x%X mode=0%o returned %d\n",
+ flags,(flags2&~(O_TRUNC|O_CREAT)),(int)mode,(int)fsp_open ));
+
+ unlock_share_entry(conn, dev, inode);
+ if (fsp_open)
+ fd_close(conn, fsp);
+ file_free(fsp);
+ return NULL;
+ }
+
+ /*
+ * We exit this block with the share entry *locked*.....
+ */
+ }
+
+ DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
+ flags,flags2,(int)mode));
+
+ /*
+ * open_file strips any O_TRUNC flags itself.
+ */
+
+ fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,mode);
+
+ if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT) && fcbopen) {
+ if((fsp_open = open_file(fsp,conn,fname,psbuf,O_RDONLY,mode)) == True)
+ flags = O_RDONLY;
+ }
+
+ if (!fsp_open) {
+ if(file_existed)
+ unlock_share_entry(conn, dev, inode);
+ file_free(fsp);
+ return NULL;
+ }
+
+ /*
+ * Deal with the race condition where two smbd's detect the file doesn't
+ * exist and do the create at the same time. One of them will win and
+ * set a share mode, the other (ie. this one) should check if the
+ * requested share mode for this create is allowed.
+ */
+
+ if (!file_existed) {
+
+ lock_share_entry_fsp(fsp);
+
+ num_share_modes = open_mode_check(conn, fname, dev, inode, share_mode,
+ &flags, &oplock_request, &all_current_opens_are_level_II);
+
+ if(num_share_modes == -1) {
+ unlock_share_entry_fsp(fsp);
+ fd_close(conn,fsp);
+ file_free(fsp);
+ return NULL;
+ }
+
+ /*
+ * If there are any share modes set then the file *did*
+ * exist. Ensure we return the correct value for action.
+ */
+
+ if (num_share_modes > 0)
+ file_existed = True;
+
+ /*
+ * We exit this block with the share entry *locked*.....
+ */
+ }
+
+ /* note that we ignore failure for the following. It is
+ basically a hack for NFS, and NFS will never set one of
+ these only read them. Nobody but Samba can ever set a deny
+ mode and we have already checked our more authoritative
+ locking database for permission to set this deny mode. If
+ the kernel refuses the operations then the kernel is wrong */
+ kernel_flock(fsp, deny_mode);
+
+ /*
+ * At this point onwards, we can guarentee that the share entry
+ * is locked, whether we created the file or not, and that the
+ * deny mode is compatible with all current opens.
+ */
+
+ /*
+ * If requested, truncate the file.
+ */
+
+ if (flags2&O_TRUNC) {
+ /*
+ * We are modifing the file after open - update the stat struct..
+ */
+ if ((truncate_unless_locked(conn,fsp) == -1) || (vfs_fstat(fsp,fsp->fd,psbuf)==-1)) {
+ unlock_share_entry_fsp(fsp);
+ fd_close(conn,fsp);
+ file_free(fsp);
+ return NULL;
+ }
+ }
+
+ switch (flags) {
+ case O_RDONLY:
+ open_mode = DOS_OPEN_RDONLY;
+ break;
+ case O_RDWR:
+ open_mode = DOS_OPEN_RDWR;
+ break;
+ case O_WRONLY:
+ open_mode = DOS_OPEN_WRONLY;
+ break;
+ }
+
+ fsp->share_mode = SET_DENY_MODE(deny_mode) |
+ SET_OPEN_MODE(open_mode) |
+ SET_ALLOW_SHARE_DELETE(allow_share_delete) |
+ SET_DELETE_ACCESS_REQUESTED(delete_access_requested);
+
+ DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode ));
+
+ if (Access)
+ (*Access) = open_mode;
+
+ if (action) {
+ if (file_existed && !(flags2 & O_TRUNC))
+ *action = FILE_WAS_OPENED;
+ if (!file_existed)
+ *action = FILE_WAS_CREATED;
+ if (file_existed && (flags2 & O_TRUNC))
+ *action = FILE_WAS_OVERWRITTEN;
+ }
+
+ /*
+ * Setup the oplock info in both the shared memory and
+ * file structs.
+ */
+
+ if(oplock_request && (num_share_modes == 0) &&
+ !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) {
+ port = global_oplock_port;
+ } else if (oplock_request && all_current_opens_are_level_II) {
+ port = global_oplock_port;
+ oplock_request = LEVEL_II_OPLOCK;
+ set_file_oplock(fsp, oplock_request);
+ } else {
+ port = 0;
+ oplock_request = 0;
+ }
+
+ set_share_mode(fsp, port, oplock_request);
+
+ if (delete_on_close) {
+ NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close);
+
+ if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
+ unlock_share_entry_fsp(fsp);
+ fd_close(conn,fsp);
+ file_free(fsp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Take care of inherited ACLs on created files. JRA.
+ */
+
+ if (!file_existed && (conn->vfs_ops.fchmod_acl != NULL)) {
+ int saved_errno = errno; /* We might get ENOSYS in the next call.. */
+ if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS)
+ errno = saved_errno; /* Ignore ENOSYS */
+ }
+
+ unlock_share_entry_fsp(fsp);
+
+ conn->num_files_open++;
+
+ return fsp;
+}
+
+/****************************************************************************
+ Open a file for permissions read only. Return a pseudo file entry
+ with the 'stat_open' flag set
+****************************************************************************/
+
+files_struct *open_file_stat(connection_struct *conn, char *fname,
+ SMB_STRUCT_STAT *psbuf, int smb_ofun, int *action)
+{
+ extern struct current_user current_user;
+ files_struct *fsp = NULL;
+
+ if (!VALID_STAT(*psbuf)) {
+ DEBUG(0,("open_file_stat: unable to stat name = %s. Error was %s\n", fname, strerror(errno) ));
+ return NULL;
+ }
+
+ if(S_ISDIR(psbuf->st_mode)) {
+ DEBUG(0,("open_file_stat: %s is a directory !\n", fname ));
+ return NULL;
+ }
+
+ fsp = file_new(conn);
+ if(!fsp)
+ return NULL;
+
+ *action = FILE_WAS_OPENED;
+
+ DEBUG(5,("open_file_stat: opening file %s as a stat entry\n", fname));
+
+ /*
+ * Setup the files_struct for it.
+ */
+
+ fsp->mode = psbuf->st_mode;
+ fsp->inode = psbuf->st_ino;
+ fsp->dev = psbuf->st_dev;
+ fsp->size = psbuf->st_size;
+ fsp->vuid = current_user.vuid;
+ fsp->pos = -1;
+ fsp->can_lock = False;
+ fsp->can_read = False;
+ fsp->can_write = False;
+ fsp->share_mode = 0;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ fsp->stat_open = True;
+ fsp->directory_delete_on_close = False;
+ fsp->conn = conn;
+ string_set(&fsp->fsp_name,fname);
+ fsp->wcp = NULL; /* Write cache pointer. */
+
+ conn->num_files_open++;
+
+ return fsp;
+}
+
+/****************************************************************************
+ Open a file for for write to ensure that we can fchmod it.
+****************************************************************************/
+
+files_struct *open_file_fchmod(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf)
+{
+ files_struct *fsp = NULL;
+ BOOL fsp_open;
+
+ if (!VALID_STAT(*psbuf))
+ return NULL;
+
+ fsp = file_new(conn);
+ if(!fsp)
+ return NULL;
+
+ fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0);
+
+ /*
+ * This is not a user visible file open.
+ * Don't set a share mode and don't increment
+ * the conn->num_files_open.
+ */
+
+ if (!fsp_open) {
+ file_free(fsp);
+ return NULL;
+ }
+
+ return fsp;
+}
+
+/****************************************************************************
+ Close the fchmod file fd - ensure no locks are lost.
+****************************************************************************/
+
+int close_file_fchmod(files_struct *fsp)
+{
+ int ret = fd_close(fsp->conn, fsp);
+ file_free(fsp);
+ return ret;
+}
+
+/****************************************************************************
+ Open a directory from an NT SMB call.
+****************************************************************************/
+
+files_struct *open_directory(connection_struct *conn, char *fname,
+ SMB_STRUCT_STAT *psbuf, int share_mode, int smb_ofun, mode_t unixmode, int *action)
+{
+ extern struct current_user current_user;
+ BOOL got_stat = False;
+ files_struct *fsp = file_new(conn);
+ BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
+
+ if(!fsp)
+ return NULL;
+
+ fsp->conn = conn; /* The vfs_fXXX() macros need this. */
+
+ if (VALID_STAT(*psbuf))
+ got_stat = True;
+
+ if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) {
+ file_free(fsp);
+ errno = EEXIST; /* Setup so correct error is returned to client. */
+ return NULL;
+ }
+
+ if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) {
+
+ if (got_stat) {
+
+ if(!S_ISDIR(psbuf->st_mode)) {
+ DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
+ file_free(fsp);
+ errno = EACCES;
+ return NULL;
+ }
+ *action = FILE_WAS_OPENED;
+
+ } else {
+
+ /*
+ * Try and create the directory.
+ */
+
+ if(!CAN_WRITE(conn)) {
+ DEBUG(2,("open_directory: failing create on read-only share\n"));
+ file_free(fsp);
+ errno = EACCES;
+ return NULL;
+ }
+
+ if(vfs_mkdir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) {
+ DEBUG(2,("open_directory: unable to create %s. Error was %s\n",
+ fname, strerror(errno) ));
+ file_free(fsp);
+ return NULL;
+ }
+
+ if(vfs_stat(conn,fname, psbuf) != 0) {
+ file_free(fsp);
+ return NULL;
+ }
+
+ *action = FILE_WAS_CREATED;
+
+ }
+ } else {
+
+ /*
+ * Don't create - just check that it *was* a directory.
+ */
+
+ if(!got_stat) {
+ DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n",
+ fname, strerror(errno) ));
+ file_free(fsp);
+ return NULL;
+ }
+
+ if(!S_ISDIR(psbuf->st_mode)) {
+ DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
+ file_free(fsp);
+ return NULL;
+ }
+
+ *action = FILE_WAS_OPENED;
+ }
+
+ DEBUG(5,("open_directory: opening directory %s\n", fname));
+
+ /*
+ * Setup the files_struct for it.
+ */
+
+ fsp->mode = psbuf->st_mode;
+ fsp->inode = psbuf->st_ino;
+ fsp->dev = psbuf->st_dev;
+ fsp->size = psbuf->st_size;
+ fsp->vuid = current_user.vuid;
+ fsp->pos = -1;
+ fsp->can_lock = True;
+ fsp->can_read = False;
+ fsp->can_write = False;
+ fsp->share_mode = share_mode;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = True;
+ fsp->directory_delete_on_close = False;
+ fsp->conn = conn;
+ string_set(&fsp->fsp_name,fname);
+
+ if (delete_on_close) {
+ NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close);
+
+ if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
+ file_free(fsp);
+ return NULL;
+ }
+ }
+ conn->num_files_open++;
+
+ return fsp;
+}
+
+/*******************************************************************
+ Check if the share mode on a file allows it to be deleted or unlinked.
+ Return True if sharing doesn't prevent the operation.
+********************************************************************/
+
+BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
+{
+ int i;
+ int ret = False;
+ share_mode_entry *old_shares = 0;
+ int num_share_modes;
+ SMB_STRUCT_STAT sbuf;
+ pid_t pid = sys_getpid();
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+
+ if (vfs_stat(conn,fname,&sbuf) == -1)
+ return(True);
+
+ dev = sbuf.st_dev;
+ inode = sbuf.st_ino;
+
+ lock_share_entry(conn, dev, inode);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ if(num_share_modes != 0)
+ {
+ BOOL broke_oplock;
+
+ do
+ {
+
+ broke_oplock = False;
+ for(i = 0; i < num_share_modes; i++)
+ {
+ share_mode_entry *share_entry = &old_shares[i];
+
+ /*
+ * Break oplocks before checking share modes. See comment in
+ * open_file_shared for details.
+ * Check if someone has an oplock on this file. If so we must
+ * break it before continuing.
+ */
+ if(BATCH_OPLOCK_TYPE(share_entry->op_type))
+ {
+
+#if 0
+
+/* JRA. Try removing this code to see if the new oplock changes
+ fix the problem. I'm dubious, but Andrew is recommending we
+ try this....
+*/
+
+ /*
+ * It appears that the NT redirector may have a bug, in that
+ * it tries to do an SMBmv on a file that it has open with a
+ * batch oplock, and then fails to respond to the oplock break
+ * request. This only seems to occur when the client is doing an
+ * SMBmv to the smbd it is using - thus we try and detect this
+ * condition by checking if the file being moved is open and oplocked by
+ * this smbd process, and then not sending the oplock break in this
+ * special case. If the file was open with a deny mode that
+ * prevents the move the SMBmv will fail anyway with a share
+ * violation error. JRA.
+ */
+ if(rename_op && (share_entry->pid == pid))
+ {
+
+ DEBUG(0,("check_file_sharing: NT redirector workaround - rename attempted on \
+batch oplocked file %s, dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (double)inode));
+
+ /*
+ * This next line is a test that allows the deny-mode
+ * processing to be skipped. This seems to be needed as
+ * NT insists on the rename succeeding (in Office 9x no less !).
+ * This should be removed as soon as (a) MS fix the redirector
+ * bug or (b) NT SMB support in Samba makes NT not issue the
+ * call (as is my fervent hope). JRA.
+ */
+ continue;
+ }
+ else
+#endif /* 0 */
+ {
+
+ DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode));
+
+ /* Oplock break.... */
+ unlock_share_entry(conn, dev, inode);
+ if(request_oplock_break(share_entry) == False)
+ {
+ DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
+
+ SAFE_FREE(old_shares);
+ return False;
+ }
+ lock_share_entry(conn, dev, inode);
+ broke_oplock = True;
+ break;
+ }
+ }
+
+ /*
+ * If this is a delete request and ALLOW_SHARE_DELETE is set then allow
+ * this to proceed. This takes precedence over share modes.
+ */
+
+ if(!rename_op && GET_ALLOW_SHARE_DELETE(share_entry->share_mode))
+ continue;
+
+ /*
+ * Someone else has a share lock on it, check to see
+ * if we can too.
+ */
+
+ if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||
+ (share_entry->pid != pid))
+ goto free_and_exit;
+
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ SAFE_FREE(old_shares);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ }
+ } while(broke_oplock);
+ }
+
+ /* XXXX exactly what share mode combinations should be allowed for
+ deleting/renaming? */
+ /*
+ * If we got here then either there were no share modes or
+ * all share modes were DENY_DOS and the pid == getpid() or
+ * delete access was requested and all share modes had the
+ * ALLOW_SHARE_DELETE bit set (takes precedence over other
+ * share modes).
+ */
+
+ ret = True;
+
+free_and_exit:
+
+ unlock_share_entry(conn, dev, inode);
+ SAFE_FREE(old_shares);
+ return(ret);
+}
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
new file mode 100644
index 00000000000..844e7d812a9
--- /dev/null
+++ b/source/smbd/oplock.c
@@ -0,0 +1,1218 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.x
+ oplock processing
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998 - 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Oplock ipc UDP socket. */
+static int oplock_sock = -1;
+uint16 global_oplock_port = 0;
+
+/* Current number of oplocks we have outstanding. */
+static int32 exclusive_oplocks_open = 0;
+static int32 level_II_oplocks_open = 0;
+BOOL global_client_failed_oplock_break = False;
+BOOL global_oplock_break = False;
+
+extern int smb_read_error;
+
+static struct kernel_oplocks *koplocks;
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local);
+
+/****************************************************************************
+ Get the number of current exclusive oplocks.
+****************************************************************************/
+
+int32 get_number_of_exclusive_open_oplocks(void)
+{
+ return exclusive_oplocks_open;
+}
+
+/****************************************************************************
+ Return True if an oplock message is pending.
+****************************************************************************/
+
+BOOL oplock_message_waiting(fd_set *fds)
+{
+ if (koplocks && koplocks->msg_waiting(fds))
+ return True;
+
+ if (FD_ISSET(oplock_sock, fds))
+ return True;
+
+ return False;
+}
+
+/****************************************************************************
+ Read an oplock break message from either the oplock UDP fd or the
+ kernel (if kernel oplocks are supported).
+
+ If timeout is zero then *fds contains the file descriptors that
+ are ready to be read and acted upon. If timeout is non-zero then
+ *fds contains the file descriptors to be selected on for read.
+ The timeout is in milliseconds
+
+****************************************************************************/
+
+BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout)
+{
+ struct sockaddr_in from;
+ int fromlen = sizeof(from);
+ int32 msg_len = 0;
+
+ smb_read_error = 0;
+
+ if(timeout != 0) {
+ struct timeval to;
+ int selrtn;
+ int maxfd = oplock_sock;
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, fds);
+ maxfd = MAX(maxfd, koplocks->notification_fd);
+ }
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(maxfd+1,fds,&to);
+
+ if (selrtn == -1 && errno == EINTR) {
+ /* could be a kernel oplock interrupt */
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
+ }
+ }
+
+ /* Check if error */
+ if(selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
+ }
+ }
+
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
+ }
+
+ if (!FD_ISSET(oplock_sock, fds))
+ return False;
+
+ /*
+ * From here down we deal with the smbd <--> smbd
+ * oplock break protocol only.
+ */
+
+ /*
+ * Read a loopback udp message.
+ */
+ msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
+ buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen);
+
+ if(msg_len < 0) {
+ DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+ return False;
+ }
+
+ /* Validate message length. */
+ if(msg_len > (buffer_len - OPBRK_CMD_HEADER_LEN)) {
+ DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", msg_len,
+ buffer_len - OPBRK_CMD_HEADER_LEN));
+ return False;
+ }
+
+ /* Validate message from address (must be localhost). */
+ if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+ DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %lx should be 127.0.0.1)\n", (long)from.sin_addr.s_addr));
+ return False;
+ }
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,msg_len);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
+ disabled (just sets flags). Returns True if oplock set.
+****************************************************************************/
+
+BOOL set_file_oplock(files_struct *fsp, int oplock_type)
+{
+ if (koplocks && !koplocks->set_oplock(fsp, oplock_type))
+ return False;
+
+ fsp->oplock_type = oplock_type;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ if (oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open++;
+ else
+ exclusive_oplocks_open++;
+
+ DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, file_id = %lu, \
+tv_sec = %x, tv_usec = %x\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id,
+ (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec ));
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to release an oplock on a file. Decrements oplock count.
+****************************************************************************/
+
+void release_file_oplock(files_struct *fsp)
+{
+ if (koplocks)
+ koplocks->release_oplock(fsp);
+
+ if (fsp->oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open--;
+ else
+ exclusive_oplocks_open--;
+
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+
+ flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
+}
+
+/****************************************************************************
+ Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
+****************************************************************************/
+
+static void downgrade_file_oplock(files_struct *fsp)
+{
+ if (koplocks)
+ koplocks->release_oplock(fsp);
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ exclusive_oplocks_open--;
+ level_II_oplocks_open++;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+}
+
+/****************************************************************************
+ Remove a file oplock. Copes with level II and exclusive.
+ Locks then unlocks the share mode lock. Client can decide to go directly
+ to none even if a "break-to-level II" was sent.
+****************************************************************************/
+
+BOOL remove_oplock(files_struct *fsp, BOOL break_to_none)
+{
+ SMB_DEV_T dev = fsp->dev;
+ SMB_INO_T inode = fsp->inode;
+ BOOL ret = True;
+
+ /* Remove the oplock flag from the sharemode. */
+ if (lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
+ fsp->fsp_name ));
+ ret = False;
+ }
+
+ if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT || break_to_none) {
+ /*
+ * Deal with a reply when a break-to-none was sent.
+ */
+
+ if(remove_share_oplock(fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ ret = False;
+ }
+
+ release_file_oplock(fsp);
+ } else {
+ /*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+ if(downgrade_share_oplock(fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ ret = False;
+ }
+
+ downgrade_file_oplock(fsp);
+ }
+
+ unlock_share_entry_fsp(fsp);
+ return ret;
+}
+
+/****************************************************************************
+ Setup the listening set of file descriptors for an oplock break
+ message either from the UDP socket or from the kernel. Returns the maximum
+ fd used.
+****************************************************************************/
+
+int setup_oplock_select_set( fd_set *fds)
+{
+ int maxfd = oplock_sock;
+
+ if(oplock_sock == -1)
+ return 0;
+
+ FD_SET(oplock_sock,fds);
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, fds);
+ maxfd = MAX(maxfd, koplocks->notification_fd);
+ }
+
+ return maxfd;
+}
+
+/****************************************************************************
+ Process an oplock break message - whether it came from the UDP socket
+ or from the kernel.
+****************************************************************************/
+
+BOOL process_local_message(char *buffer, int buf_size)
+{
+ int32 msg_len;
+ uint16 from_port;
+ char *msg_start;
+ pid_t remotepid;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ unsigned long file_id;
+ uint16 break_cmd_type;
+
+ msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET);
+ from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET);
+
+ msg_start = &buffer[OPBRK_CMD_HEADER_LEN];
+
+ DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n",
+ msg_len, from_port));
+
+ /*
+ * Pull the info out of the requesting packet.
+ */
+
+ break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET);
+
+ switch(break_cmd_type) {
+ case KERNEL_OPLOCK_BREAK_CMD:
+ if (!koplocks) {
+ DEBUG(0,("unexpected kernel oplock break!\n"));
+ break;
+ }
+ if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev, &file_id)) {
+ DEBUG(0,("kernel oplock break parse failure!\n"));
+ }
+ break;
+
+ case OPLOCK_BREAK_CMD:
+ case LEVEL_II_OPLOCK_BREAK_CMD:
+
+ /* Ensure that the msg length is correct. */
+ if(msg_len != OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id));
+
+ DEBUG(5,("process_local_message: (%s) oplock break request from \
+pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n",
+ (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+ break;
+
+ /*
+ * Keep this as a debug case - eventually we can remove it.
+ */
+ case 0x8001:
+ DEBUG(0,("process_local_message: Received unsolicited break \
+reply - dumping info.\n"));
+
+ if(msg_len != OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("process_local_message: ubr: incorrect length for reply \
+(was %d, should be %d).\n", (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id));
+
+ DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+
+ return False;
+
+ default:
+ DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
+ (unsigned int)SVAL(msg_start,0)));
+ return False;
+ }
+
+ /*
+ * Now actually process the break request.
+ */
+
+ if((exclusive_oplocks_open + level_II_oplocks_open) != 0) {
+ if (oplock_break(dev, inode, file_id, False) == False) {
+ DEBUG(0,("process_local_message: oplock break failed.\n"));
+ return False;
+ }
+ } else {
+ /*
+ * If we have no record of any currently open oplocks,
+ * it's not an error, as a close command may have
+ * just been issued on the file that was oplocked.
+ * Just log a message and return success in this case.
+ */
+ DEBUG(3,("process_local_message: oplock break requested with no outstanding \
+oplocks. Returning success.\n"));
+ }
+
+ /*
+ * Do the appropriate reply - none in the kernel or level II case.
+ */
+
+ if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD) {
+ struct sockaddr_in toaddr;
+
+ /* Send the message back after OR'ing in the 'REPLY' bit. */
+ SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
+
+ memset((char *)&toaddr,'\0',sizeof(toaddr));
+ toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ toaddr.sin_port = htons(from_port);
+ toaddr.sin_family = AF_INET;
+
+ if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+ (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) {
+ DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
+ (int)remotepid, strerror(errno)));
+ return False;
+ }
+
+ DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %.0f, file_id = %lu\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set up an oplock break message.
+****************************************************************************/
+
+static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)
+{
+ memset(outbuf,'\0',smb_size);
+ set_message(outbuf,8,0,True);
+
+ SCVAL(outbuf,smb_com,SMBlockingX);
+ SSVAL(outbuf,smb_tid,fsp->conn->cnum);
+ SSVAL(outbuf,smb_pid,0xFFFF);
+ SSVAL(outbuf,smb_uid,0);
+ SSVAL(outbuf,smb_mid,0xFFFF);
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,fsp->fnum);
+ SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
+}
+
+/****************************************************************************
+ Function to do the waiting before sending a local break.
+****************************************************************************/
+
+static void wait_before_sending_break(BOOL local_request)
+{
+ extern struct timeval smb_last_time;
+
+ if(local_request) {
+ struct timeval cur_tv;
+ long wait_left = (long)lp_oplock_break_wait_time();
+
+ if (wait_left == 0)
+ return;
+
+ GetTimeOfDay(&cur_tv);
+
+ wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
+ ((cur_tv.tv_usec - smb_last_time.tv_usec)/1000);
+
+ if(wait_left > 0) {
+ wait_left = MIN(wait_left, 1000);
+ sys_usleep(wait_left * 1000);
+ }
+ }
+}
+
+/****************************************************************************
+ Ensure that we have a valid oplock.
+****************************************************************************/
+
+static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
+{
+ files_struct *fsp = NULL;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id);
+ dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+ exclusive_oplocks_open, level_II_oplocks_open );
+ }
+
+ /*
+ * We need to search the file open table for the
+ * entry containing this dev and inode, and ensure
+ * we have an oplock on it.
+ */
+
+ fsp = file_find_dif(dev, inode, file_id);
+
+ if(fsp == NULL) {
+ /* The file could have been closed in the meantime - return success. */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: cannot find open file with " );
+ dbgtext( "dev = %x, inode = %.0f file_id = %lu", (unsigned int)dev,
+ (double)inode, file_id);
+ dbgtext( "allowing break to succeed.\n" );
+ }
+ return NULL;
+ }
+
+ /* Ensure we have an oplock on the file */
+
+ /*
+ * There is a potential race condition in that an oplock could
+ * have been broken due to another udp request, and yet there are
+ * still oplock break messages being sent in the udp message
+ * queue for this file. So return true if we don't have an oplock,
+ * as we may have just freed it.
+ */
+
+ if(fsp->oplock_type == NO_OPLOCK) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu) has no oplock.\n",
+ (unsigned int)dev, (double)inode, fsp->file_id );
+ dbgtext( "Allowing break to succeed regardless.\n" );
+ }
+ return NULL;
+ }
+
+ return fsp;
+}
+
+/****************************************************************************
+ Process a level II oplock break directly.
+****************************************************************************/
+
+BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
+{
+ extern uint32 global_client_caps;
+ char outbuf[128];
+ BOOL got_lock = False;
+ SMB_DEV_T dev = fsp->dev;
+ SMB_INO_T inode = fsp->inode;
+
+ /*
+ * We can have a level II oplock even if the client is not
+ * level II oplock aware. In this case just remove the
+ * flags and don't send the break-to-none message to
+ * the client.
+ */
+
+ if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ prepare_break_message( outbuf, fsp, False);
+ if (!send_smb(smbd_server_fd(), outbuf))
+ exit_server("oplock_break_level2: send_smb failed.");
+ }
+
+ /*
+ * Now we must update the shared memory structure to tell
+ * everyone else we no longer have a level II oplock on
+ * this open file. If local_request is true then token is
+ * the existing lock on the shared memory area.
+ */
+
+ if(!local_request && lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
+ } else {
+ got_lock = True;
+ }
+
+ if(remove_share_oplock(fsp)==False) {
+ DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
+ }
+
+ if (!local_request && got_lock)
+ unlock_share_entry_fsp(fsp);
+
+ fsp->oplock_type = NO_OPLOCK;
+ level_II_oplocks_open--;
+
+ if(level_II_oplocks_open < 0) {
+ DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
+ level_II_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "oplock_break_level2: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, fsp->file_id );
+ dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open );
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local_request)
+{
+ extern uint32 global_client_caps;
+ extern struct current_user current_user;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ time_t start_time;
+ BOOL shutdown_server = False;
+ BOOL oplock_timeout = False;
+ connection_struct *saved_user_conn;
+ connection_struct *saved_fsp_conn;
+ int saved_vuid;
+ pstring saved_dir;
+ int timeout = (OPLOCK_BREAK_TIMEOUT * 1000);
+ pstring file_name;
+ BOOL using_levelII;
+
+ if((fsp = initial_break_processing(dev, inode, file_id)) == NULL)
+ return True;
+
+ /*
+ * Deal with a level II oplock going break to none separately.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return oplock_break_level2(fsp, local_request, -1);
+
+ /* Mark the oplock break as sent - we don't want to send twice! */
+ if (fsp->sent_oplock_break) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "oplock_break: ERROR: oplock_break already sent for " );
+ dbgtext( "file %s ", fsp->fsp_name);
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu)\n", (unsigned int)dev, (double)inode, fsp->file_id );
+ }
+
+ /*
+ * We have to fail the open here as we cannot send another oplock break on
+ * this file whilst we are awaiting a response from the client - neither
+ * can we allow another open to succeed while we are waiting for the client.
+ */
+ return False;
+ }
+
+ if(global_oplock_break) {
+ DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n"));
+ abort();
+ }
+
+ /*
+ * Now comes the horrid part. We must send an oplock break to the client,
+ * and then process incoming messages until we get a close or oplock release.
+ * At this point we know we need a new inbuf/outbuf buffer pair.
+ * We cannot use these staticaly as we may recurse into here due to
+ * messages crossing on the wire.
+ */
+
+ if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+
+ if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ SAFE_FREE(inbuf);
+ return False;
+ }
+
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+ !koplocks && /* NOTE: we force levelII off for kernel oplocks - this will change when it is supported */
+ lp_level2_oplocks(SNUM(fsp->conn))) {
+ using_levelII = True;
+ } else {
+ using_levelII = False;
+ }
+
+ prepare_break_message( outbuf, fsp, using_levelII);
+ /* Remember if we just sent a break to level II on this file. */
+ fsp->sent_oplock_break = using_levelII? LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT;
+
+ if (!send_smb(smbd_server_fd(), outbuf))
+ exit_server("oplock_break: send_smb failed.");
+
+ /* We need this in case a readraw crosses on the wire. */
+ global_oplock_break = True;
+
+ /* Process incoming messages. */
+
+ /*
+ * JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+ * seconds we should just die....
+ */
+
+ start_time = time(NULL);
+
+ /*
+ * Save the information we need to re-become the
+ * user, then unbecome the user whilst we're doing this.
+ */
+ saved_user_conn = current_user.conn;
+ saved_vuid = current_user.vuid;
+ saved_fsp_conn = fsp->conn;
+ vfs_GetWd(saved_fsp_conn,saved_dir);
+ change_to_root_user();
+ /* Save the chain fnum. */
+ file_chain_save();
+
+ /*
+ * From Charles Hoch <hoch@exemplary.com>. If the break processing
+ * code closes the file (as it often does), then the fsp pointer here
+ * points to free()'d memory. We *must* revalidate fsp each time
+ * around the loop.
+ */
+
+ pstrcpy(file_name, fsp->fsp_name);
+
+ while((fsp = initial_break_processing(dev, inode, file_id)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ if(receive_smb(smbd_server_fd(),inbuf, timeout) == False) {
+ /*
+ * Die if we got an error.
+ */
+
+ if (smb_read_error == READ_EOF) {
+ DEBUG( 0, ( "oplock_break: end of file from client\n" ) );
+ shutdown_server = True;
+ } else if (smb_read_error == READ_ERROR) {
+ DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
+ shutdown_server = True;
+ } else if (smb_read_error == READ_TIMEOUT) {
+ DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n", OPLOCK_BREAK_TIMEOUT ) );
+ oplock_timeout = True;
+ }
+
+ DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) );
+ DEBUGADD( 0, ( "(dev = %x, inode = %.0f, file_id = %lu).\n",
+ (unsigned int)dev, (double)inode, file_id));
+
+ break;
+ }
+
+ /*
+ * There are certain SMB requests that we shouldn't allow
+ * to recurse. opens, renames and deletes are the obvious
+ * ones. This is handled in the switch_message() function.
+ * If global_oplock_break is set they will push the packet onto
+ * the pending smb queue and return -1 (no reply).
+ * JRA.
+ */
+
+ process_smb(inbuf, outbuf);
+
+ /*
+ * Die if we go over the time limit.
+ */
+
+ if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "oplock_break: no break received from client " );
+ dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT );
+ dbgtext( "oplock_break failed for file %s ", fsp->fsp_name );
+ dbgtext( "(dev = %x, inode = %.0f, file_id = %lu).\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+ oplock_timeout = True;
+ break;
+ }
+ }
+
+ /*
+ * Go back to being the user who requested the oplock
+ * break.
+ */
+ if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !change_to_user(saved_user_conn, saved_vuid)) {
+ DEBUG( 0, ( "oplock_break: unable to re-become user!" ) );
+ DEBUGADD( 0, ( "Shutting down server\n" ) );
+ close(oplock_sock);
+ exit_server("unable to re-become user");
+ }
+
+ /* Including the directory. */
+ vfs_ChDir(saved_fsp_conn,saved_dir);
+
+ /* Restore the chain fnum. */
+ file_chain_restore();
+
+ /* Free the buffers we've been using to recurse. */
+ SAFE_FREE(inbuf);
+ SAFE_FREE(outbuf);
+
+ /* We need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
+ /*
+ * If the client timed out then clear the oplock (or go to level II)
+ * and continue. This seems to be what NT does and is better than dropping
+ * the connection.
+ */
+
+ if(oplock_timeout && (fsp = initial_break_processing(dev, inode, file_id)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name));
+ remove_oplock(fsp,True);
+ global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */
+ }
+
+ /*
+ * If the client had an error we must die.
+ */
+
+ if(shutdown_server) {
+ DEBUG( 0, ( "oplock_break: client failure in break - " ) );
+ DEBUGADD( 0, ( "shutting down this smbd.\n" ) );
+ close(oplock_sock);
+ exit_server("oplock break failure");
+ }
+
+ /* Santity check - remove this later. JRA */
+ if(exclusive_oplocks_open < 0) {
+ DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n", exclusive_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "oplock_break: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open );
+ }
+
+ return True;
+}
+
+/****************************************************************************
+Send an oplock break message to another smbd process. If the oplock is held
+by the local smbd then call the oplock break function directly.
+****************************************************************************/
+
+BOOL request_oplock_break(share_mode_entry *share_entry)
+{
+ char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+ struct sockaddr_in addr_out;
+ pid_t pid = sys_getpid();
+ time_t start_time;
+ int time_left;
+ SMB_DEV_T dev = share_entry->dev;
+ SMB_INO_T inode = share_entry->inode;
+ unsigned long file_id = share_entry->share_file_id;
+
+ if(pid == share_entry->pid) {
+ /* We are breaking our own oplock, make sure it's us. */
+ if(share_entry->op_port != global_oplock_port) {
+ DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
+should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
+ return False;
+ }
+
+ DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+
+#if 1 /* JRA PARANOIA TEST.... */
+ {
+ files_struct *fsp = file_find_dif(dev, inode, file_id);
+ if (!fsp) {
+ DEBUG(0,("request_oplock_break: PANIC : breaking our own oplock requested for \
+dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n",
+ (unsigned int)dev, (double)inode, file_id ));
+ smb_panic("request_oplock_break: no fsp found for our own oplock\n");
+ }
+ }
+#endif /* END JRA PARANOIA TEST... */
+
+ /* Call oplock break direct. */
+ return oplock_break(dev, inode, file_id, True);
+ }
+
+ /* We need to send a OPLOCK_BREAK_CMD message to the port in the share mode entry. */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD);
+ } else {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ }
+
+ memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
+ memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
+ memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
+ memcpy(op_break_msg+OPLOCK_BREAK_FILEID_OFFSET,(char *)&file_id,sizeof(file_id));
+
+ /* Set the address and port. */
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( share_entry->op_port );
+ addr_out.sin_family = AF_INET;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "request_oplock_break: sending a oplock break message to " );
+ dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+
+ if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: failed when sending a oplock " );
+ dbgtext( "break message to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+
+ /*
+ * If we just sent a message to a level II oplock share entry then
+ * we are done and may return.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(3,("request_oplock_break: sent break message to level II entry.\n"));
+ return True;
+ }
+
+ /*
+ * Now we must await the oplock broken message coming back
+ * from the target smbd process. Timeout if it fails to
+ * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
+ * While we get messages that aren't ours, loop.
+ */
+
+ start_time = time(NULL);
+ time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
+
+ while(time_left >= 0) {
+ char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+ uint16 reply_from_port;
+ char *reply_msg_start;
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(oplock_sock,&fds);
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, &fds);
+ }
+
+ if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
+ time_left ? time_left * 1000 : 1) == False) {
+ if(smb_read_error == READ_TIMEOUT) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: no response received to oplock " );
+ dbgtext( "break request to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+
+ /*
+ * This is a hack to make handling of failing clients more robust.
+ * If a oplock break response message is not received in the timeout
+ * period we may assume that the smbd servicing that client holding
+ * the oplock has died and the client changes were lost anyway, so
+ * we should continue to try and open the file.
+ */
+ break;
+ } else {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_oplock_break: error in response received " );
+ dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Error was (%s).\n", strerror(errno) );
+ }
+ }
+ return False;
+ }
+
+ reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET);
+ reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN];
+
+ /*
+ * Test to see if this is the reply we are awaiting.
+ */
+ if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
+ ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) &&
+ (reply_from_port == share_entry->op_port) &&
+ (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
+ OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0)) {
+
+ /*
+ * This is the reply we've been waiting for.
+ */
+ break;
+ } else {
+ /*
+ * This is another message - a break request.
+ * Note that both kernel oplock break requests
+ * and UDP inter-smbd oplock break requests will
+ * be processed here.
+ *
+ * Process it to prevent potential deadlock.
+ * Note that the code in switch_message() prevents
+ * us from recursing into here as any SMB requests
+ * we might process that would cause another oplock
+ * break request to be made will be queued.
+ * JRA.
+ */
+
+ process_local_message(op_break_reply, sizeof(op_break_reply));
+ }
+
+ time_left -= (time(NULL) - start_time);
+ }
+
+ DEBUG(3,("request_oplock_break: broke oplock.\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to break an oplock on a file (if oplocked).
+ Returns True if the file was closed as a result of
+ the oplock break, False otherwise.
+ Used as a last ditch attempt to free a space in the
+ file table when we have run out.
+****************************************************************************/
+
+BOOL attempt_close_oplocked_file(files_struct *fsp)
+{
+ DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name));
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) {
+ /* Try and break the oplock. */
+ if (oplock_break(fsp->dev, fsp->inode, fsp->file_id, True)) {
+ if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ This function is called on any file modification or lock request. If a file
+ is level 2 oplocked then it must tell all other level 2 holders to break to none.
+****************************************************************************/
+
+void release_level_2_oplocks_on_change(files_struct *fsp)
+{
+ share_mode_entry *share_list = NULL;
+ pid_t pid = sys_getpid();
+ int token = -1;
+ int num_share_modes = 0;
+ int i;
+
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return;
+
+ if (lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("release_level_2_oplocks_on_change: failed to lock share mode entry for file %s.\n", fsp->fsp_name ));
+ }
+
+ num_share_modes = get_share_modes(fsp->conn, fsp->dev, fsp->inode, &share_list);
+
+ DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n",
+ num_share_modes ));
+
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &share_list[i];
+
+ /*
+ * As there could have been multiple writes waiting at the lock_share_entry
+ * gate we may not be the first to enter. Hence the state of the op_types
+ * in the share mode entries may be partly NO_OPLOCK and partly LEVEL_II
+ * oplock. It will do no harm to re-send break messages to those smbd's
+ * that are still waiting their turn to remove their LEVEL_II state, and
+ * also no harm to ignore existing NO_OPLOCK states. JRA.
+ */
+
+ DEBUG(10,("release_level_2_oplocks_on_change: share_entry[%i]->op_type == %d\n",
+ i, share_entry->op_type ));
+
+ if (share_entry->op_type == NO_OPLOCK)
+ continue;
+
+ /* Paranoia .... */
+ if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(0,("release_level_2_oplocks_on_change: PANIC. share mode entry %d is an exlusive oplock !\n", i ));
+ unlock_share_entry(fsp->conn, fsp->dev, fsp->inode);
+ abort();
+ }
+
+ /*
+ * Check if this is a file we have open (including the
+ * file we've been called to do write_file on. If so
+ * then break it directly without releasing the lock.
+ */
+
+ if (pid == share_entry->pid) {
+ files_struct *new_fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id);
+
+ /* Paranoia check... */
+ if(new_fsp == NULL) {
+ DEBUG(0,("release_level_2_oplocks_on_change: PANIC. share mode entry %d is not a local file !\n", i ));
+ unlock_share_entry(fsp->conn, fsp->dev, fsp->inode);
+ abort();
+ }
+
+ DEBUG(10,("release_level_2_oplocks_on_change: breaking our own oplock.\n"));
+
+ oplock_break_level2(new_fsp, True, token);
+
+ } else {
+
+ /*
+ * This is a remote file and so we send an asynchronous
+ * message.
+ */
+
+ DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n"));
+ request_oplock_break(share_entry);
+ }
+ }
+
+ SAFE_FREE(share_list);
+ unlock_share_entry_fsp(fsp);
+
+ /* Paranoia check... */
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("release_level_2_oplocks_on_change: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name));
+ smb_panic("release_level_2_oplocks_on_change");
+ }
+}
+
+/****************************************************************************
+setup oplocks for this process
+****************************************************************************/
+
+BOOL init_oplocks(void)
+{
+ struct sockaddr_in sock_name;
+ socklen_t len = sizeof(sock_name);
+
+ DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+
+ /* Open a lookback UDP socket on a random port. */
+ oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False);
+ if (oplock_sock == -1) {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno)));
+ global_oplock_port = 0;
+ return(False);
+ }
+
+ /* Find out the transient UDP port we have been allocated. */
+ if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
+ strerror(errno)));
+ close(oplock_sock);
+ oplock_sock = -1;
+ global_oplock_port = 0;
+ return False;
+ }
+ global_oplock_port = ntohs(sock_name.sin_port);
+
+ if (lp_kernel_oplocks()) {
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ koplocks = irix_init_kernel_oplocks();
+#elif HAVE_KERNEL_OPLOCKS_LINUX
+ koplocks = linux_init_kernel_oplocks();
+#endif
+ }
+
+ DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",
+ (int)sys_getpid(), global_oplock_port));
+
+ return True;
+}
diff --git a/source/smbd/oplock_irix.c b/source/smbd/oplock_irix.c
new file mode 100644
index 00000000000..10520461753
--- /dev/null
+++ b/source/smbd/oplock_irix.c
@@ -0,0 +1,286 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.x
+ IRIX kernel oplock processing
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if HAVE_KERNEL_OPLOCKS_IRIX
+
+static int oplock_pipe_write = -1;
+static int oplock_pipe_read = -1;
+
+/****************************************************************************
+ Test to see if IRIX kernel oplocks work.
+****************************************************************************/
+
+static BOOL irix_oplocks_available(void)
+{
+ int fd;
+ int pfd[2];
+ pstring tmpname;
+
+ oplock_set_capability(True, False);
+
+ slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid());
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n",
+ tmpname, strerror(errno) ));
+ unlink( tmpname );
+ close(pfd[0]);
+ close(pfd[1]);
+ return False;
+ }
+
+ unlink(tmpname);
+
+ if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) {
+ DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \
+Disabling kernel oplock support.\n" ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
+ DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \
+Disabling kernel oplock support.\n", strerror(errno) ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+
+ return True;
+}
+
+/****************************************************************************
+ * Deal with the IRIX kernel <--> smbd
+ * oplock break protocol.
+****************************************************************************/
+
+static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
+{
+ extern int smb_read_error;
+ oplock_stat_t os;
+ char dummy;
+ files_struct *fsp;
+
+ /*
+ * Read one byte of zero to clear the
+ * kernel break notify message.
+ */
+
+ if(read(oplock_pipe_read, &dummy, 1) != 1) {
+ DEBUG(0,("receive_local_message: read of kernel notification failed. \
+Error was %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * Do a query to get the
+ * device and inode of the file that has the break
+ * request outstanding.
+ */
+
+ if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+ DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
+Error was %s.\n", strerror(errno) ));
+ if(errno == EAGAIN) {
+ /*
+ * Duplicate kernel break message - ignore.
+ */
+ memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
+ return True;
+ }
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * We only have device and inode info here - we have to guess that this
+ * is the first fsp open with this dev,ino pair.
+ */
+
+ if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) {
+ DEBUG(0,("receive_local_message: unable to find open file with dev = %x, inode = %.0f\n",
+ (unsigned int)os.os_dev, (double)os.os_ino ));
+ return False;
+ }
+
+ DEBUG(5,("receive_local_message: kernel oplock break request received for \
+dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
+
+ /*
+ * Create a kernel oplock break message.
+ */
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
+
+ buffer += OPBRK_CMD_HEADER_LEN;
+
+ SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
+
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to set an kernel oplock on a file.
+****************************************************************************/
+
+static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
+{
+ if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) {
+ if(errno != EAGAIN) {
+ DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
+inode = %.0f, file_id = %ul. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id,
+ strerror(errno) ));
+ } else {
+ DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+inode = %.0f, file_id = %ul. Another process had the file open.\n",
+ fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
+ }
+ return False;
+ }
+
+ DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Release a kernel oplock on a file.
+****************************************************************************/
+
+static void irix_release_kernel_oplock(files_struct *fsp)
+{
+ if (DEBUGLVL(10)) {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = fcntl(fsp->fd, F_OPLKACK, -1);
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \
+oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, fsp->file_id, state );
+ }
+
+ /*
+ * Remove the kernel oplock on this file.
+ */
+ if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
+ if( DEBUGLVL( 0 )) {
+ dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+ dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, fsp->file_id, strerror(errno) );
+ }
+ }
+}
+
+/****************************************************************************
+ Parse a kernel oplock message.
+****************************************************************************/
+
+static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len,
+ SMB_INO_T *inode, SMB_DEV_T *dev, unsigned long *file_id)
+{
+ /* Ensure that the msg length is correct. */
+ if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
+ memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id));
+
+ DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %ul\n",
+ (unsigned int)*dev, (double)*inode, *file_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Set *maxfd to include oplock read pipe.
+****************************************************************************/
+
+static BOOL irix_oplock_msg_waiting(fd_set *fds)
+{
+ if (oplock_pipe_read == -1)
+ return False;
+
+ return FD_ISSET(oplock_pipe_read,fds);
+}
+
+/****************************************************************************
+ Setup kernel oplocks.
+****************************************************************************/
+
+struct kernel_oplocks *irix_init_kernel_oplocks(void)
+{
+ int pfd[2];
+ static struct kernel_oplocks koplocks;
+
+ if (!irix_oplocks_available())
+ return NULL;
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ oplock_pipe_read = pfd[0];
+ oplock_pipe_write = pfd[1];
+
+ koplocks.receive_message = irix_oplock_receive_message;
+ koplocks.set_oplock = irix_set_kernel_oplock;
+ koplocks.release_oplock = irix_release_kernel_oplock;
+ koplocks.parse_message = irix_kernel_oplock_parse;
+ koplocks.msg_waiting = irix_oplock_msg_waiting;
+ koplocks.notification_fd = oplock_pipe_read;
+
+ return &koplocks;
+}
+#else
+ void oplock_irix_dummy(void) {}
+#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
diff --git a/source/smbd/oplock_linux.c b/source/smbd/oplock_linux.c
new file mode 100644
index 00000000000..3f22956aa02
--- /dev/null
+++ b/source/smbd/oplock_linux.c
@@ -0,0 +1,301 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ kernel oplock processing for Linux
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if HAVE_KERNEL_OPLOCKS_LINUX
+
+static VOLATILE sig_atomic_t signals_received;
+static VOLATILE sig_atomic_t signals_processed;
+static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */
+
+#ifndef F_SETLEASE
+#define F_SETLEASE 1024
+#endif
+
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+
+#ifndef CAP_LEASE
+#define CAP_LEASE 28
+#endif
+
+#ifndef RT_SIGNAL_LEASE
+#define RT_SIGNAL_LEASE 33
+#endif
+
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
+/****************************************************************************
+ Handle a LEASE signal, incrementing the signals_received and blocking the signal.
+****************************************************************************/
+
+static void signal_handler(int sig, siginfo_t *info, void *unused)
+{
+ BlockSignals(True, sig);
+ fd_pending = (sig_atomic_t)info->si_fd;
+ signals_received++;
+ sys_select_signal();
+}
+
+/****************************************************************************
+ Try to gain a linux capability.
+****************************************************************************/
+
+static void set_capability(unsigned capability)
+{
+#ifndef _LINUX_CAPABILITY_VERSION
+#define _LINUX_CAPABILITY_VERSION 0x19980330
+#endif
+ /* these can be removed when they are in glibc headers */
+ struct {
+ uint32 version;
+ int pid;
+ } header;
+ struct {
+ uint32 effective;
+ uint32 permitted;
+ uint32 inheritable;
+ } data;
+
+ header.version = _LINUX_CAPABILITY_VERSION;
+ header.pid = 0;
+
+ if (capget(&header, &data) == -1) {
+ DEBUG(3,("Unable to get kernel capabilities (%s)\n", strerror(errno)));
+ return;
+ }
+
+ data.effective |= (1<<capability);
+
+ if (capset(&header, &data) == -1) {
+ DEBUG(3,("Unable to set %d capability (%s)\n",
+ capability, strerror(errno)));
+ }
+}
+
+/****************************************************************************
+ Call SETLEASE. If we get EACCES then we try setting up the right capability and
+ try again
+****************************************************************************/
+
+static int linux_setlease(int fd, int leasetype)
+{
+ int ret;
+
+ if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
+ DEBUG(3,("Failed to set signal handler for kernel lease\n"));
+ return -1;
+ }
+
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ if (ret == -1 && errno == EACCES) {
+ set_capability(CAP_LEASE);
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Deal with the Linux kernel <--> smbd
+ * oplock break protocol.
+****************************************************************************/
+
+static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
+{
+ BOOL ret = True;
+ struct files_struct *fsp;
+
+ if (signals_received == signals_processed)
+ return False;
+
+ if ((fsp = file_find_fd(fd_pending)) == NULL) {
+ DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending));
+ ret = False;
+ goto out;
+ }
+
+ DEBUG(3,("receive_local_message: kernel oplock break request received for \
+dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
+
+ /*
+ * Create a kernel oplock break message.
+ */
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
+
+ buffer += OPBRK_CMD_HEADER_LEN;
+
+ SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
+
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
+
+ out:
+ /* now we can receive more signals */
+ fd_pending = (sig_atomic_t)-1;
+ signals_processed++;
+ BlockSignals(False, RT_SIGNAL_LEASE);
+
+ return ret;
+}
+
+/****************************************************************************
+ Attempt to set an kernel oplock on a file.
+****************************************************************************/
+
+static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
+{
+ if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
+ DEBUG(3,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+inode = %.0f. (%s)\n",
+ fsp->fsp_name, fsp->fd,
+ (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno)));
+ return False;
+ }
+
+ DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
+
+ return True;
+}
+
+/****************************************************************************
+ Release a kernel oplock on a file.
+****************************************************************************/
+
+static void linux_release_kernel_oplock(files_struct *fsp)
+{
+ if (DEBUGLVL(10)) {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = fcntl(fsp->fd, F_GETLEASE, 0);
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
+oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, fsp->file_id, state );
+ }
+
+ /*
+ * Remove the kernel oplock on this file.
+ */
+ if (linux_setlease(fsp->fd, F_UNLCK) == -1) {
+ if (DEBUGLVL(0)) {
+ dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+ dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, fsp->file_id, strerror(errno) );
+ }
+ }
+}
+
+/****************************************************************************
+ Parse a kernel oplock message.
+****************************************************************************/
+
+static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode,
+ SMB_DEV_T *dev, unsigned long *file_id)
+{
+ /* Ensure that the msg length is correct. */
+ if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
+ memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+ memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id));
+
+ DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)*dev, (double)*inode, *file_id));
+
+ return True;
+}
+
+/****************************************************************************
+ See if a oplock message is waiting.
+****************************************************************************/
+
+static BOOL linux_oplock_msg_waiting(fd_set *fds)
+{
+ return signals_processed != signals_received;
+}
+
+/****************************************************************************
+ See if the kernel supports oplocks.
+****************************************************************************/
+
+static BOOL linux_oplocks_available(void)
+{
+ int fd, ret;
+ fd = open("/dev/null", O_RDONLY);
+ if (fd == -1)
+ return False; /* uggh! */
+ ret = fcntl(fd, F_GETLEASE, 0);
+ close(fd);
+ return ret == F_UNLCK;
+}
+
+/****************************************************************************
+ Setup kernel oplocks.
+****************************************************************************/
+
+struct kernel_oplocks *linux_init_kernel_oplocks(void)
+{
+ static struct kernel_oplocks koplocks;
+ struct sigaction act;
+
+ if (!linux_oplocks_available()) {
+ DEBUG(3,("Linux kernel oplocks not available\n"));
+ return NULL;
+ }
+
+ act.sa_handler = NULL;
+ act.sa_sigaction = signal_handler;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
+ DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
+ return NULL;
+ }
+
+ koplocks.receive_message = linux_oplock_receive_message;
+ koplocks.set_oplock = linux_set_kernel_oplock;
+ koplocks.release_oplock = linux_release_kernel_oplock;
+ koplocks.parse_message = linux_kernel_oplock_parse;
+ koplocks.msg_waiting = linux_oplock_msg_waiting;
+ koplocks.notification_fd = -1;
+
+ DEBUG(3,("Linux kernel oplocks enabled\n"));
+
+ return &koplocks;
+}
+#else
+ void oplock_linux_dummy(void) {}
+#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 87c1fef94c5..71837efdcbd 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Password and authentication handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,1397 +20,577 @@
*/
#include "includes.h"
-#include "loadparm.h"
-
-extern int DEBUGLEVEL;
-extern int Protocol;
/* users from session setup */
static pstring session_users="";
-/* these are kept here to keep the string_combinations function simple */
-static char this_user[100]="";
-static char this_salt[100]="";
-static char this_crypted[100]="";
-
-#ifdef SMB_PASSWD
-/* Data to do lanman1/2 password challenge. */
-static unsigned char saved_challenge[8];
-static BOOL challenge_sent=False;
-
-/*******************************************************************
-Get the next challenge value - no repeats.
-********************************************************************/
-void generate_next_challenge(char *challenge)
-{
- extern void E1(char *,char *,char *);
- static int counter = 0;
- struct timeval tval;
- int v1,v2;
- GetTimeOfDay(&tval);
- v1 = (counter++) + getpid() + tval.tv_sec;
- v2 = (counter++) * getpid() + tval.tv_usec;
- SIVAL(challenge,0,v1);
- SIVAL(challenge,4,v2);
- E1(challenge,"SAMBA",saved_challenge);
- memcpy(challenge,saved_challenge,8);
- challenge_sent = True;
-}
-
-/*******************************************************************
-set the last challenge sent, usually from a password server
-********************************************************************/
-BOOL set_challenge(char *challenge)
-{
- memcpy(saved_challenge,challenge,8);
- challenge_sent = True;
- return(True);
-}
-
-/*******************************************************************
-get the last challenge sent
-********************************************************************/
-BOOL last_challenge(char *challenge)
-{
- if (!challenge_sent) return(False);
- memcpy(challenge,saved_challenge,8);
- return(True);
-}
-#endif
-
/* this holds info on user ids that are already validated for this VC */
-static user_struct *validated_users = NULL;
-static int num_validated_users = 0;
-
-/****************************************************************************
-check if a uid has been validated, and return an index if it has. -1 if not
-****************************************************************************/
-int valid_uid(int uid)
-{
- int i;
- if (uid == -1) return(-1);
-
- for (i=0;i<num_validated_users;i++)
- if (validated_users[i].uid == uid)
- {
- DEBUG(3,("valid uid %d mapped to vuid %d (user=%s)\n",
- uid,i,validated_users[i].name));
- return(i);
- }
- return(-1);
-}
+static user_struct *validated_users;
+static int next_vuid = VUID_OFFSET;
+static int num_validated_vuids;
/****************************************************************************
check if a uid has been validated, and return an pointer to the user_struct
-if it has. NULL if not
-****************************************************************************/
-user_struct *get_valid_user_struct(int uid)
-{
- int vuid = valid_uid(uid);
- if(vuid == -1 || validated_users[vuid].guest)
- return NULL;
- return &validated_users[vuid];
-}
-
-/****************************************************************************
-invalidate a uid
+if it has. NULL if not. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
-void invalidate_uid(int uid)
+user_struct *get_valid_user_struct(uint16 vuid)
{
- int i;
- for (i=0;i<num_validated_users;i++)
- if (validated_users[i].uid == uid)
- {
- user_struct *vuser = &validated_users[i];
- vuser->uid = -1;
- vuser->gid = -1;
- vuser->user_ngroups = 0;
- if(vuser->user_groups &&
- (vuser->user_groups != (gid_t *)vuser->user_igroups))
- free(vuser->user_groups);
- vuser->user_groups = NULL;
- if(vuser->user_igroups)
- free(vuser->user_igroups);
- vuser->user_igroups = NULL;
- }
-}
-
+ user_struct *usp;
+ int count=0;
+
+ if (vuid == UID_FIELD_INVALID)
+ return NULL;
+
+ for (usp=validated_users;usp;usp=usp->next,count++) {
+ if (vuid == usp->vuid) {
+ if (count > 10) {
+ DLIST_PROMOTE(validated_users, usp);
+ }
+ return usp;
+ }
+ }
-/****************************************************************************
-return a validated username
-****************************************************************************/
-char *validated_username(int vuid)
-{
- return(validated_users[vuid].name);
+ return NULL;
}
/****************************************************************************
-register a uid/name pair as being valid and that a valid password
-has been given.
+invalidate a uid
****************************************************************************/
-void register_uid(int uid,int gid, char *name,BOOL guest)
+void invalidate_vuid(uint16 vuid)
{
- user_struct *vuser;
-
- if (valid_uid(uid) >= 0)
- return;
- validated_users = (user_struct *)Realloc(validated_users,
- sizeof(user_struct)*
- (num_validated_users+1));
-
- if (!validated_users)
- {
- DEBUG(0,("Failed to realloc users struct!\n"));
- return;
- }
+ user_struct *vuser = get_valid_user_struct(vuid);
- vuser = &validated_users[num_validated_users];
- vuser->uid = uid;
- vuser->gid = gid;
- vuser->guest = guest;
- strcpy(vuser->name,name);
+ if (vuser == NULL)
+ return;
- vuser->user_ngroups = 0;
- vuser->user_groups = NULL;
- vuser->user_igroups = NULL;
+ session_yield(vuser);
- /* Find all the groups this uid is in and store them.
- Used by become_user() */
- setup_groups(name,uid,gid,
- &vuser->user_ngroups,
- &vuser->user_igroups,
- &vuser->user_groups);
+ DLIST_REMOVE(validated_users, vuser);
- DEBUG(3,("uid %d registered to name %s\n",uid,name));
-
- num_validated_users++;
+ SAFE_FREE(vuser->groups);
+ delete_nt_token(&vuser->nt_user_token);
+ SAFE_FREE(vuser);
+ num_validated_vuids--;
}
-
/****************************************************************************
-add a name to the session users list
+invalidate all vuid entries for this process
****************************************************************************/
-void add_session_user(char *user)
+void invalidate_all_vuids(void)
{
- fstring suser;
- StrnCpy(suser,user,sizeof(suser)-1);
-
- if (!Get_Pwnam(suser,True)) return;
+ user_struct *usp, *next=NULL;
- if (suser && *suser && !in_list(suser,session_users,False))
- {
- if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
- DEBUG(1,("Too many session users??\n"));
- else
- {
- strcat(session_users," ");
- strcat(session_users,suser);
+ for (usp=validated_users;usp;usp=next) {
+ next = usp->next;
+
+ invalidate_vuid(usp->vuid);
}
- }
}
-
-#ifdef NO_GETSPNAM
-/* a fake shadow password routine which just fills a fake spwd struct
- * with the sp_pwdp field. (sreiz@aie.nl)
- */
-static struct spwd *getspnam(char *username) /* fake shadow password routine */
-{
- FILE *f;
- char line[1024];
- static char pw[20];
- static struct spwd static_spwd;
-
- static_spwd.sp_pwdp=0;
- if (!(f=fopen("/etc/master.passwd", "r")))
- return 0;
- while (fgets(line, 1024, f)) {
- if (!strncmp(line, username, strlen(username)) &&
- line[strlen(username)]==':') { /* found entry */
- char *p, *q;
-
- p=line+strlen(username)+1;
- if ((q=strchr(p, ':'))) {
- *q=0;
- if (q-p+1>20)
- break;
- strcpy(pw, p);
- static_spwd.sp_pwdp=pw;
- }
- break;
- }
- }
- fclose(f);
- if (static_spwd.sp_pwdp)
- return &static_spwd;
- return 0;
-}
-#endif
-
-
-#ifdef OSF1_ENH_SEC
/****************************************************************************
-an enhanced crypt for OSF1
+return a validated username
****************************************************************************/
-static char *osf1_bigcrypt(char *password,char *salt1)
+char *validated_username(uint16 vuid)
{
- static char result[AUTH_MAX_PASSWD_LENGTH] = "";
- char *p1;
- char *p2=password;
- char salt[3];
- int i;
- int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
- if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
- parts++;
-
- StrnCpy(salt,salt1,2);
- StrnCpy(result,salt1,2);
-
- for (i=0; i<parts;i++)
- {
- p1 = crypt(p2,salt);
- strcat(result,p1+2);
- StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
- p2 += AUTH_CLEARTEXT_SEG_CHARS;
- }
-
- return(result);
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL)
+ return 0;
+ return(vuser->user.unix_name);
}
-#endif
-
/****************************************************************************
-update the enhanced security database. Only relevant for OSF1 at the moment.
+return a validated domain
****************************************************************************/
-static void update_protected_database( char *user, BOOL result)
+char *validated_domain(uint16 vuid)
{
-#ifdef OSF1_ENH_SEC
- struct pr_passwd *mypasswd;
- time_t starttime;
- long tz;
-
- mypasswd = getprpwnam (user);
- starttime = time (NULL);
- tz = mktime ( localtime ( &starttime ) );
-
- if (result)
- {
- mypasswd->ufld.fd_slogin = tz;
- mypasswd->ufld.fd_nlogins = 0;
-
- putprpwnam(user,mypasswd);
-
- DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
- }
- else
- {
- mypasswd->ufld.fd_ulogin = tz;
- mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
- if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
- {
- mypasswd->uflg.fg_lock = 0;
- DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
- }
- putprpwnam ( user , mypasswd );
- DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
- }
-#else
- DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
-#endif
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL)
+ return 0;
+ return(vuser->user.domain);
}
-#ifdef AFS_AUTH
-/*******************************************************************
-check on AFS authentication
-********************************************************************/
-static BOOL afs_auth(char *this_user,char *password)
-{
- long password_expires = 0;
- char *reason;
-
- /* For versions of AFS prior to 3.3, this routine has few arguments, */
- /* but since I can't find the old documentation... :-) */
- setpag();
- if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
- this_user,
- (char *) 0, /* instance */
- (char *) 0, /* cell */
- password,
- 0, /* lifetime, default */
- &password_expires, /*days 'til it expires */
- 0, /* spare 2 */
- &reason) == 0)
- return(True);
- return(False);
-}
-#endif
-
-
-#ifdef DFS_AUTH
-
-sec_login_handle_t my_dce_sec_context;
-int dcelogin_atmost_once = 0;
-
-/*******************************************************************
-check on a DCE/DFS authentication
-********************************************************************/
-static BOOL dfs_auth(char *this_user,char *password)
-{
- error_status_t err;
- int err2;
- int prterr;
- boolean32 password_reset;
- sec_passwd_rec_t my_dce_password;
- sec_login_auth_src_t auth_src = sec_login_auth_src_network;
- unsigned char dce_errstr[dce_c_error_string_len];
-
- /*
- * We only go for a DCE login context if the given password
- * matches that stored in the local password file..
- * Assumes local passwd file is kept in sync w/ DCE RGY!
- */
-
- if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
- dcelogin_atmost_once)
- return(False);
-
- if (sec_login_setup_identity(
- (unsigned char *)this_user,
- sec_login_no_flags,
- &my_dce_sec_context,
- &err) == 0)
- {
- dce_error_inq_text(err, dce_errstr, &err2);
- DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
- this_user,dce_errstr));
- return(False);
- }
-
- my_dce_password.version_number = sec_passwd_c_version_none;
- my_dce_password.pepper = NULL;
- my_dce_password.key.key_type = sec_passwd_plain;
- my_dce_password.key.tagged_union.plain = (idl_char *)password;
-
- if (sec_login_valid_and_cert_ident(my_dce_sec_context,
- &my_dce_password,
- &password_reset,
- &auth_src,
- &err) == 0 )
- {
- dce_error_inq_text(err, dce_errstr, &err2);
- DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
- this_user,dce_errstr));
-
- return(False);
- }
-
- sec_login_set_context(my_dce_sec_context, &err);
- if (err != error_status_ok )
- {
- dce_error_inq_text(err, dce_errstr, &err2);
- DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
- this_user,dce_errstr));
- sec_login_purge_context(my_dce_sec_context, &err);
- return(False);
- }
- else
- {
- DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
- this_user, getpid()));
- }
-
- dcelogin_atmost_once = 1;
- return (True);
-}
-
-void dfs_unlogin(void)
-{
- error_status_t err;
- int err2;
- unsigned char dce_errstr[dce_c_error_string_len];
-
- sec_login_purge_context(my_dce_sec_context, &err);
- if (err != error_status_ok )
- {
- dce_error_inq_text(err, dce_errstr, &err2);
- DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
- getpid(), dce_errstr));
- }
-}
-
-#endif
-
-
-#ifdef LINUX_BIGCRYPT
/****************************************************************************
-an enhanced crypt for Linux to handle password longer than 8 characters
+ Create the SID list for this user.
****************************************************************************/
-static int linux_bigcrypt(char *password,char *salt1, char *crypted)
+
+NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok)
{
-#define LINUX_PASSWORD_SEG_CHARS 8
- char salt[3];
- int i;
-
- StrnCpy(salt,salt1,2);
- crypted +=2;
-
- for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
- char * p = crypt(password,salt) + 2;
- if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
- return(0);
- password += LINUX_PASSWORD_SEG_CHARS;
- crypted += strlen(p);
- }
-
- return(1);
-}
-#endif
+ extern DOM_SID global_sid_World;
+ extern DOM_SID global_sid_Network;
+ extern DOM_SID global_sid_Builtin_Guests;
+ extern DOM_SID global_sid_Authenticated_Users;
+ NT_USER_TOKEN *token;
+ DOM_SID *psids;
+ int i, psid_ndx = 0;
+ size_t num_sids = 0;
+ fstring sid_str;
+
+ if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL)
+ return NULL;
+
+ ZERO_STRUCTP(token);
+
+ /* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */
+ num_sids = 5 + ngroups;
+
+ if (sup_tok && sup_tok->num_sids)
+ num_sids += sup_tok->num_sids;
+
+ if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) {
+ SAFE_FREE(token);
+ return NULL;
+ }
+ psids = token->user_sids;
-/****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
-****************************************************************************/
-static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
-{
- int len = strlen(s);
- int i;
+ /*
+ * Note - user SID *MUST* be first in token !
+ * se_access_check depends on this.
+ */
-#ifdef PASSWORD_LENGTH
- len = MIN(len,PASSWORD_LENGTH);
-#endif
+ uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid);
+ psid_ndx++;
- if (N <= 0 || offset >= len)
- return(fn(s));
-
- for (i=offset;i<(len-(N-1));i++)
- {
- char c = s[i];
- if (!islower(c)) continue;
- s[i] = toupper(c);
- if (string_combinations2(s,i+1,fn,N-1))
- return(True);
- s[i] = c;
- }
- return(False);
-}
+ /*
+ * Primary group SID is second in token. Convention.
+ */
-/****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with up to N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
-****************************************************************************/
-static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
-{
- int n;
- for (n=1;n<=N;n++)
- if (string_combinations2(s,0,fn,n)) return(True);
- return(False);
-}
+ gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid);
+ psid_ndx++;
+ /* Now add the group SIDs. */
+ for (i = 0; i < ngroups; i++) {
+ if (groups[i] != gid) {
+ gid_to_sid( &psids[psid_ndx++], groups[i]);
+ }
+ }
-/****************************************************************************
-core of password checking routine
-****************************************************************************/
-BOOL password_check(char *password)
-{
-#ifdef AFS_AUTH
- if (afs_auth(this_user,password)) return(True);
-#endif
+ if (sup_tok) {
+ /* Now add the additional SIDs from the supplimentary token. */
+ for (i = 0; i < sup_tok->num_sids; i++)
+ sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] );
+ }
-#ifdef DFS_AUTH
- if (dfs_auth(this_user,password)) return(True);
-#endif
+ /*
+ * Finally add the "standard" SIDs.
+ * The only difference between guest and "anonymous" (which we
+ * don't really support) is the addition of Authenticated_Users.
+ */
-#ifdef PWDAUTH
- if (pwdauth(this_user,password) == 0)
- return(True);
-#endif
+ sid_copy( &psids[psid_ndx++], &global_sid_World);
+ sid_copy( &psids[psid_ndx++], &global_sid_Network);
-#ifdef OSF1_ENH_SEC
- return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
-#endif
+ if (is_guest)
+ sid_copy( &psids[psid_ndx++], &global_sid_Builtin_Guests);
+ else
+ sid_copy( &psids[psid_ndx++], &global_sid_Authenticated_Users);
-#ifdef ULTRIX_AUTH
- return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
-#endif
+ token->num_sids = psid_ndx;
-#ifdef LINUX_BIGCRYPT
- return(linux_bigcrypt(password,this_salt,this_crypted));
-#endif
+ /* Dump list of sids in token */
-#ifdef NO_CRYPT
- DEBUG(1,("Warning - no crypt available\n"));
- return(False);
-#else
- return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
-#endif
-}
+ for (i = 0; i < token->num_sids; i++) {
+ DEBUG(5, ("user token sid %s\n",
+ sid_to_string(sid_str, &token->user_sids[i])));
+ }
-#ifdef SMB_PASSWD
-/****************************************************************************
-core of smb password checking routine.
-****************************************************************************/
-BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
-{
- /* Finish the encryption of part_passwd. */
- unsigned char p21[21];
- unsigned char p24[24];
-
- if(part_passwd == NULL)
- DEBUG(10,("No password set - allowing access\n"));
- /* No password set - always true ! */
- if(part_passwd == NULL)
- return 1;
-
- memset(p21,'\0',21);
- memcpy(p21,part_passwd,16);
- E_P24(p21, c8, p24);
-#if DEBUG_PASSWORD
- {
- int i;
- DEBUG(100,("Part password (P16) was |"));
- for(i = 0; i < 16; i++)
- DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Password from client was |"));
- for(i = 0; i < 24; i++)
- DEBUG(100,("%X ", (unsigned char)password[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Given challenge was |"));
- for(i = 0; i < 8; i++)
- DEBUG(100,("%X ", (unsigned char)c8[i]));
- DEBUG(100,("|\n"));
- DEBUG(100,("Value from encryption was |"));
- for(i = 0; i < 24; i++)
- DEBUG(100,("%X ", (unsigned char)p24[i]));
- DEBUG(100,("|\n"));
- }
-#endif
- return (memcmp(p24, password, 24) == 0);
+ return token;
}
-#endif
/****************************************************************************
-check if a username/password is OK
+register a uid/name pair as being valid and that a valid password
+has been given. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
-BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password)
-{
- pstring pass2;
- int level = lp_passwordlevel();
- struct passwd *pass;
-#ifdef SMB_PASSWD
- char challenge[8];
- struct smb_passwd *smb_pass;
- BOOL challenge_done = False;
-#endif
-
- if (password) password[pwlen] = 0;
-#ifdef SMB_PASSWD
- if (pwlen == 24)
- challenge_done = last_challenge(challenge);
-#endif
-
-#if DEBUG_PASSWORD
-#ifdef SMB_PASSWD
- if (challenge_done)
- {
- int i;
- DEBUG(100,("checking user=[%s] pass=[",user));
- for( i = 0; i < 24; i++)
- DEBUG(100,("%0x ", (unsigned char)password[i]));
- DEBUG(100,("]\n"));
- }
- else
-#endif
- DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
-#endif
-
- if (!password)
- return(False);
-
- if (((!*password) || (!pwlen)) && !lp_null_passwords())
- return(False);
-
- if (pwd && !user)
- {
- pass = (struct passwd *) pwd;
- user = pass->pw_name;
- }
- else
- pass = Get_Pwnam(user,True);
+int register_vuid(auth_serversupplied_info *server_info, char *smb_name)
+{
+ user_struct *vuser = NULL;
+ uid_t *puid;
+ gid_t *pgid;
-#ifdef SMB_PASSWD
+ /* Ensure no vuid gets registered in share level security. */
+ if(lp_security() == SEC_SHARE)
+ return UID_FIELD_INVALID;
- DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
+ /* Limit allowed vuids to 16bits - VUID_OFFSET. */
+ if (num_validated_vuids >= 0xFFFF-VUID_OFFSET)
+ return UID_FIELD_INVALID;
- if((pwlen == 24) && challenge_done)
- {
- DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
-
- if (!pass)
- {
- DEBUG(3,("Couldn't find user %s\n",user));
- return(False);
+ if((vuser = (user_struct *)malloc( sizeof(user_struct) )) == NULL) {
+ DEBUG(0,("Failed to malloc users struct!\n"));
+ return UID_FIELD_INVALID;
}
- smb_pass = get_smbpwnam(user);
- if(!smb_pass)
- {
- DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
- return(False);
- }
+ ZERO_STRUCTP(vuser);
- /* Ensure the uid's match */
- if(smb_pass->smb_userid != pass->pw_uid)
- {
- DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
- return(False);
- }
+ puid = pdb_get_uid(server_info->sam_account);
+ pgid = pdb_get_gid(server_info->sam_account);
- if(Protocol >= PROTOCOL_NT1 && is_nt_password)
- {
- /* We have the NT MD4 hash challenge available - see if we can
- use it (ie. does it exist in the smbpasswd file).
- */
- if(smb_pass->smb_nt_passwd != NULL)
- {
- DEBUG(4,("Checking NT MD4 password\n"));
- if(smb_password_check(password, smb_pass->smb_nt_passwd, challenge))
- {
- update_protected_database(user,True);
- return(True);
- }
- DEBUG(4,("NT MD4 password check failed\n"));
- return (False);
- }
+ if (!puid || !pgid) {
+ DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT\n"));
+ free(vuser);
+ return UID_FIELD_INVALID;
}
- /* Try against the lanman password */
-
- if(smb_password_check(password, smb_pass->smb_passwd, challenge))
- {
- update_protected_database(user,True);
- return(True);
+ /* Allocate a free vuid. Yes this is a linear search... :-) */
+ while( get_valid_user_struct(next_vuid) != NULL ) {
+ next_vuid++;
+ /* Check for vuid wrap. */
+ if (next_vuid == UID_FIELD_INVALID)
+ next_vuid = VUID_OFFSET;
}
- DEBUG(3,("Error smb_password_check failed\n"));
- }
-#endif
+ DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid ));
- DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
+ vuser->vuid = next_vuid;
+ vuser->uid = *puid;
+ vuser->gid = *pgid;
+ vuser->guest = server_info->guest;
+ fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account));
+ fstrcpy(vuser->user.smb_name, smb_name);
+ fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
+ fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account));
- if (!pass)
- {
- DEBUG(3,("Couldn't find user %s\n",user));
- return(False);
- }
-
-#ifdef SHADOW_PWD
- {
- struct spwd *spass;
-
- /* many shadow systems require you to be root to get the password,
- in most cases this should already be the case when this
- function is called, except perhaps for IPC password changing
- requests */
+ DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n",
+ (unsigned int)vuser->uid,
+ (unsigned int)vuser->gid,
+ vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest ));
- spass = getspnam(pass->pw_name);
- if (spass && spass->sp_pwdp)
- pass->pw_passwd = spass->sp_pwdp;
- }
-#endif
+ DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name));
-#ifdef SecureWare
- {
- struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
- if (pr_pw && pr_pw->ufld.fd_encrypt)
- pass->pw_passwd = pr_pw->ufld.fd_encrypt;
- }
-#endif
+ vuser->n_groups = 0;
+ vuser->groups = NULL;
-#ifdef HPUX_10_TRUSTED
- {
- struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
- if (pr_pw && pr_pw->ufld.fd_encrypt)
- pass->pw_passwd = pr_pw->ufld.fd_encrypt;
- }
-#endif
+ /* Find all the groups this uid is in and store them.
+ Used by change_to_user() */
+ initialise_groups(vuser->user.unix_name, vuser->uid, vuser->gid);
+ get_current_groups( &vuser->n_groups, &vuser->groups);
-#ifdef OSF1_ENH_SEC
- {
- struct pr_passwd *mypasswd;
- DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
- mypasswd = getprpwnam (user);
- if ( mypasswd )
- {
- strcpy(pass->pw_name,mypasswd->ufld.fd_name);
- strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
- }
- else
- {
- DEBUG(5,("No entry for user %s in protected database !\n",user));
- return(False);
- }
- }
-#endif
-
-#ifdef ULTRIX_AUTH
- {
- AUTHORIZATION *ap = getauthuid( pass->pw_uid );
- if (ap)
- {
- strcpy( pass->pw_passwd, ap->a_password );
- endauthent();
- }
- }
-#endif
-
- /* extract relevant info */
- strcpy(this_user,pass->pw_name);
- strcpy(this_salt,pass->pw_passwd);
- strcpy(this_crypted,pass->pw_passwd);
-
- if (!*this_crypted) {
- if (!lp_null_passwords()) {
- DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
- return(False);
- }
-#ifndef PWDAUTH
- if (!*password) {
- DEBUG(3,("Allowing access to %s with null password\n",this_user));
- return(True);
- }
-#endif
- }
-
- /* try it as it came to us */
- if (password_check(password))
- {
- update_protected_database(user,True);
- return(True);
- }
-
- /* if the password was given to us with mixed case then we don't
- need to proceed as we know it hasn't been case modified by the
- client */
- if (strhasupper(password) && strhaslower(password))
- return(False);
-
- /* make a copy of it */
- StrnCpy(pass2,password,sizeof(pstring)-1);
-
- /* try all lowercase */
- strlower(password);
- if (password_check(password))
- {
- update_protected_database(user,True);
- return(True);
- }
+ if (server_info->ptok)
+ add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, &server_info->ptok);
- /* give up? */
- if(level < 1)
- {
- update_protected_database(user,False);
+ /* Create an NT_USER_TOKEN struct for this user. */
+ vuser->nt_user_token = create_nt_token(vuser->uid, vuser->gid, vuser->n_groups, vuser->groups, vuser->guest, server_info->ptok);
- /* restore it */
- strcpy(password,pass2);
+ DEBUG(3,("uid %d registered to name %s\n",(int)vuser->uid,vuser->user.unix_name));
- return(False);
- }
+ next_vuid++;
+ num_validated_vuids++;
- /* last chance - all combinations of up to level chars upper! */
- strlower(password);
+ DLIST_ADD(validated_users, vuser);
- if (string_combinations(password,password_check,level))
- {
- update_protected_database(user,True);
- return(True);
- }
+ if (!session_claim(vuser)) {
+ DEBUG(1,("Failed to claim session for vuid=%d\n", vuser->vuid));
+ invalidate_vuid(vuser->vuid);
+ return -1;
+ }
- update_protected_database(user,False);
-
- /* restore it */
- strcpy(password,pass2);
-
- return(False);
+ return vuser->vuid;
}
-
/****************************************************************************
-check if a username is valid
+add a name to the session users list
****************************************************************************/
-BOOL user_ok(char *user,int snum)
+void add_session_user(char *user)
{
- pstring valid, invalid;
- BOOL ret;
-
- StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
- StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
-
- string_sub(valid,"%S",lp_servicename(snum));
- string_sub(invalid,"%S",lp_servicename(snum));
-
- ret = !user_in_list(user,invalid);
-
- if (ret && valid && *valid)
- ret = user_in_list(user,valid);
-
- if (ret && lp_onlyuser(snum)) {
- char *user_list = lp_username(snum);
- string_sub(user_list,"%S",lp_servicename(snum));
- ret = user_in_list(user,user_list);
- }
-
- return(ret);
-}
-
-
+ fstring suser;
+ StrnCpy(suser,user,sizeof(suser)-1);
+ if (!Get_Pwnam_Modify(suser)) return;
-/****************************************************************************
-validate a group username entry. Return the username or NULL
-****************************************************************************/
-static char *validate_group(char *group,char *password,int pwlen,int snum)
-{
-#ifdef NETGROUP
- {
- char *host, *user, *domain;
- setnetgrent(group);
- while (getnetgrent(&host, &user, &domain)) {
- if (user) {
- if (user_ok(user, snum) &&
- password_ok(user,password,pwlen,NULL,False)) {
- endnetgrent();
- return(user);
- }
- }
- }
- endnetgrent();
- }
-#endif
-
-#if HAVE_GETGRNAM
- {
- struct group *gptr = (struct group *)getgrnam(group);
- char **member;
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- static fstring name;
- strcpy(name,*member);
- if (user_ok(name,snum) &&
- password_ok(name,password,pwlen,NULL,False))
- return(&name[0]);
- member++;
- }
-#ifdef GROUP_CHECK_PWENT
+ if (suser && *suser && !in_list(suser,session_users,False))
+ {
+ if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
+ DEBUG(1,("Too many session users??\n"));
+ else
{
- struct passwd *pwd;
- static fstring tm;
-
- setpwent ();
- while (pwd = getpwent ()) {
- if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
- /* This Entry have PASSWORD and same GID then check pwd */
- if (password_ok(NULL, password, pwlen, pwd,False)) {
- strcpy(tm, pwd->pw_name);
- endpwent ();
- return tm;
- }
- }
- }
- endpwent ();
+ pstrcat(session_users," ");
+ pstrcat(session_users,suser);
}
-#endif /* GROUP_CHECK_PWENT */
- }
- }
-#endif
- return(NULL);
+ }
}
-
/****************************************************************************
-check for authority to login to a service with a given username/password
+check if a username is valid
****************************************************************************/
-BOOL authorise_login(int snum,char *user,char *password, int pwlen,
- BOOL *guest,BOOL *force,int vuid)
+BOOL user_ok(char *user,int snum)
{
- BOOL ok = False;
-
- *guest = False;
-
-#if DEBUG_PASSWORD
- DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
-#endif
-
- /* there are several possabilities:
- 1) login as the given user with given password
- 2) login as a previously registered username with the given password
- 3) login as a session list username with the given password
- 4) login as a previously validated user/password pair
- 5) login as the "user =" user with given password
- 6) login as the "user =" user with no password (guest connection)
- 7) login as guest user with no password
+ char **valid, **invalid;
+ BOOL ret;
- if the service is guest_only then steps 1 to 5 are skipped
- */
+ valid = invalid = NULL;
+ ret = True;
- if (GUEST_ONLY(snum)) *force = True;
-
- if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
- {
-
- /* check the given username and password */
- if (!ok && (*user) && user_ok(user,snum)) {
- ok = password_ok(user,password, pwlen, NULL, False);
- if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
- }
-
- /* check for a previously registered guest username */
- if (!ok && (vuid >= 0) && validated_users[vuid].guest) {
- if (user_ok(validated_users[vuid].name,snum) &&
- password_ok(validated_users[vuid].name, password, pwlen, NULL, False)) {
- strcpy(user, validated_users[vuid].name);
- validated_users[vuid].guest = False;
- DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
- ok = True;
+ if (lp_invalid_users(snum)) {
+ lp_list_copy(&invalid, lp_invalid_users(snum));
+ if (invalid && lp_list_substitute(invalid, "%S", lp_servicename(snum))) {
+ ret = !user_in_list(user, invalid);
+ }
}
- }
-
+ if (invalid) lp_list_free (&invalid);
- /* now check the list of session users */
- if (!ok)
- {
- char *auser;
- char *user_list = strdup(session_users);
- if (!user_list) return(False);
-
- for (auser=strtok(user_list,LIST_SEP);
- !ok && auser;
- auser = strtok(NULL,LIST_SEP))
- {
- fstring user2;
- strcpy(user2,auser);
- if (!user_ok(user2,snum)) continue;
-
- if (password_ok(user2,password, pwlen, NULL, False)) {
- ok = True;
- strcpy(user,user2);
- DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
- }
- }
- free(user_list);
+ if (ret && lp_valid_users(snum)) {
+ lp_list_copy(&valid, lp_valid_users(snum));
+ if (valid && lp_list_substitute(valid, "%S", lp_servicename(snum))) {
+ ret = user_in_list(user,valid);
+ }
}
+ if (valid) lp_list_free (&valid);
- /* check for a previously validated username/password pair */
- if (!ok && !lp_revalidate(snum) &&
- (vuid >= 0) && !validated_users[vuid].guest &&
- user_ok(validated_users[vuid].name,snum)) {
- strcpy(user,validated_users[vuid].name);
- *guest = False;
- DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
- ok = True;
- }
-
- /* check for a rhosts entry */
- if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
- ok = True;
- DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
- }
-
- /* check the user= fields and the given password */
- if (!ok && lp_username(snum)) {
- char *auser;
- pstring user_list;
- StrnCpy(user_list,lp_username(snum),sizeof(pstring));
-
- string_sub(user_list,"%S",lp_servicename(snum));
-
- for (auser=strtok(user_list,LIST_SEP);
- auser && !ok;
- auser = strtok(NULL,LIST_SEP))
- {
- if (*auser == '@')
- {
- auser = validate_group(auser+1,password,pwlen,snum);
- if (auser)
- {
- ok = True;
- strcpy(user,auser);
- DEBUG(3,("ACCEPTED: group username and given password ok\n"));
- }
- }
- else
- {
- fstring user2;
- strcpy(user2,auser);
- if (user_ok(user2,snum) &&
- password_ok(user2,password,pwlen,NULL, False))
- {
- ok = True;
- strcpy(user,user2);
- DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
- }
- }
- }
- }
- } /* not guest only */
-
- /* check for a normal guest connection */
- if (!ok && GUEST_OK(snum))
- {
- fstring guestname;
- StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
- if (Get_Pwnam(guestname,True))
- {
- strcpy(user,guestname);
- ok = True;
- DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
+ if (ret && lp_onlyuser(snum)) {
+ char **user_list = lp_list_make (lp_username(snum));
+ if (user_list && lp_list_substitute(user_list, "%S", lp_servicename(snum))) {
+ ret = user_in_list(user, user_list);
+ }
+ if (user_list) lp_list_free (&user_list);
}
- else
- DEBUG(0,("Invalid guest account %s??\n",guestname));
- *guest = True;
- *force = True;
- }
- if (ok && !user_ok(user,snum))
- {
- DEBUG(0,("rejected invalid user %s\n",user));
- ok = False;
- }
-
- return(ok);
+ return(ret);
}
-
/****************************************************************************
-read the a hosts.equiv or .rhosts file and check if it
-allows this user from this machine
+validate a group username entry. Return the username or NULL
****************************************************************************/
-static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
+static char *validate_group(char *group, DATA_BLOB password,int snum)
{
- pstring buf;
- int plus_allowed = 1;
- char *file_host;
- char *file_user;
- FILE *fp = fopen(equiv_file, "r");
- DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
- if (! fp) return False;
- while(fgets(buf, sizeof(buf), fp))
- {
- trim_string(buf," "," ");
-
- if (buf[0] != '#' && buf[0] != '\n')
- {
- BOOL is_group = False;
- int plus = 1;
- char *bp = buf;
- if (strcmp(buf, "NO_PLUS\n") == 0)
- {
- DEBUG(6, ("check_user_equiv NO_PLUS\n"));
- plus_allowed = 0;
- }
- else {
- if (buf[0] == '+')
+#ifdef HAVE_NETGROUP
{
- bp++;
- if (*bp == '\n' && plus_allowed)
- {
- /* a bare plus means everbody allowed */
- DEBUG(6, ("check_user_equiv everybody allowed\n"));
- fclose(fp);
- return True;
- }
- }
- else if (buf[0] == '-')
- {
- bp++;
- plus = 0;
- }
- if (*bp == '@')
- {
- is_group = True;
- bp++;
+ char *host, *user, *domain;
+ setnetgrent(group);
+ while (getnetgrent(&host, &user, &domain)) {
+ if (user) {
+ if (user_ok(user, snum) &&
+ password_ok(user,password)) {
+ endnetgrent();
+ return(user);
+ }
+ }
+ }
+ endnetgrent();
}
- file_host = strtok(bp, " \t\n");
- file_user = strtok(NULL, " \t\n");
- DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
- if (file_host && *file_host)
- {
- BOOL host_ok = False;
-
-#ifdef NETGROUP
- /* THIS IS UNTESTED!! */
- if (is_group)
- {
- static char *mydomain = NULL;
- if (!mydomain)
- yp_get_default_domain(&mydomain);
- if (mydomain && innetgr(remote,file_host,user,mydomain))
- host_ok = True;
- }
-#else
- if (is_group)
- {
- DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
- continue;
- }
#endif
-
- /* is it this host */
- /* the fact that remote has come from a call of gethostbyaddr
- * means that it may have the fully qualified domain name
- * so we could look up the file version to get it into
- * a canonical form, but I would rather just type it
- * in full in the equiv file
- */
- if (!host_ok && !is_group && strequal(remote, file_host))
- host_ok = True;
-
- if (!host_ok)
- continue;
-
- /* is it this user */
- if (file_user == 0 || strequal(user, file_user))
- {
- fclose(fp);
- DEBUG(5, ("check_user_equiv matched %s%s %s\n",
- (plus ? "+" : "-"), file_host,
- (file_user ? file_user : "")));
- return (plus ? True : False);
- }
- }
- }
- }
- }
- fclose(fp);
- return False;
-}
-
-
-/****************************************************************************
-check for a possible hosts equiv or rhosts entry for the user
-****************************************************************************/
-BOOL check_hosts_equiv(char *user)
-{
- char *fname = NULL;
- pstring rhostsfile;
- struct passwd *pass = Get_Pwnam(user,True);
-
- extern struct from_host Client_info;
- extern int Client;
-
- if (!pass)
- return(False);
-
- fromhost(Client,&Client_info);
-
- fname = lp_hosts_equiv();
-
- /* note: don't allow hosts.equiv on root */
- if (fname && *fname && (pass->pw_uid != 0))
- {
- if (check_user_equiv(user,Client_info.name,fname))
- return(True);
- }
- if (lp_use_rhosts())
- {
- char *home = get_home_dir(user);
- if (home)
+#ifdef HAVE_GETGRENT
{
- sprintf(rhostsfile, "%s/.rhosts", home);
- if (check_user_equiv(user,Client_info.name,rhostsfile))
- return(True);
- }
- }
+ struct group *gptr;
+ setgrent();
+ while ((gptr = (struct group *)getgrent())) {
+ if (strequal(gptr->gr_name,group))
+ break;
+ }
- return(False);
+ /*
+ * As user_ok can recurse doing a getgrent(), we must
+ * copy the member list into a pstring on the stack before
+ * use. Bug pointed out by leon@eatworms.swmed.edu.
+ */
+
+ if (gptr) {
+ pstring member_list;
+ char *member;
+ size_t copied_len = 0;
+ int i;
+
+ *member_list = '\0';
+ member = member_list;
+
+ for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) {
+ size_t member_len = strlen(gptr->gr_mem[i]) + 1;
+ if( copied_len + member_len < sizeof(pstring)) {
+
+ DEBUG(10,("validate_group: = gr_mem = %s\n", gptr->gr_mem[i]));
+
+ safe_strcpy(member, gptr->gr_mem[i], sizeof(pstring) - copied_len - 1);
+ copied_len += member_len;
+ member += copied_len;
+ } else {
+ *member = '\0';
+ }
+ }
+
+ endgrent();
+
+ member = member_list;
+ while (*member) {
+ static fstring name;
+ fstrcpy(name,member);
+ if (user_ok(name,snum) &&
+ password_ok(name,password)) {
+ endgrent();
+ return(&name[0]);
+ }
+
+ DEBUG(10,("validate_group = member = %s\n", member));
+
+ member += strlen(member) + 1;
+ }
+ } else {
+ endgrent();
+ return NULL;
+ }
+ }
+#endif
+ return(NULL);
}
-
-static int password_client = -1;
-static fstring pserver;
-
/****************************************************************************
-attempted support for server level security
+ Check for authority to login to a service with a given username/password.
+ Note this is *NOT* used when logging on using sessionsetup_and_X.
****************************************************************************/
-BOOL server_cryptkey(char *buf)
-{
- pstring inbuf,outbuf;
- fstring pass_protocol;
- extern fstring remote_machine;
- char *p;
- int len;
- fstring desthost;
- struct in_addr dest_ip;
- extern struct in_addr myip;
- int port = 139;
- BOOL ret;
-
- if (password_client >= 0)
- close(password_client);
- password_client = -1;
-
- if (Protocol < PROTOCOL_NT1) {
- strcpy(pass_protocol,"LM1.2X002");
- } else {
- strcpy(pass_protocol,"NT LM 0.12");
- }
-
- bzero(inbuf,sizeof(inbuf));
- bzero(outbuf,sizeof(outbuf));
-
- for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
- strcpy(desthost,p);
- standard_sub_basic(desthost);
- strupper(desthost);
-
- dest_ip = *interpret_addr2(desthost);
- if (zero_ip(dest_ip)) {
- DEBUG(1,("Can't resolve address for %s\n",p));
- continue;
- }
- if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
- DEBUG(1,("Password server loop - disabling password server %s\n",p));
- continue;
- }
-
- password_client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (password_client >= 0) {
- DEBUG(3,("connected to password server %s\n",p));
- StrnCpy(pserver,p,sizeof(pserver)-1);
- break;
- }
- }
-
- if (password_client < 0) {
- DEBUG(1,("password server not available\n"));
- return(False);
- }
+BOOL authorise_login(int snum,char *user, DATA_BLOB password,
+ BOOL *guest,BOOL *force,uint16 vuid)
+{
+ BOOL ok = False;
+ user_struct *vuser = get_valid_user_struct(vuid);
+#if DEBUG_PASSWORD
+ DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s vuid=%d\n",
+ user,password.data, vuid));
+#endif
- /* send a session request (RFC 8002) */
+ *guest = False;
+
+ if (GUEST_ONLY(snum))
+ *force = True;
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(desthost,p,' ');
- len += name_len(p);
+ if (!GUEST_ONLY(snum) && (lp_security() > SEC_SHARE)) {
- /* and my name */
- p = outbuf+len;
- name_mangle(remote_machine,p,' ');
- len += name_len(p);
+ /*
+ * We should just use the given vuid from a sessionsetup_and_X.
+ */
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
+ if (!vuser) {
+ DEBUG(1,("authorise_login: refusing user '%s' with no session setup\n", user));
+ return False;
+ }
- send_smb(password_client,outbuf);
- receive_smb(password_client,inbuf,5000);
+ if ((!vuser->guest && user_ok(vuser->user.unix_name,snum)) ||
+ (vuser->guest && GUEST_OK(snum))) {
+ fstrcpy(user,vuser->user.unix_name);
+ *guest = vuser->guest;
+ DEBUG(3,("authorise_login: ACCEPTED: validated based on vuid as %sguest \
+(user=%s)\n", vuser->guest ? "" : "non-", user));
+ return True;
+ }
+ }
- if (CVAL(inbuf,0) != 0x82) {
- DEBUG(1,("%s rejected the session\n",pserver));
- close(password_client); password_client = -1;
- return(False);
- }
-
- DEBUG(3,("got session\n"));
-
- bzero(outbuf,smb_size);
-
- /* setup the protocol string */
- set_message(outbuf,0,strlen(pass_protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,pass_protocol);
-
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
-
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
-
- if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
- DEBUG(1,("%s rejected the protocol\n",pserver));
- close(password_client); password_client= -1;
- return(False);
- }
-
- if (!(CVAL(inbuf,smb_vwv1) & 1)) {
- DEBUG(1,("%s isn't in user level security mode\n",pserver));
- close(password_client); password_client= -1;
- return(False);
- }
-
- memcpy(buf,inbuf,smb_len(inbuf)+4);
-
- DEBUG(3,("password server OK\n"));
-
- return(True);
-}
-
-/****************************************************************************
-attempted support for server level security
-****************************************************************************/
-BOOL server_validate(char *buf)
-{
- pstring inbuf,outbuf;
- BOOL ret;
-
- if (password_client < 0) {
- DEBUG(1,("%s not connected\n",pserver));
- return(False);
- }
-
- bzero(inbuf,sizeof(inbuf));
- memcpy(outbuf,buf,sizeof(outbuf));
-
- /* send a session setup command */
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
- CVAL(outbuf,smb_vwv0) = 0xFF;
-
- set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
-
- SCVAL(inbuf,smb_rcls,1);
+ /* there are several possibilities:
+ 1) login as the given user with given password
+ 2) login as a previously registered username with the given password
+ 3) login as a session list username with the given password
+ 4) login as a previously validated user/password pair
+ 5) login as the "user =" user with given password
+ 6) login as the "user =" user with no password (guest connection)
+ 7) login as guest user with no password
+
+ if the service is guest_only then steps 1 to 5 are skipped
+ */
+
+ if (!(GUEST_ONLY(snum) && GUEST_OK(snum))) {
+ /* check for a previously registered guest username */
+ if (!ok && (vuser != 0) && vuser->guest) {
+ if (user_ok(vuser->user.unix_name,snum) &&
+ password_ok(vuser->user.unix_name, password)) {
+ fstrcpy(user, vuser->user.unix_name);
+ *guest = False;
+ DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user));
+ ok = True;
+ }
+ }
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
+ /* now check the list of session users */
+ if (!ok) {
+ char *auser;
+ char *user_list = strdup(session_users);
+ if (!user_list)
+ return(False);
+
+ for (auser=strtok(user_list,LIST_SEP); !ok && auser;
+ auser = strtok(NULL,LIST_SEP)) {
+ fstring user2;
+ fstrcpy(user2,auser);
+ if (!user_ok(user2,snum))
+ continue;
+
+ if (password_ok(user2,password)) {
+ ok = True;
+ fstrcpy(user,user2);
+ DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \
+and given password ok\n", user));
+ }
+ }
+
+ SAFE_FREE(user_list);
+ }
- if (!ret || CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(1,("password server %s rejected the password\n",pserver));
- return(False);
- }
+ /* check for a previously validated username/password pair */
+ if (!ok && (lp_security() > SEC_SHARE) && (vuser != 0) && !vuser->guest &&
+ user_ok(vuser->user.unix_name,snum)) {
+ fstrcpy(user,vuser->user.unix_name);
+ *guest = False;
+ DEBUG(3,("authorise_login: ACCEPTED: validated uid (%s) as non-guest\n",
+ user));
+ ok = True;
+ }
- /* if logged in as guest then reject */
- if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
- DEBUG(1,("password server %s gave us guest only\n",pserver));
- return(False);
- }
+ /* check the user= fields and the given password */
+ if (!ok && lp_username(snum)) {
+ char *auser;
+ pstring user_list;
+ StrnCpy(user_list,lp_username(snum),sizeof(pstring));
- DEBUG(3,("password server %s accepted the password\n",pserver));
+ pstring_sub(user_list,"%S",lp_servicename(snum));
+
+ for (auser=strtok(user_list,LIST_SEP); auser && !ok;
+ auser = strtok(NULL,LIST_SEP)) {
+ if (*auser == '@') {
+ auser = validate_group(auser+1,password,snum);
+ if (auser) {
+ ok = True;
+ fstrcpy(user,auser);
+ DEBUG(3,("authorise_login: ACCEPTED: group username \
+and given password ok (%s)\n", user));
+ }
+ } else {
+ fstring user2;
+ fstrcpy(user2,auser);
+ if (user_ok(user2,snum) && password_ok(user2,password)) {
+ ok = True;
+ fstrcpy(user,user2);
+ DEBUG(3,("authorise_login: ACCEPTED: user list username \
+and given password ok (%s)\n", user));
+ }
+ }
+ }
+ }
+ } /* not guest only */
+
+ /* check for a normal guest connection */
+ if (!ok && GUEST_OK(snum)) {
+ fstring guestname;
+ StrnCpy(guestname,lp_guestaccount(),sizeof(guestname)-1);
+ if (Get_Pwnam(guestname)) {
+ fstrcpy(user,guestname);
+ ok = True;
+ DEBUG(3,("authorise_login: ACCEPTED: guest account and guest ok (%s)\n",
+ user));
+ } else {
+ DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
+ }
+ *guest = True;
+ }
-#ifndef KEEP_PASSWORD_SERVER_OPEN
- close(password_client); password_client= -1;
-#endif
+ if (ok && !user_ok(user,snum)) {
+ DEBUG(0,("authorise_login: rejected invalid user %s\n",user));
+ ok = False;
+ }
- return(True);
+ return(ok);
}
-
-
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
new file mode 100644
index 00000000000..cd8a56a5d2a
--- /dev/null
+++ b/source/smbd/pipes.c
@@ -0,0 +1,263 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1997-1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ This file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+extern struct pipe_id_info pipe_names[];
+
+/****************************************************************************
+ reply to an open and X on a named pipe
+
+ This code is basically stolen from reply_open_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+int reply_open_pipe_and_X(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ pstring fname;
+ pstring pipe_name;
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ pipes_struct *p;
+ int smb_ofun = SVAL(inbuf,smb_vwv8);
+ int size=0,fmode=0,mtime=0,rmode=0;
+ int i;
+
+ /* XXXX we need to handle passed times, sattr and flags */
+ srvstr_pull(inbuf, pipe_name, smb_buf(inbuf), sizeof(pipe_name), -1, STR_TERMINATE);
+
+ /* If the name doesn't start \PIPE\ then this is directed */
+ /* at a mailslot or something we really, really don't understand, */
+ /* not just something we really don't understand. */
+ if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 )
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+
+ DEBUG(4,("Opening pipe %s.\n", pipe_name));
+
+ /* See if it is one we want to handle. */
+ for( i = 0; pipe_names[i].client_pipe ; i++ )
+ if( strequal(pipe_name,pipe_names[i].client_pipe) )
+ break;
+
+ if (pipe_names[i].client_pipe == NULL)
+ return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
+
+ /* Strip \PIPE\ off the name. */
+ pstrcpy(fname, pipe_name + PIPELEN);
+
+
+#if 0
+ /*
+ * Hack for NT printers... JRA.
+ */
+ if(should_fail_next_srvsvc_open(fname))
+ return(ERROR(ERRSRV,ERRaccess));
+#endif
+
+ /* Known pipes arrive with DIR attribs. Remove it so a regular file */
+ /* can be opened and add it in after the open. */
+ DEBUG(3,("Known pipe %s opening.\n",fname));
+ smb_ofun |= FILE_CREATE_IF_NOT_EXIST;
+
+ p = open_rpc_pipe_p(fname, conn, vuid);
+ if (!p) return(ERROR_DOS(ERRSRV,ERRnofids));
+
+ /* Prepare the reply */
+ set_message(outbuf,15,0,True);
+
+ /* Mark the opened file as an existing named pipe in message mode. */
+ SSVAL(outbuf,smb_vwv9,2);
+ SSVAL(outbuf,smb_vwv10,0xc700);
+
+ if (rmode == 2) {
+ DEBUG(4,("Resetting open result to open from create.\n"));
+ rmode = 1;
+ }
+
+ SSVAL(outbuf,smb_vwv2, p->pnum);
+ SSVAL(outbuf,smb_vwv3,fmode);
+ put_dos_date3(outbuf,smb_vwv4,mtime);
+ SIVAL(outbuf,smb_vwv6,size);
+ SSVAL(outbuf,smb_vwv8,rmode);
+ SSVAL(outbuf,smb_vwv11,0x0001);
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ reply to a write on a pipe
+****************************************************************************/
+int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize)
+{
+ pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
+ size_t numtowrite = SVAL(inbuf,smb_vwv1);
+ int nwritten;
+ int outsize;
+ char *data;
+
+ if (!p)
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+
+ data = smb_buf(inbuf) + 3;
+
+ if (numtowrite == 0)
+ nwritten = 0;
+ else
+ nwritten = write_to_pipe(p, data, numtowrite);
+
+ if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
+ return (UNIXERROR(ERRDOS,ERRnoaccess));
+
+ outsize = set_message(outbuf,1,0,True);
+
+ SSVAL(outbuf,smb_vwv0,nwritten);
+
+ DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n",
+ p->pnum, nwritten));
+
+ return(outsize);
+}
+
+/****************************************************************************
+ Reply to a write and X.
+
+ This code is basically stolen from reply_write_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+
+int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+{
+ pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
+ size_t numtowrite = SVAL(inbuf,smb_vwv10);
+ int nwritten = -1;
+ int smb_doff = SVAL(inbuf, smb_vwv11);
+ BOOL pipe_start_message_raw = ((SVAL(inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) ==
+ (PIPE_START_MESSAGE|PIPE_RAW_MODE));
+ char *data;
+
+ if (!p)
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+
+ data = smb_base(inbuf) + smb_doff;
+
+ if (numtowrite == 0)
+ nwritten = 0;
+ else {
+ if(pipe_start_message_raw) {
+ /*
+ * For the start of a message in named pipe byte mode,
+ * the first two bytes are a length-of-pdu field. Ignore
+ * them (we don't trust the client. JRA.
+ */
+ if(numtowrite < 2) {
+ DEBUG(0,("reply_pipe_write_and_X: start of message set and not enough data sent.(%u)\n",
+ (unsigned int)numtowrite ));
+ return (UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ data += 2;
+ numtowrite -= 2;
+ }
+ nwritten = write_to_pipe(p, data, numtowrite);
+ }
+
+ if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
+ return (UNIXERROR(ERRDOS,ERRnoaccess));
+
+ set_message(outbuf,6,0,True);
+
+ nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten);
+ SSVAL(outbuf,smb_vwv2,nwritten);
+
+ DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n",
+ p->pnum, nwritten));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ reply to a read and X
+
+ This code is basically stolen from reply_read_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+{
+ pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
+ int smb_maxcnt = SVAL(inbuf,smb_vwv5);
+ int smb_mincnt = SVAL(inbuf,smb_vwv6);
+ int nread = -1;
+ char *data;
+ /* we don't use the offset given to use for pipe reads. This
+ is deliberate, instead we always return the next lump of
+ data on the pipe */
+#if 0
+ uint32 smb_offs = IVAL(inbuf,smb_vwv3);
+#endif
+
+ if (!p)
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+
+ set_message(outbuf,12,0,True);
+ data = smb_buf(outbuf);
+
+ nread = read_from_pipe(p, data, smb_maxcnt);
+
+ if (nread < 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ SSVAL(outbuf,smb_vwv5,nread);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(smb_buf(outbuf),-2,nread);
+
+ DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n",
+ p->pnum, smb_mincnt, smb_maxcnt, nread));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ reply to a close
+****************************************************************************/
+int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
+{
+ pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
+ int outsize = set_message(outbuf,0,0,True);
+
+ if (!p)
+ return(ERROR_DOS(ERRDOS,ERRbadfid));
+
+ DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
+
+ if (!close_rpc_pipe_hnd(p, conn))
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+
+ return(outsize);
+}
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
new file mode 100644
index 00000000000..765bd0f3b26
--- /dev/null
+++ b/source/smbd/posix_acls.c
@@ -0,0 +1,2295 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB NT Security Descriptor / Unix permission conversion.
+ Copyright (C) Jeremy Allison 1994-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Data structures representing the internal ACE format.
+****************************************************************************/
+
+enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
+enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
+
+typedef union posix_id {
+ uid_t uid;
+ gid_t gid;
+ int world;
+} posix_id;
+
+typedef struct canon_ace {
+ struct canon_ace *next, *prev;
+ SMB_ACL_TAG_T type;
+ mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
+ DOM_SID trustee;
+ enum ace_owner owner_type;
+ enum ace_attribute attr;
+ posix_id unix_ug;
+} canon_ace;
+
+#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
+
+/****************************************************************************
+ Functions to manipulate the internal ACE format.
+****************************************************************************/
+
+/****************************************************************************
+ Count a linked list of canonical ACE entries.
+****************************************************************************/
+
+static size_t count_canon_ace_list( canon_ace *list_head )
+{
+ size_t count = 0;
+ canon_ace *ace;
+
+ for (ace = list_head; ace; ace = ace->next)
+ count++;
+
+ return count;
+}
+
+/****************************************************************************
+ Free a linked list of canonical ACE entries.
+****************************************************************************/
+
+static void free_canon_ace_list( canon_ace *list_head )
+{
+ while (list_head) {
+ canon_ace *old_head = list_head;
+ DLIST_REMOVE(list_head, list_head);
+ SAFE_FREE(old_head);
+ }
+}
+
+/****************************************************************************
+ Function to duplicate a canon_ace entry.
+****************************************************************************/
+
+static canon_ace *dup_canon_ace( canon_ace *src_ace)
+{
+ canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
+
+ if (dst_ace == NULL)
+ return NULL;
+
+ *dst_ace = *src_ace;
+ dst_ace->prev = dst_ace->next = NULL;
+ return dst_ace;
+}
+
+/****************************************************************************
+ Print out a canon ace.
+****************************************************************************/
+
+static void print_canon_ace(canon_ace *pace, int num)
+{
+ fstring str;
+
+ dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
+ dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
+ if (pace->owner_type == UID_ACE) {
+ char *u_name = uidtoname(pace->unix_ug.uid);
+ dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name);
+ } else if (pace->owner_type == GID_ACE) {
+ char *g_name = gidtoname(pace->unix_ug.gid);
+ dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
+ } else
+ dbgtext( "other ");
+ switch (pace->type) {
+ case SMB_ACL_USER:
+ dbgtext( "SMB_ACL_USER ");
+ break;
+ case SMB_ACL_USER_OBJ:
+ dbgtext( "SMB_ACL_USER_OBJ ");
+ break;
+ case SMB_ACL_GROUP:
+ dbgtext( "SMB_ACL_GROUP ");
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ dbgtext( "SMB_ACL_GROUP_OBJ ");
+ break;
+ case SMB_ACL_OTHER:
+ dbgtext( "SMB_ACL_OTHER ");
+ break;
+ }
+ dbgtext( "perms ");
+ dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
+ dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
+ dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
+}
+
+/****************************************************************************
+ Print out a canon ace list.
+****************************************************************************/
+
+static void print_canon_ace_list(const char *name, canon_ace *ace_list)
+{
+ int count = 0;
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext( "print_canon_ace_list: %s\n", name );
+ for (;ace_list; ace_list = ace_list->next, count++)
+ print_canon_ace(ace_list, count );
+ }
+}
+
+/****************************************************************************
+ Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
+****************************************************************************/
+
+static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
+{
+ mode_t ret = 0;
+
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
+
+ return ret;
+}
+
+/****************************************************************************
+ Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
+****************************************************************************/
+
+static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
+{
+ mode_t ret = 0;
+
+ if (mode & r_mask)
+ ret |= S_IRUSR;
+ if (mode & w_mask)
+ ret |= S_IWUSR;
+ if (mode & x_mask)
+ ret |= S_IXUSR;
+
+ return ret;
+}
+
+/****************************************************************************
+ Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
+ an SMB_ACL_PERMSET_T.
+****************************************************************************/
+
+static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
+{
+ if (sys_acl_clear_perms(*p_permset) == -1)
+ return -1;
+ if (mode & S_IRUSR) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
+ return -1;
+ }
+ if (mode & S_IWUSR) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
+ return -1;
+ }
+ if (mode & S_IXUSR) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
+ return -1;
+ }
+ return 0;
+}
+/****************************************************************************
+ Function to create owner and group SIDs from a SMB_STRUCT_STAT.
+****************************************************************************/
+
+static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
+{
+ uid_to_sid( powner_sid, psbuf->st_uid );
+ gid_to_sid( pgroup_sid, psbuf->st_gid );
+}
+
+/****************************************************************************
+ Merge aces with a common sid - if both are allow or deny, OR the permissions together and
+ delete the second one. If the first is deny, mask the permissions off and delete the allow
+ if the permissions become zero, delete the deny if the permissions are non zero.
+****************************************************************************/
+
+static void merge_aces( canon_ace **pp_list_head )
+{
+ canon_ace *list_head = *pp_list_head;
+ canon_ace *curr_ace_outer;
+ canon_ace *curr_ace_outer_next;
+
+ /*
+ * First, merge allow entries with identical SIDs, and deny entries
+ * with identical SIDs.
+ */
+
+ for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+ canon_ace *curr_ace;
+ canon_ace *curr_ace_next;
+
+ curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
+
+ for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+
+ curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
+
+ if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ (curr_ace->attr == curr_ace_outer->attr)) {
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("merge_aces: Merging ACE's\n");
+ print_canon_ace( curr_ace_outer, 0);
+ print_canon_ace( curr_ace, 0);
+ }
+
+ /* Merge two allow or two deny ACE's. */
+
+ curr_ace_outer->perms |= curr_ace->perms;
+ DLIST_REMOVE(list_head, curr_ace);
+ SAFE_FREE(curr_ace);
+ curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
+ }
+ }
+ }
+
+ /*
+ * Now go through and mask off allow permissions with deny permissions.
+ * We can delete either the allow or deny here as we know that each SID
+ * appears only once in the list.
+ */
+
+ for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
+ canon_ace *curr_ace;
+ canon_ace *curr_ace_next;
+
+ curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
+
+ for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+
+ curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
+
+ /*
+ * Subtract ACE's with different entries. Due to the ordering constraints
+ * we've put on the ACL, we know the deny must be the first one.
+ */
+
+ if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("merge_aces: Masking ACE's\n");
+ print_canon_ace( curr_ace_outer, 0);
+ print_canon_ace( curr_ace, 0);
+ }
+
+ curr_ace->perms &= ~curr_ace_outer->perms;
+
+ if (curr_ace->perms == 0) {
+
+ /*
+ * The deny overrides the allow. Remove the allow.
+ */
+
+ DLIST_REMOVE(list_head, curr_ace);
+ SAFE_FREE(curr_ace);
+ curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
+
+ } else {
+
+ /*
+ * Even after removing permissions, there
+ * are still allow permissions - delete the deny.
+ * It is safe to delete the deny here,
+ * as we are guarenteed by the deny first
+ * ordering that all the deny entries for
+ * this SID have already been merged into one
+ * before we can get to an allow ace.
+ */
+
+ DLIST_REMOVE(list_head, curr_ace_outer);
+ SAFE_FREE(curr_ace_outer);
+ }
+ }
+
+ } /* end for curr_ace */
+ } /* end for curr_ace_outer */
+
+ /* We may have modified the list. */
+
+ *pp_list_head = list_head;
+}
+
+/****************************************************************************
+ Map canon_ace perms to permission bits NT.
+ The attr element is not used here - we only process deny entries on set,
+ not get. Deny entries are implicit on get with ace->perms = 0.
+****************************************************************************/
+
+static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
+{
+ SEC_ACCESS sa;
+ uint32 nt_mask = 0;
+
+ *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+
+ if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
+ nt_mask = UNIX_ACCESS_RWX;
+ } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
+ nt_mask = UNIX_ACCESS_NONE;
+ } else {
+ nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
+ nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
+ nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
+ }
+
+ DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
+ (unsigned int)ace->perms, (unsigned int)nt_mask ));
+
+ init_sec_access(&sa,nt_mask);
+ return sa;
+}
+
+/****************************************************************************
+ Map NT perms to a UNIX mode_t.
+****************************************************************************/
+
+#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
+#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
+#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
+
+static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
+{
+ mode_t mode = 0;
+
+ switch(type) {
+ case S_IRUSR:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IRUSR|S_IWUSR|S_IXUSR;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
+ }
+ break;
+ case S_IRGRP:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IRGRP|S_IWGRP|S_IXGRP;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
+ }
+ break;
+ case S_IROTH:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IROTH|S_IWOTH|S_IXOTH;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
+ }
+ break;
+ }
+
+ return mode;
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into a UNIX owner and group.
+****************************************************************************/
+
+static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ DOM_SID owner_sid;
+ DOM_SID grp_sid;
+ enum SID_NAME_USE sid_type;
+
+ *puser = (uid_t)-1;
+ *pgrp = (gid_t)-1;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
+ return True;
+ }
+
+ /*
+ * Validate the owner and group SID's.
+ */
+
+ memset(&owner_sid, '\0', sizeof(owner_sid));
+ memset(&grp_sid, '\0', sizeof(grp_sid));
+
+ DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
+
+ /*
+ * Don't immediately fail if the owner sid cannot be validated.
+ * This may be a group chown only set.
+ */
+
+ if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+ sid_copy(&owner_sid, psd->owner_sid);
+ if (!sid_to_uid( &owner_sid, puser, &sid_type)) {
+ DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Don't immediately fail if the group sid cannot be validated.
+ * This may be an owner chown only set.
+ */
+
+ if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+ sid_copy(&grp_sid, psd->grp_sid);
+ if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) {
+ DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
+ return False;
+ }
+ }
+
+ DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Ensure the enforced permissions for this share apply.
+****************************************************************************/
+
+static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type)
+{
+ int snum = SNUM(fsp->conn);
+ mode_t and_bits = (mode_t)0;
+ mode_t or_bits = (mode_t)0;
+
+ /* Get the initial bits to apply. */
+
+ if (fsp->is_directory) {
+ and_bits = lp_dir_security_mask(snum);
+ or_bits = lp_force_dir_security_mode(snum);
+ } else {
+ and_bits = lp_security_mask(snum);
+ or_bits = lp_force_security_mode(snum);
+ }
+
+ /* Now bounce them into the S_USR space. */
+ switch(type) {
+ case S_IRUSR:
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
+ break;
+ case S_IRGRP:
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
+ break;
+ case S_IROTH:
+ and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
+ or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
+ break;
+ }
+
+ return ((perms & and_bits)|or_bits);
+}
+
+/****************************************************************************
+ A well formed POSIX file or default ACL has at least 3 entries, a
+ SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
+ In addition, the owner must always have at least read access.
+ When using this call on get_acl, the pst struct is valid and contains
+ the mode of the file. When using this call on set_acl, the pst struct has
+ been modified to have a mode containing the default for this file or directory
+ type.
+****************************************************************************/
+
+static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
+ files_struct *fsp,
+ DOM_SID *pfile_owner_sid,
+ DOM_SID *pfile_grp_sid,
+ SMB_STRUCT_STAT *pst,
+ BOOL setting_acl)
+{
+ extern DOM_SID global_sid_World;
+ canon_ace *pace;
+ BOOL got_user = False;
+ BOOL got_grp = False;
+ BOOL got_other = False;
+
+ for (pace = *pp_ace; pace; pace = pace->next) {
+ if (pace->type == SMB_ACL_USER_OBJ) {
+
+ if (setting_acl) {
+ /* Ensure owner has read access. */
+ pace->perms |= S_IRUSR;
+ if (fsp->is_directory)
+ pace->perms |= (S_IWUSR|S_IXUSR);
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ pace->perms = apply_default_perms(fsp, pace->perms, S_IRUSR);
+ }
+
+ got_user = True;
+ } else if (pace->type == SMB_ACL_GROUP_OBJ) {
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ if (setting_acl)
+ pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP);
+ got_grp = True;
+ } else if (pace->type == SMB_ACL_OTHER) {
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ if (setting_acl)
+ pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH);
+ got_other = True;
+ }
+ }
+
+ if (!got_user) {
+ if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_USER_OBJ;
+ pace->owner_type = UID_ACE;
+ pace->unix_ug.uid = pst->st_uid;
+ pace->trustee = *pfile_owner_sid;
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ pace->attr = ALLOW_ACE;
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_grp) {
+ if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP_OBJ;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.uid = pst->st_gid;
+ pace->trustee = *pfile_grp_sid;
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ pace->attr = ALLOW_ACE;
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_other) {
+ if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_OTHER;
+ pace->owner_type = WORLD_ACE;
+ pace->unix_ug.world = -1;
+ pace->trustee = global_sid_World;
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
+ pace->attr = ALLOW_ACE;
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into two canonical ace lists.
+****************************************************************************/
+
+static BOOL create_canon_ace_lists(files_struct *fsp,
+ DOM_SID *pfile_owner_sid,
+ DOM_SID *pfile_grp_sid,
+ canon_ace **ppfile_ace, canon_ace **ppdir_ace,
+ SEC_ACL *dacl)
+{
+ extern DOM_SID global_sid_World;
+ extern struct generic_mapping file_generic_mapping;
+ BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+ canon_ace *tmp_ace = NULL;
+ canon_ace *current_ace = NULL;
+ BOOL got_dir_allow = False;
+ BOOL got_file_allow = False;
+ int i, j;
+
+ *ppfile_ace = NULL;
+ *ppdir_ace = NULL;
+
+ /*
+ * Convert the incoming ACL into a more regular form.
+ */
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *psa = &dacl->ace[i];
+
+ if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
+ DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
+ return False;
+ }
+
+ /*
+ * The security mask may be UNIX_ACCESS_NONE which should map into
+ * no permissions (we overload the WRITE_OWNER bit for this) or it
+ * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
+ * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
+ */
+
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&psa->info.mask, &file_generic_mapping);
+
+ psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
+
+ if(psa->info.mask != UNIX_ACCESS_NONE)
+ psa->info.mask &= ~UNIX_ACCESS_NONE;
+ }
+
+ /*
+ * Deal with the fact that NT 4.x re-writes the canonical format
+ * that we return for default ACLs. If a directory ACE is identical
+ * to a inherited directory ACE then NT changes the bits so that the
+ * first ACE is set to OI|IO and the second ACE for this SID is set
+ * to CI. We need to repair this. JRA.
+ */
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ SEC_ACE *psa1 = &dacl->ace[i];
+
+ for (j = i + 1; j < dacl->num_aces; j++) {
+ SEC_ACE *psa2 = &dacl->ace[j];
+
+ if (psa1->info.mask != psa2->info.mask)
+ continue;
+
+ if (!sid_equal(&psa1->trustee, &psa2->trustee))
+ continue;
+
+ /*
+ * Ok - permission bits and SIDs are equal.
+ * Check if flags were re-written.
+ */
+
+ if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+
+ psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
+ psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
+
+ } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+
+ psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
+ psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
+
+ }
+ }
+ }
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ enum SID_NAME_USE sid_type;
+ SEC_ACE *psa = &dacl->ace[i];
+
+ /*
+ * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
+ */
+
+ if (non_mappable_sid(&psa->trustee)) {
+ fstring str;
+ DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
+ sid_to_string(str, &psa->trustee) ));
+ continue;
+ }
+
+ /*
+ * Create a cannon_ace entry representing this NT DACL ACE.
+ */
+
+ if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(current_ace);
+
+ sid_copy(&current_ace->trustee, &psa->trustee);
+
+ /*
+ * Try and work out if the SID is a user or group
+ * as we need to flag these differently for POSIX.
+ */
+
+ if( sid_equal(&current_ace->trustee, &global_sid_World)) {
+ current_ace->owner_type = WORLD_ACE;
+ current_ace->unix_ug.world = -1;
+ } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid, &sid_type)) {
+ current_ace->owner_type = UID_ACE;
+ } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid, &sid_type)) {
+ current_ace->owner_type = GID_ACE;
+ } else {
+ fstring str;
+
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ SAFE_FREE(current_ace);
+ DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
+ sid_to_string(str, &current_ace->trustee) ));
+ return False;
+ }
+
+ /*
+ * Map the given NT permissions into a UNIX mode_t containing only
+ * S_I(R|W|X)USR bits.
+ */
+
+ current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
+ current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
+
+ /*
+ * Now note what kind of a POSIX ACL this should map to.
+ */
+
+ if(sid_equal(&current_ace->trustee, pfile_owner_sid)) {
+
+ current_ace->type = SMB_ACL_USER_OBJ;
+
+ } else if( sid_equal(&current_ace->trustee, pfile_grp_sid)) {
+
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+
+ } else if( sid_equal(&current_ace->trustee, &global_sid_World)) {
+
+ current_ace->type = SMB_ACL_OTHER;
+
+ } else {
+ /*
+ * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
+ * looking at owner_type.
+ */
+
+ current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
+ }
+
+ /*
+ * Now add the created ace to either the file list, the directory
+ * list, or both. We *MUST* preserve the order here (hence we use
+ * DLIST_ADD_END) as NT ACLs are order dependent.
+ */
+
+ if (fsp->is_directory) {
+
+ /*
+ * We can only add to the default POSIX ACE list if the ACE is
+ * designed to be inherited by both files and directories.
+ */
+
+ if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
+ (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ got_dir_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
+ DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
+Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ SAFE_FREE(current_ace);
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("create_canon_ace_lists: adding dir ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+
+ /*
+ * If this is not an inherit only ACE we need to add a duplicate
+ * to the file acl.
+ */
+
+ if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ canon_ace *dup_ace = dup_canon_ace(current_ace);
+
+ if (!dup_ace) {
+ DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ current_ace = dup_ace;
+ } else {
+ current_ace = NULL;
+ }
+ }
+ }
+
+ /*
+ * Only add to the file ACL if not inherit only.
+ */
+
+ if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ DLIST_ADD_END(file_ace, current_ace, tmp_ace);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ got_file_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+ DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
+Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ SAFE_FREE(current_ace);
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("create_canon_ace_lists: adding file ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+ all_aces_are_inherit_only = False;
+ current_ace = NULL;
+ }
+
+ /*
+ * Free if ACE was not added.
+ */
+
+ SAFE_FREE(current_ace);
+ }
+
+ if (fsp->is_directory && all_aces_are_inherit_only) {
+ /*
+ * Windows 2000 is doing one of these weird 'inherit acl'
+ * traverses to conserve NTFS ACL resources. Just pretend
+ * there was no DACL sent. JRA.
+ */
+
+ DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ file_ace = NULL;
+ dir_ace = NULL;
+ }
+
+ *ppfile_ace = file_ace;
+ *ppdir_ace = dir_ace;
+
+ return True;
+}
+
+/****************************************************************************
+ Check if a given uid/SID is in a group gid/SID. This is probably very
+ expensive and will need optimisation. A *lot* of optimisation :-). JRA.
+****************************************************************************/
+
+static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+{
+ extern DOM_SID global_sid_World;
+ fstring u_name;
+ fstring g_name;
+
+ /* "Everyone" always matches every uid. */
+
+ if (sid_equal(&group_ace->trustee, &global_sid_World))
+ return True;
+
+ fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
+ fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
+
+ /*
+ * Due to the winbind interfaces we need to do this via names,
+ * not uids/gids.
+ */
+
+ return user_in_group_list(u_name, g_name );
+}
+
+/****************************************************************************
+ ASCII art time again... JRA :-).
+
+ We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
+ we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
+ entries). Secondly, the merge code has ensured that all duplicate SID entries for
+ allow or deny have been merged, so the same SID can only appear once in the deny
+ list or once in the allow list.
+
+ We then process as follows :
+
+ ---------------------------------------------------------------------------
+ First pass - look for a Everyone DENY entry.
+
+ If it is deny all (rwx) trunate the list at this point.
+ Else, walk the list from this point and use the deny permissions of this
+ entry as a mask on all following allow entries. Finally, delete
+ the Everyone DENY entry (we have applied it to everything possible).
+
+ In addition, in this pass we remove any DENY entries that have
+ no permissions (ie. they are a DENY nothing).
+ ---------------------------------------------------------------------------
+ Second pass - only deal with deny user entries.
+
+ DENY user1 (perms XXX)
+
+ new_perms = 0
+ for all following allow group entries where user1 is in group
+ new_perms |= group_perms;
+
+ user1 entry perms = new_perms & ~ XXX;
+
+ Convert the deny entry to an allow entry with the new perms and
+ push to the end of the list. Note if the user was in no groups
+ this maps to a specific allow nothing entry for this user.
+
+ The common case from the NT ACL choser (userX deny all) is
+ optimised so we don't do the group lookup - we just map to
+ an allow nothing entry.
+
+ What we're doing here is inferring the allow permissions the
+ person setting the ACE on user1 wanted by looking at the allow
+ permissions on the groups the user is currently in. This will
+ be a snapshot, depending on group membership but is the best
+ we can do and has the advantage of failing closed rather than
+ open.
+ ---------------------------------------------------------------------------
+ Third pass - only deal with deny group entries.
+
+ DENY group1 (perms XXX)
+
+ for all following allow user entries where user is in group1
+ user entry perms = user entry perms & ~ XXX;
+
+ If there is a group Everyone allow entry with permissions YYY,
+ convert the group1 entry to an allow entry and modify its
+ permissions to be :
+
+ new_perms = YYY & ~ XXX
+
+ and push to the end of the list.
+
+ If there is no group Everyone allow entry then convert the
+ group1 entry to a allow nothing entry and push to the end of the list.
+
+ Note that the common case from the NT ACL choser (groupX deny all)
+ cannot be optimised here as we need to modify user entries who are
+ in the group to change them to a deny all also.
+
+ What we're doing here is modifying the allow permissions of
+ user entries (which are more specific in POSIX ACLs) to mask
+ out the explicit deny set on the group they are in. This will
+ be a snapshot depending on current group membership but is the
+ best we can do and has the advantage of failing closed rather
+ than open.
+ ---------------------------------------------------------------------------
+
+ Note we *MUST* do the deny user pass first as this will convert deny user
+ entries into allow user entries which can then be processed by the deny
+ group pass.
+
+ The above algorithm took a *lot* of thinking about - hence this
+ explaination :-). JRA.
+****************************************************************************/
+
+/****************************************************************************
+ Process a canon_ace list entries. This is very complex code. We need
+ to go through and remove the "deny" permissions from any allow entry that matches
+ the id of this entry. We have already refused any NT ACL that wasn't in correct
+ order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
+ we just remove it (to fail safe). We have already removed any duplicate ace
+ entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
+ allow entries.
+****************************************************************************/
+
+static void process_deny_list( canon_ace **pp_ace_list )
+{
+ extern DOM_SID global_sid_World;
+ canon_ace *ace_list = *pp_ace_list;
+ canon_ace *curr_ace = NULL;
+ canon_ace *curr_ace_next = NULL;
+
+ /* Pass 1 above - look for an Everyone, deny entry. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ canon_ace *allow_ace_p;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->perms == (mode_t)0) {
+
+ /* Deny nothing entry - delete. */
+
+ DLIST_REMOVE(ace_list, curr_ace);
+ continue;
+ }
+
+ if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+ continue;
+
+ /* JRATEST - assert. */
+ SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
+
+ if (curr_ace->perms == ALL_ACE_PERMS) {
+
+ /*
+ * Optimisation. This is a DENY_ALL to Everyone. Truncate the
+ * list at this point including this entry.
+ */
+
+ canon_ace *prev_entry = curr_ace->prev;
+
+ free_canon_ace_list( curr_ace );
+ if (prev_entry)
+ prev_entry->next = NULL;
+ else {
+ /* We deleted the entire list. */
+ ace_list = NULL;
+ }
+ break;
+ }
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ /*
+ * Only mask off allow entries.
+ */
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ allow_ace_p->perms &= ~curr_ace->perms;
+ }
+
+ /*
+ * Now it's been applied, remove it.
+ */
+
+ DLIST_REMOVE(ace_list, curr_ace);
+ }
+
+ /* Pass 2 above - deal with deny user entries. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ mode_t new_perms = (mode_t)0;
+ canon_ace *allow_ace_p;
+ canon_ace *tmp_ace;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->owner_type != UID_ACE)
+ continue;
+
+ if (curr_ace->perms == ALL_ACE_PERMS) {
+
+ /*
+ * Optimisation - this is a deny everything to this user.
+ * Convert to an allow nothing and push to the end of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ curr_ace->perms = (mode_t)0;
+ DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
+ continue;
+ }
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ /* We process GID_ACE and WORLD_ACE entries only. */
+
+ if (allow_ace_p->owner_type == UID_ACE)
+ continue;
+
+ if (uid_entry_in_group( curr_ace, allow_ace_p))
+ new_perms |= allow_ace_p->perms;
+ }
+
+ /*
+ * Convert to a allow entry, modify the perms and push to the end
+ * of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ curr_ace->perms = (new_perms & ~curr_ace->perms);
+ DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
+ }
+
+ /* Pass 3 above - deal with deny group entries. */
+
+ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
+ canon_ace *tmp_ace;
+ canon_ace *allow_ace_p;
+ canon_ace *allow_everyone_p = NULL;
+
+ curr_ace_next = curr_ace->next; /* So we can't lose the link. */
+
+ if (curr_ace->attr != DENY_ACE)
+ continue;
+
+ if (curr_ace->owner_type != GID_ACE)
+ continue;
+
+ for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
+
+ if (allow_ace_p->attr != ALLOW_ACE)
+ continue;
+
+ /* Store a pointer to the Everyone allow, if it exists. */
+ if (allow_ace_p->owner_type == WORLD_ACE)
+ allow_everyone_p = allow_ace_p;
+
+ /* We process UID_ACE entries only. */
+
+ if (allow_ace_p->owner_type != UID_ACE)
+ continue;
+
+ /* Mask off the deny group perms. */
+
+ if (uid_entry_in_group( allow_ace_p, curr_ace))
+ allow_ace_p->perms &= ~curr_ace->perms;
+ }
+
+ /*
+ * Convert the deny to an allow with the correct perms and
+ * push to the end of the list.
+ */
+
+ curr_ace->attr = ALLOW_ACE;
+ if (allow_everyone_p)
+ curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
+ else
+ curr_ace->perms = (mode_t)0;
+ DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
+
+ }
+
+ *pp_ace_list = ace_list;
+}
+
+/****************************************************************************
+ Create a default mode that will be used if a security descriptor entry has
+ no user/group/world entries.
+****************************************************************************/
+
+static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
+{
+ int snum = SNUM(fsp->conn);
+ mode_t and_bits = (mode_t)0;
+ mode_t or_bits = (mode_t)0;
+ mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
+
+ if (fsp->is_directory)
+ mode |= (S_IWUSR|S_IXUSR);
+
+ /*
+ * Now AND with the create mode/directory mode bits then OR with the
+ * force create mode/force directory mode bits.
+ */
+
+ if (fsp->is_directory) {
+ and_bits = lp_dir_security_mask(snum);
+ or_bits = lp_force_dir_security_mode(snum);
+ } else {
+ and_bits = lp_security_mask(snum);
+ or_bits = lp_force_security_mode(snum);
+ }
+
+ return ((mode & and_bits)|or_bits);
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
+ succeeding.
+****************************************************************************/
+
+static BOOL unpack_canon_ace(files_struct *fsp,
+ SMB_STRUCT_STAT *pst,
+ DOM_SID *pfile_owner_sid,
+ DOM_SID *pfile_grp_sid,
+ canon_ace **ppfile_ace, canon_ace **ppdir_ace,
+ uint32 security_info_sent, SEC_DESC *psd)
+{
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+
+ *ppfile_ace = NULL;
+ *ppdir_ace = NULL;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
+ return False;
+ }
+
+ /*
+ * If no DACL then this is a chown only security descriptor.
+ */
+
+ if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
+ return True;
+
+ /*
+ * Now go through the DACL and create the canon_ace lists.
+ */
+
+ if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid,
+ &file_ace, &dir_ace, psd->dacl))
+ return False;
+
+ if ((file_ace == NULL) && (dir_ace == NULL)) {
+ /* W2K traverse DACL set - ignore. */
+ return True;
+ }
+
+ /*
+ * Go through the canon_ace list and merge entries
+ * belonging to identical users of identical allow or deny type.
+ * We can do this as all deny entries come first, followed by
+ * all allow entries (we have mandated this before accepting this acl).
+ */
+
+ print_canon_ace_list( "file ace - before merge", file_ace);
+ merge_aces( &file_ace );
+
+ print_canon_ace_list( "dir ace - before merge", dir_ace);
+ merge_aces( &dir_ace );
+
+ /*
+ * NT ACLs are order dependent. Go through the acl lists and
+ * process DENY entries by masking the allow entries.
+ */
+
+ print_canon_ace_list( "file ace - before deny", file_ace);
+ process_deny_list( &file_ace);
+
+ print_canon_ace_list( "dir ace - before deny", dir_ace);
+ process_deny_list( &dir_ace);
+
+ /*
+ * A well formed POSIX file or default ACL has at least 3 entries, a
+ * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
+ * and optionally a mask entry. Ensure this is the case.
+ */
+
+ print_canon_ace_list( "file ace - before valid", file_ace);
+
+ /*
+ * A default 3 element mode entry for a file should be r-- --- ---.
+ * A default 3 element mode entry for a directory should be rwx --- ---.
+ */
+
+ pst->st_mode = create_default_mode(fsp, False);
+
+ if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ print_canon_ace_list( "dir ace - before valid", dir_ace);
+
+ /*
+ * A default inheritable 3 element mode entry for a directory should be the
+ * mode Samba will use to create a file within. Ensure user rwx bits are set if
+ * it's a directory.
+ */
+
+ pst->st_mode = create_default_mode(fsp, True);
+
+ if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return False;
+ }
+
+ print_canon_ace_list( "file ace - return", file_ace);
+ print_canon_ace_list( "dir ace - return", dir_ace);
+
+ *ppfile_ace = file_ace;
+ *ppdir_ace = dir_ace;
+ return True;
+
+}
+
+/******************************************************************************
+ When returning permissions, try and fit NT display
+ semantics if possible. Note the the canon_entries here must have been malloced.
+ The list format should be - first entry = owner, followed by group and other user
+ entries, last entry = other.
+
+ Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
+ are not ordered, and match on the most specific entry rather than walking a list,
+ then a simple POSIX permission of rw-r--r-- should really map to 6 entries,
+
+ Entry 0: owner : deny all except read and write.
+ Entry 1: group : deny all except read.
+ Entry 2: Everyone : deny all except read.
+ Entry 3: owner : allow read and write.
+ Entry 4: group : allow read.
+ Entry 5: Everyone : allow read.
+
+ But NT cannot display this in their ACL editor !
+********************************************************************************/
+
+static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
+{
+ canon_ace *list_head = *pp_list_head;
+ canon_ace *owner_ace = NULL;
+ canon_ace *other_ace = NULL;
+ canon_ace *ace = NULL;
+
+ for (ace = list_head; ace; ace = ace->next) {
+ if (ace->type == SMB_ACL_USER_OBJ)
+ owner_ace = ace;
+ else if (ace->type == SMB_ACL_OTHER) {
+ /* Last ace - this is "other" */
+ other_ace = ace;
+ }
+ }
+
+ if (!owner_ace || !other_ace) {
+ DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
+ filename ));
+ return;
+ }
+
+ /*
+ * The POSIX algorithm applies to owner first, and other last,
+ * so ensure they are arranged in this order.
+ */
+
+ if (owner_ace) {
+ DLIST_PROMOTE(list_head, owner_ace);
+ }
+
+ if (other_ace) {
+ DLIST_DEMOTE(list_head, other_ace, ace);
+ }
+
+ /* We have probably changed the head of the list. */
+
+ *pp_list_head = list_head;
+}
+
+/****************************************************************************
+ Create a linked list of canonical ACE entries.
+****************************************************************************/
+
+static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
+ DOM_SID *powner, DOM_SID *pgroup)
+{
+ extern DOM_SID global_sid_World;
+ mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
+ canon_ace *list_head = NULL;
+ canon_ace *ace = NULL;
+ canon_ace *next_ace = NULL;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ size_t ace_count;
+
+ while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ DOM_SID sid;
+ posix_id unix_ug;
+ enum ace_owner owner_type;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY)
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ /* Is this a MASK entry ? */
+ if (sys_acl_get_tag_type(entry, &tagtype) == -1)
+ continue;
+
+ if (sys_acl_get_permset(entry, &permset) == -1)
+ continue;
+
+ /* Decide which SID to use based on the ACL type. */
+ switch(tagtype) {
+ case SMB_ACL_USER_OBJ:
+ /* Get the SID from the owner. */
+ uid_to_sid( &sid, psbuf->st_uid );
+ unix_ug.uid = psbuf->st_uid;
+ owner_type = UID_ACE;
+ break;
+ case SMB_ACL_USER:
+ {
+ uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
+ if (puid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
+ continue;
+ }
+ uid_to_sid( &sid, *puid);
+ unix_ug.uid = *puid;
+ owner_type = UID_ACE;
+ sys_acl_free_qualifier((void *)puid,tagtype);
+ break;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ /* Get the SID from the owning group. */
+ gid_to_sid( &sid, psbuf->st_gid );
+ unix_ug.gid = psbuf->st_gid;
+ owner_type = GID_ACE;
+ break;
+ case SMB_ACL_GROUP:
+ {
+ gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
+ if (pgid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
+ continue;
+ }
+ gid_to_sid( &sid, *pgid);
+ unix_ug.gid = *pgid;
+ owner_type = GID_ACE;
+ sys_acl_free_qualifier((void *)pgid,tagtype);
+ break;
+ }
+ case SMB_ACL_MASK:
+ acl_mask = convert_permset_to_mode_t(permset);
+ continue; /* Don't count the mask as an entry. */
+ case SMB_ACL_OTHER:
+ /* Use the Everyone SID */
+ sid = global_sid_World;
+ unix_ug.world = -1;
+ owner_type = WORLD_ACE;
+ break;
+ default:
+ DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
+ continue;
+ }
+
+ /*
+ * Add this entry to the list.
+ */
+
+ if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
+ goto fail;
+
+ ZERO_STRUCTP(ace);
+ ace->type = tagtype;
+ ace->perms = convert_permset_to_mode_t(permset);
+ ace->attr = ALLOW_ACE;
+ ace->trustee = sid;
+ ace->unix_ug = unix_ug;
+ ace->owner_type = owner_type;
+
+ DLIST_ADD(list_head, ace);
+ }
+
+ /*
+ * This next call will ensure we have at least a user/group/world set.
+ */
+
+ if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
+ goto fail;
+
+ arrange_posix_perms(fsp->fsp_name,&list_head );
+
+ /*
+ * Now go through the list, masking the permissions with the
+ * acl_mask. Ensure all DENY Entries are at the start of the list.
+ */
+
+ DEBUG(10,("canonicalise_acl: ace entries before arrange :\n"));
+
+ for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
+ next_ace = ace->next;
+
+ /* Masks are only applied to entries other than USER_OBJ and OTHER. */
+ if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
+ ace->perms &= acl_mask;
+
+ if (ace->perms == 0) {
+ DLIST_PROMOTE(list_head, ace);
+ }
+
+ if( DEBUGLVL( 10 ) ) {
+ print_canon_ace(ace, ace_count);
+ }
+ }
+
+ print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
+
+ return list_head;
+
+ fail:
+
+ free_canon_ace_list(list_head);
+ return NULL;
+}
+
+/****************************************************************************
+ Attempt to apply an ACL to a file or directory.
+****************************************************************************/
+
+static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
+{
+ BOOL ret = False;
+ SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
+ canon_ace *p_ace;
+ int i;
+ SMB_ACL_ENTRY_T mask_entry;
+ SMB_ACL_PERMSET_T mask_permset;
+ SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
+
+ if (the_acl == NULL) {
+
+ if (errno != ENOSYS) {
+ /*
+ * Only print this error message if we have some kind of ACL
+ * support that's not working. Otherwise we would always get this.
+ */
+ DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
+ default_ace ? "default" : "file", strerror(errno) ));
+ }
+ *pacl_set_support = False;
+ return False;
+ }
+
+ for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
+ SMB_ACL_ENTRY_T the_entry;
+ SMB_ACL_PERMSET_T the_permset;
+
+ /*
+ * Get the entry for this ACE.
+ */
+
+ if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto done;
+ }
+
+ /*
+ * Ok - we now know the ACL calls should be working, don't
+ * allow fallback to chmod.
+ */
+
+ *pacl_set_support = True;
+
+ /*
+ * Initialise the entry from the canon_ace.
+ */
+
+ /*
+ * First tell the entry what type of ACE this is.
+ */
+
+ if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto done;
+ }
+
+ /*
+ * Only set the qualifier (user or group id) if the entry is a user
+ * or group id ACE.
+ */
+
+ if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
+ if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto done;
+ }
+ }
+
+ /*
+ * Convert the mode_t perms in the canon_ace to a POSIX permset.
+ */
+
+ if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto done;
+ }
+
+ if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
+ (unsigned int)p_ace->perms, i, strerror(errno) ));
+ goto done;
+ }
+
+ /*
+ * ..and apply them to the entry.
+ */
+
+ if (sys_acl_set_permset(the_entry, the_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
+ i, strerror(errno) ));
+ goto done;
+ }
+
+ if( DEBUGLVL( 10 ))
+ print_canon_ace( p_ace, i);
+ }
+
+ /*
+ * Add in a mask of rwx.
+ */
+
+ if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
+ goto done;
+ }
+
+ if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
+ goto done;
+ }
+
+ if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
+ goto done;
+ }
+
+ if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
+ goto done;
+ }
+
+ if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
+ DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
+ goto done;
+ }
+
+ /*
+ * Check if the ACL is valid.
+ */
+
+ if (sys_acl_valid(the_acl) == -1) {
+ DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
+ the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
+ strerror(errno) ));
+ goto done;
+ }
+
+ /*
+ * Finally apply it to the file or directory.
+ */
+
+ if(default_ace || fsp->is_directory || fsp->fd == -1) {
+ if (sys_acl_set_file(fsp->fsp_name, the_acl_type, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (errno == ENOSYS)
+ *pacl_set_support = False;
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
+ the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
+ fsp->fsp_name, strerror(errno) ));
+ goto done;
+ }
+ } else {
+ if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
+ /*
+ * Some systems allow all the above calls and only fail with no ACL support
+ * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
+ */
+ if (errno == ENOSYS)
+ *pacl_set_support = False;
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ goto done;
+ }
+ }
+
+ ret = True;
+
+ done:
+
+ if (the_acl != NULL)
+ sys_acl_free_acl(the_acl);
+
+ return ret;
+}
+
+/****************************************************************************
+ Convert a canon_ace to a generic 3 element permission - if possible.
+****************************************************************************/
+
+#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
+
+static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
+{
+ int snum = SNUM(fsp->conn);
+ size_t ace_count = count_canon_ace_list(file_ace_list);
+ canon_ace *ace_p;
+ canon_ace *owner_ace = NULL;
+ canon_ace *group_ace = NULL;
+ canon_ace *other_ace = NULL;
+ mode_t and_bits;
+ mode_t or_bits;
+
+ if (ace_count != 3) {
+ DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
+posix perms.\n", fsp->fsp_name ));
+ return False;
+ }
+
+ for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
+ if (ace_p->owner_type == UID_ACE)
+ owner_ace = ace_p;
+ else if (ace_p->owner_type == GID_ACE)
+ group_ace = ace_p;
+ else if (ace_p->owner_type == WORLD_ACE)
+ other_ace = ace_p;
+ }
+
+ if (!owner_ace || !group_ace || !other_ace) {
+ DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
+ fsp->fsp_name ));
+ return False;
+ }
+
+ *posix_perms = (mode_t)0;
+
+ *posix_perms |= owner_ace->perms;
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
+ *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
+ *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
+
+ /* The owner must have at least read access. */
+
+ *posix_perms |= S_IRUSR;
+ if (fsp->is_directory)
+ *posix_perms |= (S_IWUSR|S_IXUSR);
+
+ /* If requested apply the masks. */
+
+ /* Get the initial bits to apply. */
+
+ if (fsp->is_directory) {
+ and_bits = lp_dir_security_mask(snum);
+ or_bits = lp_force_dir_security_mode(snum);
+ } else {
+ and_bits = lp_security_mask(snum);
+ or_bits = lp_force_security_mode(snum);
+ }
+
+ *posix_perms = (((*posix_perms) & and_bits)|or_bits);
+
+ DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
+ (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
+ fsp->fsp_name ));
+
+ return True;
+}
+
+static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2)
+{
+ if (a1->type == a2->type)
+ return 0;
+
+ if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
+ return -1;
+ return 1;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor from an fsp. If it succeeds it allocates
+ the space for the return elements and returns the size needed to return the
+ security descriptor. This should be the only external function needed for
+ the UNIX style get ACL.
+****************************************************************************/
+
+size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+ SEC_ACE *nt_ace_list = NULL;
+ DOM_SID owner_sid;
+ DOM_SID group_sid;
+ size_t sd_size = 0;
+ SEC_ACL *psa = NULL;
+ size_t num_acls = 0;
+ size_t num_dir_acls = 0;
+ size_t num_aces = 0;
+ SMB_ACL_T posix_acl = NULL;
+ SMB_ACL_T dir_acl = NULL;
+ canon_ace *file_ace = NULL;
+ canon_ace *dir_ace = NULL;
+
+ *ppdesc = NULL;
+
+ DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
+
+ if(fsp->is_directory || fsp->fd == -1) {
+
+ /* Get the stat struct for the owner info. */
+ if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
+ return 0;
+ }
+ /*
+ * Get the ACL from the path.
+ */
+
+ posix_acl = sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
+
+ /*
+ * If it's a directory get the default POSIX ACL.
+ */
+
+ if(fsp->is_directory)
+ dir_acl = sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+
+ } else {
+
+ /* Get the stat struct for the owner info. */
+ if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
+ return 0;
+ }
+ /*
+ * Get the ACL from the fd.
+ */
+ posix_acl = sys_acl_get_fd(fsp->fd);
+ }
+
+ DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
+ posix_acl ? "present" : "absent",
+ dir_acl ? "present" : "absent" ));
+
+ /*
+ * Get the owner, group and world SIDs.
+ */
+
+ create_file_sids(&sbuf, &owner_sid, &group_sid);
+
+ /* Create the canon_ace lists. */
+ file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid);
+ num_acls = count_canon_ace_list(file_ace);
+
+ /* We must have *some* ACLS. */
+
+ if (num_acls == 0) {
+ DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
+ return 0;
+ }
+
+ if (fsp->is_directory) {
+ /*
+ * If we have to fake a default ACL then this is the mode to use.
+ */
+ sbuf.st_mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
+
+ dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, &owner_sid, &group_sid);
+ num_dir_acls = count_canon_ace_list(dir_ace);
+ }
+
+ /* Allocate the ace list. */
+ if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
+ goto done;
+ }
+
+ memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
+
+ /*
+ * Create the NT ACE list from the canonical ace lists.
+ */
+
+ {
+ canon_ace *ace;
+ int nt_acl_type;
+ int i;
+
+ ace = file_ace;
+
+ for (i = 0; i < num_acls; i++, ace = ace->next) {
+ SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
+ init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0);
+ }
+
+ ace = dir_ace;
+
+ for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
+ SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
+ init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
+ SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
+ }
+
+ /*
+ * Sort to force deny entries to the front.
+ */
+
+ if (num_acls + num_dir_acls)
+ qsort( nt_ace_list, num_acls + num_dir_acls, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
+ }
+
+ if (num_acls) {
+ if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
+ goto done;
+ }
+ }
+
+ *ppdesc = make_standard_sec_desc( main_loop_talloc_get(), &owner_sid, &group_sid, psa, &sd_size);
+
+ if(!*ppdesc) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
+ sd_size = 0;
+ }
+
+ done:
+
+ if (posix_acl)
+ sys_acl_free_acl(posix_acl);
+ if (dir_acl)
+ sys_acl_free_acl(dir_acl);
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ SAFE_FREE(nt_ace_list);
+
+ return sd_size;
+}
+
+/****************************************************************************
+ Reply to set a security descriptor on an fsp. security_info_sent is the
+ description of the following NT ACL.
+ This should be the only external function needed for the UNIX style set ACL.
+****************************************************************************/
+
+BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+ connection_struct *conn = fsp->conn;
+ uid_t user = (uid_t)-1;
+ gid_t grp = (gid_t)-1;
+ SMB_STRUCT_STAT sbuf;
+ DOM_SID file_owner_sid;
+ DOM_SID file_grp_sid;
+ canon_ace *file_ace_list = NULL;
+ canon_ace *dir_ace_list = NULL;
+ BOOL acl_perms = False;
+ mode_t orig_mode = (mode_t)0;
+ uid_t orig_uid;
+ gid_t orig_gid;
+
+ DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
+
+ /*
+ * Get the current state of the file.
+ */
+
+ if(fsp->is_directory || fsp->fd == -1) {
+ if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
+ return False;
+ } else {
+ if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
+ return False;
+ }
+
+ /* Save the original elements we check against. */
+ orig_mode = sbuf.st_mode;
+ orig_uid = sbuf.st_uid;
+ orig_gid = sbuf.st_gid;
+
+ /*
+ * Unpack the user/group/world id's.
+ */
+
+ if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
+ return False;
+
+ /*
+ * Do we need to chown ?
+ */
+
+ if((user != (uid_t)-1 || grp != (uid_t)-1) && (orig_uid != user || orig_gid != grp)) {
+
+ DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Recheck the current state of the file, which may have changed.
+ * (suid/sgid bits, for instance)
+ */
+
+ if(fsp->is_directory) {
+ if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
+ return False;
+ }
+ } else {
+
+ int ret;
+
+ if(fsp->fd == -1)
+ ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
+ else
+ ret = vfs_fstat(fsp,fsp->fd,&sbuf);
+
+ if(ret != 0)
+ return False;
+ }
+
+ /* Save the original elements we check against. */
+ orig_mode = sbuf.st_mode;
+ orig_uid = sbuf.st_uid;
+ orig_gid = sbuf.st_gid;
+ }
+
+ create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
+
+ acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
+ &file_ace_list, &dir_ace_list, security_info_sent, psd);
+
+ if ((file_ace_list == NULL) && (dir_ace_list == NULL)) {
+ /* W2K traverse DACL set - ignore. */
+ return True;
+ }
+
+ if (!acl_perms) {
+ DEBUG(3,("set_nt_acl: cannot set permissions\n"));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+
+ /*
+ * Only change security if we got a DACL.
+ */
+
+ if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
+
+ BOOL acl_set_support = False;
+ BOOL ret = False;
+
+ /*
+ * Try using the POSIX ACL set first. Fall back to chmod if
+ * we have no ACL support on this filesystem.
+ */
+
+ if (acl_perms && file_ace_list) {
+ ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
+ if (acl_set_support && ret == False) {
+ DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ }
+
+ if (acl_perms && acl_set_support && fsp->is_directory) {
+ if (dir_ace_list) {
+ if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
+ DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ } else {
+
+ /*
+ * No default ACL - delete one if it exists.
+ */
+
+ if (sys_acl_delete_def_file(fsp->fsp_name) == -1) {
+ DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
+ free_canon_ace_list(file_ace_list);
+ return False;
+ }
+ }
+ }
+
+ /*
+ * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
+ */
+
+ if(!acl_set_support && acl_perms) {
+ mode_t posix_perms;
+
+ if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
+ fsp->fsp_name ));
+ return False;
+ }
+
+ if (orig_mode != posix_perms) {
+
+ DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
+ fsp->fsp_name, (unsigned int)posix_perms ));
+
+ if(conn->vfs_ops.chmod(conn,fsp->fsp_name, posix_perms) == -1) {
+ DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ }
+ }
+ }
+
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+
+ return True;
+}
+
+/****************************************************************************
+ Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+****************************************************************************/
+
+static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
+{
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ int num_entries = 0;
+
+ while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ mode_t perms;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY)
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ if (sys_acl_get_tag_type(entry, &tagtype) == -1)
+ return -1;
+
+ if (sys_acl_get_permset(entry, &permset) == -1)
+ return -1;
+
+ num_entries++;
+
+ switch(tagtype) {
+ case SMB_ACL_USER_OBJ:
+ perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ break;
+ case SMB_ACL_MASK:
+ perms = S_IRUSR|S_IWUSR|S_IXUSR;
+ break;
+ case SMB_ACL_OTHER:
+ perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
+ break;
+ default:
+ continue;
+ }
+
+ if (map_acl_perms_to_permset(perms, &permset) == -1)
+ return -1;
+
+ if (sys_acl_set_permset(entry, permset) == -1)
+ return -1;
+ }
+
+ /*
+ * If this is a simple 3 element ACL or no elements then it's a standard
+ * UNIX permission set. Just use chmod...
+ */
+
+ if ((num_entries == 3) || (num_entries == 0))
+ return -1;
+
+ return 0;
+}
+
+/****************************************************************************
+ Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+ Note that name is in UNIX character set.
+****************************************************************************/
+
+int chmod_acl(const char *name, mode_t mode)
+{
+ SMB_ACL_T posix_acl = NULL;
+ int ret = -1;
+
+ if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
+ return -1;
+
+ if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
+ goto done;
+
+ ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
+
+ done:
+
+ sys_acl_free_acl(posix_acl);
+ return ret;
+}
+
+/****************************************************************************
+ Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
+ and set the mask to rwx. Needed to preserve complex ACLs set by NT.
+****************************************************************************/
+
+int fchmod_acl(int fd, mode_t mode)
+{
+ SMB_ACL_T posix_acl = NULL;
+ int ret = -1;
+
+ if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
+ return -1;
+
+ if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
+ goto done;
+
+ ret = sys_acl_set_fd(fd, posix_acl);
+
+ done:
+
+ sys_acl_free_acl(posix_acl);
+ return ret;
+}
diff --git a/source/smbd/process.c b/source/smbd/process.c
new file mode 100644
index 00000000000..111da3bceff
--- /dev/null
+++ b/source/smbd/process.c
@@ -0,0 +1,1292 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ process incoming packets - main loop
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct timeval smb_last_time;
+
+static char *InBuffer = NULL;
+char *OutBuffer = NULL;
+char *last_inbuf = NULL;
+
+/*
+ * Size of data we can send to client. Set
+ * by the client for all protocols above CORE.
+ * Set by us for CORE protocol.
+ */
+int max_send = BUFFER_SIZE;
+/*
+ * Size of the data we can receive. Set by us.
+ * Can be modified by the max xmit parameter.
+ */
+int max_recv = BUFFER_SIZE;
+
+extern int last_message;
+extern int global_oplock_break;
+extern userdom_struct current_user_info;
+extern int smb_read_error;
+extern VOLATILE sig_atomic_t reload_after_sighup;
+extern BOOL global_machine_password_needs_changing;
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+extern int max_send;
+
+/****************************************************************************
+ structure to hold a linked list of queued messages.
+ for processing.
+****************************************************************************/
+
+typedef struct {
+ ubi_slNode msg_next;
+ char *msg_buf;
+ int msg_len;
+} pending_message_list;
+
+static ubi_slList smb_oplock_queue = { NULL, (ubi_slNodePtr)&smb_oplock_queue, 0};
+
+/****************************************************************************
+ Function to push a message onto the tail of a linked list of smb messages ready
+ for processing.
+****************************************************************************/
+
+static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len)
+{
+ pending_message_list *msg = (pending_message_list *)
+ malloc(sizeof(pending_message_list));
+
+ if(msg == NULL)
+ {
+ DEBUG(0,("push_message: malloc fail (1)\n"));
+ return False;
+ }
+
+ msg->msg_buf = (char *)malloc(msg_len);
+ if(msg->msg_buf == NULL)
+ {
+ DEBUG(0,("push_message: malloc fail (2)\n"));
+ SAFE_FREE(msg);
+ return False;
+ }
+
+ memcpy(msg->msg_buf, buf, msg_len);
+ msg->msg_len = msg_len;
+
+ ubi_slAddTail( list_head, msg);
+
+ return True;
+}
+
+/****************************************************************************
+ Function to push a smb message onto a linked list of local smb messages ready
+ for processing.
+****************************************************************************/
+
+BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
+{
+ return push_message(&smb_oplock_queue, buf, msg_len);
+}
+
+/****************************************************************************
+do all async processing in here. This includes UDB oplock messages, kernel
+oplock messages, change notify events etc.
+****************************************************************************/
+static void async_processing(fd_set *fds, char *buffer, int buffer_len)
+{
+ /* check for oplock messages (both UDP and kernel) */
+ if (receive_local_message(fds, buffer, buffer_len, 0)) {
+ process_local_message(buffer, buffer_len);
+ }
+
+ /* check for async change notify events */
+ process_pending_change_notify_queue(0);
+
+ /* check for sighup processing */
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = False;
+ }
+}
+
+/****************************************************************************
+ Do a select on an two fd's - with timeout.
+
+ If a local udp message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) call async_processing()
+
+ If a pending smb message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) return this next.
+
+ If the first smbfd is ready then read an smb from it.
+ if the second (loopback UDP) fd is ready then read a message
+ from it and setup the buffer header to identify the length
+ and from address.
+ Returns False on timeout or error.
+ Else returns True.
+
+The timeout is in milli seconds
+****************************************************************************/
+
+static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
+{
+ fd_set fds;
+ int selrtn;
+ struct timeval to;
+ int maxfd;
+
+ smb_read_error = 0;
+
+ again:
+
+ /*
+ * Note that this call must be before processing any SMB
+ * messages as we need to synchronously process any messages
+ * we may have sent to ourselves from the previous SMB.
+ */
+ message_dispatch();
+
+ /*
+ * Check to see if we already have a message on the smb queue.
+ * If so - copy and return it.
+ */
+ if(ubi_slCount(&smb_oplock_queue) != 0) {
+ pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
+ memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+
+ /* Free the message we just copied. */
+ SAFE_FREE(msg->msg_buf);
+ SAFE_FREE(msg);
+
+ DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
+ return True;
+ }
+
+
+ /*
+ * Setup the select read fd set.
+ */
+
+ FD_ZERO(&fds);
+ FD_SET(smbd_server_fd(),&fds);
+ maxfd = setup_oplock_select_set(&fds);
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL);
+
+ /* if we get EINTR then maybe we have received an oplock
+ signal - treat this as select returning 1. This is ugly, but
+ is the best we can do until the oplock code knows more about
+ signals */
+ if (selrtn == -1 && errno == EINTR) {
+ async_processing(&fds, buffer, buffer_len);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
+ /* Check if error */
+ if (selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
+ }
+
+ /*
+ * Ensure we process oplock break messages by preference.
+ * This is IMPORTANT ! Otherwise we can starve other processes
+ * sending us an oplock break message. JRA.
+ */
+
+ if (oplock_message_waiting(&fds)) {
+ async_processing(&fds, buffer, buffer_len);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
+ return receive_smb(smbd_server_fd(), buffer, 0);
+}
+
+/****************************************************************************
+Get the next SMB packet, doing the local message processing automatically.
+****************************************************************************/
+
+BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
+{
+ BOOL got_keepalive;
+ BOOL ret;
+
+ do {
+ ret = receive_message_or_smb(inbuf,bufsize,timeout);
+
+ got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive));
+ } while (ret && got_keepalive);
+
+ return ret;
+}
+
+/****************************************************************************
+ We're terminating and have closed all our files/connections etc.
+ If there are any pending local messages we need to respond to them
+ before termination so that other smbds don't think we just died whilst
+ holding oplocks.
+****************************************************************************/
+
+void respond_to_all_remaining_local_messages(void)
+{
+ char buffer[1024];
+ fd_set fds;
+
+ /*
+ * Assert we have no exclusive open oplocks.
+ */
+
+ if(get_number_of_exclusive_open_oplocks()) {
+ DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
+ get_number_of_exclusive_open_oplocks() ));
+ return;
+ }
+
+ /*
+ * Setup the select read fd set.
+ */
+
+ FD_ZERO(&fds);
+ if(!setup_oplock_select_set(&fds))
+ return;
+
+ /*
+ * Keep doing receive_local_message with a 1 ms timeout until
+ * we have no more messages.
+ */
+ while(receive_local_message(&fds, buffer, sizeof(buffer), 1)) {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(buffer, sizeof(buffer));
+
+ FD_ZERO(&fds);
+ (void)setup_oplock_select_set(&fds);
+ }
+
+ return;
+}
+
+
+/*
+These flags determine some of the permissions required to do an operation
+
+Note that I don't set NEED_WRITE on some write operations because they
+are used by some brain-dead clients when printing, and I don't want to
+force write permissions on print services.
+*/
+#define AS_USER (1<<0)
+#define NEED_WRITE (1<<1)
+#define TIME_INIT (1<<2)
+#define CAN_IPC (1<<3)
+#define AS_GUEST (1<<5)
+#define QUEUE_IN_OPLOCK (1<<6)
+
+/*
+ define a list of possible SMB messages and their corresponding
+ functions. Any message that has a NULL function is unimplemented -
+ please feel free to contribute implementations!
+*/
+static struct smb_message_struct
+{
+ char *name;
+ int (*fn)(connection_struct *conn, char *, char *, int, int);
+ int flags;
+}
+ smb_messages[256] = {
+
+/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
+/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
+/* 0x02 */ { "SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
+/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
+/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
+/* 0x05 */ { "SMBflush",reply_flush,AS_USER},
+/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
+/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
+/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
+/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
+/* 0x0a */ { "SMBread",reply_read,AS_USER},
+/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
+/* 0x0c */ { "SMBlock",reply_lock,AS_USER},
+/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
+/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
+/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
+/* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
+/* 0x11 */ { "SMBexit",reply_exit,0},
+/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
+/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
+/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
+/* 0x15 */ { NULL, NULL, 0 },
+/* 0x16 */ { NULL, NULL, 0 },
+/* 0x17 */ { NULL, NULL, 0 },
+/* 0x18 */ { NULL, NULL, 0 },
+/* 0x19 */ { NULL, NULL, 0 },
+/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
+/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
+/* 0x1c */ { "SMBreadBs",NULL,0 },
+/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
+/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
+/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
+/* 0x20 */ { "SMBwritec",NULL,0},
+/* 0x21 */ { NULL, NULL, 0 },
+/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
+/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
+/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
+/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
+/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
+/* 0x27 */ { "SMBioctl",reply_ioctl,0},
+/* 0x28 */ { "SMBioctls",NULL,AS_USER},
+/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+/* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+/* 0x2b */ { "SMBecho",reply_echo,0},
+/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
+/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
+/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
+/* 0x30 */ { NULL, NULL, 0 },
+/* 0x31 */ { NULL, NULL, 0 },
+/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK | CAN_IPC },
+/* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
+/* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
+/* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
+/* 0x36 */ { NULL, NULL, 0 },
+/* 0x37 */ { NULL, NULL, 0 },
+/* 0x38 */ { NULL, NULL, 0 },
+/* 0x39 */ { NULL, NULL, 0 },
+/* 0x3a */ { NULL, NULL, 0 },
+/* 0x3b */ { NULL, NULL, 0 },
+/* 0x3c */ { NULL, NULL, 0 },
+/* 0x3d */ { NULL, NULL, 0 },
+/* 0x3e */ { NULL, NULL, 0 },
+/* 0x3f */ { NULL, NULL, 0 },
+/* 0x40 */ { NULL, NULL, 0 },
+/* 0x41 */ { NULL, NULL, 0 },
+/* 0x42 */ { NULL, NULL, 0 },
+/* 0x43 */ { NULL, NULL, 0 },
+/* 0x44 */ { NULL, NULL, 0 },
+/* 0x45 */ { NULL, NULL, 0 },
+/* 0x46 */ { NULL, NULL, 0 },
+/* 0x47 */ { NULL, NULL, 0 },
+/* 0x48 */ { NULL, NULL, 0 },
+/* 0x49 */ { NULL, NULL, 0 },
+/* 0x4a */ { NULL, NULL, 0 },
+/* 0x4b */ { NULL, NULL, 0 },
+/* 0x4c */ { NULL, NULL, 0 },
+/* 0x4d */ { NULL, NULL, 0 },
+/* 0x4e */ { NULL, NULL, 0 },
+/* 0x4f */ { NULL, NULL, 0 },
+/* 0x50 */ { NULL, NULL, 0 },
+/* 0x51 */ { NULL, NULL, 0 },
+/* 0x52 */ { NULL, NULL, 0 },
+/* 0x53 */ { NULL, NULL, 0 },
+/* 0x54 */ { NULL, NULL, 0 },
+/* 0x55 */ { NULL, NULL, 0 },
+/* 0x56 */ { NULL, NULL, 0 },
+/* 0x57 */ { NULL, NULL, 0 },
+/* 0x58 */ { NULL, NULL, 0 },
+/* 0x59 */ { NULL, NULL, 0 },
+/* 0x5a */ { NULL, NULL, 0 },
+/* 0x5b */ { NULL, NULL, 0 },
+/* 0x5c */ { NULL, NULL, 0 },
+/* 0x5d */ { NULL, NULL, 0 },
+/* 0x5e */ { NULL, NULL, 0 },
+/* 0x5f */ { NULL, NULL, 0 },
+/* 0x60 */ { NULL, NULL, 0 },
+/* 0x61 */ { NULL, NULL, 0 },
+/* 0x62 */ { NULL, NULL, 0 },
+/* 0x63 */ { NULL, NULL, 0 },
+/* 0x64 */ { NULL, NULL, 0 },
+/* 0x65 */ { NULL, NULL, 0 },
+/* 0x66 */ { NULL, NULL, 0 },
+/* 0x67 */ { NULL, NULL, 0 },
+/* 0x68 */ { NULL, NULL, 0 },
+/* 0x69 */ { NULL, NULL, 0 },
+/* 0x6a */ { NULL, NULL, 0 },
+/* 0x6b */ { NULL, NULL, 0 },
+/* 0x6c */ { NULL, NULL, 0 },
+/* 0x6d */ { NULL, NULL, 0 },
+/* 0x6e */ { NULL, NULL, 0 },
+/* 0x6f */ { NULL, NULL, 0 },
+/* 0x70 */ { "SMBtcon",reply_tcon,0},
+/* 0x71 */ { "SMBtdis",reply_tdis,0},
+/* 0x72 */ { "SMBnegprot",reply_negprot,0},
+/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
+/* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
+/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
+/* 0x76 */ { NULL, NULL, 0 },
+/* 0x77 */ { NULL, NULL, 0 },
+/* 0x78 */ { NULL, NULL, 0 },
+/* 0x79 */ { NULL, NULL, 0 },
+/* 0x7a */ { NULL, NULL, 0 },
+/* 0x7b */ { NULL, NULL, 0 },
+/* 0x7c */ { NULL, NULL, 0 },
+/* 0x7d */ { NULL, NULL, 0 },
+/* 0x7e */ { NULL, NULL, 0 },
+/* 0x7f */ { NULL, NULL, 0 },
+/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
+/* 0x81 */ { "SMBsearch",reply_search,AS_USER},
+/* 0x82 */ { "SMBffirst",reply_search,AS_USER},
+/* 0x83 */ { "SMBfunique",reply_search,AS_USER},
+/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
+/* 0x85 */ { NULL, NULL, 0 },
+/* 0x86 */ { NULL, NULL, 0 },
+/* 0x87 */ { NULL, NULL, 0 },
+/* 0x88 */ { NULL, NULL, 0 },
+/* 0x89 */ { NULL, NULL, 0 },
+/* 0x8a */ { NULL, NULL, 0 },
+/* 0x8b */ { NULL, NULL, 0 },
+/* 0x8c */ { NULL, NULL, 0 },
+/* 0x8d */ { NULL, NULL, 0 },
+/* 0x8e */ { NULL, NULL, 0 },
+/* 0x8f */ { NULL, NULL, 0 },
+/* 0x90 */ { NULL, NULL, 0 },
+/* 0x91 */ { NULL, NULL, 0 },
+/* 0x92 */ { NULL, NULL, 0 },
+/* 0x93 */ { NULL, NULL, 0 },
+/* 0x94 */ { NULL, NULL, 0 },
+/* 0x95 */ { NULL, NULL, 0 },
+/* 0x96 */ { NULL, NULL, 0 },
+/* 0x97 */ { NULL, NULL, 0 },
+/* 0x98 */ { NULL, NULL, 0 },
+/* 0x99 */ { NULL, NULL, 0 },
+/* 0x9a */ { NULL, NULL, 0 },
+/* 0x9b */ { NULL, NULL, 0 },
+/* 0x9c */ { NULL, NULL, 0 },
+/* 0x9d */ { NULL, NULL, 0 },
+/* 0x9e */ { NULL, NULL, 0 },
+/* 0x9f */ { NULL, NULL, 0 },
+/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
+/* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
+/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+/* 0xa3 */ { NULL, NULL, 0 },
+/* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
+/* 0xa5 */ { NULL, NULL, 0 },
+/* 0xa6 */ { NULL, NULL, 0 },
+/* 0xa7 */ { NULL, NULL, 0 },
+/* 0xa8 */ { NULL, NULL, 0 },
+/* 0xa9 */ { NULL, NULL, 0 },
+/* 0xaa */ { NULL, NULL, 0 },
+/* 0xab */ { NULL, NULL, 0 },
+/* 0xac */ { NULL, NULL, 0 },
+/* 0xad */ { NULL, NULL, 0 },
+/* 0xae */ { NULL, NULL, 0 },
+/* 0xaf */ { NULL, NULL, 0 },
+/* 0xb0 */ { NULL, NULL, 0 },
+/* 0xb1 */ { NULL, NULL, 0 },
+/* 0xb2 */ { NULL, NULL, 0 },
+/* 0xb3 */ { NULL, NULL, 0 },
+/* 0xb4 */ { NULL, NULL, 0 },
+/* 0xb5 */ { NULL, NULL, 0 },
+/* 0xb6 */ { NULL, NULL, 0 },
+/* 0xb7 */ { NULL, NULL, 0 },
+/* 0xb8 */ { NULL, NULL, 0 },
+/* 0xb9 */ { NULL, NULL, 0 },
+/* 0xba */ { NULL, NULL, 0 },
+/* 0xbb */ { NULL, NULL, 0 },
+/* 0xbc */ { NULL, NULL, 0 },
+/* 0xbd */ { NULL, NULL, 0 },
+/* 0xbe */ { NULL, NULL, 0 },
+/* 0xbf */ { NULL, NULL, 0 },
+/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
+/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
+/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
+/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
+/* 0xc4 */ { NULL, NULL, 0 },
+/* 0xc5 */ { NULL, NULL, 0 },
+/* 0xc6 */ { NULL, NULL, 0 },
+/* 0xc7 */ { NULL, NULL, 0 },
+/* 0xc8 */ { NULL, NULL, 0 },
+/* 0xc9 */ { NULL, NULL, 0 },
+/* 0xca */ { NULL, NULL, 0 },
+/* 0xcb */ { NULL, NULL, 0 },
+/* 0xcc */ { NULL, NULL, 0 },
+/* 0xcd */ { NULL, NULL, 0 },
+/* 0xce */ { NULL, NULL, 0 },
+/* 0xcf */ { NULL, NULL, 0 },
+/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
+/* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
+/* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
+/* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
+/* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
+/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
+/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
+/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
+/* 0xd8 */ { NULL, NULL, 0 },
+/* 0xd9 */ { NULL, NULL, 0 },
+/* 0xda */ { NULL, NULL, 0 },
+/* 0xdb */ { NULL, NULL, 0 },
+/* 0xdc */ { NULL, NULL, 0 },
+/* 0xdd */ { NULL, NULL, 0 },
+/* 0xde */ { NULL, NULL, 0 },
+/* 0xdf */ { NULL, NULL, 0 },
+/* 0xe0 */ { NULL, NULL, 0 },
+/* 0xe1 */ { NULL, NULL, 0 },
+/* 0xe2 */ { NULL, NULL, 0 },
+/* 0xe3 */ { NULL, NULL, 0 },
+/* 0xe4 */ { NULL, NULL, 0 },
+/* 0xe5 */ { NULL, NULL, 0 },
+/* 0xe6 */ { NULL, NULL, 0 },
+/* 0xe7 */ { NULL, NULL, 0 },
+/* 0xe8 */ { NULL, NULL, 0 },
+/* 0xe9 */ { NULL, NULL, 0 },
+/* 0xea */ { NULL, NULL, 0 },
+/* 0xeb */ { NULL, NULL, 0 },
+/* 0xec */ { NULL, NULL, 0 },
+/* 0xed */ { NULL, NULL, 0 },
+/* 0xee */ { NULL, NULL, 0 },
+/* 0xef */ { NULL, NULL, 0 },
+/* 0xf0 */ { NULL, NULL, 0 },
+/* 0xf1 */ { NULL, NULL, 0 },
+/* 0xf2 */ { NULL, NULL, 0 },
+/* 0xf3 */ { NULL, NULL, 0 },
+/* 0xf4 */ { NULL, NULL, 0 },
+/* 0xf5 */ { NULL, NULL, 0 },
+/* 0xf6 */ { NULL, NULL, 0 },
+/* 0xf7 */ { NULL, NULL, 0 },
+/* 0xf8 */ { NULL, NULL, 0 },
+/* 0xf9 */ { NULL, NULL, 0 },
+/* 0xfa */ { NULL, NULL, 0 },
+/* 0xfb */ { NULL, NULL, 0 },
+/* 0xfc */ { NULL, NULL, 0 },
+/* 0xfd */ { NULL, NULL, 0 },
+/* 0xfe */ { NULL, NULL, 0 },
+/* 0xff */ { NULL, NULL, 0 }
+
+};
+
+/*******************************************************************
+dump a prs to a file
+ ********************************************************************/
+static void smb_dump(char *name, int type, char *data, ssize_t len)
+{
+ int fd, i;
+ pstring fname;
+ if (DEBUGLEVEL < 50) return;
+
+ if (len < 4) len = smb_len(data)+4;
+ for (i=1;i<100;i++) {
+ slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
+ type ? "req" : "resp");
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd != -1 || errno != EEXIST) break;
+ }
+ if (fd != -1) {
+ write(fd, data, len);
+ close(fd);
+ DEBUG(0,("created %s len %d\n", fname, len));
+ }
+}
+
+
+/****************************************************************************
+do a switch on the message type, and return the response size
+****************************************************************************/
+static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
+{
+ static pid_t pid= (pid_t)-1;
+ int outsize = 0;
+ extern uint16 global_smbpid;
+
+ type &= 0xff;
+
+ if (pid == (pid_t)-1)
+ pid = sys_getpid();
+
+ errno = 0;
+ last_message = type;
+
+ /* make sure this is an SMB packet */
+ if (strncmp(smb_base(inbuf),"\377SMB",4) != 0)
+ {
+ DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
+ return(-1);
+ }
+
+ /* yuck! this is an interim measure before we get rid of our
+ current inbuf/outbuf system */
+ global_smbpid = SVAL(inbuf,smb_pid);
+
+ if (smb_messages[type].fn == NULL)
+ {
+ DEBUG(0,("Unknown message type %d!\n",type));
+ smb_dump("Unknown", 1, inbuf, size);
+ outsize = reply_unknown(inbuf,outbuf);
+ }
+ else
+ {
+ int flags = smb_messages[type].flags;
+ static uint16 last_session_tag = UID_FIELD_INVALID;
+ /* In share mode security we must ignore the vuid. */
+ uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
+ connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
+
+ DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid));
+
+ smb_dump(smb_fn_name(type), 1, inbuf, size);
+ if(global_oplock_break)
+ {
+ if(flags & QUEUE_IN_OPLOCK)
+ {
+ /*
+ * Queue this message as we are the process of an oplock break.
+ */
+
+ DEBUG( 2, ( "switch_message: queueing message due to being in " ) );
+ DEBUGADD( 2, ( "oplock break state.\n" ) );
+
+ push_oplock_pending_smb_message( inbuf, size );
+ return -1;
+ }
+ }
+
+ /* Ensure this value is replaced in the incoming packet. */
+ SSVAL(inbuf,smb_uid,session_tag);
+
+ /*
+ * Ensure the correct username is in current_user_info.
+ * This is a really ugly bugfix for problems with
+ * multiple session_setup_and_X's being done and
+ * allowing %U and %G substitutions to work correctly.
+ * There is a reason this code is done here, don't
+ * move it unless you know what you're doing... :-).
+ * JRA.
+ */
+
+ if (session_tag != last_session_tag) {
+ user_struct *vuser = NULL;
+
+ last_session_tag = session_tag;
+ if(session_tag != UID_FIELD_INVALID)
+ vuser = get_valid_user_struct(session_tag);
+ if(vuser != NULL)
+ current_user_info = vuser->user;
+ }
+
+ /* does this protocol need to be run as root? */
+ if (!(flags & AS_USER))
+ change_to_root_user();
+
+ /* does this protocol need a valid tree connection? */
+ if ((flags & AS_USER) && !conn) {
+ return ERROR_DOS(ERRSRV, ERRinvnid);
+ }
+
+
+ /* does this protocol need to be run as the connected user? */
+ if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {
+ if (flags & AS_GUEST)
+ flags &= ~AS_USER;
+ else
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+ }
+
+ /* this code is to work around a bug is MS client 3 without
+ introducing a security hole - it needs to be able to do
+ print queue checks as guest if it isn't logged in properly */
+ if (flags & AS_USER)
+ flags &= ~AS_GUEST;
+
+ /* does it need write permission? */
+ if ((flags & NEED_WRITE) && !CAN_WRITE(conn))
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+
+ /* ipc services are limited */
+ if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) {
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+ }
+
+ /* load service specific parameters */
+ if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) {
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+ }
+
+ /* does this protocol need to be run as guest? */
+ if ((flags & AS_GUEST) &&
+ (!change_to_guest() ||
+ !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) {
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+ }
+
+ last_inbuf = inbuf;
+
+ outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
+ }
+
+ smb_dump(smb_fn_name(type), 0, outbuf, outsize);
+
+ return(outsize);
+}
+
+
+/****************************************************************************
+ construct a reply to the incoming packet
+****************************************************************************/
+static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
+{
+ int type = CVAL(inbuf,smb_com);
+ int outsize = 0;
+ int msg_type = CVAL(inbuf,0);
+
+ GetTimeOfDay(&smb_last_time);
+
+ chain_size = 0;
+ file_chain_reset();
+ reset_chain_p();
+
+ if (msg_type != 0)
+ return(reply_special(inbuf,outbuf));
+
+ construct_reply_common(inbuf, outbuf);
+
+ outsize = switch_message(type,inbuf,outbuf,size,bufsize);
+
+ outsize += chain_size;
+
+ if(outsize > 4)
+ smb_setlen(outbuf,outsize - 4);
+ return(outsize);
+}
+
+/****************************************************************************
+ Keep track of the number of running smbd's. This functionality is used to
+ 'hard' limit Samba overhead on resource constrained systems.
+****************************************************************************/
+static BOOL smbd_process_limit(void)
+{
+ int total_smbds;
+
+ if (lp_max_smbd_processes()) {
+
+ /* Always add one to the smbd process count, as exit_server() always
+ * subtracts one.
+ */
+
+ total_smbds = 1; /* In case we need to create the entry. */
+
+ if (!conn_tdb_ctx()) {
+ DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \
+set. Ignoring max smbd restriction.\n"));
+ return False;
+ }
+
+ if (tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
+ return True;
+
+ return total_smbds > lp_max_smbd_processes();
+ }
+ else
+ return False;
+}
+
+/****************************************************************************
+ process an smb from the client - split out from the process() code so
+ it can be used by the oplock break code.
+****************************************************************************/
+void process_smb(char *inbuf, char *outbuf)
+{
+#ifdef WITH_SSL
+ extern BOOL sslEnabled; /* don't use function for performance reasons */
+ static int sslConnected = 0;
+#endif /* WITH_SSL */
+ static int trans_num;
+ int msg_type = CVAL(inbuf,0);
+ int32 len = smb_len(inbuf);
+ int nread = len + 4;
+
+ DO_PROFILE_INC(smb_count);
+
+ if (trans_num == 0) {
+ /* on the first packet, check the global hosts allow/ hosts
+ deny parameters before doing any parsing of the packet
+ passed to us by the client. This prevents attacks on our
+ parsing code from hosts not in the hosts allow list */
+ if (smbd_process_limit() ||
+ !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ /* send a negative session response "not listening on calling
+ name" */
+ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ DEBUG( 1, ( "Connection denied from %s\n",
+ client_addr() ) );
+ (void)send_smb(smbd_server_fd(),(char *)buf);
+ exit_server("connection denied");
+ }
+ }
+
+ DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );
+ DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
+
+#ifdef WITH_SSL
+ if(sslEnabled && !sslConnected){
+ sslConnected = sslutil_negotiate_ssl(smbd_server_fd(), msg_type);
+ if(sslConnected < 0){ /* an error occured */
+ exit_server("SSL negotiation failed");
+ }else if(sslConnected){
+ trans_num++;
+ return;
+ }
+ }
+#endif /* WITH_SSL */
+
+ if (msg_type == 0)
+ show_msg(inbuf);
+ else if(msg_type == SMBkeepalive)
+ return; /* Keepalive packet. */
+
+ nread = construct_reply(inbuf,outbuf,nread,max_send);
+
+ if(nread > 0)
+ {
+ if (CVAL(outbuf,0) == 0)
+ show_msg(outbuf);
+
+ if (nread != smb_len(outbuf) + 4)
+ {
+ DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
+ nread, smb_len(outbuf)));
+ }
+ else
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("process_smb: send_smb failed.");
+ }
+ trans_num++;
+}
+
+
+
+/****************************************************************************
+return a string containing the function name of a SMB command
+****************************************************************************/
+char *smb_fn_name(int type)
+{
+ static char *unknown_name = "SMBunknown";
+
+ if (smb_messages[type].name == NULL)
+ return(unknown_name);
+
+ return(smb_messages[type].name);
+}
+
+
+/****************************************************************************
+ Helper function for contruct_reply.
+****************************************************************************/
+
+void construct_reply_common(char *inbuf,char *outbuf)
+{
+ memset(outbuf,'\0',smb_size);
+
+ set_message(outbuf,0,0,True);
+ CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
+
+ memcpy(outbuf+4,inbuf+4,4);
+ CVAL(outbuf,smb_rcls) = SMB_SUCCESS;
+ CVAL(outbuf,smb_reh) = 0;
+ SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES));
+ SSVAL(outbuf,smb_flg2,
+ FLAGS2_UNICODE_STRINGS | FLAGS2_LONG_PATH_COMPONENTS |
+ FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
+
+ SSVAL(outbuf,smb_err,SMB_SUCCESS);
+ SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
+ SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
+ SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
+ SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
+}
+
+/****************************************************************************
+ construct a chained reply and add it to the already made reply
+ **************************************************************************/
+int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
+{
+ static char *orig_inbuf;
+ static char *orig_outbuf;
+ int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
+ unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
+ char *inbuf2, *outbuf2;
+ int outsize2;
+ char inbuf_saved[smb_wct];
+ char outbuf_saved[smb_wct];
+ int wct = CVAL(outbuf,smb_wct);
+ int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
+
+ /* maybe its not chained */
+ if (smb_com2 == 0xFF) {
+ CVAL(outbuf,smb_vwv0) = 0xFF;
+ return outsize;
+ }
+
+ if (chain_size == 0) {
+ /* this is the first part of the chain */
+ orig_inbuf = inbuf;
+ orig_outbuf = outbuf;
+ }
+
+ /*
+ * The original Win95 redirector dies on a reply to
+ * a lockingX and read chain unless the chain reply is
+ * 4 byte aligned. JRA.
+ */
+
+ outsize = (outsize + 3) & ~3;
+
+ /* we need to tell the client where the next part of the reply will be */
+ SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
+ CVAL(outbuf,smb_vwv0) = smb_com2;
+
+ /* remember how much the caller added to the chain, only counting stuff
+ after the parameter words */
+ chain_size += outsize - smb_wct;
+
+ /* work out pointers into the original packets. The
+ headers on these need to be filled in */
+ inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
+ outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
+
+ /* remember the original command type */
+ smb_com1 = CVAL(orig_inbuf,smb_com);
+
+ /* save the data which will be overwritten by the new headers */
+ memcpy(inbuf_saved,inbuf2,smb_wct);
+ memcpy(outbuf_saved,outbuf2,smb_wct);
+
+ /* give the new packet the same header as the last part of the SMB */
+ memmove(inbuf2,inbuf,smb_wct);
+
+ /* create the in buffer */
+ CVAL(inbuf2,smb_com) = smb_com2;
+
+ /* create the out buffer */
+ construct_reply_common(inbuf2, outbuf2);
+
+ DEBUG(3,("Chained message\n"));
+ show_msg(inbuf2);
+
+ /* process the request */
+ outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
+ bufsize-chain_size);
+
+ /* copy the new reply and request headers over the old ones, but
+ preserve the smb_com field */
+ memmove(orig_outbuf,outbuf2,smb_wct);
+ CVAL(orig_outbuf,smb_com) = smb_com1;
+
+ /* restore the saved data, being careful not to overwrite any
+ data from the reply header */
+ memcpy(inbuf2,inbuf_saved,smb_wct);
+ {
+ int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
+ if (ofs < 0) ofs = 0;
+ memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
+ }
+
+ return outsize2;
+}
+
+/****************************************************************************
+ Setup the needed select timeout.
+****************************************************************************/
+
+static int setup_select_timeout(void)
+{
+ int select_timeout;
+ int t;
+
+ /*
+ * Increase the select timeout back to SMBD_SELECT_TIMEOUT if we
+ * have removed any blocking locks. JRA.
+ */
+
+ select_timeout = blocking_locks_pending() ? SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS*1000 :
+ SMBD_SELECT_TIMEOUT*1000;
+
+ t = change_notify_timeout();
+ if (t != -1) select_timeout = MIN(select_timeout, t*1000);
+
+ return select_timeout;
+}
+
+/****************************************************************************
+ Check if services need reloading.
+****************************************************************************/
+
+void check_reload(int t)
+{
+ static time_t last_smb_conf_reload_time = 0;
+
+ if(last_smb_conf_reload_time == 0)
+ last_smb_conf_reload_time = t;
+
+ if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK))
+ {
+ reload_services(True);
+ reload_after_sighup = False;
+ last_smb_conf_reload_time = t;
+ }
+}
+
+/****************************************************************************
+ Process any timeout housekeeping. Return False if the caller should exit.
+****************************************************************************/
+
+static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
+{
+ static time_t last_keepalive_sent_time = 0;
+ static time_t last_idle_closed_check = 0;
+ time_t t;
+ BOOL allidle = True;
+ extern int keepalive;
+
+ if (smb_read_error == READ_EOF)
+ {
+ DEBUG(3,("end of file from client\n"));
+ return False;
+ }
+
+ if (smb_read_error == READ_ERROR)
+ {
+ DEBUG(3,("receive_smb error (%s) exiting\n",
+ strerror(errno)));
+ return False;
+ }
+
+ *last_timeout_processing_time = t = time(NULL);
+
+ if(last_keepalive_sent_time == 0)
+ last_keepalive_sent_time = t;
+
+ if(last_idle_closed_check == 0)
+ last_idle_closed_check = t;
+
+ /* become root again if waiting */
+ change_to_root_user();
+
+ /* check if we need to reload services */
+ check_reload(t);
+
+ /* automatic timeout if all connections are closed */
+ if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT)
+ {
+ DEBUG( 2, ( "Closing idle connection\n" ) );
+ return False;
+ }
+ else
+ last_idle_closed_check = t;
+
+ if (keepalive && (t - last_keepalive_sent_time)>keepalive)
+ {
+ extern auth_authsupplied_info *negprot_global_auth_info;
+ if (!send_keepalive(smbd_server_fd())) {
+ DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
+ return False;
+ }
+
+ /* send a keepalive for a password server or the like.
+ This is attached to the auth_info created in the
+ negprot */
+ if (negprot_global_auth_info
+ && negprot_global_auth_info->challenge_set_method
+ && negprot_global_auth_info->challenge_set_method->send_keepalive) {
+ negprot_global_auth_info->challenge_set_method->send_keepalive
+ (&negprot_global_auth_info->challenge_set_method->private_data);
+ }
+
+ last_keepalive_sent_time = t;
+ }
+
+ /* check for connection timeouts */
+ allidle = conn_idle_all(t, deadtime);
+
+ if (allidle && conn_num_open()>0) {
+ DEBUG(2,("Closing idle connection 2.\n"));
+ return False;
+ }
+
+ if(global_machine_password_needs_changing &&
+ /* for ADS we need to do a regular ADS password change, not a domain
+ password change */
+ lp_security() == SEC_DOMAIN)
+ {
+ unsigned char trust_passwd_hash[16];
+ time_t lct;
+ pstring remote_machine_list;
+
+ /*
+ * We're in domain level security, and the code that
+ * read the machine password flagged that the machine
+ * password needs changing.
+ */
+
+ /*
+ * First, open the machine password file with an exclusive lock.
+ */
+
+ if(!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd_hash, &lct)) {
+ DEBUG(0,("process: unable to read the machine account password for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ return True;
+ }
+
+ /*
+ * Make sure someone else hasn't already done this.
+ */
+
+ if(t < lct + lp_machine_password_timeout()) {
+ global_machine_password_needs_changing = False;
+ return True;
+ }
+
+ pstrcpy(remote_machine_list, lp_passwordserver());
+
+ change_trust_account_password( global_myworkgroup, remote_machine_list);
+ global_machine_password_needs_changing = False;
+ }
+
+ /*
+ * Check to see if we have any blocking locks
+ * outstanding on the queue.
+ */
+ process_blocking_lock_queue(t);
+
+ /*
+ * Check to see if we have any change notifies
+ * outstanding on the queue.
+ */
+ process_pending_change_notify_queue(t);
+
+ /*
+ * Now we are root, check if the log files need pruning.
+ * Force a log file check.
+ */
+ force_check_log_size();
+ check_log_size();
+
+ /*
+ * Modify the select timeout depending upon
+ * what we have remaining in our queues.
+ */
+
+ *select_timeout = setup_select_timeout();
+
+ return True;
+}
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+
+void smbd_process(void)
+{
+ extern int smb_echo_count;
+ time_t last_timeout_processing_time = time(NULL);
+ unsigned int num_smbs = 0;
+
+ InBuffer = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
+ OutBuffer = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
+ if ((InBuffer == NULL) || (OutBuffer == NULL))
+ return;
+
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+
+ /* re-initialise the timezone */
+ TimeInit();
+
+ /* register our message handlers */
+ message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis);
+
+ while (True) {
+ int deadtime = lp_deadtime()*60;
+ int select_timeout = setup_select_timeout();
+ int num_echos;
+
+ if (deadtime <= 0)
+ deadtime = DEFAULT_SMBD_TIMEOUT;
+
+ errno = 0;
+
+ /* free up temporary memory */
+ lp_talloc_free();
+ main_loop_talloc_free();
+
+ while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
+ }
+
+ /*
+ * Ensure we do timeout processing if the SMB we just got was
+ * only an echo request. This allows us to set the select
+ * timeout in 'receive_message_or_smb()' to any value we like
+ * without worrying that the client will send echo requests
+ * faster than the select timeout, thus starving out the
+ * essential processing (change notify, blocking locks) that
+ * the timeout code does. JRA.
+ */
+ num_echos = smb_echo_count;
+
+ process_smb(InBuffer, OutBuffer);
+
+ if (smb_echo_count != num_echos) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
+ }
+
+ num_smbs++;
+
+ /*
+ * If we are getting smb requests in a constant stream
+ * with no echos, make sure we attempt timeout processing
+ * every select_timeout milliseconds - but only check for this
+ * every 200 smb requests.
+ */
+
+ if ((num_smbs % 200) == 0) {
+ time_t new_check_time = time(NULL);
+ if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
+ last_timeout_processing_time = new_check_time; /* Reset time. */
+ }
+ }
+ }
+}
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
new file mode 100644
index 00000000000..73391e6c0df
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,1098 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ support for quotas
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/*
+ * This is one of the most system dependent parts of Samba, and its
+ * done a litle differently. Each system has its own way of doing
+ * things :-(
+ */
+
+#include "includes.h"
+
+#if defined(VXFS_QUOTA)
+
+/*
+ * In addition to their native filesystems, some systems have Veritas VxFS.
+ * Declare here, define at end: reduces likely "include" interaction problems.
+ * David Lee <T.D.Lee@durham.ac.uk>
+ */
+BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
+
+#endif /* VXFS_QUOTA */
+
+#ifdef LINUX
+
+#include <sys/types.h>
+#include <asm/types.h>
+
+/*
+ * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
+ * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk
+ * rather than the struct dqblk defined in /usr/include/sys/quota.h.
+ * This means we must include linux/quota.h to have a hope of working on
+ * RH7.1 systems. And it also means this breaks if the kernel is upgraded
+ * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until
+ * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA.
+ */
+
+#include <linux/quota.h>
+#ifdef HAVE_LINUX_XQM_H
+#include <linux/xqm.h>
+#endif
+
+#include <mntent.h>
+#include <linux/unistd.h>
+
+
+#define LINUX_QUOTAS_2
+
+typedef struct _LINUX_SMB_DISK_QUOTA {
+ SMB_BIG_UINT bsize;
+ SMB_BIG_UINT hardlimit; /* In bsize units. */
+ SMB_BIG_UINT softlimit; /* In bsize units. */
+ SMB_BIG_UINT curblocks; /* In bsize units. */
+ SMB_BIG_UINT ihardlimit; /* inode hard limit. */
+ SMB_BIG_UINT isoftlimit; /* inode soft limit. */
+ SMB_BIG_UINT curinodes; /* Current used inodes. */
+} LINUX_SMB_DISK_QUOTA;
+
+/****************************************************************************
+ Abstract out the XFS Quota Manager quota get call.
+****************************************************************************/
+
+static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ int ret = -1;
+#ifdef HAVE_LINUX_XQM_H
+ struct fs_disk_quota D;
+ ZERO_STRUCT(D);
+
+ if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ return ret;
+
+ dp->bsize = (SMB_BIG_UINT)512;
+ dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.d_icount;
+ dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Abstract out the old and new Linux quota get calls.
+****************************************************************************/
+
+static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ int ret;
+#ifdef LINUX_QUOTAS_1
+ struct dqblk D;
+ ZERO_STRUCT(D);
+ dp->bsize = (SMB_BIG_UINT)1024;
+#else /* LINUX_QUOTAS_2 */
+ struct mem_dqblk D;
+ ZERO_STRUCT(D);
+#ifndef QUOTABLOCK_SIZE
+#define QUOTABLOCK_SIZE 1024
+#endif
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+#endif
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ return -1;
+
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+
+#ifdef LINUX_QUOTAS_1
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
+#else /* LINUX_QUOTAS_2 */
+ dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize;
+#endif
+
+ return 0;
+}
+
+/****************************************************************************
+try to get the disk space from disk quotas (LINUX version)
+****************************************************************************/
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r;
+ SMB_STRUCT_STAT S;
+ FILE *fp;
+ LINUX_SMB_DISK_QUOTA D;
+ struct mntent *mnt;
+ SMB_DEV_T devno;
+ int found;
+ uid_t euser_id;
+
+ euser_id = geteuid();
+
+ /* find the block device file */
+
+ if ( sys_stat(path, &S) == -1 )
+ return(False) ;
+
+ devno = S.st_dev ;
+
+ fp = setmntent(MOUNTED,"r");
+ found = False ;
+
+ while ((mnt = getmntent(fp))) {
+ if ( sys_stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+
+ if (S.st_dev == devno) {
+ found = True ;
+ break;
+ }
+ }
+
+ endmntent(fp) ;
+
+ if (!found)
+ return(False);
+
+ save_re_uid();
+ set_effective_uid(0);
+ if (strcmp(mnt->mnt_type, "xfs") == 0)
+ r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
+ else
+ r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
+ restore_re_uid();
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ *bsize = D.bsize;
+ if (r == -1) {
+ if (errno == EDQUOT) {
+ *dfree =0;
+ *dsize =D.curblocks;
+ return (True);
+ } else {
+ return(False);
+ }
+ }
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.softlimit && D.curblocks >= D.softlimit) ||
+ (D.hardlimit && D.curblocks >= D.hardlimit) ||
+ (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
+ (D.ihardlimit && D.curinodes>=D.ihardlimit)
+ ) {
+ *dfree = 0;
+ *dsize = D.curblocks;
+ } else if (D.softlimit==0 && D.hardlimit==0) {
+ return(False);
+ } else {
+ if (D.softlimit == 0)
+ D.softlimit = D.hardlimit;
+ *dfree = D.softlimit - D.curblocks;
+ *dsize = D.softlimit;
+ }
+
+ return (True);
+}
+
+#elif defined(CRAY)
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (CRAY VERSION)
+****************************************************************************/
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ struct mntent *mnt;
+ FILE *fd;
+ SMB_STRUCT_STAT sbuf;
+ SMB_DEV_T devno ;
+ static SMB_DEV_T devno_cached = 0 ;
+ static pstring name;
+ struct q_request request ;
+ struct qf_header header ;
+ static int quota_default = 0 ;
+ int found ;
+
+ if ( sys_stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+
+ if ( devno != devno_cached ) {
+
+ devno_cached = devno ;
+
+ if ((fd = setmntent(KMTAB)) == NULL)
+ return(False) ;
+
+ found = False ;
+
+ while ((mnt = getmntent(fd)) != NULL) {
+
+ if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+
+ if (sbuf.st_dev == devno) {
+
+ found = True ;
+ break ;
+
+ }
+
+ }
+
+ pstrcpy(name,mnt->mnt_dir) ;
+ endmntent(fd) ;
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ request.qf_magic = QF_MAGIC ;
+ request.qf_entry.id = geteuid() ;
+
+ if (quotactl(name, Q_GETQUOTA, &request) == -1)
+ return(False) ;
+
+ if ( ! request.user )
+ return(False) ;
+
+ if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
+
+ if ( ! quota_default ) {
+
+ if ( quotactl(name, Q_GETHEADER, &header) == -1 )
+ return(False) ;
+ else
+ quota_default = header.user_h.def_fq ;
+ }
+
+ *dfree = quota_default ;
+
+ }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
+
+ *dfree = 0 ;
+
+ }else{
+
+ *dfree = request.qf_entry.user_q.f_quota ;
+
+ }
+
+ *dsize = request.qf_entry.user_q.f_use ;
+
+ if ( *dfree < *dsize )
+ *dfree = 0 ;
+ else
+ *dfree -= *dsize ;
+
+ *bsize = 4096 ; /* Cray blocksize */
+
+ return(True) ;
+
+}
+
+
+#elif defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#include <sys/param.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#include <sys/mntent.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+#if defined(SUNOS5)
+
+/****************************************************************************
+ Allows querying of remote hosts for quotas on NFS mounted shares.
+ Supports normal NFS and AMD mounts.
+ Alan Romeril <a.romeril@ic.ac.uk> July 2K.
+****************************************************************************/
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/rquota.h>
+#include <rpc/nettype.h>
+#include <rpc/xdr.h>
+
+static int quotastat;
+
+static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
+{
+ if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
+ return(0);
+ if (!xdr_int(xdrsp, &args->gqa_uid))
+ return(0);
+ return (1);
+}
+
+static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
+{
+ if (!xdr_int(xdrsp, &quotastat)) {
+ DEBUG(6,("nfs_quotas: Status bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
+ DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
+ DEBUG(6,("nfs_quotas: Active bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
+ DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
+ DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
+ DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
+ return 0;
+ }
+ return (1);
+}
+
+/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
+static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t uid = euser_id;
+ struct dqblk D;
+ char *mnttype = nfspath;
+ CLIENT *clnt;
+ struct getquota_rslt gqr;
+ struct getquota_args args;
+ char *cutstr, *pathname, *host, *testpath;
+ int len;
+ static struct timeval timeout = {2,0};
+ enum clnt_stat clnt_stat;
+ BOOL ret = True;
+
+ *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
+
+ len=strcspn(mnttype, ":");
+ pathname=strstr(mnttype, ":");
+ cutstr = (char *) malloc(sizeof(char) * len );
+ if (!cutstr)
+ return False;
+
+ host = strncat(cutstr,mnttype, sizeof(char) * len );
+ DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
+ DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
+ testpath=strchr_m(mnttype, ':');
+ args.gqa_pathp = testpath+1;
+ args.gqa_uid = uid;
+
+ DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
+
+ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
+ ret = False;
+ goto out;
+ }
+
+ clnt->cl_auth = authunix_create_default();
+ DEBUG(9,("nfs_quotas: auth_success\n"));
+
+ clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
+
+ if (clnt_stat != RPC_SUCCESS) {
+ DEBUG(9,("nfs_quotas: clnt_call fail\n"));
+ ret = False;
+ goto out;
+ }
+
+ /*
+ * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
+ * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
+ * something sensible.
+ */
+
+ switch ( quotastat ) {
+ case 0:
+ DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
+ ret = False;
+ goto out;
+
+ case 1:
+ DEBUG(9,("nfs_quotas: Good quota data\n"));
+ D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
+ D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
+ D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
+ break;
+
+ case 2:
+ case 3:
+ D.dqb_bsoftlimit = 1;
+ D.dqb_curblocks = 1;
+ DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
+ break;
+
+ default:
+ DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
+ break;
+ }
+
+ DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
+ quotastat,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
+ gqr.getquota_rslt_u.gqr_rquota.rq_active,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
+
+ *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks == D.dqb_curblocks == 1)
+ *bsize = 512;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ out:
+
+ if (clnt) {
+ if (clnt->cl_auth)
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ SAFE_FREE(cutstr);
+ DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
+ return ret;
+}
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (SunOS & Solaris2 version)
+Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
+****************************************************************************/
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t euser_id;
+ int ret;
+ struct dqblk D;
+#if defined(SUNOS5)
+ struct quotctl command;
+ int file;
+ static struct mnttab mnt;
+ static pstring name;
+ pstring devopt;
+#else /* SunOS4 */
+ struct mntent *mnt;
+ static pstring name;
+#endif
+ FILE *fd;
+ SMB_STRUCT_STAT sbuf;
+ SMB_DEV_T devno ;
+ static SMB_DEV_T devno_cached = 0 ;
+ static int found ;
+
+ euser_id = geteuid();
+
+ if ( sys_stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+ DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
+ if ( devno != devno_cached ) {
+ devno_cached = devno ;
+#if defined(SUNOS5)
+ if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
+ while (getmntent(fd, &mnt) == 0) {
+ if( !hasmntopt(&mnt, devopt) )
+ continue;
+
+ DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
+
+ /* quotas are only on vxfs, UFS or NFS */
+ if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
+ strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
+ strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
+ found = True ;
+ break;
+ }
+ }
+
+ pstrcpy(name,mnt.mnt_mountp) ;
+ pstrcat(name,"/quotas") ;
+ fclose(fd) ;
+#else /* SunOS4 */
+ if ((fd = setmntent(MOUNTED, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while ((mnt = getmntent(fd)) != NULL) {
+ if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break;
+ }
+ }
+
+ pstrcpy(name,mnt->mnt_fsname) ;
+ endmntent(fd) ;
+#endif
+ }
+
+ if ( ! found )
+ return(False) ;
+
+ save_re_uid();
+ set_effective_uid(0);
+
+#if defined(SUNOS5)
+ if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
+ BOOL retval;
+ DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
+ retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
+ restore_re_uid();
+ return retval;
+ }
+
+ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
+ if((file=sys_open(name, O_RDONLY,0))<0) {
+ restore_re_uid();
+ return(False);
+ }
+ command.op = Q_GETQUOTA;
+ command.uid = euser_id;
+ command.addr = (caddr_t) &D;
+ ret = ioctl(file, Q_QUOTACTL, &command);
+ close(file);
+#else
+ DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
+ ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
+#endif
+
+ restore_re_uid();
+
+ if (ret < 0) {
+ DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
+
+#if defined(SUNOS5) && defined(VXFS_QUOTA)
+ /* If normal quotactl() fails, try vxfs private calls */
+ set_effective_uid(euser_id);
+ DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
+ if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
+ BOOL retval;
+ retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
+ return(retval);
+ }
+#else
+ return(False);
+#endif
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ /* Use softlimit to determine disk space. A user exceeding the quota is told
+ * that there's no space left. Writes might actually work for a bit if the
+ * hardlimit is set higher than softlimit. Effectively the disk becomes
+ * made of rubber latex and begins to expand to accommodate the user :-)
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = DEV_BSIZE;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
+ path,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ return(True);
+}
+
+
+#elif defined(OSF1)
+#include <ufs/quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - OSF1 version
+****************************************************************************/
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r, save_errno;
+ struct dqblk D;
+ SMB_STRUCT_STAT S;
+ uid_t euser_id;
+
+ /*
+ * This code presumes that OSF1 will only
+ * give out quota info when the real uid
+ * matches the effective uid. JRA.
+ */
+ euser_id = geteuid();
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
+
+ r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
+ if (r) {
+ save_errno = errno;
+ }
+
+ restore_re_uid();
+
+ *bsize = DEV_BSIZE;
+
+ if (r)
+ {
+ if (save_errno == EDQUOT) /* disk quota exceeded */
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ return (True);
+ }
+ else
+ return (False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#elif defined (IRIX6)
+/****************************************************************************
+try to get the disk space from disk quotas (IRIX 6.2 version)
+****************************************************************************/
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+ struct fs_disk_quota F;
+ SMB_STRUCT_STAT S;
+ FILE *fp;
+ struct mntent *mnt;
+ SMB_DEV_T devno;
+ int found;
+
+ /* find the block device file */
+
+ if ( sys_stat(path, &S) == -1 ) {
+ return(False) ;
+ }
+
+ devno = S.st_dev ;
+
+ fp = setmntent(MOUNTED,"r");
+ found = False ;
+
+ while ((mnt = getmntent(fp))) {
+ if ( sys_stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+ if (S.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+ endmntent(fp) ;
+
+ if (!found) {
+ return(False);
+ }
+
+ euser_id=geteuid();
+ save_re_uid();
+ set_effective_uid(0);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+
+ *bsize = 512;
+
+ if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
+ {
+ r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
+
+ restore_re_uid();
+
+ if (r==-1)
+ return(False);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+ (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+ (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
+ (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+
+ }
+ else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
+ {
+ r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
+
+ restore_re_uid();
+
+ if (r==-1)
+ return(False);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
+ (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
+ (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
+ (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = F.d_bcount;
+ }
+ else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ *dfree = (F.d_blk_softlimit - F.d_bcount);
+ *dsize = F.d_blk_softlimit;
+ }
+
+ }
+ else
+ {
+ restore_re_uid();
+ return(False);
+ }
+
+ return (True);
+
+}
+
+#else
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#include <ufs/ufs/quota.h>
+#include <machine/param.h>
+#elif AIX
+/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
+#include <jfs/quota.h>
+/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
+#define dqb_curfiles dqb_curinodes
+#define dqb_fhardlimit dqb_ihardlimit
+#define dqb_fsoftlimit dqb_isoftlimit
+#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
+#include <sys/quota.h>
+#include <devnm.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas - default version
+****************************************************************************/
+
+BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ int r;
+ struct dqblk D;
+ uid_t euser_id;
+#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
+ char dev_disk[256];
+ SMB_STRUCT_STAT S;
+ /* find the block device file */
+ if ((sys_stat(path, &S)<0) ||
+ (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
+#endif
+
+ euser_id = geteuid();
+
+#ifdef HPUX
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
+
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+
+ restore_re_uid();
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ {
+ /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
+ gid_t egrp_id;
+
+ save_re_uid();
+ set_effective_uid(0);
+
+ egrp_id = getegid();
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+
+ /* As FreeBSD has group quotas, if getting the user
+ quota fails, try getting the group instead. */
+ if (r) {
+ r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
+ }
+
+ restore_re_uid();
+ }
+#elif defined(AIX)
+ /* AIX has both USER and GROUP quotas:
+ Get the USER quota (ohnielse@fysik.dtu.dk) */
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
+#endif /* HPUX */
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ *bsize = DEV_BSIZE;
+#else /* !__FreeBSD__ && !__OpenBSD__ */
+ *bsize = 1024;
+#endif /*!__FreeBSD__ && !__OpenBSD__ */
+
+ if (r)
+ {
+ if (errno == EDQUOT)
+ {
+ *dfree =0;
+ *dsize =D.dqb_curblocks;
+ return (True);
+ }
+ else return(False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
+||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
+#endif
+ ) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#endif
+
+#if defined(VXFS_QUOTA)
+
+/****************************************************************************
+Try to get the disk space from Veritas disk quotas.
+ David Lee <T.D.Lee@durham.ac.uk> August 1999.
+
+Background assumptions:
+ Potentially under many Operating Systems. Initially Solaris 2.
+
+ My guess is that Veritas is largely, though not entirely,
+ independent of OS. So I have separated it out.
+
+ There may be some details. For example, OS-specific "include" files.
+
+ It is understood that HPUX 10 somehow gets Veritas quotas without
+ any special effort; if so, this routine need not be compiled in.
+ Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
+
+Warning:
+ It is understood that Veritas do not publicly support this ioctl interface.
+ Rather their preference would be for the user (us) to call the native
+ OS and then for the OS itself to call through to the VxFS filesystem.
+ Presumably HPUX 10, see above, does this.
+
+Hints for porting:
+ Add your OS to "IFLIST" below.
+ Get it to compile successfully:
+ Almost certainly "include"s require attention: see SUNOS5.
+ In the main code above, arrange for it to be called: see SUNOS5.
+ Test!
+
+****************************************************************************/
+
+/* "IFLIST"
+ * This "if" is a list of ports:
+ * if defined(OS1) || defined(OS2) || ...
+ */
+#if defined(SUNOS5)
+
+#if defined(SUNOS5)
+#include <sys/fs/vx_solaris.h>
+#endif
+#include <sys/fs/vx_machdep.h>
+#include <sys/fs/vx_layout.h>
+#include <sys/fs/vx_quota.h>
+#include <sys/fs/vx_aioctl.h>
+#include <sys/fs/vx_ioctl.h>
+
+BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t user_id, euser_id;
+ int ret;
+ struct vx_dqblk D;
+ struct vx_quotctl quotabuf;
+ struct vx_genioctl genbuf;
+ pstring qfname;
+ int file;
+
+ /*
+ * "name" may or may not include a trailing "/quotas".
+ * Arranging consistency of calling here in "quotas.c" may not be easy and
+ * it might be easier to examine and adjust it here.
+ * Fortunately, VxFS seems not to mind at present.
+ */
+ pstrcpy(qfname, name) ;
+ /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
+
+ euser_id = geteuid();
+ set_effective_uid(0);
+
+ DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
+ if((file=sys_open(qfname, O_RDONLY,0))<0) {
+ set_effective_uid(euser_id);
+ return(False);
+ }
+ genbuf.ioc_cmd = VX_QUOTACTL;
+ genbuf.ioc_up = (void *) &quotabuf;
+
+ quotabuf.cmd = VX_GETQUOTA;
+ quotabuf.uid = euser_id;
+ quotabuf.addr = (caddr_t) &D;
+ ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
+ close(file);
+
+ set_effective_uid(euser_id);
+
+ if (ret < 0) {
+ DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
+ return(False);
+ }
+
+ /* If softlimit is zero, set it equal to hardlimit.
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+
+ /* Use softlimit to determine disk space. A user exceeding the quota is told
+ * that there's no space left. Writes might actually work for a bit if the
+ * hardlimit is set higher than softlimit. Effectively the disk becomes
+ * made of rubber latex and begins to expand to accommodate the user :-)
+ */
+ DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
+ path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
+ D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = DEV_BSIZE;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
+ path,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ return(True);
+}
+
+#endif /* SUNOS5 || ... */
+
+#endif /* VXFS_QUOTA */
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index b7b51775bb8..00e0cb8b863 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -2,8 +2,9 @@
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB reply routines
- Copyright (C) Andrew Tridgell 1992-1995
-
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett 2001
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -25,222 +26,281 @@
#include "includes.h"
-#include "loadparm.h"
-#include "trans2.h"
/* look in server.c for some explanation of these variables */
extern int Protocol;
-extern int DEBUGLEVEL;
-extern int chain_size;
-extern int maxxmit;
-extern int chain_fnum;
+extern int max_send;
+extern int max_recv;
extern char magic_char;
-extern connection_struct Connections[];
-extern files_struct Files[];
extern BOOL case_sensitive;
-extern pstring sesssetup_user;
-extern int Client;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
+extern pstring global_myname;
+extern int global_oplock_break;
+unsigned int smb_echo_count = 0;
-/* this macro should always be used to extract an fnum (smb_fid) from
-a packet to ensure chaining works correctly */
-#define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
+extern fstring remote_machine;
+extern BOOL global_encrypted_passwords_negotiated;
/****************************************************************************
reply to an special message
****************************************************************************/
+
int reply_special(char *inbuf,char *outbuf)
{
- int outsize = 4;
- int msg_type = CVAL(inbuf,0);
- int msg_flags = CVAL(inbuf,1);
- pstring name1,name2;
- extern fstring remote_machine;
- extern fstring local_machine;
- char *p;
+ int outsize = 4;
+ int msg_type = CVAL(inbuf,0);
+ int msg_flags = CVAL(inbuf,1);
+ pstring name1,name2;
+
+ extern fstring local_machine;
+ int len;
+ char name_type = 0;
+
+ *name1 = *name2 = 0;
+
+ memset(outbuf,'\0',smb_size);
- *name1 = *name2 = 0;
+ smb_setlen(outbuf,0);
+
+ switch (msg_type) {
+ case 0x81: /* session request */
+ CVAL(outbuf,0) = 0x82;
+ CVAL(outbuf,3) = 0;
+ if (name_len(inbuf+4) > 50 ||
+ name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+ DEBUG(0,("Invalid name length in session request\n"));
+ return(0);
+ }
+ name_extract(inbuf,4,name1);
+ name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+ DEBUG(2,("netbios connect: name1=%s name2=%s\n",
+ name1,name2));
+
+ fstrcpy(remote_machine,name2);
+ remote_machine[15] = 0;
+ trim_string(remote_machine," "," ");
+ strlower(remote_machine);
+ alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
+
+ fstrcpy(local_machine,name1);
+ len = strlen(local_machine);
+ if (len == 16) {
+ name_type = local_machine[15];
+ local_machine[15] = 0;
+ }
+ trim_string(local_machine," "," ");
+ strlower(local_machine);
+ alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
+
+ DEBUG(2,("netbios connect: local=%s remote=%s\n",
+ local_machine, remote_machine ));
+
+ if (name_type == 'R') {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ CVAL(outbuf, 0) = 0x83;
+ break;
+ }
- smb_setlen(outbuf,0);
+ /* only add the client's machine name to the list
+ of possibly valid usernames if we are operating
+ in share mode security */
+ if (lp_security() == SEC_SHARE) {
+ add_session_user(remote_machine);
+ }
- switch (msg_type)
- {
- case 0x81: /* session request */
- CVAL(outbuf,0) = 0x82;
- CVAL(outbuf,3) = 0;
- if (name_len(inbuf+4) > 50)
- {
- DEBUG(0,("Invalid name length in session request\n"));
- return(0);
+ reload_services(True);
+ reopen_logs();
+
+ claim_connection(NULL,"",MAXSTATUS,True);
+
+ break;
+
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ CVAL(outbuf,0) = SMBkeepalive;
+ CVAL(outbuf,3) = 0;
+ break;
+
+ case 0x82: /* positive session response */
+ case 0x83: /* negative session response */
+ case 0x84: /* retarget session response */
+ DEBUG(0,("Unexpected session response\n"));
+ break;
+
+ case SMBkeepalive: /* session keepalive */
+ default:
+ return(0);
}
- name_extract(inbuf,4,name1);
- name_extract(inbuf,4 + name_len(inbuf + 4),name2);
- DEBUG(2,("netbios connect: name1=%s name2=%s\n",name1,name2));
-
- strcpy(remote_machine,name2);
- trim_string(remote_machine," "," ");
- p = strchr(remote_machine,' ');
- strlower(remote_machine);
- if (p) *p = 0;
-
- strcpy(local_machine,name1);
- trim_string(local_machine," "," ");
- p = strchr(local_machine,' ');
- strlower(local_machine);
- if (p) *p = 0;
-
- add_session_user(remote_machine);
-
- reload_services(True);
- reopen_logs();
-
- break;
- case 0x85: /* session keepalive */
- default:
- return(0);
- }
-
- DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
-
- return(outsize);
-}
-
-
-/*******************************************************************
-work out what error to give to a failed connection
-********************************************************************/
-static int connection_error(char *inbuf,char *outbuf,int connection_num)
-{
- switch (connection_num)
- {
- case -8:
- return(ERROR(ERRSRV,ERRnoresource));
- case -7:
- return(ERROR(ERRSRV,ERRbaduid));
- case -6:
- return(ERROR(ERRSRV,ERRinvdevice));
- case -5:
- return(ERROR(ERRSRV,ERRinvnetname));
- case -4:
- return(ERROR(ERRSRV,ERRaccess));
- case -3:
- return(ERROR(ERRDOS,ERRnoipc));
- case -2:
- return(ERROR(ERRSRV,ERRinvnetname));
- }
- return(ERROR(ERRSRV,ERRbadpw));
+
+ DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
+ msg_type, msg_flags));
+
+ return(outsize);
}
/****************************************************************************
- reply to a tcon
+ Reply to a tcon.
****************************************************************************/
-int reply_tcon(char *inbuf,char *outbuf)
+
+int reply_tcon(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- pstring service;
- pstring user;
- pstring password;
- pstring dev;
- int connection_num;
- int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int pwlen;
+ pstring service;
+ pstring password;
+ pstring dev;
+ int outsize = 0;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int pwlen=0;
+ NTSTATUS nt_status;
+ char *p;
+ DATA_BLOB password_blob;
+
+ START_PROFILE(SMBtcon);
- *service = *user = *password = *dev = 0;
+ *service = *password = *dev = 0;
- vuid = valid_uid(uid);
-
- parse_connect(inbuf,service,user,password,&pwlen,dev);
+ p = smb_buf(inbuf)+1;
+ p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
+ pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
+ p += pwlen;
+ p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
- connection_num = make_connection(service,user,password,pwlen,dev,vuid);
+ p = strrchr_m(service,'\\');
+ if (p) {
+ pstrcpy(service, p+1);
+ }
+
+ password_blob = data_blob(password, pwlen+1);
+
+ conn = make_connection(service,password_blob,dev,vuid,&nt_status);
+
+ data_blob_clear_free(&password_blob);
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ if (!conn) {
+ END_PROFILE(SMBtcon);
+ return ERROR_NT(nt_status);
+ }
- outsize = set_message(outbuf,2,0,True);
- SSVAL(outbuf,smb_vwv0,maxxmit);
- SSVAL(outbuf,smb_vwv1,connection_num);
- SSVAL(outbuf,smb_tid,connection_num);
+ outsize = set_message(outbuf,2,0,True);
+ SSVAL(outbuf,smb_vwv0,max_recv);
+ SSVAL(outbuf,smb_vwv1,conn->cnum);
+ SSVAL(outbuf,smb_tid,conn->cnum);
- DEBUG(3,("%s tcon service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
+ DEBUG(3,("tcon service=%s cnum=%d\n",
+ service, conn->cnum));
- return(outsize);
+ END_PROFILE(SMBtcon);
+ return(outsize);
}
-
/****************************************************************************
- reply to a tcon and X
+ Reply to a tcon and X.
****************************************************************************/
-int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- pstring service;
- pstring user;
- pstring password;
- pstring devicename;
- int connection_num;
- int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int smb_com2 = SVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int passlen = SVAL(inbuf,smb_vwv3);
+ fstring service;
+ DATA_BLOB password;
+ pstring devicename;
+ NTSTATUS nt_status;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int passlen = SVAL(inbuf,smb_vwv3);
+ pstring path;
+ char *p, *q;
+ extern BOOL global_encrypted_passwords_negotiated;
+ START_PROFILE(SMBtconX);
+
+ *service = *devicename = 0;
+
+ /* we might have to close an old one */
+ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
+ close_cnum(conn,vuid);
+ }
- *service = *user = *password = *devicename = 0;
+ if (passlen > MAX_PASS_LEN) {
+ return ERROR_DOS(ERRDOS,ERRbuftoosmall);
+ }
+
+ if (global_encrypted_passwords_negotiated) {
+ password = data_blob(smb_buf(inbuf),passlen);
+ } else {
+ password = data_blob(smb_buf(inbuf),passlen+1);
+ /* Ensure correct termination */
+ password.data[passlen]=0;
+ }
- /* we might have to close an old one */
- if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
- close_cnum(SVAL(inbuf,smb_tid),uid);
-
- vuid = valid_uid(uid);
-
- {
- char *path;
- char *p;
- memcpy(password,smb_buf(inbuf),passlen);
- password[passlen]=0;
- path = smb_buf(inbuf) + passlen;
- DEBUG(4,("parsing net-path %s, passlen=%d\n",path,passlen));
- strcpy(service,path+2);
- p = strchr(service,'\\');
- if (!p)
- return(ERROR(ERRSRV,ERRinvnetname));
- *p = 0;
- strcpy(service,p+1);
- p = strchr(service,'%');
- if (p)
- {
- *p++ = 0;
- strcpy(user,p);
- }
- StrnCpy(devicename,path + strlen(path) + 1,6);
- DEBUG(4,("Got device type %s\n",devicename));
- }
+ p = smb_buf(inbuf) + passlen;
+ p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+
+ /*
+ * the service name can be either: \\server\share
+ * or share directly like on the DELL PowerVault 705
+ */
+ if (*path=='\\') {
+ q = strchr_m(path+2,'\\');
+ if (!q) {
+ END_PROFILE(SMBtconX);
+ return(ERROR_DOS(ERRDOS,ERRnosuchshare));
+ }
+ fstrcpy(service,q+1);
+ }
+ else
+ fstrcpy(service,path);
+
+ p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII);
- connection_num = make_connection(service,user,password,passlen,devicename,vuid);
-
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ DEBUG(4,("Got device type %s\n",devicename));
- outsize = set_message(outbuf,2,strlen(devicename)+1,True);
-
- DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
-
- /* set the incoming and outgoing tid to the just created one */
- SSVAL(inbuf,smb_tid,connection_num);
- SSVAL(outbuf,smb_tid,connection_num);
+ conn = make_connection(service,password,devicename,vuid,&nt_status);
+
+ data_blob_clear_free(&password);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size + outsize)-4);
+ if (!conn) {
+ END_PROFILE(SMBtconX);
+ return ERROR_NT(nt_status);
+ }
- strcpy(smb_buf(outbuf),devicename);
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,2,0,True);
+ p = smb_buf(outbuf);
+ p += srvstr_push(outbuf, p, devicename, -1,
+ STR_TERMINATE|STR_ASCII);
+ set_message_end(outbuf,p);
+ } else {
+ /* NT sets the fstype of IPC$ to the null string */
+ char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+
+ set_message(outbuf,3,0,True);
+
+ p = smb_buf(outbuf);
+ p += srvstr_push(outbuf, p, devicename, -1,
+ STR_TERMINATE|STR_ASCII);
+ p += srvstr_push(outbuf, p, fsname, -1,
+ STR_TERMINATE);
+
+ set_message_end(outbuf,p);
+
+ /* what does setting this bit do? It is set by NT4 and
+ may affect the ability to autorun mounted cdroms */
+ SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS);
+
+ init_dfsroot(conn, inbuf, outbuf);
+ }
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+
+ DEBUG(3,("tconX service=%s \n",
+ service));
+
+ /* set the incoming and outgoing tid to the just created one */
+ SSVAL(inbuf,smb_tid,conn->cnum);
+ SSVAL(outbuf,smb_tid,conn->cnum);
- return(outsize);
+ END_PROFILE(SMBtconX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -249,245 +309,105 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
****************************************************************************/
int reply_unknown(char *inbuf,char *outbuf)
{
- int cnum;
- int type;
- cnum = SVAL(inbuf,smb_tid);
- type = CVAL(inbuf,smb_com);
+ int type;
+ type = CVAL(inbuf,smb_com);
- DEBUG(0,("%s unknown command type (%s): cnum=%d type=%d (0x%X)\n",
- timestring(),
- smb_fn_name(type),
- cnum,type,type));
+ DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
+ smb_fn_name(type), type, type));
- return(ERROR(ERRSRV,ERRunknownsmb));
+ return(ERROR_DOS(ERRSRV,ERRunknownsmb));
}
/****************************************************************************
reply to an ioctl
****************************************************************************/
-int reply_ioctl(char *inbuf,char *outbuf)
+int reply_ioctl(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- DEBUG(3,("ignoring ioctl\n"));
-
- return(ERROR(ERRSRV,ERRnosupport));
-}
+ uint16 device = SVAL(inbuf,smb_vwv1);
+ uint16 function = SVAL(inbuf,smb_vwv2);
+ uint32 ioctl_code = (device << 16) + function;
+ int replysize, outsize;
+ char *p;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBioctl);
+ DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
-/****************************************************************************
-reply to a session setup command
-****************************************************************************/
-int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
-{
- int outsize = 0;
- int sess_uid;
- int gid;
- int smb_com2;
- int smb_off2;
- int smb_bufsize;
- int smb_mpxmax;
- int smb_vc_num;
- uint32 smb_sesskey;
- int smb_apasslen;
- pstring smb_apasswd;
- int smb_ntpasslen = 0;
- pstring smb_ntpasswd;
- BOOL valid_nt_password = False;
- pstring user;
- BOOL guest=False;
-
- *smb_apasswd = 0;
-
- sess_uid = SVAL(inbuf,smb_uid);
- smb_com2 = CVAL(inbuf,smb_vwv0);
- smb_off2 = SVAL(inbuf,smb_vwv1);
- smb_bufsize = SVAL(inbuf,smb_vwv2);
- smb_mpxmax = SVAL(inbuf,smb_vwv3);
- smb_vc_num = SVAL(inbuf,smb_vwv4);
- smb_sesskey = IVAL(inbuf,smb_vwv5);
-
- if (Protocol < PROTOCOL_NT1) {
- smb_apasslen = SVAL(inbuf,smb_vwv7);
- memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
- } else {
- uint16 passlen1 = SVAL(inbuf,smb_vwv7);
- uint16 passlen2 = SVAL(inbuf,smb_vwv8);
- BOOL doencrypt = SMBENCRYPT();
- char *p = smb_buf(inbuf);
- if (passlen1 > 256) passlen1 = 0;
- if (passlen2 > 256) passlen2 = 0; /* I don't know why NT gives weird
- lengths sometimes */
- if(doencrypt) {
- /* Save the lanman2 password and the NT md4 password. */
- smb_apasslen = passlen1;
- memcpy(smb_apasswd,p,smb_apasslen);
- smb_ntpasslen = passlen2;
- memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
- } else {
- /* for Win95 */
- if (passlen1 > passlen2) {
- smb_apasslen = passlen1;
- StrnCpy(smb_apasswd,p,smb_apasslen);
- } else {
- smb_apasslen = passlen2;
- StrnCpy(smb_apasswd,p + passlen1,smb_apasslen);
- }
- }
- if (passlen2 == 1) {
- /* apparently NT sometimes sets passlen2 to 1 when it means 0. This
- tries to work around that problem */
- passlen2 = 0;
- }
- p += passlen1 + passlen2;
- strcpy(user,p); p = skip_string(p,1);
- DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- p,skip_string(p,1),skip_string(p,2)));
- }
-
-
- DEBUG(3,("sesssetupX:name=[%s]\n",user));
-
- if (!*user)
- strcpy(user,lp_guestaccount(-1));
-
- strlower(user);
-
- strcpy(sesssetup_user,user);
-
- reload_services(True);
-
- add_session_user(user);
-
-
- if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
- !check_hosts_equiv(user))
- {
-
- if (strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
- guest = True;
-
- /* now check if it's a valid username/password */
- /* If an NT password was supplied try and validate with that
- first. This is superior as the passwords are mixed case 128 length unicode */
- if(smb_ntpasslen && !guest)
+ switch (ioctl_code)
{
- if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL,True))
- DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
- else
- valid_nt_password = True;
- }
- if (!valid_nt_password && !guest && !password_ok(user,smb_apasswd,smb_apasslen,NULL,False))
- {
- if (lp_security() >= SEC_USER) {
-#if (GUEST_SESSSETUP == 0)
- return(ERROR(ERRSRV,ERRbadpw));
-#endif
-#if (GUEST_SESSSETUP == 1)
- if (Get_Pwnam(user,True))
- return(ERROR(ERRSRV,ERRbadpw));
-#endif
- }
- if (*smb_apasswd || !Get_Pwnam(user,True))
- strcpy(user,lp_guestaccount(-1));
- DEBUG(3,("Registered username %s for guest access\n",user));
- guest = True;
+ case IOCTL_QUERY_JOB_INFO:
+ replysize = 32;
+ break;
+ default:
+ END_PROFILE(SMBioctl);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
}
- }
-
- if (!Get_Pwnam(user,True)) {
- DEBUG(3,("No such user %s - using guest account\n",user));
- strcpy(user,lp_guestaccount(-1));
- guest = True;
- }
-
- if (!strequal(user,lp_guestaccount(-1)) &&
- lp_servicenumber(user) < 0)
- {
- int homes = lp_servicenumber(HOMES_NAME);
- char *home = get_home_dir(user);
- if (homes >= 0 && home)
- lp_add_home(user,homes,home);
- }
-
-
- /* it's ok - setup a reply */
- if (Protocol < PROTOCOL_NT1) {
- outsize = set_message(outbuf,3,0,True);
- } else {
- char *p;
- outsize = set_message(outbuf,3,3,True);
- p = smb_buf(outbuf);
- strcpy(p,"Unix"); p = skip_string(p,1);
- strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
- strcpy(p,my_workgroup()); p = skip_string(p,1);
- outsize = set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
- /* perhaps grab OS version here?? */
- }
-
- /* Set the correct uid in the outgoing and incoming packets
- We will use this on future requests to determine which
- user we should become.
- */
- {
- struct passwd *pw = Get_Pwnam(user,False);
- if (!pw) {
- DEBUG(1,("Username %s is invalid on this system\n",user));
- return(ERROR(ERRSRV,ERRbadpw));
- }
- gid = pw->pw_gid;
- SSVAL(outbuf,smb_uid,(uint16)pw->pw_uid);
- SSVAL(inbuf,smb_uid,(uint16)pw->pw_uid);
- }
-
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
- if (guest)
- SSVAL(outbuf,smb_vwv2,1);
-
- /* register the name and uid as being validated, so further connections
- to a uid can get through without a password, on the same VC */
- register_uid(SVAL(inbuf,smb_uid),gid,user,guest);
-
- maxxmit = MIN(maxxmit,smb_bufsize);
+ outsize = set_message(outbuf,8,replysize+1,True);
+ SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
+ SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
+ SSVAL(outbuf,smb_vwv6,52); /* Offset to data */
+ p = smb_buf(outbuf) + 1; /* Allow for alignment */
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ switch (ioctl_code)
+ {
+ case IOCTL_QUERY_JOB_INFO:
+ SSVAL(p,0,fsp->print_jobid); /* Job number */
+ srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII);
+ srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
+ break;
+ }
- return(outsize);
+ END_PROFILE(SMBioctl);
+ return outsize;
}
-
/****************************************************************************
reply to a chkpth
****************************************************************************/
-int reply_chkpth(char *inbuf,char *outbuf)
+int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
- int cnum,mode;
+ int mode;
pstring name;
BOOL ok = False;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf) + 1);
- unix_convert(name,cnum);
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+ START_PROFILE(SMBchkpth);
+
+ srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+ unix_convert(name,conn,0,&bad_path,&sbuf);
mode = SVAL(inbuf,smb_vwv0);
- if (check_name(name,cnum))
- ok = directory_exist(name,NULL);
+ if (check_name(name,conn)) {
+ if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
+ ok = S_ISDIR(sbuf.st_mode);
+ }
+
+ if (!ok) {
+ /* We special case this - as when a Windows machine
+ is parsing a path is steps through the components
+ one at a time - if a component fails it expects
+ ERRbadpath, not ERRbadfile.
+ */
+ if(errno == ENOENT) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
- if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
-
outsize = set_message(outbuf,0,0,True);
-
- DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
-
+
+ DEBUG(3,("chkpth %s mode=%d\n", name, mode));
+
+ END_PROFILE(SMBchkpth);
return(outsize);
}
@@ -495,67 +415,81 @@ int reply_chkpth(char *inbuf,char *outbuf)
/****************************************************************************
reply to a getatr
****************************************************************************/
-int reply_getatr(char *inbuf,char *outbuf)
+int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
int outsize = 0;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
BOOL ok = False;
int mode=0;
- uint32 size=0;
+ SMB_OFF_T size=0;
time_t mtime=0;
-
- cnum = SVAL(inbuf,smb_tid);
+ BOOL bad_path = False;
+ char *p;
+ START_PROFILE(SMBgetatr);
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ p = smb_buf(inbuf) + 1;
+ p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
if (! (*fname))
- {
- mode = aHIDDEN | aDIR;
- if (!CAN_WRITE(cnum)) mode |= aRONLY;
- size = 0;
- mtime = 0;
- ok = True;
- }
+ {
+ mode = aHIDDEN | aDIR;
+ if (!CAN_WRITE(conn)) mode |= aRONLY;
+ size = 0;
+ mtime = 0;
+ ok = True;
+ }
else
- if (check_name(fname,cnum))
+ {
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (check_name(fname,conn))
+ {
+ if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
{
- if (sys_stat(fname,&sbuf) == 0)
- {
- mode = dos_mode(cnum,fname,&sbuf);
- size = sbuf.st_size;
- mtime = sbuf.st_mtime;
- if (mode & aDIR)
- size = 0;
- ok = True;
- }
- else
- DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+ mode = dos_mode(conn,fname,&sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR)
+ size = 0;
+ ok = True;
+ }
+ else
+ DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
}
+ }
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ END_PROFILE(SMBgetatr);
return(UNIXERROR(ERRDOS,ERRbadfile));
-
+ }
+
outsize = set_message(outbuf,10,0,True);
SSVAL(outbuf,smb_vwv0,mode);
- put_dos_date3(outbuf,smb_vwv1,mtime);
- SIVAL(outbuf,smb_vwv3,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv1,mtime);
+ SIVAL(outbuf,smb_vwv3,(uint32)size);
if (Protocol >= PROTOCOL_NT1) {
- char *p = strrchr(fname,'/');
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- if (!p) p = fname;
- if (!is_8_3(fname))
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
}
- DEBUG(3,("%s getatr name=%s mode=%d size=%d\n",timestring(),fname,mode,size));
+ DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
+ END_PROFILE(SMBgetatr);
return(outsize);
}
@@ -563,37 +497,50 @@ int reply_getatr(char *inbuf,char *outbuf)
/****************************************************************************
reply to a setatr
****************************************************************************/
-int reply_setatr(char *inbuf,char *outbuf)
+int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
int outsize = 0;
BOOL ok=False;
int mode;
time_t mtime;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+ char *p;
+
+ START_PROFILE(SMBsetatr);
+
+ p = smb_buf(inbuf) + 1;
+ p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
- if (directory_exist(fname,NULL))
+ if (VALID_STAT_OF_DIR(sbuf))
mode |= aDIR;
- if (check_name(fname,cnum))
- ok = (dos_chmod(cnum,fname,mode,NULL) == 0);
+ if (check_name(fname,conn))
+ ok = (file_chmod(conn,fname,mode,NULL) == 0);
if (ok)
- ok = set_filetime(fname,mtime);
+ ok = set_filetime(conn,fname,mtime);
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ END_PROFILE(SMBsetatr);
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
+ DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
+ END_PROFILE(SMBsetatr);
return(outsize);
}
@@ -601,15 +548,13 @@ int reply_setatr(char *inbuf,char *outbuf)
/****************************************************************************
reply to a dskattr
****************************************************************************/
-int reply_dskattr(char *inbuf,char *outbuf)
+int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
int outsize = 0;
- int dfree,dsize,bsize;
+ SMB_BIG_UINT dfree,dsize,bsize;
+ START_PROFILE(SMBdskattr);
- cnum = SVAL(inbuf,smb_tid);
-
- sys_disk_free(".",&bsize,&dfree,&dsize);
+ conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
outsize = set_message(outbuf,5,0,True);
@@ -617,9 +562,10 @@ int reply_dskattr(char *inbuf,char *outbuf)
SSVAL(outbuf,smb_vwv1,bsize/512);
SSVAL(outbuf,smb_vwv2,512);
SSVAL(outbuf,smb_vwv3,dfree);
-
- DEBUG(3,("%s dskattr cnum=%d dfree=%d\n",timestring(),cnum,dfree));
-
+
+ DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+
+ END_PROFILE(SMBdskattr);
return(outsize);
}
@@ -628,15 +574,15 @@ int reply_dskattr(char *inbuf,char *outbuf)
reply to a search
Can be called from SMBsearch, SMBffirst or SMBfunique.
****************************************************************************/
-int reply_search(char *inbuf,char *outbuf)
+int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring mask;
pstring directory;
pstring fname;
- int size,mode;
+ SMB_OFF_T size;
+ int mode;
time_t date;
int dirtype;
- int cnum;
int outsize = 0;
int numentries = 0;
BOOL finished = False;
@@ -645,12 +591,14 @@ int reply_search(char *inbuf,char *outbuf)
char *p;
BOOL ok = False;
int status_len;
- char *path;
+ pstring path;
char status[21];
int dptr_num= -1;
BOOL check_descend = False;
BOOL expect_close = False;
BOOL can_open = True;
+ BOOL bad_path = False;
+ START_PROFILE(SMBsearch);
*mask = *directory = *fname = 0;
@@ -658,175 +606,155 @@ int reply_search(char *inbuf,char *outbuf)
if(CVAL(inbuf,smb_com) == SMBffirst)
expect_close = True;
- cnum = SVAL(inbuf,smb_tid);
-
outsize = set_message(outbuf,1,3,True);
maxentries = SVAL(inbuf,smb_vwv0);
dirtype = SVAL(inbuf,smb_vwv1);
- path = smb_buf(inbuf) + 1;
- status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
-
+ p = smb_buf(inbuf) + 1;
+ p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+ p++;
+ status_len = SVAL(p, 0);
+ p += 2;
/* dirtype &= ~aDIR; */
- DEBUG(5,("path=%s status_len=%d\n",path,status_len));
-
-
if (status_len == 0)
- {
- pstring dir2;
-
- strcpy(directory,smb_buf(inbuf)+1);
- strcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,cnum);
- unix_format(dir2);
+ {
+ SMB_STRUCT_STAT sbuf;
+ pstring dir2;
- if (!check_name(directory,cnum))
- can_open = False;
+ pstrcpy(directory,path);
+ pstrcpy(dir2,path);
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+ unix_format(dir2);
- p = strrchr(dir2,'/');
- if (p == NULL)
- {strcpy(mask,dir2);*dir2 = 0;}
- else
- {*p = 0;strcpy(mask,p+1);}
+ if (!check_name(directory,conn))
+ can_open = False;
- p = strrchr(directory,'/');
- if (!p)
- *directory = 0;
- else
- *p = 0;
-
- if (strlen(directory) == 0)
- strcpy(directory,"./");
- bzero(status,21);
- CVAL(status,0) = dirtype;
+ p = strrchr_m(dir2,'/');
+ if (p == NULL)
+ {
+ pstrcpy(mask,dir2);
+ *dir2 = 0;
}
- else
+ else
{
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
- memcpy(mask,status+1,11);
- mask[11] = 0;
- dirtype = CVAL(status,0) & 0x1F;
- Connections[cnum].dirptr = dptr_fetch(status+12,&dptr_num);
- if (!Connections[cnum].dirptr)
- goto SearchEmpty;
- string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
- if (!case_sensitive)
- strnorm(mask);
+ *p = 0;
+ pstrcpy(mask,p+1);
}
- /* turn strings of spaces into a . */
+ p = strrchr_m(directory,'/');
+ if (!p)
+ *directory = 0;
+ else
+ *p = 0;
+
+ if (strlen(directory) == 0)
+ pstrcpy(directory,"./");
+ memset((char *)status,'\0',21);
+ CVAL(status,0) = dirtype;
+ }
+ else
{
- trim_string(mask,NULL," ");
- if ((p = strrchr(mask,' ')))
- {
- fstring ext;
- strcpy(ext,p+1);
- *p = 0;
- trim_string(mask,NULL," ");
- strcat(mask,".");
- strcat(mask,ext);
- }
+ memcpy(status,p,21);
+ dirtype = CVAL(status,0) & 0x1F;
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr)
+ goto SearchEmpty;
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+ fstrcpy(mask, dptr_wcard(dptr_num));
}
+ if (can_open)
{
- for (p=mask; *p; p++)
+ p = smb_buf(outbuf) + 3;
+
+ ok = True;
+
+ if (status_len == 0)
+ {
+ dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
{
- if (*p != '?' && *p != '*' && !isdoschar(*p))
- {
- DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
- *p = '?';
- }
+ if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBsearch);
+ return (UNIXERROR(ERRDOS,ERRnofids));
+ }
+ END_PROFILE(SMBsearch);
+ return ERROR_DOS(ERRDOS,ERRnofids);
}
- }
-
- if (!strchr(mask,'.') && strlen(mask)>8)
- {
- fstring tmp;
- strcpy(tmp,&mask[8]);
- mask[8] = '.';
- mask[9] = 0;
- strcat(mask,tmp);
+ dptr_set_wcard(dptr_num, strdup(mask));
}
- DEBUG(5,("mask=%s directory=%s\n",mask,directory));
-
- if (can_open)
- {
- p = smb_buf(outbuf) + 3;
-
- ok = True;
-
- if (status_len == 0)
- {
- dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRnofids));
- }
-
- DEBUG(4,("dptr_num is %d\n",dptr_num));
+ DEBUG(4,("dptr_num is %d\n",dptr_num));
- if (ok)
- {
- if ((dirtype&0x1F) == aVOLID)
- {
- memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0);
- dptr_fill(p+12,dptr_num);
- if (dptr_zero(p+12) && (status_len==0))
- numentries = 1;
- else
- numentries = 0;
- p += DIR_STRUCT_SIZE;
- }
- else
- {
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
- if (in_list(Connections[cnum].dirpath,
- lp_dontdescend(SNUM(cnum)),True))
- check_descend = True;
-
- for (i=numentries;(i<maxentries) && !finished;i++)
- {
- finished =
- !get_dir_entry(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend);
- if (!finished)
- {
- memcpy(p,status,21);
- make_dir_struct(p,mask,fname,size,mode,date);
- dptr_fill(p+12,dptr_num);
- numentries++;
- }
- p += DIR_STRUCT_SIZE;
- }
- }
- }
- }
+ if (ok)
+ {
+ if ((dirtype&0x1F) == aVOLID)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+ dptr_fill(p+12,dptr_num);
+ if (dptr_zero(p+12) && (status_len==0))
+ numentries = 1;
+ else
+ numentries = 0;
+ p += DIR_STRUCT_SIZE;
+ }
+ else
+ {
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+ conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+ check_descend = True;
+
+ for (i=numentries;(i<maxentries) && !finished;i++)
+ {
+ finished =
+ !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+ if (!finished)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,mask,fname,size,mode,date);
+ dptr_fill(p+12,dptr_num);
+ numentries++;
+ }
+ p += DIR_STRUCT_SIZE;
+ }
+ }
+ } /* if (ok ) */
+ }
- SearchEmpty:
+ SearchEmpty:
if (numentries == 0 || !ok)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
(X/Open spec) */
if(ok && expect_close && numentries == 0 && status_len == 0)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- /* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ /* Also close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -834,21 +762,20 @@ int reply_search(char *inbuf,char *outbuf)
SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
}
outsize += DIR_STRUCT_SIZE*numentries;
smb_setlen(outbuf,outsize - 4);
if ((! *directory) && dptr_path(dptr_num))
- sprintf(directory,"(%s)",dptr_path(dptr_num));
+ slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
- DEBUG(4,("%s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d\n",
- timestring(),
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask,directory,cnum,dirtype,numentries,maxentries));
+ DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries, maxentries ) );
+ END_PROFILE(SMBsearch);
return(outsize);
}
@@ -856,36 +783,41 @@ int reply_search(char *inbuf,char *outbuf)
/****************************************************************************
reply to a fclose (stop directory search)
****************************************************************************/
-int reply_fclose(char *inbuf,char *outbuf)
+int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
int outsize = 0;
int status_len;
- char *path;
+ pstring path;
char status[21];
- int dptr_num= -1;
+ int dptr_num= -2;
+ char *p;
- cnum = SVAL(inbuf,smb_tid);
+ START_PROFILE(SMBfclose);
outsize = set_message(outbuf,1,0,True);
- path = smb_buf(inbuf) + 1;
- status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
-
-
- if (status_len == 0)
- return(ERROR(ERRSRV,ERRsrverror));
+ p = smb_buf(inbuf) + 1;
+ p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+ p++;
+ status_len = SVAL(p,0);
+ p += 2;
+
+ if (status_len == 0) {
+ END_PROFILE(SMBfclose);
+ return ERROR_DOS(ERRSRV,ERRsrverror);
+ }
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+ memcpy(status,p,21);
if(dptr_fetch(status+12,&dptr_num)) {
/* Close the dptr - we know it's gone */
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
}
SSVAL(outbuf,smb_vwv0,0);
- DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum));
+ DEBUG(3,("search close\n"));
+ END_PROFILE(SMBfclose);
return(outsize);
}
@@ -893,63 +825,75 @@ int reply_fclose(char *inbuf,char *outbuf)
/****************************************************************************
reply to an open
****************************************************************************/
-int reply_open(char *inbuf,char *outbuf)
+
+int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum;
- int fnum = -1;
int outsize = 0;
int fmode=0;
int share_mode;
- int size = 0;
+ SMB_OFF_T size = 0;
time_t mtime=0;
- int unixmode;
+ mode_t unixmode;
int rmode=0;
- struct stat sbuf;
-
- cnum = SVAL(inbuf,smb_tid);
-
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ START_PROFILE(SMBopen);
+
share_mode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- unixmode = unix_mode(cnum,aARCH);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+
+ unixmode = unix_mode(conn,aARCH,fname);
- open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
+ fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ unixmode, oplock_request,&rmode,NULL);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBopen);
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
}
-
+
size = sbuf.st_size;
- fmode = dos_mode(cnum,fname,&sbuf);
+ fmode = dos_mode(conn,fname,&sbuf);
mtime = sbuf.st_mtime;
if (fmode & aDIR) {
DEBUG(3,("attempt to open a directory %s\n",fname));
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
+ close_file(fsp,False);
+ END_PROFILE(SMBopen);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
}
outsize = set_message(outbuf,7,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
SSVAL(outbuf,smb_vwv1,fmode);
- put_dos_date3(outbuf,smb_vwv2,mtime);
- SIVAL(outbuf,smb_vwv4,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv2,mtime);
+ SIVAL(outbuf,smb_vwv4,(uint32)size);
SSVAL(outbuf,smb_vwv6,rmode);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ END_PROFILE(SMBopen);
return(outsize);
}
@@ -957,165 +901,219 @@ int reply_open(char *inbuf,char *outbuf)
/****************************************************************************
reply to an open and X
****************************************************************************/
-int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
pstring fname;
- int cnum = SVAL(inbuf,smb_tid);
- int fnum = -1;
- int outsize = 0;
- int openmode = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int smb_mode = SVAL(inbuf,smb_vwv3);
int smb_attr = SVAL(inbuf,smb_vwv5);
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+ BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ BOOL oplock_request = ex_oplock_request | core_oplock_request;
#if 0
int open_flags = SVAL(inbuf,smb_vwv2);
int smb_sattr = SVAL(inbuf,smb_vwv4);
uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
#endif
int smb_ofun = SVAL(inbuf,smb_vwv8);
- int unixmode;
- int size=0,fmode=0,mtime=0,rmode=0;
- struct stat sbuf;
+ mode_t unixmode;
+ SMB_OFF_T size=0;
+ int fmode=0,mtime=0,rmode=0;
+ SMB_STRUCT_STAT sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ START_PROFILE(SMBopenX);
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ if (lp_nt_pipe_support()) {
+ END_PROFILE(SMBopenX);
+ return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
+ } else {
+ END_PROFILE(SMBopenX);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
+ }
/* XXXX we need to handle passed times, sattr and flags */
+ srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
- strcpy(fname,smb_buf(inbuf));
- unix_convert(fname,cnum);
-
- /* now add create and trunc bits */
- if (smb_ofun & 0x10)
- openmode |= O_CREAT;
- if ((smb_ofun & 0x3) == 2)
- openmode |= O_TRUNC;
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- unixmode = unix_mode(cnum,smb_attr | aARCH);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
- open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
- &rmode,&smb_action);
+ fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBopenX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
}
size = sbuf.st_size;
- fmode = dos_mode(cnum,fname,&sbuf);
+ fmode = dos_mode(conn,fname,&sbuf);
mtime = sbuf.st_mtime;
if (fmode & aDIR) {
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
+ close_file(fsp,False);
+ END_PROFILE(SMBopenX);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ /* If the caller set the extended oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for extended oplock reply.
+ */
+
+ if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ /* If the caller set the core oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for core oplock reply.
+ */
+
+ if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- outsize = set_message(outbuf,15,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
- SSVAL(outbuf,smb_vwv2,fnum);
+ set_message(outbuf,15,0,True);
+ SSVAL(outbuf,smb_vwv2,fsp->fnum);
SSVAL(outbuf,smb_vwv3,fmode);
- put_dos_date3(outbuf,smb_vwv4,mtime);
- SIVAL(outbuf,smb_vwv6,size);
+ if(lp_dos_filetime_resolution(SNUM(conn)) )
+ put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
+ else
+ put_dos_date3(outbuf,smb_vwv4,mtime);
+ SIVAL(outbuf,smb_vwv6,(uint32)size);
SSVAL(outbuf,smb_vwv8,rmode);
SSVAL(outbuf,smb_vwv11,smb_action);
- chain_fnum = fnum;
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ END_PROFILE(SMBopenX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a SMBulogoffX
****************************************************************************/
-int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int uid = SVAL(inbuf,smb_uid);
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ user_struct *vuser = get_valid_user_struct(vuid);
+ START_PROFILE(SMBulogoffX);
- invalidate_uid(uid);
+ if(vuser == 0) {
+ DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
+ }
- outsize = set_message(outbuf,2,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
+ /* in user level security we are supposed to close any files
+ open by this user */
+ if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
+ file_close_user(vuid);
+ }
- DEBUG(3,("%s ulogoffX uid=%d\n",timestring(),uid));
+ invalidate_vuid(vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ set_message(outbuf,2,0,True);
-
- return(outsize);
+ DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
+
+ END_PROFILE(SMBulogoffX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
- reply to a mknew
+ reply to a mknew or a create
****************************************************************************/
-int reply_mknew(char *inbuf,char *outbuf)
+int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- int cnum,com;
- int fnum = -1;
+ int com;
int outsize = 0;
int createmode;
mode_t unixmode;
-
+ int ofun = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ SMB_STRUCT_STAT sbuf;
+ START_PROFILE(SMBcreate);
+
com = SVAL(inbuf,smb_com);
- cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE);
- if (createmode & aVOLID)
- {
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+
+ if (createmode & aVOLID) {
DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
- }
+ }
- unixmode = unix_mode(cnum,createmode);
+ unixmode = unix_mode(conn,createmode,fname);
- if (com == SMBmknew && file_exist(fname,NULL))
- return(ERROR(ERRDOS,ERRfilexists));
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if(com == SMBmknew)
+ {
+ /* We should fail if file exists. */
+ ofun = FILE_CREATE_IF_NOT_EXIST;
+ }
+ else
+ {
+ /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+ ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
+ }
- open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ ofun, unixmode, oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBcreate);
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
-
- DEBUG(2,("new file %s\n",fname));
- DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd,fnum,cnum,createmode,unixmode));
-
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG( 2, ( "new file %s\n", fname ) );
+ DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
+ fname, fsp->fd, createmode, (int)unixmode ) );
+
+ END_PROFILE(SMBcreate);
return(outsize);
}
@@ -1123,334 +1121,505 @@ int reply_mknew(char *inbuf,char *outbuf)
/****************************************************************************
reply to a create temporary file
****************************************************************************/
-int reply_ctemp(char *inbuf,char *outbuf)
+int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
- pstring fname2;
- int cnum;
- int fnum = -1;
int outsize = 0;
int createmode;
mode_t unixmode;
-
- cnum = SVAL(inbuf,smb_tid);
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ int tmpfd;
+ SMB_STRUCT_STAT sbuf;
+ char *p, *s;
+
+ START_PROFILE(SMBctemp);
+
createmode = SVAL(inbuf,smb_vwv0);
- sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+ pstrcat(fname,"\\TMXXXXXX");
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(cnum,createmode);
+ unixmode = unix_mode(conn,createmode,fname);
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ tmpfd = smb_mkstemp(fname);
+ if (tmpfd == -1) {
+ END_PROFILE(SMBctemp);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (!check_name(fname,cnum))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ vfs_stat(conn,fname,&sbuf);
- strcpy(fname2,(char *)mktemp(fname));
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file does not exist. */
+ fsp = open_file_shared(conn,fname,&sbuf,
+ SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
+ unixmode, oplock_request, NULL, NULL);
- open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* close fd from smb_mkstemp() */
+ close(tmpfd);
- if (!Files[fnum].open)
+ if (!fsp) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBctemp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- outsize = set_message(outbuf,1,2 + strlen(fname2),True);
- SSVAL(outbuf,smb_vwv0,fnum);
- CVAL(smb_buf(outbuf),0) = 4;
- strcpy(smb_buf(outbuf) + 1,fname2);
-
- DEBUG(2,("created temp file %s\n",fname2));
- DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd,fnum,cnum,createmode,unixmode));
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
+
+ /* the returned filename is relative to the directory */
+ s = strrchr_m(fname, '/');
+ if (!s) {
+ s = fname;
+ } else {
+ s++;
+ }
+
+ p = smb_buf(outbuf);
+ SSVALS(p, 0, -1); /* what is this? not in spec */
+ SSVAL(p, 2, strlen(s));
+ p += 4;
+ p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
+ outsize = set_message_end(outbuf, p);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG( 2, ( "created temp file %s\n", fname ) );
+ DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
+ fname, fsp->fd, createmode, (int)unixmode ) );
+
+ END_PROFILE(SMBctemp);
return(outsize);
}
-
/*******************************************************************
-check if a user is allowed to delete a file
+ Check if a user is allowed to delete a file.
********************************************************************/
-static BOOL can_delete(char *fname,int cnum,int dirtype)
-{
- struct stat sbuf;
- int fmode;
-
- if (!CAN_WRITE(cnum)) return(False);
-
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- fmode = dos_mode(cnum,fname,&sbuf);
- if (fmode & aDIR) return(False);
- if (fmode & aRONLY) return(False);
- if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
- return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
- return(True);
-}
-/****************************************************************************
- reply to a unlink
-****************************************************************************/
-int reply_unlink(char *inbuf,char *outbuf)
+static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
{
- int outsize = 0;
- pstring name;
- int cnum;
- int dirtype;
- pstring directory;
- pstring mask;
- char *p;
- int count=0;
- int error = ERRnoaccess;
- BOOL has_wild;
- BOOL exists=False;
+ SMB_STRUCT_STAT sbuf;
+ int fmode;
- *directory = *mask = 0;
+ if (!CAN_WRITE(conn))
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
- cnum = SVAL(inbuf,smb_tid);
- dirtype = SVAL(inbuf,smb_vwv0);
-
- strcpy(name,smb_buf(inbuf) + 1);
-
- DEBUG(3,("reply_unlink : %s\n",name));
-
- unix_convert(name,cnum);
+ if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0)
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- p = strrchr(name,'/');
- if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
- } else {
- *p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
- }
-
- if (is_mangled(mask))
- check_mangled_stack(mask);
+ fmode = dos_mode(conn,fname,&sbuf);
+ if (fmode & aDIR)
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fmode & aRONLY)
+ return NT_STATUS_CANNOT_DELETE;
+ }
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+ return NT_STATUS_CANNOT_DELETE;
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ if (!check_file_sharing(conn,fname,False))
+ return NT_STATUS_SHARING_VIOLATION;
- if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
- if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
- if (!count) exists = file_exist(directory,NULL);
- } else {
- void *dirptr = NULL;
- char *dname;
+ return NT_STATUS_OK;
+}
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+/****************************************************************************
+ The guts of the unlink command, split out so it may be called by the NT SMB
+ code.
+****************************************************************************/
- if (dirptr)
- {
- error = ERRbadfile;
+NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
+{
+ pstring directory;
+ pstring mask;
+ char *p;
+ int count=0;
+ NTSTATUS error = NT_STATUS_OK;
+ BOOL has_wild;
+ BOOL exists=False;
+ BOOL bad_path = False;
+ BOOL rc = True;
+ SMB_STRUCT_STAT sbuf;
+
+ *directory = *mask = 0;
+
+ rc = unix_convert(name,conn,0,&bad_path,&sbuf);
+
+ p = strrchr_m(name,'/');
+ if (!p) {
+ pstrcpy(directory,"./");
+ pstrcpy(mask,name);
+ } else {
+ *p = 0;
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
+ }
+
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
+
+ has_wild = ms_has_wild(mask);
+
+ if (!has_wild) {
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+ error = can_delete(directory,conn,dirtype);
+ if (!NT_STATUS_IS_OK(error)) return error;
+
+ if (vfs_unlink(conn,directory) == 0) {
+ count++;
+ }
+ if (!count)
+ exists = vfs_file_exist(conn,directory,&sbuf);
+ } else {
+ void *dirptr = NULL;
+ char *dname;
+
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
+ the pattern matches against the long name, otherwise the short name
+ We don't implement this yet XXXX
+ */
+
+ if (dirptr) {
+ error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ if (strequal(mask,"????????.???"))
+ pstrcpy(mask,"*");
+
+ while ((dname = ReadDirName(dirptr))) {
+ pstring fname;
+ pstrcpy(fname,dname);
+
+ if(!mask_match(fname, mask, case_sensitive)) continue;
+
+ slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+ error = can_delete(fname,conn,dirtype);
+ if (!NT_STATUS_IS_OK(error)) continue;
+ if (vfs_unlink(conn,fname) == 0) count++;
+ DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0 && NT_STATUS_IS_OK(error)) {
+ error = map_nt_error_from_unix(errno);
+ }
- if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ return error;
+}
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- strcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+/****************************************************************************
+ Reply to a unlink
+****************************************************************************/
- error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_delete(fname,cnum,dirtype)) continue;
- if (!sys_unlink(fname)) count++;
- DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
- }
- CloseDir(dirptr);
- }
- }
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- return(UNIXERROR(ERRDOS,error));
- }
-
- outsize = set_message(outbuf,0,0,True);
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ int dirtype;
+ NTSTATUS status;
+ START_PROFILE(SMBunlink);
+
+ dirtype = SVAL(inbuf,smb_vwv0);
+
+ srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+ DEBUG(3,("reply_unlink : %s\n",name));
+
+ status = unlink_internals(conn, dirtype, name);
+ if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+
+ /*
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+ process_pending_change_notify_queue((time_t)0);
+
+ outsize = set_message(outbuf,0,0,True);
- return(outsize);
+ END_PROFILE(SMBunlink);
+ return outsize;
}
+/****************************************************************************
+ Fail for readbraw.
+****************************************************************************/
+
+void fail_readraw(void)
+{
+ pstring errstr;
+ slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
+ strerror(errno) );
+ exit_server(errstr);
+}
/****************************************************************************
- reply to a readbraw (core+ protocol)
+ Reply to a readbraw (core+ protocol).
****************************************************************************/
-int reply_readbraw(char *inbuf, char *outbuf)
+
+int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,maxcount,mincount,fnum;
- int nread = 0;
- int startpos;
- char *header = outbuf;
- int ret=0;
- int fd;
- char *fname;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- startpos = IVAL(inbuf,smb_vwv1);
- maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
-
- /* ensure we don't overrun the packet size */
- maxcount = MIN(65535,maxcount);
- maxcount = MAX(mincount,maxcount);
-
- if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
- {
- DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
- _smb_setlen(header,0);
- transfer_file(0,Client,0,header,4,0);
- return(-1);
- }
- else
- {
- fd = Files[fnum].fd;
- fname = Files[fnum].name;
- }
+ ssize_t maxcount,mincount;
+ size_t nread = 0;
+ SMB_OFF_T startpos;
+ char *header = outbuf;
+ ssize_t ret=0;
+ files_struct *fsp;
+ START_PROFILE(SMBreadbraw);
+
+ /*
+ * Special check if an oplock break has been issued
+ * and the readraw request croses on the wire, we must
+ * return a zero length response here.
+ */
+
+ if(global_oplock_break) {
+ _smb_setlen(header,0);
+ if (write_data(smbd_server_fd(),header,4) != 4)
+ fail_readraw();
+ DEBUG(5,("readbraw - oplock break finished\n"));
+ END_PROFILE(SMBreadbraw);
+ return -1;
+ }
+ fsp = file_fsp(inbuf,smb_vwv0);
+
+ if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+ /*
+ * fsp could be NULL here so use the value from the packet. JRA.
+ */
+ DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+ _smb_setlen(header,0);
+ if (write_data(smbd_server_fd(),header,4) != 4)
+ fail_readraw();
+ END_PROFILE(SMBreadbraw);
+ return(-1);
+ }
- if (!is_locked(fnum,cnum,maxcount,startpos))
- {
- int size = Files[fnum].size;
- int sizeneeded = startpos + maxcount;
-
- if (size < sizeneeded) {
- struct stat st;
- if (fstat(Files[fnum].fd,&st) == 0)
- size = st.st_size;
- if (!Files[fnum].can_write)
- Files[fnum].size = size;
- }
+ CHECK_FSP(fsp,conn);
- nread = MIN(maxcount,size - startpos);
- }
+ flush_write_cache(fsp, READRAW_FLUSH);
- if (nread < mincount)
- nread = 0;
-
- DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
- timestring(),
- fnum,cnum,startpos,
- maxcount,mincount,nread));
-
-#if UNSAFE_READRAW
- {
- int predict=0;
- _smb_setlen(header,nread);
+ startpos = IVAL(inbuf,smb_vwv1);
+ if(CVAL(inbuf,smb_wct) == 10) {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+#ifdef LARGE_SMB_OFF_T
- if (!Files[fnum].can_write)
- predict = read_predict(fd,startpos,header+4,NULL,nread);
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
- if ((nread-predict) > 0)
- seek_file(fnum,startpos + predict);
-
- ret = transfer_file(fd,Client,nread-predict,header,4+predict,
- startpos+predict);
- }
+#else /* !LARGE_SMB_OFF_T */
- if (ret != nread+4)
- DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
- fname,startpos,nread,ret));
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
-#else
- ret = read_file(fnum,header+4,startpos,nread,nread,-1,False);
- if (ret < mincount) ret = 0;
+ if(IVAL(inbuf,smb_vwv8) != 0) {
+ DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
+ _smb_setlen(header,0);
+ if (write_data(smbd_server_fd(),header,4) != 4)
+ fail_readraw();
+ END_PROFILE(SMBreadbraw);
+ return(-1);
+ }
- _smb_setlen(header,ret);
- transfer_file(0,Client,0,header,4+ret,0);
-#endif
+#endif /* LARGE_SMB_OFF_T */
- DEBUG(5,("readbraw finished\n"));
- return -1;
-}
+ if(startpos < 0) {
+ DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
+ _smb_setlen(header,0);
+ if (write_data(smbd_server_fd(),header,4) != 4)
+ fail_readraw();
+ END_PROFILE(SMBreadbraw);
+ return(-1);
+ }
+ }
+ maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
+ mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
+
+ /* ensure we don't overrun the packet size */
+ maxcount = MIN(65535,maxcount);
+ maxcount = MAX(mincount,maxcount);
+
+ if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ SMB_OFF_T size = fsp->size;
+ SMB_OFF_T sizeneeded = startpos + maxcount;
+
+ if (size < sizeneeded) {
+ SMB_STRUCT_STAT st;
+ if (vfs_fstat(fsp,fsp->fd,&st) == 0)
+ size = st.st_size;
+ if (!fsp->can_write)
+ fsp->size = size;
+ }
+
+ if (startpos >= size)
+ nread = 0;
+ else
+ nread = MIN(maxcount,(size - startpos));
+ }
+ if (nread < mincount)
+ nread = 0;
+
+ DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
+ (int)maxcount, (int)mincount, (int)nread ) );
+
+ if (nread > 0) {
+ ret = read_file(fsp,header+4,startpos,nread);
+ if (ret < mincount)
+ ret = 0;
+ }
+
+ _smb_setlen(header,ret);
+ if (write_data(smbd_server_fd(),header,4+ret) != 4+ret)
+ fail_readraw();
+
+ DEBUG(5,("readbraw finished\n"));
+ END_PROFILE(SMBreadbraw);
+ return -1;
+}
/****************************************************************************
reply to a lockread (core+ protocol)
****************************************************************************/
-int reply_lockread(char *inbuf,char *outbuf)
+int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
{
- int cnum,fnum;
- int nread = -1;
- char *data;
- int outsize = 0;
- uint32 startpos, numtoread;
- int eclass;
- uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ ssize_t nread = -1;
+ char *data;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ NTSTATUS status;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBlockread);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+
+ release_level_2_oplocks_on_change(fsp);
+
+ numtoread = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+
+ outsize = set_message(outbuf,5,3,True);
+ numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+ data = smb_buf(outbuf) + 3;
+
+ /*
+ * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+ * protocol request that predates the read/write lock concept.
+ * Thus instead of asking for a read lock here we need to ask
+ * for a write lock. JRA.
+ */
+
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid),
+ (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
+
+ if (NT_STATUS_V(status)) {
+ if (lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, -1, 0))
+ END_PROFILE(SMBlockread);
+ return -1;
+ }
+ END_PROFILE(SMBlockread);
+ return ERROR_NT(status);
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ nread = read_file(fsp,data,startpos,numtoread);
- numtoread = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
-
- outsize = set_message(outbuf,5,3,True);
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
- data = smb_buf(outbuf) + 3;
-
- if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
- return (ERROR(eclass,ecode));
+ if (nread < 0) {
+ END_PROFILE(SMBlockread);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ outsize += nread;
+ SSVAL(outbuf,smb_vwv0,nread);
+ SSVAL(outbuf,smb_vwv5,nread+3);
+ SSVAL(smb_buf(outbuf),1,nread);
+
+ DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread));
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
-
- if (nread < 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize += nread;
- SSVAL(outbuf,smb_vwv0,nread);
- SSVAL(outbuf,smb_vwv5,nread+3);
- SSVAL(smb_buf(outbuf),1,nread);
-
- DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
-
- return(outsize);
+ END_PROFILE(SMBlockread);
+ return(outsize);
}
/****************************************************************************
reply to a read
****************************************************************************/
-int reply_read(char *inbuf,char *outbuf)
+
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,numtoread,fnum;
- int nread = 0;
+ size_t numtoread;
+ ssize_t nread = 0;
char *data;
- int startpos;
+ SMB_OFF_T startpos;
int outsize = 0;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBread);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
-
+
+
outsize = set_message(outbuf,5,3,True);
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- if (is_locked(fnum,cnum,numtoread,startpos))
- return(ERROR(ERRDOS,ERRlock));
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ END_PROFILE(SMBread);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
if (numtoread > 0)
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
-
- if (nread < 0)
+ nread = read_file(fsp,data,startpos,numtoread);
+
+ if (nread < 0) {
+ END_PROFILE(SMBread);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
outsize += nread;
SSVAL(outbuf,smb_vwv0,nread);
@@ -1458,8 +1627,10 @@ int reply_read(char *inbuf,char *outbuf)
CVAL(smb_buf(outbuf),0) = 1;
SSVAL(smb_buf(outbuf),1,nread);
- DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
-
+ DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
+ fsp->fnum, (int)numtoread, (int)nread ) );
+
+ END_PROFILE(SMBread);
return(outsize);
}
@@ -1467,605 +1638,811 @@ int reply_read(char *inbuf,char *outbuf)
/****************************************************************************
reply to a read and X
****************************************************************************/
-int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
- int smb_maxcnt = SVAL(inbuf,smb_vwv5);
- int smb_mincnt = SVAL(inbuf,smb_vwv6);
- int cnum;
- int nread = -1;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
+ size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+ size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
+ ssize_t nread = -1;
char *data;
- int outsize = 0;
- BOOL ok = False;
+ START_PROFILE(SMBreadX);
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ END_PROFILE(SMBreadX);
+ return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
- outsize = set_message(outbuf,12,0,True);
+ set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
- if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
- return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False);
- ok = True;
-
- if (nread < 0)
+ if(CVAL(inbuf,smb_wct) == 12) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv10) != 0) {
+ DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
+ END_PROFILE(SMBreadX);
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+
+ }
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ END_PROFILE(SMBreadX);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
+ nread = read_file(fsp,data,startpos,smb_maxcnt);
+
+ if (nread < 0) {
+ END_PROFILE(SMBreadX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- outsize += nread;
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf) + chain_size);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,nread);
- DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d com2=%d off2=%d\n",
- timestring(),fnum,cnum,
- smb_mincnt,smb_maxcnt,nread,smb_com2,smb_off2));
-
- chain_fnum = fnum;
+ DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ END_PROFILE(SMBreadX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
-
/****************************************************************************
reply to a writebraw (core+ or LANMAN1.0 protocol)
****************************************************************************/
-int reply_writebraw(char *inbuf,char *outbuf)
-{
- int nwritten=0;
- int total_written=0;
- int numtowrite=0;
- int cnum,fnum;
- int outsize = 0;
- long startpos;
- char *data=NULL;
- BOOL write_through;
- int tcount;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
-
- tcount = IVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv3);
- write_through = BITSETW(inbuf+smb_vwv7,0);
-
- /* We have to deal with slightly different formats depending
- on whether we are using the core+ or lanman1.0 protocol */
- if(Protocol <= PROTOCOL_COREPLUS) {
- numtowrite = SVAL(smb_buf(inbuf),-2);
- data = smb_buf(inbuf);
- } else {
- numtowrite = SVAL(inbuf,smb_vwv10);
- data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
- }
- /* force the error type */
- CVAL(inbuf,smb_com) = SMBwritec;
- CVAL(outbuf,smb_com) = SMBwritec;
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ ssize_t nwritten=0;
+ ssize_t total_written=0;
+ size_t numtowrite=0;
+ size_t tcount;
+ SMB_OFF_T startpos;
+ char *data=NULL;
+ BOOL write_through;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
+ START_PROFILE(SMBwritebraw);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ tcount = IVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv3);
+ write_through = BITSETW(inbuf+smb_vwv7,0);
+
+ /* We have to deal with slightly different formats depending
+ on whether we are using the core+ or lanman1.0 protocol */
+
+ if(Protocol <= PROTOCOL_COREPLUS) {
+ numtowrite = SVAL(smb_buf(inbuf),-2);
+ data = smb_buf(inbuf);
+ } else {
+ numtowrite = SVAL(inbuf,smb_vwv10);
+ data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
+ }
- if (is_locked(fnum,cnum,tcount,startpos))
- return(ERROR(ERRDOS,ERRlock));
+ /* force the error type */
+ CVAL(inbuf,smb_com) = SMBwritec;
+ CVAL(outbuf,smb_com) = SMBwritec;
- if (seek_file(fnum,startpos) != startpos)
- DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwritebraw);
+ return(ERROR_DOS(ERRDOS,ERRlock));
+ }
- if (numtowrite>0)
- nwritten = write_file(fnum,data,numtowrite);
+ if (numtowrite>0)
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
- timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
+ DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
- if (nwritten < numtowrite)
- return(UNIXERROR(ERRHRD,ERRdiskfull));
+ if (nwritten < numtowrite) {
+ END_PROFILE(SMBwritebraw);
+ return(UNIXERROR(ERRHRD,ERRdiskfull));
+ }
- total_written = nwritten;
+ total_written = nwritten;
- /* Return a message to the redirector to tell it
- to send more bytes */
- CVAL(outbuf,smb_com) = SMBwritebraw;
- SSVALS(outbuf,smb_vwv0,-1);
- outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
- send_smb(Client,outbuf);
+ /* Return a message to the redirector to tell it to send more bytes */
+ CVAL(outbuf,smb_com) = SMBwritebraw;
+ SSVALS(outbuf,smb_vwv0,-1);
+ outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_writebraw: send_smb failed.");
- /* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
- exit_server("secondary writebraw failed");
- }
+ /* Now read the raw data into the buffer and write it */
+ if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
+ exit_server("secondary writebraw failed");
+ }
- /* Even though this is not an smb message, smb_len
- returns the generic length of an smb message */
- numtowrite = smb_len(inbuf);
+ /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
+ numtowrite = smb_len(inbuf);
- if (tcount > nwritten+numtowrite) {
- DEBUG(3,("Client overestimated the write %d %d %d\n",
- tcount,nwritten,numtowrite));
- }
+ /* Set up outbuf to return the correct return */
+ outsize = set_message(outbuf,1,0,True);
+ CVAL(outbuf,smb_com) = SMBwritec;
+ SSVAL(outbuf,smb_vwv0,total_written);
- nwritten = transfer_file(Client,Files[fnum].fd,numtowrite,NULL,0,
- startpos+nwritten);
- total_written += nwritten;
-
- /* Set up outbuf to return the correct return */
- outsize = set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBwritec;
- SSVAL(outbuf,smb_vwv0,total_written);
+ if (numtowrite != 0) {
- if (nwritten < numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
+ if (numtowrite > BUFFER_SIZE) {
+ DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
+ (unsigned int)numtowrite ));
+ exit_server("secondary writebraw failed");
+ }
- if (lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if (tcount > nwritten+numtowrite) {
+ DEBUG(3,("Client overestimated the write %d %d %d\n",
+ (int)tcount,(int)nwritten,(int)numtowrite));
+ }
- DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,startpos,numtowrite,total_written));
+ if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
+ DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
+ strerror(errno) ));
+ exit_server("secondary writebraw failed");
+ }
- /* we won't return a status if write through is not selected - this
- follows what WfWg does */
- if (!write_through && total_written==tcount)
- return(-1);
+ nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
- return(outsize);
-}
+ if (nwritten < (ssize_t)numtowrite) {
+ CVAL(outbuf,smb_rcls) = ERRHRD;
+ SSVAL(outbuf,smb_err,ERRdiskfull);
+ }
+ if (nwritten > 0)
+ total_written += nwritten;
+ }
+
+ if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
+ sync_file(conn,fsp);
+
+ DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+ fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+
+ /* we won't return a status if write through is not selected - this follows what WfWg does */
+ END_PROFILE(SMBwritebraw);
+ if (!write_through && total_written==tcount) {
+ /*
+ * Fix for "rabbit pellet" mode, trigger an early TCP ack by
+ * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
+ */
+ if (!send_keepalive(smbd_server_fd()))
+ exit_server("reply_writebraw: send of keepalive failed");
+ return(-1);
+ }
+
+ return(outsize);
+}
/****************************************************************************
reply to a writeunlock (core+)
****************************************************************************/
-int reply_writeunlock(char *inbuf,char *outbuf)
-{
- int cnum,fnum;
- int nwritten = -1;
- int outsize = 0;
- char *data;
- uint32 numtowrite,startpos;
- int eclass;
- uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
+ int size, int dum_buffsize)
+{
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
+ char *data;
+ NTSTATUS status;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
+ START_PROFILE(SMBwriteunlock);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ data = smb_buf(inbuf) + 3;
- if (is_locked(fnum,cnum,numtowrite,startpos))
- return(ERROR(ERRDOS,ERRlock));
-
- seek_file(fnum,startpos);
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
+ WRITE_LOCK,False)) {
+ END_PROFILE(SMBwriteunlock);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- /* The special X/Open SMB protocol handling of
- zero length writes is *NOT* done for
- this call */
- if(numtowrite == 0)
- nwritten = 0;
- else
- nwritten = write_file(fnum,data,numtowrite);
+ /* The special X/Open SMB protocol handling of
+ zero length writes is *NOT* done for
+ this call */
+ if(numtowrite == 0)
+ nwritten = 0;
+ else
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(cnum)))
- sync_file(fnum);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
- return(ERROR(eclass,ecode));
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ END_PROFILE(SMBwriteunlock);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- outsize = set_message(outbuf,1,0,True);
-
- SSVAL(outbuf,smb_vwv0,nwritten);
-
- DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,numtowrite,nwritten));
-
- return(outsize);
+ status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
+ (SMB_BIG_UINT)startpos);
+ if (NT_STATUS_V(status)) {
+ END_PROFILE(SMBwriteunlock);
+ return ERROR_NT(status);
+ }
+
+ outsize = set_message(outbuf,1,0,True);
+
+ SSVAL(outbuf,smb_vwv0,nwritten);
+
+ DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
+
+ END_PROFILE(SMBwriteunlock);
+ return outsize;
}
/****************************************************************************
- reply to a write
+ Reply to a write.
****************************************************************************/
-int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
+
+int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
- char *data;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
+ START_PROFILE(SMBwrite);
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ END_PROFILE(SMBwrite);
+ return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
+ }
- dum1 = dum2 = 0;
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ data = smb_buf(inbuf) + 3;
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwrite);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
+ /*
+ * X/Open SMB protocol says that if smb_vwv1 is
+ * zero then the file size should be extended or
+ * truncated to the size given in smb_vwv[2-3].
+ */
+
+ if(numtowrite == 0) {
+ /*
+ * This is actually an allocate call, and set EOF. JRA.
+ */
+ nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ END_PROFILE(SMBwrite);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
+ if (nwritten < 0) {
+ END_PROFILE(SMBwrite);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ } else
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (is_locked(fnum,cnum,numtowrite,startpos))
- return(ERROR(ERRDOS,ERRlock));
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
- seek_file(fnum,startpos);
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ END_PROFILE(SMBwrite);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* X/Open SMB protocol says that if smb_vwv1 is
- zero then the file size should be extended or
- truncated to the size given in smb_vwv[2-3] */
- if(numtowrite == 0)
- nwritten = set_filelen(Files[fnum].fd, startpos);
- else
- nwritten = write_file(fnum,data,numtowrite);
+ outsize = set_message(outbuf,1,0,True);
- if (lp_syncalways(SNUM(cnum)))
- sync_file(fnum);
-
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ SSVAL(outbuf,smb_vwv0,nwritten);
- outsize = set_message(outbuf,1,0,True);
+ if (nwritten < (ssize_t)numtowrite) {
+ CVAL(outbuf,smb_rcls) = ERRHRD;
+ SSVAL(outbuf,smb_err,ERRdiskfull);
+ }
- SSVAL(outbuf,smb_vwv0,nwritten);
+ DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
- if (nwritten < numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
-
- DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
-
- return(outsize);
+ END_PROFILE(SMBwrite);
+ return(outsize);
}
/****************************************************************************
reply to a write and X
****************************************************************************/
-int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
- int smb_dsize = SVAL(inbuf,smb_vwv10);
- int smb_doff = SVAL(inbuf,smb_vwv11);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
+ size_t numtowrite = SVAL(inbuf,smb_vwv10);
BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
- int cnum;
- int nwritten = -1;
- int outsize = 0;
+ ssize_t nwritten = -1;
+ unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
+ unsigned int smblen = smb_len(inbuf);
char *data;
+ BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
+ START_PROFILE(SMBwriteX);
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn)) {
+ END_PROFILE(SMBwriteX);
+ return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ /* Deal with possible LARGE_WRITEX */
+ if (large_writeX)
+ numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
+
+ if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
+ END_PROFILE(SMBwriteX);
+ return ERROR_DOS(ERRDOS,ERRbadmem);
+ }
data = smb_base(inbuf) + smb_doff;
- if (is_locked(fnum,cnum,smb_dsize,smb_offs))
- return(ERROR(ERRDOS,ERRlock));
+ if(CVAL(inbuf,smb_wct) == 14) {
+#ifdef LARGE_SMB_OFF_T
+ /*
+ * This is a large offset (64 bit) write.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv12) != 0) {
+ DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
+ END_PROFILE(SMBwriteX);
+ return ERROR_DOS(ERRDOS,ERRbadaccess);
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwriteX);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- seek_file(fnum,smb_offs);
-
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done, just a write of zero. To truncate a file,
use SMBwrite. */
- if(smb_dsize == 0)
+ if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fnum,data,smb_dsize);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+ END_PROFILE(SMBwriteX);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- outsize = set_message(outbuf,6,0,True);
+ set_message(outbuf,6,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv2,nwritten);
-
- if (nwritten < smb_dsize) {
+ if (large_writeX)
+ SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
+
+ if (nwritten < (ssize_t)numtowrite) {
CVAL(outbuf,smb_rcls) = ERRHRD;
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
+ DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten));
- chain_fnum = fnum;
+ if (lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- if (lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ END_PROFILE(SMBwriteX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a lseek
****************************************************************************/
-int reply_lseek(char *inbuf,char *outbuf)
+
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
- uint32 startpos;
- int32 res= -1;
+ SMB_OFF_T startpos;
+ SMB_OFF_T res= -1;
int mode,umode;
int outsize = 0;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBlseek);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+
+ flush_write_cache(fsp, SEEK_FLUSH);
mode = SVAL(inbuf,smb_vwv1) & 3;
- startpos = IVAL(inbuf,smb_vwv2);
+ startpos = IVALS(inbuf,smb_vwv2);
- switch (mode & 3)
- {
+ switch (mode) {
case 0: umode = SEEK_SET; break;
case 1: umode = SEEK_CUR; break;
case 2: umode = SEEK_END; break;
default:
umode = SEEK_SET; break;
+ }
+
+ if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
+ /*
+ * Check for the special case where a seek before the start
+ * of the file sets the offset to zero. Added in the CIFS spec,
+ * section 4.2.7.
+ */
+
+ if(errno == EINVAL) {
+ SMB_OFF_T current_pos = startpos;
+
+ if(umode == SEEK_CUR) {
+
+ if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
+ END_PROFILE(SMBlseek);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ current_pos += startpos;
+
+ } else if (umode == SEEK_END) {
+
+ SMB_STRUCT_STAT sbuf;
+
+ if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
+ END_PROFILE(SMBlseek);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ current_pos += sbuf.st_size;
+ }
+
+ if(current_pos < 0)
+ res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
}
-
- res = lseek(Files[fnum].fd,startpos,umode);
- Files[fnum].pos = res;
+
+ if(res == -1) {
+ END_PROFILE(SMBlseek);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ fsp->pos = res;
outsize = set_message(outbuf,2,0,True);
- SIVALS(outbuf,smb_vwv0,res);
-
- DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
+ SIVAL(outbuf,smb_vwv0,res);
+ DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+ fsp->fnum, (double)startpos, (double)res, mode));
+
+ END_PROFILE(SMBlseek);
return(outsize);
}
-
/****************************************************************************
reply to a flush
****************************************************************************/
-int reply_flush(char *inbuf,char *outbuf)
-{
- int cnum, fnum;
- int outsize = set_message(outbuf,0,0,True);
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- if (fnum != 0xFFFF) {
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
- }
-
- if (fnum == 0xFFFF)
- {
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if (OPEN_FNUM(i))
- sync_file(i);
- }
- else
- sync_file(fnum);
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ int outsize = set_message(outbuf,0,0,True);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBflush);
- DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
- return(outsize);
+ CHECK_FSP(fsp,conn);
+
+ if (!fsp) {
+ file_sync_all(conn);
+ } else {
+ sync_file(conn,fsp);
+ }
+
+ DEBUG(3,("flush\n"));
+ END_PROFILE(SMBflush);
+ return(outsize);
}
/****************************************************************************
reply to a exit
****************************************************************************/
-int reply_exit(char *inbuf,char *outbuf)
+int reply_exit(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s exit\n",timestring()));
-
- return(outsize);
+ int outsize;
+ START_PROFILE(SMBexit);
+ outsize = set_message(outbuf,0,0,True);
+
+ DEBUG(3,("exit\n"));
+
+ END_PROFILE(SMBexit);
+ return(outsize);
}
/****************************************************************************
- reply to a close
+ Reply to a close - has to deal with closing a directory opened by NT SMB's.
****************************************************************************/
-int reply_close(char *inbuf,char *outbuf)
+int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
+ int dum_buffsize)
{
- int fnum,cnum;
- int outsize = 0;
- time_t mtime;
- int32 eclass = 0, err = 0;
+ int outsize = 0;
+ time_t mtime;
+ int32 eclass = 0, err = 0;
+ files_struct *fsp = NULL;
+ START_PROFILE(SMBclose);
+
+ outsize = set_message(outbuf,0,0,True);
+
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(conn)) {
+ END_PROFILE(SMBclose);
+ return reply_pipe_close(conn, inbuf,outbuf);
+ }
- outsize = set_message(outbuf,0,0,True);
+ fsp = file_fsp(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
+ /*
+ * We can only use CHECK_FSP if we know it's not a directory.
+ */
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
+ if(!fsp || (fsp->conn != conn)) {
+ END_PROFILE(SMBclose);
+ return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
- if(HAS_CACHED_ERROR(fnum)) {
- eclass = Files[fnum].wbmpx_ptr->wr_errclass;
- err = Files[fnum].wbmpx_ptr->wr_error;
- }
+ if(fsp->is_directory || fsp->stat_open) {
+ /*
+ * Special case - close NT SMB directory or stat file
+ * handle.
+ */
+ DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
+ close_file(fsp,True);
+ } else {
+ /*
+ * Close ordinary file.
+ */
+ int close_err;
+ pstring file_name;
+
+ /* Save the name for time set in close. */
+ pstrcpy( file_name, fsp->fsp_name);
+
+ DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
+ fsp->fd, fsp->fnum,
+ conn->num_files_open));
+
+ /*
+ * close_file() returns the unix errno if an error
+ * was detected on close - normally this is due to
+ * a disk full error. If not then it was probably an I/O error.
+ */
+
+ if((close_err = close_file(fsp,True)) != 0) {
+ errno = close_err;
+ END_PROFILE(SMBclose);
+ return (UNIXERROR(ERRHRD,ERRgeneral));
+ }
- mtime = make_unix_date3(inbuf+smb_vwv1);
+ /*
+ * Now take care of any time sent in the close.
+ */
- close_file(fnum);
+ mtime = make_unix_date3(inbuf+smb_vwv1);
+
+ /* try and set the date */
+ set_filetime(conn, file_name, mtime);
- /* try and set the date */
- set_filetime(Files[fnum].name,mtime);
+ }
- /* We have a cached error */
- if(eclass || err)
- return(ERROR(eclass,err));
+ /* We have a cached error */
+ if(eclass || err) {
+ END_PROFILE(SMBclose);
+ return ERROR_DOS(eclass,err);
+ }
- DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
- timestring(),Files[fnum].fd,fnum,cnum,
- Connections[cnum].num_files_open));
-
- return(outsize);
+ END_PROFILE(SMBclose);
+ return(outsize);
}
/****************************************************************************
reply to a writeclose (Core+ protocol)
****************************************************************************/
-int reply_writeclose(char *inbuf,char *outbuf)
+
+int reply_writeclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
- char *data;
- time_t mtime;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ int close_err = 0;
+ SMB_OFF_T startpos;
+ char *data;
+ time_t mtime;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBwriteclose);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ numtowrite = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ mtime = make_unix_date3(inbuf+smb_vwv4);
+ data = smb_buf(inbuf) + 1;
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ END_PROFILE(SMBwriteclose);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- mtime = make_unix_date3(inbuf+smb_vwv4);
- data = smb_buf(inbuf) + 1;
+ set_filetime(conn, fsp->fsp_name,mtime);
- if (is_locked(fnum,cnum,numtowrite,startpos))
- return(ERROR(ERRDOS,ERRlock));
-
- seek_file(fnum,startpos);
-
- nwritten = write_file(fnum,data,numtowrite);
+ close_err = close_file(fsp,True);
- close_file(fnum);
-
- set_filetime(Files[fnum].name,mtime);
-
- DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
- timestring(),fnum,cnum,numtowrite,nwritten,
- Connections[cnum].num_files_open));
+ DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten,
+ conn->num_files_open));
- if (nwritten <= 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,1,0,True);
+ if (nwritten <= 0) {
+ END_PROFILE(SMBwriteclose);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if(close_err != 0) {
+ errno = close_err;
+ END_PROFILE(SMBwriteclose);
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
+ outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
- return(outsize);
+ SSVAL(outbuf,smb_vwv0,nwritten);
+ END_PROFILE(SMBwriteclose);
+ return(outsize);
}
/****************************************************************************
reply to a lock
****************************************************************************/
-int reply_lock(char *inbuf,char *outbuf)
+int reply_lock(connection_struct *conn,
+ char *inbuf,char *outbuf, int length, int dum_buffsize)
{
- int fnum,cnum;
- int outsize = set_message(outbuf,0,0,True);
- uint32 count,offset;
- int eclass;
- uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
-
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
-
- DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ int outsize = set_message(outbuf,0,0,True);
+ SMB_BIG_UINT count,offset;
+ NTSTATUS status;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBlock);
+
+ CHECK_FSP(fsp,conn);
+
+ release_level_2_oplocks_on_change(fsp);
+
+ count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+
+ DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd, fsp->fnum, (double)offset, (double)count));
+
+ status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+ if (NT_STATUS_V(status)) {
+ if (lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, -1, 0)) {
+ END_PROFILE(SMBlock);
+ return -1;
+ }
+ }
+ END_PROFILE(SMBlock);
+ return ERROR_NT(status);
+ }
- if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
- return (ERROR(eclass,ecode));
-
- return(outsize);
+ END_PROFILE(SMBlock);
+ return(outsize);
}
/****************************************************************************
reply to a unlock
****************************************************************************/
-int reply_unlock(char *inbuf,char *outbuf)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
+ int dum_buffsize)
{
- int fnum,cnum;
- int outsize = set_message(outbuf,0,0,True);
- uint32 count,offset;
- int eclass;
- uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
-
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
+ int outsize = set_message(outbuf,0,0,True);
+ SMB_BIG_UINT count,offset;
+ NTSTATUS status;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBunlock);
- if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
- return (ERROR(eclass,ecode));
+ CHECK_FSP(fsp,conn);
+
+ count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+ offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+
+ status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
+ if (NT_STATUS_V(status)) {
+ END_PROFILE(SMBunlock);
+ return ERROR_NT(status);
+ }
- DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
-
- return(outsize);
+ DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd, fsp->fnum, (double)offset, (double)count ) );
+
+ END_PROFILE(SMBunlock);
+ return(outsize);
}
/****************************************************************************
reply to a tdis
****************************************************************************/
-int reply_tdis(char *inbuf,char *outbuf)
+int reply_tdis(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum, uid;
- int outsize = set_message(outbuf,0,0,True);
-
- cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
+ int outsize = set_message(outbuf,0,0,True);
+ uint16 vuid;
+ START_PROFILE(SMBtdis);
- Connections[cnum].used = False;
+ vuid = SVAL(inbuf,smb_uid);
- close_cnum(cnum,uid);
-
- DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
+ if (!conn) {
+ DEBUG(4,("Invalid connection in tdis\n"));
+ END_PROFILE(SMBtdis);
+ return ERROR_DOS(ERRSRV,ERRinvnid);
+ }
+
+ conn->used = False;
- return outsize;
+ close_cnum(conn,vuid);
+
+ END_PROFILE(SMBtdis);
+ return outsize;
}
@@ -2073,316 +2450,438 @@ int reply_tdis(char *inbuf,char *outbuf)
/****************************************************************************
reply to a echo
****************************************************************************/
-int reply_echo(char *inbuf,char *outbuf)
+int reply_echo(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum;
- int smb_reverb = SVAL(inbuf,smb_vwv0);
- int seq_num;
- int data_len = smb_buflen(inbuf);
- int outsize = set_message(outbuf,1,data_len,True);
+ int smb_reverb = SVAL(inbuf,smb_vwv0);
+ int seq_num;
+ unsigned int data_len = smb_buflen(inbuf);
+ int outsize = set_message(outbuf,1,data_len,True);
+ START_PROFILE(SMBecho);
- cnum = SVAL(inbuf,smb_tid);
+ data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
- if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
- {
- DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
- return(ERROR(ERRSRV,ERRinvnid));
- }
+ /* copy any incoming data back out */
+ if (data_len > 0)
+ memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
- /* copy any incoming data back out */
- if (data_len > 0)
- memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
+ if (smb_reverb > 100) {
+ DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
+ smb_reverb = 100;
+ }
- if (smb_reverb > 100)
- {
- DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
- smb_reverb = 100;
- }
+ for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
+ SSVAL(outbuf,smb_vwv0,seq_num);
- for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
- {
- SSVAL(outbuf,smb_vwv0,seq_num);
+ smb_setlen(outbuf,outsize - 4);
- smb_setlen(outbuf,outsize - 4);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_echo: send_smb failed.");
+ }
- send_smb(Client,outbuf);
- }
+ DEBUG(3,("echo %d times\n", smb_reverb));
- DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
+ smb_echo_count++;
- return -1;
+ END_PROFILE(SMBecho);
+ return -1;
}
/****************************************************************************
reply to a printopen
****************************************************************************/
-int reply_printopen(char *inbuf,char *outbuf)
+int reply_printopen(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- pstring fname;
- pstring fname2;
- int cnum;
- int fnum = -1;
- int outsize = 0;
-
- *fname = *fname2 = 0;
-
- cnum = SVAL(inbuf,smb_tid);
-
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- {
- pstring s;
- char *p;
- StrnCpy(s,smb_buf(inbuf)+1,sizeof(pstring)-1);
- p = s;
- while (*p)
- {
- if (!(isalnum(*p) || strchr("._-",*p)))
- *p = 'X';
- p++;
- }
-
- if (strlen(s) > 10) s[10] = 0;
-
- sprintf(fname,"%s.XXXXXX",s);
- }
-
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- strcpy(fname2,(char *)mktemp(fname));
-
- if (!check_name(fname2,cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
+ int outsize = 0;
+ files_struct *fsp;
+ START_PROFILE(SMBsplopen);
+
+ if (!CAN_PRINT(conn)) {
+ END_PROFILE(SMBsplopen);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
- open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
- unix_mode(cnum,0));
+ /* Open for exclusive use, write only. */
+ fsp = print_fsp_open(conn);
- if (!Files[fnum].open)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (!fsp) {
+ END_PROFILE(SMBsplopen);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- /* force it to be a print file */
- Files[fnum].print_file = True;
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fnum);
-
- DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd,fnum,cnum));
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,fsp->fnum);
- return(outsize);
+ DEBUG(3,("openprint fd=%d fnum=%d\n",
+ fsp->fd, fsp->fnum));
+
+ END_PROFILE(SMBsplopen);
+ return(outsize);
}
/****************************************************************************
reply to a printclose
****************************************************************************/
-int reply_printclose(char *inbuf,char *outbuf)
+int reply_printclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int fnum,cnum;
- int outsize = set_message(outbuf,0,0,True);
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ int outsize = set_message(outbuf,0,0,True);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int close_err = 0;
+ START_PROFILE(SMBsplclose);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- close_file(fnum);
+ if (!CAN_PRINT(conn)) {
+ END_PROFILE(SMBsplclose);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
- DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd,fnum,cnum));
+ DEBUG(3,("printclose fd=%d fnum=%d\n",
+ fsp->fd,fsp->fnum));
- return(outsize);
+ close_err = close_file(fsp,True);
+
+ if(close_err != 0) {
+ errno = close_err;
+ END_PROFILE(SMBsplclose);
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
+ END_PROFILE(SMBsplclose);
+ return(outsize);
}
/****************************************************************************
reply to a printqueue
****************************************************************************/
-int reply_printqueue(char *inbuf,char *outbuf)
+int reply_printqueue(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum, uid;
- int outsize = set_message(outbuf,2,3,True);
- int max_count = SVAL(inbuf,smb_vwv0);
- int start_index = SVAL(inbuf,smb_vwv1);
-
- cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
-
-/* allow checking the queue for anyone */
-#if 0
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-#endif
+ int outsize = set_message(outbuf,2,3,True);
+ int max_count = SVAL(inbuf,smb_vwv0);
+ int start_index = SVAL(inbuf,smb_vwv1);
+ START_PROFILE(SMBsplretq);
+
+ /* we used to allow the client to get the cnum wrong, but that
+ is really quite gross and only worked when there was only
+ one printer - I think we should now only accept it if they
+ get it right (tridge) */
+ if (!CAN_PRINT(conn)) {
+ END_PROFILE(SMBsplretq);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
- SSVAL(outbuf,smb_vwv0,0);
- SSVAL(outbuf,smb_vwv1,0);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,0);
+ SSVAL(outbuf,smb_vwv0,0);
+ SSVAL(outbuf,smb_vwv1,0);
+ CVAL(smb_buf(outbuf),0) = 1;
+ SSVAL(smb_buf(outbuf),1,0);
- DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
- timestring(),cnum,start_index,max_count));
-
- if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
- {
- int i;
- cnum = -1;
-
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (CAN_PRINT(i) && Connections[i].printer)
- cnum = i;
-
- if (cnum == -1)
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (OPEN_CNUM(i))
- cnum = i;
+ DEBUG(3,("printqueue start_index=%d max_count=%d\n",
+ start_index, max_count));
- if (!OPEN_CNUM(cnum))
- return(ERROR(ERRSRV,ERRinvnid));
-
- DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
- }
-
- if (!become_user(cnum,uid))
- return(ERROR(ERRSRV,ERRinvnid));
-
- {
- print_queue_struct *queue = NULL;
- char *p = smb_buf(outbuf) + 3;
- int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
- int num_to_get = ABS(max_count);
- int first = (max_count>0?start_index:start_index+max_count+1);
- int i;
-
- if (first >= count)
- num_to_get = 0;
- else
- num_to_get = MIN(num_to_get,count-first);
+ {
+ print_queue_struct *queue = NULL;
+ char *p = smb_buf(outbuf) + 3;
+ int count = print_queue_status(SNUM(conn), &queue,NULL);
+ int num_to_get = ABS(max_count);
+ int first = (max_count>0?start_index:start_index+max_count+1);
+ int i;
+
+ if (first >= count)
+ num_to_get = 0;
+ else
+ num_to_get = MIN(num_to_get,count-first);
- for (i=first;i<first+num_to_get;i++)
- {
- put_dos_date2(p,0,queue[i].time);
- CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
- SSVAL(p,5,queue[i].job);
- SIVAL(p,7,queue[i].size);
- CVAL(p,11) = 0;
- StrnCpy(p+12,queue[i].user,16);
- p += 28;
- }
+ for (i=first;i<first+num_to_get;i++) {
+ put_dos_date2(p,0,queue[i].time);
+ CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
+ SSVAL(p,5, queue[i].job);
+ SIVAL(p,7,queue[i].size);
+ CVAL(p,11) = 0;
+ srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
+ p += 28;
+ }
- if (count > 0)
- {
- outsize = set_message(outbuf,2,28*count+3,False);
- SSVAL(outbuf,smb_vwv0,count);
- SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,28*count);
- }
+ if (count > 0) {
+ outsize = set_message(outbuf,2,28*count+3,False);
+ SSVAL(outbuf,smb_vwv0,count);
+ SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
+ CVAL(smb_buf(outbuf),0) = 1;
+ SSVAL(smb_buf(outbuf),1,28*count);
+ }
- if (queue) free(queue);
+ SAFE_FREE(queue);
- DEBUG(3,("%d entries returned in queue\n",count));
- }
+ DEBUG(3,("%d entries returned in queue\n",count));
+ }
- return(outsize);
+ END_PROFILE(SMBsplretq);
+ return(outsize);
}
/****************************************************************************
reply to a printwrite
****************************************************************************/
-int reply_printwrite(char *inbuf,char *outbuf)
+int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
+ int numtowrite;
int outsize = set_message(outbuf,0,0,True);
char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBsplwr);
- cnum = SVAL(inbuf,smb_tid);
-
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- fnum = GETFNUM(inbuf,smb_vwv0);
+ if (!CAN_PRINT(conn)) {
+ END_PROFILE(SMBsplwr);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
numtowrite = SVAL(smb_buf(inbuf),1);
data = smb_buf(inbuf) + 3;
- if (write_file(fnum,data,numtowrite) != numtowrite)
+ if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
+ END_PROFILE(SMBsplwr);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
- DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
-
+ END_PROFILE(SMBsplwr);
return(outsize);
}
/****************************************************************************
- reply to a mkdir
+ The guts of the mkdir command, split out so it may be called by the NT SMB
+ code.
****************************************************************************/
-int reply_mkdir(char *inbuf,char *outbuf)
+NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
{
- pstring directory;
- int cnum;
- int outsize,ret= -1;
-
- strcpy(directory,smb_buf(inbuf) + 1);
- cnum = SVAL(inbuf,smb_tid);
- unix_convert(directory,cnum);
-
- if (check_name(directory,cnum))
- ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
-
- if (ret < 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,0,0,True);
-
- DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
-
- return(outsize);
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+ int ret= -1;
+
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+
+ if (check_name(directory, conn))
+ ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a mkdir.
+****************************************************************************/
+
+int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+ pstring directory;
+ int outsize;
+ NTSTATUS status;
+ START_PROFILE(SMBmkdir);
+
+ srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+
+ status = mkdir_internal(conn, directory);
+ if (!NT_STATUS_IS_OK(status))
+ return ERROR_NT(status);
+
+ outsize = set_message(outbuf,0,0,True);
+
+ DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
+
+ END_PROFILE(SMBmkdir);
+ return(outsize);
+}
+
+/****************************************************************************
+ Static function used by reply_rmdir to delete an entire directory
+ tree recursively. Return False on ok, True on fail.
+****************************************************************************/
+
+static BOOL recursive_rmdir(connection_struct *conn, char *directory)
+{
+ char *dname = NULL;
+ BOOL ret = False;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if(dirptr == NULL)
+ return True;
+
+ while((dname = ReadDirName(dirptr))) {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+ errno = ENOMEM;
+ ret = True;
+ break;
+ }
+
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
+ ret = True;
+ break;
+ }
+
+ if(st.st_mode & S_IFDIR) {
+ if(recursive_rmdir(conn, fullname)!=0) {
+ ret = True;
+ break;
+ }
+ if(vfs_rmdir(conn,fullname) != 0) {
+ ret = True;
+ break;
+ }
+ } else if(vfs_unlink(conn,fullname) != 0) {
+ ret = True;
+ break;
+ }
+ }
+ CloseDir(dirptr);
+ return ret;
}
+/****************************************************************************
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+BOOL rmdir_internals(connection_struct *conn, char *directory)
+{
+ BOOL ok;
+
+ ok = (vfs_rmdir(conn,directory) == 0);
+ if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+ /*
+ * Check to see if the only thing in this directory are
+ * vetoed files/directories. If so then delete them and
+ * retry. If we fail to delete any of them (and we *don't*
+ * do a recursive delete) then fail the rmdir.
+ */
+ BOOL all_veto_files = True;
+ char *dname;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if(dirptr != NULL) {
+ int dirpos = TellDir(dirptr);
+ while ((dname = ReadDirName(dirptr))) {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+ if(!IS_VETO_PATH(conn, dname)) {
+ all_veto_files = False;
+ break;
+ }
+ }
+
+ if(all_veto_files) {
+ SeekDir(dirptr,dirpos);
+ while ((dname = ReadDirName(dirptr))) {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+ errno = ENOMEM;
+ break;
+ }
+
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
+ break;
+ if(st.st_mode & S_IFDIR) {
+ if(lp_recursive_veto_delete(SNUM(conn))) {
+ if(recursive_rmdir(conn, fullname) != 0)
+ break;
+ }
+ if(vfs_rmdir(conn,fullname) != 0)
+ break;
+ } else if(vfs_unlink(conn,fullname) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok = (vfs_rmdir(conn,directory) == 0);
+ } else {
+ CloseDir(dirptr);
+ }
+ } else {
+ errno = ENOTEMPTY;
+ }
+ }
+
+ if (!ok)
+ DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
+
+ return ok;
+}
/****************************************************************************
- reply to a rmdir
+ Reply to a rmdir.
****************************************************************************/
-int reply_rmdir(char *inbuf,char *outbuf)
+
+int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
- int cnum;
int outsize = 0;
BOOL ok = False;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
+ START_PROFILE(SMBrmdir);
+
+ srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+
+ RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+
+ unix_convert(directory,conn, NULL,&bad_path,&sbuf);
- cnum = SVAL(inbuf,smb_tid);
- strcpy(directory,smb_buf(inbuf) + 1);
- unix_convert(directory,cnum);
+ if (check_name(directory,conn))
+ {
+ dptr_closepath(directory,SVAL(inbuf,smb_pid));
+ ok = rmdir_internals(conn, directory);
+ }
- if (check_name(directory,cnum))
+ if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
{
- dptr_closepath(directory,SVAL(inbuf,smb_pid));
- ok = (sys_rmdir(directory) == 0);
- if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
- directory,strerror(errno)));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
}
-
- if (!ok)
+ END_PROFILE(SMBrmdir);
return(UNIXERROR(ERRDOS,ERRbadpath));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s rmdir %s\n",timestring(),directory));
+ DEBUG( 3, ( "rmdir %s\n", directory ) );
+ END_PROFILE(SMBrmdir);
return(outsize);
}
@@ -2396,26 +2895,26 @@ static BOOL resolve_wildcards(char *name1,char *name2)
fstring ext1,ext2;
char *p,*p2;
- name1 = strrchr(name1,'/');
- name2 = strrchr(name2,'/');
+ name1 = strrchr_m(name1,'/');
+ name2 = strrchr_m(name2,'/');
if (!name1 || !name2) return(False);
- strcpy(root1,name1);
- strcpy(root2,name2);
- p = strrchr(root1,'.');
+ fstrcpy(root1,name1);
+ fstrcpy(root2,name2);
+ p = strrchr_m(root1,'.');
if (p) {
*p = 0;
- strcpy(ext1,p+1);
+ fstrcpy(ext1,p+1);
} else {
- strcpy(ext1,"");
+ fstrcpy(ext1,"");
}
- p = strrchr(root2,'.');
+ p = strrchr_m(root2,'.');
if (p) {
*p = 0;
- strcpy(ext2,p+1);
+ fstrcpy(ext2,p+1);
} else {
- strcpy(ext2,"");
+ fstrcpy(ext2,"");
}
p = root1;
@@ -2442,10 +2941,10 @@ static BOOL resolve_wildcards(char *name1,char *name2)
if (*p) p++;
}
- strcpy(name2,root2);
+ pstrcpy(name2,root2);
if (ext2[0]) {
- strcat(name2,".");
- strcat(name2,ext2);
+ pstrcat(name2,".");
+ pstrcat(name2,ext2);
}
return(True);
@@ -2454,737 +2953,1234 @@ static BOOL resolve_wildcards(char *name1,char *name2)
/*******************************************************************
check if a user is allowed to rename a file
********************************************************************/
-static BOOL can_rename(char *fname,int cnum)
+static BOOL can_rename(char *fname,connection_struct *conn)
{
- struct stat sbuf;
-
- if (!CAN_WRITE(cnum)) return(False);
+ SMB_STRUCT_STAT sbuf;
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
+ if (!CAN_WRITE(conn)) return(False);
+ if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
+ if (!check_file_sharing(conn,fname,True)) return(False);
return(True);
}
/****************************************************************************
- reply to a mv
+ The guts of the rename command, split out so it may be called by the NT SMB
+ code.
****************************************************************************/
-int reply_mv(char *inbuf,char *outbuf)
+NTSTATUS rename_internals(connection_struct *conn,
+ char *name,
+ char *newname, BOOL replace_if_exists)
{
- int outsize = 0;
- pstring name;
- int cnum;
- pstring directory;
- pstring mask,newname;
- char *p;
- int count=0;
- int error = ERRnoaccess;
- BOOL has_wild;
- BOOL exists=False;
-
- *directory = *mask = 0;
-
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf) + 1);
- strcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
-
- DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
-
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ pstring directory;
+ pstring mask;
+ pstring newname_last_component;
+ char *p;
+ BOOL has_wild;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+ int count=0;
+ NTSTATUS error = NT_STATUS_OK;
+ BOOL exists=False;
+ BOOL rc = True;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ *directory = *mask = 0;
+
+ rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
+ unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2);
+
+ /*
+ * Split the old name into directory and last component
+ * strings. Note that unix_convert may have stripped off a
+ * leading ./ from both name and newname if the rename is
+ * at the root of the share. We need to make sure either both
+ * name and newname contain a / character or neither of them do
+ * as this is checked in resolve_wildcards().
+ */
+
+ p = strrchr_m(name,'/');
+ if (!p) {
+ pstrcpy(directory,".");
+ pstrcpy(mask,name);
+ } else {
+ *p = 0;
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
+ *p = '/'; /* Replace needed for exceptional test below. */
+ }
- p = strrchr(name,'/');
- if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
- } else {
- *p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
- }
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
- if (is_mangled(mask))
- check_mangled_stack(mask);
+#if 0
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
+#endif
+ if (!rc)
+ {
+ char *unmangled;
+
+ unmangled = dos_unmangle(mask);
+ if (unmangled)
+ strncpy(mask, unmangled, strlen(unmangled) + 1);
+
+ SAFE_FREE(unmangled);
+ }
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ has_wild = ms_has_wild(mask);
+
+ if (!has_wild) {
+ /*
+ * No wildcards - just process the one file.
+ */
+ BOOL is_short_name = is_8_3(name, True);
+
+ /* Add a terminating '/' to the directory name. */
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+
+ /* Ensure newname contains a '/' also */
+ if(strrchr_m(newname,'/') == 0) {
+ pstring tmpstr;
+
+ pstrcpy(tmpstr, "./");
+ pstrcat(tmpstr, newname);
+ pstrcpy(newname, tmpstr);
+ }
+
+ DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+ case_sensitive, case_preserve, short_case_preserve, directory,
+ newname, newname_last_component, is_short_name));
+
+ /*
+ * Check for special case with case preserving and not
+ * case sensitive, if directory and newname are identical,
+ * and the old last component differs from the original
+ * last component only by case, then we should allow
+ * the rename (user is trying to change the case of the
+ * filename).
+ */
+ if((case_sensitive == False) &&
+ (((case_preserve == True) &&
+ (is_short_name == False)) ||
+ ((short_case_preserve == True) &&
+ (is_short_name == True))) &&
+ strcsequal(directory, newname)) {
+ pstring newname_modified_last_component;
+
+ /*
+ * Get the last component of the modified name.
+ * Note that we guarantee that newname contains a '/'
+ * character above.
+ */
+ p = strrchr_m(newname,'/');
+ pstrcpy(newname_modified_last_component,p+1);
+
+ if(strcsequal(newname_modified_last_component,
+ newname_last_component) == False) {
+ /*
+ * Replace the modified last component with
+ * the original.
+ */
+ pstrcpy(p+1, newname_last_component);
+ }
+ }
+
+ if(replace_if_exists) {
+ /*
+ * NT SMB specific flag - rename can overwrite
+ * file with the same name so don't check for
+ * vfs_file_exist().
+ */
+
+ if(resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ conn->vfs_ops.rename(conn,directory,newname) == 0)
+ count++;
+ } else {
+ if (resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ !vfs_file_exist(conn,newname,NULL) &&
+ conn->vfs_ops.rename(conn,directory,newname) == 0)
+ count++;
+ }
- if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
- if (resolve_wildcards(directory,newname) &&
- can_rename(directory,cnum) &&
- !file_exist(newname,NULL) &&
- !sys_rename(directory,newname)) count++;
- if (!count) exists = file_exist(directory,NULL);
- if (!count && exists && file_exist(newname,NULL)) {
- exists = True;
- error = 183;
- }
- } else {
- void *dirptr = NULL;
- char *dname;
- pstring destname;
+ DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
+ directory,newname));
+
+ if (!count) exists = vfs_file_exist(conn,directory,NULL);
+ if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
+ exists = True;
+ error = NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ } else {
+ /*
+ * Wildcards - process each file that matches.
+ */
+ void *dirptr = NULL;
+ char *dname;
+ pstring destname;
+
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ if (dirptr) {
+ error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ if (strequal(mask,"????????.???"))
+ pstrcpy(mask,"*");
+
+ while ((dname = ReadDirName(dirptr))) {
+ pstring fname;
+
+ pstrcpy(fname,dname);
+
+ if(!mask_match(fname, mask, case_sensitive))
+ continue;
+
+ error = NT_STATUS_ACCESS_DENIED;
+ slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
+ if (!can_rename(fname,conn)) {
+ DEBUG(6,("rename %s refused\n", fname));
+ continue;
+ }
+ pstrcpy(destname,newname);
+
+ if (!resolve_wildcards(fname,destname)) {
+ DEBUG(6,("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ continue;
+ }
+
+ if (!replace_if_exists &&
+ vfs_file_exist(conn,destname, NULL)) {
+ DEBUG(6,("file_exist %s\n", destname));
+ error = NT_STATUS_OBJECT_NAME_COLLISION;
+ continue;
+ }
+
+ if (!conn->vfs_ops.rename(conn,fname,destname))
+ count++;
+ DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0 && NT_STATUS_IS_OK(error)) {
+ error = map_nt_error_from_unix(errno);
+ }
+
+ return error;
+}
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+/****************************************************************************
+ Reply to a mv.
+****************************************************************************/
- if (dirptr)
- {
- error = ERRbadfile;
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ pstring newname;
+ char *p;
+ NTSTATUS status;
- if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ START_PROFILE(SMBmv);
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- strcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ p = smb_buf(inbuf) + 1;
+ p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+ p++;
+ p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+
+ status = rename_internals(conn, name, newname, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
- error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_rename(fname,cnum)) continue;
- strcpy(destname,newname);
-
- if (!resolve_wildcards(fname,destname)) continue;
-
- if (file_exist(destname,NULL)) {
- error = 183;
- continue;
- }
- if (!sys_rename(fname,destname)) count++;
- DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
- }
- CloseDir(dirptr);
- }
- }
+ /*
+ * Win2k needs a changenotify request response before it will
+ * update after a rename..
+ */
+ process_pending_change_notify_queue((time_t)0);
+ outsize = set_message(outbuf,0,0,True);
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- return(UNIXERROR(ERRDOS,error));
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- return(outsize);
+ END_PROFILE(SMBmv);
+ return(outsize);
}
/*******************************************************************
- copy a file as part of a reply_copy
- ******************************************************************/
-static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
- int count,BOOL target_is_directory)
+ Copy a file as part of a reply_copy.
+******************************************************************/
+
+static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
+ int count,BOOL target_is_directory, int *err_ret)
{
- int Access,action;
- struct stat st;
- int ret=0;
- int fnum1,fnum2;
- pstring dest;
-
- strcpy(dest,dest1);
- if (target_is_directory) {
- char *p = strrchr(src,'/');
- if (p)
- p++;
- else
- p = src;
- strcat(dest,"/");
- strcat(dest,p);
- }
+ int Access,action;
+ SMB_STRUCT_STAT src_sbuf, sbuf2;
+ SMB_OFF_T ret=-1;
+ files_struct *fsp1,*fsp2;
+ pstring dest;
+
+ *err_ret = 0;
+
+ pstrcpy(dest,dest1);
+ if (target_is_directory) {
+ char *p = strrchr_m(src,'/');
+ if (p)
+ p++;
+ else
+ p = src;
+ pstrcat(dest,"/");
+ pstrcat(dest,p);
+ }
- if (!file_exist(src,&st)) return(False);
+ if (!vfs_file_exist(conn,src,&src_sbuf))
+ return(False);
- fnum1 = find_free_file();
- if (fnum1<0) return(False);
- open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
- 1,0,&Access,&action);
+ fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
- if (!Files[fnum1].open) return(False);
+ if (!fsp1)
+ return(False);
- if (!target_is_directory && count)
- ofun = 1;
+ if (!target_is_directory && count)
+ ofun = FILE_EXISTS_OPEN;
- fnum2 = find_free_file();
- if (fnum2<0) {
- close_file(fnum1);
- return(False);
- }
- open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
- ofun,st.st_mode,&Access,&action);
+ if (vfs_stat(conn,dest,&sbuf2) == -1)
+ ZERO_STRUCTP(&sbuf2);
- if (!Files[fnum2].open) {
- close_file(fnum1);
- return(False);
- }
+ fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+ ofun,src_sbuf.st_mode,0,&Access,&action);
- if ((ofun&3) == 1) {
- lseek(Files[fnum2].fd,0,SEEK_END);
- }
+ if (!fsp2) {
+ close_file(fsp1,False);
+ return(False);
+ }
+
+ if ((ofun&3) == 1) {
+ if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
+ DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
+ /*
+ * Stop the copy from occurring.
+ */
+ ret = -1;
+ src_sbuf.st_size = 0;
+ }
+ }
- if (st.st_size)
- ret = transfer_file(Files[fnum1].fd,Files[fnum2].fd,st.st_size,NULL,0,0);
+ if (src_sbuf.st_size)
+ ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
- close_file(fnum1);
- close_file(fnum2);
+ close_file(fsp1,False);
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ *err_ret = close_file(fsp2,False);
- return(ret == st.st_size);
+ return(ret == (SMB_OFF_T)src_sbuf.st_size);
}
-
-
/****************************************************************************
reply to a file copy.
****************************************************************************/
-int reply_copy(char *inbuf,char *outbuf)
+int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
pstring name;
- int cnum;
pstring directory;
pstring mask,newname;
char *p;
int count=0;
int error = ERRnoaccess;
+ int err = 0;
BOOL has_wild;
BOOL exists=False;
int tid2 = SVAL(inbuf,smb_vwv0);
int ofun = SVAL(inbuf,smb_vwv1);
int flags = SVAL(inbuf,smb_vwv2);
BOOL target_is_directory=False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+ BOOL rc = True;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ START_PROFILE(SMBcopy);
*directory = *mask = 0;
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf));
- strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
+ p = smb_buf(inbuf);
+ p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+ p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
- if (tid2 != cnum) {
+ if (tid2 != conn->cnum) {
/* can't currently handle inter share copies XXXX */
DEBUG(3,("Rejecting inter-share copy\n"));
- return(ERROR(ERRSRV,ERRinvdevice));
+ END_PROFILE(SMBcopy);
+ return ERROR_DOS(ERRSRV,ERRinvdevice);
}
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+ rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
+ unix_convert(newname,conn,0,&bad_path2,&sbuf2);
- target_is_directory = directory_exist(newname,NULL);
+ target_is_directory = VALID_STAT_OF_DIR(sbuf2);
if ((flags&1) && target_is_directory) {
- return(ERROR(ERRDOS,ERRbadfile));
+ END_PROFILE(SMBcopy);
+ return ERROR_DOS(ERRDOS,ERRbadfile);
}
if ((flags&2) && !target_is_directory) {
- return(ERROR(ERRDOS,ERRbadpath));
+ END_PROFILE(SMBcopy);
+ return ERROR_DOS(ERRDOS,ERRbadpath);
}
- if ((flags&(1<<5)) && directory_exist(name,NULL)) {
+ if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
/* wants a tree copy! XXXX */
DEBUG(3,("Rejecting tree copy\n"));
- return(ERROR(ERRSRV,ERRerror));
+ END_PROFILE(SMBcopy);
+ return ERROR_DOS(ERRSRV,ERRerror);
}
- p = strrchr(name,'/');
+ p = strrchr_m(name,'/');
if (!p) {
- strcpy(directory,"./");
- strcpy(mask,name);
+ pstrcpy(directory,"./");
+ pstrcpy(mask,name);
} else {
*p = 0;
- strcpy(directory,name);
- strcpy(mask,p+1);
+ pstrcpy(directory,name);
+ pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
- check_mangled_stack(mask);
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+#if 0
+ if (!rc && is_mangled(mask))
+ check_mangled_cache( mask );
+#endif
+ if (!rc)
+ {
+ char *unmangled;
+
+ unmangled = dos_unmangle(mask);
+ if (unmangled)
+ strncpy(mask, unmangled, strlen(unmangled) + 1);
+
+ SAFE_FREE(unmangled);
+ }
+
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ has_wild = ms_has_wild(mask);
if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
if (resolve_wildcards(directory,newname) &&
- copy_file(directory,newname,cnum,ofun,
- count,target_is_directory)) count++;
- if (!count) exists = file_exist(directory,NULL);
+ copy_file(directory,newname,conn,ofun,
+ count,target_is_directory,&err)) count++;
+ if(!count && err) {
+ errno = err;
+ END_PROFILE(SMBcopy);
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+ if (!count) exists = vfs_file_exist(conn,directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
pstring destname;
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
- if (dirptr)
- {
+ if (dirptr) {
error = ERRbadfile;
if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr)))
- {
+ while ((dname = ReadDirName(dirptr))) {
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ if(!mask_match(fname, mask, case_sensitive))
+ continue;
error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- strcpy(destname,newname);
+ slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+ pstrcpy(destname,newname);
if (resolve_wildcards(fname,destname) &&
- copy_file(directory,newname,cnum,ofun,
- count,target_is_directory)) count++;
+ copy_file(fname,destname,conn,ofun,
+ count,target_is_directory,&err)) count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
CloseDir(dirptr);
- }
+ }
}
if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
+ if(err) {
+ /* Error on close... */
+ errno = err;
+ END_PROFILE(SMBcopy);
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
+ if (exists) {
+ END_PROFILE(SMBcopy);
+ return ERROR_DOS(ERRDOS,error);
+ } else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ END_PROFILE(SMBcopy);
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,count);
+ END_PROFILE(SMBcopy);
return(outsize);
}
-
-
/****************************************************************************
reply to a setdir
****************************************************************************/
-int reply_setdir(char *inbuf,char *outbuf)
+int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,snum;
+ int snum;
int outsize = 0;
BOOL ok = False;
pstring newdir;
+ START_PROFILE(pathworks_setdir);
- cnum = SVAL(inbuf,smb_tid);
-
- snum = Connections[cnum].service;
- if (!CAN_SETDIR(snum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- strcpy(newdir,smb_buf(inbuf) + 1);
- strlower(newdir);
+ snum = SNUM(conn);
+ if (!CAN_SETDIR(snum)) {
+ END_PROFILE(pathworks_setdir);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
- if (strlen(newdir) == 0)
- ok = True;
- else
- {
- ok = directory_exist(newdir,NULL);
- if (ok)
- string_set(&Connections[cnum].connectpath,newdir);
- }
+ if (strlen(newdir) == 0) {
+ ok = True;
+ } else {
+ ok = vfs_directory_exist(conn,newdir,NULL);
+ if (ok) {
+ string_set(&conn->connectpath,newdir);
+ }
+ }
- if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
+ if (!ok) {
+ END_PROFILE(pathworks_setdir);
+ return ERROR_DOS(ERRDOS,ERRbadpath);
+ }
outsize = set_message(outbuf,0,0,True);
CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
- DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
-
+ DEBUG(3,("setdir %s\n", newdir));
+
+ END_PROFILE(pathworks_setdir);
return(outsize);
}
+/****************************************************************************
+ Get a lock pid, dealing with large count requests.
+****************************************************************************/
+
+uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
+{
+ if(!large_file_format)
+ return SVAL(data,SMB_LPID_OFFSET(data_offset));
+ else
+ return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
+}
/****************************************************************************
- reply to a lockingX request
+ Get a lock count, dealing with large count requests.
****************************************************************************/
-int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
+
+SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int fnum = GETFNUM(inbuf,smb_vwv2);
- uint16 locktype = SVAL(inbuf,smb_vwv3);
- uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
- uint16 num_locks = SVAL(inbuf,smb_vwv7);
- uint32 count, offset;
-
- int cnum;
- int i;
- char *data;
- uint32 ecode=0, dummy2;
- int outsize, eclass=0, dummy1;
-
- cnum = SVAL(inbuf,smb_tid);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
-
- data = smb_buf(inbuf);
- /* Data now points at the beginning of the list
- of smb_unlkrng structs */
- for(i = 0; i < (int)num_ulocks; i++) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
- return ERROR(eclass,ecode);
- }
-
- /* Now do any requested locks */
- data += 10*num_ulocks;
- /* Data now points at the beginning of the list
- of smb_lkrng structs */
- for(i = 0; i < (int)num_locks; i++) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
- break;
- }
-
- /* If any of the above locks failed, then we must unlock
- all of the previous locks (X/Open spec). */
- if(i != num_locks && num_locks != 0) {
- for(; i >= 0; i--) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
- }
- return ERROR(eclass,ecode);
- }
+ SMB_BIG_UINT count = 0;
- outsize = set_message(outbuf,2,0,True);
-
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
-
- DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
+ if(!large_file_format) {
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+ } else {
- chain_fnum = fnum;
+#if defined(HAVE_LONGLONG)
+ count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints truncate the
+ * lock count by dropping the top 32 bits.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+ DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+ SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+ }
+
+ count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
+
+ return count;
}
+#if !defined(HAVE_LONGLONG)
+/****************************************************************************
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
+****************************************************************************/
+static uint32 map_lock_offset(uint32 high, uint32 low)
+{
+ unsigned int i;
+ uint32 mask = 0;
+ uint32 highcopy = high;
+
+ /*
+ * Try and find out how many significant bits there are in high.
+ */
+
+ for(i = 0; highcopy; i++)
+ highcopy >>= 1;
+
+ /*
+ * We use 31 bits not 32 here as POSIX
+ * lock offsets may not be negative.
+ */
+
+ mask = (~0) << (31 - i);
+
+ if(low & mask)
+ return 0; /* Fail. */
+
+ high <<= (31 - i);
+
+ return (high|low);
+}
+#endif /* !defined(HAVE_LONGLONG) */
/****************************************************************************
- reply to a SMBreadbmpx (read block multiplex) request
+ Get a lock offset, dealing with large offset requests.
****************************************************************************/
-int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
+
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
{
- int cnum,fnum;
- int nread = -1;
- int total_read;
- char *data;
- int32 startpos;
- int outsize, mincount, maxcount;
- int max_per_packet;
- int tcount;
- int pad;
+ SMB_BIG_UINT offset = 0;
- /* this function doesn't seem to work - disable by default */
- if (!lp_readbmpx())
- return(ERROR(ERRSRV,ERRuseSTD));
+ *err = False;
- outsize = set_message(outbuf,8,0,True);
+ if(!large_file_format) {
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+ } else {
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+#if defined(HAVE_LONGLONG)
+ offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ /*
+ * NT4.x seems to be broken in that it sends large file (64 bit)
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large unsigned ints mangle the
+ * lock offset by mapping the top 32 bits onto the lower 32.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+ uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+ uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+ uint32 new_low = 0;
+
+ if((new_low = map_lock_offset(high, low)) == 0) {
+ *err = True;
+ return (SMB_BIG_UINT)-1;
+ }
- startpos = IVAL(inbuf,smb_vwv1);
- maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
+ DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+ (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
+ }
- data = smb_buf(outbuf);
- pad = ((int)data)%4;
- if (pad) pad = 4 - pad;
- data += pad;
+ offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+ }
- max_per_packet = bufsize-(outsize+pad);
- tcount = maxcount;
- total_read = 0;
+ return offset;
+}
- if (is_locked(fnum,cnum,maxcount,startpos))
- return(ERROR(ERRDOS,ERRlock));
-
- do
- {
- int N = MIN(max_per_packet,tcount-total_read);
-
- nread = read_file(fnum,data,startpos,N,N,-1,False);
+/****************************************************************************
+ reply to a lockingX request
+****************************************************************************/
- if (nread <= 0) nread = 0;
+int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+ uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+ uint16 num_locks = SVAL(inbuf,smb_vwv7);
+ SMB_BIG_UINT count = 0, offset = 0;
+ uint16 lock_pid;
+ int32 lock_timeout = IVAL(inbuf,smb_vwv4);
+ int i;
+ char *data;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+ BOOL err;
+ NTSTATUS status;
+
+ START_PROFILE(SMBlockingX);
+
+ CHECK_FSP(fsp,conn);
+
+ data = smb_buf(inbuf);
+
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
+ /* Client can insist on breaking to none. */
+ BOOL break_to_none = (oplocklevel == 0);
+
+ DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
+ (unsigned int)oplocklevel, fsp->fnum ));
+
+ /*
+ * Make sure we have granted an exclusive or batch oplock on this file.
+ */
+
+ if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0) {
+ END_PROFILE(SMBlockingX);
+ return -1;
+ } else {
+ END_PROFILE(SMBlockingX);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
+ }
- if (nread < N)
- tcount = total_read + nread;
+ if (remove_oplock(fsp, break_to_none) == False) {
+ DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+ fsp->fsp_name ));
+ }
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0) {
+ /* Sanity check - ensure a pure oplock break is not a
+ chained request. */
+ if(CVAL(inbuf,smb_vwv0) != 0xff)
+ DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+ (unsigned int)CVAL(inbuf,smb_vwv0) ));
+ END_PROFILE(SMBlockingX);
+ return -1;
+ }
+ }
- set_message(outbuf,8,nread,False);
- SIVAL(outbuf,smb_vwv0,startpos);
- SSVAL(outbuf,smb_vwv2,tcount);
- SSVAL(outbuf,smb_vwv6,nread);
- SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
+ /*
+ * We do this check *after* we have checked this is not a oplock break
+ * response message. JRA.
+ */
+
+ release_level_2_oplocks_on_change(fsp);
+
+ /* Data now points at the beginning of the list
+ of smb_unlkrng structs */
+ for(i = 0; i < (int)num_ulocks; i++) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
- send_smb(Client,outbuf);
+ DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
+ (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+
+ status = do_unlock(fsp,conn,lock_pid,count,offset);
+ if (NT_STATUS_V(status)) {
+ END_PROFILE(SMBlockingX);
+ return ERROR_NT(status);
+ }
+ }
- total_read += nread;
- startpos += nread;
- }
- while (total_read < tcount);
+ /* Setup the timeout in seconds. */
+ lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+
+ /* Now do any requested locks */
+ data += ((large_file_format ? 20 : 10)*num_ulocks);
+
+ /* Data now points at the beginning of the list
+ of smb_lkrng structs */
+
+ for(i = 0; i < (int)num_locks; i++) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
+ (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+
+ status = do_lock(fsp,conn,lock_pid, count,offset,
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ if (NT_STATUS_V(status)) {
+ if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
+ END_PROFILE(SMBlockingX);
+ return -1;
+ }
+ }
+ break;
+ }
+ }
+
+ /* If any of the above locks failed, then we must unlock
+ all of the previous locks (X/Open spec). */
+ if (i != num_locks && num_locks != 0) {
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+ for(i--; i >= 0; i--) {
+ lock_pid = get_lock_pid( data, i, large_file_format);
+ count = get_lock_count( data, i, large_file_format);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err) {
+ END_PROFILE(SMBlockingX);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ do_unlock(fsp,conn,lock_pid,count,offset);
+ }
+ END_PROFILE(SMBlockingX);
+ return ERROR_NT(status);
+ }
- return(-1);
+ set_message(outbuf,2,0,True);
+
+ DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
+
+ END_PROFILE(SMBlockingX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
-
/****************************************************************************
- reply to a SMBwritebmpx (write block multiplex primary) request
+ Reply to a SMBreadbmpx (read block multiplex) request.
****************************************************************************/
-int reply_writebmpx(char *inbuf,char *outbuf)
+
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
- char *data;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ ssize_t nread = -1;
+ ssize_t total_read;
+ char *data;
+ SMB_OFF_T startpos;
+ int outsize;
+ size_t maxcount;
+ int max_per_packet;
+ size_t tcount;
+ int pad;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBreadBmpx);
+
+ /* this function doesn't seem to work - disable by default */
+ if (!lp_readbmpx()) {
+ END_PROFILE(SMBreadBmpx);
+ return ERROR_DOS(ERRSRV,ERRuseSTD);
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ outsize = set_message(outbuf,8,0,True);
- tcount = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv3);
- write_through = BITSETW(inbuf+smb_vwv7,0);
- numtowrite = SVAL(inbuf,smb_vwv10);
- smb_doff = SVAL(inbuf,smb_vwv11);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
- data = smb_base(inbuf) + smb_doff;
+ startpos = IVAL(inbuf,smb_vwv1);
+ maxcount = SVAL(inbuf,smb_vwv3);
- /* If this fails we need to send an SMBwriteC response,
- not an SMBwritebmpx - set this up now so we don't forget */
- CVAL(outbuf,smb_com) = SMBwritec;
+ data = smb_buf(outbuf);
+ pad = ((long)data)%4;
+ if (pad)
+ pad = 4 - pad;
+ data += pad;
- if (is_locked(fnum,cnum,tcount,startpos))
- return(ERROR(ERRDOS,ERRlock));
+ max_per_packet = bufsize-(outsize+pad);
+ tcount = maxcount;
+ total_read = 0;
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ END_PROFILE(SMBreadBmpx);
+ return ERROR_DOS(ERRDOS,ERRlock);
+ }
- if(lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ do {
+ size_t N = MIN(max_per_packet,tcount-total_read);
- if(nwritten < numtowrite)
- return(UNIXERROR(ERRHRD,ERRdiskfull));
+ nread = read_file(fsp,data,startpos,N);
- /* If the maximum to be written to this file
- is greater than what we just wrote then set
- up a secondary struct to be attached to this
- fd, we will use this to cache error messages etc. */
- if(tcount > nwritten)
- {
- write_bmpx_struct *wbms;
- if(Files[fnum].wbmpx_ptr != NULL)
- wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
- else
- wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
- if(!wbms)
- {
- DEBUG(0,("Out of memory in reply_readmpx\n"));
- return(ERROR(ERRSRV,ERRnoresource));
- }
- wbms->wr_mode = write_through;
- wbms->wr_discard = False; /* No errors yet */
- wbms->wr_total_written = nwritten;
- wbms->wr_errclass = 0;
- wbms->wr_error = 0;
- Files[fnum].wbmpx_ptr = wbms;
- }
+ if (nread <= 0)
+ nread = 0;
- /* We are returning successfully, set the message type back to
- SMBwritebmpx */
- CVAL(outbuf,smb_com) = SMBwriteBmpx;
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
-
- DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,numtowrite,nwritten));
-
- if (write_through && tcount==nwritten) {
- /* we need to send both a primary and a secondary response */
- smb_setlen(outbuf,outsize - 4);
- send_smb(Client,outbuf);
+ if (nread < (ssize_t)N)
+ tcount = total_read + nread;
- /* now the secondary */
- outsize = set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBwritec;
- SSVAL(outbuf,smb_vwv0,nwritten);
- }
+ set_message(outbuf,8,nread,False);
+ SIVAL(outbuf,smb_vwv0,startpos);
+ SSVAL(outbuf,smb_vwv2,tcount);
+ SSVAL(outbuf,smb_vwv6,nread);
+ SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
- return(outsize);
-}
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_readbmpx: send_smb failed.");
+
+ total_read += nread;
+ startpos += nread;
+ } while (total_read < (ssize_t)tcount);
+ END_PROFILE(SMBreadBmpx);
+ return(-1);
+}
/****************************************************************************
- reply to a SMBwritebs (write block multiplex secondary) request
+ Reply to a SMBsetattrE.
****************************************************************************/
-int reply_writebs(char *inbuf,char *outbuf)
+
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
+ struct utimbuf unix_times;
int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
- char *data;
- write_bmpx_struct *wbms;
- BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBsetattrE);
+
+ outsize = set_message(outbuf,0,0,True);
+
+ CHECK_FSP(fsp,conn);
+
+ /* Convert the DOS times into unix times. Ignore create
+ time as UNIX can't set this.
+ */
+ unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
+ unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
- tcount = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- numtowrite = SVAL(inbuf,smb_vwv6);
- smb_doff = SVAL(inbuf,smb_vwv7);
+ if ((unix_times.actime == 0) && (unix_times.modtime == 0))
+ {
+ /* Ignore request */
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
+ dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
+ }
+ END_PROFILE(SMBsetattrE);
+ return(outsize);
+ }
+ else if ((unix_times.actime != 0) && (unix_times.modtime == 0))
+ {
+ /* set modify time = to access time if modify time was 0 */
+ unix_times.modtime = unix_times.actime;
+ }
- data = smb_base(inbuf) + smb_doff;
+ /* Set the date on this file */
+ if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+ END_PROFILE(SMBsetattrE);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+ fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
- /* We need to send an SMBwriteC response, not an SMBwritebs */
- CVAL(outbuf,smb_com) = SMBwritec;
+ END_PROFILE(SMBsetattrE);
+ return(outsize);
+}
- /* This fd should have an auxiliary struct attached,
- check that it does */
- wbms = Files[fnum].wbmpx_ptr;
- if(!wbms) return(-1);
- /* If write through is set we can return errors, else we must
- cache them */
- write_through = wbms->wr_mode;
+/* Back from the dead for OS/2..... JRA. */
- /* Check for an earlier error */
- if(wbms->wr_discard)
- return -1; /* Just discard the packet */
+/****************************************************************************
+ Reply to a SMBwritebmpx (write block multiplex primary) request.
+****************************************************************************/
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBwriteBmpx);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ tcount = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv3);
+ write_through = BITSETW(inbuf+smb_vwv7,0);
+ numtowrite = SVAL(inbuf,smb_vwv10);
+ smb_doff = SVAL(inbuf,smb_vwv11);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* If this fails we need to send an SMBwriteC response,
+ not an SMBwritebmpx - set this up now so we don't forget */
+ CVAL(outbuf,smb_com) = SMBwritec;
+
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
+ END_PROFILE(SMBwriteBmpx);
+ return(ERROR_DOS(ERRDOS,ERRlock));
+ }
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if(lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- if (nwritten < numtowrite)
- {
- if(write_through) {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- Files[fnum].wbmpx_ptr = NULL;
- return(ERROR(ERRHRD,ERRdiskfull));
- }
- return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
- }
+ if(nwritten < (ssize_t)numtowrite) {
+ END_PROFILE(SMBwriteBmpx);
+ return(UNIXERROR(ERRHRD,ERRdiskfull));
+ }
- /* Increment the total written, if this matches tcount
- we can discard the auxiliary struct (hurrah !) and return a writeC */
- wbms->wr_total_written += nwritten;
- if(wbms->wr_total_written >= tcount)
- {
- if (write_through) {
+ /* If the maximum to be written to this file
+ is greater than what we just wrote then set
+ up a secondary struct to be attached to this
+ fd, we will use this to cache error messages etc. */
+
+ if((ssize_t)tcount > nwritten) {
+ write_bmpx_struct *wbms;
+ if(fsp->wbmpx_ptr != NULL)
+ wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+ else
+ wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
+ if(!wbms) {
+ DEBUG(0,("Out of memory in reply_readmpx\n"));
+ END_PROFILE(SMBwriteBmpx);
+ return(ERROR_DOS(ERRSRV,ERRnoresource));
+ }
+ wbms->wr_mode = write_through;
+ wbms->wr_discard = False; /* No errors yet */
+ wbms->wr_total_written = nwritten;
+ wbms->wr_errclass = 0;
+ wbms->wr_error = 0;
+ fsp->wbmpx_ptr = wbms;
+ }
+
+ /* We are returning successfully, set the message type back to
+ SMBwritebmpx */
+ CVAL(outbuf,smb_com) = SMBwriteBmpx;
+
outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
- send_response = True;
- }
+
+ SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
+
+ DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
- free((char *)wbms);
- Files[fnum].wbmpx_ptr = NULL;
- }
+ if (write_through && tcount==nwritten) {
+ /* We need to send both a primary and a secondary response */
+ smb_setlen(outbuf,outsize - 4);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_writebmpx: send_smb failed.");
- if(send_response)
- return(outsize);
+ /* Now the secondary */
+ outsize = set_message(outbuf,1,0,True);
+ CVAL(outbuf,smb_com) = SMBwritec;
+ SSVAL(outbuf,smb_vwv0,nwritten);
+ }
- return(-1);
+ END_PROFILE(SMBwriteBmpx);
+ return(outsize);
}
-
/****************************************************************************
- reply to a SMBsetattrE
+ Reply to a SMBwritebs (write block multiplex secondary) request.
****************************************************************************/
-int reply_setattrE(char *inbuf,char *outbuf)
+
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,fnum;
- struct utimbuf unix_times;
- int outsize = 0;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ write_bmpx_struct *wbms;
+ BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBwriteBs);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+
+ tcount = SVAL(inbuf,smb_vwv1);
+ startpos = IVAL(inbuf,smb_vwv2);
+ numtowrite = SVAL(inbuf,smb_vwv6);
+ smb_doff = SVAL(inbuf,smb_vwv7);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* We need to send an SMBwriteC response, not an SMBwritebs */
+ CVAL(outbuf,smb_com) = SMBwritec;
+
+ /* This fd should have an auxiliary struct attached,
+ check that it does */
+ wbms = fsp->wbmpx_ptr;
+ if(!wbms) {
+ END_PROFILE(SMBwriteBs);
+ return(-1);
+ }
- outsize = set_message(outbuf,0,0,True);
+ /* If write through is set we can return errors, else we must cache them */
+ write_through = wbms->wr_mode;
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ /* Check for an earlier error */
+ if(wbms->wr_discard) {
+ END_PROFILE(SMBwriteBs);
+ return -1; /* Just discard the packet */
+ }
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- /* Convert the DOS times into unix times. Ignore create
- time as UNIX can't set this.
- */
- unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
- unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
-
- /* Set the date on this file */
- if(sys_utime(Files[fnum].name, &unix_times))
- return(ERROR(ERRDOS,ERRnoaccess));
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ if (nwritten < (ssize_t)numtowrite) {
+ if(write_through) {
+ /* We are returning an error - we can delete the aux struct */
+ if (wbms)
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ END_PROFILE(SMBwriteBs);
+ return(ERROR_DOS(ERRHRD,ERRdiskfull));
+ }
+ END_PROFILE(SMBwriteBs);
+ return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+ }
- return(outsize);
-}
+ /* Increment the total written, if this matches tcount
+ we can discard the auxiliary struct (hurrah !) and return a writeC */
+ wbms->wr_total_written += nwritten;
+ if(wbms->wr_total_written >= tcount) {
+ if (write_through) {
+ outsize = set_message(outbuf,1,0,True);
+ SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
+ send_response = True;
+ }
+
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ }
+
+ if(send_response) {
+ END_PROFILE(SMBwriteBs);
+ return(outsize);
+ }
+ END_PROFILE(SMBwriteBs);
+ return(-1);
+}
/****************************************************************************
- reply to a SMBgetattrE
+ Reply to a SMBgetattrE.
****************************************************************************/
-int reply_getattrE(char *inbuf,char *outbuf)
+
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- int cnum,fnum;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
int outsize = 0;
int mode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ START_PROFILE(SMBgetattrE);
outsize = set_message(outbuf,11,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
/* Do an fstat on this file */
- if(fstat(Files[fnum].fd, &sbuf))
+ if(vfs_fstat(fsp,fsp->fd, &sbuf)) {
+ END_PROFILE(SMBgetattrE);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- mode = dos_mode(cnum,Files[fnum].name,&sbuf);
+ mode = dos_mode(conn,fsp->fsp_name,&sbuf);
/* Convert the times into dos times. Set create
date to be last modify date as UNIX doesn't save
this */
- put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
+ put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
if (mode & aDIR)
@@ -3194,17 +4190,13 @@ int reply_getattrE(char *inbuf,char *outbuf)
}
else
{
- SIVAL(outbuf,smb_vwv6,sbuf.st_size);
- SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
+ SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
+ SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
}
SSVAL(outbuf,smb_vwv10, mode);
- DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
+ END_PROFILE(SMBgetattrE);
return(outsize);
}
-
-
-
-
-
diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c
new file mode 100644
index 00000000000..b774947d607
--- /dev/null
+++ b/source/smbd/sec_ctx.c
@@ -0,0 +1,425 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ uid/user handling
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern struct current_user current_user;
+
+struct sec_ctx {
+ uid_t uid;
+ uid_t gid;
+ int ngroups;
+ gid_t *groups;
+ NT_USER_TOKEN *token;
+};
+
+/* A stack of security contexts. We include the current context as being
+ the first one, so there is room for another MAX_SEC_CTX_DEPTH more. */
+
+static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
+static int sec_ctx_stack_ndx;
+
+/****************************************************************************
+ Become the specified uid.
+****************************************************************************/
+
+static BOOL become_uid(uid_t uid)
+{
+ /* Check for dodgy uid values */
+
+ if (uid == (uid_t)-1 ||
+ ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
+ static int done;
+
+ if (!done) {
+ DEBUG(1,("WARNING: using uid %d is a security risk\n",
+ (int)uid));
+ done = 1;
+ }
+ }
+
+ /* Set effective user id */
+
+ set_effective_uid(uid);
+
+ DO_PROFILE_INC(uid_changes);
+ return True;
+}
+
+/****************************************************************************
+ Become the specified gid.
+****************************************************************************/
+
+static BOOL become_gid(gid_t gid)
+{
+ /* Check for dodgy gid values */
+
+ if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
+ (gid == (gid_t)65535))) {
+ static int done;
+
+ if (!done) {
+ DEBUG(1,("WARNING: using gid %d is a security risk\n",
+ (int)gid));
+ done = 1;
+ }
+ }
+
+ /* Set effective group id */
+
+ set_effective_gid(gid);
+ return True;
+}
+
+/****************************************************************************
+ Become the specified uid and gid.
+****************************************************************************/
+
+static BOOL become_id(uid_t uid, gid_t gid)
+{
+ return become_gid(gid) && become_uid(uid);
+}
+
+/****************************************************************************
+ Drop back to root privileges in order to change to another user.
+****************************************************************************/
+
+static void gain_root(void)
+{
+ if (non_root_mode()) {
+ return;
+ }
+
+ if (geteuid() != 0) {
+ set_effective_uid(0);
+
+ if (geteuid() != 0) {
+ DEBUG(0,
+ ("Warning: You appear to have a trapdoor "
+ "uid system\n"));
+ }
+ }
+
+ if (getegid() != 0) {
+ set_effective_gid(0);
+
+ if (getegid() != 0) {
+ DEBUG(0,
+ ("Warning: You appear to have a trapdoor "
+ "gid system\n"));
+ }
+ }
+}
+
+/****************************************************************************
+ Get the list of current groups.
+****************************************************************************/
+
+int get_current_groups(int *p_ngroups, gid_t **p_groups)
+{
+ int i;
+ gid_t grp;
+ int ngroups = sys_getgroups(0,&grp);
+ gid_t *groups;
+
+ (*p_ngroups) = 0;
+ (*p_groups) = NULL;
+
+ if (ngroups <= 0)
+ return -1;
+
+ if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL) {
+ DEBUG(0,("setup_groups malloc fail !\n"));
+ return -1;
+ }
+
+ if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
+ SAFE_FREE(groups);
+ return -1;
+ }
+
+ (*p_ngroups) = ngroups;
+ (*p_groups) = groups;
+
+ DEBUG( 3, ( "get_current_groups: user is in %u groups: ", ngroups));
+ for (i = 0; i < ngroups; i++ ) {
+ DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
+ }
+ DEBUG( 3, ( "\n" ) );
+
+ return ngroups;
+}
+
+/****************************************************************************
+ Initialize the groups a user belongs to.
+****************************************************************************/
+
+BOOL initialise_groups(char *user, uid_t uid, gid_t gid)
+{
+ struct sec_ctx *prev_ctx_p;
+ BOOL result = True;
+
+ if (non_root_mode()) {
+ return True;
+ }
+
+ become_root();
+
+ /* Call initgroups() to get user groups */
+
+ if (winbind_initgroups(user,gid) == -1) {
+ DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) ));
+ if (getuid() == 0) {
+ if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) {
+ DEBUG(0,("This is probably a problem with the account %s\n", user));
+ }
+ }
+ result = False;
+ goto done;
+ }
+
+ /* Store groups in previous user's security context. This will
+ always work as the become_root() call increments the stack
+ pointer. */
+
+ prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1];
+
+ SAFE_FREE(prev_ctx_p->groups);
+ prev_ctx_p->ngroups = 0;
+
+ get_current_groups(&prev_ctx_p->ngroups, &prev_ctx_p->groups);
+
+ done:
+ unbecome_root();
+
+ return result;
+}
+
+/****************************************************************************
+ Create a new security context on the stack. It is the same as the old
+ one. User changes are done using the set_sec_ctx() function.
+****************************************************************************/
+
+BOOL push_sec_ctx(void)
+{
+ struct sec_ctx *ctx_p;
+
+ /* Check we don't overflow our stack */
+
+ if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+ DEBUG(0, ("Security context stack overflow!\n"));
+ smb_panic("Security context stack overflow!\n");
+ }
+
+ /* Store previous user context */
+
+ sec_ctx_stack_ndx++;
+
+ ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ ctx_p->uid = geteuid();
+ ctx_p->gid = getegid();
+
+ DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n",
+ (unsigned int)ctx_p->uid, (unsigned int)ctx_p->gid, sec_ctx_stack_ndx ));
+
+ ctx_p->token = dup_nt_token(sec_ctx_stack[sec_ctx_stack_ndx-1].token);
+
+ ctx_p->ngroups = sys_getgroups(0, NULL);
+
+ if (ctx_p->ngroups != 0) {
+ if (!(ctx_p->groups = malloc(ctx_p->ngroups * sizeof(gid_t)))) {
+ DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
+ delete_nt_token(&ctx_p->token);
+ return False;
+ }
+
+ sys_getgroups(ctx_p->ngroups, ctx_p->groups);
+ } else {
+ ctx_p->groups = NULL;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set the current security context to a given user.
+****************************************************************************/
+
+void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
+{
+ struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ /* Set the security context */
+
+ DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
+ (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
+
+ if (ngroups) {
+ int i;
+
+ DEBUG(3, ("%d user groups: \n", ngroups));
+ for (i = 0; i < ngroups; i++) {
+ DEBUGADD(3, ("%u ", (unsigned int)groups[i]));
+ }
+
+ DEBUG(3, ("\n"));
+ }
+
+
+ gain_root();
+
+#ifdef HAVE_SETGROUPS
+ sys_setgroups(ngroups, groups);
+#endif
+
+ ctx_p->ngroups = ngroups;
+
+ SAFE_FREE(ctx_p->groups);
+ if (token && (token == ctx_p->token))
+ smb_panic("DUPLICATE_TOKEN");
+
+ delete_nt_token(&ctx_p->token);
+
+ ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups);
+ ctx_p->token = dup_nt_token(token);
+
+ become_id(uid, gid);
+
+ ctx_p->uid = uid;
+ ctx_p->gid = gid;
+
+ /* Update current_user stuff */
+
+ current_user.uid = uid;
+ current_user.gid = gid;
+ current_user.ngroups = ngroups;
+ current_user.groups = groups;
+ current_user.nt_user_token = ctx_p->token;
+}
+
+/****************************************************************************
+ Become root context.
+****************************************************************************/
+
+void set_root_sec_ctx(void)
+{
+ /* May need to worry about supplementary groups at some stage */
+
+ set_sec_ctx(0, 0, 0, NULL, NULL);
+}
+
+/****************************************************************************
+ Pop a security context from the stack.
+****************************************************************************/
+
+BOOL pop_sec_ctx(void)
+{
+ struct sec_ctx *ctx_p;
+ struct sec_ctx *prev_ctx_p;
+
+ /* Check for stack underflow */
+
+ if (sec_ctx_stack_ndx == 0) {
+ DEBUG(0, ("Security context stack underflow!\n"));
+ smb_panic("Security context stack underflow!\n");
+ }
+
+ ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+ /* Clear previous user info */
+
+ ctx_p->uid = (uid_t)-1;
+ ctx_p->gid = (gid_t)-1;
+
+ SAFE_FREE(ctx_p->groups);
+ ctx_p->ngroups = 0;
+
+ delete_nt_token(&ctx_p->token);
+
+ /* Pop back previous user */
+
+ sec_ctx_stack_ndx--;
+
+ gain_root();
+
+ prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
+
+#ifdef HAVE_SETGROUPS
+ sys_setgroups(prev_ctx_p->ngroups, prev_ctx_p->groups);
+#endif
+
+ become_id(prev_ctx_p->uid, prev_ctx_p->gid);
+
+ /* Update current_user stuff */
+
+ current_user.uid = prev_ctx_p->uid;
+ current_user.gid = prev_ctx_p->gid;
+ current_user.ngroups = prev_ctx_p->ngroups;
+ current_user.groups = prev_ctx_p->groups;
+ current_user.nt_user_token = prev_ctx_p->token;
+
+ DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
+ (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
+
+ return True;
+}
+
+/* Initialise the security context system */
+
+void init_sec_ctx(void)
+{
+ int i;
+ struct sec_ctx *ctx_p;
+
+ /* Initialise security context stack */
+
+ memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
+
+ for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+ sec_ctx_stack[i].uid = (uid_t)-1;
+ sec_ctx_stack[i].gid = (gid_t)-1;
+ }
+
+ /* Initialise first level of stack. It is the current context */
+ ctx_p = &sec_ctx_stack[0];
+
+ ctx_p->uid = geteuid();
+ ctx_p->gid = getegid();
+
+ get_current_groups(&ctx_p->ngroups, &ctx_p->groups);
+
+ ctx_p->token = NULL; /* Maps to guest user. */
+
+ /* Initialise current_user global */
+
+ current_user.uid = ctx_p->uid;
+ current_user.gid = ctx_p->gid;
+ current_user.ngroups = ctx_p->ngroups;
+ current_user.groups = ctx_p->groups;
+
+ /* The conn and vuid are usually taken care of by other modules.
+ We initialise them here. */
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+ current_user.nt_user_token = NULL;
+}
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..c6eed4b9bb4 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB server routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,29 +20,11 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
-#include "trans2.h"
-#include "reply.h"
-pstring servicesf = CONFIGFILE;
-pstring OriginalDir ="/";
-extern pstring debugf;
-extern pstring sesssetup_user;
+extern fstring global_myworkgroup;
+extern pstring global_myname;
-char *InBuffer = NULL;
-char *OutBuffer = NULL;
-char *last_inbuf = NULL;
-
-int initial_uid = 0;
-int initial_gid = 0;
-
-BOOL share_mode_pending = False;
-
-/* have I done a become_user? */
-static struct {
- int cnum, uid;
-} last_user;
+int am_parent = 1;
/* the last message the was processed */
int last_message = -1;
@@ -50,4251 +32,838 @@ int last_message = -1;
/* a useful macro to debug the last message processed */
#define LAST_MESSAGE() smb_fn_name(last_message)
-extern pstring scope;
-extern int DEBUGLEVEL;
-extern int case_default;
-extern BOOL case_sensitive;
-extern BOOL case_preserve;
-extern BOOL use_mangled_map;
-extern BOOL short_case_preserve;
-extern BOOL case_mangle;
-extern time_t smb_last_time;
-
extern pstring user_socket_options;
-connection_struct Connections[MAX_CONNECTIONS];
-files_struct Files[MAX_OPEN_FILES];
-
-extern int Protocol;
-
-int maxxmit = BUFFER_SIZE;
-
-int chain_size = 0;
-
-/* a fnum to use when chaining */
-int chain_fnum = -1;
-
-/* number of open connections */
-static int num_connections_open = 0;
+#ifdef WITH_DFS
+extern int dcelogin_atmost_once;
+#endif /* WITH_DFS */
extern fstring remote_machine;
+/* really we should have a top level context structure that has the
+ client file descriptor as an element. That would require a major rewrite :(
-/* these can be set by some functions to override the error codes */
-int unix_ERR_class=SUCCESS;
-int unix_ERR_code=0;
-
-
-extern int extra_time_offset;
+ the following 2 functions are an alternative - they make the file
+ descriptor private to smbd
+ */
+static int server_fd = -1;
-extern pstring myhostname;
-extern struct in_addr myip;
-
-
-static int find_free_connection(int hash);
-
-#ifdef SMB_PASSWD
-extern void generate_next_challenge(char *challenge);
-extern void set_challenge(char *challenge);
-#endif
-
-/* for readability... */
-#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
-#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
-#define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0)
-#define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
-#define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
-
-
-
-/****************************************************************************
- change a dos mode to a unix mode
- base permission for files:
- everybody gets read bit set
- dos readonly is represented in unix by removing everyone's write bit
- dos archive is represented in unix by the user's execute bit
- dos system is represented in unix by the group's execute bit
- dos hidden is represented in unix by the other's execute bit
- base permission for directories:
- dos directory is represented in unix by unix's dir bit and the exec bit
-****************************************************************************/
-mode_t unix_mode(int cnum,int dosmode)
+int smbd_server_fd(void)
{
- mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
-
- if ( !IS_DOS_READONLY(dosmode) )
- result |= (S_IWUSR | S_IWGRP | S_IWOTH);
-
- if (IS_DOS_DIR(dosmode))
- result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
-
- if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
- result |= S_IXUSR;
-
- if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
- result |= S_IXGRP;
-
- if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
- result |= S_IXOTH;
-
- result &= CREATE_MODE(cnum);
- return(result);
+ return server_fd;
}
-
-/****************************************************************************
- change a unix mode to a dos mode
-****************************************************************************/
-int dos_mode(int cnum,char *path,struct stat *sbuf)
-{
- int result = 0;
-
-#if OLD_DOS_MODE
- if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) ||
- Connections[cnum].admin_user ||
- ((sbuf->st_mode & S_IWUSR) &&
- Connections[cnum].uid==sbuf->st_uid) ||
- ((sbuf->st_mode & S_IWGRP) &&
- in_group(sbuf->st_gid,Connections[cnum].gid,
- Connections[cnum].ngroups,
- Connections[cnum].igroups))))
- result |= aRONLY;
-#else
- if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
- if (!((sbuf->st_mode & S_IWOTH) ||
- Connections[cnum].admin_user ||
- ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) ||
- ((sbuf->st_mode & S_IWGRP) &&
- in_group(sbuf->st_gid,Connections[cnum].gid,
- Connections[cnum].ngroups,Connections[cnum].igroups))))
- result |= aRONLY;
- } else {
- if ((sbuf->st_mode & S_IWUSR) == 0)
- result |= aRONLY;
- }
-#endif
-
- if ((sbuf->st_mode & S_IXUSR) != 0)
- result |= aARCH;
-
- if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0))
- result |= aSYSTEM;
-
- if (MAP_HIDDEN(cnum) && ((sbuf->st_mode & S_IXOTH) != 0))
- result |= aHIDDEN;
-
- if (S_ISDIR(sbuf->st_mode))
- result = aDIR | (result & aRONLY);
-
-#if LINKS_READ_ONLY
- if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
- result |= aRONLY;
-#endif
-
- /* hide files with a name starting with a . */
- if (lp_hide_dot_files(SNUM(cnum)))
- {
- char *p = strrchr(path,'/');
- if (p)
- p++;
- else
- p = path;
-
- if (p[0] == '.' && p[1] != '.' && p[1] != 0)
- result |= aHIDDEN;
- }
-
- return(result);
-}
-
-
-/*******************************************************************
-chmod a file - but preserve some bits
-********************************************************************/
-int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
+void smbd_set_server_fd(int fd)
{
- struct stat st1;
- int mask=0;
- int tmp;
- int unixmode;
-
- if (!st) {
- st = &st1;
- if (sys_stat(fname,st)) return(-1);
- }
-
- if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
-
- if (dos_mode(cnum,fname,st) == dosmode) return(0);
-
- unixmode = unix_mode(cnum,dosmode);
-
- /* preserve the s bits */
- mask |= (S_ISUID | S_ISGID);
-
- /* preserve the t bit */
-#ifdef S_ISVTX
- mask |= S_ISVTX;
-#endif
-
- /* possibly preserve the x bits */
- if (!MAP_ARCHIVE(cnum)) mask |= S_IXUSR;
- if (!MAP_SYSTEM(cnum)) mask |= S_IXGRP;
- if (!MAP_HIDDEN(cnum)) mask |= S_IXOTH;
-
- unixmode |= (st->st_mode & mask);
-
- /* if we previously had any r bits set then leave them alone */
- if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
- unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
- unixmode |= tmp;
- }
-
- /* if we previously had any w bits set then leave them alone
- if the new mode is not rdonly */
- if (!IS_DOS_READONLY(dosmode) &&
- (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
- unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
- unixmode |= tmp;
- }
-
- return(chmod(fname,unixmode));
+ server_fd = fd;
+ client_setfd(fd);
}
-
/****************************************************************************
-check if two filenames are equal
-
-this needs to be careful about whether we are case sensitive
+ when exiting, take the whole family
****************************************************************************/
-static BOOL fname_equal(char *name1, char *name2)
+static void *dflt_sig(void)
{
- int l1 = strlen(name1);
- int l2 = strlen(name2);
-
- /* handle filenames ending in a single dot */
- if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
- {
- BOOL ret;
- name1[l1-1] = 0;
- ret = fname_equal(name1,name2);
- name1[l1-1] = '.';
- return(ret);
- }
-
- if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
- {
- BOOL ret;
- name2[l2-1] = 0;
- ret = fname_equal(name1,name2);
- name2[l2-1] = '.';
- return(ret);
- }
-
- /* now normal filename handling */
- if (case_sensitive)
- return(strcmp(name1,name2) == 0);
-
- return(strequal(name1,name2));
+ exit_server("caught signal");
+ return NULL;
}
-
/****************************************************************************
-mangle the 2nd name and check if it is then equal to the first name
-****************************************************************************/
-static BOOL mangled_equal(char *name1, char *name2)
+ Send a SIGTERM to our process group.
+*****************************************************************************/
+static void killkids(void)
{
- pstring tmpname;
-
- if (is_8_3(name2))
- return(False);
-
- strcpy(tmpname,name2);
- mangle_name_83(tmpname);
-
- return(strequal(name1,tmpname));
+ if(am_parent) kill(0,SIGTERM);
}
-
/****************************************************************************
-scan a directory to find a filename, matching without case sensitivity
-
-If the name looks like a mangled name then try via the mangling functions
+ process a sam sync message - not sure whether to do this here or
+ somewhere else
****************************************************************************/
-static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
+static void msg_sam_sync(int msg_type, pid_t pid, void *buf, size_t len)
{
- void *cur_dir;
- char *dname;
- BOOL mangled;
- fstring name2;
-
- mangled = is_mangled(name);
-
- /* handle null paths */
- if (*path == 0)
- path = ".";
-
- if (docache && (dname = DirCacheCheck(path,name,snum))) {
- strcpy(name, dname);
- return(True);
- }
-
- if (mangled)
- check_mangled_stack(name);
-
- /* open the directory */
- if (!(cur_dir = OpenDir(path)))
- {
- DEBUG(3,("scan dir didn't open dir [%s]\n",path));
- return(False);
- }
-
- /* now scan for matching names */
- while ((dname = ReadDirName(cur_dir)))
- {
- if (*dname == '.' &&
- (strequal(dname,".") || strequal(dname,"..")))
- continue;
-
- strcpy(name2,dname);
- if (!name_map_mangle(name2,False,snum)) continue;
-
- if ((mangled && mangled_equal(name,name2))
- || fname_equal(name, name2))
- {
- /* we've found the file, change it's name and return */
- if (docache) DirCacheAdd(path,name,dname,snum);
- strcpy(name, dname);
- CloseDir(cur_dir);
- return(True);
- }
- }
-
- CloseDir(cur_dir);
- return(False);
+ DEBUG(10, ("** sam sync message received, ignoring\n"));
}
/****************************************************************************
-This routine is called to convert names from the dos namespace to unix
-namespace. It needs to handle any case conversions, mangling, format
-changes etc.
-
-We assume that we have already done a chdir() to the right "root" directory
-for this service.
-
-The function will return False if some part of the name except for the last
-part cannot be resolved
+ process a sam sync replicate message - not sure whether to do this here or
+ somewhere else
****************************************************************************/
-BOOL unix_convert(char *name,int cnum)
+static void msg_sam_repl(int msg_type, pid_t pid, void *buf, size_t len)
{
- struct stat st;
- char *start, *end;
- pstring dirpath;
-
- *dirpath = 0;
-
- /* convert to basic unix format - removing \ chars and cleaning it up */
- unix_format(name);
- unix_clean_name(name);
-
- if (!case_sensitive &&
- (!case_preserve || (is_8_3(name) && !short_case_preserve)))
- strnorm(name);
-
- /* names must be relative to the root of the service - trim any leading /.
- also trim trailing /'s */
- trim_string(name,"/","/");
-
- /* check if it's a printer file */
- if (Connections[cnum].printer)
- {
- if ((! *name) || strchr(name,'/') || !is_8_3(name))
- {
- fstring name2;
- sprintf(name2,"%.6s.XXXXXX",remote_machine);
- strcpy(name,(char *)mktemp(name2));
- }
- return(True);
- }
-
- /* stat the name - if it exists then we are all done! */
- if (sys_stat(name,&st) == 0)
- return(True);
-
- DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
-
- /* a special case - if we don't have any mangling chars and are case
- sensitive then searching won't help */
- if (case_sensitive && !is_mangled(name) &&
- !lp_strip_dot() && !use_mangled_map)
- return(False);
-
- /* now we need to recursively match the name against the real
- directory structure */
-
- start = name;
- while (strncmp(start,"./",2) == 0)
- start += 2;
-
- /* now match each part of the path name separately, trying the names
- as is first, then trying to scan the directory for matching names */
- for (;start;start = (end?end+1:(char *)NULL))
- {
- /* pinpoint the end of this section of the filename */
- end = strchr(start, '/');
-
- /* chop the name at this point */
- if (end) *end = 0;
-
- /* check if the name exists up to this point */
- if (sys_stat(name, &st) == 0)
- {
- /* it exists. it must either be a directory or this must be
- the last part of the path for it to be OK */
- if (end && !(st.st_mode & S_IFDIR))
- {
- /* an intermediate part of the name isn't a directory */
- DEBUG(5,("Not a dir %s\n",start));
- *end = '/';
- return(False);
- }
- }
- else
- {
- pstring rest;
+ uint32 low_serial;
- *rest = 0;
+ if (len != sizeof(uint32))
+ return;
- /* remember the rest of the pathname so it can be restored
- later */
- if (end) strcpy(rest,end+1);
+ low_serial = *((uint32 *)buf);
-
- /* try to find this part of the path in the directory */
- if (strchr(start,'?') || strchr(start,'*') ||
- !scan_directory(dirpath, start, SNUM(cnum), end?True:False))
- {
- if (end)
- {
- /* an intermediate part of the name can't be found */
- DEBUG(5,("Intermediate not found %s\n",start));
- *end = '/';
- return(False);
- }
-
- /* just the last part of the name doesn't exist */
- /* we may need to strupper() or strlower() it in case
- this conversion is being used for file creation
- purposes */
- /* if the filename is of mixed case then don't normalise it */
- if (!case_preserve &&
- (!strhasupper(start) || !strhaslower(start)))
- strnorm(start);
-
- /* check on the mangled stack to see if we can recover the
- base of the filename */
- if (is_mangled(start))
- check_mangled_stack(start);
-
- DEBUG(5,("New file %s\n",start));
- return(True);
- }
-
- /* restore the rest of the string */
- if (end)
- {
- strcpy(start+strlen(start)+1,rest);
- end = start + strlen(start);
- }
- }
-
- /* add to the dirpath that we have resolved so far */
- if (*dirpath) strcat(dirpath,"/");
- strcat(dirpath,start);
-
- /* restore the / that we wiped out earlier */
- if (end) *end = '/';
- }
-
- /* the name has been resolved */
- DEBUG(5,("conversion finished %s\n",name));
- return(True);
+ DEBUG(3, ("received sam replication message, serial = 0x%04x\n",
+ low_serial));
}
-
-
-
-#ifdef QUOTAS
-#ifdef LINUX
/****************************************************************************
-try to get the disk space from disk quotas (LINUX version)
-****************************************************************************/
-/*
-If you didn't make the symlink to the quota package, too bad :(
-*/
-#include "quota/quotactl.c"
-#include "quota/hasquota.c"
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- uid_t euser_id;
- struct dqblk D;
- struct stat S;
- dev_t devno ;
- struct mntent *mnt;
- FILE *fp;
- int found ;
- int qcmd, fd ;
- char *qfpathname;
-
- /* find the block device file */
-
- if ( stat(path, &S) == -1 )
- return(False) ;
-
- devno = S.st_dev ;
-
- fp = setmntent(MOUNTED,"r");
- found = False ;
-
- while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
- if ( stat(mnt->mnt_dir,&S) == -1 )
- continue ;
- if (S.st_dev == devno) {
- found = True ;
- break ;
- }
- }
- endmntent(fp) ;
-
- if ( ! found )
- return(False) ;
-
- qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
-
- if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
- return(False) ;
-
- if (!hasquota(mnt, USRQUOTA, &qfpathname))
- return(False) ;
-
- euser_id = geteuid();
- seteuid(0);
-
- if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
- if ((fd = open(qfpathname, O_RDONLY)) < 0) {
- seteuid(euser_id);
- return(False);
- }
- lseek(fd, (long) dqoff(euser_id), L_SET);
- switch (read(fd, &D, sizeof(struct dqblk))) {
- case 0:/* EOF */
- memset((caddr_t)&D, 0, sizeof(struct dqblk));
- break;
- case sizeof(struct dqblk): /* OK */
- break;
- default: /* ERROR */
- close(fd);
- seteuid(euser_id);
- return(False);
- }
- }
- seteuid(euser_id);
- *bsize=1024;
-
- if (D.dqb_bsoftlimit==0)
- return(False);
- if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
- {
- *dfree = 0;
- *dsize = D.dqb_curblocks;
- }
- else {
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
- *dsize = D.dqb_bsoftlimit;
- }
- return (True);
-}
-#else
-#ifndef CRAY
-/****************************************************************************
-try to get the disk space from disk quotas
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- uid_t user_id, euser_id;
- int r;
- char dev_disk[256];
- struct dqblk D;
- struct stat S;
- /* find the block device file */
- if ((stat(path, &S)<0) ||
- (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
-
- euser_id = geteuid();
-
-#ifdef USE_SETRES
- /* for HPUX, real uid must be same as euid to execute quotactl for euid */
- user_id = getuid();
- setresuid(euser_id,-1,-1);
-#endif
- r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
- #ifdef USE_SETRES
- if (setresuid(user_id,-1,-1))
- DEBUG(5,("Unable to reset uid to %d\n", user_id));
- #endif
- /* Use softlimit to determine disk space, except when it has been exceeded */
- *bsize = 1024;
- if (r)
- {
- if (errno == EDQUOT)
- {
- *dfree =0;
- *dsize =D.dqb_curblocks;
- return (True);
- }
- else return(False);
- }
- /* Use softlimit to determine disk space, except when it has been exceeded */
- if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit))
- {
- *dfree = 0;
- *dsize = D.dqb_curblocks;
- }
- else {
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
- *dsize = D.dqb_bsoftlimit;
- }
- return (True);
-}
-#else
-/****************************************************************************
-try to get the disk space from disk quotas (CRAY VERSION)
+ open the socket communication
****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+static BOOL open_sockets_inetd(void)
{
- struct mntent *mnt;
- FILE *fd;
- struct stat sbuf;
- dev_t devno ;
- static dev_t devno_cached = 0 ;
- static char name[MNTMAXSTR] ;
- struct q_request request ;
- struct qf_header header ;
- static int quota_default = 0 ;
- int found ;
-
- if ( stat(path,&sbuf) == -1 )
- return(False) ;
-
- devno = sbuf.st_dev ;
-
- if ( devno != devno_cached ) {
-
- devno_cached = devno ;
-
- if ((fd = setmntent(KMTAB)) == NULL)
- return(False) ;
-
- found = False ;
-
- while ((mnt = getmntent(fd)) != NULL) {
-
- if ( stat(mnt->mnt_dir,&sbuf) == -1 )
- continue ;
-
- if (sbuf.st_dev == devno) {
+ /* Started from inetd. fd 0 is the socket. */
+ /* We will abort gracefully when the client or remote system
+ goes away */
+ smbd_set_server_fd(dup(0));
- found = True ;
- break ;
+ /* close our standard file descriptors */
+ close_low_fds();
- }
-
- }
-
- strcpy(name,mnt->mnt_dir) ;
- endmntent(fd) ;
-
- if ( ! found )
- return(False) ;
- }
-
- request.qf_magic = QF_MAGIC ;
- request.qf_entry.id = geteuid() ;
-
- if (quotactl(name, Q_GETQUOTA, &request) == -1)
- return(False) ;
-
- if ( ! request.user )
- return(False) ;
-
- if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
-
- if ( ! quota_default ) {
-
- if ( quotactl(name, Q_GETHEADER, &header) == -1 )
- return(False) ;
- else
- quota_default = header.user_h.def_fq ;
- }
-
- *dfree = quota_default ;
-
- }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
-
- *dfree = 0 ;
-
- }else{
-
- *dfree = request.qf_entry.user_q.f_quota ;
-
- }
-
- *dsize = request.qf_entry.user_q.f_use ;
-
- if ( *dfree )
- *dfree -= *dsize ;
-
- if ( *dfree < 0 )
- *dfree = 0 ;
-
- *bsize = 4096 ; /* Cray blocksize */
-
- return(True) ;
-
-}
-#endif /* CRAY */
-#endif /* LINUX */
-#endif /* QUOTAS */
-
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(),user_socket_options);
-/****************************************************************************
-normalise for DOS usage
-****************************************************************************/
-static void disk_norm(int *bsize,int *dfree,int *dsize)
-{
- /* check if the disk is beyond the max disk size */
- int maxdisksize = lp_maxdisksize();
- if (maxdisksize) {
- /* convert to blocks - and don't overflow */
- maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
- if (*dsize > maxdisksize) *dsize = maxdisksize;
- if (*dfree > maxdisksize) *dfree = maxdisksize-1; /* the -1 should stop
- applications getting
- div by 0 errors */
- }
-
- while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512)
- {
- *dfree /= 2;
- *dsize /= 2;
- *bsize *= 2;
- if (*bsize > WORDMAX )
- {
- *bsize = WORDMAX;
- if (*dsize > WORDMAX)
- *dsize = WORDMAX;
- if (*dfree > WORDMAX)
- *dfree = WORDMAX;
- break;
- }
- }
-}
-
-/****************************************************************************
- return number of 1K blocks available on a path and total number
-****************************************************************************/
-int disk_free(char *path,int *bsize,int *dfree,int *dsize)
-{
- char *df_command = lp_dfree_command();
-#ifndef NO_STATFS
-#ifdef USE_STATVFS
- struct statvfs fs;
-#else
-#ifdef ULTRIX
- struct fs_data fs;
-#else
- struct statfs fs;
-#endif
-#endif
-#endif
-
-#ifdef QUOTAS
- if (disk_quotas(path, bsize, dfree, dsize))
- {
- disk_norm(bsize,dfree,dsize);
- return(((*bsize)/1024)*(*dfree));
- }
-#endif
-
-
- /* possibly use system() to get the result */
- if (df_command && *df_command)
- {
- int ret;
- pstring syscmd;
- pstring outfile;
-
- sprintf(outfile,"/tmp/dfree.smb.%d",(int)getpid());
- sprintf(syscmd,"%s %s",df_command,path);
- standard_sub_basic(syscmd);
-
- ret = smbrun(syscmd,outfile);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
-
- {
- FILE *f = fopen(outfile,"r");
- *dsize = 0;
- *dfree = 0;
- *bsize = 1024;
- if (f)
- {
- fscanf(f,"%d %d %d",dsize,dfree,bsize);
- fclose(f);
- }
- else
- DEBUG(0,("Can't open %s\n",outfile));
- }
-
- unlink(outfile);
- disk_norm(bsize,dfree,dsize);
- return(((*bsize)/1024)*(*dfree));
- }
-
-#ifdef NO_STATFS
- DEBUG(1,("Warning - no statfs function\n"));
- return(1);
-#else
-#ifdef STATFS4
- if (statfs(path,&fs,sizeof(fs),0) != 0)
-#else
-#ifdef USE_STATVFS
- if (statvfs(path, &fs))
-#else
-#ifdef STATFS3
- if (statfs(path,&fs,sizeof(fs)) == -1)
-#else
- if (statfs(path,&fs) == -1)
-#endif /* STATFS3 */
-#endif /* USE_STATVFS */
-#endif /* STATFS4 */
- {
- DEBUG(3,("dfree call failed code errno=%d\n",errno));
- *bsize = 1024;
- *dfree = 1;
- *dsize = 1;
- return(((*bsize)/1024)*(*dfree));
- }
-
-#ifdef ULTRIX
- *bsize = 1024;
- *dfree = fs.fd_req.bfree;
- *dsize = fs.fd_req.btot;
-#else
-#ifdef USE_STATVFS
- *bsize = fs.f_frsize;
-#else
-#ifdef USE_F_FSIZE
- /* eg: osf1 has f_fsize = fundamental filesystem block size,
- f_bsize = optimal transfer block size (MX: 94-04-19) */
- *bsize = fs.f_fsize;
-#else
- *bsize = fs.f_bsize;
-#endif /* STATFS3 */
-#endif /* USE_STATVFS */
-
-#ifdef STATFS4
- *dfree = fs.f_bfree;
-#else
- *dfree = fs.f_bavail;
-#endif /* STATFS4 */
- *dsize = fs.f_blocks;
-#endif /* ULTRIX */
-
-#if defined(SCO) || defined(ISC) || defined(MIPS)
- *bsize = 512;
-#endif
-
-/* handle rediculous bsize values - some OSes are broken */
-if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024;
-
- disk_norm(bsize,dfree,dsize);
-
- if (*bsize < 256)
- *bsize = 512;
- if ((*dsize)<1)
- {
- DEBUG(0,("dfree seems to be broken on your system\n"));
- *dsize = 20*1024*1024/(*bsize);
- *dfree = MAX(1,*dfree);
- }
- return(((*bsize)/1024)*(*dfree));
-#endif
+ return True;
}
/****************************************************************************
-wrap it to get filenames right
-****************************************************************************/
-int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize)
-{
- return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize));
-}
-
-
-
-/****************************************************************************
-check a filename - possibly caling reducename
-
-This is called by every routine before it allows an operation on a filename.
-It does any final confirmation necessary to ensure that the filename is
-a valid one for the user to access.
-****************************************************************************/
-BOOL check_name(char *name,int cnum)
-{
- BOOL ret;
-
- errno = 0;
-
- ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
- if (!ret)
- DEBUG(5,("check_name on %s failed\n",name));
-
- return(ret);
-}
-
-/****************************************************************************
-check a filename - possibly caling reducename
-****************************************************************************/
-static void check_for_pipe(char *fname)
-{
- /* special case of pipe opens */
- char s[10];
- StrnCpy(s,fname,9);
- strlower(s);
- if (strstr(s,"pipe/"))
- {
- DEBUG(3,("Rejecting named pipe open for %s\n",fname));
- unix_ERR_class = ERRSRV;
- unix_ERR_code = ERRaccess;
- }
-}
-
-
-/****************************************************************************
-open a file
+ open the socket communication
****************************************************************************/
-void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
+static BOOL open_sockets(BOOL is_daemon,int port)
{
- pstring fname;
-
- Files[fnum].open = False;
- Files[fnum].fd = -1;
- errno = EPERM;
-
- strcpy(fname,fname1);
-
- /* check permissions */
- if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
- {
- DEBUG(3,("Permission denied opening %s\n",fname));
- check_for_pipe(fname);
- return;
- }
-
- /* this handles a bug in Win95 - it doesn't say to create the file when it
- should */
- if (Connections[cnum].printer)
- flags |= O_CREAT;
-
-/*
- if (flags == O_WRONLY)
- DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
-*/
-
-#if UTIME_WORKAROUND
- /* XXXX - is this OK?? */
- /* this works around a utime bug but can cause other problems */
- if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND))
- sys_unlink(fname);
-#endif
-
+ int num_interfaces = iface_count();
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int i;
- Files[fnum].fd = sys_open(fname,flags,mode);
-
- if ((Files[fnum].fd>=0) &&
- Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) {
- pstring dname;
- int dum1,dum2,dum3;
- char *p;
- strcpy(dname,fname);
- p = strrchr(dname,'/');
- if (p) *p = 0;
- if (sys_disk_free(dname,&dum1,&dum2,&dum3) <
- lp_minprintspace(SNUM(cnum))) {
- close(Files[fnum].fd);
- Files[fnum].fd = -1;
- sys_unlink(fname);
- errno = ENOSPC;
- return;
- }
- }
-
-
- /* Fix for files ending in '.' */
- if((Files[fnum].fd == -1) && (errno == ENOENT) &&
- (strchr(fname,'.')==NULL))
- {
- strcat(fname,".");
- Files[fnum].fd = sys_open(fname,flags,mode);
- }
-
-#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
- if ((Files[fnum].fd == -1) && (errno == ENAMETOOLONG))
- {
- int max_len;
- char *p = strrchr(fname, '/');
-
- if (p == fname) /* name is "/xxx" */
- {
- max_len = pathconf("/", _PC_NAME_MAX);
- p++;
+ if (!is_daemon) {
+ return open_sockets_inetd();
}
- else if ((p == NULL) || (p == fname))
- {
- p = fname;
- max_len = pathconf(".", _PC_NAME_MAX);
- }
- else
- {
- *p = '\0';
- max_len = pathconf(fname, _PC_NAME_MAX);
- *p = '/';
- p++;
- }
- if (strlen(p) > max_len)
- {
- char tmp = p[max_len];
-
- p[max_len] = '\0';
- if ((Files[fnum].fd = sys_open(fname,flags,mode)) == -1)
- p[max_len] = tmp;
- }
- }
-#endif
- if (Files[fnum].fd < 0)
- {
- DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
- fname,strerror(errno),flags));
- check_for_pipe(fname);
- return;
- }
-
- if (Files[fnum].fd >= 0)
- {
- struct stat st;
- Connections[cnum].num_files_open++;
- fstat(Files[fnum].fd,&st);
- Files[fnum].mode = st.st_mode;
- Files[fnum].open_time = time(NULL);
- Files[fnum].size = 0;
- Files[fnum].pos = -1;
- Files[fnum].open = True;
- Files[fnum].mmap_ptr = NULL;
- Files[fnum].mmap_size = 0;
- Files[fnum].can_lock = True;
- Files[fnum].can_read = ((flags & O_WRONLY)==0);
- Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
- Files[fnum].share_mode = 0;
- Files[fnum].share_pending = False;
- Files[fnum].print_file = Connections[cnum].printer;
- Files[fnum].modified = False;
- Files[fnum].cnum = cnum;
- string_set(&Files[fnum].name,fname);
- Files[fnum].wbmpx_ptr = NULL;
-
- /*
- * If the printer is marked as postscript output a leading
- * file identifier to ensure the file is treated as a raw
- * postscript file.
- * This has a similar effect as CtrlD=0 in WIN.INI file.
- * tim@fsg.com 09/06/94
- */
- if (Files[fnum].print_file && POSTSCRIPT(cnum) &&
- Files[fnum].can_write)
+
+#ifdef HAVE_ATEXIT
{
- DEBUG(3,("Writing postscript line\n"));
- write_file(fnum,"%!\n",3);
- }
-
- DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
- timestring(),Connections[cnum].user,fname,
- BOOLSTR(Files[fnum].can_read),BOOLSTR(Files[fnum].can_write),
- Connections[cnum].num_files_open,fnum));
-
- }
-
-#if USE_MMAP
- /* mmap it if read-only */
- if (!Files[fnum].can_write)
- {
- Files[fnum].mmap_size = file_size(fname);
- Files[fnum].mmap_ptr = (char *)mmap(NULL,Files[fnum].mmap_size,
- PROT_READ,MAP_SHARED,Files[fnum].fd,0);
-
- if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr)
- {
- DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
- Files[fnum].mmap_ptr = NULL;
+ static int atexit_set;
+ if(atexit_set == 0) {
+ atexit_set=1;
+ atexit(killkids);
+ }
}
- }
-#endif
-}
-
-/*******************************************************************
-sync a file
-********************************************************************/
-void sync_file(int fnum)
-{
-#ifndef NO_FSYNC
- fsync(Files[fnum].fd);
#endif
-}
-
-/****************************************************************************
-run a file if it is a magic script
-****************************************************************************/
-static void check_magic(int fnum,int cnum)
-{
- if (!*lp_magicscript(SNUM(cnum)))
- return;
-
- DEBUG(5,("checking magic for %s\n",Files[fnum].name));
-
- {
- char *p;
- if (!(p = strrchr(Files[fnum].name,'/')))
- p = Files[fnum].name;
- else
- p++;
-
- if (!strequal(lp_magicscript(SNUM(cnum)),p))
- return;
- }
-
- {
- int ret;
- pstring magic_output;
- pstring fname;
- strcpy(fname,Files[fnum].name);
-
- if (*lp_magicoutput(SNUM(cnum)))
- strcpy(magic_output,lp_magicoutput(SNUM(cnum)));
- else
- sprintf(magic_output,"%s.out",fname);
-
- chmod(fname,0755);
- ret = smbrun(fname,magic_output);
- DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
- unlink(fname);
- }
-}
-
-
-/****************************************************************************
-close a file - possibly invalidating the read prediction
-****************************************************************************/
-void close_file(int fnum)
-{
- int cnum = Files[fnum].cnum;
- invalidate_read_prediction(Files[fnum].fd);
- Files[fnum].open = False;
- Connections[cnum].num_files_open--;
- if(Files[fnum].wbmpx_ptr)
- {
- free((char *)Files[fnum].wbmpx_ptr);
- Files[fnum].wbmpx_ptr = NULL;
- }
-
-#if USE_MMAP
- if(Files[fnum].mmap_ptr)
- {
- munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size);
- Files[fnum].mmap_ptr = NULL;
- }
-#endif
-
- if (lp_share_modes(SNUM(cnum)))
- del_share_mode(fnum);
-
- if (Files[fnum].modified) {
- struct stat st;
- if (fstat(Files[fnum].fd,&st) == 0) {
- int dosmode = dos_mode(cnum,Files[fnum].name,&st);
- if (!IS_DOS_ARCHIVE(dosmode)) {
- dos_chmod(cnum,Files[fnum].name,dosmode | aARCH,&st);
- }
- }
- }
-
- close(Files[fnum].fd);
-
- /* NT uses smbclose to start a print - weird */
- if (Files[fnum].print_file)
- print_file(fnum);
-
- /* check for magic scripts */
- check_magic(fnum,cnum);
- DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
- timestring(),Connections[cnum].user,Files[fnum].name,
- Connections[cnum].num_files_open));
-}
-
-enum {AFAIL,AREAD,AWRITE,AALL};
-
-/*******************************************************************
-reproduce the share mode access table
-********************************************************************/
-static int access_table(int new_deny,int old_deny,int old_mode,
- int share_pid,char *fname)
-{
- if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
-
- if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- if (old_deny == new_deny && share_pid == getpid())
- return(AALL);
-
- if (old_mode == 0) return(AREAD);
-
- /* the new smbpub.zip spec says that if the file extension is
- .com, .dll, .exe or .sym then allow the open. I will force
- it to read-only as this seems sensible although the spec is
- a little unclear on this. */
- if ((fname = strrchr(fname,'.'))) {
- if (strequal(fname,".com") ||
- strequal(fname,".dll") ||
- strequal(fname,".exe") ||
- strequal(fname,".sym"))
- return(AREAD);
- }
-
- return(AFAIL);
- }
-
- switch (new_deny)
- {
- case DENY_WRITE:
- if (old_deny==DENY_WRITE && old_mode==0) return(AREAD);
- if (old_deny==DENY_READ && old_mode==0) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==0) return(AALL);
- return(AFAIL);
- case DENY_READ:
- if (old_deny==DENY_WRITE && old_mode==1) return(AREAD);
- if (old_deny==DENY_READ && old_mode==1) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==1) return(AALL);
- return(AFAIL);
- case DENY_NONE:
- if (old_deny==DENY_WRITE) return(AREAD);
- if (old_deny==DENY_READ) return(AWRITE);
- if (old_deny==DENY_NONE) return(AALL);
- return(AFAIL);
- }
- return(AFAIL);
-}
-
-/*******************************************************************
-check if the share mode on a file allows it to be deleted or unlinked
-return True if sharing doesn't prevent the operation
-********************************************************************/
-BOOL check_file_sharing(int cnum,char *fname)
-{
- int pid=0;
- int share_mode = get_share_mode_byname(cnum,fname,&pid);
-
- if (!pid || !share_mode) return(True);
+ /* Stop zombies */
+ CatchChild();
+
+
+ FD_ZERO(&listen_set);
+
+ if(lp_interfaces() && lp_bind_interfaces_only()) {
+ /* We have been given an interfaces line, and been
+ told to only bind to those interfaces. Create a
+ socket per interface and bind to only these.
+ */
+
+ if(num_interfaces > FD_SETSIZE) {
+ DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \
+max can be %d\n",
+ num_interfaces, FD_SETSIZE));
+ return False;
+ }
+
+ /* Now open a listen socket for each of the
+ interfaces. */
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if(ifip == NULL) {
+ DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+ s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if(s == -1)
+ return False;
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,user_socket_options);
+
+ if (listen(s, 5) == -1) {
+ DEBUG(0,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
+ FD_SET(s,&listen_set);
+ }
+ } else {
+ /* Just bind to 0.0.0.0 - accept connections
+ from anywhere. */
+ num_interfaces = 1;
+
+ /* open an incoming socket */
+ s = open_socket_in(SOCK_STREAM, port, 0,
+ interpret_addr(lp_socket_address()),True);
+ if (s == -1)
+ return(False);
+
+ /* ready to listen */
+ set_socket_options(s,"SO_KEEPALIVE");
+ set_socket_options(s,user_socket_options);
+
+ if (listen(s, 5) == -1) {
+ DEBUG(0,("open_sockets: listen: %s\n",
+ strerror(errno)));
+ close(s);
+ return False;
+ }
+
+ fd_listenset[0] = s;
+ FD_SET(s,&listen_set);
+ }
+
+ /* Listen to messages */
+
+ message_register(MSG_SMB_SAM_SYNC, msg_sam_sync);
+ message_register(MSG_SMB_SAM_REPL, msg_sam_repl);
+
+ /* now accept incoming connections - forking a new process
+ for each incoming connection */
+ DEBUG(2,("waiting for a connection\n"));
+ while (1) {
+ fd_set lfds;
+ int num;
+
+ /* Free up temporary memory from the main smbd. */
+ lp_talloc_free();
+
+ /* Ensure we respond to PING and DEBUG messages from the main smbd. */
+ message_dispatch();
+
+ memcpy((char *)&lfds, (char *)&listen_set,
+ sizeof(listen_set));
+
+ num = sys_select(FD_SETSIZE,&lfds,NULL);
+
+ if (num == -1 && errno == EINTR) {
+ extern VOLATILE sig_atomic_t reload_after_sighup;
+
+ /* check for sighup processing */
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = False;
+ }
+
+ continue;
+ }
+
+ /* check if we need to reload services */
+ check_reload(time(NULL));
+
+ /* Find the sockets that are read-ready -
+ accept on these. */
+ for( ; num > 0; num--) {
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+
+ s = -1;
+ for(i = 0; i < num_interfaces; i++) {
+ if(FD_ISSET(fd_listenset[i],&lfds)) {
+ s = fd_listenset[i];
+ /* Clear this so we don't look
+ at it again. */
+ FD_CLR(fd_listenset[i],&lfds);
+ break;
+ }
+ }
+
+ smbd_set_server_fd(accept(s,&addr,&in_addrlen));
+
+ if (smbd_server_fd() == -1 && errno == EINTR)
+ continue;
+
+ if (smbd_server_fd() == -1) {
+ DEBUG(0,("open_sockets: accept: %s\n",
+ strerror(errno)));
+ continue;
+ }
+
+ if (smbd_server_fd() != -1 && sys_fork()==0) {
+ /* Child code ... */
+
+ /* close the listening socket(s) */
+ for(i = 0; i < num_interfaces; i++)
+ close(fd_listenset[i]);
+
+ /* close our standard file
+ descriptors */
+ close_low_fds();
+ am_parent = 0;
+
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(),user_socket_options);
+
+ /* Reset global variables in util.c so
+ that client substitutions will be
+ done correctly in the process. */
+ reset_globals_after_fork();
+
+ /* tdb needs special fork handling */
+ tdb_reopen_all();
+
+ return True;
+ }
+ /* The parent doesn't need this socket */
+ close(smbd_server_fd());
+
+ /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:
+ Clear the closed fd info out of server_fd --
+ and more importantly, out of client_fd in
+ util_sock.c, to avoid a possible
+ getpeername failure if we reopen the logs
+ and use %I in the filename.
+ */
+
+ smbd_set_server_fd(-1);
+
+ /* Force parent to check log size after
+ * spawning child. Fix from
+ * klausr@ITAP.Physik.Uni-Stuttgart.De. The
+ * parent smbd will log to logserver.smb. It
+ * writes only two messages for each child
+ * started/finished. But each child writes,
+ * say, 50 messages also in logserver.smb,
+ * begining with the debug_count of the
+ * parent, before the child opens its own log
+ * file logserver.client. In a worst case
+ * scenario the size of logserver.smb would be
+ * checked after about 50*50=2500 messages
+ * (ca. 100kb).
+ * */
+ force_check_log_size();
- if (share_mode == DENY_DOS)
- return(pid == getpid());
+ } /* end for num */
+ } /* end while 1 */
- /* XXXX exactly what share mode combinations should be allowed for
- deleting/renaming? */
- return(False);
+/* NOTREACHED return True; */
}
/****************************************************************************
- C. Hoch 11/22/95
- Helper for open_file_shared.
- Truncate a file after checking locking; close file if locked.
+ reload the services file
**************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum)
-{
- if (Files[fnum].can_write){
- if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
- close_file(fnum);
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRlock;
- }
- else
- ftruncate(Files[fnum].fd,0);
- }
-}
-
-
-/****************************************************************************
-open a file with a share mode
-****************************************************************************/
-void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
- int mode,int *Access,int *action)
+BOOL reload_services(BOOL test)
{
- int flags=0;
- int flags2=0;
- int deny_mode = (share_mode>>4)&7;
- struct stat sbuf;
- BOOL file_existed = file_exist(fname,&sbuf);
- BOOL fcbopen = False;
- int share_pid=0;
-
- Files[fnum].open = False;
- Files[fnum].fd = -1;
-
- /* this is for OS/2 EAs - try and say we don't support them */
- if (strstr(fname,".+,;=[].")) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
- return;
- }
-
- if ((ofun & 0x3) == 0 && file_existed) {
- errno = EEXIST;
- return;
- }
-
- if (ofun & 0x10)
- flags2 |= O_CREAT;
- if ((ofun & 0x3) == 2)
- flags2 |= O_TRUNC;
-
- /* note that we ignore the append flag as
- append does not mean the same thing under dos and unix */
-
- switch (share_mode&0xF)
- {
- case 1:
- flags = O_WRONLY;
- break;
- case 0xF:
- fcbopen = True;
- flags = O_RDWR;
- break;
- case 2:
- flags = O_RDWR;
- break;
- default:
- flags = O_RDONLY;
- break;
- }
-
- if (flags != O_RDONLY && file_existed &&
- (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) {
- if (!fcbopen) {
- errno = EACCES;
- return;
- }
- flags = O_RDONLY;
- }
-
- if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
- DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
- errno = EINVAL;
- return;
- }
-
- if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
-
- if (lp_share_modes(SNUM(cnum))) {
- int old_share=0;
-
- if (file_existed)
- old_share = get_share_mode(cnum,&sbuf,&share_pid);
-
- if (share_pid) {
- /* someone else has a share lock on it, check to see
- if we can too */
- int old_open_mode = old_share&0xF;
- int old_deny_mode = (old_share>>4)&7;
-
- if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) {
- DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
- deny_mode,old_deny_mode,old_open_mode,fname));
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- return;
- }
-
- {
- int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
- share_pid,fname);
-
- if ((access_allowed == AFAIL) ||
- (access_allowed == AREAD && flags == O_WRONLY) ||
- (access_allowed == AWRITE && flags == O_RDONLY)) {
- DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
- deny_mode,old_deny_mode,old_open_mode,
- share_pid,fname,
- access_allowed));
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- return;
- }
-
- if (access_allowed == AREAD)
- flags = O_RDONLY;
+ BOOL ret;
- if (access_allowed == AWRITE)
- flags = O_WRONLY;
- }
- }
- }
-
- DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
- flags,flags2,mode));
-
- open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode);
- if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) {
- flags = O_RDONLY;
- open_file(fnum,cnum,fname,flags,mode);
- }
-
- if (Files[fnum].open) {
- int open_mode=0;
- switch (flags) {
- case O_RDONLY:
- open_mode = 0;
- break;
- case O_RDWR:
- open_mode = 2;
- break;
- case O_WRONLY:
- open_mode = 1;
- break;
- }
-
- Files[fnum].share_mode = (deny_mode<<4) | open_mode;
- Files[fnum].share_pending = True;
-
- if (Access) {
- (*Access) = open_mode;
- }
-
- if (action) {
- if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
- if (!file_existed) *action = 2;
- if (file_existed && (flags2 & O_TRUNC)) *action = 3;
- }
-
- if (!share_pid)
- share_mode_pending = True;
-
- if ((flags2&O_TRUNC) && file_existed)
- truncate_unless_locked(fnum,cnum);
- }
-}
+ if (lp_loaded()) {
+ pstring fname;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,dyn_CONFIGFILE)) {
+ pstrcpy(dyn_CONFIGFILE,fname);
+ test = False;
+ }
+ }
+ reopen_logs();
+ if (test && !lp_file_list_changed())
+ return(True);
-/*******************************************************************
-check for files that we should now set our share modes on
-********************************************************************/
-static void check_share_modes(void)
-{
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if(Files[i].open && Files[i].share_pending) {
- if (lp_share_modes(SNUM(Files[i].cnum))) {
- int pid=0;
- get_share_mode_by_fnum(Files[i].cnum,i,&pid);
- if (!pid) {
- set_share_mode(i,Files[i].share_mode);
- Files[i].share_pending = False;
- }
- } else {
- Files[i].share_pending = False;
- }
- }
-}
+ lp_killunused(conn_snum_used);
+
+ ret = lp_load(dyn_CONFIGFILE,False,False,True);
+ load_printers();
-/****************************************************************************
-seek a file. Try to avoid the seek if possible
-****************************************************************************/
-int seek_file(int fnum,int pos)
-{
- int offset = 0;
- if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
- offset = 3;
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
- Files[fnum].pos = lseek(Files[fnum].fd,pos+offset,SEEK_SET) - offset;
- return(Files[fnum].pos);
-}
+ reopen_logs();
+
+ load_interfaces();
-/****************************************************************************
-read from a file
-****************************************************************************/
-int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact)
-{
- int ret=0;
-
- if (!Files[fnum].can_write)
- {
- ret = read_predict(Files[fnum].fd,
- pos,
- data,
- NULL,
- maxcnt);
-
- data += ret;
- maxcnt -= ret;
- mincnt = MAX(mincnt-ret,0);
- pos += ret;
- }
-
-#if USE_MMAP
- if (Files[fnum].mmap_ptr)
- {
- int num = MIN(maxcnt,Files[fnum].mmap_size-pos);
- if (num > 0)
{
- memcpy(data,Files[fnum].mmap_ptr+pos,num);
- data += num;
- pos += num;
- maxcnt -= num;
- mincnt = MAX(mincnt-num,0);
- ret += num;
+ if (smbd_server_fd() != -1) {
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(),user_socket_options);
+ }
}
- }
-#endif
- if (maxcnt <= 0)
- return(ret);
-
- if (seek_file(fnum,pos) != pos)
- {
- DEBUG(3,("Failed to seek to %d\n",pos));
- return(ret);
- }
-
- if (maxcnt > 0)
- ret += read_with_timeout(Files[fnum].fd,
- data,
- mincnt,
- maxcnt,
- timeout,
- exact);
-
- return(ret);
-}
+ reset_mangled_cache();
+ reset_stat_cache();
+ /* this forces service parameters to be flushed */
+ set_current_service(NULL,True);
-/****************************************************************************
-write to a file
-****************************************************************************/
-int write_file(int fnum,char *data,int n)
-{
- if (!Files[fnum].can_write) {
- errno = EPERM;
- return(0);
- }
-
- Files[fnum].modified = True;
-
- return(write_data(Files[fnum].fd,data,n));
+ return(ret);
}
-static int old_umask = 022;
/****************************************************************************
-load parameters specific to a connection/service
+ Catch a sighup.
****************************************************************************/
-BOOL become_service(int cnum,BOOL do_chdir)
-{
- extern char magic_char;
- static int last_cnum = -1;
- int snum;
-
- if (!OPEN_CNUM(cnum))
- {
- last_cnum = -1;
- return(False);
- }
-
- Connections[cnum].lastused = smb_last_time;
-
- snum = SNUM(cnum);
-
- if (do_chdir &&
- ChDir(Connections[cnum].connectpath) != 0 &&
- ChDir(Connections[cnum].origpath) != 0)
- {
- DEBUG(0,("%s chdir (%s) failed cnum=%d\n",timestring(),
- Connections[cnum].connectpath,cnum));
- return(False);
- }
-
- if (cnum == last_cnum)
- return(True);
-
- last_cnum = cnum;
-
- case_default = lp_defaultcase(snum);
- case_preserve = lp_preservecase(snum);
- short_case_preserve = lp_shortpreservecase(snum);
- case_mangle = lp_casemangle(snum);
- case_sensitive = lp_casesensitive(snum);
- magic_char = lp_magicchar(snum);
- use_mangled_map = (*lp_mangled_map(snum) ? True:False);
- return(True);
-}
+VOLATILE sig_atomic_t reload_after_sighup = False;
-/****************************************************************************
- become the specified uid
-****************************************************************************/
-static BOOL become_uid(int uid)
+static void sig_hup(int sig)
{
- if (initial_uid != 0)
- return(True);
-
-#ifdef AIX
- {
- /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
- priv_t priv;
-
- priv.pv_priv[0] = 0;
- priv.pv_priv[1] = 0;
- if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
- &priv, sizeof(priv_t)) < 0 ||
- setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
- seteuid((uid_t)uid) < 0)
- DEBUG(1,("Can't set uid (AIX3)"));
- }
-#endif
+ BlockSignals(True,SIGHUP);
+ DEBUG(0,("Got SIGHUP\n"));
-#ifdef USE_SETRES
- if (setresuid(-1,uid,-1) != 0)
-#else
- if ((seteuid(uid) != 0) &&
- (setuid(uid) != 0))
-#endif
- {
- DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
- uid,getuid(), geteuid()));
- if (uid > 32000)
- DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
- return(False);
- }
-
- if (((uid == -1) || (uid == 65535)) && geteuid() != uid)
- {
- DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
- return(False);
- }
-
- return(True);
+ sys_select_signal();
+ reload_after_sighup = True;
+ BlockSignals(False,SIGHUP);
}
-/****************************************************************************
- become the specified gid
-****************************************************************************/
-static BOOL become_gid(int gid)
-{
- if (initial_uid != 0)
- return(True);
-
-#ifdef USE_SETRES
- if (setresgid(-1,gid,-1) != 0)
-#else
- if (setgid(gid) != 0)
-#endif
- {
- DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
- gid,getgid(),getegid()));
- if (gid > 32000)
- DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
- return(False);
- }
-
- return(True);
-}
-
-
-/****************************************************************************
- become the specified uid and gid
-****************************************************************************/
-static BOOL become_id(int uid,int gid)
-{
- return(become_gid(gid) && become_uid(uid));
-}
-
-/****************************************************************************
-become the guest user
-****************************************************************************/
-static BOOL become_guest(void)
-{
- BOOL ret;
- static struct passwd *pass=NULL;
-
- if (initial_uid != 0)
- return(True);
-
- if (!pass)
- pass = Get_Pwnam(lp_guestaccount(-1),True);
- if (!pass) return(False);
-
- ret = become_id(pass->pw_uid,pass->pw_gid);
-
- if (!ret)
- DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
-
- last_user.cnum = -2;
-
- return(ret);
-}
+#if DUMP_CORE
/*******************************************************************
-check if a username is OK
+prepare to dump a core file - carefully!
********************************************************************/
-static BOOL check_user_ok(int cnum,user_struct *vuser,int snum)
-{
- int i;
- for (i=0;i<Connections[cnum].uid_cache.entries;i++)
- if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True);
-
- if (!user_ok(vuser->name,snum)) return(False);
-
- i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE;
- Connections[cnum].uid_cache.list[i] = vuser->uid;
-
- if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE)
- Connections[cnum].uid_cache.entries++;
-
- return(True);
-}
-
-
-/****************************************************************************
- become the user of a connection number
-****************************************************************************/
-BOOL become_user(int cnum, int uid)
-{
- int new_umask;
- user_struct *vuser;
- int snum,gid;
- int ngroups;
- gid_t *groups;
-
- if (last_user.cnum == cnum && last_user.uid == uid) {
- DEBUG(4,("Skipping become_user - already user\n"));
- return(True);
- }
-
- unbecome_user();
-
- if (!OPEN_CNUM(cnum)) {
- DEBUG(2,("Connection %d not open\n",cnum));
- return(False);
- }
-
- snum = Connections[cnum].service;
-
- if (Connections[cnum].force_user ||
- lp_security() == SEC_SHARE ||
- !(vuser = get_valid_user_struct(uid)) ||
- !check_user_ok(cnum,vuser,snum)) {
- uid = Connections[cnum].uid;
- gid = Connections[cnum].gid;
- groups = Connections[cnum].groups;
- ngroups = Connections[cnum].ngroups;
- } else {
- if (!vuser) {
- DEBUG(2,("Invalid vuid used %d\n",uid));
- return(False);
- }
- uid = vuser->uid;
- if(!*lp_force_group(snum))
- gid = vuser->gid;
- else
- gid = Connections[cnum].gid;
- groups = vuser->user_groups;
- ngroups = vuser->user_ngroups;
- }
-
- if (initial_uid == 0)
- {
- if (!become_gid(gid)) return(False);
-
-#ifndef NO_SETGROUPS
- if (!IS_IPC(cnum)) {
- /* groups stuff added by ih/wreu */
- if (ngroups > 0)
- if (setgroups(ngroups,groups)<0)
- DEBUG(0,("setgroups call failed!\n"));
- }
-#endif
-
- if (!Connections[cnum].admin_user && !become_uid(uid))
- return(False);
- }
-
- new_umask = 0777 & ~CREATE_MODE(cnum);
- old_umask = umask(new_umask);
-
- last_user.cnum = cnum;
- last_user.uid = uid;
-
- DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n",
- getuid(),geteuid(),getgid(),getegid(),new_umask));
-
- return(True);
-}
-
-/****************************************************************************
- unbecome the user of a connection number
-****************************************************************************/
-BOOL unbecome_user(void )
+static BOOL dump_core(void)
{
- if (last_user.cnum == -1)
- return(False);
-
- ChDir(OriginalDir);
-
- umask(old_umask);
-
- if (initial_uid == 0)
- {
-#ifdef USE_SETRES
- setresuid(-1,getuid(),-1);
- setresgid(-1,getgid(),-1);
-#else
- if (seteuid(initial_uid) != 0)
- setuid(initial_uid);
- setgid(initial_gid);
+ char *p;
+ pstring dname;
+ pstrcpy(dname,lp_logfile());
+ if ((p=strrchr_m(dname,'/'))) *p=0;
+ pstrcat(dname,"/corefiles");
+ mkdir(dname,0700);
+ sys_chown(dname,getuid(),getgid());
+ chmod(dname,0700);
+ if (chdir(dname)) return(False);
+ umask(~(0700));
+
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Core limits now %d %d\n",
+ (int)rlp.rlim_cur,(int)rlp.rlim_max));
+ }
#endif
- }
-#ifdef NO_EID
- if (initial_uid == 0)
- DEBUG(2,("Running with no EID\n"));
- initial_uid = getuid();
- initial_gid = getgid();
-#else
- if (geteuid() != initial_uid)
- {
- DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
- initial_uid = geteuid();
- }
- if (getegid() != initial_gid)
- {
- DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
- initial_gid = getegid();
- }
#endif
-
- if (ChDir(OriginalDir) != 0)
- DEBUG(0,("%s chdir(%s) failed in unbecome_user\n",
- timestring(),OriginalDir));
-
- DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
- getuid(),geteuid(),getgid(),getegid()));
- last_user.cnum = -1;
- return(True);
-}
-
-/****************************************************************************
- find a service entry
-****************************************************************************/
-int find_service(char *service)
-{
- int iService;
-
- string_sub(service,"\\","/");
-
- iService = lp_servicenumber(service);
-
- /* now handle the special case of a home directory */
- if (iService < 0)
- {
- char *phome_dir = get_home_dir(service);
- DEBUG(3,("checking for home directory %s gave %s\n",service,
- phome_dir?phome_dir:"(NULL)"));
- if (phome_dir)
- {
- int iHomeService;
- if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
- {
- lp_add_home(service,iHomeService,phome_dir);
- iService = lp_servicenumber(service);
- }
- }
- }
-
- /* If we still don't have a service, attempt to add it as a printer. */
- if (iService < 0)
- {
- int iPrinterService;
-
- if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
- {
- char *pszTemp;
-
- DEBUG(3,("checking whether %s is a valid printer name...\n", service));
- pszTemp = PRINTCAP;
- if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
- {
- DEBUG(3,("%s is a valid printer name\n", service));
- DEBUG(3,("adding %s as a printer service\n", service));
- lp_add_printer(service,iPrinterService);
- iService = lp_servicenumber(service);
- if (iService < 0)
- DEBUG(0,("failed to add %s as a printer service!\n", service));
- }
- else
- DEBUG(3,("%s is not a valid printer name\n", service));
- }
- }
-
- /* just possibly it's a default service? */
- if (iService < 0)
- {
- char *defservice = lp_defaultservice();
- if (defservice && *defservice && !strequal(defservice,service)) {
- iService = find_service(defservice);
- if (iService >= 0) {
- string_sub(service,"_","/");
- iService = lp_add_service(service,iService);
- }
- }
- }
-
- if (iService >= 0)
- if (!VALID_SNUM(iService))
- {
- DEBUG(0,("Invalid snum %d for %s\n",iService,service));
- iService = -1;
- }
-
- if (iService < 0)
- DEBUG(3,("find_service() failed to find service %s\n", service));
-
- return (iService);
+ DEBUG(0,("Dumping core in %s\n",dname));
+ abort();
+ return(True);
}
-
+#endif
/****************************************************************************
- create an error packet from a cached error.
+update the current smbd process count
****************************************************************************/
-int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line)
-{
- write_bmpx_struct *wbmpx = Files[fnum].wbmpx_ptr;
-
- int32 eclass = wbmpx->wr_errclass;
- int32 err = wbmpx->wr_error;
-
- /* We can now delete the auxiliary struct */
- free((char *)wbmpx);
- Files[fnum].wbmpx_ptr = NULL;
- return error_packet(inbuf,outbuf,eclass,err,line);
-}
-
-struct
-{
- int unixerror;
- int smbclass;
- int smbcode;
-} unix_smb_errmap[] =
+static void decrement_smbd_process_count(void)
{
- {EPERM,ERRDOS,ERRnoaccess},
- {EACCES,ERRDOS,ERRnoaccess},
- {ENOENT,ERRDOS,ERRbadfile},
- {EIO,ERRHRD,ERRgeneral},
- {EBADF,ERRSRV,ERRsrverror},
- {EINVAL,ERRSRV,ERRsrverror},
- {EEXIST,ERRDOS,ERRfilexists},
- {ENFILE,ERRDOS,ERRnofids},
- {EMFILE,ERRDOS,ERRnofids},
- {ENOSPC,ERRHRD,ERRdiskfull},
-#ifdef EDQUOT
- {EDQUOT,ERRHRD,ERRdiskfull},
-#endif
-#ifdef ENOTEMPTY
- {ENOTEMPTY,ERRDOS,ERRnoaccess},
-#endif
-#ifdef EXDEV
- {EXDEV,ERRDOS,ERRdiffdevice},
-#endif
- {EROFS,ERRHRD,ERRnowrite},
- {0,0,0}
-};
+ int total_smbds;
-
-/****************************************************************************
- create an error packet from errno
-****************************************************************************/
-int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line)
-{
- int eclass=def_class;
- int ecode=def_code;
- int i=0;
-
- if (unix_ERR_class != SUCCESS)
- {
- eclass = unix_ERR_class;
- ecode = unix_ERR_code;
- unix_ERR_class = SUCCESS;
- unix_ERR_code = 0;
- }
- else
- {
- while (unix_smb_errmap[i].smbclass != 0)
- {
- if (unix_smb_errmap[i].unixerror == errno)
- {
- eclass = unix_smb_errmap[i].smbclass;
- ecode = unix_smb_errmap[i].smbcode;
- break;
- }
- i++;
+ if (lp_max_smbd_processes()) {
+ total_smbds = 0;
+ tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1);
}
- }
-
- return(error_packet(inbuf,outbuf,eclass,ecode,line));
-}
-
-
-/****************************************************************************
- create an error packet. Normally called using the ERROR() macro
-****************************************************************************/
-int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line)
-{
- int outsize = set_message(outbuf,0,0,True);
- int cmd;
- cmd = CVAL(inbuf,smb_com);
-
- CVAL(outbuf,smb_rcls) = error_class;
- SSVAL(outbuf,smb_err,error_code);
-
- DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
- timestring(),
- line,
- (int)CVAL(inbuf,smb_com),
- smb_fn_name(CVAL(inbuf,smb_com)),
- error_class,
- error_code));
-
- if (errno != 0)
- DEBUG(3,("error string = %s\n",strerror(errno)));
-
- return(outsize);
}
-
-#ifndef SIGCLD_IGNORE
/****************************************************************************
-this prevents zombie child processes
+exit the server
****************************************************************************/
-static int sig_cld()
+void exit_server(char *reason)
{
- static int depth = 0;
- if (depth != 0)
- {
- DEBUG(0,("ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'?\n"));
- depth=0;
- return(0);
- }
- depth++;
-
- BlockSignals(True);
- DEBUG(5,("got SIGCLD\n"));
-
-#ifdef USE_WAITPID
- while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
-#endif
+ static int firsttime=1;
+ extern char *last_inbuf;
+ extern auth_authsupplied_info *negprot_global_auth_info;
- /* Stop zombies */
- /* Stevens, Adv. Unix Prog. says that on system V you must call
- wait before reinstalling the signal handler, because the kernel
- calls the handler from within the signal-call when there is a
- child that has exited. This would lead to an infinite recursion
- if done vice versa. */
-
-#ifndef DONT_REINSTALL_SIG
-#ifdef SIGCLD_IGNORE
- signal(SIGCLD, SIG_IGN);
-#else
- signal(SIGCLD, SIGNAL_CAST sig_cld);
-#endif
-#endif
+ if (!firsttime)
+ exit(0);
+ firsttime = 0;
-#ifndef USE_WAITPID
- while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
-#endif
- depth--;
- BlockSignals(False);
- return 0;
-}
-#endif
+ change_to_root_user();
+ DEBUG(2,("Closing connections\n"));
-/****************************************************************************
- this is called when the client exits abruptly
- **************************************************************************/
-static int sig_pipe()
-{
- exit_server("Got sigpipe\n");
- return(0);
-}
-
-/****************************************************************************
- open the socket communication
-****************************************************************************/
-static BOOL open_sockets(BOOL is_daemon,int port)
-{
- extern int Client;
-
- if (is_daemon)
- {
- int s;
- struct sockaddr addr;
- int in_addrlen = sizeof(addr);
-
- /* Stop zombies */
-#ifdef SIGCLD_IGNORE
- signal(SIGCLD, SIG_IGN);
-#else
- signal(SIGCLD, SIGNAL_CAST sig_cld);
-#endif
+ free_auth_info(&negprot_global_auth_info);
- /* open an incoming socket */
- s = open_socket_in(SOCK_STREAM, port, 0);
- if (s == -1)
- return(False);
+ conn_close_all();
- /* ready to listen */
- if (listen(s, 5) == -1)
- {
- DEBUG(0,("listen: %s",strerror(errno)));
- close(s);
- return False;
- }
-
- /* now accept incoming connections - forking a new process
- for each incoming connection */
- DEBUG(2,("waiting for a connection\n"));
- while (1)
- {
- Client = accept(s,&addr,&in_addrlen);
+ invalidate_all_vuids();
- if (Client == -1 && errno == EINTR)
- continue;
+ /* delete our entry in the connections database. */
+ yield_connection(NULL,"",MAXSTATUS);
- if (Client == -1)
- {
- DEBUG(0,("accept: %s",strerror(errno)));
- return False;
- }
+ respond_to_all_remaining_local_messages();
+ decrement_smbd_process_count();
-#ifdef NO_FORK_DEBUG
-#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
- signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
- return True;
-#else
- if (Client != -1 && fork()==0)
- {
-#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
- signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
- /* close our standard file descriptors */
- close_low_fds();
-
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
-
- return True;
- }
- close(Client); /* The parent doesn't need this socket */
-#endif
+#ifdef WITH_DFS
+ if (dcelogin_atmost_once) {
+ dfs_unlogin();
}
- }
- else
- {
- /* We will abort gracefully when the client or remote system
- goes away */
-#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
#endif
- Client = dup(0);
- /* close our standard file descriptors */
- close_low_fds();
+ if (!reason) {
+ int oldlevel = DEBUGLEVEL;
+ DEBUGLEVEL = 10;
+ DEBUG(0,("Last message was %s\n",smb_fn_name(last_message)));
+ if (last_inbuf)
+ show_msg(last_inbuf);
+ DEBUGLEVEL = oldlevel;
+ DEBUG(0,("===============================================================\n"));
+#if DUMP_CORE
+ if (dump_core()) return;
+#endif
+ }
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
- }
+ locking_end();
- return True;
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
}
-
/****************************************************************************
-check if a snum is in use
+ initialise connect, service and file structs
****************************************************************************/
-BOOL snum_used(int snum)
-{
- int i;
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (OPEN_CNUM(i) && (SNUM(i) == snum))
- return(True);
- return(False);
-}
-
-/****************************************************************************
- reload the services file
- **************************************************************************/
-BOOL reload_services(BOOL test)
+static void init_structs(void )
{
- BOOL ret;
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
- if (lp_loaded())
- {
- pstring fname;
- strcpy(fname,lp_configfile());
- if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
- {
- strcpy(servicesf,fname);
- test = False;
+ if (!*global_myname) {
+ char *p;
+ fstrcpy( global_myname, myhostname() );
+ p = strchr_m( global_myname, '.' );
+ if (p)
+ *p = 0;
}
- }
- reopen_logs();
+ strupper( global_myname );
- if (test && !lp_file_list_changed())
- return(True);
+ conn_init();
- lp_killunused(snum_used);
+ file_init();
- ret = lp_load(servicesf,False);
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
- /* perhaps the config filename is now set */
- if (!test)
- reload_services(True);
+ init_dptrs();
- reopen_logs();
-
- {
- extern int Client;
- if (Client != -1) {
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
- }
- }
-
- create_mangled_stack(lp_mangledstack());
-
- /* this forces service parameters to be flushed */
- become_service(-1,True);
-
- return(ret);
+ secrets_init();
}
-
-
/****************************************************************************
-this prevents zombie child processes
+usage on the program
****************************************************************************/
-static int sig_hup()
+static void usage(char *pname)
{
- BlockSignals(True);
- DEBUG(0,("Got SIGHUP\n"));
- reload_services(False);
-#ifndef DONT_REINSTALL_SIG
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
- BlockSignals(False);
- return(0);
-}
-/****************************************************************************
-Setup the groups a user belongs to.
-****************************************************************************/
-int setup_groups(char *user, int uid, int gid, int *p_ngroups,
- int **p_igroups, gid_t **p_groups)
-{
- if (-1 == initgroups(user,gid))
- {
- if (getuid() == 0)
- {
- DEBUG(0,("Unable to initgroups!\n"));
- if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
- DEBUG(0,("This is probably a problem with the account %s\n",user));
- }
- }
- else
- {
- int i,ngroups;
- int *igroups;
- gid_t grp = 0;
- ngroups = getgroups(0,&grp);
- if (ngroups <= 0)
- ngroups = 32;
- igroups = (int *)malloc(sizeof(int)*ngroups);
- for (i=0;i<ngroups;i++)
- igroups[i] = 0x42424242;
- ngroups = getgroups(ngroups,(gid_t *)igroups);
-
- if (igroups[0] == 0x42424242)
- ngroups = 0;
-
- *p_ngroups = ngroups;
-
- /* The following bit of code is very strange. It is due to the
- fact that some OSes use int* and some use gid_t* for
- getgroups, and some (like SunOS) use both, one in prototypes,
- and one in man pages and the actual code. Thus we detect it
- dynamically using some very ugly code */
- if (ngroups > 0)
- {
- /* does getgroups return ints or gid_t ?? */
- static BOOL groups_use_ints = True;
-
- if (groups_use_ints &&
- ngroups == 1 &&
- SVAL(igroups,2) == 0x4242)
- groups_use_ints = False;
-
- for (i=0;groups_use_ints && i<ngroups;i++)
- if (igroups[i] == 0x42424242)
- groups_use_ints = False;
-
- if (groups_use_ints)
- {
- *p_igroups = igroups;
- *p_groups = (gid_t *)igroups;
- }
- else
- {
- gid_t *groups = (gid_t *)igroups;
- igroups = (int *)malloc(sizeof(int)*ngroups);
- for (i=0;i<ngroups;i++)
- igroups[i] = groups[i];
- *p_igroups = igroups;
- *p_groups = (gid_t *)groups;
- }
- }
- DEBUG(3,("%s is in %d groups\n",user,ngroups));
- for (i=0;i<ngroups;i++)
- DEBUG(3,("%d ",igroups[i]));
- DEBUG(3,("\n"));
- }
- return 0;
+ d_printf("Usage: %s [-DaoPh?Vb] [-d debuglevel] [-l log basename] [-p port]\n", pname);
+ d_printf(" [-O socket options] [-s services file]\n");
+ d_printf("\t-D Become a daemon\n");
+ d_printf("\t-a Append to log file (default)\n");
+ d_printf("\t-o Overwrite log file, don't append\n");
+ d_printf("\t-h Print usage\n");
+ d_printf("\t-? Print usage\n");
+ d_printf("\t-V Print version\n");
+ d_printf("\t-b Print build options\n");
+ d_printf("\t-d debuglevel Set the debuglevel\n");
+ d_printf("\t-l log basename. Basename for log/debug files\n");
+ d_printf("\t-p port Listen on the specified port\n");
+ d_printf("\t-O socket options Socket options\n");
+ d_printf("\t-s services file. Filename of services file\n");
+ d_printf("\n");
}
/****************************************************************************
- make a connection to a service
+ main program
****************************************************************************/
-int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid)
-{
- int cnum;
- int snum;
- struct passwd *pass = NULL;
- connection_struct *pcon;
- BOOL guest = False;
- BOOL force = False;
- static BOOL first_connection = True;
-
- strlower(service);
-
- snum = find_service(service);
- if (snum < 0)
- {
- if (strequal(service,"IPC$"))
- {
- DEBUG(3,("%s refusing IPC connection\n",timestring()));
- return(-3);
- }
-
- DEBUG(0,("%s couldn't find service %s\n",timestring(),service));
- return(-2);
- }
-
- if (strequal(service,HOMES_NAME))
- {
- if (*user && Get_Pwnam(user,True))
- return(make_connection(user,user,password,pwlen,dev,vuid));
-
- if (validated_username(vuid))
- {
- strcpy(user,validated_username(vuid));
- return(make_connection(user,user,password,pwlen,dev,vuid));
- }
- }
-
- if (!lp_snum_ok(snum) || !check_access(snum)) {
- return(-4);
- }
-
- /* you can only connect to the IPC$ service as an ipc device */
- if (strequal(service,"IPC$"))
- strcpy(dev,"IPC");
-
- if (*dev == '?' || !*dev)
- {
- if (lp_print_ok(snum))
- strcpy(dev,"LPT1:");
- else
- strcpy(dev,"A:");
- }
-
- /* if the request is as a printer and you can't print then refuse */
- strupper(dev);
- if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
- DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
- return(-6);
- }
-
- /* lowercase the user name */
- strlower(user);
-
- /* add it as a possible user name */
- add_session_user(service);
-
- /* shall we let them in? */
- if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid))
- {
- DEBUG(2,("%s invalid username/password for %s\n",timestring(),service));
- return(-1);
- }
-
- cnum = find_free_connection(str_checksum(service) + str_checksum(user));
- if (cnum < 0)
- {
- DEBUG(0,("%s couldn't find free connection\n",timestring()));
- return(-1);
- }
-
- pcon = &Connections[cnum];
- bzero((char *)pcon,sizeof(*pcon));
-
- /* find out some info about the user */
- pass = Get_Pwnam(user,True);
-
- if (pass == NULL)
- {
- DEBUG(0,("%s couldn't find account %s\n",timestring(),user));
- return(-7);
- }
-
- pcon->read_only = lp_readonly(snum);
-
- {
- pstring list;
- StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
- string_sub(list,"%S",service);
-
- if (user_in_list(user,list))
- pcon->read_only = True;
-
- StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
- string_sub(list,"%S",service);
-
- if (user_in_list(user,list))
- pcon->read_only = False;
- }
-
- /* admin user check */
- if (user_in_list(user,lp_admin_users(snum)) &&
- !pcon->read_only)
- {
- pcon->admin_user = True;
- DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
- }
- else
- pcon->admin_user = False;
-
- pcon->force_user = force;
- pcon->uid = pass->pw_uid;
- pcon->gid = pass->pw_gid;
- pcon->num_files_open = 0;
- pcon->lastused = time(NULL);
- pcon->service = snum;
- pcon->used = True;
- pcon->printer = (strncmp(dev,"LPT",3) == 0);
- pcon->ipc = (strncmp(dev,"IPC",3) == 0);
- pcon->dirptr = NULL;
- string_set(&pcon->dirpath,"");
- string_set(&pcon->user,user);
-
-#if HAVE_GETGRNAM
- if (*lp_force_group(snum))
- {
- struct group *gptr = (struct group *)getgrnam(lp_force_group(snum));
- if (gptr)
- {
- pcon->gid = gptr->gr_gid;
- DEBUG(3,("Forced group %s\n",lp_force_group(snum)));
- }
- else
- DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum)));
- }
-#endif
+ int main(int argc,char *argv[])
+{
+ extern BOOL append_log;
+ extern char *optarg;
+ /* shall I run as a daemon */
+ BOOL is_daemon = False;
+ BOOL specified_logfile = False;
+ int port = SMB_PORT;
+ int opt;
+ pstring logfile;
+
+#ifdef HAVE_SET_AUTH_PARAMETERS
+ set_auth_parameters(argc,argv);
+#endif
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-')) {
+ argv++;
+ argc--;
+ }
+
+ while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dp:h?bVaof:")) )
+ switch (opt) {
+ case 'O':
+ pstrcpy(user_socket_options,optarg);
+ break;
+
+ case 's':
+ pstrcpy(dyn_CONFIGFILE,optarg);
+ break;
+
+ case 'l':
+ specified_logfile = True;
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd", optarg);
+ lp_set_logfile(logfile);
+ break;
+
+ case 'a':
+ append_log = True;
+ break;
+
+ case 'o':
+ append_log = False;
+ break;
+
+ case 'D':
+ is_daemon = True;
+ break;
+
+ case 'd':
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+
+ case 'p':
+ port = atoi(optarg);
+ break;
+
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(0);
+ break;
+
+ case 'V':
+ d_printf("Version %s\n",VERSION);
+ exit(0);
+ break;
+ case 'b':
+ build_options(True); /* Display output to screen as well as debug */
+ exit(0);
+ break;
+ default:
+ DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
+ usage(argv[0]);
+ exit(1);
+ }
- if (*lp_force_user(snum))
- {
- struct passwd *pass2;
- fstring fuser;
- strcpy(fuser,lp_force_user(snum));
- pass2 = (struct passwd *)Get_Pwnam(fuser,True);
- if (pass2)
- {
- pcon->uid = pass2->pw_uid;
- string_set(&pcon->user,fuser);
- strcpy(user,fuser);
- pcon->force_user = True;
- DEBUG(3,("Forced user %s\n",fuser));
- }
- else
- DEBUG(1,("Couldn't find user %s\n",fuser));
- }
-
- {
- pstring s;
- strcpy(s,lp_pathname(snum));
- standard_sub(cnum,s);
- string_set(&pcon->connectpath,s);
- DEBUG(3,("Connect path is %s\n",s));
- }
-
- /* groups stuff added by ih */
- pcon->ngroups = 0;
- pcon->groups = NULL;
-
- if (!IS_IPC(cnum))
- {
- /* Find all the groups this uid is in and store them. Used by become_user() */
- setup_groups(pcon->user,pcon->uid,pcon->gid,&pcon->ngroups,&pcon->igroups,&pcon->groups);
-
- /* check number of connections */
- if (!claim_connection(cnum,
- lp_servicename(SNUM(cnum)),
- lp_max_connections(SNUM(cnum)),False))
- {
- DEBUG(1,("too many connections - rejected\n"));
- return(-8);
- }
-
- if (lp_status(SNUM(cnum)))
- claim_connection(cnum,"STATUS.",MAXSTATUS,first_connection);
-
- first_connection = False;
- } /* IS_IPC */
-
- pcon->open = True;
-
- /* execute any "root preexec = " line */
- if (*lp_rootpreexec(SNUM(cnum)))
- {
- pstring cmd;
- strcpy(cmd,lp_rootpreexec(SNUM(cnum)));
- standard_sub(cnum,cmd);
- DEBUG(5,("cmd=%s\n",cmd));
- smbrun(cmd,NULL);
- }
-
- if (!become_user(cnum,pcon->uid))
- {
- DEBUG(0,("Can't become connected user!\n"));
- pcon->open = False;
- if (!IS_IPC(cnum)) {
- yield_connection(cnum,
- lp_servicename(SNUM(cnum)),
- lp_max_connections(SNUM(cnum)));
- if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS);
- }
- return(-1);
- }
-
- if (ChDir(pcon->connectpath) != 0)
- {
- DEBUG(0,("Can't change directory to %s\n",pcon->connectpath));
- pcon->open = False;
- unbecome_user();
- if (!IS_IPC(cnum)) {
- yield_connection(cnum,
- lp_servicename(SNUM(cnum)),
- lp_max_connections(SNUM(cnum)));
- if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS);
- }
- return(-5);
- }
-
- string_set(&pcon->origpath,pcon->connectpath);
-
-#if SOFTLINK_OPTIMISATION
- /* resolve any soft links early */
- {
- pstring s;
- strcpy(s,pcon->connectpath);
- GetWd(s);
- string_set(&pcon->connectpath,s);
- ChDir(pcon->connectpath);
- }
+#ifdef HAVE_SETLUID
+ /* needed for SecureWare on SCO */
+ setluid(0);
#endif
- num_connections_open++;
- add_session_user(user);
-
- /* execute any "preexec = " line */
- if (*lp_preexec(SNUM(cnum)))
- {
- pstring cmd;
- strcpy(cmd,lp_preexec(SNUM(cnum)));
- standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
- }
-
- /* we've finished with the sensitive stuff */
- unbecome_user();
-
- {
- extern struct from_host Client_info;
- DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
- timestring(),
- Client_info.name,Client_info.addr,
- lp_servicename(SNUM(cnum)),user,
- pcon->uid,
- pcon->gid,
- (int)getpid()));
- }
-
- return(cnum);
-}
-
+ sec_init();
-/****************************************************************************
- find first available file slot
-****************************************************************************/
-int find_free_file(void )
-{
- int i;
- for (i=1;i<MAX_OPEN_FILES;i++)
- if (!Files[i].open)
- return(i);
- DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
- return(-1);
-}
+ load_case_tables();
-/****************************************************************************
- find first available connection slot, starting from a random position.
-The randomisation stops problems with the server dieing and clients
-thinking the server is still available.
-****************************************************************************/
-static int find_free_connection(int hash )
-{
- int i;
- BOOL used=False;
- hash = (hash % (MAX_CONNECTIONS-2))+1;
-
- again:
+ append_log = True;
- for (i=hash+1;i!=hash;)
- {
- if (!Connections[i].open && Connections[i].used == used)
- {
- DEBUG(3,("found free connection number %d\n",i));
- return(i);
+ if(!specified_logfile) {
+ slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd",
+ dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
}
- i++;
- if (i == MAX_CONNECTIONS)
- i = 1;
- }
-
- if (!used)
- {
- used = !used;
- goto again;
- }
-
- DEBUG(1,("ERROR! Out of connection structures\n"));
- return(-1);
-}
+ pstrcpy(remote_machine, "smbd");
-/****************************************************************************
-reply for the core protocol
-****************************************************************************/
-int reply_corep(char *outbuf)
-{
- int outsize = set_message(outbuf,1,0,True);
+ setup_logging(argv[0],False);
- Protocol = PROTOCOL_CORE;
+ /* we want to re-seed early to prevent time delays causing
+ client problems at a later date. (tridge) */
+ generate_random_buffer(NULL, 0, False);
- return outsize;
-}
+ /* make absolutely sure we run as root - to handle cases where people
+ are crazy enough to have it setuid */
+ gain_root_privilege();
+ gain_root_group_privilege();
-/****************************************************************************
-reply for the coreplus protocol
-****************************************************************************/
-int reply_coreplus(char *outbuf)
-{
- int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
- int outsize = set_message(outbuf,13,0,True);
- SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
- readbraw and writebraw (possibly) */
- CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */
-
- Protocol = PROTOCOL_COREPLUS;
+ fault_setup((void (*)(void *))exit_server);
+ CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
- return outsize;
-}
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
-
-/****************************************************************************
-reply for the lanman 1.0 protocol
-****************************************************************************/
-int reply_lanman1(char *outbuf)
-{
- int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
- int secword=0;
- BOOL doencrypt = SMBENCRYPT();
- time_t t = time(NULL);
-
- if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
-
- set_message(outbuf,13,doencrypt?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
-#ifdef SMB_PASSWD
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- generate_next_challenge(smb_buf(outbuf));
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
#endif
- Protocol = PROTOCOL_LANMAN1;
-
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
+#if defined(SIGUSR2)
+ /* We are no longer interested in USR2 */
+ BlockSignals(True,SIGUSR2);
#endif
- }
- CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_vwv2,maxxmit);
- SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
- SSVAL(outbuf,smb_vwv4,1);
- SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
- readbraw writebraw (possibly) */
- SIVAL(outbuf,smb_vwv6,getpid());
- SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't recieve them. */
+ BlockSignals(False, SIGHUP);
+ BlockSignals(False, SIGUSR1);
- put_dos_date(outbuf,smb_vwv8,t);
-
- return (smb_len(outbuf)+4);
-}
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
+ init_sec_ctx();
-/****************************************************************************
-reply for the lanman 2.0 protocol
-****************************************************************************/
-int reply_lanman2(char *outbuf)
-{
- int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
- int secword=0;
- BOOL doencrypt = SMBENCRYPT();
- time_t t = time(NULL);
-
- if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
-
- set_message(outbuf,13,doencrypt?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
-#ifdef SMB_PASSWD
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- generate_next_challenge(smb_buf(outbuf));
-#endif
+ reopen_logs();
- SIVAL(outbuf,smb_vwv6,getpid());
+ DEBUG(1,( "smbd version %s started.\n", VERSION));
+ DEBUGADD(1,( "Copyright Andrew Tridgell 1992-1998\n"));
- Protocol = PROTOCOL_LANMAN2;
+ DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
+ (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
-#endif
- }
+ /* Output the build options to the debug log */
+ build_options(False);
- CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_vwv2,maxxmit);
- SSVAL(outbuf,smb_vwv3,lp_maxmux());
- SSVAL(outbuf,smb_vwv4,1);
- SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
- SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
- put_dos_date(outbuf,smb_vwv8,t);
-
- return (smb_len(outbuf)+4);
-}
-
-/****************************************************************************
-reply for the nt protocol
-****************************************************************************/
-int reply_nt1(char *outbuf)
-{
- int capabilities=0x300; /* has dual names + lock_and_read */
- int secword=0;
- BOOL doencrypt = SMBENCRYPT();
-
- if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
-
- set_message(outbuf,17,doencrypt?8:0,True);
- CVAL(outbuf,smb_vwv1) = secword;
-#ifdef SMB_PASSWD
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt) {
- generate_next_challenge(smb_buf(outbuf));
- /* Tell the nt machine how long the challenge is. */
- SSVALS(outbuf,smb_vwv16+1,8);
- }
-#endif
-
- SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
-
- Protocol = PROTOCOL_NT1;
-
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
-#endif
- }
-
- if (lp_readraw() && lp_writeraw())
- capabilities |= 1;
-
- SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
- SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
- SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
- SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
- SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
- put_long_date(outbuf+smb_vwv11+1,time(NULL));
- SSVALS(outbuf,smb_vwv15+1,TimeDiff(time(NULL))/60);
-
- return (smb_len(outbuf)+4);
-}
-
-
-/* these are the protocol lists used for auto architecture detection:
-
-WinNT 3.51:
-protocol [PC NETWORK PROGRAM 1.0]
-protocol [XENIX CORE]
-protocol [MICROSOFT NETWORKS 1.03]
-protocol [LANMAN1.0]
-protocol [Windows for Workgroups 3.1a]
-protocol [LM1.2X002]
-protocol [LANMAN2.1]
-protocol [NT LM 0.12]
-
-Win95:
-protocol [PC NETWORK PROGRAM 1.0]
-protocol [XENIX CORE]
-protocol [MICROSOFT NETWORKS 1.03]
-protocol [LANMAN1.0]
-protocol [Windows for Workgroups 3.1a]
-protocol [LM1.2X002]
-protocol [LANMAN2.1]
-protocol [NT LM 0.12]
-
-OS/2:
-protocol [PC NETWORK PROGRAM 1.0]
-protocol [XENIX CORE]
-protocol [LANMAN1.0]
-protocol [LM1.2X002]
-protocol [LANMAN2.1]
-*/
-
-/*
- * Modified to recognize the architecture of the remote machine better.
- *
- * This appears to be the matrix of which protocol is used by which
- * MS product.
- Protocol WfWg Win95 WinNT OS/2
- PC NETWORK PROGRAM 1.0 1 1 1 1
- XENIX CORE 2 2
- MICROSOFT NETWORKS 3.0 2 2
- DOS LM1.2X002 3 3
- MICROSOFT NETWORKS 1.03 3
- DOS LANMAN2.1 4 4
- LANMAN1.0 4 3
- Windows for Workgroups 3.1a 5 5 5
- LM1.2X002 6 4
- LANMAN2.1 7 5
- NT LM 0.12 6 8
- *
- * tim@fsg.com 09/29/95
- */
-
-#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
-#define ARCH_WIN95 0x2
-#define ARCH_OS2 0xC /* Again OS/2 is like NT */
-#define ARCH_WINNT 0x8
-#define ARCH_SAMBA 0x10
-
-#define ARCH_ALL 0x1F
-
-/* List of supported protocols, most desired first */
-struct {
- char *proto_name;
- char *short_name;
- int (*proto_reply_fn)(char *);
- int protocol_level;
-} supported_protocols[] = {
- {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
- {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
- {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
- {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
- {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
- {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
- {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
- {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
- {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
- {NULL,NULL},
-};
-
-
-/****************************************************************************
- reply to a negprot
-****************************************************************************/
-static int reply_negprot(char *inbuf,char *outbuf)
-{
- extern fstring remote_arch;
- int outsize = set_message(outbuf,1,0,True);
- int Index=0;
- int choice= -1;
- int protocol;
- char *p;
- int bcc = SVAL(smb_buf(inbuf),-2);
- int arch = ARCH_ALL;
-
- p = smb_buf(inbuf)+1;
- while (p < (smb_buf(inbuf) + bcc))
- {
- Index++;
- DEBUG(3,("Requested protocol [%s]\n",p));
- if (strcsequal(p,"Windows for Workgroups 3.1a"))
- arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT );
- else if (strcsequal(p,"DOS LM1.2X002"))
- arch &= ( ARCH_WFWG | ARCH_WIN95 );
- else if (strcsequal(p,"DOS LANMAN2.1"))
- arch &= ( ARCH_WFWG | ARCH_WIN95 );
- else if (strcsequal(p,"NT LM 0.12"))
- arch &= ( ARCH_WIN95 | ARCH_WINNT );
- else if (strcsequal(p,"LANMAN2.1"))
- arch &= ( ARCH_WINNT | ARCH_OS2 );
- else if (strcsequal(p,"LM1.2X002"))
- arch &= ( ARCH_WINNT | ARCH_OS2 );
- else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
- arch &= ARCH_WINNT;
- else if (strcsequal(p,"XENIX CORE"))
- arch &= ( ARCH_WINNT | ARCH_OS2 );
- else if (strcsequal(p,"Samba")) {
- arch = ARCH_SAMBA;
- break;
- }
-
- p += strlen(p) + 2;
- }
-
- switch ( arch ) {
- case ARCH_SAMBA:
- strcpy(remote_arch,"Samba");
- break;
- case ARCH_WFWG:
- strcpy(remote_arch,"WfWg");
- break;
- case ARCH_WIN95:
- strcpy(remote_arch,"Win95");
- break;
- case ARCH_WINNT:
- strcpy(remote_arch,"WinNT");
- break;
- case ARCH_OS2:
- strcpy(remote_arch,"OS2");
- break;
- default:
- strcpy(remote_arch,"UNKNOWN");
- break;
- }
-
- /* possibly reload - change of architecture */
- reload_services(True);
-
- /* a special case to stop password server loops */
- if (Index == 1 && strequal(remote_machine,myhostname) &&
- lp_security()==SEC_SERVER)
- exit_server("Password server loop!");
-
- /* Check for protocols, most desirable first */
- for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
- {
- p = smb_buf(inbuf)+1;
- Index = 0;
- if (lp_maxprotocol() >= supported_protocols[protocol].protocol_level)
- while (p < (smb_buf(inbuf) + bcc))
- {
- if (strequal(p,supported_protocols[protocol].proto_name))
- choice = Index;
- Index++;
- p += strlen(p) + 2;
- }
- if(choice != -1)
- break;
- }
-
- SSVAL(outbuf,smb_vwv0,choice);
- if(choice != -1) {
- extern fstring remote_proto;
- strcpy(remote_proto,supported_protocols[protocol].short_name);
- reload_services(True);
- outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
- DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
- }
- else {
- DEBUG(0,("No protocol supported !\n"));
- }
- SSVAL(outbuf,smb_vwv0,choice);
-
- DEBUG(5,("%s negprot index=%d\n",timestring(),choice));
-
- return(outsize);
-}
-
-
-/****************************************************************************
- parse a connect packet
-****************************************************************************/
-void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev)
-{
- char *p = smb_buf(buf) + 1;
- char *p2;
-
- DEBUG(4,("parsing connect string %s\n",p));
-
- p2 = strrchr(p,'\\');
- if (p2 == NULL)
- strcpy(service,p);
- else
- strcpy(service,p2+1);
-
- p += strlen(p) + 2;
-
- strcpy(password,p);
- *pwlen = strlen(password);
-
- p += strlen(p) + 2;
-
- strcpy(dev,p);
-
- *user = 0;
- p = strchr(service,'%');
- if (p != NULL)
- {
- *p = 0;
- strcpy(user,p+1);
- }
-}
-
-
-/****************************************************************************
-close all open files for a connection
-****************************************************************************/
-static void close_open_files(int cnum)
-{
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if( Files[i].cnum == cnum && Files[i].open) {
- close_file(i);
- }
-}
-
-
-
-/****************************************************************************
-close a cnum
-****************************************************************************/
-void close_cnum(int cnum, int uid)
-{
- extern struct from_host Client_info;
-
- DirCacheFlush(SNUM(cnum));
-
- unbecome_user();
-
- if (!OPEN_CNUM(cnum))
- {
- DEBUG(0,("Can't close cnum %d\n",cnum));
- return;
- }
-
- DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
- timestring(),
- Client_info.name,Client_info.addr,
- lp_servicename(SNUM(cnum))));
-
- yield_connection(cnum,
- lp_servicename(SNUM(cnum)),
- lp_max_connections(SNUM(cnum)));
-
- if (lp_status(SNUM(cnum)))
- yield_connection(cnum,"STATUS.",MAXSTATUS);
-
- close_open_files(cnum);
- dptr_closecnum(cnum);
-
- /* execute any "postexec = " line */
- if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid))
- {
- pstring cmd;
- strcpy(cmd,lp_postexec(SNUM(cnum)));
- standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
- unbecome_user();
- }
-
- unbecome_user();
- /* execute any "root postexec = " line */
- if (*lp_rootpostexec(SNUM(cnum)))
- {
- pstring cmd;
- strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
- standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
- }
-
- Connections[cnum].open = False;
- num_connections_open--;
- if (Connections[cnum].ngroups && Connections[cnum].groups)
- {
- if (Connections[cnum].igroups != (int *)Connections[cnum].groups)
- free(Connections[cnum].groups);
- free(Connections[cnum].igroups);
- Connections[cnum].groups = NULL;
- Connections[cnum].igroups = NULL;
- Connections[cnum].ngroups = 0;
- }
-
- string_set(&Connections[cnum].user,"");
- string_set(&Connections[cnum].dirpath,"");
- string_set(&Connections[cnum].connectpath,"");
-}
-
-
-/****************************************************************************
-simple routines to do connection counting
-****************************************************************************/
-BOOL yield_connection(int cnum,char *name,int max_connections)
-{
- struct connect_record crec;
- pstring fname;
- FILE *f;
- int mypid = getpid();
- int i;
-
- DEBUG(3,("Yielding connection to %d %s\n",cnum,name));
-
- if (max_connections <= 0)
- return(True);
-
- bzero(&crec,sizeof(crec));
-
- strcpy(fname,lp_lockdir());
- standard_sub(cnum,fname);
- trim_string(fname,"","/");
-
- strcat(fname,"/");
- strcat(fname,name);
- strcat(fname,".LCK");
-
- f = fopen(fname,"r+");
- if (!f)
- {
- DEBUG(2,("Coudn't open lock file %s (%s)\n",fname,strerror(errno)));
- return(False);
- }
-
- fseek(f,0,SEEK_SET);
-
- /* find a free spot */
- for (i=0;i<max_connections;i++)
- {
- if (fread(&crec,sizeof(crec),1,f) != 1)
- {
- DEBUG(2,("Entry not found in lock file %s\n",fname));
- fclose(f);
- return(False);
+ if (sizeof(uint16) < 2 || sizeof(uint32) < 4) {
+ DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
+ exit(1);
}
- if (crec.pid == mypid && crec.cnum == cnum)
- break;
- }
-
- if (crec.pid != mypid || crec.cnum != cnum)
- {
- fclose(f);
- DEBUG(2,("Entry not found in lock file %s\n",fname));
- return(False);
- }
-
- bzero((void *)&crec,sizeof(crec));
-
- /* remove our mark */
- if (fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
- fwrite(&crec,sizeof(crec),1,f) != 1)
- {
- DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
- fclose(f);
- return(False);
- }
-
- DEBUG(3,("Yield successful\n"));
-
- fclose(f);
- return(True);
-}
-
-/****************************************************************************
-simple routines to do connection counting
-****************************************************************************/
-BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
-{
- struct connect_record crec;
- pstring fname;
- FILE *f;
- int snum = SNUM(cnum);
- int i,foundi= -1;
- int total_recs;
-
- if (max_connections <= 0)
- return(True);
-
- DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
-
- strcpy(fname,lp_lockdir());
- standard_sub(cnum,fname);
- trim_string(fname,"","/");
-
- if (!directory_exist(fname,NULL))
- mkdir(fname,0755);
-
- strcat(fname,"/");
- strcat(fname,name);
- strcat(fname,".LCK");
-
- if (!file_exist(fname,NULL))
- {
- f = fopen(fname,"w");
- if (f) fclose(f);
- }
-
- total_recs = file_size(fname) / sizeof(crec);
-
- f = fopen(fname,"r+");
+ /*
+ * Do this before reload_services.
+ */
- if (!f)
- {
- DEBUG(1,("couldn't open lock file %s\n",fname));
- return(False);
- }
+ if (!reload_services(False))
+ return(-1);
- /* find a free spot */
- for (i=0;i<max_connections;i++)
- {
+ init_structs();
- if (i>=total_recs ||
- fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
- fread(&crec,sizeof(crec),1,f) != 1)
- {
- if (foundi < 0) foundi = i;
- break;
+ /* don't call winbind for our domain if we are the DC */
+ if (lp_domain_logons()) {
+ winbind_exclude_domain(lp_workgroup());
}
-
- if (Clear && crec.pid && !process_exists(crec.pid))
- {
- fseek(f,i*sizeof(crec),SEEK_SET);
- bzero((void *)&crec,sizeof(crec));
- fwrite(&crec,sizeof(crec),1,f);
- if (foundi < 0) foundi = i;
- continue;
- }
- if (foundi < 0 && (!crec.pid || !process_exists(crec.pid)))
- {
- foundi=i;
- if (!Clear) break;
+
+#ifdef WITH_PROFILE
+ if (!profile_setup(False)) {
+ DEBUG(0,("ERROR: failed to setup profiling\n"));
+ return -1;
}
- }
-
- if (foundi < 0)
- {
- DEBUG(3,("no free locks in %s\n",fname));
- fclose(f);
- return(False);
- }
-
- /* fill in the crec */
- bzero((void *)&crec,sizeof(crec));
- crec.magic = 0x280267;
- crec.pid = getpid();
- crec.cnum = cnum;
- crec.uid = Connections[cnum].uid;
- crec.gid = Connections[cnum].gid;
- StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
- crec.start = time(NULL);
-
- {
- extern struct from_host Client_info;
- StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1);
- StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1);
- }
-
- /* make our mark */
- if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
- fwrite(&crec,sizeof(crec),1,f) != 1)
- {
- fclose(f);
- return(False);
- }
-
- fclose(f);
- return(True);
-}
-
-#if DUMP_CORE
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
-static BOOL dump_core(void)
-{
- char *p;
- pstring dname;
- strcpy(dname,debugf);
- if ((p=strrchr(dname,'/'))) *p=0;
- strcat(dname,"/corefiles");
- mkdir(dname,0700);
- sys_chown(dname,getuid(),getgid());
- chmod(dname,0700);
- if (chdir(dname)) return(False);
- umask(~(0700));
-
-#ifndef NO_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit(RLIMIT_CORE, &rlp);
- rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
- setrlimit(RLIMIT_CORE, &rlp);
- getrlimit(RLIMIT_CORE, &rlp);
- DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
- }
-#endif
-#endif
-
-
- DEBUG(0,("Dumping core in %s\n",dname));
- return(True);
-}
-#endif
-
-/****************************************************************************
-exit the server
-****************************************************************************/
-void exit_server(char *reason)
-{
- static int firsttime=1;
- int i;
-
- if (!firsttime) exit(0);
- firsttime = 0;
-
- unbecome_user();
- DEBUG(2,("Closing connections\n"));
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (Connections[i].open)
- close_cnum(i,-1);
-#ifdef DFS_AUTH
- if (dcelogin_atmost_once)
- dfs_unlogin();
-#endif
- if (!reason) {
- int oldlevel = DEBUGLEVEL;
- DEBUGLEVEL = 10;
- DEBUG(0,("Last message was %s\n",smb_fn_name(last_message)));
- if (last_inbuf)
- show_msg(last_inbuf);
- DEBUGLEVEL = oldlevel;
- DEBUG(0,("===============================================================\n"));
-#if DUMP_CORE
- if (dump_core()) return;
-#endif
- }
- DEBUG(3,("%s Server exit (%s)\n",timestring(),reason?reason:""));
- exit(0);
-}
-
-/****************************************************************************
-do some standard substitutions in a string
-****************************************************************************/
-void standard_sub(int cnum,char *s)
-{
- if (!strchr(s,'%')) return;
-
- if (VALID_CNUM(cnum))
- {
- string_sub(s,"%S",lp_servicename(Connections[cnum].service));
- string_sub(s,"%P",Connections[cnum].connectpath);
- string_sub(s,"%u",Connections[cnum].user);
- if (strstr(s,"%H")) {
- char *home = get_home_dir(Connections[cnum].user);
- if (home) string_sub(s,"%H",home);
- }
- string_sub(s,"%g",gidtoname(Connections[cnum].gid));
- }
- standard_sub_basic(s);
-}
-
-/*
-These flags determine some of the permissions required to do an operation
-
-Note that I don't set NEED_WRITE on some write operations because they
-are used by some brain-dead clients when printing, and I don't want to
-force write permissions on print services.
-*/
-#define AS_USER (1<<0)
-#define NEED_WRITE (1<<1)
-#define TIME_INIT (1<<2)
-#define CAN_IPC (1<<3)
-#define AS_GUEST (1<<5)
-
-
-/*
- define a list of possible SMB messages and their corresponding
- functions. Any message that has a NULL function is unimplemented -
- please feel free to contribute implementations!
-*/
-struct smb_message_struct
-{
- int code;
- char *name;
- int (*fn)();
- int flags;
-#if PROFILING
- unsigned long time;
-#endif
-}
- smb_messages[] = {
-
- /* CORE PROTOCOL */
-
- {SMBnegprot,"SMBnegprot",reply_negprot,0},
- {SMBtcon,"SMBtcon",reply_tcon,0},
- {SMBtdis,"SMBtdis",reply_tdis,0},
- {SMBexit,"SMBexit",reply_exit,0},
- {SMBioctl,"SMBioctl",reply_ioctl,0},
- {SMBecho,"SMBecho",reply_echo,0},
- {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0},
- {SMBtconX,"SMBtconX",reply_tcon_and_X,0},
- {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0},
- {SMBgetatr,"SMBgetatr",reply_getatr,AS_USER},
- {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
- {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
- {SMBsearch,"SMBsearch",reply_search,AS_USER},
- {SMBopen,"SMBopen",reply_open,AS_USER},
-
- /* note that SMBmknew and SMBcreate are deliberately overloaded */
- {SMBcreate,"SMBcreate",reply_mknew,AS_USER},
- {SMBmknew,"SMBmknew",reply_mknew,AS_USER},
-
- {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
- {SMBread,"SMBread",reply_read,AS_USER},
- {SMBwrite,"SMBwrite",reply_write,AS_USER},
- {SMBclose,"SMBclose",reply_close,AS_USER},
- {SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
- {SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
- {SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
- {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
-
- /* this is a Pathworks specific call, allowing the
- changing of the root path */
- {pSETDIR,"pSETDIR",reply_setdir,AS_USER},
-
- {SMBlseek,"SMBlseek",reply_lseek,AS_USER},
- {SMBflush,"SMBflush",reply_flush,AS_USER},
- {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
- {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
- {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
- {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER},
- {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
- {SMBlock,"SMBlock",reply_lock,AS_USER},
- {SMBunlock,"SMBunlock",reply_unlock,AS_USER},
-
- /* CORE+ PROTOCOL FOLLOWS */
-
- {SMBreadbraw,"SMBreadbraw",reply_readbraw,AS_USER},
- {SMBwritebraw,"SMBwritebraw",reply_writebraw,AS_USER},
- {SMBwriteclose,"SMBwriteclose",reply_writeclose,AS_USER},
- {SMBlockread,"SMBlockread",reply_lockread,AS_USER},
- {SMBwriteunlock,"SMBwriteunlock",reply_writeunlock,AS_USER},
-
- /* LANMAN1.0 PROTOCOL FOLLOWS */
-
- {SMBreadBmpx,"SMBreadBmpx",reply_readbmpx,AS_USER},
- {SMBreadBs,"SMBreadBs",NULL,AS_USER},
- {SMBwriteBmpx,"SMBwriteBmpx",reply_writebmpx,AS_USER},
- {SMBwriteBs,"SMBwriteBs",reply_writebs,AS_USER},
- {SMBwritec,"SMBwritec",NULL,AS_USER},
- {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE},
- {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER},
- {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
- {SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
- {SMBioctls,"SMBioctls",NULL,AS_USER},
- {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
- {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
-
- {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER},
- {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
- {SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
- {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
-
- {SMBffirst,"SMBffirst",reply_search,AS_USER},
- {SMBfunique,"SMBfunique",reply_search,AS_USER},
- {SMBfclose,"SMBfclose",reply_fclose,AS_USER},
-
- /* LANMAN2.0 PROTOCOL FOLLOWS */
- {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
- {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
- {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
- {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
-
- /* messaging routines */
- {SMBsends,"SMBsends",reply_sends,AS_GUEST},
- {SMBsendstrt,"SMBsendstrt",reply_sendstrt,AS_GUEST},
- {SMBsendend,"SMBsendend",reply_sendend,AS_GUEST},
- {SMBsendtxt,"SMBsendtxt",reply_sendtxt,AS_GUEST},
-
- /* NON-IMPLEMENTED PARTS OF THE CORE PROTOCOL */
-
- {SMBsendb,"SMBsendb",NULL,AS_GUEST},
- {SMBfwdname,"SMBfwdname",NULL,AS_GUEST},
- {SMBcancelf,"SMBcancelf",NULL,AS_GUEST},
- {SMBgetmac,"SMBgetmac",NULL,AS_GUEST}
- };
-
-/****************************************************************************
-return a string containing the function name of a SMB command
-****************************************************************************/
-char *smb_fn_name(int type)
-{
- static char *unknown_name = "SMBunknown";
- static int num_smb_messages =
- sizeof(smb_messages) / sizeof(struct smb_message_struct);
- int match;
-
- for (match=0;match<num_smb_messages;match++)
- if (smb_messages[match].code == type)
- break;
-
- if (match == num_smb_messages)
- return(unknown_name);
-
- return(smb_messages[match].name);
-}
-
-
-/****************************************************************************
-do a switch on the message type, and return the response size
-****************************************************************************/
-static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
-{
- static int pid= -1;
- int outsize = 0;
- static int num_smb_messages =
- sizeof(smb_messages) / sizeof(struct smb_message_struct);
- int match;
-
-#if PROFILING
- struct timeval msg_start_time;
- struct timeval msg_end_time;
- static unsigned long total_time = 0;
-
- GetTimeOfDay(&msg_start_time);
#endif
- if (pid == -1)
- pid = getpid();
-
- errno = 0;
- last_message = type;
-
- /* make sure this is an SMB packet */
- if (strncmp(smb_base(inbuf),"\377SMB",4) != 0)
- {
- DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
- return(-1);
- }
-
- for (match=0;match<num_smb_messages;match++)
- if (smb_messages[match].code == type)
- break;
-
- if (match == num_smb_messages)
- {
- DEBUG(0,("Unknown message type %d!\n",type));
- outsize = reply_unknown(inbuf,outbuf);
- }
- else
- {
- DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
- if (smb_messages[match].fn)
+#ifdef WITH_SSL
{
- int cnum = SVAL(inbuf,smb_tid);
- int flags = smb_messages[match].flags;
- int uid = SVAL(inbuf,smb_uid);
-
- /* does this protocol need to be run as root? */
- if (!(flags & AS_USER))
- unbecome_user();
-
- /* does this protocol need to be run as the connected user? */
- if ((flags & AS_USER) && !become_user(cnum,uid))
- return(ERROR(ERRSRV,ERRinvnid));
-
- /* does it need write permission? */
- if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
- return(ERROR(ERRSRV,ERRaccess));
-
- /* ipc services are limited */
- if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC))
- return(ERROR(ERRSRV,ERRaccess));
-
- /* load service specific parameters */
- if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False))
- return(ERROR(ERRSRV,ERRaccess));
-
- /* does this protocol need to be run as guest? */
- if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1)))
- return(ERROR(ERRSRV,ERRaccess));
-
- last_inbuf = inbuf;
-
- outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
+ extern BOOL sslEnabled;
+ sslEnabled = lp_ssl_enabled();
+ if(sslEnabled)
+ sslutil_init(True);
}
- else
- {
- outsize = reply_unknown(inbuf,outbuf);
- }
- }
-
-#if PROFILING
- GetTimeOfDay(&msg_end_time);
- if (!(smb_messages[match].flags & TIME_INIT))
- {
- smb_messages[match].time = 0;
- smb_messages[match].flags |= TIME_INIT;
- }
- {
- unsigned long this_time =
- (msg_end_time.tv_sec - msg_start_time.tv_sec)*1e6 +
- (msg_end_time.tv_usec - msg_start_time.tv_usec);
- smb_messages[match].time += this_time;
- total_time += this_time;
- }
- DEBUG(2,("TIME %s %d usecs %g pct\n",
- smb_fn_name(type),smb_messages[match].time,
- (100.0*smb_messages[match].time) / total_time));
-#endif
-
- return(outsize);
-}
-
-
-/****************************************************************************
-construct a chained reply and add it to the already made reply
-
-inbuf points to the original message start.
-inbuf2 points to the smb_wct part of the secondary message
-type is the type of the secondary message
-outbuf points to the original outbuffer
-outbuf2 points to the smb_wct field of the new outbuffer
-size is the total length of the incoming message (from inbuf1)
-bufsize is the total buffer size
-
-return how many bytes were added to the response
-****************************************************************************/
-int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize)
-{
- int outsize = 0;
- char *ibuf,*obuf;
- static BOOL in_chain = False;
- static char *last_outbuf=NULL;
- BOOL was_inchain = in_chain;
- int insize_remaining;
- static int insize_deleted;
-
-
- chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct;
- if (was_inchain)
- outbuf = last_outbuf;
- else
- insize_deleted = 0;
-
-
- insize_deleted = 0;
- inbuf2 -= insize_deleted;
- insize_remaining = size - PTR_DIFF(inbuf2,inbuf);
- insize_deleted += size - (insize_remaining + smb_wct);
-
- in_chain = True;
- last_outbuf = outbuf;
-
-
- /* allocate some space for the in and out buffers of the chained message */
- ibuf = (char *)malloc(size + SAFETY_MARGIN);
- obuf = (char *)malloc(bufsize + SAFETY_MARGIN);
-
- if (!ibuf || !obuf)
- {
- DEBUG(0,("Out of memory in chain reply\n"));
- return(ERROR(ERRSRV,ERRnoresource));
- }
-
- ibuf += SMB_ALIGNMENT;
- obuf += SMB_ALIGNMENT;
-
- /* create the in buffer */
- memcpy(ibuf,inbuf,smb_wct);
- memcpy(ibuf+smb_wct,inbuf2,insize_remaining);
- CVAL(ibuf,smb_com) = type;
+#endif /* WITH_SSL */
- /* create the out buffer */
- bzero(obuf,smb_size);
-
- set_message(obuf,0,0,True);
- CVAL(obuf,smb_com) = CVAL(ibuf,smb_com);
-
- memcpy(obuf+4,ibuf+4,4);
- CVAL(obuf,smb_rcls) = SUCCESS;
- CVAL(obuf,smb_reh) = 0;
- CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set
- means a reply */
- SSVAL(obuf,smb_flg2,1); /* say we support long filenames */
- SSVAL(obuf,smb_err,SUCCESS);
- SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid));
- SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid));
- SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid));
- SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid));
-
- DEBUG(3,("Chained message\n"));
- show_msg(ibuf);
-
- /* process the request */
- outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining,
- bufsize-chain_size);
-
- /* copy the new reply header over the old one, but preserve
- the smb_com field */
- memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1));
-
- /* and copy the data from the reply to the right spot */
- memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
-
- /* free the allocated buffers */
- if (ibuf) free(ibuf-SMB_ALIGNMENT);
- if (obuf) free(obuf-SMB_ALIGNMENT);
-
- in_chain = was_inchain;
-
- /* return how much extra has been added to the packet */
- return(outsize - smb_wct);
-}
-
-
-
-/****************************************************************************
- construct a reply to the incoming packet
-****************************************************************************/
-int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
-{
- int type = CVAL(inbuf,smb_com);
- int outsize = 0;
- int msg_type = CVAL(inbuf,0);
-
- smb_last_time = time(NULL);
-
- chain_size = 0;
-
- bzero(outbuf,smb_size);
-
- if (msg_type != 0)
- return(reply_special(inbuf,outbuf));
-
- CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
- set_message(outbuf,0,0,True);
-
- memcpy(outbuf+4,inbuf+4,4);
- CVAL(outbuf,smb_rcls) = SUCCESS;
- CVAL(outbuf,smb_reh) = 0;
- CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set
- means a reply */
- SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
- SSVAL(outbuf,smb_err,SUCCESS);
- SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
- SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
- SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
- SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
-
- outsize = switch_message(type,inbuf,outbuf,size,bufsize);
-
- if(outsize > 4)
- smb_setlen(outbuf,outsize - 4);
- return(outsize);
-}
+ fstrcpy(global_myworkgroup, lp_workgroup());
+ CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
+
+ DEBUG(3,( "loaded services\n"));
-/****************************************************************************
- process commands from the client
-****************************************************************************/
-void process(void )
-{
- static int trans_num = 0;
- int nread;
- extern struct from_host Client_info;
- extern int Client;
-
- fromhost(Client,&Client_info);
-
- InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if ((InBuffer == NULL) || (OutBuffer == NULL))
- return;
-
- InBuffer += SMB_ALIGNMENT;
- OutBuffer += SMB_ALIGNMENT;
-
-#if PRIME_NMBD
- DEBUG(3,("priming nmbd\n"));
- {
- struct in_addr ip;
- ip = *interpret_addr2("localhost");
- if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
- *OutBuffer = 0;
- send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM);
- }
-#endif
-
- last_user.cnum = -1;
-
- while (True)
- {
- int32 len;
- int msg_type;
- int msg_flags;
- int type;
- int deadtime = lp_deadtime()*60;
- int counter;
- int last_keepalive=0;
-
- if (deadtime <= 0)
- deadtime = DEFAULT_SMBD_TIMEOUT;
-
- if (lp_readprediction())
- do_read_prediction();
-
- {
- extern pstring share_del_pending;
- if (*share_del_pending) {
- unbecome_user();
- if (!unlink(share_del_pending))
- DEBUG(3,("Share file deleted %s\n",share_del_pending));
- else
- DEBUG(2,("Share del failed of %s\n",share_del_pending));
- share_del_pending[0] = 0;
+ if (!is_daemon && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
}
- }
-
- if (share_mode_pending) {
- unbecome_user();
- check_share_modes();
- share_mode_pending=False;
- }
-
- errno = 0;
- for (counter=SMBD_SELECT_LOOP;
- !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000);
- counter += SMBD_SELECT_LOOP)
- {
- int i;
- time_t t;
- BOOL allidle = True;
- extern int keepalive;
-
- /* check for socket failure */
- if (errno == EBADF) {
- DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
- return;
- }
-
- t = time(NULL);
-
- /* become root again if waiting */
- unbecome_user();
-
- /* check for smb.conf reload */
- if (!(counter%SMBD_RELOAD_CHECK))
- reload_services(True);
-
- /* check the share modes every 10 secs */
- if (!(counter%SHARE_MODES_CHECK))
- check_share_modes();
-
- /* clean the share modes every 5 minutes */
- if (!(counter%SHARE_MODES_CLEAN))
- clean_share_files();
-
- /* automatic timeout if all connections are closed */
- if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
- DEBUG(2,("%s Closing idle connection\n",timestring()));
- return;
- }
-
- if (keepalive && (counter-last_keepalive)>keepalive) {
- if (!send_keepalive(Client)) {
- DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
- return;
- }
- last_keepalive = counter;
- }
-
- /* check for connection timeouts */
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (Connections[i].open)
- {
- /* close dirptrs on connections that are idle */
- if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
- dptr_idlecnum(i);
-
- if (Connections[i].num_files_open > 0 ||
- (t-Connections[i].lastused)<deadtime)
- allidle = False;
- }
-
- if (allidle && num_connections_open>0) {
- DEBUG(2,("%s Closing idle connection 2\n",timestring()));
- return;
- }
+ if (is_daemon) {
+ DEBUG( 3, ( "Becoming a daemon.\n" ) );
+ become_daemon();
}
- msg_type = CVAL(InBuffer,0);
- msg_flags = CVAL(InBuffer,1);
- type = CVAL(InBuffer,smb_com);
-
- len = smb_len(InBuffer);
-
- DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
-
- nread = len + 4;
-
- DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
-
-#ifdef WITH_VTP
- if(trans_num == 1 && VT_Check(InBuffer)) {
- VT_Process();
- return;
- }
-#endif
-
-
- if (msg_type == 0)
- show_msg(InBuffer);
-
- nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit);
-
- if(nread > 0) {
- if (CVAL(OutBuffer,0) == 0)
- show_msg(OutBuffer);
-
- if (nread != smb_len(OutBuffer) + 4)
- {
- DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
- nread,
- smb_len(OutBuffer)));
- }
- else
- send_smb(Client,OutBuffer);
- }
- trans_num++;
- }
-}
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+ if (is_daemon) {
+ pidfile_create("smbd");
+ }
-/****************************************************************************
- initialise connect, service and file structs
-****************************************************************************/
-static void init_structs(void )
-{
- int i;
- get_myname(myhostname,&myip);
-
- for (i=0;i<MAX_CONNECTIONS;i++)
- {
- Connections[i].open = False;
- Connections[i].num_files_open=0;
- Connections[i].lastused=0;
- Connections[i].used=False;
- string_init(&Connections[i].user,"");
- string_init(&Connections[i].dirpath,"");
- string_init(&Connections[i].connectpath,"");
- string_init(&Connections[i].origpath,"");
- }
-
- for (i=0;i<MAX_OPEN_FILES;i++)
- {
- Files[i].open = False;
- string_init(&Files[i].name,"");
- }
-
- init_dptrs();
-}
+ if (!message_init()) {
+ exit(1);
+ }
-/****************************************************************************
-usage on the program
-****************************************************************************/
-void usage(char *pname)
-{
- DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
-
- printf("Usage: %s [-D] [-p port] [-d debuglevel] [-l log basename] [-s services file]\n",pname);
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
- printf("\t-l log basename. Basename for log/debug files\n");
- printf("\t-s services file. Filename of services file\n");
- printf("\t-P passive only\n");
- printf("\t-a overwrite log file, don't append\n");
- printf("\n");
-}
+ /* Setup the main smbd so that we can get messages. */
+ claim_connection(NULL,"",MAXSTATUS,True);
+ /*
+ DO NOT ENABLE THIS TILL YOU COPE WITH KILLING THESE TASKS AND INETD
+ THIS *killed* LOTS OF BUILD FARM MACHINES. IT CREATED HUNDREDS OF
+ smbd PROCESSES THAT NEVER DIE
+ start_background_queue();
+ */
-/****************************************************************************
- main program
-****************************************************************************/
-int main(int argc,char *argv[])
-{
- extern BOOL append_log;
- /* shall I run as a daemon */
- BOOL is_daemon = False;
- int port = 139;
- int opt;
- extern char *optarg;
-
-#ifdef NEED_AUTH_PARAMETERS
- set_auth_parameters(argc,argv);
-#endif
+ if (!open_sockets(is_daemon,port))
+ exit(1);
-#ifdef SecureWare
- setluid(0);
-#endif
+ /*
+ * everything after this point is run after the fork()
+ */
- append_log = True;
+ if (!locking_init(0)) {
+ exit(1);
+ }
- TimeInit();
+ if (!print_backend_init()) {
+ exit(1);
+ }
- strcpy(debugf,SMBLOGFILE);
+ if (!share_info_db_init()) {
+ exit(1);
+ }
- setup_logging(argv[0],False);
+ if(!initialize_password_db(False)) {
+ exit(1);
+ }
- charset_initialise();
+ /* possibly reload the services file. */
+ reload_services(True);
- /* make absolutely sure we run as root - to handle cases whre people
- are crazy enough to have it setuid */
-#ifdef USE_SETRES
- setresuid(0,0,0);
-#else
- setuid(0);
- seteuid(0);
- setuid(0);
- seteuid(0);
-#endif
+ if(!pdb_generate_sam_sid()) {
+ DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
+ exit(1);
+ }
- fault_setup(exit_server);
+ if (!init_group_mapping()) {
+ DEBUG(0,("Could not open tdb mapping file.\n"));
+ return 0;
+ }
- umask(0777 & ~DEF_CREATE_MASK);
+ if (!init_account_policy()) {
+ DEBUG(0,("Could not open account policy tdb.\n"));
+ exit(1);
+ }
- initial_uid = geteuid();
- initial_gid = getegid();
+ if (*lp_rootdir()) {
+ if (sys_chroot(lp_rootdir()) == 0)
+ DEBUG(2,("Changed root to %s\n", lp_rootdir()));
+ }
- if (initial_gid != 0 && initial_uid == 0)
- {
-#ifdef HPUX
- setresgid(0,0,0);
-#else
- setgid(0);
- setegid(0);
-#endif
- }
-
- initial_uid = geteuid();
- initial_gid = getegid();
-
-
- /* this is for people who can't start the program correctly */
- while (argc > 1 && (*argv[1] != '-'))
- {
- argv++;
- argc--;
- }
-
- while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPa")) != EOF)
- switch (opt)
- {
- case 'O':
- strcpy(user_socket_options,optarg);
- break;
- case 'i':
- strcpy(scope,optarg);
- break;
- case 'P':
- {
- extern BOOL passive;
- passive = True;
+ /* Setup oplocks */
+ if (!init_oplocks()) {
+ exit(1);
}
- break;
- case 's':
- strcpy(servicesf,optarg);
- break;
- case 'l':
- strcpy(debugf,optarg);
- break;
- case 'a':
- {
- extern BOOL append_log;
- append_log = !append_log;
+
+ /* Setup mangle */
+ if (!init_mangle_tdb()) {
+ exit(1);
}
- break;
- case 'D':
- is_daemon = True;
- break;
- case 'd':
- if (*optarg == 'A')
- DEBUGLEVEL = 10000;
- else
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'h':
- usage(argv[0]);
- exit(0);
- break;
- default:
- usage(argv[0]);
- exit(1);
- }
-
- reopen_logs();
-
- DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
- DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
-
- GetWd(OriginalDir);
-
-#ifndef NO_GETRLIMIT
-#ifdef RLIMIT_NOFILE
- {
- struct rlimit rlp;
- getrlimit(RLIMIT_NOFILE, &rlp);
- rlp.rlim_cur = (MAX_OPEN_FILES>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES;
- setrlimit(RLIMIT_NOFILE, &rlp);
- getrlimit(RLIMIT_NOFILE, &rlp);
- DEBUG(3,("Maximum number of open files per session is %d\n",rlp.rlim_cur));
- }
-#endif
-#endif
-
-
- DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
- getuid(),getgid(),geteuid(),getegid()));
-
- if (sizeof(uint16) < 2 || sizeof(uint32) < 4)
- {
- DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
- exit(1);
- }
-
- init_structs();
-
- if (!reload_services(False))
- return(-1);
-#ifndef NO_SIGNAL_TEST
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
-
- DEBUG(3,("%s loaded services\n",timestring()));
-
- if (!is_daemon && !is_a_socket(0))
- {
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
- is_daemon = True;
- }
-
- if (is_daemon)
- {
- DEBUG(3,("%s becoming a daemon\n",timestring()));
- become_daemon();
- }
-
- if (open_sockets(is_daemon,port))
- {
- /* possibly reload the services file. */
- reload_services(True);
-
- maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
-
- if (*lp_rootdir())
- {
- if (sys_chroot(lp_rootdir()) == 0)
- DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
+ /* Setup change notify */
+ if (!init_change_notify()) {
+ exit(1);
}
- process();
- close_sockets();
- }
- exit_server("normal exit");
- return(0);
+ smbd_process();
+
+ exit_server("normal exit");
+ return(0);
}
-
-
diff --git a/source/smbd/service.c b/source/smbd/service.c
new file mode 100644
index 00000000000..49fbee2607d
--- /dev/null
+++ b/source/smbd/service.c
@@ -0,0 +1,742 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ service (connection) opening and closing
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern struct timeval smb_last_time;
+extern int case_default;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
+extern BOOL case_mangle;
+extern BOOL case_sensitive;
+extern BOOL use_mangled_map;
+extern fstring remote_machine;
+extern userdom_struct current_user_info;
+extern fstring remote_machine;
+
+
+/****************************************************************************
+ Load parameters specific to a connection/service.
+****************************************************************************/
+
+BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
+{
+ extern char magic_char;
+ static connection_struct *last_conn;
+ int snum;
+
+ if (!conn) {
+ last_conn = NULL;
+ return(False);
+ }
+
+ conn->lastused = smb_last_time.tv_sec;
+
+ snum = SNUM(conn);
+
+ if (do_chdir &&
+ vfs_ChDir(conn,conn->connectpath) != 0 &&
+ vfs_ChDir(conn,conn->origpath) != 0) {
+ DEBUG(0,("chdir (%s) failed\n",
+ conn->connectpath));
+ return(False);
+ }
+
+ if (conn == last_conn)
+ return(True);
+
+ last_conn = conn;
+
+ case_default = lp_defaultcase(snum);
+ case_preserve = lp_preservecase(snum);
+ short_case_preserve = lp_shortpreservecase(snum);
+ case_mangle = lp_casemangle(snum);
+ case_sensitive = lp_casesensitive(snum);
+ magic_char = lp_magicchar(snum);
+ use_mangled_map = (*lp_mangled_map(snum) ? True:False);
+ return(True);
+}
+
+/****************************************************************************
+ Add a home service. Returns the new service number or -1 if fail.
+****************************************************************************/
+
+int add_home_service(const char *service, const char *homedir)
+{
+ int iHomeService;
+ int iService;
+ fstring new_service;
+ char *usr_p = NULL;
+
+ if (!service || !homedir)
+ return -1;
+
+ if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
+ return -1;
+
+ /*
+ * If this is a winbindd provided username, remove
+ * the domain component before adding the service.
+ * Log a warning if the "path=" parameter does not
+ * include any macros.
+ */
+
+ fstrcpy(new_service, service);
+
+ if ((usr_p = strchr_m(service,*lp_winbind_separator())) != NULL)
+ fstrcpy(new_service, usr_p+1);
+
+ lp_add_home(new_service,iHomeService,homedir);
+ iService = lp_servicenumber(new_service);
+
+ return iService;
+}
+
+/****************************************************************************
+ Find a service entry. service is always in dos codepage.
+****************************************************************************/
+
+int find_service(char *service)
+{
+ int iService;
+
+ all_string_sub(service,"\\","/",0);
+
+ iService = lp_servicenumber(service);
+
+ /* now handle the special case of a home directory */
+ if (iService < 0)
+ {
+ char *phome_dir = get_user_home_dir(service);
+
+ if(!phome_dir)
+ {
+ /*
+ * Try mapping the servicename, it may
+ * be a Windows to unix mapped user name.
+ */
+ if(map_username(service))
+ phome_dir = get_user_home_dir(service);
+ }
+
+ DEBUG(3,("checking for home directory %s gave %s\n",service,
+ phome_dir?phome_dir:"(NULL)"));
+
+ iService = add_home_service(service,phome_dir);
+ }
+
+ /* If we still don't have a service, attempt to add it as a printer. */
+ if (iService < 0)
+ {
+ int iPrinterService;
+
+ if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
+ {
+ char *pszTemp;
+
+ DEBUG(3,("checking whether %s is a valid printer name...\n", service));
+ pszTemp = PRINTCAP;
+ if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
+ {
+ DEBUG(3,("%s is a valid printer name\n", service));
+ DEBUG(3,("adding %s as a printer service\n", service));
+ lp_add_printer(service,iPrinterService);
+ iService = lp_servicenumber(service);
+ if (iService < 0)
+ DEBUG(0,("failed to add %s as a printer service!\n", service));
+ }
+ else
+ DEBUG(3,("%s is not a valid printer name\n", service));
+ }
+ }
+
+ /* Check for default vfs service? Unsure whether to implement this */
+ if (iService < 0)
+ {
+ }
+
+ /* just possibly it's a default service? */
+ if (iService < 0)
+ {
+ char *pdefservice = lp_defaultservice();
+ if (pdefservice && *pdefservice &&
+ !strequal(pdefservice,service) &&
+ !strstr(service,".."))
+ {
+ /*
+ * We need to do a local copy here as lp_defaultservice()
+ * returns one of the rotating lp_string buffers that
+ * could get overwritten by the recursive find_service() call
+ * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
+ */
+ pstring defservice;
+ pstrcpy(defservice, pdefservice);
+ iService = find_service(defservice);
+ if (iService >= 0)
+ {
+ all_string_sub(service,"_","/",0);
+ iService = lp_add_service(service,iService);
+ }
+ }
+ }
+
+ if (iService >= 0)
+ if (!VALID_SNUM(iService))
+ {
+ DEBUG(0,("Invalid snum %d for %s\n",iService,service));
+ iService = -1;
+ }
+
+ if (iService < 0)
+ DEBUG(3,("find_service() failed to find service %s\n", service));
+
+ return (iService);
+}
+
+
+/****************************************************************************
+ do some basic sainity checks on the share.
+ This function modifies dev, ecode.
+****************************************************************************/
+static NTSTATUS share_sanity_checks(int snum, char* service, char *dev)
+{
+
+ if (!lp_snum_ok(snum) ||
+ !check_access(smbd_server_fd(),
+ lp_hostsallow(snum), lp_hostsdeny(snum))) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* you can only connect to the IPC$ service as an ipc device */
+ if (strequal(service,"IPC$") || strequal(service,"ADMIN$"))
+ pstrcpy(dev,"IPC");
+
+ if (*dev == '?' || !*dev) {
+ if (lp_print_ok(snum)) {
+ pstrcpy(dev,"LPT1:");
+ } else {
+ pstrcpy(dev,"A:");
+ }
+ }
+
+ /* if the request is as a printer and you can't print then refuse */
+ strupper(dev);
+ if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
+ DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
+ return NT_STATUS_BAD_DEVICE_TYPE;
+ }
+
+ /* Behave as a printer if we are supposed to */
+ if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
+ pstrcpy(dev, "LPT1:");
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ readonly share?
+****************************************************************************/
+static void set_read_only(connection_struct *conn)
+{
+ char **list;
+ char *service = lp_servicename(conn->service);
+ conn->read_only = lp_readonly(conn->service);
+
+ if (!service) return;
+
+ lp_list_copy(&list, lp_readlist(conn->service));
+ if (list) {
+ if (!lp_list_substitute(list, "%S", service)) {
+ DEBUG(0, ("ERROR: read list substitution failed\n"));
+ }
+ if (user_in_list(conn->user, list))
+ conn->read_only = True;
+ lp_list_free(&list);
+ }
+
+ lp_list_copy(&list, lp_writelist(conn->service));
+ if (list) {
+ if (!lp_list_substitute(list, "%S", service)) {
+ DEBUG(0, ("ERROR: write list substitution failed\n"));
+ }
+ if (user_in_list(conn->user, list))
+ conn->read_only = False;
+ lp_list_free(&list);
+ }
+}
+
+
+/****************************************************************************
+ admin user check
+****************************************************************************/
+static void set_admin_user(connection_struct *conn)
+{
+ /* admin user check */
+
+ /* JRA - original code denied admin user if the share was
+ marked read_only. Changed as I don't think this is needed,
+ but old code left in case there is a problem here.
+ */
+ if (user_in_list(conn->user,lp_admin_users(conn->service))
+#if 0
+ && !conn->read_only
+#endif
+ ) {
+ conn->admin_user = True;
+ DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
+ } else {
+ conn->admin_user = False;
+ }
+
+#if 0 /* This done later, for now */
+ /* admin users always run as uid=0 */
+ if (conn->admin_user) {
+ conn->uid = 0;
+ }
+#endif
+}
+
+/****************************************************************************
+ Make a connection to a service.
+****************************************************************************/
+
+connection_struct *make_connection(char *service, DATA_BLOB password,
+ char *dev,uint16 vuid, NTSTATUS *status)
+{
+ int snum;
+ struct passwd *pass = NULL;
+ BOOL guest = False;
+ BOOL force = False;
+ connection_struct *conn;
+ uid_t euid;
+
+ fstring user;
+ ZERO_STRUCT(user);
+
+ /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
+ if (!non_root_mode() && (euid = geteuid()) != 0) {
+ DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
+ smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
+ }
+
+ strlower(service);
+
+ snum = find_service(service);
+
+ if (snum < 0) {
+ if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
+ DEBUG(3,("refusing IPC connection\n"));
+ *status = NT_STATUS_ACCESS_DENIED;
+ return NULL;
+ }
+
+ DEBUG(0,("%s (%s) couldn't find service %s\n",
+ remote_machine, client_addr(), service));
+ *status = NT_STATUS_BAD_NETWORK_PATH;
+ return NULL;
+ }
+
+ if (strequal(service,HOMES_NAME)) {
+ if(lp_security() != SEC_SHARE) {
+ if (validated_username(vuid)) {
+ fstring unix_username;
+ fstrcpy(unix_username,validated_username(vuid));
+ return(make_connection(unix_username,password,dev,vuid,status));
+ }
+ } else {
+ /* Security = share. Try with current_user_info.smb_name
+ * as the username. */
+ if(*current_user_info.smb_name) {
+ fstring unix_username;
+ fstrcpy(unix_username,current_user_info.smb_name);
+ map_username(unix_username);
+ return(make_connection(unix_username,password,dev,vuid,status));
+ }
+ }
+ }
+
+ if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, service, dev))) {
+ return NULL;
+ }
+
+ /* add it as a possible user name if we
+ are in share mode security */
+ if (lp_security() == SEC_SHARE) {
+ add_session_user(service);
+ }
+
+
+ /* shall we let them in? */
+ if (!authorise_login(snum,user,password,&guest,&force,vuid)) {
+ DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
+ *status = NT_STATUS_WRONG_PASSWORD;
+ return NULL;
+ }
+
+ add_session_user(user);
+
+ conn = conn_new();
+ if (!conn) {
+ DEBUG(0,("Couldn't find free connection.\n"));
+ *status = NT_STATUS_INSUFFICIENT_RESOURCES;
+ return NULL;
+ }
+
+ /* find out some info about the user */
+ pass = smb_getpwnam(user,True);
+
+ if (pass == NULL) {
+ DEBUG(0,( "Couldn't find account %s\n",user));
+ *status = NT_STATUS_NO_SUCH_USER;
+ conn_free(conn);
+ return NULL;
+ }
+
+ conn->force_user = force;
+ conn->vuid = vuid;
+ conn->uid = pass->pw_uid;
+ conn->gid = pass->pw_gid;
+ safe_strcpy(conn->client_address, client_addr(),
+ sizeof(conn->client_address)-1);
+ conn->num_files_open = 0;
+ conn->lastused = time(NULL);
+ conn->service = snum;
+ conn->used = True;
+ conn->printer = (strncmp(dev,"LPT",3) == 0);
+ conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
+ conn->dirptr = NULL;
+ conn->veto_list = NULL;
+ conn->hide_list = NULL;
+ conn->veto_oplock_list = NULL;
+ string_set(&conn->dirpath,"");
+ string_set(&conn->user,user);
+ conn->nt_user_token = NULL;
+
+ set_read_only(conn);
+
+ set_admin_user(conn);
+
+ /*
+ * If force user is true, then store the
+ * given userid and also the primary groupid
+ * of the user we're forcing.
+ */
+
+ if (*lp_force_user(snum)) {
+ struct passwd *pass2;
+ pstring fuser;
+ pstrcpy(fuser,lp_force_user(snum));
+
+ /* Allow %S to be used by force user. */
+ pstring_sub(fuser,"%S",service);
+
+ pass2 = (struct passwd *)Get_Pwnam_Modify(fuser);
+ if (pass2) {
+ conn->uid = pass2->pw_uid;
+ conn->gid = pass2->pw_gid;
+ string_set(&conn->user,fuser);
+ fstrcpy(user,fuser);
+ conn->force_user = True;
+ DEBUG(3,("Forced user %s\n",fuser));
+ } else {
+ DEBUG(1,("Couldn't find user %s\n",fuser));
+ }
+ }
+
+ /* admin users always run as uid=0 */
+ if (conn->admin_user) {
+ conn->uid = 0;
+ }
+
+#ifdef HAVE_GETGRNAM
+ /*
+ * If force group is true, then override
+ * any groupid stored for the connecting user.
+ */
+
+ if (*lp_force_group(snum)) {
+ gid_t gid;
+ pstring gname;
+ pstring tmp_gname;
+ BOOL user_must_be_member = False;
+
+ StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
+
+ if (tmp_gname[0] == '+') {
+ user_must_be_member = True;
+ StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
+ } else {
+ StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
+ }
+ /* default service may be a group name */
+ pstring_sub(gname,"%S",service);
+ gid = nametogid(gname);
+
+ if (gid != (gid_t)-1) {
+ /*
+ * If the user has been forced and the forced group starts
+ * with a '+', then we only set the group to be the forced
+ * group if the forced user is a member of that group.
+ * Otherwise, the meaning of the '+' would be ignored.
+ */
+ if (conn->force_user && user_must_be_member) {
+ if (user_in_group_list( user, gname )) {
+ conn->gid = gid;
+ DEBUG(3,("Forced group %s for member %s\n",gname,user));
+ }
+ } else {
+ conn->gid = gid;
+ DEBUG(3,("Forced group %s\n",gname));
+ }
+ } else {
+ DEBUG(1,("Couldn't find group %s\n",gname));
+ }
+ }
+#endif /* HAVE_GETGRNAM */
+
+ {
+ pstring s;
+ pstrcpy(s,lp_pathname(snum));
+ standard_sub_conn(conn,s);
+ string_set(&conn->connectpath,s);
+ DEBUG(3,("Connect path is %s\n",s));
+ }
+
+ /* groups stuff added by ih */
+ conn->ngroups = 0;
+ conn->groups = NULL;
+
+ /* Find all the groups this uid is in and
+ store them. Used by change_to_user() */
+ initialise_groups(conn->user, conn->uid, conn->gid);
+ get_current_groups(&conn->ngroups,&conn->groups);
+
+ conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
+ conn->ngroups, conn->groups,
+ guest, NULL);
+
+ /*
+ * New code to check if there's a share security descripter
+ * added from NT server manager. This is done after the
+ * smb.conf checks are done as we need a uid and token. JRA.
+ */
+
+ {
+ BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA);
+
+ if (!can_write) {
+ if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) {
+ /* No access, read or write. */
+ *status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
+ service ));
+ conn_free(conn);
+ return NULL;
+ } else {
+ conn->read_only = True;
+ }
+ }
+ }
+ /* Initialise VFS function pointers */
+
+ if (!smbd_vfs_init(conn)) {
+ DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
+ conn_free(conn);
+ return NULL;
+ }
+
+/* ROOT Activities: */
+ /* check number of connections */
+ if (!claim_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)),
+ False)) {
+ DEBUG(1,("too many connections - rejected\n"));
+ *status = NT_STATUS_INSUFFICIENT_RESOURCES;
+ conn_free(conn);
+ return NULL;
+ }
+
+ /* Preexecs are done here as they might make the dir we are to ChDir to below */
+ /* execute any "root preexec = " line */
+ if (*lp_rootpreexec(SNUM(conn))) {
+ int ret;
+ pstring cmd;
+ pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
+ standard_sub_conn(conn,cmd);
+ DEBUG(5,("cmd=%s\n",cmd));
+ ret = smbrun(cmd,NULL);
+ if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
+ DEBUG(1,("root preexec gave %d - failing connection\n", ret));
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+ conn_free(conn);
+ *status = NT_STATUS_UNSUCCESSFUL;
+ return NULL;
+ }
+ }
+
+/* USER Activites: */
+ if (!change_to_user(conn, conn->vuid)) {
+ /* No point continuing if they fail the basic checks */
+ DEBUG(0,("Can't become connected user!\n"));
+ conn_free(conn);
+ *status = NT_STATUS_LOGON_FAILURE;
+ return NULL;
+ }
+
+ /* Remember that a different vuid can connect later without these checks... */
+
+ /* Preexecs are done here as they might make the dir we are to ChDir to below */
+ /* execute any "preexec = " line */
+ if (*lp_preexec(SNUM(conn))) {
+ int ret;
+ pstring cmd;
+ pstrcpy(cmd,lp_preexec(SNUM(conn)));
+ standard_sub_conn(conn,cmd);
+ ret = smbrun(cmd,NULL);
+ if (ret != 0 && lp_preexec_close(SNUM(conn))) {
+ DEBUG(1,("preexec gave %d - failing connection\n", ret));
+ change_to_root_user();
+ yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
+ conn_free(conn);
+ *status = NT_STATUS_UNSUCCESSFUL;
+ return NULL;
+ }
+ }
+
+ if (vfs_ChDir(conn,conn->connectpath) != 0) {
+ DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
+ remote_machine, conn->client_address,
+ conn->connectpath,strerror(errno)));
+ change_to_root_user();
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+ conn_free(conn);
+ *status = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
+
+ string_set(&conn->origpath,conn->connectpath);
+
+#if SOFTLINK_OPTIMISATION
+ /* resolve any soft links early */
+ {
+ pstring s;
+ pstrcpy(s,conn->connectpath);
+ vfs_GetWd(conn,s);
+ string_set(&conn->connectpath,s);
+ vfs_ChDir(conn,conn->connectpath);
+ }
+#endif
+
+ /*
+ * Print out the 'connected as' stuff here as we need
+ * to know the effective uid and gid we will be using
+ * (at least initially).
+ */
+
+ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
+ dbgtext( "%s (%s) ", remote_machine, conn->client_address );
+ dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
+ dbgtext( "initially as user %s ", user );
+ dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
+ dbgtext( "(pid %d)\n", (int)sys_getpid() );
+ }
+
+ /* Add veto/hide lists */
+ if (!IS_IPC(conn) && !IS_PRINT(conn)) {
+ set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
+ set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
+ set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
+ }
+
+ /* Invoke VFS make connection hook */
+
+ if (conn->vfs_ops.connect) {
+ if (conn->vfs_ops.connect(conn, service, user) < 0) {
+ DEBUG(0,("make_connection: VFS make connection failed!\n"));
+ *status = NT_STATUS_UNSUCCESSFUL;
+ change_to_root_user();
+ conn_free(conn);
+ return NULL;
+ }
+ }
+
+ /* we've finished with the user stuff - go back to root */
+ change_to_root_user();
+
+ return(conn);
+}
+
+
+/****************************************************************************
+close a cnum
+****************************************************************************/
+void close_cnum(connection_struct *conn, uint16 vuid)
+{
+ DirCacheFlush(SNUM(conn));
+
+ change_to_root_user();
+
+ DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
+ remote_machine,conn->client_address,
+ lp_servicename(SNUM(conn))));
+
+ if (conn->vfs_ops.disconnect != NULL) {
+
+ /* Call VFS disconnect hook */
+
+ conn->vfs_ops.disconnect(conn);
+
+ }
+
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+
+ file_close_conn(conn);
+ dptr_closecnum(conn);
+
+ /* execute any "postexec = " line */
+ if (*lp_postexec(SNUM(conn)) &&
+ change_to_user(conn, vuid)) {
+ pstring cmd;
+ pstrcpy(cmd,lp_postexec(SNUM(conn)));
+ standard_sub_conn(conn,cmd);
+ smbrun(cmd,NULL);
+ change_to_root_user();
+ }
+
+ change_to_root_user();
+ /* execute any "root postexec = " line */
+ if (*lp_rootpostexec(SNUM(conn))) {
+ pstring cmd;
+ pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
+ standard_sub_conn(conn,cmd);
+ smbrun(cmd,NULL);
+ }
+ conn_free(conn);
+}
diff --git a/source/smbd/session.c b/source/smbd/session.c
new file mode 100644
index 00000000000..d483f12d169
--- /dev/null
+++ b/source/smbd/session.c
@@ -0,0 +1,175 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ session handling for utmp and PAM
+ Copyright (C) tridge@samba.org 2001
+ Copyright (C) abartlet@pcug.org.au 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* a "session" is claimed when we do a SessionSetupX operation
+ and is yielded when the corresponding vuid is destroyed.
+
+ sessions are used to populate utmp and PAM session structures
+*/
+
+#include "includes.h"
+
+extern fstring remote_machine;
+
+static TDB_CONTEXT *tdb;
+/* called when a session is created */
+BOOL session_claim(user_struct *vuser)
+{
+ int i;
+ TDB_DATA data;
+ struct sessionid sessionid;
+ uint32 pid = (uint32)sys_getpid();
+ TDB_DATA key;
+ fstring keystr;
+ char * hostname;
+
+ vuser->session_id = 0;
+
+ /* don't register sessions for the guest user - its just too
+ expensive to go through pam session code for browsing etc */
+ if (vuser->guest) {
+ return True;
+ }
+
+ if (!tdb) {
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ if (!tdb) {
+ DEBUG(1,("session_claim: failed to open sessionid tdb\n"));
+ return False;
+ }
+ }
+
+ ZERO_STRUCT(sessionid);
+
+ data.dptr = NULL;
+ data.dsize = 0;
+
+ for (i=1;i<MAX_SESSION_ID;i++) {
+ slprintf(keystr, sizeof(keystr)-1, "ID/%d", i);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr)+1;
+
+ if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break;
+ }
+
+ if (i == MAX_SESSION_ID) {
+ DEBUG(1,("session_claim: out of session IDs (max is %d)\n",
+ MAX_SESSION_ID));
+ return False;
+ }
+
+ /* Don't resolve the hostname in smbd as we can pause for a long
+ time while waiting for DNS timeouts to occur. The correct
+ place to do this is in the code that displays the session
+ information. */
+
+ hostname = client_addr();
+
+ fstrcpy(sessionid.username, vuser->user.unix_name);
+ fstrcpy(sessionid.hostname, hostname);
+ slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_TEMPLATE, i);
+ sessionid.id_num = i;
+ sessionid.pid = pid;
+ sessionid.uid = vuser->uid;
+ sessionid.gid = vuser->gid;
+ fstrcpy(sessionid.remote_machine, remote_machine);
+ fstrcpy(sessionid.ip_addr, client_addr());
+
+ if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) {
+ DEBUG(1,("pam_session rejected the session for %s [%s]\n",
+ sessionid.username, sessionid.id_str));
+ tdb_delete(tdb, key);
+ return False;
+ }
+
+ data.dptr = (char *)&sessionid;
+ data.dsize = sizeof(sessionid);
+ if (tdb_store(tdb, key, data, TDB_MODIFY) != 0) {
+ DEBUG(1,("session_claim: unable to create session id record\n"));
+ return False;
+ }
+
+#if WITH_UTMP
+ if (lp_utmp()) {
+ sys_utmp_claim(sessionid.username, sessionid.hostname,
+ sessionid.id_str, sessionid.id_num);
+ }
+#endif
+
+ vuser->session_id = i;
+ return True;
+}
+
+/* called when a session is destroyed */
+void session_yield(user_struct *vuser)
+{
+ TDB_DATA dbuf;
+ struct sessionid sessionid;
+ TDB_DATA key;
+ fstring keystr;
+
+ if (!tdb) return;
+
+ if (vuser->session_id == 0) {
+ return;
+ }
+
+ slprintf(keystr, sizeof(keystr)-1, "ID/%d", vuser->session_id);
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr)+1;
+
+ dbuf = tdb_fetch(tdb, key);
+
+ if (dbuf.dsize != sizeof(sessionid))
+ return;
+
+ memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
+
+ SAFE_FREE(dbuf.dptr);
+
+#if WITH_UTMP
+ if (lp_utmp()) {
+ sys_utmp_yield(sessionid.username, sessionid.hostname,
+ sessionid.id_str, sessionid.id_num);
+ }
+#endif
+
+ smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname);
+
+ tdb_delete(tdb, key);
+}
+
+BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state)
+{
+ if (!tdb) {
+ DEBUG(3, ("No tdb opened\n"));
+ return False;
+ }
+
+ tdb_traverse(tdb, fn, state);
+ return True;
+}
+
+
+
diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c
new file mode 100644
index 00000000000..7791637606b
--- /dev/null
+++ b/source/smbd/sesssetup.c
@@ -0,0 +1,799 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ handle SMBsessionsetup
+ Copyright (C) Andrew Tridgell 1998-2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+uint32 global_client_caps = 0;
+static auth_authsupplied_info *ntlmssp_auth_info;
+
+/*
+ on a logon error possibly map the error to success if "map to guest"
+ is set approriately
+*/
+static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
+ const char *user, const char *domain)
+{
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+ if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
+ (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
+ DEBUG(3,("No such user %s [%s] - using guest account\n",
+ user, domain));
+ make_server_info_guest(server_info);
+ status = NT_STATUS_OK;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
+ DEBUG(3,("Registered username %s for guest access\n",user));
+ make_server_info_guest(server_info);
+ status = NT_STATUS_OK;
+ }
+ }
+
+ return status;
+}
+
+
+/****************************************************************************
+ Add the standard 'Samba' signature to the end of the session setup.
+****************************************************************************/
+static void add_signature(char *outbuf)
+{
+ char *p;
+ p = smb_buf(outbuf);
+ p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
+ p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
+ p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
+ set_message_end(outbuf,p);
+}
+
+/****************************************************************************
+ Do a 'guest' logon, getting back the
+****************************************************************************/
+static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
+{
+
+ auth_authsupplied_info *auth_info;
+ auth_usersupplied_info *user_info = NULL;
+
+ NTSTATUS nt_status;
+ char chal[8];
+
+ ZERO_STRUCT(chal);
+
+ DEBUG(3,("Got anonymous request\n"));
+
+ make_user_info_guest(&user_info);
+ make_auth_info_fixed(&auth_info, chal);
+
+ nt_status = check_password(user_info, auth_info, server_info);
+ free_auth_info(&auth_info);
+ free_user_info(&user_info);
+ return nt_status;
+}
+
+
+#ifdef HAVE_KRB5
+/****************************************************************************
+reply to a session setup spnego negotiate packet for kerberos
+****************************************************************************/
+static int reply_spnego_kerberos(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ DATA_BLOB *secblob)
+{
+ DATA_BLOB ticket;
+ char *client, *p;
+ const struct passwd *pw;
+ char *user;
+ int sess_vuid;
+ NTSTATUS ret;
+ DATA_BLOB auth_data;
+ auth_serversupplied_info *server_info = NULL;
+ ADS_STRUCT *ads;
+
+ if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ ads = ads_init(NULL, NULL, NULL, NULL);
+
+ ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1,("Failed to verify incoming ticket!\n"));
+ ads_destroy(&ads);
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ DEBUG(3,("Ticket name is [%s]\n", client));
+
+ p = strchr_m(client, '@');
+ if (!p) {
+ DEBUG(3,("Doesn't look like a valid principal\n"));
+ ads_destroy(&ads);
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ *p = 0;
+ if (strcasecmp(p+1, ads->realm) != 0) {
+ DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
+ if (!lp_allow_trusted_domains()) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+ /* this gives a fully qualified user name (ie. with full realm).
+ that leads to very long usernames, but what else can we do? */
+ asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
+ } else {
+ user = strdup(client);
+ }
+ ads_destroy(&ads);
+
+ /* the password is good - let them in */
+ pw = smb_getpwnam(user,False);
+ if (!pw && !strstr(user, lp_winbind_separator())) {
+ char *user2;
+ /* try it with a winbind domain prefix */
+ asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
+ pw = smb_getpwnam(user2,False);
+ if (pw) {
+ free(user);
+ user = user2;
+ }
+ }
+
+ if (!pw) {
+ DEBUG(1,("Username %s is invalid on this system\n",user));
+ return ERROR_NT(NT_STATUS_NO_SUCH_USER);
+ }
+
+ if (!make_server_info_pw(&server_info,pw)) {
+ DEBUG(1,("make_server_info_from_pw failed!\n"));
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ sess_vuid = register_vuid(server_info, user);
+
+ free(user);
+ free_server_info(&server_info);
+
+ if (sess_vuid == -1) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ set_message(outbuf,4,0,True);
+ SSVAL(outbuf, smb_vwv3, 0);
+ add_signature(outbuf);
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+#endif
+
+
+/****************************************************************************
+send a security blob via a session setup reply
+****************************************************************************/
+static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
+ DATA_BLOB blob)
+{
+ char *p;
+
+ set_message(outbuf,4,0,True);
+
+ /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
+ that we aren't finished yet */
+
+ SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
+ SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
+ SSVAL(outbuf, smb_vwv3, blob.length);
+ p = smb_buf(outbuf);
+ memcpy(p, blob.data, blob.length);
+ p += blob.length;
+ p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
+ p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
+ p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
+ set_message_end(outbuf,p);
+
+ return send_smb(smbd_server_fd(),outbuf);
+}
+
+/****************************************************************************
+reply to a session setup spnego negotiate packet
+****************************************************************************/
+static int reply_spnego_negotiate(connection_struct *conn,
+ char *inbuf,
+ char *outbuf,
+ int length, int bufsize,
+ DATA_BLOB blob1)
+{
+ char *OIDs[ASN1_MAX_OIDS];
+ DATA_BLOB secblob;
+ int i;
+ uint32 ntlmssp_command, neg_flags;
+ DATA_BLOB sess_key, chal, spnego_chal;
+ DATA_BLOB cryptkey;
+ BOOL got_kerberos = False;
+
+ /* parse out the OIDs and the first sec blob */
+ if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("Got OID %s\n", OIDs[i]));
+ if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
+ strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
+ got_kerberos = True;
+ }
+ free(OIDs[i]);
+ }
+ DEBUG(3,("Got secblob of size %d\n", secblob.length));
+
+#ifdef HAVE_KRB5
+ if (got_kerberos) {
+ int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
+ length, bufsize, &secblob);
+ data_blob_free(&secblob);
+ return ret;
+ }
+#endif
+
+ /* parse the NTLMSSP packet */
+#if 0
+ file_save("secblob.dat", secblob.data, secblob.length);
+#endif
+
+ if (!msrpc_parse(&secblob, "CddB",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &neg_flags,
+ &sess_key)) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ data_blob_free(&secblob);
+ data_blob_free(&sess_key);
+
+ if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ DEBUG(3,("Got neg_flags=%08x\n", neg_flags));
+
+ if (!make_auth_info_subsystem(&ntlmssp_auth_info)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ cryptkey = auth_get_challenge(ntlmssp_auth_info);
+
+ /* Give them the challenge. For now, ignore neg_flags and just
+ return the flags we want. Obviously this is not correct */
+
+ neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_LM_KEY |
+ NTLMSSP_NEGOTIATE_NTLM;
+
+ msrpc_gen(&chal, "Cddddbdddd",
+ "NTLMSSP",
+ NTLMSSP_CHALLENGE,
+ 0,
+ 0x30, /* ?? */
+ neg_flags,
+ cryptkey.data, cryptkey.length,
+ 0, 0, 0,
+ 0x3000); /* ?? */
+
+ if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
+ DEBUG(3,("Failed to generate challenge\n"));
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ /* now tell the client to send the auth packet */
+ reply_sesssetup_blob(conn, outbuf, spnego_chal);
+
+ data_blob_free(&chal);
+ data_blob_free(&cryptkey);
+ data_blob_free(&spnego_chal);
+
+ /* and tell smbd that we have already replied to this packet */
+ return -1;
+}
+
+
+/****************************************************************************
+reply to a session setup spnego auth packet
+****************************************************************************/
+static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
+ int length, int bufsize,
+ DATA_BLOB blob1)
+{
+ DATA_BLOB auth;
+ char *workgroup = NULL, *user = NULL, *machine = NULL;
+ DATA_BLOB lmhash, nthash, sess_key;
+ DATA_BLOB plaintext_password = data_blob(NULL, 0);
+ uint32 ntlmssp_command, neg_flags;
+ NTSTATUS nt_status;
+ int sess_vuid;
+ BOOL as_guest;
+
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+
+ if (!spnego_parse_auth(blob1, &auth)) {
+#if 0
+ file_save("auth.dat", blob1.data, blob1.length);
+#endif
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ /* now the NTLMSSP encoded auth hashes */
+ if (!msrpc_parse(&auth, "CdBBUUUBd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &lmhash,
+ &nthash,
+ &workgroup,
+ &user,
+ &machine,
+ &sess_key,
+ &neg_flags)) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ data_blob_free(&auth);
+ data_blob_free(&sess_key);
+
+ DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
+ user, workgroup, machine, lmhash.length, nthash.length));
+
+#if 0
+ file_save("nthash1.dat", nthash.data, nthash.length);
+ file_save("lmhash1.dat", lmhash.data, lmhash.length);
+#endif
+
+ if (!make_user_info_map(&user_info,
+ user, workgroup,
+ machine,
+ lmhash, nthash,
+ plaintext_password,
+ neg_flags, True)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ nt_status = check_password(user_info, ntlmssp_auth_info, &server_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
+ }
+
+ SAFE_FREE(workgroup);
+ SAFE_FREE(machine);
+
+ free_auth_info(&ntlmssp_auth_info);
+
+ free_user_info(&user_info);
+
+ data_blob_free(&lmhash);
+
+ data_blob_free(&nthash);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ SAFE_FREE(user);
+ return ERROR_NT(nt_status_squash(nt_status));
+ }
+
+ as_guest = server_info->guest;
+
+ sess_vuid = register_vuid(server_info, user);
+ free_server_info(&server_info);
+
+ SAFE_FREE(user);
+
+ if (sess_vuid == -1) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ set_message(outbuf,4,0,True);
+ SSVAL(outbuf, smb_vwv3, 0);
+
+ if (as_guest) {
+ SSVAL(outbuf,smb_vwv2,1);
+ }
+
+ add_signature(outbuf);
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+/****************************************************************************
+reply to a session setup spnego anonymous packet
+****************************************************************************/
+static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
+{
+ int sess_vuid;
+ auth_serversupplied_info *server_info = NULL;
+ NTSTATUS nt_status;
+
+ nt_status = check_guest_password(&server_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return ERROR_NT(nt_status_squash(nt_status));
+ }
+
+ sess_vuid = register_vuid(server_info, lp_guestaccount());
+
+ free_server_info(&server_info);
+
+ if (sess_vuid == -1) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ set_message(outbuf,4,0,True);
+ SSVAL(outbuf, smb_vwv3, 0);
+ add_signature(outbuf);
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+/****************************************************************************
+reply to a session setup command
+****************************************************************************/
+static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
+ int length,int bufsize)
+{
+ uint8 *p;
+ DATA_BLOB blob1;
+ int ret;
+
+ DEBUG(3,("Doing spnego session setup\n"));
+
+ if (global_client_caps == 0) {
+ global_client_caps = IVAL(inbuf,smb_vwv10);
+ }
+
+ p = (uint8 *)smb_buf(inbuf);
+
+ if (SVAL(inbuf, smb_vwv7) == 0) {
+ /* an anonymous request */
+ return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
+ }
+
+ /* pull the spnego blob */
+ blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
+
+#if 0
+ file_save("negotiate.dat", blob1.data, blob1.length);
+#endif
+
+ if (blob1.data[0] == ASN1_APPLICATION(0)) {
+ /* its a negTokenTarg packet */
+ ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
+ data_blob_free(&blob1);
+ return ret;
+ }
+
+ if (blob1.data[0] == ASN1_CONTEXT(1)) {
+ /* its a auth packet */
+ ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
+ data_blob_free(&blob1);
+ return ret;
+ }
+
+ /* what sort of packet is this? */
+ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
+
+ data_blob_free(&blob1);
+
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+}
+
+
+/****************************************************************************
+reply to a session setup command
+****************************************************************************/
+int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
+ int length,int bufsize)
+{
+ int sess_vuid;
+ int smb_bufsize;
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ DATA_BLOB plaintext_password;
+ pstring user;
+ pstring sub_user; /* Sainitised username for substituion */
+ fstring domain;
+ fstring native_os;
+ fstring native_lanman;
+ static BOOL done_sesssetup = False;
+ extern BOOL global_encrypted_passwords_negotiated;
+ extern BOOL global_spnego_negotiated;
+ extern int Protocol;
+ extern fstring remote_machine;
+ extern userdom_struct current_user_info;
+ extern int max_send;
+
+ auth_usersupplied_info *user_info = NULL;
+ extern auth_authsupplied_info *negprot_global_auth_info;
+ auth_serversupplied_info *server_info = NULL;
+
+ NTSTATUS nt_status;
+
+ BOOL doencrypt = global_encrypted_passwords_negotiated;
+
+ START_PROFILE(SMBsesssetupX);
+
+ ZERO_STRUCT(lm_resp);
+ ZERO_STRUCT(nt_resp);
+ ZERO_STRUCT(plaintext_password);
+
+ DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
+
+ /* a SPNEGO session setup has 12 command words, whereas a normal
+ NT1 session setup has 13. See the cifs spec. */
+ if (CVAL(inbuf, smb_wct) == 12 &&
+ (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
+ if (!global_spnego_negotiated) {
+ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
+ return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ }
+
+ return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
+ }
+
+ smb_bufsize = SVAL(inbuf,smb_vwv2);
+
+ if (Protocol < PROTOCOL_NT1) {
+ uint16 passlen1 = SVAL(inbuf,smb_vwv7);
+ if (passlen1 > MAX_PASS_LEN) {
+ return ERROR_DOS(ERRDOS,ERRbuftoosmall);
+ }
+
+ if (doencrypt) {
+ lm_resp = data_blob(smb_buf(inbuf), passlen1);
+ } else {
+ plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
+ /* Ensure null termination */
+ plaintext_password.data[passlen1] = 0;
+ }
+
+ srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
+ *domain = 0;
+
+ } else {
+ uint16 passlen1 = SVAL(inbuf,smb_vwv7);
+ uint16 passlen2 = SVAL(inbuf,smb_vwv8);
+ enum remote_arch_types ra_type = get_remote_arch();
+ char *p = smb_buf(inbuf);
+
+ if(global_client_caps == 0)
+ global_client_caps = IVAL(inbuf,smb_vwv11);
+
+ /* client_caps is used as final determination if client is NT or Win95.
+ This is needed to return the correct error codes in some
+ circumstances.
+ */
+
+ if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
+ if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
+ set_remote_arch( RA_WIN95);
+ }
+ }
+
+ if (passlen1 > MAX_PASS_LEN) {
+ return ERROR_DOS(ERRDOS,ERRbuftoosmall);
+ }
+
+ passlen1 = MIN(passlen1, MAX_PASS_LEN);
+ passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
+ if (!doencrypt) {
+ /* both Win95 and WinNT stuff up the password lengths for
+ non-encrypting systems. Uggh.
+
+ if passlen1==24 its a win95 system, and its setting the
+ password length incorrectly. Luckily it still works with the
+ default code because Win95 will null terminate the password
+ anyway
+
+ if passlen1>0 and passlen2>0 then maybe its a NT box and its
+ setting passlen2 to some random value which really stuffs
+ things up. we need to fix that one. */
+
+ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
+ passlen2 = 0;
+ }
+
+ /* Save the lanman2 password and the NT md4 password. */
+
+ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
+ doencrypt = False;
+ }
+
+ if (doencrypt) {
+ lm_resp = data_blob(p, passlen1);
+ nt_resp = data_blob(p+passlen1, passlen2);
+ } else {
+ plaintext_password = data_blob(p, passlen1+1);
+ /* Ensure null termination */
+ plaintext_password.data[passlen1] = 0;
+ }
+
+ p += passlen1 + passlen2;
+ p += srvstr_pull(inbuf, user, p, sizeof(user), -1,
+ STR_TERMINATE);
+ p += srvstr_pull(inbuf, domain, p, sizeof(domain),
+ -1, STR_TERMINATE);
+ p += srvstr_pull(inbuf, native_os, p, sizeof(native_os),
+ -1, STR_TERMINATE);
+ p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
+ -1, STR_TERMINATE);
+ DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
+ domain,native_os,native_lanman));
+ }
+
+ /* don't allow for weird usernames or domains */
+ alpha_strcpy(user, user, ". _-$", sizeof(user));
+ alpha_strcpy(domain, domain, ". _-", sizeof(domain));
+ if (strstr(user, "..") || strstr(domain,"..")) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
+
+ if (*user) {
+ if (global_spnego_negotiated) {
+ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
+ return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ if (*user) {
+ pstrcpy(sub_user, user);
+ } else {
+ pstrcpy(sub_user, lp_guestaccount());
+ }
+
+ pstrcpy(current_user_info.smb_name,sub_user);
+
+ reload_services(True);
+
+ if (lp_security() == SEC_SHARE) {
+ /* in share level we should ignore any passwords */
+
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_clear_free(&plaintext_password);
+
+ map_username(sub_user);
+ add_session_user(sub_user);
+ /* Then force it to null for the benfit of the code below */
+ *user = 0;
+ }
+
+ if (!*user) {
+
+ nt_status = check_guest_password(&server_info);
+
+ } else if (doencrypt) {
+ if (!make_user_info_for_reply_enc(&user_info,
+ user, domain,
+ lm_resp, nt_resp,
+ plaintext_password)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ nt_status = check_password(user_info, negprot_global_auth_info, &server_info);
+ } else {
+ auth_authsupplied_info *plaintext_auth_info = NULL;
+ DATA_BLOB chal;
+ if (!make_auth_info_subsystem(&plaintext_auth_info)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ chal = auth_get_challenge(plaintext_auth_info);
+
+ if (!make_user_info_for_reply(&user_info,
+ user, domain, chal.data,
+ plaintext_password)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ nt_status = check_password(user_info, plaintext_auth_info, &server_info);
+
+ data_blob_free(&chal);
+ free_auth_info(&plaintext_auth_info);
+ }
+
+ free_user_info(&user_info);
+
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_clear_free(&plaintext_password);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return ERROR_NT(nt_status_squash(nt_status));
+ }
+
+ /* it's ok - setup a reply */
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,3,0,True);
+ } else {
+ set_message(outbuf,3,0,True);
+ add_signature(outbuf);
+ /* perhaps grab OS version here?? */
+ }
+
+ if (server_info->guest) {
+ SSVAL(outbuf,smb_vwv2,1);
+ } else {
+ const char *home_dir = pdb_get_homedir(server_info->sam_account);
+ const char *username = pdb_get_username(server_info->sam_account);
+ if ((home_dir && *home_dir)
+ && (lp_servicenumber(username) < 0)) {
+ add_home_service(username, home_dir);
+ }
+ }
+
+ /* register the name and uid as being validated, so further connections
+ to a uid can get through without a password, on the same VC */
+
+ sess_vuid = register_vuid(server_info, sub_user);
+
+ free_server_info(&server_info);
+
+ if (sess_vuid == -1) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
+
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
+
+ done_sesssetup = True;
+
+ END_PROFILE(SMBsesssetupX);
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+
+
+
diff --git a/source/smbd/smbrun.c b/source/smbd/smbrun.c
deleted file mode 100644
index df12ae1f85c..00000000000
--- a/source/smbd/smbrun.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- external program running routine
- Copyright (C) Andrew Tridgell 1992-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
-
-/*******************************************************************
-close the low 3 fd's and open dev/null in their place
-********************************************************************/
-static void close_fds(void)
-{
- int fd;
- int i;
- close(0); close(1); close(2);
- /* try and use up these file descriptors, so silly
- library routines writing to stdout etc won't cause havoc */
- for (i=0;i<3;i++) {
- fd = open("/dev/null",O_RDWR,0);
- if (fd < 0) fd = open("/dev/null",O_WRONLY,0);
- if (fd != i) return;
- }
-}
-
-
-/*
-This is a wrapper around the system call to allow commands to run correctly
-as non root from a program which is switching between root and non-root
-
-It takes one argument as argv[1] and runs it after becoming a non-root
-user
-*/
-int main(int argc,char *argv[])
-{
- close_fds();
-
- if (getuid() != geteuid())
- {
- int uid,gid;
-
- if (getuid() == 0)
- uid = geteuid();
- else
- uid = getuid();
-
- if (getgid() == 0)
- gid = getegid();
- else
- gid = getgid();
-
-#ifdef USE_SETRES
- setresgid(0,0,0);
- setresuid(0,0,0);
- setresgid(gid,gid,gid);
- setresuid(uid,uid,uid);
-#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
-#endif
-
- if (getuid() != uid)
- return(3);
- }
-
- if (geteuid() != getuid())
- return(1);
-
- if (argc < 2)
- return(2);
-
- /* this is to make sure that the system() call doesn't run forever */
- alarm(30);
-
- return(system(argv[1]));
-}
diff --git a/source/smbd/srvstr.c b/source/smbd/srvstr.c
new file mode 100644
index 00000000000..3c452653f2e
--- /dev/null
+++ b/source/smbd/srvstr.c
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ server specific string routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+int srvstr_push(void *base_ptr, void *dest, const char *src, int dest_len, int flags)
+{
+ return push_string(base_ptr, dest, src, dest_len, flags);
+}
+
+int srvstr_pull(void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ return pull_string(base_ptr, dest, src, dest_len, src_len, flags);
+}
diff --git a/source/smbd/ssl.c b/source/smbd/ssl.c
new file mode 100644
index 00000000000..349ca34f959
--- /dev/null
+++ b/source/smbd/ssl.c
@@ -0,0 +1,287 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SSLeay utility functions
+ Copyright (C) Christian Starkjohann <cs@obdev.at> 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * since includes.h pulls in config.h which is were WITH_SSL will be
+ * defined, we want to include includes.h before testing for WITH_SSL
+ * RJS 26-Jan-1999
+ */
+
+#include "includes.h"
+
+#ifdef WITH_SSL /* should always be defined if this module is compiled */
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+BOOL sslEnabled;
+SSL *ssl = NULL;
+int sslFd = -1;
+static SSL_CTX *sslContext = NULL;
+extern int DEBUGLEVEL;
+
+static int ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+char buffer[256];
+
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
+ buffer, sizeof(buffer));
+ if(ok){
+ DEBUG(0, ("SSL: Certificate OK: %s\n", buffer));
+ }else{
+ switch (ctx->error){
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ DEBUG(0, ("SSL: Cert error: CA not known: %s\n", buffer));
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ DEBUG(0, ("SSL: Cert error: Cert not yet valid: %s\n", buffer));
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ DEBUG(0, ("SSL: Cert error: illegal \'not before\' field: %s\n",
+ buffer));
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ DEBUG(0, ("SSL: Cert error: Cert expired: %s\n", buffer));
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ DEBUG(0, ("SSL: Cert error: invalid \'not after\' field: %s\n",
+ buffer));
+ break;
+ default:
+ DEBUG(0, ("SSL: Cert error: unknown error %d in %s\n", ctx->error,
+ buffer));
+ break;
+ }
+ }
+ return ok;
+}
+
+static RSA *ssl_temp_rsa_cb(SSL *ssl, int is_export, int keylength)
+{
+static RSA *rsa = NULL;
+
+ if(rsa == NULL)
+ rsa = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
+ return rsa;
+}
+
+/* This is called before we fork. It should ask the user for the pass phrase
+ * if necessary. Error output can still go to stderr because the process
+ * has a terminal.
+ */
+int sslutil_init(int isServer)
+{
+int err, entropybytes;
+char *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
+char *egdsocket, *entropyfile;
+
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+ egdsocket = lp_ssl_egdsocket();
+ if (egdsocket != NULL && *egdsocket != 0)
+ RAND_egd(egdsocket);
+ entropyfile = lp_ssl_entropyfile();
+ entropybytes = lp_ssl_entropybytes();
+ if (entropyfile != NULL && *entropyfile != 0)
+ RAND_load_file(entropyfile, entropybytes);
+ switch(lp_ssl_version()){
+ case SMB_SSL_V2: sslContext = SSL_CTX_new(SSLv2_method()); break;
+ case SMB_SSL_V3: sslContext = SSL_CTX_new(SSLv3_method()); break;
+ default:
+ case SMB_SSL_V23: sslContext = SSL_CTX_new(SSLv23_method()); break;
+ case SMB_SSL_TLS1: sslContext = SSL_CTX_new(TLSv1_method()); break;
+ }
+ if(sslContext == NULL){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Error allocating context: %s\n",
+ ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(lp_ssl_compatibility()){
+ SSL_CTX_set_options(sslContext, SSL_OP_ALL);
+ }
+ certfile = isServer ? lp_ssl_server_cert() : lp_ssl_client_cert();
+ if((certfile == NULL || *certfile == 0) && isServer){
+ fprintf(stderr, "SSL: No cert file specified in config file!\n");
+ fprintf(stderr, "The server MUST have a certificate!\n");
+ exit(1);
+ }
+ keyfile = isServer ? lp_ssl_server_privkey() : lp_ssl_client_privkey();
+ if(keyfile == NULL || *keyfile == 0)
+ keyfile = certfile;
+ if(certfile != NULL && *certfile != 0){
+ if(!SSL_CTX_use_certificate_chain_file(sslContext, certfile)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: error reading certificate from file %s: %s\n",
+ certfile, ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: error reading private key from file %s: %s\n",
+ keyfile, ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(!SSL_CTX_check_private_key(sslContext)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Private key does not match public key in cert!\n");
+ exit(1);
+ }
+ }
+ cacertDir = lp_ssl_cacertdir();
+ cacertFile = lp_ssl_cacertfile();
+ if(cacertDir != NULL && *cacertDir == 0)
+ cacertDir = NULL;
+ if(cacertFile != NULL && *cacertFile == 0)
+ cacertFile = NULL;
+ if(!SSL_CTX_load_verify_locations(sslContext, cacertFile, cacertDir)){
+ err = ERR_get_error();
+ if (cacertFile || cacertDir) {
+ fprintf(stderr, "SSL: Error error setting CA cert locations: %s\n",
+ ERR_error_string(err, NULL));
+ fprintf(stderr, "trying default locations.\n");
+ }
+ cacertFile = cacertDir = NULL;
+ if(!SSL_CTX_set_default_verify_paths(sslContext)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Error error setting default CA cert location: %s\n",
+ ERR_error_string(err, NULL));
+ exit(1);
+ }
+ }
+ SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+ if((ciphers = lp_ssl_ciphers()) != NULL && *ciphers != 0)
+ SSL_CTX_set_cipher_list(sslContext, ciphers);
+ if((isServer && lp_ssl_reqClientCert()) || (!isServer && lp_ssl_reqServerCert())){
+ SSL_CTX_set_verify(sslContext,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+ }else{
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
+ }
+#if 1 /* don't know what this is good for, but s_server in SSLeay does it, too */
+ if(isServer){
+ SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
+ }
+#endif
+ return 0;
+}
+
+int sslutil_accept(int fd)
+{
+int err;
+
+ if(ssl != NULL){
+ DEBUG(0, ("SSL: internal error: more than one SSL connection (server)\n"));
+ return -1;
+ }
+ if((ssl = SSL_new(sslContext)) == NULL){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error allocating handle: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ SSL_set_fd(ssl, fd);
+ sslFd = fd;
+ if(SSL_accept(ssl) <= 0){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error accepting on socket: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
+ return 0;
+}
+
+int sslutil_fd_is_ssl(int fd)
+{
+ return fd == sslFd;
+}
+
+int sslutil_connect(int fd)
+{
+int err;
+
+ if(ssl != NULL){
+ DEBUG(0, ("SSL: internal error: more than one SSL connection (client)\n"));
+ return -1;
+ }
+ if((ssl = SSL_new(sslContext)) == NULL){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error allocating handle: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ SSL_set_fd(ssl, fd);
+ sslFd = fd;
+ if(SSL_connect(ssl) <= 0){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error conencting socket: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
+ return 0;
+}
+
+int sslutil_disconnect(int fd)
+{
+ if(fd == sslFd && ssl != NULL){
+ SSL_free(ssl);
+ ssl = NULL;
+ sslFd = -1;
+ }
+ return 0;
+}
+
+int sslutil_negotiate_ssl(int fd, int msg_type)
+{
+unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+char *reqHosts, *resignHosts;
+
+ reqHosts = lp_ssl_hosts();
+ resignHosts = lp_ssl_hosts_resign();
+ if(!allow_access(resignHosts, reqHosts, get_socket_name(fd), get_socket_addr(fd))){
+ sslEnabled = False;
+ return 0;
+ }
+ if(msg_type != 0x81){ /* first packet must be a session request */
+ DEBUG( 0, ( "Client %s did not use session setup; access denied\n",
+ client_addr() ) );
+ if (!send_smb(fd, (char *)buf))
+ DEBUG(0, ("sslutil_negotiate_ssl: send_smb failed.\n"));
+ return -1;
+ }
+ buf[4] = 0x8e; /* negative session response: use SSL */
+ if (!send_smb(fd, (char *)buf)) {
+ DEBUG(0,("sslutil_negotiate_ssl: send_smb failed.\n"));
+ return -1;
+ }
+ if(sslutil_accept(fd) != 0){
+ DEBUG( 0, ( "Client %s failed SSL negotiation!\n", client_addr() ) );
+ return -1;
+ }
+ return 1;
+}
+
+#else /* WITH_SSL */
+ void ssl_dummy(void);
+ void ssl_dummy(void) {;} /* So some compilers don't complain. */
+#endif /* WITH_SSL */
diff --git a/source/smbd/statcache.c b/source/smbd/statcache.c
new file mode 100644
index 00000000000..09aa63d56d7
--- /dev/null
+++ b/source/smbd/statcache.c
@@ -0,0 +1,231 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ stat cache code
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1999-2000
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern BOOL case_sensitive;
+
+
+/****************************************************************************
+ Stat cache code used in unix_convert.
+*****************************************************************************/
+
+typedef struct {
+ int name_len;
+ char names[2]; /* This is extended via malloc... */
+} stat_cache_entry;
+
+#define INIT_STAT_CACHE_SIZE 512
+static hash_table stat_cache;
+
+/****************************************************************************
+ Add an entry into the stat cache.
+*****************************************************************************/
+
+void stat_cache_add( char *full_orig_name, char *orig_translated_path)
+{
+ stat_cache_entry *scp;
+ stat_cache_entry *found_scp;
+ pstring orig_name;
+ pstring translated_path;
+ int namelen;
+ hash_element *hash_elem;
+
+ if (!lp_stat_cache()) return;
+
+ namelen = strlen(orig_translated_path);
+
+ /*
+ * Don't cache trivial valid directory entries.
+ */
+ if((*full_orig_name == '\0') || (strcmp(full_orig_name, ".") == 0) ||
+ (strcmp(full_orig_name, "..") == 0))
+ return;
+
+ /*
+ * If we are in case insentive mode, we need to
+ * store names that need no translation - else, it
+ * would be a waste.
+ */
+
+ if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0))
+ return;
+
+ /*
+ * Remove any trailing '/' characters from the
+ * translated path.
+ */
+
+ pstrcpy(translated_path, orig_translated_path);
+ if(translated_path[namelen-1] == '/') {
+ translated_path[namelen-1] = '\0';
+ namelen--;
+ }
+
+ /*
+ * We will only replace namelen characters
+ * of full_orig_name.
+ * StrnCpy always null terminates.
+ */
+
+ StrnCpy(orig_name, full_orig_name, namelen);
+ if(!case_sensitive)
+ strupper( orig_name );
+
+ /*
+ * Check this name doesn't exist in the cache before we
+ * add it.
+ */
+
+ if ((hash_elem = hash_lookup(&stat_cache, orig_name))) {
+ found_scp = (stat_cache_entry *)(hash_elem->value);
+ if (strcmp((found_scp->names+found_scp->name_len+1), translated_path) == 0) {
+ return;
+ } else {
+ hash_remove(&stat_cache, hash_elem);
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy((scp->names+namelen+1), translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
+ }
+ return;
+ } else {
+
+ /*
+ * New entry.
+ */
+
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy(scp->names+namelen+1, translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
+ }
+
+ DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->names, (scp->names+scp->name_len+1)));
+}
+
+/****************************************************************************
+ Look through the stat cache for an entry - promote it to the top if found.
+ Return True if we translated (and did a scuccessful stat on) the entire name.
+*****************************************************************************/
+
+BOOL stat_cache_lookup(connection_struct *conn, char *name, char *dirpath,
+ char **start, SMB_STRUCT_STAT *pst)
+{
+ stat_cache_entry *scp;
+ char *trans_name;
+ pstring chk_name;
+ int namelen;
+ hash_element *hash_elem;
+ char *sp;
+
+ if (!lp_stat_cache())
+ return False;
+
+ namelen = strlen(name);
+
+ *start = name;
+
+ DO_PROFILE_INC(statcache_lookups);
+
+ /*
+ * Don't lookup trivial valid directory entries.
+ */
+ if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
+ DO_PROFILE_INC(statcache_misses);
+ return False;
+ }
+
+ pstrcpy(chk_name, name);
+ if(!case_sensitive)
+ strupper( chk_name );
+
+ while (1) {
+ hash_elem = hash_lookup(&stat_cache, chk_name);
+ if(hash_elem == NULL) {
+ /*
+ * Didn't find it - remove last component for next try.
+ */
+ sp = strrchr_m(chk_name, '/');
+ if (sp) {
+ *sp = '\0';
+ } else {
+ /*
+ * We reached the end of the name - no match.
+ */
+ DO_PROFILE_INC(statcache_misses);
+ return False;
+ }
+ if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0)
+ || (strcmp(chk_name, "..") == 0)) {
+ DO_PROFILE_INC(statcache_misses);
+ return False;
+ }
+ } else {
+ scp = (stat_cache_entry *)(hash_elem->value);
+ DO_PROFILE_INC(statcache_hits);
+ trans_name = scp->names+scp->name_len+1;
+ if(vfs_stat(conn,trans_name, pst) != 0) {
+ /* Discard this entry - it doesn't exist in the filesystem. */
+ hash_remove(&stat_cache, hash_elem);
+ return False;
+ }
+ memcpy(name, trans_name, scp->name_len);
+ *start = &name[scp->name_len];
+ if(**start == '/')
+ ++*start;
+ StrnCpy( dirpath, trans_name, name - (*start));
+ return (namelen == scp->name_len);
+ }
+ }
+}
+
+/*************************************************************************** **
+ * Initializes or clears the stat cache.
+ *
+ * Input: none.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+BOOL reset_stat_cache( void )
+{
+ static BOOL initialised;
+ if (!lp_stat_cache()) return True;
+
+ if (initialised) {
+ hash_clear(&stat_cache);
+ }
+
+ initialised = hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE,
+ (compare_function)(strcmp));
+ return initialised;
+} /* reset_stat_cache */
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9d02123cf87..73496f406b0 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994
+ Copyright (C) Jeremy Allison 1994-2001
Extensively modified by Andrew Tridgell, 1995
@@ -22,15 +22,14 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "trans2.h"
-extern int DEBUGLEVEL;
extern int Protocol;
-extern connection_struct Connections[];
-extern files_struct Files[];
extern BOOL case_sensitive;
-extern int Client;
+extern int smb_read_error;
+extern fstring local_machine;
+extern int global_oplock_break;
+extern uint32 global_client_caps;
+extern pstring global_myname;
/****************************************************************************
Send the required number of replies back.
@@ -38,23 +37,25 @@ extern int Client;
set correctly for the type of call.
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
+
static int send_trans2_replies(char *outbuf, int bufsize, char *params,
- int paramsize, char *pdata, int datasize)
+ int paramsize, char *pdata, int datasize)
{
- /* As we are using a protocol > LANMAN1 then the maxxmit
+ /* As we are using a protocol > LANMAN1 then the max_send
variable must have been set in the sessetupX call.
This takes precedence over the max_xmit field in the
global struct. These different max_xmit variables should
be merged as this is now too confusing */
- extern int maxxmit;
+ extern int max_send;
int data_to_send = datasize;
int params_to_send = paramsize;
int useable_space;
char *pp = params;
char *pd = pdata;
int params_sent_thistime, data_sent_thistime, total_sent_thistime;
- int alignment_offset = 1;
+ int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
+ int data_alignment_offset = 0;
/* Initially set the wcnt area to be 10 - this is true for all
trans2 replies */
@@ -63,107 +64,136 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
/* If there genuinely are no parameters or data to send just send
the empty packet */
if(params_to_send == 0 && data_to_send == 0)
- {
- send_smb(Client,outbuf);
- return 0;
- }
+ {
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans2_replies: send_smb failed.");
+ return 0;
+ }
+
+ /* When sending params and data ensure that both are nicely aligned */
+ /* Only do this alignment when there is also data to send - else
+ can cause NT redirector problems. */
+ if (((params_to_send % 4) != 0) && (data_to_send != 0))
+ data_alignment_offset = 4 - (params_to_send % 4);
/* Space is bufsize minus Netbios over TCP header minus SMB header */
- /* The + 1 is to align the param and data bytes on an even byte
+ /* The alignment_offset is to align the param bytes on an even byte
boundary. NT 4.0 Beta needs this to work correctly. */
- useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf);
- useable_space = MIN(useable_space, maxxmit); /* XXX is this needed? correct? */
+ useable_space = bufsize - ((smb_buf(outbuf)+
+ alignment_offset+data_alignment_offset) -
+ outbuf);
+
+ /* useable_space can never be more than max_send minus the
+ alignment offset. */
+ useable_space = MIN(useable_space,
+ max_send - (alignment_offset+data_alignment_offset));
- while( params_to_send || data_to_send)
- {
- /* Calculate whether we will totally or partially fill this packet */
- total_sent_thistime = params_to_send + data_to_send + alignment_offset;
- total_sent_thistime = MIN(total_sent_thistime, useable_space);
- set_message(outbuf, 10, total_sent_thistime, True);
+ while (params_to_send || data_to_send)
+ {
+ /* Calculate whether we will totally or partially fill this packet */
+ total_sent_thistime = params_to_send + data_to_send +
+ alignment_offset + data_alignment_offset;
+ /* We can never send more than useable_space */
+ /*
+ * Note that 'useable_space' does not include the alignment offsets,
+ * but we must include the alignment offsets in the calculation of
+ * the length of the data we send over the wire, as the alignment offsets
+ * are sent here. Fix from Marc_Jacobsen@hp.com.
+ */
+ total_sent_thistime = MIN(total_sent_thistime, useable_space+
+ alignment_offset + data_alignment_offset);
+
+ set_message(outbuf, 10, total_sent_thistime, True);
+
+ /* Set total params and data to be sent */
+ SSVAL(outbuf,smb_tprcnt,paramsize);
+ SSVAL(outbuf,smb_tdrcnt,datasize);
+
+ /* Calculate how many parameters and data we can fit into
+ this packet. Parameters get precedence */
+
+ params_sent_thistime = MIN(params_to_send,useable_space);
+ data_sent_thistime = useable_space - params_sent_thistime;
+ data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+
+ SSVAL(outbuf,smb_prcnt, params_sent_thistime);
+
+ /* smb_proff is the offset from the start of the SMB header to the
+ parameter bytes, however the first 4 bytes of outbuf are
+ the Netbios over TCP header. Thus use smb_base() to subtract
+ them from the calculation */
+
+ SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+
+ if(params_sent_thistime == 0)
+ SSVAL(outbuf,smb_prdisp,0);
+ else
+ /* Absolute displacement of param bytes sent in this packet */
+ SSVAL(outbuf,smb_prdisp,pp - params);
+
+ SSVAL(outbuf,smb_drcnt, data_sent_thistime);
+ if(data_sent_thistime == 0)
+ {
+ SSVAL(outbuf,smb_droff,0);
+ SSVAL(outbuf,smb_drdisp, 0);
+ }
+ else
+ {
+ /* The offset of the data bytes is the offset of the
+ parameter bytes plus the number of parameters being sent this time */
+ SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) -
+ smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
+ SSVAL(outbuf,smb_drdisp, pd - pdata);
+ }
- /* Set total params and data to be sent */
- SSVAL(outbuf,smb_tprcnt,paramsize);
- SSVAL(outbuf,smb_tdrcnt,datasize);
+ /* Copy the param bytes into the packet */
+ if(params_sent_thistime)
+ memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
+ /* Copy in the data bytes */
+ if(data_sent_thistime)
+ memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
+ data_alignment_offset,pd,data_sent_thistime);
- /* Calculate how many parameters and data we can fit into
- this packet. Parameters get precedence */
+ DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
+ params_sent_thistime, data_sent_thistime, useable_space));
+ DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
+ params_to_send, data_to_send, paramsize, datasize));
- params_sent_thistime = MIN(params_to_send,useable_space);
- data_sent_thistime = useable_space - params_sent_thistime;
- data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+ /* Send the packet */
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("send_trans2_replies: send_smb failed.");
- SSVAL(outbuf,smb_prcnt, params_sent_thistime);
- if(params_sent_thistime == 0)
- {
- SSVAL(outbuf,smb_proff,0);
- SSVAL(outbuf,smb_prdisp,0);
- } else {
- /* smb_proff is the offset from the start of the SMB header to the
- parameter bytes, however the first 4 bytes of outbuf are
- the Netbios over TCP header. Thus use smb_base() to subtract
- them from the calculation */
- SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
- /* Absolute displacement of param bytes sent in this packet */
- SSVAL(outbuf,smb_prdisp,pp - params);
- }
+ pp += params_sent_thistime;
+ pd += data_sent_thistime;
- SSVAL(outbuf,smb_drcnt, data_sent_thistime);
- if(data_sent_thistime == 0)
- {
- SSVAL(outbuf,smb_droff,0);
- SSVAL(outbuf,smb_drdisp, 0);
- } else {
- /* The offset of the data bytes is the offset of the
- parameter bytes plus the number of parameters being sent this time */
- SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) -
- smb_base(outbuf)) + params_sent_thistime);
- SSVAL(outbuf,smb_drdisp, pd - pdata);
- }
+ params_to_send -= params_sent_thistime;
+ data_to_send -= data_sent_thistime;
- /* Copy the param bytes into the packet */
- if(params_sent_thistime)
- memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
- /* Copy in the data bytes */
- if(data_sent_thistime)
- memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime,pd,data_sent_thistime);
-
- DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
- params_sent_thistime, data_sent_thistime, useable_space));
- DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
- params_to_send, data_to_send, paramsize, datasize));
-
- /* Send the packet */
- send_smb(Client,outbuf);
-
- pp += params_sent_thistime;
- pd += data_sent_thistime;
-
- params_to_send -= params_sent_thistime;
- data_to_send -= data_sent_thistime;
-
- /* Sanity check */
- if(params_to_send < 0 || data_to_send < 0)
- {
- DEBUG(2,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
- params_to_send, data_to_send));
- return -1;
- }
+ /* Sanity check */
+ if(params_to_send < 0 || data_to_send < 0)
+ {
+ DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
+ params_to_send, data_to_send));
+ return -1;
}
+ }
return 0;
}
-
/****************************************************************************
- reply to a TRANSACT2_OPEN
+ Reply to a TRANSACT2_OPEN.
****************************************************************************/
-static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
- char **pparams, char **ppdata)
+
+static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
+ int bufsize,
+ char **pparams, char **ppdata)
{
char *params = *pparams;
int16 open_mode = SVAL(params, 2);
int16 open_attr = SVAL(params,6);
+ BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
#if 0
BOOL return_additional_info = BITSETW(params,0);
int16 open_sattr = SVAL(params, 4);
@@ -172,68 +202,85 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
int16 open_ofun = SVAL(params,12);
int32 open_size = IVAL(params,14);
char *pname = &params[28];
- int16 namelen = strlen(pname)+1;
-
pstring fname;
- int fnum = -1;
- int unixmode;
- int size=0,fmode=0,mtime=0,rmode;
- int32 inode = 0;
- struct stat sbuf;
+ mode_t unixmode;
+ SMB_OFF_T size=0;
+ int fmode=0,mtime=0,rmode;
+ SMB_INO_T inode = 0;
+ SMB_STRUCT_STAT sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
- StrnCpy(fname,pname,namelen);
+ srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE);
- DEBUG(3,("trans2open %s cnum=%d mode=%d attr=%d ofun=%d size=%d\n",
- fname,cnum,open_mode, open_attr, open_ofun, open_size));
+ DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
+ fname,open_mode, open_attr, open_ofun, open_size));
+
+ if (IS_IPC(conn)) {
+ return(ERROR_DOS(ERRSRV,ERRaccess));
+ }
/* XXXX we need to handle passed times, sattr and flags */
- unix_convert(fname,cnum);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,cnum))
+ if (!check_name(fname,conn))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- unixmode = unix_mode(cnum,open_attr | aARCH);
+ unixmode = unix_mode(conn,open_attr | aARCH, fname);
+ fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
- &rmode,&smb_action);
-
- if (!Files[fnum].open)
+ if (!fsp)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
}
-
+
size = sbuf.st_size;
- fmode = dos_mode(cnum,fname,&sbuf);
+ fmode = dos_mode(conn,fname,&sbuf);
mtime = sbuf.st_mtime;
inode = sbuf.st_ino;
if (fmode & aDIR) {
- close_file(fnum);
- return(ERROR(ERRDOS,ERRnoaccess));
+ close_file(fsp,False);
+ return(ERROR_DOS(ERRDOS,ERRnoaccess));
}
/* Realloc the size of parameters and data we will return */
- params = *pparams = Realloc(*pparams, 28);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ params = Realloc(*pparams, 28);
+ if( params == NULL ) {
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ *pparams = params;
- bzero(params,28);
- SSVAL(params,0,fnum);
+ memset((char *)params,'\0',28);
+ SSVAL(params,0,fsp->fnum);
SSVAL(params,2,fmode);
put_dos_date2(params,4, mtime);
- SIVAL(params,8, size);
+ SIVAL(params,8, (uint32)size);
SSVAL(params,12,rmode);
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
SSVAL(params,18,smb_action);
+ /*
+ * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
+ */
SIVAL(params,20,inode);
/* Send the required number of replies */
@@ -242,292 +289,333 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
return -1;
}
+/*********************************************************
+ Routine to check if a given string matches exactly.
+ as a special case a mask of "." does NOT match. That
+ is required for correct wildcard semantics
+ Case can be significant or not.
+**********************************************************/
+
+static BOOL exact_match(char *str,char *mask, BOOL case_sig)
+{
+ if (mask[0] == '.' && mask[1] == 0)
+ return False;
+ if (case_sig)
+ return strcmp(str,mask)==0;
+ return strcasecmp(str,mask) == 0;
+}
+
/****************************************************************************
- get a level dependent lanman2 dir entry.
+ Get a level dependent lanman2 dir entry.
****************************************************************************/
-static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_level,
+
+static BOOL get_lanman2_dir_entry(connection_struct *conn,
+ void *inbuf, void *outbuf,
+ char *path_mask,int dirtype,int info_level,
int requires_resume_key,
BOOL dont_descend,char **ppdata,
char *base_data, int space_remaining,
- BOOL *out_of_space,
+ BOOL *out_of_space, BOOL *got_exact_match,
int *last_name_off)
{
- char *dname;
- BOOL found = False;
- struct stat sbuf;
- pstring mask;
- pstring pathreal;
- pstring fname;
- BOOL matched;
- char *p, *pdata = *ppdata;
- int reskey=0, prev_dirpos=0;
- int mode=0;
- uint32 size=0,len;
- uint32 mdate=0, adate=0, cdate=0;
- char *name_ptr;
- BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
- strequal(Connections[cnum].dirpath,".") ||
- strequal(Connections[cnum].dirpath,"/"));
- BOOL was_8_3;
-
- *fname = 0;
- *out_of_space = False;
-
- if (!Connections[cnum].dirptr)
- return(False);
-
- p = strrchr(path_mask,'/');
- if(p != NULL)
- {
- if(p[1] == '\0')
- strcpy(mask,"*.*");
- else
- strcpy(mask, p+1);
- }
- else
- strcpy(mask, path_mask);
-
- while (!found)
- {
- /* Needed if we run out of space */
- prev_dirpos = TellDir(Connections[cnum].dirptr);
- dname = ReadDirName(Connections[cnum].dirptr);
-
- reskey = TellDir(Connections[cnum].dirptr);
-
- DEBUG(6,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
- Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
+ char *dname;
+ BOOL found = False;
+ SMB_STRUCT_STAT sbuf;
+ pstring mask;
+ pstring pathreal;
+ pstring fname;
+ char *p, *q, *pdata = *ppdata;
+ uint32 reskey=0;
+ int prev_dirpos=0;
+ int mode=0;
+ SMB_OFF_T size = 0;
+ SMB_OFF_T allocation_size = 0;
+ uint32 len;
+ time_t mdate=0, adate=0, cdate=0;
+ char *nameptr;
+ BOOL was_8_3;
+ int nt_extmode; /* Used for NT connections instead of mode */
+ BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+ *fname = 0;
+ *out_of_space = False;
+ *got_exact_match = False;
+
+ if (!conn->dirptr)
+ return(False);
+
+ p = strrchr_m(path_mask,'/');
+ if(p != NULL) {
+ if(p[1] == '\0')
+ pstrcpy(mask,"*.*");
+ else
+ pstrcpy(mask, p+1);
+ } else
+ pstrcpy(mask, path_mask);
+
+ while (!found) {
+ BOOL got_match;
+
+ /* Needed if we run out of space */
+ prev_dirpos = TellDir(conn->dirptr);
+ dname = ReadDirName(conn->dirptr);
+
+ /*
+ * Due to bugs in NT client redirectors we are not using
+ * resume keys any more - set them to zero.
+ * Check out the related comments in findfirst/findnext.
+ * JRA.
+ */
+
+ reskey = 0;
+
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
+ (long)conn->dirptr,TellDir(conn->dirptr)));
- if (!dname)
- return(False);
-
- matched = False;
-
- strcpy(fname,dname);
-
- if(mask_match(fname, mask, case_sensitive, True))
- {
- BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
- if (dont_descend && !isdots)
- continue;
+ if (!dname)
+ return(False);
+
+ pstrcpy(fname,dname);
+
+ if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive)))
+ got_match = mask_match(fname, mask, case_sensitive);
+
+ if(!got_match && !is_8_3(fname, False)) {
+
+ /*
+ * It turns out that NT matches wildcards against
+ * both long *and* short names. This may explain some
+ * of the wildcard wierdness from old DOS clients
+ * that some people have been seeing.... JRA.
+ */
+
+ pstring newname;
+ pstrcpy( newname, fname);
+ name_map_mangle( newname, True, False, SNUM(conn));
+ if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
+ got_match = mask_match(newname, mask, case_sensitive);
+ }
+
+ if(got_match) {
+ BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
+ if (dont_descend && !isdots)
+ continue;
- if (isrootdir && isdots)
- continue;
-
- strcpy(pathreal,Connections[cnum].dirpath);
- strcat(pathreal,"/");
- strcat(pathreal,fname);
- if (sys_stat(pathreal,&sbuf) != 0)
- {
- DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
- continue;
- }
-
- mode = dos_mode(cnum,pathreal,&sbuf);
-
- if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
- {
- DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
- continue;
- }
- size = sbuf.st_size;
- mdate = sbuf.st_mtime;
- adate = sbuf.st_atime;
- cdate = sbuf.st_ctime;
- if(mode & aDIR)
- size = 0;
-
- DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
+ pstrcpy(pathreal,conn->dirpath);
+ if(needslash)
+ pstrcat(pathreal,"/");
+ pstrcat(pathreal,dname);
+
+ if (vfs_stat(conn,pathreal,&sbuf) != 0) {
+ /* Needed to show the msdfs symlinks as directories */
+ if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn))
+ || !is_msdfs_link(conn, pathreal)) {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
+ pathreal,strerror(errno)));
+ continue;
+ } else {
+ DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n",
+ pathreal));
+ sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
+ }
+ }
+
+ mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ continue;
+ }
+
+ size = sbuf.st_size;
+ allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
+ mdate = sbuf.st_mtime;
+ adate = sbuf.st_atime;
+ cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ cdate &= ~1;
+ mdate &= ~1;
+ adate &= ~1;
+ }
+
+ if(mode & aDIR)
+ size = 0;
+
+ DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
- found = True;
+ found = True;
+ }
}
- }
-
-
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif
-
- p = pdata;
- name_ptr = p;
-
- name_map_mangle(fname,False,SNUM(cnum));
- switch (info_level)
- {
- case 1:
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l1_fdateCreation,cdate);
- put_dos_date2(p,l1_fdateLastAccess,adate);
- put_dos_date2(p,l1_fdateLastWrite,mdate);
- SIVAL(p,l1_cbFile,size);
- SIVAL(p,l1_cbFileAlloc,ROUNDUP(size,1024));
- SSVAL(p,l1_attrFile,mode);
- SCVAL(p,l1_cchName,strlen(fname));
- strcpy(p + l1_achName, fname);
- name_ptr = p + l1_achName;
- p += l1_achName + strlen(fname) + 1;
- break;
-
- case 2:
- /* info_level 2 */
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- put_dos_date2(p,l2_fdateCreation,cdate);
- put_dos_date2(p,l2_fdateLastAccess,adate);
- put_dos_date2(p,l2_fdateLastWrite,mdate);
- SIVAL(p,l2_cbFile,size);
- SIVAL(p,l2_cbFileAlloc,ROUNDUP(size,1024));
- SSVAL(p,l2_attrFile,mode);
- SIVAL(p,l2_cbList,0); /* No extended attributes */
- SCVAL(p,l2_cchName,strlen(fname));
- strcpy(p + l2_achName, fname);
- name_ptr = p + l2_achName;
- p += l2_achName + strlen(fname) + 1;
- break;
-
- case 3:
- SIVAL(p,0,reskey);
- put_dos_date2(p,4,cdate);
- put_dos_date2(p,8,adate);
- put_dos_date2(p,12,mdate);
- SIVAL(p,16,size);
- SIVAL(p,20,ROUNDUP(size,1024));
- SSVAL(p,24,mode);
- SIVAL(p,26,4);
- CVAL(p,30) = strlen(fname);
- strcpy(p+31, fname);
- name_ptr = p+31;
- p += 31 + strlen(fname) + 1;
- break;
-
- case 4:
- if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
- }
- SIVAL(p,0,33+strlen(fname)+1);
- put_dos_date2(p,4,cdate);
- put_dos_date2(p,8,adate);
- put_dos_date2(p,12,mdate);
- SIVAL(p,16,size);
- SIVAL(p,20,ROUNDUP(size,1024));
- SSVAL(p,24,mode);
- CVAL(p,32) = strlen(fname);
- strcpy(p + 33, fname);
- name_ptr = p+33;
- p += 33 + strlen(fname) + 1;
- break;
-
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- was_8_3 = is_8_3(fname);
- len = 94+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- SIVAL(p,0,0); p += 4;
- if (!was_8_3) {
-#ifndef KANJI
- strcpy(p+2,unix2dos_format(fname,False));
-#else
- strcpy(p+2,fname);
-#endif
- if (!name_map_mangle(p+2,True,SNUM(cnum)))
- (p+2)[12] = 0;
- } else
- *(p+2) = 0;
- strupper(p+2);
- SSVAL(p,0,strlen(p+2));
- p += 2 + 24;
- /* name_ptr = p; */
- strcpy(p,fname); p += strlen(p);
- p = pdata + len;
- break;
-
- case SMB_FIND_FILE_DIRECTORY_INFO:
- len = 64+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- strcpy(p,fname);
- p = pdata + len;
- break;
+ name_map_mangle(fname,False,True,SNUM(conn));
+
+ p = pdata;
+ nameptr = p;
+
+ nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+
+ switch (info_level) {
+ case 1:
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l1_fdateCreation,cdate);
+ put_dos_date2(p,l1_fdateLastAccess,adate);
+ put_dos_date2(p,l1_fdateLastWrite,mdate);
+ SIVAL(p,l1_cbFile,(uint32)size);
+ SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l1_attrFile,mode);
+ p += l1_achName;
+ nameptr = p;
+ p += align_string(outbuf, p, 0);
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ SCVAL(nameptr, -1, len);
+ p += len;
+ break;
+
+ case 2:
+ if(requires_resume_key) {
+ SIVAL(p,0,reskey);
+ p += 4;
+ }
+ put_dos_date2(p,l2_fdateCreation,cdate);
+ put_dos_date2(p,l2_fdateLastAccess,adate);
+ put_dos_date2(p,l2_fdateLastWrite,mdate);
+ SIVAL(p,l2_cbFile,(uint32)size);
+ SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(p,l2_attrFile,mode);
+ SIVAL(p,l2_cbList,0); /* No extended attributes */
+ p += l2_achName;
+ nameptr = p;
+ len = srvstr_push(outbuf, p, fname, -1, STR_NOALIGN);
+ SCVAL(p, -1, len);
+ p += len;
+ *p++ = 0; /* craig from unisys pointed out we need this */
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ was_8_3 = is_8_3(fname, True);
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ q = p; p += 4;
+ SIVAL(p,0,0); p += 4;
+ if (!was_8_3) {
+ pstring mangled_name;
+ pstrcpy(mangled_name, fname);
+ name_map_mangle(mangled_name,True,True,SNUM(conn));
+ mangled_name[12] = 0;
+ len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER);
+ SSVAL(p, 0, len);
+ } else {
+ SSVAL(p,0,0);
+ *(p+2) = 0;
+ }
+ p += 2 + 24;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ SIVAL(q,0,len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ p += 4;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ SIVAL(p, -4, len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
-
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- len = 68+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- put_long_date(p,cdate); p += 8;
- put_long_date(p,adate); p += 8;
- put_long_date(p,mdate); p += 8;
- put_long_date(p,mdate); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- SIVAL(p,0,0); p += 4;
- strcpy(p,fname);
- p = pdata + len;
- break;
-
- case SMB_FIND_FILE_NAMES_INFO:
- len = 12+strlen(fname);
- len = (len + 3) & ~3;
- SIVAL(p,0,len); p += 4;
- SIVAL(p,0,reskey); p += 4;
- SIVAL(p,0,strlen(fname)); p += 4;
- strcpy(p,fname);
- p = pdata + len;
- break;
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ put_long_date(p,cdate); p += 8;
+ put_long_date(p,adate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ put_long_date(p,mdate); p += 8;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,allocation_size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
+ p += 4;
+ SIVAL(p,0,0); p += 4;
+
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ SIVAL(p, -4, len);
+ p += len;
+
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ p += 4;
+ SIVAL(p,0,reskey); p += 4;
+ p += 4;
+ len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+ SIVAL(p, -4, len);
+ p += len;
+ len = PTR_DIFF(p, pdata);
+ len = (len + 3) & ~3;
+ SIVAL(pdata,0,len);
+ p = pdata + len;
+ break;
+
+ default:
+ return(False);
+ }
- default:
- return(False);
- }
+ if (PTR_DIFF(p,pdata) > space_remaining) {
+ /* Move the dirptr back to prev_dirpos */
+ SeekDir(conn->dirptr, prev_dirpos);
+ *out_of_space = True;
+ DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+ return False; /* Not finished - just out of space */
+ }
- if (PTR_DIFF(p,pdata) > space_remaining) {
- /* Move the dirptr back to prev_dirpos */
- SeekDir(Connections[cnum].dirptr, prev_dirpos);
- *out_of_space = True;
- DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
- return False; /* Not finished - just out of space */
- }
+ /* Setup the last_filename pointer, as an offset from base_data */
+ *last_name_off = PTR_DIFF(nameptr,base_data);
+ /* Advance the data pointer to the next slot */
+ *ppdata = p;
- /* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(name_ptr,base_data);
- /* Advance the data pointer to the next slot */
- *ppdata = p;
- return(found);
+ return(found);
}
-
+
/****************************************************************************
- reply to a TRANS2_FINDFIRST
+ Reply to a TRANS2_FINDFIRST.
****************************************************************************/
-static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum,
- char **pparams, char **ppdata)
+
+static int call_trans2findfirst(connection_struct *conn,
+ char *inbuf, char *outbuf, int bufsize,
+ char **pparams, char **ppdata)
{
/* We must be careful here that we don't return more than the
allowed number of data bytes. If this means returning fewer than
@@ -554,6 +642,8 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
BOOL dont_descend = False;
BOOL out_of_space = False;
int space_remaining;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT sbuf;
*directory = *mask = 0;
@@ -573,68 +663,69 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
break;
default:
- return(ERROR(ERRDOS,ERRunknownlevel));
+ return(ERROR_DOS(ERRDOS,ERRunknownlevel));
}
- strcpy(directory, params + 12); /* Complete directory path with
- wildcard mask appended */
+ srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE);
+
+ RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
+
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if(!check_name(directory,conn)) {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
- DEBUG(5,("path=%s\n",directory));
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
+#endif
- unix_convert(directory,cnum);
- if(!check_name(directory,cnum)) {
- return(ERROR(ERRDOS,ERRbadpath));
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
- p = strrchr(directory,'/');
+ p = strrchr_m(directory,'/');
if(p == NULL) {
- strcpy(mask,directory);
- strcpy(directory,"./");
+ pstrcpy(mask,directory);
+ pstrcpy(directory,"./");
} else {
- strcpy(mask,p+1);
+ pstrcpy(mask,p+1);
*p = 0;
}
DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
- pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
- if(!*ppdata)
- return(ERROR(ERRDOS,ERRnomem));
- bzero(pdata,max_data_bytes);
+ pdata = Realloc(*ppdata, max_data_bytes + 1024);
+ if( pdata == NULL ) {
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
/* Realloc the params space */
- params = *pparams = Realloc(*pparams, 10);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
-
- dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRbadpath));
-
- /* convert the formatted masks */
- {
- p = mask;
- while (*p) {
- if (*p == '<') *p = '*';
- if (*p == '>') *p = '?';
- if (*p == '"') *p = '.';
- p++;
- }
+ params = Realloc(*pparams, 10);
+ if (params == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
-
- /* a special case for 16 bit apps */
- if (strequal(mask,"????????.???")) strcpy(mask,"*");
+ *pparams = params;
- /* handle broken clients that send us old 8.3 format */
- string_sub(mask,"????????","*");
- string_sub(mask,".???",".*");
+ dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
+ return(UNIXERROR(ERRDOS,ERRbadfile));
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
if(!(wcard = strdup(mask))) {
- dptr_close(dptr_num);
- return(ERROR(ERRDOS,ERRnomem));
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRnomem);
}
dptr_set_wcard(dptr_num, wcard);
@@ -646,8 +737,8 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
a different TRANS2 call. */
DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
- if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
+ conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
dont_descend = True;
p = pdata;
@@ -655,39 +746,61 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
out_of_space = False;
for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
+ {
+ BOOL got_exact_match = False;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0)
+ {
+ out_of_space = True;
+ finished = False;
+ }
+ else
{
+ finished = !get_lanman2_dir_entry(conn,
+ inbuf, outbuf,
+ mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished =
- !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space,
- &last_name_off);
- }
+ if (finished && out_of_space)
+ finished = False;
- if (finished && out_of_space)
- finished = False;
+ if (!finished && !out_of_space)
+ numentries++;
- if (!finished && !out_of_space)
- numentries++;
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
/* Check if we can close the dirptr */
if(close_after_first || (finished && close_if_end))
- {
- dptr_close(dptr_num);
- DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_num = -1;
- }
+ {
+ DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+ dptr_close(&dptr_num);
+ }
+
+ /*
+ * If there are no matching entries we must return ERRDOS/ERRbadfile -
+ * from observation of NT.
+ */
+
+ if(numentries == 0) {
+ dptr_close(&dptr_num);
+ return ERROR_DOS(ERRDOS,ERRbadfile);
+ }
/* At this point pdata points to numentries directory entries. */
@@ -701,22 +814,34 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
if ((! *directory) && dptr_path(dptr_num))
- sprintf(directory,"(%s)",dptr_path(dptr_num));
+ slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
+
+ DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
- DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
- timestring(),
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask,directory,cnum,dirtype,numentries));
+ /*
+ * Force a name mangle here to ensure that the
+ * mask as an 8.3 name is top of the mangled cache.
+ * The reasons for this are subtle. Don't remove
+ * this code unless you know what you are doing
+ * (see PR#13758). JRA.
+ */
+
+ if(!is_8_3( mask, False))
+ name_map_mangle(mask, True, True, SNUM(conn));
return(-1);
}
-
/****************************************************************************
- reply to a TRANS2_FINDNEXT
+ Reply to a TRANS2_FINDNEXT.
****************************************************************************/
-static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2findnext(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ char **pparams, char **ppdata)
{
/* We must be careful here that we don't return more than the
allowed number of data bytes. If this means returning fewer than
@@ -726,7 +851,7 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
- int16 dptr_num = SVAL(params,0);
+ int dptr_num = SVAL(params,0);
int maxentries = SVAL(params,2);
uint16 info_level = SVAL(params,4);
uint32 resume_key = IVAL(params,6);
@@ -734,6 +859,7 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
BOOL close_if_end = BITSETW(params+10,1);
BOOL requires_resume_key = BITSETW(params+10,2);
BOOL continue_bit = BITSETW(params+10,3);
+ pstring resume_name;
pstring mask;
pstring directory;
char *p;
@@ -745,11 +871,15 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
BOOL out_of_space = False;
int space_remaining;
- *mask = *directory = 0;
+ *mask = *directory = *resume_name = 0;
- DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, close_after_request=%d, close_if_end = %d requires_resume_key = %d resume_key = %d continue=%d level = %d\n",
+ srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE);
+
+ DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
+close_after_request=%d, close_if_end = %d requires_resume_key = %d \
+resume_key = %d resume name = %s continue=%d level = %d\n",
dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
- requires_resume_key, resume_key, continue_bit, info_level));
+ requires_resume_key, resume_key, resume_name, continue_bit, info_level));
switch (info_level)
{
@@ -763,89 +893,179 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
break;
default:
- return(ERROR(ERRDOS,ERRunknownlevel));
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
- pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
- if(!*ppdata)
- return(ERROR(ERRDOS,ERRnomem));
- bzero(pdata,max_data_bytes);
+ pdata = Realloc( *ppdata, max_data_bytes + 1024);
+ if(pdata == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
/* Realloc the params space */
- params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
- if(!params)
- return(ERROR(ERRDOS,ERRnomem));
+ params = Realloc(*pparams, 6*SIZEOFWORD);
+ if( params == NULL ) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *pparams = params;
/* Check that the dptr is valid */
- if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
- return(ERROR(ERRDOS,ERRnofiles));
+ if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num)))
+ return ERROR_DOS(ERRDOS,ERRnofiles);
- string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
+ string_set(&conn->dirpath,dptr_path(dptr_num));
/* Get the wildcard mask from the dptr */
if((p = dptr_wcard(dptr_num))== NULL) {
DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
- return (ERROR(ERRDOS,ERRnofiles));
+ return ERROR_DOS(ERRDOS,ERRnofiles);
}
- strcpy(mask, p);
- strcpy(directory,Connections[cnum].dirpath);
+ pstrcpy(mask, p);
+ pstrcpy(directory,conn->dirpath);
/* Get the attr mask from the dptr */
dirtype = dptr_attr(dptr_num);
- DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n",
+ DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
dptr_num, mask, dirtype,
- Connections[cnum].dirptr,
- TellDir(Connections[cnum].dirptr)));
+ (long)conn->dirptr,
+ TellDir(conn->dirptr)));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
- if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
dont_descend = True;
p = pdata;
space_remaining = max_data_bytes;
out_of_space = False;
- /* If we have a resume key - seek to the correct position. */
- if(requires_resume_key && !continue_bit)
- SeekDir(Connections[cnum].dirptr, resume_key);
+ /*
+ * Seek to the correct position. We no longer use the resume key but
+ * depend on the last file name instead.
+ */
+ if(requires_resume_key && *resume_name && !continue_bit)
+ {
+ /*
+ * Fix for NT redirector problem triggered by resume key indexes
+ * changing between directory scans. We now return a resume key of 0
+ * and instead look for the filename to continue from (also given
+ * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
+ * findfirst/findnext (as is usual) then the directory pointer
+ * should already be at the correct place. Check this by scanning
+ * backwards looking for an exact (ie. case sensitive) filename match.
+ * If we get to the beginning of the directory and haven't found it then scan
+ * forwards again looking for a match. JRA.
+ */
+
+ int current_pos, start_pos;
+ char *dname = NULL;
+ void *dirptr = conn->dirptr;
+ start_pos = TellDir(dirptr);
+ for(current_pos = start_pos; current_pos >= 0; current_pos--)
+ {
+ DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
+
+ SeekDir(dirptr, current_pos);
+ dname = ReadDirName(dirptr);
- for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
+ /*
+ * Remember, name_map_mangle is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we do the same
+ * here.
+ */
+
+ if(dname != NULL)
+ name_map_mangle( dname, False, True, SNUM(conn));
+
+ if(dname && strcsequal( resume_name, dname))
+ {
+ SeekDir(dirptr, current_pos+1);
+ DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
+ break;
+ }
+ }
+
+ /*
+ * Scan forward from start if not found going backwards.
+ */
+
+ if(current_pos < 0)
{
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished =
- !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space,
- &last_name_off);
- }
+ DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
+ SeekDir(dirptr, start_pos);
+ for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos))
+ {
+ /*
+ * Remember, name_map_mangle is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we do the same
+ * here.
+ */
+
+ if(dname != NULL)
+ name_map_mangle( dname, False, True, SNUM(conn));
+
+ if(dname && strcsequal( resume_name, dname))
+ {
+ SeekDir(dirptr, current_pos+1);
+ DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
+ break;
+ }
+ } /* end for */
+ } /* end if current_pos */
+ } /* end if requires_resume_key && !continue_bit */
- if (finished && out_of_space)
- finished = False;
+ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
+ {
+ BOOL got_exact_match = False;
- if (!finished && !out_of_space)
- numentries++;
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0)
+ {
+ out_of_space = True;
+ finished = False;
}
+ else
+ {
+ finished = !get_lanman2_dir_entry(conn,
+ inbuf, outbuf,
+ mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
+
+ if (finished && out_of_space)
+ finished = False;
+
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
/* Check if we can close the dirptr */
if(close_after_request || (finished && close_if_end))
- {
- dptr_close(dptr_num); /* This frees up the saved mask */
- DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
- dptr_num = -1;
- }
+ {
+ DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
+ dptr_close(&dptr_num); /* This frees up the saved mask */
+ }
/* Set up the return parameter block */
@@ -857,124 +1077,166 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
if ((! *directory) && dptr_path(dptr_num))
- sprintf(directory,"(%s)",dptr_path(dptr_num));
+ slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
- DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
- timestring(),
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask,directory,cnum,dirtype,numentries));
+ DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
return(-1);
}
/****************************************************************************
- reply to a TRANS2_QFSINFO (query filesystem info)
+ Reply to a TRANS2_QFSINFO (query filesystem info).
****************************************************************************/
-static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2qfsinfo(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ char **pparams, char **ppdata)
{
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *pdata = *ppdata;
char *params = *pparams;
uint16 info_level = SVAL(params,0);
- int data_len;
- struct stat st;
- char *vname = volume_label(SNUM(cnum));
-
- DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
+ int data_len, len;
+ SMB_STRUCT_STAT st;
+ char *vname = volume_label(SNUM(conn));
+ int snum = SNUM(conn);
+ char *fstype = lp_fstype(SNUM(conn));
- if(sys_stat(".",&st)!=0) {
+ DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
+
+ if(vfs_stat(conn,".",&st)!=0) {
DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
- return (ERROR(ERRSRV,ERRinvdevice));
+ return ERROR_DOS(ERRSRV,ERRinvdevice);
}
- pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
+ pdata = Realloc(*ppdata, max_data_bytes + 1024);
+ if ( pdata == NULL ) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *ppdata = pdata;
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
switch (info_level)
- {
+ {
case 1:
- {
- int dfree,dsize,bsize;
- data_len = 18;
- sys_disk_free(".",&bsize,&dfree,&dsize);
- SIVAL(pdata,l1_idFileSystem,st.st_dev);
- SIVAL(pdata,l1_cSectorUnit,bsize/512);
- SIVAL(pdata,l1_cUnit,dsize);
- SIVAL(pdata,l1_cUnitAvail,dfree);
- SSVAL(pdata,l1_cbSector,512);
- DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n",
- bsize, st.st_dev, bsize/512, dsize, dfree, 512));
- break;
- }
- case 2:
- {
- /* Return volume name */
- int volname_len = MIN(strlen(vname),11);
- data_len = l2_vol_szVolLabel + volname_len + 1;
- put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
- SCVAL(pdata,l2_vol_cch,volname_len);
- StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
- DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime,volname_len,
- pdata+l2_vol_szVolLabel));
+ {
+ SMB_BIG_UINT dfree,dsize,bsize;
+ data_len = 18;
+ conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ SIVAL(pdata,l1_idFileSystem,st.st_dev);
+ SIVAL(pdata,l1_cSectorUnit,bsize/512);
+ SIVAL(pdata,l1_cUnit,dsize);
+ SIVAL(pdata,l1_cUnitAvail,dfree);
+ SSVAL(pdata,l1_cbSector,512);
+ DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n",
+ (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize,
+ (unsigned int)dfree, 512));
break;
}
+ case 2:
+ /* Return volume name */
+ /*
+ * Add volume serial number - hash of a combination of
+ * the called hostname and the service name.
+ */
+ SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) );
+ len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1,
+ STR_TERMINATE);
+ SCVAL(pdata,l2_vol_cch,len);
+ data_len = l2_vol_szVolLabel + len;
+ DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
+ (unsigned)st.st_ctime, len, vname));
+ break;
+
case SMB_QUERY_FS_ATTRIBUTE_INFO:
- data_len = 12 + 2*strlen(FSTYPE_STRING);
- SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
- SIVAL(pdata,4,128); /* Max filename component length */
- SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
- PutUniCode(pdata+12,FSTYPE_STRING);
- break;
+ SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
+ (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */
+ SIVAL(pdata,4,255); /* Max filename component length */
+ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
+ and will think we can't do long filenames */
+ len = srvstr_push(outbuf, pdata+12, fstype, -1, 0);
+ SIVAL(pdata,8,len);
+ data_len = 12 + len;
+ break;
+
case SMB_QUERY_FS_LABEL_INFO:
- data_len = 4 + strlen(vname);
- SIVAL(pdata,0,strlen(vname));
- strcpy(pdata+4,vname);
- break;
+ len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE);
+ data_len = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
case SMB_QUERY_FS_VOLUME_INFO:
- data_len = 17 + strlen(vname);
- SIVAL(pdata,12,strlen(vname));
- strcpy(pdata+17,vname);
- break;
+ /*
+ * Add volume serial number - hash of a combination of
+ * the called hostname and the service name.
+ */
+ SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
+ (str_checksum(local_machine)<<16));
+
+ len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE);
+ SIVAL(pdata,12,len);
+ data_len = 18+len;
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
+ (int)strlen(vname),vname, lp_servicename(snum)));
+ break;
case SMB_QUERY_FS_SIZE_INFO:
- {
- int dfree,dsize,bsize;
- data_len = 24;
- sys_disk_free(".",&bsize,&dfree,&dsize);
- SIVAL(pdata,0,dsize);
- SIVAL(pdata,8,dfree);
- SIVAL(pdata,16,bsize/512);
- SIVAL(pdata,20,512);
- }
+ {
+ SMB_BIG_UINT dfree,dsize,bsize;
+ data_len = 24;
+ conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ SBIG_UINT(pdata,0,dsize);
+ SBIG_UINT(pdata,8,dfree);
+ SIVAL(pdata,16,bsize/512);
+ SIVAL(pdata,20,512);
break;
+ }
case SMB_QUERY_FS_DEVICE_INFO:
data_len = 8;
SIVAL(pdata,0,0); /* dev type */
SIVAL(pdata,4,0); /* characteristics */
break;
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
+ case SMB_MAC_QUERY_FS_INFO:
+ /*
+ * Thursby MAC extension... ONLY on NTFS filesystems
+ * once we do streams then we don't need this
+ */
+ if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
+ data_len = 88;
+ SIVAL(pdata,84,0x100); /* Don't support mac... */
+ break;
+ }
+ /* drop through */
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
- DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
+ DEBUG( 4, ( "%s info_level = %d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)), info_level) );
return -1;
}
/****************************************************************************
- reply to a TRANS2_SETFSINFO (set filesystem info)
+ Reply to a TRANS2_SETFSINFO (set filesystem info).
****************************************************************************/
-static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2setfsinfo(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize,
+ char **pparams, char **ppdata)
{
/* Just say yes we did it - there is nothing that
can be set here so it doesn't matter. */
int outsize;
DEBUG(3,("call_trans2setfsinfo\n"));
- if (!CAN_WRITE(cnum))
- return(ERROR(ERRSRV,ERRaccess));
+ if (!CAN_WRITE(conn))
+ return ERROR_DOS(ERRSRV,ERRaccess);
outsize = set_message(outbuf,10,0,True);
@@ -982,388 +1244,955 @@ static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsi
}
/****************************************************************************
- reply to a TRANS2_QFILEINFO (query file info by fileid)
+ Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
+ file name or file id).
****************************************************************************/
-static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
- int bufsize,int cnum,
+
+static int call_trans2qfilepathinfo(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize,
char **pparams,char **ppdata,
int total_data)
{
- char *params = *pparams;
- char *pdata = *ppdata;
- uint16 tran_call = SVAL(inbuf, smb_setup0);
- uint16 info_level;
- int mode=0;
- int size=0;
- unsigned int data_size;
- struct stat sbuf;
- pstring fname1;
- char *fname;
- char *p;
- int l,pos;
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ uint16 tran_call = SVAL(inbuf, smb_setup0);
+ uint16 info_level;
+ int mode=0;
+ SMB_OFF_T size=0;
+ SMB_OFF_T allocation_size=0;
+ unsigned int data_size;
+ SMB_STRUCT_STAT sbuf;
+ pstring fname;
+ char *base_name;
+ char *p;
+ SMB_OFF_T pos = 0;
+ BOOL bad_path = False;
+ BOOL delete_pending = False;
+ int len;
+ time_t c_time;
+
+ if (tran_call == TRANSACT2_QFILEINFO) {
+ files_struct *fsp = file_fsp(params,0);
+ info_level = SVAL(params,2);
+
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
+
+ if(fsp && (fsp->is_directory || fsp->stat_open)) {
+ /*
+ * This is actually a QFILEINFO on a directory
+ * handle (returned from an NT SMB). NT5.0 seems
+ * to do this call. JRA.
+ */
+ pstrcpy(fname, fsp->fsp_name);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) ||
+ (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) {
+ DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
+ delete_pending = fsp->directory_delete_on_close;
+ } else {
+ /*
+ * Original code - this is an open file.
+ */
+ CHECK_FSP(fsp,conn);
+
+ pstrcpy(fname, fsp->fsp_name);
+ if (vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
+ if((pos = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ delete_pending = fsp->delete_on_close;
+ }
+ } else {
+ /* qpathinfo */
+ info_level = SVAL(params,0);
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
- if (tran_call == TRANSACT2_QFILEINFO) {
- int16 fnum = SVAL(params,0);
- info_level = SVAL(params,2);
+ srvstr_pull(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- fname = Files[fnum].name;
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
- return(UNIXERROR(ERRDOS,ERRbadfid));
- }
- pos = lseek(Files[fnum].fd,0,SEEK_CUR);
- } else {
- /* qpathinfo */
- info_level = SVAL(params,0);
- fname = &fname1[0];
- strcpy(fname,&params[6]);
- unix_convert(fname,cnum);
- if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
- DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
- pos = 0;
- }
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) ||
+ (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) {
+ DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ }
- DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
- fname,info_level,tran_call,total_data));
+ DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
+ fname,info_level,tran_call,total_data));
+
+ p = strrchr_m(fname,'/');
+ if (!p)
+ base_name = fname;
+ else
+ base_name = p+1;
+
+ mode = dos_mode(conn,fname,&sbuf);
+ size = sbuf.st_size;
+ allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
+
+ if (mode & aDIR)
+ size = 0;
+
+ params = Realloc(*pparams,2);
+ if (params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
+ memset((char *)params,'\0',2);
+ data_size = max_data_bytes + 1024;
+ pdata = Realloc(*ppdata, data_size);
+ if ( pdata == NULL )
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *ppdata = pdata;
+
+ if (total_data > 0 && IVAL(pdata,0) == total_data) {
+ /* uggh, EAs for OS2 */
+ DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
+ }
- p = strrchr(fname,'/');
- if (!p)
- p = fname;
- else
- p++;
- l = strlen(p);
- mode = dos_mode(cnum,fname,&sbuf);
- size = sbuf.st_size;
- if (mode & aDIR) size = 0;
-
- params = *pparams = Realloc(*pparams,2); bzero(params,2);
- data_size = 1024;
- pdata = *ppdata = Realloc(*ppdata, data_size);
+ memset((char *)pdata,'\0',data_size);
+
+ c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+ if (lp_dos_filetime_resolution(SNUM(conn))) {
+ c_time &= ~1;
+ sbuf.st_atime &= ~1;
+ sbuf.st_mtime &= ~1;
+ sbuf.st_mtime &= ~1;
+ }
+
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ data_size = (info_level==1?22:26);
+ put_dos_date2(pdata,l1_fdateCreation,c_time);
+ put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
+ put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
+ SIVAL(pdata,l1_cbFile,(uint32)size);
+ SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
+ SSVAL(pdata,l1_attrFile,mode);
+ SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ data_size = 24;
+ put_dos_date2(pdata,0,c_time);
+ put_dos_date2(pdata,4,sbuf.st_atime);
+ put_dos_date2(pdata,8,sbuf.st_mtime);
+ SIVAL(pdata,12,(uint32)size);
+ SIVAL(pdata,16,(uint32)allocation_size);
+ SIVAL(pdata,20,mode);
+ break;
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ data_size = 4;
+ SIVAL(pdata,0,data_size);
+ break;
+
+ case 6:
+ return ERROR_DOS(ERRDOS,ERRbadfunc); /* os/2 needs this */
+
+ case SMB_FILE_BASIC_INFORMATION:
+ case SMB_QUERY_FILE_BASIC_INFO:
+
+ if (info_level == SMB_QUERY_FILE_BASIC_INFO)
+ data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
+ else {
+ data_size = 40;
+ SIVAL(pdata,36,0);
+ }
+ put_long_date(pdata,c_time);
+ put_long_date(pdata+8,sbuf.st_atime);
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
+ SIVAL(pdata,32,mode);
+
+ DEBUG(5,("SMB_QFBI - "));
+ {
+ time_t create_time = c_time;
+ DEBUG(5,("create: %s ", ctime(&create_time)));
+ }
+ DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
+ DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
+ DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
+ DEBUG(5,("mode: %x\n", mode));
+
+ break;
+
+ case SMB_FILE_STANDARD_INFORMATION:
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ data_size = 24;
+ /* Fake up allocation size. */
+ SOFF_T(pdata,0,allocation_size);
+ SOFF_T(pdata,8,size);
+ SIVAL(pdata,16,sbuf.st_nlink);
+ CVAL(pdata,20) = 0;
+ CVAL(pdata,21) = (mode&aDIR)?1:0;
+ break;
+
+ case SMB_FILE_EA_INFORMATION:
+ case SMB_QUERY_FILE_EA_INFO:
+ data_size = 4;
+ break;
+
+ /* Get the 8.3 name - used if NT SMB was negotiated. */
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ {
+ pstring short_name;
+
+ pstrcpy(short_name,base_name);
+ /* Mangle if not already 8.3 */
+ if(!is_8_3(short_name, True)) {
+ if(!name_map_mangle(short_name,True,True,SNUM(conn)))
+ *short_name = '\0';
+ }
+ len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_TERMINATE|STR_UPPER);
+ data_size = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
+ }
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * The first part of this code is essential
+ * to get security descriptors to work on mapped
+ * drives. Don't ask how I discovered this unless
+ * you like hearing about me suffering.... :-). JRA.
+ */
+ if(strequal(".", fname)) {
+ len = srvstr_push(outbuf, pdata+4, "\\", -1, STR_TERMINATE);
+ } else {
+ len = srvstr_push(outbuf, pdata+4, fname, -1, STR_TERMINATE);
+ }
+ data_size = 4 + len;
+ SIVAL(pdata,0,len);
+ break;
+
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ case SMB_QUERY_FILE_END_OF_FILEINFO:
+ data_size = 8;
+ SOFF_T(pdata,0,size);
+ break;
+
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ case SMB_QUERY_FILE_ALLOCATION_INFO:
+ data_size = 8;
+ SOFF_T(pdata,0,allocation_size);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ put_long_date(pdata,c_time);
+ put_long_date(pdata+8,sbuf.st_atime);
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
+ SIVAL(pdata,32,mode);
+ pdata += 40;
+ SOFF_T(pdata,0,allocation_size);
+ SOFF_T(pdata,8,size);
+ SIVAL(pdata,16,sbuf.st_nlink);
+ CVAL(pdata,20) = delete_pending;
+ CVAL(pdata,21) = (mode&aDIR)?1:0;
+ pdata += 24;
+ SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino);
+ pdata += 8; /* index number */
+ pdata += 4; /* EA info */
+ if (mode & aRONLY)
+ SIVAL(pdata,0,0xA9);
+ else
+ SIVAL(pdata,0,0xd01BF);
+ pdata += 4;
+ SOFF_T(pdata,0,pos); /* current offset */
+ pdata += 8;
+ SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
+ pdata += 4;
+ pdata += 4; /* alignment */
+ len = srvstr_push(outbuf, pdata+4, fname, -1, STR_TERMINATE);
+ SIVAL(pdata,0,len);
+ pdata += 4 + len;
+ data_size = PTR_DIFF(pdata,(*ppdata));
+ break;
+
+ case SMB_FILE_INTERNAL_INFORMATION:
+ /* This should be an index number - looks like dev/ino to me :-) */
+ SIVAL(pdata,0,sbuf.st_dev);
+ SIVAL(pdata,4,sbuf.st_ino);
+ data_size = 8;
+ break;
+
+ case SMB_FILE_ACCESS_INFORMATION:
+ SIVAL(pdata,0,0x12019F); /* ??? */
+ data_size = 4;
+ break;
+
+ case SMB_FILE_NAME_INFORMATION:
+ /* Pathname with leading '\'. */
+ {
+ pstring new_fname;
+ size_t byte_len;
+
+ pstrcpy(new_fname, "\\");
+ pstrcat(new_fname, fname);
+ byte_len = dos_PutUniCode(pdata+4,new_fname,max_data_bytes,False);
+ SIVAL(pdata,0,byte_len);
+ data_size = 4 + byte_len;
+ break;
+ }
+
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ data_size = 1;
+ CVAL(pdata,0) = delete_pending;
+ break;
+
+ case SMB_FILE_POSITION_INFORMATION:
+ data_size = 8;
+ SOFF_T(pdata,0,pos);
+ break;
+
+ case SMB_FILE_MODE_INFORMATION:
+ SIVAL(pdata,0,mode);
+ data_size = 4;
+ break;
+
+ case SMB_FILE_ALIGNMENT_INFORMATION:
+ SIVAL(pdata,0,0); /* No alignment needed. */
+ data_size = 4;
+ break;
- if (total_data > 0 && IVAL(pdata,0) == total_data) {
- /* uggh, EAs for OS2 */
- DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
#if 0
- SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
- return(-1);
-#else
- return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
+ /* Not yet finished... JRA */
+ case 1018:
+ {
+ pstring new_fname;
+ size_t byte_len;
+
+ put_long_date(pdata,c_time);
+ put_long_date(pdata+8,sbuf.st_atime);
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
+ SIVAL(pdata,32,mode);
+ SIVAL(pdata,36,0); /* ??? */
+ SIVAL(pdata,40,0x20); /* ??? */
+ SIVAL(pdata,44,0); /* ??? */
+ SOFF_T(pdata,48,size);
+ SIVAL(pdata,56,0x1); /* ??? */
+ SIVAL(pdata,60,0); /* ??? */
+ SIVAL(pdata,64,0); /* ??? */
+ SIVAL(pdata,68,length); /* Following string length in bytes. */
+ dos_PutUniCode(pdata+72,,False);
+ break;
+ }
#endif
- }
- bzero(pdata,data_size);
+ case SMB_FILE_ALTERNATE_NAME_INFORMATION:
+ /* Last component of pathname. */
+ {
+ size_t byte_len = dos_PutUniCode(pdata+4,fname,max_data_bytes,False);
+ SIVAL(pdata,0,byte_len);
+ data_size = 4 + byte_len;
+ break;
+ }
+
+ case SMB_FILE_STREAM_INFORMATION:
+ if (mode & aDIR) {
+ data_size = 0;
+ } else {
+ size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
+ SIVAL(pdata,0,0); /* ??? */
+ SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
+ SOFF_T(pdata,8,size);
+ SIVAL(pdata,16,allocation_size);
+ SIVAL(pdata,20,0); /* ??? */
+ data_size = 24 + byte_len;
+ }
+ break;
+
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ SOFF_T(pdata,0,size);
+ SIVAL(pdata,8,0); /* ??? */
+ SIVAL(pdata,12,0); /* ??? */
+ data_size = 16;
+ break;
+
+ case SMB_FILE_NETWORK_OPEN_INFORMATION:
+ put_long_date(pdata,c_time);
+ put_long_date(pdata+8,sbuf.st_atime);
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
+ SIVAL(pdata,32,allocation_size);
+ SOFF_T(pdata,40,size);
+ SIVAL(pdata,48,mode);
+ SIVAL(pdata,52,0); /* ??? */
+ data_size = 56;
+ break;
+
+ case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
+ SIVAL(pdata,0,mode);
+ SIVAL(pdata,4,0);
+ data_size = 8;
+ break;
- switch (info_level)
- {
- case 1:
- case 2:
- data_size = (info_level==1?22:26);
- put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime);
- put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
- put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime);
- SIVAL(pdata,l1_cbFile,size);
- SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
- SSVAL(pdata,l1_attrFile,mode);
- SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
- break;
+#if 0
+ /* NT4 server just returns "invalid query" to this - if we try to answer
+ it then NTws gets a BSOD! (tridge) */
+ case SMB_QUERY_FILE_STREAM_INFO:
+ SIVAL(pdata,0,pos);
+ SIVAL(pdata,4,(uint32)size);
+ SIVAL(pdata,12,(uint32)allocation_size);
+ len = srvstr_push(outbuf, pdata+24, fname, -1, STR_TERMINATE);
+ SIVAL(pdata,20,len);
+ data_size = 24 + len;
+ break;
+#endif
- case 3:
- data_size = 24;
- put_dos_date2(pdata,0,sbuf.st_ctime);
- put_dos_date2(pdata,4,sbuf.st_atime);
- put_dos_date2(pdata,8,sbuf.st_mtime);
- SIVAL(pdata,12,size);
- SIVAL(pdata,16,ROUNDUP(size,1024));
- SIVAL(pdata,20,mode);
- break;
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
- case 4:
- data_size = 4;
- SIVAL(pdata,0,data_size);
- break;
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, data_size);
- case 6:
- return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */
+ return(-1);
+}
- case SMB_QUERY_FILE_BASIC_INFO:
- data_size = 36;
- put_long_date(pdata,sbuf.st_ctime);
- put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
- SIVAL(pdata,32,mode);
- break;
+/****************************************************************************
+ Deal with the internal needs of setting the delete on close flag. Note that
+ as the tdb locking is recursive, it is safe to call this from within
+ open_file_shared. JRA.
+****************************************************************************/
- case SMB_QUERY_FILE_STANDARD_INFO:
- data_size = 22;
- SIVAL(pdata,0,size);
- SIVAL(pdata,8,size);
- SIVAL(pdata,16,sbuf.st_nlink);
- CVAL(pdata,20) = 0;
- CVAL(pdata,21) = (mode&aDIR)?1:0;
- break;
+NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close)
+{
+ /*
+ * Only allow delete on close for writable shares.
+ */
+
+ if (delete_on_close && !CAN_WRITE(fsp->conn)) {
+ DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ /*
+ * Only allow delete on close for files/directories opened with delete intent.
+ */
+
+ if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) {
+ DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
- case SMB_QUERY_FILE_EA_INFO:
- data_size = 4;
- break;
+ if(fsp->is_directory) {
+ fsp->directory_delete_on_close = delete_on_close;
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, directory %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ } else if(fsp->stat_open) {
- case SMB_QUERY_FILE_NAME_INFO:
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- data_size = 4 + l;
- SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
- break;
- case SMB_QUERY_FILE_ALLOCATION_INFO:
- case SMB_QUERY_FILE_END_OF_FILEINFO:
- data_size = 8;
- SIVAL(pdata,0,size);
- break;
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, stat open %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
- case SMB_QUERY_FILE_ALL_INFO:
- put_long_date(pdata,sbuf.st_ctime);
- put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
- SIVAL(pdata,32,mode);
- pdata += 40;
- SIVAL(pdata,0,size);
- SIVAL(pdata,8,size);
- SIVAL(pdata,16,sbuf.st_nlink);
- CVAL(pdata,20) = 0;
- CVAL(pdata,21) = (mode&aDIR)?1:0;
- pdata += 24;
- pdata += 8; /* index number */
- pdata += 4; /* EA info */
- if (mode & aRONLY)
- SIVAL(pdata,0,0xA9);
- else
- SIVAL(pdata,0,0xd01BF);
- pdata += 4;
- SIVAL(pdata,0,pos); /* current offset */
- pdata += 8;
- SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
- pdata += 4;
- pdata += 4; /* alignment */
- SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
- pdata += 4 + l;
- data_size = PTR_DIFF(pdata,(*ppdata));
- break;
+ } else {
- case SMB_QUERY_FILE_STREAM_INFO:
- data_size = 24 + l;
- SIVAL(pdata,0,pos);
- SIVAL(pdata,4,size);
- SIVAL(pdata,12,size);
- SIVAL(pdata,20,l);
- strcpy(pdata+24,fname);
- break;
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
+ files_struct *iterate_fsp;
- send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
+ /*
+ * Modify the share mode entry for all files open
+ * on this device and inode to tell other smbds we have
+ * changed the delete on close flag. This will be noticed
+ * in the close code, the last closer will delete the file
+ * if flag is set.
+ */
- return(-1);
+ DEBUG(10,("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
+
+ if (lock_share_entry_fsp(fsp) == False)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
+ DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n",
+ fsp->fsp_name ));
+ unlock_share_entry_fsp(fsp);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Release the lock.
+ */
+
+ unlock_share_entry_fsp(fsp);
+
+ /*
+ * Go through all files we have open on the same device and
+ * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
+ * Other smbd's that have this file open will look in the share_mode on close.
+ * take care of this (rare) case in close_file(). See the comment there.
+ * NB. JRA. We don't really need to do this anymore - all should be taken
+ * care of in the share_mode changes in the tdb.
+ */
+
+ for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode);
+ iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp))
+ fsp->delete_on_close = delete_on_close;
+
+ /*
+ * Set the delete on close flag in the fsp.
+ */
+ fsp->delete_on_close = delete_on_close;
+
+ DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+
+ }
+
+ return NT_STATUS_OK;
}
/****************************************************************************
- reply to a TRANS2_SETFILEINFO (set file info by fileid)
+ Reply to a TRANS2_SETFILEINFO (set file info by fileid).
****************************************************************************/
-static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
- int bufsize, int cnum, char **pparams,
+
+static int call_trans2setfilepathinfo(connection_struct *conn,
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **pparams,
char **ppdata, int total_data)
{
- char *params = *pparams;
- char *pdata = *ppdata;
- uint16 tran_call = SVAL(inbuf, smb_setup0);
- uint16 info_level;
- int mode=0;
- int size=0;
- struct utimbuf tvs;
- struct stat st;
- pstring fname1;
- char *fname;
- int fd = -1;
-
- if (!CAN_WRITE(cnum))
- return(ERROR(ERRSRV,ERRaccess));
-
- if (tran_call == TRANSACT2_SETFILEINFO) {
- int16 fnum = SVAL(params,0);
- info_level = SVAL(params,2);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
-
- fname = Files[fnum].name;
- fd = Files[fnum].fd;
-
- if(fstat(fd,&st)!=0) {
- DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRbadpath));
- }
- } else {
- /* set path info */
- info_level = SVAL(params,0);
- fname = fname1;
- strcpy(fname,&params[6]);
- unix_convert(fname,cnum);
- if(!check_name(fname, cnum))
- return(ERROR(ERRDOS,ERRbadpath));
-
- if(sys_stat(fname,&st)!=0) {
- DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRbadpath));
- }
- }
+ char *params = *pparams;
+ char *pdata = *ppdata;
+ uint16 tran_call = SVAL(inbuf, smb_setup0);
+ uint16 info_level;
+ int mode=0;
+ SMB_OFF_T size=0;
+ struct utimbuf tvs;
+ SMB_STRUCT_STAT sbuf;
+ pstring fname;
+ int fd = -1;
+ BOOL bad_path = False;
+ files_struct *fsp = NULL;
+
+ if (tran_call == TRANSACT2_SETFILEINFO) {
+ fsp = file_fsp(params,0);
+ info_level = SVAL(params,2);
+
+ if(fsp && (fsp->is_directory || fsp->stat_open)) {
+ /*
+ * This is actually a SETFILEINFO on a directory
+ * handle (returned from an NT SMB). NT5.0 seems
+ * to do this call. JRA.
+ */
+ pstrcpy(fname, fsp->fsp_name);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+ DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ } else if (fsp && fsp->print_file) {
+ /*
+ * Doing a DELETE_ON_CLOSE should cancel a print job.
+ */
+ if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
+ fsp->share_mode = FILE_DELETE_ON_CLOSE;
+
+ DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+ } else {
+ /*
+ * Original code - this is an open file.
+ */
+ CHECK_FSP(fsp,conn);
+
+ pstrcpy(fname, fsp->fsp_name);
+ fd = fsp->fd;
+
+ if (vfs_fstat(fsp,fd,&sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
+ }
+ } else {
+ /* set path info */
+ info_level = SVAL(params,0);
+ srvstr_pull(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if(!check_name(fname, conn)) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
+ if(!VALID_STAT(sbuf)) {
+ DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ }
- DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
- tran_call,fname,info_level,total_data));
+ if (!CAN_WRITE(conn))
+ return ERROR_DOS(ERRSRV,ERRaccess);
- /* Realloc the parameter and data sizes */
- params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
+ tran_call,fname,info_level,total_data));
- size = st.st_size;
- tvs.modtime = st.st_mtime;
- tvs.actime = st.st_atime;
- mode = dos_mode(cnum,fname,&st);
+ /* Realloc the parameter and data sizes */
+ params = Realloc(*pparams,2);
+ if(params == NULL)
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ *pparams = params;
- if (total_data > 0 && IVAL(pdata,0) == total_data) {
- /* uggh, EAs for OS2 */
- DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
- SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
+ SSVAL(params,0,0);
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-
- return(-1);
- }
+ size = sbuf.st_size;
+ tvs.modtime = sbuf.st_mtime;
+ tvs.actime = sbuf.st_atime;
+ mode = dos_mode(conn,fname,&sbuf);
- switch (info_level)
- {
- case 1:
- tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
- tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
- mode = SVAL(pdata,l1_attrFile);
- size = IVAL(pdata,l1_cbFile);
- break;
+ if (total_data > 4 && IVAL(pdata,0) == total_data) {
+ /* uggh, EAs for OS2 */
+ DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
+ return ERROR_DOS(ERRDOS,ERReasnotsupported);
+ }
- case 2:
- tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
- tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
- mode = SVAL(pdata,l1_attrFile);
- size = IVAL(pdata,l1_cbFile);
- break;
+ switch (info_level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ {
+ /* access time */
+ tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
+
+ /* write time */
+ tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
+
+ mode = SVAL(pdata,l1_attrFile);
+ size = IVAL(pdata,l1_cbFile);
+ break;
+ }
+
+ /* XXXX um, i don't think this is right.
+ it's also not in the cifs6.txt spec.
+ */
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ tvs.actime = make_unix_date2(pdata+8);
+ tvs.modtime = make_unix_date2(pdata+12);
+ size = IVAL(pdata,16);
+ mode = IVAL(pdata,24);
+ break;
+
+ /* XXXX nor this. not in cifs6.txt, either. */
+ case SMB_INFO_QUERY_ALL_EAS:
+ tvs.actime = make_unix_date2(pdata+8);
+ tvs.modtime = make_unix_date2(pdata+12);
+ size = IVAL(pdata,16);
+ mode = IVAL(pdata,24);
+ break;
+
+ case SMB_SET_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ {
+ /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
+ time_t write_time;
+ time_t changed_time;
+
+ /* Ignore create time at offset pdata. */
+
+ /* access time */
+ tvs.actime = interpret_long_date(pdata+8);
+
+ write_time = interpret_long_date(pdata+16);
+ changed_time = interpret_long_date(pdata+24);
+
+ tvs.modtime = MIN(write_time, changed_time);
+
+ /* Prefer a defined time to an undefined one. */
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
+ ? changed_time : write_time);
+
+ /* attributes */
+ mode = IVAL(pdata,32);
+ break;
+ }
+
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ {
+ int ret = -1;
+ SMB_OFF_T allocation_size = IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+ allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+#endif /* LARGE_SMB_OFF_T */
+ DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
+ fname, (double)allocation_size ));
+
+ if(allocation_size != sbuf.st_size) {
+ SMB_STRUCT_STAT new_sbuf;
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new allocation size to %.0f\n",
+ fname, (double)allocation_size ));
+
+ if (fd == -1) {
+ files_struct *new_fsp = NULL;
+ int access_mode = 0;
+ int action = 0;
+
+ if(global_oplock_break) {
+ /* Queue this file modify as we are the process of an oplock break. */
+
+ DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
+
+ push_oplock_pending_smb_message(inbuf, length);
+ return -1;
+ }
+
+ new_fsp = open_file_shared(conn, fname, &sbuf,
+ SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
+
+ if (new_fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ ret = vfs_allocate_file_space(new_fsp, allocation_size);
+ if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",new_fsp->fnum, strerror(errno)));
+ ret = -1;
+ }
+ close_file(new_fsp,True);
+ } else {
+ ret = vfs_allocate_file_space(fsp, size);
+ if (vfs_fstat(fsp,fd,&new_sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
+ ret = -1;
+ }
+ }
+ if (ret == -1)
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+
+ /* Allocate can trucate size... */
+ size = new_sbuf.st_size;
+ }
+
+ break;
+ }
+
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ {
+ size = IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+ size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+#endif /* LARGE_SMB_OFF_T */
+ DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
+ break;
+ }
+
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
+ {
+ BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
+ NTSTATUS status;
+
+ if (tran_call != TRANSACT2_SETFILEINFO)
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+
+ if (fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+
+ status = set_delete_on_close_internal(fsp, delete_on_close);
+
+ if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK))
+ return ERROR_NT(status);
- case 3:
- tvs.actime = make_unix_date2(pdata+8);
- tvs.modtime = make_unix_date2(pdata+12);
- size = IVAL(pdata,16);
- mode = IVAL(pdata,24);
- break;
+ break;
+ }
- case 4:
- tvs.actime = make_unix_date2(pdata+8);
- tvs.modtime = make_unix_date2(pdata+12);
- size = IVAL(pdata,16);
- mode = IVAL(pdata,24);
- break;
+ default:
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ }
- case SMB_SET_FILE_BASIC_INFO:
- pdata += 8; /* create time */
- tvs.actime = interpret_long_date(pdata); pdata += 8;
- tvs.modtime=MAX(interpret_long_date(pdata),interpret_long_date(pdata+8));
- pdata += 16;
- mode = IVAL(pdata,0);
- break;
+ /* get some defaults (no modifications) if any info is zero or -1. */
+ if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
+ tvs.actime = sbuf.st_atime;
+
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = sbuf.st_mtime;
+
+ DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
+ DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
+ DEBUG(6,("size: %.0f ", (double)size));
+ DEBUG(6,("mode: %x\n" , mode));
+
+ if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) ||
+ (info_level == SMB_SET_FILE_ALLOCATION_INFO) ||
+ (info_level == SMB_FILE_ALLOCATION_INFORMATION) ||
+ (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) {
+
+ /*
+ * Only do this test if we are not explicitly
+ * changing the size of a file.
+ */
+ if (!size)
+ size = sbuf.st_size;
+ }
- case SMB_SET_FILE_END_OF_FILE_INFO:
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return(ERROR(ERRDOS,ERRunknownlevel));
- size = IVAL(pdata,0);
- break;
+ /*
+ * Try and set the times, size and mode of this file -
+ * if they are different from the current values
+ */
+ if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
+ if(fsp != NULL) {
+ /*
+ * This was a setfileinfo on an open file.
+ * NT does this a lot. It's actually pointless
+ * setting the time here, as it will be overwritten
+ * on the next write, so we save the request
+ * away and will set it on file code. JRA.
+ */
+
+ if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
+ DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
+ fsp->pending_modtime = tvs.modtime;
+ }
+
+ } else {
+
+ DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
+
+ if(file_utime(conn, fname, &tvs)!=0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
- case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
- case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
- default:
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
+ /* check the mode isn't different, before changing it */
+ if ((mode != 0) && (mode != dos_mode(conn, fname, &sbuf))) {
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, mode ));
- if (!tvs.actime) tvs.actime = st.st_atime;
- if (!tvs.modtime) tvs.modtime = st.st_mtime;
- if (!size) size = st.st_size;
+ if(file_chmod(conn, fname, mode, NULL)) {
+ DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
- /* Try and set the times, size and mode of this file - if they are different
- from the current values */
- if(st.st_mtime != tvs.modtime || st.st_atime != tvs.actime) {
- if(sys_utime(fname, &tvs)!=0)
- return(ERROR(ERRDOS,ERRnoaccess));
- }
- if(mode != dos_mode(cnum,fname,&st) && dos_chmod(cnum,fname,mode,NULL)) {
- DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRnoaccess));
- }
- if(size != st.st_size) {
- if (fd == -1) {
- fd = sys_open(fname,O_RDWR,0);
- if (fd == -1)
- return(ERROR(ERRDOS,ERRbadpath));
- set_filelen(fd, size);
- close(fd);
- } else {
- set_filelen(fd, size);
- }
- }
+ if(size != sbuf.st_size) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
+ fname, (double)size ));
+
+ if (fd == -1) {
+ files_struct *new_fsp = NULL;
+ int access_mode = 0;
+ int action = 0;
+
+ if(global_oplock_break) {
+ /* Queue this file modify as we are the process of an oplock break. */
+
+ DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
+
+ push_oplock_pending_smb_message(inbuf, length);
+ return -1;
+ }
+
+ new_fsp = open_file_shared(conn, fname, &sbuf,
+ SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ 0, 0, &access_mode, &action);
+
+ if (new_fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ vfs_set_filelen(new_fsp, size);
+ close_file(new_fsp,True);
+ } else {
+ vfs_set_filelen(fsp, size);
+ }
+ }
- SSVAL(params,0,0);
+ SSVAL(params,0,0);
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
- return(-1);
+ return(-1);
}
/****************************************************************************
- reply to a TRANS2_MKDIR (make directory with extended attributes).
+ Reply to a TRANS2_MKDIR (make directory with extended attributes).
****************************************************************************/
-static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2mkdir(connection_struct *conn,
+ char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, char **ppdata)
{
char *params = *pparams;
pstring directory;
int ret = -1;
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
- if (!CAN_WRITE(cnum))
- return(ERROR(ERRSRV,ERRaccess));
+ if (!CAN_WRITE(conn))
+ return ERROR_DOS(ERRSRV,ERRaccess);
- strcpy(directory, &params[4]);
+ srvstr_pull(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE);
DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
- unix_convert(directory,cnum);
- if (check_name(directory,cnum))
- ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
+ unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if (check_name(directory,conn))
+ ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
if(ret < 0)
{
DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
/* Realloc the parameter and data sizes */
- params = *pparams = Realloc(*pparams,2);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ params = Realloc(*pparams,2);
+ if(params == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *pparams = params;
SSVAL(params,0,0);
@@ -1373,11 +2202,14 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
}
/****************************************************************************
- reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
- We don't actually do this - we just send a null response.
+ Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
+ We don't actually do this - we just send a null response.
****************************************************************************/
-static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2findnotifyfirst(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ char **pparams, char **ppdata)
{
static uint16 fnf_handle = 257;
char *params = *pparams;
@@ -1391,13 +2223,15 @@ static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int
case 2:
break;
default:
- return(ERROR(ERRDOS,ERRunknownlevel));
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
/* Realloc the parameter and data sizes */
- params = *pparams = Realloc(*pparams,6);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ params = Realloc(*pparams,6);
+ if(params == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *pparams = params;
SSVAL(params,0,fnf_handle);
SSVAL(params,2,0); /* No changes */
@@ -1414,20 +2248,25 @@ static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int
}
/****************************************************************************
- reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
- changes). Currently this does nothing.
+ Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
+ changes). Currently this does nothing.
****************************************************************************/
-static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
- int cnum, char **pparams, char **ppdata)
+
+static int call_trans2findnotifynext(connection_struct *conn,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
+ char **pparams, char **ppdata)
{
char *params = *pparams;
DEBUG(3,("call_trans2findnotifynext\n"));
/* Realloc the parameter and data sizes */
- params = *pparams = Realloc(*pparams,4);
- if(params == NULL)
- return(ERROR(ERRDOS,ERRnomem));
+ params = Realloc(*pparams,4);
+ if(params == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *pparams = params;
SSVAL(params,0,0); /* No changes */
SSVAL(params,2,0); /* No EA errors */
@@ -1438,209 +2277,388 @@ static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int
}
/****************************************************************************
- reply to a SMBfindclose (stop trans2 directory search)
+ Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
****************************************************************************/
-int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
+
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
+ char* outbuf, int length, int bufsize,
+ char** pparams, char** ppdata)
{
- int cnum;
- int outsize = 0;
- uint16 dptr_num=SVAL(inbuf,smb_vwv0);
+ char *params = *pparams;
+ pstring pathname;
+ int reply_size = 0;
+ int max_referral_level = SVAL(params,0);
- cnum = SVAL(inbuf,smb_tid);
- DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
+ DEBUG(10,("call_trans2getdfsreferral\n"));
- dptr_close(dptr_num);
+ if(!lp_host_msdfs())
+ return ERROR_DOS(ERRDOS,ERRbadfunc);
- outsize = set_message(outbuf,0,0,True);
+ srvstr_pull(inbuf, pathname, &params[2], sizeof(pathname), -1, STR_TERMINATE);
- DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
+ if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0)
+ return ERROR_DOS(ERRDOS,ERRbadfile);
+
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
+ send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size);
- return(outsize);
+ return(-1);
}
+#define LMCAT_SPL 0x53
+#define LMFUNC_GETJOBID 0x60
+
/****************************************************************************
- reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
+ Reply to a TRANS2_IOCTL - used for OS/2 printing.
****************************************************************************/
-int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
+
+static int call_trans2ioctl(connection_struct *conn, char* inbuf,
+ char* outbuf, int length, int bufsize,
+ char** pparams, char** ppdata)
{
- int cnum;
- int outsize = 0;
- int dptr_num= -1;
+ char *pdata = *ppdata;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv15);
+
+ if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ pdata = Realloc(*ppdata, 32);
+ if(pdata == NULL) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+ *ppdata = pdata;
+
+ /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
+ CAN ACCEPT THIS IN UNICODE. JRA. */
+
+ SSVAL(pdata,0,fsp->print_jobid); /* Job number */
+ srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
+ srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */
+ send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32);
+ return(-1);
+ } else {
+ DEBUG(2,("Unknown TRANS2_IOCTL\n"));
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+}
+
+/****************************************************************************
+ Reply to a SMBfindclose (stop trans2 directory search).
+****************************************************************************/
- cnum = SVAL(inbuf,smb_tid);
- dptr_num = SVAL(inbuf,smb_vwv0);
+int reply_findclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ int outsize = 0;
+ int dptr_num=SVALS(inbuf,smb_vwv0);
+ START_PROFILE(SMBfindclose);
- DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
+ DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
- /* We never give out valid handles for a
- findnotifyfirst - so any dptr_num is ok here.
- Just ignore it. */
+ dptr_close(&dptr_num);
- outsize = set_message(outbuf,0,0,True);
+ outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
+ DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
- return(outsize);
+ END_PROFILE(SMBfindclose);
+ return(outsize);
}
+/****************************************************************************
+ Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
+****************************************************************************/
+
+int reply_findnclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ int outsize = 0;
+ int dptr_num= -1;
+ START_PROFILE(SMBfindnclose);
+
+ dptr_num = SVAL(inbuf,smb_vwv0);
+
+ DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
+
+ /* We never give out valid handles for a
+ findnotifyfirst - so any dptr_num is ok here.
+ Just ignore it. */
+
+ outsize = set_message(outbuf,0,0,True);
+
+ DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
+
+ END_PROFILE(SMBfindnclose);
+ return(outsize);
+}
/****************************************************************************
- reply to a SMBtranss2 - just ignore it!
+ Reply to a SMBtranss2 - just ignore it!
****************************************************************************/
-int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_transs2(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
{
- DEBUG(4,("Ignoring transs2 of length %d\n",length));
- return(-1);
+ START_PROFILE(SMBtranss2);
+ DEBUG(4,("Ignoring transs2 of length %d\n",length));
+ END_PROFILE(SMBtranss2);
+ return(-1);
}
/****************************************************************************
- reply to a SMBtrans2
+ Reply to a SMBtrans2.
****************************************************************************/
-int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
+
+int reply_trans2(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int cnum = SVAL(inbuf,smb_tid);
- unsigned int total_params = SVAL(inbuf, smb_tpscnt);
- unsigned int total_data =SVAL(inbuf, smb_tdscnt);
+ int outsize = 0;
+ unsigned int total_params = SVAL(inbuf, smb_tpscnt);
+ unsigned int total_data =SVAL(inbuf, smb_tdscnt);
#if 0
- unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
- unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
- unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
- BOOL close_tid = BITSETW(inbuf+smb_flags,0);
- BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
- int32 timeout = IVALS(inbuf,smb_timeout);
+ unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
+ unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
+ unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
+ BOOL close_tid = BITSETW(inbuf+smb_flags,0);
+ BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
+ int32 timeout = IVALS(inbuf,smb_timeout);
#endif
- unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
- unsigned int tran_call = SVAL(inbuf, smb_setup0);
- char *params = NULL, *data = NULL;
- int num_params, num_params_sofar, num_data, num_data_sofar;
-
- outsize = set_message(outbuf,0,0,True);
+ unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
+ unsigned int tran_call = SVAL(inbuf, smb_setup0);
+ char *params = NULL, *data = NULL;
+ int num_params, num_params_sofar, num_data, num_data_sofar;
+ START_PROFILE(SMBtrans2);
+
+ if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) {
+ /* Queue this open message as we are the process of an
+ * oplock break. */
+
+ DEBUG(2,("reply_trans2: queueing message trans2open due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
+
+ push_oplock_pending_smb_message(inbuf, length);
+ END_PROFILE(SMBtrans2);
+ return -1;
+ }
+
+ if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
+ && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
- /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
- is so as a sanity check */
- if(suwcnt != 1 )
- {
- DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
- return(ERROR(ERRSRV,ERRerror));
- }
+ outsize = set_message(outbuf,0,0,True);
+
+ /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
+ is so as a sanity check */
+ if (suwcnt != 1) {
+ /*
+ * Need to have rc=0 for ioctl to get job id for OS/2.
+ * Network printing will fail if function is not successful.
+ * Similar function in reply.c will be used if protocol
+ * is LANMAN1.0 instead of LM1.2X002.
+ * Until DosPrintSetJobInfo with PRJINFO3 is supported,
+ * outbuf doesn't have to be set(only job id is used).
+ */
+ if ( (suwcnt == 4) && (tran_call == TRANSACT2_IOCTL) &&
+ (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+ DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
+ } else {
+ DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt));
+ DEBUG(2,("Transaction is %d\n",tran_call));
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+ }
- /* Allocate the space for the maximum needed parameters and data */
- if (total_params > 0)
- params = (char *)malloc(total_params);
- if (total_data > 0)
- data = (char *)malloc(total_data);
+ /* Allocate the space for the maximum needed parameters and data */
+ if (total_params > 0)
+ params = (char *)malloc(total_params);
+ if (total_data > 0)
+ data = (char *)malloc(total_data);
- if ((total_params && !params) || (total_data && !data))
- {
- DEBUG(2,("Out of memory in reply_trans2\n"));
- return(ERROR(ERRDOS,ERRnomem));
- }
-
- /* Copy the param and data bytes sent with this request into
- the params buffer */
- num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
- num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
-
- memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
- memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
+ if ((total_params && !params) || (total_data && !data)) {
+ DEBUG(2,("Out of memory in reply_trans2\n"));
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
- if(num_data_sofar < total_data || num_params_sofar < total_params)
- {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- send_smb(Client,outbuf);
-
- while( num_data_sofar < total_data || num_params_sofar < total_params)
- {
- receive_smb(Client,inbuf, 0);
-
- /* Ensure this is still a trans2 packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtranss2)
- {
- outsize = set_message(outbuf,0,0,True);
- DEBUG(2,("Invalid secondary trans2 packet\n"));
- free(params);
- free(data);
- return(ERROR(ERRSRV,ERRerror));
- }
+ /* Copy the param and data bytes sent with this request into
+ the params buffer */
+ num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
+ num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
+
+ if (num_params > total_params || num_data > total_data)
+ exit_server("invalid params in reply_trans2");
+
+ if(params)
+ memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
+ if(data)
+ memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
+
+ if(num_data_sofar < total_data || num_params_sofar < total_params) {
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,True);
+ if (!send_smb(smbd_server_fd(),outbuf))
+ exit_server("reply_trans2: send_smb failed.");
+
+ while (num_data_sofar < total_data ||
+ num_params_sofar < total_params) {
+ BOOL ret;
+
+ ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+
+ if ((ret &&
+ (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) {
+ outsize = set_message(outbuf,0,0,True);
+ if(ret)
+ DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
+ else
+ DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
+ (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
- /* Revise total_params and total_data in case they have changed downwards */
- total_params = SVAL(inbuf, smb_tpscnt);
- total_data = SVAL(inbuf, smb_tdscnt);
- num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
- num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
- memcpy( &params[ SVAL(inbuf, smb_spsdisp)],
- smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
- memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
- smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
+ /* Revise total_params and total_data in case
+ they have changed downwards */
+ total_params = SVAL(inbuf, smb_tpscnt);
+ total_data = SVAL(inbuf, smb_tdscnt);
+ num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
+ num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
+ if (num_params_sofar > total_params || num_data_sofar > total_data)
+ exit_server("data overflow in trans2");
+
+ memcpy( &params[ SVAL(inbuf, smb_spsdisp)],
+ smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
+ memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
+ smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
+ }
+ }
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
}
- }
-
- if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
- }
-
- /* Now we must call the relevant TRANS2 function */
- switch(tran_call)
- {
- case TRANSACT2_OPEN:
- outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_FINDFIRST:
- outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_FINDNEXT:
- outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_QFSINFO:
- outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_SETFSINFO:
- outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_QPATHINFO:
- case TRANSACT2_QFILEINFO:
- outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
- break;
- case TRANSACT2_SETPATHINFO:
- case TRANSACT2_SETFILEINFO:
- outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
- break;
- case TRANSACT2_FINDNOTIFYFIRST:
- outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_FINDNOTIFYNEXT:
- outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- case TRANSACT2_MKDIR:
- outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
- break;
- default:
- /* Error in request */
- DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
- if(params)
- free(params);
- if(data)
- free(data);
- return (ERROR(ERRSRV,ERRerror));
- }
- /* As we do not know how many data packets will need to be
- returned here the various call_trans2xxxx calls
- must send their own. Thus a call_trans2xxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
-
- if(params)
- free(params);
- if(data)
- free(data);
- return outsize; /* If a correct response was needed the call_trans2xxx
- calls have already sent it. If outsize != -1 then it is
- returning an error packet. */
+ /* Now we must call the relevant TRANS2 function */
+ switch(tran_call) {
+ case TRANSACT2_OPEN:
+ START_PROFILE_NESTED(Trans2_open);
+ outsize = call_trans2open(conn,
+ inbuf, outbuf, bufsize,
+ &params, &data);
+ END_PROFILE_NESTED(Trans2_open);
+ break;
+
+ case TRANSACT2_FINDFIRST:
+ START_PROFILE_NESTED(Trans2_findfirst);
+ outsize = call_trans2findfirst(conn, inbuf, outbuf,
+ bufsize, &params, &data);
+ END_PROFILE_NESTED(Trans2_findfirst);
+ break;
+
+ case TRANSACT2_FINDNEXT:
+ START_PROFILE_NESTED(Trans2_findnext);
+ outsize = call_trans2findnext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ END_PROFILE_NESTED(Trans2_findnext);
+ break;
+
+ case TRANSACT2_QFSINFO:
+ START_PROFILE_NESTED(Trans2_qfsinfo);
+ outsize = call_trans2qfsinfo(conn, inbuf, outbuf,
+ length, bufsize, &params,
+ &data);
+ END_PROFILE_NESTED(Trans2_qfsinfo);
+ break;
+
+ case TRANSACT2_SETFSINFO:
+ START_PROFILE_NESTED(Trans2_setfsinfo);
+ outsize = call_trans2setfsinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ END_PROFILE_NESTED(Trans2_setfsinfo);
+ break;
+
+ case TRANSACT2_QPATHINFO:
+ case TRANSACT2_QFILEINFO:
+ START_PROFILE_NESTED(Trans2_qpathinfo);
+ outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data, total_data);
+ END_PROFILE_NESTED(Trans2_qpathinfo);
+ break;
+ case TRANSACT2_SETPATHINFO:
+ case TRANSACT2_SETFILEINFO:
+ START_PROFILE_NESTED(Trans2_setpathinfo);
+ outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data,
+ total_data);
+ END_PROFILE_NESTED(Trans2_setpathinfo);
+ break;
+
+ case TRANSACT2_FINDNOTIFYFIRST:
+ START_PROFILE_NESTED(Trans2_findnotifyfirst);
+ outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ END_PROFILE_NESTED(Trans2_findnotifyfirst);
+ break;
+
+ case TRANSACT2_FINDNOTIFYNEXT:
+ START_PROFILE_NESTED(Trans2_findnotifynext);
+ outsize = call_trans2findnotifynext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ END_PROFILE_NESTED(Trans2_findnotifynext);
+ break;
+ case TRANSACT2_MKDIR:
+ START_PROFILE_NESTED(Trans2_mkdir);
+ outsize = call_trans2mkdir(conn, inbuf, outbuf, length,
+ bufsize, &params, &data);
+ END_PROFILE_NESTED(Trans2_mkdir);
+ break;
+
+ case TRANSACT2_GET_DFS_REFERRAL:
+ START_PROFILE_NESTED(Trans2_get_dfs_referral);
+ outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length,
+ bufsize, &params, &data);
+ END_PROFILE_NESTED(Trans2_get_dfs_referral);
+ break;
+ case TRANSACT2_IOCTL:
+ START_PROFILE_NESTED(Trans2_ioctl);
+ outsize = call_trans2ioctl(conn,inbuf,outbuf,length,
+ bufsize,&params,&data);
+ END_PROFILE_NESTED(Trans2_ioctl);
+ break;
+ default:
+ /* Error in request */
+ DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBtrans2);
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+
+ /* As we do not know how many data packets will need to be
+ returned here the various call_trans2xxxx calls
+ must send their own. Thus a call_trans2xxx routine only
+ returns a value other than -1 when it wants to send
+ an error packet.
+ */
+
+ SAFE_FREE(params);
+ SAFE_FREE(data);
+ END_PROFILE(SMBtrans2);
+ return outsize; /* If a correct response was needed the
+ call_trans2xxx calls have already sent
+ it. If outsize != -1 then it is returning */
}
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
new file mode 100644
index 00000000000..650d9270cbb
--- /dev/null
+++ b/source/smbd/uid.c
@@ -0,0 +1,709 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* what user is current? */
+extern struct current_user current_user;
+
+/****************************************************************************
+ Become the guest user without changing the security context stack.
+****************************************************************************/
+
+BOOL change_to_guest(void)
+{
+ static struct passwd *pass=NULL;
+ static uid_t guest_uid = (uid_t)-1;
+ static gid_t guest_gid = (gid_t)-1;
+ static fstring guest_name;
+
+ if (!pass) {
+ pass = sys_getpwnam(lp_guestaccount());
+ if (!pass)
+ return(False);
+ guest_uid = pass->pw_uid;
+ guest_gid = pass->pw_gid;
+ fstrcpy(guest_name, pass->pw_name);
+ }
+
+#ifdef AIX
+ /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
+ setting IDs */
+ initgroups(guest_name, guest_gid);
+#endif
+
+ set_sec_ctx(guest_uid, guest_gid, 0, NULL, NULL);
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ return True;
+}
+
+/*******************************************************************
+ Check if a username is OK.
+********************************************************************/
+
+static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
+{
+ int i;
+ for (i=0;i<conn->uid_cache.entries;i++)
+ if (conn->uid_cache.list[i] == vuser->uid)
+ return(True);
+
+ if (!user_ok(vuser->user.unix_name,snum))
+ return(False);
+
+ i = conn->uid_cache.entries % UID_CACHE_SIZE;
+ conn->uid_cache.list[i] = vuser->uid;
+
+ if (conn->uid_cache.entries < UID_CACHE_SIZE)
+ conn->uid_cache.entries++;
+
+ return(True);
+}
+
+/****************************************************************************
+ Become the user of a connection number without changing the security context
+ stack, but modify the currnet_user entries.
+****************************************************************************/
+
+BOOL change_to_user(connection_struct *conn, uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ int snum;
+ gid_t gid;
+ uid_t uid;
+ char group_c;
+ BOOL must_free_token = False;
+ NT_USER_TOKEN *token = NULL;
+
+ if (!conn) {
+ DEBUG(2,("change_to_user: Connection not open\n"));
+ return(False);
+ }
+
+ /*
+ * We need a separate check in security=share mode due to vuid
+ * always being UID_FIELD_INVALID. If we don't do this then
+ * in share mode security we are *always* changing uid's between
+ * SMB's - this hurts performance - Badly.
+ */
+
+ if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
+ (current_user.uid == conn->uid)) {
+ DEBUG(4,("change_to_user: Skipping user change - already user\n"));
+ return(True);
+ } else if ((current_user.conn == conn) &&
+ (vuser != 0) && (current_user.vuid == vuid) &&
+ (current_user.uid == vuser->uid)) {
+ DEBUG(4,("change_to_user: Skipping user change - already user\n"));
+ return(True);
+ }
+
+ snum = SNUM(conn);
+
+ if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
+ return False;
+
+ if (conn->force_user ||
+ conn->admin_user ||
+ (lp_security() == SEC_SHARE)) {
+ uid = conn->uid;
+ gid = conn->gid;
+ current_user.groups = conn->groups;
+ current_user.ngroups = conn->ngroups;
+ token = conn->nt_user_token;
+ } else {
+ if (!vuser) {
+ DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid));
+ return(False);
+ }
+ uid = vuser->uid;
+ gid = vuser->gid;
+ current_user.ngroups = vuser->n_groups;
+ current_user.groups = vuser->groups;
+ token = vuser->nt_user_token;
+ }
+
+ /*
+ * See if we should force group for this service.
+ * If so this overrides any group set in the force
+ * user code.
+ */
+
+ if((group_c = *lp_force_group(snum))) {
+ BOOL is_guest = False;
+
+ if(group_c == '+') {
+
+ /*
+ * Only force group if the user is a member of
+ * the service group. Check the group memberships for
+ * this user (we already have this) to
+ * see if we should force the group.
+ */
+
+ int i;
+ for (i = 0; i < current_user.ngroups; i++) {
+ if (current_user.groups[i] == conn->gid) {
+ gid = conn->gid;
+ break;
+ }
+ }
+ } else {
+ gid = conn->gid;
+ }
+
+ /*
+ * We've changed the group list in the token - we must
+ * re-create it.
+ */
+
+ if (vuser && vuser->guest)
+ is_guest = True;
+
+ token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL);
+ must_free_token = True;
+ }
+
+ set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
+
+ /*
+ * Free the new token (as set_sec_ctx copies it).
+ */
+
+ if (must_free_token)
+ delete_nt_token(&token);
+
+ current_user.conn = conn;
+ current_user.vuid = vuid;
+
+ DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+
+ return(True);
+}
+
+/****************************************************************************
+ Go back to being root without changing the security context stack,
+ but modify the current_user entries.
+****************************************************************************/
+
+BOOL change_to_root_user(void)
+{
+ set_root_sec_ctx();
+
+ DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ return(True);
+}
+
+/****************************************************************************
+ Become the user of an authenticated connected named pipe.
+ When this is called we are currently running as the connection
+ user. Doesn't modify current_user.
+****************************************************************************/
+
+BOOL become_authenticated_pipe_user(pipes_struct *p)
+{
+ if (!push_sec_ctx())
+ return False;
+
+ set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid,
+ p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
+
+ return True;
+}
+
+/****************************************************************************
+ Unbecome the user of an authenticated connected named pipe.
+ When this is called we are running as the authenticated pipe
+ user and need to go back to being the connection user. Doesn't modify
+ current_user.
+****************************************************************************/
+
+BOOL unbecome_authenticated_pipe_user(void)
+{
+ return pop_sec_ctx();
+}
+
+/****************************************************************************
+ Utility functions used by become_xxx/unbecome_xxx.
+****************************************************************************/
+
+struct conn_ctx {
+ connection_struct *conn;
+ uint16 vuid;
+};
+
+/* A stack of current_user connection contexts. */
+
+static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
+static int conn_ctx_stack_ndx;
+
+static void push_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check we don't overflow our stack */
+
+ if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
+ DEBUG(0, ("Connection context stack overflow!\n"));
+ smb_panic("Connection context stack overflow!\n");
+ }
+
+ /* Store previous user context */
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ ctx_p->conn = current_user.conn;
+ ctx_p->vuid = current_user.vuid;
+
+ DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
+ (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
+
+ conn_ctx_stack_ndx++;
+}
+
+static void pop_conn_ctx(void)
+{
+ struct conn_ctx *ctx_p;
+
+ /* Check for stack underflow. */
+
+ if (conn_ctx_stack_ndx == 0) {
+ DEBUG(0, ("Connection context stack underflow!\n"));
+ smb_panic("Connection context stack underflow!\n");
+ }
+
+ conn_ctx_stack_ndx--;
+ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
+
+ current_user.conn = ctx_p->conn;
+ current_user.vuid = ctx_p->vuid;
+
+ ctx_p->conn = NULL;
+ ctx_p->vuid = UID_FIELD_INVALID;
+}
+
+void init_conn_ctx(void)
+{
+ int i;
+
+ /* Initialise connection context stack */
+ for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+ conn_ctx_stack[i].conn = NULL;
+ conn_ctx_stack[i].vuid = UID_FIELD_INVALID;
+ }
+}
+
+/****************************************************************************
+ Temporarily become a root user. Must match with unbecome_root(). Saves and
+ restores the connection context.
+****************************************************************************/
+
+void become_root(void)
+{
+ push_sec_ctx();
+ push_conn_ctx();
+ set_root_sec_ctx();
+}
+
+/* Unbecome the root user */
+
+void unbecome_root(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+}
+
+/****************************************************************************
+ Push the current security context then force a change via change_to_user().
+ Saves and restores the connection context.
+****************************************************************************/
+
+BOOL become_user(connection_struct *conn, uint16 vuid)
+{
+ if (!push_sec_ctx())
+ return False;
+
+ push_conn_ctx();
+
+ if (!change_to_user(conn, vuid)) {
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return False;
+ }
+
+ return True;
+}
+
+BOOL unbecome_user(void)
+{
+ pop_sec_ctx();
+ pop_conn_ctx();
+ return True;
+}
+
+/*****************************************************************
+ Convert the suplimentary SIDs returned in a netlogon into UNIX
+ group gid_t's. Add to the total group array.
+*****************************************************************/
+
+void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok)
+{
+ int total_groups;
+ int current_n_groups = *n_groups;
+ gid_t *final_groups = NULL;
+ size_t i;
+ NT_USER_TOKEN *ptok = *pptok;
+ NT_USER_TOKEN *new_tok = NULL;
+
+ if (!ptok || (ptok->num_sids == 0))
+ return;
+
+ new_tok = dup_nt_token(ptok);
+ if (!new_tok) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n"));
+ return;
+ }
+ /* Leave the allocated space but empty the number of SIDs. */
+ new_tok->num_sids = 0;
+
+ total_groups = current_n_groups + ptok->num_sids;
+
+ final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t));
+ if (!final_groups) {
+ DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n"));
+ delete_nt_token(&new_tok);
+ return;
+ }
+
+ memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t));
+ for (i = 0; i < ptok->num_sids; i++) {
+ enum SID_NAME_USE sid_type;
+ gid_t new_grp;
+
+ if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) {
+ /*
+ * Don't add the gid_t if it is already in the current group
+ * list. Some UNIXen don't like the same group more than once.
+ */
+ int j;
+
+ for (j = 0; j < current_n_groups; j++)
+ if (final_groups[j] == new_grp)
+ break;
+
+ if ( j == current_n_groups) {
+ /* Group not already present. */
+ final_groups[current_n_groups++] = new_grp;
+ }
+ } else {
+ /* SID didn't map. Copy to the new token to be saved. */
+ sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]);
+ }
+ }
+
+ SAFE_FREE(*pp_groups);
+ *pp_groups = final_groups;
+ *n_groups = current_n_groups;
+
+ /* Replace the old token with the truncated one. */
+ delete_nt_token(&ptok);
+ *pptok = new_tok;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert name to SID function.
+ Tries winbind first - then uses local lookup.
+*****************************************************************/
+
+BOOL lookup_name(const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
+{
+ extern pstring global_myname;
+ extern fstring global_myworkgroup;
+ fstring sid;
+ char *sep = lp_winbind_separator();
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ if (!winbind_lookup_name(name, psid, name_type) || (*name_type != SID_NAME_USER) ) {
+ BOOL ret = False;
+
+ DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
+
+ /* If we are looking up a domain user, make sure it is
+ for the local machine only */
+
+ if (strchr_m(name, sep[0]) || strchr_m(name, '\\')) {
+ fstring domain, username;
+
+ split_domain_name(name, domain, username);
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ if (strequal(domain, global_myworkgroup)) {
+ fstrcpy(domain, global_myname);
+ ret = local_lookup_name(domain, username, psid, name_type);
+ }
+ /* No break is deliberate here. JRA. */
+ default:
+ if (strcasecmp(global_myname, domain) != 0) {
+ DEBUG(5, ("lookup_name: domain %s is not local\n", domain));
+ ret = local_lookup_name(global_myname, username, psid, name_type);
+ }
+ }
+ } else {
+ ret = local_lookup_name(global_myname, name, psid, name_type);
+ }
+
+ if (ret) {
+ DEBUG(10,
+ ("lookup_name: (local) %s -> SID %s (type %u)\n",
+ name, sid_to_string(sid,psid),
+ (unsigned int)*name_type ));
+ } else {
+ DEBUG(10,("lookup name: (local) %s failed.\n", name));
+ }
+
+ return ret;
+ }
+
+ DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
+ name, sid_to_string(sid, psid),
+ (unsigned int)*name_type));
+ return True;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to name function.
+ Tries winbind first - then uses local lookup.
+*****************************************************************/
+
+BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
+{
+ if (!name_type)
+ return False;
+
+ *name_type = SID_NAME_UNKNOWN;
+
+ /* Check if this is our own sid. This should perhaps be done by
+ winbind? For the moment handle it here. */
+
+ if (sid->num_auths == 5) {
+ DOM_SID tmp_sid;
+ uint32 rid;
+
+ sid_copy(&tmp_sid, sid);
+ sid_split_rid(&tmp_sid, &rid);
+
+ if (sid_equal(&global_sam_sid, &tmp_sid)) {
+
+ return map_domain_sid_to_name(&tmp_sid, dom_name) &&
+ local_lookup_sid(sid, name, name_type);
+ }
+ }
+
+ if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
+ fstring sid_str;
+ DOM_SID tmp_sid;
+ uint32 rid;
+
+ DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
+
+ sid_copy(&tmp_sid, sid);
+ sid_split_rid(&tmp_sid, &rid);
+ return map_domain_sid_to_name(&tmp_sid, dom_name) &&
+ lookup_known_rid(&tmp_sid, rid, name, name_type);
+ }
+ return True;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert uid_t to SID function.
+ Tries winbind first - then uses local lookup.
+ Returns SID pointer.
+*****************************************************************/
+
+DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
+{
+ uid_t low, high;
+ fstring sid;
+
+ if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
+ if (winbind_uid_to_sid(psid, uid)) {
+
+ DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)uid, sid_to_string(sid, psid)));
+
+ return psid;
+ }
+ }
+
+ local_uid_to_sid(psid, uid);
+
+ DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
+
+ return psid;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert gid_t to SID function.
+ Tries winbind first - then uses local lookup.
+ Returns SID pointer.
+*****************************************************************/
+
+DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
+{
+ gid_t low, high;
+ fstring sid;
+
+ if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
+ if (winbind_gid_to_sid(psid, gid)) {
+
+ DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
+ (unsigned int)gid, sid_to_string(sid, psid)));
+
+ return psid;
+ }
+ }
+
+ local_gid_to_sid(psid, gid);
+
+ DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
+
+ return psid;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to uid function.
+ Tries winbind first - then uses local lookup.
+ Returns True if this name is a user sid and the conversion
+ was done correctly, False if not. sidtype is set by this function.
+*****************************************************************/
+
+BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
+{
+ fstring dom_name, name, sid_str;
+ enum SID_NAME_USE name_type;
+
+ *sidtype = SID_NAME_UNKNOWN;
+
+ /*
+ * First we must look up the name and decide if this is a user sid.
+ */
+
+ if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
+ DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
+ sid_to_string(sid_str, psid) ));
+
+ return local_sid_to_uid(puid, psid, sidtype);
+ }
+
+ /*
+ * Ensure this is a user sid.
+ */
+
+ if (name_type != SID_NAME_USER) {
+ DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n",
+ (unsigned int)name_type ));
+ return False;
+ }
+
+ *sidtype = SID_NAME_USER;
+
+ /*
+ * Get the uid for this SID.
+ */
+
+ if (!winbind_sid_to_uid(puid, psid)) {
+ DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed.\n",
+ sid_to_string(sid_str, psid) ));
+ return False;
+ }
+
+ DEBUG(10,("sid_to_uid: winbindd %s -> %u\n",
+ sid_to_string(sid_str, psid),
+ (unsigned int)*puid ));
+
+ return True;
+}
+
+/*****************************************************************
+ *THE CANONICAL* convert SID to gid function.
+ Tries winbind first - then uses local lookup.
+ Returns True if this name is a user sid and the conversion
+ was done correctly, False if not.
+*****************************************************************/
+
+BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
+{
+ fstring dom_name, name, sid_str;
+ enum SID_NAME_USE name_type;
+
+ *sidtype = SID_NAME_UNKNOWN;
+
+ /*
+ * First we must look up the name and decide if this is a group sid.
+ */
+
+ if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
+ DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
+ sid_to_string(sid_str, psid) ));
+
+ return local_sid_to_gid(pgid, psid, sidtype);
+ }
+
+ /*
+ * Ensure this is a group sid.
+ */
+
+ if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
+ DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
+ (unsigned int)name_type ));
+
+ return local_sid_to_gid(pgid, psid, sidtype);
+ }
+
+ *sidtype = name_type;
+
+ /*
+ * Get the gid for this SID.
+ */
+
+ if (!winbind_sid_to_gid(pgid, psid)) {
+ DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed.\n",
+ sid_to_string(sid_str, psid) ));
+ return False;
+ }
+
+ DEBUG(10,("sid_to_gid: winbindd %s -> %u\n",
+ sid_to_string(sid_str, psid),
+ (unsigned int)*pgid ));
+
+ return True;
+}
diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c
new file mode 100644
index 00000000000..92e001cd036
--- /dev/null
+++ b/source/smbd/utmp.c
@@ -0,0 +1,607 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ utmp routines
+ Copyright (C) T.D.Lee@durham.ac.uk 1999
+ Heavily modified by Andrew Bartlett and Tridge, April 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_UTMP
+
+/****************************************************************************
+Reflect connection status in utmp/wtmp files.
+ T.D.Lee@durham.ac.uk September 1999
+
+ With grateful thanks since then to many who have helped port it to
+ different operating systems. The variety of OS quirks thereby
+ uncovered is amazing...
+
+Hints for porting:
+ o Always attempt to use programmatic interface (pututline() etc.)
+ Indeed, at present only programmatic use is supported.
+ o The only currently supported programmatic interface to "wtmp{,x}"
+ is through "updwtmp*()" routines.
+ o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
+ o The HAVE_* items should identify supported features.
+ o If at all possible, avoid "if defined(MY-OS)" constructions.
+
+OS observations and status:
+ Almost every OS seems to have its own quirks.
+
+ Solaris 2.x:
+ Tested on 2.6 and 2.7; should be OK on other flavours.
+ AIX:
+ Apparently has utmpx.h but doesn't implement.
+ OSF:
+ Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
+ Redhat 6:
+ utmpx.h seems not to set default filenames. non-x better.
+ IRIX 6.5:
+ Not tested. Appears to have "x".
+ HP-UX 9.x:
+ Not tested. Appears to lack "x".
+ HP-UX 10.x:
+ Not tested.
+ "updwtmp*()" routines seem absent, so no current wtmp* support.
+ Has "ut_addr": probably trivial to implement (although remember
+ that IPv6 is coming...).
+
+ FreeBSD:
+ No "putut*()" type of interface.
+ No "ut_type" and associated defines.
+ Write files directly. Alternatively use its login(3)/logout(3).
+ SunOS 4:
+ Not tested. Resembles FreeBSD, but no login()/logout().
+
+lastlog:
+ Should "lastlog" files, if any, be updated?
+ BSD systems (SunOS 4, FreeBSD):
+ o Prominent mention on man pages.
+ System-V (e.g. Solaris 2):
+ o No mention on man pages, even under "man -k".
+ o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
+ not to touch it.
+ o Despite downplaying (above), nevertheless has <lastlog.h>.
+ So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
+
+Notes:
+ Each connection requires a small number (starting at 0, working up)
+ to represent the line (unum). This must be unique within and across
+ all smbd processes.
+
+ The 4 byte 'ut_id' component is vital to distinguish connections,
+ of which there could be several hundered or even thousand.
+ Entries seem to be printable characters, with optional NULL pads.
+
+ We need to be distinct from other entries in utmp/wtmp.
+
+ Observed things: therefore avoid them. Add to this list please.
+ From Solaris 2.x (because that's what I have):
+ 'sN' : run-levels; N: [0-9]
+ 'co' : console
+ 'CC' : arbitrary things; C: [a-z]
+ 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ '/NNN' : Solaris CDE
+ 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
+ Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
+ but differences have been seen.
+
+ Arbitrarily I have chosen to use a distinctive 'SM' for the
+ first two bytes.
+
+ The remaining two encode the "unum" (see above).
+
+ For "utmp consolidate" the suggestion was made to encode the pid into
+ those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8)
+ is migrating to pids > 16 bits, so we ought not to do this.
+
+****************************************************************************/
+
+#include <utmp.h>
+
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+/* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
+/* Some System-V systems (e.g. Solaris 2) declare this too. */
+#ifdef HAVE_LASTLOG_H
+#include <lastlog.h>
+#endif
+
+/****************************************************************************
+ Obtain/release a small number (0 upwards) unique within and across smbds.
+****************************************************************************/
+/*
+ * Need a "small" number to represent this connection, unique within this
+ * smbd and across all smbds.
+ *
+ * claim:
+ * Start at 0, hunt up for free, unique number "unum" by attempting to
+ * store it as a key in a tdb database:
+ * key: unum data: pid+conn
+ * Also store its inverse, ready for yield function:
+ * key: pid+conn data: unum
+ *
+ * yield:
+ * Find key: pid+conn; data is unum; delete record
+ * Find key: unum ; delete record.
+ *
+ * Comment:
+ * The claim algorithm (a "for" loop attempting to store numbers in a tdb
+ * database) will be increasingly inefficient with larger numbers of
+ * connections. Is it possible to write a suitable primitive within tdb?
+ *
+ * However, by also storing the inverse key/data pair, we at least make
+ * the yield algorithm efficient.
+ */
+
+/****************************************************************************
+ Default paths to various {u,w}tmp{,x} files.
+****************************************************************************/
+
+#ifdef HAVE_UTMPX_H
+
+static const char *ux_pathname =
+# if defined (UTMPX_FILE)
+ UTMPX_FILE ;
+# elif defined (_UTMPX_FILE)
+ _UTMPX_FILE ;
+# elif defined (_PATH_UTMPX)
+ _PATH_UTMPX ;
+# else
+ "" ;
+# endif
+
+static const char *wx_pathname =
+# if defined (WTMPX_FILE)
+ WTMPX_FILE ;
+# elif defined (_WTMPX_FILE)
+ _WTMPX_FILE ;
+# elif defined (_PATH_WTMPX)
+ _PATH_WTMPX ;
+# else
+ "" ;
+# endif
+
+#endif /* HAVE_UTMPX_H */
+
+static const char *ut_pathname =
+# if defined (UTMP_FILE)
+ UTMP_FILE ;
+# elif defined (_UTMP_FILE)
+ _UTMP_FILE ;
+# elif defined (_PATH_UTMP)
+ _PATH_UTMP ;
+# else
+ "" ;
+# endif
+
+static const char *wt_pathname =
+# if defined (WTMP_FILE)
+ WTMP_FILE ;
+# elif defined (_WTMP_FILE)
+ _WTMP_FILE ;
+# elif defined (_PATH_WTMP)
+ _PATH_WTMP ;
+# else
+ "" ;
+# endif
+
+/* BSD-like systems might want "lastlog" support. */
+/* *** Not yet implemented */
+#ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
+static const char *ll_pathname =
+# if defined (_PATH_LASTLOG) /* what other names (if any?) */
+ _PATH_LASTLOG ;
+# else
+ "" ;
+# endif /* _PATH_LASTLOG */
+#endif /* HAVE_PUTUTLINE */
+
+/*
+ * Get name of {u,w}tmp{,x} file.
+ * return: fname contains filename
+ * Possibly empty if this code not yet ported to this system.
+ *
+ * utmp{,x}: try "utmp dir", then default (a define)
+ * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
+ */
+static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default)
+{
+ pstring dirname;
+
+ pstrcpy(dirname, "");
+
+ /* For w-files, first look for explicit "wtmp dir" */
+ if (uw_name[0] == 'w') {
+ pstrcpy(dirname,lp_wtmpdir());
+ trim_string(dirname,"","/");
+ }
+
+ /* For u-files and non-explicit w-dir, look for "utmp dir" */
+ if (dirname == 0 || strlen(dirname) == 0) {
+ pstrcpy(dirname,lp_utmpdir());
+ trim_string(dirname,"","/");
+ }
+
+ /* If explicit directory above, use it */
+ if (dirname != 0 && strlen(dirname) != 0) {
+ pstrcpy(fname, dirname);
+ pstrcat(fname, "/");
+ pstrcat(fname, uw_name);
+ return;
+ }
+
+ /* No explicit directory: attempt to use default paths */
+ if (strlen(uw_default) == 0) {
+ /* No explicit setting, no known default.
+ * Has it yet been ported to this OS?
+ */
+ DEBUG(2,("uw_pathname: unable to determine pathname\n"));
+ }
+ pstrcpy(fname, uw_default);
+}
+
+#ifndef HAVE_PUTUTLINE
+
+/****************************************************************************
+ Update utmp file directly. No subroutine interface: probably a BSD system.
+****************************************************************************/
+
+static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
+{
+ DEBUG(1,("pututline_my: not yet implemented\n"));
+ /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
+}
+#endif /* HAVE_PUTUTLINE */
+
+#ifndef HAVE_UPDWTMP
+
+/****************************************************************************
+ Update wtmp file directly. No subroutine interface: probably a BSD system.
+ Credit: Michail Vidiassov <master@iaas.msu.ru>
+****************************************************************************/
+
+static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
+{
+ int fd;
+ struct stat buf;
+
+ if (! claim) {
+ /*
+ * BSD-like systems:
+ * may use empty ut_name to distinguish a logout record.
+ *
+ * May need "if defined(SUNOS4)" etc. around some of these,
+ * but try to avoid if possible.
+ *
+ * SunOS 4:
+ * man page indicates ut_name and ut_host both NULL
+ * FreeBSD 4.0:
+ * man page appears not to specify (hints non-NULL)
+ * A correspondent suggest at least ut_name should be NULL
+ */
+ memset((char *)&u->ut_name, '\0', sizeof(u->ut_name));
+ memset((char *)&u->ut_host, '\0', sizeof(u->ut_host));
+ }
+ /* Stolen from logwtmp function in libutil.
+ * May be more locking/blocking is needed?
+ */
+ if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (fstat(fd, &buf) == 0) {
+ if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void) ftruncate(fd, buf.st_size);
+ }
+ (void) close(fd);
+}
+#endif /* HAVE_UPDWTMP */
+
+/****************************************************************************
+ Update via utmp/wtmp (not utmpx/wtmpx).
+****************************************************************************/
+
+static void utmp_nox_update(struct utmp *u, BOOL claim)
+{
+ pstring uname, wname;
+#if defined(PUTUTLINE_RETURNS_UTMP)
+ struct utmp *urc;
+#endif /* PUTUTLINE_RETURNS_UTMP */
+
+ uw_pathname(uname, "utmp", ut_pathname);
+ DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
+
+#ifdef HAVE_PUTUTLINE
+ if (strlen(uname) != 0) {
+ utmpname(uname);
+ }
+
+# if defined(PUTUTLINE_RETURNS_UTMP)
+ setutent();
+ urc = pututline(u);
+ endutent();
+ if (urc == NULL) {
+ DEBUG(2,("utmp_nox_update: pututline() failed\n"));
+ return;
+ }
+# else /* PUTUTLINE_RETURNS_UTMP */
+ setutent();
+ pututline(u);
+ endutent();
+# endif /* PUTUTLINE_RETURNS_UTMP */
+
+#else /* HAVE_PUTUTLINE */
+ if (strlen(uname) != 0) {
+ pututline_my(uname, u, claim);
+ }
+#endif /* HAVE_PUTUTLINE */
+
+ uw_pathname(wname, "wtmp", wt_pathname);
+ DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
+ if (strlen(wname) != 0) {
+#ifdef HAVE_UPDWTMP
+ updwtmp(wname, u);
+ /*
+ * updwtmp() and the newer updwtmpx() may be unsymmetrical.
+ * At least one OS, Solaris 2.x declares the former in the
+ * "utmpx" (latter) file and context.
+ * In the Solaris case this is irrelevant: it has both and
+ * we always prefer the "x" case, so doesn't come here.
+ * But are there other systems, with no "x", which lack
+ * updwtmp() perhaps?
+ */
+#else
+ updwtmp_my(wname, u, claim);
+#endif /* HAVE_UPDWTMP */
+ }
+}
+
+/****************************************************************************
+ Copy a string in the utmp structure.
+****************************************************************************/
+
+static void utmp_strcpy(char *dest, const char *src, size_t n)
+{
+ size_t len = 0;
+
+ memset(dest, '\0', n);
+ if (src)
+ len = strlen(src);
+ if (len >= n) {
+ memcpy(dest, src, n);
+ } else {
+ if (len)
+ memcpy(dest, src, len);
+ }
+}
+
+/****************************************************************************
+ Update via utmpx/wtmpx (preferred) or via utmp/wtmp.
+****************************************************************************/
+
+static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
+{
+#if !defined(HAVE_UTMPX_H)
+ /* No utmpx stuff. Drop to non-x stuff */
+ utmp_nox_update(u, claim);
+#elif !defined(HAVE_PUTUTXLINE)
+ /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
+ utmp_nox_update(u, claim);
+#elif !defined(HAVE_GETUTMPX)
+ /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
+ utmp_nox_update(u, claim);
+#else
+ pstring uname, wname;
+ struct utmpx ux, *uxrc;
+
+ getutmpx(u, &ux);
+
+#if defined(HAVE_UX_UT_SYSLEN)
+ if (hostname)
+ ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */
+ else
+ ux.ut_syslen = 0;
+#endif
+ utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host));
+
+ uw_pathname(uname, "utmpx", ux_pathname);
+ uw_pathname(wname, "wtmpx", wx_pathname);
+ DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
+ /*
+ * Check for either uname or wname being empty.
+ * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
+ * define default filenames.
+ * Also, our local installation has not provided an override.
+ * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
+ */
+ if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
+ utmp_nox_update(u, claim);
+ } else {
+ utmpxname(uname);
+ setutxent();
+ uxrc = pututxline(&ux);
+ endutxent();
+ if (uxrc == NULL) {
+ DEBUG(2,("utmp_update: pututxline() failed\n"));
+ return;
+ }
+ updwtmpx(wname, &ux);
+ }
+#endif /* HAVE_UTMPX_H */
+}
+
+#if defined(HAVE_UT_UT_ID)
+/****************************************************************************
+ Encode the unique connection number into "ut_id".
+****************************************************************************/
+
+static int ut_id_encode(int i, char *fourbyte)
+{
+ int nbase;
+ char *ut_id_encstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ fourbyte[0] = 'S';
+ fourbyte[1] = 'M';
+
+/*
+ * Encode remaining 2 bytes from 'i'.
+ * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
+ * Example: digits would produce the base-10 numbers from '001'.
+ */
+ nbase = strlen(ut_id_encstr);
+
+ fourbyte[3] = ut_id_encstr[i % nbase];
+ i /= nbase;
+ fourbyte[2] = ut_id_encstr[i % nbase];
+ i /= nbase;
+
+ return(i); /* 0: good; else overflow */
+}
+#endif /* defined(HAVE_UT_UT_ID) */
+
+
+/*
+ fill a system utmp structure given all the info we can gather
+*/
+static BOOL sys_utmp_fill(struct utmp *u,
+ const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct timeval timeval;
+
+ /*
+ * ut_name, ut_user:
+ * Several (all?) systems seems to define one as the other.
+ * It is easier and clearer simply to let the following take its course,
+ * rather than to try to detect and optimise.
+ */
+#if defined(HAVE_UT_UT_USER)
+ utmp_strcpy(u->ut_user, username, sizeof(u->ut_user));
+#elif defined(HAVE_UT_UT_NAME)
+ utmp_strcpy(u->ut_name, username, sizeof(u->ut_name));
+#endif
+
+ /*
+ * ut_line:
+ * If size limit proves troublesome, then perhaps use "ut_id_encode()".
+ *
+ * Temporary variable "line_tmp" avoids trouble:
+ * o with unwanted trailing NULL if ut_line full;
+ * o with overflow if ut_line would be more than full.
+ */
+ if (strlen(id_str) > sizeof(u->ut_line)) {
+ DEBUG(1,("id_str [%s] is too long for %d char utmp field\n",
+ id_str, sizeof(u->ut_line)));
+ return False;
+ }
+ utmp_strcpy(u->ut_line, id_str, sizeof(u->ut_line));
+
+#if defined(HAVE_UT_UT_PID)
+ u->ut_pid = sys_getpid();
+#endif
+
+/*
+ * ut_time, ut_tv:
+ * Some have one, some the other. Many have both, but defined (aliased).
+ * It is easier and clearer simply to let the following take its course.
+ * But note that we do the more precise ut_tv as the final assignment.
+ */
+#if defined(HAVE_UT_UT_TIME)
+ gettimeofday(&timeval, NULL);
+ u->ut_time = timeval.tv_sec;
+#elif defined(HAVE_UT_UT_TV)
+ gettimeofday(&timeval, NULL);
+ u->ut_tv = timeval;
+#else
+#error "with-utmp must have UT_TIME or UT_TV"
+#endif
+
+#if defined(HAVE_UT_UT_HOST)
+ utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host));
+#endif
+
+#if defined(HAVE_UT_UT_ADDR)
+ /*
+ * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
+ * Volunteer to implement, please ...
+ */
+#endif
+
+#if defined(HAVE_UT_UT_ID)
+ if (ut_id_encode(id_num, u->ut_id) != 0) {
+ DEBUG(1,("utmp_fill: cannot encode id %d\n", id_num));
+ return False;
+ }
+#endif
+
+ return True;
+}
+
+/****************************************************************************
+ Close a connection.
+****************************************************************************/
+
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_EXIT)
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit = 0;
+#endif
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = DEAD_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return;
+
+ sys_utmp_update(&u, NULL, False);
+}
+
+/****************************************************************************
+ Claim a entry in whatever utmp system the OS uses.
+****************************************************************************/
+
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = USER_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return;
+
+ sys_utmp_update(&u, hostname, True);
+}
+
+#else /* WITH_UTMP */
+ void dummy_utmp(void) {}
+#endif
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
new file mode 100644
index 00000000000..eff72c1f107
--- /dev/null
+++ b/source/smbd/vfs-wrap.c
@@ -0,0 +1,650 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Wrap disk only vfs functions to sidestep dodgy compilers.
+ Copyright (C) Tim Potter 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Check for NULL pointer parameters in vfswrap_* functions */
+
+#define VFS_CHECK_NULL
+
+/* We don't want to have NULL function pointers lying around. Someone
+ is sure to try and execute them. These stubs are used to prevent
+ this possibility. */
+
+int vfswrap_dummy_connect(connection_struct *conn, const char *service, const char *user)
+{
+ return 0; /* Return >= 0 for success */
+}
+
+void vfswrap_dummy_disconnect(connection_struct *conn)
+{
+}
+
+/* Disk operations */
+
+SMB_BIG_UINT vfswrap_disk_free(connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize,
+ SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ SMB_BIG_UINT result;
+
+#ifdef VFS_CHECK_NULL
+ if ((path == NULL) || (bsize == NULL) || (dfree == NULL) ||
+ (dsize == NULL)) {
+
+ smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
+ }
+#endif
+
+ result = sys_disk_free(path, small_query, bsize, dfree, dsize);
+ return result;
+}
+
+/* Directory operations */
+
+DIR *vfswrap_opendir(connection_struct *conn, const char *fname)
+{
+ DIR *result;
+
+ START_PROFILE(syscall_opendir);
+
+#ifdef VFS_CHECK_NULL
+ if (fname == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_opendir()\n");
+ }
+#endif
+
+ result = opendir(fname);
+ END_PROFILE(syscall_opendir);
+ return result;
+}
+
+struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp)
+{
+ struct dirent *result;
+
+ START_PROFILE(syscall_readdir);
+
+#ifdef VFS_CHECK_NULL
+ if (dirp == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_readdir()\n");
+ }
+#endif
+
+ result = readdir(dirp);
+ END_PROFILE(syscall_readdir);
+ return result;
+}
+
+int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_mkdir);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
+ }
+#endif
+
+ result = mkdir(path, mode);
+
+ if (result == 0) {
+ /*
+ * We need to do this as the default behavior of POSIX ACLs
+ * is to set the mask to be the requested group permission
+ * bits, not the group permission bits to be the requested
+ * group permission bits. This is not what we want, as it will
+ * mess up any inherited ACL bits that were set. JRA.
+ */
+ int saved_errno = errno; /* We may get ENOSYS */
+ if (conn->vfs_ops.chmod_acl != NULL) {
+ if ((conn->vfs_ops.chmod_acl(conn, path, mode) == -1) && (errno == ENOSYS))
+ errno = saved_errno;
+ }
+ }
+
+ END_PROFILE(syscall_mkdir);
+ return result;
+}
+
+int vfswrap_rmdir(connection_struct *conn, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_rmdir);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
+ }
+#endif
+
+ result = rmdir(path);
+ END_PROFILE(syscall_rmdir);
+ return result;
+}
+
+int vfswrap_closedir(connection_struct *conn, DIR *dirp)
+{
+ int result;
+
+ START_PROFILE(syscall_closedir);
+
+#ifdef VFS_CHECK_NULL
+ if (dirp == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_closedir()\n");
+ }
+#endif
+
+ result = closedir(dirp);
+ END_PROFILE(syscall_closedir);
+ return result;
+}
+
+/* File operations */
+
+int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_open);
+
+#ifdef VFS_CHECK_NULL
+ if (fname == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_open()\n");
+ }
+#endif
+
+ result = sys_open(fname, flags, mode);
+ END_PROFILE(syscall_open);
+ return result;
+}
+
+int vfswrap_close(files_struct *fsp, int fd)
+{
+ int result;
+
+ START_PROFILE(syscall_close);
+
+ result = close(fd);
+ END_PROFILE(syscall_close);
+ return result;
+}
+
+ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_read, n);
+
+#ifdef VFS_CHECK_NULL
+ if (data == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_read()\n");
+ }
+#endif
+
+ result = read(fd, data, n);
+ END_PROFILE(syscall_read);
+ return result;
+}
+
+ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n)
+{
+ ssize_t result;
+
+ START_PROFILE_BYTES(syscall_write, n);
+
+#ifdef VFS_CHECK_NULL
+ if (data == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_write()\n");
+ }
+#endif
+
+ result = write(fd, data, n);
+ END_PROFILE(syscall_write);
+ return result;
+}
+
+SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
+{
+ SMB_OFF_T result;
+
+ START_PROFILE(syscall_lseek);
+
+ result = sys_lseek(filedes, offset, whence);
+ END_PROFILE(syscall_lseek);
+ return result;
+}
+
+int vfswrap_rename(connection_struct *conn, const char *old, const char *new)
+{
+ int result;
+
+ START_PROFILE(syscall_rename);
+
+#ifdef VFS_CHECK_NULL
+ if ((old == NULL) || (new == NULL)) {
+ smb_panic("NULL pointer passed to vfswrap_rename()\n");
+ }
+#endif
+
+ result = rename(old, new);
+ END_PROFILE(syscall_rename);
+ return result;
+}
+
+int vfswrap_fsync(files_struct *fsp, int fd)
+{
+#ifdef HAVE_FSYNC
+ int result;
+
+ START_PROFILE(syscall_fsync);
+
+ result = fsync(fd);
+ END_PROFILE(syscall_fsync);
+ return result;
+#else
+ return 0;
+#endif
+}
+
+int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_stat);
+
+#ifdef VFS_CHECK_NULL
+ if ((fname == NULL) || (sbuf == NULL)) {
+ smb_panic("NULL pointer passed to vfswrap_stat()\n");
+ }
+#endif
+
+ result = sys_stat(fname, sbuf);
+ END_PROFILE(syscall_stat);
+ return result;
+}
+
+int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_fstat);
+
+#ifdef VFS_CHECK_NULL
+ if (sbuf == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_fstat()\n");
+ }
+#endif
+
+ result = sys_fstat(fd, sbuf);
+ END_PROFILE(syscall_fstat);
+ return result;
+}
+
+int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ int result;
+
+ START_PROFILE(syscall_lstat);
+
+#ifdef VFS_CHECK_NULL
+ if ((path == NULL) || (sbuf == NULL)) {
+ smb_panic("NULL pointer passed to vfswrap_lstat()\n");
+ }
+#endif
+
+ result = sys_lstat(path, sbuf);
+ END_PROFILE(syscall_lstat);
+ return result;
+}
+
+int vfswrap_unlink(connection_struct *conn, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_unlink);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_unlink()\n");
+ }
+#endif
+
+ result = unlink(path);
+ END_PROFILE(syscall_unlink);
+ return result;
+}
+
+int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(syscall_chmod);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_chmod()\n");
+ }
+#endif
+
+ /*
+ * We need to do this due to the fact that the default POSIX ACL
+ * chmod modifies the ACL *mask* for the group owner, not the
+ * group owner bits directly. JRA.
+ */
+
+
+ if (conn->vfs_ops.chmod_acl != NULL) {
+ int saved_errno = errno; /* We might get ENOSYS */
+ if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) {
+ END_PROFILE(syscall_chmod);
+ return result;
+ }
+ /* Error - return the old errno. */
+ errno = saved_errno;
+ }
+
+ result = chmod(path, mode);
+ END_PROFILE(syscall_chmod);
+ return result;
+}
+
+int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode)
+{
+ int result;
+ struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
+
+ START_PROFILE(syscall_fchmod);
+
+ /*
+ * We need to do this due to the fact that the default POSIX ACL
+ * chmod modifies the ACL *mask* for the group owner, not the
+ * group owner bits directly. JRA.
+ */
+
+ if (vfs_ops->fchmod_acl != NULL) {
+ int saved_errno = errno; /* We might get ENOSYS */
+ if ((result = vfs_ops->fchmod_acl(fsp, fd, mode)) == 0) {
+ END_PROFILE(syscall_chmod);
+ return result;
+ }
+ /* Error - return the old errno. */
+ errno = saved_errno;
+ }
+
+ result = fchmod(fd, mode);
+ END_PROFILE(syscall_fchmod);
+ return result;
+}
+
+int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+ START_PROFILE(syscall_chown);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_chown()\n");
+ }
+#endif
+
+ result = sys_chown(path, uid, gid);
+ END_PROFILE(syscall_chown);
+ return result;
+}
+
+int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
+{
+ int result;
+
+ START_PROFILE(syscall_fchown);
+
+ result = fchown(fd, uid, gid);
+ END_PROFILE(syscall_fchown);
+ return result;
+}
+
+int vfswrap_chdir(connection_struct *conn, const char *path)
+{
+ int result;
+
+ START_PROFILE(syscall_chdir);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_chdir()\n");
+ }
+#endif
+
+ result = chdir(path);
+ END_PROFILE(syscall_chdir);
+ return result;
+}
+
+char *vfswrap_getwd(connection_struct *conn, char *path)
+{
+ char *result;
+
+ START_PROFILE(syscall_getwd);
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_getwd()\n");
+ }
+#endif
+
+ result = sys_getwd(path);
+ END_PROFILE(syscall_getwd);
+ return result;
+}
+
+int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *times)
+{
+ int result;
+
+ START_PROFILE(syscall_utime);
+
+#ifdef VFS_CHECK_NULL
+ if ((path == NULL) || (times == NULL)) {
+ smb_panic("NULL pointer passed to vfswrap_utime()\n");
+ }
+#endif
+
+ result = utime(path, times);
+ END_PROFILE(syscall_utime);
+ return result;
+}
+
+int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
+{
+ int result = -1;
+ struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
+ SMB_STRUCT_STAT st;
+ char c = 0;
+ SMB_OFF_T currpos;
+
+ START_PROFILE(syscall_ftruncate);
+
+ /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
+ sys_ftruncate if the system supports it. Then I discovered that
+ you can have some filesystems that support ftruncate
+ expansion and some that don't! On Linux fat can't do
+ ftruncate extend but ext2 can. */
+ result = sys_ftruncate(fd, len);
+ if (result == 0) goto done;
+
+ /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
+ extend a file with ftruncate. Provide alternate implementation
+ for this */
+ currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
+ if (currpos == -1) {
+ goto done;
+ }
+
+ /* Do an fstat to see if the file is longer than the requested
+ size in which case the ftruncate above should have
+ succeeded or shorter, in which case seek to len - 1 and
+ write 1 byte of zero */
+ if (vfs_ops->fstat(fsp, fd, &st) < 0) {
+ goto done;
+ }
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(st.st_mode)) {
+ result = 0;
+ goto done;
+ }
+#endif
+
+ if (st.st_size == len) {
+ result = 0;
+ goto done;
+ }
+
+ if (st.st_size > len) {
+ /* the sys_ftruncate should have worked */
+ goto done;
+ }
+
+ if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) {
+ goto done;
+ }
+
+ if (vfs_ops->write(fsp, fd, &c, 1)!=1) {
+ goto done;
+ }
+
+ /* Seek to where we were */
+ if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) {
+ goto done;
+ }
+ result = 0;
+ done:
+
+ END_PROFILE(syscall_ftruncate);
+ return result;
+}
+
+BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ BOOL result;
+
+ START_PROFILE(syscall_fcntl_lock);
+
+ result = fcntl_lock(fd, op, offset, count,type);
+ END_PROFILE(syscall_fcntl_lock);
+ return result;
+}
+
+int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath)
+{
+ int result;
+
+ START_PROFILE(syscall_symlink);
+
+#ifdef VFS_CHECK_NULL
+ if ((oldpath == NULL) || (newpath == NULL))
+ smb_panic("NULL pointer passed to vfswrap_symlink()\n");
+#endif
+
+ result = sys_symlink(oldpath, newpath);
+ END_PROFILE(syscall_symlink);
+ return result;
+}
+
+int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz)
+{
+ int result;
+
+ START_PROFILE(syscall_readlink);
+
+#ifdef VFS_CHECK_NULL
+ if ((path == NULL) || (buf == NULL))
+ smb_panic("NULL pointer passed to vfswrap_readlink()\n");
+#endif
+
+ result = sys_readlink(path, buf, bufsiz);
+ END_PROFILE(syscall_readlink);
+ return result;
+}
+
+size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
+{
+ size_t result;
+
+ START_PROFILE(fget_nt_acl);
+ result = get_nt_acl(fsp, ppdesc);
+ END_PROFILE(fget_nt_acl);
+ return result;
+}
+
+size_t vfswrap_get_nt_acl(files_struct *fsp, const char *name, SEC_DESC **ppdesc)
+{
+ size_t result;
+
+ START_PROFILE(get_nt_acl);
+ result = get_nt_acl(fsp, ppdesc);
+ END_PROFILE(get_nt_acl);
+ return result;
+}
+
+BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
+{
+ BOOL result;
+
+ START_PROFILE(fset_nt_acl);
+ result = set_nt_acl(fsp, security_info_sent, psd);
+ END_PROFILE(fset_nt_acl);
+ return result;
+}
+
+BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd)
+{
+ BOOL result;
+
+ START_PROFILE(set_nt_acl);
+ result = set_nt_acl(fsp, security_info_sent, psd);
+ END_PROFILE(set_nt_acl);
+ return result;
+}
+
+int vfswrap_chmod_acl(connection_struct *conn, const char *name, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(chmod_acl);
+ result = chmod_acl(name, mode);
+ END_PROFILE(chmod_acl);
+ return result;
+}
+
+int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode)
+{
+ int result;
+
+ START_PROFILE(fchmod_acl);
+ result = fchmod_acl(fd, mode);
+ END_PROFILE(fchmod_acl);
+ return result;
+}
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
new file mode 100644
index 00000000000..6d8e9cc76c2
--- /dev/null
+++ b/source/smbd/vfs.c
@@ -0,0 +1,789 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ VFS initialisation and support functions
+ Copyright (C) Tim Potter 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Some structures to help us initialise the vfs operations table */
+
+struct vfs_syminfo {
+ char *name;
+ void *fptr;
+};
+
+/* Default vfs hooks. WARNING: The order of these initialisers is
+ very important. They must be in the same order as defined in
+ vfs.h. Change at your own peril. */
+
+static struct vfs_ops default_vfs_ops = {
+
+ /* Disk operations */
+
+ vfswrap_dummy_connect,
+ vfswrap_dummy_disconnect,
+ vfswrap_disk_free,
+
+ /* Directory operations */
+
+ vfswrap_opendir,
+ vfswrap_readdir,
+ vfswrap_mkdir,
+ vfswrap_rmdir,
+ vfswrap_closedir,
+
+ /* File operations */
+
+ vfswrap_open,
+ vfswrap_close,
+ vfswrap_read,
+ vfswrap_write,
+ vfswrap_lseek,
+ vfswrap_rename,
+ vfswrap_fsync,
+ vfswrap_stat,
+ vfswrap_fstat,
+ vfswrap_lstat,
+ vfswrap_unlink,
+ vfswrap_chmod,
+ vfswrap_fchmod,
+ vfswrap_chown,
+ vfswrap_fchown,
+ vfswrap_chdir,
+ vfswrap_getwd,
+ vfswrap_utime,
+ vfswrap_ftruncate,
+ vfswrap_lock,
+ vfswrap_symlink,
+ vfswrap_readlink,
+
+ vfswrap_fget_nt_acl,
+ vfswrap_get_nt_acl,
+ vfswrap_fset_nt_acl,
+ vfswrap_set_nt_acl,
+
+#if defined(HAVE_NO_ACLS)
+ NULL,
+ NULL
+#else
+ vfswrap_chmod_acl,
+ vfswrap_fchmod_acl
+#endif
+};
+
+/****************************************************************************
+ initialise default vfs hooks
+****************************************************************************/
+
+static BOOL vfs_init_default(connection_struct *conn)
+{
+ DEBUG(3, ("Initialising default vfs hooks\n"));
+
+ memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
+ return True;
+}
+
+/****************************************************************************
+ initialise custom vfs hooks
+****************************************************************************/
+
+#ifdef HAVE_LIBDL
+static BOOL vfs_init_custom(connection_struct *conn)
+{
+ int vfs_version = -1;
+ struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
+
+ DEBUG(3, ("Initialising custom vfs hooks from %s\n",
+ lp_vfsobj(SNUM(conn))));
+
+ /* Open object file */
+ if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)),
+ RTLD_NOW | RTLD_GLOBAL)) == NULL) {
+ DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror()));
+ return False;
+ }
+
+ /* Get handle on vfs_init() symbol */
+ init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
+
+ if (init_fptr == NULL) {
+ DEBUG(0, ("No vfs_init() symbol found in %s\n",
+ lp_vfsobj(SNUM(conn))));
+ return False;
+ }
+
+ /* Initialise vfs_ops structure */
+ conn->vfs_ops = default_vfs_ops;
+
+ if ((ops = init_fptr(&vfs_version, &conn->vfs_ops)) == NULL) {
+ DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
+ return False;
+ }
+
+ if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
+ DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
+ vfs_version, SMB_VFS_INTERFACE_VERSION ));
+ return False;
+ }
+
+ if (ops != &conn->vfs_ops) {
+ memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
+ }
+
+ return True;
+}
+#endif
+
+/*****************************************************************
+ Generic VFS init.
+******************************************************************/
+
+BOOL smbd_vfs_init(connection_struct *conn)
+{
+ if (*lp_vfsobj(SNUM(conn))) {
+#ifdef HAVE_LIBDL
+
+ /* Loadable object file */
+
+ if (!vfs_init_custom(conn)) {
+ DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
+ return False;
+ }
+
+ return True;
+#else
+ DEBUG(0, ("smbd_vfs_init: No libdl present - cannot use VFS objects\n"));
+ return False;
+#endif
+ }
+
+ /* Normal share - initialise with disk access functions */
+
+ return vfs_init_default(conn);
+}
+
+/*******************************************************************
+ Check if directory exists.
+********************************************************************/
+
+BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st2;
+ BOOL ret;
+
+ if (!st)
+ st = &st2;
+
+ if (vfs_stat(conn,dname,st) != 0)
+ return(False);
+
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+
+ return ret;
+}
+
+/*******************************************************************
+ vfs getwd wrapper
+********************************************************************/
+char *vfs_getwd(connection_struct *conn, char *path)
+{
+ return conn->vfs_ops.getwd(conn,path);
+}
+
+/*******************************************************************
+ vfs mkdir wrapper
+********************************************************************/
+
+int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
+{
+ int ret;
+ SMB_STRUCT_STAT sbuf;
+
+ if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
+ /*
+ * Check if high bits should have been set,
+ * then (if bits are missing): add them.
+ * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
+ */
+ if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
+ !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
+ vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Check if a vfs file exists.
+********************************************************************/
+
+BOOL vfs_file_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ SMB_STRUCT_STAT st;
+
+ if (!sbuf)
+ sbuf = &st;
+
+ ZERO_STRUCTP(sbuf);
+
+ if (vfs_stat(conn,fname,sbuf) != 0)
+ return(False);
+
+ return(S_ISREG(sbuf->st_mode));
+}
+
+/****************************************************************************
+ Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
+****************************************************************************/
+
+ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
+{
+ size_t total=0;
+
+ while (total < byte_count)
+ {
+ ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
+ byte_count - total);
+
+ if (ret == 0) return total;
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a fd on the vfs.
+****************************************************************************/
+
+ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ while (total < N) {
+ ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
+
+ if (ret == -1)
+ return -1;
+ if (ret == 0)
+ return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ An allocate file space call using the vfs interface.
+ Allocates space for a file from a filedescriptor.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
+{
+ int ret;
+ SMB_STRUCT_STAT st;
+ connection_struct *conn = fsp->conn;
+ struct vfs_ops *vfs_ops = &conn->vfs_ops;
+ SMB_OFF_T space_avail;
+ SMB_BIG_UINT bsize,dfree,dsize;
+
+ release_level_2_oplocks_on_change(fsp);
+
+ /*
+ * Actually try and commit the space on disk....
+ */
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
+
+ ret = vfs_fstat(fsp,fsp->fd,&st);
+ if (ret == -1)
+ return ret;
+
+ if (len == st.st_size)
+ return 0;
+
+ if (len < st.st_size) {
+ /* Shrink - use ftruncate. */
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
+ fsp->fsp_name, (double)st.st_size ));
+
+ if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
+ set_filelen_write_cache(fsp, len);
+ }
+ return ret;
+ }
+
+ /* Grow - we need to test if we have enough space. */
+
+ if (!lp_strict_allocate(SNUM(fsp->conn)))
+ return 0;
+
+ len -= st.st_size;
+ len /= 1024; /* Len is now number of 1k blocks needed. */
+ space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
+
+ DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
+ fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
+
+ if (len > space_avail) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ A vfs set_filelen call.
+ set the length of a file from a filedescriptor.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
+{
+ int ret;
+
+ release_level_2_oplocks_on_change(fsp);
+ DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
+ if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
+ set_filelen_write_cache(fsp, len);
+
+ return ret;
+}
+
+/****************************************************************************
+ Transfer some data (n bytes) between two file_struct's.
+****************************************************************************/
+
+static files_struct *in_fsp;
+static files_struct *out_fsp;
+
+static ssize_t read_fn(int fd, void *buf, size_t len)
+{
+ return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
+}
+
+static ssize_t write_fn(int fd, const void *buf, size_t len)
+{
+ return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
+}
+
+SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
+{
+ in_fsp = in;
+ out_fsp = out;
+
+ return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
+}
+
+/*******************************************************************
+ A vfs_readdir wrapper which just returns the file name.
+********************************************************************/
+
+char *vfs_readdirname(connection_struct *conn, void *p)
+{
+ struct dirent *ptr;
+ char *dname;
+
+ if (!p)
+ return(NULL);
+
+ ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
+ if (!ptr)
+ return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0)
+ return(NULL);
+#endif
+
+#ifdef HAVE_BROKEN_READDIR
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
+#endif
+
+ return(dname);
+}
+
+/* VFS options not quite working yet */
+
+#if 0
+
+/***************************************************************************
+ handle the interpretation of the vfs option parameter
+ *************************************************************************/
+static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
+{
+ struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
+ int i;
+
+ /* Create new vfs option */
+
+ new_option = (struct vfs_options *)malloc(sizeof(*new_option));
+ if (new_option == NULL) {
+ return False;
+ }
+
+ ZERO_STRUCTP(new_option);
+
+ /* Get name and value */
+
+ new_option->name = strtok(pszParmValue, "=");
+
+ if (new_option->name == NULL) {
+ return False;
+ }
+
+ while(isspace(*new_option->name)) {
+ new_option->name++;
+ }
+
+ for (i = strlen(new_option->name); i > 0; i--) {
+ if (!isspace(new_option->name[i - 1])) break;
+ }
+
+ new_option->name[i] = '\0';
+ new_option->name = strdup(new_option->name);
+
+ new_option->value = strtok(NULL, "=");
+
+ if (new_option->value != NULL) {
+
+ while(isspace(*new_option->value)) {
+ new_option->value++;
+ }
+
+ for (i = strlen(new_option->value); i > 0; i--) {
+ if (!isspace(new_option->value[i - 1])) break;
+ }
+
+ new_option->value[i] = '\0';
+ new_option->value = strdup(new_option->value);
+ }
+
+ /* Add to list */
+
+ DLIST_ADD(*options, new_option);
+
+ return True;
+}
+
+#endif
+
+
+/*******************************************************************
+ A wrapper for vfs_chdir().
+********************************************************************/
+
+int vfs_ChDir(connection_struct *conn, char *path)
+{
+ int res;
+ static pstring LastDir="";
+
+ if (strcsequal(path,"."))
+ return(0);
+
+ if (*path == '/' && strcsequal(LastDir,path))
+ return(0);
+
+ DEBUG(3,("vfs_ChDir to %s\n",path));
+
+ res = vfs_chdir(conn,path);
+ if (!res)
+ pstrcpy(LastDir,path);
+ return(res);
+}
+
+/* number of list structures for a caching GetWd function. */
+#define MAX_GETWDCACHE (50)
+
+struct
+{
+ SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
+ SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
+ char *dos_path; /* The pathname in DOS format. */
+ BOOL valid;
+} ino_list[MAX_GETWDCACHE];
+
+extern BOOL use_getwd_cache;
+
+/****************************************************************************
+ Prompte a ptr (to make it recently used)
+****************************************************************************/
+
+static void array_promote(char *array,int elsize,int element)
+{
+ char *p;
+ if (element == 0)
+ return;
+
+ p = (char *)malloc(elsize);
+
+ if (!p) {
+ DEBUG(5,("array_promote: malloc fail\n"));
+ return;
+ }
+
+ memcpy(p,array + element * elsize, elsize);
+ memmove(array + elsize,array,elsize*element);
+ memcpy(array,p,elsize);
+ SAFE_FREE(p);
+}
+
+/*******************************************************************
+ Return the absolute current directory path - given a UNIX pathname.
+ Note that this path is returned in DOS format, not UNIX
+ format. Note this can be called with conn == NULL.
+********************************************************************/
+
+char *vfs_GetWd(connection_struct *conn, char *path)
+{
+ pstring s;
+ static BOOL getwd_cache_init = False;
+ SMB_STRUCT_STAT st, st2;
+ int i;
+
+ *s = 0;
+
+ if (!use_getwd_cache)
+ return(vfs_getwd(conn,path));
+
+ /* init the cache */
+ if (!getwd_cache_init)
+ {
+ getwd_cache_init = True;
+ for (i=0;i<MAX_GETWDCACHE;i++)
+ {
+ string_set(&ino_list[i].dos_path,"");
+ ino_list[i].valid = False;
+ }
+ }
+
+ /* Get the inode of the current directory, if this doesn't work we're
+ in trouble :-) */
+
+ if (vfs_stat(conn, ".",&st) == -1)
+ {
+ DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
+ return(vfs_getwd(conn,path));
+ }
+
+
+ for (i=0; i<MAX_GETWDCACHE; i++)
+ if (ino_list[i].valid)
+ {
+
+ /* If we have found an entry with a matching inode and dev number
+ then find the inode number for the directory in the cached string.
+ If this agrees with that returned by the stat for the current
+ directory then all is o.k. (but make sure it is a directory all
+ the same...) */
+
+ if (st.st_ino == ino_list[i].inode &&
+ st.st_dev == ino_list[i].dev)
+ {
+ if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
+ {
+ if (st.st_ino == st2.st_ino &&
+ st.st_dev == st2.st_dev &&
+ (st2.st_mode & S_IFMT) == S_IFDIR)
+ {
+ pstrcpy (path, ino_list[i].dos_path);
+
+ /* promote it for future use */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+ return (path);
+ }
+ else
+ {
+ /* If the inode is different then something's changed,
+ scrub the entry and start from scratch. */
+ ino_list[i].valid = False;
+ }
+ }
+ }
+ }
+
+
+ /* We don't have the information to hand so rely on traditional methods.
+ The very slow getcwd, which spawns a process on some systems, or the
+ not quite so bad getwd. */
+
+ if (!vfs_getwd(conn,s))
+ {
+ DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
+ return (NULL);
+ }
+
+ pstrcpy(path,s);
+
+ DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
+
+ /* add it to the cache */
+ i = MAX_GETWDCACHE - 1;
+ string_set(&ino_list[i].dos_path,s);
+ ino_list[i].dev = st.st_dev;
+ ino_list[i].inode = st.st_ino;
+ ino_list[i].valid = True;
+
+ /* put it at the top of the list */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+
+ return (path);
+}
+
+/*******************************************************************
+ Reduce a file name, removing .. elements and checking that
+ it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
+ on the system that has the referenced file system.
+ Widelinks are allowed if widelinks is true.
+********************************************************************/
+
+BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
+{
+#ifndef REDUCE_PATHS
+ return True;
+#else
+ pstring dir2;
+ pstring wd;
+ pstring base_name;
+ pstring newname;
+ char *p=NULL;
+ BOOL relative = (*s != '/');
+
+ *dir2 = *wd = *base_name = *newname = 0;
+
+ if (widelinks)
+ {
+ unix_clean_name(s);
+ /* can't have a leading .. */
+ if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
+ {
+ DEBUG(3,("Illegal file name? (%s)\n",s));
+ return(False);
+ }
+
+ if (strlen(s) == 0)
+ pstrcpy(s,"./");
+
+ return(True);
+ }
+
+ DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
+
+ /* remove any double slashes */
+ all_string_sub(s,"//","/",0);
+
+ pstrcpy(base_name,s);
+ p = strrchr_m(base_name,'/');
+
+ if (!p)
+ return(True);
+
+ if (!vfs_GetWd(conn,wd))
+ {
+ DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
+ return(False);
+ }
+
+ if (vfs_ChDir(conn,dir) != 0)
+ {
+ DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
+ return(False);
+ }
+
+ if (!vfs_GetWd(conn,dir2))
+ {
+ DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
+ vfs_ChDir(conn,wd);
+ return(False);
+ }
+
+ if (p && (p != base_name))
+ {
+ *p = 0;
+ if (strcmp(p+1,".")==0)
+ p[1]=0;
+ if (strcmp(p+1,"..")==0)
+ *p = '/';
+ }
+
+ if (vfs_ChDir(conn,base_name) != 0)
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
+ return(False);
+ }
+
+ if (!vfs_GetWd(conn,newname))
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
+ return(False);
+ }
+
+ if (p && (p != base_name))
+ {
+ pstrcat(newname,"/");
+ pstrcat(newname,p+1);
+ }
+
+ {
+ size_t l = strlen(dir2);
+ if (dir2[l-1] == '/')
+ l--;
+
+ if (strncmp(newname,dir2,l) != 0)
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
+ return(False);
+ }
+
+ if (relative)
+ {
+ if (newname[l] == '/')
+ pstrcpy(s,newname + l + 1);
+ else
+ pstrcpy(s,newname+l);
+ }
+ else
+ pstrcpy(s,newname);
+ }
+
+ vfs_ChDir(conn,wd);
+
+ if (strlen(s) == 0)
+ pstrcpy(s,"./");
+
+ DEBUG(3,("reduced to %s\n",s));
+ return(True);
+#endif
+}
diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c
deleted file mode 100644
index 83b62a38ac2..00000000000
--- a/source/smbd/vt_mode.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/* vt_mode.c */
-/*
-support vtp-sessions
-
-written by Christian A. Lademann <cal@zls.com>
-*/
-
-/*
-02.05.95:cal:ported to samba-1.9.13
-*/
-
-#define __vt_mode_c__
-
-
-/* #include <stdio.h> */
-/* #include <fcntl.h> */
-/* #include <sys/types.h> */
-/* #include <unistd.h> */
-/* #include <signal.h> */
-/* #include <errno.h> */
-/* #include <ctype.h> */
-/* #include <utmp.h> */
-/* #include <sys/param.h> */
-/* #include <sys/ioctl.h> */
-/* #include <stdlib.h> */
-/* #include <string.h> */
-
-#include "includes.h"
-#include "vt_mode.h"
-#include <utmp.h>
-
-#ifdef SCO
- extern char *strdup();
-#endif
-
-extern int Client;
-
-#ifdef LINUX
-# define HAS_VTY
-#endif
-
-#ifdef SCO
-# define HAS_PTY
-# define HAS_VTY
-
-# include <sys/tty.h>
-#endif
-
-extern int DEBUGLEVEL;
-extern char *InBuffer, *OutBuffer;
-extern int done_become_user;
-
-char master_name [64], slave_name [64];
-int master, slave, i, o, e;
-
-int ms_type = MS_NONE,
- ms_poll = 0;
-
-
-/*
-VT_Check: test incoming packet for "vtp" or "iVT1\0"
-*/
-int VT_Check(buffer)
-char *buffer;
-{
- DEBUG(3,("Checking packet: <%10s...>\n", buffer+4));
- if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5))
- return(1);
- else
- return(0);
-}
-
-
-/*
-VT_Start_utmp: prepare /etc/utmp for /bin/login
-*/
-VT_Start_utmp()
-{
- struct utmp u, *v;
- char *tt;
-
-
- setutent();
-
- strcpy(u.ut_line, VT_Line);
-
- if((v = getutline(&u)) == NULL) {
- if(strncmp(VT_Line, "tty", 3) == 0)
- tt = VT_Line + 3;
- else if(strlen(VT_Line) > 4)
- tt = VT_Line + strlen(VT_Line) - 4;
- else
- tt = VT_Line;
-
- strcpy(u.ut_id, tt);
- u.ut_time = time((time_t*)0);
- }
-
- strcpy(u.ut_user, "LOGIN");
- strcpy(u.ut_line, VT_Line);
- u.ut_pid = getpid();
- u.ut_type = LOGIN_PROCESS;
- pututline(&u);
-
- endutent();
-
- return(0);
-}
-
-
-/*
-VT_Stop_utmp: prepare /etc/utmp for other processes
-*/
-VT_Stop_utmp()
-{
- struct utmp u, *v;
-
-
- if(VT_Line != NULL) {
- setutent();
-
- strcpy(u.ut_line, VT_Line);
-
- if((v = getutline(&u)) != NULL) {
- strcpy(v->ut_user, "");
- v->ut_type = DEAD_PROCESS;
- v->ut_time = time((time_t*)0);
- pututline(v);
- }
-
- endutent();
- }
-
- return(0);
-}
-
-
-/*
-VT_AtExit: Things to do when the program exits
-*/
-void VT_AtExit()
-{
- if(VT_ChildPID > 0) {
- kill(VT_ChildPID, SIGHUP);
- (void)wait(NULL);
- }
-
- VT_Stop_utmp();
-}
-
-
-/*
-VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
-*/
-void VT_SigCLD(sig)
-int sig;
-{
- if(wait(NULL) == VT_ChildPID)
- VT_ChildDied = True;
- else
- signal(SIGCLD, VT_SigCLD);
-}
-
-
-/*
-VT_SigEXIT: signalhandler for signals that cause the process to exit
-*/
-void VT_SigEXIT(sig)
-int sig;
-{
- VT_AtExit();
-
- exit(1);
-}
-
-
-/*
-VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
-*/
-int VT_Start()
-{
- char OutBuf [64], *X, *Y;
-
-
- ms_type = MS_NONE;
- master = slave = -1;
-
-#ifdef HAS_VTY
-#ifdef LINUX
-# define MASTER_TMPL "/dev/pty "
-# define SLAVE_TMPL "/dev/tty "
-# define LETTER1 "pqrs"
-# define POS1 8
-# define LETTER2 "0123456789abcdef"
-# define POS2 9
-#endif
-
-#ifdef SCO
-# define MASTER_TMPL "/dev/ptyp_ "
-# define SLAVE_TMPL "/dev/ttyp_ "
-# define LETTER1 "0123456"
-# define POS1 10
-# define LETTER2 "0123456789abcdef"
-# define POS2 11
-#endif
-
- if(ms_poll == MS_VTY || ms_poll == 0) {
- strcpy(master_name, MASTER_TMPL);
- strcpy(slave_name, SLAVE_TMPL);
-
- for(X = LETTER1; *X && master < 0; X++)
- for(Y = LETTER2; *Y && master < 0; Y++) {
- master_name [POS1] = *X;
- master_name [POS2] = *Y;
- if((master = open(master_name, O_RDWR)) >= 0) {
- slave_name [POS1] = *X;
- slave_name [POS2] = *Y;
- if((slave = open(slave_name, O_RDWR)) < 0)
- close(master);
- }
- }
-
- if(master >= 0 && slave >= 0)
- ms_type = MS_VTY;
- }
-
-# undef MASTER_TMPL
-# undef SLAVE_TMPL
-# undef LETTER1
-# undef LETTER2
-# undef POS1
-# undef POS2
-#endif
-
-
-#ifdef HAS_PTY
-#ifdef SCO
-# define MASTER_TMPL "/dev/ptyp%d"
-# define SLAVE_TMPL "/dev/ttyp%d"
-# define MIN_I 0
-# define MAX_I 63
-#endif
-
- if(ms_poll == MS_PTY || ms_poll == 0) {
- int i;
-
- for(i = MIN_I; i <= MAX_I && master < 0; i++) {
- sprintf(master_name, MASTER_TMPL, i);
- if((master = open(master_name, O_RDWR)) >= 0) {
- sprintf(slave_name, SLAVE_TMPL, i);
- if((slave = open(slave_name, O_RDWR)) < 0)
- close(master);
- }
- }
-
- if(master >= 0 && slave >= 0)
- ms_type = MS_PTY;
- }
-
-# undef MASTER_TMPL
-# undef SLAVE_TMPL
-# undef MIN_I
-# undef MAX_I
-#endif
-
-
- if(! ms_type)
- return(-1);
-
- VT_Line = strdup(strrchr(slave_name, '/') + 1);
-
- switch((VT_ChildPID = fork())) {
- case -1:
- return(-1);
- break;
-
- case 0:
-#ifdef SCO
- setsid();
-#endif
- close(0);
- close(1);
- close(2);
-
- i = open(slave_name, O_RDWR);
- o = open(slave_name, O_RDWR);
- e = open(slave_name, O_RDWR);
-
-#ifdef LINUX
- setsid();
- if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1)
- exit(1);
-#endif
-#ifdef SCO
- tcsetpgrp(0, getpid());
-#endif
-
- VT_Start_utmp();
-
- system("stty sane");
- execlp("/bin/login", "login", "-c", (char*)0);
- exit(1);
- break;
-
- default:
- VT_Mode = True;
- VT_Status = VT_OPEN;
- VT_ChildDied = False;
- VT_Fd = master;
-
- signal(SIGCLD, VT_SigCLD);
-
- signal(SIGHUP, VT_SigEXIT);
- signal(SIGTERM, VT_SigEXIT);
- signal(SIGINT, VT_SigEXIT);
- signal(SIGQUIT, VT_SigEXIT);
-
- memset(OutBuf, 0, sizeof(OutBuf));
- OutBuf [4] = 0x06;
- _smb_setlen(OutBuf, 1);
-
- send_smb(Client,OutBuf);
-
- return(0);
- break;
- }
-}
-
-
-/*
-VT_Output: transport data from socket to pty
-*/
-int VT_Output(Buffer)
-char *Buffer;
-{
- int i, len, nb;
-
-
- if(VT_Status != VT_OPEN)
- return(-1);
-
- len = smb_len(Buffer);
-
- nb = write(VT_Fd, Buffer + 4, len);
-
- return((nb == len) ? 0 : -1);
-}
-
-
-/*
-VT_Input: transport data from pty to socket
-*/
-int VT_Input(Buffer, Size)
-char *Buffer;
-int Size;
-{
- int len;
-
-
- if(VT_Status != VT_OPEN)
- return(-1);
-
- memset(Buffer, 0, Size);
- len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size));
-
- _smb_setlen(Buffer, len);
-
- return(len + 4);
-}
-
-
-/*
-VT_Process: main loop while in vt-mode
-*/
-void VT_Process()
-{
- static int trans_num = 0;
- extern int Client;
- int nread;
-
-
- VT_Start();
-
- atexit(VT_AtExit);
-
- while (True) {
- int32 len;
- int msg_type;
- int msg_flags;
- int counter;
- int last_keepalive=0;
- struct fd_set si;
- struct timeval to, *top;
- int n, ret, t;
-
-
- errno = 0;
- t = SMBD_SELECT_LOOP*1000;
-
-
- FD_ZERO(&si);
- FD_SET(Client, &si);
-
- FD_SET(VT_Fd, &si);
-
- if(t >= 0) {
- to.tv_sec = t / 1000;
- to.tv_usec = t - (to.tv_sec * 1000);
-
- top = &to;
- } else
- top = NULL;
-
- if(VT_ChildDied)
- goto leave_VT_Process;
-
- n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top);
-
- if(VT_ChildDied)
- goto leave_VT_Process;
-
- if(n == 0) {
- int i;
- time_t t;
- BOOL allidle = True;
- extern int keepalive;
-
- counter += SMBD_SELECT_LOOP;
-
- t = time(NULL);
-
- if (keepalive && (counter-last_keepalive)>keepalive) {
- if (!send_keepalive(Client))
- goto leave_VT_Process;
- last_keepalive = counter;
- }
- } else if(n > 0) {
- counter = 0;
-
- if(FD_ISSET(VT_Fd, &si)) {
- /* got input from vt */
- nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit()));
-
- if(nread > 0)
- send_smb(Client,OutBuffer);
- }
-
- if(FD_ISSET(Client, &si)) {
- /* got input from socket */
-
- if(receive_smb(Client,InBuffer, 0)) {
- msg_type = CVAL(InBuffer,0);
- msg_flags = CVAL(InBuffer,1);
-
- len = smb_len(InBuffer);
-
- DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
-
- nread = len + 4;
-
- DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
-
- if(msg_type == 0)
- VT_Output(InBuffer);
- else {
- nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit()));
-
- if(nread > 0) {
- if (nread != smb_len(OutBuffer) + 4) {
- DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
- nread,
- smb_len(OutBuffer)));
- } else
- send_smb(Client,OutBuffer);
- }
- }
- } else
- if(errno == EBADF)
- goto leave_VT_Process;
- }
- }
-
- trans_num++;
- }
-
- leave_VT_Process:
-/*
- if(VT_ChildPID > 0)
- kill(VT_ChildPID, SIGHUP);
-
- VT_Stop_utmp(VT_Line);
- return;
-*/
- close_sockets();
- exit(0);
-}
diff --git a/source/smbwrapper/.cvsignore b/source/smbwrapper/.cvsignore
new file mode 100644
index 00000000000..7835612d320
--- /dev/null
+++ b/source/smbwrapper/.cvsignore
@@ -0,0 +1,8 @@
+*.po
+*.po32
+kernel_stat.h
+smbsh
+tst
+tst.c
+wrapper.h
+xstat.c
diff --git a/source/smbwrapper/PORTING b/source/smbwrapper/PORTING
new file mode 100644
index 00000000000..884246d078a
--- /dev/null
+++ b/source/smbwrapper/PORTING
@@ -0,0 +1,77 @@
+This describes how to port the smbwrapper portion of Samba to a new
+unix-like platform. Note that porting smbwrapper is considerably
+harder than porting Samba, for Samba you generally just need to run
+configure and recompile whereas for smbwrapper some extra effort is
+generally required.
+
+
+STEP 1
+------
+
+The first step is to work out how to create a shared library on your
+OS and how to compile C code to produce position independent object
+files (PIC files). You shoud be able to find this information in the
+man pages for your compiler and loader (ld). Then modify configure.in
+to give that information to Samba.
+
+
+STEP 2
+------
+
+The next step is to work out how to preload shared objects. On many
+systems this is done using a LD_PRELOAD environment variable. On
+others (shc as IRIX) it may use a _RTL_LIST variable.
+
+To make sure it works I suggest you create two C files like this:
+
+/* first C file */
+main()
+{
+ unlink("foo.txt");
+}
+
+/* second C file */
+#include <stdio.h>
+
+int unlink(char *fname)
+{
+ fprintf(stderr,"unlink(%s) called\n",fname);
+}
+
+
+then compile the first as an ordinary C program and the second as a
+shared library. Then use LD_PRELOAD to preload the resulting shared
+library. Then run the first program. It should print "unlink(foo.txt)
+called". If it doesn't then consult your man pages till you get it
+right.
+
+Once you work this out then edit smbwrapper/smbsh.in and add a section
+if necessary to correctly set the necessary preload options for your
+OS.
+
+
+STEP 3
+------
+
+The next step is to work out how to make direct system calls. On most
+machines this will work without any source code changes to
+smbwrapper. To test that it does work create the following C program:
+
+#include <sys/syscall.h>
+main()
+{
+ syscall(SYS_write, 1, "hello world\n", 12);
+}
+
+and try to compile/run it. If it produces "hello world" then syscall()
+works as expected. If not then work out what needs to be changed and
+then make that change in realcalls.h. For example, on IRIX 6.4 the
+system call numbers are wrong and need to be fixed up by getting an
+offset right.
+
+
+STEP 4
+------
+
+Try compiling smbwrapper! Then test it. Then debug it. Simple really :)
+
diff --git a/source/smbwrapper/README b/source/smbwrapper/README
new file mode 100644
index 00000000000..8d5c376f825
--- /dev/null
+++ b/source/smbwrapper/README
@@ -0,0 +1,94 @@
+This is a prelodable shared library that provides SMB client services
+for existing executables. Using this you can simulate a smb
+filesystem.
+
+*** This is code under development. Some things don't work yet ***
+
+Currently this code has been tested on:
+
+- Linux 2.0 with glibc2 (RH5.1)
+- Linux 2.1 with glibc2
+- Solaris 2.5.1 with gcc
+- Solaris 2.6 with gcc
+- SunOS 4.1.3 with gcc
+- IRIX 6.4 with cc
+- OSF1 with gcc
+
+
+It probably won't run on other systems without some porting. If you
+have a different system then see the file PORTING.
+
+To use it you need to do this:
+
+1) build smbwrapper.so using the command "make smbwrapper"
+3) run smbsh
+
+You will be asked for a username and password. After that you will be
+returned to a shell prompt. It is actually a subshell running with
+smbwrapper enabled.
+
+Now try to access /smb/SERVER for some SMB server name and see what
+happens. If you use the -W option to set your workgroup or have
+workgroup set in your smb.conf then listing /smb/ should list all SMB
+servers in your workgroup.
+
+
+OPTIONS
+-------
+
+-U username
+ specify the username and optional password (as user%password)
+
+-d debug level
+ This is an integer that controls the internal debug level of smbw. It
+ defaults to 0, which means no debug info.
+
+-l logfile
+ The place where smbw debug logs are put. If this is not set then
+ stderr is used.
+
+-P prefix
+ The root of the SMB filesystem. This defaults to /smb/ but you can
+ set it to any name you like.
+
+-W workgroup
+ This is the workgroup used for browsing (ie. listing machines in the
+ /smb/ directory). It defaults to the one set in smb.conf.
+
+-R resolve order
+ This allows you to override the setting of the name resolve order
+ from smb.conf
+
+
+ATTRIBUTE MAPPING
+-----------------
+
+smbwrapper does an inverse attribute maping to what Samba does. This
+means that the archive bit appears as the user execute bit, the system
+bit appears as the group execute bit and the hidden bit appears as the
+other execute bit. You can control these with chmod. The mapping can
+be enabled an disabled using the normal smb.conf controls (ie. "map
+archive", "map system" and "map hidden").
+
+Read-only files appear as non-writeable by everyone. Writeable files
+appear as writeable by the current user.
+
+
+WHAT WORKS
+----------
+
+Things that I have tried and do seem to work include:
+
+ emacs, tar, ls, cmp, cp, rsync, du, cat, rm, mv, less, more, wc, head,
+ tail, bash, tcsh, mkdir, rmdir, vim, xedit, diff
+
+things that I know don't work:
+
+ anything executing from the share
+ anything that uses mmap
+ redirection within shells to smbsh files
+
+If you want to help with the development of this code then join the
+samba-technical mailing list.
+
+
diff --git a/source/smbwrapper/init.c b/source/smbwrapper/init.c
new file mode 100644
index 00000000000..23d85eb4cff
--- /dev/null
+++ b/source/smbwrapper/init.c
@@ -0,0 +1,22 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ initialise connections in smbwrapper
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
diff --git a/source/smbwrapper/realcalls.c b/source/smbwrapper/realcalls.c
new file mode 100644
index 00000000000..aabde7fa87c
--- /dev/null
+++ b/source/smbwrapper/realcalls.c
@@ -0,0 +1,49 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions for calls that syscall() can't do
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "realcalls.h"
+
+#ifdef REPLACE_UTIME
+int real_utime(const char *name, struct utimbuf *buf)
+{
+ struct timeval tv[2];
+
+ tv[0].tv_sec = buf->actime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = buf->modtime;
+ tv[1].tv_usec = 0;
+
+ return real_utimes(name, &tv[0]);
+}
+#endif
+
+#ifdef REPLACE_UTIMES
+int real_utimes(const char *name, struct timeval tv[2])
+{
+ struct utimbuf buf;
+
+ buf.actime = tv[0].tv_sec;
+ buf.modtime = tv[1].tv_sec;
+
+ return real_utime(name, &buf);
+}
+#endif
diff --git a/source/smbwrapper/realcalls.h b/source/smbwrapper/realcalls.h
new file mode 100644
index 00000000000..251c2673372
--- /dev/null
+++ b/source/smbwrapper/realcalls.h
@@ -0,0 +1,264 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ defintions of syscall entries
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#if HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#elif HAVE_SYSCALL_H
+#include <syscall.h>
+#endif
+
+#ifdef IRIX
+/* amazingly, IRIX gets its own syscall numbers wrong! */
+#ifdef SYSVoffset
+#if (SYSVoffset == 1)
+#undef SYSVoffset
+#define SYSVoffset 1000
+#endif
+#endif
+#endif
+
+/* this file is partly derived from zlibc by Alain Knaff */
+
+#define real_access(fn, mode) (syscall(SYS_access, (fn), (mode)))
+#define real_chdir(fn) (syscall(SYS_chdir, (fn)))
+#define real_chmod(fn, mode) (syscall(SYS_chmod,(fn), (mode)))
+#define real_chown(fn, owner, group) (syscall(SYS_chown,(fn),(owner),(group)))
+
+#ifdef SYS_getdents
+#define real_getdents(fd, dirp, count) (syscall(SYS_getdents, (fd), (dirp), (count)))
+#endif
+
+#define real_link(fn1, fn2) (syscall(SYS_link, (fn1), (fn2)))
+
+#define real_open(fn,flags,mode) (syscall(SYS_open, (fn), (flags), (mode)))
+
+#ifdef SYS_open64
+#define real_open64(fn,flags,mode) (syscall(SYS_open64, (fn), (flags), (mode)))
+#elif HAVE__OPEN64
+#define real_open64(fn,flags,mode) (_open64(fn,flags,mode))
+#define NO_OPEN64_ALIAS
+#elif HAVE___OPEN64
+#define real_open64(fn,flags,mode) (__open64(fn,flags,mode))
+#define NO_OPEN64_ALIAS
+#endif
+
+#ifdef HAVE__FORK
+#define real_fork() (_fork())
+#elif HAVE___FORK
+#define real_fork() (__fork())
+#elif SYS_fork
+#define real_fork() (syscall(SYS_fork))
+#endif
+
+#ifdef HAVE__OPENDIR
+#define real_opendir(fn) (_opendir(fn))
+#elif SYS_opendir
+#define real_opendir(fn) (syscall(SYS_opendir,(fn)))
+#elif HAVE___OPENDIR
+#define real_opendir(fn) (__opendir(fn))
+#endif
+
+#ifdef HAVE__READDIR
+#define real_readdir(d) (_readdir(d))
+#elif HAVE___READDIR
+#define real_readdir(d) (__readdir(d))
+#elif SYS_readdir
+#define real_readdir(d) (syscall(SYS_readdir,(d)))
+#endif
+
+#ifdef HAVE__CLOSEDIR
+#define real_closedir(d) (_closedir(d))
+#elif SYS_closedir
+#define real_closedir(d) (syscall(SYS_closedir,(d)))
+#elif HAVE___CLOSEDIR
+#define real_closedir(d) (__closedir(d))
+#endif
+
+#ifdef HAVE__SEEKDIR
+#define real_seekdir(d,l) (_seekdir(d,l))
+#elif SYS_seekdir
+#define real_seekdir(d,l) (syscall(SYS_seekdir,(d),(l)))
+#elif HAVE___SEEKDIR
+#define real_seekdir(d,l) (__seekdir(d,l))
+#else
+#define NO_SEEKDIR_WRAPPER
+#endif
+
+#ifdef HAVE__TELLDIR
+#define real_telldir(d) (_telldir(d))
+#elif SYS_telldir
+#define real_telldir(d) (syscall(SYS_telldir,(d)))
+#elif HAVE___TELLDIR
+#define real_telldir(d) (__telldir(d))
+#endif
+
+#ifdef HAVE__DUP
+#define real_dup(d) (_dup(d))
+#elif SYS_dup
+#define real_dup(d) (syscall(SYS_dup,(d)))
+#elif HAVE___DUP
+#define real_dup(d) (__dup(d))
+#endif
+
+#ifdef HAVE__DUP2
+#define real_dup2(d1,d2) (_dup2(d1,d2))
+#elif SYS_dup2
+#define real_dup2(d1,d2) (syscall(SYS_dup2,(d1),(d2)))
+#elif HAVE___DUP2
+#define real_dup2(d1,d2) (__dup2(d1,d2))
+#endif
+
+#ifdef HAVE__GETCWD
+#define real_getcwd(b,s) ((char *)_getcwd(b,s))
+#elif SYS_getcwd
+#define real_getcwd(b,s) ((char *)syscall(SYS_getcwd,(b),(s)))
+#elif HAVE___GETCWD
+#define real_getcwd(b,s) ((char *)__getcwd(b,s))
+#endif
+
+#ifdef HAVE__STAT
+#define real_stat(fn,st) (_stat(fn,st))
+#elif SYS_stat
+#define real_stat(fn,st) (syscall(SYS_stat,(fn),(st)))
+#elif HAVE___STAT
+#define real_stat(fn,st) (__stat(fn,st))
+#endif
+
+#ifdef HAVE__LSTAT
+#define real_lstat(fn,st) (_lstat(fn,st))
+#elif SYS_lstat
+#define real_lstat(fn,st) (syscall(SYS_lstat,(fn),(st)))
+#elif HAVE___LSTAT
+#define real_lstat(fn,st) (__lstat(fn,st))
+#endif
+
+#ifdef HAVE__FSTAT
+#define real_fstat(fd,st) (_fstat(fd,st))
+#elif SYS_fstat
+#define real_fstat(fd,st) (syscall(SYS_fstat,(fd),(st)))
+#elif HAVE___FSTAT
+#define real_fstat(fd,st) (__fstat(fd,st))
+#endif
+
+#if defined(HAVE_SYS_ACL_H) && defined(HAVE__ACL)
+#define real_acl(fn,cmd,n,buf) (_acl(fn,cmd,n,buf))
+#elif SYS_acl
+#define real_acl(fn,cmd,n,buf) (syscall(SYS_acl,(fn),(cmd),(n),(buf)))
+#elif HAVE___ACL
+#define real_acl(fn,cmd,n,buf) (__acl(fn,cmd,n,buf))
+#else
+#define NO_ACL_WRAPPER
+#endif
+
+#ifdef HAVE__FACL
+#define real_facl(fd,cmd,n,buf) (_facl(fd,cmd,n,buf))
+#elif SYS_facl
+#define real_facl(fd,cmd,n,buf) (syscall(SYS_facl,(fd),(cmd),(n),(buf)))
+#elif HAVE___FACL
+#define real_facl(fd,cmd,n,buf) (__facl(fd,cmd,n,buf))
+#else
+#define NO_FACL_WRAPPER
+#endif
+
+
+#ifdef HAVE__STAT64
+#define real_stat64(fn,st) (_stat64(fn,st))
+#elif HAVE___STAT64
+#define real_stat64(fn,st) (__stat64(fn,st))
+#endif
+
+#ifdef HAVE__LSTAT64
+#define real_lstat64(fn,st) (_lstat64(fn,st))
+#elif HAVE___LSTAT64
+#define real_lstat64(fn,st) (__lstat64(fn,st))
+#endif
+
+#ifdef HAVE__FSTAT64
+#define real_fstat64(fd,st) (_fstat64(fd,st))
+#elif HAVE___FSTAT64
+#define real_fstat64(fd,st) (__fstat64(fd,st))
+#endif
+
+#ifdef HAVE__READDIR64
+#define real_readdir64(d) (_readdir64(d))
+#elif HAVE___READDIR64
+#define real_readdir64(d) (__readdir64(d))
+#endif
+
+#ifdef HAVE__LLSEEK
+#define real_llseek(fd,ofs,whence) (_llseek(fd,ofs,whence))
+#elif HAVE___LLSEEK
+#define real_llseek(fd,ofs,whence) (__llseek(fd,ofs,whence))
+#elif HAVE___SYS_LLSEEK
+#define real_llseek(fd,ofs,whence) (__sys_llseek(fd,ofs,whence))
+#endif
+
+
+#ifdef HAVE__PREAD
+#define real_pread(fd,buf,size,ofs) (_pread(fd,buf,size,ofs))
+#elif HAVE___PREAD
+#define real_pread(fd,buf,size,ofs) (__pread(fd,buf,size,ofs))
+#endif
+
+#ifdef HAVE__PREAD64
+#define real_pread64(fd,buf,size,ofs) (_pread64(fd,buf,size,ofs))
+#elif HAVE___PREAD64
+#define real_pread64(fd,buf,size,ofs) (__pread64(fd,buf,size,ofs))
+#endif
+
+#ifdef HAVE__PWRITE
+#define real_pwrite(fd,buf,size,ofs) (_pwrite(fd,buf,size,ofs))
+#elif HAVE___PWRITE
+#define real_pwrite(fd,buf,size,ofs) (__pwrite(fd,buf,size,ofs))
+#endif
+
+#ifdef HAVE__PWRITE64
+#define real_pwrite64(fd,buf,size,ofs) (_pwrite64(fd,buf,size,ofs))
+#elif HAVE___PWRITE64
+#define real_pwrite64(fd,buf,size,ofs) (__pwrite64(fd,buf,size,ofs))
+#endif
+
+
+#define real_readlink(fn,buf,len) (syscall(SYS_readlink, (fn), (buf), (len)))
+#define real_rename(fn1, fn2) (syscall(SYS_rename, (fn1), (fn2)))
+#define real_symlink(fn1, fn2) (syscall(SYS_symlink, (fn1), (fn2)))
+#define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))
+#define real_lseek(fd, offset, whence) (syscall(SYS_lseek, (fd), (offset), (whence)))
+#define real_write(fd, buf, count ) (syscall(SYS_write, (fd), (buf), (count)))
+#define real_close(fd) (syscall(SYS_close, (fd)))
+#define real_fchdir(fd) (syscall(SYS_fchdir, (fd)))
+#define real_fcntl(fd,cmd,arg) (syscall(SYS_fcntl, (fd), (cmd), (arg)))
+#define real_symlink(fn1, fn2) (syscall(SYS_symlink, (fn1), (fn2)))
+#define real_unlink(fn) (syscall(SYS_unlink, (fn)))
+#define real_rmdir(fn) (syscall(SYS_rmdir, (fn)))
+#define real_mkdir(fn, mode) (syscall(SYS_mkdir, (fn), (mode)))
+
+#ifdef SYS_utime
+#define real_utime(fn, buf) (syscall(SYS_utime, (fn), (buf)))
+#else
+#define REPLACE_UTIME 1
+#endif
+
+#ifdef SYS_utimes
+#define real_utimes(fn, buf) (syscall(SYS_utimes, (fn), (buf)))
+#else
+#define REPLACE_UTIMES 1
+#endif
diff --git a/source/smbwrapper/shared.c b/source/smbwrapper/shared.c
new file mode 100644
index 00000000000..90accbb503f
--- /dev/null
+++ b/source/smbwrapper/shared.c
@@ -0,0 +1,222 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions - shared variables
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static int shared_fd;
+static char *variables;
+static int shared_size;
+
+/*****************************************************
+setup the shared area
+*******************************************************/
+void smbw_setup_shared(void)
+{
+ int fd;
+ pstring name, s;
+
+ slprintf(name,sizeof(name)-1, "%s/smbw.XXXXXX",tmpdir());
+
+ fd = smb_mkstemp(name);
+
+ if (fd == -1) goto failed;
+
+ unlink(name);
+
+ shared_fd = set_maxfiles(SMBW_MAX_OPEN);
+
+ while (shared_fd && dup2(fd, shared_fd) != shared_fd) shared_fd--;
+
+ if (shared_fd == 0) goto failed;
+
+ close(fd);
+
+ DEBUG(4,("created shared_fd=%d\n", shared_fd));
+
+ slprintf(s,sizeof(s)-1,"%d", shared_fd);
+
+ smbw_setenv("SMBW_HANDLE", s);
+
+ return;
+
+ failed:
+ perror("Failed to setup shared variable area ");
+ exit(1);
+}
+
+static int locked;
+
+/*****************************************************
+lock the shared variable area
+*******************************************************/
+static void lockit(void)
+{
+ if (shared_fd == 0) {
+ char *p = getenv("SMBW_HANDLE");
+ if (!p) {
+ DEBUG(0,("ERROR: can't get smbw shared handle\n"));
+ exit(1);
+ }
+ shared_fd = atoi(p);
+ }
+ if (locked==0 &&
+ fcntl_lock(shared_fd,SMB_F_SETLKW,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: can't get smbw shared lock (%s)\n", strerror(errno)));
+ exit(1);
+ }
+ locked++;
+}
+
+/*****************************************************
+unlock the shared variable area
+*******************************************************/
+static void unlockit(void)
+{
+ locked--;
+ if (locked == 0) {
+ fcntl_lock(shared_fd,SMB_F_SETLK,0,1,F_UNLCK);
+ }
+}
+
+
+/*****************************************************
+get a variable from the shared area
+*******************************************************/
+char *smbw_getshared(const char *name)
+{
+ int i;
+ struct stat st;
+ char *var;
+
+ lockit();
+
+ /* maybe the area has changed */
+ if (fstat(shared_fd, &st)) goto failed;
+
+ if (st.st_size != shared_size) {
+ var = (char *)Realloc(variables, st.st_size);
+ if (!var) goto failed;
+ else variables = var;
+ shared_size = st.st_size;
+ lseek(shared_fd, 0, SEEK_SET);
+ if (read(shared_fd, variables, shared_size) != shared_size) {
+ goto failed;
+ }
+ }
+
+ unlockit();
+
+ i=0;
+ while (i < shared_size) {
+ char *n, *v;
+ int l1, l2;
+
+ l1 = SVAL(&variables[i], 0);
+ l2 = SVAL(&variables[i], 2);
+
+ n = &variables[i+4];
+ v = &variables[i+4+l1];
+ i += 4+l1+l2;
+
+ if (strcmp(name,n)) {
+ continue;
+ }
+ return v;
+ }
+
+ return NULL;
+
+ failed:
+ DEBUG(0,("smbw: shared variables corrupt (%s)\n", strerror(errno)));
+ exit(1);
+ return NULL;
+}
+
+
+
+/*****************************************************
+set a variable in the shared area
+*******************************************************/
+void smbw_setshared(const char *name, const char *val)
+{
+ int l1, l2;
+ char *var;
+
+ /* we don't allow variable overwrite */
+ if (smbw_getshared(name)) return;
+
+ lockit();
+
+ l1 = strlen(name)+1;
+ l2 = strlen(val)+1;
+
+ var = (char *)Realloc(variables, shared_size + l1+l2+4);
+
+ if (!var) {
+ DEBUG(0,("out of memory in smbw_setshared\n"));
+ exit(1);
+ }
+
+ variables = var;
+
+ SSVAL(&variables[shared_size], 0, l1);
+ SSVAL(&variables[shared_size], 2, l2);
+
+ pstrcpy(&variables[shared_size] + 4, name);
+ pstrcpy(&variables[shared_size] + 4 + l1, val);
+
+ shared_size += l1+l2+4;
+
+ lseek(shared_fd, 0, SEEK_SET);
+ if (write(shared_fd, variables, shared_size) != shared_size) {
+ DEBUG(0,("smbw_setshared failed (%s)\n", strerror(errno)));
+ exit(1);
+ }
+
+ unlockit();
+}
+
+
+/*****************************************************************
+set an env variable - some systems don't have this
+*****************************************************************/
+int smbw_setenv(const char *name, const char *value)
+{
+ pstring s;
+ char *p;
+ int ret = -1;
+
+ slprintf(s,sizeof(s)-1,"%s=%s", name, value);
+
+ p = strdup(s);
+
+ if (p) ret = putenv(p);
+
+ return ret;
+}
+
+/*****************************************************************
+return true if the passed fd is the SMBW_HANDLE
+*****************************************************************/
+int smbw_shared_fd(int fd)
+{
+ return (shared_fd && shared_fd == fd);
+}
diff --git a/source/smbwrapper/smbsh.c b/source/smbwrapper/smbsh.c
new file mode 100644
index 00000000000..694c6dd7994
--- /dev/null
+++ b/source/smbwrapper/smbsh.c
@@ -0,0 +1,128 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions - frontend
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static void smbsh_usage(void)
+{
+ printf("smbsh [options]\n\n");
+ printf(" -W workgroup\n");
+ printf(" -U username\n");
+ printf(" -P prefix\n");
+ printf(" -R resolve order\n");
+ printf(" -d debug level\n");
+ printf(" -l logfile\n");
+ printf(" -L libdir\n");
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ char *p, *u;
+ char *libd = dyn_BINDIR;
+ pstring line, wd;
+ int opt;
+ extern char *optarg;
+ extern int optind;
+
+ dbf = x_stdout;
+ smbw_setup_shared();
+
+ while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) {
+ switch (opt) {
+ case 'L':
+ libd = optarg;
+ break;
+ case 'W':
+ smbw_setshared("WORKGROUP", optarg);
+ break;
+ case 'l':
+ smbw_setshared("LOGFILE", optarg);
+ break;
+ case 'P':
+ smbw_setshared("PREFIX", optarg);
+ break;
+ case 'd':
+ smbw_setshared("DEBUG", optarg);
+ break;
+ case 'U':
+ p = strchr_m(optarg,'%');
+ if (p) {
+ *p=0;
+ smbw_setshared("PASSWORD",p+1);
+ }
+ smbw_setshared("USER", optarg);
+ break;
+ case 'R':
+ smbw_setshared("RESOLVE_ORDER",optarg);
+ break;
+
+ case 'h':
+ default:
+ smbsh_usage();
+ }
+ }
+
+
+ if (!smbw_getshared("USER")) {
+ printf("Username: ");
+ u = fgets_slash(line, sizeof(line)-1, x_stdin);
+ smbw_setshared("USER", u);
+ }
+
+ if (!smbw_getshared("PASSWORD")) {
+ p = getpass("Password: ");
+ smbw_setshared("PASSWORD", p);
+ }
+
+ smbw_setenv("PS1", "smbsh$ ");
+
+ sys_getwd(wd);
+
+ slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
+
+ smbw_setshared(line, wd);
+
+ slprintf(line,sizeof(line)-1,"%s/smbwrapper.so", libd);
+ smbw_setenv("LD_PRELOAD", line);
+
+ slprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so", libd);
+
+ if (file_exist(line, NULL)) {
+ slprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so:DEFAULT", libd);
+ smbw_setenv("_RLD_LIST", line);
+ slprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd);
+ smbw_setenv("_RLDN32_LIST", line);
+ } else {
+ slprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd);
+ smbw_setenv("_RLD_LIST", line);
+ }
+
+ {
+ char *shellpath = getenv("SHELL");
+ if(shellpath)
+ execl(shellpath,"smbsh",NULL);
+ else
+ execl("/bin/sh","smbsh",NULL);
+ }
+ printf("launch failed!\n");
+ return 1;
+}
diff --git a/source/smbwrapper/smbsh.in b/source/smbwrapper/smbsh.in
new file mode 100644
index 00000000000..323f0916993
--- /dev/null
+++ b/source/smbwrapper/smbsh.in
@@ -0,0 +1,54 @@
+#! /bin/sh
+
+SMBW_LIBDIR=${SMBW_LIBDIR-@builddir@/smbwrapper}
+
+if [ ! -f ${SMBW_LIBDIR}/smbwrapper.so ]; then
+ echo You need to set LIBDIR in smbsh
+ exit
+fi
+
+# a simple launcher for the smbwrapper.so preloadde library
+
+if [ x"${SMBW_USER+set}" != x"set" ]; then
+ echo username?
+ read user
+ SMBW_USER=$user
+ export SMBW_USER
+fi
+
+# this doesn't hide the password - we need a proper launch app for that
+if [ x"${SMBW_PASSWORD+set}" != x"set" ]; then
+ echo password?
+ read pass
+ SMBW_PASSWORD=$pass
+ export SMBW_PASSWORD
+fi
+
+PWD=`pwd`
+export PWD
+PS1='smbsh$ '
+export PS1
+
+
+host_os=@HOST_OS@
+
+case "$host_os" in
+ *irix*)
+ _RLDN32_LIST=$SMBW_LIBDIR/smbwrapper.so:DEFAULT
+ _RLD_LIST=$SMBW_LIBDIR/smbwrapper.32.so:DEFAULT
+ export _RLDN32_LIST
+ export _RLD_LIST
+ ;;
+ *osf*)
+ _RLD_LIST=$SMBW_LIBDIR/smbwrapper.so:DEFAULT
+ export _RLD_LIST
+ ;;
+ *)
+ LD_PRELOAD=$SMBW_LIBDIR/smbwrapper.so
+ export LD_PRELOAD
+ ;;
+esac
+
+echo starting smbwrapper on $host_os
+
+exec ${SMBW_SHELL-${SHELL-/bin/sh}} ${1+"$@"}
diff --git a/source/smbwrapper/smbw.c b/source/smbwrapper/smbw.c
new file mode 100644
index 00000000000..047db9bb963
--- /dev/null
+++ b/source/smbwrapper/smbw.c
@@ -0,0 +1,1555 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "realcalls.h"
+
+pstring smbw_cwd;
+
+static struct smbw_file *smbw_files;
+static struct smbw_server *smbw_srvs;
+
+struct bitmap *smbw_file_bmap;
+extern pstring global_myname;
+
+fstring smbw_prefix = SMBW_PREFIX;
+
+int smbw_busy=0;
+
+/* needs to be here because of dumb include files on some systems */
+int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
+
+
+/*****************************************************
+initialise structures
+*******************************************************/
+void smbw_init(void)
+{
+ extern BOOL in_client;
+ static int initialised;
+ char *p;
+ int eno;
+ pstring line;
+
+ if (initialised) return;
+ initialised = 1;
+
+ eno = errno;
+
+ smbw_busy++;
+
+ DEBUGLEVEL = 0;
+ setup_logging("smbsh",True);
+
+ dbf = x_stderr;
+
+ if ((p=smbw_getshared("LOGFILE"))) {
+ dbf = sys_fopen(p, "a");
+ }
+
+ smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
+ if (!smbw_file_bmap) {
+ exit(1);
+ }
+
+ in_client = True;
+
+ load_interfaces();
+
+ if ((p=smbw_getshared("SERVICESF"))) {
+ pstrcpy(dyn_CONFIGFILE, p);
+ }
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+
+ get_myname(global_myname);
+
+ if ((p=smbw_getshared("DEBUG"))) {
+ DEBUGLEVEL = atoi(p);
+ }
+
+ if ((p=smbw_getshared("RESOLVE_ORDER"))) {
+ lp_set_name_resolve_order(p);
+ }
+
+ if ((p=smbw_getshared("PREFIX"))) {
+ slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
+ all_string_sub(smbw_prefix,"//", "/", 0);
+ DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
+ }
+
+ slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
+
+ p = smbw_getshared(line);
+ if (!p) {
+ sys_getwd(smbw_cwd);
+ }
+ pstrcpy(smbw_cwd, p);
+ DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
+
+ smbw_busy--;
+
+ set_maxfiles(SMBW_MAX_OPEN);
+
+ BlockSignals(True,SIGPIPE);
+
+ errno = eno;
+}
+
+/*****************************************************
+determine if a file descriptor is a smb one
+*******************************************************/
+int smbw_fd(int fd)
+{
+ if (smbw_busy) return 0;
+ return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
+}
+
+/*****************************************************
+determine if a file descriptor is an internal smbw fd
+*******************************************************/
+int smbw_local_fd(int fd)
+{
+ struct smbw_server *srv;
+
+ smbw_init();
+
+ if (smbw_busy) return 0;
+ if (smbw_shared_fd(fd)) return 1;
+
+ for (srv=smbw_srvs;srv;srv=srv->next) {
+ if (srv->cli.fd == fd) return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************
+a crude inode number generator
+*******************************************************/
+ino_t smbw_inode(const char *name)
+{
+ if (!*name) return 2;
+ return (ino_t)str_checksum(name);
+}
+
+/*****************************************************
+remove redundent stuff from a filename
+*******************************************************/
+void clean_fname(char *name)
+{
+ char *p, *p2;
+ int l;
+ int modified = 1;
+
+ if (!name) return;
+
+ while (modified) {
+ modified = 0;
+
+ DEBUG(5,("cleaning %s\n", name));
+
+ if ((p=strstr(name,"/./"))) {
+ modified = 1;
+ while (*p) {
+ p[0] = p[2];
+ p++;
+ }
+ }
+
+ if ((p=strstr(name,"//"))) {
+ modified = 1;
+ while (*p) {
+ p[0] = p[1];
+ p++;
+ }
+ }
+
+ if (strcmp(name,"/../")==0) {
+ modified = 1;
+ name[1] = 0;
+ }
+
+ if ((p=strstr(name,"/../"))) {
+ modified = 1;
+ for (p2=(p>name?p-1:p);p2>name;p2--) {
+ if (p2[0] == '/') break;
+ }
+ while (*p2) {
+ p2[0] = p2[3];
+ p2++;
+ }
+ }
+
+ if (strcmp(name,"/..")==0) {
+ modified = 1;
+ name[1] = 0;
+ }
+
+ l = strlen(name);
+ p = l>=3?(name+l-3):name;
+ if (strcmp(p,"/..")==0) {
+ modified = 1;
+ for (p2=p-1;p2>name;p2--) {
+ if (p2[0] == '/') break;
+ }
+ if (p2==name) {
+ p[0] = '/';
+ p[1] = 0;
+ } else {
+ p2[0] = 0;
+ }
+ }
+
+ l = strlen(name);
+ p = l>=2?(name+l-2):name;
+ if (strcmp(p,"/.")==0) {
+ if (p == name) {
+ p[1] = 0;
+ } else {
+ p[0] = 0;
+ }
+ }
+
+ if (strncmp(p=name,"./",2) == 0) {
+ modified = 1;
+ do {
+ p[0] = p[2];
+ } while (*p++);
+ }
+
+ l = strlen(p=name);
+ if (l > 1 && p[l-1] == '/') {
+ modified = 1;
+ p[l-1] = 0;
+ }
+ }
+}
+
+
+
+/*****************************************************
+find a workgroup (any workgroup!) that has a master
+browser on the local network
+*******************************************************/
+static char *smbw_find_workgroup(void)
+{
+ fstring server;
+ char *p;
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+
+ /* first off see if an existing workgroup name exists */
+ p = smbw_getshared("WORKGROUP");
+ if (!p) p = lp_workgroup();
+
+ slprintf(server, sizeof(server), "%s#1D", p);
+ if (smbw_server(server, "IPC$")) return p;
+
+ /* go looking for workgroups */
+ if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
+ DEBUG(1,("No workgroups found!"));
+ return p;
+ }
+
+ for (i=0;i<count;i++) {
+ static fstring name;
+ if (name_status_find("*", 0, 0x1d, ip_list[i], name)) {
+ slprintf(server, sizeof(server), "%s#1D", name);
+ if (smbw_server(server, "IPC$")) {
+ smbw_setshared("WORKGROUP", name);
+ SAFE_FREE(ip_list);
+ return name;
+ }
+ }
+ }
+
+ SAFE_FREE(ip_list);
+
+ return p;
+}
+
+/*****************************************************
+parse a smb path into its components.
+server is one of
+ 1) the name of the SMB server
+ 2) WORKGROUP#1D for share listing
+ 3) WORKGROUP#__ for workgroup listing
+share is the share on the server to query
+path is the SMB path on the server
+return the full path (ie. add cwd if needed)
+*******************************************************/
+char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
+{
+ static pstring s;
+ char *p;
+ int len;
+ fstring workgroup;
+
+ /* add cwd if necessary */
+ if (fname[0] != '/') {
+ slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
+ } else {
+ pstrcpy(s, fname);
+ }
+ clean_fname(s);
+
+ /* see if it has the right prefix */
+ len = strlen(smbw_prefix)-1;
+ if (strncmp(s,smbw_prefix,len) ||
+ (s[len] != '/' && s[len] != 0)) return s;
+
+ /* ok, its for us. Now parse out the workgroup, share etc. */
+ p = s+len;
+ if (*p == '/') p++;
+ if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
+ /* we're in /smb - give a list of workgroups */
+ slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
+ fstrcpy(share,"IPC$");
+ pstrcpy(path,"");
+ return s;
+ }
+
+ if (!next_token(&p, server, "/", sizeof(fstring))) {
+ /* we are in /smb/WORKGROUP */
+ slprintf(server,sizeof(fstring), "%s#1D", workgroup);
+ fstrcpy(share,"IPC$");
+ pstrcpy(path,"");
+ }
+
+ if (!next_token(&p, share, "/", sizeof(fstring))) {
+ /* we are in /smb/WORKGROUP/SERVER */
+ fstrcpy(share,"IPC$");
+ pstrcpy(path,"");
+ }
+
+ pstrcpy(path, p);
+
+ all_string_sub(path, "/", "\\", 0);
+
+ return s;
+}
+
+/*****************************************************
+determine if a path name (possibly relative) is in the
+smb name space
+*******************************************************/
+int smbw_path(const char *path)
+{
+ fstring server, share;
+ pstring s;
+ char *cwd;
+ int len;
+
+ if(!path)
+ return 0;
+
+ /* this is needed to prevent recursion with the BSD malloc which
+ opens /etc/malloc.conf on the first call */
+ if (strncmp(path,"/etc/", 5) == 0) {
+ return 0;
+ }
+
+ smbw_init();
+
+ len = strlen(smbw_prefix)-1;
+
+ if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
+ return 0;
+ }
+
+ if (smbw_busy) return 0;
+
+ DEBUG(3,("smbw_path(%s)\n", path));
+
+ cwd = smbw_parse_path(path, server, share, s);
+
+ if (strncmp(cwd,smbw_prefix,len) == 0 &&
+ (cwd[len] == '/' || cwd[len] == 0)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************
+return a unix errno from a SMB error pair
+*******************************************************/
+int smbw_errno(struct cli_state *c)
+{
+ return cli_errno(c);
+}
+
+/* Return a username and password given a server and share name */
+
+void get_envvar_auth_data(char *server, char *share, char **workgroup,
+ char **username, char **password)
+{
+ /* Fall back to shared memory/environment variables */
+
+ *username = smbw_getshared("USER");
+ if (!*username) *username = getenv("USER");
+ if (!*username) *username = "guest";
+
+ *workgroup = smbw_getshared("WORKGROUP");
+ if (!*workgroup) *workgroup = lp_workgroup();
+
+ *password = smbw_getshared("PASSWORD");
+ if (!*password) *password = "";
+}
+
+static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
+
+/*****************************************************
+set the get auth data function
+******************************************************/
+void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
+{
+ get_auth_data_fn = fn;
+}
+
+/*****************************************************
+return a connection to a server (existing or new)
+*******************************************************/
+struct smbw_server *smbw_server(char *server, char *share)
+{
+ struct smbw_server *srv=NULL;
+ struct cli_state c;
+ char *username;
+ char *password;
+ char *workgroup;
+ struct nmb_name called, calling;
+ char *p, *server_n = server;
+ fstring group;
+ pstring ipenv;
+ struct in_addr ip;
+
+ zero_ip(&ip);
+ ZERO_STRUCT(c);
+
+ get_auth_data_fn(server, share, &workgroup, &username, &password);
+
+ /* try to use an existing connection */
+ for (srv=smbw_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ if (server[0] == 0) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ make_nmb_name(&calling, global_myname, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
+
+ if ((p=strchr_m(server_n,'#')) &&
+ (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
+ struct in_addr sip;
+ pstring s;
+
+ fstrcpy(group, server_n);
+ p = strchr_m(group,'#');
+ *p = 0;
+
+ /* cache the workgroup master lookup */
+ slprintf(s,sizeof(s)-1,"MASTER_%s", group);
+ if (!(server_n = smbw_getshared(s))) {
+ if (!find_master_ip(group, &sip)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ fstrcpy(group, inet_ntoa(sip));
+ server_n = group;
+ smbw_setshared(s,server_n);
+ }
+ }
+
+ DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
+
+ again:
+ slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
+
+ zero_ip(&ip);
+ if ((p=smbw_getshared(ipenv))) {
+ ip = *(interpret_addr2(p));
+ }
+
+ /* have to open a new connection */
+ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_request(&c, &calling, &called)) {
+ cli_shutdown(&c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ errno = ENOENT;
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(&c)) {
+ cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_setup(&c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup) &&
+ /* try an anonymous login if it failed */
+ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
+ cli_shutdown(&c);
+ errno = EPERM;
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(&c, share, "?????",
+ password, strlen(password)+1)) {
+ errno = smbw_errno(&c);
+ cli_shutdown(&c);
+ return NULL;
+ }
+
+ smbw_setshared(ipenv,inet_ntoa(ip));
+
+ DEBUG(4,(" tconx ok\n"));
+
+ srv = (struct smbw_server *)malloc(sizeof(*srv));
+ if (!srv) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(srv);
+
+ srv->cli = c;
+
+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+
+ srv->server_name = strdup(server);
+ if (!srv->server_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->share_name = strdup(share);
+ if (!srv->share_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->workgroup = strdup(workgroup);
+ if (!srv->workgroup) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->username = strdup(username);
+ if (!srv->username) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ /* some programs play with file descriptors fairly intimately. We
+ try to get out of the way by duping to a high fd number */
+ if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
+ if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
+ srv->cli.fd+SMBW_CLI_FD) {
+ close(srv->cli.fd);
+ srv->cli.fd += SMBW_CLI_FD;
+ }
+ }
+
+ DLIST_ADD(smbw_srvs, srv);
+
+ return srv;
+
+ failed:
+ cli_shutdown(&c);
+ if (!srv) return NULL;
+
+ SAFE_FREE(srv->server_name);
+ SAFE_FREE(srv->share_name);
+ SAFE_FREE(srv);
+ return NULL;
+}
+
+
+/*****************************************************
+map a fd to a smbw_file structure
+*******************************************************/
+struct smbw_file *smbw_file(int fd)
+{
+ struct smbw_file *file;
+
+ for (file=smbw_files;file;file=file->next) {
+ if (file->fd == fd) return file;
+ }
+ return NULL;
+}
+
+/*****************************************************
+a wrapper for open()
+*******************************************************/
+int smbw_open(const char *fname, int flags, mode_t mode)
+{
+ fstring server, share;
+ pstring path;
+ struct smbw_server *srv=NULL;
+ int eno=0, fd = -1;
+ struct smbw_file *file=NULL;
+
+ smbw_init();
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (path[strlen(path)-1] == '\\') {
+ fd = -1;
+ } else {
+ fd = cli_open(&srv->cli, path, flags, DENY_NONE);
+ }
+ if (fd == -1) {
+ /* it might be a directory. Maybe we should use chkpath? */
+ eno = smbw_errno(&srv->cli);
+ fd = smbw_dir_open(fname);
+ if (fd == -1) errno = eno;
+ smbw_busy--;
+ return fd;
+ }
+
+ file = (struct smbw_file *)malloc(sizeof(*file));
+ if (!file) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(file);
+
+ file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
+ if (!file->f) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(file->f);
+
+ file->f->cli_fd = fd;
+ file->f->fname = strdup(path);
+ if (!file->f->fname) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ file->srv = srv;
+ file->fd = open(SMBW_DUMMY, O_WRONLY);
+ if (file->fd == -1) {
+ errno = EMFILE;
+ goto failed;
+ }
+
+ if (bitmap_query(smbw_file_bmap, file->fd)) {
+ DEBUG(0,("ERROR: fd used in smbw_open\n"));
+ errno = EIO;
+ goto failed;
+ }
+
+ file->f->ref_count=1;
+
+ bitmap_set(smbw_file_bmap, file->fd);
+
+ DLIST_ADD(smbw_files, file);
+
+ DEBUG(4,("opened %s\n", fname));
+
+ smbw_busy--;
+ return file->fd;
+
+ failed:
+ if (fd != -1) {
+ cli_close(&srv->cli, fd);
+ }
+ if (file) {
+ if (file->f) {
+ SAFE_FREE(file->f->fname);
+ SAFE_FREE(file->f);
+ }
+ SAFE_FREE(file);
+ }
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for pread()
+*******************************************************/
+ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
+{
+ struct smbw_file *file;
+ int ret;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ smbw_busy--;
+ return -1;
+ }
+
+ ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
+
+ if (ret == -1) {
+ errno = smbw_errno(&file->srv->cli);
+ smbw_busy--;
+ return -1;
+ }
+
+ smbw_busy--;
+ return ret;
+}
+
+/*****************************************************
+a wrapper for read()
+*******************************************************/
+ssize_t smbw_read(int fd, void *buf, size_t count)
+{
+ struct smbw_file *file;
+ int ret;
+
+ DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ smbw_busy--;
+ return -1;
+ }
+
+ ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
+ file->f->offset, count);
+
+ if (ret == -1) {
+ errno = smbw_errno(&file->srv->cli);
+ smbw_busy--;
+ return -1;
+ }
+
+ file->f->offset += ret;
+
+ DEBUG(4,(" -> %d\n", ret));
+
+ smbw_busy--;
+ return ret;
+}
+
+
+
+/*****************************************************
+a wrapper for write()
+*******************************************************/
+ssize_t smbw_write(int fd, void *buf, size_t count)
+{
+ struct smbw_file *file;
+ int ret;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ smbw_busy--;
+ return -1;
+ }
+
+ ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
+
+ if (ret == -1) {
+ errno = smbw_errno(&file->srv->cli);
+ smbw_busy--;
+ return -1;
+ }
+
+ file->f->offset += ret;
+
+ smbw_busy--;
+ return ret;
+}
+
+/*****************************************************
+a wrapper for pwrite()
+*******************************************************/
+ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
+{
+ struct smbw_file *file;
+ int ret;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ smbw_busy--;
+ return -1;
+ }
+
+ ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
+
+ if (ret == -1) {
+ errno = smbw_errno(&file->srv->cli);
+ smbw_busy--;
+ return -1;
+ }
+
+ smbw_busy--;
+ return ret;
+}
+
+/*****************************************************
+a wrapper for close()
+*******************************************************/
+int smbw_close(int fd)
+{
+ struct smbw_file *file;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ int ret = smbw_dir_close(fd);
+ smbw_busy--;
+ return ret;
+ }
+
+ if (file->f->ref_count == 1 &&
+ !cli_close(&file->srv->cli, file->f->cli_fd)) {
+ errno = smbw_errno(&file->srv->cli);
+ smbw_busy--;
+ return -1;
+ }
+
+
+ bitmap_clear(smbw_file_bmap, file->fd);
+ close(file->fd);
+
+ DLIST_REMOVE(smbw_files, file);
+
+ file->f->ref_count--;
+ if (file->f->ref_count == 0) {
+ SAFE_FREE(file->f->fname);
+ SAFE_FREE(file->f);
+ }
+ ZERO_STRUCTP(file);
+ SAFE_FREE(file);
+
+ smbw_busy--;
+
+ return 0;
+}
+
+
+/*****************************************************
+a wrapper for fcntl()
+*******************************************************/
+int smbw_fcntl(int fd, int cmd, long arg)
+{
+ return 0;
+}
+
+
+/*****************************************************
+a wrapper for access()
+*******************************************************/
+int smbw_access(const char *name, int mode)
+{
+ struct stat st;
+
+ DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
+
+ if (smbw_stat(name, &st)) return -1;
+
+ if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
+ ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
+ ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************
+a wrapper for realink() - needed for correct errno setting
+*******************************************************/
+int smbw_readlink(const char *path, char *buf, size_t bufsize)
+{
+ struct stat st;
+ int ret;
+
+ ret = smbw_stat(path, &st);
+ if (ret != 0) {
+ DEBUG(4,("readlink(%s) failed\n", path));
+ return -1;
+ }
+
+ /* it exists - say it isn't a link */
+ DEBUG(4,("readlink(%s) not a link\n", path));
+
+ errno = EINVAL;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for unlink()
+*******************************************************/
+int smbw_unlink(const char *fname)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+ int job = smbw_stat_printjob(srv, path, NULL, NULL);
+ if (job == -1) {
+ goto failed;
+ }
+ if (cli_printjob_del(&srv->cli, job) != 0) {
+ goto failed;
+ }
+ } else if (!cli_unlink(&srv->cli, path)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for rename()
+*******************************************************/
+int smbw_rename(const char *oldname, const char *newname)
+{
+ struct smbw_server *srv;
+ fstring server1, share1;
+ pstring path1;
+ fstring server2, share2;
+ pstring path2;
+
+ if (!oldname || !newname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(oldname, server1, share1, path1);
+ smbw_parse_path(newname, server2, share2, path2);
+
+ if (strcmp(server1, server2) || strcmp(share1, share2)) {
+ /* can't cross filesystems */
+ errno = EXDEV;
+ return -1;
+ }
+
+ /* get a connection to the server */
+ srv = smbw_server(server1, share1);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (!cli_rename(&srv->cli, path1, path2)) {
+ int eno = smbw_errno(&srv->cli);
+ if (eno != EEXIST ||
+ !cli_unlink(&srv->cli, path2) ||
+ !cli_rename(&srv->cli, path1, path2)) {
+ errno = eno;
+ goto failed;
+ }
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for utime and utimes
+*******************************************************/
+static int smbw_settime(const char *fname, time_t t)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+ uint16 mode;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ if (!cli_setatr(&srv->cli, path, mode, t)) {
+ /* some servers always refuse directory changes */
+ if (!(mode & aDIR)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+/*****************************************************
+a wrapper for utime
+*******************************************************/
+int smbw_utime(const char *fname, void *buf)
+{
+ struct utimbuf *tbuf = (struct utimbuf *)buf;
+ return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
+}
+
+/*****************************************************
+a wrapper for utime
+*******************************************************/
+int smbw_utimes(const char *fname, void *buf)
+{
+ struct timeval *tbuf = (struct timeval *)buf;
+ return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
+}
+
+
+/*****************************************************
+a wrapper for chown()
+*******************************************************/
+int smbw_chown(const char *fname, uid_t owner, gid_t group)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+ uint16 mode;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ /* assume success */
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+/*****************************************************
+a wrapper for chmod()
+*******************************************************/
+int smbw_chmod(const char *fname, mode_t newmode)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+ uint32 mode;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ mode = 0;
+
+ if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
+ if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
+ if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
+ if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
+
+ if (!cli_setatr(&srv->cli, path, mode, 0)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+/*****************************************************
+a wrapper for lseek()
+*******************************************************/
+off_t smbw_lseek(int fd, off_t offset, int whence)
+{
+ struct smbw_file *file;
+ size_t size;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ off_t ret = smbw_dir_lseek(fd, offset, whence);
+ smbw_busy--;
+ return ret;
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ file->f->offset = offset;
+ break;
+ case SEEK_CUR:
+ file->f->offset += offset;
+ break;
+ case SEEK_END:
+ if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
+ NULL, &size, NULL, NULL, NULL,
+ NULL, NULL) &&
+ !cli_getattrE(&file->srv->cli, file->f->cli_fd,
+ NULL, &size, NULL, NULL, NULL)) {
+ errno = EINVAL;
+ smbw_busy--;
+ return -1;
+ }
+ file->f->offset = size + offset;
+ break;
+ }
+
+ smbw_busy--;
+ return file->f->offset;
+}
+
+
+/*****************************************************
+a wrapper for dup()
+*******************************************************/
+int smbw_dup(int fd)
+{
+ int fd2;
+ struct smbw_file *file, *file2;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ goto failed;
+ }
+
+ fd2 = dup(file->fd);
+ if (fd2 == -1) {
+ goto failed;
+ }
+
+ if (bitmap_query(smbw_file_bmap, fd2)) {
+ DEBUG(0,("ERROR: fd already open in dup!\n"));
+ errno = EIO;
+ goto failed;
+ }
+
+ file2 = (struct smbw_file *)malloc(sizeof(*file2));
+ if (!file2) {
+ close(fd2);
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(file2);
+
+ *file2 = *file;
+ file2->fd = fd2;
+
+ file->f->ref_count++;
+
+ bitmap_set(smbw_file_bmap, fd2);
+
+ DLIST_ADD(smbw_files, file2);
+
+ smbw_busy--;
+ return fd2;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for dup2()
+*******************************************************/
+int smbw_dup2(int fd, int fd2)
+{
+ struct smbw_file *file, *file2;
+
+ smbw_busy++;
+
+ file = smbw_file(fd);
+ if (!file) {
+ errno = EBADF;
+ goto failed;
+ }
+
+ if (bitmap_query(smbw_file_bmap, fd2)) {
+ DEBUG(0,("ERROR: fd already open in dup2!\n"));
+ errno = EIO;
+ goto failed;
+ }
+
+ if (dup2(file->fd, fd2) != fd2) {
+ goto failed;
+ }
+
+ file2 = (struct smbw_file *)malloc(sizeof(*file2));
+ if (!file2) {
+ close(fd2);
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(file2);
+
+ *file2 = *file;
+ file2->fd = fd2;
+
+ file->f->ref_count++;
+
+ bitmap_set(smbw_file_bmap, fd2);
+
+ DLIST_ADD(smbw_files, file2);
+
+ smbw_busy--;
+ return fd2;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+close a connection to a server
+*******************************************************/
+static void smbw_srv_close(struct smbw_server *srv)
+{
+ smbw_busy++;
+
+ cli_shutdown(&srv->cli);
+
+ SAFE_FREE(srv->server_name);
+ SAFE_FREE(srv->share_name);
+
+ DLIST_REMOVE(smbw_srvs, srv);
+
+ ZERO_STRUCTP(srv);
+
+ SAFE_FREE(srv);
+
+ smbw_busy--;
+}
+
+/*****************************************************
+when we fork we have to close all connections and files
+in the child
+*******************************************************/
+int smbw_fork(void)
+{
+ pid_t child;
+ int p[2];
+ char c=0;
+ pstring line;
+
+ struct smbw_file *file, *next_file;
+ struct smbw_server *srv, *next_srv;
+
+ if (pipe(p)) return real_fork();
+
+ child = real_fork();
+
+ if (child) {
+ /* block the parent for a moment until the sockets are
+ closed */
+ close(p[1]);
+ read(p[0], &c, 1);
+ close(p[0]);
+ return child;
+ }
+
+ close(p[0]);
+
+ /* close all files */
+ for (file=smbw_files;file;file=next_file) {
+ next_file = file->next;
+ close(file->fd);
+ }
+
+ /* close all server connections */
+ for (srv=smbw_srvs;srv;srv=next_srv) {
+ next_srv = srv->next;
+ smbw_srv_close(srv);
+ }
+
+ slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
+ smbw_setshared(line,smbw_cwd);
+
+ /* unblock the parent */
+ write(p[1], &c, 1);
+ close(p[1]);
+
+ /* and continue in the child */
+ return 0;
+}
+
+#ifndef NO_ACL_WRAPPER
+/*****************************************************
+say no to acls
+*******************************************************/
+ int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
+{
+ if (cmd == GETACL || cmd == GETACLCNT) return 0;
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef NO_FACL_WRAPPER
+/*****************************************************
+say no to acls
+*******************************************************/
+ int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
+{
+ if (cmd == GETACL || cmd == GETACLCNT) return 0;
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
+#ifdef HAVE_STAT64
+/* this can't be in wrapped.c because of include conflicts */
+ void stat64_convert(struct stat *st, struct stat64 *st64)
+{
+ st64->st_size = st->st_size;
+ st64->st_mode = st->st_mode;
+ st64->st_ino = st->st_ino;
+ st64->st_dev = st->st_dev;
+ st64->st_rdev = st->st_rdev;
+ st64->st_nlink = st->st_nlink;
+ st64->st_uid = st->st_uid;
+ st64->st_gid = st->st_gid;
+ st64->st_atime = st->st_atime;
+ st64->st_mtime = st->st_mtime;
+ st64->st_ctime = st->st_ctime;
+ st64->st_blksize = st->st_blksize;
+ st64->st_blocks = st->st_blocks;
+}
+#endif
+
+#ifdef HAVE_READDIR64
+ void dirent64_convert(struct dirent *d, struct dirent64 *d64)
+{
+ d64->d_ino = d->d_ino;
+ d64->d_off = d->d_off;
+ d64->d_reclen = d->d_reclen;
+ pstrcpy(d64->d_name, d->d_name);
+}
+#endif
+#endif
+
+
+#ifdef HAVE___XSTAT
+/* Definition of `struct stat' used in the linux kernel.. */
+struct kernel_stat {
+ unsigned short int st_dev;
+ unsigned short int __pad1;
+ unsigned long int st_ino;
+ unsigned short int st_mode;
+ unsigned short int st_nlink;
+ unsigned short int st_uid;
+ unsigned short int st_gid;
+ unsigned short int st_rdev;
+ unsigned short int __pad2;
+ unsigned long int st_size;
+ unsigned long int st_blksize;
+ unsigned long int st_blocks;
+ unsigned long int st_atime;
+ unsigned long int __unused1;
+ unsigned long int st_mtime;
+ unsigned long int __unused2;
+ unsigned long int st_ctime;
+ unsigned long int __unused3;
+ unsigned long int __unused4;
+ unsigned long int __unused5;
+};
+
+/*
+ * Prototype for gcc in 'fussy' mode.
+ */
+ void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
+ void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
+{
+#ifdef _STAT_VER_LINUX_OLD
+ if (vers == _STAT_VER_LINUX_OLD) {
+ memcpy(st, kbuf, sizeof(*st));
+ return;
+ }
+#endif
+
+ ZERO_STRUCTP(st);
+
+ st->st_dev = kbuf->st_dev;
+ st->st_ino = kbuf->st_ino;
+ st->st_mode = kbuf->st_mode;
+ st->st_nlink = kbuf->st_nlink;
+ st->st_uid = kbuf->st_uid;
+ st->st_gid = kbuf->st_gid;
+ st->st_rdev = kbuf->st_rdev;
+ st->st_size = kbuf->st_size;
+ st->st_blksize = kbuf->st_blksize;
+ st->st_blocks = kbuf->st_blocks;
+ st->st_atime = kbuf->st_atime;
+ st->st_mtime = kbuf->st_mtime;
+ st->st_ctime = kbuf->st_ctime;
+}
+#endif
diff --git a/source/smbwrapper/smbw.h b/source/smbwrapper/smbw.h
new file mode 100644
index 00000000000..d059b20c788
--- /dev/null
+++ b/source/smbwrapper/smbw.h
@@ -0,0 +1,72 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions - definitions
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SMBW_H
+#define _SMBW_H
+
+#define SMBW_PREFIX "/smb/"
+#define SMBW_DUMMY "/dev/null"
+
+#define SMBW_CLI_FD 512
+#define SMBW_MAX_OPEN 8192
+
+#define SMBW_FILE_MODE (S_IFREG | 0444)
+#define SMBW_DIR_MODE (S_IFDIR | 0555)
+
+struct smbw_server {
+ struct smbw_server *next, *prev;
+ struct cli_state cli;
+ char *server_name;
+ char *share_name;
+ char *workgroup;
+ char *username;
+ dev_t dev;
+ BOOL no_pathinfo2;
+};
+
+struct smbw_filedes {
+ int cli_fd;
+ int ref_count;
+ char *fname;
+ off_t offset;
+};
+
+struct smbw_file {
+ struct smbw_file *next, *prev;
+ struct smbw_filedes *f;
+ int fd;
+ struct smbw_server *srv;
+};
+
+struct smbw_dir {
+ struct smbw_dir *next, *prev;
+ int fd;
+ int offset, count, malloced;
+ struct smbw_server *srv;
+ struct file_info *list;
+ char *path;
+};
+
+typedef void (*smbw_get_auth_data_fn)(char *server, char *share,
+ char **workgroup, char **username,
+ char **password);
+
+#endif /* _SMBW_H */
diff --git a/source/smbwrapper/smbw_cache.c b/source/smbwrapper/smbw_cache.c
new file mode 100644
index 00000000000..13a68e74544
--- /dev/null
+++ b/source/smbwrapper/smbw_cache.c
@@ -0,0 +1,208 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper directory functions
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* We cache lists of workgroups, lists of servers in workgroups, and lists
+ of shares exported by servers. */
+
+#define CACHE_TIMEOUT 30
+
+struct name_list {
+ struct name_list *prev, *next;
+ char *name;
+ uint32 stype;
+ char *comment;
+};
+
+struct cached_names {
+ struct cached_names *prev, *next;
+ char *key;
+ struct name_list *name_list;
+ time_t cache_timeout;
+ int result;
+};
+
+static struct cached_names *cached_names = NULL;
+
+/* Find a list of cached name for a workgroup, server or share list */
+
+static struct cached_names *find_cached_names(char *key)
+{
+ struct cached_names *tmp;
+
+ for (tmp = cached_names; tmp; tmp = tmp->next) {
+ if (strequal(tmp->key, key)) {
+ return tmp;
+ }
+ }
+
+ return NULL;
+}
+
+/* Add a name to a list stored in the state variable */
+
+static void add_cached_names(const char *name, uint32 stype,
+ const char *comment, void *state)
+{
+ struct name_list **name_list = (struct name_list **)state;
+ struct name_list *new_name;
+
+ new_name = (struct name_list *)malloc(sizeof(struct name_list));
+ if (!new_name) return;
+
+ ZERO_STRUCTP(new_name);
+
+ new_name->name = strdup(name);
+ new_name->stype = stype;
+ new_name->comment = strdup(comment);
+
+ DLIST_ADD(*name_list, new_name);
+}
+
+static void free_name_list(struct name_list *name_list)
+{
+ struct name_list *tmp = name_list;
+
+ while(tmp) {
+ struct name_list *next;
+
+ next = tmp->next;
+
+ SAFE_FREE(tmp->name);
+ SAFE_FREE(tmp->comment);
+ SAFE_FREE(tmp);
+
+ tmp = next;
+ }
+}
+
+/* Wrapper for NetServerEnum function */
+
+BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ struct cached_names *names;
+ struct name_list *tmp;
+ time_t now = time(NULL);
+ char key[PATH_MAX];
+ BOOL result = True;
+
+ slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost,
+ workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV"));
+
+ names = find_cached_names(key);
+
+ if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
+ struct cached_names *new_names = NULL;
+
+ /* No names cached for this workgroup */
+
+ if (names == NULL) {
+ new_names = (struct cached_names *)
+ malloc(sizeof(struct cached_names));
+
+ ZERO_STRUCTP(new_names);
+ DLIST_ADD(cached_names, new_names);
+
+ } else {
+
+ /* Dispose of out of date name list */
+
+ free_name_list(names->name_list);
+ names->name_list = NULL;
+
+ new_names = names;
+ }
+
+ result = cli_NetServerEnum(cli, workgroup, stype,
+ add_cached_names,
+ &new_names->name_list);
+
+ new_names->cache_timeout = now;
+ new_names->result = result;
+ new_names->key = strdup(key);
+
+ names = new_names;
+ }
+
+ /* Return names by running callback function. */
+
+ for (tmp = names->name_list; tmp; tmp = tmp->next)
+ fn(tmp->name, stype, tmp->comment, state);
+
+ return names->result;
+}
+
+/* Wrapper for RNetShareEnum function */
+
+int smbw_RNetShareEnum(struct cli_state *cli,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ struct cached_names *names;
+ struct name_list *tmp;
+ time_t now = time(NULL);
+ char key[PATH_MAX];
+
+ slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost);
+
+ names = find_cached_names(key);
+
+ if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
+ struct cached_names *new_names = NULL;
+
+ /* No names cached for this server */
+
+ if (names == NULL) {
+ new_names = (struct cached_names *)
+ malloc(sizeof(struct cached_names));
+
+ ZERO_STRUCTP(new_names);
+ DLIST_ADD(cached_names, new_names);
+
+ } else {
+
+ /* Dispose of out of date name list */
+
+ free_name_list(names->name_list);
+ names->name_list = NULL;
+
+ new_names = names;
+ }
+
+ new_names->result = cli_RNetShareEnum(cli, add_cached_names,
+ &new_names->name_list);
+
+ new_names->cache_timeout = now;
+ new_names->key = strdup(key);
+
+ names = new_names;
+ }
+
+ /* Return names by running callback function. */
+
+ for (tmp = names->name_list; tmp; tmp = tmp->next)
+ fn(tmp->name, tmp->stype, tmp->comment, state);
+
+ return names->result;
+}
diff --git a/source/smbwrapper/smbw_dir.c b/source/smbwrapper/smbw_dir.c
new file mode 100644
index 00000000000..6be88e4df38
--- /dev/null
+++ b/source/smbwrapper/smbw_dir.c
@@ -0,0 +1,689 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper directory functions
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "realcalls.h"
+
+extern pstring smbw_cwd;
+extern fstring smbw_prefix;
+
+static struct smbw_dir *smbw_dirs;
+
+extern struct bitmap *smbw_file_bmap;
+
+extern int smbw_busy;
+
+/*****************************************************
+map a fd to a smbw_dir structure
+*******************************************************/
+struct smbw_dir *smbw_dir(int fd)
+{
+ struct smbw_dir *dir;
+
+ for (dir=smbw_dirs;dir;dir=dir->next) {
+ if (dir->fd == fd) return dir;
+ }
+ return NULL;
+}
+
+/*****************************************************
+check if a DIR* is one of ours
+*******************************************************/
+int smbw_dirp(DIR *dirp)
+{
+ struct smbw_dir *d = (struct smbw_dir *)dirp;
+ struct smbw_dir *dir;
+
+ for (dir=smbw_dirs;dir;dir=dir->next) {
+ if (dir == d) return 1;
+ }
+ return 0;
+}
+
+/*****************************************************
+free a smbw_dir structure and all entries
+*******************************************************/
+static void free_dir(struct smbw_dir *dir)
+{
+ if(!dir) return;
+
+ SAFE_FREE(dir->list);
+ SAFE_FREE(dir->path);
+ ZERO_STRUCTP(dir);
+ SAFE_FREE(dir);
+}
+
+static struct smbw_dir *cur_dir;
+
+/*****************************************************
+add a entry to a directory listing
+*******************************************************/
+static void smbw_dir_add(struct file_info *finfo, const char *mask,
+ void *state)
+{
+ struct file_info *cdl;
+
+ DEBUG(5,("%s\n", finfo->name));
+
+ if (cur_dir->malloced == cur_dir->count) {
+ cdl = (struct file_info *)Realloc(cur_dir->list,
+ sizeof(cur_dir->list[0])*
+ (cur_dir->count+100));
+ if (!cdl) {
+ /* oops */
+ return;
+ }
+ cur_dir->list = cdl;
+ cur_dir->malloced += 100;
+ }
+
+ cur_dir->list[cur_dir->count] = *finfo;
+ cur_dir->count++;
+}
+
+/*****************************************************
+add a entry to a directory listing
+*******************************************************/
+static void smbw_share_add(const char *share, uint32 type,
+ const char *comment, void *state)
+{
+ struct file_info finfo;
+
+ if (strcmp(share,"IPC$") == 0) return;
+
+ ZERO_STRUCT(finfo);
+
+ pstrcpy(finfo.name, share);
+ finfo.mode = aRONLY | aDIR;
+
+ smbw_dir_add(&finfo, NULL, NULL);
+}
+
+
+/*****************************************************
+add a server to a directory listing
+*******************************************************/
+static void smbw_server_add(const char *name, uint32 type,
+ const char *comment, void *state)
+{
+ struct file_info finfo;
+
+ ZERO_STRUCT(finfo);
+
+ pstrcpy(finfo.name, name);
+ finfo.mode = aRONLY | aDIR;
+
+ smbw_dir_add(&finfo, NULL, NULL);
+}
+
+
+/*****************************************************
+add a entry to a directory listing
+*******************************************************/
+static void smbw_printjob_add(struct print_job_info *job)
+{
+ struct file_info finfo;
+
+ ZERO_STRUCT(finfo);
+
+ pstrcpy(finfo.name, job->name);
+ finfo.mode = aRONLY | aDIR;
+ finfo.mtime = job->t;
+ finfo.atime = job->t;
+ finfo.ctime = job->t;
+ finfo.uid = nametouid(job->user);
+ finfo.mode = aRONLY;
+ finfo.size = job->size;
+
+ smbw_dir_add(&finfo, NULL, NULL);
+}
+
+
+/*****************************************************
+open a directory on the server
+*******************************************************/
+int smbw_dir_open(const char *fname)
+{
+ fstring server, share;
+ pstring path;
+ struct smbw_server *srv=NULL;
+ struct smbw_dir *dir=NULL;
+ pstring mask;
+ int fd;
+ char *s, *p;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ /* work out what server they are after */
+ s = smbw_parse_path(fname, server, share, path);
+
+ DEBUG(4,("dir_open share=%s\n", share));
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ dir = (struct smbw_dir *)malloc(sizeof(*dir));
+ if (!dir) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(dir);
+
+ cur_dir = dir;
+
+ slprintf(mask, sizeof(mask)-1, "%s\\*", path);
+ all_string_sub(mask,"\\\\","\\",0);
+
+ if ((p=strstr(srv->server_name,"#01"))) {
+ *p = 0;
+ smbw_server_add(".",0,"", NULL);
+ smbw_server_add("..",0,"", NULL);
+ smbw_NetServerEnum(&srv->cli, srv->server_name,
+ SV_TYPE_DOMAIN_ENUM, smbw_server_add, NULL);
+ *p = '#';
+ } else if ((p=strstr(srv->server_name,"#1D"))) {
+ DEBUG(4,("doing NetServerEnum\n"));
+ *p = 0;
+ smbw_server_add(".",0,"", NULL);
+ smbw_server_add("..",0,"", NULL);
+ smbw_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL,
+ smbw_server_add, NULL);
+ *p = '#';
+ } else if (strcmp(srv->cli.dev,"IPC") == 0) {
+ DEBUG(4,("doing NetShareEnum\n"));
+ smbw_share_add(".",0,"", NULL);
+ smbw_share_add("..",0,"", NULL);
+ if (smbw_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+ } else if (strncmp(srv->cli.dev,"LPT",3) == 0) {
+ smbw_share_add(".",0,"", NULL);
+ smbw_share_add("..",0,"", NULL);
+ if (cli_print_queue(&srv->cli, smbw_printjob_add) < 0) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+ } else {
+#if 0
+ if (strcmp(path,"\\") == 0) {
+ smbw_share_add(".",0,"");
+ smbw_share_add("..",0,"");
+ }
+#endif
+ if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR,
+ smbw_dir_add, NULL) < 0) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+ }
+
+ cur_dir = NULL;
+
+ fd = open(SMBW_DUMMY, O_WRONLY);
+ if (fd == -1) {
+ errno = EMFILE;
+ goto failed;
+ }
+
+ if (bitmap_query(smbw_file_bmap, fd)) {
+ DEBUG(0,("ERROR: fd used in smbw_dir_open\n"));
+ errno = EIO;
+ goto failed;
+ }
+
+ DLIST_ADD(smbw_dirs, dir);
+
+ bitmap_set(smbw_file_bmap, fd);
+
+ dir->fd = fd;
+ dir->srv = srv;
+ dir->path = strdup(s);
+
+ DEBUG(4,(" -> %d\n", dir->count));
+
+ return dir->fd;
+
+ failed:
+ free_dir(dir);
+
+ return -1;
+}
+
+/*****************************************************
+a wrapper for fstat() on a directory
+*******************************************************/
+int smbw_dir_fstat(int fd, struct stat *st)
+{
+ struct smbw_dir *dir;
+
+ dir = smbw_dir(fd);
+ if (!dir) {
+ errno = EBADF;
+ return -1;
+ }
+
+ ZERO_STRUCTP(st);
+
+ smbw_setup_stat(st, "", dir->count*DIRP_SIZE, aDIR);
+
+ st->st_dev = dir->srv->dev;
+
+ return 0;
+}
+
+/*****************************************************
+close a directory handle
+*******************************************************/
+int smbw_dir_close(int fd)
+{
+ struct smbw_dir *dir;
+
+ dir = smbw_dir(fd);
+ if (!dir) {
+ errno = EBADF;
+ return -1;
+ }
+
+ bitmap_clear(smbw_file_bmap, dir->fd);
+ close(dir->fd);
+
+ DLIST_REMOVE(smbw_dirs, dir);
+
+ free_dir(dir);
+
+ return 0;
+}
+
+/*****************************************************
+a wrapper for getdents()
+*******************************************************/
+int smbw_getdents(unsigned int fd, struct dirent *dirp, int count)
+{
+ struct smbw_dir *dir;
+ int n=0;
+
+ smbw_busy++;
+
+ dir = smbw_dir(fd);
+ if (!dir) {
+ errno = EBADF;
+ smbw_busy--;
+ return -1;
+ }
+
+ while (count>=DIRP_SIZE && (dir->offset < dir->count)) {
+#if HAVE_DIRENT_D_OFF
+ dirp->d_off = (dir->offset+1)*DIRP_SIZE;
+#endif
+ dirp->d_reclen = DIRP_SIZE;
+ fstrcpy(&dirp->d_name[0], dir->list[dir->offset].name);
+ dirp->d_ino = smbw_inode(dir->list[dir->offset].name);
+ dir->offset++;
+ count -= dirp->d_reclen;
+#if HAVE_DIRENT_D_OFF
+ if (dir->offset == dir->count) {
+ dirp->d_off = -1;
+ }
+#endif
+ dirp = (struct dirent *)(((char *)dirp) + DIRP_SIZE);
+ n++;
+ }
+
+ smbw_busy--;
+ return n*DIRP_SIZE;
+}
+
+
+/*****************************************************
+a wrapper for chdir()
+*******************************************************/
+int smbw_chdir(const char *name)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+ uint16 mode = aDIR;
+ char *cwd;
+ int len;
+
+ smbw_init();
+
+ len = strlen(smbw_prefix);
+
+ if (smbw_busy) return real_chdir(name);
+
+ smbw_busy++;
+
+ if (!name) {
+ errno = EINVAL;
+ goto failed;
+ }
+
+ DEBUG(4,("smbw_chdir(%s)\n", name));
+
+ /* work out what server they are after */
+ cwd = smbw_parse_path(name, server, share, path);
+
+ /* a special case - accept cd to /smb */
+ if (strncmp(cwd, smbw_prefix, len-1) == 0 &&
+ cwd[len-1] == 0) {
+ goto success1;
+ }
+
+ if (strncmp(cwd,smbw_prefix,strlen(smbw_prefix))) {
+ if (real_chdir(cwd) == 0) {
+ goto success2;
+ }
+ goto failed;
+ }
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (strncmp(srv->cli.dev,"IPC",3) &&
+ strncmp(srv->cli.dev,"LPT",3) &&
+ !smbw_getatr(srv, path,
+ &mode, NULL, NULL, NULL, NULL, NULL)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ if (!(mode & aDIR)) {
+ errno = ENOTDIR;
+ goto failed;
+ }
+
+ success1:
+ /* we don't want the old directory to be busy */
+ real_chdir("/");
+
+ success2:
+
+ DEBUG(4,("set SMBW_CWD to %s\n", cwd));
+
+ pstrcpy(smbw_cwd, cwd);
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for lseek() on directories
+*******************************************************/
+off_t smbw_dir_lseek(int fd, off_t offset, int whence)
+{
+ struct smbw_dir *dir;
+ off_t ret;
+
+ dir = smbw_dir(fd);
+ if (!dir) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ dir->offset = offset/DIRP_SIZE;
+ break;
+ case SEEK_CUR:
+ dir->offset += offset/DIRP_SIZE;
+ break;
+ case SEEK_END:
+ dir->offset = (dir->count * DIRP_SIZE) + offset;
+ dir->offset /= DIRP_SIZE;
+ break;
+ }
+
+ ret = dir->offset * DIRP_SIZE;
+
+ DEBUG(4,(" -> %d\n", (int)ret));
+
+ return ret;
+}
+
+
+/*****************************************************
+a wrapper for mkdir()
+*******************************************************/
+int smbw_mkdir(const char *fname, mode_t mode)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (!cli_mkdir(&srv->cli, path)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+/*****************************************************
+a wrapper for rmdir()
+*******************************************************/
+int smbw_rmdir(const char *fname)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+ /* smbw_server sets errno */
+ goto failed;
+ }
+
+ if (!cli_rmdir(&srv->cli, path)) {
+ errno = smbw_errno(&srv->cli);
+ goto failed;
+ }
+
+ smbw_busy--;
+ return 0;
+
+ failed:
+ smbw_busy--;
+ return -1;
+}
+
+
+/*****************************************************
+a wrapper for getcwd()
+*******************************************************/
+char *smbw_getcwd(char *buf, size_t size)
+{
+ smbw_init();
+
+ if (smbw_busy) {
+ return (char *)real_getcwd(buf, size);
+ }
+
+ smbw_busy++;
+
+ if (!buf) {
+ if (size <= 0) size = strlen(smbw_cwd)+1;
+ buf = (char *)malloc(size);
+ if (!buf) {
+ errno = ENOMEM;
+ smbw_busy--;
+ return NULL;
+ }
+ }
+
+ if (strlen(smbw_cwd) > size-1) {
+ errno = ERANGE;
+ smbw_busy--;
+ return NULL;
+ }
+
+ safe_strcpy(buf, smbw_cwd, size);
+
+ smbw_busy--;
+ return buf;
+}
+
+/*****************************************************
+a wrapper for fchdir()
+*******************************************************/
+int smbw_fchdir(unsigned int fd)
+{
+ struct smbw_dir *dir;
+ int ret;
+
+ smbw_busy++;
+
+ dir = smbw_dir(fd);
+ if (dir) {
+ smbw_busy--;
+ return chdir(dir->path);
+ }
+
+ ret = real_fchdir(fd);
+ if (ret == 0) {
+ sys_getwd(smbw_cwd);
+ }
+
+ smbw_busy--;
+ return ret;
+}
+
+/*****************************************************
+open a directory on the server
+*******************************************************/
+DIR *smbw_opendir(const char *fname)
+{
+ int fd;
+
+ smbw_busy++;
+
+ fd = smbw_dir_open(fname);
+
+ if (fd == -1) {
+ smbw_busy--;
+ return NULL;
+ }
+
+ smbw_busy--;
+
+ return (DIR *)smbw_dir(fd);
+}
+
+/*****************************************************
+read one entry from a directory
+*******************************************************/
+struct dirent *smbw_readdir(DIR *dirp)
+{
+ struct smbw_dir *d = (struct smbw_dir *)dirp;
+ static union {
+ char buf[DIRP_SIZE];
+ struct dirent de;
+ } dbuf;
+
+ if (smbw_getdents(d->fd, &dbuf.de, DIRP_SIZE) > 0)
+ return &dbuf.de;
+
+ return NULL;
+}
+
+/*****************************************************
+close a DIR*
+*******************************************************/
+int smbw_closedir(DIR *dirp)
+{
+ struct smbw_dir *d = (struct smbw_dir *)dirp;
+ return smbw_close(d->fd);
+}
+
+/*****************************************************
+seek in a directory
+*******************************************************/
+void smbw_seekdir(DIR *dirp, off_t offset)
+{
+ struct smbw_dir *d = (struct smbw_dir *)dirp;
+ smbw_dir_lseek(d->fd,offset, SEEK_SET);
+}
+
+/*****************************************************
+current loc in a directory
+*******************************************************/
+off_t smbw_telldir(DIR *dirp)
+{
+ struct smbw_dir *d = (struct smbw_dir *)dirp;
+ return smbw_dir_lseek(d->fd,0,SEEK_CUR);
+}
diff --git a/source/smbwrapper/smbw_stat.c b/source/smbwrapper/smbw_stat.c
new file mode 100644
index 00000000000..40fb191e02d
--- /dev/null
+++ b/source/smbwrapper/smbw_stat.c
@@ -0,0 +1,251 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper stat functions
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int smbw_busy;
+
+/*****************************************************
+setup basic info in a stat structure
+*******************************************************/
+void smbw_setup_stat(struct stat *st, char *fname, size_t size, int mode)
+{
+ st->st_mode = 0;
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_mode = SMBW_DIR_MODE;
+ } else {
+ st->st_mode = SMBW_FILE_MODE;
+ }
+
+ if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
+ if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
+ if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
+ if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
+
+ st->st_size = size;
+ st->st_blksize = 512;
+ st->st_blocks = (size+511)/512;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+ if (IS_DOS_DIR(mode)) {
+ st->st_nlink = 2;
+ } else {
+ st->st_nlink = 1;
+ }
+ if (st->st_ino == 0) {
+ st->st_ino = smbw_inode(fname);
+ }
+}
+
+
+/*****************************************************
+try to do a QPATHINFO and if that fails then do a getatr
+this is needed because win95 sometimes refuses the qpathinfo
+*******************************************************/
+BOOL smbw_getatr(struct smbw_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino)
+{
+ DEBUG(4,("sending qpathinfo\n"));
+
+ if (!srv->no_pathinfo2 &&
+ cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
+ size, mode, ino)) return True;
+
+ /* if this is NT then don't bother with the getatr */
+ if (srv->cli.capabilities & CAP_NT_SMBS) return False;
+
+ if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
+ a_time = c_time = m_time;
+ srv->no_pathinfo2 = True;
+ return True;
+ }
+ return False;
+}
+
+
+static struct print_job_info printjob;
+
+/*****************************************************
+gather info from a printjob listing
+*******************************************************/
+static void smbw_printjob_stat(struct print_job_info *job)
+{
+ if (strcmp(job->name, printjob.name) == 0) {
+ printjob = *job;
+ }
+}
+
+/*****************************************************
+stat a printjob
+*******************************************************/
+int smbw_stat_printjob(struct smbw_server *srv,char *path,
+ size_t *size, time_t *m_time)
+{
+ if (path[0] == '\\') path++;
+
+ ZERO_STRUCT(printjob);
+
+ fstrcpy(printjob.name, path);
+ cli_print_queue(&srv->cli, smbw_printjob_stat);
+
+ if (size) {
+ *size = printjob.size;
+ }
+ if (m_time) {
+ *m_time = printjob.t;
+ }
+ return printjob.id;
+}
+
+
+/*****************************************************
+a wrapper for fstat()
+*******************************************************/
+int smbw_fstat(int fd, struct stat *st)
+{
+ struct smbw_file *file;
+ time_t c_time, a_time, m_time;
+ size_t size;
+ uint16 mode;
+ SMB_INO_T ino = 0;
+
+ smbw_busy++;
+
+ ZERO_STRUCTP(st);
+
+ file = smbw_file(fd);
+ if (!file) {
+ int ret = smbw_dir_fstat(fd, st);
+ smbw_busy--;
+ return ret;
+ }
+
+ if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time, NULL,
+ &ino) &&
+ !cli_getattrE(&file->srv->cli, file->f->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time)) {
+ errno = EINVAL;
+ smbw_busy--;
+ return -1;
+ }
+
+ st->st_ino = ino;
+
+ smbw_setup_stat(st, file->f->fname, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = file->srv->dev;
+
+ smbw_busy--;
+ return 0;
+}
+
+
+/*****************************************************
+a wrapper for stat()
+*******************************************************/
+int smbw_stat(const char *fname, struct stat *st)
+{
+ struct smbw_server *srv;
+ fstring server, share;
+ pstring path;
+ time_t m_time=0, a_time=0, c_time=0;
+ size_t size=0;
+ uint16 mode=0;
+ SMB_INO_T ino = 0;
+ int result = 0;
+
+ ZERO_STRUCTP(st);
+
+ if (!fname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ DEBUG(4,("stat(%s)\n", fname));
+
+ smbw_init();
+
+ smbw_busy++;
+
+ /* work out what server they are after */
+ smbw_parse_path(fname, server, share, path);
+
+ /* get a connection to the server */
+ srv = smbw_server(server, share);
+ if (!srv) {
+
+ /* For shares we aren't allowed to connect to, or no master
+ browser found, return an empty directory */
+
+ if ((server[0] && share[0] && !path[0] && errno == EACCES) ||
+ (!path[0] && errno == ENOENT)) {
+ mode = aDIR | aRONLY;
+ smbw_setup_stat(st, path, size, mode);
+ goto done;
+ }
+
+ /* smbw_server sets errno */
+ result = -1;
+ goto done;
+ }
+
+ DEBUG(4,("smbw_stat\n"));
+
+ if (strncmp(srv->cli.dev,"IPC",3) == 0) {
+ mode = aDIR | aRONLY;
+ } else if (strncmp(srv->cli.dev,"LPT",3) == 0) {
+ if (strcmp(path,"\\") == 0) {
+ mode = aDIR | aRONLY;
+ } else {
+ mode = aRONLY;
+ smbw_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+ }
+ } else {
+ if (!smbw_getatr(srv, path,
+ &mode, &size, &c_time, &a_time, &m_time,
+ &ino)) {
+ errno = smbw_errno(&srv->cli);
+ result = -1;
+ goto done;
+ }
+ }
+
+ st->st_ino = ino;
+
+ smbw_setup_stat(st, path, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = srv->dev;
+
+ done:
+ smbw_busy--;
+ return result;
+}
diff --git a/source/smbwrapper/wrapped.c b/source/smbwrapper/wrapped.c
new file mode 100644
index 00000000000..b8787a00c01
--- /dev/null
+++ b/source/smbwrapper/wrapped.c
@@ -0,0 +1,706 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB wrapper functions
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* NOTE: This file WILL produce compiler warnings. They are unavoidable
+
+ Do not try and get rid of them by including other include files or
+ by including includes.h or proto.h or you will break portability.
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <errno.h>
+#include "realcalls.h"
+
+#ifndef NULL
+# define NULL ((void *)0)
+#endif
+
+ int open(char *name, int flags, mode_t mode)
+{
+ if (smbw_path(name)) {
+ return smbw_open(name, flags, mode);
+ }
+
+ return real_open(name, flags, mode);
+}
+
+#ifdef HAVE__OPEN
+ int _open(char *name, int flags, mode_t mode)
+{
+ return open(name, flags, mode);
+}
+#elif HAVE___OPEN
+ int __open(char *name, int flags, mode_t mode)
+{
+ return open(name, flags, mode);
+}
+#endif
+
+
+#ifdef HAVE_OPEN64
+ int open64(char *name, int flags, mode_t mode)
+{
+ if (smbw_path(name)) {
+ return smbw_open(name, flags, mode);
+ }
+
+ return real_open64(name, flags, mode);
+}
+#endif
+
+#ifndef NO_OPEN64_ALIAS
+#ifdef HAVE__OPEN64
+ int _open64(char *name, int flags, mode_t mode)
+{
+ return open64(name, flags, mode);
+}
+#elif HAVE___OPEN64
+ int __open64(char *name, int flags, mode_t mode)
+{
+ return open64(name, flags, mode);
+}
+#endif
+#endif
+
+#ifdef HAVE_PREAD
+ ssize_t pread(int fd, void *buf, size_t size, off_t ofs)
+{
+ if (smbw_fd(fd)) {
+ return smbw_pread(fd, buf, size, ofs);
+ }
+
+ return real_pread(fd, buf, size, ofs);
+}
+#endif
+
+#if defined(HAVE_PREAD64) && defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT)
+ ssize_t pread64(int fd, void *buf, size_t size, off64_t ofs)
+{
+ if (smbw_fd(fd)) {
+ return smbw_pread(fd, buf, size, ofs);
+ }
+
+ return real_pread64(fd, buf, size, ofs);
+}
+#endif
+
+#ifdef HAVE_PWRITE
+ ssize_t pwrite(int fd, void *buf, size_t size, off_t ofs)
+{
+ if (smbw_fd(fd)) {
+ return smbw_pwrite(fd, buf, size, ofs);
+ }
+
+ return real_pwrite(fd, buf, size, ofs);
+}
+#endif
+
+#if defined(HAVE_PWRITE64) && defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT)
+ ssize_t pwrite64(int fd, void *buf, size_t size, off64_t ofs)
+{
+ if (smbw_fd(fd)) {
+ return smbw_pwrite(fd, buf, size, ofs);
+ }
+
+ return real_pwrite64(fd, buf, size, ofs);
+}
+#endif
+
+
+ int chdir(char *name)
+{
+ return smbw_chdir(name);
+}
+
+#ifdef HAVE___CHDIR
+ int __chdir(char *name)
+{
+ return chdir(name);
+}
+#elif HAVE__CHDIR
+ int _chdir(char *name)
+{
+ return chdir(name);
+}
+#endif
+
+
+ int close(int fd)
+{
+ if (smbw_fd(fd)) {
+ return smbw_close(fd);
+ }
+ if (smbw_local_fd(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return real_close(fd);
+}
+
+#ifdef HAVE___CLOSE
+ int __close(int fd)
+{
+ return close(fd);
+}
+#elif HAVE__CLOSE
+ int _close(int fd)
+{
+ return close(fd);
+}
+#endif
+
+
+ int fchdir(int fd)
+{
+ return smbw_fchdir(fd);
+}
+
+#ifdef HAVE___FCHDIR
+ int __fchdir(int fd)
+{
+ return fchdir(fd);
+}
+#elif HAVE__FCHDIR
+ int _fchdir(int fd)
+{
+ return fchdir(fd);
+}
+#endif
+
+
+ int fcntl(int fd, int cmd, long arg)
+{
+ if (smbw_fd(fd)) {
+ return smbw_fcntl(fd, cmd, arg);
+ }
+
+ return real_fcntl(fd, cmd, arg);
+}
+
+
+#ifdef HAVE___FCNTL
+ int __fcntl(int fd, int cmd, long arg)
+{
+ return fcntl(fd, cmd, arg);
+}
+#elif HAVE__FCNTL
+ int _fcntl(int fd, int cmd, long arg)
+{
+ return fcntl(fd, cmd, arg);
+}
+#endif
+
+
+
+#ifdef real_getdents
+ int getdents(int fd, void *dirp, unsigned int count)
+{
+ if (smbw_fd(fd)) {
+ return smbw_getdents(fd, dirp, count);
+ }
+
+ return real_getdents(fd, dirp, count);
+}
+#endif
+
+#ifdef HAVE___GETDENTS
+ int __getdents(int fd, void *dirp, unsigned int count)
+{
+ return getdents(fd, dirp, count);
+}
+#elif HAVE__GETDENTS
+ int _getdents(int fd, void *dirp, unsigned int count)
+{
+ return getdents(fd, dirp, count);
+}
+#endif
+
+
+ off_t lseek(int fd, off_t offset, int whence)
+{
+ if (smbw_fd(fd)) {
+ return smbw_lseek(fd, offset, whence);
+ }
+
+ return real_lseek(fd, offset, whence);
+}
+
+#ifdef HAVE___LSEEK
+ off_t __lseek(int fd, off_t offset, int whence)
+{
+ return lseek(fd, offset, whence);
+}
+#elif HAVE__LSEEK
+ off_t _lseek(int fd, off_t offset, int whence)
+{
+ return lseek(fd, offset, whence);
+}
+#endif
+
+
+ ssize_t read(int fd, void *buf, size_t count)
+{
+ if (smbw_fd(fd)) {
+ return smbw_read(fd, buf, count);
+ }
+
+ return real_read(fd, buf, count);
+}
+
+#ifdef HAVE___READ
+ ssize_t __read(int fd, void *buf, size_t count)
+{
+ return read(fd, buf, count);
+}
+#elif HAVE__READ
+ ssize_t _read(int fd, void *buf, size_t count)
+{
+ return read(fd, buf, count);
+}
+#endif
+
+
+ ssize_t write(int fd, void *buf, size_t count)
+{
+ if (smbw_fd(fd)) {
+ return smbw_write(fd, buf, count);
+ }
+
+ return real_write(fd, buf, count);
+}
+
+#ifdef HAVE___WRITE
+ ssize_t __write(int fd, void *buf, size_t count)
+{
+ return write(fd, buf, count);
+}
+#elif HAVE__WRITE
+ ssize_t _write(int fd, void *buf, size_t count)
+{
+ return write(fd, buf, count);
+}
+#endif
+
+
+
+ int access(char *name, int mode)
+{
+ if (smbw_path(name)) {
+ return smbw_access(name, mode);
+ }
+
+ return real_access(name, mode);
+}
+
+
+
+ int chmod(char *name,mode_t mode)
+{
+ if (smbw_path(name)) {
+ return smbw_chmod(name, mode);
+ }
+
+ return real_chmod(name, mode);
+}
+
+
+
+ int chown(char *name,uid_t owner, gid_t group)
+{
+ if (smbw_path(name)) {
+ return smbw_chown(name, owner, group);
+ }
+
+ return real_chown(name, owner, group);
+}
+
+
+ char *getcwd(char *buf, size_t size)
+{
+ return (char *)smbw_getcwd(buf, size);
+}
+
+
+
+
+ int mkdir(char *name, mode_t mode)
+{
+ if (smbw_path(name)) {
+ return smbw_mkdir(name, mode);
+ }
+
+ return real_mkdir(name, mode);
+}
+
+
+#if HAVE___FXSTAT
+ int __fxstat(int vers, int fd, void *st)
+{
+ double xx[32];
+ int ret;
+
+ if (smbw_fd(fd)) {
+ return smbw_fstat(fd, st);
+ }
+
+ ret = real_fstat(fd, xx);
+ xstat_convert(vers, st, xx);
+ return ret;
+}
+#endif
+
+#if HAVE___XSTAT
+ int __xstat(int vers, char *name, void *st)
+{
+ double xx[32];
+ int ret;
+
+ if (smbw_path(name)) {
+ return smbw_stat(name, st);
+ }
+
+ ret = real_stat(name, xx);
+ xstat_convert(vers, st, xx);
+ return ret;
+}
+#endif
+
+
+#if HAVE___LXSTAT
+ int __lxstat(int vers, char *name, void *st)
+{
+ double xx[32];
+ int ret;
+
+ if (smbw_path(name)) {
+ return smbw_stat(name, st);
+ }
+
+ ret = real_lstat(name, xx);
+ xstat_convert(vers, st, xx);
+ return ret;
+}
+#endif
+
+
+ int stat(char *name, void *st)
+{
+#if HAVE___XSTAT
+ return __xstat(0, name, st);
+#else
+ if (smbw_path(name)) {
+ return smbw_stat(name, st);
+ }
+ return real_stat(name, st);
+#endif
+}
+
+ int lstat(char *name, void *st)
+{
+#if HAVE___LXSTAT
+ return __lxstat(0, name, st);
+#else
+ if (smbw_path(name)) {
+ return smbw_stat(name, st);
+ }
+ return real_lstat(name, st);
+#endif
+}
+
+ int fstat(int fd, void *st)
+{
+#if HAVE___LXSTAT
+ return __fxstat(0, fd, st);
+#else
+ if (smbw_fd(fd)) {
+ return smbw_fstat(fd, st);
+ }
+ return real_fstat(fd, st);
+#endif
+}
+
+
+ int unlink(char *name)
+{
+ if (smbw_path(name)) {
+ return smbw_unlink(name);
+ }
+
+ return real_unlink(name);
+}
+
+
+#ifdef HAVE_UTIME
+ int utime(char *name,void *tvp)
+{
+ if (smbw_path(name)) {
+ return smbw_utime(name, tvp);
+ }
+
+ return real_utime(name, tvp);
+}
+#endif
+
+#ifdef HAVE_UTIMES
+ int utimes(const char *name, const struct timeval *tvp)
+{
+ if (smbw_path(name)) {
+ return smbw_utimes(name, tvp);
+ }
+
+ return real_utimes(name, tvp);
+}
+#endif
+
+ int readlink(char *path, char *buf, size_t bufsize)
+{
+ if (smbw_path(path)) {
+ return smbw_readlink(path, buf, bufsize);
+ }
+
+ return real_readlink(path, buf, bufsize);
+}
+
+
+ int rename(char *oldname,char *newname)
+{
+ int p1, p2;
+ p1 = smbw_path(oldname);
+ p2 = smbw_path(newname);
+ if (p1 ^ p2) {
+ /* can't cross filesystem boundaries */
+ errno = EXDEV;
+ return -1;
+ }
+ if (p1 && p2) {
+ return smbw_rename(oldname, newname);
+ }
+
+ return real_rename(oldname, newname);
+}
+
+ int rmdir(char *name)
+{
+ if (smbw_path(name)) {
+ return smbw_rmdir(name);
+ }
+
+ return real_rmdir(name);
+}
+
+
+ int symlink(char *topath,char *frompath)
+{
+ int p1, p2;
+ p1 = smbw_path(topath);
+ p2 = smbw_path(frompath);
+ if (p1 || p2) {
+ /* can't handle symlinks */
+ errno = EPERM;
+ return -1;
+ }
+
+ return real_symlink(topath, frompath);
+}
+
+ int dup(int fd)
+{
+ if (smbw_fd(fd)) {
+ return smbw_dup(fd);
+ }
+
+ return real_dup(fd);
+}
+
+ int dup2(int oldfd, int newfd)
+{
+ if (smbw_fd(newfd)) {
+ close(newfd);
+ }
+
+ if (smbw_fd(oldfd)) {
+ return smbw_dup2(oldfd, newfd);
+ }
+
+ return real_dup2(oldfd, newfd);
+}
+
+#ifdef real_opendir
+ void *opendir(char *name)
+{
+ if (smbw_path(name)) {
+ return (void *)smbw_opendir(name);
+ }
+
+ return (void *)real_opendir(name);
+}
+#endif
+
+#ifdef real_readdir
+ void *readdir(void *dir)
+{
+ if (smbw_dirp(dir)) {
+ return (void *)smbw_readdir(dir);
+ }
+
+ return (void *)real_readdir(dir);
+}
+#endif
+
+#ifdef real_closedir
+ int closedir(void *dir)
+{
+ if (smbw_dirp(dir)) {
+ return smbw_closedir(dir);
+ }
+
+ return real_closedir(dir);
+}
+#endif
+
+#ifdef real_telldir
+ off_t telldir(void *dir)
+{
+ if (smbw_dirp(dir)) {
+ return smbw_telldir(dir);
+ }
+
+ return real_telldir(dir);
+}
+#endif
+
+#ifdef real_seekdir
+ int seekdir(void *dir, off_t offset)
+{
+ if (smbw_dirp(dir)) {
+ smbw_seekdir(dir, offset);
+ return 0;
+ }
+
+ real_seekdir(dir, offset);
+ return 0;
+}
+#endif
+
+
+#ifndef NO_ACL_WRAPPER
+ int acl(char *pathp, int cmd, int nentries, void *aclbufp)
+{
+ if (smbw_path(pathp)) {
+ return smbw_acl(pathp, cmd, nentries, aclbufp);
+ }
+
+ return real_acl(pathp, cmd, nentries, aclbufp);
+}
+#endif
+
+#ifndef NO_FACL_WRAPPER
+ int facl(int fd, int cmd, int nentries, void *aclbufp)
+{
+ if (smbw_fd(fd)) {
+ return smbw_facl(fd, cmd, nentries, aclbufp);
+ }
+
+ return real_facl(fd, cmd, nentries, aclbufp);
+}
+#endif
+
+ int creat(char *path, mode_t mode)
+{
+ extern int creat_bits;
+ return open(path, creat_bits, mode);
+}
+
+#ifdef HAVE_CREAT64
+ int creat64(char *path, mode_t mode)
+{
+ extern int creat_bits;
+ return open64(path, creat_bits, mode);
+}
+#endif
+
+#ifdef HAVE_STAT64
+ int stat64(char *name, void *st64)
+{
+ if (smbw_path(name)) {
+ double xx[32];
+ int ret = stat(name, xx);
+ stat64_convert(xx, st64);
+ return ret;
+ }
+ return real_stat64(name, st64);
+}
+
+ int fstat64(int fd, void *st64)
+{
+ if (smbw_fd(fd)) {
+ double xx[32];
+ int ret = fstat(fd, xx);
+ stat64_convert(xx, st64);
+ return ret;
+ }
+ return real_fstat64(fd, st64);
+}
+
+ int lstat64(char *name, void *st64)
+{
+ if (smbw_path(name)) {
+ double xx[32];
+ int ret = lstat(name, xx);
+ stat64_convert(xx, st64);
+ return ret;
+ }
+ return real_lstat64(name, st64);
+}
+#endif
+
+#ifdef HAVE_LLSEEK
+ offset_t llseek(int fd, offset_t ofs, int whence)
+{
+ if (smbw_fd(fd)) {
+ return lseek(fd, ofs, whence);
+ }
+ return real_llseek(fd, ofs, whence);
+}
+#endif
+
+#ifdef HAVE_READDIR64
+ void *readdir64(void *dir)
+{
+ if (smbw_dirp(dir)) {
+ static double xx[70];
+ void *d;
+ d = (void *)readdir(dir);
+ if (!d) return NULL;
+ dirent64_convert(d, xx);
+ return xx;
+ }
+ return (void *)real_readdir64(dir);
+}
+#endif
+
+ int fork(void)
+{
+ return smbw_fork();
+}
+
diff --git a/source/tdb/.cvsignore b/source/tdb/.cvsignore
new file mode 100644
index 00000000000..15ff2846c7a
--- /dev/null
+++ b/source/tdb/.cvsignore
@@ -0,0 +1,10 @@
+*.po
+*.po32
+tdbdump
+tdbtest
+tdbtool
+tdbtorture
+test.db
+test.gdbm
+test.tdb
+torture.tdb
diff --git a/source/tdb/Makefile b/source/tdb/Makefile
new file mode 100644
index 00000000000..b29bedf92c7
--- /dev/null
+++ b/source/tdb/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for tdb directory
+#
+
+CFLAGS = -DSTANDALONE -DTDB_DEBUG -O2 -g -DHAVE_MMAP=1
+CC = gcc
+
+PROGS = tdbtest tdbtool tdbtorture
+TDB_OBJ = tdb.o spinlock.o
+
+default: $(PROGS)
+
+tdbtest: tdbtest.o $(TDB_OBJ)
+ $(CC) $(CFLAGS) -o tdbtest tdbtest.o $(TDB_OBJ) -lgdbm
+
+tdbtool: tdbtool.o $(TDB_OBJ)
+ $(CC) $(CFLAGS) -o tdbtool tdbtool.o $(TDB_OBJ)
+
+tdbtorture: tdbtorture.o $(TDB_OBJ)
+ $(CC) $(CFLAGS) -o tdbtorture tdbtorture.o $(TDB_OBJ)
+
+tdbdump: tdbdump.o $(TDB_OBJ)
+ $(CC) $(CFLAGS) -o tdbdump tdbdump.o $(TDB_OBJ)
+
+clean:
+ rm -f $(PROGS) *.o *~ *% core test.db test.tdb test.gdbm
diff --git a/source/tdb/README b/source/tdb/README
new file mode 100644
index 00000000000..fac3eacb4db
--- /dev/null
+++ b/source/tdb/README
@@ -0,0 +1,167 @@
+tdb - a trivial database system
+tridge@linuxcare.com December 1999
+==================================
+
+This is a simple database API. It was inspired by the realisation that
+in Samba we have several ad-hoc bits of code that essentially
+implement small databases for sharing structures between parts of
+Samba. As I was about to add another I realised that a generic
+database module was called for to replace all the ad-hoc bits.
+
+I based the interface on gdbm. I couldn't use gdbm as we need to be
+able to have multiple writers to the databases at one time.
+
+Compilation
+-----------
+
+add HAVE_MMAP=1 to use mmap instead of read/write
+add TDB_DEBUG=1 for verbose debug info
+add NOLOCK=1 to disable locking code
+
+Testing
+-------
+
+Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
+identical operations via tdb and gdbm then make sure the result is the
+same
+
+Also included is tdbtool, which allows simple database manipulation
+on the commandline.
+
+tdbtest and tdbtool are not built as part of Samba, but are included
+for completeness.
+
+Interface
+---------
+
+The interface is very similar to gdbm except for the following:
+
+- different open interface. The tdb_open call is more similar to a
+ traditional open()
+- no tdbm_reorganise() function
+- no tdbm_sync() function. No operations are cached in the library anyway
+- added a tdb_traverse() function for traversing the whole database
+
+A general rule for using tdb is that the caller frees any returned
+TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
+return value called p. This is the same as gdbm.
+
+here is a full list of tdb functions with brief descriptions.
+
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+
+ open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the database
+ file. A flags value of O_WRONLY is invalid
+
+ The hash size is advisory, use zero for a default value.
+
+ return is NULL on error
+
+ possible tdb_flags are:
+ TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
+ TDB_INTERNAL - don't use a file, instaed store the data in
+ memory. The filename is ignored in this case.
+ TDB_NOLOCK - don't do any locking
+ TDB_NOMMAP - don't use mmap
+
+----------------------------------------------------------------------
+char *tdb_error(TDB_CONTEXT *tdb);
+
+ return a error string for the last tdb error
+
+----------------------------------------------------------------------
+int tdb_close(TDB_CONTEXT *tdb);
+
+ close a database
+
+----------------------------------------------------------------------
+int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf);
+
+ update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1
+
+----------------------------------------------------------------------
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ fetch an entry in the database given a key
+ if the return value has a null dptr then a error occurred
+
+ caller must free the resulting data
+
+----------------------------------------------------------------------
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+
+----------------------------------------------------------------------
+int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+ TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+ traverse the entire database - calling fn(tdb, key, data, state) on each
+ element.
+
+ return -1 on error or the record count traversed
+
+ if fn is NULL then it is not called
+
+ a non-zero return value from fn() indicates that the traversal should stop
+
+----------------------------------------------------------------------
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+
+ find the first entry in the database and return its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ find the next entry in the database, returning its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ delete an entry in the database given a key
+
+----------------------------------------------------------------------
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+ store an element in the database, replacing any existing element
+ with the same key
+
+ If flag==TDB_INSERT then don't overwrite an existing entry
+ If flag==TDB_MODIFY then don't create a new entry
+
+ return 0 on success, -1 on failure
+
+----------------------------------------------------------------------
+int tdb_writelock(TDB_CONTEXT *tdb);
+
+ lock the database. If we already have it locked then don't do anything
+
+----------------------------------------------------------------------
+int tdb_writeunlock(TDB_CONTEXT *tdb);
+ unlock the database
+
+----------------------------------------------------------------------
+int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ lock one hash chain. This is meant to be used to reduce locking
+ contention - it cannot guarantee how many records will be locked
+
+----------------------------------------------------------------------
+int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ unlock one hash chain
diff --git a/source/tdb/spinlock.c b/source/tdb/spinlock.c
new file mode 100644
index 00000000000..0b2994f8f58
--- /dev/null
+++ b/source/tdb/spinlock.c
@@ -0,0 +1,430 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba database functions
+ Copyright (C) Anton Blanchard 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if STANDALONE
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include "tdb.h"
+#include "spinlock.h"
+
+#define DEBUG
+#else
+#include "includes.h"
+#endif
+
+#ifdef USE_SPINLOCKS
+
+/*
+ * ARCH SPECIFIC
+ */
+
+#if defined(SPARC_SPINLOCKS)
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+ unsigned int result;
+
+ asm volatile("ldstub [%1], %0"
+ : "=r" (result)
+ : "r" (lock)
+ : "memory");
+
+ return (result == 0) ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+ asm volatile("":::"memory");
+ *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+ *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+ return (*lock != 0);
+}
+
+#elif defined(POWERPC_SPINLOCKS)
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+ unsigned int result;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%1\n\
+ cmpwi 0,%0,0\n\
+ li %0,0\n\
+ bne- 2f\n\
+ li %0,1\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b\n\
+ isync\n\
+2:" : "=&r"(result)
+ : "r"(lock)
+ : "cr0", "memory");
+
+ return (result == 1) ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+ asm volatile("eieio":::"memory");
+ *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+ *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+ return (*lock != 0);
+}
+
+#elif defined(INTEL_SPINLOCKS)
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+ int oldval;
+
+ asm volatile("xchgl %0,%1"
+ : "=r" (oldval), "=m" (*lock)
+ : "0" (0)
+ : "memory");
+
+ return oldval > 0 ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+ asm volatile("":::"memory");
+ *lock = 1;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+ *lock = 1;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+ return (*lock != 1);
+}
+
+#elif defined(MIPS_SPINLOCKS)
+
+static inline unsigned int load_linked(unsigned long addr)
+{
+ unsigned int res;
+
+ __asm__ __volatile__("ll\t%0,(%1)"
+ : "=r" (res)
+ : "r" (addr));
+
+ return res;
+}
+
+static inline unsigned int store_conditional(unsigned long addr, unsigned int value)
+{
+ unsigned int res;
+
+ __asm__ __volatile__("sc\t%0,(%2)"
+ : "=r" (res)
+ : "0" (value), "r" (addr));
+ return res;
+}
+
+static inline int __spin_trylock(spinlock_t *lock)
+{
+ unsigned int mw;
+
+ do {
+ mw = load_linked(lock);
+ if (mw)
+ return EBUSY;
+ } while (!store_conditional(lock, 1));
+
+ asm volatile("":::"memory");
+
+ return 0;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+ asm volatile("":::"memory");
+ *lock = 0;
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+ *lock = 0;
+}
+
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+ return (*lock != 0);
+}
+
+#else
+#error Need to implement spinlock code in spinlock.c
+#endif
+
+/*
+ * OS SPECIFIC
+ */
+
+static void yield_cpu(void)
+{
+ struct timespec tm;
+
+#ifdef USE_SCHED_YIELD
+ sched_yield();
+#else
+ /* Linux will busy loop for delays < 2ms on real time tasks */
+ tm.tv_sec = 0;
+ tm.tv_nsec = 2000000L + 1;
+ nanosleep(&tm, NULL);
+#endif
+}
+
+static int this_is_smp(void)
+{
+ return 0;
+}
+
+/*
+ * GENERIC
+ */
+
+static int smp_machine = 0;
+
+static inline void __spin_lock(spinlock_t *lock)
+{
+ int ntries = 0;
+
+ while(__spin_trylock(lock)) {
+ while(__spin_is_locked(lock)) {
+ if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+ continue;
+ yield_cpu();
+ }
+ }
+}
+
+static void __read_lock(tdb_rwlock_t *rwlock)
+{
+ int ntries = 0;
+
+ while(1) {
+ __spin_lock(&rwlock->lock);
+
+ if (!(rwlock->count & RWLOCK_BIAS)) {
+ rwlock->count++;
+ __spin_unlock(&rwlock->lock);
+ return;
+ }
+
+ __spin_unlock(&rwlock->lock);
+
+ while(rwlock->count & RWLOCK_BIAS) {
+ if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+ continue;
+ yield_cpu();
+ }
+ }
+}
+
+static void __write_lock(tdb_rwlock_t *rwlock)
+{
+ int ntries = 0;
+
+ while(1) {
+ __spin_lock(&rwlock->lock);
+
+ if (rwlock->count == 0) {
+ rwlock->count |= RWLOCK_BIAS;
+ __spin_unlock(&rwlock->lock);
+ return;
+ }
+
+ __spin_unlock(&rwlock->lock);
+
+ while(rwlock->count != 0) {
+ if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
+ continue;
+ yield_cpu();
+ }
+ }
+}
+
+static void __write_unlock(tdb_rwlock_t *rwlock)
+{
+ __spin_lock(&rwlock->lock);
+
+#ifdef DEBUG
+ if (!(rwlock->count & RWLOCK_BIAS))
+ fprintf(stderr, "bug: write_unlock\n");
+#endif
+
+ rwlock->count &= ~RWLOCK_BIAS;
+ __spin_unlock(&rwlock->lock);
+}
+
+static void __read_unlock(tdb_rwlock_t *rwlock)
+{
+ __spin_lock(&rwlock->lock);
+
+#ifdef DEBUG
+ if (!rwlock->count)
+ fprintf(stderr, "bug: read_unlock\n");
+
+ if (rwlock->count & RWLOCK_BIAS)
+ fprintf(stderr, "bug: read_unlock\n");
+#endif
+
+ rwlock->count--;
+ __spin_unlock(&rwlock->lock);
+}
+
+/* TDB SPECIFIC */
+
+/* lock a list in the database. list -1 is the alloc list */
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type)
+{
+ tdb_rwlock_t *rwlocks;
+
+ if (!tdb->map_ptr) return -1;
+ rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+
+ switch(rw_type) {
+ case F_RDLCK:
+ __read_lock(&rwlocks[list+1]);
+ break;
+
+ case F_WRLCK:
+ __write_lock(&rwlocks[list+1]);
+ break;
+
+ default:
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+ return 0;
+}
+
+/* unlock the database. */
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type)
+{
+ tdb_rwlock_t *rwlocks;
+
+ if (!tdb->map_ptr) return -1;
+ rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+
+ switch(rw_type) {
+ case F_RDLCK:
+ __read_unlock(&rwlocks[list+1]);
+ break;
+
+ case F_WRLCK:
+ __write_unlock(&rwlocks[list+1]);
+ break;
+
+ default:
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+
+ return 0;
+}
+
+int tdb_create_rwlocks(int fd, unsigned int hash_size)
+{
+ unsigned size, i;
+ tdb_rwlock_t *rwlocks;
+
+ size = (hash_size + 1) * sizeof(tdb_rwlock_t);
+ rwlocks = malloc(size);
+ if (!rwlocks)
+ return -1;
+
+ for(i = 0; i < hash_size+1; i++) {
+ __spin_lock_init(&rwlocks[i].lock);
+ rwlocks[i].count = 0;
+ }
+
+ /* Write it out (appending to end) */
+ if (write(fd, rwlocks, size) != size) {
+ free(rwlocks);
+ return -1;
+ }
+ smp_machine = this_is_smp();
+ free(rwlocks);
+ return 0;
+}
+
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
+{
+ tdb_rwlock_t *rwlocks;
+ unsigned i;
+
+ if (tdb->header.rwlocks == 0) return 0;
+ if (!tdb->map_ptr) return -1;
+
+ /* We're mmapped here */
+ rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
+ for(i = 0; i < tdb->header.hash_size+1; i++) {
+ __spin_lock_init(&rwlocks[i].lock);
+ rwlocks[i].count = 0;
+ }
+ return 0;
+}
+#else
+int tdb_create_rwlocks(int fd, unsigned int hash_size) { return 0; }
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
+
+/* Non-spinlock version: remove spinlock pointer */
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
+{
+ tdb_off off = (tdb_off)((char *)&tdb->header.rwlocks
+ - (char *)&tdb->header);
+
+ tdb->header.rwlocks = 0;
+ if (lseek(tdb->fd, off, SEEK_SET) != off
+ || write(tdb->fd, (void *)&tdb->header.rwlocks,
+ sizeof(tdb->header.rwlocks))
+ != sizeof(tdb->header.rwlocks))
+ return -1;
+ return 0;
+}
+#endif
diff --git a/source/tdb/spinlock.h b/source/tdb/spinlock.h
new file mode 100644
index 00000000000..d6a2ac6eb88
--- /dev/null
+++ b/source/tdb/spinlock.h
@@ -0,0 +1,55 @@
+#ifndef __SPINLOCK_H__
+#define __SPINLOCK_H__
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tdb.h"
+
+#ifdef USE_SPINLOCKS
+
+#define RWLOCK_BIAS 0x1000UL
+
+/* OS SPECIFIC */
+#define MAX_BUSY_LOOPS 1000
+#undef USE_SCHED_YIELD
+
+/* ARCH SPECIFIC */
+/* We should make sure these are padded to a cache line */
+#if defined(SPARC_SPINLOCKS)
+typedef volatile char spinlock_t;
+#elif defined(POWERPC_SPINLOCKS)
+typedef volatile unsigned long spinlock_t;
+#elif defined(INTEL_SPINLOCKS)
+typedef volatile int spinlock_t;
+#elif defined(MIPS_SPINLOCKS)
+typedef volatile unsigned long spinlock_t;
+#else
+#error Need to implement spinlock code in spinlock.h
+#endif
+
+typedef struct {
+ spinlock_t lock;
+ volatile int count;
+} tdb_rwlock_t;
+
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_create_rwlocks(int fd, unsigned int hash_size);
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
+
+#else /* !USE_SPINLOCKS */
+#if 0
+#define tdb_create_rwlocks(fd, hash_size) 0
+#define tdb_spinlock(tdb, list, rw_type) (-1)
+#define tdb_spinunlock(tdb, list, rw_type) (-1)
+#else
+int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
+int tdb_create_rwlocks(int fd, unsigned int hash_size);
+#endif
+int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
+#endif
+
+#endif
diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c
new file mode 100644
index 00000000000..28425c29892
--- /dev/null
+++ b/source/tdb/tdb.c
@@ -0,0 +1,1742 @@
+ /*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba database functions
+ Copyright (C) Andrew Tridgell 1999-2000
+ Copyright (C) Luke Kenneth Casson Leighton 2000
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifdef STANDALONE
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "tdb.h"
+#include "spinlock.h"
+#else
+#include "includes.h"
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_ALIGNMENT 4
+#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGNMENT)
+#define DEFAULT_HASH_SIZE 131
+#define TDB_PAGE_SIZE 0x2000
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off))
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) (tdb->log_fn?((tdb->log_fn x),0) : 0)
+
+/* lock offsets */
+#define GLOBAL_LOCK 0
+#define ACTIVE_LOCK 4
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+TDB_DATA tdb_null;
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static TDB_CONTEXT *tdbs = NULL;
+
+static void tdb_munmap(TDB_CONTEXT *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return;
+
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr)
+ munmap(tdb->map_ptr, tdb->map_size);
+#endif
+ tdb->map_ptr = NULL;
+}
+
+static void tdb_mmap(TDB_CONTEXT *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return;
+
+#ifdef HAVE_MMAP
+ if (!(tdb->flags & TDB_NOMMAP)) {
+ tdb->map_ptr = mmap(NULL, tdb->map_size,
+ PROT_READ|(tdb->read_only? 0:PROT_WRITE),
+ MAP_SHARED|MAP_FILE, tdb->fd, 0);
+
+ /*
+ * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+ */
+
+ if (tdb->map_ptr == MAP_FAILED) {
+ tdb->map_ptr = NULL;
+ TDB_LOG((tdb, 2, "tdb_mmap failed for size %d (%s)\n",
+ tdb->map_size, strerror(errno)));
+ }
+ } else {
+ tdb->map_ptr = NULL;
+ }
+#else
+ tdb->map_ptr = NULL;
+#endif
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+static void *convert(void *buf, u32 size)
+{
+ u32 i, *p = buf;
+ for (i = 0; i < size / 4; i++)
+ p[i] = TDB_BYTEREV(p[i]);
+ return buf;
+}
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? convert(&x, sizeof(x)) : &x)
+
+/* the body of the database is made of one list_struct for the free space
+ plus a separate data list for each hash value */
+struct list_struct {
+ tdb_off next; /* offset of the next record in the list */
+ tdb_len rec_len; /* total byte length of record */
+ tdb_len key_len; /* byte length of key */
+ tdb_len data_len; /* byte length of data */
+ u32 full_hash; /* the full 32 bit hash of the key */
+ u32 magic; /* try to catch errors */
+ /* the following union is implied:
+ union {
+ char record[rec_len];
+ struct {
+ char key[key_len];
+ char data[data_len];
+ }
+ u32 totalsize; (tailer)
+ }
+ */
+};
+
+/* a byte range locking function - return 0 on success
+ this functions locks/unlocks 1 byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open(). */
+static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
+ int rw_type, int lck_type, int probe)
+{
+ struct flock fl;
+
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+ if (tdb->read_only) {
+ errno = EACCES;
+ return -1;
+ }
+
+ fl.l_type = rw_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = offset;
+ fl.l_len = 1;
+ fl.l_pid = 0;
+
+ if (fcntl(tdb->fd,lck_type,&fl) == -1) {
+ if (!probe) {
+ TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n",
+ tdb->fd, offset, rw_type, lck_type));
+ }
+ /* errno set by fcntl */
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+ return 0;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, 0,"tdb_lock: invalid list %d for ltype=%d\n",
+ list, ltype));
+ return -1;
+ }
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ /* Since fcntl locks don't nest, we do a lock for the first one,
+ and simply bump the count for future ones */
+ if (tdb->locked[list+1].count == 0) {
+ if (!tdb->read_only && tdb->header.rwlocks) {
+ if (tdb_spinlock(tdb, list, ltype)) {
+ TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list ltype=%d\n",
+ list, ltype));
+ return -1;
+ }
+ } else if (tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0)) {
+ TDB_LOG((tdb, 0,"tdb_lock failed on list %d ltype=%d (%s)\n",
+ list, ltype, strerror(errno)));
+ return -1;
+ }
+ tdb->locked[list+1].ltype = ltype;
+ }
+ tdb->locked[list+1].count++;
+ return 0;
+}
+
+/* unlock the database: returns void because it's too late for errors. */
+static void tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+ if (tdb->flags & TDB_NOLOCK)
+ return;
+
+ /* Sanity checks */
+ if (list < -1 || list >= (int)tdb->header.hash_size)
+ return;
+ if (tdb->locked[list+1].count==0)
+ return;
+
+ if (tdb->locked[list+1].count == 1) {
+ /* Down to last nested lock: unlock underneath */
+ if (!tdb->read_only && tdb->header.rwlocks)
+ tdb_spinunlock(tdb, list, ltype);
+ else
+ tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+ }
+ tdb->locked[list+1].count--;
+}
+
+/* This is based on the hash agorithm from gdbm */
+static u32 tdb_hash(TDB_DATA *key)
+{
+ u32 value; /* Used to compute the hash value. */
+ u32 i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+ value = (value + (key->dptr[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/* check for an out of bounds access - if it is out of bounds then
+ see if the database has been expanded by someone else and expand
+ if necessary
+ note that "len" is the minimum length needed for the db
+*/
+static int tdb_oob(TDB_CONTEXT *tdb, tdb_off len, int probe)
+{
+ struct stat st;
+ if (len <= tdb->map_size)
+ return 0;
+ if (tdb->flags & TDB_INTERNAL) {
+ if (!probe) {
+ TDB_LOG((tdb, 0,"tdb_oob len %d beyond internal malloc size %d\n",
+ (int)len, (int)tdb->map_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ if (fstat(tdb->fd, &st) == -1)
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+
+ if (st.st_size < (size_t)len) {
+ if (!probe) {
+ TDB_LOG((tdb, 0,"tdb_oob len %d beyond eof at %d\n",
+ (int)len, (int)st.st_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ /* Unmap, update size, remap */
+ tdb_munmap(tdb);
+ tdb->map_size = st.st_size;
+ tdb_mmap(tdb);
+ return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(TDB_CONTEXT *tdb, tdb_off off, void *buf, tdb_len len)
+{
+ if (tdb_oob(tdb, off + len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr)
+ memcpy(off + (char *)tdb->map_ptr, buf, len);
+#ifdef HAVE_PWRITE
+ else if (pwrite(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+ else if (lseek(tdb->fd, off, SEEK_SET) != off
+ || write(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+ TDB_LOG((tdb, 0,"tdb_write failed at %d len=%d (%s)\n",
+ off, len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ return 0;
+}
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(TDB_CONTEXT *tdb,tdb_off off,void *buf,tdb_len len,int cv)
+{
+ if (tdb_oob(tdb, off + len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr)
+ memcpy(buf, off + (char *)tdb->map_ptr, len);
+#ifdef HAVE_PREAD
+ else if (pread(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+ else if (lseek(tdb->fd, off, SEEK_SET) != off
+ || read(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+ TDB_LOG((tdb, 0,"tdb_read failed at %d len=%d (%s)\n",
+ off, len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ if (cv)
+ convert(buf, len);
+ return 0;
+}
+
+/* read a lump of data, allocating the space for it */
+static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
+{
+ char *buf;
+
+ if (!(buf = malloc(len))) {
+ TDB_LOG((tdb, 0,"tdb_alloc_read malloc failed len=%d (%s)\n",
+ len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_OOM, buf);
+ }
+ if (tdb_read(tdb, offset, buf, len, 0) == -1) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/* read/write a tdb_off */
+static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ return tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ tdb_off off = *d;
+ return tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+/* read/write a record */
+static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ if (tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+ if (TDB_BAD_MAGIC(rec)) {
+ TDB_LOG((tdb, 0,"rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ return tdb_oob(tdb, rec->next+sizeof(*rec), 0);
+}
+static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ struct list_struct r = *rec;
+ return tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+/* read a freelist record and check for simple errors */
+static int rec_free_read(TDB_CONTEXT *tdb, tdb_off off, struct list_struct *rec)
+{
+ if (tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+ if (rec->magic != TDB_FREE_MAGIC) {
+ TDB_LOG((tdb, 0,"rec_free_read bad magic 0x%x at offset=%d\n",
+ rec->magic, off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ if (tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
+ return -1;
+ return 0;
+}
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(TDB_CONTEXT *tdb, tdb_off offset,
+ const struct list_struct *rec)
+{
+ tdb_off totalsize;
+
+ /* Offset of tailer from record header */
+ totalsize = sizeof(*rec) + rec->rec_len;
+ return ofs_write(tdb, offset + totalsize - sizeof(tdb_off),
+ &totalsize);
+}
+
+static tdb_off tdb_dump_record(TDB_CONTEXT *tdb, tdb_off offset)
+{
+ struct list_struct rec;
+ tdb_off tailer_ofs, tailer;
+
+ if (tdb_read(tdb, offset, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+ printf("ERROR: failed to read record at %u\n", offset);
+ return 0;
+ }
+
+ printf(" rec: offset=%u next=%d rec_len=%d key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+ offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, rec.full_hash, rec.magic);
+
+ tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off);
+ if (ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+ printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+ return rec.next;
+ }
+
+ if (tailer != rec.rec_len + sizeof(rec)) {
+ printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n", tailer, rec.rec_len + sizeof(rec));
+ }
+ return rec.next;
+}
+
+static void tdb_dump_chain(TDB_CONTEXT *tdb, int i)
+{
+ tdb_off rec_ptr, top;
+
+ top = TDB_HASH_TOP(i);
+
+ tdb_lock(tdb, i, F_WRLCK);
+
+ if (ofs_read(tdb, top, &rec_ptr) == -1) {
+ tdb_unlock(tdb, i, F_WRLCK);
+ return;
+ }
+
+ if (rec_ptr)
+ printf("hash=%d\n", i);
+
+ while (rec_ptr) {
+ rec_ptr = tdb_dump_record(tdb, rec_ptr);
+ }
+ tdb_unlock(tdb, i, F_WRLCK);
+}
+
+void tdb_dump_all(TDB_CONTEXT *tdb)
+{
+ int i;
+ for (i=0;i<tdb->header.hash_size;i++) {
+ tdb_dump_chain(tdb, i);
+ }
+ printf("freelist:\n");
+ tdb_dump_chain(tdb, -1);
+}
+
+void tdb_printfreelist(TDB_CONTEXT *tdb)
+{
+ long total_free = 0;
+ tdb_off offset, rec_ptr, last_ptr;
+ struct list_struct rec;
+
+ tdb_lock(tdb, -1, F_WRLCK);
+
+ last_ptr = 0;
+ offset = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ return;
+ }
+
+ printf("freelist top=[0x%08x]\n", rec_ptr );
+ while (rec_ptr) {
+ if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+ return;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) {
+ printf("bad magic 0x%08x in free list\n", rec.magic);
+ return;
+ }
+
+ printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)]\n", rec.next, rec.rec_len, rec.rec_len );
+ total_free += rec.rec_len;
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ }
+ printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
+ (int)total_free);
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+}
+
+/* Remove an element from the freelist. Must have alloc lock. */
+static int remove_from_freelist(TDB_CONTEXT *tdb, tdb_off off, tdb_off next)
+{
+ tdb_off last_ptr, i;
+
+ /* read in the freelist top */
+ last_ptr = FREELIST_TOP;
+ while (ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
+ if (i == off) {
+ /* We've found it! */
+ return ofs_write(tdb, last_ptr, &next);
+ }
+ /* Follow chain (next offset is at start of record) */
+ last_ptr = i;
+ }
+ TDB_LOG((tdb, 0,"remove_from_freelist: not on list at off=%d\n", off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+}
+
+/* Add an element into the freelist. Merge adjacent records if
+ neccessary. */
+static int tdb_free(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ tdb_off right, left;
+
+ /* Allocation and tailer lock */
+ if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+ return -1;
+
+ /* set an initial tailer, so if we fail we don't leave a bogus record */
+ update_tailer(tdb, offset, rec);
+
+ /* Look right first (I'm an Australian, dammit) */
+ right = offset + sizeof(*rec) + rec->rec_len;
+ if (right + sizeof(*rec) <= tdb->map_size) {
+ struct list_struct r;
+
+ if (tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: right read failed at %u\n", right));
+ goto left;
+ }
+
+ /* If it's free, expand to include it. */
+ if (r.magic == TDB_FREE_MAGIC) {
+ if (remove_from_freelist(tdb, right, r.next) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: right free failed at %u\n", right));
+ goto left;
+ }
+ rec->rec_len += sizeof(r) + r.rec_len;
+ }
+ }
+
+left:
+ /* Look left */
+ left = offset - sizeof(tdb_off);
+ if (left > TDB_HASH_TOP(tdb->header.hash_size-1)) {
+ struct list_struct l;
+ tdb_off leftsize;
+
+ /* Read in tailer and jump back to header */
+ if (ofs_read(tdb, left, &leftsize) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left offset read failed at %u\n", left));
+ goto update;
+ }
+ left = offset - leftsize;
+
+ /* Now read in record */
+ if (tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+ goto update;
+ }
+
+ /* If it's free, expand to include it. */
+ if (l.magic == TDB_FREE_MAGIC) {
+ if (remove_from_freelist(tdb, left, l.next) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left free failed at %u\n", left));
+ goto update;
+ } else {
+ offset = left;
+ rec->rec_len += leftsize;
+ }
+ }
+ }
+
+update:
+ if (update_tailer(tdb, offset, rec) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: update_tailer failed at %u\n", offset));
+ goto fail;
+ }
+
+ /* Now, prepend to free list */
+ rec->magic = TDB_FREE_MAGIC;
+
+ if (ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+ rec_write(tdb, offset, rec) == -1 ||
+ ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free record write failed at offset=%d\n", offset));
+ goto fail;
+ }
+
+ /* And we're done. */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+
+/* expand a file. we prefer to use ftruncate, as that is what posix
+ says to use for mmap expansion */
+static int expand_file(TDB_CONTEXT *tdb, tdb_off size, tdb_off addition)
+{
+ char buf[1024];
+#if HAVE_FTRUNCATE_EXTEND
+ if (ftruncate(tdb->fd, size+addition) != 0) {
+ TDB_LOG((tdb, 0, "expand_file ftruncate to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+#else
+ char b = 0;
+
+#ifdef HAVE_PWRITE
+ if (pwrite(tdb->fd, &b, 1, (size+addition) - 1) != 1) {
+#else
+ if (lseek(tdb->fd, (size+addition) - 1, SEEK_SET) != (size+addition) - 1 ||
+ write(tdb->fd, &b, 1) != 1) {
+#endif
+ TDB_LOG((tdb, 0, "expand_file to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+#endif
+
+ /* now fill the file with something. This ensures that the file isn't sparse, which would be
+ very bad if we ran out of disk. This must be done with write, not via mmap */
+ memset(buf, 0x42, sizeof(buf));
+ while (addition) {
+ int n = addition>sizeof(buf)?sizeof(buf):addition;
+#ifdef HAVE_PWRITE
+ int ret = pwrite(tdb->fd, buf, n, size);
+#else
+ int ret;
+ if (lseek(tdb->fd, size, SEEK_SET) != size)
+ return -1;
+ ret = write(tdb->fd, buf, n);
+#endif
+ if (ret != n) {
+ TDB_LOG((tdb, 0, "expand_file write of %d failed (%s)\n",
+ n, strerror(errno)));
+ return -1;
+ }
+ addition -= n;
+ size += n;
+ }
+ return 0;
+}
+
+
+/* expand the database at least size bytes by expanding the underlying
+ file and doing the mmap again if necessary */
+static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size)
+{
+ struct list_struct rec;
+ tdb_off offset;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ TDB_LOG((tdb, 0, "lock failed in tdb_expand\n"));
+ return -1;
+ }
+
+ /* must know about any previous expansions by another process */
+ tdb_oob(tdb, tdb->map_size + 1, 1);
+
+ /* always make room for at least 10 more records, and round
+ the database up to a multiple of TDB_PAGE_SIZE */
+ size = TDB_ALIGN(tdb->map_size + size*10, TDB_PAGE_SIZE) - tdb->map_size;
+
+ if (!(tdb->flags & TDB_INTERNAL))
+ tdb_munmap(tdb);
+
+ /*
+ * We must ensure the file is unmapped before doing this
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* expand the file itself */
+ if (!(tdb->flags & TDB_INTERNAL)) {
+ if (expand_file(tdb, tdb->map_size, size) != 0)
+ goto fail;
+ }
+
+ tdb->map_size += size;
+
+ if (tdb->flags & TDB_INTERNAL)
+ tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);
+ else {
+ /*
+ * We must ensure the file is remapped before adding the space
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* We're ok if the mmap fails as we'll fallback to read/write */
+ tdb_mmap(tdb);
+ }
+
+ /* form a new freelist record */
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = size - sizeof(rec);
+
+ /* link it into the free list */
+ offset = tdb->map_size - size;
+ if (tdb_free(tdb, offset, &rec) == -1)
+ goto fail;
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+/* allocate some space from the free list. The offset returned points
+ to a unconnected list_struct within the database with room for at
+ least length bytes of total data
+
+ 0 is returned if the space could not be allocated
+ */
+static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length,
+ struct list_struct *rec)
+{
+ tdb_off rec_ptr, last_ptr, newrec_ptr;
+ struct list_struct newrec;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1)
+ return 0;
+
+ /* Extra bytes required for tailer */
+ length += sizeof(tdb_off);
+
+ again:
+ last_ptr = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+ goto fail;
+
+ /* keep looking until we find a freelist record big enough */
+ while (rec_ptr) {
+ if (rec_free_read(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ if (rec->rec_len >= length) {
+ /* found it - now possibly split it up */
+ if (rec->rec_len > length + MIN_REC_SIZE) {
+ /* Length of left piece */
+ length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+ /* Right piece to go on free list */
+ newrec.rec_len = rec->rec_len
+ - (sizeof(*rec) + length);
+ newrec_ptr = rec_ptr + sizeof(*rec) + length;
+
+ /* And left record is shortened */
+ rec->rec_len = length;
+ } else
+ newrec_ptr = 0;
+
+ /* Remove allocated record from the free list */
+ if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+ goto fail;
+
+ /* Update header: do this before we drop alloc
+ lock, otherwise tdb_free() might try to
+ merge with us, thinking we're free.
+ (Thanks Jeremy Allison). */
+ rec->magic = TDB_MAGIC;
+ if (rec_write(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ /* Did we create new block? */
+ if (newrec_ptr) {
+ /* Update allocated record tailer (we
+ shortened it). */
+ if (update_tailer(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ /* Free new record */
+ if (tdb_free(tdb, newrec_ptr, &newrec) == -1)
+ goto fail;
+ }
+
+ /* all done - return the new record offset */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return rec_ptr;
+ }
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ rec_ptr = rec->next;
+ }
+ /* we didn't find enough space. See if we can expand the
+ database and if we can then try again */
+ if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+ goto again;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
+{
+ struct tdb_header *newdb;
+ int size, ret = -1;
+
+ /* We make it up in memory, then write it out if not internal */
+ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off);
+ if (!(newdb = calloc(size, 1)))
+ return TDB_ERRCODE(TDB_ERR_OOM, -1);
+
+ /* Fill in the header */
+ newdb->version = TDB_VERSION;
+ newdb->hash_size = hash_size;
+#ifdef USE_SPINLOCKS
+ newdb->rwlocks = size;
+#endif
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->map_size = size;
+ tdb->map_ptr = (char *)newdb;
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Convert the `ondisk' version if asked. */
+ CONVERT(*newdb);
+ return 0;
+ }
+ if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+ goto fail;
+
+ if (ftruncate(tdb->fd, 0) == -1)
+ goto fail;
+
+ /* This creates an endian-converted header, as if read from disk */
+ CONVERT(*newdb);
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Don't endian-convert the magic food! */
+ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+ if (write(tdb->fd, newdb, size) != size)
+ ret = -1;
+ else
+ ret = tdb_create_rwlocks(tdb->fd, hash_size);
+
+ fail:
+ free(newdb);
+ return ret;
+}
+
+/* Returns 0 on fail. On success, return offset of record, and fills
+ in rec */
+static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash,
+ struct list_struct *r)
+{
+ tdb_off rec_ptr;
+
+ /* read in the hash top */
+ if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (!TDB_DEAD(r) && hash==r->full_hash && key.dsize==r->key_len) {
+ char *k;
+ /* a very likely hit - read the key */
+ k = tdb_alloc_read(tdb, rec_ptr + sizeof(*r),
+ r->key_len);
+ if (!k)
+ return 0;
+
+ if (memcmp(key.dptr, k, key.dsize) == 0) {
+ free(k);
+ return rec_ptr;
+ }
+ free(k);
+ }
+ rec_ptr = r->next;
+ }
+ return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
+}
+
+/* If they do lockkeys, check that this hash is one they locked */
+static int tdb_keylocked(TDB_CONTEXT *tdb, u32 hash)
+{
+ u32 i;
+ if (!tdb->lockedkeys)
+ return 1;
+ for (i = 0; i < tdb->lockedkeys[0]; i++)
+ if (tdb->lockedkeys[i+1] == hash)
+ return 1;
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, 0);
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+static tdb_off tdb_find_lock(TDB_CONTEXT *tdb, TDB_DATA key, int locktype,
+ struct list_struct *rec)
+{
+ u32 hash, rec_ptr;
+
+ hash = tdb_hash(&key);
+ if (!tdb_keylocked(tdb, hash))
+ return 0;
+ if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+ return 0;
+ if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+ tdb_unlock(tdb, BUCKET(hash), locktype);
+ return rec_ptr;
+}
+
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb)
+{
+ return tdb->ecode;
+}
+
+static struct tdb_errname {
+ enum TDB_ERROR ecode; const char *estring;
+} emap[] = { {TDB_SUCCESS, "Success"},
+ {TDB_ERR_CORRUPT, "Corrupt database"},
+ {TDB_ERR_IO, "IO Error"},
+ {TDB_ERR_LOCK, "Locking error"},
+ {TDB_ERR_OOM, "Out of memory"},
+ {TDB_ERR_EXISTS, "Record exists"},
+ {TDB_ERR_NOLOCK, "Lock exists on other keys"},
+ {TDB_ERR_NOEXIST, "Record does not exist"} };
+
+/* Error string for the last tdb error */
+const char *tdb_errorstr(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
+ if (tdb->ecode == emap[i].ecode)
+ return emap[i].estring;
+ return "Invalid error code";
+}
+
+/* update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1
+*/
+static int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
+{
+ struct list_struct rec;
+ tdb_off rec_ptr;
+ int ret = -1;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find_lock(tdb, key, F_WRLCK, &rec)))
+ return -1;
+
+ /* must be long enough key, data and tailer */
+ if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off)) {
+ tdb->ecode = TDB_SUCCESS; /* Not really an error */
+ goto out;
+ }
+
+ if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ dbuf.dptr, dbuf.dsize) == -1)
+ goto out;
+
+ if (dbuf.dsize != rec.data_len) {
+ /* update size */
+ rec.data_len = dbuf.dsize;
+ ret = rec_write(tdb, rec_ptr, &rec);
+ } else
+ ret = 0;
+ out:
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK);
+ return ret;
+}
+
+/* find an entry in the database given a key */
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ tdb_off rec_ptr;
+ struct list_struct rec;
+ TDB_DATA ret;
+
+ /* find which hash bucket it is in */
+ if (!(rec_ptr = tdb_find_lock(tdb,key,F_RDLCK,&rec)))
+ return tdb_null;
+
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ ret.dsize = rec.data_len;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return ret;
+}
+
+/* check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+*/
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ struct list_struct rec;
+
+ if (tdb_find_lock(tdb, key, F_RDLCK, &rec) == 0)
+ return 0;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return 1;
+}
+
+/* record lock stops delete underneath */
+static int lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ return off ? tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0) : 0;
+}
+/*
+ Write locks override our own fcntl readlocks, so check it here.
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+
+static int write_lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ struct tdb_traverse_lock *i;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ return -1;
+ return tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1);
+}
+
+/*
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+
+static int write_unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ return tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0);
+}
+/* fcntl locks don't stack: avoid unlocking someone else's */
+static int unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ struct tdb_traverse_lock *i;
+ u32 count = 0;
+
+ if (off == 0)
+ return 0;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ count++;
+ return (count == 1 ? tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0) : 0);
+}
+
+/* actually delete an entry in the database given the offset */
+static int do_delete(TDB_CONTEXT *tdb, tdb_off rec_ptr, struct list_struct*rec)
+{
+ tdb_off last_ptr, i;
+ struct list_struct lastrec;
+
+ if (tdb->read_only) return -1;
+
+ if (write_lock_record(tdb, rec_ptr) == -1) {
+ /* Someone traversing here: mark it as dead */
+ rec->magic = TDB_DEAD_MAGIC;
+ return rec_write(tdb, rec_ptr, rec);
+ }
+ write_unlock_record(tdb, rec_ptr);
+
+ /* find previous record in hash chain */
+ if (ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
+ return -1;
+ for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
+ if (rec_read(tdb, i, &lastrec) == -1)
+ return -1;
+
+ /* unlink it: next ptr is at start of record. */
+ if (last_ptr == 0)
+ last_ptr = TDB_HASH_TOP(rec->full_hash);
+ if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+ return -1;
+
+ /* recover the space */
+ if (tdb_free(tdb, rec_ptr, rec) == -1)
+ return -1;
+ return 0;
+}
+
+/* Uses traverse lock: 0 = finish, -1 = error, other = record offset */
+static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
+ struct list_struct *rec)
+{
+ int want_next = (tlock->off != 0);
+
+ /* No traversal allows if you've called tdb_lockkeys() */
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+
+ /* Lock each chain from the start one. */
+ for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+ if (tdb_lock(tdb, tlock->hash, F_WRLCK) == -1)
+ return -1;
+
+ /* No previous record? Start at top of chain. */
+ if (!tlock->off) {
+ if (ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+ &tlock->off) == -1)
+ goto fail;
+ } else {
+ /* Otherwise unlock the previous record. */
+ unlock_record(tdb, tlock->off);
+ }
+
+ if (want_next) {
+ /* We have offset of old record: grab next */
+ if (rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ tlock->off = rec->next;
+ }
+
+ /* Iterate through chain */
+ while( tlock->off) {
+ tdb_off current;
+ if (rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ if (!TDB_DEAD(rec)) {
+ /* Woohoo: we found one! */
+ lock_record(tdb, tlock->off);
+ return tlock->off;
+ }
+ /* Try to clean dead ones from old traverses */
+ current = tlock->off;
+ tlock->off = rec->next;
+ do_delete(tdb, current, rec);
+ }
+ tdb_unlock(tdb, tlock->hash, F_WRLCK);
+ want_next = 0;
+ }
+ /* We finished iteration without finding anything */
+ return TDB_ERRCODE(TDB_SUCCESS, 0);
+
+ fail:
+ tlock->off = 0;
+ tdb_unlock(tdb, tlock->hash, F_WRLCK);
+ return -1;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+ return -1 on error or the record count traversed
+ if fn is NULL then it is not called
+ a non-zero return value from fn() indicates that the traversal should stop
+ */
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state)
+{
+ TDB_DATA key, dbuf;
+ struct list_struct rec;
+ struct tdb_traverse_lock tl = { NULL, 0, 0 };
+ int ret, count = 0;
+
+ /* This was in the initializaton, above, but the IRIX compiler
+ * did not like it. crh
+ */
+ tl.next = tdb->travlocks.next;
+
+ /* fcntl locks don't stack: beware traverse inside traverse */
+ tdb->travlocks.next = &tl;
+
+ /* tdb_next_lock places locks on the record returned, and its chain */
+ while ((ret = tdb_next_lock(tdb, &tl, &rec)) > 0) {
+ count++;
+ /* now read the full record */
+ key.dptr = tdb_alloc_read(tdb, tl.off + sizeof(rec),
+ rec.key_len + rec.data_len);
+ if (!key.dptr) {
+ tdb_unlock(tdb, tl.hash, F_WRLCK);
+ unlock_record(tdb, tl.off);
+ tdb->travlocks.next = tl.next;
+ return -1;
+ }
+ key.dsize = rec.key_len;
+ dbuf.dptr = key.dptr + rec.key_len;
+ dbuf.dsize = rec.data_len;
+
+ /* Drop chain lock, call out */
+ tdb_unlock(tdb, tl.hash, F_WRLCK);
+ if (fn && fn(tdb, key, dbuf, state)) {
+ /* They want us to terminate traversal */
+ unlock_record(tdb, tl.off);
+ tdb->travlocks.next = tl.next;
+ free(key.dptr);
+ return count;
+ }
+ free(key.dptr);
+ }
+ tdb->travlocks.next = tl.next;
+ if (ret < 0)
+ return -1;
+ else
+ return count;
+}
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
+{
+ TDB_DATA key;
+ struct list_struct rec;
+
+ /* release any old lock */
+ unlock_record(tdb, tdb->travlocks.off);
+ tdb->travlocks.off = tdb->travlocks.hash = 0;
+
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0)
+ return tdb_null;
+ /* now read the key */
+ key.dsize = rec.key_len;
+ key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+ tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK);
+ return key;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
+{
+ u32 oldhash;
+ TDB_DATA key = tdb_null;
+ struct list_struct rec;
+ char *k = NULL;
+
+ /* Is locked key the old key? If so, traverse will be reliable. */
+ if (tdb->travlocks.off) {
+ if (tdb_lock(tdb,tdb->travlocks.hash,F_WRLCK))
+ return tdb_null;
+ if (rec_read(tdb, tdb->travlocks.off, &rec) == -1
+ || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+ rec.key_len))
+ || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+ /* No, it wasn't: unlock it and start from scratch */
+ unlock_record(tdb, tdb->travlocks.off);
+ tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK);
+ tdb->travlocks.off = 0;
+ }
+
+ if (k)
+ free(k);
+ }
+
+ if (!tdb->travlocks.off) {
+ /* No previous element: do normal find, and lock record */
+ tdb->travlocks.off = tdb_find_lock(tdb, oldkey, F_WRLCK, &rec);
+ if (!tdb->travlocks.off)
+ return tdb_null;
+ tdb->travlocks.hash = BUCKET(rec.full_hash);
+ lock_record(tdb, tdb->travlocks.off);
+ }
+ oldhash = tdb->travlocks.hash;
+
+ /* Grab next record: locks chain and returned record,
+ unlocks old record */
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 0) {
+ key.dsize = rec.key_len;
+ key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+ key.dsize);
+ /* Unlock the chain of this new record */
+ tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK);
+ }
+ /* Unlock the chain of old record */
+ tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK);
+ return key;
+}
+
+/* delete an entry in the database given a key */
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ tdb_off rec_ptr;
+ struct list_struct rec;
+ int ret;
+
+ if (!(rec_ptr = tdb_find_lock(tdb, key, F_WRLCK, &rec)))
+ return -1;
+ ret = do_delete(tdb, rec_ptr, &rec);
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK);
+ return ret;
+}
+
+/* store an element in the database, replacing any existing element
+ with the same key
+
+ return 0 on success, -1 on failure
+*/
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+ struct list_struct rec;
+ u32 hash;
+ tdb_off rec_ptr;
+ char *p = NULL;
+ int ret = 0;
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+ if (!tdb_keylocked(tdb, hash))
+ return -1;
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ /* check for it existing, on insert. */
+ if (flag == TDB_INSERT) {
+ if (tdb_exists(tdb, key)) {
+ tdb->ecode = TDB_ERR_EXISTS;
+ goto fail;
+ }
+ } else {
+ /* first try in-place update, on modify or replace. */
+ if (tdb_update(tdb, key, dbuf) == 0)
+ goto out;
+ if (flag == TDB_MODIFY && tdb->ecode == TDB_ERR_NOEXIST)
+ goto fail;
+ }
+ /* reset the error code potentially set by the tdb_update() */
+ tdb->ecode = TDB_SUCCESS;
+
+ /* delete any existing record - if it doesn't exist we don't
+ care. Doing this first reduces fragmentation, and avoids
+ coalescing with `allocated' block before it's updated. */
+ if (flag != TDB_INSERT)
+ tdb_delete(tdb, key);
+
+ /* Copy key+value *before* allocating free space in case malloc
+ fails and we are left with a dead spot in the tdb. */
+
+ if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ memcpy(p, key.dptr, key.dsize);
+ memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
+
+ /* now we're into insert / modify / replace of a record which
+ * we know could not be optimised by an in-place store (for
+ * various reasons). */
+ if (!(rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec)))
+ goto fail;
+
+ /* Read hash top into next ptr */
+ if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+ goto fail;
+
+ rec.key_len = key.dsize;
+ rec.data_len = dbuf.dsize;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ /* write out and point the top of the hash chain at it */
+ if (rec_write(tdb, rec_ptr, &rec) == -1
+ || tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
+ || ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+ fail:
+ /* Need to tdb_unallocate() here */
+ ret = -1;
+ }
+ out:
+ if (p)
+ free(p);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+}
+
+static int tdb_already_open(dev_t device,
+ ino_t ino)
+{
+ TDB_CONTEXT *i;
+
+ for (i = tdbs; i; i = i->next) {
+ if (i->device == device && i->inode == ino) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the
+ database file. A flags value of O_WRONLY is invalid. The hash size
+ is advisory, use zero for a default value.
+
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno).
+
+ @param name may be NULL for internal databases. */
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL);
+}
+
+
+TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ tdb_log_func log_fn)
+{
+ TDB_CONTEXT *tdb;
+ struct stat st;
+ int rev = 0, locked;
+
+ if (!(tdb = calloc(1, sizeof *tdb))) {
+ /* Can't log this */
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb->fd = -1;
+ tdb->name = NULL;
+ tdb->map_ptr = NULL;
+ tdb->lockedkeys = NULL;
+ tdb->flags = tdb_flags;
+ tdb->open_flags = open_flags;
+ tdb->log_fn = log_fn;
+
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
+ name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (hash_size == 0)
+ hash_size = DEFAULT_HASH_SIZE;
+ if ((open_flags & O_ACCMODE) == O_RDONLY) {
+ tdb->read_only = 1;
+ /* read only databases don't do locking or clear if first */
+ tdb->flags |= TDB_NOLOCK;
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ }
+
+ /* internal databases don't mmap or lock, and start off cleared */
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ tdb_new_database(tdb, hash_size);
+ goto internal;
+ }
+
+ if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: could not open file %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by open(2) */
+ }
+
+ /* ensure there is only one process initialising at once */
+ if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by tdb_brlock */
+ }
+
+ /* we need to zero database if we are the only one with it open */
+ if ((locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))
+ && (tdb_flags & TDB_CLEAR_IF_FIRST)) {
+ open_flags |= O_CREAT;
+ if (ftruncate(tdb->fd, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to truncate %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by ftruncate */
+ }
+ }
+
+ if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
+ || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
+ || (tdb->header.version != TDB_VERSION
+ && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
+ /* its not a valid database - possibly initialise it */
+ if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
+ errno = EIO; /* ie bad format or something */
+ goto fail;
+ }
+ rev = (tdb->flags & TDB_CONVERT);
+ }
+ if (!rev)
+ tdb->flags &= ~TDB_CONVERT;
+ else {
+ tdb->flags |= TDB_CONVERT;
+ convert(&tdb->header, sizeof(tdb->header));
+ }
+ if (fstat(tdb->fd, &st) == -1)
+ goto fail;
+
+ /* Is it already in the open list? If so, fail. */
+ if (tdb_already_open(st.st_dev, st.st_ino)) {
+ TDB_LOG((tdb, 2, "tdb_open_ex: "
+ "%s (%d,%d) is already open in this process\n",
+ name, st.st_dev, st.st_ino));
+ errno = EBUSY;
+ goto fail;
+ }
+
+ if (!(tdb->name = (char *)strdup(name))) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ tdb->map_size = st.st_size;
+ tdb->device = st.st_dev;
+ tdb->inode = st.st_ino;
+ tdb->locked = calloc(tdb->header.hash_size+1, sizeof(tdb->locked[0]));
+ if (!tdb->locked) {
+ TDB_LOG((tdb, 2, "tdb_open_ex: "
+ "failed to allocate lock structure for %s\n",
+ name));
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb_mmap(tdb);
+ if (locked) {
+ if (!tdb->read_only)
+ tdb_clear_spinlocks(tdb);
+ if (tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to take ACTIVE_LOCK on %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ }
+ /* leave this lock in place to indicate it's in use */
+ if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
+ goto fail;
+
+ internal:
+ /* Internal (memory-only) databases skip all the code above to
+ * do with disk files, and resume here by releasing their
+ * global lock and hooking into the active list. */
+ if (tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
+ goto fail;
+ tdb->next = tdbs;
+ tdbs = tdb;
+ return tdb;
+
+ fail:
+ { int save_errno = errno;
+
+ if (!tdb)
+ return NULL;
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ free(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ if (tdb->name)
+ free(tdb->name);
+ if (tdb->fd != -1)
+ close(tdb->fd);
+ if (tdb->locked)
+ free(tdb->locked);
+ errno = save_errno;
+ return NULL;
+ }
+}
+
+/* close a database */
+int tdb_close(TDB_CONTEXT *tdb)
+{
+ TDB_CONTEXT **i;
+ int ret = 0;
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ free(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ if (tdb->name)
+ free(tdb->name);
+ if (tdb->fd != -1)
+ ret = close(tdb->fd);
+ if (tdb->locked)
+ free(tdb->locked);
+ if (tdb->lockedkeys)
+ free(tdb->lockedkeys);
+
+ /* Remove from contexts list */
+ for (i = &tdbs; *i; i = &(*i)->next) {
+ if (*i == tdb) {
+ *i = tdb->next;
+ break;
+ }
+ }
+
+ memset(tdb, 0, sizeof(*tdb));
+ free(tdb);
+
+ return ret;
+}
+
+/* lock/unlock entire database */
+int tdb_lockall(TDB_CONTEXT *tdb)
+{
+ u32 i;
+
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only)
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ for (i = 0; i < tdb->header.hash_size; i++)
+ if (tdb_lock(tdb, i, F_WRLCK))
+ break;
+
+ /* If error, release locks we have... */
+ if (i < tdb->header.hash_size) {
+ u32 j;
+
+ for ( j = 0; j < i; j++)
+ tdb_unlock(tdb, j, F_WRLCK);
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ }
+
+ return 0;
+}
+void tdb_unlockall(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ for (i=0; i < tdb->header.hash_size; i++)
+ tdb_unlock(tdb, i, F_WRLCK);
+}
+
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[])
+{
+ u32 i, j, hash;
+
+ /* Can't lock more keys if already locked */
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ if (!(tdb->lockedkeys = malloc(sizeof(u32) * (number+1))))
+ return TDB_ERRCODE(TDB_ERR_OOM, -1);
+ /* First number in array is # keys */
+ tdb->lockedkeys[0] = number;
+
+ /* Insertion sort by bucket */
+ for (i = 0; i < number; i++) {
+ hash = tdb_hash(&keys[i]);
+ for (j = 0; j < i && BUCKET(tdb->lockedkeys[j+1]) < BUCKET(hash); j++);
+ memmove(&tdb->lockedkeys[j+2], &tdb->lockedkeys[j+1], sizeof(u32) * (i-j));
+ tdb->lockedkeys[j+1] = hash;
+ }
+ /* Finally, lock in order */
+ for (i = 0; i < number; i++)
+ if (tdb_lock(tdb, i, F_WRLCK))
+ break;
+
+ /* If error, release locks we have... */
+ if (i < number) {
+ for ( j = 0; j < i; j++)
+ tdb_unlock(tdb, j, F_WRLCK);
+ free(tdb->lockedkeys);
+ tdb->lockedkeys = NULL;
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ }
+ return 0;
+}
+
+/* Unlock the keys previously locked by tdb_lockkeys() */
+void tdb_unlockkeys(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ for (i = 0; i < tdb->lockedkeys[0]; i++)
+ tdb_unlock(tdb, tdb->lockedkeys[i+1], F_WRLCK);
+ free(tdb->lockedkeys);
+ tdb->lockedkeys = NULL;
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+ contention - it cannot guarantee how many records will be locked */
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+void tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+
+
+/* register a loging function */
+void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , const char *, ...))
+{
+ tdb->log_fn = fn;
+}
+
+
+/* reopen a tdb - this is used after a fork to ensure that we have an independent
+ seek pointer from our parent and to re-establish locks */
+int tdb_reopen(TDB_CONTEXT *tdb)
+{
+ struct stat st;
+
+ tdb_munmap(tdb);
+ close(tdb->fd);
+ tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+ if (tdb->fd == -1) {
+ TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ fstat(tdb->fd, &st);
+ if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+ TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
+ goto fail;
+ }
+ tdb_mmap(tdb);
+ if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ tdb_close(tdb);
+ return -1;
+}
+
+/* reopen all tdb's */
+int tdb_reopen_all(void)
+{
+ TDB_CONTEXT *tdb;
+
+ for (tdb=tdbs; tdb; tdb = tdb->next) {
+ if (tdb_reopen(tdb) != 0) return -1;
+ }
+
+ return 0;
+}
diff --git a/source/tdb/tdb.h b/source/tdb/tdb.h
new file mode 100644
index 00000000000..6877e5cdf49
--- /dev/null
+++ b/source/tdb/tdb.h
@@ -0,0 +1,141 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba database functions
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1
+#define TDB_INSERT 2
+#define TDB_MODIFY 3
+
+/* flags for tdb_open() */
+#define TDB_DEFAULT 0 /* just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1
+#define TDB_INTERNAL 2 /* don't store on disk */
+#define TDB_NOLOCK 4 /* don't do any locking */
+#define TDB_NOMMAP 8 /* don't use mmap */
+#define TDB_CONVERT 16 /* convert endian (internal use) */
+
+#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
+ TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK };
+
+#ifndef u32
+#define u32 unsigned
+#endif
+
+typedef struct {
+ char *dptr;
+ size_t dsize;
+} TDB_DATA;
+
+typedef u32 tdb_len;
+typedef u32 tdb_off;
+
+/* this is stored at the front of every database */
+struct tdb_header {
+ char magic_food[32]; /* for /etc/magic */
+ u32 version; /* version of the code */
+ u32 hash_size; /* number of hash entries */
+ tdb_off rwlocks;
+ tdb_off reserved[31];
+};
+
+struct tdb_lock_type {
+ u32 count;
+ u32 ltype;
+};
+
+struct tdb_traverse_lock {
+ struct tdb_traverse_lock *next;
+ u32 off;
+ u32 hash;
+};
+
+/* this is the context structure that is returned from a db open */
+typedef struct tdb_context {
+ char *name; /* the name of the database */
+ void *map_ptr; /* where it is currently mapped */
+ int fd; /* open file descriptor for the database */
+ tdb_len map_size; /* how much space has been mapped */
+ int read_only; /* opened read-only */
+ struct tdb_lock_type *locked; /* array of chain locks */
+ enum TDB_ERROR ecode; /* error code for last tdb error */
+ struct tdb_header header; /* a cached copy of the header */
+ u32 flags; /* the flags passed to tdb_open */
+ u32 *lockedkeys; /* array of locked keys: first is #keys */
+ struct tdb_traverse_lock travlocks; /* current traversal locks */
+ struct tdb_context *next; /* all tdbs to avoid multiple opens */
+ dev_t device; /* uniquely identifies this tdb */
+ ino_t inode; /* uniquely identifies this tdb */
+ void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */
+ int open_flags; /* flags used in the open - needed by reopen */
+} TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
+
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ tdb_log_func log_fn);
+
+int tdb_reopen(TDB_CONTEXT *tdb);
+int tdb_reopen_all(void);
+void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
+const char *tdb_errorstr(TDB_CONTEXT *tdb);
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+int tdb_close(TDB_CONTEXT *tdb);
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state);
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[]);
+void tdb_unlockkeys(TDB_CONTEXT *tdb);
+int tdb_lockall(TDB_CONTEXT *tdb);
+void tdb_unlockall(TDB_CONTEXT *tdb);
+
+/* Low level locking functions: use with care */
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
+void tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
+
+/* Debug functions. Not used in production. */
+void tdb_dump_all(TDB_CONTEXT *tdb);
+void tdb_printfreelist(TDB_CONTEXT *tdb);
+
+extern TDB_DATA tdb_null;
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* tdb.h */
diff --git a/source/tdb/tdb.magic b/source/tdb/tdb.magic
new file mode 100644
index 00000000000..f5619e7327e
--- /dev/null
+++ b/source/tdb/tdb.magic
@@ -0,0 +1,10 @@
+# Magic file(1) information about tdb files.
+#
+# Install this into /etc/magic or the corresponding location for your
+# system, or pass as a -m argument to file(1).
+
+# You may use and redistribute this file without restriction.
+
+0 string TDB\ file TDB database
+>32 lelong =0x2601196D version 6, little-endian
+>>36 lelong x hash size %d bytes
diff --git a/source/tdb/tdbdump.c b/source/tdb/tdbdump.c
new file mode 100644
index 00000000000..ddaff162091
--- /dev/null
+++ b/source/tdb/tdbdump.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ simple tdb dump util
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include "tdb.h"
+
+static void print_data(TDB_DATA d)
+{
+ unsigned char *p = d.dptr;
+ int len = d.dsize;
+ while (len--) {
+ if (isprint(*p) && !strchr("\"\\", *p)) {
+ fputc(*p, stdout);
+ } else {
+ printf("\\%02X", *p);
+ }
+ p++;
+ }
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("{\n");
+ printf("key = \"");
+ print_data(key);
+ printf("\"\n");
+ printf("data = \"");
+ print_data(dbuf);
+ printf("\"\n");
+ printf("}\n");
+ return 0;
+}
+
+static int dump_tdb(const char *fname)
+{
+ TDB_CONTEXT *tdb;
+
+ tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+ if (!tdb) {
+ printf("Failed to open %s\n", fname);
+ return 1;
+ }
+
+ tdb_traverse(tdb, traverse_fn, NULL);
+ return 0;
+}
+
+ int main(int argc, char *argv[])
+{
+ char *fname;
+
+ if (argc < 2) {
+ printf("Usage: tdbdump <fname>\n");
+ exit(1);
+ }
+
+ fname = argv[1];
+
+ return dump_tdb(fname);
+}
diff --git a/source/tdb/tdbtest.c b/source/tdb/tdbtest.c
new file mode 100644
index 00000000000..0741073ce11
--- /dev/null
+++ b/source/tdb/tdbtest.c
@@ -0,0 +1,262 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "tdb.h"
+#include <gdbm.h>
+
+/* a test program for tdb - the trivial database */
+
+
+
+#define DELETE_PROB 7
+#define STORE_PROB 5
+
+static TDB_CONTEXT *db;
+static GDBM_FILE gdbm;
+
+struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void fatal(char *why)
+{
+ perror(why);
+ exit(1);
+}
+
+static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+}
+
+static void compare_db(void)
+{
+ TDB_DATA d, key, nextkey;
+ datum gd, gkey, gnextkey;
+
+ key = tdb_firstkey(db);
+ while (key.dptr) {
+ d = tdb_fetch(db, key);
+ gkey.dptr = key.dptr;
+ gkey.dsize = key.dsize;
+
+ gd = gdbm_fetch(gdbm, gkey);
+
+ if (!gd.dptr) fatal("key not in gdbm");
+ if (gd.dsize != d.dsize) fatal("data sizes differ");
+ if (memcmp(gd.dptr, d.dptr, d.dsize)) {
+ fatal("data differs");
+ }
+
+ nextkey = tdb_nextkey(db, key);
+ free(key.dptr);
+ free(d.dptr);
+ free(gd.dptr);
+ key = nextkey;
+ }
+
+ gkey = gdbm_firstkey(gdbm);
+ while (gkey.dptr) {
+ gd = gdbm_fetch(gdbm, gkey);
+ key.dptr = gkey.dptr;
+ key.dsize = gkey.dsize;
+
+ d = tdb_fetch(db, key);
+
+ if (!d.dptr) fatal("key not in db");
+ if (d.dsize != gd.dsize) fatal("data sizes differ");
+ if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
+ fatal("data differs");
+ }
+
+ gnextkey = gdbm_nextkey(gdbm, gkey);
+ free(gkey.dptr);
+ free(gd.dptr);
+ free(d.dptr);
+ gkey = gnextkey;
+ }
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ TDB_DATA key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ } else {
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static void addrec_gdbm(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ datum key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ gdbm_delete(gdbm, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
+ fatal("gdbm_store failed");
+ }
+ } else {
+ data = gdbm_fetch(gdbm, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+#if 0
+ printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
+#endif
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+static void merge_test(void)
+{
+ int i;
+ char keys[5][2];
+ TDB_DATA key, data;
+
+ for (i = 0; i < 5; i++) {
+ sprintf(keys[i], "%d", i);
+ key.dptr = keys[i];
+ key.dsize = 2;
+
+ data.dptr = "test";
+ data.dsize = 4;
+
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ }
+
+ key.dptr = keys[0];
+ tdb_delete(db, key);
+ key.dptr = keys[4];
+ tdb_delete(db, key);
+ key.dptr = keys[2];
+ tdb_delete(db, key);
+ key.dptr = keys[1];
+ tdb_delete(db, key);
+ key.dptr = keys[3];
+ tdb_delete(db, key);
+}
+
+int main(int argc, char *argv[])
+{
+ int i, seed=0;
+ int loops = 10000;
+
+ unlink("test.gdbm");
+
+ db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
+ 0600, NULL);
+
+ if (!db || !gdbm) {
+ fatal("db open failed");
+ }
+
+ tdb_logging_function(db, tdb_log);
+
+#if 1
+ srand(seed);
+ start_timer();
+ for (i=0;i<loops;i++) addrec_gdbm();
+ printf("gdbm got %.2f ops/sec\n", i/end_timer());
+#endif
+
+ merge_test();
+
+ srand(seed);
+ start_timer();
+ for (i=0;i<loops;i++) addrec_db();
+ printf("tdb got %.2f ops/sec\n", i/end_timer());
+
+ compare_db();
+
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+
+ tdb_close(db);
+ gdbm_close(gdbm);
+
+ return 0;
+}
diff --git a/source/tdb/tdbtool.c b/source/tdb/tdbtool.c
new file mode 100644
index 00000000000..d1c199849b3
--- /dev/null
+++ b/source/tdb/tdbtool.c
@@ -0,0 +1,479 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba database functions
+ Copyright (C) Andrew Tridgell 1999-2000
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000
+ Copyright (C) Andrew Esh 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include "tdb.h"
+
+/* a tdb tool for manipulating a tdb database */
+
+#define FSTRING_LEN 256
+typedef char fstring[FSTRING_LEN];
+
+typedef struct connections_key {
+ pid_t pid;
+ int cnum;
+ fstring name;
+} connections_key;
+
+typedef struct connections_data {
+ int magic;
+ pid_t pid;
+ int cnum;
+ uid_t uid;
+ gid_t gid;
+ char name[24];
+ char addr[24];
+ char machine[128];
+ time_t start;
+} connections_data;
+
+static TDB_CONTEXT *tdb;
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+
+static void print_asc(unsigned char *buf,int len)
+{
+ int i;
+
+ /* We're probably printing ASCII strings so don't try to display
+ the trailing NULL character. */
+
+ if (buf[len - 1] == 0)
+ len--;
+
+ for (i=0;i<len;i++)
+ printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static void print_data(unsigned char *buf,int len)
+{
+ int i=0;
+ if (len<=0) return;
+ printf("[%03X] ",i);
+ for (i=0;i<len;) {
+ printf("%02X ",(int)buf[i]);
+ i++;
+ if (i%8 == 0) printf(" ");
+ if (i%16 == 0) {
+ print_asc(&buf[i-16],8); printf(" ");
+ print_asc(&buf[i-8],8); printf("\n");
+ if (i<len) printf("[%03X] ",i);
+ }
+ }
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ printf(" ");
+ if (n>8) printf(" ");
+ while (n--) printf(" ");
+
+ n = i%16;
+ if (n > 8) n = 8;
+ print_asc(&buf[i-(i%16)],n); printf(" ");
+ n = (i%16) - n;
+ if (n>0) print_asc(&buf[i-n],n);
+ printf("\n");
+ }
+}
+
+static void help(void)
+{
+ printf("
+tdbtool:
+ create dbname : create a database
+ open dbname : open an existing database
+ erase : erase the database
+ dump : dump the database as strings
+ insert key data : insert a record
+ store key data : store a record (replace)
+ show key : show a record by key
+ delete key : delete a record by key
+ list : print the database hash table and freelist
+ free : print the database freelist
+ 1 | first : print the first record
+ n | next : print the next record
+ q | quit : terminate
+ \\n : repeat 'next' command
+");
+}
+
+static void terror(char *why)
+{
+ printf("%s\n", why);
+}
+
+static char *get_token(int startover)
+{
+ static char tmp[1024];
+ static char *cont = NULL;
+ char *insert, *start;
+ char *k = strtok(NULL, " ");
+
+ if (!k)
+ return NULL;
+
+ if (startover)
+ start = tmp;
+ else
+ start = cont;
+
+ strcpy(start, k);
+ insert = start + strlen(start) - 1;
+ while (*insert == '\\') {
+ *insert++ = ' ';
+ k = strtok(NULL, " ");
+ if (!k)
+ break;
+ strcpy(insert, k);
+ insert = start + strlen(start) - 1;
+ }
+
+ /* Get ready for next call */
+ cont = start + strlen(start) + 1;
+ return start;
+}
+
+static void create_tdb(void)
+{
+ char *tok = get_token(1);
+ if (!tok) {
+ help();
+ return;
+ }
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open(tok, 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (!tdb) {
+ printf("Could not create %s: %s\n", tok, strerror(errno));
+ }
+}
+
+static void open_tdb(void)
+{
+ char *tok = get_token(1);
+ if (!tok) {
+ help();
+ return;
+ }
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open(tok, 0, 0, O_RDWR, 0600);
+ if (!tdb) {
+ printf("Could not open %s: %s\n", tok, strerror(errno));
+ }
+}
+
+static void insert_tdb(void)
+{
+ char *k = get_token(1);
+ char *d = get_token(0);
+ TDB_DATA key, dbuf;
+
+ if (!k || !d) {
+ help();
+ return;
+ }
+
+ key.dptr = k;
+ key.dsize = strlen(k)+1;
+ dbuf.dptr = d;
+ dbuf.dsize = strlen(d)+1;
+
+ if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
+ terror("insert failed");
+ }
+}
+
+static void store_tdb(void)
+{
+ char *k = get_token(1);
+ char *d = get_token(0);
+ TDB_DATA key, dbuf;
+
+ if (!k || !d) {
+ help();
+ return;
+ }
+
+ key.dptr = k;
+ key.dsize = strlen(k)+1;
+ dbuf.dptr = d;
+ dbuf.dsize = strlen(d)+1;
+
+ printf("Storing key:\n");
+ print_rec(tdb, key, dbuf, NULL);
+
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
+ terror("store failed");
+ }
+}
+
+static void show_tdb(void)
+{
+ char *k = get_token(1);
+ TDB_DATA key, dbuf;
+
+ if (!k) {
+ help();
+ return;
+ }
+
+ key.dptr = k;
+ key.dsize = strlen(k)+1;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ terror("fetch failed");
+ return;
+ }
+ /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
+ print_rec(tdb, key, dbuf, NULL);
+}
+
+static void delete_tdb(void)
+{
+ char *k = get_token(1);
+ TDB_DATA key;
+
+ if (!k) {
+ help();
+ return;
+ }
+
+ key.dptr = k;
+ key.dsize = strlen(k)+1;
+
+ if (tdb_delete(tdb, key) != 0) {
+ terror("delete failed");
+ }
+}
+
+#if 0
+static int print_conn_key(TDB_DATA key)
+{
+ printf( "pid =%5d ", ((connections_key*)key.dptr)->pid);
+ printf( "cnum =%10d ", ((connections_key*)key.dptr)->cnum);
+ printf( "name =[%s]\n", ((connections_key*)key.dptr)->name);
+ return 0;
+}
+
+static int print_conn_data(TDB_DATA dbuf)
+{
+ printf( "pid =%5d ", ((connections_data*)dbuf.dptr)->pid);
+ printf( "cnum =%10d ", ((connections_data*)dbuf.dptr)->cnum);
+ printf( "name =[%s]\n", ((connections_data*)dbuf.dptr)->name);
+
+ printf( "uid =%5d ", ((connections_data*)dbuf.dptr)->uid);
+ printf( "addr =[%s]\n", ((connections_data*)dbuf.dptr)->addr);
+ printf( "gid =%5d ", ((connections_data*)dbuf.dptr)->gid);
+ printf( "machine=[%s]\n", ((connections_data*)dbuf.dptr)->machine);
+ printf( "start = %s\n", ctime(&((connections_data*)dbuf.dptr)->start));
+ return 0;
+}
+#endif
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+#if 0
+ print_conn_key(key);
+ print_conn_data(dbuf);
+ return 0;
+#else
+ printf("\nkey %d bytes\n", key.dsize);
+ print_asc(key.dptr, key.dsize);
+ printf("\ndata %d bytes\n", dbuf.dsize);
+ print_data(dbuf.dptr, dbuf.dsize);
+ return 0;
+#endif
+}
+
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ print_asc(key.dptr, key.dsize);
+ printf("\n");
+ return 0;
+}
+
+static int total_bytes;
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ total_bytes += dbuf.dsize;
+ return 0;
+}
+
+static void info_tdb(void)
+{
+ int count;
+ total_bytes = 0;
+ if ((count = tdb_traverse(tdb, traverse_fn, NULL) == -1))
+ printf("Error = %s\n", tdb_errorstr(tdb));
+ else
+ printf("%d records totalling %d bytes\n", count, total_bytes);
+}
+
+static char *tdb_getline(char *prompt)
+{
+ static char line[1024];
+ char *p;
+ fputs(prompt, stdout);
+ line[0] = 0;
+ p = fgets(line, sizeof(line)-1, stdin);
+ if (p) p = strchr(p, '\n');
+ if (p) *p = 0;
+ return p?line:NULL;
+}
+
+static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ return tdb_delete(the_tdb, key);
+}
+
+static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_firstkey(the_tdb);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr) terror("fetch failed");
+ /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_nextkey(the_tdb, *pkey);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr)
+ terror("fetch failed");
+ else
+ /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ int bIterate = 0;
+ char *line;
+ char *tok;
+ TDB_DATA iterate_kbuf;
+
+ if (argv[1]) {
+ static char tmp[1024];
+ sprintf(tmp, "open %s", argv[1]);
+ tok=strtok(tmp," ");
+ open_tdb();
+ }
+
+ while ((line = tdb_getline("tdb> "))) {
+
+ /* Shell command */
+
+ if (line[0] == '!') {
+ system(line + 1);
+ continue;
+ }
+
+ if ((tok = strtok(line," "))==NULL) {
+ if (bIterate)
+ next_record(tdb, &iterate_kbuf);
+ continue;
+ }
+ if (strcmp(tok,"create") == 0) {
+ bIterate = 0;
+ create_tdb();
+ continue;
+ } else if (strcmp(tok,"open") == 0) {
+ open_tdb();
+ continue;
+ } else if ((strcmp(tok, "q") == 0) ||
+ (strcmp(tok, "quit") == 0)) {
+ break;
+ }
+
+ /* all the rest require a open database */
+ if (!tdb) {
+ bIterate = 0;
+ terror("database not open");
+ help();
+ continue;
+ }
+
+ if (strcmp(tok,"insert") == 0) {
+ bIterate = 0;
+ insert_tdb();
+ } else if (strcmp(tok,"store") == 0) {
+ bIterate = 0;
+ store_tdb();
+ } else if (strcmp(tok,"show") == 0) {
+ bIterate = 0;
+ show_tdb();
+ } else if (strcmp(tok,"erase") == 0) {
+ bIterate = 0;
+ tdb_traverse(tdb, do_delete_fn, NULL);
+ } else if (strcmp(tok,"delete") == 0) {
+ bIterate = 0;
+ delete_tdb();
+ } else if (strcmp(tok,"dump") == 0) {
+ bIterate = 0;
+ tdb_traverse(tdb, print_rec, NULL);
+ } else if (strcmp(tok,"list") == 0) {
+ tdb_dump_all(tdb);
+ } else if (strcmp(tok, "free") == 0) {
+ tdb_printfreelist(tdb);
+ } else if (strcmp(tok,"info") == 0) {
+ info_tdb();
+ } else if ( (strcmp(tok, "1") == 0) ||
+ (strcmp(tok, "first") == 0)) {
+ bIterate = 1;
+ first_record(tdb, &iterate_kbuf);
+ } else if ((strcmp(tok, "n") == 0) ||
+ (strcmp(tok, "next") == 0)) {
+ next_record(tdb, &iterate_kbuf);
+ } else if ((strcmp(tok, "keys") == 0)) {
+ bIterate = 0;
+ tdb_traverse(tdb, print_key, NULL);
+ } else {
+ help();
+ }
+ }
+
+ if (tdb) tdb_close(tdb);
+
+ return 0;
+}
diff --git a/source/tdb/tdbtorture.c b/source/tdb/tdbtorture.c
new file mode 100644
index 00000000000..c4d912a1477
--- /dev/null
+++ b/source/tdb/tdbtorture.c
@@ -0,0 +1,216 @@
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include "tdb.h"
+
+/* this tests tdb by doing lots of ops from several simultaneous
+ writers - that stresses the locking code. Build with TDB_DEBUG=1
+ for best effect */
+
+
+
+#define REOPEN_PROB 30
+#define DELETE_PROB 8
+#define STORE_PROB 4
+#define LOCKSTORE_PROB 0
+#define TRAVERSE_PROB 20
+#define CULL_PROB 100
+#define KEYLEN 3
+#define DATALEN 100
+#define LOCKLEN 20
+
+static TDB_CONTEXT *db;
+
+static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+#if 0
+ {
+ char *ptr;
+ asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
+ system(ptr);
+ free(ptr);
+ }
+#endif
+}
+
+static void fatal(char *why)
+{
+ perror(why);
+ exit(1);
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static int cull_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ if (random() % CULL_PROB == 0) {
+ tdb_delete(tdb, key);
+ }
+ return 0;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen, slen;
+ char *k, *d, *s;
+ TDB_DATA key, data, lockkey;
+
+ klen = 1 + (rand() % KEYLEN);
+ dlen = 1 + (rand() % DATALEN);
+ slen = 1 + (rand() % LOCKLEN);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+ s = randbuf(slen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ lockkey.dptr = s;
+ lockkey.dsize = slen+1;
+
+#if REOPEN_PROB
+ if (random() % REOPEN_PROB == 0) {
+ tdb_reopen_all();
+ goto next;
+ }
+#endif
+
+#if DELETE_PROB
+ if (random() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ goto next;
+ }
+#endif
+
+#if STORE_PROB
+ if (random() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ goto next;
+ }
+#endif
+
+#if LOCKSTORE_PROB
+ if (random() % LOCKSTORE_PROB == 0) {
+ tdb_chainlock(db, lockkey);
+ data = tdb_fetch(db, key);
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ if (data.dptr) free(data.dptr);
+ tdb_chainunlock(db, lockkey);
+ goto next;
+ }
+#endif
+
+#if TRAVERSE_PROB
+ if (random() % TRAVERSE_PROB == 0) {
+ tdb_traverse(db, cull_traverse, NULL);
+ goto next;
+ }
+#endif
+
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+
+next:
+ free(k);
+ free(d);
+ free(s);
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+#ifndef NPROC
+#define NPROC 6
+#endif
+
+#ifndef NLOOPS
+#define NLOOPS 200000
+#endif
+
+int main(int argc, char *argv[])
+{
+ int i, seed=0;
+ int loops = NLOOPS;
+ pid_t pids[NPROC];
+
+ pids[0] = getpid();
+
+ for (i=0;i<NPROC-1;i++) {
+ if ((pids[i+1]=fork()) == 0) break;
+ }
+
+ db = tdb_open("torture.tdb", 2, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT, 0600);
+ if (!db) {
+ fatal("db open failed");
+ }
+ tdb_logging_function(db, tdb_log);
+
+ srand(seed + getpid());
+ srandom(seed + getpid() + time(NULL));
+ for (i=0;i<loops;i++) addrec_db();
+
+ tdb_traverse(db, NULL, NULL);
+ tdb_traverse(db, traverse_fn, NULL);
+ tdb_traverse(db, traverse_fn, NULL);
+
+ tdb_close(db);
+
+ if (getpid() == pids[0]) {
+ for (i=0;i<NPROC-1;i++) {
+ int status;
+ if (waitpid(pids[i+1], &status, 0) != pids[i+1]) {
+ printf("failed to wait for %d\n",
+ (int)pids[i+1]);
+ exit(1);
+ }
+ if (WEXITSTATUS(status) != 0) {
+ printf("child %d exited with status %d\n",
+ (int)pids[i+1], WEXITSTATUS(status));
+ exit(1);
+ }
+ }
+ printf("OK\n");
+ }
+
+ return 0;
+}
diff --git a/source/tdb/tdbutil.c b/source/tdb/tdbutil.c
new file mode 100644
index 00000000000..9e24562118f
--- /dev/null
+++ b/source/tdb/tdbutil.c
@@ -0,0 +1,401 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ tdb utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* these are little tdb utility functions that are meant to make
+ dealing with a tdb database a little less cumbersome in Samba */
+
+/****************************************************************************
+ Lock a chain by string.
+****************************************************************************/
+
+int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
+{
+ TDB_DATA key;
+
+ key.dptr = keyval;
+ key.dsize = strlen(keyval)+1;
+
+ return tdb_chainlock(tdb, key);
+}
+
+/****************************************************************************
+ Unlock a chain by string.
+****************************************************************************/
+
+void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
+{
+ TDB_DATA key;
+
+ key.dptr = keyval;
+ key.dsize = strlen(keyval)+1;
+
+ tdb_chainunlock(tdb, key);
+}
+
+/****************************************************************************
+ Fetch a value by a arbitrary blob key, return -1 if not found.
+****************************************************************************/
+
+int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
+{
+ TDB_DATA key, data;
+ int ret;
+
+ key.dptr = keyval;
+ key.dsize = len;
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr || data.dsize != sizeof(int))
+ return -1;
+
+ memcpy(&ret, data.dptr, sizeof(int));
+ free(data.dptr);
+ return ret;
+}
+
+/****************************************************************************
+ Fetch a value by string key, return -1 if not found.
+****************************************************************************/
+
+int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
+{
+ return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
+}
+
+/****************************************************************************
+ Store a value by an arbitary blob key, return 0 on success, -1 on failure.
+****************************************************************************/
+
+int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystr;
+ key.dsize = len;
+ data.dptr = (void *)&v;
+ data.dsize = sizeof(int);
+
+ return tdb_store(tdb, key, data, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Store a value by string key, return 0 on success, -1 on failure.
+****************************************************************************/
+
+int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
+{
+ return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
+}
+
+/****************************************************************************
+ Store a buffer by a null terminated string key. Return 0 on success, -1
+ on failure.
+****************************************************************************/
+
+int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ data.dptr = buffer;
+ data.dsize = len;
+
+ return tdb_store(tdb, key, data, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Fetch a buffer using a null terminated string key. Don't forget to call
+ free() on the result dptr.
+****************************************************************************/
+
+TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
+{
+ TDB_DATA key;
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ return tdb_fetch(tdb, key);
+}
+
+/****************************************************************************
+ Atomic integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+int tdb_change_int_atomic(TDB_CONTEXT *tdb, char *keystr, int *oldval, int change_val)
+{
+ int val;
+ int ret = -1;
+
+ if (tdb_lock_bystring(tdb, keystr) == -1)
+ return -1;
+
+ if ((val = tdb_fetch_int(tdb, keystr)) == -1) {
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST)
+ goto err_out;
+
+ val = *oldval;
+
+ } else {
+ *oldval = val;
+ val += change_val;
+ }
+
+ if (tdb_store_int(tdb, keystr, val) == -1)
+ goto err_out;
+
+ ret = 0;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Useful pair of routines for packing/unpacking data consisting of
+ integers and strings.
+****************************************************************************/
+
+size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
+{
+ va_list ap;
+ uint16 w;
+ uint32 d;
+ int i;
+ void *p;
+ int len;
+ char *s;
+ char c;
+ char *buf0 = buf;
+ char *fmt0 = fmt;
+ int bufsize0 = bufsize;
+
+ va_start(ap, fmt);
+
+ while (*fmt) {
+ switch ((c = *fmt++)) {
+ case 'w':
+ len = 2;
+ w = (uint16)va_arg(ap, int);
+ if (bufsize >= len)
+ SSVAL(buf, 0, w);
+ break;
+ case 'd':
+ len = 4;
+ d = va_arg(ap, uint32);
+ if (bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'p':
+ len = 4;
+ p = va_arg(ap, void *);
+ d = p?1:0;
+ if (bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'P':
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'f':
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'B':
+ i = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ len = 4+i;
+ if (bufsize >= len) {
+ SIVAL(buf, 0, i);
+ memcpy(buf+4, s, i);
+ }
+ break;
+ default:
+ DEBUG(0,("Unknown tdb_pack format %c in %s\n",
+ c, fmt));
+ len = 0;
+ break;
+ }
+
+ buf += len;
+ bufsize -= len;
+ }
+
+ va_end(ap);
+
+ DEBUG(18,("tdb_pack(%s, %d) -> %d\n",
+ fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
+
+ return PTR_DIFF(buf, buf0);
+}
+
+/****************************************************************************
+ Useful pair of routines for packing/unpacking data consisting of
+ integers and strings.
+****************************************************************************/
+
+int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
+{
+ va_list ap;
+ uint16 *w;
+ uint32 *d;
+ int len;
+ int *i;
+ void **p;
+ char *s, **b;
+ char c;
+ char *buf0 = buf;
+ char *fmt0 = fmt;
+ int bufsize0 = bufsize;
+
+ va_start(ap, fmt);
+
+ while (*fmt) {
+ switch ((c=*fmt++)) {
+ case 'w':
+ len = 2;
+ w = va_arg(ap, uint16 *);
+ if (bufsize < len)
+ goto no_space;
+ *w = SVAL(buf, 0);
+ break;
+ case 'd':
+ len = 4;
+ d = va_arg(ap, uint32 *);
+ if (bufsize < len)
+ goto no_space;
+ *d = IVAL(buf, 0);
+ break;
+ case 'p':
+ len = 4;
+ p = va_arg(ap, void **);
+ if (bufsize < len)
+ goto no_space;
+ *p = (void *)IVAL(buf, 0);
+ break;
+ case 'P':
+ s = va_arg(ap,char *);
+ len = strlen(buf) + 1;
+ if (bufsize < len || len > sizeof(pstring))
+ goto no_space;
+ memcpy(s, buf, len);
+ break;
+ case 'f':
+ s = va_arg(ap,char *);
+ len = strlen(buf) + 1;
+ if (bufsize < len || len > sizeof(fstring))
+ goto no_space;
+ memcpy(s, buf, len);
+ break;
+ case 'B':
+ i = va_arg(ap, int *);
+ b = va_arg(ap, char **);
+ len = 4;
+ if (bufsize < len)
+ goto no_space;
+ *i = IVAL(buf, 0);
+ if (! *i) {
+ *b = NULL;
+ break;
+ }
+ len += *i;
+ if (bufsize < len)
+ goto no_space;
+ *b = (char *)malloc(*i);
+ if (! *b)
+ goto no_space;
+ memcpy(*b, buf+4, *i);
+ break;
+ default:
+ DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
+ c, fmt));
+
+ len = 0;
+ break;
+ }
+
+ buf += len;
+ bufsize -= len;
+ }
+
+ va_end(ap);
+
+ DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
+ fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
+
+ return PTR_DIFF(buf, buf0);
+
+ no_space:
+ return -1;
+}
+
+/****************************************************************************
+ Log tdb messages via DEBUG().
+****************************************************************************/
+
+static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+{
+ va_list ap;
+ char *ptr = NULL;
+
+ va_start(ap, format);
+ vasprintf(&ptr, format, ap);
+ va_end(ap);
+
+ if (!ptr || !*ptr)
+ return;
+
+ DEBUG(level, ("tdb(%s): %s", tdb->name, ptr));
+ free(ptr);
+}
+
+/****************************************************************************
+ Like tdb_open() but also setup a logging function that redirects to
+ the samba DEBUG() system.
+****************************************************************************/
+
+TDB_CONTEXT *tdb_open_log(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ TDB_CONTEXT *tdb;
+
+ if (!lp_use_mmap())
+ tdb_flags |= TDB_NOMMAP;
+
+ tdb = tdb_open(name, hash_size, tdb_flags,
+ open_flags, mode);
+ if (!tdb)
+ return NULL;
+
+ tdb_logging_function(tdb, tdb_log);
+
+ return tdb;
+}
diff --git a/source/tests/.cvsignore b/source/tests/.cvsignore
new file mode 100644
index 00000000000..b6c1f01120e
--- /dev/null
+++ b/source/tests/.cvsignore
@@ -0,0 +1 @@
+unixsock
diff --git a/source/tests/README b/source/tests/README
new file mode 100644
index 00000000000..cf1be8b00a7
--- /dev/null
+++ b/source/tests/README
@@ -0,0 +1,10 @@
+This directory contains autoconf test programs that are too large to
+comfortably fit in configure.in.
+
+These programs should test one feature of the OS and exit(0) if it
+works or exit(1) if it doesn't work (do _not_ use return)
+
+The programs should be kept simple and to the point. Beautiful/fast
+code is not necessary
+
+
diff --git a/source/tests/crypttest.c b/source/tests/crypttest.c
new file mode 100644
index 00000000000..efee2e593d4
--- /dev/null
+++ b/source/tests/crypttest.c
@@ -0,0 +1,852 @@
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#if !defined(HAVE_CRYPT)
+
+/*
+ This bit of code was derived from the UFC-crypt package which
+ carries the following copyright
+
+ Modified for use by Samba by Andrew Tridgell, October 1994
+
+ Note that this routine is only faster on some machines. Under Linux 1.1.51
+ libc 4.5.26 I actually found this routine to be slightly slower.
+
+ Under SunOS I found a huge speedup by using these routines
+ (a factor of 20 or so)
+
+ Warning: I've had a report from Steve Kennedy <steve@gbnet.org>
+ that this crypt routine may sometimes get the wrong answer. Only
+ use UFC_CRYT if you really need it.
+
+*/
+
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991-1998, Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * @(#)crypt_util.c 2.31 02/08/92
+ *
+ * Support routines
+ *
+ */
+
+
+#ifndef long32
+#if (SIZEOF_INT == 4)
+#define long32 int
+#elif (SIZEOF_LONG == 4)
+#define long32 long
+#elif (SIZEOF_SHORT == 4)
+#define long32 short
+#else
+/* uggh - no 32 bit type?? probably a CRAY. just hope this works ... */
+#define long32 int
+#endif
+#endif
+
+#ifndef long64
+#ifdef HAVE_LONGLONG
+#define long64 long long long
+#endif
+#endif
+
+#ifndef ufc_long
+#define ufc_long unsigned
+#endif
+
+#ifndef _UFC_64_
+#define _UFC_32_
+#endif
+
+/*
+ * Permutation done once on the 56 bit
+ * key derived from the original 8 byte ASCII key.
+ */
+static int pc1[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+/*
+ * How much to rotate each 28 bit half of the pc1 permutated
+ * 56 bit key before using pc2 to give the i' key
+ */
+static int rots[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+/*
+ * Permutation giving the key
+ * of the i' DES round
+ */
+static int pc2[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * The E expansion table which selects
+ * bits from the 32 bit intermediate result.
+ */
+static int esel[48] = {
+ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
+};
+static int e_inverse[64];
+
+/*
+ * Permutation done on the
+ * result of sbox lookups
+ */
+static int perm32[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+/*
+ * The sboxes
+ */
+static int sbox[8][4][16]= {
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
+ },
+
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
+ },
+
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
+ },
+
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
+ },
+
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
+ },
+
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
+ },
+
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
+ },
+
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
+ }
+};
+
+/*
+ * This is the final
+ * permutation matrix
+ */
+static int final_perm[64] = {
+ 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/*
+ * The 16 DES keys in BITMASK format
+ */
+#ifdef _UFC_32_
+long32 _ufc_keytab[16][2];
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_keytab[16];
+#endif
+
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+/* Macro to set a bit (0..23) */
+#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) )
+
+/*
+ * sb arrays:
+ *
+ * Workhorses of the inner loop of the DES implementation.
+ * They do sbox lookup, shifting of this value, 32 bit
+ * permutation and E permutation for the next round.
+ *
+ * Kept in 'BITMASK' format.
+ */
+
+#ifdef _UFC_32_
+long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192];
+static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096];
+static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+/*
+ * eperm32tab: do 32 bit permutation and E selection
+ *
+ * The first index is the byte number in the 32 bit value to be permuted
+ * - second - is the value of this byte
+ * - third - selects the two 32 bit values
+ *
+ * The table is used and generated internally in init_des to speed it up
+ */
+static ufc_long eperm32tab[4][256][2];
+
+/*
+ * do_pc1: permform pc1 permutation in the key schedule generation.
+ *
+ * The first index is the byte number in the 8 byte ASCII key
+ * - second - - the two 28 bits halfs of the result
+ * - third - selects the 7 bits actually used of each byte
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc1[8][2][128];
+
+/*
+ * do_pc2: permform pc2 permutation in the key schedule generation.
+ *
+ * The first index is the septet number in the two 28 bit intermediate values
+ * - second - - - septet values
+ *
+ * Knowledge of the structure of the pc2 permutation is used.
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc2[8][128];
+
+/*
+ * efp: undo an extra e selection and do final
+ * permutation giving the DES result.
+ *
+ * Invoked 6 bit a time on two 48 bit values
+ * giving two 32 bit longs.
+ */
+static ufc_long efp[16][64][2];
+
+static unsigned char bytemask[8] = {
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static ufc_long longmask[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+
+/*
+ * Silly rewrite of 'bzero'. I do so
+ * because some machines don't have
+ * bzero and some don't have memset.
+ */
+
+static void clearmem(char *start, int cnt)
+ { while(cnt--)
+ *start++ = '\0';
+ }
+
+static int initialized = 0;
+
+/* lookup a 6 bit value in sbox */
+
+#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
+
+/*
+ * Initialize unit - may be invoked directly
+ * by fcrypt users.
+ */
+
+static void ufc_init_des(void)
+ { int comes_from_bit;
+ int bit, sg;
+ ufc_long j;
+ ufc_long mask1, mask2;
+
+ /*
+ * Create the do_pc1 table used
+ * to affect pc1 permutation
+ * when generating keys
+ */
+ for(bit = 0; bit < 56; bit++) {
+ comes_from_bit = pc1[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 8 + 1];
+ mask2 = longmask[bit % 28 + 4];
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
+ }
+ }
+
+ /*
+ * Create the do_pc2 table used
+ * to affect pc2 permutation when
+ * generating keys
+ */
+ for(bit = 0; bit < 48; bit++) {
+ comes_from_bit = pc2[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 7 + 1];
+ mask2 = BITMASK(bit % 24);
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc2[comes_from_bit / 7][j] |= mask2;
+ }
+ }
+
+ /*
+ * Now generate the table used to do combined
+ * 32 bit permutation and e expansion
+ *
+ * We use it because we have to permute 16384 32 bit
+ * longs into 48 bit in order to initialize sb.
+ *
+ * Looping 48 rounds per permutation becomes
+ * just too slow...
+ *
+ */
+
+ clearmem((char*)eperm32tab, sizeof(eperm32tab));
+
+ for(bit = 0; bit < 48; bit++) {
+ ufc_long inner_mask1,comes_from;
+
+ comes_from = perm32[esel[bit]-1]-1;
+ inner_mask1 = bytemask[comes_from % 8];
+
+ for(j = 256; j--;) {
+ if(j & inner_mask1)
+ eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
+ }
+ }
+
+ /*
+ * Create the sb tables:
+ *
+ * For each 12 bit segment of an 48 bit intermediate
+ * result, the sb table precomputes the two 4 bit
+ * values of the sbox lookups done with the two 6
+ * bit halves, shifts them to their proper place,
+ * sends them through perm32 and finally E expands
+ * them so that they are ready for the next
+ * DES round.
+ *
+ */
+ for(sg = 0; sg < 4; sg++) {
+ int j1, j2;
+ int s1, s2;
+
+ for(j1 = 0; j1 < 64; j1++) {
+ s1 = s_lookup(2 * sg, j1);
+ for(j2 = 0; j2 < 64; j2++) {
+ ufc_long to_permute, inx;
+
+ s2 = s_lookup(2 * sg + 1, j2);
+ to_permute = ((s1 << 4) | s2) << (24 - 8 * sg);
+
+#ifdef _UFC_32_
+ inx = ((j1 << 6) | j2) << 1;
+ sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0];
+ sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+#ifdef _UFC_64_
+ inx = ((j1 << 6) | j2);
+ sb[sg][inx] =
+ ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
+ (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
+ (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) |
+ (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) |
+ (long64)eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+ }
+ }
+ }
+
+ /*
+ * Create an inverse matrix for esel telling
+ * where to plug out bits if undoing it
+ */
+ for(bit=48; bit--;) {
+ e_inverse[esel[bit] - 1 ] = bit;
+ e_inverse[esel[bit] - 1 + 32] = bit + 48;
+ }
+
+ /*
+ * create efp: the matrix used to
+ * undo the E expansion and effect final permutation
+ */
+ clearmem((char*)efp, sizeof efp);
+ for(bit = 0; bit < 64; bit++) {
+ int o_bit, o_long;
+ ufc_long word_value, inner_mask1, inner_mask2;
+ int comes_from_f_bit, comes_from_e_bit;
+ int comes_from_word, bit_within_word;
+
+ /* See where bit i belongs in the two 32 bit long's */
+ o_long = bit / 32; /* 0..1 */
+ o_bit = bit % 32; /* 0..31 */
+
+ /*
+ * And find a bit in the e permutated value setting this bit.
+ *
+ * Note: the e selection may have selected the same bit several
+ * times. By the initialization of e_inverse, we only look
+ * for one specific instance.
+ */
+ comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */
+ comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
+ comes_from_word = comes_from_e_bit / 6; /* 0..15 */
+ bit_within_word = comes_from_e_bit % 6; /* 0..5 */
+
+ inner_mask1 = longmask[bit_within_word + 26];
+ inner_mask2 = longmask[o_bit];
+
+ for(word_value = 64; word_value--;) {
+ if(word_value & inner_mask1)
+ efp[comes_from_word][word_value][o_long] |= inner_mask2;
+ }
+ }
+ initialized++;
+ }
+
+/*
+ * Process the elements of the sb table permuting the
+ * bits swapped in the expansion by the current salt.
+ */
+
+#ifdef _UFC_32_
+static void shuffle_sb(long32 *k, ufc_long saltbits)
+ { ufc_long j;
+ long32 x;
+ for(j=4096; j--;) {
+ x = (k[0] ^ k[1]) & (long32)saltbits;
+ *k++ ^= x;
+ *k++ ^= x;
+ }
+ }
+#endif
+
+#ifdef _UFC_64_
+static void shuffle_sb(long64 *k, ufc_long saltbits)
+ { ufc_long j;
+ long64 x;
+ for(j=4096; j--;) {
+ x = ((*k >> 32) ^ *k) & (long64)saltbits;
+ *k++ ^= (x << 32) | x;
+ }
+ }
+#endif
+
+/*
+ * Setup the unit for a new salt
+ * Hopefully we'll not see a new salt in each crypt call.
+ */
+
+static unsigned char current_salt[3] = "&&"; /* invalid value */
+static ufc_long current_saltbits = 0;
+static int direction = 0;
+
+static void setup_salt(const char *s1)
+ { ufc_long i, j, saltbits;
+ const unsigned char *s2 = (const unsigned char *)s1;
+
+ if(!initialized)
+ ufc_init_des();
+
+ if(s2[0] == current_salt[0] && s2[1] == current_salt[1])
+ return;
+ current_salt[0] = s2[0]; current_salt[1] = s2[1];
+
+ /*
+ * This is the only crypt change to DES:
+ * entries are swapped in the expansion table
+ * according to the bits set in the salt.
+ */
+ saltbits = 0;
+ for(i = 0; i < 2; i++) {
+ long c=ascii_to_bin(s2[i]);
+ if(c < 0 || c > 63)
+ c = 0;
+ for(j = 0; j < 6; j++) {
+ if((c >> j) & 0x1)
+ saltbits |= BITMASK(6 * i + j);
+ }
+ }
+
+ /*
+ * Permute the sb table values
+ * to reflect the changed e
+ * selection table
+ */
+ shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits);
+
+ current_saltbits = saltbits;
+ }
+
+static void ufc_mk_keytab(char *key)
+ { ufc_long v1, v2, *k1;
+ int i;
+#ifdef _UFC_32_
+ long32 v, *k2 = &_ufc_keytab[0][0];
+#endif
+#ifdef _UFC_64_
+ long64 v, *k2 = &_ufc_keytab[0];
+#endif
+
+ v1 = v2 = 0; k1 = &do_pc1[0][0][0];
+ for(i = 8; i--;) {
+ v1 |= k1[*key & 0x7f]; k1 += 128;
+ v2 |= k1[*key++ & 0x7f]; k1 += 128;
+ }
+
+ for(i = 0; i < 16; i++) {
+ k1 = &do_pc2[0][0];
+
+ v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
+ v = k1[(v1 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v1 ) & 0x7f]; k1 += 128;
+
+#ifdef _UFC_32_
+ *k2++ = v;
+ v = 0;
+#endif
+#ifdef _UFC_64_
+ v <<= 32;
+#endif
+
+ v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
+ v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v2 ) & 0x7f];
+
+ *k2++ = v;
+ }
+
+ direction = 0;
+ }
+
+/*
+ * Undo an extra E selection and do final permutations
+ */
+
+ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
+ { ufc_long v1, v2, x;
+ static ufc_long ary[2];
+
+ x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x;
+ x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x;
+
+ v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
+
+ v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
+ v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
+ v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
+ v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
+
+ v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
+ v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
+ v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
+ v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
+
+ v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
+ v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
+ v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
+ v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
+
+ v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
+ v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
+ v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
+ v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
+
+ ary[0] = v1; ary[1] = v2;
+ return ary;
+ }
+
+/*
+ * crypt only: convert from 64 bit to 11 bit ASCII
+ * prefixing with the salt
+ */
+
+static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
+ { static char outbuf[14];
+ int i, s;
+
+ outbuf[0] = salt[0];
+ outbuf[1] = salt[1] ? salt[1] : salt[0];
+
+ for(i = 0; i < 5; i++)
+ outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f);
+
+ s = (v2 & 0xf) << 2;
+ v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
+
+ for(i = 5; i < 10; i++)
+ outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f);
+
+ outbuf[12] = bin_to_ascii(s);
+ outbuf[13] = 0;
+
+ return outbuf;
+ }
+
+/*
+ * UNIX crypt function
+ */
+
+static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
+
+char *ufc_crypt(const char *key,const char *salt)
+ { ufc_long *s;
+ char ktab[9];
+
+ /*
+ * Hack DES tables according to salt
+ */
+ setup_salt(salt);
+
+ /*
+ * Setup key schedule
+ */
+ clearmem(ktab, sizeof ktab);
+ strncpy(ktab, key, 8);
+ ufc_mk_keytab(ktab);
+
+ /*
+ * Go for the 25 DES encryptions
+ */
+ s = _ufc_doit((ufc_long)0, (ufc_long)0,
+ (ufc_long)0, (ufc_long)0, (ufc_long)25);
+
+ /*
+ * And convert back to 6 bit ASCII
+ */
+ return output_conversion(s[0], s[1], salt);
+ }
+
+
+#ifdef _UFC_32_
+
+/*
+ * 32 bit version
+ */
+
+extern long32 _ufc_keytab[16][2];
+extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long32 s, *k;
+
+ while(itr--) {
+ k = &_ufc_keytab[0][0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r1;
+ l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ r2;
+ l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4);
+
+ s = *k++ ^ l1;
+ r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ l2;
+ r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4);
+ }
+ s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
+ }
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#ifdef _UFC_64_
+
+/*
+ * 64 bit version
+ */
+
+extern long64 _ufc_keytab[16];
+extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
+
+#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
+
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
+ { int i;
+ long64 l, r, s, *k;
+
+ l = (((long64)l1) << 32) | ((long64)l2);
+ r = (((long64)r1) << 32) | ((long64)r2);
+
+ while(itr--) {
+ k = &_ufc_keytab[0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r;
+ l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+
+ s = *k++ ^ l;
+ r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+ }
+ s=l; l=r; r=s;
+ }
+
+ l1 = l >> 32; l2 = l & 0xffffffff;
+ r1 = r >> 32; r2 = r & 0xffffffff;
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#define crypt ufc_crypt
+#endif
+
+main()
+{
+ char passwd[9];
+ char salt[9];
+ char c_out1[256];
+ char c_out2[256];
+
+ char expected_out[14];
+
+ strcpy(expected_out, "12yJ.Of/NQ.Pk");
+ strcpy(passwd, "12345678");
+ strcpy(salt, "12345678");
+
+ strcpy(c_out1, crypt(passwd, salt));
+ salt[2] = '\0';
+ strcpy(c_out2, crypt(passwd, salt));
+
+ /*
+ * If the non-trucated salt fails but the
+ * truncated salt succeeds then exit 1.
+ */
+
+ if((strcmp(c_out1, expected_out) != 0) &&
+ (strcmp(c_out2, expected_out) == 0))
+ exit(1);
+
+#ifdef HAVE_BIGCRYPT
+ /*
+ * Try the same with bigcrypt...
+ */
+
+ {
+ char big_passwd[17];
+ char big_salt[17];
+ char big_c_out1[256];
+ char big_c_out2[256];
+ char big_expected_out[27];
+
+ strcpy(big_passwd, "1234567812345678");
+ strcpy(big_salt, "1234567812345678");
+ strcpy(big_expected_out, "12yJ.Of/NQ.PklfyCuHi/rwM");
+
+ strcpy(big_c_out1, bigcrypt(big_passwd, big_salt));
+ big_salt[2] = '\0';
+ strcpy(big_c_out2, bigcrypt(big_passwd, big_salt));
+
+ /*
+ * If the non-trucated salt fails but the
+ * truncated salt succeeds then exit 1.
+ */
+
+ if((strcmp(big_c_out1, big_expected_out) != 0) &&
+ (strcmp(big_c_out2, big_expected_out) == 0))
+ exit(1);
+
+ }
+#endif
+
+ exit(0);
+}
diff --git a/source/tests/fcntl_lock.c b/source/tests/fcntl_lock.c
new file mode 100644
index 00000000000..3dc12a38973
--- /dev/null
+++ b/source/tests/fcntl_lock.c
@@ -0,0 +1,121 @@
+/* test whether fcntl locking works on this system */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <errno.h>
+
+static int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* USE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* USE_WAITPID */
+}
+
+#define DATA "conftest.fcntl"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* lock a byte range in a open file */
+int main(int argc, char *argv[])
+{
+ struct flock lock;
+ int fd, ret, status=1;
+ pid_t pid;
+ char *testdir = NULL;
+
+ testdir = getenv("TESTDIR");
+ if (testdir) chdir(testdir);
+
+ alarm(10);
+
+ if (!(pid=fork())) {
+ sleep(2);
+ fd = open(DATA, O_RDONLY);
+
+ if (fd == -1) {
+ fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n",
+ DATA, (int)errno);
+ exit(1);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ lock.l_type = F_WRLCK;
+
+ /* check if a lock applies */
+ ret = fcntl(fd,F_GETLK,&lock);
+
+ if ((ret == -1) ||
+ (lock.l_type == F_UNLCK)) {
+ fprintf(stderr,"ERROR: lock test failed (ret=%d errno=%d)\n", ret, (int)errno);
+ exit(1);
+ } else {
+ exit(0);
+ }
+ }
+
+ unlink(DATA);
+ fd = open(DATA, O_RDWR|O_CREAT|O_EXCL, 0600);
+
+ if (fd == -1) {
+ fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n",
+ DATA, (int)errno);
+ exit(1);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ /* set a 4 byte write lock */
+ fcntl(fd,F_SETLK,&lock);
+
+ sys_waitpid(pid, &status, 0);
+
+ unlink(DATA);
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ } else {
+ status = 1;
+ }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+ status = (status == 0) ? 0 : 1;
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+ if (status) {
+ fprintf(stderr,"ERROR: lock test failed with status=%d\n",
+ status);
+ }
+
+ exit(status);
+}
diff --git a/source/tests/fcntl_lock64.c b/source/tests/fcntl_lock64.c
new file mode 100644
index 00000000000..e5ecd88fd04
--- /dev/null
+++ b/source/tests/fcntl_lock64.c
@@ -0,0 +1,96 @@
+/* test whether 64 bit fcntl locking really works on this system */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+
+#include <errno.h>
+
+static int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* USE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* USE_WAITPID */
+}
+
+#define DATA "conftest.fcntl64"
+
+/* lock a byte range in a open file */
+int main(int argc, char *argv[])
+{
+ struct flock64 lock;
+ int fd, ret, status=1;
+ pid_t pid;
+
+ if (!(pid=fork())) {
+ sleep(2);
+ fd = open64(DATA, O_RDONLY);
+
+ if (fd == -1) exit(1);
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ lock.l_type = F_WRLCK;
+
+ /* check if a lock applies */
+ ret = fcntl(fd,F_GETLK64,&lock);
+
+ if ((ret == -1) ||
+ (lock.l_type == F_UNLCK)) {
+/* printf("No lock conflict\n"); */
+ exit(1);
+ } else {
+/* printf("lock conflict\n"); */
+ exit(0);
+ }
+ }
+
+ fd = open64(DATA, O_RDWR|O_CREAT|O_TRUNC, 0600);
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+#if defined(COMPILER_SUPPORTS_LL)
+ lock.l_start = 0x100000000LL;
+#else
+ lock.l_start = 0x100000000;
+#endif
+ lock.l_len = 4;
+ lock.l_pid = getpid();
+
+ /* set a 4 byte write lock */
+ fcntl(fd,F_SETLK64,&lock);
+
+ sys_waitpid(pid, &status, 0);
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ } else {
+ status = 1;
+ }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+ status = (status == 0) ? 0 : 1;
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+ unlink(DATA);
+
+ exit(status);
+}
diff --git a/source/tests/ftruncate.c b/source/tests/ftruncate.c
new file mode 100644
index 00000000000..93282782eed
--- /dev/null
+++ b/source/tests/ftruncate.c
@@ -0,0 +1,27 @@
+/* test whether ftruncte() can extend a file */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.trunc"
+#define LEN 7663
+
+main()
+{
+ int *buf;
+ int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+
+ ftruncate(fd, LEN);
+
+ unlink(DATA);
+
+ if (lseek(fd, 0, SEEK_END) == LEN) {
+ exit(0);
+ }
+ exit(1);
+}
diff --git a/source/tests/getgroups.c b/source/tests/getgroups.c
new file mode 100644
index 00000000000..343fd5a184f
--- /dev/null
+++ b/source/tests/getgroups.c
@@ -0,0 +1,66 @@
+/* this tests whether getgroups actually returns lists of integers
+ rather than gid_t. The test only works if the user running
+ the test is in at least 1 group
+
+ The test is designed to check for those broken OSes that define
+ getgroups() as returning an array of gid_t but actually return a
+ array of ints! Ultrix is one culprit
+ */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <grp.h>
+
+main()
+{
+ int i;
+ int *igroups;
+ char *cgroups;
+ int grp = 0;
+ int ngroups = getgroups(0,&grp);
+
+ if (sizeof(gid_t) == sizeof(int)) {
+ fprintf(stderr,"gid_t and int are the same size\n");
+ exit(1);
+ }
+
+ if (ngroups <= 0)
+ ngroups = 32;
+
+ igroups = (int *)malloc(sizeof(int)*ngroups);
+
+ for (i=0;i<ngroups;i++)
+ igroups[i] = 0x42424242;
+
+ ngroups = getgroups(ngroups,(gid_t *)igroups);
+
+ if (igroups[0] == 0x42424242)
+ ngroups = 0;
+
+ if (ngroups == 0) {
+ printf("WARNING: can't determine getgroups return type\n");
+ exit(1);
+ }
+
+ cgroups = (char *)igroups;
+
+ if (ngroups == 1 &&
+ cgroups[2] == 0x42 && cgroups[3] == 0x42) {
+ fprintf(stderr,"getgroups returns gid_t\n");
+ exit(1);
+ }
+
+ for (i=0;i<ngroups;i++) {
+ if (igroups[i] == 0x42424242) {
+ fprintf(stderr,"getgroups returns gid_t\n");
+ exit(1);
+ }
+ }
+
+ exit(0);
+}
diff --git a/source/tests/shared_mmap.c b/source/tests/shared_mmap.c
new file mode 100644
index 00000000000..fcef75d0d61
--- /dev/null
+++ b/source/tests/shared_mmap.c
@@ -0,0 +1,68 @@
+/* this tests whether we can use a shared writeable mmap on a file -
+ as needed for the mmap varient of FAST_SHARE_MODES */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.mmap"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+main()
+{
+ int *buf;
+ int i;
+ int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+ int count=7;
+
+ if (fd == -1) exit(1);
+
+ for (i=0;i<10000;i++) {
+ write(fd,&i,sizeof(i));
+ }
+
+ close(fd);
+
+ if (fork() == 0) {
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ while (count-- && buf[9124] != 55732) sleep(1);
+
+ if (count <= 0) exit(1);
+
+ buf[1763] = 7268;
+ exit(0);
+ }
+
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ if (buf == (int *)-1) exit(1);
+
+ buf[9124] = 55732;
+
+ while (count-- && buf[1763] != 7268) sleep(1);
+
+ unlink(DATA);
+
+ if (count > 0) exit(0);
+ exit(1);
+}
diff --git a/source/tests/summary.c b/source/tests/summary.c
new file mode 100644
index 00000000000..79a530b0136
--- /dev/null
+++ b/source/tests/summary.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+main()
+{
+#if !(defined(HAVE_FCNTL_LOCK) || defined(HAVE_STRUCT_FLOCK64))
+ printf("ERROR: No locking available. Running Samba would be unsafe\n");
+ exit(1);
+#endif
+
+#if !(defined(HAVE_IFACE_IFCONF) || defined(HAVE_IFACE_IFREQ) || defined(HAVE_IFACE_AIX))
+ printf("WARNING: No automated network interface determination\n");
+#endif
+
+#if !(defined(USE_SETEUID) || defined(USE_SETREUID) || defined(USE_SETRESUID) || defined(USE_SETUIDX))
+ printf("ERROR: no seteuid method available\n");
+ exit(1);
+#endif
+
+#if !(defined(STAT_STATVFS) || defined(STAT_STATVFS64) || defined(STAT_STATFS3_OSF1) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS4) || defined(STAT_STATFS2_FSIZE) || defined(STAT_STATFS2_FS_DATA))
+ printf("ERROR: No disk free routine!\n");
+ exit(1);
+#endif
+
+#if !((defined(HAVE_RANDOM) || defined(HAVE_RAND)) && (defined(HAVE_SRANDOM) || defined(HAVE_SRAND)))
+ printf("ERROR: No random or srandom routine!\n");
+ exit(1);
+#endif
+
+ exit(0);
+}
diff --git a/source/tests/trivial.c b/source/tests/trivial.c
new file mode 100644
index 00000000000..2723637a0ff
--- /dev/null
+++ b/source/tests/trivial.c
@@ -0,0 +1,4 @@
+main()
+{
+ exit(0);
+}
diff --git a/source/tests/unixsock.c b/source/tests/unixsock.c
new file mode 100644
index 00000000000..f2765d68f67
--- /dev/null
+++ b/source/tests/unixsock.c
@@ -0,0 +1,93 @@
+/* -*- c-file-style: "linux" -*-
+ *
+ * Try creating a Unix-domain socket, opening it, and reading from it.
+ * The POSIX name for these is AF_LOCAL/PF_LOCAL.
+ *
+ * This is used by the Samba autoconf scripts to detect systems which
+ * don't have Unix-domain sockets, such as (probably) VMS, or systems
+ * on which they are broken under some conditions, such as RedHat 7.0
+ * (unpatched). We can't build WinBind there at the moment.
+ *
+ * Coding standard says to always use exit() for this, not return, so
+ * we do.
+ *
+ * Martin Pool <mbp@samba.org>, June 2000. */
+
+/* TODO: Look for AF_LOCAL (most standard), AF_UNIX, and AF_FILE. */
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#if HAVE_ERRNO_DECL
+# include <errno.h>
+#else
+extern int errno;
+#endif
+
+static int bind_socket(char const *filename)
+{
+ int sock_fd;
+ struct sockaddr_un name;
+ size_t size;
+
+ /* Create the socket. */
+ if ((sock_fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ perror ("socket(PF_LOCAL, SOCK_STREAM)");
+ exit(1);
+ }
+
+ /* Bind a name to the socket. */
+ name.sun_family = AF_LOCAL;
+ strncpy(name.sun_path, filename, sizeof (name.sun_path));
+
+ /* The size of the address is
+ the offset of the start of the filename,
+ plus its length,
+ plus one for the terminating null byte.
+ Alternatively you can just do:
+ size = SUN_LEN (&name);
+ */
+ size = SUN_LEN(&name);
+ /* XXX: This probably won't work on unfriendly libcs */
+
+ if (bind(sock_fd, (struct sockaddr *) &name, size) < 0) {
+ perror ("bind");
+ exit(1);
+ }
+
+ return sock_fd;
+}
+
+
+int main(void)
+{
+ int sock_fd;
+ int kid;
+ char const *filename = "conftest.unixsock.sock";
+
+ /* abolish hanging */
+ alarm(15); /* secs */
+
+ if ((sock_fd = bind_socket(filename)) < 0)
+ exit(1);
+
+ /* the socket will be deleted when autoconf cleans up these
+ files. */
+
+ exit(0);
+}
diff --git a/source/torture/denytest.c b/source/torture/denytest.c
new file mode 100644
index 00000000000..a19b0347676
--- /dev/null
+++ b/source/torture/denytest.c
@@ -0,0 +1,1567 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ SMB torture tester - scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+extern BOOL torture_showall;
+
+enum deny_result {A_0=0, A_X=1, A_R=2, A_W=3, A_RW=5};
+
+
+static char *denystr(int denymode)
+{
+ struct {
+ int v;
+ char *name;
+ } deny_modes[] = {
+ {DENY_DOS, "DENY_DOS"},
+ {DENY_ALL, "DENY_ALL"},
+ {DENY_WRITE, "DENY_WRITE"},
+ {DENY_READ, "DENY_READ"},
+ {DENY_NONE, "DENY_NONE"},
+ {DENY_FCB, "DENY_FCB"},
+ {-1, NULL}};
+ int i;
+ for (i=0;deny_modes[i].name;i++) {
+ if (deny_modes[i].v == denymode) return deny_modes[i].name;
+ }
+ return "DENY_XXX";
+}
+
+static char *openstr(int mode)
+{
+ struct {
+ int v;
+ char *name;
+ } open_modes[] = {
+ {O_RDWR, "O_RDWR"},
+ {O_RDONLY, "O_RDONLY"},
+ {O_WRONLY, "O_WRONLY"},
+ {-1, NULL}};
+ int i;
+ for (i=0;open_modes[i].name;i++) {
+ if (open_modes[i].v == mode) return open_modes[i].name;
+ }
+ return "O_XXX";
+}
+
+static char *resultstr(enum deny_result res)
+{
+ struct {
+ enum deny_result res;
+ char *name;
+ } results[] = {
+ {A_X, "X"},
+ {A_0, "-"},
+ {A_R, "R"},
+ {A_W, "W"},
+ {A_RW,"RW"}};
+ int i;
+ for (i=0;ARRAY_SIZE(results);i++) {
+ if (results[i].res == res) return results[i].name;
+ }
+ return "*";
+}
+
+static struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable2[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0}
+};
+
+
+static struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable1[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW}
+};
+
+
+/*
+ this produces a matrix of deny mode behaviour for 1 connection
+ */
+BOOL torture_denytest1(int dummy)
+{
+ static struct cli_state cli1;
+ int fnum1, fnum2;
+ int i;
+ BOOL correct = True;
+ char *fnames[2] = {"\\denytest1.dat", "\\denytest1.exe"};
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+
+ printf("starting denytest1\n");
+
+ for (i=0;i<2;i++) {
+ cli_unlink(&cli1, fnames[i]);
+ fnum1 = cli_open(&cli1, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(&cli1, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ cli_close(&cli1, fnum1);
+ }
+
+ printf("testing %d entries\n", ARRAY_SIZE(denytable1));
+
+ for (i=0; i<ARRAY_SIZE(denytable1); i++) {
+ enum deny_result res;
+ char *fname = fnames[denytable1[i].isexe];
+
+ fnum1 = cli_open(&cli1, fname,
+ denytable1[i].mode1,
+ denytable1[i].deny1);
+ fnum2 = cli_open(&cli1, fname,
+ denytable1[i].mode2,
+ denytable1[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ char x = 1;
+ res = A_0;
+ if (cli_read(&cli1, fnum2, (void *)&x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (cli_write(&cli1, fnum2, 0, (void *)&x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (res != denytable1[i].result) {
+ correct = False;
+ }
+
+ if (torture_showall || res != denytable1[i].result) {
+ printf("%s %8s %10s %8s %10s %s (correct=%s)\n",
+ fname,
+ denystr(denytable1[i].deny1),
+ openstr(denytable1[i].mode1),
+ denystr(denytable1[i].deny2),
+ openstr(denytable1[i].mode2),
+ resultstr(res),
+ resultstr(denytable1[i].result));
+ }
+
+ cli_close(&cli1, fnum1);
+ cli_close(&cli1, fnum2);
+ }
+
+ for (i=0;i<2;i++) {
+ cli_unlink(&cli1, fnames[i]);
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+
+ printf("finshed denytest1\n");
+ return correct;
+}
+
+
+/*
+ this produces a matrix of deny mode behaviour with 2 connections
+ */
+BOOL torture_denytest2(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ int fnum1, fnum2;
+ int i;
+ BOOL correct = True;
+ char *fnames[2] = {"\\denytest2.dat", "\\denytest2.exe"};
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+
+ printf("starting denytest2\n");
+
+ for (i=0;i<2;i++) {
+ cli_unlink(&cli1, fnames[i]);
+ fnum1 = cli_open(&cli1, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(&cli1, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ cli_close(&cli1, fnum1);
+ }
+
+ for (i=0; i<ARRAY_SIZE(denytable2); i++) {
+ enum deny_result res;
+ char *fname = fnames[denytable2[i].isexe];
+
+ fnum1 = cli_open(&cli1, fname,
+ denytable2[i].mode1,
+ denytable2[i].deny1);
+ fnum2 = cli_open(&cli2, fname,
+ denytable2[i].mode2,
+ denytable2[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ char x = 1;
+ res = A_0;
+ if (cli_read(&cli2, fnum2, (void *)&x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (cli_write(&cli2, fnum2, 0, (void *)&x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (res != denytable2[i].result) {
+ correct = False;
+ }
+
+ if (torture_showall || res != denytable2[i].result) {
+ printf("%s %8s %10s %8s %10s %s (correct=%s)\n",
+ fname,
+ denystr(denytable2[i].deny1),
+ openstr(denytable2[i].mode1),
+ denystr(denytable2[i].deny2),
+ openstr(denytable2[i].mode2),
+ resultstr(res),
+ resultstr(denytable2[i].result));
+ }
+
+ cli_close(&cli1, fnum1);
+ cli_close(&cli2, fnum2);
+ }
+
+ for (i=0;i<2;i++) {
+ cli_unlink(&cli1, fnames[i]);
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(&cli2)) {
+ correct = False;
+ }
+
+ printf("finshed denytest2\n");
+ return correct;
+}
+
diff --git a/source/torture/locktest.c b/source/torture/locktest.c
new file mode 100644
index 00000000000..4e5d630f302
--- /dev/null
+++ b/source/torture/locktest.c
@@ -0,0 +1,625 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ randomised byte range lock tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+static fstring password;
+static fstring username;
+static int got_pass;
+static int numops = 1000;
+static BOOL showall;
+static BOOL analyze;
+static BOOL hide_unlock_fails;
+static BOOL use_oplocks;
+
+#define FILENAME "\\locktest.dat"
+#define LOCKRANGE 100
+#define LOCKBASE 0
+#define MINLENGTH 0
+
+#define ZERO_ZERO 0
+
+/*
+#define LOCKBASE (0x40000000 - 50)
+*/
+
+#define READ_PCT 50
+#define LOCK_PCT 45
+#define UNLOCK_PCT 70
+#define RANGE_MULTIPLE 1
+#define NSERVERS 2
+#define NCONNECTIONS 2
+#define NFILES 2
+#define LOCK_TIMEOUT 0
+
+#define NASTY_POSIX_LOCK_HACK 0
+
+enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN};
+
+struct record {
+ enum lock_op lock_op;
+ enum brl_type lock_type;
+ char conn, f;
+ SMB_BIG_UINT start, len;
+ char needed;
+};
+
+#define PRESETS 0
+
+#if PRESETS
+static struct record preset[] = {
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1},
+{OP_UNLOCK, 0 , 0, 0, 2, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+};
+#endif
+
+static struct record *recorded;
+
+static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
+ enum brl_type lock_type,
+ br_off start, br_off size)
+{
+#if NASTY_POSIX_LOCK_HACK
+ {
+ pstring cmd;
+ static SMB_INO_T lastino;
+
+ if (lastino != ino) {
+ slprintf(cmd, sizeof(cmd),
+ "egrep POSIX.*%u /proc/locks", (int)ino);
+ system(cmd);
+ }
+ lastino = ino;
+ }
+#endif
+
+ printf("%6d %05x:%05x %s %.0f:%.0f(%.0f)\n",
+ (int)pid, (int)dev, (int)ino,
+ lock_type==READ_LOCK?"R":"W",
+ (double)start, (double)start+size-1,(double)size);
+
+}
+
+
+static void show_locks(void)
+{
+ brl_forall(print_brl);
+ /* system("cat /proc/locks"); */
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ fstring server;
+ struct in_addr ip;
+ fstring myname;
+ static int count;
+
+ fstrcpy(server,share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ zero_ip(&ip);
+
+ slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), count++);
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
+ return NULL;
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup())) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ c->use_oplocks = use_oplocks;
+
+ return c;
+}
+
+
+static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ char *share[NSERVERS])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++) {
+ if (cli[server][conn]) {
+ for (f=0;f<NFILES;f++) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ }
+ cli_ulogoff(cli[server][conn]);
+ cli_shutdown(cli[server][conn]);
+ }
+ cli[server][conn] = connect_one(share[server]);
+ if (!cli[server][conn]) {
+ DEBUG(0,("Failed to connect to %s\n", share[server]));
+ exit(1);
+ }
+ }
+}
+
+
+
+static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ struct record *rec)
+{
+ unsigned conn = rec->conn;
+ unsigned f = rec->f;
+ SMB_BIG_UINT start = rec->start;
+ SMB_BIG_UINT len = rec->len;
+ enum brl_type op = rec->lock_type;
+ int server;
+ BOOL ret[NSERVERS];
+
+ switch (rec->lock_op) {
+ case OP_LOCK:
+ /* set a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = cli_lock64(cli[server][conn],
+ fnum[server][conn][f],
+ start, len, LOCK_TIMEOUT, op);
+ }
+ if (showall || ret[0] != ret[1]) {
+ printf("lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %u:%u\n",
+ conn, f,
+ (double)start, (double)len,
+ op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
+ ret[0], ret[1]);
+ }
+ if (showall || ret[0] != ret[1]) show_locks();
+ if (ret[0] != ret[1]) return False;
+ break;
+
+ case OP_UNLOCK:
+ /* unset a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = cli_unlock64(cli[server][conn],
+ fnum[server][conn][f],
+ start, len);
+ }
+ if (showall || (!hide_unlock_fails && (ret[0] != ret[1]))) {
+ printf("unlock conn=%u f=%u range=%.0f(%.0f) -> %u:%u\n",
+ conn, f,
+ (double)start, (double)len,
+ ret[0], ret[1]);
+ }
+ if (showall || ret[0] != ret[1]) show_locks();
+ if (!hide_unlock_fails && ret[0] != ret[1]) return False;
+ break;
+
+ case OP_REOPEN:
+ /* reopen the file */
+ for (server=0;server<NSERVERS;server++) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ }
+ for (server=0;server<NSERVERS;server++) {
+ fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ printf("failed to reopen on share%d\n", server);
+ return False;
+ }
+ }
+ if (showall) {
+ printf("reopen conn=%u f=%u\n",
+ conn, f);
+ show_locks();
+ }
+ break;
+ }
+
+ return True;
+}
+
+static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][conn][f] != -1) {
+ cli_close(cli[server][conn], fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ }
+ for (server=0;server<NSERVERS;server++) {
+ cli_unlink(cli[server][0], FILENAME);
+ }
+}
+
+static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ fprintf(stderr,"Failed to open fnum[%u][%u][%u]\n",
+ server, conn, f);
+ exit(1);
+ }
+ }
+}
+
+
+static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ int n)
+{
+ int i;
+ printf("testing %u ...\n", n);
+ for (i=0; i<n; i++) {
+ if (i && i % 100 == 0) {
+ printf("%u\n", i);
+ }
+
+ if (recorded[i].needed &&
+ !test_one(cli, fnum, &recorded[i])) return i;
+ }
+ return n;
+}
+
+
+/* each server has two connections open to it. Each connection has two file
+ descriptors open on the file - 8 file descriptors in total
+
+ we then do random locking ops in tamdem on the 4 fnums from each
+ server and ensure that the results match
+ */
+static void test_locks(char *share[NSERVERS])
+{
+ struct cli_state *cli[NSERVERS][NCONNECTIONS];
+ int fnum[NSERVERS][NCONNECTIONS][NFILES];
+ int n, i, n1, skip, r1, r2;
+
+ ZERO_STRUCT(fnum);
+ ZERO_STRUCT(cli);
+
+ recorded = (struct record *)malloc(sizeof(*recorded) * numops);
+
+ for (n=0; n<numops; n++) {
+#if PRESETS
+ if (n < sizeof(preset) / sizeof(preset[0])) {
+ recorded[n] = preset[n];
+ } else {
+#endif
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
+ recorded[n].len = MINLENGTH +
+ random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ r1 = random() % 100;
+ r2 = random() % 100;
+ if (r1 < READ_PCT) {
+ recorded[n].lock_type = READ_LOCK;
+ } else {
+ recorded[n].lock_type = WRITE_LOCK;
+ }
+ if (r2 < LOCK_PCT) {
+ recorded[n].lock_op = OP_LOCK;
+ } else if (r2 < UNLOCK_PCT) {
+ recorded[n].lock_op = OP_UNLOCK;
+ } else {
+ recorded[n].lock_op = OP_REOPEN;
+ }
+ recorded[n].needed = True;
+#if !ZERO_ZERO
+ if (recorded[n].start == 0 &&
+ recorded[n].len == 0) {
+ recorded[n].len = 1;
+ }
+#endif
+#if PRESETS
+ }
+#endif
+ }
+
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+ n = retest(cli, fnum, numops);
+
+ if (n == numops || !analyze) return;
+ n++;
+
+ skip = n/2;
+
+ while (1) {
+ n1 = n;
+
+ close_files(cli, fnum);
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+
+ for (i=0;i<n-skip;i+=skip) {
+ int m, j;
+ printf("excluding %d-%d\n", i, i+skip-1);
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = False;
+ }
+
+ close_files(cli, fnum);
+ open_files(cli, fnum);
+
+ m = retest(cli, fnum, n);
+ if (m == n) {
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = True;
+ }
+ } else {
+ if (i+(skip-1) < m) {
+ memmove(&recorded[i], &recorded[i+skip],
+ (m-(i+skip-1))*sizeof(recorded[0]));
+ }
+ n = m-(skip-1);
+ i--;
+ }
+ }
+
+ if (skip > 1) {
+ skip = skip/2;
+ printf("skip=%d\n", skip);
+ continue;
+ }
+
+ if (n1 == n) break;
+ }
+
+ close_files(cli, fnum);
+ reconnect(cli, fnum, share);
+ open_files(cli, fnum);
+ showall = True;
+ n1 = retest(cli, fnum, n);
+ if (n1 != n-1) {
+ printf("ERROR - inconsistent result (%u %u)\n", n1, n);
+ }
+ close_files(cli, fnum);
+
+ for (i=0;i<n;i++) {
+ printf("{%d, %d, %u, %u, %.0f, %.0f, %u},\n",
+ recorded[i].lock_op,
+ recorded[i].lock_type,
+ recorded[i].conn,
+ recorded[i].f,
+ (double)recorded[i].start,
+ (double)recorded[i].len,
+ recorded[i].needed);
+ }
+}
+
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ locktest //server1/share1 //server2/share2 [options..]\n\
+ options:\n\
+ -U user%%pass\n\
+ -s seed\n\
+ -o numops\n\
+ -u hide unlock fails\n\
+ -a (show all ops)\n\
+ -A analyse for minimal ops\n\
+ -O use oplocks\n\
+");
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share[NSERVERS];
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *p;
+ int seed, server;
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ if (argc < 3 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ setup_logging(argv[0],True);
+
+ for (server=0;server<NSERVERS;server++) {
+ share[server] = argv[1+server];
+ all_string_sub(share[server],"/","\\",0);
+ }
+
+ argc -= NSERVERS;
+ argv += NSERVERS;
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "U:s:ho:aAW:O")) != EOF) {
+ switch (opt) {
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'u':
+ hide_unlock_fails = True;
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'O':
+ use_oplocks = True;
+ break;
+ case 'a':
+ showall = True;
+ break;
+ case 'A':
+ analyze = True;
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ DEBUG(0,("seed=%u\n", seed));
+ srandom(seed);
+
+ test_locks(share);
+
+ return(0);
+}
diff --git a/source/torture/locktest2.c b/source/torture/locktest2.c
new file mode 100644
index 00000000000..175039bd14c
--- /dev/null
+++ b/source/torture/locktest2.c
@@ -0,0 +1,616 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ byte range lock tester - with local filesystem support
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+static fstring password;
+static fstring username;
+static int got_pass;
+static int numops = 1000;
+static BOOL showall;
+static BOOL analyze;
+static BOOL hide_unlock_fails;
+static BOOL use_oplocks;
+
+#define FILENAME "\\locktest.dat"
+#define LOCKRANGE 100
+#define LOCKBASE 0
+
+/*
+#define LOCKBASE (0x40000000 - 50)
+*/
+
+#define READ_PCT 50
+#define LOCK_PCT 25
+#define UNLOCK_PCT 65
+#define RANGE_MULTIPLE 1
+
+#define NSERVERS 2
+#define NCONNECTIONS 2
+#define NUMFSTYPES 2
+#define NFILES 2
+#define LOCK_TIMEOUT 0
+
+#define FSTYPE_SMB 0
+#define FSTYPE_NFS 1
+
+struct record {
+ char r1, r2;
+ char conn, f, fstype;
+ unsigned start, len;
+ char needed;
+};
+
+static struct record *recorded;
+
+static int try_open(struct cli_state *c, char *nfs, int fstype, char *fname, int flags)
+{
+ pstring path;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_open(c, fname, flags, DENY_NONE);
+
+ case FSTYPE_NFS:
+ slprintf(path, sizeof(path), "%s%s", nfs, fname);
+ pstring_sub(path,"\\", "/");
+ return open(path, flags, 0666);
+ }
+
+ return -1;
+}
+
+static BOOL try_close(struct cli_state *c, int fstype, int fd)
+{
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_close(c, fd);
+
+ case FSTYPE_NFS:
+ return close(fd) == 0;
+ }
+
+ return False;
+}
+
+static BOOL try_lock(struct cli_state *c, int fstype,
+ int fd, unsigned start, unsigned len,
+ enum brl_type op)
+{
+ struct flock lock;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_lock(c, fd, start, len, LOCK_TIMEOUT, op);
+
+ case FSTYPE_NFS:
+ lock.l_type = (op==READ_LOCK) ? F_RDLCK:F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = len;
+ lock.l_pid = getpid();
+ return fcntl(fd,F_SETLK,&lock) == 0;
+ }
+
+ return False;
+}
+
+static BOOL try_unlock(struct cli_state *c, int fstype,
+ int fd, unsigned start, unsigned len)
+{
+ struct flock lock;
+
+ switch (fstype) {
+ case FSTYPE_SMB:
+ return cli_unlock(c, fd, start, len);
+
+ case FSTYPE_NFS:
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = len;
+ lock.l_pid = getpid();
+ return fcntl(fd,F_SETLK,&lock) == 0;
+ }
+
+ return False;
+}
+
+static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
+ enum brl_type lock_type,
+ br_off start, br_off size)
+{
+ printf("%6d %05x:%05x %s %.0f:%.0f(%.0f)\n",
+ (int)pid, (int)dev, (int)ino,
+ lock_type==READ_LOCK?"R":"W",
+ (double)start, (double)start+size-1,(double)size);
+
+}
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ fstring server;
+ struct in_addr ip;
+ fstring myname;
+ static int count;
+
+ fstrcpy(server,share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ zero_ip(&ip);
+
+ slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), count++);
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
+ return NULL;
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup())) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ c->use_oplocks = use_oplocks;
+
+ return c;
+}
+
+
+static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ char *share1, char *share2)
+{
+ int server, conn, f, fstype;
+ char *share[2];
+ share[0] = share1;
+ share[1] = share2;
+
+ fstype = FSTYPE_SMB;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++) {
+ if (cli[server][conn]) {
+ for (f=0;f<NFILES;f++) {
+ cli_close(cli[server][conn], fnum[server][fstype][conn][f]);
+ }
+ cli_ulogoff(cli[server][conn]);
+ cli_shutdown(cli[server][conn]);
+ }
+ cli[server][conn] = connect_one(share[server]);
+ if (!cli[server][conn]) {
+ DEBUG(0,("Failed to connect to %s\n", share[server]));
+ exit(1);
+ }
+ }
+}
+
+
+
+static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ struct record *rec)
+{
+ unsigned conn = rec->conn;
+ unsigned f = rec->f;
+ unsigned fstype = rec->fstype;
+ unsigned start = rec->start;
+ unsigned len = rec->len;
+ unsigned r1 = rec->r1;
+ unsigned r2 = rec->r2;
+ enum brl_type op;
+ int server;
+ BOOL ret[NSERVERS];
+
+ if (r1 < READ_PCT) {
+ op = READ_LOCK;
+ } else {
+ op = WRITE_LOCK;
+ }
+
+ if (r2 < LOCK_PCT) {
+ /* set a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = try_lock(cli[server][conn], fstype,
+ fnum[server][fstype][conn][f],
+ start, len, op);
+ }
+ if (showall || ret[0] != ret[1]) {
+ printf("lock conn=%u fstype=%u f=%u range=%u:%u(%u) op=%s -> %u:%u\n",
+ conn, fstype, f,
+ start, start+len-1, len,
+ op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
+ ret[0], ret[1]);
+ }
+ if (showall) brl_forall(print_brl);
+ if (ret[0] != ret[1]) return False;
+ } else if (r2 < LOCK_PCT+UNLOCK_PCT) {
+ /* unset a lock */
+ for (server=0;server<NSERVERS;server++) {
+ ret[server] = try_unlock(cli[server][conn], fstype,
+ fnum[server][fstype][conn][f],
+ start, len);
+ }
+ if (showall || (!hide_unlock_fails && (ret[0] != ret[1]))) {
+ printf("unlock conn=%u fstype=%u f=%u range=%u:%u(%u) -> %u:%u\n",
+ conn, fstype, f,
+ start, start+len-1, len,
+ ret[0], ret[1]);
+ }
+ if (showall) brl_forall(print_brl);
+ if (!hide_unlock_fails && ret[0] != ret[1]) return False;
+ } else {
+ /* reopen the file */
+ for (server=0;server<NSERVERS;server++) {
+ try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
+ fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
+ O_RDWR|O_CREAT);
+ if (fnum[server][fstype][conn][f] == -1) {
+ printf("failed to reopen on share1\n");
+ return False;
+ }
+ }
+ if (showall) {
+ printf("reopen conn=%u fstype=%u f=%u\n",
+ conn, fstype, f);
+ brl_forall(print_brl);
+ }
+ }
+ return True;
+}
+
+static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
+{
+ int server, conn, f, fstype;
+
+ for (server=0;server<NSERVERS;server++)
+ for (fstype=0;fstype<NUMFSTYPES;fstype++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][fstype][conn][f] != -1) {
+ try_close(cli[server][conn], fstype, fnum[server][fstype][conn][f]);
+ fnum[server][fstype][conn][f] = -1;
+ }
+ }
+ for (server=0;server<NSERVERS;server++) {
+ cli_unlink(cli[server][0], FILENAME);
+ }
+}
+
+static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES])
+{
+ int server, fstype, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (fstype=0;fstype<NUMFSTYPES;fstype++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ fnum[server][fstype][conn][f] = try_open(cli[server][conn], nfs[server], fstype, FILENAME,
+ O_RDWR|O_CREAT);
+ if (fnum[server][fstype][conn][f] == -1) {
+ fprintf(stderr,"Failed to open fnum[%u][%u][%u][%u]\n",
+ server, fstype, conn, f);
+ exit(1);
+ }
+ }
+}
+
+
+static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
+ char *nfs[NSERVERS],
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES],
+ int n)
+{
+ int i;
+ printf("testing %u ...\n", n);
+ for (i=0; i<n; i++) {
+ if (i && i % 100 == 0) {
+ printf("%u\n", i);
+ }
+
+ if (recorded[i].needed &&
+ !test_one(cli, nfs, fnum, &recorded[i])) return i;
+ }
+ return n;
+}
+
+
+/* each server has two connections open to it. Each connection has two file
+ descriptors open on the file - 8 file descriptors in total
+
+ we then do random locking ops in tamdem on the 4 fnums from each
+ server and ensure that the results match
+ */
+static void test_locks(char *share1, char *share2, char *nfspath1, char *nfspath2)
+{
+ struct cli_state *cli[NSERVERS][NCONNECTIONS];
+ char *nfs[NSERVERS];
+ int fnum[NSERVERS][NUMFSTYPES][NCONNECTIONS][NFILES];
+ int n, i, n1;
+
+ nfs[0] = nfspath1;
+ nfs[1] = nfspath2;
+
+ ZERO_STRUCT(fnum);
+ ZERO_STRUCT(cli);
+
+ recorded = (struct record *)malloc(sizeof(*recorded) * numops);
+
+ for (n=0; n<numops; n++) {
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].fstype = random() % NUMFSTYPES;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
+ recorded[n].len = 1 +
+ random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ recorded[n].r1 = random() % 100;
+ recorded[n].r2 = random() % 100;
+ recorded[n].needed = True;
+ }
+
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+ n = retest(cli, nfs, fnum, numops);
+
+ if (n == numops || !analyze) return;
+ n++;
+
+ while (1) {
+ n1 = n;
+
+ close_files(cli, nfs, fnum);
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+
+ for (i=0;i<n-1;i++) {
+ int m;
+ recorded[i].needed = False;
+
+ close_files(cli, nfs, fnum);
+ open_files(cli, nfs, fnum);
+
+ m = retest(cli, nfs, fnum, n);
+ if (m == n) {
+ recorded[i].needed = True;
+ } else {
+ if (i < m) {
+ memmove(&recorded[i], &recorded[i+1],
+ (m-i)*sizeof(recorded[0]));
+ }
+ n = m;
+ i--;
+ }
+ }
+
+ if (n1 == n) break;
+ }
+
+ close_files(cli, nfs, fnum);
+ reconnect(cli, nfs, fnum, share1, share2);
+ open_files(cli, nfs, fnum);
+ showall = True;
+ n1 = retest(cli, nfs, fnum, n);
+ if (n1 != n-1) {
+ printf("ERROR - inconsistent result (%u %u)\n", n1, n);
+ }
+ close_files(cli, nfs, fnum);
+
+ for (i=0;i<n;i++) {
+ printf("{%u, %u, %u, %u, %u, %u, %u, %u},\n",
+ recorded[i].r1,
+ recorded[i].r2,
+ recorded[i].conn,
+ recorded[i].fstype,
+ recorded[i].f,
+ recorded[i].start,
+ recorded[i].len,
+ recorded[i].needed);
+ }
+}
+
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ locktest //server1/share1 //server2/share2 /path1 /path2 [options..]\n\
+ options:\n\
+ -U user%%pass\n\
+ -s seed\n\
+ -o numops\n\
+ -u hide unlock fails\n\
+ -a (show all ops)\n\
+ -O use oplocks\n\
+");
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share1, *share2, *nfspath1, *nfspath2;
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *p;
+ int seed;
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ if (argc < 5 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ share1 = argv[1];
+ share2 = argv[2];
+ nfspath1 = argv[3];
+ nfspath2 = argv[4];
+
+ all_string_sub(share1,"/","\\",0);
+ all_string_sub(share2,"/","\\",0);
+
+ setup_logging(argv[0],True);
+
+ argc -= 4;
+ argv += 4;
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "U:s:ho:aAW:O")) != EOF) {
+ switch (opt) {
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'u':
+ hide_unlock_fails = True;
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'O':
+ use_oplocks = True;
+ break;
+ case 'a':
+ showall = True;
+ break;
+ case 'A':
+ analyze = True;
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ DEBUG(0,("seed=%u\n", seed));
+ srandom(seed);
+
+ locking_init(1);
+ test_locks(share1, share2, nfspath1, nfspath2);
+
+ return(0);
+}
diff --git a/source/torture/masktest.c b/source/torture/masktest.c
new file mode 100644
index 00000000000..e8c88a9fc14
--- /dev/null
+++ b/source/torture/masktest.c
@@ -0,0 +1,513 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ mask_match tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+static fstring password;
+static fstring username;
+static int got_pass;
+static int max_protocol = PROTOCOL_NT1;
+static BOOL showall = False;
+static BOOL old_list = False;
+static char *maskchars = "<>\"?*abc.";
+static char *filechars = "abcdefghijklm.";
+static int verbose;
+static int die_on_error;
+
+/* a test fn for LANMAN mask support */
+int ms_fnmatch_lanman_core(char *pattern, char *string)
+{
+ char *p = pattern, *n = string;
+ char c;
+
+ if (strcmp(p,"?")==0 && strcmp(n,".")==0) goto match;
+
+ while ((c = *p++)) {
+ switch (c) {
+ case '.':
+ /* if (! *n && ! *p) goto match; */
+ if (*n != '.') goto nomatch;
+ n++;
+ break;
+
+ case '?':
+ if ((*n == '.' && n[1] != '.') || ! *n) goto next;
+ n++;
+ break;
+
+ case '>':
+ if (n[0] == '.') {
+ if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+ }
+ if (! *n) goto next;
+ n++;
+ break;
+
+ case '*':
+ if (! *p) goto match;
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ }
+ break;
+
+ case '<':
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n == '.' && !strchr_m(n+1,'.')) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case '"':
+ if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n != '.') goto nomatch;
+ n++;
+ break;
+
+ default:
+ if (c != *n) goto nomatch;
+ n++;
+ }
+ }
+
+ if (! *n) goto match;
+
+ nomatch:
+ if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
+ return -1;
+
+next:
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+
+ match:
+ if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
+ return 0;
+}
+
+int ms_fnmatch_lanman(char *pattern, char *string)
+{
+ if (!strpbrk(pattern, "?*<>\"")) {
+ if (strcmp(string,"..") == 0) string = ".";
+ return strcmp(pattern, string);
+ }
+
+ if (strcmp(string,"..") == 0 || strcmp(string,".") == 0) {
+ return ms_fnmatch_lanman_core(pattern, "..") &&
+ ms_fnmatch_lanman_core(pattern, ".");
+ }
+
+ return ms_fnmatch_lanman_core(pattern, string);
+}
+
+static BOOL reg_match_one(struct cli_state *cli, char *pattern, char *file)
+{
+ /* oh what a weird world this is */
+ if (old_list && strcmp(pattern, "*.*") == 0) return True;
+
+ if (strcmp(pattern,".") == 0) return False;
+
+ if (max_protocol <= PROTOCOL_LANMAN2) {
+ return ms_fnmatch_lanman(pattern, file)==0;
+ }
+
+ if (strcmp(file,"..") == 0) file = ".";
+
+ return ms_fnmatch(pattern, file, cli->protocol)==0;
+}
+
+static char *reg_test(struct cli_state *cli, char *pattern, char *long_name, char *short_name)
+{
+ static fstring ret;
+ fstrcpy(ret, "---");
+
+ pattern = 1+strrchr_m(pattern,'\\');
+
+ if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
+ if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
+ if (reg_match_one(cli, pattern, long_name) ||
+ (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
+ return ret;
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ char *server;
+ struct in_addr ip;
+
+ server = share+2;
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ zero_ip(&ip);
+
+ make_nmb_name(&calling, "masktest", 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
+ return NULL;
+ }
+
+ c->protocol = max_protocol;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup())) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ return c;
+}
+
+static char *resultp;
+static file_info *f_info;
+
+void listfn(file_info *f, const char *s, void *state)
+{
+ if (strcmp(f->name,".") == 0) {
+ resultp[0] = '+';
+ } else if (strcmp(f->name,"..") == 0) {
+ resultp[1] = '+';
+ } else {
+ resultp[2] = '+';
+ }
+ f_info = f;
+}
+
+static void get_real_name(struct cli_state *cli,
+ pstring long_name, fstring short_name)
+{
+ /* nasty hack to force level 260 listings - tridge */
+ cli->capabilities |= CAP_NT_SMBS;
+ if (max_protocol <= PROTOCOL_LANMAN1) {
+ cli_list_new(cli, "\\masktest\\*.*", aHIDDEN | aDIR, listfn, NULL);
+ } else {
+ cli_list_new(cli, "\\masktest\\*", aHIDDEN | aDIR, listfn, NULL);
+ }
+ if (f_info) {
+ fstrcpy(short_name, f_info->short_name);
+ strlower(short_name);
+ pstrcpy(long_name, f_info->name);
+ strlower(long_name);
+ }
+
+ if (*short_name == 0) {
+ fstrcpy(short_name, long_name);
+ }
+
+#if 0
+ if (!strchr_m(short_name,'.')) {
+ fstrcat(short_name,".");
+ }
+#endif
+}
+
+static void testpair(struct cli_state *cli, char *mask, char *file)
+{
+ int fnum;
+ fstring res1;
+ char *res2;
+ static int count;
+ fstring short_name;
+ pstring long_name;
+
+ count++;
+
+ fstrcpy(res1, "---");
+
+ fnum = cli_open(cli, file, O_CREAT|O_TRUNC|O_RDWR, 0);
+ if (fnum == -1) {
+ DEBUG(0,("Can't create %s\n", file));
+ return;
+ }
+ cli_close(cli, fnum);
+
+ resultp = res1;
+ fstrcpy(short_name, "");
+ f_info = NULL;
+ get_real_name(cli, long_name, short_name);
+ f_info = NULL;
+ fstrcpy(res1, "---");
+ cli_list(cli, mask, aHIDDEN | aDIR, listfn, NULL);
+
+ res2 = reg_test(cli, mask, long_name, short_name);
+
+ if (showall || strcmp(res1, res2)) {
+ DEBUG(0,("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
+ res1, res2, count, mask, file, long_name, short_name));
+ if (die_on_error) exit(1);
+ }
+
+ cli_unlink(cli, file);
+
+ if (count % 100 == 0) DEBUG(0,("%d\n", count));
+}
+
+static void test_mask(int argc, char *argv[],
+ struct cli_state *cli)
+{
+ pstring mask, file;
+ int l1, l2, i, l;
+ int mc_len = strlen(maskchars);
+ int fc_len = strlen(filechars);
+
+ cli_mkdir(cli, "\\masktest");
+
+ cli_unlink(cli, "\\masktest\\*");
+
+ if (argc >= 2) {
+ while (argc >= 2) {
+ pstrcpy(mask,"\\masktest\\");
+ pstrcpy(file,"\\masktest\\");
+ pstrcat(mask, argv[0]);
+ pstrcat(file, argv[1]);
+ testpair(cli, mask, file);
+ argv += 2;
+ argc -= 2;
+ }
+ goto finished;
+ }
+
+ while (1) {
+ l1 = 1 + random() % 20;
+ l2 = 1 + random() % 20;
+ pstrcpy(mask,"\\masktest\\");
+ pstrcpy(file,"\\masktest\\");
+ l = strlen(mask);
+ for (i=0;i<l1;i++) {
+ mask[i+l] = maskchars[random() % mc_len];
+ }
+ mask[l+l1] = 0;
+
+ for (i=0;i<l2;i++) {
+ file[i+l] = filechars[random() % fc_len];
+ }
+ file[l+l2] = 0;
+
+ if (strcmp(file+l,".") == 0 ||
+ strcmp(file+l,"..") == 0 ||
+ strcmp(mask+l,"..") == 0) continue;
+
+ if (strspn(file+l, ".") == strlen(file+l)) continue;
+
+ testpair(cli, mask, file);
+ }
+
+ finished:
+ cli_rmdir(cli, "\\masktest");
+}
+
+
+static void usage(void)
+{
+ printf(
+"Usage:\n\
+ masktest //server/share [options..]\n\
+ options:\n\
+ -W workgroup\n\
+ -U user%%pass\n\
+ -s seed\n\
+ -M max protocol\n\
+ -f filechars (default %s)\n\
+ -m maskchars (default %s)\n\
+ -a show all tests\n\
+\n\
+ This program tests wildcard matching between two servers. It generates\n\
+ random pairs of filenames/masks and tests that they match in the same\n\
+ way on the servers and internally\n\
+",
+ filechars, maskchars);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share;
+ struct cli_state *cli;
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *p;
+ int seed;
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ if (argv[1][0] == '-' || argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ share = argv[1];
+
+ all_string_sub(share,"/","\\",0);
+
+ setup_logging(argv[0],True);
+
+ argc -= 1;
+ argv += 1;
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
+ }
+
+ seed = time(NULL);
+
+ while ((opt = getopt(argc, argv, "U:s:hm:f:aoW:M:vE")) != EOF) {
+ switch (opt) {
+ case 'E':
+ die_on_error = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'M':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+ case 's':
+ seed = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ case 'm':
+ maskchars = optarg;
+ break;
+ case 'f':
+ filechars = optarg;
+ break;
+ case 'a':
+ showall = 1;
+ break;
+ case 'o':
+ old_list = True;
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+
+ cli = connect_one(share);
+ if (!cli) {
+ DEBUG(0,("Failed to connect to %s\n", share));
+ exit(1);
+ }
+
+ /* need to init seed after connect as clientgen uses random numbers */
+ DEBUG(0,("seed=%d\n", seed));
+ srandom(seed);
+
+ test_mask(argc, argv, cli);
+
+ return(0);
+}
diff --git a/source/torture/msgtest.c b/source/torture/msgtest.c
new file mode 100644
index 00000000000..9f3c083b809
--- /dev/null
+++ b/source/torture/msgtest.c
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Copyright (C) Andrew Tridgell 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ test code for internal messaging
+ */
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+static int pong_count;
+
+/****************************************************************************
+a useful function for testing the message system
+****************************************************************************/
+void pong_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ pong_count++;
+}
+
+ int main(int argc, char *argv[])
+{
+ pid_t pid;
+ int i, n;
+ char buf[12];
+
+ setup_logging(argv[0],True);
+
+ lp_load(dyn_CONFIGFILE,False,False,False);
+
+ message_init();
+
+ if (argc != 3) {
+ fprintf(stderr, "%s: Usage - %s pid count\n", argv[0], argv[0]);
+ exit(1);
+ }
+
+ pid = atoi(argv[1]);
+ n = atoi(argv[2]);
+
+ message_register(MSG_PONG, pong_message);
+
+ for (i=0;i<n;i++) {
+ message_send_pid(pid, MSG_PING, NULL, 0, True);
+ }
+
+ while (pong_count < i) {
+ message_dispatch();
+ msleep(1);
+ }
+
+ /* Now test that the duplicate filtering code works. */
+ pong_count = 0;
+
+ safe_strcpy(buf, "1234567890", sizeof(buf)-1);
+
+ for (i=0;i<n;i++) {
+ message_send_pid(getpid(), MSG_PING, NULL, 0, False);
+ message_send_pid(getpid(), MSG_PING, buf, 11, False);
+ }
+
+ for (i=0;i<n;i++) {
+ message_dispatch();
+ msleep(1);
+ }
+
+ if (pong_count != 2) {
+ fprintf(stderr, "Duplicate filter failed (%d).\n", pong_count);
+ exit(1);
+ }
+
+ return (0);
+}
+
diff --git a/source/torture/nbio.c b/source/torture/nbio.c
new file mode 100644
index 00000000000..4866e52d4ec
--- /dev/null
+++ b/source/torture/nbio.c
@@ -0,0 +1,240 @@
+#define NBDEBUG 0
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#define MAX_FILES 1000
+
+static char buf[70000];
+extern int line_count;
+
+static struct {
+ int fd;
+ int handle;
+} ftable[MAX_FILES];
+
+static struct cli_state *c;
+
+static void sigsegv(int sig)
+{
+ char line[200];
+ printf("segv at line %d\n", line_count);
+ slprintf(line, sizeof(line), "/usr/X11R6/bin/xterm -e gdb /proc/%d/exe %d",
+ (int)getpid(), (int)getpid());
+ system(line);
+ exit(1);
+}
+
+void nb_setup(struct cli_state *cli)
+{
+ signal(SIGSEGV, sigsegv);
+ c = cli;
+}
+
+
+void nb_unlink(char *fname)
+{
+ strupper(fname);
+
+ if (!cli_unlink(c, fname)) {
+#if NBDEBUG
+ printf("(%d) unlink %s failed (%s)\n",
+ line_count, fname, cli_errstr(c));
+#endif
+ }
+}
+
+void nb_open(char *fname, int handle, int size)
+{
+ int fd, i;
+ int flags = O_RDWR|O_CREAT;
+ size_t st_size;
+ static int count;
+
+ strupper(fname);
+
+ if (size == 0) flags |= O_TRUNC;
+
+ fd = cli_open(c, fname, flags, DENY_NONE);
+ if (fd == -1) {
+#if NBDEBUG
+ printf("(%d) open %s failed for handle %d (%s)\n",
+ line_count, fname, handle, cli_errstr(c));
+#endif
+ return;
+ }
+ cli_getattrE(c, fd, NULL, &st_size, NULL, NULL, NULL);
+ if (size > st_size) {
+#if NBDEBUG
+ printf("(%d) needs expanding %s to %d from %d\n",
+ line_count, fname, size, (int)st_size);
+#endif
+ } else if (size < st_size) {
+#if NBDEBUG
+ printf("(%d) needs truncating %s to %d from %d\n",
+ line_count, fname, size, (int)st_size);
+#endif
+ }
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == 0) break;
+ }
+ if (i == MAX_FILES) {
+ printf("file table full for %s\n", fname);
+ exit(1);
+ }
+ ftable[i].handle = handle;
+ ftable[i].fd = fd;
+ if (count++ % 100 == 0) {
+ printf(".");
+ }
+}
+
+void nb_write(int handle, int size, int offset)
+{
+ int i;
+
+ if (buf[0] == 0) memset(buf, 1, sizeof(buf));
+
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == handle) break;
+ }
+ if (i == MAX_FILES) {
+#if NBDEBUG
+ printf("(%d) nb_write: handle %d was not open size=%d ofs=%d\n",
+ line_count, handle, size, offset);
+#endif
+ return;
+ }
+ if (cli_smbwrite(c, ftable[i].fd, buf, offset, size) != size) {
+ printf("(%d) write failed on handle %d, fd %d \
+errno %d (%s)\n", line_count, handle, ftable[i].fd, errno, strerror(errno));
+ if (errno == ENOSPC) {
+ printf("Halting.\n");
+ fflush(stdout);
+ fflush(stderr);
+ exit(3);
+ }
+ }
+}
+
+void nb_read(int handle, int size, int offset)
+{
+ int i, ret;
+
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == handle) break;
+ }
+ if (i == MAX_FILES) {
+ printf("(%d) nb_read: handle %d was not open size=%d ofs=%d\n",
+ line_count, handle, size, offset);
+ return;
+ }
+ if ((ret=cli_read(c, ftable[i].fd, buf, offset, size)) != size) {
+#if NBDEBUG
+ printf("(%d) read failed on handle %d ofs=%d size=%d res=%d fd %d errno %d (%s)\n",
+ line_count, handle, offset, size, ret, ftable[i].fd, errno, strerror(errno));
+#endif
+ }
+}
+
+void nb_close(int handle)
+{
+ int i;
+ for (i=0;i<MAX_FILES;i++) {
+ if (ftable[i].handle == handle) break;
+ }
+ if (i == MAX_FILES) {
+ printf("(%d) nb_close: handle %d was not open\n",
+ line_count, handle);
+ return;
+ }
+ cli_close(c, ftable[i].fd);
+ ftable[i].handle = 0;
+}
+
+void nb_mkdir(char *fname)
+{
+ strupper(fname);
+
+ if (!cli_mkdir(c, fname)) {
+#if NBDEBUG
+ printf("mkdir %s failed (%s)\n",
+ fname, cli_errstr(c));
+#endif
+ }
+}
+
+void nb_rmdir(char *fname)
+{
+ strupper(fname);
+
+ if (!cli_rmdir(c, fname)) {
+#if NBDEBUG
+ printf("rmdir %s failed (%s)\n",
+ fname, cli_errstr(c));
+#endif
+ }
+}
+
+void nb_rename(char *old, char *new)
+{
+ strupper(old);
+ strupper(new);
+
+ if (!cli_rename(c, old, new)) {
+#if NBDEBUG
+ printf("rename %s %s failed (%s)\n",
+ old, new, cli_errstr(c));
+#endif
+ }
+}
+
+
+void nb_stat(char *fname, int size)
+{
+ size_t st_size;
+
+ strupper(fname);
+
+ if (!cli_getatr(c, fname, NULL, &st_size, NULL)) {
+#if NBDEBUG
+ printf("(%d) nb_stat: %s size=%d %s\n",
+ line_count, fname, size, cli_errstr(c));
+#endif
+ return;
+ }
+ if (st_size != size) {
+#if NBDEBUG
+ printf("(%d) nb_stat: %s wrong size %d %d\n",
+ line_count, fname, (int)st_size, size);
+#endif
+ }
+}
+
+void nb_create(char *fname, int size)
+{
+ nb_open(fname, 5000, size);
+ nb_close(5000);
+}
diff --git a/source/torture/nsstest.c b/source/torture/nsstest.c
new file mode 100644
index 00000000000..f4becf2baf4
--- /dev/null
+++ b/source/torture/nsstest.c
@@ -0,0 +1,411 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ nss tester for winbindd
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static char *so_path = "/lib/libnss_winbind.so";
+static char *nss_name = "winbind";
+static int nss_errno;
+static NSS_STATUS last_error;
+static int total_errors;
+
+static void *find_fn(const char *name)
+{
+ char s[1024];
+ static void *h;
+ void *res;
+
+ snprintf(s,sizeof(s), "_nss_%s_%s", nss_name, name);
+
+ if (!h) {
+ h = dlopen(so_path, RTLD_LAZY);
+ }
+ if (!h) {
+ printf("Can't open shared library %s\n", so_path);
+ exit(1);
+ }
+ res = dlsym(h, s);
+ if (!res) {
+ printf("Can't find function %s\n", s);
+ return NULL;
+ }
+ return res;
+}
+
+static void report_nss_error(const char *who, NSS_STATUS status)
+{
+ last_error = status;
+ total_errors++;
+ printf("ERROR %s: NSS_STATUS=%d %d (nss_errno=%d)\n",
+ who, status, NSS_STATUS_SUCCESS, nss_errno);
+}
+
+static struct passwd *nss_getpwent(void)
+{
+ NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *,
+ size_t , int *) = find_fn("getpwent_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ status = _nss_getpwent_r(&pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwent", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static struct passwd *nss_getpwnam(const char *name)
+{
+ NSS_STATUS (*_nss_getpwnam_r)(const char *, struct passwd *, char *,
+ size_t , int *) = find_fn("getpwnam_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ status = _nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwnam", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static struct passwd *nss_getpwuid(uid_t uid)
+{
+ NSS_STATUS (*_nss_getpwuid_r)(uid_t , struct passwd *, char *,
+ size_t , int *) = find_fn("getpwuid_r");
+ static struct passwd pwd;
+ static char buf[1000];
+ NSS_STATUS status;
+
+ status = _nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getpwuid", status);
+ return NULL;
+ }
+ return &pwd;
+}
+
+static void nss_setpwent(void)
+{
+ NSS_STATUS (*_nss_setpwent)(void) = find_fn("setpwent");
+ NSS_STATUS status;
+ status = _nss_setpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("setpwent", status);
+ }
+}
+
+static void nss_endpwent(void)
+{
+ NSS_STATUS (*_nss_endpwent)(void) = find_fn("endpwent");
+ NSS_STATUS status;
+ status = _nss_endpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("endpwent", status);
+ }
+}
+
+
+static struct group *nss_getgrent(void)
+{
+ NSS_STATUS (*_nss_getgrent_r)(struct group *, char *,
+ size_t , int *) = find_fn("getgrent_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1024;
+ NSS_STATUS status;
+
+ if (!buf) buf = malloc(buflen);
+
+again:
+ status = _nss_getgrent_r(&grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = realloc(buf, buflen);
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrent", status);
+ return NULL;
+ }
+ return &grp;
+}
+
+static struct group *nss_getgrnam(const char *name)
+{
+ NSS_STATUS (*_nss_getgrnam_r)(const char *, struct group *, char *,
+ size_t , int *) = find_fn("getgrnam_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!buf) buf = malloc(buflen);
+again:
+ status = _nss_getgrnam_r(name, &grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = realloc(buf, buflen);
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrnam", status);
+ return NULL;
+ }
+ return &grp;
+}
+
+static struct group *nss_getgrgid(gid_t gid)
+{
+ NSS_STATUS (*_nss_getgrgid_r)(gid_t , struct group *, char *,
+ size_t , int *) = find_fn("getgrgid_r");
+ static struct group grp;
+ static char *buf;
+ static int buflen = 1000;
+ NSS_STATUS status;
+
+ if (!buf) buf = malloc(buflen);
+again:
+ status = _nss_getgrgid_r(gid, &grp, buf, buflen, &nss_errno);
+ if (status == NSS_STATUS_TRYAGAIN) {
+ buflen *= 2;
+ buf = realloc(buf, buflen);
+ goto again;
+ }
+ if (status == NSS_STATUS_NOTFOUND) {
+ return NULL;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("getgrgid", status);
+ return NULL;
+ }
+ return &grp;
+}
+
+static void nss_setgrent(void)
+{
+ NSS_STATUS (*_nss_setgrent)(void) = find_fn("setgrent");
+ NSS_STATUS status;
+ status = _nss_setgrent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("setgrent", status);
+ }
+}
+
+static void nss_endgrent(void)
+{
+ NSS_STATUS (*_nss_endgrent)(void) = find_fn("endgrent");
+ NSS_STATUS status;
+ status = _nss_endgrent();
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("endgrent", status);
+ }
+}
+
+static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *start, long int *size)
+{
+ NSS_STATUS (*_nss_initgroups)(char *, gid_t , long int *,
+ long int *, gid_t **, long int , int *) =
+ find_fn("initgroups_dyn");
+ NSS_STATUS status;
+
+ if (!_nss_initgroups) return NSS_STATUS_UNAVAIL;
+
+ status = _nss_initgroups(user, group, start, size, groups, 0, &nss_errno);
+ if (status != NSS_STATUS_SUCCESS) {
+ report_nss_error("initgroups", status);
+ }
+ return status;
+}
+
+static void print_passwd(struct passwd *pwd)
+{
+ printf("%s:%s:%d:%d:%s:%s:%s\n",
+ pwd->pw_name,
+ pwd->pw_passwd,
+ pwd->pw_uid,
+ pwd->pw_gid,
+ pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell);
+}
+
+static void print_group(struct group *grp)
+{
+ int i;
+ printf("%s:%s:%d: ",
+ grp->gr_name,
+ grp->gr_passwd,
+ grp->gr_gid);
+
+ if (!grp->gr_mem[0]) {
+ printf("\n");
+ return;
+ }
+
+ for (i=0; grp->gr_mem[i+1]; i++) {
+ printf("%s, ", grp->gr_mem[i]);
+ }
+ printf("%s\n", grp->gr_mem[i]);
+}
+
+static void nss_test_initgroups(char *name, gid_t gid)
+{
+ long int size = 16;
+ long int start = 1;
+ gid_t *groups = NULL;
+ int i;
+ NSS_STATUS status;
+
+ groups = (gid_t *)malloc(size * sizeof(gid_t));
+ groups[0] = gid;
+
+ status = nss_initgroups(name, gid, &groups, &start, &size);
+ if (status == NSS_STATUS_UNAVAIL) {
+ printf("No initgroups fn\n");
+ return;
+ }
+
+ for (i=0; i<start-1; i++) {
+ printf("%d, ", groups[i]);
+ }
+ printf("%d\n", groups[i]);
+}
+
+
+static void nss_test_users(void)
+{
+ struct passwd *pwd;
+
+ nss_setpwent();
+ /* loop over all users */
+ while ((pwd = nss_getpwent())) {
+ printf("Testing user %s\n", pwd->pw_name);
+ printf("getpwent: "); print_passwd(pwd);
+ pwd = nss_getpwuid(pwd->pw_uid);
+ if (!pwd) {
+ total_errors++;
+ printf("ERROR: can't getpwuid\n");
+ continue;
+ }
+ printf("getpwuid: "); print_passwd(pwd);
+ pwd = nss_getpwnam(pwd->pw_name);
+ if (!pwd) {
+ total_errors++;
+ printf("ERROR: can't getpwnam\n");
+ continue;
+ }
+ printf("getpwnam: "); print_passwd(pwd);
+ printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid);
+ printf("\n");
+ }
+ nss_endpwent();
+}
+
+static void nss_test_groups(void)
+{
+ struct group *grp;
+
+ nss_setgrent();
+ /* loop over all groups */
+ while ((grp = nss_getgrent())) {
+ printf("Testing group %s\n", grp->gr_name);
+ printf("getgrent: "); print_group(grp);
+ grp = nss_getgrnam(grp->gr_name);
+ if (!grp) {
+ total_errors++;
+ printf("ERROR: can't getgrnam\n");
+ continue;
+ }
+ printf("getgrnam: "); print_group(grp);
+ grp = nss_getgrgid(grp->gr_gid);
+ if (!grp) {
+ total_errors++;
+ printf("ERROR: can't getgrgid\n");
+ continue;
+ }
+ printf("getgrgid: "); print_group(grp);
+ printf("\n");
+ }
+ nss_endgrent();
+}
+
+static void nss_test_errors(void)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = getpwnam("nosuchname");
+ if (pwd || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant user gave error %d\n", last_error);
+ }
+
+ pwd = getpwuid(0xFFF0);
+ if (pwd || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant uid gave error %d\n", last_error);
+ }
+
+ grp = getgrnam("nosuchgroup");
+ if (grp || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant group gave error %d\n", last_error);
+ }
+
+ grp = getgrgid(0xFFF0);
+ if (grp || last_error != NSS_STATUS_NOTFOUND) {
+ total_errors++;
+ printf("ERROR Non existant gid gave error %d\n", last_error);
+ }
+}
+
+ int main(int argc, char *argv[])
+{
+ if (argc > 1) so_path = argv[1];
+ if (argc > 2) nss_name = argv[2];
+
+ nss_test_users();
+ nss_test_groups();
+ nss_test_errors();
+
+ printf("total_errors=%d\n", total_errors);
+
+ return total_errors;
+}
diff --git a/source/torture/rpctorture.c b/source/torture/rpctorture.c
new file mode 100644
index 00000000000..6844440fbec
--- /dev/null
+++ b/source/torture/rpctorture.c
@@ -0,0 +1,546 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+extern pstring global_myname;
+
+extern pstring user_socket_options;
+
+
+extern file_info def_finfo;
+
+#define CNV_LANG(s) dos2unix_format(s,False)
+#define CNV_INPUT(s) unix2dos_format(s,True)
+
+static struct cli_state smbcli;
+struct cli_state *smb_cli = &smbcli;
+
+FILE *out_hnd;
+
+static pstring password; /* local copy only, if one is entered */
+
+/****************************************************************************
+initialise smb client structure
+****************************************************************************/
+void rpcclient_init(void)
+{
+ memset((char *)smb_cli, '\0', sizeof(smb_cli));
+ cli_initialise(smb_cli);
+ smb_cli->capabilities |= CAP_NT_SMBS;
+}
+
+/****************************************************************************
+make smb client connection
+****************************************************************************/
+static BOOL rpcclient_connect(struct client_info *info)
+{
+ struct nmb_name calling;
+ struct nmb_name called;
+
+ make_nmb_name(&called , dns_to_netbios_name(info->dest_host ), info->name_type);
+ make_nmb_name(&calling, dns_to_netbios_name(info->myhostname), 0x0);
+
+ if (!cli_establish_connection(smb_cli,
+ info->dest_host, &info->dest_ip,
+ &calling, &called,
+ info->share, info->svc_type,
+ False, True))
+ {
+ DEBUG(0,("rpcclient_connect: connection failed\n"));
+ cli_shutdown(smb_cli);
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+stop the smb connection(s?)
+****************************************************************************/
+static void rpcclient_stop(void)
+{
+ cli_shutdown(smb_cli);
+}
+
+/****************************************************************************
+ log in as an nt user, log out again.
+****************************************************************************/
+void run_enums_test(int num_ops, struct client_info *cli_info, struct cli_state *cli)
+{
+ pstring cmd;
+ int i;
+
+ /* establish connections. nothing to stop these being re-established. */
+ rpcclient_connect(cli_info);
+
+ DEBUG(5,("rpcclient_connect: cli->fd:%d\n", cli->fd));
+ if (cli->fd <= 0)
+ {
+ fprintf(out_hnd, "warning: connection could not be established to %s<%02x>\n",
+ cli_info->dest_host, cli_info->name_type);
+ return;
+ }
+
+ for (i = 0; i < num_ops; i++)
+ {
+ set_first_token("");
+ cmd_srv_enum_sess(cli_info);
+ set_first_token("");
+ cmd_srv_enum_shares(cli_info);
+ set_first_token("");
+ cmd_srv_enum_files(cli_info);
+
+ if (password[0] != 0)
+ {
+ slprintf(cmd, sizeof(cmd)-1, "1");
+ set_first_token(cmd);
+ }
+ else
+ {
+ set_first_token("");
+ }
+ cmd_srv_enum_conn(cli_info);
+ }
+
+ rpcclient_stop();
+
+}
+
+/****************************************************************************
+ log in as an nt user, log out again.
+****************************************************************************/
+void run_ntlogin_test(int num_ops, struct client_info *cli_info, struct cli_state *cli)
+{
+ pstring cmd;
+ int i;
+
+ /* establish connections. nothing to stop these being re-established. */
+ rpcclient_connect(cli_info);
+
+ DEBUG(5,("rpcclient_connect: cli->fd:%d\n", cli->fd));
+ if (cli->fd <= 0)
+ {
+ fprintf(out_hnd, "warning: connection could not be established to %s<%02x>\n",
+ cli_info->dest_host, cli_info->name_type);
+ return;
+ }
+
+ for (i = 0; i < num_ops; i++)
+ {
+ slprintf(cmd, sizeof(cmd)-1, "%s %s", cli->user_name, password);
+ set_first_token(cmd);
+
+ cmd_netlogon_login_test(cli_info);
+ }
+
+ rpcclient_stop();
+
+}
+
+/****************************************************************************
+ runs n simultaneous functions.
+****************************************************************************/
+static void create_procs(int nprocs, int numops,
+ struct client_info *cli_info, struct cli_state *cli,
+ void (*fn)(int, struct client_info *, struct cli_state *))
+{
+ int i, status;
+
+ for (i=0;i<nprocs;i++)
+ {
+ if (fork() == 0)
+ {
+ pid_t mypid = getpid();
+ sys_srandom(mypid ^ time(NULL));
+ fn(numops, cli_info, cli);
+ fflush(out_hnd);
+ _exit(0);
+ }
+ }
+
+ for (i=0;i<nprocs;i++)
+ {
+ waitpid(0, &status, 0);
+ }
+}
+/****************************************************************************
+usage on the program - OUT OF DATE!
+****************************************************************************/
+static void usage(char *pname)
+{
+ fprintf(out_hnd, "Usage: %s service <password> [-d debuglevel] [-l log] ",
+ pname);
+
+ fprintf(out_hnd, "\nVersion %s\n",VERSION);
+ fprintf(out_hnd, "\t-d debuglevel set the debuglevel\n");
+ fprintf(out_hnd, "\t-l log basename. Basename for log/debug files\n");
+ fprintf(out_hnd, "\t-n netbios name. Use this name as my netbios name\n");
+ fprintf(out_hnd, "\t-m max protocol set the max protocol level\n");
+ fprintf(out_hnd, "\t-I dest IP use this IP to connect to\n");
+ fprintf(out_hnd, "\t-E write messages to stderr instead of stdout\n");
+ fprintf(out_hnd, "\t-U username set the network username\n");
+ fprintf(out_hnd, "\t-W workgroup set the workgroup name\n");
+ fprintf(out_hnd, "\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n");
+ fprintf(out_hnd, "\n");
+}
+
+enum client_action
+{
+ CLIENT_NONE,
+ CLIENT_IPC,
+ CLIENT_SVC
+};
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *pname = argv[0];
+ int opt;
+ extern char *optarg;
+ extern int optind;
+ pstring term_code;
+ BOOL got_pass = False;
+ char *cmd_str="";
+ mode_t myumask = 0755;
+ enum client_action cli_action = CLIENT_NONE;
+ int nprocs = 1;
+ int numops = 100;
+ pstring logfile;
+
+ struct client_info cli_info;
+
+ out_hnd = stdout;
+
+ rpcclient_init();
+
+#ifdef KANJI
+ pstrcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
+#endif /* KANJI */
+
+ if (!lp_load(dyn_CONFIGFILE,True, False, False))
+ {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
+ }
+
+ DEBUGLEVEL = 0;
+
+ cli_info.put_total_size = 0;
+ cli_info.put_total_time_ms = 0;
+ cli_info.get_total_size = 0;
+ cli_info.get_total_time_ms = 0;
+
+ cli_info.dir_total = 0;
+ cli_info.newer_than = 0;
+ cli_info.archive_level = 0;
+ cli_info.print_mode = 1;
+
+ cli_info.translation = False;
+ cli_info.recurse_dir = False;
+ cli_info.lowercase = False;
+ cli_info.prompt = True;
+ cli_info.abort_mget = True;
+
+ cli_info.dest_ip.s_addr = 0;
+ cli_info.name_type = 0x20;
+
+ pstrcpy(cli_info.cur_dir , "\\");
+ pstrcpy(cli_info.file_sel, "");
+ pstrcpy(cli_info.base_dir, "");
+ pstrcpy(smb_cli->domain, "");
+ pstrcpy(smb_cli->user_name, "");
+ pstrcpy(cli_info.myhostname, "");
+ pstrcpy(cli_info.dest_host, "");
+
+ pstrcpy(cli_info.svc_type, "A:");
+ pstrcpy(cli_info.share, "");
+ pstrcpy(cli_info.service, "");
+
+ ZERO_STRUCT(cli_info.dom.level3_sid);
+ pstrcpy(cli_info.dom.level3_dom, "");
+ ZERO_STRUCT(cli_info.dom.level5_sid);
+ pstrcpy(cli_info.dom.level5_dom, "");
+
+ smb_cli->nt_pipe_fnum = 0xffff;
+
+ setup_logging(pname, True);
+
+ myumask = umask(0);
+ umask(myumask);
+
+ if (!get_myname(global_myname))
+ {
+ fprintf(stderr, "Failed to get my hostname.\n");
+ }
+
+ password[0] = 0;
+
+ if (argc < 2)
+ {
+ usage(pname);
+ exit(1);
+ }
+
+ if (*argv[1] != '-')
+ {
+ pstrcpy(cli_info.service, argv[1]);
+ /* Convert any '/' characters in the service name to '\' characters */
+ string_replace( cli_info.service, '/','\\');
+ argc--;
+ argv++;
+
+ DEBUG(1,("service: %s\n", cli_info.service));
+
+ if (count_chars(cli_info.service,'\\') < 3)
+ {
+ usage(pname);
+ printf("\n%s: Not enough '\\' characters in service\n", cli_info.service);
+ exit(1);
+ }
+
+ /*
+ if (count_chars(cli_info.service,'\\') > 3)
+ {
+ usage(pname);
+ printf("\n%s: Too many '\\' characters in service\n", cli_info.service);
+ exit(1);
+ }
+ */
+
+ if (argc > 1 && (*argv[1] != '-'))
+ {
+ got_pass = True;
+ pstrcpy(password,argv[1]);
+ memset(argv[1],'X',strlen(argv[1]));
+ argc--;
+ argv++;
+ }
+
+ cli_action = CLIENT_SVC;
+ }
+
+ while ((opt = getopt(argc, argv,"s:O:M:S:i:N:o:n:d:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'm':
+ {
+ /* FIXME ... max_protocol seems to be funny here */
+
+ int max_protocol = 0;
+ max_protocol = interpret_protocol(optarg,max_protocol);
+ fprintf(stderr, "max protocol not currently supported\n");
+ break;
+ }
+
+ case 'O':
+ {
+ pstrcpy(user_socket_options,optarg);
+ break;
+ }
+
+ case 'S':
+ {
+ pstrcpy(cli_info.dest_host,optarg);
+ strupper(cli_info.dest_host);
+ cli_action = CLIENT_IPC;
+ break;
+ }
+
+ case 'i':
+ {
+ pstrcpy(scope, optarg);
+ break;
+ }
+
+ case 'U':
+ {
+ char *lp;
+ pstrcpy(smb_cli->user_name,optarg);
+ if ((lp=strchr_m(smb_cli->user_name,'%')))
+ {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr_m(optarg,'%')+1,'X',strlen(password));
+ }
+ break;
+ }
+
+ case 'W':
+ {
+ pstrcpy(smb_cli->domain,optarg);
+ break;
+ }
+
+ case 'E':
+ {
+ dbf = x_stderr;
+ break;
+ }
+
+ case 'I':
+ {
+ cli_info.dest_ip = *interpret_addr2(optarg);
+ if (is_zero_ip(cli_info.dest_ip))
+ {
+ exit(1);
+ }
+ break;
+ }
+
+ case 'N':
+ {
+ nprocs = atoi(optarg);
+ break;
+ }
+
+ case 'o':
+ {
+ numops = atoi(optarg);
+ break;
+ }
+
+ case 'n':
+ {
+ fstrcpy(global_myname, optarg);
+ break;
+ }
+
+ case 'd':
+ {
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ }
+
+ case 'l':
+ {
+ slprintf(logfile, sizeof(logfile)-1,
+ "%s.client",optarg);
+ lp_set_logfile(logfile);
+ break;
+ }
+
+ case 'c':
+ {
+ cmd_str = optarg;
+ got_pass = True;
+ break;
+ }
+
+ case 'h':
+ {
+ usage(pname);
+ exit(0);
+ break;
+ }
+
+ case 's':
+ {
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ }
+
+ case 't':
+ {
+ pstrcpy(term_code, optarg);
+ break;
+ }
+
+ default:
+ {
+ usage(pname);
+ exit(1);
+ break;
+ }
+ }
+ }
+
+ if (cli_action == CLIENT_NONE)
+ {
+ usage(pname);
+ exit(1);
+ }
+
+ strupper(global_myname);
+ fstrcpy(cli_info.myhostname, global_myname);
+
+ DEBUG(3,("%s client started (version %s)\n",timestring(False),VERSION));
+
+ if (*smb_cli->domain == 0)
+ {
+ pstrcpy(smb_cli->domain,lp_workgroup());
+ }
+ strupper(smb_cli->domain);
+
+ load_interfaces();
+
+ if (cli_action == CLIENT_IPC)
+ {
+ pstrcpy(cli_info.share, "IPC$");
+ pstrcpy(cli_info.svc_type, "IPC");
+ }
+
+ fstrcpy(cli_info.mach_acct, cli_info.myhostname);
+ strupper(cli_info.mach_acct);
+ fstrcat(cli_info.mach_acct, "$");
+
+ /* set the password cache info */
+ if (got_pass)
+ {
+ if (password[0] == 0)
+ {
+ pwd_set_nullpwd(&(smb_cli->pwd));
+ }
+ else
+ {
+ pwd_make_lm_nt_16(&(smb_cli->pwd), password); /* generate 16 byte hashes */
+ }
+ }
+ else
+ {
+ char *pwd = getpass("Enter Password:");
+ safe_strcpy(password, pwd, sizeof(password));
+ pwd_make_lm_nt_16(&(smb_cli->pwd), password); /* generate 16 byte hashes */
+ }
+
+ create_procs(nprocs, numops, &cli_info, smb_cli, run_enums_test);
+
+ if (password[0] != 0)
+ {
+ create_procs(nprocs, numops, &cli_info, smb_cli, run_ntlogin_test);
+ }
+
+ fflush(out_hnd);
+
+ return(0);
+}
diff --git a/source/torture/scanner.c b/source/torture/scanner.c
new file mode 100644
index 00000000000..a6025593ff9
--- /dev/null
+++ b/source/torture/scanner.c
@@ -0,0 +1,431 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ SMB torture tester - scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#define VERBOSE 0
+#define OP_MIN 0
+#define OP_MAX 20
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void trans2_check_hit(char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, get_nt_error_msg(status));
+#endif
+}
+
+/****************************************************************************
+check for existance of a trans2 call
+****************************************************************************/
+static NTSTATUS try_trans2(struct cli_state *cli,
+ int op,
+ char *param, char *data,
+ int param_len, int data_len,
+ int *rparam_len, int *rdata_len)
+{
+ uint16 setup = op;
+ char *rparam=NULL, *rdata=NULL;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return cli_nt_error(cli);
+ }
+
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, rparam_len,
+ &rdata, rdata_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return cli_nt_error(cli);
+}
+
+
+static NTSTATUS try_trans2_len(struct cli_state *cli,
+ char *format,
+ int op, int level,
+ char *param, char *data,
+ int param_len, int *data_len,
+ int *rparam_len, int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_trans2(cli, op, param, data, param_len,
+ sizeof(pstring), rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, get_nt_error_msg(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < sizeof(pstring)) {
+ ret = try_trans2(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ trans2_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+check for existance of a trans2 call
+****************************************************************************/
+static BOOL scan_trans2(struct cli_state *cli, int op, int level,
+ int fnum, int dnum, char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ int rparam_len, rdata_len;
+ pstring param, data;
+ NTSTATUS status;
+
+ memset(data, 0, sizeof(data));
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_unlink(cli, "\\newfile.dat");
+ cli_rmdir(cli, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try dfs style */
+ cli_mkdir(cli, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
+
+ status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_rmdir(cli, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ return False;
+}
+
+
+BOOL torture_trans2_scan(int dummy)
+{
+ static struct cli_state cli;
+ int op, level;
+ char *fname = "\\scanner.dat";
+ int fnum, dnum;
+
+ printf("starting trans2 scan test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ dnum = cli_open(&cli, "\\", O_RDONLY, DENY_NONE);
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+ printf("Scanning op=%d\n", op);
+ for (level = 0; level <= 50; level++) {
+ scan_trans2(&cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_trans2(&cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_trans2(&cli, op, level, fnum, dnum, fname);
+ }
+ }
+
+ torture_close_connection(&cli);
+
+ printf("trans2 scan finished\n");
+ return True;
+}
+
+
+
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void nttrans_check_hit(char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, get_nt_error_msg(status));
+#endif
+}
+
+/****************************************************************************
+check for existance of a nttrans call
+****************************************************************************/
+static NTSTATUS try_nttrans(struct cli_state *cli,
+ int op,
+ char *param, char *data,
+ int param_len, int data_len,
+ int *rparam_len, int *rdata_len)
+{
+ char *rparam=NULL, *rdata=NULL;
+
+ if (!cli_send_nt_trans(cli, op,
+ 0,
+ NULL, 0, 0,
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return cli_nt_error(cli);
+ }
+
+ cli_receive_nt_trans(cli,
+ &rparam, rparam_len,
+ &rdata, rdata_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return cli_nt_error(cli);
+}
+
+
+static NTSTATUS try_nttrans_len(struct cli_state *cli,
+ char *format,
+ int op, int level,
+ char *param, char *data,
+ int param_len, int *data_len,
+ int *rparam_len, int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_nttrans(cli, op, param, data, param_len,
+ sizeof(pstring), rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, get_nt_error_msg(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < sizeof(pstring)) {
+ ret = try_nttrans(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ nttrans_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+check for existance of a nttrans call
+****************************************************************************/
+static BOOL scan_nttrans(struct cli_state *cli, int op, int level,
+ int fnum, int dnum, char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ int rparam_len, rdata_len;
+ pstring param, data;
+ NTSTATUS status;
+
+ memset(data, 0, sizeof(data));
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_unlink(cli, "\\newfile.dat");
+ cli_rmdir(cli, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ /* try dfs style */
+ cli_mkdir(cli, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
+
+ status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len,
+ &rparam_len, &rdata_len);
+ cli_rmdir(cli, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) return True;
+
+ return False;
+}
+
+
+BOOL torture_nttrans_scan(int dummy)
+{
+ static struct cli_state cli;
+ int op, level;
+ char *fname = "\\scanner.dat";
+ int fnum, dnum;
+
+ printf("starting nttrans scan test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ dnum = cli_open(&cli, "\\", O_RDONLY, DENY_NONE);
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+ printf("Scanning op=%d\n", op);
+ for (level = 0; level <= 50; level++) {
+ scan_nttrans(&cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_nttrans(&cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_nttrans(&cli, op, level, fnum, dnum, fname);
+ }
+ }
+
+ torture_close_connection(&cli);
+
+ printf("nttrans scan finished\n");
+ return True;
+}
diff --git a/source/torture/torture.c b/source/torture/torture.c
new file mode 100644
index 00000000000..bc3310886d9
--- /dev/null
+++ b/source/torture/torture.c
@@ -0,0 +1,3272 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+static fstring host, workgroup, share, password, username, myname;
+static int max_protocol = PROTOCOL_NT1;
+static char *sockops="TCP_NODELAY";
+static int nprocs=1, numops=100;
+static int procnum; /* records process count number when forking */
+static struct cli_state current_cli;
+static fstring randomfname;
+static BOOL use_oplocks;
+static BOOL use_level_II_oplocks;
+BOOL torture_showall = False;
+
+static double create_procs(BOOL (*fn)(int), BOOL *result);
+
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+
+/* return a pointer to a anonymous shared memory segment of size "size"
+ which will persist across fork() but will disappear when all processes
+ exit
+
+ The memory is not zeroed
+
+ This function uses system5 shared memory. It takes advantage of a property
+ that the memory is not destroyed if it is attached when the id is removed
+ */
+static void *shm_setup(int size)
+{
+ int shmid;
+ void *ret;
+
+ shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
+ if (shmid == -1) {
+ printf("can't get shared memory\n");
+ exit(1);
+ }
+ ret = (void *)shmat(shmid, 0, 0);
+ if (!ret || ret == (void *)-1) {
+ printf("can't attach to shared memory\n");
+ return NULL;
+ }
+ /* the following releases the ipc, but note that this process
+ and all its children will still have access to the memory, its
+ just that the shmid is no longer valid for other shm calls. This
+ means we don't leave behind lots of shm segments after we exit
+
+ See Stevens "advanced programming in unix env" for details
+ */
+ shmctl(shmid, IPC_RMID, 0);
+
+ return ret;
+}
+
+
+static BOOL open_nbt_connection(struct cli_state *c)
+{
+ struct nmb_name called, calling;
+ struct in_addr ip;
+
+ ZERO_STRUCTP(c);
+
+ make_nmb_name(&calling, myname, 0x0);
+ make_nmb_name(&called , host, 0x20);
+
+ zero_ip(&ip);
+
+ if (!cli_initialise(c) || !cli_connect(c, host, &ip)) {
+ printf("Failed to connect with %s\n", host);
+ return False;
+ }
+
+ c->timeout = 120000; /* set a really long timeout (2 minutes) */
+ if (use_oplocks) c->use_oplocks = True;
+ if (use_level_II_oplocks) c->use_level_II_oplocks = True;
+
+ if (!cli_session_request(c, &calling, &called)) {
+ printf("%s rejected the session\n",host);
+ cli_shutdown(c);
+ return False;
+ }
+
+ return True;
+}
+
+BOOL torture_open_connection(struct cli_state *c)
+{
+ ZERO_STRUCTP(c);
+
+ if (!open_nbt_connection(c)) {
+ return False;
+ }
+
+ if (!cli_negprot(c)) {
+ printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ return True;
+}
+
+
+BOOL torture_close_connection(struct cli_state *c)
+{
+ BOOL ret = True;
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
+ ret = False;
+ }
+
+ cli_shutdown(c);
+
+ return ret;
+}
+
+
+/* check if the server produced the expected error code */
+static BOOL check_error(int line, struct cli_state *c,
+ uint8 eclass, uint32 ecode, NTSTATUS nterr)
+{
+ if (cli_is_dos_error(c)) {
+ uint8 class;
+ uint32 num;
+
+ /* Check DOS error */
+
+ cli_dos_error(c, &class, &num);
+
+ if (eclass != class || ecode != num) {
+ printf("unexpected error code class=%d code=%d\n",
+ (int)class, (int)num);
+ printf(" expected %d/%d %s (line=%d)\n",
+ (int)eclass, (int)ecode, get_nt_error_msg(nterr), line);
+ return False;
+ }
+
+ } else {
+ NTSTATUS status;
+
+ /* Check NT error */
+
+ status = cli_nt_error(c);
+
+ if (NT_STATUS_V(nterr) != NT_STATUS_V(status)) {
+ printf("unexpected error code %s\n", get_nt_error_msg(status));
+ printf(" expected %s (line=%d)\n", get_nt_error_msg(nterr), line);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
+{
+ while (!cli_lock(c, fnum, offset, len, -1, WRITE_LOCK)) {
+ if (!check_error(__LINE__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+ return True;
+}
+
+
+static BOOL rw_torture(struct cli_state *c)
+{
+ char *lockfname = "\\torture.lck";
+ fstring fname;
+ int fnum;
+ int fnum2;
+ pid_t pid2, pid = getpid();
+ int i, j;
+ char buf[1024];
+ BOOL correct = True;
+
+ fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum2 == -1)
+ fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
+ return False;
+ }
+
+
+ for (i=0;i<numops;i++) {
+ unsigned n = (unsigned)sys_random()%10;
+ if (i % 10 == 0) {
+ printf("%d\r", i); fflush(stdout);
+ }
+ slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
+
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return False;
+ }
+
+ fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ if (fnum == -1) {
+ printf("open failed (%s)\n", cli_errstr(c));
+ correct = False;
+ break;
+ }
+
+ if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ for (j=0;j<50;j++) {
+ if (cli_write(c, fnum, 0, (char *)buf,
+ sizeof(pid)+(j*sizeof(buf)),
+ sizeof(buf)) != sizeof(buf)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+
+ pid2 = 0;
+
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (pid2 != pid) {
+ printf("data corruption!\n");
+ correct = False;
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+
+ cli_close(c, fnum2);
+ cli_unlink(c, lockfname);
+
+ printf("%d\n", i);
+
+ return correct;
+}
+
+static BOOL run_torture(int dummy)
+{
+ struct cli_state cli;
+ BOOL ret;
+
+ cli = current_cli;
+
+ cli_sockopt(&cli, sockops);
+
+ ret = rw_torture(&cli);
+
+ if (!torture_close_connection(&cli)) {
+ ret = False;
+ }
+
+ return ret;
+}
+
+static BOOL rw_torture3(struct cli_state *c, char *lockfname)
+{
+ int fnum = -1;
+ int i = 0;
+ char buf[131072];
+ char buf_rd[131072];
+ unsigned count;
+ unsigned countprev = 0;
+ ssize_t sent = 0;
+ BOOL correct = True;
+
+ srandom(1);
+ for (i = 0; i < sizeof(buf); i += sizeof(uint32))
+ {
+ SIVAL(buf, i, sys_random());
+ }
+
+ if (procnum == 0)
+ {
+ fnum = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum == -1) {
+ printf("first open read/write of %s failed (%s)\n",
+ lockfname, cli_errstr(c));
+ return False;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 500 && fnum == -1; i++)
+ {
+ fnum = cli_open(c, lockfname, O_RDONLY,
+ DENY_NONE);
+ msleep(10);
+ }
+ if (fnum == -1) {
+ printf("second open read-only of %s failed (%s)\n",
+ lockfname, cli_errstr(c));
+ return False;
+ }
+ }
+
+ i = 0;
+ for (count = 0; count < sizeof(buf); count += sent)
+ {
+ if (count >= countprev) {
+ printf("%d %8d\r", i, count);
+ fflush(stdout);
+ i++;
+ countprev += (sizeof(buf) / 20);
+ }
+
+ if (procnum == 0)
+ {
+ sent = ((unsigned)sys_random()%(20))+ 1;
+ if (sent > sizeof(buf) - count)
+ {
+ sent = sizeof(buf) - count;
+ }
+
+ if (cli_write(c, fnum, 0, buf+count, count, (size_t)sent) != sent) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+ }
+ else
+ {
+ sent = cli_read(c, fnum, buf_rd+count, count,
+ sizeof(buf)-count);
+ if (sent < 0)
+ {
+ printf("read failed offset:%d size:%d (%s)\n",
+ count, sizeof(buf)-count,
+ cli_errstr(c));
+ correct = False;
+ sent = 0;
+ }
+ if (sent > 0)
+ {
+ if (memcmp(buf_rd+count, buf+count, sent) != 0)
+ {
+ printf("read/write compare failed\n");
+ printf("offset: %d req %d recvd %d\n",
+ count, sizeof(buf)-count, sent);
+ correct = False;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ correct = False;
+ }
+
+ return correct;
+}
+
+static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
+{
+ char *lockfname = "\\torture2.lck";
+ int fnum1;
+ int fnum2;
+ int i;
+ uchar buf[131072];
+ uchar buf_rd[131072];
+ BOOL correct = True;
+ ssize_t bytes_read;
+
+ if (!cli_unlink(c1, lockfname)) {
+ printf("unlink failed (%s) (normal, this file should not exist)\n", cli_errstr(c1));
+ }
+
+ fnum1 = cli_open(c1, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum1 == -1) {
+ printf("first open read/write of %s failed (%s)\n",
+ lockfname, cli_errstr(c1));
+ return False;
+ }
+ fnum2 = cli_open(c2, lockfname, O_RDONLY,
+ DENY_NONE);
+ if (fnum2 == -1) {
+ printf("second open read-only of %s failed (%s)\n",
+ lockfname, cli_errstr(c2));
+ cli_close(c1, fnum1);
+ return False;
+ }
+
+ for (i=0;i<numops;i++)
+ {
+ size_t buf_size = ((unsigned)sys_random()%(sizeof(buf)-1))+ 1;
+ if (i % 10 == 0) {
+ printf("%d\r", i); fflush(stdout);
+ }
+
+ generate_random_buffer(buf, buf_size, False);
+
+ if (cli_write(c1, fnum1, 0, buf, 0, buf_size) != buf_size) {
+ printf("write failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ }
+
+ if ((bytes_read = cli_read(c2, fnum2, buf_rd, 0, buf_size)) != buf_size) {
+ printf("read failed (%s)\n", cli_errstr(c2));
+ printf("read %d, expected %d\n", bytes_read, buf_size);
+ correct = False;
+ }
+
+ if (memcmp(buf_rd, buf, buf_size) != 0)
+ {
+ printf("read/write compare failed\n");
+ correct = False;
+ }
+ }
+
+ if (!cli_close(c2, fnum2)) {
+ printf("close failed (%s)\n", cli_errstr(c2));
+ correct = False;
+ }
+ if (!cli_close(c1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ }
+
+ if (!cli_unlink(c1, lockfname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c1));
+ correct = False;
+ }
+
+ return correct;
+}
+
+static BOOL run_readwritetest(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ BOOL test1, test2;
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting readwritetest\n");
+
+ test1 = rw_torture2(&cli1, &cli2);
+ printf("Passed readwritetest v1: %s\n", BOOLSTR(test1));
+
+ test2 = rw_torture2(&cli1, &cli1);
+ printf("Passed readwritetest v2: %s\n", BOOLSTR(test2));
+
+ if (!torture_close_connection(&cli1)) {
+ test1 = False;
+ }
+
+ if (!torture_close_connection(&cli2)) {
+ test2 = False;
+ }
+
+ return (test1 && test2);
+}
+
+static BOOL run_readwritemulti(int dummy)
+{
+ static struct cli_state cli;
+ BOOL test;
+
+ cli = current_cli;
+
+ cli_sockopt(&cli, sockops);
+
+ printf("run_readwritemulti: fname %s\n", randomfname);
+ test = rw_torture3(&cli, randomfname);
+
+ if (!torture_close_connection(&cli)) {
+ test = False;
+ }
+
+ return test;
+}
+
+static BOOL run_readwritelarge(int dummy)
+{
+ static struct cli_state cli1;
+ int fnum1;
+ char *lockfname = "\\large.dat";
+ size_t fsize;
+ char buf[0x10000];
+ BOOL correct = True;
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+ memset(buf,'\0',sizeof(buf));
+
+ cli1.max_xmit = 0x11000;
+
+ printf("starting readwritelarge\n");
+
+ cli_unlink(&cli1, lockfname);
+
+ fnum1 = cli_open(&cli1, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open read/write of %s failed (%s)\n", lockfname, cli_errstr(&cli1));
+ return False;
+ }
+
+ cli_write(&cli1, fnum1, 0, buf, 0, sizeof(buf));
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ if (!cli_qpathinfo(&cli1, lockfname, NULL, NULL, NULL, &fsize, NULL)) {
+ printf("qpathinfo failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ if (fsize == sizeof(buf))
+ printf("readwritelarge test 1 succeeded (size = %x)\n", fsize);
+ else {
+ printf("readwritelarge test 1 failed (size = %x)\n", fsize);
+ correct = False;
+ }
+
+ if (!cli_unlink(&cli1, lockfname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ fnum1 = cli_open(&cli1, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open read/write of %s failed (%s)\n", lockfname, cli_errstr(&cli1));
+ return False;
+ }
+
+ cli_smbwrite(&cli1, fnum1, buf, 0, sizeof(buf));
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+ return correct;
+ }
+
+int line_count = 0;
+
+/* run a test that simulates an approximate netbench client load */
+static BOOL run_netbench(int client)
+{
+ struct cli_state cli;
+ int i;
+ fstring fname;
+ pstring line;
+ char cname[20];
+ FILE *f;
+ char *params[20];
+ BOOL correct = True;
+
+ cli = current_cli;
+
+ cli_sockopt(&cli, sockops);
+
+ nb_setup(&cli);
+
+ slprintf(cname,sizeof(fname), "CLIENT%d", client);
+
+ f = fopen("client.txt", "r");
+
+ if (!f) {
+ perror("client.txt");
+ return False;
+ }
+
+ while (fgets(line, sizeof(line)-1, f)) {
+ line_count++;
+
+ line[strlen(line)-1] = 0;
+
+ /* printf("[%d] %s\n", line_count, line); */
+
+ all_string_sub(line,"CLIENT1", cname, sizeof(line));
+
+ for (i=0;i<20;i++) params[i] = "";
+
+ /* parse the command parameters */
+ params[0] = strtok(line," ");
+ i = 0;
+ while (params[i]) params[++i] = strtok(NULL," ");
+
+ params[i] = "";
+
+ if (i < 2) continue;
+
+ if (strcmp(params[1],"REQUEST") == 0) {
+ if (!strcmp(params[0],"SMBopenX")) {
+ fstrcpy(fname, params[5]);
+ } else if (!strcmp(params[0],"SMBclose")) {
+ nb_close(atoi(params[3]));
+ } else if (!strcmp(params[0],"SMBmkdir")) {
+ nb_mkdir(params[3]);
+ } else if (!strcmp(params[0],"CREATE")) {
+ nb_create(params[3], atoi(params[5]));
+ } else if (!strcmp(params[0],"SMBrmdir")) {
+ nb_rmdir(params[3]);
+ } else if (!strcmp(params[0],"SMBunlink")) {
+ fstrcpy(fname, params[3]);
+ } else if (!strcmp(params[0],"SMBmv")) {
+ nb_rename(params[3], params[5]);
+ } else if (!strcmp(params[0],"SMBgetatr")) {
+ fstrcpy(fname, params[3]);
+ } else if (!strcmp(params[0],"SMBwrite")) {
+ nb_write(atoi(params[3]),
+ atoi(params[5]), atoi(params[7]));
+ } else if (!strcmp(params[0],"SMBwritebraw")) {
+ nb_write(atoi(params[3]),
+ atoi(params[7]), atoi(params[5]));
+ } else if (!strcmp(params[0],"SMBreadbraw")) {
+ nb_read(atoi(params[3]),
+ atoi(params[7]), atoi(params[5]));
+ } else if (!strcmp(params[0],"SMBread")) {
+ nb_read(atoi(params[3]),
+ atoi(params[5]), atoi(params[7]));
+ }
+ } else {
+ if (!strcmp(params[0],"SMBopenX")) {
+ if (!strncmp(params[2], "ERR", 3)) continue;
+ nb_open(fname, atoi(params[3]), atoi(params[5]));
+ } else if (!strcmp(params[0],"SMBgetatr")) {
+ if (!strncmp(params[2], "ERR", 3)) continue;
+ nb_stat(fname, atoi(params[3]));
+ } else if (!strcmp(params[0],"SMBunlink")) {
+ if (!strncmp(params[2], "ERR", 3)) continue;
+ nb_unlink(fname);
+ }
+ }
+ }
+ fclose(f);
+
+ slprintf(fname,sizeof(fname), "CLIENTS/CLIENT%d", client);
+ rmdir(fname);
+ rmdir("CLIENTS");
+
+ printf("+");
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+
+/* run a test that simulates an approximate netbench w9X client load */
+static BOOL run_nbw95(int dummy)
+{
+ double t;
+ BOOL correct = True;
+ t = create_procs(run_netbench, &correct);
+ /* to produce a netbench result we scale accoding to the
+ netbench measured throughput for the run that produced the
+ sniff that was used to produce client.txt. That run used 2
+ clients and ran for 660 seconds to produce a result of
+ 4MBit/sec. */
+ printf("Throughput %g MB/sec (NB=%g MB/sec %g MBit/sec)\n",
+ 132*nprocs/t, 0.5*0.5*nprocs*660/t, 2*nprocs*660/t);
+ return correct;
+}
+
+/* run a test that simulates an approximate netbench wNT client load */
+static BOOL run_nbwnt(int dummy)
+{
+ double t;
+ BOOL correct = True;
+ t = create_procs(run_netbench, &correct);
+ printf("Throughput %g MB/sec (NB=%g MB/sec %g MBit/sec)\n",
+ 132*nprocs/t, 0.5*0.5*nprocs*660/t, 2*nprocs*660/t);
+ return correct;
+}
+
+
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static BOOL run_locktest1(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt1.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest1\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+ fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return False;
+ }
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, &cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+
+ printf("Testing lock timeouts\n");
+ t1 = time(NULL);
+ if (cli_lock(&cli2, fnum3, 0, 4, 10*1000, WRITE_LOCK)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, &cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+ t2 = time(NULL);
+
+ if (t2 - t1 < 5) {
+ printf("error: This server appears not to support timed lock requests\n");
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return False;
+ } else {
+ if (!check_error(__LINE__, &cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli2));
+ return False;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+
+ if (!torture_close_connection(&cli1)) {
+ return False;
+ }
+
+ if (!torture_close_connection(&cli2)) {
+ return False;
+ }
+
+ printf("Passed locktest1\n");
+ return True;
+}
+
+/*
+ checks for correct tconX support
+ */
+static BOOL run_tcon_test(int dummy)
+{
+ static struct cli_state cli1;
+ char *fname = "\\tcontest.tmp";
+ int fnum1;
+ uint16 cnum;
+ char buf[4];
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+
+ printf("starting tcontest\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1)
+ {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ cnum = cli1.cnum;
+
+ if (cli_write(&cli1, fnum1, 0, buf, 130, 4) != 4)
+ {
+ printf("write failed (%s)", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_send_tconX(&cli1, share, "?????",
+ password, strlen(password)+1)) {
+ printf("%s refused 2nd tree connect (%s)\n", host,
+ cli_errstr(&cli1));
+ cli_shutdown(&cli1);
+ return False;
+ }
+
+ if (cli_write(&cli1, fnum1, 0, buf, 130, 4) == 4)
+ {
+ printf("write succeeded (%s)", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (cli_close(&cli1, fnum1)) {
+ printf("close2 succeeded (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_tdis(&cli1)) {
+ printf("tdis failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ cli1.cnum = cnum;
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ return False;
+ }
+
+ printf("Passed tcontest\n");
+ return True;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static BOOL run_locktest2(int dummy)
+{
+ static struct cli_state cli;
+ char *fname = "\\lockt2.lck";
+ int fnum1, fnum2, fnum3;
+ BOOL correct = True;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting locktest2\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return False;
+ }
+
+ fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return False;
+ }
+
+ cli_setpid(&cli, 2);
+
+ fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return False;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_lock(&cli, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli));
+ return False;
+ }
+
+ if (cli_lock(&cli, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("WRITE lock1 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0, WRITE_LOCK)) {
+ printf("WRITE lock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0, READ_LOCK)) {
+ printf("READ lock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (!cli_lock(&cli, fnum1, 100, 4, 0, WRITE_LOCK)) {
+ printf("lock at 100 failed (%s)\n", cli_errstr(&cli));
+ }
+ cli_setpid(&cli, 2);
+ if (cli_unlock(&cli, fnum1, 100, 4)) {
+ printf("unlock at 100 succeeded! This is a locking bug\n");
+ correct = False;
+ }
+
+ if (cli_unlock(&cli, fnum1, 0, 4)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli,
+ ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_unlock(&cli, fnum1, 0, 8)) {
+ printf("unlock2 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli,
+ ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ if (cli_lock(&cli, fnum3, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ correct = False;
+ } else {
+ if (!check_error(__LINE__, &cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_close(&cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli));
+ return False;
+ }
+
+ if (!cli_close(&cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli));
+ return False;
+ }
+
+ if (!cli_close(&cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli));
+ return False;
+ }
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("locktest2 finished\n");
+
+ return correct;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports the full offset range in lock requests
+*/
+static BOOL run_locktest3(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt3.lck";
+ int fnum1, fnum2, i;
+ uint32 offset;
+ BOOL correct = True;
+
+#define NEXT_OFFSET offset += (~(uint32)0) / numops
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest3\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return False;
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+ if (!cli_lock(&cli1, fnum1, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("lock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_lock(&cli2, fnum2, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("lock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return False;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (cli_lock(&cli1, fnum1, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("error: lock1 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("error: lock2 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(&cli1, fnum1, offset-1, 1, 0, WRITE_LOCK)) {
+ printf("error: lock3 %d succeeded!\n", i);
+ return False;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-2, 1, 0, WRITE_LOCK)) {
+ printf("error: lock4 %d succeeded!\n", i);
+ return False;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (!cli_unlock(&cli1, fnum1, offset-1, 1)) {
+ printf("unlock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_unlock(&cli2, fnum2, offset-2, 1)) {
+ printf("unlock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return False;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli2));
+ return False;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+
+ if (!torture_close_connection(&cli2)) {
+ correct = False;
+ }
+
+ printf("finished locktest3\n");
+
+ return correct;
+}
+
+#define EXPECTED(ret, v) if ((ret) != (v)) { \
+ printf("** "); correct = False; \
+ }
+
+/*
+ looks at overlapping locks
+*/
+static BOOL run_locktest4(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt4.lck";
+ int fnum1, fnum2, f;
+ BOOL ret;
+ char buf[1000];
+ BOOL correct = True;
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest4\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (cli_write(&cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to create file\n");
+ correct = False;
+ goto fail;
+ }
+
+ ret = cli_lock(&cli1, fnum1, 0, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 2, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 10, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 12, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 20, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli2, fnum2, 22, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("a different connection %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 30, 4, 0, READ_LOCK) &&
+ cli_lock(&cli2, fnum2, 32, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("a different connection %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(&cli1, 1), cli_lock(&cli1, fnum1, 40, 4, 0, WRITE_LOCK)) &&
+ (cli_setpid(&cli1, 2), cli_lock(&cli1, fnum1, 42, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, False);
+ printf("a different pid %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(&cli1, 1), cli_lock(&cli1, fnum1, 50, 4, 0, READ_LOCK)) &&
+ (cli_setpid(&cli1, 2), cli_lock(&cli1, fnum1, 52, 4, 0, READ_LOCK));
+ EXPECTED(ret, True);
+ printf("a different pid %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 60, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 60, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s set the same read lock twice\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 70, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 70, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s set the same write lock twice\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 80, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 80, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, False);
+ printf("the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 90, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 90, 4, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = (cli_setpid(&cli1, 1), cli_lock(&cli1, fnum1, 100, 4, 0, WRITE_LOCK)) &&
+ (cli_setpid(&cli1, 2), cli_lock(&cli1, fnum1, 100, 4, 0, READ_LOCK));
+ EXPECTED(ret, False);
+ printf("a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 110, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 112, 4, 0, READ_LOCK) &&
+ cli_unlock(&cli1, fnum1, 110, 6);
+ EXPECTED(ret, False);
+ printf("the same process %s coalesce read locks\n", ret?"can":"cannot");
+
+
+ ret = cli_lock(&cli1, fnum1, 120, 4, 0, WRITE_LOCK) &&
+ (cli_read(&cli2, fnum2, buf, 120, 4) == 4);
+ EXPECTED(ret, False);
+ printf("this server %s strict write locking\n", ret?"doesn't do":"does");
+
+ ret = cli_lock(&cli1, fnum1, 130, 4, 0, READ_LOCK) &&
+ (cli_write(&cli2, fnum2, 0, buf, 130, 4) == 4);
+ EXPECTED(ret, False);
+ printf("this server %s strict read locking\n", ret?"doesn't do":"does");
+
+
+ ret = cli_lock(&cli1, fnum1, 140, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 140, 4, 0, READ_LOCK) &&
+ cli_unlock(&cli1, fnum1, 140, 4) &&
+ cli_unlock(&cli1, fnum1, 140, 4);
+ EXPECTED(ret, True);
+ printf("this server %s do recursive read locking\n", ret?"does":"doesn't");
+
+
+ ret = cli_lock(&cli1, fnum1, 150, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 150, 4, 0, READ_LOCK) &&
+ cli_unlock(&cli1, fnum1, 150, 4) &&
+ (cli_read(&cli2, fnum2, buf, 150, 4) == 4) &&
+ !(cli_write(&cli2, fnum2, 0, buf, 150, 4) == 4) &&
+ cli_unlock(&cli1, fnum1, 150, 4);
+ EXPECTED(ret, True);
+ printf("this server %s do recursive lock overlays\n", ret?"does":"doesn't");
+
+ ret = cli_lock(&cli1, fnum1, 160, 4, 0, READ_LOCK) &&
+ cli_unlock(&cli1, fnum1, 160, 4) &&
+ (cli_write(&cli2, fnum2, 0, buf, 160, 4) == 4) &&
+ (cli_read(&cli2, fnum2, buf, 160, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 170, 4, 0, WRITE_LOCK) &&
+ cli_unlock(&cli1, fnum1, 170, 4) &&
+ (cli_write(&cli2, fnum2, 0, buf, 170, 4) == 4) &&
+ (cli_read(&cli2, fnum2, buf, 170, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli1, fnum1, 190, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 190, 4, 0, READ_LOCK) &&
+ cli_unlock(&cli1, fnum1, 190, 4) &&
+ !(cli_write(&cli2, fnum2, 0, buf, 190, 4) == 4) &&
+ (cli_read(&cli2, fnum2, buf, 190, 4) == 4);
+ EXPECTED(ret, True);
+ printf("the same process %s remove the first lock first\n", ret?"does":"doesn't");
+
+ cli_close(&cli1, fnum1);
+ cli_close(&cli2, fnum2);
+ fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ f = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ ret = cli_lock(&cli1, fnum1, 0, 8, 0, READ_LOCK) &&
+ cli_lock(&cli1, f, 0, 1, 0, READ_LOCK) &&
+ cli_close(&cli1, fnum1) &&
+ ((fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE)) != -1) &&
+ cli_lock(&cli1, fnum1, 7, 1, 0, WRITE_LOCK);
+ cli_close(&cli1, f);
+ EXPECTED(ret, True);
+ printf("the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
+
+ fail:
+ cli_close(&cli1, fnum1);
+ cli_close(&cli2, fnum2);
+ cli_unlink(&cli1, fname);
+ torture_close_connection(&cli1);
+ torture_close_connection(&cli2);
+
+ printf("finished locktest4\n");
+ return correct;
+}
+
+/*
+ looks at lock upgrade/downgrade.
+*/
+static BOOL run_locktest5(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt5.lck";
+ int fnum1, fnum2, fnum3;
+ BOOL ret;
+ char buf[1000];
+ BOOL correct = True;
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest5\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ fnum3 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (cli_write(&cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to create file\n");
+ correct = False;
+ goto fail;
+ }
+
+ /* Check for NT bug... */
+ ret = cli_lock(&cli1, fnum1, 0, 8, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum3, 0, 1, 0, READ_LOCK);
+ cli_close(&cli1, fnum1);
+ fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ ret = cli_lock(&cli1, fnum1, 7, 1, 0, WRITE_LOCK);
+ EXPECTED(ret, True);
+ printf("this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
+ cli_close(&cli1, fnum1);
+ fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ cli_unlock(&cli1, fnum3, 0, 1);
+
+ ret = cli_lock(&cli1, fnum1, 0, 4, 0, WRITE_LOCK) &&
+ cli_lock(&cli1, fnum1, 1, 1, 0, READ_LOCK);
+ EXPECTED(ret, True);
+ printf("the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
+
+ ret = cli_lock(&cli2, fnum2, 0, 4, 0, READ_LOCK);
+ EXPECTED(ret, False);
+
+ printf("a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
+
+ /* Unlock the process 2 lock. */
+ cli_unlock(&cli2, fnum2, 0, 4);
+
+ ret = cli_lock(&cli1, fnum3, 0, 4, 0, READ_LOCK);
+ EXPECTED(ret, False);
+
+ printf("the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
+
+ /* Unlock the process 1 fnum3 lock. */
+ cli_unlock(&cli1, fnum3, 0, 4);
+
+ /* Stack 2 more locks here. */
+ ret = cli_lock(&cli1, fnum1, 0, 4, 0, READ_LOCK) &&
+ cli_lock(&cli1, fnum1, 0, 4, 0, READ_LOCK);
+
+ EXPECTED(ret, True);
+ printf("the same process %s stack read locks\n", ret?"can":"cannot");
+
+ /* Unlock the first process lock, then check this was the WRITE lock that was
+ removed. */
+
+ ret = cli_unlock(&cli1, fnum1, 0, 4) &&
+ cli_lock(&cli2, fnum2, 0, 4, 0, READ_LOCK);
+
+ EXPECTED(ret, True);
+ printf("the first unlock removes the %s lock\n", ret?"WRITE":"READ");
+
+ /* Unlock the process 2 lock. */
+ cli_unlock(&cli2, fnum2, 0, 4);
+
+ /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
+
+ ret = cli_unlock(&cli1, fnum1, 1, 1) &&
+ cli_unlock(&cli1, fnum1, 0, 4) &&
+ cli_unlock(&cli1, fnum1, 0, 4);
+
+ EXPECTED(ret, True);
+ printf("the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
+
+ /* Ensure the next unlock fails. */
+ ret = cli_unlock(&cli1, fnum1, 0, 4);
+ EXPECTED(ret, False);
+ printf("the same process %s count the lock stack\n", !ret?"can":"cannot");
+
+ /* Ensure connection 2 can get a write lock. */
+ ret = cli_lock(&cli2, fnum2, 0, 4, 0, WRITE_LOCK);
+ EXPECTED(ret, True);
+
+ printf("a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
+
+
+ fail:
+ cli_close(&cli1, fnum1);
+ cli_close(&cli2, fnum2);
+ cli_unlink(&cli1, fname);
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(&cli2)) {
+ correct = False;
+ }
+
+ printf("finished locktest5\n");
+
+ return correct;
+}
+
+/*
+test whether fnums and tids open on one VC are available on another (a major
+security hole)
+*/
+static BOOL run_fdpasstest(int dummy)
+{
+ static struct cli_state cli1, cli2, cli3;
+ char *fname = "\\fdpass.tst";
+ int fnum1;
+ pstring buf;
+
+ if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+ return False;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting fdpasstest\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
+ printf("write failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ cli3 = cli2;
+ cli3.vuid = cli1.vuid;
+ cli3.cnum = cli1.cnum;
+ cli3.pid = cli1.pid;
+
+ if (cli_read(&cli3, fnum1, buf, 0, 13) == 13) {
+ printf("read succeeded! nasty security hole [%s]\n",
+ buf);
+ return False;
+ }
+
+ cli_close(&cli1, fnum1);
+ cli_unlink(&cli1, fname);
+
+ torture_close_connection(&cli1);
+ torture_close_connection(&cli2);
+
+ printf("finished fdpasstest\n");
+ return True;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server does not allow an unlink on a file that is open
+*/
+static BOOL run_unlinktest(int dummy)
+{
+ static struct cli_state cli;
+ char *fname = "\\unlink.tst";
+ int fnum;
+ BOOL correct = True;
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting unlink test\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return False;
+ }
+
+ if (cli_unlink(&cli, fname)) {
+ printf("error: server allowed unlink on an open file\n");
+ correct = False;
+ } else {
+ correct = check_error(__LINE__, &cli, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+ }
+
+ cli_close(&cli, fnum);
+ cli_unlink(&cli, fname);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("unlink test finished\n");
+
+ return correct;
+}
+
+
+/*
+test how many open files this server supports on the one socket
+*/
+static BOOL run_maxfidtest(int dummy)
+{
+ static struct cli_state cli;
+ char *template = "\\maxfid.%d.%d";
+ fstring fname;
+ int fnums[0x11000], i;
+ int retries=4;
+ BOOL correct = True;
+
+ cli = current_cli;
+
+ if (retries <= 0) {
+ printf("failed to connect\n");
+ return False;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ for (i=0; i<0x11000; i++) {
+ slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+ if ((fnums[i] = cli_open(&cli, fname,
+ O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
+ -1) {
+ printf("open of %s failed (%s)\n",
+ fname, cli_errstr(&cli));
+ printf("maximum fnum is %d\n", i);
+ break;
+ }
+ printf("%6d\r", i);
+ }
+ printf("%6d\n", i);
+ i--;
+
+ printf("cleaning up\n");
+ for (;i>=0;i--) {
+ slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+ cli_close(&cli, fnums[i]);
+ if (!cli_unlink(&cli, fname)) {
+ printf("unlink of %s failed (%s)\n",
+ fname, cli_errstr(&cli));
+ correct = False;
+ }
+ printf("%6d\r", i);
+ }
+ printf("%6d\n", 0);
+
+ printf("maxfid test finished\n");
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+ return correct;
+}
+
+/* generate a random buffer */
+static void rand_buf(char *buf, int len)
+{
+ while (len--) {
+ *buf = (char)sys_random();
+ buf++;
+ }
+}
+
+/* send smb negprot commands, not reading the response */
+static BOOL run_negprot_nowait(int dummy)
+{
+ int i;
+ static struct cli_state cli;
+ BOOL correct = True;
+
+ printf("starting negprot nowait test\n");
+
+ if (!open_nbt_connection(&cli)) {
+ return False;
+ }
+
+ for (i=0;i<50000;i++) {
+ cli_negprot_send(&cli);
+ }
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("finished negprot nowait test\n");
+
+ return correct;
+}
+
+
+/* send random IPC commands */
+static BOOL run_randomipc(int dummy)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ pstring param;
+ int api, param_len, i;
+ static struct cli_state cli;
+ BOOL correct = True;
+ int count = 50000;
+
+ printf("starting random ipc test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ for (i=0;i<count;i++) {
+ api = sys_random() % 500;
+ param_len = (sys_random() % 64);
+
+ rand_buf(param, param_len);
+
+ SSVAL(param,0,api);
+
+ cli_api(&cli,
+ param, param_len, 8,
+ NULL, 0, BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt);
+ if (i % 100 == 0) {
+ printf("%d/%d\r", i,count);
+ }
+ }
+ printf("%d/%d\n", i, count);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("finished random ipc test\n");
+
+ return correct;
+}
+
+
+
+static void browse_callback(const char *sname, uint32 stype,
+ const char *comment, void *state)
+{
+ printf("\t%20.20s %08x %s\n", sname, stype, comment);
+}
+
+
+
+/*
+ This test checks the browse list code
+
+*/
+static BOOL run_browsetest(int dummy)
+{
+ static struct cli_state cli;
+ BOOL correct = True;
+
+ printf("starting browse test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ printf("domain list:\n");
+ cli_NetServerEnum(&cli, cli.server_domain,
+ SV_TYPE_DOMAIN_ENUM,
+ browse_callback, NULL);
+
+ printf("machine list:\n");
+ cli_NetServerEnum(&cli, cli.server_domain,
+ SV_TYPE_ALL,
+ browse_callback, NULL);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("browse test finished\n");
+
+ return correct;
+
+}
+
+
+/*
+ This checks how the getatr calls works
+*/
+static BOOL run_attrtest(int dummy)
+{
+ static struct cli_state cli;
+ int fnum;
+ time_t t, t2;
+ char *fname = "\\attrib.tst";
+ BOOL correct = True;
+
+ printf("starting attrib test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+ if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ }
+
+ if (abs(t - time(NULL)) > 2) {
+ printf("ERROR: SMBgetatr bug. time is %s",
+ ctime(&t));
+ t = time(NULL);
+ correct = True;
+ }
+
+ t2 = t-60*60*24; /* 1 day ago */
+
+ if (!cli_setatr(&cli, fname, 0, t2)) {
+ printf("setatr failed (%s)\n", cli_errstr(&cli));
+ correct = True;
+ }
+
+ if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(&cli));
+ correct = True;
+ }
+
+ if (t != t2) {
+ printf("ERROR: getatr/setatr bug. times are\n%s",
+ ctime(&t));
+ printf("%s", ctime(&t2));
+ correct = True;
+ }
+
+ cli_unlink(&cli, fname);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("attrib test finished\n");
+
+ return correct;
+}
+
+
+/*
+ This checks a couple of trans2 calls
+*/
+static BOOL run_trans2test(int dummy)
+{
+ static struct cli_state cli;
+ int fnum;
+ size_t size;
+ time_t c_time, a_time, m_time, w_time, m_time2;
+ char *fname = "\\trans2.tst";
+ char *dname = "\\trans2";
+ char *fname2 = "\\trans2\\trans2.tst";
+ BOOL correct = True;
+
+ printf("starting trans2 test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
+ NULL, NULL)) {
+ printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ }
+ cli_close(&cli, fnum);
+
+ sleep(2);
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return False;
+ }
+ cli_close(&cli, fnum);
+
+ if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
+ printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ } else {
+ if (c_time != m_time) {
+ printf("create time=%s", ctime(&c_time));
+ printf("modify time=%s", ctime(&m_time));
+ printf("This system appears to have sticky create times\n");
+ correct = False;
+ }
+ if (a_time % (60*60) == 0) {
+ printf("access time=%s", ctime(&a_time));
+ printf("This system appears to set a midnight access time\n");
+ correct = False;
+ }
+
+ if (abs(m_time - time(NULL)) > 60*60*24*7) {
+ printf("ERROR: totally incorrect times - maybe word reversed? mtime=%s", ctime(&m_time));
+ correct = False;
+ }
+ }
+
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+ if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
+ &w_time, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ } else {
+ if (w_time < 60*60*24*2) {
+ printf("write time=%s", ctime(&w_time));
+ printf("This system appears to set a initial 0 write time\n");
+ correct = False;
+ }
+ }
+
+ cli_unlink(&cli, fname);
+
+
+ /* check if the server updates the directory modification time
+ when creating a new file */
+ if (!cli_mkdir(&cli, dname)) {
+ printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ }
+ sleep(3);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
+ &w_time, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ }
+
+ fnum = cli_open(&cli, fname2,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
+ cli_close(&cli, fnum);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
+ &w_time, &size, NULL, NULL)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ correct = False;
+ } else {
+ if (m_time2 == m_time) {
+ printf("This system does not update directory modification times\n");
+ correct = False;
+ }
+ }
+ cli_unlink(&cli, fname2);
+ cli_rmdir(&cli, dname);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("trans2 test finished\n");
+
+ return correct;
+}
+
+/*
+ This checks new W2K calls.
+*/
+
+static BOOL new_trans(struct cli_state *pcli, int fnum, int level)
+{
+ char buf[4096];
+ BOOL correct = True;
+
+ memset(buf, 0xff, sizeof(buf));
+
+ if (!cli_qfileinfo_test(pcli, fnum, level, buf)) {
+ printf("ERROR: qfileinfo (%d) failed (%s)\n", level, cli_errstr(pcli));
+ correct = False;
+ } else {
+ printf("qfileinfo: level %d\n", level);
+ dump_data(0, buf, 256);
+ printf("\n");
+ }
+ return correct;
+}
+
+static BOOL run_w2ktest(int dummy)
+{
+ static struct cli_state cli;
+ int fnum;
+ char *fname = "\\w2ktest\\w2k.tst";
+ int level;
+ BOOL correct = True;
+
+ printf("starting w2k test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT , DENY_NONE);
+
+ for (level = 1004; level < 1040; level++) {
+ new_trans(&cli, fnum, level);
+ }
+
+ cli_close(&cli, fnum);
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("w2k test finished\n");
+
+ return correct;
+}
+
+
+/*
+ this is a harness for some oplock tests
+ */
+static BOOL run_oplock1(int dummy)
+{
+ static struct cli_state cli1;
+ char *fname = "\\lockt1.lck";
+ int fnum1;
+ BOOL correct = True;
+
+ printf("starting oplock test 1\n");
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+
+ cli_unlink(&cli1, fname);
+
+ cli_sockopt(&cli1, sockops);
+
+ cli1.use_oplocks = True;
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ cli1.use_oplocks = False;
+
+ cli_unlink(&cli1, fname);
+ cli_unlink(&cli1, fname);
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+
+ printf("finished oplock test 1\n");
+
+ return correct;
+}
+
+static BOOL run_oplock2(int dummy)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt2.lck";
+ int fnum1, fnum2;
+ int saved_use_oplocks = use_oplocks;
+ char buf[4];
+ BOOL correct = True;
+ volatile BOOL *shared_correct;
+
+ shared_correct = (volatile BOOL *)shm_setup(sizeof(BOOL));
+ *shared_correct = True;
+
+ use_level_II_oplocks = True;
+ use_oplocks = True;
+
+ printf("starting oplock test 2\n");
+
+ if (!torture_open_connection(&cli1)) {
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+ return False;
+ }
+
+ cli1.use_oplocks = True;
+ cli1.use_level_II_oplocks = True;
+
+ if (!torture_open_connection(&cli2)) {
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+ return False;
+ }
+
+ cli2.use_oplocks = True;
+ cli2.use_level_II_oplocks = True;
+
+ cli_unlink(&cli1, fname);
+
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* Don't need the globals any more. */
+ use_level_II_oplocks = False;
+ use_oplocks = saved_use_oplocks;
+
+ if (fork() == 0) {
+ /* Child code */
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("second open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ *shared_correct = False;
+ exit(0);
+ }
+
+ sleep(2);
+
+ if (!cli_close(&cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ *shared_correct = False;
+ }
+
+ exit(0);
+ }
+
+ sleep(2);
+
+ /* Ensure cli1 processes the break. */
+
+ if (cli_read(&cli1, fnum1, buf, 0, 4) != 4) {
+ printf("read on fnum1 failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ /* Should now be at level II. */
+ /* Test if sending a write locks causes a break to none. */
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0, READ_LOCK)) {
+ printf("lock failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ cli_unlock(&cli1, fnum1, 0, 4);
+
+ sleep(2);
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0, WRITE_LOCK)) {
+ printf("lock failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ cli_unlock(&cli1, fnum1, 0, 4);
+
+ sleep(2);
+
+ cli_read(&cli1, fnum1, buf, 0, 4);
+
+#if 0
+ if (cli_write(&cli1, fnum1, 0, buf, 0, 4) != 4) {
+ printf("write on fnum1 failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+#endif
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ sleep(4);
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+
+ if (!*shared_correct) {
+ correct = False;
+ }
+
+ printf("finished oplock test 2\n");
+
+ return correct;
+}
+
+/* handler for oplock 3 tests */
+static BOOL oplock3_handler(struct cli_state *cli, int fnum, unsigned char level)
+{
+ printf("got oplock break fnum=%d level=%d\n",
+ fnum, level);
+ return cli_oplock_ack(cli, fnum, level);
+}
+
+static BOOL run_oplock3(int dummy)
+{
+ static struct cli_state cli;
+ char *fname = "\\oplockt3.dat";
+ int fnum;
+ char buf[4] = "abcd";
+ BOOL correct = True;
+ volatile BOOL *shared_correct;
+
+ shared_correct = (volatile BOOL *)shm_setup(sizeof(BOOL));
+ *shared_correct = True;
+
+ printf("starting oplock test 3\n");
+
+ if (fork() == 0) {
+ /* Child code */
+ use_oplocks = True;
+ use_level_II_oplocks = True;
+ if (!torture_open_connection(&cli)) {
+ *shared_correct = False;
+ exit(0);
+ }
+ sleep(2);
+ /* try to trigger a oplock break in parent */
+ fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ cli_write(&cli, fnum, 0, buf, 0, 4);
+ exit(0);
+ }
+
+ /* parent code */
+ use_oplocks = True;
+ use_level_II_oplocks = True;
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+ cli_oplock_handler(&cli, oplock3_handler);
+ fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ cli_write(&cli, fnum, 0, buf, 0, 4);
+ cli_close(&cli, fnum);
+ fnum = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ cli.timeout = 20000;
+ cli_receive_smb(&cli);
+ printf("finished oplock test 3\n");
+
+ return (correct && *shared_correct);
+
+/* What are we looking for here? What's sucess and what's FAILURE? */
+}
+
+
+
+/*
+ Test delete on close semantics.
+ */
+static BOOL run_deletetest(int dummy)
+{
+ static struct cli_state cli1;
+ static struct cli_state cli2;
+ char *fname = "\\delete.file";
+ int fnum1, fnum2;
+ BOOL correct = True;
+
+ printf("starting delete test\n");
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+
+ cli_sockopt(&cli1, sockops);
+
+ /* Test 1 - this should *NOT* delete the file on close. */
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_DELETE, FILE_OVERWRITE_IF,
+ DELETE_ON_CLOSE_FLAG);
+
+ if (fnum1 == -1) {
+ printf("[1] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[1] close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("[1] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[1] close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ printf("first delete on close test succeeded.\n");
+
+ /* Test 2 - this should delete the file on close. */
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE,
+ FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[2] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[2] setting delete_on_close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[2] close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[2] open of %s succeeded should have been deleted on close !\n", fname);
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[2] close failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+ cli_unlink(&cli1, fname);
+ } else
+ printf("second delete on close test succeeded.\n");
+
+ /* Test 3 - ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[3] open - 1 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should fail with a sharing violation - open for delete is only compatible
+ with SHARE_DELETE. */
+
+ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0);
+
+ if (fnum2 != -1) {
+ printf("[3] open - 2 of %s succeeded - should have failed.\n", fname);
+ return False;
+ }
+
+ /* This should succeed. */
+
+ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0);
+
+ if (fnum2 == -1) {
+ printf("[3] open - 2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[3] setting delete_on_close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[3] close 1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("[3] close 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should fail - file should no longer be there. */
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[3] open of %s succeeded should have been deleted on close !\n", fname);
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[3] close failed (%s)\n", cli_errstr(&cli1));
+ }
+ cli_unlink(&cli1, fname);
+ correct = False;
+ } else
+ printf("third delete on close test succeeded.\n");
+
+ /* Test 4 ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[4] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should succeed. */
+ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0);
+ if (fnum2 == -1) {
+ printf("[4] open - 2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("[4] close - 1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[4] setting delete_on_close failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should fail - no more opens once delete on close set. */
+ fnum2 = cli_nt_create_full(&cli1, fname, GENERIC_READ_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0);
+ if (fnum2 != -1) {
+ printf("[4] open - 3 of %s succeeded ! Should have failed.\n", fname );
+ return False;
+ } else
+ printf("fourth delete on close test succeeded.\n");
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[4] close - 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* Test 5 ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("[5] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ if (cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[5] setting delete_on_close on OpenX file succeeded - should fail !\n");
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[5] close - 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ printf("fifth delete on close test succeeded.\n");
+
+ /* Test 6 ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[6] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ if (cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[6] setting delete_on_close on file with no delete access succeeded - should fail !\n");
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[6] close - 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ printf("sixth delete on close test succeeded.\n");
+
+ /* Test 7 ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[7] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[7] setting delete_on_close on file failed !\n");
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, False)) {
+ printf("[7] unsetting delete_on_close on file failed !\n");
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[7] close - 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This next open should succeed - we reset the flag. */
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("[5] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[7] close - 2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ printf("seventh delete on close test succeeded.\n");
+
+ /* Test 7 ... */
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ if (!torture_open_connection(&cli2)) {
+ printf("[8] failed to open second connection.\n");
+ return False;
+ }
+
+ cli_sockopt(&cli1, sockops);
+
+ fnum1 = cli_nt_create_full(&cli1, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OVERWRITE_IF, 0);
+
+ if (fnum1 == -1) {
+ printf("[8] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ fnum2 = cli_nt_create_full(&cli2, fname, FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0);
+
+ if (fnum2 == -1) {
+ printf("[8] open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_nt_delete_on_close(&cli1, fnum1, True)) {
+ printf("[8] setting delete_on_close on file failed !\n");
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[8] close - 1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli2, fnum2)) {
+ printf("[8] close - 2 failed (%s)\n", cli_errstr(&cli2));
+ return False;
+ }
+
+ /* This should fail.. */
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("[8] open of %s succeeded should have been deleted on close !\n", fname);
+ if (!cli_close(&cli1, fnum1)) {
+ printf("[8] close failed (%s)\n", cli_errstr(&cli1));
+ }
+ cli_unlink(&cli1, fname);
+ correct = False;
+ } else
+ printf("eighth delete on close test succeeded.\n");
+
+ printf("finished delete test\n");
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+ if (!torture_close_connection(&cli2)) {
+ correct = False;
+ }
+ return correct;
+}
+
+/*
+ Test open mode returns on read-only files.
+ */
+static BOOL run_opentest(int dummy)
+{
+ static struct cli_state cli1;
+ char *fname = "\\readonly.file";
+ int fnum1, fnum2;
+ char buf[20];
+ size_t fsize;
+ BOOL correct = True;
+ char *tmp_path;
+
+ printf("starting open test\n");
+
+ if (!torture_open_connection(&cli1)) {
+ return False;
+ }
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ cli_sockopt(&cli1, sockops);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_setatr(&cli1, fname, aRONLY, 0)) {
+ printf("cli_setatr failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This will fail - but the error should be ERRnoaccess, not ERRbadshare. */
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__LINE__, &cli1, ERRDOS, ERRnoaccess,
+ NT_STATUS_ACCESS_DENIED)) {
+ printf("correct error code ERRDOS/ERRnoaccess returned\n");
+ }
+
+ printf("finished open test 1\n");
+
+ cli_close(&cli1, fnum1);
+
+ /* Now try not readonly and ensure ERRbadshare is returned. */
+
+ cli_setatr(&cli1, fname, 0, 0);
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* This will fail - but the error should be ERRshare. */
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__LINE__, &cli1, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION)) {
+ printf("correct error code ERRDOS/ERRbadshare returned\n");
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ cli_unlink(&cli1, fname);
+
+ printf("finished open test 2\n");
+
+ /* Test truncate open disposition on file opened for read. */
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("(3) open (1) of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ /* write 20 bytes. */
+
+ memset(buf, '\0', 20);
+
+ if (cli_write(&cli1, fnum1, 0, buf, 0, 20) != 20) {
+ printf("write failed (%s)\n", cli_errstr(&cli1));
+ correct = False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("(3) close1 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* Ensure size == 20. */
+ if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) {
+ printf("(3) getatr failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (fsize != 20) {
+ printf("(3) file size != 20\n");
+ return False;
+ }
+
+ /* Now test if we can truncate a file opened for readonly. */
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY|O_TRUNC, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("(3) open (2) of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return False;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ /* Ensure size == 0. */
+ if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) {
+ printf("(3) getatr failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+
+ if (fsize != 0) {
+ printf("(3) file size != 0\n");
+ return False;
+ }
+ printf("finished open test 3\n");
+
+ cli_unlink(&cli1, fname);
+
+
+ printf("testing ctemp\n");
+ fnum1 = cli_ctemp(&cli1, "\\", &tmp_path);
+ if (fnum1 == -1) {
+ printf("ctemp failed (%s)\n", cli_errstr(&cli1));
+ return False;
+ }
+ printf("ctemp gave path %s\n", tmp_path);
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close of temp failed (%s)\n", cli_errstr(&cli1));
+ }
+ if (!cli_unlink(&cli1, tmp_path)) {
+ printf("unlink of temp failed (%s)\n", cli_errstr(&cli1));
+ }
+
+ if (!torture_close_connection(&cli1)) {
+ correct = False;
+ }
+
+ return correct;
+}
+
+static void list_fn(file_info *finfo, const char *name, void *state)
+{
+
+}
+
+/*
+ test directory listing speed
+ */
+static BOOL run_dirtest(int dummy)
+{
+ int i;
+ static struct cli_state cli;
+ int fnum;
+ double t1;
+ BOOL correct = True;
+
+ printf("starting directory test\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ srandom(0);
+ for (i=0;i<numops;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "%x", (int)random());
+ fnum = cli_open(&cli, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ fprintf(stderr,"Failed to open %s\n", fname);
+ return False;
+ }
+ cli_close(&cli, fnum);
+ }
+
+ t1 = end_timer();
+
+ printf("Matched %d\n", cli_list(&cli, "a*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(&cli, "b*.*", 0, list_fn, NULL));
+ printf("Matched %d\n", cli_list(&cli, "xyzabc", 0, list_fn, NULL));
+
+ printf("dirtest core %g seconds\n", end_timer() - t1);
+
+ srandom(0);
+ for (i=0;i<numops;i++) {
+ fstring fname;
+ slprintf(fname, sizeof(fname), "%x", (int)random());
+ cli_unlink(&cli, fname);
+ }
+
+ if (!torture_close_connection(&cli)) {
+ correct = False;
+ }
+
+ printf("finished dirtest\n");
+
+ return correct;
+}
+
+static BOOL run_error_map_extract(int dummy) {
+
+ static struct cli_state c_dos;
+ static struct cli_state c_nt;
+
+ uint32 error;
+
+ uint32 flgs2, errnum;
+ uint8 errclass;
+
+ NTSTATUS nt_status;
+
+ fstring user;
+
+ open_nbt_connection(&c_nt);
+ open_nbt_connection(&c_dos);
+
+ c_dos.force_dos_errors = True;
+
+ if (!cli_negprot(&c_dos)) {
+ printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(&c_dos));
+ cli_shutdown(&c_dos);
+ return False;
+ }
+ if (!cli_negprot(&c_nt)) {
+ printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(&c_nt));
+ cli_shutdown(&c_nt);
+ return False;
+ }
+
+ for (error=(0xc0000000 | 0x1); error < (0xc0000000| 0xFFF); error++) {
+ snprintf(user, sizeof(user), "%X", error);
+
+ if (!cli_session_setup(&c_nt, user,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ flgs2 = SVAL(c_nt.inbuf,smb_flg2);
+
+ /* Case #1: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ nt_status = NT_STATUS(IVAL(c_nt.inbuf,smb_rcls));
+ } else {
+ printf("** Dos error on NT connection! (%s)\n", cli_errstr(&c_nt));
+ nt_status = NT_STATUS(0xc0000000);
+ }
+ } else {
+ printf("** Session setup succeeded. This shouldn't happen...\n");
+ }
+
+ if (!cli_session_setup(&c_dos, user,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ flgs2 = SVAL(c_dos.inbuf,smb_flg2), errnum;
+
+ /* Case #1: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ printf("** NT error on DOS connection! (%s)\n", cli_errstr(&c_nt));
+ errnum = errclass = 0;
+ } else {
+ cli_dos_error(&c_dos, &errclass, &errnum);
+ }
+ } else {
+ printf("** Session setup succeeded. This shouldn't happen...\n");
+ }
+ if (NT_STATUS_V(nt_status) == error) {
+ printf("\t{%s,\t%s,\t%s}\n", smb_dos_err_class(errclass), smb_dos_err_name(errclass, errnum), get_nt_error_c_code(nt_status));
+ } else {
+ printf("/*\t{ This NT error code was 'sqashed'\n\t from %s to %s \n\t during the session setup }\n*/\n", get_nt_error_c_code(NT_STATUS(error)), get_nt_error_c_code(nt_status));
+ }
+ }
+ return True;
+}
+
+static double create_procs(BOOL (*fn)(int), BOOL *result)
+{
+ int i, status;
+ volatile pid_t *child_status;
+ volatile BOOL *child_status_out;
+ int synccount;
+ int tries = 8;
+
+ synccount = 0;
+
+ child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*nprocs);
+ if (!child_status) {
+ printf("Failed to setup shared memory\n");
+ return -1;
+ }
+
+ child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*nprocs);
+ if (!child_status_out) {
+ printf("Failed to setup result status shared memory\n");
+ return -1;
+ }
+
+ memset((void *)child_status, 0, sizeof(pid_t)*nprocs);
+ memset((void *)child_status_out, True, sizeof(BOOL)*nprocs);
+
+ start_timer();
+
+ for (i=0;i<nprocs;i++) {
+ procnum = i;
+ if (fork() == 0) {
+ pid_t mypid = getpid();
+ sys_srandom(((int)mypid) ^ ((int)time(NULL)));
+
+ slprintf(myname,sizeof(myname),"CLIENT%d", i);
+
+ while (1) {
+ memset(&current_cli, 0, sizeof(current_cli));
+ if (torture_open_connection(&current_cli)) break;
+ if (tries-- == 0) {
+ printf("pid %d failed to start\n", (int)getpid());
+ _exit(1);
+ }
+ msleep(10);
+ }
+
+ child_status[i] = getpid();
+
+ while (child_status[i]) msleep(2);
+
+ child_status_out[i] = fn(i);
+ _exit(0);
+ }
+ }
+
+ do {
+ synccount = 0;
+ for (i=0;i<nprocs;i++) {
+ if (child_status[i]) synccount++;
+ }
+ if (synccount == nprocs) break;
+ msleep(10);
+ } while (end_timer() < 30);
+
+ if (synccount != nprocs) {
+ printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
+ *result = False;
+ return end_timer();
+ }
+
+ /* start the client load */
+ start_timer();
+
+ for (i=0;i<nprocs;i++) {
+ child_status[i] = 0;
+ }
+
+ printf("%d clients started\n", nprocs);
+
+ for (i=0;i<nprocs;i++) {
+ waitpid(0, &status, 0);
+ printf("*");
+ }
+
+ printf("\n");
+
+ for (i=0;i<nprocs;i++) {
+ if (!child_status_out[i]) {
+ *result = False;
+ }
+ }
+ return end_timer();
+}
+
+
+#define FLAG_MULTIPROC 1
+
+static struct {
+ char *name;
+ BOOL (*fn)(int);
+ unsigned flags;
+} torture_ops[] = {
+ {"FDPASS", run_fdpasstest, 0},
+ {"LOCK1", run_locktest1, 0},
+ {"LOCK2", run_locktest2, 0},
+ {"LOCK3", run_locktest3, 0},
+ {"LOCK4", run_locktest4, 0},
+ {"LOCK5", run_locktest5, 0},
+ {"UNLINK", run_unlinktest, 0},
+ {"BROWSE", run_browsetest, 0},
+ {"ATTR", run_attrtest, 0},
+ {"TRANS2", run_trans2test, 0},
+ {"MAXFID", run_maxfidtest, FLAG_MULTIPROC},
+ {"TORTURE",run_torture, FLAG_MULTIPROC},
+ {"RANDOMIPC", run_randomipc, 0},
+ {"NEGNOWAIT", run_negprot_nowait, 0},
+ {"NBW95", run_nbw95, 0},
+ {"NBWNT", run_nbwnt, 0},
+ {"OPLOCK1", run_oplock1, 0},
+ {"OPLOCK2", run_oplock2, 0},
+ {"OPLOCK3", run_oplock3, 0},
+ {"DIR", run_dirtest, 0},
+ {"DENY1", torture_denytest1, 0},
+ {"DENY2", torture_denytest2, 0},
+ {"TCON", run_tcon_test, 0},
+ {"RW1", run_readwritetest, 0},
+ {"RW2", run_readwritemulti, FLAG_MULTIPROC},
+ {"RW3", run_readwritelarge, 0},
+ {"OPEN", run_opentest, 0},
+ {"DELETE", run_deletetest, 0},
+ {"W2K", run_w2ktest, 0},
+ {"TRANS2SCAN", torture_trans2_scan, 0},
+ {"NTTRANSSCAN", torture_nttrans_scan, 0},
+ {"UTABLE", torture_utable, 0},
+ {"CASETABLE", torture_casetable, 0},
+ {"ERRMAPEXTRACT", run_error_map_extract, 0},
+ {NULL, NULL, 0}};
+
+
+
+/****************************************************************************
+run a specified test or "ALL"
+****************************************************************************/
+static BOOL run_test(char *name)
+{
+ BOOL ret = True;
+ BOOL result = True;
+ int i;
+ double t;
+ if (strequal(name,"ALL")) {
+ for (i=0;torture_ops[i].name;i++) {
+ run_test(torture_ops[i].name);
+ }
+ }
+
+ for (i=0;torture_ops[i].name;i++) {
+ snprintf(randomfname, sizeof(randomfname), "\\XX%x",
+ (unsigned)random());
+
+ if (strequal(name, torture_ops[i].name)) {
+ printf("Running %s\n", name);
+ if (torture_ops[i].flags & FLAG_MULTIPROC) {
+ t = create_procs(torture_ops[i].fn, &result);
+ if (!result) {
+ ret = False;
+ printf("TEST %s FAILED!\n", name);
+ }
+
+ } else {
+ start_timer();
+ if (!torture_ops[i].fn(0)) {
+ ret = False;
+ printf("TEST %s FAILED!\n", name);
+ }
+ t = end_timer();
+ }
+ printf("%s took %g secs\n\n", name, t);
+ }
+ }
+ return ret;
+}
+
+
+static void usage(void)
+{
+ int i;
+
+ printf("Usage: smbtorture //server/share <options> TEST1 TEST2 ...\n");
+
+ printf("\t-d debuglevel\n");
+ printf("\t-U user%%pass\n");
+ printf("\t-N numprocs\n");
+ printf("\t-n my_netbios_name\n");
+ printf("\t-W workgroup\n");
+ printf("\t-o num_operations\n");
+ printf("\t-O socket_options\n");
+ printf("\t-m maximum protocol\n");
+ printf("\t-L use oplocks\n");
+ printf("\t-A showall\n");
+ printf("\n\n");
+
+ printf("tests are:");
+ for (i=0;torture_ops[i].name;i++) {
+ printf(" %s", torture_ops[i].name);
+ }
+ printf("\n");
+
+ printf("default test is ALL\n");
+
+ exit(1);
+}
+
+
+
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int opt, i;
+ char *p;
+ int gotpass = 0;
+ extern char *optarg;
+ extern int optind;
+ BOOL correct = True;
+
+ dbf = x_stdout;
+
+#ifdef HAVE_SETBUFFER
+ setbuffer(stdout, NULL, 0);
+#endif
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (argc < 2) {
+ usage();
+ }
+
+ for(p = argv[1]; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+
+ if (strncmp(argv[1], "//", 2)) {
+ usage();
+ }
+
+ fstrcpy(host, &argv[1][2]);
+ p = strchr_m(&host[2],'/');
+ if (!p) {
+ usage();
+ }
+ *p = 0;
+ fstrcpy(share, p+1);
+
+ get_myname(myname);
+
+ if (*username == 0 && getenv("LOGNAME")) {
+ pstrcpy(username,getenv("LOGNAME"));
+ }
+
+ argc--;
+ argv++;
+
+
+ fstrcpy(workgroup, lp_workgroup());
+
+ while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:Ld:A")) != EOF) {
+ switch (opt) {
+ case 'W':
+ fstrcpy(workgroup,optarg);
+ break;
+ case 'm':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'N':
+ nprocs = atoi(optarg);
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'O':
+ sockops = optarg;
+ break;
+ case 'L':
+ use_oplocks = True;
+ break;
+ case 'A':
+ torture_showall = True;
+ break;
+ case 'n':
+ fstrcpy(myname, optarg);
+ break;
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(password, p+1);
+ gotpass = 1;
+ }
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ usage();
+ }
+ }
+
+
+ while (!gotpass) {
+ p = getpass("Password:");
+ if (p) {
+ pstrcpy(password, p);
+ gotpass = 1;
+ }
+ }
+
+ printf("host=%s share=%s user=%s myname=%s\n",
+ host, share, username, myname);
+
+ if (argc == 1) {
+ correct = run_test("ALL");
+ } else {
+ for (i=1;i<argc;i++) {
+ if (!run_test(argv[i])) {
+ correct = False;
+ }
+ }
+ }
+
+ if (correct) {
+ return(0);
+ } else {
+ return(1);
+ }
+}
diff --git a/source/torture/utable.c b/source/torture/utable.c
new file mode 100644
index 00000000000..a9f3afb3f29
--- /dev/null
+++ b/source/torture/utable.c
@@ -0,0 +1,187 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ SMB torture tester - unicode table dumper
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+BOOL torture_utable(int dummy)
+{
+ static struct cli_state cli;
+ fstring fname, alt_name;
+ int fnum;
+ smb_ucs2_t c2;
+ int c, len, fd;
+ int chars_allowed=0, alt_allowed=0;
+ uint8 valid[0x10000];
+
+ printf("starting utable\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ memset(valid, 0, sizeof(valid));
+
+ cli_mkdir(&cli, "\\utable");
+ cli_unlink(&cli, "\\utable\\*");
+
+ for (c=1; c < 0x10000; c++) {
+ char *p;
+
+ SSVAL(&c2, 0, c);
+ fstrcpy(fname, "\\utable\\x");
+ p = fname+strlen(fname);
+ len = convert_string(CH_UCS2, CH_UNIX,
+ &c2, 2,
+ p, sizeof(fname)-strlen(fname));
+ p[len] = 0;
+ fstrcat(fname,"_a_long_extension");
+
+ fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (fnum == -1) continue;
+
+ chars_allowed++;
+
+ cli_qpathinfo_alt_name(&cli, fname, alt_name);
+
+ if (strncmp(alt_name, "X_A_L", 5) != 0) {
+ alt_allowed++;
+ valid[c] = 1;
+ d_printf("fname=[%s] alt_name=[%s]\n", fname, alt_name);
+ }
+
+ cli_close(&cli, fnum);
+ cli_unlink(&cli, fname);
+
+ if (c % 100 == 0) {
+ printf("%d (%d/%d)\r", c, chars_allowed, alt_allowed);
+ }
+ }
+ printf("%d (%d/%d)\n", c, chars_allowed, alt_allowed);
+
+ cli_rmdir(&cli, "\\utable");
+
+ d_printf("%d chars allowed %d alt chars allowed\n", chars_allowed, alt_allowed);
+
+ fd = open("valid.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ d_printf("Failed to create valid.dat - %s", strerror(errno));
+ return False;
+ }
+ write(fd, valid, 0x10000);
+ close(fd);
+ d_printf("wrote valid.dat\n");
+
+ return True;
+}
+
+
+static char *form_name(int c)
+{
+ static fstring fname;
+ smb_ucs2_t c2;
+ char *p;
+ int len;
+
+ fstrcpy(fname, "\\utable\\");
+ p = fname+strlen(fname);
+ SSVAL(&c2, 0, c);
+
+ len = convert_string(CH_UCS2, CH_UNIX,
+ &c2, 2,
+ p, sizeof(fname)-strlen(fname));
+ p[len] = 0;
+ return fname;
+}
+
+BOOL torture_casetable(int dummy)
+{
+ static struct cli_state cli;
+ char *fname;
+ int fnum;
+ int c, i;
+#define MAX_EQUIVALENCE 8
+ smb_ucs2_t equiv[0x10000][MAX_EQUIVALENCE];
+ printf("starting casetable\n");
+
+ if (!torture_open_connection(&cli)) {
+ return False;
+ }
+
+ memset(equiv, 0, sizeof(equiv));
+
+ cli_mkdir(&cli, "\\utable");
+ cli_unlink(&cli, "\\utable\\*");
+
+ for (c=1; c < 0x10000; c++) {
+ size_t size;
+
+ if (c == '.' || c == '\\') continue;
+
+ printf("%04x\n", c);
+
+ fname = form_name(c);
+ fnum = cli_nt_create_full(&cli, fname,
+ GENERIC_ALL_ACCESS,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_NONE,
+ FILE_OPEN_IF, 0);
+
+ if (fnum == -1) continue;
+
+ size = 0;
+
+ if (!cli_qfileinfo(&cli, fnum, NULL, &size,
+ NULL, NULL, NULL, NULL, NULL)) continue;
+
+ if (size > 0) {
+ /* found a character equivalence! */
+ int c2[MAX_EQUIVALENCE];
+
+ if (size/sizeof(int) >= MAX_EQUIVALENCE) {
+ printf("too many chars match?? size=%d c=0x%04x\n",
+ size, c);
+ cli_close(&cli, fnum);
+ return False;
+ }
+
+ cli_read(&cli, fnum, (char *)c2, 0, size);
+ printf("%04x: ", c);
+ equiv[c][0] = c;
+ for (i=0; i<size/sizeof(int); i++) {
+ printf("%04x ", c2[i]);
+ equiv[c][i+1] = c2[i];
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+
+ cli_write(&cli, fnum, 0, (char *)&c, size, sizeof(c));
+ cli_close(&cli, fnum);
+ }
+
+ cli_unlink(&cli, "\\utable\\*");
+ cli_rmdir(&cli, "\\utable");
+
+ return True;
+}
diff --git a/source/ubiqx/.cvsignore b/source/ubiqx/.cvsignore
new file mode 100644
index 00000000000..07da2225c72
--- /dev/null
+++ b/source/ubiqx/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source/ubiqx/COPYING.LIB b/source/ubiqx/COPYING.LIB
new file mode 100644
index 00000000000..8c8377da464
--- /dev/null
+++ b/source/ubiqx/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/source/ubiqx/README.UBI b/source/ubiqx/README.UBI
new file mode 100644
index 00000000000..a2c14ca62c9
--- /dev/null
+++ b/source/ubiqx/README.UBI
@@ -0,0 +1,18 @@
+Fri Apr 17 10:21:56 CDT 1998
+
+The C code files in the samba/source/ubiqx directory are licensed under
+the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE (LGPL). A copy of the
+LGPL should also be included in this directory under the name COPYING.LIB.
+If this file is not present, you can obtain a copy of the LGPL by writing
+to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+USA.
+
+The versions of the ubiqx modules distributed with Samba may have been
+modified for inclusion with Samba. The main distribution, which contains
+additional available modules, can be found at:
+
+ http://www.interads.co.uk/~crh/ubiqx/
+
+Chris Hertel
+Samba Team
+ubiqx@ubiqx.mn.org
diff --git a/source/ubiqx/debugparse.c b/source/ubiqx/debugparse.c
new file mode 100644
index 00000000000..5da5280f19e
--- /dev/null
+++ b/source/ubiqx/debugparse.c
@@ -0,0 +1,308 @@
+/* ========================================================================== **
+ * debugparse.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is a very simple parser for Samba debug log files.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ * The important function in this module is dbg_char2token(). The rest is
+ * basically fluff. (Potentially useful fluff, but still fluff.)
+ * ========================================================================== **
+ */
+
+#include "debugparse.h"
+
+/* -------------------------------------------------------------------------- **
+ * Constants...
+ *
+ * DBG_BSIZE - This internal constant is used only by dbg_test(). It is the
+ * size of the read buffer. I've tested the function using a
+ * DBG_BSIZE value of 2.
+ */
+
+#define DBG_BSIZE 128
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+char *dbg_token2string( dbg_Token tok )
+ /* ------------------------------------------------------------------------ **
+ * Given a token, return a string describing the token.
+ *
+ * Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
+ *
+ * Output: A string identifying the token. This is useful for debugging,
+ * etc.
+ *
+ * Note: If the token is not known, this function will return the
+ * string "<unknown>".
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( tok )
+ {
+ case dbg_null:
+ return( "null" );
+ case dbg_ignore:
+ return( "ignore" );
+ case dbg_header:
+ return( "header" );
+ case dbg_timestamp:
+ return( "time stamp" );
+ case dbg_level:
+ return( "level" );
+ case dbg_sourcefile:
+ return( "source file" );
+ case dbg_function:
+ return( "function" );
+ case dbg_lineno:
+ return( "line number" );
+ case dbg_message:
+ return( "message" );
+ case dbg_eof:
+ return( "[EOF]" );
+ }
+ return( "<unknown>" );
+ } /* dbg_token2string */
+
+dbg_Token dbg_char2token( dbg_Token *state, int c )
+ /* ------------------------------------------------------------------------ **
+ * Parse input one character at a time.
+ *
+ * Input: state - A pointer to a token variable. This is used to
+ * maintain the parser state between calls. For
+ * each input stream, you should set up a separate
+ * state variable and initialize it to dbg_null.
+ * Pass a pointer to it into this function with each
+ * character in the input stream. See dbg_test()
+ * for an example.
+ * c - The "current" character in the input stream.
+ *
+ * Output: A token.
+ * The token value will change when delimiters are found,
+ * which indicate a transition between syntactical objects.
+ * Possible return values are:
+ *
+ * dbg_null - The input character was an end-of-line.
+ * This resets the parser to its initial state
+ * in preparation for parsing the next line.
+ * dbg_eof - Same as dbg_null, except that the character
+ * was an end-of-file.
+ * dbg_ignore - Returned for whitespace and delimiters.
+ * These lexical tokens are only of interest
+ * to the parser.
+ * dbg_header - Indicates the start of a header line. The
+ * input character was '[' and was the first on
+ * the line.
+ * dbg_timestamp - Indicates that the input character was part
+ * of a header timestamp.
+ * dbg_level - Indicates that the input character was part
+ * of the debug-level value in the header.
+ * dbg_sourcefile - Indicates that the input character was part
+ * of the sourcefile name in the header.
+ * dbg_function - Indicates that the input character was part
+ * of the function name in the header.
+ * dbg_lineno - Indicates that the input character was part
+ * of the DEBUG call line number in the header.
+ * dbg_message - Indicates that the input character was part
+ * of the DEBUG message text.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* The terminating characters that we see will greatly depend upon
+ * how they are read. For example, if gets() is used instead of
+ * fgets(), then we will not see newline characters. A lot also
+ * depends on the calling function, which may handle terminators
+ * itself.
+ *
+ * '\n', '\0', and EOF are all considered line terminators. The
+ * dbg_eof token is sent back if an EOF is encountered.
+ *
+ * Warning: only allow the '\0' character to be sent if you are
+ * using gets() to read whole lines (thus replacing '\n'
+ * with '\0'). Sending '\0' at the wrong time will mess
+ * up the parsing.
+ */
+ switch( c )
+ {
+ case EOF:
+ *state = dbg_null; /* Set state to null (initial state) so */
+ return( dbg_eof ); /* that we can restart with new input. */
+ case '\n':
+ case '\0':
+ *state = dbg_null; /* A newline or eoln resets to the null state. */
+ return( dbg_null );
+ }
+
+ /* When within the body of the message, only a line terminator
+ * can cause a change of state. We've already checked for line
+ * terminators, so if the current state is dbg_msgtxt, simply
+ * return that as our current token.
+ */
+ if( dbg_message == *state )
+ return( dbg_message );
+
+ /* If we are at the start of a new line, and the input character
+ * is an opening bracket, then the line is a header line, otherwise
+ * it's a message body line.
+ */
+ if( dbg_null == *state )
+ {
+ if( '[' == c )
+ {
+ *state = dbg_timestamp;
+ return( dbg_header );
+ }
+ *state = dbg_message;
+ return( dbg_message );
+ }
+
+ /* We've taken care of terminators, text blocks and new lines.
+ * The remaining possibilities are all within the header line
+ * itself.
+ */
+
+ /* Within the header line, whitespace can be ignored *except*
+ * within the timestamp.
+ */
+ if( isspace( c ) )
+ {
+ /* Fudge. The timestamp may contain space characters. */
+ if( (' ' == c) && (dbg_timestamp == *state) )
+ return( dbg_timestamp );
+ /* Otherwise, ignore whitespace. */
+ return( dbg_ignore );
+ }
+
+ /* Okay, at this point we know we're somewhere in the header.
+ * Valid header *states* are: dbg_timestamp, dbg_level,
+ * dbg_sourcefile, dbg_function, and dbg_lineno.
+ */
+ switch( c )
+ {
+ case ',':
+ if( dbg_timestamp == *state )
+ {
+ *state = dbg_level;
+ return( dbg_ignore );
+ }
+ break;
+ case ']':
+ if( dbg_level == *state )
+ {
+ *state = dbg_sourcefile;
+ return( dbg_ignore );
+ }
+ break;
+ case ':':
+ if( dbg_sourcefile == *state )
+ {
+ *state = dbg_function;
+ return( dbg_ignore );
+ }
+ break;
+ case '(':
+ if( dbg_function == *state )
+ {
+ *state = dbg_lineno;
+ return( dbg_ignore );
+ }
+ break;
+ case ')':
+ if( dbg_lineno == *state )
+ {
+ *state = dbg_null;
+ return( dbg_ignore );
+ }
+ break;
+ }
+
+ /* If the previous block did not result in a state change, then
+ * return the current state as the current token.
+ */
+ return( *state );
+ } /* dbg_char2token */
+
+void dbg_test( void )
+ /* ------------------------------------------------------------------------ **
+ * Simple test function.
+ *
+ * Input: none.
+ * Output: none.
+ * Notes: This function was used to test dbg_char2token(). It reads a
+ * Samba log file from stdin and prints parsing info to stdout.
+ * It also serves as a simple example.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ char bufr[DBG_BSIZE];
+ int i;
+ int linecount = 1;
+ dbg_Token old = dbg_null,
+ new = dbg_null,
+ state = dbg_null;
+
+ while( fgets( bufr, DBG_BSIZE, stdin ) )
+ {
+ for( i = 0; bufr[i]; i++ )
+ {
+ old = new;
+ new = dbg_char2token( &state, bufr[i] );
+ switch( new )
+ {
+ case dbg_header:
+ if( linecount > 1 )
+ (void)putchar( '\n' );
+ break;
+ case dbg_null:
+ linecount++;
+ break;
+ case dbg_ignore:
+ break;
+ default:
+ if( old != new )
+ (void)printf( "\n[%05d]%12s: ", linecount, dbg_token2string(new) );
+ (void)putchar( bufr[i] );
+ }
+ }
+ }
+ (void)putchar( '\n' );
+ } /* dbg_test */
+
+
+/* -------------------------------------------------------------------------- **
+ * This simple main line can be uncommented and used to test the parser.
+ */
+
+/*
+ * int main( void )
+ * {
+ * dbg_test();
+ * return( 0 );
+ * }
+ */
+
+/* ========================================================================== */
diff --git a/source/ubiqx/debugparse.h b/source/ubiqx/debugparse.h
new file mode 100644
index 00000000000..9ed1777e956
--- /dev/null
+++ b/source/ubiqx/debugparse.h
@@ -0,0 +1,127 @@
+#ifndef DEBUGPARSE_H
+#define DEBUGPARSE_H
+/* ========================================================================== **
+ * debugparse.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is a very simple parser for Samba debug log files.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ * The important function in this module is dbg_char2token(). The rest is
+ * basically fluff. (Potentially useful fluff, but still fluff.)
+ * ========================================================================== **
+ */
+
+#include "sys_include.h"
+
+/* This module compiles quite nicely outside of the Samba environment.
+ * You'll need the following headers:
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+ */
+
+/* -------------------------------------------------------------------------- **
+ * These are the tokens returned by dbg_char2token().
+ */
+
+typedef enum
+ {
+ dbg_null = 0,
+ dbg_ignore,
+ dbg_header,
+ dbg_timestamp,
+ dbg_level,
+ dbg_sourcefile,
+ dbg_function,
+ dbg_lineno,
+ dbg_message,
+ dbg_eof
+ } dbg_Token;
+
+/* -------------------------------------------------------------------------- **
+ * Function prototypes...
+ */
+
+ char *dbg_token2string( dbg_Token tok );
+ /* ------------------------------------------------------------------------ **
+ * Given a token, return a string describing the token.
+ *
+ * Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
+ *
+ * Output: A string identifying the token. This is useful for debugging,
+ * etc.
+ *
+ * Note: If the token is not known, this function will return the
+ * string "<unknown>".
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ dbg_Token dbg_char2token( dbg_Token *state, int c );
+ /* ------------------------------------------------------------------------ **
+ * Parse input one character at a time.
+ *
+ * Input: state - A pointer to a token variable. This is used to
+ * maintain the parser state between calls. For
+ * each input stream, you should set up a separate
+ * state variable and initialize it to dbg_null.
+ * Pass a pointer to it into this function with each
+ * character in the input stream. See dbg_test()
+ * for an example.
+ * c - The "current" character in the input stream.
+ *
+ * Output: A token.
+ * The token value will change when delimiters are found,
+ * which indicate a transition between syntactical objects.
+ * Possible return values are:
+ *
+ * dbg_null - The input character was an end-of-line.
+ * This resets the parser to its initial state
+ * in preparation for parsing the next line.
+ * dbg_eof - Same as dbg_null, except that the character
+ * was an end-of-file.
+ * dbg_ignore - Returned for whitespace and delimiters.
+ * These lexical tokens are only of interest
+ * to the parser.
+ * dbg_header - Indicates the start of a header line. The
+ * input character was '[' and was the first on
+ * the line.
+ * dbg_timestamp - Indicates that the input character was part
+ * of a header timestamp.
+ * dbg_level - Indicates that the input character was part
+ * of the debug-level value in the header.
+ * dbg_sourcefile - Indicates that the input character was part
+ * of the sourcefile name in the header.
+ * dbg_function - Indicates that the input character was part
+ * of the function name in the header.
+ * dbg_lineno - Indicates that the input character was part
+ * of the DEBUG call line number in the header.
+ * dbg_message - Indicates that the input character was part
+ * of the DEBUG message text.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+/* -------------------------------------------------------------------------- */
+#endif /* DEBUGPARSE_H */
diff --git a/source/ubiqx/sys_include.h b/source/ubiqx/sys_include.h
new file mode 100644
index 00000000000..8ff270afe85
--- /dev/null
+++ b/source/ubiqx/sys_include.h
@@ -0,0 +1,52 @@
+#ifndef SYS_INCLUDE_H
+#define SYS_INCLUDE_H
+/* ========================================================================== **
+ * sys_include.h
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This header provides system declarations and data types used internally
+ * by the ubiqx modules.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Samba version of sys_include.h
+ *
+ * ========================================================================== **
+ */
+
+#ifndef _INCLUDES_H
+
+/* Block the inclusion of some Samba headers so that ubiqx types won't be
+ * used before the headers that define them. These headers are not needed
+ * in the ubiqx modules anyway.
+ */
+#define _PROTO_H_
+#define _NAMESERV_H_
+#define _HASH_H_
+
+/* The main Samba system-adaptive header file.
+ */
+#include "includes.h"
+
+#endif /* _INCLUDES_H */
+
+/* ================================ The End ================================= */
+#endif /* SYS_INCLUDE_H */
diff --git a/source/ubiqx/ubi_BinTree.c b/source/ubiqx/ubi_BinTree.c
new file mode 100644
index 00000000000..8a4d4612800
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.c
@@ -0,0 +1,1132 @@
+/* ========================================================================== **
+ * ubi_BinTree.c
+ *
+ * Copyright (C) 1991-1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements a simple binary tree.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_BinTree.c,v
+ * Revision 4.10 2000/06/06 20:38:40 crh
+ * In the ReplaceNode() function, the old node header was being copied
+ * to the new node header using a byte-by-byte copy. This was causing
+ * the 'insure' software testing program to report a memory leak. The
+ * fix was to do a simple assignement: *newnode = *oldnode;
+ * This quieted the (errant) memory leak reports and is probably a bit
+ * faster than the bytewise copy.
+ *
+ * Revision 4.9 2000/01/08 23:24:30 crh
+ * Clarified a variety of if( pointer ) lines, replacing them with
+ * if( NULL != pointer ). This is more correct, and I have heard
+ * of at least one (obscure?) system out there that uses a non-zero
+ * value for NULL.
+ * Also, speed improvement in Neighbor(). It was comparing pointers
+ * when it could have compared two gender values. The pointer
+ * comparison was somewhat indirect (does pointer equal the pointer
+ * of the parent of the node pointed to by pointer). Urq.
+ *
+ * Revision 4.8 1999/09/22 03:40:30 crh
+ * Modified ubi_btTraverse() and ubi_btKillTree(). They now return an
+ * unsigned long indicating the number of nodes processed. The change
+ * is subtle. An empty tree formerly returned False, and now returns
+ * zero.
+ *
+ * Revision 4.7 1998/10/21 06:14:42 crh
+ * Fixed bugs in FirstOf() and LastOf() reported by Massimo Campostrini.
+ * See function comments.
+ *
+ * Revision 4.6 1998/07/25 17:02:10 crh
+ * Added the ubi_trNewTree() macro.
+ *
+ * Revision 4.5 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 4.4 1998/06/03 17:42:46 crh
+ * Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
+ * included by all of the binary tree files.
+ *
+ * Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
+ * ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
+ * of tree types by simply changing a header. Unfortunately, the
+ * macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
+ * conflict if used together. You must either choose a single tree
+ * type, or use the underlying function calls directly. Compare
+ * the two header files for more information.
+ *
+ * Revision 4.3 1998/06/02 01:28:43 crh
+ * Changed ubi_null.h to sys_include.h to make it more generic.
+ *
+ * Revision 4.2 1998/05/20 04:32:36 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ * Also, the balance and gender fields of the node were declared as
+ * signed char. As I understand it, at least one SunOS or Solaris
+ * compiler doesn't like "signed char". The declarations were
+ * wrong anyway, so I changed them to simple "char".
+ *
+ * Revision 4.1 1998/03/31 06:11:57 crh
+ * Thomas Aglassinger sent E'mail pointing out errors in the
+ * dereferencing of function pointers, and a missing typecast.
+ * Thanks, Thomas!
+ *
+ * Revision 4.0 1998/03/10 03:19:22 crh
+ * Added the AVL field 'balance' to the ubi_btNode structure. This means
+ * that all BinTree modules now use the same basic node structure, which
+ * greatly simplifies the AVL module.
+ * Decided that this was a big enough change to justify a new major revision
+ * number. 3.0 was an error, so we're at 4.0.
+ *
+ * Revision 2.6 1998/01/24 06:27:46 crh
+ * Added ubi_trCount() macro.
+ *
+ * Revision 2.5 1997/12/23 03:56:29 crh
+ * In this version, all constants & macros defined in the header file have
+ * the ubi_tr prefix. Also cleaned up anything that gcc complained about
+ * when run with '-pedantic -fsyntax-only -Wall'.
+ *
+ * Revision 2.4 1997/07/26 04:11:10 crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ * and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h". I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3 1997/06/03 05:16:17 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree(). See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2 1995/10/03 22:00:07 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:37:10 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:00:17 CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ * 1) A fix to a major typo in the RepaceNode() function.
+ * 2) The addition of the static function Border().
+ * 3) The addition of the public functions FirstOf() and LastOf(), which
+ * use Border(). These functions are used with trees that allow
+ * duplicate keys.
+ * 4) A complete rewrite of the Locate() function. Locate() now accepts
+ * a "comparison" operator.
+ * 5) Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed. In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0 93/10/15 22:44:59 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_SplayTree, the locate function was
+ * called "ubi_sptLocate", but the next and previous functions remained
+ * "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h" /* Header for this module. */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_BinTree\n\
+\tRevision: 4.10 \n\
+\tDate: 2000/06/06 20:38:40 \n\
+\tAuthor: crh \n";
+
+/* ========================================================================== **
+ * Internal (private) functions.
+ */
+
+static ubi_btNodePtr qFind( ubi_btCompFunc cmp,
+ ubi_btItemPtr FindMe,
+ register ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for a node
+ * matching a specific key. It is called "qFind()" because it is
+ * faster that TreeFind (below).
+ *
+ * Input:
+ * cmp - a pointer to the tree's comparison function.
+ * FindMe - a pointer to the key value for which to search.
+ * p - a pointer to the starting point of the search. <p>
+ * is considered to be the root of a subtree, and only
+ * the subtree will be searched.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int tmp;
+
+ while( (NULL != p)
+ && ((tmp = ubi_trAbNormal( (*cmp)(FindMe, p) )) != ubi_trEQUAL) )
+ p = p->Link[tmp];
+
+ return( p );
+ } /* qFind */
+
+static ubi_btNodePtr TreeFind( ubi_btItemPtr findme,
+ ubi_btNodePtr p,
+ ubi_btNodePtr *parentp,
+ char *gender,
+ ubi_btCompFunc CmpFunc )
+ /* ------------------------------------------------------------------------ **
+ * TreeFind() searches a tree for a given value (findme). It will return a
+ * pointer to the target node, if found, or NULL if the target node was not
+ * found.
+ *
+ * TreeFind() also returns, via parameters, a pointer to the parent of the
+ * target node, and a LEFT or RIGHT value indicating which child of the
+ * parent is the target node. *If the target is not found*, then these
+ * values indicate the place at which the target *should be found*. This
+ * is useful when inserting a new node into a tree or searching for nodes
+ * "near" the target node.
+ *
+ * The parameters are:
+ *
+ * findme - is a pointer to the key information to be searched for.
+ * p - points to the root of the tree to be searched.
+ * parentp - will return a pointer to a pointer to the !parent! of the
+ * target node, which can be especially usefull if the target
+ * was not found.
+ * gender - returns LEFT or RIGHT to indicate which child of *parentp
+ * was last searched.
+ * CmpFunc - points to the comparison function.
+ *
+ * This function is called by ubi_btLocate() and ubi_btInsert().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr tmp_p = p;
+ ubi_btNodePtr tmp_pp = NULL;
+ char tmp_gender = ubi_trEQUAL;
+ int tmp_cmp;
+
+ while( (NULL != tmp_p)
+ && (ubi_trEQUAL != (tmp_cmp = ubi_trAbNormal((*CmpFunc)(findme, tmp_p)))) )
+ {
+ tmp_pp = tmp_p; /* Keep track of previous node. */
+ tmp_gender = (char)tmp_cmp; /* Keep track of sex of child. */
+ tmp_p = tmp_p->Link[tmp_cmp]; /* Go to child. */
+ }
+ *parentp = tmp_pp; /* Return results. */
+ *gender = tmp_gender;
+ return( tmp_p );
+ } /* TreeFind */
+
+static void ReplaceNode( ubi_btNodePtr *parent,
+ ubi_btNodePtr oldnode,
+ ubi_btNodePtr newnode )
+ /* ------------------------------------------------------------------------ **
+ * Remove node oldnode from the tree, replacing it with node newnode.
+ *
+ * Input:
+ * parent - A pointer to he parent pointer of the node to be
+ * replaced. <parent> may point to the Link[] field of
+ * a parent node, or it may indicate the root pointer at
+ * the top of the tree.
+ * oldnode - A pointer to the node that is to be replaced.
+ * newnode - A pointer to the node that is to be installed in the
+ * place of <*oldnode>.
+ *
+ * Notes: Don't forget to free oldnode.
+ * Also, this function used to have a really nasty typo
+ * bug. "oldnode" and "newnode" were swapped in the line
+ * that now reads:
+ * ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+ * Bleah!
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ *newnode = *oldnode; /* Copy node internals to new node. */
+
+ (*parent) = newnode; /* Old node's parent points to new child. */
+ /* Now tell the children about their new step-parent. */
+ if( oldnode->Link[ubi_trLEFT] )
+ (oldnode->Link[ubi_trLEFT])->Link[ubi_trPARENT] = newnode;
+ if( oldnode->Link[ubi_trRIGHT] )
+ (oldnode->Link[ubi_trRIGHT])->Link[ubi_trPARENT] = newnode;
+ } /* ReplaceNode */
+
+static void SwapNodes( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr Node1,
+ ubi_btNodePtr Node2 )
+ /* ------------------------------------------------------------------------ **
+ * This function swaps two nodes in the tree. Node1 will take the place of
+ * Node2, and Node2 will fill in the space left vacant by Node 1.
+ *
+ * Input:
+ * RootPtr - pointer to the tree header structure for this tree.
+ * Node1 - \
+ * > These are the two nodes which are to be swapped.
+ * Node2 - /
+ *
+ * Notes:
+ * This function does a three step swap, using a dummy node as a place
+ * holder. This function is used by ubi_btRemove().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr *Parent;
+ ubi_btNode dummy;
+ ubi_btNodePtr dummy_p = &dummy;
+
+ /* Replace Node 1 with the dummy, thus removing Node1 from the tree. */
+ if( NULL != Node1->Link[ubi_trPARENT] )
+ Parent = &((Node1->Link[ubi_trPARENT])->Link[(int)(Node1->gender)]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, Node1, dummy_p );
+
+ /* Swap Node 1 with Node 2, placing Node 1 back into the tree. */
+ if( NULL != Node2->Link[ubi_trPARENT] )
+ Parent = &((Node2->Link[ubi_trPARENT])->Link[(int)(Node2->gender)]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, Node2, Node1 );
+
+ /* Swap Node 2 and the dummy, thus placing Node 2 back into the tree. */
+ if( NULL != dummy_p->Link[ubi_trPARENT] )
+ Parent = &((dummy_p->Link[ubi_trPARENT])->Link[(int)(dummy_p->gender)]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, dummy_p, Node2 );
+ } /* SwapNodes */
+
+/* -------------------------------------------------------------------------- **
+ * These routines allow you to walk through the tree, forwards or backwards.
+ */
+
+static ubi_btNodePtr SubSlide( register ubi_btNodePtr P,
+ register int whichway )
+ /* ------------------------------------------------------------------------ **
+ * Slide down the side of a subtree.
+ *
+ * Given a starting node, this function returns a pointer to the LEFT-, or
+ * RIGHT-most descendent, *or* (if whichway is PARENT) to the tree root.
+ *
+ * Input: P - a pointer to a starting place.
+ * whichway - the direction (LEFT, RIGHT, or PARENT) in which to
+ * travel.
+ * Output: A pointer to a node that is either the root, or has no
+ * whichway-th child but is within the subtree of P. Note that
+ * the return value may be the same as P. The return value *will
+ * be* NULL if P is NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+
+ if( NULL != P )
+ while( NULL != P->Link[ whichway ] )
+ P = P->Link[ whichway ];
+ return( P );
+ } /* SubSlide */
+
+static ubi_btNodePtr Neighbor( register ubi_btNodePtr P,
+ register int whichway )
+ /* ------------------------------------------------------------------------ **
+ * Given starting point p, return the (key order) next or preceeding node
+ * in the tree.
+ *
+ * Input: P - Pointer to our starting place node.
+ * whichway - the direction in which to travel to find the
+ * neighbor, i.e., the RIGHT neighbor or the LEFT
+ * neighbor.
+ *
+ * Output: A pointer to the neighboring node, or NULL if P was NULL.
+ *
+ * Notes: If whichway is PARENT, the results are unpredictable.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( P )
+ {
+ if( NULL != P->Link[ whichway ] )
+ return( SubSlide( P->Link[ whichway ], (char)ubi_trRevWay(whichway) ) );
+ else
+ while( NULL != P->Link[ ubi_trPARENT ] )
+ {
+ if( whichway == P->gender )
+ P = P->Link[ ubi_trPARENT ];
+ else
+ return( P->Link[ ubi_trPARENT ] );
+ }
+ }
+ return( NULL );
+ } /* Neighbor */
+
+static ubi_btNodePtr Border( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_btNodePtr p,
+ int whichway )
+ /* ------------------------------------------------------------------------ **
+ * Given starting point p, which has a key value equal to *FindMe, locate
+ * the first (index order) node with the same key value.
+ *
+ * This function is useful in trees that have can have duplicate keys.
+ * For example, consider the following tree:
+ * Tree Traversal
+ * 2 If <p> points to the root and <whichway> is RIGHT, 3
+ * / \ then the return value will be a pointer to the / \
+ * 2 2 RIGHT child of the root node. The tree on 2 5
+ * / / \ the right shows the order of traversal. / / \
+ * 1 2 3 1 4 6
+ *
+ * Input: RootPtr - Pointer to the tree root structure.
+ * FindMe - Key value for comparisons.
+ * p - Pointer to the starting-point node.
+ * whichway - the direction in which to travel to find the
+ * neighbor, i.e., the RIGHT neighbor or the LEFT
+ * neighbor.
+ *
+ * Output: A pointer to the first (index, or "traversal", order) node with
+ * a Key value that matches *FindMe.
+ *
+ * Notes: If whichway is PARENT, or if the tree does not allow duplicate
+ * keys, this function will return <p>.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr q;
+
+ /* Exit if there's nothing that can be done. */
+ if( !ubi_trDups_OK( RootPtr ) || (ubi_trPARENT == whichway) )
+ return( p );
+
+ /* First, if needed, move up the tree. We need to get to the root of the
+ * subtree that contains all of the matching nodes.
+ */
+ q = p->Link[ubi_trPARENT];
+ while( (NULL != q)
+ && (ubi_trEQUAL == ubi_trAbNormal( (*(RootPtr->cmp))(FindMe, q) )) )
+ {
+ p = q;
+ q = p->Link[ubi_trPARENT];
+ }
+
+ /* Next, move back down in the "whichway" direction. */
+ q = p->Link[whichway];
+ while( NULL != q )
+ {
+ q = qFind( RootPtr->cmp, FindMe, q );
+ if( q )
+ {
+ p = q;
+ q = p->Link[whichway];
+ }
+ }
+ return( p );
+ } /* Border */
+
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+long ubi_btSgn( register long x )
+ /* ------------------------------------------------------------------------ **
+ * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+ *
+ * Input: x - a signed long integer value.
+ *
+ * Output: the "sign" of x, represented as follows:
+ * -1 == negative
+ * 0 == zero (no sign)
+ * 1 == positive
+ *
+ * Note: This utility is provided in order to facilitate the conversion
+ * of C comparison function return values into BinTree direction
+ * values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
+ * ubi_trAbNormal() conversion macro!
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( (x)?((x>0)?(1):(-1)):(0) );
+ } /* ubi_btSgn */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: a pointer to a ubi_btNode structure to be initialized.
+ * Output: a pointer to the initialized ubi_btNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ NodePtr->Link[ ubi_trLEFT ] = NULL;
+ NodePtr->Link[ ubi_trPARENT ] = NULL;
+ NodePtr->Link[ ubi_trRIGHT ] = NULL;
+ NodePtr->gender = ubi_trEQUAL;
+ NodePtr->balance = ubi_trEQUAL;
+ return( NodePtr );
+ } /* ubi_btInitNode */
+
+ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
+ ubi_btCompFunc CompFunc,
+ char Flags )
+ /* ------------------------------------------------------------------------ **
+ * Initialize the fields of a Tree Root header structure.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure to be
+ * initialized.
+ * CompFunc - a pointer to a comparison function that will be used
+ * whenever nodes in the tree must be compared against
+ * outside values.
+ * Flags - One bytes worth of flags. Flags include
+ * ubi_trOVERWRITE and ubi_trDUPKEY. See the header
+ * file for more info.
+ *
+ * Output: a pointer to the initialized ubi_btRoot structure (ie. the
+ * same value as RootPtr).
+ *
+ * Note: The interface to this function has changed from that of
+ * previous versions. The <Flags> parameter replaces two
+ * boolean parameters that had the same basic effect.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( RootPtr )
+ {
+ RootPtr->root = NULL;
+ RootPtr->count = 0L;
+ RootPtr->cmp = CompFunc;
+ RootPtr->flags = (Flags & ubi_trDUPKEY) ? ubi_trDUPKEY : Flags;
+ } /* There are only two supported flags, and they are
+ * mutually exclusive. ubi_trDUPKEY takes precedence
+ * over ubi_trOVERWRITE.
+ */
+ return( RootPtr );
+ } /* ubi_btInitTree */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode )
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr OtherP,
+ parent = NULL;
+ char tmp;
+
+ if( NULL == OldNode ) /* If they didn't give us a pointer, supply our own. */
+ OldNode = &OtherP;
+
+ (void)ubi_btInitNode( NewNode ); /* Init the new node's BinTree fields. */
+
+ /* Find a place for the new node. */
+ *OldNode = TreeFind(ItemPtr, (RootPtr->root), &parent, &tmp, (RootPtr->cmp));
+
+ /* Now add the node to the tree... */
+ if( NULL == (*OldNode) ) /* The easy one: we have a space for a new node! */
+ {
+ if( NULL == parent )
+ RootPtr->root = NewNode;
+ else
+ {
+ parent->Link[(int)tmp] = NewNode;
+ NewNode->Link[ubi_trPARENT] = parent;
+ NewNode->gender = tmp;
+ }
+ (RootPtr->count)++;
+ return( ubi_trTRUE );
+ }
+
+ /* If we reach this point, we know that a duplicate node exists. This
+ * section adds the node to the tree if duplicate keys are allowed.
+ */
+ if( ubi_trDups_OK(RootPtr) ) /* Key exists, add duplicate */
+ {
+ ubi_btNodePtr q;
+
+ tmp = ubi_trRIGHT;
+ q = (*OldNode);
+ *OldNode = NULL;
+ while( NULL != q )
+ {
+ parent = q;
+ if( tmp == ubi_trEQUAL )
+ tmp = ubi_trRIGHT;
+ q = q->Link[(int)tmp];
+ if ( q )
+ tmp = ubi_trAbNormal( (*(RootPtr->cmp))(ItemPtr, q) );
+ }
+ parent->Link[(int)tmp] = NewNode;
+ NewNode->Link[ubi_trPARENT] = parent;
+ NewNode->gender = tmp;
+ (RootPtr->count)++;
+ return( ubi_trTRUE );
+ }
+
+ /* If we get to *this* point, we know that we are not allowed to have
+ * duplicate nodes, but our node keys match, so... may we replace the
+ * old one?
+ */
+ if( ubi_trOvwt_OK(RootPtr) ) /* Key exists, we replace */
+ {
+ if( NULL == parent )
+ ReplaceNode( &(RootPtr->root), *OldNode, NewNode );
+ else
+ ReplaceNode( &(parent->Link[(int)((*OldNode)->gender)]),
+ *OldNode, NewNode );
+ return( ubi_trTRUE );
+ }
+
+ return( ubi_trFALSE ); /* Failure: could not replace an existing node. */
+ } /* ubi_btInsert */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr DeadNode )
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p,
+ *parentp;
+ int tmp;
+
+ /* if the node has both left and right subtrees, then we have to swap
+ * it with another node. The other node we choose will be the Prev()ious
+ * node, which is garunteed to have no RIGHT child.
+ */
+ if( (NULL != DeadNode->Link[ubi_trLEFT])
+ && (NULL != DeadNode->Link[ubi_trRIGHT]) )
+ SwapNodes( RootPtr, DeadNode, ubi_btPrev( DeadNode ) );
+
+ /* The parent of the node to be deleted may be another node, or it may be
+ * the root of the tree. Since we're not sure, it's best just to have
+ * a pointer to the parent pointer, whatever it is.
+ */
+ if( NULL == DeadNode->Link[ubi_trPARENT] )
+ parentp = &( RootPtr->root );
+ else
+ parentp = &((DeadNode->Link[ubi_trPARENT])->Link[(int)(DeadNode->gender)]);
+
+ /* Now link the parent to the only grand-child and patch up the gender. */
+ tmp = ((DeadNode->Link[ubi_trLEFT])?ubi_trLEFT:ubi_trRIGHT);
+
+ p = (DeadNode->Link[tmp]);
+ if( NULL != p )
+ {
+ p->Link[ubi_trPARENT] = DeadNode->Link[ubi_trPARENT];
+ p->gender = DeadNode->gender;
+ }
+ (*parentp) = p;
+
+ /* Finished, reduce the node count and return. */
+ (RootPtr->count)--;
+ return( DeadNode );
+ } /* ubi_btRemove */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp )
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr p;
+ ubi_btNodePtr parent;
+ char whichkid;
+
+ /* Start by searching for a matching node. */
+ p = TreeFind( FindMe,
+ RootPtr->root,
+ &parent,
+ &whichkid,
+ RootPtr->cmp );
+
+ if( NULL != p ) /* If we have found a match, we can resolve as follows: */
+ {
+ switch( CompOp )
+ {
+ case ubi_trLT: /* It's just a jump to the left... */
+ p = Border( RootPtr, FindMe, p, ubi_trLEFT );
+ return( Neighbor( p, ubi_trLEFT ) );
+ case ubi_trGT: /* ...and then a jump to the right. */
+ p = Border( RootPtr, FindMe, p, ubi_trRIGHT );
+ return( Neighbor( p, ubi_trRIGHT ) );
+ default:
+ p = Border( RootPtr, FindMe, p, ubi_trLEFT );
+ return( p );
+ }
+ }
+
+ /* Else, no match. */
+ if( ubi_trEQ == CompOp ) /* If we were looking for an exact match... */
+ return( NULL ); /* ...forget it. */
+
+ /* We can still return a valid result for GT, GE, LE, and LT.
+ * <parent> points to a node with a value that is either just before or
+ * just after the target value.
+ * Remaining possibilities are LT and GT (including LE & GE).
+ */
+ if( (ubi_trLT == CompOp) || (ubi_trLE == CompOp) )
+ return( (ubi_trLEFT == whichkid) ? Neighbor( parent, whichkid ) : parent );
+ else
+ return( (ubi_trRIGHT == whichkid) ? Neighbor( parent, whichkid ) : parent );
+ } /* ubi_btLocate */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_btLocate().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( qFind( RootPtr->cmp, FindMe, RootPtr->root ) );
+ } /* ubi_btFind */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Next node in the
+ * tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "next" node in the tree, or NULL if P pointed
+ * to the "last" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( Neighbor( P, ubi_trRIGHT ) );
+ } /* ubi_btNext */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Previous node in
+ * the tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "previous" node in the tree, or NULL if P
+ * pointed to the "first" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( Neighbor( P, ubi_trLEFT ) );
+ } /* ubi_btPrev */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) First node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "first" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( SubSlide( P, ubi_trLEFT ) );
+ } /* ubi_btFirst */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Last node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "last" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( SubSlide( P, ubi_trRIGHT ) );
+ } /* ubi_btLast */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the first (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the first node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ *
+ * 4.7: Bug found & fixed by Massimo Campostrini,
+ * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( (NULL == p)
+ || (ubi_trEQUAL != ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) )) )
+ return( NULL );
+ return( Border( RootPtr, MatchMe, p, ubi_trLEFT ) );
+ } /* ubi_btFirstOf */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the last (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the last node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ *
+ * 4.7: Bug found & fixed by Massimo Campostrini,
+ * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( (NULL != p)
+ || (ubi_trEQUAL != ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) )) )
+ return( NULL );
+ return( Border( RootPtr, MatchMe, p, ubi_trRIGHT ) );
+ } /* ubi_btLastOf */
+
+unsigned long ubi_btTraverse( ubi_btRootPtr RootPtr,
+ ubi_btActionRtn EachNode,
+ void *UserData )
+ /* ------------------------------------------------------------------------ **
+ * Traverse a tree in sorted order (non-recursively). At each node, call
+ * (*EachNode)(), passing a pointer to the current node, and UserData as the
+ * second parameter.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the tree to be traversed.
+ * EachNode - a pointer to a function to be called at each node
+ * as the node is visited.
+ * UserData - a generic pointer that may point to anything that
+ * you choose.
+ *
+ * Output: A count of the number of nodes visited. This will be zero
+ * if the tree is empty.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p = ubi_btFirst( RootPtr->root );
+ unsigned long count = 0;
+
+ while( NULL != p )
+ {
+ (*EachNode)( p, UserData );
+ count++;
+ p = ubi_btNext( p );
+ }
+ return( count );
+ } /* ubi_btTraverse */
+
+unsigned long ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode )
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Return a count of the number of nodes deleted.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the root of the tree to delete.
+ * FreeNode - a function that will be called for each node in the
+ * tree to deallocate the memory used by the node.
+ *
+ * Output: The number of nodes removed from the tree.
+ * A value of 0 will be returned if:
+ * - The tree actually contains 0 entries.
+ * - the value of <RootPtr> is NULL, in which case the tree is
+ * assumed to be empty
+ * - the value of <FreeNode> is NULL, in which case entries
+ * cannot be removed, so 0 is returned. *Make sure that you
+ * provide a valid value for <FreeNode>*.
+ * In all other cases, you should get a positive value equal to
+ * the value of RootPtr->count upon entry.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p, q;
+ unsigned long count = 0;
+
+ if( (NULL == RootPtr) || (NULL == FreeNode) )
+ return( 0 );
+
+ p = ubi_btFirst( RootPtr->root );
+ while( NULL != p )
+ {
+ q = p;
+ while( q->Link[ubi_trRIGHT] )
+ q = SubSlide( q->Link[ubi_trRIGHT], ubi_trLEFT );
+ p = q->Link[ubi_trPARENT];
+ if( NULL != p )
+ p->Link[ ((p->Link[ubi_trLEFT] == q)?ubi_trLEFT:ubi_trRIGHT) ] = NULL;
+ (*FreeNode)((void *)q);
+ count++;
+ }
+
+ /* overkill... */
+ (void)ubi_btInitTree( RootPtr,
+ RootPtr->cmp,
+ RootPtr->flags );
+ return( count );
+ } /* ubi_btKillTree */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader )
+ /* ------------------------------------------------------------------------ **
+ * Returns a pointer to a leaf node.
+ *
+ * Input: leader - Pointer to a node at which to start the descent.
+ *
+ * Output: A pointer to a leaf node selected in a somewhat arbitrary
+ * manner.
+ *
+ * Notes: I wrote this function because I was using splay trees as a
+ * database cache. The cache had a maximum size on it, and I
+ * needed a way of choosing a node to sacrifice if the cache
+ * became full. In a splay tree, less recently accessed nodes
+ * tend toward the bottom of the tree, meaning that leaf nodes
+ * are good candidates for removal. (I really can't think of
+ * any other reason to use this function.)
+ * + In a simple binary tree or an AVL tree, the most recently
+ * added nodes tend to be nearer the bottom, making this a *bad*
+ * way to choose which node to remove from the cache.
+ * + Randomizing the traversal order is probably a good idea. You
+ * can improve the randomization of leaf node selection by passing
+ * in pointers to nodes other than the root node each time. A
+ * pointer to any node in the tree will do. Of course, if you
+ * pass a pointer to a leaf node you'll get the same thing back.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr follower = NULL;
+ int whichway = ubi_trLEFT;
+
+ while( NULL != leader )
+ {
+ follower = leader;
+ leader = follower->Link[ whichway ];
+ if( NULL == leader )
+ {
+ whichway = ubi_trRevWay( whichway );
+ leader = follower->Link[ whichway ];
+ }
+ }
+
+ return( follower );
+ } /* ubi_btLeafNode */
+
+int ubi_btModuleID( int size, char *list[] )
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( size > 0 )
+ {
+ list[0] = ModuleID;
+ if( size > 1 )
+ list[1] = NULL;
+ return( 1 );
+ }
+ return( 0 );
+ } /* ubi_btModuleID */
+
+
+/* ========================================================================== */
diff --git a/source/ubiqx/ubi_BinTree.h b/source/ubiqx/ubi_BinTree.h
new file mode 100644
index 00000000000..c0c6d593094
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.h
@@ -0,0 +1,864 @@
+#ifndef UBI_BINTREE_H
+#define UBI_BINTREE_H
+/* ========================================================================== **
+ * ubi_BinTree.h
+ *
+ * Copyright (C) 1991-1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements a simple binary tree.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_BinTree.h,v
+ * Revision 4.10 2000/06/06 20:38:40 crh
+ * In the ReplaceNode() function, the old node header was being copied
+ * to the new node header using a byte-by-byte copy. This was causing
+ * the 'insure' software testing program to report a memory leak. The
+ * fix was to do a simple assignement: *newnode = *oldnode;
+ * This quieted the (errant) memory leak reports and is probably a bit
+ * faster than the bytewise copy.
+ *
+ * Revision 4.9 2000/01/08 23:24:30 crh
+ * Clarified a variety of if( pointer ) lines, replacing them with
+ * if( NULL != pointer ). This is more correct, and I have heard
+ * of at least one (obscure?) system out there that uses a non-zero
+ * value for NULL.
+ * Also, speed improvement in Neighbor(). It was comparing pointers
+ * when it could have compared two gender values. The pointer
+ * comparison was somewhat indirect (does pointer equal the pointer
+ * of the parent of the node pointed to by pointer). Urq.
+ *
+ * Revision 4.8 1999/09/22 03:40:30 crh
+ * Modified ubi_btTraverse() and ubi_btKillTree(). They now return an
+ * unsigned long indicating the number of nodes processed. The change
+ * is subtle. An empty tree formerly returned False, and now returns
+ * zero.
+ *
+ * Revision 4.7 1998/10/21 06:15:07 crh
+ * Fixed bugs in FirstOf() and LastOf() reported by Massimo Campostrini.
+ * See function comments.
+ *
+ * Revision 4.6 1998/07/25 17:02:10 crh
+ * Added the ubi_trNewTree() macro.
+ *
+ * Revision 4.5 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 4.4 1998/06/03 17:42:46 crh
+ * Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
+ * included by all of the binary tree files.
+ *
+ * Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
+ * ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
+ * of tree types by simply changing a header. Unfortunately, the
+ * macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
+ * conflict if used together. You must either choose a single tree
+ * type, or use the underlying function calls directly. Compare
+ * the two header files for more information.
+ *
+ * Revision 4.3 1998/06/02 01:28:43 crh
+ * Changed ubi_null.h to sys_include.h to make it more generic.
+ *
+ * Revision 4.2 1998/05/20 04:32:36 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ * Also, the balance and gender fields of the node were declared as
+ * signed char. As I understand it, at least one SunOS or Solaris
+ * compiler doesn't like "signed char". The declarations were
+ * wrong anyway, so I changed them to simple "char".
+ *
+ * Revision 4.1 1998/03/31 06:13:47 crh
+ * Thomas Aglassinger sent E'mail pointing out errors in the
+ * dereferencing of function pointers, and a missing typecast.
+ * Thanks, Thomas!
+ *
+ * Revision 4.0 1998/03/10 03:16:04 crh
+ * Added the AVL field 'balance' to the ubi_btNode structure. This means
+ * that all BinTree modules now use the same basic node structure, which
+ * greatly simplifies the AVL module.
+ * Decided that this was a big enough change to justify a new major revision
+ * number. 3.0 was an error, so we're at 4.0.
+ *
+ * Revision 2.6 1998/01/24 06:27:30 crh
+ * Added ubi_trCount() macro.
+ *
+ * Revision 2.5 1997/12/23 03:59:21 crh
+ * In this version, all constants & macros defined in the header file have
+ * the ubi_tr prefix. Also cleaned up anything that gcc complained about
+ * when run with '-pedantic -fsyntax-only -Wall'.
+ *
+ * Revision 2.4 1997/07/26 04:11:14 crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ * and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h". I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3 1997/06/03 05:15:27 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree(). See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2 1995/10/03 22:00:40 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:43:46 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:00:33 CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ * 1) A fix to a major typo in the RepaceNode() function.
+ * 2) The addition of the static function Border().
+ * 3) The addition of the public functions FirstOf() and LastOf(), which
+ * use Border(). These functions are used with trees that allow
+ * duplicate keys.
+ * 4) A complete rewrite of the Locate() function. Locate() now accepts
+ * a "comparison" operator.
+ * 5) Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed. In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0 93/10/15 22:55:04 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_SplayTree, the locate function was
+ * called "ubi_sptLocate", but the next and previous functions remained
+ * "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+#include "sys_include.h" /* Global include file, used to adapt the ubiqx
+ * modules to the host environment and the project
+ * with which the modules will be used. See
+ * sys_include.h for more info.
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Macros and constants.
+ *
+ * General purpose:
+ * ubi_trTRUE - Boolean TRUE.
+ * ubi_trFALSE - Boolean FALSE.
+ *
+ * Flags used in the tree header:
+ * ubi_trOVERWRITE - This flag indicates that an existing node may be
+ * overwritten by a new node with a matching key.
+ * ubi_trDUPKEY - This flag indicates that the tree allows duplicate
+ * keys. If the tree does allow duplicates, the
+ * overwrite flag is ignored.
+ *
+ * Node link array index constants: (Each node has an array of three
+ * pointers. One to the left, one to the right, and one back to the
+ * parent.)
+ * ubi_trLEFT - Left child pointer.
+ * ubi_trPARENT - Parent pointer.
+ * ubi_trRIGHT - Right child pointer.
+ * ubi_trEQUAL - Synonym for PARENT.
+ *
+ * ubi_trCompOps: These values are used in the ubi_trLocate() function.
+ * ubi_trLT - request the first instance of the greatest key less than
+ * the search key.
+ * ubi_trLE - request the first instance of the greatest key that is less
+ * than or equal to the search key.
+ * ubi_trEQ - request the first instance of key that is equal to the
+ * search key.
+ * ubi_trGE - request the first instance of a key that is greater than
+ * or equal to the search key.
+ * ubi_trGT - request the first instance of the first key that is greater
+ * than the search key.
+ * -------------------------------------------------------------------------- **
+ */
+
+#define ubi_trTRUE 0xFF
+#define ubi_trFALSE 0x00
+
+#define ubi_trOVERWRITE 0x01 /* Turn on allow overwrite */
+#define ubi_trDUPKEY 0x02 /* Turn on allow duplicate keys */
+
+/* Pointer array index constants... */
+#define ubi_trLEFT 0x00
+#define ubi_trPARENT 0x01
+#define ubi_trRIGHT 0x02
+#define ubi_trEQUAL ubi_trPARENT
+
+typedef enum {
+ ubi_trLT = 1,
+ ubi_trLE,
+ ubi_trEQ,
+ ubi_trGE,
+ ubi_trGT
+ } ubi_trCompOps;
+
+/* -------------------------------------------------------------------------- **
+ * These three macros allow simple manipulation of pointer index values (LEFT,
+ * RIGHT, and PARENT).
+ *
+ * Normalize() - converts {LEFT, PARENT, RIGHT} into {-1, 0 ,1}. C
+ * uses {negative, zero, positive} values to indicate
+ * {less than, equal to, greater than}.
+ * AbNormal() - converts {negative, zero, positive} to {LEFT, PARENT,
+ * RIGHT} (opposite of Normalize()). Note: C comparison
+ * functions, such as strcmp(), return {negative, zero,
+ * positive} values, which are not necessarily {-1, 0,
+ * 1}. This macro uses the the ubi_btSgn() function to
+ * compensate.
+ * RevWay() - converts LEFT to RIGHT and RIGHT to LEFT. PARENT (EQUAL)
+ * is left as is.
+ * -------------------------------------------------------------------------- **
+ */
+#define ubi_trNormalize(W) ((char)( (W) - ubi_trEQUAL ))
+#define ubi_trAbNormal(W) ((char)( ((char)ubi_btSgn( (long)(W) )) \
+ + ubi_trEQUAL ))
+#define ubi_trRevWay(W) ((char)( ubi_trEQUAL - ((W) - ubi_trEQUAL) ))
+
+/* -------------------------------------------------------------------------- **
+ * These macros allow us to quickly read the values of the OVERWRITE and
+ * DUPlicate KEY bits of the tree root flags field.
+ * -------------------------------------------------------------------------- **
+ */
+#define ubi_trDups_OK(A) \
+ ((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+#define ubi_trOvwt_OK(A) \
+ ((ubi_trOVERWRITE & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+
+/* -------------------------------------------------------------------------- **
+ * Additional Macros...
+ *
+ * ubi_trCount() - Given a pointer to a tree root, this macro returns the
+ * number of nodes currently in the tree.
+ *
+ * ubi_trNewTree() - This macro makes it easy to declare and initialize a
+ * tree header in one step. The line
+ *
+ * static ubi_trNewTree( MyTree, cmpfn, ubi_trDUPKEY );
+ *
+ * is equivalent to
+ *
+ * static ubi_trRoot MyTree[1]
+ * = {{ NULL, cmpfn, 0, ubi_trDUPKEY }};
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+#define ubi_trCount( R ) (((ubi_trRootPtr)(R))->count)
+
+#define ubi_trNewTree( N, C, F ) ubi_trRoot (N)[1] = {{ NULL, (C), 0, (F) }}
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ *
+ * ubi_trBool - Your typcial true or false...
+ *
+ * Item Pointer: The ubi_btItemPtr is a generic pointer. It is used to
+ * indicate a key that is being searched for within the tree.
+ * Searching occurs whenever the ubi_trFind(), ubi_trLocate(),
+ * or ubi_trInsert() functions are called.
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef unsigned char ubi_trBool;
+
+typedef void *ubi_btItemPtr; /* A pointer to key data within a node. */
+
+/* ------------------------------------------------------------------------- **
+ * Binary Tree Node Structure: This structure defines the basic elements of
+ * the tree nodes. In general you *SHOULD NOT PLAY WITH THESE FIELDS*!
+ * But, of course, I have to put the structure into this header so that
+ * you can use it as a building block.
+ *
+ * The fields are as follows:
+ * Link - an array of pointers. These pointers are manipulated by
+ * the BT routines. The pointers indicate the left and right
+ * child nodes and the parent node. By keeping track of the
+ * parent pointer, we avoid the need for recursive routines or
+ * hand-tooled stacks to keep track of our path back to the
+ * root. The use of these pointers is subject to change without
+ * notice.
+ * gender - a one-byte field indicating whether the node is the RIGHT or
+ * LEFT child of its parent. If the node is the root of the
+ * tree, gender will be PARENT.
+ * balance - only used by the AVL tree module. This field indicates
+ * the height balance at a given node. See ubi_AVLtree for
+ * details.
+ *
+ * ------------------------------------------------------------------------- **
+ */
+typedef struct ubi_btNodeStruct {
+ struct ubi_btNodeStruct *Link[ 3 ];
+ char gender;
+ char balance;
+ } ubi_btNode;
+
+typedef ubi_btNode *ubi_btNodePtr; /* Pointer to an ubi_btNode structure. */
+
+/* ------------------------------------------------------------------------- **
+ * The next three typedefs define standard function types used by the binary
+ * tree management routines. In particular:
+ *
+ * ubi_btCompFunc is a pointer to a comparison function. Comparison
+ * functions are passed an ubi_btItemPtr and an
+ * ubi_btNodePtr. They return a value that is (<0), 0,
+ * or (>0) to indicate that the Item is (respectively)
+ * "less than", "equal to", or "greater than" the Item
+ * contained within the node. (See ubi_btInitTree()).
+ * ubi_btActionRtn is a pointer to a function that may be called for each
+ * node visited when performing a tree traversal (see
+ * ubi_btTraverse()). The function will be passed two
+ * parameters: the first is a pointer to a node in the
+ * tree, the second is a generic pointer that may point to
+ * anything that you like.
+ * ubi_btKillNodeRtn is a pointer to a function that will deallocate the
+ * memory used by a node (see ubi_btKillTree()). Since
+ * memory management is left up to you, deallocation may
+ * mean anything that you want it to mean. Just remember
+ * that the tree *will* be destroyed and that none of the
+ * node pointers will be valid any more.
+ * ------------------------------------------------------------------------- **
+ */
+
+typedef int (*ubi_btCompFunc)( ubi_btItemPtr, ubi_btNodePtr );
+
+typedef void (*ubi_btActionRtn)( ubi_btNodePtr, void * );
+
+typedef void (*ubi_btKillNodeRtn)( ubi_btNodePtr );
+
+/* -------------------------------------------------------------------------- **
+ * Tree Root Structure: This structure gives us a convenient handle for
+ * accessing whole binary trees. The fields are:
+ * root - A pointer to the root node of the tree.
+ * count - A count of the number of nodes stored in the tree.
+ * cmp - A pointer to the comparison routine to be used when building or
+ * searching the tree.
+ * flags - A set of bit flags. Two flags are currently defined:
+ *
+ * ubi_trOVERWRITE - If set, this flag indicates that a new node should
+ * (bit 0x01) overwrite an old node if the two have identical
+ * keys (ie., the keys are equal).
+ * ubi_trDUPKEY - If set, this flag indicates that the tree is
+ * (bit 0x02) allowed to contain nodes with duplicate keys.
+ *
+ * NOTE: ubi_trInsert() tests ubi_trDUPKEY before ubi_trOVERWRITE.
+ *
+ * All of these values are set when you initialize the root structure by
+ * calling ubi_trInitTree().
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef struct {
+ ubi_btNodePtr root; /* A pointer to the root node of the tree */
+ ubi_btCompFunc cmp; /* A pointer to the tree's comparison function */
+ unsigned long count; /* A count of the number of nodes in the tree */
+ char flags; /* Overwrite Y|N, Duplicate keys Y|N... */
+ } ubi_btRoot;
+
+typedef ubi_btRoot *ubi_btRootPtr; /* Pointer to an ubi_btRoot structure. */
+
+
+/* -------------------------------------------------------------------------- **
+ * Function Prototypes.
+ */
+
+long ubi_btSgn( long x );
+ /* ------------------------------------------------------------------------ **
+ * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+ *
+ * Input: x - a signed long integer value.
+ *
+ * Output: the "sign" of x, represented as follows:
+ * -1 == negative
+ * 0 == zero (no sign)
+ * 1 == positive
+ *
+ * Note: This utility is provided in order to facilitate the conversion
+ * of C comparison function return values into BinTree direction
+ * values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
+ * AbNormal() conversion macro!
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: a pointer to a ubi_btNode structure to be initialized.
+ * Output: a pointer to the initialized ubi_btNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
+ ubi_btCompFunc CompFunc,
+ char Flags );
+ /* ------------------------------------------------------------------------ **
+ * Initialize the fields of a Tree Root header structure.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure to be
+ * initialized.
+ * CompFunc - a pointer to a comparison function that will be used
+ * whenever nodes in the tree must be compared against
+ * outside values.
+ * Flags - One bytes worth of flags. Flags include
+ * ubi_trOVERWRITE and ubi_trDUPKEY. See the header
+ * file for more info.
+ *
+ * Output: a pointer to the initialized ubi_btRoot structure (ie. the
+ * same value as RootPtr).
+ *
+ * Note: The interface to this function has changed from that of
+ * previous versions. The <Flags> parameter replaces two
+ * boolean parameters that had the same basic effect.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode );
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr DeadNode );
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp );
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe );
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_btLocate().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Next node in the
+ * tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "next" node in the tree, or NULL if P pointed
+ * to the "last" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Previous node in
+ * the tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "previous" node in the tree, or NULL if P
+ * pointed to the "first" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) First node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "first" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Last node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "last" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p );
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the first (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the first node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ *
+ * 4.7: Bug found & fixed by Massimo Campostrini,
+ * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p );
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the last (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the last node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ *
+ * 4.7: Bug found & fixed by Massimo Campostrini,
+ * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+unsigned long ubi_btTraverse( ubi_btRootPtr RootPtr,
+ ubi_btActionRtn EachNode,
+ void *UserData );
+ /* ------------------------------------------------------------------------ **
+ * Traverse a tree in sorted order (non-recursively). At each node, call
+ * (*EachNode)(), passing a pointer to the current node, and UserData as the
+ * second parameter.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the tree to be traversed.
+ * EachNode - a pointer to a function to be called at each node
+ * as the node is visited.
+ * UserData - a generic pointer that may point to anything that
+ * you choose.
+ *
+ * Output: A count of the number of nodes visited. This will be zero
+ * if the tree is empty.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+unsigned long ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode );
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Return a count of the number of nodes deleted.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the root of the tree to delete.
+ * FreeNode - a function that will be called for each node in the
+ * tree to deallocate the memory used by the node.
+ *
+ * Output: The number of nodes removed from the tree.
+ * A value of 0 will be returned if:
+ * - The tree actually contains 0 entries.
+ * - the value of <RootPtr> is NULL, in which case the tree is
+ * assumed to be empty
+ * - the value of <FreeNode> is NULL, in which case entries
+ * cannot be removed, so 0 is returned. *Make sure that you
+ * provide a valid value for <FreeNode>*.
+ * In all other cases, you should get a positive value equal to
+ * the value of RootPtr->count upon entry.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader );
+ /* ------------------------------------------------------------------------ **
+ * Returns a pointer to a leaf node.
+ *
+ * Input: leader - Pointer to a node at which to start the descent.
+ *
+ * Output: A pointer to a leaf node selected in a somewhat arbitrary
+ * manner.
+ *
+ * Notes: I wrote this function because I was using splay trees as a
+ * database cache. The cache had a maximum size on it, and I
+ * needed a way of choosing a node to sacrifice if the cache
+ * became full. In a splay tree, less recently accessed nodes
+ * tend toward the bottom of the tree, meaning that leaf nodes
+ * are good candidates for removal. (I really can't think of
+ * any other reason to use this function.)
+ * + In a simple binary tree or an AVL tree, the most recently
+ * added nodes tend to be nearer the bottom, making this a *bad*
+ * way to choose which node to remove from the cache.
+ * + Randomizing the traversal order is probably a good idea. You
+ * can improve the randomization of leaf node selection by passing
+ * in pointers to nodes other than the root node each time. A
+ * pointer to any node in the tree will do. Of course, if you
+ * pass a pointer to a leaf node you'll get the same thing back.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+int ubi_btModuleID( int size, char *list[] );
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#define ubi_trItemPtr ubi_btItemPtr
+
+#define ubi_trNode ubi_btNode
+#define ubi_trNodePtr ubi_btNodePtr
+
+#define ubi_trRoot ubi_btRoot
+#define ubi_trRootPtr ubi_btRootPtr
+
+#define ubi_trCompFunc ubi_btCompFunc
+#define ubi_trActionRtn ubi_btActionRtn
+#define ubi_trKillNodeRtn ubi_btKillNodeRtn
+
+#define ubi_trSgn( x ) ubi_btSgn( x )
+
+#define ubi_trInitNode( Np ) ubi_btInitNode( (ubi_btNodePtr)(Np) )
+
+#define ubi_trInitTree( Rp, Cf, Fl ) \
+ ubi_btInitTree( (ubi_btRootPtr)(Rp), (ubi_btCompFunc)(Cf), (Fl) )
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+ ubi_btInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+ (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+ ubi_btRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+ ubi_btLocate( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+ ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trNext( P ) ubi_btNext( (ubi_btNodePtr)(P) )
+
+#define ubi_trPrev( P ) ubi_btPrev( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirst( P ) ubi_btFirst( (ubi_btNodePtr)(P) )
+
+#define ubi_trLast( P ) ubi_btLast( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirstOf( Rp, Ip, P ) \
+ ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#define ubi_trLastOf( Rp, Ip, P ) \
+ ubi_btLastOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#define ubi_trTraverse( Rp, En, Ud ) \
+ ubi_btTraverse((ubi_btRootPtr)(Rp), (ubi_btActionRtn)(En), (void *)(Ud))
+
+#define ubi_trKillTree( Rp, Fn ) \
+ ubi_btKillTree( (ubi_btRootPtr)(Rp), (ubi_btKillNodeRtn)(Fn) )
+
+#define ubi_trLeafNode( Nd ) \
+ ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
+
+#define ubi_trModuleID( s, l ) ubi_btModuleID( s, l )
+
+/* ========================================================================== */
+#endif /* UBI_BINTREE_H */
diff --git a/source/ubiqx/ubi_Cache.c b/source/ubiqx/ubi_Cache.c
new file mode 100644
index 00000000000..f428dcefe97
--- /dev/null
+++ b/source/ubiqx/ubi_Cache.c
@@ -0,0 +1,505 @@
+/* ========================================================================== **
+ * ubi_Cache.c
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements a generic cache.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This module uses a splay tree to implement a simple cache. The cache
+ * module adds a thin layer of functionality to the splay tree. In
+ * particular:
+ *
+ * - The tree (cache) may be limited in size by the number of
+ * entries permitted or the amount of memory used. When either
+ * limit is exceeded cache entries are removed until the cache
+ * conforms.
+ * - Some statistical information is kept so that an approximate
+ * "hit ratio" can be calculated.
+ * - There are several functions available that provide access to
+ * and management of cache size limits, hit ratio, and tree
+ * trimming.
+ *
+ * The splay tree is used because recently accessed items tend toward the
+ * top of the tree and less recently accessed items tend toward the bottom.
+ * This makes it easy to purge less recently used items should the cache
+ * exceed its limits.
+ *
+ * To use this module, you will need to supply a comparison function of
+ * type ubi_trCompFunc and a node-freeing function of type
+ * ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
+ * these. (This is all basic ubiqx tree management stuff.)
+ *
+ * Notes:
+ *
+ * - Cache performance will start to suffer dramatically if the
+ * cache becomes large enough to force the OS to start swapping
+ * memory to disk. This is because the nodes of the underlying tree
+ * will be scattered across memory in an order that is completely
+ * unrelated to their traversal order. As more and more of the
+ * cache is placed into swap space, more and more swaps will be
+ * required for a simple traversal (...and then there's the splay
+ * operation).
+ *
+ * In one simple test under Linux, the load and dump of a cache of
+ * 400,000 entries took only 1min, 40sec of real time. The same
+ * test with 450,000 records took 2 *hours* and eight minutes.
+ *
+ * - In an effort to save memory, I considered using an unsigned
+ * short to save the per-entry entry size. I would have tucked this
+ * value into some unused space in the tree node structure. On
+ * 32-bit word aligned systems this would have saved an additional
+ * four bytes per entry. I may revisit this issue, but for now I've
+ * decided against it.
+ *
+ * Using an unsigned short would limit the size of an entry to 64K
+ * bytes. That's probably more than enough for most applications.
+ * The key word in that last sentence, however, is "probably". I
+ * really dislike imposing such limits on things.
+ *
+ * - Each entry keeps track of the amount of memory it used and the
+ * cache header keeps the total. This information is provided via
+ * the EntrySize parameter in ubi_cachePut(), so it is up to you to
+ * make sure that the numbers are accurate. (The numbers don't even
+ * have to represent bytes used.)
+ *
+ * As you consider this, note that the strdup() function--as an
+ * example--will call malloc(). The latter generally allocates a
+ * multiple of the system word size, which may be more than the
+ * number of bytes needed to store the string.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_Cache.c,v
+ * Revision 0.4 1999/09/22 03:42:24 crh
+ * Fixed a minor typo.
+ *
+ * Revision 0.3 1998/06/03 18:00:15 crh
+ * Further fiddling with sys_include.h, which is no longer explicitly
+ * included by this module since it is inherited from ubi_BinTree.h.
+ *
+ * Revision 0.2 1998/06/02 01:36:18 crh
+ * Changed include name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.1 1998/05/20 04:36:02 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.0 1997/12/18 06:24:33 crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_Cache.h" /* Header for *this* module. */
+
+/* -------------------------------------------------------------------------- **
+ * Static data...
+ */
+
+/* commented out until I make use of it...
+static char ModuleID[] =
+"ubi_Cache\n\
+\tRevision: 0.4 \n\
+\tDate: 1999/09/22 03:42:24 \n\
+\tAuthor: crh \n";
+*/
+
+/* -------------------------------------------------------------------------- **
+ * Internal functions...
+ */
+
+static void free_entry( ubi_cacheRootPtr CachePtr, ubi_cacheEntryPtr EntryPtr )
+ /* ------------------------------------------------------------------------ **
+ * Free a ubi_cacheEntry, and adjust the mem_used counter accordingly.
+ *
+ * Input: CachePtr - A pointer to the cache from which the entry has
+ * been removed.
+ * EntryPtr - A pointer to the already removed entry.
+ *
+ * Output: none.
+ *
+ * Notes: The entry must be removed from the cache *before* this function
+ * is called!!!!
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ CachePtr->mem_used -= EntryPtr->entry_size;
+ (*CachePtr->free_func)( (void *)EntryPtr );
+ } /* free_entry */
+
+static void cachetrim( ubi_cacheRootPtr crptr )
+ /* ------------------------------------------------------------------------ **
+ * Remove entries from the cache until the number of entries and the amount
+ * of memory used are *both* below or at the maximum.
+ *
+ * Input: crptr - pointer to the cache to be trimmed.
+ *
+ * Output: None.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ while( ( crptr->max_entries && (crptr->max_entries < crptr->root.count) )
+ || ( crptr->max_memory && (crptr->max_memory < crptr->mem_used) ) )
+ {
+ if( !ubi_cacheReduce( crptr, 1 ) )
+ return;
+ }
+ } /* cachetrim */
+
+
+/* -------------------------------------------------------------------------- **
+ * Exported functions...
+ */
+
+ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
+ ubi_trCompFunc CompFunc,
+ ubi_trKillNodeRtn FreeFunc,
+ unsigned long MaxEntries,
+ unsigned long MaxMemory )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a cache header structure.
+ *
+ * Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
+ * to be initialized.
+ * CompFunc - A pointer to the function that will be called
+ * to compare two cache values. See the module
+ * comments, above, for more information.
+ * FreeFunc - A pointer to a function that will be called
+ * to free a cache entry. If you allocated
+ * the cache entry using malloc(), then this
+ * will likely be free(). If you are allocating
+ * cache entries from a free list, then this will
+ * likely be a function that returns memory to the
+ * free list, etc.
+ * MaxEntries - The maximum number of entries that will be
+ * allowed to exist in the cache. If this limit
+ * is exceeded, then existing entries will be
+ * removed from the cache. A value of zero
+ * indicates that there is no limit on the number
+ * of cache entries. See ubi_cachePut().
+ * MaxMemory - The maximum amount of memory, in bytes, to be
+ * allocated to the cache (excluding the cache
+ * header). If this is exceeded, existing entries
+ * in the cache will be removed until enough memory
+ * has been freed to meet the condition. See
+ * ubi_cachePut().
+ *
+ * Output: A pointer to the initialized cache (i.e., the same as CachePtr).
+ *
+ * Notes: Both MaxEntries and MaxMemory may be changed after the cache
+ * has been created. See
+ * ubi_cacheSetMaxEntries()
+ * ubi_cacheSetMaxMemory()
+ * ubi_cacheGetMaxEntries()
+ * ubi_cacheGetMaxMemory() (the latter two are macros).
+ *
+ * - Memory is allocated in multiples of the word size. The
+ * return value of the strlen() function does not reflect
+ * this; it will allways be less than or equal to the amount
+ * of memory actually allocated. Keep this in mind when
+ * choosing a value for MaxMemory.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( CachePtr )
+ {
+ (void)ubi_trInitTree( CachePtr, CompFunc, ubi_trOVERWRITE );
+ CachePtr->free_func = FreeFunc;
+ CachePtr->max_entries = MaxEntries;
+ CachePtr->max_memory = MaxMemory;
+ CachePtr->mem_used = 0;
+ CachePtr->cache_hits = 0;
+ CachePtr->cache_trys = 0;
+ }
+ return( CachePtr );
+ } /* ubi_cacheInit */
+
+ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr )
+ /* ------------------------------------------------------------------------ **
+ * Remove and free all entries in an existing cache.
+ *
+ * Input: CachePtr - A pointer to the cache that is to be cleared.
+ *
+ * Output: A pointer to the cache header (i.e., the same as CachePtr).
+ * This function re-initializes the cache header.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( CachePtr )
+ {
+ (void)ubi_trKillTree( CachePtr, CachePtr->free_func );
+ CachePtr->mem_used = 0;
+ CachePtr->cache_hits = 0;
+ CachePtr->cache_trys = 0;
+ }
+ return( CachePtr );
+ } /* ubi_cacheClear */
+
+void ubi_cachePut( ubi_cacheRootPtr CachePtr,
+ unsigned long EntrySize,
+ ubi_cacheEntryPtr EntryPtr,
+ ubi_trItemPtr Key )
+ /* ------------------------------------------------------------------------ **
+ * Add an entry to the cache.
+ *
+ * Input: CachePtr - A pointer to the cache into which the entry
+ * will be added.
+ * EntrySize - The size, in bytes, of the memory block indicated
+ * by EntryPtr. This will be copied into the
+ * EntryPtr->entry_size field.
+ * EntryPtr - A pointer to a memory block that begins with a
+ * ubi_cacheEntry structure. The entry structure
+ * should be followed immediately by the data to be
+ * cached (even if that is a pointer to yet more data).
+ * Key - Pointer used to identify the lookup key within the
+ * Entry.
+ *
+ * Output: None.
+ *
+ * Notes: After adding the new node, the cache is "trimmed". This
+ * removes extra nodes if the tree has exceeded it's memory or
+ * entry count limits. It is unlikely that the newly added node
+ * will be purged from the cache (assuming a reasonably large
+ * cache), since new nodes in a splay tree (which is what this
+ * module was designed to use) are moved to the top of the tree
+ * and the cache purge process removes nodes from the bottom of
+ * the tree.
+ * - The underlying splay tree is opened in OVERWRITE mode. If
+ * the input key matches an existing key, the existing entry will
+ * be politely removed from the tree and freed.
+ * - Memory is allocated in multiples of the word size. The
+ * return value of the strlen() function does not reflect
+ * this; it will allways be less than or equal to the amount
+ * of memory actually allocated.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_trNodePtr OldNode;
+
+ EntryPtr->entry_size = EntrySize;
+ CachePtr->mem_used += EntrySize;
+ (void)ubi_trInsert( CachePtr, EntryPtr, Key, &OldNode );
+ if( OldNode )
+ free_entry( CachePtr, (ubi_cacheEntryPtr)OldNode );
+
+ cachetrim( CachePtr );
+ } /* ubi_cachePut */
+
+ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
+ ubi_trItemPtr FindMe )
+ /* ------------------------------------------------------------------------ **
+ * Attempt to retrieve an entry from the cache.
+ *
+ * Input: CachePtr - A ponter to the cache that is to be searched.
+ * FindMe - A ubi_trItemPtr that indicates the key for which
+ * to search.
+ *
+ * Output: A pointer to the cache entry that was found, or NULL if no
+ * matching entry was found.
+ *
+ * Notes: This function also updates the hit ratio counters.
+ * The counters are unsigned short. If the number of cache tries
+ * reaches 32768, then both the number of tries and the number of
+ * hits are divided by two. This prevents the counters from
+ * overflowing. See the comments in ubi_cacheHitRatio() for
+ * additional notes.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_trNodePtr FoundPtr;
+
+ FoundPtr = ubi_trFind( CachePtr, FindMe );
+
+ if( FoundPtr )
+ CachePtr->cache_hits++;
+ CachePtr->cache_trys++;
+
+ if( CachePtr->cache_trys & 0x8000 )
+ {
+ CachePtr->cache_hits = CachePtr->cache_hits / 2;
+ CachePtr->cache_trys = CachePtr->cache_trys / 2;
+ }
+
+ return( (ubi_cacheEntryPtr)FoundPtr );
+ } /* ubi_cacheGet */
+
+ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe )
+ /* ------------------------------------------------------------------------ **
+ * Find and delete the specified cache entry.
+ *
+ * Input: CachePtr - A pointer to the cache.
+ * DeleteMe - The key of the entry to be deleted.
+ *
+ * Output: TRUE if the entry was found & freed, else FALSE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_trNodePtr FoundPtr;
+
+ FoundPtr = ubi_trFind( CachePtr, DeleteMe );
+ if( FoundPtr )
+ {
+ (void)ubi_trRemove( CachePtr, FoundPtr );
+ free_entry( CachePtr, (ubi_cacheEntryPtr)FoundPtr );
+ return( ubi_trTRUE );
+ }
+ return( ubi_trFALSE );
+ } /* ubi_cacheDelete */
+
+ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count )
+ /* ------------------------------------------------------------------------ **
+ * Remove <count> entries from the bottom of the cache.
+ *
+ * Input: CachePtr - A pointer to the cache which is to be reduced in
+ * size.
+ * count - The number of entries to remove.
+ *
+ * Output: The function will return TRUE if <count> entries were removed,
+ * else FALSE. A return value of FALSE should indicate that
+ * there were less than <count> entries in the cache, and that the
+ * cache is now empty.
+ *
+ * Notes: This function forces a reduction in the number of cache entries
+ * without requiring that the MaxMemory or MaxEntries values be
+ * changed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_trNodePtr NodePtr;
+
+ while( count )
+ {
+ NodePtr = ubi_trLeafNode( CachePtr->root.root );
+ if( NULL == NodePtr )
+ return( ubi_trFALSE );
+ else
+ {
+ (void)ubi_trRemove( CachePtr, NodePtr );
+ free_entry( CachePtr, (ubi_cacheEntryPtr)NodePtr );
+ }
+ count--;
+ }
+ return( ubi_trTRUE );
+ } /* ubi_cacheReduce */
+
+unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
+ unsigned long NewSize )
+ /* ------------------------------------------------------------------------ **
+ * Change the maximum number of entries allowed to exist in the cache.
+ *
+ * Input: CachePtr - A pointer to the cache to be modified.
+ * NewSize - The new maximum number of cache entries.
+ *
+ * Output: The maximum number of entries previously allowed to exist in
+ * the cache.
+ *
+ * Notes: If the new size is less than the old size, this function will
+ * trim the cache (remove excess entries).
+ * - A value of zero indicates an unlimited number of entries.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ unsigned long oldsize = CachePtr->max_entries; /* Save the old value. */
+
+ CachePtr->max_entries = NewSize; /* Apply the new value. */
+ if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
+ cachetrim( CachePtr ); /* remove excess. */
+ return( oldsize );
+ } /* ubi_cacheSetMaxEntries */
+
+unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
+ unsigned long NewSize )
+ /* ------------------------------------------------------------------------ **
+ * Change the maximum amount of memory to be used for storing cache
+ * entries.
+ *
+ * Input: CachePtr - A pointer to the cache to be modified.
+ * NewSize - The new cache memory size.
+ *
+ * Output: The previous maximum memory size.
+ *
+ * Notes: If the new size is less than the old size, this function will
+ * trim the cache (remove excess entries).
+ * - A value of zero indicates that the cache has no memory limit.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ unsigned long oldsize = CachePtr->max_memory; /* Save the old value. */
+
+ CachePtr->max_memory = NewSize; /* Apply the new value. */
+ if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
+ cachetrim( CachePtr ); /* remove excess. */
+ return( oldsize );
+ } /* ubi_cacheSetMaxMemory */
+
+int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr )
+ /* ------------------------------------------------------------------------ **
+ * Returns a value that is 10,000 times the slightly weighted average hit
+ * ratio for the cache.
+ *
+ * Input: CachePtr - Pointer to the cache to be queried.
+ *
+ * Output: An integer that is 10,000 times the number of successful
+ * cache hits divided by the number of cache lookups, or:
+ * (10000 * hits) / trys
+ * You can easily convert this to a float, or do something
+ * like this (where i is the return value of this function):
+ *
+ * printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
+ *
+ * Notes: I say "slightly-weighted", because the numerator and
+ * denominator are both accumulated in locations of type
+ * 'unsigned short'. If the number of cache trys becomes
+ * large enough, both are divided by two. (See function
+ * ubi_cacheGet().)
+ * Dividing both numerator and denominator by two does not
+ * change the ratio (much...it is an integer divide), but it
+ * does mean that subsequent increments to either counter will
+ * have twice as much significance as previous ones.
+ *
+ * - The value returned by this function will be in the range
+ * [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
+ * always be true.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int tmp = 0;
+
+ if( CachePtr->cache_trys )
+ tmp = (int)( (10000 * (long)(CachePtr->cache_hits) )
+ / (long)(CachePtr->cache_trys) );
+ return( tmp );
+ } /* ubi_cacheHitRatio */
+
+/* -------------------------------------------------------------------------- */
diff --git a/source/ubiqx/ubi_Cache.h b/source/ubiqx/ubi_Cache.h
new file mode 100644
index 00000000000..0fc3a074f72
--- /dev/null
+++ b/source/ubiqx/ubi_Cache.h
@@ -0,0 +1,412 @@
+#ifndef UBI_CACHE_H
+#define UBI_CACHE_H
+/* ========================================================================== **
+ * ubi_Cache.h
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements a generic cache.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This module uses a splay tree to implement a simple cache. The cache
+ * module adds a thin layer of functionality to the splay tree. In
+ * particular:
+ *
+ * - The tree (cache) may be limited in size by the number of
+ * entries permitted or the amount of memory used. When either
+ * limit is exceeded cache entries are removed until the cache
+ * conforms.
+ * - Some statistical information is kept so that an approximate
+ * "hit ratio" can be calculated.
+ * - There are several functions available that provide access to
+ * and management of cache size limits, hit ratio, and tree
+ * trimming.
+ *
+ * The splay tree is used because recently accessed items tend toward the
+ * top of the tree and less recently accessed items tend toward the bottom.
+ * This makes it easy to purge less recently used items should the cache
+ * exceed its limits.
+ *
+ * To use this module, you will need to supply a comparison function of
+ * type ubi_trCompFunc and a node-freeing function of type
+ * ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
+ * these. (This is all basic ubiqx tree management stuff.)
+ *
+ * Notes:
+ *
+ * - Cache performance will start to suffer dramatically if the
+ * cache becomes large enough to force the OS to start swapping
+ * memory to disk. This is because the nodes of the underlying tree
+ * will be scattered across memory in an order that is completely
+ * unrelated to their traversal order. As more and more of the
+ * cache is placed into swap space, more and more swaps will be
+ * required for a simple traversal (...and then there's the splay
+ * operation).
+ *
+ * In one simple test under Linux, the load and dump of a cache of
+ * 400,000 entries took only 1min, 40sec of real time. The same
+ * test with 450,000 records took 2 *hours* and eight minutes.
+ *
+ * - In an effort to save memory, I considered using an unsigned
+ * short to save the per-entry entry size. I would have tucked this
+ * value into some unused space in the tree node structure. On
+ * 32-bit word aligned systems this would have saved an additional
+ * four bytes per entry. I may revisit this issue, but for now I've
+ * decided against it.
+ *
+ * Using an unsigned short would limit the size of an entry to 64K
+ * bytes. That's probably more than enough for most applications.
+ * The key word in that last sentence, however, is "probably". I
+ * really dislike imposing such limits on things.
+ *
+ * - Each entry keeps track of the amount of memory it used and the
+ * cache header keeps the total. This information is provided via
+ * the EntrySize parameter in ubi_cachePut(), so it is up to you to
+ * make sure that the numbers are accurate. (The numbers don't even
+ * have to represent bytes used.)
+ *
+ * As you consider this, note that the strdup() function--as an
+ * example--will call malloc(). The latter generally allocates a
+ * multiple of the system word size, which may be more than the
+ * number of bytes needed to store the string.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_Cache.h,v
+ * Revision 0.4 1999/09/22 03:42:24 crh
+ * Fixed a minor typo.
+ *
+ * Revision 0.3 1998/06/03 18:00:15 crh
+ * Further fiddling with sys_include.h, which is no longer explicitly
+ * included by this module since it is inherited from ubi_BinTree.h.
+ *
+ * Revision 0.2 1998/06/02 01:36:18 crh
+ * Changed include name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.1 1998/05/20 04:36:02 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.0 1997/12/18 06:25:23 crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_SplayTree.h"
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ *
+ * ubi_cacheRoot - Cache header structure, which consists of a binary
+ * tree root and other required housekeeping fields, as
+ * listed below.
+ * ubi_cacheRootPtr - Pointer to a Cache.
+ *
+ * ubi_cacheEntry - A cache Entry, which consists of a tree node
+ * structure and the size (in bytes) of the entry
+ * data. The entry size should be supplied via
+ * the EntrySize parameter of the ubi_cachePut()
+ * function.
+ *
+ * ubi_cacheEntryPtr - Pointer to a ubi_cacheEntry.
+ *
+ */
+
+typedef struct
+ {
+ ubi_trRoot root; /* Splay tree control structure. */
+ ubi_trKillNodeRtn free_func; /* Function used to free entries. */
+ unsigned long max_entries; /* Max cache entries. 0 == unlimited */
+ unsigned long max_memory; /* Max memory to use. 0 == unlimited */
+ unsigned long mem_used; /* Memory currently in use (bytes). */
+ unsigned short cache_hits; /* Incremented on succesful find. */
+ unsigned short cache_trys; /* Incremented on cache lookup. */
+ } ubi_cacheRoot;
+
+typedef ubi_cacheRoot *ubi_cacheRootPtr;
+
+
+typedef struct
+ {
+ ubi_trNode node; /* Tree node structure. */
+ unsigned long entry_size; /* Entry size. Used when managing
+ * caches with maximum memory limits.
+ */
+ } ubi_cacheEntry;
+
+typedef ubi_cacheEntry *ubi_cacheEntryPtr;
+
+
+/* -------------------------------------------------------------------------- **
+ * Macros...
+ *
+ * ubi_cacheGetMaxEntries() - Report the current maximum number of entries
+ * allowed in the cache. Zero indicates no
+ * maximum.
+ * ubi_cacheGetMaxMemory() - Report the current maximum amount of memory
+ * that may be used in the cache. Zero
+ * indicates no maximum.
+ * ubi_cacheGetEntryCount() - Report the current number of entries in the
+ * cache.
+ * ubi_cacheGetMemUsed() - Report the amount of memory currently in use
+ * by the cache.
+ */
+
+#define ubi_cacheGetMaxEntries( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_entries)
+#define ubi_cacheGetMaxMemory( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_memory)
+
+#define ubi_cacheGetEntryCount( Cptr ) (((ubi_cacheRootPtr)(Cptr))->root.count)
+#define ubi_cacheGetMemUsed( Cptr ) (((ubi_cacheRootPtr)(Cptr))->mem_used)
+
+/* -------------------------------------------------------------------------- **
+ * Prototypes...
+ */
+
+ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
+ ubi_trCompFunc CompFunc,
+ ubi_trKillNodeRtn FreeFunc,
+ unsigned long MaxEntries,
+ unsigned long MaxMemory );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a cache header structure.
+ *
+ * Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
+ * to be initialized.
+ * CompFunc - A pointer to the function that will be called
+ * to compare two cache values. See the module
+ * comments, above, for more information.
+ * FreeFunc - A pointer to a function that will be called
+ * to free a cache entry. If you allocated
+ * the cache entry using malloc(), then this
+ * will likely be free(). If you are allocating
+ * cache entries from a free list, then this will
+ * likely be a function that returns memory to the
+ * free list, etc.
+ * MaxEntries - The maximum number of entries that will be
+ * allowed to exist in the cache. If this limit
+ * is exceeded, then existing entries will be
+ * removed from the cache. A value of zero
+ * indicates that there is no limit on the number
+ * of cache entries. See ubi_cachePut().
+ * MaxMemory - The maximum amount of memory, in bytes, to be
+ * allocated to the cache (excluding the cache
+ * header). If this is exceeded, existing entries
+ * in the cache will be removed until enough memory
+ * has been freed to meet the condition. See
+ * ubi_cachePut().
+ *
+ * Output: A pointer to the initialized cache (i.e., the same as CachePtr).
+ *
+ * Notes: Both MaxEntries and MaxMemory may be changed after the cache
+ * has been created. See
+ * ubi_cacheSetMaxEntries()
+ * ubi_cacheSetMaxMemory()
+ * ubi_cacheGetMaxEntries()
+ * ubi_cacheGetMaxMemory() (the latter two are macros).
+ *
+ * - Memory is allocated in multiples of the word size. The
+ * return value of the strlen() function does not reflect
+ * this; it will allways be less than or equal to the amount
+ * of memory actually allocated. Keep this in mind when
+ * choosing a value for MaxMemory.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr );
+ /* ------------------------------------------------------------------------ **
+ * Remove and free all entries in an existing cache.
+ *
+ * Input: CachePtr - A pointer to the cache that is to be cleared.
+ *
+ * Output: A pointer to the cache header (i.e., the same as CachePtr).
+ * This function re-initializes the cache header.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+void ubi_cachePut( ubi_cacheRootPtr CachePtr,
+ unsigned long EntrySize,
+ ubi_cacheEntryPtr EntryPtr,
+ ubi_trItemPtr Key );
+ /* ------------------------------------------------------------------------ **
+ * Add an entry to the cache.
+ *
+ * Input: CachePtr - A pointer to the cache into which the entry
+ * will be added.
+ * EntrySize - The size, in bytes, of the memory block indicated
+ * by EntryPtr. This will be copied into the
+ * EntryPtr->entry_size field.
+ * EntryPtr - A pointer to a memory block that begins with a
+ * ubi_cacheEntry structure. The entry structure
+ * should be followed immediately by the data to be
+ * cached (even if that is a pointer to yet more data).
+ * Key - Pointer used to identify the lookup key within the
+ * Entry.
+ *
+ * Output: None.
+ *
+ * Notes: After adding the new node, the cache is "trimmed". This
+ * removes extra nodes if the tree has exceeded it's memory or
+ * entry count limits. It is unlikely that the newly added node
+ * will be purged from the cache (assuming a reasonably large
+ * cache), since new nodes in a splay tree (which is what this
+ * module was designed to use) are moved to the top of the tree
+ * and the cache purge process removes nodes from the bottom of
+ * the tree.
+ * - The underlying splay tree is opened in OVERWRITE mode. If
+ * the input key matches an existing key, the existing entry will
+ * be politely removed from the tree and freed.
+ * - Memory is allocated in multiples of the word size. The
+ * return value of the strlen() function does not reflect
+ * this; it will allways be less than or equal to the amount
+ * of memory actually allocated.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
+ ubi_trItemPtr FindMe );
+ /* ------------------------------------------------------------------------ **
+ * Attempt to retrieve an entry from the cache.
+ *
+ * Input: CachePtr - A ponter to the cache that is to be searched.
+ * FindMe - A ubi_trItemPtr that indicates the key for which
+ * to search.
+ *
+ * Output: A pointer to the cache entry that was found, or NULL if no
+ * matching entry was found.
+ *
+ * Notes: This function also updates the hit ratio counters.
+ * The counters are unsigned short. If the number of cache tries
+ * reaches 32768, then both the number of tries and the number of
+ * hits are divided by two. This prevents the counters from
+ * overflowing. See the comments in ubi_cacheHitRatio() for
+ * additional notes.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe );
+ /* ------------------------------------------------------------------------ **
+ * Find and delete the specified cache entry.
+ *
+ * Input: CachePtr - A pointer to the cache.
+ * DeleteMe - The key of the entry to be deleted.
+ *
+ * Output: TRUE if the entry was found & freed, else FALSE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count );
+ /* ------------------------------------------------------------------------ **
+ * Remove <count> entries from the bottom of the cache.
+ *
+ * Input: CachePtr - A pointer to the cache which is to be reduced in
+ * size.
+ * count - The number of entries to remove.
+ *
+ * Output: The function will return TRUE if <count> entries were removed,
+ * else FALSE. A return value of FALSE should indicate that
+ * there were less than <count> entries in the cache, and that the
+ * cache is now empty.
+ *
+ * Notes: This function forces a reduction in the number of cache entries
+ * without requiring that the MaxMemory or MaxEntries values be
+ * changed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
+ unsigned long NewSize );
+ /* ------------------------------------------------------------------------ **
+ * Change the maximum number of entries allowed to exist in the cache.
+ *
+ * Input: CachePtr - A pointer to the cache to be modified.
+ * NewSize - The new maximum number of cache entries.
+ *
+ * Output: The maximum number of entries previously allowed to exist in
+ * the cache.
+ *
+ * Notes: If the new size is less than the old size, this function will
+ * trim the cache (remove excess entries).
+ * - A value of zero indicates an unlimited number of entries.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
+ unsigned long NewSize );
+ /* ------------------------------------------------------------------------ **
+ * Change the maximum amount of memory to be used for storing cache
+ * entries.
+ *
+ * Input: CachePtr - A pointer to the cache to be modified.
+ * NewSize - The new cache memory size.
+ *
+ * Output: The previous maximum memory size.
+ *
+ * Notes: If the new size is less than the old size, this function will
+ * trim the cache (remove excess entries).
+ * - A value of zero indicates that the cache has no memory limit.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr );
+ /* ------------------------------------------------------------------------ **
+ * Returns a value that is 10,000 times the slightly weighted average hit
+ * ratio for the cache.
+ *
+ * Input: CachePtr - Pointer to the cache to be queried.
+ *
+ * Output: An integer that is 10,000 times the number of successful
+ * cache hits divided by the number of cache lookups, or:
+ * (10000 * hits) / trys
+ * You can easily convert this to a float, or do something
+ * like this (where i is the return value of this function):
+ *
+ * printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
+ *
+ * Notes: I say "slightly-weighted", because the numerator and
+ * denominator are both accumulated in locations of type
+ * 'unsigned short'. If the number of cache trys becomes
+ * large enough, both are divided by two. (See function
+ * ubi_cacheGet().)
+ * Dividing both numerator and denominator by two does not
+ * change the ratio (much...it is an integer divide), but it
+ * does mean that subsequent increments to either counter will
+ * have twice as much significance as previous ones.
+ *
+ * - The value returned by this function will be in the range
+ * [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
+ * always be true.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- */
+#endif /* ubi_CACHE_H */
diff --git a/source/ubiqx/ubi_SplayTree.c b/source/ubiqx/ubi_SplayTree.c
new file mode 100644
index 00000000000..222506bd06b
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.c
@@ -0,0 +1,512 @@
+/* ========================================================================== **
+ * ubi_SplayTree.c
+ *
+ * Copyright (C) 1993-1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements "splay" trees. Splay trees are binary trees
+ * that are rearranged (splayed) whenever a node is accessed. The
+ * splaying process *tends* to make the tree bushier (improves balance),
+ * and the nodes that are accessed most frequently *tend* to be closer to
+ * the top.
+ *
+ * References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ * Robert Tarjan. Journal of the Association for Computing
+ * Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * See also: http://www.cs.cmu.edu/~sleator/
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_SplayTree.c,v
+ * Revision 4.5 2000/01/08 23:26:49 crh
+ * Added ubi_trSplay() macro, which does a type cast for us.
+ *
+ * Revision 4.4 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 4.3 1998/06/03 17:45:05 crh
+ * Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
+ * included by all of the binary tree files.
+ *
+ * Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
+ * to like syntax like this:
+ *
+ * if( (a = b) )
+ *
+ * The fix was to change lines like the above to:
+ *
+ * if( 0 != (a=b) )
+ *
+ * Which means the same thing.
+ *
+ * Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
+ * ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
+ * of tree types by simply changing a header. Unfortunately, the
+ * macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
+ * conflict if used together. You must either choose a single tree
+ * type, or use the underlying function calls directly. Compare
+ * the two header files for more information.
+ *
+ * Revision 4.2 1998/06/02 01:29:14 crh
+ * Changed ubi_null.h to sys_include.h to make it more generic.
+ *
+ * Revision 4.1 1998/05/20 04:37:54 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 4.0 1998/03/10 03:41:33 crh
+ * Minor comment changes. The revision number is now 4.0 to match the
+ * BinTree and AVLtree modules.
+ *
+ * Revision 2.7 1998/01/24 06:37:08 crh
+ * Added a URL for more information.
+ *
+ * Revision 2.6 1997/12/23 04:01:12 crh
+ * In this version, all constants & macros defined in the header file have
+ * the ubi_tr prefix. Also cleaned up anything that gcc complained about
+ * when run with '-pedantic -fsyntax-only -Wall'.
+ *
+ * Revision 2.5 1997/07/26 04:15:42 crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4 1997/06/03 04:42:21 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3 1995/10/03 22:19:07 CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1 95/03/09 23:54:42 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:34:46 CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module. In particular, the interface to the Locate() function
+ * has changed. See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ * Revision 1.1 93/10/18 20:35:16 CRH
+ * I removed the hard-coded logical device names from the include file
+ * specifications. CRH
+ *
+ * Revision 1.0 93/10/15 23:00:15 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_SplayTree, the locate function was
+ * called "ubi_sptLocate", but the next and previous functions remained
+ * "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * Revision 0.1 93/04/25 22:03:32 CRH
+ * Simply changed the <exec/types.h> #include reference the .c file to
+ * use <stdlib.h> instead. The latter is portable, the former is not.
+ *
+ * Revision 0.0 93/04/21 23:05:52 CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_SplayTree.h" /* Header for THIS module. */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_SplayTree\n\
+\tRevision: 4.5 \n\
+\tDate: 2000/01/08 23:26:49 \n\
+\tAuthor: crh \n";
+
+
+/* ========================================================================== **
+ * Private functions...
+ */
+
+static void Rotate( ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a single rotation, moving node *p up one level
+ * in the tree.
+ *
+ * Input: p - a pointer to an ubi_btNode in a tree.
+ *
+ * Output: None.
+ *
+ * Notes: This implements a single rotation in either direction (left
+ * or right). This is the basic building block of all splay
+ * tree rotations.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr parentp;
+ ubi_btNodePtr tmp;
+ char way;
+ char revway;
+
+ parentp = p->Link[ubi_trPARENT]; /* Find parent. */
+
+ if( parentp ) /* If no parent, then we're already the root. */
+ {
+ way = p->gender;
+ revway = ubi_trRevWay(way);
+ tmp = p->Link[(int)revway];
+
+ parentp->Link[(int)way] = tmp;
+ if( tmp )
+ {
+ tmp->Link[ubi_trPARENT] = parentp;
+ tmp->gender = way;
+ }
+
+ tmp = parentp->Link[ubi_trPARENT];
+ p->Link[ubi_trPARENT] = tmp;
+ p->gender = parentp->gender;
+ if( tmp )
+ tmp->Link[(int)(p->gender)] = p;
+
+ parentp->Link[ubi_trPARENT] = p;
+ parentp->gender = revway;
+ p->Link[(int)revway] = parentp;
+ }
+ } /* Rotate */
+
+static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
+ /* ------------------------------------------------------------------------ **
+ * Move the node indicated by SplayWithMe to the root of the tree by
+ * splaying the tree.
+ *
+ * Input: SplayWithMe - A pointer to an ubi_btNode within a tree.
+ *
+ * Output: A pointer to the root of the splay tree (i.e., the same as
+ * SplayWithMe).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr parent;
+
+ while( NULL != (parent = SplayWithMe->Link[ubi_trPARENT]) )
+ {
+ if( parent->gender == SplayWithMe->gender ) /* Zig-Zig */
+ Rotate( parent );
+ else
+ {
+ if( ubi_trEQUAL != parent->gender ) /* Zig-Zag */
+ Rotate( SplayWithMe );
+ }
+ Rotate( SplayWithMe ); /* Zig */
+ } /* while */
+ return( SplayWithMe );
+ } /* Splay */
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode )
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * splay tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr OtherP;
+
+ if( !(OldNode) )
+ OldNode = &OtherP;
+
+ if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
+ {
+ RootPtr->root = Splay( NewNode );
+ return( ubi_trTRUE );
+ }
+
+ /* Splay the unreplacable, duplicate keyed, unique, old node. */
+ RootPtr->root = Splay( (*OldNode) );
+ return( ubi_trFALSE );
+ } /* ubi_sptInsert */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ (void)Splay( DeadNode ); /* Move dead node to root. */
+ if( NULL != (p = DeadNode->Link[ubi_trLEFT]) )
+ { /* If left subtree exists... */
+ ubi_btNodePtr q = DeadNode->Link[ubi_trRIGHT];
+
+ p->Link[ubi_trPARENT] = NULL; /* Left subtree node becomes root.*/
+ p->gender = ubi_trPARENT;
+ p = ubi_btLast( p ); /* Find rightmost left node... */
+ p->Link[ubi_trRIGHT] = q; /* ...attach right tree. */
+ if( q )
+ q->Link[ubi_trPARENT] = p;
+ RootPtr->root = Splay( p ); /* Resplay at p. */
+ }
+ else
+ {
+ if( NULL != (p = DeadNode->Link[ubi_trRIGHT]) )
+ { /* No left, but right subtree exists... */
+ p->Link[ubi_trPARENT] = NULL; /* Right subtree root becomes... */
+ p->gender = ubi_trPARENT; /* ...overall tree root. */
+ RootPtr->root = p;
+ }
+ else
+ RootPtr->root = NULL; /* No subtrees => empty tree. */
+ }
+
+ (RootPtr->count)--; /* Decrement node count. */
+ return( DeadNode ); /* Return pointer to pruned node. */
+ } /* ubi_sptRemove */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp )
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ p = ubi_btLocate( RootPtr, FindMe, CompOp );
+ if( p )
+ RootPtr->root = Splay( p );
+ return( p );
+ } /* ubi_sptLocate */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_sptLocate().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ p = ubi_btFind( RootPtr, FindMe );
+ if( p )
+ RootPtr->root = Splay( p );
+ return( p );
+ } /* ubi_sptFind */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr SplayMe )
+ /* ------------------------------------------------------------------------ **
+ * This function allows you to splay the tree at a given node, thus moving
+ * the node to the top of the tree.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be splayed.
+ * SplayMe - a pointer to a node within the tree. This will become
+ * the new root node.
+ * Output: None.
+ *
+ * Notes: This is an uncharacteristic function for this group of modules
+ * in that it provides access to the internal balancing routines,
+ * which would normally be hidden.
+ * Splaying the tree will not damage it (assuming that I've done
+ * *my* job), but there is overhead involved. I don't recommend
+ * that you use this function unless you understand the underlying
+ * Splay Tree principles involved.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ RootPtr->root = Splay( SplayMe );
+ } /* ubi_sptSplay */
+
+int ubi_sptModuleID( int size, char *list[] )
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( size > 0 )
+ {
+ list[0] = ModuleID;
+ if( size > 1 )
+ return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
+ return( 1 );
+ }
+ return( 0 );
+ } /* ubi_sptModuleID */
+
+/* ================================ The End ================================= */
+
diff --git a/source/ubiqx/ubi_SplayTree.h b/source/ubiqx/ubi_SplayTree.h
new file mode 100644
index 00000000000..e4fac796a91
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.h
@@ -0,0 +1,377 @@
+#ifndef UBI_SPLAYTREE_H
+#define UBI_SPLAYTREE_H
+/* ========================================================================== **
+ * ubi_SplayTree.h
+ *
+ * Copyright (C) 1993-1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements "splay" trees. Splay trees are binary trees
+ * that are rearranged (splayed) whenever a node is accessed. The
+ * splaying process *tends* to make the tree bushier (improves balance),
+ * and the nodes that are accessed most frequently *tend* to be closer to
+ * the top.
+ *
+ * References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ * Robert Tarjan. Journal of the Association for Computing
+ * Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * See also: http://www.cs.cmu.edu/~sleator/
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_SplayTree.h,v
+ * Revision 4.5 2000/01/08 23:26:49 crh
+ * Added ubi_trSplay() macro, which does a type cast for us.
+ *
+ * Revision 4.4 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 4.3 1998/06/03 17:45:05 crh
+ * Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
+ * included by all of the binary tree files.
+ *
+ * Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
+ * to like syntax like this:
+ *
+ * if( (a = b) )
+ *
+ * The fix was to change lines like the above to:
+ *
+ * if( 0 != (a=b) )
+ *
+ * Which means the same thing.
+ *
+ * Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
+ * ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
+ * of tree types by simply changing a header. Unfortunately, the
+ * macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
+ * conflict if used together. You must either choose a single tree
+ * type, or use the underlying function calls directly. Compare
+ * the two header files for more information.
+ *
+ * Revision 4.2 1998/06/02 01:29:14 crh
+ * Changed ubi_null.h to sys_include.h to make it more generic.
+ *
+ * Revision 4.1 1998/05/20 04:37:54 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 4.0 1998/03/10 03:40:57 crh
+ * Minor comment changes. The revision number is now 4.0 to match the
+ * BinTree and AVLtree modules.
+ *
+ * Revision 2.7 1998/01/24 06:37:57 crh
+ * Added a URL for more information.
+ *
+ * Revision 2.6 1997/12/23 04:02:20 crh
+ * In this version, all constants & macros defined in the header file have
+ * the ubi_tr prefix. Also cleaned up anything that gcc complained about
+ * when run with '-pedantic -fsyntax-only -Wall'.
+ *
+ * Revision 2.5 1997/07/26 04:15:46 crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4 1997/06/03 05:22:56 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3 1995/10/03 22:19:37 CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1 95/03/09 23:55:04 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:34:55 CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module. In particular, the interface to the Locate() function
+ * has changed. See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ *
+ * Revision 1.0 93/10/15 22:59:36 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_SplayTree, the locate function was
+ * called "ubi_sptLocate", but the next and previous functions remained
+ * "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * Revision 0.0 93/04/21 23:07:13 CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h" /* Base binary tree functions, types, etc. */
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode );
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * splay tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode );
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp );
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe );
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_sptLocate().
+ * ------------------------------------------------------------------------ **
+ */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr SplayMe );
+ /* ------------------------------------------------------------------------ **
+ * This function allows you to splay the tree at a given node, thus moving
+ * the node to the top of the tree.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be splayed.
+ * SplayMe - a pointer to a node within the tree. This will become
+ * the new root node.
+ * Output: None.
+ *
+ * Notes: This is an uncharacteristic function for this group of modules
+ * in that it provides access to the internal balancing routines,
+ * which would normally be hidden.
+ * Splaying the tree will not damage it (assuming that I've done
+ * *my* job), but there is overhead involved. I don't recommend
+ * that you use this function unless you understand the underlying
+ * Splay Tree principles involved.
+ * ------------------------------------------------------------------------ **
+ */
+
+int ubi_sptModuleID( int size, char *list[] );
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#undef ubi_trInsert
+#undef ubi_trRemove
+#undef ubi_trLocate
+#undef ubi_trFind
+#undef ubi_trModuleID
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+ ubi_sptInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+ (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+ ubi_sptRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+ ubi_sptLocate( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+ ubi_sptFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trSplay( Rp, Sm ) \
+ ubi_sptSplay( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Sm) )
+
+#define ubi_trModuleID( s, l ) ubi_sptModuleID( s, l )
+
+/* ================================ The End ================================= */
+#endif /* UBI_SPLAYTREE_H */
diff --git a/source/ubiqx/ubi_dLinkList.c b/source/ubiqx/ubi_dLinkList.c
new file mode 100644
index 00000000000..eb95033c695
--- /dev/null
+++ b/source/ubiqx/ubi_dLinkList.c
@@ -0,0 +1,171 @@
+/* ========================================================================== **
+ * ubi_dLinkList.c
+ *
+ * Copyright (C) 1997, 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_dLinkList.c,v
+ * Revision 0.11 1999/06/19 16:58:06 crh
+ * Renamed the ubi_slRemove() function in ubi_sLinkList to
+ * ubi_slRemoveNext(). I was bothered by the fact that it didn't
+ * match the functionality of the ubi_dlRemove() function in
+ * ubi_dLinkList. The new name is more 'correct'.
+ *
+ * Revision 0.10 1998/07/24 07:30:20 crh
+ * Added the ubi_dlNewList() macro.
+ *
+ * Revision 0.9 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 0.8 1998/06/03 18:06:03 crh
+ * Further fiddling with sys_include.h, which has been moved from the .c file
+ * to the .h file.
+ *
+ * Revision 0.7 1998/06/02 01:38:47 crh
+ * Changed include file name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.6 1998/05/20 04:38:05 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.5 1998/03/10 02:55:00 crh
+ * Simplified the code and added macros for stack & queue manipulations.
+ *
+ * Revision 0.4 1998/01/03 01:53:56 crh
+ * Added ubi_dlCount() macro.
+ *
+ * Revision 0.3 1997/10/15 03:05:39 crh
+ * Added some handy type casting to the macros. Added AddHere and RemThis
+ * macros.
+ *
+ * Revision 0.2 1997/10/08 03:07:21 crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1 1997/10/07 04:34:07 crh
+ * Initial Revision.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is similar to the ubi_sLinkList module, but it is neither a
+ * descendant type nor an easy drop-in replacement for the latter. One key
+ * difference is that the ubi_dlRemove() function removes the indicated node,
+ * while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
+ * *following* the indicated node.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_dLinkList.h" /* Header for *this* module. */
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a doubly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ListPtr->Head = NULL;
+ ListPtr->Tail = NULL;
+ ListPtr->count = 0;
+ return( ListPtr );
+ } /* ubi_dlInitList */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+ ubi_dlNodePtr New,
+ ubi_dlNodePtr After )
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node into the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the new node.
+ * After - NULL, or a pointer to a node that is already in the
+ * list.
+ * If NULL, then <New> will be added at the head of the
+ * list, else it will be added following <After>.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_dlNodePtr PredNode = After ? After : (ubi_dlNodePtr)ListPtr;
+
+ New->Next = PredNode->Next;
+ New->Prev = After;
+ PredNode->Next = New;
+ if( New->Next )
+ New->Next->Prev = New;
+ else
+ ListPtr->Tail = New;
+
+ (ListPtr->count)++;
+
+ return( New );
+ } /* ubi_dlInsert */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old )
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the list.
+ *
+ * Input: ListPtr - A pointer to the list from which <Old> is to be
+ * removed.
+ * Old - A pointer to the node that is to be removed from the
+ * list.
+ *
+ * Output: A pointer to the node that was removed (i.e., <Old>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( Old )
+ {
+ if( Old->Next )
+ Old->Next->Prev = Old->Prev;
+ else
+ ListPtr->Tail = Old->Prev;
+
+ if( Old->Prev )
+ Old->Prev->Next = Old->Next;
+ else
+ ListPtr->Head = Old->Next;
+
+ (ListPtr->count)--;
+ }
+
+ return( Old );
+ } /* ubi_dlRemove */
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_dLinkList.h b/source/ubiqx/ubi_dLinkList.h
new file mode 100644
index 00000000000..682e566ee67
--- /dev/null
+++ b/source/ubiqx/ubi_dLinkList.h
@@ -0,0 +1,242 @@
+#ifndef UBI_DLINKLIST_H
+#define UBI_DLINKLIST_H
+/* ========================================================================== **
+ * ubi_dLinkList.h
+ *
+ * Copyright (C) 1997, 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_dLinkList.h,v
+ * Revision 0.11 1999/06/19 16:58:06 crh
+ * Renamed the ubi_slRemove() function in ubi_sLinkList to
+ * ubi_slRemoveNext(). I was bothered by the fact that it didn't
+ * match the functionality of the ubi_dlRemove() function in
+ * ubi_dLinkList. The new name is more 'correct'.
+ *
+ * Revision 0.10 1998/07/24 07:30:20 crh
+ * Added the ubi_dlNewList() macro.
+ *
+ * Revision 0.9 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 0.8 1998/06/03 18:06:03 crh
+ * Further fiddling with sys_include.h, which has been moved from the .c file
+ * to the .h file.
+ *
+ * Revision 0.7 1998/06/02 01:38:47 crh
+ * Changed include file name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.6 1998/05/20 04:38:05 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.5 1998/03/10 02:54:04 crh
+ * Simplified the code and added macros for stack & queue manipulations.
+ *
+ * Revision 0.4 1998/01/03 01:53:44 crh
+ * Added ubi_dlCount() macro.
+ *
+ * Revision 0.3 1997/10/15 03:04:31 crh
+ * Added some handy type casting to the macros. Added AddHere and RemThis
+ * macros.
+ *
+ * Revision 0.2 1997/10/08 03:08:16 crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1 1997/10/07 04:34:38 crh
+ * Initial Revision.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module is similar to the ubi_sLinkList module, but it is neither a
+ * descendant type nor an easy drop-in replacement for the latter. One key
+ * difference is that the ubi_dlRemove() function removes the indicated node,
+ * while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
+ * *following* the indicated node.
+ *
+ * ========================================================================== **
+ */
+
+#include "sys_include.h" /* System-specific includes. */
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ * ubi_dlNode - This is the basic node structure.
+ * ubi_dlNodePtr - Pointer to a node.
+ * ubi_dlList - This is the list header structure.
+ * ubi_dlListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_dlListNode
+ {
+ struct ubi_dlListNode *Next;
+ struct ubi_dlListNode *Prev;
+ } ubi_dlNode;
+
+typedef ubi_dlNode *ubi_dlNodePtr;
+
+typedef struct
+ {
+ ubi_dlNodePtr Head;
+ ubi_dlNodePtr Tail;
+ unsigned long count;
+ } ubi_dlList;
+
+typedef ubi_dlList *ubi_dlListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ *
+ * ubi_dlNewList - Macro used to declare and initialize a new list in one
+ * swell foop. It is used when defining a variable of
+ * type ubi_dlList. The definition
+ * static ubi_dlNewList( gerbil );
+ * is translated to
+ * static ubi_dlList gerbil[1] = {{ NULL, NULL, 0 }};
+ *
+ * ubi_dlCount - Return the number of entries currently in the list.
+ *
+ * ubi_dlAddHead - Add a new node at the head of the list.
+ * ubi_dlAddNext - Add a node following the given node.
+ * ubi_dlAddTail - Add a new node at the tail of the list.
+ * Note: AddTail evaluates the L parameter twice.
+ *
+ * ubi_dlRemHead - Remove the node at the head of the list, if any.
+ * Note: RemHead evaluates the L parameter twice.
+ * ubi_dlRemThis - Remove the indicated node.
+ * ubi_dlRemTail - Remove the node at the tail of the list, if any.
+ * Note: RemTail evaluates the L parameter twice.
+ *
+ * ubi_dlFirst - Return a pointer to the first node in the list, if any.
+ * ubi_dlLast - Return a pointer to the last node in the list, if any.
+ * ubi_dlNext - Given a node, return a pointer to the next node.
+ * ubi_dlPrev - Given a node, return a pointer to the previous node.
+ *
+ * ubi_dlPush - Add a node at the head of the list (synonym of AddHead).
+ * ubi_dlPop - Remove a node at the head of the list (synonym of RemHead).
+ * ubi_dlEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
+ * ubi_dlDequeue - Remove a node at the head of the list (synonym of RemHead).
+ *
+ * Note that all of these provide type casting of the parameters. The
+ * Add and Rem macros are nothing more than nice front-ends to the
+ * Insert and Remove operations.
+ *
+ * Also note that the First, Next and Last macros do no parameter checking!
+ *
+ */
+
+#define ubi_dlNewList( L ) ubi_dlList (L)[1] = {{ NULL, NULL, 0 }}
+
+#define ubi_dlCount( L ) (((ubi_dlListPtr)(L))->count)
+
+#define ubi_dlAddHead( L, N ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), (ubi_dlNodePtr)(N), NULL )
+
+#define ubi_dlAddNext( L, N, A ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N), \
+ (ubi_dlNodePtr)(A) )
+
+#define ubi_dlAddTail( L, N ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N), \
+ (((ubi_dlListPtr)(L))->Tail) )
+
+#define ubi_dlRemHead( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (((ubi_dlListPtr)(L))->Head) )
+
+#define ubi_dlRemThis( L, N ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N) )
+
+#define ubi_dlRemTail( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (((ubi_dlListPtr)(L))->Tail) )
+
+#define ubi_dlFirst( L ) (((ubi_dlListPtr)(L))->Head)
+
+#define ubi_dlLast( L ) (((ubi_dlListPtr)(L))->Tail)
+
+#define ubi_dlNext( N ) (((ubi_dlNodePtr)(N))->Next)
+
+#define ubi_dlPrev( N ) (((ubi_dlNodePtr)(N))->Prev)
+
+#define ubi_dlPush ubi_dlAddHead
+#define ubi_dlPop ubi_dlRemHead
+#define ubi_dlEnqueue ubi_dlAddTail
+#define ubi_dlDequeue ubi_dlRemHead
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a doubly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+ ubi_dlNodePtr New,
+ ubi_dlNodePtr After );
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node into the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the new node.
+ * After - NULL, or a pointer to a node that is already in the
+ * list.
+ * If NULL, then <New> will be added at the head of the
+ * list, else it will be added following <After>.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old );
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the list.
+ *
+ * Input: ListPtr - A pointer to the list from which <Old> is to be
+ * removed.
+ * Old - A pointer to the node that is to be removed from the
+ * list.
+ *
+ * Output: A pointer to the node that was removed (i.e., <Old>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+/* ================================ The End ================================= */
+#endif /* UBI_DLINKLIST_H */
diff --git a/source/ubiqx/ubi_sLinkList.c b/source/ubiqx/ubi_sLinkList.c
new file mode 100644
index 00000000000..ff75931b470
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.c
@@ -0,0 +1,187 @@
+/* ========================================================================== **
+ * ubi_sLinkList.c
+ *
+ * Copyright (C) 1997, 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements a simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_sLinkList.c,v
+ * Revision 0.10 1999/06/19 16:58:06 crh
+ * Renamed the ubi_slRemove() function in ubi_sLinkList to
+ * ubi_slRemoveNext(). I was bothered by the fact that it didn't
+ * match the functionality of the ubi_dlRemove() function in
+ * ubi_dLinkList. The new name is more 'correct'.
+ *
+ * Revision 0.9 1998/07/24 07:30:20 crh
+ * Added the ubi_slNewList() macro.
+ *
+ * Revision 0.8 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 0.7 1998/06/03 18:06:03 crh
+ * Further fiddling with sys_include.h, which has been moved from the .c file
+ * to the .h file.
+ *
+ * Revision 0.6 1998/06/02 01:38:47 crh
+ * Changed include file name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.5 1998/05/20 04:38:05 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.4 1998/03/10 02:23:20 crh
+ * Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
+ * the functions and macros. Not a complete rewrite but close to it.
+ *
+ * Revision 0.3 1998/01/03 01:59:52 crh
+ * Added ubi_slCount() macro.
+ *
+ * Revision 0.2 1997/10/21 03:35:18 crh
+ * Added parameter <After> in function Insert(). Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1 1997/10/16 02:53:45 crh
+ * Initial Revision.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module implements a singly-linked list which may also be used as a
+ * queue or a stack. For a queue, entries are added at the tail and removed
+ * from the head of the list. For a stack, the entries are entered and
+ * removed from the head of the list. A traversal of the list will always
+ * start at the head of the list and proceed toward the tail. This is all
+ * mind-numbingly simple, but I'm surprised by the number of programs out
+ * there which re-implement this a dozen or so times.
+ *
+ * Note: When the list header is initialized, the Tail pointer is set to
+ * point to the Head pointer. This simplifies things a great deal,
+ * except that you can't initialize a stack or queue by simply
+ * zeroing it out. One sure way to initialize the header is to call
+ * ubi_slInit(). Another option would be something like this:
+ *
+ * ubi_slNewList( MyList );
+ *
+ * Which translates to:
+ *
+ * ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
+ *
+ * See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
+ * for more info.
+ *
+ * + Also, note that this module is similar to the ubi_dLinkList
+ * module. There are three key differences:
+ * - This is a singly-linked list, the other is a doubly-linked
+ * list.
+ * - In this module, if the list is empty, the tail pointer will
+ * point back to the head of the list as described above. This
+ * is not done in ubi_dLinkList.
+ * - The ubi_slRemoveNext() function, by necessity, removes the
+ * 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
+ * removes the 'current' node.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_sLinkList.h" /* Header for *this* module. */
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a singly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ListPtr->Head = NULL;
+ ListPtr->Tail = (ubi_slNodePtr)ListPtr;
+ ListPtr->count = 0;
+ return( ListPtr );
+ } /* ubi_slInitList */
+
+ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+ ubi_slNodePtr New,
+ ubi_slNodePtr After )
+ /* ------------------------------------------------------------------------ **
+ * Add a node to the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be added to the list.
+ * After - Pointer to a list in a node after which the new node
+ * will be inserted. If NULL, then the new node will
+ * be added at the head of the list.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ After = After ? After : (ubi_slNodePtr)ListPtr;
+ New->Next = After->Next;
+ After->Next = New;
+ if( !(New->Next) )
+ ListPtr->Tail = New;
+ (ListPtr->count)++;
+ return( New );
+ } /* ubi_slInsert */
+
+ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe )
+ /* ------------------------------------------------------------------------ **
+ * Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
+ * the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ * AfterMe - Pointer to the node preceeding the node to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed, or NULL if the list is
+ * empty.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_slNodePtr DelNode;
+
+ AfterMe = AfterMe ? AfterMe : (ubi_slNodePtr)ListPtr;
+ DelNode = AfterMe->Next;
+ if( DelNode )
+ {
+ if( !(DelNode->Next) )
+ ListPtr->Tail = AfterMe;
+ AfterMe->Next = DelNode->Next;
+ (ListPtr->count)--;
+ }
+ return( DelNode );
+ } /* ubi_slRemoveNext */
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_sLinkList.h b/source/ubiqx/ubi_sLinkList.h
new file mode 100644
index 00000000000..53bfa400671
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.h
@@ -0,0 +1,254 @@
+#ifndef UBI_SLINKLIST_H
+#define UBI_SLINKLIST_H
+/* ========================================================================== **
+ * ubi_sLinkList.h
+ *
+ * Copyright (C) 1997, 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements a simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Log: ubi_sLinkList.h,v
+ * Revision 0.10 1999/06/19 16:58:06 crh
+ * Renamed the ubi_slRemove() function in ubi_sLinkList to
+ * ubi_slRemoveNext(). I was bothered by the fact that it didn't
+ * match the functionality of the ubi_dlRemove() function in
+ * ubi_dLinkList. The new name is more 'correct'.
+ *
+ * Revision 0.9 1998/07/24 07:30:20 crh
+ * Added the ubi_slNewList() macro.
+ *
+ * Revision 0.8 1998/06/04 21:29:27 crh
+ * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
+ * This is more "standard", and is what people expect. Weird, eh?
+ *
+ * Revision 0.7 1998/06/03 18:06:03 crh
+ * Further fiddling with sys_include.h, which has been moved from the .c file
+ * to the .h file.
+ *
+ * Revision 0.6 1998/06/02 01:38:47 crh
+ * Changed include file name from ubi_null.h to sys_include.h to make it
+ * more generic.
+ *
+ * Revision 0.5 1998/05/20 04:38:05 crh
+ * The C file now includes ubi_null.h. See ubi_null.h for more info.
+ *
+ * Revision 0.4 1998/03/10 02:22:39 crh
+ * Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
+ * the functions and macros. Not a complete rewrite but close to it.
+ *
+ * Revision 0.3 1998/01/03 02:00:02 crh
+ * Added ubi_slCount() macro.
+ *
+ * Revision 0.2 1997/10/21 03:36:14 crh
+ * Added parameter <After> in function Insert(). Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1 1997/10/16 02:54:08 crh
+ * Initial Revision.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module implements a singly-linked list which may also be used as a
+ * queue or a stack. For a queue, entries are added at the tail and removed
+ * from the head of the list. For a stack, the entries are entered and
+ * removed from the head of the list. A traversal of the list will always
+ * start at the head of the list and proceed toward the tail. This is all
+ * mind-numbingly simple, but I'm surprised by the number of programs out
+ * there which re-implement this a dozen or so times.
+ *
+ * Note: When the list header is initialized, the Tail pointer is set to
+ * point to the Head pointer. This simplifies things a great deal,
+ * except that you can't initialize a stack or queue by simply
+ * zeroing it out. One sure way to initialize the header is to call
+ * ubi_slInit(). Another option would be something like this:
+ *
+ * ubi_slNewList( MyList );
+ *
+ * Which translates to:
+ *
+ * ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
+ *
+ * See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
+ * for more info.
+ *
+ * + Also, note that this module is similar to the ubi_dLinkList
+ * module. There are three key differences:
+ * - This is a singly-linked list, the other is a doubly-linked
+ * list.
+ * - In this module, if the list is empty, the tail pointer will
+ * point back to the head of the list as described above. This
+ * is not done in ubi_dLinkList.
+ * - The ubi_slRemoveNext() function, by necessity, removes the
+ * 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
+ * removes the 'current' node.
+ *
+ * ========================================================================== **
+ */
+
+#include "sys_include.h" /* System-specific includes. */
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ * ubi_slNode - This is the basic node structure.
+ * ubi_slNodePtr - Pointer to a node.
+ * ubi_slList - This is the list header structure.
+ * ubi_slListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_slListNode
+ {
+ struct ubi_slListNode *Next;
+ } ubi_slNode;
+
+typedef ubi_slNode *ubi_slNodePtr;
+
+typedef struct
+ {
+ ubi_slNodePtr Head;
+ ubi_slNodePtr Tail;
+ unsigned long count;
+ } ubi_slList;
+
+typedef ubi_slList *ubi_slListPtr;
+
+
+/* ========================================================================== **
+ * Macros...
+ *
+ * ubi_slNewList - Macro used to declare and initialize a list header in
+ * one step.
+ *
+ * ubi_slCount - Returns the current number of entries in the list.
+ *
+ * ubi_slAddHead - Add a new node at the head of the list.
+ * ubi_slAddNext - Add a new node following the indicated node.
+ * ubi_slAddTail - Add a new node to the tail of the list.
+ * Note: AddTail evaluates the L parameter twice.
+ *
+ * ubi_slRemHead - Remove the node at the head of the list, if any.
+ * ubi_slRemNext - Remove the node following the given node.
+ *
+ * ubi_slFirst - Return a pointer to the first node in the list, if any.
+ * ubi_slNext - Given a node, return a pointer to the next node.
+ * ubi_slLast - Return a pointer to the last node in the list, if any.
+ *
+ * ubi_slPush - Add a node at the head of the list (synonym of AddHead).
+ * ubi_slPop - Remove a node at the head of the list (synonym of RemHead).
+ * ubi_slEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
+ * ubi_slDequeue - Remove a node at the head of the list (synonym of RemHead).
+ *
+ * Note that all of these provide type casting of the parameters. The
+ * Add and Rem macros are nothing more than nice front-ends to the
+ * Insert and Remove functions.
+ *
+ * Also note that the First, Next and Last macros do no parameter checking!
+ *
+ */
+
+#define ubi_slNewList( L ) ubi_slList (L)[1] = {{ NULL, (ubi_slNodePtr)(L), 0 }}
+
+#define ubi_slCount( L ) (((ubi_slListPtr)(L))->count)
+
+#define ubi_slAddHead( L, N ) \
+ ubi_slInsert( (ubi_slListPtr)(L), (ubi_slNodePtr)(N), NULL )
+
+#define ubi_slAddNext( L, N, A ) \
+ ubi_slInsert( (ubi_slListPtr)(L), \
+ (ubi_slNodePtr)(N), \
+ (ubi_slNodePtr)(A) )
+
+#define ubi_slAddTail( L, N ) \
+ ubi_slInsert( (ubi_slListPtr)(L), \
+ (ubi_slNodePtr)(N), \
+ ((ubi_slListPtr)(L))->Tail )
+
+#define ubi_slRemHead( L ) ubi_slRemoveNext( (ubi_slListPtr)(L), NULL )
+
+#define ubi_slRemNext( L, N ) \
+ ubi_slRemoveNext( (ubi_slListPtr)(L), (ubi_slNodePtr)(N) )
+
+#define ubi_slFirst( L ) (((ubi_slListPtr)(L))->Head)
+
+#define ubi_slNext( N ) (((ubi_slNodePtr)(N))->Next)
+
+#define ubi_slLast( L ) (((ubi_slListPtr)(L))->Tail)
+
+#define ubi_slPush ubi_slAddHead
+#define ubi_slPop ubi_slRemHead
+#define ubi_slEnqueue ubi_slAddTail
+#define ubi_slDequeue ubi_slRemHead
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a singly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+ ubi_slNodePtr New,
+ ubi_slNodePtr After );
+ /* ------------------------------------------------------------------------ **
+ * Add a node to the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be added to the list.
+ * After - Pointer to a list in a node after which the new node
+ * will be inserted. If NULL, then the new node will
+ * be added at the head of the list.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe );
+ /* ------------------------------------------------------------------------ **
+ * Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
+ * the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ * AfterMe - Pointer to the node preceeding the node to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed, or NULL if the list is
+ * empty.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+/* ================================ The End ================================= */
+#endif /* UBI_SLINKLIST_H */
diff --git a/source/utils/debug2html.c b/source/utils/debug2html.c
new file mode 100644
index 00000000000..f9a1f43f461
--- /dev/null
+++ b/source/utils/debug2html.c
@@ -0,0 +1,253 @@
+/* ========================================================================== **
+ * debug2html.c
+ *
+ * Copyright (C) 1998 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ *
+ * -------------------------------------------------------------------------- **
+ * Parse Samba debug logs (2.0 & greater) and output the results as HTML.
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ * This program provides an example of the use of debugparse.c, and also
+ * does a decent job of converting Samba logs into HTML.
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 1.4 1998/11/13 03:37:01 tridge
+ * fixes for OSF1 compilation
+ *
+ * Revision 1.3 1998/10/28 20:33:35 crh
+ * I've moved the debugparse module files into the ubiqx directory because I
+ * know that 'make proto' will ignore them there. The debugparse.h header
+ * file is included in includes.h, and includes.h is included in debugparse.c,
+ * so all of the pieces "see" each other. I've compiled and tested this,
+ * and it does seem to work. It's the same compromise model I used when
+ * adding the ubiqx modules into the system, which is why I put it all into
+ * the same directory.
+ *
+ * Chris -)-----
+ *
+ * Revision 1.1 1998/10/26 23:21:37 crh
+ * Here is the simple debug parser and the debug2html converter. Still to do:
+ *
+ * * Debug message filtering.
+ * * I need to add all this to Makefile.in
+ * (If it looks at all strange I'll ask for help.)
+ *
+ * If you want to compile debug2html, you'll need to do it by hand until I
+ * make the changes to Makefile.in. Sorry.
+ *
+ * Chris -)-----
+ *
+ * ========================================================================== **
+ */
+
+#include "debugparse.h"
+
+/* -------------------------------------------------------------------------- **
+ * The size of the read buffer.
+ */
+
+#define DBG_BSIZE 1024
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static dbg_Token modechange( dbg_Token new, dbg_Token mode )
+ /* ------------------------------------------------------------------------ **
+ * Handle a switch between header and message printing.
+ *
+ * Input: new - The token value of the current token. This indicates
+ * the lexical item currently being recognized.
+ * mode - The current mode. This is either dbg_null or
+ * dbg_message. It could really be any toggle
+ * (true/false, etc.)
+ *
+ * Output: The new mode. This will be the same as the input mode unless
+ * there was a transition in or out of message processing.
+ *
+ * Notes: The purpose of the mode value is to mark the beginning and end
+ * of the message text block. In order to show the text in its
+ * correct format, it must be included within a <PRE></PRE> block.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( new )
+ {
+ case dbg_null:
+ case dbg_ignore:
+ return( mode );
+ case dbg_message:
+ if( dbg_message != mode )
+ {
+ /* Switching to message mode. */
+ (void)printf( "<PRE>\n" );
+ return( dbg_message );
+ }
+ break;
+ default:
+ if( dbg_message == mode )
+ {
+ /* Switching out of message mode. */
+ (void)printf( "</PRE>\n\n" );
+ return( dbg_null );
+ }
+ }
+
+ return( mode );
+ } /* modechange */
+
+static void newblock( dbg_Token old, dbg_Token new )
+ /* ------------------------------------------------------------------------ **
+ * Handle the transition between tokens.
+ *
+ * Input: old - The previous token.
+ * new - The current token.
+ *
+ * Output: none.
+ *
+ * Notes: This is called whenever there is a transition from one token
+ * type to another. It first prints the markup tags that close
+ * the previous token, and then the markup tags for the new
+ * token.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( old )
+ {
+ case dbg_timestamp:
+ (void)printf( ",</B>" );
+ break;
+ case dbg_level:
+ (void)printf( "</FONT>]</B>\n " );
+ break;
+ case dbg_sourcefile:
+ (void)printf( ":" );
+ break;
+ case dbg_lineno:
+ (void)printf( ")" );
+ break;
+ }
+
+ switch( new )
+ {
+ case dbg_timestamp:
+ (void)printf( "<B>[" );
+ break;
+ case dbg_level:
+ (void)printf( " <B><FONT COLOR=MAROON>" );
+ break;
+ case dbg_lineno:
+ (void)printf( "(" );
+ break;
+ }
+ } /* newblock */
+
+static void charprint( dbg_Token tok, int c )
+ /* ------------------------------------------------------------------------ **
+ * Filter the input characters to determine what goes to output.
+ *
+ * Input: tok - The token value of the current character.
+ * c - The current character.
+ *
+ * Output: none.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ switch( tok )
+ {
+ case dbg_ignore:
+ case dbg_header:
+ break;
+ case dbg_null:
+ case dbg_eof:
+ (void)putchar( '\n' );
+ break;
+ default:
+ switch( c )
+ {
+ case '<':
+ (void)printf( "&lt;" );
+ break;
+ case '>':
+ (void)printf( "&gt;" );
+ break;
+ case '&':
+ (void)printf( "&amp;" );
+ break;
+ case '\"':
+ (void)printf( "&#34;" );
+ break;
+ default:
+ (void)putchar( c );
+ break;
+ }
+ }
+ } /* charprint */
+
+int main( int argc, char *argv[] )
+ /* ------------------------------------------------------------------------ **
+ * This simple program scans and parses Samba debug logs, and produces HTML
+ * output.
+ *
+ * Input: argc - Currently ignored.
+ * argv - Currently ignored.
+ *
+ * Output: Always zero.
+ *
+ * Notes: The HTML output is sent to stdout.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int i;
+ int len;
+ char bufr[DBG_BSIZE];
+ dbg_Token old = dbg_null,
+ new = dbg_null,
+ state = dbg_null,
+ mode = dbg_null;
+
+ (void)printf( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n" );
+ (void)printf( "<HTML>\n<HEAD>\n" );
+ (void)printf( " <TITLE>Samba Debug Output</TITLE>\n</HEAD>\n\n<BODY>\n" );
+
+ while( (!feof( stdin ))
+ && ((len = fread( bufr, 1, DBG_BSIZE, stdin )) > 0) )
+ {
+ for( i = 0; i < len; i++ )
+ {
+ old = new;
+ new = dbg_char2token( &state, bufr[i] );
+ if( new != old )
+ {
+ mode = modechange( new, mode );
+ newblock( old, new );
+ }
+ charprint( new, bufr[i] );
+ }
+ }
+ (void)modechange( dbg_eof, mode );
+
+ (void)printf( "</BODY>\n</HTML>\n" );
+ return( 0 );
+ } /* main */
diff --git a/source/utils/make_printerdef.c b/source/utils/make_printerdef.c
new file mode 100644
index 00000000000..47589984ccb
--- /dev/null
+++ b/source/utils/make_printerdef.c
@@ -0,0 +1,586 @@
+ /*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Create printer definition files.
+
+ Copyright (C) Jean-Francois.Micouleau@utc.fr, 10/26/97 - 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+#define DEBUGIT
+*/
+
+char *files_to_copy;
+char *driverfile, *datafile, *helpfile, *languagemonitor, *datatype, *vendorsetup;
+char buffer[50][sizeof(pstring)];
+char sbuffer[50][sizeof(pstring)];
+char sub_dir[50][2][sizeof(pstring)];
+
+static void usage(char *name)
+{
+ fprintf(stderr,"%s: printer.def \"Printer Name\"\n", name);
+}
+
+static char *myfgets(char *s, int n, FILE *stream)
+{
+ char *LString1;
+ char *LString2;
+ char *temp;
+ pstring String;
+ pstring NewString;
+ int i;
+
+ fgets(s,n,stream);
+ while ((LString1 = strchr_m(s,'%')) != NULL) {
+ if (!(LString2 = strchr_m(LString1+1,'%'))) break;
+ *LString2 = '\0';
+ pstrcpy(String,LString1+1);
+ i = 0;
+ while(*sbuffer[i]!='\0') {
+ if (strncmp(sbuffer[i],String,strlen(String))==0)
+ {
+ pstrcpy(String,sbuffer[i]);
+ if ((temp = strchr_m(String,'=')) != NULL) ++temp;
+ pstrcpy(String,temp);
+ break;
+ }
+ i++;
+ }
+ *LString1 = '\0';
+ pstrcpy(NewString,s);
+ pstrcat(NewString,String);
+ pstrcat(NewString,LString2+1);
+ pstrcpy(s, NewString);
+ }
+ return(s);
+}
+
+/*
+ This function split a line in two parts
+ on both side of the equal sign
+ "entry=value"
+*/
+static char *scan(char *chaine,char **entry)
+{
+ char *value;
+ char *temp;
+ int i=0;
+
+ *entry=(char *)malloc(sizeof(pstring));
+ value=(char *)malloc(sizeof(pstring));
+
+ if(*entry == NULL || value == NULL) {
+ fprintf(stderr,"scan: malloc fail !\n");
+ exit(1);
+ }
+
+ pstrcpy(*entry,chaine);
+ temp=chaine;
+ while( temp[i]!='=' && temp[i]!='\0') {
+ i++;
+ }
+ (*entry)[i]='\0';
+ if (temp[i]!='\0') {
+ i++;
+ }
+ while( temp[i]==' ' && temp[i]!='\0') {
+ i++;
+ }
+ pstrcpy(value,temp+i);
+ return (value);
+}
+
+static void build_subdir(void)
+{
+ int i=0;
+ int j=0;
+ char *entry;
+ char *data;
+
+ while (*buffer[i]!='\0') {
+ data=scan(buffer[i],&entry);
+#ifdef DEBUGIT
+ fprintf(stderr,"\tentry=data %s:%s\n",entry,data);
+#endif
+ j = strlen(entry);
+ while (j) {
+ if (entry[j-1] != ' ') break;
+ j--;
+ }
+ entry[j] = '\0';
+
+ if (strncmp(data,"11",2)==0) {
+ pstrcpy(sub_dir[i][0],entry);
+ pstrcpy(sub_dir[i][1],"");
+ }
+ if (strncmp(data,"23",2)==0) {
+ pstrcpy(sub_dir[i][0],entry);
+ pstrcpy(sub_dir[i][1],"color\\");
+ }
+#ifdef DEBUGIT
+ fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]);
+#endif
+ i++;
+ }
+}
+
+/*
+ Lockup Strings entry in a file
+ Return all the lines between the entry and the next one or the end of file
+ An entry is something between braces.
+*/
+static void lookup_strings(FILE *fichier)
+{
+ int found=0,pointeur=0,i=0;
+ char *temp,*temp2;
+
+ temp=(char *)malloc(sizeof(pstring));
+ temp2=(char *)malloc(sizeof(pstring));
+
+ if(temp == NULL || temp2 == NULL) {
+ SAFE_FREE(temp);
+ SAFE_FREE(temp2);
+ fprintf(stderr,"lookup_strings: malloc fail !\n");
+ exit(1);
+ }
+
+ *sbuffer[0]='\0';
+
+ pstrcpy(temp2,"[Strings]");
+
+ rewind(fichier);
+#ifdef DEBUGIT
+ fprintf(stderr,"\tLooking for Strings\n");
+#endif
+
+ while (!feof(fichier) && found==0) {
+ *temp='\0';
+ fgets(temp,255,fichier);
+ if (strncmp(temp,temp2,strlen(temp2))==0) found=1;
+ }
+
+
+ while (!feof(fichier) && found==1) {
+ *temp='\0';
+ fgets(temp,255,fichier);
+ if (*temp=='[') {
+ found=2;
+ *sbuffer[pointeur]='\0';
+ }
+ else {
+ pstrcpy(sbuffer[pointeur],temp);
+ i=strlen(sbuffer[pointeur])-1;
+ while (sbuffer[pointeur][i]=='\r' || sbuffer[pointeur][i]=='\n')
+ sbuffer[pointeur][i--]='\0';
+ pointeur++;
+ }
+ }
+
+ /* CCMRCF Mod, seg fault or worse if not found */
+ if (pointeur == 0) {
+ fprintf(stderr,"Printer not found\tNo [Strings] block in inf file\n");
+ exit(2);
+ }
+
+#ifdef DEBUGIT
+ fprintf(stderr,"\t\tFound %d entries\n",pointeur-1);
+#endif
+}
+
+
+/*
+ Lockup an entry in a file
+ Return all the lines between the entry and the next one or the end of file
+ An entry is something between braces.
+*/
+static void lookup_entry(FILE *fichier,char *chaine)
+{
+ int found=0,pointeur=0,i=0;
+ char *temp,*temp2;
+
+ temp=(char *)malloc(sizeof(pstring));
+ temp2=(char *)malloc(sizeof(pstring));
+
+ if(temp == NULL || temp2 == NULL) {
+ SAFE_FREE(temp);
+ SAFE_FREE(temp2);
+ fprintf(stderr,"lookup_entry: malloc fail !\n");
+ exit(1);
+ }
+
+ *buffer[0]='\0';
+
+ pstrcpy(temp2,"[");
+ pstrcat(temp2,chaine);
+ pstrcat(temp2,"]");
+
+ rewind(fichier);
+#ifdef DEBUGIT
+ fprintf(stderr,"\tLooking for %s\n",chaine);
+#endif
+
+ while (!feof(fichier) && found==0) {
+ *temp='\0';
+ myfgets(temp,255,fichier);
+ if (strncmp(temp,temp2,strlen(temp2))==0) found=1;
+ }
+
+
+ while (!feof(fichier) && found==1) {
+ *temp='\0';
+ myfgets(temp,255,fichier);
+ if (*temp=='[') {
+ found=2;
+ *buffer[pointeur]='\0';
+ }
+ else {
+ pstrcpy(buffer[pointeur],temp);
+ i=strlen(buffer[pointeur])-1;
+ while (buffer[pointeur][i]=='\r' || buffer[pointeur][i]=='\n')
+ buffer[pointeur][i--]='\0';
+ pointeur++;
+ }
+ }
+#ifdef DEBUGIT
+ fprintf(stderr,"\t\tFound %d entries\n",pointeur-1);
+#endif
+}
+
+static char *find_desc(FILE *fichier,char *text)
+{
+ char *chaine;
+ char *long_desc;
+ char *short_desc;
+ char *crap = NULL;
+ char *p;
+
+ int found=0;
+
+ chaine=(char *)malloc(sizeof(pstring));
+ long_desc=(char *)malloc(sizeof(pstring));
+ short_desc=(char *)malloc(sizeof(pstring));
+ if (!chaine || !long_desc || !short_desc) {
+ SAFE_FREE(chaine);
+ SAFE_FREE(long_desc);
+ SAFE_FREE(short_desc);
+ fprintf(stderr,"find_desc: Unable to malloc memory\n");
+ exit(1);
+ }
+
+ rewind(fichier);
+ while (!feof(fichier) && found==0)
+ {
+ myfgets(chaine,255,fichier);
+
+ long_desc=strtok(chaine,"=");
+ crap=strtok(NULL,",\r");
+
+ p=long_desc;
+ while(*p!='"' && *p!='\0')
+ p++;
+ if (*p=='"' && *(p+1)!='\0') p++;
+ long_desc=p;
+
+ if (*p!='\0')
+ {
+ p++;
+ while(*p!='\"')
+ p++;
+ *p='\0';
+ }
+ if (!strcmp(text,long_desc))
+ found=1;
+ }
+ SAFE_FREE(chaine);
+ if (!found || !crap) return(NULL);
+ while(*crap==' ') crap++;
+ pstrcpy(short_desc,crap);
+ return(short_desc);
+}
+
+static void scan_copyfiles(FILE *fichier, char *chaine)
+{
+ char *part;
+ char *mpart;
+ int i;
+ pstring direc;
+#ifdef DEBUGIT
+ fprintf(stderr,"In scan_copyfiles Lookup up of %s\n",chaine);
+#endif
+ fprintf(stderr,"\nCopy the following files to your printer$ share location:\n");
+ part=strtok(chaine,",");
+ do {
+ /* If the entry start with a @ then it's a file to copy
+ else it's an entry refering to files to copy
+ the main difference is when it's an entry
+ you can have a directory to append before the file name
+ */
+ if (*part=='@') {
+ if (strlen(files_to_copy) != 0)
+ pstrcat(files_to_copy,",");
+ pstrcat(files_to_copy,&part[1]);
+ fprintf(stderr,"%s\n",&part[1]);
+ } else {
+ lookup_entry(fichier,part);
+ i=0;
+ pstrcpy(direc,"");
+ while (*sub_dir[i][0]!='\0') {
+#ifdef DEBUGIT
+ fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]);
+#endif
+ if (strcmp(sub_dir[i][0],part)==0)
+ pstrcpy(direc,sub_dir[i][1]);
+ i++;
+ }
+ i=0;
+ while (*buffer[i]!='\0') {
+/*
+ * HP inf files have strange entries that this attempts to address
+ * Entries in the Copy sections normally have only a single file name
+ * on each line. I have seen the following format in various HP inf files:
+ *
+ * pscript.hlp = pscript.hl_
+ * hpdcmon.dll,hpdcmon.dl_
+ * MSVCRT.DLL,MSVCRT.DL_,,32
+ * ctl3dv2.dll,ctl3dv2.dl_,ctl3dv2.tmp
+ *
+ * In the first 2 cases you want the first file name - in the last case
+ * you only want the last file name (at least that is what a Win95
+ * machine sent). In the third case you also want the first file name
+ * (detect by the last component being just a number ?).
+ * This may still be wrong but at least I get the same list
+ * of files as seen on a printer test page.
+ */
+ part = strchr_m(buffer[i],'=');
+ if (part) {
+ /*
+ * Case (1) eg. pscript.hlp = pscript.hl_ - chop after the first name.
+ */
+
+ *part = '\0';
+
+ /*
+ * Now move back to the start and print that.
+ */
+
+ while (--part > buffer[i]) {
+ if ((*part == ' ') || (*part =='\t'))
+ *part = '\0';
+ else
+ break;
+ }
+ } else {
+ part = strchr_m(buffer[i],',');
+ if (part) {
+ /*
+ * Cases (2-4)
+ */
+
+ if ((mpart = strrchr_m(part+1,','))!=NULL) {
+ /*
+ * Second ',' - case 3 or 4.
+ * Check if the last part is just a number,
+ * if so we need the first part.
+ */
+
+ char *endptr = NULL;
+ BOOL isnumber = False;
+
+ mpart++;
+ (void)strtol(mpart, &endptr, 10);
+
+ isnumber = ((endptr > mpart) && isdigit(*mpart));
+ if(!isnumber)
+ pstrcpy(buffer[i],mpart+1);
+ else
+ *part = '\0';
+ } else {
+ *part = '\0';
+ }
+ while (--part > buffer[i])
+ if ((*part == ' ') || (*part =='\t')) *part = '\0';
+ else break;
+ }
+ }
+ if (*buffer[i] != ';') {
+ if (strlen(files_to_copy) != 0)
+ pstrcat(files_to_copy,",");
+ pstrcat(files_to_copy,direc);
+ pstrcat(files_to_copy,buffer[i]);
+ fprintf(stderr,"%s%s\n",direc,buffer[i]);
+ }
+ i++;
+ } /* end while */
+ }
+ part=strtok(NULL,",");
+ if (part) {
+ while( *part ==' ' && *part != '\0') {
+ part++;
+ }
+ }
+ } while (part!=NULL);
+ fprintf(stderr,"\n");
+}
+
+
+static void scan_short_desc(FILE *fichier, char *short_desc)
+{
+ int i=0;
+ char *temp;
+ char *copyfiles=0,*datasection=0;
+
+ helpfile=0;
+ languagemonitor=0;
+ vendorsetup=0;
+ datatype="RAW";
+ if((temp=(char *)malloc(sizeof(pstring))) == NULL) {
+ fprintf(stderr, "scan_short_desc: malloc fail !\n");
+ exit(1);
+ }
+
+ driverfile=short_desc;
+ datafile=short_desc;
+
+ lookup_entry(fichier,short_desc);
+
+ while(*buffer[i]!='\0') {
+#ifdef DEBUGIT
+ fprintf(stderr,"\tLookup up of %s\n",buffer[i]);
+#endif
+ if (strncasecmp(buffer[i],"CopyFiles",9)==0)
+ copyfiles=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DataSection",11)==0)
+ datasection=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DataFile",8)==0)
+ datafile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DriverFile",10)==0)
+ driverfile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"HelpFile",8)==0)
+ helpfile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"LanguageMonitor",15)==0)
+ languagemonitor=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DefaultDataType",15)==0)
+ datatype=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"VendorSetup",11)==0)
+ vendorsetup=scan(buffer[i],&temp);
+ i++;
+ }
+
+ if (datasection) {
+ lookup_entry(fichier,datasection);
+
+ i = 0;
+ while(*buffer[i]!='\0') {
+#ifdef DEBUGIT
+ fprintf(stderr,"\tLookup up of %s\n",buffer[i]);
+#endif
+ if (strncasecmp(buffer[i],"CopyFiles",9)==0)
+ copyfiles=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DataSection",11)==0)
+ datasection=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DataFile",8)==0)
+ datafile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DriverFile",10)==0)
+ driverfile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"HelpFile",8)==0)
+ helpfile=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"LanguageMonitor",15)==0)
+ languagemonitor=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"DefaultDataType",15)==0)
+ datatype=scan(buffer[i],&temp);
+ else if (strncasecmp(buffer[i],"VendorSetup",11)==0)
+ vendorsetup=scan(buffer[i],&temp);
+ i++;
+ }
+ }
+
+ if (languagemonitor) {
+ temp = strtok(languagemonitor,",");
+ if (*temp == '"') ++temp;
+ pstrcpy(languagemonitor,temp);
+ if ((temp = strchr_m(languagemonitor,'"'))!=NULL) *temp = '\0';
+ }
+
+ if (i) fprintf(stderr,"End of section found\n");
+
+ fprintf(stderr,"CopyFiles: %s\n",
+ copyfiles?copyfiles:"(null)");
+ fprintf(stderr,"Datasection: %s\n",
+ datasection?datasection:"(null)");
+ fprintf(stderr,"Datafile: %s\n",
+ datafile?datafile:"(null)");
+ fprintf(stderr,"Driverfile: %s\n",
+ driverfile?driverfile:"(null)");
+ fprintf(stderr,"Helpfile: %s\n",
+ helpfile?helpfile:"(null)");
+ fprintf(stderr,"LanguageMonitor: %s\n",
+ languagemonitor?languagemonitor:"(null)");
+ fprintf(stderr,"VendorSetup: %s\n",
+ vendorsetup?vendorsetup:"(null)");
+ if (copyfiles) scan_copyfiles(fichier,copyfiles);
+}
+
+int main(int argc, char *argv[])
+{
+ char *short_desc;
+ FILE *inf_file;
+
+ if (argc!=3)
+ {
+ usage(argv[0]);
+ return(-1);
+ }
+
+ inf_file=sys_fopen(argv[1],"r");
+ if (!inf_file)
+ {
+ fprintf(stderr,"Description file not found, bye\n");
+ return(-1);
+ }
+
+ lookup_strings(inf_file);
+
+ short_desc=find_desc(inf_file,argv[2]);
+ if (short_desc==NULL)
+ {
+ fprintf(stderr,"Printer not found\n");
+ return(-1);
+ }
+ else fprintf(stderr,"Found:%s\n",short_desc);
+
+ lookup_entry(inf_file,"DestinationDirs");
+ build_subdir();
+
+ if((files_to_copy=(char *)malloc(2048*sizeof(char))) == NULL) {
+ fprintf(stderr, "%s: malloc fail.\n", argv[0] );
+ exit(1);
+ }
+ *files_to_copy='\0';
+ scan_short_desc(inf_file,short_desc);
+ fprintf(stdout,"%s:%s:%s:",
+ argv[2],driverfile,datafile);
+ fprintf(stdout,"%s:",
+ helpfile?helpfile:"");
+ fprintf(stdout,"%s:",
+ languagemonitor?languagemonitor:"");
+ fprintf(stdout,"%s:",datatype);
+ fprintf(stdout,"%s\n",files_to_copy);
+ return 0;
+}
+
diff --git a/source/utils/net.c b/source/utils/net.c
new file mode 100644
index 00000000000..a87f11b57fd
--- /dev/null
+++ b/source/utils/net.c
@@ -0,0 +1,454 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ Originally written by Steve and Jim. Largely rewritten by tridge in
+ November 2001.
+
+ Reworked again by abartlet in December 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*****************************************************/
+/* */
+/* Distributed SMB/CIFS Server Management Utility */
+/* */
+/* The intent was to make the syntax similar */
+/* to the NET utility (first developed in DOS */
+/* with additional interesting & useful functions */
+/* added in later SMB server network operating */
+/* systems). */
+/* */
+/*****************************************************/
+
+#include "includes.h"
+#include "../utils/net.h"
+
+/***********************************************************************/
+/* Beginning of internationalization section. Translatable constants */
+/* should be kept in this area and referenced in the rest of the code. */
+/* */
+/* No functions, outside of Samba or LSB (Linux Standards Base) should */
+/* be used (if possible). */
+/***********************************************************************/
+
+#define YES_STRING "Yes"
+#define NO_STRING "No"
+
+/************************************************************************************/
+/* end of internationalization section */
+/************************************************************************************/
+
+/* Yes, these buggers are globals.... */
+char *opt_requester_name = NULL;
+char *opt_host = NULL;
+char *opt_password = NULL;
+char *opt_user_name = NULL;
+char *opt_workgroup = NULL;
+int opt_long_list_entries = 0;
+int opt_port = 0;
+int opt_maxusers = -1;
+char *opt_comment = "";
+int opt_flags = -1;
+int opt_jobid = 0;
+char *opt_target_workgroup = NULL;
+
+static BOOL got_pass = False;
+BOOL opt_have_ip = False;
+struct in_addr opt_dest_ip;
+
+extern pstring global_myname;
+
+/*
+ run a function from a function table. If not found then
+ call the specified usage function
+*/
+int net_run_function(int argc, const char **argv, struct functable *table,
+ int (*usage_fn)(int argc, const char **argv))
+{
+ int i;
+
+ if (argc < 1) {
+ d_printf("\nUsage: \n");
+ return usage_fn(argc, argv);
+ }
+ for (i=0; table[i].funcname; i++) {
+ if (StrCaseCmp(argv[0], table[i].funcname) == 0)
+ return table[i].fn(argc-1, argv+1);
+ }
+ d_printf("No command: %s\n", argv[0]);
+ return usage_fn(argc, argv);
+}
+
+
+/****************************************************************************
+connect to \\server\ipc$
+****************************************************************************/
+static struct cli_state *connect_to_ipc(struct in_addr *server_ip, const char *server_name)
+{
+ struct cli_state *c;
+ NTSTATUS nt_status;
+
+ if (!got_pass) {
+ char *pass = getpass("Password:");
+ if (pass) {
+ opt_password = strdup(pass);
+ }
+ }
+
+ nt_status = cli_full_connection(&c, opt_requester_name, server_name,
+ server_ip, opt_port,
+ "IPC$", "IPC",
+ opt_user_name, opt_workgroup,
+ opt_password, strlen(opt_password));
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return c;
+ } else {
+ DEBUG(0,("Cannot connect to server. Error was %s\n",
+ get_nt_error_msg(nt_status)));
+
+ /* Display a nicer message depending on the result */
+
+ if (NT_STATUS_V(nt_status) ==
+ NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
+ d_printf("The username or password was not correct.\n");
+
+ return NULL;
+ }
+}
+
+/****************************************************************************
+connect to \\server\ipc$ anonymously
+****************************************************************************/
+static struct cli_state *connect_to_ipc_anonymous(struct in_addr *server_ip, const char *server_name)
+{
+ struct cli_state *c;
+ NTSTATUS nt_status;
+
+ nt_status = cli_full_connection(&c, opt_requester_name, server_name,
+ server_ip, opt_port,
+ "IPC$", "IPC",
+ "", "",
+ "", 0);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return c;
+ } else {
+ DEBUG(0,("Cannot connect to server (anonymously). Error was %s\n", get_nt_error_msg(nt_status)));
+ return NULL;
+ }
+}
+
+static BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name)
+{
+
+ if (opt_host) {
+ *server_name = strdup(opt_host);
+ }
+
+ if (opt_have_ip) {
+ *server_ip = opt_dest_ip;
+ if (!*server_name) {
+ *server_name = strdup(inet_ntoa(opt_dest_ip));
+ }
+ } else if (*server_name) {
+ /* resolve the IP address */
+ if (!resolve_name(*server_name, server_ip, 0x20)) {
+ DEBUG(1,("Unable to resolve server name\n"));
+ return False;
+ }
+ } else if (flags & NET_FLAGS_PDC) {
+ struct in_addr *ip_list;
+ int addr_count;
+ if (get_dc_list(True /* PDC only*/, opt_target_workgroup, &ip_list, &addr_count)) {
+ fstring dc_name;
+ if (addr_count < 1) {
+ return False;
+ }
+
+ *server_ip = *ip_list;
+
+ if (is_zero_ip(*server_ip))
+ return False;
+
+ if (!lookup_dc_name(global_myname, opt_target_workgroup, server_ip, dc_name))
+ return False;
+
+ *server_name = strdup(dc_name);
+ }
+
+ } else if (flags & NET_FLAGS_DMB) {
+ struct in_addr msbrow_ip;
+ /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */
+ if (!resolve_name(opt_target_workgroup, &msbrow_ip, 0x1B)) {
+ DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
+ return False;
+ } else {
+ *server_ip = msbrow_ip;
+ }
+ *server_name = strdup(inet_ntoa(opt_dest_ip));
+ } else if (flags & NET_FLAGS_MASTER) {
+ struct in_addr brow_ips;
+ if (!resolve_name(opt_target_workgroup, &brow_ips, 0x1D)) {
+ /* go looking for workgroups */
+ DEBUG(1,("Unable to resolve master browser via name lookup\n"));
+ return False;
+ } else {
+ *server_ip = brow_ips;
+ }
+ *server_name = strdup(inet_ntoa(opt_dest_ip));
+ } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) {
+ extern struct in_addr loopback_ip;
+ *server_ip = loopback_ip;
+ *server_name = strdup("127.0.0.1");
+ }
+
+ if (!server_name || !*server_name) {
+ DEBUG(1,("no server to connect to\n"));
+ return False;
+ }
+
+ return True;
+}
+
+struct cli_state *net_make_ipc_connection(unsigned flags)
+{
+ char *server_name = NULL;
+ struct in_addr server_ip;
+ struct cli_state *cli;
+
+ if (!net_find_server(flags, &server_ip, &server_name)) {
+ d_printf("\nUnable to find a suitable server\n");
+ return NULL;
+ }
+
+ if (flags & NET_FLAGS_ANONYMOUS) {
+ cli = connect_to_ipc_anonymous(&server_ip, server_name);
+ } else {
+ cli = connect_to_ipc(&server_ip, server_name);
+ }
+ SAFE_FREE(server_name);
+ return cli;
+}
+
+
+static int net_usage(int argc, const char **argv)
+{
+ d_printf(" net ads [command]\tto run ADS commands\n"\
+ " net rap [command]\tto run RAP (pre-RPC) commands\n"\
+ " net rpc [command]\tto run RPC commands\n"\
+ " net rap help\n"\
+ "\nType \"net help <option>\" to get more information on that option\n");
+ return -1;
+}
+
+static int help_usage(int argc, const char **argv)
+{
+ d_printf(
+"\n"\
+"Usage: net help <function>\n"\
+"\n"\
+"Valid functions are:\n"\
+" RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\
+" GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n");
+ return -1;
+}
+
+/*
+ handle "net help *" subcommands
+*/
+static int net_help(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"ADS", net_ads_usage},
+ {"RAP", net_rap_usage},
+ {"RPC", net_rpc_usage},
+
+ {"FILE", net_rap_file_usage},
+ {"SHARE", net_rap_share_usage},
+ {"SESSION", net_rap_session_usage},
+ {"SERVER", net_rap_server_usage},
+ {"DOMAIN", net_rap_domain_usage},
+ {"PRINTQ", net_rap_printq_usage},
+ {"USER", net_rap_user_usage},
+ {"GROUP", net_rap_group_usage},
+ {"VALIDATE", net_rap_validate_usage},
+ {"GROUPMEMBER", net_rap_groupmember_usage},
+ {"ADMIN", net_rap_admin_usage},
+ {"SERVICE", net_rap_service_usage},
+ {"PASSWORD", net_rap_password_usage},
+ {"TIME", net_time_usage},
+ {"LOOKUP", net_lookup_usage},
+
+ {"HELP", help_usage},
+ {NULL, NULL}};
+
+ return net_run_function(argc, argv, func, help_usage);
+}
+
+/* main function table */
+static struct functable net_func[] = {
+ {"RPC", net_rpc},
+ {"RAP", net_rap},
+ {"ADS", net_ads},
+
+ /* eventually these should auto-choose the transport ... */
+ {"FILE", net_rap_file},
+ {"SHARE", net_rap_share},
+ {"SESSION", net_rap_session},
+ {"SERVER", net_rap_server},
+ {"DOMAIN", net_rap_domain},
+ {"PRINTQ", net_rap_printq},
+ {"USER", net_rap_user},
+ {"GROUP", net_rap_group},
+ {"VALIDATE", net_rap_validate},
+ {"GROUPMEMBER", net_rap_groupmember},
+ {"ADMIN", net_rap_admin},
+ {"SERVICE", net_rap_service},
+ {"PASSWORD", net_rap_password},
+ {"TIME", net_time},
+ {"LOOKUP", net_lookup},
+
+ {"HELP", net_help},
+ {NULL, NULL}
+};
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc, const char **argv)
+{
+ int opt,i;
+ char *p;
+ int rc = 0;
+ int argc_new = 0;
+ const char ** argv_new;
+ poptContext pc;
+ static char *servicesf = dyn_CONFIGFILE;
+ static int debuglevel;
+
+ struct poptOption long_options[] = {
+ {"help", 'h', POPT_ARG_NONE, 0, 'h'},
+ {"workgroup", 'w', POPT_ARG_STRING, &opt_target_workgroup},
+ {"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup},
+ {"user", 'U', POPT_ARG_STRING, &opt_user_name, 'U'},
+ {"ipaddress", 'I', POPT_ARG_STRING, 0, 'I'},
+ {"port", 'p', POPT_ARG_INT, &opt_port},
+ {"myname", 'n', POPT_ARG_STRING, &opt_requester_name},
+ {"conf", 's', POPT_ARG_STRING, &servicesf},
+ {"debug", 'd', POPT_ARG_INT, &debuglevel, 'd'},
+ {"debuglevel", 'd', POPT_ARG_INT, &debuglevel, 'd'},
+ {"server", 'S', POPT_ARG_STRING, &opt_host},
+ {"comment", 'C', POPT_ARG_STRING, &opt_comment},
+ {"maxusers", 'M', POPT_ARG_INT, &opt_maxusers},
+ {"flags", 'F', POPT_ARG_INT, &opt_flags},
+ {"jobid", 'j', POPT_ARG_INT, &opt_jobid},
+ {"long", 'l', POPT_ARG_NONE, &opt_long_list_entries},
+ { 0, 0, 0, 0}
+ };
+
+ got_pass = 0;
+ zero_ip(&opt_dest_ip);
+
+ dbf = x_stderr;
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'h':
+ net_usage(argc, argv);
+ exit(0);
+ break;
+ case 'I':
+ opt_dest_ip = *interpret_addr2(poptGetOptArg(pc));
+ if (is_zero_ip(opt_dest_ip))
+ d_printf("\nInvalid ip address specified\n");
+ else
+ opt_have_ip = True;
+ break;
+ case 'U':
+ opt_user_name = strdup(opt_user_name);
+ p = strchr(opt_user_name,'%');
+ if (p) {
+ *p = 0;
+ opt_password = p+1;
+ got_pass = 1;
+ }
+ break;
+ default:
+ d_printf("\nInvalid option %c (%d)\n", (char)opt, opt);
+ net_usage(argc, argv);
+ }
+ }
+
+ lp_load(servicesf,True,False,False);
+
+ DEBUGLEVEL = debuglevel;
+
+ argv_new = (const char **)poptGetArgs(pc);
+
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (!opt_requester_name) {
+ static fstring myname;
+ get_myname(myname);
+ opt_requester_name = myname;
+ }
+
+ if (!opt_user_name && getenv("LOGNAME")) {
+ opt_user_name = getenv("LOGNAME");
+ }
+
+ if (!opt_workgroup) {
+ opt_workgroup = lp_workgroup();
+ }
+
+ if (!opt_target_workgroup) {
+ opt_target_workgroup = lp_workgroup();
+ }
+
+ if (!*global_myname) {
+ char *p2;
+
+ fstrcpy(global_myname, myhostname());
+ p2 = strchr_m(global_myname, '.');
+ if (p2)
+ *p2 = 0;
+ }
+
+ strupper(global_myname);
+
+ load_interfaces();
+
+ rc = net_run_function(argc_new-1, argv_new+1, net_func, net_usage);
+
+ DEBUG(2,("return code = %d\n", rc));
+ return rc;
+}
diff --git a/source/utils/net.h b/source/utils/net.h
new file mode 100644
index 00000000000..e912efe09e0
--- /dev/null
+++ b/source/utils/net.h
@@ -0,0 +1,45 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define NET_FLAGS_MASTER 1
+#define NET_FLAGS_DMB 2
+
+/* Would it be insane to set 'localhost' as the default
+ remote host for this operation?
+
+ For example, localhost is insane for a 'join' operation.
+*/
+#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 4
+
+/* We want to find the PDC only */
+#define NET_FLAGS_PDC 8
+
+/* We want an anonymous connection */
+#define NET_FLAGS_ANONYMOUS 16
+
+
+extern int opt_maxusers;
+extern char *opt_comment;
+extern int opt_flags;
+
+extern char *opt_comment;
+
+extern char *opt_target_workgroup;
+extern int opt_long_list_entries;
diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c
new file mode 100644
index 00000000000..7baa2972305
--- /dev/null
+++ b/source/utils/net_ads.c
@@ -0,0 +1,391 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ net ads commands
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_ADS
+
+int net_ads_usage(int argc, const char **argv)
+{
+ d_printf(
+"\nnet ads join <org_unit>"\
+"\n\tjoins the local machine to a ADS realm\n"\
+"\nnet ads leave"\
+"\n\tremoves the local machine from a ADS realm\n"\
+"\nnet ads user"\
+"\n\tlist users in the realm\n"\
+"\nnet ads group"\
+"\n\tlist groups in the realm\n"\
+"\nnet ads info"\
+"\n\tshows some info on the server\n"\
+"\nnet ads status"\
+"\n\tdump the machine account details to stdout\n"
+"\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
+"\n\tchange a user's password using an admin account"
+"\n\t(note: use realm in UPPERCASE)\n"
+"\nnet ads chostpass"
+"\n\tchange the trust account password of this machine in the AD tree\n"
+ );
+ return -1;
+}
+
+
+static int net_ads_info(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+
+ ads = ads_init(NULL, NULL, NULL, NULL);
+ ads_connect(ads);
+
+ if (!ads) {
+ d_printf("Didn't find the ldap server!\n");
+ return -1;
+ }
+
+ d_printf("LDAP server: %s\n", ads->ldap_server);
+ d_printf("LDAP server name: %s\n", ads->ldap_server_name);
+ d_printf("Realm: %s\n", ads->realm);
+ d_printf("Bind Path: %s\n", ads->bind_path);
+ d_printf("LDAP port: %d\n", ads->ldap_port);
+
+ return 0;
+}
+
+
+static ADS_STRUCT *ads_startup(void)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ extern char *opt_password;
+ extern char *opt_user_name;
+
+ ads = ads_init(NULL, NULL, NULL, NULL);
+
+ if (!opt_user_name) {
+ opt_user_name = "administrator";
+ }
+
+ if (!opt_password) {
+ char *prompt;
+ asprintf(&prompt,"%s password: ", opt_user_name);
+ opt_password = getpass(prompt);
+ free(prompt);
+ }
+ ads->password = strdup(opt_password);
+ ads->user_name = strdup(opt_user_name);
+
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status)) {
+ d_printf("ads_connect: %s\n", ads_errstr(status));
+ return NULL;
+ }
+ return ads;
+}
+
+static int net_ads_user(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ void *res;
+ const char *attrs[] = {"sAMAccountName", "name", "objectSid", NULL};
+
+ if (!(ads = ads_startup())) return -1;
+ rc = ads_search(ads, &res, "(objectclass=user)", attrs);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_search: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_printf("No users found\n");
+ return -1;
+ }
+
+ ads_dump(ads, res);
+ ads_destroy(&ads);
+ return 0;
+}
+
+static int net_ads_group(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ void *res;
+ const char *attrs[] = {"sAMAccountName", "name", "objectSid", NULL};
+
+ if (!(ads = ads_startup())) return -1;
+ rc = ads_search(ads, &res, "(objectclass=group)", attrs);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_search: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_printf("No groups found\n");
+ return -1;
+ }
+
+ ads_dump(ads, res);
+ return 0;
+}
+
+static int net_ads_status(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ extern pstring global_myname;
+ void *res;
+
+ if (!(ads = ads_startup())) return -1;
+
+ rc = ads_find_machine_acct(ads, &res, global_myname);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ if (ads_count_replies(ads, res) == 0) {
+ d_printf("No machine account for '%s' found\n", global_myname);
+ return -1;
+ }
+
+ ads_dump(ads, res);
+
+ return 0;
+}
+
+static int net_ads_leave(int argc, const char **argv)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS rc;
+ extern pstring global_myname;
+
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
+
+ if (!secrets_init()) {
+ DEBUG(1,("Failed to initialise secrets database\n"));
+ return -1;
+ }
+
+ rc = ads_leave_realm(ads, global_myname);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("Failed to delete host '%s' from the '%s' realm.\n",
+ global_myname, ads->realm);
+ return -1;
+ }
+
+ d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm);
+
+ return 0;
+}
+
+static int net_ads_join(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ char *password;
+ char *tmp_password;
+ extern pstring global_myname;
+ const char *org_unit = "Computers";
+ char *dn;
+ void *res;
+ DOM_SID dom_sid;
+
+ if (argc > 0) org_unit = argv[0];
+
+ if (!secrets_init()) {
+ DEBUG(1,("Failed to initialise secrets database\n"));
+ return -1;
+ }
+
+ tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ password = strdup(tmp_password);
+
+ if (!(ads = ads_startup())) return -1;
+
+ asprintf(&dn, "cn=%s,%s", org_unit, ads->bind_path);
+
+ rc = ads_search_dn(ads, &res, dn, NULL);
+ free(dn);
+ ads_msgfree(ads, res);
+
+ if (rc.error_type == ADS_ERROR_LDAP && rc.rc == LDAP_NO_SUCH_OBJECT) {
+ d_printf("ads_join_realm: organisational unit %s does not exist\n", org_unit);
+ return -1;
+ }
+
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_join_realm: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ rc = ads_join_realm(ads, global_myname, org_unit);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_join_realm: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ rc = ads_set_machine_password(ads, global_myname, password);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ rc = ads_domain_sid(ads, &dom_sid);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
+ return -1;
+ }
+
+ if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
+ DEBUG(1,("Failed to save domain sid\n"));
+ return -1;
+ }
+
+ if (!secrets_store_machine_password(password)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ return -1;
+ }
+
+ d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm);
+
+ free(password);
+
+ return 0;
+}
+
+
+static int net_ads_password(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ extern char *opt_user_name;
+ extern char *opt_password;
+ char *auth_principal = opt_user_name;
+ char *auth_password = opt_password;
+ char *realm = NULL;
+ char *new_password = NULL;
+ char *c;
+ char *prompt;
+ ADS_STATUS ret;
+
+
+ if ((argc != 1) || (opt_user_name == NULL) ||
+ (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
+ (strchr(argv[0], '@') == NULL)) {
+ return net_ads_usage(argc, argv);
+ }
+
+ c = strchr(auth_principal, '@');
+ realm = ++c;
+
+ /* use the realm so we can eventually change passwords for users
+ in realms other than default */
+ if (!(ads = ads_init(realm, NULL, NULL, NULL))) return -1;
+
+ asprintf(&prompt, "Enter new password for %s:", argv[0]);
+
+ new_password = getpass(prompt);
+
+ ret = kerberos_set_password(ads->kdc_server, auth_principal,
+ auth_password, argv[0], new_password);
+ if (!ADS_ERR_OK(ret)) {
+ d_printf("Password change failed :-( ...\n");
+ ads_destroy(&ads);
+ free(prompt);
+ return -1;
+ }
+
+ d_printf("Password change for %s completed.\n", argv[0]);
+ ads_destroy(&ads);
+ free(prompt);
+
+ return 0;
+}
+
+
+static int net_ads_change_localhost_pass(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ extern pstring global_myname;
+ char *host_principal;
+ char *hostname;
+ ADS_STATUS ret;
+
+
+ if (!(ads = ads_init(NULL, NULL, NULL, NULL))) return -1;
+
+ hostname = strdup(global_myname);
+ strlower(hostname);
+ asprintf(&host_principal, "%s@%s", hostname, ads->realm);
+ SAFE_FREE(hostname);
+ d_printf("Changing password for principal: HOST/%s\n", host_principal);
+
+ ret = ads_change_trust_account_password(ads, host_principal);
+
+ if (!ADS_ERR_OK(ret)) {
+ d_printf("Password change failed :-( ...\n");
+ ads_destroy(&ads);
+ SAFE_FREE(host_principal);
+ return -1;
+ }
+
+ d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
+ ads_destroy(&ads);
+ SAFE_FREE(host_principal);
+
+ return 0;
+}
+
+
+int net_ads(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"INFO", net_ads_info},
+ {"JOIN", net_ads_join},
+ {"LEAVE", net_ads_leave},
+ {"STATUS", net_ads_status},
+ {"USER", net_ads_user},
+ {"GROUP", net_ads_group},
+ {"PASSWORD", net_ads_password},
+ {"CHOSTPASS", net_ads_change_localhost_pass},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_ads_usage);
+}
+
+#else
+
+int net_ads_usage(int argc, const char **argv)
+{
+ d_printf("ADS support not compiled in\n");
+ return -1;
+}
+
+int net_ads(int argc, const char **argv)
+{
+ return net_ads_usage(argc, argv);
+}
+
+#endif
diff --git a/source/utils/net_lookup.c b/source/utils/net_lookup.c
new file mode 100644
index 00000000000..21f3eb033de
--- /dev/null
+++ b/source/utils/net_lookup.c
@@ -0,0 +1,62 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ net lookup command
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "includes.h"
+#include "../utils/net.h"
+
+int net_lookup_usage(int argc, const char **argv)
+{
+ d_printf(
+"net lookup host HOSTNAME <type>\n\tgives IP for a hostname\n\n"\
+"\n");
+ return -1;
+}
+
+/* lookup a hostname giving an IP */
+static int net_lookup_host(int argc, const char **argv)
+{
+ struct in_addr ip;
+ int name_type = 0x20;
+
+ if (argc == 0) return net_lookup_usage(argc, argv);
+ if (argc > 1) name_type = strtol(argv[1], NULL, 0);
+
+ if (!resolve_name(argv[0], &ip, name_type)) {
+ /* we deliberately use DEBUG() here to send it to stderr
+ so scripts aren't mucked up */
+ DEBUG(0,("Didn't find %s#%02x\n", argv[0], name_type));
+ return -1;
+ }
+
+ d_printf("%s\n", inet_ntoa(ip));
+ return 0;
+}
+
+
+/* lookup hosts or IP addresses using internal samba lookup fns */
+int net_lookup(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"HOST", net_lookup_host},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_lookup_usage);
+}
diff --git a/source/utils/net_rap.c b/source/utils/net_rap.c
new file mode 100644
index 00000000000..5b52e614f9a
--- /dev/null
+++ b/source/utils/net_rap.c
@@ -0,0 +1,1127 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ Originally written by Steve and Jim. Largely rewritten by tridge in
+ November 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "includes.h"
+#include "../utils/net.h"
+
+/* The following messages were for error checking that is not properly
+ reported at the moment. Which should be reinstated? */
+#define ERRMSG_TARGET_WG_NOT_VALID "\nTarget workgroup option not valid "\
+ "except on net rap server command, ignored"
+#define ERRMSG_INVALID_HELP_OPTION "\nInvalid help option\n"
+
+#define ERRMSG_BOTH_SERVER_IPADDRESS "\nTarget server and IP address both "\
+ "specified. Do not set both at the same time. The target IP address was used\n"
+
+static const char *share_type[] = {
+ "Disk",
+ "Print",
+ "Dev",
+ "IPC"
+};
+
+static int errmsg_not_implemented(void)
+{
+ d_printf("\nNot implemented\n");
+ return 0;
+}
+
+int general_rap_usage(int argc, const char **argv)
+{
+
+ d_printf("Valid targets: choose one (none defaults to localhost)\n");
+ d_printf("\t-S or --server=<server>\t\tserver name\n");
+ d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n");
+ d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n");
+
+ d_printf("\n");
+ d_printf("Valid miscellaneous options are:\n"); /* misc options */
+ d_printf("\t-p or --port=<port>\tconnection port on target server\n");
+ d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n");
+ d_printf("\t-d or --debug=<level>\t\tdebug level (0-10)\n");
+ d_printf("\t-n or --myname=<name>\t\tclient name\n");
+ d_printf("\t-U or --user=<name>\t\tuser name\n");
+ d_printf("\t-s or --conf=<path>\t\tpathname of smb.conf file\n");
+ d_printf("\t-l or --long\t\t\tDisplay full information\n");
+ return -1;
+}
+
+
+int net_rap_file_usage(int argc, const char **argv)
+{
+ d_printf("net rap file [misc. options] [targets]\n"\
+ "\tlists all open files on file server\n\n");
+ d_printf("net rap file USER <username> [misc. options] [targets]\n"\
+ "\tlists all files opened by username on file server\n\n");
+ d_printf("net rap file CLOSE <id> [misc. options] [targets]\n"\
+ "\tcloses specified file on target server\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+/***************************************************************************
+ list info on an open file
+***************************************************************************/
+static void file_fn(const char * pPath, const char * pUser, uint16 perms,
+ uint16 locks, uint32 id)
+{
+ d_printf("\t%-7.1d %-20.20s 0x%-4.2x %-6.1d %s\n",
+ id, pUser, perms, locks, pPath);
+}
+
+static void one_file_fn(const char *pPath, const char *pUser, uint16 perms,
+ uint16 locks, uint32 id)
+{
+ d_printf("File ID %d\n"\
+ "User name %s\n"\
+ "Locks 0x%-4.2x\n"\
+ "Path %s\n"\
+ "Permissions 0x%x\n",
+ id, pUser, locks, pPath, perms);
+}
+
+
+static int rap_file_close(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0) {
+ d_printf("\nMissing fileid of file to close\n\n");
+ return net_rap_file_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetFileClose(cli, atoi(argv[0]));
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_file_info(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0)
+ return net_rap_file_usage(argc, argv);
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetFileGetInfo(cli, atoi(argv[0]), one_file_fn);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_file_user(int argc, const char **argv)
+{
+ if (argc == 0)
+ return net_rap_file_usage(argc, argv);
+
+ d_printf("net rap file user not implemented yet\n");
+ return -1;
+}
+
+int net_rap_file(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"CLOSE", rap_file_close},
+ {"USER", rap_file_user},
+ {"INFO", rap_file_info},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ /* list open files */
+ d_printf(
+ "\nEnumerating open files on remote server:\n\n"\
+ "\n\tFileId Opened by Perms Locks Path \n"\
+ "\t------ --------- ----- ----- ---- \n");
+ ret = cli_NetFileEnum(cli, NULL, NULL, file_fn);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_file_usage);
+}
+
+int net_rap_share_usage(int argc, const char **argv)
+{
+ d_printf(
+ "\nnet [rap] share [misc. options] [targets] \n"\
+ "\tenumerates all exported resources (network shares) "\
+ "on target server\n");
+ d_printf(
+ "\nnet rap share ADD <name=serverpath> [misc. options] [targets]"\
+ "\n\tAdds a share from a server (makes the export active)\n");
+ d_printf(
+ "\nnet rap share DELETE <sharename> [misc. options] [targets]\n"\
+ "\tor"\
+ "\nnet rap share CLOSE <sharename> [misc. options] [targets]"\
+ "\n\tDeletes a share from a server (makes the export inactive)\n");
+ general_rap_usage(argc, argv);
+ d_printf(
+ "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
+ d_printf("\t-M or --maxusers=<num>\t\tmax users allowed for share\n");
+ return -1;
+}
+
+static void long_share_fn(const char *share_name, uint32 type,
+ const char *comment, void *state)
+{
+ d_printf("%-12.12s %-8.8s %-50.50s\n",
+ share_name, share_type[type], comment);
+}
+
+static void share_fn(const char *share_name, uint32 type,
+ const char *comment, void *state)
+{
+ d_printf("%-12.12s\n", share_name);
+}
+
+static int rap_share_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0) {
+ d_printf("\n\nShare name not specified\n");
+ return net_rap_share_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetShareDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_share_add(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ RAP_SHARE_INFO_2 sinfo;
+ char *p;
+ char *sharename;
+
+ if (argc == 0) {
+ d_printf("\n\nShare name not specified\n");
+ return net_rap_share_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ sharename = strdup(argv[0]);
+ p = strchr(sharename, '=');
+ *p = 0;
+ strlcpy(sinfo.share_name, sharename, sizeof(sinfo.share_name));
+ sinfo.reserved1 = '\0';
+ sinfo.share_type = 0;
+ sinfo.comment = opt_comment;
+ sinfo.perms = 0;
+ sinfo.maximum_users = opt_maxusers;
+ sinfo.active_users = 0;
+ sinfo.path = p+1;
+ memset(sinfo.password, '\0', sizeof(sinfo.password));
+ sinfo.reserved2 = '\0';
+
+ ret = cli_NetShareAdd(cli, &sinfo);
+ cli_shutdown(cli);
+ return ret;
+}
+
+
+int net_rap_share(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"DELETE", rap_share_delete},
+ {"CLOSE", rap_share_delete},
+ {"ADD", rap_share_add},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ if (opt_long_list_entries) {
+ d_printf(
+ "\nEnumerating shared resources (exports) on remote server:\n\n"\
+ "\nShare name Type Description\n"\
+ "---------- ---- -----------\n");
+ ret = cli_RNetShareEnum(cli, long_share_fn, NULL);
+ }
+ ret = cli_RNetShareEnum(cli, share_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_share_usage);
+}
+
+
+int net_rap_session_usage(int argc, const char **argv)
+{
+ d_printf(
+ "\nnet rap session [misc. options] [targets]"\
+ "\n\tenumerates all active SMB/CIFS sessions on target server\n");
+ d_printf(
+ "\nnet rap session DELETE <client_name> [misc. options] [targets] \n"\
+ "\tor"\
+ "\nnet rap session CLOSE <client_name> [misc. options] [targets]"\
+ "\n\tDeletes (closes) a session from specified client to server\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+static void list_sessions_func(char *wsname, char *username, uint16 conns,
+ uint16 opens, uint16 users, uint32 sess_time,
+ uint32 idle_time, uint32 user_flags, char *clitype)
+{
+ int hrs = idle_time / 3600;
+ int min = (idle_time / 60) % 60;
+ int sec = idle_time % 60;
+
+ d_printf("\\\\%-18.18s %-20.20s %-18.18s %5d %2.2d:%2.2d:%2.2d\n",
+ wsname, username, clitype, opens, hrs, min, sec);
+}
+
+static void display_session_func(const char *wsname, const char *username,
+ uint16 conns, uint16 opens, uint16 users,
+ uint32 sess_time, uint32 idle_time,
+ uint32 user_flags, const char *clitype)
+{
+ int ihrs = idle_time / 3600;
+ int imin = (idle_time / 60) % 60;
+ int isec = idle_time % 60;
+ int shrs = sess_time / 3600;
+ int smin = (sess_time / 60) % 60;
+ int ssec = sess_time % 60;
+ d_printf("User name %-20.20s\n"\
+ "Computer %-20.20s\n"\
+ "Guest logon %-20.20s\n"\
+ "Client Type %-40.40s\n"\
+ "Sess time %2.2d:%2.2d:%2.2d\n"\
+ "Idle time %2.2d:%2.2d:%2.2d\n",
+ username, wsname,
+ (user_flags&0x0)?"yes":"no", clitype,
+ shrs, smin, ssec, ihrs, imin, isec);
+}
+
+static void display_conns_func(uint16 conn_id, uint16 conn_type, uint16 opens,
+ uint16 users, uint32 conn_time,
+ const char *username, const char *netname)
+{
+ d_printf("%-14.14s %-8.8s %5d\n",
+ netname, share_type[conn_type], opens);
+}
+
+static int rap_session_info(int argc, const char **argv)
+{
+ const char *sessname;
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ if (argc == 0)
+ return net_rap_session_usage(argc, argv);
+
+ sessname = argv[0];
+
+ ret = cli_NetSessionGetInfo(cli, sessname, display_session_func);
+ if (ret < 0) {
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ d_printf("Share name Type # Opens\n-------------------------"\
+ "-----------------------------------------------------\n");
+ ret = cli_NetConnectionEnum(cli, sessname, display_conns_func);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_session_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ if (argc == 0)
+ return net_rap_session_usage(argc, argv);
+
+ ret = cli_NetSessionDel(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_session(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"INFO", rap_session_info},
+ {"DELETE", rap_session_delete},
+ {"CLOSE", rap_session_delete},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ d_printf("Computer User name "\
+ "Client Type Opens Idle time\n"\
+ "------------------------------------------"\
+ "------------------------------------\n");
+ ret = cli_NetSessionEnum(cli, list_sessions_func);
+
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_session_usage);
+}
+
+/****************************************************************************
+list a server name
+****************************************************************************/
+static void display_server_func(const char *name, uint32 m,
+ const char *comment, void * reserved)
+{
+ d_printf("\t%-16.16s %s\n", name, comment);
+}
+
+
+int net_rap_server_usage(int argc, const char **argv)
+{
+ d_printf("net rap server [misc. options] [target]\n\t"\
+ "lists the servers in the specified domain or workgroup.\n");
+ d_printf("\n\tIf domain is not specified, it uses the current"\
+ " domain or workgroup as\n\tthe default.\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+int net_rap_server(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ d_printf("\nEnumerating servers in this domain or workgroup: \n\n"\
+ "\tServer name Server description\n"\
+ "\t------------- ----------------------------\n");
+
+ ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL,
+ display_server_func,NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_domain_usage(int argc, const char **argv)
+{
+ d_printf("net rap domain [misc. options] [target]\n\tlists the"\
+ " domains or workgroups visible on the current network\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+
+int net_rap_domain(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ d_printf("\nEnumerating domains:\n\n"\
+ "\tDomain name Server name of Browse Master\n"\
+ "\t------------- ----------------------------\n");
+
+ ret = cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
+ display_server_func,NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_printq_usage(int argc, const char **argv)
+{
+ d_printf(
+ "net rap printq [misc. options] [targets]\n"\
+ "\tor\n"\
+ "net rap printq list [<queue_name>] [misc. options] [targets]\n"\
+ "\tlists the specified queue and jobs on the target server.\n"\
+ "\tIf the queue name is not specified, all queues are listed.\n\n");
+ d_printf(
+ "net rap printq delete [<queue name>] [misc. options] [targets]\n"\
+ "\tdeletes the specified job number on the target server, or the\n"\
+ "\tprinter queue if no job number is specified\n");
+
+ general_rap_usage(argc, argv);
+ d_printf("\t-j or --jobid=<job id>\t\tjob id\n");
+
+ return -1;
+}
+
+static void enum_queue(const char *queuename, uint16 pri, uint16 start,
+ uint16 until, const char *sep, const char *pproc,
+ const char *dest, const char *qparms,
+ const char *qcomment, uint16 status, uint16 jobcount)
+{
+ d_printf("%-17.17s Queue %5d jobs ",
+ queuename, jobcount);
+
+ switch (status) {
+ case 0:
+ d_printf("*Printer Active*\n");
+ break;
+ case 1:
+ d_printf("*Printer Paused*\n");
+ break;
+ case 2:
+ d_printf("*Printer error*\n");
+ break;
+ case 3:
+ d_printf("*Delete Pending*\n");
+ break;
+ default:
+ d_printf("**UNKNOWN STATUS**\n");
+ }
+}
+
+static void enum_jobs(uint16 jobid, const char *ownername,
+ const char *notifyname, const char *datatype,
+ const char *jparms, uint16 pos, uint16 status,
+ const char *jstatus, uint submitted, uint jobsize,
+ const char *comment)
+{
+ d_printf(" %-23.23s %5d %9d ",
+ ownername, jobid, jobsize);
+ switch (status) {
+ case 0:
+ d_printf("Waiting\n");
+ break;
+ case 1:
+ d_printf("Held in queue\n");
+ break;
+ case 2:
+ d_printf("Spooling\n");
+ break;
+ case 3:
+ d_printf("Printing\n");
+ break;
+ default:
+ d_printf("**UNKNOWN STATUS**\n");
+ }
+}
+
+#define PRINTQ_ENUM_DISPLAY \
+ "Print queues at \\\\%s\n\n"\
+ "Name Job # Size Status\n\n"\
+ "------------------------------------------------------------------"\
+ "-------------\n"
+
+static int rap_printq_info(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0)
+ return net_rap_printq_usage(argc, argv);
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */
+ ret = cli_NetPrintQGetInfo(cli, argv[0], enum_queue, enum_jobs);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_printq_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0)
+ return net_rap_printq_usage(argc, argv);
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_printjob_del(cli, atoi(argv[0]));
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_printq(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ struct functable func[] = {
+ {"INFO", rap_printq_info},
+ {"DELETE", rap_printq_delete},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ d_printf(PRINTQ_ENUM_DISPLAY, cli->desthost); /* list header */
+ ret = cli_NetPrintQEnum(cli, enum_queue, enum_jobs);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_printq_usage);
+}
+
+
+int net_rap_user_usage(int argc, const char **argv)
+{
+ d_printf("\nnet rap user [misc. options] [targets]\n\tList users\n");
+ d_printf("\nnet rap user DELETE <name> [misc. options] [targets]"\
+ "\n\tDelete specified user\n");
+ d_printf("\nnet rap user INFO <name> [misc. options] [targets]"\
+ "\n\tList the domain groups of the specified user\n");
+ d_printf("\nnet rap user ADD <name> [-F user flags] [misc. options]"\
+ " [targets]\n\tAdd specified user\n");
+
+ general_rap_usage(argc, argv);
+ d_printf(
+ "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
+ return -1;
+}
+
+static void user_fn(const char *user_name, const char *comment,
+ const char * home_dir, const char * logon_script,
+ void *state)
+{
+ d_printf("%-21.21s\n", user_name);
+}
+
+static void long_user_fn(const char *user_name, const char *comment,
+ const char * home_dir, const char * logon_script,
+ void *state)
+{
+ d_printf("%-21.21s %-47.47s %-35.35s %35.35s\n",
+ user_name, comment, home_dir, logon_script);
+}
+
+static void group_member_fn(const char *user_name, void *state)
+{
+ d_printf("%-21.21s\n", user_name);
+}
+
+static int rap_user_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc == 0) {
+ d_printf("\n\nUser name not specified\n");
+ return net_rap_user_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetUserDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_user_add(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ RAP_USER_INFO_1 userinfo;
+
+ if (argc == 0) {
+ d_printf("\n\nUser name not specified\n");
+ return net_rap_user_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ safe_strcpy(userinfo.user_name, argv[0], sizeof(userinfo.user_name));
+ if (opt_flags == -1)
+ opt_flags = 0x21;
+
+ userinfo.userflags = opt_flags;
+ userinfo.reserved1 = '\0';
+ userinfo.comment = opt_comment;
+ userinfo.priv = 1;
+ userinfo.home_dir = NULL;
+ userinfo.logon_script = NULL;
+
+ ret = cli_NetUserAdd(cli, &userinfo);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_user_info(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0) {
+ d_printf("\n\nUser name not specified\n");
+ return net_rap_user_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetUserGetGroups(cli, argv[0], group_member_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_user(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"ADD", rap_user_add},
+ {"INFO", rap_user_info},
+ {"DELETE", rap_user_delete},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+ if (opt_long_list_entries) {
+ d_printf(
+ "\nListing users on remote server:\n\n"\
+ "\nUser name Description "\
+ "Home Directory Profile Directory"\
+ "\n--------- ----------- "\
+ "-------------- -----------------\n");
+ ret = cli_RNetUserEnum(cli, long_user_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+ ret = cli_RNetUserEnum(cli, user_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_user_usage);
+}
+
+
+int net_rap_group_usage(int argc, const char **argv)
+{
+ d_printf("net rap group [misc. options] [targets]"\
+ "\n\tList user groups\n");
+ d_printf("\nnet rap group DELETE <name> [misc. options] [targets]"\
+ "\n\tDelete specified group\n");
+ d_printf("\nnet rap group ADD <name> [-C comment] [misc. options]"\
+ " [targets]\n\tCreate specified group\n");
+
+ general_rap_usage(argc, argv);
+ d_printf(
+ "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
+ return -1;
+}
+
+static void long_group_fn(const char *group_name, const char *comment,
+ void *state)
+{
+ d_printf("%-21.21s %-50.50s\n", group_name, comment);
+}
+
+static void group_fn(const char *group_name, const char *comment, void *state)
+{
+ d_printf("%-21.21s\n", group_name);
+}
+
+static int rap_group_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0) {
+ d_printf("\n\nGroup name not specified\n");
+ return net_rap_group_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetGroupDelete(cli, argv[0]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_group_add(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ RAP_GROUP_INFO_1 grinfo;
+
+ if (argc == 0) {
+ d_printf("\n\nGroup name not specified\n");
+ return net_rap_group_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ /* BB check for length 21 or smaller explicitly ? BB */
+ safe_strcpy(grinfo.group_name, argv[0], sizeof(grinfo.group_name));
+ grinfo.reserved1 = '\0';
+ grinfo.comment = opt_comment;
+
+ ret = cli_NetGroupAdd(cli, &grinfo);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_group(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"ADD", rap_group_add},
+ {"DELETE", rap_group_delete},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+ if (opt_long_list_entries) {
+ d_printf("Group name Comment\n");
+ d_printf("-----------------------------\n");
+ ret = cli_RNetGroupEnum(cli, long_group_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+ ret = cli_RNetGroupEnum(cli, group_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_group_usage);
+}
+
+int net_rap_groupmember_usage(int argc, const char **argv)
+{
+ d_printf(
+ "net rap groupmember LIST <group> [misc. options] [targets]"\
+ "\n\t Enumerate users in a group\n"\
+ "\nnet rap groupmember DELETE <group> <user> [misc. options] "\
+ "[targets]\n\t Delete sepcified user from specified group\n"\
+ "\nnet rap groupmember ADD <group> <user> [misc. options] [targets]"\
+ "\n\t Add specified user to specified group\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+
+static int rap_groupmember_add(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc != 2) {
+ d_printf("\n\nGroup or user name not specified\n");
+ return net_rap_groupmember_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetGroupAddUser(cli, argv[0], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_groupmember_delete(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc != 2) {
+ d_printf("\n\nGroup or user name not specified\n");
+ return net_rap_groupmember_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetGroupDelUser(cli, argv[0], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+static int rap_groupmember_list(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+ if (argc == 0) {
+ d_printf("\n\nGroup name not specified\n");
+ return net_rap_groupmember_usage(argc, argv);
+ }
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ ret = cli_NetGroupGetUsers(cli, argv[0], group_member_fn, NULL );
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_groupmember(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"ADD", rap_groupmember_add},
+ {"LIST", rap_groupmember_list},
+ {"DELETE", rap_groupmember_delete},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_rap_groupmember_usage);
+}
+
+int net_rap_validate_usage(int argc, const char **argv)
+{
+ d_printf("net rap validate <username> [password]\n"\
+ "\tValidate user and password to check whether they"\
+ " can access target server or domain\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+int net_rap_validate(int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+int net_rap_service_usage(int argc, const char **argv)
+{
+ d_printf("net rap service [misc. options] [targets] \n"\
+ "\tlists all running service daemons on target server\n");
+ d_printf("\nnet rap service START <name> [service startup arguments]"\
+ " [misc. options] [targets]"\
+ "\n\tStart named service on remote server\n");
+ d_printf("\nnet rap service STOP <name> [misc. options] [targets]\n"\
+ "\n\tStop named service on remote server\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+static int rap_service_start(int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+static int rap_service_stop(int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+int net_rap_service(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"START", rap_service_start},
+ {"STOP", rap_service_stop},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ struct cli_state *cli;
+ int ret;
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ if (opt_long_list_entries) {
+ d_printf("Service name Comment\n");
+ d_printf("-----------------------------\n");
+ ret = cli_RNetServiceEnum(cli, long_group_fn, NULL);
+ }
+ ret = cli_RNetServiceEnum(cli, group_fn, NULL);
+ cli_shutdown(cli);
+ return ret;
+ }
+
+ return net_run_function(argc, argv, func, net_rap_service_usage);
+}
+
+int net_rap_password_usage(int argc, const char **argv)
+{
+ d_printf(
+ "net rap password <user> <oldpwo> <newpw> [misc. options] [target]\n"\
+ "\tchanges the password for the specified user at target\n");
+
+ return -1;
+}
+
+
+int net_rap_password(int argc, const char **argv)
+{
+ struct cli_state *cli;
+ int ret;
+
+ if (argc < 3)
+ return net_rap_password_usage(argc, argv);
+
+ if (!(cli = net_make_ipc_connection(0)))
+ return -1;
+
+ /* BB Add check for password lengths? */
+ ret = cli_oem_change_password(cli, argv[0], argv[2], argv[1]);
+ cli_shutdown(cli);
+ return ret;
+}
+
+int net_rap_admin_usage(int argc, const char **argv)
+{
+ d_printf(
+ "net rap admin <remote command> [cmd args [env]] [misc. options] [targets]"\
+ "\n\texecutes a remote command on an os/2 target server\n");
+
+ return -1;
+}
+
+
+int net_rap_admin(int argc, const char **argv)
+{
+ return errmsg_not_implemented();
+}
+
+/* The help subsystem for the RAP subcommand */
+
+int net_rap_usage(int argc, const char **argv)
+{
+ d_printf(" net rap domain \tto list domains \n"\
+ " net rap file \tto list open files on a server \n"\
+ " net rap group \tto list user groups \n"\
+ " net rap groupmember to list users in a group \n"\
+ " net rap password\t to change the password of a user\n"\
+ " net rap printq \tto list the print queues on a server\n"\
+ " net rap server \tto list servers in a domain\n"\
+ " net rap session \tto list clients with open sessions to a server\n"\
+ " net rap share \tto list shares exported by a server\n"\
+ " net rap user \tto list users\n"\
+ " net rap validate \tto check whether a user and the corresponding password are valid\n"\
+ " net rap help\n"\
+ "\nType \"net help <option>\" to get more information on that option\n\n");
+
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+int rap_help_usage(int argc, const char **argv)
+{
+ d_printf("\n"\
+ "Usage: net rap help <function>\n"\
+ "\n"\
+ "Valid functions are:\n"\
+ " FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP\n"\
+ " VALIDATE GROUPMEMBER ADMIN SERVICE PASSWORD\n");
+ return -1;
+}
+
+/*
+ handle "net help rap *" subcommands
+*/
+static int net_rap_help(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"FILE", net_rap_file_usage},
+ {"SHARE", net_rap_share_usage},
+ {"SESSION", net_rap_session_usage},
+ {"SERVER", net_rap_server_usage},
+ {"DOMAIN", net_rap_domain_usage},
+ {"PRINTQ", net_rap_printq_usage},
+ {"USER", net_rap_user_usage},
+ {"GROUP", net_rap_group_usage},
+ {"VALIDATE", net_rap_validate_usage},
+ {"GROUPMEMBER", net_rap_groupmember_usage},
+ {"ADMIN", net_rap_admin_usage},
+ {"SERVICE", net_rap_service_usage},
+ {"PASSWORD", net_rap_password_usage},
+ {NULL, NULL}};
+
+ return net_run_function(argc, argv, func, rap_help_usage);
+}
+
+/* Entry-point for all the RAP functions. */
+
+int net_rap(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"FILE", net_rap_file},
+ {"SHARE", net_rap_share},
+ {"SESSION", net_rap_session},
+ {"SERVER", net_rap_server},
+ {"DOMAIN", net_rap_domain},
+ {"PRINTQ", net_rap_printq},
+ {"USER", net_rap_user},
+ {"GROUP", net_rap_group},
+ {"VALIDATE", net_rap_validate},
+ {"GROUPMEMBER", net_rap_groupmember},
+ {"ADMIN", net_rap_admin},
+ {"SERVICE", net_rap_service},
+ {"PASSWORD", net_rap_password},
+ {"HELP", net_rap_help},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_rap_usage);
+}
+
diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c
new file mode 100644
index 00000000000..97a1a1d342b
--- /dev/null
+++ b/source/utils/net_rpc.c
@@ -0,0 +1,261 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "includes.h"
+#include "../utils/net.h"
+
+
+typedef NTSTATUS (*rpc_command_fn)(const DOM_SID *, struct cli_state *, TALLOC_CTX *, int, const char **);
+
+
+static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli)
+{
+ DOM_SID *domain_sid;
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_OK;
+ uint32 info_class = 5;
+ fstring domain_name;
+ TALLOC_CTX *mem_ctx;
+
+ if (!(domain_sid = malloc(sizeof(DOM_SID)))){
+ DEBUG(0,("fetch_domain_sid: malloc returned NULL!\n"));
+ goto error;
+ }
+
+ if (!(mem_ctx=talloc_init()))
+ {
+ DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n"));
+ goto error;
+ }
+
+
+ if (!cli_nt_session_open (cli, PIPE_LSARPC)) {
+ fprintf(stderr, "could not initialise lsa pipe\n");
+ goto error;
+ }
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class,
+ domain_name, domain_sid);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto error;
+ }
+
+ cli_lsa_close(cli, mem_ctx, &pol);
+ cli_nt_session_close(cli);
+ talloc_destroy(mem_ctx);
+
+ return domain_sid;
+
+ error:
+ fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ fprintf(stderr, "error: %s\n", get_nt_error_msg(result));
+ }
+
+ exit(1);
+}
+
+
+static int run_rpc_command(const char *pipe_name, int conn_flags,
+ rpc_command_fn fn,
+ int argc, const char **argv)
+{
+ struct cli_state *cli = net_make_ipc_connection(conn_flags);
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS nt_status;
+ DOM_SID *domain_sid = net_get_remote_domain_sid(cli);
+ /* Create mem_ctx */
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0, ("talloc_init() failed\n"));
+ cli_shutdown(cli);
+ return -1;
+ }
+
+ if (!cli_nt_session_open(cli, pipe_name)) {
+ DEBUG(0, ("Could not initialise samr pipe\n"));
+ }
+
+ nt_status = fn(domain_sid, cli, mem_ctx, argc, argv);
+
+ DEBUG(5, ("rpc command function returned %s\n", get_nt_error_msg(nt_status)));
+
+ if (cli->nt_pipe_fnum)
+ cli_nt_session_close(cli);
+
+ talloc_destroy(mem_ctx);
+
+ return (!NT_STATUS_IS_OK(nt_status));
+}
+
+static NTSTATUS rpc_user_add_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv) {
+
+ POLICY_HND connect_pol, domain_pol, user_pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ const char *acct_name;
+ uint16 acb_info;
+ uint32 unknown, user_rid;
+
+ if (argc != 1) {
+ d_printf("Usage: net rpc user add username\n");
+ return NT_STATUS_OK;
+ }
+
+ acct_name = argv[0];
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Get domain policy handle */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ domain_sid, &domain_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ /* Create domain user */
+
+ acb_info = ACB_NORMAL;
+ unknown = 0xe005000b; /* No idea what this is - a permission mask? */
+
+ result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
+ acct_name, acb_info, unknown,
+ &user_pol, &user_rid);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ done:
+ return result;
+}
+
+static NTSTATUS rpc_changetrustpw_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv) {
+
+ return trust_pw_find_change_and_store_it(cli, mem_ctx, opt_target_workgroup);
+}
+
+static int rpc_changetrustpw(int argc, const char **argv)
+{
+ return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_changetrustpw_internals,
+ argc, argv);
+}
+
+static NTSTATUS rpc_join_oldstyle_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv) {
+
+ extern pstring global_myname;
+ fstring trust_passwd;
+ unsigned char orig_trust_passwd_hash[16];
+
+ fstrcpy(trust_passwd, global_myname);
+ strlower(trust_passwd);
+ E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
+
+ return trust_pw_change_and_store_it(cli, mem_ctx, orig_trust_passwd_hash);
+}
+
+static int rpc_join_oldstyle(int argc, const char **argv)
+{
+ return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_join_oldstyle_internals,
+ argc, argv);
+}
+
+static int rpc_join_usage(int argc, const char **argv)
+{
+ d_printf(" net rpc join \t to join a domain with admin username & password\n");
+ d_printf(" net rpc join oldstyle \t to join a domain created in server manager\n");
+ return -1;
+}
+
+static int rpc_join(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"oldstyle", rpc_join_oldstyle},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ return net_rpc_join(argc, argv);
+ }
+
+ return net_run_function(argc, argv, func, rpc_join_usage);
+}
+
+static int rpc_user_add(int argc, const char **argv)
+{
+ return run_rpc_command(PIPE_SAMR, 0, rpc_user_add_internals,
+ argc, argv);
+}
+
+static int rpc_user_usage(int argc, const char **argv)
+{
+ d_printf(" net rpc user add \t to add a user\n");
+ return -1;
+}
+
+static int rpc_user(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"add", rpc_user_add},
+ {NULL, NULL}
+ };
+
+ if (argc == 0) {
+ rpc_user_usage(argc, argv);
+ }
+
+ return net_run_function(argc, argv, func, rpc_user_usage);
+}
+
+int net_rpc_usage(int argc, const char **argv)
+{
+ d_printf(" net rpc join \tto join a domain \n");
+ d_printf(" net rpc user \tto add, delete and list users\n");
+ d_printf(" net rpc changetrustpw \tto change the trust account password\n");
+ return -1;
+}
+
+int net_rpc(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"join", rpc_join},
+ {"user", rpc_user},
+ {"changetrustpw", rpc_changetrustpw},
+ {NULL, NULL}
+ };
+ return net_run_function(argc, argv, func, net_rpc_usage);
+}
diff --git a/source/utils/net_rpc_join.c b/source/utils/net_rpc_join.c
new file mode 100644
index 00000000000..16b0ccbaa80
--- /dev/null
+++ b/source/utils/net_rpc_join.c
@@ -0,0 +1,296 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ Distributed SMB/CIFS Server Management Utility
+ Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "includes.h"
+#include "../utils/net.h"
+
+/* Macro for checking RPC error codes to make things more readable */
+
+#define CHECK_RPC_ERR(rpc, msg) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, (msg ": %s\n", get_nt_error_msg(result))); \
+ goto done; \
+ }
+
+#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, debug_args); \
+ goto done; \
+ }
+
+/*********************************************************
+Join a domain using the administrator username and password
+**********************************************************/
+
+int net_rpc_join(int argc, const char **argv)
+{
+
+ extern pstring global_myname;
+
+ /* libsmb variables */
+
+ struct cli_state *cli;
+ fstring acct_name;
+ TALLOC_CTX *mem_ctx;
+ uint32 acb_info;
+
+ /* rpc variables */
+
+ POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
+ DOM_SID domain_sid;
+ uint32 user_rid;
+
+ /* Password stuff */
+
+ char *clear_trust_password = NULL;
+ fstring ucs2_trust_password;
+ int ucs2_pw_len;
+ uchar stored_md4_trust_password[16];
+ uchar pwbuf[516], sess_key[16];
+ SAM_USERINFO_CTR ctr;
+ SAM_USER_INFO_24 p24;
+ SAM_USER_INFO_10 p10;
+
+ /* Misc */
+
+ NTSTATUS result;
+ int retval = 1;
+ fstring domain;
+ uint32 num_rids, *name_types, *user_rids;
+ uint32 flags = 0x3e8;
+ char *names;
+
+ /* Connect to remote machine */
+
+ if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC)))
+ return 1;
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0, ("Could not initialise talloc context\n"));
+ goto done;
+ }
+
+ /* Fetch domain sid */
+
+ if (!cli_nt_session_open(cli, PIPE_LSARPC)) {
+ DEBUG(0, ("Error connecting to SAM pipe\n"));
+ goto done;
+ }
+
+
+ CHECK_RPC_ERR(cli_lsa_open_policy(cli, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &lsa_pol),
+ "error opening lsa policy handle");
+
+ CHECK_RPC_ERR(cli_lsa_query_info_policy(cli, mem_ctx, &lsa_pol,
+ 5, domain, &domain_sid),
+ "error querying info policy");
+
+ cli_lsa_close(cli, mem_ctx, &lsa_pol);
+
+ cli_nt_session_close(cli); /* Done with this pipe */
+
+ /* Create domain user */
+ if (!cli_nt_session_open(cli, PIPE_SAMR)) {
+ DEBUG(0, ("Error connecting to SAM pipe\n"));
+ goto done;
+ }
+
+ CHECK_RPC_ERR(cli_samr_connect(cli, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &sam_pol),
+ "could not connect to SAM database");
+
+
+ CHECK_RPC_ERR(cli_samr_open_domain(cli, mem_ctx, &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &domain_sid, &domain_pol),
+ "could not open domain");
+
+ /* Create domain user */
+ fstrcpy(acct_name, global_myname);
+ fstrcat(acct_name, "$");
+ strlower(acct_name);
+
+ acb_info = (lp_server_role() == ROLE_DOMAIN_BDC) ? ACB_SVRTRUST : ACB_WSTRUST;
+
+ result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
+ acct_name, acb_info,
+ 0xe005000b, &user_pol,
+ &user_rid);
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
+ d_printf("Create of workstation account failed\n");
+
+ /* If NT_STATUS_ACCESS_DENIED then we have a valid
+ username/password combo but the user does not have
+ administrator access. */
+
+ if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
+ d_printf("User specified does not have administrator privileges\n");
+
+ goto done;
+ }
+
+ /* We *must* do this.... don't ask... */
+
+ if (NT_STATUS_IS_OK(result))
+ cli_samr_close(cli, mem_ctx, &user_pol);
+
+ names = (char *)&acct_name[0];
+
+ CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli, mem_ctx,
+ &domain_pol, flags,
+ 1, &names, &num_rids,
+ &user_rids, &name_types),
+ ("error looking up rid for user %s: %s\n",
+ acct_name, get_nt_error_msg(result)));
+
+ if (name_types[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account\n", acct_name));
+ goto done;
+ }
+
+ user_rid = user_rids[0];
+
+ /* Open handle on user */
+
+ CHECK_RPC_ERR_DEBUG(
+ cli_samr_open_user(cli, mem_ctx, &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ user_rid, &user_pol),
+ ("could not re-open existing user %s: %s\n",
+ acct_name, get_nt_error_msg(result)));
+
+ /* Create a random machine account password */
+
+ {
+ char *str;
+ str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ clear_trust_password = strdup(str);
+ }
+
+ ucs2_pw_len = push_ucs2(NULL, ucs2_trust_password,
+ clear_trust_password,
+ sizeof(ucs2_trust_password), 0);
+
+ encode_pw_buffer((char *)pwbuf, ucs2_trust_password,
+ ucs2_pw_len);
+
+ /* Set password on machine account */
+
+ ZERO_STRUCT(ctr);
+ ZERO_STRUCT(p24);
+
+ init_sam_user_info24(&p24, (char *)pwbuf,24);
+
+ ctr.switch_value = 24;
+ ctr.info.id24 = &p24;
+
+ /* I don't think this is quite the right place for this
+ calculation. It should be moved somewhere where the credentials
+ are calculated. )-: */
+
+ mdfour(sess_key, cli->pwd.smb_nt_pwd, 16);
+
+ CHECK_RPC_ERR(cli_samr_set_userinfo(cli, mem_ctx, &user_pol, 24,
+ sess_key, &ctr),
+ "error setting trust account password");
+
+ /* Why do we have to try to (re-)set the ACB to be the same as what
+ we passed in the samr_create_dom_user() call? When a NT
+ workstation is joined to a domain by an administrator the
+ acb_info is set to 0x80. For a normal user with "Add
+ workstations to the domain" rights the acb_info is 0x84. I'm
+ not sure whether it is supposed to make a difference or not. NT
+ seems to cope with either value so don't bomb out if the set
+ userinfo2 level 0x10 fails. -tpot */
+
+ ZERO_STRUCT(ctr);
+ ctr.switch_value = 0x10;
+ ctr.info.id10 = &p10;
+
+ init_sam_user_info10(&p10, acb_info);
+
+ /* Ignoring the return value is necessary for joining a domain
+ as a normal user with "Add workstation to domain" privilege. */
+
+ result = cli_samr_set_userinfo2(cli, mem_ctx, &user_pol, 0x10,
+ sess_key, &ctr);
+
+ /* Now store the secret in the secrets database */
+
+ strupper(domain);
+
+ if (!secrets_store_domain_sid(domain, &domain_sid)) {
+ DEBUG(0, ("error storing domain sid for %s\n", domain));
+ goto done;
+ }
+
+ if (!secrets_store_machine_password(clear_trust_password)) {
+ DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
+ }
+
+ /* Now check the whole process from top-to-bottom */
+
+ cli_samr_close(cli, mem_ctx, &user_pol);
+
+ cli_nt_session_close(cli); /* Done with this pipe */
+
+ if (!cli_nt_session_open(cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Error connecting to NETLOGON pipe\n"));
+ goto done;
+ }
+
+ if (!secrets_fetch_trust_account_password(domain,
+ stored_md4_trust_password, NULL)) {
+ DEBUG(0, ("Could not reterive secrets we just stored!"));
+ goto done;
+ }
+
+ CHECK_RPC_ERR(new_cli_nt_setup_creds(cli, stored_md4_trust_password),
+ "error in domain join verification");
+
+ retval = 0; /* Success! */
+
+done:
+ /* Close down pipe - this will clean up open policy handles */
+
+ if (cli->nt_pipe_fnum)
+ cli_nt_session_close(cli);
+
+ /* Display success or failure */
+
+ if (retval != 0) {
+ trust_password_delete(domain);
+ fprintf(stderr,"Unable to join domain %s.\n",domain);
+ } else {
+ printf("Joined domain %s.\n",domain);
+ }
+
+ cli_shutdown(cli);
+
+ SAFE_FREE(clear_trust_password);
+
+ return retval;
+}
diff --git a/source/utils/net_time.c b/source/utils/net_time.c
new file mode 100644
index 00000000000..dea1bcd6776
--- /dev/null
+++ b/source/utils/net_time.c
@@ -0,0 +1,182 @@
+/*
+ Samba Unix/Linux SMB client library
+ Version 3.0
+ net time command
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "includes.h"
+#include "../utils/net.h"
+
+
+/*
+ return the time on a server. This does not require any authentication
+*/
+static time_t cli_servertime(const char *host, struct in_addr *ip, int *zone)
+{
+ struct nmb_name calling, called;
+ time_t ret = 0;
+ extern pstring global_myname;
+ struct cli_state *cli = NULL;
+
+ cli = cli_initialise(NULL);
+ if (!cli) goto done;
+
+ if (!cli_connect(cli, host, ip)) {
+ fprintf(stderr,"Can't contact server\n");
+ goto done;
+ }
+
+ make_nmb_name(&calling, global_myname, 0x0);
+ if (host) {
+ make_nmb_name(&called, host, 0x20);
+ } else {
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ fprintf(stderr,"Session request failed\n");
+ goto done;
+ }
+ if (!cli_negprot(cli)) {
+ fprintf(stderr,"Protocol negotiation failed\n");
+ goto done;
+ }
+
+ ret = cli->servertime;
+ if (zone) *zone = cli->serverzone;
+
+done:
+ if (cli) cli_shutdown(cli);
+ return ret;
+}
+
+/* find the servers time on the opt_host host */
+static time_t nettime(int *zone)
+{
+ extern BOOL opt_have_ip;
+ extern struct in_addr opt_dest_ip;
+ extern char *opt_host;
+ return cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, zone);
+}
+
+/* return a time as a string ready to be passed to /bin/date */
+static char *systime(time_t t)
+{
+ static char s[100];
+ struct tm *tm;
+
+ tm = localtime(&t);
+
+ snprintf(s, sizeof(s), "%02d%02d%02d%02d%04d.%02d",
+ tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_year + 1900, tm->tm_sec);
+ return s;
+}
+
+int net_time_usage(int argc, const char **argv)
+{
+ d_printf(
+"net time\n\tdisplays time on a server\n\n"\
+"net time system\n\tdisplays time on a server in a format ready for /bin/date\n\n"\
+"net time set\n\truns /bin/date with the time from the server\n\n"\
+"net time zone\n\tdisplays the timezone in hours from GMT on the remote computer\n\n"\
+"\n");
+ general_rap_usage(argc, argv);
+ return -1;
+}
+
+/* try to set the system clock using /bin/date */
+static int net_time_set(int argc, const char **argv)
+{
+ time_t t = nettime(NULL);
+ char *cmd;
+
+ if (t == 0) return -1;
+
+ /* yes, I know this is cheesy. Use "net time system" if you want to
+ roll your own. I'm putting this in as it works on a large number
+ of systems and the user has a choice in whether its used or not */
+ asprintf(&cmd, "/bin/date %s", systime(t));
+ system(cmd);
+ free(cmd);
+
+ return 0;
+}
+
+/* display the time on a remote box in a format ready for /bin/date */
+static int net_time_system(int argc, const char **argv)
+{
+ time_t t = nettime(NULL);
+
+ if (t == 0) return -1;
+
+ printf("%s\n", systime(t));
+
+ return 0;
+}
+
+/* display the time on a remote box in a format ready for /bin/date */
+static int net_time_zone(int argc, const char **argv)
+{
+ int zone = 0;
+ time_t t;
+
+ t = nettime(&zone);
+
+ if (t == 0) return -1;
+
+ zone /= 60;
+
+ if (zone % 60 == 0) {
+ printf("%+d\n", -zone / 60);
+ } else {
+ printf("%+.1f\n", ((double)-zone) / 60);
+ }
+
+ return 0;
+}
+
+/* display or set the time on a host */
+int net_time(int argc, const char **argv)
+{
+ time_t t;
+ extern BOOL opt_have_ip;
+ extern struct in_addr opt_dest_ip;
+ extern char *opt_host;
+ struct functable func[] = {
+ {"SYSTEM", net_time_system},
+ {"SET", net_time_set},
+ {"ZONE", net_time_zone},
+ {NULL, NULL}
+ };
+
+ if (!opt_host && !opt_have_ip) {
+ d_printf("You must specify a hostname or IP\n");
+ return -1;
+ }
+
+ if (argc != 0) {
+ return net_run_function(argc, argv, func, net_time_usage);
+ }
+
+ /* default - print the time */
+ t = cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, NULL);
+ if (t == 0) return -1;
+
+ d_printf("%s", ctime(&t));
+ return 0;
+}
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index aa431733322..5b22872cb37 100644
--- a/source/utils/nmblookup.c
+++ b/source/utils/nmblookup.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT client - used to lookup netbios names
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,44 +20,33 @@
*/
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
+#define NO_SYSLOG
#include "includes.h"
-#include "nameserv.h"
-
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-
-extern struct in_addr bcast_ip;
-extern pstring myhostname;
+static BOOL use_bcast = True;
static BOOL got_bcast = False;
-
-int ServerFD= -1;
+static struct in_addr bcast_addr;
+static BOOL recursion_desired = False;
+static BOOL translate_addresses = False;
+static int ServerFD= -1;
+static int RootPort = False;
+static BOOL find_status=False;
/****************************************************************************
open the socket communication
**************************************************************************/
static BOOL open_sockets(void)
{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
- ServerFD = open_socket_in(SOCK_DGRAM, 0,3);
+ ServerFD = open_socket_in( SOCK_DGRAM,
+ (RootPort ? 137 : 0),
+ (RootPort ? 0 : 3),
+ interpret_addr(lp_socket_address()), True );
if (ServerFD == -1)
return(False);
- set_socket_options(ServerFD,"SO_BROADCAST");
+ set_socket_options( ServerFD, "SO_BROADCAST" );
DEBUG(3, ("Socket opened.\n"));
return True;
@@ -65,43 +54,128 @@ static BOOL open_sockets(void)
/****************************************************************************
- initialise connect, service and file structs
+usage on the program
****************************************************************************/
-static BOOL init_structs(void )
+static void usage(void)
{
- struct in_addr myip;
-
- if (!get_myname(myhostname,&myip))
- return(False);
-
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip2;
-
- ip0 = myip;
-
- if (!got_bcast) {
- get_broadcast(&ip0,&bcast_ip,&ip2);
+ d_printf("Usage: nmblookup [-M] [-B bcast address] [-d debuglevel] name\n");
+ d_printf("Version %s\n",VERSION);
+ d_printf("\t-d debuglevel set the debuglevel\n");
+ d_printf("\t-B broadcast address the address to use for broadcasts\n");
+ d_printf("\t-U unicast address the address to use for unicast\n");
+ d_printf("\t-M searches for a master browser\n");
+ d_printf("\t-R set recursion desired in packet\n");
+ d_printf("\t-S lookup node status as well\n");
+ d_printf("\t-T translate IP addresses into names\n");
+ d_printf("\t-r Use root port 137 (Win95 only replies to this)\n");
+ d_printf("\t-A Do a node status on <name> as an IP Address\n");
+ d_printf("\t-i NetBIOS scope Use the given NetBIOS scope for name queries\n");
+ d_printf("\t-s smb.conf file Use the given path to the smb.conf file\n");
+ d_printf("\t-h Print this help message.\n");
+ d_printf("\n If you specify -M and name is \"-\", nmblookup looks up __MSBROWSE__<01>\n");
+ d_printf("\n");
+}
- DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip)));
- }
- }
+/****************************************************************************
+turn a node status flags field into a string
+****************************************************************************/
+static char *node_status_flags(unsigned char flags)
+{
+ static fstring ret;
+ fstrcpy(ret,"");
+
+ fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
+ if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
+ if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
+ if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
+ if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
+ if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
+ if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
+ if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
+ if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
+
+ return ret;
+}
- return True;
+/****************************************************************************
+do a node status query
+****************************************************************************/
+static void do_node_status(int fd, char *name, int type, struct in_addr ip)
+{
+ struct nmb_name nname;
+ int count, i, j;
+ struct node_status *status;
+ fstring cleanname;
+
+ d_printf("Looking up status of %s\n",inet_ntoa(ip));
+ make_nmb_name(&nname, name, type);
+ status = node_status_query(fd,&nname,ip, &count);
+ if (status) {
+ for (i=0;i<count;i++) {
+ fstrcpy(cleanname, status[i].name);
+ for (j=0;cleanname[j];j++) {
+ if (!isprint((int)cleanname[j])) cleanname[j] = '.';
+ }
+ d_printf("\t%-15s <%02x> - %s\n",
+ cleanname,status[i].type,
+ node_status_flags(status[i].flags));
+ }
+ SAFE_FREE(status);
+ }
+ d_printf("\n");
}
+
/****************************************************************************
-usage on the program
+send out one query
****************************************************************************/
-static void usage(void)
+static BOOL query_one(char *lookup, unsigned int lookup_type)
{
- printf("Usage: nmblookup [-M] [-B bcast address] [-d debuglevel] name\n");
- printf("Version %s\n",VERSION);
- printf("\t-d debuglevel set the debuglevel\n");
- printf("\t-B broadcast address the address to use for broadcasts\n");
- printf("\t-M searches for a master browser\n");
- printf("\t-S lookup node status as well\n");
- printf("\n");
+ int j, count;
+ struct in_addr *ip_list=NULL;
+
+ if (got_bcast) {
+ d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr));
+ ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
+ use_bcast?True:recursion_desired,
+ bcast_addr,&count);
+ } else {
+ struct in_addr *bcast;
+ for (j=iface_count() - 1;
+ !ip_list && j >= 0;
+ j--) {
+ bcast = iface_n_bcast(j);
+ d_printf("querying %s on %s\n",
+ lookup, inet_ntoa(*bcast));
+ ip_list = name_query(ServerFD,lookup,lookup_type,
+ use_bcast,
+ use_bcast?True:recursion_desired,
+ *bcast,&count);
+ }
+ }
+
+ if (!ip_list) return False;
+
+ for (j=0;j<count;j++) {
+ if (translate_addresses) {
+ struct hostent *host = gethostbyaddr((char *)&ip_list[j], sizeof(ip_list[j]), AF_INET);
+ if (host) {
+ d_printf("%s, ", host -> h_name);
+ }
+ }
+ d_printf("%s %s<%02x>\n",inet_ntoa(ip_list[j]),lookup, lookup_type);
+ }
+
+ /* We can only do find_status if the ip address returned
+ was valid - ie. name_query returned true.
+ */
+ if (find_status) {
+ do_node_status(ServerFD, lookup, lookup_type, ip_list[0]);
+ }
+
+ safe_free(ip_list);
+
+ return (ip_list != NULL);
}
@@ -111,50 +185,68 @@ static void usage(void)
int main(int argc,char *argv[])
{
int opt;
- unsigned int lookup_type = 0x20;
+ unsigned int lookup_type = 0x0;
pstring lookup;
extern int optind;
extern char *optarg;
BOOL find_master=False;
- BOOL find_status=False;
int i;
-
+ BOOL lookup_by_ip = False;
+ int commandline_debuglevel = -2;
+
DEBUGLEVEL = 1;
*lookup = 0;
- TimeInit();
-
setup_logging(argv[0],True);
- charset_initialise();
-
- while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF)
+ while ((opt = getopt(argc, argv, "d:B:U:i:s:SMrhART")) != EOF)
switch (opt)
{
case 'B':
- {
- unsigned long a = interpret_addr(optarg);
- putip((char *)&bcast_ip,(char *)&a);
- got_bcast = True;
- }
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = True;
break;
- case 'i':
- strcpy(scope,optarg);
- strupper(scope);
+ case 'U':
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = False;
+ break;
+ case 'T':
+ translate_addresses = !translate_addresses;
break;
+ case 'i':
+ {
+ extern pstring global_scope;
+ pstrcpy(global_scope,optarg);
+ strupper(global_scope);
+ }
+ break;
case 'M':
find_master = True;
break;
case 'S':
find_status = True;
break;
+ case 'R':
+ recursion_desired = True;
+ break;
case 'd':
- DEBUGLEVEL = atoi(optarg);
+ commandline_debuglevel = DEBUGLEVEL = atoi(optarg);
+ break;
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
break;
+ case 'r':
+ RootPort = True;
+ break;
case 'h':
usage();
exit(0);
break;
+ case 'A':
+ lookup_by_ip = True;
+ break;
default:
usage();
exit(1);
@@ -165,53 +257,58 @@ int main(int argc,char *argv[])
exit(1);
}
- init_structs();
- if (!open_sockets()) return(1);
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
+ }
- DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip)));
+ /*
+ * Ensure we reset DEBUGLEVEL if someone specified it
+ * on the command line.
+ */
+ if(commandline_debuglevel != -2)
+ DEBUGLEVEL = commandline_debuglevel;
+
+ load_interfaces();
+ if (!open_sockets()) return(1);
for (i=optind;i<argc;i++)
- {
- BOOL bcast = True;
- int retries = 2;
+ {
char *p;
struct in_addr ip;
- strcpy(lookup,argv[i]);
+ fstrcpy(lookup,argv[i]);
+
+ if(lookup_by_ip)
+ {
+ fstrcpy(lookup,"*");
+ ip = *interpret_addr2(argv[i]);
+ do_node_status(ServerFD, lookup, lookup_type, ip);
+ continue;
+ }
if (find_master) {
if (*lookup == '-') {
- strcpy(lookup,"\01\02__MSBROWSE__\02");
+ fstrcpy(lookup,"\01\02__MSBROWSE__\02");
lookup_type = 1;
} else {
lookup_type = 0x1d;
}
}
- p = strchr(lookup,'#');
-
+ p = strchr_m(lookup,'#');
if (p) {
- *p = 0;
- sscanf(p+1,"%x",&lookup_type);
- bcast = False;
- retries = 1;
+ *p = '\0';
+ sscanf(++p,"%x",&lookup_type);
}
- if (name_query(ServerFD,lookup,lookup_type,bcast,True,
- bcast_ip,&ip,NULL))
- {
- printf("%s %s\n",inet_ntoa(ip),lookup);
- if (find_status)
- {
- printf("Looking up status of %s\n",inet_ntoa(ip));
- name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
- printf("\n");
- }
- } else {
- printf("couldn't find name %s\n",lookup);
+ if (!query_one(lookup, lookup_type)) {
+ d_printf( "name_query failed to find name %s", lookup );
+ if( 0 != lookup_type )
+ d_printf( "#%02x", lookup_type );
+ d_printf( "\n" );
}
- }
-
+ }
+
return(0);
}
diff --git a/source/utils/pdbedit.c b/source/utils/pdbedit.c
new file mode 100644
index 00000000000..73423e0beeb
--- /dev/null
+++ b/source/utils/pdbedit.c
@@ -0,0 +1,675 @@
+/*
+ Unix SMB/Netbios implementation.
+ passdb editing frontend
+ Version 3.0
+
+ Copyright (C) Simo Sorce 2000
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* base uid for trust accounts is set to 60000 !
+ * May be we should add the defines in smb.h to make it possible having
+ * different values on different platforms?
+ */
+
+#define BASE_MACHINE_UID 60000
+#define MAX_MACHINE_UID 65500 /* 5500 trust accounts aren't enough? */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*
+ * Next two lines needed for SunOS and don't
+ * hurt anything else...
+ */
+extern char *optarg;
+extern int optind;
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+static void usage(void)
+{
+ if (getuid() == 0) {
+ printf("pdbedit options\n");
+ } else {
+ printf("You need to be root to use this tool!\n");
+ }
+ printf("(actually to add a user you need to use smbpasswd)\n");
+ printf("options:\n");
+ printf(" -l list usernames\n");
+ printf(" -v verbose output\n");
+ printf(" -w smbpasswd file style\n");
+ printf(" -u username print user's info\n");
+ printf(" -f fullname set Full Name\n");
+ printf(" -h homedir set home directory\n");
+ printf(" -d drive set home dir drive\n");
+ printf(" -s script set logon script\n");
+ printf(" -p profile set profile path\n");
+ printf(" -a create new account\n");
+ printf(" -m it is a machine trust\n");
+ printf(" -x delete this user\n");
+ printf(" -i file import account from file (smbpasswd style)\n");
+ exit(1);
+}
+
+/*********************************************************
+ Print info from sam structure
+**********************************************************/
+
+static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdstyle)
+{
+ uid_t *puid;
+ gid_t *pgid;
+
+ /* TODO: chaeck if entry is a user or a workstation */
+ if (!sam_pwent) return -1;
+
+ if (verbosity) {
+ printf ("username: %s\n", pdb_get_username(sam_pwent));
+ if ((puid = pdb_get_uid(sam_pwent)) && (pgid = pdb_get_gid(sam_pwent))) {
+ printf ("user ID/Group: %d/%d\n", (unsigned int)*puid,
+ (unsigned int)*pgid);
+ }
+ printf ("user RID/GRID: %u/%u\n", (unsigned int)sam_pwent->user_rid,
+ (unsigned int)sam_pwent->group_rid);
+ printf ("Full Name: %s\n", pdb_get_fullname(sam_pwent));
+ printf ("Home Directory: %s\n", pdb_get_homedir(sam_pwent));
+ printf ("HomeDir Drive: %s\n", pdb_get_dirdrive(sam_pwent));
+ printf ("Logon Script: %s\n", pdb_get_logon_script(sam_pwent));
+ printf ("Profile Path: %s\n", pdb_get_profile_path(sam_pwent));
+ } else if (smbpwdstyle) {
+ if ((puid = pdb_get_uid(sam_pwent))) {
+ char lm_passwd[33];
+ char nt_passwd[33];
+ pdb_sethexpwd(lm_passwd,
+ pdb_get_lanman_passwd(sam_pwent),
+ pdb_get_acct_ctrl(sam_pwent));
+ pdb_sethexpwd(nt_passwd,
+ pdb_get_nt_passwd(sam_pwent),
+ pdb_get_acct_ctrl(sam_pwent));
+
+ printf("%s:%d:%s:%s:%s:LCT-%08X:\n",
+ pdb_get_username(sam_pwent),
+ (unsigned int)*puid,
+ lm_passwd,
+ nt_passwd,
+ pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)pdb_get_pass_last_set_time(sam_pwent));
+ } else {
+ fprintf(stderr, "Can't output in smbpasswd format, no uid on this record.\n");
+ }
+ } else {
+ if ((puid = pdb_get_uid(sam_pwent))) {
+ printf ("%s:%d:%s\n", pdb_get_username(sam_pwent), *puid, pdb_get_fullname(sam_pwent));
+ } else {
+ printf ("%s:(null):%s\n", pdb_get_username(sam_pwent), pdb_get_fullname(sam_pwent));
+ }
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Get an Print User Info
+**********************************************************/
+
+static int print_user_info (char *username, BOOL verbosity, BOOL smbpwdstyle)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+
+ ret = pdb_getsampwnam (sam_pwent, username);
+
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ pdb_free_sam(&sam_pwent);
+
+ return ret;
+}
+
+/*********************************************************
+ List Users
+**********************************************************/
+static int print_users_list (BOOL verbosity, BOOL smbpwdstyle)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+ errno = 0; /* testing --simo */
+ ret = pdb_setsampwent(False);
+ if (ret && errno == ENOENT) {
+ fprintf (stderr,"Password database not found!\n");
+ pdb_free_sam(&sam_pwent);
+ exit(1);
+ }
+
+ while ((ret = pdb_getsampwent (sam_pwent))) {
+ if (verbosity)
+ printf ("---------------\n");
+ print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ pdb_reset_sam(sam_pwent);
+ }
+
+ pdb_endsampwent ();
+ pdb_free_sam(&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Set User Info
+**********************************************************/
+
+static int set_user_info (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+
+ ret = pdb_getsampwnam (sam_pwent, username);
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname);
+ if (homedir)
+ pdb_set_homedir(sam_pwent, homedir);
+ if (drive)
+ pdb_set_dir_drive(sam_pwent,drive);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile);
+
+ if (pdb_update_sam_account (sam_pwent, True))
+ print_user_info (username, True, False);
+ else {
+ fprintf (stderr, "Unable to modify entry!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam(&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New User
+**********************************************************/
+static int new_user (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ struct passwd *pwd = NULL;
+ char *password1, *password2;
+
+ ZERO_STRUCT(sam_pwent);
+
+ if (!(pwd = sys_getpwnam(username))) {
+ fprintf (stderr, "User %s does not exist in system passwd!\n", username);
+ return -1;
+ }
+
+ pdb_init_sam_pw (&sam_pwent, pwd);
+
+ password1 = getpass("new password:");
+ password2 = getpass("retype new password:");
+ if (strcmp (password1, password2)) {
+ fprintf (stderr, "Passwords does not match!\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+
+ pdb_set_plaintext_passwd(sam_pwent, password1);
+
+ pdb_set_username(sam_pwent, username);
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname);
+ if (homedir)
+ pdb_set_homedir (sam_pwent, homedir);
+ if (drive)
+ pdb_set_dir_drive (sam_pwent, drive);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile);
+
+ pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL);
+
+ if (pdb_add_sam_account (sam_pwent)) {
+ print_user_info (username, True, False);
+ } else {
+ fprintf (stderr, "Unable to add user! (does it alredy exist?)\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam (&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New Machine
+**********************************************************/
+
+static int new_machine (char *machinename)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ SAM_ACCOUNT *sam_trust=NULL;
+ char name[16];
+ char *password = NULL;
+ uid_t uid;
+
+ pdb_init_sam (&sam_pwent);
+
+ if (machinename[strlen (machinename) -1] == '$')
+ machinename[strlen (machinename) -1] = '\0';
+
+ safe_strcpy (name, machinename, 16);
+ safe_strcat (name, "$", 16);
+
+ string_set (&password, machinename);
+ strlower_m(password);
+
+ pdb_set_plaintext_passwd (sam_pwent, password);
+
+ pdb_set_username (sam_pwent, name);
+
+ for (uid=BASE_MACHINE_UID; uid<=MAX_MACHINE_UID; uid++) {
+ pdb_init_sam (&sam_trust);
+ if (pdb_getsampwrid (sam_trust, pdb_uid_to_user_rid (uid))) {
+ pdb_free_sam (&sam_trust);
+ } else {
+ break;
+ }
+ }
+
+ if (uid>MAX_MACHINE_UID) {
+ fprintf (stderr, "No more free UIDs available to Machine accounts!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ pdb_set_user_rid (sam_pwent,pdb_uid_to_user_rid (uid));
+ pdb_set_group_rid (sam_pwent, pdb_gid_to_group_rid (BASE_MACHINE_UID));
+ pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST);
+
+ if (pdb_add_sam_account (sam_pwent)) {
+ print_user_info (name, True, False);
+ } else {
+ fprintf (stderr, "Unable to add machine! (does it already exist?)\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam (&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Delete user entry
+**********************************************************/
+
+static int delete_user_entry (char *username)
+{
+ return pdb_delete_sam_account (username);
+}
+
+/*********************************************************
+ Delete machine entry
+**********************************************************/
+
+static int delete_machine_entry (char *machinename)
+{
+ char name[16];
+
+ safe_strcpy (name, machinename, 16);
+ if (name[strlen(name)] != '$')
+ safe_strcat (name, "$", 16);
+ return pdb_delete_sam_account (name);
+}
+
+/*********************************************************
+ Import smbpasswd style file
+**********************************************************/
+
+static int import_users (char *filename)
+{
+ FILE *fp = NULL;
+ SAM_ACCOUNT *sam_pwent = NULL;
+ static pstring user_name;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+ char linebuf[256];
+ size_t linebuf_len;
+ unsigned char c;
+ unsigned char *p;
+ long uidval;
+ int line = 0;
+ int good = 0;
+ struct passwd *pwd;
+
+ if((fp = sys_fopen(filename, "rb")) == NULL) {
+ fprintf (stderr, "%s\n", strerror (ferror (fp)));
+ return -1;
+ }
+
+ while (!feof(fp)) {
+ /*Get a new line*/
+ linebuf[0] = '\0';
+ fgets(linebuf, 256, fp);
+ if (ferror(fp)) {
+ fprintf (stderr, "%s\n", strerror (ferror (fp)));
+ return -1;
+ }
+ if ((linebuf_len = strlen(linebuf)) == 0) {
+ line++;
+ continue;
+ }
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') break;
+ }
+ } else
+ linebuf[linebuf_len - 1] = '\0';
+ linebuf[linebuf_len] = '\0';
+ if ((linebuf[0] == 0) && feof(fp)) {
+ /*end of file!!*/
+ return 0;
+ }
+ line++;
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ continue;
+
+ /* Get user name */
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ fprintf (stderr, "Error: malformed password entry at line %d !!\n", line);
+ continue;
+ }
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+ p++;
+ if(*p == '-') {
+ fprintf (stderr, "Error: negative uid at line %d\n", line);
+ continue;
+ }
+ if (!isdigit(*p)) {
+ fprintf (stderr, "Error: malformed password entry at line %d (uid not number)\n", line);
+ continue;
+ }
+ uidval = atoi((char *) p);
+ while (*p && isdigit(*p)) p++;
+ if (*p != ':') {
+ fprintf (stderr, "Error: malformed password entry at line %d (no : after uid)\n", line);
+ continue;
+ }
+ if(!(pwd = sys_getpwnam(user_name))) {
+ fprintf(stderr, "User %s does not \
+exist in system password file (usually /etc/passwd). Cannot add \
+account without a valid local system user.\n", user_name);
+ return False;
+ }
+
+ if (!pdb_init_sam_pw(&sam_pwent, pwd)) {
+ fprintf(stderr, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
+ return False;
+ }
+
+ /* Get passwords */
+ p++;
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid */
+ fprintf (stderr, "Warning: entry invalidated for user %s\n", user_name);
+ pdb_set_lanman_passwd(sam_pwent, NULL);
+ pdb_set_nt_passwd(sam_pwent,NULL);
+ pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_DISABLED);
+ } else {
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ fprintf (stderr, "Error: malformed password entry at line %d (password too short)\n",line);
+ pdb_free_sam (&sam_pwent);
+ continue;
+ }
+ if (p[32] != ':') {
+ fprintf (stderr, "Error: malformed password entry at line %d (no terminating :)\n",line);
+ pdb_free_sam (&sam_pwent);
+ continue;
+ }
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+ pdb_set_lanman_passwd(sam_pwent, NULL);
+ pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_PWNOTREQ);
+ } else {
+ if (!pdb_gethexpwd((char *)p, smbpwd)) {
+ fprintf (stderr, "Error: malformed Lanman password entry at line %d (non hex chars)\n", line);
+ pdb_free_sam (&sam_pwent);
+ continue;
+ }
+ pdb_set_lanman_passwd(sam_pwent, smbpwd);
+ }
+ /* NT password */
+ p += 33;
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if (pdb_gethexpwd((char *)p,smbntpwd)) {
+ pdb_set_nt_passwd(sam_pwent, smbntpwd);
+ }
+ }
+ p += 33;
+ }
+ }
+
+ /* Get ACCT_CTRL field if any */
+ if (*p == '[') {
+ uint16 acct_ctrl;
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+
+ acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+ if (acct_ctrl)
+ acct_ctrl = ACB_NORMAL;
+
+ pdb_set_acct_ctrl(sam_pwent, acct_ctrl);
+
+ /* Get last change time */
+ if(end_p)
+ p = end_p + 1;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) break;
+ }
+ if(i == 8) {
+ pdb_set_pass_last_set_time (sam_pwent, (time_t)strtol((char *)p, NULL, 16));
+ }
+ }
+ }
+ }
+
+ /* Now ADD the entry */
+ if (!(pdb_add_sam_account (sam_pwent))) {
+ fprintf (stderr, "Unable to add user entry!\n");
+ pdb_free_sam (&sam_pwent);
+ continue;
+ }
+ printf ("%s imported!\n", user_name);
+ good++;
+ pdb_free_sam (&sam_pwent);
+ }
+ printf ("%d lines read.\n%d entryes imported\n", line, good);
+ return 0;
+}
+
+/*********************************************************
+ Start here.
+**********************************************************/
+
+int main (int argc, char **argv)
+{
+ int ch;
+ BOOL list_users = False;
+ BOOL verbose = False;
+ BOOL spstyle = False;
+ BOOL setparms = False;
+ BOOL machine = False;
+ BOOL add_user = False;
+ BOOL delete_user = False;
+ BOOL import = False;
+ char *user_name = NULL;
+ char *full_name = NULL;
+ char *home_dir = NULL;
+ char *home_drive = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *smbpasswd = NULL;
+
+ setup_logging("pdbedit", True);
+
+ if (argc < 2) {
+ usage();
+ return 0;
+ }
+
+ if(!initialize_password_db(True)) {
+ fprintf(stderr, "Can't setup password database vectors.\n");
+ exit(1);
+ }
+
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ dyn_CONFIGFILE);
+ exit(1);
+ }
+
+ while ((ch = getopt(argc, argv, "ad:f:h:i:lmp:s:u:vwx")) != EOF) {
+ switch(ch) {
+ case 'a':
+ add_user = True;
+ break;
+ case 'm':
+ machine = True;
+ break;
+ case 'l':
+ list_users = True;
+ break;
+ case 'v':
+ verbose = True;
+ break;
+ case 'w':
+ spstyle = True;
+ break;
+ case 'u':
+ user_name = optarg;
+ break;
+ case 'f':
+ setparms = True;
+ full_name = optarg;
+ break;
+ case 'h':
+ setparms = True;
+ home_dir = optarg;
+ break;
+ case 'd':
+ setparms = True;
+ home_drive = optarg;
+ break;
+ case 's':
+ setparms = True;
+ logon_script = optarg;
+ break;
+ case 'p':
+ setparms = True;
+ profile_path = optarg;
+ break;
+ case 'x':
+ delete_user = True;
+ break;
+ case 'i':
+ import = True;
+ smbpasswd = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (((add_user?1:0) + (delete_user?1:0) + (list_users?1:0) + (import?1:0) + (setparms?1:0)) > 1) {
+ fprintf (stderr, "Incompatible options on command line!\n");
+ usage();
+ exit(1);
+ }
+
+ if (add_user) {
+ if (!user_name) {
+ fprintf (stderr, "Username not specified! (use -u option)\n");
+ return -1;
+ }
+ if (machine)
+ return new_machine (user_name);
+ else
+ return new_user (user_name, full_name, home_dir, home_drive, logon_script, profile_path);
+ }
+
+ if (delete_user) {
+ if (!user_name) {
+ fprintf (stderr, "Username not specified! (use -u option)\n");
+ return -1;
+ }
+ if (machine)
+ return delete_machine_entry (user_name);
+ else
+ return delete_user_entry (user_name);
+ }
+
+ if (user_name) {
+ if (setparms)
+ set_user_info ( user_name, full_name,
+ home_dir,
+ home_drive,
+ logon_script,
+ profile_path);
+ else
+ return print_user_info (user_name, verbose, spstyle);
+
+ return 0;
+ }
+
+
+ if (list_users)
+ return print_users_list (verbose, spstyle);
+
+ if (import)
+ return import_users (smbpasswd);
+
+ usage();
+
+ return 0;
+}
diff --git a/source/utils/rpccheck.c b/source/utils/rpccheck.c
new file mode 100644
index 00000000000..39563102410
--- /dev/null
+++ b/source/utils/rpccheck.c
@@ -0,0 +1,63 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+
+ Copyright (C) Jean François Micouleau 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+main()
+{
+ char filter[]="0123456789ABCDEF";
+
+ char s[128];
+ char d=0;
+ int x=0;
+ prs_struct ps;
+ TALLOC_CTX *ctx;
+
+ /* change that struct */
+ SAMR_R_QUERY_USERINFO rpc_stub;
+
+ ZERO_STRUCT(rpc_stub);
+
+ setup_logging("", True);
+ DEBUGLEVEL=10;
+
+ ctx=talloc_init();
+ if (!ctx) exit(1);
+
+ prs_init(&ps, 1600, 4, ctx, MARSHALL);
+
+ while (scanf("%s", s)!=-1) {
+ if (strlen(s)==2 && strchr_m(filter, *s)!=NULL && strchr_m(filter, *(s+1))!=NULL) {
+ d=strtol(s, NULL, 16);
+ if(!prs_append_data(&ps, &d, 1))
+ printf("error while reading data\n");
+ }
+ }
+
+ prs_switch_type(&ps, UNMARSHALL);
+ prs_set_offset(&ps, 0);
+
+ /* change that call */
+ if(!samr_io_r_query_userinfo("", &rpc_stub, &ps, 0))
+ printf("error while UNMARSHALLING the data\n");
+
+ printf("\n");
+}
diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c
new file mode 100644
index 00000000000..94eada5c3d6
--- /dev/null
+++ b/source/utils/smbcacls.c
@@ -0,0 +1,959 @@
+/*
+ Unix SMB/Netbios implementation.
+ ACL get/set utility
+ Version 3.0
+
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jeremy Allison 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static fstring password;
+static pstring username;
+static pstring owner_username;
+static fstring server;
+static int got_pass;
+static int test_args;
+TALLOC_CTX *ctx;
+
+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
+#define CREATE_ACCESS_WRITE (WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS)
+
+/* numeric is set when the user wants numeric SIDs and ACEs rather
+ than going via LSA calls to resolve them */
+static int numeric;
+
+enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
+enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP};
+enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
+
+struct perm_value {
+ char *perm;
+ uint32 mask;
+};
+
+/* These values discovered by inspection */
+
+static struct perm_value special_values[] = {
+ { "R", 0x00120089 },
+ { "W", 0x00120116 },
+ { "X", 0x001200a0 },
+ { "D", 0x00010000 },
+ { "P", 0x00040000 },
+ { "O", 0x00080000 },
+ { NULL, 0 },
+};
+
+static struct perm_value standard_values[] = {
+ { "READ", 0x001200a9 },
+ { "CHANGE", 0x001301bf },
+ { "FULL", 0x001f01ff },
+ { NULL, 0 },
+};
+
+struct cli_state lsa_cli;
+POLICY_HND pol;
+struct ntuser_creds creds;
+BOOL got_policy_hnd;
+
+/* Open cli connection and policy handle */
+
+static BOOL cacls_open_policy_hnd(void)
+{
+ creds.pwd.null_pwd = 1;
+
+ /* Initialise cli LSA connection */
+
+ if (!lsa_cli.initialised &&
+ !cli_lsa_initialise(&lsa_cli, server, &creds)) {
+ return False;
+ }
+
+ /* Open policy handle */
+
+ if (!got_policy_hnd) {
+
+ /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
+ but NT sends 0x2000000 so we might as well do it too. */
+
+ if (!NT_STATUS_IS_OK(cli_lsa_open_policy(&lsa_cli, lsa_cli.mem_ctx, True,
+ GENERIC_EXECUTE_ACCESS, &pol))) {
+ return False;
+ }
+
+ got_policy_hnd = True;
+ }
+
+ return True;
+}
+
+/* convert a SID to a string, either numeric or username/group */
+static void SidToString(fstring str, DOM_SID *sid)
+{
+ char **names = NULL;
+ uint32 *types = NULL;
+ int num_names;
+
+ sid_to_string(str, sid);
+
+ if (numeric) return;
+
+ /* Ask LSA to convert the sid to a name */
+
+ if (!cacls_open_policy_hnd() ||
+ !NT_STATUS_IS_OK(cli_lsa_lookup_sids(&lsa_cli, lsa_cli.mem_ctx, &pol, 1, sid, &names,
+ &types, &num_names)) ||
+ !names || !names[0]) {
+ return;
+ }
+
+ /* Converted OK */
+
+ fstrcpy(str, names[0]);
+}
+
+/* convert a string to a SID, either numeric or username/group */
+static BOOL StringToSid(DOM_SID *sid, const char *str)
+{
+ uint32 *types = NULL;
+ DOM_SID *sids = NULL;
+ int num_sids;
+ BOOL result = True;
+
+ if (strncmp(str, "S-", 2) == 0) {
+ return string_to_sid(sid, str);
+ }
+
+ if (!cacls_open_policy_hnd() ||
+ !NT_STATUS_IS_OK(cli_lsa_lookup_names(&lsa_cli, lsa_cli.mem_ctx, &pol, 1, &str,
+ &sids, &types, &num_sids))) {
+ result = False;
+ goto done;
+ }
+
+ sid_copy(sid, &sids[0]);
+
+ done:
+
+ return result;
+}
+
+
+/* print an ACE on a FILE, using either numeric or ascii representation */
+static void print_ace(FILE *f, SEC_ACE *ace)
+{
+ struct perm_value *v;
+ fstring sidstr;
+ int do_print = 0;
+ uint32 got_mask;
+
+ SidToString(sidstr, &ace->trustee);
+
+ fprintf(f, "%s:", sidstr);
+
+ if (numeric) {
+ fprintf(f, "%d/%d/0x%08x",
+ ace->type, ace->flags, ace->info.mask);
+ return;
+ }
+
+ /* Ace type */
+
+ if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+ fprintf(f, "ALLOWED");
+ } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ fprintf(f, "DENIED");
+ } else {
+ fprintf(f, "%d", ace->type);
+ }
+
+ /* Not sure what flags can be set in a file ACL */
+
+ fprintf(f, "/%d/", ace->flags);
+
+ /* Standard permissions */
+
+ for (v = standard_values; v->perm; v++) {
+ if (ace->info.mask == v->mask) {
+ fprintf(f, "%s", v->perm);
+ return;
+ }
+ }
+
+ /* Special permissions. Print out a hex value if we have
+ leftover bits in the mask. */
+
+ got_mask = ace->info.mask;
+
+ again:
+ for (v = special_values; v->perm; v++) {
+ if ((ace->info.mask & v->mask) == v->mask) {
+ if (do_print) {
+ fprintf(f, "%s", v->perm);
+ }
+ got_mask &= ~v->mask;
+ }
+ }
+
+ if (!do_print) {
+ if (got_mask != 0) {
+ fprintf(f, "0x%08x", ace->info.mask);
+ } else {
+ do_print = 1;
+ goto again;
+ }
+ }
+}
+
+
+/* parse an ACE in the same format as print_ace() */
+static BOOL parse_ace(SEC_ACE *ace, char *str)
+{
+ char *p;
+ fstring tok;
+ unsigned atype, aflags, amask;
+ DOM_SID sid;
+ SEC_ACCESS mask;
+ struct perm_value *v;
+
+ ZERO_STRUCTP(ace);
+ p = strchr_m(str,':');
+ if (!p) return False;
+ *p = '\0';
+ p++;
+
+ /* Try to parse numeric form */
+
+ if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
+ StringToSid(&sid, str)) {
+ goto done;
+ }
+
+ /* Try to parse text form */
+
+ if (!StringToSid(&sid, str)) {
+ return False;
+ }
+
+ if (!next_token(&p, tok, "/", sizeof(fstring))) {
+ return False;
+ }
+
+ if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
+ atype = SEC_ACE_TYPE_ACCESS_DENIED;
+ } else {
+ return False;
+ }
+
+ /* Only numeric form accepted for flags at present */
+
+ if (!(next_token(&p, tok, "/", sizeof(fstring)) &&
+ sscanf(tok, "%i", &aflags))) {
+ return False;
+ }
+
+ if (!next_token(&p, tok, "/", sizeof(fstring))) {
+ return False;
+ }
+
+ if (strncmp(tok, "0x", 2) == 0) {
+ if (sscanf(tok, "%i", &amask) != 1) {
+ return False;
+ }
+ goto done;
+ }
+
+ for (v = standard_values; v->perm; v++) {
+ if (strcmp(tok, v->perm) == 0) {
+ amask = v->mask;
+ goto done;
+ }
+ }
+
+ p = tok;
+
+ while(*p) {
+ BOOL found = False;
+
+ for (v = special_values; v->perm; v++) {
+ if (v->perm[0] == *p) {
+ amask |= v->mask;
+ found = True;
+ }
+ }
+
+ if (!found) return False;
+ p++;
+ }
+
+ if (*p) {
+ return False;
+ }
+
+ done:
+ mask.mask = amask;
+ init_sec_ace(ace, &sid, atype, mask, aflags);
+ return True;
+}
+
+/* add an ACE to a list of ACEs in a SEC_ACL */
+static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace)
+{
+ SEC_ACL *new;
+ SEC_ACE *aces;
+ if (! *the_acl) {
+ (*the_acl) = make_sec_acl(ctx, 3, 1, ace);
+ return True;
+ }
+
+ aces = calloc(1+(*the_acl)->num_aces,sizeof(SEC_ACE));
+ memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
+ memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
+ new = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
+ SAFE_FREE(aces);
+ (*the_acl) = new;
+ return True;
+}
+
+/* parse a ascii version of a security descriptor */
+static SEC_DESC *sec_desc_parse(char *str)
+{
+ char *p = str;
+ fstring tok;
+ SEC_DESC *ret;
+ size_t sd_size;
+ DOM_SID *grp_sid=NULL, *owner_sid=NULL;
+ SEC_ACL *dacl=NULL;
+ int revision=1;
+
+ while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
+
+ if (strncmp(tok,"REVISION:", 9) == 0) {
+ revision = strtol(tok+9, NULL, 16);
+ continue;
+ }
+
+ if (strncmp(tok,"OWNER:", 6) == 0) {
+ owner_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
+ if (!owner_sid ||
+ !StringToSid(owner_sid, tok+6)) {
+ printf("Failed to parse owner sid\n");
+ return NULL;
+ }
+ continue;
+ }
+
+ if (strncmp(tok,"GROUP:", 6) == 0) {
+ grp_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
+ if (!grp_sid ||
+ !StringToSid(grp_sid, tok+6)) {
+ printf("Failed to parse group sid\n");
+ return NULL;
+ }
+ continue;
+ }
+
+ if (strncmp(tok,"ACL:", 4) == 0) {
+ SEC_ACE ace;
+ if (!parse_ace(&ace, tok+4)) {
+ printf("Failed to parse ACL %s\n", tok);
+ return NULL;
+ }
+ if(!add_ace(&dacl, &ace)) {
+ printf("Failed to add ACL %s\n", tok);
+ return NULL;
+ }
+ continue;
+ }
+
+ printf("Failed to parse security descriptor\n");
+ return NULL;
+ }
+
+ ret = make_sec_desc(ctx,revision, owner_sid, grp_sid,
+ NULL, dacl, &sd_size);
+
+ SAFE_FREE(grp_sid);
+ SAFE_FREE(owner_sid);
+
+ return ret;
+}
+
+
+/* print a ascii version of a security descriptor on a FILE handle */
+static void sec_desc_print(FILE *f, SEC_DESC *sd)
+{
+ fstring sidstr;
+ int i;
+
+ printf("REVISION:%d\n", sd->revision);
+
+ /* Print owner and group sid */
+
+ if (sd->owner_sid) {
+ SidToString(sidstr, sd->owner_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ printf("OWNER:%s\n", sidstr);
+
+ if (sd->grp_sid) {
+ SidToString(sidstr, sd->grp_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ fprintf(f, "GROUP:%s\n", sidstr);
+
+ /* Print aces */
+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+ SEC_ACE *ace = &sd->dacl->ace[i];
+ fprintf(f, "ACL:");
+ print_ace(f, ace);
+ fprintf(f, "\n");
+ }
+
+}
+
+/*****************************************************
+dump the acls for a file
+*******************************************************/
+static int cacl_dump(struct cli_state *cli, char *filename)
+{
+ int fnum;
+ SEC_DESC *sd;
+
+ if (test_args) return EXIT_OK;
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ sd = cli_query_secdesc(cli, fnum, ctx);
+
+ if (!sd) {
+ printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ sec_desc_print(stdout, sd);
+
+ cli_close(cli, fnum);
+
+ return EXIT_OK;
+}
+
+/*****************************************************
+Change the ownership or group ownership of a file. Just
+because the NT docs say this can't be done :-). JRA.
+*******************************************************/
+
+static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
+ char *filename, char *new_username)
+{
+ int fnum;
+ DOM_SID sid;
+ SEC_DESC *sd, *old;
+ size_t sd_size;
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!StringToSid(&sid, new_username))
+ return EXIT_PARSE_ERROR;
+
+ old = cli_query_secdesc(cli, fnum, ctx);
+
+ cli_close(cli, fnum);
+
+ if (!old) {
+ printf("owner_set: Failed to query old descriptor\n");
+ return EXIT_FAILED;
+ }
+
+ sd = make_sec_desc(ctx,old->revision,
+ (change_mode == REQUEST_CHOWN) ? &sid : old->owner_sid,
+ (change_mode == REQUEST_CHGRP) ? &sid : old->grp_sid,
+ NULL, old->dacl, &sd_size);
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
+
+ if (fnum == -1) {
+ printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!cli_set_secdesc(cli, fnum, sd)) {
+ printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
+ }
+
+ cli_close(cli, fnum);
+
+ return EXIT_OK;
+}
+
+
+/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
+ However NT4 gives a "The information may have been modified by a
+ computer running Windows NT 5.0" if denied ACEs do not appear before
+ allowed ACEs. */
+
+static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
+{
+ if (sec_ace_equal(ace1, ace2))
+ return 0;
+
+ if (ace1->type != ace2->type)
+ return ace2->type - ace1->type;
+
+ if (sid_compare(&ace1->trustee, &ace2->trustee))
+ return sid_compare(&ace1->trustee, &ace2->trustee);
+
+ if (ace1->flags != ace2->flags)
+ return ace1->flags - ace2->flags;
+
+ if (ace1->info.mask != ace2->info.mask)
+ return ace1->info.mask - ace2->info.mask;
+
+ if (ace1->size != ace2->size)
+ return ace1->size - ace2->size;
+
+ return memcmp(ace1, ace2, sizeof(SEC_ACE));
+}
+
+static void sort_acl(SEC_ACL *the_acl)
+{
+ int i;
+ if (!the_acl) return;
+
+ qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare);
+
+ for (i=1;i<the_acl->num_aces;) {
+ if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
+ int j;
+ for (j=i; j<the_acl->num_aces-1; j++) {
+ the_acl->ace[j] = the_acl->ace[j+1];
+ }
+ the_acl->num_aces--;
+ } else {
+ i++;
+ }
+ }
+}
+
+/*****************************************************
+set the ACLs on a file given an ascii description
+*******************************************************/
+static int cacl_set(struct cli_state *cli, char *filename,
+ char *the_acl, enum acl_mode mode)
+{
+ int fnum;
+ SEC_DESC *sd, *old;
+ int i, j;
+ size_t sd_size;
+ int result = EXIT_OK;
+
+ sd = sec_desc_parse(the_acl);
+
+ if (!sd) return EXIT_PARSE_ERROR;
+ if (test_args) return EXIT_OK;
+
+ /* The desired access below is the only one I could find that works
+ with NT4, W2KP and Samba */
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
+
+ if (fnum == -1) {
+ printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ old = cli_query_secdesc(cli, fnum, ctx);
+
+ if (!old) {
+ printf("calc_set: Failed to query old descriptor\n");
+ return EXIT_FAILED;
+ }
+
+ cli_close(cli, fnum);
+
+ /* the logic here is rather more complex than I would like */
+ switch (mode) {
+ case SMB_ACL_DELETE:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ BOOL found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sec_ace_equal(&sd->dacl->ace[i],
+ &old->dacl->ace[j])) {
+ int k;
+ for (k=j; k<old->dacl->num_aces-1;k++) {
+ old->dacl->ace[k] = old->dacl->ace[k+1];
+ }
+ old->dacl->num_aces--;
+ if (old->dacl->num_aces == 0) {
+ SAFE_FREE(old->dacl->ace);
+ SAFE_FREE(old->dacl);
+ old->off_dacl = 0;
+ }
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("ACL for ACE:");
+ print_ace(stdout, &sd->dacl->ace[i]);
+ printf(" not found\n");
+ }
+ }
+ break;
+
+ case SMB_ACL_MODIFY:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ BOOL found = False;
+
+ for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
+ if (sid_equal(&sd->dacl->ace[i].trustee,
+ &old->dacl->ace[j].trustee)) {
+ old->dacl->ace[j] = sd->dacl->ace[i];
+ found = True;
+ }
+ }
+
+ if (!found) {
+ fstring str;
+
+ SidToString(str, &sd->dacl->ace[i].trustee);
+ printf("ACL for SID %s not found\n", str);
+ }
+ }
+
+ break;
+
+ case SMB_ACL_ADD:
+ for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
+ add_ace(&old->dacl, &sd->dacl->ace[i]);
+ }
+ break;
+
+ case SMB_ACL_SET:
+ old = sd;
+ break;
+ }
+
+ /* Denied ACE entries must come before allowed ones */
+ sort_acl(old->dacl);
+
+ /* Create new security descriptor and set it */
+ sd = make_sec_desc(ctx,old->revision, old->owner_sid, old->grp_sid,
+ NULL, old->dacl, &sd_size);
+
+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
+
+ if (fnum == -1) {
+ printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
+ return EXIT_FAILED;
+ }
+
+ if (!cli_set_secdesc(cli, fnum, sd)) {
+ printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
+ result = EXIT_FAILED;
+ }
+
+ /* Clean up */
+
+ cli_close(cli, fnum);
+
+ return result;
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+struct cli_state *connect_one(char *share)
+{
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ struct in_addr ip;
+ extern pstring global_myname;
+
+ fstrcpy(server,share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ zero_ip(&ip);
+
+ make_nmb_name(&calling, global_myname, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ again:
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server, &ip)) {
+ DEBUG(0,("Connection to %s failed\n", server));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ DEBUG(0,("session request to %s failed\n", called.name));
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ lp_workgroup())) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ return c;
+}
+
+
+static void usage(void)
+{
+ printf(
+"Usage: smbcacls //server1/share1 filename [options]\n\
+\n\
+\t-D <acls> delete an acl\n\
+\t-M <acls> modify an acl\n\
+\t-A <acls> add an acl\n\
+\t-S <acls> set acls\n\
+\t-C username change ownership of a file\n\
+\t-G username change group ownership of a file\n\
+\t-n don't resolve sids or masks to names\n\
+\t-h print help\n\
+\t-d debuglevel set debug output level\n\
+\t-U username user to autheticate as\n\
+\n\
+The username can be of the form username%%password or\n\
+workgroup\\username%%password.\n\n\
+An acl is of the form ACL:<SID>:type/flags/mask\n\
+You can string acls together with spaces, commas or newlines\n\
+");
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ char *share;
+ pstring filename;
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *p;
+ struct cli_state *cli=NULL;
+ enum acl_mode mode = SMB_ACL_SET;
+ char *the_acl = NULL;
+ enum chown_mode change_mode = REQUEST_NONE;
+ int result;
+
+ ctx=talloc_init();
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ if (argc < 3 || argv[1][0] == '-') {
+ usage();
+ talloc_destroy(ctx);
+ exit(EXIT_PARSE_ERROR);
+ }
+
+ setup_logging(argv[0],True);
+
+ share = argv[1];
+ pstrcpy(filename, argv[2]);
+ all_string_sub(share,"/","\\",0);
+
+ argc -= 2;
+ argv += 2;
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
+
+ if ((p=strchr_m(username,'%'))) {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr_m(getenv("USER"), '%') + 1, 'X',
+ strlen(password));
+ }
+ }
+
+ while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:")) != EOF) {
+ switch (opt) {
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr_m(username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(password, p+1);
+ got_pass = 1;
+ }
+ break;
+
+ case 'S':
+ the_acl = optarg;
+ mode = SMB_ACL_SET;
+ break;
+
+ case 'D':
+ the_acl = optarg;
+ mode = SMB_ACL_DELETE;
+ break;
+
+ case 'M':
+ the_acl = optarg;
+ mode = SMB_ACL_MODIFY;
+ break;
+
+ case 'A':
+ the_acl = optarg;
+ mode = SMB_ACL_ADD;
+ break;
+
+ case 'C':
+ pstrcpy(owner_username,optarg);
+ change_mode = REQUEST_CHOWN;
+ break;
+
+ case 'G':
+ pstrcpy(owner_username,optarg);
+ change_mode = REQUEST_CHGRP;
+ break;
+
+ case 'n':
+ numeric = 1;
+ break;
+
+ case 't':
+ test_args = 1;
+ break;
+
+ case 'h':
+ usage();
+ talloc_destroy(ctx);
+ exit(EXIT_PARSE_ERROR);
+
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ talloc_destroy(ctx);
+ exit(EXIT_PARSE_ERROR);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ usage();
+ talloc_destroy(ctx);
+ exit(EXIT_PARSE_ERROR);
+ }
+
+ /* Make connection to server */
+
+ if (!test_args) {
+ cli = connect_one(share);
+ if (!cli) {
+ talloc_destroy(ctx);
+ exit(EXIT_FAILED);
+ }
+ }
+
+ all_string_sub(filename, "/", "\\", 0);
+ if (filename[0] != '\\') {
+ pstring s;
+ s[0] = '\\';
+ safe_strcpy(&s[1], filename, sizeof(pstring)-1);
+ pstrcpy(filename, s);
+ }
+
+ /* Perform requested action */
+
+ if (change_mode != REQUEST_NONE) {
+ result = owner_set(cli, change_mode, filename, owner_username);
+ } else if (the_acl) {
+ result = cacl_set(cli, filename, the_acl, mode);
+ } else {
+ result = cacl_dump(cli, filename);
+ }
+
+ talloc_destroy(ctx);
+
+ return result;
+}
diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c
new file mode 100644
index 00000000000..ce04d7a2158
--- /dev/null
+++ b/source/utils/smbcontrol.c
@@ -0,0 +1,432 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ program to send control messages to Samba processes
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static struct {
+ char *name;
+ int value;
+} msg_types[] = {
+ {"debug", MSG_DEBUG},
+ {"force-election", MSG_FORCE_ELECTION},
+ {"ping", MSG_PING},
+ {"profile", MSG_PROFILE},
+ {"profilelevel", MSG_REQ_PROFILELEVEL},
+ {"debuglevel", MSG_REQ_DEBUGLEVEL},
+ {"printer-notify", MSG_PRINTER_NOTIFY},
+ {"close-share", MSG_SMB_FORCE_TDIS},
+ {"samsync", MSG_SMB_SAM_SYNC},
+ {"samrepl", MSG_SMB_SAM_REPL},
+ {NULL, -1}
+};
+
+time_t timeout_start;
+
+#define MAX_WAIT 10
+
+static void usage(BOOL doexit)
+{
+ int i;
+ if (doexit) {
+ printf("Usage: smbcontrol -i -s configfile\n");
+ printf(" smbcontrol <destination> <message-type> <parameters>\n\n");
+ } else {
+ printf("<destination> <message-type> <parameters>\n\n");
+ }
+ printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
+ printf("\t<message-type> is one of: ");
+ for (i=0; msg_types[i].name; i++)
+ printf("%s%s", i?", ":"",msg_types[i].name);
+ printf("\n");
+ if (doexit) exit(1);
+}
+
+static int pong_count;
+static BOOL got_level;
+static BOOL pong_registered = False;
+static BOOL debuglevel_registered = False;
+static BOOL profilelevel_registered = False;
+
+
+/****************************************************************************
+a useful function for testing the message system
+****************************************************************************/
+void pong_function(int msg_type, pid_t src, void *buf, size_t len)
+{
+ pong_count++;
+ printf("PONG from PID %u\n",(unsigned int)src);
+}
+
+/****************************************************************************
+Prints out the current Debug level returned by MSG_DEBUGLEVEL
+****************************************************************************/
+void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
+{
+ int i;
+ int debuglevel_class[DBGC_LAST];
+
+ memcpy(debuglevel_class, buf, len);
+
+ printf("Current debug level of PID %u is %d ",(unsigned int)src, debuglevel_class[0]);
+ for (i=1;i<DBGC_LAST;i++)
+ if (debuglevel_class[i])
+ printf("%s:%d ", debug_classname_from_index(i), debuglevel_class[i]);
+ printf("\n");
+
+ got_level = True;
+}
+
+/****************************************************************************
+Prints out the current Profile level returned by MSG_PROFILELEVEL
+****************************************************************************/
+void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
+{
+ int level;
+ char *s=NULL;
+ memcpy(&level, buf, sizeof(int));
+
+ if (level) {
+ switch (level) {
+ case 1:
+ s = "off";
+ break;
+ case 3:
+ s = "count only";
+ break;
+ case 7:
+ s = "count and time";
+ break;
+ }
+ printf("Profiling %s on PID %u\n",s,(unsigned int)src);
+ } else {
+ printf("Profiling not available on PID %u\n",(unsigned int)src);
+ }
+ got_level = True;
+}
+
+/****************************************************************************
+send a message to a named destination
+****************************************************************************/
+static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
+{
+ pid_t pid;
+ /* "smbd" is the only broadcast operation */
+ if (strequal(dest,"smbd")) {
+ TDB_CONTEXT *tdb;
+ BOOL ret;
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
+ if (!tdb) {
+ fprintf(stderr,"Failed to open connections database in send_message.\n");
+ return False;
+ }
+
+ ret = message_send_all(tdb,msg_type, buf, len, duplicates);
+ tdb_close(tdb);
+
+ return ret;
+ } else if (strequal(dest,"nmbd")) {
+ pid = pidfile_pid(dest);
+ if (pid == 0) {
+ fprintf(stderr,"Can't find pid for nmbd\n");
+ return False;
+ }
+ } else if (strequal(dest,"self")) {
+ pid = getpid();
+ } else {
+ pid = atoi(dest);
+ if (pid == 0) {
+ fprintf(stderr,"Not a valid pid\n");
+ return False;
+ }
+ }
+
+ return message_send_pid(pid, msg_type, buf, len, duplicates);
+}
+
+/****************************************************************************
+evaluate a message type string
+****************************************************************************/
+static int parse_type(char *mtype)
+{
+ int i;
+ for (i=0;msg_types[i].name;i++) {
+ if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
+ }
+ return -1;
+}
+
+
+/****************************************************************************
+do command
+****************************************************************************/
+static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
+{
+ int i, n, v;
+ int mtype;
+ BOOL retval=False;
+
+ mtype = parse_type(msg_name);
+ if (mtype == -1) {
+ fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
+ return(False);
+ }
+
+ switch (mtype) {
+ case MSG_DEBUG: {
+ struct debuglevel_message dm;
+
+ if (!params || !params[0]) {
+ fprintf(stderr,"MSG_DEBUG needs a parameter\n");
+ return(False);
+ }
+
+ ZERO_STRUCT(dm);
+ if (!debug_parse_params(params, dm.debuglevel_class, dm.debuglevel_class_isset)) {
+ fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n");
+ return(False);
+ } else
+ send_message(dest, MSG_DEBUG, &dm, sizeof(dm), False);
+ break;
+ }
+
+ case MSG_PROFILE:
+ if (!params || !params[0]) {
+ fprintf(stderr,"MSG_PROFILE needs a parameter\n");
+ return(False);
+ }
+ if (strequal(params[0], "off")) {
+ v = 0;
+ } else if (strequal(params[0], "count")) {
+ v = 1;
+ } else if (strequal(params[0], "on")) {
+ v = 2;
+ } else if (strequal(params[0], "flush")) {
+ v = 3;
+ } else {
+ fprintf(stderr,
+ "MSG_PROFILE parameter must be off, count, on, or flush\n");
+ return(False);
+ }
+ send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
+ break;
+
+ case MSG_FORCE_ELECTION:
+ if (!strequal(dest, "nmbd")) {
+ fprintf(stderr,"force-election can only be sent to nmbd\n");
+ return(False);
+ }
+ send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
+ break;
+
+ case MSG_REQ_PROFILELEVEL:
+ if (!profilelevel_registered) {
+ message_register(MSG_PROFILELEVEL, profilelevel_function);
+ profilelevel_registered = True;
+ }
+ got_level = False;
+ retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
+ if (retval) {
+ timeout_start = time(NULL);
+ while (!got_level) {
+ message_dispatch();
+ if ((time(NULL) - timeout_start) > MAX_WAIT) {
+ fprintf(stderr,"profilelevel timeout\n");
+ break;
+ }
+ }
+ }
+ break;
+
+ case MSG_REQ_DEBUGLEVEL:
+ if (!debuglevel_registered) {
+ message_register(MSG_DEBUGLEVEL, debuglevel_function);
+ debuglevel_registered = True;
+ }
+ got_level = False;
+ retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
+ if (retval) {
+ timeout_start = time(NULL);
+ while (!got_level) {
+ message_dispatch();
+ if ((time(NULL) - timeout_start) > MAX_WAIT) {
+ fprintf(stderr,"debuglevel timeout\n");
+ break;
+ }
+ }
+ }
+ break;
+
+ case MSG_PRINTER_NOTIFY:
+ if (!strequal(dest, "smbd")) {
+ fprintf(stderr,"printer-notify can only be sent to smbd\n");
+ return(False);
+ }
+ if (!params || !params[0]) {
+ fprintf(stderr, "printer-notify needs a printer name\n");
+ return (False);
+ }
+ retval = send_message(dest, MSG_PRINTER_NOTIFY, params[0],
+ strlen(params[0]) + 1, False);
+ break;
+
+ case MSG_SMB_FORCE_TDIS:
+ if (!strequal(dest, "smbd")) {
+ fprintf(stderr,"close-share can only be sent to smbd\n");
+ return(False);
+ }
+ if (!params || !params[0]) {
+ fprintf(stderr, "close-share needs a share name or '*'\n");
+ return (False);
+ }
+ retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
+ strlen(params[0]) + 1, False);
+ break;
+
+ case MSG_SMB_SAM_SYNC:
+ if (!strequal(dest, "smbd")) {
+ fprintf(stderr, "samsync can only be sent to smbd\n");
+ return False;
+ }
+
+ if (params) {
+ fprintf(stderr, "samsync does not take any parameters\n");
+ return False;
+ }
+
+ retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
+
+ break;
+
+ case MSG_SMB_SAM_REPL: {
+ uint32 seqnum;
+
+ if (!strequal(dest, "smbd")) {
+ fprintf(stderr, "sam repl can only be sent to smbd\n");
+ return False;
+ }
+
+ if (!params || !params[0]) {
+ fprintf(stderr, "SAM_REPL needs a parameter\n");
+ return False;
+ }
+
+ seqnum = atoi(params[0]);
+
+ retval = send_message(dest, MSG_SMB_SAM_SYNC,
+ (char *)&seqnum, sizeof(uint32), False);
+
+ break;
+ }
+
+ case MSG_PING:
+ if (!pong_registered) {
+ message_register(MSG_PONG, pong_function);
+ pong_registered = True;
+ }
+ if (!params || !params[0]) {
+ fprintf(stderr,"MSG_PING needs a parameter\n");
+ return(False);
+ }
+ n = atoi(params[0]);
+ pong_count = 0;
+ for (i=0;i<n;i++) {
+ if (iparams > 1)
+ retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
+ else
+ retval = send_message(dest, MSG_PING, NULL, 0, True);
+ if (retval == False) break;
+ }
+ if (retval) {
+ timeout_start = time(NULL);
+ while (pong_count < n) {
+ message_dispatch();
+ if ((time(NULL) - timeout_start) > MAX_WAIT) {
+ fprintf(stderr,"PING timeout\n");
+ break;
+ }
+ }
+ }
+ break;
+
+ }
+
+ return (True);
+}
+
+ int main(int argc, char *argv[])
+{
+ int opt;
+ char temp[255];
+ extern int optind;
+ BOOL interactive = False;
+
+ setup_logging(argv[0],True);
+
+ if (argc < 2) usage(True);
+
+ while ((opt = getopt(argc, argv,"is:")) != EOF) {
+ switch (opt) {
+ case 'i':
+ interactive = True;
+ break;
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ usage(True);
+ }
+ }
+
+ lp_load(dyn_CONFIGFILE,False,False,False);
+
+ if (!message_init()) exit(1);
+
+ argc -= optind;
+ argv = &argv[optind];
+
+ if (!interactive) {
+ if (argc < 2) usage(True);
+ return (do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0));
+ }
+
+ while (True) {
+ char *myargv[4];
+ int myargc;
+
+ printf("smbcontrol> ");
+ if (!fgets(temp, sizeof(temp)-1, stdin)) break;
+ myargc = 0;
+ while ((myargc < 4) &&
+ (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
+ myargc++;
+ }
+ if (!myargc) break;
+ if (strequal(myargv[0],"q")) break;
+ if (myargc < 2)
+ usage(False);
+ else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
+ usage(False);
+ }
+ return(0);
+}
+
diff --git a/source/utils/smbfilter.c b/source/utils/smbfilter.c
new file mode 100644
index 00000000000..c7df7458d23
--- /dev/null
+++ b/source/utils/smbfilter.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2
+ SMB filter/socket plugin
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+#define SECURITY_MASK 0
+#define SECURITY_SET 0
+
+/* this forces non-unicode */
+#define CAPABILITY_MASK 0
+#define CAPABILITY_SET 0
+
+/* and non-unicode for the client too */
+#define CLI_CAPABILITY_MASK 0
+#define CLI_CAPABILITY_SET 0
+
+static char *netbiosname;
+static char packet[BUFFER_SIZE];
+
+static void save_file(const char *fname, void *packet, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ perror(fname);
+ return;
+ }
+ if (write(fd, packet, length) != length) {
+ fprintf(stderr,"Failed to write %s\n", fname);
+ return;
+ }
+ close(fd);
+ printf("Wrote %d bytes to %s\n", length, fname);
+}
+
+static void filter_reply(char *buf)
+{
+ int msg_type = CVAL(buf,0);
+ int type = CVAL(buf,smb_com);
+ unsigned x;
+
+ if (msg_type) return;
+
+ switch (type) {
+
+ case SMBnegprot:
+ /* force the security bits */
+ x = CVAL(buf, smb_vwv1);
+ x = (x | SECURITY_SET) & ~SECURITY_MASK;
+ SCVAL(buf, smb_vwv1, x);
+
+ /* force the capabilities */
+ x = IVAL(buf,smb_vwv9+1);
+ x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
+ SIVAL(buf, smb_vwv9+1, x);
+ break;
+
+ }
+}
+
+static void filter_request(char *buf)
+{
+ int msg_type = CVAL(buf,0);
+ int type = CVAL(buf,smb_com);
+ pstring name1,name2;
+ unsigned x;
+
+ if (msg_type) {
+ /* it's a netbios special */
+ switch (msg_type) {
+ case 0x81:
+ /* session request */
+ name_extract(buf,4,name1);
+ name_extract(buf,4 + name_len(buf + 4),name2);
+ d_printf("sesion_request: %s -> %s\n",
+ name1, name2);
+ if (netbiosname) {
+ /* replace the destination netbios name */
+ name_mangle(netbiosname, buf+4, 0x20);
+ }
+ }
+ return;
+ }
+
+ /* it's an ordinary SMB request */
+ switch (type) {
+ case SMBsesssetupX:
+ /* force the client capabilities */
+ x = IVAL(buf,smb_vwv11);
+ d_printf("SMBsesssetupX cap=0x%08x\n", x);
+ d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8));
+ system("mv sessionsetup.dat sessionsetup1.dat");
+ save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7));
+ x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
+ SIVAL(buf, smb_vwv11, x);
+ break;
+ }
+
+}
+
+
+static void filter_child(int c, struct in_addr dest_ip)
+{
+ int s;
+
+ /* we have a connection from a new client, now connect to the server */
+ s = open_socket_out(SOCK_STREAM, &dest_ip, 445, LONG_CONNECT_TIMEOUT);
+
+ if (s == -1) {
+ d_printf("Unable to connect to %s\n", inet_ntoa(dest_ip));
+ exit(1);
+ }
+
+ while (c != -1 || s != -1) {
+ fd_set fds;
+ int num;
+
+ FD_ZERO(&fds);
+ if (s != -1) FD_SET(s, &fds);
+ if (c != -1) FD_SET(c, &fds);
+
+ num = sys_select_intr(MAX(s+1, c+1),&fds,NULL);
+ if (num <= 0) continue;
+
+ if (c != -1 && FD_ISSET(c, &fds)) {
+ if (!receive_smb(c, packet, 0)) {
+ d_printf("client closed connection\n");
+ exit(0);
+ }
+ filter_request(packet);
+ if (!send_smb(s, packet)) {
+ d_printf("server is dead\n");
+ exit(1);
+ }
+ }
+ if (s != -1 && FD_ISSET(s, &fds)) {
+ if (!receive_smb(s, packet, 0)) {
+ d_printf("server closed connection\n");
+ exit(0);
+ }
+ filter_reply(packet);
+ if (!send_smb(c, packet)) {
+ d_printf("client is dead\n");
+ exit(1);
+ }
+ }
+ }
+ d_printf("Connection closed\n");
+ exit(0);
+}
+
+
+static void start_filter(char *desthost)
+{
+ int s, c;
+ struct in_addr dest_ip;
+
+ CatchChild();
+
+ /* start listening on port 445 locally */
+ s = open_socket_in(SOCK_STREAM, 445, 0, 0, True);
+
+ if (s == -1) {
+ d_printf("bind failed\n");
+ exit(1);
+ }
+
+ if (listen(s, 5) == -1) {
+ d_printf("listen failed\n");
+ }
+
+ if (!resolve_name(desthost, &dest_ip, 0x20)) {
+ d_printf("Unable to resolve host %s\n", desthost);
+ exit(1);
+ }
+
+ while (1) {
+ fd_set fds;
+ int num;
+ struct sockaddr addr;
+ socklen_t in_addrlen = sizeof(addr);
+
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+
+ num = sys_select_intr(s+1,&fds,NULL);
+ if (num > 0) {
+ c = accept(s, &addr, &in_addrlen);
+ if (c != -1) {
+ if (fork() == 0) {
+ close(s);
+ filter_child(c, dest_ip);
+ exit(0);
+ } else {
+ close(c);
+ }
+ }
+ }
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ char *desthost;
+ pstring configfile;
+
+ setup_logging(argv[0],True);
+
+ pstrcpy(configfile,dyn_CONFIGFILE);
+
+ if (argc < 2) {
+ fprintf(stderr,"smbfilter <desthost> <netbiosname>\n");
+ exit(1);
+ }
+
+ desthost = argv[1];
+ if (argc > 2) {
+ netbiosname = argv[2];
+ }
+
+ if (!lp_load(configfile,True,False,False)) {
+ d_printf("Unable to load config file\n");
+ }
+
+ start_filter(desthost);
+ return 0;
+}
diff --git a/source/utils/smbgroupedit.c b/source/utils/smbgroupedit.c
new file mode 100644
index 00000000000..f32f7b71291
--- /dev/null
+++ b/source/utils/smbgroupedit.c
@@ -0,0 +1,359 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern pstring global_myname;
+extern DOM_SID global_sam_sid;
+
+/*
+ * Next two lines needed for SunOS and don't
+ * hurt anything else...
+ */
+extern char *optarg;
+extern int optind;
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+static void usage(void)
+{
+ if (getuid() == 0) {
+ printf("smbgroupedit options\n");
+ } else {
+ printf("You need to be root to use this tool!\n");
+ }
+ printf("options:\n");
+ printf(" -a group create new group\n");
+ printf(" -n group NT group name\n");
+ printf(" -p privilege only local\n");
+ printf(" -v list groups\n");
+ printf(" -l long list (include details)\n");
+ printf(" -s short list (default)\n");
+ printf(" -c SID change group\n");
+ printf(" -u unix group\n");
+ printf(" -x group delete this group\n");
+ printf("\n");
+ printf(" -t[b|d|l] type: builtin, domain, local \n");
+ exit(1);
+}
+
+/*********************************************************
+ add a group.
+**********************************************************/
+int addgroup(char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *ntcomment, char *privilege)
+{
+ PRIVILEGE_SET se_priv;
+ gid_t gid;
+ DOM_SID sid;
+ fstring string_sid;
+ fstring name, comment;
+
+ gid=nametogid(group);
+ if (gid==-1)
+ return -1;
+
+ local_gid_to_sid(&sid, gid);
+ sid_to_string(string_sid, &sid);
+
+ if (ntgroup==NULL)
+ fstrcpy(name, group);
+ else
+ fstrcpy(name, ntgroup);
+
+ if (ntcomment==NULL)
+ fstrcpy(comment, "Local Unix group");
+ else
+ fstrcpy(comment, ntcomment);
+
+ init_privilege(&se_priv);
+ if (privilege!=NULL)
+ convert_priv_from_text(&se_priv, privilege);
+
+ if(!add_initial_entry(gid, string_sid, sid_type, name, comment, se_priv, PR_ACCESS_FROM_NETWORK)) {
+ free_privilege(&se_priv);
+ return -1;
+ }
+
+ free_privilege(&se_priv);
+ return 0;
+}
+
+/*********************************************************
+ Change a group.
+**********************************************************/
+int changegroup(char *sid_string, char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *groupdesc, char *privilege)
+{
+ DOM_SID sid;
+ GROUP_MAP map;
+ gid_t gid;
+
+ string_to_sid(&sid, sid_string);
+
+ /* Get the current mapping from the database */
+ if(!get_group_map_from_sid(sid, &map, MAPPING_WITH_PRIV)) {
+ printf("This SID does not exist in the database\n");
+ return -1;
+ }
+
+ /* If a new Unix group is specified, check and change */
+ if (group!=NULL) {
+ gid=nametogid(group);
+ if (gid==-1) {
+ printf("The UNIX group does not exist\n");
+ return -1;
+ } else
+ map.gid=gid;
+ }
+
+ /*
+ * Allow changing of group type only between domain and local
+ * We disallow changing Builtin groups !!! (SID problem)
+ */
+ if (sid_type==SID_NAME_ALIAS || sid_type==SID_NAME_DOM_GRP)
+ if (map.sid_name_use==SID_NAME_ALIAS || map.sid_name_use==SID_NAME_DOM_GRP)
+ map.sid_name_use=sid_type;
+
+
+ if (ntgroup!=NULL)
+ fstrcpy(map.nt_name, ntgroup);
+
+ /* Change comment if new one */
+ if (groupdesc!=NULL)
+ fstrcpy(map.comment, groupdesc);
+
+ /* Change the privilege if new one */
+ if (privilege!=NULL)
+ convert_priv_from_text(&map.priv_set, privilege);
+
+ if (!add_mapping_entry(&map, TDB_REPLACE)) {
+ printf("Count not update group database\n");
+ free_privilege(&map.priv_set);
+ return -1;
+ }
+
+ free_privilege(&map.priv_set);
+ return 0;
+}
+
+/*********************************************************
+ Delete the group.
+**********************************************************/
+BOOL deletegroup(char *group)
+{
+ DOM_SID sid;
+
+ string_to_sid(&sid, group);
+
+ if(!group_map_remove(sid))
+ return False;
+
+ return True;
+}
+
+/*********************************************************
+ List the groups.
+**********************************************************/
+int listgroup(enum SID_NAME_USE sid_type, BOOL long_list)
+{
+ int entries,i;
+ GROUP_MAP *map=NULL;
+ fstring string_sid;
+ fstring group_type;
+ fstring priv_text;
+
+ if (!long_list)
+ printf("NT group (SID) -> Unix group\n");
+
+ if (!enum_group_mapping(sid_type, &map, &entries, ENUM_ALL_MAPPED, MAPPING_WITH_PRIV))
+ return -1;
+
+ for (i=0; i<entries; i++) {
+ decode_sid_name_use(group_type, (map[i]).sid_name_use);
+ sid_to_string(string_sid, &map[i].sid);
+ convert_priv_to_text(&(map[i].priv_set), priv_text);
+ free_privilege(&(map[i].priv_set));
+
+ if (!long_list)
+ printf("%s (%s) -> %s\n", map[i].nt_name, string_sid, gidtoname(map[i].gid));
+ else {
+ printf("%s\n", map[i].nt_name);
+ printf("\tSID : %s\n", string_sid);
+ printf("\tUnix group: %s\n", gidtoname(map[i].gid));
+ printf("\tGroup type: %s\n", group_type);
+ printf("\tComment : %s\n", map[i].comment);
+ printf("\tPrivilege : %s\n\n", priv_text);
+ }
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Start here.
+**********************************************************/
+int main (int argc, char **argv)
+{
+ int ch;
+ BOOL add_group = False;
+ BOOL view_group = False;
+ BOOL change_group = False;
+ BOOL delete_group = False;
+ BOOL nt_group = False;
+ BOOL priv = False;
+ BOOL group_type = False;
+ BOOL long_list = False;
+
+ char *group = NULL;
+ char *sid = NULL;
+ char *ntgroup = NULL;
+ char *privilege = NULL;
+ char *groupt = NULL;
+ char *group_desc = NULL;
+
+ enum SID_NAME_USE sid_type;
+
+ setup_logging("groupedit", True);
+
+ if (argc < 2) {
+ usage();
+ return 0;
+ }
+
+ if(!initialize_password_db(True)) {
+ fprintf(stderr, "Can't setup password database vectors.\n");
+ exit(1);
+ }
+
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ dyn_CONFIGFILE);
+ exit(1);
+ }
+
+ if(pdb_generate_sam_sid()==False) {
+ printf("Can not read machine SID\n");
+ return 0;
+ }
+
+ if (init_group_mapping()==False) {
+ printf("Could not open tdb mapping file.\n");
+ return 0;
+ }
+
+ while ((ch = getopt(argc, argv, "a:c:d:ln:p:st:u:vx:")) != EOF) {
+ switch(ch) {
+ case 'a':
+ add_group = True;
+ group=optarg;
+ break;
+ case 'c':
+ change_group = True;
+ sid=optarg;
+ break;
+ case 'd':
+ group_desc=optarg;
+ break;
+ case 'l':
+ long_list = True;
+ break;
+ case 'n':
+ nt_group = True;
+ ntgroup=optarg;
+ break;
+ case 'p':
+ priv = True;
+ privilege=optarg;
+ break;
+ case 's':
+ long_list = False;
+ break;
+ case 't':
+ group_type = True;
+ groupt=optarg;
+ break;
+ case 'u':
+ group=optarg;
+ break;
+ case 'v':
+ view_group = True;
+ break;
+ case 'x':
+ delete_group = True;
+ group=optarg;
+ break;
+ /*default:
+ usage();*/
+ }
+ }
+
+
+ if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) > 1) {
+ fprintf (stderr, "Incompatible options on command line!\n");
+ usage();
+ exit(1);
+ }
+
+ /* no option on command line -> list groups */
+ if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) == 0)
+ view_group = True;
+
+
+ if (group_type==False)
+ sid_type=SID_NAME_UNKNOWN;
+ else {
+ switch (groupt[0]) {
+ case 'l':
+ case 'L':
+ sid_type=SID_NAME_ALIAS;
+ break;
+ case 'd':
+ case 'D':
+ sid_type=SID_NAME_DOM_GRP;
+ break;
+ case 'b':
+ case 'B':
+ sid_type=SID_NAME_WKN_GRP;
+ break;
+ default:
+ sid_type=SID_NAME_UNKNOWN;
+ break;
+ }
+ }
+
+ if (add_group)
+ return addgroup(group, sid_type, ntgroup, group_desc, privilege);
+
+ if (view_group)
+ return listgroup(sid_type, long_list);
+
+ if (delete_group)
+ return deletegroup(group);
+
+ if (change_group) {
+ return changegroup(sid, group, sid_type, ntgroup, group_desc, privilege);
+ }
+
+ usage();
+
+ return 0;
+}
diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c
index 167eb2ed5f3..3ee94661ab9 100644
--- a/source/utils/smbpasswd.c
+++ b/source/utils/smbpasswd.c
@@ -1,13 +1,12 @@
-#ifdef SMB_PASSWD
-
/*
- * Unix SMB/Netbios implementation. Version 1.9. smbpasswd module. Copyright
- * (C) Jeremy Allison 1995.
+ * Unix SMB/Netbios implementation.
+ * Copyright (C) Jeremy Allison 1995-1998
+ * Copyright (C) Tim Potter 2001
*
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@@ -16,441 +15,604 @@
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 675
- * Mass Ave, Cambridge, MA 02139, USA.
- */
+ * Mass Ave, Cambridge, MA 02139, USA. */
#include "includes.h"
-#include "des.h"
-/* Static buffers we will return. */
-static struct smb_passwd pw_buf;
-static pstring user_name;
-static unsigned char smbpwd[16];
-static unsigned char smbntpwd[16];
+extern pstring global_myname;
+
+/*
+ * Next two lines needed for SunOS and don't
+ * hurt anything else...
+ */
+extern char *optarg;
+extern int optind;
+
+/** forced running in root-mode **/
+static BOOL local_mode;
-static int gethexpwd(char *p, char *pwd)
+/**
+ * Print command usage on stderr and die.
+ **/
+static void usage(void)
{
- int i;
- unsigned char lonybble, hinybble;
- char *hexchars = "0123456789ABCDEF";
- char *p1, *p2;
- for (i = 0; i < 32; i += 2) {
- hinybble = toupper(p[i]);
- lonybble = toupper(p[i + 1]);
-
- p1 = strchr(hexchars, hinybble);
- p2 = strchr(hexchars, lonybble);
- if (!p1 || !p2)
- return (False);
-
- hinybble = PTR_DIFF(p1, hexchars);
- lonybble = PTR_DIFF(p2, hexchars);
-
- pwd[i / 2] = (hinybble << 4) | lonybble;
- }
- return (True);
+ printf("When run by root:\n");
+ printf(" smbpasswd [options] [username] [password]\n");
+ printf("otherwise:\n");
+ printf(" smbpasswd [options] [password]\n\n");
+
+ printf("options:\n");
+ printf(" -s use stdin for password prompt\n");
+ printf(" -D LEVEL debug level\n");
+ printf(" -U USER remote username\n");
+ printf(" -r MACHINE remote machine\n");
+
+ printf("extra options when run by root or in local mode:\n");
+ printf(" -L local mode (must be first option)\n");
+ printf(" -R ORDER name resolve order\n");
+ printf(" -a add user\n");
+ printf(" -x delete user\n");
+ printf(" -d disable user\n");
+ printf(" -e enable user\n");
+ printf(" -n set no password\n");
+ printf(" -m machine trust account\n");
+ printf(" -i interdomain trust account\n");
+#ifdef WITH_LDAP_SAM
+ printf(" -w ldap admin password\n");
+#endif
+
+ exit(1);
+}
+
+static void set_line_buffering(FILE *f)
+{
+ setvbuf(f, NULL, _IOLBF, 0);
}
-struct smb_passwd *
-_my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
- BOOL *got_valid_nt_entry, long *pwd_seekpos)
+/*************************************************************
+ Utility function to prompt for passwords from stdin. Each
+ password entered must end with a newline.
+*************************************************************/
+static char *stdin_new_passwd(void)
{
- char linebuf[256];
- unsigned char c;
- unsigned char *p;
- long uidval;
- long linebuf_len;
+ static fstring new_passwd;
+ size_t len;
+
+ ZERO_ARRAY(new_passwd);
/*
- * Scan the file, a line at a time and check if the name matches.
+ * if no error is reported from fgets() and string at least contains
+ * the newline that ends the password, then replace the newline with
+ * a null terminator.
*/
- while (!feof(fp)) {
- linebuf[0] = '\0';
- *pwd_seekpos = ftell(fp);
+ if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) {
+ if ((len = strlen(new_passwd)) > 0) {
+ if(new_passwd[len-1] == '\n')
+ new_passwd[len - 1] = 0;
+ }
+ }
+ return(new_passwd);
+}
- fgets(linebuf, 256, fp);
- if (ferror(fp))
- return NULL;
- /*
- * Check if the string is terminated with a newline - if not
- * then we must keep reading and discard until we get one.
- */
- linebuf_len = strlen(linebuf);
- if (linebuf[linebuf_len - 1] != '\n') {
- c = '\0';
- while (!ferror(fp) && !feof(fp)) {
- c = fgetc(fp);
- if (c == '\n')
- break;
+/*************************************************************
+ Utility function to get passwords via tty or stdin
+ Used if the '-s' option is set to silently get passwords
+ to enable scripting.
+*************************************************************/
+static char *get_pass( char *prompt, BOOL stdin_get)
+{
+ char *p;
+ if (stdin_get) {
+ p = stdin_new_passwd();
+ } else {
+ p = getpass(prompt);
+ }
+ return smb_xstrdup(p);
+}
+
+/*************************************************************
+ Utility function to prompt for new password.
+*************************************************************/
+static char *prompt_for_new_password(BOOL stdin_get)
+{
+ char *p;
+ fstring new_passwd;
+
+ ZERO_ARRAY(new_passwd);
+
+ p = get_pass("New SMB password:", stdin_get);
+
+ fstrcpy(new_passwd, p);
+ SAFE_FREE(p);
+
+ p = get_pass("Retype new SMB password:", stdin_get);
+
+ if (strcmp(p, new_passwd)) {
+ fprintf(stderr, "Mismatch - password unchanged.\n");
+ ZERO_ARRAY(new_passwd);
+ SAFE_FREE(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/*************************************************************
+ Change a password either locally or remotely.
+*************************************************************/
+
+static BOOL password_change(const char *remote_machine, char *user_name,
+ char *old_passwd, char *new_passwd, int local_flags)
+{
+ BOOL ret;
+ pstring err_str;
+ pstring msg_str;
+
+ if (remote_machine != NULL) {
+ if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
+ LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
+ /* these things can't be done remotely yet */
+ return False;
+ }
+ ret = remote_password_change(remote_machine, user_name,
+ old_passwd, new_passwd, err_str, sizeof(err_str));
+ if(*err_str)
+ fprintf(stderr, err_str);
+ return ret;
+ }
+
+ ret = local_password_change(user_name, local_flags, new_passwd,
+ err_str, sizeof(err_str), msg_str, sizeof(msg_str));
+
+ if(*msg_str)
+ printf(msg_str);
+ if(*err_str)
+ fprintf(stderr, err_str);
+
+ return ret;
+}
+
+#ifdef WITH_LDAP_SAM
+/*******************************************************************
+ Store the LDAP admin password in secrets.tdb
+ ******************************************************************/
+static BOOL store_ldap_admin_pw (char* pw)
+{
+ if (!pw)
+ return False;
+
+ if (!secrets_init())
+ return False;
+
+ return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw);
+}
+#endif
+
+/*************************************************************
+ Handle password changing for root.
+*************************************************************/
+
+static int process_root(int argc, char *argv[])
+{
+ struct passwd *pwd;
+ int result = 0, ch;
+ BOOL got_pass = False, got_username = False;
+ int local_flags = LOCAL_SET_PASSWORD;
+ BOOL stdin_passwd_get = False;
+ fstring user_name, user_password;
+ char *new_passwd = NULL;
+ char *old_passwd = NULL;
+ char *remote_machine = NULL;
+#ifdef WITH_LDAP_SAM
+ fstring ldap_secret;
+#endif
+
+ ZERO_STRUCT(user_name);
+ ZERO_STRUCT(user_password);
+
+ user_name[0] = '\0';
+
+ while ((ch = getopt(argc, argv, "axdehmnijr:swR:D:U:L")) != EOF) {
+ switch(ch) {
+ case 'L':
+ local_mode = True;
+ break;
+ case 'a':
+ local_flags |= LOCAL_ADD_USER;
+ break;
+ case 'x':
+ local_flags |= LOCAL_DELETE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'd':
+ local_flags |= LOCAL_DISABLE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'e':
+ local_flags |= LOCAL_ENABLE_USER;
+ local_flags &= ~LOCAL_SET_PASSWORD;
+ break;
+ case 'm':
+ local_flags |= LOCAL_TRUST_ACCOUNT;
+ break;
+ case 'i':
+ local_flags |= LOCAL_INTERDOM_ACCOUNT;
+ break;
+ case 'j':
+ d_printf("See 'net rpc join' for this functionality\n");
+ exit(1);
+ break;
+ case 'r':
+ remote_machine = optarg;
+ break;
+ case 's':
+ set_line_buffering(stdin);
+ set_line_buffering(stdout);
+ set_line_buffering(stderr);
+ stdin_passwd_get = True;
+ break;
+ case 'w':
+#ifdef WITH_LDAP_SAM
+ local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
+ fstrcpy(ldap_secret, optarg);
+ break;
+#else
+ printf("-w not available unless configured --with-ldap\n");
+ goto done;
+#endif
+ case 'R':
+ lp_set_name_resolve_order(optarg);
+ break;
+ case 'D':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'U': {
+ char *lp;
+
+ got_username = True;
+ fstrcpy(user_name, optarg);
+
+ if ((lp = strchr_m(user_name, '%'))) {
+ *lp = 0;
+ fstrcpy(user_password, lp + 1);
+ got_pass = True;
+ memset(strchr_m(optarg, '%') + 1, 'X',
+ strlen(user_password));
}
- } else
- linebuf[linebuf_len - 1] = '\0';
- if ((linebuf[0] == 0) && feof(fp))
break;
- /*
- * The line we have should be of the form :-
- *
- * username:uid:[32hex bytes]:....other flags presently
- * ignored....
- *
- * or,
- *
- * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
- *
- * if Windows NT compatible passwords are also present.
- */
+ }
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
- if (linebuf[0] == '#' || linebuf[0] == '\0')
- continue;
- p = (unsigned char *) strchr(linebuf, ':');
- if (p == NULL)
- continue;
- /*
- * As 256 is shorter than a pstring we don't need to check
- * length here - if this ever changes....
- */
- strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
- user_name[PTR_DIFF(p, linebuf)] = '\0';
- if (!strequal(user_name, name))
- continue;
+#ifdef WITH_LDAP_SAM
+ if (local_flags & LOCAL_SET_LDAP_ADMIN_PW)
+ {
+ printf("Setting stored password for \"%s\" in secrets.tdb\n",
+ lp_ldap_admin_dn());
+ if (!store_ldap_admin_pw(ldap_secret))
+ DEBUG(0,("ERROR: Failed to store the ldap admin password!\n"));
+ goto done;
+ }
+#endif
+ /*
+ * Ensure both add/delete user are not set
+ * Ensure add/delete user and either remote machine or join domain are
+ * not both set.
+ */
+ if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) ||
+ ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) &&
+ (remote_machine != NULL))) {
+ usage();
+ }
+
+ /* Only load interfaces if we are doing network operations. */
+
+ if (remote_machine) {
+ load_interfaces();
+ }
+
+ /*
+ * Deal with root - can add a user, but only locally.
+ */
- /* User name matches - get uid and password */
- p++; /* Go past ':' */
- if (!isdigit(*p))
- return (False);
+ switch(argc) {
+ case 0:
+ if (!got_username)
+ fstrcpy(user_name, "");
+ break;
+ case 1:
+ if (got_username)
+ usage();
+ fstrcpy(user_name, argv[0]);
+ break;
+ case 2:
+ if (got_username || got_pass)
+ usage();
+ fstrcpy(user_name, argv[0]);
+ new_passwd = smb_xstrdup(argv[1]);
+ break;
+ default:
+ usage();
+ }
- uidval = atoi((char *) p);
- while (*p && isdigit(*p))
- p++;
+ if (!user_name[0] && (pwd = sys_getpwuid(geteuid()))) {
+ fstrcpy(user_name, pwd->pw_name);
+ }
+
+ if (!user_name[0]) {
+ fprintf(stderr,"You must specify a username\n");
+ exit(1);
+ }
- if (*p != ':')
- return (False);
+ if (local_flags & LOCAL_TRUST_ACCOUNT) {
+ /* add the $ automatically */
+ static fstring buf;
/*
- * Now get the password value - this should be 32 hex digits
- * which are the ascii representations of a 16 byte string.
- * Get two at a time and put them into the password.
+ * Remove any trailing '$' before we
+ * generate the initial machine password.
*/
- p++;
- *pwd_seekpos += PTR_DIFF(p, linebuf); /* Save exact position
- * of passwd in file -
- * this is used by
- * smbpasswd.c */
- if (*p == '*' || *p == 'X') {
- /* Password deliberately invalid - end here. */
- *valid_old_pwd = False;
- *got_valid_nt_entry = False;
- pw_buf.smb_nt_passwd = NULL; /* No NT password (yet)*/
-
- /* Now check if the NT compatible password is
- available. */
- p += 33; /* Move to the first character of the line after
- the lanman password. */
- if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
- /* NT Entry was valid - even if 'X' or '*', can be overwritten */
- *got_valid_nt_entry = True;
- if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
- }
- }
- pw_buf.smb_name = user_name;
- pw_buf.smb_userid = uidval;
- pw_buf.smb_passwd = NULL; /* No password */
- return (&pw_buf);
+
+ if (user_name[strlen(user_name)-1] == '$') {
+ user_name[strlen(user_name)-1] = 0;
}
- if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
- return (False);
- if (p[32] != ':')
- return (False);
+ if (local_flags & LOCAL_ADD_USER) {
+ SAFE_FREE(new_passwd);
+ new_passwd = smb_xstrdup(user_name);
+ strlower(new_passwd);
+ }
- if (!strncasecmp(p, "NO PASSWORD", 11)) {
- pw_buf.smb_passwd = NULL; /* No password */
- } else {
- if(!gethexpwd(p,smbpwd))
- return False;
- pw_buf.smb_passwd = smbpwd;
+ /*
+ * Now ensure the username ends in '$' for
+ * the machine add.
+ */
+
+ slprintf(buf, sizeof(buf)-1, "%s$", user_name);
+ fstrcpy(user_name, buf);
+ } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+ static fstring buf;
+
+ if (local_flags & LOCAL_ADD_USER) {
+ /*
+ * Prompt for trusting domain's account password
+ */
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+ if(!new_passwd) {
+ fprintf(stderr, "Unable to get newpassword.\n");
+ exit(1);
+ }
}
+ slprintf(buf, sizeof(buf) - 1, "%s$", user_name);
+ fstrcpy(user_name, buf);
- pw_buf.smb_name = user_name;
- pw_buf.smb_userid = uidval;
- pw_buf.smb_nt_passwd = NULL;
- *got_valid_nt_entry = False;
- *valid_old_pwd = True;
-
- /* Now check if the NT compatible password is
- available. */
- p += 33; /* Move to the first character of the line after
- the lanman password. */
- if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
- /* NT Entry was valid - even if 'X' or '*', can be overwritten */
- *got_valid_nt_entry = True;
- if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
+ } else {
+
+ if (remote_machine != NULL) {
+ old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
+ }
+
+ if (!(local_flags & LOCAL_SET_PASSWORD)) {
+
+ /*
+ * If we are trying to enable a user, first we need to find out
+ * if they are using a modern version of the smbpasswd file that
+ * disables a user by just writing a flag into the file. If so
+ * then we can re-enable a user without prompting for a new
+ * password. If not (ie. they have a no stored password in the
+ * smbpasswd file) then we need to prompt for a new password.
+ */
+
+ if(local_flags & LOCAL_ENABLE_USER) {
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+ ret = pdb_getsampwnam(sampass, user_name);
+ if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) {
+ local_flags |= LOCAL_SET_PASSWORD;
+ }
+ pdb_free_sam(&sampass);
}
}
- return &pw_buf;
+
+ if(local_flags & LOCAL_SET_PASSWORD) {
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+
+ if(!new_passwd) {
+ fprintf(stderr, "Unable to get new password.\n");
+ exit(1);
+ }
+ }
+ }
+
+ if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) {
+ fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
+ result = 1;
+ goto done;
+ }
+
+ if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
+ SAM_ACCOUNT *sampass = NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sampass);
+ ret = pdb_getsampwnam(sampass, user_name);
+
+ printf("Password changed for user %s.", user_name );
+ if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) )
+ printf(" User has disabled flag set.");
+ if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) )
+ printf(" User has no password flag set.");
+ printf("\n");
+ pdb_free_sam(&sampass);
}
- return NULL;
+
+ done:
+ SAFE_FREE(new_passwd);
+ return result;
}
-/*
- * Print command usage on stderr and die.
- */
-void
-usage(char *name)
+
+/**
+ handle password changing for non-root
+**/
+static int process_nonroot(int argc, char *argv[])
{
- fprintf(stderr, "Usage is : %s [username]\n", name);
- exit(1);
+ struct passwd *pwd = NULL;
+ int result = 0, ch;
+ BOOL stdin_passwd_get = False;
+ char *old_passwd = NULL;
+ char *remote_machine = NULL;
+ char *user_name = NULL;
+ char *new_passwd = NULL;
+
+ while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
+ switch(ch) {
+ case 'D':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'r':
+ remote_machine = optarg;
+ break;
+ case 's':
+ set_line_buffering(stdin);
+ set_line_buffering(stdout);
+ set_line_buffering(stderr);
+ stdin_passwd_get = True;
+ break;
+ case 'U':
+ user_name = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc > 1) {
+ usage();
+ }
+
+ if (argc == 1) {
+ new_passwd = argv[0];
+ }
+
+ if (!user_name) {
+ pwd = sys_getpwuid(getuid());
+ if (pwd) {
+ user_name = smb_xstrdup(pwd->pw_name);
+ } else {
+ fprintf(stderr, "smbpasswd: you don't exist - go away\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * A non-root user is always setting a password
+ * via a remote machine (even if that machine is
+ * localhost).
+ */
+
+ load_interfaces(); /* Delayed from main() */
+
+ if (remote_machine == NULL) {
+ remote_machine = "127.0.0.1";
+ }
+
+ if (remote_machine != NULL) {
+ old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
+ }
+
+ if (!new_passwd) {
+ new_passwd = prompt_for_new_password(stdin_passwd_get);
+ }
+
+ if (!new_passwd) {
+ fprintf(stderr, "Unable to get new password.\n");
+ exit(1);
+ }
+
+ if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) {
+ fprintf(stderr,"Failed to change password for %s\n", user_name);
+ result = 1;
+ goto done;
+ }
+
+ printf("Password changed for user %s\n", user_name);
+
+ done:
+ SAFE_FREE(old_passwd);
+ SAFE_FREE(new_passwd);
+
+ return result;
}
+
+
+/*********************************************************
+ Start here.
+**********************************************************/
int main(int argc, char **argv)
-{
- int real_uid;
- struct passwd *pwd;
- fstring old_passwd;
- uchar old_p16[16];
- uchar old_nt_p16[16];
- fstring new_passwd;
- uchar new_p16[16];
- uchar new_nt_p16[16];
- char *p;
- struct smb_passwd *smb_pwent;
- FILE *fp;
- BOOL valid_old_pwd = False;
- BOOL got_valid_nt_entry = False;
- long seekpos;
- int pwfd;
- char ascii_p16[66];
- char c;
- int ret, i, err, writelen;
- int lockfd = -1;
- char *pfile = SMB_PASSWD_FILE;
- char readbuf[16 * 1024];
-
- setup_logging(argv[0],True);
-
- charset_initialise();
-
-#ifndef DEBUG_PASSWORD
- /* Check the effective uid */
- if (geteuid() != 0) {
- fprintf(stderr, "%s: Must be setuid root.\n", argv[0]);
- exit(1);
- }
-#endif
-
- /* Get the real uid */
- real_uid = getuid();
-
- /* Deal with usage problems */
- if (real_uid == 0) {
- /* As root we can change anothers password. */
- if (argc != 1 && argc != 2)
- usage(argv[0]);
- } else if (argc != 1)
- usage(argv[0]);
-
-
- if (real_uid == 0 && argc == 2) {
- /* If we are root we can change anothers password. */
- strncpy(user_name, argv[1], sizeof(user_name) - 1);
- user_name[sizeof(user_name) - 1] = '\0';
- pwd = getpwnam(user_name);
- } else {
- pwd = getpwuid(real_uid);
- }
-
- if (pwd == 0) {
- fprintf(stderr, "%s: Unable to get UNIX password entry for user.\n", argv[0]);
- exit(1);
- }
- /* If we are root we don't ask for the old password. */
- old_passwd[0] = '\0';
- if (real_uid != 0) {
- p = getpass("Old SMB password:");
- strncpy(old_passwd, p, sizeof(fstring));
- old_passwd[sizeof(fstring)-1] = '\0';
- }
- new_passwd[0] = '\0';
- p = getpass("New SMB password:");
- strncpy(new_passwd, p, sizeof(fstring));
- new_passwd[sizeof(fstring)-1] = '\0';
- p = getpass("Retype new SMB password:");
- if (strcmp(p, new_passwd)) {
- fprintf(stderr, "%s: Mismatch - password unchanged.\n", argv[0]);
- exit(1);
- }
-
- if (new_passwd[0] == '\0') {
- printf("Password not set\n");
- exit(0);
- }
-
- /* Calculate the MD4 hash (NT compatible) of the old and new passwords */
- memset(old_nt_p16, '\0', 16);
- E_md4hash((uchar *)old_passwd, old_nt_p16);
-
- memset(new_nt_p16, '\0', 16);
- E_md4hash((uchar *) new_passwd, new_nt_p16);
-
- /* Mangle the passwords into Lanman format */
- old_passwd[14] = '\0';
- strupper(old_passwd);
- new_passwd[14] = '\0';
- strupper(new_passwd);
-
- /*
- * Calculate the SMB (lanman) hash functions of both old and new passwords.
- */
-
- memset(old_p16, '\0', 16);
- E_P16((uchar *) old_passwd, old_p16);
-
- memset(new_p16, '\0', 16);
- E_P16((uchar *) new_passwd, new_p16);
-
- /*
- * Open the smbpaswd file XXXX - we need to parse smb.conf to get the
- * filename
- */
- if ((fp = fopen(pfile, "r+")) == NULL) {
- err = errno;
- fprintf(stderr, "%s: Failed to open password file %s.\n",
- argv[0], pfile);
- errno = err;
- perror(argv[0]);
- exit(err);
- }
- /* Set read buffer to 16k for effiecient reads */
- setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
-
- /* make sure it is only rw by the owner */
- chmod(pfile, 0600);
-
- /* Lock the smbpasswd file for write. */
- if ((lockfd = pw_file_lock(pfile, F_WRLCK, 5)) < 0) {
- err = errno;
- fprintf(stderr, "%s: Failed to lock password file %s.\n",
- argv[0], pfile);
- fclose(fp);
- errno = err;
- perror(argv[0]);
- exit(err);
- }
- /* Get the smb passwd entry for this user */
- smb_pwent = _my_get_smbpwnam(fp, pwd->pw_name, &valid_old_pwd,
- &got_valid_nt_entry, &seekpos);
- if (smb_pwent == NULL) {
- fprintf(stderr, "%s: Failed to find entry for user %s in file %s.\n",
- argv[0], pwd->pw_name, pfile);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- /* If we are root we don't need to check the old password. */
- if (real_uid != 0) {
- if ((valid_old_pwd == False) || (smb_pwent->smb_passwd == NULL)) {
- fprintf(stderr, "%s: User %s is disabled, plase contact your administrator to enable it.\n", argv[0], pwd->pw_name);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- /* Check the old Lanman password */
- if (memcmp(old_p16, smb_pwent->smb_passwd, 16)) {
- fprintf(stderr, "%s: Couldn't change password.\n", argv[0]);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- /* Check the NT password if it exists */
- if (smb_pwent->smb_nt_passwd != NULL) {
- if (memcmp(old_nt_p16, smb_pwent->smb_nt_passwd, 16)) {
- fprintf(stderr, "%s: Couldn't change password.\n", argv[0]);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- }
- }
- /*
- * If we get here either we were root or the old password checked out
- * ok.
- */
- /* Create the 32 byte representation of the new p16 */
- for (i = 0; i < 16; i++) {
- sprintf(&ascii_p16[i * 2], "%02X", (uchar) new_p16[i]);
- }
- if(got_valid_nt_entry) {
- /* Add on the NT md4 hash */
- ascii_p16[32] = ':';
- for (i = 0; i < 16; i++) {
- sprintf(&ascii_p16[(i * 2)+33], "%02X", (uchar) new_nt_p16[i]);
- }
- }
- /*
- * Do an atomic write into the file at the position defined by
- * seekpos.
- */
- pwfd = fileno(fp);
- ret = lseek(pwfd, seekpos - 1, SEEK_SET);
- if (ret != seekpos - 1) {
- err = errno;
- fprintf(stderr, "%s: seek fail on file %s.\n",
- argv[0], pfile);
- fclose(fp);
- errno = err;
- perror(argv[0]);
- pw_file_unlock(lockfd);
- exit(1);
- }
- /* Sanity check - ensure the character is a ':' */
- if (read(pwfd, &c, 1) != 1) {
- err = errno;
- fprintf(stderr, "%s: read fail on file %s.\n",
- argv[0], pfile);
- fclose(fp);
- errno = err;
- perror(argv[0]);
- pw_file_unlock(lockfd);
- exit(1);
- }
- if (c != ':') {
- fprintf(stderr, "%s: sanity check on passwd file %s failed.\n",
- argv[0], pfile);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- writelen = (got_valid_nt_entry) ? 65 : 32;
- if (write(pwfd, ascii_p16, writelen) != writelen) {
- err = errno;
- fprintf(stderr, "%s: write fail in file %s.\n",
- argv[0], pfile);
- fclose(fp);
- errno = err;
- perror(argv[0]);
- pw_file_unlock(lockfd);
- exit(err);
- }
- fclose(fp);
- pw_file_unlock(lockfd);
- printf("Password changed\n");
- return 0;
-}
+{
+#if defined(HAVE_SET_AUTH_PARAMETERS)
+ set_auth_parameters(argc, argv);
+#endif /* HAVE_SET_AUTH_PARAMETERS */
-#else
+ setup_logging("smbpasswd", True);
+
+ if(!initialize_password_db(True)) {
+ fprintf(stderr, "Can't setup password database vectors.\n");
+ exit(1);
+ }
-#include "includes.h"
+ if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ dyn_CONFIGFILE);
+ exit(1);
+ }
-int
-main(int argc, char **argv)
-{
- printf("smb password encryption not selected in Makefile\n");
- return 0;
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
+
+ if (!*global_myname) {
+ char *p;
+ fstrcpy(global_myname, myhostname());
+ p = strchr_m(global_myname, '.' );
+ if (p) *p = 0;
+ }
+ strupper(global_myname);
+
+ /* Check the effective uid - make sure we are not setuid */
+ if (is_setuid_root()) {
+ fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
+ exit(1);
+ }
+
+ /* pre-check for local mode option as first option. We can't
+ do this via normal getopt as getopt can't be called
+ twice. */
+ if (argc > 1 && strcmp(argv[1], "-L") == 0) {
+ local_mode = True;
+ }
+
+ if (local_mode || getuid() == 0) {
+ secrets_init();
+ return process_root(argc, argv);
+ }
+
+ return process_nonroot(argc, argv);
}
-#endif
diff --git a/source/utils/smbtree.c b/source/utils/smbtree.c
new file mode 100644
index 00000000000..b06920418d6
--- /dev/null
+++ b/source/utils/smbtree.c
@@ -0,0 +1,424 @@
+/*
+ Unix SMB/Netbios implementation.
+ Network neighbourhood browser.
+ Version 3.0
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static BOOL use_bcast;
+
+struct user_auth_info {
+ pstring username;
+ pstring password;
+ pstring workgroup;
+};
+
+/* How low can we go? */
+
+enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE};
+enum tree_level level = LEV_SHARE;
+
+static void usage(void)
+{
+ printf(
+"Usage: smbtree [options]\n\
+\n\
+\t-d debuglevel set debug output level\n\
+\t-U username user to autheticate as\n\
+\t-W workgroup workgroup of user to authenticate as\n\
+\t-D list only domains (workgroups) of tree\n\
+\t-S list domains and servers of tree\n\
+\t-b use bcast instead of using the master browser\n\
+\n\
+The username can be of the form username%%password or\n\
+workgroup\\username%%password.\n\n\
+");
+}
+
+/* Holds a list of workgroups or servers */
+
+struct name_list {
+ struct name_list *prev, *next;
+ pstring name, comment;
+ uint32 server_type;
+};
+
+static struct name_list *workgroups, *servers, *shares;
+
+static void free_name_list(struct name_list *list)
+{
+ while(list)
+ DLIST_REMOVE(list, list);
+}
+
+static void add_name(const char *machine_name, uint32 server_type,
+ const char *comment, void *state)
+{
+ struct name_list **name_list = (struct name_list **)state;
+ struct name_list *new_name;
+
+ new_name = (struct name_list *)malloc(sizeof(struct name_list));
+
+ if (!new_name)
+ return;
+
+ ZERO_STRUCTP(new_name);
+
+ pstrcpy(new_name->name, machine_name);
+ pstrcpy(new_name->comment, comment);
+ new_name->server_type = server_type;
+
+ DLIST_ADD(*name_list, new_name);
+}
+
+/* Return a cli_state pointing at the IPC$ share for the given workgroup */
+
+static struct cli_state *get_ipc_connect(char *server,
+ struct user_auth_info *user_info)
+{
+ struct nmb_name calling, called;
+ struct in_addr server_ip;
+ struct cli_state *cli;
+ pstring myname;
+
+ zero_ip(&server_ip);
+
+ get_myname(myname);
+
+ make_nmb_name(&called, myname, 0x0);
+ make_nmb_name(&calling, server, 0x20);
+
+ if (is_ipaddress(server))
+ if (!resolve_name(server, &server_ip, 0x20))
+ return False;
+
+ again:
+ if (!(cli = cli_initialise(NULL))) {
+ DEBUG(4, ("Unable to initialise cli structure\n"));
+ goto error;
+ }
+
+ if (!cli_connect(cli, server, &server_ip)) {
+ DEBUG(4, ("Unable to connect to %s\n", server));
+ goto error;
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ cli_shutdown(cli);
+ if (!strequal(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ DEBUG(4, ("Session request failed to %s\n", called.name));
+ goto error;
+ }
+
+ if (!cli_negprot(cli)) {
+ DEBUG(4, ("Negprot failed\n"));
+ goto error;
+ }
+
+ if (!cli_session_setup(cli, user_info->username, user_info->password,
+ strlen(user_info->password),
+ user_info->password,
+ strlen(user_info->password), server) &&
+ /* try an anonymous login if it failed */
+ !cli_session_setup(cli, "", "", 1,"", 0, server)) {
+ DEBUG(4, ("Session setup failed\n"));
+ goto error;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(cli, "IPC$", "?????",
+ user_info->password,
+ strlen(user_info->password)+1)) {
+ DEBUG(4, ("Tconx failed\n"));
+ goto error;
+ }
+
+ return cli;
+
+ /* Clean up after error */
+
+ error:
+ if (cli && cli->initialised)
+ cli_shutdown(cli);
+
+ return NULL;
+}
+
+/* Return the IP address and workgroup of a master browser on the
+ network. */
+
+static BOOL find_master_ip_bcast(pstring workgroup, struct in_addr *server_ip)
+{
+ struct in_addr *ip_list;
+ int i, count;
+
+ /* Go looking for workgroups by broadcasting on the local network */
+
+ if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
+ return False;
+ }
+
+ for (i = 0; i < count; i++) {
+ static fstring name;
+
+ if (!name_status_find("*", 0, 0x1d, ip_list[i], name))
+ continue;
+
+ if (!find_master_ip(name, server_ip))
+ continue;
+
+ pstrcpy(workgroup, name);
+
+ DEBUG(4, ("found master browser %s, %s\n",
+ name, inet_ntoa(ip_list[i])));
+
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ display tree of smb workgroups, servers and shares
+****************************************************************************/
+static BOOL get_workgroups(struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+ struct in_addr server_ip;
+ pstring master_workgroup;
+
+ /* Try to connect to a #1d name of our current workgroup. If that
+ doesn't work broadcast for a master browser and then jump off
+ that workgroup. */
+
+ pstrcpy(master_workgroup, lp_workgroup());
+
+ if (use_bcast || !find_master_ip(lp_workgroup(), &server_ip)) {
+ DEBUG(4, ("Unable to find master browser for workgroup %s\n",
+ master_workgroup));
+ if (!find_master_ip_bcast(master_workgroup, &server_ip)) {
+ DEBUG(4, ("Unable to find master browser by "
+ "broadcast\n"));
+ return False;
+ }
+ }
+
+ if (!(cli = get_ipc_connect(inet_ntoa(server_ip), user_info)))
+ return False;
+
+ if (!cli_NetServerEnum(cli, master_workgroup,
+ SV_TYPE_DOMAIN_ENUM, add_name, &workgroups))
+ return False;
+
+ return True;
+}
+
+/* Retrieve the list of servers for a given workgroup */
+
+static BOOL get_servers(char *workgroup, struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+ struct in_addr server_ip;
+
+ /* Open an IPC$ connection to the master browser for the workgroup */
+
+ if (!find_master_ip(workgroup, &server_ip)) {
+ DEBUG(4, ("Cannot find master browser for workgroup %s\n",
+ workgroup));
+ return False;
+ }
+
+ if (!(cli = get_ipc_connect(inet_ntoa(server_ip), user_info)))
+ return False;
+
+ if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name,
+ &servers))
+ return False;
+
+ return True;
+}
+
+static BOOL get_shares(char *server_name, struct user_auth_info *user_info)
+{
+ struct cli_state *cli;
+
+ if (!(cli = get_ipc_connect(server_name, user_info)))
+ return False;
+
+ if (!cli_RNetShareEnum(cli, add_name, &shares))
+ return False;
+
+ return True;
+}
+
+static BOOL print_tree(struct user_auth_info *user_info)
+{
+ struct name_list *wg, *sv, *sh;
+
+ /* List workgroups */
+
+ if (!get_workgroups(user_info))
+ return False;
+
+ for (wg = workgroups; wg; wg = wg->next) {
+
+ printf("%s\n", wg->name);
+
+ /* List servers */
+
+ free_name_list(servers);
+ servers = NULL;
+
+ if (level == LEV_WORKGROUP ||
+ !get_servers(wg->name, user_info))
+ continue;
+
+ for (sv = servers; sv; sv = sv->next) {
+
+ printf("\t\\\\%-15s\t\t%s\n",
+ sv->name, sv->comment);
+
+ /* List shares */
+
+ free_name_list(shares);
+ shares = NULL;
+
+ if (level == LEV_SERVER ||
+ !get_shares(sv->name, user_info))
+ continue;
+
+ for (sh = shares; sh; sh = sh->next) {
+ printf("\t\t\\\\%s\\%-15s\t%s\n",
+ sv->name, sh->name, sh->comment);
+ }
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *p;
+ struct user_auth_info user_info;
+ BOOL got_pass = False;
+
+ /* Initialise samba stuff */
+
+ setlinebuf(stdout);
+
+ dbf = x_stderr;
+
+ setup_logging(argv[0],True);
+
+ lp_load(dyn_CONFIGFILE,True,False,False);
+ load_interfaces();
+
+ if (getenv("USER")) {
+ pstrcpy(user_info.username, getenv("USER"));
+
+ if ((p=strchr(user_info.username, '%'))) {
+ *p = 0;
+ pstrcpy(user_info.password, p+1);
+ got_pass = True;
+ memset(strchr(getenv("USER"), '%') + 1, 'X',
+ strlen(user_info.password));
+ }
+ }
+
+ pstrcpy(user_info.workgroup, lp_workgroup());
+
+ /* Parse command line args */
+
+ while ((opt = getopt(argc, argv, "U:hd:W:DSb")) != EOF) {
+ switch (opt) {
+ case 'U':
+ pstrcpy(user_info.username,optarg);
+ p = strchr(user_info.username,'%');
+ if (p) {
+ *p = 0;
+ pstrcpy(user_info.password, p+1);
+ got_pass = 1;
+ }
+ break;
+
+ case 'b':
+ use_bcast = True;
+ break;
+
+ case 'h':
+ usage();
+ exit(1);
+
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+
+ case 'W':
+ pstrcpy(user_info.workgroup, optarg);
+ break;
+
+ case 'D':
+ level = LEV_WORKGROUP;
+ break;
+
+ case 'S':
+ level = LEV_SERVER;
+ break;
+
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ usage();
+ exit(1);
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(user_info.password, pass);
+ }
+ got_pass = True;
+ }
+
+ /* Now do our stuff */
+
+ if (!print_tree(&user_info))
+ return 1;
+
+ return 0;
+}
diff --git a/source/utils/smbw_sample.c b/source/utils/smbw_sample.c
new file mode 100644
index 00000000000..5cd792df7a2
--- /dev/null
+++ b/source/utils/smbw_sample.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+static void usage(void)
+{
+ printf("
+smbw_sample - a sample program that uses smbw
+
+smbw_sample <options> path
+
+ options:
+ -W workgroup
+ -l logfile
+ -P prefix
+ -d debuglevel
+ -U username%%password
+ -R resolve order
+
+note that path must start with /smb/
+");
+}
+
+int main(int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *dent;
+ int opt;
+ char *p;
+ extern char *optarg;
+ extern int optind;
+ char *path;
+
+ lp_load(dyn_CONFIGFILE,1,0,0);
+ smbw_setup_shared();
+
+ while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) {
+ switch (opt) {
+ case 'W':
+ smbw_setshared("WORKGROUP", optarg);
+ break;
+ case 'l':
+ smbw_setshared("LOGFILE", optarg);
+ break;
+ case 'P':
+ smbw_setshared("PREFIX", optarg);
+ break;
+ case 'd':
+ smbw_setshared("DEBUG", optarg);
+ break;
+ case 'U':
+ p = strchr_m(optarg,'%');
+ if (p) {
+ *p=0;
+ smbw_setshared("PASSWORD",p+1);
+ }
+ smbw_setshared("USER", optarg);
+ break;
+ case 'R':
+ smbw_setshared("RESOLVE_ORDER",optarg);
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ path = argv[0];
+
+ smbw_init();
+
+ dir = smbw_opendir(path);
+ if (!dir) {
+ printf("failed to open %s\n", path);
+ exit(1);
+ }
+
+ while ((dent = smbw_readdir(dir))) {
+ printf("%s\n", dent->d_name);
+ }
+ smbw_closedir(dir);
+ return 0;
+}
diff --git a/source/utils/status.c b/source/utils/status.c
index ed0ae532114..e17a6589efe 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
status reporting
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,242 +17,662 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ 21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe)
+ Added -L (locks only) -S (shares only) flags and code
+
*/
/*
* This program reports current SMB connections
*/
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
+#define NO_SYSLOG
#include "includes.h"
-#include "loadparm.h"
-struct connect_record crec;
-extern int DEBUGLEVEL;
-extern FILE *dbf;
+struct session_record{
+ pid_t pid;
+ uid_t uid;
+ char machine[31];
+ time_t start;
+ struct session_record *next;
+} *srecs;
static pstring Ucrit_username = ""; /* added by OH */
-int Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */
-int Ucrit_MaxPid=0; /* added by OH */
-unsigned int Ucrit_IsActive = 0; /* added by OH */
-void Ucrit_addUsername(pstring username); /* added by OH */
-unsigned int Ucrit_checkUsername(pstring username); /* added by OH */
-void Ucrit_addPid(int pid); /* added by OH */
-unsigned int Ucrit_checkPid(int pid); /* added by OH */
-
-int main(int argc, char *argv[])
+static pid_t Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */
+static int Ucrit_MaxPid=0; /* added by OH */
+static unsigned int Ucrit_IsActive = 0; /* added by OH */
+static int verbose, brief;
+static int shares_only = 0; /* Added by RJS */
+static int locks_only = 0; /* Added by RJS */
+static BOOL processes_only=False;
+static int show_brl;
+
+/* we need these because we link to locking*.o */
+ void become_root(void) {}
+ void unbecome_root(void) {}
+
+
+/* added by OH */
+static void Ucrit_addUsername(char *username)
+{
+ pstrcpy(Ucrit_username, username);
+ if(strlen(Ucrit_username) > 0)
+ Ucrit_IsActive = 1;
+}
+
+static unsigned int Ucrit_checkUsername(char *username)
+{
+ if ( !Ucrit_IsActive) return 1;
+ if (strcmp(Ucrit_username,username) ==0) return 1;
+ return 0;
+}
+
+static unsigned int Ucrit_checkPid(pid_t pid)
{
- FILE *f;
- pstring fname;
- int uid, c, n;
- static pstring servicesf = CONFIGFILE;
- extern char *optarg;
- int verbose = 0;
- void *dir;
- char *s;
- BOOL firstopen=True;
- BOOL processes_only=False;
- int last_pid=0;
-
- setup_logging(argv[0],True);
-
- charset_initialise();
-
- DEBUGLEVEL = 0;
- dbf = fopen("/dev/null","w");
-
- if (getuid() != geteuid()) {
- printf("smbstatus should not be run setuid\n");
- return(1);
- }
-
- while ((c = getopt(argc, argv, "pdsu:")) != EOF) {
- switch (c) {
- case 'd':
- verbose = 1;
- break;
- case 'p':
- processes_only = 1;
- break;
- case 's':
- strcpy(servicesf, optarg);
- break;
- case 'u': /* added by OH */
- Ucrit_addUsername(optarg); /* added by OH */
- break;
- default:
- fprintf(stderr, "Usage: %s [-d] [-p] [-s configfile] [-u username]\n", *argv); /* changed by OH */
- return (-1);
- }
- }
-
-
-
- if (!lp_load(servicesf,False)) {
- fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
- return (-1);
- }
-
- if (verbose) {
- printf("using configfile = %s\n", servicesf);
- printf("lockdir = %s\n", *lp_lockdir() ? lp_lockdir() : "NULL");
- }
-
- strcpy(fname,lp_lockdir());
- standard_sub_basic(fname);
- trim_string(fname,"","/");
- strcat(fname,"/STATUS..LCK");
-
- f = fopen(fname,"r");
- if (!f) {
- printf("Couldn't open status file %s\n",fname);
- if (!lp_status(-1))
- printf("You need to have status=yes in your smb config file\n");
- return(0);
- }
-
- uid = getuid();
-
- if (!processes_only) {
- printf("\nSamba version %s\n",VERSION);
-
- printf("Service uid gid pid machine\n");
- printf("----------------------------------------------\n");
- }
-
- while (!feof(f))
- {
- if (fread(&crec,sizeof(crec),1,f) != 1)
- break;
- if ( crec.magic == 0x280267 && process_exists(crec.pid)
- && Ucrit_checkUsername(uidtoname(crec.uid)) /* added by OH */
- )
- {
- Ucrit_addPid(crec.pid); /* added by OH */
- if (processes_only) {
- if (last_pid != crec.pid)
- printf("%d\n",crec.pid);
- last_pid = crec.pid; /* XXXX we can still get repeats, have to
- add a sort at some time */
+ int i;
+ if ( !Ucrit_IsActive) return 1;
+ for (i=0;i<Ucrit_MaxPid;i++)
+ if( pid == Ucrit_pid[i] ) return 1;
+ return 0;
+}
+
+
+static void print_share_mode(share_mode_entry *e, char *fname)
+{
+ static int count;
+ if (count==0) {
+ d_printf("Locked files:\n");
+ d_printf("Pid DenyMode R/W Oplock Name\n");
+ d_printf("--------------------------------------------------\n");
+ }
+ count++;
+
+ if (Ucrit_checkPid(e->pid)) {
+ d_printf("%-5d ",(int)e->pid);
+ switch (GET_DENY_MODE(e->share_mode)) {
+ case DENY_NONE: d_printf("DENY_NONE "); break;
+ case DENY_ALL: d_printf("DENY_ALL "); break;
+ case DENY_DOS: d_printf("DENY_DOS "); break;
+ case DENY_READ: d_printf("DENY_READ "); break;
+ case DENY_WRITE:printf("DENY_WRITE "); break;
+ case DENY_FCB: d_printf("DENY_FCB "); break;
+ }
+ switch (e->share_mode&0xF) {
+ case 0: d_printf("RDONLY "); break;
+ case 1: d_printf("WRONLY "); break;
+ case 2: d_printf("RDWR "); break;
+ }
+
+ if((e->op_type &
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ d_printf("EXCLUSIVE+BATCH ");
+ else if (e->op_type & EXCLUSIVE_OPLOCK)
+ d_printf("EXCLUSIVE ");
+ else if (e->op_type & BATCH_OPLOCK)
+ d_printf("BATCH ");
+ else if (e->op_type & LEVEL_II_OPLOCK)
+ d_printf("LEVEL_II ");
+ else
+ d_printf("NONE ");
+
+ d_printf(" %s %s",fname,
+ asctime(LocalTime((time_t *)&e->time.tv_sec)));
}
- else
- printf("%-10.10s %-8s %-8s %5d %-8s (%s) %s",
- crec.name,uidtoname(crec.uid),gidtoname(crec.gid),crec.pid,
- crec.machine,crec.addr,
- asctime(LocalTime(&crec.start,GMT_TO_LOCAL)));
- }
- }
- fclose(f);
-
- if (processes_only) exit(0);
-
- printf("\n");
-
- dir = opendir(lp_lockdir());
- if (!dir) return(0);
- while ((s=readdirname(dir))) {
- char buf[16];
- int pid,mode;
- time_t t;
- int fd;
- pstring lname;
- int dev,inode;
-
- if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
-
- strcpy(lname,lp_lockdir());
- trim_string(lname,NULL,"/");
- strcat(lname,"/");
- strcat(lname,s);
-
- fd = open(lname,O_RDONLY,0);
- if (fd < 0) continue;
- if (read(fd,buf,16) != 16) continue;
- n = read(fd,fname,sizeof(fname));
- fname[MAX(n,0)]=0;
- close(fd);
-
- t = IVAL(buf,0);
- mode = IVAL(buf,4);
- pid = IVAL(buf,8);
-
- if ( !Ucrit_checkPid(pid) ) /* added by OH */
- continue;
-
- if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
- if (unlink(lname)==0)
- printf("Deleted stale share file %s\n",s);
- continue;
- }
-
- fname[sizeof(fname)-1] = 0;
-
- if (firstopen) {
- firstopen=False;
- printf("Locked files:\n");
- printf("Pid DenyMode R/W Name\n");
- printf("------------------------------\n");
- }
-
-
- printf("%-5d ",pid);
- switch ((mode>>4)&0xF)
- {
- case DENY_NONE: printf("DENY_NONE "); break;
- case DENY_ALL: printf("DENY_ALL "); break;
- case DENY_DOS: printf("DENY_DOS "); break;
- case DENY_READ: printf("DENY_READ "); break;
- case DENY_WRITE:printf("DENY_WRITE "); break;
- }
- switch (mode&0xF)
- {
- case 0: printf("RDONLY "); break;
- case 1: printf("WRONLY "); break;
- case 2: printf("RDWR "); break;
- }
- printf(" %s %s",fname,asctime(LocalTime(&t,GMT_TO_LOCAL)));
- }
- closedir(dir);
-
- if (firstopen)
- printf("No locked files\n");
-
- return (0);
}
-/* added by OH */
-void Ucrit_addUsername(pstring username)
+static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
+ enum brl_type lock_type,
+ br_off start, br_off size)
{
- strcpy(Ucrit_username, username);
- if(strlen(Ucrit_username) > 0)
- Ucrit_IsActive = 1;
+ static int count;
+ if (count==0) {
+ d_printf("Byte range locks:\n");
+ d_printf(" Pid dev:inode R/W start size\n");
+ d_printf("------------------------------------------------\n");
+ }
+ count++;
+
+ d_printf("%6d %05x:%05x %s %9.0f %9.0f\n",
+ (int)pid, (int)dev, (int)ino,
+ lock_type==READ_LOCK?"R":"W",
+ (double)start, (double)size);
}
-unsigned int Ucrit_checkUsername(pstring username)
+
+/*******************************************************************
+ dump the elements of the profile structure
+ ******************************************************************/
+static int profile_dump(void)
{
- if ( !Ucrit_IsActive) return 1;
- if (strcmp(Ucrit_username,username) ==0) return 1;
- return 0;
+ if (!profile_setup(True)) {
+ fprintf(stderr,"Failed to initialise profile memory\n");
+ return -1;
+ }
+
+ d_printf("smb_count: %u\n", profile_p->smb_count);
+ d_printf("uid_changes: %u\n", profile_p->uid_changes);
+ d_printf("************************ System Calls ****************************\n");
+ d_printf("opendir_count: %u\n", profile_p->syscall_opendir_count);
+ d_printf("opendir_time: %u\n", profile_p->syscall_opendir_time);
+ d_printf("readdir_count: %u\n", profile_p->syscall_readdir_count);
+ d_printf("readdir_time: %u\n", profile_p->syscall_readdir_time);
+ d_printf("mkdir_count: %u\n", profile_p->syscall_mkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->syscall_mkdir_time);
+ d_printf("rmdir_count: %u\n", profile_p->syscall_rmdir_count);
+ d_printf("rmdir_time: %u\n", profile_p->syscall_rmdir_time);
+ d_printf("closedir_count: %u\n", profile_p->syscall_closedir_count);
+ d_printf("closedir_time: %u\n", profile_p->syscall_closedir_time);
+ d_printf("open_count: %u\n", profile_p->syscall_open_count);
+ d_printf("open_time: %u\n", profile_p->syscall_open_time);
+ d_printf("close_count: %u\n", profile_p->syscall_close_count);
+ d_printf("close_time: %u\n", profile_p->syscall_close_time);
+ d_printf("read_count: %u\n", profile_p->syscall_read_count);
+ d_printf("read_time: %u\n", profile_p->syscall_read_time);
+ d_printf("read_bytes: %u\n", profile_p->syscall_read_bytes);
+ d_printf("write_count: %u\n", profile_p->syscall_write_count);
+ d_printf("write_time: %u\n", profile_p->syscall_write_time);
+ d_printf("write_bytes: %u\n", profile_p->syscall_write_bytes);
+ d_printf("lseek_count: %u\n", profile_p->syscall_lseek_count);
+ d_printf("lseek_time: %u\n", profile_p->syscall_lseek_time);
+ d_printf("rename_count: %u\n", profile_p->syscall_rename_count);
+ d_printf("rename_time: %u\n", profile_p->syscall_rename_time);
+ d_printf("fsync_count: %u\n", profile_p->syscall_fsync_count);
+ d_printf("fsync_time: %u\n", profile_p->syscall_fsync_time);
+ d_printf("stat_count: %u\n", profile_p->syscall_stat_count);
+ d_printf("stat_time: %u\n", profile_p->syscall_stat_time);
+ d_printf("fstat_count: %u\n", profile_p->syscall_fstat_count);
+ d_printf("fstat_time: %u\n", profile_p->syscall_fstat_time);
+ d_printf("lstat_count: %u\n", profile_p->syscall_lstat_count);
+ d_printf("lstat_time: %u\n", profile_p->syscall_lstat_time);
+ d_printf("unlink_count: %u\n", profile_p->syscall_unlink_count);
+ d_printf("unlink_time: %u\n", profile_p->syscall_unlink_time);
+ d_printf("chmod_count: %u\n", profile_p->syscall_chmod_count);
+ d_printf("chmod_time: %u\n", profile_p->syscall_chmod_time);
+ d_printf("fchmod_count: %u\n", profile_p->syscall_fchmod_count);
+ d_printf("fchmod_time: %u\n", profile_p->syscall_fchmod_time);
+ d_printf("chown_count: %u\n", profile_p->syscall_chown_count);
+ d_printf("chown_time: %u\n", profile_p->syscall_chown_time);
+ d_printf("fchown_count: %u\n", profile_p->syscall_fchown_count);
+ d_printf("fchown_time: %u\n", profile_p->syscall_fchown_time);
+ d_printf("chdir_count: %u\n", profile_p->syscall_chdir_count);
+ d_printf("chdir_time: %u\n", profile_p->syscall_chdir_time);
+ d_printf("getwd_count: %u\n", profile_p->syscall_getwd_count);
+ d_printf("getwd_time: %u\n", profile_p->syscall_getwd_time);
+ d_printf("utime_count: %u\n", profile_p->syscall_utime_count);
+ d_printf("utime_time: %u\n", profile_p->syscall_utime_time);
+ d_printf("ftruncate_count: %u\n", profile_p->syscall_ftruncate_count);
+ d_printf("ftruncate_time: %u\n", profile_p->syscall_ftruncate_time);
+ d_printf("fcntl_lock_count: %u\n", profile_p->syscall_fcntl_lock_count);
+ d_printf("fcntl_lock_time: %u\n", profile_p->syscall_fcntl_lock_time);
+ d_printf("readlink_count: %u\n", profile_p->syscall_readlink_count);
+ d_printf("readlink_time: %u\n", profile_p->syscall_readlink_time);
+ d_printf("symlink_count: %u\n", profile_p->syscall_symlink_count);
+ d_printf("symlink_time: %u\n", profile_p->syscall_symlink_time);
+ d_printf("************************ Statcache *******************************\n");
+ d_printf("lookups: %u\n", profile_p->statcache_lookups);
+ d_printf("misses: %u\n", profile_p->statcache_misses);
+ d_printf("hits: %u\n", profile_p->statcache_hits);
+ d_printf("************************ Writecache ******************************\n");
+ d_printf("read_hits: %u\n", profile_p->writecache_read_hits);
+ d_printf("abutted_writes: %u\n", profile_p->writecache_abutted_writes);
+ d_printf("total_writes: %u\n", profile_p->writecache_total_writes);
+ d_printf("non_oplock_writes: %u\n", profile_p->writecache_non_oplock_writes);
+ d_printf("direct_writes: %u\n", profile_p->writecache_direct_writes);
+ d_printf("init_writes: %u\n", profile_p->writecache_init_writes);
+ d_printf("flushed_writes[SEEK]: %u\n", profile_p->writecache_flushed_writes[SEEK_FLUSH]);
+ d_printf("flushed_writes[READ]: %u\n", profile_p->writecache_flushed_writes[READ_FLUSH]);
+ d_printf("flushed_writes[WRITE]: %u\n", profile_p->writecache_flushed_writes[WRITE_FLUSH]);
+ d_printf("flushed_writes[READRAW]: %u\n", profile_p->writecache_flushed_writes[READRAW_FLUSH]);
+ d_printf("flushed_writes[OPLOCK_RELEASE]: %u\n", profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH]);
+ d_printf("flushed_writes[CLOSE]: %u\n", profile_p->writecache_flushed_writes[CLOSE_FLUSH]);
+ d_printf("flushed_writes[SYNC]: %u\n", profile_p->writecache_flushed_writes[SYNC_FLUSH]);
+ d_printf("flushed_writes[SIZECHANGE]: %u\n", profile_p->writecache_flushed_writes[SIZECHANGE_FLUSH]);
+ d_printf("num_perfect_writes: %u\n", profile_p->writecache_num_perfect_writes);
+ d_printf("num_write_caches: %u\n", profile_p->writecache_num_write_caches);
+ d_printf("allocated_write_caches: %u\n", profile_p->writecache_allocated_write_caches);
+ d_printf("************************ SMB Calls *******************************\n");
+ d_printf("mkdir_count: %u\n", profile_p->SMBmkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->SMBmkdir_time);
+ d_printf("rmdir_count: %u\n", profile_p->SMBrmdir_count);
+ d_printf("rmdir_time: %u\n", profile_p->SMBrmdir_time);
+ d_printf("open_count: %u\n", profile_p->SMBopen_count);
+ d_printf("open_time: %u\n", profile_p->SMBopen_time);
+ d_printf("create_count: %u\n", profile_p->SMBcreate_count);
+ d_printf("create_time: %u\n", profile_p->SMBcreate_time);
+ d_printf("close_count: %u\n", profile_p->SMBclose_count);
+ d_printf("close_time: %u\n", profile_p->SMBclose_time);
+ d_printf("flush_count: %u\n", profile_p->SMBflush_count);
+ d_printf("flush_time: %u\n", profile_p->SMBflush_time);
+ d_printf("unlink_count: %u\n", profile_p->SMBunlink_count);
+ d_printf("unlink_time: %u\n", profile_p->SMBunlink_time);
+ d_printf("mv_count: %u\n", profile_p->SMBmv_count);
+ d_printf("mv_time: %u\n", profile_p->SMBmv_time);
+ d_printf("getatr_count: %u\n", profile_p->SMBgetatr_count);
+ d_printf("getatr_time: %u\n", profile_p->SMBgetatr_time);
+ d_printf("setatr_count: %u\n", profile_p->SMBsetatr_count);
+ d_printf("setatr_time: %u\n", profile_p->SMBsetatr_time);
+ d_printf("read_count: %u\n", profile_p->SMBread_count);
+ d_printf("read_time: %u\n", profile_p->SMBread_time);
+ d_printf("write_count: %u\n", profile_p->SMBwrite_count);
+ d_printf("write_time: %u\n", profile_p->SMBwrite_time);
+ d_printf("lock_count: %u\n", profile_p->SMBlock_count);
+ d_printf("lock_time: %u\n", profile_p->SMBlock_time);
+ d_printf("unlock_count: %u\n", profile_p->SMBunlock_count);
+ d_printf("unlock_time: %u\n", profile_p->SMBunlock_time);
+ d_printf("ctemp_count: %u\n", profile_p->SMBctemp_count);
+ d_printf("ctemp_time: %u\n", profile_p->SMBctemp_time);
+ d_printf("mknew_count: %u\n", profile_p->SMBmknew_count);
+ d_printf("mknew_time: %u\n", profile_p->SMBmknew_time);
+ d_printf("chkpth_count: %u\n", profile_p->SMBchkpth_count);
+ d_printf("chkpth_time: %u\n", profile_p->SMBchkpth_time);
+ d_printf("exit_count: %u\n", profile_p->SMBexit_count);
+ d_printf("exit_time: %u\n", profile_p->SMBexit_time);
+ d_printf("lseek_count: %u\n", profile_p->SMBlseek_count);
+ d_printf("lseek_time: %u\n", profile_p->SMBlseek_time);
+ d_printf("lockread_count: %u\n", profile_p->SMBlockread_count);
+ d_printf("lockread_time: %u\n", profile_p->SMBlockread_time);
+ d_printf("writeunlock_count: %u\n", profile_p->SMBwriteunlock_count);
+ d_printf("writeunlock_time: %u\n", profile_p->SMBwriteunlock_time);
+ d_printf("readbraw_count: %u\n", profile_p->SMBreadbraw_count);
+ d_printf("readbraw_time: %u\n", profile_p->SMBreadbraw_time);
+ d_printf("readBmpx_count: %u\n", profile_p->SMBreadBmpx_count);
+ d_printf("readBmpx_time: %u\n", profile_p->SMBreadBmpx_time);
+ d_printf("readBs_count: %u\n", profile_p->SMBreadBs_count);
+ d_printf("readBs_time: %u\n", profile_p->SMBreadBs_time);
+ d_printf("writebraw_count: %u\n", profile_p->SMBwritebraw_count);
+ d_printf("writebraw_time: %u\n", profile_p->SMBwritebraw_time);
+ d_printf("writeBmpx_count: %u\n", profile_p->SMBwriteBmpx_count);
+ d_printf("writeBmpx_time: %u\n", profile_p->SMBwriteBmpx_time);
+ d_printf("writeBs_count: %u\n", profile_p->SMBwriteBs_count);
+ d_printf("writeBs_time: %u\n", profile_p->SMBwriteBs_time);
+ d_printf("writec_count: %u\n", profile_p->SMBwritec_count);
+ d_printf("writec_time: %u\n", profile_p->SMBwritec_time);
+ d_printf("setattrE_count: %u\n", profile_p->SMBsetattrE_count);
+ d_printf("setattrE_time: %u\n", profile_p->SMBsetattrE_time);
+ d_printf("getattrE_count: %u\n", profile_p->SMBgetattrE_count);
+ d_printf("getattrE_time: %u\n", profile_p->SMBgetattrE_time);
+ d_printf("lockingX_count: %u\n", profile_p->SMBlockingX_count);
+ d_printf("lockingX_time: %u\n", profile_p->SMBlockingX_time);
+ d_printf("trans_count: %u\n", profile_p->SMBtrans_count);
+ d_printf("trans_time: %u\n", profile_p->SMBtrans_time);
+ d_printf("transs_count: %u\n", profile_p->SMBtranss_count);
+ d_printf("transs_time: %u\n", profile_p->SMBtranss_time);
+ d_printf("ioctl_count: %u\n", profile_p->SMBioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->SMBioctl_time);
+ d_printf("ioctls_count: %u\n", profile_p->SMBioctls_count);
+ d_printf("ioctls_time: %u\n", profile_p->SMBioctls_time);
+ d_printf("copy_count: %u\n", profile_p->SMBcopy_count);
+ d_printf("copy_time: %u\n", profile_p->SMBcopy_time);
+ d_printf("move_count: %u\n", profile_p->SMBmove_count);
+ d_printf("move_time: %u\n", profile_p->SMBmove_time);
+ d_printf("echo_count: %u\n", profile_p->SMBecho_count);
+ d_printf("echo_time: %u\n", profile_p->SMBecho_time);
+ d_printf("writeclose_count: %u\n", profile_p->SMBwriteclose_count);
+ d_printf("writeclose_time: %u\n", profile_p->SMBwriteclose_time);
+ d_printf("openX_count: %u\n", profile_p->SMBopenX_count);
+ d_printf("openX_time: %u\n", profile_p->SMBopenX_time);
+ d_printf("readX_count: %u\n", profile_p->SMBreadX_count);
+ d_printf("readX_time: %u\n", profile_p->SMBreadX_time);
+ d_printf("writeX_count: %u\n", profile_p->SMBwriteX_count);
+ d_printf("writeX_time: %u\n", profile_p->SMBwriteX_time);
+ d_printf("trans2_count: %u\n", profile_p->SMBtrans2_count);
+ d_printf("trans2_time: %u\n", profile_p->SMBtrans2_time);
+ d_printf("transs2_count: %u\n", profile_p->SMBtranss2_count);
+ d_printf("transs2_time: %u\n", profile_p->SMBtranss2_time);
+ d_printf("findclose_count: %u\n", profile_p->SMBfindclose_count);
+ d_printf("findclose_time: %u\n", profile_p->SMBfindclose_time);
+ d_printf("findnclose_count: %u\n", profile_p->SMBfindnclose_count);
+ d_printf("findnclose_time: %u\n", profile_p->SMBfindnclose_time);
+ d_printf("tcon_count: %u\n", profile_p->SMBtcon_count);
+ d_printf("tcon_time: %u\n", profile_p->SMBtcon_time);
+ d_printf("tdis_count: %u\n", profile_p->SMBtdis_count);
+ d_printf("tdis_time: %u\n", profile_p->SMBtdis_time);
+ d_printf("negprot_count: %u\n", profile_p->SMBnegprot_count);
+ d_printf("negprot_time: %u\n", profile_p->SMBnegprot_time);
+ d_printf("sesssetupX_count: %u\n", profile_p->SMBsesssetupX_count);
+ d_printf("sesssetupX_time: %u\n", profile_p->SMBsesssetupX_time);
+ d_printf("ulogoffX_count: %u\n", profile_p->SMBulogoffX_count);
+ d_printf("ulogoffX_time: %u\n", profile_p->SMBulogoffX_time);
+ d_printf("tconX_count: %u\n", profile_p->SMBtconX_count);
+ d_printf("tconX_time: %u\n", profile_p->SMBtconX_time);
+ d_printf("dskattr_count: %u\n", profile_p->SMBdskattr_count);
+ d_printf("dskattr_time: %u\n", profile_p->SMBdskattr_time);
+ d_printf("search_count: %u\n", profile_p->SMBsearch_count);
+ d_printf("search_time: %u\n", profile_p->SMBsearch_time);
+ d_printf("ffirst_count: %u\n", profile_p->SMBffirst_count);
+ d_printf("ffirst_time: %u\n", profile_p->SMBffirst_time);
+ d_printf("funique_count: %u\n", profile_p->SMBfunique_count);
+ d_printf("funique_time: %u\n", profile_p->SMBfunique_time);
+ d_printf("fclose_count: %u\n", profile_p->SMBfclose_count);
+ d_printf("fclose_time: %u\n", profile_p->SMBfclose_time);
+ d_printf("nttrans_count: %u\n", profile_p->SMBnttrans_count);
+ d_printf("nttrans_time: %u\n", profile_p->SMBnttrans_time);
+ d_printf("nttranss_count: %u\n", profile_p->SMBnttranss_count);
+ d_printf("nttranss_time: %u\n", profile_p->SMBnttranss_time);
+ d_printf("ntcreateX_count: %u\n", profile_p->SMBntcreateX_count);
+ d_printf("ntcreateX_time: %u\n", profile_p->SMBntcreateX_time);
+ d_printf("ntcancel_count: %u\n", profile_p->SMBntcancel_count);
+ d_printf("ntcancel_time: %u\n", profile_p->SMBntcancel_time);
+ d_printf("splopen_count: %u\n", profile_p->SMBsplopen_count);
+ d_printf("splopen_time: %u\n", profile_p->SMBsplopen_time);
+ d_printf("splwr_count: %u\n", profile_p->SMBsplwr_count);
+ d_printf("splwr_time: %u\n", profile_p->SMBsplwr_time);
+ d_printf("splclose_count: %u\n", profile_p->SMBsplclose_count);
+ d_printf("splclose_time: %u\n", profile_p->SMBsplclose_time);
+ d_printf("splretq_count: %u\n", profile_p->SMBsplretq_count);
+ d_printf("splretq_time: %u\n", profile_p->SMBsplretq_time);
+ d_printf("sends_count: %u\n", profile_p->SMBsends_count);
+ d_printf("sends_time: %u\n", profile_p->SMBsends_time);
+ d_printf("sendb_count: %u\n", profile_p->SMBsendb_count);
+ d_printf("sendb_time: %u\n", profile_p->SMBsendb_time);
+ d_printf("fwdname_count: %u\n", profile_p->SMBfwdname_count);
+ d_printf("fwdname_time: %u\n", profile_p->SMBfwdname_time);
+ d_printf("cancelf_count: %u\n", profile_p->SMBcancelf_count);
+ d_printf("cancelf_time: %u\n", profile_p->SMBcancelf_time);
+ d_printf("getmac_count: %u\n", profile_p->SMBgetmac_count);
+ d_printf("getmac_time: %u\n", profile_p->SMBgetmac_time);
+ d_printf("sendstrt_count: %u\n", profile_p->SMBsendstrt_count);
+ d_printf("sendstrt_time: %u\n", profile_p->SMBsendstrt_time);
+ d_printf("sendend_count: %u\n", profile_p->SMBsendend_count);
+ d_printf("sendend_time: %u\n", profile_p->SMBsendend_time);
+ d_printf("sendtxt_count: %u\n", profile_p->SMBsendtxt_count);
+ d_printf("sendtxt_time: %u\n", profile_p->SMBsendtxt_time);
+ d_printf("invalid_count: %u\n", profile_p->SMBinvalid_count);
+ d_printf("invalid_time: %u\n", profile_p->SMBinvalid_time);
+ d_printf("************************ Pathworks Calls *************************\n");
+ d_printf("setdir_count: %u\n", profile_p->pathworks_setdir_count);
+ d_printf("setdir_time: %u\n", profile_p->pathworks_setdir_time);
+ d_printf("************************ Trans2 Calls ****************************\n");
+ d_printf("open_count: %u\n", profile_p->Trans2_open_count);
+ d_printf("open_time: %u\n", profile_p->Trans2_open_time);
+ d_printf("findfirst_count: %u\n", profile_p->Trans2_findfirst_count);
+ d_printf("findfirst_time: %u\n", profile_p->Trans2_findfirst_time);
+ d_printf("findnext_count: %u\n", profile_p->Trans2_findnext_count);
+ d_printf("findnext_time: %u\n", profile_p->Trans2_findnext_time);
+ d_printf("qfsinfo_count: %u\n", profile_p->Trans2_qfsinfo_count);
+ d_printf("qfsinfo_time: %u\n", profile_p->Trans2_qfsinfo_time);
+ d_printf("setfsinfo_count: %u\n", profile_p->Trans2_setfsinfo_count);
+ d_printf("setfsinfo_time: %u\n", profile_p->Trans2_setfsinfo_time);
+ d_printf("qpathinfo_count: %u\n", profile_p->Trans2_qpathinfo_count);
+ d_printf("qpathinfo_time: %u\n", profile_p->Trans2_qpathinfo_time);
+ d_printf("setpathinfo_count: %u\n", profile_p->Trans2_setpathinfo_count);
+ d_printf("setpathinfo_time: %u\n", profile_p->Trans2_setpathinfo_time);
+ d_printf("qfileinfo_count: %u\n", profile_p->Trans2_qfileinfo_count);
+ d_printf("qfileinfo_time: %u\n", profile_p->Trans2_qfileinfo_time);
+ d_printf("setfileinfo_count: %u\n", profile_p->Trans2_setfileinfo_count);
+ d_printf("setfileinfo_time: %u\n", profile_p->Trans2_setfileinfo_time);
+ d_printf("fsctl_count: %u\n", profile_p->Trans2_fsctl_count);
+ d_printf("fsctl_time: %u\n", profile_p->Trans2_fsctl_time);
+ d_printf("ioctl_count: %u\n", profile_p->Trans2_ioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->Trans2_ioctl_time);
+ d_printf("findnotifyfirst_count: %u\n", profile_p->Trans2_findnotifyfirst_count);
+ d_printf("findnotifyfirst_time: %u\n", profile_p->Trans2_findnotifyfirst_time);
+ d_printf("findnotifynext_count: %u\n", profile_p->Trans2_findnotifynext_count);
+ d_printf("findnotifynext_time: %u\n", profile_p->Trans2_findnotifynext_time);
+ d_printf("mkdir_count: %u\n", profile_p->Trans2_mkdir_count);
+ d_printf("mkdir_time: %u\n", profile_p->Trans2_mkdir_time);
+ d_printf("session_setup_count: %u\n", profile_p->Trans2_session_setup_count);
+ d_printf("session_setup_time: %u\n", profile_p->Trans2_session_setup_time);
+ d_printf("get_dfs_referral_count: %u\n", profile_p->Trans2_get_dfs_referral_count);
+ d_printf("get_dfs_referral_time: %u\n", profile_p->Trans2_get_dfs_referral_time);
+ d_printf("report_dfs_inconsistancy_count: %u\n", profile_p->Trans2_report_dfs_inconsistancy_count);
+ d_printf("report_dfs_inconsistancy_time: %u\n", profile_p->Trans2_report_dfs_inconsistancy_time);
+ d_printf("************************ NT Transact Calls ***********************\n");
+ d_printf("create_count: %u\n", profile_p->NT_transact_create_count);
+ d_printf("create_time: %u\n", profile_p->NT_transact_create_time);
+ d_printf("ioctl_count: %u\n", profile_p->NT_transact_ioctl_count);
+ d_printf("ioctl_time: %u\n", profile_p->NT_transact_ioctl_time);
+ d_printf("set_security_desc_count: %u\n", profile_p->NT_transact_set_security_desc_count);
+ d_printf("set_security_desc_time: %u\n", profile_p->NT_transact_set_security_desc_time);
+ d_printf("notify_change_count: %u\n", profile_p->NT_transact_notify_change_count);
+ d_printf("notify_change_time: %u\n", profile_p->NT_transact_notify_change_time);
+ d_printf("rename_count: %u\n", profile_p->NT_transact_rename_count);
+ d_printf("rename_time: %u\n", profile_p->NT_transact_rename_time);
+ d_printf("query_security_desc_count: %u\n", profile_p->NT_transact_query_security_desc_count);
+ d_printf("query_security_desc_time: %u\n", profile_p->NT_transact_query_security_desc_time);
+ d_printf("************************ ACL Calls *******************************\n");
+ d_printf("get_nt_acl_count: %u\n", profile_p->get_nt_acl_count);
+ d_printf("get_nt_acl_time: %u\n", profile_p->get_nt_acl_time);
+ d_printf("fget_nt_acl_count: %u\n", profile_p->fget_nt_acl_count);
+ d_printf("fget_nt_acl_time: %u\n", profile_p->fget_nt_acl_time);
+ d_printf("set_nt_acl_count: %u\n", profile_p->set_nt_acl_count);
+ d_printf("set_nt_acl_time: %u\n", profile_p->set_nt_acl_time);
+ d_printf("fset_nt_acl_count: %u\n", profile_p->fset_nt_acl_count);
+ d_printf("fset_nt_acl_time: %u\n", profile_p->fset_nt_acl_time);
+ d_printf("chmod_acl_count: %u\n", profile_p->chmod_acl_count);
+ d_printf("chmod_acl_time: %u\n", profile_p->chmod_acl_time);
+ d_printf("fchmod_acl_count: %u\n", profile_p->fchmod_acl_count);
+ d_printf("fchmod_acl_time: %u\n", profile_p->fchmod_acl_time);
+ d_printf("************************ NMBD Calls ****************************\n");
+ d_printf("name_release_count: %u\n", profile_p->name_release_count);
+ d_printf("name_release_time: %u\n", profile_p->name_release_time);
+ d_printf("name_refresh_count: %u\n", profile_p->name_refresh_count);
+ d_printf("name_refresh_time: %u\n", profile_p->name_refresh_time);
+ d_printf("name_registration_count: %u\n", profile_p->name_registration_count);
+ d_printf("name_registration_time: %u\n", profile_p->name_registration_time);
+ d_printf("node_status_count: %u\n", profile_p->node_status_count);
+ d_printf("node_status_time: %u\n", profile_p->node_status_time);
+ d_printf("name_query_count: %u\n", profile_p->name_query_count);
+ d_printf("name_query_time: %u\n", profile_p->name_query_time);
+ d_printf("host_announce_count: %u\n", profile_p->host_announce_count);
+ d_printf("host_announce_time: %u\n", profile_p->host_announce_time);
+ d_printf("workgroup_announce_count: %u\n", profile_p->workgroup_announce_count);
+ d_printf("workgroup_announce_time: %u\n", profile_p->workgroup_announce_time);
+ d_printf("local_master_announce_count: %u\n", profile_p->local_master_announce_count);
+ d_printf("local_master_announce_time: %u\n", profile_p->local_master_announce_time);
+ d_printf("master_browser_announce_count: %u\n", profile_p->master_browser_announce_count);
+ d_printf("master_browser_announce_time: %u\n", profile_p->master_browser_announce_time);
+ d_printf("lm_host_announce_count: %u\n", profile_p->lm_host_announce_count);
+ d_printf("lm_host_announce_time: %u\n", profile_p->lm_host_announce_time);
+ d_printf("get_backup_list_count: %u\n", profile_p->get_backup_list_count);
+ d_printf("get_backup_list_time: %u\n", profile_p->get_backup_list_time);
+ d_printf("reset_browser_count: %u\n", profile_p->reset_browser_count);
+ d_printf("reset_browser_time: %u\n", profile_p->reset_browser_time);
+ d_printf("announce_request_count: %u\n", profile_p->announce_request_count);
+ d_printf("announce_request_time: %u\n", profile_p->announce_request_time);
+ d_printf("lm_announce_request_count: %u\n", profile_p->lm_announce_request_count);
+ d_printf("lm_announce_request_time: %u\n", profile_p->lm_announce_request_time);
+ d_printf("domain_logon_count: %u\n", profile_p->domain_logon_count);
+ d_printf("domain_logon_time: %u\n", profile_p->domain_logon_time);
+ d_printf("sync_browse_lists_count: %u\n", profile_p->sync_browse_lists_count);
+ d_printf("sync_browse_lists_time: %u\n", profile_p->sync_browse_lists_time);
+ d_printf("run_elections_count: %u\n", profile_p->run_elections_count);
+ d_printf("run_elections_time: %u\n", profile_p->run_elections_time);
+ d_printf("election_count: %u\n", profile_p->election_count);
+ d_printf("election_time: %u\n", profile_p->election_time);
+
+ return 0;
}
-void Ucrit_addPid(int pid)
+
+static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
{
- int i;
- if ( !Ucrit_IsActive) return;
- for (i=0;i<Ucrit_MaxPid;i++)
- if( pid == Ucrit_pid[i] ) return;
- Ucrit_pid[Ucrit_MaxPid++] = pid;
+ struct connections_data crec;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum == -1)
+ return 0;
+
+ if (!process_exists(crec.pid) || !Ucrit_checkUsername(uidtoname(crec.uid))) {
+ return 0;
+ }
+
+ d_printf("%-10.10s %5d %-12s %s",
+ crec.name,(int)crec.pid,
+ crec.machine,
+ asctime(LocalTime(&crec.start)));
+
+ return 0;
}
-unsigned int Ucrit_checkPid(int pid)
+static int traverse_sessionid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
{
- int i;
- if ( !Ucrit_IsActive) return 1;
- for (i=0;i<Ucrit_MaxPid;i++)
- if( pid == Ucrit_pid[i] ) return 1;
- return 0;
+ struct sessionid sessionid;
+
+ if (dbuf.dsize != sizeof(sessionid))
+ return 0;
+
+ memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
+
+ if (!process_exists(sessionid.pid) || !Ucrit_checkUsername(uidtoname(sessionid.uid))) {
+ return 0;
+ }
+
+ d_printf("%5d %-12s %-12s %-12s (%s)\n",
+ (int)sessionid.pid, uidtoname(sessionid.uid), gidtoname(sessionid.gid),
+ sessionid.remote_machine, sessionid.hostname);
+
+ return 0;
}
+
+
+
+ int main(int argc, char *argv[])
+{
+ pstring fname;
+ int c;
+ extern char *optarg;
+ int profile_only = 0, new_debuglevel = -1;
+ TDB_CONTEXT *tdb;
+
+ setup_logging(argv[0],True);
+
+ DEBUGLEVEL = 0;
+ dbf = x_stderr;
+
+ if (getuid() != geteuid()) {
+ d_printf("smbstatus should not be run setuid\n");
+ return(1);
+ }
+
+ while ((c = getopt(argc, argv, "pvLSs:u:bPBd:")) != EOF) {
+ switch (c) {
+ case 'b':
+ brief = 1;
+ break;
+ case 'B':
+ show_brl = 1;
+ break;
+ case 'd':
+ new_debuglevel = atoi(optarg);
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+ case 'L':
+ locks_only = 1;
+ break;
+ case 'p':
+ processes_only = 1;
+ break;
+ case 'P':
+ profile_only = 1;
+ break;
+ case 'S':
+ shares_only = 1;
+ break;
+ case 's':
+ pstrcpy(dyn_CONFIGFILE, optarg);
+ break;
+ case 'u':
+ Ucrit_addUsername(optarg);
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-P] [-v] [-L] [-p] [-S] [-s configfile] [-u username] [-d debuglevel]\n", *argv);
+ return (-1);
+ }
+ }
+
+ if (!lp_load(dyn_CONFIGFILE,False,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
+ return (-1);
+ }
+
+ if (new_debuglevel != -1) {
+ DEBUGLEVEL = new_debuglevel;
+ }
+
+ if (verbose) {
+ d_printf("using configfile = %s\n", dyn_CONFIGFILE);
+ }
+
+ if (profile_only) {
+ return profile_dump();
+ }
+
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb) {
+ d_printf("sessionid.tdb not initialised\n");
+ } else {
+ if (locks_only) goto locks;
+
+ d_printf("\nSamba version %s\n",VERSION);
+ d_printf("PID Username Group Machine \n");
+ d_printf("-------------------------------------------------------------------\n");
+
+ tdb_traverse(tdb, traverse_sessionid, NULL);
+ tdb_close(tdb);
+ }
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb) {
+ d_printf("connections.tdb not initialised\n");
+ } else {
+ if (verbose) {
+ d_printf("Opened status file %s\n", fname);
+ }
+
+ if (brief)
+ exit(0);
+
+ d_printf("\nService pid machine Connected at\n");
+ d_printf("-------------------------------------------------------\n");
+
+ tdb_traverse(tdb, traverse_fn1, NULL);
+ tdb_close(tdb);
+ }
+
+ locks:
+ if (processes_only) exit(0);
+
+ if (!shares_only) {
+ int ret;
+
+ if (!locking_init(1)) {
+ d_printf("Can't initialise locking module - exiting\n");
+ exit(1);
+ }
+
+ ret = share_mode_forall(print_share_mode);
+
+ if (ret == 0) {
+ d_printf("No locked files\n");
+ } else if (ret == -1) {
+ d_printf("locked file list truncated\n");
+ }
+
+ d_printf("\n");
+
+ if (show_brl) {
+ brl_forall(print_brl);
+ }
+
+ locking_end();
+ }
+
+ return (0);
+}
diff --git a/source/utils/testparm.c b/source/utils/testparm.c
index e1f070a4b83..97dc0c014a2 100644
--- a/source/utils/testparm.c
+++ b/source/utils/testparm.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Test validity of smb.conf
- Copyright (C) Karl Auer 1993, 1994
+ Copyright (C) Karl Auer 1993, 1994-1998
Extensively modified by Andrew Tridgell, 1995
@@ -34,80 +34,277 @@
#include "includes.h"
#include "smb.h"
-#include "params.h"
-#include "loadparm.h"
-/* these live in util.c */
-extern FILE *dbf;
-extern int DEBUGLEVEL;
+/***********************************************
+ Here we do a set of 'hard coded' checks for bad
+ configuration settings.
+************************************************/
+
+static int do_global_checks(void)
+{
+ int ret = 0;
+ SMB_STRUCT_STAT st;
+
+ if (lp_security() == SEC_DOMAIN && !lp_encrypted_passwords()) {
+ printf("ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must also be set to 'true'.\n");
+ ret = 1;
+ }
+
+ if (lp_wins_support() && wins_srv_count()) {
+ printf("ERROR: both 'wins support = true' and 'wins server = <server>' \
+cannot be set in the smb.conf file. nmbd will abort with this setting.\n");
+ ret = 1;
+ }
+
+ if (!directory_exist(lp_lockdir(), &st)) {
+ printf("ERROR: lock directory %s does not exist\n",
+ lp_lockdir());
+ ret = 1;
+ } else if ((st.st_mode & 0777) != 0755) {
+ printf("WARNING: lock directory %s should have permissions 0755 for browsing to work\n",
+ lp_lockdir());
+ ret = 1;
+ }
+
+ /*
+ * Password server sanity checks.
+ */
+
+ if((lp_security() == SEC_SERVER || lp_security() == SEC_DOMAIN) && !lp_passwordserver()) {
+ pstring sec_setting;
+ if(lp_security() == SEC_SERVER)
+ pstrcpy(sec_setting, "server");
+ else if(lp_security() == SEC_DOMAIN)
+ pstrcpy(sec_setting, "domain");
+
+ printf("ERROR: The setting 'security=%s' requires the 'password server' parameter be set \
+to a valid password server.\n", sec_setting );
+ ret = 1;
+ }
+
+
+ /*
+ * Check 'hosts equiv' and 'use rhosts' compatability with 'hostname lookup' value.
+ */
+
+ if(*lp_hosts_equiv() && !lp_hostname_lookups()) {
+ printf("ERROR: The setting 'hosts equiv = %s' requires that 'hostname lookups = yes'.\n", lp_hosts_equiv());
+ ret = 1;
+ }
+
+ /*
+ * Password chat sanity checks.
+ */
+
+ if(lp_security() == SEC_USER && lp_unix_password_sync()) {
+
+ /*
+ * Check that we have a valid lp_passwd_program() if not using pam.
+ */
+
+#ifdef WITH_PAM
+ if (!lp_pam_password_change()) {
+#endif
+
+ if(lp_passwd_program() == NULL) {
+ printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd program' \
+parameter.\n" );
+ ret = 1;
+ } else {
+ pstring passwd_prog;
+ pstring truncated_prog;
+ char *p;
+
+ pstrcpy( passwd_prog, lp_passwd_program());
+ p = passwd_prog;
+ *truncated_prog = '\0';
+ next_token(&p, truncated_prog, NULL, sizeof(pstring));
+
+ if(access(truncated_prog, F_OK) == -1) {
+ printf("ERROR: the 'unix password sync' parameter is set and the 'passwd program' (%s) \
+cannot be executed (error was %s).\n", truncated_prog, strerror(errno) );
+ ret = 1;
+ }
+ }
+
+#ifdef WITH_PAM
+ }
+#endif
+
+ if(lp_passwd_chat() == NULL) {
+ printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd chat' \
+parameter.\n");
+ ret = 1;
+ }
+
+ /*
+ * Check that we have a valid script and that it hasn't
+ * been written to expect the old password.
+ */
+
+ if(lp_encrypted_passwords()) {
+ if(strstr( lp_passwd_chat(), "%o")!=NULL) {
+ printf("ERROR: the 'passwd chat' script [%s] expects to use the old plaintext password \
+via the %%o substitution. With encrypted passwords this is not possible.\n", lp_passwd_chat() );
+ ret = 1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void usage(char *pname)
+{
+ printf("Usage: %s [-sh] [-L servername] [configfilename] [hostname hostIP]\n", pname);
+ printf("\t-s Suppress prompt for enter\n");
+ printf("\t-h Print usage\n");
+ printf("\t-L servername Set %%L macro to servername\n");
+ printf("\t-t encoding Print parameters with encoding\n");
+ printf("\tconfigfilename Configuration file to test\n");
+ printf("\thostname hostIP. Hostname and Host IP address to test\n");
+ printf("\t against \"host allow\" and \"host deny\"\n");
+ printf("\n");
+}
+
int main(int argc, char *argv[])
{
+ extern char *optarg;
+ extern int optind;
+ extern fstring local_machine;
pstring configfile;
+ int opt;
int s;
+ BOOL silent_mode = False;
+ int ret = 0;
+ pstring term_code;
+
+ *term_code = 0;
setup_logging(argv[0],True);
- charset_initialise();
+ while ((opt = getopt(argc, argv,"shL:t:")) != EOF) {
+ switch (opt) {
+ case 's':
+ silent_mode = True;
+ break;
+ case 'L':
+ fstrcpy(local_machine,optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 't':
+ pstrcpy(term_code,optarg);
+ break;
+ default:
+ printf("Incorrect program usage\n");
+ usage(argv[0]);
+ exit(1);
+ break;
+ }
+ }
+
+ argc += (1 - optind);
- if (argc < 2)
- strcpy(configfile,CONFIGFILE);
- else
- strcpy(configfile,argv[1]);
+ if ((argc == 1) || (argc == 3))
+ pstrcpy(configfile, dyn_CONFIGFILE);
+ else if ((argc == 2) || (argc == 4))
+ pstrcpy(configfile,argv[optind]);
- dbf = stdout;
+ dbf = x_stdout;
DEBUGLEVEL = 2;
printf("Load smb config files from %s\n",configfile);
- if (!lp_load(configfile,False))
- {
+ if (!lp_load(configfile,False,True,False)) {
printf("Error loading services.\n");
return(1);
- }
-
+ }
printf("Loaded services file OK.\n");
- for (s=0;s<1000;s++)
+ ret = do_global_checks();
+
+ for (s=0;s<1000;s++) {
if (VALID_SNUM(s))
if (strlen(lp_servicename(s)) > 8) {
- printf("WARNING: You have some share names that are longer than 8 chars\n");
- printf("These may give errors while browsing or may not be accessible\nto some older clients\n");
- break;
+ printf("WARNING: You have some share names that are longer than 8 chars\n");
+ printf("These may give errors while browsing or may not be accessible\nto some older clients\n");
+ break;
+ }
+ }
+
+ for (s=0;s<1000;s++) {
+ if (VALID_SNUM(s)) {
+ char **deny_list = lp_hostsdeny(s);
+ char **allow_list = lp_hostsallow(s);
+ int i;
+ if(deny_list) {
+ for (i=0; deny_list[i]; i++) {
+ char *hasstar = strchr_m(deny_list[i], '*');
+ char *hasquery = strchr_m(deny_list[i], '?');
+ if(hasstar || hasquery) {
+ printf("Invalid character %c in hosts deny list (%s) for service %s.\n",
+ hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(s) );
+ }
+ }
}
- if (argc < 4)
- {
+ if(allow_list) {
+ for (i=0; allow_list[i]; i++) {
+ char *hasstar = strchr_m(allow_list[i], '*');
+ char *hasquery = strchr_m(allow_list[i], '?');
+ if(hasstar || hasquery) {
+ printf("Invalid character %c in hosts allow list (%s) for service %s.\n",
+ hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(s) );
+ }
+ }
+ }
+
+ if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
+ printf("Invalid combination of parameters for service %s. \
+Level II oplocks can only be set if oplocks are also set.\n",
+ lp_servicename(s) );
+ }
+ }
+ }
+
+ if (argc < 3) {
+ if (!silent_mode) {
printf("Press enter to see a dump of your service definitions\n");
fflush(stdout);
getc(stdin);
- lp_dump();
}
+ lp_dump(stdout,True, lp_numservices());
+ }
- if (argc == 4)
- {
- struct from_host f;
- f.name = argv[2];
- f.addr = argv[3];
+ if (argc >= 3) {
+ char *cname;
+ char *caddr;
- /* this is totally ugly, a real `quick' hack */
- for (s=0;s<1000;s++)
- if (VALID_SNUM(s))
- {
- if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),&f))
- {
- printf("Allow connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
- }
- else
- {
- printf("Deny connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
- }
- }
+ if (argc == 3) {
+ cname = argv[optind];
+ caddr = argv[optind+1];
+ } else {
+ cname = argv[optind+1];
+ caddr = argv[optind+2];
}
- return(0);
-}
-
+ /* this is totally ugly, a real `quick' hack */
+ for (s=0;s<1000;s++) {
+ if (VALID_SNUM(s)) {
+ if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),cname,caddr)) {
+ printf("Allow connection from %s (%s) to %s\n",
+ cname,caddr,lp_servicename(s));
+ } else {
+ printf("Deny connection from %s (%s) to %s\n",
+ cname,caddr,lp_servicename(s));
+ }
+ }
+ }
+ }
+ return(ret);
+}
diff --git a/source/utils/testprns.c b/source/utils/testprns.c
index 89c615898d7..c3aa25ada86 100644
--- a/source/utils/testprns.c
+++ b/source/utils/testprns.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
test printer setup
- Copyright (C) Karl Auer 1993, 1994
+ Copyright (C) Karl Auer 1993, 1994-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,11 +33,6 @@
#include "includes.h"
#include "smb.h"
-#include "pcap.h"
-
-/* these live in util.c */
-extern FILE *dbf;
-extern int DEBUGLEVEL;
int main(int argc, char *argv[])
{
@@ -45,17 +40,14 @@ int main(int argc, char *argv[])
setup_logging(argv[0],True);
- charset_initialise();
-
if (argc < 2 || argc > 3)
printf("Usage: testprns printername [printcapfile]\n");
else
{
- dbf = fopen("test.log", "w");
- if (dbf == NULL)
+ dbf = x_fopen("test.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (dbf == NULL) {
printf("Unable to open logfile.\n");
- else
- {
+ } else {
DEBUGLEVEL = 3;
pszTemp = (argc < 3) ? PRINTCAP_NAME : argv[2];
printf("Looking for printer %s in printcap file %s\n",
@@ -64,9 +56,8 @@ int main(int argc, char *argv[])
printf("Printer name %s is not valid.\n", argv[1]);
else
printf("Printer name %s is valid.\n", argv[1]);
- fclose(dbf);
+ x_fclose(dbf);
}
}
return (0);
}
-
diff --git a/source/web/.cvsignore b/source/web/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/web/.cvsignore
diff --git a/source/web/cgi.c b/source/web/cgi.c
new file mode 100644
index 00000000000..9a029684ce1
--- /dev/null
+++ b/source/web/cgi.c
@@ -0,0 +1,662 @@
+/*
+ some simple CGI helper routines
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+#include "smb.h"
+
+#define MAX_VARIABLES 10000
+
+/* set the expiry on fixed pages */
+#define EXPIRY_TIME (60*60*24*7)
+
+#ifdef DEBUG_COMMENTS
+extern void print_title(char *fmt, ...);
+#endif
+
+struct var {
+ char *name;
+ char *value;
+};
+
+static struct var variables[MAX_VARIABLES];
+static int num_variables;
+static int content_length;
+static int request_post;
+static char *query_string;
+static char *baseurl;
+static char *pathinfo;
+static char *C_user;
+static BOOL inetd_server;
+static BOOL got_request;
+
+static void unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr_m(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
+ while (p && *p && (p=strchr_m(p,'%'))) {
+ int c1 = p[1];
+ int c2 = p[2];
+
+ if (c1 >= '0' && c1 <= '9')
+ c1 = c1 - '0';
+ else if (c1 >= 'A' && c1 <= 'F')
+ c1 = 10 + c1 - 'A';
+ else if (c1 >= 'a' && c1 <= 'f')
+ c1 = 10 + c1 - 'a';
+ else {p++; continue;}
+
+ if (c2 >= '0' && c2 <= '9')
+ c2 = c2 - '0';
+ else if (c2 >= 'A' && c2 <= 'F')
+ c2 = 10 + c2 - 'A';
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 = 10 + c2 - 'a';
+ else {p++; continue;}
+
+ *p = (c1<<4) | c2;
+
+ memcpy(p+1, p+3, strlen(p+3)+1);
+ p++;
+ }
+}
+
+
+static char *grab_line(FILE *f, int *cl)
+{
+ char *ret = NULL;
+ int i = 0;
+ int len = 0;
+
+ while ((*cl)) {
+ int c;
+
+ if (i == len) {
+ char *ret2;
+ if (len == 0) len = 1024;
+ else len *= 2;
+ ret2 = (char *)Realloc(ret, len);
+ if (!ret2) return ret;
+ ret = ret2;
+ }
+
+ c = fgetc(f);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr_m("\n&", c)) break;
+
+ ret[i++] = c;
+
+ }
+
+
+ ret[i] = 0;
+ return ret;
+}
+
+/***************************************************************************
+ load all the variables passed to the CGI program. May have multiple variables
+ with the same name and the same or different values. Takes a file parameter
+ for simulating CGI invocation eg loading saved preferences.
+ ***************************************************************************/
+void cgi_load_variables(void)
+{
+ static char *line;
+ char *p, *s, *tok;
+ int len, i;
+ FILE *f = stdin;
+
+#ifdef DEBUG_COMMENTS
+ char dummy[100]="";
+ print_title(dummy);
+ d_printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+#endif
+
+ if (!content_length) {
+ p = getenv("CONTENT_LENGTH");
+ len = p?atoi(p):0;
+ } else {
+ len = content_length;
+ }
+
+
+ if (len > 0 &&
+ (request_post ||
+ ((s=getenv("REQUEST_METHOD")) &&
+ strcasecmp(s,"POST")==0))) {
+ while (len && (line=grab_line(f, &len))) {
+ p = strchr_m(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ SAFE_FREE(line);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== POST var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+ }
+
+ fclose(stdin);
+ open("/dev/null", O_RDWR);
+
+ if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
+ for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) {
+ p = strchr_m(tok,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(tok);
+ variables[num_variables].value = strdup(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== Commandline var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ }
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+
+ /* variables from the client are in display charset - convert them
+ to our internal charset before use */
+ for (i=0;i<num_variables;i++) {
+ pstring dest;
+
+ convert_string(CH_DISPLAY, CH_UNIX,
+ variables[i].name, -1,
+ dest, sizeof(dest));
+ free(variables[i].name);
+ variables[i].name = strdup(dest);
+
+ convert_string(CH_DISPLAY, CH_UNIX,
+ variables[i].value, -1,
+ dest, sizeof(dest));
+ free(variables[i].value);
+ variables[i].value = strdup(dest);
+ }
+}
+
+
+/***************************************************************************
+ find a variable passed via CGI
+ Doesn't quite do what you think in the case of POST text variables, because
+ if they exist they might have a value of "" or even " ", depending on the
+ browser. Also doesn't allow for variables[] containing multiple variables
+ with the same name and the same or different values.
+ ***************************************************************************/
+char *cgi_variable(char *name)
+{
+ int i;
+
+ for (i=0;i<num_variables;i++)
+ if (strcmp(variables[i].name, name) == 0)
+ return variables[i].value;
+ return NULL;
+}
+
+/***************************************************************************
+tell a browser about a fatal error in the http processing
+ ***************************************************************************/
+static void cgi_setup_error(char *err, char *header, char *info)
+{
+ if (!got_request) {
+ /* damn browsers don't like getting cut off before they give a request */
+ char line[1024];
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (strncasecmp(line,"GET ", 4)==0 ||
+ strncasecmp(line,"POST ", 5)==0 ||
+ strncasecmp(line,"PUT ", 4)==0) {
+ break;
+ }
+ }
+ }
+
+ d_printf("HTTP/1.0 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n\r\n", err, header, err, err, info);
+ fclose(stdin);
+ fclose(stdout);
+ exit(0);
+}
+
+
+/***************************************************************************
+tell a browser about a fatal authentication error
+ ***************************************************************************/
+static void cgi_auth_error(void)
+{
+ if (inetd_server) {
+ cgi_setup_error("401 Authorization Required",
+ "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
+ "You must be authenticated to use this service");
+ } else {
+ printf("Content-Type: text/html\r\n");
+
+ printf("\r\n<HTML><HEAD><TITLE>SWAT</TITLE></HEAD>\n");
+ printf("<BODY><H1>Installation Error</H1>\n");
+ printf("SWAT must be installed via inetd. It cannot be run as a CGI script<p>\n");
+ printf("</BODY></HTML>\r\n");
+ }
+ exit(0);
+}
+
+/***************************************************************************
+authenticate when we are running as a CGI
+ ***************************************************************************/
+static void cgi_web_auth(void)
+{
+ char *user = getenv("REMOTE_USER");
+ struct passwd *pwd;
+ char *head = "Content-Type: text/html\r\n\r\n<HTML><BODY><H1>SWAT installation Error</H1>\n";
+ char *tail = "</BODY></HTML>\r\n";
+
+ if (!user) {
+ printf("%sREMOTE_USER not set. Not authenticated by web server.<br>%s\n",
+ head, tail);
+ exit(0);
+ }
+
+ pwd = getpwnam(user);
+ if (!pwd) {
+ printf("%sCannot find user %s<br>%s\n", head, user, tail);
+ exit(0);
+ }
+
+ setuid(0);
+ setuid(pwd->pw_uid);
+ if (geteuid() != pwd->pw_uid || getuid() != pwd->pw_uid) {
+ printf("%sFailed to become user %s - uid=%d/%d<br>%s\n",
+ head, user, (int)geteuid(), (int)getuid(), tail);
+ exit(0);
+ }
+}
+
+/***************************************************************************
+decode a base64 string in-place - simple and slow algorithm
+ ***************************************************************************/
+static void base64_decode(char *s)
+{
+ char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i, n;
+ unsigned char *d = (unsigned char *)s;
+ char *p;
+
+ n=i=0;
+
+ while (*s && (p=strchr_m(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ n = byte_offset+1;
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ n = byte_offset+2;
+ }
+ s++; i++;
+ }
+ /* null terminate */
+ d[n] = 0;
+}
+
+/***************************************************************************
+handle a http authentication line
+ ***************************************************************************/
+static BOOL cgi_handle_authorization(char *line)
+{
+ char *p, *user, *user_pass;
+ struct passwd *pass = NULL;
+
+ if (strncasecmp(line,"Basic ", 6)) {
+ goto err;
+ }
+ line += 6;
+ while (line[0] == ' ') line++;
+ base64_decode(line);
+ if (!(p=strchr_m(line,':'))) {
+ /*
+ * Always give the same error so a cracker
+ * cannot tell why we fail.
+ */
+ goto err;
+ }
+ *p = 0;
+ user = line;
+ user_pass = p+1;
+
+ /*
+ * Try and get the user from the UNIX password file.
+ */
+
+ pass = sys_getpwnam(user);
+
+ /*
+ * Validate the password they have given.
+ */
+
+ if NT_STATUS_IS_OK(pass_check(pass, user, user_pass,
+ strlen(user_pass), NULL, False)) {
+
+ if (pass) {
+ /*
+ * Password was ok.
+ */
+
+ become_user_permanently(pass->pw_uid, pass->pw_gid);
+
+ /* Save the users name */
+ C_user = strdup(user);
+ return True;
+ }
+ }
+
+err:
+ cgi_setup_error("401 Bad Authorization", "",
+ "username or password incorrect");
+
+ return False;
+}
+
+/***************************************************************************
+is this root?
+ ***************************************************************************/
+BOOL am_root(void)
+{
+ if (geteuid() == 0) {
+ return( True);
+ } else {
+ return( False);
+ }
+}
+
+/***************************************************************************
+return a ptr to the users name
+ ***************************************************************************/
+char *cgi_user_name(void)
+{
+ return(C_user);
+}
+
+
+/***************************************************************************
+handle a file download
+ ***************************************************************************/
+static void cgi_download(char *file)
+{
+ SMB_STRUCT_STAT st;
+ char buf[1024];
+ int fd, l, i;
+ char *p;
+ char *lang;
+
+ /* sanitise the filename */
+ for (i=0;file[i];i++) {
+ if (!isalnum((int)file[i]) && !strchr_m("/.-_", file[i])) {
+ cgi_setup_error("404 File Not Found","",
+ "Illegal character in filename");
+ }
+ }
+
+ if (!file_exist(file, &st)) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+
+ fd = web_open(file,O_RDONLY,0);
+ if (fd == -1) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ printf("HTTP/1.0 200 OK\r\n");
+ if ((p=strrchr_m(file,'.'))) {
+ if (strcmp(p,".gif")==0) {
+ printf("Content-Type: image/gif\r\n");
+ } else if (strcmp(p,".jpg")==0) {
+ printf("Content-Type: image/jpeg\r\n");
+ } else if (strcmp(p,".txt")==0) {
+ printf("Content-Type: text/plain\r\n");
+ } else {
+ printf("Content-Type: text/html\r\n");
+ }
+ }
+ printf("Expires: %s\r\n", http_timestring(time(NULL)+EXPIRY_TIME));
+
+ lang = lang_tdb_current();
+ if (lang) {
+ printf("Content-Language: %s\r\n", lang);
+ }
+
+ printf("Content-Length: %d\r\n\r\n", (int)st.st_size);
+ while ((l=read(fd,buf,sizeof(buf)))>0) {
+ fwrite(buf, 1, l, stdout);
+ }
+ close(fd);
+ exit(0);
+}
+
+
+
+
+/**
+ * @brief Setup the CGI framework.
+ *
+ * Setup the cgi framework, handling the possibility that this program
+ * is either run as a true CGI program with a gateway to a web server, or
+ * is itself a mini web server.
+ **/
+void cgi_setup(const char *rootdir, int auth_required)
+{
+ BOOL authenticated = False;
+ char line[1024];
+ char *url=NULL;
+ char *p;
+ char *lang;
+
+ if (chdir(rootdir)) {
+ cgi_setup_error("400 Server Error", "",
+ "chdir failed - the server is not configured correctly");
+ }
+
+ /* Handle the possability we might be running as non-root */
+ sec_init();
+
+ if ((lang=getenv("HTTP_ACCEPT_LANGUAGE"))) {
+ /* if running as a cgi program */
+ web_set_lang(lang);
+ }
+
+ /* maybe we are running under a web server */
+ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+ if (auth_required) {
+ cgi_web_auth();
+ }
+ return;
+ }
+
+ inetd_server = True;
+
+ if (!check_access(1, lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ cgi_setup_error("400 Server Error", "",
+ "Samba is configured to deny access from this client\n<br>Check your \"hosts allow\" and \"hosts deny\" options in smb.conf ");
+ }
+
+ /* we are a mini-web server. We need to read the request from stdin
+ and handle authentication etc */
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (line[0] == '\r' || line[0] == '\n') break;
+ if (strncasecmp(line,"GET ", 4)==0) {
+ got_request = True;
+ url = strdup(&line[4]);
+ } else if (strncasecmp(line,"POST ", 5)==0) {
+ got_request = True;
+ request_post = 1;
+ url = strdup(&line[5]);
+ } else if (strncasecmp(line,"PUT ", 4)==0) {
+ got_request = True;
+ cgi_setup_error("400 Bad Request", "",
+ "This server does not accept PUT requests");
+ } else if (strncasecmp(line,"Authorization: ", 15)==0) {
+ authenticated = cgi_handle_authorization(&line[15]);
+ } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
+ content_length = atoi(&line[16]);
+ } else if (strncasecmp(line,"Accept-Language: ", 17)==0) {
+ web_set_lang(&line[17]);
+ }
+ /* ignore all other requests! */
+ }
+
+ if (auth_required && !authenticated) {
+ cgi_auth_error();
+ }
+
+ if (!url) {
+ cgi_setup_error("400 Bad Request", "",
+ "You must specify a GET or POST request");
+ }
+
+ /* trim the URL */
+ if ((p = strchr_m(url,' ')) || (p=strchr_m(url,'\t'))) {
+ *p = 0;
+ }
+ while (*url && strchr_m("\r\n",url[strlen(url)-1])) {
+ url[strlen(url)-1] = 0;
+ }
+
+ /* anything following a ? in the URL is part of the query string */
+ if ((p=strchr_m(url,'?'))) {
+ query_string = p+1;
+ *p = 0;
+ }
+
+ string_sub(url, "/swat/", "", 0);
+
+ if (url[0] != '/' && strstr(url,"..")==0 && file_exist(url, NULL)) {
+ cgi_download(url);
+ }
+
+ printf("HTTP/1.0 200 OK\r\nConnection: close\r\n");
+ printf("Date: %s\r\n", http_timestring(time(NULL)));
+ baseurl = "";
+ pathinfo = url+1;
+}
+
+
+/***************************************************************************
+return the current pages URL
+ ***************************************************************************/
+char *cgi_baseurl(void)
+{
+ if (inetd_server) {
+ return baseurl;
+ }
+ return getenv("SCRIPT_NAME");
+}
+
+/***************************************************************************
+return the current pages path info
+ ***************************************************************************/
+char *cgi_pathinfo(void)
+{
+ char *r;
+ if (inetd_server) {
+ return pathinfo;
+ }
+ r = getenv("PATH_INFO");
+ if (!r) return "";
+ if (*r == '/') r++;
+ return r;
+}
+
+/***************************************************************************
+return the hostname of the client
+ ***************************************************************************/
+char *cgi_remote_host(void)
+{
+ if (inetd_server) {
+ return get_socket_name(1);
+ }
+ return getenv("REMOTE_HOST");
+}
+
+/***************************************************************************
+return the hostname of the client
+ ***************************************************************************/
+char *cgi_remote_addr(void)
+{
+ if (inetd_server) {
+ return get_socket_addr(1);
+ }
+ return getenv("REMOTE_ADDR");
+}
+
+
+/***************************************************************************
+return True if the request was a POST
+ ***************************************************************************/
+BOOL cgi_waspost(void)
+{
+ if (inetd_server) {
+ return request_post;
+ }
+ return strequal(getenv("REQUEST_METHOD"), "POST");
+}
diff --git a/source/web/diagnose.c b/source/web/diagnose.c
new file mode 100644
index 00000000000..bf2e6da17d1
--- /dev/null
+++ b/source/web/diagnose.c
@@ -0,0 +1,67 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ diagnosis tools for web admin
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+
+/* check to see if nmbd is running on localhost by looking for a __SAMBA__
+ response */
+BOOL nmbd_running(void)
+{
+ extern struct in_addr loopback_ip;
+ int fd, count;
+ struct in_addr *ip_list;
+
+ if ((fd = open_socket_in(SOCK_DGRAM, 0, 3,
+ interpret_addr("127.0.0.1"), True)) != -1) {
+ if ((ip_list = name_query(fd, "__SAMBA__", 0,
+ True, True, loopback_ip,
+ &count)) != NULL) {
+ SAFE_FREE(ip_list);
+ close(fd);
+ return True;
+ }
+ close (fd);
+ }
+
+ return False;
+}
+
+
+/* check to see if smbd is running on localhost by trying to open a connection
+ then closing it */
+BOOL smbd_running(void)
+{
+ static struct cli_state cli;
+ extern struct in_addr loopback_ip;
+
+ if (!cli_initialise(&cli))
+ return False;
+
+ if (!cli_connect(&cli, "localhost", &loopback_ip)) {
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli_shutdown(&cli);
+ return True;
+}
diff --git a/source/web/neg_lang.c b/source/web/neg_lang.c
new file mode 100644
index 00000000000..8a5b60d99fd
--- /dev/null
+++ b/source/web/neg_lang.c
@@ -0,0 +1,67 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ SWAT language handling
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Created by Ryo Kawahara <rkawa@lbe.co.jp>
+*/
+
+#include "includes.h"
+
+/*
+ during a file download we first check to see if there is a language
+ specific file available. If there is then use that, otherwise
+ just open the specified file
+*/
+int web_open(const char *fname, int flags, mode_t mode)
+{
+ char *p = NULL;
+ char *lang = lang_tdb_current();
+ int fd;
+ if (lang) {
+ asprintf(&p, "lang/%s/%s", lang, fname);
+ if (p) {
+ fd = sys_open(p, flags, mode);
+ free(p);
+ if (fd != -1) {
+ return fd;
+ }
+ }
+ }
+
+ /* fall through to default name */
+ return sys_open(fname, flags, mode);
+}
+
+
+/*
+ choose from a list of languages. The list can be comma or space
+ separated
+ Keep choosing until we get a hit
+*/
+void web_set_lang(const char *lang_list)
+{
+ fstring lang;
+ char *p = (char *)lang_list;
+
+ while (next_token(&p, lang, ", \t\r\n", sizeof(lang))) {
+ if (lang_tdb_init(lang)) return;
+ }
+
+ /* it's not an error to not initialise - we just fall back to
+ the default */
+}
diff --git a/source/web/startstop.c b/source/web/startstop.c
new file mode 100644
index 00000000000..80b5ce7444b
--- /dev/null
+++ b/source/web/startstop.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ start/stop nmbd and smbd
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb.h"
+#include "dynconfig.h"
+
+/** Need to wait for daemons to startup */
+#define SLEEP_TIME 3
+
+/** Startup smbd from web interface. */
+void start_smbd(void)
+{
+ pstring binfile;
+
+ if (geteuid() != 0) return;
+
+ if (fork()) {
+ sleep(SLEEP_TIME);
+ return;
+ }
+
+ slprintf(binfile, sizeof(pstring) - 1, "%s/smbd", dyn_SBINDIR);
+
+ become_daemon();
+
+ execl(binfile, binfile, "-D", NULL);
+
+ exit(0);
+}
+
+/* startup nmbd */
+void start_nmbd(void)
+{
+ pstring binfile;
+
+ if (geteuid() != 0) return;
+
+ if (fork()) {
+ sleep(SLEEP_TIME);
+ return;
+ }
+
+ slprintf(binfile, sizeof(pstring) - 1, "%s/nmbd", dyn_SBINDIR);
+
+ become_daemon();
+
+ execl(binfile, binfile, "-D", NULL);
+
+ exit(0);
+}
+
+
+/* stop smbd */
+void stop_smbd(void)
+{
+ pid_t pid = pidfile_pid("smbd");
+
+ if (geteuid() != 0) return;
+
+ if (pid == 0) return;
+
+ kill(pid, SIGTERM);
+}
+
+/* stop nmbd */
+void stop_nmbd(void)
+{
+ pid_t pid = pidfile_pid("nmbd");
+
+ if (geteuid() != 0) return;
+
+ if (pid == 0) return;
+
+ kill(pid, SIGTERM);
+}
+
+/* kill a specified process */
+void kill_pid(pid_t pid)
+{
+ if (geteuid() != 0) return;
+
+ if (pid <= 0) return;
+
+ kill(pid, SIGTERM);
+ sleep(SLEEP_TIME);
+}
diff --git a/source/web/statuspage.c b/source/web/statuspage.c
new file mode 100644
index 00000000000..6af7674dc92
--- /dev/null
+++ b/source/web/statuspage.c
@@ -0,0 +1,374 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.
+ web status page
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define PIDMAP struct PidMap
+
+PIDMAP {
+ PIDMAP *next, *prev;
+ pid_t pid;
+ char *machine;
+};
+
+static PIDMAP *pidmap;
+static int PID_or_Machine; /* 0 = show PID, else show Machine name */
+
+static pid_t smbd_pid;
+
+/* from 2nd call on, remove old list */
+static void initPid2Machine (void)
+{
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ PIDMAP *p;
+
+ for (p = pidmap; p != NULL; ) {
+ DLIST_REMOVE(pidmap, p);
+ SAFE_FREE(p->machine);
+ SAFE_FREE(p);
+ }
+
+ pidmap = NULL;
+ }
+}
+
+/* add new PID <-> Machine name mapping */
+static void addPid2Machine (pid_t pid, char *machine)
+{
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ PIDMAP *newmap;
+
+ if ((newmap = (PIDMAP *) malloc (sizeof (PIDMAP))) == NULL) {
+ /* XXX need error message for this?
+ if malloc fails, PID is always shown */
+ return;
+ }
+
+ newmap->pid = pid;
+ newmap->machine = strdup (machine);
+
+ DLIST_ADD(pidmap, newmap);
+ }
+}
+
+/* lookup PID <-> Machine name mapping */
+static char *mapPid2Machine (pid_t pid)
+{
+ static char pidbuf [64];
+ PIDMAP *map;
+
+ /* show machine name rather PID on table "Open Files"? */
+ if (PID_or_Machine) {
+ for (map = pidmap; map != NULL; map = map->next) {
+ if (pid == map->pid) {
+ if (map->machine == NULL) /* no machine name */
+ break; /* show PID */
+
+ return map->machine;
+ }
+ }
+ }
+
+ /* PID not in list or machine name NULL? return pid as string */
+ snprintf (pidbuf, sizeof (pidbuf) - 1, "%d", pid);
+ return pidbuf;
+}
+
+static char *tstring(time_t t)
+{
+ static pstring buf;
+ pstrcpy(buf, asctime(LocalTime(&t)));
+ all_string_sub(buf," ","&nbsp;",sizeof(buf));
+ return buf;
+}
+
+static void print_share_mode(share_mode_entry *e, char *fname)
+{
+ d_printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid)));
+ d_printf("<td>");
+ switch ((e->share_mode>>4)&0xF) {
+ case DENY_NONE: d_printf("DENY_NONE"); break;
+ case DENY_ALL: d_printf("DENY_ALL "); break;
+ case DENY_DOS: d_printf("DENY_DOS "); break;
+ case DENY_READ: d_printf("DENY_READ "); break;
+ case DENY_WRITE:d_printf("DENY_WRITE "); break;
+ }
+ d_printf("</td>");
+
+ d_printf("<td>");
+ switch (e->share_mode&0xF) {
+ case 0: d_printf("RDONLY "); break;
+ case 1: d_printf("WRONLY "); break;
+ case 2: d_printf("RDWR "); break;
+ }
+ d_printf("</td>");
+
+ d_printf("<td>");
+ if((e->op_type &
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ d_printf("EXCLUSIVE+BATCH ");
+ else if (e->op_type & EXCLUSIVE_OPLOCK)
+ d_printf("EXCLUSIVE ");
+ else if (e->op_type & BATCH_OPLOCK)
+ d_printf("BATCH ");
+ else if (e->op_type & LEVEL_II_OPLOCK)
+ d_printf("LEVEL_II ");
+ else
+ d_printf("NONE ");
+ d_printf("</td>");
+
+ d_printf("<td>%s</td><td>%s</td></tr>\n",
+ fname,tstring(e->time.tv_sec));
+}
+
+
+/* kill off any connections chosen by the user */
+static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
+{
+ struct connections_data crec;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum == -1 && process_exists(crec.pid)) {
+ char buf[30];
+ slprintf(buf,sizeof(buf)-1,"kill_%d", (int)crec.pid);
+ if (cgi_variable(buf)) {
+ kill_pid(crec.pid);
+ }
+ }
+ return 0;
+}
+
+/* traversal fn for showing machine connections */
+static int traverse_fn2(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
+{
+ struct connections_data crec;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum != -1 || !process_exists(crec.pid) || (crec.pid == smbd_pid))
+ return 0;
+
+ addPid2Machine (crec.pid, crec.machine);
+
+ d_printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td>\n",
+ (int)crec.pid,
+ crec.machine,crec.addr,
+ tstring(crec.start));
+ if (geteuid() == 0) {
+ d_printf("<td><input type=submit value=\"X\" name=\"kill_%d\"></td>\n",
+ (int)crec.pid);
+ }
+ d_printf("</tr>\n");
+
+ return 0;
+}
+
+/* traversal fn for showing share connections */
+static int traverse_fn3(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void* state)
+{
+ struct connections_data crec;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum == -1 || !process_exists(crec.pid))
+ return 0;
+
+ d_printf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td></tr>\n",
+ crec.name,uidtoname(crec.uid),
+ gidtoname(crec.gid),(int)crec.pid,
+ crec.machine,
+ tstring(crec.start));
+ return 0;
+}
+
+
+/* show the current server status */
+void status_page(void)
+{
+ char *v;
+ int autorefresh=0;
+ int refresh_interval=30;
+ TDB_CONTEXT *tdb;
+
+ smbd_pid = pidfile_pid("smbd");
+
+ if (cgi_variable("smbd_restart")) {
+ stop_smbd();
+ start_smbd();
+ }
+
+ if (cgi_variable("smbd_start")) {
+ start_smbd();
+ }
+
+ if (cgi_variable("smbd_stop")) {
+ stop_smbd();
+ }
+
+ if (cgi_variable("nmbd_restart")) {
+ stop_nmbd();
+ start_nmbd();
+ }
+ if (cgi_variable("nmbd_start")) {
+ start_nmbd();
+ }
+
+ if (cgi_variable("nmbd_stop")) {
+ stop_nmbd();
+ }
+
+ if (cgi_variable("autorefresh")) {
+ autorefresh = 1;
+ } else if (cgi_variable("norefresh")) {
+ autorefresh = 0;
+ } else if (cgi_variable("refresh")) {
+ autorefresh = 1;
+ }
+
+ if ((v=cgi_variable("refresh_interval"))) {
+ refresh_interval = atoi(v);
+ }
+
+ if (cgi_variable("show_client_in_col_1")) {
+ PID_or_Machine = 1;
+ }
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (tdb) tdb_traverse(tdb, traverse_fn1, NULL);
+
+ initPid2Machine ();
+
+ d_printf("<H2>%s</H2>\n", _("Server Status"));
+
+ d_printf("<FORM method=post>\n");
+
+ if (!autorefresh) {
+ d_printf("<input type=submit value=\"%s\" name=autorefresh>\n", _("Auto Refresh"));
+ d_printf("<br>%s", _("Refresh Interval: "));
+ d_printf("<input type=text size=2 name=\"refresh_interval\" value=%d>\n",
+ refresh_interval);
+ } else {
+ d_printf("<input type=submit value=\"%s\" name=norefresh>\n", _("Stop Refreshing"));
+ d_printf("<br>%s%d\n", _("Refresh Interval: "), refresh_interval);
+ d_printf("<input type=hidden name=refresh value=1>\n");
+ }
+
+ d_printf("<p>\n");
+
+ if (!tdb) {
+ /* open failure either means no connections have been
+ made */
+ }
+
+
+ d_printf("<table>\n");
+
+ d_printf("<tr><td>%s</td><td>%s</td></tr>", _("version:"), VERSION);
+
+ fflush(stdout);
+ d_printf("<tr><td>%s</td><td>%s</td>\n", _("smbd:"), smbd_running()?_("running"):_("not running"));
+ if (geteuid() == 0) {
+ if (smbd_running()) {
+ d_printf("<td><input type=submit name=\"smbd_stop\" value=\"%s\"></td>\n", _("Stop smbd"));
+ } else {
+ d_printf("<td><input type=submit name=\"smbd_start\" value=\"%s\"></td>\n", _("Start smbd"));
+ }
+ d_printf("<td><input type=submit name=\"smbd_restart\" value=\"%s\"></td>\n", _("Restart smbd"));
+ }
+ d_printf("</tr>\n");
+
+ fflush(stdout);
+ d_printf("<tr><td>%s</td><td>%s</td>\n", _("nmbd:"), nmbd_running()?_("running"):_("not running"));
+ if (geteuid() == 0) {
+ if (nmbd_running()) {
+ d_printf("<td><input type=submit name=\"nmbd_stop\" value=\"%s\"></td>\n", _("Stop nmbd"));
+ } else {
+ d_printf("<td><input type=submit name=\"nmbd_start\" value=\"%s\"></td>\n", _("Start nmbd"));
+ }
+ d_printf("<td><input type=submit name=\"nmbd_restart\" value=\"%s\"></td>\n", _("Restart nmbd"));
+ }
+ d_printf("</tr>\n");
+
+ d_printf("</table>\n");
+ fflush(stdout);
+
+ d_printf("<p><h3>%s</h3>\n", _("Active Connections"));
+ d_printf("<table border=1>\n");
+ d_printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th>\n", _("PID"), _("Client"), _("IP address"), _("Date"));
+ if (geteuid() == 0) {
+ d_printf("<th>%s</th>\n", _("Kill"));
+ }
+ d_printf("</tr>\n");
+
+ if (tdb) tdb_traverse(tdb, traverse_fn2, NULL);
+
+ d_printf("</table><p>\n");
+
+ d_printf("<p><h3>%s</h3>\n", _("Active Shares"));
+ d_printf("<table border=1>\n");
+ d_printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n\n",
+ _("Share"), _("User"), _("Group"), _("PID"), _("Client"), _("Date"));
+
+ if (tdb) tdb_traverse(tdb, traverse_fn3, NULL);
+
+ d_printf("</table><p>\n");
+
+ d_printf("<h3>%s</h3>\n", _("Open Files"));
+ d_printf("<table border=1>\n");
+ d_printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n", _("PID"), _("Sharing"), _("R/W"), _("Oplock"), _("File"), _("Date"));
+
+ locking_init(1);
+ share_mode_forall(print_share_mode);
+ locking_end();
+ d_printf("</table>\n");
+
+ if (tdb) tdb_close(tdb);
+
+ d_printf("<br><input type=submit name=\"show_client_in_col_1\" value=\"Show Client in col 1\">\n");
+ d_printf("<input type=submit name=\"show_pid_in_col_1\" value=\"Show PID in col 1\">\n");
+
+ d_printf("</FORM>\n");
+
+ if (autorefresh) {
+ /* this little JavaScript allows for automatic refresh
+ of the page. There are other methods but this seems
+ to be the best alternative */
+ d_printf("<script language=\"JavaScript\">\n");
+ d_printf("<!--\nsetTimeout('window.location.replace(\"%s/status?refresh_interval=%d&refresh=1\")', %d)\n",
+ cgi_baseurl(),
+ refresh_interval,
+ refresh_interval*1000);
+ d_printf("//-->\n</script>\n");
+ }
+}
diff --git a/source/web/swat.c b/source/web/swat.c
new file mode 100644
index 00000000000..506a6263e9a
--- /dev/null
+++ b/source/web/swat.c
@@ -0,0 +1,1119 @@
+/*
+ Unix SMB/Netbios implementation.
+ Samba Web Administration Tool
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ * @group swat SWAT
+ * @{
+ * @file swat.c
+ *
+ * @brief Samba Web Administration Tool.
+ **/
+
+#include "includes.h"
+
+#define GLOBALS_SNUM -1
+
+static BOOL demo_mode = False;
+static BOOL have_write_access = False;
+static BOOL have_read_access = False;
+static int iNumNonAutoPrintServices = 0;
+
+/*
+ * Password Management Globals
+ */
+#define SWAT_USER "username"
+#define OLD_PSWD "old_passwd"
+#define NEW_PSWD "new_passwd"
+#define NEW2_PSWD "new2_passwd"
+#define CHG_S_PASSWD_FLAG "chg_s_passwd_flag"
+#define CHG_R_PASSWD_FLAG "chg_r_passwd_flag"
+#define ADD_USER_FLAG "add_user_flag"
+#define DELETE_USER_FLAG "delete_user_flag"
+#define DISABLE_USER_FLAG "disable_user_flag"
+#define ENABLE_USER_FLAG "enable_user_flag"
+#define RHOST "remote_host"
+
+/* we need these because we link to locking*.o */
+ void become_root(void) {}
+ void unbecome_root(void) {}
+
+/****************************************************************************
+****************************************************************************/
+static int enum_index(int value, struct enum_list *enumlist)
+{
+ int i;
+ for (i=0;enumlist[i].name;i++)
+ if (value == enumlist[i].value) break;
+ return(i);
+}
+
+static char *fix_backslash(char *str)
+{
+ static char newstring[1024];
+ char *p = newstring;
+
+ while (*str) {
+ if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
+ else *p++ = *str;
+ ++str;
+ }
+ *p = '\0';
+ return newstring;
+}
+
+static char *stripspace(char *str)
+{
+static char newstring[1024];
+char *p = newstring;
+
+ while (*str) {
+ if (*str != ' ') *p++ = *str;
+ ++str;
+ }
+ *p = '\0';
+ return newstring;
+}
+
+static char *make_parm_name(char *label)
+{
+ static char parmname[1024];
+ char *p = parmname;
+
+ while (*label) {
+ if (*label == ' ') *p++ = '_';
+ else *p++ = *label;
+ ++label;
+ }
+ *p = '\0';
+ return parmname;
+}
+
+/****************************************************************************
+ include a lump of html in a page
+****************************************************************************/
+static int include_html(char *fname)
+{
+ int fd;
+ char buf[1024];
+ int ret;
+
+ fd = web_open(fname, O_RDONLY, 0);
+
+ if (fd == -1) {
+ d_printf("ERROR: Can't open %s\n", fname);
+ return 0;
+ }
+
+ while ((ret = read(fd, buf, sizeof(buf))) > 0) {
+ write(1, buf, ret);
+ }
+
+ close(fd);
+ return 1;
+}
+
+/****************************************************************************
+ start the page with standard stuff
+****************************************************************************/
+static void print_header(void)
+{
+ if (!cgi_waspost()) {
+ d_printf("Expires: 0\r\n");
+ }
+ d_printf("Content-type: text/html\r\n\r\n");
+
+ if (!include_html("include/header.html")) {
+ d_printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
+ d_printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
+ }
+}
+
+/* *******************************************************************
+ show parameter label with translated name in the following form
+ because showing original and translated label in one line looks
+ too long, and showing translated label only is unusable for
+ heavy users.
+ -------------------------------
+ HELP security [combo box][button]
+ SECURITY
+ -------------------------------
+ (capital words are translated by gettext.)
+ if no translation is available, then same form as original is
+ used.
+ "i18n_translated_parm" class is used to change the color of the
+ translated parameter with CSS.
+ **************************************************************** */
+static const char* get_parm_translated(
+ const char* pAnchor, const char* pHelp, const char* pLabel)
+{
+ const char* pTranslated = _(pLabel);
+ static pstring output;
+ if(strcmp(pLabel, pTranslated) != 0)
+ {
+ snprintf(output, sizeof(output),
+ "<A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\"> %s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s <br><span class=\"i18n_translated_parm\">%s</span>",
+ pAnchor, pHelp, pLabel, pTranslated);
+ return output;
+ }
+ snprintf(output, sizeof(output),
+ "<A HREF=\"/swat/help/smb.conf.5.html#%s\" target=\"docs\"> %s</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %s",
+ pAnchor, pHelp, pLabel);
+ return output;
+}
+/****************************************************************************
+ finish off the page
+****************************************************************************/
+static void print_footer(void)
+{
+ if (!include_html("include/footer.html")) {
+ d_printf("\n</BODY>\n</HTML>\n");
+ }
+}
+
+/****************************************************************************
+ display one editable parameter in a form
+****************************************************************************/
+static void show_parameter(int snum, struct parm_struct *parm)
+{
+ int i;
+ void *ptr = parm->ptr;
+
+ if (parm->class == P_LOCAL && snum >= 0) {
+ ptr = lp_local_ptr(snum, ptr);
+ }
+
+ printf("<tr><td>%s</td><td>", get_parm_translated(stripspace(parm->label), _("Help"), parm->label));
+ switch (parm->type) {
+ case P_CHAR:
+ d_printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
+ make_parm_name(parm->label), *(char *)ptr);
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
+ _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
+ break;
+
+ case P_LIST:
+ d_printf("<input type=text size=40 name=\"parm_%s\" value=\"",
+ make_parm_name(parm->label));
+ if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
+ char **list = *(char ***)ptr;
+ for (;*list;list++) {
+ d_printf("%s%s", *list, ((*(list+1))?" ":""));
+ }
+ }
+ d_printf("\">");
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
+ _("Set Default"), make_parm_name(parm->label));
+ if (parm->def.lvalue) {
+ char **list = (char **)(parm->def.lvalue);
+ for (; *list; list++) {
+ d_printf("%s%s", *list, ((*(list+1))?" ":""));
+ }
+ }
+ d_printf("\'\">");
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ d_printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
+ make_parm_name(parm->label), *(char **)ptr);
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
+ break;
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ d_printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
+ make_parm_name(parm->label), (char *)ptr);
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
+ break;
+
+ case P_BOOL:
+ d_printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ d_printf("<option %s>Yes", (*(BOOL *)ptr)?"selected":"");
+ d_printf("<option %s>No", (*(BOOL *)ptr)?"":"selected");
+ d_printf("</select>");
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?0:1);
+ break;
+
+ case P_BOOLREV:
+ d_printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ d_printf("<option %s>Yes", (*(BOOL *)ptr)?"":"selected");
+ d_printf("<option %s>No", (*(BOOL *)ptr)?"selected":"");
+ d_printf("</select>");
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?1:0);
+ break;
+
+ case P_INTEGER:
+ d_printf("<input type=text size=8 name=\"parm_%s\" value=%d>", make_parm_name(parm->label), *(int *)ptr);
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
+ break;
+
+ case P_OCTAL:
+ d_printf("<input type=text size=8 name=\"parm_%s\" value=%s>", make_parm_name(parm->label), octal_string(*(int *)ptr));
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ _("Set Default"), make_parm_name(parm->label),
+ octal_string((int)(parm->def.ivalue)));
+ break;
+
+ case P_ENUM:
+ d_printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ for (i=0;parm->enum_list[i].name;i++) {
+ if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
+ d_printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
+ }
+ }
+ d_printf("</select>");
+ d_printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
+ break;
+ case P_SEP:
+ break;
+ }
+ d_printf("</td></tr>\n");
+}
+
+/****************************************************************************
+ display a set of parameters for a service
+****************************************************************************/
+static void show_parameters(int snum, int allparameters, int advanced, int printers)
+{
+ int i = 0;
+ struct parm_struct *parm;
+ char *heading = NULL;
+ char *last_heading = NULL;
+
+ while ((parm = lp_next_parameter(snum, &i, allparameters))) {
+ if (snum < 0 && parm->class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
+ continue;
+ if (parm->class == P_SEPARATOR) {
+ heading = parm->label;
+ continue;
+ }
+ if (parm->flags & FLAG_HIDE) continue;
+ if (snum >= 0) {
+ if (printers & !(parm->flags & FLAG_PRINT)) continue;
+ if (!printers & !(parm->flags & FLAG_SHARE)) continue;
+ }
+ if (!advanced) {
+ if (!(parm->flags & FLAG_BASIC)) {
+ void *ptr = parm->ptr;
+
+ if (parm->class == P_LOCAL && snum >= 0) {
+ ptr = lp_local_ptr(snum, ptr);
+ }
+
+ switch (parm->type) {
+ case P_CHAR:
+ if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
+ break;
+
+ case P_LIST:
+ if (!lp_list_compare(*(char ***)ptr, (char **)(parm->def.lvalue))) continue;
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
+ break;
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ if (!strcmp((char *)ptr,(char *)(parm->def.svalue))) continue;
+ break;
+
+ case P_BOOL:
+ case P_BOOLREV:
+ if (*(BOOL *)ptr == (BOOL)(parm->def.bvalue)) continue;
+ break;
+
+ case P_INTEGER:
+ case P_OCTAL:
+ if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
+ break;
+
+
+ case P_ENUM:
+ if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
+ break;
+ case P_SEP:
+ continue;
+ }
+ }
+ if (printers && !(parm->flags & FLAG_PRINT)) continue;
+ }
+ if (heading && heading != last_heading) {
+ d_printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", _(heading));
+ last_heading = heading;
+ }
+ show_parameter(snum, parm);
+ }
+}
+
+/****************************************************************************
+ load the smb.conf file into loadparm.
+****************************************************************************/
+static BOOL load_config(BOOL save_def)
+{
+ lp_resetnumservices();
+ return lp_load(dyn_CONFIGFILE,False,save_def,False);
+}
+
+/****************************************************************************
+ write a config file
+****************************************************************************/
+static void write_config(FILE *f, BOOL show_defaults)
+{
+ fprintf(f, "# Samba config file created using SWAT\n");
+ fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
+ fprintf(f, "# Date: %s\n\n", timestring(False));
+
+ lp_dump(f, show_defaults, iNumNonAutoPrintServices);
+}
+
+/****************************************************************************
+ save and reoad the smb.conf config file
+****************************************************************************/
+static int save_reload(int snum)
+{
+ FILE *f;
+ struct stat st;
+
+ f = sys_fopen(dyn_CONFIGFILE,"w");
+ if (!f) {
+ d_printf("failed to open %s for writing\n", dyn_CONFIGFILE);
+ return 0;
+ }
+
+ /* just in case they have used the buggy xinetd to create the file */
+ if (fstat(fileno(f), &st) == 0 &&
+ (st.st_mode & S_IWOTH)) {
+ fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+ }
+
+ write_config(f, False);
+ if (snum)
+ lp_dump_one(f, False, snum);
+ fclose(f);
+
+ lp_killunused(NULL);
+
+ if (!load_config(False)) {
+ d_printf("Can't reload %s\n", dyn_CONFIGFILE);
+ return 0;
+ }
+ iNumNonAutoPrintServices = lp_numservices();
+ load_printers();
+
+ return 1;
+}
+
+/****************************************************************************
+ commit one parameter
+****************************************************************************/
+static void commit_parameter(int snum, struct parm_struct *parm, char *v)
+{
+ int i;
+ char *s;
+
+ if (snum < 0 && parm->class == P_LOCAL) {
+ /* this handles the case where we are changing a local
+ variable globally. We need to change the parameter in
+ all shares where it is currently set to the default */
+ for (i=0;i<lp_numservices();i++) {
+ s = lp_servicename(i);
+ if (s && (*s) && lp_is_default(i, parm)) {
+ lp_do_parameter(i, parm->label, v);
+ }
+ }
+ }
+
+ lp_do_parameter(snum, parm->label, v);
+}
+
+/****************************************************************************
+ commit a set of parameters for a service
+****************************************************************************/
+static void commit_parameters(int snum)
+{
+ int i = 0;
+ struct parm_struct *parm;
+ pstring label;
+ char *v;
+
+ while ((parm = lp_next_parameter(snum, &i, 1))) {
+ slprintf(label, sizeof(label)-1, "parm_%s", make_parm_name(parm->label));
+ if ((v = cgi_variable(label))) {
+ if (parm->flags & FLAG_HIDE) continue;
+ commit_parameter(snum, parm, v);
+ }
+ }
+}
+
+/****************************************************************************
+ spit out the html for a link with an image
+****************************************************************************/
+static void image_link(const char *name, const char *hlink, const char *src)
+{
+ d_printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
+ cgi_baseurl(), hlink, src, name);
+}
+
+/****************************************************************************
+ display the main navigation controls at the top of each page along
+ with a title
+****************************************************************************/
+static void show_main_buttons(void)
+{
+ char *p;
+
+ if ((p = cgi_user_name()) && strcmp(p, "root")) {
+ d_printf(_("Logged in as <b>%s</b><p>\n"), p);
+ }
+
+ image_link(_("Home"), "", "images/home.gif");
+ if (have_write_access) {
+ image_link(_("Globals"), "globals", "images/globals.gif");
+ image_link(_("Shares"), "shares", "images/shares.gif");
+ image_link(_("Printers"), "printers", "images/printers.gif");
+ }
+ if (have_read_access) {
+ image_link(_("Status"), "status", "images/status.gif");
+ image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
+ }
+ image_link(_("Password Management"), "passwd", "images/passwd.gif");
+
+ d_printf("<HR>\n");
+}
+
+/****************************************************************************
+ display a welcome page
+****************************************************************************/
+static void welcome_page(void)
+{
+ include_html("help/welcome.html");
+}
+
+/****************************************************************************
+ display the current smb.conf
+****************************************************************************/
+static void viewconfig_page(void)
+{
+ int full_view=0;
+
+ if (cgi_variable("full_view")) {
+ full_view = 1;
+ }
+
+ d_printf("<H2>%s</H2>\n", _("Current Config"));
+ d_printf("<form method=post>\n");
+
+ if (full_view) {
+ d_printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
+ } else {
+ d_printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
+ }
+
+ d_printf("<p><pre>");
+ write_config(stdout, full_view);
+ d_printf("</pre>");
+ d_printf("</form>\n");
+}
+
+/****************************************************************************
+ display a globals editing page
+****************************************************************************/
+static void globals_page(void)
+{
+ int advanced = 0;
+
+ d_printf("<H2>%s</H2>\n", _("Global Variables"));
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit")) {
+ commit_parameters(GLOBALS_SNUM);
+ save_reload(0);
+ }
+
+ d_printf("<FORM name=\"swatform\" method=post>\n");
+
+ if (have_write_access) {
+ d_printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
+ _("Commit Changes"));
+ }
+
+ d_printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
+ _("Reset Values"));
+ if (advanced == 0) {
+ d_printf("<input type=submit name=\"Advanced\" value=\"%s\">\n", _("Advanced View"));
+ } else {
+ d_printf("<input type=submit name=\"Basic\" value=\"%s\">\n", _("Basic View"));
+ }
+ d_printf("<p>\n");
+
+ d_printf("<table>\n");
+ show_parameters(GLOBALS_SNUM, 1, advanced, 0);
+ d_printf("</table>\n");
+
+ if (advanced) {
+ d_printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ d_printf("</FORM>\n");
+}
+
+/****************************************************************************
+ display a shares editing page. share is in unix codepage, and must be in
+ dos codepage. FIXME !!! JRA.
+****************************************************************************/
+static void shares_page(void)
+{
+ char *share = cgi_variable("share");
+ char *s;
+ int snum = -1;
+ int i;
+ int advanced = 0;
+
+ if (share)
+ snum = lp_servicenumber(share);
+
+ d_printf("<H2>%s</H2>\n", _("Share Parameters"));
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ save_reload(0);
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload(0);
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ load_config(False);
+ lp_copy_service(GLOBALS_SNUM, share);
+ iNumNonAutoPrintServices = lp_numservices();
+ save_reload(0);
+ snum = lp_servicenumber(share);
+ }
+
+ d_printf("<FORM name=\"swatform\" method=post>\n");
+
+ d_printf("<table>\n");
+ d_printf("<tr>\n");
+ d_printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
+ d_printf("<td><select name=share>\n");
+ if (snum < 0)
+ d_printf("<option value=\" \"> \n");
+ for (i=0;i<lp_numservices();i++) {
+ s = lp_servicename(i);
+ if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
+ d_printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ }
+ }
+ d_printf("</select></td>\n");
+ if (have_write_access) {
+ d_printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
+ }
+ d_printf("</tr>\n");
+ d_printf("</table>");
+ d_printf("<table>");
+ if (have_write_access) {
+ d_printf("<tr>\n");
+ d_printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
+ d_printf("<td><input type=text size=30 name=newshare></td></tr>\n");
+ }
+ d_printf("</table>");
+
+
+ if (snum >= 0) {
+ if (have_write_access) {
+ d_printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
+ }
+
+ d_printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
+ if (advanced == 0) {
+ d_printf("<input type=submit name=\"Advanced\" value=\"%s\">\n", _("Advanced View"));
+ } else {
+ d_printf("<input type=submit name=\"Basic\" value=\"%s\">\n", _("Basic View"));
+ }
+ d_printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ d_printf("<table>\n");
+ show_parameters(snum, 1, advanced, 0);
+ d_printf("</table>\n");
+ }
+
+ if (advanced) {
+ d_printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ d_printf("</FORM>\n");
+}
+
+/*************************************************************
+change a password either locally or remotely
+*************************************************************/
+static BOOL change_password(const char *remote_machine, char *user_name,
+ char *old_passwd, char *new_passwd,
+ int local_flags)
+{
+ BOOL ret = False;
+ pstring err_str;
+ pstring msg_str;
+
+ if (demo_mode) {
+ d_printf("%s<p>", _("password change in demo mode rejected\n"));
+ return False;
+ }
+
+ if (remote_machine != NULL) {
+ ret = remote_password_change(remote_machine, user_name, old_passwd,
+ new_passwd, err_str, sizeof(err_str));
+ if(*err_str)
+ d_printf("%s\n<p>", err_str);
+ return ret;
+ }
+
+ if(!initialize_password_db(True)) {
+ d_printf("Can't setup password database vectors.\n<p>");
+ return False;
+ }
+
+ ret = local_password_change(user_name, local_flags, new_passwd, err_str, sizeof(err_str),
+ msg_str, sizeof(msg_str));
+
+ if(*msg_str)
+ d_printf("%s\n<p>", msg_str);
+ if(*err_str)
+ d_printf("%s\n<p>", err_str);
+
+ return ret;
+}
+
+/****************************************************************************
+ do the stuff required to add or change a password
+****************************************************************************/
+static void chg_passwd(void)
+{
+ char *host;
+ BOOL rslt;
+ int local_flags = 0;
+
+ /* Make sure users name has been specified */
+ if (strlen(cgi_variable(SWAT_USER)) == 0) {
+ d_printf("<p>%s", _(" Must specify \"User Name\" \n"));
+ return;
+ }
+
+ /*
+ * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
+ * so if that's what we're doing, skip the rest of the checks
+ */
+ if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
+
+ /*
+ * If current user is not root, make sure old password has been specified
+ * If REMOTE change, even root must provide old password
+ */
+ if (((!am_root()) && (strlen( cgi_variable(OLD_PSWD)) <= 0)) ||
+ ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable(OLD_PSWD)) <= 0))) {
+ d_printf("<p>%s", _(" Must specify \"Old Password\" \n"));
+ return;
+ }
+
+ /* If changing a users password on a remote hosts we have to know what host */
+ if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable(RHOST)) <= 0)) {
+ d_printf("<p>%s", _(" Must specify \"Remote Machine\" \n"));
+ return;
+ }
+
+ /* Make sure new passwords have been specified */
+ if ((strlen( cgi_variable(NEW_PSWD)) <= 0) ||
+ (strlen( cgi_variable(NEW2_PSWD)) <= 0)) {
+ d_printf("<p>%s", _(" Must specify \"New, and Re-typed Passwords\" \n"));
+ return;
+ }
+
+ /* Make sure new passwords was typed correctly twice */
+ if (strcmp(cgi_variable(NEW_PSWD), cgi_variable(NEW2_PSWD)) != 0) {
+ d_printf("<p>%s", _(" Re-typed password didn't match new password\n"));
+ return;
+ }
+ }
+
+ if (cgi_variable(CHG_R_PASSWD_FLAG)) {
+ host = cgi_variable(RHOST);
+ } else if (am_root()) {
+ host = NULL;
+ } else {
+ host = "127.0.0.1";
+ }
+
+ /*
+ * Set up the local flags.
+ */
+
+ local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
+ local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
+ local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
+ local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
+
+ rslt = change_password(host,
+ cgi_variable(SWAT_USER),
+ cgi_variable(OLD_PSWD), cgi_variable(NEW_PSWD),
+ local_flags);
+
+ if(local_flags == 0) {
+ d_printf("<p>");
+ if (rslt == True) {
+ d_printf(_(" The passwd for '%s' has been changed. \n"), cgi_variable(SWAT_USER));
+ } else {
+ d_printf(_(" The passwd for '%s' has NOT been changed. \n"), cgi_variable(SWAT_USER));
+ }
+ }
+
+ return;
+}
+
+/****************************************************************************
+ display a password editing page
+****************************************************************************/
+static void passwd_page(void)
+{
+ char *new_name = cgi_user_name();
+
+ /*
+ * After the first time through here be nice. If the user
+ * changed the User box text to another users name, remember it.
+ */
+ if (cgi_variable(SWAT_USER)) {
+ new_name = cgi_variable(SWAT_USER);
+ }
+
+ if (!new_name) new_name = "";
+
+ d_printf("<H2>%s</H2>\n", _("Server Password Management"));
+
+ d_printf("<FORM name=\"swatform\" method=post>\n");
+
+ d_printf("<table>\n");
+
+ /*
+ * Create all the dialog boxes for data collection
+ */
+ d_printf("<tr><td>%s</td>\n", _(" User Name : "));
+ d_printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
+ if (!am_root()) {
+ d_printf("<tr><td>%s</td>\n", _(" Old Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
+ }
+ d_printf("<tr><td>%s</td>\n", _(" New Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
+ d_printf("<tr><td>%s</td>\n", _(" Re-type New Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
+ d_printf("</table>\n");
+
+ /*
+ * Create all the control buttons for requesting action
+ */
+ d_printf("<input type=submit name=%s value=\"%s\">\n",
+ CHG_S_PASSWD_FLAG, _("Change Password"));
+ if (demo_mode || am_root()) {
+ d_printf("<input type=submit name=%s value=\"%s\">\n",
+ ADD_USER_FLAG, _("Add New User"));
+ d_printf("<input type=submit name=%s value=\"%s\">\n",
+ DELETE_USER_FLAG, _("Delete User"));
+ d_printf("<input type=submit name=%s value=\"%s\">\n",
+ DISABLE_USER_FLAG, _("Disable User"));
+ d_printf("<input type=submit name=%s value=\"%s\">\n",
+ ENABLE_USER_FLAG, _("Enable User"));
+ }
+ d_printf("<p></FORM>\n");
+
+ /*
+ * Do some work if change, add, disable or enable was
+ * requested. It could be this is the first time through this
+ * code, so there isn't anything to do. */
+ if ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
+ (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG))) {
+ chg_passwd();
+ }
+
+ d_printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
+
+ d_printf("<FORM name=\"swatform\" method=post>\n");
+
+ d_printf("<table>\n");
+
+ /*
+ * Create all the dialog boxes for data collection
+ */
+ d_printf("<tr><td>%s</td>\n", _(" User Name : "));
+ d_printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
+ d_printf("<tr><td>%s</td>\n", _(" Old Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
+ d_printf("<tr><td>%s</td>\n", _(" New Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
+ d_printf("<tr><td>%s</td>\n", _(" Re-type New Password : "));
+ d_printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
+ d_printf("<tr><td>%s</td>\n", _(" Remote Machine : "));
+ d_printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
+
+ d_printf("</table>");
+
+ /*
+ * Create all the control buttons for requesting action
+ */
+ d_printf("<input type=submit name=%s value=\"%s\">",
+ CHG_R_PASSWD_FLAG, _("Change Password"));
+
+ d_printf("<p></FORM>\n");
+
+ /*
+ * Do some work if a request has been made to change the
+ * password somewhere other than the server. It could be this
+ * is the first time through this code, so there isn't
+ * anything to do. */
+ if (cgi_variable(CHG_R_PASSWD_FLAG)) {
+ chg_passwd();
+ }
+
+}
+
+/****************************************************************************
+ display a printers editing page
+****************************************************************************/
+static void printers_page(void)
+{
+ char *share = cgi_variable("share");
+ char *s;
+ int snum=-1;
+ int i;
+ int advanced = 0;
+
+ if (share)
+ snum = lp_servicenumber(share);
+
+ d_printf("<H2>%s</H2>\n", _("Printer Parameters"));
+
+ d_printf("<H3>%s</H3>\n", _("Important Note:"));
+ d_printf(_("Printer names marked with [*] in the Choose Printer drop-down box "));
+ d_printf(_("are autoloaded printers from "));
+ d_printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
+ d_printf(_("Attempting to delete these printers from SWAT will have no effect.\n"));
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ if (snum >= iNumNonAutoPrintServices)
+ save_reload(snum);
+ else
+ save_reload(0);
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload(0);
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ load_config(False);
+ lp_copy_service(GLOBALS_SNUM, share);
+ iNumNonAutoPrintServices = lp_numservices();
+ snum = lp_servicenumber(share);
+ lp_do_parameter(snum, "print ok", "Yes");
+ save_reload(0);
+ snum = lp_servicenumber(share);
+ }
+
+ d_printf("<FORM name=\"swatform\" method=post>\n");
+
+ d_printf("<table>\n");
+ d_printf("<tr><td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Printer"));
+ d_printf("<td><select name=share>\n");
+ if (snum < 0 || !lp_print_ok(snum))
+ d_printf("<option value=\" \"> \n");
+ for (i=0;i<lp_numservices();i++) {
+ s = lp_servicename(i);
+ if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
+ if (i >= iNumNonAutoPrintServices)
+ d_printf("<option %s value=\"%s\">[*]%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ else
+ d_printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ }
+ }
+ d_printf("</select></td>");
+ if (have_write_access) {
+ d_printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
+ }
+ d_printf("</tr>");
+ d_printf("</table>\n");
+
+ if (have_write_access) {
+ d_printf("<table>\n");
+ d_printf("<tr><td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Printer"));
+ d_printf("<td><input type=text size=30 name=newshare></td></tr>\n");
+ d_printf("</table>");
+ }
+
+
+ if (snum >= 0) {
+ if (have_write_access) {
+ d_printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
+ }
+ d_printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
+ if (advanced == 0) {
+ d_printf("<input type=submit name=\"Advanced\" value=\"%s\">\n", _("Advanced View"));
+ } else {
+ d_printf("<input type=submit name=\"Basic\" value=\"%s\">\n", _("Basic View"));
+ }
+ d_printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ d_printf("<table>\n");
+ show_parameters(snum, 1, advanced, 1);
+ d_printf("</table>\n");
+ }
+
+ if (advanced) {
+ d_printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ d_printf("</FORM>\n");
+}
+
+
+/**
+ * main function for SWAT.
+ **/
+ int main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ char *page;
+
+ fault_setup(NULL);
+ umask(S_IWGRP | S_IWOTH);
+
+#if defined(HAVE_SET_AUTH_PARAMETERS)
+ set_auth_parameters(argc, argv);
+#endif /* HAVE_SET_AUTH_PARAMETERS */
+
+ /* just in case it goes wild ... */
+ alarm(300);
+
+ setlinebuf(stdout);
+
+ /* we don't want any SIGPIPE messages */
+ BlockSignals(True,SIGPIPE);
+
+ dbf = x_fopen("/dev/null", O_WRONLY, 0);
+ if (!dbf) dbf = x_stderr;
+
+ /* we don't want stderr screwing us up */
+ close(2);
+ open("/dev/null", O_WRONLY);
+
+ while ((opt = getopt(argc, argv,"s:a")) != EOF) {
+ switch (opt) {
+ case 's':
+ pstrcpy(dyn_CONFIGFILE,optarg);
+ break;
+ case 'a':
+ demo_mode = True;
+ break;
+ }
+ }
+
+ setup_logging(argv[0],False);
+ load_config(True);
+ iNumNonAutoPrintServices = lp_numservices();
+ load_printers();
+
+ cgi_setup(dyn_SWATDIR, !demo_mode);
+
+ print_header();
+
+ cgi_load_variables();
+
+ if (!file_exist(dyn_CONFIGFILE, NULL)) {
+ have_read_access = True;
+ have_write_access = True;
+ } else {
+ /* check if the authenticated user has write access - if not then
+ don't show write options */
+ have_write_access = (access(dyn_CONFIGFILE,W_OK) == 0);
+
+ /* if the user doesn't have read access to smb.conf then
+ don't let them view it */
+ have_read_access = (access(dyn_CONFIGFILE,R_OK) == 0);
+ }
+
+ show_main_buttons();
+
+ page = cgi_pathinfo();
+
+ /* Root gets full functionality */
+ if (have_read_access && strcmp(page, "globals")==0) {
+ globals_page();
+ } else if (have_read_access && strcmp(page,"shares")==0) {
+ shares_page();
+ } else if (have_read_access && strcmp(page,"printers")==0) {
+ printers_page();
+ } else if (have_read_access && strcmp(page,"status")==0) {
+ status_page();
+ } else if (have_read_access && strcmp(page,"viewconfig")==0) {
+ viewconfig_page();
+ } else if (strcmp(page,"passwd")==0) {
+ passwd_page();
+ } else {
+ welcome_page();
+ }
+
+ print_footer();
+ return 0;
+}
+
+/** @} **/
diff --git a/swat/README b/swat/README
new file mode 100644
index 00000000000..588ecef769a
--- /dev/null
+++ b/swat/README
@@ -0,0 +1,77 @@
+This is a brief description of how to install and use the Samba Web
+Administration Tool on your machine.
+
+Installation
+------------
+
+After you compile SWAT you need to run "make install" to install the
+swat binary and the various help files and images. A default install
+would put these in:
+
+/usr/local/samba/bin/swat
+/usr/local/samba/swat/images/*
+/usr/local/samba/swat/help/*
+
+Running via inetd
+-----------------
+
+You then need to edit your /etc/inetd.conf and /etc/services to enable
+SWAT to be launched via inetd.
+
+In /etc/services you need to add a line like this:
+
+swat 901/tcp
+
+the choice of port number isn't really important except that it should
+be less than 1024 and not currently used (using a number above 1024
+presents an obscure security hole depending on the implementation
+details of your inetd daemon).
+
+In /etc/inetd.conf you should add a line like this:
+
+swat stream tcp nowait.400 root /usr/local/samba/bin/swat swat
+
+One you have edited /etc/services and /etc/inetd.conf you need to send
+a HUP signal to inetd. On many systems "killall -1 inetd" will do this
+on others you will need to use "kill -1 PID" where PID is the process
+ID of the inetd daemon.
+
+
+
+Launching
+---------
+
+To launch SWAT just run your favourite web browser and point it at
+http://localhost:901/
+
+Note that you can attach to SWAT from any IP connected machine but
+connecting from a remote machine leaves your connection open to
+password sniffing as passwords will be sent in the clear over the
+wire.
+
+You should be prompted for a username/password when you connect. You
+will need to provide the username "root" and the correct root
+password.
+
+Running
+-------
+
+Just follow your nose! If you can't work out how to use it then maybe
+you should use "vi smb.conf" instead.
+
+
+WARNINGS
+--------
+
+SWAT will rewrite your smb.conf file. It will rearrange the entries
+and delete all comments, include= and copy= options. If you have a
+carefully crafted smb.conf then back it up or don't use SWAT!
+
+
+Development
+-----------
+
+Please join the samba-technical mailing list if you want to discuss
+the development of SWAT. Note that this list is for technical developer
+discussions and is not a general help list.
+
diff --git a/swat/help/welcome.html b/swat/help/welcome.html
new file mode 100644
index 00000000000..1c23d35a27c
--- /dev/null
+++ b/swat/help/welcome.html
@@ -0,0 +1,68 @@
+<h3>Welcome to SWAT!</h3>
+
+Please choose a configuration action using one of the above buttons
+
+<h3><a href="/swat/help/samba.7.html" target="docs">Samba</a> Documentation</h3>
+
+<ul>
+ <li><b>Daemons</b>
+ <ul>
+ <li><a href="/swat/help/smbd.8.html" target="docs">smbd</a> - the SMB daemon
+ <li><a href="/swat/help/nmbd.8.html" target="docs">nmbd</a> - the NetBIOS nameserver
+ <li><a href="/swat/help/winbindd.8.html" target="docs">winbindd</a> - the winbind daemon
+ </ul>
+ <li><b>Configuration Files</b>
+ <ul>
+ <li><a href="/swat/help/smb.conf.5.html" target="docs">smb.conf</a> - the main Samba configuration file
+ <li><a href="/swat/help/lmhosts.5.html" target="docs">lmhosts</a> - NetBIOS hosts file
+ <li><a href="/swat/help/smbpasswd.5.html" target="docs">smbpasswd</a> - SMB password file
+ </ul>
+ <li><b>Administrative Utilities</b>
+ <ul>
+ <li><a href="/swat/help/smbcontrol.1.html" target="docs">smbcontrol</a> - send control messages to Samba daemons
+ <li><a href="/swat/help/smbpasswd.8.html" target="docs">smbpasswd</a> - managing SMB passwords
+ <li><a href="/swat/help/swat.8.html" target="docs">SWAT</a> - web configuration tool
+ <li><a href="/swat/help/make_smbcodepage.1.html" target="docs">make_smbcodepage</a> - codepage creation
+ <li><a href="/swat/help/make_unicodemap.1.html" target="docs">make_unicodemap</a> - unicode map file creation
+ <li><a href="/swat/help/smbrun.1.html" target="docs">smbrun</a> - internal smbd utility
+ </ul>
+ <li><b>Client Tools</b>
+ <ul>
+ <li><a href="/swat/help/rpcclient.1.html" target="docs">rpcclient</a> - command line MS-RPC client
+ <li><a href="/swat/help/smbtar.1.html" target="docs">smbtar</a> - SMB backup tool
+ <li><a href="/swat/help/smbclient.1.html" target="docs">smbclient</a> - command line SMB client
+ <li><a href="/swat/help/smbmnt.8.html" target="docs">smbmnt</a> - helper utility for mounting SMB filesystems on Linux hosts
+ <li><a href="/swat/help/smbmount.8.html" target="docs">smbmount</a> - user space tool for mounting SMB filesystems under Linux
+ <li><a href="/swat/help/smbspool.8.html" target="docs">smbspool</a> - command line SMB print client
+ <li><a href="/swat/help/smbumount.8.html" target="docs">smbumount</a> - user space tool for umounting SMB filesystems under Linux
+ </ul>
+ <li><b>Diagnostic Utilities</b>
+ <ul>
+ <li><a href="/swat/help/smbstatus.1.html" target="docs">smbstatus</a> - monitoring Samba
+ <li><a href="/swat/help/testparm.1.html" target="docs">testparm</a> - validating your config file
+ <li><a href="/swat/help/testprns.1.html" target="docs">testprns</a> - testing printer configuration
+ <li><a href="/swat/help/nmblookup.1.html" target="docs">nmblookup</a> - NetBIOS name query tool
+ </ul>
+ <li><b>Books</b>
+ <ul>
+ <li><a href="/swat/using_samba/index.html" target="docs">Using Samba</a> - by Robert Eckstein, David Collier-Brown and Peter Kelly
+ </ul>
+ <li><b>Samba HOWTO Collection</b></li>
+ <ul>
+ <li><a href="/swat/help/Samba-HOWTO-Collection.html">Entire Collection (one file)</a>
+ <li><a href="/swat/help/DOMAIN_MEMBER.html">security = domain in Samba 2.x</a>
+ <li><a href="/swat/help/winbind.html">Unified Logons between Windows NT and UNIX Using Winbind</a>
+ <li><a href="/swat/help/msdfs_setup.html">Setting Samba as an MS-DFS server</a>
+ <li><a href="/swat/help/NT_Security.html">UNIX Permission Bits and Samba 2.x</a>
+ <li><a href="/swat/help/OS2-Client-HOWTO.html">OS/2 Clients and Samba</a>
+ <li><a href="/swat/help/printer_driver2.html">Printing under Samba 2.2.x</a>
+ <li><a href="/swat/help/UNIX_INSTALL.html">HOWTO Install and Test Samba</a>
+ <li><a href="/swat/help/Integrating-with-Windows.html">Integrating Name Resolution and Authentication Services</a>
+ <li><a href="/swat/help/CVS-Access.html">CVS Access to Samba code</a>
+ </ul>
+</ul>
+
+ <h3>Feedback</h3>
+
+ Please join the <A HREF="http://lists.samba.org/">samba</A> mailing
+ list if you want to discuss issues with this release of SWAT.
diff --git a/swat/images/globals.gif b/swat/images/globals.gif
new file mode 100644
index 00000000000..75e874f380c
--- /dev/null
+++ b/swat/images/globals.gif
Binary files differ
diff --git a/swat/images/home.gif b/swat/images/home.gif
new file mode 100644
index 00000000000..364a2955c84
--- /dev/null
+++ b/swat/images/home.gif
Binary files differ
diff --git a/swat/images/passwd.gif b/swat/images/passwd.gif
new file mode 100644
index 00000000000..2fc88fb182e
--- /dev/null
+++ b/swat/images/passwd.gif
Binary files differ
diff --git a/swat/images/printers.gif b/swat/images/printers.gif
new file mode 100644
index 00000000000..212a70c6640
--- /dev/null
+++ b/swat/images/printers.gif
Binary files differ
diff --git a/swat/images/samba.gif b/swat/images/samba.gif
new file mode 100644
index 00000000000..3ec3d2195ff
--- /dev/null
+++ b/swat/images/samba.gif
Binary files differ
diff --git a/swat/images/shares.gif b/swat/images/shares.gif
new file mode 100644
index 00000000000..2c04ca8b9c7
--- /dev/null
+++ b/swat/images/shares.gif
Binary files differ
diff --git a/swat/images/status.gif b/swat/images/status.gif
new file mode 100644
index 00000000000..48e2f07fcd7
--- /dev/null
+++ b/swat/images/status.gif
Binary files differ
diff --git a/swat/images/viewconfig.gif b/swat/images/viewconfig.gif
new file mode 100644
index 00000000000..5dee5156690
--- /dev/null
+++ b/swat/images/viewconfig.gif
Binary files differ
diff --git a/swat/include/footer.html b/swat/include/footer.html
new file mode 100644
index 00000000000..7c3b483684c
--- /dev/null
+++ b/swat/include/footer.html
@@ -0,0 +1,3 @@
+</TD></TR></TABLE></CENTER>
+</BODY>
+</HTML>
diff --git a/swat/include/header.html b/swat/include/header.html
new file mode 100644
index 00000000000..f964133316a
--- /dev/null
+++ b/swat/include/header.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>Samba Web Administration Tool</TITLE>
+</HEAD>
+<BODY bgcolor="white">
+<CENTER>
+<IMG SRC="/swat/images/samba.gif" ALT="[ Samba ]" border=0><BR>
+<TABLE WIDTH="98%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
+<TR><TD BGCOLOR="#ddddd0">
diff --git a/swat/lang/ja/help/welcome.html b/swat/lang/ja/help/welcome.html
new file mode 100644
index 00000000000..f8266cf825b
--- /dev/null
+++ b/swat/lang/ja/help/welcome.html
@@ -0,0 +1,86 @@
+<h2>SWAT : Samba Web Administaration Tool !</h2>
+
+<p>Samba‚ÌÝ’è‚Íã‚̃{ƒ^ƒ“‚ðƒNƒŠƒbƒN‚µ‚Äs‚¢‚Ü‚·B </p>
+
+<h3>ƒhƒLƒ…ƒƒ“ƒg</h3>
+
+<ul>
+ <li><b>“±“ü•Ò</b><ul>
+ <li><a href="/swat/ja/help/samba-j.html" target="docs">Samba“ú–{Œê”łɂ‚¢‚Ä</a>
+ <li><a href="/swat/ja/help/samba-func.html" target="docs">Samba ‹@”\Ú×</a> - Windows NT‚Æ‚Ì‹@”\”äŠr
+ <li><a href="/swat/ja/help/samba2.html" target="docs">Samba 2.0 V‹@”\Љî</a>
+ <li><a href="/swat/ja/help/sambafaq.html" target="docs">Samba FAQ ‚æ‚­‚ ‚鎿–â</a>
+
+ <li><a href="/swat/ja/help/encrypt-passwd.html" target="docs">Windows 98/Me, Windows NT 4.0, Windows 2000‚Å‚Ì’ˆÓŽ–€</a>
+ <li><a href="/swat/ja/help/HowToUseSamba/index.html" target="docs">Samba‚É‚æ‚éƒtƒ@ƒCƒ‹ƒT[ƒo\’z–@(Samba“ü–å)</a>
+ <li><a href="/swat/using_samba/ja/index.html" target="docs">Using Samba(–|–ó”Å)</a>
+ </ul>
+
+ <li><b>ƒf[ƒ‚ƒ“</b> <ul>
+ <li><a href="/swat/ja/help/smbd.8.html" target="docs">smbd</a> - ƒtƒ@ƒCƒ‹‹¤—LƒT[ƒrƒXƒf[ƒ‚ƒ“
+ <li><a href="/swat/ja/help/nmbd.8.html" target="docs">nmbd</a> - ƒl[ƒ€ ƒT[ƒrƒXƒf[ƒ‚ƒ“
+ </ul>
+
+ <li><b>ŠÇ—ƒ†[ƒeƒBƒŠƒeƒB</b> <ul>
+ <li><a href="/swat/ja/help/smbstatus.1.html" target="docs">smbstatus</a> - Œ»Ý‚Ì Samba ‚Ö‚ÌÚ‘±ó‹µ‚ð•ñ
+ <li><a href="/swat/ja/help/swat.8.html" target="docs">SWAT</a> - Samba Web ŠÇ—ƒc[ƒ‹
+ <li><a href="/swat/ja/help/smbpasswd.8.html" target="docs">smbpasswd</a> - ƒ†[ƒU‚Ì SMB ƒpƒXƒ[ƒh‚Ì•ÏX
+ <li><a href="/swat/ja/help/make_smbcodepage.1.html" target="docs">make_smbcodepage</a> - ƒR[ƒhƒy[ƒW’è‹`ƒtƒ@ƒCƒ‹‚Ìì¬
+ <li><a href="/swat/ja/help/testparm.1.html" target="docs">testparm</a> - smb.conf Ý’èƒtƒ@ƒCƒ‹“à•”‚̳“–«‚ðŒŸ¸
+ <li><a href="/swat/ja/help/testprns.1.html" target="docs">testprns</a> - smbd ‚Å—LŒø‚ȃvƒŠƒ“ƒ^–¼‚©‚Ç‚¤‚©‚ÌŒŸ¸
+ <li><a href="/swat/ja/help/smbmnt.8.html" target="docs">smbmnt(8)</a> - SMB ƒtƒ@ƒCƒ‹ƒVƒXƒeƒ€‚̃}ƒEƒ“ƒg
+ <li><a href="/swat/ja/help/smbmount.8.html" target="docs">smbmount(8)</a> - SMB ƒtƒ@ƒCƒ‹ƒVƒXƒeƒ€‚̃}ƒEƒ“ƒg
+<!-- <li><a href="/swat/ja/help/smbumount.8.html" target="docs">smbumount(8)</a> -
+ ˆê”ʃ†[ƒU‚É‚æ‚éƒAƒ“ƒ}ƒEƒ“ƒg -->
+ </ul>
+
+ <li><b>ƒ†[ƒeƒBƒŠƒeƒB</b> <ul>
+ <li><a href="/swat/ja/help/smbsh.1.html" target="docs">smbsh(1)</a> - UNIX ƒVƒFƒ‹‚©‚ç SMB ‹¤—L‚ւ̃AƒNƒZƒX‚ðŽÀŒ»
+ <li><a href="/swat/ja/help/nmblookup.1.html" target="docs">nmblookup</a> - NetBIOS –¼‚ÌŒŸõ
+ <li><a href="/swat/ja/help/smbtar.1.html" target="docs">smbtar</a> - SMB/CIFS ‹¤—L‚ð UNIX ‚̃e[ƒv‚È‚Ç‚ÖƒoƒbƒNƒAƒbƒv
+ <li><a href="/swat/ja/help/smbclient.1.html" target="docs">smbclient</a> - ftp ƒRƒ}ƒ“ƒh•—‚Ì SMB/CIFS ƒNƒ‰ƒCƒAƒ“ƒg
+ </ul>
+
+ <li><b>Ý’èƒtƒ@ƒCƒ‹</b> <ul>
+ <li><a href="/swat/ja/help/smb.conf.5.html" target="docs">smb.conf</a> - Samba ‚ÌÝ’èƒtƒ@ƒCƒ‹
+<!-- <li><a href="/swat/ja/help/smb.conf.default.txt.html" target="docs">smb.conf.default</a> - SambaÝ’èƒtƒ@ƒCƒ‹‚Ì—á</code>
+ -->
+ <li><a href="/swat/ja/help/lmhosts.5.html" target="docs">lmhosts</a> - Samba ‚Ì NetBIOS hosts ƒtƒ@ƒCƒ‹
+ <li><a href="/swat/ja/help/smbpasswd.5.html" target="docs">smbpasswd</a> - Samba ‚̈Ɖ»ƒpƒXƒ[ƒhEƒtƒ@ƒCƒ‹
+ </ul>
+
+ <li><b>‚»‚Ì‘¼</b> <ul>
+ <li><a href="/swat/ja/help/DIAGNOSIS.txt.html" target="docs">SambaƒT[ƒo‚Ìf’fEáŠQ‰ðÍ•û–@</a> - <code>DIAGNOSIS.txt</code>
+ <li><a href="/swat/ja/help/tuning.japanese.html" target="docs">Samba‚ÅWindows NT Server ‚Æ“¯‚¶“]‘—‘¬“x‚ðŠm•Û‚·‚é•û–@</a>
+ <li><a href="/swat/help/samba.7.html" target="docs">Samba introduction</a> - UNIX —p‚Ì Windows SMB/CIFS ƒtƒ@ƒCƒ‹ƒT[ƒo
+ <li><a href="/swat/ja/help/DOMAIN_MEMBER.txt.html" target="docs">Samba ƒT[ƒo‚ð NT ƒhƒƒCƒ“‚ÉŽQ‰Á‚³‚¹‚é‚É‚Í</a> - <code>DOMAIN_MEMBER.txt</code>
+ <li><a href="/swat/ja/help/NT_Security.html" target="docs">NT ‚̃ZƒLƒ…ƒŠƒeƒBƒ_ƒCƒAƒƒO‚ð—˜—p‚µ UNIX ‚̃p[ƒ~ƒbƒVƒ‡ƒ“‚ð‰{——/•ÏX‚·‚é</a>
+ <li><a href="/swat/ja/help/smbrun.1.html" target="docs">smbrun</a> - smbd ‚ÆŠO•”ƒvƒƒOƒ‰ƒ€ŠÔ‚̃Cƒ“ƒ^ƒtƒF[ƒX
+ <li><a href="/swat/ja/help/Application_Serving.txt.html" target="docs">Samba ‹¤—L‚ð MS Office ‚È‚Ç‚ÌŠÇ—‹¤—L‚Æ‚µ‚ÄŽg—p</a> - <code>Application_Serving.txt</code>
+ <li><a href="/swat/ja/help/BROWSING.txt.html" target="docs">ƒuƒ‰ƒEƒWƒ“ƒO‚ð‰ü‘P‚·‚邽‚ß‚ÌÝ’è•û–@</a> - <code>BROWSING.txt</code>
+ <li><a href="/swat/ja/help/CRLF-LF-Conversions.txt.html" target="docs">ƒvƒ‰ƒbƒgƒtƒH[ƒ€ŠÔ‚̃eƒLƒXƒgƒtƒ@ƒCƒ‹‚Ì–â‘è</a> - <code>CRLF-LF-Conversions.txt</code>
+ <li><a href="/swat/ja/help/DOMAIN.txt.html" target="docs">ƒlƒbƒgƒ[ƒNƒƒOƒIƒ“‚ƈړ®ƒvƒƒtƒ@ƒCƒ‹</a> - <code>DOMAIN.txt</code>
+ <li><a href="/swat/ja/help/ENCRYPTION.txt.html" target="docs">LanManager / Samba ƒpƒXƒ[ƒh‚̈Ɖ»</a> - <code>ENCRYPTION.txt</code>
+ <li><a href="/swat/ja/help/File-Cacheing.txt.html" target="docs">•Ö‹X“IƒƒbƒN(oplocks)‚É‚æ‚éƒLƒƒƒbƒVƒ…‚Ì–â‘è</a> - <code>File-Cacheing.txt</code>
+ <li><a href="/swat/ja/help/NT-Guest-Access.txt.html" target="docs">NT ‚̃QƒXƒgEƒAƒJƒEƒ“ƒg‚̃oƒO</a> - <code>NT-Guest-Access.txt</code>
+ <li><a href="/swat/ja/help/NTDOMAIN.txt.html" target="docs">NT ƒhƒƒCƒ“ƒƒOƒIƒ“‹@”\</a> - <code>NTDOMAIN.txt</code>
+ <li><a href="/swat/ja/help/NetBIOS.txt.html" target="docs">NetBIOS
+ ƒvƒƒgƒRƒ‹‚Æ–¼‘O‰ðŒˆ•ûŽ®‚Ìà–¾</a> - <code>NetBIOS.txt</code>
+ <li><a href="/swat/ja/help/PRINTER_DRIVER.txt.html" target="docs">‹¤—L <code>PRINTER$</code> ‚̃Tƒ|[ƒg</a> - <code>PRINTER_DRIVER.txt</code>
+ <li><a href="/swat/ja/help/PROFILES.txt.html" target="docs">ƒ†[ƒUEƒvƒƒtƒ@ƒCƒ‹‚ɂ‚¢‚Ä‚Ì‹c˜_</a> - <code>PROFILES.txt</code>
+ <li><a href="/swat/ja/help/Passwords.txt.html" target="docs">ƒpƒXƒ[ƒh‚ɂ‚¢‚Ä‚Ì’ˆÓ</a> - <code>Passwords.txt</code>
+ <li><a href="/swat/ja/help/README.smbmount.txt.html" target="docs">SMBFS —pƒ}ƒEƒ“ƒgƒc[ƒ‹‚ÉŠÖ‚µ‚Ä</a> - <code>README.smbmount</code>
+ <li><a href="/swat/ja/help/Speed.txt.html" target="docs">Samba ‚Ì«”\‚ɂ‚¢‚Ä</a> - <code>Speed.txt</code>
+ <li><a href="/swat/ja/help/Speed2.txt.html" target="docs">Samba <code>Speed.txt</code> ‚ɑ΂·‚éƒRƒƒ“ƒg</a> - <code>Speed2.txt</code>
+ <li><a href="/swat/ja/help/UNIX-SMB.txt.html" target="docs">UNIX ŠE‚É‚¨‚¯‚é NetBIOS ‚ɂ‚¢‚Ă̘_•¶</a> - <code>UNIX-SMB.txt</code>
+ <li><a href="/swat/ja/help/UNIX_INSTALL.txt.html" target="docs">Samba ‚̃Cƒ“ƒXƒg[ƒ‹‚ƃeƒXƒg•û–@</a> - <code>UNIX_INSTALL.txt</code>
+ <li><a href="/swat/ja/help/security_level.txt.html" target="docs">SMB ƒZƒLƒ…ƒŠƒeƒBEƒŒƒxƒ‹‚ÌŽí—Þ</a> - <code>security_level.txt</code>
+ <li><a href="/swat/ja/help/WinNT.txt.html" target="docs">Samba ‚Æ Windows NT ‚̃pƒXƒ[ƒh‚̈µ‚¢</a> - <code>WinNT.txt</code>
+ <li><a href="/swat/ja/help/Win95.txt.html" target="docs">Windows 95 / 98 ‚Æ Samba ‚Ì‘ŠŒÝ‰^—p</a> - <code>Win95.txt</code>
+ <li><a href="/swat/ja/help/Macintosh_Clients.txt.html" target="docs">ƒ}ƒbƒN‚Å“®‚­ Samba ƒNƒ‰ƒCƒAƒ“ƒg‚Í‚ ‚è‚Ü‚·‚©?</a> - <code>Macintosh_Clients.txt</code>
+ </ul>
+</ul>
+
+<h3>ƒtƒB[ƒhƒoƒbƒN</h3>
+
+<p>“ú–{Œê‰»‚ÉŠÖ‚·‚邱‚Æ‚ÍA <a href="http://www.samba.gr.jp/ml/#sugj-tech" target="docs">SambaƒeƒNƒjƒJƒ‹ƒ[ƒŠƒ“ƒOƒŠƒXƒg</a>‚Ü‚Å‚¨Šè‚¢‚µ‚Ü‚·B</p>
diff --git a/swat/lang/ja/images/globals.gif b/swat/lang/ja/images/globals.gif
new file mode 100644
index 00000000000..5f8eb15b34a
--- /dev/null
+++ b/swat/lang/ja/images/globals.gif
Binary files differ
diff --git a/swat/lang/ja/images/home.gif b/swat/lang/ja/images/home.gif
new file mode 100644
index 00000000000..a4e61229583
--- /dev/null
+++ b/swat/lang/ja/images/home.gif
Binary files differ
diff --git a/swat/lang/ja/images/passwd.gif b/swat/lang/ja/images/passwd.gif
new file mode 100644
index 00000000000..c8242bf7228
--- /dev/null
+++ b/swat/lang/ja/images/passwd.gif
Binary files differ
diff --git a/swat/lang/ja/images/printers.gif b/swat/lang/ja/images/printers.gif
new file mode 100644
index 00000000000..f0db94cb57a
--- /dev/null
+++ b/swat/lang/ja/images/printers.gif
Binary files differ
diff --git a/swat/lang/ja/images/samba.gif b/swat/lang/ja/images/samba.gif
new file mode 100644
index 00000000000..0c13dc9ef37
--- /dev/null
+++ b/swat/lang/ja/images/samba.gif
Binary files differ
diff --git a/swat/lang/ja/images/shares.gif b/swat/lang/ja/images/shares.gif
new file mode 100644
index 00000000000..afc1b55cf5e
--- /dev/null
+++ b/swat/lang/ja/images/shares.gif
Binary files differ
diff --git a/swat/lang/ja/images/status.gif b/swat/lang/ja/images/status.gif
new file mode 100644
index 00000000000..f506cda77f8
--- /dev/null
+++ b/swat/lang/ja/images/status.gif
Binary files differ
diff --git a/swat/lang/ja/images/viewconfig.gif b/swat/lang/ja/images/viewconfig.gif
new file mode 100644
index 00000000000..ebc05f6c69d
--- /dev/null
+++ b/swat/lang/ja/images/viewconfig.gif
Binary files differ
diff --git a/swat/lang/ja/include/footer.html b/swat/lang/ja/include/footer.html
new file mode 100644
index 00000000000..7c3b483684c
--- /dev/null
+++ b/swat/lang/ja/include/footer.html
@@ -0,0 +1,3 @@
+</TD></TR></TABLE></CENTER>
+</BODY>
+</HTML>
diff --git a/swat/lang/ja/include/header.html b/swat/lang/ja/include/header.html
new file mode 100644
index 00000000000..2fbe9bb7546
--- /dev/null
+++ b/swat/lang/ja/include/header.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
+<TITLE>Samba Web Administration Tool</TITLE>
+<link rel="STYLESHEET" type="text/css" href="/swat/include/header_css.html">
+</HEAD>
+<BODY bgcolor="white">
+<CENTER>
+<IMG SRC="/swat/images/samba.gif" ALT="[ Samba ]" border=0><BR>
+<TABLE WIDTH="98%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
+<TR><TD BGCOLOR="#ddddd0">
diff --git a/swat/lang/ja/include/header.nocss.html b/swat/lang/ja/include/header.nocss.html
new file mode 100644
index 00000000000..56d13dbc6d1
--- /dev/null
+++ b/swat/lang/ja/include/header.nocss.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
+<TITLE>Samba Web Administration Tool</TITLE>
+</HEAD>
+<BODY bgcolor="white">
+<CENTER>
+<IMG SRC="/swat/images/samba.gif" ALT="[ Samba ]" border=0><BR>
+<TABLE WIDTH="98%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
+<TR><TD BGCOLOR="#ddddd0">
diff --git a/swat/lang/ja/include/header_css.html b/swat/lang/ja/include/header_css.html
new file mode 100644
index 00000000000..b70876b6f82
--- /dev/null
+++ b/swat/lang/ja/include/header_css.html
@@ -0,0 +1 @@
+.i18n_translated_parm {color: #555555}
diff --git a/swat/lang/tr/help/welcome.html b/swat/lang/tr/help/welcome.html
new file mode 100644
index 00000000000..617f3678d39
--- /dev/null
+++ b/swat/lang/tr/help/welcome.html
@@ -0,0 +1,69 @@
+<h3>Swat'a Hoþgeldiniz!</h3>
+
+Yukarýdaki düðmelerden birini kullanarak bir ayar eylemi seçin.
+
+<h3><a href="/swat/help/samba.7.html" target="docs">Samba</a> Dökümantasyon</h3>
+
+<ul>
+ <li><b>Sunucular</b>
+ <ul>
+ <li><a href="/swat/help/smbd.8.html" target="docs">smbd</a> - SMB sunucusu
+ <li><a href="/swat/help/nmbd.8.html" target="docs">nmbd</a> - NetBIOS isim sunucusu
+ <li><a href="/swat/help/winbindd.8.html" target="docs">winbindd</a> - winbind sunucusu
+ </ul>
+ <li><b>Ayar dosyalarý</b>
+ <ul>
+ <li><a href="/swat/help/smb.conf.5.html" target="docs">smb.conf</a> - ana Samba ayar dosyasý
+ <li><a href="/swat/help/lmhosts.5.html" target="docs">lmhosts</a> - NetBIOS hosts dosyasý
+ <li><a href="/swat/help/smbpasswd.5.html" target="docs">smbpasswd</a> - SMB þifre dosyasý
+ </ul>
+ <li><b>Yönetim Araçlarý</b>
+ <ul>
+ <li><a href="/swat/help/smbcontrol.1.html" target="docs">smbcontrol</a> - Samba sunucularýna kontrol iletileri gönderir
+ <li><a href="/swat/help/smbpasswd.8.html" target="docs">smbpasswd</a> - SMB þifrelerini düzenler
+ <li><a href="/swat/help/swat.8.html" target="docs">SWAT</a> - web arayüzlü ayar aracý
+ <li><a href="/swat/help/make_smbcodepage.1.html" target="docs">make_smbcodepage</a> - kod sayfasý oluþturur
+ <li><a href="/swat/help/make_unicodemap.1.html" target="docs">make_unicodemap</a> - unicode eþleþme dosyasý oluþturur
+ <li><a href="/swat/help/smbrun.1.html" target="docs">smbrun</a> - içsel smbd aracý
+ </ul>
+ <li><b>Ýstemci Araçlarý</b>
+ <ul>
+ <li><a href="/swat/help/rpcclient.1.html" target="docs">rpcclient</a> - komut satýrý MS-RPC istemcisi
+ <li><a href="/swat/help/smbtar.1.html" target="docs">smbtar</a> - SMB yedekleme aracý
+ <li><a href="/swat/help/smbclient.1.html" target="docs">smbclient</a> - komut satýrý SMB istemcisi
+ <li><a href="/swat/help/smbmnt.8.html" target="docs">smbmnt</a> - Linux makinalarýna SMB dosya sistemlerini baðlamak için yardýmcý araç
+ <li><a href="/swat/help/smbmount.8.html" target="docs">smbmount</a> - Linux altýnda SMB dosya sistemlerini baðlamak için kullanýcý aracý
+ <li><a href="/swat/help/smbspool.8.html" target="docs">smbspool</a> - komut satýrý SMB yazýcý istemcisi
+ <li><a href="/swat/help/smbumount.8.html" target="docs">smbumount</a> - Linux altýnda SMB dosya sistemlerini çözmek için kullanýcý aracý
+ </ul>
+ <li><b>Teþhis Araçlarý</b>
+ <ul>
+ <li><a href="/swat/help/smbstatus.1.html" target="docs">smbstatus</a> - Samba gözlemcisi
+ <li><a href="/swat/help/testparm.1.html" target="docs">testparm</a> - ayar dosyasýný kontrol eder
+ <li><a href="/swat/help/testprns.1.html" target="docs">testprns</a> - yazýcý ayarlarýný kontrol eder
+ <li><a href="/swat/help/nmblookup.1.html" target="docs">nmblookup</a> - NetBIOS isim sorgulama aracý
+ </ul>
+ <li><b>Kitaplar</b>
+ <ul>
+ <li><a href="/swat/using_samba/index.html" target="docs">Samba'yý Kullanmak</a> - Yazan: Robert Eckstein, David Collier-Brown ve Peter Kelly
+ </ul>
+ <li><b>Samba HOWTO (Nasýl Yapýlýr?) Koleksiyonu</b></li>
+ <ul>
+ <li><a href="/swat/help/Samba-HOWTO-Collection.html">Bütün koleksiyon (tek dosya)</a>
+ <li><a href="/swat/help/DOMAIN_MEMBER.html">Samba 2.x'de security = domain </a>
+ <li><a href="/swat/help/winbind.html">Winbind Kullanarak Windows NT ve UNIX Arasýnda Birleþik Sistem Giriþi</a>
+ <li><a href="/swat/help/msdfs_setup.html">Samba'yý bir MS-DFS Sunucusu Olarak Ayarlamak</a>
+ <li><a href="/swat/help/NT_Security.html">UNIX Ýzin Bitleri ve Samba 2.x</a>
+ <li><a href="/swat/help/OS2-Client-HOWTO.html">OS/2 Ýstemcileri ve Samba</a>
+ <li><a href="/swat/help/printer_driver2.html">Samba 2.2.x Altýnda Yazýcý Kullanýmý</a>
+ <li><a href="/swat/help/UNIX_INSTALL.html">Samba Nasýl Kurulur ve Kontrol Edilir?</a>
+ <li><a href="/swat/help/Integrating-with-Windows.html">Ýsim Çözünme ve Yetkilendirme Ýþlemlerini Birleþtirmek</a>
+ <li><a href="/swat/help/CVS-Access.html">Samba yazýlýmlarýna CVS Eriþimi</a>
+ </ul>
+</ul>
+
+ <h3>Ýletiþim</h3>
+
+ Eðer SWAT'ýn bu sürümü ile ilgili konularý tartýþmak istiyorsanýz, lütfen
+<A HREF="http://lists.samba.org/">samba</A> eposta listesine üye olun.
+ \ No newline at end of file
diff --git a/swat/lang/tr/images/globals.gif b/swat/lang/tr/images/globals.gif
new file mode 100644
index 00000000000..c0722d2df52
--- /dev/null
+++ b/swat/lang/tr/images/globals.gif
Binary files differ
diff --git a/swat/lang/tr/images/home.gif b/swat/lang/tr/images/home.gif
new file mode 100644
index 00000000000..119b6da6edf
--- /dev/null
+++ b/swat/lang/tr/images/home.gif
Binary files differ
diff --git a/swat/lang/tr/images/passwd.gif b/swat/lang/tr/images/passwd.gif
new file mode 100644
index 00000000000..25652f211b1
--- /dev/null
+++ b/swat/lang/tr/images/passwd.gif
Binary files differ
diff --git a/swat/lang/tr/images/printers.gif b/swat/lang/tr/images/printers.gif
new file mode 100644
index 00000000000..a3caf2543b2
--- /dev/null
+++ b/swat/lang/tr/images/printers.gif
Binary files differ
diff --git a/swat/lang/tr/images/samba.gif b/swat/lang/tr/images/samba.gif
new file mode 100644
index 00000000000..3ec3d2195ff
--- /dev/null
+++ b/swat/lang/tr/images/samba.gif
Binary files differ
diff --git a/swat/lang/tr/images/shares.gif b/swat/lang/tr/images/shares.gif
new file mode 100644
index 00000000000..bbac9d5411e
--- /dev/null
+++ b/swat/lang/tr/images/shares.gif
Binary files differ
diff --git a/swat/lang/tr/images/status.gif b/swat/lang/tr/images/status.gif
new file mode 100644
index 00000000000..c606d6fcb07
--- /dev/null
+++ b/swat/lang/tr/images/status.gif
Binary files differ
diff --git a/swat/lang/tr/images/viewconfig.gif b/swat/lang/tr/images/viewconfig.gif
new file mode 100644
index 00000000000..3261ab4d8ba
--- /dev/null
+++ b/swat/lang/tr/images/viewconfig.gif
Binary files differ
diff --git a/swat/lang/tr/include/header.html b/swat/lang/tr/include/header.html
new file mode 100644
index 00000000000..7c11fd0ef9f
--- /dev/null
+++ b/swat/lang/tr/include/header.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>Samba Web Yönetim Aracý</TITLE>
+</HEAD>
+<BODY bgcolor="white">
+<CENTER>
+<IMG SRC="/swat/images/samba.gif" ALT="[ Samba ]" border=0><BR>
+<TABLE WIDTH="98%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
+<TR><TD BGCOLOR="#ddddd0">
diff --git a/testsuite/README b/testsuite/README
new file mode 100644
index 00000000000..0d5157325a9
--- /dev/null
+++ b/testsuite/README
@@ -0,0 +1,19 @@
+README for testsuite directory
+------------------------------
+
+The Samba testsuite is divided up into the following subdirectories.
+
+ - config Configuration for DejaGnu program
+ - lib Various library files used by tool directories
+
+ - nsswitch Tests for nsswitch extensions
+ - server Miscellaneous server tests
+ - rpc_client Tests for the RPC client library code
+ - rpcclient Tests for the rpcclient program
+
+ - build_farm Tests designed to run automatically on the build farm
+
+All the scripts except those in build_farm require an unreleased
+version of DejaGNU, and although they contain some useful tests they
+are not so useful at the moment. All scripts are migrating to a
+single test framework, Satyr. <cvs://cvs.samba.org/data/cvs/satyr>
diff --git a/testsuite/build_farm/basicsmb-domainsec-nt4.test b/testsuite/build_farm/basicsmb-domainsec-nt4.test
new file mode 100644
index 00000000000..933f8f9804c
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-domainsec-nt4.test
@@ -0,0 +1,31 @@
+if [ $whoami != "root" ]; then
+ exit 0;
+fi
+
+. basicsmb.fns
+
+test_joindomain_nt4() {
+
+ smbpasswd -a -m buildfarm$
+
+ echo $prefix/bin/smbpasswd -L -j TESTWG
+ $prefix/bin/smbpasswd -L -j TESTWG
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly joined the domain ($workgroup)"
+ else
+ echo "smbpasswd failed to join the domain ($workgroup)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+password=samba
+security=DOMAIN
+(test_smb_conf_setup && test_smbpasswd $password ) || exit 1
+
+test_joindomain_nt4 $password || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-domainsec.test b/testsuite/build_farm/basicsmb-domainsec.test
new file mode 100644
index 00000000000..ff184c4c7f3
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-domainsec.test
@@ -0,0 +1,30 @@
+if [ $whoami != "root" ]; then
+ exit 0;
+fi
+
+. basicsmb.fns
+
+test_joindomain() {
+ test_joindomain_password="$1"
+
+ echo "$prefix/bin/smbpasswd -L -j TESTWG -U $whoami%$test_join_domain_password"
+ $prefix/bin/smbpasswd -L -j TESTWG -U $whoami%$test_join_domain_password
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly joined the domain ($workgroup)"
+ else
+ echo "smbpasswd failed to join the domain ($workgroup)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+password=samba
+security=DOMAIN
+(test_smb_conf_setup && test_smbpasswd $password ) || exit 1
+
+test_joindomain $password || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-hostsdeny.test b/testsuite/build_farm/basicsmb-hostsdeny.test
new file mode 100644
index 00000000000..c7f6bec62f7
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-hostsdeny.test
@@ -0,0 +1,18 @@
+. basicsmb.fns
+
+password="samba"
+security="hostsdeny"
+(test_smb_conf_setup && test_smbpasswd $password) || exit 1
+
+(test_listfilesauth_should_deny $security) || exit 1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/build_farm/basicsmb-hostsequiv.test b/testsuite/build_farm/basicsmb-hostsequiv.test
new file mode 100644
index 00000000000..d424743d116
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-hostsequiv.test
@@ -0,0 +1,26 @@
+if [ $whoami = "root" ]; then
+ exit 0;
+fi
+
+. basicsmb.fns
+
+test_listfilesrootnpw() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient //$remote_name/samba -n buildclient -Uroot% -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -Uroot% -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd listed files AS ROOT with NO PASSWORD (hosts equiv test)!"
+ return 1
+ else
+ echo "listing files with smbd failed with status $status (correct)"
+ fi
+ return 0
+}
+
+password="not-a-valid-password"
+security="hostsequiv"
+(test_smb_conf_setup ) || exit 1
+
+(test_listfilesauth $security) || exit 1
+(test_listfilesrootnpw $security) || exit 1
diff --git a/testsuite/build_farm/basicsmb-invalidusers.test b/testsuite/build_farm/basicsmb-invalidusers.test
new file mode 100644
index 00000000000..54c9c758c69
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-invalidusers.test
@@ -0,0 +1,8 @@
+. basicsmb.fns
+
+password="samba"
+security="invalidusers"
+(test_smb_conf_setup && test_smbpasswd $password) || exit 1
+
+(test_listfilesauth_should_deny $security) || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-local-pass-change.test b/testsuite/build_farm/basicsmb-local-pass-change.test
new file mode 100644
index 00000000000..432376c6662
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-local-pass-change.test
@@ -0,0 +1,10 @@
+. basicsmb.fns
+
+passwordold=samba
+password=samba2
+security=USER
+(test_smb_conf_setup && test_smbpasswd $passwordold && test_smbpasswd_local $passwordold $password) || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-remote-pass-change.test b/testsuite/build_farm/basicsmb-remote-pass-change.test
new file mode 100644
index 00000000000..adfe0dc3ebc
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-remote-pass-change.test
@@ -0,0 +1,10 @@
+. basicsmb.fns
+
+passwordold=samba
+password=samba2
+security=USER
+(test_smb_conf_setup && test_smbpasswd $passwordold && test_smbpasswd_remote $passwordold $password) || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-serversec.test b/testsuite/build_farm/basicsmb-serversec.test
new file mode 100644
index 00000000000..b45899ab774
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-serversec.test
@@ -0,0 +1,9 @@
+. basicsmb.fns
+
+password=samba
+security=SERVER
+(test_smb_conf_setup && test_smbpasswd $password ) || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-shareguest.test b/testsuite/build_farm/basicsmb-shareguest.test
new file mode 100644
index 00000000000..4ba445a17e3
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-shareguest.test
@@ -0,0 +1,20 @@
+. basicsmb.fns
+
+test_listfilesguestshare() {
+ remote_name=$1
+ echo $prefix/bin/smbclient //$remote_name/guest_share -n buildclient -U$whoami% -c 'ls'
+ $prefix/bin/smbclient //$remote_name/guest_share -n buildclient -U$whoami% -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd listed files correctly (guest share)"
+ else
+ echo "listing files on a guest share failed with status $status"
+ return 1
+ fi
+ return 0
+}
+
+security=SHARE
+( test_smb_conf_setup ) || exit 1
+
+( test_listfilesguestshare $security ) || exit 1 \ No newline at end of file
diff --git a/testsuite/build_farm/basicsmb-sharelist.test b/testsuite/build_farm/basicsmb-sharelist.test
new file mode 100644
index 00000000000..87c3e475525
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-sharelist.test
@@ -0,0 +1,19 @@
+. basicsmb.fns
+test_sharelist() {
+ echo $prefix/bin/smbclient -U$whoami% -L localhost
+ $prefix/bin/smbclient -U$whoami% -L localhost
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd listed shares OK"
+ else
+ echo "listing shares with smbd failed with status $status"
+ return 1
+ fi
+ return 0
+}
+
+(test_smb_conf_setup) || exit 1
+
+test_sharelist || exit 1
+
+
diff --git a/testsuite/build_farm/basicsmb-sharesec.test b/testsuite/build_farm/basicsmb-sharesec.test
new file mode 100644
index 00000000000..edef6a91230
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-sharesec.test
@@ -0,0 +1,9 @@
+. basicsmb.fns
+
+password="samba"
+security="SHARE"
+(test_smb_conf_setup && ( test_smbpasswd $password ) ) || exit 1
+
+(test_listfilesauth $security) || exit 1
+(test_listfilesnpw $security) || exit 1
+
diff --git a/testsuite/build_farm/basicsmb-usersec.test b/testsuite/build_farm/basicsmb-usersec.test
new file mode 100644
index 00000000000..06f2a1c4040
--- /dev/null
+++ b/testsuite/build_farm/basicsmb-usersec.test
@@ -0,0 +1,9 @@
+. basicsmb.fns
+
+password=samba
+security=USER
+(test_smb_conf_setup && test_smbpasswd $password ) || exit 1
+
+test_listfilesauth $security || exit 1
+test_listfilesnpw $security || exit 1
+
diff --git a/testsuite/build_farm/basicsmb.fns b/testsuite/build_farm/basicsmb.fns
new file mode 100644
index 00000000000..ab866601a34
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.fns
@@ -0,0 +1,186 @@
+#! /bin/sh
+
+# Common functions for Samba build scripts.
+
+# Copyright (C) 2001 by Martin Pool <mbp@samba.org> and others
+
+# The following variables are passed in by the calling script. They
+# originate in either the buildfarm scripts or the configured
+# Makefile.
+
+# PREFIX = Installed prefix of samba test installation. Used to
+# locate binaries, configuration files, etc.
+
+# XXX: It's pretty bad to clobber the installed configuration file and
+# other data in $prefix, because somebody might unwittingly run this
+# with prefix=/usr.
+
+# Really what we want is a consistent way to pass the location of the
+# configuration and all other files into *all* Samba programs
+# (smbclient, smd, ...) and be able to set them to a temporary
+# directory when testing. Some of them take a -c parameter, but tpot
+# says it's not done consistently.
+
+template_smb_conf_setup() {
+ cat basicsmb.smb.conf$1.template | \
+ sed "s|PREFIX|$prefix|g" | \
+ sed "s|BUILD_FARM|$test_root|g" | \
+ sed "s|WHOAMI|$whoami|g" | \
+ sed "s|LOGLEVEL|$loglevel|g" \
+ > $prefix/lib/smb.conf$1
+ echo "template_smb_conf_setup: Created $prefix/lib/smb.conf$1"
+}
+
+test_smb_conf_setup() {
+ echo "test_smb_conf_setup: Configuring: "
+ echo " PREFIX=$prefix"
+ echo " BUILD_FARM=$test_root"
+ echo " WHOAMI=$whoami"
+ echo " LOGLEVEL=$loglevel"
+ echo " TREE=$tree"
+
+ case "$prefix" in
+ /usr*|/|//)
+ echo "** I don't want to clobber your installation in "
+ echo "** $prefix"
+ echo "** by running tests there. Please reconfigure this source tree to"
+ echo "** use a different prefix."
+ exit 1
+ esac
+
+ template_smb_conf_setup
+ template_smb_conf_setup .hostsequiv
+ template_smb_conf_setup .invalidusers
+
+ echo "127.0.0.1 localhost">$prefix/lib/lmhosts
+ echo "127.0.0.2 BUILDFARM">>$prefix/lib/lmhosts
+ echo "127.0.0.3 SHARE">>$prefix/lib/lmhosts
+ echo "127.0.0.4 USER">>$prefix/lib/lmhosts
+ echo "127.0.0.5 SERVER">>$prefix/lib/lmhosts
+ echo "127.0.0.6 DOMAIN">>$prefix/lib/lmhosts
+ echo "127.0.0.7 HOSTSEQUIV">>$prefix/lib/lmhosts
+
+ echo "127.0.0.1" > $prefix/lib/hosts.equiv
+
+ cp basicsmb.smb.conf.share $prefix/lib/smb.conf.share
+ cp basicsmb.smb.conf.user $prefix/lib/smb.conf.user
+ cp basicsmb.smb.conf.server $prefix/lib/smb.conf.server
+ cp basicsmb.smb.conf.domain $prefix/lib/smb.conf.domain
+
+ touch $prefix/lib/smb.conf.
+ touch $prefix/lib/smb.conf.localhost
+}
+
+test_smbpasswd() {
+ test_smbpasswd_password="$1"
+ rm -f $prefix/private/smbpasswd
+ echo "( echo $test_smbpasswd_password ; echo $test_smbpasswd_password; ) | $prefix/bin/smbpasswd -L -s -a $whoami"
+ ( echo $password ; echo $password; ) | $prefix/bin/smbpasswd -L -s -a $whoami
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly set initial password ($test_smbpasswd_password)"
+ else
+ echo "smbpasswd failed to set initial password ($test_smbpasswd_password)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+test_smbpasswd_remote() {
+ test_smbpasswd_password="$1"
+ test_smbpasswd_newpassword="$2"
+ rm -f $prefix/private/smbpasswd
+ echo "( echo $test_smbpasswd_password; echo $test_smbpasswd_newpassword ; echo $test_smbpasswd_newpassword; ) | $prefix/bin/smbpasswd -r localhost -s -U $whoami"
+ ( echo $test_smbpasswd_password; echo $test_smbpasswd_newpassword ; echo $test_smbpasswd_newpassword; ) | $prefix/bin/smbpasswd -r localhost -s -U $whoami
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly remotely changed password ($test_smbpasswd_password -> $test_smbpasswd_newpassword)"
+ else
+ echo "smbpasswd failed to remotely changed password ($test_smbpasswd_password -> $test_smbpasswd_newpassword)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+test_smbpasswd_local() {
+ test_smbpasswd_newpassword="$2"
+ rm -f $prefix/private/smbpasswd
+ echo "( echo $test_smbpasswd_newpassword ; echo $test_smbpasswd_newpassword; ) | $prefix/bin/smbpasswd -L $whoami"
+ ( echo $test_smbpasswd_newpassword ; echo $test_smbpasswd_newpassword; ) | $prefix/bin/smbpasswd -L $whoami
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly locally changed password ($test_smbpasswd_password -> $test_smbpasswd_newpassword)"
+ else
+ echo "smbpasswd failed to locallly changed password ($test_smbpasswd_password -> $test_smbpasswd_newpassword)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+test_listfilesauth() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient//$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "listed files OK"
+ else
+ echo "listing files with smbd failed with status $status"
+ return 1
+ fi
+ return 0
+}
+
+test_listfilesnpw() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami% -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami% -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd listed files with NO PASSWORD on an authenticated share!"
+ return 1
+ else
+ echo "listing files with smbd failed with status $status (correct)"
+ fi
+ return 0
+}
+
+test_listfilesauth_should_deny() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd LISTED FILES despite smb.conf entires to the contary!"
+ return 1
+ else
+ echo "listing files with smbd failed with status $status (correct)"
+ fi
+ return 0
+}
+
+echo "LIBSMB_PROG=$LIBSMB_PROG" >&2
+
+
+
+# Give sensible defaults to some variables.
+
+# "What's my age again?"
+
+if [ ! $USER = "" ]; then
+ whoami=$USER
+else
+ if [ ! $LOGNAME = "" ]; then
+ whoami=$LOGNAME
+ else
+ whoami=build
+ fi
+fi
+
+
+
+if test -z "$loglevel"
+then
+ loglevel=1
+fi
+
diff --git a/testsuite/build_farm/basicsmb.smb.conf.domain b/testsuite/build_farm/basicsmb.smb.conf.domain
new file mode 100644
index 00000000000..8b9728838e1
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.domain
@@ -0,0 +1,2 @@
+security=domain
+password server=user
diff --git a/testsuite/build_farm/basicsmb.smb.conf.hostsdeny b/testsuite/build_farm/basicsmb.smb.conf.hostsdeny
new file mode 100644
index 00000000000..3fce0bdbf4e
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.hostsdeny
@@ -0,0 +1 @@
+ hosts deny = 127. \ No newline at end of file
diff --git a/testsuite/build_farm/basicsmb.smb.conf.hostsequiv.template b/testsuite/build_farm/basicsmb.smb.conf.hostsequiv.template
new file mode 100644
index 00000000000..750af74f59c
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.hostsequiv.template
@@ -0,0 +1,3 @@
+ hostname lookups = no
+ hosts equiv=PREFIX/lib/hosts.equiv
+ auth methods = hostsequiv
diff --git a/testsuite/build_farm/basicsmb.smb.conf.invalidusers.template b/testsuite/build_farm/basicsmb.smb.conf.invalidusers.template
new file mode 100644
index 00000000000..a96a316db9f
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.invalidusers.template
@@ -0,0 +1 @@
+ invalid users = WHOAMI
diff --git a/testsuite/build_farm/basicsmb.smb.conf.server b/testsuite/build_farm/basicsmb.smb.conf.server
new file mode 100644
index 00000000000..016f84cd353
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.server
@@ -0,0 +1,3 @@
+security=server
+password server=user
+smb passwd file=NON_EXISTANT_FILE
diff --git a/testsuite/build_farm/basicsmb.smb.conf.share b/testsuite/build_farm/basicsmb.smb.conf.share
new file mode 100644
index 00000000000..8e69cc199a5
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.share
@@ -0,0 +1 @@
+ security = share
diff --git a/testsuite/build_farm/basicsmb.smb.conf.template b/testsuite/build_farm/basicsmb.smb.conf.template
new file mode 100644
index 00000000000..ff837bbb098
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.template
@@ -0,0 +1,43 @@
+[global]
+ netbios name = BUILDFARM
+ workgroup = TESTWG
+ log level = LOGLEVEL
+ debug timestamp = no
+ encrypt passwords = yes
+ server string = Samba %v Build Farm Tests
+ name resolve order = lmhosts
+ guest account = WHOAMI
+ domain logons = yes
+
+ strict locking = yes
+
+ include = PREFIX/lib/smb.conf.%L
+
+ add machine script = useradd %u -d /dev/null -s /bin/false
+
+ panic action = echo bt | gdb PREFIX/sbin/smbd %d
+
+[test]
+ path = PREFIX/testdir
+ read only = no
+
+[samba]
+ path = BUILD_FARM/samba
+ read only = yes
+ comment = Samba HEAD Sources
+
+[samba_2_2]
+ path = BUILD_FARM/samba_2_2
+ read only = yes
+ comment = Samba 2.2. Sources
+
+[rsync]
+ path = BUILD_FARM/rsync
+ read only = yes
+ comment = Rsync Sources
+
+[guest_share]
+ path = PREFIX
+ guest ok = yes
+ read only = yes
+ comment = Unauthenticated share for use in share level test
diff --git a/testsuite/build_farm/basicsmb.smb.conf.user b/testsuite/build_farm/basicsmb.smb.conf.user
new file mode 100644
index 00000000000..9d294b9c396
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.user
@@ -0,0 +1 @@
+ security = user
diff --git a/testsuite/build_farm/runlist b/testsuite/build_farm/runlist
new file mode 100644
index 00000000000..784b5e0387d
--- /dev/null
+++ b/testsuite/build_farm/runlist
@@ -0,0 +1,3 @@
+TEST_ALL="basicsmb-sharelist basicsmb-sharesec basicsmb-usersec basicsmb-serversec basicsmb-domainsec basicsmb-domainsec-nt4 basicsmb-shareguest basicsmb-hostsequiv basicsmb-invalidusers basicsmb-hostsdeny torture-FDPASS torture-LOCK1 torture-LOCK2 torture-LOCK3 torture-LOCK4 torture-LOCK5 torture-UNLINK torture-BROWSE torture-ATTR torture-TRANS2 torture-TORTURE torture-OPLOCK1 torture-OPLOCK3 torture-DIR torture-DENY1 torture-DENY2 torture-TCON torture-RW1 torture-RW2 torture-OPEN torture-DELETE"
+
+#basicsmb-serversec
diff --git a/testsuite/build_farm/torture-ATTR.test b/testsuite/build_farm/torture-ATTR.test
new file mode 100644
index 00000000000..db6d5e87824
--- /dev/null
+++ b/testsuite/build_farm/torture-ATTR.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "ATTR"
diff --git a/testsuite/build_farm/torture-BROWSE.test b/testsuite/build_farm/torture-BROWSE.test
new file mode 100644
index 00000000000..da758977da5
--- /dev/null
+++ b/testsuite/build_farm/torture-BROWSE.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "BROWSE"
diff --git a/testsuite/build_farm/torture-DELETE.test b/testsuite/build_farm/torture-DELETE.test
new file mode 100644
index 00000000000..395f449d1e1
--- /dev/null
+++ b/testsuite/build_farm/torture-DELETE.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "DELETE"
diff --git a/testsuite/build_farm/torture-DENY1.test b/testsuite/build_farm/torture-DENY1.test
new file mode 100644
index 00000000000..99ce7ea8869
--- /dev/null
+++ b/testsuite/build_farm/torture-DENY1.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "DENY1"
diff --git a/testsuite/build_farm/torture-DENY2.test b/testsuite/build_farm/torture-DENY2.test
new file mode 100644
index 00000000000..17c8f707d87
--- /dev/null
+++ b/testsuite/build_farm/torture-DENY2.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "DENY2"
diff --git a/testsuite/build_farm/torture-DIR.test b/testsuite/build_farm/torture-DIR.test
new file mode 100644
index 00000000000..085ce59c3b0
--- /dev/null
+++ b/testsuite/build_farm/torture-DIR.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "DIR"
diff --git a/testsuite/build_farm/torture-FDPASS.test b/testsuite/build_farm/torture-FDPASS.test
new file mode 100644
index 00000000000..e8af277d430
--- /dev/null
+++ b/testsuite/build_farm/torture-FDPASS.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "FDPASS"
diff --git a/testsuite/build_farm/torture-LOCK1.test b/testsuite/build_farm/torture-LOCK1.test
new file mode 100644
index 00000000000..fd01c492f16
--- /dev/null
+++ b/testsuite/build_farm/torture-LOCK1.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "LOCK1"
diff --git a/testsuite/build_farm/torture-LOCK2.test b/testsuite/build_farm/torture-LOCK2.test
new file mode 100644
index 00000000000..66b671d8010
--- /dev/null
+++ b/testsuite/build_farm/torture-LOCK2.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "LOCK2"
diff --git a/testsuite/build_farm/torture-LOCK3.test b/testsuite/build_farm/torture-LOCK3.test
new file mode 100644
index 00000000000..dcf14019d8e
--- /dev/null
+++ b/testsuite/build_farm/torture-LOCK3.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "LOCK3"
diff --git a/testsuite/build_farm/torture-LOCK4.test b/testsuite/build_farm/torture-LOCK4.test
new file mode 100644
index 00000000000..8fdc9b66615
--- /dev/null
+++ b/testsuite/build_farm/torture-LOCK4.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "LOCK4"
diff --git a/testsuite/build_farm/torture-LOCK5.test b/testsuite/build_farm/torture-LOCK5.test
new file mode 100644
index 00000000000..a04f83c8491
--- /dev/null
+++ b/testsuite/build_farm/torture-LOCK5.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "LOCK5"
diff --git a/testsuite/build_farm/torture-OPEN.test b/testsuite/build_farm/torture-OPEN.test
new file mode 100644
index 00000000000..ee3e55f0890
--- /dev/null
+++ b/testsuite/build_farm/torture-OPEN.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "OPEN"
diff --git a/testsuite/build_farm/torture-OPLOCK1.test b/testsuite/build_farm/torture-OPLOCK1.test
new file mode 100644
index 00000000000..bb606ad3bc9
--- /dev/null
+++ b/testsuite/build_farm/torture-OPLOCK1.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "OPLOCK1"
diff --git a/testsuite/build_farm/torture-OPLOCK3.test b/testsuite/build_farm/torture-OPLOCK3.test
new file mode 100644
index 00000000000..f8dfb3f8e9b
--- /dev/null
+++ b/testsuite/build_farm/torture-OPLOCK3.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "OPLOCK3"
diff --git a/testsuite/build_farm/torture-RANDOMIPC.test b/testsuite/build_farm/torture-RANDOMIPC.test
new file mode 100644
index 00000000000..e510b6b6672
--- /dev/null
+++ b/testsuite/build_farm/torture-RANDOMIPC.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "RANDOMIPC"
diff --git a/testsuite/build_farm/torture-RW1.test b/testsuite/build_farm/torture-RW1.test
new file mode 100644
index 00000000000..6be4a897d91
--- /dev/null
+++ b/testsuite/build_farm/torture-RW1.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "RW1"
diff --git a/testsuite/build_farm/torture-RW2.test b/testsuite/build_farm/torture-RW2.test
new file mode 100644
index 00000000000..a647d9de2e9
--- /dev/null
+++ b/testsuite/build_farm/torture-RW2.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "RW22"
diff --git a/testsuite/build_farm/torture-TCON.test b/testsuite/build_farm/torture-TCON.test
new file mode 100644
index 00000000000..7d1aba0f29f
--- /dev/null
+++ b/testsuite/build_farm/torture-TCON.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "TCON"
diff --git a/testsuite/build_farm/torture-TORTURE.test b/testsuite/build_farm/torture-TORTURE.test
new file mode 100644
index 00000000000..bc97e94e850
--- /dev/null
+++ b/testsuite/build_farm/torture-TORTURE.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "TORTURE"
diff --git a/testsuite/build_farm/torture-TRANS2.test b/testsuite/build_farm/torture-TRANS2.test
new file mode 100644
index 00000000000..d2a387f1afc
--- /dev/null
+++ b/testsuite/build_farm/torture-TRANS2.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "TRANS2"
diff --git a/testsuite/build_farm/torture-UNLINK.test b/testsuite/build_farm/torture-UNLINK.test
new file mode 100644
index 00000000000..b7086bbc838
--- /dev/null
+++ b/testsuite/build_farm/torture-UNLINK.test
@@ -0,0 +1,2 @@
+. torture_setup.fns
+test_torture "UNLINK"
diff --git a/testsuite/build_farm/torture_setup.fns b/testsuite/build_farm/torture_setup.fns
new file mode 100644
index 00000000000..bf5146148ea
--- /dev/null
+++ b/testsuite/build_farm/torture_setup.fns
@@ -0,0 +1,19 @@
+. basicsmb.fns
+
+test_torture() {
+ torture_test=$1
+ password=samba
+ security=USER
+ (test_smb_conf_setup && test_smbpasswd $password ) || return 1
+
+ echo $srcdir/bin/smbtorture //localhost/test -U$whoami%$password $torture_test
+ $srcdir/bin/smbtorture //localhost/test -U$whoami%$password $torture_test
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbtorture test $torture_test worked"
+ else
+ echo "smbtorture test $torture_test FAILED!"
+ return 1
+ fi
+ return 0
+}
diff --git a/testsuite/config/unix.exp b/testsuite/config/unix.exp
new file mode 100644
index 00000000000..c8b3b28779d
--- /dev/null
+++ b/testsuite/config/unix.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 1988, 1990, 1991, 1992, 1994, 1997 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# This file was written by Rob Savoye. (rob@cygnus.com)
+
+# Set a default timeout to be used for the tests under UNIX, rather than
+# accepting whatever default dejagnu gives us (apparently 10 seconds).
+# When running the tests over NFS, under somewhat heavy load, 10 seconds
+# does not seem to be enough. Try starting with 60.
+set timeout 60
+verbose "Timeout is now $timeout seconds" 2
diff --git a/testsuite/lib/compile.exp b/testsuite/lib/compile.exp
new file mode 100644
index 00000000000..070498d9589
--- /dev/null
+++ b/testsuite/lib/compile.exp
@@ -0,0 +1,79 @@
+#
+# Compilation utility functions
+#
+
+#
+# Unix SMB/Netbios implementation.
+# Copyright (C) Tim Potter 2000
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Compile a program consisting of one .c file. For example
+# simple_compile "foo" will compile foo.c to the executable foo.exe
+# Use a second argument to specify link libraries.
+
+proc simple_compile { args } {
+ global srcdir
+ global subdir
+
+ # Compile up program
+
+ set program [lindex $args 0]
+ set libs [lindex $args 1]
+
+ if { $libs == "" } {
+
+ set output [target_compile "$srcdir/$subdir/$program.c" \
+ "$srcdir/$subdir/$program" executable \
+ {additional_flags="-g"}]
+ } else {
+
+ set output [target_compile "$srcdir/$subdir/$program.c" \
+ "$srcdir/$subdir/$program" executable \
+ [list libs=$libs additional_flags="-g"]]
+ }
+
+ # Check for errors
+
+ if {$output != ""} {
+ perror "compile $program"
+ puts $output
+ return -1
+ }
+}
+
+# Compile a program from a Makefile.suffix
+
+proc simple_make { args } {
+ global srcdir
+ global subdir
+
+ # Compile up program with make
+
+ set suffix [lindex $args 0]
+ set program [lindex $args 1]
+
+ set output [util_start "make" \
+ "-C $srcdir/$subdir -f Makefile.$suffix $program"]
+
+ # Check for errors
+
+ if { [regexp "Error" $output] } {
+ perror "make $program"
+ puts $output
+ return -1
+ }
+}
diff --git a/testsuite/lib/default-nt-names.exp b/testsuite/lib/default-nt-names.exp
new file mode 100644
index 00000000000..5d01d2a5bb3
--- /dev/null
+++ b/testsuite/lib/default-nt-names.exp
@@ -0,0 +1,20 @@
+#
+# A list of default domain/local users/groups. Unfortunately this is tied
+# to the English language version of Windows NT.
+#
+
+global domain
+
+# Domain users and groups
+
+set domain_users [list "$domain/Administrator" "$domain/Guest"]
+
+set domain_groups [list "$domain/Domain Admins" "$domain/Domain Guests" \
+ "$domain/Domain Users"]
+
+# Local groups
+
+set local_groups [list "BUILTIN/Replicator" "BUILTIN/Server Operators" \
+ "BUILTIN/Account Operators" "BUILTIN/Backup Operators" \
+ "BUILTIN/Print Operators" "BUILTIN/Guests" "BUILTIN/Users" \
+ "BUILTIN/Administrators"]
diff --git a/testsuite/lib/env-single.exp b/testsuite/lib/env-single.exp
new file mode 100644
index 00000000000..6cd7f94a869
--- /dev/null
+++ b/testsuite/lib/env-single.exp
@@ -0,0 +1,36 @@
+#
+# Environment variables for a single machine test. We look for the
+# following environment variables:
+#
+# $TEST_SERVER The SMB server to contact for the test
+# $TEST_SHARE Share name on $TEST_SERVER to contact
+# $TEST_USER The username to connect to $TEST_SHARE as
+#
+# These are stored in the Tcl variables $server, $share and $user
+# respectively.
+#
+# An error will be produced and the test will exit if any of these
+# variables are not present.
+#
+
+verbose "Loading single machine environment variables"
+
+catch {set server "$env(TEST_SERVER)"} tmp
+
+if {[regexp "^can't read" $tmp]} {
+ error "Environment variable TEST_SERVER not set"
+}
+
+catch {set share "$env(TEST_SHARE)"} tmp
+
+if {[regexp "^can't read" $tmp]} {
+ error "Environment variable TEST_SHARE not set"
+}
+
+catch {set user "$env(TEST_USER)"} tmp
+
+if {[regexp "^can't read" $tmp]} {
+ error "Environment variable TEST_USER not set"
+}
+
+verbose "Single machine is //$server/$share -U $user"
diff --git a/testsuite/lib/nsswitch-config.exp b/testsuite/lib/nsswitch-config.exp
new file mode 100644
index 00000000000..38342685dfa
--- /dev/null
+++ b/testsuite/lib/nsswitch-config.exp
@@ -0,0 +1,21 @@
+#
+# Load environment variables
+#
+
+global tool
+
+if { [file exists "deja-$tool.tcl"] } {
+ source "deja-$tool.tcl"
+}
+
+# Required options
+
+if { ![info exists WORKGROUP] } {
+ error "\$WORKGROUP not set in config file"
+}
+
+if { ![info exists PDC] } {
+ error "\$PDC not set in config file"
+}
+
+set domain $WORKGROUP
diff --git a/testsuite/lib/smbclient.exp b/testsuite/lib/smbclient.exp
new file mode 100644
index 00000000000..dc55d72139c
--- /dev/null
+++ b/testsuite/lib/smbclient.exp
@@ -0,0 +1,54 @@
+#
+# Utilities for driving smbclient
+#
+
+# Variables
+
+set smb_prompt "smb: \\\\>"
+
+# Spawn smbclient and wait for a prompt
+
+proc spawn_smbclient { args } {
+ set result 0
+ global smb_prompt
+ global spawn_id
+
+ # Spawn smbclient
+
+ spawn smbclient [lindex $args 0] [lindex $args 1] [lindex $args 2] \
+ [lindex $args 3] [lindex $args 4] [lindex $args 5] \
+ [lindex $args 6]
+
+ # Wait for prompt
+
+ expect {
+ $smb_prompt { set result 1 }
+ timeout { perror "timed out spawning smbclient" }
+ eof { perror "end of file spawning smbclient" }
+ }
+
+ return $result
+}
+
+# Run a command and wait for a prompt
+
+proc do_smbclient { args } {
+ set action [lindex $args 0]
+ set description [lindex $args 1]
+ global smb_prompt
+
+ # Send command
+
+ verbose $action
+
+ send $action
+
+ expect {
+ $smb_prompt {}
+ timeout { perror "timed out $description"; return -1}
+ eof { perror "end of file $description"; return -1 }
+ }
+
+ verbose $expect_out(buffer)
+ return $expect_out(buffer)
+}
diff --git a/testsuite/libsmbclient/src/Makefile b/testsuite/libsmbclient/src/Makefile
new file mode 100644
index 00000000000..a59f1342801
--- /dev/null
+++ b/testsuite/libsmbclient/src/Makefile
@@ -0,0 +1,817 @@
+CC = gcc
+CFLAGS = -Wall -W -O2 -g
+LFLAGS = -L/root/samba-head-old/source/bin
+
+LIBS= -L/usr/lib -lsmbclient
+INCPATH= -I. -I/usr/include -I./include
+BIN_DIR=bin
+
+SUB_DIRS=init fstat open unlink chown close opendir closedir rename lseek lseekdir stat \
+ getdents creat read readdir mkdir rmdir write chmod open_print_job list_print_jobs \
+ print_file telldir unlink_print_job
+
+
+G_INIT = $(BIN_DIR)/init_1 \
+ $(BIN_DIR)/init_2 \
+ $(BIN_DIR)/init_3 \
+ $(BIN_DIR)/init_4
+
+G_FSTAT = $(BIN_DIR)/fstat_1 \
+ $(BIN_DIR)/fstat_2 \
+ $(BIN_DIR)/fstat_3 \
+ $(BIN_DIR)/fstat_4 \
+ $(BIN_DIR)/fstat_5 \
+ $(BIN_DIR)/fstat_6
+
+G_OPEN = $(BIN_DIR)/open_1 \
+ $(BIN_DIR)/open_2 \
+ $(BIN_DIR)/open_3 \
+ $(BIN_DIR)/open_4 \
+ $(BIN_DIR)/open_5
+
+G_UNLINK = $(BIN_DIR)/unlink_1 \
+ $(BIN_DIR)/unlink_2 \
+ $(BIN_DIR)/unlink_3 \
+ $(BIN_DIR)/unlink_4 \
+ $(BIN_DIR)/unlink_5 \
+ $(BIN_DIR)/unlink_6 \
+ $(BIN_DIR)/unlink_7 \
+ $(BIN_DIR)/unlink_8 \
+ $(BIN_DIR)/unlink_9 \
+ $(BIN_DIR)/unlink_10 \
+ $(BIN_DIR)/unlink_11 \
+ $(BIN_DIR)/unlink_12
+
+
+G_CLOSE = $(BIN_DIR)/close_1 \
+ $(BIN_DIR)/close_2
+
+G_OPENDIR = $(BIN_DIR)/opendir_1 \
+ $(BIN_DIR)/opendir_2 \
+ $(BIN_DIR)/opendir_3 \
+ $(BIN_DIR)/opendir_4
+
+G_CLOSEDIR = $(BIN_DIR)/closedir_1 \
+ $(BIN_DIR)/closedir_2 \
+ $(BIN_DIR)/closedir_3 \
+ $(BIN_DIR)/closedir_4
+
+G_RENAME = $(BIN_DIR)/rename_1 \
+ $(BIN_DIR)/rename_2 \
+ $(BIN_DIR)/rename_3 \
+ $(BIN_DIR)/rename_4 \
+ $(BIN_DIR)/rename_5 \
+ $(BIN_DIR)/rename_6 \
+ $(BIN_DIR)/rename_7 \
+ $(BIN_DIR)/rename_8 \
+ $(BIN_DIR)/rename_9 \
+ $(BIN_DIR)/rename_10 \
+ $(BIN_DIR)/rename_11 \
+ $(BIN_DIR)/rename_12 \
+ $(BIN_DIR)/rename_13 \
+ $(BIN_DIR)/rename_14
+
+G_LSEEK = $(BIN_DIR)/lseek_1 \
+ $(BIN_DIR)/lseek_2 \
+ $(BIN_DIR)/lseek_3 \
+ $(BIN_DIR)/lseek_4 \
+ $(BIN_DIR)/lseek_5 \
+ $(BIN_DIR)/lseek_6 \
+ $(BIN_DIR)/lseek_7 \
+ $(BIN_DIR)/lseek_8
+
+G_LSEEKDIR = $(BIN_DIR)/lseekdir_1 \
+ $(BIN_DIR)/lseekdir_2 \
+ $(BIN_DIR)/lseekdir_3 \
+ $(BIN_DIR)/lseekdir_4 \
+ $(BIN_DIR)/lseekdir_5 \
+ $(BIN_DIR)/lseekdir_6
+
+G_STAT = $(BIN_DIR)/stat_1 \
+ $(BIN_DIR)/stat_2 \
+ $(BIN_DIR)/stat_3 \
+ $(BIN_DIR)/stat_4 \
+ $(BIN_DIR)/stat_5 \
+ $(BIN_DIR)/stat_6
+
+G_GETDENTS = $(BIN_DIR)/getdents_1 \
+ $(BIN_DIR)/getdents_2 \
+ $(BIN_DIR)/getdents_3 \
+ $(BIN_DIR)/getdents_4 \
+ $(BIN_DIR)/getdents_5
+
+G_CREAT = $(BIN_DIR)/creat_1 \
+ $(BIN_DIR)/creat_2 \
+ $(BIN_DIR)/creat_3
+
+G_READ = $(BIN_DIR)/read_1 \
+ $(BIN_DIR)/read_2 \
+ $(BIN_DIR)/read_3 \
+ $(BIN_DIR)/read_4 \
+ $(BIN_DIR)/read_5 \
+ $(BIN_DIR)/read_6 \
+ $(BIN_DIR)/read_7 \
+ $(BIN_DIR)/read_8 \
+ $(BIN_DIR)/read_9 \
+ $(BIN_DIR)/read_10 \
+ $(BIN_DIR)/read_11 \
+ $(BIN_DIR)/read_12 \
+ $(BIN_DIR)/read_13
+
+G_MKDIR = $(BIN_DIR)/mkdir_1 \
+ $(BIN_DIR)/mkdir_2 \
+ $(BIN_DIR)/mkdir_3 \
+ $(BIN_DIR)/mkdir_4
+
+G_RMDIR = $(BIN_DIR)/rmdir_1 \
+ $(BIN_DIR)/rmdir_2 \
+ $(BIN_DIR)/rmdir_3 \
+ $(BIN_DIR)/rmdir_4 \
+ $(BIN_DIR)/rmdir_5 \
+ $(BIN_DIR)/rmdir_6
+
+G_READDIR = $(BIN_DIR)/readdir_1 \
+ $(BIN_DIR)/readdir_2 \
+ $(BIN_DIR)/readdir_3 \
+ $(BIN_DIR)/readdir_4 \
+ $(BIN_DIR)/readdir_5
+
+G_WRITE = $(BIN_DIR)/write_1 \
+ $(BIN_DIR)/write_2 \
+ $(BIN_DIR)/write_3 \
+ $(BIN_DIR)/write_4 \
+ $(BIN_DIR)/write_5 \
+ $(BIN_DIR)/write_6 \
+ $(BIN_DIR)/write_7 \
+ $(BIN_DIR)/write_8 \
+ $(BIN_DIR)/write_9 \
+ $(BIN_DIR)/write_10 \
+ $(BIN_DIR)/write_11 \
+ $(BIN_DIR)/write_12 \
+ $(BIN_DIR)/write_13
+
+G_TELLDIR = $(BIN_DIR)/telldir_1 \
+ $(BIN_DIR)/telldir_2 \
+ $(BIN_DIR)/telldir_3 \
+ $(BIN_DIR)/telldir_4 \
+ $(BIN_DIR)/telldir_5
+
+G_CHMOD = $(BIN_DIR)/chmod_1
+
+G_CHOWN = $(BIN_DIR)/chown_1
+
+G_PRINT_FILE = $(BIN_DIR)/print_file_1 \
+ $(BIN_DIR)/print_file_2 \
+ $(BIN_DIR)/print_file_3 \
+ $(BIN_DIR)/print_file_4
+
+G_OPEN_PRINT_JOB = $(BIN_DIR)/open_print_job_1 \
+ $(BIN_DIR)/open_print_job_2
+
+G_LIST_PRINT_JOBS = $(BIN_DIR)/list_print_jobs_1 \
+ $(BIN_DIR)/list_print_jobs_2 \
+ $(BIN_DIR)/list_print_jobs_3 \
+ $(BIN_DIR)/list_print_jobs_4 \
+ $(BIN_DIR)/list_print_jobs_5 \
+ $(BIN_DIR)/list_print_jobs_6 \
+ $(BIN_DIR)/list_print_jobs_7
+
+G_UNLINK_PRINT_JOB = $(BIN_DIR)/unlink_print_job_1 \
+ $(BIN_DIR)/unlink_print_job_2 \
+ $(BIN_DIR)/unlink_print_job_3 \
+ $(BIN_DIR)/unlink_print_job_4 \
+ $(BIN_DIR)/unlink_print_job_5
+
+GROUPS= $(G_CHMOD) $(G_CHOWN) $(G_CLOSE) $(G_CLOSEDIR) $(G_CREAT) $(G_FSTAT)\
+ $(G_GETDENTS) $(G_INIT) $(G_LIST_PRINT_JOBS) $(G_LSEEK) $(G_LSEEKDIR) \
+ $(G_MKDIR) $(G_OPEN) $(G_OPENDIR) $(G_OPEN_PRINT_JOB) $(G_PRINT_FILE)\
+ $(G_READ) $(G_READDIR) $(G_RENAME) $(G_RMDIR) $(G_STAT) $(G_TELLDIR) $(G_UNLINK) \
+ $(G_UNLINK_PRINT_JOB) $(G_WRITE)
+
+.c.o:
+ @echo Compiling $*.c
+ @$(CC) -c $(CFLAGS) -o $@ $(INCPATH) $<
+
+
+all: $(GROUPS)
+
+init: $(G_INIT)
+fstat: $(G_FSTAT)
+open: $(G_OPEN)
+unlink: $(G_UNLINK)
+chown: $(G_CHOWN)
+close: $(G_CLOSE)
+opendir: $(G_OPENDIR)
+closedir: $(G_CLOSEDIR)
+rename: $(G_RENAME)
+readdir: $(G_READDIR)
+lseek: $(G_LSEEK)
+lseekdir: $(G_LSEEKDIR)
+stat: $(G_STAT)
+getdents: $(G_GETDENTS)
+creat: $(G_CREAT)
+read: $(G_READ)
+mkdir: $(G_MKDIR)
+rmdir: $(G_RMDIR)
+write: $(G_WRITE)
+chmod: $(G_CHMOD)
+telldir: $(G_TELLDIR)
+print_file: $(G_PRINT_FILE)
+open_print_job: $(G_OPEN_PRINT_JOB)
+list_print_jobs: $(G_LIST_PRINT_JOBS)
+unlink_print_job: $(G_UNLINK_PRINT_JOB)
+
+
+$(BIN_DIR)/testsmbc: testsmbc.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ testsmbc.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/init_1: init/init_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ init/init_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/init_2: init/init_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ init/init_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/init_3: init/init_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ init/init_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/init_4: init/init_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ init/init_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_1: fstat/fstat_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_2: fstat/fstat_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_3: fstat/fstat_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_4: fstat/fstat_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_5: fstat/fstat_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/fstat_6: fstat/fstat_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ fstat/fstat_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_1: open/open_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open/open_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_2: open/open_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open/open_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_3: open/open_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open/open_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_4: open/open_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open/open_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_5: open/open_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open/open_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_1: unlink/unlink_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_2: unlink/unlink_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_3: unlink/unlink_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_4: unlink/unlink_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_5: unlink/unlink_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_6: unlink/unlink_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_7: unlink/unlink_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_8: unlink/unlink_8.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_8.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_9: unlink/unlink_9.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_9.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_10: unlink/unlink_10.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_10.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_11: unlink/unlink_11.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_11.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_12: unlink/unlink_12.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink/unlink_12.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/chown_1: chown/chown_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ chown/chown_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/close_1: close/close_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ close/close_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/close_2: close/close_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ close/close_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/opendir_1: opendir/opendir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ opendir/opendir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/opendir_2: opendir/opendir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ opendir/opendir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/opendir_3: opendir/opendir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ opendir/opendir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/opendir_4: opendir/opendir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ opendir/opendir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/closedir_1: closedir/closedir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ closedir/closedir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/closedir_2: closedir/closedir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ closedir/closedir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/closedir_3: closedir/closedir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ closedir/closedir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/closedir_4: closedir/closedir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ closedir/closedir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_1: rename/rename_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_2: rename/rename_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_3: rename/rename_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_4: rename/rename_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_5: rename/rename_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_6: rename/rename_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_7: rename/rename_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_8: rename/rename_8.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_8.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_9: rename/rename_9.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_9.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_10: rename/rename_10.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_10.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_11: rename/rename_11.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_11.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_12: rename/rename_12.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_12.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_13: rename/rename_13.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_13.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rename_14: rename/rename_14.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rename/rename_14.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_1: lseek/lseek_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_2: lseek/lseek_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_3: lseek/lseek_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_4: lseek/lseek_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_5: lseek/lseek_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_6: lseek/lseek_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_7: lseek/lseek_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseek_8: lseek/lseek_8.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseek/lseek_8.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_1: lseekdir/lseekdir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_2: lseekdir/lseekdir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_3: lseekdir/lseekdir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_4: lseekdir/lseekdir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_5: lseekdir/lseekdir_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/lseekdir_6: lseekdir/lseekdir_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ lseekdir/lseekdir_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_1: stat/stat_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_2: stat/stat_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_3: stat/stat_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_4: stat/stat_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_5: stat/stat_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/stat_6: stat/stat_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ stat/stat_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/getdents_1: getdents/getdents_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ getdents/getdents_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/getdents_2: getdents/getdents_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ getdents/getdents_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/getdents_3: getdents/getdents_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ getdents/getdents_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/getdents_4: getdents/getdents_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ getdents/getdents_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/getdents_5: getdents/getdents_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ getdents/getdents_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/creat_1: creat/creat_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ creat/creat_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/creat_2: creat/creat_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ creat/creat_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/creat_3: creat/creat_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ creat/creat_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/mkdir_1: mkdir/mkdir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ mkdir/mkdir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/mkdir_2: mkdir/mkdir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ mkdir/mkdir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/mkdir_3: mkdir/mkdir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ mkdir/mkdir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/mkdir_4: mkdir/mkdir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ mkdir/mkdir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/readdir_1: readdir/readdir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ readdir/readdir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/readdir_2: readdir/readdir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ readdir/readdir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/readdir_3: readdir/readdir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ readdir/readdir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/readdir_4: readdir/readdir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ readdir/readdir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/readdir_5: readdir/readdir_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ readdir/readdir_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_1: rmdir/rmdir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_2: rmdir/rmdir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_3: rmdir/rmdir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_4: rmdir/rmdir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_5: rmdir/rmdir_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/rmdir_6: rmdir/rmdir_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ rmdir/rmdir_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_1: write/write_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_2: write/write_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_3: write/write_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_4: write/write_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_5: write/write_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_6: write/write_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_7: write/write_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_8: write/write_8.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_8.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_9: write/write_9.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_9.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_10: write/write_10.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_10.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_11: write/write_11.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_11.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_12: write/write_12.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_12.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/write_13: write/write_13.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ write/write_13.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_1: read/read_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_2: read/read_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_3: read/read_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_4: read/read_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_5: read/read_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_6: read/read_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_7: read/read_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_8: read/read_8.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_8.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_9: read/read_9.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_9.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_10: read/read_10.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_10.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_11: read/read_11.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_11.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_12: read/read_12.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_12.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/read_13: read/read_13.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ read/read_13.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/chmod_1: chmod/chmod_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ chmod/chmod_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/telldir_1: telldir/telldir_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ telldir/telldir_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/telldir_2: telldir/telldir_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ telldir/telldir_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/telldir_3: telldir/telldir_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ telldir/telldir_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/telldir_4: telldir/telldir_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ telldir/telldir_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/telldir_5: telldir/telldir_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ telldir/telldir_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/print_file_1: print_file/print_file_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ print_file/print_file_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/print_file_2: print_file/print_file_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ print_file/print_file_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/print_file_3: print_file/print_file_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ print_file/print_file_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/print_file_4: print_file/print_file_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ print_file/print_file_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_print_job_1: open_print_job/open_print_job_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open_print_job/open_print_job_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/open_print_job_2: open_print_job/open_print_job_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ open_print_job/open_print_job_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_1: list_print_jobs/list_print_jobs_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_2: list_print_jobs/list_print_jobs_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_3: list_print_jobs/list_print_jobs_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_4: list_print_jobs/list_print_jobs_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_5: list_print_jobs/list_print_jobs_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_5.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_6: list_print_jobs/list_print_jobs_6.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_6.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/list_print_jobs_7: list_print_jobs/list_print_jobs_7.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ list_print_jobs/list_print_jobs_7.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_print_job_1: unlink_print_job/unlink_print_job_1.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink_print_job/unlink_print_job_1.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_print_job_2: unlink_print_job/unlink_print_job_2.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink_print_job/unlink_print_job_2.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_print_job_3: unlink_print_job/unlink_print_job_3.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink_print_job/unlink_print_job_3.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_print_job_4: unlink_print_job/unlink_print_job_4.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink_print_job/unlink_print_job_4.o $(INCPATH) $(LIBS)
+
+$(BIN_DIR)/unlink_print_job_5: unlink_print_job/unlink_print_job_5.o
+ @echo Linking $@
+ @$(CC) $(LFLAGS) -o $@ unlink_print_job/unlink_print_job_5.o $(INCPATH) $(LIBS)
+
+
+clean:
+ @for i in $(SUB_DIRS); do \
+ rm -f $$i/*.o; \
+ done
+
+ @rm -f $(GROUPS)
+ @echo "Done"
+
diff --git a/testsuite/libsmbclient/src/chmod/chmod_1.c b/testsuite/libsmbclient/src/chmod/chmod_1.c
new file mode 100644
index 00000000000..47c86b1f809
--- /dev/null
+++ b/testsuite/libsmbclient/src/chmod/chmod_1.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ fd = smbc_init(auth_fn, 0);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/chown/chown_1.c b/testsuite/libsmbclient/src/chown/chown_1.c
new file mode 100644
index 00000000000..47c86b1f809
--- /dev/null
+++ b/testsuite/libsmbclient/src/chown/chown_1.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ fd = smbc_init(auth_fn, 0);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/close/close_1.c b/testsuite/libsmbclient/src/close/close_1.c
new file mode 100644
index 00000000000..983e627d897
--- /dev/null
+++ b/testsuite/libsmbclient/src/close/close_1.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ err = smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/close/close_2.c b/testsuite/libsmbclient/src/close/close_2.c
new file mode 100644
index 00000000000..b0319e41d9d
--- /dev/null
+++ b/testsuite/libsmbclient/src/close/close_2.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/closedir/closedir_1.c b/testsuite/libsmbclient/src/closedir/closedir_1.c
new file mode 100644
index 00000000000..8d27b8ddd87
--- /dev/null
+++ b/testsuite/libsmbclient/src/closedir/closedir_1.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_closedir(dh);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/closedir/closedir_2.c b/testsuite/libsmbclient/src/closedir/closedir_2.c
new file mode 100644
index 00000000000..c66cbb9c87d
--- /dev/null
+++ b/testsuite/libsmbclient/src/closedir/closedir_2.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ smbc_closedir(dh);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/closedir/closedir_3.c b/testsuite/libsmbclient/src/closedir/closedir_3.c
new file mode 100644
index 00000000000..23f5f679713
--- /dev/null
+++ b/testsuite/libsmbclient/src/closedir/closedir_3.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_closedir(dh);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/closedir/closedir_4.c b/testsuite/libsmbclient/src/closedir/closedir_4.c
new file mode 100644
index 00000000000..bb5dc08331e
--- /dev/null
+++ b/testsuite/libsmbclient/src/closedir/closedir_4.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ smbc_closedir(dh);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/creat/creat_1.c b/testsuite/libsmbclient/src/creat/creat_1.c
new file mode 100644
index 00000000000..9ccab002c13
--- /dev/null
+++ b/testsuite/libsmbclient/src/creat/creat_1.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_creat(url, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/creat/creat_2.c b/testsuite/libsmbclient/src/creat/creat_2.c
new file mode 100644
index 00000000000..599a1845d34
--- /dev/null
+++ b/testsuite/libsmbclient/src/creat/creat_2.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+ fd = 0;
+ fd = smbc_creat(url, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/creat/creat_3.c b/testsuite/libsmbclient/src/creat/creat_3.c
new file mode 100644
index 00000000000..ae27a2a1c90
--- /dev/null
+++ b/testsuite/libsmbclient/src/creat/creat_3.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_creat(url, 0666);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_1.c b/testsuite/libsmbclient/src/fstat/fstat_1.c
new file mode 100644
index 00000000000..fd63400869d
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_1.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ smbc_init(auth_fn, 0);
+
+ fd = 11234;
+ err = smbc_fstat(fd,&st);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_2.c b/testsuite/libsmbclient/src/fstat/fstat_2.c
new file mode 100644
index 00000000000..ea2e7e3145f
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_2.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ smbc_init(auth_fn, 0);
+
+ fd = 11234;
+ smbc_fstat(fd,&st);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_3.c b/testsuite/libsmbclient/src/fstat/fstat_3.c
new file mode 100644
index 00000000000..57bb3b7557d
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_3.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ err = smbc_fstat(fd, &st);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_4.c b/testsuite/libsmbclient/src/fstat/fstat_4.c
new file mode 100644
index 00000000000..57bb3b7557d
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_4.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ err = smbc_fstat(fd, &st);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_5.c b/testsuite/libsmbclient/src/fstat/fstat_5.c
new file mode 100644
index 00000000000..9ebdd602646
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_5.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+
+ smbc_fstat(fd,&st);
+
+ smbc_close(fd);
+ free(message);
+
+ if ( st.st_size != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/fstat/fstat_6.c b/testsuite/libsmbclient/src/fstat/fstat_6.c
new file mode 100644
index 00000000000..a570c0adbc7
--- /dev/null
+++ b/testsuite/libsmbclient/src/fstat/fstat_6.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ unsigned int mode_mask = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+
+ smbc_fstat(fd,&st);
+
+ smbc_close(fd);
+ free(message);
+
+ mode_mask = mode_mask | S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //0666 or 33206
+
+ if ( st.st_mode != mode_mask )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/getdents/getdents_1.c b/testsuite/libsmbclient/src/getdents/getdents_1.c
new file mode 100644
index 00000000000..96fa45cc10b
--- /dev/null
+++ b/testsuite/libsmbclient/src/getdents/getdents_1.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ //int dirsize = 0;
+ //int dircount = 0;
+
+ struct smbc_dirent *dirptr;
+
+ char url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ err = smbc_getdents( dh, dirptr, sizeof(dirbuff));
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/getdents/getdents_2.c b/testsuite/libsmbclient/src/getdents/getdents_2.c
new file mode 100644
index 00000000000..9d9d5b0b184
--- /dev/null
+++ b/testsuite/libsmbclient/src/getdents/getdents_2.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ //int dirsize = 0;
+ //int dircount = 0;
+
+ struct smbc_dirent *dirptr;
+
+ char url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ err = smbc_getdents( dh, dirptr, sizeof(dirbuff));
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/getdents/getdents_3.c b/testsuite/libsmbclient/src/getdents/getdents_3.c
new file mode 100644
index 00000000000..aa22caa4d40
--- /dev/null
+++ b/testsuite/libsmbclient/src/getdents/getdents_3.c
@@ -0,0 +1,155 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ int j = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+ int direntsize = 0;
+ int diramount = 0;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ diramount = smbc_getdents( dh, dirptr, sizeof(dirbuff));
+
+ err = 0;
+ i = 0;
+ bzero(buff,MAX_BUFF_SIZE);
+ bzero(tmp_file_ptr,MAX_BUFF_SIZE-9);
+
+ while ( diramount > 0 )
+ {
+ direntsize = dirptr->dirlen;
+ //printf("Name: %s\n",dirptr->name);
+ if ( j == 0 )
+ {
+ if ( !(( strncmp(dirptr->name,".",1) == 0 )) )
+ {
+ break;
+ err = 1;
+ }
+
+ } else if ( j == 1 ) {
+
+ if ( !(( strncmp(dirptr->name,"..",2) == 0 )) )
+ {
+ break;
+ err = 1;
+ }
+
+ } else if ( j > 1 ) {
+
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+
+ if ( !(( strcmp(dirptr->name,file_url) == 0 )) ) // make sure entries match
+ {
+ err = 1;
+ break;
+ }
+
+ i++;
+
+ }
+
+ (char *)dirptr += direntsize;
+ (char *)diramount -= direntsize;
+ j++;
+
+ }
+
+ if ( ! err )
+ {
+ if ( (j - 2) != entry_num ) // Make sure that all entries created are counted and returned - minus . and ..
+ err = 1;
+ }
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/getdents/getdents_4.c b/testsuite/libsmbclient/src/getdents/getdents_4.c
new file mode 100644
index 00000000000..4afd3539b8e
--- /dev/null
+++ b/testsuite/libsmbclient/src/getdents/getdents_4.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+ int diramount = 0;
+
+ struct smbc_dirent *dirptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ diramount = smbc_getdents( dh, dirptr, 20 /*sizeof(dirbuff)*/ );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/getdents/getdents_5.c b/testsuite/libsmbclient/src/getdents/getdents_5.c
new file mode 100644
index 00000000000..5cf7c1b9282
--- /dev/null
+++ b/testsuite/libsmbclient/src/getdents/getdents_5.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+ int diramount = 0;
+
+ struct smbc_dirent *dirptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ diramount = smbc_getdents( dh, dirptr, 20 /* sizeof(dirbuff)*/);
+
+ if ( diramount < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/init/init_1.c b/testsuite/libsmbclient/src/init/init_1.c
new file mode 100644
index 00000000000..bc928ac3d5c
--- /dev/null
+++ b/testsuite/libsmbclient/src/init/init_1.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+
+int main()
+{
+ int err = -1;
+
+ err = smbc_init(NULL, 0);
+
+ if ( err < 0 )
+ err = 1;
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/init/init_2.c b/testsuite/libsmbclient/src/init/init_2.c
new file mode 100644
index 00000000000..120160297b6
--- /dev/null
+++ b/testsuite/libsmbclient/src/init/init_2.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+
+int main(int argc, char **argv )
+{
+ int err = -1;
+
+ if ( argc > 1 )
+ {
+ err = smbc_init(NULL, atoi(argv[1]));
+
+ if ( err < 0 )
+ err = 1;
+
+ }
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/init/init_3.c b/testsuite/libsmbclient/src/init/init_3.c
new file mode 100644
index 00000000000..f49ed982e18
--- /dev/null
+++ b/testsuite/libsmbclient/src/init/init_3.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ err = smbc_init(auth_fn, atoi(argv[4]));
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/init/init_4.c b/testsuite/libsmbclient/src/init/init_4.c
new file mode 100644
index 00000000000..d8e44b50eed
--- /dev/null
+++ b/testsuite/libsmbclient/src/init/init_4.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+
+int main( )
+{
+ int err = -1;
+
+ err = smbc_init(NULL, 0);
+
+ err = errno;
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_1.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_1.c
new file mode 100644
index 00000000000..f12fcb48c6b
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_1.c
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+int call_back_flag;
+int print_queue_empty;
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn_2(struct print_job_info *pji)
+{
+ print_queue_empty = 0;
+ g_print_id = pji->id;
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ call_back_flag = 1;
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+ call_back_flag = 0;
+ print_queue_empty = 0;
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ while ( ! print_queue_empty ) // Wait until the queue is empty
+ {
+ sleep(1);
+ print_queue_empty = 1;
+ smbc_list_print_jobs(url,print_list_fn_2);
+ }
+
+ smbc_list_print_jobs(url,print_list_fn);
+
+ if ( call_back_flag )
+
+ err = 0;
+
+ else
+ err = 1;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_2.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_2.c
new file mode 100644
index 00000000000..faa60cd31b1
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_2.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+int print_queue_empty;
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn_2(struct print_job_info *pji)
+{
+ print_queue_empty = 0;
+ g_print_id = pji->id;
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ print_queue_empty = 0;
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ while ( ! print_queue_empty ) // Wait until the queue is empty
+ {
+ sleep(1);
+ print_queue_empty = 1;
+ smbc_list_print_jobs(url,print_list_fn_2);
+ }
+
+ err = smbc_list_print_jobs(url,print_list_fn);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_3.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_3.c
new file mode 100644
index 00000000000..c08240d1d51
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_3.c
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ err = smbc_list_print_jobs(argv[6],print_list_fn);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_4.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_4.c
new file mode 100644
index 00000000000..89234b358fd
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_4.c
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ err = smbc_list_print_jobs(argv[6],print_list_fn);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_5.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_5.c
new file mode 100644
index 00000000000..fa0007f7a55
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_5.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+int print_queue_empty;
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn_2(struct print_job_info *pji)
+{
+ print_queue_empty = 0;
+ g_print_id = pji->id;
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ print_queue_empty = 0;
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ while ( ! print_queue_empty ) // Wait until the queue is empty
+ {
+ sleep(1);
+ print_queue_empty = 1;
+ smbc_list_print_jobs(url,print_list_fn_2);
+ }
+
+ smbc_list_print_jobs(url,print_list_fn);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_6.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_6.c
new file mode 100644
index 00000000000..d752d0d0ab5
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_6.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+int print_fn_call_flag;
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+
+ print_fn_call_flag = 1;
+
+}
+
+int main(int argc, char** argv)
+{
+
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char * message;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ print_fn_call_flag = 0;
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(url,print_list_fn);
+
+ if ( print_fn_call_flag == 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_7.c b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_7.c
new file mode 100644
index 00000000000..2675e12d9d3
--- /dev/null
+++ b/testsuite/libsmbclient/src/list_print_jobs/list_print_jobs_7.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+
+ if (( (g_print_size > 0) && (g_print_size > 0) && (strcasecmp(g_username,g_print_user)==0) ))
+ // && (strlen(g_print_name) > 0) ))
+ err = 0;
+
+ else
+ err = 1;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_1.c b/testsuite/libsmbclient/src/lseek/lseek_1.c
new file mode 100644
index 00000000000..c358565d31c
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_1.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ smbc_init(auth_fn, 0);
+
+ fd = -1;
+ err = smbc_lseek(fd, 0, SEEK_SET);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_2.c b/testsuite/libsmbclient/src/lseek/lseek_2.c
new file mode 100644
index 00000000000..8b58ade0836
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_2.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ smbc_init(auth_fn, 0);
+
+ fd = -1;
+ smbc_lseek(fd, 0, SEEK_SET);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_3.c b/testsuite/libsmbclient/src/lseek/lseek_3.c
new file mode 100644
index 00000000000..c8a62e682b2
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_3.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,msg_len,SEEK_SET);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_4.c b/testsuite/libsmbclient/src/lseek/lseek_4.c
new file mode 100644
index 00000000000..c8a62e682b2
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_4.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,msg_len,SEEK_SET);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_5.c b/testsuite/libsmbclient/src/lseek/lseek_5.c
new file mode 100644
index 00000000000..2e40c96410c
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_5.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,msg_len,SEEK_SET);
+ smbc_close(fd);
+
+ if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_6.c b/testsuite/libsmbclient/src/lseek/lseek_6.c
new file mode 100644
index 00000000000..b5236b8537e
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_6.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,msg_len,SEEK_SET);
+ err = errno;
+ smbc_close(fd);
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_7.c b/testsuite/libsmbclient/src/lseek/lseek_7.c
new file mode 100644
index 00000000000..e3ef6cdd544
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_7.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,0,SEEK_END);
+ smbc_close(fd);
+
+ if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseek/lseek_8.c b/testsuite/libsmbclient/src/lseek/lseek_8.c
new file mode 100644
index 00000000000..e70f3ca6b55
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseek/lseek_8.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_lseek(fd,0,SEEK_END);
+ err = errno;
+ smbc_close(fd);
+
+ free(message);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_1.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_1.c
new file mode 100644
index 00000000000..1c1ffa330e8
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_1.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_lseekdir(dh,0);
+ //printf("err: %i\n",err);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_2.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_2.c
new file mode 100644
index 00000000000..cb729d8642e
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_2.c
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ smbc_lseekdir(dh,0);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_3.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_3.c
new file mode 100644
index 00000000000..eae8c63b770
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_3.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_lseekdir(dh,0);
+ //printf("err: %i\n",err);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_4.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_4.c
new file mode 100644
index 00000000000..ac21616340f
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_4.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ smbc_lseekdir(dh,0);
+ err = errno;
+ //printf("err: %i\n",err);
+
+
+ }
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_5.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_5.c
new file mode 100644
index 00000000000..08af806f5fe
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_5.c
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ int dirsize = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ err = 0;
+
+ while ( 1 )
+ {
+ dirptr = smbc_readdir(dh);
+
+ if ( dirptr == NULL )
+ {
+ break;
+ }
+
+ (char*)dirsize += dirptr->dirlen;
+
+ }
+
+ smbc_lseekdir(dh,0);
+ err = smbc_telldir(dh);
+
+ if ( err != 0 )
+ err = 1;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/lseekdir/lseekdir_6.c b/testsuite/libsmbclient/src/lseekdir/lseekdir_6.c
new file mode 100644
index 00000000000..94c86e26ebd
--- /dev/null
+++ b/testsuite/libsmbclient/src/lseekdir/lseekdir_6.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ int offset = 0;
+ int dirsize = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ err = 0;
+
+ while ( 1 )
+ {
+ dirptr = smbc_readdir(dh);
+
+ if ( dirptr == NULL )
+ {
+ break;
+ }
+
+ (char*)dirsize += dirptr->dirlen;
+
+ }
+
+ smbc_lseekdir(dh,0); // move to front
+ smbc_lseekdir(dh,dirsize); // move to end
+ offset = smbc_telldir(dh);
+
+ if ( offset != dirsize )
+ {
+ //printf("offset: %i dirsize: %i\n",offset,dirsize);
+ err = 1;
+ }
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/mkdir/mkdir_1.c b/testsuite/libsmbclient/src/mkdir/mkdir_1.c
new file mode 100644
index 00000000000..20389bcb9b6
--- /dev/null
+++ b/testsuite/libsmbclient/src/mkdir/mkdir_1.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_rmdir( url );
+ err = smbc_mkdir( url, 0666 );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/mkdir/mkdir_2.c b/testsuite/libsmbclient/src/mkdir/mkdir_2.c
new file mode 100644
index 00000000000..ebbc94a18bb
--- /dev/null
+++ b/testsuite/libsmbclient/src/mkdir/mkdir_2.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_rmdir( url );
+ smbc_mkdir( url, 0666 );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/mkdir/mkdir_3.c b/testsuite/libsmbclient/src/mkdir/mkdir_3.c
new file mode 100644
index 00000000000..e5a0ce2561f
--- /dev/null
+++ b/testsuite/libsmbclient/src/mkdir/mkdir_3.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_rmdir( url );
+
+ smbc_mkdir( url, 0666 );
+ smbc_mkdir( url, 0666 );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/mkdir/mkdir_4.c b/testsuite/libsmbclient/src/mkdir/mkdir_4.c
new file mode 100644
index 00000000000..ed1aa70f33f
--- /dev/null
+++ b/testsuite/libsmbclient/src/mkdir/mkdir_4.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_rmdir( url );
+
+ smbc_mkdir( url, 0666 );
+ err = smbc_mkdir( url, 0666 );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open/open_1.c b/testsuite/libsmbclient/src/open/open_1.c
new file mode 100644
index 00000000000..9f72985cec7
--- /dev/null
+++ b/testsuite/libsmbclient/src/open/open_1.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open/open_2.c b/testsuite/libsmbclient/src/open/open_2.c
new file mode 100644
index 00000000000..8903ee912b0
--- /dev/null
+++ b/testsuite/libsmbclient/src/open/open_2.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open/open_3.c b/testsuite/libsmbclient/src/open/open_3.c
new file mode 100644
index 00000000000..25a663d6ab7
--- /dev/null
+++ b/testsuite/libsmbclient/src/open/open_3.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open/open_4.c b/testsuite/libsmbclient/src/open/open_4.c
new file mode 100644
index 00000000000..2bfe30f1af1
--- /dev/null
+++ b/testsuite/libsmbclient/src/open/open_4.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+ fd = 0;
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open/open_5.c b/testsuite/libsmbclient/src/open/open_5.c
new file mode 100644
index 00000000000..93ffb4891ed
--- /dev/null
+++ b/testsuite/libsmbclient/src/open/open_5.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open_print_job/open_print_job_1.c b/testsuite/libsmbclient/src/open_print_job/open_print_job_1.c
new file mode 100644
index 00000000000..585fdee377f
--- /dev/null
+++ b/testsuite/libsmbclient/src/open_print_job/open_print_job_1.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open_print_job(url);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/open_print_job/open_print_job_2.c b/testsuite/libsmbclient/src/open_print_job/open_print_job_2.c
new file mode 100644
index 00000000000..f737f19bfec
--- /dev/null
+++ b/testsuite/libsmbclient/src/open_print_job/open_print_job_2.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open_print_job(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/opendir/opendir_1.c b/testsuite/libsmbclient/src/opendir/opendir_1.c
new file mode 100644
index 00000000000..e839b99cd12
--- /dev/null
+++ b/testsuite/libsmbclient/src/opendir/opendir_1.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+
+ if ( dh < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/opendir/opendir_2.c b/testsuite/libsmbclient/src/opendir/opendir_2.c
new file mode 100644
index 00000000000..60658d2cd56
--- /dev/null
+++ b/testsuite/libsmbclient/src/opendir/opendir_2.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_opendir(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/opendir/opendir_3.c b/testsuite/libsmbclient/src/opendir/opendir_3.c
new file mode 100644
index 00000000000..3b6f28eaf34
--- /dev/null
+++ b/testsuite/libsmbclient/src/opendir/opendir_3.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR|O_CREAT,0666);
+ smbc_close(fd);
+
+ err = smbc_opendir(url);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/opendir/opendir_4.c b/testsuite/libsmbclient/src/opendir/opendir_4.c
new file mode 100644
index 00000000000..23b25e55063
--- /dev/null
+++ b/testsuite/libsmbclient/src/opendir/opendir_4.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR|O_CREAT,0666);
+ smbc_close(fd);
+
+ smbc_opendir(url);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/print_file/print_file_1.c b/testsuite/libsmbclient/src/print_file/print_file_1.c
new file mode 100644
index 00000000000..fcb4466112b
--- /dev/null
+++ b/testsuite/libsmbclient/src/print_file/print_file_1.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ err = smbc_print_file(url,argv[6]);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/print_file/print_file_2.c b/testsuite/libsmbclient/src/print_file/print_file_2.c
new file mode 100644
index 00000000000..a217a0f3b40
--- /dev/null
+++ b/testsuite/libsmbclient/src/print_file/print_file_2.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ smbc_print_file(url,argv[6]);
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/print_file/print_file_3.c b/testsuite/libsmbclient/src/print_file/print_file_3.c
new file mode 100644
index 00000000000..4b2a6af84f2
--- /dev/null
+++ b/testsuite/libsmbclient/src/print_file/print_file_3.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+
+ char url[MAX_BUFF_SIZE];
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ err = smbc_print_file(url,argv[6]);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/print_file/print_file_4.c b/testsuite/libsmbclient/src/print_file/print_file_4.c
new file mode 100644
index 00000000000..1650f7340df
--- /dev/null
+++ b/testsuite/libsmbclient/src/print_file/print_file_4.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+
+ char url[MAX_BUFF_SIZE];
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_print_file(url,argv[6]);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/read/read_1.c b/testsuite/libsmbclient/src/read/read_1.c
new file mode 100644
index 00000000000..accf0bf8721
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_1.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_RDWR, 0666);
+ err = smbc_read(fd,response,msg_len);
+
+ free(message);
+ free(response);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_10.c b/testsuite/libsmbclient/src/read/read_10.c
new file mode 100644
index 00000000000..d5b66dfe635
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_10.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message = NULL;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ msg_len = 10;
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+
+ err = errno;
+
+ smbc_close(fd);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_11.c b/testsuite/libsmbclient/src/read/read_11.c
new file mode 100644
index 00000000000..3f9ae3f97da
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_11.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+ smbc_read(fd,response,msg_len);
+ smbc_close(fd);
+
+ if ( memcmp ( message, response, msg_len) == 0 )
+ err = 0;
+
+ else
+ err = 1;
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_12.c b/testsuite/libsmbclient/src/read/read_12.c
new file mode 100644
index 00000000000..2747f62e1c8
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_12.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ strncpy(g_username,"xxxxxxxx",8);
+ strncpy(g_password,"xxxxxxxx",8);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+
+ err = smbc_read(fd,response,msg_len);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_13.c b/testsuite/libsmbclient/src/read/read_13.c
new file mode 100644
index 00000000000..89bc68f915b
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_13.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ strncpy(g_username,"xxxxxxxx",8);
+ strncpy(g_password,"xxxxxxxx",8);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+
+ if (fd < 0)
+
+ err = errno;
+
+ else {
+
+ err = smbc_read(fd,response,msg_len);
+ err = errno;
+
+ smbc_close(fd);
+
+ }
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_2.c b/testsuite/libsmbclient/src/read/read_2.c
new file mode 100644
index 00000000000..4b3dc9439c1
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_2.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_RDWR, 0666);
+ smbc_read(fd,response,msg_len);
+ err = errno;
+
+ free(message);
+ free(response);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_3.c b/testsuite/libsmbclient/src/read/read_3.c
new file mode 100644
index 00000000000..3f4493487e7
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_3.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_WRONLY, 0666);
+ err = smbc_read(fd,response,msg_len);
+
+ free(message);
+ free(response);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_4.c b/testsuite/libsmbclient/src/read/read_4.c
new file mode 100644
index 00000000000..dbacfa392e8
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_4.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ bzero(response,msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_WRONLY, 0666);
+ smbc_read(fd,response,msg_len);
+ err = errno;
+
+ free(message);
+ free(response);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_5.c b/testsuite/libsmbclient/src/read/read_5.c
new file mode 100644
index 00000000000..96891ef8da6
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_5.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_RDONLY, 0666);
+ err = smbc_read(fd,response,msg_len);
+
+ free(message);
+ free(response);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_6.c b/testsuite/libsmbclient/src/read/read_6.c
new file mode 100644
index 00000000000..7839a964ee4
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_6.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ bzero(response,msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url,O_RDONLY, 0666);
+ smbc_read(fd,response,msg_len);
+ err = errno;
+
+ free(message);
+ free(response);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_7.c b/testsuite/libsmbclient/src/read/read_7.c
new file mode 100644
index 00000000000..081b50a3c82
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_7.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char* message = "Testing";
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ fd = 10345; // Random value for File Descriptor
+ smbc_init(auth_fn, 0);
+ err = smbc_read(fd, message, sizeof(message));
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_8.c b/testsuite/libsmbclient/src/read/read_8.c
new file mode 100644
index 00000000000..5523fbaac3a
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_8.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char* message = "Testing";
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ fd = 10345; // Random value for File Descriptor
+ smbc_init(auth_fn, 0);
+ err = smbc_read(fd, message, sizeof(message));
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/read/read_9.c b/testsuite/libsmbclient/src/read/read_9.c
new file mode 100644
index 00000000000..77468317d92
--- /dev/null
+++ b/testsuite/libsmbclient/src/read/read_9.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message = NULL;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ msg_len = 10;
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_read(fd, message, msg_len);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/readdir/readdir_1.c b/testsuite/libsmbclient/src/readdir/readdir_1.c
new file mode 100644
index 00000000000..5ca7e38bf8d
--- /dev/null
+++ b/testsuite/libsmbclient/src/readdir/readdir_1.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ dirptr = smbc_readdir( dh );
+
+ if ( dirptr == NULL )
+
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/readdir/readdir_2.c b/testsuite/libsmbclient/src/readdir/readdir_2.c
new file mode 100644
index 00000000000..bc4f53dd859
--- /dev/null
+++ b/testsuite/libsmbclient/src/readdir/readdir_2.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ dirptr = smbc_readdir( dh );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/readdir/readdir_3.c b/testsuite/libsmbclient/src/readdir/readdir_3.c
new file mode 100644
index 00000000000..06a4c9eded1
--- /dev/null
+++ b/testsuite/libsmbclient/src/readdir/readdir_3.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ struct smbc_dirent *dirptr;
+
+
+ char url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ dirptr = smbc_readdir( dh );
+
+ if ( dirptr == NULL )
+
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/readdir/readdir_4.c b/testsuite/libsmbclient/src/readdir/readdir_4.c
new file mode 100644
index 00000000000..42b18aaa48b
--- /dev/null
+++ b/testsuite/libsmbclient/src/readdir/readdir_4.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ struct smbc_dirent *dirptr;
+
+
+ char url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+
+ dh = smbc_opendir(url);
+ dirptr = smbc_readdir( dh );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/readdir/readdir_5.c b/testsuite/libsmbclient/src/readdir/readdir_5.c
new file mode 100644
index 00000000000..d1a31ef9f08
--- /dev/null
+++ b/testsuite/libsmbclient/src/readdir/readdir_5.c
@@ -0,0 +1,155 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ int j = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+
+ err = 0;
+ i = 0;
+ bzero(buff,MAX_BUFF_SIZE);
+ bzero(tmp_file_ptr,MAX_BUFF_SIZE-9);
+
+ while ( 1 )
+ {
+ dirptr = smbc_readdir( dh );
+ if ( dirptr == NULL )
+ {
+ break;
+ }
+
+ //printf("Name: %s\n",dirptr->name);
+ if ( j == 0 )
+ {
+ if ( !(( strncmp(dirptr->name,".",1) == 0 )) )
+ {
+ break;
+ err = 1;
+ }
+
+ } else if ( j == 1 ) {
+
+ if ( !(( strncmp(dirptr->name,"..",2) == 0 )) )
+ {
+ break;
+ err = 1;
+ }
+
+ } else if ( j > 1 ) {
+
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+
+ if ( !(( strcmp(dirptr->name,file_url) == 0 )) ) // make sure entries match
+ {
+ err = 1;
+ break;
+ }
+
+ i++;
+
+ }
+
+ j++;
+
+ }
+
+ if ( ! err )
+ {
+ if ( (j - 2) != entry_num ) // Make sure that all entries created are counted and returned - minus . and ..
+ err = 1;
+ }
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_1.c b/testsuite/libsmbclient/src/rename/rename_1.c
new file mode 100644
index 00000000000..c3e1377c293
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_1.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ err = smbc_rename( url, argv[5] );
+
+ if ( err < 0 )
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_10.c b/testsuite/libsmbclient/src/rename/rename_10.c
new file mode 100644
index 00000000000..01fb144c593
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_10.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 9 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[6], strlen(argv[6]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_mkdir( argv[7], 0700 );
+
+ strncpy( g_username, argv[4], strlen(argv[4]) );
+ strncpy( g_password, argv[5], strlen(argv[5]) );
+
+ smbc_rename( url, argv[8] );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_11.c b/testsuite/libsmbclient/src/rename/rename_11.c
new file mode 100644
index 00000000000..0c341088026
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_11.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ err = smbc_rename( NULL, url );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_12.c b/testsuite/libsmbclient/src/rename/rename_12.c
new file mode 100644
index 00000000000..cc34e079e18
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_12.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_rename( NULL, url );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_13.c b/testsuite/libsmbclient/src/rename/rename_13.c
new file mode 100644
index 00000000000..30b33499d60
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_13.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ err = smbc_rename( url, NULL );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_14.c b/testsuite/libsmbclient/src/rename/rename_14.c
new file mode 100644
index 00000000000..61aad34e722
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_14.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_rename( url, NULL );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_2.c b/testsuite/libsmbclient/src/rename/rename_2.c
new file mode 100644
index 00000000000..b3d340348c8
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_2.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_rename( url, argv[5] );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_3.c b/testsuite/libsmbclient/src/rename/rename_3.c
new file mode 100644
index 00000000000..a7508e969c8
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_3.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_open(url,O_RDWR | O_CREAT,0666);
+ err = smbc_rename( url, argv[5] );
+
+ if ( err < 0 )
+ err = 1;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_4.c b/testsuite/libsmbclient/src/rename/rename_4.c
new file mode 100644
index 00000000000..a4c26470017
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_4.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_open(url,O_RDWR | O_CREAT,0666);
+ smbc_rename( url, argv[5] );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_5.c b/testsuite/libsmbclient/src/rename/rename_5.c
new file mode 100644
index 00000000000..97fb8fe6830
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_5.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd );
+ err = smbc_rename( url, argv[5] );
+
+ if ( err < 0 )
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_6.c b/testsuite/libsmbclient/src/rename/rename_6.c
new file mode 100644
index 00000000000..c9c349427e4
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_6.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url,O_RDWR | O_CREAT,0666);
+ smbc_close( fd );
+ smbc_rename( url, argv[5] );
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_7.c b/testsuite/libsmbclient/src/rename/rename_7.c
new file mode 100644
index 00000000000..67188abea96
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_7.c
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ int fd2 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_rename( url, argv[5] );
+ fd1 = smbc_open( url, O_RDWR, 0666 );
+ fd2 = smbc_open( argv[5], O_RDWR, 0666 );
+
+ if ( fd1 == -1 && fd2 != -1 )
+ err = 0;
+
+ else
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_8.c b/testsuite/libsmbclient/src/rename/rename_8.c
new file mode 100644
index 00000000000..efbef5c30cd
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_8.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ int fd2 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 7 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_mkdir( argv[5], 0666 );
+ smbc_rename( url, argv[6] );
+
+ fd1 = smbc_open( url, O_RDWR, 0666 );
+ fd2 = smbc_open( argv[6], O_RDWR, 0666 );
+
+ if ( fd1 == -1 && fd2 != -1 )
+ err = 0;
+
+ else
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rename/rename_9.c b/testsuite/libsmbclient/src/rename/rename_9.c
new file mode 100644
index 00000000000..1c1876dbb00
--- /dev/null
+++ b/testsuite/libsmbclient/src/rename/rename_9.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 9 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[6], strlen(argv[6]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_mkdir( argv[7], 0700 );
+
+ strncpy( g_username, argv[4], strlen(argv[4]) );
+ strncpy( g_password, argv[5], strlen(argv[5]) );
+
+ err = smbc_rename( url, argv[8] );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_1.c b/testsuite/libsmbclient/src/rmdir/rmdir_1.c
new file mode 100644
index 00000000000..2c64052d8be
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_1.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ err = smbc_rmdir( url );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_2.c b/testsuite/libsmbclient/src/rmdir/rmdir_2.c
new file mode 100644
index 00000000000..700b1d7a97f
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_2.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_rmdir( url );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_3.c b/testsuite/libsmbclient/src/rmdir/rmdir_3.c
new file mode 100644
index 00000000000..c1b881d4d4d
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_3.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_mkdir( url, 700 );
+
+ err = smbc_rmdir( url );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_4.c b/testsuite/libsmbclient/src/rmdir/rmdir_4.c
new file mode 100644
index 00000000000..a7723037256
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_4.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ smbc_mkdir( url, 700 );
+
+ smbc_rmdir( url );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_5.c b/testsuite/libsmbclient/src/rmdir/rmdir_5.c
new file mode 100644
index 00000000000..c4f787f63bc
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_5.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ err = smbc_rmdir( url );
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/rmdir/rmdir_6.c b/testsuite/libsmbclient/src/rmdir/rmdir_6.c
new file mode 100644
index 00000000000..a44e6778322
--- /dev/null
+++ b/testsuite/libsmbclient/src/rmdir/rmdir_6.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd1 = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+ strncpy( g_workgroup, argv[1], strlen(argv[1]) );
+ strncpy( g_username, argv[2], strlen(argv[2]) );
+ strncpy( g_password, argv[3], strlen(argv[3]) );
+ strncpy( url, argv[4], strlen(argv[4]) );
+
+ smbc_init( auth_fn, 0 );
+ fd1 = smbc_open( url, O_RDWR | O_CREAT, 0666 );
+ smbc_close( fd1 );
+
+ smbc_rmdir( url );
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_1.c b/testsuite/libsmbclient/src/stat/stat_1.c
new file mode 100644
index 00000000000..08382acd74a
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_1.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ err = smbc_stat(url, &st);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_2.c b/testsuite/libsmbclient/src/stat/stat_2.c
new file mode 100644
index 00000000000..80ee5dd8713
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_2.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_stat(url, &st);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_3.c b/testsuite/libsmbclient/src/stat/stat_3.c
new file mode 100644
index 00000000000..1220577a3c7
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_3.c
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ err = smbc_stat(url, &st);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_4.c b/testsuite/libsmbclient/src/stat/stat_4.c
new file mode 100644
index 00000000000..8bc544833e7
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_4.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ smbc_stat(url, &st);
+
+ err = errno;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_5.c b/testsuite/libsmbclient/src/stat/stat_5.c
new file mode 100644
index 00000000000..86028f0598a
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_5.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ smbc_stat(url,&st);
+
+ free(message);
+
+ if ( st.st_size != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/stat/stat_6.c b/testsuite/libsmbclient/src/stat/stat_6.c
new file mode 100644
index 00000000000..a27e9ba1394
--- /dev/null
+++ b/testsuite/libsmbclient/src/stat/stat_6.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ unsigned int mode_mask = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ struct stat st;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ smbc_stat(url,&st);
+
+ free(message);
+
+ mode_mask = mode_mask | S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //0666 or 33206
+
+ if ( st.st_mode != mode_mask )
+ err = 1;
+
+ else
+ err = 0;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/telldir/telldir_1.c b/testsuite/libsmbclient/src/telldir/telldir_1.c
new file mode 100644
index 00000000000..401bae9e166
--- /dev/null
+++ b/testsuite/libsmbclient/src/telldir/telldir_1.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_telldir(dh);
+ //printf("err: %i\n",err);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/telldir/telldir_2.c b/testsuite/libsmbclient/src/telldir/telldir_2.c
new file mode 100644
index 00000000000..6971b79b0f9
--- /dev/null
+++ b/testsuite/libsmbclient/src/telldir/telldir_2.c
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ smbc_telldir(dh);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/telldir/telldir_3.c b/testsuite/libsmbclient/src/telldir/telldir_3.c
new file mode 100644
index 00000000000..18f1aac6958
--- /dev/null
+++ b/testsuite/libsmbclient/src/telldir/telldir_3.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ err = smbc_telldir(dh);
+ //printf("err: %i\n",err);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/telldir/telldir_4.c b/testsuite/libsmbclient/src/telldir/telldir_4.c
new file mode 100644
index 00000000000..da9ca00b4df
--- /dev/null
+++ b/testsuite/libsmbclient/src/telldir/telldir_4.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int dh = 0;
+
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+
+ dh = smbc_opendir(url);
+ //printf("directory handle: %i\n",dh);
+ smbc_telldir(dh);
+ err = errno;
+ //printf("err: %i\n",err);
+
+
+ }
+
+ return err;
+
+}
diff --git a/testsuite/libsmbclient/src/telldir/telldir_5.c b/testsuite/libsmbclient/src/telldir/telldir_5.c
new file mode 100644
index 00000000000..3d7e92fb066
--- /dev/null
+++ b/testsuite/libsmbclient/src/telldir/telldir_5.c
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int dh = 0;
+ int entry_num = 0;
+ int i = 0;
+ int offset = 0;
+ int dirsize = 0;
+ char *file_name;
+ char *tmp_file_ptr;
+
+ struct smbc_dirent *dirptr;
+
+
+ char buff[MAX_BUFF_SIZE];
+ char url[MAX_BUFF_SIZE];
+ char file_url[MAX_BUFF_SIZE];
+ char dir_url[MAX_BUFF_SIZE];
+ char dirbuff[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(file_url,MAX_BUFF_SIZE);
+ bzero(dir_url,MAX_BUFF_SIZE);
+ bzero(buff,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ dirptr = (struct smbc_dirent *) dirbuff;
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+ smbc_init(auth_fn, 0);
+
+ strncpy(file_url,"tempfile-",9);
+ tmp_file_ptr = file_url;
+ tmp_file_ptr += 9;
+
+ smbc_rmdir(url);
+ smbc_mkdir(url,0666);
+
+ entry_num = atoi(argv[5]);
+ strcat(dir_url,url);
+ strcat(dir_url,"/");
+
+ file_name = dir_url;
+ file_name += strlen(dir_url);
+
+ for ( i = 0; i < entry_num; i++ )
+ {
+ sprintf(buff,"%d",i);
+ memcpy(tmp_file_ptr,buff,strlen(buff)+4);
+ strncat(tmp_file_ptr,".txt",4);
+ strcpy(file_name,file_url);
+ fd = smbc_open(dir_url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ }
+
+ dh = smbc_opendir(url);
+ err = 0;
+
+ while ( 1 )
+ {
+ dirptr = smbc_readdir(dh);
+
+ if ( dirptr == NULL )
+ {
+ break;
+ }
+
+ (char*)dirsize += dirptr->dirlen;
+
+ }
+
+ offset = smbc_telldir(dh);
+
+ if ( offset != dirsize )
+ {
+ //printf("offset: %i dirsize: %i\n",offset,dirsize);
+ err = 1;
+ }
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_1.c b/testsuite/libsmbclient/src/unlink/unlink_1.c
new file mode 100644
index 00000000000..12e9d1d0aa8
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_1.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_10.c b/testsuite/libsmbclient/src/unlink/unlink_10.c
new file mode 100644
index 00000000000..58f541c69a1
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_10.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0000);
+ smbc_close(fd);
+
+ strncpy(g_username, "xxxxxx", 6);
+ strncpy(g_password, "xxxxxx", 6);
+
+ smbc_unlink(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_11.c b/testsuite/libsmbclient/src/unlink/unlink_11.c
new file mode 100644
index 00000000000..f94b93d0482
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_11.c
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0000);
+ smbc_close(fd);
+
+ strncpy(g_username, "xxxxxx", 6);
+ strncpy(g_password, "xxxxxx", 6);
+
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_12.c b/testsuite/libsmbclient/src/unlink/unlink_12.c
new file mode 100644
index 00000000000..f6082595a35
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_12.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ smbc_unlink(url);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ if ( fd < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_2.c b/testsuite/libsmbclient/src/unlink/unlink_2.c
new file mode 100644
index 00000000000..3980704847f
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_2.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_mkdir(url, 0666);
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_3.c b/testsuite/libsmbclient/src/unlink/unlink_3.c
new file mode 100644
index 00000000000..551a651ae45
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_3.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_mkdir(url, 0666);
+ smbc_unlink(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_4.c b/testsuite/libsmbclient/src/unlink/unlink_4.c
new file mode 100644
index 00000000000..309dc39639d
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_4.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[6],strlen(argv[6]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ strncpy(g_username,argv[4],strlen(argv[4]));
+ strncpy(g_password,argv[5],strlen(argv[5]));
+
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_5.c b/testsuite/libsmbclient/src/unlink/unlink_5.c
new file mode 100644
index 00000000000..73a8e057a6b
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_5.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_6.c b/testsuite/libsmbclient/src/unlink/unlink_6.c
new file mode 100644
index 00000000000..334c3653d1f
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_6.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+ smbc_unlink(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_7.c b/testsuite/libsmbclient/src/unlink/unlink_7.c
new file mode 100644
index 00000000000..cda3c9d7b07
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_7.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[6],strlen(argv[6]));
+
+ smbc_init(auth_fn, 0);
+ fd = smbc_open(url, O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ strncpy(g_username,argv[4],strlen(argv[4]));
+ strncpy(g_password,argv[5],strlen(argv[5]));
+
+ smbc_unlink(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_8.c b/testsuite/libsmbclient/src/unlink/unlink_8.c
new file mode 100644
index 00000000000..2053be3c961
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_8.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink/unlink_9.c b/testsuite/libsmbclient/src/unlink/unlink_9.c
new file mode 100644
index 00000000000..78f9c297481
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink/unlink_9.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ char url[MAX_BUFF_SIZE];
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ err = smbc_unlink(url);
+
+ if ( err < 0 )
+ err = 1;
+
+
+ }
+
+ return 1;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_1.c b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_1.c
new file mode 100644
index 00000000000..1b937192a0b
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_1.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+ g_print_id = -1;
+ err = smbc_unlink_print_job(argv[6],g_print_id);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_2.c b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_2.c
new file mode 100644
index 00000000000..49c9ef66876
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_2.c
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+ g_print_id = -1;
+ smbc_unlink_print_job(argv[6],g_print_id);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_3.c b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_3.c
new file mode 100644
index 00000000000..a4cbf42fec5
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_3.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+ err = smbc_unlink_print_job(argv[6],g_print_id);
+
+ if ( err < 0 )
+
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_4.c b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_4.c
new file mode 100644
index 00000000000..156d3413943
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_4.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+ smbc_print_file(url,argv[6]);
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+ smbc_unlink_print_job(argv[6],g_print_id);
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_5.c b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_5.c
new file mode 100644
index 00000000000..4ba5e208b21
--- /dev/null
+++ b/testsuite/libsmbclient/src/unlink_print_job/unlink_print_job_5.c
@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+char g_print_user[MAX_BUFF_SIZE];
+char g_print_name[MAX_BUFF_SIZE];
+unsigned int g_print_id;
+unsigned int g_print_priority;
+unsigned int g_print_size;
+
+unsigned int print_ids[MAX_BUFF_SIZE];
+unsigned int print_id_count;
+int call_flag;
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+void print_list_fn_2(struct print_job_info *pji)
+{
+
+ print_ids[print_id_count] = pji->id;
+ print_id_count++;
+
+ //fprintf(stdout, "Call to Second Print Function - Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ g_print_id = pji->id;
+ g_print_priority = pji->priority;
+ g_print_size = pji->size;
+ strcpy(g_print_user,pji->user);
+ strcpy(g_print_name,pji->name);
+
+ //fprintf(stdout, "Call to First Print Function - Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ // pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ unsigned int i = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+ bzero(g_print_user,MAX_BUFF_SIZE);
+ bzero(g_print_name,MAX_BUFF_SIZE);
+
+ g_print_id = 0;
+ g_print_priority = 0;
+ g_print_size = 0;
+
+ print_id_count = 0;
+
+ if ( argc == 7 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+ //printf("Message: %s\n",message);
+ //printf("Message len: %i\n",msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ smbc_print_file(url,argv[6]);
+ smbc_print_file(url,argv[6]);
+ smbc_print_file(url,argv[6]);
+
+ smbc_list_print_jobs(argv[6],print_list_fn);
+
+ if ( smbc_unlink_print_job(argv[6],g_print_id) == 0 )
+ {
+ if ( smbc_list_print_jobs(argv[6],print_list_fn_2) == 0 )
+ {
+ err = 0;
+
+ for ( i=0; i<print_id_count; i++ )
+ {
+ if ( g_print_id == print_ids[i] )
+ {
+ err = 1;
+ break;
+ }
+
+ }
+ }
+
+ } else
+ err = 1;
+
+
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_1.c b/testsuite/libsmbclient/src/write/write_1.c
new file mode 100644
index 00000000000..fa147f8f503
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_1.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ err = smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_10.c b/testsuite/libsmbclient/src/write/write_10.c
new file mode 100644
index 00000000000..1f43c60bb75
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_10.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message = NULL;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ msg_len = 10;
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+
+ err = errno;
+
+ smbc_close(fd);
+
+ free(message);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_11.c b/testsuite/libsmbclient/src/write/write_11.c
new file mode 100644
index 00000000000..3f9ae3f97da
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_11.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+ smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+ smbc_read(fd,response,msg_len);
+ smbc_close(fd);
+
+ if ( memcmp ( message, response, msg_len) == 0 )
+ err = 0;
+
+ else
+ err = 1;
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_12.c b/testsuite/libsmbclient/src/write/write_12.c
new file mode 100644
index 00000000000..3528dbb36e2
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_12.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ strncpy(g_username,"xxxxxxxx",8);
+ strncpy(g_password,"xxxxxxxx",8);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ err = smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_13.c b/testsuite/libsmbclient/src/write/write_13.c
new file mode 100644
index 00000000000..f3c2ad5bc3f
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_13.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+ char* response;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ response = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ strncpy(g_username,"xxxxxxxx",8);
+ strncpy(g_password,"xxxxxxxx",8);
+
+ fd = smbc_open(url, O_RDWR, 0666);
+
+ if (fd < 0)
+
+ err = errno;
+
+ else {
+
+ smbc_write(fd, message, msg_len);
+ err = errno;
+
+ smbc_close(fd);
+
+ }
+
+ free(message);
+ free(response);
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_2.c b/testsuite/libsmbclient/src/write/write_2.c
new file mode 100644
index 00000000000..49763ebe0cd
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_2.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+
+ smbc_write(fd, message, msg_len);
+ err = errno;
+
+ smbc_close(fd);
+
+ free(message);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_3.c b/testsuite/libsmbclient/src/write/write_3.c
new file mode 100644
index 00000000000..254782946d7
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_3.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+ err = smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_4.c b/testsuite/libsmbclient/src/write/write_4.c
new file mode 100644
index 00000000000..6ee585f0210
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_4.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_RDONLY, 0666);
+
+ smbc_write(fd, message, msg_len);
+ err = errno;
+
+ smbc_close(fd);
+
+ free(message);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_5.c b/testsuite/libsmbclient/src/write/write_5.c
new file mode 100644
index 00000000000..84cb50123cc
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_5.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_WRONLY, 0666);
+ err = smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ if ( err < 0 )
+ err = 1;
+
+ else if ( err != msg_len )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_6.c b/testsuite/libsmbclient/src/write/write_6.c
new file mode 100644
index 00000000000..c139ff81379
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_6.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 6 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ msg_len = strlen(argv[5])+1;
+ message = malloc(msg_len);
+ message[msg_len - 1] = 0;
+ strncpy(message,argv[5],msg_len);
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ fd = smbc_open(url, O_WRONLY, 0666);
+
+ smbc_write(fd, message, msg_len);
+ err = errno;
+
+ smbc_close(fd);
+
+ free(message);
+
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_7.c b/testsuite/libsmbclient/src/write/write_7.c
new file mode 100644
index 00000000000..b0ce9b6fa26
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_7.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char* message = "Testing";
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ fd = 10345; // Random value for File Descriptor
+ smbc_init(auth_fn, 0);
+ err = smbc_write(fd, message, sizeof(message));
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_8.c b/testsuite/libsmbclient/src/write/write_8.c
new file mode 100644
index 00000000000..4176bec6012
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_8.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ char* message = "Testing";
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+
+ if ( argc == 4 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+
+ fd = 10345; // Random value for File Descriptor
+ smbc_init(auth_fn, 0);
+ err = smbc_write(fd, message, sizeof(message));
+
+ err = errno;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/libsmbclient/src/write/write_9.c b/testsuite/libsmbclient/src/write/write_9.c
new file mode 100644
index 00000000000..b707d5c688e
--- /dev/null
+++ b/testsuite/libsmbclient/src/write/write_9.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libsmbclient.h>
+
+#define MAX_BUFF_SIZE 255
+char g_workgroup[MAX_BUFF_SIZE];
+char g_username[MAX_BUFF_SIZE];
+char g_password[MAX_BUFF_SIZE];
+char g_server[MAX_BUFF_SIZE];
+char g_share[MAX_BUFF_SIZE];
+
+
+void auth_fn(const char *server, const char *share, char *workgroup, int wgmaxlen,
+ char *username, int unmaxlen, char *password, int pwmaxlen)
+{
+
+ strncpy(workgroup, g_workgroup, wgmaxlen - 1);
+
+ strncpy(username, g_username, unmaxlen - 1);
+
+ strncpy(password, g_password, pwmaxlen - 1);
+
+ strcpy(g_server, server);
+ strcpy(g_share, share);
+
+}
+
+int main(int argc, char** argv)
+{
+ int err = -1;
+ int fd = 0;
+ int msg_len = 0;
+ char url[MAX_BUFF_SIZE];
+ char* message = NULL;
+
+ bzero(g_workgroup,MAX_BUFF_SIZE);
+ bzero(url,MAX_BUFF_SIZE);
+
+ if ( argc == 5 )
+ {
+
+ strncpy(g_workgroup,argv[1],strlen(argv[1]));
+ strncpy(g_username,argv[2],strlen(argv[2]));
+ strncpy(g_password,argv[3],strlen(argv[3]));
+ strncpy(url,argv[4],strlen(argv[4]));
+
+ smbc_init(auth_fn, 0);
+ smbc_unlink(url);
+ fd = smbc_open(url,O_RDWR | O_CREAT, 0666);
+ smbc_close(fd);
+
+ msg_len = 10;
+ fd = smbc_open(url, O_RDWR, 0666);
+ err = smbc_write(fd, message, msg_len);
+ smbc_close(fd);
+
+ free(message);
+
+ if ( err < 0 )
+ err = 1;
+
+ else
+ err = 0;
+
+ }
+
+ return err;
+
+}
+
diff --git a/testsuite/nsswitch/.cvsignore b/testsuite/nsswitch/.cvsignore
new file mode 100644
index 00000000000..1c30875a884
--- /dev/null
+++ b/testsuite/nsswitch/.cvsignore
@@ -0,0 +1,12 @@
+initgroups
+nss_winbind_syms
+getgrent_r
+getgrgid
+getgrnam
+getpwent_r
+getpwnam
+wbtorture
+leaktest?
+getpwuid
+getent_pwent
+getent_grent
diff --git a/testsuite/nsswitch/Makefile.longarg b/testsuite/nsswitch/Makefile.longarg
new file mode 100644
index 00000000000..6cc7ef8306d
--- /dev/null
+++ b/testsuite/nsswitch/Makefile.longarg
@@ -0,0 +1,5 @@
+#
+# Makefile for null tests
+#
+
+longarg_getpwnam: longarg_getpwnam.o \ No newline at end of file
diff --git a/testsuite/nsswitch/bigfd.c b/testsuite/nsswitch/bigfd.c
new file mode 100644
index 00000000000..99e402e0f33
--- /dev/null
+++ b/testsuite/nsswitch/bigfd.c
@@ -0,0 +1,38 @@
+/*
+ * Test maximum number of file descriptors winbind daemon can handle
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ struct passwd *pw;
+ int i;
+
+ while(1) {
+
+ /* Start getpwent until we get an NT user. This way we know we
+ have at least opened a connection to the winbind daemon */
+
+ setpwent();
+
+ while((pw = getpwent()) != NULL) {
+ if (strchr(pw->pw_name, '/') != NULL) {
+ break;
+ }
+ }
+
+ if (pw != NULL) {
+ i++;
+ printf("got pwent handle %d\n", i);
+ } else {
+ printf("winbind daemon not running?\n");
+ exit(1);
+ }
+
+ sleep(1);
+ }
+}
diff --git a/testsuite/nsswitch/bigfd.exp b/testsuite/nsswitch/bigfd.exp
new file mode 100644
index 00000000000..62fc9ea7f35
--- /dev/null
+++ b/testsuite/nsswitch/bigfd.exp
@@ -0,0 +1,28 @@
+#
+# @(#) Test maximum number of clients (file descriptors) for winbindd
+#
+
+load_lib util-defs.exp
+
+# Unimplemented - eek!
+
+untested "bigfd"
+return
+
+# Compile bigfd.c
+
+set output [target_compile "$srcdir/$subdir/bigfd.c" \
+ "$srcdir/$subdir/bigfd" executable {additional_flags="-g"}]
+
+if {$output != ""} {
+ perror "compile bigfd"
+ puts $output
+ return
+}
+
+# Run bigfd
+
+set output [util_start "$srcdir/$subdir/bigfd" "" ""]
+puts $output
+
+pass "bigfd"
diff --git a/testsuite/nsswitch/domusers.exp b/testsuite/nsswitch/domusers.exp
new file mode 100644
index 00000000000..3b291ab398b
--- /dev/null
+++ b/testsuite/nsswitch/domusers.exp
@@ -0,0 +1,38 @@
+#
+# @(#) Test that all users are members of the Domain Users group.
+#
+# Note that this isn't necessarily true all the time but you have to
+# explicitly move people out of that group so it should be OK for te
+#
+
+load_lib util-defs.exp
+load_lib $srcdir/lib/nsswitch-config.exp
+
+# Get list of users and stick usernames in a hash
+
+set user_list [util_start "getent" "passwd" ""]
+
+foreach { user } [split $user_list "\n"] {
+ set user_elts [split $user ":"]
+ set users([lindex $user_elts 0]) 1
+}
+
+# Get list of groups
+
+set group_list [util_start "getent" "group" ""]
+
+foreach { group } [split $group_list "\n"] {
+ set group_elts [split $group ":"]
+
+ # Look for domain users group
+
+ if { ![regexp "Domain Users" [lindex $group_elts 0]] } {
+ continue
+ }
+
+ # Check each member of group was found in getent passwd
+
+ foreach { mem } [split [lindex $group_elts 3] ","] {
+ set mems($mem) 1
+ }
+}
diff --git a/testsuite/nsswitch/envvar.exp b/testsuite/nsswitch/envvar.exp
new file mode 100644
index 00000000000..134a8b37a85
--- /dev/null
+++ b/testsuite/nsswitch/envvar.exp
@@ -0,0 +1,282 @@
+#
+# @(#) Test operation of WINBINDD_DOMAIN environment variable
+#
+
+load_lib "util-defs.exp"
+load_lib "$srcdir/lib/nsswitch-config.exp"
+
+#
+# @(#) Test that there is at least one domain user and domain group
+# @(#) in the output of getent passwd and getent group.
+#
+
+# Get list of users and groups
+
+set user_list [util_start "getent passwd"]
+set group_list [util_start "getent group"]
+
+verbose "user list is:\n$user_list"
+verbose "group list is:\n$group_list"
+
+# Check for domain users
+
+set no_dom 0
+
+if { ![regexp "$domain/" $user_list] } {
+ fail "no domain users in getent"
+ set no_dom 1
+}
+
+# Check for domain groups
+
+if { ![regexp "$domain/" $group_list] } {
+ fail "no domain groups in getent group"
+ set no_dom 1
+}
+
+if { $no_dom } {
+ return
+}
+
+#
+# @(#) Check for "leakage" between different domains using the
+# @(#) WINBINDD_DOMAIN environment variable.
+#
+
+verbose "Domain is $domain"
+
+set output [util_start "bin/wbinfo" "-m"]
+verbose "Trusted domains are $output"
+set trusted_domain_list [split $output "\n"]
+
+# Test simple inclusion by setting $WINBINDD_DOMAIN to each trusted domain
+# in turn and checking there are no users/groups from other domains in the
+# output of getent.
+
+set domain_list $trusted_domain_list
+lappend domain_list $domain
+
+foreach { the_domain } $domain_list {
+
+ set env(WINBINDD_DOMAIN) $the_domain
+
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { user } [split $user_out "\n"] {
+ set user_name [lindex [split $user ":"] 0]
+ if { [regexp "/" $user_name] && ![regexp $the_domain $user_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { group } [split $group_out "\n"] {
+ set group_name [lindex [split $group ":"] 0]
+ if { [regexp "/" $group_name] && ![regexp $the_domain $group_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Test inclusion of a dummy domain doesn't generate users/groups
+# @(#) from that domain.
+#
+
+set env(WINBINDD_DOMAIN) "asmithee"
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+# Users
+
+set test_desc "users in different WINBINDD_DOMAIN"
+if { [regexp $domain $user_out] } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Groups
+
+set test_desc "groups in different WINBINDD_DOMAIN"
+if { [regexp $domain $group_out] } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+#
+# @(#) Test comma separated inclusion of dummy domain doesn't generate
+# @(#) users/groups in the dummy domain.
+#
+
+foreach { the_domain } $domain_list {
+ set env(WINBINDD_DOMAIN) "$the_domain,asmithee"
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in comma separated WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { user } [split $user_out "\n"] {
+ set user_name [lindex [split $user ":"] 0]
+ if { [regexp "/" $user_name] && ![regexp $the_domain $user_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in comma separated WINBINDD_DOMAIN $the_domain"
+ set failed 0
+
+ foreach { group } [split $group_out "\n"] {
+ set group_name [lindex [split $group ":"] 0]
+ if { [regexp "/" $group_name] && ![regexp $the_domain $group_name]} {
+ set failed 1
+ }
+ }
+
+ if { $failed } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Test two comma separated dummy domains do not generate any domain
+# @(#) users or groups.
+#
+
+foreach { the_domain } $domain_list {
+
+ set env(WINBINDD_DOMAIN) "moose,asmithee"
+ set user_out [util_start "getent passwd"]
+ set group_out [util_start "getent group"]
+
+ verbose "users in $the_domain:\n$user_out\n"
+ verbose "groups in $the_domain:\n$group_out\n"
+
+ # Users
+
+ set test_desc "users in comma separated invalid WINBINDD_DOMAIN"
+ if { [regexp $the_domain $user_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups in comma separated invalid WINBINDD_DOMAIN"
+ if { [regexp $the_domain $group_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+set env(WINBINDD_DOMAIN) ""
+
+#
+# @(#) Test _NO_WINBINDD doesn't return any domain users or groups
+#
+
+set env(_NO_WINBINDD) "1"
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+verbose "users with _NO_WINBINDD:\n$user_out\n"
+verbose "groups with _NO_WINBINDD:\n$group_out\n"
+
+foreach { the_domain } $domain_list {
+
+ # Users
+
+ set test_desc "users found with _NO_WINBINDD environment variable set"
+ if { [regexp $the_domain $user_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ # Groups
+
+ set test_desc "groups found with _NO_WINBINDD environment variable set"
+ if { [regexp $the_domain $group_out] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Unset _NO_WINBINDD and make sure everything still works
+
+unset env(_NO_WINBINDD)
+
+set user_out [util_start "getent passwd"]
+set group_out [util_start "getent group"]
+
+verbose "users with _NO_WINBINDD unset:\n$user_out\n"
+verbose "groups with _NO_WINBINDD unset:\n$group_out\n"
+
+# Users
+
+set test_desc "no users found with _NO_WINBINDD environment variable set"
+if { $user_out != $user_list } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Groups
+
+set test_desc "no groups found with _NO_WINBINDD environment variable set"
+if { $group_out != $group_list } {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Make sure we unset the environment vars so we don't cause subsequent tests
+# any grief.
+
+catch { unset env(WINBINDD_DOMAIN) } tmp
+catch { unset env(_NO_WINBINDD) } tmp
diff --git a/testsuite/nsswitch/finger.exp b/testsuite/nsswitch/finger.exp
new file mode 100644
index 00000000000..36bab8e1990
--- /dev/null
+++ b/testsuite/nsswitch/finger.exp
@@ -0,0 +1,39 @@
+#
+# @(#) Test default domain users resolve using the finger command
+#
+
+load_lib util-defs.exp
+
+set output [util_start "bin/wbinfo" "-u"]
+if { [regexp "Error" $output] } {
+ fail "error running wbinfo"
+ return
+}
+
+set user_list [split $output "\n"]
+
+# Look up all users using finger -m. This should test getpwnam()
+
+foreach { user } $user_list {
+ set output [util_start "finger" "-m \"$user\"" "" "no such user"]
+ verbose $output
+
+ if { [regexp "no such user" $output] } {
+ fail "finger -m $user"
+ } else {
+ pass "finger -m $user"
+ }
+}
+
+# Run finger without the -m to also test set/get/endpwent()
+
+foreach { user } $user_list {
+ set output [util_start "finger" "\"$user\""]
+ verbose $output
+
+ if { [regexp "no such user" $output] } {
+ fail "finger $user"
+ } else {
+ pass "finger $user"
+ }
+}
diff --git a/testsuite/nsswitch/getent.c b/testsuite/nsswitch/getent.c
new file mode 100644
index 00000000000..b4c4e50c6fe
--- /dev/null
+++ b/testsuite/nsswitch/getent.c
@@ -0,0 +1,151 @@
+/* Cut down version of getent which only returns passwd and group database
+ entries and seems to compile on most systems without too much fuss.
+ Original copyright notice below. */
+
+/* Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+
+group_keys (int number, char *key[])
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < number; ++i)
+ {
+ struct group *grp;
+
+ if (isdigit (key[i][0]))
+ grp = getgrgid (atol (key[i]));
+ else
+ grp = getgrnam (key[i]);
+
+ if (grp == NULL)
+ result = 2;
+ else
+ print_group (grp);
+ }
+
+ return result;
+}
+
+passwd_keys (int number, char *key[])
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < number; ++i)
+ {
+ struct passwd *pwd;
+
+ if (isdigit (key[i][0]))
+ pwd = getpwuid (atol (key[i]));
+ else
+ pwd = getpwnam (key[i]);
+
+ if (pwd == NULL)
+ result = 2;
+ else
+ print_passwd (pwd);
+ }
+
+ return result;
+}
+
+print_group (struct group *grp)
+{
+ unsigned int i = 0;
+
+ printf ("%s:%s:%ld:", grp->gr_name ? grp->gr_name : "",
+ grp->gr_passwd ? grp->gr_passwd : "",
+ (unsigned long)grp->gr_gid);
+
+ while (grp->gr_mem[i] != NULL)
+ {
+ fputs (grp->gr_mem[i], stdout);
+ ++i;
+ if (grp->gr_mem[i] != NULL)
+ fputs (",", stdout);
+ }
+ fputs ("\n", stdout);
+}
+
+print_passwd (struct passwd *pwd)
+{
+ printf ("%s:%s:%ld:%ld:%s:%s:%s\n",
+ pwd->pw_name ? pwd->pw_name : "",
+ pwd->pw_passwd ? pwd->pw_passwd : "",
+ (unsigned long)pwd->pw_uid,
+ (unsigned long)pwd->pw_gid,
+ pwd->pw_gecos ? pwd->pw_gecos : "",
+ pwd->pw_dir ? pwd->pw_dir : "",
+ pwd->pw_shell ? pwd->pw_shell : "");
+}
+
+int main(int argc, char **argv)
+{
+ switch(argv[1][0])
+ {
+ case 'g': /* group */
+ if (strcmp (argv[1], "group") == 0)
+ {
+ if (argc == 2)
+ {
+ struct group *grp;
+
+ setgrent ();
+ while ((grp = getgrent()) != NULL)
+ print_group (grp);
+ endgrent ();
+ }
+ else
+ return group_keys (argc - 2, &argv[2]);
+ }
+ else
+ goto error;
+ break;
+
+ case 'p': /* passwd, protocols */
+ if (strcmp (argv[1], "passwd") == 0)
+ {
+ if (argc == 2)
+ {
+ struct passwd *pwd;
+
+ setpwent ();
+ while ((pwd = getpwent()) != NULL)
+ print_passwd (pwd);
+ endpwent ();
+ }
+ else
+ return passwd_keys (argc - 2, &argv[2]);
+ }
+ else
+ goto error;
+ break;
+ default:
+ error:
+ fprintf (stderr, "Unknown database: %s\n", argv[1]);
+ return 1;
+ }
+ return 0;
+}
diff --git a/testsuite/nsswitch/getent.exp b/testsuite/nsswitch/getent.exp
new file mode 100644
index 00000000000..72bf2ea1ebe
--- /dev/null
+++ b/testsuite/nsswitch/getent.exp
@@ -0,0 +1,148 @@
+#
+# @(#) Test the getent command returns domain/local users and groups
+#
+
+load_lib util-defs.exp
+load_lib compile.exp
+load_lib $srcdir/lib/nsswitch-config.exp
+
+#
+# @(#) Test getent passwd returns domain users
+#
+
+set wbinfo_output [util_start "bin/wbinfo" "-u"]
+set getent_output [util_start "getent" "passwd" ""]
+
+if { ![regexp "$domain/" $getent_output] } {
+ fail "no domain users in getent passwd"
+ return
+}
+
+if { [regexp "Error" $wbinfo_output] } {
+ fail "wbinfo -u failed"
+ return
+}
+
+#
+# @(#) Test each user in the output of wbinfo is also in the output of
+# @(#) getent.
+#
+
+# Test wbinfo user names are in getent user names
+
+foreach { user } [split $wbinfo_output "\n"] {
+
+ verbose "looking for $user"
+
+ set test_desc "getent passwd does not contain $user"
+
+ if { ![regexp "$user" $getent_output] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Test getent user names are in wbinfo user names
+
+foreach { user } [split $getent_output "\n"] {
+
+ set user_info [split $user ":"]
+ set username [lindex $user_info 0]
+
+ if { [regexp {^[^/]+/} $username] } {
+
+ set test_desc "wbinfo -u does not contain $username"
+
+ if { ![regexp "$username" $wbinfo_output] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+ } else {
+ verbose "ignoring non-domain user $username"
+ }
+}
+
+#
+# @(#) Test each group in the output of wbinfo is also in the output of
+# @(#) getent.
+#
+
+set wbinfo_output [util_start "bin/wbinfo" "-g"]
+set getent_output [util_start "getent" "group" ""]
+
+if { ![regexp "$domain/" $getent_output] } {
+ fail "no domain groups in getent passwd"
+ return
+}
+
+if { [regexp "Error" $wbinfo_output] } {
+ fail "wbinfo -g failed"
+ return
+}
+
+# Test wbinfo group names are in getent group names
+
+foreach { group } [split $wbinfo_output "\n"] {
+
+ verbose "looking for $group"
+
+ set test_desc "getent group does not contain $group"
+
+ if { ![regexp "$group" $getent_output] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Test getent group names are in wbinfo group names
+
+foreach { group } [split $getent_output "\n"] {
+
+ set group_info [split $group ":"]
+ set groupname [lindex $group_info 0]
+
+ if { [regexp {^[^/]+/} $groupname] } {
+
+ set test_desc "wbinfo -g does not contain $groupname"
+
+ if { ![regexp "$groupname" $wbinfo_output] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+ } else {
+ verbose "ignoring non-domain group $groupname"
+ }
+}
+
+#
+# @(#) Test out of order and repeat calls of pwent functions
+# @(#) Test out of order and repeat calls of grent functions
+#
+
+set getent_tests [list \
+ { "out of order pwent operations" "getent_pwent" } \
+ { "out of order grent operations" "getent_grent" } \
+ ]
+
+# Compile and run each test
+
+foreach { test } $getent_tests {
+ set test_desc [lindex $test 0]
+ set test_file [lindex $test 1]
+
+ simple_compile $test_file
+ set output [util_start "$srcdir/$subdir/$test_file" ]
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_file" "$srcdir/$subdir/$test_file.o"
+ } else {
+ fail $test_desc
+ puts $output
+ }
+
+}
diff --git a/testsuite/nsswitch/getent_grent.c b/testsuite/nsswitch/getent_grent.c
new file mode 100644
index 00000000000..782cc0c86b7
--- /dev/null
+++ b/testsuite/nsswitch/getent_grent.c
@@ -0,0 +1,101 @@
+/* Test out of order operations with {set,get,end}grent */
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <grp.h>
+
+int main (int argc, char **argv)
+{
+ struct group *gr;
+ int found = 0;
+ int num_users, i;
+
+ /* Test getgrent() without setgrent() */
+
+ for (i = 0; i < 100; i++) {
+ gr = getgrent();
+
+ /* This is supposed to work */
+
+#if 0
+ if (gr != NULL) {
+ printf("FAIL: getgrent() with no setgrent()\n");
+ return 1;
+ }
+#endif
+ }
+
+ /* Work out how many user till first domain group */
+
+ num_users = 0;
+ setgrent();
+
+ while (1) {
+ gr = getgrent();
+ num_users++;
+
+ if (gr == NULL) break;
+
+ if (strchr(gr->gr_name, '/')) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ printf("FAIL: could not find any domain groups\n");
+ return 1;
+ }
+
+ /* Test stopping getgrent in the middle of a set of users */
+
+ endgrent();
+
+ /* Test setgrent() without any getgrent() calls */
+
+ setgrent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getgrent();
+ }
+
+ endgrent();
+
+ /* Test lots of setgrent() calls */
+
+ for (i = 0; i < 100; i++) {
+ setgrent();
+ }
+
+ /* Test lots of endgrent() calls */
+
+ for (i = 0; i < 100; i++) {
+ endgrent();
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/getent_pwent.c b/testsuite/nsswitch/getent_pwent.c
new file mode 100644
index 00000000000..96c804433a4
--- /dev/null
+++ b/testsuite/nsswitch/getent_pwent.c
@@ -0,0 +1,113 @@
+/* Test out of order operations with {set,get,end}pwent */
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <pwd.h>
+
+int main (int argc, char **argv)
+{
+ struct passwd *pw;
+ int found = 0;
+ int num_users, i;
+
+ /* Test getpwent() without setpwent() */
+
+ for (i = 0; i < 100; i++) {
+ pw = getpwent();
+
+ /* This is supposed to work */
+
+#if 0
+ if (pw != NULL) {
+ printf("FAIL: getpwent() with no setpwent()\n");
+ return 1;
+ }
+#endif
+ }
+
+ /* Work out how many user till first domain user */
+
+ num_users = 0;
+ setpwent();
+
+ while (1) {
+ pw = getpwent();
+ num_users++;
+
+ if (pw == NULL) break;
+
+ if (strchr(pw->pw_name, '/')) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ printf("FAIL: could not find any domain users\n");
+ return 1;
+ }
+
+ /* Test stopping getpwent in the middle of a set of users */
+
+ endpwent();
+
+ /* Test setpwent() without any getpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ endpwent();
+
+ /* Test lots of setpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ for (i = 0; i < 100; i++) {
+ setpwent();
+ }
+
+ /* Test lots of endpwent() calls */
+
+ setpwent();
+
+ for (i = 0; i < (num_users - 1); i++) {
+ getpwent();
+ }
+
+ for (i = 0; i < 100; i++) {
+ endpwent();
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/getent_r.sh b/testsuite/nsswitch/getent_r.sh
new file mode 100755
index 00000000000..75dc603f829
--- /dev/null
+++ b/testsuite/nsswitch/getent_r.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Verify test output. Basically we check to see if all the files generated
+# in /tmp by the get{pw,gr}ent_r.c and program are identical. If there is
+# some problem with the re-entrancy of the code then the information in the
+# two files will be different.
+#
+
+TYPE=$1
+ID=$2
+FILES="/tmp/${TYPE}_r-${ID}.out-*"
+
+# Sort files
+
+for file in $FILES; do
+ cat $file | sort > $file.sorted
+done
+
+# Diff files
+
+SORTED="/tmp/${TYPE}_r-${ID}.out-*.sorted"
+failed=0
+
+for file1 in $SORTED; do
+ for file2 in $SORTED; do
+ if [ $file1 != $file2 ]; then
+ diff $file1 $file2
+ fi
+ done
+done
+
+# Clean up
+
+rm -f $SORTED
+
diff --git a/testsuite/nsswitch/getgrent_r.c b/testsuite/nsswitch/getgrent_r.c
new file mode 100644
index 00000000000..3eac8aa218d
--- /dev/null
+++ b/testsuite/nsswitch/getgrent_r.c
@@ -0,0 +1,84 @@
+/*
+ * Use set/get/endgrent calls from two processes to iterate over the
+ * password database. This checks the multithreaded stuff works.
+ */
+
+#include <stdio.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <wait.h>
+
+void dump_grent(char *id)
+{
+ struct group *gr;
+ char fname[255];
+ FILE *fptr;
+
+ /* Open results file */
+
+ sprintf(fname, "/tmp/getgrent_r-%s.out-%d", id, getpid());
+
+ if ((fptr = fopen(fname, "w")) < 0) {
+ fprintf(stderr, "ERROR: could not open file %s: %s\n", fname,
+ sys_errlist[errno]);
+ return;
+ }
+
+ /* Dump group database */
+
+ setgrent();
+
+ while((gr = getgrent()) != NULL) {
+ fprintf(fptr,"%s:%s:%d:%d\n", gr->gr_name, gr->gr_passwd,
+ gr->gr_gid);
+ }
+
+ endgrent();
+
+ /* Close results file */
+
+ fclose(fptr);
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: must specify output file identifier\n");
+ return 1;
+ }
+
+ /* Fork child process */
+
+ if ((pid = fork()) == -1) {
+ printf("ERROR: unable to fork\n");
+ return 1;
+ }
+
+ /* Handle test case */
+
+ if (pid > 0) {
+ int status;
+
+ /* Parent */
+
+ dump_grent(argv[1]);
+ wait(&status);
+
+ } else {
+
+ /* Child */
+
+ dump_grent(argv[1]);
+ return 0;
+ }
+
+ printf("PASS: run getgrent_r.c\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/getgrent_r.exp b/testsuite/nsswitch/getgrent_r.exp
new file mode 100644
index 00000000000..c03237c2ad1
--- /dev/null
+++ b/testsuite/nsswitch/getgrent_r.exp
@@ -0,0 +1,41 @@
+#
+# @(#) Test multiple threads can enumerate groups correctly
+#
+
+load_lib util-defs.exp
+load_lib "$srcdir/lib/nsswitch-config.exp"
+
+# Compile getgrent_r.c
+
+set output [target_compile "$srcdir/$subdir/getgrent_r.c" \
+ "$srcdir/$subdir/getgrent_r" executable {additional_flags="-g"}]
+
+if {$output != ""} {
+ perror "compile getgrent_r"
+ puts $output
+ return
+}
+
+# Clean up output from previous tests
+
+set pid [pid]
+file delete [glob -nocomplain "/tmp/getgrent_r-$pid.out-*"]
+
+# Run test proggy
+
+set output [util_start "$srcdir/$subdir/getgrent_r" "$pid" ""]
+if {![regexp "^PASS:" $output]} {
+ perror "run getgrent_r"
+ puts $output
+ return -1
+}
+
+# Sort and compare output
+
+set output [util_start "$srcdir/$subdir/getent_r.sh" "getgrent $pid" ""]
+if {$output == ""} {
+ pass "getgrent_r"
+} else {
+ fail "getgrent_r"
+ puts $output
+}
diff --git a/testsuite/nsswitch/getgrgid.c b/testsuite/nsswitch/getgrgid.c
new file mode 100644
index 00000000000..947dd0ac4c7
--- /dev/null
+++ b/testsuite/nsswitch/getgrgid.c
@@ -0,0 +1,57 @@
+/*
+ * Lookup a group by gid.
+ */
+
+#include <stdio.h>
+#include <grp.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ struct group *gr;
+ gid_t gid;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: no arg specified\n");
+ exit(1);
+ }
+
+ if ((gid = atoi(argv[1])) == 0) {
+ printf("ERROR: invalid gid specified\n");
+ exit(1);
+ }
+
+ /* Do getgrgid() */
+
+ if ((gr = getgrgid(gid)) == NULL) {
+ printf("FAIL: gid %d does not exist\n", gid);
+ exit(1);
+ }
+
+ /* Print group info */
+
+ printf("PASS: gid %d exists\n", gid);
+ printf("gr_name = %s\n", gr->gr_name);
+ printf("gr_passwd = %s\n", gr->gr_passwd);
+ printf("gr_gid = %d\n", gr->gr_gid);
+
+ /* Group membership */
+
+ if (gr->gr_mem != NULL) {
+ int i = 0;
+
+ printf("gr_mem = ");
+ while(gr->gr_mem[i] != NULL) {
+ printf("%s", gr->gr_mem[i]);
+ i++;
+ if (gr->gr_mem != NULL) {
+ printf(",");
+ }
+ }
+ printf("\n");
+ }
+
+ exit(0);
+}
diff --git a/testsuite/nsswitch/getgrgid.exp b/testsuite/nsswitch/getgrgid.exp
new file mode 100644
index 00000000000..c53749f2629
--- /dev/null
+++ b/testsuite/nsswitch/getgrgid.exp
@@ -0,0 +1,50 @@
+#
+# @(#) Test reverse lookup of group ids from getent match getgrgid() output
+#
+
+load_lib util-defs.exp
+load_lib compile.exp
+
+# Compile getgruid.c
+
+simple_compile "getgrgid"
+
+# Get list of gids using getent
+
+set output [util_start "getent" "group" ""]
+set got_entries 0
+
+verbose $output
+
+foreach {line} [split $output "\n"] {
+
+ # Process user
+
+ set grp_entry [split $line ":"]
+ set group [lindex $grp_entry 0]
+
+ if {[regexp {^[^/]+/} $group]} {
+
+ set got_entries 1
+
+ # Only lookup winbindd users
+
+ set gid [lindex $grp_entry 2]
+
+ # Test lookup of gid succeeds
+
+ set output [util_start "$srcdir/$subdir/getgrgid" "$gid" ""]
+ verbose $output
+
+ if {[regexp "PASS:" $output]} {
+ pass "getgrgid $gid ($group)"
+ } else {
+ fail "getgrgid $gid ($group)"
+ }
+ }
+
+}
+
+if {!$got_entries} {
+ perror "No domain groups returned from getent"
+}
diff --git a/testsuite/nsswitch/getgrnam.c b/testsuite/nsswitch/getgrnam.c
new file mode 100644
index 00000000000..8ab4046bd9e
--- /dev/null
+++ b/testsuite/nsswitch/getgrnam.c
@@ -0,0 +1,51 @@
+/*
+ * Lookup a group by name
+ */
+
+#include <stdio.h>
+#include <grp.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ struct group *gr;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: no arg specified\n");
+ exit(1);
+ }
+
+ /* Do getgrnam() */
+
+ if ((gr = getgrnam(argv[1])) == NULL) {
+ printf("FAIL: group %s does not exist\n", argv[1]);
+ exit(1);
+ }
+
+ /* Print group info */
+
+ printf("PASS: group %s exists\n", argv[1]);
+ printf("gr_name = %s\n", gr->gr_name);
+ printf("gr_passwd = %s\n", gr->gr_passwd);
+ printf("gr_gid = %d\n", gr->gr_gid);
+
+ /* Group membership */
+
+ if (gr->gr_mem != NULL) {
+ int i = 0;
+
+ printf("gr_mem = ");
+ while(gr->gr_mem[i] != NULL) {
+ printf("%s", gr->gr_mem[i]);
+ i++;
+ if (gr->gr_mem != NULL) {
+ printf(",");
+ }
+ }
+ printf("\n");
+ }
+
+ exit(0);
+}
diff --git a/testsuite/nsswitch/getgrnam.exp b/testsuite/nsswitch/getgrnam.exp
new file mode 100644
index 00000000000..92c5b76742e
--- /dev/null
+++ b/testsuite/nsswitch/getgrnam.exp
@@ -0,0 +1,28 @@
+#
+# @(#) Test domain groups resolve using getgrnam()
+#
+
+load_lib "util-defs.exp"
+load_lib "compile.exp"
+
+# Compile getgrnam.c
+
+simple_compile "getgrnam"
+
+# Test domain groups
+
+set group_list [split [util_start "bin/wbinfo" "-g"] "\n"]
+
+verbose $group_list
+
+foreach {group} $group_list {
+ set output [util_start "$srcdir/$subdir/getgrnam" "\"$group\"" ""]
+
+ verbose $output
+
+ if {[regexp "PASS:" $output]} {
+ pass "getgrnam $group"
+ } else {
+ fail "getgrnam $group"
+ }
+}
diff --git a/testsuite/nsswitch/getpwent_r.c b/testsuite/nsswitch/getpwent_r.c
new file mode 100644
index 00000000000..2ba7ea96f1e
--- /dev/null
+++ b/testsuite/nsswitch/getpwent_r.c
@@ -0,0 +1,85 @@
+/*
+ * Use set/get/endpwent calls from two processes to iterate over the
+ * password database. This checks the multithreaded stuff works.
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <wait.h>
+
+void dump_pwent(char *id)
+{
+ struct passwd *pw;
+ char fname[255];
+ FILE *fptr;
+
+ /* Open results file */
+
+ sprintf(fname, "/tmp/getpwent_r-%s.out-%d", id, getpid());
+
+ if ((fptr = fopen(fname, "w")) < 0) {
+ fprintf(stderr, "ERROR: could not open file %s: %s\n", fname,
+ sys_errlist[errno]);
+ return;
+ }
+
+ /* Dump passwd database */
+
+ setpwent();
+
+ while((pw = getpwent()) != NULL) {
+ fprintf(fptr,"%s:%s:%s:%d:%d\n", pw->pw_name, pw->pw_passwd,
+ pw->pw_gecos, pw->pw_uid, pw->pw_gid);
+ }
+
+ endpwent();
+
+ /* Close results file */
+
+ fclose(fptr);
+}
+
+#define NUM_FORKS 2
+
+int main(int argc, char **argv)
+{
+ pid_t pids[NUM_FORKS];
+ int i, status;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: must specify output file identifier\n");
+ return 1;
+ }
+
+ for(i = 0; i < NUM_FORKS; i++) {
+
+ /* Fork off lots */
+
+ if ((pids[i] = fork()) == -1) {
+ perror("fork");
+ return 1;
+ }
+
+ /* Child does tests */
+
+ if (pids[i] == 0) {
+ dump_pwent(argv[1]);
+ return 0;
+ }
+ }
+
+ /* Wait for everyone to finish */
+
+ for (i = 0; i < NUM_FORKS; i++) {
+ waitpid(pids[i], &status, 0);
+ }
+
+ printf("PASS: getpwent_r.c\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/getpwent_r.exp b/testsuite/nsswitch/getpwent_r.exp
new file mode 100644
index 00000000000..95c155d78cc
--- /dev/null
+++ b/testsuite/nsswitch/getpwent_r.exp
@@ -0,0 +1,41 @@
+#
+# @(#) Test multiple threads can enumerate users correctly
+#
+
+load_lib util-defs.exp
+load_lib "$srcdir/lib/nsswitch-config.exp"
+
+# Compile getpwent_r.c
+
+set output [target_compile "$srcdir/$subdir/getpwent_r.c" \
+ "$srcdir/$subdir/getpwent_r" executable {additional_flags="-g"}]
+
+if {$output != ""} {
+ perror "compile getpwent_r"
+ puts $output
+ fail ""
+}
+
+# Clean up output from previous tests
+
+set pid [pid]
+file delete [glob -nocomplain "/tmp/getpwent_r-$pid.out-*"]
+
+# Run test proggy
+
+set output [util_start "$srcdir/$subdir/getpwent_r" "$pid" ""]
+if {![regexp "^PASS:" $output]} {
+ perror "run getpwent_r"
+ puts $output
+ return -1
+}
+
+# Sort and compare output
+
+set output [util_start "$srcdir/$subdir/getent_r.sh" "getpwent $pid" ""]
+if {$output == ""} {
+ pass "getpwent_r"
+} else {
+ fail "getpwent_r"
+ puts $output
+}
diff --git a/testsuite/nsswitch/getpwnam.c b/testsuite/nsswitch/getpwnam.c
new file mode 100644
index 00000000000..e7dd2910b66
--- /dev/null
+++ b/testsuite/nsswitch/getpwnam.c
@@ -0,0 +1,37 @@
+/*
+ * Lookup a user by name
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ struct passwd *pw;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: no arg specified\n");
+ exit(1);
+ }
+
+ /* Do getpwnam() */
+
+ if ((pw = getpwnam(argv[1])) == NULL) {
+ printf("FAIL: user %s does not exist\n", argv[1]);
+ exit(1);
+ }
+
+ printf("PASS: user %s exists\n", argv[1]);
+ printf("pw_name = %s\n", pw->pw_name);
+ printf("pw_passwd = %s\n", pw->pw_passwd);
+ printf("pw_uid = %d\n", pw->pw_uid);
+ printf("pw_gid = %d\n", pw->pw_gid);
+ printf("pw_gecos = %s\n", pw->pw_gecos);
+ printf("pw_dir = %s\n", pw->pw_dir);
+ printf("pw_shell = %s\n", pw->pw_shell);
+
+ exit(0);
+}
diff --git a/testsuite/nsswitch/getpwnam.exp b/testsuite/nsswitch/getpwnam.exp
new file mode 100644
index 00000000000..5f6b2343392
--- /dev/null
+++ b/testsuite/nsswitch/getpwnam.exp
@@ -0,0 +1,28 @@
+#
+# @(#) Test domain users resolve using getpwnam()
+#
+
+load_lib util-defs.exp
+load_lib "compile.exp"
+
+# Compile getpwnam.c
+
+simple_compile "getpwnam"
+
+# Test domain users
+
+set user_list [split [util_start "bin/wbinfo" "-u"] "\n"]
+
+verbose $user_list
+
+foreach { user } $user_list {
+ set output [util_start "$srcdir/$subdir/getpwnam" "\"$user\"" ""]
+
+ verbose $output
+
+ if {[regexp "PASS:" $output]} {
+ pass "getpwnam $user"
+ } else {
+ fail "getpwnam $user"
+ }
+}
diff --git a/testsuite/nsswitch/getpwuid.c b/testsuite/nsswitch/getpwuid.c
new file mode 100644
index 00000000000..3f364df29d5
--- /dev/null
+++ b/testsuite/nsswitch/getpwuid.c
@@ -0,0 +1,43 @@
+/*
+ * Lookup a user by uid.
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ struct passwd *pw;
+ uid_t uid;
+
+ /* Check args */
+
+ if (argc != 2) {
+ printf("ERROR: no arg specified\n");
+ exit(1);
+ }
+
+ if ((uid = atoi(argv[1])) == 0) {
+ printf("ERROR: invalid uid specified\n");
+ exit(1);
+ }
+
+ /* Do getpwuid() */
+
+ if ((pw = getpwuid(uid)) == NULL) {
+ printf("FAIL: uid %d does not exist\n", uid);
+ exit(1);
+ }
+
+ printf("PASS: uid %d exists\n", uid);
+ printf("pw_name = %s\n", pw->pw_name);
+ printf("pw_passwd = %s\n", pw->pw_passwd);
+ printf("pw_uid = %d\n", pw->pw_uid);
+ printf("pw_gid = %d\n", pw->pw_gid);
+ printf("pw_gecos = %s\n", pw->pw_gecos);
+ printf("pw_dir = %s\n", pw->pw_dir);
+ printf("pw_shell = %s\n", pw->pw_shell);
+
+ exit(0);
+}
diff --git a/testsuite/nsswitch/getpwuid.exp b/testsuite/nsswitch/getpwuid.exp
new file mode 100644
index 00000000000..be6a01cb9e1
--- /dev/null
+++ b/testsuite/nsswitch/getpwuid.exp
@@ -0,0 +1,59 @@
+#
+# @(#) Test reverse lookup of user ids from getent match getpwuid() output
+#
+
+load_lib util-defs.exp
+
+# Compile getpwuid.c
+
+set output [target_compile "$srcdir/$subdir/getpwuid.c" \
+ "$srcdir/$subdir/getpwuid" executable {additional_flags="-g"}]
+
+if {$output != ""} {
+ perror "compile getpwuid"
+ puts $output
+ return
+}
+
+# Get list of uids using getent
+
+set output [util_start "getent" "passwd" ""]
+set got_entries 0
+
+verbose $output
+
+foreach {line} [split $output "\n"] {
+
+ # Process user
+
+ set pwd_entry [split $line ":"]
+ set user [lindex $pwd_entry 0]
+
+ if {[regexp {^[^/]+/} $user]} {
+
+ set got_entries 1
+
+ # Only lookup winbindd users
+
+ set uid [lindex $pwd_entry 2]
+ set gid [lindex $pwd_entry 3]
+
+ # Test lookup of uid succeeds
+
+ set output [util_start "$srcdir/$subdir/getpwuid" "$uid" ""]
+
+ verbose $output
+
+ set test_desc "getpwuid $uid ($user)"
+
+ if {[regexp "PASS:" $output]} {
+ pass $test_desc
+ } else {
+ fail $test_desc
+ }
+ }
+}
+
+if {!$got_entries} {
+ perror "No domain users returned from getent"
+}
diff --git a/testsuite/nsswitch/groupmem_dom.exp b/testsuite/nsswitch/groupmem_dom.exp
new file mode 100644
index 00000000000..3ba34bb810e
--- /dev/null
+++ b/testsuite/nsswitch/groupmem_dom.exp
@@ -0,0 +1,33 @@
+#
+# @(#) Test whether members of domain groups all have domain names
+#
+
+load_lib util-defs.exp
+
+set group_list [split [util_start "getent group" ""] "\n"]
+set failed 0
+
+foreach { group } $group_list {
+ set group_entry [split $group ":"]
+
+ set group_name [lindex $group_entry 0]
+ set group_members [split [lindex $group_entry 3] ","]
+
+ if { [regexp {^[^/]+/} $group_name] } {
+
+ verbose "group $group_name has members $group_members"
+
+ foreach { user } $group_members {
+ if { ![regexp {^[^/]+/} $user] } {
+ fail "group $group has non-domain user $user"
+ set failed 1
+ }
+ }
+ } else {
+ verbose "ignoring non-domain group $group_name"
+ }
+}
+
+if { !$failed } {
+ pass "domain groups contain only domain members"
+}
diff --git a/testsuite/nsswitch/initgroups.c b/testsuite/nsswitch/initgroups.c
new file mode 100644
index 00000000000..b7d9c50eaa3
--- /dev/null
+++ b/testsuite/nsswitch/initgroups.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv)
+{
+ int result, ngroups, i;
+ gid_t *groups;
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(argv[1]))) {
+ printf("FAIL: no passwd entry for %s\n", argv[1]);
+ return 1;
+ }
+
+ result = initgroups(argv[1], pw->pw_gid);
+
+ if (result == -1) {
+ printf("FAIL");
+ return 1;
+ }
+
+ ngroups = getgroups(0, NULL);
+
+ groups = (gid_t *)malloc(sizeof(gid_t) * ngroups);
+ ngroups = getgroups(ngroups, groups);
+
+ printf("%s is a member of groups:\n", argv[1]);
+
+ for (i = 0; i < ngroups; i++) {
+ struct group *grp;
+
+ grp = getgrgid(groups[i]);
+
+ printf("%d (%s)\n", groups[i], grp ? grp->gr_name : "?");
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/nsswitch/initgroups.exp b/testsuite/nsswitch/initgroups.exp
new file mode 100644
index 00000000000..ab21bcc9e7b
--- /dev/null
+++ b/testsuite/nsswitch/initgroups.exp
@@ -0,0 +1,37 @@
+#
+# @(#) Test initgroups function
+#
+
+load_lib util-defs.exp
+load_lib compile.exp
+
+if { [util_start "id -u"] != 0 } {
+ set test_desc "must be userid 0 to run"
+ note $test_desc
+ untested $test_desc
+ return
+}
+
+# Compile test program
+
+simple_compile "initgroups"
+
+# Test domain users
+
+set user_list [split [util_start "bin/wbinfo" "-u"] "\n"]
+
+verbose $user_list
+
+foreach { user } $user_list {
+ set output [util_start "$srcdir/$subdir/initgroups" "\"$user\"" ""]
+
+ verbose $output
+
+ set test_desc "initgroups $user"
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ } else {
+ fail $test_desc
+ }
+}
diff --git a/testsuite/nsswitch/login.exp b/testsuite/nsswitch/login.exp
new file mode 100644
index 00000000000..c2bb0e5a40a
--- /dev/null
+++ b/testsuite/nsswitch/login.exp
@@ -0,0 +1,102 @@
+#
+# @(#) Test logins using pam_winbind.so module using telnet
+#
+
+load_lib util-defs.exp
+load_lib nsswitch-config.exp
+
+#
+# @(#) Test user can login
+#
+
+spawn telnet localhost
+
+set test_desc "telnet localhost (login)"
+
+expect {
+ "login:" { }
+ timeout { fail "timed out in $test_desc"; return }
+ eof { fail "end of file in $test_desc"; return }
+}
+
+send "$domain/$USER\r"
+
+set test_desc "telnet localhost (password)"
+
+expect {
+ "Password:" { }
+ timeout { fail "timed out in $test_desc"; return }
+ eof { fail "end of file in $test_desc"; return }
+}
+
+send "$PASSWORD\r"
+
+expect {
+ "$ " { }
+ "Login incorrect" { fail "login incorrect"; return }
+ timeout { fail "timed out in $test_desc"; return }
+ eof { fail "end of file in $test_desc"; return }
+}
+
+pass "login $domain/$USER"
+
+#
+# @(#) Check supplementary group membership
+#
+
+set test_desc "supplementary groups"
+
+# Get list of groups
+
+send "id -G\r"
+
+expect {
+ -re "((\[0-9]+ )*\[0-9]+\r)" { exp_continue; }
+ "$ " { }
+ timeout { fail "timed out in $test_desc"; return }
+ eof { fail "end of file in $test_desc"; return }
+}
+
+set groups $expect_out(1,string)
+set wb_groups [util_start "bin/wbinfo" "-r $domain/$USER"]
+
+verbose "id groups are $groups"
+verbose "wbinfo groups are $wb_groups"
+
+# Check all groups from id are in wbinfo and vice-versa
+
+set failed 0
+
+foreach { group } $groups {
+ set got_group 0
+ foreach { wb_group } $wb_groups {
+ if { $wb_group == $group } {
+ set got_group 1
+ break
+ }
+ }
+
+ if { !$got_group } {
+ fail "group $group not in output of wbinfo -r"
+ set failed 1
+ }
+}
+
+foreach { wb_group } $wb_groups {
+ set got_group 0
+ foreach { group } $groups {
+ if { $group == $wb_group } {
+ set got_group 1
+ break
+ }
+ }
+
+ if { !$got_group } {
+ fail "group $group not in output of id -G"
+ set failed 1
+ }
+}
+
+if { !$failed } {
+ pass "id/wbinfo groups match"
+}
diff --git a/testsuite/nsswitch/longarg.exp b/testsuite/nsswitch/longarg.exp
new file mode 100644
index 00000000000..e1d0eda9ccb
--- /dev/null
+++ b/testsuite/nsswitch/longarg.exp
@@ -0,0 +1,29 @@
+#
+# @(#) Test handling of long arguments passed to various nss functions
+#
+
+load_lib compile.exp
+load_lib util-defs.exp
+
+# Run tests from C source files
+
+set longarg_tests [list \
+ { "long arg to getpwnam()" "longarg_getpwnam" } \
+ { "long arg to getgrnam()" "longarg_getgrnam" } \
+ ]
+
+foreach { test } $longarg_tests {
+ set test_desc [lindex $test 0]
+ set test_file [lindex $test 1]
+
+ simple_make "longarg" $test_file
+ set output [util_start "$srcdir/$subdir/$test_file" ]
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_file" "$srcdir/$subdir/$test_file.o"
+ } else {
+ fail $test_desc
+ puts $output
+ }
+}
diff --git a/testsuite/nsswitch/longarg_getgrnam.c b/testsuite/nsswitch/longarg_getgrnam.c
new file mode 100644
index 00000000000..84083d2620e
--- /dev/null
+++ b/testsuite/nsswitch/longarg_getgrnam.c
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#include "longarg_utils.h"
+
+int main(void)
+{
+ struct group *grp;
+ char *domain = getenv("TEST_WORKGROUP");
+ char long_name[65535];
+ int failed = 0;
+
+ sprintf(long_name, "%s/%s", domain, LONG_STRING);
+
+ grp = getgrnam(long_name);
+ printf("%s\n", !grp ? "PASS" : "FAIL");
+
+ return grp == NULL;
+}
diff --git a/testsuite/nsswitch/longarg_getpwnam.c b/testsuite/nsswitch/longarg_getpwnam.c
new file mode 100644
index 00000000000..f2a0a73ddca
--- /dev/null
+++ b/testsuite/nsswitch/longarg_getpwnam.c
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+#include "longarg_utils.h"
+
+int main(void)
+{
+ struct passwd *pwd;
+ char *domain = getenv("TEST_WORKGROUP");
+ char long_name[65535];
+ int failed = 0;
+
+ sprintf(long_name, "%s/%s", domain, LONG_STRING);
+
+ pwd = getpwnam(long_name);
+ printf("%s\n", !pwd ? "PASS" : "FAIL");
+
+ return pwd == NULL;
+}
diff --git a/testsuite/nsswitch/longarg_utils.h b/testsuite/nsswitch/longarg_utils.h
new file mode 100644
index 00000000000..1f2f2a7065d
--- /dev/null
+++ b/testsuite/nsswitch/longarg_utils.h
@@ -0,0 +1,27 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LONGARG_UTILS_H
+#define _LONGARG_UTILS_H
+
+#define LONG_STRING "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+#endif
diff --git a/testsuite/nsswitch/nss_winbind_syms.c b/testsuite/nsswitch/nss_winbind_syms.c
new file mode 100644
index 00000000000..29d1da9d499
--- /dev/null
+++ b/testsuite/nsswitch/nss_winbind_syms.c
@@ -0,0 +1,63 @@
+/*
+ * Test required functions are exported from the libnss_winbind.so library
+ */
+
+#include <stdio.h>
+#include <dlfcn.h>
+
+/* Symbol list to check */
+
+static char *symlist[] = {
+ "_nss_winbind_getgrent_r",
+ "_nss_winbind_endgrent",
+ "_nss_winbind_endpwent",
+ "_nss_winbind_getgrgid_r",
+ "_nss_winbind_getgrnam_r",
+ "_nss_winbind_getpwent_r",
+ "_nss_winbind_getpwnam_r",
+ "_nss_winbind_getpwuid_r",
+ "_nss_winbind_setgrent",
+ "_nss_winbind_setpwent",
+ "_nss_winbind_initgroups",
+ NULL
+};
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ void *handle, *sym;
+ int i, y;
+
+ /* Open library */
+
+ if (argc != 2) {
+ printf("FAIL: usage '%s sharedlibname'\n", argv[0]);
+ return 1;
+ }
+
+ handle = dlopen(argv[1], RTLD_NOW);
+
+ if (handle == NULL) {
+ printf("FAIL: could not dlopen library: %s\n", dlerror());
+ return 1;
+ }
+
+ /* Read symbols */
+
+ for (i = 0; symlist[i] != NULL; i++) {
+ sym = dlsym(handle, symlist[i]);
+ if (sym == NULL) {
+ printf("FAIL: could not resolve symbol '%s': %s\n",
+ symlist[i], dlerror());
+ return 1;
+ } else {
+ printf("loaded symbol '%s' ok\n", symlist[i]);
+ }
+ }
+
+ /* Clean up */
+
+ dlclose(handle);
+ return 0;
+}
diff --git a/testsuite/nsswitch/nss_winbind_syms.exp b/testsuite/nsswitch/nss_winbind_syms.exp
new file mode 100644
index 00000000000..ab84cc5c757
--- /dev/null
+++ b/testsuite/nsswitch/nss_winbind_syms.exp
@@ -0,0 +1,42 @@
+#
+# @(#) Test nss functions are exported from the libnss_winbind.so library
+# @(#) Test there are no external dependencies in the libnss_winbind.so library
+#
+# We expect the following symbols to be exported:
+#
+# _nss_winbind_getgrent_r
+# _nss_winbind_endgrent
+# _nss_winbind_endpwent
+# _nss_winbind_getgrgid_r
+# _nss_winbind_getgrnam_r
+# _nss_winbind_getpwent_r
+# _nss_winbind_getpwnam_r
+# _nss_winbind_getpwuid_r
+# _nss_winbind_setgrent
+# _nss_winbind_setpwent
+# _nss_winbind_initgroups
+#
+# This test also has the nice side-effect of showing any unresolved symbols
+# in the library.
+#
+
+load_lib util-defs.exp
+load_lib compile.exp
+
+simple_compile "nss_winbind_syms" "-ldl"
+
+set output [util_start "$srcdir/$subdir/nss_winbind_syms" \
+ "nsswitch/libnss_winbind.so"]
+
+verbose $output
+
+if { [regexp "FAIL:" $output] } {
+ fail "run nss_winbind_syms"
+ return
+}
+
+pass "nss_winbind_syms"
+
+# Clean up
+
+file delete "$srcdir/$subdir/nss_winbind_syms"
diff --git a/testsuite/nsswitch/pam_winbind_syms.c b/testsuite/nsswitch/pam_winbind_syms.c
new file mode 100644
index 00000000000..1264bdb23e2
--- /dev/null
+++ b/testsuite/nsswitch/pam_winbind_syms.c
@@ -0,0 +1,55 @@
+/*
+ * Test required functions are exported from the pam_winbind.so library
+ */
+
+#include <stdio.h>
+#include <dlfcn.h>
+
+/* Symbol list to check */
+
+static char *symlist[] = {
+ "pam_sm_acct_mgmt",
+ "pam_sm_authenticate",
+ "pam_sm_setcred",
+ NULL
+};
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ void *handle, *sym;
+ int i, y;
+
+ /* Open library */
+
+ if (argc != 2) {
+ printf("FAIL: usage '%s sharedlibname'\n", argv[0]);
+ return 1;
+ }
+
+ handle = dlopen(argv[1], RTLD_NOW);
+
+ if (handle == NULL) {
+ printf("FAIL: could not dlopen library: %s\n", dlerror());
+ return 1;
+ }
+
+ /* Read symbols */
+
+ for (i = 0; symlist[i] != NULL; i++) {
+ sym = dlsym(handle, symlist[i]);
+ if (sym == NULL) {
+ printf("FAIL: could not resolve symbol '%s': %s\n",
+ symlist[i], dlerror());
+ return 1;
+ } else {
+ printf("loaded symbol '%s' ok\n", symlist[i]);
+ }
+ }
+
+ /* Clean up */
+
+ dlclose(handle);
+ return 0;
+}
diff --git a/testsuite/nsswitch/pam_winbind_syms.exp b/testsuite/nsswitch/pam_winbind_syms.exp
new file mode 100644
index 00000000000..f95274cdd9d
--- /dev/null
+++ b/testsuite/nsswitch/pam_winbind_syms.exp
@@ -0,0 +1,44 @@
+#
+# @(#) Test nss functions are exported from the pam_winbind.so library
+# @(#) Test there are no external dependencies in the pam_winbind.so library
+#
+# We expect the following symbols to be exported:
+#
+# pam_sm_acct_mgmt
+# pam_sm_authenticate
+# pam_sm_setcred
+#
+# This test also has the nice side-effect of showing any unresolved symbols
+# in the library.
+#
+
+load_lib util-defs.exp
+
+# Compile pam_winbind_syms.c
+
+set output [target_compile "$srcdir/$subdir/pam_winbind_syms.c" \
+ "$srcdir/$subdir/pam_winbind_syms" executable \
+ {"libs=-ldl -lpam" "additional_flags=-g"}]
+
+if {$output != ""} {
+ perror "compile pam_winbind_syms.c"
+ puts $output
+ return
+}
+
+# Run load-dl.c
+
+set output [util_start "$srcdir/$subdir/pam_winbind_syms" \
+ "nsswitch/pam_winbind.so"]
+
+if {[regexp "FAIL:" $output]} {
+ fail "run pam_winbind_syms"
+ puts $output
+ return
+}
+
+pass "pam_winbind_syms"
+
+# Clean up
+
+file delete "$srcdir/$subdir/pam_winbind_syms"
diff --git a/testsuite/nsswitch/wbinfo.exp b/testsuite/nsswitch/wbinfo.exp
new file mode 100644
index 00000000000..8be25b2a0f1
--- /dev/null
+++ b/testsuite/nsswitch/wbinfo.exp
@@ -0,0 +1,360 @@
+#
+# @(#) Test wbinfo client access to winbind daemon
+#
+
+load_lib "util-defs.exp"
+load_lib "$srcdir/lib/nsswitch-config.exp"
+load_lib "$srcdir/lib/default-nt-names.exp"
+
+# Name types
+
+set SID_NAME_USER 1
+set SID_NAME_DOM_GRP 2
+set SID_NAME_DOMAIN 3
+set SID_NAME_ALIAS 4
+set SID_NAME_UNKNOWN 8
+
+# Get list of users and groups
+
+set user_list [util_start "bin/wbinfo" "-u"]
+set group_list [util_start "bin/wbinfo" "-g"]
+
+verbose "user list is:\n$user_list"
+verbose "group list is:\n$group_list"
+
+set user_list [split $user_list "\n"]
+set group_list [split $group_list "\n"]
+
+#
+# @(#) Check list of users and groups contain default NT user and group
+# @(#) names
+#
+
+# Users
+
+foreach { user } $domain_users {
+ set test_desc "user $user in wbinfo domain users"
+ if {![regexp $user $user_list]} {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Groups
+
+foreach { group } $domain_groups {
+ set test_desc "group $group in wbinfo domain groups"
+ if {![regexp $group $group_list]} {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+#
+# @(#) Lookup sids for all user and group names returned by wbinfo
+#
+
+# Users
+
+foreach { user } $user_list {
+ set test_desc "get sid for user $user"
+ set output [util_start "bin/wbinfo" "-n \"$user\""]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set sid_type [lindex $list [expr [llength $list] - 1]]
+ set sid [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { ![regexp "S-" $sid] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "sid type for user $user"
+ if { $sid_type != $SID_NAME_USER } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ lappend user_sid_list $sid
+}
+
+# Groups
+
+foreach { group } $group_list {
+ set test_desc "get sid for group $group"
+ set output [util_start "bin/wbinfo" "-n \"$group\""]
+
+ verbose $output
+
+ # Split output into sid and sid type
+
+ set list [split $output " "]
+ set sid_type [lindex $list [expr [llength $list] - 1]]
+ set sid [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { ![regexp "S-" $sid] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "sid type for group group"
+ if { $sid_type != $SID_NAME_DOM_GRP } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ lappend group_sid_list $sid
+}
+
+#
+# @(#) Check reverse lookup of sids to names
+#
+
+# Users
+
+set count 0
+
+foreach { sid } $user_sid_list {
+ set test_desc "reverse user name lookup for sid $sid"
+ set output [util_start "bin/wbinfo" "-s $sid"]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { $name != [lindex $user_list $count] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "reverse user name type lookup for sid $sid"
+
+ if { $name_type != 1 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ incr count
+}
+
+# Groups
+
+set count 0
+
+foreach { sid } $group_sid_list {
+ set test_desc "reverse group name lookup for sid $sid"
+ set output [util_start "bin/wbinfo" "-s $sid"]
+
+ verbose $output
+
+ # Split output into name and name_type
+
+ set list [split $output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+
+ if { $name != [lindex $group_list $count] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "reverse group name type lookup for sid $sid"
+
+ if { $name_type != 2 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ incr count
+}
+
+#
+# @(#) Cross-check the output of wbinfo -n, getent passwd/group and
+# @(#) wbinfo -S
+#
+
+# Get mapped list of uids from winbindd
+
+set output [util_start "getent" "passwd"]
+set user_list [split $output "\n"]
+
+foreach { user_entry } $user_list {
+ if { [regexp $domain $user_entry] } {
+ set field_list [split $user_entry ":"]
+ set name_output [util_start "bin/wbinfo" \
+ "-n \"[lindex $field_list 0]\""]
+ set list [split $name_output " "]
+ set name_type [lindex $list [expr [llength $list] - 1]]
+ set name [join [lrange $list 0 [expr [llength $list] - 2]] " "]
+ set username_uid_sid [lappend username_uid_sid [list \
+ [lindex $field_list 0] \
+ [lindex $field_list 2] \
+ $name]]
+ }
+}
+
+# Get mapped list of gids from winbindd
+
+set output [util_start "getent" "group"]
+set group_list [split $output "\n"]
+
+foreach { group_entry } $group_list {
+ if { [regexp $domain $group_entry] } {
+ set field_list [split $group_entry ":"]
+ set groupname_gid_sid [lappend groupname_gid_sid [list \
+ [lindex $field_list 0] \
+ [lindex $field_list 2] \
+ [util_start "bin/wbinfo" "-n \"[lindex $field_list 0]\""]]]
+ }
+}
+
+# OK, now we have enough info to cross-check the uid/gid -> sid and
+# sid -> uid/gid functions
+
+foreach { user } $username_uid_sid {
+ set sid [util_start "bin/wbinfo" "-U [lindex $user 1]"]
+ set uid [util_start "bin/wbinfo" "-S [lindex $user 2]"]
+
+ set test_desc "lookup sid by uid [lindex $user 1]"
+
+ if { $sid != [lindex $user 2] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "lookup uid by sid [lindex $user 2]"
+
+ if { $uid != [lindex $user 1] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+foreach { group } $groupname_gid_sid {
+ set sid [util_start "bin/wbinfo" "-G [lindex $group 1]"]
+ set gid [util_start "bin/wbinfo" "-Y [lindex $group 2]"]
+
+ set test_desc "lookup sid by gid [lindex $group 1]"
+
+ if { $sid != [lindex [split [lindex $group 2] " "] 0] ||
+ [lindex [split [lindex $group 2] " " ] 1] != 2 } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+
+ set test_desc "lookup gid by sid [lindex $group 2]"
+
+ if { $gid != [lindex $group 1] } {
+ fail $test_desc
+ } else {
+ pass $test_desc
+ }
+}
+
+# Check exit codes
+
+proc check_errcode { args } {
+ global errorCode
+ set test_desc [lindex $args 0]
+ set cmd [lindex $args 1]
+ set result [lindex $args 2]
+
+ set errorCode ""
+ verbose "Spawning $cmd"
+ catch "exec $cmd" output
+ set exit_code [lindex $errorCode 2]
+ if { $exit_code == "" } { set exit_code 0 }
+
+ if { $exit_code == $result } {
+ verbose "process returned correct exit code $exit_code"
+ pass $test_desc
+ } else {
+ verbose "process returned bad exit code $exit_code instead of $result"
+ fail $test_desc
+ }
+}
+
+set gooduser_name [lindex [split [lindex $user_list 0] ":"] 0]
+set gooduser_sid [util_start "bin/wbinfo" "-n $gooduser_name"]
+
+set goodgroup_name [lindex [split [lindex $group_list 0] ":"] 0]
+set goodgroup_sid [util_start "bin/wbinfo" "-n $goodgroup_name"]
+
+# Some conditions not tested:
+# - bad list users/groups
+# - good uid/gid to sid
+
+set errcode_tests [list \
+ { "exit code, no arg" "bin/wbinfo" 1 } \
+ { "exit code, invalid arg" "bin/wbinfo -@" 1 } \
+ { "exit code, list users" "bin/wbinfo -u" 0 } \
+ { "exit code, list groups" "bin/wbinfo -g" 0 } \
+ { "exit code, good name to sid" "bin/wbinfo -n $gooduser_name" 0 } \
+ { "exit code, bad name to sid" "bin/wbinfo -n asmithee" 1 } \
+ { "exit code, good sid to name" "bin/wbinfo -s $gooduser_sid" 0 } \
+ { "exit code, bad sid to name" "bin/wbinfo -s S-1234" 1 } \
+ { "exit code, bad uid to sid" "bin/wbinfo -U 0" 1 } \
+ { "exit code, bad gid to sid" "bin/wbinfo -G 0" 1} \
+ { "exit code, good sid to uid" "bin/wbinfo -S $gooduser_sid" 0 } \
+ { "exit code, bad sid to uid" "bin/wbinfo -S S-1234" 1 } \
+ { "exit code, good sid to gid" "bin/wbinfo -Y $goodgroup_sid" 0 } \
+ { "exit code, bad sid to gid" "bin/wbinfo -Y S-1234" 1 } \
+ ]
+
+foreach { test } $errcode_tests {
+ check_errcode [lindex $test 0] [lindex $test 1] [lindex $test 2]
+}
+
+# Test enumerate trusted domains
+
+set test_desc "enumerate trusted domains"
+set output [util_start "bin/wbinfo" "-m"]
+
+verbose $output
+
+foreach { the_domain } $output {
+ if { $the_domain == $domain} {
+ fail "own domain appears in trusted list"
+ }
+}
+
+if {[regexp "Usage" $output] || [regexp "Could not" $output]} {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
+
+# Test check machine account
+
+set test_desc "check machine account"
+set output [util_start "bin/wbinfo" "-t"]
+
+verbose $output
+
+if {[regexp "Usage" $output] || [regexp "Could not" $output] || \
+ ![regexp "(good|bad)" $output]} {
+ fail $test_desc
+} else {
+ pass $test_desc
+}
diff --git a/testsuite/printing/.cvsignore b/testsuite/printing/.cvsignore
new file mode 100644
index 00000000000..392f2777686
--- /dev/null
+++ b/testsuite/printing/.cvsignore
@@ -0,0 +1,2 @@
+vlp
+psec
diff --git a/testsuite/printing/Makefile.psec b/testsuite/printing/Makefile.psec
new file mode 100644
index 00000000000..1410c9e0099
--- /dev/null
+++ b/testsuite/printing/Makefile.psec
@@ -0,0 +1,22 @@
+#
+# Makefile for psec utility
+#
+
+#
+# NOTE: Samba must be configured with the --srcdir option before this Makefile
+# will work: ./configure --srcdir=`pwd`
+#
+# Compile with: make -f Makefile.psec psec
+#
+
+psec_default: psec
+
+include ../../source/Makefile
+
+PSEC_OBJ1 = $(LIB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(RPC_PARSE_OBJ) \
+ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(RPC_CLIENT_OBJ)
+
+PSEC_OBJS = $(PSEC_OBJ1:%=$(srcdir)/%)
+
+psec: $(PSEC_OBJS) psec.o
+ $(CC) -o $@ psec.o $(PSEC_OBJS) $(LIBS)
diff --git a/testsuite/printing/Makefile.vlp b/testsuite/printing/Makefile.vlp
new file mode 100644
index 00000000000..142082ebfe6
--- /dev/null
+++ b/testsuite/printing/Makefile.vlp
@@ -0,0 +1,14 @@
+#
+# Makefile for vlp utility
+#
+
+vlp_default: vlp
+
+include ../../source/Makefile
+
+VLP_OBJ1 = $(LIB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
+
+VLP_OBJS = $(VLP_OBJ1:%=$(srcdir)/%)
+
+vlp: $(VLP_OBJS) vlp.o
+ $(CC) -o $@ vlp.o $(VLP_OBJS) $(LIBS)
diff --git a/testsuite/printing/README.vlp b/testsuite/printing/README.vlp
new file mode 100644
index 00000000000..48d2c8c0a2b
--- /dev/null
+++ b/testsuite/printing/README.vlp
@@ -0,0 +1,35 @@
+Virtual line printer test program (vlp)
+=======================================
+
+This can be useful for testing/debugging Samba print code. It gives you a
+virtual full-function printer.
+
+Setup
+
+1) Configure and build Samba.
+ For this to work, you need to add:
+ -DDEVELOPER
+ to your CFLAGS, and add:
+ --srcdir=<wherever your source is>
+ when running configure. Generally
+ ./configure --srcdir=`pwd` <other configure options>
+ should work.
+
+2) Build and install vlp.
+ # cd testsuite/printing
+ # make -f Makefile.vlp vlp
+ # su
+ # cp vlp /usr/local/samba/bin
+
+3) Set up Samba to use vlp.
+ In your smb.conf file under [global], add the following option:
+ printing = vlp
+ and then add any number of print shares, without needing to make them
+ really exist.
+
+ [testprinter]
+ printable = yes
+
+ is all you need for the most basic virtual printer.
+
+
diff --git a/testsuite/printing/psec.c b/testsuite/printing/psec.c
new file mode 100644
index 00000000000..9d38b9b10ae
--- /dev/null
+++ b/testsuite/printing/psec.c
@@ -0,0 +1,433 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Printer security permission manipulation.
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This program can get or set NT printer security permissions from the
+ command line. Usage: psec getsec|setsec printername. You must have
+ write access to the ntdrivers.tdb file to set permissions and read
+ access to get permissions.
+
+ For this program to compile using the supplied Makefile.psec, Samba
+ must be configured with the --srcdir option
+
+ For getsec, output like the following is sent to standard output:
+
+ S-1-5-21-1067277791-1719175008-3000797951-500
+
+ 1 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-501
+ 1 2 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-501
+ 0 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-500
+ 0 2 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-500
+ 0 9 0x10000000 S-1-5-21-1067277791-1719175008-3000797951-513
+ 0 2 0x00020000 S-1-5-21-1067277791-1719175008-3000797951-513
+ 0 2 0xe0000000 S-1-1-0
+
+ The first two lines describe the owner user and owner group of the printer.
+ If either of these lines are blank then the respective owner property is
+ not set. The remaining lines list the printer permissions or ACE entries,
+ one per line. Each column describes a different property of the ACE:
+
+ Column Description
+ -------------------------------------------------------------------
+ 1 ACE type (allow/deny etc) defined in rpc_secdes.h
+ 2 ACE flags defined in rpc_secdes.h
+ 3 ACE mask - printer ACE masks are defined in rpc_spoolss.h
+ 4 SID the ACE applies to
+
+ The above example describes the following permissions in order:
+
+ - The guest user has No Access to the printer
+ - The domain administrator has Full Access
+ - Domain Users can Manage Documents
+ - Everyone has Print access
+
+ The setsec command takes the output format but sets the security descriptor
+ appropriately. */
+
+#include "includes.h"
+
+TDB_CONTEXT *tdb;
+
+/* ACE type conversions */
+
+char *ace_type_to_str(uint ace_type)
+{
+ static fstring temp;
+
+ switch(ace_type) {
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ return "DENY";
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ return "ALLOW";
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "0x%02x", ace_type);
+ return temp;
+}
+
+uint str_to_ace_type(char *ace_type)
+{
+ if (strcmp(ace_type, "ALLOWED") == 0)
+ return SEC_ACE_TYPE_ACCESS_ALLOWED;
+
+ if (strcmp(ace_type, "DENIED") == 0)
+ return SEC_ACE_TYPE_ACCESS_DENIED;
+
+ return -1;
+}
+
+/* ACE mask (permission) conversions */
+
+char *ace_mask_to_str(uint32 ace_mask)
+{
+ static fstring temp;
+
+ switch (ace_mask) {
+ case PRINTER_ACE_FULL_CONTROL:
+ return "Full Control";
+ case PRINTER_ACE_MANAGE_DOCUMENTS:
+ return "Manage Documents";
+ case PRINTER_ACE_PRINT:
+ return "Print";
+ }
+
+ slprintf(temp, sizeof(temp) - 1, "0x%08x", ace_mask);
+ return temp;
+}
+
+uint32 str_to_ace_mask(char *ace_mask)
+{
+ if (strcmp(ace_mask, "Full Control") == 0)
+ return PRINTER_ACE_FULL_CONTROL;
+
+ if (strcmp(ace_mask, "Manage Documents") == 0)
+ return PRINTER_ACE_MANAGE_DOCUMENTS;
+
+ if (strcmp(ace_mask, "Print") == 0)
+ return PRINTER_ACE_PRINT;
+
+ return -1;
+}
+
+/* ACE conversions */
+
+char *ace_to_str(SEC_ACE *ace)
+{
+ static pstring temp;
+ fstring sidstr;
+
+ sid_to_string(sidstr, &ace->sid);
+
+ slprintf(temp, sizeof(temp) - 1, "%s %d %s %s",
+ ace_type_to_str(ace->type), ace->flags,
+ ace_mask_to_str(ace->info.mask), sidstr);
+
+ return temp;
+}
+
+void str_to_ace(SEC_ACE *ace, char *ace_str)
+{
+ SEC_ACCESS sa;
+ DOM_SID sid;
+ uint32 mask;
+ uint8 type, flags;
+
+ init_sec_access(&sa, mask);
+ init_sec_ace(ace, &sid, type, sa, flags);
+}
+
+/* Get a printer security descriptor */
+
+int psec_getsec(char *printer)
+{
+ SEC_DESC_BUF *secdesc_ctr = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ fstring keystr, sidstr, tdb_path;
+ prs_struct ps;
+ int result = 0, i;
+
+ ZERO_STRUCT(ps);
+
+ /* Open tdb for reading */
+
+ slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb",
+ lp_lockdir());
+
+ tdb = tdb_open(tdb_path, 0, 0, O_RDONLY, 0600);
+
+ if (!tdb) {
+ printf("psec: failed to open nt drivers database: %s\n",
+ sys_errlist[errno]);
+ return 1;
+ }
+
+ /* Get security blob from tdb */
+
+ slprintf(keystr, sizeof(keystr) - 1, "SECDESC/%s", printer);
+
+ mem_ctx = talloc_init();
+
+ if (!mem_ctx) {
+ printf("memory allocation error\n");
+ result = 1;
+ goto done;
+ }
+
+ if (tdb_prs_fetch(tdb, keystr, &ps, mem_ctx) != 0) {
+ printf("error fetching descriptor for printer %s\n",
+ printer);
+ result = 1;
+ goto done;
+ }
+
+ /* Unpack into security descriptor buffer */
+
+ if (!sec_io_desc_buf("nt_printing_getsec", &secdesc_ctr, &ps, 1)) {
+ printf("error unpacking sec_desc_buf\n");
+ result = 1;
+ goto done;
+ }
+
+ /* Print owner and group sid */
+
+ if (secdesc_ctr->sec->owner_sid) {
+ sid_to_string(sidstr, secdesc_ctr->sec->owner_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ printf("%s\n", sidstr);
+
+ if (secdesc_ctr->sec->grp_sid) {
+ sid_to_string(sidstr, secdesc_ctr->sec->grp_sid);
+ } else {
+ fstrcpy(sidstr, "");
+ }
+
+ printf("%s\n", sidstr);
+
+ /* Print aces */
+
+ if (!secdesc_ctr->sec->dacl) {
+ result = 0;
+ goto done;
+ }
+
+ for (i = 0; i < secdesc_ctr->sec->dacl->num_aces; i++) {
+ SEC_ACE *ace = &secdesc_ctr->sec->dacl->ace[i];
+
+ sid_to_string(sidstr, &ace->sid);
+
+ printf("%d %d 0x%08x %s\n", ace->type, ace->flags,
+ ace->info.mask, sidstr);
+ }
+
+ done:
+ if (tdb) tdb_close(tdb);
+ if (mem_ctx) talloc_destroy(mem_ctx);
+ if (secdesc_ctr) free_sec_desc_buf(&secdesc_ctr);
+ prs_mem_free(&ps);
+
+ return result;
+}
+
+/* Set a printer security descriptor */
+
+int psec_setsec(char *printer)
+{
+ DOM_SID user_sid, group_sid;
+ SEC_ACE *ace_list = NULL;
+ SEC_ACL *dacl = NULL;
+ SEC_DESC *sd;
+ SEC_DESC_BUF *sdb = NULL;
+ int result = 0, num_aces = 0;
+ fstring line, keystr, tdb_path;
+ size_t size;
+ prs_struct ps;
+ TALLOC_CTX *mem_ctx = NULL;
+ BOOL has_user_sid = False, has_group_sid = False;
+
+ ZERO_STRUCT(ps);
+
+ /* Open tdb for reading */
+
+ slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb",
+ lp_lockdir());
+
+ tdb = tdb_open(tdb_path, 0, 0, O_RDWR, 0600);
+
+ if (!tdb) {
+ printf("psec: failed to open nt drivers database: %s\n",
+ sys_errlist[errno]);
+ result = 1;
+ goto done;
+ }
+
+ /* Read owner and group sid */
+
+ fgets(line, sizeof(fstring), stdin);
+ if (line[0] != '\n') {
+ string_to_sid(&user_sid, line);
+ has_user_sid = True;
+ }
+
+ fgets(line, sizeof(fstring), stdin);
+ if (line[0] != '\n') {
+ string_to_sid(&group_sid, line);
+ has_group_sid = True;
+ }
+
+ /* Read ACEs from standard input for discretionary ACL */
+
+ while(fgets(line, sizeof(fstring), stdin)) {
+ int ace_type, ace_flags;
+ uint32 ace_mask;
+ fstring sidstr;
+ DOM_SID sid;
+ SEC_ACCESS sa;
+
+ if (sscanf(line, "%d %d 0x%x %s", &ace_type, &ace_flags,
+ &ace_mask, sidstr) != 4) {
+ continue;
+ }
+
+ string_to_sid(&sid, sidstr);
+
+ ace_list = Realloc(ace_list, sizeof(SEC_ACE) *
+ (num_aces + 1));
+
+ init_sec_access(&sa, ace_mask);
+ init_sec_ace(&ace_list[num_aces], &sid, ace_type, sa,
+ ace_flags);
+
+ num_aces++;
+ }
+
+ dacl = make_sec_acl(ACL_REVISION, num_aces, ace_list);
+ free(ace_list);
+
+ /* Create security descriptor */
+
+ sd = make_sec_desc(SEC_DESC_REVISION,
+ has_user_sid ? &user_sid : NULL,
+ has_group_sid ? &group_sid : NULL,
+ NULL, /* System ACL */
+ dacl, /* Discretionary ACL */
+ &size);
+
+ free_sec_acl(&dacl);
+
+ sdb = make_sec_desc_buf(size, sd);
+
+ free_sec_desc(&sd);
+
+ /* Write security descriptor to tdb */
+
+ mem_ctx = talloc_init();
+
+ if (!mem_ctx) {
+ printf("memory allocation error\n");
+ result = 1;
+ goto done;
+ }
+
+ prs_init(&ps, (uint32)sec_desc_size(sdb->sec) +
+ sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL);
+
+ if (!sec_io_desc_buf("nt_printing_setsec", &sdb, &ps, 1)) {
+ printf("sec_io_desc_buf failed\n");
+ goto done;
+ }
+
+ slprintf(keystr, sizeof(keystr) - 1, "SECDESC/%s", printer);
+
+ if (!tdb_prs_store(tdb, keystr, &ps)==0) {
+ printf("Failed to store secdesc for %s\n", printer);
+ goto done;
+ }
+
+ done:
+ if (tdb) tdb_close(tdb);
+ if (sdb) free_sec_desc_buf(&sdb);
+ if (mem_ctx) talloc_destroy(mem_ctx);
+ prs_mem_free(&ps);
+
+ return result;
+}
+
+/* Help */
+
+void usage(void)
+{
+ printf("Usage: psec getsec|setsec printername\n");
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ pstring servicesf = CONFIGFILE;
+
+ /* Argument check */
+
+ if (argc == 1) {
+ usage();
+ return 1;
+ }
+
+ /* Load smb.conf file */
+
+ charset_initialise();
+
+ if (!lp_load(servicesf,False,False,True)) {
+ fprintf(stderr, "Couldn't load confiuration file %s\n",
+ servicesf);
+ return 1;
+ }
+
+ /* Do commands */
+
+ if (strcmp(argv[1], "setsec") == 0) {
+
+ if (argc != 3) {
+ usage();
+ return 1;
+ }
+
+ return psec_setsec(argv[2]);
+ }
+
+ if (strcmp(argv[1], "getsec") == 0) {
+
+ if (argc != 3) {
+ usage();
+ return 1;
+ }
+
+ return psec_getsec(argv[2]);
+ }
+
+ /* An unknown command */
+
+ printf("psec: unknown command %s\n", argv[1]);
+ return 1;
+}
diff --git a/testsuite/printing/vlp.c b/testsuite/printing/vlp.c
new file mode 100644
index 00000000000..2dd028fcd38
--- /dev/null
+++ b/testsuite/printing/vlp.c
@@ -0,0 +1,426 @@
+/*
+ Unix SMB/Netbios implementation.
+
+ Virtual lp system for printer testing
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define PRINT_TDB "/tmp/vlp.tdb"
+#define PRINT_FIRSTJOB "100"
+
+static TDB_CONTEXT *tdb;
+
+struct vlp_job {
+ fstring owner;
+ int jobid;
+ fstring jobname;
+ int size;
+ int status;
+ time_t submit_time;
+ int deleted;
+};
+
+/* Print usage */
+
+static void usage(void)
+{
+ printf("Usage: print-test lpq|lprm|print|queuepause|queueresume|"
+ "lppause|lpresume [args]\n");
+}
+
+/* Return an array of vlp jobs that is the printer queue */
+
+static void get_job_list(char *printer, struct vlp_job **job_list,
+ int *num_jobs)
+{
+ fstring keystr;
+ TDB_DATA data;
+
+ slprintf(keystr, sizeof(keystr) - 1, "LPQ/%s", printer);
+ data = tdb_fetch_by_string(tdb, keystr);
+
+ *job_list = (struct vlp_job *)data.dptr;
+ *num_jobs = data.dsize / sizeof(struct vlp_job);
+}
+
+/* Store an array of vl jobs for the queue */
+
+static void set_job_list(char *printer, struct vlp_job *job_list,
+ int num_jobs)
+{
+ fstring keystr;
+
+ slprintf(keystr, sizeof(keystr) - 1, "LPQ/%s", printer);
+
+ tdb_store_by_string(tdb, keystr, job_list,
+ num_jobs * sizeof(struct vlp_job));
+}
+
+/* Return the next job number for a printer */
+
+static int next_jobnum(char *printer)
+{
+ fstring keystr;
+ int jobnum;
+
+ slprintf(keystr, sizeof(keystr) - 1, "JOBNUM/%s", printer);
+
+ tdb_lock_bystring(tdb, keystr);
+
+ jobnum = tdb_fetch_int(tdb, keystr);
+
+ /* Create next job index if none exists */
+
+ if (jobnum == -1) {
+ jobnum = atoi(PRINT_FIRSTJOB);
+ }
+
+ jobnum++;
+ tdb_store_int(tdb, keystr, jobnum);
+
+ tdb_unlock_bystring(tdb, keystr);
+
+ return jobnum;
+}
+
+static void set_printer_status(char *printer, int status)
+{
+ fstring keystr;
+ int result;
+
+ slprintf(keystr, sizeof(keystr) - 1, "STATUS/%s", printer);
+ result = tdb_store_int(tdb, keystr, status);
+}
+
+static int get_printer_status(char *printer)
+{
+ fstring keystr;
+ TDB_DATA data;
+
+ slprintf(keystr, sizeof(keystr) - 1, "STATUS/%s", printer);
+
+ data.dptr = keystr;
+ data.dsize = strlen(keystr) + 1;
+
+ if (!tdb_exists(tdb, data)) {
+ set_printer_status(printer, LPSTAT_OK);
+ return LPSTAT_OK;
+ }
+
+ return tdb_fetch_int(tdb, keystr);
+}
+
+/* Display printer queue */
+
+static int lpq_command(int argc, char **argv)
+{
+ char *printer;
+ struct vlp_job *job_list = NULL;
+ int i, num_jobs, job_count = 0;
+
+ if (argc != 2) {
+ printf("Usage: lpq <printername>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+
+ /* Display printer status */
+
+ switch (get_printer_status(printer)) {
+ case LPSTAT_OK:
+ printf("enabled\n");
+ break;
+ case LPSTAT_STOPPED:
+ printf("disabled\n");
+ break;
+ case LPSTAT_ERROR:
+ default:
+ printf("error\n");
+ break;
+ }
+
+ /* Print queued documents */
+
+ get_job_list(printer, &job_list, &num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (job_list[i].deleted) continue;
+ printf("%d\t%d\t%d\t%ld\t%s\t%s\n", job_list[i].jobid,
+ job_list[i].size,
+ (i == 0 && job_list[i].status == LPQ_QUEUED) ?
+ LPQ_SPOOLING : job_list[i].status,
+ job_list[i].submit_time, job_list[i].owner,
+ job_list[i].jobname);
+ job_count++;
+ }
+
+ free(job_list);
+
+ return 0;
+}
+
+/* Remove a job */
+
+static int lprm_command(int argc, char **argv)
+{
+ char *printer;
+ int jobid, num_jobs, i;
+ struct vlp_job *job_list;
+
+ if (argc < 3) {
+ printf("Usage: lprm <printername> <jobid>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+ jobid = atoi(argv[2]);
+
+ get_job_list(printer, &job_list, &num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (job_list[i].jobid == jobid) {
+ job_list[i].deleted = 1;
+ set_job_list(printer, job_list, num_jobs);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* print command = print-test %p %s */
+
+static int print_command(int argc, char **argv)
+{
+ char *printer;
+ fstring keystr;
+ struct passwd *pw;
+ TDB_DATA value;
+ struct vlp_job job;
+ int i;
+
+ if (argc < 3) {
+ printf("Usage: print <printername> <jobname>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+
+ ZERO_STRUCT(job);
+
+ /* Create a job record */
+
+ for (i = 2; i < argc; i++) {
+ fstrcat(job.jobname, argv[i]);
+ if (i < argc - 1) {
+ fstrcat(job.jobname, " ");
+ }
+ }
+
+ if (!(pw = getpwuid(getuid()))) {
+ return 1;
+ }
+
+ fstrcpy(job.owner, pw->pw_name);
+
+ job.jobid = next_jobnum(printer);
+ job.size = 666;
+ job.submit_time = time(NULL);
+
+ /* Store job entry in queue */
+
+ slprintf(keystr, sizeof(keystr) - 1, "LPQ/%s", printer);
+
+ value = tdb_fetch_by_string(tdb, keystr);
+
+ if (value.dptr) {
+
+ /* Add job to end of queue */
+
+ value.dptr = realloc(value.dptr, value.dsize +
+ sizeof(struct vlp_job));
+ if (!value.dptr) return 1;
+
+ memcpy(value.dptr + value.dsize, &job, sizeof(struct vlp_job));
+
+ tdb_store_by_string(tdb, keystr, value.dptr, value.dsize +
+ sizeof(struct vlp_job));
+
+ free(value.dptr);
+
+ } else {
+
+ /* Create new queue */
+
+ tdb_store_by_string(tdb, keystr, &job, sizeof(struct vlp_job));
+ }
+
+ return 0;
+}
+
+/* Pause the queue */
+
+static int queuepause_command(int argc, char **argv)
+{
+ char *printer;
+
+ if (argc != 2) {
+ printf("Usage: queuepause <printername>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+ set_printer_status(printer, LPSTAT_STOPPED);
+
+ return 0;
+}
+
+/* Resume the queue */
+
+static int queueresume_command(int argc, char **argv)
+{
+ char *printer;
+
+ if (argc != 2) {
+ printf("Usage: queueresume <printername>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+ set_printer_status(printer, LPSTAT_OK);
+
+ return 0;
+}
+
+/* Pause a job */
+
+static int lppause_command(int argc, char **argv)
+{
+ struct vlp_job *job_list;
+ char *printer;
+ int jobid, num_jobs, i;
+
+ if (argc != 3) {
+ printf("Usage: lppause <printername> <jobid>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+ jobid = atoi(argv[2]);
+
+ get_job_list(printer, &job_list, &num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (job_list[i].jobid == jobid) {
+ job_list[i].status = LPQ_PAUSED;
+ set_job_list(printer, job_list, num_jobs);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Resume a job */
+
+static int lpresume_command(int argc, char **argv)
+{
+ struct vlp_job *job_list;
+ char *printer;
+ int jobid, num_jobs, i;
+
+ if (argc != 3) {
+ printf("Usage: lpresume <printername> <jobid>\n");
+ return 1;
+ }
+
+ printer = argv[1];
+ jobid = atoi(argv[2]);
+
+ get_job_list(printer, &job_list, &num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ if (job_list[i].jobid == jobid) {
+ job_list[i].status = LPQ_QUEUED;
+ set_job_list(printer, job_list, num_jobs);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ /* Parameter check */
+
+ if (argc == 1) {
+ usage();
+ return 1;
+ }
+
+ /* Initialise */
+
+ if (!(tdb = tdb_open(PRINT_TDB, 0, 0, O_RDWR | O_CREAT,
+ 0666))) {
+ printf("%s: unable to open %s\n", argv[0], PRINT_TDB);
+ return 1;
+ }
+
+ /* Ensure we are modes 666 */
+
+ chmod(PRINT_TDB, 0666);
+
+ /* Do commands */
+
+ if (strcmp(argv[1], "lpq") == 0) {
+ return lpq_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "lprm") == 0) {
+ return lprm_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "print") == 0) {
+ return print_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "queuepause") == 0) {
+ return queuepause_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "queueresume") == 0) {
+ return queueresume_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "lppause") == 0) {
+ return lppause_command(argc - 1, &argv[1]);
+ }
+
+ if (strcmp(argv[1], "lpresume") == 0) {
+ return lpresume_command(argc - 1, &argv[1]);
+ }
+
+ /* Unknown command */
+
+ printf("%s: invalid command %s\n", argv[0], argv[1]);
+ return 1;
+}
diff --git a/testsuite/server/ipc.exp b/testsuite/server/ipc.exp
new file mode 100644
index 00000000000..ae0688872a8
--- /dev/null
+++ b/testsuite/server/ipc.exp
@@ -0,0 +1,44 @@
+#
+# Test operations on IPC$ share
+#
+
+# Initialisation
+
+load_lib env-single.exp
+load_lib smbclient.exp
+
+set timeout 10
+
+# Spawn a smbclient
+
+if {![spawn_smbclient //$server/ipc\$ -U $user]} {
+ perror "error spawning smbclient"
+ return -1
+}
+
+#
+# Start performing tests
+#
+
+global smb_prompt
+
+do_smbclient "lcd /tmp\r" "lcd /tmp"
+do_smbclient "!touch test.out\r" "touch test.out"
+
+foreach { op } { "dir\r" "put test.out\r" "get test.out\r" \
+ "get /etc/passwd\r" "mkdir foo\r" "print test.out\r" } {
+
+ set action "doing $op"
+ set output [do_smbclient $op $action]
+
+ if {![regexp "ERR" $output]} {
+ fail $action
+ puts $output
+ } else {
+ pass $action
+ }
+}
+
+# Clean up
+
+file delete test.out
diff --git a/testsuite/server/masktest.exp b/testsuite/server/masktest.exp
new file mode 100644
index 00000000000..532291bffb8
--- /dev/null
+++ b/testsuite/server/masktest.exp
@@ -0,0 +1,57 @@
+#
+# Test various things using the masktest program
+#
+
+# Initialisation
+
+load_lib env-single.exp
+
+set timeout 10
+
+# Test each wildcard individually, then all together at once
+
+set testlist {{"abc" "<"} {"abc" ">"} {"abc" "\""} {"abc" "?"} {"abc" "*"} \
+ {"abc" "."} {"abc" "<>\"?*."}}
+
+foreach { test } $testlist {
+
+ set got_output 0
+ set fail 0
+
+ # Spawn masktest
+
+ spawn bin/masktest //$server/$share -U $user -n 1000 -a \
+ -f [lindex $test 0] -m [concat [lindex $test 0] [lindex $test 1]]
+
+ # Check output
+
+ while 1 {
+ expect {
+ -re "(...) (...) \[0-9\]+ mask=" {
+ if { $expect_out(1,string) != $expect_out(2,string) } {
+ fail "masktest [lindex $test 1]"
+ puts $expect_out(0,string);
+ set fail 1
+ break;
+ } else {
+ set got_output 1
+ }
+ }
+ eof { break }
+ }
+ }
+
+ # Produce result
+
+ set testname "[lindex $test 0] [lindex $test 1]"
+
+ if {$got_output} {
+ if {$fail} {
+ fail "masktest $testname"
+ } else {
+ pass "masktest $testname"
+ }
+ } else {
+ perror "no output seen for test $testname"
+ }
+}
diff --git a/testsuite/server/rename.exp b/testsuite/server/rename.exp
new file mode 100644
index 00000000000..77e7297776b
--- /dev/null
+++ b/testsuite/server/rename.exp
@@ -0,0 +1,59 @@
+#
+# Test misc file operations
+#
+
+# Initialisation
+
+load_lib env-single.exp
+load_lib smbclient.exp
+
+set timeout 10
+
+# Spawn a connection
+
+if {![spawn_smbclient //$server/$share -U $user]} {
+ perror "error spawning smbclient"
+ return -1
+}
+
+# Do wildcard rename test
+
+foreach { op } {"!touch /tmp/test.out\r" "lcd /tmp\r" "rm test.out\r" \
+ "put test.out\r"} {
+
+ set action "doing $op"
+ set output [do_smbclient $op $action]
+
+ if {[regexp "ERR" $output]} {
+ perror $action
+ puts $output
+ return -1;
+ }
+}
+
+file delete "/tmp/test.out"
+
+# Perform rename
+
+set output [do_smbclient "rename *.out *.dat\r" "wildcard rename"]
+
+if {[regexp "ERR" $output]} {
+ perror "wildcard rename didn't work"
+ return -1
+}
+
+# Check it worked
+
+set testname "wildcard match"
+set output [do_smbclient "dir\r" "wildcard rename check"]
+
+if {[regexp "test.dat" $output]} {
+ pass $testname
+} else {
+ fail $testname
+}
+
+# Clean up
+
+set op "rm test.dat\r"
+do_smbclient $op "doing $op"
diff --git a/testsuite/server/xfer.exp b/testsuite/server/xfer.exp
new file mode 100644
index 00000000000..6d00b29885c
--- /dev/null
+++ b/testsuite/server/xfer.exp
@@ -0,0 +1,48 @@
+#
+# Test file transfer
+#
+
+# Initialisation
+
+load_lib util-defs.exp
+load_lib smbclient.exp
+load_lib env-single.exp
+
+set timeout 60
+
+# Spawn a connection
+
+if {![spawn_smbclient //$server/$share -U $user]} {
+ perror "error spawning smbclient"
+ return -1
+}
+
+# Create a big file, store it and fetch it again
+
+foreach { op } { "!dd if=/dev/urandom of=/tmp/file bs=1048576 count=1\r" \
+ "lcd /tmp\r" "put file\r" "get file /tmp/file2\r" } {
+
+ set action "doing $op"
+ set output [do_smbclient $op $action]
+
+ if {[regexp "ERR" $output]} {
+ error $action
+ puts $output
+ return -1
+ }
+}
+
+# Compare the two files
+
+set output [util_start "diff" "/tmp/file /tmp/file2" ""]
+
+if {[regexp "differ" $output]} {
+ fail "xfertest"
+ puts $output
+} else {
+ pass "xfertest"
+}
+
+# Clean up temporary files
+
+file delete /tmp/file /tmp/file2
diff --git a/testsuite/smbd/Makefile.se_access_check b/testsuite/smbd/Makefile.se_access_check
new file mode 100644
index 00000000000..5637fa2f2fc
--- /dev/null
+++ b/testsuite/smbd/Makefile.se_access_check
@@ -0,0 +1,24 @@
+#
+# Makefile for se_access_check tests
+#
+
+include ../../source/Makefile
+
+# Objects common to all tests
+
+SE_ACCESS_CHECK_OBJ1 = $(LIB_OBJ) $(UBIQX_OBJ) $(PARAM_OBJ) $(RPC_PARSE_OBJ) \
+ $(LIBSMB_OBJ) lib/util_seaccess.o nsswitch/common.o
+
+SE_ACCESS_CHECK_OBJS = $(SE_ACCESS_CHECK_OBJ1:%=$(srcdir)/%) \
+ se_access_check_utils.o
+
+# Targets for individual tests
+
+se_access_check_nullsd: $(SE_ACCESS_CHECK_OBJS) se_access_check_nullsd.o
+se_access_check_everyone: $(SE_ACCESS_CHECK_OBJS) se_access_check_everyone.o
+se_access_check_allowall: $(SE_ACCESS_CHECK_OBJS) se_access_check_allowall.o
+se_access_check_denyall: $(SE_ACCESS_CHECK_OBJS) se_access_check_denyall.o
+se_access_check_allowsome: $(SE_ACCESS_CHECK_OBJS) se_access_check_allowsome.o
+se_access_check_denysome: $(SE_ACCESS_CHECK_OBJS) se_access_check_denysome.o
+se_access_check_empty: $(SE_ACCESS_CHECK_OBJS) se_access_check_empty.o
+se_access_check_printer: $(SE_ACCESS_CHECK_OBJS) se_access_check_printer.o
diff --git a/testsuite/smbd/Makefile.sec_ctx b/testsuite/smbd/Makefile.sec_ctx
new file mode 100644
index 00000000000..c45ab5bb5e8
--- /dev/null
+++ b/testsuite/smbd/Makefile.sec_ctx
@@ -0,0 +1,57 @@
+#
+# Makefile for sec_ctx tests
+#
+
+include ../../source/Makefile
+
+# Objects common to all tests
+
+SEC_CTX_OBJ1 = $(RPC_CLIENT_OBJ) $(LIB_OBJ) $(RPC_PARSE_OBJ) $(PARAM_OBJ) \
+ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(UBIQX_OBJ) smbd/password.o smbd/uid.o \
+ smbd/chgpasswd.o smbd/sec_ctx.o
+
+SEC_CTX_OBJS = $(SEC_CTX_OBJ1:%=$(srcdir)/%) sec_ctx_utils.o
+
+# Targets for tests
+
+SEC_CTX_NONROOT_OBJS = $(SEC_CTX_OBJS) sec_ctx_nonroot.o
+
+sec_ctx_nonroot: $(SEC_CTX_NONROOT_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_NONROOT_OBJS) $(LIBS)
+
+SEC_CTX_STACK_OBJS = $(SEC_CTX_OBJS) sec_ctx_stack.o
+
+sec_ctx_stack: $(SEC_CTX_STACK_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_STACK_OBJS) $(LIBS)
+
+SEC_CTX_FLOW_OBJS = $(SEC_CTX_OBJS) sec_ctx_flow.o
+
+sec_ctx_flow: $(SEC_CTX_FLOW_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_FLOW_OBJS) $(LIBS)
+
+SEC_CTX_TORTURE_OBJS = $(SEC_CTX_OBJS) sec_ctx_torture.o
+
+sec_ctx_torture: $(SEC_CTX_TORTURE_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_TORTURE_OBJS) $(LIBS)
+
+SEC_CTX_CURRENT_USER_OBJS = $(SEC_CTX_OBJS) sec_ctx_current_user.o
+
+sec_ctx_current_user: $(SEC_CTX_CURRENT_USER_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_CURRENT_USER_OBJS) $(LIBS)
+
+SEC_CTX_GROUPS_OBJS = $(SEC_CTX_OBJS) sec_ctx_groups.o
+
+sec_ctx_groups: $(SEC_CTX_GROUPS_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_GROUPS_OBJS) $(LIBS)
+
+SEC_CTX_ROOT_OBJS = $(SEC_CTX_OBJS) sec_ctx_root.o
+
+sec_ctx_root: $(SEC_CTX_ROOT_OBJS)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(SEC_CTX_ROOT_OBJS) $(LIBS)
diff --git a/testsuite/smbd/se_access_check.exp b/testsuite/smbd/se_access_check.exp
new file mode 100644
index 00000000000..cd84ab8ee08
--- /dev/null
+++ b/testsuite/smbd/se_access_check.exp
@@ -0,0 +1,54 @@
+#
+# @(#) Test se_access_check() function
+#
+
+#
+# Unix SMB/Netbios implementation.
+# Copyright (C) Tim Potter 2000
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+load_lib "compile.exp"
+load_lib "util-defs.exp"
+
+# Run tests from C source files
+
+set se_access_check_tests [list \
+ { "null security descriptor" "se_access_check_nullsd" } \
+ { "security descriptor allow everyone" "se_access_check_allowall" } \
+ { "security descriptor allow everyone" "se_access_check_allowall" } \
+ { "security descriptor deny everyone" "se_access_check_denyall" } \
+ { "empty security descriptor" "se_access_check_empty" } \
+ { "allow some users access" "se_access_check_allowsome" } \
+ { "deny some users access" "se_access_check_denysome" } \
+ { "printer access permissions" "se_access_check_printer" } \
+ ]
+
+foreach { test } $se_access_check_tests {
+ set test_desc [lindex $test 0]
+ set test_file [lindex $test 1]
+
+ simple_make "se_access_check" $test_file
+ set output [util_start "$srcdir/$subdir/$test_file" ]
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_file" "$srcdir/$subdir/$test_file.o"
+ } else {
+ fail $test_desc
+ puts $output
+ }
+}
diff --git a/testsuite/smbd/se_access_check_allowall.c b/testsuite/smbd/se_access_check_allowall.c
new file mode 100644
index 00000000000..b49e8e52e7f
--- /dev/null
+++ b/testsuite/smbd/se_access_check_allowall.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_allowall[] = {
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "S-1-1-0" },
+ { 0, 0, 0, NULL}
+};
+
+/* Check that access is always allowed for a NULL security descriptor */
+
+BOOL allowall_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ BOOL result;
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ if (!result || status != NT_STATUS_NO_PROBLEMO ||
+ acc_granted != GENERIC_ALL_ACCESS) {
+ printf("FAIL: allowall se_access_check %d/%d\n",
+ pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_allowall, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ visit_pwdb(allowall_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_allowsome.c b/testsuite/smbd/se_access_check_allowsome.c
new file mode 100644
index 00000000000..529b2007622
--- /dev/null
+++ b/testsuite/smbd/se_access_check_allowsome.c
@@ -0,0 +1,104 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_allowsome[] = {
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "user0" },
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "user2" },
+ { 0, 0, 0, NULL}
+};
+
+BOOL allowsome_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ fstring name;
+ BOOL result;
+ int len1, len2;
+
+ /* Check only user0 and user2 allowed access */
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ len1 = (int)strlen(pw->pw_name) - strlen("user0");
+ len2 = (int)strlen(pw->pw_name) - strlen("user2");
+
+ if ((strncmp("user0", &pw->pw_name[MAX(len1, 0)],
+ strlen("user0")) == 0) ||
+ (strncmp("user2", &pw->pw_name[MAX(len2, 0)],
+ strlen("user2")) == 0)) {
+ if (!result || acc_granted != GENERIC_ALL_ACCESS) {
+ printf("FAIL: access not granted for %s\n",
+ pw->pw_name);
+ }
+ } else {
+ if (result || acc_granted != 0) {
+ printf("FAIL: access granted for %s\n", pw->pw_name);
+ }
+ }
+
+ printf("result %s for user %s\n", result ? "allowed" : "denied",
+ pw->pw_name);
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_allowsome, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ visit_pwdb(allowsome_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_denyall.c b/testsuite/smbd/se_access_check_denyall.c
new file mode 100644
index 00000000000..016e6f6d549
--- /dev/null
+++ b/testsuite/smbd/se_access_check_denyall.c
@@ -0,0 +1,86 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_denyall[] = {
+ { SEC_ACE_TYPE_ACCESS_DENIED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "S-1-1-0" },
+ { 0, 0, 0, NULL}
+};
+
+/* Check that access is always allowed for a NULL security descriptor */
+
+BOOL denyall_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ BOOL result;
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ if (result || acc_granted != 0) {
+ printf("FAIL: denyall se_access_check %d/%d\n",
+ pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_denyall, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ visit_pwdb(denyall_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_denysome.c b/testsuite/smbd/se_access_check_denysome.c
new file mode 100644
index 00000000000..1f0aaaf1392
--- /dev/null
+++ b/testsuite/smbd/se_access_check_denysome.c
@@ -0,0 +1,106 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_denysome[] = {
+ { SEC_ACE_TYPE_ACCESS_DENIED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "user1" },
+ { SEC_ACE_TYPE_ACCESS_DENIED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "user3" },
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ GENERIC_ALL_ACCESS, "S-1-1-0" },
+ { 0, 0, 0, NULL}
+};
+
+BOOL denysome_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ fstring name;
+ BOOL result;
+ int len1, len2;
+
+ /* Check only user1 and user3 denied access */
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ len1 = (int)strlen(pw->pw_name) - strlen("user1");
+ len2 = (int)strlen(pw->pw_name) - strlen("user3");
+
+ if ((strncmp("user1", &pw->pw_name[MAX(len1, 0)],
+ strlen("user1")) == 0) ||
+ (strncmp("user3", &pw->pw_name[MAX(len2, 0)],
+ strlen("user3")) == 0)) {
+ if (result || acc_granted != 0) {
+ printf("FAIL: access not denied for %s\n",
+ pw->pw_name);
+ }
+ } else {
+ if (!result || acc_granted != GENERIC_ALL_ACCESS) {
+ printf("FAIL: access denied for %s\n", pw->pw_name);
+ }
+ }
+
+ printf("result %s for user %s\n", result ? "allowed" : "denied",
+ pw->pw_name);
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_denysome, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ visit_pwdb(denysome_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_empty.c b/testsuite/smbd/se_access_check_empty.c
new file mode 100644
index 00000000000..6602b1147ee
--- /dev/null
+++ b/testsuite/smbd/se_access_check_empty.c
@@ -0,0 +1,109 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_empty[] = {
+ { 0, 0, 0, NULL}
+};
+
+/* Check that access is always allowed for a NULL security descriptor */
+
+BOOL emptysd_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ BOOL result;
+
+ /* For no DACL, access is allowed and the desired access mask is
+ returned */
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ if (!result || !(acc_granted == SEC_RIGHTS_MAXIMUM_ALLOWED)) {
+ printf("FAIL: no dacl for %s (%d/%d)\n", pw->pw_name,
+ pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups, 0x1234,
+ &acc_granted, &status);
+
+ if (!result || !(acc_granted == 0x1234)) {
+ printf("FAIL: no dacl2 for %s (%d/%d)\n", pw->pw_name,
+ pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ /* If desired access mask is empty then no access is allowed */
+
+ result = se_access_check(sd, pw->pw_uid, pw->pw_gid,
+ ngroups, groups, 0,
+ &acc_granted, &status);
+
+ if (result) {
+ printf("FAIL: zero desired access for %s (%d/%d)\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_empty, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ visit_pwdb(emptysd_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_nullsd.c b/testsuite/smbd/se_access_check_nullsd.c
new file mode 100644
index 00000000000..c042c2b1485
--- /dev/null
+++ b/testsuite/smbd/se_access_check_nullsd.c
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+
+/* Check that access is always allowed for a NULL security descriptor */
+
+BOOL nullsd_check(struct passwd *pw, int ngroups, gid_t *groups)
+{
+ uint32 acc_granted, status;
+ BOOL result;
+
+ result = se_access_check(NULL, pw->pw_uid, pw->pw_gid,
+ ngroups, groups,
+ SEC_RIGHTS_MAXIMUM_ALLOWED,
+ &acc_granted, &status);
+
+ if (!result || status != NT_STATUS_NO_PROBLEMO ||
+ acc_granted != SEC_RIGHTS_MAXIMUM_ALLOWED) {
+ printf("FAIL: null se_access_check %d/%d\n",
+ pw->pw_uid, pw->pw_gid);
+ failed = True;
+ }
+
+ printf("access check passed for user %s (%d/%d)\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid);
+
+ return True;
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Run test */
+
+ visit_pwdb(nullsd_check);
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_printer.c b/testsuite/smbd/se_access_check_printer.c
new file mode 100644
index 00000000000..e73a23ce21b
--- /dev/null
+++ b/testsuite/smbd/se_access_check_printer.c
@@ -0,0 +1,212 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+/* Globals */
+
+BOOL failed;
+SEC_DESC *sd;
+
+struct ace_entry acl_printer[] = {
+
+ /* Everyone is allowed to print */
+
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_PRINT, "S-1-1-0" },
+
+ /* Except for user0 who uses too much paper */
+
+ { SEC_ACE_TYPE_ACCESS_DENIED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_FULL_CONTROL, "user0" },
+
+ /* Users 1 and 2 can manage documents */
+
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_MANAGE_DOCUMENTS, "user1" },
+
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_MANAGE_DOCUMENTS, "user2" },
+
+ /* Domain Admins can also manage documents */
+
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_MANAGE_DOCUMENTS, "Domain Admins" },
+
+ /* User 3 is da man */
+
+ { SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_ACE_FLAG_CONTAINER_INHERIT,
+ PRINTER_ACE_FULL_CONTROL, "user3" },
+
+ { 0, 0, 0, NULL}
+};
+
+BOOL test_user(char *username, uint32 acc_desired, uint32 *acc_granted)
+{
+ struct passwd *pw;
+ uint32 status;
+
+ if (!(pw = getpwnam(username))) {
+ printf("FAIL: could not lookup user info for %s\n",
+ username);
+ exit(1);
+ }
+
+ return se_access_check(sd, pw->pw_uid, pw->pw_gid, 0, NULL,
+ acc_desired, acc_granted, &status);
+}
+
+static char *pace_str(uint32 ace_flags)
+{
+ if ((ace_flags & PRINTER_ACE_FULL_CONTROL) ==
+ PRINTER_ACE_FULL_CONTROL) return "full control";
+
+ if ((ace_flags & PRINTER_ACE_MANAGE_DOCUMENTS) ==
+ PRINTER_ACE_MANAGE_DOCUMENTS) return "manage documents";
+
+ if ((ace_flags & PRINTER_ACE_PRINT) == PRINTER_ACE_PRINT)
+ return "print";
+
+ return "UNKNOWN";
+}
+
+uint32 perms[] = {
+ PRINTER_ACE_PRINT,
+ PRINTER_ACE_FULL_CONTROL,
+ PRINTER_ACE_MANAGE_DOCUMENTS,
+ 0
+};
+
+void runtest(void)
+{
+ uint32 acc_granted;
+ BOOL result;
+ int i, j;
+
+ for (i = 0; perms[i]; i++) {
+
+ /* Test 10 users */
+
+ for (j = 0; j < 10; j++) {
+ fstring name;
+
+ /* Test user against ACL */
+
+ snprintf(name, sizeof(fstring), "%s/user%d",
+ getenv("TEST_WORKGROUP"), j);
+
+ result = test_user(name, perms[i], &acc_granted);
+
+ printf("%s: %s %s 0x%08x\n", name,
+ pace_str(perms[i]),
+ result ? "TRUE " : "FALSE", acc_granted);
+
+ /* Check results */
+
+ switch (perms[i]) {
+
+ case PRINTER_ACE_PRINT: {
+ if (!result || acc_granted !=
+ PRINTER_ACE_PRINT) {
+ printf("FAIL: user %s can't print\n",
+ name);
+ failed = True;
+ }
+ break;
+ }
+
+ case PRINTER_ACE_FULL_CONTROL: {
+ if (j == 3) {
+ if (!result || acc_granted !=
+ PRINTER_ACE_FULL_CONTROL) {
+ printf("FAIL: user %s doesn't "
+ "have full control\n",
+ name);
+ failed = True;
+ }
+ } else {
+ if (result || acc_granted != 0) {
+ printf("FAIL: user %s has full "
+ "control\n", name);
+ failed = True;
+ }
+ }
+ break;
+ }
+ case PRINTER_ACE_MANAGE_DOCUMENTS: {
+ if (j == 1 || j == 2) {
+ if (!result || acc_granted !=
+ PRINTER_ACE_MANAGE_DOCUMENTS) {
+ printf("FAIL: user %s can't "
+ "manage documents\n",
+ name);
+ failed = True;
+ }
+ } else {
+ if (result || acc_granted != 0) {
+ printf("FAIL: user %s can "
+ "manage documents\n",
+ name);
+ failed = True;
+ }
+ }
+ break;
+ }
+
+ default:
+ printf("FAIL: internal error\n");
+ exit(1);
+ }
+ }
+ }
+}
+
+/* Main function */
+
+int main(int argc, char **argv)
+{
+ /* Initialisation */
+
+ generate_wellknown_sids();
+
+ /* Create security descriptor */
+
+ sd = build_sec_desc(acl_printer, NULL, NULL_SID, NULL_SID);
+
+ if (!sd) {
+ printf("FAIL: could not build security descriptor\n");
+ return 1;
+ }
+
+ /* Run test */
+
+ runtest();
+
+ /* Return */
+
+ if (!failed) {
+ printf("PASS\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testsuite/smbd/se_access_check_utils.c b/testsuite/smbd/se_access_check_utils.c
new file mode 100644
index 00000000000..316bb5d905a
--- /dev/null
+++ b/testsuite/smbd/se_access_check_utils.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "se_access_check_utils.h"
+
+void char_to_sid(DOM_SID *sid, char *sid_str)
+{
+ /* If it looks like a SID, call string_to_sid() else look it up
+ using wbinfo. */
+
+ if (strncmp(sid_str, "S-", 2) == 0) {
+ string_to_sid(sid, sid_str);
+ } else {
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ /* Send off request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ fstrcpy(request.data.name, sid_str);
+ if (winbindd_request(WINBINDD_LOOKUPNAME, &request,
+ &response) != NSS_STATUS_SUCCESS) {
+ printf("FAIL: unable to look up sid for name %s\n",
+ sid_str);
+ exit(1);
+ }
+
+ string_to_sid(sid, response.data.sid.sid);
+ printf("converted char %s to sid %s\n", sid_str,
+ response.data.sid.sid);
+ }
+}
+
+/* Construct an ACL from a list of ace_entry structures */
+
+SEC_ACL *build_acl(struct ace_entry *ace_list)
+{
+ SEC_ACE *aces = NULL;
+ SEC_ACL *result;
+ int num_aces = 0;
+
+ if (ace_list == NULL) return NULL;
+
+ /* Create aces */
+
+ while(ace_list->sid) {
+ SEC_ACCESS sa;
+ DOM_SID sid;
+
+ /* Create memory for new ACE */
+
+ if (!(aces = Realloc(aces,
+ sizeof(SEC_ACE) * (num_aces + 1)))) {
+ return NULL;
+ }
+
+ /* Create ace */
+
+ init_sec_access(&sa, ace_list->mask);
+
+ char_to_sid(&sid, ace_list->sid);
+ init_sec_ace(&aces[num_aces], &sid, ace_list->type,
+ sa, ace_list->flags);
+
+ num_aces++;
+ ace_list++;
+ }
+
+ /* Create ACL from list of ACEs */
+
+ result = make_sec_acl(ACL_REVISION, num_aces, aces);
+ free(aces);
+
+ return result;
+}
+
+/* Make a security descriptor */
+
+SEC_DESC *build_sec_desc(struct ace_entry *dacl, struct ace_entry *sacl,
+ char *owner_sid, char *group_sid)
+{
+ DOM_SID the_owner_sid, the_group_sid;
+ SEC_ACL *the_dacl, *the_sacl;
+ SEC_DESC *result;
+ size_t size;
+
+ /* Build up bits of security descriptor */
+
+ char_to_sid(&the_owner_sid, owner_sid);
+ char_to_sid(&the_group_sid, group_sid);
+
+ the_dacl = build_acl(dacl);
+ the_sacl = build_acl(sacl);
+
+ result = make_sec_desc(SEC_DESC_REVISION,
+ SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT,
+ &the_owner_sid, &the_group_sid,
+ the_sacl, the_dacl, &size);
+
+ free_sec_acl(&the_dacl);
+ free_sec_acl(&the_sacl);
+
+ return result;
+}
+
+/* Iterate over password database and call a user-specified function */
+
+void visit_pwdb(BOOL (*fn)(struct passwd *pw, int ngroups, gid_t *groups))
+{
+ struct passwd *pw;
+ int ngroups;
+ gid_t *groups;
+
+ setpwent();
+
+ while ((pw = getpwent())) {
+ BOOL result;
+
+ /* Get grouplist */
+
+ ngroups = getgroups(0, NULL);
+
+ groups = malloc(sizeof(gid_t) * ngroups);
+ getgroups(ngroups, groups);
+
+ /* Call function */
+
+ result = fn(pw, ngroups, groups);
+ if (!result) break;
+
+ /* Clean up */
+
+ free(groups);
+ }
+
+ endpwent();
+}
diff --git a/testsuite/smbd/se_access_check_utils.h b/testsuite/smbd/se_access_check_utils.h
new file mode 100644
index 00000000000..bae0d171abf
--- /dev/null
+++ b/testsuite/smbd/se_access_check_utils.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SE_ACCESS_CHECK_UTILS_H
+#define _SE_ACCESS_CHECK_UTILS_H
+
+#include "includes.h"
+
+/* Structure to build ACE lists from */
+
+struct ace_entry {
+ uint8 type, flags;
+ uint32 mask;
+ char *sid;
+};
+
+#define NULL_SID "S-1-0-0"
+#define WORLD_SID "S-1-1-0"
+
+/* Function prototypes */
+
+SEC_ACL *build_acl(struct ace_entry *ace_list);
+SEC_DESC *build_sec_desc(struct ace_entry *dacl, struct ace_entry *sacl,
+ char *owner_sid, char *group_sid);
+
+void visit_pwdb(BOOL (*fn)(struct passwd *pw, int ngroups, gid_t *groups));
+
+#endif
diff --git a/testsuite/smbd/sec_ctx.exp b/testsuite/smbd/sec_ctx.exp
new file mode 100644
index 00000000000..0831400e702
--- /dev/null
+++ b/testsuite/smbd/sec_ctx.exp
@@ -0,0 +1,67 @@
+#
+# @(#) Test the push_sec_ctx() and pop_sec_ctx() functions
+#
+
+#
+# Unix SMB/Netbios implementation.
+# Copyright (C) Tim Potter 2000
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+load_lib "compile.exp"
+load_lib "util-defs.exp"
+
+# Non-root test
+
+set test_desc "change sec_ctx as non-root"
+set test_prog "sec_ctx_nonroot"
+simple_make "sec_ctx" $test_prog
+set output [util_start "$srcdir/$subdir/$test_prog"]
+
+if { [regexp "child killed" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_prog" "$srcdir/$subdir/$test_prog.o"
+} else {
+ fail $test_desc
+}
+
+# Run tests from C files as root
+
+set sec_ctx_tests [list \
+ { "security contexts are stackable" "sec_ctx_stack" } \
+ { "over/underflow tests" "sec_ctx_flow" } \
+ { "torture test" "sec_ctx_torture" } \
+ { "current_user global" "sec_ctx_current_user" } \
+ { "group membership" "sec_ctx_groups" } \
+ { "become root" "sec_ctx_root" } \
+ ]
+
+foreach { test } $sec_ctx_tests {
+ set test_desc [lindex $test 0]
+ set test_file [lindex $test 1]
+
+ simple_make "sec_ctx" $test_file
+ set output [util_start "sudo $srcdir/$subdir/$test_file" ]
+
+ if { [regexp "PASS" $output] } {
+ pass $test_desc
+ file delete "$srcdir/$subdir/$test_file" "$srcdir/$subdir/$test_file.o"
+ } else {
+ fail $test_desc
+ puts $output
+ }
+
+}
diff --git a/testsuite/smbd/sec_ctx1.c b/testsuite/smbd/sec_ctx1.c
new file mode 100644
index 00000000000..b74b6ed9009
--- /dev/null
+++ b/testsuite/smbd/sec_ctx1.c
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void exit_server(char *reason) {}
+
+int main (int argc, char **argv)
+{
+ /* Become a non-root user */
+
+ setuid(1);
+ setgid(1);
+
+ /* Try to push a security context. This should fail with a
+ smb_assert() error. */
+
+ push_sec_ctx(2, 2);
+ printf("FAIL\n");
+
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_current_user.c b/testsuite/smbd/sec_ctx_current_user.c
new file mode 100644
index 00000000000..5b7da0ef464
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_current_user.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main(int argc, char **argv)
+{
+ extern struct current_user current_user;
+ uid_t initial_uid = current_user.uid;
+ gid_t initial_gid = current_user.gid;
+ int ngroups;
+ gid_t *groups;
+
+ init_sec_ctx();
+
+ /* Check initial id */
+
+ if (initial_uid != 0 || initial_gid != 0) {
+ printf("FAIL: current_user not initialised to root\n");
+ return 1;
+ }
+
+ /* Push a context and check current user is updated */
+
+ if (!push_sec_ctx()) {
+ printf("FAIL: push_sec_ctx\n");
+ return 1;
+ }
+
+ set_sec_ctx(1, 2, 0, NULL);
+
+ if (current_user.uid != 1 || current_user.gid != 2) {
+ printf("FAIL: current_user id not updated after push\n");
+ return 1;
+ }
+
+ if (current_user.ngroups != 0 || current_user.groups) {
+ printf("FAIL: current_user groups not updated after push\n");
+ return 1;
+ }
+
+ /* Push another */
+
+ get_random_grouplist(&ngroups, &groups);
+
+ if (!push_sec_ctx()) {
+ printf("FAIL: push_sec_ctx\n");
+ return 1;
+ }
+
+ set_sec_ctx(2, 3, ngroups, groups);
+
+ if (current_user.uid != 2 || current_user.gid != 3) {
+ printf("FAIL: current_user id not updated after second "
+ "push\n");
+ return 1;
+ }
+
+ if (current_user.ngroups != ngroups ||
+ (memcmp(current_user.groups, groups,
+ sizeof(gid_t) * ngroups) != 0)) {
+ printf("FAIL: current_user groups not updated\n");
+ return 1;
+ }
+
+ /* Pop them both off */
+
+ if (!pop_sec_ctx()) {
+ printf("FAIL: pop_sec_ctx\n");
+ return 1;
+ }
+
+ if (current_user.uid != 1 || current_user.gid != 2) {
+ printf("FAIL: current_user not updaded pop\n");
+ return 1;
+ }
+
+ if (!pop_sec_ctx()) {
+ printf("FAIL: pop_sec_ctx\n");
+ return 1;
+ }
+
+ /* Check initial state was returned */
+
+ if (current_user.uid != initial_uid ||
+ current_user.gid != initial_gid) {
+ printf("FAIL: current_user not updaded pop\n");
+ return 1;
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_flow.c b/testsuite/smbd/sec_ctx_flow.c
new file mode 100644
index 00000000000..7b251784671
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_flow.c
@@ -0,0 +1,73 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ init_sec_ctx();
+
+ /* Check for underflow */
+
+ if (!push_sec_ctx()) {
+ printf("FAIL: push_sec_ctx\n");
+ return 1;
+ }
+
+ set_sec_ctx(1, 1, 0, NULL);
+
+ if (!pop_sec_ctx()) {
+ printf("FAIL: pop_sec_ctx\n");
+ return 1;
+ }
+
+ if (pop_sec_ctx()) {
+ printf("FAIL: underflow push_sec_ctx\n");
+ return 1;
+ }
+
+ /* Check for overflow */
+
+ for (i = 0; i < MAX_SEC_CTX_DEPTH + 1; i++) {
+ BOOL result;
+
+ result = push_sec_ctx();
+ set_sec_ctx(i, i, 0, NULL);
+
+ if ((i < MAX_SEC_CTX_DEPTH) && !result) {
+ printf("FAIL: push_sec_ctx(%d)\n", i);
+ return 1;
+ }
+
+ if ((i == MAX_SEC_CTX_DEPTH + 1) && result) {
+ printf("FAIL: overflow push_sec_ctx(%d)\n", i);
+ return 1;
+ }
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_groups.c b/testsuite/smbd/sec_ctx_groups.c
new file mode 100644
index 00000000000..61d77f6f4f0
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_groups.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main (int argc, char **argv)
+{
+ int ngroups, initial_ngroups, check_ngroups, final_ngroups;
+ gid_t *groups, *initial_groups, *check_groups, *final_groups;
+ int i;
+
+ init_sec_ctx();
+
+ /* Save current groups */
+
+ initial_ngroups = sys_getgroups(0, NULL);
+ initial_groups = malloc(sizeof(gid_t) * initial_ngroups);
+ sys_getgroups(initial_ngroups, initial_groups);
+
+ printf("Initial groups are: ");
+ for (i = 0; i < initial_ngroups; i++) {
+ printf("%d, ", initial_groups[i]);
+ }
+ printf("\n");
+
+ /* Push a context plus groups */
+
+ get_random_grouplist(&ngroups, &groups);
+
+ printf("Random groups are: ");
+ for (i = 0; i < ngroups; i++) {
+ printf("%d, ", groups[i]);
+ }
+ printf("\n");
+
+ if (!push_sec_ctx()) {
+ printf("FAIL: push_sec_ctx\n");
+ return 1;
+ }
+
+ set_sec_ctx(1, 2, ngroups, groups);
+
+ /* Check grouplist stuck */
+
+ check_ngroups = sys_getgroups(0, NULL);
+ check_groups = malloc(sizeof(gid_t) * check_ngroups);
+ sys_getgroups(check_ngroups, check_groups);
+
+ printf("Actual groups are: ");
+ for (i = 0; i < check_ngroups; i++) {
+ printf("%d, ", check_groups[i]);
+ }
+ printf("\n");
+
+ if (ngroups != check_ngroups) {
+ printf("FAIL: number of groups differs\n");
+ return 1;
+ }
+
+ for (i = 0; i < ngroups; i++) {
+ if (groups[i] != check_groups[i]) {
+ printf("FAIL: group %d differs\n", i);
+ return 1;
+ }
+ }
+
+ safe_free(groups);
+ safe_free(check_groups);
+
+ /* Pop and check initial groups are back */
+
+ if (!pop_sec_ctx()) {
+ printf("FAIL: pop_sec_ctx\n");
+ return 1;
+ }
+
+ final_ngroups = sys_getgroups(0, NULL);
+ final_groups = malloc(sizeof(gid_t) * final_ngroups);
+ sys_getgroups(final_ngroups, final_groups);
+
+ printf("Final groups are: ");
+ for (i = 0; i < final_ngroups; i++) {
+ printf("%d, ", final_groups[i]);
+ }
+ printf("\n");
+
+ if (initial_ngroups != final_ngroups) {
+ printf("FAIL: final number of groups differ\n");
+ return 1;
+ }
+
+ for (i = 0; i < initial_ngroups; i++) {
+ if (initial_groups[i] != final_groups[i]) {
+ printf("FAIL: final group %d differs\n", i);
+ return 1;
+ }
+ }
+
+ printf("Final groups are: ");
+ for (i = 0; i < final_ngroups; i++) {
+ printf("%d, ", final_groups[i]);
+ }
+ printf("\n");
+
+ safe_free(initial_groups);
+ safe_free(final_groups);
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_nonroot.c b/testsuite/smbd/sec_ctx_nonroot.c
new file mode 100644
index 00000000000..18bba7e2806
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_nonroot.c
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main (int argc, char **argv)
+{
+ init_sec_ctx();
+
+ /* Become a non-root user */
+
+ setuid(1);
+ setgid(1);
+
+ /* Try to push a security context. This should fail with a
+ smb_assert() error. */
+
+ push_sec_ctx();
+ set_sec_ctx(2, 2, 0, NULL);
+ printf("FAIL\n");
+
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_root.c b/testsuite/smbd/sec_ctx_root.c
new file mode 100644
index 00000000000..f2e46f0a5cd
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_root.c
@@ -0,0 +1,61 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main (int argc, char **argv)
+{
+ int ngroups, actual_ngroups;
+ gid_t *groups, *actual_groups;
+ extern struct current_user current_user;
+
+ init_sec_ctx();
+
+ /* Initialise a security context */
+
+ get_random_grouplist(&ngroups, &groups);
+ set_sec_ctx(1, 1, ngroups, groups);
+
+ /* Become root and check */
+
+ set_root_sec_ctx();
+
+ actual_ngroups = getgroups(0, NULL);
+ actual_groups = (gid_t *)malloc(actual_ngroups * sizeof(gid_t));
+
+ getgroups(actual_ngroups, actual_groups);
+
+ if (geteuid() != 0 || getegid() != 0 || actual_ngroups != 0) {
+ printf("FAIL: root id not set\n");
+ return 1;
+ }
+
+ if (current_user.uid != 0 || current_user.gid != 0 ||
+ current_user.ngroups != 0 || current_user.groups) {
+ printf("FAIL: current_user not set correctly\n");
+ return 1;
+ }
+
+ printf("PASS\n");
+
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_stack.c b/testsuite/smbd/sec_ctx_stack.c
new file mode 100644
index 00000000000..f6952fabb4e
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_stack.c
@@ -0,0 +1,86 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+int main (int argc, char **argv)
+{
+ BOOL result;
+ int i;
+
+ init_sec_ctx();
+
+ /* Push a whole bunch of security contexts */
+
+ for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
+
+ result = push_sec_ctx();
+ set_sec_ctx(i + 1, i + 2, 0, NULL);
+
+ if (!result) {
+ printf("FAIL: push_sec_ctx(%d)\n", i);
+ return 1;
+ }
+
+ printf("pushed context (%d, %d) eff=(%d, %d)\n",
+ getuid(), getgid(), geteuid(), getegid());
+
+ if ((geteuid() != i + 1) || (getegid() != i + 2)) {
+ printf("FAIL: incorrect context pushed\n");
+ return 1;
+ }
+ }
+
+ /* Pop them all off */
+
+ for (i = MAX_SEC_CTX_DEPTH; i > 0; i--) {
+
+ result = pop_sec_ctx();
+
+ if (!result) {
+ printf("FAIL: pop_sec_ctx(%d)\n", i);
+ return 1;
+ }
+
+ printf("popped context (%d, %d) eff=(%d, %d)\n",
+ getuid(), getgid(), geteuid(), getegid());
+
+ printf("i = %d\n",i);
+
+ if (i > 1) {
+ if ((geteuid() != i - 1) || (getegid() != i)) {
+ printf("FAIL: incorrect context popped\n");
+ return 1;
+ }
+ } else {
+ if ((geteuid() != 0) || (getegid() != 0)) {
+ printf("FAIL: incorrect context popped\n");
+ return 1;
+ }
+ }
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_torture.c b/testsuite/smbd/sec_ctx_torture.c
new file mode 100644
index 00000000000..effee069ef9
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_torture.c
@@ -0,0 +1,103 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "sec_ctx_utils.h"
+
+#define NUM_TESTS 10000
+
+int main (int argc, char **argv)
+{
+ int seed, level = 0, num_tests = 0;
+
+ init_sec_ctx();
+
+ if (argc == 1) {
+ seed = time(NULL);
+ } else {
+ seed = atoi(argv[1]);
+ }
+
+ printf("seed = %d\n", seed);
+
+ while(num_tests < NUM_TESTS) {
+ switch (random() % 2) {
+
+ /* Push a random context */
+
+ case 0:
+ if (level < MAX_SEC_CTX_DEPTH) {
+ int ngroups;
+ gid_t *groups;
+
+ if (!push_sec_ctx()) {
+ printf("FAIL: push random ctx\n");
+ return 1;
+ }
+
+ get_random_grouplist(&ngroups, &groups);
+
+ set_sec_ctx(random() % 32767,
+ random() % 32767,
+ ngroups, groups);
+
+ if (!verify_current_groups(ngroups,
+ groups)) {
+ printf("FAIL: groups did not stick\n");
+ return 1;
+ }
+
+ printf("pushed (%d, %d) eff=(%d, %d)\n",
+ getuid(), getgid(), geteuid(),
+ getegid());
+
+ level++;
+ num_tests++;
+
+ free(groups);
+ }
+ break;
+
+ /* Pop a random context */
+
+ case 1:
+ if (level > 0) {
+ if (!pop_sec_ctx()) {
+ printf("FAIL: pop random ctx\n");
+ return 1;
+ }
+
+ printf("popped (%d, %d) eff=(%d, %d)\n",
+ getuid(), getgid(), geteuid(),
+ getegid());
+
+ level--;
+ num_tests++;
+ }
+ break;
+ }
+ }
+
+ /* Everything's cool */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/testsuite/smbd/sec_ctx_utils.c b/testsuite/smbd/sec_ctx_utils.c
new file mode 100644
index 00000000000..fbda6352c46
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_utils.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Keep linker happy */
+
+void exit_server(char *reason) {}
+
+/* Generate random list of groups */
+
+void get_random_grouplist(int *ngroups, gid_t **groups)
+{
+ int i;
+
+ *ngroups = random() % groups_max();
+ *groups = malloc(*ngroups * sizeof(gid_t));
+
+ if (!groups) {
+ printf("FAIL: malloc random grouplist\n");
+ return;
+ }
+
+ for (i = 0; i < *ngroups; i++) {
+ (*groups)[i] = random() % 32767;
+ }
+}
+
+/* Check a list of groups with current groups */
+
+BOOL verify_current_groups(int ngroups, gid_t *groups)
+{
+ int actual_ngroups;
+ gid_t *actual_groups;
+
+ actual_ngroups = getgroups(0, NULL);
+ actual_groups = (gid_t *)malloc(actual_ngroups * sizeof(gid_t));
+
+ getgroups(actual_ngroups, actual_groups);
+
+ if (actual_ngroups != ngroups) {
+ return False;
+ }
+
+ return memcmp(actual_groups, groups, actual_ngroups *
+ sizeof(gid_t)) == 0;
+}
diff --git a/testsuite/smbd/sec_ctx_utils.h b/testsuite/smbd/sec_ctx_utils.h
new file mode 100644
index 00000000000..1f4bde841ed
--- /dev/null
+++ b/testsuite/smbd/sec_ctx_utils.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Security context tests
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SEC_CTX_UTILS_H
+#define _SEC_CTX_UTILS_H
+
+/* Function prototypes */
+
+void get_random_grouplist(int *ngroups, gid_t **groups);
+BOOL verify_current_groups(int ngroups, gid_t *groups);
+
+#endif /* _SEC_CTX_UTILS_H */
diff --git a/testsuite/smbd/sighup.exp b/testsuite/smbd/sighup.exp
new file mode 100644
index 00000000000..a9e1bffe11d
--- /dev/null
+++ b/testsuite/smbd/sighup.exp
@@ -0,0 +1,107 @@
+#
+# @(#) Check services file reloaded after SIGHUP
+#
+
+load_lib "util-defs.exp"
+
+# Create a smb.conf file from a list of sections. Each section consists of
+# a name and a list of lines which are the contents of that section.
+# Returns a temporary filename which must be deleted after use.
+
+proc write_smb_conf { args } {
+
+ # Set up temporary file
+
+ set name "/tmp/smb.conf-test-[pid]"
+ set f [open $name "w"]
+
+ # Parse sections
+
+ foreach section [lindex $args 0] {
+ set secname [lindex $section 0]
+ set contents [lindex $section 1]
+
+ puts $f "\[$secname]"
+
+ foreach { line } $contents {
+ puts $f "\t$line"
+ }
+
+ puts $f ""
+ }
+
+ close $f
+
+ # Return filename of smb.conf file
+
+ return $name
+}
+
+proc append_smb_conf { args } {
+
+ set name [lindex $args 0]
+ set f [open $name "a"]
+
+ foreach section [lindex $args 1] {
+ set secname [lindex $section 0]
+ set contents [lindex $section 1]
+
+ puts $f "\[$secname]"
+
+ foreach { line } $contents {
+ puts $f "\t$line"
+ }
+
+ puts $f ""
+ }
+
+ close $f
+}
+
+# Create a smb.conf file
+
+set smb_conf [list \
+ [list "global" \
+ [list "netbios name = testing" \
+ "guest ok = true"]]]
+
+set name [write_smb_conf $smb_conf]
+
+# Run smbd and smbclient output
+
+set smbd_output [util_start "bin/smbd" "-s $name"]
+set nmbd_output [util_start "bin/nmbd" "-s $name"]
+
+sleep 5
+
+set smbclient_output [util_start "bin/smbclient -L //testing -N"]
+verbose $smbclient_output
+
+if { ![regexp "Anonymous login successful" $smbclient_output] } {
+ untested "smbd could not be started"
+ util_start "killall" "smbd nmbd"
+ file delete $name
+ return
+}
+
+# Append another share and sighup
+
+append_smb_conf $name [list [list "tmp" [list "browseable = true"]]]
+set output [util_start "killall" "-HUP smbd"]
+verbose $output
+
+sleep 2
+
+set smbclient_output2 [util_start "bin/smbclient -L //testing -N"]
+verbose $smbclient_output2
+
+if { [regexp "tmp.*Disk" $smbclient_output2] } {
+ pass "sighup reload"
+} else {
+ fail "sighup reload"
+}
+
+# Clean up
+
+util_start "killall" "smbd nmbd"
+file delete $name